From a2c6c34739b8af7fd3c78de099e5dbd9ac964deb Mon Sep 17 00:00:00 2001 From: Ben Doherty Date: Tue, 10 Mar 2020 15:32:41 -0700 Subject: [PATCH] Update SPIRV-Tools to 2020.1 / SPIRV-Cross to 65aa0c3 (#2121) --- libs/filamat/src/GLSLPostProcessor.cpp | 2 + third_party/spirv-cross/.travis.yml | 6 +- third_party/spirv-cross/CMakeLists.txt | 132 +- third_party/spirv-cross/README.md | 2 +- .../checkout_glslang_spirv_tools.sh | 6 +- third_party/spirv-cross/gn/BUILD.gn | 63 + .../include/spirv_cross/sampler.hpp | 2 +- third_party/spirv-cross/main.cpp | 115 +- .../pkg-config/spirv-cross-c-shared.pc.in | 8 +- .../asm/comp/bitcast_icmp.asm.comp | 28 + .../asm/frag/line-directive.line.asm.frag | 12 +- .../comp/access-chain-load-composite.comp | 108 + .../opt/shaders-hlsl/comp/access-chains.comp | 2 + .../comp/access-chains.force-uav.comp | 23 + .../shaders-hlsl/comp/address-buffers.comp | 2 + .../comp/atomic-decrement.asm.comp | 22 - .../comp/atomic-increment.asm.comp | 22 - .../opt/shaders-hlsl/comp/atomic.comp | 2 + .../shaders-hlsl/comp/globallycoherent.comp | 2 + .../opt/shaders-hlsl/comp/image.comp | 2 + .../opt/shaders-hlsl/comp/inverse.comp | 2 + .../comp/num-workgroups-alone.comp | 2 + .../comp/num-workgroups-with-builtins.comp | 2 + .../opt/shaders-hlsl/comp/outer-product.comp | 2 + .../opt/shaders-hlsl/comp/rmw-matrix.comp | 2 + .../shaders-hlsl/comp/rwbuffer-matrix.comp | 104 +- ...alar-std450-distance-length-normalize.comp | 2 + .../comp/spec-constant-op-member-array.comp | 1 + .../shaders-hlsl/comp/ssbo-array-length.comp | 2 + .../opt/shaders-hlsl/comp/ssbo-array.comp | 2 + .../comp/subgroups.invalid.nofxc.sm60.comp | 67 - .../shaders-hlsl/frag/bvec-operations.frag | 2 +- .../frag/fp16.invalid.desktop.frag | 45 - .../pixel-interlock-ordered.sm51.fxconly.frag | 24 + .../readonly-coherent-ssbo.force-uav.frag | 21 + .../frag/readonly-coherent-ssbo.frag | 21 + .../asm/comp/atomic-decrement.asm.comp | 1 + .../asm/comp/atomic-increment.asm.comp | 1 + .../asm/comp/bitcast_icmp.asm.comp | 29 + .../comp/buffer-write-relative-addr.asm.comp | 1 + .../asm/comp/buffer-write.asm.comp | 1 + .../asm/frag/line-directive.line.asm.frag | 12 +- .../frag/lut-promotion-initializer.asm.frag | 64 +- .../asm/frag/min-max-clamp.invalid.asm.frag | 9 - .../frag/single-function-private-lut.asm.frag | 45 +- .../storage-class-output-initializer.asm.frag | 45 +- .../asm/frag/texture-atomics.asm.frag | 121 + ...re-atomics.asm.graphics-robust-access.frag | 122 + ...input-array-builtin-array.invalid.asm.tesc | 73 - .../clip-distance-plain-variable.asm.vert | 29 + .../access-private-workgroup-in-function.comp | 2 + ...ffers-discrete.msl2.argument.discrete.comp | 2 + ...rs-image-load-store.ios.msl2.argument.comp | 11 + .../opt/shaders-msl/comp/array-length.comp | 2 + .../array-length.msl2.argument.discrete.comp | 2 + .../opt/shaders-msl/comp/atomic.comp | 2 + .../reference/opt/shaders-msl/comp/basic.comp | 2 + .../shaders-msl/comp/basic.dispatchbase.comp | 38 + .../comp/basic.dispatchbase.msl11.comp | 36 + .../comp/basic.inline-block.msl2.comp | 53 + .../comp/bitcast-16bit-1.invalid.comp | 22 - .../comp/bitcast-16bit-2.invalid.comp | 28 - .../opt/shaders-msl/comp/coherent-block.comp | 2 + .../opt/shaders-msl/comp/coherent-image.comp | 2 + .../complex-composite-constant-array.comp | 59 + .../comp/composite-array-initialization.comp | 62 +- ...ray-initialization.force-native-array.comp | 94 + .../shaders-msl/comp/composite-construct.comp | 58 +- .../comp/copy-array-of-arrays.comp | 2 + ...py-array-of-arrays.force-native-array.comp | 20 + .../opt/shaders-msl/comp/defer-parens.comp | 2 + .../opt/shaders-msl/comp/dowhile.comp | 18 +- .../comp/force-recompile-hooks.swizzle.comp | 82 +- ...vocation-id-writable-ssbo-in-function.comp | 2 +- .../comp/global-invocation-id.comp | 2 +- .../comp/image-atomic-automatic-bindings.comp | 25 + .../comp/image-cube-array-load-store.comp | 2 + .../reference/opt/shaders-msl/comp/image.comp | 2 + .../opt/shaders-msl/comp/insert.comp | 22 +- .../shaders-msl/comp/int64.invalid.msl22.comp | 24 - .../opt/shaders-msl/comp/inverse.comp | 11 +- .../shaders-msl/comp/local-invocation-id.comp | 2 +- .../comp/local-invocation-index.comp | 2 +- .../reference/opt/shaders-msl/comp/mat3.comp | 2 + .../reference/opt/shaders-msl/comp/mod.comp | 4 +- .../reference/opt/shaders-msl/comp/modf.comp | 2 + .../opt/shaders-msl/comp/outer-product.comp | 2 + .../opt/shaders-msl/comp/read-write-only.comp | 2 + .../opt/shaders-msl/comp/rmw-matrix.comp | 2 + .../opt/shaders-msl/comp/rmw-opt.comp | 2 + ...alar-std450-distance-length-normalize.comp | 2 + .../comp/spec-constant-op-member-array.comp | 1 + .../comp/spec-constant-work-group-size.comp | 43 +- .../storage-buffer-std140-vector-array.comp | 91 +- .../opt/shaders-msl/comp/struct-layout.comp | 2 + .../opt/shaders-msl/comp/struct-nested.comp | 2 + .../opt/shaders-msl/comp/struct-packing.comp | 2 + .../opt/shaders-msl/comp/torture-loop.comp | 30 +- .../opt/shaders-msl/comp/type-alias.comp | 2 + .../reference/opt/shaders-msl/comp/udiv.comp | 2 + .../opt/shaders-msl/comp/writable-ssbo.comp | 2 +- .../comp/extended-arithmetic.desktop.comp | 2 + .../tesc/arrayed-output.desktop.sso.tesc | 45 +- .../tesc/struct-copy.desktop.sso.tesc | 6 +- .../vert/clip-cull-distance.desktop.vert | 4 + .../vert/shader-draw-parameters.desktop.vert | 2 +- .../frag/16bit-constants.invalid.frag | 21 - .../frag/array-lut-no-loop-variable.frag | 43 +- .../shaders-msl/frag/array-of-array-lut.frag | 68 + ...wizzle.msl2.argument.discrete.swizzle.frag | 82 +- ...array-of-texture-swizzle.msl2.swizzle.frag | 82 +- .../shaders-msl/frag/buffer-read-write.frag | 1 + .../frag/clip-distance-varying.frag | 67 + .../opt/shaders-msl/frag/constant-array.frag | 52 +- .../shaders-msl/frag/constant-composites.frag | 46 +- .../opt/shaders-msl/frag/for-loop-init.frag | 99 +- .../frag/fp16.desktop.invalid.frag | 16 - ...agment-component-padding.pad-fragment.frag | 47 +- ....device-argument-buffer.argument.msl2.frag | 44 + .../opt/shaders-msl/frag/lut-promotion.frag | 60 +- .../opt/shaders-msl/frag/mrt-array.frag | 43 +- ...pixel-interlock-ordered.msl2.argument.frag | 43 + .../frag/pixel-interlock-ordered.msl2.frag | 33 + ...e-depth-propagate-state-from-resource.frag | 23 + .../frag/shader-arithmetic-8bit.frag | 61 +- .../shadow-compare-global-alias.invalid.frag | 27 - .../shaders-msl/frag/texture-cube-array.frag | 22 + ...ure-cube-array.ios.emulate-cube-array.frag | 58 + .../load-control-point-array-of-matrix.tesc | 73 + .../load-control-point-array-of-struct.tesc | 84 + .../tesc/load-control-point-array.tesc | 70 + .../opt/shaders-msl/tese/input-types.tese | 16 +- .../load-control-point-array-of-matrix.tese | 85 + .../tese/load-control-point-array.tese | 78 + .../shaders-msl/tese/triangle-tess-level.tese | 45 +- .../shaders-msl/vert/clip-distance-block.vert | 29 + .../vert/float-math.invariant-float-math.vert | 137 + .../opt/shaders-msl/vert/float-math.vert | 88 + .../opt/shaders-msl/vert/functions.vert | 15 +- .../shaders-msl/vert/in_out_array_mat.vert | 43 +- .../interface-block-block-composites.frag | 43 +- .../interface-block-block-composites.vert | 43 +- .../opt/shaders-msl/vert/no_stage_out.vert | 2 +- .../vert/read-from-row-major-array.vert | 2 +- .../return-array.force-native-array.vert} | 6 +- .../opt/shaders-msl/vert/sign-int-types.vert | 2 +- .../opt/shaders-msl/vert/texture_buffer.vert | 1 + .../subgroups.nocompat.invalid.vk.msl21.comp | 92 - ...bgroups.nocompat.invalid.vk.msl21.ios.comp | 23 - .../frag/basic.multiview.nocompat.vk.frag | 43 +- ...e-to-helper.vk.nocompat.msl21.invalid.frag | 10 - .../subgroups.nocompat.invalid.vk.msl21.frag | 89 - .../vulkan/vert/vulkan-vertex.vk.vert | 2 +- .../asm/frag/depth-compare.asm.frag | 314 + .../asm/frag/global-constant-arrays.asm.frag | 1141 + .../padded-float-array-member-defef.asm.frag | 1190 + .../asm/frag/sample-mask-not-array.asm.frag | 503 + ...bpass-input.ios.framebuffer-fetch.asm.frag | 213 + .../asm/frag/texture-atomics.asm.frag | 121 + ...re-atomics.asm.graphics-robust-access.frag | 122 + .../asm/tesc/hs-incorrect-base-type.asm.tesc | 399 + .../asm/tesc/hs-input-array-access.asm.tesc | 467 + .../asm/tesc/hs-texcoord-array.asm.tesc | 411 + .../tess-factor-must-be-threadgroup.asm.tesc | 178 + .../asm/tese/ds-double-gl-in-deref.asm.tese | 419 + .../asm/tese/ds-patch-input-fixes.asm.tese | 417 + .../asm/tese/ds-patch-inputs.asm.tese | 216 + .../asm/tese/ds-texcoord-array.asm.tese | 318 + .../asm/vert/array-missing-copies.asm.vert | 464 + .../asm/vert/texture-buffer.asm.vert | 387 + .../shaders/asm/comp/bitcast_icmp.asm.comp | 27 + .../asm/comp/switch-break-ladder.asm.comp | 6 +- .../frag/complex-name-workarounds.asm.frag | 5 +- ...etch-no-sampler.no-samplerless.asm.vk.frag | 13 + ...h-no-sampler.no-samplerless.asm.vk.frag.vk | 14 + ...uery-no-sampler.no-samplerless.vk.asm.frag | 6 + ...y-no-sampler.no-samplerless.vk.asm.frag.vk | 6 + .../asm/frag/line-directive.line.asm.frag | 12 +- ...op-body-dominator-continue-access.asm.frag | 81 +- .../asm/frag/loop-merge-to-continue.asm.frag | 21 - .../frag/selection-merge-to-continue.asm.frag | 24 - .../frag/switch-merge-to-continue.asm.frag | 31 - .../reference/opt/shaders/comp/barriers.comp | 6 - .../reference/opt/shaders/comp/cfg.comp | 14 +- .../reference/opt/shaders/comp/dowhile.comp | 16 +- .../reference/opt/shaders/comp/insert.comp | 20 +- .../reference/opt/shaders/comp/shared.comp | 1 - .../opt/shaders/comp/torture-loop.comp | 28 +- .../shaders/desktop-only/frag/image-size.frag | 12 + .../image-size.no-qualifier-deduction.frag | 12 + .../desktop-only/tesc/basic.desktop.sso.tesc | 2 +- .../tese/triangle.desktop.sso.tese | 2 +- .../opt/shaders/frag/for-loop-init.frag | 99 +- ...temporary-use-continue-block-as-value.frag | 8 +- .../loop-dominator-and-switch-default.frag | 1 - .../shaders/frag/pixel-interlock-ordered.frag | 23 + .../frag/pixel-interlock-unordered.frag | 23 + .../shaders/frag/post-depth-coverage-es.frag | 14 + .../opt/shaders/frag/post-depth-coverage.frag | 4 + .../frag/sample-interlock-ordered.frag | 23 + .../frag/sample-interlock-unordered.frag | 23 + .../frag/selection-block-dominator.frag | 13 +- .../frag/struct-type-unrelated-alias.frag | 9 + .../shaders/geom/geometry-passthrough.geom | 27 + .../opt/shaders/geom/multi-stream.geom | 14 + .../opt/shaders/tese/load-array-of-array.tese | 10 + .../opt/shaders/tese/patch-input-array.tese | 10 + .../vert/transform-feedback-decorations.vert | 22 + .../comp/buffer-reference.nocompat.vk.comp.vk | 22 +- ...shader-arithmetic-8bit.nocompat.vk.frag.vk | 57 +- ...access-chain-load-store-composite.asm.comp | 75 + ...ased-struct-divergent-member-name.asm.comp | 27 + .../comp/bitfield-signed-operations.asm.comp | 105 + .../comp/constant-composite-undef.asm.comp | 2 +- ...torage-buffer-basic.invalid.nofxc.asm.comp | 0 .../asm/frag/empty-struct-in-struct.asm.frag | 37 + ...-interlock-callstack.sm51.fxconly.asm.frag | 32 + ...terlock-control-flow.sm51.fxconly.asm.frag | 42 + ...lock-split-functions.sm51.fxconly.asm.frag | 42 + ...rithmetic-cast.invalid.nofxc.sm60.asm.frag | 30 + ...h-block-case-fallthrough.asm.invalid.frag} | 0 .../asm/frag/unordered-compare.asm.frag | 51 + .../frag/vector-shuffle-undef-index.asm.frag | 2 +- .../shaders-hlsl-no-opt/comp/bitfield.comp | 4 +- .../comp/glsl.std450.fxconly.comp | 2 + .../comp/illegal-struct-name.asm.comp | 22 + .../comp/subgroups.invalid.nofxc.sm60.comp | 2 + .../constant-buffer-array.invalid.sm51.frag | 0 .../frag/fp16.invalid.desktop.frag | 0 ...terlock-simple-callstack.sm51.fxconly.frag | 32 + .../asm/comp/bitcast_icmp.asm.comp | 28 + ...torage-buffer-basic.invalid.nofxc.asm.comp | 32 - .../asm/frag/unreachable.asm.frag | 2 +- .../comp/access-chain-load-composite.comp | 164 + .../shaders-hlsl/comp/access-chains.comp | 2 + .../comp/access-chains.force-uav.comp | 23 + .../shaders-hlsl/comp/address-buffers.comp | 2 + .../reference/shaders-hlsl/comp/atomic.comp | 2 + .../shaders-hlsl/comp/globallycoherent.comp | 2 + .../reference/shaders-hlsl/comp/image.comp | 2 + .../reference/shaders-hlsl/comp/inverse.comp | 2 + .../comp/num-workgroups-alone.comp | 2 + .../comp/num-workgroups-with-builtins.comp | 2 + .../shaders-hlsl/comp/outer-product.comp | 2 + .../shaders-hlsl/comp/rmw-matrix.comp | 2 + .../shaders-hlsl/comp/rwbuffer-matrix.comp | 2 + ...alar-std450-distance-length-normalize.comp | 2 + .../comp/spec-constant-op-member-array.comp | 1 + .../shaders-hlsl/comp/ssbo-array-length.comp | 2 + .../shaders-hlsl/comp/ssbo-array.comp | 2 + .../constant-buffer-array.invalid.sm51.frag | 44 - .../pixel-interlock-ordered.sm51.fxconly.frag | 24 + .../readonly-coherent-ssbo.force-uav.frag | 21 + .../frag/readonly-coherent-ssbo.frag | 21 + ...ased-struct-divergent-member-name.asm.comp | 38 + .../comp/bitfield-signed-operations.asm.comp | 29 + .../asm/comp/bitscan.asm.comp | 6 +- .../asm/comp/copy-logical-2.spv14.asm.comp | 60 + .../asm/comp/copy-logical.spv14.asm.comp | 47 + .../asm/comp/glsl-signed-operations.asm.comp | 6 +- .../storage-buffer-basic.invalid.asm.comp | 0 .../storage-buffer-pointer-argument.asm.comp | 1 + .../asm/comp/variable-pointers.asm.comp | 3 + .../asm/frag/empty-struct-in-struct.asm.frag | 35 + .../inliner-dominator-inside-loop.asm.frag | 235 - ...-frexp-scalar-access-chain-output.asm.frag | 17 + .../pixel-interlock-callstack.msl2.asm.frag | 37 + ...pixel-interlock-control-flow.msl2.asm.frag | 52 + ...el-interlock-split-functions.msl2.asm.frag | 49 + .../subgroup-arithmetic-cast.msl21.asm.frag | 30 + ...h-block-case-fallthrough.asm.invalid.frag} | 0 .../asm/frag/texture-access.swizzle.asm.frag | 47 +- .../composite-extract-row-major.asm.comp | 2 +- ...input-array-builtin-array.invalid.asm.tesc | 72 +- .../asm/vert/empty-struct-composite.asm.vert | 5 +- .../op-load-forced-temporary-array.asm.frag | 43 +- .../comp/array-copy-threadgroup-memory.comp | 118 + .../basic.dynamic-buffer.msl2.invalid.comp | 90 + .../comp/bitcast-16bit-1.invalid.comp | 2 + .../comp/bitcast-16bit-2.invalid.comp | 2 + .../shaders-msl-no-opt/comp/bitfield.comp | 16 +- .../shaders-msl-no-opt/comp/glsl.std450.comp | 23 +- .../comp/illegal-struct-name.asm.comp | 29 + .../comp/int64.invalid.msl22.comp | 106 + .../shaders-msl-no-opt/comp/loop.comp | 24 +- .../shaders-msl-no-opt/comp/return.comp | 5 +- ...std140-array-load-composite-construct.comp | 18 + ...ct-packing-scalar.nocompat.invalid.vk.comp | 2 + .../subgroups.nocompat.invalid.vk.msl21.comp | 2 + ...bgroups.nocompat.invalid.vk.msl21.ios.comp | 2 + .../components/fragment-input-component.frag | 23 + .../components/fragment-output-component.frag | 25 + ...ragment-output-component.pad-fragment.frag | 22 + .../components/vertex-input-component.vert | 28 + .../components/vertex-output-component.vert} | 10 +- .../frag/16bit-constants.invalid.frag | 4 +- ...e-to-helper.vk.nocompat.msl21.invalid.frag | 0 ....msl2.argument..force-active.discrete.frag | 31 + .../frag/fp16.desktop.invalid.frag | 12 +- .../frag/min-max-clamp.invalid.asm.frag | 0 ...pixel-interlock-simple-callstack.msl2.frag | 37 + ...layout-ubo-std430.vk.nocompat.invalid.frag | 0 .../shadow-compare-global-alias.invalid.frag | 4 + .../subgroups.nocompat.invalid.vk.msl21.frag | 0 .../frag/texture-access-int.swizzle.frag | 58 +- .../frag/texture-access-leaf.swizzle.frag | 48 +- .../frag/texture-access-uint.swizzle.frag | 58 +- .../frag/texture-access.swizzle.frag | 47 +- .../packing/array-of-vec3.comp | 17 + .../packing/array-of-vec4.comp | 17 + .../packing/load-store-col-rows.comp | 76 + .../packing/matrix-2x2-scalar.comp | 10 + .../packing/matrix-2x2-std140.comp | 10 + .../packing/matrix-2x2-std430.comp | 10 + .../packing/matrix-2x3-scalar.comp | 10 + .../packing/matrix-2x3-std140.comp | 10 + .../packing/matrix-2x3-std430.comp | 10 + .../packing/matrix-2x4-scalar.comp | 10 + .../packing/matrix-2x4-std140.comp | 10 + .../packing/matrix-2x4-std430.comp | 10 + .../packing/matrix-3x2-scalar.comp | 10 + .../packing/matrix-3x2-std140.comp | 10 + .../packing/matrix-3x2-std430.comp | 10 + .../packing/matrix-3x3-scalar.comp | 10 + .../packing/matrix-3x3-std140.comp | 10 + .../packing/matrix-3x3-std430.comp | 10 + .../packing/matrix-3x4-scalar.comp | 10 + .../packing/matrix-3x4-std140.comp | 10 + .../packing/matrix-3x4-std430.comp | 10 + .../packing/matrix-4x2-scalar.comp | 10 + .../packing/matrix-4x2-std140.comp | 10 + .../packing/matrix-4x2-std430.comp | 10 + .../packing/matrix-4x3-scalar.comp | 10 + .../packing/matrix-4x3-std140.comp | 10 + .../packing/matrix-4x3-std430.comp | 10 + .../packing/matrix-4x4-scalar.comp | 10 + .../packing/matrix-4x4-std140.comp | 10 + .../packing/matrix-4x4-std430.comp | 10 + .../packing/matrix-multiply-row-major.comp | 2 + .../matrix-multiply-unpacked-col-major-2.comp | 2 + .../matrix-multiply-unpacked-col-major.comp | 2 + .../matrix-multiply-unpacked-row-major-2.comp | 2 + .../matrix-multiply-unpacked-row-major.comp | 2 + .../packing/member-padding.comp | 2 + .../packing/std140-array-of-vectors.comp | 2 + .../packing/struct-alignment.comp | 2 + .../struct-packing-array-of-scalar.comp | 2 + .../packing/struct-packing-recursive.comp | 2 + .../packing/struct-packing.comp | 2 + .../struct-size-padding-array-of-array.comp | 2 + .../packing/struct-size-padding.comp | 2 + .../vert/functions_nested.vert | 10 +- .../vert/layer.msl11.invalid.vert | 0 ...ass-array-by-value.force-native-array.vert | 103 + .../vert/pass-array-by-value.vert | 73 +- .../vert/viewport-index.msl2.invalid.vert | 0 .../texture-access-function.swizzle.vk.frag | 48 +- .../asm/comp/atomic-decrement.asm.comp | 1 + .../asm/comp/atomic-increment.asm.comp | 1 + .../asm/comp/bitcast_icmp.asm.comp | 29 + .../comp/buffer-write-relative-addr.asm.comp | 1 + .../asm/comp/buffer-write.asm.comp | 1 + .../comp/global-parameter-name-alias.asm.comp | 2 + .../image-load-store-short-vector.asm.comp | 1 + .../storage-buffer-basic.invalid.asm.comp | 22 - .../struct-resource-name-aliasing.asm.comp | 1 + .../asm/comp/variable-pointers-2.asm.comp | 2 + ...ariable-pointers-store-forwarding.asm.comp | 1 + .../vector-builtin-type-cast-func.asm.comp | 1 + .../asm/frag/empty-struct.asm.frag | 7 +- .../extract-packed-from-composite.asm.frag | 1 + .../asm/frag/function-overload-alias.asm.frag | 4 + .../asm/frag/line-directive.line.asm.frag | 1 + .../frag/lut-promotion-initializer.asm.frag | 64 +- .../asm/frag/op-constant-null.asm.frag | 43 +- .../asm/frag/pass-by-value.asm.frag | 1 + .../frag/single-function-private-lut.asm.frag | 58 +- .../storage-class-output-initializer.asm.frag | 45 +- .../asm/frag/texture-atomics.asm.frag | 121 + ...re-atomics.asm.graphics-robust-access.frag | 121 + .../asm/frag/unknown-depth-state.asm.frag | 2 + .../clip-distance-plain-variable.asm.vert | 49 + ...act-transposed-matrix-from-struct.asm.vert | 1 + .../asm/vert/invariant.msl21.asm.vert | 1 + .../vert/uint-vertex-id-instance-id.asm.vert | 1 + .../access-private-workgroup-in-function.comp | 4 + ...ffers-discrete.msl2.argument.discrete.comp | 2 + ...rs-image-load-store.ios.msl2.argument.comp | 11 + .../shaders-msl/comp/array-length.comp | 3 + .../array-length.msl2.argument.discrete.comp | 3 + .../reference/shaders-msl/comp/atomic.comp | 2 + .../reference/shaders-msl/comp/barriers.comp | 11 + .../reference/shaders-msl/comp/basic.comp | 2 + .../shaders-msl/comp/basic.dispatchbase.comp | 41 + .../comp/basic.dispatchbase.msl11.comp | 39 + .../comp/basic.inline-block.msl2.comp | 54 + .../comp/cfg-preserve-parameter.comp | 4 + .../shaders-msl/comp/coherent-block.comp | 2 + .../shaders-msl/comp/coherent-image.comp | 2 + .../complex-composite-constant-array.comp | 65 + .../shaders-msl/comp/complex-type-alias.comp | 1 + .../comp/composite-array-initialization.comp | 63 +- ...ray-initialization.force-native-array.comp | 104 + .../shaders-msl/comp/composite-construct.comp | 60 +- .../comp/copy-array-of-arrays.comp | 122 +- ...py-array-of-arrays.force-native-array.comp | 202 + .../shaders-msl/comp/defer-parens.comp | 2 + .../reference/shaders-msl/comp/dowhile.comp | 2 + .../comp/force-recompile-hooks.swizzle.comp | 82 +- .../reference/shaders-msl/comp/functions.comp | 1 + ...vocation-id-writable-ssbo-in-function.comp | 3 +- .../comp/global-invocation-id.comp | 2 +- .../comp/image-atomic-automatic-bindings.comp | 26 + .../comp/image-cube-array-load-store.comp | 2 + .../reference/shaders-msl/comp/image.comp | 2 + .../reference/shaders-msl/comp/insert.comp | 2 + .../shaders-msl/comp/int64.invalid.msl22.comp | 63 - .../reference/shaders-msl/comp/inverse.comp | 11 +- .../shaders-msl/comp/local-invocation-id.comp | 2 +- .../comp/local-invocation-index.comp | 2 +- .../reference/shaders-msl/comp/mat3.comp | 2 + .../reference/shaders-msl/comp/mod.comp | 4 +- .../reference/shaders-msl/comp/modf.comp | 2 + .../shaders-msl/comp/outer-product.comp | 2 + .../shaders-msl/comp/read-write-only.comp | 2 + .../shaders-msl/comp/rmw-matrix.comp | 2 + .../reference/shaders-msl/comp/rmw-opt.comp | 2 + ...alar-std450-distance-length-normalize.comp | 2 + .../comp/shared-array-of-arrays.comp | 1 + .../comp/spec-constant-op-member-array.comp | 1 + .../comp/spec-constant-work-group-size.comp | 43 +- .../storage-buffer-std140-vector-array.comp | 51 +- .../shaders-msl/comp/struct-layout.comp | 2 + .../shaders-msl/comp/struct-nested.comp | 2 + .../shaders-msl/comp/struct-packing.comp | 2 + .../shaders-msl/comp/torture-loop.comp | 2 + .../shaders-msl/comp/type-alias.comp | 4 + .../reference/shaders-msl/comp/udiv.comp | 2 + .../shaders-msl/comp/writable-ssbo.comp | 2 +- .../comp/extended-arithmetic.desktop.comp | 2 + .../tesc/arrayed-output.desktop.sso.tesc | 45 +- .../desktop-only/tesc/basic.desktop.sso.tesc | 1 + .../tesc/struct-copy.desktop.sso.tesc | 6 +- .../vert/clip-cull-distance.desktop.vert | 4 + .../vert/shader-draw-parameters.desktop.vert | 2 +- .../frag/argument-buffers.msl2.argument.frag | 2 + .../frag/array-lut-no-loop-variable.frag | 43 +- .../shaders-msl/frag/array-of-array-lut.frag | 68 + ...wizzle.msl2.argument.discrete.swizzle.frag | 85 +- ...array-of-texture-swizzle.msl2.swizzle.frag | 84 +- .../shaders-msl/frag/buffer-read-write.frag | 1 + .../frag/clip-distance-varying.frag | 67 + .../shaders-msl/frag/constant-array.frag | 50 +- .../shaders-msl/frag/constant-composites.frag | 57 +- .../shaders-msl/frag/flush_params.frag | 2 + ...agment-component-padding.pad-fragment.frag | 48 +- .../frag/helper-invocation.msl21.frag | 1 + ....device-argument-buffer.argument.msl2.frag | 58 + .../frag/image-query-lod.msl22.frag | 1 + .../shaders-msl/frag/input-attachment-ms.frag | 1 + .../shaders-msl/frag/input-attachment.frag | 1 + .../shaders-msl/frag/lut-promotion.frag | 64 +- .../reference/shaders-msl/frag/mrt-array.frag | 49 +- .../shaders-msl/frag/packing-test-3.frag | 1 + ...pixel-interlock-ordered.msl2.argument.frag | 43 + .../frag/pixel-interlock-ordered.msl2.frag | 33 + ...rivate-variable-prototype-declaration.frag | 2 + .../shaders-msl/frag/readonly-ssbo.frag | 1 + ...e-depth-propagate-state-from-resource.frag | 43 + .../sample-depth-separate-image-sampler.frag | 2 + .../frag/sample-position-func.frag | 1 + .../frag/sampler-image-arrays.msl2.frag | 3 + .../reference/shaders-msl/frag/sampler.frag | 1 + .../frag/separate-image-sampler-argument.frag | 1 + .../frag/shader-arithmetic-8bit.frag | 8 +- .../frag/stencil-export.msl21.frag | 1 + .../shaders-msl/frag/texture-cube-array.frag | 25 + ...ure-cube-array.ios.emulate-cube-array.frag | 61 + .../frag/write-depth-in-function.frag | 1 + .../load-control-point-array-of-matrix.tesc | 73 + .../load-control-point-array-of-struct.tesc | 86 + .../tesc/load-control-point-array.tesc | 70 + .../shaders-msl/tesc/water_tess.tesc | 5 + .../shaders-msl/tese/input-array.tese | 1 + .../shaders-msl/tese/input-types.tese | 13 +- .../load-control-point-array-of-matrix.tese | 84 + .../tese/load-control-point-array.tese | 81 + .../reference/shaders-msl/tese/quad.tese | 1 + .../shaders-msl/tese/set-from-function.tese | 1 + .../shaders-msl/tese/triangle-tess-level.tese | 45 +- .../shaders-msl/tese/water_tess.tese | 3 + .../shaders-msl/vert/clip-distance-block.vert | 29 + .../vert/float-math.invariant-float-math.vert | 136 + .../shaders-msl/vert/float-math.vert | 87 + .../reference/shaders-msl/vert/functions.vert | 15 +- .../shaders-msl/vert/in_out_array_mat.vert | 47 +- .../interface-block-block-composites.frag | 43 +- .../interface-block-block-composites.vert | 43 +- .../vert/leaf-function.capture.vert | 1 + .../shaders-msl/vert/no_stage_out.vert | 2 +- .../shaders-msl/vert/packed_matrix.vert | 4 +- .../vert/read-from-row-major-array.vert | 3 + .../vert/resource-arrays-leaf.ios.vert | 1 + .../vert/return-array.force-native-array.vert | 100 + .../shaders-msl/vert/return-array.vert | 72 +- .../shaders-msl/vert/set_builtin_in_func.vert | 1 + .../shaders-msl/vert/sign-int-types.vert | 2 +- .../shaders-msl/vert/texture_buffer.vert | 1 + ...ct-packing-scalar.nocompat.invalid.vk.comp | 148 - .../frag/basic.multiview.nocompat.vk.frag | 43 +- ...layout-ubo-std430.vk.nocompat.invalid.frag | 36 - .../vulkan/vert/vulkan-vertex.vk.vert | 2 +- ...ess-tracking-function-call-result.asm.comp | 24 + ...ased-struct-divergent-member-name.asm.comp | 30 + ...c-conversion-signs.asm.nocompat.vk.comp.vk | 4 + .../comp/bitfield-signed-operations.asm.comp | 27 + .../asm/comp/copy-logical.spv14.asm.comp | 45 + .../extended-debug-extinst.invalid.asm.comp | 0 ...orary-copy-loop-variable.asm.invalid.comp} | 7 +- .../storage-buffer-basic.invalid.asm.comp | 0 ...ge-sampler-dxc-min16float.asm.invalid.frag | 28 + ...pure-function-call.vk.nocompat.asm.frag.vk | 22 + .../discard-impure-function-call.asm.frag | 21 + .../do-while-continue-phi.asm.invalid.frag | 37 + .../asm/frag/empty-struct-in-struct.asm.frag | 31 + ...ted-merge-block-inverted.asm.invalid.frag} | 0 ...merge-block-non-inverted.asm.invalid.frag} | 0 .../inliner-dominator-inside-loop.asm.frag | 12 +- .../asm/frag/ldexp-uint-exponent.asm.frag | 11 + .../loop-merge-to-continue.asm.invalid.frag} | 0 .../frag/pixel-interlock-callstack.asm.frag | 39 + .../pixel-interlock-control-flow.asm.frag | 53 + .../pixel-interlock-split-functions.asm.frag | 49 + ...ection-merge-to-continue.asm.invalid.frag} | 2 - ...up-arithmetic-cast.nocompat.vk.asm.frag.vk | 24 + ...h-block-case-fallthrough.asm.invalid.frag} | 0 ...switch-merge-to-continue.asm.invalid.frag} | 0 ...tch-single-case-multiple-exit-cfg.asm.frag | 29 + .../asm/frag/unordered-compare.asm.frag | 33 + ...tor-extract-dynamic-spec-constant.asm.frag | 27 + .../geom/store-uint-layer.invalid.asm.geom | 0 ...input-array-builtin-array.invalid.asm.tesc | 0 .../comp/bitcast-16bit-1.invalid.comp | 0 .../comp/bitcast-16bit-2.invalid.comp | 0 .../comp/illegal-struct-name.asm.comp | 22 + .../comp/inout-struct.invalid.comp | 0 .../reference/shaders-no-opt/comp/loop.comp | 25 - .../reference/shaders-no-opt/comp/return.comp | 3 +- ...ballot_nonuniform_invocations.invalid.comp | 0 ...packing-scalar.nocompat.invalid.vk.comp.vk | 0 .../subgroups.nocompat.invalid.vk.comp.vk | 0 .../frag/16bit-constants.invalid.frag | 0 .../frag/fp16.invalid.desktop.frag | 0 ...h_subpassInput.vk.nocompat.invalid.frag.vk | 0 .../frag}/fs.invalid.frag | 0 ...mensional.desktop.invalid.flatten_dim.frag | 0 .../pixel-interlock-simple-callstack.frag | 34 + ...out-ubo-std430.vk.nocompat.invalid.frag.vk | 0 .../aliased-entry-point-names.asm.multi.json | 6 + .../asm/op-source-glsl-ssbo-1.asm.comp.json | 18 +- .../asm/op-source-glsl-ssbo-2.asm.comp.json | 24 +- .../asm/op-source-hlsl-uav-1.asm.comp.json | 18 +- .../asm/op-source-hlsl-uav-2.asm.comp.json | 18 +- .../asm/op-source-none-ssbo-1.asm.comp.json | 18 +- .../asm/op-source-none-ssbo-2.asm.comp.json | 24 +- .../asm/op-source-none-uav-1.asm.comp.json | 18 +- .../asm/op-source-none-uav-2.asm.comp.json | 18 +- .../comp/struct-layout.comp.json | 27 +- .../comp/struct-packing.comp.json | 198 +- .../workgroup-size-spec-constant.comp.json | 59 + ...eparate-sampler-texture-array.vk.frag.json | 12 + .../frag/spec-constant.vk.frag.json | 11 + .../vert/array-size-reflection.vert.json | 77 + .../vert/read-from-row-major-array.vert.json | 10 +- .../vert/stride-reflection.vert.json | 96 + ...schain-invalid-expression.asm.invalid.frag | 366 + .../frag/array-copy-error.asm.invalid.frag | 350 + .../phi-variable-declaration.asm.invalid.frag | 350 + ...-accesschain-writethrough.asm.invalid.vert | 122 + .../asm/frag/depth-compare.asm.frag | 314 + .../asm/frag/global-constant-arrays.asm.frag | 1365 ++ .../padded-float-array-member-defef.asm.frag | 1414 ++ .../asm/frag/sample-mask-not-array.asm.frag | 503 + ...bpass-input.ios.framebuffer-fetch.asm.frag | 213 + .../asm/frag/texture-atomics.asm.frag | 121 + ...re-atomics.asm.graphics-robust-access.frag | 121 + .../asm/tesc/hs-incorrect-base-type.asm.tesc | 399 + .../asm/tesc/hs-input-array-access.asm.tesc | 467 + .../asm/tesc/hs-texcoord-array.asm.tesc | 411 + .../tess-factor-must-be-threadgroup.asm.tesc | 178 + .../asm/tese/ds-double-gl-in-deref.asm.tese | 420 + .../asm/tese/ds-patch-input-fixes.asm.tese | 417 + .../asm/tese/ds-patch-inputs.asm.tese | 217 + .../asm/tese/ds-texcoord-array.asm.tese | 318 + .../asm/vert/array-missing-copies.asm.vert | 466 + .../asm/vert/texture-buffer.asm.vert | 387 + ...h_subpassInput.vk.nocompat.invalid.frag.vk | 11 - .../reference/shaders/amd/fs.invalid.frag | 15 - ...ballot_nonuniform_invocations.invalid.comp | 11 - .../shaders/asm/comp/bitcast_icmp.asm.comp | 27 + .../phi-temporary-copy-loop-variable.asm.comp | 25 - .../storage-buffer-basic.invalid.asm.comp | 28 - .../extended-debug-extinst.invalid.asm.comp | 18 - .../frag/for-loop-phi-only-continue.asm.frag | 1 - ...etch-no-sampler.no-samplerless.asm.vk.frag | 38 + ...h-no-sampler.no-samplerless.asm.vk.frag.vk | 37 + ...uery-no-sampler.no-samplerless.vk.asm.frag | 13 + ...y-no-sampler.no-samplerless.vk.asm.frag.vk | 14 + .../frag/op-phi-swap-continue-block.asm.frag | 1 - .../geom/store-uint-layer.invalid.asm.geom | 41 - ...input-array-builtin-array.invalid.asm.tesc | 79 - .../reference/shaders/comp/barriers.comp | 6 - .../shaders/comp/bitcast-16bit-1.invalid.comp | 34 - .../shaders/comp/bitcast-16bit-2.invalid.comp | 39 - .../shaders/comp/inout-struct.invalid.comp | 65 - .../reference/shaders/comp/shared.comp | 1 - .../frag/fp16.invalid.desktop.frag | 159 - .../shaders/desktop-only/frag/image-size.frag | 12 + .../image-size.no-qualifier-deduction.frag | 12 + .../desktop-only/tesc/basic.desktop.sso.tesc | 2 +- .../tese/triangle.desktop.sso.tese | 2 +- ...mensional.desktop.invalid.flatten_dim.frag | 24 - .../shaders/frag/16bit-constants.invalid.frag | 25 - .../shaders/frag/pixel-interlock-ordered.frag | 23 + .../frag/pixel-interlock-unordered.frag | 23 + .../shaders/frag/post-depth-coverage-es.frag | 14 + .../shaders/frag/post-depth-coverage.frag | 4 + .../frag/sample-interlock-ordered.frag | 23 + .../frag/sample-interlock-unordered.frag | 23 + .../frag/struct-type-unrelated-alias.frag | 23 + .../shaders/geom/geometry-passthrough.geom | 27 + .../reference/shaders/geom/multi-stream.geom | 14 + .../shaders/tese/load-array-of-array.tese | 16 + .../shaders/tese/patch-input-array.tese | 10 + .../vert/transform-feedback-decorations.vert | 22 + ...packing-scalar.nocompat.invalid.vk.comp.vk | 147 - .../subgroups.nocompat.invalid.vk.comp.vk | 110 - ...out-ubo-std430.vk.nocompat.invalid.frag.vk | 24 - ...access-chain-load-store-composite.asm.comp | 118 + ...ased-struct-divergent-member-name.asm.comp | 77 + .../comp/bitfield-signed-operations.asm.comp | 97 + ...torage-buffer-basic.invalid.nofxc.asm.comp | 0 .../asm/frag/empty-struct-in-struct.asm.frag | 61 + ...-interlock-callstack.sm51.fxconly.asm.frag | 89 + ...terlock-control-flow.sm51.fxconly.asm.frag | 121 + ...lock-split-functions.sm51.fxconly.asm.frag | 102 + ...rithmetic-cast.invalid.nofxc.sm60.asm.frag | 65 + ...h-block-case-fallthrough.asm.invalid.frag} | 0 .../asm/frag/unordered-compare.asm.frag | 177 + .../comp/illegal-struct-name.asm.comp | 62 + .../comp/subgroups.invalid.nofxc.sm60.comp | 0 .../constant-buffer-array.invalid.sm51.frag | 0 .../frag/fp16.invalid.desktop.frag | 0 ...terlock-simple-callstack.sm51.fxconly.frag | 31 + .../asm/comp/bitcast_icmp.asm.comp | 101 + .../comp/access-chain-load-composite.comp | 35 + .../comp/access-chains.force-uav.comp | 24 + .../pixel-interlock-ordered.sm51.fxconly.frag | 36 + .../readonly-coherent-ssbo.force-uav.frag | 12 + .../frag/readonly-coherent-ssbo.frag | 12 + ...ased-struct-divergent-member-name.asm.comp | 77 + .../comp/bitfield-signed-operations.asm.comp | 97 + .../asm/comp/copy-logical-2.spv14.asm.comp | 81 + .../asm/comp/copy-logical.spv14.asm.comp | 69 + .../storage-buffer-basic.invalid.asm.comp | 0 .../asm/frag/empty-struct-in-struct.asm.frag | 61 + .../inliner-dominator-inside-loop.asm.frag | 646 - ...-frexp-scalar-access-chain-output.asm.frag | 36 + .../pixel-interlock-callstack.msl2.asm.frag | 89 + ...pixel-interlock-control-flow.msl2.asm.frag | 121 + ...el-interlock-split-functions.msl2.asm.frag | 102 + .../subgroup-arithmetic-cast.msl21.asm.frag | 65 + ...h-block-case-fallthrough.asm.invalid.frag} | 0 ...input-array-builtin-array.invalid.asm.tesc | 0 .../comp/array-copy-threadgroup-memory.comp | 18 + .../basic.dynamic-buffer.msl2.invalid.comp | 27 + .../comp/bitcast-16bit-1.invalid.comp | 0 .../comp/bitcast-16bit-2.invalid.comp | 0 .../comp/illegal-struct-name.asm.comp | 62 + .../comp/int64.invalid.msl22.comp | 0 ...std140-array-load-composite-construct.comp | 13 + ...ct-packing-scalar.nocompat.invalid.vk.comp | 0 .../subgroups.nocompat.invalid.vk.msl21.comp | 0 ...bgroups.nocompat.invalid.vk.msl21.ios.comp | 0 .../components/fragment-input-component.frag | 10 + .../components/fragment-output-component.frag | 12 + ...ragment-output-component.pad-fragment.frag | 10 + .../components/vertex-input-component.vert | 11 + .../components/vertex-output-component.vert | 12 + .../frag/16bit-constants.invalid.frag | 0 ...e-to-helper.vk.nocompat.msl21.invalid.frag | 0 ....msl2.argument..force-active.discrete.frag | 15 + .../frag/fp16.desktop.invalid.frag | 0 .../frag/min-max-clamp.invalid.asm.frag | 0 ...pixel-interlock-simple-callstack.msl2.frag | 31 + ...layout-ubo-std430.vk.nocompat.invalid.frag | 0 .../shadow-compare-global-alias.invalid.frag | 0 .../subgroups.nocompat.invalid.vk.msl21.frag | 0 .../packing/array-of-vec3.comp | 13 + .../packing/array-of-vec4.comp | 13 + .../packing/load-store-col-rows.comp | 59 + .../vert/layer.msl11.invalid.vert | 0 ...ass-array-by-value.force-native-array.vert | 26 + .../vert/viewport-index.msl2.invalid.vert | 0 .../asm/comp/bitcast_icmp.asm.comp | 101 + .../clip-distance-plain-variable.asm.vert | 91 + ...rs-image-load-store.ios.msl2.argument.comp | 10 + .../shaders-msl/comp/basic.dispatchbase.comp | 29 + .../comp/basic.dispatchbase.msl11.comp | 29 + .../comp/basic.inline-block.msl2.comp | 37 + .../complex-composite-constant-array.comp | 19 + ...ray-initialization.force-native-array.comp | 28 + ...py-array-of-arrays.force-native-array.comp | 21 + .../comp/image-atomic-automatic-bindings.comp | 16 + .../shaders-msl/frag/array-of-array-lut.frag | 12 + .../frag/clip-distance-varying.frag | 10 + ....device-argument-buffer.argument.msl2.frag | 26 + ...pixel-interlock-ordered.msl2.argument.frag | 36 + .../frag/pixel-interlock-ordered.msl2.frag | 36 + ...e-depth-propagate-state-from-resource.frag | 29 + .../shaders-msl/frag/texture-cube-array.frag | 16 + ...ure-cube-array.ios.emulate-cube-array.frag | 16 + .../load-control-point-array-of-matrix.tesc | 12 + .../load-control-point-array-of-struct.tesc | 21 + .../tesc/load-control-point-array.tesc | 12 + .../load-control-point-array-of-matrix.tese | 13 + .../tese/load-control-point-array.tese | 13 + .../shaders-msl/vert/clip-distance-block.vert | 15 + .../vert/float-math.invariant-float-math.vert | 25 + .../shaders-msl/vert/float-math.vert | 25 + .../vert/return-array.force-native-array.vert | 22 + ...ess-tracking-function-call-result.asm.comp | 54 + ...ased-struct-divergent-member-name.asm.comp | 77 + ...etic-conversion-signs.asm.nocompat.vk.comp | 12 + .../comp/bitfield-signed-operations.asm.comp | 97 + .../asm/comp/copy-logical.spv14.asm.comp | 69 + .../extended-debug-extinst.invalid.asm.comp | 0 ...orary-copy-loop-variable.asm.invalid.comp} | 0 .../storage-buffer-basic.invalid.asm.comp | 0 ...ge-sampler-dxc-min16float.asm.invalid.frag | 95 + ...-impure-function-call.vk.nocompat.asm.frag | 63 + .../discard-impure-function-call.asm.frag | 59 + .../do-while-continue-phi.asm.invalid.frag | 64 + .../asm/frag/empty-struct-in-struct.asm.frag | 61 + ...ted-merge-block-inverted.asm.invalid.frag} | 0 ...merge-block-non-inverted.asm.invalid.frag} | 0 .../asm/frag/ldexp-uint-exponent.asm.frag | 36 + .../loop-merge-to-continue.asm.invalid.frag} | 0 .../frag/pixel-interlock-callstack.asm.frag | 89 + .../pixel-interlock-control-flow.asm.frag | 121 + .../pixel-interlock-split-functions.asm.frag | 102 + ...ection-merge-to-continue.asm.invalid.frag} | 0 ...group-arithmetic-cast.nocompat.vk.asm.frag | 65 + ...h-block-case-fallthrough.asm.invalid.frag} | 0 ...switch-merge-to-continue.asm.invalid.frag} | 0 ...tch-single-case-multiple-exit-cfg.asm.frag | 57 + .../asm/frag/unordered-compare.asm.frag | 177 + ...tor-extract-dynamic-spec-constant.asm.frag | 49 + .../geom/store-uint-layer.invalid.asm.geom | 0 ...input-array-builtin-array.invalid.asm.tesc | 0 .../comp/bitcast-16bit-1.invalid.comp | 0 .../comp/bitcast-16bit-2.invalid.comp | 0 .../comp/illegal-struct-name.asm.comp | 62 + .../comp/inout-struct.invalid.comp | 0 ...ballot_nonuniform_invocations.invalid.comp | 0 ...ct-packing-scalar.nocompat.invalid.vk.comp | 0 .../comp/subgroups.nocompat.invalid.vk.comp | 0 .../frag/16bit-constants.invalid.frag | 0 .../frag/fp16.invalid.desktop.frag | 0 ...etch_subpassInput.vk.nocompat.invalid.frag | 0 .../frag}/fs.invalid.frag | 0 ...mensional.desktop.invalid.flatten_dim.frag | 0 .../pixel-interlock-simple-callstack.frag | 31 + ...layout-ubo-std430.vk.nocompat.invalid.frag | 0 .../comp/workgroup-size-spec-constant.comp | 13 + .../vert/array-size-reflection.vert | 13 + .../vert/stride-reflection.vert | 14 + ...schain-invalid-expression.asm.invalid.frag | 1087 + .../frag/array-copy-error.asm.invalid.frag | 878 + .../phi-variable-declaration.asm.invalid.frag | 878 + ...-accesschain-writethrough.asm.invalid.vert | 259 + .../asm/frag/depth-compare.asm.frag | 961 + .../asm/frag/global-constant-arrays.asm.frag | 3556 +++ .../padded-float-array-member-defef.asm.frag | 3694 ++++ .../asm/frag/sample-mask-not-array.asm.frag | 1230 ++ ...bpass-input.ios.framebuffer-fetch.asm.frag | 589 + .../asm/frag/texture-atomics.asm.frag | 242 + ...re-atomics.asm.graphics-robust-access.frag | 242 + .../asm/tesc/hs-incorrect-base-type.asm.tesc | 1158 + .../asm/tesc/hs-input-array-access.asm.tesc | 1264 ++ .../asm/tesc/hs-texcoord-array.asm.tesc | 1144 + .../tess-factor-must-be-threadgroup.asm.tesc | 352 + .../asm/tese/ds-double-gl-in-deref.asm.tese | 1046 + .../asm/tese/ds-patch-input-fixes.asm.tese | 1175 + .../asm/tese/ds-patch-inputs.asm.tese | 547 + .../asm/tese/ds-texcoord-array.asm.tese | 715 + .../asm/vert/array-missing-copies.asm.vert | 1131 + .../asm/vert/texture-buffer.asm.vert | 1054 + .../shaders/asm/comp/bitcast_icmp.asm.comp | 101 + ...etch-no-sampler.no-samplerless.asm.vk.frag | 163 + ...uery-no-sampler.no-samplerless.vk.asm.frag | 57 + .../shaders/desktop-only/frag/image-size.frag | 10 + .../image-size.no-qualifier-deduction.frag | 10 + .../shaders/frag/pixel-interlock-ordered.frag | 22 + .../frag/pixel-interlock-unordered.frag | 22 + .../shaders/frag/post-depth-coverage-es.frag | 13 + .../frag/sample-interlock-ordered.frag | 22 + .../frag/sample-interlock-unordered.frag | 22 + .../frag/struct-type-unrelated-alias.frag | 19 + .../shaders/geom/geometry-passthrough.geom | 28 + .../shaders/geom/multi-stream.geom | 15 + .../shaders/tese/load-array-of-array.tese | 10 + .../shaders/tese/patch-input-array.tese | 9 + .../vert/transform-feedback-decorations.vert | 20 + third_party/spirv-cross/spirv.h | 49 +- third_party/spirv-cross/spirv.hpp | 49 +- third_party/spirv-cross/spirv_cfg.cpp | 112 +- third_party/spirv-cross/spirv_cfg.hpp | 12 +- third_party/spirv-cross/spirv_common.hpp | 404 +- third_party/spirv-cross/spirv_cpp.cpp | 2 +- third_party/spirv-cross/spirv_cpp.hpp | 2 +- third_party/spirv-cross/spirv_cross.cpp | 676 +- third_party/spirv-cross/spirv_cross.hpp | 199 +- third_party/spirv-cross/spirv_cross_c.cpp | 315 +- third_party/spirv-cross/spirv_cross_c.h | 153 +- .../spirv-cross/spirv_cross_containers.hpp | 83 +- .../spirv_cross_error_handling.hpp | 8 +- .../spirv-cross/spirv_cross_parsed_ir.cpp | 121 +- .../spirv-cross/spirv_cross_parsed_ir.hpp | 62 +- third_party/spirv-cross/spirv_cross_util.cpp | 2 +- third_party/spirv-cross/spirv_cross_util.hpp | 2 +- third_party/spirv-cross/spirv_glsl.cpp | 1537 +- third_party/spirv-cross/spirv_glsl.hpp | 77 +- third_party/spirv-cross/spirv_hlsl.cpp | 626 +- third_party/spirv-cross/spirv_hlsl.hpp | 92 +- third_party/spirv-cross/spirv_msl.cpp | 4377 +++- third_party/spirv-cross/spirv_msl.hpp | 328 +- third_party/spirv-cross/spirv_parser.cpp | 27 +- third_party/spirv-cross/spirv_parser.hpp | 2 +- third_party/spirv-cross/spirv_reflect.cpp | 59 +- third_party/spirv-cross/spirv_reflect.hpp | 2 +- third_party/spirv-cross/test_shaders.py | 121 +- third_party/spirv-cross/test_shaders.sh | 25 +- .../tests-other/hlsl_resource_binding.spv | Bin 0 -> 796 bytes .../tests-other/hlsl_resource_bindings.cpp | 89 + .../tests-other/msl_ycbcr_conversion_test.cpp | 103 + .../tests-other/msl_ycbcr_conversion_test.spv | Bin 0 -> 728 bytes .../msl_ycbcr_conversion_test_2.spv | Bin 0 -> 840 bytes .../spirv-cross/tests-other/small_vector.cpp | 2 +- .../spirv-cross/tests-other/typed_id_test.cpp | 49 + .../spirv-cross/update_test_shaders.sh | 23 +- third_party/spirv-tools/.appveyor.yml | 6 +- third_party/spirv-tools/.gitignore | 12 + third_party/spirv-tools/Android.mk | 134 +- third_party/spirv-tools/BUILD.bazel | 511 + third_party/spirv-tools/BUILD.gn | 642 +- third_party/spirv-tools/CHANGES | 403 +- third_party/spirv-tools/CMakeLists.txt | 91 +- third_party/spirv-tools/CODE_OF_CONDUCT.md | 1 + third_party/spirv-tools/CONTRIBUTING.md | 2 +- third_party/spirv-tools/DEPS | 166 +- third_party/spirv-tools/FILAMENT_README.md | 6 + third_party/spirv-tools/README.md | 202 +- third_party/spirv-tools/WORKSPACE | 19 + third_party/spirv-tools/build_defs.bzl | 291 + .../spirv-tools/cmake/setup_build.cmake | 20 - third_party/spirv-tools/docs/downloads.md | 14 + .../spirv-tools/{ => docs}/projects.md | 0 third_party/spirv-tools/{ => docs}/syntax.md | 0 .../examples/cpp-interface/main.cpp | 5 +- .../spirv-tools/external/CMakeLists.txt | 89 +- .../external/spirv-headers/.gitignore | 1 + .../external/spirv-headers/CMakeLists.txt | 89 +- .../external/spirv-headers/README.md | 60 +- .../spirv-headers/include/spirv/1.2/spirv.py | 0 .../spirv-headers/include/spirv/spir-v.xml | 35 +- .../include/spirv/unified1/OpenCL.std.h | 188 +- .../spirv/unified1/spirv.core.grammar.json | 3798 +++- .../include/spirv/unified1/spirv.h | 889 +- .../include/spirv/unified1/spirv.hpp | 887 +- .../include/spirv/unified1/spirv.hpp11 | 887 +- .../include/spirv/unified1/spirv.json | 353 +- .../include/spirv/unified1/spirv.lua | 353 +- .../include/spirv/unified1/spirv.py | 353 +- .../tools/buildHeaders/CMakeLists.txt | 0 .../tools/buildHeaders/bin/makeHeaders | 2 +- .../tools/buildHeaders/header.cpp | 170 +- .../spirv-headers/tools/buildHeaders/header.h | 14 +- .../tools/buildHeaders/jsonToSpirv.cpp | 53 +- .../tools/buildHeaders/jsonToSpirv.h | 50 +- .../spirv-headers/tools/buildHeaders/main.cpp | 20 +- .../filament-specific-changes.patch | 118 + .../include/spirv-tools/instrument.hpp | 259 + .../include/spirv-tools/libspirv.h | 237 +- .../include/spirv-tools/libspirv.hpp | 166 +- .../include/spirv-tools/optimizer.hpp | 272 +- .../spirv-tools/kokoro/android/build.sh | 2 +- .../linux-clang-asan/build.sh} | 25 +- .../kokoro/linux-clang-asan/continuous.cfg | 16 + .../kokoro/linux-clang-asan/presubmit.cfg | 16 + .../kokoro/linux-clang-debug/continuous.cfg | 6 + .../kokoro/linux-clang-release-bazel/build.sh | 42 + .../linux-clang-release-bazel/continuous.cfg | 16 + .../linux-clang-release-bazel/presubmit.cfg | 16 + .../kokoro/linux-clang-release/continuous.cfg | 6 + .../kokoro/linux-gcc-debug/continuous.cfg | 6 + .../kokoro/linux-gcc-release/continuous.cfg | 6 + .../kokoro/macos-clang-debug/continuous.cfg | 6 + .../kokoro/macos-clang-release-bazel/build.sh | 43 + .../macos-clang-release-bazel/continuous.cfg | 16 + .../macos-clang-release-bazel/presubmit.cfg | 16 + .../kokoro/macos-clang-release/continuous.cfg | 6 + .../spirv-tools/kokoro/scripts/linux/build.sh | 18 +- .../spirv-tools/kokoro/scripts/macos/build.sh | 21 +- .../kokoro/scripts/windows/build.bat | 46 +- .../kokoro/shaderc-smoketest/build.sh | 71 + .../kokoro/shaderc-smoketest/continuous.cfg | 17 + .../kokoro/shaderc-smoketest/presubmit.cfg | 17 + .../windows-msvc-2015-release-bazel/build.bat | 59 + .../continuous.cfg | 16 + .../presubmit.cfg | 16 + .../windows-msvc-2017-debug/continuous.cfg | 6 + .../windows-msvc-2017-release/continuous.cfg | 6 + third_party/spirv-tools/source/CMakeLists.txt | 173 +- .../spirv-tools/source/assembly_grammar.cpp | 5 +- third_party/spirv-tools/source/binary.cpp | 42 +- .../spirv-tools/source/comp/CMakeLists.txt | 52 - .../spirv-tools/source/comp/bit_stream.cpp | 348 - .../spirv-tools/source/comp/bit_stream.h | 280 - .../spirv-tools/source/comp/huffman_codec.h | 389 - third_party/spirv-tools/source/comp/markv.cpp | 112 - third_party/spirv-tools/source/comp/markv.h | 74 - .../spirv-tools/source/comp/markv_codec.cpp | 793 - .../spirv-tools/source/comp/markv_codec.h | 337 - .../spirv-tools/source/comp/markv_decoder.cpp | 925 - .../spirv-tools/source/comp/markv_decoder.h | 175 - .../spirv-tools/source/comp/markv_encoder.cpp | 486 - .../spirv-tools/source/comp/markv_encoder.h | 167 - .../spirv-tools/source/comp/markv_logger.h | 93 - .../spirv-tools/source/comp/markv_model.h | 232 - .../spirv-tools/source/comp/move_to_front.cpp | 456 - .../spirv-tools/source/comp/move_to_front.h | 384 - .../spirv-tools/source/disassemble.cpp | 22 +- third_party/spirv-tools/source/enum_set.h | 20 + third_party/spirv-tools/source/ext_inst.cpp | 33 +- third_party/spirv-tools/source/ext_inst.h | 6 + .../extinst.opencl.debuginfo.100.grammar.json | 632 + .../spirv-tools/source/fuzz/CMakeLists.txt | 230 + .../source/fuzz/data_descriptor.cpp | 69 + .../spirv-tools/source/fuzz/data_descriptor.h | 48 + .../source/fuzz/equivalence_relation.h | 237 + .../spirv-tools/source/fuzz/fact_manager.cpp | 1032 + .../spirv-tools/source/fuzz/fact_manager.h | 203 + .../source/fuzz/force_render_red.cpp | 370 + .../source/fuzz/force_render_red.h | 48 + .../spirv-tools/source/fuzz/fuzzer.cpp | 268 + third_party/spirv-tools/source/fuzz/fuzzer.h | 80 + .../source/fuzz/fuzzer_context.cpp | 149 + .../spirv-tools/source/fuzz/fuzzer_context.h | 191 + .../spirv-tools/source/fuzz/fuzzer_pass.cpp | 258 + .../spirv-tools/source/fuzz/fuzzer_pass.h | 156 + .../fuzz/fuzzer_pass_add_composite_types.cpp | 138 + .../fuzz/fuzzer_pass_add_composite_types.h | 61 + .../fuzz/fuzzer_pass_add_dead_blocks.cpp | 64 + .../source/fuzz/fuzzer_pass_add_dead_blocks.h | 39 + .../fuzz/fuzzer_pass_add_dead_breaks.cpp | 95 + .../source/fuzz/fuzzer_pass_add_dead_breaks.h | 38 + .../fuzz/fuzzer_pass_add_dead_continues.cpp | 59 + .../fuzz/fuzzer_pass_add_dead_continues.h | 39 + ...er_pass_add_no_contraction_decorations.cpp | 61 + ...zzer_pass_add_no_contraction_decorations.h | 39 + .../fuzzer_pass_add_useful_constructs.cpp | 214 + .../fuzz/fuzzer_pass_add_useful_constructs.h | 46 + .../fuzzer_pass_adjust_function_controls.cpp | 73 + .../fuzzer_pass_adjust_function_controls.h | 39 + .../fuzz/fuzzer_pass_adjust_loop_controls.cpp | 121 + .../fuzz/fuzzer_pass_adjust_loop_controls.h | 39 + ...zzer_pass_adjust_memory_operands_masks.cpp | 113 + ...fuzzer_pass_adjust_memory_operands_masks.h | 40 + .../fuzzer_pass_adjust_selection_controls.cpp | 76 + .../fuzzer_pass_adjust_selection_controls.h | 39 + .../fuzz/fuzzer_pass_apply_id_synonyms.cpp | 147 + .../fuzz/fuzzer_pass_apply_id_synonyms.h | 42 + .../fuzz/fuzzer_pass_construct_composites.cpp | 362 + .../fuzz/fuzzer_pass_construct_composites.h | 79 + .../source/fuzz/fuzzer_pass_copy_objects.cpp | 80 + .../source/fuzz/fuzzer_pass_copy_objects.h | 38 + .../fuzz/fuzzer_pass_donate_modules.cpp | 748 + .../source/fuzz/fuzzer_pass_donate_modules.h | 93 + .../source/fuzz/fuzzer_pass_merge_blocks.cpp | 65 + .../source/fuzz/fuzzer_pass_merge_blocks.h | 38 + .../fuzz/fuzzer_pass_obfuscate_constants.cpp | 458 + .../fuzz/fuzzer_pass_obfuscate_constants.h | 107 + .../fuzz/fuzzer_pass_outline_functions.cpp | 99 + .../fuzz/fuzzer_pass_outline_functions.h | 40 + .../fuzz/fuzzer_pass_permute_blocks.cpp | 82 + .../source/fuzz/fuzzer_pass_permute_blocks.h | 39 + .../source/fuzz/fuzzer_pass_split_blocks.cpp | 106 + .../source/fuzz/fuzzer_pass_split_blocks.h | 39 + .../spirv-tools/source/fuzz/fuzzer_util.cpp | 397 + .../spirv-tools/source/fuzz/fuzzer_util.h | 145 + .../source/fuzz/id_use_descriptor.cpp | 62 + .../source/fuzz/id_use_descriptor.h | 47 + .../source/fuzz/instruction_descriptor.cpp | 127 + .../source/fuzz/instruction_descriptor.h | 53 + .../source/fuzz/instruction_message.cpp | 68 + .../source/fuzz/instruction_message.h | 43 + .../fuzz/protobufs/spirvfuzz_protobufs.h | 52 + .../source/fuzz/protobufs/spvtoolsfuzz.proto | 942 + .../source/fuzz/pseudo_random_generator.cpp | 47 + .../source/fuzz/pseudo_random_generator.h | 47 + .../source/fuzz/random_generator.cpp | 25 + .../source/fuzz/random_generator.h | 45 + .../spirv-tools/source/fuzz/replayer.cpp | 134 + .../spirv-tools/source/fuzz/replayer.h | 74 + .../spirv-tools/source/fuzz/shrinker.cpp | 244 + .../spirv-tools/source/fuzz/shrinker.h | 92 + .../source/fuzz/transformation.cpp | 177 + .../spirv-tools/source/fuzz/transformation.h | 100 + .../transformation_add_constant_boolean.cpp | 64 + .../transformation_add_constant_boolean.h | 51 + .../transformation_add_constant_composite.cpp | 130 + .../transformation_add_constant_composite.h | 58 + .../transformation_add_constant_scalar.cpp | 87 + .../fuzz/transformation_add_constant_scalar.h | 55 + .../fuzz/transformation_add_dead_block.cpp | 169 + .../fuzz/transformation_add_dead_block.h | 63 + .../fuzz/transformation_add_dead_break.cpp | 207 + .../fuzz/transformation_add_dead_break.h | 84 + .../fuzz/transformation_add_dead_continue.cpp | 151 + .../fuzz/transformation_add_dead_continue.h | 81 + .../fuzz/transformation_add_function.cpp | 921 + .../source/fuzz/transformation_add_function.h | 124 + .../fuzz/transformation_add_global_undef.cpp | 62 + .../fuzz/transformation_add_global_undef.h | 51 + .../transformation_add_global_variable.cpp | 137 + .../fuzz/transformation_add_global_variable.h | 61 + ...ormation_add_no_contraction_decoration.cpp | 110 + ...sformation_add_no_contraction_decoration.h | 58 + .../fuzz/transformation_add_type_array.cpp | 88 + .../fuzz/transformation_add_type_array.h | 55 + .../fuzz/transformation_add_type_boolean.cpp | 61 + .../fuzz/transformation_add_type_boolean.h | 50 + .../fuzz/transformation_add_type_float.cpp | 65 + .../fuzz/transformation_add_type_float.h | 51 + .../fuzz/transformation_add_type_function.cpp | 113 + .../fuzz/transformation_add_type_function.h | 59 + .../fuzz/transformation_add_type_int.cpp | 68 + .../source/fuzz/transformation_add_type_int.h | 52 + .../fuzz/transformation_add_type_matrix.cpp | 71 + .../fuzz/transformation_add_type_matrix.h | 53 + .../fuzz/transformation_add_type_pointer.cpp | 65 + .../fuzz/transformation_add_type_pointer.h | 53 + .../fuzz/transformation_add_type_struct.cpp | 73 + .../fuzz/transformation_add_type_struct.h | 54 + .../fuzz/transformation_add_type_vector.cpp | 69 + .../fuzz/transformation_add_type_vector.h | 53 + .../transformation_composite_construct.cpp | 305 + .../fuzz/transformation_composite_construct.h | 88 + .../fuzz/transformation_composite_extract.cpp | 125 + .../fuzz/transformation_composite_extract.h | 63 + .../fuzz/transformation_copy_object.cpp | 117 + .../source/fuzz/transformation_copy_object.h | 72 + .../fuzz/transformation_merge_blocks.cpp | 81 + .../source/fuzz/transformation_merge_blocks.h | 54 + .../fuzz/transformation_move_block_down.cpp | 109 + .../fuzz/transformation_move_block_down.h | 54 + .../fuzz/transformation_outline_function.cpp | 943 + .../fuzz/transformation_outline_function.h | 221 + ..._boolean_constant_with_constant_binary.cpp | 304 + ...ce_boolean_constant_with_constant_binary.h | 76 + ...ormation_replace_constant_with_uniform.cpp | 235 + ...sformation_replace_constant_with_uniform.h | 91 + ...transformation_replace_id_with_synonym.cpp | 195 + .../transformation_replace_id_with_synonym.h | 80 + .../transformation_set_function_control.cpp | 100 + .../transformation_set_function_control.h | 58 + .../fuzz/transformation_set_loop_control.cpp | 216 + .../fuzz/transformation_set_loop_control.h | 79 + ...ransformation_set_memory_operands_mask.cpp | 201 + .../transformation_set_memory_operands_mask.h | 76 + .../transformation_set_selection_control.cpp | 60 + .../transformation_set_selection_control.h | 54 + .../fuzz/transformation_split_block.cpp | 135 + .../source/fuzz/transformation_split_block.h | 63 + .../fuzz/transformation_vector_shuffle.cpp | 203 + .../fuzz/transformation_vector_shuffle.h | 82 + .../uniform_buffer_element_descriptor.cpp | 118 + .../fuzz/uniform_buffer_element_descriptor.h | 52 + .../spirv-tools/source/id_descriptor.cpp | 78 - .../spirv-tools/source/id_descriptor.h | 63 - third_party/spirv-tools/source/libspirv.cpp | 4 +- .../spirv-tools/source/link/CMakeLists.txt | 16 +- .../spirv-tools/source/link/linker.cpp | 64 +- third_party/spirv-tools/source/opcode.cpp | 74 +- third_party/spirv-tools/source/opcode.h | 12 + third_party/spirv-tools/source/operand.cpp | 82 +- third_party/spirv-tools/source/operand.h | 10 + .../spirv-tools/source/opt/CMakeLists.txt | 75 +- .../opt/aggressive_dead_code_elim_pass.cpp | 213 +- .../opt/aggressive_dead_code_elim_pass.h | 14 +- .../spirv-tools/source/opt/amd_ext_to_khr.cpp | 972 + .../spirv-tools/source/opt/amd_ext_to_khr.h | 51 + .../spirv-tools/source/opt/basic_block.cpp | 56 +- .../spirv-tools/source/opt/basic_block.h | 26 +- .../source/opt/block_merge_pass.cpp | 120 +- .../spirv-tools/source/opt/block_merge_pass.h | 13 +- .../source/opt/block_merge_util.cpp | 194 + .../spirv-tools/source/opt/block_merge_util.h | 44 + .../spirv-tools/source/opt/ccp_pass.cpp | 3 +- third_party/spirv-tools/source/opt/ccp_pass.h | 3 +- third_party/spirv-tools/source/opt/cfg.cpp | 58 +- third_party/spirv-tools/source/opt/cfg.h | 30 +- .../source/opt/cfg_cleanup_pass.cpp | 2 +- .../spirv-tools/source/opt/cfg_cleanup_pass.h | 3 +- .../spirv-tools/source/opt/code_sink.cpp | 319 + .../spirv-tools/source/opt/code_sink.h | 107 + .../source/opt/combine_access_chains.h | 3 +- .../source/opt/common_uniform_elim_pass.cpp | 580 - .../source/opt/common_uniform_elim_pass.h | 213 - .../source/opt/const_folding_rules.cpp | 556 +- .../source/opt/const_folding_rules.h | 68 +- .../spirv-tools/source/opt/constants.cpp | 77 +- .../spirv-tools/source/opt/constants.h | 38 +- .../source/opt/convert_to_half_pass.cpp | 471 + .../source/opt/convert_to_half_pass.h | 148 + .../source/opt/copy_prop_arrays.cpp | 310 +- .../spirv-tools/source/opt/copy_prop_arrays.h | 36 +- .../source/opt/dead_branch_elim_pass.cpp | 286 +- .../source/opt/dead_branch_elim_pass.h | 33 +- .../source/opt/dead_insert_elim_pass.cpp | 2 +- .../source/opt/dead_insert_elim_pass.h | 3 +- .../source/opt/dead_variable_elimination.h | 3 +- .../decompose_initialized_variables_pass.cpp | 112 + .../decompose_initialized_variables_pass.h | 57 + .../source/opt/decoration_manager.cpp | 163 +- .../source/opt/decoration_manager.h | 66 +- .../source/opt/def_use_manager.cpp | 12 +- .../spirv-tools/source/opt/desc_sroa.cpp | 273 + .../spirv-tools/source/opt/desc_sroa.h | 84 + .../opt/eliminate_dead_functions_pass.cpp | 12 +- .../opt/eliminate_dead_functions_pass.h | 3 +- .../opt/eliminate_dead_functions_util.cpp | 32 + .../opt/eliminate_dead_functions_util.h | 36 + .../opt/eliminate_dead_members_pass.cpp | 637 + .../source/opt/eliminate_dead_members_pass.h | 146 + .../source/opt/feature_manager.cpp | 41 +- .../spirv-tools/source/opt/feature_manager.h | 18 +- .../source/opt/fix_storage_class.cpp | 330 + .../source/opt/fix_storage_class.h | 93 + third_party/spirv-tools/source/opt/fold.cpp | 121 +- third_party/spirv-tools/source/opt/fold.h | 30 +- ...ld_spec_constant_op_and_composite_pass.cpp | 198 +- ...fold_spec_constant_op_and_composite_pass.h | 8 +- .../spirv-tools/source/opt/folding_rules.cpp | 400 +- .../spirv-tools/source/opt/folding_rules.h | 53 +- .../spirv-tools/source/opt/function.cpp | 118 +- third_party/spirv-tools/source/opt/function.h | 27 +- .../opt/generate_webgpu_initializers_pass.cpp | 116 + .../opt/generate_webgpu_initializers_pass.h | 62 + .../opt/graphics_robust_access_pass.cpp | 1053 + .../source/opt/graphics_robust_access_pass.h | 156 + .../spirv-tools/source/opt/if_conversion.cpp | 7 + .../spirv-tools/source/opt/if_conversion.h | 3 +- .../source/opt/inline_exhaustive_pass.cpp | 18 +- .../source/opt/inline_exhaustive_pass.h | 4 +- .../source/opt/inline_opaque_pass.cpp | 19 +- .../source/opt/inline_opaque_pass.h | 2 +- .../spirv-tools/source/opt/inline_pass.cpp | 800 +- .../spirv-tools/source/opt/inline_pass.h | 58 +- .../source/opt/inst_bindless_check_pass.cpp | 446 + .../source/opt/inst_bindless_check_pass.h | 182 + .../source/opt/inst_buff_addr_check_pass.cpp | 441 + .../source/opt/inst_buff_addr_check_pass.h | 133 + .../spirv-tools/source/opt/instruction.cpp | 51 +- .../spirv-tools/source/opt/instruction.h | 44 +- .../source/opt/instrument_pass.cpp | 1025 + .../spirv-tools/source/opt/instrument_pass.h | 440 + .../spirv-tools/source/opt/ir_builder.h | 233 +- .../spirv-tools/source/opt/ir_context.cpp | 324 +- .../spirv-tools/source/opt/ir_context.h | 287 +- .../spirv-tools/source/opt/ir_loader.cpp | 53 +- .../opt/legalize_vector_shuffle_pass.cpp | 39 + .../source/opt/legalize_vector_shuffle_pass.h | 53 + .../spirv-tools/source/opt/licm_pass.cpp | 83 +- .../spirv-tools/source/opt/licm_pass.h | 27 +- .../opt/local_access_chain_convert_pass.cpp | 64 +- .../opt/local_access_chain_convert_pass.h | 15 +- .../source/opt/local_redundancy_elimination.h | 3 +- .../opt/local_single_block_elim_pass.cpp | 15 +- .../source/opt/local_single_block_elim_pass.h | 4 +- .../opt/local_single_store_elim_pass.cpp | 13 +- .../source/opt/local_single_store_elim_pass.h | 4 +- .../source/opt/local_ssa_elim_pass.cpp | 105 - .../source/opt/local_ssa_elim_pass.h | 70 - third_party/spirv-tools/source/opt/log.h | 80 +- .../spirv-tools/source/opt/loop_dependence.h | 12 +- .../source/opt/loop_descriptor.cpp | 8 +- .../spirv-tools/source/opt/loop_descriptor.h | 10 +- .../spirv-tools/source/opt/loop_fission.cpp | 1 + .../spirv-tools/source/opt/loop_peeling.cpp | 17 +- .../spirv-tools/source/opt/loop_unroller.cpp | 88 +- .../spirv-tools/source/opt/loop_unroller.h | 8 + .../source/opt/loop_unswitch_pass.cpp | 456 +- .../spirv-tools/source/opt/loop_utils.cpp | 5 + .../spirv-tools/source/opt/mem_pass.cpp | 6 +- third_party/spirv-tools/source/opt/mem_pass.h | 7 +- .../source/opt/merge_return_pass.cpp | 615 +- .../source/opt/merge_return_pass.h | 209 +- third_party/spirv-tools/source/opt/module.cpp | 18 + third_party/spirv-tools/source/opt/module.h | 82 +- .../spirv-tools/source/opt/optimizer.cpp | 343 +- third_party/spirv-tools/source/opt/pass.cpp | 174 +- third_party/spirv-tools/source/opt/pass.h | 45 +- .../spirv-tools/source/opt/pass_manager.cpp | 14 + .../spirv-tools/source/opt/pass_manager.h | 29 +- third_party/spirv-tools/source/opt/passes.h | 21 +- .../spirv-tools/source/opt/pch_source_opt.cpp | 15 + .../spirv-tools/source/opt/pch_source_opt.h | 32 + .../source/opt/private_to_local_pass.cpp | 64 +- .../source/opt/private_to_local_pass.h | 13 +- .../source/opt/process_lines_pass.cpp | 157 + .../source/opt/process_lines_pass.h | 87 + .../source/opt/reduce_load_size.cpp | 3 +- .../spirv-tools/source/opt/reduce_load_size.h | 3 +- third_party/spirv-tools/source/opt/reflect.h | 4 +- .../source/opt/register_pressure.cpp | 13 +- .../source/opt/relax_float_ops_pass.cpp | 178 + .../source/opt/relax_float_ops_pass.h | 80 + .../source/opt/remove_duplicates_pass.cpp | 89 +- .../source/opt/remove_duplicates_pass.h | 6 - .../source/opt/scalar_analysis_nodes.h | 16 +- .../source/opt/scalar_replacement_pass.cpp | 383 +- .../source/opt/scalar_replacement_pass.h | 58 +- .../source/opt/simplification_pass.cpp | 61 +- .../source/opt/simplification_pass.h | 11 +- .../opt/split_invalid_unreachable_pass.cpp | 95 + .../opt/split_invalid_unreachable_pass.h | 51 + .../source/opt/ssa_rewrite_pass.cpp | 79 +- .../spirv-tools/source/opt/ssa_rewrite_pass.h | 17 +- .../opt/strip_atomic_counter_memory_pass.cpp | 57 + .../opt/strip_atomic_counter_memory_pass.h | 51 + .../source/opt/strip_debug_info_pass.cpp | 81 +- .../source/opt/strip_reflect_info_pass.cpp | 54 + .../source/opt/strip_reflect_info_pass.h | 3 +- .../source/opt/struct_cfg_analysis.cpp | 219 + .../source/opt/struct_cfg_analysis.h | 148 + .../spirv-tools/source/opt/type_manager.cpp | 150 +- .../spirv-tools/source/opt/type_manager.h | 64 +- third_party/spirv-tools/source/opt/types.cpp | 110 +- third_party/spirv-tools/source/opt/types.h | 139 +- .../source/opt/upgrade_memory_model.cpp | 770 + .../source/opt/upgrade_memory_model.h | 150 + .../source/opt/value_number_table.cpp | 10 +- .../spirv-tools/source/opt/vector_dce.cpp | 78 +- .../spirv-tools/source/opt/vector_dce.h | 4 +- .../spirv-tools/source/opt/wrap_opkill.cpp | 181 + .../spirv-tools/source/opt/wrap_opkill.h | 75 + third_party/spirv-tools/source/pch_source.cpp | 15 + third_party/spirv-tools/source/pch_source.h | 15 + third_party/spirv-tools/source/print.cpp | 3 +- .../spirv-tools/source/reduce/CMakeLists.txt | 107 + .../change_operand_reduction_opportunity.cpp | 32 + .../change_operand_reduction_opportunity.h | 54 + ...operand_to_undef_reduction_opportunity.cpp | 41 + ...e_operand_to_undef_reduction_opportunity.h | 53 + ..._conditional_branch_opportunity_finder.cpp | 89 + ...le_conditional_branch_opportunity_finder.h | 37 + ...nditional_branch_reduction_opportunity.cpp | 70 + ...conditional_branch_reduction_opportunity.h | 54 + .../merge_blocks_reduction_opportunity.cpp | 83 + .../merge_blocks_reduction_opportunity.h | 53 + ...ge_blocks_reduction_opportunity_finder.cpp | 48 + ...erge_blocks_reduction_opportunity_finder.h | 42 + ..._to_const_reduction_opportunity_finder.cpp | 83 + ...nd_to_const_reduction_opportunity_finder.h | 44 + ...nating_id_reduction_opportunity_finder.cpp | 118 + ...minating_id_reduction_opportunity_finder.h | 56 + ..._to_undef_reduction_opportunity_finder.cpp | 94 + ...nd_to_undef_reduction_opportunity_finder.h | 43 + .../source/reduce/pch_source_reduce.cpp | 15 + .../source/reduce/pch_source_reduce.h | 23 + .../spirv-tools/source/reduce/reducer.cpp | 242 + .../spirv-tools/source/reduce/reducer.h | 122 + .../source/reduce/reduction_opportunity.cpp | 27 + .../source/reduce/reduction_opportunity.h | 47 + .../reduce/reduction_opportunity_finder.h | 43 + .../source/reduce/reduction_pass.cpp | 86 + .../source/reduce/reduction_pass.h | 81 + .../source/reduce/reduction_util.cpp | 65 + .../source/reduce/reduction_util.h | 41 + .../remove_block_reduction_opportunity.cpp | 57 + .../remove_block_reduction_opportunity.h | 46 + ...ove_block_reduction_opportunity_finder.cpp | 98 + ...emove_block_reduction_opportunity_finder.h | 55 + .../remove_function_reduction_opportunity.cpp | 41 + .../remove_function_reduction_opportunity.h | 49 + ..._function_reduction_opportunity_finder.cpp | 43 + ...ve_function_reduction_opportunity_finder.h | 42 + ...ove_instruction_reduction_opportunity.cpp} | 26 +- ...remove_instruction_reduction_opportunity.h | 44 + ...remove_selection_reduction_opportunity.cpp | 31 + .../remove_selection_reduction_opportunity.h | 47 + ...selection_reduction_opportunity_finder.cpp | 150 + ...e_selection_reduction_opportunity_finder.h | 49 + ...struction_reduction_opportunity_finder.cpp | 148 + ...instruction_reduction_opportunity_finder.h | 48 + ...al_branch_to_branch_opportunity_finder.cpp | 65 + ...onal_branch_to_branch_opportunity_finder.h | 37 + ...branch_to_branch_reduction_opportunity.cpp | 59 + ...l_branch_to_branch_reduction_opportunity.h | 45 + ...oop_to_selection_reduction_opportunity.cpp | 343 + ..._loop_to_selection_reduction_opportunity.h | 111 + ...selection_reduction_opportunity_finder.cpp | 104 + ...o_selection_reduction_opportunity_finder.h | 57 + .../source/spirv_fuzzer_options.cpp | 56 + .../spirv-tools/source/spirv_fuzzer_options.h | 42 + .../source/spirv_optimizer_options.cpp | 51 + .../source/spirv_optimizer_options.h | 49 + .../source/spirv_reducer_options.cpp | 44 + .../source/spirv_reducer_options.h | 35 + .../spirv-tools/source/spirv_target_env.cpp | 315 +- .../spirv-tools/source/spirv_target_env.h | 30 +- .../source/spirv_validator_options.cpp | 23 +- .../source/spirv_validator_options.h | 9 +- third_party/spirv-tools/source/table.cpp | 4 + third_party/spirv-tools/source/table.h | 5 +- third_party/spirv-tools/source/text.cpp | 54 +- .../spirv-tools/source/text_handler.cpp | 2 +- .../spirv-tools/source/util/bitutils.h | 93 +- .../spirv-tools/source/util/hex_float.h | 4 +- .../spirv-tools/source/util/string_utils.cpp | 17 + .../spirv-tools/source/util/string_utils.h | 49 + .../spirv-tools/source/val/basic_block.h | 4 +- .../spirv-tools/source/val/construct.cpp | 107 +- .../spirv-tools/source/val/construct.h | 19 + .../spirv-tools/source/val/function.cpp | 52 +- third_party/spirv-tools/source/val/function.h | 42 + .../spirv-tools/source/val/instruction.h | 12 + .../spirv-tools/source/val/validate.cpp | 266 +- third_party/spirv-tools/source/val/validate.h | 40 +- .../source/val/validate_adjacency.cpp | 134 +- .../source/val/validate_annotation.cpp | 334 +- .../source/val/validate_arithmetics.cpp | 107 +- .../source/val/validate_atomics.cpp | 260 +- .../source/val/validate_barriers.cpp | 184 +- .../source/val/validate_builtins.cpp | 826 +- .../source/val/validate_capability.cpp | 76 + .../spirv-tools/source/val/validate_cfg.cpp | 462 +- .../source/val/validate_composites.cpp | 130 +- .../source/val/validate_constants.cpp | 140 +- .../source/val/validate_conversion.cpp | 223 +- .../source/val/validate_datarules.cpp | 267 - .../spirv-tools/source/val/validate_debug.cpp | 2 + .../source/val/validate_decorations.cpp | 965 +- .../source/val/validate_derivatives.cpp | 48 +- .../val/validate_execution_limitations.cpp | 11 + ...e_ext_inst.cpp => validate_extensions.cpp} | 184 +- .../source/val/validate_function.cpp | 189 +- .../spirv-tools/source/val/validate_id.cpp | 208 +- .../spirv-tools/source/val/validate_image.cpp | 474 +- .../source/val/validate_instruction.cpp | 321 +- .../source/val/validate_interfaces.cpp | 27 +- .../source/val/validate_layout.cpp | 146 +- .../source/val/validate_logicals.cpp | 72 +- .../source/val/validate_memory.cpp | 1263 +- .../source/val/validate_memory_semantics.cpp | 295 + .../source/val/validate_memory_semantics.h | 28 + .../spirv-tools/source/val/validate_misc.cpp | 163 + .../source/val/validate_mode_setting.cpp | 462 +- .../source/val/validate_non_uniform.cpp | 48 +- .../source/val/validate_scopes.cpp | 272 + .../spirv-tools/source/val/validate_scopes.h | 33 + .../source/val/validate_small_type_uses.cpp | 57 + .../spirv-tools/source/val/validate_type.cpp | 478 +- .../source/val/validation_state.cpp | 468 +- .../spirv-tools/source/val/validation_state.h | 265 +- third_party/spirv-tools/test/CMakeLists.txt | 68 +- .../test/assembly_context_test.cpp | 10 +- .../spirv-tools/test/assembly_format_test.cpp | 15 +- .../test/binary_header_get_test.cpp | 3 +- .../spirv-tools/test/binary_parse_test.cpp | 79 +- .../test/binary_to_text.literal_test.cpp | 8 +- .../spirv-tools/test/binary_to_text_test.cpp | 113 +- third_party/spirv-tools/test/bit_stream.cpp | 1025 - .../spirv-tools/test/c_interface_test.cpp | 6 +- third_party/spirv-tools/test/comment_test.cpp | 3 +- .../test/comp/markv_codec_test.cpp | 829 - .../spirv-tools/test/cpp_interface_test.cpp | 17 +- .../spirv-tools/test/enum_set_test.cpp | 36 +- .../test/enum_string_mapping_test.cpp | 16 +- .../test/ext_inst.cldebug100_test.cpp | 1070 + .../test/ext_inst.debuginfo_test.cpp | 409 +- .../spirv-tools/test/ext_inst.glsl_test.cpp | 7 +- .../test/ext_inst.non_semantic_test.cpp | 90 + .../spirv-tools/test/ext_inst.opencl_test.cpp | 39 +- .../spirv-tools/test/fuzz/CMakeLists.txt | 78 + .../fuzz/data_synonym_transformation_test.cpp | 1122 + .../test/fuzz/equivalence_relation_test.cpp | 145 + .../test/fuzz/fact_manager_test.cpp | 1178 + .../spirv-tools/test/fuzz/fuzz_test_util.cpp | 126 + .../spirv-tools/test/fuzz/fuzz_test_util.h | 113 + ...fuzzer_pass_add_useful_constructs_test.cpp | 393 + .../fuzz/fuzzer_pass_donate_modules_test.cpp | 673 + .../test/fuzz/fuzzer_replayer_test.cpp | 1641 ++ .../test/fuzz/fuzzer_shrinker_test.cpp | 1116 + .../test/fuzz/instruction_descriptor_test.cpp | 69 + ...ansformation_add_constant_boolean_test.cpp | 141 + ...sformation_add_constant_composite_test.cpp | 158 + ...ransformation_add_constant_scalar_test.cpp | 187 + .../transformation_add_dead_block_test.cpp | 321 + .../transformation_add_dead_break_test.cpp | 2610 +++ .../transformation_add_dead_continue_test.cpp | 1562 ++ .../fuzz/transformation_add_function_test.cpp | 2850 +++ .../transformation_add_global_undef_test.cpp | 118 + ...ransformation_add_global_variable_test.cpp | 285 + ...ion_add_no_contraction_decoration_test.cpp | 194 + .../transformation_add_type_array_test.cpp | 136 + .../transformation_add_type_boolean_test.cpp | 80 + .../transformation_add_type_float_test.cpp | 80 + .../transformation_add_type_function_test.cpp | 134 + .../fuzz/transformation_add_type_int_test.cpp | 93 + .../transformation_add_type_matrix_test.cpp | 130 + .../transformation_add_type_pointer_test.cpp | 206 + .../transformation_add_type_struct_test.cpp | 110 + .../transformation_add_type_vector_test.cpp | 102 + ...ransformation_composite_construct_test.cpp | 1356 ++ .../transformation_composite_extract_test.cpp | 398 + .../fuzz/transformation_copy_object_test.cpp | 631 + .../fuzz/transformation_merge_blocks_test.cpp | 675 + .../transformation_move_block_down_test.cpp | 670 + .../transformation_outline_function_test.cpp | 2789 +++ ...ean_constant_with_constant_binary_test.cpp | 655 + ...ion_replace_constant_with_uniform_test.cpp | 1447 ++ ...formation_replace_id_with_synonym_test.cpp | 1217 ++ ...ansformation_set_function_control_test.cpp | 251 + .../transformation_set_loop_control_test.cpp | 968 + ...ormation_set_memory_operands_mask_test.cpp | 432 + ...nsformation_set_selection_control_test.cpp | 219 + .../fuzz/transformation_split_block_test.cpp | 850 + .../transformation_vector_shuffle_test.cpp | 532 + ...uniform_buffer_element_descriptor_test.cpp | 84 + third_party/spirv-tools/test/fuzzers/BUILD.gn | 98 +- .../test/fuzzers/spvtools_as_fuzzer.cpp | 72 + .../fuzzers/spvtools_binary_parser_fuzzer.cpp | 44 + .../test/fuzzers/spvtools_dis_fuzzer.cpp | 71 + .../spvtools_opt_vulkantowebgpu_fuzzer.cpp | 38 + .../spvtools_opt_webgputovulkan_fuzzer.cpp | 38 + .../fuzzers/spvtools_val_webgpu_fuzzer.cpp | 36 + .../test/generator_magic_number_test.cpp | 8 +- .../spirv-tools/test/hex_float_test.cpp | 95 +- .../spirv-tools/test/huffman_codec.cpp | 317 - .../spirv-tools/test/link/CMakeLists.txt | 1 + .../spirv-tools/test/link/linker_fixture.h | 97 + .../link/matching_imports_to_exports_test.cpp | 73 + .../spirv-tools/test/link/type_match_test.cpp | 148 + .../spirv-tools/test/move_to_front_test.cpp | 828 - .../spirv-tools/test/name_mapper_test.cpp | 156 +- .../spirv-tools/test/named_id_test.cpp | 4 +- .../test/opcode_require_capabilities_test.cpp | 4 +- .../test/opcode_table_get_test.cpp | 4 +- .../test/operand_capabilities_test.cpp | 186 +- .../spirv-tools/test/operand_pattern_test.cpp | 22 +- third_party/spirv-tools/test/operand_test.cpp | 8 +- .../spirv-tools/test/opt/CMakeLists.txt | 406 +- .../opt/aggressive_dead_code_elim_test.cpp | 1031 +- .../spirv-tools/test/opt/amd_ext_to_khr.cpp | 953 + .../spirv-tools/test/opt/block_merge_test.cpp | 319 +- third_party/spirv-tools/test/opt/ccp_test.cpp | 44 +- .../spirv-tools/test/opt/cfg_cleanup_test.cpp | 8 + third_party/spirv-tools/test/opt/cfg_test.cpp | 205 + .../spirv-tools/test/opt/code_sink_test.cpp | 557 + .../test/opt/combine_access_chains_test.cpp | 23 +- .../test/opt/common_uniform_elim_test.cpp | 1341 -- .../test/opt/constant_manager_test.cpp | 22 + .../spirv-tools/test/opt/constants_test.cpp | 167 + .../test/opt/convert_relaxed_to_half_test.cpp | 1336 ++ .../test/opt/copy_prop_array_test.cpp | 366 +- .../test/opt/dead_branch_elim_test.cpp | 1038 +- .../test/opt/dead_variable_elim_test.cpp | 2 +- .../decompose_initialized_variables_test.cpp | 252 + .../test/opt/decoration_manager_test.cpp | 242 +- .../spirv-tools/test/opt/def_use_test.cpp | 12 +- .../spirv-tools/test/opt/desc_sroa_test.cpp | 270 + .../test/opt/dominator_tree/CMakeLists.txt | 1 + .../opt/dominator_tree/pch_test_opt_dom.cpp | 15 + .../opt/dominator_tree/pch_test_opt_dom.h | 25 + .../test/opt/eliminate_dead_const_test.cpp | 14 +- .../test/opt/eliminate_dead_member_test.cpp | 1088 + .../test/opt/fix_storage_class_test.cpp | 840 + .../test/opt/flatten_decoration_test.cpp | 293 +- .../opt/fold_spec_const_op_composite_test.cpp | 167 +- .../spirv-tools/test/opt/fold_test.cpp | 1392 +- .../test/opt/freeze_spec_const_test.cpp | 2 +- .../spirv-tools/test/opt/function_test.cpp | 173 + .../opt/generate_webgpu_initializers_test.cpp | 347 + .../test/opt/graphics_robust_access_test.cpp | 1401 ++ .../test/opt/if_conversion_test.cpp | 49 +- .../spirv-tools/test/opt/inline_test.cpp | 593 +- .../test/opt/inst_bindless_check_test.cpp | 7195 ++++++ .../test/opt/inst_buff_addr_check_test.cpp | 620 + .../spirv-tools/test/opt/instruction_test.cpp | 29 + .../spirv-tools/test/opt/ir_builder.cpp | 71 +- .../spirv-tools/test/opt/ir_context_test.cpp | 527 +- .../spirv-tools/test/opt/ir_loader_test.cpp | 615 + .../test/opt/legalize_vector_shuffle_test.cpp | 81 + .../opt/local_access_chain_convert_test.cpp | 230 +- .../opt/local_redundancy_elimination_test.cpp | 2 - .../test/opt/local_single_block_elim.cpp | 58 + .../test/opt/local_single_store_elim_test.cpp | 57 + .../test/opt/local_ssa_elim_test.cpp | 388 +- .../opt/loop_optimizations/CMakeLists.txt | 1 + .../opt/loop_optimizations/fusion_legal.cpp | 19 +- .../opt/loop_optimizations/fusion_pass.cpp | 9 +- .../hoist_single_nested_loops.cpp | 46 + .../hoist_without_preheader.cpp | 77 +- .../test/opt/loop_optimizations/lcssa.cpp | 9 +- .../loop_optimizations/pch_test_opt_loop.cpp | 15 + .../loop_optimizations/pch_test_opt_loop.h | 25 + .../test/opt/loop_optimizations/peeling.cpp | 23 +- .../opt/loop_optimizations/unroll_simple.cpp | 46 + .../test/opt/loop_optimizations/unswitch.cpp | 298 +- .../spirv-tools/test/opt/module_test.cpp | 156 + .../spirv-tools/test/opt/optimizer_test.cpp | 542 +- .../spirv-tools/test/opt/pass_fixture.h | 108 +- .../test/opt/pass_manager_test.cpp | 11 +- .../test/opt/pass_merge_return_test.cpp | 1296 +- .../spirv-tools/test/opt/pass_test.cpp | 242 - .../spirv-tools/test/opt/pass_utils.cpp | 20 + third_party/spirv-tools/test/opt/pass_utils.h | 16 + .../spirv-tools/test/opt/pch_test_opt.cpp | 15 + .../spirv-tools/test/opt/pch_test_opt.h | 25 + .../test/opt/private_to_local_test.cpp | 145 +- .../test/opt/process_lines_test.cpp | 695 + .../test/opt/reduce_load_size_test.cpp | 2 - .../test/opt/redundancy_elimination_test.cpp | 3 - .../test/opt/register_liveness.cpp | 40 + .../test/opt/relax_float_ops_test.cpp | 142 + .../test/opt/replace_invalid_opc_test.cpp | 32 +- .../test/opt/scalar_replacement_test.cpp | 385 +- .../opt/set_spec_const_default_value_test.cpp | 12 +- .../test/opt/simplification_test.cpp | 159 +- .../opt/split_invalid_unreachable_test.cpp | 155 + .../test/opt/strength_reduction_test.cpp | 2 - .../opt/strip_atomic_counter_memory_test.cpp | 406 + .../test/opt/strip_debug_info_test.cpp | 127 +- .../test/opt/strip_reflect_info_test.cpp | 68 + .../test/opt/struct_cfg_analysis_test.cpp | 1374 ++ .../test/opt/type_manager_test.cpp | 109 +- .../spirv-tools/test/opt/types_test.cpp | 107 +- .../spirv-tools/test/opt/unify_const_test.cpp | 10 +- .../test/opt/upgrade_memory_model_test.cpp | 2272 ++ .../spirv-tools/test/opt/utils_test.cpp | 2 +- .../spirv-tools/test/opt/value_table_test.cpp | 98 + .../spirv-tools/test/opt/vector_dce_test.cpp | 25 +- .../test/opt/workaround1209_test.cpp | 2 - .../spirv-tools/test/opt/wrap_opkill_test.cpp | 518 + third_party/spirv-tools/test/pch_test.cpp | 15 + third_party/spirv-tools/test/pch_test.h | 18 + .../spirv-tools/test/reduce/CMakeLists.txt | 34 + ...anch_to_simple_conditional_branch_test.cpp | 501 + .../test/reduce/merge_blocks_test.cpp | 652 + .../test/reduce/operand_to_constant_test.cpp | 160 + .../reduce/operand_to_dominating_id_test.cpp | 198 + .../test/reduce/operand_to_undef_test.cpp | 230 + .../test/reduce/reduce_test_util.cpp | 112 + .../test/reduce/reduce_test_util.h | 75 + .../spirv-tools/test/reduce/reducer_test.cpp | 441 + .../test/reduce/remove_block_test.cpp | 358 + .../test/reduce/remove_function_test.cpp | 295 + .../test/reduce/remove_selection_test.cpp | 557 + .../remove_unreferenced_instruction_test.cpp | 380 + ...mple_conditional_branch_to_branch_test.cpp | 486 + .../structured_loop_to_selection_test.cpp | 3628 ++++ .../validation_during_reduction_test.cpp | 589 + .../test/scripts/test_compact_ids.py | 2 - .../spirv-tools/test/stats/CMakeLists.txt | 32 - .../test/stats/stats_aggregate_test.cpp | 438 - .../test/stats/stats_analyzer_test.cpp | 174 - .../spirv-tools/test/target_env_test.cpp | 71 +- third_party/spirv-tools/test/test_fixture.h | 13 + .../spirv-tools/test/text_literal_test.cpp | 16 +- .../test/text_to_binary.annotation_test.cpp | 81 +- .../test/text_to_binary.composite_test.cpp | 49 + .../test/text_to_binary.constant_test.cpp | 74 +- .../test/text_to_binary.control_flow_test.cpp | 41 +- .../test/text_to_binary.debug_test.cpp | 39 +- ...ext_to_binary.device_side_enqueue_test.cpp | 4 +- .../test/text_to_binary.extension_test.cpp | 334 +- .../test/text_to_binary.function_test.cpp | 4 +- .../test/text_to_binary.group_test.cpp | 4 +- .../test/text_to_binary.image_test.cpp | 42 +- .../test/text_to_binary.memory_test.cpp | 327 +- .../test/text_to_binary.mode_setting_test.cpp | 23 +- .../text_to_binary.type_declaration_test.cpp | 16 +- .../spirv-tools/test/text_to_binary_test.cpp | 24 +- third_party/spirv-tools/test/timer_test.cpp | 2 +- .../spirv-tools/test/tools/CMakeLists.txt | 9 +- third_party/spirv-tools/test/tools/expect.py | 43 +- .../spirv-tools/test/tools/expect_nosetest.py | 80 - .../spirv-tools/test/tools/expect_unittest.py | 82 + .../spirv-tools/test/tools/opt/CMakeLists.txt | 2 +- .../spirv-tools/test/tools/opt/flags.py | 114 +- .../spirv-tools/test/tools/opt/oconfig.py | 15 + .../test/tools/spirv_test_framework.py | 33 +- .../tools/spirv_test_framework_nosetest.py | 155 - .../tools/spirv_test_framework_unittest.py | 158 + third_party/spirv-tools/test/unit_spirv.cpp | 3 +- third_party/spirv-tools/test/unit_spirv.h | 23 - .../spirv-tools/test/util/CMakeLists.txt | 13 +- .../spirv-tools/test/util/bitutils_test.cpp | 193 + .../spirv-tools/test/val/CMakeLists.txt | 25 +- .../spirv-tools/test/val/pch_test_val.cpp | 15 + .../spirv-tools/test/val/pch_test_val.h | 19 + .../test/val/val_adjacency_test.cpp | 426 +- .../test/val/val_arithmetics_test.cpp | 152 +- .../spirv-tools/test/val/val_atomics_test.cpp | 1294 +- .../test/val/val_barriers_test.cpp | 809 +- .../spirv-tools/test/val/val_bitwise_test.cpp | 1 + .../test/val/val_builtins_test.cpp | 2415 +- .../test/val/val_capability_test.cpp | 884 +- .../spirv-tools/test/val/val_cfg_test.cpp | 2777 ++- .../test/val/val_code_generator.cpp | 224 + .../spirv-tools/test/val/val_code_generator.h | 49 + .../test/val/val_composites_test.cpp | 604 +- .../test/val/val_constants_test.cpp | 483 + .../test/val/val_conversion_test.cpp | 649 +- .../spirv-tools/test/val/val_data_test.cpp | 353 +- .../test/val/val_decoration_test.cpp | 4257 +++- .../test/val/val_derivatives_test.cpp | 58 +- .../spirv-tools/test/val/val_entry_point.cpp | 76 + .../test/val/val_ext_inst_test.cpp | 1015 +- .../test/val/val_extensions_test.cpp | 48 +- .../spirv-tools/test/val/val_fixtures.h | 55 +- .../test/val/val_function_test.cpp | 843 + .../spirv-tools/test/val/val_id_test.cpp | 2247 +- .../spirv-tools/test/val/val_image_test.cpp | 1101 +- .../test/val/val_interfaces_test.cpp | 260 +- .../spirv-tools/test/val/val_layout_test.cpp | 58 +- .../spirv-tools/test/val/val_limits_test.cpp | 92 +- .../test/val/val_literals_test.cpp | 14 +- .../test/val/val_logicals_test.cpp | 241 + .../spirv-tools/test/val/val_memory_test.cpp | 4483 ++++ .../spirv-tools/test/val/val_misc_test.cpp | 231 + .../spirv-tools/test/val/val_modes_test.cpp | 1183 + .../test/val/val_non_semantic_test.cpp | 195 + .../test/val/val_non_uniform_test.cpp | 197 +- .../spirv-tools/test/val/val_opencl_test.cpp | 275 + .../test/val/val_primitives_test.cpp | 4 + .../test/val/val_small_type_uses_test.cpp | 338 + .../spirv-tools/test/val/val_ssa_test.cpp | 30 +- .../spirv-tools/test/val/val_state_test.cpp | 2 +- .../spirv-tools/test/val/val_storage_test.cpp | 189 +- .../test/val/val_type_unique_test.cpp | 6 +- .../test/val/val_validation_state_test.cpp | 214 +- .../spirv-tools/test/val/val_version_test.cpp | 42 +- .../spirv-tools/test/val/val_webgpu_test.cpp | 332 +- third_party/spirv-tools/tools/CMakeLists.txt | 36 +- third_party/spirv-tools/tools/as/as.cpp | 10 +- third_party/spirv-tools/tools/cfg/cfg.cpp | 2 +- third_party/spirv-tools/tools/comp/markv.cpp | 385 - .../tools/comp/markv_model_factory.cpp | 50 - .../tools/comp/markv_model_shader.cpp | 84 - .../tools/comp/markv_model_shader.h | 47 - .../markv_model_shader_default_autogen.inc | 14519 ------------- third_party/spirv-tools/tools/dis/dis.cpp | 2 +- third_party/spirv-tools/tools/fuzz/fuzz.cpp | 636 + third_party/spirv-tools/tools/io.h | 3 + .../tools/lesspipe/spirv-lesspipe.sh | 2 +- third_party/spirv-tools/tools/link/linker.cpp | 7 +- third_party/spirv-tools/tools/opt/opt.cpp | 469 +- .../spirv-tools/tools/reduce/reduce.cpp | 327 + .../spirv-tools/tools/stats/spirv_stats.cpp | 165 - .../spirv-tools/tools/stats/spirv_stats.h | 93 - third_party/spirv-tools/tools/stats/stats.cpp | 180 - .../tools/stats/stats_analyzer.cpp | 235 - .../spirv-tools/tools/stats/stats_analyzer.h | 58 - .../spirv-tools/tools/sva/.eslintrc.json | 25 + third_party/spirv-tools/tools/sva/.gitignore | 6 + third_party/spirv-tools/tools/sva/README.md | 41 + third_party/spirv-tools/tools/sva/bin/sva.js | 32 + third_party/spirv-tools/tools/sva/mocha.opts | 1 + .../spirv-tools/tools/sva/package.json | 25 + .../spirv-tools/tools/sva/rollup.config.js | 7 + .../spirv-tools/tools/sva/src/assembler.js | 98 + .../tools/sva/src/assembler_test.js | 165 + third_party/spirv-tools/tools/sva/src/ast.js | 141 + .../spirv-tools/tools/sva/src/lexer.js | 363 + .../spirv-tools/tools/sva/src/lexer_test.js | 191 + .../spirv-tools/tools/sva/src/parser.js | 283 + .../spirv-tools/tools/sva/src/parser_test.js | 489 + .../spirv-tools/tools/sva/src/spirv.data.js | 4567 ++++ third_party/spirv-tools/tools/sva/src/sva.js | 40 + .../spirv-tools/tools/sva/src/token.js | 55 + .../tools/sva/tests/empty_main.spv_asm | 18 + .../spirv-tools/tools/sva/tests/index.html | 23 + .../tools/sva/tests/simple.spv_asm | 30 + .../tools/sva/tools/process_grammar.rb | 119 + third_party/spirv-tools/tools/sva/yarn.lock | 1778 ++ .../spirv-tools/tools/util/cli_consumer.h | 2 +- third_party/spirv-tools/tools/val/val.cpp | 56 +- .../spirv-tools/utils/check_code_format.sh | 6 +- .../spirv-tools/utils/check_copyright.py | 8 +- .../spirv-tools/utils/check_symbol_exports.py | 13 +- .../utils/generate_grammar_tables.py | 269 +- .../utils/generate_language_headers.py | 5 +- .../utils/generate_registry_tables.py | 5 +- .../spirv-tools/utils/generate_vim_syntax.py | 2 - third_party/spirv-tools/utils/git-sync-deps | 282 + third_party/spirv-tools/utils/roll_deps.sh | 31 + .../spirv-tools/utils/update_build_version.py | 8 +- .../spirv-tools/utils/vscode/.gitignore | 1 + .../spirv-tools/utils/vscode/README.md | 17 + .../spirv-tools/utils/vscode/extension.js | 66 + .../spirv-tools/utils/vscode/install.bat | 30 + .../spirv-tools/utils/vscode/install.sh | 32 + .../spirv-tools/utils/vscode/package.json | 39 + .../spirv-tools/utils/vscode/spirv.json | 212 + .../spirv-tools/utils/vscode/spirv.json.tmpl | 67 + .../utils/vscode/src/grammar/grammar.go | 81 + .../spirv-tools/utils/vscode/src/langsvr.go | 527 + .../spirv-tools/utils/vscode/src/lsp/LICENSE | 202 + .../utils/vscode/src/lsp/README.md | 5 + .../utils/vscode/src/lsp/jsonrpc2/handler.go | 134 + .../utils/vscode/src/lsp/jsonrpc2/jsonrpc2.go | 416 + .../utils/vscode/src/lsp/jsonrpc2/stream.go | 160 + .../utils/vscode/src/lsp/jsonrpc2/wire.go | 148 + .../utils/vscode/src/lsp/protocol/context.go | 29 + .../utils/vscode/src/lsp/protocol/doc.go | 26 + .../utils/vscode/src/lsp/protocol/enums.go | 256 + .../utils/vscode/src/lsp/protocol/log.go | 258 + .../utils/vscode/src/lsp/protocol/protocol.go | 86 + .../utils/vscode/src/lsp/protocol/span.go | 137 + .../utils/vscode/src/lsp/protocol/tsclient.go | 221 + .../vscode/src/lsp/protocol/tsprotocol.go | 4630 ++++ .../utils/vscode/src/lsp/protocol/tsserver.go | 842 + .../utils/vscode/src/lsp/span/parse.go | 110 + .../utils/vscode/src/lsp/span/span.go | 295 + .../utils/vscode/src/lsp/span/token.go | 161 + .../utils/vscode/src/lsp/span/token111.go | 49 + .../utils/vscode/src/lsp/span/token112.go | 26 + .../utils/vscode/src/lsp/span/uri.go | 162 + .../utils/vscode/src/lsp/span/utf16.go | 104 + .../utils/vscode/src/parser/parser.go | 763 + .../utils/vscode/src/schema/schema.go | 18118 ++++++++++++++++ .../utils/vscode/src/schema/schema.go.tmpl | 133 + .../utils/vscode/src/tools/gen-grammar.go | 171 + 1747 files changed, 265215 insertions(+), 44507 deletions(-) create mode 100644 third_party/spirv-cross/gn/BUILD.gn create mode 100644 third_party/spirv-cross/reference/opt/shaders-hlsl/asm/comp/bitcast_icmp.asm.comp create mode 100644 third_party/spirv-cross/reference/opt/shaders-hlsl/comp/access-chain-load-composite.comp create mode 100644 third_party/spirv-cross/reference/opt/shaders-hlsl/comp/access-chains.force-uav.comp delete mode 100644 third_party/spirv-cross/reference/opt/shaders-hlsl/comp/atomic-decrement.asm.comp delete mode 100644 third_party/spirv-cross/reference/opt/shaders-hlsl/comp/atomic-increment.asm.comp delete mode 100644 third_party/spirv-cross/reference/opt/shaders-hlsl/comp/subgroups.invalid.nofxc.sm60.comp delete mode 100644 third_party/spirv-cross/reference/opt/shaders-hlsl/frag/fp16.invalid.desktop.frag create mode 100644 third_party/spirv-cross/reference/opt/shaders-hlsl/frag/pixel-interlock-ordered.sm51.fxconly.frag create mode 100644 third_party/spirv-cross/reference/opt/shaders-hlsl/frag/readonly-coherent-ssbo.force-uav.frag create mode 100644 third_party/spirv-cross/reference/opt/shaders-hlsl/frag/readonly-coherent-ssbo.frag create mode 100644 third_party/spirv-cross/reference/opt/shaders-msl/asm/comp/bitcast_icmp.asm.comp delete mode 100644 third_party/spirv-cross/reference/opt/shaders-msl/asm/frag/min-max-clamp.invalid.asm.frag create mode 100644 third_party/spirv-cross/reference/opt/shaders-msl/asm/frag/texture-atomics.asm.frag create mode 100644 third_party/spirv-cross/reference/opt/shaders-msl/asm/frag/texture-atomics.asm.graphics-robust-access.frag delete mode 100644 third_party/spirv-cross/reference/opt/shaders-msl/asm/tesc/tess-fixed-input-array-builtin-array.invalid.asm.tesc create mode 100644 third_party/spirv-cross/reference/opt/shaders-msl/asm/vert/clip-distance-plain-variable.asm.vert create mode 100644 third_party/spirv-cross/reference/opt/shaders-msl/comp/argument-buffers-image-load-store.ios.msl2.argument.comp create mode 100644 third_party/spirv-cross/reference/opt/shaders-msl/comp/basic.dispatchbase.comp create mode 100644 third_party/spirv-cross/reference/opt/shaders-msl/comp/basic.dispatchbase.msl11.comp create mode 100644 third_party/spirv-cross/reference/opt/shaders-msl/comp/basic.inline-block.msl2.comp delete mode 100644 third_party/spirv-cross/reference/opt/shaders-msl/comp/bitcast-16bit-1.invalid.comp delete mode 100644 third_party/spirv-cross/reference/opt/shaders-msl/comp/bitcast-16bit-2.invalid.comp create mode 100644 third_party/spirv-cross/reference/opt/shaders-msl/comp/complex-composite-constant-array.comp create mode 100644 third_party/spirv-cross/reference/opt/shaders-msl/comp/composite-array-initialization.force-native-array.comp create mode 100644 third_party/spirv-cross/reference/opt/shaders-msl/comp/copy-array-of-arrays.force-native-array.comp create mode 100644 third_party/spirv-cross/reference/opt/shaders-msl/comp/image-atomic-automatic-bindings.comp delete mode 100644 third_party/spirv-cross/reference/opt/shaders-msl/comp/int64.invalid.msl22.comp delete mode 100644 third_party/spirv-cross/reference/opt/shaders-msl/frag/16bit-constants.invalid.frag create mode 100644 third_party/spirv-cross/reference/opt/shaders-msl/frag/array-of-array-lut.frag create mode 100644 third_party/spirv-cross/reference/opt/shaders-msl/frag/clip-distance-varying.frag delete mode 100644 third_party/spirv-cross/reference/opt/shaders-msl/frag/fp16.desktop.invalid.frag create mode 100644 third_party/spirv-cross/reference/opt/shaders-msl/frag/huge-argument-buffer.device-argument-buffer.argument.msl2.frag create mode 100644 third_party/spirv-cross/reference/opt/shaders-msl/frag/pixel-interlock-ordered.msl2.argument.frag create mode 100644 third_party/spirv-cross/reference/opt/shaders-msl/frag/pixel-interlock-ordered.msl2.frag create mode 100644 third_party/spirv-cross/reference/opt/shaders-msl/frag/sample-depth-propagate-state-from-resource.frag delete mode 100644 third_party/spirv-cross/reference/opt/shaders-msl/frag/shadow-compare-global-alias.invalid.frag create mode 100644 third_party/spirv-cross/reference/opt/shaders-msl/frag/texture-cube-array.frag create mode 100644 third_party/spirv-cross/reference/opt/shaders-msl/frag/texture-cube-array.ios.emulate-cube-array.frag create mode 100644 third_party/spirv-cross/reference/opt/shaders-msl/tesc/load-control-point-array-of-matrix.tesc create mode 100644 third_party/spirv-cross/reference/opt/shaders-msl/tesc/load-control-point-array-of-struct.tesc create mode 100644 third_party/spirv-cross/reference/opt/shaders-msl/tesc/load-control-point-array.tesc create mode 100644 third_party/spirv-cross/reference/opt/shaders-msl/tese/load-control-point-array-of-matrix.tese create mode 100644 third_party/spirv-cross/reference/opt/shaders-msl/tese/load-control-point-array.tese create mode 100644 third_party/spirv-cross/reference/opt/shaders-msl/vert/clip-distance-block.vert create mode 100644 third_party/spirv-cross/reference/opt/shaders-msl/vert/float-math.invariant-float-math.vert create mode 100644 third_party/spirv-cross/reference/opt/shaders-msl/vert/float-math.vert rename third_party/spirv-cross/reference/{shaders-msl/vert/layer.msl11.invalid.vert => opt/shaders-msl/vert/return-array.force-native-array.vert} (61%) delete mode 100644 third_party/spirv-cross/reference/opt/shaders-msl/vulkan/comp/subgroups.nocompat.invalid.vk.msl21.comp delete mode 100644 third_party/spirv-cross/reference/opt/shaders-msl/vulkan/comp/subgroups.nocompat.invalid.vk.msl21.ios.comp delete mode 100644 third_party/spirv-cross/reference/opt/shaders-msl/vulkan/frag/demote-to-helper.vk.nocompat.msl21.invalid.frag delete mode 100644 third_party/spirv-cross/reference/opt/shaders-msl/vulkan/frag/subgroups.nocompat.invalid.vk.msl21.frag create mode 100644 third_party/spirv-cross/reference/opt/shaders-ue4/asm/frag/depth-compare.asm.frag create mode 100644 third_party/spirv-cross/reference/opt/shaders-ue4/asm/frag/global-constant-arrays.asm.frag create mode 100644 third_party/spirv-cross/reference/opt/shaders-ue4/asm/frag/padded-float-array-member-defef.asm.frag create mode 100644 third_party/spirv-cross/reference/opt/shaders-ue4/asm/frag/sample-mask-not-array.asm.frag create mode 100644 third_party/spirv-cross/reference/opt/shaders-ue4/asm/frag/subpass-input.ios.framebuffer-fetch.asm.frag create mode 100644 third_party/spirv-cross/reference/opt/shaders-ue4/asm/frag/texture-atomics.asm.frag create mode 100644 third_party/spirv-cross/reference/opt/shaders-ue4/asm/frag/texture-atomics.asm.graphics-robust-access.frag create mode 100644 third_party/spirv-cross/reference/opt/shaders-ue4/asm/tesc/hs-incorrect-base-type.asm.tesc create mode 100644 third_party/spirv-cross/reference/opt/shaders-ue4/asm/tesc/hs-input-array-access.asm.tesc create mode 100644 third_party/spirv-cross/reference/opt/shaders-ue4/asm/tesc/hs-texcoord-array.asm.tesc create mode 100644 third_party/spirv-cross/reference/opt/shaders-ue4/asm/tesc/tess-factor-must-be-threadgroup.asm.tesc create mode 100644 third_party/spirv-cross/reference/opt/shaders-ue4/asm/tese/ds-double-gl-in-deref.asm.tese create mode 100644 third_party/spirv-cross/reference/opt/shaders-ue4/asm/tese/ds-patch-input-fixes.asm.tese create mode 100644 third_party/spirv-cross/reference/opt/shaders-ue4/asm/tese/ds-patch-inputs.asm.tese create mode 100644 third_party/spirv-cross/reference/opt/shaders-ue4/asm/tese/ds-texcoord-array.asm.tese create mode 100644 third_party/spirv-cross/reference/opt/shaders-ue4/asm/vert/array-missing-copies.asm.vert create mode 100644 third_party/spirv-cross/reference/opt/shaders-ue4/asm/vert/texture-buffer.asm.vert create mode 100644 third_party/spirv-cross/reference/opt/shaders/asm/comp/bitcast_icmp.asm.comp create mode 100644 third_party/spirv-cross/reference/opt/shaders/asm/frag/image-fetch-no-sampler.no-samplerless.asm.vk.frag create mode 100644 third_party/spirv-cross/reference/opt/shaders/asm/frag/image-fetch-no-sampler.no-samplerless.asm.vk.frag.vk create mode 100644 third_party/spirv-cross/reference/opt/shaders/asm/frag/image-query-no-sampler.no-samplerless.vk.asm.frag create mode 100644 third_party/spirv-cross/reference/opt/shaders/asm/frag/image-query-no-sampler.no-samplerless.vk.asm.frag.vk delete mode 100644 third_party/spirv-cross/reference/opt/shaders/asm/frag/loop-merge-to-continue.asm.frag delete mode 100644 third_party/spirv-cross/reference/opt/shaders/asm/frag/selection-merge-to-continue.asm.frag delete mode 100644 third_party/spirv-cross/reference/opt/shaders/asm/frag/switch-merge-to-continue.asm.frag create mode 100644 third_party/spirv-cross/reference/opt/shaders/desktop-only/frag/image-size.frag create mode 100644 third_party/spirv-cross/reference/opt/shaders/desktop-only/frag/image-size.no-qualifier-deduction.frag create mode 100644 third_party/spirv-cross/reference/opt/shaders/frag/pixel-interlock-ordered.frag create mode 100644 third_party/spirv-cross/reference/opt/shaders/frag/pixel-interlock-unordered.frag create mode 100644 third_party/spirv-cross/reference/opt/shaders/frag/post-depth-coverage-es.frag create mode 100644 third_party/spirv-cross/reference/opt/shaders/frag/sample-interlock-ordered.frag create mode 100644 third_party/spirv-cross/reference/opt/shaders/frag/sample-interlock-unordered.frag create mode 100644 third_party/spirv-cross/reference/opt/shaders/frag/struct-type-unrelated-alias.frag create mode 100644 third_party/spirv-cross/reference/opt/shaders/geom/geometry-passthrough.geom create mode 100644 third_party/spirv-cross/reference/opt/shaders/geom/multi-stream.geom create mode 100644 third_party/spirv-cross/reference/opt/shaders/tese/load-array-of-array.tese create mode 100644 third_party/spirv-cross/reference/opt/shaders/tese/patch-input-array.tese create mode 100644 third_party/spirv-cross/reference/opt/shaders/vert/transform-feedback-decorations.vert create mode 100644 third_party/spirv-cross/reference/shaders-hlsl-no-opt/asm/comp/access-chain-load-store-composite.asm.comp create mode 100644 third_party/spirv-cross/reference/shaders-hlsl-no-opt/asm/comp/aliased-struct-divergent-member-name.asm.comp create mode 100644 third_party/spirv-cross/reference/shaders-hlsl-no-opt/asm/comp/bitfield-signed-operations.asm.comp rename third_party/spirv-cross/reference/{opt/shaders-hlsl => shaders-hlsl-no-opt}/asm/comp/storage-buffer-basic.invalid.nofxc.asm.comp (100%) create mode 100644 third_party/spirv-cross/reference/shaders-hlsl-no-opt/asm/frag/empty-struct-in-struct.asm.frag create mode 100644 third_party/spirv-cross/reference/shaders-hlsl-no-opt/asm/frag/pixel-interlock-callstack.sm51.fxconly.asm.frag create mode 100644 third_party/spirv-cross/reference/shaders-hlsl-no-opt/asm/frag/pixel-interlock-control-flow.sm51.fxconly.asm.frag create mode 100644 third_party/spirv-cross/reference/shaders-hlsl-no-opt/asm/frag/pixel-interlock-split-functions.sm51.fxconly.asm.frag create mode 100644 third_party/spirv-cross/reference/shaders-hlsl-no-opt/asm/frag/subgroup-arithmetic-cast.invalid.nofxc.sm60.asm.frag rename third_party/spirv-cross/reference/shaders-hlsl-no-opt/asm/frag/{switch-block-case-fallthrough.asm.frag => switch-block-case-fallthrough.asm.invalid.frag} (100%) create mode 100644 third_party/spirv-cross/reference/shaders-hlsl-no-opt/asm/frag/unordered-compare.asm.frag create mode 100644 third_party/spirv-cross/reference/shaders-hlsl-no-opt/comp/illegal-struct-name.asm.comp rename third_party/spirv-cross/reference/{shaders-hlsl => shaders-hlsl-no-opt}/comp/subgroups.invalid.nofxc.sm60.comp (98%) rename third_party/spirv-cross/reference/{opt/shaders-hlsl => shaders-hlsl-no-opt}/frag/constant-buffer-array.invalid.sm51.frag (100%) rename third_party/spirv-cross/reference/{shaders-hlsl => shaders-hlsl-no-opt}/frag/fp16.invalid.desktop.frag (100%) create mode 100644 third_party/spirv-cross/reference/shaders-hlsl-no-opt/frag/pixel-interlock-simple-callstack.sm51.fxconly.frag create mode 100644 third_party/spirv-cross/reference/shaders-hlsl/asm/comp/bitcast_icmp.asm.comp delete mode 100644 third_party/spirv-cross/reference/shaders-hlsl/asm/comp/storage-buffer-basic.invalid.nofxc.asm.comp create mode 100644 third_party/spirv-cross/reference/shaders-hlsl/comp/access-chain-load-composite.comp create mode 100644 third_party/spirv-cross/reference/shaders-hlsl/comp/access-chains.force-uav.comp delete mode 100644 third_party/spirv-cross/reference/shaders-hlsl/frag/constant-buffer-array.invalid.sm51.frag create mode 100644 third_party/spirv-cross/reference/shaders-hlsl/frag/pixel-interlock-ordered.sm51.fxconly.frag create mode 100644 third_party/spirv-cross/reference/shaders-hlsl/frag/readonly-coherent-ssbo.force-uav.frag create mode 100644 third_party/spirv-cross/reference/shaders-hlsl/frag/readonly-coherent-ssbo.frag create mode 100644 third_party/spirv-cross/reference/shaders-msl-no-opt/asm/comp/aliased-struct-divergent-member-name.asm.comp create mode 100644 third_party/spirv-cross/reference/shaders-msl-no-opt/asm/comp/bitfield-signed-operations.asm.comp create mode 100644 third_party/spirv-cross/reference/shaders-msl-no-opt/asm/comp/copy-logical-2.spv14.asm.comp create mode 100644 third_party/spirv-cross/reference/shaders-msl-no-opt/asm/comp/copy-logical.spv14.asm.comp rename third_party/spirv-cross/reference/{opt/shaders-msl => shaders-msl-no-opt}/asm/comp/storage-buffer-basic.invalid.asm.comp (100%) create mode 100644 third_party/spirv-cross/reference/shaders-msl-no-opt/asm/frag/empty-struct-in-struct.asm.frag delete mode 100644 third_party/spirv-cross/reference/shaders-msl-no-opt/asm/frag/inliner-dominator-inside-loop.asm.frag create mode 100644 third_party/spirv-cross/reference/shaders-msl-no-opt/asm/frag/modf-frexp-scalar-access-chain-output.asm.frag create mode 100644 third_party/spirv-cross/reference/shaders-msl-no-opt/asm/frag/pixel-interlock-callstack.msl2.asm.frag create mode 100644 third_party/spirv-cross/reference/shaders-msl-no-opt/asm/frag/pixel-interlock-control-flow.msl2.asm.frag create mode 100644 third_party/spirv-cross/reference/shaders-msl-no-opt/asm/frag/pixel-interlock-split-functions.msl2.asm.frag create mode 100644 third_party/spirv-cross/reference/shaders-msl-no-opt/asm/frag/subgroup-arithmetic-cast.msl21.asm.frag rename third_party/spirv-cross/reference/shaders-msl-no-opt/asm/frag/{switch-block-case-fallthrough.asm.frag => switch-block-case-fallthrough.asm.invalid.frag} (100%) rename third_party/spirv-cross/reference/{shaders-msl => shaders-msl-no-opt}/asm/tesc/tess-fixed-input-array-builtin-array.invalid.asm.tesc (63%) create mode 100644 third_party/spirv-cross/reference/shaders-msl-no-opt/comp/array-copy-threadgroup-memory.comp create mode 100644 third_party/spirv-cross/reference/shaders-msl-no-opt/comp/basic.dynamic-buffer.msl2.invalid.comp rename third_party/spirv-cross/reference/{shaders-msl => shaders-msl-no-opt}/comp/bitcast-16bit-1.invalid.comp (90%) rename third_party/spirv-cross/reference/{shaders-msl => shaders-msl-no-opt}/comp/bitcast-16bit-2.invalid.comp (92%) create mode 100644 third_party/spirv-cross/reference/shaders-msl-no-opt/comp/illegal-struct-name.asm.comp create mode 100644 third_party/spirv-cross/reference/shaders-msl-no-opt/comp/int64.invalid.msl22.comp create mode 100644 third_party/spirv-cross/reference/shaders-msl-no-opt/comp/std140-array-load-composite-construct.comp rename third_party/spirv-cross/reference/{opt/shaders-msl/vulkan => shaders-msl-no-opt}/comp/struct-packing-scalar.nocompat.invalid.vk.comp (98%) rename third_party/spirv-cross/reference/{shaders-msl/vulkan => shaders-msl-no-opt}/comp/subgroups.nocompat.invalid.vk.msl21.comp (99%) rename third_party/spirv-cross/reference/{shaders-msl/vulkan => shaders-msl-no-opt}/comp/subgroups.nocompat.invalid.vk.msl21.ios.comp (95%) create mode 100644 third_party/spirv-cross/reference/shaders-msl-no-opt/components/fragment-input-component.frag create mode 100644 third_party/spirv-cross/reference/shaders-msl-no-opt/components/fragment-output-component.frag create mode 100644 third_party/spirv-cross/reference/shaders-msl-no-opt/components/fragment-output-component.pad-fragment.frag create mode 100644 third_party/spirv-cross/reference/shaders-msl-no-opt/components/vertex-input-component.vert rename third_party/spirv-cross/reference/{shaders-msl/vert/viewport-index.msl2.invalid.vert => shaders-msl-no-opt/components/vertex-output-component.vert} (57%) rename third_party/spirv-cross/reference/{shaders-msl => shaders-msl-no-opt}/frag/16bit-constants.invalid.frag (84%) rename third_party/spirv-cross/reference/{shaders-msl/vulkan => shaders-msl-no-opt}/frag/demote-to-helper.vk.nocompat.msl21.invalid.frag (100%) create mode 100644 third_party/spirv-cross/reference/shaders-msl-no-opt/frag/force-active-resources.msl2.argument..force-active.discrete.frag rename third_party/spirv-cross/reference/{shaders-msl => shaders-msl-no-opt}/frag/fp16.desktop.invalid.frag (92%) rename third_party/spirv-cross/reference/{shaders-msl/asm => shaders-msl-no-opt}/frag/min-max-clamp.invalid.asm.frag (100%) create mode 100644 third_party/spirv-cross/reference/shaders-msl-no-opt/frag/pixel-interlock-simple-callstack.msl2.frag rename third_party/spirv-cross/reference/{opt/shaders-msl/vulkan => shaders-msl-no-opt}/frag/scalar-block-layout-ubo-std430.vk.nocompat.invalid.frag (100%) rename third_party/spirv-cross/reference/{shaders-msl => shaders-msl-no-opt}/frag/shadow-compare-global-alias.invalid.frag (90%) rename third_party/spirv-cross/reference/{shaders-msl/vulkan => shaders-msl-no-opt}/frag/subgroups.nocompat.invalid.vk.msl21.frag (100%) create mode 100644 third_party/spirv-cross/reference/shaders-msl-no-opt/packing/array-of-vec3.comp create mode 100644 third_party/spirv-cross/reference/shaders-msl-no-opt/packing/array-of-vec4.comp create mode 100644 third_party/spirv-cross/reference/shaders-msl-no-opt/packing/load-store-col-rows.comp rename third_party/spirv-cross/reference/{opt/shaders-msl => shaders-msl-no-opt}/vert/layer.msl11.invalid.vert (100%) create mode 100644 third_party/spirv-cross/reference/shaders-msl-no-opt/vert/pass-array-by-value.force-native-array.vert rename third_party/spirv-cross/reference/{opt/shaders-msl => shaders-msl-no-opt}/vert/viewport-index.msl2.invalid.vert (100%) create mode 100644 third_party/spirv-cross/reference/shaders-msl/asm/comp/bitcast_icmp.asm.comp delete mode 100644 third_party/spirv-cross/reference/shaders-msl/asm/comp/storage-buffer-basic.invalid.asm.comp create mode 100644 third_party/spirv-cross/reference/shaders-msl/asm/frag/texture-atomics.asm.frag create mode 100644 third_party/spirv-cross/reference/shaders-msl/asm/frag/texture-atomics.asm.graphics-robust-access.frag create mode 100644 third_party/spirv-cross/reference/shaders-msl/asm/vert/clip-distance-plain-variable.asm.vert create mode 100644 third_party/spirv-cross/reference/shaders-msl/comp/argument-buffers-image-load-store.ios.msl2.argument.comp create mode 100644 third_party/spirv-cross/reference/shaders-msl/comp/basic.dispatchbase.comp create mode 100644 third_party/spirv-cross/reference/shaders-msl/comp/basic.dispatchbase.msl11.comp create mode 100644 third_party/spirv-cross/reference/shaders-msl/comp/basic.inline-block.msl2.comp create mode 100644 third_party/spirv-cross/reference/shaders-msl/comp/complex-composite-constant-array.comp create mode 100644 third_party/spirv-cross/reference/shaders-msl/comp/composite-array-initialization.force-native-array.comp create mode 100644 third_party/spirv-cross/reference/shaders-msl/comp/copy-array-of-arrays.force-native-array.comp create mode 100644 third_party/spirv-cross/reference/shaders-msl/comp/image-atomic-automatic-bindings.comp delete mode 100644 third_party/spirv-cross/reference/shaders-msl/comp/int64.invalid.msl22.comp create mode 100644 third_party/spirv-cross/reference/shaders-msl/frag/array-of-array-lut.frag create mode 100644 third_party/spirv-cross/reference/shaders-msl/frag/clip-distance-varying.frag create mode 100644 third_party/spirv-cross/reference/shaders-msl/frag/huge-argument-buffer.device-argument-buffer.argument.msl2.frag create mode 100644 third_party/spirv-cross/reference/shaders-msl/frag/pixel-interlock-ordered.msl2.argument.frag create mode 100644 third_party/spirv-cross/reference/shaders-msl/frag/pixel-interlock-ordered.msl2.frag create mode 100644 third_party/spirv-cross/reference/shaders-msl/frag/sample-depth-propagate-state-from-resource.frag create mode 100644 third_party/spirv-cross/reference/shaders-msl/frag/texture-cube-array.frag create mode 100644 third_party/spirv-cross/reference/shaders-msl/frag/texture-cube-array.ios.emulate-cube-array.frag create mode 100644 third_party/spirv-cross/reference/shaders-msl/tesc/load-control-point-array-of-matrix.tesc create mode 100644 third_party/spirv-cross/reference/shaders-msl/tesc/load-control-point-array-of-struct.tesc create mode 100644 third_party/spirv-cross/reference/shaders-msl/tesc/load-control-point-array.tesc create mode 100644 third_party/spirv-cross/reference/shaders-msl/tese/load-control-point-array-of-matrix.tese create mode 100644 third_party/spirv-cross/reference/shaders-msl/tese/load-control-point-array.tese create mode 100644 third_party/spirv-cross/reference/shaders-msl/vert/clip-distance-block.vert create mode 100644 third_party/spirv-cross/reference/shaders-msl/vert/float-math.invariant-float-math.vert create mode 100644 third_party/spirv-cross/reference/shaders-msl/vert/float-math.vert create mode 100644 third_party/spirv-cross/reference/shaders-msl/vert/return-array.force-native-array.vert delete mode 100644 third_party/spirv-cross/reference/shaders-msl/vulkan/comp/struct-packing-scalar.nocompat.invalid.vk.comp delete mode 100644 third_party/spirv-cross/reference/shaders-msl/vulkan/frag/scalar-block-layout-ubo-std430.vk.nocompat.invalid.frag create mode 100644 third_party/spirv-cross/reference/shaders-no-opt/asm/comp/access-tracking-function-call-result.asm.comp create mode 100644 third_party/spirv-cross/reference/shaders-no-opt/asm/comp/aliased-struct-divergent-member-name.asm.comp create mode 100644 third_party/spirv-cross/reference/shaders-no-opt/asm/comp/bitfield-signed-operations.asm.comp create mode 100644 third_party/spirv-cross/reference/shaders-no-opt/asm/comp/copy-logical.spv14.asm.comp rename third_party/spirv-cross/reference/{opt/shaders/asm => shaders-no-opt/asm/comp}/extended-debug-extinst.invalid.asm.comp (100%) rename third_party/spirv-cross/reference/{opt/shaders/asm/comp/phi-temporary-copy-loop-variable.asm.comp => shaders-no-opt/asm/comp/phi-temporary-copy-loop-variable.asm.invalid.comp} (86%) rename third_party/spirv-cross/reference/{opt/shaders => shaders-no-opt}/asm/comp/storage-buffer-basic.invalid.asm.comp (100%) create mode 100644 third_party/spirv-cross/reference/shaders-no-opt/asm/frag/combined-image-sampler-dxc-min16float.asm.invalid.frag create mode 100644 third_party/spirv-cross/reference/shaders-no-opt/asm/frag/demote-impure-function-call.vk.nocompat.asm.frag.vk create mode 100644 third_party/spirv-cross/reference/shaders-no-opt/asm/frag/discard-impure-function-call.asm.frag create mode 100644 third_party/spirv-cross/reference/shaders-no-opt/asm/frag/do-while-continue-phi.asm.invalid.frag create mode 100644 third_party/spirv-cross/reference/shaders-no-opt/asm/frag/empty-struct-in-struct.asm.frag rename third_party/spirv-cross/reference/shaders-no-opt/asm/frag/{for-loop-dedicated-merge-block-inverted.asm.frag => for-loop-dedicated-merge-block-inverted.asm.invalid.frag} (100%) rename third_party/spirv-cross/reference/shaders-no-opt/asm/frag/{for-loop-dedicated-merge-block-non-inverted.asm.frag => for-loop-dedicated-merge-block-non-inverted.asm.invalid.frag} (100%) create mode 100644 third_party/spirv-cross/reference/shaders-no-opt/asm/frag/ldexp-uint-exponent.asm.frag rename third_party/spirv-cross/reference/{shaders/asm/frag/loop-merge-to-continue.asm.frag => shaders-no-opt/asm/frag/loop-merge-to-continue.asm.invalid.frag} (100%) create mode 100644 third_party/spirv-cross/reference/shaders-no-opt/asm/frag/pixel-interlock-callstack.asm.frag create mode 100644 third_party/spirv-cross/reference/shaders-no-opt/asm/frag/pixel-interlock-control-flow.asm.frag create mode 100644 third_party/spirv-cross/reference/shaders-no-opt/asm/frag/pixel-interlock-split-functions.asm.frag rename third_party/spirv-cross/reference/{shaders/asm/frag/selection-merge-to-continue.asm.frag => shaders-no-opt/asm/frag/selection-merge-to-continue.asm.invalid.frag} (88%) create mode 100644 third_party/spirv-cross/reference/shaders-no-opt/asm/frag/subgroup-arithmetic-cast.nocompat.vk.asm.frag.vk rename third_party/spirv-cross/reference/shaders-no-opt/asm/frag/{switch-block-case-fallthrough.asm.frag => switch-block-case-fallthrough.asm.invalid.frag} (100%) rename third_party/spirv-cross/reference/{shaders/asm/frag/switch-merge-to-continue.asm.frag => shaders-no-opt/asm/frag/switch-merge-to-continue.asm.invalid.frag} (100%) create mode 100644 third_party/spirv-cross/reference/shaders-no-opt/asm/frag/switch-single-case-multiple-exit-cfg.asm.frag create mode 100644 third_party/spirv-cross/reference/shaders-no-opt/asm/frag/unordered-compare.asm.frag create mode 100644 third_party/spirv-cross/reference/shaders-no-opt/asm/frag/vector-extract-dynamic-spec-constant.asm.frag rename third_party/spirv-cross/reference/{opt/shaders => shaders-no-opt}/asm/geom/store-uint-layer.invalid.asm.geom (100%) rename third_party/spirv-cross/reference/{opt/shaders => shaders-no-opt}/asm/tesc/tess-fixed-input-array-builtin-array.invalid.asm.tesc (100%) rename third_party/spirv-cross/reference/{opt/shaders => shaders-no-opt}/comp/bitcast-16bit-1.invalid.comp (100%) rename third_party/spirv-cross/reference/{opt/shaders => shaders-no-opt}/comp/bitcast-16bit-2.invalid.comp (100%) create mode 100644 third_party/spirv-cross/reference/shaders-no-opt/comp/illegal-struct-name.asm.comp rename third_party/spirv-cross/reference/{opt/shaders => shaders-no-opt}/comp/inout-struct.invalid.comp (100%) rename third_party/spirv-cross/reference/{opt/shaders/amd => shaders-no-opt/comp}/shader_ballot_nonuniform_invocations.invalid.comp (100%) rename third_party/spirv-cross/reference/{opt/shaders/vulkan => shaders-no-opt}/comp/struct-packing-scalar.nocompat.invalid.vk.comp.vk (100%) rename third_party/spirv-cross/reference/{opt/shaders/vulkan => shaders-no-opt}/comp/subgroups.nocompat.invalid.vk.comp.vk (100%) rename third_party/spirv-cross/reference/{opt/shaders => shaders-no-opt}/frag/16bit-constants.invalid.frag (100%) rename third_party/spirv-cross/reference/{opt/shaders/desktop-only => shaders-no-opt}/frag/fp16.invalid.desktop.frag (100%) rename third_party/spirv-cross/reference/{opt/shaders/amd => shaders-no-opt/frag}/fragmentMaskFetch_subpassInput.vk.nocompat.invalid.frag.vk (100%) rename third_party/spirv-cross/reference/{opt/shaders/amd => shaders-no-opt/frag}/fs.invalid.frag (100%) rename third_party/spirv-cross/reference/{opt/shaders/flatten => shaders-no-opt/frag}/multi-dimensional.desktop.invalid.flatten_dim.frag (100%) create mode 100644 third_party/spirv-cross/reference/shaders-no-opt/frag/pixel-interlock-simple-callstack.frag rename third_party/spirv-cross/reference/{opt/shaders/vulkan => shaders-no-opt}/frag/scalar-block-layout-ubo-std430.vk.nocompat.invalid.frag.vk (100%) create mode 100644 third_party/spirv-cross/reference/shaders-reflection/comp/workgroup-size-spec-constant.comp.json create mode 100644 third_party/spirv-cross/reference/shaders-reflection/vert/array-size-reflection.vert.json create mode 100644 third_party/spirv-cross/reference/shaders-reflection/vert/stride-reflection.vert.json create mode 100644 third_party/spirv-cross/reference/shaders-ue4-no-opt/asm/frag/accesschain-invalid-expression.asm.invalid.frag create mode 100644 third_party/spirv-cross/reference/shaders-ue4-no-opt/asm/frag/array-copy-error.asm.invalid.frag create mode 100644 third_party/spirv-cross/reference/shaders-ue4-no-opt/asm/frag/phi-variable-declaration.asm.invalid.frag create mode 100644 third_party/spirv-cross/reference/shaders-ue4-no-opt/asm/vert/loop-accesschain-writethrough.asm.invalid.vert create mode 100644 third_party/spirv-cross/reference/shaders-ue4/asm/frag/depth-compare.asm.frag create mode 100644 third_party/spirv-cross/reference/shaders-ue4/asm/frag/global-constant-arrays.asm.frag create mode 100644 third_party/spirv-cross/reference/shaders-ue4/asm/frag/padded-float-array-member-defef.asm.frag create mode 100644 third_party/spirv-cross/reference/shaders-ue4/asm/frag/sample-mask-not-array.asm.frag create mode 100644 third_party/spirv-cross/reference/shaders-ue4/asm/frag/subpass-input.ios.framebuffer-fetch.asm.frag create mode 100644 third_party/spirv-cross/reference/shaders-ue4/asm/frag/texture-atomics.asm.frag create mode 100644 third_party/spirv-cross/reference/shaders-ue4/asm/frag/texture-atomics.asm.graphics-robust-access.frag create mode 100644 third_party/spirv-cross/reference/shaders-ue4/asm/tesc/hs-incorrect-base-type.asm.tesc create mode 100644 third_party/spirv-cross/reference/shaders-ue4/asm/tesc/hs-input-array-access.asm.tesc create mode 100644 third_party/spirv-cross/reference/shaders-ue4/asm/tesc/hs-texcoord-array.asm.tesc create mode 100644 third_party/spirv-cross/reference/shaders-ue4/asm/tesc/tess-factor-must-be-threadgroup.asm.tesc create mode 100644 third_party/spirv-cross/reference/shaders-ue4/asm/tese/ds-double-gl-in-deref.asm.tese create mode 100644 third_party/spirv-cross/reference/shaders-ue4/asm/tese/ds-patch-input-fixes.asm.tese create mode 100644 third_party/spirv-cross/reference/shaders-ue4/asm/tese/ds-patch-inputs.asm.tese create mode 100644 third_party/spirv-cross/reference/shaders-ue4/asm/tese/ds-texcoord-array.asm.tese create mode 100644 third_party/spirv-cross/reference/shaders-ue4/asm/vert/array-missing-copies.asm.vert create mode 100644 third_party/spirv-cross/reference/shaders-ue4/asm/vert/texture-buffer.asm.vert delete mode 100644 third_party/spirv-cross/reference/shaders/amd/fragmentMaskFetch_subpassInput.vk.nocompat.invalid.frag.vk delete mode 100644 third_party/spirv-cross/reference/shaders/amd/fs.invalid.frag delete mode 100644 third_party/spirv-cross/reference/shaders/amd/shader_ballot_nonuniform_invocations.invalid.comp create mode 100644 third_party/spirv-cross/reference/shaders/asm/comp/bitcast_icmp.asm.comp delete mode 100644 third_party/spirv-cross/reference/shaders/asm/comp/phi-temporary-copy-loop-variable.asm.comp delete mode 100644 third_party/spirv-cross/reference/shaders/asm/comp/storage-buffer-basic.invalid.asm.comp delete mode 100644 third_party/spirv-cross/reference/shaders/asm/extended-debug-extinst.invalid.asm.comp create mode 100644 third_party/spirv-cross/reference/shaders/asm/frag/image-fetch-no-sampler.no-samplerless.asm.vk.frag create mode 100644 third_party/spirv-cross/reference/shaders/asm/frag/image-fetch-no-sampler.no-samplerless.asm.vk.frag.vk create mode 100644 third_party/spirv-cross/reference/shaders/asm/frag/image-query-no-sampler.no-samplerless.vk.asm.frag create mode 100644 third_party/spirv-cross/reference/shaders/asm/frag/image-query-no-sampler.no-samplerless.vk.asm.frag.vk delete mode 100644 third_party/spirv-cross/reference/shaders/asm/geom/store-uint-layer.invalid.asm.geom delete mode 100644 third_party/spirv-cross/reference/shaders/asm/tesc/tess-fixed-input-array-builtin-array.invalid.asm.tesc delete mode 100644 third_party/spirv-cross/reference/shaders/comp/bitcast-16bit-1.invalid.comp delete mode 100644 third_party/spirv-cross/reference/shaders/comp/bitcast-16bit-2.invalid.comp delete mode 100644 third_party/spirv-cross/reference/shaders/comp/inout-struct.invalid.comp delete mode 100644 third_party/spirv-cross/reference/shaders/desktop-only/frag/fp16.invalid.desktop.frag create mode 100644 third_party/spirv-cross/reference/shaders/desktop-only/frag/image-size.frag create mode 100644 third_party/spirv-cross/reference/shaders/desktop-only/frag/image-size.no-qualifier-deduction.frag delete mode 100644 third_party/spirv-cross/reference/shaders/flatten/multi-dimensional.desktop.invalid.flatten_dim.frag delete mode 100644 third_party/spirv-cross/reference/shaders/frag/16bit-constants.invalid.frag create mode 100644 third_party/spirv-cross/reference/shaders/frag/pixel-interlock-ordered.frag create mode 100644 third_party/spirv-cross/reference/shaders/frag/pixel-interlock-unordered.frag create mode 100644 third_party/spirv-cross/reference/shaders/frag/post-depth-coverage-es.frag create mode 100644 third_party/spirv-cross/reference/shaders/frag/sample-interlock-ordered.frag create mode 100644 third_party/spirv-cross/reference/shaders/frag/sample-interlock-unordered.frag create mode 100644 third_party/spirv-cross/reference/shaders/frag/struct-type-unrelated-alias.frag create mode 100644 third_party/spirv-cross/reference/shaders/geom/geometry-passthrough.geom create mode 100644 third_party/spirv-cross/reference/shaders/geom/multi-stream.geom create mode 100644 third_party/spirv-cross/reference/shaders/tese/load-array-of-array.tese create mode 100644 third_party/spirv-cross/reference/shaders/tese/patch-input-array.tese create mode 100644 third_party/spirv-cross/reference/shaders/vert/transform-feedback-decorations.vert delete mode 100644 third_party/spirv-cross/reference/shaders/vulkan/comp/struct-packing-scalar.nocompat.invalid.vk.comp.vk delete mode 100644 third_party/spirv-cross/reference/shaders/vulkan/comp/subgroups.nocompat.invalid.vk.comp.vk delete mode 100644 third_party/spirv-cross/reference/shaders/vulkan/frag/scalar-block-layout-ubo-std430.vk.nocompat.invalid.frag.vk create mode 100644 third_party/spirv-cross/shaders-hlsl-no-opt/asm/comp/access-chain-load-store-composite.asm.comp create mode 100644 third_party/spirv-cross/shaders-hlsl-no-opt/asm/comp/aliased-struct-divergent-member-name.asm.comp create mode 100644 third_party/spirv-cross/shaders-hlsl-no-opt/asm/comp/bitfield-signed-operations.asm.comp rename third_party/spirv-cross/{shaders-hlsl => shaders-hlsl-no-opt}/asm/comp/storage-buffer-basic.invalid.nofxc.asm.comp (100%) create mode 100644 third_party/spirv-cross/shaders-hlsl-no-opt/asm/frag/empty-struct-in-struct.asm.frag create mode 100644 third_party/spirv-cross/shaders-hlsl-no-opt/asm/frag/pixel-interlock-callstack.sm51.fxconly.asm.frag create mode 100644 third_party/spirv-cross/shaders-hlsl-no-opt/asm/frag/pixel-interlock-control-flow.sm51.fxconly.asm.frag create mode 100644 third_party/spirv-cross/shaders-hlsl-no-opt/asm/frag/pixel-interlock-split-functions.sm51.fxconly.asm.frag create mode 100644 third_party/spirv-cross/shaders-hlsl-no-opt/asm/frag/subgroup-arithmetic-cast.invalid.nofxc.sm60.asm.frag rename third_party/spirv-cross/shaders-hlsl-no-opt/asm/frag/{switch-block-case-fallthrough.asm.frag => switch-block-case-fallthrough.asm.invalid.frag} (100%) create mode 100644 third_party/spirv-cross/shaders-hlsl-no-opt/asm/frag/unordered-compare.asm.frag create mode 100644 third_party/spirv-cross/shaders-hlsl-no-opt/comp/illegal-struct-name.asm.comp rename third_party/spirv-cross/{shaders-hlsl => shaders-hlsl-no-opt}/comp/subgroups.invalid.nofxc.sm60.comp (100%) rename third_party/spirv-cross/{shaders-hlsl => shaders-hlsl-no-opt}/frag/constant-buffer-array.invalid.sm51.frag (100%) rename third_party/spirv-cross/{shaders-hlsl => shaders-hlsl-no-opt}/frag/fp16.invalid.desktop.frag (100%) create mode 100644 third_party/spirv-cross/shaders-hlsl-no-opt/frag/pixel-interlock-simple-callstack.sm51.fxconly.frag create mode 100644 third_party/spirv-cross/shaders-hlsl/asm/comp/bitcast_icmp.asm.comp create mode 100644 third_party/spirv-cross/shaders-hlsl/comp/access-chain-load-composite.comp create mode 100644 third_party/spirv-cross/shaders-hlsl/comp/access-chains.force-uav.comp create mode 100644 third_party/spirv-cross/shaders-hlsl/frag/pixel-interlock-ordered.sm51.fxconly.frag create mode 100644 third_party/spirv-cross/shaders-hlsl/frag/readonly-coherent-ssbo.force-uav.frag create mode 100644 third_party/spirv-cross/shaders-hlsl/frag/readonly-coherent-ssbo.frag create mode 100644 third_party/spirv-cross/shaders-msl-no-opt/asm/comp/aliased-struct-divergent-member-name.asm.comp create mode 100644 third_party/spirv-cross/shaders-msl-no-opt/asm/comp/bitfield-signed-operations.asm.comp create mode 100644 third_party/spirv-cross/shaders-msl-no-opt/asm/comp/copy-logical-2.spv14.asm.comp create mode 100644 third_party/spirv-cross/shaders-msl-no-opt/asm/comp/copy-logical.spv14.asm.comp rename third_party/spirv-cross/{shaders-msl => shaders-msl-no-opt}/asm/comp/storage-buffer-basic.invalid.asm.comp (100%) create mode 100644 third_party/spirv-cross/shaders-msl-no-opt/asm/frag/empty-struct-in-struct.asm.frag delete mode 100644 third_party/spirv-cross/shaders-msl-no-opt/asm/frag/inliner-dominator-inside-loop.asm.frag create mode 100644 third_party/spirv-cross/shaders-msl-no-opt/asm/frag/modf-frexp-scalar-access-chain-output.asm.frag create mode 100644 third_party/spirv-cross/shaders-msl-no-opt/asm/frag/pixel-interlock-callstack.msl2.asm.frag create mode 100644 third_party/spirv-cross/shaders-msl-no-opt/asm/frag/pixel-interlock-control-flow.msl2.asm.frag create mode 100644 third_party/spirv-cross/shaders-msl-no-opt/asm/frag/pixel-interlock-split-functions.msl2.asm.frag create mode 100644 third_party/spirv-cross/shaders-msl-no-opt/asm/frag/subgroup-arithmetic-cast.msl21.asm.frag rename third_party/spirv-cross/shaders-msl-no-opt/asm/frag/{switch-block-case-fallthrough.asm.frag => switch-block-case-fallthrough.asm.invalid.frag} (100%) rename third_party/spirv-cross/{shaders-msl => shaders-msl-no-opt}/asm/tesc/tess-fixed-input-array-builtin-array.invalid.asm.tesc (100%) create mode 100644 third_party/spirv-cross/shaders-msl-no-opt/comp/array-copy-threadgroup-memory.comp create mode 100644 third_party/spirv-cross/shaders-msl-no-opt/comp/basic.dynamic-buffer.msl2.invalid.comp rename third_party/spirv-cross/{shaders-msl => shaders-msl-no-opt}/comp/bitcast-16bit-1.invalid.comp (100%) rename third_party/spirv-cross/{shaders-msl => shaders-msl-no-opt}/comp/bitcast-16bit-2.invalid.comp (100%) create mode 100644 third_party/spirv-cross/shaders-msl-no-opt/comp/illegal-struct-name.asm.comp rename third_party/spirv-cross/{shaders-msl => shaders-msl-no-opt}/comp/int64.invalid.msl22.comp (100%) create mode 100644 third_party/spirv-cross/shaders-msl-no-opt/comp/std140-array-load-composite-construct.comp rename third_party/spirv-cross/{shaders-msl/vulkan => shaders-msl-no-opt}/comp/struct-packing-scalar.nocompat.invalid.vk.comp (100%) rename third_party/spirv-cross/{shaders-msl/vulkan => shaders-msl-no-opt}/comp/subgroups.nocompat.invalid.vk.msl21.comp (100%) rename third_party/spirv-cross/{shaders-msl/vulkan => shaders-msl-no-opt}/comp/subgroups.nocompat.invalid.vk.msl21.ios.comp (100%) create mode 100644 third_party/spirv-cross/shaders-msl-no-opt/components/fragment-input-component.frag create mode 100644 third_party/spirv-cross/shaders-msl-no-opt/components/fragment-output-component.frag create mode 100644 third_party/spirv-cross/shaders-msl-no-opt/components/fragment-output-component.pad-fragment.frag create mode 100644 third_party/spirv-cross/shaders-msl-no-opt/components/vertex-input-component.vert create mode 100644 third_party/spirv-cross/shaders-msl-no-opt/components/vertex-output-component.vert rename third_party/spirv-cross/{shaders-msl => shaders-msl-no-opt}/frag/16bit-constants.invalid.frag (100%) rename third_party/spirv-cross/{shaders-msl/vulkan => shaders-msl-no-opt}/frag/demote-to-helper.vk.nocompat.msl21.invalid.frag (100%) create mode 100644 third_party/spirv-cross/shaders-msl-no-opt/frag/force-active-resources.msl2.argument..force-active.discrete.frag rename third_party/spirv-cross/{shaders-msl => shaders-msl-no-opt}/frag/fp16.desktop.invalid.frag (100%) rename third_party/spirv-cross/{shaders-msl/asm => shaders-msl-no-opt}/frag/min-max-clamp.invalid.asm.frag (100%) create mode 100644 third_party/spirv-cross/shaders-msl-no-opt/frag/pixel-interlock-simple-callstack.msl2.frag rename third_party/spirv-cross/{shaders-msl/vulkan => shaders-msl-no-opt}/frag/scalar-block-layout-ubo-std430.vk.nocompat.invalid.frag (100%) rename third_party/spirv-cross/{shaders-msl => shaders-msl-no-opt}/frag/shadow-compare-global-alias.invalid.frag (100%) rename third_party/spirv-cross/{shaders-msl/vulkan => shaders-msl-no-opt}/frag/subgroups.nocompat.invalid.vk.msl21.frag (100%) create mode 100644 third_party/spirv-cross/shaders-msl-no-opt/packing/array-of-vec3.comp create mode 100644 third_party/spirv-cross/shaders-msl-no-opt/packing/array-of-vec4.comp create mode 100644 third_party/spirv-cross/shaders-msl-no-opt/packing/load-store-col-rows.comp rename third_party/spirv-cross/{shaders-msl => shaders-msl-no-opt}/vert/layer.msl11.invalid.vert (100%) create mode 100644 third_party/spirv-cross/shaders-msl-no-opt/vert/pass-array-by-value.force-native-array.vert rename third_party/spirv-cross/{shaders-msl => shaders-msl-no-opt}/vert/viewport-index.msl2.invalid.vert (100%) create mode 100644 third_party/spirv-cross/shaders-msl/asm/comp/bitcast_icmp.asm.comp create mode 100644 third_party/spirv-cross/shaders-msl/asm/vert/clip-distance-plain-variable.asm.vert create mode 100644 third_party/spirv-cross/shaders-msl/comp/argument-buffers-image-load-store.ios.msl2.argument.comp create mode 100644 third_party/spirv-cross/shaders-msl/comp/basic.dispatchbase.comp create mode 100644 third_party/spirv-cross/shaders-msl/comp/basic.dispatchbase.msl11.comp create mode 100644 third_party/spirv-cross/shaders-msl/comp/basic.inline-block.msl2.comp create mode 100644 third_party/spirv-cross/shaders-msl/comp/complex-composite-constant-array.comp create mode 100644 third_party/spirv-cross/shaders-msl/comp/composite-array-initialization.force-native-array.comp create mode 100644 third_party/spirv-cross/shaders-msl/comp/copy-array-of-arrays.force-native-array.comp create mode 100644 third_party/spirv-cross/shaders-msl/comp/image-atomic-automatic-bindings.comp create mode 100644 third_party/spirv-cross/shaders-msl/frag/array-of-array-lut.frag create mode 100644 third_party/spirv-cross/shaders-msl/frag/clip-distance-varying.frag create mode 100644 third_party/spirv-cross/shaders-msl/frag/huge-argument-buffer.device-argument-buffer.argument.msl2.frag create mode 100644 third_party/spirv-cross/shaders-msl/frag/pixel-interlock-ordered.msl2.argument.frag create mode 100644 third_party/spirv-cross/shaders-msl/frag/pixel-interlock-ordered.msl2.frag create mode 100644 third_party/spirv-cross/shaders-msl/frag/sample-depth-propagate-state-from-resource.frag create mode 100644 third_party/spirv-cross/shaders-msl/frag/texture-cube-array.frag create mode 100644 third_party/spirv-cross/shaders-msl/frag/texture-cube-array.ios.emulate-cube-array.frag create mode 100644 third_party/spirv-cross/shaders-msl/tesc/load-control-point-array-of-matrix.tesc create mode 100644 third_party/spirv-cross/shaders-msl/tesc/load-control-point-array-of-struct.tesc create mode 100644 third_party/spirv-cross/shaders-msl/tesc/load-control-point-array.tesc create mode 100644 third_party/spirv-cross/shaders-msl/tese/load-control-point-array-of-matrix.tese create mode 100644 third_party/spirv-cross/shaders-msl/tese/load-control-point-array.tese create mode 100644 third_party/spirv-cross/shaders-msl/vert/clip-distance-block.vert create mode 100644 third_party/spirv-cross/shaders-msl/vert/float-math.invariant-float-math.vert create mode 100644 third_party/spirv-cross/shaders-msl/vert/float-math.vert create mode 100644 third_party/spirv-cross/shaders-msl/vert/return-array.force-native-array.vert create mode 100644 third_party/spirv-cross/shaders-no-opt/asm/comp/access-tracking-function-call-result.asm.comp create mode 100644 third_party/spirv-cross/shaders-no-opt/asm/comp/aliased-struct-divergent-member-name.asm.comp create mode 100644 third_party/spirv-cross/shaders-no-opt/asm/comp/bitfield-signed-operations.asm.comp create mode 100644 third_party/spirv-cross/shaders-no-opt/asm/comp/copy-logical.spv14.asm.comp rename third_party/spirv-cross/{shaders/asm => shaders-no-opt/asm/comp}/extended-debug-extinst.invalid.asm.comp (100%) rename third_party/spirv-cross/{shaders/asm/comp/phi-temporary-copy-loop-variable.asm.comp => shaders-no-opt/asm/comp/phi-temporary-copy-loop-variable.asm.invalid.comp} (100%) rename third_party/spirv-cross/{shaders => shaders-no-opt}/asm/comp/storage-buffer-basic.invalid.asm.comp (100%) create mode 100644 third_party/spirv-cross/shaders-no-opt/asm/frag/combined-image-sampler-dxc-min16float.asm.invalid.frag create mode 100644 third_party/spirv-cross/shaders-no-opt/asm/frag/demote-impure-function-call.vk.nocompat.asm.frag create mode 100644 third_party/spirv-cross/shaders-no-opt/asm/frag/discard-impure-function-call.asm.frag create mode 100644 third_party/spirv-cross/shaders-no-opt/asm/frag/do-while-continue-phi.asm.invalid.frag create mode 100644 third_party/spirv-cross/shaders-no-opt/asm/frag/empty-struct-in-struct.asm.frag rename third_party/spirv-cross/shaders-no-opt/asm/frag/{for-loop-dedicated-merge-block-inverted.asm.frag => for-loop-dedicated-merge-block-inverted.asm.invalid.frag} (100%) rename third_party/spirv-cross/shaders-no-opt/asm/frag/{for-loop-dedicated-merge-block-non-inverted.asm.frag => for-loop-dedicated-merge-block-non-inverted.asm.invalid.frag} (100%) create mode 100644 third_party/spirv-cross/shaders-no-opt/asm/frag/ldexp-uint-exponent.asm.frag rename third_party/spirv-cross/{shaders/asm/frag/loop-merge-to-continue.asm.frag => shaders-no-opt/asm/frag/loop-merge-to-continue.asm.invalid.frag} (100%) create mode 100644 third_party/spirv-cross/shaders-no-opt/asm/frag/pixel-interlock-callstack.asm.frag create mode 100644 third_party/spirv-cross/shaders-no-opt/asm/frag/pixel-interlock-control-flow.asm.frag create mode 100644 third_party/spirv-cross/shaders-no-opt/asm/frag/pixel-interlock-split-functions.asm.frag rename third_party/spirv-cross/{shaders/asm/frag/selection-merge-to-continue.asm.frag => shaders-no-opt/asm/frag/selection-merge-to-continue.asm.invalid.frag} (100%) create mode 100644 third_party/spirv-cross/shaders-no-opt/asm/frag/subgroup-arithmetic-cast.nocompat.vk.asm.frag rename third_party/spirv-cross/shaders-no-opt/asm/frag/{switch-block-case-fallthrough.asm.frag => switch-block-case-fallthrough.asm.invalid.frag} (100%) rename third_party/spirv-cross/{shaders/asm/frag/switch-merge-to-continue.asm.frag => shaders-no-opt/asm/frag/switch-merge-to-continue.asm.invalid.frag} (100%) create mode 100644 third_party/spirv-cross/shaders-no-opt/asm/frag/switch-single-case-multiple-exit-cfg.asm.frag create mode 100644 third_party/spirv-cross/shaders-no-opt/asm/frag/unordered-compare.asm.frag create mode 100644 third_party/spirv-cross/shaders-no-opt/asm/frag/vector-extract-dynamic-spec-constant.asm.frag rename third_party/spirv-cross/{shaders => shaders-no-opt}/asm/geom/store-uint-layer.invalid.asm.geom (100%) rename third_party/spirv-cross/{shaders => shaders-no-opt}/asm/tesc/tess-fixed-input-array-builtin-array.invalid.asm.tesc (100%) rename third_party/spirv-cross/{shaders => shaders-no-opt}/comp/bitcast-16bit-1.invalid.comp (100%) rename third_party/spirv-cross/{shaders => shaders-no-opt}/comp/bitcast-16bit-2.invalid.comp (100%) create mode 100644 third_party/spirv-cross/shaders-no-opt/comp/illegal-struct-name.asm.comp rename third_party/spirv-cross/{shaders => shaders-no-opt}/comp/inout-struct.invalid.comp (100%) rename third_party/spirv-cross/{shaders/amd => shaders-no-opt/comp}/shader_ballot_nonuniform_invocations.invalid.comp (100%) rename third_party/spirv-cross/{shaders/vulkan => shaders-no-opt}/comp/struct-packing-scalar.nocompat.invalid.vk.comp (100%) rename third_party/spirv-cross/{shaders/vulkan => shaders-no-opt}/comp/subgroups.nocompat.invalid.vk.comp (100%) rename third_party/spirv-cross/{shaders => shaders-no-opt}/frag/16bit-constants.invalid.frag (100%) rename third_party/spirv-cross/{shaders/desktop-only => shaders-no-opt}/frag/fp16.invalid.desktop.frag (100%) rename third_party/spirv-cross/{shaders/amd => shaders-no-opt/frag}/fragmentMaskFetch_subpassInput.vk.nocompat.invalid.frag (100%) rename third_party/spirv-cross/{shaders/amd => shaders-no-opt/frag}/fs.invalid.frag (100%) rename third_party/spirv-cross/{shaders/flatten => shaders-no-opt/frag}/multi-dimensional.desktop.invalid.flatten_dim.frag (100%) create mode 100644 third_party/spirv-cross/shaders-no-opt/frag/pixel-interlock-simple-callstack.frag rename third_party/spirv-cross/{shaders/vulkan => shaders-no-opt}/frag/scalar-block-layout-ubo-std430.vk.nocompat.invalid.frag (100%) create mode 100644 third_party/spirv-cross/shaders-reflection/comp/workgroup-size-spec-constant.comp create mode 100644 third_party/spirv-cross/shaders-reflection/vert/array-size-reflection.vert create mode 100644 third_party/spirv-cross/shaders-reflection/vert/stride-reflection.vert create mode 100644 third_party/spirv-cross/shaders-ue4-no-opt/asm/frag/accesschain-invalid-expression.asm.invalid.frag create mode 100644 third_party/spirv-cross/shaders-ue4-no-opt/asm/frag/array-copy-error.asm.invalid.frag create mode 100644 third_party/spirv-cross/shaders-ue4-no-opt/asm/frag/phi-variable-declaration.asm.invalid.frag create mode 100644 third_party/spirv-cross/shaders-ue4-no-opt/asm/vert/loop-accesschain-writethrough.asm.invalid.vert create mode 100644 third_party/spirv-cross/shaders-ue4/asm/frag/depth-compare.asm.frag create mode 100644 third_party/spirv-cross/shaders-ue4/asm/frag/global-constant-arrays.asm.frag create mode 100644 third_party/spirv-cross/shaders-ue4/asm/frag/padded-float-array-member-defef.asm.frag create mode 100644 third_party/spirv-cross/shaders-ue4/asm/frag/sample-mask-not-array.asm.frag create mode 100644 third_party/spirv-cross/shaders-ue4/asm/frag/subpass-input.ios.framebuffer-fetch.asm.frag create mode 100644 third_party/spirv-cross/shaders-ue4/asm/frag/texture-atomics.asm.frag create mode 100644 third_party/spirv-cross/shaders-ue4/asm/frag/texture-atomics.asm.graphics-robust-access.frag create mode 100644 third_party/spirv-cross/shaders-ue4/asm/tesc/hs-incorrect-base-type.asm.tesc create mode 100644 third_party/spirv-cross/shaders-ue4/asm/tesc/hs-input-array-access.asm.tesc create mode 100644 third_party/spirv-cross/shaders-ue4/asm/tesc/hs-texcoord-array.asm.tesc create mode 100644 third_party/spirv-cross/shaders-ue4/asm/tesc/tess-factor-must-be-threadgroup.asm.tesc create mode 100644 third_party/spirv-cross/shaders-ue4/asm/tese/ds-double-gl-in-deref.asm.tese create mode 100644 third_party/spirv-cross/shaders-ue4/asm/tese/ds-patch-input-fixes.asm.tese create mode 100644 third_party/spirv-cross/shaders-ue4/asm/tese/ds-patch-inputs.asm.tese create mode 100644 third_party/spirv-cross/shaders-ue4/asm/tese/ds-texcoord-array.asm.tese create mode 100644 third_party/spirv-cross/shaders-ue4/asm/vert/array-missing-copies.asm.vert create mode 100644 third_party/spirv-cross/shaders-ue4/asm/vert/texture-buffer.asm.vert create mode 100644 third_party/spirv-cross/shaders/asm/comp/bitcast_icmp.asm.comp create mode 100644 third_party/spirv-cross/shaders/asm/frag/image-fetch-no-sampler.no-samplerless.asm.vk.frag create mode 100644 third_party/spirv-cross/shaders/asm/frag/image-query-no-sampler.no-samplerless.vk.asm.frag create mode 100644 third_party/spirv-cross/shaders/desktop-only/frag/image-size.frag create mode 100644 third_party/spirv-cross/shaders/desktop-only/frag/image-size.no-qualifier-deduction.frag create mode 100644 third_party/spirv-cross/shaders/frag/pixel-interlock-ordered.frag create mode 100644 third_party/spirv-cross/shaders/frag/pixel-interlock-unordered.frag create mode 100644 third_party/spirv-cross/shaders/frag/post-depth-coverage-es.frag create mode 100644 third_party/spirv-cross/shaders/frag/sample-interlock-ordered.frag create mode 100644 third_party/spirv-cross/shaders/frag/sample-interlock-unordered.frag create mode 100644 third_party/spirv-cross/shaders/frag/struct-type-unrelated-alias.frag create mode 100644 third_party/spirv-cross/shaders/geom/geometry-passthrough.geom create mode 100644 third_party/spirv-cross/shaders/geom/multi-stream.geom create mode 100644 third_party/spirv-cross/shaders/tese/load-array-of-array.tese create mode 100644 third_party/spirv-cross/shaders/tese/patch-input-array.tese create mode 100644 third_party/spirv-cross/shaders/vert/transform-feedback-decorations.vert create mode 100644 third_party/spirv-cross/tests-other/hlsl_resource_binding.spv create mode 100644 third_party/spirv-cross/tests-other/hlsl_resource_bindings.cpp create mode 100644 third_party/spirv-cross/tests-other/msl_ycbcr_conversion_test.cpp create mode 100644 third_party/spirv-cross/tests-other/msl_ycbcr_conversion_test.spv create mode 100644 third_party/spirv-cross/tests-other/msl_ycbcr_conversion_test_2.spv create mode 100644 third_party/spirv-cross/tests-other/typed_id_test.cpp create mode 100644 third_party/spirv-tools/BUILD.bazel create mode 100644 third_party/spirv-tools/CODE_OF_CONDUCT.md create mode 100644 third_party/spirv-tools/WORKSPACE create mode 100644 third_party/spirv-tools/build_defs.bzl delete mode 100644 third_party/spirv-tools/cmake/setup_build.cmake create mode 100644 third_party/spirv-tools/docs/downloads.md rename third_party/spirv-tools/{ => docs}/projects.md (100%) rename third_party/spirv-tools/{ => docs}/syntax.md (100%) mode change 100755 => 100644 third_party/spirv-tools/external/spirv-headers/include/spirv/1.2/spirv.py mode change 100755 => 100644 third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/spirv.core.grammar.json mode change 100755 => 100644 third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/spirv.py mode change 100755 => 100644 third_party/spirv-tools/external/spirv-headers/tools/buildHeaders/CMakeLists.txt mode change 100755 => 100644 third_party/spirv-tools/external/spirv-headers/tools/buildHeaders/header.cpp mode change 100755 => 100644 third_party/spirv-tools/external/spirv-headers/tools/buildHeaders/header.h mode change 100755 => 100644 third_party/spirv-tools/external/spirv-headers/tools/buildHeaders/jsonToSpirv.cpp mode change 100755 => 100644 third_party/spirv-tools/external/spirv-headers/tools/buildHeaders/jsonToSpirv.h mode change 100755 => 100644 third_party/spirv-tools/external/spirv-headers/tools/buildHeaders/main.cpp create mode 100644 third_party/spirv-tools/filament-specific-changes.patch create mode 100644 third_party/spirv-tools/include/spirv-tools/instrument.hpp rename third_party/spirv-tools/{test/comp/CMakeLists.txt => kokoro/linux-clang-asan/build.sh} (51%) create mode 100644 third_party/spirv-tools/kokoro/linux-clang-asan/continuous.cfg create mode 100644 third_party/spirv-tools/kokoro/linux-clang-asan/presubmit.cfg create mode 100644 third_party/spirv-tools/kokoro/linux-clang-release-bazel/build.sh create mode 100644 third_party/spirv-tools/kokoro/linux-clang-release-bazel/continuous.cfg create mode 100644 third_party/spirv-tools/kokoro/linux-clang-release-bazel/presubmit.cfg create mode 100644 third_party/spirv-tools/kokoro/macos-clang-release-bazel/build.sh create mode 100644 third_party/spirv-tools/kokoro/macos-clang-release-bazel/continuous.cfg create mode 100644 third_party/spirv-tools/kokoro/macos-clang-release-bazel/presubmit.cfg create mode 100644 third_party/spirv-tools/kokoro/shaderc-smoketest/build.sh create mode 100644 third_party/spirv-tools/kokoro/shaderc-smoketest/continuous.cfg create mode 100644 third_party/spirv-tools/kokoro/shaderc-smoketest/presubmit.cfg create mode 100644 third_party/spirv-tools/kokoro/windows-msvc-2015-release-bazel/build.bat create mode 100644 third_party/spirv-tools/kokoro/windows-msvc-2015-release-bazel/continuous.cfg create mode 100644 third_party/spirv-tools/kokoro/windows-msvc-2015-release-bazel/presubmit.cfg delete mode 100644 third_party/spirv-tools/source/comp/CMakeLists.txt delete mode 100644 third_party/spirv-tools/source/comp/bit_stream.cpp delete mode 100644 third_party/spirv-tools/source/comp/bit_stream.h delete mode 100644 third_party/spirv-tools/source/comp/huffman_codec.h delete mode 100644 third_party/spirv-tools/source/comp/markv.cpp delete mode 100644 third_party/spirv-tools/source/comp/markv.h delete mode 100644 third_party/spirv-tools/source/comp/markv_codec.cpp delete mode 100644 third_party/spirv-tools/source/comp/markv_codec.h delete mode 100644 third_party/spirv-tools/source/comp/markv_decoder.cpp delete mode 100644 third_party/spirv-tools/source/comp/markv_decoder.h delete mode 100644 third_party/spirv-tools/source/comp/markv_encoder.cpp delete mode 100644 third_party/spirv-tools/source/comp/markv_encoder.h delete mode 100644 third_party/spirv-tools/source/comp/markv_logger.h delete mode 100644 third_party/spirv-tools/source/comp/markv_model.h delete mode 100644 third_party/spirv-tools/source/comp/move_to_front.cpp delete mode 100644 third_party/spirv-tools/source/comp/move_to_front.h create mode 100644 third_party/spirv-tools/source/extinst.opencl.debuginfo.100.grammar.json create mode 100644 third_party/spirv-tools/source/fuzz/CMakeLists.txt create mode 100644 third_party/spirv-tools/source/fuzz/data_descriptor.cpp create mode 100644 third_party/spirv-tools/source/fuzz/data_descriptor.h create mode 100644 third_party/spirv-tools/source/fuzz/equivalence_relation.h create mode 100644 third_party/spirv-tools/source/fuzz/fact_manager.cpp create mode 100644 third_party/spirv-tools/source/fuzz/fact_manager.h create mode 100644 third_party/spirv-tools/source/fuzz/force_render_red.cpp create mode 100644 third_party/spirv-tools/source/fuzz/force_render_red.h create mode 100644 third_party/spirv-tools/source/fuzz/fuzzer.cpp create mode 100644 third_party/spirv-tools/source/fuzz/fuzzer.h create mode 100644 third_party/spirv-tools/source/fuzz/fuzzer_context.cpp create mode 100644 third_party/spirv-tools/source/fuzz/fuzzer_context.h create mode 100644 third_party/spirv-tools/source/fuzz/fuzzer_pass.cpp create mode 100644 third_party/spirv-tools/source/fuzz/fuzzer_pass.h create mode 100644 third_party/spirv-tools/source/fuzz/fuzzer_pass_add_composite_types.cpp create mode 100644 third_party/spirv-tools/source/fuzz/fuzzer_pass_add_composite_types.h create mode 100644 third_party/spirv-tools/source/fuzz/fuzzer_pass_add_dead_blocks.cpp create mode 100644 third_party/spirv-tools/source/fuzz/fuzzer_pass_add_dead_blocks.h create mode 100644 third_party/spirv-tools/source/fuzz/fuzzer_pass_add_dead_breaks.cpp create mode 100644 third_party/spirv-tools/source/fuzz/fuzzer_pass_add_dead_breaks.h create mode 100644 third_party/spirv-tools/source/fuzz/fuzzer_pass_add_dead_continues.cpp create mode 100644 third_party/spirv-tools/source/fuzz/fuzzer_pass_add_dead_continues.h create mode 100644 third_party/spirv-tools/source/fuzz/fuzzer_pass_add_no_contraction_decorations.cpp create mode 100644 third_party/spirv-tools/source/fuzz/fuzzer_pass_add_no_contraction_decorations.h create mode 100644 third_party/spirv-tools/source/fuzz/fuzzer_pass_add_useful_constructs.cpp create mode 100644 third_party/spirv-tools/source/fuzz/fuzzer_pass_add_useful_constructs.h create mode 100644 third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_function_controls.cpp create mode 100644 third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_function_controls.h create mode 100644 third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_loop_controls.cpp create mode 100644 third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_loop_controls.h create mode 100644 third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_memory_operands_masks.cpp create mode 100644 third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_memory_operands_masks.h create mode 100644 third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_selection_controls.cpp create mode 100644 third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_selection_controls.h create mode 100644 third_party/spirv-tools/source/fuzz/fuzzer_pass_apply_id_synonyms.cpp create mode 100644 third_party/spirv-tools/source/fuzz/fuzzer_pass_apply_id_synonyms.h create mode 100644 third_party/spirv-tools/source/fuzz/fuzzer_pass_construct_composites.cpp create mode 100644 third_party/spirv-tools/source/fuzz/fuzzer_pass_construct_composites.h create mode 100644 third_party/spirv-tools/source/fuzz/fuzzer_pass_copy_objects.cpp create mode 100644 third_party/spirv-tools/source/fuzz/fuzzer_pass_copy_objects.h create mode 100644 third_party/spirv-tools/source/fuzz/fuzzer_pass_donate_modules.cpp create mode 100644 third_party/spirv-tools/source/fuzz/fuzzer_pass_donate_modules.h create mode 100644 third_party/spirv-tools/source/fuzz/fuzzer_pass_merge_blocks.cpp create mode 100644 third_party/spirv-tools/source/fuzz/fuzzer_pass_merge_blocks.h create mode 100644 third_party/spirv-tools/source/fuzz/fuzzer_pass_obfuscate_constants.cpp create mode 100644 third_party/spirv-tools/source/fuzz/fuzzer_pass_obfuscate_constants.h create mode 100644 third_party/spirv-tools/source/fuzz/fuzzer_pass_outline_functions.cpp create mode 100644 third_party/spirv-tools/source/fuzz/fuzzer_pass_outline_functions.h create mode 100644 third_party/spirv-tools/source/fuzz/fuzzer_pass_permute_blocks.cpp create mode 100644 third_party/spirv-tools/source/fuzz/fuzzer_pass_permute_blocks.h create mode 100644 third_party/spirv-tools/source/fuzz/fuzzer_pass_split_blocks.cpp create mode 100644 third_party/spirv-tools/source/fuzz/fuzzer_pass_split_blocks.h create mode 100644 third_party/spirv-tools/source/fuzz/fuzzer_util.cpp create mode 100644 third_party/spirv-tools/source/fuzz/fuzzer_util.h create mode 100644 third_party/spirv-tools/source/fuzz/id_use_descriptor.cpp create mode 100644 third_party/spirv-tools/source/fuzz/id_use_descriptor.h create mode 100644 third_party/spirv-tools/source/fuzz/instruction_descriptor.cpp create mode 100644 third_party/spirv-tools/source/fuzz/instruction_descriptor.h create mode 100644 third_party/spirv-tools/source/fuzz/instruction_message.cpp create mode 100644 third_party/spirv-tools/source/fuzz/instruction_message.h create mode 100644 third_party/spirv-tools/source/fuzz/protobufs/spirvfuzz_protobufs.h create mode 100644 third_party/spirv-tools/source/fuzz/protobufs/spvtoolsfuzz.proto create mode 100644 third_party/spirv-tools/source/fuzz/pseudo_random_generator.cpp create mode 100644 third_party/spirv-tools/source/fuzz/pseudo_random_generator.h create mode 100644 third_party/spirv-tools/source/fuzz/random_generator.cpp create mode 100644 third_party/spirv-tools/source/fuzz/random_generator.h create mode 100644 third_party/spirv-tools/source/fuzz/replayer.cpp create mode 100644 third_party/spirv-tools/source/fuzz/replayer.h create mode 100644 third_party/spirv-tools/source/fuzz/shrinker.cpp create mode 100644 third_party/spirv-tools/source/fuzz/shrinker.h create mode 100644 third_party/spirv-tools/source/fuzz/transformation.cpp create mode 100644 third_party/spirv-tools/source/fuzz/transformation.h create mode 100644 third_party/spirv-tools/source/fuzz/transformation_add_constant_boolean.cpp create mode 100644 third_party/spirv-tools/source/fuzz/transformation_add_constant_boolean.h create mode 100644 third_party/spirv-tools/source/fuzz/transformation_add_constant_composite.cpp create mode 100644 third_party/spirv-tools/source/fuzz/transformation_add_constant_composite.h create mode 100644 third_party/spirv-tools/source/fuzz/transformation_add_constant_scalar.cpp create mode 100644 third_party/spirv-tools/source/fuzz/transformation_add_constant_scalar.h create mode 100644 third_party/spirv-tools/source/fuzz/transformation_add_dead_block.cpp create mode 100644 third_party/spirv-tools/source/fuzz/transformation_add_dead_block.h create mode 100644 third_party/spirv-tools/source/fuzz/transformation_add_dead_break.cpp create mode 100644 third_party/spirv-tools/source/fuzz/transformation_add_dead_break.h create mode 100644 third_party/spirv-tools/source/fuzz/transformation_add_dead_continue.cpp create mode 100644 third_party/spirv-tools/source/fuzz/transformation_add_dead_continue.h create mode 100644 third_party/spirv-tools/source/fuzz/transformation_add_function.cpp create mode 100644 third_party/spirv-tools/source/fuzz/transformation_add_function.h create mode 100644 third_party/spirv-tools/source/fuzz/transformation_add_global_undef.cpp create mode 100644 third_party/spirv-tools/source/fuzz/transformation_add_global_undef.h create mode 100644 third_party/spirv-tools/source/fuzz/transformation_add_global_variable.cpp create mode 100644 third_party/spirv-tools/source/fuzz/transformation_add_global_variable.h create mode 100644 third_party/spirv-tools/source/fuzz/transformation_add_no_contraction_decoration.cpp create mode 100644 third_party/spirv-tools/source/fuzz/transformation_add_no_contraction_decoration.h create mode 100644 third_party/spirv-tools/source/fuzz/transformation_add_type_array.cpp create mode 100644 third_party/spirv-tools/source/fuzz/transformation_add_type_array.h create mode 100644 third_party/spirv-tools/source/fuzz/transformation_add_type_boolean.cpp create mode 100644 third_party/spirv-tools/source/fuzz/transformation_add_type_boolean.h create mode 100644 third_party/spirv-tools/source/fuzz/transformation_add_type_float.cpp create mode 100644 third_party/spirv-tools/source/fuzz/transformation_add_type_float.h create mode 100644 third_party/spirv-tools/source/fuzz/transformation_add_type_function.cpp create mode 100644 third_party/spirv-tools/source/fuzz/transformation_add_type_function.h create mode 100644 third_party/spirv-tools/source/fuzz/transformation_add_type_int.cpp create mode 100644 third_party/spirv-tools/source/fuzz/transformation_add_type_int.h create mode 100644 third_party/spirv-tools/source/fuzz/transformation_add_type_matrix.cpp create mode 100644 third_party/spirv-tools/source/fuzz/transformation_add_type_matrix.h create mode 100644 third_party/spirv-tools/source/fuzz/transformation_add_type_pointer.cpp create mode 100644 third_party/spirv-tools/source/fuzz/transformation_add_type_pointer.h create mode 100644 third_party/spirv-tools/source/fuzz/transformation_add_type_struct.cpp create mode 100644 third_party/spirv-tools/source/fuzz/transformation_add_type_struct.h create mode 100644 third_party/spirv-tools/source/fuzz/transformation_add_type_vector.cpp create mode 100644 third_party/spirv-tools/source/fuzz/transformation_add_type_vector.h create mode 100644 third_party/spirv-tools/source/fuzz/transformation_composite_construct.cpp create mode 100644 third_party/spirv-tools/source/fuzz/transformation_composite_construct.h create mode 100644 third_party/spirv-tools/source/fuzz/transformation_composite_extract.cpp create mode 100644 third_party/spirv-tools/source/fuzz/transformation_composite_extract.h create mode 100644 third_party/spirv-tools/source/fuzz/transformation_copy_object.cpp create mode 100644 third_party/spirv-tools/source/fuzz/transformation_copy_object.h create mode 100644 third_party/spirv-tools/source/fuzz/transformation_merge_blocks.cpp create mode 100644 third_party/spirv-tools/source/fuzz/transformation_merge_blocks.h create mode 100644 third_party/spirv-tools/source/fuzz/transformation_move_block_down.cpp create mode 100644 third_party/spirv-tools/source/fuzz/transformation_move_block_down.h create mode 100644 third_party/spirv-tools/source/fuzz/transformation_outline_function.cpp create mode 100644 third_party/spirv-tools/source/fuzz/transformation_outline_function.h create mode 100644 third_party/spirv-tools/source/fuzz/transformation_replace_boolean_constant_with_constant_binary.cpp create mode 100644 third_party/spirv-tools/source/fuzz/transformation_replace_boolean_constant_with_constant_binary.h create mode 100644 third_party/spirv-tools/source/fuzz/transformation_replace_constant_with_uniform.cpp create mode 100644 third_party/spirv-tools/source/fuzz/transformation_replace_constant_with_uniform.h create mode 100644 third_party/spirv-tools/source/fuzz/transformation_replace_id_with_synonym.cpp create mode 100644 third_party/spirv-tools/source/fuzz/transformation_replace_id_with_synonym.h create mode 100644 third_party/spirv-tools/source/fuzz/transformation_set_function_control.cpp create mode 100644 third_party/spirv-tools/source/fuzz/transformation_set_function_control.h create mode 100644 third_party/spirv-tools/source/fuzz/transformation_set_loop_control.cpp create mode 100644 third_party/spirv-tools/source/fuzz/transformation_set_loop_control.h create mode 100644 third_party/spirv-tools/source/fuzz/transformation_set_memory_operands_mask.cpp create mode 100644 third_party/spirv-tools/source/fuzz/transformation_set_memory_operands_mask.h create mode 100644 third_party/spirv-tools/source/fuzz/transformation_set_selection_control.cpp create mode 100644 third_party/spirv-tools/source/fuzz/transformation_set_selection_control.h create mode 100644 third_party/spirv-tools/source/fuzz/transformation_split_block.cpp create mode 100644 third_party/spirv-tools/source/fuzz/transformation_split_block.h create mode 100644 third_party/spirv-tools/source/fuzz/transformation_vector_shuffle.cpp create mode 100644 third_party/spirv-tools/source/fuzz/transformation_vector_shuffle.h create mode 100644 third_party/spirv-tools/source/fuzz/uniform_buffer_element_descriptor.cpp create mode 100644 third_party/spirv-tools/source/fuzz/uniform_buffer_element_descriptor.h delete mode 100644 third_party/spirv-tools/source/id_descriptor.cpp delete mode 100644 third_party/spirv-tools/source/id_descriptor.h create mode 100644 third_party/spirv-tools/source/opt/amd_ext_to_khr.cpp create mode 100644 third_party/spirv-tools/source/opt/amd_ext_to_khr.h create mode 100644 third_party/spirv-tools/source/opt/block_merge_util.cpp create mode 100644 third_party/spirv-tools/source/opt/block_merge_util.h create mode 100644 third_party/spirv-tools/source/opt/code_sink.cpp create mode 100644 third_party/spirv-tools/source/opt/code_sink.h delete mode 100644 third_party/spirv-tools/source/opt/common_uniform_elim_pass.cpp delete mode 100644 third_party/spirv-tools/source/opt/common_uniform_elim_pass.h create mode 100644 third_party/spirv-tools/source/opt/convert_to_half_pass.cpp create mode 100644 third_party/spirv-tools/source/opt/convert_to_half_pass.h create mode 100644 third_party/spirv-tools/source/opt/decompose_initialized_variables_pass.cpp create mode 100644 third_party/spirv-tools/source/opt/decompose_initialized_variables_pass.h create mode 100644 third_party/spirv-tools/source/opt/desc_sroa.cpp create mode 100644 third_party/spirv-tools/source/opt/desc_sroa.h create mode 100644 third_party/spirv-tools/source/opt/eliminate_dead_functions_util.cpp create mode 100644 third_party/spirv-tools/source/opt/eliminate_dead_functions_util.h create mode 100644 third_party/spirv-tools/source/opt/eliminate_dead_members_pass.cpp create mode 100644 third_party/spirv-tools/source/opt/eliminate_dead_members_pass.h create mode 100644 third_party/spirv-tools/source/opt/fix_storage_class.cpp create mode 100644 third_party/spirv-tools/source/opt/fix_storage_class.h create mode 100644 third_party/spirv-tools/source/opt/generate_webgpu_initializers_pass.cpp create mode 100644 third_party/spirv-tools/source/opt/generate_webgpu_initializers_pass.h create mode 100644 third_party/spirv-tools/source/opt/graphics_robust_access_pass.cpp create mode 100644 third_party/spirv-tools/source/opt/graphics_robust_access_pass.h create mode 100644 third_party/spirv-tools/source/opt/inst_bindless_check_pass.cpp create mode 100644 third_party/spirv-tools/source/opt/inst_bindless_check_pass.h create mode 100644 third_party/spirv-tools/source/opt/inst_buff_addr_check_pass.cpp create mode 100644 third_party/spirv-tools/source/opt/inst_buff_addr_check_pass.h create mode 100644 third_party/spirv-tools/source/opt/instrument_pass.cpp create mode 100644 third_party/spirv-tools/source/opt/instrument_pass.h create mode 100644 third_party/spirv-tools/source/opt/legalize_vector_shuffle_pass.cpp create mode 100644 third_party/spirv-tools/source/opt/legalize_vector_shuffle_pass.h delete mode 100644 third_party/spirv-tools/source/opt/local_ssa_elim_pass.cpp delete mode 100644 third_party/spirv-tools/source/opt/local_ssa_elim_pass.h create mode 100644 third_party/spirv-tools/source/opt/pch_source_opt.cpp create mode 100644 third_party/spirv-tools/source/opt/pch_source_opt.h create mode 100644 third_party/spirv-tools/source/opt/process_lines_pass.cpp create mode 100644 third_party/spirv-tools/source/opt/process_lines_pass.h create mode 100644 third_party/spirv-tools/source/opt/relax_float_ops_pass.cpp create mode 100644 third_party/spirv-tools/source/opt/relax_float_ops_pass.h create mode 100644 third_party/spirv-tools/source/opt/split_invalid_unreachable_pass.cpp create mode 100644 third_party/spirv-tools/source/opt/split_invalid_unreachable_pass.h create mode 100644 third_party/spirv-tools/source/opt/strip_atomic_counter_memory_pass.cpp create mode 100644 third_party/spirv-tools/source/opt/strip_atomic_counter_memory_pass.h create mode 100644 third_party/spirv-tools/source/opt/struct_cfg_analysis.cpp create mode 100644 third_party/spirv-tools/source/opt/struct_cfg_analysis.h create mode 100644 third_party/spirv-tools/source/opt/upgrade_memory_model.cpp create mode 100644 third_party/spirv-tools/source/opt/upgrade_memory_model.h create mode 100644 third_party/spirv-tools/source/opt/wrap_opkill.cpp create mode 100644 third_party/spirv-tools/source/opt/wrap_opkill.h create mode 100644 third_party/spirv-tools/source/pch_source.cpp create mode 100644 third_party/spirv-tools/source/pch_source.h create mode 100644 third_party/spirv-tools/source/reduce/CMakeLists.txt create mode 100644 third_party/spirv-tools/source/reduce/change_operand_reduction_opportunity.cpp create mode 100644 third_party/spirv-tools/source/reduce/change_operand_reduction_opportunity.h create mode 100644 third_party/spirv-tools/source/reduce/change_operand_to_undef_reduction_opportunity.cpp create mode 100644 third_party/spirv-tools/source/reduce/change_operand_to_undef_reduction_opportunity.h create mode 100644 third_party/spirv-tools/source/reduce/conditional_branch_to_simple_conditional_branch_opportunity_finder.cpp create mode 100644 third_party/spirv-tools/source/reduce/conditional_branch_to_simple_conditional_branch_opportunity_finder.h create mode 100644 third_party/spirv-tools/source/reduce/conditional_branch_to_simple_conditional_branch_reduction_opportunity.cpp create mode 100644 third_party/spirv-tools/source/reduce/conditional_branch_to_simple_conditional_branch_reduction_opportunity.h create mode 100644 third_party/spirv-tools/source/reduce/merge_blocks_reduction_opportunity.cpp create mode 100644 third_party/spirv-tools/source/reduce/merge_blocks_reduction_opportunity.h create mode 100644 third_party/spirv-tools/source/reduce/merge_blocks_reduction_opportunity_finder.cpp create mode 100644 third_party/spirv-tools/source/reduce/merge_blocks_reduction_opportunity_finder.h create mode 100644 third_party/spirv-tools/source/reduce/operand_to_const_reduction_opportunity_finder.cpp create mode 100644 third_party/spirv-tools/source/reduce/operand_to_const_reduction_opportunity_finder.h create mode 100644 third_party/spirv-tools/source/reduce/operand_to_dominating_id_reduction_opportunity_finder.cpp create mode 100644 third_party/spirv-tools/source/reduce/operand_to_dominating_id_reduction_opportunity_finder.h create mode 100644 third_party/spirv-tools/source/reduce/operand_to_undef_reduction_opportunity_finder.cpp create mode 100644 third_party/spirv-tools/source/reduce/operand_to_undef_reduction_opportunity_finder.h create mode 100644 third_party/spirv-tools/source/reduce/pch_source_reduce.cpp create mode 100644 third_party/spirv-tools/source/reduce/pch_source_reduce.h create mode 100644 third_party/spirv-tools/source/reduce/reducer.cpp create mode 100644 third_party/spirv-tools/source/reduce/reducer.h create mode 100644 third_party/spirv-tools/source/reduce/reduction_opportunity.cpp create mode 100644 third_party/spirv-tools/source/reduce/reduction_opportunity.h create mode 100644 third_party/spirv-tools/source/reduce/reduction_opportunity_finder.h create mode 100644 third_party/spirv-tools/source/reduce/reduction_pass.cpp create mode 100644 third_party/spirv-tools/source/reduce/reduction_pass.h create mode 100644 third_party/spirv-tools/source/reduce/reduction_util.cpp create mode 100644 third_party/spirv-tools/source/reduce/reduction_util.h create mode 100644 third_party/spirv-tools/source/reduce/remove_block_reduction_opportunity.cpp create mode 100644 third_party/spirv-tools/source/reduce/remove_block_reduction_opportunity.h create mode 100644 third_party/spirv-tools/source/reduce/remove_block_reduction_opportunity_finder.cpp create mode 100644 third_party/spirv-tools/source/reduce/remove_block_reduction_opportunity_finder.h create mode 100644 third_party/spirv-tools/source/reduce/remove_function_reduction_opportunity.cpp create mode 100644 third_party/spirv-tools/source/reduce/remove_function_reduction_opportunity.h create mode 100644 third_party/spirv-tools/source/reduce/remove_function_reduction_opportunity_finder.cpp create mode 100644 third_party/spirv-tools/source/reduce/remove_function_reduction_opportunity_finder.h rename third_party/spirv-tools/{tools/comp/markv_model_factory.h => source/reduce/remove_instruction_reduction_opportunity.cpp} (57%) create mode 100644 third_party/spirv-tools/source/reduce/remove_instruction_reduction_opportunity.h create mode 100644 third_party/spirv-tools/source/reduce/remove_selection_reduction_opportunity.cpp create mode 100644 third_party/spirv-tools/source/reduce/remove_selection_reduction_opportunity.h create mode 100644 third_party/spirv-tools/source/reduce/remove_selection_reduction_opportunity_finder.cpp create mode 100644 third_party/spirv-tools/source/reduce/remove_selection_reduction_opportunity_finder.h create mode 100644 third_party/spirv-tools/source/reduce/remove_unreferenced_instruction_reduction_opportunity_finder.cpp create mode 100644 third_party/spirv-tools/source/reduce/remove_unreferenced_instruction_reduction_opportunity_finder.h create mode 100644 third_party/spirv-tools/source/reduce/simple_conditional_branch_to_branch_opportunity_finder.cpp create mode 100644 third_party/spirv-tools/source/reduce/simple_conditional_branch_to_branch_opportunity_finder.h create mode 100644 third_party/spirv-tools/source/reduce/simple_conditional_branch_to_branch_reduction_opportunity.cpp create mode 100644 third_party/spirv-tools/source/reduce/simple_conditional_branch_to_branch_reduction_opportunity.h create mode 100644 third_party/spirv-tools/source/reduce/structured_loop_to_selection_reduction_opportunity.cpp create mode 100644 third_party/spirv-tools/source/reduce/structured_loop_to_selection_reduction_opportunity.h create mode 100644 third_party/spirv-tools/source/reduce/structured_loop_to_selection_reduction_opportunity_finder.cpp create mode 100644 third_party/spirv-tools/source/reduce/structured_loop_to_selection_reduction_opportunity_finder.h create mode 100644 third_party/spirv-tools/source/spirv_fuzzer_options.cpp create mode 100644 third_party/spirv-tools/source/spirv_fuzzer_options.h create mode 100644 third_party/spirv-tools/source/spirv_optimizer_options.cpp create mode 100644 third_party/spirv-tools/source/spirv_optimizer_options.h create mode 100644 third_party/spirv-tools/source/spirv_reducer_options.cpp create mode 100644 third_party/spirv-tools/source/spirv_reducer_options.h delete mode 100644 third_party/spirv-tools/source/val/validate_datarules.cpp rename third_party/spirv-tools/source/val/{validate_ext_inst.cpp => validate_extensions.cpp} (96%) create mode 100644 third_party/spirv-tools/source/val/validate_memory_semantics.cpp create mode 100644 third_party/spirv-tools/source/val/validate_memory_semantics.h create mode 100644 third_party/spirv-tools/source/val/validate_misc.cpp create mode 100644 third_party/spirv-tools/source/val/validate_scopes.cpp create mode 100644 third_party/spirv-tools/source/val/validate_scopes.h create mode 100644 third_party/spirv-tools/source/val/validate_small_type_uses.cpp delete mode 100644 third_party/spirv-tools/test/bit_stream.cpp delete mode 100644 third_party/spirv-tools/test/comp/markv_codec_test.cpp create mode 100644 third_party/spirv-tools/test/ext_inst.cldebug100_test.cpp create mode 100644 third_party/spirv-tools/test/ext_inst.non_semantic_test.cpp create mode 100644 third_party/spirv-tools/test/fuzz/CMakeLists.txt create mode 100644 third_party/spirv-tools/test/fuzz/data_synonym_transformation_test.cpp create mode 100644 third_party/spirv-tools/test/fuzz/equivalence_relation_test.cpp create mode 100644 third_party/spirv-tools/test/fuzz/fact_manager_test.cpp create mode 100644 third_party/spirv-tools/test/fuzz/fuzz_test_util.cpp create mode 100644 third_party/spirv-tools/test/fuzz/fuzz_test_util.h create mode 100644 third_party/spirv-tools/test/fuzz/fuzzer_pass_add_useful_constructs_test.cpp create mode 100644 third_party/spirv-tools/test/fuzz/fuzzer_pass_donate_modules_test.cpp create mode 100644 third_party/spirv-tools/test/fuzz/fuzzer_replayer_test.cpp create mode 100644 third_party/spirv-tools/test/fuzz/fuzzer_shrinker_test.cpp create mode 100644 third_party/spirv-tools/test/fuzz/instruction_descriptor_test.cpp create mode 100644 third_party/spirv-tools/test/fuzz/transformation_add_constant_boolean_test.cpp create mode 100644 third_party/spirv-tools/test/fuzz/transformation_add_constant_composite_test.cpp create mode 100644 third_party/spirv-tools/test/fuzz/transformation_add_constant_scalar_test.cpp create mode 100644 third_party/spirv-tools/test/fuzz/transformation_add_dead_block_test.cpp create mode 100644 third_party/spirv-tools/test/fuzz/transformation_add_dead_break_test.cpp create mode 100644 third_party/spirv-tools/test/fuzz/transformation_add_dead_continue_test.cpp create mode 100644 third_party/spirv-tools/test/fuzz/transformation_add_function_test.cpp create mode 100644 third_party/spirv-tools/test/fuzz/transformation_add_global_undef_test.cpp create mode 100644 third_party/spirv-tools/test/fuzz/transformation_add_global_variable_test.cpp create mode 100644 third_party/spirv-tools/test/fuzz/transformation_add_no_contraction_decoration_test.cpp create mode 100644 third_party/spirv-tools/test/fuzz/transformation_add_type_array_test.cpp create mode 100644 third_party/spirv-tools/test/fuzz/transformation_add_type_boolean_test.cpp create mode 100644 third_party/spirv-tools/test/fuzz/transformation_add_type_float_test.cpp create mode 100644 third_party/spirv-tools/test/fuzz/transformation_add_type_function_test.cpp create mode 100644 third_party/spirv-tools/test/fuzz/transformation_add_type_int_test.cpp create mode 100644 third_party/spirv-tools/test/fuzz/transformation_add_type_matrix_test.cpp create mode 100644 third_party/spirv-tools/test/fuzz/transformation_add_type_pointer_test.cpp create mode 100644 third_party/spirv-tools/test/fuzz/transformation_add_type_struct_test.cpp create mode 100644 third_party/spirv-tools/test/fuzz/transformation_add_type_vector_test.cpp create mode 100644 third_party/spirv-tools/test/fuzz/transformation_composite_construct_test.cpp create mode 100644 third_party/spirv-tools/test/fuzz/transformation_composite_extract_test.cpp create mode 100644 third_party/spirv-tools/test/fuzz/transformation_copy_object_test.cpp create mode 100644 third_party/spirv-tools/test/fuzz/transformation_merge_blocks_test.cpp create mode 100644 third_party/spirv-tools/test/fuzz/transformation_move_block_down_test.cpp create mode 100644 third_party/spirv-tools/test/fuzz/transformation_outline_function_test.cpp create mode 100644 third_party/spirv-tools/test/fuzz/transformation_replace_boolean_constant_with_constant_binary_test.cpp create mode 100644 third_party/spirv-tools/test/fuzz/transformation_replace_constant_with_uniform_test.cpp create mode 100644 third_party/spirv-tools/test/fuzz/transformation_replace_id_with_synonym_test.cpp create mode 100644 third_party/spirv-tools/test/fuzz/transformation_set_function_control_test.cpp create mode 100644 third_party/spirv-tools/test/fuzz/transformation_set_loop_control_test.cpp create mode 100644 third_party/spirv-tools/test/fuzz/transformation_set_memory_operands_mask_test.cpp create mode 100644 third_party/spirv-tools/test/fuzz/transformation_set_selection_control_test.cpp create mode 100644 third_party/spirv-tools/test/fuzz/transformation_split_block_test.cpp create mode 100644 third_party/spirv-tools/test/fuzz/transformation_vector_shuffle_test.cpp create mode 100644 third_party/spirv-tools/test/fuzz/uniform_buffer_element_descriptor_test.cpp create mode 100644 third_party/spirv-tools/test/fuzzers/spvtools_as_fuzzer.cpp create mode 100644 third_party/spirv-tools/test/fuzzers/spvtools_binary_parser_fuzzer.cpp create mode 100644 third_party/spirv-tools/test/fuzzers/spvtools_dis_fuzzer.cpp create mode 100644 third_party/spirv-tools/test/fuzzers/spvtools_opt_vulkantowebgpu_fuzzer.cpp create mode 100644 third_party/spirv-tools/test/fuzzers/spvtools_opt_webgputovulkan_fuzzer.cpp create mode 100644 third_party/spirv-tools/test/fuzzers/spvtools_val_webgpu_fuzzer.cpp delete mode 100644 third_party/spirv-tools/test/huffman_codec.cpp create mode 100644 third_party/spirv-tools/test/link/type_match_test.cpp delete mode 100644 third_party/spirv-tools/test/move_to_front_test.cpp create mode 100644 third_party/spirv-tools/test/opt/amd_ext_to_khr.cpp create mode 100644 third_party/spirv-tools/test/opt/cfg_test.cpp create mode 100644 third_party/spirv-tools/test/opt/code_sink_test.cpp delete mode 100644 third_party/spirv-tools/test/opt/common_uniform_elim_test.cpp create mode 100644 third_party/spirv-tools/test/opt/constants_test.cpp create mode 100644 third_party/spirv-tools/test/opt/convert_relaxed_to_half_test.cpp create mode 100644 third_party/spirv-tools/test/opt/decompose_initialized_variables_test.cpp create mode 100644 third_party/spirv-tools/test/opt/desc_sroa_test.cpp create mode 100644 third_party/spirv-tools/test/opt/dominator_tree/pch_test_opt_dom.cpp create mode 100644 third_party/spirv-tools/test/opt/dominator_tree/pch_test_opt_dom.h create mode 100644 third_party/spirv-tools/test/opt/eliminate_dead_member_test.cpp create mode 100644 third_party/spirv-tools/test/opt/fix_storage_class_test.cpp create mode 100644 third_party/spirv-tools/test/opt/function_test.cpp create mode 100644 third_party/spirv-tools/test/opt/generate_webgpu_initializers_test.cpp create mode 100644 third_party/spirv-tools/test/opt/graphics_robust_access_test.cpp create mode 100644 third_party/spirv-tools/test/opt/inst_bindless_check_test.cpp create mode 100644 third_party/spirv-tools/test/opt/inst_buff_addr_check_test.cpp create mode 100644 third_party/spirv-tools/test/opt/legalize_vector_shuffle_test.cpp create mode 100644 third_party/spirv-tools/test/opt/loop_optimizations/pch_test_opt_loop.cpp create mode 100644 third_party/spirv-tools/test/opt/loop_optimizations/pch_test_opt_loop.h delete mode 100644 third_party/spirv-tools/test/opt/pass_test.cpp create mode 100644 third_party/spirv-tools/test/opt/pch_test_opt.cpp create mode 100644 third_party/spirv-tools/test/opt/pch_test_opt.h create mode 100644 third_party/spirv-tools/test/opt/process_lines_test.cpp create mode 100644 third_party/spirv-tools/test/opt/relax_float_ops_test.cpp create mode 100644 third_party/spirv-tools/test/opt/split_invalid_unreachable_test.cpp create mode 100644 third_party/spirv-tools/test/opt/strip_atomic_counter_memory_test.cpp create mode 100644 third_party/spirv-tools/test/opt/struct_cfg_analysis_test.cpp create mode 100644 third_party/spirv-tools/test/opt/upgrade_memory_model_test.cpp create mode 100644 third_party/spirv-tools/test/opt/wrap_opkill_test.cpp create mode 100644 third_party/spirv-tools/test/pch_test.cpp create mode 100644 third_party/spirv-tools/test/pch_test.h create mode 100644 third_party/spirv-tools/test/reduce/CMakeLists.txt create mode 100644 third_party/spirv-tools/test/reduce/conditional_branch_to_simple_conditional_branch_test.cpp create mode 100644 third_party/spirv-tools/test/reduce/merge_blocks_test.cpp create mode 100644 third_party/spirv-tools/test/reduce/operand_to_constant_test.cpp create mode 100644 third_party/spirv-tools/test/reduce/operand_to_dominating_id_test.cpp create mode 100644 third_party/spirv-tools/test/reduce/operand_to_undef_test.cpp create mode 100644 third_party/spirv-tools/test/reduce/reduce_test_util.cpp create mode 100644 third_party/spirv-tools/test/reduce/reduce_test_util.h create mode 100644 third_party/spirv-tools/test/reduce/reducer_test.cpp create mode 100644 third_party/spirv-tools/test/reduce/remove_block_test.cpp create mode 100644 third_party/spirv-tools/test/reduce/remove_function_test.cpp create mode 100644 third_party/spirv-tools/test/reduce/remove_selection_test.cpp create mode 100644 third_party/spirv-tools/test/reduce/remove_unreferenced_instruction_test.cpp create mode 100644 third_party/spirv-tools/test/reduce/simple_conditional_branch_to_branch_test.cpp create mode 100644 third_party/spirv-tools/test/reduce/structured_loop_to_selection_test.cpp create mode 100644 third_party/spirv-tools/test/reduce/validation_during_reduction_test.cpp delete mode 100644 third_party/spirv-tools/test/stats/CMakeLists.txt delete mode 100644 third_party/spirv-tools/test/stats/stats_aggregate_test.cpp delete mode 100644 third_party/spirv-tools/test/stats/stats_analyzer_test.cpp create mode 100644 third_party/spirv-tools/test/text_to_binary.composite_test.cpp delete mode 100755 third_party/spirv-tools/test/tools/expect_nosetest.py create mode 100644 third_party/spirv-tools/test/tools/expect_unittest.py delete mode 100755 third_party/spirv-tools/test/tools/spirv_test_framework_nosetest.py create mode 100644 third_party/spirv-tools/test/tools/spirv_test_framework_unittest.py create mode 100644 third_party/spirv-tools/test/util/bitutils_test.cpp create mode 100644 third_party/spirv-tools/test/val/pch_test_val.cpp create mode 100644 third_party/spirv-tools/test/val/pch_test_val.h create mode 100644 third_party/spirv-tools/test/val/val_code_generator.cpp create mode 100644 third_party/spirv-tools/test/val/val_code_generator.h create mode 100644 third_party/spirv-tools/test/val/val_constants_test.cpp create mode 100644 third_party/spirv-tools/test/val/val_entry_point.cpp create mode 100644 third_party/spirv-tools/test/val/val_function_test.cpp create mode 100644 third_party/spirv-tools/test/val/val_memory_test.cpp create mode 100644 third_party/spirv-tools/test/val/val_misc_test.cpp create mode 100644 third_party/spirv-tools/test/val/val_modes_test.cpp create mode 100644 third_party/spirv-tools/test/val/val_non_semantic_test.cpp create mode 100644 third_party/spirv-tools/test/val/val_opencl_test.cpp create mode 100644 third_party/spirv-tools/test/val/val_small_type_uses_test.cpp delete mode 100644 third_party/spirv-tools/tools/comp/markv.cpp delete mode 100644 third_party/spirv-tools/tools/comp/markv_model_factory.cpp delete mode 100644 third_party/spirv-tools/tools/comp/markv_model_shader.cpp delete mode 100644 third_party/spirv-tools/tools/comp/markv_model_shader.h delete mode 100644 third_party/spirv-tools/tools/comp/markv_model_shader_default_autogen.inc create mode 100644 third_party/spirv-tools/tools/fuzz/fuzz.cpp create mode 100644 third_party/spirv-tools/tools/reduce/reduce.cpp delete mode 100644 third_party/spirv-tools/tools/stats/spirv_stats.cpp delete mode 100644 third_party/spirv-tools/tools/stats/spirv_stats.h delete mode 100644 third_party/spirv-tools/tools/stats/stats.cpp delete mode 100644 third_party/spirv-tools/tools/stats/stats_analyzer.cpp delete mode 100644 third_party/spirv-tools/tools/stats/stats_analyzer.h create mode 100644 third_party/spirv-tools/tools/sva/.eslintrc.json create mode 100644 third_party/spirv-tools/tools/sva/.gitignore create mode 100644 third_party/spirv-tools/tools/sva/README.md create mode 100755 third_party/spirv-tools/tools/sva/bin/sva.js create mode 100644 third_party/spirv-tools/tools/sva/mocha.opts create mode 100644 third_party/spirv-tools/tools/sva/package.json create mode 100644 third_party/spirv-tools/tools/sva/rollup.config.js create mode 100644 third_party/spirv-tools/tools/sva/src/assembler.js create mode 100644 third_party/spirv-tools/tools/sva/src/assembler_test.js create mode 100644 third_party/spirv-tools/tools/sva/src/ast.js create mode 100644 third_party/spirv-tools/tools/sva/src/lexer.js create mode 100644 third_party/spirv-tools/tools/sva/src/lexer_test.js create mode 100644 third_party/spirv-tools/tools/sva/src/parser.js create mode 100644 third_party/spirv-tools/tools/sva/src/parser_test.js create mode 100644 third_party/spirv-tools/tools/sva/src/spirv.data.js create mode 100644 third_party/spirv-tools/tools/sva/src/sva.js create mode 100644 third_party/spirv-tools/tools/sva/src/token.js create mode 100644 third_party/spirv-tools/tools/sva/tests/empty_main.spv_asm create mode 100644 third_party/spirv-tools/tools/sva/tests/index.html create mode 100644 third_party/spirv-tools/tools/sva/tests/simple.spv_asm create mode 100755 third_party/spirv-tools/tools/sva/tools/process_grammar.rb create mode 100644 third_party/spirv-tools/tools/sva/yarn.lock create mode 100755 third_party/spirv-tools/utils/git-sync-deps create mode 100755 third_party/spirv-tools/utils/roll_deps.sh create mode 100644 third_party/spirv-tools/utils/vscode/.gitignore create mode 100644 third_party/spirv-tools/utils/vscode/README.md create mode 100644 third_party/spirv-tools/utils/vscode/extension.js create mode 100644 third_party/spirv-tools/utils/vscode/install.bat create mode 100755 third_party/spirv-tools/utils/vscode/install.sh create mode 100644 third_party/spirv-tools/utils/vscode/package.json create mode 100644 third_party/spirv-tools/utils/vscode/spirv.json create mode 100644 third_party/spirv-tools/utils/vscode/spirv.json.tmpl create mode 100644 third_party/spirv-tools/utils/vscode/src/grammar/grammar.go create mode 100644 third_party/spirv-tools/utils/vscode/src/langsvr.go create mode 100644 third_party/spirv-tools/utils/vscode/src/lsp/LICENSE create mode 100644 third_party/spirv-tools/utils/vscode/src/lsp/README.md create mode 100644 third_party/spirv-tools/utils/vscode/src/lsp/jsonrpc2/handler.go create mode 100644 third_party/spirv-tools/utils/vscode/src/lsp/jsonrpc2/jsonrpc2.go create mode 100644 third_party/spirv-tools/utils/vscode/src/lsp/jsonrpc2/stream.go create mode 100644 third_party/spirv-tools/utils/vscode/src/lsp/jsonrpc2/wire.go create mode 100644 third_party/spirv-tools/utils/vscode/src/lsp/protocol/context.go create mode 100644 third_party/spirv-tools/utils/vscode/src/lsp/protocol/doc.go create mode 100644 third_party/spirv-tools/utils/vscode/src/lsp/protocol/enums.go create mode 100644 third_party/spirv-tools/utils/vscode/src/lsp/protocol/log.go create mode 100644 third_party/spirv-tools/utils/vscode/src/lsp/protocol/protocol.go create mode 100644 third_party/spirv-tools/utils/vscode/src/lsp/protocol/span.go create mode 100644 third_party/spirv-tools/utils/vscode/src/lsp/protocol/tsclient.go create mode 100644 third_party/spirv-tools/utils/vscode/src/lsp/protocol/tsprotocol.go create mode 100644 third_party/spirv-tools/utils/vscode/src/lsp/protocol/tsserver.go create mode 100644 third_party/spirv-tools/utils/vscode/src/lsp/span/parse.go create mode 100644 third_party/spirv-tools/utils/vscode/src/lsp/span/span.go create mode 100644 third_party/spirv-tools/utils/vscode/src/lsp/span/token.go create mode 100644 third_party/spirv-tools/utils/vscode/src/lsp/span/token111.go create mode 100644 third_party/spirv-tools/utils/vscode/src/lsp/span/token112.go create mode 100644 third_party/spirv-tools/utils/vscode/src/lsp/span/uri.go create mode 100644 third_party/spirv-tools/utils/vscode/src/lsp/span/utf16.go create mode 100644 third_party/spirv-tools/utils/vscode/src/parser/parser.go create mode 100755 third_party/spirv-tools/utils/vscode/src/schema/schema.go create mode 100644 third_party/spirv-tools/utils/vscode/src/schema/schema.go.tmpl create mode 100644 third_party/spirv-tools/utils/vscode/src/tools/gen-grammar.go diff --git a/libs/filamat/src/GLSLPostProcessor.cpp b/libs/filamat/src/GLSLPostProcessor.cpp index 1889b40e46..ec5f5caae4 100644 --- a/libs/filamat/src/GLSLPostProcessor.cpp +++ b/libs/filamat/src/GLSLPostProcessor.cpp @@ -356,6 +356,7 @@ void GLSLPostProcessor::fullOptimization(const TShader& tShader, void GLSLPostProcessor::registerPerformancePasses(Optimizer& optimizer) const { optimizer + .RegisterPass(CreateDeadBranchElimPass()) .RegisterPass(CreateMergeReturnPass()) .RegisterPass(CreateInlineExhaustivePass()) .RegisterPass(CreateAggressiveDCEPass()) @@ -392,6 +393,7 @@ void GLSLPostProcessor::registerPerformancePasses(Optimizer& optimizer) const { void GLSLPostProcessor::registerSizePasses(Optimizer& optimizer) const { optimizer + .RegisterPass(CreateDeadBranchElimPass()) .RegisterPass(CreateMergeReturnPass()) .RegisterPass(CreateInlineExhaustivePass()) .RegisterPass(CreateAggressiveDCEPass()) diff --git a/third_party/spirv-cross/.travis.yml b/third_party/spirv-cross/.travis.yml index 46b92c8fc8..575262531d 100644 --- a/third_party/spirv-cross/.travis.yml +++ b/third_party/spirv-cross/.travis.yml @@ -27,14 +27,14 @@ matrix: - os: windows before_install: - choco install python3 - - export PATH="/c/Python37:/c/Python37/Scripts:$PATH" + - export PATH="/c/Python38:/c/Python38/Scripts:$PATH" env: - GENERATOR="Visual Studio 15 2017" - ARTIFACT=vs2017-32bit - os: windows before_install: - choco install python3 - - export PATH="/c/Python37:/c/Python37/Scripts:$PATH" + - export PATH="/c/Python38:/c/Python38/Scripts:$PATH" env: - GENERATOR="Visual Studio 15 2017 Win64" - ARTIFACT=vs2017-64bit @@ -48,7 +48,7 @@ script: - "./build_glslang_spirv_tools.sh Release" - mkdir build - cd build - - cmake .. -DSPIRV_CROSS_SHARED=ON -DCMAKE_INSTALL_PREFIX=output -DCMAKE_BUILD_TYPE=Release -G "${GENERATOR}" -DPYTHON_EXECUTABLE:FILEPATH="${PYTHON3}" -DSPIRV_CROSS_ENABLE_TESTS=ON + - cmake .. -DSPIRV_CROSS_WERROR=ON -DSPIRV_CROSS_MISC_WARNINGS=ON -DSPIRV_CROSS_SHARED=ON -DCMAKE_INSTALL_PREFIX=output -DCMAKE_BUILD_TYPE=Release -G "${GENERATOR}" -DPYTHON_EXECUTABLE:FILEPATH="${PYTHON3}" -DSPIRV_CROSS_ENABLE_TESTS=ON - cmake --build . --config Release - cmake --build . --config Release --target install - ctest --verbose -C Release diff --git a/third_party/spirv-cross/CMakeLists.txt b/third_party/spirv-cross/CMakeLists.txt index 5cfa74117b..b8d47ea2dc 100644 --- a/third_party/spirv-cross/CMakeLists.txt +++ b/third_party/spirv-cross/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright 2016 Google Inc. +# Copyright 2016-2020 Google Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -14,9 +14,17 @@ cmake_minimum_required(VERSION 2.8) set(CMAKE_CXX_STANDARD 11) + +# Avoid a warning if parent project sets VERSION in project(). +if (${CMAKE_VERSION} VERSION_GREATER "3.0.1") + cmake_policy(SET CMP0048 NEW) +endif() + project(SPIRV-Cross LANGUAGES CXX C) enable_testing() +include(GNUInstallDirs) + option(SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS "Instead of throwing exceptions assert" OFF) option(SPIRV_CROSS_SHARED "Build the C API as a single shared library." OFF) option(SPIRV_CROSS_STATIC "Build the C and C++ API as static libraries." ON) @@ -39,6 +47,13 @@ option(SPIRV_CROSS_SANITIZE_UNDEFINED "Sanitize undefined" OFF) option(SPIRV_CROSS_NAMESPACE_OVERRIDE "" "Override the namespace used in the C++ API.") option(SPIRV_CROSS_FORCE_STL_TYPES "Force use of STL types instead of STL replacements in certain places. Might reduce performance." OFF) +option(SPIRV_CROSS_SKIP_INSTALL "Skips installation targets." OFF) + +option(SPIRV_CROSS_WERROR "Fail build on warnings." OFF) +option(SPIRV_CROSS_MISC_WARNINGS "Misc warnings useful for Travis runs." OFF) + +option(SPIRV_CROSS_FORCE_PIC "Force position-independent code for all targets." OFF) + if(${CMAKE_GENERATOR} MATCHES "Makefile") if(${CMAKE_CURRENT_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_BINARY_DIR}) message(FATAL_ERROR "Build out of tree to avoid overwriting Makefile") @@ -49,7 +64,7 @@ set(spirv-compiler-options "") set(spirv-compiler-defines "") set(spirv-cross-link-flags "") -message(STATUS "Finding Git version for SPIRV-Cross.") +message(STATUS "SPIRV-Cross: Finding Git version for SPIRV-Cross.") set(spirv-cross-build-version "unknown") find_package(Git) if (GIT_FOUND) @@ -60,24 +75,39 @@ if (GIT_FOUND) ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE ) - message(STATUS "Git hash: ${spirv-cross-build-version}") + message(STATUS "SPIRV-Cross: Git hash: ${spirv-cross-build-version}") else() - message(STATUS "Git not found, using unknown build version.") + message(STATUS "SPIRV-Cross: Git not found, using unknown build version.") endif() string(TIMESTAMP spirv-cross-timestamp) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/gitversion.in.h ${CMAKE_CURRENT_BINARY_DIR}/gitversion.h @ONLY) -if(SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS) +if (SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS) set(spirv-compiler-defines ${spirv-compiler-defines} SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS) + if (NOT MSVC) + set(spirv-compiler-options ${spirv-compiler-options} -fno-exceptions) + endif() endif() -if(SPIRV_CROSS_FORCE_STL_TYPES) +if (SPIRV_CROSS_FORCE_STL_TYPES) set(spirv-compiler-defines ${spirv-compiler-defines} SPIRV_CROSS_FORCE_STL_TYPES) endif() +if (WIN32) + set(CMAKE_DEBUG_POSTFIX "d") +endif() + if (CMAKE_COMPILER_IS_GNUCXX OR (${CMAKE_CXX_COMPILER_ID} MATCHES "Clang")) - set(spirv-compiler-options ${spirv-compiler-options} -Wall -Wextra -Werror -Wshadow) + set(spirv-compiler-options ${spirv-compiler-options} -Wall -Wextra -Wshadow) + if (SPIRV_CROSS_MISC_WARNINGS) + if (${CMAKE_CXX_COMPILER_ID} MATCHES "Clang") + set(spirv-compiler-options ${spirv-compiler-options} -Wshorten-64-to-32) + endif() + endif() + if (SPIRV_CROSS_WERROR) + set(spirv-compiler-options ${spirv-compiler-options} -Werror) + endif() if (SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS) set(spirv-compiler-options ${spirv-compiler-options} -fno-exceptions) @@ -130,9 +160,12 @@ macro(spirv_cross_add_library name config_name library_type) extract_headers(hdrs "${ARGN}") target_include_directories(${name} PUBLIC $ - $) + $) set_target_properties(${name} PROPERTIES PUBLIC_HEADERS "${hdrs}") + if (SPIRV_CROSS_FORCE_PIC) + set_target_properties(${name} PROPERTIES POSITION_INDEPENDENT_CODE ON) + endif() target_compile_options(${name} PRIVATE ${spirv-compiler-options}) target_compile_definitions(${name} PRIVATE ${spirv-compiler-defines}) if (SPIRV_CROSS_NAMESPACE_OVERRIDE) @@ -142,15 +175,18 @@ macro(spirv_cross_add_library name config_name library_type) target_compile_definitions(${name} PRIVATE SPIRV_CROSS_NAMESPACE_OVERRIDE=${SPIRV_CROSS_NAMESPACE_OVERRIDE}) endif() endif() - install(TARGETS ${name} + + if (NOT SPIRV_CROSS_SKIP_INSTALL) + install(TARGETS ${name} EXPORT ${config_name}Config - RUNTIME DESTINATION bin - LIBRARY DESTINATION lib - ARCHIVE DESTINATION lib - PUBLIC_HEADER DESTINATION include/spirv_cross) - install(FILES ${hdrs} DESTINATION include/spirv_cross) - install(EXPORT ${config_name}Config DESTINATION share/${config_name}/cmake) - export(TARGETS ${name} FILE ${config_name}Config.cmake) + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/spirv_cross) + install(FILES ${hdrs} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/spirv_cross) + install(EXPORT ${config_name}Config DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/${config_name}/cmake) + export(TARGETS ${name} FILE ${config_name}Config.cmake) + endif() endmacro() set(spirv-cross-core-sources @@ -287,17 +323,18 @@ if (SPIRV_CROSS_STATIC) endif() set(spirv-cross-abi-major 0) -set(spirv-cross-abi-minor 16) +set(spirv-cross-abi-minor 27) set(spirv-cross-abi-patch 0) if (SPIRV_CROSS_SHARED) set(SPIRV_CROSS_VERSION ${spirv-cross-abi-major}.${spirv-cross-abi-minor}.${spirv-cross-abi-patch}) - set(SPIRV_CROSS_INSTALL_LIB_DIR ${CMAKE_INSTALL_PREFIX}/lib) - set(SPIRV_CROSS_INSTALL_INC_DIR ${CMAKE_INSTALL_PREFIX}/include/spirv_cross) - configure_file( + + if (NOT SPIRV_CROSS_SKIP_INSTALL) + configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/pkg-config/spirv-cross-c-shared.pc.in ${CMAKE_CURRENT_BINARY_DIR}/spirv-cross-c-shared.pc @ONLY) - install(FILES ${CMAKE_CURRENT_BINARY_DIR}/spirv-cross-c-shared.pc DESTINATION ${CMAKE_INSTALL_PREFIX}/share/pkgconfig) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/spirv-cross-c-shared.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) + endif() spirv_cross_add_library(spirv-cross-c-shared spirv_cross_c_shared SHARED ${spirv-cross-core-sources} @@ -395,7 +432,9 @@ if (SPIRV_CROSS_CLI) target_include_directories(spirv-cross PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) target_compile_definitions(spirv-cross PRIVATE ${spirv-compiler-defines} HAVE_SPIRV_CROSS_GIT_VERSION) set_target_properties(spirv-cross PROPERTIES LINK_FLAGS "${spirv-cross-link-flags}") - install(TARGETS spirv-cross RUNTIME DESTINATION bin) + if (NOT SPIRV_CROSS_SKIP_INSTALL) + install(TARGETS spirv-cross RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) + endif() target_link_libraries(spirv-cross PRIVATE spirv-cross-glsl spirv-cross-hlsl @@ -427,14 +466,14 @@ if (SPIRV_CROSS_CLI) if ((${spirv-cross-glslang} MATCHES "NOTFOUND") OR (${spirv-cross-spirv-as} MATCHES "NOTFOUND") OR (${spirv-cross-spirv-val} MATCHES "NOTFOUND") OR (${spirv-cross-spirv-opt} MATCHES "NOTFOUND")) set(SPIRV_CROSS_ENABLE_TESTS OFF) - message("Could not find glslang or SPIRV-Tools build under external/. Run ./checkout_glslang_spirv_tools.sh and ./build_glslang_spirv_tools.sh. Testing will be disabled.") + message("SPIRV-Cross: Testing will be disabled for SPIRV-Cross. Could not find glslang or SPIRV-Tools build under external/. To enable testing, run ./checkout_glslang_spirv_tools.sh and ./build_glslang_spirv_tools.sh first.") else() set(SPIRV_CROSS_ENABLE_TESTS ON) - message("Found glslang and SPIRV-Tools. Enabling test suite.") - message("Found glslangValidator in: ${spirv-cross-glslang}.") - message("Found spirv-as in: ${spirv-cross-spirv-as}.") - message("Found spirv-val in: ${spirv-cross-spirv-val}.") - message("Found spirv-opt in: ${spirv-cross-spirv-opt}.") + message("SPIRV-Cross: Found glslang and SPIRV-Tools. Enabling test suite.") + message("SPIRV-Cross: Found glslangValidator in: ${spirv-cross-glslang}.") + message("SPIRV-Cross: Found spirv-as in: ${spirv-cross-spirv-as}.") + message("SPIRV-Cross: Found spirv-val in: ${spirv-cross-spirv-val}.") + message("SPIRV-Cross: Found spirv-opt in: ${spirv-cross-spirv-opt}.") endif() set(spirv-cross-externals @@ -461,6 +500,18 @@ if (SPIRV_CROSS_CLI) target_link_libraries(spirv-cross-msl-resource-binding-test spirv-cross-c) set_target_properties(spirv-cross-msl-resource-binding-test PROPERTIES LINK_FLAGS "${spirv-cross-link-flags}") + add_executable(spirv-cross-hlsl-resource-binding-test tests-other/hlsl_resource_bindings.cpp) + target_link_libraries(spirv-cross-hlsl-resource-binding-test spirv-cross-c) + set_target_properties(spirv-cross-hlsl-resource-binding-test PROPERTIES LINK_FLAGS "${spirv-cross-link-flags}") + + add_executable(spirv-cross-msl-ycbcr-conversion-test tests-other/msl_ycbcr_conversion_test.cpp) + target_link_libraries(spirv-cross-msl-ycbcr-conversion-test spirv-cross-c) + set_target_properties(spirv-cross-msl-ycbcr-conversion-test PROPERTIES LINK_FLAGS "${spirv-cross-link-flags}") + + add_executable(spirv-cross-typed-id-test tests-other/typed_id_test.cpp) + target_link_libraries(spirv-cross-typed-id-test spirv-cross-core) + set_target_properties(spirv-cross-typed-id-test PROPERTIES LINK_FLAGS "${spirv-cross-link-flags}") + if (CMAKE_COMPILER_IS_GNUCXX OR (${CMAKE_CXX_COMPILER_ID} MATCHES "Clang")) target_compile_options(spirv-cross-c-api-test PRIVATE -std=c89 -Wall -Wextra) endif() @@ -475,6 +526,14 @@ if (SPIRV_CROSS_CLI) COMMAND $ ${CMAKE_CURRENT_SOURCE_DIR}/tests-other/msl_constexpr_test.spv) add_test(NAME spirv-cross-msl-resource-binding-test COMMAND $ ${CMAKE_CURRENT_SOURCE_DIR}/tests-other/msl_resource_binding.spv) + add_test(NAME spirv-cross-hlsl-resource-binding-test + COMMAND $ ${CMAKE_CURRENT_SOURCE_DIR}/tests-other/hlsl_resource_binding.spv) + add_test(NAME spirv-cross-msl-ycbcr-conversion-test + COMMAND $ ${CMAKE_CURRENT_SOURCE_DIR}/tests-other/msl_ycbcr_conversion_test.spv) + add_test(NAME spirv-cross-msl-ycbcr-conversion-test-2 + COMMAND $ ${CMAKE_CURRENT_SOURCE_DIR}/tests-other/msl_ycbcr_conversion_test_2.spv) + add_test(NAME spirv-cross-typed-id-test + COMMAND $) add_test(NAME spirv-cross-test COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test_shaders.py --parallel ${spirv-cross-externals} @@ -525,9 +584,24 @@ if (SPIRV_CROSS_CLI) ${spirv-cross-externals} ${CMAKE_CURRENT_SOURCE_DIR}/shaders-reflection WORKING_DIRECTORY $) + add_test(NAME spirv-cross-test-ue4 + COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test_shaders.py --msl --parallel + ${spirv-cross-externals} + ${CMAKE_CURRENT_SOURCE_DIR}/shaders-ue4 + WORKING_DIRECTORY $) + add_test(NAME spirv-cross-test-ue4-opt + COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test_shaders.py --msl --opt --parallel + ${spirv-cross-externals} + ${CMAKE_CURRENT_SOURCE_DIR}/shaders-ue4 + WORKING_DIRECTORY $) + add_test(NAME spirv-cross-test-ue4-no-opt + COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test_shaders.py --msl --parallel + ${spirv-cross-externals} + ${CMAKE_CURRENT_SOURCE_DIR}/shaders-ue4-no-opt + WORKING_DIRECTORY $) endif() elseif(NOT ${PYTHONINTERP_FOUND}) - message(WARNING "Testing disabled. Could not find python3. If you have python3 installed try running " + message(WARNING "SPIRV-Cross: Testing disabled. Could not find python3. If you have python3 installed try running " "cmake with -DPYTHON_EXECUTABLE:FILEPATH=/path/to/python3 to help it find the executable") endif() endif() diff --git a/third_party/spirv-cross/README.md b/third_party/spirv-cross/README.md index 831c6ff00e..969c7d9fb4 100644 --- a/third_party/spirv-cross/README.md +++ b/third_party/spirv-cross/README.md @@ -321,7 +321,7 @@ compiler.set_name(varying_resource.base_type_id, "VertexFragmentLinkage"); ``` Some platform may require identical variable name for both vertex outputs and fragment inputs. (for example MacOSX) -to rename varaible base on location, please add +to rename variable base on location, please add ``` --rename-interface-variable ``` diff --git a/third_party/spirv-cross/checkout_glslang_spirv_tools.sh b/third_party/spirv-cross/checkout_glslang_spirv_tools.sh index bd2b5fab82..22720fff21 100755 --- a/third_party/spirv-cross/checkout_glslang_spirv_tools.sh +++ b/third_party/spirv-cross/checkout_glslang_spirv_tools.sh @@ -1,8 +1,8 @@ #!/bin/bash -GLSLANG_REV=25a508cc735109cc4e382c3a1cc293a9452a41f3 -SPIRV_TOOLS_REV=55adf4cf707bb12c29fc12f784ebeaa29a819e9b -SPIRV_HEADERS_REV=29c11140baaf9f7fdaa39a583672c556bf1795a1 +GLSLANG_REV=c008fcb8cc0f6a413162fb5236d0c548cc1e0ef6 +SPIRV_TOOLS_REV=79f8caf9154a0328a87424354bd10ab69e811185 +SPIRV_HEADERS_REV=5dbc1c32182e17b8ab8e8158a802ecabaf35aad3 if [ -z $PROTOCOL ]; then PROTOCOL=git diff --git a/third_party/spirv-cross/gn/BUILD.gn b/third_party/spirv-cross/gn/BUILD.gn new file mode 100644 index 0000000000..8458c1a703 --- /dev/null +++ b/third_party/spirv-cross/gn/BUILD.gn @@ -0,0 +1,63 @@ +# Copyright (C) 2019 Google, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +config("spirv_cross_public") { + include_dirs = [ ".." ] + + defines = [ "SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS" ] +} + +source_set("spirv_cross_sources") { + public_configs = [ ":spirv_cross_public" ] + + sources = [ + "../GLSL.std.450.h", + "../spirv.hpp", + "../spirv_cfg.cpp", + "../spirv_cfg.hpp", + "../spirv_common.hpp", + "../spirv_cross.cpp", + "../spirv_cross.hpp", + "../spirv_cross_containers.hpp", + "../spirv_cross_error_handling.hpp", + "../spirv_cross_parsed_ir.cpp", + "../spirv_cross_parsed_ir.hpp", + "../spirv_cross_util.cpp", + "../spirv_cross_util.hpp", + "../spirv_glsl.cpp", + "../spirv_glsl.hpp", + "../spirv_msl.cpp", + "../spirv_msl.hpp", + "../spirv_parser.cpp", + "../spirv_parser.hpp", + "../spirv_reflect.cpp", + "../spirv_reflect.hpp", + ] + + cflags = [ "-fno-exceptions" ] + + if (is_clang) { + cflags_cc = [ + "-Wno-extra-semi", + "-Wno-ignored-qualifiers", + "-Wno-implicit-fallthrough", + "-Wno-inconsistent-missing-override", + "-Wno-missing-field-initializers", + "-Wno-newline-eof", + "-Wno-sign-compare", + "-Wno-unused-variable", + ] + } +} diff --git a/third_party/spirv-cross/include/spirv_cross/sampler.hpp b/third_party/spirv-cross/include/spirv_cross/sampler.hpp index a95d489e2d..542e11b444 100644 --- a/third_party/spirv-cross/include/spirv_cross/sampler.hpp +++ b/third_party/spirv-cross/include/spirv_cross/sampler.hpp @@ -85,7 +85,7 @@ struct sampler2DBase : spirv_cross_sampler_2d std::vector mips; spirv_cross_format format; spirv_cross_wrap wrap_s; - spirv_cross_format wrap_t; + spirv_cross_wrap wrap_t; spirv_cross_filter min_filter; spirv_cross_filter mag_filter; spirv_cross_mipfilter mip_filter; diff --git a/third_party/spirv-cross/main.cpp b/third_party/spirv-cross/main.cpp index 00db1be1f6..5b1b96e201 100644 --- a/third_party/spirv-cross/main.cpp +++ b/third_party/spirv-cross/main.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2015-2019 Arm Limited + * Copyright 2015-2020 Arm Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -246,7 +246,7 @@ static void print_resources(const Compiler &compiler, const char *tag, const Sma compiler.get_decoration_bitset(type.self).get(DecorationBufferBlock); bool is_sized_block = is_block && (compiler.get_storage_class(res.id) == StorageClassUniform || compiler.get_storage_class(res.id) == StorageClassUniformConstant); - uint32_t fallback_id = !is_push_constant && is_block ? res.base_type_id : res.id; + ID fallback_id = !is_push_constant && is_block ? ID(res.base_type_id) : ID(res.id); uint32_t block_size = 0; uint32_t runtime_array_stride = 0; @@ -268,7 +268,7 @@ static void print_resources(const Compiler &compiler, const char *tag, const Sma for (auto arr : type.array) array = join("[", arr ? convert_to_string(arr) : "", "]") + array; - fprintf(stderr, " ID %03u : %s%s", res.id, + fprintf(stderr, " ID %03u : %s%s", uint32_t(res.id), !res.name.empty() ? res.name.c_str() : compiler.get_fallback_name(fallback_id).c_str(), array.c_str()); if (mask.get(DecorationLocation)) @@ -442,7 +442,7 @@ static void print_spec_constants(const Compiler &compiler) fprintf(stderr, "Specialization constants\n"); fprintf(stderr, "==================\n\n"); for (auto &c : spec_constants) - fprintf(stderr, "ID: %u, Spec ID: %u\n", c.id, c.constant_id); + fprintf(stderr, "ID: %u, Spec ID: %u\n", uint32_t(c.id), c.constant_id); fprintf(stderr, "==================\n\n"); } @@ -514,12 +514,24 @@ struct CLIArguments bool msl_domain_lower_left = false; bool msl_argument_buffers = false; bool msl_texture_buffer_native = false; + bool msl_framebuffer_fetch = false; + bool msl_invariant_float_math = false; + bool msl_emulate_cube_array = false; bool msl_multiview = false; bool msl_view_index_from_device_index = false; + bool msl_dispatch_base = false; + bool msl_decoration_binding = false; + bool msl_force_active_argument_buffer_resources = false; + bool msl_force_native_arrays = false; bool glsl_emit_push_constant_as_ubo = false; bool glsl_emit_ubo_as_plain_uniforms = false; + bool vulkan_glsl_disable_ext_samplerless_texture_functions = false; bool emit_line_directives = false; + bool enable_storage_image_qualifier_deduction = true; SmallVector msl_discrete_descriptor_sets; + SmallVector msl_device_argument_buffers; + SmallVector> msl_dynamic_buffers; + SmallVector> msl_inline_uniform_blocks; SmallVector pls_in; SmallVector pls_out; SmallVector remaps; @@ -545,6 +557,8 @@ struct CLIArguments bool hlsl = false; bool hlsl_compat = false; bool hlsl_support_nonzero_base = false; + bool hlsl_force_storage_buffer_as_uav = false; + HLSLBindingFlags hlsl_binding_flags = 0; bool vulkan_semantics = false; bool flatten_multidimensional_arrays = false; bool use_420pack_extension = true; @@ -575,15 +589,17 @@ static void print_help() "\t[--help]\n" "\t[--revision]\n" "\t[--force-temporary]\n" - "\t[--vulkan-semantics]\n" + "\t[--vulkan-semantics] or [-V]\n" "\t[--flatten-ubo]\n" "\t[--fixup-clipspace]\n" "\t[--flip-vert-y]\n" "\t[--iterations iter]\n" "\t[--cpp]\n" "\t[--cpp-interface-name ]\n" + "\t[--disable-storage-image-qualifier-deduction]\n" "\t[--glsl-emit-push-constant-as-ubo]\n" "\t[--glsl-emit-ubo-as-plain-uniforms]\n" + "\t[--vulkan-glsl-disable-ext-samplerless-texture-functions]\n" "\t[--msl]\n" "\t[--msl-version ]\n" "\t[--msl-capture-output]\n" @@ -593,14 +609,25 @@ static void print_help() "\t[--msl-domain-lower-left]\n" "\t[--msl-argument-buffers]\n" "\t[--msl-texture-buffer-native]\n" + "\t[--msl-framebuffer-fetch]\n" + "\t[--msl-emulate-cube-array]\n" "\t[--msl-discrete-descriptor-set ]\n" + "\t[--msl-device-argument-buffer ]\n" "\t[--msl-multiview]\n" "\t[--msl-view-index-from-device-index]\n" + "\t[--msl-dispatch-base]\n" + "\t[--msl-dynamic-buffer ]\n" + "\t[--msl-inline-uniform-block ]\n" + "\t[--msl-decoration-binding]\n" + "\t[--msl-force-active-argument-buffer-resources]\n" + "\t[--msl-force-native-arrays]\n" "\t[--hlsl]\n" "\t[--reflect]\n" "\t[--shader-model]\n" "\t[--hlsl-enable-compat]\n" "\t[--hlsl-support-nonzero-basevertex-baseinstance]\n" + "\t[--hlsl-auto-binding (push, cbv, srv, uav, sampler, all)]\n" + "\t[--hlsl-force-storage-buffer-as-uav]\n" "\t[--separate-shader-objects]\n" "\t[--pls-in format input-name]\n" "\t[--pls-out format output-name]\n" @@ -723,6 +750,27 @@ static ExecutionModel stage_to_execution_model(const std::string &stage) SPIRV_CROSS_THROW("Invalid stage."); } +static HLSLBindingFlags hlsl_resource_type_to_flag(const std::string &arg) +{ + if (arg == "push") + return HLSL_BINDING_AUTO_PUSH_CONSTANT_BIT; + else if (arg == "cbv") + return HLSL_BINDING_AUTO_CBV_BIT; + else if (arg == "srv") + return HLSL_BINDING_AUTO_SRV_BIT; + else if (arg == "uav") + return HLSL_BINDING_AUTO_UAV_BIT; + else if (arg == "sampler") + return HLSL_BINDING_AUTO_SAMPLER_BIT; + else if (arg == "all") + return HLSL_BINDING_AUTO_ALL; + else + { + fprintf(stderr, "Invalid resource type for --hlsl-auto-binding: %s\n", arg.c_str()); + return 0; + } +} + static string compile_iteration(const CLIArguments &args, std::vector spirv_file) { Parser spirv_parser(move(spirv_file)); @@ -748,24 +796,40 @@ static string compile_iteration(const CLIArguments &args, std::vector msl_opts.msl_version = args.msl_version; msl_opts.capture_output_to_buffer = args.msl_capture_output_to_buffer; msl_opts.swizzle_texture_samples = args.msl_swizzle_texture_samples; + msl_opts.invariant_float_math = args.msl_invariant_float_math; if (args.msl_ios) + { msl_opts.platform = CompilerMSL::Options::iOS; + msl_opts.ios_use_framebuffer_fetch_subpasses = args.msl_framebuffer_fetch; + msl_opts.emulate_cube_array = args.msl_emulate_cube_array; + } msl_opts.pad_fragment_output_components = args.msl_pad_fragment_output; msl_opts.tess_domain_origin_lower_left = args.msl_domain_lower_left; msl_opts.argument_buffers = args.msl_argument_buffers; msl_opts.texture_buffer_native = args.msl_texture_buffer_native; msl_opts.multiview = args.msl_multiview; msl_opts.view_index_from_device_index = args.msl_view_index_from_device_index; + msl_opts.dispatch_base = args.msl_dispatch_base; + msl_opts.enable_decoration_binding = args.msl_decoration_binding; + msl_opts.force_active_argument_buffer_resources = args.msl_force_active_argument_buffer_resources; + msl_opts.force_native_arrays = args.msl_force_native_arrays; msl_comp->set_msl_options(msl_opts); for (auto &v : args.msl_discrete_descriptor_sets) msl_comp->add_discrete_descriptor_set(v); + for (auto &v : args.msl_device_argument_buffers) + msl_comp->set_argument_buffer_device_address_space(v, true); + uint32_t i = 0; + for (auto &v : args.msl_dynamic_buffers) + msl_comp->add_dynamic_buffer(v.first, v.second, i++); + for (auto &v : args.msl_inline_uniform_blocks) + msl_comp->add_inline_uniform_block(v.first, v.second); } else if (args.hlsl) compiler.reset(new CompilerHLSL(move(spirv_parser.get_parsed_ir()))); else { combined_image_samplers = !args.vulkan_semantics; - if (!args.vulkan_semantics) + if (!args.vulkan_semantics || args.vulkan_glsl_disable_ext_samplerless_texture_functions) build_dummy_sampler = true; compiler.reset(new CompilerGLSL(move(spirv_parser.get_parsed_ir()))); } @@ -882,6 +946,7 @@ static string compile_iteration(const CLIArguments &args, std::vector opts.emit_push_constant_as_uniform_buffer = args.glsl_emit_push_constant_as_ubo; opts.emit_uniform_buffer_as_plain_uniforms = args.glsl_emit_ubo_as_plain_uniforms; opts.emit_line_directives = args.emit_line_directives; + opts.enable_storage_image_qualifier_deduction = args.enable_storage_image_qualifier_deduction; compiler->set_common_options(opts); // Set HLSL specific options. @@ -914,7 +979,9 @@ static string compile_iteration(const CLIArguments &args, std::vector } hlsl_opts.support_nonzero_base_vertex_base_instance = args.hlsl_support_nonzero_base; + hlsl_opts.force_storage_buffer_as_uav = args.hlsl_force_storage_buffer_as_uav; hlsl->set_hlsl_options(hlsl_opts); + hlsl->set_resource_binding_flags(args.hlsl_binding_flags); } if (build_dummy_sampler) @@ -1058,12 +1125,22 @@ static int main_inner(int argc, char *argv[]) cbs.add("--metal", [&args](CLIParser &) { args.msl = true; }); // Legacy compatibility cbs.add("--glsl-emit-push-constant-as-ubo", [&args](CLIParser &) { args.glsl_emit_push_constant_as_ubo = true; }); cbs.add("--glsl-emit-ubo-as-plain-uniforms", [&args](CLIParser &) { args.glsl_emit_ubo_as_plain_uniforms = true; }); + cbs.add("--vulkan-glsl-disable-ext-samplerless-texture-functions", + [&args](CLIParser &) { args.vulkan_glsl_disable_ext_samplerless_texture_functions = true; }); + cbs.add("--disable-storage-image-qualifier-deduction", [&args](CLIParser &) { args.enable_storage_image_qualifier_deduction = false; }); cbs.add("--msl", [&args](CLIParser &) { args.msl = true; }); cbs.add("--hlsl", [&args](CLIParser &) { args.hlsl = true; }); cbs.add("--hlsl-enable-compat", [&args](CLIParser &) { args.hlsl_compat = true; }); cbs.add("--hlsl-support-nonzero-basevertex-baseinstance", [&args](CLIParser &) { args.hlsl_support_nonzero_base = true; }); + cbs.add("--hlsl-auto-binding", [&args](CLIParser &parser) { + args.hlsl_binding_flags |= hlsl_resource_type_to_flag(parser.next_string()); + }); + cbs.add("--hlsl-force-storage-buffer-as-uav", [&args](CLIParser &) { + args.hlsl_force_storage_buffer_as_uav = true; + }); cbs.add("--vulkan-semantics", [&args](CLIParser &) { args.vulkan_semantics = true; }); + cbs.add("-V", [&args](CLIParser &) { args.vulkan_semantics = true; }); cbs.add("--flatten-multidimensional-arrays", [&args](CLIParser &) { args.flatten_multidimensional_arrays = true; }); cbs.add("--no-420pack-extension", [&args](CLIParser &) { args.use_420pack_extension = false; }); cbs.add("--msl-capture-output", [&args](CLIParser &) { args.msl_capture_output_to_buffer = true; }); @@ -1074,10 +1151,36 @@ static int main_inner(int argc, char *argv[]) cbs.add("--msl-argument-buffers", [&args](CLIParser &) { args.msl_argument_buffers = true; }); cbs.add("--msl-discrete-descriptor-set", [&args](CLIParser &parser) { args.msl_discrete_descriptor_sets.push_back(parser.next_uint()); }); + cbs.add("--msl-device-argument-buffer", + [&args](CLIParser &parser) { args.msl_device_argument_buffers.push_back(parser.next_uint()); }); cbs.add("--msl-texture-buffer-native", [&args](CLIParser &) { args.msl_texture_buffer_native = true; }); + cbs.add("--msl-framebuffer-fetch", [&args](CLIParser &) { args.msl_framebuffer_fetch = true; }); + cbs.add("--msl-invariant-float-math", [&args](CLIParser &) { args.msl_invariant_float_math = true; }); + cbs.add("--msl-emulate-cube-array", [&args](CLIParser &) { args.msl_emulate_cube_array = true; }); cbs.add("--msl-multiview", [&args](CLIParser &) { args.msl_multiview = true; }); cbs.add("--msl-view-index-from-device-index", [&args](CLIParser &) { args.msl_view_index_from_device_index = true; }); + cbs.add("--msl-dispatch-base", [&args](CLIParser &) { args.msl_dispatch_base = true; }); + cbs.add("--msl-dynamic-buffer", [&args](CLIParser &parser) { + args.msl_argument_buffers = true; + // Make sure next_uint() is called in-order. + uint32_t desc_set = parser.next_uint(); + uint32_t binding = parser.next_uint(); + args.msl_dynamic_buffers.push_back(make_pair(desc_set, binding)); + }); + cbs.add("--msl-decoration-binding", [&args](CLIParser &) { args.msl_decoration_binding = true; }); + cbs.add("--msl-force-active-argument-buffer-resources", + [&args](CLIParser &) { args.msl_force_active_argument_buffer_resources = true; }); + cbs.add("--msl-inline-uniform-block", [&args](CLIParser &parser) { + args.msl_argument_buffers = true; + // Make sure next_uint() is called in-order. + uint32_t desc_set = parser.next_uint(); + uint32_t binding = parser.next_uint(); + args.msl_inline_uniform_blocks.push_back(make_pair(desc_set, binding)); + }); + cbs.add("--msl-force-native-arrays", [&args](CLIParser &) { + args.msl_force_native_arrays = true; + }); cbs.add("--extension", [&args](CLIParser &parser) { args.extensions.push_back(parser.next_string()); }); cbs.add("--rename-entry-point", [&args](CLIParser &parser) { auto old_name = parser.next_string(); diff --git a/third_party/spirv-cross/pkg-config/spirv-cross-c-shared.pc.in b/third_party/spirv-cross/pkg-config/spirv-cross-c-shared.pc.in index 823e4ce48b..09678c53a5 100644 --- a/third_party/spirv-cross/pkg-config/spirv-cross-c-shared.pc.in +++ b/third_party/spirv-cross/pkg-config/spirv-cross-c-shared.pc.in @@ -1,8 +1,8 @@ prefix=@CMAKE_INSTALL_PREFIX@ -exec_prefix=@CMAKE_INSTALL_PREFIX@ -libdir=@SPIRV_CROSS_INSTALL_LIB_DIR@ -sharedlibdir=@SPIRV_CROSS_INSTALL_LIB_DIR@ -includedir=@SPIRV_CROSS_INSTALL_INC_DIR@ +exec_prefix=${prefix} +libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@ +sharedlibdir=${prefix}/@CMAKE_INSTALL_LIBDIR@ +includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@/spirv_cross Name: spirv-cross-c-shared Description: C API for SPIRV-Cross diff --git a/third_party/spirv-cross/reference/opt/shaders-hlsl/asm/comp/bitcast_icmp.asm.comp b/third_party/spirv-cross/reference/opt/shaders-hlsl/asm/comp/bitcast_icmp.asm.comp new file mode 100644 index 0000000000..35143a486e --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders-hlsl/asm/comp/bitcast_icmp.asm.comp @@ -0,0 +1,28 @@ +RWByteAddressBuffer _5 : register(u0); +RWByteAddressBuffer _6 : register(u1); + +void comp_main() +{ + bool4 _31 = bool4(int(_5.Load4(16).x) < int4(_5.Load4(0)).x, int(_5.Load4(16).y) < int4(_5.Load4(0)).y, int(_5.Load4(16).z) < int4(_5.Load4(0)).z, int(_5.Load4(16).w) < int4(_5.Load4(0)).w); + bool4 _32 = bool4(int(_5.Load4(16).x) <= int4(_5.Load4(0)).x, int(_5.Load4(16).y) <= int4(_5.Load4(0)).y, int(_5.Load4(16).z) <= int4(_5.Load4(0)).z, int(_5.Load4(16).w) <= int4(_5.Load4(0)).w); + bool4 _33 = bool4(_5.Load4(16).x < uint(int4(_5.Load4(0)).x), _5.Load4(16).y < uint(int4(_5.Load4(0)).y), _5.Load4(16).z < uint(int4(_5.Load4(0)).z), _5.Load4(16).w < uint(int4(_5.Load4(0)).w)); + bool4 _34 = bool4(_5.Load4(16).x <= uint(int4(_5.Load4(0)).x), _5.Load4(16).y <= uint(int4(_5.Load4(0)).y), _5.Load4(16).z <= uint(int4(_5.Load4(0)).z), _5.Load4(16).w <= uint(int4(_5.Load4(0)).w)); + bool4 _35 = bool4(int(_5.Load4(16).x) > int4(_5.Load4(0)).x, int(_5.Load4(16).y) > int4(_5.Load4(0)).y, int(_5.Load4(16).z) > int4(_5.Load4(0)).z, int(_5.Load4(16).w) > int4(_5.Load4(0)).w); + bool4 _36 = bool4(int(_5.Load4(16).x) >= int4(_5.Load4(0)).x, int(_5.Load4(16).y) >= int4(_5.Load4(0)).y, int(_5.Load4(16).z) >= int4(_5.Load4(0)).z, int(_5.Load4(16).w) >= int4(_5.Load4(0)).w); + bool4 _37 = bool4(_5.Load4(16).x > uint(int4(_5.Load4(0)).x), _5.Load4(16).y > uint(int4(_5.Load4(0)).y), _5.Load4(16).z > uint(int4(_5.Load4(0)).z), _5.Load4(16).w > uint(int4(_5.Load4(0)).w)); + bool4 _38 = bool4(_5.Load4(16).x >= uint(int4(_5.Load4(0)).x), _5.Load4(16).y >= uint(int4(_5.Load4(0)).y), _5.Load4(16).z >= uint(int4(_5.Load4(0)).z), _5.Load4(16).w >= uint(int4(_5.Load4(0)).w)); + _6.Store4(0, uint4(_31.x ? uint4(1u, 1u, 1u, 1u).x : uint4(0u, 0u, 0u, 0u).x, _31.y ? uint4(1u, 1u, 1u, 1u).y : uint4(0u, 0u, 0u, 0u).y, _31.z ? uint4(1u, 1u, 1u, 1u).z : uint4(0u, 0u, 0u, 0u).z, _31.w ? uint4(1u, 1u, 1u, 1u).w : uint4(0u, 0u, 0u, 0u).w)); + _6.Store4(0, uint4(_32.x ? uint4(1u, 1u, 1u, 1u).x : uint4(0u, 0u, 0u, 0u).x, _32.y ? uint4(1u, 1u, 1u, 1u).y : uint4(0u, 0u, 0u, 0u).y, _32.z ? uint4(1u, 1u, 1u, 1u).z : uint4(0u, 0u, 0u, 0u).z, _32.w ? uint4(1u, 1u, 1u, 1u).w : uint4(0u, 0u, 0u, 0u).w)); + _6.Store4(0, uint4(_33.x ? uint4(1u, 1u, 1u, 1u).x : uint4(0u, 0u, 0u, 0u).x, _33.y ? uint4(1u, 1u, 1u, 1u).y : uint4(0u, 0u, 0u, 0u).y, _33.z ? uint4(1u, 1u, 1u, 1u).z : uint4(0u, 0u, 0u, 0u).z, _33.w ? uint4(1u, 1u, 1u, 1u).w : uint4(0u, 0u, 0u, 0u).w)); + _6.Store4(0, uint4(_34.x ? uint4(1u, 1u, 1u, 1u).x : uint4(0u, 0u, 0u, 0u).x, _34.y ? uint4(1u, 1u, 1u, 1u).y : uint4(0u, 0u, 0u, 0u).y, _34.z ? uint4(1u, 1u, 1u, 1u).z : uint4(0u, 0u, 0u, 0u).z, _34.w ? uint4(1u, 1u, 1u, 1u).w : uint4(0u, 0u, 0u, 0u).w)); + _6.Store4(0, uint4(_35.x ? uint4(1u, 1u, 1u, 1u).x : uint4(0u, 0u, 0u, 0u).x, _35.y ? uint4(1u, 1u, 1u, 1u).y : uint4(0u, 0u, 0u, 0u).y, _35.z ? uint4(1u, 1u, 1u, 1u).z : uint4(0u, 0u, 0u, 0u).z, _35.w ? uint4(1u, 1u, 1u, 1u).w : uint4(0u, 0u, 0u, 0u).w)); + _6.Store4(0, uint4(_36.x ? uint4(1u, 1u, 1u, 1u).x : uint4(0u, 0u, 0u, 0u).x, _36.y ? uint4(1u, 1u, 1u, 1u).y : uint4(0u, 0u, 0u, 0u).y, _36.z ? uint4(1u, 1u, 1u, 1u).z : uint4(0u, 0u, 0u, 0u).z, _36.w ? uint4(1u, 1u, 1u, 1u).w : uint4(0u, 0u, 0u, 0u).w)); + _6.Store4(0, uint4(_37.x ? uint4(1u, 1u, 1u, 1u).x : uint4(0u, 0u, 0u, 0u).x, _37.y ? uint4(1u, 1u, 1u, 1u).y : uint4(0u, 0u, 0u, 0u).y, _37.z ? uint4(1u, 1u, 1u, 1u).z : uint4(0u, 0u, 0u, 0u).z, _37.w ? uint4(1u, 1u, 1u, 1u).w : uint4(0u, 0u, 0u, 0u).w)); + _6.Store4(0, uint4(_38.x ? uint4(1u, 1u, 1u, 1u).x : uint4(0u, 0u, 0u, 0u).x, _38.y ? uint4(1u, 1u, 1u, 1u).y : uint4(0u, 0u, 0u, 0u).y, _38.z ? uint4(1u, 1u, 1u, 1u).z : uint4(0u, 0u, 0u, 0u).z, _38.w ? uint4(1u, 1u, 1u, 1u).w : uint4(0u, 0u, 0u, 0u).w)); +} + +[numthreads(1, 1, 1)] +void main() +{ + comp_main(); +} diff --git a/third_party/spirv-cross/reference/opt/shaders-hlsl/asm/frag/line-directive.line.asm.frag b/third_party/spirv-cross/reference/opt/shaders-hlsl/asm/frag/line-directive.line.asm.frag index b596a8446e..93bb69eb3f 100644 --- a/third_party/spirv-cross/reference/opt/shaders-hlsl/asm/frag/line-directive.line.asm.frag +++ b/third_party/spirv-cross/reference/opt/shaders-hlsl/asm/frag/line-directive.line.asm.frag @@ -14,14 +14,12 @@ struct SPIRV_Cross_Output #line 8 "test.frag" void frag_main() { - float _80; #line 8 "test.frag" FragColor = 1.0f; #line 9 "test.frag" FragColor = 2.0f; #line 10 "test.frag" - _80 = vColor; - if (_80 < 0.0f) + if (vColor < 0.0f) { #line 12 "test.frag" FragColor = 3.0f; @@ -31,16 +29,16 @@ void frag_main() #line 16 "test.frag" FragColor = 4.0f; } - for (int _126 = 0; float(_126) < (40.0f + _80); ) + for (int _126 = 0; float(_126) < (40.0f + vColor); ) { #line 21 "test.frag" FragColor += 0.20000000298023223876953125f; #line 22 "test.frag" FragColor += 0.300000011920928955078125f; - _126 += (int(_80) + 5); + _126 += (int(vColor) + 5); continue; } - switch (int(_80)) + switch (int(vColor)) { case 0: { @@ -66,7 +64,7 @@ void frag_main() } for (;;) { - FragColor += (10.0f + _80); + FragColor += (10.0f + vColor); #line 43 "test.frag" if (FragColor < 100.0f) { diff --git a/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/access-chain-load-composite.comp b/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/access-chain-load-composite.comp new file mode 100644 index 0000000000..778f62e83c --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/access-chain-load-composite.comp @@ -0,0 +1,108 @@ +struct Baz +{ + float c; +}; + +struct Bar +{ + float d[2][4]; + Baz baz[2]; +}; + +struct Foo +{ + column_major float2x2 a; + float2 b; + Bar c[5]; +}; + +static const uint3 gl_WorkGroupSize = uint3(1u, 1u, 1u); + +RWByteAddressBuffer _31 : register(u0); + +void comp_main() +{ + Foo _36; + _36.a = asfloat(uint2x2(_31.Load(0), _31.Load(8), _31.Load(4), _31.Load(12))); + _36.b = asfloat(_31.Load2(16)); + [unroll] + for (int _4ident = 0; _4ident < 5; _4ident++) + { + [unroll] + for (int _5ident = 0; _5ident < 2; _5ident++) + { + [unroll] + for (int _6ident = 0; _6ident < 4; _6ident++) + { + _36.c[_4ident].d[_5ident][_6ident] = asfloat(_31.Load(_6ident * 4 + _5ident * 16 + _4ident * 40 + 24)); + } + } + [unroll] + for (int _7ident = 0; _7ident < 2; _7ident++) + { + _36.c[_4ident].baz[_7ident].c = asfloat(_31.Load(_7ident * 4 + _4ident * 40 + 56)); + } + } + float2x2 _234 = float2x2(_36.a[0] + 1.0f.xx, _36.a[1] + 1.0f.xx); + _31.Store(224, asuint(_234[0].x)); + _31.Store(228, asuint(_234[1].x)); + _31.Store(232, asuint(_234[0].y)); + _31.Store(236, asuint(_234[1].y)); + _31.Store2(240, asuint(_36.b + 2.0f.xx)); + _31.Store(248, asuint(_36.c[0].d[0][0])); + _31.Store(252, asuint(_36.c[0].d[0][1])); + _31.Store(256, asuint(_36.c[0].d[0][2])); + _31.Store(260, asuint(_36.c[0].d[0][3])); + _31.Store(264, asuint(_36.c[0].d[1][0])); + _31.Store(268, asuint(_36.c[0].d[1][1])); + _31.Store(272, asuint(_36.c[0].d[1][2])); + _31.Store(276, asuint(_36.c[0].d[1][3])); + _31.Store(280, asuint(_36.c[0].baz[0].c)); + _31.Store(284, asuint(_36.c[0].baz[1].c)); + _31.Store(288, asuint(_36.c[1].d[0][0])); + _31.Store(292, asuint(_36.c[1].d[0][1])); + _31.Store(296, asuint(_36.c[1].d[0][2])); + _31.Store(300, asuint(_36.c[1].d[0][3])); + _31.Store(304, asuint(_36.c[1].d[1][0])); + _31.Store(308, asuint(_36.c[1].d[1][1])); + _31.Store(312, asuint(_36.c[1].d[1][2])); + _31.Store(316, asuint(_36.c[1].d[1][3])); + _31.Store(320, asuint(_36.c[1].baz[0].c)); + _31.Store(324, asuint(_36.c[1].baz[1].c)); + _31.Store(328, asuint(_36.c[2].d[0][0])); + _31.Store(332, asuint(_36.c[2].d[0][1])); + _31.Store(336, asuint(_36.c[2].d[0][2])); + _31.Store(340, asuint(_36.c[2].d[0][3])); + _31.Store(344, asuint(_36.c[2].d[1][0])); + _31.Store(348, asuint(_36.c[2].d[1][1])); + _31.Store(352, asuint(_36.c[2].d[1][2])); + _31.Store(356, asuint(_36.c[2].d[1][3])); + _31.Store(360, asuint(_36.c[2].baz[0].c)); + _31.Store(364, asuint(_36.c[2].baz[1].c)); + _31.Store(368, asuint(_36.c[3].d[0][0])); + _31.Store(372, asuint(_36.c[3].d[0][1])); + _31.Store(376, asuint(_36.c[3].d[0][2])); + _31.Store(380, asuint(_36.c[3].d[0][3])); + _31.Store(384, asuint(_36.c[3].d[1][0])); + _31.Store(388, asuint(_36.c[3].d[1][1] + 5.0f)); + _31.Store(392, asuint(_36.c[3].d[1][2])); + _31.Store(396, asuint(_36.c[3].d[1][3])); + _31.Store(400, asuint(_36.c[3].baz[0].c)); + _31.Store(404, asuint(_36.c[3].baz[1].c)); + _31.Store(408, asuint(_36.c[4].d[0][0])); + _31.Store(412, asuint(_36.c[4].d[0][1])); + _31.Store(416, asuint(_36.c[4].d[0][2])); + _31.Store(420, asuint(_36.c[4].d[0][3])); + _31.Store(424, asuint(_36.c[4].d[1][0])); + _31.Store(428, asuint(_36.c[4].d[1][1])); + _31.Store(432, asuint(_36.c[4].d[1][2])); + _31.Store(436, asuint(_36.c[4].d[1][3])); + _31.Store(440, asuint(_36.c[4].baz[0].c)); + _31.Store(444, asuint(_36.c[4].baz[1].c)); +} + +[numthreads(1, 1, 1)] +void main() +{ + comp_main(); +} diff --git a/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/access-chains.comp b/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/access-chains.comp index 924e919124..c748200b96 100644 --- a/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/access-chains.comp +++ b/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/access-chains.comp @@ -1,3 +1,5 @@ +static const uint3 gl_WorkGroupSize = uint3(1u, 1u, 1u); + RWByteAddressBuffer wo : register(u1); ByteAddressBuffer ro : register(t0); diff --git a/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/access-chains.force-uav.comp b/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/access-chains.force-uav.comp new file mode 100644 index 0000000000..97d046d89a --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/access-chains.force-uav.comp @@ -0,0 +1,23 @@ +static const uint3 gl_WorkGroupSize = uint3(1u, 1u, 1u); + +RWByteAddressBuffer wo : register(u1); +RWByteAddressBuffer ro : register(u0); + +static uint3 gl_GlobalInvocationID; +struct SPIRV_Cross_Input +{ + uint3 gl_GlobalInvocationID : SV_DispatchThreadID; +}; + +void comp_main() +{ + wo.Store4(gl_GlobalInvocationID.x * 64 + 272, asuint(asfloat(ro.Load4(gl_GlobalInvocationID.x * 64 + 160)))); + wo.Store4(gl_GlobalInvocationID.x * 16 + 480, asuint(asfloat(ro.Load4(gl_GlobalInvocationID.x * 16 + 480)))); +} + +[numthreads(1, 1, 1)] +void main(SPIRV_Cross_Input stage_input) +{ + gl_GlobalInvocationID = stage_input.gl_GlobalInvocationID; + comp_main(); +} diff --git a/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/address-buffers.comp b/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/address-buffers.comp index a252fc8ae3..7f1c7975bc 100644 --- a/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/address-buffers.comp +++ b/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/address-buffers.comp @@ -1,3 +1,5 @@ +static const uint3 gl_WorkGroupSize = uint3(1u, 1u, 1u); + RWByteAddressBuffer WriteOnly : register(u2); ByteAddressBuffer ReadOnly : register(t0); RWByteAddressBuffer ReadWrite : register(u1); diff --git a/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/atomic-decrement.asm.comp b/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/atomic-decrement.asm.comp deleted file mode 100644 index b86b5327e7..0000000000 --- a/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/atomic-decrement.asm.comp +++ /dev/null @@ -1,22 +0,0 @@ -RWByteAddressBuffer u0_counter : register(u1); -RWBuffer u0 : register(u0); - -static uint3 gl_GlobalInvocationID; -struct SPIRV_Cross_Input -{ - uint3 gl_GlobalInvocationID : SV_DispatchThreadID; -}; - -void comp_main() -{ - uint _29; - u0_counter.InterlockedAdd(0, -1, _29); - u0[uint(asint(asfloat(_29))) + 0u] = uint(int(gl_GlobalInvocationID.x)).x; -} - -[numthreads(4, 1, 1)] -void main(SPIRV_Cross_Input stage_input) -{ - gl_GlobalInvocationID = stage_input.gl_GlobalInvocationID; - comp_main(); -} diff --git a/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/atomic-increment.asm.comp b/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/atomic-increment.asm.comp deleted file mode 100644 index f2338f2251..0000000000 --- a/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/atomic-increment.asm.comp +++ /dev/null @@ -1,22 +0,0 @@ -RWByteAddressBuffer u0_counter : register(u1); -RWBuffer u0 : register(u0); - -static uint3 gl_GlobalInvocationID; -struct SPIRV_Cross_Input -{ - uint3 gl_GlobalInvocationID : SV_DispatchThreadID; -}; - -void comp_main() -{ - uint _29; - u0_counter.InterlockedAdd(0, 1, _29); - u0[uint(asint(asfloat(_29))) + 0u] = uint(int(gl_GlobalInvocationID.x)).x; -} - -[numthreads(4, 1, 1)] -void main(SPIRV_Cross_Input stage_input) -{ - gl_GlobalInvocationID = stage_input.gl_GlobalInvocationID; - comp_main(); -} diff --git a/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/atomic.comp b/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/atomic.comp index 72e15bf77d..e6ff891e8c 100644 --- a/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/atomic.comp +++ b/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/atomic.comp @@ -1,3 +1,5 @@ +static const uint3 gl_WorkGroupSize = uint3(1u, 1u, 1u); + RWByteAddressBuffer ssbo : register(u2); RWTexture2D uImage : register(u0); RWTexture2D iImage : register(u1); diff --git a/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/globallycoherent.comp b/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/globallycoherent.comp index 1637727deb..b5f1e377ca 100644 --- a/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/globallycoherent.comp +++ b/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/globallycoherent.comp @@ -1,3 +1,5 @@ +static const uint3 gl_WorkGroupSize = uint3(1u, 1u, 1u); + globallycoherent RWByteAddressBuffer _29 : register(u3); ByteAddressBuffer _33 : register(t2); RWTexture2D uImageIn : register(u0); diff --git a/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/image.comp b/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/image.comp index 6c2b58cd29..e2f6b0a340 100644 --- a/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/image.comp +++ b/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/image.comp @@ -1,3 +1,5 @@ +static const uint3 gl_WorkGroupSize = uint3(1u, 1u, 1u); + RWTexture2D uImageInF : register(u0); RWTexture2D uImageOutF : register(u1); RWTexture2D uImageInI : register(u2); diff --git a/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/inverse.comp b/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/inverse.comp index 3be954a6f6..f9ec89aa31 100644 --- a/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/inverse.comp +++ b/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/inverse.comp @@ -1,3 +1,5 @@ +static const uint3 gl_WorkGroupSize = uint3(1u, 1u, 1u); + RWByteAddressBuffer _15 : register(u0); ByteAddressBuffer _20 : register(t1); diff --git a/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/num-workgroups-alone.comp b/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/num-workgroups-alone.comp index dee39e3d57..dc87dc84f8 100644 --- a/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/num-workgroups-alone.comp +++ b/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/num-workgroups-alone.comp @@ -1,3 +1,5 @@ +static const uint3 gl_WorkGroupSize = uint3(1u, 1u, 1u); + RWByteAddressBuffer _10 : register(u0); cbuffer SPIRV_Cross_NumWorkgroups : register(b0) { diff --git a/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/num-workgroups-with-builtins.comp b/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/num-workgroups-with-builtins.comp index 1c98e5e56d..2e2ad55fdd 100644 --- a/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/num-workgroups-with-builtins.comp +++ b/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/num-workgroups-with-builtins.comp @@ -1,3 +1,5 @@ +static const uint3 gl_WorkGroupSize = uint3(1u, 1u, 1u); + RWByteAddressBuffer _10 : register(u0); cbuffer SPIRV_Cross_NumWorkgroups : register(b0) { diff --git a/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/outer-product.comp b/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/outer-product.comp index 71613d4f15..e58c02fe0b 100644 --- a/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/outer-product.comp +++ b/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/outer-product.comp @@ -1,3 +1,5 @@ +static const uint3 gl_WorkGroupSize = uint3(1u, 1u, 1u); + RWByteAddressBuffer _21 : register(u0); ByteAddressBuffer _26 : register(t1); diff --git a/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/rmw-matrix.comp b/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/rmw-matrix.comp index ed66669358..30ac03f84f 100644 --- a/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/rmw-matrix.comp +++ b/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/rmw-matrix.comp @@ -1,3 +1,5 @@ +static const uint3 gl_WorkGroupSize = uint3(1u, 1u, 1u); + RWByteAddressBuffer _11 : register(u0); void comp_main() diff --git a/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/rwbuffer-matrix.comp b/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/rwbuffer-matrix.comp index 42103c2bd4..a6621c9746 100644 --- a/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/rwbuffer-matrix.comp +++ b/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/rwbuffer-matrix.comp @@ -1,3 +1,5 @@ +static const uint3 gl_WorkGroupSize = uint3(1u, 1u, 1u); + RWByteAddressBuffer _28 : register(u0); cbuffer UBO : register(b1) { @@ -8,57 +10,57 @@ cbuffer UBO : register(b1) void comp_main() { - float4x4 _253 = asfloat(uint4x4(_28.Load(64), _28.Load(80), _28.Load(96), _28.Load(112), _28.Load(68), _28.Load(84), _28.Load(100), _28.Load(116), _28.Load(72), _28.Load(88), _28.Load(104), _28.Load(120), _28.Load(76), _28.Load(92), _28.Load(108), _28.Load(124))); - _28.Store4(0, asuint(_253[0])); - _28.Store4(16, asuint(_253[1])); - _28.Store4(32, asuint(_253[2])); - _28.Store4(48, asuint(_253[3])); - float2x2 _256 = asfloat(uint2x2(_28.Load(144), _28.Load(152), _28.Load(148), _28.Load(156))); - _28.Store2(128, asuint(_256[0])); - _28.Store2(136, asuint(_256[1])); - float2x3 _259 = asfloat(uint2x3(_28.Load(192), _28.Load(200), _28.Load(208), _28.Load(196), _28.Load(204), _28.Load(212))); - _28.Store3(160, asuint(_259[0])); - _28.Store3(176, asuint(_259[1])); - float3x2 _262 = asfloat(uint3x2(_28.Load(240), _28.Load(256), _28.Load(244), _28.Load(260), _28.Load(248), _28.Load(264))); - _28.Store2(216, asuint(_262[0])); - _28.Store2(224, asuint(_262[1])); - _28.Store2(232, asuint(_262[2])); - float4x4 _265 = asfloat(uint4x4(_28.Load4(0), _28.Load4(16), _28.Load4(32), _28.Load4(48))); - _28.Store(64, asuint(_265[0].x)); - _28.Store(68, asuint(_265[1].x)); - _28.Store(72, asuint(_265[2].x)); - _28.Store(76, asuint(_265[3].x)); - _28.Store(80, asuint(_265[0].y)); - _28.Store(84, asuint(_265[1].y)); - _28.Store(88, asuint(_265[2].y)); - _28.Store(92, asuint(_265[3].y)); - _28.Store(96, asuint(_265[0].z)); - _28.Store(100, asuint(_265[1].z)); - _28.Store(104, asuint(_265[2].z)); - _28.Store(108, asuint(_265[3].z)); - _28.Store(112, asuint(_265[0].w)); - _28.Store(116, asuint(_265[1].w)); - _28.Store(120, asuint(_265[2].w)); - _28.Store(124, asuint(_265[3].w)); - float2x2 _268 = asfloat(uint2x2(_28.Load2(128), _28.Load2(136))); - _28.Store(144, asuint(_268[0].x)); - _28.Store(148, asuint(_268[1].x)); - _28.Store(152, asuint(_268[0].y)); - _28.Store(156, asuint(_268[1].y)); - float2x3 _271 = asfloat(uint2x3(_28.Load3(160), _28.Load3(176))); - _28.Store(192, asuint(_271[0].x)); - _28.Store(196, asuint(_271[1].x)); - _28.Store(200, asuint(_271[0].y)); - _28.Store(204, asuint(_271[1].y)); - _28.Store(208, asuint(_271[0].z)); - _28.Store(212, asuint(_271[1].z)); - float3x2 _274 = asfloat(uint3x2(_28.Load2(216), _28.Load2(224), _28.Load2(232))); - _28.Store(240, asuint(_274[0].x)); - _28.Store(244, asuint(_274[1].x)); - _28.Store(248, asuint(_274[2].x)); - _28.Store(256, asuint(_274[0].y)); - _28.Store(260, asuint(_274[1].y)); - _28.Store(264, asuint(_274[2].y)); + float4x4 _257 = asfloat(uint4x4(_28.Load(64), _28.Load(80), _28.Load(96), _28.Load(112), _28.Load(68), _28.Load(84), _28.Load(100), _28.Load(116), _28.Load(72), _28.Load(88), _28.Load(104), _28.Load(120), _28.Load(76), _28.Load(92), _28.Load(108), _28.Load(124))); + _28.Store4(0, asuint(_257[0])); + _28.Store4(16, asuint(_257[1])); + _28.Store4(32, asuint(_257[2])); + _28.Store4(48, asuint(_257[3])); + float2x2 _260 = asfloat(uint2x2(_28.Load(144), _28.Load(152), _28.Load(148), _28.Load(156))); + _28.Store2(128, asuint(_260[0])); + _28.Store2(136, asuint(_260[1])); + float2x3 _263 = asfloat(uint2x3(_28.Load(192), _28.Load(200), _28.Load(208), _28.Load(196), _28.Load(204), _28.Load(212))); + _28.Store3(160, asuint(_263[0])); + _28.Store3(176, asuint(_263[1])); + float3x2 _266 = asfloat(uint3x2(_28.Load(240), _28.Load(256), _28.Load(244), _28.Load(260), _28.Load(248), _28.Load(264))); + _28.Store2(216, asuint(_266[0])); + _28.Store2(224, asuint(_266[1])); + _28.Store2(232, asuint(_266[2])); + float4x4 _269 = asfloat(uint4x4(_28.Load4(0), _28.Load4(16), _28.Load4(32), _28.Load4(48))); + _28.Store(64, asuint(_269[0].x)); + _28.Store(68, asuint(_269[1].x)); + _28.Store(72, asuint(_269[2].x)); + _28.Store(76, asuint(_269[3].x)); + _28.Store(80, asuint(_269[0].y)); + _28.Store(84, asuint(_269[1].y)); + _28.Store(88, asuint(_269[2].y)); + _28.Store(92, asuint(_269[3].y)); + _28.Store(96, asuint(_269[0].z)); + _28.Store(100, asuint(_269[1].z)); + _28.Store(104, asuint(_269[2].z)); + _28.Store(108, asuint(_269[3].z)); + _28.Store(112, asuint(_269[0].w)); + _28.Store(116, asuint(_269[1].w)); + _28.Store(120, asuint(_269[2].w)); + _28.Store(124, asuint(_269[3].w)); + float2x2 _272 = asfloat(uint2x2(_28.Load2(128), _28.Load2(136))); + _28.Store(144, asuint(_272[0].x)); + _28.Store(148, asuint(_272[1].x)); + _28.Store(152, asuint(_272[0].y)); + _28.Store(156, asuint(_272[1].y)); + float2x3 _275 = asfloat(uint2x3(_28.Load3(160), _28.Load3(176))); + _28.Store(192, asuint(_275[0].x)); + _28.Store(196, asuint(_275[1].x)); + _28.Store(200, asuint(_275[0].y)); + _28.Store(204, asuint(_275[1].y)); + _28.Store(208, asuint(_275[0].z)); + _28.Store(212, asuint(_275[1].z)); + float3x2 _278 = asfloat(uint3x2(_28.Load2(216), _28.Load2(224), _28.Load2(232))); + _28.Store(240, asuint(_278[0].x)); + _28.Store(244, asuint(_278[1].x)); + _28.Store(248, asuint(_278[2].x)); + _28.Store(256, asuint(_278[0].y)); + _28.Store(260, asuint(_278[1].y)); + _28.Store(264, asuint(_278[2].y)); _28.Store(_68_index0 * 4 + _68_index1 * 16 + 64, asuint(1.0f)); _28.Store(_68_index0 * 4 + _68_index1 * 8 + 144, asuint(2.0f)); _28.Store(_68_index0 * 4 + _68_index1 * 8 + 192, asuint(3.0f)); diff --git a/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/scalar-std450-distance-length-normalize.comp b/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/scalar-std450-distance-length-normalize.comp index 47f2fe4107..db2bbe9698 100644 --- a/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/scalar-std450-distance-length-normalize.comp +++ b/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/scalar-std450-distance-length-normalize.comp @@ -1,3 +1,5 @@ +static const uint3 gl_WorkGroupSize = uint3(1u, 1u, 1u); + RWByteAddressBuffer _9 : register(u0); void comp_main() diff --git a/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/spec-constant-op-member-array.comp b/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/spec-constant-op-member-array.comp index c4537db039..4e7c5e6167 100644 --- a/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/spec-constant-op-member-array.comp +++ b/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/spec-constant-op-member-array.comp @@ -28,6 +28,7 @@ static const int d = (c + 50); #define SPIRV_CROSS_CONSTANT_ID_3 400 #endif static const int e = SPIRV_CROSS_CONSTANT_ID_3; +static const uint3 gl_WorkGroupSize = uint3(1u, 1u, 1u); RWByteAddressBuffer _22 : register(u0); diff --git a/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/ssbo-array-length.comp b/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/ssbo-array-length.comp index 2e3df626ae..82657cacfc 100644 --- a/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/ssbo-array-length.comp +++ b/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/ssbo-array-length.comp @@ -1,3 +1,5 @@ +static const uint3 gl_WorkGroupSize = uint3(1u, 1u, 1u); + RWByteAddressBuffer _11 : register(u1); void comp_main() diff --git a/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/ssbo-array.comp b/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/ssbo-array.comp index d8bce8d54b..ee202a2225 100644 --- a/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/ssbo-array.comp +++ b/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/ssbo-array.comp @@ -1,3 +1,5 @@ +static const uint3 gl_WorkGroupSize = uint3(1u, 1u, 1u); + void comp_main() { } diff --git a/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/subgroups.invalid.nofxc.sm60.comp b/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/subgroups.invalid.nofxc.sm60.comp deleted file mode 100644 index dabc7df9e2..0000000000 --- a/third_party/spirv-cross/reference/opt/shaders-hlsl/comp/subgroups.invalid.nofxc.sm60.comp +++ /dev/null @@ -1,67 +0,0 @@ -RWByteAddressBuffer _9 : register(u0, space0); - -static uint4 gl_SubgroupEqMask; -static uint4 gl_SubgroupGeMask; -static uint4 gl_SubgroupGtMask; -static uint4 gl_SubgroupLeMask; -static uint4 gl_SubgroupLtMask; -void comp_main() -{ - _9.Store(0, asuint(float(WaveGetLaneCount()))); - _9.Store(0, asuint(float(WaveGetLaneIndex()))); - _9.Store(0, asuint(float4(gl_SubgroupEqMask).x)); - _9.Store(0, asuint(float4(gl_SubgroupGeMask).x)); - _9.Store(0, asuint(float4(gl_SubgroupGtMask).x)); - _9.Store(0, asuint(float4(gl_SubgroupLeMask).x)); - _9.Store(0, asuint(float4(gl_SubgroupLtMask).x)); - uint4 _75 = WaveActiveBallot(true); - float4 _88 = WaveActiveSum(20.0f.xxxx); - int4 _94 = WaveActiveSum(int4(20, 20, 20, 20)); - float4 _96 = WaveActiveProduct(20.0f.xxxx); - int4 _98 = WaveActiveProduct(int4(20, 20, 20, 20)); - float4 _127 = WavePrefixProduct(_96) * _96; - int4 _129 = WavePrefixProduct(_98) * _98; -} - -[numthreads(1, 1, 1)] -void main() -{ - gl_SubgroupEqMask = 1u << (WaveGetLaneIndex() - uint4(0, 32, 64, 96)); - if (WaveGetLaneIndex() >= 32) gl_SubgroupEqMask.x = 0; - if (WaveGetLaneIndex() >= 64 || WaveGetLaneIndex() < 32) gl_SubgroupEqMask.y = 0; - if (WaveGetLaneIndex() >= 96 || WaveGetLaneIndex() < 64) gl_SubgroupEqMask.z = 0; - if (WaveGetLaneIndex() < 96) gl_SubgroupEqMask.w = 0; - gl_SubgroupGeMask = ~((1u << (WaveGetLaneIndex() - uint4(0, 32, 64, 96))) - 1u); - if (WaveGetLaneIndex() >= 32) gl_SubgroupGeMask.x = 0u; - if (WaveGetLaneIndex() >= 64) gl_SubgroupGeMask.y = 0u; - if (WaveGetLaneIndex() >= 96) gl_SubgroupGeMask.z = 0u; - if (WaveGetLaneIndex() < 32) gl_SubgroupGeMask.y = ~0u; - if (WaveGetLaneIndex() < 64) gl_SubgroupGeMask.z = ~0u; - if (WaveGetLaneIndex() < 96) gl_SubgroupGeMask.w = ~0u; - uint gt_lane_index = WaveGetLaneIndex() + 1; - gl_SubgroupGtMask = ~((1u << (gt_lane_index - uint4(0, 32, 64, 96))) - 1u); - if (gt_lane_index >= 32) gl_SubgroupGtMask.x = 0u; - if (gt_lane_index >= 64) gl_SubgroupGtMask.y = 0u; - if (gt_lane_index >= 96) gl_SubgroupGtMask.z = 0u; - if (gt_lane_index >= 128) gl_SubgroupGtMask.w = 0u; - if (gt_lane_index < 32) gl_SubgroupGtMask.y = ~0u; - if (gt_lane_index < 64) gl_SubgroupGtMask.z = ~0u; - if (gt_lane_index < 96) gl_SubgroupGtMask.w = ~0u; - uint le_lane_index = WaveGetLaneIndex() + 1; - gl_SubgroupLeMask = (1u << (le_lane_index - uint4(0, 32, 64, 96))) - 1u; - if (le_lane_index >= 32) gl_SubgroupLeMask.x = ~0u; - if (le_lane_index >= 64) gl_SubgroupLeMask.y = ~0u; - if (le_lane_index >= 96) gl_SubgroupLeMask.z = ~0u; - if (le_lane_index >= 128) gl_SubgroupLeMask.w = ~0u; - if (le_lane_index < 32) gl_SubgroupLeMask.y = 0u; - if (le_lane_index < 64) gl_SubgroupLeMask.z = 0u; - if (le_lane_index < 96) gl_SubgroupLeMask.w = 0u; - gl_SubgroupLtMask = (1u << (WaveGetLaneIndex() - uint4(0, 32, 64, 96))) - 1u; - if (WaveGetLaneIndex() >= 32) gl_SubgroupLtMask.x = ~0u; - if (WaveGetLaneIndex() >= 64) gl_SubgroupLtMask.y = ~0u; - if (WaveGetLaneIndex() >= 96) gl_SubgroupLtMask.z = ~0u; - if (WaveGetLaneIndex() < 32) gl_SubgroupLtMask.y = 0u; - if (WaveGetLaneIndex() < 64) gl_SubgroupLtMask.z = 0u; - if (WaveGetLaneIndex() < 96) gl_SubgroupLtMask.w = 0u; - comp_main(); -} diff --git a/third_party/spirv-cross/reference/opt/shaders-hlsl/frag/bvec-operations.frag b/third_party/spirv-cross/reference/opt/shaders-hlsl/frag/bvec-operations.frag index 6a22df1ed7..2770e97c0a 100644 --- a/third_party/spirv-cross/reference/opt/shaders-hlsl/frag/bvec-operations.frag +++ b/third_party/spirv-cross/reference/opt/shaders-hlsl/frag/bvec-operations.frag @@ -11,7 +11,7 @@ struct SPIRV_Cross_Output float4 FragColor : SV_Target0; }; -bool _47; +static bool _47; void frag_main() { diff --git a/third_party/spirv-cross/reference/opt/shaders-hlsl/frag/fp16.invalid.desktop.frag b/third_party/spirv-cross/reference/opt/shaders-hlsl/frag/fp16.invalid.desktop.frag deleted file mode 100644 index 8ec30af16f..0000000000 --- a/third_party/spirv-cross/reference/opt/shaders-hlsl/frag/fp16.invalid.desktop.frag +++ /dev/null @@ -1,45 +0,0 @@ -static min16float4 v4; -static min16float3 v3; -static min16float v1; -static min16float2 v2; -static float o1; -static float2 o2; -static float3 o3; -static float4 o4; - -struct SPIRV_Cross_Input -{ - min16float v1 : TEXCOORD0; - min16float2 v2 : TEXCOORD1; - min16float3 v3 : TEXCOORD2; - min16float4 v4 : TEXCOORD3; -}; - -struct SPIRV_Cross_Output -{ - float o1 : SV_Target0; - float2 o2 : SV_Target1; - float3 o3 : SV_Target2; - float4 o4 : SV_Target3; -}; - -void frag_main() -{ - min16float4 _324; - min16float4 _387 = modf(v4, _324); -} - -SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input) -{ - v4 = stage_input.v4; - v3 = stage_input.v3; - v1 = stage_input.v1; - v2 = stage_input.v2; - frag_main(); - SPIRV_Cross_Output stage_output; - stage_output.o1 = o1; - stage_output.o2 = o2; - stage_output.o3 = o3; - stage_output.o4 = o4; - return stage_output; -} diff --git a/third_party/spirv-cross/reference/opt/shaders-hlsl/frag/pixel-interlock-ordered.sm51.fxconly.frag b/third_party/spirv-cross/reference/opt/shaders-hlsl/frag/pixel-interlock-ordered.sm51.fxconly.frag new file mode 100644 index 0000000000..8923f96a75 --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders-hlsl/frag/pixel-interlock-ordered.sm51.fxconly.frag @@ -0,0 +1,24 @@ +RWByteAddressBuffer _9 : register(u6, space0); +globallycoherent RasterizerOrderedByteAddressBuffer _42 : register(u3, space0); +RasterizerOrderedByteAddressBuffer _52 : register(u4, space0); +RWTexture2D img4 : register(u5, space0); +RasterizerOrderedTexture2D img : register(u0, space0); +RasterizerOrderedTexture2D img3 : register(u2, space0); +RasterizerOrderedTexture2D img2 : register(u1, space0); + +void frag_main() +{ + _9.Store(0, uint(0)); + img4[int2(1, 1)] = float4(1.0f, 0.0f, 0.0f, 1.0f); + img[int2(0, 0)] = img3[int2(0, 0)]; + uint _39; + InterlockedAdd(img2[int2(0, 0)], 1u, _39); + _42.Store(0, uint(int(_42.Load(0)) + 42)); + uint _55; + _42.InterlockedAnd(4, _52.Load(0), _55); +} + +void main() +{ + frag_main(); +} diff --git a/third_party/spirv-cross/reference/opt/shaders-hlsl/frag/readonly-coherent-ssbo.force-uav.frag b/third_party/spirv-cross/reference/opt/shaders-hlsl/frag/readonly-coherent-ssbo.force-uav.frag new file mode 100644 index 0000000000..bbe3e4a7d3 --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders-hlsl/frag/readonly-coherent-ssbo.force-uav.frag @@ -0,0 +1,21 @@ +globallycoherent RWByteAddressBuffer _12 : register(u0); + +static float4 FragColor; + +struct SPIRV_Cross_Output +{ + float4 FragColor : SV_Target0; +}; + +void frag_main() +{ + FragColor = asfloat(_12.Load4(0)); +} + +SPIRV_Cross_Output main() +{ + frag_main(); + SPIRV_Cross_Output stage_output; + stage_output.FragColor = FragColor; + return stage_output; +} diff --git a/third_party/spirv-cross/reference/opt/shaders-hlsl/frag/readonly-coherent-ssbo.frag b/third_party/spirv-cross/reference/opt/shaders-hlsl/frag/readonly-coherent-ssbo.frag new file mode 100644 index 0000000000..02252f9cbc --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders-hlsl/frag/readonly-coherent-ssbo.frag @@ -0,0 +1,21 @@ +ByteAddressBuffer _12 : register(t0); + +static float4 FragColor; + +struct SPIRV_Cross_Output +{ + float4 FragColor : SV_Target0; +}; + +void frag_main() +{ + FragColor = asfloat(_12.Load4(0)); +} + +SPIRV_Cross_Output main() +{ + frag_main(); + SPIRV_Cross_Output stage_output; + stage_output.FragColor = FragColor; + return stage_output; +} diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/asm/comp/atomic-decrement.asm.comp b/third_party/spirv-cross/reference/opt/shaders-msl/asm/comp/atomic-decrement.asm.comp index 04d92a346d..3dc6fffcf8 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/asm/comp/atomic-decrement.asm.comp +++ b/third_party/spirv-cross/reference/opt/shaders-msl/asm/comp/atomic-decrement.asm.comp @@ -13,6 +13,7 @@ struct u0_counters }; // Returns 2D texture coords corresponding to 1D texel buffer coords +static inline __attribute__((always_inline)) uint2 spvTexelBufferCoord(uint tc) { return uint2(tc % 4096, tc / 4096); diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/asm/comp/atomic-increment.asm.comp b/third_party/spirv-cross/reference/opt/shaders-msl/asm/comp/atomic-increment.asm.comp index b0fd1d4f38..6f42bb9d2b 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/asm/comp/atomic-increment.asm.comp +++ b/third_party/spirv-cross/reference/opt/shaders-msl/asm/comp/atomic-increment.asm.comp @@ -13,6 +13,7 @@ struct u0_counters }; // Returns 2D texture coords corresponding to 1D texel buffer coords +static inline __attribute__((always_inline)) uint2 spvTexelBufferCoord(uint tc) { return uint2(tc % 4096, tc / 4096); diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/asm/comp/bitcast_icmp.asm.comp b/third_party/spirv-cross/reference/opt/shaders-msl/asm/comp/bitcast_icmp.asm.comp new file mode 100644 index 0000000000..31c71daa4b --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders-msl/asm/comp/bitcast_icmp.asm.comp @@ -0,0 +1,29 @@ +#include +#include + +using namespace metal; + +struct _3 +{ + int4 _m0; + uint4 _m1; +}; + +struct _4 +{ + uint4 _m0; + int4 _m1; +}; + +kernel void main0(device _3& restrict _5 [[buffer(0)]], device _4& restrict _6 [[buffer(1)]]) +{ + _6._m0 = select(uint4(0u), uint4(1u), int4(_5._m1) < _5._m0); + _6._m0 = select(uint4(0u), uint4(1u), int4(_5._m1) <= _5._m0); + _6._m0 = select(uint4(0u), uint4(1u), _5._m1 < uint4(_5._m0)); + _6._m0 = select(uint4(0u), uint4(1u), _5._m1 <= uint4(_5._m0)); + _6._m0 = select(uint4(0u), uint4(1u), int4(_5._m1) > _5._m0); + _6._m0 = select(uint4(0u), uint4(1u), int4(_5._m1) >= _5._m0); + _6._m0 = select(uint4(0u), uint4(1u), _5._m1 > uint4(_5._m0)); + _6._m0 = select(uint4(0u), uint4(1u), _5._m1 >= uint4(_5._m0)); +} + diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/asm/comp/buffer-write-relative-addr.asm.comp b/third_party/spirv-cross/reference/opt/shaders-msl/asm/comp/buffer-write-relative-addr.asm.comp index fa2b5fe53a..bb51fd7b1c 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/asm/comp/buffer-write-relative-addr.asm.comp +++ b/third_party/spirv-cross/reference/opt/shaders-msl/asm/comp/buffer-write-relative-addr.asm.comp @@ -11,6 +11,7 @@ struct cb5_struct }; // Returns 2D texture coords corresponding to 1D texel buffer coords +static inline __attribute__((always_inline)) uint2 spvTexelBufferCoord(uint tc) { return uint2(tc % 4096, tc / 4096); diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/asm/comp/buffer-write.asm.comp b/third_party/spirv-cross/reference/opt/shaders-msl/asm/comp/buffer-write.asm.comp index 159d09b38c..8c9e23aa06 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/asm/comp/buffer-write.asm.comp +++ b/third_party/spirv-cross/reference/opt/shaders-msl/asm/comp/buffer-write.asm.comp @@ -11,6 +11,7 @@ struct cb }; // Returns 2D texture coords corresponding to 1D texel buffer coords +static inline __attribute__((always_inline)) uint2 spvTexelBufferCoord(uint tc) { return uint2(tc % 4096, tc / 4096); diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/asm/frag/line-directive.line.asm.frag b/third_party/spirv-cross/reference/opt/shaders-msl/asm/frag/line-directive.line.asm.frag index 30018aad4c..0d9666d668 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/asm/frag/line-directive.line.asm.frag +++ b/third_party/spirv-cross/reference/opt/shaders-msl/asm/frag/line-directive.line.asm.frag @@ -17,14 +17,12 @@ struct main0_in fragment main0_out main0(main0_in in [[stage_in]]) { main0_out out = {}; - float _80; #line 8 "test.frag" out.FragColor = 1.0; #line 9 "test.frag" out.FragColor = 2.0; #line 10 "test.frag" - _80 = in.vColor; - if (_80 < 0.0) + if (in.vColor < 0.0) { #line 12 "test.frag" out.FragColor = 3.0; @@ -34,16 +32,16 @@ fragment main0_out main0(main0_in in [[stage_in]]) #line 16 "test.frag" out.FragColor = 4.0; } - for (int _126 = 0; float(_126) < (40.0 + _80); ) + for (int _126 = 0; float(_126) < (40.0 + in.vColor); ) { #line 21 "test.frag" out.FragColor += 0.20000000298023223876953125; #line 22 "test.frag" out.FragColor += 0.300000011920928955078125; - _126 += (int(_80) + 5); + _126 += (int(in.vColor) + 5); continue; } - switch (int(_80)) + switch (int(in.vColor)) { case 0: { @@ -69,7 +67,7 @@ fragment main0_out main0(main0_in in [[stage_in]]) } for (;;) { - out.FragColor += (10.0 + _80); + out.FragColor += (10.0 + in.vColor); #line 43 "test.frag" if (out.FragColor < 100.0) { diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/asm/frag/lut-promotion-initializer.asm.frag b/third_party/spirv-cross/reference/opt/shaders-msl/asm/frag/lut-promotion-initializer.asm.frag index 610d447a8d..726976631a 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/asm/frag/lut-promotion-initializer.asm.frag +++ b/third_party/spirv-cross/reference/opt/shaders-msl/asm/frag/lut-promotion-initializer.asm.frag @@ -1,13 +1,52 @@ #pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" #include #include using namespace metal; -constant float _46[16] = { 1.0, 2.0, 3.0, 4.0, 1.0, 2.0, 3.0, 4.0, 1.0, 2.0, 3.0, 4.0, 1.0, 2.0, 3.0, 4.0 }; -constant float4 _76[4] = { float4(0.0), float4(1.0), float4(8.0), float4(5.0) }; -constant float4 _90[4] = { float4(20.0), float4(30.0), float4(50.0), float4(60.0) }; +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +constant spvUnsafeArray _46 = spvUnsafeArray({ 1.0, 2.0, 3.0, 4.0, 1.0, 2.0, 3.0, 4.0, 1.0, 2.0, 3.0, 4.0, 1.0, 2.0, 3.0, 4.0 }); +constant spvUnsafeArray _76 = spvUnsafeArray({ float4(0.0), float4(1.0), float4(8.0), float4(5.0) }); +constant spvUnsafeArray _90 = spvUnsafeArray({ float4(20.0), float4(30.0), float4(50.0), float4(60.0) }); struct main0_out { @@ -19,23 +58,10 @@ struct main0_in int index [[user(locn0)]]; }; -// Implementation of an array copy function to cover GLSL's ability to copy an array via assignment. -template -void spvArrayCopyFromStack1(thread T (&dst)[N], thread const T (&src)[N]) -{ - for (uint i = 0; i < N; dst[i] = src[i], i++); -} - -template -void spvArrayCopyFromConstant1(thread T (&dst)[N], constant T (&src)[N]) -{ - for (uint i = 0; i < N; dst[i] = src[i], i++); -} - fragment main0_out main0(main0_in in [[stage_in]]) { - float4 foobar[4] = { float4(0.0), float4(1.0), float4(8.0), float4(5.0) }; - float4 baz[4] = { float4(0.0), float4(1.0), float4(8.0), float4(5.0) }; + spvUnsafeArray foobar = spvUnsafeArray({ float4(0.0), float4(1.0), float4(8.0), float4(5.0) }); + spvUnsafeArray baz = spvUnsafeArray({ float4(0.0), float4(1.0), float4(8.0), float4(5.0) }); main0_out out = {}; out.FragColor = _46[in.index]; if (in.index < 10) @@ -61,7 +87,7 @@ fragment main0_out main0(main0_in in [[stage_in]]) } int _37 = in.index & 3; out.FragColor += foobar[_37].z; - spvArrayCopyFromConstant1(baz, _90); + baz = _90; out.FragColor += baz[_37].z; return out; } diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/asm/frag/min-max-clamp.invalid.asm.frag b/third_party/spirv-cross/reference/opt/shaders-msl/asm/frag/min-max-clamp.invalid.asm.frag deleted file mode 100644 index 92ac1d9f83..0000000000 --- a/third_party/spirv-cross/reference/opt/shaders-msl/asm/frag/min-max-clamp.invalid.asm.frag +++ /dev/null @@ -1,9 +0,0 @@ -#include -#include - -using namespace metal; - -fragment void main0() -{ -} - diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/asm/frag/single-function-private-lut.asm.frag b/third_party/spirv-cross/reference/opt/shaders-msl/asm/frag/single-function-private-lut.asm.frag index 4081c3d89a..4c0ea901dd 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/asm/frag/single-function-private-lut.asm.frag +++ b/third_party/spirv-cross/reference/opt/shaders-msl/asm/frag/single-function-private-lut.asm.frag @@ -1,17 +1,54 @@ #pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" #include #include using namespace metal; +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + struct myType { float data; }; -constant myType _21[5] = { myType{ 0.0 }, myType{ 1.0 }, myType{ 0.0 }, myType{ 1.0 }, myType{ 0.0 } }; - struct main0_out { float4 o_color [[color(0)]]; @@ -19,13 +56,15 @@ struct main0_out // Implementation of the GLSL mod() function, which is slightly different than Metal fmod() template -Tx mod(Tx x, Ty y) +inline Tx mod(Tx x, Ty y) { return x - y * floor(x / y); } fragment main0_out main0(float4 gl_FragCoord [[position]]) { + spvUnsafeArray _21 = spvUnsafeArray({ myType{ 0.0 }, myType{ 1.0 }, myType{ 0.0 }, myType{ 1.0 }, myType{ 0.0 } }); + main0_out out = {}; if (_21[int(mod(gl_FragCoord.x, 4.0))].data > 0.0) { diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/asm/frag/storage-class-output-initializer.asm.frag b/third_party/spirv-cross/reference/opt/shaders-msl/asm/frag/storage-class-output-initializer.asm.frag index 1bafc6953b..d59013daaf 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/asm/frag/storage-class-output-initializer.asm.frag +++ b/third_party/spirv-cross/reference/opt/shaders-msl/asm/frag/storage-class-output-initializer.asm.frag @@ -1,9 +1,50 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + #include #include using namespace metal; -constant float4 _20[2] = { float4(1.0, 2.0, 3.0, 4.0), float4(10.0) }; +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +constant spvUnsafeArray _20 = spvUnsafeArray({ float4(1.0, 2.0, 3.0, 4.0), float4(10.0) }); struct main0_out { @@ -15,7 +56,7 @@ struct main0_out fragment main0_out main0() { main0_out out = {}; - float4 FragColors[2] = { float4(1.0, 2.0, 3.0, 4.0), float4(10.0) }; + spvUnsafeArray FragColors = spvUnsafeArray({ float4(1.0, 2.0, 3.0, 4.0), float4(10.0) }); out.FragColor = float4(5.0); out.FragColors_0 = FragColors[0]; out.FragColors_1 = FragColors[1]; diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/asm/frag/texture-atomics.asm.frag b/third_party/spirv-cross/reference/opt/shaders-msl/asm/frag/texture-atomics.asm.frag new file mode 100644 index 0000000000..ab5be64984 --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders-msl/asm/frag/texture-atomics.asm.frag @@ -0,0 +1,121 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" +#pragma clang diagnostic ignored "-Wunused-variable" + +#include +#include +#include + +using namespace metal; + +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +struct type_StructuredBuffer_v4float +{ + spvUnsafeArray _m0; +}; + +struct type_Globals +{ + uint2 ShadowTileListGroupSize; +}; + +constant float3 _70 = {}; + +struct main0_out +{ + float4 out_var_SV_Target0 [[color(0)]]; +}; + +struct main0_in +{ + uint in_var_TEXCOORD0 [[user(locn0)]]; +}; + +fragment main0_out main0(main0_in in [[stage_in]], const device type_StructuredBuffer_v4float& CulledObjectBoxBounds [[buffer(0)]], constant type_Globals& _Globals [[buffer(1)]], texture2d RWShadowTileNumCulledObjects [[texture(2)]], device atomic_uint* RWShadowTileNumCulledObjects_atomic [[buffer(2)]], float4 gl_FragCoord [[position]]) +{ + main0_out out = {}; + uint2 _77 = uint2(gl_FragCoord.xy); + uint _78 = _77.y; + uint _83 = _77.x; + float2 _91 = float2(float(_83), float((_Globals.ShadowTileListGroupSize.y - 1u) - _78)); + float2 _93 = float2(_Globals.ShadowTileListGroupSize); + float2 _96 = ((_91 / _93) * float2(2.0)) - float2(1.0); + float2 _100 = (((_91 + float2(1.0)) / _93) * float2(2.0)) - float2(1.0); + float3 _102 = float3(_100.x, _100.y, _70.z); + _102.z = 1.0; + uint _103 = in.in_var_TEXCOORD0 * 5u; + uint _107 = _103 + 1u; + if (all(CulledObjectBoxBounds._m0[_107].xy > _96.xy) && all(CulledObjectBoxBounds._m0[_103].xyz < _102)) + { + float _122 = _96.x; + float _123 = _96.y; + spvUnsafeArray _73; + _73[0] = float3(_122, _123, -1000.0); + float _126 = _100.x; + _73[1] = float3(_126, _123, -1000.0); + float _129 = _100.y; + _73[2] = float3(_122, _129, -1000.0); + _73[3] = float3(_126, _129, -1000.0); + _73[4] = float3(_122, _123, 1.0); + _73[5] = float3(_126, _123, 1.0); + _73[6] = float3(_122, _129, 1.0); + _73[7] = float3(_126, _129, 1.0); + float3 _155; + float3 _158; + _155 = float3(-500000.0); + _158 = float3(500000.0); + for (int _160 = 0; _160 < 8; ) + { + float3 _166 = _73[_160] - (float3(0.5) * (CulledObjectBoxBounds._m0[_103].xyz + CulledObjectBoxBounds._m0[_107].xyz)); + float3 _170 = float3(dot(_166, CulledObjectBoxBounds._m0[_103 + 2u].xyz), dot(_166, CulledObjectBoxBounds._m0[_103 + 3u].xyz), dot(_166, CulledObjectBoxBounds._m0[_103 + 4u].xyz)); + _155 = fast::max(_155, _170); + _158 = fast::min(_158, _170); + _160++; + continue; + } + if (all(_158 < float3(1.0)) && all(_155 > float3(-1.0))) + { + uint _179 = atomic_fetch_add_explicit((device atomic_uint*)&RWShadowTileNumCulledObjects_atomic[(_78 * _Globals.ShadowTileListGroupSize.x) + _83], 1u, memory_order_relaxed); + } + } + out.out_var_SV_Target0 = float4(0.0); + return out; +} + diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/asm/frag/texture-atomics.asm.graphics-robust-access.frag b/third_party/spirv-cross/reference/opt/shaders-msl/asm/frag/texture-atomics.asm.graphics-robust-access.frag new file mode 100644 index 0000000000..ca5e3eadb7 --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders-msl/asm/frag/texture-atomics.asm.graphics-robust-access.frag @@ -0,0 +1,122 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" +#pragma clang diagnostic ignored "-Wunused-variable" + +#include +#include +#include + +using namespace metal; + +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +struct type_StructuredBuffer_v4float +{ + spvUnsafeArray _m0; +}; + +struct type_Globals +{ + uint2 ShadowTileListGroupSize; +}; + +constant float3 _70 = {}; + +struct main0_out +{ + float4 out_var_SV_Target0 [[color(0)]]; +}; + +struct main0_in +{ + uint in_var_TEXCOORD0 [[user(locn0)]]; +}; + +fragment main0_out main0(main0_in in [[stage_in]], constant uint* spvBufferSizeConstants [[buffer(25)]], const device type_StructuredBuffer_v4float& CulledObjectBoxBounds [[buffer(0)]], constant type_Globals& _Globals [[buffer(1)]], texture2d RWShadowTileNumCulledObjects [[texture(2)]], device atomic_uint* RWShadowTileNumCulledObjects_atomic [[buffer(2)]], float4 gl_FragCoord [[position]]) +{ + main0_out out = {}; + constant uint& CulledObjectBoxBoundsBufferSize = spvBufferSizeConstants[0]; + uint2 _77 = uint2(gl_FragCoord.xy); + uint _78 = _77.y; + uint _83 = _77.x; + float2 _91 = float2(float(_83), float((_Globals.ShadowTileListGroupSize.y - 1u) - _78)); + float2 _93 = float2(_Globals.ShadowTileListGroupSize); + float2 _96 = ((_91 / _93) * float2(2.0)) - float2(1.0); + float2 _100 = (((_91 + float2(1.0)) / _93) * float2(2.0)) - float2(1.0); + float3 _102 = float3(_100.x, _100.y, _70.z); + _102.z = 1.0; + uint _103 = in.in_var_TEXCOORD0 * 5u; + uint _186 = clamp(_103 + 1u, 0u, ((CulledObjectBoxBoundsBufferSize - 0) / 16) - 1u); + if (all(CulledObjectBoxBounds._m0[_186].xy > _96.xy) && all(CulledObjectBoxBounds._m0[clamp(_103, 0u, ((CulledObjectBoxBoundsBufferSize - 0) / 16) - 1u)].xyz < _102)) + { + float _122 = _96.x; + float _123 = _96.y; + spvUnsafeArray _73; + _73[0] = float3(_122, _123, -1000.0); + float _126 = _100.x; + _73[1] = float3(_126, _123, -1000.0); + float _129 = _100.y; + _73[2] = float3(_122, _129, -1000.0); + _73[3] = float3(_126, _129, -1000.0); + _73[4] = float3(_122, _123, 1.0); + _73[5] = float3(_126, _123, 1.0); + _73[6] = float3(_122, _129, 1.0); + _73[7] = float3(_126, _129, 1.0); + float3 _155; + float3 _158; + _155 = float3(-500000.0); + _158 = float3(500000.0); + for (int _160 = 0; _160 < 8; ) + { + float3 _166 = _73[int(clamp(uint(_160), uint(0), uint(7)))] - (float3(0.5) * (CulledObjectBoxBounds._m0[clamp(_103, 0u, ((CulledObjectBoxBoundsBufferSize - 0) / 16) - 1u)].xyz + CulledObjectBoxBounds._m0[_186].xyz)); + float3 _170 = float3(dot(_166, CulledObjectBoxBounds._m0[clamp(_103 + 2u, 0u, ((CulledObjectBoxBoundsBufferSize - 0) / 16) - 1u)].xyz), dot(_166, CulledObjectBoxBounds._m0[clamp(_103 + 3u, 0u, ((CulledObjectBoxBoundsBufferSize - 0) / 16) - 1u)].xyz), dot(_166, CulledObjectBoxBounds._m0[clamp(_103 + 4u, 0u, ((CulledObjectBoxBoundsBufferSize - 0) / 16) - 1u)].xyz)); + _155 = fast::max(_155, _170); + _158 = fast::min(_158, _170); + _160++; + continue; + } + if (all(_158 < float3(1.0)) && all(_155 > float3(-1.0))) + { + uint _179 = atomic_fetch_add_explicit((device atomic_uint*)&RWShadowTileNumCulledObjects_atomic[(_78 * _Globals.ShadowTileListGroupSize.x) + _83], 1u, memory_order_relaxed); + } + } + out.out_var_SV_Target0 = float4(0.0); + return out; +} + diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/asm/tesc/tess-fixed-input-array-builtin-array.invalid.asm.tesc b/third_party/spirv-cross/reference/opt/shaders-msl/asm/tesc/tess-fixed-input-array-builtin-array.invalid.asm.tesc deleted file mode 100644 index bbda7be5bd..0000000000 --- a/third_party/spirv-cross/reference/opt/shaders-msl/asm/tesc/tess-fixed-input-array-builtin-array.invalid.asm.tesc +++ /dev/null @@ -1,73 +0,0 @@ -#pragma clang diagnostic ignored "-Wmissing-prototypes" - -#include -#include - -using namespace metal; - -struct VertexOutput -{ - float4 pos; - float2 uv; -}; - -struct VertexOutput_1 -{ - float2 uv; -}; - -struct HSOut -{ - float2 uv; -}; - -struct main0_out -{ - HSOut _entryPointOutput; - float4 gl_Position; -}; - -struct main0_in -{ - float2 VertexOutput_uv [[attribute(0)]]; - float4 gl_Position [[attribute(1)]]; -}; - -// Implementation of an array copy function to cover GLSL's ability to copy an array via assignment. -template -void spvArrayCopyFromStack1(thread T (&dst)[N], thread const T (&src)[N]) -{ - for (uint i = 0; i < N; dst[i] = src[i], i++); -} - -template -void spvArrayCopyFromConstant1(thread T (&dst)[N], constant T (&src)[N]) -{ - for (uint i = 0; i < N; dst[i] = src[i], i++); -} - -kernel void main0(main0_in in [[stage_in]], uint gl_InvocationID [[thread_index_in_threadgroup]], uint gl_PrimitiveID [[threadgroup_position_in_grid]], device main0_out* spvOut [[buffer(28)]], constant uint* spvIndirectParams [[buffer(29)]], device MTLTriangleTessellationFactorsHalf* spvTessLevel [[buffer(26)]], threadgroup main0_in* gl_in [[threadgroup(0)]]) -{ - device main0_out* gl_out = &spvOut[gl_PrimitiveID * 3]; - if (gl_InvocationID < spvIndirectParams[0]) - gl_in[gl_InvocationID] = in; - threadgroup_barrier(mem_flags::mem_threadgroup); - if (gl_InvocationID >= 3) - return; - VertexOutput _223[3] = { VertexOutput{ gl_in[0].gl_Position, gl_in[0].VertexOutput_uv }, VertexOutput{ gl_in[1].gl_Position, gl_in[1].VertexOutput_uv }, VertexOutput{ gl_in[2].gl_Position, gl_in[2].VertexOutput_uv } }; - VertexOutput param[3]; - spvArrayCopyFromStack1(param, _223); - gl_out[gl_InvocationID].gl_Position = param[gl_InvocationID].pos; - gl_out[gl_InvocationID]._entryPointOutput.uv = param[gl_InvocationID].uv; - threadgroup_barrier(mem_flags::mem_device); - if (int(gl_InvocationID) == 0) - { - float2 _174 = float2(1.0) + gl_in[0].VertexOutput_uv; - float _175 = _174.x; - spvTessLevel[gl_PrimitiveID].edgeTessellationFactor[0] = half(_175); - spvTessLevel[gl_PrimitiveID].edgeTessellationFactor[1] = half(_175); - spvTessLevel[gl_PrimitiveID].edgeTessellationFactor[2] = half(_175); - spvTessLevel[gl_PrimitiveID].insideTessellationFactor = half(_175); - } -} - diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/asm/vert/clip-distance-plain-variable.asm.vert b/third_party/spirv-cross/reference/opt/shaders-msl/asm/vert/clip-distance-plain-variable.asm.vert new file mode 100644 index 0000000000..1528c8350d --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders-msl/asm/vert/clip-distance-plain-variable.asm.vert @@ -0,0 +1,29 @@ +#include +#include + +using namespace metal; + +struct main0_out +{ + float4 gl_Position [[position]]; + float gl_ClipDistance [[clip_distance]] [2]; + float gl_ClipDistance_0 [[user(clip0)]]; + float gl_ClipDistance_1 [[user(clip1)]]; +}; + +struct main0_in +{ + float4 pos [[attribute(0)]]; +}; + +vertex main0_out main0(main0_in in [[stage_in]]) +{ + main0_out out = {}; + out.gl_Position = in.pos; + out.gl_ClipDistance[0] = in.pos.x; + out.gl_ClipDistance[1] = in.pos.y; + out.gl_ClipDistance_0 = out.gl_ClipDistance[0]; + out.gl_ClipDistance_1 = out.gl_ClipDistance[1]; + return out; +} + diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/comp/access-private-workgroup-in-function.comp b/third_party/spirv-cross/reference/opt/shaders-msl/comp/access-private-workgroup-in-function.comp index 59fc03a752..e57b2ea171 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/comp/access-private-workgroup-in-function.comp +++ b/third_party/spirv-cross/reference/opt/shaders-msl/comp/access-private-workgroup-in-function.comp @@ -3,6 +3,8 @@ using namespace metal; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + kernel void main0() { } diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/comp/argument-buffers-discrete.msl2.argument.discrete.comp b/third_party/spirv-cross/reference/opt/shaders-msl/comp/argument-buffers-discrete.msl2.argument.discrete.comp index f7757cd19f..18cfd68c19 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/comp/argument-buffers-discrete.msl2.argument.discrete.comp +++ b/third_party/spirv-cross/reference/opt/shaders-msl/comp/argument-buffers-discrete.msl2.argument.discrete.comp @@ -23,6 +23,8 @@ struct SSBO2 float4 v; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + struct spvDescriptorSetBuffer0 { const device SSBO0* ssbo0 [[id(0)]]; diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/comp/argument-buffers-image-load-store.ios.msl2.argument.comp b/third_party/spirv-cross/reference/opt/shaders-msl/comp/argument-buffers-image-load-store.ios.msl2.argument.comp new file mode 100644 index 0000000000..25a0233aec --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders-msl/comp/argument-buffers-image-load-store.ios.msl2.argument.comp @@ -0,0 +1,11 @@ +#include +#include + +using namespace metal; + +kernel void main0(texture2d uImage [[texture(0)]], texture2d uImageRead [[texture(1)]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]]) +{ + int2 _17 = int2(gl_GlobalInvocationID.xy); + uImage.write(uImageRead.read(uint2(_17)), uint2(_17)); +} + diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/comp/array-length.comp b/third_party/spirv-cross/reference/opt/shaders-msl/comp/array-length.comp index 79358eb90e..5a284b9666 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/comp/array-length.comp +++ b/third_party/spirv-cross/reference/opt/shaders-msl/comp/array-length.comp @@ -14,6 +14,8 @@ struct SSBO1 float bz[1]; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + kernel void main0(constant uint* spvBufferSizeConstants [[buffer(25)]], device SSBO& _14 [[buffer(0)]], device SSBO1* ssbos_0 [[buffer(1)]], device SSBO1* ssbos_1 [[buffer(2)]]) { device SSBO1* ssbos[] = diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/comp/array-length.msl2.argument.discrete.comp b/third_party/spirv-cross/reference/opt/shaders-msl/comp/array-length.msl2.argument.discrete.comp index 6ec9b11bbe..d804e18767 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/comp/array-length.msl2.argument.discrete.comp +++ b/third_party/spirv-cross/reference/opt/shaders-msl/comp/array-length.msl2.argument.discrete.comp @@ -25,6 +25,8 @@ struct SSBO3 float bz[1]; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + struct spvDescriptorSetBuffer0 { device SSBO* m_16 [[id(0)]]; diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/comp/atomic.comp b/third_party/spirv-cross/reference/opt/shaders-msl/comp/atomic.comp index 047215022a..fca72bfcfe 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/comp/atomic.comp +++ b/third_party/spirv-cross/reference/opt/shaders-msl/comp/atomic.comp @@ -12,6 +12,8 @@ struct SSBO int i32; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + kernel void main0(device SSBO& ssbo [[buffer(0)]]) { threadgroup uint shared_u32; diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/comp/basic.comp b/third_party/spirv-cross/reference/opt/shaders-msl/comp/basic.comp index e37d4fc593..dbb839f581 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/comp/basic.comp +++ b/third_party/spirv-cross/reference/opt/shaders-msl/comp/basic.comp @@ -21,6 +21,8 @@ struct SSBO3 uint counter; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + kernel void main0(const device SSBO& _23 [[buffer(0)]], device SSBO2& _45 [[buffer(1)]], device SSBO3& _48 [[buffer(2)]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]]) { float4 _29 = _23.in_data[gl_GlobalInvocationID.x]; diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/comp/basic.dispatchbase.comp b/third_party/spirv-cross/reference/opt/shaders-msl/comp/basic.dispatchbase.comp new file mode 100644 index 0000000000..ebbc144c7b --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders-msl/comp/basic.dispatchbase.comp @@ -0,0 +1,38 @@ +#pragma clang diagnostic ignored "-Wunused-variable" + +#include +#include +#include + +using namespace metal; + +struct SSBO +{ + float4 in_data[1]; +}; + +struct SSBO2 +{ + float4 out_data[1]; +}; + +struct SSBO3 +{ + uint counter; +}; + +constant uint _59_tmp [[function_constant(10)]]; +constant uint _59 = is_function_constant_defined(_59_tmp) ? _59_tmp : 1u; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(_59, 1u, 1u); + +kernel void main0(const device SSBO& _27 [[buffer(0)]], device SSBO2& _49 [[buffer(1)]], device SSBO3& _52 [[buffer(2)]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]], uint3 spvDispatchBase [[grid_origin]]) +{ + gl_GlobalInvocationID += spvDispatchBase * gl_WorkGroupSize; + float4 _33 = _27.in_data[gl_GlobalInvocationID.x]; + if (dot(_33, float4(1.0, 5.0, 6.0, 2.0)) > 8.19999980926513671875) + { + uint _56 = atomic_fetch_add_explicit((device atomic_uint*)&_52.counter, 1u, memory_order_relaxed); + _49.out_data[_56] = _33; + } +} + diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/comp/basic.dispatchbase.msl11.comp b/third_party/spirv-cross/reference/opt/shaders-msl/comp/basic.dispatchbase.msl11.comp new file mode 100644 index 0000000000..2d991f5db5 --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders-msl/comp/basic.dispatchbase.msl11.comp @@ -0,0 +1,36 @@ +#pragma clang diagnostic ignored "-Wunused-variable" + +#include +#include +#include + +using namespace metal; + +struct SSBO +{ + float4 in_data[1]; +}; + +struct SSBO2 +{ + float4 out_data[1]; +}; + +struct SSBO3 +{ + uint counter; +}; + +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + +kernel void main0(constant uint3& spvDispatchBase [[buffer(29)]], const device SSBO& _27 [[buffer(0)]], device SSBO2& _49 [[buffer(1)]], device SSBO3& _52 [[buffer(2)]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]]) +{ + gl_GlobalInvocationID += spvDispatchBase * gl_WorkGroupSize; + float4 _33 = _27.in_data[gl_GlobalInvocationID.x]; + if (dot(_33, float4(1.0, 5.0, 6.0, 2.0)) > 8.19999980926513671875) + { + uint _56 = atomic_fetch_add_explicit((device atomic_uint*)&_52.counter, 1u, memory_order_relaxed); + _49.out_data[_56] = _33; + } +} + diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/comp/basic.inline-block.msl2.comp b/third_party/spirv-cross/reference/opt/shaders-msl/comp/basic.inline-block.msl2.comp new file mode 100644 index 0000000000..902dfc92d9 --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders-msl/comp/basic.inline-block.msl2.comp @@ -0,0 +1,53 @@ +#include +#include + +using namespace metal; + +typedef packed_float4 packed_float4x4[4]; + +struct Baz +{ + int f; + int g; +}; + +struct X +{ + int x; + int y; + float z; +}; + +struct Foo +{ + int a; + int b; + packed_float4x4 c; + X x[2]; +}; + +struct Bar +{ + int d; + int e; +}; + +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(3u, 3u, 2u); + +struct spvDescriptorSetBuffer0 +{ + constant Bar* m_38 [[id(0)]]; + Foo m_32 [[id(1)]]; +}; + +struct spvDescriptorSetBuffer1 +{ + device Baz* baz [[id(0)]][3]; +}; + +kernel void main0(constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]], constant spvDescriptorSetBuffer1& spvDescriptorSet1 [[buffer(1)]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]]) +{ + spvDescriptorSet1.baz[gl_GlobalInvocationID.x]->f = spvDescriptorSet0.m_32.a + (*spvDescriptorSet0.m_38).d; + spvDescriptorSet1.baz[gl_GlobalInvocationID.x]->g = spvDescriptorSet0.m_32.b * (*spvDescriptorSet0.m_38).e; +} + diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/comp/bitcast-16bit-1.invalid.comp b/third_party/spirv-cross/reference/opt/shaders-msl/comp/bitcast-16bit-1.invalid.comp deleted file mode 100644 index ad9733a8b5..0000000000 --- a/third_party/spirv-cross/reference/opt/shaders-msl/comp/bitcast-16bit-1.invalid.comp +++ /dev/null @@ -1,22 +0,0 @@ -#include -#include - -using namespace metal; - -struct SSBO0 -{ - short4 inputs[1]; -}; - -struct SSBO1 -{ - int4 outputs[1]; -}; - -kernel void main0(device SSBO0& _25 [[buffer(0)]], device SSBO1& _39 [[buffer(1)]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]]) -{ - _39.outputs[gl_GlobalInvocationID.x].x = int(as_type(as_type(_25.inputs[gl_GlobalInvocationID.x].xy) + half2(half(1.0)))); - _39.outputs[gl_GlobalInvocationID.x].y = as_type(_25.inputs[gl_GlobalInvocationID.x].zw); - _39.outputs[gl_GlobalInvocationID.x].z = int(as_type(ushort2(_25.inputs[gl_GlobalInvocationID.x].xy))); -} - diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/comp/bitcast-16bit-2.invalid.comp b/third_party/spirv-cross/reference/opt/shaders-msl/comp/bitcast-16bit-2.invalid.comp deleted file mode 100644 index a4230b1eb6..0000000000 --- a/third_party/spirv-cross/reference/opt/shaders-msl/comp/bitcast-16bit-2.invalid.comp +++ /dev/null @@ -1,28 +0,0 @@ -#include -#include - -using namespace metal; - -struct SSBO1 -{ - short4 outputs[1]; -}; - -struct SSBO0 -{ - int4 inputs[1]; -}; - -struct UBO -{ - half4 const0; -}; - -kernel void main0(device SSBO1& _21 [[buffer(0)]], device SSBO0& _29 [[buffer(1)]], constant UBO& _40 [[buffer(2)]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]]) -{ - short2 _47 = as_type(_29.inputs[gl_GlobalInvocationID.x].x) + as_type(_40.const0.xy); - _21.outputs[gl_GlobalInvocationID.x] = short4(_47.x, _47.y, _21.outputs[gl_GlobalInvocationID.x].z, _21.outputs[gl_GlobalInvocationID.x].w); - short2 _66 = short2(as_type(uint(_29.inputs[gl_GlobalInvocationID.x].y)) - as_type(_40.const0.zw)); - _21.outputs[gl_GlobalInvocationID.x] = short4(_21.outputs[gl_GlobalInvocationID.x].x, _21.outputs[gl_GlobalInvocationID.x].y, _66.x, _66.y); -} - diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/comp/coherent-block.comp b/third_party/spirv-cross/reference/opt/shaders-msl/comp/coherent-block.comp index 580b9e3e9d..58bbacb7f0 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/comp/coherent-block.comp +++ b/third_party/spirv-cross/reference/opt/shaders-msl/comp/coherent-block.comp @@ -8,6 +8,8 @@ struct SSBO float4 value; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + kernel void main0(volatile device SSBO& _10 [[buffer(0)]]) { _10.value = float4(20.0); diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/comp/coherent-image.comp b/third_party/spirv-cross/reference/opt/shaders-msl/comp/coherent-image.comp index c6af46b5a4..5090484464 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/comp/coherent-image.comp +++ b/third_party/spirv-cross/reference/opt/shaders-msl/comp/coherent-image.comp @@ -8,6 +8,8 @@ struct SSBO int4 value; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + kernel void main0(volatile device SSBO& _10 [[buffer(0)]], texture2d uImage [[texture(0)]]) { _10.value = uImage.read(uint2(int2(10))); diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/comp/complex-composite-constant-array.comp b/third_party/spirv-cross/reference/opt/shaders-msl/comp/complex-composite-constant-array.comp new file mode 100644 index 0000000000..bd58c95a00 --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders-msl/comp/complex-composite-constant-array.comp @@ -0,0 +1,59 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + +#include +#include + +using namespace metal; + +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +struct SSBO +{ + float4x4 a; + uint index; +}; + +kernel void main0(device SSBO& _14 [[buffer(0)]]) +{ + spvUnsafeArray _32 = spvUnsafeArray({ float4x4(float4(1.0, 0.0, 0.0, 0.0), float4(0.0, 1.0, 0.0, 0.0), float4(0.0, 0.0, 1.0, 0.0), float4(0.0, 0.0, 0.0, 1.0)), float4x4(float4(2.0, 0.0, 0.0, 0.0), float4(0.0, 2.0, 0.0, 0.0), float4(0.0, 0.0, 2.0, 0.0), float4(0.0, 0.0, 0.0, 2.0)) }); + + _14.a = _32[_14.index]; +} + diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/comp/composite-array-initialization.comp b/third_party/spirv-cross/reference/opt/shaders-msl/comp/composite-array-initialization.comp index 8dec8bddb3..6181ae69b1 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/comp/composite-array-initialization.comp +++ b/third_party/spirv-cross/reference/opt/shaders-msl/comp/composite-array-initialization.comp @@ -1,10 +1,49 @@ #pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" #include #include using namespace metal; +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + struct Data { float a; @@ -27,26 +66,13 @@ struct SSBO constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(2u, 1u, 1u); -constant Data _25[2] = { Data{ 1.0, 2.0 }, Data{ 3.0, 4.0 } }; - -// Implementation of an array copy function to cover GLSL's ability to copy an array via assignment. -template -void spvArrayCopyFromStack1(thread T (&dst)[N], thread const T (&src)[N]) -{ - for (uint i = 0; i < N; dst[i] = src[i], i++); -} - -template -void spvArrayCopyFromConstant1(thread T (&dst)[N], constant T (&src)[N]) -{ - for (uint i = 0; i < N; dst[i] = src[i], i++); -} - kernel void main0(device SSBO& _53 [[buffer(0)]], uint3 gl_WorkGroupID [[threadgroup_position_in_grid]], uint3 gl_LocalInvocationID [[thread_position_in_threadgroup]]) { - Data _31[2] = { Data{ X, 2.0 }, Data{ 3.0, 5.0 } }; - Data data2[2]; - spvArrayCopyFromStack1(data2, _31); + spvUnsafeArray _25 = spvUnsafeArray({ Data{ 1.0, 2.0 }, Data{ 3.0, 4.0 } }); + + spvUnsafeArray _31 = spvUnsafeArray({ Data{ X, 2.0 }, Data{ 3.0, 5.0 } }); + spvUnsafeArray data2; + data2 = _31; _53.outdata[gl_WorkGroupID.x].a = _25[gl_LocalInvocationID.x].a + data2[gl_LocalInvocationID.x].a; _53.outdata[gl_WorkGroupID.x].b = _25[gl_LocalInvocationID.x].b + data2[gl_LocalInvocationID.x].b; } diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/comp/composite-array-initialization.force-native-array.comp b/third_party/spirv-cross/reference/opt/shaders-msl/comp/composite-array-initialization.force-native-array.comp new file mode 100644 index 0000000000..8f150e473d --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders-msl/comp/composite-array-initialization.force-native-array.comp @@ -0,0 +1,94 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" + +#include +#include + +using namespace metal; + +struct Data +{ + float a; + float b; +}; + +constant float X_tmp [[function_constant(0)]]; +constant float X = is_function_constant_defined(X_tmp) ? X_tmp : 4.0; + +struct Data_1 +{ + float a; + float b; +}; + +struct SSBO +{ + Data_1 outdata[1]; +}; + +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(2u, 1u, 1u); + +template +inline void spvArrayCopyFromConstantToStack1(thread T (&dst)[A], constant T (&src)[A]) +{ + for (uint i = 0; i < A; i++) + { + dst[i] = src[i]; + } +} + +template +inline void spvArrayCopyFromConstantToThreadGroup1(threadgroup T (&dst)[A], constant T (&src)[A]) +{ + for (uint i = 0; i < A; i++) + { + dst[i] = src[i]; + } +} + +template +inline void spvArrayCopyFromStackToStack1(thread T (&dst)[A], thread const T (&src)[A]) +{ + for (uint i = 0; i < A; i++) + { + dst[i] = src[i]; + } +} + +template +inline void spvArrayCopyFromStackToThreadGroup1(threadgroup T (&dst)[A], thread const T (&src)[A]) +{ + for (uint i = 0; i < A; i++) + { + dst[i] = src[i]; + } +} + +template +inline void spvArrayCopyFromThreadGroupToStack1(thread T (&dst)[A], threadgroup const T (&src)[A]) +{ + for (uint i = 0; i < A; i++) + { + dst[i] = src[i]; + } +} + +template +inline void spvArrayCopyFromThreadGroupToThreadGroup1(threadgroup T (&dst)[A], threadgroup const T (&src)[A]) +{ + for (uint i = 0; i < A; i++) + { + dst[i] = src[i]; + } +} + +kernel void main0(device SSBO& _53 [[buffer(0)]], uint3 gl_WorkGroupID [[threadgroup_position_in_grid]], uint3 gl_LocalInvocationID [[thread_position_in_threadgroup]]) +{ + Data _25[2] = { Data{ 1.0, 2.0 }, Data{ 3.0, 4.0 } }; + + Data _31[2] = { Data{ X, 2.0 }, Data{ 3.0, 5.0 } }; + Data data2[2]; + spvArrayCopyFromStackToStack1(data2, _31); + _53.outdata[gl_WorkGroupID.x].a = _25[gl_LocalInvocationID.x].a + data2[gl_LocalInvocationID.x].a; + _53.outdata[gl_WorkGroupID.x].b = _25[gl_LocalInvocationID.x].b + data2[gl_LocalInvocationID.x].b; +} + diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/comp/composite-construct.comp b/third_party/spirv-cross/reference/opt/shaders-msl/comp/composite-construct.comp index 6d44fc57b2..09e6fc7d95 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/comp/composite-construct.comp +++ b/third_party/spirv-cross/reference/opt/shaders-msl/comp/composite-construct.comp @@ -1,10 +1,49 @@ #pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" #include #include using namespace metal; +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + struct SSBO0 { float4 as[1]; @@ -15,24 +54,13 @@ struct SSBO1 float4 bs[1]; }; -// Implementation of an array copy function to cover GLSL's ability to copy an array via assignment. -template -void spvArrayCopyFromStack1(thread T (&dst)[N], thread const T (&src)[N]) -{ - for (uint i = 0; i < N; dst[i] = src[i], i++); -} - -template -void spvArrayCopyFromConstant1(thread T (&dst)[N], constant T (&src)[N]) -{ - for (uint i = 0; i < N; dst[i] = src[i], i++); -} +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); kernel void main0(device SSBO0& _16 [[buffer(0)]], device SSBO1& _32 [[buffer(1)]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]], uint gl_LocalInvocationIndex [[thread_index_in_threadgroup]]) { - float4 _37[2] = { _16.as[gl_GlobalInvocationID.x], _32.bs[gl_GlobalInvocationID.x] }; - float4 values[2]; - spvArrayCopyFromStack1(values, _37); + spvUnsafeArray _37 = spvUnsafeArray({ _16.as[gl_GlobalInvocationID.x], _32.bs[gl_GlobalInvocationID.x] }); + spvUnsafeArray values; + values = _37; _16.as[0] = values[gl_LocalInvocationIndex]; _32.bs[1] = float4(40.0); } diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/comp/copy-array-of-arrays.comp b/third_party/spirv-cross/reference/opt/shaders-msl/comp/copy-array-of-arrays.comp index ea9693ce47..cb396cff20 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/comp/copy-array-of-arrays.comp +++ b/third_party/spirv-cross/reference/opt/shaders-msl/comp/copy-array-of-arrays.comp @@ -10,6 +10,8 @@ struct BUF float c; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + kernel void main0(device BUF& o [[buffer(0)]]) { o.a = 4; diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/comp/copy-array-of-arrays.force-native-array.comp b/third_party/spirv-cross/reference/opt/shaders-msl/comp/copy-array-of-arrays.force-native-array.comp new file mode 100644 index 0000000000..cb396cff20 --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders-msl/comp/copy-array-of-arrays.force-native-array.comp @@ -0,0 +1,20 @@ +#include +#include + +using namespace metal; + +struct BUF +{ + int a; + float b; + float c; +}; + +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + +kernel void main0(device BUF& o [[buffer(0)]]) +{ + o.a = 4; + o.b = o.c; +} + diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/comp/defer-parens.comp b/third_party/spirv-cross/reference/opt/shaders-msl/comp/defer-parens.comp index 69a8aab92d..8c130e3a0c 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/comp/defer-parens.comp +++ b/third_party/spirv-cross/reference/opt/shaders-msl/comp/defer-parens.comp @@ -9,6 +9,8 @@ struct SSBO int index; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + kernel void main0(device SSBO& _13 [[buffer(0)]]) { float4 _17 = _13.data; diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/comp/dowhile.comp b/third_party/spirv-cross/reference/opt/shaders-msl/comp/dowhile.comp index 3ebafe0fde..b503c948ad 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/comp/dowhile.comp +++ b/third_party/spirv-cross/reference/opt/shaders-msl/comp/dowhile.comp @@ -14,21 +14,23 @@ struct SSBO2 float4 out_data[1]; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + kernel void main0(const device SSBO& _28 [[buffer(0)]], device SSBO2& _52 [[buffer(1)]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]]) { - float4 _57; - int _58; - _58 = 0; - _57 = _28.in_data[gl_GlobalInvocationID.x]; + float4 _59; + int _60; + _60 = 0; + _59 = _28.in_data[gl_GlobalInvocationID.x]; float4 _42; for (;;) { - _42 = _28.mvp * _57; - int _44 = _58 + 1; + _42 = _28.mvp * _59; + int _44 = _60 + 1; if (_44 < 16) { - _58 = _44; - _57 = _42; + _60 = _44; + _59 = _42; } else { diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/comp/force-recompile-hooks.swizzle.comp b/third_party/spirv-cross/reference/opt/shaders-msl/comp/force-recompile-hooks.swizzle.comp index 7cb8913dab..fbf4c4f7fc 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/comp/force-recompile-hooks.swizzle.comp +++ b/third_party/spirv-cross/reference/opt/shaders-msl/comp/force-recompile-hooks.swizzle.comp @@ -5,17 +5,6 @@ using namespace metal; -enum class spvSwizzle : uint -{ - none = 0, - zero, - one, - red, - green, - blue, - alpha -}; - template struct spvRemoveReference { typedef T type; }; template struct spvRemoveReference { typedef T type; }; template struct spvRemoveReference { typedef T type; }; @@ -28,6 +17,17 @@ template inline constexpr thread T&& spvForward(thread typename spvR return static_cast(x); } +enum class spvSwizzle : uint +{ + none = 0, + zero, + one, + red, + green, + blue, + alpha +}; + template inline T spvGetSwizzle(vec x, T c, spvSwizzle s) { @@ -65,66 +65,6 @@ inline T spvTextureSwizzle(T x, uint s) return spvTextureSwizzle(vec(x, 0, 0, 1), s).x; } -// Wrapper function that swizzles texture gathers. -template -inline vec spvGatherSwizzle(sampler s, const thread Tex& t, Ts... params, component c, uint sw) METAL_CONST_ARG(c) -{ - if (sw) - { - switch (spvSwizzle((sw >> (uint(c) * 8)) & 0xFF)) - { - case spvSwizzle::none: - break; - case spvSwizzle::zero: - return vec(0, 0, 0, 0); - case spvSwizzle::one: - return vec(1, 1, 1, 1); - case spvSwizzle::red: - return t.gather(s, spvForward(params)..., component::x); - case spvSwizzle::green: - return t.gather(s, spvForward(params)..., component::y); - case spvSwizzle::blue: - return t.gather(s, spvForward(params)..., component::z); - case spvSwizzle::alpha: - return t.gather(s, spvForward(params)..., component::w); - } - } - switch (c) - { - case component::x: - return t.gather(s, spvForward(params)..., component::x); - case component::y: - return t.gather(s, spvForward(params)..., component::y); - case component::z: - return t.gather(s, spvForward(params)..., component::z); - case component::w: - return t.gather(s, spvForward(params)..., component::w); - } -} - -// Wrapper function that swizzles depth texture gathers. -template -inline vec spvGatherCompareSwizzle(sampler s, const thread Tex& t, Ts... params, uint sw) -{ - if (sw) - { - switch (spvSwizzle(sw & 0xFF)) - { - case spvSwizzle::none: - case spvSwizzle::red: - break; - case spvSwizzle::zero: - case spvSwizzle::green: - case spvSwizzle::blue: - case spvSwizzle::alpha: - return vec(0, 0, 0, 0); - case spvSwizzle::one: - return vec(1, 1, 1, 1); - } - } - return t.gather_compare(s, spvForward(params)...); -} - kernel void main0(constant uint* spvSwizzleConstants [[buffer(30)]], texture2d foo [[texture(0)]], texture2d bar [[texture(1)]], sampler fooSmplr [[sampler(0)]]) { constant uint& fooSwzl = spvSwizzleConstants[0]; diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/comp/global-invocation-id-writable-ssbo-in-function.comp b/third_party/spirv-cross/reference/opt/shaders-msl/comp/global-invocation-id-writable-ssbo-in-function.comp index fe0212ec3f..9900b59311 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/comp/global-invocation-id-writable-ssbo-in-function.comp +++ b/third_party/spirv-cross/reference/opt/shaders-msl/comp/global-invocation-id-writable-ssbo-in-function.comp @@ -13,7 +13,7 @@ struct myBlock // Implementation of the GLSL mod() function, which is slightly different than Metal fmod() template -Tx mod(Tx x, Ty y) +inline Tx mod(Tx x, Ty y) { return x - y * floor(x / y); } diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/comp/global-invocation-id.comp b/third_party/spirv-cross/reference/opt/shaders-msl/comp/global-invocation-id.comp index fe0212ec3f..9900b59311 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/comp/global-invocation-id.comp +++ b/third_party/spirv-cross/reference/opt/shaders-msl/comp/global-invocation-id.comp @@ -13,7 +13,7 @@ struct myBlock // Implementation of the GLSL mod() function, which is slightly different than Metal fmod() template -Tx mod(Tx x, Ty y) +inline Tx mod(Tx x, Ty y) { return x - y * floor(x / y); } diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/comp/image-atomic-automatic-bindings.comp b/third_party/spirv-cross/reference/opt/shaders-msl/comp/image-atomic-automatic-bindings.comp new file mode 100644 index 0000000000..a8ade54be4 --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders-msl/comp/image-atomic-automatic-bindings.comp @@ -0,0 +1,25 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wunused-variable" + +#include +#include +#include + +using namespace metal; + +struct SSBO +{ + float4 outdata; +}; + +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + +// Returns buffer coords corresponding to 2D texture coords for emulating 2D texture atomics +#define spvImage2DAtomicCoord(tc, tex) (((tex).get_width() * (tc).x) + (tc).y) + +kernel void main0(device SSBO& _31 [[buffer(1)]], texture2d uImage [[texture(0)]], device atomic_uint* uImage_atomic [[buffer(0)]], texture2d uTexture [[texture(1)]], sampler uTextureSmplr [[sampler(0)]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]]) +{ + uint _26 = atomic_fetch_add_explicit((device atomic_uint*)&uImage_atomic[spvImage2DAtomicCoord(int2(gl_GlobalInvocationID.xy), uImage)], 10u, memory_order_relaxed); + _31.outdata = uTexture.sample(uTextureSmplr, float2(gl_GlobalInvocationID.xy), level(0.0)) + float4(float(_26)); +} + diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/comp/image-cube-array-load-store.comp b/third_party/spirv-cross/reference/opt/shaders-msl/comp/image-cube-array-load-store.comp index 1eeaf87cf4..41c4dfc180 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/comp/image-cube-array-load-store.comp +++ b/third_party/spirv-cross/reference/opt/shaders-msl/comp/image-cube-array-load-store.comp @@ -3,6 +3,8 @@ using namespace metal; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + kernel void main0(texturecube_array uImageIn [[texture(0)]], texturecube_array uImageOut [[texture(1)]]) { uImageOut.write(uImageIn.read(uint2(int3(9, 7, 11).xy), uint(int3(9, 7, 11).z) % 6u, uint(int3(9, 7, 11).z) / 6u), uint2(int3(9, 7, 11).xy), uint(int3(9, 7, 11).z) % 6u, uint(int3(9, 7, 11).z) / 6u); diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/comp/image.comp b/third_party/spirv-cross/reference/opt/shaders-msl/comp/image.comp index 447732dd23..c875e78de0 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/comp/image.comp +++ b/third_party/spirv-cross/reference/opt/shaders-msl/comp/image.comp @@ -3,6 +3,8 @@ using namespace metal; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + kernel void main0(texture2d uImageIn [[texture(0)]], texture2d uImageOut [[texture(1)]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]]) { int2 _23 = int2(gl_GlobalInvocationID.xy); diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/comp/insert.comp b/third_party/spirv-cross/reference/opt/shaders-msl/comp/insert.comp index 1418ce35b5..d7392c982a 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/comp/insert.comp +++ b/third_party/spirv-cross/reference/opt/shaders-msl/comp/insert.comp @@ -8,19 +8,21 @@ struct SSBO float4 out_data[1]; }; -constant float4 _52 = {}; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + +constant float4 _53 = {}; kernel void main0(device SSBO& _27 [[buffer(0)]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]]) { - float4 _45 = _52; - _45.x = 10.0; - float4 _47 = _45; - _47.y = 30.0; - float4 _49 = _47; - _49.z = 70.0; - float4 _51 = _49; - _51.w = 90.0; - _27.out_data[gl_GlobalInvocationID.x] = _51; + float4 _46 = _53; + _46.x = 10.0; + float4 _48 = _46; + _48.y = 30.0; + float4 _50 = _48; + _50.z = 70.0; + float4 _52 = _50; + _52.w = 90.0; + _27.out_data[gl_GlobalInvocationID.x] = _52; _27.out_data[gl_GlobalInvocationID.x].y = 20.0; } diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/comp/int64.invalid.msl22.comp b/third_party/spirv-cross/reference/opt/shaders-msl/comp/int64.invalid.msl22.comp deleted file mode 100644 index 13304bd0e8..0000000000 --- a/third_party/spirv-cross/reference/opt/shaders-msl/comp/int64.invalid.msl22.comp +++ /dev/null @@ -1,24 +0,0 @@ -#include -#include - -using namespace metal; - -struct SSBO -{ - int s32; - uint u32; -}; - -constant long _162 = {}; - -kernel void main0(device SSBO& _96 [[buffer(0)]]) -{ - long4 _137; - ulong4 _141; - _137 = abs((_137 + long4(30l, 40l, 50l, 60l)) + long4(_141 + ulong4(999999999999999999ul, 8888888888888888ul, 77777777777777777ul, 6666666666666666ul))); - _141 += ulong4(long4(999999999999999999l, 8888888888888888l, 77777777777777777l, 6666666666666666l)); - ulong _109 = ulong(_162); - _96.s32 = int(uint(((ulong(_137.x) + _141.y) + _109) + _109)); - _96.u32 = uint(((ulong(_137.y) + _141.z) + ulong(_162 + 1l)) + _109); -} - diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/comp/inverse.comp b/third_party/spirv-cross/reference/opt/shaders-msl/comp/inverse.comp index f2f499b91e..33aed468f7 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/comp/inverse.comp +++ b/third_party/spirv-cross/reference/opt/shaders-msl/comp/inverse.comp @@ -19,20 +19,25 @@ struct MatrixIn float4x4 m4in; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + // Returns the determinant of a 2x2 matrix. -inline float spvDet2x2(float a1, float a2, float b1, float b2) +static inline __attribute__((always_inline)) +float spvDet2x2(float a1, float a2, float b1, float b2) { return a1 * b2 - b1 * a2; } // Returns the determinant of a 3x3 matrix. -inline float spvDet3x3(float a1, float a2, float a3, float b1, float b2, float b3, float c1, float c2, float c3) +static inline __attribute__((always_inline)) +float spvDet3x3(float a1, float a2, float a3, float b1, float b2, float b3, float c1, float c2, float c3) { return a1 * spvDet2x2(b2, b3, c2, c3) - b1 * spvDet2x2(a2, a3, c2, c3) + c1 * spvDet2x2(a2, a3, b2, b3); } // Returns the inverse of a matrix, by using the algorithm of calculating the classical // adjoint and dividing by the determinant. The contents of the matrix are changed. +static inline __attribute__((always_inline)) float4x4 spvInverse4x4(float4x4 m) { float4x4 adj; // The adjoint matrix (inverse after dividing by determinant) @@ -68,6 +73,7 @@ float4x4 spvInverse4x4(float4x4 m) // Returns the inverse of a matrix, by using the algorithm of calculating the classical // adjoint and dividing by the determinant. The contents of the matrix are changed. +static inline __attribute__((always_inline)) float3x3 spvInverse3x3(float3x3 m) { float3x3 adj; // The adjoint matrix (inverse after dividing by determinant) @@ -95,6 +101,7 @@ float3x3 spvInverse3x3(float3x3 m) // Returns the inverse of a matrix, by using the algorithm of calculating the classical // adjoint and dividing by the determinant. The contents of the matrix are changed. +static inline __attribute__((always_inline)) float2x2 spvInverse2x2(float2x2 m) { float2x2 adj; // The adjoint matrix (inverse after dividing by determinant) diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/comp/local-invocation-id.comp b/third_party/spirv-cross/reference/opt/shaders-msl/comp/local-invocation-id.comp index 772e5e0d86..362aaa30c8 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/comp/local-invocation-id.comp +++ b/third_party/spirv-cross/reference/opt/shaders-msl/comp/local-invocation-id.comp @@ -13,7 +13,7 @@ struct myBlock // Implementation of the GLSL mod() function, which is slightly different than Metal fmod() template -Tx mod(Tx x, Ty y) +inline Tx mod(Tx x, Ty y) { return x - y * floor(x / y); } diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/comp/local-invocation-index.comp b/third_party/spirv-cross/reference/opt/shaders-msl/comp/local-invocation-index.comp index 41adbdca5c..f8c1550eab 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/comp/local-invocation-index.comp +++ b/third_party/spirv-cross/reference/opt/shaders-msl/comp/local-invocation-index.comp @@ -13,7 +13,7 @@ struct myBlock // Implementation of the GLSL mod() function, which is slightly different than Metal fmod() template -Tx mod(Tx x, Ty y) +inline Tx mod(Tx x, Ty y) { return x - y * floor(x / y); } diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/comp/mat3.comp b/third_party/spirv-cross/reference/opt/shaders-msl/comp/mat3.comp index 72f08dd85e..31351ba57b 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/comp/mat3.comp +++ b/third_party/spirv-cross/reference/opt/shaders-msl/comp/mat3.comp @@ -8,6 +8,8 @@ struct SSBO2 float3x3 out_data[1]; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + kernel void main0(device SSBO2& _22 [[buffer(0)]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]]) { _22.out_data[gl_GlobalInvocationID.x] = float3x3(float3(10.0), float3(20.0), float3(40.0)); diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/comp/mod.comp b/third_party/spirv-cross/reference/opt/shaders-msl/comp/mod.comp index 8574f87b7e..e8c01f966c 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/comp/mod.comp +++ b/third_party/spirv-cross/reference/opt/shaders-msl/comp/mod.comp @@ -15,9 +15,11 @@ struct SSBO2 float4 out_data[1]; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + // Implementation of the GLSL mod() function, which is slightly different than Metal fmod() template -Tx mod(Tx x, Ty y) +inline Tx mod(Tx x, Ty y) { return x - y * floor(x / y); } diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/comp/modf.comp b/third_party/spirv-cross/reference/opt/shaders-msl/comp/modf.comp index 39e402337f..df19cae502 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/comp/modf.comp +++ b/third_party/spirv-cross/reference/opt/shaders-msl/comp/modf.comp @@ -13,6 +13,8 @@ struct SSBO2 float4 out_data[1]; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + kernel void main0(const device SSBO& _23 [[buffer(0)]], device SSBO2& _35 [[buffer(1)]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]]) { float4 i; diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/comp/outer-product.comp b/third_party/spirv-cross/reference/opt/shaders-msl/comp/outer-product.comp index 8e32db392e..e589642dbd 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/comp/outer-product.comp +++ b/third_party/spirv-cross/reference/opt/shaders-msl/comp/outer-product.comp @@ -23,6 +23,8 @@ struct ReadSSBO float4 v4; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + kernel void main0(device SSBO& _21 [[buffer(0)]], const device ReadSSBO& _26 [[buffer(1)]]) { _21.m22 = float2x2(_26.v2 * _26.v2.x, _26.v2 * _26.v2.y); diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/comp/read-write-only.comp b/third_party/spirv-cross/reference/opt/shaders-msl/comp/read-write-only.comp index 7547b417d8..0cf8d8e321 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/comp/read-write-only.comp +++ b/third_party/spirv-cross/reference/opt/shaders-msl/comp/read-write-only.comp @@ -21,6 +21,8 @@ struct SSBO1 float4 data3; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + kernel void main0(device SSBO2& _10 [[buffer(0)]], const device SSBO0& _15 [[buffer(1)]], device SSBO1& _21 [[buffer(2)]]) { _10.data4 = _15.data0 + _21.data2; diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/comp/rmw-matrix.comp b/third_party/spirv-cross/reference/opt/shaders-msl/comp/rmw-matrix.comp index 150db7ede9..b53a3a75c2 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/comp/rmw-matrix.comp +++ b/third_party/spirv-cross/reference/opt/shaders-msl/comp/rmw-matrix.comp @@ -13,6 +13,8 @@ struct SSBO float4x4 c1; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + kernel void main0(device SSBO& _11 [[buffer(0)]]) { _11.a *= _11.a1; diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/comp/rmw-opt.comp b/third_party/spirv-cross/reference/opt/shaders-msl/comp/rmw-opt.comp index 05e1f6f283..f93967da53 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/comp/rmw-opt.comp +++ b/third_party/spirv-cross/reference/opt/shaders-msl/comp/rmw-opt.comp @@ -8,6 +8,8 @@ struct SSBO int a; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + kernel void main0(device SSBO& _9 [[buffer(0)]]) { _9.a += 10; diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/comp/scalar-std450-distance-length-normalize.comp b/third_party/spirv-cross/reference/opt/shaders-msl/comp/scalar-std450-distance-length-normalize.comp index 312a6f9453..0ae6e5562b 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/comp/scalar-std450-distance-length-normalize.comp +++ b/third_party/spirv-cross/reference/opt/shaders-msl/comp/scalar-std450-distance-length-normalize.comp @@ -12,6 +12,8 @@ struct SSBO float e; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + kernel void main0(device SSBO& _9 [[buffer(0)]]) { _9.c = abs(_9.a - _9.b); diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/comp/spec-constant-op-member-array.comp b/third_party/spirv-cross/reference/opt/shaders-msl/comp/spec-constant-op-member-array.comp index d3c8b7dc4a..8f54f0528d 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/comp/spec-constant-op-member-array.comp +++ b/third_party/spirv-cross/reference/opt/shaders-msl/comp/spec-constant-op-member-array.comp @@ -40,6 +40,7 @@ struct SSBO constant int e_tmp [[function_constant(3)]]; constant int e = is_function_constant_defined(e_tmp) ? e_tmp : 400; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); kernel void main0(device SSBO& _22 [[buffer(0)]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]]) { diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/comp/spec-constant-work-group-size.comp b/third_party/spirv-cross/reference/opt/shaders-msl/comp/spec-constant-work-group-size.comp index bb796ab95d..de30edec15 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/comp/spec-constant-work-group-size.comp +++ b/third_party/spirv-cross/reference/opt/shaders-msl/comp/spec-constant-work-group-size.comp @@ -1,8 +1,49 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + #include #include using namespace metal; +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + #ifndef SPIRV_CROSS_CONSTANT_ID_1 #define SPIRV_CROSS_CONSTANT_ID_1 2 #endif @@ -27,7 +68,7 @@ constant int _32 = (1 - a); kernel void main0(device SSBO& _17 [[buffer(0)]]) { - int spec_const_array_size[b]; + spvUnsafeArray spec_const_array_size; spec_const_array_size[a] = a; _17.v[_30] = b + spec_const_array_size[_32]; } diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/comp/storage-buffer-std140-vector-array.comp b/third_party/spirv-cross/reference/opt/shaders-msl/comp/storage-buffer-std140-vector-array.comp index 905222d398..ac28fc9b33 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/comp/storage-buffer-std140-vector-array.comp +++ b/third_party/spirv-cross/reference/opt/shaders-msl/comp/storage-buffer-std140-vector-array.comp @@ -1,8 +1,49 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + #include #include using namespace metal; +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + struct Sub { float4 f[2]; @@ -16,32 +57,34 @@ struct SSBO Sub sub[2]; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + kernel void main0(device SSBO& _27 [[buffer(0)]], uint3 gl_WorkGroupID [[threadgroup_position_in_grid]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]]) { - float _153[2]; - _153[0] = _27.sub[gl_WorkGroupID.x].f[0].x; - _153[1] = _27.sub[gl_WorkGroupID.x].f[1].x; - float2 _154[2]; - _154[0] = _27.sub[gl_WorkGroupID.x].f2[0].xy; - _154[1] = _27.sub[gl_WorkGroupID.x].f2[1].xy; - float3 _155[2]; - _155[0] = _27.sub[gl_WorkGroupID.x].f3[0]; - _155[1] = _27.sub[gl_WorkGroupID.x].f3[1]; - float4 _156[2]; - _156[0] = _27.sub[gl_WorkGroupID.x].f4[0]; - _156[1] = _27.sub[gl_WorkGroupID.x].f4[1]; - _153[gl_GlobalInvocationID.x] += 1.0; - _154[gl_GlobalInvocationID.x] += float2(2.0); - _155[gl_GlobalInvocationID.x] += float3(3.0); - _156[gl_GlobalInvocationID.x] += float4(4.0); - _27.sub[gl_WorkGroupID.x].f[0].x = _153[0]; - _27.sub[gl_WorkGroupID.x].f[1].x = _153[1]; - _27.sub[gl_WorkGroupID.x].f2[0].xy = _154[0]; - _27.sub[gl_WorkGroupID.x].f2[1].xy = _154[1]; - _27.sub[gl_WorkGroupID.x].f3[0] = _155[0]; - _27.sub[gl_WorkGroupID.x].f3[1] = _155[1]; - _27.sub[gl_WorkGroupID.x].f4[0] = _156[0]; - _27.sub[gl_WorkGroupID.x].f4[1] = _156[1]; + spvUnsafeArray _155; + _155[0] = _27.sub[gl_WorkGroupID.x].f[0].x; + _155[1] = _27.sub[gl_WorkGroupID.x].f[1].x; + spvUnsafeArray _156; + _156[0] = _27.sub[gl_WorkGroupID.x].f2[0].xy; + _156[1] = _27.sub[gl_WorkGroupID.x].f2[1].xy; + spvUnsafeArray _157; + _157[0] = _27.sub[gl_WorkGroupID.x].f3[0]; + _157[1] = _27.sub[gl_WorkGroupID.x].f3[1]; + spvUnsafeArray _158; + _158[0] = _27.sub[gl_WorkGroupID.x].f4[0]; + _158[1] = _27.sub[gl_WorkGroupID.x].f4[1]; + _155[gl_GlobalInvocationID.x] += 1.0; + _156[gl_GlobalInvocationID.x] += float2(2.0); + _157[gl_GlobalInvocationID.x] += float3(3.0); + _158[gl_GlobalInvocationID.x] += float4(4.0); + _27.sub[gl_WorkGroupID.x].f[0].x = _155[0]; + _27.sub[gl_WorkGroupID.x].f[1].x = _155[1]; + _27.sub[gl_WorkGroupID.x].f2[0].xy = _156[0]; + _27.sub[gl_WorkGroupID.x].f2[1].xy = _156[1]; + _27.sub[gl_WorkGroupID.x].f3[0] = _157[0]; + _27.sub[gl_WorkGroupID.x].f3[1] = _157[1]; + _27.sub[gl_WorkGroupID.x].f4[0] = _158[0]; + _27.sub[gl_WorkGroupID.x].f4[1] = _158[1]; _27.sub[0].f[0].x += 5.0; _27.sub[0].f2[1].xy += float2(5.0); } diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/comp/struct-layout.comp b/third_party/spirv-cross/reference/opt/shaders-msl/comp/struct-layout.comp index d441362527..0445f5aef9 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/comp/struct-layout.comp +++ b/third_party/spirv-cross/reference/opt/shaders-msl/comp/struct-layout.comp @@ -18,6 +18,8 @@ struct SSBO Foo in_data[1]; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + kernel void main0(device SSBO2& _23 [[buffer(0)]], const device SSBO& _30 [[buffer(1)]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]]) { _23.out_data[gl_GlobalInvocationID.x].m = _30.in_data[gl_GlobalInvocationID.x].m * _30.in_data[gl_GlobalInvocationID.x].m; diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/comp/struct-nested.comp b/third_party/spirv-cross/reference/opt/shaders-msl/comp/struct-nested.comp index 6a1419cecb..ad706c5909 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/comp/struct-nested.comp +++ b/third_party/spirv-cross/reference/opt/shaders-msl/comp/struct-nested.comp @@ -18,6 +18,8 @@ struct dstbuffer s2 test[1]; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + kernel void main0(device dstbuffer& _19 [[buffer(0)]]) { _19.test[0].b.a = 0; diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/comp/struct-packing.comp b/third_party/spirv-cross/reference/opt/shaders-msl/comp/struct-packing.comp index ad22c257ad..775bb34881 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/comp/struct-packing.comp +++ b/third_party/spirv-cross/reference/opt/shaders-msl/comp/struct-packing.comp @@ -118,6 +118,8 @@ struct SSBO0 float4 array[1]; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + kernel void main0(device SSBO1& ssbo_430 [[buffer(0)]], device SSBO0& ssbo_140 [[buffer(1)]]) { Content_1 _60 = ssbo_140.content; diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/comp/torture-loop.comp b/third_party/spirv-cross/reference/opt/shaders-msl/comp/torture-loop.comp index 4c367d3e6d..ff7e02e202 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/comp/torture-loop.comp +++ b/third_party/spirv-cross/reference/opt/shaders-msl/comp/torture-loop.comp @@ -14,29 +14,31 @@ struct SSBO2 float4 out_data[1]; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + kernel void main0(const device SSBO& _24 [[buffer(0)]], device SSBO2& _89 [[buffer(1)]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]]) { - float4 _99; - _99 = _24.in_data[gl_GlobalInvocationID.x]; - for (int _93 = 0; (_93 + 1) < 10; ) + float4 _101; + _101 = _24.in_data[gl_GlobalInvocationID.x]; + for (int _95 = 0; (_95 + 1) < 10; ) { - _99 *= 2.0; - _93 += 2; + _101 *= 2.0; + _95 += 2; continue; } - float4 _98; - _98 = _99; - float4 _103; - for (uint _94 = 0u; _94 < 16u; _98 = _103, _94++) + float4 _100; + _100 = _101; + float4 _105; + for (uint _96 = 0u; _96 < 16u; _100 = _105, _96++) { - _103 = _98; - for (uint _100 = 0u; _100 < 30u; ) + _105 = _100; + for (uint _102 = 0u; _102 < 30u; ) { - _103 = _24.mvp * _103; - _100++; + _105 = _24.mvp * _105; + _102++; continue; } } - _89.out_data[gl_GlobalInvocationID.x] = _98; + _89.out_data[gl_GlobalInvocationID.x] = _100; } diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/comp/type-alias.comp b/third_party/spirv-cross/reference/opt/shaders-msl/comp/type-alias.comp index 8a68933d82..2f6a0b7ba8 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/comp/type-alias.comp +++ b/third_party/spirv-cross/reference/opt/shaders-msl/comp/type-alias.comp @@ -28,6 +28,8 @@ struct SSBO2 float4 outputs[1]; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + kernel void main0(device SSBO0& _36 [[buffer(0)]], device SSBO1& _55 [[buffer(1)]], device SSBO2& _66 [[buffer(2)]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]]) { _66.outputs[gl_GlobalInvocationID.x] = _36.s0s[gl_GlobalInvocationID.x].a + _55.s1s[gl_GlobalInvocationID.x].a; diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/comp/udiv.comp b/third_party/spirv-cross/reference/opt/shaders-msl/comp/udiv.comp index 32874ad787..7f7315b882 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/comp/udiv.comp +++ b/third_party/spirv-cross/reference/opt/shaders-msl/comp/udiv.comp @@ -13,6 +13,8 @@ struct SSBO uint inputs[1]; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + kernel void main0(device SSBO2& _10 [[buffer(0)]], device SSBO& _23 [[buffer(1)]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]]) { _10.outputs[gl_GlobalInvocationID.x] = _23.inputs[gl_GlobalInvocationID.x] / 29u; diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/comp/writable-ssbo.comp b/third_party/spirv-cross/reference/opt/shaders-msl/comp/writable-ssbo.comp index 9dc53b6dd5..dcec81a369 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/comp/writable-ssbo.comp +++ b/third_party/spirv-cross/reference/opt/shaders-msl/comp/writable-ssbo.comp @@ -13,7 +13,7 @@ struct myBlock // Implementation of the GLSL mod() function, which is slightly different than Metal fmod() template -Tx mod(Tx x, Ty y) +inline Tx mod(Tx x, Ty y) { return x - y * floor(x / y); } diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/desktop-only/comp/extended-arithmetic.desktop.comp b/third_party/spirv-cross/reference/opt/shaders-msl/desktop-only/comp/extended-arithmetic.desktop.comp index a37fe519a5..cea12980c6 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/desktop-only/comp/extended-arithmetic.desktop.comp +++ b/third_party/spirv-cross/reference/opt/shaders-msl/desktop-only/comp/extended-arithmetic.desktop.comp @@ -91,6 +91,8 @@ struct ResType_7 int4 _m1; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + kernel void main0(device SSBOUint& u [[buffer(0)]], device SSBOInt& i [[buffer(1)]]) { ResType _25; diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/desktop-only/tesc/arrayed-output.desktop.sso.tesc b/third_party/spirv-cross/reference/opt/shaders-msl/desktop-only/tesc/arrayed-output.desktop.sso.tesc index a5e30b6de1..01fceeb6c7 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/desktop-only/tesc/arrayed-output.desktop.sso.tesc +++ b/third_party/spirv-cross/reference/opt/shaders-msl/desktop-only/tesc/arrayed-output.desktop.sso.tesc @@ -1,8 +1,49 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + #include #include using namespace metal; +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + struct main0_out { float3 vVertex; @@ -10,7 +51,7 @@ struct main0_out struct main0_patchOut { - float3 vPatch[2]; + spvUnsafeArray vPatch; }; struct main0_in @@ -28,7 +69,7 @@ kernel void main0(main0_in in [[stage_in]], uint gl_InvocationID [[thread_index_ if (gl_InvocationID >= 4) return; gl_out[gl_InvocationID].vVertex = gl_in[gl_InvocationID].vInput + gl_in[gl_InvocationID ^ 1].vInput; - threadgroup_barrier(mem_flags::mem_device); + threadgroup_barrier(mem_flags::mem_device | mem_flags::mem_threadgroup); if (gl_InvocationID == 0) { patchOut.vPatch[0] = float3(10.0); diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/desktop-only/tesc/struct-copy.desktop.sso.tesc b/third_party/spirv-cross/reference/opt/shaders-msl/desktop-only/tesc/struct-copy.desktop.sso.tesc index cd4d8d80e5..e7e184a980 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/desktop-only/tesc/struct-copy.desktop.sso.tesc +++ b/third_party/spirv-cross/reference/opt/shaders-msl/desktop-only/tesc/struct-copy.desktop.sso.tesc @@ -28,10 +28,8 @@ kernel void main0(main0_in in [[stage_in]], uint gl_InvocationID [[thread_index_ threadgroup_barrier(mem_flags::mem_threadgroup); if (gl_InvocationID >= 4) return; - Boo vInput_24; - vInput_24.a = gl_in[gl_InvocationID].Boo_a; - vInput_24.b = gl_in[gl_InvocationID].Boo_b; - gl_out[gl_InvocationID].vVertex = vInput_24; + Boo _25 = Boo{ gl_in[gl_InvocationID].Boo_a, gl_in[gl_InvocationID].Boo_b }; + gl_out[gl_InvocationID].vVertex = _25; spvTessLevel[gl_PrimitiveID].edgeTessellationFactor[0] = half(1.0); spvTessLevel[gl_PrimitiveID].edgeTessellationFactor[1] = half(2.0); spvTessLevel[gl_PrimitiveID].edgeTessellationFactor[2] = half(3.0); diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/desktop-only/vert/clip-cull-distance.desktop.vert b/third_party/spirv-cross/reference/opt/shaders-msl/desktop-only/vert/clip-cull-distance.desktop.vert index a414c98542..2d98929051 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/desktop-only/vert/clip-cull-distance.desktop.vert +++ b/third_party/spirv-cross/reference/opt/shaders-msl/desktop-only/vert/clip-cull-distance.desktop.vert @@ -7,6 +7,8 @@ struct main0_out { float4 gl_Position [[position]]; float gl_ClipDistance [[clip_distance]] [2]; + float gl_ClipDistance_0 [[user(clip0)]]; + float gl_ClipDistance_1 [[user(clip1)]]; }; vertex main0_out main0() @@ -15,6 +17,8 @@ vertex main0_out main0() out.gl_Position = float4(10.0); out.gl_ClipDistance[0] = 1.0; out.gl_ClipDistance[1] = 4.0; + out.gl_ClipDistance_0 = out.gl_ClipDistance[0]; + out.gl_ClipDistance_1 = out.gl_ClipDistance[1]; return out; } diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/desktop-only/vert/shader-draw-parameters.desktop.vert b/third_party/spirv-cross/reference/opt/shaders-msl/desktop-only/vert/shader-draw-parameters.desktop.vert index 1d203ba98b..a32c1948f8 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/desktop-only/vert/shader-draw-parameters.desktop.vert +++ b/third_party/spirv-cross/reference/opt/shaders-msl/desktop-only/vert/shader-draw-parameters.desktop.vert @@ -11,7 +11,7 @@ struct main0_out vertex main0_out main0(uint gl_BaseVertex [[base_vertex]], uint gl_BaseInstance [[base_instance]]) { main0_out out = {}; - out.gl_Position = float4(float(gl_BaseVertex), float(gl_BaseInstance), 0.0, 1.0); + out.gl_Position = float4(float(int(gl_BaseVertex)), float(int(gl_BaseInstance)), 0.0, 1.0); return out; } diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/frag/16bit-constants.invalid.frag b/third_party/spirv-cross/reference/opt/shaders-msl/frag/16bit-constants.invalid.frag deleted file mode 100644 index 56c7ea5df4..0000000000 --- a/third_party/spirv-cross/reference/opt/shaders-msl/frag/16bit-constants.invalid.frag +++ /dev/null @@ -1,21 +0,0 @@ -#include -#include - -using namespace metal; - -struct main0_out -{ - half foo [[color(0)]]; - short bar [[color(1)]]; - ushort baz [[color(2)]]; -}; - -fragment main0_out main0() -{ - main0_out out = {}; - out.foo = half(1.0); - out.bar = 2; - out.baz = 3u; - return out; -} - diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/frag/array-lut-no-loop-variable.frag b/third_party/spirv-cross/reference/opt/shaders-msl/frag/array-lut-no-loop-variable.frag index 9b757b6a31..79f9025a78 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/frag/array-lut-no-loop-variable.frag +++ b/third_party/spirv-cross/reference/opt/shaders-msl/frag/array-lut-no-loop-variable.frag @@ -1,9 +1,50 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + #include #include using namespace metal; -constant float _17[5] = { 1.0, 2.0, 3.0, 4.0, 5.0 }; +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +constant spvUnsafeArray _17 = spvUnsafeArray({ 1.0, 2.0, 3.0, 4.0, 5.0 }); struct main0_out { diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/frag/array-of-array-lut.frag b/third_party/spirv-cross/reference/opt/shaders-msl/frag/array-of-array-lut.frag new file mode 100644 index 0000000000..ba553824e7 --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders-msl/frag/array-of-array-lut.frag @@ -0,0 +1,68 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + +#include +#include + +using namespace metal; + +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +constant spvUnsafeArray _17 = spvUnsafeArray({ 1.0, 2.0, 3.0 }); +constant spvUnsafeArray _21 = spvUnsafeArray({ 4.0, 5.0, 6.0 }); +constant spvUnsafeArray, 2> _22 = spvUnsafeArray, 2>({ spvUnsafeArray({ 1.0, 2.0, 3.0 }), spvUnsafeArray({ 4.0, 5.0, 6.0 }) }); + +struct main0_out +{ + float vOutput [[color(0)]]; +}; + +struct main0_in +{ + int vIndex1 [[user(locn0)]]; + int vIndex2 [[user(locn1)]]; +}; + +fragment main0_out main0(main0_in in [[stage_in]]) +{ + main0_out out = {}; + out.vOutput = _22[in.vIndex1][in.vIndex2]; + return out; +} + diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/frag/array-of-texture-swizzle.msl2.argument.discrete.swizzle.frag b/third_party/spirv-cross/reference/opt/shaders-msl/frag/array-of-texture-swizzle.msl2.argument.discrete.swizzle.frag index 2160e0be61..bf91953341 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/frag/array-of-texture-swizzle.msl2.argument.discrete.swizzle.frag +++ b/third_party/spirv-cross/reference/opt/shaders-msl/frag/array-of-texture-swizzle.msl2.argument.discrete.swizzle.frag @@ -22,17 +22,6 @@ struct main0_in float2 vUV [[user(locn0)]]; }; -enum class spvSwizzle : uint -{ - none = 0, - zero, - one, - red, - green, - blue, - alpha -}; - template struct spvRemoveReference { typedef T type; }; template struct spvRemoveReference { typedef T type; }; template struct spvRemoveReference { typedef T type; }; @@ -45,6 +34,17 @@ template inline constexpr thread T&& spvForward(thread typename spvR return static_cast(x); } +enum class spvSwizzle : uint +{ + none = 0, + zero, + one, + red, + green, + blue, + alpha +}; + template inline T spvGetSwizzle(vec x, T c, spvSwizzle s) { @@ -82,66 +82,6 @@ inline T spvTextureSwizzle(T x, uint s) return spvTextureSwizzle(vec(x, 0, 0, 1), s).x; } -// Wrapper function that swizzles texture gathers. -template -inline vec spvGatherSwizzle(sampler s, const thread Tex& t, Ts... params, component c, uint sw) METAL_CONST_ARG(c) -{ - if (sw) - { - switch (spvSwizzle((sw >> (uint(c) * 8)) & 0xFF)) - { - case spvSwizzle::none: - break; - case spvSwizzle::zero: - return vec(0, 0, 0, 0); - case spvSwizzle::one: - return vec(1, 1, 1, 1); - case spvSwizzle::red: - return t.gather(s, spvForward(params)..., component::x); - case spvSwizzle::green: - return t.gather(s, spvForward(params)..., component::y); - case spvSwizzle::blue: - return t.gather(s, spvForward(params)..., component::z); - case spvSwizzle::alpha: - return t.gather(s, spvForward(params)..., component::w); - } - } - switch (c) - { - case component::x: - return t.gather(s, spvForward(params)..., component::x); - case component::y: - return t.gather(s, spvForward(params)..., component::y); - case component::z: - return t.gather(s, spvForward(params)..., component::z); - case component::w: - return t.gather(s, spvForward(params)..., component::w); - } -} - -// Wrapper function that swizzles depth texture gathers. -template -inline vec spvGatherCompareSwizzle(sampler s, const thread Tex& t, Ts... params, uint sw) -{ - if (sw) - { - switch (spvSwizzle(sw & 0xFF)) - { - case spvSwizzle::none: - case spvSwizzle::red: - break; - case spvSwizzle::zero: - case spvSwizzle::green: - case spvSwizzle::blue: - case spvSwizzle::alpha: - return vec(0, 0, 0, 0); - case spvSwizzle::one: - return vec(1, 1, 1, 1); - } - } - return t.gather_compare(s, spvForward(params)...); -} - fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]], constant uint* spvSwizzleConstants [[buffer(30)]], texture2d uSampler1 [[texture(0)]], sampler uSampler1Smplr [[sampler(0)]]) { main0_out out = {}; diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/frag/array-of-texture-swizzle.msl2.swizzle.frag b/third_party/spirv-cross/reference/opt/shaders-msl/frag/array-of-texture-swizzle.msl2.swizzle.frag index 337abb99d8..2f9aef1382 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/frag/array-of-texture-swizzle.msl2.swizzle.frag +++ b/third_party/spirv-cross/reference/opt/shaders-msl/frag/array-of-texture-swizzle.msl2.swizzle.frag @@ -15,17 +15,6 @@ struct main0_in float2 vUV [[user(locn0)]]; }; -enum class spvSwizzle : uint -{ - none = 0, - zero, - one, - red, - green, - blue, - alpha -}; - template struct spvRemoveReference { typedef T type; }; template struct spvRemoveReference { typedef T type; }; template struct spvRemoveReference { typedef T type; }; @@ -38,6 +27,17 @@ template inline constexpr thread T&& spvForward(thread typename spvR return static_cast(x); } +enum class spvSwizzle : uint +{ + none = 0, + zero, + one, + red, + green, + blue, + alpha +}; + template inline T spvGetSwizzle(vec x, T c, spvSwizzle s) { @@ -75,66 +75,6 @@ inline T spvTextureSwizzle(T x, uint s) return spvTextureSwizzle(vec(x, 0, 0, 1), s).x; } -// Wrapper function that swizzles texture gathers. -template -inline vec spvGatherSwizzle(sampler s, const thread Tex& t, Ts... params, component c, uint sw) METAL_CONST_ARG(c) -{ - if (sw) - { - switch (spvSwizzle((sw >> (uint(c) * 8)) & 0xFF)) - { - case spvSwizzle::none: - break; - case spvSwizzle::zero: - return vec(0, 0, 0, 0); - case spvSwizzle::one: - return vec(1, 1, 1, 1); - case spvSwizzle::red: - return t.gather(s, spvForward(params)..., component::x); - case spvSwizzle::green: - return t.gather(s, spvForward(params)..., component::y); - case spvSwizzle::blue: - return t.gather(s, spvForward(params)..., component::z); - case spvSwizzle::alpha: - return t.gather(s, spvForward(params)..., component::w); - } - } - switch (c) - { - case component::x: - return t.gather(s, spvForward(params)..., component::x); - case component::y: - return t.gather(s, spvForward(params)..., component::y); - case component::z: - return t.gather(s, spvForward(params)..., component::z); - case component::w: - return t.gather(s, spvForward(params)..., component::w); - } -} - -// Wrapper function that swizzles depth texture gathers. -template -inline vec spvGatherCompareSwizzle(sampler s, const thread Tex& t, Ts... params, uint sw) -{ - if (sw) - { - switch (spvSwizzle(sw & 0xFF)) - { - case spvSwizzle::none: - case spvSwizzle::red: - break; - case spvSwizzle::zero: - case spvSwizzle::green: - case spvSwizzle::blue: - case spvSwizzle::alpha: - return vec(0, 0, 0, 0); - case spvSwizzle::one: - return vec(1, 1, 1, 1); - } - } - return t.gather_compare(s, spvForward(params)...); -} - fragment main0_out main0(main0_in in [[stage_in]], constant uint* spvSwizzleConstants [[buffer(30)]], array, 4> uSampler [[texture(0)]], array uSamplerSmplr [[sampler(0)]]) { main0_out out = {}; diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/frag/buffer-read-write.frag b/third_party/spirv-cross/reference/opt/shaders-msl/frag/buffer-read-write.frag index 2b2ac7f060..166d4311ba 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/frag/buffer-read-write.frag +++ b/third_party/spirv-cross/reference/opt/shaders-msl/frag/buffer-read-write.frag @@ -11,6 +11,7 @@ struct main0_out }; // Returns 2D texture coords corresponding to 1D texel buffer coords +static inline __attribute__((always_inline)) uint2 spvTexelBufferCoord(uint tc) { return uint2(tc % 4096, tc / 4096); diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/frag/clip-distance-varying.frag b/third_party/spirv-cross/reference/opt/shaders-msl/frag/clip-distance-varying.frag new file mode 100644 index 0000000000..9a72d5ba39 --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders-msl/frag/clip-distance-varying.frag @@ -0,0 +1,67 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + +#include +#include + +using namespace metal; + +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +struct main0_out +{ + float4 FragColor [[color(0)]]; +}; + +struct main0_in +{ + float gl_ClipDistance_0 [[user(clip0)]]; + float gl_ClipDistance_1 [[user(clip1)]]; +}; + +fragment main0_out main0(main0_in in [[stage_in]]) +{ + main0_out out = {}; + spvUnsafeArray gl_ClipDistance = {}; + gl_ClipDistance[0] = in.gl_ClipDistance_0; + gl_ClipDistance[1] = in.gl_ClipDistance_1; + out.FragColor = float4((1.0 - gl_ClipDistance[0]) - gl_ClipDistance[1]); + return out; +} + diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/frag/constant-array.frag b/third_party/spirv-cross/reference/opt/shaders-msl/frag/constant-array.frag index a0b830daae..ca7efc5341 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/frag/constant-array.frag +++ b/third_party/spirv-cross/reference/opt/shaders-msl/frag/constant-array.frag @@ -1,19 +1,59 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + #include #include using namespace metal; +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + struct Foobar { float a; float b; }; -constant float4 _37[3] = { float4(1.0), float4(2.0), float4(3.0) }; -constant float4 _49[2] = { float4(1.0), float4(2.0) }; -constant float4 _54[2] = { float4(8.0), float4(10.0) }; -constant float4 _55[2][2] = { { float4(1.0), float4(2.0) }, { float4(8.0), float4(10.0) } }; -constant Foobar _75[2] = { Foobar{ 10.0, 40.0 }, Foobar{ 90.0, 70.0 } }; +constant spvUnsafeArray _37 = spvUnsafeArray({ float4(1.0), float4(2.0), float4(3.0) }); +constant spvUnsafeArray _49 = spvUnsafeArray({ float4(1.0), float4(2.0) }); +constant spvUnsafeArray _54 = spvUnsafeArray({ float4(8.0), float4(10.0) }); +constant spvUnsafeArray, 2> _55 = spvUnsafeArray, 2>({ spvUnsafeArray({ float4(1.0), float4(2.0) }), spvUnsafeArray({ float4(8.0), float4(10.0) }) }); struct main0_out { @@ -27,6 +67,8 @@ struct main0_in fragment main0_out main0(main0_in in [[stage_in]]) { + spvUnsafeArray _75 = spvUnsafeArray({ Foobar{ 10.0, 40.0 }, Foobar{ 90.0, 70.0 } }); + main0_out out = {}; out.FragColor = ((_37[in.index] + _55[in.index][in.index + 1]) + float4(30.0)) + float4(_75[in.index].a + _75[in.index].b); return out; diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/frag/constant-composites.frag b/third_party/spirv-cross/reference/opt/shaders-msl/frag/constant-composites.frag index 335cbcd796..e0fa980fb8 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/frag/constant-composites.frag +++ b/third_party/spirv-cross/reference/opt/shaders-msl/frag/constant-composites.frag @@ -1,16 +1,56 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + #include #include using namespace metal; +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + struct Foo { float a; float b; }; -constant float _16[4] = { 1.0, 4.0, 3.0, 2.0 }; -constant Foo _28[2] = { Foo{ 10.0, 20.0 }, Foo{ 30.0, 40.0 } }; +constant spvUnsafeArray _16 = spvUnsafeArray({ 1.0, 4.0, 3.0, 2.0 }); struct main0_out { @@ -24,6 +64,8 @@ struct main0_in fragment main0_out main0(main0_in in [[stage_in]]) { + spvUnsafeArray _28 = spvUnsafeArray({ Foo{ 10.0, 20.0 }, Foo{ 30.0, 40.0 } }); + main0_out out = {}; out.FragColor = float4(_16[in.line]); out.FragColor += float4(_28[in.line].a * _28[1 - in.line].a); diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/frag/for-loop-init.frag b/third_party/spirv-cross/reference/opt/shaders-msl/frag/for-loop-init.frag index cef6e11d37..c57aa1bd1e 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/frag/for-loop-init.frag +++ b/third_party/spirv-cross/reference/opt/shaders-msl/frag/for-loop-init.frag @@ -11,62 +11,63 @@ struct main0_out fragment main0_out main0() { main0_out out = {}; - int _145; - for (;;) + switch (0u) { - out.FragColor = 16; - _145 = 0; - for (; _145 < 25; ) + default: { - out.FragColor += 10; - _145++; - continue; - } - for (int _146 = 1; _146 < 30; ) - { - out.FragColor += 11; - _146++; - continue; - } - int _147; - _147 = 0; - for (; _147 < 20; ) - { - out.FragColor += 12; - _147++; - continue; - } - int _62 = _147 + 3; - out.FragColor += _62; - if (_62 == 40) - { - for (int _151 = 0; _151 < 40; ) + out.FragColor = 16; + for (int _143 = 0; _143 < 25; ) { - out.FragColor += 13; - _151++; + out.FragColor += 10; + _143++; continue; } + for (int _144 = 1; _144 < 30; ) + { + out.FragColor += 11; + _144++; + continue; + } + int _145; + _145 = 0; + for (; _145 < 20; ) + { + out.FragColor += 12; + _145++; + continue; + } + int _62 = _145 + 3; + out.FragColor += _62; + if (_62 == 40) + { + for (int _149 = 0; _149 < 40; ) + { + out.FragColor += 13; + _149++; + continue; + } + break; + } + out.FragColor += _62; + int2 _146; + _146 = int2(0); + for (; _146.x < 10; ) + { + out.FragColor += _146.y; + int2 _142 = _146; + _142.x = _146.x + 4; + _146 = _142; + continue; + } + for (int _148 = _62; _148 < 40; ) + { + out.FragColor += _148; + _148++; + continue; + } + out.FragColor += _62; break; } - out.FragColor += _62; - int2 _148; - _148 = int2(0); - for (; _148.x < 10; ) - { - out.FragColor += _148.y; - int2 _144 = _148; - _144.x = _148.x + 4; - _148 = _144; - continue; - } - for (int _150 = _62; _150 < 40; ) - { - out.FragColor += _150; - _150++; - continue; - } - out.FragColor += _62; - break; } return out; } diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/frag/fp16.desktop.invalid.frag b/third_party/spirv-cross/reference/opt/shaders-msl/frag/fp16.desktop.invalid.frag deleted file mode 100644 index d9a0390e1f..0000000000 --- a/third_party/spirv-cross/reference/opt/shaders-msl/frag/fp16.desktop.invalid.frag +++ /dev/null @@ -1,16 +0,0 @@ -#include -#include - -using namespace metal; - -struct main0_in -{ - half4 v4 [[user(locn3)]]; -}; - -fragment void main0(main0_in in [[stage_in]]) -{ - half4 _491; - half4 _563 = modf(in.v4, _491); -} - diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/frag/fragment-component-padding.pad-fragment.frag b/third_party/spirv-cross/reference/opt/shaders-msl/frag/fragment-component-padding.pad-fragment.frag index 53aafa5f7f..19840fa434 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/frag/fragment-component-padding.pad-fragment.frag +++ b/third_party/spirv-cross/reference/opt/shaders-msl/frag/fragment-component-padding.pad-fragment.frag @@ -1,8 +1,49 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + #include #include using namespace metal; +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + struct main0_out { float4 FragColors_0 [[color(0)]]; @@ -19,7 +60,7 @@ struct main0_in fragment main0_out main0(main0_in in [[stage_in]]) { main0_out out = {}; - float FragColors[2] = {}; + spvUnsafeArray FragColors = {}; float2 FragColor2 = {}; float3 FragColor3 = {}; FragColors[0] = in.vColor.x; @@ -28,8 +69,8 @@ fragment main0_out main0(main0_in in [[stage_in]]) FragColor3 = in.vColor.zzz; out.FragColors_0 = float4(FragColors[0]); out.FragColors_1 = float4(FragColors[1]); - out.FragColor2 = FragColor2.xyyy; - out.FragColor3 = FragColor3.xyzz; + out.FragColor2.xy = FragColor2; + out.FragColor3.xyz = FragColor3; return out; } diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/frag/huge-argument-buffer.device-argument-buffer.argument.msl2.frag b/third_party/spirv-cross/reference/opt/shaders-msl/frag/huge-argument-buffer.device-argument-buffer.argument.msl2.frag new file mode 100644 index 0000000000..0c6e6f4991 --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders-msl/frag/huge-argument-buffer.device-argument-buffer.argument.msl2.frag @@ -0,0 +1,44 @@ +#include +#include + +using namespace metal; + +struct UBO +{ + float4 v; +}; + +struct spvDescriptorSetBuffer0 +{ + array, 10000> uSamplers [[id(0)]]; + array uSamplersSmplr [[id(10000)]]; +}; + +struct spvDescriptorSetBuffer1 +{ + constant UBO* vs [[id(0)]][10000]; +}; + +struct spvDescriptorSetBuffer2 +{ + texture2d uSampler [[id(0)]]; + sampler uSamplerSmplr [[id(1)]]; +}; + +struct main0_out +{ + float4 FragColor [[color(0)]]; +}; + +struct main0_in +{ + float2 vUV [[user(locn0)]]; +}; + +fragment main0_out main0(main0_in in [[stage_in]], const device spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]], const device spvDescriptorSetBuffer1& spvDescriptorSet1 [[buffer(1)]], constant spvDescriptorSetBuffer2& spvDescriptorSet2 [[buffer(2)]]) +{ + main0_out out = {}; + out.FragColor = (spvDescriptorSet0.uSamplers[9999].sample(spvDescriptorSet0.uSamplersSmplr[9999], in.vUV) + spvDescriptorSet1.vs[5000]->v) + spvDescriptorSet2.uSampler.sample(spvDescriptorSet2.uSamplerSmplr, in.vUV); + return out; +} + diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/frag/lut-promotion.frag b/third_party/spirv-cross/reference/opt/shaders-msl/frag/lut-promotion.frag index c9169b790d..e24bcd6d11 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/frag/lut-promotion.frag +++ b/third_party/spirv-cross/reference/opt/shaders-msl/frag/lut-promotion.frag @@ -1,13 +1,52 @@ #pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" #include #include using namespace metal; -constant float _16[16] = { 1.0, 2.0, 3.0, 4.0, 1.0, 2.0, 3.0, 4.0, 1.0, 2.0, 3.0, 4.0, 1.0, 2.0, 3.0, 4.0 }; -constant float4 _60[4] = { float4(0.0), float4(1.0), float4(8.0), float4(5.0) }; -constant float4 _104[4] = { float4(20.0), float4(30.0), float4(50.0), float4(60.0) }; +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +constant spvUnsafeArray _16 = spvUnsafeArray({ 1.0, 2.0, 3.0, 4.0, 1.0, 2.0, 3.0, 4.0, 1.0, 2.0, 3.0, 4.0, 1.0, 2.0, 3.0, 4.0 }); +constant spvUnsafeArray _60 = spvUnsafeArray({ float4(0.0), float4(1.0), float4(8.0), float4(5.0) }); +constant spvUnsafeArray _104 = spvUnsafeArray({ float4(20.0), float4(30.0), float4(50.0), float4(60.0) }); struct main0_out { @@ -19,19 +58,6 @@ struct main0_in int index [[user(locn0)]]; }; -// Implementation of an array copy function to cover GLSL's ability to copy an array via assignment. -template -void spvArrayCopyFromStack1(thread T (&dst)[N], thread const T (&src)[N]) -{ - for (uint i = 0; i < N; dst[i] = src[i], i++); -} - -template -void spvArrayCopyFromConstant1(thread T (&dst)[N], constant T (&src)[N]) -{ - for (uint i = 0; i < N; dst[i] = src[i], i++); -} - fragment main0_out main0(main0_in in [[stage_in]]) { main0_out out = {}; @@ -53,7 +79,7 @@ fragment main0_out main0(main0_in in [[stage_in]]) { out.FragColor += _60[in.index & 1].x; } - float4 foobar[4] = { float4(0.0), float4(1.0), float4(8.0), float4(5.0) }; + spvUnsafeArray foobar = spvUnsafeArray({ float4(0.0), float4(1.0), float4(8.0), float4(5.0) }); if (_63) { foobar[1].z = 20.0; diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/frag/mrt-array.frag b/third_party/spirv-cross/reference/opt/shaders-msl/frag/mrt-array.frag index d7cea6baf9..79fc0391b5 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/frag/mrt-array.frag +++ b/third_party/spirv-cross/reference/opt/shaders-msl/frag/mrt-array.frag @@ -1,10 +1,49 @@ #pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" #include #include using namespace metal; +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + struct main0_out { float4 FragColor_0 [[color(0)]]; @@ -21,7 +60,7 @@ struct main0_in // Implementation of the GLSL mod() function, which is slightly different than Metal fmod() template -Tx mod(Tx x, Ty y) +inline Tx mod(Tx x, Ty y) { return x - y * floor(x / y); } @@ -29,7 +68,7 @@ Tx mod(Tx x, Ty y) fragment main0_out main0(main0_in in [[stage_in]]) { main0_out out = {}; - float4 FragColor[4] = {}; + spvUnsafeArray FragColor = {}; FragColor[0] = mod(in.vA, in.vB); FragColor[1] = in.vA + in.vB; FragColor[2] = in.vA - in.vB; diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/frag/pixel-interlock-ordered.msl2.argument.frag b/third_party/spirv-cross/reference/opt/shaders-msl/frag/pixel-interlock-ordered.msl2.argument.frag new file mode 100644 index 0000000000..f77b8ed99e --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders-msl/frag/pixel-interlock-ordered.msl2.argument.frag @@ -0,0 +1,43 @@ +#pragma clang diagnostic ignored "-Wunused-variable" + +#include +#include +#include + +using namespace metal; + +struct Buffer3 +{ + int baz; +}; + +struct Buffer +{ + int foo; + uint bar; +}; + +struct Buffer2 +{ + uint quux; +}; + +struct spvDescriptorSetBuffer0 +{ + device Buffer3* m_9 [[id(0)]]; + texture2d img4 [[id(1)]]; + texture2d img [[id(2), raster_order_group(0)]]; + texture2d img3 [[id(3), raster_order_group(0)]]; + volatile device Buffer* m_34 [[id(4), raster_order_group(0)]]; + device Buffer2* m_44 [[id(5), raster_order_group(0)]]; +}; + +fragment void main0(constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]]) +{ + (*spvDescriptorSet0.m_9).baz = 0; + spvDescriptorSet0.img4.write(float4(1.0, 0.0, 0.0, 1.0), uint2(int2(1))); + spvDescriptorSet0.img.write(spvDescriptorSet0.img3.read(uint2(int2(0))), uint2(int2(0))); + (*spvDescriptorSet0.m_34).foo += 42; + uint _49 = atomic_fetch_and_explicit((volatile device atomic_uint*)&(*spvDescriptorSet0.m_34).bar, (*spvDescriptorSet0.m_44).quux, memory_order_relaxed); +} + diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/frag/pixel-interlock-ordered.msl2.frag b/third_party/spirv-cross/reference/opt/shaders-msl/frag/pixel-interlock-ordered.msl2.frag new file mode 100644 index 0000000000..803416c669 --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders-msl/frag/pixel-interlock-ordered.msl2.frag @@ -0,0 +1,33 @@ +#pragma clang diagnostic ignored "-Wunused-variable" + +#include +#include +#include + +using namespace metal; + +struct Buffer3 +{ + int baz; +}; + +struct Buffer +{ + int foo; + uint bar; +}; + +struct Buffer2 +{ + uint quux; +}; + +fragment void main0(device Buffer3& _9 [[buffer(0)]], volatile device Buffer& _34 [[buffer(1), raster_order_group(0)]], device Buffer2& _44 [[buffer(2), raster_order_group(0)]], texture2d img4 [[texture(0)]], texture2d img [[texture(1), raster_order_group(0)]], texture2d img3 [[texture(2), raster_order_group(0)]]) +{ + _9.baz = 0; + img4.write(float4(1.0, 0.0, 0.0, 1.0), uint2(int2(1))); + img.write(img3.read(uint2(int2(0))), uint2(int2(0))); + _34.foo += 42; + uint _49 = atomic_fetch_and_explicit((volatile device atomic_uint*)&_34.bar, _44.quux, memory_order_relaxed); +} + diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/frag/sample-depth-propagate-state-from-resource.frag b/third_party/spirv-cross/reference/opt/shaders-msl/frag/sample-depth-propagate-state-from-resource.frag new file mode 100644 index 0000000000..4f7e9b53b2 --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders-msl/frag/sample-depth-propagate-state-from-resource.frag @@ -0,0 +1,23 @@ +#include +#include + +using namespace metal; + +struct main0_out +{ + float FragColor [[color(0)]]; +}; + +struct main0_in +{ + float3 vUV [[user(locn0)]]; +}; + +fragment main0_out main0(main0_in in [[stage_in]], depth2d uTexture [[texture(0)]], sampler uSampler [[sampler(0)]], sampler uSamplerShadow [[sampler(1)]]) +{ + main0_out out = {}; + out.FragColor = float4(uTexture.sample(uSampler, in.vUV.xy)).x; + out.FragColor += uTexture.sample_compare(uSamplerShadow, in.vUV.xy, in.vUV.z); + return out; +} + diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/frag/shader-arithmetic-8bit.frag b/third_party/spirv-cross/reference/opt/shaders-msl/frag/shader-arithmetic-8bit.frag index 30b28d2131..325e300b7c 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/frag/shader-arithmetic-8bit.frag +++ b/third_party/spirv-cross/reference/opt/shaders-msl/frag/shader-arithmetic-8bit.frag @@ -35,21 +35,23 @@ struct main0_in fragment main0_out main0(main0_in in [[stage_in]], device SSBO& ssbo [[buffer(0)]], constant Push& registers [[buffer(1)]], constant UBO& ubo [[buffer(2)]]) { main0_out out = {}; - short _196 = 10; + short _196 = short(10); int _197 = 20; - char2 _198 = as_type(_196); - char4 _199 = as_type(_197); - _196 = as_type(_198); + char2 _201 = as_type(short(10)); + char2 _198 = _201; + char4 _199 = as_type(20); + _196 = as_type(_201); _197 = as_type(_199); ssbo.i8[0] = _199.x; ssbo.i8[1] = _199.y; ssbo.i8[2] = _199.z; ssbo.i8[3] = _199.w; - ushort _220 = 10u; + ushort _220 = ushort(10); uint _221 = 20u; - uchar2 _222 = as_type(_220); - uchar4 _223 = as_type(_221); - _220 = as_type(_222); + uchar2 _225 = as_type(ushort(10)); + uchar2 _222 = _225; + uchar4 _223 = as_type(20u); + _220 = as_type(_225); _221 = as_type(_223); ssbo.u8[0] = _223.x; ssbo.u8[1] = _223.y; @@ -57,21 +59,34 @@ fragment main0_out main0(main0_in in [[stage_in]], device SSBO& ssbo [[buffer(0) ssbo.u8[3] = _223.w; char4 _246 = char4(in.vColor); char4 _244 = _246; - _244 += char4(registers.i8); - _244 += char4(-40); - _244 += char4(-50); - _244 += char4(char(10), char(20), char(30), char(40)); - _244 += char4(ssbo.i8[4]); - _244 += char4(ubo.i8); - out.FragColorInt = int4(_244); - uchar4 _271 = uchar4(_246); - _271 += uchar4(registers.u8); - _271 += uchar4(216); - _271 += uchar4(206); - _271 += uchar4(uchar(10), uchar(20), uchar(30), uchar(40)); - _271 += uchar4(ssbo.u8[4]); - _271 += uchar4(ubo.u8); - out.FragColorUint = uint4(_271); + char4 _251 = _246 + char4(registers.i8); + _244 = _251; + char4 _254 = _251 + char4(-40); + _244 = _254; + char4 _256 = _254 + char4(-50); + _244 = _256; + char4 _258 = _256 + char4(char(10), char(20), char(30), char(40)); + _244 = _258; + char4 _263 = _258 + char4(ssbo.i8[4]); + _244 = _263; + char4 _268 = _263 + char4(ubo.i8); + _244 = _268; + out.FragColorInt = int4(_268); + uchar4 _274 = uchar4(_246); + uchar4 _271 = _274; + uchar4 _279 = _274 + uchar4(registers.u8); + _271 = _279; + uchar4 _282 = _279 + uchar4(216); + _271 = _282; + uchar4 _284 = _282 + uchar4(206); + _271 = _284; + uchar4 _286 = _284 + uchar4(uchar(10), uchar(20), uchar(30), uchar(40)); + _271 = _286; + uchar4 _291 = _286 + uchar4(ssbo.u8[4]); + _271 = _291; + uchar4 _296 = _291 + uchar4(ubo.u8); + _271 = _296; + out.FragColorUint = uint4(_296); return out; } diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/frag/shadow-compare-global-alias.invalid.frag b/third_party/spirv-cross/reference/opt/shaders-msl/frag/shadow-compare-global-alias.invalid.frag deleted file mode 100644 index a58f13fc40..0000000000 --- a/third_party/spirv-cross/reference/opt/shaders-msl/frag/shadow-compare-global-alias.invalid.frag +++ /dev/null @@ -1,27 +0,0 @@ -#include -#include - -using namespace metal; - -struct main0_out -{ - float FragColor [[color(0)]]; -}; - -struct main0_in -{ - float3 vUV [[user(locn0)]]; -}; - -fragment main0_out main0(main0_in in [[stage_in]], depth2d uTex [[texture(0)]], depth2d uSampler [[texture(1)]], sampler uSamp [[sampler(0)]], sampler uSamplerSmplr [[sampler(1)]]) -{ - main0_out out = {}; - out.FragColor = uSampler.sample_compare(uSamplerSmplr, in.vUV.xy, in.vUV.z); - out.FragColor += uTex.sample_compare(uSamp, in.vUV.xy, in.vUV.z); - out.FragColor += uTex.sample_compare(uSamp, in.vUV.xy, in.vUV.z); - out.FragColor += uSampler.sample_compare(uSamplerSmplr, in.vUV.xy, in.vUV.z); - out.FragColor += uTex.sample_compare(uSamp, in.vUV.xy, in.vUV.z); - out.FragColor += uSampler.sample_compare(uSamplerSmplr, in.vUV.xy, in.vUV.z); - return out; -} - diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/frag/texture-cube-array.frag b/third_party/spirv-cross/reference/opt/shaders-msl/frag/texture-cube-array.frag new file mode 100644 index 0000000000..0af8a047b3 --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders-msl/frag/texture-cube-array.frag @@ -0,0 +1,22 @@ +#include +#include + +using namespace metal; + +struct main0_out +{ + float4 FragColor [[color(0)]]; +}; + +struct main0_in +{ + float4 vUV [[user(locn0)]]; +}; + +fragment main0_out main0(main0_in in [[stage_in]], texturecube cubeSampler [[texture(0)]], texturecube_array cubeArraySampler [[texture(1)]], texture2d_array texArraySampler [[texture(2)]], sampler cubeSamplerSmplr [[sampler(0)]], sampler cubeArraySamplerSmplr [[sampler(1)]], sampler texArraySamplerSmplr [[sampler(2)]]) +{ + main0_out out = {}; + out.FragColor = (cubeSampler.sample(cubeSamplerSmplr, in.vUV.xyz) + cubeArraySampler.sample(cubeArraySamplerSmplr, in.vUV.xyz, uint(round(in.vUV.w)))) + texArraySampler.sample(texArraySamplerSmplr, in.vUV.xyz.xy, uint(round(in.vUV.xyz.z))); + return out; +} + diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/frag/texture-cube-array.ios.emulate-cube-array.frag b/third_party/spirv-cross/reference/opt/shaders-msl/frag/texture-cube-array.ios.emulate-cube-array.frag new file mode 100644 index 0000000000..217a7a9e20 --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders-msl/frag/texture-cube-array.ios.emulate-cube-array.frag @@ -0,0 +1,58 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" + +#include +#include + +using namespace metal; + +struct main0_out +{ + float4 FragColor [[color(0)]]; +}; + +struct main0_in +{ + float4 vUV [[user(locn0)]]; +}; + +static inline __attribute__((always_inline)) +float3 spvCubemapTo2DArrayFace(float3 P) +{ + float3 Coords = abs(P.xyz); + float CubeFace = 0; + float ProjectionAxis = 0; + float u = 0; + float v = 0; + if (Coords.x >= Coords.y && Coords.x >= Coords.z) + { + CubeFace = P.x >= 0 ? 0 : 1; + ProjectionAxis = Coords.x; + u = P.x >= 0 ? -P.z : P.z; + v = -P.y; + } + else if (Coords.y >= Coords.x && Coords.y >= Coords.z) + { + CubeFace = P.y >= 0 ? 2 : 3; + ProjectionAxis = Coords.y; + u = P.x; + v = P.y >= 0 ? P.z : -P.z; + } + else + { + CubeFace = P.z >= 0 ? 4 : 5; + ProjectionAxis = Coords.z; + u = P.z >= 0 ? P.x : -P.x; + v = -P.y; + } + u = 0.5 * (u/ProjectionAxis + 1); + v = 0.5 * (v/ProjectionAxis + 1); + return float3(u, v, CubeFace); +} + +fragment main0_out main0(main0_in in [[stage_in]], texturecube cubeSampler [[texture(0)]], texture2d_array cubeArraySampler [[texture(1)]], texture2d_array texArraySampler [[texture(2)]], sampler cubeSamplerSmplr [[sampler(0)]], sampler cubeArraySamplerSmplr [[sampler(1)]], sampler texArraySamplerSmplr [[sampler(2)]]) +{ + main0_out out = {}; + out.FragColor = (cubeSampler.sample(cubeSamplerSmplr, in.vUV.xyz) + cubeArraySampler.sample(cubeArraySamplerSmplr, spvCubemapTo2DArrayFace(in.vUV.xyz).xy, uint(spvCubemapTo2DArrayFace(in.vUV.xyz).z) + (uint(round(in.vUV.w)) * 6u))) + texArraySampler.sample(texArraySamplerSmplr, in.vUV.xyz.xy, uint(round(in.vUV.xyz.z))); + return out; +} + diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/tesc/load-control-point-array-of-matrix.tesc b/third_party/spirv-cross/reference/opt/shaders-msl/tesc/load-control-point-array-of-matrix.tesc new file mode 100644 index 0000000000..46d4b4ad58 --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders-msl/tesc/load-control-point-array-of-matrix.tesc @@ -0,0 +1,73 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + +#include +#include + +using namespace metal; + +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +struct main0_out +{ + float4x4 vOutputs; +}; + +struct main0_in +{ + float4 vInputs_0 [[attribute(0)]]; + float4 vInputs_1 [[attribute(1)]]; + float4 vInputs_2 [[attribute(2)]]; + float4 vInputs_3 [[attribute(3)]]; +}; + +kernel void main0(main0_in in [[stage_in]], uint gl_InvocationID [[thread_index_in_threadgroup]], uint gl_PrimitiveID [[threadgroup_position_in_grid]], device main0_out* spvOut [[buffer(28)]], constant uint* spvIndirectParams [[buffer(29)]], device MTLQuadTessellationFactorsHalf* spvTessLevel [[buffer(26)]], threadgroup main0_in* gl_in [[threadgroup(0)]]) +{ + device main0_out* gl_out = &spvOut[gl_PrimitiveID * 4]; + if (gl_InvocationID < spvIndirectParams[0]) + gl_in[gl_InvocationID] = in; + threadgroup_barrier(mem_flags::mem_threadgroup); + if (gl_InvocationID >= 4) + return; + spvUnsafeArray _16 = spvUnsafeArray({ float4x4(gl_in[0].vInputs_0, gl_in[0].vInputs_1, gl_in[0].vInputs_2, gl_in[0].vInputs_3), float4x4(gl_in[1].vInputs_0, gl_in[1].vInputs_1, gl_in[1].vInputs_2, gl_in[1].vInputs_3), float4x4(gl_in[2].vInputs_0, gl_in[2].vInputs_1, gl_in[2].vInputs_2, gl_in[2].vInputs_3), float4x4(gl_in[3].vInputs_0, gl_in[3].vInputs_1, gl_in[3].vInputs_2, gl_in[3].vInputs_3), float4x4(gl_in[4].vInputs_0, gl_in[4].vInputs_1, gl_in[4].vInputs_2, gl_in[4].vInputs_3), float4x4(gl_in[5].vInputs_0, gl_in[5].vInputs_1, gl_in[5].vInputs_2, gl_in[5].vInputs_3), float4x4(gl_in[6].vInputs_0, gl_in[6].vInputs_1, gl_in[6].vInputs_2, gl_in[6].vInputs_3), float4x4(gl_in[7].vInputs_0, gl_in[7].vInputs_1, gl_in[7].vInputs_2, gl_in[7].vInputs_3), float4x4(gl_in[8].vInputs_0, gl_in[8].vInputs_1, gl_in[8].vInputs_2, gl_in[8].vInputs_3), float4x4(gl_in[9].vInputs_0, gl_in[9].vInputs_1, gl_in[9].vInputs_2, gl_in[9].vInputs_3), float4x4(gl_in[10].vInputs_0, gl_in[10].vInputs_1, gl_in[10].vInputs_2, gl_in[10].vInputs_3), float4x4(gl_in[11].vInputs_0, gl_in[11].vInputs_1, gl_in[11].vInputs_2, gl_in[11].vInputs_3), float4x4(gl_in[12].vInputs_0, gl_in[12].vInputs_1, gl_in[12].vInputs_2, gl_in[12].vInputs_3), float4x4(gl_in[13].vInputs_0, gl_in[13].vInputs_1, gl_in[13].vInputs_2, gl_in[13].vInputs_3), float4x4(gl_in[14].vInputs_0, gl_in[14].vInputs_1, gl_in[14].vInputs_2, gl_in[14].vInputs_3), float4x4(gl_in[15].vInputs_0, gl_in[15].vInputs_1, gl_in[15].vInputs_2, gl_in[15].vInputs_3), float4x4(gl_in[16].vInputs_0, gl_in[16].vInputs_1, gl_in[16].vInputs_2, gl_in[16].vInputs_3), float4x4(gl_in[17].vInputs_0, gl_in[17].vInputs_1, gl_in[17].vInputs_2, gl_in[17].vInputs_3), float4x4(gl_in[18].vInputs_0, gl_in[18].vInputs_1, gl_in[18].vInputs_2, gl_in[18].vInputs_3), float4x4(gl_in[19].vInputs_0, gl_in[19].vInputs_1, gl_in[19].vInputs_2, gl_in[19].vInputs_3), float4x4(gl_in[20].vInputs_0, gl_in[20].vInputs_1, gl_in[20].vInputs_2, gl_in[20].vInputs_3), float4x4(gl_in[21].vInputs_0, gl_in[21].vInputs_1, gl_in[21].vInputs_2, gl_in[21].vInputs_3), float4x4(gl_in[22].vInputs_0, gl_in[22].vInputs_1, gl_in[22].vInputs_2, gl_in[22].vInputs_3), float4x4(gl_in[23].vInputs_0, gl_in[23].vInputs_1, gl_in[23].vInputs_2, gl_in[23].vInputs_3), float4x4(gl_in[24].vInputs_0, gl_in[24].vInputs_1, gl_in[24].vInputs_2, gl_in[24].vInputs_3), float4x4(gl_in[25].vInputs_0, gl_in[25].vInputs_1, gl_in[25].vInputs_2, gl_in[25].vInputs_3), float4x4(gl_in[26].vInputs_0, gl_in[26].vInputs_1, gl_in[26].vInputs_2, gl_in[26].vInputs_3), float4x4(gl_in[27].vInputs_0, gl_in[27].vInputs_1, gl_in[27].vInputs_2, gl_in[27].vInputs_3), float4x4(gl_in[28].vInputs_0, gl_in[28].vInputs_1, gl_in[28].vInputs_2, gl_in[28].vInputs_3), float4x4(gl_in[29].vInputs_0, gl_in[29].vInputs_1, gl_in[29].vInputs_2, gl_in[29].vInputs_3), float4x4(gl_in[30].vInputs_0, gl_in[30].vInputs_1, gl_in[30].vInputs_2, gl_in[30].vInputs_3), float4x4(gl_in[31].vInputs_0, gl_in[31].vInputs_1, gl_in[31].vInputs_2, gl_in[31].vInputs_3) }); + spvUnsafeArray tmp; + tmp = _16; + gl_out[gl_InvocationID].vOutputs = tmp[gl_InvocationID]; +} + diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/tesc/load-control-point-array-of-struct.tesc b/third_party/spirv-cross/reference/opt/shaders-msl/tesc/load-control-point-array-of-struct.tesc new file mode 100644 index 0000000000..fc2cec1c3f --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders-msl/tesc/load-control-point-array-of-struct.tesc @@ -0,0 +1,84 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + +#include +#include + +using namespace metal; + +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +struct VertexData +{ + float4x4 a; + spvUnsafeArray b; + float4 c; +}; + +struct main0_out +{ + float4 vOutputs; +}; + +struct main0_in +{ + float4 VertexData_a_0 [[attribute(0)]]; + float4 VertexData_a_1 [[attribute(1)]]; + float4 VertexData_a_2 [[attribute(2)]]; + float4 VertexData_a_3 [[attribute(3)]]; + float4 VertexData_b_0 [[attribute(4)]]; + float4 VertexData_b_1 [[attribute(5)]]; + float4 VertexData_c [[attribute(6)]]; +}; + +kernel void main0(main0_in in [[stage_in]], uint gl_InvocationID [[thread_index_in_threadgroup]], uint gl_PrimitiveID [[threadgroup_position_in_grid]], device main0_out* spvOut [[buffer(28)]], constant uint* spvIndirectParams [[buffer(29)]], device MTLQuadTessellationFactorsHalf* spvTessLevel [[buffer(26)]], threadgroup main0_in* gl_in [[threadgroup(0)]]) +{ + device main0_out* gl_out = &spvOut[gl_PrimitiveID * 4]; + if (gl_InvocationID < spvIndirectParams[0]) + gl_in[gl_InvocationID] = in; + threadgroup_barrier(mem_flags::mem_threadgroup); + if (gl_InvocationID >= 4) + return; + spvUnsafeArray _19 = spvUnsafeArray({ VertexData{ float4x4(gl_in[0].VertexData_a_0, gl_in[0].VertexData_a_1, gl_in[0].VertexData_a_2, gl_in[0].VertexData_a_3), spvUnsafeArray({ gl_in[0].VertexData_b_0, gl_in[0].VertexData_b_1 }), gl_in[0].VertexData_c }, VertexData{ float4x4(gl_in[1].VertexData_a_0, gl_in[1].VertexData_a_1, gl_in[1].VertexData_a_2, gl_in[1].VertexData_a_3), spvUnsafeArray({ gl_in[1].VertexData_b_0, gl_in[1].VertexData_b_1 }), gl_in[1].VertexData_c }, VertexData{ float4x4(gl_in[2].VertexData_a_0, gl_in[2].VertexData_a_1, gl_in[2].VertexData_a_2, gl_in[2].VertexData_a_3), spvUnsafeArray({ gl_in[2].VertexData_b_0, gl_in[2].VertexData_b_1 }), gl_in[2].VertexData_c }, VertexData{ float4x4(gl_in[3].VertexData_a_0, gl_in[3].VertexData_a_1, gl_in[3].VertexData_a_2, gl_in[3].VertexData_a_3), spvUnsafeArray({ gl_in[3].VertexData_b_0, gl_in[3].VertexData_b_1 }), gl_in[3].VertexData_c }, VertexData{ float4x4(gl_in[4].VertexData_a_0, gl_in[4].VertexData_a_1, gl_in[4].VertexData_a_2, gl_in[4].VertexData_a_3), spvUnsafeArray({ gl_in[4].VertexData_b_0, gl_in[4].VertexData_b_1 }), gl_in[4].VertexData_c }, VertexData{ float4x4(gl_in[5].VertexData_a_0, gl_in[5].VertexData_a_1, gl_in[5].VertexData_a_2, gl_in[5].VertexData_a_3), spvUnsafeArray({ gl_in[5].VertexData_b_0, gl_in[5].VertexData_b_1 }), gl_in[5].VertexData_c }, VertexData{ float4x4(gl_in[6].VertexData_a_0, gl_in[6].VertexData_a_1, gl_in[6].VertexData_a_2, gl_in[6].VertexData_a_3), spvUnsafeArray({ gl_in[6].VertexData_b_0, gl_in[6].VertexData_b_1 }), gl_in[6].VertexData_c }, VertexData{ float4x4(gl_in[7].VertexData_a_0, gl_in[7].VertexData_a_1, gl_in[7].VertexData_a_2, gl_in[7].VertexData_a_3), spvUnsafeArray({ gl_in[7].VertexData_b_0, gl_in[7].VertexData_b_1 }), gl_in[7].VertexData_c }, VertexData{ float4x4(gl_in[8].VertexData_a_0, gl_in[8].VertexData_a_1, gl_in[8].VertexData_a_2, gl_in[8].VertexData_a_3), spvUnsafeArray({ gl_in[8].VertexData_b_0, gl_in[8].VertexData_b_1 }), gl_in[8].VertexData_c }, VertexData{ float4x4(gl_in[9].VertexData_a_0, gl_in[9].VertexData_a_1, gl_in[9].VertexData_a_2, gl_in[9].VertexData_a_3), spvUnsafeArray({ gl_in[9].VertexData_b_0, gl_in[9].VertexData_b_1 }), gl_in[9].VertexData_c }, VertexData{ float4x4(gl_in[10].VertexData_a_0, gl_in[10].VertexData_a_1, gl_in[10].VertexData_a_2, gl_in[10].VertexData_a_3), spvUnsafeArray({ gl_in[10].VertexData_b_0, gl_in[10].VertexData_b_1 }), gl_in[10].VertexData_c }, VertexData{ float4x4(gl_in[11].VertexData_a_0, gl_in[11].VertexData_a_1, gl_in[11].VertexData_a_2, gl_in[11].VertexData_a_3), spvUnsafeArray({ gl_in[11].VertexData_b_0, gl_in[11].VertexData_b_1 }), gl_in[11].VertexData_c }, VertexData{ float4x4(gl_in[12].VertexData_a_0, gl_in[12].VertexData_a_1, gl_in[12].VertexData_a_2, gl_in[12].VertexData_a_3), spvUnsafeArray({ gl_in[12].VertexData_b_0, gl_in[12].VertexData_b_1 }), gl_in[12].VertexData_c }, VertexData{ float4x4(gl_in[13].VertexData_a_0, gl_in[13].VertexData_a_1, gl_in[13].VertexData_a_2, gl_in[13].VertexData_a_3), spvUnsafeArray({ gl_in[13].VertexData_b_0, gl_in[13].VertexData_b_1 }), gl_in[13].VertexData_c }, VertexData{ float4x4(gl_in[14].VertexData_a_0, gl_in[14].VertexData_a_1, gl_in[14].VertexData_a_2, gl_in[14].VertexData_a_3), spvUnsafeArray({ gl_in[14].VertexData_b_0, gl_in[14].VertexData_b_1 }), gl_in[14].VertexData_c }, VertexData{ float4x4(gl_in[15].VertexData_a_0, gl_in[15].VertexData_a_1, gl_in[15].VertexData_a_2, gl_in[15].VertexData_a_3), spvUnsafeArray({ gl_in[15].VertexData_b_0, gl_in[15].VertexData_b_1 }), gl_in[15].VertexData_c }, VertexData{ float4x4(gl_in[16].VertexData_a_0, gl_in[16].VertexData_a_1, gl_in[16].VertexData_a_2, gl_in[16].VertexData_a_3), spvUnsafeArray({ gl_in[16].VertexData_b_0, gl_in[16].VertexData_b_1 }), gl_in[16].VertexData_c }, VertexData{ float4x4(gl_in[17].VertexData_a_0, gl_in[17].VertexData_a_1, gl_in[17].VertexData_a_2, gl_in[17].VertexData_a_3), spvUnsafeArray({ gl_in[17].VertexData_b_0, gl_in[17].VertexData_b_1 }), gl_in[17].VertexData_c }, VertexData{ float4x4(gl_in[18].VertexData_a_0, gl_in[18].VertexData_a_1, gl_in[18].VertexData_a_2, gl_in[18].VertexData_a_3), spvUnsafeArray({ gl_in[18].VertexData_b_0, gl_in[18].VertexData_b_1 }), gl_in[18].VertexData_c }, VertexData{ float4x4(gl_in[19].VertexData_a_0, gl_in[19].VertexData_a_1, gl_in[19].VertexData_a_2, gl_in[19].VertexData_a_3), spvUnsafeArray({ gl_in[19].VertexData_b_0, gl_in[19].VertexData_b_1 }), gl_in[19].VertexData_c }, VertexData{ float4x4(gl_in[20].VertexData_a_0, gl_in[20].VertexData_a_1, gl_in[20].VertexData_a_2, gl_in[20].VertexData_a_3), spvUnsafeArray({ gl_in[20].VertexData_b_0, gl_in[20].VertexData_b_1 }), gl_in[20].VertexData_c }, VertexData{ float4x4(gl_in[21].VertexData_a_0, gl_in[21].VertexData_a_1, gl_in[21].VertexData_a_2, gl_in[21].VertexData_a_3), spvUnsafeArray({ gl_in[21].VertexData_b_0, gl_in[21].VertexData_b_1 }), gl_in[21].VertexData_c }, VertexData{ float4x4(gl_in[22].VertexData_a_0, gl_in[22].VertexData_a_1, gl_in[22].VertexData_a_2, gl_in[22].VertexData_a_3), spvUnsafeArray({ gl_in[22].VertexData_b_0, gl_in[22].VertexData_b_1 }), gl_in[22].VertexData_c }, VertexData{ float4x4(gl_in[23].VertexData_a_0, gl_in[23].VertexData_a_1, gl_in[23].VertexData_a_2, gl_in[23].VertexData_a_3), spvUnsafeArray({ gl_in[23].VertexData_b_0, gl_in[23].VertexData_b_1 }), gl_in[23].VertexData_c }, VertexData{ float4x4(gl_in[24].VertexData_a_0, gl_in[24].VertexData_a_1, gl_in[24].VertexData_a_2, gl_in[24].VertexData_a_3), spvUnsafeArray({ gl_in[24].VertexData_b_0, gl_in[24].VertexData_b_1 }), gl_in[24].VertexData_c }, VertexData{ float4x4(gl_in[25].VertexData_a_0, gl_in[25].VertexData_a_1, gl_in[25].VertexData_a_2, gl_in[25].VertexData_a_3), spvUnsafeArray({ gl_in[25].VertexData_b_0, gl_in[25].VertexData_b_1 }), gl_in[25].VertexData_c }, VertexData{ float4x4(gl_in[26].VertexData_a_0, gl_in[26].VertexData_a_1, gl_in[26].VertexData_a_2, gl_in[26].VertexData_a_3), spvUnsafeArray({ gl_in[26].VertexData_b_0, gl_in[26].VertexData_b_1 }), gl_in[26].VertexData_c }, VertexData{ float4x4(gl_in[27].VertexData_a_0, gl_in[27].VertexData_a_1, gl_in[27].VertexData_a_2, gl_in[27].VertexData_a_3), spvUnsafeArray({ gl_in[27].VertexData_b_0, gl_in[27].VertexData_b_1 }), gl_in[27].VertexData_c }, VertexData{ float4x4(gl_in[28].VertexData_a_0, gl_in[28].VertexData_a_1, gl_in[28].VertexData_a_2, gl_in[28].VertexData_a_3), spvUnsafeArray({ gl_in[28].VertexData_b_0, gl_in[28].VertexData_b_1 }), gl_in[28].VertexData_c }, VertexData{ float4x4(gl_in[29].VertexData_a_0, gl_in[29].VertexData_a_1, gl_in[29].VertexData_a_2, gl_in[29].VertexData_a_3), spvUnsafeArray({ gl_in[29].VertexData_b_0, gl_in[29].VertexData_b_1 }), gl_in[29].VertexData_c }, VertexData{ float4x4(gl_in[30].VertexData_a_0, gl_in[30].VertexData_a_1, gl_in[30].VertexData_a_2, gl_in[30].VertexData_a_3), spvUnsafeArray({ gl_in[30].VertexData_b_0, gl_in[30].VertexData_b_1 }), gl_in[30].VertexData_c }, VertexData{ float4x4(gl_in[31].VertexData_a_0, gl_in[31].VertexData_a_1, gl_in[31].VertexData_a_2, gl_in[31].VertexData_a_3), spvUnsafeArray({ gl_in[31].VertexData_b_0, gl_in[31].VertexData_b_1 }), gl_in[31].VertexData_c } }); + spvUnsafeArray tmp; + tmp = _19; + int _27 = gl_InvocationID ^ 1; + gl_out[gl_InvocationID].vOutputs = ((tmp[gl_InvocationID].a[1] + tmp[gl_InvocationID].b[1]) + tmp[gl_InvocationID].c) + gl_in[_27].VertexData_c; +} + diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/tesc/load-control-point-array.tesc b/third_party/spirv-cross/reference/opt/shaders-msl/tesc/load-control-point-array.tesc new file mode 100644 index 0000000000..d04571ae36 --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders-msl/tesc/load-control-point-array.tesc @@ -0,0 +1,70 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + +#include +#include + +using namespace metal; + +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +struct main0_out +{ + float4 vOutputs; +}; + +struct main0_in +{ + float4 vInputs [[attribute(0)]]; +}; + +kernel void main0(main0_in in [[stage_in]], uint gl_InvocationID [[thread_index_in_threadgroup]], uint gl_PrimitiveID [[threadgroup_position_in_grid]], device main0_out* spvOut [[buffer(28)]], constant uint* spvIndirectParams [[buffer(29)]], device MTLQuadTessellationFactorsHalf* spvTessLevel [[buffer(26)]], threadgroup main0_in* gl_in [[threadgroup(0)]]) +{ + device main0_out* gl_out = &spvOut[gl_PrimitiveID * 4]; + if (gl_InvocationID < spvIndirectParams[0]) + gl_in[gl_InvocationID] = in; + threadgroup_barrier(mem_flags::mem_threadgroup); + if (gl_InvocationID >= 4) + return; + spvUnsafeArray _15 = spvUnsafeArray({ gl_in[0].vInputs, gl_in[1].vInputs, gl_in[2].vInputs, gl_in[3].vInputs, gl_in[4].vInputs, gl_in[5].vInputs, gl_in[6].vInputs, gl_in[7].vInputs, gl_in[8].vInputs, gl_in[9].vInputs, gl_in[10].vInputs, gl_in[11].vInputs, gl_in[12].vInputs, gl_in[13].vInputs, gl_in[14].vInputs, gl_in[15].vInputs, gl_in[16].vInputs, gl_in[17].vInputs, gl_in[18].vInputs, gl_in[19].vInputs, gl_in[20].vInputs, gl_in[21].vInputs, gl_in[22].vInputs, gl_in[23].vInputs, gl_in[24].vInputs, gl_in[25].vInputs, gl_in[26].vInputs, gl_in[27].vInputs, gl_in[28].vInputs, gl_in[29].vInputs, gl_in[30].vInputs, gl_in[31].vInputs }); + spvUnsafeArray tmp; + tmp = _15; + gl_out[gl_InvocationID].vOutputs = tmp[gl_InvocationID]; +} + diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/tese/input-types.tese b/third_party/spirv-cross/reference/opt/shaders-msl/tese/input-types.tese index 2a936fce3a..75f917e264 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/tese/input-types.tese +++ b/third_party/spirv-cross/reference/opt/shaders-msl/tese/input-types.tese @@ -65,16 +65,12 @@ struct main0_patchIn out.gl_Position += patchIn.vColors; out.gl_Position += vFoo.a; out.gl_Position += vFoo.b; - Foo vFoos_202; - vFoos_202.a = patchIn.gl_in[0].Foo_a; - vFoos_202.b = patchIn.gl_in[0].Foo_b; - out.gl_Position += vFoos_202.a; - out.gl_Position += vFoos_202.b; - Foo vFoos_216; - vFoos_216.a = patchIn.gl_in[1].Foo_a; - vFoos_216.b = patchIn.gl_in[1].Foo_b; - out.gl_Position += vFoos_216.a; - out.gl_Position += vFoos_216.b; + Foo _203 = Foo{ patchIn.gl_in[0].Foo_a, patchIn.gl_in[0].Foo_b }; + out.gl_Position += _203.a; + out.gl_Position += _203.b; + Foo _217 = Foo{ patchIn.gl_in[1].Foo_a, patchIn.gl_in[1].Foo_b }; + out.gl_Position += _217.a; + out.gl_Position += _217.b; return out; } diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/tese/load-control-point-array-of-matrix.tese b/third_party/spirv-cross/reference/opt/shaders-msl/tese/load-control-point-array-of-matrix.tese new file mode 100644 index 0000000000..e4bbeb7ede --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders-msl/tese/load-control-point-array-of-matrix.tese @@ -0,0 +1,85 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + +#include +#include + +using namespace metal; + +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +struct main0_out +{ + float4 gl_Position [[position]]; +}; + +struct main0_in +{ + float4 vInputs_0 [[attribute(0)]]; + float4 vInputs_1 [[attribute(1)]]; + float4 vInputs_2 [[attribute(2)]]; + float4 vInputs_3 [[attribute(3)]]; +}; + +struct main0_patchIn +{ + float4 vBoo_0 [[attribute(4)]]; + float4 vBoo_1 [[attribute(5)]]; + float4 vBoo_2 [[attribute(6)]]; + float4 vBoo_3 [[attribute(7)]]; + int vIndex [[attribute(8)]]; + patch_control_point gl_in; +}; + +[[ patch(quad, 0) ]] vertex main0_out main0(main0_patchIn patchIn [[stage_in]]) +{ + main0_out out = {}; + spvUnsafeArray vBoo = {}; + vBoo[0] = patchIn.vBoo_0; + vBoo[1] = patchIn.vBoo_1; + vBoo[2] = patchIn.vBoo_2; + vBoo[3] = patchIn.vBoo_3; + float4x4 _57 = float4x4(patchIn.gl_in[0u].vInputs_0, patchIn.gl_in[0u].vInputs_1, patchIn.gl_in[0u].vInputs_2, patchIn.gl_in[0u].vInputs_3); + float4x4 _59 = float4x4(patchIn.gl_in[1u].vInputs_0, patchIn.gl_in[1u].vInputs_1, patchIn.gl_in[1u].vInputs_2, patchIn.gl_in[1u].vInputs_3); + float4x4 _47 = _57; + float4x4 _48 = _59; + out.gl_Position = (_47[patchIn.vIndex] + _48[patchIn.vIndex]) + vBoo[patchIn.vIndex]; + return out; +} + diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/tese/load-control-point-array.tese b/third_party/spirv-cross/reference/opt/shaders-msl/tese/load-control-point-array.tese new file mode 100644 index 0000000000..54d7419f5a --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders-msl/tese/load-control-point-array.tese @@ -0,0 +1,78 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + +#include +#include + +using namespace metal; + +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +struct main0_out +{ + float4 gl_Position [[position]]; +}; + +struct main0_in +{ + float4 vInputs [[attribute(0)]]; +}; + +struct main0_patchIn +{ + float4 vBoo_0 [[attribute(1)]]; + float4 vBoo_1 [[attribute(2)]]; + float4 vBoo_2 [[attribute(3)]]; + float4 vBoo_3 [[attribute(4)]]; + int vIndex [[attribute(5)]]; + patch_control_point gl_in; +}; + +[[ patch(quad, 0) ]] vertex main0_out main0(main0_patchIn patchIn [[stage_in]]) +{ + main0_out out = {}; + spvUnsafeArray vBoo = {}; + vBoo[0] = patchIn.vBoo_0; + vBoo[1] = patchIn.vBoo_1; + vBoo[2] = patchIn.vBoo_2; + vBoo[3] = patchIn.vBoo_3; + out.gl_Position = (patchIn.gl_in[0u].vInputs + patchIn.gl_in[1u].vInputs) + vBoo[patchIn.vIndex]; + return out; +} + diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/tese/triangle-tess-level.tese b/third_party/spirv-cross/reference/opt/shaders-msl/tese/triangle-tess-level.tese index 975e629851..6930e1479d 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/tese/triangle-tess-level.tese +++ b/third_party/spirv-cross/reference/opt/shaders-msl/tese/triangle-tess-level.tese @@ -1,8 +1,49 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + #include #include using namespace metal; +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + struct main0_out { float4 gl_Position [[position]]; @@ -16,8 +57,8 @@ struct main0_patchIn [[ patch(triangle, 0) ]] vertex main0_out main0(main0_patchIn patchIn [[stage_in]], float3 gl_TessCoord [[position_in_patch]]) { main0_out out = {}; - float gl_TessLevelInner[2] = {}; - float gl_TessLevelOuter[4] = {}; + spvUnsafeArray gl_TessLevelInner = {}; + spvUnsafeArray gl_TessLevelOuter = {}; gl_TessLevelInner[0] = patchIn.gl_TessLevel.w; gl_TessLevelOuter[0] = patchIn.gl_TessLevel.x; gl_TessLevelOuter[1] = patchIn.gl_TessLevel.y; diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/vert/clip-distance-block.vert b/third_party/spirv-cross/reference/opt/shaders-msl/vert/clip-distance-block.vert new file mode 100644 index 0000000000..af58f35ff5 --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders-msl/vert/clip-distance-block.vert @@ -0,0 +1,29 @@ +#include +#include + +using namespace metal; + +struct main0_out +{ + float4 gl_Position [[position]]; + float gl_ClipDistance [[clip_distance]] [2]; + float gl_ClipDistance_0 [[user(clip0)]]; + float gl_ClipDistance_1 [[user(clip1)]]; +}; + +struct main0_in +{ + float4 Position [[attribute(0)]]; +}; + +vertex main0_out main0(main0_in in [[stage_in]]) +{ + main0_out out = {}; + out.gl_Position = in.Position; + out.gl_ClipDistance[0] = in.Position.x; + out.gl_ClipDistance[1] = in.Position.y; + out.gl_ClipDistance_0 = out.gl_ClipDistance[0]; + out.gl_ClipDistance_1 = out.gl_ClipDistance[1]; + return out; +} + diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/vert/float-math.invariant-float-math.vert b/third_party/spirv-cross/reference/opt/shaders-msl/vert/float-math.invariant-float-math.vert new file mode 100644 index 0000000000..05e09e2d18 --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders-msl/vert/float-math.invariant-float-math.vert @@ -0,0 +1,137 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + +#include +#include + +using namespace metal; + +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +struct Matrices +{ + float4x4 vpMatrix; + float4x4 wMatrix; + float4x3 wMatrix4x3; + float3x4 wMatrix3x4; +}; + +struct main0_out +{ + float3 OutNormal [[user(locn0)]]; + float4 OutWorldPos_0 [[user(locn1)]]; + float4 OutWorldPos_1 [[user(locn2)]]; + float4 OutWorldPos_2 [[user(locn3)]]; + float4 OutWorldPos_3 [[user(locn4)]]; + float4 gl_Position [[position]]; +}; + +struct main0_in +{ + float3 InPos [[attribute(0)]]; + float3 InNormal [[attribute(1)]]; +}; + +template +T spvFMul(T l, T r) +{ + return fma(l, r, T(0)); +} + +template +vec spvFMulVectorMatrix(vec v, matrix m) +{ + vec res = vec(0); + for (uint i = Rows; i > 0; --i) + { + vec tmp(0); + for (uint j = 0; j < Cols; ++j) + { + tmp[j] = m[j][i - 1]; + } + res = fma(tmp, vec(v[i - 1]), res); + } + return res; +} + +template +vec spvFMulMatrixVector(matrix m, vec v) +{ + vec res = vec(0); + for (uint i = Cols; i > 0; --i) + { + res = fma(m[i - 1], vec(v[i - 1]), res); + } + return res; +} + +template +matrix spvFMulMatrixMatrix(matrix l, matrix r) +{ + matrix res; + for (uint i = 0; i < RCols; i++) + { + vec tmp(0); + for (uint j = 0; j < LCols; j++) + { + tmp = fma(vec(r[i][j]), l[j], tmp); + } + res[i] = tmp; + } + return res; +} + +vertex main0_out main0(main0_in in [[stage_in]], constant Matrices& _22 [[buffer(0)]]) +{ + main0_out out = {}; + spvUnsafeArray OutWorldPos = {}; + float4 _37 = float4(in.InPos, 1.0); + out.gl_Position = spvFMulMatrixVector(spvFMulMatrixMatrix(_22.vpMatrix, _22.wMatrix), _37); + OutWorldPos[0] = spvFMulMatrixVector(_22.wMatrix, _37); + OutWorldPos[1] = spvFMulVectorMatrix(_37, _22.wMatrix); + OutWorldPos[2] = spvFMulMatrixVector(_22.wMatrix3x4, in.InPos); + OutWorldPos[3] = spvFMulVectorMatrix(in.InPos, _22.wMatrix4x3); + out.OutNormal = spvFMulMatrixVector(_22.wMatrix, float4(in.InNormal, 0.0)).xyz; + out.OutWorldPos_0 = OutWorldPos[0]; + out.OutWorldPos_1 = OutWorldPos[1]; + out.OutWorldPos_2 = OutWorldPos[2]; + out.OutWorldPos_3 = OutWorldPos[3]; + return out; +} + diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/vert/float-math.vert b/third_party/spirv-cross/reference/opt/shaders-msl/vert/float-math.vert new file mode 100644 index 0000000000..da468c24c9 --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders-msl/vert/float-math.vert @@ -0,0 +1,88 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + +#include +#include + +using namespace metal; + +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +struct Matrices +{ + float4x4 vpMatrix; + float4x4 wMatrix; + float4x3 wMatrix4x3; + float3x4 wMatrix3x4; +}; + +struct main0_out +{ + float3 OutNormal [[user(locn0)]]; + float4 OutWorldPos_0 [[user(locn1)]]; + float4 OutWorldPos_1 [[user(locn2)]]; + float4 OutWorldPos_2 [[user(locn3)]]; + float4 OutWorldPos_3 [[user(locn4)]]; + float4 gl_Position [[position]]; +}; + +struct main0_in +{ + float3 InPos [[attribute(0)]]; + float3 InNormal [[attribute(1)]]; +}; + +vertex main0_out main0(main0_in in [[stage_in]], constant Matrices& _22 [[buffer(0)]]) +{ + main0_out out = {}; + spvUnsafeArray OutWorldPos = {}; + float4 _37 = float4(in.InPos, 1.0); + out.gl_Position = (_22.vpMatrix * _22.wMatrix) * _37; + OutWorldPos[0] = _22.wMatrix * _37; + OutWorldPos[1] = _37 * _22.wMatrix; + OutWorldPos[2] = _22.wMatrix3x4 * in.InPos; + OutWorldPos[3] = in.InPos * _22.wMatrix4x3; + out.OutNormal = (_22.wMatrix * float4(in.InNormal, 0.0)).xyz; + out.OutWorldPos_0 = OutWorldPos[0]; + out.OutWorldPos_1 = OutWorldPos[1]; + out.OutWorldPos_2 = OutWorldPos[2]; + out.OutWorldPos_3 = OutWorldPos[3]; + return out; +} + diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/vert/functions.vert b/third_party/spirv-cross/reference/opt/shaders-msl/vert/functions.vert index 9af0f3f356..73eaa8b751 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/vert/functions.vert +++ b/third_party/spirv-cross/reference/opt/shaders-msl/vert/functions.vert @@ -31,47 +31,50 @@ struct main0_in // Implementation of the GLSL radians() function template -T radians(T d) +inline T radians(T d) { return d * T(0.01745329251); } // Implementation of the GLSL degrees() function template -T degrees(T r) +inline T degrees(T r) { return r * T(57.2957795131); } // Implementation of the GLSL findLSB() function template -T spvFindLSB(T x) +inline T spvFindLSB(T x) { return select(ctz(x), T(-1), x == T(0)); } // Implementation of the signed GLSL findMSB() function template -T spvFindSMSB(T x) +inline T spvFindSMSB(T x) { T v = select(x, T(-1) - x, x < T(0)); return select(clz(T(0)) - (clz(v) + T(1)), T(-1), v == T(0)); } // Returns the determinant of a 2x2 matrix. -inline float spvDet2x2(float a1, float a2, float b1, float b2) +static inline __attribute__((always_inline)) +float spvDet2x2(float a1, float a2, float b1, float b2) { return a1 * b2 - b1 * a2; } // Returns the determinant of a 3x3 matrix. -inline float spvDet3x3(float a1, float a2, float a3, float b1, float b2, float b3, float c1, float c2, float c3) +static inline __attribute__((always_inline)) +float spvDet3x3(float a1, float a2, float a3, float b1, float b2, float b3, float c1, float c2, float c3) { return a1 * spvDet2x2(b2, b3, c2, c3) - b1 * spvDet2x2(a2, a3, c2, c3) + c1 * spvDet2x2(a2, a3, b2, b3); } // Returns the inverse of a matrix, by using the algorithm of calculating the classical // adjoint and dividing by the determinant. The contents of the matrix are changed. +static inline __attribute__((always_inline)) float4x4 spvInverse4x4(float4x4 m) { float4x4 adj; // The adjoint matrix (inverse after dividing by determinant) diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/vert/in_out_array_mat.vert b/third_party/spirv-cross/reference/opt/shaders-msl/vert/in_out_array_mat.vert index 0d6976e260..7a74f49a49 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/vert/in_out_array_mat.vert +++ b/third_party/spirv-cross/reference/opt/shaders-msl/vert/in_out_array_mat.vert @@ -1,8 +1,49 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + #include #include using namespace metal; +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + struct UBO { float4x4 projection; @@ -40,7 +81,7 @@ vertex main0_out main0(main0_in in [[stage_in]], constant UBO& ubo [[buffer(0)]] { main0_out out = {}; float4x4 outTransModel = {}; - float4 colors[3] = {}; + spvUnsafeArray colors = {}; float4x4 inViewMat = {}; colors[0] = in.colors_0; colors[1] = in.colors_1; diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/vert/interface-block-block-composites.frag b/third_party/spirv-cross/reference/opt/shaders-msl/vert/interface-block-block-composites.frag index 90d732cc52..4b27f4a3d5 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/vert/interface-block-block-composites.frag +++ b/third_party/spirv-cross/reference/opt/shaders-msl/vert/interface-block-block-composites.frag @@ -1,13 +1,54 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + #include #include using namespace metal; +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + struct Vert { float3x3 wMatrix; float4 wTmp; - float arr[4]; + spvUnsafeArray arr; }; struct main0_out diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/vert/interface-block-block-composites.vert b/third_party/spirv-cross/reference/opt/shaders-msl/vert/interface-block-block-composites.vert index 3d97ae6dcf..69f271a83c 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/vert/interface-block-block-composites.vert +++ b/third_party/spirv-cross/reference/opt/shaders-msl/vert/interface-block-block-composites.vert @@ -1,11 +1,52 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + #include #include using namespace metal; +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + struct Vert { - float arr[3]; + spvUnsafeArray arr; float3x3 wMatrix; float4 wTmp; }; diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/vert/no_stage_out.vert b/third_party/spirv-cross/reference/opt/shaders-msl/vert/no_stage_out.vert index 28098ee88e..30613cc4b8 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/vert/no_stage_out.vert +++ b/third_party/spirv-cross/reference/opt/shaders-msl/vert/no_stage_out.vert @@ -15,6 +15,6 @@ struct main0_in vertex void main0(main0_in in [[stage_in]], device _10& _12 [[buffer(0)]], uint gl_VertexIndex [[vertex_id]]) { - _12._m0[gl_VertexIndex] = in.m_19; + _12._m0[int(gl_VertexIndex)] = in.m_19; } diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/vert/read-from-row-major-array.vert b/third_party/spirv-cross/reference/opt/shaders-msl/vert/read-from-row-major-array.vert index be3c5e4ee6..ec3e7b7248 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/vert/read-from-row-major-array.vert +++ b/third_party/spirv-cross/reference/opt/shaders-msl/vert/read-from-row-major-array.vert @@ -23,7 +23,7 @@ vertex main0_out main0(main0_in in [[stage_in]], constant Block& _104 [[buffer(0 { main0_out out = {}; out.gl_Position = in.a_position; - out.v_vtxResult = ((float(abs(float3(_104.var[0][0][0][0], _104.var[0][0][1][0], _104.var[0][0][2][0])[0] - 2.0) < 0.0500000007450580596923828125) * float(abs(float3(_104.var[0][0][0][0], _104.var[0][0][1][0], _104.var[0][0][2][0])[1] - 6.0) < 0.0500000007450580596923828125)) * float(abs(float3(_104.var[0][0][0][0], _104.var[0][0][1][0], _104.var[0][0][2][0])[2] - (-6.0)) < 0.0500000007450580596923828125)) * ((float(abs(float3(_104.var[0][0][0][1], _104.var[0][0][1][1], _104.var[0][0][2][1])[0]) < 0.0500000007450580596923828125) * float(abs(float3(_104.var[0][0][0][1], _104.var[0][0][1][1], _104.var[0][0][2][1])[1] - 5.0) < 0.0500000007450580596923828125)) * float(abs(float3(_104.var[0][0][0][1], _104.var[0][0][1][1], _104.var[0][0][2][1])[2] - 5.0) < 0.0500000007450580596923828125)); + out.v_vtxResult = ((float(abs(_104.var[0][0][0][0] - 2.0) < 0.0500000007450580596923828125) * float(abs(_104.var[0][0][1][0] - 6.0) < 0.0500000007450580596923828125)) * float(abs(_104.var[0][0][2][0] - (-6.0)) < 0.0500000007450580596923828125)) * ((float(abs(_104.var[0][0][0][1]) < 0.0500000007450580596923828125) * float(abs(_104.var[0][0][1][1] - 5.0) < 0.0500000007450580596923828125)) * float(abs(_104.var[0][0][2][1] - 5.0) < 0.0500000007450580596923828125)); return out; } diff --git a/third_party/spirv-cross/reference/shaders-msl/vert/layer.msl11.invalid.vert b/third_party/spirv-cross/reference/opt/shaders-msl/vert/return-array.force-native-array.vert similarity index 61% rename from third_party/spirv-cross/reference/shaders-msl/vert/layer.msl11.invalid.vert rename to third_party/spirv-cross/reference/opt/shaders-msl/vert/return-array.force-native-array.vert index b6f39dca3e..ce13349a0f 100644 --- a/third_party/spirv-cross/reference/shaders-msl/vert/layer.msl11.invalid.vert +++ b/third_party/spirv-cross/reference/opt/shaders-msl/vert/return-array.force-native-array.vert @@ -6,19 +6,17 @@ using namespace metal; struct main0_out { float4 gl_Position [[position]]; - uint gl_Layer [[render_target_array_index]]; }; struct main0_in { - float4 coord [[attribute(0)]]; + float4 vInput1 [[attribute(1)]]; }; vertex main0_out main0(main0_in in [[stage_in]]) { main0_out out = {}; - out.gl_Position = in.coord; - out.gl_Layer = uint(int(in.coord.z)); + out.gl_Position = float4(10.0) + in.vInput1; return out; } diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/vert/sign-int-types.vert b/third_party/spirv-cross/reference/opt/shaders-msl/vert/sign-int-types.vert index 2f518b1291..a510645223 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/vert/sign-int-types.vert +++ b/third_party/spirv-cross/reference/opt/shaders-msl/vert/sign-int-types.vert @@ -38,7 +38,7 @@ struct main0_in // Implementation of the GLSL sign() function for integer types template::value>::type> -T sign(T x) +inline T sign(T x) { return select(select(select(x, T(0), x == T(0)), T(1), x > T(0)), T(-1), x < T(0)); } diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/vert/texture_buffer.vert b/third_party/spirv-cross/reference/opt/shaders-msl/vert/texture_buffer.vert index ee3956fad8..3b3d92b565 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/vert/texture_buffer.vert +++ b/third_party/spirv-cross/reference/opt/shaders-msl/vert/texture_buffer.vert @@ -11,6 +11,7 @@ struct main0_out }; // Returns 2D texture coords corresponding to 1D texel buffer coords +static inline __attribute__((always_inline)) uint2 spvTexelBufferCoord(uint tc) { return uint2(tc % 4096, tc / 4096); diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/vulkan/comp/subgroups.nocompat.invalid.vk.msl21.comp b/third_party/spirv-cross/reference/opt/shaders-msl/vulkan/comp/subgroups.nocompat.invalid.vk.msl21.comp deleted file mode 100644 index 948806db4e..0000000000 --- a/third_party/spirv-cross/reference/opt/shaders-msl/vulkan/comp/subgroups.nocompat.invalid.vk.msl21.comp +++ /dev/null @@ -1,92 +0,0 @@ -#pragma clang diagnostic ignored "-Wmissing-prototypes" - -#include -#include - -using namespace metal; - -struct SSBO -{ - float FragColor; -}; - -inline uint4 spvSubgroupBallot(bool value) -{ - simd_vote vote = simd_ballot(value); - // simd_ballot() returns a 64-bit integer-like object, but - // SPIR-V callers expect a uint4. We must convert. - // FIXME: This won't include higher bits if Apple ever supports - // 128 lanes in an SIMD-group. - return uint4((uint)((simd_vote::vote_t)vote & 0xFFFFFFFF), (uint)(((simd_vote::vote_t)vote >> 32) & 0xFFFFFFFF), 0, 0); -} - -inline bool spvSubgroupBallotBitExtract(uint4 ballot, uint bit) -{ - return !!extract_bits(ballot[bit / 32], bit % 32, 1); -} - -inline uint spvSubgroupBallotFindLSB(uint4 ballot) -{ - return select(ctz(ballot.x), select(32 + ctz(ballot.y), select(64 + ctz(ballot.z), select(96 + ctz(ballot.w), uint(-1), ballot.w == 0), ballot.z == 0), ballot.y == 0), ballot.x == 0); -} - -inline uint spvSubgroupBallotFindMSB(uint4 ballot) -{ - return select(128 - (clz(ballot.w) + 1), select(96 - (clz(ballot.z) + 1), select(64 - (clz(ballot.y) + 1), select(32 - (clz(ballot.x) + 1), uint(-1), ballot.x == 0), ballot.y == 0), ballot.z == 0), ballot.w == 0); -} - -inline uint spvSubgroupBallotBitCount(uint4 ballot) -{ - return popcount(ballot.x) + popcount(ballot.y) + popcount(ballot.z) + popcount(ballot.w); -} - -inline uint spvSubgroupBallotInclusiveBitCount(uint4 ballot, uint gl_SubgroupInvocationID) -{ - uint4 mask = uint4(extract_bits(0xFFFFFFFF, 0, min(gl_SubgroupInvocationID + 1, 32u)), extract_bits(0xFFFFFFFF, 0, (uint)max((int)gl_SubgroupInvocationID + 1 - 32, 0)), uint2(0)); - return spvSubgroupBallotBitCount(ballot & mask); -} - -inline uint spvSubgroupBallotExclusiveBitCount(uint4 ballot, uint gl_SubgroupInvocationID) -{ - uint4 mask = uint4(extract_bits(0xFFFFFFFF, 0, min(gl_SubgroupInvocationID, 32u)), extract_bits(0xFFFFFFFF, 0, (uint)max((int)gl_SubgroupInvocationID - 32, 0)), uint2(0)); - return spvSubgroupBallotBitCount(ballot & mask); -} - -template -inline bool spvSubgroupAllEqual(T value) -{ - return simd_all(value == simd_broadcast_first(value)); -} - -template<> -inline bool spvSubgroupAllEqual(bool value) -{ - return simd_all(value) || !simd_any(value); -} - -kernel void main0(device SSBO& _9 [[buffer(0)]], uint gl_NumSubgroups [[simdgroups_per_threadgroup]], uint gl_SubgroupID [[simdgroup_index_in_threadgroup]], uint gl_SubgroupSize [[thread_execution_width]], uint gl_SubgroupInvocationID [[thread_index_in_simdgroup]]) -{ - uint4 gl_SubgroupEqMask = gl_SubgroupInvocationID > 32 ? uint4(0, (1 << (gl_SubgroupInvocationID - 32)), uint2(0)) : uint4(1 << gl_SubgroupInvocationID, uint3(0)); - uint4 gl_SubgroupGeMask = uint4(extract_bits(0xFFFFFFFF, min(gl_SubgroupInvocationID, 32u), (uint)max(min((int)gl_SubgroupSize, 32) - (int)gl_SubgroupInvocationID, 0)), extract_bits(0xFFFFFFFF, (uint)max((int)gl_SubgroupInvocationID - 32, 0), (uint)max((int)gl_SubgroupSize - (int)max(gl_SubgroupInvocationID, 32u), 0)), uint2(0)); - uint4 gl_SubgroupGtMask = uint4(extract_bits(0xFFFFFFFF, min(gl_SubgroupInvocationID + 1, 32u), (uint)max(min((int)gl_SubgroupSize, 32) - (int)gl_SubgroupInvocationID - 1, 0)), extract_bits(0xFFFFFFFF, (uint)max((int)gl_SubgroupInvocationID + 1 - 32, 0), (uint)max((int)gl_SubgroupSize - (int)max(gl_SubgroupInvocationID + 1, 32u), 0)), uint2(0)); - uint4 gl_SubgroupLeMask = uint4(extract_bits(0xFFFFFFFF, 0, min(gl_SubgroupInvocationID + 1, 32u)), extract_bits(0xFFFFFFFF, 0, (uint)max((int)gl_SubgroupInvocationID + 1 - 32, 0)), uint2(0)); - uint4 gl_SubgroupLtMask = uint4(extract_bits(0xFFFFFFFF, 0, min(gl_SubgroupInvocationID, 32u)), extract_bits(0xFFFFFFFF, 0, (uint)max((int)gl_SubgroupInvocationID - 32, 0)), uint2(0)); - _9.FragColor = float(gl_NumSubgroups); - _9.FragColor = float(gl_SubgroupID); - _9.FragColor = float(gl_SubgroupSize); - _9.FragColor = float(gl_SubgroupInvocationID); - simdgroup_barrier(mem_flags::mem_device | mem_flags::mem_threadgroup | mem_flags::mem_texture); - simdgroup_barrier(mem_flags::mem_device | mem_flags::mem_threadgroup | mem_flags::mem_texture); - simdgroup_barrier(mem_flags::mem_device); - simdgroup_barrier(mem_flags::mem_threadgroup); - simdgroup_barrier(mem_flags::mem_texture); - _9.FragColor = float4(gl_SubgroupEqMask).x; - _9.FragColor = float4(gl_SubgroupGeMask).x; - _9.FragColor = float4(gl_SubgroupGtMask).x; - _9.FragColor = float4(gl_SubgroupLeMask).x; - _9.FragColor = float4(gl_SubgroupLtMask).x; - uint4 _83 = spvSubgroupBallot(true); - float4 _165 = simd_prefix_inclusive_product(simd_product(float4(20.0))); - int4 _167 = simd_prefix_inclusive_product(simd_product(int4(20))); -} - diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/vulkan/comp/subgroups.nocompat.invalid.vk.msl21.ios.comp b/third_party/spirv-cross/reference/opt/shaders-msl/vulkan/comp/subgroups.nocompat.invalid.vk.msl21.ios.comp deleted file mode 100644 index 6d32de695a..0000000000 --- a/third_party/spirv-cross/reference/opt/shaders-msl/vulkan/comp/subgroups.nocompat.invalid.vk.msl21.ios.comp +++ /dev/null @@ -1,23 +0,0 @@ -#include -#include - -using namespace metal; - -struct SSBO -{ - float FragColor; -}; - -kernel void main0(device SSBO& _9 [[buffer(0)]], uint gl_NumSubgroups [[quadgroups_per_threadgroup]], uint gl_SubgroupID [[quadgroup_index_in_threadgroup]], uint gl_SubgroupSize [[thread_execution_width]], uint gl_SubgroupInvocationID [[thread_index_in_quadgroup]]) -{ - _9.FragColor = float(gl_NumSubgroups); - _9.FragColor = float(gl_SubgroupID); - _9.FragColor = float(gl_SubgroupSize); - _9.FragColor = float(gl_SubgroupInvocationID); - simdgroup_barrier(mem_flags::mem_device | mem_flags::mem_threadgroup | mem_flags::mem_texture); - simdgroup_barrier(mem_flags::mem_device | mem_flags::mem_threadgroup | mem_flags::mem_texture); - simdgroup_barrier(mem_flags::mem_device); - simdgroup_barrier(mem_flags::mem_threadgroup); - simdgroup_barrier(mem_flags::mem_texture); -} - diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/vulkan/frag/basic.multiview.nocompat.vk.frag b/third_party/spirv-cross/reference/opt/shaders-msl/vulkan/frag/basic.multiview.nocompat.vk.frag index 23c554940b..67895e3e92 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/vulkan/frag/basic.multiview.nocompat.vk.frag +++ b/third_party/spirv-cross/reference/opt/shaders-msl/vulkan/frag/basic.multiview.nocompat.vk.frag @@ -1,8 +1,49 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + #include #include using namespace metal; +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + struct main0_out { float4 FragColor [[color(0)]]; @@ -20,7 +61,7 @@ struct main0_in fragment main0_out main0(main0_in in [[stage_in]], constant uint* spvViewMask [[buffer(24)]], texture2d uTex [[texture(0)]], sampler uTexSmplr [[sampler(0)]], uint gl_ViewIndex [[render_target_array_index]]) { main0_out out = {}; - float2 vTex[4] = {}; + spvUnsafeArray vTex = {}; vTex[0] = in.vTex_0; vTex[1] = in.vTex_1; vTex[2] = in.vTex_2; diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/vulkan/frag/demote-to-helper.vk.nocompat.msl21.invalid.frag b/third_party/spirv-cross/reference/opt/shaders-msl/vulkan/frag/demote-to-helper.vk.nocompat.msl21.invalid.frag deleted file mode 100644 index 429da47679..0000000000 --- a/third_party/spirv-cross/reference/opt/shaders-msl/vulkan/frag/demote-to-helper.vk.nocompat.msl21.invalid.frag +++ /dev/null @@ -1,10 +0,0 @@ -#include -#include - -using namespace metal; - -fragment void main0() -{ - bool _9 = simd_is_helper_thread(); -} - diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/vulkan/frag/subgroups.nocompat.invalid.vk.msl21.frag b/third_party/spirv-cross/reference/opt/shaders-msl/vulkan/frag/subgroups.nocompat.invalid.vk.msl21.frag deleted file mode 100644 index fc9c4fcdd1..0000000000 --- a/third_party/spirv-cross/reference/opt/shaders-msl/vulkan/frag/subgroups.nocompat.invalid.vk.msl21.frag +++ /dev/null @@ -1,89 +0,0 @@ -#pragma clang diagnostic ignored "-Wmissing-prototypes" - -#include -#include - -using namespace metal; - -struct main0_out -{ - float FragColor [[color(0)]]; -}; - -inline uint4 spvSubgroupBallot(bool value) -{ - simd_vote vote = simd_ballot(value); - // simd_ballot() returns a 64-bit integer-like object, but - // SPIR-V callers expect a uint4. We must convert. - // FIXME: This won't include higher bits if Apple ever supports - // 128 lanes in an SIMD-group. - return uint4((uint)((simd_vote::vote_t)vote & 0xFFFFFFFF), (uint)(((simd_vote::vote_t)vote >> 32) & 0xFFFFFFFF), 0, 0); -} - -inline bool spvSubgroupBallotBitExtract(uint4 ballot, uint bit) -{ - return !!extract_bits(ballot[bit / 32], bit % 32, 1); -} - -inline uint spvSubgroupBallotFindLSB(uint4 ballot) -{ - return select(ctz(ballot.x), select(32 + ctz(ballot.y), select(64 + ctz(ballot.z), select(96 + ctz(ballot.w), uint(-1), ballot.w == 0), ballot.z == 0), ballot.y == 0), ballot.x == 0); -} - -inline uint spvSubgroupBallotFindMSB(uint4 ballot) -{ - return select(128 - (clz(ballot.w) + 1), select(96 - (clz(ballot.z) + 1), select(64 - (clz(ballot.y) + 1), select(32 - (clz(ballot.x) + 1), uint(-1), ballot.x == 0), ballot.y == 0), ballot.z == 0), ballot.w == 0); -} - -inline uint spvSubgroupBallotBitCount(uint4 ballot) -{ - return popcount(ballot.x) + popcount(ballot.y) + popcount(ballot.z) + popcount(ballot.w); -} - -inline uint spvSubgroupBallotInclusiveBitCount(uint4 ballot, uint gl_SubgroupInvocationID) -{ - uint4 mask = uint4(extract_bits(0xFFFFFFFF, 0, min(gl_SubgroupInvocationID + 1, 32u)), extract_bits(0xFFFFFFFF, 0, (uint)max((int)gl_SubgroupInvocationID + 1 - 32, 0)), uint2(0)); - return spvSubgroupBallotBitCount(ballot & mask); -} - -inline uint spvSubgroupBallotExclusiveBitCount(uint4 ballot, uint gl_SubgroupInvocationID) -{ - uint4 mask = uint4(extract_bits(0xFFFFFFFF, 0, min(gl_SubgroupInvocationID, 32u)), extract_bits(0xFFFFFFFF, 0, (uint)max((int)gl_SubgroupInvocationID - 32, 0)), uint2(0)); - return spvSubgroupBallotBitCount(ballot & mask); -} - -template -inline bool spvSubgroupAllEqual(T value) -{ - return simd_all(value == simd_broadcast_first(value)); -} - -template<> -inline bool spvSubgroupAllEqual(bool value) -{ - return simd_all(value) || !simd_any(value); -} - -fragment main0_out main0() -{ - main0_out out = {}; - uint gl_SubgroupSize = simd_sum(1); - uint gl_SubgroupInvocationID = simd_prefix_exclusive_sum(1); - uint4 gl_SubgroupEqMask = gl_SubgroupInvocationID > 32 ? uint4(0, (1 << (gl_SubgroupInvocationID - 32)), uint2(0)) : uint4(1 << gl_SubgroupInvocationID, uint3(0)); - uint4 gl_SubgroupGeMask = uint4(extract_bits(0xFFFFFFFF, min(gl_SubgroupInvocationID, 32u), (uint)max(min((int)gl_SubgroupSize, 32) - (int)gl_SubgroupInvocationID, 0)), extract_bits(0xFFFFFFFF, (uint)max((int)gl_SubgroupInvocationID - 32, 0), (uint)max((int)gl_SubgroupSize - (int)max(gl_SubgroupInvocationID, 32u), 0)), uint2(0)); - uint4 gl_SubgroupGtMask = uint4(extract_bits(0xFFFFFFFF, min(gl_SubgroupInvocationID + 1, 32u), (uint)max(min((int)gl_SubgroupSize, 32) - (int)gl_SubgroupInvocationID - 1, 0)), extract_bits(0xFFFFFFFF, (uint)max((int)gl_SubgroupInvocationID + 1 - 32, 0), (uint)max((int)gl_SubgroupSize - (int)max(gl_SubgroupInvocationID + 1, 32u), 0)), uint2(0)); - uint4 gl_SubgroupLeMask = uint4(extract_bits(0xFFFFFFFF, 0, min(gl_SubgroupInvocationID + 1, 32u)), extract_bits(0xFFFFFFFF, 0, (uint)max((int)gl_SubgroupInvocationID + 1 - 32, 0)), uint2(0)); - uint4 gl_SubgroupLtMask = uint4(extract_bits(0xFFFFFFFF, 0, min(gl_SubgroupInvocationID, 32u)), extract_bits(0xFFFFFFFF, 0, (uint)max((int)gl_SubgroupInvocationID - 32, 0)), uint2(0)); - out.FragColor = float(gl_SubgroupSize); - out.FragColor = float(gl_SubgroupInvocationID); - out.FragColor = float4(gl_SubgroupEqMask).x; - out.FragColor = float4(gl_SubgroupGeMask).x; - out.FragColor = float4(gl_SubgroupGtMask).x; - out.FragColor = float4(gl_SubgroupLeMask).x; - out.FragColor = float4(gl_SubgroupLtMask).x; - uint4 _63 = spvSubgroupBallot(true); - float4 _147 = simd_prefix_inclusive_product(simd_product(float4(20.0))); - int4 _149 = simd_prefix_inclusive_product(simd_product(int4(20))); - return out; -} - diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/vulkan/vert/vulkan-vertex.vk.vert b/third_party/spirv-cross/reference/opt/shaders-msl/vulkan/vert/vulkan-vertex.vk.vert index 53e26e4a8e..86a0cea5bb 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/vulkan/vert/vulkan-vertex.vk.vert +++ b/third_party/spirv-cross/reference/opt/shaders-msl/vulkan/vert/vulkan-vertex.vk.vert @@ -11,7 +11,7 @@ struct main0_out vertex main0_out main0(uint gl_VertexIndex [[vertex_id]], uint gl_InstanceIndex [[instance_id]]) { main0_out out = {}; - out.gl_Position = float4(1.0, 2.0, 3.0, 4.0) * float(gl_VertexIndex + gl_InstanceIndex); + out.gl_Position = float4(1.0, 2.0, 3.0, 4.0) * float(int(gl_VertexIndex) + int(gl_InstanceIndex)); return out; } diff --git a/third_party/spirv-cross/reference/opt/shaders-ue4/asm/frag/depth-compare.asm.frag b/third_party/spirv-cross/reference/opt/shaders-ue4/asm/frag/depth-compare.asm.frag new file mode 100644 index 0000000000..7f593efeef --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders-ue4/asm/frag/depth-compare.asm.frag @@ -0,0 +1,314 @@ +#include +#include + +using namespace metal; + +struct type_View +{ + float4x4 View_TranslatedWorldToClip; + float4x4 View_WorldToClip; + float4x4 View_TranslatedWorldToView; + float4x4 View_ViewToTranslatedWorld; + float4x4 View_TranslatedWorldToCameraView; + float4x4 View_CameraViewToTranslatedWorld; + float4x4 View_ViewToClip; + float4x4 View_ViewToClipNoAA; + float4x4 View_ClipToView; + float4x4 View_ClipToTranslatedWorld; + float4x4 View_SVPositionToTranslatedWorld; + float4x4 View_ScreenToWorld; + float4x4 View_ScreenToTranslatedWorld; + packed_float3 View_ViewForward; + float PrePadding_View_844; + packed_float3 View_ViewUp; + float PrePadding_View_860; + packed_float3 View_ViewRight; + float PrePadding_View_876; + packed_float3 View_HMDViewNoRollUp; + float PrePadding_View_892; + packed_float3 View_HMDViewNoRollRight; + float PrePadding_View_908; + float4 View_InvDeviceZToWorldZTransform; + float4 View_ScreenPositionScaleBias; + packed_float3 View_WorldCameraOrigin; + float PrePadding_View_956; + packed_float3 View_TranslatedWorldCameraOrigin; + float PrePadding_View_972; + packed_float3 View_WorldViewOrigin; + float PrePadding_View_988; + packed_float3 View_PreViewTranslation; + float PrePadding_View_1004; + float4x4 View_PrevProjection; + float4x4 View_PrevViewProj; + float4x4 View_PrevViewRotationProj; + float4x4 View_PrevViewToClip; + float4x4 View_PrevClipToView; + float4x4 View_PrevTranslatedWorldToClip; + float4x4 View_PrevTranslatedWorldToView; + float4x4 View_PrevViewToTranslatedWorld; + float4x4 View_PrevTranslatedWorldToCameraView; + float4x4 View_PrevCameraViewToTranslatedWorld; + packed_float3 View_PrevWorldCameraOrigin; + float PrePadding_View_1660; + packed_float3 View_PrevWorldViewOrigin; + float PrePadding_View_1676; + packed_float3 View_PrevPreViewTranslation; + float PrePadding_View_1692; + float4x4 View_PrevInvViewProj; + float4x4 View_PrevScreenToTranslatedWorld; + float4x4 View_ClipToPrevClip; + float4 View_TemporalAAJitter; + float4 View_GlobalClippingPlane; + float2 View_FieldOfViewWideAngles; + float2 View_PrevFieldOfViewWideAngles; + float4 View_ViewRectMin; + float4 View_ViewSizeAndInvSize; + float4 View_BufferSizeAndInvSize; + float4 View_BufferBilinearUVMinMax; + int View_NumSceneColorMSAASamples; + float View_PreExposure; + float View_OneOverPreExposure; + float PrePadding_View_2012; + float4 View_DiffuseOverrideParameter; + float4 View_SpecularOverrideParameter; + float4 View_NormalOverrideParameter; + float2 View_RoughnessOverrideParameter; + float View_PrevFrameGameTime; + float View_PrevFrameRealTime; + float View_OutOfBoundsMask; + float PrePadding_View_2084; + float PrePadding_View_2088; + float PrePadding_View_2092; + packed_float3 View_WorldCameraMovementSinceLastFrame; + float View_CullingSign; + float View_NearPlane; + float View_AdaptiveTessellationFactor; + float View_GameTime; + float View_RealTime; + float View_DeltaTime; + float View_MaterialTextureMipBias; + float View_MaterialTextureDerivativeMultiply; + uint View_Random; + uint View_FrameNumber; + uint View_StateFrameIndexMod8; + uint View_StateFrameIndex; + float View_CameraCut; + float View_UnlitViewmodeMask; + float PrePadding_View_2164; + float PrePadding_View_2168; + float PrePadding_View_2172; + float4 View_DirectionalLightColor; + packed_float3 View_DirectionalLightDirection; + float PrePadding_View_2204; + float4 View_TranslucencyLightingVolumeMin[2]; + float4 View_TranslucencyLightingVolumeInvSize[2]; + float4 View_TemporalAAParams; + float4 View_CircleDOFParams; + float View_DepthOfFieldSensorWidth; + float View_DepthOfFieldFocalDistance; + float View_DepthOfFieldScale; + float View_DepthOfFieldFocalLength; + float View_DepthOfFieldFocalRegion; + float View_DepthOfFieldNearTransitionRegion; + float View_DepthOfFieldFarTransitionRegion; + float View_MotionBlurNormalizedToPixel; + float View_bSubsurfacePostprocessEnabled; + float View_GeneralPurposeTweak; + float View_DemosaicVposOffset; + float PrePadding_View_2348; + packed_float3 View_IndirectLightingColorScale; + float View_HDR32bppEncodingMode; + packed_float3 View_AtmosphericFogSunDirection; + float View_AtmosphericFogSunPower; + float View_AtmosphericFogPower; + float View_AtmosphericFogDensityScale; + float View_AtmosphericFogDensityOffset; + float View_AtmosphericFogGroundOffset; + float View_AtmosphericFogDistanceScale; + float View_AtmosphericFogAltitudeScale; + float View_AtmosphericFogHeightScaleRayleigh; + float View_AtmosphericFogStartDistance; + float View_AtmosphericFogDistanceOffset; + float View_AtmosphericFogSunDiscScale; + uint View_AtmosphericFogRenderMask; + uint View_AtmosphericFogInscatterAltitudeSampleNum; + float4 View_AtmosphericFogSunColor; + packed_float3 View_NormalCurvatureToRoughnessScaleBias; + float View_RenderingReflectionCaptureMask; + float4 View_AmbientCubemapTint; + float View_AmbientCubemapIntensity; + float View_SkyLightParameters; + float PrePadding_View_2488; + float PrePadding_View_2492; + float4 View_SkyLightColor; + float4 View_SkyIrradianceEnvironmentMap[7]; + float View_MobilePreviewMode; + float View_HMDEyePaddingOffset; + float View_ReflectionCubemapMaxMip; + float View_ShowDecalsMask; + uint View_DistanceFieldAOSpecularOcclusionMode; + float View_IndirectCapsuleSelfShadowingIntensity; + float PrePadding_View_2648; + float PrePadding_View_2652; + packed_float3 View_ReflectionEnvironmentRoughnessMixingScaleBiasAndLargestWeight; + int View_StereoPassIndex; + float4 View_GlobalVolumeCenterAndExtent[4]; + float4 View_GlobalVolumeWorldToUVAddAndMul[4]; + float View_GlobalVolumeDimension; + float View_GlobalVolumeTexelSize; + float View_MaxGlobalDistance; + float View_bCheckerboardSubsurfaceProfileRendering; + packed_float3 View_VolumetricFogInvGridSize; + float PrePadding_View_2828; + packed_float3 View_VolumetricFogGridZParams; + float PrePadding_View_2844; + float2 View_VolumetricFogSVPosToVolumeUV; + float View_VolumetricFogMaxDistance; + float PrePadding_View_2860; + packed_float3 View_VolumetricLightmapWorldToUVScale; + float PrePadding_View_2876; + packed_float3 View_VolumetricLightmapWorldToUVAdd; + float PrePadding_View_2892; + packed_float3 View_VolumetricLightmapIndirectionTextureSize; + float View_VolumetricLightmapBrickSize; + packed_float3 View_VolumetricLightmapBrickTexelSize; + float View_StereoIPD; + float View_IndirectLightingCacheShowFlag; + float View_EyeToPixelSpreadAngle; +}; + +struct type_Globals +{ + float3 SoftTransitionScale; + float4x4 ShadowViewProjectionMatrices[6]; + float InvShadowmapResolution; + float ShadowFadeFraction; + float ShadowSharpen; + float4 LightPositionAndInvRadius; + float2 ProjectionDepthBiasParameters; + float4 PointLightDepthBiasAndProjParameters; +}; + +constant float4 _453 = {}; + +struct main0_out +{ + float4 out_var_SV_Target0 [[color(0)]]; +}; + +fragment main0_out main0(constant type_View& View [[buffer(0)]], constant type_Globals& _Globals [[buffer(1)]], texture2d SceneTexturesStruct_SceneDepthTexture [[texture(0)]], texture2d SceneTexturesStruct_GBufferATexture [[texture(1)]], texture2d SceneTexturesStruct_GBufferBTexture [[texture(2)]], texture2d SceneTexturesStruct_GBufferDTexture [[texture(3)]], depthcube ShadowDepthCubeTexture [[texture(4)]], texture2d SSProfilesTexture [[texture(5)]], sampler SceneTexturesStruct_SceneDepthTextureSampler [[sampler(0)]], sampler SceneTexturesStruct_GBufferATextureSampler [[sampler(1)]], sampler SceneTexturesStruct_GBufferBTextureSampler [[sampler(2)]], sampler SceneTexturesStruct_GBufferDTextureSampler [[sampler(3)]], sampler ShadowDepthTextureSampler [[sampler(4)]], sampler ShadowDepthCubeTextureSampler [[sampler(5)]], float4 gl_FragCoord [[position]]) +{ + main0_out out = {}; + float2 _114 = gl_FragCoord.xy * View.View_BufferSizeAndInvSize.zw; + float4 _118 = SceneTexturesStruct_SceneDepthTexture.sample(SceneTexturesStruct_SceneDepthTextureSampler, _114, level(0.0)); + float _119 = _118.x; + float _133 = ((_119 * View.View_InvDeviceZToWorldZTransform.x) + View.View_InvDeviceZToWorldZTransform.y) + (1.0 / ((_119 * View.View_InvDeviceZToWorldZTransform.z) - View.View_InvDeviceZToWorldZTransform.w)); + float4 _147 = View.View_ScreenToWorld * float4(((_114 - View.View_ScreenPositionScaleBias.wz) / View.View_ScreenPositionScaleBias.xy) * float2(_133), _133, 1.0); + float3 _148 = _147.xyz; + float3 _152 = _Globals.LightPositionAndInvRadius.xyz - _148; + float _158 = length(_152); + bool _160 = (_158 * _Globals.LightPositionAndInvRadius.w) < 1.0; + float _207; + if (_160) + { + float3 _165 = abs(_152); + float _166 = _165.x; + float _167 = _165.y; + float _168 = _165.z; + float _170 = fast::max(_166, fast::max(_167, _168)); + int _189; + if (_170 == _166) + { + _189 = (_166 == _152.x) ? 0 : 1; + } + else + { + int _185; + if (_170 == _167) + { + _185 = (_167 == _152.y) ? 2 : 3; + } + else + { + _185 = (_168 == _152.z) ? 4 : 5; + } + _189 = _185; + } + float4 _196 = _Globals.ShadowViewProjectionMatrices[_189] * float4(_147.xyz, 1.0); + float _198 = _196.w; + _207 = ShadowDepthCubeTexture.sample_compare(ShadowDepthCubeTextureSampler, (_152 / float3(_158)), (_196.z / _198) + ((-_Globals.PointLightDepthBiasAndProjParameters.x) / _198), level(0.0)); + } + else + { + _207 = 1.0; + } + float _213 = fast::clamp(((_207 - 0.5) * _Globals.ShadowSharpen) + 0.5, 0.0, 1.0); + float _218 = sqrt(mix(1.0, _213 * _213, _Globals.ShadowFadeFraction)); + float4 _219 = _453; + _219.z = _218; + float3 _236 = normalize((SceneTexturesStruct_GBufferATexture.sample(SceneTexturesStruct_GBufferATextureSampler, _114, level(0.0)).xyz * float3(2.0)) - float3(1.0)); + uint _240 = uint(round(SceneTexturesStruct_GBufferBTexture.sample(SceneTexturesStruct_GBufferBTextureSampler, _114, level(0.0)).w * 255.0)); + bool _248 = (_240 & 15u) == 5u; + float _448; + if (_248) + { + float4 _260 = SSProfilesTexture.read(uint2(int3(1, int(uint((select(float4(0.0), SceneTexturesStruct_GBufferDTexture.sample(SceneTexturesStruct_GBufferDTextureSampler, _114, level(0.0)), bool4(!(((_240 & 4294967280u) & 16u) != 0u))).x * 255.0) + 0.5)), 0).xy), 0); + float _263 = _260.y * 0.5; + float _274 = pow(fast::clamp(dot(-(_152 * float3(rsqrt(dot(_152, _152)))), _236), 0.0, 1.0), 1.0); + float _445; + if (_160) + { + float3 _278 = _152 / float3(_158); + float3 _280 = normalize(cross(_278, float3(0.0, 0.0, 1.0))); + float3 _284 = float3(_Globals.InvShadowmapResolution); + float3 _285 = _280 * _284; + float3 _286 = cross(_280, _278) * _284; + float3 _287 = abs(_278); + float _288 = _287.x; + float _289 = _287.y; + float _290 = _287.z; + float _292 = fast::max(_288, fast::max(_289, _290)); + int _311; + if (_292 == _288) + { + _311 = (_288 == _278.x) ? 0 : 1; + } + else + { + int _307; + if (_292 == _289) + { + _307 = (_289 == _278.y) ? 2 : 3; + } + else + { + _307 = (_290 == _278.z) ? 4 : 5; + } + _311 = _307; + } + float4 _318 = _Globals.ShadowViewProjectionMatrices[_311] * float4(_148 - (_236 * float3(_263)), 1.0); + float _323 = _260.x * (10.0 / _Globals.LightPositionAndInvRadius.w); + float _329 = (1.0 / (((_318.z / _318.w) * _Globals.PointLightDepthBiasAndProjParameters.z) - _Globals.PointLightDepthBiasAndProjParameters.w)) * _Globals.LightPositionAndInvRadius.w; + float _342 = (_329 - ((1.0 / ((float4(ShadowDepthCubeTexture.sample(ShadowDepthTextureSampler, (_278 + (_286 * float3(2.5))), level(0.0))).x * _Globals.PointLightDepthBiasAndProjParameters.z) - _Globals.PointLightDepthBiasAndProjParameters.w)) * _Globals.LightPositionAndInvRadius.w)) * _323; + float _364 = (_329 - ((1.0 / ((float4(ShadowDepthCubeTexture.sample(ShadowDepthTextureSampler, ((_278 + (_285 * float3(2.3776409626007080078125))) + (_286 * float3(0.77254199981689453125))), level(0.0))).x * _Globals.PointLightDepthBiasAndProjParameters.z) - _Globals.PointLightDepthBiasAndProjParameters.w)) * _Globals.LightPositionAndInvRadius.w)) * _323; + float _387 = (_329 - ((1.0 / ((float4(ShadowDepthCubeTexture.sample(ShadowDepthTextureSampler, ((_278 + (_285 * float3(1.46946299076080322265625))) + (_286 * float3(-2.0225429534912109375))), level(0.0))).x * _Globals.PointLightDepthBiasAndProjParameters.z) - _Globals.PointLightDepthBiasAndProjParameters.w)) * _Globals.LightPositionAndInvRadius.w)) * _323; + float _410 = (_329 - ((1.0 / ((float4(ShadowDepthCubeTexture.sample(ShadowDepthTextureSampler, ((_278 + (_285 * float3(-1.46946299076080322265625))) + (_286 * float3(-2.02254199981689453125))), level(0.0))).x * _Globals.PointLightDepthBiasAndProjParameters.z) - _Globals.PointLightDepthBiasAndProjParameters.w)) * _Globals.LightPositionAndInvRadius.w)) * _323; + float _433 = (_329 - ((1.0 / ((float4(ShadowDepthCubeTexture.sample(ShadowDepthTextureSampler, ((_278 + (_285 * float3(-2.3776409626007080078125))) + (_286 * float3(0.772543013095855712890625))), level(0.0))).x * _Globals.PointLightDepthBiasAndProjParameters.z) - _Globals.PointLightDepthBiasAndProjParameters.w)) * _Globals.LightPositionAndInvRadius.w)) * _323; + _445 = (((((fast::clamp(abs((_342 > 0.0) ? (_342 + _263) : fast::max(0.0, (_342 * _274) + _263)), 0.1500000059604644775390625, 5.0) + 0.25) + (fast::clamp(abs((_364 > 0.0) ? (_364 + _263) : fast::max(0.0, (_364 * _274) + _263)), 0.1500000059604644775390625, 5.0) + 0.25)) + (fast::clamp(abs((_387 > 0.0) ? (_387 + _263) : fast::max(0.0, (_387 * _274) + _263)), 0.1500000059604644775390625, 5.0) + 0.25)) + (fast::clamp(abs((_410 > 0.0) ? (_410 + _263) : fast::max(0.0, (_410 * _274) + _263)), 0.1500000059604644775390625, 5.0) + 0.25)) + (fast::clamp(abs((_433 > 0.0) ? (_433 + _263) : fast::max(0.0, (_433 * _274) + _263)), 0.1500000059604644775390625, 5.0) + 0.25)) * 0.20000000298023223876953125; + } + else + { + _445 = 1.0; + } + _448 = 1.0 - (_445 * 0.20000000298023223876953125); + } + else + { + _448 = 1.0; + } + float4 _451 = float4(float3(1.0).x, float3(1.0).y, _219.z, float3(1.0).z); + _451.w = _248 ? sqrt(_448) : _218; + out.out_var_SV_Target0 = _451; + return out; +} + diff --git a/third_party/spirv-cross/reference/opt/shaders-ue4/asm/frag/global-constant-arrays.asm.frag b/third_party/spirv-cross/reference/opt/shaders-ue4/asm/frag/global-constant-arrays.asm.frag new file mode 100644 index 0000000000..f749ad5388 --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders-ue4/asm/frag/global-constant-arrays.asm.frag @@ -0,0 +1,1141 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + +#include +#include + +using namespace metal; + +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +struct type_Globals +{ + float4 MappingPolynomial; + float3 InverseGamma; + float4 ColorMatrixR_ColorCurveCd1; + float4 ColorMatrixG_ColorCurveCd3Cm3; + float4 ColorMatrixB_ColorCurveCm2; + float4 ColorCurve_Cm0Cd0_Cd2_Ch0Cm1_Ch3; + float4 ColorCurve_Ch1_Ch2; + float4 ColorShadow_Luma; + float4 ColorShadow_Tint1; + float4 ColorShadow_Tint2; + float FilmSlope; + float FilmToe; + float FilmShoulder; + float FilmBlackClip; + float FilmWhiteClip; + packed_float3 ColorScale; + float4 OverlayColor; + float WhiteTemp; + float WhiteTint; + float4 ColorSaturation; + float4 ColorContrast; + float4 ColorGamma; + float4 ColorGain; + float4 ColorOffset; + float4 ColorSaturationShadows; + float4 ColorContrastShadows; + float4 ColorGammaShadows; + float4 ColorGainShadows; + float4 ColorOffsetShadows; + float4 ColorSaturationMidtones; + float4 ColorContrastMidtones; + float4 ColorGammaMidtones; + float4 ColorGainMidtones; + float4 ColorOffsetMidtones; + float4 ColorSaturationHighlights; + float4 ColorContrastHighlights; + float4 ColorGammaHighlights; + float4 ColorGainHighlights; + float4 ColorOffsetHighlights; + float ColorCorrectionShadowsMax; + float ColorCorrectionHighlightsMin; + uint OutputDevice; + uint OutputGamut; + float BlueCorrection; + float ExpandGamut; +}; + +constant spvUnsafeArray _475 = spvUnsafeArray({ -4.0, -4.0, -3.1573765277862548828125, -0.485249996185302734375, 1.84773242473602294921875, 1.84773242473602294921875 }); +constant spvUnsafeArray _476 = spvUnsafeArray({ -0.718548238277435302734375, 2.0810306072235107421875, 3.66812419891357421875, 4.0, 4.0, 4.0 }); +constant spvUnsafeArray _479 = spvUnsafeArray({ -4.97062206268310546875, -3.0293781757354736328125, -2.1261999607086181640625, -1.5104999542236328125, -1.0578000545501708984375, -0.4668000042438507080078125, 0.11937999725341796875, 0.7088134288787841796875, 1.2911865711212158203125, 1.2911865711212158203125 }); +constant spvUnsafeArray _480 = spvUnsafeArray({ 0.80891323089599609375, 1.19108676910400390625, 1.5683000087738037109375, 1.94830000400543212890625, 2.308300018310546875, 2.63840007781982421875, 2.85949993133544921875, 2.9872608184814453125, 3.0127391815185546875, 3.0127391815185546875 }); +constant spvUnsafeArray _482 = spvUnsafeArray({ -2.3010299205780029296875, -2.3010299205780029296875, -1.9312000274658203125, -1.5204999446868896484375, -1.0578000545501708984375, -0.4668000042438507080078125, 0.11937999725341796875, 0.7088134288787841796875, 1.2911865711212158203125, 1.2911865711212158203125 }); +constant spvUnsafeArray _483 = spvUnsafeArray({ 0.801995217800140380859375, 1.19800484180450439453125, 1.5943000316619873046875, 1.99730002880096435546875, 2.3782999515533447265625, 2.7683999538421630859375, 3.0515000820159912109375, 3.2746293544769287109375, 3.32743072509765625, 3.32743072509765625 }); + +constant float3 _391 = {}; + +struct main0_out +{ + float4 out_var_SV_Target0 [[color(0)]]; +}; + +struct main0_in +{ + float2 in_var_TEXCOORD0 [[user(locn0), center_no_perspective]]; +}; + +fragment main0_out main0(main0_in in [[stage_in]], constant type_Globals& _Globals [[buffer(0)]], uint gl_Layer [[render_target_array_index]]) +{ + main0_out out = {}; + float3x3 _546 = float3x3(float3(0.41245639324188232421875, 0.3575761020183563232421875, 0.180437505245208740234375), float3(0.21267290413379669189453125, 0.715152204036712646484375, 0.072175003588199615478515625), float3(0.01933390088379383087158203125, 0.119191996753215789794921875, 0.950304090976715087890625)) * float3x3(float3(1.01303005218505859375, 0.0061053098179399967193603515625, -0.014971000142395496368408203125), float3(0.0076982299797236919403076171875, 0.99816501140594482421875, -0.005032029934227466583251953125), float3(-0.0028413101099431514739990234375, 0.0046851597726345062255859375, 0.92450702190399169921875)); + float3x3 _547 = _546 * float3x3(float3(1.6410233974456787109375, -0.324803292751312255859375, -0.23642469942569732666015625), float3(-0.663662850856781005859375, 1.6153316497802734375, 0.016756348311901092529296875), float3(0.01172189414501190185546875, -0.008284442126750946044921875, 0.98839485645294189453125)); + float3x3 _548 = float3x3(float3(0.662454187870025634765625, 0.1340042054653167724609375, 0.1561876833438873291015625), float3(0.272228717803955078125, 0.674081742763519287109375, 0.053689517080783843994140625), float3(-0.0055746496655046939849853515625, 0.0040607335977256298065185546875, 1.01033914089202880859375)) * float3x3(float3(0.98722398281097412109375, -0.0061132698319852352142333984375, 0.01595330052077770233154296875), float3(-0.007598360069096088409423828125, 1.00186002254486083984375, 0.0053300200961530208587646484375), float3(0.003072570078074932098388671875, -0.0050959498621523380279541015625, 1.0816800594329833984375)); + float3x3 _549 = _548 * float3x3(float3(3.2409698963165283203125, -1.53738319873809814453125, -0.4986107647418975830078125), float3(-0.96924364566802978515625, 1.875967502593994140625, 0.0415550582110881805419921875), float3(0.055630080401897430419921875, -0.2039769589900970458984375, 1.05697154998779296875)); + float3x3 _550 = float3x3(float3(0.952552378177642822265625, 0.0, 9.25), float3(0.3439664542675018310546875, 0.728166103363037109375, -0.07213254272937774658203125), float3(0.0, 0.0, 1.00882518291473388671875)) * float3x3(float3(1.6410233974456787109375, -0.324803292751312255859375, -0.23642469942569732666015625), float3(-0.663662850856781005859375, 1.6153316497802734375, 0.016756348311901092529296875), float3(0.01172189414501190185546875, -0.008284442126750946044921875, 0.98839485645294189453125)); + float3x3 _551 = float3x3(float3(0.662454187870025634765625, 0.1340042054653167724609375, 0.1561876833438873291015625), float3(0.272228717803955078125, 0.674081742763519287109375, 0.053689517080783843994140625), float3(-0.0055746496655046939849853515625, 0.0040607335977256298065185546875, 1.01033914089202880859375)) * float3x3(float3(1.04981100559234619140625, 0.0, -9.74845024757087230682373046875e-05), float3(-0.49590301513671875, 1.37331306934356689453125, 0.09824003279209136962890625), float3(0.0, 0.0, 0.991252005100250244140625)); + float3x3 _576; + for (;;) + { + if (_Globals.OutputGamut == 1u) + { + _576 = _548 * float3x3(float3(2.493396282196044921875, -0.931345880031585693359375, -0.4026944935321807861328125), float3(-0.829486787319183349609375, 1.76265966892242431640625, 0.02362460084259510040283203125), float3(0.0358506999909877777099609375, -0.076182700693607330322265625, 0.957014024257659912109375)); + break; + } + else + { + if (_Globals.OutputGamut == 2u) + { + _576 = _548 * float3x3(float3(1.71660840511322021484375, -0.3556621074676513671875, -0.253360092639923095703125), float3(-0.666682898998260498046875, 1.61647760868072509765625, 0.01576850004494190216064453125), float3(0.017642199993133544921875, -0.04277630150318145751953125, 0.94222867488861083984375)); + break; + } + else + { + if (_Globals.OutputGamut == 3u) + { + _576 = float3x3(float3(0.695452213287353515625, 0.140678703784942626953125, 0.16386906802654266357421875), float3(0.0447945632040500640869140625, 0.859671115875244140625, 0.095534317195415496826171875), float3(-0.0055258828215301036834716796875, 0.0040252101607620716094970703125, 1.00150072574615478515625)); + break; + } + else + { + if (_Globals.OutputGamut == 4u) + { + _576 = float3x3(float3(1.0, 0.0, 0.0), float3(0.0, 1.0, 0.0), float3(0.0, 0.0, 1.0)); + break; + } + else + { + _576 = _549; + break; + } + } + } + } + } + float3 _577 = float4((in.in_var_TEXCOORD0 - float2(0.015625)) * float2(1.03225803375244140625), float(gl_Layer) * 0.0322580635547637939453125, 0.0).xyz; + float3 _599; + if (_Globals.OutputDevice >= 3u) + { + float3 _591 = pow(_577, float3(0.0126833133399486541748046875)); + _599 = pow(fast::max(float3(0.0), _591 - float3(0.8359375)) / (float3(18.8515625) - (float3(18.6875) * _591)), float3(6.277394771575927734375)) * float3(10000.0); + } + else + { + _599 = (exp2((_577 - float3(0.434017598628997802734375)) * float3(14.0)) * float3(0.180000007152557373046875)) - float3(0.00266771926544606685638427734375); + } + float _602 = _Globals.WhiteTemp * 1.00055634975433349609375; + float _616 = (_602 <= 7000.0) ? (0.24406300485134124755859375 + ((99.1100006103515625 + ((2967800.0 - (4604438528.0 / _Globals.WhiteTemp)) / _602)) / _602)) : (0.23703999817371368408203125 + ((247.4799957275390625 + ((1901800.0 - (2005284352.0 / _Globals.WhiteTemp)) / _602)) / _602)); + float _633 = ((0.860117733478546142578125 + (0.00015411825734190642833709716796875 * _Globals.WhiteTemp)) + ((1.2864121856637211749330163002014e-07 * _Globals.WhiteTemp) * _Globals.WhiteTemp)) / ((1.0 + (0.0008424202096648514270782470703125 * _Globals.WhiteTemp)) + ((7.0814513719597016461193561553955e-07 * _Globals.WhiteTemp) * _Globals.WhiteTemp)); + float _644 = ((0.317398726940155029296875 + (4.25 * _Globals.WhiteTemp)) + ((4.2048167614439080352894961833954e-08 * _Globals.WhiteTemp) * _Globals.WhiteTemp)) / ((1.0 - (2.8974181986995972692966461181641e-05 * _Globals.WhiteTemp)) + ((1.6145605741257895715534687042236e-07 * _Globals.WhiteTemp) * _Globals.WhiteTemp)); + float _649 = ((2.0 * _633) - (8.0 * _644)) + 4.0; + float2 _653 = float2((3.0 * _633) / _649, (2.0 * _644) / _649); + float2 _660 = normalize(float2(_633, _644)); + float _665 = _633 + (((-_660.y) * _Globals.WhiteTint) * 0.0500000007450580596923828125); + float _669 = _644 + ((_660.x * _Globals.WhiteTint) * 0.0500000007450580596923828125); + float _674 = ((2.0 * _665) - (8.0 * _669)) + 4.0; + float2 _680 = select(float2(_616, (_616 * (((-3.0) * _616) + 2.86999988555908203125)) - 0.2750000059604644775390625), _653, bool2(_Globals.WhiteTemp < 4000.0)) + (float2((3.0 * _665) / _674, (2.0 * _669) / _674) - _653); + float _681 = _680.x; + float _682 = _680.y; + float _683 = fast::max(_682, 1.0000000133514319600180897396058e-10); + float3 _685 = _391; + _685.x = _681 / _683; + float3 _686 = _685; + _686.y = 1.0; + float3 _690 = _686; + _690.z = ((1.0 - _681) - _682) / _683; + float3 _693 = _391; + _693.x = 0.950455963611602783203125; + float3 _694 = _693; + _694.y = 1.0; + float3 _696 = _694; + _696.z = 1.0890576839447021484375; + float3 _697 = _690 * float3x3(float3(0.89509999752044677734375, 0.2664000093936920166015625, -0.16140000522136688232421875), float3(-0.750199973583221435546875, 1.71350002288818359375, 0.0366999991238117218017578125), float3(0.0388999991118907928466796875, -0.06849999725818634033203125, 1.02960002422332763671875)); + float3 _698 = _696 * float3x3(float3(0.89509999752044677734375, 0.2664000093936920166015625, -0.16140000522136688232421875), float3(-0.750199973583221435546875, 1.71350002288818359375, 0.0366999991238117218017578125), float3(0.0388999991118907928466796875, -0.06849999725818634033203125, 1.02960002422332763671875)); + float3 _717 = (_599 * ((float3x3(float3(0.41245639324188232421875, 0.3575761020183563232421875, 0.180437505245208740234375), float3(0.21267290413379669189453125, 0.715152204036712646484375, 0.072175003588199615478515625), float3(0.01933390088379383087158203125, 0.119191996753215789794921875, 0.950304090976715087890625)) * ((float3x3(float3(0.89509999752044677734375, 0.2664000093936920166015625, -0.16140000522136688232421875), float3(-0.750199973583221435546875, 1.71350002288818359375, 0.0366999991238117218017578125), float3(0.0388999991118907928466796875, -0.06849999725818634033203125, 1.02960002422332763671875)) * float3x3(float3(_698.x / _697.x, 0.0, 0.0), float3(0.0, _698.y / _697.y, 0.0), float3(0.0, 0.0, _698.z / _697.z))) * float3x3(float3(0.986992895603179931640625, -0.14705429971218109130859375, 0.15996269881725311279296875), float3(0.4323053061962127685546875, 0.518360316753387451171875, 0.049291200935840606689453125), float3(-0.00852870009839534759521484375, 0.0400427989661693572998046875, 0.968486726284027099609375)))) * float3x3(float3(3.2409698963165283203125, -1.53738319873809814453125, -0.4986107647418975830078125), float3(-0.96924364566802978515625, 1.875967502593994140625, 0.0415550582110881805419921875), float3(0.055630080401897430419921875, -0.2039769589900970458984375, 1.05697154998779296875)))) * _547; + float3 _745; + if (_Globals.ColorShadow_Tint2.w != 0.0) + { + float _724 = dot(_717, float3(0.272228717803955078125, 0.674081742763519287109375, 0.053689517080783843994140625)); + float3 _727 = (_717 / float3(_724)) - float3(1.0); + _745 = mix(_717, _717 * (_549 * (float3x3(float3(0.544169127941131591796875, 0.23959259688854217529296875, 0.16669429838657379150390625), float3(0.23946559429168701171875, 0.702153027057647705078125, 0.058381401002407073974609375), float3(-0.0023439000360667705535888671875, 0.0361833982169628143310546875, 1.05521833896636962890625)) * float3x3(float3(1.6410233974456787109375, -0.324803292751312255859375, -0.23642469942569732666015625), float3(-0.663662850856781005859375, 1.6153316497802734375, 0.016756348311901092529296875), float3(0.01172189414501190185546875, -0.008284442126750946044921875, 0.98839485645294189453125)))), float3((1.0 - exp2((-4.0) * dot(_727, _727))) * (1.0 - exp2((((-4.0) * _Globals.ExpandGamut) * _724) * _724)))); + } + else + { + _745 = _717; + } + float _746 = dot(_745, float3(0.272228717803955078125, 0.674081742763519287109375, 0.053689517080783843994140625)); + float4 _751 = _Globals.ColorSaturationShadows * _Globals.ColorSaturation; + float4 _756 = _Globals.ColorContrastShadows * _Globals.ColorContrast; + float4 _761 = _Globals.ColorGammaShadows * _Globals.ColorGamma; + float4 _766 = _Globals.ColorGainShadows * _Globals.ColorGain; + float4 _771 = _Globals.ColorOffsetShadows + _Globals.ColorOffset; + float3 _772 = float3(_746); + float _804 = smoothstep(0.0, _Globals.ColorCorrectionShadowsMax, _746); + float4 _808 = _Globals.ColorSaturationHighlights * _Globals.ColorSaturation; + float4 _811 = _Globals.ColorContrastHighlights * _Globals.ColorContrast; + float4 _814 = _Globals.ColorGammaHighlights * _Globals.ColorGamma; + float4 _817 = _Globals.ColorGainHighlights * _Globals.ColorGain; + float4 _820 = _Globals.ColorOffsetHighlights + _Globals.ColorOffset; + float _852 = smoothstep(_Globals.ColorCorrectionHighlightsMin, 1.0, _746); + float4 _855 = _Globals.ColorSaturationMidtones * _Globals.ColorSaturation; + float4 _858 = _Globals.ColorContrastMidtones * _Globals.ColorContrast; + float4 _861 = _Globals.ColorGammaMidtones * _Globals.ColorGamma; + float4 _864 = _Globals.ColorGainMidtones * _Globals.ColorGain; + float4 _867 = _Globals.ColorOffsetMidtones + _Globals.ColorOffset; + float3 _905 = ((((pow(pow(fast::max(float3(0.0), mix(_772, _745, _751.xyz * float3(_751.w))) * float3(5.5555553436279296875), _756.xyz * float3(_756.w)) * float3(0.180000007152557373046875), float3(1.0) / (_761.xyz * float3(_761.w))) * (_766.xyz * float3(_766.w))) + (_771.xyz + float3(_771.w))) * float3(1.0 - _804)) + (((pow(pow(fast::max(float3(0.0), mix(_772, _745, _855.xyz * float3(_855.w))) * float3(5.5555553436279296875), _858.xyz * float3(_858.w)) * float3(0.180000007152557373046875), float3(1.0) / (_861.xyz * float3(_861.w))) * (_864.xyz * float3(_864.w))) + (_867.xyz + float3(_867.w))) * float3(_804 - _852))) + (((pow(pow(fast::max(float3(0.0), mix(_772, _745, _808.xyz * float3(_808.w))) * float3(5.5555553436279296875), _811.xyz * float3(_811.w)) * float3(0.180000007152557373046875), float3(1.0) / (_814.xyz * float3(_814.w))) * (_817.xyz * float3(_817.w))) + (_820.xyz + float3(_820.w))) * float3(_852)); + float3 _906 = _905 * _549; + float3 _914 = float3(_Globals.BlueCorrection); + float3 _916 = mix(_905, _905 * ((_551 * float3x3(float3(0.940437257289886474609375, -0.01830687932670116424560546875, 0.07786960899829864501953125), float3(0.008378696627914905548095703125, 0.82866001129150390625, 0.162961304187774658203125), float3(0.0005471261101774871349334716796875, -0.00088337459601461887359619140625, 1.00033628940582275390625))) * _550), _914) * _551; + float _917 = _916.x; + float _918 = _916.y; + float _920 = _916.z; + float _923 = fast::max(fast::max(_917, _918), _920); + float _928 = (fast::max(_923, 1.0000000133514319600180897396058e-10) - fast::max(fast::min(fast::min(_917, _918), _920), 1.0000000133514319600180897396058e-10)) / fast::max(_923, 0.00999999977648258209228515625); + float _941 = ((_920 + _918) + _917) + (1.75 * sqrt(((_920 * (_920 - _918)) + (_918 * (_918 - _917))) + (_917 * (_917 - _920)))); + float _942 = _941 * 0.3333333432674407958984375; + float _943 = _928 - 0.4000000059604644775390625; + float _948 = fast::max(1.0 - abs(_943 * 2.5), 0.0); + float _956 = (1.0 + (float(int(sign(_943 * 5.0))) * (1.0 - (_948 * _948)))) * 0.02500000037252902984619140625; + float _969; + if (_942 <= 0.053333334624767303466796875) + { + _969 = _956; + } + else + { + float _968; + if (_942 >= 0.1599999964237213134765625) + { + _968 = 0.0; + } + else + { + _968 = _956 * ((0.23999999463558197021484375 / _941) - 0.5); + } + _969 = _968; + } + float3 _972 = _916 * float3(1.0 + _969); + float _973 = _972.x; + float _974 = _972.y; + float _976 = _972.z; + float _990; + if ((_973 == _974) && (_974 == _976)) + { + _990 = 0.0; + } + else + { + _990 = 57.2957763671875 * atan2(1.73205077648162841796875 * (_974 - _976), ((2.0 * _973) - _974) - _976); + } + float _995; + if (_990 < 0.0) + { + _995 = _990 + 360.0; + } + else + { + _995 = _990; + } + float _996 = fast::clamp(_995, 0.0, 360.0); + float _1001; + if (_996 > 180.0) + { + _1001 = _996 - 360.0; + } + else + { + _1001 = _996; + } + float _1005 = smoothstep(0.0, 1.0, 1.0 - abs(_1001 * 0.01481481455266475677490234375)); + float3 _1012 = _972; + _1012.x = _973 + ((((_1005 * _1005) * _928) * (0.02999999932944774627685546875 - _973)) * 0.180000007152557373046875); + float3 _1014 = fast::max(float3(0.0), _1012 * float3x3(float3(1.45143926143646240234375, -0.236510753631591796875, -0.214928567409515380859375), float3(-0.07655377686023712158203125, 1.1762297153472900390625, -0.0996759235858917236328125), float3(0.0083161480724811553955078125, -0.0060324496589601039886474609375, 0.99771630764007568359375))); + float _1023 = (1.0 + _Globals.FilmBlackClip) - _Globals.FilmToe; + float _1026 = 1.0 + _Globals.FilmWhiteClip; + float _1029 = _1026 - _Globals.FilmShoulder; + float _1056; + if (_Globals.FilmToe > 0.800000011920928955078125) + { + _1056 = ((0.819999992847442626953125 - _Globals.FilmToe) / _Globals.FilmSlope) + (-0.744727432727813720703125); + } + else + { + float _1035 = (0.180000007152557373046875 + _Globals.FilmBlackClip) / _1023; + _1056 = (-0.744727432727813720703125) - ((0.5 * log(_1035 / (2.0 - _1035))) * (_1023 / _Globals.FilmSlope)); + } + float _1061 = ((1.0 - _Globals.FilmToe) / _Globals.FilmSlope) - _1056; + float _1063 = (_Globals.FilmShoulder / _Globals.FilmSlope) - _1061; + float3 _1067 = log(mix(float3(dot(_1014, float3(0.272228717803955078125, 0.674081742763519287109375, 0.053689517080783843994140625))), _1014, float3(0.959999978542327880859375))) * float3(0.4342944622039794921875); + float3 _1071 = float3(_Globals.FilmSlope) * (_1067 + float3(_1061)); + float3 _1079 = float3(_1056); + float3 _1080 = _1067 - _1079; + float3 _1092 = float3(_1063); + float3 _1106 = fast::clamp(_1080 / float3(_1063 - _1056), float3(0.0), float3(1.0)); + float3 _1110 = select(_1106, float3(1.0) - _1106, bool3(_1063 < _1056)); + float3 _1115 = mix(select(_1071, float3(-_Globals.FilmBlackClip) + (float3(2.0 * _1023) / (float3(1.0) + exp(float3(((-2.0) * _Globals.FilmSlope) / _1023) * _1080))), _1067 < _1079), select(_1071, float3(_1026) - (float3(2.0 * _1029) / (float3(1.0) + exp(float3((2.0 * _Globals.FilmSlope) / _1029) * (_1067 - _1092)))), _1067 > _1092), ((float3(3.0) - (float3(2.0) * _1110)) * _1110) * _1110); + float3 _1119 = fast::max(float3(0.0), mix(float3(dot(_1115, float3(0.272228717803955078125, 0.674081742763519287109375, 0.053689517080783843994140625))), _1115, float3(0.930000007152557373046875))); + float3 _1189; + if (_Globals.ColorShadow_Tint2.w == 0.0) + { + float3 _1131 = _391; + _1131.x = dot(_906, _Globals.ColorMatrixR_ColorCurveCd1.xyz); + float3 _1136 = _1131; + _1136.y = dot(_906, _Globals.ColorMatrixG_ColorCurveCd3Cm3.xyz); + float3 _1141 = _1136; + _1141.z = dot(_906, _Globals.ColorMatrixB_ColorCurveCm2.xyz); + float3 _1157 = fast::max(float3(0.0), _1141 * (_Globals.ColorShadow_Tint1.xyz + (_Globals.ColorShadow_Tint2.xyz * float3(1.0 / (dot(_906, _Globals.ColorShadow_Luma.xyz) + 1.0))))); + float3 _1162 = fast::max(float3(0.0), _Globals.ColorCurve_Cm0Cd0_Cd2_Ch0Cm1_Ch3.xxx - _1157); + float3 _1164 = fast::max(_1157, _Globals.ColorCurve_Cm0Cd0_Cd2_Ch0Cm1_Ch3.zzz); + _1189 = ((((_1164 * _Globals.ColorCurve_Ch1_Ch2.xxx) + _Globals.ColorCurve_Ch1_Ch2.yyy) * (float3(1.0) / (_1164 + _Globals.ColorCurve_Cm0Cd0_Cd2_Ch0Cm1_Ch3.www))) + ((fast::clamp(_1157, _Globals.ColorCurve_Cm0Cd0_Cd2_Ch0Cm1_Ch3.xxx, _Globals.ColorCurve_Cm0Cd0_Cd2_Ch0Cm1_Ch3.zzz) * _Globals.ColorMatrixB_ColorCurveCm2.www) + (((_1162 * _Globals.ColorMatrixR_ColorCurveCd1.www) * (float3(1.0) / (_1162 + _Globals.ColorCurve_Cm0Cd0_Cd2_Ch0Cm1_Ch3.yyy))) + _Globals.ColorMatrixG_ColorCurveCd3Cm3.www))) - float3(0.00200000009499490261077880859375); + } + else + { + _1189 = fast::max(float3(0.0), mix(_1119, _1119 * ((_551 * float3x3(float3(1.06317996978759765625, 0.02339559979736804962158203125, -0.08657260239124298095703125), float3(-0.010633699595928192138671875, 1.2063200473785400390625, -0.1956900060176849365234375), float3(-0.0005908869788981974124908447265625, 0.00105247995816171169281005859375, 0.999538004398345947265625))) * _550), _914) * _549); + } + float3 _1218 = pow(fast::max(float3(0.0), mix((((float3(_Globals.MappingPolynomial.x) * (_1189 * _1189)) + (float3(_Globals.MappingPolynomial.y) * _1189)) + float3(_Globals.MappingPolynomial.z)) * float3(_Globals.ColorScale), _Globals.OverlayColor.xyz, float3(_Globals.OverlayColor.w))), float3(_Globals.InverseGamma.y)); + float3 _3001; + if (_Globals.OutputDevice == 0u) + { + float _2961 = _1218.x; + float _2973; + for (;;) + { + if (_2961 < 0.00313066993840038776397705078125) + { + _2973 = _2961 * 12.9200000762939453125; + break; + } + _2973 = (pow(_2961, 0.4166666567325592041015625) * 1.05499994754791259765625) - 0.054999999701976776123046875; + break; + } + float _2974 = _1218.y; + float _2986; + for (;;) + { + if (_2974 < 0.00313066993840038776397705078125) + { + _2986 = _2974 * 12.9200000762939453125; + break; + } + _2986 = (pow(_2974, 0.4166666567325592041015625) * 1.05499994754791259765625) - 0.054999999701976776123046875; + break; + } + float _2987 = _1218.z; + float _2999; + for (;;) + { + if (_2987 < 0.00313066993840038776397705078125) + { + _2999 = _2987 * 12.9200000762939453125; + break; + } + _2999 = (pow(_2987, 0.4166666567325592041015625) * 1.05499994754791259765625) - 0.054999999701976776123046875; + break; + } + _3001 = float3(_2973, _2986, _2999); + } + else + { + float3 _2960; + if (_Globals.OutputDevice == 1u) + { + float3 _2953 = fast::max(float3(6.1035199905745685100555419921875e-05), (_1218 * _547) * _576); + _2960 = fast::min(_2953 * float3(4.5), (pow(fast::max(_2953, float3(0.017999999225139617919921875)), float3(0.449999988079071044921875)) * float3(1.09899997711181640625)) - float3(0.098999999463558197021484375)); + } + else + { + float3 _2950; + if ((_Globals.OutputDevice == 3u) || (_Globals.OutputDevice == 5u)) + { + float3 _2100 = (_906 * float3(1.5)) * (_546 * float3x3(float3(1.04981100559234619140625, 0.0, -9.74845024757087230682373046875e-05), float3(-0.49590301513671875, 1.37331306934356689453125, 0.09824003279209136962890625), float3(0.0, 0.0, 0.991252005100250244140625))); + float _2101 = _2100.x; + float _2102 = _2100.y; + float _2104 = _2100.z; + float _2107 = fast::max(fast::max(_2101, _2102), _2104); + float _2112 = (fast::max(_2107, 1.0000000133514319600180897396058e-10) - fast::max(fast::min(fast::min(_2101, _2102), _2104), 1.0000000133514319600180897396058e-10)) / fast::max(_2107, 0.00999999977648258209228515625); + float _2125 = ((_2104 + _2102) + _2101) + (1.75 * sqrt(((_2104 * (_2104 - _2102)) + (_2102 * (_2102 - _2101))) + (_2101 * (_2101 - _2104)))); + float _2126 = _2125 * 0.3333333432674407958984375; + float _2127 = _2112 - 0.4000000059604644775390625; + float _2132 = fast::max(1.0 - abs(_2127 * 2.5), 0.0); + float _2140 = (1.0 + (float(int(sign(_2127 * 5.0))) * (1.0 - (_2132 * _2132)))) * 0.02500000037252902984619140625; + float _2153; + if (_2126 <= 0.053333334624767303466796875) + { + _2153 = _2140; + } + else + { + float _2152; + if (_2126 >= 0.1599999964237213134765625) + { + _2152 = 0.0; + } + else + { + _2152 = _2140 * ((0.23999999463558197021484375 / _2125) - 0.5); + } + _2153 = _2152; + } + float3 _2156 = _2100 * float3(1.0 + _2153); + float _2157 = _2156.x; + float _2158 = _2156.y; + float _2160 = _2156.z; + float _2174; + if ((_2157 == _2158) && (_2158 == _2160)) + { + _2174 = 0.0; + } + else + { + _2174 = 57.2957763671875 * atan2(1.73205077648162841796875 * (_2158 - _2160), ((2.0 * _2157) - _2158) - _2160); + } + float _2179; + if (_2174 < 0.0) + { + _2179 = _2174 + 360.0; + } + else + { + _2179 = _2174; + } + float _2180 = fast::clamp(_2179, 0.0, 360.0); + float _2185; + if (_2180 > 180.0) + { + _2185 = _2180 - 360.0; + } + else + { + _2185 = _2180; + } + float _2235; + if ((_2185 > (-67.5)) && (_2185 < 67.5)) + { + float _2192 = (_2185 - (-67.5)) * 0.0296296291053295135498046875; + int _2193 = int(_2192); + float _2195 = _2192 - float(_2193); + float _2196 = _2195 * _2195; + float _2197 = _2196 * _2195; + float _2234; + if (_2193 == 3) + { + _2234 = (((_2197 * (-0.16666667163372039794921875)) + (_2196 * 0.5)) + (_2195 * (-0.5))) + 0.16666667163372039794921875; + } + else + { + float _2227; + if (_2193 == 2) + { + _2227 = ((_2197 * 0.5) + (_2196 * (-1.0))) + 0.666666686534881591796875; + } + else + { + float _2222; + if (_2193 == 1) + { + _2222 = (((_2197 * (-0.5)) + (_2196 * 0.5)) + (_2195 * 0.5)) + 0.16666667163372039794921875; + } + else + { + float _2215; + if (_2193 == 0) + { + _2215 = _2197 * 0.16666667163372039794921875; + } + else + { + _2215 = 0.0; + } + _2222 = _2215; + } + _2227 = _2222; + } + _2234 = _2227; + } + _2235 = _2234; + } + else + { + _2235 = 0.0; + } + float3 _2242 = _2156; + _2242.x = _2157 + ((((_2235 * 1.5) * _2112) * (0.02999999932944774627685546875 - _2157)) * 0.180000007152557373046875); + float3 _2245 = fast::clamp(fast::clamp(_2242, float3(0.0), float3(65535.0)) * float3x3(float3(1.45143926143646240234375, -0.236510753631591796875, -0.214928567409515380859375), float3(-0.07655377686023712158203125, 1.1762297153472900390625, -0.0996759235858917236328125), float3(0.0083161480724811553955078125, -0.0060324496589601039886474609375, 0.99771630764007568359375)), float3(0.0), float3(65535.0)); + float3 _2248 = mix(float3(dot(_2245, float3(0.272228717803955078125, 0.674081742763519287109375, 0.053689517080783843994140625))), _2245, float3(0.959999978542327880859375)); + float _2249 = _2248.x; + float _2258 = log((_2249 <= 0.0) ? 6.103515625e-05 : _2249) * 0.4342944622039794921875; + float _2327; + if (_2258 <= (-5.2601776123046875)) + { + _2327 = -4.0; + } + else + { + float _2324; + if ((_2258 > (-5.2601776123046875)) && (_2258 < (-0.744727432727813720703125))) + { + float _2307 = (_2258 - (-5.2601776123046875)) * 0.6643855571746826171875; + int _2308 = int(_2307); + float _2310 = _2307 - float(_2308); + _2324 = dot(float3(_2310 * _2310, _2310, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_475[_2308], _475[_2308 + 1], _475[_2308 + 2])); + } + else + { + float _2303; + if ((_2258 >= (-0.744727432727813720703125)) && (_2258 < 4.673812389373779296875)) + { + float _2286 = (_2258 - (-0.744727432727813720703125)) * 0.55365467071533203125; + int _2287 = int(_2286); + float _2289 = _2286 - float(_2287); + _2303 = dot(float3(_2289 * _2289, _2289, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_476[_2287], _476[_2287 + 1], _476[_2287 + 2])); + } + else + { + _2303 = 4.0; + } + _2324 = _2303; + } + _2327 = _2324; + } + float3 _2329 = _391; + _2329.x = pow(10.0, _2327); + float _2330 = _2248.y; + float _2334 = log((_2330 <= 0.0) ? 6.103515625e-05 : _2330) * 0.4342944622039794921875; + float _2401; + if (_2334 <= (-5.2601776123046875)) + { + _2401 = -4.0; + } + else + { + float _2398; + if ((_2334 > (-5.2601776123046875)) && (_2334 < (-0.744727432727813720703125))) + { + float _2381 = (_2334 - (-5.2601776123046875)) * 0.6643855571746826171875; + int _2382 = int(_2381); + float _2384 = _2381 - float(_2382); + _2398 = dot(float3(_2384 * _2384, _2384, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_475[_2382], _475[_2382 + 1], _475[_2382 + 2])); + } + else + { + float _2377; + if ((_2334 >= (-0.744727432727813720703125)) && (_2334 < 4.673812389373779296875)) + { + float _2360 = (_2334 - (-0.744727432727813720703125)) * 0.55365467071533203125; + int _2361 = int(_2360); + float _2363 = _2360 - float(_2361); + _2377 = dot(float3(_2363 * _2363, _2363, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_476[_2361], _476[_2361 + 1], _476[_2361 + 2])); + } + else + { + _2377 = 4.0; + } + _2398 = _2377; + } + _2401 = _2398; + } + float3 _2403 = _2329; + _2403.y = pow(10.0, _2401); + float _2404 = _2248.z; + float _2408 = log((_2404 <= 0.0) ? 6.103515625e-05 : _2404) * 0.4342944622039794921875; + float _2475; + if (_2408 <= (-5.2601776123046875)) + { + _2475 = -4.0; + } + else + { + float _2472; + if ((_2408 > (-5.2601776123046875)) && (_2408 < (-0.744727432727813720703125))) + { + float _2455 = (_2408 - (-5.2601776123046875)) * 0.6643855571746826171875; + int _2456 = int(_2455); + float _2458 = _2455 - float(_2456); + _2472 = dot(float3(_2458 * _2458, _2458, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_475[_2456], _475[_2456 + 1], _475[_2456 + 2])); + } + else + { + float _2451; + if ((_2408 >= (-0.744727432727813720703125)) && (_2408 < 4.673812389373779296875)) + { + float _2434 = (_2408 - (-0.744727432727813720703125)) * 0.55365467071533203125; + int _2435 = int(_2434); + float _2437 = _2434 - float(_2435); + _2451 = dot(float3(_2437 * _2437, _2437, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_476[_2435], _476[_2435 + 1], _476[_2435 + 2])); + } + else + { + _2451 = 4.0; + } + _2472 = _2451; + } + _2475 = _2472; + } + float3 _2477 = _2403; + _2477.z = pow(10.0, _2475); + float3 _2479 = (_2477 * float3x3(float3(0.695452213287353515625, 0.140678703784942626953125, 0.16386906802654266357421875), float3(0.0447945632040500640869140625, 0.859671115875244140625, 0.095534317195415496826171875), float3(-0.0055258828215301036834716796875, 0.0040252101607620716094970703125, 1.00150072574615478515625))) * float3x3(float3(1.45143926143646240234375, -0.236510753631591796875, -0.214928567409515380859375), float3(-0.07655377686023712158203125, 1.1762297153472900390625, -0.0996759235858917236328125), float3(0.0083161480724811553955078125, -0.0060324496589601039886474609375, 0.99771630764007568359375)); + float _2612 = pow(10.0, (float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_476[0], _476[1], _476[2])).z); + float _2684 = pow(10.0, dot(float3(0.4444443881511688232421875, 0.66666662693023681640625, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_476[1], _476[2], _476[3]))); + float _2685 = _2479.x; + float _2688 = log((_2685 <= 0.0) ? 9.9999997473787516355514526367188e-05 : _2685); + float _2689 = _2688 * 0.4342944622039794921875; + float _2690 = log(pow(10.0, dot(float3(0.3600003719329833984375, 0.600000321865081787109375, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_475[0], _475[1], _475[2])))); + float _2691 = _2690 * 0.4342944622039794921875; + float _2768; + if (_2689 <= _2691) + { + _2768 = (_2688 * 1.3028833866119384765625) + ((-4.0) - (_2690 * 1.3028833866119384765625)); + } + else + { + float _2698 = log(_2612) * 0.4342944622039794921875; + float _2760; + if ((_2689 > _2691) && (_2689 < _2698)) + { + float _2743 = (7.0 * (_2689 - _2691)) / (_2698 - _2691); + int _2744 = int(_2743); + float _2746 = _2743 - float(_2744); + _2760 = dot(float3(_2746 * _2746, _2746, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_479[_2744], _479[_2744 + 1], _479[_2744 + 2])); + } + else + { + float _2705 = log(_2684); + float _2706 = _2705 * 0.4342944622039794921875; + float _2739; + if ((_2689 >= _2698) && (_2689 < _2706)) + { + float _2722 = (7.0 * (_2689 - _2698)) / (_2706 - _2698); + int _2723 = int(_2722); + float _2725 = _2722 - float(_2723); + _2739 = dot(float3(_2725 * _2725, _2725, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_480[_2723], _480[_2723 + 1], _480[_2723 + 2])); + } + else + { + _2739 = (_2688 * 0.026057668030261993408203125) + (3.0 - (_2705 * 0.026057668030261993408203125)); + } + _2760 = _2739; + } + _2768 = _2760; + } + float3 _2770 = _391; + _2770.x = pow(10.0, _2768); + float _2771 = _2479.y; + float _2774 = log((_2771 <= 0.0) ? 9.9999997473787516355514526367188e-05 : _2771); + float _2775 = _2774 * 0.4342944622039794921875; + float _2852; + if (_2775 <= _2691) + { + _2852 = (_2774 * 1.3028833866119384765625) + ((-4.0) - (_2690 * 1.3028833866119384765625)); + } + else + { + float _2782 = log(_2612) * 0.4342944622039794921875; + float _2844; + if ((_2775 > _2691) && (_2775 < _2782)) + { + float _2827 = (7.0 * (_2775 - _2691)) / (_2782 - _2691); + int _2828 = int(_2827); + float _2830 = _2827 - float(_2828); + _2844 = dot(float3(_2830 * _2830, _2830, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_479[_2828], _479[_2828 + 1], _479[_2828 + 2])); + } + else + { + float _2789 = log(_2684); + float _2790 = _2789 * 0.4342944622039794921875; + float _2823; + if ((_2775 >= _2782) && (_2775 < _2790)) + { + float _2806 = (7.0 * (_2775 - _2782)) / (_2790 - _2782); + int _2807 = int(_2806); + float _2809 = _2806 - float(_2807); + _2823 = dot(float3(_2809 * _2809, _2809, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_480[_2807], _480[_2807 + 1], _480[_2807 + 2])); + } + else + { + _2823 = (_2774 * 0.026057668030261993408203125) + (3.0 - (_2789 * 0.026057668030261993408203125)); + } + _2844 = _2823; + } + _2852 = _2844; + } + float3 _2854 = _2770; + _2854.y = pow(10.0, _2852); + float _2855 = _2479.z; + float _2858 = log((_2855 <= 0.0) ? 9.9999997473787516355514526367188e-05 : _2855); + float _2859 = _2858 * 0.4342944622039794921875; + float _2936; + if (_2859 <= _2691) + { + _2936 = (_2858 * 1.3028833866119384765625) + ((-4.0) - (_2690 * 1.3028833866119384765625)); + } + else + { + float _2866 = log(_2612) * 0.4342944622039794921875; + float _2928; + if ((_2859 > _2691) && (_2859 < _2866)) + { + float _2911 = (7.0 * (_2859 - _2691)) / (_2866 - _2691); + int _2912 = int(_2911); + float _2914 = _2911 - float(_2912); + _2928 = dot(float3(_2914 * _2914, _2914, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_479[_2912], _479[_2912 + 1], _479[_2912 + 2])); + } + else + { + float _2873 = log(_2684); + float _2874 = _2873 * 0.4342944622039794921875; + float _2907; + if ((_2859 >= _2866) && (_2859 < _2874)) + { + float _2890 = (7.0 * (_2859 - _2866)) / (_2874 - _2866); + int _2891 = int(_2890); + float _2893 = _2890 - float(_2891); + _2907 = dot(float3(_2893 * _2893, _2893, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_480[_2891], _480[_2891 + 1], _480[_2891 + 2])); + } + else + { + _2907 = (_2858 * 0.026057668030261993408203125) + (3.0 - (_2873 * 0.026057668030261993408203125)); + } + _2928 = _2907; + } + _2936 = _2928; + } + float3 _2938 = _2854; + _2938.z = pow(10.0, _2936); + float3 _2942 = pow(((_2938 - float3(3.5073844628641381859779357910156e-05)) * _576) * float3(9.9999997473787516355514526367188e-05), float3(0.1593017578125)); + _2950 = pow((float3(0.8359375) + (float3(18.8515625) * _2942)) * (float3(1.0) / (float3(1.0) + (float3(18.6875) * _2942))), float3(78.84375)); + } + else + { + float3 _2097; + if ((_Globals.OutputDevice == 4u) || (_Globals.OutputDevice == 6u)) + { + float3 _1263 = (_906 * float3(1.5)) * (_546 * float3x3(float3(1.04981100559234619140625, 0.0, -9.74845024757087230682373046875e-05), float3(-0.49590301513671875, 1.37331306934356689453125, 0.09824003279209136962890625), float3(0.0, 0.0, 0.991252005100250244140625))); + float _1264 = _1263.x; + float _1265 = _1263.y; + float _1267 = _1263.z; + float _1270 = fast::max(fast::max(_1264, _1265), _1267); + float _1275 = (fast::max(_1270, 1.0000000133514319600180897396058e-10) - fast::max(fast::min(fast::min(_1264, _1265), _1267), 1.0000000133514319600180897396058e-10)) / fast::max(_1270, 0.00999999977648258209228515625); + float _1288 = ((_1267 + _1265) + _1264) + (1.75 * sqrt(((_1267 * (_1267 - _1265)) + (_1265 * (_1265 - _1264))) + (_1264 * (_1264 - _1267)))); + float _1289 = _1288 * 0.3333333432674407958984375; + float _1290 = _1275 - 0.4000000059604644775390625; + float _1295 = fast::max(1.0 - abs(_1290 * 2.5), 0.0); + float _1303 = (1.0 + (float(int(sign(_1290 * 5.0))) * (1.0 - (_1295 * _1295)))) * 0.02500000037252902984619140625; + float _1316; + if (_1289 <= 0.053333334624767303466796875) + { + _1316 = _1303; + } + else + { + float _1315; + if (_1289 >= 0.1599999964237213134765625) + { + _1315 = 0.0; + } + else + { + _1315 = _1303 * ((0.23999999463558197021484375 / _1288) - 0.5); + } + _1316 = _1315; + } + float3 _1319 = _1263 * float3(1.0 + _1316); + float _1320 = _1319.x; + float _1321 = _1319.y; + float _1323 = _1319.z; + float _1337; + if ((_1320 == _1321) && (_1321 == _1323)) + { + _1337 = 0.0; + } + else + { + _1337 = 57.2957763671875 * atan2(1.73205077648162841796875 * (_1321 - _1323), ((2.0 * _1320) - _1321) - _1323); + } + float _1342; + if (_1337 < 0.0) + { + _1342 = _1337 + 360.0; + } + else + { + _1342 = _1337; + } + float _1343 = fast::clamp(_1342, 0.0, 360.0); + float _1348; + if (_1343 > 180.0) + { + _1348 = _1343 - 360.0; + } + else + { + _1348 = _1343; + } + float _1398; + if ((_1348 > (-67.5)) && (_1348 < 67.5)) + { + float _1355 = (_1348 - (-67.5)) * 0.0296296291053295135498046875; + int _1356 = int(_1355); + float _1358 = _1355 - float(_1356); + float _1359 = _1358 * _1358; + float _1360 = _1359 * _1358; + float _1397; + if (_1356 == 3) + { + _1397 = (((_1360 * (-0.16666667163372039794921875)) + (_1359 * 0.5)) + (_1358 * (-0.5))) + 0.16666667163372039794921875; + } + else + { + float _1390; + if (_1356 == 2) + { + _1390 = ((_1360 * 0.5) + (_1359 * (-1.0))) + 0.666666686534881591796875; + } + else + { + float _1385; + if (_1356 == 1) + { + _1385 = (((_1360 * (-0.5)) + (_1359 * 0.5)) + (_1358 * 0.5)) + 0.16666667163372039794921875; + } + else + { + float _1378; + if (_1356 == 0) + { + _1378 = _1360 * 0.16666667163372039794921875; + } + else + { + _1378 = 0.0; + } + _1385 = _1378; + } + _1390 = _1385; + } + _1397 = _1390; + } + _1398 = _1397; + } + else + { + _1398 = 0.0; + } + float3 _1405 = _1319; + _1405.x = _1320 + ((((_1398 * 1.5) * _1275) * (0.02999999932944774627685546875 - _1320)) * 0.180000007152557373046875); + float3 _1408 = fast::clamp(fast::clamp(_1405, float3(0.0), float3(65535.0)) * float3x3(float3(1.45143926143646240234375, -0.236510753631591796875, -0.214928567409515380859375), float3(-0.07655377686023712158203125, 1.1762297153472900390625, -0.0996759235858917236328125), float3(0.0083161480724811553955078125, -0.0060324496589601039886474609375, 0.99771630764007568359375)), float3(0.0), float3(65535.0)); + float3 _1411 = mix(float3(dot(_1408, float3(0.272228717803955078125, 0.674081742763519287109375, 0.053689517080783843994140625))), _1408, float3(0.959999978542327880859375)); + float _1412 = _1411.x; + float _1421 = log((_1412 <= 0.0) ? 6.103515625e-05 : _1412) * 0.4342944622039794921875; + float _1490; + if (_1421 <= (-5.2601776123046875)) + { + _1490 = -4.0; + } + else + { + float _1487; + if ((_1421 > (-5.2601776123046875)) && (_1421 < (-0.744727432727813720703125))) + { + float _1470 = (_1421 - (-5.2601776123046875)) * 0.6643855571746826171875; + int _1471 = int(_1470); + float _1473 = _1470 - float(_1471); + _1487 = dot(float3(_1473 * _1473, _1473, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_475[_1471], _475[_1471 + 1], _475[_1471 + 2])); + } + else + { + float _1466; + if ((_1421 >= (-0.744727432727813720703125)) && (_1421 < 4.673812389373779296875)) + { + float _1449 = (_1421 - (-0.744727432727813720703125)) * 0.55365467071533203125; + int _1450 = int(_1449); + float _1452 = _1449 - float(_1450); + _1466 = dot(float3(_1452 * _1452, _1452, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_476[_1450], _476[_1450 + 1], _476[_1450 + 2])); + } + else + { + _1466 = 4.0; + } + _1487 = _1466; + } + _1490 = _1487; + } + float3 _1492 = _391; + _1492.x = pow(10.0, _1490); + float _1493 = _1411.y; + float _1497 = log((_1493 <= 0.0) ? 6.103515625e-05 : _1493) * 0.4342944622039794921875; + float _1564; + if (_1497 <= (-5.2601776123046875)) + { + _1564 = -4.0; + } + else + { + float _1561; + if ((_1497 > (-5.2601776123046875)) && (_1497 < (-0.744727432727813720703125))) + { + float _1544 = (_1497 - (-5.2601776123046875)) * 0.6643855571746826171875; + int _1545 = int(_1544); + float _1547 = _1544 - float(_1545); + _1561 = dot(float3(_1547 * _1547, _1547, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_475[_1545], _475[_1545 + 1], _475[_1545 + 2])); + } + else + { + float _1540; + if ((_1497 >= (-0.744727432727813720703125)) && (_1497 < 4.673812389373779296875)) + { + float _1523 = (_1497 - (-0.744727432727813720703125)) * 0.55365467071533203125; + int _1524 = int(_1523); + float _1526 = _1523 - float(_1524); + _1540 = dot(float3(_1526 * _1526, _1526, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_476[_1524], _476[_1524 + 1], _476[_1524 + 2])); + } + else + { + _1540 = 4.0; + } + _1561 = _1540; + } + _1564 = _1561; + } + float3 _1566 = _1492; + _1566.y = pow(10.0, _1564); + float _1567 = _1411.z; + float _1571 = log((_1567 <= 0.0) ? 6.103515625e-05 : _1567) * 0.4342944622039794921875; + float _1638; + if (_1571 <= (-5.2601776123046875)) + { + _1638 = -4.0; + } + else + { + float _1635; + if ((_1571 > (-5.2601776123046875)) && (_1571 < (-0.744727432727813720703125))) + { + float _1618 = (_1571 - (-5.2601776123046875)) * 0.6643855571746826171875; + int _1619 = int(_1618); + float _1621 = _1618 - float(_1619); + _1635 = dot(float3(_1621 * _1621, _1621, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_475[_1619], _475[_1619 + 1], _475[_1619 + 2])); + } + else + { + float _1614; + if ((_1571 >= (-0.744727432727813720703125)) && (_1571 < 4.673812389373779296875)) + { + float _1597 = (_1571 - (-0.744727432727813720703125)) * 0.55365467071533203125; + int _1598 = int(_1597); + float _1600 = _1597 - float(_1598); + _1614 = dot(float3(_1600 * _1600, _1600, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_476[_1598], _476[_1598 + 1], _476[_1598 + 2])); + } + else + { + _1614 = 4.0; + } + _1635 = _1614; + } + _1638 = _1635; + } + float3 _1640 = _1566; + _1640.z = pow(10.0, _1638); + float3 _1642 = (_1640 * float3x3(float3(0.695452213287353515625, 0.140678703784942626953125, 0.16386906802654266357421875), float3(0.0447945632040500640869140625, 0.859671115875244140625, 0.095534317195415496826171875), float3(-0.0055258828215301036834716796875, 0.0040252101607620716094970703125, 1.00150072574615478515625))) * float3x3(float3(1.45143926143646240234375, -0.236510753631591796875, -0.214928567409515380859375), float3(-0.07655377686023712158203125, 1.1762297153472900390625, -0.0996759235858917236328125), float3(0.0083161480724811553955078125, -0.0060324496589601039886474609375, 0.99771630764007568359375)); + float _1775 = pow(10.0, (float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_476[0], _476[1], _476[2])).z); + float _1847 = pow(10.0, dot(float3(0.69444429874420166015625, 0.8333332538604736328125, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_476[1], _476[2], _476[3]))); + float _1848 = _1642.x; + float _1851 = log((_1848 <= 0.0) ? 9.9999997473787516355514526367188e-05 : _1848); + float _1852 = _1851 * 0.4342944622039794921875; + float _1854 = log(pow(10.0, dot(float3(0.3600003719329833984375, 0.600000321865081787109375, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_475[0], _475[1], _475[2])))) * 0.4342944622039794921875; + float _1926; + if (_1852 <= _1854) + { + _1926 = -2.3010299205780029296875; + } + else + { + float _1861 = log(_1775) * 0.4342944622039794921875; + float _1923; + if ((_1852 > _1854) && (_1852 < _1861)) + { + float _1906 = (7.0 * (_1852 - _1854)) / (_1861 - _1854); + int _1907 = int(_1906); + float _1909 = _1906 - float(_1907); + _1923 = dot(float3(_1909 * _1909, _1909, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_482[_1907], _482[_1907 + 1], _482[_1907 + 2])); + } + else + { + float _1868 = log(_1847); + float _1869 = _1868 * 0.4342944622039794921875; + float _1902; + if ((_1852 >= _1861) && (_1852 < _1869)) + { + float _1885 = (7.0 * (_1852 - _1861)) / (_1869 - _1861); + int _1886 = int(_1885); + float _1888 = _1885 - float(_1886); + _1902 = dot(float3(_1888 * _1888, _1888, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_483[_1886], _483[_1886 + 1], _483[_1886 + 2])); + } + else + { + _1902 = (_1851 * 0.05211533606052398681640625) + (3.3010299205780029296875 - (_1868 * 0.05211533606052398681640625)); + } + _1923 = _1902; + } + _1926 = _1923; + } + float3 _1928 = _391; + _1928.x = pow(10.0, _1926); + float _1929 = _1642.y; + float _1932 = log((_1929 <= 0.0) ? 9.9999997473787516355514526367188e-05 : _1929); + float _1933 = _1932 * 0.4342944622039794921875; + float _2005; + if (_1933 <= _1854) + { + _2005 = -2.3010299205780029296875; + } + else + { + float _1940 = log(_1775) * 0.4342944622039794921875; + float _2002; + if ((_1933 > _1854) && (_1933 < _1940)) + { + float _1985 = (7.0 * (_1933 - _1854)) / (_1940 - _1854); + int _1986 = int(_1985); + float _1988 = _1985 - float(_1986); + _2002 = dot(float3(_1988 * _1988, _1988, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_482[_1986], _482[_1986 + 1], _482[_1986 + 2])); + } + else + { + float _1947 = log(_1847); + float _1948 = _1947 * 0.4342944622039794921875; + float _1981; + if ((_1933 >= _1940) && (_1933 < _1948)) + { + float _1964 = (7.0 * (_1933 - _1940)) / (_1948 - _1940); + int _1965 = int(_1964); + float _1967 = _1964 - float(_1965); + _1981 = dot(float3(_1967 * _1967, _1967, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_483[_1965], _483[_1965 + 1], _483[_1965 + 2])); + } + else + { + _1981 = (_1932 * 0.05211533606052398681640625) + (3.3010299205780029296875 - (_1947 * 0.05211533606052398681640625)); + } + _2002 = _1981; + } + _2005 = _2002; + } + float3 _2007 = _1928; + _2007.y = pow(10.0, _2005); + float _2008 = _1642.z; + float _2011 = log((_2008 <= 0.0) ? 9.9999997473787516355514526367188e-05 : _2008); + float _2012 = _2011 * 0.4342944622039794921875; + float _2084; + if (_2012 <= _1854) + { + _2084 = -2.3010299205780029296875; + } + else + { + float _2019 = log(_1775) * 0.4342944622039794921875; + float _2081; + if ((_2012 > _1854) && (_2012 < _2019)) + { + float _2064 = (7.0 * (_2012 - _1854)) / (_2019 - _1854); + int _2065 = int(_2064); + float _2067 = _2064 - float(_2065); + _2081 = dot(float3(_2067 * _2067, _2067, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_482[_2065], _482[_2065 + 1], _482[_2065 + 2])); + } + else + { + float _2026 = log(_1847); + float _2027 = _2026 * 0.4342944622039794921875; + float _2060; + if ((_2012 >= _2019) && (_2012 < _2027)) + { + float _2043 = (7.0 * (_2012 - _2019)) / (_2027 - _2019); + int _2044 = int(_2043); + float _2046 = _2043 - float(_2044); + _2060 = dot(float3(_2046 * _2046, _2046, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_483[_2044], _483[_2044 + 1], _483[_2044 + 2])); + } + else + { + _2060 = (_2011 * 0.05211533606052398681640625) + (3.3010299205780029296875 - (_2026 * 0.05211533606052398681640625)); + } + _2081 = _2060; + } + _2084 = _2081; + } + float3 _2086 = _2007; + _2086.z = pow(10.0, _2084); + float3 _2089 = pow((_2086 * _576) * float3(9.9999997473787516355514526367188e-05), float3(0.1593017578125)); + _2097 = pow((float3(0.8359375) + (float3(18.8515625) * _2089)) * (float3(1.0) / (float3(1.0) + (float3(18.6875) * _2089))), float3(78.84375)); + } + else + { + float3 _1260; + if (_Globals.OutputDevice == 7u) + { + float3 _1252 = pow(((_906 * _547) * _576) * float3(9.9999997473787516355514526367188e-05), float3(0.1593017578125)); + _1260 = pow((float3(0.8359375) + (float3(18.8515625) * _1252)) * (float3(1.0) / (float3(1.0) + (float3(18.6875) * _1252))), float3(78.84375)); + } + else + { + _1260 = pow((_1218 * _547) * _576, float3(_Globals.InverseGamma.z)); + } + _2097 = _1260; + } + _2950 = _2097; + } + _2960 = _2950; + } + _3001 = _2960; + } + float3 _3002 = _3001 * float3(0.95238101482391357421875); + float4 _3004 = float4(_3002.x, _3002.y, _3002.z, float4(0.0).w); + _3004.w = 0.0; + out.out_var_SV_Target0 = _3004; + return out; +} + diff --git a/third_party/spirv-cross/reference/opt/shaders-ue4/asm/frag/padded-float-array-member-defef.asm.frag b/third_party/spirv-cross/reference/opt/shaders-ue4/asm/frag/padded-float-array-member-defef.asm.frag new file mode 100644 index 0000000000..7e2f5b6b76 --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders-ue4/asm/frag/padded-float-array-member-defef.asm.frag @@ -0,0 +1,1190 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + +#include +#include + +using namespace metal; + +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +struct type_Globals +{ + float4 MappingPolynomial; + float3 InverseGamma; + float4 ColorMatrixR_ColorCurveCd1; + float4 ColorMatrixG_ColorCurveCd3Cm3; + float4 ColorMatrixB_ColorCurveCm2; + float4 ColorCurve_Cm0Cd0_Cd2_Ch0Cm1_Ch3; + float4 ColorCurve_Ch1_Ch2; + float4 ColorShadow_Luma; + float4 ColorShadow_Tint1; + float4 ColorShadow_Tint2; + float FilmSlope; + float FilmToe; + float FilmShoulder; + float FilmBlackClip; + float FilmWhiteClip; + float4 LUTWeights[5]; + float3 ColorScale; + float4 OverlayColor; + float WhiteTemp; + float WhiteTint; + float4 ColorSaturation; + float4 ColorContrast; + float4 ColorGamma; + float4 ColorGain; + float4 ColorOffset; + float4 ColorSaturationShadows; + float4 ColorContrastShadows; + float4 ColorGammaShadows; + float4 ColorGainShadows; + float4 ColorOffsetShadows; + float4 ColorSaturationMidtones; + float4 ColorContrastMidtones; + float4 ColorGammaMidtones; + float4 ColorGainMidtones; + float4 ColorOffsetMidtones; + float4 ColorSaturationHighlights; + float4 ColorContrastHighlights; + float4 ColorGammaHighlights; + float4 ColorGainHighlights; + float4 ColorOffsetHighlights; + float ColorCorrectionShadowsMax; + float ColorCorrectionHighlightsMin; + uint OutputDevice; + uint OutputGamut; + float BlueCorrection; + float ExpandGamut; +}; + +constant spvUnsafeArray _499 = spvUnsafeArray({ -4.0, -4.0, -3.1573765277862548828125, -0.485249996185302734375, 1.84773242473602294921875, 1.84773242473602294921875 }); +constant spvUnsafeArray _500 = spvUnsafeArray({ -0.718548238277435302734375, 2.0810306072235107421875, 3.66812419891357421875, 4.0, 4.0, 4.0 }); +constant spvUnsafeArray _503 = spvUnsafeArray({ -4.97062206268310546875, -3.0293781757354736328125, -2.1261999607086181640625, -1.5104999542236328125, -1.0578000545501708984375, -0.4668000042438507080078125, 0.11937999725341796875, 0.7088134288787841796875, 1.2911865711212158203125, 1.2911865711212158203125 }); +constant spvUnsafeArray _504 = spvUnsafeArray({ 0.80891323089599609375, 1.19108676910400390625, 1.5683000087738037109375, 1.94830000400543212890625, 2.308300018310546875, 2.63840007781982421875, 2.85949993133544921875, 2.9872608184814453125, 3.0127391815185546875, 3.0127391815185546875 }); +constant spvUnsafeArray _506 = spvUnsafeArray({ -2.3010299205780029296875, -2.3010299205780029296875, -1.9312000274658203125, -1.5204999446868896484375, -1.0578000545501708984375, -0.4668000042438507080078125, 0.11937999725341796875, 0.7088134288787841796875, 1.2911865711212158203125, 1.2911865711212158203125 }); +constant spvUnsafeArray _507 = spvUnsafeArray({ 0.801995217800140380859375, 1.19800484180450439453125, 1.5943000316619873046875, 1.99730002880096435546875, 2.3782999515533447265625, 2.7683999538421630859375, 3.0515000820159912109375, 3.2746293544769287109375, 3.32743072509765625, 3.32743072509765625 }); + +constant float3 _523 = {}; +constant float3 _3219 = {}; + +struct main0_out +{ + float4 out_var_SV_Target0 [[color(0)]]; +}; + +struct main0_in +{ + float2 in_var_TEXCOORD0 [[user(locn0), center_no_perspective]]; +}; + +fragment main0_out main0(main0_in in [[stage_in]], constant type_Globals& _Globals [[buffer(0)]], texture2d Texture1 [[texture(0)]], sampler Texture1Sampler [[sampler(0)]], uint gl_Layer [[render_target_array_index]]) +{ + main0_out out = {}; + float3x3 _572 = float3x3(float3(0.41245639324188232421875, 0.3575761020183563232421875, 0.180437505245208740234375), float3(0.21267290413379669189453125, 0.715152204036712646484375, 0.072175003588199615478515625), float3(0.01933390088379383087158203125, 0.119191996753215789794921875, 0.950304090976715087890625)) * float3x3(float3(1.01303005218505859375, 0.0061053098179399967193603515625, -0.014971000142395496368408203125), float3(0.0076982299797236919403076171875, 0.99816501140594482421875, -0.005032029934227466583251953125), float3(-0.0028413101099431514739990234375, 0.0046851597726345062255859375, 0.92450702190399169921875)); + float3x3 _573 = _572 * float3x3(float3(1.6410233974456787109375, -0.324803292751312255859375, -0.23642469942569732666015625), float3(-0.663662850856781005859375, 1.6153316497802734375, 0.016756348311901092529296875), float3(0.01172189414501190185546875, -0.008284442126750946044921875, 0.98839485645294189453125)); + float3x3 _574 = float3x3(float3(0.662454187870025634765625, 0.1340042054653167724609375, 0.1561876833438873291015625), float3(0.272228717803955078125, 0.674081742763519287109375, 0.053689517080783843994140625), float3(-0.0055746496655046939849853515625, 0.0040607335977256298065185546875, 1.01033914089202880859375)) * float3x3(float3(0.98722398281097412109375, -0.0061132698319852352142333984375, 0.01595330052077770233154296875), float3(-0.007598360069096088409423828125, 1.00186002254486083984375, 0.0053300200961530208587646484375), float3(0.003072570078074932098388671875, -0.0050959498621523380279541015625, 1.0816800594329833984375)); + float3x3 _575 = _574 * float3x3(float3(3.2409698963165283203125, -1.53738319873809814453125, -0.4986107647418975830078125), float3(-0.96924364566802978515625, 1.875967502593994140625, 0.0415550582110881805419921875), float3(0.055630080401897430419921875, -0.2039769589900970458984375, 1.05697154998779296875)); + float3x3 _576 = float3x3(float3(0.952552378177642822265625, 0.0, 9.25), float3(0.3439664542675018310546875, 0.728166103363037109375, -0.07213254272937774658203125), float3(0.0, 0.0, 1.00882518291473388671875)) * float3x3(float3(1.6410233974456787109375, -0.324803292751312255859375, -0.23642469942569732666015625), float3(-0.663662850856781005859375, 1.6153316497802734375, 0.016756348311901092529296875), float3(0.01172189414501190185546875, -0.008284442126750946044921875, 0.98839485645294189453125)); + float3x3 _577 = float3x3(float3(0.662454187870025634765625, 0.1340042054653167724609375, 0.1561876833438873291015625), float3(0.272228717803955078125, 0.674081742763519287109375, 0.053689517080783843994140625), float3(-0.0055746496655046939849853515625, 0.0040607335977256298065185546875, 1.01033914089202880859375)) * float3x3(float3(1.04981100559234619140625, 0.0, -9.74845024757087230682373046875e-05), float3(-0.49590301513671875, 1.37331306934356689453125, 0.09824003279209136962890625), float3(0.0, 0.0, 0.991252005100250244140625)); + float3x3 _602; + for (;;) + { + if (_Globals.OutputGamut == 1u) + { + _602 = _574 * float3x3(float3(2.493396282196044921875, -0.931345880031585693359375, -0.4026944935321807861328125), float3(-0.829486787319183349609375, 1.76265966892242431640625, 0.02362460084259510040283203125), float3(0.0358506999909877777099609375, -0.076182700693607330322265625, 0.957014024257659912109375)); + break; + } + else + { + if (_Globals.OutputGamut == 2u) + { + _602 = _574 * float3x3(float3(1.71660840511322021484375, -0.3556621074676513671875, -0.253360092639923095703125), float3(-0.666682898998260498046875, 1.61647760868072509765625, 0.01576850004494190216064453125), float3(0.017642199993133544921875, -0.04277630150318145751953125, 0.94222867488861083984375)); + break; + } + else + { + if (_Globals.OutputGamut == 3u) + { + _602 = float3x3(float3(0.695452213287353515625, 0.140678703784942626953125, 0.16386906802654266357421875), float3(0.0447945632040500640869140625, 0.859671115875244140625, 0.095534317195415496826171875), float3(-0.0055258828215301036834716796875, 0.0040252101607620716094970703125, 1.00150072574615478515625)); + break; + } + else + { + if (_Globals.OutputGamut == 4u) + { + _602 = float3x3(float3(1.0, 0.0, 0.0), float3(0.0, 1.0, 0.0), float3(0.0, 0.0, 1.0)); + break; + } + else + { + _602 = _575; + break; + } + } + } + } + } + float3 _603 = float4((in.in_var_TEXCOORD0 - float2(0.015625)) * float2(1.03225803375244140625), float(gl_Layer) * 0.0322580635547637939453125, 0.0).xyz; + float3 _625; + if (_Globals.OutputDevice >= 3u) + { + float3 _617 = pow(_603, float3(0.0126833133399486541748046875)); + _625 = pow(fast::max(float3(0.0), _617 - float3(0.8359375)) / (float3(18.8515625) - (float3(18.6875) * _617)), float3(6.277394771575927734375)) * float3(10000.0); + } + else + { + _625 = (exp2((_603 - float3(0.434017598628997802734375)) * float3(14.0)) * float3(0.180000007152557373046875)) - float3(0.00266771926544606685638427734375); + } + float _628 = _Globals.WhiteTemp * 1.00055634975433349609375; + float _642 = (_628 <= 7000.0) ? (0.24406300485134124755859375 + ((99.1100006103515625 + ((2967800.0 - (4604438528.0 / _Globals.WhiteTemp)) / _628)) / _628)) : (0.23703999817371368408203125 + ((247.4799957275390625 + ((1901800.0 - (2005284352.0 / _Globals.WhiteTemp)) / _628)) / _628)); + float _659 = ((0.860117733478546142578125 + (0.00015411825734190642833709716796875 * _Globals.WhiteTemp)) + ((1.2864121856637211749330163002014e-07 * _Globals.WhiteTemp) * _Globals.WhiteTemp)) / ((1.0 + (0.0008424202096648514270782470703125 * _Globals.WhiteTemp)) + ((7.0814513719597016461193561553955e-07 * _Globals.WhiteTemp) * _Globals.WhiteTemp)); + float _670 = ((0.317398726940155029296875 + (4.25 * _Globals.WhiteTemp)) + ((4.2048167614439080352894961833954e-08 * _Globals.WhiteTemp) * _Globals.WhiteTemp)) / ((1.0 - (2.8974181986995972692966461181641e-05 * _Globals.WhiteTemp)) + ((1.6145605741257895715534687042236e-07 * _Globals.WhiteTemp) * _Globals.WhiteTemp)); + float _675 = ((2.0 * _659) - (8.0 * _670)) + 4.0; + float2 _679 = float2((3.0 * _659) / _675, (2.0 * _670) / _675); + float2 _686 = normalize(float2(_659, _670)); + float _691 = _659 + (((-_686.y) * _Globals.WhiteTint) * 0.0500000007450580596923828125); + float _695 = _670 + ((_686.x * _Globals.WhiteTint) * 0.0500000007450580596923828125); + float _700 = ((2.0 * _691) - (8.0 * _695)) + 4.0; + float2 _706 = select(float2(_642, (_642 * (((-3.0) * _642) + 2.86999988555908203125)) - 0.2750000059604644775390625), _679, bool2(_Globals.WhiteTemp < 4000.0)) + (float2((3.0 * _691) / _700, (2.0 * _695) / _700) - _679); + float _707 = _706.x; + float _708 = _706.y; + float _709 = fast::max(_708, 1.0000000133514319600180897396058e-10); + float3 _711 = _523; + _711.x = _707 / _709; + float3 _712 = _711; + _712.y = 1.0; + float3 _716 = _712; + _716.z = ((1.0 - _707) - _708) / _709; + float3 _719 = _523; + _719.x = 0.950455963611602783203125; + float3 _720 = _719; + _720.y = 1.0; + float3 _722 = _720; + _722.z = 1.0890576839447021484375; + float3 _723 = _716 * float3x3(float3(0.89509999752044677734375, 0.2664000093936920166015625, -0.16140000522136688232421875), float3(-0.750199973583221435546875, 1.71350002288818359375, 0.0366999991238117218017578125), float3(0.0388999991118907928466796875, -0.06849999725818634033203125, 1.02960002422332763671875)); + float3 _724 = _722 * float3x3(float3(0.89509999752044677734375, 0.2664000093936920166015625, -0.16140000522136688232421875), float3(-0.750199973583221435546875, 1.71350002288818359375, 0.0366999991238117218017578125), float3(0.0388999991118907928466796875, -0.06849999725818634033203125, 1.02960002422332763671875)); + float3 _743 = (_625 * ((float3x3(float3(0.41245639324188232421875, 0.3575761020183563232421875, 0.180437505245208740234375), float3(0.21267290413379669189453125, 0.715152204036712646484375, 0.072175003588199615478515625), float3(0.01933390088379383087158203125, 0.119191996753215789794921875, 0.950304090976715087890625)) * ((float3x3(float3(0.89509999752044677734375, 0.2664000093936920166015625, -0.16140000522136688232421875), float3(-0.750199973583221435546875, 1.71350002288818359375, 0.0366999991238117218017578125), float3(0.0388999991118907928466796875, -0.06849999725818634033203125, 1.02960002422332763671875)) * float3x3(float3(_724.x / _723.x, 0.0, 0.0), float3(0.0, _724.y / _723.y, 0.0), float3(0.0, 0.0, _724.z / _723.z))) * float3x3(float3(0.986992895603179931640625, -0.14705429971218109130859375, 0.15996269881725311279296875), float3(0.4323053061962127685546875, 0.518360316753387451171875, 0.049291200935840606689453125), float3(-0.00852870009839534759521484375, 0.0400427989661693572998046875, 0.968486726284027099609375)))) * float3x3(float3(3.2409698963165283203125, -1.53738319873809814453125, -0.4986107647418975830078125), float3(-0.96924364566802978515625, 1.875967502593994140625, 0.0415550582110881805419921875), float3(0.055630080401897430419921875, -0.2039769589900970458984375, 1.05697154998779296875)))) * _573; + float3 _771; + if (_Globals.ColorShadow_Tint2.w != 0.0) + { + float _750 = dot(_743, float3(0.272228717803955078125, 0.674081742763519287109375, 0.053689517080783843994140625)); + float3 _753 = (_743 / float3(_750)) - float3(1.0); + _771 = mix(_743, _743 * (_575 * (float3x3(float3(0.544169127941131591796875, 0.23959259688854217529296875, 0.16669429838657379150390625), float3(0.23946559429168701171875, 0.702153027057647705078125, 0.058381401002407073974609375), float3(-0.0023439000360667705535888671875, 0.0361833982169628143310546875, 1.05521833896636962890625)) * float3x3(float3(1.6410233974456787109375, -0.324803292751312255859375, -0.23642469942569732666015625), float3(-0.663662850856781005859375, 1.6153316497802734375, 0.016756348311901092529296875), float3(0.01172189414501190185546875, -0.008284442126750946044921875, 0.98839485645294189453125)))), float3((1.0 - exp2((-4.0) * dot(_753, _753))) * (1.0 - exp2((((-4.0) * _Globals.ExpandGamut) * _750) * _750)))); + } + else + { + _771 = _743; + } + float _772 = dot(_771, float3(0.272228717803955078125, 0.674081742763519287109375, 0.053689517080783843994140625)); + float4 _777 = _Globals.ColorSaturationShadows * _Globals.ColorSaturation; + float4 _782 = _Globals.ColorContrastShadows * _Globals.ColorContrast; + float4 _787 = _Globals.ColorGammaShadows * _Globals.ColorGamma; + float4 _792 = _Globals.ColorGainShadows * _Globals.ColorGain; + float4 _797 = _Globals.ColorOffsetShadows + _Globals.ColorOffset; + float3 _798 = float3(_772); + float _830 = smoothstep(0.0, _Globals.ColorCorrectionShadowsMax, _772); + float4 _834 = _Globals.ColorSaturationHighlights * _Globals.ColorSaturation; + float4 _837 = _Globals.ColorContrastHighlights * _Globals.ColorContrast; + float4 _840 = _Globals.ColorGammaHighlights * _Globals.ColorGamma; + float4 _843 = _Globals.ColorGainHighlights * _Globals.ColorGain; + float4 _846 = _Globals.ColorOffsetHighlights + _Globals.ColorOffset; + float _878 = smoothstep(_Globals.ColorCorrectionHighlightsMin, 1.0, _772); + float4 _881 = _Globals.ColorSaturationMidtones * _Globals.ColorSaturation; + float4 _884 = _Globals.ColorContrastMidtones * _Globals.ColorContrast; + float4 _887 = _Globals.ColorGammaMidtones * _Globals.ColorGamma; + float4 _890 = _Globals.ColorGainMidtones * _Globals.ColorGain; + float4 _893 = _Globals.ColorOffsetMidtones + _Globals.ColorOffset; + float3 _931 = ((((pow(pow(fast::max(float3(0.0), mix(_798, _771, _777.xyz * float3(_777.w))) * float3(5.5555553436279296875), _782.xyz * float3(_782.w)) * float3(0.180000007152557373046875), float3(1.0) / (_787.xyz * float3(_787.w))) * (_792.xyz * float3(_792.w))) + (_797.xyz + float3(_797.w))) * float3(1.0 - _830)) + (((pow(pow(fast::max(float3(0.0), mix(_798, _771, _881.xyz * float3(_881.w))) * float3(5.5555553436279296875), _884.xyz * float3(_884.w)) * float3(0.180000007152557373046875), float3(1.0) / (_887.xyz * float3(_887.w))) * (_890.xyz * float3(_890.w))) + (_893.xyz + float3(_893.w))) * float3(_830 - _878))) + (((pow(pow(fast::max(float3(0.0), mix(_798, _771, _834.xyz * float3(_834.w))) * float3(5.5555553436279296875), _837.xyz * float3(_837.w)) * float3(0.180000007152557373046875), float3(1.0) / (_840.xyz * float3(_840.w))) * (_843.xyz * float3(_843.w))) + (_846.xyz + float3(_846.w))) * float3(_878)); + float3 _932 = _931 * _575; + float3 _940 = float3(_Globals.BlueCorrection); + float3 _942 = mix(_931, _931 * ((_577 * float3x3(float3(0.940437257289886474609375, -0.01830687932670116424560546875, 0.07786960899829864501953125), float3(0.008378696627914905548095703125, 0.82866001129150390625, 0.162961304187774658203125), float3(0.0005471261101774871349334716796875, -0.00088337459601461887359619140625, 1.00033628940582275390625))) * _576), _940) * _577; + float _943 = _942.x; + float _944 = _942.y; + float _946 = _942.z; + float _949 = fast::max(fast::max(_943, _944), _946); + float _954 = (fast::max(_949, 1.0000000133514319600180897396058e-10) - fast::max(fast::min(fast::min(_943, _944), _946), 1.0000000133514319600180897396058e-10)) / fast::max(_949, 0.00999999977648258209228515625); + float _967 = ((_946 + _944) + _943) + (1.75 * sqrt(((_946 * (_946 - _944)) + (_944 * (_944 - _943))) + (_943 * (_943 - _946)))); + float _968 = _967 * 0.3333333432674407958984375; + float _969 = _954 - 0.4000000059604644775390625; + float _974 = fast::max(1.0 - abs(_969 * 2.5), 0.0); + float _982 = (1.0 + (float(int(sign(_969 * 5.0))) * (1.0 - (_974 * _974)))) * 0.02500000037252902984619140625; + float _995; + if (_968 <= 0.053333334624767303466796875) + { + _995 = _982; + } + else + { + float _994; + if (_968 >= 0.1599999964237213134765625) + { + _994 = 0.0; + } + else + { + _994 = _982 * ((0.23999999463558197021484375 / _967) - 0.5); + } + _995 = _994; + } + float3 _998 = _942 * float3(1.0 + _995); + float _999 = _998.x; + float _1000 = _998.y; + float _1002 = _998.z; + float _1016; + if ((_999 == _1000) && (_1000 == _1002)) + { + _1016 = 0.0; + } + else + { + _1016 = 57.2957763671875 * atan2(1.73205077648162841796875 * (_1000 - _1002), ((2.0 * _999) - _1000) - _1002); + } + float _1021; + if (_1016 < 0.0) + { + _1021 = _1016 + 360.0; + } + else + { + _1021 = _1016; + } + float _1022 = fast::clamp(_1021, 0.0, 360.0); + float _1027; + if (_1022 > 180.0) + { + _1027 = _1022 - 360.0; + } + else + { + _1027 = _1022; + } + float _1031 = smoothstep(0.0, 1.0, 1.0 - abs(_1027 * 0.01481481455266475677490234375)); + float3 _1038 = _998; + _1038.x = _999 + ((((_1031 * _1031) * _954) * (0.02999999932944774627685546875 - _999)) * 0.180000007152557373046875); + float3 _1040 = fast::max(float3(0.0), _1038 * float3x3(float3(1.45143926143646240234375, -0.236510753631591796875, -0.214928567409515380859375), float3(-0.07655377686023712158203125, 1.1762297153472900390625, -0.0996759235858917236328125), float3(0.0083161480724811553955078125, -0.0060324496589601039886474609375, 0.99771630764007568359375))); + float _1049 = (1.0 + _Globals.FilmBlackClip) - _Globals.FilmToe; + float _1052 = 1.0 + _Globals.FilmWhiteClip; + float _1055 = _1052 - _Globals.FilmShoulder; + float _1082; + if (_Globals.FilmToe > 0.800000011920928955078125) + { + _1082 = ((0.819999992847442626953125 - _Globals.FilmToe) / _Globals.FilmSlope) + (-0.744727432727813720703125); + } + else + { + float _1061 = (0.180000007152557373046875 + _Globals.FilmBlackClip) / _1049; + _1082 = (-0.744727432727813720703125) - ((0.5 * log(_1061 / (2.0 - _1061))) * (_1049 / _Globals.FilmSlope)); + } + float _1087 = ((1.0 - _Globals.FilmToe) / _Globals.FilmSlope) - _1082; + float _1089 = (_Globals.FilmShoulder / _Globals.FilmSlope) - _1087; + float3 _1093 = log(mix(float3(dot(_1040, float3(0.272228717803955078125, 0.674081742763519287109375, 0.053689517080783843994140625))), _1040, float3(0.959999978542327880859375))) * float3(0.4342944622039794921875); + float3 _1097 = float3(_Globals.FilmSlope) * (_1093 + float3(_1087)); + float3 _1105 = float3(_1082); + float3 _1106 = _1093 - _1105; + float3 _1118 = float3(_1089); + float3 _1132 = fast::clamp(_1106 / float3(_1089 - _1082), float3(0.0), float3(1.0)); + float3 _1136 = select(_1132, float3(1.0) - _1132, bool3(_1089 < _1082)); + float3 _1141 = mix(select(_1097, float3(-_Globals.FilmBlackClip) + (float3(2.0 * _1049) / (float3(1.0) + exp(float3(((-2.0) * _Globals.FilmSlope) / _1049) * _1106))), _1093 < _1105), select(_1097, float3(_1052) - (float3(2.0 * _1055) / (float3(1.0) + exp(float3((2.0 * _Globals.FilmSlope) / _1055) * (_1093 - _1118)))), _1093 > _1118), ((float3(3.0) - (float3(2.0) * _1136)) * _1136) * _1136); + float3 _1145 = fast::max(float3(0.0), mix(float3(dot(_1141, float3(0.272228717803955078125, 0.674081742763519287109375, 0.053689517080783843994140625))), _1141, float3(0.930000007152557373046875))); + float3 _1215; + if (_Globals.ColorShadow_Tint2.w == 0.0) + { + float3 _1157 = _3219; + _1157.x = dot(_932, _Globals.ColorMatrixR_ColorCurveCd1.xyz); + float3 _1162 = _1157; + _1162.y = dot(_932, _Globals.ColorMatrixG_ColorCurveCd3Cm3.xyz); + float3 _1167 = _1162; + _1167.z = dot(_932, _Globals.ColorMatrixB_ColorCurveCm2.xyz); + float3 _1183 = fast::max(float3(0.0), _1167 * (_Globals.ColorShadow_Tint1.xyz + (_Globals.ColorShadow_Tint2.xyz * float3(1.0 / (dot(_932, _Globals.ColorShadow_Luma.xyz) + 1.0))))); + float3 _1188 = fast::max(float3(0.0), _Globals.ColorCurve_Cm0Cd0_Cd2_Ch0Cm1_Ch3.xxx - _1183); + float3 _1190 = fast::max(_1183, _Globals.ColorCurve_Cm0Cd0_Cd2_Ch0Cm1_Ch3.zzz); + _1215 = ((((_1190 * _Globals.ColorCurve_Ch1_Ch2.xxx) + _Globals.ColorCurve_Ch1_Ch2.yyy) * (float3(1.0) / (_1190 + _Globals.ColorCurve_Cm0Cd0_Cd2_Ch0Cm1_Ch3.www))) + ((fast::clamp(_1183, _Globals.ColorCurve_Cm0Cd0_Cd2_Ch0Cm1_Ch3.xxx, _Globals.ColorCurve_Cm0Cd0_Cd2_Ch0Cm1_Ch3.zzz) * _Globals.ColorMatrixB_ColorCurveCm2.www) + (((_1188 * _Globals.ColorMatrixR_ColorCurveCd1.www) * (float3(1.0) / (_1188 + _Globals.ColorCurve_Cm0Cd0_Cd2_Ch0Cm1_Ch3.yyy))) + _Globals.ColorMatrixG_ColorCurveCd3Cm3.www))) - float3(0.00200000009499490261077880859375); + } + else + { + _1215 = fast::max(float3(0.0), mix(_1145, _1145 * ((_577 * float3x3(float3(1.06317996978759765625, 0.02339559979736804962158203125, -0.08657260239124298095703125), float3(-0.010633699595928192138671875, 1.2063200473785400390625, -0.1956900060176849365234375), float3(-0.0005908869788981974124908447265625, 0.00105247995816171169281005859375, 0.999538004398345947265625))) * _576), _940) * _575); + } + float3 _1216 = fast::clamp(_1215, float3(0.0), float3(1.0)); + float _1217 = _1216.x; + float _1229; + for (;;) + { + if (_1217 < 0.00313066993840038776397705078125) + { + _1229 = _1217 * 12.9200000762939453125; + break; + } + _1229 = (pow(_1217, 0.4166666567325592041015625) * 1.05499994754791259765625) - 0.054999999701976776123046875; + break; + } + float _1230 = _1216.y; + float _1242; + for (;;) + { + if (_1230 < 0.00313066993840038776397705078125) + { + _1242 = _1230 * 12.9200000762939453125; + break; + } + _1242 = (pow(_1230, 0.4166666567325592041015625) * 1.05499994754791259765625) - 0.054999999701976776123046875; + break; + } + float _1243 = _1216.z; + float _1255; + for (;;) + { + if (_1243 < 0.00313066993840038776397705078125) + { + _1255 = _1243 * 12.9200000762939453125; + break; + } + _1255 = (pow(_1243, 0.4166666567325592041015625) * 1.05499994754791259765625) - 0.054999999701976776123046875; + break; + } + float3 _1256 = float3(_1229, _1242, _1255); + float3 _1258 = (_1256 * float3(0.9375)) + float3(0.03125); + float _1270 = (_1258.z * 16.0) - 0.5; + float _1271 = floor(_1270); + float _1275 = (_1258.x + _1271) * 0.0625; + float _1276 = _1258.y; + float4 _1279 = Texture1.sample(Texture1Sampler, float2(_1275, _1276)); + float4 _1283 = Texture1.sample(Texture1Sampler, float2(_1275 + 0.0625, _1276)); + float3 _1289 = fast::max(float3(6.1035199905745685100555419921875e-05), (float3(_Globals.LUTWeights[0].x) * _1256) + (float3(_Globals.LUTWeights[1].x) * mix(_1279, _1283, float4(_1270 - _1271)).xyz)); + float3 _1295 = select(_1289 * float3(0.077399380505084991455078125), pow((_1289 * float3(0.94786727428436279296875)) + float3(0.0521326996386051177978515625), float3(2.400000095367431640625)), _1289 > float3(0.040449999272823333740234375)); + float3 _1324 = pow(fast::max(float3(0.0), mix((((float3(_Globals.MappingPolynomial.x) * (_1295 * _1295)) + (float3(_Globals.MappingPolynomial.y) * _1295)) + float3(_Globals.MappingPolynomial.z)) * _Globals.ColorScale, _Globals.OverlayColor.xyz, float3(_Globals.OverlayColor.w))), float3(_Globals.InverseGamma.y)); + float3 _3103; + if (_Globals.OutputDevice == 0u) + { + float _3063 = _1324.x; + float _3075; + for (;;) + { + if (_3063 < 0.00313066993840038776397705078125) + { + _3075 = _3063 * 12.9200000762939453125; + break; + } + _3075 = (pow(_3063, 0.4166666567325592041015625) * 1.05499994754791259765625) - 0.054999999701976776123046875; + break; + } + float _3076 = _1324.y; + float _3088; + for (;;) + { + if (_3076 < 0.00313066993840038776397705078125) + { + _3088 = _3076 * 12.9200000762939453125; + break; + } + _3088 = (pow(_3076, 0.4166666567325592041015625) * 1.05499994754791259765625) - 0.054999999701976776123046875; + break; + } + float _3089 = _1324.z; + float _3101; + for (;;) + { + if (_3089 < 0.00313066993840038776397705078125) + { + _3101 = _3089 * 12.9200000762939453125; + break; + } + _3101 = (pow(_3089, 0.4166666567325592041015625) * 1.05499994754791259765625) - 0.054999999701976776123046875; + break; + } + _3103 = float3(_3075, _3088, _3101); + } + else + { + float3 _3062; + if (_Globals.OutputDevice == 1u) + { + float3 _3055 = fast::max(float3(6.1035199905745685100555419921875e-05), (_1324 * _573) * _602); + _3062 = fast::min(_3055 * float3(4.5), (pow(fast::max(_3055, float3(0.017999999225139617919921875)), float3(0.449999988079071044921875)) * float3(1.09899997711181640625)) - float3(0.098999999463558197021484375)); + } + else + { + float3 _3052; + if ((_Globals.OutputDevice == 3u) || (_Globals.OutputDevice == 5u)) + { + float3 _2204 = (_932 * float3(1.5)) * (_572 * float3x3(float3(1.04981100559234619140625, 0.0, -9.74845024757087230682373046875e-05), float3(-0.49590301513671875, 1.37331306934356689453125, 0.09824003279209136962890625), float3(0.0, 0.0, 0.991252005100250244140625))); + float _2205 = _2204.x; + float _2206 = _2204.y; + float _2208 = _2204.z; + float _2211 = fast::max(fast::max(_2205, _2206), _2208); + float _2216 = (fast::max(_2211, 1.0000000133514319600180897396058e-10) - fast::max(fast::min(fast::min(_2205, _2206), _2208), 1.0000000133514319600180897396058e-10)) / fast::max(_2211, 0.00999999977648258209228515625); + float _2229 = ((_2208 + _2206) + _2205) + (1.75 * sqrt(((_2208 * (_2208 - _2206)) + (_2206 * (_2206 - _2205))) + (_2205 * (_2205 - _2208)))); + float _2230 = _2229 * 0.3333333432674407958984375; + float _2231 = _2216 - 0.4000000059604644775390625; + float _2236 = fast::max(1.0 - abs(_2231 * 2.5), 0.0); + float _2244 = (1.0 + (float(int(sign(_2231 * 5.0))) * (1.0 - (_2236 * _2236)))) * 0.02500000037252902984619140625; + float _2257; + if (_2230 <= 0.053333334624767303466796875) + { + _2257 = _2244; + } + else + { + float _2256; + if (_2230 >= 0.1599999964237213134765625) + { + _2256 = 0.0; + } + else + { + _2256 = _2244 * ((0.23999999463558197021484375 / _2229) - 0.5); + } + _2257 = _2256; + } + float3 _2260 = _2204 * float3(1.0 + _2257); + float _2261 = _2260.x; + float _2262 = _2260.y; + float _2264 = _2260.z; + float _2278; + if ((_2261 == _2262) && (_2262 == _2264)) + { + _2278 = 0.0; + } + else + { + _2278 = 57.2957763671875 * atan2(1.73205077648162841796875 * (_2262 - _2264), ((2.0 * _2261) - _2262) - _2264); + } + float _2283; + if (_2278 < 0.0) + { + _2283 = _2278 + 360.0; + } + else + { + _2283 = _2278; + } + float _2284 = fast::clamp(_2283, 0.0, 360.0); + float _2289; + if (_2284 > 180.0) + { + _2289 = _2284 - 360.0; + } + else + { + _2289 = _2284; + } + float _2339; + if ((_2289 > (-67.5)) && (_2289 < 67.5)) + { + float _2296 = (_2289 - (-67.5)) * 0.0296296291053295135498046875; + int _2297 = int(_2296); + float _2299 = _2296 - float(_2297); + float _2300 = _2299 * _2299; + float _2301 = _2300 * _2299; + float _2338; + if (_2297 == 3) + { + _2338 = (((_2301 * (-0.16666667163372039794921875)) + (_2300 * 0.5)) + (_2299 * (-0.5))) + 0.16666667163372039794921875; + } + else + { + float _2331; + if (_2297 == 2) + { + _2331 = ((_2301 * 0.5) + (_2300 * (-1.0))) + 0.666666686534881591796875; + } + else + { + float _2326; + if (_2297 == 1) + { + _2326 = (((_2301 * (-0.5)) + (_2300 * 0.5)) + (_2299 * 0.5)) + 0.16666667163372039794921875; + } + else + { + float _2319; + if (_2297 == 0) + { + _2319 = _2301 * 0.16666667163372039794921875; + } + else + { + _2319 = 0.0; + } + _2326 = _2319; + } + _2331 = _2326; + } + _2338 = _2331; + } + _2339 = _2338; + } + else + { + _2339 = 0.0; + } + float3 _2346 = _2260; + _2346.x = _2261 + ((((_2339 * 1.5) * _2216) * (0.02999999932944774627685546875 - _2261)) * 0.180000007152557373046875); + float3 _2349 = fast::clamp(fast::clamp(_2346, float3(0.0), float3(65535.0)) * float3x3(float3(1.45143926143646240234375, -0.236510753631591796875, -0.214928567409515380859375), float3(-0.07655377686023712158203125, 1.1762297153472900390625, -0.0996759235858917236328125), float3(0.0083161480724811553955078125, -0.0060324496589601039886474609375, 0.99771630764007568359375)), float3(0.0), float3(65535.0)); + float3 _2352 = mix(float3(dot(_2349, float3(0.272228717803955078125, 0.674081742763519287109375, 0.053689517080783843994140625))), _2349, float3(0.959999978542327880859375)); + float _2353 = _2352.x; + float _2362 = log((_2353 <= 0.0) ? 6.103515625e-05 : _2353) * 0.4342944622039794921875; + float _2431; + if (_2362 <= (-5.2601776123046875)) + { + _2431 = -4.0; + } + else + { + float _2428; + if ((_2362 > (-5.2601776123046875)) && (_2362 < (-0.744727432727813720703125))) + { + float _2411 = (_2362 - (-5.2601776123046875)) * 0.6643855571746826171875; + int _2412 = int(_2411); + float _2414 = _2411 - float(_2412); + _2428 = dot(float3(_2414 * _2414, _2414, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_499[_2412], _499[_2412 + 1], _499[_2412 + 2])); + } + else + { + float _2407; + if ((_2362 >= (-0.744727432727813720703125)) && (_2362 < 4.673812389373779296875)) + { + float _2390 = (_2362 - (-0.744727432727813720703125)) * 0.55365467071533203125; + int _2391 = int(_2390); + float _2393 = _2390 - float(_2391); + _2407 = dot(float3(_2393 * _2393, _2393, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_500[_2391], _500[_2391 + 1], _500[_2391 + 2])); + } + else + { + _2407 = 4.0; + } + _2428 = _2407; + } + _2431 = _2428; + } + float3 _2433 = _523; + _2433.x = pow(10.0, _2431); + float _2434 = _2352.y; + float _2438 = log((_2434 <= 0.0) ? 6.103515625e-05 : _2434) * 0.4342944622039794921875; + float _2505; + if (_2438 <= (-5.2601776123046875)) + { + _2505 = -4.0; + } + else + { + float _2502; + if ((_2438 > (-5.2601776123046875)) && (_2438 < (-0.744727432727813720703125))) + { + float _2485 = (_2438 - (-5.2601776123046875)) * 0.6643855571746826171875; + int _2486 = int(_2485); + float _2488 = _2485 - float(_2486); + _2502 = dot(float3(_2488 * _2488, _2488, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_499[_2486], _499[_2486 + 1], _499[_2486 + 2])); + } + else + { + float _2481; + if ((_2438 >= (-0.744727432727813720703125)) && (_2438 < 4.673812389373779296875)) + { + float _2464 = (_2438 - (-0.744727432727813720703125)) * 0.55365467071533203125; + int _2465 = int(_2464); + float _2467 = _2464 - float(_2465); + _2481 = dot(float3(_2467 * _2467, _2467, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_500[_2465], _500[_2465 + 1], _500[_2465 + 2])); + } + else + { + _2481 = 4.0; + } + _2502 = _2481; + } + _2505 = _2502; + } + float3 _2507 = _2433; + _2507.y = pow(10.0, _2505); + float _2508 = _2352.z; + float _2512 = log((_2508 <= 0.0) ? 6.103515625e-05 : _2508) * 0.4342944622039794921875; + float _2579; + if (_2512 <= (-5.2601776123046875)) + { + _2579 = -4.0; + } + else + { + float _2576; + if ((_2512 > (-5.2601776123046875)) && (_2512 < (-0.744727432727813720703125))) + { + float _2559 = (_2512 - (-5.2601776123046875)) * 0.6643855571746826171875; + int _2560 = int(_2559); + float _2562 = _2559 - float(_2560); + _2576 = dot(float3(_2562 * _2562, _2562, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_499[_2560], _499[_2560 + 1], _499[_2560 + 2])); + } + else + { + float _2555; + if ((_2512 >= (-0.744727432727813720703125)) && (_2512 < 4.673812389373779296875)) + { + float _2538 = (_2512 - (-0.744727432727813720703125)) * 0.55365467071533203125; + int _2539 = int(_2538); + float _2541 = _2538 - float(_2539); + _2555 = dot(float3(_2541 * _2541, _2541, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_500[_2539], _500[_2539 + 1], _500[_2539 + 2])); + } + else + { + _2555 = 4.0; + } + _2576 = _2555; + } + _2579 = _2576; + } + float3 _2581 = _2507; + _2581.z = pow(10.0, _2579); + float3 _2583 = (_2581 * float3x3(float3(0.695452213287353515625, 0.140678703784942626953125, 0.16386906802654266357421875), float3(0.0447945632040500640869140625, 0.859671115875244140625, 0.095534317195415496826171875), float3(-0.0055258828215301036834716796875, 0.0040252101607620716094970703125, 1.00150072574615478515625))) * float3x3(float3(1.45143926143646240234375, -0.236510753631591796875, -0.214928567409515380859375), float3(-0.07655377686023712158203125, 1.1762297153472900390625, -0.0996759235858917236328125), float3(0.0083161480724811553955078125, -0.0060324496589601039886474609375, 0.99771630764007568359375)); + float _2714 = pow(10.0, (float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_500[0], _500[1], _500[2])).z); + float _2786 = pow(10.0, dot(float3(0.4444443881511688232421875, 0.66666662693023681640625, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_500[1], _500[2], _500[3]))); + float _2787 = _2583.x; + float _2790 = log((_2787 <= 0.0) ? 9.9999997473787516355514526367188e-05 : _2787); + float _2791 = _2790 * 0.4342944622039794921875; + float _2792 = log(pow(10.0, dot(float3(0.3600003719329833984375, 0.600000321865081787109375, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_499[0], _499[1], _499[2])))); + float _2793 = _2792 * 0.4342944622039794921875; + float _2870; + if (_2791 <= _2793) + { + _2870 = (_2790 * 1.3028833866119384765625) + ((-4.0) - (_2792 * 1.3028833866119384765625)); + } + else + { + float _2800 = log(_2714) * 0.4342944622039794921875; + float _2862; + if ((_2791 > _2793) && (_2791 < _2800)) + { + float _2845 = (7.0 * (_2791 - _2793)) / (_2800 - _2793); + int _2846 = int(_2845); + float _2848 = _2845 - float(_2846); + _2862 = dot(float3(_2848 * _2848, _2848, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_503[_2846], _503[_2846 + 1], _503[_2846 + 2])); + } + else + { + float _2807 = log(_2786); + float _2808 = _2807 * 0.4342944622039794921875; + float _2841; + if ((_2791 >= _2800) && (_2791 < _2808)) + { + float _2824 = (7.0 * (_2791 - _2800)) / (_2808 - _2800); + int _2825 = int(_2824); + float _2827 = _2824 - float(_2825); + _2841 = dot(float3(_2827 * _2827, _2827, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_504[_2825], _504[_2825 + 1], _504[_2825 + 2])); + } + else + { + _2841 = (_2790 * 0.026057668030261993408203125) + (3.0 - (_2807 * 0.026057668030261993408203125)); + } + _2862 = _2841; + } + _2870 = _2862; + } + float3 _2872 = _523; + _2872.x = pow(10.0, _2870); + float _2873 = _2583.y; + float _2876 = log((_2873 <= 0.0) ? 9.9999997473787516355514526367188e-05 : _2873); + float _2877 = _2876 * 0.4342944622039794921875; + float _2954; + if (_2877 <= _2793) + { + _2954 = (_2876 * 1.3028833866119384765625) + ((-4.0) - (_2792 * 1.3028833866119384765625)); + } + else + { + float _2884 = log(_2714) * 0.4342944622039794921875; + float _2946; + if ((_2877 > _2793) && (_2877 < _2884)) + { + float _2929 = (7.0 * (_2877 - _2793)) / (_2884 - _2793); + int _2930 = int(_2929); + float _2932 = _2929 - float(_2930); + _2946 = dot(float3(_2932 * _2932, _2932, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_503[_2930], _503[_2930 + 1], _503[_2930 + 2])); + } + else + { + float _2891 = log(_2786); + float _2892 = _2891 * 0.4342944622039794921875; + float _2925; + if ((_2877 >= _2884) && (_2877 < _2892)) + { + float _2908 = (7.0 * (_2877 - _2884)) / (_2892 - _2884); + int _2909 = int(_2908); + float _2911 = _2908 - float(_2909); + _2925 = dot(float3(_2911 * _2911, _2911, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_504[_2909], _504[_2909 + 1], _504[_2909 + 2])); + } + else + { + _2925 = (_2876 * 0.026057668030261993408203125) + (3.0 - (_2891 * 0.026057668030261993408203125)); + } + _2946 = _2925; + } + _2954 = _2946; + } + float3 _2956 = _2872; + _2956.y = pow(10.0, _2954); + float _2957 = _2583.z; + float _2960 = log((_2957 <= 0.0) ? 9.9999997473787516355514526367188e-05 : _2957); + float _2961 = _2960 * 0.4342944622039794921875; + float _3038; + if (_2961 <= _2793) + { + _3038 = (_2960 * 1.3028833866119384765625) + ((-4.0) - (_2792 * 1.3028833866119384765625)); + } + else + { + float _2968 = log(_2714) * 0.4342944622039794921875; + float _3030; + if ((_2961 > _2793) && (_2961 < _2968)) + { + float _3013 = (7.0 * (_2961 - _2793)) / (_2968 - _2793); + int _3014 = int(_3013); + float _3016 = _3013 - float(_3014); + _3030 = dot(float3(_3016 * _3016, _3016, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_503[_3014], _503[_3014 + 1], _503[_3014 + 2])); + } + else + { + float _2975 = log(_2786); + float _2976 = _2975 * 0.4342944622039794921875; + float _3009; + if ((_2961 >= _2968) && (_2961 < _2976)) + { + float _2992 = (7.0 * (_2961 - _2968)) / (_2976 - _2968); + int _2993 = int(_2992); + float _2995 = _2992 - float(_2993); + _3009 = dot(float3(_2995 * _2995, _2995, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_504[_2993], _504[_2993 + 1], _504[_2993 + 2])); + } + else + { + _3009 = (_2960 * 0.026057668030261993408203125) + (3.0 - (_2975 * 0.026057668030261993408203125)); + } + _3030 = _3009; + } + _3038 = _3030; + } + float3 _3040 = _2956; + _3040.z = pow(10.0, _3038); + float3 _3044 = pow(((_3040 - float3(3.5073844628641381859779357910156e-05)) * _602) * float3(9.9999997473787516355514526367188e-05), float3(0.1593017578125)); + _3052 = pow((float3(0.8359375) + (float3(18.8515625) * _3044)) * (float3(1.0) / (float3(1.0) + (float3(18.6875) * _3044))), float3(78.84375)); + } + else + { + float3 _2201; + if ((_Globals.OutputDevice == 4u) || (_Globals.OutputDevice == 6u)) + { + float3 _1369 = (_932 * float3(1.5)) * (_572 * float3x3(float3(1.04981100559234619140625, 0.0, -9.74845024757087230682373046875e-05), float3(-0.49590301513671875, 1.37331306934356689453125, 0.09824003279209136962890625), float3(0.0, 0.0, 0.991252005100250244140625))); + float _1370 = _1369.x; + float _1371 = _1369.y; + float _1373 = _1369.z; + float _1376 = fast::max(fast::max(_1370, _1371), _1373); + float _1381 = (fast::max(_1376, 1.0000000133514319600180897396058e-10) - fast::max(fast::min(fast::min(_1370, _1371), _1373), 1.0000000133514319600180897396058e-10)) / fast::max(_1376, 0.00999999977648258209228515625); + float _1394 = ((_1373 + _1371) + _1370) + (1.75 * sqrt(((_1373 * (_1373 - _1371)) + (_1371 * (_1371 - _1370))) + (_1370 * (_1370 - _1373)))); + float _1395 = _1394 * 0.3333333432674407958984375; + float _1396 = _1381 - 0.4000000059604644775390625; + float _1401 = fast::max(1.0 - abs(_1396 * 2.5), 0.0); + float _1409 = (1.0 + (float(int(sign(_1396 * 5.0))) * (1.0 - (_1401 * _1401)))) * 0.02500000037252902984619140625; + float _1422; + if (_1395 <= 0.053333334624767303466796875) + { + _1422 = _1409; + } + else + { + float _1421; + if (_1395 >= 0.1599999964237213134765625) + { + _1421 = 0.0; + } + else + { + _1421 = _1409 * ((0.23999999463558197021484375 / _1394) - 0.5); + } + _1422 = _1421; + } + float3 _1425 = _1369 * float3(1.0 + _1422); + float _1426 = _1425.x; + float _1427 = _1425.y; + float _1429 = _1425.z; + float _1443; + if ((_1426 == _1427) && (_1427 == _1429)) + { + _1443 = 0.0; + } + else + { + _1443 = 57.2957763671875 * atan2(1.73205077648162841796875 * (_1427 - _1429), ((2.0 * _1426) - _1427) - _1429); + } + float _1448; + if (_1443 < 0.0) + { + _1448 = _1443 + 360.0; + } + else + { + _1448 = _1443; + } + float _1449 = fast::clamp(_1448, 0.0, 360.0); + float _1454; + if (_1449 > 180.0) + { + _1454 = _1449 - 360.0; + } + else + { + _1454 = _1449; + } + float _1504; + if ((_1454 > (-67.5)) && (_1454 < 67.5)) + { + float _1461 = (_1454 - (-67.5)) * 0.0296296291053295135498046875; + int _1462 = int(_1461); + float _1464 = _1461 - float(_1462); + float _1465 = _1464 * _1464; + float _1466 = _1465 * _1464; + float _1503; + if (_1462 == 3) + { + _1503 = (((_1466 * (-0.16666667163372039794921875)) + (_1465 * 0.5)) + (_1464 * (-0.5))) + 0.16666667163372039794921875; + } + else + { + float _1496; + if (_1462 == 2) + { + _1496 = ((_1466 * 0.5) + (_1465 * (-1.0))) + 0.666666686534881591796875; + } + else + { + float _1491; + if (_1462 == 1) + { + _1491 = (((_1466 * (-0.5)) + (_1465 * 0.5)) + (_1464 * 0.5)) + 0.16666667163372039794921875; + } + else + { + float _1484; + if (_1462 == 0) + { + _1484 = _1466 * 0.16666667163372039794921875; + } + else + { + _1484 = 0.0; + } + _1491 = _1484; + } + _1496 = _1491; + } + _1503 = _1496; + } + _1504 = _1503; + } + else + { + _1504 = 0.0; + } + float3 _1511 = _1425; + _1511.x = _1426 + ((((_1504 * 1.5) * _1381) * (0.02999999932944774627685546875 - _1426)) * 0.180000007152557373046875); + float3 _1514 = fast::clamp(fast::clamp(_1511, float3(0.0), float3(65535.0)) * float3x3(float3(1.45143926143646240234375, -0.236510753631591796875, -0.214928567409515380859375), float3(-0.07655377686023712158203125, 1.1762297153472900390625, -0.0996759235858917236328125), float3(0.0083161480724811553955078125, -0.0060324496589601039886474609375, 0.99771630764007568359375)), float3(0.0), float3(65535.0)); + float3 _1517 = mix(float3(dot(_1514, float3(0.272228717803955078125, 0.674081742763519287109375, 0.053689517080783843994140625))), _1514, float3(0.959999978542327880859375)); + float _1518 = _1517.x; + float _1527 = log((_1518 <= 0.0) ? 6.103515625e-05 : _1518) * 0.4342944622039794921875; + float _1596; + if (_1527 <= (-5.2601776123046875)) + { + _1596 = -4.0; + } + else + { + float _1593; + if ((_1527 > (-5.2601776123046875)) && (_1527 < (-0.744727432727813720703125))) + { + float _1576 = (_1527 - (-5.2601776123046875)) * 0.6643855571746826171875; + int _1577 = int(_1576); + float _1579 = _1576 - float(_1577); + _1593 = dot(float3(_1579 * _1579, _1579, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_499[_1577], _499[_1577 + 1], _499[_1577 + 2])); + } + else + { + float _1572; + if ((_1527 >= (-0.744727432727813720703125)) && (_1527 < 4.673812389373779296875)) + { + float _1555 = (_1527 - (-0.744727432727813720703125)) * 0.55365467071533203125; + int _1556 = int(_1555); + float _1558 = _1555 - float(_1556); + _1572 = dot(float3(_1558 * _1558, _1558, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_500[_1556], _500[_1556 + 1], _500[_1556 + 2])); + } + else + { + _1572 = 4.0; + } + _1593 = _1572; + } + _1596 = _1593; + } + float3 _1598 = _523; + _1598.x = pow(10.0, _1596); + float _1599 = _1517.y; + float _1603 = log((_1599 <= 0.0) ? 6.103515625e-05 : _1599) * 0.4342944622039794921875; + float _1670; + if (_1603 <= (-5.2601776123046875)) + { + _1670 = -4.0; + } + else + { + float _1667; + if ((_1603 > (-5.2601776123046875)) && (_1603 < (-0.744727432727813720703125))) + { + float _1650 = (_1603 - (-5.2601776123046875)) * 0.6643855571746826171875; + int _1651 = int(_1650); + float _1653 = _1650 - float(_1651); + _1667 = dot(float3(_1653 * _1653, _1653, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_499[_1651], _499[_1651 + 1], _499[_1651 + 2])); + } + else + { + float _1646; + if ((_1603 >= (-0.744727432727813720703125)) && (_1603 < 4.673812389373779296875)) + { + float _1629 = (_1603 - (-0.744727432727813720703125)) * 0.55365467071533203125; + int _1630 = int(_1629); + float _1632 = _1629 - float(_1630); + _1646 = dot(float3(_1632 * _1632, _1632, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_500[_1630], _500[_1630 + 1], _500[_1630 + 2])); + } + else + { + _1646 = 4.0; + } + _1667 = _1646; + } + _1670 = _1667; + } + float3 _1672 = _1598; + _1672.y = pow(10.0, _1670); + float _1673 = _1517.z; + float _1677 = log((_1673 <= 0.0) ? 6.103515625e-05 : _1673) * 0.4342944622039794921875; + float _1744; + if (_1677 <= (-5.2601776123046875)) + { + _1744 = -4.0; + } + else + { + float _1741; + if ((_1677 > (-5.2601776123046875)) && (_1677 < (-0.744727432727813720703125))) + { + float _1724 = (_1677 - (-5.2601776123046875)) * 0.6643855571746826171875; + int _1725 = int(_1724); + float _1727 = _1724 - float(_1725); + _1741 = dot(float3(_1727 * _1727, _1727, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_499[_1725], _499[_1725 + 1], _499[_1725 + 2])); + } + else + { + float _1720; + if ((_1677 >= (-0.744727432727813720703125)) && (_1677 < 4.673812389373779296875)) + { + float _1703 = (_1677 - (-0.744727432727813720703125)) * 0.55365467071533203125; + int _1704 = int(_1703); + float _1706 = _1703 - float(_1704); + _1720 = dot(float3(_1706 * _1706, _1706, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_500[_1704], _500[_1704 + 1], _500[_1704 + 2])); + } + else + { + _1720 = 4.0; + } + _1741 = _1720; + } + _1744 = _1741; + } + float3 _1746 = _1672; + _1746.z = pow(10.0, _1744); + float3 _1748 = (_1746 * float3x3(float3(0.695452213287353515625, 0.140678703784942626953125, 0.16386906802654266357421875), float3(0.0447945632040500640869140625, 0.859671115875244140625, 0.095534317195415496826171875), float3(-0.0055258828215301036834716796875, 0.0040252101607620716094970703125, 1.00150072574615478515625))) * float3x3(float3(1.45143926143646240234375, -0.236510753631591796875, -0.214928567409515380859375), float3(-0.07655377686023712158203125, 1.1762297153472900390625, -0.0996759235858917236328125), float3(0.0083161480724811553955078125, -0.0060324496589601039886474609375, 0.99771630764007568359375)); + float _1879 = pow(10.0, (float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_500[0], _500[1], _500[2])).z); + float _1951 = pow(10.0, dot(float3(0.69444429874420166015625, 0.8333332538604736328125, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_500[1], _500[2], _500[3]))); + float _1952 = _1748.x; + float _1955 = log((_1952 <= 0.0) ? 9.9999997473787516355514526367188e-05 : _1952); + float _1956 = _1955 * 0.4342944622039794921875; + float _1958 = log(pow(10.0, dot(float3(0.3600003719329833984375, 0.600000321865081787109375, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_499[0], _499[1], _499[2])))) * 0.4342944622039794921875; + float _2030; + if (_1956 <= _1958) + { + _2030 = -2.3010299205780029296875; + } + else + { + float _1965 = log(_1879) * 0.4342944622039794921875; + float _2027; + if ((_1956 > _1958) && (_1956 < _1965)) + { + float _2010 = (7.0 * (_1956 - _1958)) / (_1965 - _1958); + int _2011 = int(_2010); + float _2013 = _2010 - float(_2011); + _2027 = dot(float3(_2013 * _2013, _2013, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_506[_2011], _506[_2011 + 1], _506[_2011 + 2])); + } + else + { + float _1972 = log(_1951); + float _1973 = _1972 * 0.4342944622039794921875; + float _2006; + if ((_1956 >= _1965) && (_1956 < _1973)) + { + float _1989 = (7.0 * (_1956 - _1965)) / (_1973 - _1965); + int _1990 = int(_1989); + float _1992 = _1989 - float(_1990); + _2006 = dot(float3(_1992 * _1992, _1992, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_507[_1990], _507[_1990 + 1], _507[_1990 + 2])); + } + else + { + _2006 = (_1955 * 0.05211533606052398681640625) + (3.3010299205780029296875 - (_1972 * 0.05211533606052398681640625)); + } + _2027 = _2006; + } + _2030 = _2027; + } + float3 _2032 = _523; + _2032.x = pow(10.0, _2030); + float _2033 = _1748.y; + float _2036 = log((_2033 <= 0.0) ? 9.9999997473787516355514526367188e-05 : _2033); + float _2037 = _2036 * 0.4342944622039794921875; + float _2109; + if (_2037 <= _1958) + { + _2109 = -2.3010299205780029296875; + } + else + { + float _2044 = log(_1879) * 0.4342944622039794921875; + float _2106; + if ((_2037 > _1958) && (_2037 < _2044)) + { + float _2089 = (7.0 * (_2037 - _1958)) / (_2044 - _1958); + int _2090 = int(_2089); + float _2092 = _2089 - float(_2090); + _2106 = dot(float3(_2092 * _2092, _2092, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_506[_2090], _506[_2090 + 1], _506[_2090 + 2])); + } + else + { + float _2051 = log(_1951); + float _2052 = _2051 * 0.4342944622039794921875; + float _2085; + if ((_2037 >= _2044) && (_2037 < _2052)) + { + float _2068 = (7.0 * (_2037 - _2044)) / (_2052 - _2044); + int _2069 = int(_2068); + float _2071 = _2068 - float(_2069); + _2085 = dot(float3(_2071 * _2071, _2071, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_507[_2069], _507[_2069 + 1], _507[_2069 + 2])); + } + else + { + _2085 = (_2036 * 0.05211533606052398681640625) + (3.3010299205780029296875 - (_2051 * 0.05211533606052398681640625)); + } + _2106 = _2085; + } + _2109 = _2106; + } + float3 _2111 = _2032; + _2111.y = pow(10.0, _2109); + float _2112 = _1748.z; + float _2115 = log((_2112 <= 0.0) ? 9.9999997473787516355514526367188e-05 : _2112); + float _2116 = _2115 * 0.4342944622039794921875; + float _2188; + if (_2116 <= _1958) + { + _2188 = -2.3010299205780029296875; + } + else + { + float _2123 = log(_1879) * 0.4342944622039794921875; + float _2185; + if ((_2116 > _1958) && (_2116 < _2123)) + { + float _2168 = (7.0 * (_2116 - _1958)) / (_2123 - _1958); + int _2169 = int(_2168); + float _2171 = _2168 - float(_2169); + _2185 = dot(float3(_2171 * _2171, _2171, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_506[_2169], _506[_2169 + 1], _506[_2169 + 2])); + } + else + { + float _2130 = log(_1951); + float _2131 = _2130 * 0.4342944622039794921875; + float _2164; + if ((_2116 >= _2123) && (_2116 < _2131)) + { + float _2147 = (7.0 * (_2116 - _2123)) / (_2131 - _2123); + int _2148 = int(_2147); + float _2150 = _2147 - float(_2148); + _2164 = dot(float3(_2150 * _2150, _2150, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_507[_2148], _507[_2148 + 1], _507[_2148 + 2])); + } + else + { + _2164 = (_2115 * 0.05211533606052398681640625) + (3.3010299205780029296875 - (_2130 * 0.05211533606052398681640625)); + } + _2185 = _2164; + } + _2188 = _2185; + } + float3 _2190 = _2111; + _2190.z = pow(10.0, _2188); + float3 _2193 = pow((_2190 * _602) * float3(9.9999997473787516355514526367188e-05), float3(0.1593017578125)); + _2201 = pow((float3(0.8359375) + (float3(18.8515625) * _2193)) * (float3(1.0) / (float3(1.0) + (float3(18.6875) * _2193))), float3(78.84375)); + } + else + { + float3 _1366; + if (_Globals.OutputDevice == 7u) + { + float3 _1358 = pow(((_932 * _573) * _602) * float3(9.9999997473787516355514526367188e-05), float3(0.1593017578125)); + _1366 = pow((float3(0.8359375) + (float3(18.8515625) * _1358)) * (float3(1.0) / (float3(1.0) + (float3(18.6875) * _1358))), float3(78.84375)); + } + else + { + _1366 = pow((_1324 * _573) * _602, float3(_Globals.InverseGamma.z)); + } + _2201 = _1366; + } + _3052 = _2201; + } + _3062 = _3052; + } + _3103 = _3062; + } + float3 _3104 = _3103 * float3(0.95238101482391357421875); + float4 _3106 = float4(_3104.x, _3104.y, _3104.z, float4(0.0).w); + _3106.w = 0.0; + out.out_var_SV_Target0 = _3106; + return out; +} + diff --git a/third_party/spirv-cross/reference/opt/shaders-ue4/asm/frag/sample-mask-not-array.asm.frag b/third_party/spirv-cross/reference/opt/shaders-ue4/asm/frag/sample-mask-not-array.asm.frag new file mode 100644 index 0000000000..479471d245 --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders-ue4/asm/frag/sample-mask-not-array.asm.frag @@ -0,0 +1,503 @@ +#include +#include + +using namespace metal; + +struct type_View +{ + float4x4 View_TranslatedWorldToClip; + float4x4 View_WorldToClip; + float4x4 View_TranslatedWorldToView; + float4x4 View_ViewToTranslatedWorld; + float4x4 View_TranslatedWorldToCameraView; + float4x4 View_CameraViewToTranslatedWorld; + float4x4 View_ViewToClip; + float4x4 View_ViewToClipNoAA; + float4x4 View_ClipToView; + float4x4 View_ClipToTranslatedWorld; + float4x4 View_SVPositionToTranslatedWorld; + float4x4 View_ScreenToWorld; + float4x4 View_ScreenToTranslatedWorld; + packed_float3 View_ViewForward; + float PrePadding_View_844; + packed_float3 View_ViewUp; + float PrePadding_View_860; + packed_float3 View_ViewRight; + float PrePadding_View_876; + packed_float3 View_HMDViewNoRollUp; + float PrePadding_View_892; + packed_float3 View_HMDViewNoRollRight; + float PrePadding_View_908; + float4 View_InvDeviceZToWorldZTransform; + float4 View_ScreenPositionScaleBias; + packed_float3 View_WorldCameraOrigin; + float PrePadding_View_956; + packed_float3 View_TranslatedWorldCameraOrigin; + float PrePadding_View_972; + packed_float3 View_WorldViewOrigin; + float PrePadding_View_988; + packed_float3 View_PreViewTranslation; + float PrePadding_View_1004; + float4x4 View_PrevProjection; + float4x4 View_PrevViewProj; + float4x4 View_PrevViewRotationProj; + float4x4 View_PrevViewToClip; + float4x4 View_PrevClipToView; + float4x4 View_PrevTranslatedWorldToClip; + float4x4 View_PrevTranslatedWorldToView; + float4x4 View_PrevViewToTranslatedWorld; + float4x4 View_PrevTranslatedWorldToCameraView; + float4x4 View_PrevCameraViewToTranslatedWorld; + packed_float3 View_PrevWorldCameraOrigin; + float PrePadding_View_1660; + packed_float3 View_PrevWorldViewOrigin; + float PrePadding_View_1676; + packed_float3 View_PrevPreViewTranslation; + float PrePadding_View_1692; + float4x4 View_PrevInvViewProj; + float4x4 View_PrevScreenToTranslatedWorld; + float4x4 View_ClipToPrevClip; + float4 View_TemporalAAJitter; + float4 View_GlobalClippingPlane; + float2 View_FieldOfViewWideAngles; + float2 View_PrevFieldOfViewWideAngles; + float4 View_ViewRectMin; + float4 View_ViewSizeAndInvSize; + float4 View_BufferSizeAndInvSize; + float4 View_BufferBilinearUVMinMax; + int View_NumSceneColorMSAASamples; + float View_PreExposure; + float View_OneOverPreExposure; + float PrePadding_View_2012; + float4 View_DiffuseOverrideParameter; + float4 View_SpecularOverrideParameter; + float4 View_NormalOverrideParameter; + float2 View_RoughnessOverrideParameter; + float View_PrevFrameGameTime; + float View_PrevFrameRealTime; + float View_OutOfBoundsMask; + float PrePadding_View_2084; + float PrePadding_View_2088; + float PrePadding_View_2092; + packed_float3 View_WorldCameraMovementSinceLastFrame; + float View_CullingSign; + float View_NearPlane; + float View_AdaptiveTessellationFactor; + float View_GameTime; + float View_RealTime; + float View_DeltaTime; + float View_MaterialTextureMipBias; + float View_MaterialTextureDerivativeMultiply; + uint View_Random; + uint View_FrameNumber; + uint View_StateFrameIndexMod8; + uint View_StateFrameIndex; + float View_CameraCut; + float View_UnlitViewmodeMask; + float PrePadding_View_2164; + float PrePadding_View_2168; + float PrePadding_View_2172; + float4 View_DirectionalLightColor; + packed_float3 View_DirectionalLightDirection; + float PrePadding_View_2204; + float4 View_TranslucencyLightingVolumeMin[2]; + float4 View_TranslucencyLightingVolumeInvSize[2]; + float4 View_TemporalAAParams; + float4 View_CircleDOFParams; + float View_DepthOfFieldSensorWidth; + float View_DepthOfFieldFocalDistance; + float View_DepthOfFieldScale; + float View_DepthOfFieldFocalLength; + float View_DepthOfFieldFocalRegion; + float View_DepthOfFieldNearTransitionRegion; + float View_DepthOfFieldFarTransitionRegion; + float View_MotionBlurNormalizedToPixel; + float View_bSubsurfacePostprocessEnabled; + float View_GeneralPurposeTweak; + float View_DemosaicVposOffset; + float PrePadding_View_2348; + packed_float3 View_IndirectLightingColorScale; + float View_HDR32bppEncodingMode; + packed_float3 View_AtmosphericFogSunDirection; + float View_AtmosphericFogSunPower; + float View_AtmosphericFogPower; + float View_AtmosphericFogDensityScale; + float View_AtmosphericFogDensityOffset; + float View_AtmosphericFogGroundOffset; + float View_AtmosphericFogDistanceScale; + float View_AtmosphericFogAltitudeScale; + float View_AtmosphericFogHeightScaleRayleigh; + float View_AtmosphericFogStartDistance; + float View_AtmosphericFogDistanceOffset; + float View_AtmosphericFogSunDiscScale; + uint View_AtmosphericFogRenderMask; + uint View_AtmosphericFogInscatterAltitudeSampleNum; + float4 View_AtmosphericFogSunColor; + packed_float3 View_NormalCurvatureToRoughnessScaleBias; + float View_RenderingReflectionCaptureMask; + float4 View_AmbientCubemapTint; + float View_AmbientCubemapIntensity; + float View_SkyLightParameters; + float PrePadding_View_2488; + float PrePadding_View_2492; + float4 View_SkyLightColor; + float4 View_SkyIrradianceEnvironmentMap[7]; + float View_MobilePreviewMode; + float View_HMDEyePaddingOffset; + float View_ReflectionCubemapMaxMip; + float View_ShowDecalsMask; + uint View_DistanceFieldAOSpecularOcclusionMode; + float View_IndirectCapsuleSelfShadowingIntensity; + float PrePadding_View_2648; + float PrePadding_View_2652; + packed_float3 View_ReflectionEnvironmentRoughnessMixingScaleBiasAndLargestWeight; + int View_StereoPassIndex; + float4 View_GlobalVolumeCenterAndExtent[4]; + float4 View_GlobalVolumeWorldToUVAddAndMul[4]; + float View_GlobalVolumeDimension; + float View_GlobalVolumeTexelSize; + float View_MaxGlobalDistance; + float View_bCheckerboardSubsurfaceProfileRendering; + packed_float3 View_VolumetricFogInvGridSize; + float PrePadding_View_2828; + packed_float3 View_VolumetricFogGridZParams; + float PrePadding_View_2844; + float2 View_VolumetricFogSVPosToVolumeUV; + float View_VolumetricFogMaxDistance; + float PrePadding_View_2860; + packed_float3 View_VolumetricLightmapWorldToUVScale; + float PrePadding_View_2876; + packed_float3 View_VolumetricLightmapWorldToUVAdd; + float PrePadding_View_2892; + packed_float3 View_VolumetricLightmapIndirectionTextureSize; + float View_VolumetricLightmapBrickSize; + packed_float3 View_VolumetricLightmapBrickTexelSize; + float View_StereoIPD; + float View_IndirectLightingCacheShowFlag; + float View_EyeToPixelSpreadAngle; +}; + +struct type_StructuredBuffer_v4float +{ + float4 _m0[1]; +}; + +struct type_TranslucentBasePass +{ + uint TranslucentBasePass_Shared_Forward_NumLocalLights; + uint TranslucentBasePass_Shared_Forward_NumReflectionCaptures; + uint TranslucentBasePass_Shared_Forward_HasDirectionalLight; + uint TranslucentBasePass_Shared_Forward_NumGridCells; + packed_int3 TranslucentBasePass_Shared_Forward_CulledGridSize; + uint TranslucentBasePass_Shared_Forward_MaxCulledLightsPerCell; + uint TranslucentBasePass_Shared_Forward_LightGridPixelSizeShift; + uint PrePadding_TranslucentBasePass_Shared_Forward_36; + uint PrePadding_TranslucentBasePass_Shared_Forward_40; + uint PrePadding_TranslucentBasePass_Shared_Forward_44; + packed_float3 TranslucentBasePass_Shared_Forward_LightGridZParams; + float PrePadding_TranslucentBasePass_Shared_Forward_60; + packed_float3 TranslucentBasePass_Shared_Forward_DirectionalLightDirection; + float PrePadding_TranslucentBasePass_Shared_Forward_76; + packed_float3 TranslucentBasePass_Shared_Forward_DirectionalLightColor; + float TranslucentBasePass_Shared_Forward_DirectionalLightVolumetricScatteringIntensity; + uint TranslucentBasePass_Shared_Forward_DirectionalLightShadowMapChannelMask; + uint PrePadding_TranslucentBasePass_Shared_Forward_100; + float2 TranslucentBasePass_Shared_Forward_DirectionalLightDistanceFadeMAD; + uint TranslucentBasePass_Shared_Forward_NumDirectionalLightCascades; + uint PrePadding_TranslucentBasePass_Shared_Forward_116; + uint PrePadding_TranslucentBasePass_Shared_Forward_120; + uint PrePadding_TranslucentBasePass_Shared_Forward_124; + float4 TranslucentBasePass_Shared_Forward_CascadeEndDepths; + float4x4 TranslucentBasePass_Shared_Forward_DirectionalLightWorldToShadowMatrix[4]; + float4 TranslucentBasePass_Shared_Forward_DirectionalLightShadowmapMinMax[4]; + float4 TranslucentBasePass_Shared_Forward_DirectionalLightShadowmapAtlasBufferSize; + float TranslucentBasePass_Shared_Forward_DirectionalLightDepthBias; + uint TranslucentBasePass_Shared_Forward_DirectionalLightUseStaticShadowing; + uint PrePadding_TranslucentBasePass_Shared_Forward_488; + uint PrePadding_TranslucentBasePass_Shared_Forward_492; + float4 TranslucentBasePass_Shared_Forward_DirectionalLightStaticShadowBufferSize; + float4x4 TranslucentBasePass_Shared_Forward_DirectionalLightWorldToStaticShadow; + float PrePadding_TranslucentBasePass_Shared_ForwardISR_576; + float PrePadding_TranslucentBasePass_Shared_ForwardISR_580; + float PrePadding_TranslucentBasePass_Shared_ForwardISR_584; + float PrePadding_TranslucentBasePass_Shared_ForwardISR_588; + float PrePadding_TranslucentBasePass_Shared_ForwardISR_592; + float PrePadding_TranslucentBasePass_Shared_ForwardISR_596; + float PrePadding_TranslucentBasePass_Shared_ForwardISR_600; + float PrePadding_TranslucentBasePass_Shared_ForwardISR_604; + float PrePadding_TranslucentBasePass_Shared_ForwardISR_608; + float PrePadding_TranslucentBasePass_Shared_ForwardISR_612; + float PrePadding_TranslucentBasePass_Shared_ForwardISR_616; + float PrePadding_TranslucentBasePass_Shared_ForwardISR_620; + float PrePadding_TranslucentBasePass_Shared_ForwardISR_624; + float PrePadding_TranslucentBasePass_Shared_ForwardISR_628; + float PrePadding_TranslucentBasePass_Shared_ForwardISR_632; + float PrePadding_TranslucentBasePass_Shared_ForwardISR_636; + uint TranslucentBasePass_Shared_ForwardISR_NumLocalLights; + uint TranslucentBasePass_Shared_ForwardISR_NumReflectionCaptures; + uint TranslucentBasePass_Shared_ForwardISR_HasDirectionalLight; + uint TranslucentBasePass_Shared_ForwardISR_NumGridCells; + packed_int3 TranslucentBasePass_Shared_ForwardISR_CulledGridSize; + uint TranslucentBasePass_Shared_ForwardISR_MaxCulledLightsPerCell; + uint TranslucentBasePass_Shared_ForwardISR_LightGridPixelSizeShift; + uint PrePadding_TranslucentBasePass_Shared_ForwardISR_676; + uint PrePadding_TranslucentBasePass_Shared_ForwardISR_680; + uint PrePadding_TranslucentBasePass_Shared_ForwardISR_684; + packed_float3 TranslucentBasePass_Shared_ForwardISR_LightGridZParams; + float PrePadding_TranslucentBasePass_Shared_ForwardISR_700; + packed_float3 TranslucentBasePass_Shared_ForwardISR_DirectionalLightDirection; + float PrePadding_TranslucentBasePass_Shared_ForwardISR_716; + packed_float3 TranslucentBasePass_Shared_ForwardISR_DirectionalLightColor; + float TranslucentBasePass_Shared_ForwardISR_DirectionalLightVolumetricScatteringIntensity; + uint TranslucentBasePass_Shared_ForwardISR_DirectionalLightShadowMapChannelMask; + uint PrePadding_TranslucentBasePass_Shared_ForwardISR_740; + float2 TranslucentBasePass_Shared_ForwardISR_DirectionalLightDistanceFadeMAD; + uint TranslucentBasePass_Shared_ForwardISR_NumDirectionalLightCascades; + uint PrePadding_TranslucentBasePass_Shared_ForwardISR_756; + uint PrePadding_TranslucentBasePass_Shared_ForwardISR_760; + uint PrePadding_TranslucentBasePass_Shared_ForwardISR_764; + float4 TranslucentBasePass_Shared_ForwardISR_CascadeEndDepths; + float4x4 TranslucentBasePass_Shared_ForwardISR_DirectionalLightWorldToShadowMatrix[4]; + float4 TranslucentBasePass_Shared_ForwardISR_DirectionalLightShadowmapMinMax[4]; + float4 TranslucentBasePass_Shared_ForwardISR_DirectionalLightShadowmapAtlasBufferSize; + float TranslucentBasePass_Shared_ForwardISR_DirectionalLightDepthBias; + uint TranslucentBasePass_Shared_ForwardISR_DirectionalLightUseStaticShadowing; + uint PrePadding_TranslucentBasePass_Shared_ForwardISR_1128; + uint PrePadding_TranslucentBasePass_Shared_ForwardISR_1132; + float4 TranslucentBasePass_Shared_ForwardISR_DirectionalLightStaticShadowBufferSize; + float4x4 TranslucentBasePass_Shared_ForwardISR_DirectionalLightWorldToStaticShadow; + float PrePadding_TranslucentBasePass_Shared_Reflection_1216; + float PrePadding_TranslucentBasePass_Shared_Reflection_1220; + float PrePadding_TranslucentBasePass_Shared_Reflection_1224; + float PrePadding_TranslucentBasePass_Shared_Reflection_1228; + float PrePadding_TranslucentBasePass_Shared_Reflection_1232; + float PrePadding_TranslucentBasePass_Shared_Reflection_1236; + float PrePadding_TranslucentBasePass_Shared_Reflection_1240; + float PrePadding_TranslucentBasePass_Shared_Reflection_1244; + float PrePadding_TranslucentBasePass_Shared_Reflection_1248; + float PrePadding_TranslucentBasePass_Shared_Reflection_1252; + float PrePadding_TranslucentBasePass_Shared_Reflection_1256; + float PrePadding_TranslucentBasePass_Shared_Reflection_1260; + float PrePadding_TranslucentBasePass_Shared_Reflection_1264; + float PrePadding_TranslucentBasePass_Shared_Reflection_1268; + float PrePadding_TranslucentBasePass_Shared_Reflection_1272; + float PrePadding_TranslucentBasePass_Shared_Reflection_1276; + float4 TranslucentBasePass_Shared_Reflection_SkyLightParameters; + float TranslucentBasePass_Shared_Reflection_SkyLightCubemapBrightness; + float PrePadding_TranslucentBasePass_Shared_PlanarReflection_1300; + float PrePadding_TranslucentBasePass_Shared_PlanarReflection_1304; + float PrePadding_TranslucentBasePass_Shared_PlanarReflection_1308; + float PrePadding_TranslucentBasePass_Shared_PlanarReflection_1312; + float PrePadding_TranslucentBasePass_Shared_PlanarReflection_1316; + float PrePadding_TranslucentBasePass_Shared_PlanarReflection_1320; + float PrePadding_TranslucentBasePass_Shared_PlanarReflection_1324; + float PrePadding_TranslucentBasePass_Shared_PlanarReflection_1328; + float PrePadding_TranslucentBasePass_Shared_PlanarReflection_1332; + float PrePadding_TranslucentBasePass_Shared_PlanarReflection_1336; + float PrePadding_TranslucentBasePass_Shared_PlanarReflection_1340; + float PrePadding_TranslucentBasePass_Shared_PlanarReflection_1344; + float PrePadding_TranslucentBasePass_Shared_PlanarReflection_1348; + float PrePadding_TranslucentBasePass_Shared_PlanarReflection_1352; + float PrePadding_TranslucentBasePass_Shared_PlanarReflection_1356; + float4 TranslucentBasePass_Shared_PlanarReflection_ReflectionPlane; + float4 TranslucentBasePass_Shared_PlanarReflection_PlanarReflectionOrigin; + float4 TranslucentBasePass_Shared_PlanarReflection_PlanarReflectionXAxis; + float4 TranslucentBasePass_Shared_PlanarReflection_PlanarReflectionYAxis; + float3x4 TranslucentBasePass_Shared_PlanarReflection_InverseTransposeMirrorMatrix; + packed_float3 TranslucentBasePass_Shared_PlanarReflection_PlanarReflectionParameters; + float PrePadding_TranslucentBasePass_Shared_PlanarReflection_1484; + float2 TranslucentBasePass_Shared_PlanarReflection_PlanarReflectionParameters2; + float PrePadding_TranslucentBasePass_Shared_PlanarReflection_1496; + float PrePadding_TranslucentBasePass_Shared_PlanarReflection_1500; + float4x4 TranslucentBasePass_Shared_PlanarReflection_ProjectionWithExtraFOV[2]; + float4 TranslucentBasePass_Shared_PlanarReflection_PlanarReflectionScreenScaleBias[2]; + float2 TranslucentBasePass_Shared_PlanarReflection_PlanarReflectionScreenBound; + uint TranslucentBasePass_Shared_PlanarReflection_bIsStereo; + float PrePadding_TranslucentBasePass_Shared_Fog_1676; + float PrePadding_TranslucentBasePass_Shared_Fog_1680; + float PrePadding_TranslucentBasePass_Shared_Fog_1684; + float PrePadding_TranslucentBasePass_Shared_Fog_1688; + float PrePadding_TranslucentBasePass_Shared_Fog_1692; + float4 TranslucentBasePass_Shared_Fog_ExponentialFogParameters; + float4 TranslucentBasePass_Shared_Fog_ExponentialFogParameters2; + float4 TranslucentBasePass_Shared_Fog_ExponentialFogColorParameter; + float4 TranslucentBasePass_Shared_Fog_ExponentialFogParameters3; + float4 TranslucentBasePass_Shared_Fog_InscatteringLightDirection; + float4 TranslucentBasePass_Shared_Fog_DirectionalInscatteringColor; + float2 TranslucentBasePass_Shared_Fog_SinCosInscatteringColorCubemapRotation; + float PrePadding_TranslucentBasePass_Shared_Fog_1800; + float PrePadding_TranslucentBasePass_Shared_Fog_1804; + packed_float3 TranslucentBasePass_Shared_Fog_FogInscatteringTextureParameters; + float TranslucentBasePass_Shared_Fog_ApplyVolumetricFog; + float PrePadding_TranslucentBasePass_1824; + float PrePadding_TranslucentBasePass_1828; + float PrePadding_TranslucentBasePass_1832; + float PrePadding_TranslucentBasePass_1836; + float PrePadding_TranslucentBasePass_1840; + float PrePadding_TranslucentBasePass_1844; + float PrePadding_TranslucentBasePass_1848; + float PrePadding_TranslucentBasePass_1852; + float PrePadding_TranslucentBasePass_1856; + float PrePadding_TranslucentBasePass_1860; + float PrePadding_TranslucentBasePass_1864; + float PrePadding_TranslucentBasePass_1868; + float PrePadding_TranslucentBasePass_1872; + float PrePadding_TranslucentBasePass_1876; + float PrePadding_TranslucentBasePass_1880; + float PrePadding_TranslucentBasePass_1884; + float PrePadding_TranslucentBasePass_1888; + float PrePadding_TranslucentBasePass_1892; + float PrePadding_TranslucentBasePass_1896; + float PrePadding_TranslucentBasePass_1900; + float PrePadding_TranslucentBasePass_1904; + float PrePadding_TranslucentBasePass_1908; + float PrePadding_TranslucentBasePass_1912; + float PrePadding_TranslucentBasePass_1916; + float PrePadding_TranslucentBasePass_1920; + float PrePadding_TranslucentBasePass_1924; + float PrePadding_TranslucentBasePass_1928; + float PrePadding_TranslucentBasePass_1932; + float PrePadding_TranslucentBasePass_1936; + float PrePadding_TranslucentBasePass_1940; + float PrePadding_TranslucentBasePass_1944; + float PrePadding_TranslucentBasePass_1948; + float PrePadding_TranslucentBasePass_1952; + float PrePadding_TranslucentBasePass_1956; + float PrePadding_TranslucentBasePass_1960; + float PrePadding_TranslucentBasePass_1964; + float PrePadding_TranslucentBasePass_1968; + float PrePadding_TranslucentBasePass_1972; + float PrePadding_TranslucentBasePass_1976; + float PrePadding_TranslucentBasePass_1980; + float PrePadding_TranslucentBasePass_1984; + float PrePadding_TranslucentBasePass_1988; + float PrePadding_TranslucentBasePass_1992; + float PrePadding_TranslucentBasePass_1996; + float PrePadding_TranslucentBasePass_2000; + float PrePadding_TranslucentBasePass_2004; + float PrePadding_TranslucentBasePass_2008; + float PrePadding_TranslucentBasePass_2012; + float PrePadding_TranslucentBasePass_2016; + float PrePadding_TranslucentBasePass_2020; + float PrePadding_TranslucentBasePass_2024; + float PrePadding_TranslucentBasePass_2028; + float PrePadding_TranslucentBasePass_2032; + float PrePadding_TranslucentBasePass_2036; + float PrePadding_TranslucentBasePass_2040; + float PrePadding_TranslucentBasePass_2044; + float PrePadding_TranslucentBasePass_2048; + float PrePadding_TranslucentBasePass_2052; + float PrePadding_TranslucentBasePass_2056; + float PrePadding_TranslucentBasePass_2060; + float PrePadding_TranslucentBasePass_2064; + float PrePadding_TranslucentBasePass_2068; + float PrePadding_TranslucentBasePass_2072; + float PrePadding_TranslucentBasePass_2076; + float PrePadding_TranslucentBasePass_2080; + float PrePadding_TranslucentBasePass_2084; + float PrePadding_TranslucentBasePass_2088; + float PrePadding_TranslucentBasePass_2092; + float PrePadding_TranslucentBasePass_2096; + float PrePadding_TranslucentBasePass_2100; + float PrePadding_TranslucentBasePass_2104; + float PrePadding_TranslucentBasePass_2108; + float PrePadding_TranslucentBasePass_2112; + float PrePadding_TranslucentBasePass_2116; + float PrePadding_TranslucentBasePass_2120; + float PrePadding_TranslucentBasePass_2124; + float PrePadding_TranslucentBasePass_2128; + float PrePadding_TranslucentBasePass_2132; + float PrePadding_TranslucentBasePass_2136; + float PrePadding_TranslucentBasePass_2140; + float4 TranslucentBasePass_HZBUvFactorAndInvFactor; + float4 TranslucentBasePass_PrevScreenPositionScaleBias; + float TranslucentBasePass_PrevSceneColorPreExposureInv; +}; + +struct type_Material +{ + float4 Material_VectorExpressions[2]; + float4 Material_ScalarExpressions[1]; +}; + +constant float _108 = {}; + +struct main0_out +{ + float4 out_var_SV_Target0 [[color(0)]]; + uint gl_SampleMask [[sample_mask]]; +}; + +struct main0_in +{ + float4 in_var_TEXCOORD10_centroid [[user(locn0)]]; + float4 in_var_TEXCOORD11_centroid [[user(locn1)]]; + uint in_var_PRIMITIVE_ID [[user(locn2)]]; + float4 in_var_TEXCOORD7 [[user(locn3)]]; +}; + +fragment main0_out main0(main0_in in [[stage_in]], constant type_View& View [[buffer(0)]], const device type_StructuredBuffer_v4float& View_PrimitiveSceneData [[buffer(1)]], constant type_TranslucentBasePass& TranslucentBasePass [[buffer(2)]], constant type_Material& Material [[buffer(3)]], texture3d TranslucentBasePass_Shared_Fog_IntegratedLightScattering [[texture(0)]], sampler View_SharedBilinearClampedSampler [[sampler(0)]], float4 gl_FragCoord [[position]], uint gl_SampleMaskIn [[sample_mask]]) +{ + main0_out out = {}; + float4 _137 = View.View_SVPositionToTranslatedWorld * float4(gl_FragCoord.xyz, 1.0); + float3 _142 = (_137.xyz / float3(_137.w)) - float3(View.View_PreViewTranslation); + bool _165 = TranslucentBasePass.TranslucentBasePass_Shared_Fog_ApplyVolumetricFog > 0.0; + float4 _215; + if (_165) + { + float4 _172 = View.View_WorldToClip * float4(_142, 1.0); + float _173 = _172.w; + float4 _202; + if (_165) + { + _202 = TranslucentBasePass_Shared_Fog_IntegratedLightScattering.sample(View_SharedBilinearClampedSampler, float3(((_172.xy / float2(_173)).xy * float2(0.5, -0.5)) + float2(0.5), (log2((_173 * View.View_VolumetricFogGridZParams[0]) + View.View_VolumetricFogGridZParams[1]) * View.View_VolumetricFogGridZParams[2]) * View.View_VolumetricFogInvGridSize[2]), level(0.0)); + } + else + { + _202 = float4(0.0, 0.0, 0.0, 1.0); + } + _215 = float4(_202.xyz + (in.in_var_TEXCOORD7.xyz * float3(_202.w)), _202.w * in.in_var_TEXCOORD7.w); + } + else + { + _215 = in.in_var_TEXCOORD7; + } + float3 _216 = fast::max(Material.Material_VectorExpressions[1].xyz * float3(((1.0 + dot(float3(-0.2857142984867095947265625, -0.4285714328289031982421875, 0.857142865657806396484375), normalize(float3x3(in.in_var_TEXCOORD10_centroid.xyz, cross(in.in_var_TEXCOORD11_centroid.xyz, in.in_var_TEXCOORD10_centroid.xyz) * float3(in.in_var_TEXCOORD11_centroid.w), in.in_var_TEXCOORD11_centroid.xyz) * normalize((float3(0.0, 0.0, 1.0) * float3(View.View_NormalOverrideParameter.w)) + View.View_NormalOverrideParameter.xyz)))) * 0.5) + 0.20000000298023223876953125), float3(0.0)); + float3 _246; + if (View.View_OutOfBoundsMask > 0.0) + { + uint _222 = in.in_var_PRIMITIVE_ID * 26u; + float3 _245; + if (any(abs(_142 - View_PrimitiveSceneData._m0[_222 + 5u].xyz) > (View_PrimitiveSceneData._m0[_222 + 19u].xyz + float3(1.0)))) + { + _245 = mix(float3(1.0, 1.0, 0.0), float3(0.0, 1.0, 1.0), select(float3(0.0), float3(1.0), float3(fract(dot(_142, float3(0.57700002193450927734375)) * 0.00200000009499490261077880859375)) > float3(0.5))); + } + else + { + _245 = _216; + } + _246 = _245; + } + else + { + _246 = _216; + } + float4 _256 = float4((_246 * float3(_215.w)) + _215.xyz, _108); + _256.w = 1.0; + float4 _268; + uint _269; + if (View.View_NumSceneColorMSAASamples > 1) + { + _268 = _256 * float4(float(View.View_NumSceneColorMSAASamples) * 0.25); + _269 = gl_SampleMaskIn & 15u; + } + else + { + _268 = _256; + _269 = gl_SampleMaskIn; + } + out.out_var_SV_Target0 = _268; + out.gl_SampleMask = _269; + return out; +} + diff --git a/third_party/spirv-cross/reference/opt/shaders-ue4/asm/frag/subpass-input.ios.framebuffer-fetch.asm.frag b/third_party/spirv-cross/reference/opt/shaders-ue4/asm/frag/subpass-input.ios.framebuffer-fetch.asm.frag new file mode 100644 index 0000000000..02cfc88294 --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders-ue4/asm/frag/subpass-input.ios.framebuffer-fetch.asm.frag @@ -0,0 +1,213 @@ +#include +#include + +using namespace metal; + +struct type_View +{ + float4x4 View_TranslatedWorldToClip; + float4x4 View_WorldToClip; + float4x4 View_TranslatedWorldToView; + float4x4 View_ViewToTranslatedWorld; + float4x4 View_TranslatedWorldToCameraView; + float4x4 View_CameraViewToTranslatedWorld; + float4x4 View_ViewToClip; + float4x4 View_ViewToClipNoAA; + float4x4 View_ClipToView; + float4x4 View_ClipToTranslatedWorld; + float4x4 View_SVPositionToTranslatedWorld; + float4x4 View_ScreenToWorld; + float4x4 View_ScreenToTranslatedWorld; + packed_float3 View_ViewForward; + float PrePadding_View_844; + packed_float3 View_ViewUp; + float PrePadding_View_860; + packed_float3 View_ViewRight; + float PrePadding_View_876; + packed_float3 View_HMDViewNoRollUp; + float PrePadding_View_892; + packed_float3 View_HMDViewNoRollRight; + float PrePadding_View_908; + float4 View_InvDeviceZToWorldZTransform; + float4 View_ScreenPositionScaleBias; + packed_float3 View_WorldCameraOrigin; + float PrePadding_View_956; + packed_float3 View_TranslatedWorldCameraOrigin; + float PrePadding_View_972; + packed_float3 View_WorldViewOrigin; + float PrePadding_View_988; + packed_float3 View_PreViewTranslation; + float PrePadding_View_1004; + float4x4 View_PrevProjection; + float4x4 View_PrevViewProj; + float4x4 View_PrevViewRotationProj; + float4x4 View_PrevViewToClip; + float4x4 View_PrevClipToView; + float4x4 View_PrevTranslatedWorldToClip; + float4x4 View_PrevTranslatedWorldToView; + float4x4 View_PrevViewToTranslatedWorld; + float4x4 View_PrevTranslatedWorldToCameraView; + float4x4 View_PrevCameraViewToTranslatedWorld; + packed_float3 View_PrevWorldCameraOrigin; + float PrePadding_View_1660; + packed_float3 View_PrevWorldViewOrigin; + float PrePadding_View_1676; + packed_float3 View_PrevPreViewTranslation; + float PrePadding_View_1692; + float4x4 View_PrevInvViewProj; + float4x4 View_PrevScreenToTranslatedWorld; + float4x4 View_ClipToPrevClip; + float4 View_TemporalAAJitter; + float4 View_GlobalClippingPlane; + float2 View_FieldOfViewWideAngles; + float2 View_PrevFieldOfViewWideAngles; + float4 View_ViewRectMin; + float4 View_ViewSizeAndInvSize; + float4 View_BufferSizeAndInvSize; + float4 View_BufferBilinearUVMinMax; + int View_NumSceneColorMSAASamples; + float View_PreExposure; + float View_OneOverPreExposure; + float PrePadding_View_2012; + float4 View_DiffuseOverrideParameter; + float4 View_SpecularOverrideParameter; + float4 View_NormalOverrideParameter; + float2 View_RoughnessOverrideParameter; + float View_PrevFrameGameTime; + float View_PrevFrameRealTime; + float View_OutOfBoundsMask; + float PrePadding_View_2084; + float PrePadding_View_2088; + float PrePadding_View_2092; + packed_float3 View_WorldCameraMovementSinceLastFrame; + float View_CullingSign; + float View_NearPlane; + float View_AdaptiveTessellationFactor; + float View_GameTime; + float View_RealTime; + float View_DeltaTime; + float View_MaterialTextureMipBias; + float View_MaterialTextureDerivativeMultiply; + uint View_Random; + uint View_FrameNumber; + uint View_StateFrameIndexMod8; + uint View_StateFrameIndex; + float View_CameraCut; + float View_UnlitViewmodeMask; + float PrePadding_View_2164; + float PrePadding_View_2168; + float PrePadding_View_2172; + float4 View_DirectionalLightColor; + packed_float3 View_DirectionalLightDirection; + float PrePadding_View_2204; + float4 View_TranslucencyLightingVolumeMin[2]; + float4 View_TranslucencyLightingVolumeInvSize[2]; + float4 View_TemporalAAParams; + float4 View_CircleDOFParams; + float View_DepthOfFieldSensorWidth; + float View_DepthOfFieldFocalDistance; + float View_DepthOfFieldScale; + float View_DepthOfFieldFocalLength; + float View_DepthOfFieldFocalRegion; + float View_DepthOfFieldNearTransitionRegion; + float View_DepthOfFieldFarTransitionRegion; + float View_MotionBlurNormalizedToPixel; + float View_bSubsurfacePostprocessEnabled; + float View_GeneralPurposeTweak; + float View_DemosaicVposOffset; + float PrePadding_View_2348; + packed_float3 View_IndirectLightingColorScale; + float View_HDR32bppEncodingMode; + packed_float3 View_AtmosphericFogSunDirection; + float View_AtmosphericFogSunPower; + float View_AtmosphericFogPower; + float View_AtmosphericFogDensityScale; + float View_AtmosphericFogDensityOffset; + float View_AtmosphericFogGroundOffset; + float View_AtmosphericFogDistanceScale; + float View_AtmosphericFogAltitudeScale; + float View_AtmosphericFogHeightScaleRayleigh; + float View_AtmosphericFogStartDistance; + float View_AtmosphericFogDistanceOffset; + float View_AtmosphericFogSunDiscScale; + uint View_AtmosphericFogRenderMask; + uint View_AtmosphericFogInscatterAltitudeSampleNum; + float4 View_AtmosphericFogSunColor; + packed_float3 View_NormalCurvatureToRoughnessScaleBias; + float View_RenderingReflectionCaptureMask; + float4 View_AmbientCubemapTint; + float View_AmbientCubemapIntensity; + float View_SkyLightParameters; + float PrePadding_View_2488; + float PrePadding_View_2492; + float4 View_SkyLightColor; + float4 View_SkyIrradianceEnvironmentMap[7]; + float View_MobilePreviewMode; + float View_HMDEyePaddingOffset; + float View_ReflectionCubemapMaxMip; + float View_ShowDecalsMask; + uint View_DistanceFieldAOSpecularOcclusionMode; + float View_IndirectCapsuleSelfShadowingIntensity; + float PrePadding_View_2648; + float PrePadding_View_2652; + packed_float3 View_ReflectionEnvironmentRoughnessMixingScaleBiasAndLargestWeight; + int View_StereoPassIndex; + float4 View_GlobalVolumeCenterAndExtent[4]; + float4 View_GlobalVolumeWorldToUVAddAndMul[4]; + float View_GlobalVolumeDimension; + float View_GlobalVolumeTexelSize; + float View_MaxGlobalDistance; + float View_bCheckerboardSubsurfaceProfileRendering; + packed_float3 View_VolumetricFogInvGridSize; + float PrePadding_View_2828; + packed_float3 View_VolumetricFogGridZParams; + float PrePadding_View_2844; + float2 View_VolumetricFogSVPosToVolumeUV; + float View_VolumetricFogMaxDistance; + float PrePadding_View_2860; + packed_float3 View_VolumetricLightmapWorldToUVScale; + float PrePadding_View_2876; + packed_float3 View_VolumetricLightmapWorldToUVAdd; + float PrePadding_View_2892; + packed_float3 View_VolumetricLightmapIndirectionTextureSize; + float View_VolumetricLightmapBrickSize; + packed_float3 View_VolumetricLightmapBrickTexelSize; + float View_StereoIPD; + float View_IndirectLightingCacheShowFlag; + float View_EyeToPixelSpreadAngle; +}; + +struct type_Globals +{ + float3 SoftTransitionScale; + float4 ShadowBufferSize; + float ShadowFadeFraction; + float ShadowSharpen; + float4 LightPositionAndInvRadius; + float4x4 ScreenToShadowMatrix; + float2 ProjectionDepthBiasParameters; + float4 ModulatedShadowColor; + float4 ShadowTileOffsetAndSize; +}; + +constant float4 _58 = {}; + +struct main0_out +{ + float4 out_var_SV_Target0 [[color(0)]]; +}; + +fragment main0_out main0(constant type_View& View [[buffer(0)]], constant type_Globals& _Globals [[buffer(1)]], float4 _gl_LastFragData [[color(0)]], texture2d ShadowDepthTexture [[texture(1)]], sampler ShadowDepthTextureSampler [[sampler(0)]], float4 gl_FragCoord [[position]]) +{ + main0_out out = {}; + float4 _67 = _gl_LastFragData; + float _68 = _67.w; + float4 _82 = _Globals.ScreenToShadowMatrix * float4((((gl_FragCoord.xy * View.View_BufferSizeAndInvSize.zw) - View.View_ScreenPositionScaleBias.wz) / View.View_ScreenPositionScaleBias.xy) * float2(_68), _68, 1.0); + float _118 = fast::clamp(((fast::clamp((ShadowDepthTexture.sample(ShadowDepthTextureSampler, (((_82.xyz / float3(_82.w)).xy * _Globals.ShadowTileOffsetAndSize.zw).xy + _Globals.ShadowTileOffsetAndSize.xy).xy, level(0.0)).xxx * float3(_Globals.SoftTransitionScale.z)) - float3((fast::min(_82.z, 0.999989986419677734375) * _Globals.SoftTransitionScale.z) - 1.0), float3(0.0), float3(1.0)).x - 0.5) * _Globals.ShadowSharpen) + 0.5, 0.0, 1.0); + float3 _127 = mix(_Globals.ModulatedShadowColor.xyz, float3(1.0), float3(mix(1.0, _118 * _118, _Globals.ShadowFadeFraction))); + float4 _129 = float4(_127.x, _127.y, _127.z, _58.w); + _129.w = 0.0; + out.out_var_SV_Target0 = _129; + return out; +} + diff --git a/third_party/spirv-cross/reference/opt/shaders-ue4/asm/frag/texture-atomics.asm.frag b/third_party/spirv-cross/reference/opt/shaders-ue4/asm/frag/texture-atomics.asm.frag new file mode 100644 index 0000000000..98cdda44d7 --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders-ue4/asm/frag/texture-atomics.asm.frag @@ -0,0 +1,121 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" +#pragma clang diagnostic ignored "-Wunused-variable" + +#include +#include +#include + +using namespace metal; + +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +struct type_StructuredBuffer_v4float +{ + float4 _m0[1]; +}; + +struct type_Globals +{ + uint2 ShadowTileListGroupSize; +}; + +constant float3 _70 = {}; + +struct main0_out +{ + float4 out_var_SV_Target0 [[color(0)]]; +}; + +struct main0_in +{ + uint in_var_TEXCOORD0 [[user(locn0)]]; +}; + +fragment main0_out main0(main0_in in [[stage_in]], const device type_StructuredBuffer_v4float& CulledObjectBoxBounds [[buffer(0)]], constant type_Globals& _Globals [[buffer(1)]], texture2d RWShadowTileNumCulledObjects [[texture(0)]], device atomic_uint* RWShadowTileNumCulledObjects_atomic [[buffer(2)]], float4 gl_FragCoord [[position]]) +{ + main0_out out = {}; + uint2 _77 = uint2(gl_FragCoord.xy); + uint _78 = _77.y; + uint _83 = _77.x; + float2 _91 = float2(float(_83), float((_Globals.ShadowTileListGroupSize.y - 1u) - _78)); + float2 _93 = float2(_Globals.ShadowTileListGroupSize); + float2 _96 = ((_91 / _93) * float2(2.0)) - float2(1.0); + float2 _100 = (((_91 + float2(1.0)) / _93) * float2(2.0)) - float2(1.0); + float3 _102 = float3(_100.x, _100.y, _70.z); + _102.z = 1.0; + uint _103 = in.in_var_TEXCOORD0 * 5u; + uint _107 = _103 + 1u; + if (all(CulledObjectBoxBounds._m0[_107].xy > _96.xy) && all(CulledObjectBoxBounds._m0[_103].xyz < _102)) + { + float _122 = _96.x; + float _123 = _96.y; + spvUnsafeArray _73; + _73[0] = float3(_122, _123, -1000.0); + float _126 = _100.x; + _73[1] = float3(_126, _123, -1000.0); + float _129 = _100.y; + _73[2] = float3(_122, _129, -1000.0); + _73[3] = float3(_126, _129, -1000.0); + _73[4] = float3(_122, _123, 1.0); + _73[5] = float3(_126, _123, 1.0); + _73[6] = float3(_122, _129, 1.0); + _73[7] = float3(_126, _129, 1.0); + float3 _155; + float3 _158; + _155 = float3(-500000.0); + _158 = float3(500000.0); + for (int _160 = 0; _160 < 8; ) + { + float3 _166 = _73[_160] - (float3(0.5) * (CulledObjectBoxBounds._m0[_103].xyz + CulledObjectBoxBounds._m0[_107].xyz)); + float3 _170 = float3(dot(_166, CulledObjectBoxBounds._m0[_103 + 2u].xyz), dot(_166, CulledObjectBoxBounds._m0[_103 + 3u].xyz), dot(_166, CulledObjectBoxBounds._m0[_103 + 4u].xyz)); + _155 = fast::max(_155, _170); + _158 = fast::min(_158, _170); + _160++; + continue; + } + if (all(_158 < float3(1.0)) && all(_155 > float3(-1.0))) + { + uint _179 = atomic_fetch_add_explicit((device atomic_uint*)&RWShadowTileNumCulledObjects_atomic[(_78 * _Globals.ShadowTileListGroupSize.x) + _83], 1u, memory_order_relaxed); + } + } + out.out_var_SV_Target0 = float4(0.0); + return out; +} + diff --git a/third_party/spirv-cross/reference/opt/shaders-ue4/asm/frag/texture-atomics.asm.graphics-robust-access.frag b/third_party/spirv-cross/reference/opt/shaders-ue4/asm/frag/texture-atomics.asm.graphics-robust-access.frag new file mode 100644 index 0000000000..aa36f6ccea --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders-ue4/asm/frag/texture-atomics.asm.graphics-robust-access.frag @@ -0,0 +1,122 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" +#pragma clang diagnostic ignored "-Wunused-variable" + +#include +#include +#include + +using namespace metal; + +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +struct type_StructuredBuffer_v4float +{ + float4 _m0[1]; +}; + +struct type_Globals +{ + uint2 ShadowTileListGroupSize; +}; + +constant float3 _70 = {}; + +struct main0_out +{ + float4 out_var_SV_Target0 [[color(0)]]; +}; + +struct main0_in +{ + uint in_var_TEXCOORD0 [[user(locn0)]]; +}; + +fragment main0_out main0(main0_in in [[stage_in]], constant uint* spvBufferSizeConstants [[buffer(25)]], const device type_StructuredBuffer_v4float& CulledObjectBoxBounds [[buffer(0)]], constant type_Globals& _Globals [[buffer(1)]], texture2d RWShadowTileNumCulledObjects [[texture(0)]], device atomic_uint* RWShadowTileNumCulledObjects_atomic [[buffer(2)]], float4 gl_FragCoord [[position]]) +{ + main0_out out = {}; + constant uint& CulledObjectBoxBoundsBufferSize = spvBufferSizeConstants[0]; + uint2 _77 = uint2(gl_FragCoord.xy); + uint _78 = _77.y; + uint _83 = _77.x; + float2 _91 = float2(float(_83), float((_Globals.ShadowTileListGroupSize.y - 1u) - _78)); + float2 _93 = float2(_Globals.ShadowTileListGroupSize); + float2 _96 = ((_91 / _93) * float2(2.0)) - float2(1.0); + float2 _100 = (((_91 + float2(1.0)) / _93) * float2(2.0)) - float2(1.0); + float3 _102 = float3(_100.x, _100.y, _70.z); + _102.z = 1.0; + uint _103 = in.in_var_TEXCOORD0 * 5u; + uint _189 = uint(clamp(int(_103 + 1u), int(0u), int(min((((CulledObjectBoxBoundsBufferSize - 0) / 16) - 1u), 2147483647u)))); + if (all(CulledObjectBoxBounds._m0[_189].xy > _96.xy) && all(CulledObjectBoxBounds._m0[uint(clamp(int(_103), int(0u), int(min((((CulledObjectBoxBoundsBufferSize - 0) / 16) - 1u), 2147483647u))))].xyz < _102)) + { + float _122 = _96.x; + float _123 = _96.y; + spvUnsafeArray _73; + _73[0] = float3(_122, _123, -1000.0); + float _126 = _100.x; + _73[1] = float3(_126, _123, -1000.0); + float _129 = _100.y; + _73[2] = float3(_122, _129, -1000.0); + _73[3] = float3(_126, _129, -1000.0); + _73[4] = float3(_122, _123, 1.0); + _73[5] = float3(_126, _123, 1.0); + _73[6] = float3(_122, _129, 1.0); + _73[7] = float3(_126, _129, 1.0); + float3 _155; + float3 _158; + _155 = float3(-500000.0); + _158 = float3(500000.0); + for (int _160 = 0; _160 < 8; ) + { + float3 _166 = _73[clamp(_160, 0, 7)] - (float3(0.5) * (CulledObjectBoxBounds._m0[uint(clamp(int(_103), int(0u), int(min((((CulledObjectBoxBoundsBufferSize - 0) / 16) - 1u), 2147483647u))))].xyz + CulledObjectBoxBounds._m0[_189].xyz)); + float3 _170 = float3(dot(_166, CulledObjectBoxBounds._m0[uint(clamp(int(_103 + 2u), int(0u), int(min((((CulledObjectBoxBoundsBufferSize - 0) / 16) - 1u), 2147483647u))))].xyz), dot(_166, CulledObjectBoxBounds._m0[uint(clamp(int(_103 + 3u), int(0u), int(min((((CulledObjectBoxBoundsBufferSize - 0) / 16) - 1u), 2147483647u))))].xyz), dot(_166, CulledObjectBoxBounds._m0[uint(clamp(int(_103 + 4u), int(0u), int(min((((CulledObjectBoxBoundsBufferSize - 0) / 16) - 1u), 2147483647u))))].xyz)); + _155 = fast::max(_155, _170); + _158 = fast::min(_158, _170); + _160++; + continue; + } + if (all(_158 < float3(1.0)) && all(_155 > float3(-1.0))) + { + uint _179 = atomic_fetch_add_explicit((device atomic_uint*)&RWShadowTileNumCulledObjects_atomic[(_78 * _Globals.ShadowTileListGroupSize.x) + _83], 1u, memory_order_relaxed); + } + } + out.out_var_SV_Target0 = float4(0.0); + return out; +} + diff --git a/third_party/spirv-cross/reference/opt/shaders-ue4/asm/tesc/hs-incorrect-base-type.asm.tesc b/third_party/spirv-cross/reference/opt/shaders-ue4/asm/tesc/hs-incorrect-base-type.asm.tesc new file mode 100644 index 0000000000..ec5d9960f9 --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders-ue4/asm/tesc/hs-incorrect-base-type.asm.tesc @@ -0,0 +1,399 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + +#include +#include + +using namespace metal; + +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +struct FVertexFactoryInterpolantsVSToPS +{ + float4 TangentToWorld0; + float4 TangentToWorld2; + float4 Color; + spvUnsafeArray TexCoords; + float4 LightMapCoordinate; + uint PrimitiveId; + uint LightmapDataIndex; +}; + +struct FVertexFactoryInterpolantsVSToDS +{ + FVertexFactoryInterpolantsVSToPS InterpolantsVSToPS; +}; + +struct FSharedBasePassInterpolants +{ +}; +struct FBasePassInterpolantsVSToDS +{ + FSharedBasePassInterpolants _m0; +}; + +struct FBasePassVSToDS +{ + FVertexFactoryInterpolantsVSToDS FactoryInterpolants; + FBasePassInterpolantsVSToDS BasePassInterpolants; + float4 Position; +}; + +struct FPNTessellationHSToDS +{ + FBasePassVSToDS PassSpecificData; + spvUnsafeArray WorldPosition; + float3 DisplacementScale; + float TessellationMultiplier; + float WorldDisplacementMultiplier; +}; + +struct type_View +{ + float4x4 View_TranslatedWorldToClip; + float4x4 View_WorldToClip; + float4x4 View_TranslatedWorldToView; + float4x4 View_ViewToTranslatedWorld; + float4x4 View_TranslatedWorldToCameraView; + float4x4 View_CameraViewToTranslatedWorld; + float4x4 View_ViewToClip; + float4x4 View_ViewToClipNoAA; + float4x4 View_ClipToView; + float4x4 View_ClipToTranslatedWorld; + float4x4 View_SVPositionToTranslatedWorld; + float4x4 View_ScreenToWorld; + float4x4 View_ScreenToTranslatedWorld; + packed_float3 View_ViewForward; + float PrePadding_View_844; + packed_float3 View_ViewUp; + float PrePadding_View_860; + packed_float3 View_ViewRight; + float PrePadding_View_876; + packed_float3 View_HMDViewNoRollUp; + float PrePadding_View_892; + packed_float3 View_HMDViewNoRollRight; + float PrePadding_View_908; + float4 View_InvDeviceZToWorldZTransform; + float4 View_ScreenPositionScaleBias; + packed_float3 View_WorldCameraOrigin; + float PrePadding_View_956; + packed_float3 View_TranslatedWorldCameraOrigin; + float PrePadding_View_972; + packed_float3 View_WorldViewOrigin; + float PrePadding_View_988; + packed_float3 View_PreViewTranslation; + float PrePadding_View_1004; + float4x4 View_PrevProjection; + float4x4 View_PrevViewProj; + float4x4 View_PrevViewRotationProj; + float4x4 View_PrevViewToClip; + float4x4 View_PrevClipToView; + float4x4 View_PrevTranslatedWorldToClip; + float4x4 View_PrevTranslatedWorldToView; + float4x4 View_PrevViewToTranslatedWorld; + float4x4 View_PrevTranslatedWorldToCameraView; + float4x4 View_PrevCameraViewToTranslatedWorld; + packed_float3 View_PrevWorldCameraOrigin; + float PrePadding_View_1660; + packed_float3 View_PrevWorldViewOrigin; + float PrePadding_View_1676; + packed_float3 View_PrevPreViewTranslation; + float PrePadding_View_1692; + float4x4 View_PrevInvViewProj; + float4x4 View_PrevScreenToTranslatedWorld; + float4x4 View_ClipToPrevClip; + float4 View_TemporalAAJitter; + float4 View_GlobalClippingPlane; + float2 View_FieldOfViewWideAngles; + float2 View_PrevFieldOfViewWideAngles; + float4 View_ViewRectMin; + float4 View_ViewSizeAndInvSize; + float4 View_BufferSizeAndInvSize; + float4 View_BufferBilinearUVMinMax; + int View_NumSceneColorMSAASamples; + float View_PreExposure; + float View_OneOverPreExposure; + float PrePadding_View_2012; + float4 View_DiffuseOverrideParameter; + float4 View_SpecularOverrideParameter; + float4 View_NormalOverrideParameter; + float2 View_RoughnessOverrideParameter; + float View_PrevFrameGameTime; + float View_PrevFrameRealTime; + float View_OutOfBoundsMask; + float PrePadding_View_2084; + float PrePadding_View_2088; + float PrePadding_View_2092; + packed_float3 View_WorldCameraMovementSinceLastFrame; + float View_CullingSign; + float View_NearPlane; + float View_AdaptiveTessellationFactor; + float View_GameTime; + float View_RealTime; + float View_DeltaTime; + float View_MaterialTextureMipBias; + float View_MaterialTextureDerivativeMultiply; + uint View_Random; + uint View_FrameNumber; + uint View_StateFrameIndexMod8; + uint View_StateFrameIndex; + float View_CameraCut; + float View_UnlitViewmodeMask; + float PrePadding_View_2164; + float PrePadding_View_2168; + float PrePadding_View_2172; + float4 View_DirectionalLightColor; + packed_float3 View_DirectionalLightDirection; + float PrePadding_View_2204; + float4 View_TranslucencyLightingVolumeMin[2]; + float4 View_TranslucencyLightingVolumeInvSize[2]; + float4 View_TemporalAAParams; + float4 View_CircleDOFParams; + float View_DepthOfFieldSensorWidth; + float View_DepthOfFieldFocalDistance; + float View_DepthOfFieldScale; + float View_DepthOfFieldFocalLength; + float View_DepthOfFieldFocalRegion; + float View_DepthOfFieldNearTransitionRegion; + float View_DepthOfFieldFarTransitionRegion; + float View_MotionBlurNormalizedToPixel; + float View_bSubsurfacePostprocessEnabled; + float View_GeneralPurposeTweak; + float View_DemosaicVposOffset; + float PrePadding_View_2348; + packed_float3 View_IndirectLightingColorScale; + float View_HDR32bppEncodingMode; + packed_float3 View_AtmosphericFogSunDirection; + float View_AtmosphericFogSunPower; + float View_AtmosphericFogPower; + float View_AtmosphericFogDensityScale; + float View_AtmosphericFogDensityOffset; + float View_AtmosphericFogGroundOffset; + float View_AtmosphericFogDistanceScale; + float View_AtmosphericFogAltitudeScale; + float View_AtmosphericFogHeightScaleRayleigh; + float View_AtmosphericFogStartDistance; + float View_AtmosphericFogDistanceOffset; + float View_AtmosphericFogSunDiscScale; + uint View_AtmosphericFogRenderMask; + uint View_AtmosphericFogInscatterAltitudeSampleNum; + float4 View_AtmosphericFogSunColor; + packed_float3 View_NormalCurvatureToRoughnessScaleBias; + float View_RenderingReflectionCaptureMask; + float4 View_AmbientCubemapTint; + float View_AmbientCubemapIntensity; + float View_SkyLightParameters; + float PrePadding_View_2488; + float PrePadding_View_2492; + float4 View_SkyLightColor; + float4 View_SkyIrradianceEnvironmentMap[7]; + float View_MobilePreviewMode; + float View_HMDEyePaddingOffset; + float View_ReflectionCubemapMaxMip; + float View_ShowDecalsMask; + uint View_DistanceFieldAOSpecularOcclusionMode; + float View_IndirectCapsuleSelfShadowingIntensity; + float PrePadding_View_2648; + float PrePadding_View_2652; + packed_float3 View_ReflectionEnvironmentRoughnessMixingScaleBiasAndLargestWeight; + int View_StereoPassIndex; + float4 View_GlobalVolumeCenterAndExtent[4]; + float4 View_GlobalVolumeWorldToUVAddAndMul[4]; + float View_GlobalVolumeDimension; + float View_GlobalVolumeTexelSize; + float View_MaxGlobalDistance; + float View_bCheckerboardSubsurfaceProfileRendering; + packed_float3 View_VolumetricFogInvGridSize; + float PrePadding_View_2828; + packed_float3 View_VolumetricFogGridZParams; + float PrePadding_View_2844; + float2 View_VolumetricFogSVPosToVolumeUV; + float View_VolumetricFogMaxDistance; + float PrePadding_View_2860; + packed_float3 View_VolumetricLightmapWorldToUVScale; + float PrePadding_View_2876; + packed_float3 View_VolumetricLightmapWorldToUVAdd; + float PrePadding_View_2892; + packed_float3 View_VolumetricLightmapIndirectionTextureSize; + float View_VolumetricLightmapBrickSize; + packed_float3 View_VolumetricLightmapBrickTexelSize; + float View_StereoIPD; + float View_IndirectLightingCacheShowFlag; + float View_EyeToPixelSpreadAngle; +}; + +struct type_StructuredBuffer_v4float +{ + float4 _m0[1]; +}; + +constant float4 _602 = {}; + +struct main0_out +{ + float4 out_var_COLOR0; + uint out_var_LIGHTMAP_ID; + float3 out_var_PN_DisplacementScales; + spvUnsafeArray out_var_PN_POSITION; + float out_var_PN_TessellationMultiplier; + float out_var_PN_WorldDisplacementMultiplier; + uint out_var_PRIMITIVE_ID; + spvUnsafeArray out_var_TEXCOORD0; + float4 out_var_TEXCOORD10_centroid; + float4 out_var_TEXCOORD11_centroid; + float4 out_var_TEXCOORD4; + float4 out_var_VS_To_DS_Position; +}; + +struct main0_patchOut +{ + float4 out_var_PN_POSITION9; +}; + +struct main0_in +{ + float4 in_var_TEXCOORD10_centroid [[attribute(0)]]; + float4 in_var_TEXCOORD11_centroid [[attribute(1)]]; + float4 in_var_COLOR0 [[attribute(2)]]; + float4 in_var_TEXCOORD0_0 [[attribute(3)]]; + float4 in_var_TEXCOORD4 [[attribute(4)]]; + uint in_var_PRIMITIVE_ID [[attribute(5)]]; + uint in_var_LIGHTMAP_ID [[attribute(6)]]; + float4 in_var_VS_To_DS_Position [[attribute(7)]]; +}; + +kernel void main0(main0_in in [[stage_in]], constant type_View& View [[buffer(0)]], const device type_StructuredBuffer_v4float& View_PrimitiveSceneData [[buffer(1)]], uint gl_InvocationID [[thread_index_in_threadgroup]], uint gl_PrimitiveID [[threadgroup_position_in_grid]], device main0_out* spvOut [[buffer(28)]], constant uint* spvIndirectParams [[buffer(29)]], device main0_patchOut* spvPatchOut [[buffer(27)]], device MTLTriangleTessellationFactorsHalf* spvTessLevel [[buffer(26)]], threadgroup main0_in* gl_in [[threadgroup(0)]]) +{ + threadgroup FPNTessellationHSToDS temp_var_hullMainRetVal[3]; + device main0_out* gl_out = &spvOut[gl_PrimitiveID * 3]; + device main0_patchOut& patchOut = spvPatchOut[gl_PrimitiveID]; + if (gl_InvocationID < spvIndirectParams[0]) + gl_in[gl_InvocationID] = in; + threadgroup_barrier(mem_flags::mem_threadgroup); + if (gl_InvocationID >= 3) + return; + spvUnsafeArray _144 = spvUnsafeArray({ gl_in[0].in_var_TEXCOORD10_centroid, gl_in[1].in_var_TEXCOORD10_centroid, gl_in[2].in_var_TEXCOORD10_centroid, gl_in[3].in_var_TEXCOORD10_centroid, gl_in[4].in_var_TEXCOORD10_centroid, gl_in[5].in_var_TEXCOORD10_centroid, gl_in[6].in_var_TEXCOORD10_centroid, gl_in[7].in_var_TEXCOORD10_centroid, gl_in[8].in_var_TEXCOORD10_centroid, gl_in[9].in_var_TEXCOORD10_centroid, gl_in[10].in_var_TEXCOORD10_centroid, gl_in[11].in_var_TEXCOORD10_centroid }); + spvUnsafeArray _145 = spvUnsafeArray({ gl_in[0].in_var_TEXCOORD11_centroid, gl_in[1].in_var_TEXCOORD11_centroid, gl_in[2].in_var_TEXCOORD11_centroid, gl_in[3].in_var_TEXCOORD11_centroid, gl_in[4].in_var_TEXCOORD11_centroid, gl_in[5].in_var_TEXCOORD11_centroid, gl_in[6].in_var_TEXCOORD11_centroid, gl_in[7].in_var_TEXCOORD11_centroid, gl_in[8].in_var_TEXCOORD11_centroid, gl_in[9].in_var_TEXCOORD11_centroid, gl_in[10].in_var_TEXCOORD11_centroid, gl_in[11].in_var_TEXCOORD11_centroid }); + spvUnsafeArray _146 = spvUnsafeArray({ gl_in[0].in_var_COLOR0, gl_in[1].in_var_COLOR0, gl_in[2].in_var_COLOR0, gl_in[3].in_var_COLOR0, gl_in[4].in_var_COLOR0, gl_in[5].in_var_COLOR0, gl_in[6].in_var_COLOR0, gl_in[7].in_var_COLOR0, gl_in[8].in_var_COLOR0, gl_in[9].in_var_COLOR0, gl_in[10].in_var_COLOR0, gl_in[11].in_var_COLOR0 }); + spvUnsafeArray, 12> _147 = spvUnsafeArray, 12>({ spvUnsafeArray({ gl_in[0].in_var_TEXCOORD0_0 }), spvUnsafeArray({ gl_in[1].in_var_TEXCOORD0_0 }), spvUnsafeArray({ gl_in[2].in_var_TEXCOORD0_0 }), spvUnsafeArray({ gl_in[3].in_var_TEXCOORD0_0 }), spvUnsafeArray({ gl_in[4].in_var_TEXCOORD0_0 }), spvUnsafeArray({ gl_in[5].in_var_TEXCOORD0_0 }), spvUnsafeArray({ gl_in[6].in_var_TEXCOORD0_0 }), spvUnsafeArray({ gl_in[7].in_var_TEXCOORD0_0 }), spvUnsafeArray({ gl_in[8].in_var_TEXCOORD0_0 }), spvUnsafeArray({ gl_in[9].in_var_TEXCOORD0_0 }), spvUnsafeArray({ gl_in[10].in_var_TEXCOORD0_0 }), spvUnsafeArray({ gl_in[11].in_var_TEXCOORD0_0 }) }); + spvUnsafeArray _148 = spvUnsafeArray({ gl_in[0].in_var_TEXCOORD4, gl_in[1].in_var_TEXCOORD4, gl_in[2].in_var_TEXCOORD4, gl_in[3].in_var_TEXCOORD4, gl_in[4].in_var_TEXCOORD4, gl_in[5].in_var_TEXCOORD4, gl_in[6].in_var_TEXCOORD4, gl_in[7].in_var_TEXCOORD4, gl_in[8].in_var_TEXCOORD4, gl_in[9].in_var_TEXCOORD4, gl_in[10].in_var_TEXCOORD4, gl_in[11].in_var_TEXCOORD4 }); + spvUnsafeArray _149 = spvUnsafeArray({ gl_in[0].in_var_PRIMITIVE_ID, gl_in[1].in_var_PRIMITIVE_ID, gl_in[2].in_var_PRIMITIVE_ID, gl_in[3].in_var_PRIMITIVE_ID, gl_in[4].in_var_PRIMITIVE_ID, gl_in[5].in_var_PRIMITIVE_ID, gl_in[6].in_var_PRIMITIVE_ID, gl_in[7].in_var_PRIMITIVE_ID, gl_in[8].in_var_PRIMITIVE_ID, gl_in[9].in_var_PRIMITIVE_ID, gl_in[10].in_var_PRIMITIVE_ID, gl_in[11].in_var_PRIMITIVE_ID }); + spvUnsafeArray _150 = spvUnsafeArray({ gl_in[0].in_var_LIGHTMAP_ID, gl_in[1].in_var_LIGHTMAP_ID, gl_in[2].in_var_LIGHTMAP_ID, gl_in[3].in_var_LIGHTMAP_ID, gl_in[4].in_var_LIGHTMAP_ID, gl_in[5].in_var_LIGHTMAP_ID, gl_in[6].in_var_LIGHTMAP_ID, gl_in[7].in_var_LIGHTMAP_ID, gl_in[8].in_var_LIGHTMAP_ID, gl_in[9].in_var_LIGHTMAP_ID, gl_in[10].in_var_LIGHTMAP_ID, gl_in[11].in_var_LIGHTMAP_ID }); + spvUnsafeArray _259 = spvUnsafeArray({ gl_in[0].in_var_VS_To_DS_Position, gl_in[1].in_var_VS_To_DS_Position, gl_in[2].in_var_VS_To_DS_Position, gl_in[3].in_var_VS_To_DS_Position, gl_in[4].in_var_VS_To_DS_Position, gl_in[5].in_var_VS_To_DS_Position, gl_in[6].in_var_VS_To_DS_Position, gl_in[7].in_var_VS_To_DS_Position, gl_in[8].in_var_VS_To_DS_Position, gl_in[9].in_var_VS_To_DS_Position, gl_in[10].in_var_VS_To_DS_Position, gl_in[11].in_var_VS_To_DS_Position }); + spvUnsafeArray _284 = spvUnsafeArray({ FBasePassVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _144[0], _145[0], _146[0], _147[0], _148[0], _149[0], _150[0] } }, FBasePassInterpolantsVSToDS{ { } }, _259[0] }, FBasePassVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _144[1], _145[1], _146[1], _147[1], _148[1], _149[1], _150[1] } }, FBasePassInterpolantsVSToDS{ { } }, _259[1] }, FBasePassVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _144[2], _145[2], _146[2], _147[2], _148[2], _149[2], _150[2] } }, FBasePassInterpolantsVSToDS{ { } }, _259[2] }, FBasePassVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _144[3], _145[3], _146[3], _147[3], _148[3], _149[3], _150[3] } }, FBasePassInterpolantsVSToDS{ { } }, _259[3] }, FBasePassVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _144[4], _145[4], _146[4], _147[4], _148[4], _149[4], _150[4] } }, FBasePassInterpolantsVSToDS{ { } }, _259[4] }, FBasePassVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _144[5], _145[5], _146[5], _147[5], _148[5], _149[5], _150[5] } }, FBasePassInterpolantsVSToDS{ { } }, _259[5] }, FBasePassVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _144[6], _145[6], _146[6], _147[6], _148[6], _149[6], _150[6] } }, FBasePassInterpolantsVSToDS{ { } }, _259[6] }, FBasePassVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _144[7], _145[7], _146[7], _147[7], _148[7], _149[7], _150[7] } }, FBasePassInterpolantsVSToDS{ { } }, _259[7] }, FBasePassVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _144[8], _145[8], _146[8], _147[8], _148[8], _149[8], _150[8] } }, FBasePassInterpolantsVSToDS{ { } }, _259[8] }, FBasePassVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _144[9], _145[9], _146[9], _147[9], _148[9], _149[9], _150[9] } }, FBasePassInterpolantsVSToDS{ { } }, _259[9] }, FBasePassVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _144[10], _145[10], _146[10], _147[10], _148[10], _149[10], _150[10] } }, FBasePassInterpolantsVSToDS{ { } }, _259[10] }, FBasePassVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _144[11], _145[11], _146[11], _147[11], _148[11], _149[11], _150[11] } }, FBasePassInterpolantsVSToDS{ { } }, _259[11] } }); + spvUnsafeArray param_var_I; + param_var_I = _284; + float4 _301 = float4(param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld2.xyz, 0.0); + float3 _310 = View_PrimitiveSceneData._m0[(param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.PrimitiveId * 26u) + 22u].xyz * float3x3(param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld0.xyz, cross(param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld2.xyz, param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld0.xyz) * float3(param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld2.w), param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld2.xyz); + uint _313 = (gl_InvocationID < 2u) ? (gl_InvocationID + 1u) : 0u; + uint _314 = 2u * gl_InvocationID; + uint _315 = 3u + _314; + uint _316 = _314 + 4u; + float4 _328 = float4(param_var_I[_313].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld2.xyz, 0.0); + float4 _336 = float4(param_var_I[_315].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld2.xyz, 0.0); + float4 _344 = float4(param_var_I[_316].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld2.xyz, 0.0); + spvUnsafeArray _392 = spvUnsafeArray({ param_var_I[gl_InvocationID].Position, ((((float4(2.0) * param_var_I[gl_InvocationID].Position) + param_var_I[_313].Position) - (float4(dot(param_var_I[_313].Position - param_var_I[gl_InvocationID].Position, _301)) * _301)) + (((float4(2.0) * param_var_I[_315].Position) + param_var_I[_316].Position) - (float4(dot(param_var_I[_316].Position - param_var_I[_315].Position, _336)) * _336))) * float4(0.16666667163372039794921875), ((((float4(2.0) * param_var_I[_313].Position) + param_var_I[gl_InvocationID].Position) - (float4(dot(param_var_I[gl_InvocationID].Position - param_var_I[_313].Position, _328)) * _328)) + (((float4(2.0) * param_var_I[_316].Position) + param_var_I[_315].Position) - (float4(dot(param_var_I[_315].Position - param_var_I[_316].Position, _344)) * _344))) * float4(0.16666667163372039794921875) }); + gl_out[gl_InvocationID].out_var_TEXCOORD10_centroid = param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld0; + gl_out[gl_InvocationID].out_var_TEXCOORD11_centroid = param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld2; + gl_out[gl_InvocationID].out_var_COLOR0 = param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.Color; + gl_out[gl_InvocationID].out_var_TEXCOORD0 = param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TexCoords; + gl_out[gl_InvocationID].out_var_TEXCOORD4 = param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.LightMapCoordinate; + gl_out[gl_InvocationID].out_var_PRIMITIVE_ID = param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.PrimitiveId; + gl_out[gl_InvocationID].out_var_LIGHTMAP_ID = param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.LightmapDataIndex; + gl_out[gl_InvocationID].out_var_VS_To_DS_Position = param_var_I[gl_InvocationID].Position; + gl_out[gl_InvocationID].out_var_PN_POSITION = _392; + gl_out[gl_InvocationID].out_var_PN_DisplacementScales = _310; + gl_out[gl_InvocationID].out_var_PN_TessellationMultiplier = 1.0; + gl_out[gl_InvocationID].out_var_PN_WorldDisplacementMultiplier = 1.0; + temp_var_hullMainRetVal[gl_InvocationID] = FPNTessellationHSToDS{ param_var_I[gl_InvocationID], _392, _310, 1.0, 1.0 }; + threadgroup_barrier(mem_flags::mem_device | mem_flags::mem_threadgroup); + if (gl_InvocationID == 0u) + { + float4 _450 = (((((temp_var_hullMainRetVal[0u].WorldPosition[1] + temp_var_hullMainRetVal[0u].WorldPosition[2]) + temp_var_hullMainRetVal[1u].WorldPosition[1]) + temp_var_hullMainRetVal[1u].WorldPosition[2]) + temp_var_hullMainRetVal[2u].WorldPosition[1]) + temp_var_hullMainRetVal[2u].WorldPosition[2]) * float4(0.16666667163372039794921875); + float4 _463 = _602; + _463.x = 0.5 * (temp_var_hullMainRetVal[1u].TessellationMultiplier + temp_var_hullMainRetVal[2u].TessellationMultiplier); + float4 _469 = _463; + _469.y = 0.5 * (temp_var_hullMainRetVal[2u].TessellationMultiplier + temp_var_hullMainRetVal[0u].TessellationMultiplier); + float4 _474 = _469; + _474.z = 0.5 * (temp_var_hullMainRetVal[0u].TessellationMultiplier + temp_var_hullMainRetVal[1u].TessellationMultiplier); + float4 _481 = _474; + _481.w = 0.333000004291534423828125 * ((temp_var_hullMainRetVal[0u].TessellationMultiplier + temp_var_hullMainRetVal[1u].TessellationMultiplier) + temp_var_hullMainRetVal[2u].TessellationMultiplier); + float4 _589; + for (;;) + { + float4 _489 = View.View_ViewToClip * float4(0.0); + float4 _494 = View.View_TranslatedWorldToClip * float4(temp_var_hullMainRetVal[0u].WorldPosition[0].xyz, 1.0); + float3 _495 = _494.xyz; + float3 _496 = _489.xyz; + float _498 = _494.w; + float _499 = _489.w; + float4 _516 = View.View_TranslatedWorldToClip * float4(temp_var_hullMainRetVal[1u].WorldPosition[0].xyz, 1.0); + float3 _517 = _516.xyz; + float _519 = _516.w; + float4 _537 = View.View_TranslatedWorldToClip * float4(temp_var_hullMainRetVal[2u].WorldPosition[0].xyz, 1.0); + float3 _538 = _537.xyz; + float _540 = _537.w; + if (any((((select(int3(0), int3(1), (_495 - _496) < float3(_498 + _499)) + (int3(2) * select(int3(0), int3(1), (_495 + _496) > float3((-_498) - _499)))) | (select(int3(0), int3(1), (_517 - _496) < float3(_519 + _499)) + (int3(2) * select(int3(0), int3(1), (_517 + _496) > float3((-_519) - _499))))) | (select(int3(0), int3(1), (_538 - _496) < float3(_540 + _499)) + (int3(2) * select(int3(0), int3(1), (_538 + _496) > float3((-_540) - _499))))) != int3(3))) + { + _589 = float4(0.0); + break; + } + float3 _558 = temp_var_hullMainRetVal[0u].WorldPosition[0].xyz - temp_var_hullMainRetVal[1u].WorldPosition[0].xyz; + float3 _559 = temp_var_hullMainRetVal[1u].WorldPosition[0].xyz - temp_var_hullMainRetVal[2u].WorldPosition[0].xyz; + float3 _560 = temp_var_hullMainRetVal[2u].WorldPosition[0].xyz - temp_var_hullMainRetVal[0u].WorldPosition[0].xyz; + float3 _563 = (float3(0.5) * (temp_var_hullMainRetVal[0u].WorldPosition[0].xyz + temp_var_hullMainRetVal[1u].WorldPosition[0].xyz)) - float3(View.View_TranslatedWorldCameraOrigin); + float3 _566 = (float3(0.5) * (temp_var_hullMainRetVal[1u].WorldPosition[0].xyz + temp_var_hullMainRetVal[2u].WorldPosition[0].xyz)) - float3(View.View_TranslatedWorldCameraOrigin); + float3 _569 = (float3(0.5) * (temp_var_hullMainRetVal[2u].WorldPosition[0].xyz + temp_var_hullMainRetVal[0u].WorldPosition[0].xyz)) - float3(View.View_TranslatedWorldCameraOrigin); + float _573 = sqrt(dot(_559, _559) / dot(_566, _566)); + float _577 = sqrt(dot(_560, _560) / dot(_569, _569)); + float _581 = sqrt(dot(_558, _558) / dot(_563, _563)); + float4 _586 = float4(_573, _577, _581, 1.0); + _586.w = 0.333000004291534423828125 * ((_573 + _577) + _581); + _589 = float4(View.View_AdaptiveTessellationFactor) * _586; + break; + } + float4 _591 = fast::clamp(_481 * _589, float4(1.0), float4(15.0)); + spvTessLevel[gl_PrimitiveID].edgeTessellationFactor[0u] = half(_591.x); + spvTessLevel[gl_PrimitiveID].edgeTessellationFactor[1u] = half(_591.y); + spvTessLevel[gl_PrimitiveID].edgeTessellationFactor[2u] = half(_591.z); + spvTessLevel[gl_PrimitiveID].insideTessellationFactor = half(_591.w); + patchOut.out_var_PN_POSITION9 = _450 + ((_450 - (((temp_var_hullMainRetVal[2u].WorldPosition[0] + temp_var_hullMainRetVal[1u].WorldPosition[0]) + temp_var_hullMainRetVal[0u].WorldPosition[0]) * float4(0.3333333432674407958984375))) * float4(0.5)); + } +} + diff --git a/third_party/spirv-cross/reference/opt/shaders-ue4/asm/tesc/hs-input-array-access.asm.tesc b/third_party/spirv-cross/reference/opt/shaders-ue4/asm/tesc/hs-input-array-access.asm.tesc new file mode 100644 index 0000000000..848aa9ab61 --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders-ue4/asm/tesc/hs-input-array-access.asm.tesc @@ -0,0 +1,467 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + +#include +#include + +using namespace metal; + +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +struct FVertexFactoryInterpolantsVSToPS +{ + float4 TangentToWorld0; + float4 TangentToWorld2; +}; + +struct FVertexFactoryInterpolantsVSToDS +{ + FVertexFactoryInterpolantsVSToPS InterpolantsVSToPS; +}; + +struct FHitProxyVSToDS +{ + FVertexFactoryInterpolantsVSToDS FactoryInterpolants; + float4 Position; + uint VertexID; +}; + +struct FHullShaderConstantDominantVertexData +{ + float2 UV; + float4 Normal; + float3 Tangent; +}; + +struct FHullShaderConstantDominantEdgeData +{ + float2 UV0; + float2 UV1; + float4 Normal0; + float4 Normal1; + float3 Tangent0; + float3 Tangent1; +}; + +struct FPNTessellationHSToDS +{ + FHitProxyVSToDS PassSpecificData; + spvUnsafeArray WorldPosition; + float3 DisplacementScale; + float TessellationMultiplier; + float WorldDisplacementMultiplier; + FHullShaderConstantDominantVertexData DominantVertex; + FHullShaderConstantDominantEdgeData DominantEdge; +}; + +struct type_View +{ + float4x4 View_TranslatedWorldToClip; + float4x4 View_WorldToClip; + float4x4 View_ClipToWorld; + float4x4 View_TranslatedWorldToView; + float4x4 View_ViewToTranslatedWorld; + float4x4 View_TranslatedWorldToCameraView; + float4x4 View_CameraViewToTranslatedWorld; + float4x4 View_ViewToClip; + float4x4 View_ViewToClipNoAA; + float4x4 View_ClipToView; + float4x4 View_ClipToTranslatedWorld; + float4x4 View_SVPositionToTranslatedWorld; + float4x4 View_ScreenToWorld; + float4x4 View_ScreenToTranslatedWorld; + packed_float3 View_ViewForward; + float PrePadding_View_908; + packed_float3 View_ViewUp; + float PrePadding_View_924; + packed_float3 View_ViewRight; + float PrePadding_View_940; + packed_float3 View_HMDViewNoRollUp; + float PrePadding_View_956; + packed_float3 View_HMDViewNoRollRight; + float PrePadding_View_972; + float4 View_InvDeviceZToWorldZTransform; + float4 View_ScreenPositionScaleBias; + packed_float3 View_WorldCameraOrigin; + float PrePadding_View_1020; + packed_float3 View_TranslatedWorldCameraOrigin; + float PrePadding_View_1036; + packed_float3 View_WorldViewOrigin; + float PrePadding_View_1052; + packed_float3 View_PreViewTranslation; + float PrePadding_View_1068; + float4x4 View_PrevProjection; + float4x4 View_PrevViewProj; + float4x4 View_PrevViewRotationProj; + float4x4 View_PrevViewToClip; + float4x4 View_PrevClipToView; + float4x4 View_PrevTranslatedWorldToClip; + float4x4 View_PrevTranslatedWorldToView; + float4x4 View_PrevViewToTranslatedWorld; + float4x4 View_PrevTranslatedWorldToCameraView; + float4x4 View_PrevCameraViewToTranslatedWorld; + packed_float3 View_PrevWorldCameraOrigin; + float PrePadding_View_1724; + packed_float3 View_PrevWorldViewOrigin; + float PrePadding_View_1740; + packed_float3 View_PrevPreViewTranslation; + float PrePadding_View_1756; + float4x4 View_PrevInvViewProj; + float4x4 View_PrevScreenToTranslatedWorld; + float4x4 View_ClipToPrevClip; + float4 View_TemporalAAJitter; + float4 View_GlobalClippingPlane; + float2 View_FieldOfViewWideAngles; + float2 View_PrevFieldOfViewWideAngles; + float4 View_ViewRectMin; + float4 View_ViewSizeAndInvSize; + float4 View_BufferSizeAndInvSize; + float4 View_BufferBilinearUVMinMax; + int View_NumSceneColorMSAASamples; + float View_PreExposure; + float View_OneOverPreExposure; + float PrePadding_View_2076; + float4 View_DiffuseOverrideParameter; + float4 View_SpecularOverrideParameter; + float4 View_NormalOverrideParameter; + float2 View_RoughnessOverrideParameter; + float View_PrevFrameGameTime; + float View_PrevFrameRealTime; + float View_OutOfBoundsMask; + float PrePadding_View_2148; + float PrePadding_View_2152; + float PrePadding_View_2156; + packed_float3 View_WorldCameraMovementSinceLastFrame; + float View_CullingSign; + float View_NearPlane; + float View_AdaptiveTessellationFactor; + float View_GameTime; + float View_RealTime; + float View_DeltaTime; + float View_MaterialTextureMipBias; + float View_MaterialTextureDerivativeMultiply; + uint View_Random; + uint View_FrameNumber; + uint View_StateFrameIndexMod8; + uint View_StateFrameIndex; + float View_CameraCut; + float View_UnlitViewmodeMask; + float PrePadding_View_2228; + float PrePadding_View_2232; + float PrePadding_View_2236; + float4 View_DirectionalLightColor; + packed_float3 View_DirectionalLightDirection; + float PrePadding_View_2268; + float4 View_TranslucencyLightingVolumeMin[2]; + float4 View_TranslucencyLightingVolumeInvSize[2]; + float4 View_TemporalAAParams; + float4 View_CircleDOFParams; + float View_DepthOfFieldSensorWidth; + float View_DepthOfFieldFocalDistance; + float View_DepthOfFieldScale; + float View_DepthOfFieldFocalLength; + float View_DepthOfFieldFocalRegion; + float View_DepthOfFieldNearTransitionRegion; + float View_DepthOfFieldFarTransitionRegion; + float View_MotionBlurNormalizedToPixel; + float View_bSubsurfacePostprocessEnabled; + float View_GeneralPurposeTweak; + float View_DemosaicVposOffset; + float PrePadding_View_2412; + packed_float3 View_IndirectLightingColorScale; + float View_HDR32bppEncodingMode; + packed_float3 View_AtmosphericFogSunDirection; + float View_AtmosphericFogSunPower; + float View_AtmosphericFogPower; + float View_AtmosphericFogDensityScale; + float View_AtmosphericFogDensityOffset; + float View_AtmosphericFogGroundOffset; + float View_AtmosphericFogDistanceScale; + float View_AtmosphericFogAltitudeScale; + float View_AtmosphericFogHeightScaleRayleigh; + float View_AtmosphericFogStartDistance; + float View_AtmosphericFogDistanceOffset; + float View_AtmosphericFogSunDiscScale; + float View_AtmosphericFogSunDiscHalfApexAngleRadian; + float PrePadding_View_2492; + float4 View_AtmosphericFogSunDiscLuminance; + uint View_AtmosphericFogRenderMask; + uint View_AtmosphericFogInscatterAltitudeSampleNum; + uint PrePadding_View_2520; + uint PrePadding_View_2524; + float4 View_AtmosphericFogSunColor; + packed_float3 View_NormalCurvatureToRoughnessScaleBias; + float View_RenderingReflectionCaptureMask; + float4 View_AmbientCubemapTint; + float View_AmbientCubemapIntensity; + float View_SkyLightParameters; + float PrePadding_View_2584; + float PrePadding_View_2588; + float4 View_SkyLightColor; + float4 View_SkyIrradianceEnvironmentMap[7]; + float View_MobilePreviewMode; + float View_HMDEyePaddingOffset; + float View_ReflectionCubemapMaxMip; + float View_ShowDecalsMask; + uint View_DistanceFieldAOSpecularOcclusionMode; + float View_IndirectCapsuleSelfShadowingIntensity; + float PrePadding_View_2744; + float PrePadding_View_2748; + packed_float3 View_ReflectionEnvironmentRoughnessMixingScaleBiasAndLargestWeight; + int View_StereoPassIndex; + float4 View_GlobalVolumeCenterAndExtent[4]; + float4 View_GlobalVolumeWorldToUVAddAndMul[4]; + float View_GlobalVolumeDimension; + float View_GlobalVolumeTexelSize; + float View_MaxGlobalDistance; + float PrePadding_View_2908; + int2 View_CursorPosition; + float View_bCheckerboardSubsurfaceProfileRendering; + float PrePadding_View_2924; + packed_float3 View_VolumetricFogInvGridSize; + float PrePadding_View_2940; + packed_float3 View_VolumetricFogGridZParams; + float PrePadding_View_2956; + float2 View_VolumetricFogSVPosToVolumeUV; + float View_VolumetricFogMaxDistance; + float PrePadding_View_2972; + packed_float3 View_VolumetricLightmapWorldToUVScale; + float PrePadding_View_2988; + packed_float3 View_VolumetricLightmapWorldToUVAdd; + float PrePadding_View_3004; + packed_float3 View_VolumetricLightmapIndirectionTextureSize; + float View_VolumetricLightmapBrickSize; + packed_float3 View_VolumetricLightmapBrickTexelSize; + float View_StereoIPD; + float View_IndirectLightingCacheShowFlag; + float View_EyeToPixelSpreadAngle; +}; + +struct type_Primitive +{ + float4x4 Primitive_LocalToWorld; + float4 Primitive_InvNonUniformScaleAndDeterminantSign; + float4 Primitive_ObjectWorldPositionAndRadius; + float4x4 Primitive_WorldToLocal; + float4x4 Primitive_PreviousLocalToWorld; + float4x4 Primitive_PreviousWorldToLocal; + packed_float3 Primitive_ActorWorldPosition; + float Primitive_UseSingleSampleShadowFromStationaryLights; + packed_float3 Primitive_ObjectBounds; + float Primitive_LpvBiasMultiplier; + float Primitive_DecalReceiverMask; + float Primitive_PerObjectGBufferData; + float Primitive_UseVolumetricLightmapShadowFromStationaryLights; + float Primitive_DrawsVelocity; + float4 Primitive_ObjectOrientation; + float4 Primitive_NonUniformScale; + packed_float3 Primitive_LocalObjectBoundsMin; + uint Primitive_LightingChannelMask; + packed_float3 Primitive_LocalObjectBoundsMax; + uint Primitive_LightmapDataIndex; + packed_float3 Primitive_PreSkinnedLocalBounds; + int Primitive_SingleCaptureIndex; + uint Primitive_OutputVelocity; + uint PrePadding_Primitive_420; + uint PrePadding_Primitive_424; + uint PrePadding_Primitive_428; + float4 Primitive_CustomPrimitiveData[4]; +}; + +constant float4 _613 = {}; + +struct main0_out +{ + float3 out_var_PN_DisplacementScales; + float2 out_var_PN_DominantEdge; + float2 out_var_PN_DominantEdge1; + float4 out_var_PN_DominantEdge2; + float4 out_var_PN_DominantEdge3; + float3 out_var_PN_DominantEdge4; + float3 out_var_PN_DominantEdge5; + float2 out_var_PN_DominantVertex; + float4 out_var_PN_DominantVertex1; + float3 out_var_PN_DominantVertex2; + spvUnsafeArray out_var_PN_POSITION; + float out_var_PN_TessellationMultiplier; + float out_var_PN_WorldDisplacementMultiplier; + float4 out_var_TEXCOORD10_centroid; + float4 out_var_TEXCOORD11_centroid; + float4 out_var_VS_To_DS_Position; + uint out_var_VS_To_DS_VertexID; +}; + +struct main0_patchOut +{ + float4 out_var_PN_POSITION9; +}; + +struct main0_in +{ + float4 in_var_TEXCOORD10_centroid [[attribute(0)]]; + float4 in_var_TEXCOORD11_centroid [[attribute(1)]]; + float4 in_var_VS_To_DS_Position [[attribute(2)]]; + uint in_var_VS_To_DS_VertexID [[attribute(3)]]; +}; + +kernel void main0(main0_in in [[stage_in]], constant type_View& View [[buffer(0)]], constant type_Primitive& Primitive [[buffer(1)]], uint gl_InvocationID [[thread_index_in_threadgroup]], uint gl_PrimitiveID [[threadgroup_position_in_grid]], device main0_out* spvOut [[buffer(28)]], constant uint* spvIndirectParams [[buffer(29)]], device main0_patchOut* spvPatchOut [[buffer(27)]], device MTLTriangleTessellationFactorsHalf* spvTessLevel [[buffer(26)]], threadgroup main0_in* gl_in [[threadgroup(0)]]) +{ + threadgroup FPNTessellationHSToDS temp_var_hullMainRetVal[3]; + device main0_out* gl_out = &spvOut[gl_PrimitiveID * 3]; + device main0_patchOut& patchOut = spvPatchOut[gl_PrimitiveID]; + if (gl_InvocationID < spvIndirectParams[0]) + gl_in[gl_InvocationID] = in; + threadgroup_barrier(mem_flags::mem_threadgroup); + if (gl_InvocationID >= 3) + return; + spvUnsafeArray _142 = spvUnsafeArray({ gl_in[0].in_var_TEXCOORD10_centroid, gl_in[1].in_var_TEXCOORD10_centroid, gl_in[2].in_var_TEXCOORD10_centroid, gl_in[3].in_var_TEXCOORD10_centroid, gl_in[4].in_var_TEXCOORD10_centroid, gl_in[5].in_var_TEXCOORD10_centroid, gl_in[6].in_var_TEXCOORD10_centroid, gl_in[7].in_var_TEXCOORD10_centroid, gl_in[8].in_var_TEXCOORD10_centroid, gl_in[9].in_var_TEXCOORD10_centroid, gl_in[10].in_var_TEXCOORD10_centroid, gl_in[11].in_var_TEXCOORD10_centroid }); + spvUnsafeArray _143 = spvUnsafeArray({ gl_in[0].in_var_TEXCOORD11_centroid, gl_in[1].in_var_TEXCOORD11_centroid, gl_in[2].in_var_TEXCOORD11_centroid, gl_in[3].in_var_TEXCOORD11_centroid, gl_in[4].in_var_TEXCOORD11_centroid, gl_in[5].in_var_TEXCOORD11_centroid, gl_in[6].in_var_TEXCOORD11_centroid, gl_in[7].in_var_TEXCOORD11_centroid, gl_in[8].in_var_TEXCOORD11_centroid, gl_in[9].in_var_TEXCOORD11_centroid, gl_in[10].in_var_TEXCOORD11_centroid, gl_in[11].in_var_TEXCOORD11_centroid }); + spvUnsafeArray _192 = spvUnsafeArray({ gl_in[0].in_var_VS_To_DS_Position, gl_in[1].in_var_VS_To_DS_Position, gl_in[2].in_var_VS_To_DS_Position, gl_in[3].in_var_VS_To_DS_Position, gl_in[4].in_var_VS_To_DS_Position, gl_in[5].in_var_VS_To_DS_Position, gl_in[6].in_var_VS_To_DS_Position, gl_in[7].in_var_VS_To_DS_Position, gl_in[8].in_var_VS_To_DS_Position, gl_in[9].in_var_VS_To_DS_Position, gl_in[10].in_var_VS_To_DS_Position, gl_in[11].in_var_VS_To_DS_Position }); + spvUnsafeArray _193 = spvUnsafeArray({ gl_in[0].in_var_VS_To_DS_VertexID, gl_in[1].in_var_VS_To_DS_VertexID, gl_in[2].in_var_VS_To_DS_VertexID, gl_in[3].in_var_VS_To_DS_VertexID, gl_in[4].in_var_VS_To_DS_VertexID, gl_in[5].in_var_VS_To_DS_VertexID, gl_in[6].in_var_VS_To_DS_VertexID, gl_in[7].in_var_VS_To_DS_VertexID, gl_in[8].in_var_VS_To_DS_VertexID, gl_in[9].in_var_VS_To_DS_VertexID, gl_in[10].in_var_VS_To_DS_VertexID, gl_in[11].in_var_VS_To_DS_VertexID }); + spvUnsafeArray _230 = spvUnsafeArray({ FHitProxyVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _142[0], _143[0] } }, _192[0], _193[0] }, FHitProxyVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _142[1], _143[1] } }, _192[1], _193[1] }, FHitProxyVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _142[2], _143[2] } }, _192[2], _193[2] }, FHitProxyVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _142[3], _143[3] } }, _192[3], _193[3] }, FHitProxyVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _142[4], _143[4] } }, _192[4], _193[4] }, FHitProxyVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _142[5], _143[5] } }, _192[5], _193[5] }, FHitProxyVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _142[6], _143[6] } }, _192[6], _193[6] }, FHitProxyVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _142[7], _143[7] } }, _192[7], _193[7] }, FHitProxyVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _142[8], _143[8] } }, _192[8], _193[8] }, FHitProxyVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _142[9], _143[9] } }, _192[9], _193[9] }, FHitProxyVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _142[10], _143[10] } }, _192[10], _193[10] }, FHitProxyVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _142[11], _143[11] } }, _192[11], _193[11] } }); + spvUnsafeArray param_var_I; + param_var_I = _230; + float4 _247 = float4(param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld2.xyz, 0.0); + float3 _251 = Primitive.Primitive_NonUniformScale.xyz * float3x3(param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld0.xyz, cross(param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld2.xyz, param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld0.xyz) * float3(param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld2.w), param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld2.xyz); + uint _254 = (gl_InvocationID < 2u) ? (gl_InvocationID + 1u) : 0u; + uint _255 = 2u * gl_InvocationID; + uint _256 = 3u + _255; + uint _257 = _255 + 4u; + uint _264 = (_254 < 2u) ? (_254 + 1u) : 0u; + uint _265 = 2u * _254; + uint _266 = 3u + _265; + uint _267 = _265 + 4u; + float4 _279 = float4(param_var_I[9u + gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld2.xyz, 0.0); + float4 _315; + float4 _316; + float4 _317; + float4 _318; + if ((param_var_I[_266].VertexID < param_var_I[_254].VertexID) || ((param_var_I[_266].VertexID == param_var_I[_254].VertexID) && (param_var_I[_267].VertexID < param_var_I[_264].VertexID))) + { + _315 = param_var_I[_267].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld0; + _316 = param_var_I[_267].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld2; + _317 = param_var_I[_266].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld0; + _318 = param_var_I[_266].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld2; + } + else + { + _315 = param_var_I[_264].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld0; + _316 = param_var_I[_264].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld2; + _317 = param_var_I[_254].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld0; + _318 = param_var_I[_254].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld2; + } + float4 _324 = float4(_318.xyz, 0.0); + float4 _328 = float4(_316.xyz, 0.0); + float4 _336 = float4(param_var_I[_254].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld2.xyz, 0.0); + float4 _344 = float4(param_var_I[_256].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld2.xyz, 0.0); + float4 _352 = float4(param_var_I[_257].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld2.xyz, 0.0); + spvUnsafeArray _402 = spvUnsafeArray({ param_var_I[gl_InvocationID].Position, ((((float4(2.0) * param_var_I[gl_InvocationID].Position) + param_var_I[_254].Position) - (float4(dot(param_var_I[_254].Position - param_var_I[gl_InvocationID].Position, _247)) * _247)) + (((float4(2.0) * param_var_I[_256].Position) + param_var_I[_257].Position) - (float4(dot(param_var_I[_257].Position - param_var_I[_256].Position, _344)) * _344))) * float4(0.16666667163372039794921875), ((((float4(2.0) * param_var_I[_254].Position) + param_var_I[gl_InvocationID].Position) - (float4(dot(param_var_I[gl_InvocationID].Position - param_var_I[_254].Position, _336)) * _336)) + (((float4(2.0) * param_var_I[_257].Position) + param_var_I[_256].Position) - (float4(dot(param_var_I[_256].Position - param_var_I[_257].Position, _352)) * _352))) * float4(0.16666667163372039794921875) }); + gl_out[gl_InvocationID].out_var_TEXCOORD10_centroid = param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld0; + gl_out[gl_InvocationID].out_var_TEXCOORD11_centroid = param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld2; + gl_out[gl_InvocationID].out_var_VS_To_DS_Position = param_var_I[gl_InvocationID].Position; + gl_out[gl_InvocationID].out_var_VS_To_DS_VertexID = param_var_I[gl_InvocationID].VertexID; + gl_out[gl_InvocationID].out_var_PN_POSITION = _402; + gl_out[gl_InvocationID].out_var_PN_DisplacementScales = _251; + gl_out[gl_InvocationID].out_var_PN_TessellationMultiplier = 1.0; + gl_out[gl_InvocationID].out_var_PN_WorldDisplacementMultiplier = 1.0; + gl_out[gl_InvocationID].out_var_PN_DominantVertex = float2(0.0); + gl_out[gl_InvocationID].out_var_PN_DominantVertex1 = _279; + gl_out[gl_InvocationID].out_var_PN_DominantVertex2 = param_var_I[9u + gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld0.xyz; + gl_out[gl_InvocationID].out_var_PN_DominantEdge = float2(0.0); + gl_out[gl_InvocationID].out_var_PN_DominantEdge1 = float2(0.0); + gl_out[gl_InvocationID].out_var_PN_DominantEdge2 = _324; + gl_out[gl_InvocationID].out_var_PN_DominantEdge3 = _328; + gl_out[gl_InvocationID].out_var_PN_DominantEdge4 = _317.xyz; + gl_out[gl_InvocationID].out_var_PN_DominantEdge5 = _315.xyz; + temp_var_hullMainRetVal[gl_InvocationID] = FPNTessellationHSToDS{ param_var_I[gl_InvocationID], _402, _251, 1.0, 1.0, FHullShaderConstantDominantVertexData{ float2(0.0), _279, param_var_I[9u + gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld0.xyz }, FHullShaderConstantDominantEdgeData{ float2(0.0), float2(0.0), _324, _328, _317.xyz, _315.xyz } }; + threadgroup_barrier(mem_flags::mem_device | mem_flags::mem_threadgroup); + if (gl_InvocationID == 0u) + { + float4 _461 = (((((temp_var_hullMainRetVal[0u].WorldPosition[1] + temp_var_hullMainRetVal[0u].WorldPosition[2]) + temp_var_hullMainRetVal[1u].WorldPosition[1]) + temp_var_hullMainRetVal[1u].WorldPosition[2]) + temp_var_hullMainRetVal[2u].WorldPosition[1]) + temp_var_hullMainRetVal[2u].WorldPosition[2]) * float4(0.16666667163372039794921875); + float4 _474 = _613; + _474.x = 0.5 * (temp_var_hullMainRetVal[1u].TessellationMultiplier + temp_var_hullMainRetVal[2u].TessellationMultiplier); + float4 _480 = _474; + _480.y = 0.5 * (temp_var_hullMainRetVal[2u].TessellationMultiplier + temp_var_hullMainRetVal[0u].TessellationMultiplier); + float4 _485 = _480; + _485.z = 0.5 * (temp_var_hullMainRetVal[0u].TessellationMultiplier + temp_var_hullMainRetVal[1u].TessellationMultiplier); + float4 _492 = _485; + _492.w = 0.333000004291534423828125 * ((temp_var_hullMainRetVal[0u].TessellationMultiplier + temp_var_hullMainRetVal[1u].TessellationMultiplier) + temp_var_hullMainRetVal[2u].TessellationMultiplier); + float4 _600; + for (;;) + { + float4 _500 = View.View_ViewToClip * float4(0.0); + float4 _505 = View.View_TranslatedWorldToClip * float4(temp_var_hullMainRetVal[0u].WorldPosition[0].xyz, 1.0); + float3 _506 = _505.xyz; + float3 _507 = _500.xyz; + float _509 = _505.w; + float _510 = _500.w; + float4 _527 = View.View_TranslatedWorldToClip * float4(temp_var_hullMainRetVal[1u].WorldPosition[0].xyz, 1.0); + float3 _528 = _527.xyz; + float _530 = _527.w; + float4 _548 = View.View_TranslatedWorldToClip * float4(temp_var_hullMainRetVal[2u].WorldPosition[0].xyz, 1.0); + float3 _549 = _548.xyz; + float _551 = _548.w; + if (any((((select(int3(0), int3(1), (_506 - _507) < float3(_509 + _510)) + (int3(2) * select(int3(0), int3(1), (_506 + _507) > float3((-_509) - _510)))) | (select(int3(0), int3(1), (_528 - _507) < float3(_530 + _510)) + (int3(2) * select(int3(0), int3(1), (_528 + _507) > float3((-_530) - _510))))) | (select(int3(0), int3(1), (_549 - _507) < float3(_551 + _510)) + (int3(2) * select(int3(0), int3(1), (_549 + _507) > float3((-_551) - _510))))) != int3(3))) + { + _600 = float4(0.0); + break; + } + float3 _569 = temp_var_hullMainRetVal[0u].WorldPosition[0].xyz - temp_var_hullMainRetVal[1u].WorldPosition[0].xyz; + float3 _570 = temp_var_hullMainRetVal[1u].WorldPosition[0].xyz - temp_var_hullMainRetVal[2u].WorldPosition[0].xyz; + float3 _571 = temp_var_hullMainRetVal[2u].WorldPosition[0].xyz - temp_var_hullMainRetVal[0u].WorldPosition[0].xyz; + float3 _574 = (float3(0.5) * (temp_var_hullMainRetVal[0u].WorldPosition[0].xyz + temp_var_hullMainRetVal[1u].WorldPosition[0].xyz)) - float3(View.View_TranslatedWorldCameraOrigin); + float3 _577 = (float3(0.5) * (temp_var_hullMainRetVal[1u].WorldPosition[0].xyz + temp_var_hullMainRetVal[2u].WorldPosition[0].xyz)) - float3(View.View_TranslatedWorldCameraOrigin); + float3 _580 = (float3(0.5) * (temp_var_hullMainRetVal[2u].WorldPosition[0].xyz + temp_var_hullMainRetVal[0u].WorldPosition[0].xyz)) - float3(View.View_TranslatedWorldCameraOrigin); + float _584 = sqrt(dot(_570, _570) / dot(_577, _577)); + float _588 = sqrt(dot(_571, _571) / dot(_580, _580)); + float _592 = sqrt(dot(_569, _569) / dot(_574, _574)); + float4 _597 = float4(_584, _588, _592, 1.0); + _597.w = 0.333000004291534423828125 * ((_584 + _588) + _592); + _600 = float4(View.View_AdaptiveTessellationFactor) * _597; + break; + } + float4 _602 = fast::clamp(_492 * _600, float4(1.0), float4(15.0)); + spvTessLevel[gl_PrimitiveID].edgeTessellationFactor[0u] = half(_602.x); + spvTessLevel[gl_PrimitiveID].edgeTessellationFactor[1u] = half(_602.y); + spvTessLevel[gl_PrimitiveID].edgeTessellationFactor[2u] = half(_602.z); + spvTessLevel[gl_PrimitiveID].insideTessellationFactor = half(_602.w); + patchOut.out_var_PN_POSITION9 = _461 + ((_461 - (((temp_var_hullMainRetVal[2u].WorldPosition[0] + temp_var_hullMainRetVal[1u].WorldPosition[0]) + temp_var_hullMainRetVal[0u].WorldPosition[0]) * float4(0.3333333432674407958984375))) * float4(0.5)); + } +} + diff --git a/third_party/spirv-cross/reference/opt/shaders-ue4/asm/tesc/hs-texcoord-array.asm.tesc b/third_party/spirv-cross/reference/opt/shaders-ue4/asm/tesc/hs-texcoord-array.asm.tesc new file mode 100644 index 0000000000..674992ca8e --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders-ue4/asm/tesc/hs-texcoord-array.asm.tesc @@ -0,0 +1,411 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + +#include +#include + +using namespace metal; + +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +struct FVertexFactoryInterpolantsVSToPS +{ + float4 TangentToWorld0; + float4 TangentToWorld2; + float4 Color; + spvUnsafeArray TexCoords; +}; + +struct FVertexFactoryInterpolantsVSToDS +{ + FVertexFactoryInterpolantsVSToPS InterpolantsVSToPS; +}; + +struct FHitProxyVSToDS +{ + FVertexFactoryInterpolantsVSToDS FactoryInterpolants; + float4 Position; +}; + +struct FPNTessellationHSToDS +{ + FHitProxyVSToDS PassSpecificData; + spvUnsafeArray WorldPosition; + float3 DisplacementScale; + float TessellationMultiplier; + float WorldDisplacementMultiplier; +}; + +struct type_View +{ + float4x4 View_TranslatedWorldToClip; + float4x4 View_WorldToClip; + float4x4 View_ClipToWorld; + float4x4 View_TranslatedWorldToView; + float4x4 View_ViewToTranslatedWorld; + float4x4 View_TranslatedWorldToCameraView; + float4x4 View_CameraViewToTranslatedWorld; + float4x4 View_ViewToClip; + float4x4 View_ViewToClipNoAA; + float4x4 View_ClipToView; + float4x4 View_ClipToTranslatedWorld; + float4x4 View_SVPositionToTranslatedWorld; + float4x4 View_ScreenToWorld; + float4x4 View_ScreenToTranslatedWorld; + packed_float3 View_ViewForward; + float PrePadding_View_908; + packed_float3 View_ViewUp; + float PrePadding_View_924; + packed_float3 View_ViewRight; + float PrePadding_View_940; + packed_float3 View_HMDViewNoRollUp; + float PrePadding_View_956; + packed_float3 View_HMDViewNoRollRight; + float PrePadding_View_972; + float4 View_InvDeviceZToWorldZTransform; + float4 View_ScreenPositionScaleBias; + packed_float3 View_WorldCameraOrigin; + float PrePadding_View_1020; + packed_float3 View_TranslatedWorldCameraOrigin; + float PrePadding_View_1036; + packed_float3 View_WorldViewOrigin; + float PrePadding_View_1052; + packed_float3 View_PreViewTranslation; + float PrePadding_View_1068; + float4x4 View_PrevProjection; + float4x4 View_PrevViewProj; + float4x4 View_PrevViewRotationProj; + float4x4 View_PrevViewToClip; + float4x4 View_PrevClipToView; + float4x4 View_PrevTranslatedWorldToClip; + float4x4 View_PrevTranslatedWorldToView; + float4x4 View_PrevViewToTranslatedWorld; + float4x4 View_PrevTranslatedWorldToCameraView; + float4x4 View_PrevCameraViewToTranslatedWorld; + packed_float3 View_PrevWorldCameraOrigin; + float PrePadding_View_1724; + packed_float3 View_PrevWorldViewOrigin; + float PrePadding_View_1740; + packed_float3 View_PrevPreViewTranslation; + float PrePadding_View_1756; + float4x4 View_PrevInvViewProj; + float4x4 View_PrevScreenToTranslatedWorld; + float4x4 View_ClipToPrevClip; + float4 View_TemporalAAJitter; + float4 View_GlobalClippingPlane; + float2 View_FieldOfViewWideAngles; + float2 View_PrevFieldOfViewWideAngles; + float4 View_ViewRectMin; + float4 View_ViewSizeAndInvSize; + float4 View_BufferSizeAndInvSize; + float4 View_BufferBilinearUVMinMax; + int View_NumSceneColorMSAASamples; + float View_PreExposure; + float View_OneOverPreExposure; + float PrePadding_View_2076; + float4 View_DiffuseOverrideParameter; + float4 View_SpecularOverrideParameter; + float4 View_NormalOverrideParameter; + float2 View_RoughnessOverrideParameter; + float View_PrevFrameGameTime; + float View_PrevFrameRealTime; + float View_OutOfBoundsMask; + float PrePadding_View_2148; + float PrePadding_View_2152; + float PrePadding_View_2156; + packed_float3 View_WorldCameraMovementSinceLastFrame; + float View_CullingSign; + float View_NearPlane; + float View_AdaptiveTessellationFactor; + float View_GameTime; + float View_RealTime; + float View_DeltaTime; + float View_MaterialTextureMipBias; + float View_MaterialTextureDerivativeMultiply; + uint View_Random; + uint View_FrameNumber; + uint View_StateFrameIndexMod8; + uint View_StateFrameIndex; + float View_CameraCut; + float View_UnlitViewmodeMask; + float PrePadding_View_2228; + float PrePadding_View_2232; + float PrePadding_View_2236; + float4 View_DirectionalLightColor; + packed_float3 View_DirectionalLightDirection; + float PrePadding_View_2268; + float4 View_TranslucencyLightingVolumeMin[2]; + float4 View_TranslucencyLightingVolumeInvSize[2]; + float4 View_TemporalAAParams; + float4 View_CircleDOFParams; + float View_DepthOfFieldSensorWidth; + float View_DepthOfFieldFocalDistance; + float View_DepthOfFieldScale; + float View_DepthOfFieldFocalLength; + float View_DepthOfFieldFocalRegion; + float View_DepthOfFieldNearTransitionRegion; + float View_DepthOfFieldFarTransitionRegion; + float View_MotionBlurNormalizedToPixel; + float View_bSubsurfacePostprocessEnabled; + float View_GeneralPurposeTweak; + float View_DemosaicVposOffset; + float PrePadding_View_2412; + packed_float3 View_IndirectLightingColorScale; + float View_HDR32bppEncodingMode; + packed_float3 View_AtmosphericFogSunDirection; + float View_AtmosphericFogSunPower; + float View_AtmosphericFogPower; + float View_AtmosphericFogDensityScale; + float View_AtmosphericFogDensityOffset; + float View_AtmosphericFogGroundOffset; + float View_AtmosphericFogDistanceScale; + float View_AtmosphericFogAltitudeScale; + float View_AtmosphericFogHeightScaleRayleigh; + float View_AtmosphericFogStartDistance; + float View_AtmosphericFogDistanceOffset; + float View_AtmosphericFogSunDiscScale; + float View_AtmosphericFogSunDiscHalfApexAngleRadian; + float PrePadding_View_2492; + float4 View_AtmosphericFogSunDiscLuminance; + uint View_AtmosphericFogRenderMask; + uint View_AtmosphericFogInscatterAltitudeSampleNum; + uint PrePadding_View_2520; + uint PrePadding_View_2524; + float4 View_AtmosphericFogSunColor; + packed_float3 View_NormalCurvatureToRoughnessScaleBias; + float View_RenderingReflectionCaptureMask; + float4 View_AmbientCubemapTint; + float View_AmbientCubemapIntensity; + float View_SkyLightParameters; + float PrePadding_View_2584; + float PrePadding_View_2588; + float4 View_SkyLightColor; + float4 View_SkyIrradianceEnvironmentMap[7]; + float View_MobilePreviewMode; + float View_HMDEyePaddingOffset; + float View_ReflectionCubemapMaxMip; + float View_ShowDecalsMask; + uint View_DistanceFieldAOSpecularOcclusionMode; + float View_IndirectCapsuleSelfShadowingIntensity; + float PrePadding_View_2744; + float PrePadding_View_2748; + packed_float3 View_ReflectionEnvironmentRoughnessMixingScaleBiasAndLargestWeight; + int View_StereoPassIndex; + float4 View_GlobalVolumeCenterAndExtent[4]; + float4 View_GlobalVolumeWorldToUVAddAndMul[4]; + float View_GlobalVolumeDimension; + float View_GlobalVolumeTexelSize; + float View_MaxGlobalDistance; + float PrePadding_View_2908; + int2 View_CursorPosition; + float View_bCheckerboardSubsurfaceProfileRendering; + float PrePadding_View_2924; + packed_float3 View_VolumetricFogInvGridSize; + float PrePadding_View_2940; + packed_float3 View_VolumetricFogGridZParams; + float PrePadding_View_2956; + float2 View_VolumetricFogSVPosToVolumeUV; + float View_VolumetricFogMaxDistance; + float PrePadding_View_2972; + packed_float3 View_VolumetricLightmapWorldToUVScale; + float PrePadding_View_2988; + packed_float3 View_VolumetricLightmapWorldToUVAdd; + float PrePadding_View_3004; + packed_float3 View_VolumetricLightmapIndirectionTextureSize; + float View_VolumetricLightmapBrickSize; + packed_float3 View_VolumetricLightmapBrickTexelSize; + float View_StereoIPD; + float View_IndirectLightingCacheShowFlag; + float View_EyeToPixelSpreadAngle; +}; + +struct type_Primitive +{ + float4x4 Primitive_LocalToWorld; + float4 Primitive_InvNonUniformScaleAndDeterminantSign; + float4 Primitive_ObjectWorldPositionAndRadius; + float4x4 Primitive_WorldToLocal; + float4x4 Primitive_PreviousLocalToWorld; + float4x4 Primitive_PreviousWorldToLocal; + packed_float3 Primitive_ActorWorldPosition; + float Primitive_UseSingleSampleShadowFromStationaryLights; + packed_float3 Primitive_ObjectBounds; + float Primitive_LpvBiasMultiplier; + float Primitive_DecalReceiverMask; + float Primitive_PerObjectGBufferData; + float Primitive_UseVolumetricLightmapShadowFromStationaryLights; + float Primitive_DrawsVelocity; + float4 Primitive_ObjectOrientation; + float4 Primitive_NonUniformScale; + packed_float3 Primitive_LocalObjectBoundsMin; + uint Primitive_LightingChannelMask; + packed_float3 Primitive_LocalObjectBoundsMax; + uint Primitive_LightmapDataIndex; + packed_float3 Primitive_PreSkinnedLocalBounds; + int Primitive_SingleCaptureIndex; + uint Primitive_OutputVelocity; + uint PrePadding_Primitive_420; + uint PrePadding_Primitive_424; + uint PrePadding_Primitive_428; + float4 Primitive_CustomPrimitiveData[4]; +}; + +constant float4 _537 = {}; + +struct main0_out +{ + float4 out_var_COLOR0; + float3 out_var_PN_DisplacementScales; + spvUnsafeArray out_var_PN_POSITION; + float out_var_PN_TessellationMultiplier; + float out_var_PN_WorldDisplacementMultiplier; + spvUnsafeArray out_var_TEXCOORD0; + float4 out_var_TEXCOORD10_centroid; + float4 out_var_TEXCOORD11_centroid; + float4 out_var_VS_To_DS_Position; +}; + +struct main0_patchOut +{ + float4 out_var_PN_POSITION9; +}; + +struct main0_in +{ + float4 in_var_TEXCOORD10_centroid [[attribute(0)]]; + float4 in_var_TEXCOORD11_centroid [[attribute(1)]]; + float4 in_var_COLOR0 [[attribute(2)]]; + float2 in_var_TEXCOORD0_0 [[attribute(3)]]; + float2 in_var_TEXCOORD0_1 [[attribute(4)]]; + float4 in_var_VS_To_DS_Position [[attribute(5)]]; +}; + +kernel void main0(main0_in in [[stage_in]], constant type_View& View [[buffer(0)]], constant type_Primitive& Primitive [[buffer(1)]], uint gl_InvocationID [[thread_index_in_threadgroup]], uint gl_PrimitiveID [[threadgroup_position_in_grid]], device main0_out* spvOut [[buffer(28)]], constant uint* spvIndirectParams [[buffer(29)]], device main0_patchOut* spvPatchOut [[buffer(27)]], device MTLTriangleTessellationFactorsHalf* spvTessLevel [[buffer(26)]], threadgroup main0_in* gl_in [[threadgroup(0)]]) +{ + threadgroup FPNTessellationHSToDS temp_var_hullMainRetVal[3]; + device main0_out* gl_out = &spvOut[gl_PrimitiveID * 3]; + device main0_patchOut& patchOut = spvPatchOut[gl_PrimitiveID]; + if (gl_InvocationID < spvIndirectParams[0]) + gl_in[gl_InvocationID] = in; + threadgroup_barrier(mem_flags::mem_threadgroup); + if (gl_InvocationID >= 3) + return; + spvUnsafeArray _129 = spvUnsafeArray({ gl_in[0].in_var_TEXCOORD10_centroid, gl_in[1].in_var_TEXCOORD10_centroid, gl_in[2].in_var_TEXCOORD10_centroid, gl_in[3].in_var_TEXCOORD10_centroid, gl_in[4].in_var_TEXCOORD10_centroid, gl_in[5].in_var_TEXCOORD10_centroid, gl_in[6].in_var_TEXCOORD10_centroid, gl_in[7].in_var_TEXCOORD10_centroid, gl_in[8].in_var_TEXCOORD10_centroid, gl_in[9].in_var_TEXCOORD10_centroid, gl_in[10].in_var_TEXCOORD10_centroid, gl_in[11].in_var_TEXCOORD10_centroid }); + spvUnsafeArray _130 = spvUnsafeArray({ gl_in[0].in_var_TEXCOORD11_centroid, gl_in[1].in_var_TEXCOORD11_centroid, gl_in[2].in_var_TEXCOORD11_centroid, gl_in[3].in_var_TEXCOORD11_centroid, gl_in[4].in_var_TEXCOORD11_centroid, gl_in[5].in_var_TEXCOORD11_centroid, gl_in[6].in_var_TEXCOORD11_centroid, gl_in[7].in_var_TEXCOORD11_centroid, gl_in[8].in_var_TEXCOORD11_centroid, gl_in[9].in_var_TEXCOORD11_centroid, gl_in[10].in_var_TEXCOORD11_centroid, gl_in[11].in_var_TEXCOORD11_centroid }); + spvUnsafeArray _131 = spvUnsafeArray({ gl_in[0].in_var_COLOR0, gl_in[1].in_var_COLOR0, gl_in[2].in_var_COLOR0, gl_in[3].in_var_COLOR0, gl_in[4].in_var_COLOR0, gl_in[5].in_var_COLOR0, gl_in[6].in_var_COLOR0, gl_in[7].in_var_COLOR0, gl_in[8].in_var_COLOR0, gl_in[9].in_var_COLOR0, gl_in[10].in_var_COLOR0, gl_in[11].in_var_COLOR0 }); + spvUnsafeArray, 12> _132 = spvUnsafeArray, 12>({ spvUnsafeArray({ gl_in[0].in_var_TEXCOORD0_0, gl_in[0].in_var_TEXCOORD0_1 }), spvUnsafeArray({ gl_in[1].in_var_TEXCOORD0_0, gl_in[1].in_var_TEXCOORD0_1 }), spvUnsafeArray({ gl_in[2].in_var_TEXCOORD0_0, gl_in[2].in_var_TEXCOORD0_1 }), spvUnsafeArray({ gl_in[3].in_var_TEXCOORD0_0, gl_in[3].in_var_TEXCOORD0_1 }), spvUnsafeArray({ gl_in[4].in_var_TEXCOORD0_0, gl_in[4].in_var_TEXCOORD0_1 }), spvUnsafeArray({ gl_in[5].in_var_TEXCOORD0_0, gl_in[5].in_var_TEXCOORD0_1 }), spvUnsafeArray({ gl_in[6].in_var_TEXCOORD0_0, gl_in[6].in_var_TEXCOORD0_1 }), spvUnsafeArray({ gl_in[7].in_var_TEXCOORD0_0, gl_in[7].in_var_TEXCOORD0_1 }), spvUnsafeArray({ gl_in[8].in_var_TEXCOORD0_0, gl_in[8].in_var_TEXCOORD0_1 }), spvUnsafeArray({ gl_in[9].in_var_TEXCOORD0_0, gl_in[9].in_var_TEXCOORD0_1 }), spvUnsafeArray({ gl_in[10].in_var_TEXCOORD0_0, gl_in[10].in_var_TEXCOORD0_1 }), spvUnsafeArray({ gl_in[11].in_var_TEXCOORD0_0, gl_in[11].in_var_TEXCOORD0_1 }) }); + spvUnsafeArray _205 = spvUnsafeArray({ gl_in[0].in_var_VS_To_DS_Position, gl_in[1].in_var_VS_To_DS_Position, gl_in[2].in_var_VS_To_DS_Position, gl_in[3].in_var_VS_To_DS_Position, gl_in[4].in_var_VS_To_DS_Position, gl_in[5].in_var_VS_To_DS_Position, gl_in[6].in_var_VS_To_DS_Position, gl_in[7].in_var_VS_To_DS_Position, gl_in[8].in_var_VS_To_DS_Position, gl_in[9].in_var_VS_To_DS_Position, gl_in[10].in_var_VS_To_DS_Position, gl_in[11].in_var_VS_To_DS_Position }); + spvUnsafeArray _230 = spvUnsafeArray({ FHitProxyVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _129[0], _130[0], _131[0], _132[0] } }, _205[0] }, FHitProxyVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _129[1], _130[1], _131[1], _132[1] } }, _205[1] }, FHitProxyVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _129[2], _130[2], _131[2], _132[2] } }, _205[2] }, FHitProxyVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _129[3], _130[3], _131[3], _132[3] } }, _205[3] }, FHitProxyVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _129[4], _130[4], _131[4], _132[4] } }, _205[4] }, FHitProxyVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _129[5], _130[5], _131[5], _132[5] } }, _205[5] }, FHitProxyVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _129[6], _130[6], _131[6], _132[6] } }, _205[6] }, FHitProxyVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _129[7], _130[7], _131[7], _132[7] } }, _205[7] }, FHitProxyVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _129[8], _130[8], _131[8], _132[8] } }, _205[8] }, FHitProxyVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _129[9], _130[9], _131[9], _132[9] } }, _205[9] }, FHitProxyVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _129[10], _130[10], _131[10], _132[10] } }, _205[10] }, FHitProxyVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _129[11], _130[11], _131[11], _132[11] } }, _205[11] } }); + spvUnsafeArray param_var_I; + param_var_I = _230; + float4 _247 = float4(param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld2.xyz, 0.0); + float3 _251 = Primitive.Primitive_NonUniformScale.xyz * float3x3(param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld0.xyz, cross(param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld2.xyz, param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld0.xyz) * float3(param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld2.w), param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld2.xyz); + uint _254 = (gl_InvocationID < 2u) ? (gl_InvocationID + 1u) : 0u; + uint _255 = 2u * gl_InvocationID; + uint _256 = 3u + _255; + uint _257 = _255 + 4u; + float4 _269 = float4(param_var_I[_254].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld2.xyz, 0.0); + float4 _277 = float4(param_var_I[_256].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld2.xyz, 0.0); + float4 _285 = float4(param_var_I[_257].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld2.xyz, 0.0); + spvUnsafeArray _333 = spvUnsafeArray({ param_var_I[gl_InvocationID].Position, ((((float4(2.0) * param_var_I[gl_InvocationID].Position) + param_var_I[_254].Position) - (float4(dot(param_var_I[_254].Position - param_var_I[gl_InvocationID].Position, _247)) * _247)) + (((float4(2.0) * param_var_I[_256].Position) + param_var_I[_257].Position) - (float4(dot(param_var_I[_257].Position - param_var_I[_256].Position, _277)) * _277))) * float4(0.16666667163372039794921875), ((((float4(2.0) * param_var_I[_254].Position) + param_var_I[gl_InvocationID].Position) - (float4(dot(param_var_I[gl_InvocationID].Position - param_var_I[_254].Position, _269)) * _269)) + (((float4(2.0) * param_var_I[_257].Position) + param_var_I[_256].Position) - (float4(dot(param_var_I[_256].Position - param_var_I[_257].Position, _285)) * _285))) * float4(0.16666667163372039794921875) }); + gl_out[gl_InvocationID].out_var_TEXCOORD10_centroid = param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld0; + gl_out[gl_InvocationID].out_var_TEXCOORD11_centroid = param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld2; + gl_out[gl_InvocationID].out_var_COLOR0 = param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.Color; + gl_out[gl_InvocationID].out_var_TEXCOORD0 = param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TexCoords; + gl_out[gl_InvocationID].out_var_VS_To_DS_Position = param_var_I[gl_InvocationID].Position; + gl_out[gl_InvocationID].out_var_PN_POSITION = _333; + gl_out[gl_InvocationID].out_var_PN_DisplacementScales = _251; + gl_out[gl_InvocationID].out_var_PN_TessellationMultiplier = 1.0; + gl_out[gl_InvocationID].out_var_PN_WorldDisplacementMultiplier = 1.0; + temp_var_hullMainRetVal[gl_InvocationID] = FPNTessellationHSToDS{ param_var_I[gl_InvocationID], _333, _251, 1.0, 1.0 }; + threadgroup_barrier(mem_flags::mem_device | mem_flags::mem_threadgroup); + if (gl_InvocationID == 0u) + { + float4 _385 = (((((temp_var_hullMainRetVal[0u].WorldPosition[1] + temp_var_hullMainRetVal[0u].WorldPosition[2]) + temp_var_hullMainRetVal[1u].WorldPosition[1]) + temp_var_hullMainRetVal[1u].WorldPosition[2]) + temp_var_hullMainRetVal[2u].WorldPosition[1]) + temp_var_hullMainRetVal[2u].WorldPosition[2]) * float4(0.16666667163372039794921875); + float4 _398 = _537; + _398.x = 0.5 * (temp_var_hullMainRetVal[1u].TessellationMultiplier + temp_var_hullMainRetVal[2u].TessellationMultiplier); + float4 _404 = _398; + _404.y = 0.5 * (temp_var_hullMainRetVal[2u].TessellationMultiplier + temp_var_hullMainRetVal[0u].TessellationMultiplier); + float4 _409 = _404; + _409.z = 0.5 * (temp_var_hullMainRetVal[0u].TessellationMultiplier + temp_var_hullMainRetVal[1u].TessellationMultiplier); + float4 _416 = _409; + _416.w = 0.333000004291534423828125 * ((temp_var_hullMainRetVal[0u].TessellationMultiplier + temp_var_hullMainRetVal[1u].TessellationMultiplier) + temp_var_hullMainRetVal[2u].TessellationMultiplier); + float4 _524; + for (;;) + { + float4 _424 = View.View_ViewToClip * float4(0.0); + float4 _429 = View.View_TranslatedWorldToClip * float4(temp_var_hullMainRetVal[0u].WorldPosition[0].xyz, 1.0); + float3 _430 = _429.xyz; + float3 _431 = _424.xyz; + float _433 = _429.w; + float _434 = _424.w; + float4 _451 = View.View_TranslatedWorldToClip * float4(temp_var_hullMainRetVal[1u].WorldPosition[0].xyz, 1.0); + float3 _452 = _451.xyz; + float _454 = _451.w; + float4 _472 = View.View_TranslatedWorldToClip * float4(temp_var_hullMainRetVal[2u].WorldPosition[0].xyz, 1.0); + float3 _473 = _472.xyz; + float _475 = _472.w; + if (any((((select(int3(0), int3(1), (_430 - _431) < float3(_433 + _434)) + (int3(2) * select(int3(0), int3(1), (_430 + _431) > float3((-_433) - _434)))) | (select(int3(0), int3(1), (_452 - _431) < float3(_454 + _434)) + (int3(2) * select(int3(0), int3(1), (_452 + _431) > float3((-_454) - _434))))) | (select(int3(0), int3(1), (_473 - _431) < float3(_475 + _434)) + (int3(2) * select(int3(0), int3(1), (_473 + _431) > float3((-_475) - _434))))) != int3(3))) + { + _524 = float4(0.0); + break; + } + float3 _493 = temp_var_hullMainRetVal[0u].WorldPosition[0].xyz - temp_var_hullMainRetVal[1u].WorldPosition[0].xyz; + float3 _494 = temp_var_hullMainRetVal[1u].WorldPosition[0].xyz - temp_var_hullMainRetVal[2u].WorldPosition[0].xyz; + float3 _495 = temp_var_hullMainRetVal[2u].WorldPosition[0].xyz - temp_var_hullMainRetVal[0u].WorldPosition[0].xyz; + float3 _498 = (float3(0.5) * (temp_var_hullMainRetVal[0u].WorldPosition[0].xyz + temp_var_hullMainRetVal[1u].WorldPosition[0].xyz)) - float3(View.View_TranslatedWorldCameraOrigin); + float3 _501 = (float3(0.5) * (temp_var_hullMainRetVal[1u].WorldPosition[0].xyz + temp_var_hullMainRetVal[2u].WorldPosition[0].xyz)) - float3(View.View_TranslatedWorldCameraOrigin); + float3 _504 = (float3(0.5) * (temp_var_hullMainRetVal[2u].WorldPosition[0].xyz + temp_var_hullMainRetVal[0u].WorldPosition[0].xyz)) - float3(View.View_TranslatedWorldCameraOrigin); + float _508 = sqrt(dot(_494, _494) / dot(_501, _501)); + float _512 = sqrt(dot(_495, _495) / dot(_504, _504)); + float _516 = sqrt(dot(_493, _493) / dot(_498, _498)); + float4 _521 = float4(_508, _512, _516, 1.0); + _521.w = 0.333000004291534423828125 * ((_508 + _512) + _516); + _524 = float4(View.View_AdaptiveTessellationFactor) * _521; + break; + } + float4 _526 = fast::clamp(_416 * _524, float4(1.0), float4(15.0)); + spvTessLevel[gl_PrimitiveID].edgeTessellationFactor[0u] = half(_526.x); + spvTessLevel[gl_PrimitiveID].edgeTessellationFactor[1u] = half(_526.y); + spvTessLevel[gl_PrimitiveID].edgeTessellationFactor[2u] = half(_526.z); + spvTessLevel[gl_PrimitiveID].insideTessellationFactor = half(_526.w); + patchOut.out_var_PN_POSITION9 = _385 + ((_385 - (((temp_var_hullMainRetVal[2u].WorldPosition[0] + temp_var_hullMainRetVal[1u].WorldPosition[0]) + temp_var_hullMainRetVal[0u].WorldPosition[0]) * float4(0.3333333432674407958984375))) * float4(0.5)); + } +} + diff --git a/third_party/spirv-cross/reference/opt/shaders-ue4/asm/tesc/tess-factor-must-be-threadgroup.asm.tesc b/third_party/spirv-cross/reference/opt/shaders-ue4/asm/tesc/tess-factor-must-be-threadgroup.asm.tesc new file mode 100644 index 0000000000..13ea8bb712 --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders-ue4/asm/tesc/tess-factor-must-be-threadgroup.asm.tesc @@ -0,0 +1,178 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + +#include +#include + +using namespace metal; + +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +struct FVertexFactoryInterpolantsVSToPS +{ + float4 TangentToWorld0; + float4 TangentToWorld2; +}; + +struct FVertexFactoryInterpolantsVSToDS +{ + FVertexFactoryInterpolantsVSToPS InterpolantsVSToPS; +}; + +struct FSharedBasePassInterpolants +{ +}; +struct FBasePassInterpolantsVSToDS +{ + FSharedBasePassInterpolants _m0; +}; + +struct FBasePassVSToDS +{ + FVertexFactoryInterpolantsVSToDS FactoryInterpolants; + FBasePassInterpolantsVSToDS BasePassInterpolants; + float4 Position; +}; + +struct FFlatTessellationHSToDS +{ + FBasePassVSToDS PassSpecificData; + float3 DisplacementScale; + float TessellationMultiplier; + float WorldDisplacementMultiplier; +}; + +struct type_Primitive +{ + float4x4 Primitive_LocalToWorld; + float4 Primitive_InvNonUniformScaleAndDeterminantSign; + float4 Primitive_ObjectWorldPositionAndRadius; + float4x4 Primitive_WorldToLocal; + float4x4 Primitive_PreviousLocalToWorld; + float4x4 Primitive_PreviousWorldToLocal; + packed_float3 Primitive_ActorWorldPosition; + float Primitive_UseSingleSampleShadowFromStationaryLights; + packed_float3 Primitive_ObjectBounds; + float Primitive_LpvBiasMultiplier; + float Primitive_DecalReceiverMask; + float Primitive_PerObjectGBufferData; + float Primitive_UseVolumetricLightmapShadowFromStationaryLights; + float Primitive_DrawsVelocity; + float4 Primitive_ObjectOrientation; + float4 Primitive_NonUniformScale; + packed_float3 Primitive_LocalObjectBoundsMin; + uint Primitive_LightingChannelMask; + packed_float3 Primitive_LocalObjectBoundsMax; + uint Primitive_LightmapDataIndex; + packed_float3 Primitive_PreSkinnedLocalBounds; + int Primitive_SingleCaptureIndex; + uint Primitive_OutputVelocity; + uint PrePadding_Primitive_420; + uint PrePadding_Primitive_424; + uint PrePadding_Primitive_428; + float4 Primitive_CustomPrimitiveData[4]; +}; + +struct type_Material +{ + float4 Material_VectorExpressions[3]; + float4 Material_ScalarExpressions[1]; +}; + +constant float4 _182 = {}; + +struct main0_out +{ + float3 out_var_Flat_DisplacementScales; + float out_var_Flat_TessellationMultiplier; + float out_var_Flat_WorldDisplacementMultiplier; + float4 out_var_TEXCOORD10_centroid; + float4 out_var_TEXCOORD11_centroid; + float4 out_var_VS_To_DS_Position; +}; + +struct main0_in +{ + float4 in_var_TEXCOORD10_centroid [[attribute(0)]]; + float4 in_var_TEXCOORD11_centroid [[attribute(1)]]; + float4 in_var_VS_To_DS_Position [[attribute(2)]]; +}; + +kernel void main0(main0_in in [[stage_in]], constant type_Primitive& Primitive [[buffer(0)]], constant type_Material& Material [[buffer(1)]], uint gl_InvocationID [[thread_index_in_threadgroup]], uint gl_PrimitiveID [[threadgroup_position_in_grid]], device main0_out* spvOut [[buffer(28)]], constant uint* spvIndirectParams [[buffer(29)]], device MTLTriangleTessellationFactorsHalf* spvTessLevel [[buffer(26)]], threadgroup main0_in* gl_in [[threadgroup(0)]]) +{ + threadgroup FFlatTessellationHSToDS temp_var_hullMainRetVal[3]; + device main0_out* gl_out = &spvOut[gl_PrimitiveID * 3]; + if (gl_InvocationID < spvIndirectParams[0]) + gl_in[gl_InvocationID] = in; + threadgroup_barrier(mem_flags::mem_threadgroup); + if (gl_InvocationID >= 3) + return; + spvUnsafeArray _90 = spvUnsafeArray({ gl_in[0].in_var_TEXCOORD10_centroid, gl_in[1].in_var_TEXCOORD10_centroid, gl_in[2].in_var_TEXCOORD10_centroid }); + spvUnsafeArray _91 = spvUnsafeArray({ gl_in[0].in_var_TEXCOORD11_centroid, gl_in[1].in_var_TEXCOORD11_centroid, gl_in[2].in_var_TEXCOORD11_centroid }); + spvUnsafeArray _104 = spvUnsafeArray({ gl_in[0].in_var_VS_To_DS_Position, gl_in[1].in_var_VS_To_DS_Position, gl_in[2].in_var_VS_To_DS_Position }); + spvUnsafeArray _111 = spvUnsafeArray({ FBasePassVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _90[0], _91[0] } }, FBasePassInterpolantsVSToDS{ { } }, _104[0] }, FBasePassVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _90[1], _91[1] } }, FBasePassInterpolantsVSToDS{ { } }, _104[1] }, FBasePassVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _90[2], _91[2] } }, FBasePassInterpolantsVSToDS{ { } }, _104[2] } }); + spvUnsafeArray param_var_I; + param_var_I = _111; + float3 _128 = Primitive.Primitive_NonUniformScale.xyz * float3x3(param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld0.xyz, cross(param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld2.xyz, param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld0.xyz) * float3(param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld2.w), param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld2.xyz); + gl_out[gl_InvocationID].out_var_TEXCOORD10_centroid = param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld0; + gl_out[gl_InvocationID].out_var_TEXCOORD11_centroid = param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld2; + gl_out[gl_InvocationID].out_var_VS_To_DS_Position = param_var_I[gl_InvocationID].Position; + gl_out[gl_InvocationID].out_var_Flat_DisplacementScales = _128; + gl_out[gl_InvocationID].out_var_Flat_TessellationMultiplier = Material.Material_ScalarExpressions[0].x; + gl_out[gl_InvocationID].out_var_Flat_WorldDisplacementMultiplier = 1.0; + temp_var_hullMainRetVal[gl_InvocationID] = FFlatTessellationHSToDS{ param_var_I[gl_InvocationID], _128, Material.Material_ScalarExpressions[0].x, 1.0 }; + threadgroup_barrier(mem_flags::mem_device | mem_flags::mem_threadgroup); + if (gl_InvocationID == 0u) + { + float4 _154 = _182; + _154.x = 0.5 * (temp_var_hullMainRetVal[1u].TessellationMultiplier + temp_var_hullMainRetVal[2u].TessellationMultiplier); + float4 _160 = _154; + _160.y = 0.5 * (temp_var_hullMainRetVal[2u].TessellationMultiplier + temp_var_hullMainRetVal[0u].TessellationMultiplier); + float4 _165 = _160; + _165.z = 0.5 * (temp_var_hullMainRetVal[0u].TessellationMultiplier + temp_var_hullMainRetVal[1u].TessellationMultiplier); + float4 _172 = _165; + _172.w = 0.333000004291534423828125 * ((temp_var_hullMainRetVal[0u].TessellationMultiplier + temp_var_hullMainRetVal[1u].TessellationMultiplier) + temp_var_hullMainRetVal[2u].TessellationMultiplier); + float4 _173 = fast::clamp(_172, float4(1.0), float4(15.0)); + spvTessLevel[gl_PrimitiveID].edgeTessellationFactor[0u] = half(_173.x); + spvTessLevel[gl_PrimitiveID].edgeTessellationFactor[1u] = half(_173.y); + spvTessLevel[gl_PrimitiveID].edgeTessellationFactor[2u] = half(_173.z); + spvTessLevel[gl_PrimitiveID].insideTessellationFactor = half(_173.w); + } +} + diff --git a/third_party/spirv-cross/reference/opt/shaders-ue4/asm/tese/ds-double-gl-in-deref.asm.tese b/third_party/spirv-cross/reference/opt/shaders-ue4/asm/tese/ds-double-gl-in-deref.asm.tese new file mode 100644 index 0000000000..19e402e67f --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders-ue4/asm/tese/ds-double-gl-in-deref.asm.tese @@ -0,0 +1,419 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + +#include +#include + +using namespace metal; + +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +struct type_View +{ + float4x4 View_TranslatedWorldToClip; + float4x4 View_WorldToClip; + float4x4 View_ClipToWorld; + float4x4 View_TranslatedWorldToView; + float4x4 View_ViewToTranslatedWorld; + float4x4 View_TranslatedWorldToCameraView; + float4x4 View_CameraViewToTranslatedWorld; + float4x4 View_ViewToClip; + float4x4 View_ViewToClipNoAA; + float4x4 View_ClipToView; + float4x4 View_ClipToTranslatedWorld; + float4x4 View_SVPositionToTranslatedWorld; + float4x4 View_ScreenToWorld; + float4x4 View_ScreenToTranslatedWorld; + packed_float3 View_ViewForward; + float PrePadding_View_908; + packed_float3 View_ViewUp; + float PrePadding_View_924; + packed_float3 View_ViewRight; + float PrePadding_View_940; + packed_float3 View_HMDViewNoRollUp; + float PrePadding_View_956; + packed_float3 View_HMDViewNoRollRight; + float PrePadding_View_972; + float4 View_InvDeviceZToWorldZTransform; + float4 View_ScreenPositionScaleBias; + packed_float3 View_WorldCameraOrigin; + float PrePadding_View_1020; + packed_float3 View_TranslatedWorldCameraOrigin; + float PrePadding_View_1036; + packed_float3 View_WorldViewOrigin; + float PrePadding_View_1052; + packed_float3 View_PreViewTranslation; + float PrePadding_View_1068; + float4x4 View_PrevProjection; + float4x4 View_PrevViewProj; + float4x4 View_PrevViewRotationProj; + float4x4 View_PrevViewToClip; + float4x4 View_PrevClipToView; + float4x4 View_PrevTranslatedWorldToClip; + float4x4 View_PrevTranslatedWorldToView; + float4x4 View_PrevViewToTranslatedWorld; + float4x4 View_PrevTranslatedWorldToCameraView; + float4x4 View_PrevCameraViewToTranslatedWorld; + packed_float3 View_PrevWorldCameraOrigin; + float PrePadding_View_1724; + packed_float3 View_PrevWorldViewOrigin; + float PrePadding_View_1740; + packed_float3 View_PrevPreViewTranslation; + float PrePadding_View_1756; + float4x4 View_PrevInvViewProj; + float4x4 View_PrevScreenToTranslatedWorld; + float4x4 View_ClipToPrevClip; + float4 View_TemporalAAJitter; + float4 View_GlobalClippingPlane; + float2 View_FieldOfViewWideAngles; + float2 View_PrevFieldOfViewWideAngles; + float4 View_ViewRectMin; + float4 View_ViewSizeAndInvSize; + float4 View_BufferSizeAndInvSize; + float4 View_BufferBilinearUVMinMax; + int View_NumSceneColorMSAASamples; + float View_PreExposure; + float View_OneOverPreExposure; + float PrePadding_View_2076; + float4 View_DiffuseOverrideParameter; + float4 View_SpecularOverrideParameter; + float4 View_NormalOverrideParameter; + float2 View_RoughnessOverrideParameter; + float View_PrevFrameGameTime; + float View_PrevFrameRealTime; + float View_OutOfBoundsMask; + float PrePadding_View_2148; + float PrePadding_View_2152; + float PrePadding_View_2156; + packed_float3 View_WorldCameraMovementSinceLastFrame; + float View_CullingSign; + float View_NearPlane; + float View_AdaptiveTessellationFactor; + float View_GameTime; + float View_RealTime; + float View_DeltaTime; + float View_MaterialTextureMipBias; + float View_MaterialTextureDerivativeMultiply; + uint View_Random; + uint View_FrameNumber; + uint View_StateFrameIndexMod8; + uint View_StateFrameIndex; + float View_CameraCut; + float View_UnlitViewmodeMask; + float PrePadding_View_2228; + float PrePadding_View_2232; + float PrePadding_View_2236; + float4 View_DirectionalLightColor; + packed_float3 View_DirectionalLightDirection; + float PrePadding_View_2268; + float4 View_TranslucencyLightingVolumeMin[2]; + float4 View_TranslucencyLightingVolumeInvSize[2]; + float4 View_TemporalAAParams; + float4 View_CircleDOFParams; + float View_DepthOfFieldSensorWidth; + float View_DepthOfFieldFocalDistance; + float View_DepthOfFieldScale; + float View_DepthOfFieldFocalLength; + float View_DepthOfFieldFocalRegion; + float View_DepthOfFieldNearTransitionRegion; + float View_DepthOfFieldFarTransitionRegion; + float View_MotionBlurNormalizedToPixel; + float View_bSubsurfacePostprocessEnabled; + float View_GeneralPurposeTweak; + float View_DemosaicVposOffset; + float PrePadding_View_2412; + packed_float3 View_IndirectLightingColorScale; + float View_HDR32bppEncodingMode; + packed_float3 View_AtmosphericFogSunDirection; + float View_AtmosphericFogSunPower; + float View_AtmosphericFogPower; + float View_AtmosphericFogDensityScale; + float View_AtmosphericFogDensityOffset; + float View_AtmosphericFogGroundOffset; + float View_AtmosphericFogDistanceScale; + float View_AtmosphericFogAltitudeScale; + float View_AtmosphericFogHeightScaleRayleigh; + float View_AtmosphericFogStartDistance; + float View_AtmosphericFogDistanceOffset; + float View_AtmosphericFogSunDiscScale; + float View_AtmosphericFogSunDiscHalfApexAngleRadian; + float PrePadding_View_2492; + float4 View_AtmosphericFogSunDiscLuminance; + uint View_AtmosphericFogRenderMask; + uint View_AtmosphericFogInscatterAltitudeSampleNum; + uint PrePadding_View_2520; + uint PrePadding_View_2524; + float4 View_AtmosphericFogSunColor; + packed_float3 View_NormalCurvatureToRoughnessScaleBias; + float View_RenderingReflectionCaptureMask; + float4 View_AmbientCubemapTint; + float View_AmbientCubemapIntensity; + float View_SkyLightParameters; + float PrePadding_View_2584; + float PrePadding_View_2588; + float4 View_SkyLightColor; + float4 View_SkyIrradianceEnvironmentMap[7]; + float View_MobilePreviewMode; + float View_HMDEyePaddingOffset; + float View_ReflectionCubemapMaxMip; + float View_ShowDecalsMask; + uint View_DistanceFieldAOSpecularOcclusionMode; + float View_IndirectCapsuleSelfShadowingIntensity; + float PrePadding_View_2744; + float PrePadding_View_2748; + packed_float3 View_ReflectionEnvironmentRoughnessMixingScaleBiasAndLargestWeight; + int View_StereoPassIndex; + float4 View_GlobalVolumeCenterAndExtent[4]; + float4 View_GlobalVolumeWorldToUVAddAndMul[4]; + float View_GlobalVolumeDimension; + float View_GlobalVolumeTexelSize; + float View_MaxGlobalDistance; + float PrePadding_View_2908; + int2 View_CursorPosition; + float View_bCheckerboardSubsurfaceProfileRendering; + float PrePadding_View_2924; + packed_float3 View_VolumetricFogInvGridSize; + float PrePadding_View_2940; + packed_float3 View_VolumetricFogGridZParams; + float PrePadding_View_2956; + float2 View_VolumetricFogSVPosToVolumeUV; + float View_VolumetricFogMaxDistance; + float PrePadding_View_2972; + packed_float3 View_VolumetricLightmapWorldToUVScale; + float PrePadding_View_2988; + packed_float3 View_VolumetricLightmapWorldToUVAdd; + float PrePadding_View_3004; + packed_float3 View_VolumetricLightmapIndirectionTextureSize; + float View_VolumetricLightmapBrickSize; + packed_float3 View_VolumetricLightmapBrickTexelSize; + float View_StereoIPD; + float View_IndirectLightingCacheShowFlag; + float View_EyeToPixelSpreadAngle; +}; + +struct type_ShadowDepthPass +{ + float PrePadding_ShadowDepthPass_LPV_0; + float PrePadding_ShadowDepthPass_LPV_4; + float PrePadding_ShadowDepthPass_LPV_8; + float PrePadding_ShadowDepthPass_LPV_12; + float PrePadding_ShadowDepthPass_LPV_16; + float PrePadding_ShadowDepthPass_LPV_20; + float PrePadding_ShadowDepthPass_LPV_24; + float PrePadding_ShadowDepthPass_LPV_28; + float PrePadding_ShadowDepthPass_LPV_32; + float PrePadding_ShadowDepthPass_LPV_36; + float PrePadding_ShadowDepthPass_LPV_40; + float PrePadding_ShadowDepthPass_LPV_44; + float PrePadding_ShadowDepthPass_LPV_48; + float PrePadding_ShadowDepthPass_LPV_52; + float PrePadding_ShadowDepthPass_LPV_56; + float PrePadding_ShadowDepthPass_LPV_60; + float PrePadding_ShadowDepthPass_LPV_64; + float PrePadding_ShadowDepthPass_LPV_68; + float PrePadding_ShadowDepthPass_LPV_72; + float PrePadding_ShadowDepthPass_LPV_76; + float PrePadding_ShadowDepthPass_LPV_80; + float PrePadding_ShadowDepthPass_LPV_84; + float PrePadding_ShadowDepthPass_LPV_88; + float PrePadding_ShadowDepthPass_LPV_92; + float PrePadding_ShadowDepthPass_LPV_96; + float PrePadding_ShadowDepthPass_LPV_100; + float PrePadding_ShadowDepthPass_LPV_104; + float PrePadding_ShadowDepthPass_LPV_108; + float PrePadding_ShadowDepthPass_LPV_112; + float PrePadding_ShadowDepthPass_LPV_116; + float PrePadding_ShadowDepthPass_LPV_120; + float PrePadding_ShadowDepthPass_LPV_124; + float PrePadding_ShadowDepthPass_LPV_128; + float PrePadding_ShadowDepthPass_LPV_132; + float PrePadding_ShadowDepthPass_LPV_136; + float PrePadding_ShadowDepthPass_LPV_140; + float PrePadding_ShadowDepthPass_LPV_144; + float PrePadding_ShadowDepthPass_LPV_148; + float PrePadding_ShadowDepthPass_LPV_152; + float PrePadding_ShadowDepthPass_LPV_156; + float PrePadding_ShadowDepthPass_LPV_160; + float PrePadding_ShadowDepthPass_LPV_164; + float PrePadding_ShadowDepthPass_LPV_168; + float PrePadding_ShadowDepthPass_LPV_172; + float PrePadding_ShadowDepthPass_LPV_176; + float PrePadding_ShadowDepthPass_LPV_180; + float PrePadding_ShadowDepthPass_LPV_184; + float PrePadding_ShadowDepthPass_LPV_188; + float PrePadding_ShadowDepthPass_LPV_192; + float PrePadding_ShadowDepthPass_LPV_196; + float PrePadding_ShadowDepthPass_LPV_200; + float PrePadding_ShadowDepthPass_LPV_204; + float PrePadding_ShadowDepthPass_LPV_208; + float PrePadding_ShadowDepthPass_LPV_212; + float PrePadding_ShadowDepthPass_LPV_216; + float PrePadding_ShadowDepthPass_LPV_220; + float PrePadding_ShadowDepthPass_LPV_224; + float PrePadding_ShadowDepthPass_LPV_228; + float PrePadding_ShadowDepthPass_LPV_232; + float PrePadding_ShadowDepthPass_LPV_236; + float PrePadding_ShadowDepthPass_LPV_240; + float PrePadding_ShadowDepthPass_LPV_244; + float PrePadding_ShadowDepthPass_LPV_248; + float PrePadding_ShadowDepthPass_LPV_252; + float PrePadding_ShadowDepthPass_LPV_256; + float PrePadding_ShadowDepthPass_LPV_260; + float PrePadding_ShadowDepthPass_LPV_264; + float PrePadding_ShadowDepthPass_LPV_268; + float4x4 ShadowDepthPass_LPV_mRsmToWorld; + float4 ShadowDepthPass_LPV_mLightColour; + float4 ShadowDepthPass_LPV_GeometryVolumeCaptureLightDirection; + float4 ShadowDepthPass_LPV_mEyePos; + packed_int3 ShadowDepthPass_LPV_mOldGridOffset; + int PrePadding_ShadowDepthPass_LPV_396; + packed_int3 ShadowDepthPass_LPV_mLpvGridOffset; + float ShadowDepthPass_LPV_ClearMultiplier; + float ShadowDepthPass_LPV_LpvScale; + float ShadowDepthPass_LPV_OneOverLpvScale; + float ShadowDepthPass_LPV_DirectionalOcclusionIntensity; + float ShadowDepthPass_LPV_DirectionalOcclusionRadius; + float ShadowDepthPass_LPV_RsmAreaIntensityMultiplier; + float ShadowDepthPass_LPV_RsmPixelToTexcoordMultiplier; + float ShadowDepthPass_LPV_SecondaryOcclusionStrength; + float ShadowDepthPass_LPV_SecondaryBounceStrength; + float ShadowDepthPass_LPV_VplInjectionBias; + float ShadowDepthPass_LPV_GeometryVolumeInjectionBias; + float ShadowDepthPass_LPV_EmissiveInjectionMultiplier; + int ShadowDepthPass_LPV_PropagationIndex; + float4x4 ShadowDepthPass_ProjectionMatrix; + float4x4 ShadowDepthPass_ViewMatrix; + float4 ShadowDepthPass_ShadowParams; + float ShadowDepthPass_bClampToNearPlane; + float PrePadding_ShadowDepthPass_612; + float PrePadding_ShadowDepthPass_616; + float PrePadding_ShadowDepthPass_620; + float4x4 ShadowDepthPass_ShadowViewProjectionMatrices[6]; + float4x4 ShadowDepthPass_ShadowViewMatrices[6]; +}; + +constant float4 _113 = {}; + +struct main0_out +{ + float4 out_var_TEXCOORD10_centroid [[user(locn0)]]; + float4 out_var_TEXCOORD11_centroid [[user(locn1)]]; + float4 out_var_COLOR0 [[user(locn2)]]; + float4 out_var_TEXCOORD0_0 [[user(locn3)]]; + uint out_var_PRIMITIVE_ID [[user(locn4)]]; + float out_var_TEXCOORD6 [[user(locn5)]]; + float out_var_TEXCOORD8 [[user(locn6)]]; + float3 out_var_TEXCOORD7 [[user(locn7)]]; + float4 gl_Position [[position]]; +}; + +struct main0_in +{ + float4 in_var_COLOR0 [[attribute(0)]]; + float4 in_var_PN_POSITION_0 [[attribute(2)]]; + float4 in_var_PN_POSITION_1 [[attribute(3)]]; + float4 in_var_PN_POSITION_2 [[attribute(4)]]; + float in_var_PN_WorldDisplacementMultiplier [[attribute(7)]]; + uint in_var_PRIMITIVE_ID [[attribute(8)]]; + float4 in_var_TEXCOORD0_0 [[attribute(9)]]; + float4 in_var_TEXCOORD10_centroid [[attribute(10)]]; + float4 in_var_TEXCOORD11_centroid [[attribute(11)]]; +}; + +struct main0_patchIn +{ + float4 in_var_PN_POSITION9 [[attribute(5)]]; + patch_control_point gl_in; +}; + +[[ patch(triangle, 0) ]] vertex main0_out main0(main0_patchIn patchIn [[stage_in]], constant type_View& View [[buffer(0)]], constant type_ShadowDepthPass& ShadowDepthPass [[buffer(1)]], texture2d Material_Texture2D_3 [[texture(0)]], sampler Material_Texture2D_3Sampler [[sampler(0)]], float3 gl_TessCoord [[position_in_patch]]) +{ + main0_out out = {}; + spvUnsafeArray out_var_TEXCOORD0 = {}; + spvUnsafeArray _117 = spvUnsafeArray({ patchIn.gl_in[0].in_var_TEXCOORD10_centroid, patchIn.gl_in[1].in_var_TEXCOORD10_centroid, patchIn.gl_in[2].in_var_TEXCOORD10_centroid }); + spvUnsafeArray _118 = spvUnsafeArray({ patchIn.gl_in[0].in_var_TEXCOORD11_centroid, patchIn.gl_in[1].in_var_TEXCOORD11_centroid, patchIn.gl_in[2].in_var_TEXCOORD11_centroid }); + spvUnsafeArray _119 = spvUnsafeArray({ patchIn.gl_in[0].in_var_COLOR0, patchIn.gl_in[1].in_var_COLOR0, patchIn.gl_in[2].in_var_COLOR0 }); + spvUnsafeArray, 3> _120 = spvUnsafeArray, 3>({ spvUnsafeArray({ patchIn.gl_in[0].in_var_TEXCOORD0_0 }), spvUnsafeArray({ patchIn.gl_in[1].in_var_TEXCOORD0_0 }), spvUnsafeArray({ patchIn.gl_in[2].in_var_TEXCOORD0_0 }) }); + spvUnsafeArray, 3> _135 = spvUnsafeArray, 3>({ spvUnsafeArray({ patchIn.gl_in[0].in_var_PN_POSITION_0, patchIn.gl_in[0].in_var_PN_POSITION_1, patchIn.gl_in[0].in_var_PN_POSITION_2 }), spvUnsafeArray({ patchIn.gl_in[1].in_var_PN_POSITION_0, patchIn.gl_in[1].in_var_PN_POSITION_1, patchIn.gl_in[1].in_var_PN_POSITION_2 }), spvUnsafeArray({ patchIn.gl_in[2].in_var_PN_POSITION_0, patchIn.gl_in[2].in_var_PN_POSITION_1, patchIn.gl_in[2].in_var_PN_POSITION_2 }) }); + spvUnsafeArray _136 = spvUnsafeArray({ patchIn.gl_in[0].in_var_PN_WorldDisplacementMultiplier, patchIn.gl_in[1].in_var_PN_WorldDisplacementMultiplier, patchIn.gl_in[2].in_var_PN_WorldDisplacementMultiplier }); + float _157 = gl_TessCoord.x * gl_TessCoord.x; + float _158 = gl_TessCoord.y * gl_TessCoord.y; + float _159 = gl_TessCoord.z * gl_TessCoord.z; + float4 _165 = float4(gl_TessCoord.x); + float4 _169 = float4(gl_TessCoord.y); + float4 _174 = float4(gl_TessCoord.z); + float4 _177 = float4(_157 * 3.0); + float4 _181 = float4(_158 * 3.0); + float4 _188 = float4(_159 * 3.0); + float4 _202 = ((((((((((_135[0][0] * float4(_157)) * _165) + ((_135[1][0] * float4(_158)) * _169)) + ((_135[2][0] * float4(_159)) * _174)) + ((_135[0][1] * _177) * _169)) + ((_135[0][2] * _181) * _165)) + ((_135[1][1] * _181) * _174)) + ((_135[1][2] * _188) * _169)) + ((_135[2][1] * _188) * _165)) + ((_135[2][2] * _177) * _174)) + ((((patchIn.in_var_PN_POSITION9 * float4(6.0)) * _174) * _165) * _169); + float3 _226 = ((_117[0].xyz * float3(gl_TessCoord.x)) + (_117[1].xyz * float3(gl_TessCoord.y))).xyz + (_117[2].xyz * float3(gl_TessCoord.z)); + float4 _229 = ((_118[0] * _165) + (_118[1] * _169)) + (_118[2] * _174); + float4 _231 = ((_119[0] * _165) + (_119[1] * _169)) + (_119[2] * _174); + float4 _233 = ((_120[0][0] * _165) + (_120[1][0] * _169)) + (_120[2][0] * _174); + spvUnsafeArray _234 = spvUnsafeArray({ _233 }); + float3 _236 = _229.xyz; + float3 _264 = _202.xyz + (((float3((Material_Texture2D_3.sample(Material_Texture2D_3Sampler, (float2(View.View_GameTime * 0.20000000298023223876953125, View.View_GameTime * (-0.699999988079071044921875)) + (_233.zw * float2(1.0, 2.0))), level(-1.0)).x * 10.0) * (1.0 - _231.x)) * _236) * float3(0.5)) * float3(((_136[0] * gl_TessCoord.x) + (_136[1] * gl_TessCoord.y)) + (_136[2] * gl_TessCoord.z))); + float4 _270 = ShadowDepthPass.ShadowDepthPass_ProjectionMatrix * float4(_264.x, _264.y, _264.z, _202.w); + float4 _281; + if ((ShadowDepthPass.ShadowDepthPass_bClampToNearPlane > 0.0) && (_270.z < 0.0)) + { + float4 _279 = _270; + _279.z = 9.9999999747524270787835121154785e-07; + float4 _280 = _279; + _280.w = 1.0; + _281 = _280; + } + else + { + _281 = _270; + } + float _290 = abs(dot(float3(ShadowDepthPass.ShadowDepthPass_ViewMatrix[0].z, ShadowDepthPass.ShadowDepthPass_ViewMatrix[1].z, ShadowDepthPass.ShadowDepthPass_ViewMatrix[2].z), _236)); + out.out_var_TEXCOORD10_centroid = float4(_226.x, _226.y, _226.z, _113.w); + out.out_var_TEXCOORD11_centroid = _229; + out.out_var_COLOR0 = _231; + out_var_TEXCOORD0 = _234; + out.out_var_PRIMITIVE_ID = patchIn.gl_in[0u].in_var_PRIMITIVE_ID; + out.out_var_TEXCOORD6 = _281.z; + out.out_var_TEXCOORD8 = (ShadowDepthPass.ShadowDepthPass_ShadowParams.y * fast::clamp((abs(_290) > 0.0) ? (sqrt(fast::clamp(1.0 - (_290 * _290), 0.0, 1.0)) / _290) : ShadowDepthPass.ShadowDepthPass_ShadowParams.z, 0.0, ShadowDepthPass.ShadowDepthPass_ShadowParams.z)) + ShadowDepthPass.ShadowDepthPass_ShadowParams.x; + out.out_var_TEXCOORD7 = _264.xyz; + out.gl_Position = _281; + out.out_var_TEXCOORD0_0 = out_var_TEXCOORD0[0]; + return out; +} + diff --git a/third_party/spirv-cross/reference/opt/shaders-ue4/asm/tese/ds-patch-input-fixes.asm.tese b/third_party/spirv-cross/reference/opt/shaders-ue4/asm/tese/ds-patch-input-fixes.asm.tese new file mode 100644 index 0000000000..738b073a1d --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders-ue4/asm/tese/ds-patch-input-fixes.asm.tese @@ -0,0 +1,417 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + +#include +#include + +using namespace metal; + +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +struct type_View +{ + float4x4 View_TranslatedWorldToClip; + float4x4 View_WorldToClip; + float4x4 View_ClipToWorld; + float4x4 View_TranslatedWorldToView; + float4x4 View_ViewToTranslatedWorld; + float4x4 View_TranslatedWorldToCameraView; + float4x4 View_CameraViewToTranslatedWorld; + float4x4 View_ViewToClip; + float4x4 View_ViewToClipNoAA; + float4x4 View_ClipToView; + float4x4 View_ClipToTranslatedWorld; + float4x4 View_SVPositionToTranslatedWorld; + float4x4 View_ScreenToWorld; + float4x4 View_ScreenToTranslatedWorld; + packed_float3 View_ViewForward; + float PrePadding_View_908; + packed_float3 View_ViewUp; + float PrePadding_View_924; + packed_float3 View_ViewRight; + float PrePadding_View_940; + packed_float3 View_HMDViewNoRollUp; + float PrePadding_View_956; + packed_float3 View_HMDViewNoRollRight; + float PrePadding_View_972; + float4 View_InvDeviceZToWorldZTransform; + float4 View_ScreenPositionScaleBias; + packed_float3 View_WorldCameraOrigin; + float PrePadding_View_1020; + packed_float3 View_TranslatedWorldCameraOrigin; + float PrePadding_View_1036; + packed_float3 View_WorldViewOrigin; + float PrePadding_View_1052; + packed_float3 View_PreViewTranslation; + float PrePadding_View_1068; + float4x4 View_PrevProjection; + float4x4 View_PrevViewProj; + float4x4 View_PrevViewRotationProj; + float4x4 View_PrevViewToClip; + float4x4 View_PrevClipToView; + float4x4 View_PrevTranslatedWorldToClip; + float4x4 View_PrevTranslatedWorldToView; + float4x4 View_PrevViewToTranslatedWorld; + float4x4 View_PrevTranslatedWorldToCameraView; + float4x4 View_PrevCameraViewToTranslatedWorld; + packed_float3 View_PrevWorldCameraOrigin; + float PrePadding_View_1724; + packed_float3 View_PrevWorldViewOrigin; + float PrePadding_View_1740; + packed_float3 View_PrevPreViewTranslation; + float PrePadding_View_1756; + float4x4 View_PrevInvViewProj; + float4x4 View_PrevScreenToTranslatedWorld; + float4x4 View_ClipToPrevClip; + float4 View_TemporalAAJitter; + float4 View_GlobalClippingPlane; + float2 View_FieldOfViewWideAngles; + float2 View_PrevFieldOfViewWideAngles; + float4 View_ViewRectMin; + float4 View_ViewSizeAndInvSize; + float4 View_BufferSizeAndInvSize; + float4 View_BufferBilinearUVMinMax; + int View_NumSceneColorMSAASamples; + float View_PreExposure; + float View_OneOverPreExposure; + float PrePadding_View_2076; + float4 View_DiffuseOverrideParameter; + float4 View_SpecularOverrideParameter; + float4 View_NormalOverrideParameter; + float2 View_RoughnessOverrideParameter; + float View_PrevFrameGameTime; + float View_PrevFrameRealTime; + float View_OutOfBoundsMask; + float PrePadding_View_2148; + float PrePadding_View_2152; + float PrePadding_View_2156; + packed_float3 View_WorldCameraMovementSinceLastFrame; + float View_CullingSign; + float View_NearPlane; + float View_AdaptiveTessellationFactor; + float View_GameTime; + float View_RealTime; + float View_DeltaTime; + float View_MaterialTextureMipBias; + float View_MaterialTextureDerivativeMultiply; + uint View_Random; + uint View_FrameNumber; + uint View_StateFrameIndexMod8; + uint View_StateFrameIndex; + float View_CameraCut; + float View_UnlitViewmodeMask; + float PrePadding_View_2228; + float PrePadding_View_2232; + float PrePadding_View_2236; + float4 View_DirectionalLightColor; + packed_float3 View_DirectionalLightDirection; + float PrePadding_View_2268; + float4 View_TranslucencyLightingVolumeMin[2]; + float4 View_TranslucencyLightingVolumeInvSize[2]; + float4 View_TemporalAAParams; + float4 View_CircleDOFParams; + float View_DepthOfFieldSensorWidth; + float View_DepthOfFieldFocalDistance; + float View_DepthOfFieldScale; + float View_DepthOfFieldFocalLength; + float View_DepthOfFieldFocalRegion; + float View_DepthOfFieldNearTransitionRegion; + float View_DepthOfFieldFarTransitionRegion; + float View_MotionBlurNormalizedToPixel; + float View_bSubsurfacePostprocessEnabled; + float View_GeneralPurposeTweak; + float View_DemosaicVposOffset; + float PrePadding_View_2412; + packed_float3 View_IndirectLightingColorScale; + float View_HDR32bppEncodingMode; + packed_float3 View_AtmosphericFogSunDirection; + float View_AtmosphericFogSunPower; + float View_AtmosphericFogPower; + float View_AtmosphericFogDensityScale; + float View_AtmosphericFogDensityOffset; + float View_AtmosphericFogGroundOffset; + float View_AtmosphericFogDistanceScale; + float View_AtmosphericFogAltitudeScale; + float View_AtmosphericFogHeightScaleRayleigh; + float View_AtmosphericFogStartDistance; + float View_AtmosphericFogDistanceOffset; + float View_AtmosphericFogSunDiscScale; + float View_AtmosphericFogSunDiscHalfApexAngleRadian; + float PrePadding_View_2492; + float4 View_AtmosphericFogSunDiscLuminance; + uint View_AtmosphericFogRenderMask; + uint View_AtmosphericFogInscatterAltitudeSampleNum; + uint PrePadding_View_2520; + uint PrePadding_View_2524; + float4 View_AtmosphericFogSunColor; + packed_float3 View_NormalCurvatureToRoughnessScaleBias; + float View_RenderingReflectionCaptureMask; + float4 View_AmbientCubemapTint; + float View_AmbientCubemapIntensity; + float View_SkyLightParameters; + float PrePadding_View_2584; + float PrePadding_View_2588; + float4 View_SkyLightColor; + float4 View_SkyIrradianceEnvironmentMap[7]; + float View_MobilePreviewMode; + float View_HMDEyePaddingOffset; + float View_ReflectionCubemapMaxMip; + float View_ShowDecalsMask; + uint View_DistanceFieldAOSpecularOcclusionMode; + float View_IndirectCapsuleSelfShadowingIntensity; + float PrePadding_View_2744; + float PrePadding_View_2748; + packed_float3 View_ReflectionEnvironmentRoughnessMixingScaleBiasAndLargestWeight; + int View_StereoPassIndex; + float4 View_GlobalVolumeCenterAndExtent[4]; + float4 View_GlobalVolumeWorldToUVAddAndMul[4]; + float View_GlobalVolumeDimension; + float View_GlobalVolumeTexelSize; + float View_MaxGlobalDistance; + float PrePadding_View_2908; + int2 View_CursorPosition; + float View_bCheckerboardSubsurfaceProfileRendering; + float PrePadding_View_2924; + packed_float3 View_VolumetricFogInvGridSize; + float PrePadding_View_2940; + packed_float3 View_VolumetricFogGridZParams; + float PrePadding_View_2956; + float2 View_VolumetricFogSVPosToVolumeUV; + float View_VolumetricFogMaxDistance; + float PrePadding_View_2972; + packed_float3 View_VolumetricLightmapWorldToUVScale; + float PrePadding_View_2988; + packed_float3 View_VolumetricLightmapWorldToUVAdd; + float PrePadding_View_3004; + packed_float3 View_VolumetricLightmapIndirectionTextureSize; + float View_VolumetricLightmapBrickSize; + packed_float3 View_VolumetricLightmapBrickTexelSize; + float View_StereoIPD; + float View_IndirectLightingCacheShowFlag; + float View_EyeToPixelSpreadAngle; + float PrePadding_View_3048; + float PrePadding_View_3052; + float4x4 View_WorldToVirtualTexture; + float4 View_VirtualTextureParams; + float4 View_XRPassthroughCameraUVs[2]; +}; + +struct type_Material +{ + float4 Material_VectorExpressions[5]; + float4 Material_ScalarExpressions[2]; +}; + +constant float4 _118 = {}; + +struct main0_out +{ + float4 out_var_TEXCOORD6 [[user(locn0)]]; + float4 out_var_TEXCOORD7 [[user(locn1)]]; + float4 out_var_TEXCOORD10_centroid [[user(locn2)]]; + float4 out_var_TEXCOORD11_centroid [[user(locn3)]]; + float gl_ClipDistance [[clip_distance]] [1]; + float gl_ClipDistance_0 [[user(clip0)]]; + float4 gl_Position [[position]]; +}; + +struct main0_in +{ + float4 in_var_PN_DominantEdge2 [[attribute(3)]]; + float4 in_var_PN_DominantEdge3 [[attribute(4)]]; + float3 in_var_PN_DominantEdge4 [[attribute(5)]]; + float3 in_var_PN_DominantEdge5 [[attribute(6)]]; + float4 in_var_PN_DominantVertex1 [[attribute(8)]]; + float3 in_var_PN_DominantVertex2 [[attribute(9)]]; + float4 in_var_PN_POSITION_0 [[attribute(10)]]; + float4 in_var_PN_POSITION_1 [[attribute(11)]]; + float4 in_var_PN_POSITION_2 [[attribute(12)]]; + float in_var_PN_WorldDisplacementMultiplier [[attribute(15)]]; + float4 in_var_TEXCOORD10_centroid [[attribute(16)]]; + float4 in_var_TEXCOORD11_centroid [[attribute(17)]]; + float4 in_var_TEXCOORD6 [[attribute(18)]]; + float4 in_var_TEXCOORD8 [[attribute(19)]]; +}; + +struct main0_patchIn +{ + float4 in_var_PN_POSITION9 [[attribute(13)]]; + patch_control_point gl_in; +}; + +[[ patch(triangle, 0) ]] vertex main0_out main0(main0_patchIn patchIn [[stage_in]], constant type_View& View [[buffer(0)]], constant type_Material& Material [[buffer(1)]], texture3d View_GlobalDistanceFieldTexture0 [[texture(0)]], texture3d View_GlobalDistanceFieldTexture1 [[texture(1)]], texture3d View_GlobalDistanceFieldTexture2 [[texture(2)]], texture3d View_GlobalDistanceFieldTexture3 [[texture(3)]], sampler View_GlobalDistanceFieldSampler0 [[sampler(0)]], float3 gl_TessCoord [[position_in_patch]]) +{ + main0_out out = {}; + spvUnsafeArray _120 = spvUnsafeArray({ patchIn.gl_in[0].in_var_TEXCOORD6, patchIn.gl_in[1].in_var_TEXCOORD6, patchIn.gl_in[2].in_var_TEXCOORD6 }); + spvUnsafeArray _121 = spvUnsafeArray({ patchIn.gl_in[0].in_var_TEXCOORD8, patchIn.gl_in[1].in_var_TEXCOORD8, patchIn.gl_in[2].in_var_TEXCOORD8 }); + spvUnsafeArray _128 = spvUnsafeArray({ patchIn.gl_in[0].in_var_TEXCOORD10_centroid, patchIn.gl_in[1].in_var_TEXCOORD10_centroid, patchIn.gl_in[2].in_var_TEXCOORD10_centroid }); + spvUnsafeArray _129 = spvUnsafeArray({ patchIn.gl_in[0].in_var_TEXCOORD11_centroid, patchIn.gl_in[1].in_var_TEXCOORD11_centroid, patchIn.gl_in[2].in_var_TEXCOORD11_centroid }); + spvUnsafeArray, 3> _136 = spvUnsafeArray, 3>({ spvUnsafeArray({ patchIn.gl_in[0].in_var_PN_POSITION_0, patchIn.gl_in[0].in_var_PN_POSITION_1, patchIn.gl_in[0].in_var_PN_POSITION_2 }), spvUnsafeArray({ patchIn.gl_in[1].in_var_PN_POSITION_0, patchIn.gl_in[1].in_var_PN_POSITION_1, patchIn.gl_in[1].in_var_PN_POSITION_2 }), spvUnsafeArray({ patchIn.gl_in[2].in_var_PN_POSITION_0, patchIn.gl_in[2].in_var_PN_POSITION_1, patchIn.gl_in[2].in_var_PN_POSITION_2 }) }); + spvUnsafeArray _137 = spvUnsafeArray({ patchIn.gl_in[0].in_var_PN_WorldDisplacementMultiplier, patchIn.gl_in[1].in_var_PN_WorldDisplacementMultiplier, patchIn.gl_in[2].in_var_PN_WorldDisplacementMultiplier }); + spvUnsafeArray _138 = spvUnsafeArray({ patchIn.gl_in[0].in_var_PN_DominantVertex1, patchIn.gl_in[1].in_var_PN_DominantVertex1, patchIn.gl_in[2].in_var_PN_DominantVertex1 }); + spvUnsafeArray _139 = spvUnsafeArray({ patchIn.gl_in[0].in_var_PN_DominantVertex2, patchIn.gl_in[1].in_var_PN_DominantVertex2, patchIn.gl_in[2].in_var_PN_DominantVertex2 }); + spvUnsafeArray _146 = spvUnsafeArray({ patchIn.gl_in[0].in_var_PN_DominantEdge2, patchIn.gl_in[1].in_var_PN_DominantEdge2, patchIn.gl_in[2].in_var_PN_DominantEdge2 }); + spvUnsafeArray _147 = spvUnsafeArray({ patchIn.gl_in[0].in_var_PN_DominantEdge3, patchIn.gl_in[1].in_var_PN_DominantEdge3, patchIn.gl_in[2].in_var_PN_DominantEdge3 }); + spvUnsafeArray _148 = spvUnsafeArray({ patchIn.gl_in[0].in_var_PN_DominantEdge4, patchIn.gl_in[1].in_var_PN_DominantEdge4, patchIn.gl_in[2].in_var_PN_DominantEdge4 }); + spvUnsafeArray _149 = spvUnsafeArray({ patchIn.gl_in[0].in_var_PN_DominantEdge5, patchIn.gl_in[1].in_var_PN_DominantEdge5, patchIn.gl_in[2].in_var_PN_DominantEdge5 }); + float _190 = gl_TessCoord.x * gl_TessCoord.x; + float _191 = gl_TessCoord.y * gl_TessCoord.y; + float _192 = gl_TessCoord.z * gl_TessCoord.z; + float4 _198 = float4(gl_TessCoord.x); + float4 _202 = float4(gl_TessCoord.y); + float4 _207 = float4(gl_TessCoord.z); + float4 _210 = float4(_190 * 3.0); + float4 _214 = float4(_191 * 3.0); + float4 _221 = float4(_192 * 3.0); + float4 _235 = ((((((((((_136[0][0] * float4(_190)) * _198) + ((_136[1][0] * float4(_191)) * _202)) + ((_136[2][0] * float4(_192)) * _207)) + ((_136[0][1] * _210) * _202)) + ((_136[0][2] * _214) * _198)) + ((_136[1][1] * _214) * _207)) + ((_136[1][2] * _221) * _202)) + ((_136[2][1] * _221) * _198)) + ((_136[2][2] * _210) * _207)) + ((((patchIn.in_var_PN_POSITION9 * float4(6.0)) * _207) * _198) * _202); + float3 _237 = float3(gl_TessCoord.x); + float3 _240 = float3(gl_TessCoord.y); + float3 _254 = float3(gl_TessCoord.z); + float3 _256 = ((_128[0].xyz * _237) + (_128[1].xyz * _240)).xyz + (_128[2].xyz * _254); + float4 _259 = ((_129[0] * _198) + (_129[1] * _202)) + (_129[2] * _207); + float3 _264 = _235.xyz; + float3 _265 = _256.xyz; + float3 _266 = _259.xyz; + float3 _272 = _264 + float3(View.View_WorldCameraOrigin); + float _279 = float(int(gl_TessCoord.x == 0.0)); + float _282 = float(int(gl_TessCoord.y == 0.0)); + float _285 = float(int(gl_TessCoord.z == 0.0)); + float _286 = _279 + _282; + float _287 = _286 + _285; + float4 _387; + float3 _388; + if (float(int(_287 == 2.0)) == 1.0) + { + float _363 = float(int((_282 + _285) == 2.0)); + float _367 = float(int((_285 + _279) == 2.0)); + float _370 = float(int(_286 == 2.0)); + _387 = ((float4(_363) * _138[0]) + (float4(_367) * _138[1])) + (float4(_370) * _138[2]); + _388 = ((float3(_363) * _139[0]) + (float3(_367) * _139[1])) + (float3(_370) * _139[2]); + } + else + { + float4 _358; + float3 _359; + if (float(int(_287 == 1.0)) != 0.0) + { + float4 _304 = float4(_279); + float4 _306 = float4(_282); + float4 _309 = float4(_285); + float4 _311 = ((_304 * _146[0]) + (_306 * _146[1])) + (_309 * _146[2]); + float4 _316 = ((_304 * _147[0]) + (_306 * _147[1])) + (_309 * _147[2]); + float3 _331 = float3(_279); + float3 _333 = float3(_282); + float3 _336 = float3(_285); + float3 _338 = ((_331 * _148[0]) + (_333 * _148[1])) + (_336 * _148[2]); + float3 _343 = ((_331 * _149[0]) + (_333 * _149[1])) + (_336 * _149[2]); + _358 = ((_304 * ((_202 * _311) + (_207 * _316))) + (_306 * ((_207 * _311) + (_198 * _316)))) + (_309 * ((_198 * _311) + (_202 * _316))); + _359 = ((_331 * ((_240 * _338) + (_254 * _343))) + (_333 * ((_254 * _338) + (_237 * _343)))) + (_336 * ((_237 * _338) + (_240 * _343))); + } + else + { + _358 = float4(_259.xyz, 0.0); + _359 = _265; + } + _387 = _358; + _388 = _359; + } + float3x3 _398; + if (float(int(_287 == 0.0)) == 0.0) + { + _398 = float3x3(_388, cross(_387.xyz, _388) * float3(_387.w), _387.xyz); + } + else + { + _398 = float3x3(_265, cross(_266, _265) * float3(_259.w), _266); + } + float3 _411 = fast::min(fast::max((_272 - View.View_GlobalVolumeCenterAndExtent[0].xyz) + View.View_GlobalVolumeCenterAndExtent[0].www, float3(0.0)), fast::max((View.View_GlobalVolumeCenterAndExtent[0].xyz + View.View_GlobalVolumeCenterAndExtent[0].www) - _272, float3(0.0))); + float _547; + if (fast::min(_411.x, fast::min(_411.y, _411.z)) > (View.View_GlobalVolumeCenterAndExtent[0].w * View.View_GlobalVolumeTexelSize)) + { + _547 = View_GlobalDistanceFieldTexture0.sample(View_GlobalDistanceFieldSampler0, ((_272 * View.View_GlobalVolumeWorldToUVAddAndMul[0u].www) + View.View_GlobalVolumeWorldToUVAddAndMul[0u].xyz), level(0.0)).x; + } + else + { + float3 _436 = fast::min(fast::max((_272 - View.View_GlobalVolumeCenterAndExtent[1].xyz) + View.View_GlobalVolumeCenterAndExtent[1].www, float3(0.0)), fast::max((View.View_GlobalVolumeCenterAndExtent[1].xyz + View.View_GlobalVolumeCenterAndExtent[1].www) - _272, float3(0.0))); + float _535; + if (fast::min(_436.x, fast::min(_436.y, _436.z)) > (View.View_GlobalVolumeCenterAndExtent[1].w * View.View_GlobalVolumeTexelSize)) + { + _535 = View_GlobalDistanceFieldTexture1.sample(View_GlobalDistanceFieldSampler0, ((_272 * View.View_GlobalVolumeWorldToUVAddAndMul[1u].www) + View.View_GlobalVolumeWorldToUVAddAndMul[1u].xyz), level(0.0)).x; + } + else + { + float3 _459 = fast::min(fast::max((_272 - View.View_GlobalVolumeCenterAndExtent[2].xyz) + View.View_GlobalVolumeCenterAndExtent[2].www, float3(0.0)), fast::max((View.View_GlobalVolumeCenterAndExtent[2].xyz + View.View_GlobalVolumeCenterAndExtent[2].www) - _272, float3(0.0))); + float3 _475 = fast::min(fast::max((_272 - View.View_GlobalVolumeCenterAndExtent[3].xyz) + View.View_GlobalVolumeCenterAndExtent[3].www, float3(0.0)), fast::max((View.View_GlobalVolumeCenterAndExtent[3].xyz + View.View_GlobalVolumeCenterAndExtent[3].www) - _272, float3(0.0))); + float _480 = fast::min(_475.x, fast::min(_475.y, _475.z)); + float _523; + if (fast::min(_459.x, fast::min(_459.y, _459.z)) > (View.View_GlobalVolumeCenterAndExtent[2].w * View.View_GlobalVolumeTexelSize)) + { + _523 = View_GlobalDistanceFieldTexture2.sample(View_GlobalDistanceFieldSampler0, ((_272 * View.View_GlobalVolumeWorldToUVAddAndMul[2u].www) + View.View_GlobalVolumeWorldToUVAddAndMul[2u].xyz), level(0.0)).x; + } + else + { + float _511; + if (_480 > (View.View_GlobalVolumeCenterAndExtent[3].w * View.View_GlobalVolumeTexelSize)) + { + _511 = mix(View.View_MaxGlobalDistance, View_GlobalDistanceFieldTexture3.sample(View_GlobalDistanceFieldSampler0, ((_272 * View.View_GlobalVolumeWorldToUVAddAndMul[3u].www) + View.View_GlobalVolumeWorldToUVAddAndMul[3u].xyz), level(0.0)).x, fast::clamp((_480 * 10.0) * View.View_GlobalVolumeWorldToUVAddAndMul[3].w, 0.0, 1.0)); + } + else + { + _511 = View.View_MaxGlobalDistance; + } + _523 = _511; + } + _535 = _523; + } + _547 = _535; + } + float3 _565 = _264 + ((_398[2] * float3(fast::min(_547 + Material.Material_ScalarExpressions[0].z, 0.0) * Material.Material_ScalarExpressions[0].w)) * float3(((_137[0] * gl_TessCoord.x) + (_137[1] * gl_TessCoord.y)) + (_137[2] * gl_TessCoord.z))); + float4 _574 = View.View_TranslatedWorldToClip * float4(_565.x, _565.y, _565.z, _235.w); + float4 _579 = _574; + _579.z = _574.z + (0.001000000047497451305389404296875 * _574.w); + out.gl_Position = _579; + out.out_var_TEXCOORD6 = ((_120[0] * _198) + (_120[1] * _202)) + (_120[2] * _207); + out.out_var_TEXCOORD7 = ((_121[0] * _198) + (_121[1] * _202)) + (_121[2] * _207); + out.out_var_TEXCOORD10_centroid = float4(_256.x, _256.y, _256.z, _118.w); + out.out_var_TEXCOORD11_centroid = _259; + out.gl_ClipDistance[0u] = dot(View.View_GlobalClippingPlane, float4(_565.xyz - float3(View.View_PreViewTranslation), 1.0)); + out.gl_ClipDistance_0 = out.gl_ClipDistance[0]; + return out; +} + diff --git a/third_party/spirv-cross/reference/opt/shaders-ue4/asm/tese/ds-patch-inputs.asm.tese b/third_party/spirv-cross/reference/opt/shaders-ue4/asm/tese/ds-patch-inputs.asm.tese new file mode 100644 index 0000000000..4a872e5f7d --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders-ue4/asm/tese/ds-patch-inputs.asm.tese @@ -0,0 +1,216 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + +#include +#include + +using namespace metal; + +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +struct type_ShadowDepthPass +{ + float PrePadding_ShadowDepthPass_LPV_0; + float PrePadding_ShadowDepthPass_LPV_4; + float PrePadding_ShadowDepthPass_LPV_8; + float PrePadding_ShadowDepthPass_LPV_12; + float PrePadding_ShadowDepthPass_LPV_16; + float PrePadding_ShadowDepthPass_LPV_20; + float PrePadding_ShadowDepthPass_LPV_24; + float PrePadding_ShadowDepthPass_LPV_28; + float PrePadding_ShadowDepthPass_LPV_32; + float PrePadding_ShadowDepthPass_LPV_36; + float PrePadding_ShadowDepthPass_LPV_40; + float PrePadding_ShadowDepthPass_LPV_44; + float PrePadding_ShadowDepthPass_LPV_48; + float PrePadding_ShadowDepthPass_LPV_52; + float PrePadding_ShadowDepthPass_LPV_56; + float PrePadding_ShadowDepthPass_LPV_60; + float PrePadding_ShadowDepthPass_LPV_64; + float PrePadding_ShadowDepthPass_LPV_68; + float PrePadding_ShadowDepthPass_LPV_72; + float PrePadding_ShadowDepthPass_LPV_76; + float PrePadding_ShadowDepthPass_LPV_80; + float PrePadding_ShadowDepthPass_LPV_84; + float PrePadding_ShadowDepthPass_LPV_88; + float PrePadding_ShadowDepthPass_LPV_92; + float PrePadding_ShadowDepthPass_LPV_96; + float PrePadding_ShadowDepthPass_LPV_100; + float PrePadding_ShadowDepthPass_LPV_104; + float PrePadding_ShadowDepthPass_LPV_108; + float PrePadding_ShadowDepthPass_LPV_112; + float PrePadding_ShadowDepthPass_LPV_116; + float PrePadding_ShadowDepthPass_LPV_120; + float PrePadding_ShadowDepthPass_LPV_124; + float PrePadding_ShadowDepthPass_LPV_128; + float PrePadding_ShadowDepthPass_LPV_132; + float PrePadding_ShadowDepthPass_LPV_136; + float PrePadding_ShadowDepthPass_LPV_140; + float PrePadding_ShadowDepthPass_LPV_144; + float PrePadding_ShadowDepthPass_LPV_148; + float PrePadding_ShadowDepthPass_LPV_152; + float PrePadding_ShadowDepthPass_LPV_156; + float PrePadding_ShadowDepthPass_LPV_160; + float PrePadding_ShadowDepthPass_LPV_164; + float PrePadding_ShadowDepthPass_LPV_168; + float PrePadding_ShadowDepthPass_LPV_172; + float PrePadding_ShadowDepthPass_LPV_176; + float PrePadding_ShadowDepthPass_LPV_180; + float PrePadding_ShadowDepthPass_LPV_184; + float PrePadding_ShadowDepthPass_LPV_188; + float PrePadding_ShadowDepthPass_LPV_192; + float PrePadding_ShadowDepthPass_LPV_196; + float PrePadding_ShadowDepthPass_LPV_200; + float PrePadding_ShadowDepthPass_LPV_204; + float PrePadding_ShadowDepthPass_LPV_208; + float PrePadding_ShadowDepthPass_LPV_212; + float PrePadding_ShadowDepthPass_LPV_216; + float PrePadding_ShadowDepthPass_LPV_220; + float PrePadding_ShadowDepthPass_LPV_224; + float PrePadding_ShadowDepthPass_LPV_228; + float PrePadding_ShadowDepthPass_LPV_232; + float PrePadding_ShadowDepthPass_LPV_236; + float PrePadding_ShadowDepthPass_LPV_240; + float PrePadding_ShadowDepthPass_LPV_244; + float PrePadding_ShadowDepthPass_LPV_248; + float PrePadding_ShadowDepthPass_LPV_252; + float PrePadding_ShadowDepthPass_LPV_256; + float PrePadding_ShadowDepthPass_LPV_260; + float PrePadding_ShadowDepthPass_LPV_264; + float PrePadding_ShadowDepthPass_LPV_268; + float4x4 ShadowDepthPass_LPV_mRsmToWorld; + float4 ShadowDepthPass_LPV_mLightColour; + float4 ShadowDepthPass_LPV_GeometryVolumeCaptureLightDirection; + float4 ShadowDepthPass_LPV_mEyePos; + packed_int3 ShadowDepthPass_LPV_mOldGridOffset; + int PrePadding_ShadowDepthPass_LPV_396; + packed_int3 ShadowDepthPass_LPV_mLpvGridOffset; + float ShadowDepthPass_LPV_ClearMultiplier; + float ShadowDepthPass_LPV_LpvScale; + float ShadowDepthPass_LPV_OneOverLpvScale; + float ShadowDepthPass_LPV_DirectionalOcclusionIntensity; + float ShadowDepthPass_LPV_DirectionalOcclusionRadius; + float ShadowDepthPass_LPV_RsmAreaIntensityMultiplier; + float ShadowDepthPass_LPV_RsmPixelToTexcoordMultiplier; + float ShadowDepthPass_LPV_SecondaryOcclusionStrength; + float ShadowDepthPass_LPV_SecondaryBounceStrength; + float ShadowDepthPass_LPV_VplInjectionBias; + float ShadowDepthPass_LPV_GeometryVolumeInjectionBias; + float ShadowDepthPass_LPV_EmissiveInjectionMultiplier; + int ShadowDepthPass_LPV_PropagationIndex; + float4x4 ShadowDepthPass_ProjectionMatrix; + float4x4 ShadowDepthPass_ViewMatrix; + float4 ShadowDepthPass_ShadowParams; + float ShadowDepthPass_bClampToNearPlane; + float PrePadding_ShadowDepthPass_612; + float PrePadding_ShadowDepthPass_616; + float PrePadding_ShadowDepthPass_620; + float4x4 ShadowDepthPass_ShadowViewProjectionMatrices[6]; + float4x4 ShadowDepthPass_ShadowViewMatrices[6]; +}; + +constant float4 _90 = {}; + +struct main0_out +{ + float4 out_var_TEXCOORD10_centroid [[user(locn0)]]; + float4 out_var_TEXCOORD11_centroid [[user(locn1)]]; + float out_var_TEXCOORD6 [[user(locn2)]]; + float3 out_var_TEXCOORD7 [[user(locn3)]]; + float4 gl_Position [[position]]; +}; + +struct main0_in +{ + float4 in_var_PN_POSITION_0 [[attribute(10)]]; + float4 in_var_PN_POSITION_1 [[attribute(11)]]; + float4 in_var_PN_POSITION_2 [[attribute(12)]]; + float4 in_var_TEXCOORD10_centroid [[attribute(16)]]; + float4 in_var_TEXCOORD11_centroid [[attribute(17)]]; +}; + +struct main0_patchIn +{ + float4 in_var_PN_POSITION9 [[attribute(13)]]; + patch_control_point gl_in; +}; + +[[ patch(triangle, 0) ]] vertex main0_out main0(main0_patchIn patchIn [[stage_in]], constant type_ShadowDepthPass& ShadowDepthPass [[buffer(0)]], float3 gl_TessCoord [[position_in_patch]]) +{ + main0_out out = {}; + spvUnsafeArray _93 = spvUnsafeArray({ patchIn.gl_in[0].in_var_TEXCOORD10_centroid, patchIn.gl_in[1].in_var_TEXCOORD10_centroid, patchIn.gl_in[2].in_var_TEXCOORD10_centroid }); + spvUnsafeArray _94 = spvUnsafeArray({ patchIn.gl_in[0].in_var_TEXCOORD11_centroid, patchIn.gl_in[1].in_var_TEXCOORD11_centroid, patchIn.gl_in[2].in_var_TEXCOORD11_centroid }); + spvUnsafeArray, 3> _101 = spvUnsafeArray, 3>({ spvUnsafeArray({ patchIn.gl_in[0].in_var_PN_POSITION_0, patchIn.gl_in[0].in_var_PN_POSITION_1, patchIn.gl_in[0].in_var_PN_POSITION_2 }), spvUnsafeArray({ patchIn.gl_in[1].in_var_PN_POSITION_0, patchIn.gl_in[1].in_var_PN_POSITION_1, patchIn.gl_in[1].in_var_PN_POSITION_2 }), spvUnsafeArray({ patchIn.gl_in[2].in_var_PN_POSITION_0, patchIn.gl_in[2].in_var_PN_POSITION_1, patchIn.gl_in[2].in_var_PN_POSITION_2 }) }); + float _119 = gl_TessCoord.x * gl_TessCoord.x; + float _120 = gl_TessCoord.y * gl_TessCoord.y; + float _121 = gl_TessCoord.z * gl_TessCoord.z; + float4 _127 = float4(gl_TessCoord.x); + float4 _131 = float4(gl_TessCoord.y); + float4 _136 = float4(gl_TessCoord.z); + float4 _139 = float4(_119 * 3.0); + float4 _143 = float4(_120 * 3.0); + float4 _150 = float4(_121 * 3.0); + float4 _164 = ((((((((((_101[0][0] * float4(_119)) * _127) + ((_101[1][0] * float4(_120)) * _131)) + ((_101[2][0] * float4(_121)) * _136)) + ((_101[0][1] * _139) * _131)) + ((_101[0][2] * _143) * _127)) + ((_101[1][1] * _143) * _136)) + ((_101[1][2] * _150) * _131)) + ((_101[2][1] * _150) * _127)) + ((_101[2][2] * _139) * _136)) + ((((patchIn.in_var_PN_POSITION9 * float4(6.0)) * _136) * _127) * _131); + float3 _179 = ((_93[0].xyz * float3(gl_TessCoord.x)) + (_93[1].xyz * float3(gl_TessCoord.y))).xyz + (_93[2].xyz * float3(gl_TessCoord.z)); + float4 _182 = ((_94[0] * _127) + (_94[1] * _131)) + (_94[2] * _136); + float4 _189 = ShadowDepthPass.ShadowDepthPass_ProjectionMatrix * float4(_164.x, _164.y, _164.z, _164.w); + float4 _200; + if ((ShadowDepthPass.ShadowDepthPass_bClampToNearPlane > 0.0) && (_189.z < 0.0)) + { + float4 _198 = _189; + _198.z = 9.9999999747524270787835121154785e-07; + float4 _199 = _198; + _199.w = 1.0; + _200 = _199; + } + else + { + _200 = _189; + } + float _209 = abs(dot(float3(ShadowDepthPass.ShadowDepthPass_ViewMatrix[0].z, ShadowDepthPass.ShadowDepthPass_ViewMatrix[1].z, ShadowDepthPass.ShadowDepthPass_ViewMatrix[2].z), _182.xyz)); + float4 _234 = _200; + _234.z = ((_200.z * ShadowDepthPass.ShadowDepthPass_ShadowParams.w) + ((ShadowDepthPass.ShadowDepthPass_ShadowParams.y * fast::clamp((abs(_209) > 0.0) ? (sqrt(fast::clamp(1.0 - (_209 * _209), 0.0, 1.0)) / _209) : ShadowDepthPass.ShadowDepthPass_ShadowParams.z, 0.0, ShadowDepthPass.ShadowDepthPass_ShadowParams.z)) + ShadowDepthPass.ShadowDepthPass_ShadowParams.x)) * _200.w; + out.out_var_TEXCOORD10_centroid = float4(_179.x, _179.y, _179.z, _90.w); + out.out_var_TEXCOORD11_centroid = _182; + out.out_var_TEXCOORD6 = 0.0; + out.out_var_TEXCOORD7 = _164.xyz; + out.gl_Position = _234; + return out; +} + diff --git a/third_party/spirv-cross/reference/opt/shaders-ue4/asm/tese/ds-texcoord-array.asm.tese b/third_party/spirv-cross/reference/opt/shaders-ue4/asm/tese/ds-texcoord-array.asm.tese new file mode 100644 index 0000000000..346d7e3fc9 --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders-ue4/asm/tese/ds-texcoord-array.asm.tese @@ -0,0 +1,318 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + +#include +#include + +using namespace metal; + +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +struct type_View +{ + float4x4 View_TranslatedWorldToClip; + float4x4 View_WorldToClip; + float4x4 View_ClipToWorld; + float4x4 View_TranslatedWorldToView; + float4x4 View_ViewToTranslatedWorld; + float4x4 View_TranslatedWorldToCameraView; + float4x4 View_CameraViewToTranslatedWorld; + float4x4 View_ViewToClip; + float4x4 View_ViewToClipNoAA; + float4x4 View_ClipToView; + float4x4 View_ClipToTranslatedWorld; + float4x4 View_SVPositionToTranslatedWorld; + float4x4 View_ScreenToWorld; + float4x4 View_ScreenToTranslatedWorld; + packed_float3 View_ViewForward; + float PrePadding_View_908; + packed_float3 View_ViewUp; + float PrePadding_View_924; + packed_float3 View_ViewRight; + float PrePadding_View_940; + packed_float3 View_HMDViewNoRollUp; + float PrePadding_View_956; + packed_float3 View_HMDViewNoRollRight; + float PrePadding_View_972; + float4 View_InvDeviceZToWorldZTransform; + float4 View_ScreenPositionScaleBias; + packed_float3 View_WorldCameraOrigin; + float PrePadding_View_1020; + packed_float3 View_TranslatedWorldCameraOrigin; + float PrePadding_View_1036; + packed_float3 View_WorldViewOrigin; + float PrePadding_View_1052; + packed_float3 View_PreViewTranslation; + float PrePadding_View_1068; + float4x4 View_PrevProjection; + float4x4 View_PrevViewProj; + float4x4 View_PrevViewRotationProj; + float4x4 View_PrevViewToClip; + float4x4 View_PrevClipToView; + float4x4 View_PrevTranslatedWorldToClip; + float4x4 View_PrevTranslatedWorldToView; + float4x4 View_PrevViewToTranslatedWorld; + float4x4 View_PrevTranslatedWorldToCameraView; + float4x4 View_PrevCameraViewToTranslatedWorld; + packed_float3 View_PrevWorldCameraOrigin; + float PrePadding_View_1724; + packed_float3 View_PrevWorldViewOrigin; + float PrePadding_View_1740; + packed_float3 View_PrevPreViewTranslation; + float PrePadding_View_1756; + float4x4 View_PrevInvViewProj; + float4x4 View_PrevScreenToTranslatedWorld; + float4x4 View_ClipToPrevClip; + float4 View_TemporalAAJitter; + float4 View_GlobalClippingPlane; + float2 View_FieldOfViewWideAngles; + float2 View_PrevFieldOfViewWideAngles; + float4 View_ViewRectMin; + float4 View_ViewSizeAndInvSize; + float4 View_BufferSizeAndInvSize; + float4 View_BufferBilinearUVMinMax; + int View_NumSceneColorMSAASamples; + float View_PreExposure; + float View_OneOverPreExposure; + float PrePadding_View_2076; + float4 View_DiffuseOverrideParameter; + float4 View_SpecularOverrideParameter; + float4 View_NormalOverrideParameter; + float2 View_RoughnessOverrideParameter; + float View_PrevFrameGameTime; + float View_PrevFrameRealTime; + float View_OutOfBoundsMask; + float PrePadding_View_2148; + float PrePadding_View_2152; + float PrePadding_View_2156; + packed_float3 View_WorldCameraMovementSinceLastFrame; + float View_CullingSign; + float View_NearPlane; + float View_AdaptiveTessellationFactor; + float View_GameTime; + float View_RealTime; + float View_DeltaTime; + float View_MaterialTextureMipBias; + float View_MaterialTextureDerivativeMultiply; + uint View_Random; + uint View_FrameNumber; + uint View_StateFrameIndexMod8; + uint View_StateFrameIndex; + float View_CameraCut; + float View_UnlitViewmodeMask; + float PrePadding_View_2228; + float PrePadding_View_2232; + float PrePadding_View_2236; + float4 View_DirectionalLightColor; + packed_float3 View_DirectionalLightDirection; + float PrePadding_View_2268; + float4 View_TranslucencyLightingVolumeMin[2]; + float4 View_TranslucencyLightingVolumeInvSize[2]; + float4 View_TemporalAAParams; + float4 View_CircleDOFParams; + float View_DepthOfFieldSensorWidth; + float View_DepthOfFieldFocalDistance; + float View_DepthOfFieldScale; + float View_DepthOfFieldFocalLength; + float View_DepthOfFieldFocalRegion; + float View_DepthOfFieldNearTransitionRegion; + float View_DepthOfFieldFarTransitionRegion; + float View_MotionBlurNormalizedToPixel; + float View_bSubsurfacePostprocessEnabled; + float View_GeneralPurposeTweak; + float View_DemosaicVposOffset; + float PrePadding_View_2412; + packed_float3 View_IndirectLightingColorScale; + float View_HDR32bppEncodingMode; + packed_float3 View_AtmosphericFogSunDirection; + float View_AtmosphericFogSunPower; + float View_AtmosphericFogPower; + float View_AtmosphericFogDensityScale; + float View_AtmosphericFogDensityOffset; + float View_AtmosphericFogGroundOffset; + float View_AtmosphericFogDistanceScale; + float View_AtmosphericFogAltitudeScale; + float View_AtmosphericFogHeightScaleRayleigh; + float View_AtmosphericFogStartDistance; + float View_AtmosphericFogDistanceOffset; + float View_AtmosphericFogSunDiscScale; + float View_AtmosphericFogSunDiscHalfApexAngleRadian; + float PrePadding_View_2492; + float4 View_AtmosphericFogSunDiscLuminance; + uint View_AtmosphericFogRenderMask; + uint View_AtmosphericFogInscatterAltitudeSampleNum; + uint PrePadding_View_2520; + uint PrePadding_View_2524; + float4 View_AtmosphericFogSunColor; + packed_float3 View_NormalCurvatureToRoughnessScaleBias; + float View_RenderingReflectionCaptureMask; + float4 View_AmbientCubemapTint; + float View_AmbientCubemapIntensity; + float View_SkyLightParameters; + float PrePadding_View_2584; + float PrePadding_View_2588; + float4 View_SkyLightColor; + float4 View_SkyIrradianceEnvironmentMap[7]; + float View_MobilePreviewMode; + float View_HMDEyePaddingOffset; + float View_ReflectionCubemapMaxMip; + float View_ShowDecalsMask; + uint View_DistanceFieldAOSpecularOcclusionMode; + float View_IndirectCapsuleSelfShadowingIntensity; + float PrePadding_View_2744; + float PrePadding_View_2748; + packed_float3 View_ReflectionEnvironmentRoughnessMixingScaleBiasAndLargestWeight; + int View_StereoPassIndex; + float4 View_GlobalVolumeCenterAndExtent[4]; + float4 View_GlobalVolumeWorldToUVAddAndMul[4]; + float View_GlobalVolumeDimension; + float View_GlobalVolumeTexelSize; + float View_MaxGlobalDistance; + float PrePadding_View_2908; + int2 View_CursorPosition; + float View_bCheckerboardSubsurfaceProfileRendering; + float PrePadding_View_2924; + packed_float3 View_VolumetricFogInvGridSize; + float PrePadding_View_2940; + packed_float3 View_VolumetricFogGridZParams; + float PrePadding_View_2956; + float2 View_VolumetricFogSVPosToVolumeUV; + float View_VolumetricFogMaxDistance; + float PrePadding_View_2972; + packed_float3 View_VolumetricLightmapWorldToUVScale; + float PrePadding_View_2988; + packed_float3 View_VolumetricLightmapWorldToUVAdd; + float PrePadding_View_3004; + packed_float3 View_VolumetricLightmapIndirectionTextureSize; + float View_VolumetricLightmapBrickSize; + packed_float3 View_VolumetricLightmapBrickTexelSize; + float View_StereoIPD; + float View_IndirectLightingCacheShowFlag; + float View_EyeToPixelSpreadAngle; + float PrePadding_View_3048; + float PrePadding_View_3052; + float4x4 View_WorldToVirtualTexture; + float4 View_VirtualTextureParams; + float4 View_XRPassthroughCameraUVs[2]; +}; + +constant float4 _68 = {}; + +struct main0_out +{ + float4 out_var_TEXCOORD10_centroid [[user(locn0)]]; + float4 out_var_TEXCOORD11_centroid [[user(locn1)]]; + float4 out_var_TEXCOORD0_0 [[user(locn2)]]; + float4 out_var_COLOR1 [[user(locn3)]]; + float4 out_var_COLOR2 [[user(locn4)]]; + float4 out_var_TEXCOORD6 [[user(locn5)]]; + float3 out_var_TEXCOORD7 [[user(locn6)]]; + float4 gl_Position [[position]]; +}; + +struct main0_in +{ + float4 in_var_COLOR1 [[attribute(0)]]; + float4 in_var_COLOR2 [[attribute(1)]]; + float4 in_var_TEXCOORD0_0 [[attribute(5)]]; + float4 in_var_TEXCOORD10_centroid [[attribute(6)]]; + float4 in_var_TEXCOORD11_centroid [[attribute(7)]]; + float3 in_var_TEXCOORD7 [[attribute(8)]]; + float4 in_var_VS_To_DS_Position [[attribute(9)]]; +}; + +struct main0_patchIn +{ + patch_control_point gl_in; +}; + +[[ patch(triangle, 0) ]] vertex main0_out main0(main0_patchIn patchIn [[stage_in]], constant type_View& View [[buffer(0)]], float3 gl_TessCoord [[position_in_patch]]) +{ + main0_out out = {}; + spvUnsafeArray out_var_TEXCOORD0 = {}; + spvUnsafeArray _77 = spvUnsafeArray({ patchIn.gl_in[0].in_var_TEXCOORD10_centroid, patchIn.gl_in[1].in_var_TEXCOORD10_centroid, patchIn.gl_in[2].in_var_TEXCOORD10_centroid }); + spvUnsafeArray _78 = spvUnsafeArray({ patchIn.gl_in[0].in_var_TEXCOORD11_centroid, patchIn.gl_in[1].in_var_TEXCOORD11_centroid, patchIn.gl_in[2].in_var_TEXCOORD11_centroid }); + spvUnsafeArray, 3> _79 = spvUnsafeArray, 3>({ spvUnsafeArray({ patchIn.gl_in[0].in_var_TEXCOORD0_0 }), spvUnsafeArray({ patchIn.gl_in[1].in_var_TEXCOORD0_0 }), spvUnsafeArray({ patchIn.gl_in[2].in_var_TEXCOORD0_0 }) }); + spvUnsafeArray _80 = spvUnsafeArray({ patchIn.gl_in[0].in_var_COLOR1, patchIn.gl_in[1].in_var_COLOR1, patchIn.gl_in[2].in_var_COLOR1 }); + spvUnsafeArray _81 = spvUnsafeArray({ patchIn.gl_in[0].in_var_COLOR2, patchIn.gl_in[1].in_var_COLOR2, patchIn.gl_in[2].in_var_COLOR2 }); + spvUnsafeArray _97 = spvUnsafeArray({ patchIn.gl_in[0].in_var_VS_To_DS_Position, patchIn.gl_in[1].in_var_VS_To_DS_Position, patchIn.gl_in[2].in_var_VS_To_DS_Position }); + spvUnsafeArray _98 = spvUnsafeArray({ patchIn.gl_in[0].in_var_TEXCOORD7, patchIn.gl_in[1].in_var_TEXCOORD7, patchIn.gl_in[2].in_var_TEXCOORD7 }); + float4 _111 = float4(gl_TessCoord.x); + float4 _113 = float4(gl_TessCoord.y); + float4 _116 = float4(gl_TessCoord.z); + float4 _118 = ((_97[0] * _111) + (_97[1] * _113)) + (_97[2] * _116); + spvUnsafeArray _72; + _72 = _79[0]; + spvUnsafeArray _71; + _71 = _79[1]; + float3 _120 = float3(gl_TessCoord.x); + float3 _123 = float3(gl_TessCoord.y); + spvUnsafeArray _73; + for (int _133 = 0; _133 < 1; ) + { + _73[_133] = (_72[_133] * _111) + (_71[_133] * _113); + _133++; + continue; + } + spvUnsafeArray _75; + _75 = _73; + spvUnsafeArray _74; + _74 = _79[2]; + float3 _155 = float3(gl_TessCoord.z); + float3 _157 = ((_77[0].xyz * _120) + (_77[1].xyz * _123)).xyz + (_77[2].xyz * _155); + spvUnsafeArray _76; + for (int _164 = 0; _164 < 1; ) + { + _76[_164] = _75[_164] + (_74[_164] * _116); + _164++; + continue; + } + float4 _181 = float4(_118.x, _118.y, _118.z, _118.w); + out.out_var_TEXCOORD10_centroid = float4(_157.x, _157.y, _157.z, _68.w); + out.out_var_TEXCOORD11_centroid = ((_78[0] * _111) + (_78[1] * _113)) + (_78[2] * _116); + out_var_TEXCOORD0 = _76; + out.out_var_COLOR1 = ((_80[0] * _111) + (_80[1] * _113)) + (_80[2] * _116); + out.out_var_COLOR2 = ((_81[0] * _111) + (_81[1] * _113)) + (_81[2] * _116); + out.out_var_TEXCOORD6 = _181; + out.out_var_TEXCOORD7 = ((_98[0] * _120) + (_98[1] * _123)) + (_98[2] * _155); + out.gl_Position = View.View_TranslatedWorldToClip * _181; + out.out_var_TEXCOORD0_0 = out_var_TEXCOORD0[0]; + return out; +} + diff --git a/third_party/spirv-cross/reference/opt/shaders-ue4/asm/vert/array-missing-copies.asm.vert b/third_party/spirv-cross/reference/opt/shaders-ue4/asm/vert/array-missing-copies.asm.vert new file mode 100644 index 0000000000..cb5f5fd19a --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders-ue4/asm/vert/array-missing-copies.asm.vert @@ -0,0 +1,464 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + +#include +#include + +using namespace metal; + +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +struct type_View +{ + float4x4 View_TranslatedWorldToClip; + float4x4 View_WorldToClip; + float4x4 View_TranslatedWorldToView; + float4x4 View_ViewToTranslatedWorld; + float4x4 View_TranslatedWorldToCameraView; + float4x4 View_CameraViewToTranslatedWorld; + float4x4 View_ViewToClip; + float4x4 View_ViewToClipNoAA; + float4x4 View_ClipToView; + float4x4 View_ClipToTranslatedWorld; + float4x4 View_SVPositionToTranslatedWorld; + float4x4 View_ScreenToWorld; + float4x4 View_ScreenToTranslatedWorld; + packed_float3 View_ViewForward; + float PrePadding_View_844; + packed_float3 View_ViewUp; + float PrePadding_View_860; + packed_float3 View_ViewRight; + float PrePadding_View_876; + packed_float3 View_HMDViewNoRollUp; + float PrePadding_View_892; + packed_float3 View_HMDViewNoRollRight; + float PrePadding_View_908; + float4 View_InvDeviceZToWorldZTransform; + float4 View_ScreenPositionScaleBias; + packed_float3 View_WorldCameraOrigin; + float PrePadding_View_956; + packed_float3 View_TranslatedWorldCameraOrigin; + float PrePadding_View_972; + packed_float3 View_WorldViewOrigin; + float PrePadding_View_988; + packed_float3 View_PreViewTranslation; + float PrePadding_View_1004; + float4x4 View_PrevProjection; + float4x4 View_PrevViewProj; + float4x4 View_PrevViewRotationProj; + float4x4 View_PrevViewToClip; + float4x4 View_PrevClipToView; + float4x4 View_PrevTranslatedWorldToClip; + float4x4 View_PrevTranslatedWorldToView; + float4x4 View_PrevViewToTranslatedWorld; + float4x4 View_PrevTranslatedWorldToCameraView; + float4x4 View_PrevCameraViewToTranslatedWorld; + packed_float3 View_PrevWorldCameraOrigin; + float PrePadding_View_1660; + packed_float3 View_PrevWorldViewOrigin; + float PrePadding_View_1676; + packed_float3 View_PrevPreViewTranslation; + float PrePadding_View_1692; + float4x4 View_PrevInvViewProj; + float4x4 View_PrevScreenToTranslatedWorld; + float4x4 View_ClipToPrevClip; + float4 View_TemporalAAJitter; + float4 View_GlobalClippingPlane; + float2 View_FieldOfViewWideAngles; + float2 View_PrevFieldOfViewWideAngles; + float4 View_ViewRectMin; + float4 View_ViewSizeAndInvSize; + float4 View_BufferSizeAndInvSize; + float4 View_BufferBilinearUVMinMax; + int View_NumSceneColorMSAASamples; + float View_PreExposure; + float View_OneOverPreExposure; + float PrePadding_View_2012; + float4 View_DiffuseOverrideParameter; + float4 View_SpecularOverrideParameter; + float4 View_NormalOverrideParameter; + float2 View_RoughnessOverrideParameter; + float View_PrevFrameGameTime; + float View_PrevFrameRealTime; + float View_OutOfBoundsMask; + float PrePadding_View_2084; + float PrePadding_View_2088; + float PrePadding_View_2092; + packed_float3 View_WorldCameraMovementSinceLastFrame; + float View_CullingSign; + float View_NearPlane; + float View_AdaptiveTessellationFactor; + float View_GameTime; + float View_RealTime; + float View_DeltaTime; + float View_MaterialTextureMipBias; + float View_MaterialTextureDerivativeMultiply; + uint View_Random; + uint View_FrameNumber; + uint View_StateFrameIndexMod8; + uint View_StateFrameIndex; + float View_CameraCut; + float View_UnlitViewmodeMask; + float PrePadding_View_2164; + float PrePadding_View_2168; + float PrePadding_View_2172; + float4 View_DirectionalLightColor; + packed_float3 View_DirectionalLightDirection; + float PrePadding_View_2204; + float4 View_TranslucencyLightingVolumeMin[2]; + float4 View_TranslucencyLightingVolumeInvSize[2]; + float4 View_TemporalAAParams; + float4 View_CircleDOFParams; + float View_DepthOfFieldSensorWidth; + float View_DepthOfFieldFocalDistance; + float View_DepthOfFieldScale; + float View_DepthOfFieldFocalLength; + float View_DepthOfFieldFocalRegion; + float View_DepthOfFieldNearTransitionRegion; + float View_DepthOfFieldFarTransitionRegion; + float View_MotionBlurNormalizedToPixel; + float View_bSubsurfacePostprocessEnabled; + float View_GeneralPurposeTweak; + float View_DemosaicVposOffset; + float PrePadding_View_2348; + packed_float3 View_IndirectLightingColorScale; + float View_HDR32bppEncodingMode; + packed_float3 View_AtmosphericFogSunDirection; + float View_AtmosphericFogSunPower; + float View_AtmosphericFogPower; + float View_AtmosphericFogDensityScale; + float View_AtmosphericFogDensityOffset; + float View_AtmosphericFogGroundOffset; + float View_AtmosphericFogDistanceScale; + float View_AtmosphericFogAltitudeScale; + float View_AtmosphericFogHeightScaleRayleigh; + float View_AtmosphericFogStartDistance; + float View_AtmosphericFogDistanceOffset; + float View_AtmosphericFogSunDiscScale; + uint View_AtmosphericFogRenderMask; + uint View_AtmosphericFogInscatterAltitudeSampleNum; + float4 View_AtmosphericFogSunColor; + packed_float3 View_NormalCurvatureToRoughnessScaleBias; + float View_RenderingReflectionCaptureMask; + float4 View_AmbientCubemapTint; + float View_AmbientCubemapIntensity; + float View_SkyLightParameters; + float PrePadding_View_2488; + float PrePadding_View_2492; + float4 View_SkyLightColor; + float4 View_SkyIrradianceEnvironmentMap[7]; + float View_MobilePreviewMode; + float View_HMDEyePaddingOffset; + float View_ReflectionCubemapMaxMip; + float View_ShowDecalsMask; + uint View_DistanceFieldAOSpecularOcclusionMode; + float View_IndirectCapsuleSelfShadowingIntensity; + float PrePadding_View_2648; + float PrePadding_View_2652; + packed_float3 View_ReflectionEnvironmentRoughnessMixingScaleBiasAndLargestWeight; + int View_StereoPassIndex; + float4 View_GlobalVolumeCenterAndExtent[4]; + float4 View_GlobalVolumeWorldToUVAddAndMul[4]; + float View_GlobalVolumeDimension; + float View_GlobalVolumeTexelSize; + float View_MaxGlobalDistance; + float View_bCheckerboardSubsurfaceProfileRendering; + packed_float3 View_VolumetricFogInvGridSize; + float PrePadding_View_2828; + packed_float3 View_VolumetricFogGridZParams; + float PrePadding_View_2844; + float2 View_VolumetricFogSVPosToVolumeUV; + float View_VolumetricFogMaxDistance; + float PrePadding_View_2860; + packed_float3 View_VolumetricLightmapWorldToUVScale; + float PrePadding_View_2876; + packed_float3 View_VolumetricLightmapWorldToUVAdd; + float PrePadding_View_2892; + packed_float3 View_VolumetricLightmapIndirectionTextureSize; + float View_VolumetricLightmapBrickSize; + packed_float3 View_VolumetricLightmapBrickTexelSize; + float View_StereoIPD; + float View_IndirectLightingCacheShowFlag; + float View_EyeToPixelSpreadAngle; +}; + +struct type_MobileBasePass +{ + float4 MobileBasePass_Fog_ExponentialFogParameters; + float4 MobileBasePass_Fog_ExponentialFogParameters2; + float4 MobileBasePass_Fog_ExponentialFogColorParameter; + float4 MobileBasePass_Fog_ExponentialFogParameters3; + float4 MobileBasePass_Fog_InscatteringLightDirection; + float4 MobileBasePass_Fog_DirectionalInscatteringColor; + float2 MobileBasePass_Fog_SinCosInscatteringColorCubemapRotation; + float PrePadding_MobileBasePass_Fog_104; + float PrePadding_MobileBasePass_Fog_108; + packed_float3 MobileBasePass_Fog_FogInscatteringTextureParameters; + float MobileBasePass_Fog_ApplyVolumetricFog; + float PrePadding_MobileBasePass_PlanarReflection_128; + float PrePadding_MobileBasePass_PlanarReflection_132; + float PrePadding_MobileBasePass_PlanarReflection_136; + float PrePadding_MobileBasePass_PlanarReflection_140; + float PrePadding_MobileBasePass_PlanarReflection_144; + float PrePadding_MobileBasePass_PlanarReflection_148; + float PrePadding_MobileBasePass_PlanarReflection_152; + float PrePadding_MobileBasePass_PlanarReflection_156; + float4 MobileBasePass_PlanarReflection_ReflectionPlane; + float4 MobileBasePass_PlanarReflection_PlanarReflectionOrigin; + float4 MobileBasePass_PlanarReflection_PlanarReflectionXAxis; + float4 MobileBasePass_PlanarReflection_PlanarReflectionYAxis; + float3x4 MobileBasePass_PlanarReflection_InverseTransposeMirrorMatrix; + packed_float3 MobileBasePass_PlanarReflection_PlanarReflectionParameters; + float PrePadding_MobileBasePass_PlanarReflection_284; + float2 MobileBasePass_PlanarReflection_PlanarReflectionParameters2; + float PrePadding_MobileBasePass_PlanarReflection_296; + float PrePadding_MobileBasePass_PlanarReflection_300; + float4x4 MobileBasePass_PlanarReflection_ProjectionWithExtraFOV[2]; + float4 MobileBasePass_PlanarReflection_PlanarReflectionScreenScaleBias[2]; + float2 MobileBasePass_PlanarReflection_PlanarReflectionScreenBound; + uint MobileBasePass_PlanarReflection_bIsStereo; +}; + +struct type_Primitive +{ + float4x4 Primitive_LocalToWorld; + float4 Primitive_InvNonUniformScaleAndDeterminantSign; + float4 Primitive_ObjectWorldPositionAndRadius; + float4x4 Primitive_WorldToLocal; + float4x4 Primitive_PreviousLocalToWorld; + float4x4 Primitive_PreviousWorldToLocal; + packed_float3 Primitive_ActorWorldPosition; + float Primitive_UseSingleSampleShadowFromStationaryLights; + packed_float3 Primitive_ObjectBounds; + float Primitive_LpvBiasMultiplier; + float Primitive_DecalReceiverMask; + float Primitive_PerObjectGBufferData; + float Primitive_UseVolumetricLightmapShadowFromStationaryLights; + float Primitive_UseEditorDepthTest; + float4 Primitive_ObjectOrientation; + float4 Primitive_NonUniformScale; + packed_float3 Primitive_LocalObjectBoundsMin; + float PrePadding_Primitive_380; + packed_float3 Primitive_LocalObjectBoundsMax; + uint Primitive_LightingChannelMask; + uint Primitive_LightmapDataIndex; + int Primitive_SingleCaptureIndex; +}; + +struct type_LandscapeParameters +{ + float4 LandscapeParameters_HeightmapUVScaleBias; + float4 LandscapeParameters_WeightmapUVScaleBias; + float4 LandscapeParameters_LandscapeLightmapScaleBias; + float4 LandscapeParameters_SubsectionSizeVertsLayerUVPan; + float4 LandscapeParameters_SubsectionOffsetParams; + float4 LandscapeParameters_LightmapSubsectionOffsetParams; + float4x4 LandscapeParameters_LocalToWorldNoScaling; +}; + +struct type_Globals +{ + float4 LodBias; + float4 LodValues; + float4 SectionLods; + float4 NeighborSectionLod[4]; +}; + +struct main0_out +{ + float2 out_var_TEXCOORD0 [[user(locn0)]]; + float2 out_var_TEXCOORD1 [[user(locn1)]]; + float4 out_var_TEXCOORD2 [[user(locn2)]]; + float4 out_var_TEXCOORD3 [[user(locn3)]]; + float4 out_var_TEXCOORD8 [[user(locn4)]]; + float4 gl_Position [[position]]; +}; + +struct main0_in +{ + float4 in_var_ATTRIBUTE0 [[attribute(0)]]; + float4 in_var_ATTRIBUTE1_0 [[attribute(1)]]; + float4 in_var_ATTRIBUTE1_1 [[attribute(2)]]; +}; + +vertex main0_out main0(main0_in in [[stage_in]], constant type_View& View [[buffer(0)]], constant type_MobileBasePass& MobileBasePass [[buffer(1)]], constant type_Primitive& Primitive [[buffer(2)]], constant type_LandscapeParameters& LandscapeParameters [[buffer(3)]], constant type_Globals& _Globals [[buffer(4)]]) +{ + main0_out out = {}; + spvUnsafeArray in_var_ATTRIBUTE1 = {}; + in_var_ATTRIBUTE1[0] = in.in_var_ATTRIBUTE1_0; + in_var_ATTRIBUTE1[1] = in.in_var_ATTRIBUTE1_1; + spvUnsafeArray _97; + for (int _107 = 0; _107 < 1; ) + { + _97[_107] = float4(0.0); + _107++; + continue; + } + float4 _115 = in.in_var_ATTRIBUTE0 * float4(255.0); + float2 _116 = _115.zw; + float2 _119 = fract(_116 * float2(0.5)) * float2(2.0); + float2 _121 = (_116 - _119) * float2(0.0039215688593685626983642578125); + float2 _122 = _115.xy; + float2 _126 = _122 * float2(_Globals.LodValues.w); + float _127 = _126.y; + float _128 = _126.x; + float4 _132 = float4(_127, _128, 1.0 - _128, 1.0 - _127) * float4(2.0); + float4 _186; + if (_119.y > 0.5) + { + float4 _161; + if (_119.x > 0.5) + { + _161 = (_132 * float4(_Globals.SectionLods.w)) + ((float4(1.0) - _132) * _Globals.NeighborSectionLod[3]); + } + else + { + _161 = (_132 * float4(_Globals.SectionLods.z)) + ((float4(1.0) - _132) * _Globals.NeighborSectionLod[2]); + } + _186 = _161; + } + else + { + float4 _185; + if (_119.x > 0.5) + { + _185 = (_132 * float4(_Globals.SectionLods.y)) + ((float4(1.0) - _132) * _Globals.NeighborSectionLod[1]); + } + else + { + _185 = (_132 * float4(_Globals.SectionLods.x)) + ((float4(1.0) - _132) * _Globals.NeighborSectionLod[0]); + } + _186 = _185; + } + float _206; + if ((_128 + _127) > 1.0) + { + float _198; + if (_128 < _127) + { + _198 = _186.w; + } + else + { + _198 = _186.z; + } + _206 = _198; + } + else + { + float _205; + if (_128 < _127) + { + _205 = _186.y; + } + else + { + _205 = _186.x; + } + _206 = _205; + } + float _207 = floor(_206); + float _220 = _121.x; + float3 _235 = select(select(select(select(select(float3(0.03125, _121.yy), float3(0.0625, _220, _121.y), bool3(_207 < 5.0)), float3(0.125, in_var_ATTRIBUTE1[1].w, _220), bool3(_207 < 4.0)), float3(0.25, in_var_ATTRIBUTE1[1].zw), bool3(_207 < 3.0)), float3(0.5, in_var_ATTRIBUTE1[1].yz), bool3(_207 < 2.0)), float3(1.0, in_var_ATTRIBUTE1[1].xy), bool3(_207 < 1.0)); + float _236 = _235.x; + float _245 = (((in_var_ATTRIBUTE1[0].x * 65280.0) + (in_var_ATTRIBUTE1[0].y * 255.0)) - 32768.0) * 0.0078125; + float _252 = (((in_var_ATTRIBUTE1[0].z * 65280.0) + (in_var_ATTRIBUTE1[0].w * 255.0)) - 32768.0) * 0.0078125; + float2 _257 = floor(_122 * float2(_236)); + float2 _271 = float2((LandscapeParameters.LandscapeParameters_SubsectionSizeVertsLayerUVPan.x * _236) - 1.0, fast::max((LandscapeParameters.LandscapeParameters_SubsectionSizeVertsLayerUVPan.x * 0.5) * _236, 2.0) - 1.0) * float2(LandscapeParameters.LandscapeParameters_SubsectionSizeVertsLayerUVPan.y); + float3 _287 = mix(float3(_257 / float2(_271.x), mix(_245, _252, _235.y)), float3(floor(_257 * float2(0.5)) / float2(_271.y), mix(_245, _252, _235.z)), float3(_206 - _207)); + float2 _288 = _119.xy; + float2 _292 = _288 * LandscapeParameters.LandscapeParameters_SubsectionOffsetParams.ww; + float3 _296 = _287 + float3(_292, 0.0); + float4 _322 = float4((((Primitive.Primitive_LocalToWorld[0u].xyz * _296.xxx) + (Primitive.Primitive_LocalToWorld[1u].xyz * _296.yyy)) + (Primitive.Primitive_LocalToWorld[2u].xyz * _296.zzz)) + (Primitive.Primitive_LocalToWorld[3u].xyz + float3(View.View_PreViewTranslation)), 1.0); + float2 _323 = _287.xy; + float4 _338 = float4(_322.x, _322.y, _322.z, _322.w); + float4 _339 = View.View_TranslatedWorldToClip * _338; + float3 _341 = _322.xyz - float3(View.View_TranslatedWorldCameraOrigin); + float _345 = dot(_341, _341); + float _346 = rsqrt(_345); + float _347 = _345 * _346; + float _354 = _341.z; + float _357 = fast::max(0.0, MobileBasePass.MobileBasePass_Fog_ExponentialFogParameters.w); + float _393; + float _394; + float _395; + float _396; + if (_357 > 0.0) + { + float _361 = _357 * _346; + float _362 = _361 * _354; + float _365 = View.View_WorldCameraOrigin[2] + _362; + _393 = (1.0 - _361) * _347; + _394 = MobileBasePass.MobileBasePass_Fog_ExponentialFogParameters2.z * exp2(-fast::max(-127.0, MobileBasePass.MobileBasePass_Fog_ExponentialFogParameters2.y * (_365 - MobileBasePass.MobileBasePass_Fog_ExponentialFogParameters2.w))); + _395 = MobileBasePass.MobileBasePass_Fog_ExponentialFogParameters3.x * exp2(-fast::max(-127.0, MobileBasePass.MobileBasePass_Fog_ExponentialFogParameters.y * (_365 - MobileBasePass.MobileBasePass_Fog_ExponentialFogParameters3.y))); + _396 = _354 - _362; + } + else + { + _393 = _347; + _394 = MobileBasePass.MobileBasePass_Fog_ExponentialFogParameters2.x; + _395 = MobileBasePass.MobileBasePass_Fog_ExponentialFogParameters.x; + _396 = _354; + } + float _400 = fast::max(-127.0, MobileBasePass.MobileBasePass_Fog_ExponentialFogParameters.y * _396); + float _417 = fast::max(-127.0, MobileBasePass.MobileBasePass_Fog_ExponentialFogParameters2.y * _396); + float _428 = (_395 * ((abs(_400) > 0.00999999977648258209228515625) ? ((1.0 - exp2(-_400)) / _400) : (0.693147182464599609375 - (0.2402265071868896484375 * _400)))) + (_394 * ((abs(_417) > 0.00999999977648258209228515625) ? ((1.0 - exp2(-_417)) / _417) : (0.693147182464599609375 - (0.2402265071868896484375 * _417)))); + float3 _459; + if (MobileBasePass.MobileBasePass_Fog_InscatteringLightDirection.w >= 0.0) + { + _459 = (MobileBasePass.MobileBasePass_Fog_DirectionalInscatteringColor.xyz * float3(pow(fast::clamp(dot(_341 * float3(_346), MobileBasePass.MobileBasePass_Fog_InscatteringLightDirection.xyz), 0.0, 1.0), MobileBasePass.MobileBasePass_Fog_DirectionalInscatteringColor.w))) * float3(1.0 - fast::clamp(exp2(-(_428 * fast::max(_393 - MobileBasePass.MobileBasePass_Fog_InscatteringLightDirection.w, 0.0))), 0.0, 1.0)); + } + else + { + _459 = float3(0.0); + } + bool _468 = (MobileBasePass.MobileBasePass_Fog_ExponentialFogParameters3.w > 0.0) && (_347 > MobileBasePass.MobileBasePass_Fog_ExponentialFogParameters3.w); + float _471 = _468 ? 1.0 : fast::max(fast::clamp(exp2(-(_428 * _393)), 0.0, 1.0), MobileBasePass.MobileBasePass_Fog_ExponentialFogColorParameter.w); + _97[0] = float4((MobileBasePass.MobileBasePass_Fog_ExponentialFogColorParameter.xyz * float3(1.0 - _471)) + select(_459, float3(0.0), bool3(_468)), _471); + float4 _482 = _338; + _482.w = _339.w; + out.out_var_TEXCOORD0 = ((_323 + LandscapeParameters.LandscapeParameters_SubsectionSizeVertsLayerUVPan.zw) + _292).xy; + out.out_var_TEXCOORD1 = ((_323 * LandscapeParameters.LandscapeParameters_WeightmapUVScaleBias.xy) + LandscapeParameters.LandscapeParameters_WeightmapUVScaleBias.zw) + (_288 * LandscapeParameters.LandscapeParameters_SubsectionOffsetParams.zz); + out.out_var_TEXCOORD2 = float4(float4(0.0).x, float4(0.0).y, _97[0].x, _97[0].y); + out.out_var_TEXCOORD3 = float4(float4(0.0).x, float4(0.0).y, _97[0].z, _97[0].w); + out.out_var_TEXCOORD8 = _482; + out.gl_Position = _339; + return out; +} + diff --git a/third_party/spirv-cross/reference/opt/shaders-ue4/asm/vert/texture-buffer.asm.vert b/third_party/spirv-cross/reference/opt/shaders-ue4/asm/vert/texture-buffer.asm.vert new file mode 100644 index 0000000000..6384e1b9d4 --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders-ue4/asm/vert/texture-buffer.asm.vert @@ -0,0 +1,387 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" + +#include +#include + +using namespace metal; + +struct type_View +{ + float4x4 View_TranslatedWorldToClip; + float4x4 View_WorldToClip; + float4x4 View_TranslatedWorldToView; + float4x4 View_ViewToTranslatedWorld; + float4x4 View_TranslatedWorldToCameraView; + float4x4 View_CameraViewToTranslatedWorld; + float4x4 View_ViewToClip; + float4x4 View_ViewToClipNoAA; + float4x4 View_ClipToView; + float4x4 View_ClipToTranslatedWorld; + float4x4 View_SVPositionToTranslatedWorld; + float4x4 View_ScreenToWorld; + float4x4 View_ScreenToTranslatedWorld; + packed_float3 View_ViewForward; + float PrePadding_View_844; + packed_float3 View_ViewUp; + float PrePadding_View_860; + packed_float3 View_ViewRight; + float PrePadding_View_876; + packed_float3 View_HMDViewNoRollUp; + float PrePadding_View_892; + packed_float3 View_HMDViewNoRollRight; + float PrePadding_View_908; + float4 View_InvDeviceZToWorldZTransform; + float4 View_ScreenPositionScaleBias; + packed_float3 View_WorldCameraOrigin; + float PrePadding_View_956; + packed_float3 View_TranslatedWorldCameraOrigin; + float PrePadding_View_972; + packed_float3 View_WorldViewOrigin; + float PrePadding_View_988; + packed_float3 View_PreViewTranslation; + float PrePadding_View_1004; + float4x4 View_PrevProjection; + float4x4 View_PrevViewProj; + float4x4 View_PrevViewRotationProj; + float4x4 View_PrevViewToClip; + float4x4 View_PrevClipToView; + float4x4 View_PrevTranslatedWorldToClip; + float4x4 View_PrevTranslatedWorldToView; + float4x4 View_PrevViewToTranslatedWorld; + float4x4 View_PrevTranslatedWorldToCameraView; + float4x4 View_PrevCameraViewToTranslatedWorld; + packed_float3 View_PrevWorldCameraOrigin; + float PrePadding_View_1660; + packed_float3 View_PrevWorldViewOrigin; + float PrePadding_View_1676; + packed_float3 View_PrevPreViewTranslation; + float PrePadding_View_1692; + float4x4 View_PrevInvViewProj; + float4x4 View_PrevScreenToTranslatedWorld; + float4x4 View_ClipToPrevClip; + float4 View_TemporalAAJitter; + float4 View_GlobalClippingPlane; + float2 View_FieldOfViewWideAngles; + float2 View_PrevFieldOfViewWideAngles; + float4 View_ViewRectMin; + float4 View_ViewSizeAndInvSize; + float4 View_BufferSizeAndInvSize; + float4 View_BufferBilinearUVMinMax; + int View_NumSceneColorMSAASamples; + float View_PreExposure; + float View_OneOverPreExposure; + float PrePadding_View_2012; + float4 View_DiffuseOverrideParameter; + float4 View_SpecularOverrideParameter; + float4 View_NormalOverrideParameter; + float2 View_RoughnessOverrideParameter; + float View_PrevFrameGameTime; + float View_PrevFrameRealTime; + float View_OutOfBoundsMask; + float PrePadding_View_2084; + float PrePadding_View_2088; + float PrePadding_View_2092; + packed_float3 View_WorldCameraMovementSinceLastFrame; + float View_CullingSign; + float View_NearPlane; + float View_AdaptiveTessellationFactor; + float View_GameTime; + float View_RealTime; + float View_DeltaTime; + float View_MaterialTextureMipBias; + float View_MaterialTextureDerivativeMultiply; + uint View_Random; + uint View_FrameNumber; + uint View_StateFrameIndexMod8; + uint View_StateFrameIndex; + float View_CameraCut; + float View_UnlitViewmodeMask; + float PrePadding_View_2164; + float PrePadding_View_2168; + float PrePadding_View_2172; + float4 View_DirectionalLightColor; + packed_float3 View_DirectionalLightDirection; + float PrePadding_View_2204; + float4 View_TranslucencyLightingVolumeMin[2]; + float4 View_TranslucencyLightingVolumeInvSize[2]; + float4 View_TemporalAAParams; + float4 View_CircleDOFParams; + float View_DepthOfFieldSensorWidth; + float View_DepthOfFieldFocalDistance; + float View_DepthOfFieldScale; + float View_DepthOfFieldFocalLength; + float View_DepthOfFieldFocalRegion; + float View_DepthOfFieldNearTransitionRegion; + float View_DepthOfFieldFarTransitionRegion; + float View_MotionBlurNormalizedToPixel; + float View_bSubsurfacePostprocessEnabled; + float View_GeneralPurposeTweak; + float View_DemosaicVposOffset; + float PrePadding_View_2348; + packed_float3 View_IndirectLightingColorScale; + float View_HDR32bppEncodingMode; + packed_float3 View_AtmosphericFogSunDirection; + float View_AtmosphericFogSunPower; + float View_AtmosphericFogPower; + float View_AtmosphericFogDensityScale; + float View_AtmosphericFogDensityOffset; + float View_AtmosphericFogGroundOffset; + float View_AtmosphericFogDistanceScale; + float View_AtmosphericFogAltitudeScale; + float View_AtmosphericFogHeightScaleRayleigh; + float View_AtmosphericFogStartDistance; + float View_AtmosphericFogDistanceOffset; + float View_AtmosphericFogSunDiscScale; + uint View_AtmosphericFogRenderMask; + uint View_AtmosphericFogInscatterAltitudeSampleNum; + float4 View_AtmosphericFogSunColor; + packed_float3 View_NormalCurvatureToRoughnessScaleBias; + float View_RenderingReflectionCaptureMask; + float4 View_AmbientCubemapTint; + float View_AmbientCubemapIntensity; + float View_SkyLightParameters; + float PrePadding_View_2488; + float PrePadding_View_2492; + float4 View_SkyLightColor; + float4 View_SkyIrradianceEnvironmentMap[7]; + float View_MobilePreviewMode; + float View_HMDEyePaddingOffset; + float View_ReflectionCubemapMaxMip; + float View_ShowDecalsMask; + uint View_DistanceFieldAOSpecularOcclusionMode; + float View_IndirectCapsuleSelfShadowingIntensity; + float PrePadding_View_2648; + float PrePadding_View_2652; + packed_float3 View_ReflectionEnvironmentRoughnessMixingScaleBiasAndLargestWeight; + int View_StereoPassIndex; + float4 View_GlobalVolumeCenterAndExtent[4]; + float4 View_GlobalVolumeWorldToUVAddAndMul[4]; + float View_GlobalVolumeDimension; + float View_GlobalVolumeTexelSize; + float View_MaxGlobalDistance; + float View_bCheckerboardSubsurfaceProfileRendering; + packed_float3 View_VolumetricFogInvGridSize; + float PrePadding_View_2828; + packed_float3 View_VolumetricFogGridZParams; + float PrePadding_View_2844; + float2 View_VolumetricFogSVPosToVolumeUV; + float View_VolumetricFogMaxDistance; + float PrePadding_View_2860; + packed_float3 View_VolumetricLightmapWorldToUVScale; + float PrePadding_View_2876; + packed_float3 View_VolumetricLightmapWorldToUVAdd; + float PrePadding_View_2892; + packed_float3 View_VolumetricLightmapIndirectionTextureSize; + float View_VolumetricLightmapBrickSize; + packed_float3 View_VolumetricLightmapBrickTexelSize; + float View_StereoIPD; + float View_IndirectLightingCacheShowFlag; + float View_EyeToPixelSpreadAngle; +}; + +struct type_Primitive +{ + float4x4 Primitive_LocalToWorld; + float4 Primitive_InvNonUniformScaleAndDeterminantSign; + float4 Primitive_ObjectWorldPositionAndRadius; + float4x4 Primitive_WorldToLocal; + float4x4 Primitive_PreviousLocalToWorld; + float4x4 Primitive_PreviousWorldToLocal; + packed_float3 Primitive_ActorWorldPosition; + float Primitive_UseSingleSampleShadowFromStationaryLights; + packed_float3 Primitive_ObjectBounds; + float Primitive_LpvBiasMultiplier; + float Primitive_DecalReceiverMask; + float Primitive_PerObjectGBufferData; + float Primitive_UseVolumetricLightmapShadowFromStationaryLights; + float Primitive_UseEditorDepthTest; + float4 Primitive_ObjectOrientation; + float4 Primitive_NonUniformScale; + packed_float3 Primitive_LocalObjectBoundsMin; + float PrePadding_Primitive_380; + packed_float3 Primitive_LocalObjectBoundsMax; + uint Primitive_LightingChannelMask; + uint Primitive_LightmapDataIndex; + int Primitive_SingleCaptureIndex; +}; + +struct type_MobileShadowDepthPass +{ + float PrePadding_MobileShadowDepthPass_0; + float PrePadding_MobileShadowDepthPass_4; + float PrePadding_MobileShadowDepthPass_8; + float PrePadding_MobileShadowDepthPass_12; + float PrePadding_MobileShadowDepthPass_16; + float PrePadding_MobileShadowDepthPass_20; + float PrePadding_MobileShadowDepthPass_24; + float PrePadding_MobileShadowDepthPass_28; + float PrePadding_MobileShadowDepthPass_32; + float PrePadding_MobileShadowDepthPass_36; + float PrePadding_MobileShadowDepthPass_40; + float PrePadding_MobileShadowDepthPass_44; + float PrePadding_MobileShadowDepthPass_48; + float PrePadding_MobileShadowDepthPass_52; + float PrePadding_MobileShadowDepthPass_56; + float PrePadding_MobileShadowDepthPass_60; + float PrePadding_MobileShadowDepthPass_64; + float PrePadding_MobileShadowDepthPass_68; + float PrePadding_MobileShadowDepthPass_72; + float PrePadding_MobileShadowDepthPass_76; + float4x4 MobileShadowDepthPass_ProjectionMatrix; + float2 MobileShadowDepthPass_ShadowParams; + float MobileShadowDepthPass_bClampToNearPlane; + float PrePadding_MobileShadowDepthPass_156; + float4x4 MobileShadowDepthPass_ShadowViewProjectionMatrices[6]; +}; + +struct type_EmitterDynamicUniforms +{ + float2 EmitterDynamicUniforms_LocalToWorldScale; + float EmitterDynamicUniforms_EmitterInstRandom; + float PrePadding_EmitterDynamicUniforms_12; + float4 EmitterDynamicUniforms_AxisLockRight; + float4 EmitterDynamicUniforms_AxisLockUp; + float4 EmitterDynamicUniforms_DynamicColor; + float4 EmitterDynamicUniforms_MacroUVParameters; +}; + +struct type_EmitterUniforms +{ + float4 EmitterUniforms_ColorCurve; + float4 EmitterUniforms_ColorScale; + float4 EmitterUniforms_ColorBias; + float4 EmitterUniforms_MiscCurve; + float4 EmitterUniforms_MiscScale; + float4 EmitterUniforms_MiscBias; + float4 EmitterUniforms_SizeBySpeed; + float4 EmitterUniforms_SubImageSize; + float4 EmitterUniforms_TangentSelector; + packed_float3 EmitterUniforms_CameraFacingBlend; + float EmitterUniforms_RemoveHMDRoll; + float EmitterUniforms_RotationRateScale; + float EmitterUniforms_RotationBias; + float EmitterUniforms_CameraMotionBlurAmount; + float PrePadding_EmitterUniforms_172; + float2 EmitterUniforms_PivotOffset; +}; + +struct type_Globals +{ + uint ParticleIndicesOffset; +}; + +struct main0_out +{ + float out_var_TEXCOORD6 [[user(locn0)]]; + float4 gl_Position [[position]]; +}; + +struct main0_in +{ + float2 in_var_ATTRIBUTE0 [[attribute(0)]]; +}; + +// Returns 2D texture coords corresponding to 1D texel buffer coords +static inline __attribute__((always_inline)) +uint2 spvTexelBufferCoord(uint tc) +{ + return uint2(tc % 4096, tc / 4096); +} + +vertex main0_out main0(main0_in in [[stage_in]], constant type_View& View [[buffer(0)]], constant type_Primitive& Primitive [[buffer(1)]], constant type_MobileShadowDepthPass& MobileShadowDepthPass [[buffer(2)]], constant type_EmitterDynamicUniforms& EmitterDynamicUniforms [[buffer(3)]], constant type_EmitterUniforms& EmitterUniforms [[buffer(4)]], constant type_Globals& _Globals [[buffer(5)]], texture2d ParticleIndices [[texture(0)]], texture2d PositionTexture [[texture(1)]], texture2d VelocityTexture [[texture(2)]], texture2d AttributesTexture [[texture(3)]], texture2d CurveTexture [[texture(4)]], sampler PositionTextureSampler [[sampler(0)]], sampler VelocityTextureSampler [[sampler(1)]], sampler AttributesTextureSampler [[sampler(2)]], sampler CurveTextureSampler [[sampler(3)]], uint gl_VertexIndex [[vertex_id]], uint gl_InstanceIndex [[instance_id]]) +{ + main0_out out = {}; + float2 _133 = ParticleIndices.read(spvTexelBufferCoord((_Globals.ParticleIndicesOffset + ((gl_InstanceIndex * 16u) + (gl_VertexIndex / 4u))))).xy; + float4 _137 = PositionTexture.sample(PositionTextureSampler, _133, level(0.0)); + float4 _145 = AttributesTexture.sample(AttributesTextureSampler, _133, level(0.0)); + float _146 = _137.w; + float3 _158 = float3x3(Primitive.Primitive_LocalToWorld[0].xyz, Primitive.Primitive_LocalToWorld[1].xyz, Primitive.Primitive_LocalToWorld[2].xyz) * VelocityTexture.sample(VelocityTextureSampler, _133, level(0.0)).xyz; + float3 _160 = normalize(_158 + float3(0.0, 0.0, 9.9999997473787516355514526367188e-05)); + float2 _204 = ((((_145.xy + float2((_145.x < 0.5) ? 0.0 : (-0.5), (_145.y < 0.5) ? 0.0 : (-0.5))) * float2(2.0)) * (((CurveTexture.sample(CurveTextureSampler, (EmitterUniforms.EmitterUniforms_MiscCurve.xy + (EmitterUniforms.EmitterUniforms_MiscCurve.zw * float2(_146))), level(0.0)) * EmitterUniforms.EmitterUniforms_MiscScale) + EmitterUniforms.EmitterUniforms_MiscBias).xy * EmitterDynamicUniforms.EmitterDynamicUniforms_LocalToWorldScale)) * fast::min(fast::max(EmitterUniforms.EmitterUniforms_SizeBySpeed.xy * float2(length(_158)), float2(1.0)), EmitterUniforms.EmitterUniforms_SizeBySpeed.zw)) * float2(step(_146, 1.0)); + float3 _239 = float4((((Primitive.Primitive_LocalToWorld[0u].xyz * _137.xxx) + (Primitive.Primitive_LocalToWorld[1u].xyz * _137.yyy)) + (Primitive.Primitive_LocalToWorld[2u].xyz * _137.zzz)) + (Primitive.Primitive_LocalToWorld[3u].xyz + float3(View.View_PreViewTranslation)), 1.0).xyz; + float3 _242 = float3(EmitterUniforms.EmitterUniforms_RemoveHMDRoll); + float3 _251 = mix(mix(float3(View.View_ViewRight), float3(View.View_HMDViewNoRollRight), _242), EmitterDynamicUniforms.EmitterDynamicUniforms_AxisLockRight.xyz, float3(EmitterDynamicUniforms.EmitterDynamicUniforms_AxisLockRight.w)); + float3 _259 = mix(-mix(float3(View.View_ViewUp), float3(View.View_HMDViewNoRollUp), _242), EmitterDynamicUniforms.EmitterDynamicUniforms_AxisLockUp.xyz, float3(EmitterDynamicUniforms.EmitterDynamicUniforms_AxisLockUp.w)); + float3 _260 = float3(View.View_TranslatedWorldCameraOrigin) - _239; + float _261 = dot(_260, _260); + float3 _265 = _260 / float3(sqrt(fast::max(_261, 0.00999999977648258209228515625))); + float3 _335; + float3 _336; + if (EmitterUniforms.EmitterUniforms_CameraFacingBlend[0] > 0.0) + { + float3 _279 = cross(_265, float3(0.0, 0.0, 1.0)); + float3 _284 = _279 / float3(sqrt(fast::max(dot(_279, _279), 0.00999999977648258209228515625))); + float3 _286 = float3(fast::clamp((_261 * EmitterUniforms.EmitterUniforms_CameraFacingBlend[1]) - EmitterUniforms.EmitterUniforms_CameraFacingBlend[2], 0.0, 1.0)); + _335 = normalize(mix(_251, _284, _286)); + _336 = normalize(mix(_259, cross(_265, _284), _286)); + } + else + { + float3 _333; + float3 _334; + if (EmitterUniforms.EmitterUniforms_TangentSelector.y > 0.0) + { + float3 _297 = cross(_265, _160); + _333 = _297 / float3(sqrt(fast::max(dot(_297, _297), 0.00999999977648258209228515625))); + _334 = -_160; + } + else + { + float3 _331; + float3 _332; + if (EmitterUniforms.EmitterUniforms_TangentSelector.z > 0.0) + { + float3 _310 = cross(EmitterDynamicUniforms.EmitterDynamicUniforms_AxisLockRight.xyz, _265); + _331 = EmitterDynamicUniforms.EmitterDynamicUniforms_AxisLockRight.xyz; + _332 = -(_310 / float3(sqrt(fast::max(dot(_310, _310), 0.00999999977648258209228515625)))); + } + else + { + float3 _329; + float3 _330; + if (EmitterUniforms.EmitterUniforms_TangentSelector.w > 0.0) + { + float3 _322 = cross(_265, float3(0.0, 0.0, 1.0)); + float3 _327 = _322 / float3(sqrt(fast::max(dot(_322, _322), 0.00999999977648258209228515625))); + _329 = _327; + _330 = cross(_265, _327); + } + else + { + _329 = _251; + _330 = _259; + } + _331 = _329; + _332 = _330; + } + _333 = _331; + _334 = _332; + } + _335 = _333; + _336 = _334; + } + float _339 = ((_145.z + ((_145.w * EmitterUniforms.EmitterUniforms_RotationRateScale) * _146)) * 6.283185482025146484375) + EmitterUniforms.EmitterUniforms_RotationBias; + float3 _342 = float3(sin(_339)); + float3 _344 = float3(cos(_339)); + float4 _371 = float4(_239 + ((float3(_204.x * (in.in_var_ATTRIBUTE0.x + EmitterUniforms.EmitterUniforms_PivotOffset.x)) * ((_342 * _336) + (_344 * _335))) + (float3(_204.y * (in.in_var_ATTRIBUTE0.y + EmitterUniforms.EmitterUniforms_PivotOffset.y)) * ((_344 * _336) - (_342 * _335)))), 1.0); + float4 _375 = MobileShadowDepthPass.MobileShadowDepthPass_ProjectionMatrix * float4(_371.x, _371.y, _371.z, _371.w); + float4 _386; + if ((MobileShadowDepthPass.MobileShadowDepthPass_bClampToNearPlane > 0.0) && (_375.z < 0.0)) + { + float4 _384 = _375; + _384.z = 9.9999999747524270787835121154785e-07; + float4 _385 = _384; + _385.w = 1.0; + _386 = _385; + } + else + { + _386 = _375; + } + float4 _396 = _386; + _396.z = ((_386.z * MobileShadowDepthPass.MobileShadowDepthPass_ShadowParams.y) + MobileShadowDepthPass.MobileShadowDepthPass_ShadowParams.x) * _386.w; + out.out_var_TEXCOORD6 = 0.0; + out.gl_Position = _396; + return out; +} + diff --git a/third_party/spirv-cross/reference/opt/shaders/asm/comp/bitcast_icmp.asm.comp b/third_party/spirv-cross/reference/opt/shaders/asm/comp/bitcast_icmp.asm.comp new file mode 100644 index 0000000000..bed3b90a7b --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders/asm/comp/bitcast_icmp.asm.comp @@ -0,0 +1,27 @@ +#version 310 es +layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in; + +layout(binding = 0, std430) restrict buffer _3_5 +{ + ivec4 _m0; + uvec4 _m1; +} _5; + +layout(binding = 1, std430) restrict buffer _4_6 +{ + uvec4 _m0; + ivec4 _m1; +} _6; + +void main() +{ + _6._m0 = mix(uvec4(0u), uvec4(1u), lessThan(ivec4(_5._m1), _5._m0)); + _6._m0 = mix(uvec4(0u), uvec4(1u), lessThanEqual(ivec4(_5._m1), _5._m0)); + _6._m0 = mix(uvec4(0u), uvec4(1u), lessThan(_5._m1, uvec4(_5._m0))); + _6._m0 = mix(uvec4(0u), uvec4(1u), lessThanEqual(_5._m1, uvec4(_5._m0))); + _6._m0 = mix(uvec4(0u), uvec4(1u), greaterThan(ivec4(_5._m1), _5._m0)); + _6._m0 = mix(uvec4(0u), uvec4(1u), greaterThanEqual(ivec4(_5._m1), _5._m0)); + _6._m0 = mix(uvec4(0u), uvec4(1u), greaterThan(_5._m1, uvec4(_5._m0))); + _6._m0 = mix(uvec4(0u), uvec4(1u), greaterThanEqual(_5._m1, uvec4(_5._m0))); +} + diff --git a/third_party/spirv-cross/reference/opt/shaders/asm/comp/switch-break-ladder.asm.comp b/third_party/spirv-cross/reference/opt/shaders/asm/comp/switch-break-ladder.asm.comp index 4cf3f126d6..2aebe7941c 100644 --- a/third_party/spirv-cross/reference/opt/shaders/asm/comp/switch-break-ladder.asm.comp +++ b/third_party/spirv-cross/reference/opt/shaders/asm/comp/switch-break-ladder.asm.comp @@ -12,9 +12,10 @@ void main() { int _44; _44 = o.a; - int _48; + int _41; for (;;) { + int _48; bool _22_ladder_break = false; switch (_44) { @@ -61,7 +62,8 @@ void main() { break; } - _44 = _48 + 1; + _41 = _48 + 1; + _44 = _41; continue; } o.b = _44; diff --git a/third_party/spirv-cross/reference/opt/shaders/asm/frag/complex-name-workarounds.asm.frag b/third_party/spirv-cross/reference/opt/shaders/asm/frag/complex-name-workarounds.asm.frag index c07f1657f4..d68f84b48e 100644 --- a/third_party/spirv-cross/reference/opt/shaders/asm/frag/complex-name-workarounds.asm.frag +++ b/third_party/spirv-cross/reference/opt/shaders/asm/frag/complex-name-workarounds.asm.frag @@ -7,10 +7,9 @@ layout(location = 0) out vec4 b; void main() { vec4 _28 = (_ + a) + _; - vec4 _34 = (_ - a) + a; b = _28; - b = _34; + b = _; b = _28; - b = _34; + b = _; } diff --git a/third_party/spirv-cross/reference/opt/shaders/asm/frag/image-fetch-no-sampler.no-samplerless.asm.vk.frag b/third_party/spirv-cross/reference/opt/shaders/asm/frag/image-fetch-no-sampler.no-samplerless.asm.vk.frag new file mode 100644 index 0000000000..452fd6fb95 --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders/asm/frag/image-fetch-no-sampler.no-samplerless.asm.vk.frag @@ -0,0 +1,13 @@ +#version 450 + +uniform sampler2D SPIRV_Cross_CombinedSampledImageSPIRV_Cross_DummySampler; +uniform sampler2D SPIRV_Cross_CombinedSampledImageSampler; + +layout(location = 0) out vec4 _entryPointOutput; + +void main() +{ + ivec2 _152 = ivec3(int(gl_FragCoord.x * 1280.0), int(gl_FragCoord.y * 720.0), 0).xy; + _entryPointOutput = ((texelFetch(SPIRV_Cross_CombinedSampledImageSPIRV_Cross_DummySampler, _152, 0) + texelFetch(SPIRV_Cross_CombinedSampledImageSPIRV_Cross_DummySampler, _152, 0)) + texture(SPIRV_Cross_CombinedSampledImageSampler, gl_FragCoord.xy)) + texture(SPIRV_Cross_CombinedSampledImageSampler, gl_FragCoord.xy); +} + diff --git a/third_party/spirv-cross/reference/opt/shaders/asm/frag/image-fetch-no-sampler.no-samplerless.asm.vk.frag.vk b/third_party/spirv-cross/reference/opt/shaders/asm/frag/image-fetch-no-sampler.no-samplerless.asm.vk.frag.vk new file mode 100644 index 0000000000..23acab0b16 --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders/asm/frag/image-fetch-no-sampler.no-samplerless.asm.vk.frag.vk @@ -0,0 +1,14 @@ +#version 450 + +layout(set = 0, binding = 0) uniform sampler Sampler; +layout(set = 0, binding = 0) uniform texture2D SampledImage; +layout(set = 0, binding = 0) uniform sampler SPIRV_Cross_DummySampler; + +layout(location = 0) out vec4 _entryPointOutput; + +void main() +{ + ivec2 _152 = ivec3(int(gl_FragCoord.x * 1280.0), int(gl_FragCoord.y * 720.0), 0).xy; + _entryPointOutput = ((texelFetch(sampler2D(SampledImage, SPIRV_Cross_DummySampler), _152, 0) + texelFetch(sampler2D(SampledImage, SPIRV_Cross_DummySampler), _152, 0)) + texture(sampler2D(SampledImage, Sampler), gl_FragCoord.xy)) + texture(sampler2D(SampledImage, Sampler), gl_FragCoord.xy); +} + diff --git a/third_party/spirv-cross/reference/opt/shaders/asm/frag/image-query-no-sampler.no-samplerless.vk.asm.frag b/third_party/spirv-cross/reference/opt/shaders/asm/frag/image-query-no-sampler.no-samplerless.vk.asm.frag new file mode 100644 index 0000000000..05ce10adfa --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders/asm/frag/image-query-no-sampler.no-samplerless.vk.asm.frag @@ -0,0 +1,6 @@ +#version 450 + +void main() +{ +} + diff --git a/third_party/spirv-cross/reference/opt/shaders/asm/frag/image-query-no-sampler.no-samplerless.vk.asm.frag.vk b/third_party/spirv-cross/reference/opt/shaders/asm/frag/image-query-no-sampler.no-samplerless.vk.asm.frag.vk new file mode 100644 index 0000000000..05ce10adfa --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders/asm/frag/image-query-no-sampler.no-samplerless.vk.asm.frag.vk @@ -0,0 +1,6 @@ +#version 450 + +void main() +{ +} + diff --git a/third_party/spirv-cross/reference/opt/shaders/asm/frag/line-directive.line.asm.frag b/third_party/spirv-cross/reference/opt/shaders/asm/frag/line-directive.line.asm.frag index 30be934fc6..74eb62bbe2 100644 --- a/third_party/spirv-cross/reference/opt/shaders/asm/frag/line-directive.line.asm.frag +++ b/third_party/spirv-cross/reference/opt/shaders/asm/frag/line-directive.line.asm.frag @@ -7,14 +7,12 @@ layout(location = 0) in float vColor; #line 8 "test.frag" void main() { - float _80; #line 8 "test.frag" FragColor = 1.0; #line 9 "test.frag" FragColor = 2.0; #line 10 "test.frag" - _80 = vColor; - if (_80 < 0.0) + if (vColor < 0.0) { #line 12 "test.frag" FragColor = 3.0; @@ -24,16 +22,16 @@ void main() #line 16 "test.frag" FragColor = 4.0; } - for (int _126 = 0; float(_126) < (40.0 + _80); ) + for (int _126 = 0; float(_126) < (40.0 + vColor); ) { #line 21 "test.frag" FragColor += 0.20000000298023223876953125; #line 22 "test.frag" FragColor += 0.300000011920928955078125; - _126 += (int(_80) + 5); + _126 += (int(vColor) + 5); continue; } - switch (int(_80)) + switch (int(vColor)) { case 0: { @@ -59,7 +57,7 @@ void main() } for (;;) { - FragColor += (10.0 + _80); + FragColor += (10.0 + vColor); #line 43 "test.frag" if (FragColor < 100.0) { diff --git a/third_party/spirv-cross/reference/opt/shaders/asm/frag/loop-body-dominator-continue-access.asm.frag b/third_party/spirv-cross/reference/opt/shaders/asm/frag/loop-body-dominator-continue-access.asm.frag index ad7913294e..f3028a47a6 100644 --- a/third_party/spirv-cross/reference/opt/shaders/asm/frag/loop-body-dominator-continue-access.asm.frag +++ b/third_party/spirv-cross/reference/opt/shaders/asm/frag/loop-body-dominator-continue-access.asm.frag @@ -10,67 +10,60 @@ layout(binding = 0, std140) uniform Foo layout(location = 0) in vec3 fragWorld; layout(location = 0) out int _entryPointOutput; -int _240; +int _228; void main() { - uint _227; - int _236; - for (;;) + int _225; + switch (0u) { - _227 = 0u; - bool _231; - int _237; - for (;;) + default: { - if (_227 < _11.shadowCascadesNum) + bool _222; + int _226; + uint _219 = 0u; + for (;;) { - mat4 _228; - for (;;) + if (_219 < _11.shadowCascadesNum) { - if (_11.test == 0) + mat4 _220; + switch (0u) { - _228 = mat4(vec4(0.5, 0.0, 0.0, 0.0), vec4(0.0, 0.5, 0.0, 0.0), vec4(0.0, 0.0, 0.5, 0.0), vec4(0.0, 0.0, 0.0, 1.0)); + default: + { + if (_11.test == 0) + { + _220 = mat4(vec4(0.5, 0.0, 0.0, 0.0), vec4(0.0, 0.5, 0.0, 0.0), vec4(0.0, 0.0, 0.5, 0.0), vec4(0.0, 0.0, 0.0, 1.0)); + break; + } + _220 = mat4(vec4(1.0, 0.0, 0.0, 0.0), vec4(0.0, 1.0, 0.0, 0.0), vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)); + break; + } + } + vec4 _171 = (_220 * _11.lightVP[_219]) * vec4(fragWorld, 1.0); + float _173 = _171.z; + float _180 = _171.x; + float _182 = _171.y; + if ((((_173 >= 0.0) && (_173 <= 1.0)) && (max(_180, _182) <= 1.0)) && (min(_180, _182) >= 0.0)) + { + _226 = int(_219); + _222 = true; break; } - _228 = mat4(vec4(1.0, 0.0, 0.0, 0.0), vec4(0.0, 1.0, 0.0, 0.0), vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)); - break; - } - vec4 _177 = (_228 * _11.lightVP[_227]) * vec4(fragWorld, 1.0); - float _179 = _177.z; - float _186 = _177.x; - float _188 = _177.y; - if ((((_179 >= 0.0) && (_179 <= 1.0)) && (max(_186, _188) <= 1.0)) && (min(_186, _188) >= 0.0)) - { - _237 = int(_227); - _231 = true; - break; + _219++; + continue; } else { - uint _204 = _227 + uint(1); - _227 = _204; - continue; + _226 = _228; + _222 = false; + break; } - uint _204 = _227 + uint(1); - _227 = _204; - continue; } - else - { - _237 = _240; - _231 = false; - break; - } - } - if (_231) - { - _236 = _237; + _225 = -1; break; } - _236 = -1; - break; } - _entryPointOutput = _236; + _entryPointOutput = _225; } diff --git a/third_party/spirv-cross/reference/opt/shaders/asm/frag/loop-merge-to-continue.asm.frag b/third_party/spirv-cross/reference/opt/shaders/asm/frag/loop-merge-to-continue.asm.frag deleted file mode 100644 index faf32edcf4..0000000000 --- a/third_party/spirv-cross/reference/opt/shaders/asm/frag/loop-merge-to-continue.asm.frag +++ /dev/null @@ -1,21 +0,0 @@ -#version 450 - -layout(location = 0) out vec4 FragColor; -layout(location = 0) in vec4 v0; - -void main() -{ - FragColor = vec4(1.0); - int _50; - _50 = 0; - for (; _50 < 4; _50++) - { - for (int _51 = 0; _51 < 4; ) - { - FragColor += vec4(v0[(_50 + _51) & 3]); - _51++; - continue; - } - } -} - diff --git a/third_party/spirv-cross/reference/opt/shaders/asm/frag/selection-merge-to-continue.asm.frag b/third_party/spirv-cross/reference/opt/shaders/asm/frag/selection-merge-to-continue.asm.frag deleted file mode 100644 index 05c17c7a66..0000000000 --- a/third_party/spirv-cross/reference/opt/shaders/asm/frag/selection-merge-to-continue.asm.frag +++ /dev/null @@ -1,24 +0,0 @@ -#version 450 - -layout(location = 0) out vec4 FragColor; -layout(location = 0) in vec4 v0; - -void main() -{ - FragColor = vec4(1.0); - for (int _54 = 0; _54 < 4; _54++) - { - if (v0.x == 20.0) - { - FragColor += vec4(v0[_54 & 3]); - continue; - } - else - { - FragColor += vec4(v0[_54 & 1]); - continue; - } - continue; - } -} - diff --git a/third_party/spirv-cross/reference/opt/shaders/asm/frag/switch-merge-to-continue.asm.frag b/third_party/spirv-cross/reference/opt/shaders/asm/frag/switch-merge-to-continue.asm.frag deleted file mode 100644 index ea4a25995a..0000000000 --- a/third_party/spirv-cross/reference/opt/shaders/asm/frag/switch-merge-to-continue.asm.frag +++ /dev/null @@ -1,31 +0,0 @@ -#version 450 - -layout(location = 0) out vec4 FragColor; - -void main() -{ - FragColor = vec4(1.0); - for (int _52 = 0; _52 < 4; _52++) - { - switch (_52) - { - case 0: - { - FragColor.x += 1.0; - break; - } - case 1: - { - FragColor.y += 3.0; - break; - } - default: - { - FragColor.z += 3.0; - break; - } - } - continue; - } -} - diff --git a/third_party/spirv-cross/reference/opt/shaders/comp/barriers.comp b/third_party/spirv-cross/reference/opt/shaders/comp/barriers.comp index a091497a49..7dfde372ad 100644 --- a/third_party/spirv-cross/reference/opt/shaders/comp/barriers.comp +++ b/third_party/spirv-cross/reference/opt/shaders/comp/barriers.comp @@ -8,21 +8,15 @@ void main() memoryBarrierImage(); memoryBarrierBuffer(); groupMemoryBarrier(); - memoryBarrierShared(); barrier(); memoryBarrier(); - memoryBarrierShared(); barrier(); memoryBarrierImage(); - memoryBarrierShared(); barrier(); memoryBarrierBuffer(); - memoryBarrierShared(); barrier(); groupMemoryBarrier(); - memoryBarrierShared(); barrier(); - memoryBarrierShared(); barrier(); } diff --git a/third_party/spirv-cross/reference/opt/shaders/comp/cfg.comp b/third_party/spirv-cross/reference/opt/shaders/comp/cfg.comp index 0b7e0c1616..bc1a417803 100644 --- a/third_party/spirv-cross/reference/opt/shaders/comp/cfg.comp +++ b/third_party/spirv-cross/reference/opt/shaders/comp/cfg.comp @@ -6,7 +6,7 @@ layout(binding = 0, std430) buffer SSBO float data; } _11; -float _183; +float _187; void main() { @@ -31,14 +31,14 @@ void main() break; } } - float _180; - _180 = _183; - for (int _179 = 0; _179 < 20; ) + float _184; + _184 = _187; + for (int _183 = 0; _183 < 20; ) { - _180 += 10.0; - _179++; + _184 += 10.0; + _183++; continue; } - _11.data = _180; + _11.data = _184; } diff --git a/third_party/spirv-cross/reference/opt/shaders/comp/dowhile.comp b/third_party/spirv-cross/reference/opt/shaders/comp/dowhile.comp index 4370ea3079..d9a9f77cbf 100644 --- a/third_party/spirv-cross/reference/opt/shaders/comp/dowhile.comp +++ b/third_party/spirv-cross/reference/opt/shaders/comp/dowhile.comp @@ -14,19 +14,19 @@ layout(binding = 1, std430) writeonly buffer SSBO2 void main() { - vec4 _57; - int _58; - _58 = 0; - _57 = _28.in_data[gl_GlobalInvocationID.x]; + vec4 _59; + int _60; + _60 = 0; + _59 = _28.in_data[gl_GlobalInvocationID.x]; vec4 _42; for (;;) { - _42 = _28.mvp * _57; - int _44 = _58 + 1; + _42 = _28.mvp * _59; + int _44 = _60 + 1; if (_44 < 16) { - _58 = _44; - _57 = _42; + _60 = _44; + _59 = _42; } else { diff --git a/third_party/spirv-cross/reference/opt/shaders/comp/insert.comp b/third_party/spirv-cross/reference/opt/shaders/comp/insert.comp index 5ff719449a..ad394aab6c 100644 --- a/third_party/spirv-cross/reference/opt/shaders/comp/insert.comp +++ b/third_party/spirv-cross/reference/opt/shaders/comp/insert.comp @@ -6,19 +6,19 @@ layout(binding = 0, std430) writeonly buffer SSBO vec4 out_data[]; } _27; -vec4 _52; +vec4 _53; void main() { - vec4 _45 = _52; - _45.x = 10.0; - vec4 _47 = _45; - _47.y = 30.0; - vec4 _49 = _47; - _49.z = 70.0; - vec4 _51 = _49; - _51.w = 90.0; - _27.out_data[gl_GlobalInvocationID.x] = _51; + vec4 _46 = _53; + _46.x = 10.0; + vec4 _48 = _46; + _48.y = 30.0; + vec4 _50 = _48; + _50.z = 70.0; + vec4 _52 = _50; + _52.w = 90.0; + _27.out_data[gl_GlobalInvocationID.x] = _52; _27.out_data[gl_GlobalInvocationID.x].y = 20.0; } diff --git a/third_party/spirv-cross/reference/opt/shaders/comp/shared.comp b/third_party/spirv-cross/reference/opt/shaders/comp/shared.comp index f95cb2b8b9..62cf4a4b20 100644 --- a/third_party/spirv-cross/reference/opt/shaders/comp/shared.comp +++ b/third_party/spirv-cross/reference/opt/shaders/comp/shared.comp @@ -16,7 +16,6 @@ shared float sShared[4]; void main() { sShared[gl_LocalInvocationIndex] = _22.in_data[gl_GlobalInvocationID.x]; - memoryBarrierShared(); barrier(); _44.out_data[gl_GlobalInvocationID.x] = sShared[3u - gl_LocalInvocationIndex]; } diff --git a/third_party/spirv-cross/reference/opt/shaders/comp/torture-loop.comp b/third_party/spirv-cross/reference/opt/shaders/comp/torture-loop.comp index 5943966c05..9ca2b9591f 100644 --- a/third_party/spirv-cross/reference/opt/shaders/comp/torture-loop.comp +++ b/third_party/spirv-cross/reference/opt/shaders/comp/torture-loop.comp @@ -14,27 +14,27 @@ layout(binding = 1, std430) writeonly buffer SSBO2 void main() { - vec4 _99; - _99 = _24.in_data[gl_GlobalInvocationID.x]; - for (int _93 = 0; (_93 + 1) < 10; ) + vec4 _101; + _101 = _24.in_data[gl_GlobalInvocationID.x]; + for (int _95 = 0; (_95 + 1) < 10; ) { - _99 *= 2.0; - _93 += 2; + _101 *= 2.0; + _95 += 2; continue; } - vec4 _98; - _98 = _99; - vec4 _103; - for (uint _94 = 0u; _94 < 16u; _98 = _103, _94++) + vec4 _100; + _100 = _101; + vec4 _105; + for (uint _96 = 0u; _96 < 16u; _100 = _105, _96++) { - _103 = _98; - for (uint _100 = 0u; _100 < 30u; ) + _105 = _100; + for (uint _102 = 0u; _102 < 30u; ) { - _103 = _24.mvp * _103; - _100++; + _105 = _24.mvp * _105; + _102++; continue; } } - _89.out_data[gl_GlobalInvocationID.x] = _98; + _89.out_data[gl_GlobalInvocationID.x] = _100; } diff --git a/third_party/spirv-cross/reference/opt/shaders/desktop-only/frag/image-size.frag b/third_party/spirv-cross/reference/opt/shaders/desktop-only/frag/image-size.frag new file mode 100644 index 0000000000..5bb060398e --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders/desktop-only/frag/image-size.frag @@ -0,0 +1,12 @@ +#version 450 + +layout(binding = 0, r32f) uniform readonly writeonly image2D uImage1; +layout(binding = 1, r32f) uniform readonly writeonly image2D uImage2; + +layout(location = 0) out vec4 FragColor; + +void main() +{ + FragColor = vec4(vec2(imageSize(uImage1)), vec2(imageSize(uImage2))); +} + diff --git a/third_party/spirv-cross/reference/opt/shaders/desktop-only/frag/image-size.no-qualifier-deduction.frag b/third_party/spirv-cross/reference/opt/shaders/desktop-only/frag/image-size.no-qualifier-deduction.frag new file mode 100644 index 0000000000..1d9062064a --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders/desktop-only/frag/image-size.no-qualifier-deduction.frag @@ -0,0 +1,12 @@ +#version 450 + +layout(binding = 0, r32f) uniform image2D uImage1; +layout(binding = 1, r32f) uniform image2D uImage2; + +layout(location = 0) out vec4 FragColor; + +void main() +{ + FragColor = vec4(vec2(imageSize(uImage1)), vec2(imageSize(uImage2))); +} + diff --git a/third_party/spirv-cross/reference/opt/shaders/desktop-only/tesc/basic.desktop.sso.tesc b/third_party/spirv-cross/reference/opt/shaders/desktop-only/tesc/basic.desktop.sso.tesc index 5e958256af..c51699db6d 100644 --- a/third_party/spirv-cross/reference/opt/shaders/desktop-only/tesc/basic.desktop.sso.tesc +++ b/third_party/spirv-cross/reference/opt/shaders/desktop-only/tesc/basic.desktop.sso.tesc @@ -4,7 +4,7 @@ layout(vertices = 1) out; in gl_PerVertex { vec4 gl_Position; -} gl_in[gl_MaxPatchVertices]; +} gl_in[]; out gl_PerVertex { diff --git a/third_party/spirv-cross/reference/opt/shaders/desktop-only/tese/triangle.desktop.sso.tese b/third_party/spirv-cross/reference/opt/shaders/desktop-only/tese/triangle.desktop.sso.tese index 31027dae80..c9bacd464e 100644 --- a/third_party/spirv-cross/reference/opt/shaders/desktop-only/tese/triangle.desktop.sso.tese +++ b/third_party/spirv-cross/reference/opt/shaders/desktop-only/tese/triangle.desktop.sso.tese @@ -4,7 +4,7 @@ layout(triangles, cw, fractional_even_spacing) in; in gl_PerVertex { vec4 gl_Position; -} gl_in[gl_MaxPatchVertices]; +} gl_in[]; out gl_PerVertex { diff --git a/third_party/spirv-cross/reference/opt/shaders/frag/for-loop-init.frag b/third_party/spirv-cross/reference/opt/shaders/frag/for-loop-init.frag index 3aee71c7a1..3cfcd3c159 100644 --- a/third_party/spirv-cross/reference/opt/shaders/frag/for-loop-init.frag +++ b/third_party/spirv-cross/reference/opt/shaders/frag/for-loop-init.frag @@ -6,62 +6,63 @@ layout(location = 0) out mediump int FragColor; void main() { - mediump int _145; - for (;;) + switch (0u) { - FragColor = 16; - _145 = 0; - for (; _145 < 25; ) + default: { - FragColor += 10; - _145++; - continue; - } - for (mediump int _146 = 1; _146 < 30; ) - { - FragColor += 11; - _146++; - continue; - } - mediump int _147; - _147 = 0; - for (; _147 < 20; ) - { - FragColor += 12; - _147++; - continue; - } - mediump int _62 = _147 + 3; - FragColor += _62; - if (_62 == 40) - { - for (mediump int _151 = 0; _151 < 40; ) + FragColor = 16; + for (mediump int _143 = 0; _143 < 25; ) { - FragColor += 13; - _151++; + FragColor += 10; + _143++; continue; } + for (mediump int _144 = 1; _144 < 30; ) + { + FragColor += 11; + _144++; + continue; + } + mediump int _145; + _145 = 0; + for (; _145 < 20; ) + { + FragColor += 12; + _145++; + continue; + } + mediump int _62 = _145 + 3; + FragColor += _62; + if (_62 == 40) + { + for (mediump int _149 = 0; _149 < 40; ) + { + FragColor += 13; + _149++; + continue; + } + break; + } + FragColor += _62; + mediump ivec2 _146; + _146 = ivec2(0); + for (; _146.x < 10; ) + { + FragColor += _146.y; + mediump ivec2 _142 = _146; + _142.x = _146.x + 4; + _146 = _142; + continue; + } + for (mediump int _148 = _62; _148 < 40; ) + { + FragColor += _148; + _148++; + continue; + } + FragColor += _62; break; } - FragColor += _62; - mediump ivec2 _148; - _148 = ivec2(0); - for (; _148.x < 10; ) - { - FragColor += _148.y; - mediump ivec2 _144 = _148; - _144.x = _148.x + 4; - _148 = _144; - continue; - } - for (mediump int _150 = _62; _150 < 40; ) - { - FragColor += _150; - _150++; - continue; - } - FragColor += _62; - break; } } diff --git a/third_party/spirv-cross/reference/opt/shaders/frag/hoisted-temporary-use-continue-block-as-value.frag b/third_party/spirv-cross/reference/opt/shaders/frag/hoisted-temporary-use-continue-block-as-value.frag index 91d7e37cdd..050218b13b 100644 --- a/third_party/spirv-cross/reference/opt/shaders/frag/hoisted-temporary-use-continue-block-as-value.frag +++ b/third_party/spirv-cross/reference/opt/shaders/frag/hoisted-temporary-use-continue-block-as-value.frag @@ -9,20 +9,20 @@ layout(location = 1) flat in mediump int vB; void main() { FragColor = vec4(0.0); + mediump int _49; mediump int _58; - for (mediump int _57 = 0, _60 = 0; _57 < vA; FragColor += vec4(1.0), _60 = _58, _57 += (_58 + 10)) + for (mediump int _57 = 0, _60 = 0; _57 < vA; _60 = _58, _57 += _49) { if ((vA + _57) == 20) { _58 = 50; - continue; } else { _58 = ((vB + _57) == 40) ? 60 : _60; - continue; } - continue; + _49 = _58 + 10; + FragColor += vec4(1.0); } } diff --git a/third_party/spirv-cross/reference/opt/shaders/frag/loop-dominator-and-switch-default.frag b/third_party/spirv-cross/reference/opt/shaders/frag/loop-dominator-and-switch-default.frag index 00f4b6be4a..2c193483d1 100644 --- a/third_party/spirv-cross/reference/opt/shaders/frag/loop-dominator-and-switch-default.frag +++ b/third_party/spirv-cross/reference/opt/shaders/frag/loop-dominator-and-switch-default.frag @@ -50,7 +50,6 @@ void main() vec4 _79 = _83; _79.y = _83.y + 0.5; _89 = _79; - continue; } fragColor = _82; } diff --git a/third_party/spirv-cross/reference/opt/shaders/frag/pixel-interlock-ordered.frag b/third_party/spirv-cross/reference/opt/shaders/frag/pixel-interlock-ordered.frag new file mode 100644 index 0000000000..46cca96c6a --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders/frag/pixel-interlock-ordered.frag @@ -0,0 +1,23 @@ +#version 450 +#extension GL_ARB_fragment_shader_interlock : require +layout(pixel_interlock_ordered) in; + +layout(binding = 2, std430) coherent buffer Buffer +{ + int foo; + uint bar; +} _30; + +layout(binding = 0, rgba8) uniform writeonly image2D img; +layout(binding = 1, r32ui) uniform uimage2D img2; + +void main() +{ + beginInvocationInterlockARB(); + imageStore(img, ivec2(0), vec4(1.0, 0.0, 0.0, 1.0)); + uint _27 = imageAtomicAdd(img2, ivec2(0), 1u); + _30.foo += 42; + uint _41 = atomicAnd(_30.bar, 255u); + endInvocationInterlockARB(); +} + diff --git a/third_party/spirv-cross/reference/opt/shaders/frag/pixel-interlock-unordered.frag b/third_party/spirv-cross/reference/opt/shaders/frag/pixel-interlock-unordered.frag new file mode 100644 index 0000000000..d60cd14518 --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders/frag/pixel-interlock-unordered.frag @@ -0,0 +1,23 @@ +#version 450 +#extension GL_ARB_fragment_shader_interlock : require +layout(pixel_interlock_unordered) in; + +layout(binding = 2, std430) coherent buffer Buffer +{ + int foo; + uint bar; +} _30; + +layout(binding = 0, rgba8) uniform writeonly image2D img; +layout(binding = 1, r32ui) uniform uimage2D img2; + +void main() +{ + beginInvocationInterlockARB(); + imageStore(img, ivec2(0), vec4(1.0, 0.0, 0.0, 1.0)); + uint _27 = imageAtomicAdd(img2, ivec2(0), 1u); + _30.foo += 42; + uint _41 = atomicAnd(_30.bar, 255u); + endInvocationInterlockARB(); +} + diff --git a/third_party/spirv-cross/reference/opt/shaders/frag/post-depth-coverage-es.frag b/third_party/spirv-cross/reference/opt/shaders/frag/post-depth-coverage-es.frag new file mode 100644 index 0000000000..d086560e5d --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders/frag/post-depth-coverage-es.frag @@ -0,0 +1,14 @@ +#version 310 es +#extension GL_EXT_post_depth_coverage : require +#extension GL_OES_sample_variables : require +precision mediump float; +precision highp int; +layout(early_fragment_tests, post_depth_coverage) in; + +layout(location = 0) out vec4 FragColor; + +void main() +{ + FragColor = vec4(float(gl_SampleMaskIn[0])); +} + diff --git a/third_party/spirv-cross/reference/opt/shaders/frag/post-depth-coverage.frag b/third_party/spirv-cross/reference/opt/shaders/frag/post-depth-coverage.frag index 3e78fcd0a7..caca9c03cb 100644 --- a/third_party/spirv-cross/reference/opt/shaders/frag/post-depth-coverage.frag +++ b/third_party/spirv-cross/reference/opt/shaders/frag/post-depth-coverage.frag @@ -1,5 +1,9 @@ #version 450 +#if defined(GL_ARB_post_depth_coverge) #extension GL_ARB_post_depth_coverage : require +#else +#extension GL_EXT_post_depth_coverage : require +#endif layout(early_fragment_tests, post_depth_coverage) in; layout(location = 0) out vec4 FragColor; diff --git a/third_party/spirv-cross/reference/opt/shaders/frag/sample-interlock-ordered.frag b/third_party/spirv-cross/reference/opt/shaders/frag/sample-interlock-ordered.frag new file mode 100644 index 0000000000..67ca5560e3 --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders/frag/sample-interlock-ordered.frag @@ -0,0 +1,23 @@ +#version 450 +#extension GL_ARB_fragment_shader_interlock : require +layout(sample_interlock_ordered) in; + +layout(binding = 2, std430) coherent buffer Buffer +{ + int foo; + uint bar; +} _30; + +layout(binding = 0, rgba8) uniform writeonly image2D img; +layout(binding = 1, r32ui) uniform uimage2D img2; + +void main() +{ + beginInvocationInterlockARB(); + imageStore(img, ivec2(0), vec4(1.0, 0.0, 0.0, 1.0)); + uint _27 = imageAtomicAdd(img2, ivec2(0), 1u); + _30.foo += 42; + uint _47 = atomicAnd(_30.bar, uint(gl_SampleMaskIn[0])); + endInvocationInterlockARB(); +} + diff --git a/third_party/spirv-cross/reference/opt/shaders/frag/sample-interlock-unordered.frag b/third_party/spirv-cross/reference/opt/shaders/frag/sample-interlock-unordered.frag new file mode 100644 index 0000000000..ea74397d63 --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders/frag/sample-interlock-unordered.frag @@ -0,0 +1,23 @@ +#version 450 +#extension GL_ARB_fragment_shader_interlock : require +layout(sample_interlock_unordered) in; + +layout(binding = 2, std430) coherent buffer Buffer +{ + int foo; + uint bar; +} _30; + +layout(binding = 0, rgba8) uniform writeonly image2D img; +layout(binding = 1, r32ui) uniform uimage2D img2; + +void main() +{ + beginInvocationInterlockARB(); + imageStore(img, ivec2(0), vec4(1.0, 0.0, 0.0, 1.0)); + uint _27 = imageAtomicAdd(img2, ivec2(0), 1u); + _30.foo += 42; + uint _41 = atomicAnd(_30.bar, 255u); + endInvocationInterlockARB(); +} + diff --git a/third_party/spirv-cross/reference/opt/shaders/frag/selection-block-dominator.frag b/third_party/spirv-cross/reference/opt/shaders/frag/selection-block-dominator.frag index f737f48917..ac8840faff 100644 --- a/third_party/spirv-cross/reference/opt/shaders/frag/selection-block-dominator.frag +++ b/third_party/spirv-cross/reference/opt/shaders/frag/selection-block-dominator.frag @@ -5,15 +5,18 @@ layout(location = 0) out vec4 FragColor; void main() { - for (;;) + switch (0u) { - if (vIndex != 1) + default: { - FragColor = vec4(1.0); + if (vIndex != 1) + { + FragColor = vec4(1.0); + break; + } + FragColor = vec4(10.0); break; } - FragColor = vec4(10.0); - break; } } diff --git a/third_party/spirv-cross/reference/opt/shaders/frag/struct-type-unrelated-alias.frag b/third_party/spirv-cross/reference/opt/shaders/frag/struct-type-unrelated-alias.frag new file mode 100644 index 0000000000..d6fa667f3b --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders/frag/struct-type-unrelated-alias.frag @@ -0,0 +1,9 @@ +#version 450 + +layout(location = 0) out float FragColor; + +void main() +{ + FragColor = 30.0; +} + diff --git a/third_party/spirv-cross/reference/opt/shaders/geom/geometry-passthrough.geom b/third_party/spirv-cross/reference/opt/shaders/geom/geometry-passthrough.geom new file mode 100644 index 0000000000..d0d8806ad2 --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders/geom/geometry-passthrough.geom @@ -0,0 +1,27 @@ +#version 450 +#extension GL_NV_geometry_shader_passthrough : require +layout(triangles) in; + +layout(passthrough) in gl_PerVertex +{ + vec4 gl_Position; +} gl_in[]; + +layout(passthrough, location = 0) in VertexBlock +{ + int a; + int b; +} v1[3]; + +layout(location = 2) in VertexBlock2 +{ + int a; + layout(passthrough) int b; +} v2[3]; + + +void main() +{ + gl_Layer = (gl_InvocationID + v1[0].a) + v2[1].b; +} + diff --git a/third_party/spirv-cross/reference/opt/shaders/geom/multi-stream.geom b/third_party/spirv-cross/reference/opt/shaders/geom/multi-stream.geom new file mode 100644 index 0000000000..548164d780 --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders/geom/multi-stream.geom @@ -0,0 +1,14 @@ +#version 450 +layout(triangles) in; +layout(max_vertices = 2, points) out; + +void main() +{ + gl_Position = gl_in[0].gl_Position; + EmitStreamVertex(0); + EndStreamPrimitive(0); + gl_Position = gl_in[0].gl_Position + vec4(2.0); + EmitStreamVertex(1); + EndStreamPrimitive(1); +} + diff --git a/third_party/spirv-cross/reference/opt/shaders/tese/load-array-of-array.tese b/third_party/spirv-cross/reference/opt/shaders/tese/load-array-of-array.tese new file mode 100644 index 0000000000..e4b426d0ad --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders/tese/load-array-of-array.tese @@ -0,0 +1,10 @@ +#version 450 +layout(quads, ccw, equal_spacing) in; + +layout(location = 0) in vec4 vTexCoord[][1]; + +void main() +{ + gl_Position = (vTexCoord[0u][0] + vTexCoord[2u][0]) + vTexCoord[3u][0]; +} + diff --git a/third_party/spirv-cross/reference/opt/shaders/tese/patch-input-array.tese b/third_party/spirv-cross/reference/opt/shaders/tese/patch-input-array.tese new file mode 100644 index 0000000000..413d8b391f --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders/tese/patch-input-array.tese @@ -0,0 +1,10 @@ +#version 450 +layout(quads, ccw, equal_spacing) in; + +layout(location = 0) patch in float P[4]; + +void main() +{ + gl_Position = vec4(P[0], P[1], P[2], P[3]); +} + diff --git a/third_party/spirv-cross/reference/opt/shaders/vert/transform-feedback-decorations.vert b/third_party/spirv-cross/reference/opt/shaders/vert/transform-feedback-decorations.vert new file mode 100644 index 0000000000..23e7cf3c19 --- /dev/null +++ b/third_party/spirv-cross/reference/opt/shaders/vert/transform-feedback-decorations.vert @@ -0,0 +1,22 @@ +#version 450 + +layout(xfb_buffer = 1, xfb_stride = 20) out gl_PerVertex +{ + layout(xfb_offset = 4) vec4 gl_Position; + float gl_PointSize; +}; + +layout(location = 0, xfb_buffer = 2, xfb_stride = 32, xfb_offset = 16) out vec4 vFoo; +layout(xfb_buffer = 3, xfb_stride = 16) out VertOut +{ + layout(location = 1, xfb_offset = 0) vec4 vBar; +} _22; + + +void main() +{ + gl_Position = vec4(1.0); + vFoo = vec4(3.0); + _22.vBar = vec4(5.0); +} + diff --git a/third_party/spirv-cross/reference/opt/shaders/vulkan/comp/buffer-reference.nocompat.vk.comp.vk b/third_party/spirv-cross/reference/opt/shaders/vulkan/comp/buffer-reference.nocompat.vk.comp.vk index dfcaac8361..3128319617 100644 --- a/third_party/spirv-cross/reference/opt/shaders/vulkan/comp/buffer-reference.nocompat.vk.comp.vk +++ b/third_party/spirv-cross/reference/opt/shaders/vulkan/comp/buffer-reference.nocompat.vk.comp.vk @@ -19,27 +19,17 @@ layout(set = 0, binding = 0, std430) restrict buffer LinkedList void main() { - Node _45; + Node _112; if (gl_WorkGroupID.x < 4u) { - _45 = _50.head1; + _112 = _50.head1; } else { - _45 = _50.head2; + _112 = _50.head2; } - restrict Node n = _45; - Node param = n.next; - Node param_1 = _50.head1; - Node param_2 = _50.head2; - param.value = param_1.value + param_2.value; - Node param_4 = _50.head1; - Node param_3 = param_4; - n = param_3; - int v = _50.head2.value; - n.value = 20; - n.value = v * 10; - uint64_t uptr = uint64_t(_50.head2.next); - Node unode = Node(uptr); + _112.next.value = _50.head1.value + _50.head2.value; + _50.head1.value = 20; + _50.head1.value = _50.head2.value * 10; } diff --git a/third_party/spirv-cross/reference/opt/shaders/vulkan/frag/shader-arithmetic-8bit.nocompat.vk.frag.vk b/third_party/spirv-cross/reference/opt/shaders/vulkan/frag/shader-arithmetic-8bit.nocompat.vk.frag.vk index d09930f3ad..69558dee63 100644 --- a/third_party/spirv-cross/reference/opt/shaders/vulkan/frag/shader-arithmetic-8bit.nocompat.vk.frag.vk +++ b/third_party/spirv-cross/reference/opt/shaders/vulkan/frag/shader-arithmetic-8bit.nocompat.vk.frag.vk @@ -30,9 +30,10 @@ void main() { int16_t _196 = 10s; int _197 = 20; - i8vec2 _198 = unpack8(_196); - i8vec4 _199 = unpack8(_197); - _196 = pack16(_198); + i8vec2 _201 = unpack8(10s); + i8vec2 _198 = _201; + i8vec4 _199 = unpack8(20); + _196 = pack16(_201); _197 = pack32(_199); ssbo.i8[0] = _199.x; ssbo.i8[1] = _199.y; @@ -40,9 +41,10 @@ void main() ssbo.i8[3] = _199.w; uint16_t _220 = 10us; uint _221 = 20u; - u8vec2 _222 = unpack8(_220); - u8vec4 _223 = unpack8(_221); - _220 = pack16(_222); + u8vec2 _225 = unpack8(10us); + u8vec2 _222 = _225; + u8vec4 _223 = unpack8(20u); + _220 = pack16(_225); _221 = pack32(_223); ssbo.u8[0] = _223.x; ssbo.u8[1] = _223.y; @@ -50,20 +52,33 @@ void main() ssbo.u8[3] = _223.w; i8vec4 _246 = i8vec4(vColor); i8vec4 _244 = _246; - _244 += i8vec4(registers.i8); - _244 += i8vec4(-40); - _244 += i8vec4(-50); - _244 += i8vec4(int8_t(10), int8_t(20), int8_t(30), int8_t(40)); - _244 += i8vec4(ssbo.i8[4]); - _244 += i8vec4(ubo.i8); - FragColorInt = ivec4(_244); - u8vec4 _271 = u8vec4(_246); - _271 += u8vec4(registers.u8); - _271 += u8vec4(216); - _271 += u8vec4(206); - _271 += u8vec4(uint8_t(10), uint8_t(20), uint8_t(30), uint8_t(40)); - _271 += u8vec4(ssbo.u8[4]); - _271 += u8vec4(ubo.u8); - FragColorUint = uvec4(_271); + i8vec4 _251 = _246 + i8vec4(registers.i8); + _244 = _251; + i8vec4 _254 = _251 + i8vec4(-40); + _244 = _254; + i8vec4 _256 = _254 + i8vec4(-50); + _244 = _256; + i8vec4 _258 = _256 + i8vec4(int8_t(10), int8_t(20), int8_t(30), int8_t(40)); + _244 = _258; + i8vec4 _263 = _258 + i8vec4(ssbo.i8[4]); + _244 = _263; + i8vec4 _268 = _263 + i8vec4(ubo.i8); + _244 = _268; + FragColorInt = ivec4(_268); + u8vec4 _274 = u8vec4(_246); + u8vec4 _271 = _274; + u8vec4 _279 = _274 + u8vec4(registers.u8); + _271 = _279; + u8vec4 _282 = _279 + u8vec4(216); + _271 = _282; + u8vec4 _284 = _282 + u8vec4(206); + _271 = _284; + u8vec4 _286 = _284 + u8vec4(uint8_t(10), uint8_t(20), uint8_t(30), uint8_t(40)); + _271 = _286; + u8vec4 _291 = _286 + u8vec4(ssbo.u8[4]); + _271 = _291; + u8vec4 _296 = _291 + u8vec4(ubo.u8); + _271 = _296; + FragColorUint = uvec4(_296); } diff --git a/third_party/spirv-cross/reference/shaders-hlsl-no-opt/asm/comp/access-chain-load-store-composite.asm.comp b/third_party/spirv-cross/reference/shaders-hlsl-no-opt/asm/comp/access-chain-load-store-composite.asm.comp new file mode 100644 index 0000000000..986cc6289f --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-hlsl-no-opt/asm/comp/access-chain-load-store-composite.asm.comp @@ -0,0 +1,75 @@ +struct Baz +{ + float c; +}; + +struct Bar +{ + float d[2][4]; + Baz baz[2]; +}; + +struct Foo +{ + column_major float2x2 a; + float2 b; + Bar c[5]; +}; + +static const uint3 gl_WorkGroupSize = uint3(1u, 1u, 1u); + +RWByteAddressBuffer _10 : register(u0); + +void comp_main() +{ + Foo _64; + _64.a = asfloat(uint2x2(_10.Load(0), _10.Load(8), _10.Load(4), _10.Load(12))); + _64.b = asfloat(_10.Load2(16)); + [unroll] + for (int _0ident = 0; _0ident < 5; _0ident++) + { + [unroll] + for (int _1ident = 0; _1ident < 2; _1ident++) + { + [unroll] + for (int _2ident = 0; _2ident < 4; _2ident++) + { + _64.c[_0ident].d[_1ident][_2ident] = asfloat(_10.Load(_2ident * 4 + _1ident * 16 + _0ident * 40 + 24)); + } + } + [unroll] + for (int _3ident = 0; _3ident < 2; _3ident++) + { + _64.c[_0ident].baz[_3ident].c = asfloat(_10.Load(_3ident * 4 + _0ident * 40 + 56)); + } + } + _10.Store(224, asuint(_64.a[0].x)); + _10.Store(228, asuint(_64.a[1].x)); + _10.Store(232, asuint(_64.a[0].y)); + _10.Store(236, asuint(_64.a[1].y)); + _10.Store2(240, asuint(_64.b)); + [unroll] + for (int _4ident = 0; _4ident < 5; _4ident++) + { + [unroll] + for (int _5ident = 0; _5ident < 2; _5ident++) + { + [unroll] + for (int _6ident = 0; _6ident < 4; _6ident++) + { + _10.Store(_6ident * 4 + _5ident * 16 + _4ident * 40 + 248, asuint(_64.c[_4ident].d[_5ident][_6ident])); + } + } + [unroll] + for (int _7ident = 0; _7ident < 2; _7ident++) + { + _10.Store(_7ident * 4 + _4ident * 40 + 280, asuint(_64.c[_4ident].baz[_7ident].c)); + } + } +} + +[numthreads(1, 1, 1)] +void main() +{ + comp_main(); +} diff --git a/third_party/spirv-cross/reference/shaders-hlsl-no-opt/asm/comp/aliased-struct-divergent-member-name.asm.comp b/third_party/spirv-cross/reference/shaders-hlsl-no-opt/asm/comp/aliased-struct-divergent-member-name.asm.comp new file mode 100644 index 0000000000..dd29c5a497 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-hlsl-no-opt/asm/comp/aliased-struct-divergent-member-name.asm.comp @@ -0,0 +1,27 @@ +struct T +{ + float c; +}; + +struct T_1 +{ + float b; +}; + +static const T _18 = { 40.0f }; + +RWByteAddressBuffer _7 : register(u0); +RWByteAddressBuffer _10 : register(u1); + +void comp_main() +{ + T v = _18; + _7.Store(40, asuint(v.c)); + _10.Store(480, asuint(v.c)); +} + +[numthreads(1, 1, 1)] +void main() +{ + comp_main(); +} diff --git a/third_party/spirv-cross/reference/shaders-hlsl-no-opt/asm/comp/bitfield-signed-operations.asm.comp b/third_party/spirv-cross/reference/shaders-hlsl-no-opt/asm/comp/bitfield-signed-operations.asm.comp new file mode 100644 index 0000000000..ae5fe5adbc --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-hlsl-no-opt/asm/comp/bitfield-signed-operations.asm.comp @@ -0,0 +1,105 @@ +RWByteAddressBuffer _3 : register(u0); + +uint SPIRV_Cross_bitfieldInsert(uint Base, uint Insert, uint Offset, uint Count) +{ + uint Mask = Count == 32 ? 0xffffffff : (((1u << Count) - 1) << (Offset & 31)); + return (Base & ~Mask) | ((Insert << Offset) & Mask); +} + +uint2 SPIRV_Cross_bitfieldInsert(uint2 Base, uint2 Insert, uint Offset, uint Count) +{ + uint Mask = Count == 32 ? 0xffffffff : (((1u << Count) - 1) << (Offset & 31)); + return (Base & ~Mask) | ((Insert << Offset) & Mask); +} + +uint3 SPIRV_Cross_bitfieldInsert(uint3 Base, uint3 Insert, uint Offset, uint Count) +{ + uint Mask = Count == 32 ? 0xffffffff : (((1u << Count) - 1) << (Offset & 31)); + return (Base & ~Mask) | ((Insert << Offset) & Mask); +} + +uint4 SPIRV_Cross_bitfieldInsert(uint4 Base, uint4 Insert, uint Offset, uint Count) +{ + uint Mask = Count == 32 ? 0xffffffff : (((1u << Count) - 1) << (Offset & 31)); + return (Base & ~Mask) | ((Insert << Offset) & Mask); +} + +uint SPIRV_Cross_bitfieldUExtract(uint Base, uint Offset, uint Count) +{ + uint Mask = Count == 32 ? 0xffffffff : ((1 << Count) - 1); + return (Base >> Offset) & Mask; +} + +uint2 SPIRV_Cross_bitfieldUExtract(uint2 Base, uint Offset, uint Count) +{ + uint Mask = Count == 32 ? 0xffffffff : ((1 << Count) - 1); + return (Base >> Offset) & Mask; +} + +uint3 SPIRV_Cross_bitfieldUExtract(uint3 Base, uint Offset, uint Count) +{ + uint Mask = Count == 32 ? 0xffffffff : ((1 << Count) - 1); + return (Base >> Offset) & Mask; +} + +uint4 SPIRV_Cross_bitfieldUExtract(uint4 Base, uint Offset, uint Count) +{ + uint Mask = Count == 32 ? 0xffffffff : ((1 << Count) - 1); + return (Base >> Offset) & Mask; +} + +int SPIRV_Cross_bitfieldSExtract(int Base, int Offset, int Count) +{ + int Mask = Count == 32 ? -1 : ((1 << Count) - 1); + int Masked = (Base >> Offset) & Mask; + int ExtendShift = (32 - Count) & 31; + return (Masked << ExtendShift) >> ExtendShift; +} + +int2 SPIRV_Cross_bitfieldSExtract(int2 Base, int Offset, int Count) +{ + int Mask = Count == 32 ? -1 : ((1 << Count) - 1); + int2 Masked = (Base >> Offset) & Mask; + int ExtendShift = (32 - Count) & 31; + return (Masked << ExtendShift) >> ExtendShift; +} + +int3 SPIRV_Cross_bitfieldSExtract(int3 Base, int Offset, int Count) +{ + int Mask = Count == 32 ? -1 : ((1 << Count) - 1); + int3 Masked = (Base >> Offset) & Mask; + int ExtendShift = (32 - Count) & 31; + return (Masked << ExtendShift) >> ExtendShift; +} + +int4 SPIRV_Cross_bitfieldSExtract(int4 Base, int Offset, int Count) +{ + int Mask = Count == 32 ? -1 : ((1 << Count) - 1); + int4 Masked = (Base >> Offset) & Mask; + int ExtendShift = (32 - Count) & 31; + return (Masked << ExtendShift) >> ExtendShift; +} + +void comp_main() +{ + int4 _19 = int4(_3.Load4(0)); + uint4 _20 = _3.Load4(16); + _3.Store4(0, uint4(countbits(_19))); + _3.Store4(16, uint4(countbits(_19))); + _3.Store4(0, uint4(int4(countbits(_20)))); + _3.Store4(16, countbits(_20)); + _3.Store4(0, uint4(reversebits(_19))); + _3.Store4(16, reversebits(_20)); + _3.Store4(0, uint4(SPIRV_Cross_bitfieldSExtract(_19, 1, 11u))); + _3.Store4(16, SPIRV_Cross_bitfieldSExtract(_20, 11u, 1)); + _3.Store4(0, uint4(SPIRV_Cross_bitfieldUExtract(_19, 1, 11u))); + _3.Store4(16, SPIRV_Cross_bitfieldUExtract(_20, 11u, 1)); + _3.Store4(0, uint4(int4(SPIRV_Cross_bitfieldInsert(_19, _19.wzyx, 1, 11u)))); + _3.Store4(16, SPIRV_Cross_bitfieldInsert(_20, _20.wzyx, 11u, 1)); +} + +[numthreads(1, 1, 1)] +void main() +{ + comp_main(); +} diff --git a/third_party/spirv-cross/reference/shaders-hlsl-no-opt/asm/comp/constant-composite-undef.asm.comp b/third_party/spirv-cross/reference/shaders-hlsl-no-opt/asm/comp/constant-composite-undef.asm.comp index 4851d21e16..e05b2f1d29 100644 --- a/third_party/spirv-cross/reference/shaders-hlsl-no-opt/asm/comp/constant-composite-undef.asm.comp +++ b/third_party/spirv-cross/reference/shaders-hlsl-no-opt/asm/comp/constant-composite-undef.asm.comp @@ -1,6 +1,6 @@ RWByteAddressBuffer block : register(u0); -float _15; +static float _15; void comp_main() { diff --git a/third_party/spirv-cross/reference/opt/shaders-hlsl/asm/comp/storage-buffer-basic.invalid.nofxc.asm.comp b/third_party/spirv-cross/reference/shaders-hlsl-no-opt/asm/comp/storage-buffer-basic.invalid.nofxc.asm.comp similarity index 100% rename from third_party/spirv-cross/reference/opt/shaders-hlsl/asm/comp/storage-buffer-basic.invalid.nofxc.asm.comp rename to third_party/spirv-cross/reference/shaders-hlsl-no-opt/asm/comp/storage-buffer-basic.invalid.nofxc.asm.comp diff --git a/third_party/spirv-cross/reference/shaders-hlsl-no-opt/asm/frag/empty-struct-in-struct.asm.frag b/third_party/spirv-cross/reference/shaders-hlsl-no-opt/asm/frag/empty-struct-in-struct.asm.frag new file mode 100644 index 0000000000..e7ffd8d606 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-hlsl-no-opt/asm/frag/empty-struct-in-struct.asm.frag @@ -0,0 +1,37 @@ +struct EmptyStructTest +{ + int empty_struct_member; +}; + +struct EmptyStruct2Test +{ + EmptyStructTest _m0; +}; + +static const EmptyStructTest _30 = { 0 }; +static const EmptyStruct2Test _20 = { { 0 } }; + +float GetValue(EmptyStruct2Test self) +{ + return 0.0f; +} + +float GetValue_1(EmptyStruct2Test self) +{ + return 0.0f; +} + +void frag_main() +{ + EmptyStructTest _25 = { 0 }; + EmptyStruct2Test _26 = { _25 }; + EmptyStruct2Test emptyStruct; + float value = GetValue(emptyStruct); + value = GetValue_1(_26); + value = GetValue_1(_20); +} + +void main() +{ + frag_main(); +} diff --git a/third_party/spirv-cross/reference/shaders-hlsl-no-opt/asm/frag/pixel-interlock-callstack.sm51.fxconly.asm.frag b/third_party/spirv-cross/reference/shaders-hlsl-no-opt/asm/frag/pixel-interlock-callstack.sm51.fxconly.asm.frag new file mode 100644 index 0000000000..3268995c8d --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-hlsl-no-opt/asm/frag/pixel-interlock-callstack.sm51.fxconly.asm.frag @@ -0,0 +1,32 @@ +RasterizerOrderedByteAddressBuffer _7 : register(u1, space0); +RWByteAddressBuffer _9 : register(u0, space0); + +static float4 gl_FragCoord; +struct SPIRV_Cross_Input +{ + float4 gl_FragCoord : SV_Position; +}; + +void callee2() +{ + int _31 = int(gl_FragCoord.x); + _7.Store(_31 * 4 + 0, _7.Load(_31 * 4 + 0) + 1u); +} + +void callee() +{ + int _39 = int(gl_FragCoord.x); + _9.Store(_39 * 4 + 0, _9.Load(_39 * 4 + 0) + 1u); + callee2(); +} + +void frag_main() +{ + callee(); +} + +void main(SPIRV_Cross_Input stage_input) +{ + gl_FragCoord = stage_input.gl_FragCoord; + frag_main(); +} diff --git a/third_party/spirv-cross/reference/shaders-hlsl-no-opt/asm/frag/pixel-interlock-control-flow.sm51.fxconly.asm.frag b/third_party/spirv-cross/reference/shaders-hlsl-no-opt/asm/frag/pixel-interlock-control-flow.sm51.fxconly.asm.frag new file mode 100644 index 0000000000..692771215b --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-hlsl-no-opt/asm/frag/pixel-interlock-control-flow.sm51.fxconly.asm.frag @@ -0,0 +1,42 @@ +RasterizerOrderedByteAddressBuffer _7 : register(u1, space0); +RWByteAddressBuffer _13 : register(u2, space0); +RasterizerOrderedByteAddressBuffer _9 : register(u0, space0); + +static float4 gl_FragCoord; +struct SPIRV_Cross_Input +{ + float4 gl_FragCoord : SV_Position; +}; + +void callee2() +{ + int _44 = int(gl_FragCoord.x); + _7.Store(_44 * 4 + 0, _7.Load(_44 * 4 + 0) + 1u); +} + +void callee() +{ + int _52 = int(gl_FragCoord.x); + _9.Store(_52 * 4 + 0, _9.Load(_52 * 4 + 0) + 1u); + callee2(); + if (true) + { + } +} + +void _35() +{ + _13.Store(int(gl_FragCoord.x) * 4 + 0, 4u); +} + +void frag_main() +{ + callee(); + _35(); +} + +void main(SPIRV_Cross_Input stage_input) +{ + gl_FragCoord = stage_input.gl_FragCoord; + frag_main(); +} diff --git a/third_party/spirv-cross/reference/shaders-hlsl-no-opt/asm/frag/pixel-interlock-split-functions.sm51.fxconly.asm.frag b/third_party/spirv-cross/reference/shaders-hlsl-no-opt/asm/frag/pixel-interlock-split-functions.sm51.fxconly.asm.frag new file mode 100644 index 0000000000..bd963a74de --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-hlsl-no-opt/asm/frag/pixel-interlock-split-functions.sm51.fxconly.asm.frag @@ -0,0 +1,42 @@ +RasterizerOrderedByteAddressBuffer _7 : register(u1, space0); +RasterizerOrderedByteAddressBuffer _9 : register(u0, space0); + +static float4 gl_FragCoord; +struct SPIRV_Cross_Input +{ + float4 gl_FragCoord : SV_Position; +}; + +void callee2() +{ + int _37 = int(gl_FragCoord.x); + _7.Store(_37 * 4 + 0, _7.Load(_37 * 4 + 0) + 1u); +} + +void callee() +{ + int _45 = int(gl_FragCoord.x); + _9.Store(_45 * 4 + 0, _9.Load(_45 * 4 + 0) + 1u); + callee2(); +} + +void _29() +{ +} + +void _31() +{ +} + +void frag_main() +{ + callee(); + _29(); + _31(); +} + +void main(SPIRV_Cross_Input stage_input) +{ + gl_FragCoord = stage_input.gl_FragCoord; + frag_main(); +} diff --git a/third_party/spirv-cross/reference/shaders-hlsl-no-opt/asm/frag/subgroup-arithmetic-cast.invalid.nofxc.sm60.asm.frag b/third_party/spirv-cross/reference/shaders-hlsl-no-opt/asm/frag/subgroup-arithmetic-cast.invalid.nofxc.sm60.asm.frag new file mode 100644 index 0000000000..b98e681f6d --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-hlsl-no-opt/asm/frag/subgroup-arithmetic-cast.invalid.nofxc.sm60.asm.frag @@ -0,0 +1,30 @@ +static int index; +static uint FragColor; + +struct SPIRV_Cross_Input +{ + nointerpolation int index : TEXCOORD0; +}; + +struct SPIRV_Cross_Output +{ + uint FragColor : SV_Target0; +}; + +void frag_main() +{ + uint _17 = uint(index); + FragColor = uint(WaveActiveMin(index)); + FragColor = uint(WaveActiveMax(int(_17))); + FragColor = WaveActiveMin(uint(index)); + FragColor = WaveActiveMax(_17); +} + +SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input) +{ + index = stage_input.index; + frag_main(); + SPIRV_Cross_Output stage_output; + stage_output.FragColor = FragColor; + return stage_output; +} diff --git a/third_party/spirv-cross/reference/shaders-hlsl-no-opt/asm/frag/switch-block-case-fallthrough.asm.frag b/third_party/spirv-cross/reference/shaders-hlsl-no-opt/asm/frag/switch-block-case-fallthrough.asm.invalid.frag similarity index 100% rename from third_party/spirv-cross/reference/shaders-hlsl-no-opt/asm/frag/switch-block-case-fallthrough.asm.frag rename to third_party/spirv-cross/reference/shaders-hlsl-no-opt/asm/frag/switch-block-case-fallthrough.asm.invalid.frag diff --git a/third_party/spirv-cross/reference/shaders-hlsl-no-opt/asm/frag/unordered-compare.asm.frag b/third_party/spirv-cross/reference/shaders-hlsl-no-opt/asm/frag/unordered-compare.asm.frag new file mode 100644 index 0000000000..1143ade716 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-hlsl-no-opt/asm/frag/unordered-compare.asm.frag @@ -0,0 +1,51 @@ +static float4 A; +static float4 B; +static float4 FragColor; + +struct SPIRV_Cross_Input +{ + float4 A : TEXCOORD0; + float4 B : TEXCOORD1; +}; + +struct SPIRV_Cross_Output +{ + float4 FragColor : SV_Target0; +}; + +float4 test_vector() +{ + bool4 le = bool4(!(A.x >= B.x), !(A.y >= B.y), !(A.z >= B.z), !(A.w >= B.w)); + bool4 leq = bool4(!(A.x > B.x), !(A.y > B.y), !(A.z > B.z), !(A.w > B.w)); + bool4 ge = bool4(!(A.x <= B.x), !(A.y <= B.y), !(A.z <= B.z), !(A.w <= B.w)); + bool4 geq = bool4(!(A.x < B.x), !(A.y < B.y), !(A.z < B.z), !(A.w < B.w)); + bool4 eq = bool4(A.x == B.x, A.y == B.y, A.z == B.z, A.w == B.w); + bool4 neq = bool4(A.x != B.x, A.y != B.y, A.z != B.z, A.w != B.w); + return ((((float4(le.x ? 1.0f.xxxx.x : 0.0f.xxxx.x, le.y ? 1.0f.xxxx.y : 0.0f.xxxx.y, le.z ? 1.0f.xxxx.z : 0.0f.xxxx.z, le.w ? 1.0f.xxxx.w : 0.0f.xxxx.w) + float4(leq.x ? 1.0f.xxxx.x : 0.0f.xxxx.x, leq.y ? 1.0f.xxxx.y : 0.0f.xxxx.y, leq.z ? 1.0f.xxxx.z : 0.0f.xxxx.z, leq.w ? 1.0f.xxxx.w : 0.0f.xxxx.w)) + float4(ge.x ? 1.0f.xxxx.x : 0.0f.xxxx.x, ge.y ? 1.0f.xxxx.y : 0.0f.xxxx.y, ge.z ? 1.0f.xxxx.z : 0.0f.xxxx.z, ge.w ? 1.0f.xxxx.w : 0.0f.xxxx.w)) + float4(geq.x ? 1.0f.xxxx.x : 0.0f.xxxx.x, geq.y ? 1.0f.xxxx.y : 0.0f.xxxx.y, geq.z ? 1.0f.xxxx.z : 0.0f.xxxx.z, geq.w ? 1.0f.xxxx.w : 0.0f.xxxx.w)) + float4(eq.x ? 1.0f.xxxx.x : 0.0f.xxxx.x, eq.y ? 1.0f.xxxx.y : 0.0f.xxxx.y, eq.z ? 1.0f.xxxx.z : 0.0f.xxxx.z, eq.w ? 1.0f.xxxx.w : 0.0f.xxxx.w)) + float4(neq.x ? 1.0f.xxxx.x : 0.0f.xxxx.x, neq.y ? 1.0f.xxxx.y : 0.0f.xxxx.y, neq.z ? 1.0f.xxxx.z : 0.0f.xxxx.z, neq.w ? 1.0f.xxxx.w : 0.0f.xxxx.w); +} + +float test_scalar() +{ + bool le = !(A.x >= B.x); + bool leq = !(A.x > B.x); + bool ge = !(A.x <= B.x); + bool geq = !(A.x < B.x); + bool eq = A.x == B.x; + bool neq = A.x != B.x; + return ((((float(le) + float(leq)) + float(ge)) + float(geq)) + float(eq)) + float(neq); +} + +void frag_main() +{ + FragColor = test_vector() + test_scalar().xxxx; +} + +SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input) +{ + A = stage_input.A; + B = stage_input.B; + frag_main(); + SPIRV_Cross_Output stage_output; + stage_output.FragColor = FragColor; + return stage_output; +} diff --git a/third_party/spirv-cross/reference/shaders-hlsl-no-opt/asm/frag/vector-shuffle-undef-index.asm.frag b/third_party/spirv-cross/reference/shaders-hlsl-no-opt/asm/frag/vector-shuffle-undef-index.asm.frag index a01d5fa7d0..fa41b13c50 100644 --- a/third_party/spirv-cross/reference/shaders-hlsl-no-opt/asm/frag/vector-shuffle-undef-index.asm.frag +++ b/third_party/spirv-cross/reference/shaders-hlsl-no-opt/asm/frag/vector-shuffle-undef-index.asm.frag @@ -11,7 +11,7 @@ struct SPIRV_Cross_Output float4 FragColor : SV_Target0; }; -float4 undef; +static float4 undef; void frag_main() { diff --git a/third_party/spirv-cross/reference/shaders-hlsl-no-opt/comp/bitfield.comp b/third_party/spirv-cross/reference/shaders-hlsl-no-opt/comp/bitfield.comp index 4e93a14535..0dc089c1de 100644 --- a/third_party/spirv-cross/reference/shaders-hlsl-no-opt/comp/bitfield.comp +++ b/third_party/spirv-cross/reference/shaders-hlsl-no-opt/comp/bitfield.comp @@ -90,7 +90,7 @@ void comp_main() u = SPIRV_Cross_bitfieldInsert(u, 60u, 5, 4); u = reversebits(u); s = reversebits(s); - int v0 = countbits(u); + int v0 = int(countbits(u)); int v1 = countbits(s); int v2 = int(firstbithigh(u)); int v3 = firstbitlow(s); @@ -100,7 +100,7 @@ void comp_main() u_1 = SPIRV_Cross_bitfieldInsert(u_1, uint3(60u, 60u, 60u), 5, 4); u_1 = reversebits(u_1); s_1 = reversebits(s_1); - int3 v0_1 = countbits(u_1); + int3 v0_1 = int3(countbits(u_1)); int3 v1_1 = countbits(s_1); int3 v2_1 = int3(firstbithigh(u_1)); int3 v3_1 = firstbitlow(s_1); diff --git a/third_party/spirv-cross/reference/shaders-hlsl-no-opt/comp/glsl.std450.fxconly.comp b/third_party/spirv-cross/reference/shaders-hlsl-no-opt/comp/glsl.std450.fxconly.comp index d697ed4e7f..7558afaa86 100644 --- a/third_party/spirv-cross/reference/shaders-hlsl-no-opt/comp/glsl.std450.fxconly.comp +++ b/third_party/spirv-cross/reference/shaders-hlsl-no-opt/comp/glsl.std450.fxconly.comp @@ -4,6 +4,8 @@ struct ResType int _m1; }; +static const uint3 gl_WorkGroupSize = uint3(1u, 1u, 1u); + RWByteAddressBuffer _19 : register(u0); uint SPIRV_Cross_packHalf2x16(float2 value) diff --git a/third_party/spirv-cross/reference/shaders-hlsl-no-opt/comp/illegal-struct-name.asm.comp b/third_party/spirv-cross/reference/shaders-hlsl-no-opt/comp/illegal-struct-name.asm.comp new file mode 100644 index 0000000000..dc972bdda8 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-hlsl-no-opt/comp/illegal-struct-name.asm.comp @@ -0,0 +1,22 @@ +struct Foo +{ + float _abs; +}; + +RWByteAddressBuffer _7 : register(u0); + +void comp_main() +{ + Foo _24; + _24._abs = asfloat(_7.Load(0)); + Foo f; + f._abs = _24._abs; + int _abs = 10; + _7.Store(4, asuint(f._abs)); +} + +[numthreads(1, 1, 1)] +void main() +{ + comp_main(); +} diff --git a/third_party/spirv-cross/reference/shaders-hlsl/comp/subgroups.invalid.nofxc.sm60.comp b/third_party/spirv-cross/reference/shaders-hlsl-no-opt/comp/subgroups.invalid.nofxc.sm60.comp similarity index 98% rename from third_party/spirv-cross/reference/shaders-hlsl/comp/subgroups.invalid.nofxc.sm60.comp rename to third_party/spirv-cross/reference/shaders-hlsl-no-opt/comp/subgroups.invalid.nofxc.sm60.comp index b87574f1a7..0957a70872 100644 --- a/third_party/spirv-cross/reference/shaders-hlsl/comp/subgroups.invalid.nofxc.sm60.comp +++ b/third_party/spirv-cross/reference/shaders-hlsl-no-opt/comp/subgroups.invalid.nofxc.sm60.comp @@ -1,3 +1,5 @@ +static const uint3 gl_WorkGroupSize = uint3(1u, 1u, 1u); + RWByteAddressBuffer _9 : register(u0, space0); static uint4 gl_SubgroupEqMask; diff --git a/third_party/spirv-cross/reference/opt/shaders-hlsl/frag/constant-buffer-array.invalid.sm51.frag b/third_party/spirv-cross/reference/shaders-hlsl-no-opt/frag/constant-buffer-array.invalid.sm51.frag similarity index 100% rename from third_party/spirv-cross/reference/opt/shaders-hlsl/frag/constant-buffer-array.invalid.sm51.frag rename to third_party/spirv-cross/reference/shaders-hlsl-no-opt/frag/constant-buffer-array.invalid.sm51.frag diff --git a/third_party/spirv-cross/reference/shaders-hlsl/frag/fp16.invalid.desktop.frag b/third_party/spirv-cross/reference/shaders-hlsl-no-opt/frag/fp16.invalid.desktop.frag similarity index 100% rename from third_party/spirv-cross/reference/shaders-hlsl/frag/fp16.invalid.desktop.frag rename to third_party/spirv-cross/reference/shaders-hlsl-no-opt/frag/fp16.invalid.desktop.frag diff --git a/third_party/spirv-cross/reference/shaders-hlsl-no-opt/frag/pixel-interlock-simple-callstack.sm51.fxconly.frag b/third_party/spirv-cross/reference/shaders-hlsl-no-opt/frag/pixel-interlock-simple-callstack.sm51.fxconly.frag new file mode 100644 index 0000000000..55b71de210 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-hlsl-no-opt/frag/pixel-interlock-simple-callstack.sm51.fxconly.frag @@ -0,0 +1,32 @@ +RasterizerOrderedByteAddressBuffer _14 : register(u1, space0); +RasterizerOrderedByteAddressBuffer _35 : register(u0, space0); + +static float4 gl_FragCoord; +struct SPIRV_Cross_Input +{ + float4 gl_FragCoord : SV_Position; +}; + +void callee2() +{ + int _25 = int(gl_FragCoord.x); + _14.Store(_25 * 4 + 0, _14.Load(_25 * 4 + 0) + 1u); +} + +void callee() +{ + int _38 = int(gl_FragCoord.x); + _35.Store(_38 * 4 + 0, _35.Load(_38 * 4 + 0) + 1u); + callee2(); +} + +void frag_main() +{ + callee(); +} + +void main(SPIRV_Cross_Input stage_input) +{ + gl_FragCoord = stage_input.gl_FragCoord; + frag_main(); +} diff --git a/third_party/spirv-cross/reference/shaders-hlsl/asm/comp/bitcast_icmp.asm.comp b/third_party/spirv-cross/reference/shaders-hlsl/asm/comp/bitcast_icmp.asm.comp new file mode 100644 index 0000000000..35143a486e --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-hlsl/asm/comp/bitcast_icmp.asm.comp @@ -0,0 +1,28 @@ +RWByteAddressBuffer _5 : register(u0); +RWByteAddressBuffer _6 : register(u1); + +void comp_main() +{ + bool4 _31 = bool4(int(_5.Load4(16).x) < int4(_5.Load4(0)).x, int(_5.Load4(16).y) < int4(_5.Load4(0)).y, int(_5.Load4(16).z) < int4(_5.Load4(0)).z, int(_5.Load4(16).w) < int4(_5.Load4(0)).w); + bool4 _32 = bool4(int(_5.Load4(16).x) <= int4(_5.Load4(0)).x, int(_5.Load4(16).y) <= int4(_5.Load4(0)).y, int(_5.Load4(16).z) <= int4(_5.Load4(0)).z, int(_5.Load4(16).w) <= int4(_5.Load4(0)).w); + bool4 _33 = bool4(_5.Load4(16).x < uint(int4(_5.Load4(0)).x), _5.Load4(16).y < uint(int4(_5.Load4(0)).y), _5.Load4(16).z < uint(int4(_5.Load4(0)).z), _5.Load4(16).w < uint(int4(_5.Load4(0)).w)); + bool4 _34 = bool4(_5.Load4(16).x <= uint(int4(_5.Load4(0)).x), _5.Load4(16).y <= uint(int4(_5.Load4(0)).y), _5.Load4(16).z <= uint(int4(_5.Load4(0)).z), _5.Load4(16).w <= uint(int4(_5.Load4(0)).w)); + bool4 _35 = bool4(int(_5.Load4(16).x) > int4(_5.Load4(0)).x, int(_5.Load4(16).y) > int4(_5.Load4(0)).y, int(_5.Load4(16).z) > int4(_5.Load4(0)).z, int(_5.Load4(16).w) > int4(_5.Load4(0)).w); + bool4 _36 = bool4(int(_5.Load4(16).x) >= int4(_5.Load4(0)).x, int(_5.Load4(16).y) >= int4(_5.Load4(0)).y, int(_5.Load4(16).z) >= int4(_5.Load4(0)).z, int(_5.Load4(16).w) >= int4(_5.Load4(0)).w); + bool4 _37 = bool4(_5.Load4(16).x > uint(int4(_5.Load4(0)).x), _5.Load4(16).y > uint(int4(_5.Load4(0)).y), _5.Load4(16).z > uint(int4(_5.Load4(0)).z), _5.Load4(16).w > uint(int4(_5.Load4(0)).w)); + bool4 _38 = bool4(_5.Load4(16).x >= uint(int4(_5.Load4(0)).x), _5.Load4(16).y >= uint(int4(_5.Load4(0)).y), _5.Load4(16).z >= uint(int4(_5.Load4(0)).z), _5.Load4(16).w >= uint(int4(_5.Load4(0)).w)); + _6.Store4(0, uint4(_31.x ? uint4(1u, 1u, 1u, 1u).x : uint4(0u, 0u, 0u, 0u).x, _31.y ? uint4(1u, 1u, 1u, 1u).y : uint4(0u, 0u, 0u, 0u).y, _31.z ? uint4(1u, 1u, 1u, 1u).z : uint4(0u, 0u, 0u, 0u).z, _31.w ? uint4(1u, 1u, 1u, 1u).w : uint4(0u, 0u, 0u, 0u).w)); + _6.Store4(0, uint4(_32.x ? uint4(1u, 1u, 1u, 1u).x : uint4(0u, 0u, 0u, 0u).x, _32.y ? uint4(1u, 1u, 1u, 1u).y : uint4(0u, 0u, 0u, 0u).y, _32.z ? uint4(1u, 1u, 1u, 1u).z : uint4(0u, 0u, 0u, 0u).z, _32.w ? uint4(1u, 1u, 1u, 1u).w : uint4(0u, 0u, 0u, 0u).w)); + _6.Store4(0, uint4(_33.x ? uint4(1u, 1u, 1u, 1u).x : uint4(0u, 0u, 0u, 0u).x, _33.y ? uint4(1u, 1u, 1u, 1u).y : uint4(0u, 0u, 0u, 0u).y, _33.z ? uint4(1u, 1u, 1u, 1u).z : uint4(0u, 0u, 0u, 0u).z, _33.w ? uint4(1u, 1u, 1u, 1u).w : uint4(0u, 0u, 0u, 0u).w)); + _6.Store4(0, uint4(_34.x ? uint4(1u, 1u, 1u, 1u).x : uint4(0u, 0u, 0u, 0u).x, _34.y ? uint4(1u, 1u, 1u, 1u).y : uint4(0u, 0u, 0u, 0u).y, _34.z ? uint4(1u, 1u, 1u, 1u).z : uint4(0u, 0u, 0u, 0u).z, _34.w ? uint4(1u, 1u, 1u, 1u).w : uint4(0u, 0u, 0u, 0u).w)); + _6.Store4(0, uint4(_35.x ? uint4(1u, 1u, 1u, 1u).x : uint4(0u, 0u, 0u, 0u).x, _35.y ? uint4(1u, 1u, 1u, 1u).y : uint4(0u, 0u, 0u, 0u).y, _35.z ? uint4(1u, 1u, 1u, 1u).z : uint4(0u, 0u, 0u, 0u).z, _35.w ? uint4(1u, 1u, 1u, 1u).w : uint4(0u, 0u, 0u, 0u).w)); + _6.Store4(0, uint4(_36.x ? uint4(1u, 1u, 1u, 1u).x : uint4(0u, 0u, 0u, 0u).x, _36.y ? uint4(1u, 1u, 1u, 1u).y : uint4(0u, 0u, 0u, 0u).y, _36.z ? uint4(1u, 1u, 1u, 1u).z : uint4(0u, 0u, 0u, 0u).z, _36.w ? uint4(1u, 1u, 1u, 1u).w : uint4(0u, 0u, 0u, 0u).w)); + _6.Store4(0, uint4(_37.x ? uint4(1u, 1u, 1u, 1u).x : uint4(0u, 0u, 0u, 0u).x, _37.y ? uint4(1u, 1u, 1u, 1u).y : uint4(0u, 0u, 0u, 0u).y, _37.z ? uint4(1u, 1u, 1u, 1u).z : uint4(0u, 0u, 0u, 0u).z, _37.w ? uint4(1u, 1u, 1u, 1u).w : uint4(0u, 0u, 0u, 0u).w)); + _6.Store4(0, uint4(_38.x ? uint4(1u, 1u, 1u, 1u).x : uint4(0u, 0u, 0u, 0u).x, _38.y ? uint4(1u, 1u, 1u, 1u).y : uint4(0u, 0u, 0u, 0u).y, _38.z ? uint4(1u, 1u, 1u, 1u).z : uint4(0u, 0u, 0u, 0u).z, _38.w ? uint4(1u, 1u, 1u, 1u).w : uint4(0u, 0u, 0u, 0u).w)); +} + +[numthreads(1, 1, 1)] +void main() +{ + comp_main(); +} diff --git a/third_party/spirv-cross/reference/shaders-hlsl/asm/comp/storage-buffer-basic.invalid.nofxc.asm.comp b/third_party/spirv-cross/reference/shaders-hlsl/asm/comp/storage-buffer-basic.invalid.nofxc.asm.comp deleted file mode 100644 index c567fbaf14..0000000000 --- a/third_party/spirv-cross/reference/shaders-hlsl/asm/comp/storage-buffer-basic.invalid.nofxc.asm.comp +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef SPIRV_CROSS_CONSTANT_ID_0 -#define SPIRV_CROSS_CONSTANT_ID_0 1u -#endif -static const uint _3 = SPIRV_CROSS_CONSTANT_ID_0; -#ifndef SPIRV_CROSS_CONSTANT_ID_2 -#define SPIRV_CROSS_CONSTANT_ID_2 3u -#endif -static const uint _4 = SPIRV_CROSS_CONSTANT_ID_2; -static const uint3 gl_WorkGroupSize = uint3(_3, 2u, _4); - -RWByteAddressBuffer _8 : register(u0); -RWByteAddressBuffer _9 : register(u1); - -static uint3 gl_WorkGroupID; -struct SPIRV_Cross_Input -{ - uint3 gl_WorkGroupID : SV_GroupID; -}; - -static uint3 _22 = gl_WorkGroupSize; - -void comp_main() -{ - _8.Store(gl_WorkGroupID.x * 4 + 0, asuint(asfloat(_9.Load(gl_WorkGroupID.x * 4 + 0)) + asfloat(_8.Load(gl_WorkGroupID.x * 4 + 0)))); -} - -[numthreads(SPIRV_CROSS_CONSTANT_ID_0, 2, SPIRV_CROSS_CONSTANT_ID_2)] -void main(SPIRV_Cross_Input stage_input) -{ - gl_WorkGroupID = stage_input.gl_WorkGroupID; - comp_main(); -} diff --git a/third_party/spirv-cross/reference/shaders-hlsl/asm/frag/unreachable.asm.frag b/third_party/spirv-cross/reference/shaders-hlsl/asm/frag/unreachable.asm.frag index c2fa519df8..86c1daa242 100644 --- a/third_party/spirv-cross/reference/shaders-hlsl/asm/frag/unreachable.asm.frag +++ b/third_party/spirv-cross/reference/shaders-hlsl/asm/frag/unreachable.asm.frag @@ -11,7 +11,7 @@ struct SPIRV_Cross_Output float4 FragColor : SV_Target0; }; -float4 _21; +static float4 _21; void frag_main() { diff --git a/third_party/spirv-cross/reference/shaders-hlsl/comp/access-chain-load-composite.comp b/third_party/spirv-cross/reference/shaders-hlsl/comp/access-chain-load-composite.comp new file mode 100644 index 0000000000..1c4016008b --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-hlsl/comp/access-chain-load-composite.comp @@ -0,0 +1,164 @@ +struct Baz +{ + float c; +}; + +struct Bar +{ + float d[2][4]; + Baz baz[2]; +}; + +struct Foo +{ + column_major float2x2 a; + float2 b; + Bar c[5]; +}; + +static const uint3 gl_WorkGroupSize = uint3(1u, 1u, 1u); + +RWByteAddressBuffer _31 : register(u0); + +void comp_main() +{ + Foo _36; + _36.a = asfloat(uint2x2(_31.Load(0), _31.Load(8), _31.Load(4), _31.Load(12))); + _36.b = asfloat(_31.Load2(16)); + [unroll] + for (int _4ident = 0; _4ident < 5; _4ident++) + { + [unroll] + for (int _5ident = 0; _5ident < 2; _5ident++) + { + [unroll] + for (int _6ident = 0; _6ident < 4; _6ident++) + { + _36.c[_4ident].d[_5ident][_6ident] = asfloat(_31.Load(_6ident * 4 + _5ident * 16 + _4ident * 40 + 24)); + } + } + [unroll] + for (int _7ident = 0; _7ident < 2; _7ident++) + { + _36.c[_4ident].baz[_7ident].c = asfloat(_31.Load(_7ident * 4 + _4ident * 40 + 56)); + } + } + Foo f; + f.a = _36.a; + f.b = _36.b; + f.c[0].d[0][0] = _36.c[0].d[0][0]; + f.c[0].d[0][1] = _36.c[0].d[0][1]; + f.c[0].d[0][2] = _36.c[0].d[0][2]; + f.c[0].d[0][3] = _36.c[0].d[0][3]; + f.c[0].d[1][0] = _36.c[0].d[1][0]; + f.c[0].d[1][1] = _36.c[0].d[1][1]; + f.c[0].d[1][2] = _36.c[0].d[1][2]; + f.c[0].d[1][3] = _36.c[0].d[1][3]; + f.c[0].baz[0].c = _36.c[0].baz[0].c; + f.c[0].baz[1].c = _36.c[0].baz[1].c; + f.c[1].d[0][0] = _36.c[1].d[0][0]; + f.c[1].d[0][1] = _36.c[1].d[0][1]; + f.c[1].d[0][2] = _36.c[1].d[0][2]; + f.c[1].d[0][3] = _36.c[1].d[0][3]; + f.c[1].d[1][0] = _36.c[1].d[1][0]; + f.c[1].d[1][1] = _36.c[1].d[1][1]; + f.c[1].d[1][2] = _36.c[1].d[1][2]; + f.c[1].d[1][3] = _36.c[1].d[1][3]; + f.c[1].baz[0].c = _36.c[1].baz[0].c; + f.c[1].baz[1].c = _36.c[1].baz[1].c; + f.c[2].d[0][0] = _36.c[2].d[0][0]; + f.c[2].d[0][1] = _36.c[2].d[0][1]; + f.c[2].d[0][2] = _36.c[2].d[0][2]; + f.c[2].d[0][3] = _36.c[2].d[0][3]; + f.c[2].d[1][0] = _36.c[2].d[1][0]; + f.c[2].d[1][1] = _36.c[2].d[1][1]; + f.c[2].d[1][2] = _36.c[2].d[1][2]; + f.c[2].d[1][3] = _36.c[2].d[1][3]; + f.c[2].baz[0].c = _36.c[2].baz[0].c; + f.c[2].baz[1].c = _36.c[2].baz[1].c; + f.c[3].d[0][0] = _36.c[3].d[0][0]; + f.c[3].d[0][1] = _36.c[3].d[0][1]; + f.c[3].d[0][2] = _36.c[3].d[0][2]; + f.c[3].d[0][3] = _36.c[3].d[0][3]; + f.c[3].d[1][0] = _36.c[3].d[1][0]; + f.c[3].d[1][1] = _36.c[3].d[1][1]; + f.c[3].d[1][2] = _36.c[3].d[1][2]; + f.c[3].d[1][3] = _36.c[3].d[1][3]; + f.c[3].baz[0].c = _36.c[3].baz[0].c; + f.c[3].baz[1].c = _36.c[3].baz[1].c; + f.c[4].d[0][0] = _36.c[4].d[0][0]; + f.c[4].d[0][1] = _36.c[4].d[0][1]; + f.c[4].d[0][2] = _36.c[4].d[0][2]; + f.c[4].d[0][3] = _36.c[4].d[0][3]; + f.c[4].d[1][0] = _36.c[4].d[1][0]; + f.c[4].d[1][1] = _36.c[4].d[1][1]; + f.c[4].d[1][2] = _36.c[4].d[1][2]; + f.c[4].d[1][3] = _36.c[4].d[1][3]; + f.c[4].baz[0].c = _36.c[4].baz[0].c; + f.c[4].baz[1].c = _36.c[4].baz[1].c; + float2 _229 = 1.0f.xx; + f.a = float2x2(f.a[0] + _229, f.a[1] + _229); + f.b += 2.0f.xx; + f.c[3].d[1][1] += 5.0f; + _31.Store(224, asuint(f.a[0].x)); + _31.Store(228, asuint(f.a[1].x)); + _31.Store(232, asuint(f.a[0].y)); + _31.Store(236, asuint(f.a[1].y)); + _31.Store2(240, asuint(f.b)); + _31.Store(248, asuint(f.c[0].d[0][0])); + _31.Store(252, asuint(f.c[0].d[0][1])); + _31.Store(256, asuint(f.c[0].d[0][2])); + _31.Store(260, asuint(f.c[0].d[0][3])); + _31.Store(264, asuint(f.c[0].d[1][0])); + _31.Store(268, asuint(f.c[0].d[1][1])); + _31.Store(272, asuint(f.c[0].d[1][2])); + _31.Store(276, asuint(f.c[0].d[1][3])); + _31.Store(280, asuint(f.c[0].baz[0].c)); + _31.Store(284, asuint(f.c[0].baz[1].c)); + _31.Store(288, asuint(f.c[1].d[0][0])); + _31.Store(292, asuint(f.c[1].d[0][1])); + _31.Store(296, asuint(f.c[1].d[0][2])); + _31.Store(300, asuint(f.c[1].d[0][3])); + _31.Store(304, asuint(f.c[1].d[1][0])); + _31.Store(308, asuint(f.c[1].d[1][1])); + _31.Store(312, asuint(f.c[1].d[1][2])); + _31.Store(316, asuint(f.c[1].d[1][3])); + _31.Store(320, asuint(f.c[1].baz[0].c)); + _31.Store(324, asuint(f.c[1].baz[1].c)); + _31.Store(328, asuint(f.c[2].d[0][0])); + _31.Store(332, asuint(f.c[2].d[0][1])); + _31.Store(336, asuint(f.c[2].d[0][2])); + _31.Store(340, asuint(f.c[2].d[0][3])); + _31.Store(344, asuint(f.c[2].d[1][0])); + _31.Store(348, asuint(f.c[2].d[1][1])); + _31.Store(352, asuint(f.c[2].d[1][2])); + _31.Store(356, asuint(f.c[2].d[1][3])); + _31.Store(360, asuint(f.c[2].baz[0].c)); + _31.Store(364, asuint(f.c[2].baz[1].c)); + _31.Store(368, asuint(f.c[3].d[0][0])); + _31.Store(372, asuint(f.c[3].d[0][1])); + _31.Store(376, asuint(f.c[3].d[0][2])); + _31.Store(380, asuint(f.c[3].d[0][3])); + _31.Store(384, asuint(f.c[3].d[1][0])); + _31.Store(388, asuint(f.c[3].d[1][1])); + _31.Store(392, asuint(f.c[3].d[1][2])); + _31.Store(396, asuint(f.c[3].d[1][3])); + _31.Store(400, asuint(f.c[3].baz[0].c)); + _31.Store(404, asuint(f.c[3].baz[1].c)); + _31.Store(408, asuint(f.c[4].d[0][0])); + _31.Store(412, asuint(f.c[4].d[0][1])); + _31.Store(416, asuint(f.c[4].d[0][2])); + _31.Store(420, asuint(f.c[4].d[0][3])); + _31.Store(424, asuint(f.c[4].d[1][0])); + _31.Store(428, asuint(f.c[4].d[1][1])); + _31.Store(432, asuint(f.c[4].d[1][2])); + _31.Store(436, asuint(f.c[4].d[1][3])); + _31.Store(440, asuint(f.c[4].baz[0].c)); + _31.Store(444, asuint(f.c[4].baz[1].c)); +} + +[numthreads(1, 1, 1)] +void main() +{ + comp_main(); +} diff --git a/third_party/spirv-cross/reference/shaders-hlsl/comp/access-chains.comp b/third_party/spirv-cross/reference/shaders-hlsl/comp/access-chains.comp index 924e919124..c748200b96 100644 --- a/third_party/spirv-cross/reference/shaders-hlsl/comp/access-chains.comp +++ b/third_party/spirv-cross/reference/shaders-hlsl/comp/access-chains.comp @@ -1,3 +1,5 @@ +static const uint3 gl_WorkGroupSize = uint3(1u, 1u, 1u); + RWByteAddressBuffer wo : register(u1); ByteAddressBuffer ro : register(t0); diff --git a/third_party/spirv-cross/reference/shaders-hlsl/comp/access-chains.force-uav.comp b/third_party/spirv-cross/reference/shaders-hlsl/comp/access-chains.force-uav.comp new file mode 100644 index 0000000000..97d046d89a --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-hlsl/comp/access-chains.force-uav.comp @@ -0,0 +1,23 @@ +static const uint3 gl_WorkGroupSize = uint3(1u, 1u, 1u); + +RWByteAddressBuffer wo : register(u1); +RWByteAddressBuffer ro : register(u0); + +static uint3 gl_GlobalInvocationID; +struct SPIRV_Cross_Input +{ + uint3 gl_GlobalInvocationID : SV_DispatchThreadID; +}; + +void comp_main() +{ + wo.Store4(gl_GlobalInvocationID.x * 64 + 272, asuint(asfloat(ro.Load4(gl_GlobalInvocationID.x * 64 + 160)))); + wo.Store4(gl_GlobalInvocationID.x * 16 + 480, asuint(asfloat(ro.Load4(gl_GlobalInvocationID.x * 16 + 480)))); +} + +[numthreads(1, 1, 1)] +void main(SPIRV_Cross_Input stage_input) +{ + gl_GlobalInvocationID = stage_input.gl_GlobalInvocationID; + comp_main(); +} diff --git a/third_party/spirv-cross/reference/shaders-hlsl/comp/address-buffers.comp b/third_party/spirv-cross/reference/shaders-hlsl/comp/address-buffers.comp index a252fc8ae3..7f1c7975bc 100644 --- a/third_party/spirv-cross/reference/shaders-hlsl/comp/address-buffers.comp +++ b/third_party/spirv-cross/reference/shaders-hlsl/comp/address-buffers.comp @@ -1,3 +1,5 @@ +static const uint3 gl_WorkGroupSize = uint3(1u, 1u, 1u); + RWByteAddressBuffer WriteOnly : register(u2); ByteAddressBuffer ReadOnly : register(t0); RWByteAddressBuffer ReadWrite : register(u1); diff --git a/third_party/spirv-cross/reference/shaders-hlsl/comp/atomic.comp b/third_party/spirv-cross/reference/shaders-hlsl/comp/atomic.comp index 72e15bf77d..e6ff891e8c 100644 --- a/third_party/spirv-cross/reference/shaders-hlsl/comp/atomic.comp +++ b/third_party/spirv-cross/reference/shaders-hlsl/comp/atomic.comp @@ -1,3 +1,5 @@ +static const uint3 gl_WorkGroupSize = uint3(1u, 1u, 1u); + RWByteAddressBuffer ssbo : register(u2); RWTexture2D uImage : register(u0); RWTexture2D iImage : register(u1); diff --git a/third_party/spirv-cross/reference/shaders-hlsl/comp/globallycoherent.comp b/third_party/spirv-cross/reference/shaders-hlsl/comp/globallycoherent.comp index 69886256f8..236f341e1a 100644 --- a/third_party/spirv-cross/reference/shaders-hlsl/comp/globallycoherent.comp +++ b/third_party/spirv-cross/reference/shaders-hlsl/comp/globallycoherent.comp @@ -1,3 +1,5 @@ +static const uint3 gl_WorkGroupSize = uint3(1u, 1u, 1u); + globallycoherent RWByteAddressBuffer _29 : register(u3); ByteAddressBuffer _33 : register(t2); RWTexture2D uImageIn : register(u0); diff --git a/third_party/spirv-cross/reference/shaders-hlsl/comp/image.comp b/third_party/spirv-cross/reference/shaders-hlsl/comp/image.comp index c8504e636c..89a9940942 100644 --- a/third_party/spirv-cross/reference/shaders-hlsl/comp/image.comp +++ b/third_party/spirv-cross/reference/shaders-hlsl/comp/image.comp @@ -1,3 +1,5 @@ +static const uint3 gl_WorkGroupSize = uint3(1u, 1u, 1u); + RWTexture2D uImageInF : register(u0); RWTexture2D uImageOutF : register(u1); RWTexture2D uImageInI : register(u2); diff --git a/third_party/spirv-cross/reference/shaders-hlsl/comp/inverse.comp b/third_party/spirv-cross/reference/shaders-hlsl/comp/inverse.comp index 3be954a6f6..f9ec89aa31 100644 --- a/third_party/spirv-cross/reference/shaders-hlsl/comp/inverse.comp +++ b/third_party/spirv-cross/reference/shaders-hlsl/comp/inverse.comp @@ -1,3 +1,5 @@ +static const uint3 gl_WorkGroupSize = uint3(1u, 1u, 1u); + RWByteAddressBuffer _15 : register(u0); ByteAddressBuffer _20 : register(t1); diff --git a/third_party/spirv-cross/reference/shaders-hlsl/comp/num-workgroups-alone.comp b/third_party/spirv-cross/reference/shaders-hlsl/comp/num-workgroups-alone.comp index dee39e3d57..dc87dc84f8 100644 --- a/third_party/spirv-cross/reference/shaders-hlsl/comp/num-workgroups-alone.comp +++ b/third_party/spirv-cross/reference/shaders-hlsl/comp/num-workgroups-alone.comp @@ -1,3 +1,5 @@ +static const uint3 gl_WorkGroupSize = uint3(1u, 1u, 1u); + RWByteAddressBuffer _10 : register(u0); cbuffer SPIRV_Cross_NumWorkgroups : register(b0) { diff --git a/third_party/spirv-cross/reference/shaders-hlsl/comp/num-workgroups-with-builtins.comp b/third_party/spirv-cross/reference/shaders-hlsl/comp/num-workgroups-with-builtins.comp index 1c98e5e56d..2e2ad55fdd 100644 --- a/third_party/spirv-cross/reference/shaders-hlsl/comp/num-workgroups-with-builtins.comp +++ b/third_party/spirv-cross/reference/shaders-hlsl/comp/num-workgroups-with-builtins.comp @@ -1,3 +1,5 @@ +static const uint3 gl_WorkGroupSize = uint3(1u, 1u, 1u); + RWByteAddressBuffer _10 : register(u0); cbuffer SPIRV_Cross_NumWorkgroups : register(b0) { diff --git a/third_party/spirv-cross/reference/shaders-hlsl/comp/outer-product.comp b/third_party/spirv-cross/reference/shaders-hlsl/comp/outer-product.comp index 71613d4f15..e58c02fe0b 100644 --- a/third_party/spirv-cross/reference/shaders-hlsl/comp/outer-product.comp +++ b/third_party/spirv-cross/reference/shaders-hlsl/comp/outer-product.comp @@ -1,3 +1,5 @@ +static const uint3 gl_WorkGroupSize = uint3(1u, 1u, 1u); + RWByteAddressBuffer _21 : register(u0); ByteAddressBuffer _26 : register(t1); diff --git a/third_party/spirv-cross/reference/shaders-hlsl/comp/rmw-matrix.comp b/third_party/spirv-cross/reference/shaders-hlsl/comp/rmw-matrix.comp index ed66669358..30ac03f84f 100644 --- a/third_party/spirv-cross/reference/shaders-hlsl/comp/rmw-matrix.comp +++ b/third_party/spirv-cross/reference/shaders-hlsl/comp/rmw-matrix.comp @@ -1,3 +1,5 @@ +static const uint3 gl_WorkGroupSize = uint3(1u, 1u, 1u); + RWByteAddressBuffer _11 : register(u0); void comp_main() diff --git a/third_party/spirv-cross/reference/shaders-hlsl/comp/rwbuffer-matrix.comp b/third_party/spirv-cross/reference/shaders-hlsl/comp/rwbuffer-matrix.comp index e79829283e..197c9a9513 100644 --- a/third_party/spirv-cross/reference/shaders-hlsl/comp/rwbuffer-matrix.comp +++ b/third_party/spirv-cross/reference/shaders-hlsl/comp/rwbuffer-matrix.comp @@ -1,3 +1,5 @@ +static const uint3 gl_WorkGroupSize = uint3(1u, 1u, 1u); + RWByteAddressBuffer _28 : register(u0); cbuffer UBO : register(b1) { diff --git a/third_party/spirv-cross/reference/shaders-hlsl/comp/scalar-std450-distance-length-normalize.comp b/third_party/spirv-cross/reference/shaders-hlsl/comp/scalar-std450-distance-length-normalize.comp index 47f2fe4107..db2bbe9698 100644 --- a/third_party/spirv-cross/reference/shaders-hlsl/comp/scalar-std450-distance-length-normalize.comp +++ b/third_party/spirv-cross/reference/shaders-hlsl/comp/scalar-std450-distance-length-normalize.comp @@ -1,3 +1,5 @@ +static const uint3 gl_WorkGroupSize = uint3(1u, 1u, 1u); + RWByteAddressBuffer _9 : register(u0); void comp_main() diff --git a/third_party/spirv-cross/reference/shaders-hlsl/comp/spec-constant-op-member-array.comp b/third_party/spirv-cross/reference/shaders-hlsl/comp/spec-constant-op-member-array.comp index c4537db039..4e7c5e6167 100644 --- a/third_party/spirv-cross/reference/shaders-hlsl/comp/spec-constant-op-member-array.comp +++ b/third_party/spirv-cross/reference/shaders-hlsl/comp/spec-constant-op-member-array.comp @@ -28,6 +28,7 @@ static const int d = (c + 50); #define SPIRV_CROSS_CONSTANT_ID_3 400 #endif static const int e = SPIRV_CROSS_CONSTANT_ID_3; +static const uint3 gl_WorkGroupSize = uint3(1u, 1u, 1u); RWByteAddressBuffer _22 : register(u0); diff --git a/third_party/spirv-cross/reference/shaders-hlsl/comp/ssbo-array-length.comp b/third_party/spirv-cross/reference/shaders-hlsl/comp/ssbo-array-length.comp index 2e3df626ae..82657cacfc 100644 --- a/third_party/spirv-cross/reference/shaders-hlsl/comp/ssbo-array-length.comp +++ b/third_party/spirv-cross/reference/shaders-hlsl/comp/ssbo-array-length.comp @@ -1,3 +1,5 @@ +static const uint3 gl_WorkGroupSize = uint3(1u, 1u, 1u); + RWByteAddressBuffer _11 : register(u1); void comp_main() diff --git a/third_party/spirv-cross/reference/shaders-hlsl/comp/ssbo-array.comp b/third_party/spirv-cross/reference/shaders-hlsl/comp/ssbo-array.comp index 90927421c6..dab20325b0 100644 --- a/third_party/spirv-cross/reference/shaders-hlsl/comp/ssbo-array.comp +++ b/third_party/spirv-cross/reference/shaders-hlsl/comp/ssbo-array.comp @@ -1,3 +1,5 @@ +static const uint3 gl_WorkGroupSize = uint3(1u, 1u, 1u); + RWByteAddressBuffer ssbo0 : register(u0); void comp_main() diff --git a/third_party/spirv-cross/reference/shaders-hlsl/frag/constant-buffer-array.invalid.sm51.frag b/third_party/spirv-cross/reference/shaders-hlsl/frag/constant-buffer-array.invalid.sm51.frag deleted file mode 100644 index d330706c7b..0000000000 --- a/third_party/spirv-cross/reference/shaders-hlsl/frag/constant-buffer-array.invalid.sm51.frag +++ /dev/null @@ -1,44 +0,0 @@ -struct CBO_1 -{ - float4 a; - float4 b; - float4 c; - float4 d; -}; - -ConstantBuffer cbo[2][4] : register(b4, space0); -cbuffer PushMe -{ - float4 push_a : packoffset(c0); - float4 push_b : packoffset(c1); - float4 push_c : packoffset(c2); - float4 push_d : packoffset(c3); -}; - - -static float4 FragColor; - -struct SPIRV_Cross_Output -{ - float4 FragColor : SV_Target0; -}; - -void frag_main() -{ - FragColor = cbo[1][2].a; - FragColor += cbo[1][2].b; - FragColor += cbo[1][2].c; - FragColor += cbo[1][2].d; - FragColor += push_a; - FragColor += push_b; - FragColor += push_c; - FragColor += push_d; -} - -SPIRV_Cross_Output main() -{ - frag_main(); - SPIRV_Cross_Output stage_output; - stage_output.FragColor = FragColor; - return stage_output; -} diff --git a/third_party/spirv-cross/reference/shaders-hlsl/frag/pixel-interlock-ordered.sm51.fxconly.frag b/third_party/spirv-cross/reference/shaders-hlsl/frag/pixel-interlock-ordered.sm51.fxconly.frag new file mode 100644 index 0000000000..8923f96a75 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-hlsl/frag/pixel-interlock-ordered.sm51.fxconly.frag @@ -0,0 +1,24 @@ +RWByteAddressBuffer _9 : register(u6, space0); +globallycoherent RasterizerOrderedByteAddressBuffer _42 : register(u3, space0); +RasterizerOrderedByteAddressBuffer _52 : register(u4, space0); +RWTexture2D img4 : register(u5, space0); +RasterizerOrderedTexture2D img : register(u0, space0); +RasterizerOrderedTexture2D img3 : register(u2, space0); +RasterizerOrderedTexture2D img2 : register(u1, space0); + +void frag_main() +{ + _9.Store(0, uint(0)); + img4[int2(1, 1)] = float4(1.0f, 0.0f, 0.0f, 1.0f); + img[int2(0, 0)] = img3[int2(0, 0)]; + uint _39; + InterlockedAdd(img2[int2(0, 0)], 1u, _39); + _42.Store(0, uint(int(_42.Load(0)) + 42)); + uint _55; + _42.InterlockedAnd(4, _52.Load(0), _55); +} + +void main() +{ + frag_main(); +} diff --git a/third_party/spirv-cross/reference/shaders-hlsl/frag/readonly-coherent-ssbo.force-uav.frag b/third_party/spirv-cross/reference/shaders-hlsl/frag/readonly-coherent-ssbo.force-uav.frag new file mode 100644 index 0000000000..bbe3e4a7d3 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-hlsl/frag/readonly-coherent-ssbo.force-uav.frag @@ -0,0 +1,21 @@ +globallycoherent RWByteAddressBuffer _12 : register(u0); + +static float4 FragColor; + +struct SPIRV_Cross_Output +{ + float4 FragColor : SV_Target0; +}; + +void frag_main() +{ + FragColor = asfloat(_12.Load4(0)); +} + +SPIRV_Cross_Output main() +{ + frag_main(); + SPIRV_Cross_Output stage_output; + stage_output.FragColor = FragColor; + return stage_output; +} diff --git a/third_party/spirv-cross/reference/shaders-hlsl/frag/readonly-coherent-ssbo.frag b/third_party/spirv-cross/reference/shaders-hlsl/frag/readonly-coherent-ssbo.frag new file mode 100644 index 0000000000..02252f9cbc --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-hlsl/frag/readonly-coherent-ssbo.frag @@ -0,0 +1,21 @@ +ByteAddressBuffer _12 : register(t0); + +static float4 FragColor; + +struct SPIRV_Cross_Output +{ + float4 FragColor : SV_Target0; +}; + +void frag_main() +{ + FragColor = asfloat(_12.Load4(0)); +} + +SPIRV_Cross_Output main() +{ + frag_main(); + SPIRV_Cross_Output stage_output; + stage_output.FragColor = FragColor; + return stage_output; +} diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/comp/aliased-struct-divergent-member-name.asm.comp b/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/comp/aliased-struct-divergent-member-name.asm.comp new file mode 100644 index 0000000000..d24b9666fa --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/comp/aliased-struct-divergent-member-name.asm.comp @@ -0,0 +1,38 @@ +#include +#include + +using namespace metal; + +struct T +{ + float a; +}; + +struct T_1 +{ + float b; +}; + +struct SSBO1 +{ + T_1 foo[1]; +}; + +struct T_2 +{ + float c; + char _m0_final_padding[12]; +}; + +struct SSBO2 +{ + T_2 bar[1]; +}; + +kernel void main0(device SSBO1& _7 [[buffer(0)]], device SSBO2& _10 [[buffer(1)]]) +{ + T v = T{ 40.0 }; + _7.foo[10].b = v.a; + _10.bar[30].c = v.a; +} + diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/comp/bitfield-signed-operations.asm.comp b/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/comp/bitfield-signed-operations.asm.comp new file mode 100644 index 0000000000..8e198a94df --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/comp/bitfield-signed-operations.asm.comp @@ -0,0 +1,29 @@ +#include +#include + +using namespace metal; + +struct SSBO +{ + int4 ints; + uint4 uints; +}; + +kernel void main0(device SSBO& _3 [[buffer(0)]]) +{ + int4 _19 = _3.ints; + uint4 _20 = _3.uints; + _3.ints = popcount(_19); + _3.uints = uint4(popcount(_19)); + _3.ints = int4(popcount(_20)); + _3.uints = popcount(_20); + _3.ints = reverse_bits(_19); + _3.uints = reverse_bits(_20); + _3.ints = extract_bits(_19, uint(1), 11u); + _3.uints = uint4(extract_bits(int4(_20), 11u, uint(1))); + _3.ints = int4(extract_bits(uint4(_19), uint(1), 11u)); + _3.uints = extract_bits(_20, 11u, uint(1)); + _3.ints = insert_bits(_19, _19.wzyx, uint(1), 11u); + _3.uints = insert_bits(_20, _20.wzyx, 11u, uint(1)); +} + diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/comp/bitscan.asm.comp b/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/comp/bitscan.asm.comp index 1b9c4bd953..5634d9da69 100644 --- a/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/comp/bitscan.asm.comp +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/comp/bitscan.asm.comp @@ -13,14 +13,14 @@ struct SSBO // Implementation of the GLSL findLSB() function template -T spvFindLSB(T x) +inline T spvFindLSB(T x) { return select(ctz(x), T(-1), x == T(0)); } // Implementation of the signed GLSL findMSB() function template -T spvFindSMSB(T x) +inline T spvFindSMSB(T x) { T v = select(x, T(-1) - x, x < T(0)); return select(clz(T(0)) - (clz(v) + T(1)), T(-1), v == T(0)); @@ -28,7 +28,7 @@ T spvFindSMSB(T x) // Implementation of the unsigned GLSL findMSB() function template -T spvFindUMSB(T x) +inline T spvFindUMSB(T x) { return select(clz(T(0)) - (clz(x) + T(1)), T(-1), x == T(0)); } diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/comp/copy-logical-2.spv14.asm.comp b/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/comp/copy-logical-2.spv14.asm.comp new file mode 100644 index 0000000000..09a31d68a8 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/comp/copy-logical-2.spv14.asm.comp @@ -0,0 +1,60 @@ +#include +#include + +using namespace metal; + +struct _11 +{ + float2x2 _m0; +}; + +struct _12 +{ + float2x4 _m0; +}; + +struct B2 +{ + float4 elem2; +}; + +struct C +{ + float4 c; + B2 b2; + B2 b2_array[4]; + _12 _m3; +}; + +struct B1 +{ + float4 elem1; +}; + +struct A +{ + float4 a; + B1 b1; + B1 b1_array[4]; + _11 _m3; +}; + +struct _8 +{ + A a_block; + C c_block; +}; + +kernel void main0(device _8& _3 [[buffer(0)]]) +{ + A _31; + _31.a = _3.c_block.c; + _31.b1.elem1 = _3.c_block.b2.elem2; + _31.b1_array[0].elem1 = _3.c_block.b2_array[0].elem2; + _31.b1_array[1].elem1 = _3.c_block.b2_array[1].elem2; + _31.b1_array[2].elem1 = _3.c_block.b2_array[2].elem2; + _31.b1_array[3].elem1 = _3.c_block.b2_array[3].elem2; + _31._m3._m0 = transpose(float2x2(_3.c_block._m3._m0[0].xy, _3.c_block._m3._m0[1].xy)); + _3.a_block = _31; +} + diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/comp/copy-logical.spv14.asm.comp b/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/comp/copy-logical.spv14.asm.comp new file mode 100644 index 0000000000..2225981524 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/comp/copy-logical.spv14.asm.comp @@ -0,0 +1,47 @@ +#include +#include + +using namespace metal; + +struct B2 +{ + float4 elem2; +}; + +struct C +{ + float4 c; + B2 b2; + B2 b2_array[4]; +}; + +struct B1 +{ + float4 elem1; +}; + +struct A +{ + float4 a; + B1 b1; + B1 b1_array[4]; +}; + +struct _8 +{ + A a_block; + C c_block; +}; + +kernel void main0(device _8& _3 [[buffer(0)]]) +{ + A _27; + _27.a = _3.c_block.c; + _27.b1.elem1 = _3.c_block.b2.elem2; + _27.b1_array[0].elem1 = _3.c_block.b2_array[0].elem2; + _27.b1_array[1].elem1 = _3.c_block.b2_array[1].elem2; + _27.b1_array[2].elem1 = _3.c_block.b2_array[2].elem2; + _27.b1_array[3].elem1 = _3.c_block.b2_array[3].elem2; + _3.a_block = _27; +} + diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/comp/glsl-signed-operations.asm.comp b/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/comp/glsl-signed-operations.asm.comp index 0376bc4fb2..7de0020ca1 100644 --- a/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/comp/glsl-signed-operations.asm.comp +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/comp/glsl-signed-operations.asm.comp @@ -13,7 +13,7 @@ struct SSBO // Implementation of the signed GLSL findMSB() function template -T spvFindSMSB(T x) +inline T spvFindSMSB(T x) { T v = select(x, T(-1) - x, x < T(0)); return select(clz(T(0)) - (clz(v) + T(1)), T(-1), v == T(0)); @@ -21,14 +21,14 @@ T spvFindSMSB(T x) // Implementation of the unsigned GLSL findMSB() function template -T spvFindUMSB(T x) +inline T spvFindUMSB(T x) { return select(clz(T(0)) - (clz(x) + T(1)), T(-1), x == T(0)); } // Implementation of the GLSL sign() function for integer types template::value>::type> -T sign(T x) +inline T sign(T x) { return select(select(select(x, T(0), x == T(0)), T(1), x > T(0)), T(-1), x < T(0)); } diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/asm/comp/storage-buffer-basic.invalid.asm.comp b/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/comp/storage-buffer-basic.invalid.asm.comp similarity index 100% rename from third_party/spirv-cross/reference/opt/shaders-msl/asm/comp/storage-buffer-basic.invalid.asm.comp rename to third_party/spirv-cross/reference/shaders-msl-no-opt/asm/comp/storage-buffer-basic.invalid.asm.comp diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/comp/storage-buffer-pointer-argument.asm.comp b/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/comp/storage-buffer-pointer-argument.asm.comp index ec40c6afc1..6e9768540b 100644 --- a/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/comp/storage-buffer-pointer-argument.asm.comp +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/comp/storage-buffer-pointer-argument.asm.comp @@ -15,6 +15,7 @@ struct SSBORead float b; }; +static inline __attribute__((always_inline)) void copy_out(device float& A, device const float& B) { A = B; diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/comp/variable-pointers.asm.comp b/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/comp/variable-pointers.asm.comp index 37731c720e..7c9718d1c9 100644 --- a/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/comp/variable-pointers.asm.comp +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/comp/variable-pointers.asm.comp @@ -22,16 +22,19 @@ struct baz int e[128]; }; +static inline __attribute__((always_inline)) device int* select_buffer(device foo& buf, device baz& buf2, constant bar& cb) { return (cb.d != 0) ? &buf.a[0u] : &buf2.e[0u]; } +static inline __attribute__((always_inline)) device int* select_buffer_null(device foo& buf, constant bar& cb) { return (cb.d != 0) ? &buf.a[0u] : nullptr; } +static inline __attribute__((always_inline)) threadgroup int* select_tgsm(constant bar& cb, threadgroup int (&tgsm)[128]) { return (cb.d != 0) ? &tgsm[0u] : nullptr; diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/frag/empty-struct-in-struct.asm.frag b/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/frag/empty-struct-in-struct.asm.frag new file mode 100644 index 0000000000..fdf4a92b99 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/frag/empty-struct-in-struct.asm.frag @@ -0,0 +1,35 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" + +#include +#include + +using namespace metal; + +struct EmptyStructTest +{ +}; +struct EmptyStruct2Test +{ + EmptyStructTest _m0; +}; + +static inline __attribute__((always_inline)) +float GetValue(thread const EmptyStruct2Test& self) +{ + return 0.0; +} + +static inline __attribute__((always_inline)) +float GetValue_1(EmptyStruct2Test self) +{ + return 0.0; +} + +fragment void main0() +{ + EmptyStruct2Test emptyStruct; + float value = GetValue(emptyStruct); + value = GetValue_1(EmptyStruct2Test{ EmptyStructTest{ } }); + value = GetValue_1(EmptyStruct2Test{ { } }); +} + diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/frag/inliner-dominator-inside-loop.asm.frag b/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/frag/inliner-dominator-inside-loop.asm.frag deleted file mode 100644 index f63c9ab5cf..0000000000 --- a/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/frag/inliner-dominator-inside-loop.asm.frag +++ /dev/null @@ -1,235 +0,0 @@ -#include -#include - -using namespace metal; - -struct VertexOutput -{ - float4 HPosition; - float4 Uv_EdgeDistance1; - float4 UvStuds_EdgeDistance2; - float4 Color; - float4 LightPosition_Fog; - float4 View_Depth; - float4 Normal_SpecPower; - float3 Tangent; - float4 PosLightSpace_Reflectance; - float studIndex; -}; - -struct Surface -{ - float3 albedo; - float3 normal; - float specular; - float gloss; - float reflectance; - float opacity; -}; - -struct SurfaceInput -{ - float4 Color; - float2 Uv; - float2 UvStuds; -}; - -struct Globals -{ - float4x4 ViewProjection; - float4 ViewRight; - float4 ViewUp; - float4 ViewDir; - float3 CameraPosition; - float3 AmbientColor; - float3 Lamp0Color; - float3 Lamp0Dir; - float3 Lamp1Color; - float4 FogParams; - float3 FogColor; - float4 LightBorder; - float4 LightConfig0; - float4 LightConfig1; - float4 LightConfig2; - float4 LightConfig3; - float4 RefractionBias_FadeDistance_GlowFactor; - float4 OutlineBrightness_ShadowInfo; - float4 ShadowMatrix0; - float4 ShadowMatrix1; - float4 ShadowMatrix2; -}; - -struct CB0 -{ - Globals CB0; -}; - -struct Params -{ - float4 LqmatFarTilingFactor; -}; - -struct CB2 -{ - Params CB2; -}; - -constant VertexOutput _121 = {}; -constant SurfaceInput _122 = {}; -constant float2 _123 = {}; -constant float4 _124 = {}; -constant Surface _125 = {}; -constant float4 _192 = {}; -constant float4 _219 = {}; -constant float4 _297 = {}; - -struct main0_out -{ - float4 _entryPointOutput [[color(0)]]; -}; - -struct main0_in -{ - float4 IN_Uv_EdgeDistance1 [[user(locn0)]]; - float4 IN_UvStuds_EdgeDistance2 [[user(locn1)]]; - float4 IN_Color [[user(locn2)]]; - float4 IN_LightPosition_Fog [[user(locn3)]]; - float4 IN_View_Depth [[user(locn4)]]; - float4 IN_Normal_SpecPower [[user(locn5)]]; - float3 IN_Tangent [[user(locn6)]]; - float4 IN_PosLightSpace_Reflectance [[user(locn7)]]; - float IN_studIndex [[user(locn8)]]; -}; - -fragment main0_out main0(main0_in in [[stage_in]], constant CB0& _19 [[buffer(0)]], texture3d LightMapTexture [[texture(0)]], texture2d ShadowMapTexture [[texture(1)]], texturecube EnvironmentMapTexture [[texture(2)]], texture2d DiffuseMapTexture [[texture(3)]], texture2d NormalMapTexture [[texture(4)]], texture2d NormalDetailMapTexture [[texture(5)]], texture2d StudsMapTexture [[texture(6)]], texture2d SpecularMapTexture [[texture(7)]], sampler LightMapSampler [[sampler(0)]], sampler ShadowMapSampler [[sampler(1)]], sampler EnvironmentMapSampler [[sampler(2)]], sampler DiffuseMapSampler [[sampler(3)]], sampler NormalMapSampler [[sampler(4)]], sampler NormalDetailMapSampler [[sampler(5)]], sampler StudsMapSampler [[sampler(6)]], sampler SpecularMapSampler [[sampler(7)]], float4 gl_FragCoord [[position]]) -{ - main0_out out = {}; - VertexOutput _128 = _121; - _128.HPosition = gl_FragCoord; - VertexOutput _130 = _128; - _130.Uv_EdgeDistance1 = in.IN_Uv_EdgeDistance1; - VertexOutput _132 = _130; - _132.UvStuds_EdgeDistance2 = in.IN_UvStuds_EdgeDistance2; - VertexOutput _134 = _132; - _134.Color = in.IN_Color; - VertexOutput _136 = _134; - _136.LightPosition_Fog = in.IN_LightPosition_Fog; - VertexOutput _138 = _136; - _138.View_Depth = in.IN_View_Depth; - VertexOutput _140 = _138; - _140.Normal_SpecPower = in.IN_Normal_SpecPower; - VertexOutput _142 = _140; - _142.Tangent = in.IN_Tangent; - VertexOutput _144 = _142; - _144.PosLightSpace_Reflectance = in.IN_PosLightSpace_Reflectance; - VertexOutput _146 = _144; - _146.studIndex = in.IN_studIndex; - SurfaceInput _147 = _122; - _147.Color = in.IN_Color; - SurfaceInput _149 = _147; - _149.Uv = in.IN_Uv_EdgeDistance1.xy; - SurfaceInput _151 = _149; - _151.UvStuds = in.IN_UvStuds_EdgeDistance2.xy; - SurfaceInput _156 = _151; - _156.UvStuds.y = (fract(_151.UvStuds.y) + in.IN_studIndex) * 0.25; - float _163 = _146.View_Depth.w * _19.CB0.RefractionBias_FadeDistance_GlowFactor.y; - float _165 = fast::clamp(1.0 - _163, 0.0, 1.0); - float2 _166 = in.IN_Uv_EdgeDistance1.xy * 1.0; - bool _173; - float4 _193; - do - { - _173 = 0.0 == 0.0; - if (_173) - { - _193 = DiffuseMapTexture.sample(DiffuseMapSampler, _166); - break; - } - else - { - float _180 = 1.0 / (1.0 - 0.0); - _193 = mix(DiffuseMapTexture.sample(DiffuseMapSampler, (_166 * 0.25)), DiffuseMapTexture.sample(DiffuseMapSampler, _166), float4(fast::clamp((fast::clamp(1.0 - (_146.View_Depth.w * 0.00333332992158830165863037109375), 0.0, 1.0) * _180) - (0.0 * _180), 0.0, 1.0))); - break; - } - _193 = _192; - break; - } while (false); - float4 _220; - do - { - if (_173) - { - _220 = NormalMapTexture.sample(NormalMapSampler, _166); - break; - } - else - { - float _207 = 1.0 / (1.0 - 0.0); - _220 = mix(NormalMapTexture.sample(NormalMapSampler, (_166 * 0.25)), NormalMapTexture.sample(NormalMapSampler, _166), float4(fast::clamp((_165 * _207) - (0.0 * _207), 0.0, 1.0))); - break; - } - _220 = _219; - break; - } while (false); - float2 _223 = float2(1.0); - float2 _224 = (_220.wy * 2.0) - _223; - float3 _232 = float3(_224, sqrt(fast::clamp(1.0 + dot(-_224, _224), 0.0, 1.0))); - float2 _240 = (NormalDetailMapTexture.sample(NormalDetailMapSampler, (_166 * 0.0)).wy * 2.0) - _223; - float2 _252 = _232.xy + (float3(_240, sqrt(fast::clamp(1.0 + dot(-_240, _240), 0.0, 1.0))).xy * 0.0); - float3 _253 = float3(_252.x, _252.y, _232.z); - float2 _255 = _253.xy * _165; - float3 _256 = float3(_255.x, _255.y, _253.z); - float3 _271 = ((in.IN_Color.xyz * (_193 * 1.0).xyz) * (1.0 + (_256.x * 0.300000011920928955078125))) * (StudsMapTexture.sample(StudsMapSampler, _156.UvStuds).x * 2.0); - float4 _298; - do - { - if (0.75 == 0.0) - { - _298 = SpecularMapTexture.sample(SpecularMapSampler, _166); - break; - } - else - { - float _285 = 1.0 / (1.0 - 0.75); - _298 = mix(SpecularMapTexture.sample(SpecularMapSampler, (_166 * 0.25)), SpecularMapTexture.sample(SpecularMapSampler, _166), float4(fast::clamp((_165 * _285) - (0.75 * _285), 0.0, 1.0))); - break; - } - _298 = _297; - break; - } while (false); - float2 _303 = mix(float2(0.800000011920928955078125, 120.0), (_298.xy * float2(2.0, 256.0)) + float2(0.0, 0.00999999977648258209228515625), float2(_165)); - Surface _304 = _125; - _304.albedo = _271; - Surface _305 = _304; - _305.normal = _256; - float _306 = _303.x; - Surface _307 = _305; - _307.specular = _306; - float _308 = _303.y; - Surface _309 = _307; - _309.gloss = _308; - float _312 = (_298.xy.y * _165) * 0.0; - Surface _313 = _309; - _313.reflectance = _312; - float4 _318 = float4(_271, _146.Color.w); - float3 _329 = normalize(((in.IN_Tangent * _313.normal.x) + (cross(in.IN_Normal_SpecPower.xyz, in.IN_Tangent) * _313.normal.y)) + (in.IN_Normal_SpecPower.xyz * _313.normal.z)); - float3 _332 = -_19.CB0.Lamp0Dir; - float _333 = dot(_329, _332); - float _357 = fast::clamp(dot(step(_19.CB0.LightConfig3.xyz, abs(in.IN_LightPosition_Fog.xyz - _19.CB0.LightConfig2.xyz)), float3(1.0)), 0.0, 1.0); - float4 _368 = mix(LightMapTexture.sample(LightMapSampler, (in.IN_LightPosition_Fog.xyz.yzx - (in.IN_LightPosition_Fog.xyz.yzx * _357))), _19.CB0.LightBorder, float4(_357)); - float2 _376 = ShadowMapTexture.sample(ShadowMapSampler, in.IN_PosLightSpace_Reflectance.xyz.xy).xy; - float _392 = (1.0 - (((step(_376.x, in.IN_PosLightSpace_Reflectance.xyz.z) * fast::clamp(9.0 - (20.0 * abs(in.IN_PosLightSpace_Reflectance.xyz.z - 0.5)), 0.0, 1.0)) * _376.y) * _19.CB0.OutlineBrightness_ShadowInfo.w)) * _368.w; - float3 _403 = mix(_318.xyz, EnvironmentMapTexture.sample(EnvironmentMapSampler, reflect(-in.IN_View_Depth.xyz, _329)).xyz, float3(_312)); - float4 _404 = float4(_403.x, _403.y, _403.z, _318.w); - float3 _422 = (((_19.CB0.AmbientColor + (((_19.CB0.Lamp0Color * fast::clamp(_333, 0.0, 1.0)) + (_19.CB0.Lamp1Color * fast::max(-_333, 0.0))) * _392)) + _368.xyz) * _404.xyz) + (_19.CB0.Lamp0Color * (((step(0.0, _333) * _306) * _392) * pow(fast::clamp(dot(_329, normalize(_332 + normalize(in.IN_View_Depth.xyz))), 0.0, 1.0), _308))); - float4 _425 = float4(_422.x, _422.y, _422.z, _124.w); - _425.w = _404.w; - float2 _435 = fast::min(in.IN_Uv_EdgeDistance1.wz, in.IN_UvStuds_EdgeDistance2.wz); - float _439 = fast::min(_435.x, _435.y) / _163; - float3 _445 = _425.xyz * fast::clamp((fast::clamp((_163 * _19.CB0.OutlineBrightness_ShadowInfo.x) + _19.CB0.OutlineBrightness_ShadowInfo.y, 0.0, 1.0) * (1.5 - _439)) + _439, 0.0, 1.0); - float4 _446 = float4(_445.x, _445.y, _445.z, _425.w); - float3 _453 = mix(_19.CB0.FogColor, _446.xyz, float3(fast::clamp(_146.LightPosition_Fog.w, 0.0, 1.0))); - out._entryPointOutput = float4(_453.x, _453.y, _453.z, _446.w); - return out; -} - diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/frag/modf-frexp-scalar-access-chain-output.asm.frag b/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/frag/modf-frexp-scalar-access-chain-output.asm.frag new file mode 100644 index 0000000000..910c8fa734 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/frag/modf-frexp-scalar-access-chain-output.asm.frag @@ -0,0 +1,17 @@ +#include +#include + +using namespace metal; + +fragment void main0() +{ + float3 col; + int2 _18; + float _23; + float _21 = modf(0.1500000059604644775390625, _23); + col.x = _23; + int _24; + float _22 = frexp(0.1500000059604644775390625, _24); + _18.y = _24; +} + diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/frag/pixel-interlock-callstack.msl2.asm.frag b/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/frag/pixel-interlock-callstack.msl2.asm.frag new file mode 100644 index 0000000000..8ceb9f43e7 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/frag/pixel-interlock-callstack.msl2.asm.frag @@ -0,0 +1,37 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" + +#include +#include + +using namespace metal; + +struct SSBO1 +{ + uint values1[1]; +}; + +struct SSBO0 +{ + uint values0[1]; +}; + +static inline __attribute__((always_inline)) +void callee2(thread float4& gl_FragCoord, device SSBO1& v_7) +{ + int _31 = int(gl_FragCoord.x); + v_7.values1[_31]++; +} + +static inline __attribute__((always_inline)) +void callee(thread float4& gl_FragCoord, device SSBO1& v_7, device SSBO0& v_9) +{ + int _39 = int(gl_FragCoord.x); + v_9.values0[_39]++; + callee2(gl_FragCoord, v_7); +} + +fragment void main0(device SSBO1& v_7 [[buffer(0), raster_order_group(0)]], device SSBO0& v_9 [[buffer(1)]], float4 gl_FragCoord [[position]]) +{ + callee(gl_FragCoord, v_7, v_9); +} + diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/frag/pixel-interlock-control-flow.msl2.asm.frag b/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/frag/pixel-interlock-control-flow.msl2.asm.frag new file mode 100644 index 0000000000..a382316391 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/frag/pixel-interlock-control-flow.msl2.asm.frag @@ -0,0 +1,52 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" + +#include +#include + +using namespace metal; + +struct SSBO1 +{ + uint values1[1]; +}; + +struct _12 +{ + uint _m0[1]; +}; + +struct SSBO0 +{ + uint values0[1]; +}; + +static inline __attribute__((always_inline)) +void callee2(thread float4& gl_FragCoord, device SSBO1& v_7) +{ + int _44 = int(gl_FragCoord.x); + v_7.values1[_44]++; +} + +static inline __attribute__((always_inline)) +void callee(thread float4& gl_FragCoord, device SSBO1& v_7, device SSBO0& v_9) +{ + int _52 = int(gl_FragCoord.x); + v_9.values0[_52]++; + callee2(gl_FragCoord, v_7); + if (true) + { + } +} + +static inline __attribute__((always_inline)) +void _35(thread float4& gl_FragCoord, device _12& v_13) +{ + v_13._m0[int(gl_FragCoord.x)] = 4u; +} + +fragment void main0(device SSBO1& v_7 [[buffer(0), raster_order_group(0)]], device _12& v_13 [[buffer(1)]], device SSBO0& v_9 [[buffer(2), raster_order_group(0)]], float4 gl_FragCoord [[position]]) +{ + callee(gl_FragCoord, v_7, v_9); + _35(gl_FragCoord, v_13); +} + diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/frag/pixel-interlock-split-functions.msl2.asm.frag b/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/frag/pixel-interlock-split-functions.msl2.asm.frag new file mode 100644 index 0000000000..beb21241f4 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/frag/pixel-interlock-split-functions.msl2.asm.frag @@ -0,0 +1,49 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" + +#include +#include + +using namespace metal; + +struct SSBO1 +{ + uint values1[1]; +}; + +struct SSBO0 +{ + uint values0[1]; +}; + +static inline __attribute__((always_inline)) +void callee2(thread float4& gl_FragCoord, device SSBO1& v_7) +{ + int _37 = int(gl_FragCoord.x); + v_7.values1[_37]++; +} + +static inline __attribute__((always_inline)) +void callee(thread float4& gl_FragCoord, device SSBO1& v_7, device SSBO0& v_9) +{ + int _45 = int(gl_FragCoord.x); + v_9.values0[_45]++; + callee2(gl_FragCoord, v_7); +} + +static inline __attribute__((always_inline)) +void _29() +{ +} + +static inline __attribute__((always_inline)) +void _31() +{ +} + +fragment void main0(device SSBO1& v_7 [[buffer(0), raster_order_group(0)]], device SSBO0& v_9 [[buffer(1), raster_order_group(0)]], float4 gl_FragCoord [[position]]) +{ + callee(gl_FragCoord, v_7, v_9); + _29(); + _31(); +} + diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/frag/subgroup-arithmetic-cast.msl21.asm.frag b/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/frag/subgroup-arithmetic-cast.msl21.asm.frag new file mode 100644 index 0000000000..2f5cd66284 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/frag/subgroup-arithmetic-cast.msl21.asm.frag @@ -0,0 +1,30 @@ +#include +#include + +using namespace metal; + +struct main0_out +{ + uint FragColor [[color(0)]]; +}; + +struct main0_in +{ + int index [[user(locn0)]]; +}; + +fragment main0_out main0(main0_in in [[stage_in]]) +{ + main0_out out = {}; + uint _17 = uint(in.index); + out.FragColor = uint(simd_min(in.index)); + out.FragColor = uint(simd_max(int(_17))); + out.FragColor = simd_min(uint(in.index)); + out.FragColor = simd_max(_17); + out.FragColor = uint(quad_min(in.index)); + out.FragColor = uint(quad_max(int(_17))); + out.FragColor = quad_min(uint(in.index)); + out.FragColor = quad_max(_17); + return out; +} + diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/frag/switch-block-case-fallthrough.asm.frag b/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/frag/switch-block-case-fallthrough.asm.invalid.frag similarity index 100% rename from third_party/spirv-cross/reference/shaders-msl-no-opt/asm/frag/switch-block-case-fallthrough.asm.frag rename to third_party/spirv-cross/reference/shaders-msl-no-opt/asm/frag/switch-block-case-fallthrough.asm.invalid.frag diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/frag/texture-access.swizzle.asm.frag b/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/frag/texture-access.swizzle.asm.frag index fce6757b45..9d71a91e43 100644 --- a/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/frag/texture-access.swizzle.asm.frag +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/frag/texture-access.swizzle.asm.frag @@ -6,22 +6,12 @@ using namespace metal; // Returns 2D texture coords corresponding to 1D texel buffer coords +static inline __attribute__((always_inline)) uint2 spvTexelBufferCoord(uint tc) { return uint2(tc % 4096, tc / 4096); } -enum class spvSwizzle : uint -{ - none = 0, - zero, - one, - red, - green, - blue, - alpha -}; - template struct spvRemoveReference { typedef T type; }; template struct spvRemoveReference { typedef T type; }; template struct spvRemoveReference { typedef T type; }; @@ -34,6 +24,17 @@ template inline constexpr thread T&& spvForward(thread typename spvR return static_cast(x); } +enum class spvSwizzle : uint +{ + none = 0, + zero, + one, + red, + green, + blue, + alpha +}; + template inline T spvGetSwizzle(vec x, T c, spvSwizzle s) { @@ -72,8 +73,8 @@ inline T spvTextureSwizzle(T x, uint s) } // Wrapper function that swizzles texture gathers. -template -inline vec spvGatherSwizzle(sampler s, const thread Tex& t, Ts... params, component c, uint sw) METAL_CONST_ARG(c) +template class Tex, typename... Ts> +inline vec spvGatherSwizzle(const thread Tex& t, sampler s, uint sw, component c, Ts... params) METAL_CONST_ARG(c) { if (sw) { @@ -109,8 +110,8 @@ inline vec spvGatherSwizzle(sampler s, const thread Tex& t, Ts... params, } // Wrapper function that swizzles depth texture gathers. -template -inline vec spvGatherCompareSwizzle(sampler s, const thread Tex& t, Ts... params, uint sw) +template class Tex, typename... Ts> +inline vec spvGatherCompareSwizzle(const thread Tex& t, sampler s, uint sw, Ts... params) { if (sw) { @@ -177,13 +178,13 @@ fragment void main0(constant uint* spvSwizzleConstants [[buffer(30)]], texture1d c = spvTextureSwizzle(tex3d.read(uint3(int3(0)), 0), tex3dSwzl); c = spvTextureSwizzle(tex2dArray.read(uint2(int3(0).xy), uint(int3(0).z), 0), tex2dArraySwzl); c = texBuffer.read(spvTexelBufferCoord(0)); - c = spvGatherSwizzle, float2, int2>(tex2dSamp, tex2d, float2(0.0), int2(0), component::x, tex2dSwzl); - c = spvGatherSwizzle, float3>(texCubeSamp, texCube, float3(0.0), component::y, texCubeSwzl); - c = spvGatherSwizzle, float2, uint, int2>(tex2dArraySamp, tex2dArray, float3(0.0).xy, uint(round(float3(0.0).z)), int2(0), component::z, tex2dArraySwzl); - c = spvGatherSwizzle, float3, uint>(texCubeArraySamp, texCubeArray, float4(0.0).xyz, uint(round(float4(0.0).w)), component::w, texCubeArraySwzl); - c = spvGatherCompareSwizzle, float2, float>(depth2dSamp, depth2d, float2(0.0), 1.0, depth2dSwzl); - c = spvGatherCompareSwizzle, float3, float>(depthCubeSamp, depthCube, float3(0.0), 1.0, depthCubeSwzl); - c = spvGatherCompareSwizzle, float2, uint, float>(depth2dArraySamp, depth2dArray, float3(0.0).xy, uint(round(float3(0.0).z)), 1.0, depth2dArraySwzl); - c = spvGatherCompareSwizzle, float3, uint, float>(depthCubeArraySamp, depthCubeArray, float4(0.0).xyz, uint(round(float4(0.0).w)), 1.0, depthCubeArraySwzl); + c = spvGatherSwizzle(tex2d, tex2dSamp, tex2dSwzl, component::x, float2(0.0), int2(0)); + c = spvGatherSwizzle(texCube, texCubeSamp, texCubeSwzl, component::y, float3(0.0)); + c = spvGatherSwizzle(tex2dArray, tex2dArraySamp, tex2dArraySwzl, component::z, float3(0.0).xy, uint(round(float3(0.0).z)), int2(0)); + c = spvGatherSwizzle(texCubeArray, texCubeArraySamp, texCubeArraySwzl, component::w, float4(0.0).xyz, uint(round(float4(0.0).w))); + c = spvGatherCompareSwizzle(depth2d, depth2dSamp, depth2dSwzl, float2(0.0), 1.0); + c = spvGatherCompareSwizzle(depthCube, depthCubeSamp, depthCubeSwzl, float3(0.0), 1.0); + c = spvGatherCompareSwizzle(depth2dArray, depth2dArraySamp, depth2dArraySwzl, float3(0.0).xy, uint(round(float3(0.0).z)), 1.0); + c = spvGatherCompareSwizzle(depthCubeArray, depthCubeArraySamp, depthCubeArraySwzl, float4(0.0).xyz, uint(round(float4(0.0).w)), 1.0); } diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/packing/composite-extract-row-major.asm.comp b/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/packing/composite-extract-row-major.asm.comp index a2d2acbb1a..d2c368b8ed 100644 --- a/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/packing/composite-extract-row-major.asm.comp +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/packing/composite-extract-row-major.asm.comp @@ -11,6 +11,6 @@ struct SSBORow kernel void main0(device SSBORow& _4 [[buffer(0)]]) { - _4.v = float4(_4.row_major0[0][1], _4.row_major0[1][1], _4.row_major0[2][1], _4.row_major0[3][1])[2]; + _4.v = _4.row_major0[2][1]; } diff --git a/third_party/spirv-cross/reference/shaders-msl/asm/tesc/tess-fixed-input-array-builtin-array.invalid.asm.tesc b/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/tesc/tess-fixed-input-array-builtin-array.invalid.asm.tesc similarity index 63% rename from third_party/spirv-cross/reference/shaders-msl/asm/tesc/tess-fixed-input-array-builtin-array.invalid.asm.tesc rename to third_party/spirv-cross/reference/shaders-msl-no-opt/asm/tesc/tess-fixed-input-array-builtin-array.invalid.asm.tesc index 6a765117e4..2c83e9e420 100644 --- a/third_party/spirv-cross/reference/shaders-msl/asm/tesc/tess-fixed-input-array-builtin-array.invalid.asm.tesc +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/tesc/tess-fixed-input-array-builtin-array.invalid.asm.tesc @@ -1,10 +1,49 @@ #pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" #include #include using namespace metal; +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + struct VertexOutput { float4 pos; @@ -19,7 +58,7 @@ struct HSOut struct HSConstantOut { - float EdgeTess[3]; + spvUnsafeArray EdgeTess; float InsideTess; }; @@ -45,20 +84,8 @@ struct main0_in float4 gl_Position [[attribute(1)]]; }; -// Implementation of an array copy function to cover GLSL's ability to copy an array via assignment. -template -void spvArrayCopyFromStack1(thread T (&dst)[N], thread const T (&src)[N]) -{ - for (uint i = 0; i < N; dst[i] = src[i], i++); -} - -template -void spvArrayCopyFromConstant1(thread T (&dst)[N], constant T (&src)[N]) -{ - for (uint i = 0; i < N; dst[i] = src[i], i++); -} - -HSOut _hs_main(thread const VertexOutput (&p)[3], thread const uint& i) +static inline __attribute__((always_inline)) +HSOut _hs_main(thread const spvUnsafeArray (&p), thread const uint& i) { HSOut _output; _output.pos = p[i].pos; @@ -66,7 +93,8 @@ HSOut _hs_main(thread const VertexOutput (&p)[3], thread const uint& i) return _output; } -HSConstantOut PatchHS(thread const VertexOutput (&_patch)[3]) +static inline __attribute__((always_inline)) +HSConstantOut PatchHS(thread const spvUnsafeArray (&_patch)) { HSConstantOut _output; _output.EdgeTess[0] = (float2(1.0) + _patch[0].uv).x; @@ -84,7 +112,7 @@ kernel void main0(main0_in in [[stage_in]], uint gl_InvocationID [[thread_index_ threadgroup_barrier(mem_flags::mem_threadgroup); if (gl_InvocationID >= 3) return; - VertexOutput p[3]; + spvUnsafeArray p; p[0].pos = gl_in[0].gl_Position; p[0].uv = gl_in[0].VertexOutput_uv; p[1].pos = gl_in[1].gl_Position; @@ -92,17 +120,17 @@ kernel void main0(main0_in in [[stage_in]], uint gl_InvocationID [[thread_index_ p[2].pos = gl_in[2].gl_Position; p[2].uv = gl_in[2].VertexOutput_uv; uint i = gl_InvocationID; - VertexOutput param[3]; - spvArrayCopyFromStack1(param, p); + spvUnsafeArray param; + param = p; uint param_1 = i; HSOut flattenTemp = _hs_main(param, param_1); gl_out[gl_InvocationID].gl_Position = flattenTemp.pos; gl_out[gl_InvocationID]._entryPointOutput.uv = flattenTemp.uv; - threadgroup_barrier(mem_flags::mem_device); + threadgroup_barrier(mem_flags::mem_device | mem_flags::mem_threadgroup); if (int(gl_InvocationID) == 0) { - VertexOutput param_2[3]; - spvArrayCopyFromStack1(param_2, p); + spvUnsafeArray param_2; + param_2 = p; HSConstantOut _patchConstantResult = PatchHS(param_2); spvTessLevel[gl_PrimitiveID].edgeTessellationFactor[0] = half(_patchConstantResult.EdgeTess[0]); spvTessLevel[gl_PrimitiveID].edgeTessellationFactor[1] = half(_patchConstantResult.EdgeTess[1]); diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/vert/empty-struct-composite.asm.vert b/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/vert/empty-struct-composite.asm.vert index e9cd6a540a..95b61a40db 100644 --- a/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/vert/empty-struct-composite.asm.vert +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/vert/empty-struct-composite.asm.vert @@ -5,12 +5,9 @@ using namespace metal; struct Test { - int empty_struct_member; }; - vertex void main0() { - Test _14 = Test{ 0 }; - Test t = _14; + Test t = Test{ }; } diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/vert/op-load-forced-temporary-array.asm.frag b/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/vert/op-load-forced-temporary-array.asm.frag index 47e4fe7160..18d98993e5 100644 --- a/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/vert/op-load-forced-temporary-array.asm.frag +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/asm/vert/op-load-forced-temporary-array.asm.frag @@ -1,8 +1,49 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + #include #include using namespace metal; +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + constant float _21 = {}; struct main0_out @@ -13,7 +54,7 @@ struct main0_out vertex main0_out main0() { main0_out out = {}; - float _23[2]; + spvUnsafeArray _23; for (int _25 = 0; _25 < 2; ) { _23[_25] = 0.0; diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/comp/array-copy-threadgroup-memory.comp b/third_party/spirv-cross/reference/shaders-msl-no-opt/comp/array-copy-threadgroup-memory.comp new file mode 100644 index 0000000000..24ae08e7bb --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/comp/array-copy-threadgroup-memory.comp @@ -0,0 +1,118 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + +#include +#include + +using namespace metal; + +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(8u, 1u, 1u); + +template +inline void spvArrayCopyFromConstantToStack1(thread T (&dst)[A], constant T (&src)[A]) +{ + for (uint i = 0; i < A; i++) + { + dst[i] = src[i]; + } +} + +template +inline void spvArrayCopyFromConstantToThreadGroup1(threadgroup T (&dst)[A], constant T (&src)[A]) +{ + for (uint i = 0; i < A; i++) + { + dst[i] = src[i]; + } +} + +template +inline void spvArrayCopyFromStackToStack1(thread T (&dst)[A], thread const T (&src)[A]) +{ + for (uint i = 0; i < A; i++) + { + dst[i] = src[i]; + } +} + +template +inline void spvArrayCopyFromStackToThreadGroup1(threadgroup T (&dst)[A], thread const T (&src)[A]) +{ + for (uint i = 0; i < A; i++) + { + dst[i] = src[i]; + } +} + +template +inline void spvArrayCopyFromThreadGroupToStack1(thread T (&dst)[A], threadgroup const T (&src)[A]) +{ + for (uint i = 0; i < A; i++) + { + dst[i] = src[i]; + } +} + +template +inline void spvArrayCopyFromThreadGroupToThreadGroup1(threadgroup T (&dst)[A], threadgroup const T (&src)[A]) +{ + for (uint i = 0; i < A; i++) + { + dst[i] = src[i]; + } +} + +kernel void main0(uint gl_LocalInvocationIndex [[thread_index_in_threadgroup]]) +{ + threadgroup float shared_group[8][8]; + threadgroup float shared_group_alt[8][8]; + spvUnsafeArray blob; + for (int i = 0; i < 8; i++) + { + blob[i] = float(i); + } + spvArrayCopyFromStackToThreadGroup1(shared_group[gl_LocalInvocationIndex], blob.elements); + threadgroup_barrier(mem_flags::mem_threadgroup); + spvUnsafeArray copied_blob; + spvArrayCopyFromThreadGroupToStack1(copied_blob.elements, shared_group[gl_LocalInvocationIndex ^ 1u]); + spvArrayCopyFromThreadGroupToThreadGroup1(shared_group_alt[gl_LocalInvocationIndex], shared_group[gl_LocalInvocationIndex]); +} + diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/comp/basic.dynamic-buffer.msl2.invalid.comp b/third_party/spirv-cross/reference/shaders-msl-no-opt/comp/basic.dynamic-buffer.msl2.invalid.comp new file mode 100644 index 0000000000..ae8c5b0295 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/comp/basic.dynamic-buffer.msl2.invalid.comp @@ -0,0 +1,90 @@ +#include +#include + +using namespace metal; + +struct Baz +{ + int e; + int f; +}; + +struct Foo +{ + int a; + int b; +}; + +struct Bar +{ + int c; + int d; +}; + +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(3u, 3u, 2u); + +struct spvDescriptorSetBuffer0 +{ + constant Foo* m_34 [[id(0)]]; + constant Bar* m_40 [[id(1)]]; +}; + +struct spvDescriptorSetBuffer1 +{ + device Baz* baz [[id(0)]][3][3][2]; +}; + +kernel void main0(constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]], constant spvDescriptorSetBuffer1& spvDescriptorSet1 [[buffer(1)]], constant uint* spvDynamicOffsets [[buffer(23)]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]]) +{ + constant auto& _34 = *(constant Foo* )((constant char* )spvDescriptorSet0.m_34 + spvDynamicOffsets[0]); + device Baz* baz[3][3][2] = + { + { + { + (device Baz* )((device char* )spvDescriptorSet1.baz[0][0][0] + spvDynamicOffsets[1]), + (device Baz* )((device char* )spvDescriptorSet1.baz[0][0][1] + spvDynamicOffsets[2]), + }, + { + (device Baz* )((device char* )spvDescriptorSet1.baz[0][1][0] + spvDynamicOffsets[3]), + (device Baz* )((device char* )spvDescriptorSet1.baz[0][1][1] + spvDynamicOffsets[4]), + }, + { + (device Baz* )((device char* )spvDescriptorSet1.baz[0][2][0] + spvDynamicOffsets[5]), + (device Baz* )((device char* )spvDescriptorSet1.baz[0][2][1] + spvDynamicOffsets[6]), + }, + }, + { + { + (device Baz* )((device char* )spvDescriptorSet1.baz[1][0][0] + spvDynamicOffsets[7]), + (device Baz* )((device char* )spvDescriptorSet1.baz[1][0][1] + spvDynamicOffsets[8]), + }, + { + (device Baz* )((device char* )spvDescriptorSet1.baz[1][1][0] + spvDynamicOffsets[9]), + (device Baz* )((device char* )spvDescriptorSet1.baz[1][1][1] + spvDynamicOffsets[10]), + }, + { + (device Baz* )((device char* )spvDescriptorSet1.baz[1][2][0] + spvDynamicOffsets[11]), + (device Baz* )((device char* )spvDescriptorSet1.baz[1][2][1] + spvDynamicOffsets[12]), + }, + }, + { + { + (device Baz* )((device char* )spvDescriptorSet1.baz[2][0][0] + spvDynamicOffsets[13]), + (device Baz* )((device char* )spvDescriptorSet1.baz[2][0][1] + spvDynamicOffsets[14]), + }, + { + (device Baz* )((device char* )spvDescriptorSet1.baz[2][1][0] + spvDynamicOffsets[15]), + (device Baz* )((device char* )spvDescriptorSet1.baz[2][1][1] + spvDynamicOffsets[16]), + }, + { + (device Baz* )((device char* )spvDescriptorSet1.baz[2][2][0] + spvDynamicOffsets[17]), + (device Baz* )((device char* )spvDescriptorSet1.baz[2][2][1] + spvDynamicOffsets[18]), + }, + }, + }; + + uint3 coords = gl_GlobalInvocationID; + baz[coords.x][coords.y][coords.z]->e = _34.a + (*spvDescriptorSet0.m_40).c; + baz[coords.x][coords.y][coords.z]->f = _34.b * (*spvDescriptorSet0.m_40).d; +} + diff --git a/third_party/spirv-cross/reference/shaders-msl/comp/bitcast-16bit-1.invalid.comp b/third_party/spirv-cross/reference/shaders-msl-no-opt/comp/bitcast-16bit-1.invalid.comp similarity index 90% rename from third_party/spirv-cross/reference/shaders-msl/comp/bitcast-16bit-1.invalid.comp rename to third_party/spirv-cross/reference/shaders-msl-no-opt/comp/bitcast-16bit-1.invalid.comp index 170e4920e7..d231a02911 100644 --- a/third_party/spirv-cross/reference/shaders-msl/comp/bitcast-16bit-1.invalid.comp +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/comp/bitcast-16bit-1.invalid.comp @@ -13,6 +13,8 @@ struct SSBO1 int4 outputs[1]; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + kernel void main0(device SSBO0& _25 [[buffer(0)]], device SSBO1& _39 [[buffer(1)]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]]) { uint ident = gl_GlobalInvocationID.x; diff --git a/third_party/spirv-cross/reference/shaders-msl/comp/bitcast-16bit-2.invalid.comp b/third_party/spirv-cross/reference/shaders-msl-no-opt/comp/bitcast-16bit-2.invalid.comp similarity index 92% rename from third_party/spirv-cross/reference/shaders-msl/comp/bitcast-16bit-2.invalid.comp rename to third_party/spirv-cross/reference/shaders-msl-no-opt/comp/bitcast-16bit-2.invalid.comp index 59eb961f12..8db1c2f865 100644 --- a/third_party/spirv-cross/reference/shaders-msl/comp/bitcast-16bit-2.invalid.comp +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/comp/bitcast-16bit-2.invalid.comp @@ -18,6 +18,8 @@ struct UBO half4 const0; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + kernel void main0(device SSBO1& _21 [[buffer(0)]], device SSBO0& _29 [[buffer(1)]], constant UBO& _40 [[buffer(2)]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]]) { uint ident = gl_GlobalInvocationID.x; diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/comp/bitfield.comp b/third_party/spirv-cross/reference/shaders-msl-no-opt/comp/bitfield.comp index 6da1225ee7..7f797add16 100644 --- a/third_party/spirv-cross/reference/shaders-msl-no-opt/comp/bitfield.comp +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/comp/bitfield.comp @@ -7,14 +7,14 @@ using namespace metal; // Implementation of the GLSL findLSB() function template -T spvFindLSB(T x) +inline T spvFindLSB(T x) { return select(ctz(x), T(-1), x == T(0)); } // Implementation of the signed GLSL findMSB() function template -T spvFindSMSB(T x) +inline T spvFindSMSB(T x) { T v = select(x, T(-1) - x, x < T(0)); return select(clz(T(0)) - (clz(v) + T(1)), T(-1), v == T(0)); @@ -22,7 +22,7 @@ T spvFindSMSB(T x) // Implementation of the unsigned GLSL findMSB() function template -T spvFindUMSB(T x) +inline T spvFindUMSB(T x) { return select(clz(T(0)) - (clz(x) + T(1)), T(-1), x == T(0)); } @@ -31,13 +31,13 @@ kernel void main0() { int signed_value = 0; uint unsigned_value = 0u; - int s = extract_bits(signed_value, 5, 20); - uint u = extract_bits(unsigned_value, 6, 21); - s = insert_bits(s, 40, 5, 4); - u = insert_bits(u, 60u, 5, 4); + int s = extract_bits(signed_value, uint(5), uint(20)); + uint u = extract_bits(unsigned_value, uint(6), uint(21)); + s = insert_bits(s, 40, uint(5), uint(4)); + u = insert_bits(u, 60u, uint(5), uint(4)); u = reverse_bits(u); s = reverse_bits(s); - int v0 = popcount(u); + int v0 = int(popcount(u)); int v1 = popcount(s); int v2 = int(spvFindUMSB(u)); int v3 = spvFindSMSB(s); diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/comp/glsl.std450.comp b/third_party/spirv-cross/reference/shaders-msl-no-opt/comp/glsl.std450.comp index 47dd35d02d..e357c64c8d 100644 --- a/third_party/spirv-cross/reference/shaders-msl-no-opt/comp/glsl.std450.comp +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/comp/glsl.std450.comp @@ -24,30 +24,32 @@ struct ResType int _m1; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + // Implementation of the GLSL radians() function template -T radians(T d) +inline T radians(T d) { return d * T(0.01745329251); } // Implementation of the GLSL degrees() function template -T degrees(T r) +inline T degrees(T r) { return r * T(57.2957795131); } // Implementation of the GLSL findLSB() function template -T spvFindLSB(T x) +inline T spvFindLSB(T x) { return select(ctz(x), T(-1), x == T(0)); } // Implementation of the signed GLSL findMSB() function template -T spvFindSMSB(T x) +inline T spvFindSMSB(T x) { T v = select(x, T(-1) - x, x < T(0)); return select(clz(T(0)) - (clz(v) + T(1)), T(-1), v == T(0)); @@ -55,32 +57,35 @@ T spvFindSMSB(T x) // Implementation of the unsigned GLSL findMSB() function template -T spvFindUMSB(T x) +inline T spvFindUMSB(T x) { return select(clz(T(0)) - (clz(x) + T(1)), T(-1), x == T(0)); } // Implementation of the GLSL sign() function for integer types template::value>::type> -T sign(T x) +inline T sign(T x) { return select(select(select(x, T(0), x == T(0)), T(1), x > T(0)), T(-1), x < T(0)); } // Returns the determinant of a 2x2 matrix. -inline float spvDet2x2(float a1, float a2, float b1, float b2) +static inline __attribute__((always_inline)) +float spvDet2x2(float a1, float a2, float b1, float b2) { return a1 * b2 - b1 * a2; } // Returns the determinant of a 3x3 matrix. -inline float spvDet3x3(float a1, float a2, float a3, float b1, float b2, float b3, float c1, float c2, float c3) +static inline __attribute__((always_inline)) +float spvDet3x3(float a1, float a2, float a3, float b1, float b2, float b3, float c1, float c2, float c3) { return a1 * spvDet2x2(b2, b3, c2, c3) - b1 * spvDet2x2(a2, a3, c2, c3) + c1 * spvDet2x2(a2, a3, b2, b3); } // Returns the inverse of a matrix, by using the algorithm of calculating the classical // adjoint and dividing by the determinant. The contents of the matrix are changed. +static inline __attribute__((always_inline)) float4x4 spvInverse4x4(float4x4 m) { float4x4 adj; // The adjoint matrix (inverse after dividing by determinant) @@ -116,6 +121,7 @@ float4x4 spvInverse4x4(float4x4 m) // Returns the inverse of a matrix, by using the algorithm of calculating the classical // adjoint and dividing by the determinant. The contents of the matrix are changed. +static inline __attribute__((always_inline)) float3x3 spvInverse3x3(float3x3 m) { float3x3 adj; // The adjoint matrix (inverse after dividing by determinant) @@ -143,6 +149,7 @@ float3x3 spvInverse3x3(float3x3 m) // Returns the inverse of a matrix, by using the algorithm of calculating the classical // adjoint and dividing by the determinant. The contents of the matrix are changed. +static inline __attribute__((always_inline)) float2x2 spvInverse2x2(float2x2 m) { float2x2 adj; // The adjoint matrix (inverse after dividing by determinant) diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/comp/illegal-struct-name.asm.comp b/third_party/spirv-cross/reference/shaders-msl-no-opt/comp/illegal-struct-name.asm.comp new file mode 100644 index 0000000000..de1695b068 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/comp/illegal-struct-name.asm.comp @@ -0,0 +1,29 @@ +#include +#include + +using namespace metal; + +struct Foo +{ + float _abs; +}; + +struct Foo_1 +{ + float _abs; +}; + +struct SSBO +{ + Foo_1 foo; + Foo_1 foo2; +}; + +kernel void main0(device SSBO& _7 [[buffer(0)]]) +{ + Foo f; + f._abs = _7.foo._abs; + int _abs = 10; + _7.foo2._abs = f._abs; +} + diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/comp/int64.invalid.msl22.comp b/third_party/spirv-cross/reference/shaders-msl-no-opt/comp/int64.invalid.msl22.comp new file mode 100644 index 0000000000..d5bbbb47fc --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/comp/int64.invalid.msl22.comp @@ -0,0 +1,106 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + +#include +#include + +using namespace metal; + +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +struct M0 +{ + long v; + spvUnsafeArray b; + ulong c; + spvUnsafeArray d; +}; + +struct SSBO0_Type +{ + long4 a; + M0 m0; +}; + +struct SSBO1_Type +{ + ulong4 b; + M0 m0; +}; + +struct SSBO2_Type +{ + spvUnsafeArray a; + spvUnsafeArray b; +}; + +struct SSBO3_Type +{ + spvUnsafeArray a; + spvUnsafeArray b; +}; + +struct SSBO +{ + int s32; + uint u32; +}; + +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + +kernel void main0(device SSBO& _96 [[buffer(0)]]) +{ + SSBO0_Type ssbo_0; + ssbo_0.a += long4(10l, 20l, 30l, 40l); + SSBO1_Type ssbo_1; + ssbo_1.b += ulong4(999999999999999999ul, 8888888888888888ul, 77777777777777777ul, 6666666666666666ul); + ssbo_0.a += long4(20l); + ssbo_0.a = abs(ssbo_0.a + long4(ssbo_1.b)); + ssbo_0.a += long4(1l); + ssbo_1.b += ulong4(long4(1l)); + ssbo_0.a -= long4(1l); + ssbo_1.b -= ulong4(long4(1l)); + SSBO2_Type ssbo_2; + ssbo_2.a[0] += 1l; + SSBO3_Type ssbo_3; + ssbo_3.a[0] += 2l; + _96.s32 = int(uint(((ulong(ssbo_0.a.x) + ssbo_1.b.y) + ulong(ssbo_2.a[1])) + ulong(ssbo_3.a[2]))); + _96.u32 = uint(((ulong(ssbo_0.a.y) + ssbo_1.b.z) + ulong(ssbo_2.a[0])) + ulong(ssbo_3.a[1])); +} + diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/comp/loop.comp b/third_party/spirv-cross/reference/shaders-msl-no-opt/comp/loop.comp index 3e6c820a55..34fe64b0a2 100644 --- a/third_party/spirv-cross/reference/shaders-msl-no-opt/comp/loop.comp +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/comp/loop.comp @@ -14,7 +14,9 @@ struct SSBO2 float4 out_data[1]; }; -kernel void main0(const device SSBO& _24 [[buffer(0)]], device SSBO2& _177 [[buffer(1)]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]]) +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + +kernel void main0(const device SSBO& _24 [[buffer(0)]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]]) { uint ident = gl_GlobalInvocationID.x; float4 idat = _24.in_data[ident]; @@ -85,25 +87,5 @@ kernel void main0(const device SSBO& _24 [[buffer(0)]], device SSBO2& _177 [[buf k += 10; continue; } - k = 0; - do - { - k++; - } while (k > 10); - int l = 0; - for (;;) - { - if (l == 5) - { - int _172 = l; - l = _172 + 1; - continue; - } - idat += float4(1.0); - int _172 = l; - l = _172 + 1; - continue; - } - _177.out_data[ident] = idat; } diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/comp/return.comp b/third_party/spirv-cross/reference/shaders-msl-no-opt/comp/return.comp index 71fcfbe391..04cacea9d5 100644 --- a/third_party/spirv-cross/reference/shaders-msl-no-opt/comp/return.comp +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/comp/return.comp @@ -8,6 +8,8 @@ struct SSBO2 float4 out_data[1]; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + kernel void main0(device SSBO2& _27 [[buffer(0)]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]]) { uint ident = gl_GlobalInvocationID.x; @@ -23,7 +25,8 @@ kernel void main0(device SSBO2& _27 [[buffer(0)]], uint3 gl_GlobalInvocationID [ return; } } - for (int i = 0; i < 20; i++) + int i = 0; + while (i < 20) { if (i == 10) { diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/comp/std140-array-load-composite-construct.comp b/third_party/spirv-cross/reference/shaders-msl-no-opt/comp/std140-array-load-composite-construct.comp new file mode 100644 index 0000000000..ba278ccde7 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/comp/std140-array-load-composite-construct.comp @@ -0,0 +1,18 @@ +#include +#include + +using namespace metal; + +struct SSBO +{ + float4 a[16]; + float4 b[16]; +}; + +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + +kernel void main0(device SSBO& _14 [[buffer(0)]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]]) +{ + _14.b[gl_GlobalInvocationID.x] = float4(_14.a[gl_GlobalInvocationID.x].x); +} + diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/vulkan/comp/struct-packing-scalar.nocompat.invalid.vk.comp b/third_party/spirv-cross/reference/shaders-msl-no-opt/comp/struct-packing-scalar.nocompat.invalid.vk.comp similarity index 98% rename from third_party/spirv-cross/reference/opt/shaders-msl/vulkan/comp/struct-packing-scalar.nocompat.invalid.vk.comp rename to third_party/spirv-cross/reference/shaders-msl-no-opt/comp/struct-packing-scalar.nocompat.invalid.vk.comp index 2f731356f5..4f3412274d 100644 --- a/third_party/spirv-cross/reference/opt/shaders-msl/vulkan/comp/struct-packing-scalar.nocompat.invalid.vk.comp +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/comp/struct-packing-scalar.nocompat.invalid.vk.comp @@ -121,6 +121,8 @@ struct SSBO2 packed_rm_float3x2 m2; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + kernel void main0(device SSBO1& ssbo_scalar [[buffer(0)]], device SSBO0& ssbo_140 [[buffer(1)]], device SSBO2& ssbo_scalar2 [[buffer(2)]]) { ssbo_scalar.content.m0s[0].a[0] = ssbo_140.content.m0s[0].a[0].xy; diff --git a/third_party/spirv-cross/reference/shaders-msl/vulkan/comp/subgroups.nocompat.invalid.vk.msl21.comp b/third_party/spirv-cross/reference/shaders-msl-no-opt/comp/subgroups.nocompat.invalid.vk.msl21.comp similarity index 99% rename from third_party/spirv-cross/reference/shaders-msl/vulkan/comp/subgroups.nocompat.invalid.vk.msl21.comp rename to third_party/spirv-cross/reference/shaders-msl-no-opt/comp/subgroups.nocompat.invalid.vk.msl21.comp index 4ebab8c734..2fd7713177 100644 --- a/third_party/spirv-cross/reference/shaders-msl/vulkan/comp/subgroups.nocompat.invalid.vk.msl21.comp +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/comp/subgroups.nocompat.invalid.vk.msl21.comp @@ -10,6 +10,8 @@ struct SSBO float FragColor; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + inline uint4 spvSubgroupBallot(bool value) { simd_vote vote = simd_ballot(value); diff --git a/third_party/spirv-cross/reference/shaders-msl/vulkan/comp/subgroups.nocompat.invalid.vk.msl21.ios.comp b/third_party/spirv-cross/reference/shaders-msl-no-opt/comp/subgroups.nocompat.invalid.vk.msl21.ios.comp similarity index 95% rename from third_party/spirv-cross/reference/shaders-msl/vulkan/comp/subgroups.nocompat.invalid.vk.msl21.ios.comp rename to third_party/spirv-cross/reference/shaders-msl-no-opt/comp/subgroups.nocompat.invalid.vk.msl21.ios.comp index 84fcb9c3a9..5c67f6e402 100644 --- a/third_party/spirv-cross/reference/shaders-msl/vulkan/comp/subgroups.nocompat.invalid.vk.msl21.ios.comp +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/comp/subgroups.nocompat.invalid.vk.msl21.ios.comp @@ -8,6 +8,8 @@ struct SSBO float FragColor; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + kernel void main0(device SSBO& _9 [[buffer(0)]], uint gl_NumSubgroups [[quadgroups_per_threadgroup]], uint gl_SubgroupID [[quadgroup_index_in_threadgroup]], uint gl_SubgroupSize [[thread_execution_width]], uint gl_SubgroupInvocationID [[thread_index_in_quadgroup]]) { _9.FragColor = float(gl_NumSubgroups); diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/components/fragment-input-component.frag b/third_party/spirv-cross/reference/shaders-msl-no-opt/components/fragment-input-component.frag new file mode 100644 index 0000000000..9a65918a7d --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/components/fragment-input-component.frag @@ -0,0 +1,23 @@ +#include +#include + +using namespace metal; + +struct main0_out +{ + float4 FragColor [[color(0)]]; +}; + +struct main0_in +{ + float3 Foo3 [[user(locn0)]]; + float Foo1 [[user(locn0_3)]]; +}; + +fragment main0_out main0(main0_in in [[stage_in]]) +{ + main0_out out = {}; + out.FragColor = float4(in.Foo3, in.Foo1); + return out; +} + diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/components/fragment-output-component.frag b/third_party/spirv-cross/reference/shaders-msl-no-opt/components/fragment-output-component.frag new file mode 100644 index 0000000000..7e030aa1ed --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/components/fragment-output-component.frag @@ -0,0 +1,25 @@ +#include +#include + +using namespace metal; + +struct main0_out +{ + float4 FragColor0 [[color(0)]]; +}; + +fragment main0_out main0() +{ + main0_out out = {}; + float FragColor0 = {}; + float2 FragColor1 = {}; + float FragColor3 = {}; + FragColor0 = 1.0; + FragColor1 = float2(2.0, 3.0); + FragColor3 = 4.0; + out.FragColor0.x = FragColor0; + out.FragColor0.yz = FragColor1; + out.FragColor0.w = FragColor3; + return out; +} + diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/components/fragment-output-component.pad-fragment.frag b/third_party/spirv-cross/reference/shaders-msl-no-opt/components/fragment-output-component.pad-fragment.frag new file mode 100644 index 0000000000..13eb7d5769 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/components/fragment-output-component.pad-fragment.frag @@ -0,0 +1,22 @@ +#include +#include + +using namespace metal; + +struct main0_out +{ + float4 FragColor0 [[color(0)]]; +}; + +fragment main0_out main0() +{ + main0_out out = {}; + float FragColor0 = {}; + float2 FragColor1 = {}; + FragColor0 = 1.0; + FragColor1 = float2(2.0, 3.0); + out.FragColor0.x = FragColor0; + out.FragColor0.yz = FragColor1; + return out; +} + diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/components/vertex-input-component.vert b/third_party/spirv-cross/reference/shaders-msl-no-opt/components/vertex-input-component.vert new file mode 100644 index 0000000000..1aae280d08 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/components/vertex-input-component.vert @@ -0,0 +1,28 @@ +#include +#include + +using namespace metal; + +struct main0_out +{ + float3 Foo [[user(locn0)]]; + float4 gl_Position [[position]]; +}; + +struct main0_in +{ + float4 Foo3 [[attribute(0)]]; +}; + +vertex main0_out main0(main0_in in [[stage_in]]) +{ + main0_out out = {}; + float3 Foo3 = {}; + float Foo1 = {}; + Foo3 = in.Foo3.xyz; + Foo1 = in.Foo3.w; + out.gl_Position = float4(Foo3, Foo1); + out.Foo = Foo3 + float3(Foo1); + return out; +} + diff --git a/third_party/spirv-cross/reference/shaders-msl/vert/viewport-index.msl2.invalid.vert b/third_party/spirv-cross/reference/shaders-msl-no-opt/components/vertex-output-component.vert similarity index 57% rename from third_party/spirv-cross/reference/shaders-msl/vert/viewport-index.msl2.invalid.vert rename to third_party/spirv-cross/reference/shaders-msl-no-opt/components/vertex-output-component.vert index e5316c072a..cf135b5128 100644 --- a/third_party/spirv-cross/reference/shaders-msl/vert/viewport-index.msl2.invalid.vert +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/components/vertex-output-component.vert @@ -5,20 +5,22 @@ using namespace metal; struct main0_out { + float3 Foo3 [[user(locn0)]]; + float Foo1 [[user(locn0_3)]]; float4 gl_Position [[position]]; - uint gl_ViewportIndex [[viewport_array_index]]; }; struct main0_in { - float4 coord [[attribute(0)]]; + float4 vFoo [[attribute(0)]]; }; vertex main0_out main0(main0_in in [[stage_in]]) { main0_out out = {}; - out.gl_Position = in.coord; - out.gl_ViewportIndex = uint(int(in.coord.z)); + out.gl_Position = in.vFoo; + out.Foo3 = in.vFoo.xyz; + out.Foo1 = in.vFoo.w; return out; } diff --git a/third_party/spirv-cross/reference/shaders-msl/frag/16bit-constants.invalid.frag b/third_party/spirv-cross/reference/shaders-msl-no-opt/frag/16bit-constants.invalid.frag similarity index 84% rename from third_party/spirv-cross/reference/shaders-msl/frag/16bit-constants.invalid.frag rename to third_party/spirv-cross/reference/shaders-msl-no-opt/frag/16bit-constants.invalid.frag index 56c7ea5df4..542beb3189 100644 --- a/third_party/spirv-cross/reference/shaders-msl/frag/16bit-constants.invalid.frag +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/frag/16bit-constants.invalid.frag @@ -14,8 +14,8 @@ fragment main0_out main0() { main0_out out = {}; out.foo = half(1.0); - out.bar = 2; - out.baz = 3u; + out.bar = short(2); + out.baz = ushort(3); return out; } diff --git a/third_party/spirv-cross/reference/shaders-msl/vulkan/frag/demote-to-helper.vk.nocompat.msl21.invalid.frag b/third_party/spirv-cross/reference/shaders-msl-no-opt/frag/demote-to-helper.vk.nocompat.msl21.invalid.frag similarity index 100% rename from third_party/spirv-cross/reference/shaders-msl/vulkan/frag/demote-to-helper.vk.nocompat.msl21.invalid.frag rename to third_party/spirv-cross/reference/shaders-msl-no-opt/frag/demote-to-helper.vk.nocompat.msl21.invalid.frag diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/frag/force-active-resources.msl2.argument..force-active.discrete.frag b/third_party/spirv-cross/reference/shaders-msl-no-opt/frag/force-active-resources.msl2.argument..force-active.discrete.frag new file mode 100644 index 0000000000..5f8dc7203e --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/frag/force-active-resources.msl2.argument..force-active.discrete.frag @@ -0,0 +1,31 @@ +#include +#include + +using namespace metal; + +struct spvDescriptorSetBuffer0 +{ + texture2d uTexture2 [[id(0)]]; + sampler uTexture2Smplr [[id(1)]]; + texture2d uTexture1 [[id(2)]]; + sampler uTexture1Smplr [[id(3)]]; +}; + +struct main0_out +{ + float4 FragColor [[color(0)]]; +}; + +struct main0_in +{ + float2 vUV [[user(locn0)]]; +}; + +fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]], texture2d uTextureDiscrete2 [[texture(0)]], sampler uTextureDiscrete2Smplr [[sampler(0)]]) +{ + main0_out out = {}; + out.FragColor = spvDescriptorSet0.uTexture2.sample(spvDescriptorSet0.uTexture2Smplr, in.vUV); + out.FragColor += uTextureDiscrete2.sample(uTextureDiscrete2Smplr, in.vUV); + return out; +} + diff --git a/third_party/spirv-cross/reference/shaders-msl/frag/fp16.desktop.invalid.frag b/third_party/spirv-cross/reference/shaders-msl-no-opt/frag/fp16.desktop.invalid.frag similarity index 92% rename from third_party/spirv-cross/reference/shaders-msl/frag/fp16.desktop.invalid.frag rename to third_party/spirv-cross/reference/shaders-msl-no-opt/frag/fp16.desktop.invalid.frag index 55be16a0b0..2814a12f13 100644 --- a/third_party/spirv-cross/reference/shaders-msl/frag/fp16.desktop.invalid.frag +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/frag/fp16.desktop.invalid.frag @@ -21,35 +21,38 @@ struct main0_in // Implementation of the GLSL mod() function, which is slightly different than Metal fmod() template -Tx mod(Tx x, Ty y) +inline Tx mod(Tx x, Ty y) { return x - y * floor(x / y); } // Implementation of the GLSL radians() function template -T radians(T d) +inline T radians(T d) { return d * T(0.01745329251); } // Implementation of the GLSL degrees() function template -T degrees(T r) +inline T degrees(T r) { return r * T(57.2957795131); } +static inline __attribute__((always_inline)) half2x2 test_mat2(thread const half2& a, thread const half2& b, thread const half2& c, thread const half2& d) { return half2x2(half2(a), half2(b)) * half2x2(half2(c), half2(d)); } +static inline __attribute__((always_inline)) half3x3 test_mat3(thread const half3& a, thread const half3& b, thread const half3& c, thread const half3& d, thread const half3& e, thread const half3& f) { return half3x3(half3(a), half3(b), half3(c)) * half3x3(half3(d), half3(e), half3(f)); } +static inline __attribute__((always_inline)) void test_constants() { half a = half(1.0); @@ -62,11 +65,13 @@ void test_constants() half h = half(9.5367431640625e-07); } +static inline __attribute__((always_inline)) half test_result() { return half(1.0); } +static inline __attribute__((always_inline)) void test_conversions() { half one = test_result(); @@ -80,6 +85,7 @@ void test_conversions() half d2 = half(d); } +static inline __attribute__((always_inline)) void test_builtins(thread half4& v4, thread half3& v3, thread half& v1) { half4 res = radians(v4); diff --git a/third_party/spirv-cross/reference/shaders-msl/asm/frag/min-max-clamp.invalid.asm.frag b/third_party/spirv-cross/reference/shaders-msl-no-opt/frag/min-max-clamp.invalid.asm.frag similarity index 100% rename from third_party/spirv-cross/reference/shaders-msl/asm/frag/min-max-clamp.invalid.asm.frag rename to third_party/spirv-cross/reference/shaders-msl-no-opt/frag/min-max-clamp.invalid.asm.frag diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/frag/pixel-interlock-simple-callstack.msl2.frag b/third_party/spirv-cross/reference/shaders-msl-no-opt/frag/pixel-interlock-simple-callstack.msl2.frag new file mode 100644 index 0000000000..cb01950d22 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/frag/pixel-interlock-simple-callstack.msl2.frag @@ -0,0 +1,37 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" + +#include +#include + +using namespace metal; + +struct SSBO1 +{ + uint values1[1]; +}; + +struct SSBO0 +{ + uint values0[1]; +}; + +static inline __attribute__((always_inline)) +void callee2(device SSBO1& v_14, thread float4& gl_FragCoord) +{ + int _25 = int(gl_FragCoord.x); + v_14.values1[_25]++; +} + +static inline __attribute__((always_inline)) +void callee(device SSBO1& v_14, thread float4& gl_FragCoord, device SSBO0& v_35) +{ + int _38 = int(gl_FragCoord.x); + v_35.values0[_38]++; + callee2(v_14, gl_FragCoord); +} + +fragment void main0(device SSBO1& v_14 [[buffer(0), raster_order_group(0)]], device SSBO0& v_35 [[buffer(1), raster_order_group(0)]], float4 gl_FragCoord [[position]]) +{ + callee(v_14, gl_FragCoord, v_35); +} + diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/vulkan/frag/scalar-block-layout-ubo-std430.vk.nocompat.invalid.frag b/third_party/spirv-cross/reference/shaders-msl-no-opt/frag/scalar-block-layout-ubo-std430.vk.nocompat.invalid.frag similarity index 100% rename from third_party/spirv-cross/reference/opt/shaders-msl/vulkan/frag/scalar-block-layout-ubo-std430.vk.nocompat.invalid.frag rename to third_party/spirv-cross/reference/shaders-msl-no-opt/frag/scalar-block-layout-ubo-std430.vk.nocompat.invalid.frag diff --git a/third_party/spirv-cross/reference/shaders-msl/frag/shadow-compare-global-alias.invalid.frag b/third_party/spirv-cross/reference/shaders-msl-no-opt/frag/shadow-compare-global-alias.invalid.frag similarity index 90% rename from third_party/spirv-cross/reference/shaders-msl/frag/shadow-compare-global-alias.invalid.frag rename to third_party/spirv-cross/reference/shaders-msl-no-opt/frag/shadow-compare-global-alias.invalid.frag index 4bd5d32091..8f7b8ece49 100644 --- a/third_party/spirv-cross/reference/shaders-msl/frag/shadow-compare-global-alias.invalid.frag +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/frag/shadow-compare-global-alias.invalid.frag @@ -15,21 +15,25 @@ struct main0_in float3 vUV [[user(locn0)]]; }; +static inline __attribute__((always_inline)) float Samp(thread const float3& uv, thread depth2d uTex, thread sampler uSamp) { return uTex.sample_compare(uSamp, uv.xy, uv.z); } +static inline __attribute__((always_inline)) float Samp2(thread const float3& uv, thread depth2d uSampler, thread const sampler uSamplerSmplr, thread float3& vUV) { return uSampler.sample_compare(uSamplerSmplr, vUV.xy, vUV.z); } +static inline __attribute__((always_inline)) float Samp3(thread const depth2d uT, thread const sampler uS, thread const float3& uv, thread float3& vUV) { return uT.sample_compare(uS, vUV.xy, vUV.z); } +static inline __attribute__((always_inline)) float Samp4(thread const depth2d uS, thread const sampler uSSmplr, thread const float3& uv, thread float3& vUV) { return uS.sample_compare(uSSmplr, vUV.xy, vUV.z); diff --git a/third_party/spirv-cross/reference/shaders-msl/vulkan/frag/subgroups.nocompat.invalid.vk.msl21.frag b/third_party/spirv-cross/reference/shaders-msl-no-opt/frag/subgroups.nocompat.invalid.vk.msl21.frag similarity index 100% rename from third_party/spirv-cross/reference/shaders-msl/vulkan/frag/subgroups.nocompat.invalid.vk.msl21.frag rename to third_party/spirv-cross/reference/shaders-msl-no-opt/frag/subgroups.nocompat.invalid.vk.msl21.frag diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/frag/texture-access-int.swizzle.frag b/third_party/spirv-cross/reference/shaders-msl-no-opt/frag/texture-access-int.swizzle.frag index 4cb0fdd59b..ff4b8a9194 100644 --- a/third_party/spirv-cross/reference/shaders-msl-no-opt/frag/texture-access-int.swizzle.frag +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/frag/texture-access-int.swizzle.frag @@ -6,22 +6,12 @@ using namespace metal; // Returns 2D texture coords corresponding to 1D texel buffer coords +static inline __attribute__((always_inline)) uint2 spvTexelBufferCoord(uint tc) { return uint2(tc % 4096, tc / 4096); } -enum class spvSwizzle : uint -{ - none = 0, - zero, - one, - red, - green, - blue, - alpha -}; - template struct spvRemoveReference { typedef T type; }; template struct spvRemoveReference { typedef T type; }; template struct spvRemoveReference { typedef T type; }; @@ -34,6 +24,17 @@ template inline constexpr thread T&& spvForward(thread typename spvR return static_cast(x); } +enum class spvSwizzle : uint +{ + none = 0, + zero, + one, + red, + green, + blue, + alpha +}; + template inline T spvGetSwizzle(vec x, T c, spvSwizzle s) { @@ -72,8 +73,8 @@ inline T spvTextureSwizzle(T x, uint s) } // Wrapper function that swizzles texture gathers. -template -inline vec spvGatherSwizzle(sampler s, const thread Tex& t, Ts... params, component c, uint sw) METAL_CONST_ARG(c) +template class Tex, typename... Ts> +inline vec spvGatherSwizzle(const thread Tex& t, sampler s, uint sw, component c, Ts... params) METAL_CONST_ARG(c) { if (sw) { @@ -108,29 +109,6 @@ inline vec spvGatherSwizzle(sampler s, const thread Tex& t, Ts... params, } } -// Wrapper function that swizzles depth texture gathers. -template -inline vec spvGatherCompareSwizzle(sampler s, const thread Tex& t, Ts... params, uint sw) -{ - if (sw) - { - switch (spvSwizzle(sw & 0xFF)) - { - case spvSwizzle::none: - case spvSwizzle::red: - break; - case spvSwizzle::zero: - case spvSwizzle::green: - case spvSwizzle::blue: - case spvSwizzle::alpha: - return vec(0, 0, 0, 0); - case spvSwizzle::one: - return vec(1, 1, 1, 1); - } - } - return t.gather_compare(s, spvForward(params)...); -} - fragment void main0(constant uint* spvSwizzleConstants [[buffer(30)]], texture1d tex1d [[texture(0)]], texture2d tex2d [[texture(1)]], texture3d tex3d [[texture(2)]], texturecube texCube [[texture(3)]], texture2d_array tex2dArray [[texture(4)]], texturecube_array texCubeArray [[texture(5)]], texture2d texBuffer [[texture(6)]], sampler tex1dSmplr [[sampler(0)]], sampler tex2dSmplr [[sampler(1)]], sampler tex3dSmplr [[sampler(2)]], sampler texCubeSmplr [[sampler(3)]], sampler tex2dArraySmplr [[sampler(4)]], sampler texCubeArraySmplr [[sampler(5)]]) { constant uint& tex1dSwzl = spvSwizzleConstants[0]; @@ -162,9 +140,9 @@ fragment void main0(constant uint* spvSwizzleConstants [[buffer(30)]], texture1d c = float4(spvTextureSwizzle(tex3d.read(uint3(int3(0)), 0), tex3dSwzl)); c = float4(spvTextureSwizzle(tex2dArray.read(uint2(int3(0).xy), uint(int3(0).z), 0), tex2dArraySwzl)); c = float4(texBuffer.read(spvTexelBufferCoord(0))); - c = float4(spvGatherSwizzle, float2, int2>(tex2dSmplr, tex2d, float2(0.0), int2(0), component::x, tex2dSwzl)); - c = float4(spvGatherSwizzle, float3>(texCubeSmplr, texCube, float3(0.0), component::y, texCubeSwzl)); - c = float4(spvGatherSwizzle, float2, uint, int2>(tex2dArraySmplr, tex2dArray, float3(0.0).xy, uint(round(float3(0.0).z)), int2(0), component::z, tex2dArraySwzl)); - c = float4(spvGatherSwizzle, float3, uint>(texCubeArraySmplr, texCubeArray, float4(0.0).xyz, uint(round(float4(0.0).w)), component::w, texCubeArraySwzl)); + c = float4(spvGatherSwizzle(tex2d, tex2dSmplr, tex2dSwzl, component::x, float2(0.0), int2(0))); + c = float4(spvGatherSwizzle(texCube, texCubeSmplr, texCubeSwzl, component::y, float3(0.0))); + c = float4(spvGatherSwizzle(tex2dArray, tex2dArraySmplr, tex2dArraySwzl, component::z, float3(0.0).xy, uint(round(float3(0.0).z)), int2(0))); + c = float4(spvGatherSwizzle(texCubeArray, texCubeArraySmplr, texCubeArraySwzl, component::w, float4(0.0).xyz, uint(round(float4(0.0).w)))); } diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/frag/texture-access-leaf.swizzle.frag b/third_party/spirv-cross/reference/shaders-msl-no-opt/frag/texture-access-leaf.swizzle.frag index 581f290941..730728c1aa 100644 --- a/third_party/spirv-cross/reference/shaders-msl-no-opt/frag/texture-access-leaf.swizzle.frag +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/frag/texture-access-leaf.swizzle.frag @@ -6,22 +6,12 @@ using namespace metal; // Returns 2D texture coords corresponding to 1D texel buffer coords +static inline __attribute__((always_inline)) uint2 spvTexelBufferCoord(uint tc) { return uint2(tc % 4096, tc / 4096); } -enum class spvSwizzle : uint -{ - none = 0, - zero, - one, - red, - green, - blue, - alpha -}; - template struct spvRemoveReference { typedef T type; }; template struct spvRemoveReference { typedef T type; }; template struct spvRemoveReference { typedef T type; }; @@ -34,6 +24,17 @@ template inline constexpr thread T&& spvForward(thread typename spvR return static_cast(x); } +enum class spvSwizzle : uint +{ + none = 0, + zero, + one, + red, + green, + blue, + alpha +}; + template inline T spvGetSwizzle(vec x, T c, spvSwizzle s) { @@ -72,8 +73,8 @@ inline T spvTextureSwizzle(T x, uint s) } // Wrapper function that swizzles texture gathers. -template -inline vec spvGatherSwizzle(sampler s, const thread Tex& t, Ts... params, component c, uint sw) METAL_CONST_ARG(c) +template class Tex, typename... Ts> +inline vec spvGatherSwizzle(const thread Tex& t, sampler s, uint sw, component c, Ts... params) METAL_CONST_ARG(c) { if (sw) { @@ -109,8 +110,8 @@ inline vec spvGatherSwizzle(sampler s, const thread Tex& t, Ts... params, } // Wrapper function that swizzles depth texture gathers. -template -inline vec spvGatherCompareSwizzle(sampler s, const thread Tex& t, Ts... params, uint sw) +template class Tex, typename... Ts> +inline vec spvGatherCompareSwizzle(const thread Tex& t, sampler s, uint sw, Ts... params) { if (sw) { @@ -131,6 +132,7 @@ inline vec spvGatherCompareSwizzle(sampler s, const thread Tex& t, Ts... p return t.gather_compare(s, spvForward(params)...); } +static inline __attribute__((always_inline)) float4 doSwizzle(thread texture1d tex1d, thread const sampler tex1dSmplr, constant uint& tex1dSwzl, thread texture2d tex2d, thread const sampler tex2dSmplr, constant uint& tex2dSwzl, thread texture3d tex3d, thread const sampler tex3dSmplr, constant uint& tex3dSwzl, thread texturecube texCube, thread const sampler texCubeSmplr, constant uint& texCubeSwzl, thread texture2d_array tex2dArray, thread const sampler tex2dArraySmplr, constant uint& tex2dArraySwzl, thread texturecube_array texCubeArray, thread const sampler texCubeArraySmplr, constant uint& texCubeArraySwzl, thread depth2d depth2d, thread const sampler depth2dSmplr, constant uint& depth2dSwzl, thread depthcube depthCube, thread const sampler depthCubeSmplr, constant uint& depthCubeSwzl, thread depth2d_array depth2dArray, thread const sampler depth2dArraySmplr, constant uint& depth2dArraySwzl, thread depthcube_array depthCubeArray, thread const sampler depthCubeArraySmplr, constant uint& depthCubeArraySwzl, thread texture2d texBuffer) { float4 c = spvTextureSwizzle(tex1d.sample(tex1dSmplr, 0.0), tex1dSwzl); @@ -167,14 +169,14 @@ float4 doSwizzle(thread texture1d tex1d, thread const sampler tex1dSmplr, c = spvTextureSwizzle(tex3d.read(uint3(int3(0)), 0), tex3dSwzl); c = spvTextureSwizzle(tex2dArray.read(uint2(int3(0).xy), uint(int3(0).z), 0), tex2dArraySwzl); c = texBuffer.read(spvTexelBufferCoord(0)); - c = spvGatherSwizzle, float2, int2>(tex2dSmplr, tex2d, float2(0.0), int2(0), component::x, tex2dSwzl); - c = spvGatherSwizzle, float3>(texCubeSmplr, texCube, float3(0.0), component::y, texCubeSwzl); - c = spvGatherSwizzle, float2, uint, int2>(tex2dArraySmplr, tex2dArray, float3(0.0).xy, uint(round(float3(0.0).z)), int2(0), component::z, tex2dArraySwzl); - c = spvGatherSwizzle, float3, uint>(texCubeArraySmplr, texCubeArray, float4(0.0).xyz, uint(round(float4(0.0).w)), component::w, texCubeArraySwzl); - c = spvGatherCompareSwizzle, float2, float>(depth2dSmplr, depth2d, float2(0.0), 1.0, depth2dSwzl); - c = spvGatherCompareSwizzle, float3, float>(depthCubeSmplr, depthCube, float3(0.0), 1.0, depthCubeSwzl); - c = spvGatherCompareSwizzle, float2, uint, float>(depth2dArraySmplr, depth2dArray, float3(0.0).xy, uint(round(float3(0.0).z)), 1.0, depth2dArraySwzl); - c = spvGatherCompareSwizzle, float3, uint, float>(depthCubeArraySmplr, depthCubeArray, float4(0.0).xyz, uint(round(float4(0.0).w)), 1.0, depthCubeArraySwzl); + c = spvGatherSwizzle(tex2d, tex2dSmplr, tex2dSwzl, component::x, float2(0.0), int2(0)); + c = spvGatherSwizzle(texCube, texCubeSmplr, texCubeSwzl, component::y, float3(0.0)); + c = spvGatherSwizzle(tex2dArray, tex2dArraySmplr, tex2dArraySwzl, component::z, float3(0.0).xy, uint(round(float3(0.0).z)), int2(0)); + c = spvGatherSwizzle(texCubeArray, texCubeArraySmplr, texCubeArraySwzl, component::w, float4(0.0).xyz, uint(round(float4(0.0).w))); + c = spvGatherCompareSwizzle(depth2d, depth2dSmplr, depth2dSwzl, float2(0.0), 1.0); + c = spvGatherCompareSwizzle(depthCube, depthCubeSmplr, depthCubeSwzl, float3(0.0), 1.0); + c = spvGatherCompareSwizzle(depth2dArray, depth2dArraySmplr, depth2dArraySwzl, float3(0.0).xy, uint(round(float3(0.0).z)), 1.0); + c = spvGatherCompareSwizzle(depthCubeArray, depthCubeArraySmplr, depthCubeArraySwzl, float4(0.0).xyz, uint(round(float4(0.0).w)), 1.0); return c; } diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/frag/texture-access-uint.swizzle.frag b/third_party/spirv-cross/reference/shaders-msl-no-opt/frag/texture-access-uint.swizzle.frag index 86b712536e..0ec278f977 100644 --- a/third_party/spirv-cross/reference/shaders-msl-no-opt/frag/texture-access-uint.swizzle.frag +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/frag/texture-access-uint.swizzle.frag @@ -6,22 +6,12 @@ using namespace metal; // Returns 2D texture coords corresponding to 1D texel buffer coords +static inline __attribute__((always_inline)) uint2 spvTexelBufferCoord(uint tc) { return uint2(tc % 4096, tc / 4096); } -enum class spvSwizzle : uint -{ - none = 0, - zero, - one, - red, - green, - blue, - alpha -}; - template struct spvRemoveReference { typedef T type; }; template struct spvRemoveReference { typedef T type; }; template struct spvRemoveReference { typedef T type; }; @@ -34,6 +24,17 @@ template inline constexpr thread T&& spvForward(thread typename spvR return static_cast(x); } +enum class spvSwizzle : uint +{ + none = 0, + zero, + one, + red, + green, + blue, + alpha +}; + template inline T spvGetSwizzle(vec x, T c, spvSwizzle s) { @@ -72,8 +73,8 @@ inline T spvTextureSwizzle(T x, uint s) } // Wrapper function that swizzles texture gathers. -template -inline vec spvGatherSwizzle(sampler s, const thread Tex& t, Ts... params, component c, uint sw) METAL_CONST_ARG(c) +template class Tex, typename... Ts> +inline vec spvGatherSwizzle(const thread Tex& t, sampler s, uint sw, component c, Ts... params) METAL_CONST_ARG(c) { if (sw) { @@ -108,29 +109,6 @@ inline vec spvGatherSwizzle(sampler s, const thread Tex& t, Ts... params, } } -// Wrapper function that swizzles depth texture gathers. -template -inline vec spvGatherCompareSwizzle(sampler s, const thread Tex& t, Ts... params, uint sw) -{ - if (sw) - { - switch (spvSwizzle(sw & 0xFF)) - { - case spvSwizzle::none: - case spvSwizzle::red: - break; - case spvSwizzle::zero: - case spvSwizzle::green: - case spvSwizzle::blue: - case spvSwizzle::alpha: - return vec(0, 0, 0, 0); - case spvSwizzle::one: - return vec(1, 1, 1, 1); - } - } - return t.gather_compare(s, spvForward(params)...); -} - fragment void main0(constant uint* spvSwizzleConstants [[buffer(30)]], texture1d tex1d [[texture(0)]], texture2d tex2d [[texture(1)]], texture3d tex3d [[texture(2)]], texturecube texCube [[texture(3)]], texture2d_array tex2dArray [[texture(4)]], texturecube_array texCubeArray [[texture(5)]], texture2d texBuffer [[texture(6)]], sampler tex1dSmplr [[sampler(0)]], sampler tex2dSmplr [[sampler(1)]], sampler tex3dSmplr [[sampler(2)]], sampler texCubeSmplr [[sampler(3)]], sampler tex2dArraySmplr [[sampler(4)]], sampler texCubeArraySmplr [[sampler(5)]]) { constant uint& tex1dSwzl = spvSwizzleConstants[0]; @@ -162,9 +140,9 @@ fragment void main0(constant uint* spvSwizzleConstants [[buffer(30)]], texture1d c = float4(spvTextureSwizzle(tex3d.read(uint3(int3(0)), 0), tex3dSwzl)); c = float4(spvTextureSwizzle(tex2dArray.read(uint2(int3(0).xy), uint(int3(0).z), 0), tex2dArraySwzl)); c = float4(texBuffer.read(spvTexelBufferCoord(0))); - c = float4(spvGatherSwizzle, float2, int2>(tex2dSmplr, tex2d, float2(0.0), int2(0), component::x, tex2dSwzl)); - c = float4(spvGatherSwizzle, float3>(texCubeSmplr, texCube, float3(0.0), component::y, texCubeSwzl)); - c = float4(spvGatherSwizzle, float2, uint, int2>(tex2dArraySmplr, tex2dArray, float3(0.0).xy, uint(round(float3(0.0).z)), int2(0), component::z, tex2dArraySwzl)); - c = float4(spvGatherSwizzle, float3, uint>(texCubeArraySmplr, texCubeArray, float4(0.0).xyz, uint(round(float4(0.0).w)), component::w, texCubeArraySwzl)); + c = float4(spvGatherSwizzle(tex2d, tex2dSmplr, tex2dSwzl, component::x, float2(0.0), int2(0))); + c = float4(spvGatherSwizzle(texCube, texCubeSmplr, texCubeSwzl, component::y, float3(0.0))); + c = float4(spvGatherSwizzle(tex2dArray, tex2dArraySmplr, tex2dArraySwzl, component::z, float3(0.0).xy, uint(round(float3(0.0).z)), int2(0))); + c = float4(spvGatherSwizzle(texCubeArray, texCubeArraySmplr, texCubeArraySwzl, component::w, float4(0.0).xyz, uint(round(float4(0.0).w)))); } diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/frag/texture-access.swizzle.frag b/third_party/spirv-cross/reference/shaders-msl-no-opt/frag/texture-access.swizzle.frag index fb9865bcf0..c31d5d7dca 100644 --- a/third_party/spirv-cross/reference/shaders-msl-no-opt/frag/texture-access.swizzle.frag +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/frag/texture-access.swizzle.frag @@ -6,22 +6,12 @@ using namespace metal; // Returns 2D texture coords corresponding to 1D texel buffer coords +static inline __attribute__((always_inline)) uint2 spvTexelBufferCoord(uint tc) { return uint2(tc % 4096, tc / 4096); } -enum class spvSwizzle : uint -{ - none = 0, - zero, - one, - red, - green, - blue, - alpha -}; - template struct spvRemoveReference { typedef T type; }; template struct spvRemoveReference { typedef T type; }; template struct spvRemoveReference { typedef T type; }; @@ -34,6 +24,17 @@ template inline constexpr thread T&& spvForward(thread typename spvR return static_cast(x); } +enum class spvSwizzle : uint +{ + none = 0, + zero, + one, + red, + green, + blue, + alpha +}; + template inline T spvGetSwizzle(vec x, T c, spvSwizzle s) { @@ -72,8 +73,8 @@ inline T spvTextureSwizzle(T x, uint s) } // Wrapper function that swizzles texture gathers. -template -inline vec spvGatherSwizzle(sampler s, const thread Tex& t, Ts... params, component c, uint sw) METAL_CONST_ARG(c) +template class Tex, typename... Ts> +inline vec spvGatherSwizzle(const thread Tex& t, sampler s, uint sw, component c, Ts... params) METAL_CONST_ARG(c) { if (sw) { @@ -109,8 +110,8 @@ inline vec spvGatherSwizzle(sampler s, const thread Tex& t, Ts... params, } // Wrapper function that swizzles depth texture gathers. -template -inline vec spvGatherCompareSwizzle(sampler s, const thread Tex& t, Ts... params, uint sw) +template class Tex, typename... Ts> +inline vec spvGatherCompareSwizzle(const thread Tex& t, sampler s, uint sw, Ts... params) { if (sw) { @@ -177,13 +178,13 @@ fragment void main0(constant uint* spvSwizzleConstants [[buffer(30)]], texture1d c = spvTextureSwizzle(tex3d.read(uint3(int3(0)), 0), tex3dSwzl); c = spvTextureSwizzle(tex2dArray.read(uint2(int3(0).xy), uint(int3(0).z), 0), tex2dArraySwzl); c = texBuffer.read(spvTexelBufferCoord(0)); - c = spvGatherSwizzle, float2, int2>(tex2dSmplr, tex2d, float2(0.0), int2(0), component::x, tex2dSwzl); - c = spvGatherSwizzle, float3>(texCubeSmplr, texCube, float3(0.0), component::y, texCubeSwzl); - c = spvGatherSwizzle, float2, uint, int2>(tex2dArraySmplr, tex2dArray, float3(0.0).xy, uint(round(float3(0.0).z)), int2(0), component::z, tex2dArraySwzl); - c = spvGatherSwizzle, float3, uint>(texCubeArraySmplr, texCubeArray, float4(0.0).xyz, uint(round(float4(0.0).w)), component::w, texCubeArraySwzl); - c = spvGatherCompareSwizzle, float2, float>(depth2dSmplr, depth2d, float2(0.0), 1.0, depth2dSwzl); - c = spvGatherCompareSwizzle, float3, float>(depthCubeSmplr, depthCube, float3(0.0), 1.0, depthCubeSwzl); - c = spvGatherCompareSwizzle, float2, uint, float>(depth2dArraySmplr, depth2dArray, float3(0.0).xy, uint(round(float3(0.0).z)), 1.0, depth2dArraySwzl); - c = spvGatherCompareSwizzle, float3, uint, float>(depthCubeArraySmplr, depthCubeArray, float4(0.0).xyz, uint(round(float4(0.0).w)), 1.0, depthCubeArraySwzl); + c = spvGatherSwizzle(tex2d, tex2dSmplr, tex2dSwzl, component::x, float2(0.0), int2(0)); + c = spvGatherSwizzle(texCube, texCubeSmplr, texCubeSwzl, component::y, float3(0.0)); + c = spvGatherSwizzle(tex2dArray, tex2dArraySmplr, tex2dArraySwzl, component::z, float3(0.0).xy, uint(round(float3(0.0).z)), int2(0)); + c = spvGatherSwizzle(texCubeArray, texCubeArraySmplr, texCubeArraySwzl, component::w, float4(0.0).xyz, uint(round(float4(0.0).w))); + c = spvGatherCompareSwizzle(depth2d, depth2dSmplr, depth2dSwzl, float2(0.0), 1.0); + c = spvGatherCompareSwizzle(depthCube, depthCubeSmplr, depthCubeSwzl, float3(0.0), 1.0); + c = spvGatherCompareSwizzle(depth2dArray, depth2dArraySmplr, depth2dArraySwzl, float3(0.0).xy, uint(round(float3(0.0).z)), 1.0); + c = spvGatherCompareSwizzle(depthCubeArray, depthCubeArraySmplr, depthCubeArraySwzl, float4(0.0).xyz, uint(round(float4(0.0).w)), 1.0); } diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/array-of-vec3.comp b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/array-of-vec3.comp new file mode 100644 index 0000000000..0dd52ab36d --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/array-of-vec3.comp @@ -0,0 +1,17 @@ +#include +#include + +using namespace metal; + +struct SSBO +{ + packed_float3 v[16]; +}; + +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + +kernel void main0(device SSBO& _13 [[buffer(0)]]) +{ + _13.v[1] = float3(_13.v[0]); +} + diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/array-of-vec4.comp b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/array-of-vec4.comp new file mode 100644 index 0000000000..025cd42546 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/array-of-vec4.comp @@ -0,0 +1,17 @@ +#include +#include + +using namespace metal; + +struct SSBO +{ + float4 v[16]; +}; + +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + +kernel void main0(device SSBO& _13 [[buffer(0)]]) +{ + _13.v[1] = _13.v[0]; +} + diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/load-store-col-rows.comp b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/load-store-col-rows.comp new file mode 100644 index 0000000000..c702435479 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/load-store-col-rows.comp @@ -0,0 +1,76 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" + +#include +#include + +using namespace metal; + +typedef packed_float3 packed_float2x3[2]; +typedef packed_float3 packed_rm_float3x2[2]; + +struct SSBO1 +{ + float2x4 a; + float2x4 a2; +}; + +struct SSBO2 +{ + packed_float2x3 b; + packed_rm_float3x2 b2; +}; + +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + +static inline __attribute__((always_inline)) +void load_store_column(device SSBO1& v_21) +{ + float2 u = v_21.a[0].xy; + float2 v = v_21.a[1].xy; + u += v; + v_21.a[0].xy = u; + v_21.a[1].xy = v; +} + +static inline __attribute__((always_inline)) +void load_store_row(device SSBO1& v_21) +{ + float2 u = float2(v_21.a2[0][0], v_21.a2[1][0]); + float2 v = float2(v_21.a2[0][1], v_21.a2[1][1]); + u += v; + v_21.a2[0][0] = u.x; + v_21.a2[1][0] = u.y; + v_21.a2[0][1] = v.x; + v_21.a2[1][1] = v.y; +} + +static inline __attribute__((always_inline)) +void load_store_packed_column(device SSBO2& v_58) +{ + float3 u = float3(v_58.b[0]); + float3 v = float3(v_58.b[1]); + u += v; + v_58.b[0] = u; + v_58.b[1] = v; +} + +static inline __attribute__((always_inline)) +void load_store_packed_row(device SSBO2& v_58) +{ + float2 u = float2(v_58.b2[0][0], v_58.b2[1][0]); + float2 v = float2(v_58.b2[0][1], v_58.b2[1][1]); + u += v; + v_58.b2[0][0] = u.x; + v_58.b2[1][0] = u.y; + v_58.b2[0][1] = v.x; + v_58.b2[1][1] = v.y; +} + +kernel void main0(device SSBO1& v_21 [[buffer(0)]], device SSBO2& v_58 [[buffer(1)]]) +{ + load_store_column(v_21); + load_store_row(v_21); + load_store_packed_column(v_58); + load_store_packed_row(v_58); +} + diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-2x2-scalar.comp b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-2x2-scalar.comp index a0fdf9d91c..d1bdd47f55 100644 --- a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-2x2-scalar.comp +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-2x2-scalar.comp @@ -17,38 +17,47 @@ struct SSBORow float2x2 row_major1; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + +static inline __attribute__((always_inline)) void load_store_to_variable_col_major(device SSBOCol& v_29) { float2x2 loaded = v_29.col_major0; v_29.col_major1 = loaded; } +static inline __attribute__((always_inline)) void load_store_to_variable_row_major(device SSBORow& v_41) { float2x2 loaded = transpose(v_41.row_major0); v_41.row_major0 = transpose(loaded); } +static inline __attribute__((always_inline)) void copy_col_major_to_col_major(device SSBOCol& v_29) { v_29.col_major0 = v_29.col_major1; } +static inline __attribute__((always_inline)) void copy_col_major_to_row_major(device SSBOCol& v_29, device SSBORow& v_41) { v_41.row_major0 = transpose(v_29.col_major0); } +static inline __attribute__((always_inline)) void copy_row_major_to_col_major(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0 = transpose(v_41.row_major0); } +static inline __attribute__((always_inline)) void copy_row_major_to_row_major(device SSBORow& v_41) { v_41.row_major0 = v_41.row_major1; } +static inline __attribute__((always_inline)) void copy_columns(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0[1] = float2(v_41.row_major0[0][1], v_41.row_major0[1][1]); @@ -56,6 +65,7 @@ void copy_columns(device SSBOCol& v_29, device SSBORow& v_41) v_41.row_major0[1][1] = v_29.col_major0[1].y; } +static inline __attribute__((always_inline)) void copy_elements(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0[0].y = v_41.row_major0[1u][0]; diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-2x2-std140.comp b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-2x2-std140.comp index e499066faa..1e23ce3723 100644 --- a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-2x2-std140.comp +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-2x2-std140.comp @@ -17,6 +17,9 @@ struct SSBORow float2x4 row_major1; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + +static inline __attribute__((always_inline)) void load_store_to_variable_col_major(device SSBOCol& v_29) { float2x2 loaded = float2x2(v_29.col_major0[0].xy, v_29.col_major0[1].xy); @@ -24,6 +27,7 @@ void load_store_to_variable_col_major(device SSBOCol& v_29) v_29.col_major1[1].xy = loaded[1]; } +static inline __attribute__((always_inline)) void load_store_to_variable_row_major(device SSBORow& v_41) { float2x2 loaded = transpose(float2x2(v_41.row_major0[0].xy, v_41.row_major0[1].xy)); @@ -31,30 +35,35 @@ void load_store_to_variable_row_major(device SSBORow& v_41) v_41.row_major0[1].xy = float2(loaded[0][1], loaded[1][1]); } +static inline __attribute__((always_inline)) void copy_col_major_to_col_major(device SSBOCol& v_29) { v_29.col_major0[0].xy = float2x2(v_29.col_major1[0].xy, v_29.col_major1[1].xy)[0]; v_29.col_major0[1].xy = float2x2(v_29.col_major1[0].xy, v_29.col_major1[1].xy)[1]; } +static inline __attribute__((always_inline)) void copy_col_major_to_row_major(device SSBOCol& v_29, device SSBORow& v_41) { v_41.row_major0[0].xy = float2(float2x2(v_29.col_major0[0].xy, v_29.col_major0[1].xy)[0][0], float2x2(v_29.col_major0[0].xy, v_29.col_major0[1].xy)[1][0]); v_41.row_major0[1].xy = float2(float2x2(v_29.col_major0[0].xy, v_29.col_major0[1].xy)[0][1], float2x2(v_29.col_major0[0].xy, v_29.col_major0[1].xy)[1][1]); } +static inline __attribute__((always_inline)) void copy_row_major_to_col_major(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0[0].xy = float2(float2x2(v_41.row_major0[0].xy, v_41.row_major0[1].xy)[0][0], float2x2(v_41.row_major0[0].xy, v_41.row_major0[1].xy)[1][0]); v_29.col_major0[1].xy = float2(float2x2(v_41.row_major0[0].xy, v_41.row_major0[1].xy)[0][1], float2x2(v_41.row_major0[0].xy, v_41.row_major0[1].xy)[1][1]); } +static inline __attribute__((always_inline)) void copy_row_major_to_row_major(device SSBORow& v_41) { v_41.row_major0[0].xy = float2x2(v_41.row_major1[0].xy, v_41.row_major1[1].xy)[0]; v_41.row_major0[1].xy = float2x2(v_41.row_major1[0].xy, v_41.row_major1[1].xy)[1]; } +static inline __attribute__((always_inline)) void copy_columns(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0[1].xy = float2(v_41.row_major0[0][1], v_41.row_major0[1][1]); @@ -62,6 +71,7 @@ void copy_columns(device SSBOCol& v_29, device SSBORow& v_41) v_41.row_major0[1][1] = v_29.col_major0[1].y; } +static inline __attribute__((always_inline)) void copy_elements(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0[0].y = v_41.row_major0[1u][0]; diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-2x2-std430.comp b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-2x2-std430.comp index a0fdf9d91c..d1bdd47f55 100644 --- a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-2x2-std430.comp +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-2x2-std430.comp @@ -17,38 +17,47 @@ struct SSBORow float2x2 row_major1; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + +static inline __attribute__((always_inline)) void load_store_to_variable_col_major(device SSBOCol& v_29) { float2x2 loaded = v_29.col_major0; v_29.col_major1 = loaded; } +static inline __attribute__((always_inline)) void load_store_to_variable_row_major(device SSBORow& v_41) { float2x2 loaded = transpose(v_41.row_major0); v_41.row_major0 = transpose(loaded); } +static inline __attribute__((always_inline)) void copy_col_major_to_col_major(device SSBOCol& v_29) { v_29.col_major0 = v_29.col_major1; } +static inline __attribute__((always_inline)) void copy_col_major_to_row_major(device SSBOCol& v_29, device SSBORow& v_41) { v_41.row_major0 = transpose(v_29.col_major0); } +static inline __attribute__((always_inline)) void copy_row_major_to_col_major(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0 = transpose(v_41.row_major0); } +static inline __attribute__((always_inline)) void copy_row_major_to_row_major(device SSBORow& v_41) { v_41.row_major0 = v_41.row_major1; } +static inline __attribute__((always_inline)) void copy_columns(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0[1] = float2(v_41.row_major0[0][1], v_41.row_major0[1][1]); @@ -56,6 +65,7 @@ void copy_columns(device SSBOCol& v_29, device SSBORow& v_41) v_41.row_major0[1][1] = v_29.col_major0[1].y; } +static inline __attribute__((always_inline)) void copy_elements(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0[0].y = v_41.row_major0[1u][0]; diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-2x3-scalar.comp b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-2x3-scalar.comp index 8c4b5617cd..cf32149247 100644 --- a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-2x3-scalar.comp +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-2x3-scalar.comp @@ -19,6 +19,9 @@ struct SSBORow float3x2 row_major1; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + +static inline __attribute__((always_inline)) void load_store_to_variable_col_major(device SSBOCol& v_29) { float2x3 loaded = float2x3(float3(v_29.col_major0[0]), float3(v_29.col_major0[1])); @@ -26,34 +29,40 @@ void load_store_to_variable_col_major(device SSBOCol& v_29) v_29.col_major1[1] = loaded[1]; } +static inline __attribute__((always_inline)) void load_store_to_variable_row_major(device SSBORow& v_41) { float2x3 loaded = transpose(v_41.row_major0); v_41.row_major0 = transpose(loaded); } +static inline __attribute__((always_inline)) void copy_col_major_to_col_major(device SSBOCol& v_29) { v_29.col_major0[0] = float2x3(float3(v_29.col_major1[0]), float3(v_29.col_major1[1]))[0]; v_29.col_major0[1] = float2x3(float3(v_29.col_major1[0]), float3(v_29.col_major1[1]))[1]; } +static inline __attribute__((always_inline)) void copy_col_major_to_row_major(device SSBOCol& v_29, device SSBORow& v_41) { v_41.row_major0 = transpose(float2x3(float3(v_29.col_major0[0]), float3(v_29.col_major0[1]))); } +static inline __attribute__((always_inline)) void copy_row_major_to_col_major(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0[0] = float3(v_41.row_major0[0][0], v_41.row_major0[1][0], v_41.row_major0[2][0]); v_29.col_major0[1] = float3(v_41.row_major0[0][1], v_41.row_major0[1][1], v_41.row_major0[2][1]); } +static inline __attribute__((always_inline)) void copy_row_major_to_row_major(device SSBORow& v_41) { v_41.row_major0 = v_41.row_major1; } +static inline __attribute__((always_inline)) void copy_columns(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0[1] = float3(v_41.row_major0[0][1], v_41.row_major0[1][1], v_41.row_major0[2][1]); @@ -62,6 +71,7 @@ void copy_columns(device SSBOCol& v_29, device SSBORow& v_41) v_41.row_major0[2][1] = v_29.col_major0[1][2]; } +static inline __attribute__((always_inline)) void copy_elements(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0[0][1u] = v_41.row_major0[1u][0]; diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-2x3-std140.comp b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-2x3-std140.comp index d04df10a62..c94069fed6 100644 --- a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-2x3-std140.comp +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-2x3-std140.comp @@ -17,12 +17,16 @@ struct SSBORow float3x4 row_major1; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + +static inline __attribute__((always_inline)) void load_store_to_variable_col_major(device SSBOCol& v_29) { float2x3 loaded = v_29.col_major0; v_29.col_major1 = loaded; } +static inline __attribute__((always_inline)) void load_store_to_variable_row_major(device SSBORow& v_41) { float2x3 loaded = transpose(float3x2(v_41.row_major0[0].xy, v_41.row_major0[1].xy, v_41.row_major0[2].xy)); @@ -31,11 +35,13 @@ void load_store_to_variable_row_major(device SSBORow& v_41) v_41.row_major0[2].xy = float2(loaded[0][2], loaded[1][2]); } +static inline __attribute__((always_inline)) void copy_col_major_to_col_major(device SSBOCol& v_29) { v_29.col_major0 = v_29.col_major1; } +static inline __attribute__((always_inline)) void copy_col_major_to_row_major(device SSBOCol& v_29, device SSBORow& v_41) { v_41.row_major0[0].xy = float2(v_29.col_major0[0][0], v_29.col_major0[1][0]); @@ -43,11 +49,13 @@ void copy_col_major_to_row_major(device SSBOCol& v_29, device SSBORow& v_41) v_41.row_major0[2].xy = float2(v_29.col_major0[0][2], v_29.col_major0[1][2]); } +static inline __attribute__((always_inline)) void copy_row_major_to_col_major(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0 = transpose(float3x2(v_41.row_major0[0].xy, v_41.row_major0[1].xy, v_41.row_major0[2].xy)); } +static inline __attribute__((always_inline)) void copy_row_major_to_row_major(device SSBORow& v_41) { v_41.row_major0[0].xy = float3x2(v_41.row_major1[0].xy, v_41.row_major1[1].xy, v_41.row_major1[2].xy)[0]; @@ -55,6 +63,7 @@ void copy_row_major_to_row_major(device SSBORow& v_41) v_41.row_major0[2].xy = float3x2(v_41.row_major1[0].xy, v_41.row_major1[1].xy, v_41.row_major1[2].xy)[2]; } +static inline __attribute__((always_inline)) void copy_columns(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0[1] = float3(v_41.row_major0[0][1], v_41.row_major0[1][1], v_41.row_major0[2][1]); @@ -63,6 +72,7 @@ void copy_columns(device SSBOCol& v_29, device SSBORow& v_41) v_41.row_major0[2][1] = v_29.col_major0[1].z; } +static inline __attribute__((always_inline)) void copy_elements(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0[0].y = v_41.row_major0[1u][0]; diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-2x3-std430.comp b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-2x3-std430.comp index b86de34756..6263c058ed 100644 --- a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-2x3-std430.comp +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-2x3-std430.comp @@ -17,38 +17,47 @@ struct SSBORow float3x2 row_major1; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + +static inline __attribute__((always_inline)) void load_store_to_variable_col_major(device SSBOCol& v_29) { float2x3 loaded = v_29.col_major0; v_29.col_major1 = loaded; } +static inline __attribute__((always_inline)) void load_store_to_variable_row_major(device SSBORow& v_41) { float2x3 loaded = transpose(v_41.row_major0); v_41.row_major0 = transpose(loaded); } +static inline __attribute__((always_inline)) void copy_col_major_to_col_major(device SSBOCol& v_29) { v_29.col_major0 = v_29.col_major1; } +static inline __attribute__((always_inline)) void copy_col_major_to_row_major(device SSBOCol& v_29, device SSBORow& v_41) { v_41.row_major0 = transpose(v_29.col_major0); } +static inline __attribute__((always_inline)) void copy_row_major_to_col_major(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0 = transpose(v_41.row_major0); } +static inline __attribute__((always_inline)) void copy_row_major_to_row_major(device SSBORow& v_41) { v_41.row_major0 = v_41.row_major1; } +static inline __attribute__((always_inline)) void copy_columns(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0[1] = float3(v_41.row_major0[0][1], v_41.row_major0[1][1], v_41.row_major0[2][1]); @@ -57,6 +66,7 @@ void copy_columns(device SSBOCol& v_29, device SSBORow& v_41) v_41.row_major0[2][1] = v_29.col_major0[1].z; } +static inline __attribute__((always_inline)) void copy_elements(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0[0].y = v_41.row_major0[1u][0]; diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-2x4-scalar.comp b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-2x4-scalar.comp index 2498d6b261..cea5620ab6 100644 --- a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-2x4-scalar.comp +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-2x4-scalar.comp @@ -17,38 +17,47 @@ struct SSBORow float4x2 row_major1; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + +static inline __attribute__((always_inline)) void load_store_to_variable_col_major(device SSBOCol& v_29) { float2x4 loaded = v_29.col_major0; v_29.col_major1 = loaded; } +static inline __attribute__((always_inline)) void load_store_to_variable_row_major(device SSBORow& v_41) { float2x4 loaded = transpose(v_41.row_major0); v_41.row_major0 = transpose(loaded); } +static inline __attribute__((always_inline)) void copy_col_major_to_col_major(device SSBOCol& v_29) { v_29.col_major0 = v_29.col_major1; } +static inline __attribute__((always_inline)) void copy_col_major_to_row_major(device SSBOCol& v_29, device SSBORow& v_41) { v_41.row_major0 = transpose(v_29.col_major0); } +static inline __attribute__((always_inline)) void copy_row_major_to_col_major(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0 = transpose(v_41.row_major0); } +static inline __attribute__((always_inline)) void copy_row_major_to_row_major(device SSBORow& v_41) { v_41.row_major0 = v_41.row_major1; } +static inline __attribute__((always_inline)) void copy_columns(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0[1] = float4(v_41.row_major0[0][1], v_41.row_major0[1][1], v_41.row_major0[2][1], v_41.row_major0[3][1]); @@ -58,6 +67,7 @@ void copy_columns(device SSBOCol& v_29, device SSBORow& v_41) v_41.row_major0[3][1] = v_29.col_major0[1].w; } +static inline __attribute__((always_inline)) void copy_elements(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0[0].y = v_41.row_major0[1u][0]; diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-2x4-std140.comp b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-2x4-std140.comp index 9d78295c8f..2227048342 100644 --- a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-2x4-std140.comp +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-2x4-std140.comp @@ -17,12 +17,16 @@ struct SSBORow float4x4 row_major1; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + +static inline __attribute__((always_inline)) void load_store_to_variable_col_major(device SSBOCol& v_29) { float2x4 loaded = v_29.col_major0; v_29.col_major1 = loaded; } +static inline __attribute__((always_inline)) void load_store_to_variable_row_major(device SSBORow& v_41) { float2x4 loaded = transpose(float4x2(v_41.row_major0[0].xy, v_41.row_major0[1].xy, v_41.row_major0[2].xy, v_41.row_major0[3].xy)); @@ -32,11 +36,13 @@ void load_store_to_variable_row_major(device SSBORow& v_41) v_41.row_major0[3].xy = float2(loaded[0][3], loaded[1][3]); } +static inline __attribute__((always_inline)) void copy_col_major_to_col_major(device SSBOCol& v_29) { v_29.col_major0 = v_29.col_major1; } +static inline __attribute__((always_inline)) void copy_col_major_to_row_major(device SSBOCol& v_29, device SSBORow& v_41) { v_41.row_major0[0].xy = float2(v_29.col_major0[0][0], v_29.col_major0[1][0]); @@ -45,11 +51,13 @@ void copy_col_major_to_row_major(device SSBOCol& v_29, device SSBORow& v_41) v_41.row_major0[3].xy = float2(v_29.col_major0[0][3], v_29.col_major0[1][3]); } +static inline __attribute__((always_inline)) void copy_row_major_to_col_major(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0 = transpose(float4x2(v_41.row_major0[0].xy, v_41.row_major0[1].xy, v_41.row_major0[2].xy, v_41.row_major0[3].xy)); } +static inline __attribute__((always_inline)) void copy_row_major_to_row_major(device SSBORow& v_41) { v_41.row_major0[0].xy = float4x2(v_41.row_major1[0].xy, v_41.row_major1[1].xy, v_41.row_major1[2].xy, v_41.row_major1[3].xy)[0]; @@ -58,6 +66,7 @@ void copy_row_major_to_row_major(device SSBORow& v_41) v_41.row_major0[3].xy = float4x2(v_41.row_major1[0].xy, v_41.row_major1[1].xy, v_41.row_major1[2].xy, v_41.row_major1[3].xy)[3]; } +static inline __attribute__((always_inline)) void copy_columns(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0[1] = float4(v_41.row_major0[0][1], v_41.row_major0[1][1], v_41.row_major0[2][1], v_41.row_major0[3][1]); @@ -67,6 +76,7 @@ void copy_columns(device SSBOCol& v_29, device SSBORow& v_41) v_41.row_major0[3][1] = v_29.col_major0[1].w; } +static inline __attribute__((always_inline)) void copy_elements(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0[0].y = v_41.row_major0[1u][0]; diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-2x4-std430.comp b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-2x4-std430.comp index 2498d6b261..cea5620ab6 100644 --- a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-2x4-std430.comp +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-2x4-std430.comp @@ -17,38 +17,47 @@ struct SSBORow float4x2 row_major1; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + +static inline __attribute__((always_inline)) void load_store_to_variable_col_major(device SSBOCol& v_29) { float2x4 loaded = v_29.col_major0; v_29.col_major1 = loaded; } +static inline __attribute__((always_inline)) void load_store_to_variable_row_major(device SSBORow& v_41) { float2x4 loaded = transpose(v_41.row_major0); v_41.row_major0 = transpose(loaded); } +static inline __attribute__((always_inline)) void copy_col_major_to_col_major(device SSBOCol& v_29) { v_29.col_major0 = v_29.col_major1; } +static inline __attribute__((always_inline)) void copy_col_major_to_row_major(device SSBOCol& v_29, device SSBORow& v_41) { v_41.row_major0 = transpose(v_29.col_major0); } +static inline __attribute__((always_inline)) void copy_row_major_to_col_major(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0 = transpose(v_41.row_major0); } +static inline __attribute__((always_inline)) void copy_row_major_to_row_major(device SSBORow& v_41) { v_41.row_major0 = v_41.row_major1; } +static inline __attribute__((always_inline)) void copy_columns(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0[1] = float4(v_41.row_major0[0][1], v_41.row_major0[1][1], v_41.row_major0[2][1], v_41.row_major0[3][1]); @@ -58,6 +67,7 @@ void copy_columns(device SSBOCol& v_29, device SSBORow& v_41) v_41.row_major0[3][1] = v_29.col_major0[1].w; } +static inline __attribute__((always_inline)) void copy_elements(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0[0].y = v_41.row_major0[1u][0]; diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-3x2-scalar.comp b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-3x2-scalar.comp index d917a91c4b..4cbd0bd2a0 100644 --- a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-3x2-scalar.comp +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-3x2-scalar.comp @@ -19,12 +19,16 @@ struct SSBORow packed_rm_float3x2 row_major1; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + +static inline __attribute__((always_inline)) void load_store_to_variable_col_major(device SSBOCol& v_29) { float3x2 loaded = v_29.col_major0; v_29.col_major1 = loaded; } +static inline __attribute__((always_inline)) void load_store_to_variable_row_major(device SSBORow& v_41) { float3x2 loaded = transpose(float2x3(float3(v_41.row_major0[0]), float3(v_41.row_major0[1]))); @@ -32,28 +36,33 @@ void load_store_to_variable_row_major(device SSBORow& v_41) v_41.row_major0[1] = float3(loaded[0][1], loaded[1][1], loaded[2][1]); } +static inline __attribute__((always_inline)) void copy_col_major_to_col_major(device SSBOCol& v_29) { v_29.col_major0 = v_29.col_major1; } +static inline __attribute__((always_inline)) void copy_col_major_to_row_major(device SSBOCol& v_29, device SSBORow& v_41) { v_41.row_major0[0] = float3(v_29.col_major0[0][0], v_29.col_major0[1][0], v_29.col_major0[2][0]); v_41.row_major0[1] = float3(v_29.col_major0[0][1], v_29.col_major0[1][1], v_29.col_major0[2][1]); } +static inline __attribute__((always_inline)) void copy_row_major_to_col_major(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0 = transpose(float2x3(float3(v_41.row_major0[0]), float3(v_41.row_major0[1]))); } +static inline __attribute__((always_inline)) void copy_row_major_to_row_major(device SSBORow& v_41) { v_41.row_major0[0] = float2x3(float3(v_41.row_major1[0]), float3(v_41.row_major1[1]))[0]; v_41.row_major0[1] = float2x3(float3(v_41.row_major1[0]), float3(v_41.row_major1[1]))[1]; } +static inline __attribute__((always_inline)) void copy_columns(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0[1] = float2(v_41.row_major0[0][1], v_41.row_major0[1][1]); @@ -61,6 +70,7 @@ void copy_columns(device SSBOCol& v_29, device SSBORow& v_41) v_41.row_major0[1][1] = v_29.col_major0[1].y; } +static inline __attribute__((always_inline)) void copy_elements(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0[0].y = v_41.row_major0[1u][0]; diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-3x2-std140.comp b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-3x2-std140.comp index eaa725cf5c..5a74c07289 100644 --- a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-3x2-std140.comp +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-3x2-std140.comp @@ -17,6 +17,9 @@ struct SSBORow float2x3 row_major1; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + +static inline __attribute__((always_inline)) void load_store_to_variable_col_major(device SSBOCol& v_29) { float3x2 loaded = float3x2(v_29.col_major0[0].xy, v_29.col_major0[1].xy, v_29.col_major0[2].xy); @@ -25,12 +28,14 @@ void load_store_to_variable_col_major(device SSBOCol& v_29) v_29.col_major1[2].xy = loaded[2]; } +static inline __attribute__((always_inline)) void load_store_to_variable_row_major(device SSBORow& v_41) { float3x2 loaded = transpose(v_41.row_major0); v_41.row_major0 = transpose(loaded); } +static inline __attribute__((always_inline)) void copy_col_major_to_col_major(device SSBOCol& v_29) { v_29.col_major0[0].xy = float3x2(v_29.col_major1[0].xy, v_29.col_major1[1].xy, v_29.col_major1[2].xy)[0]; @@ -38,11 +43,13 @@ void copy_col_major_to_col_major(device SSBOCol& v_29) v_29.col_major0[2].xy = float3x2(v_29.col_major1[0].xy, v_29.col_major1[1].xy, v_29.col_major1[2].xy)[2]; } +static inline __attribute__((always_inline)) void copy_col_major_to_row_major(device SSBOCol& v_29, device SSBORow& v_41) { v_41.row_major0 = transpose(float3x2(v_29.col_major0[0].xy, v_29.col_major0[1].xy, v_29.col_major0[2].xy)); } +static inline __attribute__((always_inline)) void copy_row_major_to_col_major(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0[0].xy = float2(v_41.row_major0[0][0], v_41.row_major0[1][0]); @@ -50,11 +57,13 @@ void copy_row_major_to_col_major(device SSBOCol& v_29, device SSBORow& v_41) v_29.col_major0[2].xy = float2(v_41.row_major0[0][2], v_41.row_major0[1][2]); } +static inline __attribute__((always_inline)) void copy_row_major_to_row_major(device SSBORow& v_41) { v_41.row_major0 = v_41.row_major1; } +static inline __attribute__((always_inline)) void copy_columns(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0[1].xy = float2(v_41.row_major0[0][1], v_41.row_major0[1][1]); @@ -62,6 +71,7 @@ void copy_columns(device SSBOCol& v_29, device SSBORow& v_41) v_41.row_major0[1][1] = v_29.col_major0[1].y; } +static inline __attribute__((always_inline)) void copy_elements(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0[0].y = v_41.row_major0[1u][0]; diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-3x2-std430.comp b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-3x2-std430.comp index 04bd790bef..77a419c4db 100644 --- a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-3x2-std430.comp +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-3x2-std430.comp @@ -17,38 +17,47 @@ struct SSBORow float2x3 row_major1; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + +static inline __attribute__((always_inline)) void load_store_to_variable_col_major(device SSBOCol& v_29) { float3x2 loaded = v_29.col_major0; v_29.col_major1 = loaded; } +static inline __attribute__((always_inline)) void load_store_to_variable_row_major(device SSBORow& v_41) { float3x2 loaded = transpose(v_41.row_major0); v_41.row_major0 = transpose(loaded); } +static inline __attribute__((always_inline)) void copy_col_major_to_col_major(device SSBOCol& v_29) { v_29.col_major0 = v_29.col_major1; } +static inline __attribute__((always_inline)) void copy_col_major_to_row_major(device SSBOCol& v_29, device SSBORow& v_41) { v_41.row_major0 = transpose(v_29.col_major0); } +static inline __attribute__((always_inline)) void copy_row_major_to_col_major(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0 = transpose(v_41.row_major0); } +static inline __attribute__((always_inline)) void copy_row_major_to_row_major(device SSBORow& v_41) { v_41.row_major0 = v_41.row_major1; } +static inline __attribute__((always_inline)) void copy_columns(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0[1] = float2(v_41.row_major0[0][1], v_41.row_major0[1][1]); @@ -56,6 +65,7 @@ void copy_columns(device SSBOCol& v_29, device SSBORow& v_41) v_41.row_major0[1][1] = v_29.col_major0[1].y; } +static inline __attribute__((always_inline)) void copy_elements(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0[0].y = v_41.row_major0[1u][0]; diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-3x3-scalar.comp b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-3x3-scalar.comp index 42d285e335..8701e96eaa 100644 --- a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-3x3-scalar.comp +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-3x3-scalar.comp @@ -20,6 +20,9 @@ struct SSBORow packed_rm_float3x3 row_major1; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + +static inline __attribute__((always_inline)) void load_store_to_variable_col_major(device SSBOCol& v_29) { float3x3 loaded = float3x3(float3(v_29.col_major0[0]), float3(v_29.col_major0[1]), float3(v_29.col_major0[2])); @@ -28,6 +31,7 @@ void load_store_to_variable_col_major(device SSBOCol& v_29) v_29.col_major1[2] = loaded[2]; } +static inline __attribute__((always_inline)) void load_store_to_variable_row_major(device SSBORow& v_41) { float3x3 loaded = transpose(float3x3(float3(v_41.row_major0[0]), float3(v_41.row_major0[1]), float3(v_41.row_major0[2]))); @@ -36,6 +40,7 @@ void load_store_to_variable_row_major(device SSBORow& v_41) v_41.row_major0[2] = float3(loaded[0][2], loaded[1][2], loaded[2][2]); } +static inline __attribute__((always_inline)) void copy_col_major_to_col_major(device SSBOCol& v_29) { v_29.col_major0[0] = float3x3(float3(v_29.col_major1[0]), float3(v_29.col_major1[1]), float3(v_29.col_major1[2]))[0]; @@ -43,6 +48,7 @@ void copy_col_major_to_col_major(device SSBOCol& v_29) v_29.col_major0[2] = float3x3(float3(v_29.col_major1[0]), float3(v_29.col_major1[1]), float3(v_29.col_major1[2]))[2]; } +static inline __attribute__((always_inline)) void copy_col_major_to_row_major(device SSBOCol& v_29, device SSBORow& v_41) { v_41.row_major0[0] = float3(float3x3(float3(v_29.col_major0[0]), float3(v_29.col_major0[1]), float3(v_29.col_major0[2]))[0][0], float3x3(float3(v_29.col_major0[0]), float3(v_29.col_major0[1]), float3(v_29.col_major0[2]))[1][0], float3x3(float3(v_29.col_major0[0]), float3(v_29.col_major0[1]), float3(v_29.col_major0[2]))[2][0]); @@ -50,6 +56,7 @@ void copy_col_major_to_row_major(device SSBOCol& v_29, device SSBORow& v_41) v_41.row_major0[2] = float3(float3x3(float3(v_29.col_major0[0]), float3(v_29.col_major0[1]), float3(v_29.col_major0[2]))[0][2], float3x3(float3(v_29.col_major0[0]), float3(v_29.col_major0[1]), float3(v_29.col_major0[2]))[1][2], float3x3(float3(v_29.col_major0[0]), float3(v_29.col_major0[1]), float3(v_29.col_major0[2]))[2][2]); } +static inline __attribute__((always_inline)) void copy_row_major_to_col_major(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0[0] = float3(float3x3(float3(v_41.row_major0[0]), float3(v_41.row_major0[1]), float3(v_41.row_major0[2]))[0][0], float3x3(float3(v_41.row_major0[0]), float3(v_41.row_major0[1]), float3(v_41.row_major0[2]))[1][0], float3x3(float3(v_41.row_major0[0]), float3(v_41.row_major0[1]), float3(v_41.row_major0[2]))[2][0]); @@ -57,6 +64,7 @@ void copy_row_major_to_col_major(device SSBOCol& v_29, device SSBORow& v_41) v_29.col_major0[2] = float3(float3x3(float3(v_41.row_major0[0]), float3(v_41.row_major0[1]), float3(v_41.row_major0[2]))[0][2], float3x3(float3(v_41.row_major0[0]), float3(v_41.row_major0[1]), float3(v_41.row_major0[2]))[1][2], float3x3(float3(v_41.row_major0[0]), float3(v_41.row_major0[1]), float3(v_41.row_major0[2]))[2][2]); } +static inline __attribute__((always_inline)) void copy_row_major_to_row_major(device SSBORow& v_41) { v_41.row_major0[0] = float3x3(float3(v_41.row_major1[0]), float3(v_41.row_major1[1]), float3(v_41.row_major1[2]))[0]; @@ -64,6 +72,7 @@ void copy_row_major_to_row_major(device SSBORow& v_41) v_41.row_major0[2] = float3x3(float3(v_41.row_major1[0]), float3(v_41.row_major1[1]), float3(v_41.row_major1[2]))[2]; } +static inline __attribute__((always_inline)) void copy_columns(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0[1] = float3(v_41.row_major0[0][1], v_41.row_major0[1][1], v_41.row_major0[2][1]); @@ -72,6 +81,7 @@ void copy_columns(device SSBOCol& v_29, device SSBORow& v_41) v_41.row_major0[2][1] = v_29.col_major0[1][2]; } +static inline __attribute__((always_inline)) void copy_elements(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0[0][1u] = v_41.row_major0[1u][0]; diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-3x3-std140.comp b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-3x3-std140.comp index ceff01e420..2551c023c6 100644 --- a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-3x3-std140.comp +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-3x3-std140.comp @@ -17,38 +17,47 @@ struct SSBORow float3x3 row_major1; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + +static inline __attribute__((always_inline)) void load_store_to_variable_col_major(device SSBOCol& v_29) { float3x3 loaded = v_29.col_major0; v_29.col_major1 = loaded; } +static inline __attribute__((always_inline)) void load_store_to_variable_row_major(device SSBORow& v_41) { float3x3 loaded = transpose(v_41.row_major0); v_41.row_major0 = transpose(loaded); } +static inline __attribute__((always_inline)) void copy_col_major_to_col_major(device SSBOCol& v_29) { v_29.col_major0 = v_29.col_major1; } +static inline __attribute__((always_inline)) void copy_col_major_to_row_major(device SSBOCol& v_29, device SSBORow& v_41) { v_41.row_major0 = transpose(v_29.col_major0); } +static inline __attribute__((always_inline)) void copy_row_major_to_col_major(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0 = transpose(v_41.row_major0); } +static inline __attribute__((always_inline)) void copy_row_major_to_row_major(device SSBORow& v_41) { v_41.row_major0 = v_41.row_major1; } +static inline __attribute__((always_inline)) void copy_columns(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0[1] = float3(v_41.row_major0[0][1], v_41.row_major0[1][1], v_41.row_major0[2][1]); @@ -57,6 +66,7 @@ void copy_columns(device SSBOCol& v_29, device SSBORow& v_41) v_41.row_major0[2][1] = v_29.col_major0[1].z; } +static inline __attribute__((always_inline)) void copy_elements(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0[0].y = v_41.row_major0[1u][0]; diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-3x3-std430.comp b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-3x3-std430.comp index ceff01e420..2551c023c6 100644 --- a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-3x3-std430.comp +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-3x3-std430.comp @@ -17,38 +17,47 @@ struct SSBORow float3x3 row_major1; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + +static inline __attribute__((always_inline)) void load_store_to_variable_col_major(device SSBOCol& v_29) { float3x3 loaded = v_29.col_major0; v_29.col_major1 = loaded; } +static inline __attribute__((always_inline)) void load_store_to_variable_row_major(device SSBORow& v_41) { float3x3 loaded = transpose(v_41.row_major0); v_41.row_major0 = transpose(loaded); } +static inline __attribute__((always_inline)) void copy_col_major_to_col_major(device SSBOCol& v_29) { v_29.col_major0 = v_29.col_major1; } +static inline __attribute__((always_inline)) void copy_col_major_to_row_major(device SSBOCol& v_29, device SSBORow& v_41) { v_41.row_major0 = transpose(v_29.col_major0); } +static inline __attribute__((always_inline)) void copy_row_major_to_col_major(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0 = transpose(v_41.row_major0); } +static inline __attribute__((always_inline)) void copy_row_major_to_row_major(device SSBORow& v_41) { v_41.row_major0 = v_41.row_major1; } +static inline __attribute__((always_inline)) void copy_columns(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0[1] = float3(v_41.row_major0[0][1], v_41.row_major0[1][1], v_41.row_major0[2][1]); @@ -57,6 +66,7 @@ void copy_columns(device SSBOCol& v_29, device SSBORow& v_41) v_41.row_major0[2][1] = v_29.col_major0[1].z; } +static inline __attribute__((always_inline)) void copy_elements(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0[0].y = v_41.row_major0[1u][0]; diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-3x4-scalar.comp b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-3x4-scalar.comp index c7b1b32618..32dafdd088 100644 --- a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-3x4-scalar.comp +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-3x4-scalar.comp @@ -19,12 +19,16 @@ struct SSBORow packed_rm_float3x4 row_major1; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + +static inline __attribute__((always_inline)) void load_store_to_variable_col_major(device SSBOCol& v_29) { float3x4 loaded = v_29.col_major0; v_29.col_major1 = loaded; } +static inline __attribute__((always_inline)) void load_store_to_variable_row_major(device SSBORow& v_41) { float3x4 loaded = transpose(float4x3(float3(v_41.row_major0[0]), float3(v_41.row_major0[1]), float3(v_41.row_major0[2]), float3(v_41.row_major0[3]))); @@ -34,11 +38,13 @@ void load_store_to_variable_row_major(device SSBORow& v_41) v_41.row_major0[3] = float3(loaded[0][3], loaded[1][3], loaded[2][3]); } +static inline __attribute__((always_inline)) void copy_col_major_to_col_major(device SSBOCol& v_29) { v_29.col_major0 = v_29.col_major1; } +static inline __attribute__((always_inline)) void copy_col_major_to_row_major(device SSBOCol& v_29, device SSBORow& v_41) { v_41.row_major0[0] = float3(v_29.col_major0[0][0], v_29.col_major0[1][0], v_29.col_major0[2][0]); @@ -47,11 +53,13 @@ void copy_col_major_to_row_major(device SSBOCol& v_29, device SSBORow& v_41) v_41.row_major0[3] = float3(v_29.col_major0[0][3], v_29.col_major0[1][3], v_29.col_major0[2][3]); } +static inline __attribute__((always_inline)) void copy_row_major_to_col_major(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0 = transpose(float4x3(float3(v_41.row_major0[0]), float3(v_41.row_major0[1]), float3(v_41.row_major0[2]), float3(v_41.row_major0[3]))); } +static inline __attribute__((always_inline)) void copy_row_major_to_row_major(device SSBORow& v_41) { v_41.row_major0[0] = float4x3(float3(v_41.row_major1[0]), float3(v_41.row_major1[1]), float3(v_41.row_major1[2]), float3(v_41.row_major1[3]))[0]; @@ -60,6 +68,7 @@ void copy_row_major_to_row_major(device SSBORow& v_41) v_41.row_major0[3] = float4x3(float3(v_41.row_major1[0]), float3(v_41.row_major1[1]), float3(v_41.row_major1[2]), float3(v_41.row_major1[3]))[3]; } +static inline __attribute__((always_inline)) void copy_columns(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0[1] = float4(v_41.row_major0[0][1], v_41.row_major0[1][1], v_41.row_major0[2][1], v_41.row_major0[3][1]); @@ -69,6 +78,7 @@ void copy_columns(device SSBOCol& v_29, device SSBORow& v_41) v_41.row_major0[3][1] = v_29.col_major0[1].w; } +static inline __attribute__((always_inline)) void copy_elements(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0[0].y = v_41.row_major0[1u][0]; diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-3x4-std140.comp b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-3x4-std140.comp index 9f6a20ed2d..e58cab0893 100644 --- a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-3x4-std140.comp +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-3x4-std140.comp @@ -17,38 +17,47 @@ struct SSBORow float4x3 row_major1; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + +static inline __attribute__((always_inline)) void load_store_to_variable_col_major(device SSBOCol& v_29) { float3x4 loaded = v_29.col_major0; v_29.col_major1 = loaded; } +static inline __attribute__((always_inline)) void load_store_to_variable_row_major(device SSBORow& v_41) { float3x4 loaded = transpose(v_41.row_major0); v_41.row_major0 = transpose(loaded); } +static inline __attribute__((always_inline)) void copy_col_major_to_col_major(device SSBOCol& v_29) { v_29.col_major0 = v_29.col_major1; } +static inline __attribute__((always_inline)) void copy_col_major_to_row_major(device SSBOCol& v_29, device SSBORow& v_41) { v_41.row_major0 = transpose(v_29.col_major0); } +static inline __attribute__((always_inline)) void copy_row_major_to_col_major(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0 = transpose(v_41.row_major0); } +static inline __attribute__((always_inline)) void copy_row_major_to_row_major(device SSBORow& v_41) { v_41.row_major0 = v_41.row_major1; } +static inline __attribute__((always_inline)) void copy_columns(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0[1] = float4(v_41.row_major0[0][1], v_41.row_major0[1][1], v_41.row_major0[2][1], v_41.row_major0[3][1]); @@ -58,6 +67,7 @@ void copy_columns(device SSBOCol& v_29, device SSBORow& v_41) v_41.row_major0[3][1] = v_29.col_major0[1].w; } +static inline __attribute__((always_inline)) void copy_elements(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0[0].y = v_41.row_major0[1u][0]; diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-3x4-std430.comp b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-3x4-std430.comp index 9f6a20ed2d..e58cab0893 100644 --- a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-3x4-std430.comp +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-3x4-std430.comp @@ -17,38 +17,47 @@ struct SSBORow float4x3 row_major1; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + +static inline __attribute__((always_inline)) void load_store_to_variable_col_major(device SSBOCol& v_29) { float3x4 loaded = v_29.col_major0; v_29.col_major1 = loaded; } +static inline __attribute__((always_inline)) void load_store_to_variable_row_major(device SSBORow& v_41) { float3x4 loaded = transpose(v_41.row_major0); v_41.row_major0 = transpose(loaded); } +static inline __attribute__((always_inline)) void copy_col_major_to_col_major(device SSBOCol& v_29) { v_29.col_major0 = v_29.col_major1; } +static inline __attribute__((always_inline)) void copy_col_major_to_row_major(device SSBOCol& v_29, device SSBORow& v_41) { v_41.row_major0 = transpose(v_29.col_major0); } +static inline __attribute__((always_inline)) void copy_row_major_to_col_major(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0 = transpose(v_41.row_major0); } +static inline __attribute__((always_inline)) void copy_row_major_to_row_major(device SSBORow& v_41) { v_41.row_major0 = v_41.row_major1; } +static inline __attribute__((always_inline)) void copy_columns(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0[1] = float4(v_41.row_major0[0][1], v_41.row_major0[1][1], v_41.row_major0[2][1], v_41.row_major0[3][1]); @@ -58,6 +67,7 @@ void copy_columns(device SSBOCol& v_29, device SSBORow& v_41) v_41.row_major0[3][1] = v_29.col_major0[1].w; } +static inline __attribute__((always_inline)) void copy_elements(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0[0].y = v_41.row_major0[1u][0]; diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-4x2-scalar.comp b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-4x2-scalar.comp index f863373e8a..f7ca929781 100644 --- a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-4x2-scalar.comp +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-4x2-scalar.comp @@ -17,38 +17,47 @@ struct SSBORow float2x4 row_major1; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + +static inline __attribute__((always_inline)) void load_store_to_variable_col_major(device SSBOCol& v_29) { float4x2 loaded = v_29.col_major0; v_29.col_major1 = loaded; } +static inline __attribute__((always_inline)) void load_store_to_variable_row_major(device SSBORow& v_41) { float4x2 loaded = transpose(v_41.row_major0); v_41.row_major0 = transpose(loaded); } +static inline __attribute__((always_inline)) void copy_col_major_to_col_major(device SSBOCol& v_29) { v_29.col_major0 = v_29.col_major1; } +static inline __attribute__((always_inline)) void copy_col_major_to_row_major(device SSBOCol& v_29, device SSBORow& v_41) { v_41.row_major0 = transpose(v_29.col_major0); } +static inline __attribute__((always_inline)) void copy_row_major_to_col_major(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0 = transpose(v_41.row_major0); } +static inline __attribute__((always_inline)) void copy_row_major_to_row_major(device SSBORow& v_41) { v_41.row_major0 = v_41.row_major1; } +static inline __attribute__((always_inline)) void copy_columns(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0[1] = float2(v_41.row_major0[0][1], v_41.row_major0[1][1]); @@ -56,6 +65,7 @@ void copy_columns(device SSBOCol& v_29, device SSBORow& v_41) v_41.row_major0[1][1] = v_29.col_major0[1].y; } +static inline __attribute__((always_inline)) void copy_elements(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0[0].y = v_41.row_major0[1u][0]; diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-4x2-std140.comp b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-4x2-std140.comp index 684cd82ee0..e5cca638e5 100644 --- a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-4x2-std140.comp +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-4x2-std140.comp @@ -17,6 +17,9 @@ struct SSBORow float2x4 row_major1; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + +static inline __attribute__((always_inline)) void load_store_to_variable_col_major(device SSBOCol& v_29) { float4x2 loaded = float4x2(v_29.col_major0[0].xy, v_29.col_major0[1].xy, v_29.col_major0[2].xy, v_29.col_major0[3].xy); @@ -26,12 +29,14 @@ void load_store_to_variable_col_major(device SSBOCol& v_29) v_29.col_major1[3].xy = loaded[3]; } +static inline __attribute__((always_inline)) void load_store_to_variable_row_major(device SSBORow& v_41) { float4x2 loaded = transpose(v_41.row_major0); v_41.row_major0 = transpose(loaded); } +static inline __attribute__((always_inline)) void copy_col_major_to_col_major(device SSBOCol& v_29) { v_29.col_major0[0].xy = float4x2(v_29.col_major1[0].xy, v_29.col_major1[1].xy, v_29.col_major1[2].xy, v_29.col_major1[3].xy)[0]; @@ -40,11 +45,13 @@ void copy_col_major_to_col_major(device SSBOCol& v_29) v_29.col_major0[3].xy = float4x2(v_29.col_major1[0].xy, v_29.col_major1[1].xy, v_29.col_major1[2].xy, v_29.col_major1[3].xy)[3]; } +static inline __attribute__((always_inline)) void copy_col_major_to_row_major(device SSBOCol& v_29, device SSBORow& v_41) { v_41.row_major0 = transpose(float4x2(v_29.col_major0[0].xy, v_29.col_major0[1].xy, v_29.col_major0[2].xy, v_29.col_major0[3].xy)); } +static inline __attribute__((always_inline)) void copy_row_major_to_col_major(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0[0].xy = float2(v_41.row_major0[0][0], v_41.row_major0[1][0]); @@ -53,11 +60,13 @@ void copy_row_major_to_col_major(device SSBOCol& v_29, device SSBORow& v_41) v_29.col_major0[3].xy = float2(v_41.row_major0[0][3], v_41.row_major0[1][3]); } +static inline __attribute__((always_inline)) void copy_row_major_to_row_major(device SSBORow& v_41) { v_41.row_major0 = v_41.row_major1; } +static inline __attribute__((always_inline)) void copy_columns(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0[1].xy = float2(v_41.row_major0[0][1], v_41.row_major0[1][1]); @@ -65,6 +74,7 @@ void copy_columns(device SSBOCol& v_29, device SSBORow& v_41) v_41.row_major0[1][1] = v_29.col_major0[1].y; } +static inline __attribute__((always_inline)) void copy_elements(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0[0].y = v_41.row_major0[1u][0]; diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-4x2-std430.comp b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-4x2-std430.comp index f863373e8a..f7ca929781 100644 --- a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-4x2-std430.comp +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-4x2-std430.comp @@ -17,38 +17,47 @@ struct SSBORow float2x4 row_major1; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + +static inline __attribute__((always_inline)) void load_store_to_variable_col_major(device SSBOCol& v_29) { float4x2 loaded = v_29.col_major0; v_29.col_major1 = loaded; } +static inline __attribute__((always_inline)) void load_store_to_variable_row_major(device SSBORow& v_41) { float4x2 loaded = transpose(v_41.row_major0); v_41.row_major0 = transpose(loaded); } +static inline __attribute__((always_inline)) void copy_col_major_to_col_major(device SSBOCol& v_29) { v_29.col_major0 = v_29.col_major1; } +static inline __attribute__((always_inline)) void copy_col_major_to_row_major(device SSBOCol& v_29, device SSBORow& v_41) { v_41.row_major0 = transpose(v_29.col_major0); } +static inline __attribute__((always_inline)) void copy_row_major_to_col_major(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0 = transpose(v_41.row_major0); } +static inline __attribute__((always_inline)) void copy_row_major_to_row_major(device SSBORow& v_41) { v_41.row_major0 = v_41.row_major1; } +static inline __attribute__((always_inline)) void copy_columns(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0[1] = float2(v_41.row_major0[0][1], v_41.row_major0[1][1]); @@ -56,6 +65,7 @@ void copy_columns(device SSBOCol& v_29, device SSBORow& v_41) v_41.row_major0[1][1] = v_29.col_major0[1].y; } +static inline __attribute__((always_inline)) void copy_elements(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0[0].y = v_41.row_major0[1u][0]; diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-4x3-scalar.comp b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-4x3-scalar.comp index 7f921db076..0655253505 100644 --- a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-4x3-scalar.comp +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-4x3-scalar.comp @@ -19,6 +19,9 @@ struct SSBORow float3x4 row_major1; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + +static inline __attribute__((always_inline)) void load_store_to_variable_col_major(device SSBOCol& v_29) { float4x3 loaded = float4x3(float3(v_29.col_major0[0]), float3(v_29.col_major0[1]), float3(v_29.col_major0[2]), float3(v_29.col_major0[3])); @@ -28,12 +31,14 @@ void load_store_to_variable_col_major(device SSBOCol& v_29) v_29.col_major1[3] = loaded[3]; } +static inline __attribute__((always_inline)) void load_store_to_variable_row_major(device SSBORow& v_41) { float4x3 loaded = transpose(v_41.row_major0); v_41.row_major0 = transpose(loaded); } +static inline __attribute__((always_inline)) void copy_col_major_to_col_major(device SSBOCol& v_29) { v_29.col_major0[0] = float4x3(float3(v_29.col_major1[0]), float3(v_29.col_major1[1]), float3(v_29.col_major1[2]), float3(v_29.col_major1[3]))[0]; @@ -42,11 +47,13 @@ void copy_col_major_to_col_major(device SSBOCol& v_29) v_29.col_major0[3] = float4x3(float3(v_29.col_major1[0]), float3(v_29.col_major1[1]), float3(v_29.col_major1[2]), float3(v_29.col_major1[3]))[3]; } +static inline __attribute__((always_inline)) void copy_col_major_to_row_major(device SSBOCol& v_29, device SSBORow& v_41) { v_41.row_major0 = transpose(float4x3(float3(v_29.col_major0[0]), float3(v_29.col_major0[1]), float3(v_29.col_major0[2]), float3(v_29.col_major0[3]))); } +static inline __attribute__((always_inline)) void copy_row_major_to_col_major(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0[0] = float3(v_41.row_major0[0][0], v_41.row_major0[1][0], v_41.row_major0[2][0]); @@ -55,11 +62,13 @@ void copy_row_major_to_col_major(device SSBOCol& v_29, device SSBORow& v_41) v_29.col_major0[3] = float3(v_41.row_major0[0][3], v_41.row_major0[1][3], v_41.row_major0[2][3]); } +static inline __attribute__((always_inline)) void copy_row_major_to_row_major(device SSBORow& v_41) { v_41.row_major0 = v_41.row_major1; } +static inline __attribute__((always_inline)) void copy_columns(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0[1] = float3(v_41.row_major0[0][1], v_41.row_major0[1][1], v_41.row_major0[2][1]); @@ -68,6 +77,7 @@ void copy_columns(device SSBOCol& v_29, device SSBORow& v_41) v_41.row_major0[2][1] = v_29.col_major0[1][2]; } +static inline __attribute__((always_inline)) void copy_elements(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0[0][1u] = v_41.row_major0[1u][0]; diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-4x3-std140.comp b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-4x3-std140.comp index 574f02e8dd..34420a46ba 100644 --- a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-4x3-std140.comp +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-4x3-std140.comp @@ -17,38 +17,47 @@ struct SSBORow float3x4 row_major1; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + +static inline __attribute__((always_inline)) void load_store_to_variable_col_major(device SSBOCol& v_29) { float4x3 loaded = v_29.col_major0; v_29.col_major1 = loaded; } +static inline __attribute__((always_inline)) void load_store_to_variable_row_major(device SSBORow& v_41) { float4x3 loaded = transpose(v_41.row_major0); v_41.row_major0 = transpose(loaded); } +static inline __attribute__((always_inline)) void copy_col_major_to_col_major(device SSBOCol& v_29) { v_29.col_major0 = v_29.col_major1; } +static inline __attribute__((always_inline)) void copy_col_major_to_row_major(device SSBOCol& v_29, device SSBORow& v_41) { v_41.row_major0 = transpose(v_29.col_major0); } +static inline __attribute__((always_inline)) void copy_row_major_to_col_major(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0 = transpose(v_41.row_major0); } +static inline __attribute__((always_inline)) void copy_row_major_to_row_major(device SSBORow& v_41) { v_41.row_major0 = v_41.row_major1; } +static inline __attribute__((always_inline)) void copy_columns(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0[1] = float3(v_41.row_major0[0][1], v_41.row_major0[1][1], v_41.row_major0[2][1]); @@ -57,6 +66,7 @@ void copy_columns(device SSBOCol& v_29, device SSBORow& v_41) v_41.row_major0[2][1] = v_29.col_major0[1].z; } +static inline __attribute__((always_inline)) void copy_elements(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0[0].y = v_41.row_major0[1u][0]; diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-4x3-std430.comp b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-4x3-std430.comp index 574f02e8dd..34420a46ba 100644 --- a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-4x3-std430.comp +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-4x3-std430.comp @@ -17,38 +17,47 @@ struct SSBORow float3x4 row_major1; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + +static inline __attribute__((always_inline)) void load_store_to_variable_col_major(device SSBOCol& v_29) { float4x3 loaded = v_29.col_major0; v_29.col_major1 = loaded; } +static inline __attribute__((always_inline)) void load_store_to_variable_row_major(device SSBORow& v_41) { float4x3 loaded = transpose(v_41.row_major0); v_41.row_major0 = transpose(loaded); } +static inline __attribute__((always_inline)) void copy_col_major_to_col_major(device SSBOCol& v_29) { v_29.col_major0 = v_29.col_major1; } +static inline __attribute__((always_inline)) void copy_col_major_to_row_major(device SSBOCol& v_29, device SSBORow& v_41) { v_41.row_major0 = transpose(v_29.col_major0); } +static inline __attribute__((always_inline)) void copy_row_major_to_col_major(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0 = transpose(v_41.row_major0); } +static inline __attribute__((always_inline)) void copy_row_major_to_row_major(device SSBORow& v_41) { v_41.row_major0 = v_41.row_major1; } +static inline __attribute__((always_inline)) void copy_columns(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0[1] = float3(v_41.row_major0[0][1], v_41.row_major0[1][1], v_41.row_major0[2][1]); @@ -57,6 +66,7 @@ void copy_columns(device SSBOCol& v_29, device SSBORow& v_41) v_41.row_major0[2][1] = v_29.col_major0[1].z; } +static inline __attribute__((always_inline)) void copy_elements(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0[0].y = v_41.row_major0[1u][0]; diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-4x4-scalar.comp b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-4x4-scalar.comp index 45bf0d87d6..c36369a6b6 100644 --- a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-4x4-scalar.comp +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-4x4-scalar.comp @@ -17,38 +17,47 @@ struct SSBORow float4x4 row_major1; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + +static inline __attribute__((always_inline)) void load_store_to_variable_col_major(device SSBOCol& v_29) { float4x4 loaded = v_29.col_major0; v_29.col_major1 = loaded; } +static inline __attribute__((always_inline)) void load_store_to_variable_row_major(device SSBORow& v_41) { float4x4 loaded = transpose(v_41.row_major0); v_41.row_major0 = transpose(loaded); } +static inline __attribute__((always_inline)) void copy_col_major_to_col_major(device SSBOCol& v_29) { v_29.col_major0 = v_29.col_major1; } +static inline __attribute__((always_inline)) void copy_col_major_to_row_major(device SSBOCol& v_29, device SSBORow& v_41) { v_41.row_major0 = transpose(v_29.col_major0); } +static inline __attribute__((always_inline)) void copy_row_major_to_col_major(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0 = transpose(v_41.row_major0); } +static inline __attribute__((always_inline)) void copy_row_major_to_row_major(device SSBORow& v_41) { v_41.row_major0 = v_41.row_major1; } +static inline __attribute__((always_inline)) void copy_columns(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0[1] = float4(v_41.row_major0[0][1], v_41.row_major0[1][1], v_41.row_major0[2][1], v_41.row_major0[3][1]); @@ -58,6 +67,7 @@ void copy_columns(device SSBOCol& v_29, device SSBORow& v_41) v_41.row_major0[3][1] = v_29.col_major0[1].w; } +static inline __attribute__((always_inline)) void copy_elements(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0[0].y = v_41.row_major0[1u][0]; diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-4x4-std140.comp b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-4x4-std140.comp index 45bf0d87d6..c36369a6b6 100644 --- a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-4x4-std140.comp +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-4x4-std140.comp @@ -17,38 +17,47 @@ struct SSBORow float4x4 row_major1; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + +static inline __attribute__((always_inline)) void load_store_to_variable_col_major(device SSBOCol& v_29) { float4x4 loaded = v_29.col_major0; v_29.col_major1 = loaded; } +static inline __attribute__((always_inline)) void load_store_to_variable_row_major(device SSBORow& v_41) { float4x4 loaded = transpose(v_41.row_major0); v_41.row_major0 = transpose(loaded); } +static inline __attribute__((always_inline)) void copy_col_major_to_col_major(device SSBOCol& v_29) { v_29.col_major0 = v_29.col_major1; } +static inline __attribute__((always_inline)) void copy_col_major_to_row_major(device SSBOCol& v_29, device SSBORow& v_41) { v_41.row_major0 = transpose(v_29.col_major0); } +static inline __attribute__((always_inline)) void copy_row_major_to_col_major(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0 = transpose(v_41.row_major0); } +static inline __attribute__((always_inline)) void copy_row_major_to_row_major(device SSBORow& v_41) { v_41.row_major0 = v_41.row_major1; } +static inline __attribute__((always_inline)) void copy_columns(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0[1] = float4(v_41.row_major0[0][1], v_41.row_major0[1][1], v_41.row_major0[2][1], v_41.row_major0[3][1]); @@ -58,6 +67,7 @@ void copy_columns(device SSBOCol& v_29, device SSBORow& v_41) v_41.row_major0[3][1] = v_29.col_major0[1].w; } +static inline __attribute__((always_inline)) void copy_elements(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0[0].y = v_41.row_major0[1u][0]; diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-4x4-std430.comp b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-4x4-std430.comp index 45bf0d87d6..c36369a6b6 100644 --- a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-4x4-std430.comp +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-4x4-std430.comp @@ -17,38 +17,47 @@ struct SSBORow float4x4 row_major1; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + +static inline __attribute__((always_inline)) void load_store_to_variable_col_major(device SSBOCol& v_29) { float4x4 loaded = v_29.col_major0; v_29.col_major1 = loaded; } +static inline __attribute__((always_inline)) void load_store_to_variable_row_major(device SSBORow& v_41) { float4x4 loaded = transpose(v_41.row_major0); v_41.row_major0 = transpose(loaded); } +static inline __attribute__((always_inline)) void copy_col_major_to_col_major(device SSBOCol& v_29) { v_29.col_major0 = v_29.col_major1; } +static inline __attribute__((always_inline)) void copy_col_major_to_row_major(device SSBOCol& v_29, device SSBORow& v_41) { v_41.row_major0 = transpose(v_29.col_major0); } +static inline __attribute__((always_inline)) void copy_row_major_to_col_major(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0 = transpose(v_41.row_major0); } +static inline __attribute__((always_inline)) void copy_row_major_to_row_major(device SSBORow& v_41) { v_41.row_major0 = v_41.row_major1; } +static inline __attribute__((always_inline)) void copy_columns(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0[1] = float4(v_41.row_major0[0][1], v_41.row_major0[1][1], v_41.row_major0[2][1], v_41.row_major0[3][1]); @@ -58,6 +67,7 @@ void copy_columns(device SSBOCol& v_29, device SSBORow& v_41) v_41.row_major0[3][1] = v_29.col_major0[1].w; } +static inline __attribute__((always_inline)) void copy_elements(device SSBOCol& v_29, device SSBORow& v_41) { v_29.col_major0[0].y = v_41.row_major0[1u][0]; diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-multiply-row-major.comp b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-multiply-row-major.comp index 8c3d5acaf7..2384e3648e 100644 --- a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-multiply-row-major.comp +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-multiply-row-major.comp @@ -11,6 +11,8 @@ struct SSBO float3 v1; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + kernel void main0(device SSBO& _11 [[buffer(0)]]) { _11.v0 = _11.v1 * (_11.m1 * _11.m0); diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-multiply-unpacked-col-major-2.comp b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-multiply-unpacked-col-major-2.comp index 1571ebaaeb..3fb36e0561 100644 --- a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-multiply-unpacked-col-major-2.comp +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-multiply-unpacked-col-major-2.comp @@ -13,6 +13,8 @@ struct SSBO packed_float3 v1; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + kernel void main0(device SSBO& _11 [[buffer(0)]]) { _11.v0 = (float3x3(float3(_11.m0[0]), float3(_11.m0[1]), float3(_11.m0[2])) * float3x3(float3(_11.m1[0]), float3(_11.m1[1]), float3(_11.m1[2]))) * float3(_11.v1); diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-multiply-unpacked-col-major.comp b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-multiply-unpacked-col-major.comp index 991a76bfed..40f00886dd 100644 --- a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-multiply-unpacked-col-major.comp +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-multiply-unpacked-col-major.comp @@ -11,6 +11,8 @@ struct SSBO float2 v1; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + kernel void main0(device SSBO& _11 [[buffer(0)]]) { _11.v0 = (float2x2(_11.m0[0].xy, _11.m0[1].xy) * float2x2(_11.m1[0].xy, _11.m1[1].xy)) * _11.v1; diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-multiply-unpacked-row-major-2.comp b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-multiply-unpacked-row-major-2.comp index ab72823181..7130c9a8e0 100644 --- a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-multiply-unpacked-row-major-2.comp +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-multiply-unpacked-row-major-2.comp @@ -13,6 +13,8 @@ struct SSBO packed_float3 v1; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + kernel void main0(device SSBO& _11 [[buffer(0)]]) { _11.v0 = float3(_11.v1) * (float3x3(float3(_11.m1[0]), float3(_11.m1[1]), float3(_11.m1[2])) * float3x3(float3(_11.m0[0]), float3(_11.m0[1]), float3(_11.m0[2]))); diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-multiply-unpacked-row-major.comp b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-multiply-unpacked-row-major.comp index d683558b6e..f061dd6662 100644 --- a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-multiply-unpacked-row-major.comp +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/matrix-multiply-unpacked-row-major.comp @@ -11,6 +11,8 @@ struct SSBO float2 v1; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + kernel void main0(device SSBO& _11 [[buffer(0)]]) { _11.v0 = _11.v1 * (float2x2(_11.m1[0].xy, _11.m1[1].xy) * float2x2(_11.m0[0].xy, _11.m0[1].xy)); diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/member-padding.comp b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/member-padding.comp index a0939047c7..4f653ecdd6 100644 --- a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/member-padding.comp +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/member-padding.comp @@ -11,6 +11,8 @@ struct SSBO float b; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + kernel void main0(device SSBO& _9 [[buffer(0)]]) { _9.a = 10.0; diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/std140-array-of-vectors.comp b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/std140-array-of-vectors.comp index 77da52fe62..9b8f76f726 100644 --- a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/std140-array-of-vectors.comp +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/std140-array-of-vectors.comp @@ -16,6 +16,8 @@ struct SSBO float4 v_unsized[1]; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + kernel void main0(device SSBO& _29 [[buffer(0)]]) { float loaded1 = _29.v1[1].x; diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/struct-alignment.comp b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/struct-alignment.comp index 8baa8146d4..baa4ee660b 100644 --- a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/struct-alignment.comp +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/struct-alignment.comp @@ -17,6 +17,8 @@ struct SSBO Foo foo; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + kernel void main0(device SSBO& _12 [[buffer(0)]]) { _12.a.x = 10.0; diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/struct-packing-array-of-scalar.comp b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/struct-packing-array-of-scalar.comp index 7715948f62..587ee4ad15 100644 --- a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/struct-packing-array-of-scalar.comp +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/struct-packing-array-of-scalar.comp @@ -13,6 +13,8 @@ struct SSBOScalar Foo v[1]; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + kernel void main0(device SSBOScalar& buffer_scalar [[buffer(0)]]) { buffer_scalar.v[1].a[1u] = 1.0; diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/struct-packing-recursive.comp b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/struct-packing-recursive.comp index a7832a5db0..e0652b933d 100644 --- a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/struct-packing-recursive.comp +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/struct-packing-recursive.comp @@ -24,6 +24,8 @@ struct SSBOScalar Baz baz; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + kernel void main0(device SSBOScalar& buffer_scalar [[buffer(0)]]) { buffer_scalar.baz.a.a.a[3u] = 10.0; diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/struct-packing.comp b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/struct-packing.comp index 115e1241ea..a86809fee9 100644 --- a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/struct-packing.comp +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/struct-packing.comp @@ -19,6 +19,8 @@ struct SSBOScalar Bar bar; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + kernel void main0(device SSBOScalar& buffer_scalar [[buffer(0)]]) { buffer_scalar.foo.a[0u] = 10.0; diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/struct-size-padding-array-of-array.comp b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/struct-size-padding-array-of-array.comp index 5dd6113b92..3c93b5d59f 100644 --- a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/struct-size-padding-array-of-array.comp +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/struct-size-padding-array-of-array.comp @@ -42,6 +42,8 @@ struct SSBO E f[1]; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + kernel void main0(device SSBO& _32 [[buffer(0)]]) { _32.f[0].a = float4(2.0); diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/struct-size-padding.comp b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/struct-size-padding.comp index 521ac01838..340ab0367b 100644 --- a/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/struct-size-padding.comp +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/packing/struct-size-padding.comp @@ -42,6 +42,8 @@ struct SSBO E f[1]; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + kernel void main0(device SSBO& _26 [[buffer(0)]]) { _26.f[0].a = float4(2.0); diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/vert/functions_nested.vert b/third_party/spirv-cross/reference/shaders-msl-no-opt/vert/functions_nested.vert index 5d67f408be..98c55aaa6e 100644 --- a/third_party/spirv-cross/reference/shaders-msl-no-opt/vert/functions_nested.vert +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/vert/functions_nested.vert @@ -27,8 +27,6 @@ struct VertexConstantsBuffer float4 vc[16]; }; -constant float4 _295 = {}; - struct main0_out { float4 tc0 [[user(locn0)]]; @@ -37,11 +35,13 @@ struct main0_out }; // Returns 2D texture coords corresponding to 1D texel buffer coords +static inline __attribute__((always_inline)) uint2 spvTexelBufferCoord(uint tc) { return uint2(tc % 4096, tc / 4096); } +static inline __attribute__((always_inline)) attr_desc fetch_desc(thread const int& location, constant VertexBuffer& v_227) { int attribute_flags = v_227.input_attributes[location].w; @@ -55,6 +55,7 @@ attr_desc fetch_desc(thread const int& location, constant VertexBuffer& v_227) return result; } +static inline __attribute__((always_inline)) uint get_bits(thread const uint4& v, thread const int& swap) { if (swap != 0) @@ -64,6 +65,7 @@ uint get_bits(thread const uint4& v, thread const int& swap) return ((v.x | (v.y << uint(8))) | (v.z << uint(16))) | (v.w << uint(24)); } +static inline __attribute__((always_inline)) float4 fetch_attr(thread const attr_desc& desc, thread const int& vertex_id, thread const texture2d input_stream) { float4 result = float4(0.0, 0.0, 0.0, 1.0); @@ -132,11 +134,12 @@ float4 fetch_attr(thread const attr_desc& desc, thread const int& vertex_id, thr return _210; } +static inline __attribute__((always_inline)) float4 read_location(thread const int& location, constant VertexBuffer& v_227, thread uint& gl_VertexIndex, thread texture2d buff_in_2, thread texture2d buff_in_1) { int param = location; attr_desc desc = fetch_desc(param, v_227); - int vertex_id = gl_VertexIndex - int(v_227.vertex_base_index); + int vertex_id = int(gl_VertexIndex) - int(v_227.vertex_base_index); if (desc.is_volatile != 0) { attr_desc param_1 = desc; @@ -151,6 +154,7 @@ float4 read_location(thread const int& location, constant VertexBuffer& v_227, t } } +static inline __attribute__((always_inline)) void vs_adjust(thread float4& dst_reg0, thread float4& dst_reg1, thread float4& dst_reg7, constant VertexBuffer& v_227, thread uint& gl_VertexIndex, thread texture2d buff_in_2, thread texture2d buff_in_1, constant VertexConstantsBuffer& v_309) { int param = 3; diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/vert/layer.msl11.invalid.vert b/third_party/spirv-cross/reference/shaders-msl-no-opt/vert/layer.msl11.invalid.vert similarity index 100% rename from third_party/spirv-cross/reference/opt/shaders-msl/vert/layer.msl11.invalid.vert rename to third_party/spirv-cross/reference/shaders-msl-no-opt/vert/layer.msl11.invalid.vert diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/vert/pass-array-by-value.force-native-array.vert b/third_party/spirv-cross/reference/shaders-msl-no-opt/vert/pass-array-by-value.force-native-array.vert new file mode 100644 index 0000000000..d686d02b7f --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/vert/pass-array-by-value.force-native-array.vert @@ -0,0 +1,103 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" + +#include +#include + +using namespace metal; + +constant float4 _68[4] = { float4(0.0), float4(1.0), float4(2.0), float4(3.0) }; + +struct main0_out +{ + float4 gl_Position [[position]]; +}; + +struct main0_in +{ + int Index1 [[attribute(0)]]; + int Index2 [[attribute(1)]]; +}; + +template +inline void spvArrayCopyFromConstantToStack1(thread T (&dst)[A], constant T (&src)[A]) +{ + for (uint i = 0; i < A; i++) + { + dst[i] = src[i]; + } +} + +template +inline void spvArrayCopyFromConstantToThreadGroup1(threadgroup T (&dst)[A], constant T (&src)[A]) +{ + for (uint i = 0; i < A; i++) + { + dst[i] = src[i]; + } +} + +template +inline void spvArrayCopyFromStackToStack1(thread T (&dst)[A], thread const T (&src)[A]) +{ + for (uint i = 0; i < A; i++) + { + dst[i] = src[i]; + } +} + +template +inline void spvArrayCopyFromStackToThreadGroup1(threadgroup T (&dst)[A], thread const T (&src)[A]) +{ + for (uint i = 0; i < A; i++) + { + dst[i] = src[i]; + } +} + +template +inline void spvArrayCopyFromThreadGroupToStack1(thread T (&dst)[A], threadgroup const T (&src)[A]) +{ + for (uint i = 0; i < A; i++) + { + dst[i] = src[i]; + } +} + +template +inline void spvArrayCopyFromThreadGroupToThreadGroup1(threadgroup T (&dst)[A], threadgroup const T (&src)[A]) +{ + for (uint i = 0; i < A; i++) + { + dst[i] = src[i]; + } +} + +static inline __attribute__((always_inline)) +float4 consume_constant_arrays2(thread const float4 (&positions)[4], thread const float4 (&positions2)[4], thread int& Index1, thread int& Index2) +{ + float4 indexable[4]; + spvArrayCopyFromStackToStack1(indexable, positions); + float4 indexable_1[4]; + spvArrayCopyFromStackToStack1(indexable_1, positions2); + return indexable[Index1] + indexable_1[Index2]; +} + +static inline __attribute__((always_inline)) +float4 consume_constant_arrays(thread const float4 (&positions)[4], thread const float4 (&positions2)[4], thread int& Index1, thread int& Index2) +{ + return consume_constant_arrays2(positions, positions2, Index1, Index2); +} + +vertex main0_out main0(main0_in in [[stage_in]]) +{ + float4 _68_array_copy[4] = { float4(0.0), float4(1.0), float4(2.0), float4(3.0) }; + main0_out out = {}; + float4 LUT2[4]; + LUT2[0] = float4(10.0); + LUT2[1] = float4(11.0); + LUT2[2] = float4(12.0); + LUT2[3] = float4(13.0); + out.gl_Position = consume_constant_arrays(_68_array_copy, LUT2, in.Index1, in.Index2); + return out; +} + diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/vert/pass-array-by-value.vert b/third_party/spirv-cross/reference/shaders-msl-no-opt/vert/pass-array-by-value.vert index ab5631366a..f6e3efbecf 100644 --- a/third_party/spirv-cross/reference/shaders-msl-no-opt/vert/pass-array-by-value.vert +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/vert/pass-array-by-value.vert @@ -1,11 +1,50 @@ #pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" #include #include using namespace metal; -constant float4 _68[4] = { float4(0.0), float4(1.0), float4(2.0), float4(3.0) }; +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +constant spvUnsafeArray _68 = spvUnsafeArray({ float4(0.0), float4(1.0), float4(2.0), float4(3.0) }); struct main0_out { @@ -18,43 +57,31 @@ struct main0_in int Index2 [[attribute(1)]]; }; -// Implementation of an array copy function to cover GLSL's ability to copy an array via assignment. -template -void spvArrayCopyFromStack1(thread T (&dst)[N], thread const T (&src)[N]) +static inline __attribute__((always_inline)) +float4 consume_constant_arrays2(spvUnsafeArray positions, spvUnsafeArray positions2, thread int& Index1, thread int& Index2) { - for (uint i = 0; i < N; dst[i] = src[i], i++); -} - -template -void spvArrayCopyFromConstant1(thread T (&dst)[N], constant T (&src)[N]) -{ - for (uint i = 0; i < N; dst[i] = src[i], i++); -} - -float4 consume_constant_arrays2(thread const float4 (&positions)[4], thread const float4 (&positions2)[4], thread int& Index1, thread int& Index2) -{ - float4 indexable[4]; - spvArrayCopyFromStack1(indexable, positions); - float4 indexable_1[4]; - spvArrayCopyFromStack1(indexable_1, positions2); + spvUnsafeArray indexable; + indexable = positions; + spvUnsafeArray indexable_1; + indexable_1 = positions2; return indexable[Index1] + indexable_1[Index2]; } -float4 consume_constant_arrays(thread const float4 (&positions)[4], thread const float4 (&positions2)[4], thread int& Index1, thread int& Index2) +static inline __attribute__((always_inline)) +float4 consume_constant_arrays(spvUnsafeArray positions, spvUnsafeArray positions2, thread int& Index1, thread int& Index2) { return consume_constant_arrays2(positions, positions2, Index1, Index2); } vertex main0_out main0(main0_in in [[stage_in]]) { - float4 _68_array_copy[4] = { float4(0.0), float4(1.0), float4(2.0), float4(3.0) }; main0_out out = {}; - float4 LUT2[4]; + spvUnsafeArray LUT2; LUT2[0] = float4(10.0); LUT2[1] = float4(11.0); LUT2[2] = float4(12.0); LUT2[3] = float4(13.0); - out.gl_Position = consume_constant_arrays(_68_array_copy, LUT2, in.Index1, in.Index2); + out.gl_Position = consume_constant_arrays(_68, LUT2, in.Index1, in.Index2); return out; } diff --git a/third_party/spirv-cross/reference/opt/shaders-msl/vert/viewport-index.msl2.invalid.vert b/third_party/spirv-cross/reference/shaders-msl-no-opt/vert/viewport-index.msl2.invalid.vert similarity index 100% rename from third_party/spirv-cross/reference/opt/shaders-msl/vert/viewport-index.msl2.invalid.vert rename to third_party/spirv-cross/reference/shaders-msl-no-opt/vert/viewport-index.msl2.invalid.vert diff --git a/third_party/spirv-cross/reference/shaders-msl-no-opt/vulkan/frag/texture-access-function.swizzle.vk.frag b/third_party/spirv-cross/reference/shaders-msl-no-opt/vulkan/frag/texture-access-function.swizzle.vk.frag index 9c3fff593b..d4f70e0e1d 100644 --- a/third_party/spirv-cross/reference/shaders-msl-no-opt/vulkan/frag/texture-access-function.swizzle.vk.frag +++ b/third_party/spirv-cross/reference/shaders-msl-no-opt/vulkan/frag/texture-access-function.swizzle.vk.frag @@ -11,22 +11,12 @@ struct main0_out }; // Returns 2D texture coords corresponding to 1D texel buffer coords +static inline __attribute__((always_inline)) uint2 spvTexelBufferCoord(uint tc) { return uint2(tc % 4096, tc / 4096); } -enum class spvSwizzle : uint -{ - none = 0, - zero, - one, - red, - green, - blue, - alpha -}; - template struct spvRemoveReference { typedef T type; }; template struct spvRemoveReference { typedef T type; }; template struct spvRemoveReference { typedef T type; }; @@ -39,6 +29,17 @@ template inline constexpr thread T&& spvForward(thread typename spvR return static_cast(x); } +enum class spvSwizzle : uint +{ + none = 0, + zero, + one, + red, + green, + blue, + alpha +}; + template inline T spvGetSwizzle(vec x, T c, spvSwizzle s) { @@ -77,8 +78,8 @@ inline T spvTextureSwizzle(T x, uint s) } // Wrapper function that swizzles texture gathers. -template -inline vec spvGatherSwizzle(sampler s, const thread Tex& t, Ts... params, component c, uint sw) METAL_CONST_ARG(c) +template class Tex, typename... Ts> +inline vec spvGatherSwizzle(const thread Tex& t, sampler s, uint sw, component c, Ts... params) METAL_CONST_ARG(c) { if (sw) { @@ -114,8 +115,8 @@ inline vec spvGatherSwizzle(sampler s, const thread Tex& t, Ts... params, } // Wrapper function that swizzles depth texture gathers. -template -inline vec spvGatherCompareSwizzle(sampler s, const thread Tex& t, Ts... params, uint sw) +template class Tex, typename... Ts> +inline vec spvGatherCompareSwizzle(const thread Tex& t, sampler s, uint sw, Ts... params) { if (sw) { @@ -136,6 +137,7 @@ inline vec spvGatherCompareSwizzle(sampler s, const thread Tex& t, Ts... p return t.gather_compare(s, spvForward(params)...); } +static inline __attribute__((always_inline)) float4 do_samples(thread const texture1d t1, thread const sampler t1Smplr, constant uint& t1Swzl, thread const texture2d t2, constant uint& t2Swzl, thread const texture3d t3, thread const sampler t3Smplr, constant uint& t3Swzl, thread const texturecube tc, constant uint& tcSwzl, thread const texture2d_array t2a, thread const sampler t2aSmplr, constant uint& t2aSwzl, thread const texturecube_array tca, thread const sampler tcaSmplr, constant uint& tcaSwzl, thread const texture2d tb, thread const depth2d d2, thread const sampler d2Smplr, constant uint& d2Swzl, thread const depthcube dc, thread const sampler dcSmplr, constant uint& dcSwzl, thread const depth2d_array d2a, constant uint& d2aSwzl, thread const depthcube_array dca, thread const sampler dcaSmplr, constant uint& dcaSwzl, thread sampler defaultSampler, thread sampler shadowSampler) { float4 c = spvTextureSwizzle(t1.sample(t1Smplr, 0.0), t1Swzl); @@ -172,14 +174,14 @@ float4 do_samples(thread const texture1d t1, thread const sampler t1Smplr c = spvTextureSwizzle(t3.read(uint3(int3(0)), 0), t3Swzl); c = spvTextureSwizzle(t2a.read(uint2(int3(0).xy), uint(int3(0).z), 0), t2aSwzl); c = tb.read(spvTexelBufferCoord(0)); - c = spvGatherSwizzle, float2, int2>(defaultSampler, t2, float2(0.0), int2(0), component::x, t2Swzl); - c = spvGatherSwizzle, float3>(defaultSampler, tc, float3(0.0), component::y, tcSwzl); - c = spvGatherSwizzle, float2, uint, int2>(t2aSmplr, t2a, float3(0.0).xy, uint(round(float3(0.0).z)), int2(0), component::z, t2aSwzl); - c = spvGatherSwizzle, float3, uint>(tcaSmplr, tca, float4(0.0).xyz, uint(round(float4(0.0).w)), component::w, tcaSwzl); - c = spvGatherCompareSwizzle, float2, float>(d2Smplr, d2, float2(0.0), 1.0, d2Swzl); - c = spvGatherCompareSwizzle, float3, float>(dcSmplr, dc, float3(0.0), 1.0, dcSwzl); - c = spvGatherCompareSwizzle, float2, uint, float>(shadowSampler, d2a, float3(0.0).xy, uint(round(float3(0.0).z)), 1.0, d2aSwzl); - c = spvGatherCompareSwizzle, float3, uint, float>(dcaSmplr, dca, float4(0.0).xyz, uint(round(float4(0.0).w)), 1.0, dcaSwzl); + c = spvGatherSwizzle(t2, defaultSampler, t2Swzl, component::x, float2(0.0), int2(0)); + c = spvGatherSwizzle(tc, defaultSampler, tcSwzl, component::y, float3(0.0)); + c = spvGatherSwizzle(t2a, t2aSmplr, t2aSwzl, component::z, float3(0.0).xy, uint(round(float3(0.0).z)), int2(0)); + c = spvGatherSwizzle(tca, tcaSmplr, tcaSwzl, component::w, float4(0.0).xyz, uint(round(float4(0.0).w))); + c = spvGatherCompareSwizzle(d2, d2Smplr, d2Swzl, float2(0.0), 1.0); + c = spvGatherCompareSwizzle(dc, dcSmplr, dcSwzl, float3(0.0), 1.0); + c = spvGatherCompareSwizzle(d2a, shadowSampler, d2aSwzl, float3(0.0).xy, uint(round(float3(0.0).z)), 1.0); + c = spvGatherCompareSwizzle(dca, dcaSmplr, dcaSwzl, float4(0.0).xyz, uint(round(float4(0.0).w)), 1.0); return c; } diff --git a/third_party/spirv-cross/reference/shaders-msl/asm/comp/atomic-decrement.asm.comp b/third_party/spirv-cross/reference/shaders-msl/asm/comp/atomic-decrement.asm.comp index b06c0e9cd0..e250770dc2 100644 --- a/third_party/spirv-cross/reference/shaders-msl/asm/comp/atomic-decrement.asm.comp +++ b/third_party/spirv-cross/reference/shaders-msl/asm/comp/atomic-decrement.asm.comp @@ -13,6 +13,7 @@ struct u0_counters }; // Returns 2D texture coords corresponding to 1D texel buffer coords +static inline __attribute__((always_inline)) uint2 spvTexelBufferCoord(uint tc) { return uint2(tc % 4096, tc / 4096); diff --git a/third_party/spirv-cross/reference/shaders-msl/asm/comp/atomic-increment.asm.comp b/third_party/spirv-cross/reference/shaders-msl/asm/comp/atomic-increment.asm.comp index 71af7bee36..22c104f933 100644 --- a/third_party/spirv-cross/reference/shaders-msl/asm/comp/atomic-increment.asm.comp +++ b/third_party/spirv-cross/reference/shaders-msl/asm/comp/atomic-increment.asm.comp @@ -13,6 +13,7 @@ struct u0_counters }; // Returns 2D texture coords corresponding to 1D texel buffer coords +static inline __attribute__((always_inline)) uint2 spvTexelBufferCoord(uint tc) { return uint2(tc % 4096, tc / 4096); diff --git a/third_party/spirv-cross/reference/shaders-msl/asm/comp/bitcast_icmp.asm.comp b/third_party/spirv-cross/reference/shaders-msl/asm/comp/bitcast_icmp.asm.comp new file mode 100644 index 0000000000..31c71daa4b --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-msl/asm/comp/bitcast_icmp.asm.comp @@ -0,0 +1,29 @@ +#include +#include + +using namespace metal; + +struct _3 +{ + int4 _m0; + uint4 _m1; +}; + +struct _4 +{ + uint4 _m0; + int4 _m1; +}; + +kernel void main0(device _3& restrict _5 [[buffer(0)]], device _4& restrict _6 [[buffer(1)]]) +{ + _6._m0 = select(uint4(0u), uint4(1u), int4(_5._m1) < _5._m0); + _6._m0 = select(uint4(0u), uint4(1u), int4(_5._m1) <= _5._m0); + _6._m0 = select(uint4(0u), uint4(1u), _5._m1 < uint4(_5._m0)); + _6._m0 = select(uint4(0u), uint4(1u), _5._m1 <= uint4(_5._m0)); + _6._m0 = select(uint4(0u), uint4(1u), int4(_5._m1) > _5._m0); + _6._m0 = select(uint4(0u), uint4(1u), int4(_5._m1) >= _5._m0); + _6._m0 = select(uint4(0u), uint4(1u), _5._m1 > uint4(_5._m0)); + _6._m0 = select(uint4(0u), uint4(1u), _5._m1 >= uint4(_5._m0)); +} + diff --git a/third_party/spirv-cross/reference/shaders-msl/asm/comp/buffer-write-relative-addr.asm.comp b/third_party/spirv-cross/reference/shaders-msl/asm/comp/buffer-write-relative-addr.asm.comp index 217782ce78..57d2205a47 100644 --- a/third_party/spirv-cross/reference/shaders-msl/asm/comp/buffer-write-relative-addr.asm.comp +++ b/third_party/spirv-cross/reference/shaders-msl/asm/comp/buffer-write-relative-addr.asm.comp @@ -11,6 +11,7 @@ struct cb5_struct }; // Returns 2D texture coords corresponding to 1D texel buffer coords +static inline __attribute__((always_inline)) uint2 spvTexelBufferCoord(uint tc) { return uint2(tc % 4096, tc / 4096); diff --git a/third_party/spirv-cross/reference/shaders-msl/asm/comp/buffer-write.asm.comp b/third_party/spirv-cross/reference/shaders-msl/asm/comp/buffer-write.asm.comp index 159d09b38c..8c9e23aa06 100644 --- a/third_party/spirv-cross/reference/shaders-msl/asm/comp/buffer-write.asm.comp +++ b/third_party/spirv-cross/reference/shaders-msl/asm/comp/buffer-write.asm.comp @@ -11,6 +11,7 @@ struct cb }; // Returns 2D texture coords corresponding to 1D texel buffer coords +static inline __attribute__((always_inline)) uint2 spvTexelBufferCoord(uint tc) { return uint2(tc % 4096, tc / 4096); diff --git a/third_party/spirv-cross/reference/shaders-msl/asm/comp/global-parameter-name-alias.asm.comp b/third_party/spirv-cross/reference/shaders-msl/asm/comp/global-parameter-name-alias.asm.comp index 967d14bfcb..ec1b2a2da2 100644 --- a/third_party/spirv-cross/reference/shaders-msl/asm/comp/global-parameter-name-alias.asm.comp +++ b/third_party/spirv-cross/reference/shaders-msl/asm/comp/global-parameter-name-alias.asm.comp @@ -10,12 +10,14 @@ struct ssbo uint _data[1]; }; +static inline __attribute__((always_inline)) void Load(thread const uint& size, const device ssbo& ssbo_1) { int byteAddrTemp = int(size >> uint(2)); uint4 data = uint4(ssbo_1._data[byteAddrTemp], ssbo_1._data[byteAddrTemp + 1], ssbo_1._data[byteAddrTemp + 2], ssbo_1._data[byteAddrTemp + 3]); } +static inline __attribute__((always_inline)) void _main(thread const uint3& id, const device ssbo& ssbo_1) { uint param = 4u; diff --git a/third_party/spirv-cross/reference/shaders-msl/asm/comp/image-load-store-short-vector.asm.comp b/third_party/spirv-cross/reference/shaders-msl/asm/comp/image-load-store-short-vector.asm.comp index c90faf9ef2..fca572e36f 100644 --- a/third_party/spirv-cross/reference/shaders-msl/asm/comp/image-load-store-short-vector.asm.comp +++ b/third_party/spirv-cross/reference/shaders-msl/asm/comp/image-load-store-short-vector.asm.comp @@ -5,6 +5,7 @@ using namespace metal; +static inline __attribute__((always_inline)) void _main(thread const uint3& id, thread texture2d TargetTexture) { float2 loaded = TargetTexture.read(uint2(id.xy)).xy; diff --git a/third_party/spirv-cross/reference/shaders-msl/asm/comp/storage-buffer-basic.invalid.asm.comp b/third_party/spirv-cross/reference/shaders-msl/asm/comp/storage-buffer-basic.invalid.asm.comp deleted file mode 100644 index 473298c274..0000000000 --- a/third_party/spirv-cross/reference/shaders-msl/asm/comp/storage-buffer-basic.invalid.asm.comp +++ /dev/null @@ -1,22 +0,0 @@ -#include -#include - -using namespace metal; - -struct _6 -{ - float _m0[1]; -}; - -constant uint _3_tmp [[function_constant(0)]]; -constant uint _3 = is_function_constant_defined(_3_tmp) ? _3_tmp : 1u; -constant uint _4_tmp [[function_constant(2)]]; -constant uint _4 = is_function_constant_defined(_4_tmp) ? _4_tmp : 3u; -constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(_3, 2u, _4); - -kernel void main0(device _6& _8 [[buffer(0)]], device _6& _9 [[buffer(1)]], uint3 gl_WorkGroupID [[threadgroup_position_in_grid]]) -{ - _8._m0[gl_WorkGroupID.x] = _9._m0[gl_WorkGroupID.x] + _8._m0[gl_WorkGroupID.x]; - uint3 _23 = gl_WorkGroupSize; -} - diff --git a/third_party/spirv-cross/reference/shaders-msl/asm/comp/struct-resource-name-aliasing.asm.comp b/third_party/spirv-cross/reference/shaders-msl/asm/comp/struct-resource-name-aliasing.asm.comp index a3323bf251..fa7d269821 100644 --- a/third_party/spirv-cross/reference/shaders-msl/asm/comp/struct-resource-name-aliasing.asm.comp +++ b/third_party/spirv-cross/reference/shaders-msl/asm/comp/struct-resource-name-aliasing.asm.comp @@ -10,6 +10,7 @@ struct bufA uint _data[1]; }; +static inline __attribute__((always_inline)) void _main(device bufA& bufA_1, device bufA& bufB) { bufA_1._data[0] = 0u; diff --git a/third_party/spirv-cross/reference/shaders-msl/asm/comp/variable-pointers-2.asm.comp b/third_party/spirv-cross/reference/shaders-msl/asm/comp/variable-pointers-2.asm.comp index 07b22d6840..4bf34ff4b2 100644 --- a/third_party/spirv-cross/reference/shaders-msl/asm/comp/variable-pointers-2.asm.comp +++ b/third_party/spirv-cross/reference/shaders-msl/asm/comp/variable-pointers-2.asm.comp @@ -17,11 +17,13 @@ struct bar int d; }; +static inline __attribute__((always_inline)) device foo* select_buffer(device foo& a, constant bar& cb) { return (cb.d != 0) ? &a : nullptr; } +static inline __attribute__((always_inline)) thread uint3* select_input(thread uint3& gl_GlobalInvocationID, thread uint3& gl_LocalInvocationID, constant bar& cb) { return (cb.d != 0) ? &gl_GlobalInvocationID : &gl_LocalInvocationID; diff --git a/third_party/spirv-cross/reference/shaders-msl/asm/comp/variable-pointers-store-forwarding.asm.comp b/third_party/spirv-cross/reference/shaders-msl/asm/comp/variable-pointers-store-forwarding.asm.comp index b2f8fc424e..00c490c77f 100644 --- a/third_party/spirv-cross/reference/shaders-msl/asm/comp/variable-pointers-store-forwarding.asm.comp +++ b/third_party/spirv-cross/reference/shaders-msl/asm/comp/variable-pointers-store-forwarding.asm.comp @@ -15,6 +15,7 @@ struct bar int b; }; +static inline __attribute__((always_inline)) device int* _24(device foo& a, device bar& b, thread uint3& gl_GlobalInvocationID) { return (gl_GlobalInvocationID.x != 0u) ? &a.a : &b.b; diff --git a/third_party/spirv-cross/reference/shaders-msl/asm/comp/vector-builtin-type-cast-func.asm.comp b/third_party/spirv-cross/reference/shaders-msl/asm/comp/vector-builtin-type-cast-func.asm.comp index e4092261d6..93e14e861d 100644 --- a/third_party/spirv-cross/reference/shaders-msl/asm/comp/vector-builtin-type-cast-func.asm.comp +++ b/third_party/spirv-cross/reference/shaders-msl/asm/comp/vector-builtin-type-cast-func.asm.comp @@ -12,6 +12,7 @@ struct cb1_struct constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(16u, 16u, 1u); +static inline __attribute__((always_inline)) int2 get_texcoord(thread const int2& base, thread const int2& index, thread uint3& gl_LocalInvocationID) { return (base * int3(gl_LocalInvocationID).xy) + index; diff --git a/third_party/spirv-cross/reference/shaders-msl/asm/frag/empty-struct.asm.frag b/third_party/spirv-cross/reference/shaders-msl/asm/frag/empty-struct.asm.frag index 0a56f1f153..e30c5864b2 100644 --- a/third_party/spirv-cross/reference/shaders-msl/asm/frag/empty-struct.asm.frag +++ b/third_party/spirv-cross/reference/shaders-msl/asm/frag/empty-struct.asm.frag @@ -7,14 +7,14 @@ using namespace metal; struct EmptyStructTest { - int empty_struct_member; }; - +static inline __attribute__((always_inline)) float GetValue(thread const EmptyStructTest& self) { return 0.0; } +static inline __attribute__((always_inline)) float GetValue_1(EmptyStructTest self) { return 0.0; @@ -22,9 +22,8 @@ float GetValue_1(EmptyStructTest self) fragment void main0() { - EmptyStructTest _23 = EmptyStructTest{ 0 }; EmptyStructTest emptyStruct; float value = GetValue(emptyStruct); - value = GetValue_1(_23); + value = GetValue_1(EmptyStructTest{ }); } diff --git a/third_party/spirv-cross/reference/shaders-msl/asm/frag/extract-packed-from-composite.asm.frag b/third_party/spirv-cross/reference/shaders-msl/asm/frag/extract-packed-from-composite.asm.frag index 1f92b341a8..e926bc5f3e 100644 --- a/third_party/spirv-cross/reference/shaders-msl/asm/frag/extract-packed-from-composite.asm.frag +++ b/third_party/spirv-cross/reference/shaders-msl/asm/frag/extract-packed-from-composite.asm.frag @@ -28,6 +28,7 @@ struct main0_out float4 _entryPointOutput [[color(0)]]; }; +static inline __attribute__((always_inline)) float4 _main(thread const float4& pos, constant buf& v_11) { int _46 = int(pos.x) % 16; diff --git a/third_party/spirv-cross/reference/shaders-msl/asm/frag/function-overload-alias.asm.frag b/third_party/spirv-cross/reference/shaders-msl/asm/frag/function-overload-alias.asm.frag index 1a6314c819..40fe5c5d81 100644 --- a/third_party/spirv-cross/reference/shaders-msl/asm/frag/function-overload-alias.asm.frag +++ b/third_party/spirv-cross/reference/shaders-msl/asm/frag/function-overload-alias.asm.frag @@ -10,21 +10,25 @@ struct main0_out float4 FragColor [[color(0)]]; }; +static inline __attribute__((always_inline)) float4 foo(thread const float4& foo_1) { return foo_1 + float4(1.0); } +static inline __attribute__((always_inline)) float4 foo(thread const float3& foo_1) { return foo_1.xyzz + float4(1.0); } +static inline __attribute__((always_inline)) float4 foo_1(thread const float4& foo_2) { return foo_2 + float4(2.0); } +static inline __attribute__((always_inline)) float4 foo(thread const float2& foo_2) { return foo_2.xyxy + float4(2.0); diff --git a/third_party/spirv-cross/reference/shaders-msl/asm/frag/line-directive.line.asm.frag b/third_party/spirv-cross/reference/shaders-msl/asm/frag/line-directive.line.asm.frag index e1d2a9d7b9..38fbd27ba3 100644 --- a/third_party/spirv-cross/reference/shaders-msl/asm/frag/line-directive.line.asm.frag +++ b/third_party/spirv-cross/reference/shaders-msl/asm/frag/line-directive.line.asm.frag @@ -16,6 +16,7 @@ struct main0_in }; #line 6 "test.frag" +static inline __attribute__((always_inline)) void func(thread float& FragColor, thread float& vColor) { #line 8 "test.frag" diff --git a/third_party/spirv-cross/reference/shaders-msl/asm/frag/lut-promotion-initializer.asm.frag b/third_party/spirv-cross/reference/shaders-msl/asm/frag/lut-promotion-initializer.asm.frag index 48f3317d2e..41193536e6 100644 --- a/third_party/spirv-cross/reference/shaders-msl/asm/frag/lut-promotion-initializer.asm.frag +++ b/third_party/spirv-cross/reference/shaders-msl/asm/frag/lut-promotion-initializer.asm.frag @@ -1,13 +1,52 @@ #pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" #include #include using namespace metal; -constant float _46[16] = { 1.0, 2.0, 3.0, 4.0, 1.0, 2.0, 3.0, 4.0, 1.0, 2.0, 3.0, 4.0, 1.0, 2.0, 3.0, 4.0 }; -constant float4 _76[4] = { float4(0.0), float4(1.0), float4(8.0), float4(5.0) }; -constant float4 _90[4] = { float4(20.0), float4(30.0), float4(50.0), float4(60.0) }; +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +constant spvUnsafeArray _46 = spvUnsafeArray({ 1.0, 2.0, 3.0, 4.0, 1.0, 2.0, 3.0, 4.0, 1.0, 2.0, 3.0, 4.0, 1.0, 2.0, 3.0, 4.0 }); +constant spvUnsafeArray _76 = spvUnsafeArray({ float4(0.0), float4(1.0), float4(8.0), float4(5.0) }); +constant spvUnsafeArray _90 = spvUnsafeArray({ float4(20.0), float4(30.0), float4(50.0), float4(60.0) }); struct main0_out { @@ -19,23 +58,10 @@ struct main0_in int index [[user(locn0)]]; }; -// Implementation of an array copy function to cover GLSL's ability to copy an array via assignment. -template -void spvArrayCopyFromStack1(thread T (&dst)[N], thread const T (&src)[N]) -{ - for (uint i = 0; i < N; dst[i] = src[i], i++); -} - -template -void spvArrayCopyFromConstant1(thread T (&dst)[N], constant T (&src)[N]) -{ - for (uint i = 0; i < N; dst[i] = src[i], i++); -} - fragment main0_out main0(main0_in in [[stage_in]]) { - float4 foobar[4] = { float4(0.0), float4(1.0), float4(8.0), float4(5.0) }; - float4 baz[4] = { float4(0.0), float4(1.0), float4(8.0), float4(5.0) }; + spvUnsafeArray foobar = spvUnsafeArray({ float4(0.0), float4(1.0), float4(8.0), float4(5.0) }); + spvUnsafeArray baz = spvUnsafeArray({ float4(0.0), float4(1.0), float4(8.0), float4(5.0) }); main0_out out = {}; out.FragColor = _46[in.index]; if (in.index < 10) @@ -59,7 +85,7 @@ fragment main0_out main0(main0_in in [[stage_in]]) foobar[1].z = 20.0; } out.FragColor += foobar[in.index & 3].z; - spvArrayCopyFromConstant1(baz, _90); + baz = _90; out.FragColor += baz[in.index & 3].z; return out; } diff --git a/third_party/spirv-cross/reference/shaders-msl/asm/frag/op-constant-null.asm.frag b/third_party/spirv-cross/reference/shaders-msl/asm/frag/op-constant-null.asm.frag index 9d5d7fb1d6..f8104f8165 100644 --- a/third_party/spirv-cross/reference/shaders-msl/asm/frag/op-constant-null.asm.frag +++ b/third_party/spirv-cross/reference/shaders-msl/asm/frag/op-constant-null.asm.frag @@ -1,15 +1,56 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + #include #include using namespace metal; +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + struct D { float4 a; float b; }; -constant float4 _14[4] = { float4(0.0), float4(0.0), float4(0.0), float4(0.0) }; +constant spvUnsafeArray _14 = spvUnsafeArray({ float4(0.0), float4(0.0), float4(0.0), float4(0.0) }); struct main0_out { diff --git a/third_party/spirv-cross/reference/shaders-msl/asm/frag/pass-by-value.asm.frag b/third_party/spirv-cross/reference/shaders-msl/asm/frag/pass-by-value.asm.frag index 6ed945ecff..46648f6d30 100644 --- a/third_party/spirv-cross/reference/shaders-msl/asm/frag/pass-by-value.asm.frag +++ b/third_party/spirv-cross/reference/shaders-msl/asm/frag/pass-by-value.asm.frag @@ -15,6 +15,7 @@ struct main0_out float FragColor [[color(0)]]; }; +static inline __attribute__((always_inline)) float add_value(float v, float w) { return v + w; diff --git a/third_party/spirv-cross/reference/shaders-msl/asm/frag/single-function-private-lut.asm.frag b/third_party/spirv-cross/reference/shaders-msl/asm/frag/single-function-private-lut.asm.frag index 628d5c7c1b..54325051f4 100644 --- a/third_party/spirv-cross/reference/shaders-msl/asm/frag/single-function-private-lut.asm.frag +++ b/third_party/spirv-cross/reference/shaders-msl/asm/frag/single-function-private-lut.asm.frag @@ -1,17 +1,54 @@ #pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" #include #include using namespace metal; +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + struct myType { float data; }; -constant myType _21[5] = { myType{ 0.0 }, myType{ 1.0 }, myType{ 0.0 }, myType{ 1.0 }, myType{ 0.0 } }; - struct main0_out { float4 o_color [[color(0)]]; @@ -19,26 +56,15 @@ struct main0_out // Implementation of the GLSL mod() function, which is slightly different than Metal fmod() template -Tx mod(Tx x, Ty y) +inline Tx mod(Tx x, Ty y) { return x - y * floor(x / y); } -// Implementation of an array copy function to cover GLSL's ability to copy an array via assignment. -template -void spvArrayCopyFromStack1(thread T (&dst)[N], thread const T (&src)[N]) -{ - for (uint i = 0; i < N; dst[i] = src[i], i++); -} - -template -void spvArrayCopyFromConstant1(thread T (&dst)[N], constant T (&src)[N]) -{ - for (uint i = 0; i < N; dst[i] = src[i], i++); -} - fragment main0_out main0(float4 gl_FragCoord [[position]]) { + spvUnsafeArray _21 = spvUnsafeArray({ myType{ 0.0 }, myType{ 1.0 }, myType{ 0.0 }, myType{ 1.0 }, myType{ 0.0 } }); + main0_out out = {}; float2 uv = gl_FragCoord.xy; int index = int(mod(uv.x, 4.0)); diff --git a/third_party/spirv-cross/reference/shaders-msl/asm/frag/storage-class-output-initializer.asm.frag b/third_party/spirv-cross/reference/shaders-msl/asm/frag/storage-class-output-initializer.asm.frag index 1bafc6953b..d59013daaf 100644 --- a/third_party/spirv-cross/reference/shaders-msl/asm/frag/storage-class-output-initializer.asm.frag +++ b/third_party/spirv-cross/reference/shaders-msl/asm/frag/storage-class-output-initializer.asm.frag @@ -1,9 +1,50 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + #include #include using namespace metal; -constant float4 _20[2] = { float4(1.0, 2.0, 3.0, 4.0), float4(10.0) }; +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +constant spvUnsafeArray _20 = spvUnsafeArray({ float4(1.0, 2.0, 3.0, 4.0), float4(10.0) }); struct main0_out { @@ -15,7 +56,7 @@ struct main0_out fragment main0_out main0() { main0_out out = {}; - float4 FragColors[2] = { float4(1.0, 2.0, 3.0, 4.0), float4(10.0) }; + spvUnsafeArray FragColors = spvUnsafeArray({ float4(1.0, 2.0, 3.0, 4.0), float4(10.0) }); out.FragColor = float4(5.0); out.FragColors_0 = FragColors[0]; out.FragColors_1 = FragColors[1]; diff --git a/third_party/spirv-cross/reference/shaders-msl/asm/frag/texture-atomics.asm.frag b/third_party/spirv-cross/reference/shaders-msl/asm/frag/texture-atomics.asm.frag new file mode 100644 index 0000000000..ab5be64984 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-msl/asm/frag/texture-atomics.asm.frag @@ -0,0 +1,121 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" +#pragma clang diagnostic ignored "-Wunused-variable" + +#include +#include +#include + +using namespace metal; + +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +struct type_StructuredBuffer_v4float +{ + spvUnsafeArray _m0; +}; + +struct type_Globals +{ + uint2 ShadowTileListGroupSize; +}; + +constant float3 _70 = {}; + +struct main0_out +{ + float4 out_var_SV_Target0 [[color(0)]]; +}; + +struct main0_in +{ + uint in_var_TEXCOORD0 [[user(locn0)]]; +}; + +fragment main0_out main0(main0_in in [[stage_in]], const device type_StructuredBuffer_v4float& CulledObjectBoxBounds [[buffer(0)]], constant type_Globals& _Globals [[buffer(1)]], texture2d RWShadowTileNumCulledObjects [[texture(2)]], device atomic_uint* RWShadowTileNumCulledObjects_atomic [[buffer(2)]], float4 gl_FragCoord [[position]]) +{ + main0_out out = {}; + uint2 _77 = uint2(gl_FragCoord.xy); + uint _78 = _77.y; + uint _83 = _77.x; + float2 _91 = float2(float(_83), float((_Globals.ShadowTileListGroupSize.y - 1u) - _78)); + float2 _93 = float2(_Globals.ShadowTileListGroupSize); + float2 _96 = ((_91 / _93) * float2(2.0)) - float2(1.0); + float2 _100 = (((_91 + float2(1.0)) / _93) * float2(2.0)) - float2(1.0); + float3 _102 = float3(_100.x, _100.y, _70.z); + _102.z = 1.0; + uint _103 = in.in_var_TEXCOORD0 * 5u; + uint _107 = _103 + 1u; + if (all(CulledObjectBoxBounds._m0[_107].xy > _96.xy) && all(CulledObjectBoxBounds._m0[_103].xyz < _102)) + { + float _122 = _96.x; + float _123 = _96.y; + spvUnsafeArray _73; + _73[0] = float3(_122, _123, -1000.0); + float _126 = _100.x; + _73[1] = float3(_126, _123, -1000.0); + float _129 = _100.y; + _73[2] = float3(_122, _129, -1000.0); + _73[3] = float3(_126, _129, -1000.0); + _73[4] = float3(_122, _123, 1.0); + _73[5] = float3(_126, _123, 1.0); + _73[6] = float3(_122, _129, 1.0); + _73[7] = float3(_126, _129, 1.0); + float3 _155; + float3 _158; + _155 = float3(-500000.0); + _158 = float3(500000.0); + for (int _160 = 0; _160 < 8; ) + { + float3 _166 = _73[_160] - (float3(0.5) * (CulledObjectBoxBounds._m0[_103].xyz + CulledObjectBoxBounds._m0[_107].xyz)); + float3 _170 = float3(dot(_166, CulledObjectBoxBounds._m0[_103 + 2u].xyz), dot(_166, CulledObjectBoxBounds._m0[_103 + 3u].xyz), dot(_166, CulledObjectBoxBounds._m0[_103 + 4u].xyz)); + _155 = fast::max(_155, _170); + _158 = fast::min(_158, _170); + _160++; + continue; + } + if (all(_158 < float3(1.0)) && all(_155 > float3(-1.0))) + { + uint _179 = atomic_fetch_add_explicit((device atomic_uint*)&RWShadowTileNumCulledObjects_atomic[(_78 * _Globals.ShadowTileListGroupSize.x) + _83], 1u, memory_order_relaxed); + } + } + out.out_var_SV_Target0 = float4(0.0); + return out; +} + diff --git a/third_party/spirv-cross/reference/shaders-msl/asm/frag/texture-atomics.asm.graphics-robust-access.frag b/third_party/spirv-cross/reference/shaders-msl/asm/frag/texture-atomics.asm.graphics-robust-access.frag new file mode 100644 index 0000000000..ab5be64984 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-msl/asm/frag/texture-atomics.asm.graphics-robust-access.frag @@ -0,0 +1,121 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" +#pragma clang diagnostic ignored "-Wunused-variable" + +#include +#include +#include + +using namespace metal; + +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +struct type_StructuredBuffer_v4float +{ + spvUnsafeArray _m0; +}; + +struct type_Globals +{ + uint2 ShadowTileListGroupSize; +}; + +constant float3 _70 = {}; + +struct main0_out +{ + float4 out_var_SV_Target0 [[color(0)]]; +}; + +struct main0_in +{ + uint in_var_TEXCOORD0 [[user(locn0)]]; +}; + +fragment main0_out main0(main0_in in [[stage_in]], const device type_StructuredBuffer_v4float& CulledObjectBoxBounds [[buffer(0)]], constant type_Globals& _Globals [[buffer(1)]], texture2d RWShadowTileNumCulledObjects [[texture(2)]], device atomic_uint* RWShadowTileNumCulledObjects_atomic [[buffer(2)]], float4 gl_FragCoord [[position]]) +{ + main0_out out = {}; + uint2 _77 = uint2(gl_FragCoord.xy); + uint _78 = _77.y; + uint _83 = _77.x; + float2 _91 = float2(float(_83), float((_Globals.ShadowTileListGroupSize.y - 1u) - _78)); + float2 _93 = float2(_Globals.ShadowTileListGroupSize); + float2 _96 = ((_91 / _93) * float2(2.0)) - float2(1.0); + float2 _100 = (((_91 + float2(1.0)) / _93) * float2(2.0)) - float2(1.0); + float3 _102 = float3(_100.x, _100.y, _70.z); + _102.z = 1.0; + uint _103 = in.in_var_TEXCOORD0 * 5u; + uint _107 = _103 + 1u; + if (all(CulledObjectBoxBounds._m0[_107].xy > _96.xy) && all(CulledObjectBoxBounds._m0[_103].xyz < _102)) + { + float _122 = _96.x; + float _123 = _96.y; + spvUnsafeArray _73; + _73[0] = float3(_122, _123, -1000.0); + float _126 = _100.x; + _73[1] = float3(_126, _123, -1000.0); + float _129 = _100.y; + _73[2] = float3(_122, _129, -1000.0); + _73[3] = float3(_126, _129, -1000.0); + _73[4] = float3(_122, _123, 1.0); + _73[5] = float3(_126, _123, 1.0); + _73[6] = float3(_122, _129, 1.0); + _73[7] = float3(_126, _129, 1.0); + float3 _155; + float3 _158; + _155 = float3(-500000.0); + _158 = float3(500000.0); + for (int _160 = 0; _160 < 8; ) + { + float3 _166 = _73[_160] - (float3(0.5) * (CulledObjectBoxBounds._m0[_103].xyz + CulledObjectBoxBounds._m0[_107].xyz)); + float3 _170 = float3(dot(_166, CulledObjectBoxBounds._m0[_103 + 2u].xyz), dot(_166, CulledObjectBoxBounds._m0[_103 + 3u].xyz), dot(_166, CulledObjectBoxBounds._m0[_103 + 4u].xyz)); + _155 = fast::max(_155, _170); + _158 = fast::min(_158, _170); + _160++; + continue; + } + if (all(_158 < float3(1.0)) && all(_155 > float3(-1.0))) + { + uint _179 = atomic_fetch_add_explicit((device atomic_uint*)&RWShadowTileNumCulledObjects_atomic[(_78 * _Globals.ShadowTileListGroupSize.x) + _83], 1u, memory_order_relaxed); + } + } + out.out_var_SV_Target0 = float4(0.0); + return out; +} + diff --git a/third_party/spirv-cross/reference/shaders-msl/asm/frag/unknown-depth-state.asm.frag b/third_party/spirv-cross/reference/shaders-msl/asm/frag/unknown-depth-state.asm.frag index ce2b95196e..01a0e5a732 100644 --- a/third_party/spirv-cross/reference/shaders-msl/asm/frag/unknown-depth-state.asm.frag +++ b/third_party/spirv-cross/reference/shaders-msl/asm/frag/unknown-depth-state.asm.frag @@ -15,11 +15,13 @@ struct main0_in float3 vUV [[user(locn0)]]; }; +static inline __attribute__((always_inline)) float sample_combined(thread float3& vUV, thread depth2d uShadow, thread const sampler uShadowSmplr) { return uShadow.sample_compare(uShadowSmplr, vUV.xy, vUV.z); } +static inline __attribute__((always_inline)) float sample_separate(thread float3& vUV, thread depth2d uTexture, thread sampler uSampler) { return uTexture.sample_compare(uSampler, vUV.xy, vUV.z); diff --git a/third_party/spirv-cross/reference/shaders-msl/asm/vert/clip-distance-plain-variable.asm.vert b/third_party/spirv-cross/reference/shaders-msl/asm/vert/clip-distance-plain-variable.asm.vert new file mode 100644 index 0000000000..ae42798e31 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-msl/asm/vert/clip-distance-plain-variable.asm.vert @@ -0,0 +1,49 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" + +#include +#include + +using namespace metal; + +struct VSOut +{ + float4 pos; + float2 clip; +}; + +struct main0_out +{ + float4 gl_Position [[position]]; + float gl_ClipDistance [[clip_distance]] [2]; + float gl_ClipDistance_0 [[user(clip0)]]; + float gl_ClipDistance_1 [[user(clip1)]]; +}; + +struct main0_in +{ + float4 pos [[attribute(0)]]; +}; + +static inline __attribute__((always_inline)) +VSOut _main(thread const float4& pos) +{ + VSOut vout; + vout.pos = pos; + vout.clip = pos.xy; + return vout; +} + +vertex main0_out main0(main0_in in [[stage_in]]) +{ + main0_out out = {}; + float4 pos = in.pos; + float4 param = pos; + VSOut flattenTemp = _main(param); + out.gl_Position = flattenTemp.pos; + out.gl_ClipDistance[0] = flattenTemp.clip.x; + out.gl_ClipDistance[1] = flattenTemp.clip.y; + out.gl_ClipDistance_0 = out.gl_ClipDistance[0]; + out.gl_ClipDistance_1 = out.gl_ClipDistance[1]; + return out; +} + diff --git a/third_party/spirv-cross/reference/shaders-msl/asm/vert/extract-transposed-matrix-from-struct.asm.vert b/third_party/spirv-cross/reference/shaders-msl/asm/vert/extract-transposed-matrix-from-struct.asm.vert index 667d363a38..b94687a52b 100644 --- a/third_party/spirv-cross/reference/shaders-msl/asm/vert/extract-transposed-matrix-from-struct.asm.vert +++ b/third_party/spirv-cross/reference/shaders-msl/asm/vert/extract-transposed-matrix-from-struct.asm.vert @@ -39,6 +39,7 @@ struct main0_in float3 PosL [[attribute(0)]]; }; +static inline __attribute__((always_inline)) V2F _VS(thread const float3& PosL, thread const uint& instanceID, const device gInstanceData& gInstanceData_1) { InstanceData instData; diff --git a/third_party/spirv-cross/reference/shaders-msl/asm/vert/invariant.msl21.asm.vert b/third_party/spirv-cross/reference/shaders-msl/asm/vert/invariant.msl21.asm.vert index 1e3a86531c..d74c43b3f0 100644 --- a/third_party/spirv-cross/reference/shaders-msl/asm/vert/invariant.msl21.asm.vert +++ b/third_party/spirv-cross/reference/shaders-msl/asm/vert/invariant.msl21.asm.vert @@ -10,6 +10,7 @@ struct main0_out float4 gl_Position [[position, invariant]]; }; +static inline __attribute__((always_inline)) float4 _main() { return float4(1.0); diff --git a/third_party/spirv-cross/reference/shaders-msl/asm/vert/uint-vertex-id-instance-id.asm.vert b/third_party/spirv-cross/reference/shaders-msl/asm/vert/uint-vertex-id-instance-id.asm.vert index 89ca17f98b..30df905e6a 100644 --- a/third_party/spirv-cross/reference/shaders-msl/asm/vert/uint-vertex-id-instance-id.asm.vert +++ b/third_party/spirv-cross/reference/shaders-msl/asm/vert/uint-vertex-id-instance-id.asm.vert @@ -10,6 +10,7 @@ struct main0_out float4 gl_Position [[position]]; }; +static inline __attribute__((always_inline)) float4 _main(thread const uint& vid, thread const uint& iid) { return float4(float(vid + iid)); diff --git a/third_party/spirv-cross/reference/shaders-msl/comp/access-private-workgroup-in-function.comp b/third_party/spirv-cross/reference/shaders-msl/comp/access-private-workgroup-in-function.comp index 17acda9678..85185e6df6 100644 --- a/third_party/spirv-cross/reference/shaders-msl/comp/access-private-workgroup-in-function.comp +++ b/third_party/spirv-cross/reference/shaders-msl/comp/access-private-workgroup-in-function.comp @@ -5,11 +5,15 @@ using namespace metal; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + +static inline __attribute__((always_inline)) void set_f(thread int& f) { f = 40; } +static inline __attribute__((always_inline)) void set_shared_u(threadgroup int& u) { u = 50; diff --git a/third_party/spirv-cross/reference/shaders-msl/comp/argument-buffers-discrete.msl2.argument.discrete.comp b/third_party/spirv-cross/reference/shaders-msl/comp/argument-buffers-discrete.msl2.argument.discrete.comp index f7757cd19f..18cfd68c19 100644 --- a/third_party/spirv-cross/reference/shaders-msl/comp/argument-buffers-discrete.msl2.argument.discrete.comp +++ b/third_party/spirv-cross/reference/shaders-msl/comp/argument-buffers-discrete.msl2.argument.discrete.comp @@ -23,6 +23,8 @@ struct SSBO2 float4 v; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + struct spvDescriptorSetBuffer0 { const device SSBO0* ssbo0 [[id(0)]]; diff --git a/third_party/spirv-cross/reference/shaders-msl/comp/argument-buffers-image-load-store.ios.msl2.argument.comp b/third_party/spirv-cross/reference/shaders-msl/comp/argument-buffers-image-load-store.ios.msl2.argument.comp new file mode 100644 index 0000000000..c23a9d1d00 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-msl/comp/argument-buffers-image-load-store.ios.msl2.argument.comp @@ -0,0 +1,11 @@ +#include +#include + +using namespace metal; + +kernel void main0(texture2d uImage [[texture(0)]], texture2d uImageRead [[texture(1)]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]]) +{ + int2 coord = int2(gl_GlobalInvocationID.xy); + uImage.write(uImageRead.read(uint2(coord)), uint2(coord)); +} + diff --git a/third_party/spirv-cross/reference/shaders-msl/comp/array-length.comp b/third_party/spirv-cross/reference/shaders-msl/comp/array-length.comp index 8406d1e50b..9ac8c827e6 100644 --- a/third_party/spirv-cross/reference/shaders-msl/comp/array-length.comp +++ b/third_party/spirv-cross/reference/shaders-msl/comp/array-length.comp @@ -16,6 +16,9 @@ struct SSBO1 float bz[1]; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + +static inline __attribute__((always_inline)) uint get_size(device SSBO& v_14, constant uint& v_14BufferSize, device SSBO1* (&ssbos)[2], constant uint* ssbosBufferSize) { return uint(int((v_14BufferSize - 16) / 16) + int((ssbosBufferSize[1] - 0) / 4)); diff --git a/third_party/spirv-cross/reference/shaders-msl/comp/array-length.msl2.argument.discrete.comp b/third_party/spirv-cross/reference/shaders-msl/comp/array-length.msl2.argument.discrete.comp index 73bd3f6d7b..aa1f4424d1 100644 --- a/third_party/spirv-cross/reference/shaders-msl/comp/array-length.msl2.argument.discrete.comp +++ b/third_party/spirv-cross/reference/shaders-msl/comp/array-length.msl2.argument.discrete.comp @@ -27,6 +27,8 @@ struct SSBO3 float bz[1]; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + struct spvDescriptorSetBuffer0 { device SSBO* v_16 [[id(0)]]; @@ -39,6 +41,7 @@ struct spvDescriptorSetBuffer1 constant uint* spvBufferSizeConstants [[id(2)]]; }; +static inline __attribute__((always_inline)) uint get_size(device SSBO& v_16, constant uint& v_16BufferSize, device SSBO1* constant (&ssbos)[2], constant uint* ssbosBufferSize, device SSBO2& v_38, constant uint& v_38BufferSize, device SSBO3* (&ssbos2)[2], constant uint* ssbos2BufferSize) { uint len = uint(int((v_16BufferSize - 16) / 16)); diff --git a/third_party/spirv-cross/reference/shaders-msl/comp/atomic.comp b/third_party/spirv-cross/reference/shaders-msl/comp/atomic.comp index 047215022a..fca72bfcfe 100644 --- a/third_party/spirv-cross/reference/shaders-msl/comp/atomic.comp +++ b/third_party/spirv-cross/reference/shaders-msl/comp/atomic.comp @@ -12,6 +12,8 @@ struct SSBO int i32; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + kernel void main0(device SSBO& ssbo [[buffer(0)]]) { threadgroup uint shared_u32; diff --git a/third_party/spirv-cross/reference/shaders-msl/comp/barriers.comp b/third_party/spirv-cross/reference/shaders-msl/comp/barriers.comp index 560fd8b53f..82813906f6 100644 --- a/third_party/spirv-cross/reference/shaders-msl/comp/barriers.comp +++ b/third_party/spirv-cross/reference/shaders-msl/comp/barriers.comp @@ -7,56 +7,67 @@ using namespace metal; constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(4u, 1u, 1u); +static inline __attribute__((always_inline)) void barrier_shared() { threadgroup_barrier(mem_flags::mem_threadgroup); } +static inline __attribute__((always_inline)) void full_barrier() { threadgroup_barrier(mem_flags::mem_device | mem_flags::mem_threadgroup | mem_flags::mem_texture); } +static inline __attribute__((always_inline)) void image_barrier() { threadgroup_barrier(mem_flags::mem_texture); } +static inline __attribute__((always_inline)) void buffer_barrier() { threadgroup_barrier(mem_flags::mem_device); } +static inline __attribute__((always_inline)) void group_barrier() { threadgroup_barrier(mem_flags::mem_device | mem_flags::mem_threadgroup | mem_flags::mem_texture); } +static inline __attribute__((always_inline)) void barrier_shared_exec() { threadgroup_barrier(mem_flags::mem_threadgroup); } +static inline __attribute__((always_inline)) void full_barrier_exec() { threadgroup_barrier(mem_flags::mem_device | mem_flags::mem_threadgroup | mem_flags::mem_texture); } +static inline __attribute__((always_inline)) void image_barrier_exec() { threadgroup_barrier(mem_flags::mem_texture); } +static inline __attribute__((always_inline)) void buffer_barrier_exec() { threadgroup_barrier(mem_flags::mem_device); } +static inline __attribute__((always_inline)) void group_barrier_exec() { threadgroup_barrier(mem_flags::mem_device | mem_flags::mem_threadgroup | mem_flags::mem_texture); } +static inline __attribute__((always_inline)) void exec_barrier() { threadgroup_barrier(mem_flags::mem_threadgroup); diff --git a/third_party/spirv-cross/reference/shaders-msl/comp/basic.comp b/third_party/spirv-cross/reference/shaders-msl/comp/basic.comp index 36b419b72a..42518f0d1d 100644 --- a/third_party/spirv-cross/reference/shaders-msl/comp/basic.comp +++ b/third_party/spirv-cross/reference/shaders-msl/comp/basic.comp @@ -21,6 +21,8 @@ struct SSBO3 uint counter; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + kernel void main0(const device SSBO& _23 [[buffer(0)]], device SSBO2& _45 [[buffer(1)]], device SSBO3& _48 [[buffer(2)]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]]) { uint ident = gl_GlobalInvocationID.x; diff --git a/third_party/spirv-cross/reference/shaders-msl/comp/basic.dispatchbase.comp b/third_party/spirv-cross/reference/shaders-msl/comp/basic.dispatchbase.comp new file mode 100644 index 0000000000..92d517cffb --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-msl/comp/basic.dispatchbase.comp @@ -0,0 +1,41 @@ +#pragma clang diagnostic ignored "-Wunused-variable" + +#include +#include +#include + +using namespace metal; + +struct SSBO +{ + float4 in_data[1]; +}; + +struct SSBO2 +{ + float4 out_data[1]; +}; + +struct SSBO3 +{ + uint counter; +}; + +constant uint _59_tmp [[function_constant(10)]]; +constant uint _59 = is_function_constant_defined(_59_tmp) ? _59_tmp : 1u; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(_59, 1u, 1u); + +kernel void main0(const device SSBO& _27 [[buffer(0)]], device SSBO2& _49 [[buffer(1)]], device SSBO3& _52 [[buffer(2)]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]], uint3 gl_WorkGroupID [[threadgroup_position_in_grid]], uint3 spvDispatchBase [[grid_origin]]) +{ + gl_GlobalInvocationID += spvDispatchBase * gl_WorkGroupSize; + gl_WorkGroupID += spvDispatchBase; + uint ident = gl_GlobalInvocationID.x; + uint workgroup = gl_WorkGroupID.x; + float4 idata = _27.in_data[ident]; + if (dot(idata, float4(1.0, 5.0, 6.0, 2.0)) > 8.19999980926513671875) + { + uint _56 = atomic_fetch_add_explicit((device atomic_uint*)&_52.counter, 1u, memory_order_relaxed); + _49.out_data[_56] = idata; + } +} + diff --git a/third_party/spirv-cross/reference/shaders-msl/comp/basic.dispatchbase.msl11.comp b/third_party/spirv-cross/reference/shaders-msl/comp/basic.dispatchbase.msl11.comp new file mode 100644 index 0000000000..87b0b44291 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-msl/comp/basic.dispatchbase.msl11.comp @@ -0,0 +1,39 @@ +#pragma clang diagnostic ignored "-Wunused-variable" + +#include +#include +#include + +using namespace metal; + +struct SSBO +{ + float4 in_data[1]; +}; + +struct SSBO2 +{ + float4 out_data[1]; +}; + +struct SSBO3 +{ + uint counter; +}; + +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + +kernel void main0(constant uint3& spvDispatchBase [[buffer(29)]], const device SSBO& _27 [[buffer(0)]], device SSBO2& _49 [[buffer(1)]], device SSBO3& _52 [[buffer(2)]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]], uint3 gl_WorkGroupID [[threadgroup_position_in_grid]]) +{ + gl_GlobalInvocationID += spvDispatchBase * gl_WorkGroupSize; + gl_WorkGroupID += spvDispatchBase; + uint ident = gl_GlobalInvocationID.x; + uint workgroup = gl_WorkGroupID.x; + float4 idata = _27.in_data[ident]; + if (dot(idata, float4(1.0, 5.0, 6.0, 2.0)) > 8.19999980926513671875) + { + uint _56 = atomic_fetch_add_explicit((device atomic_uint*)&_52.counter, 1u, memory_order_relaxed); + _49.out_data[_56] = idata; + } +} + diff --git a/third_party/spirv-cross/reference/shaders-msl/comp/basic.inline-block.msl2.comp b/third_party/spirv-cross/reference/shaders-msl/comp/basic.inline-block.msl2.comp new file mode 100644 index 0000000000..337b1b7336 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-msl/comp/basic.inline-block.msl2.comp @@ -0,0 +1,54 @@ +#include +#include + +using namespace metal; + +typedef packed_float4 packed_float4x4[4]; + +struct Baz +{ + int f; + int g; +}; + +struct X +{ + int x; + int y; + float z; +}; + +struct Foo +{ + int a; + int b; + packed_float4x4 c; + X x[2]; +}; + +struct Bar +{ + int d; + int e; +}; + +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(3u, 3u, 2u); + +struct spvDescriptorSetBuffer0 +{ + constant Bar* m_38 [[id(0)]]; + Foo m_32 [[id(1)]]; +}; + +struct spvDescriptorSetBuffer1 +{ + device Baz* baz [[id(0)]][3]; +}; + +kernel void main0(constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]], constant spvDescriptorSetBuffer1& spvDescriptorSet1 [[buffer(1)]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]]) +{ + uint3 coords = gl_GlobalInvocationID; + spvDescriptorSet1.baz[coords.x]->f = spvDescriptorSet0.m_32.a + (*spvDescriptorSet0.m_38).d; + spvDescriptorSet1.baz[coords.x]->g = spvDescriptorSet0.m_32.b * (*spvDescriptorSet0.m_38).e; +} + diff --git a/third_party/spirv-cross/reference/shaders-msl/comp/cfg-preserve-parameter.comp b/third_party/spirv-cross/reference/shaders-msl/comp/cfg-preserve-parameter.comp index d65beee5d2..ce1bef3f8e 100644 --- a/third_party/spirv-cross/reference/shaders-msl/comp/cfg-preserve-parameter.comp +++ b/third_party/spirv-cross/reference/shaders-msl/comp/cfg-preserve-parameter.comp @@ -5,6 +5,7 @@ using namespace metal; +static inline __attribute__((always_inline)) void out_test_0(thread const int& cond, thread int& i) { if (cond == 0) @@ -17,6 +18,7 @@ void out_test_0(thread const int& cond, thread int& i) } } +static inline __attribute__((always_inline)) void out_test_1(thread const int& cond, thread int& i) { switch (cond) @@ -34,6 +36,7 @@ void out_test_1(thread const int& cond, thread int& i) } } +static inline __attribute__((always_inline)) void inout_test_0(thread const int& cond, thread int& i) { if (cond == 0) @@ -42,6 +45,7 @@ void inout_test_0(thread const int& cond, thread int& i) } } +static inline __attribute__((always_inline)) void inout_test_1(thread const int& cond, thread int& i) { switch (cond) diff --git a/third_party/spirv-cross/reference/shaders-msl/comp/coherent-block.comp b/third_party/spirv-cross/reference/shaders-msl/comp/coherent-block.comp index 580b9e3e9d..58bbacb7f0 100644 --- a/third_party/spirv-cross/reference/shaders-msl/comp/coherent-block.comp +++ b/third_party/spirv-cross/reference/shaders-msl/comp/coherent-block.comp @@ -8,6 +8,8 @@ struct SSBO float4 value; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + kernel void main0(volatile device SSBO& _10 [[buffer(0)]]) { _10.value = float4(20.0); diff --git a/third_party/spirv-cross/reference/shaders-msl/comp/coherent-image.comp b/third_party/spirv-cross/reference/shaders-msl/comp/coherent-image.comp index c6af46b5a4..5090484464 100644 --- a/third_party/spirv-cross/reference/shaders-msl/comp/coherent-image.comp +++ b/third_party/spirv-cross/reference/shaders-msl/comp/coherent-image.comp @@ -8,6 +8,8 @@ struct SSBO int4 value; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + kernel void main0(volatile device SSBO& _10 [[buffer(0)]], texture2d uImage [[texture(0)]]) { _10.value = uImage.read(uint2(int2(10))); diff --git a/third_party/spirv-cross/reference/shaders-msl/comp/complex-composite-constant-array.comp b/third_party/spirv-cross/reference/shaders-msl/comp/complex-composite-constant-array.comp new file mode 100644 index 0000000000..2f5549f5fb --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-msl/comp/complex-composite-constant-array.comp @@ -0,0 +1,65 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + +#include +#include + +using namespace metal; + +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +struct SSBO +{ + float4x4 a; + uint index; +}; + +constant spvUnsafeArray _32 = spvUnsafeArray({ float4x4(float4(1.0, 0.0, 0.0, 0.0), float4(0.0, 1.0, 0.0, 0.0), float4(0.0, 0.0, 1.0, 0.0), float4(0.0, 0.0, 0.0, 1.0)), float4x4(float4(2.0, 0.0, 0.0, 0.0), float4(0.0, 2.0, 0.0, 0.0), float4(0.0, 0.0, 2.0, 0.0), float4(0.0, 0.0, 0.0, 2.0)) }); + +static inline __attribute__((always_inline)) +void write_global(device SSBO& v_14) +{ + v_14.a = _32[v_14.index]; +} + +kernel void main0(device SSBO& v_14 [[buffer(0)]]) +{ + write_global(v_14); +} + diff --git a/third_party/spirv-cross/reference/shaders-msl/comp/complex-type-alias.comp b/third_party/spirv-cross/reference/shaders-msl/comp/complex-type-alias.comp index 9101f89b74..fc0d57500b 100644 --- a/third_party/spirv-cross/reference/shaders-msl/comp/complex-type-alias.comp +++ b/third_party/spirv-cross/reference/shaders-msl/comp/complex-type-alias.comp @@ -44,6 +44,7 @@ struct SSBO constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(8u, 8u, 1u); +static inline __attribute__((always_inline)) void Zero(thread Foo0& v) { v.a = 0.0; diff --git a/third_party/spirv-cross/reference/shaders-msl/comp/composite-array-initialization.comp b/third_party/spirv-cross/reference/shaders-msl/comp/composite-array-initialization.comp index ac10e75012..c6c17b1f39 100644 --- a/third_party/spirv-cross/reference/shaders-msl/comp/composite-array-initialization.comp +++ b/third_party/spirv-cross/reference/shaders-msl/comp/composite-array-initialization.comp @@ -1,10 +1,49 @@ #pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" #include #include using namespace metal; +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + struct Data { float a; @@ -27,21 +66,9 @@ struct SSBO constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(2u, 1u, 1u); -constant Data _25[2] = { Data{ 1.0, 2.0 }, Data{ 3.0, 4.0 } }; - -// Implementation of an array copy function to cover GLSL's ability to copy an array via assignment. -template -void spvArrayCopyFromStack1(thread T (&dst)[N], thread const T (&src)[N]) -{ - for (uint i = 0; i < N; dst[i] = src[i], i++); -} - -template -void spvArrayCopyFromConstant1(thread T (&dst)[N], constant T (&src)[N]) -{ - for (uint i = 0; i < N; dst[i] = src[i], i++); -} +constant spvUnsafeArray _25 = spvUnsafeArray({ Data{ 1.0, 2.0 }, Data{ 3.0, 4.0 } }); +static inline __attribute__((always_inline)) Data combine(thread const Data& a, thread const Data& b) { return Data{ a.a + b.a, a.b + b.b }; @@ -49,10 +76,10 @@ Data combine(thread const Data& a, thread const Data& b) kernel void main0(device SSBO& _53 [[buffer(0)]], uint3 gl_WorkGroupID [[threadgroup_position_in_grid]], uint3 gl_LocalInvocationID [[thread_position_in_threadgroup]]) { - Data data[2] = { Data{ 1.0, 2.0 }, Data{ 3.0, 4.0 } }; - Data _31[2] = { Data{ X, 2.0 }, Data{ 3.0, 5.0 } }; - Data data2[2]; - spvArrayCopyFromStack1(data2, _31); + spvUnsafeArray data = spvUnsafeArray({ Data{ 1.0, 2.0 }, Data{ 3.0, 4.0 } }); + spvUnsafeArray _31 = spvUnsafeArray({ Data{ X, 2.0 }, Data{ 3.0, 5.0 } }); + spvUnsafeArray data2; + data2 = _31; Data param = data[gl_LocalInvocationID.x]; Data param_1 = data2[gl_LocalInvocationID.x]; Data _73 = combine(param, param_1); diff --git a/third_party/spirv-cross/reference/shaders-msl/comp/composite-array-initialization.force-native-array.comp b/third_party/spirv-cross/reference/shaders-msl/comp/composite-array-initialization.force-native-array.comp new file mode 100644 index 0000000000..f8e6ef92c8 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-msl/comp/composite-array-initialization.force-native-array.comp @@ -0,0 +1,104 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" + +#include +#include + +using namespace metal; + +struct Data +{ + float a; + float b; +}; + +constant float X_tmp [[function_constant(0)]]; +constant float X = is_function_constant_defined(X_tmp) ? X_tmp : 4.0; + +struct Data_1 +{ + float a; + float b; +}; + +struct SSBO +{ + Data_1 outdata[1]; +}; + +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(2u, 1u, 1u); + +constant Data _25[2] = { Data{ 1.0, 2.0 }, Data{ 3.0, 4.0 } }; + +template +inline void spvArrayCopyFromConstantToStack1(thread T (&dst)[A], constant T (&src)[A]) +{ + for (uint i = 0; i < A; i++) + { + dst[i] = src[i]; + } +} + +template +inline void spvArrayCopyFromConstantToThreadGroup1(threadgroup T (&dst)[A], constant T (&src)[A]) +{ + for (uint i = 0; i < A; i++) + { + dst[i] = src[i]; + } +} + +template +inline void spvArrayCopyFromStackToStack1(thread T (&dst)[A], thread const T (&src)[A]) +{ + for (uint i = 0; i < A; i++) + { + dst[i] = src[i]; + } +} + +template +inline void spvArrayCopyFromStackToThreadGroup1(threadgroup T (&dst)[A], thread const T (&src)[A]) +{ + for (uint i = 0; i < A; i++) + { + dst[i] = src[i]; + } +} + +template +inline void spvArrayCopyFromThreadGroupToStack1(thread T (&dst)[A], threadgroup const T (&src)[A]) +{ + for (uint i = 0; i < A; i++) + { + dst[i] = src[i]; + } +} + +template +inline void spvArrayCopyFromThreadGroupToThreadGroup1(threadgroup T (&dst)[A], threadgroup const T (&src)[A]) +{ + for (uint i = 0; i < A; i++) + { + dst[i] = src[i]; + } +} + +static inline __attribute__((always_inline)) +Data combine(thread const Data& a, thread const Data& b) +{ + return Data{ a.a + b.a, a.b + b.b }; +} + +kernel void main0(device SSBO& _53 [[buffer(0)]], uint3 gl_WorkGroupID [[threadgroup_position_in_grid]], uint3 gl_LocalInvocationID [[thread_position_in_threadgroup]]) +{ + Data data[2] = { Data{ 1.0, 2.0 }, Data{ 3.0, 4.0 } }; + Data _31[2] = { Data{ X, 2.0 }, Data{ 3.0, 5.0 } }; + Data data2[2]; + spvArrayCopyFromStackToStack1(data2, _31); + Data param = data[gl_LocalInvocationID.x]; + Data param_1 = data2[gl_LocalInvocationID.x]; + Data _73 = combine(param, param_1); + _53.outdata[gl_WorkGroupID.x].a = _73.a; + _53.outdata[gl_WorkGroupID.x].b = _73.b; +} + diff --git a/third_party/spirv-cross/reference/shaders-msl/comp/composite-construct.comp b/third_party/spirv-cross/reference/shaders-msl/comp/composite-construct.comp index 4b5ea37e98..aada82fc92 100644 --- a/third_party/spirv-cross/reference/shaders-msl/comp/composite-construct.comp +++ b/third_party/spirv-cross/reference/shaders-msl/comp/composite-construct.comp @@ -1,10 +1,49 @@ #pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" #include #include using namespace metal; +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + struct SSBO0 { float4 as[1]; @@ -21,26 +60,15 @@ struct Composite float4 b; }; -constant float4 _43[2] = { float4(20.0), float4(40.0) }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); -// Implementation of an array copy function to cover GLSL's ability to copy an array via assignment. -template -void spvArrayCopyFromStack1(thread T (&dst)[N], thread const T (&src)[N]) -{ - for (uint i = 0; i < N; dst[i] = src[i], i++); -} - -template -void spvArrayCopyFromConstant1(thread T (&dst)[N], constant T (&src)[N]) -{ - for (uint i = 0; i < N; dst[i] = src[i], i++); -} +constant spvUnsafeArray _43 = spvUnsafeArray({ float4(20.0), float4(40.0) }); kernel void main0(device SSBO0& _16 [[buffer(0)]], device SSBO1& _32 [[buffer(1)]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]], uint gl_LocalInvocationIndex [[thread_index_in_threadgroup]]) { - float4 _37[2] = { _16.as[gl_GlobalInvocationID.x], _32.bs[gl_GlobalInvocationID.x] }; - float4 values[2]; - spvArrayCopyFromStack1(values, _37); + spvUnsafeArray _37 = spvUnsafeArray({ _16.as[gl_GlobalInvocationID.x], _32.bs[gl_GlobalInvocationID.x] }); + spvUnsafeArray values; + values = _37; Composite c = Composite{ values[0], _43[1] }; _16.as[0] = values[gl_LocalInvocationIndex]; _32.bs[1] = c.b; diff --git a/third_party/spirv-cross/reference/shaders-msl/comp/copy-array-of-arrays.comp b/third_party/spirv-cross/reference/shaders-msl/comp/copy-array-of-arrays.comp index 0fa6c6bfd3..21fb9b367c 100644 --- a/third_party/spirv-cross/reference/shaders-msl/comp/copy-array-of-arrays.comp +++ b/third_party/spirv-cross/reference/shaders-msl/comp/copy-array-of-arrays.comp @@ -1,10 +1,49 @@ #pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" #include #include using namespace metal; +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + struct BUF { int a; @@ -12,76 +51,29 @@ struct BUF float c; }; -constant float _16[2] = { 1.0, 2.0 }; -constant float _19[2] = { 3.0, 4.0 }; -constant float _20[2][2] = { { 1.0, 2.0 }, { 3.0, 4.0 } }; -constant float _21[2][2][2] = { { { 1.0, 2.0 }, { 3.0, 4.0 } }, { { 1.0, 2.0 }, { 3.0, 4.0 } } }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); -// Implementation of an array copy function to cover GLSL's ability to copy an array via assignment. -template -void spvArrayCopyFromStack1(thread T (&dst)[N], thread const T (&src)[N]) -{ - for (uint i = 0; i < N; dst[i] = src[i], i++); -} - -template -void spvArrayCopyFromConstant1(thread T (&dst)[N], constant T (&src)[N]) -{ - for (uint i = 0; i < N; dst[i] = src[i], i++); -} - -template -void spvArrayCopyFromStack2(thread T (&dst)[A][B], thread const T (&src)[A][B]) -{ - for (uint i = 0; i < A; i++) - { - spvArrayCopyFromStack1(dst[i], src[i]); - } -} - -template -void spvArrayCopyFromConstant2(thread T (&dst)[A][B], constant T (&src)[A][B]) -{ - for (uint i = 0; i < A; i++) - { - spvArrayCopyFromConstant1(dst[i], src[i]); - } -} - -template -void spvArrayCopyFromStack3(thread T (&dst)[A][B][C], thread const T (&src)[A][B][C]) -{ - for (uint i = 0; i < A; i++) - { - spvArrayCopyFromStack2(dst[i], src[i]); - } -} - -template -void spvArrayCopyFromConstant3(thread T (&dst)[A][B][C], constant T (&src)[A][B][C]) -{ - for (uint i = 0; i < A; i++) - { - spvArrayCopyFromConstant2(dst[i], src[i]); - } -} +constant spvUnsafeArray _16 = spvUnsafeArray({ 1.0, 2.0 }); +constant spvUnsafeArray _19 = spvUnsafeArray({ 3.0, 4.0 }); +constant spvUnsafeArray, 2> _20 = spvUnsafeArray, 2>({ spvUnsafeArray({ 1.0, 2.0 }), spvUnsafeArray({ 3.0, 4.0 }) }); +constant spvUnsafeArray, 2>, 2> _21 = spvUnsafeArray, 2>, 2>({ spvUnsafeArray, 2>({ spvUnsafeArray({ 1.0, 2.0 }), spvUnsafeArray({ 3.0, 4.0 }) }), spvUnsafeArray, 2>({ spvUnsafeArray({ 1.0, 2.0 }), spvUnsafeArray({ 3.0, 4.0 }) }) }); kernel void main0(device BUF& o [[buffer(0)]]) { - float c[2][2][2]; - spvArrayCopyFromConstant3(c, _21); + spvUnsafeArray, 2>, 2> c; + c = _21; o.a = int(c[1][1][1]); - float _43[2] = { o.b, o.c }; - float _48[2] = { o.b, o.b }; - float _49[2][2] = { { _43[0], _43[1] }, { _48[0], _48[1] } }; - float _54[2] = { o.c, o.c }; - float _59[2] = { o.c, o.b }; - float _60[2][2] = { { _54[0], _54[1] }, { _59[0], _59[1] } }; - float _61[2][2][2] = { { { _49[0][0], _49[0][1] }, { _49[1][0], _49[1][1] } }, { { _60[0][0], _60[0][1] }, { _60[1][0], _60[1][1] } } }; - float d[2][2][2]; - spvArrayCopyFromStack3(d, _61); - float e[2][2][2]; - spvArrayCopyFromStack3(e, d); + spvUnsafeArray _43 = spvUnsafeArray({ o.b, o.c }); + spvUnsafeArray _48 = spvUnsafeArray({ o.b, o.b }); + spvUnsafeArray, 2> _49 = spvUnsafeArray, 2>({ _43, _48 }); + spvUnsafeArray _54 = spvUnsafeArray({ o.c, o.c }); + spvUnsafeArray _59 = spvUnsafeArray({ o.c, o.b }); + spvUnsafeArray, 2> _60 = spvUnsafeArray, 2>({ _54, _59 }); + spvUnsafeArray, 2>, 2> _61 = spvUnsafeArray, 2>, 2>({ _49, _60 }); + spvUnsafeArray, 2>, 2> d; + d = _61; + spvUnsafeArray, 2>, 2> e; + e = d; o.b = e[1][0][1]; } diff --git a/third_party/spirv-cross/reference/shaders-msl/comp/copy-array-of-arrays.force-native-array.comp b/third_party/spirv-cross/reference/shaders-msl/comp/copy-array-of-arrays.force-native-array.comp new file mode 100644 index 0000000000..5f8b033037 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-msl/comp/copy-array-of-arrays.force-native-array.comp @@ -0,0 +1,202 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" + +#include +#include + +using namespace metal; + +struct BUF +{ + int a; + float b; + float c; +}; + +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + +constant float _16[2] = { 1.0, 2.0 }; +constant float _19[2] = { 3.0, 4.0 }; +constant float _20[2][2] = { { 1.0, 2.0 }, { 3.0, 4.0 } }; +constant float _21[2][2][2] = { { { 1.0, 2.0 }, { 3.0, 4.0 } }, { { 1.0, 2.0 }, { 3.0, 4.0 } } }; + +template +inline void spvArrayCopyFromConstantToStack1(thread T (&dst)[A], constant T (&src)[A]) +{ + for (uint i = 0; i < A; i++) + { + dst[i] = src[i]; + } +} + +template +inline void spvArrayCopyFromConstantToThreadGroup1(threadgroup T (&dst)[A], constant T (&src)[A]) +{ + for (uint i = 0; i < A; i++) + { + dst[i] = src[i]; + } +} + +template +inline void spvArrayCopyFromStackToStack1(thread T (&dst)[A], thread const T (&src)[A]) +{ + for (uint i = 0; i < A; i++) + { + dst[i] = src[i]; + } +} + +template +inline void spvArrayCopyFromStackToThreadGroup1(threadgroup T (&dst)[A], thread const T (&src)[A]) +{ + for (uint i = 0; i < A; i++) + { + dst[i] = src[i]; + } +} + +template +inline void spvArrayCopyFromThreadGroupToStack1(thread T (&dst)[A], threadgroup const T (&src)[A]) +{ + for (uint i = 0; i < A; i++) + { + dst[i] = src[i]; + } +} + +template +inline void spvArrayCopyFromThreadGroupToThreadGroup1(threadgroup T (&dst)[A], threadgroup const T (&src)[A]) +{ + for (uint i = 0; i < A; i++) + { + dst[i] = src[i]; + } +} + +template +inline void spvArrayCopyFromConstantToStack2(thread T (&dst)[A][B], constant T (&src)[A][B]) +{ + for (uint i = 0; i < A; i++) + { + spvArrayCopyFromConstantToStack1(dst[i], src[i]); + } +} + +template +inline void spvArrayCopyFromConstantToThreadGroup2(threadgroup T (&dst)[A][B], constant T (&src)[A][B]) +{ + for (uint i = 0; i < A; i++) + { + spvArrayCopyFromConstantToThreadGroup1(dst[i], src[i]); + } +} + +template +inline void spvArrayCopyFromStackToStack2(thread T (&dst)[A][B], thread const T (&src)[A][B]) +{ + for (uint i = 0; i < A; i++) + { + spvArrayCopyFromStackToStack1(dst[i], src[i]); + } +} + +template +inline void spvArrayCopyFromStackToThreadGroup2(threadgroup T (&dst)[A][B], thread const T (&src)[A][B]) +{ + for (uint i = 0; i < A; i++) + { + spvArrayCopyFromStackToThreadGroup1(dst[i], src[i]); + } +} + +template +inline void spvArrayCopyFromThreadGroupToStack2(thread T (&dst)[A][B], threadgroup const T (&src)[A][B]) +{ + for (uint i = 0; i < A; i++) + { + spvArrayCopyFromThreadGroupToStack1(dst[i], src[i]); + } +} + +template +inline void spvArrayCopyFromThreadGroupToThreadGroup2(threadgroup T (&dst)[A][B], threadgroup const T (&src)[A][B]) +{ + for (uint i = 0; i < A; i++) + { + spvArrayCopyFromThreadGroupToThreadGroup1(dst[i], src[i]); + } +} + +template +inline void spvArrayCopyFromConstantToStack3(thread T (&dst)[A][B][C], constant T (&src)[A][B][C]) +{ + for (uint i = 0; i < A; i++) + { + spvArrayCopyFromConstantToStack2(dst[i], src[i]); + } +} + +template +inline void spvArrayCopyFromConstantToThreadGroup3(threadgroup T (&dst)[A][B][C], constant T (&src)[A][B][C]) +{ + for (uint i = 0; i < A; i++) + { + spvArrayCopyFromConstantToThreadGroup2(dst[i], src[i]); + } +} + +template +inline void spvArrayCopyFromStackToStack3(thread T (&dst)[A][B][C], thread const T (&src)[A][B][C]) +{ + for (uint i = 0; i < A; i++) + { + spvArrayCopyFromStackToStack2(dst[i], src[i]); + } +} + +template +inline void spvArrayCopyFromStackToThreadGroup3(threadgroup T (&dst)[A][B][C], thread const T (&src)[A][B][C]) +{ + for (uint i = 0; i < A; i++) + { + spvArrayCopyFromStackToThreadGroup2(dst[i], src[i]); + } +} + +template +inline void spvArrayCopyFromThreadGroupToStack3(thread T (&dst)[A][B][C], threadgroup const T (&src)[A][B][C]) +{ + for (uint i = 0; i < A; i++) + { + spvArrayCopyFromThreadGroupToStack2(dst[i], src[i]); + } +} + +template +inline void spvArrayCopyFromThreadGroupToThreadGroup3(threadgroup T (&dst)[A][B][C], threadgroup const T (&src)[A][B][C]) +{ + for (uint i = 0; i < A; i++) + { + spvArrayCopyFromThreadGroupToThreadGroup2(dst[i], src[i]); + } +} + +kernel void main0(device BUF& o [[buffer(0)]]) +{ + float c[2][2][2]; + spvArrayCopyFromConstantToStack3(c, _21); + o.a = int(c[1][1][1]); + float _43[2] = { o.b, o.c }; + float _48[2] = { o.b, o.b }; + float _49[2][2] = { { _43[0], _43[1] }, { _48[0], _48[1] } }; + float _54[2] = { o.c, o.c }; + float _59[2] = { o.c, o.b }; + float _60[2][2] = { { _54[0], _54[1] }, { _59[0], _59[1] } }; + float _61[2][2][2] = { { { _49[0][0], _49[0][1] }, { _49[1][0], _49[1][1] } }, { { _60[0][0], _60[0][1] }, { _60[1][0], _60[1][1] } } }; + float d[2][2][2]; + spvArrayCopyFromStackToStack3(d, _61); + float e[2][2][2]; + spvArrayCopyFromStackToStack3(e, d); + o.b = e[1][0][1]; +} + diff --git a/third_party/spirv-cross/reference/shaders-msl/comp/defer-parens.comp b/third_party/spirv-cross/reference/shaders-msl/comp/defer-parens.comp index 76dce77734..9a567fa6eb 100644 --- a/third_party/spirv-cross/reference/shaders-msl/comp/defer-parens.comp +++ b/third_party/spirv-cross/reference/shaders-msl/comp/defer-parens.comp @@ -9,6 +9,8 @@ struct SSBO int index; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + kernel void main0(device SSBO& _13 [[buffer(0)]]) { float4 d = _13.data; diff --git a/third_party/spirv-cross/reference/shaders-msl/comp/dowhile.comp b/third_party/spirv-cross/reference/shaders-msl/comp/dowhile.comp index 3482fb355b..2b4de9ebb7 100644 --- a/third_party/spirv-cross/reference/shaders-msl/comp/dowhile.comp +++ b/third_party/spirv-cross/reference/shaders-msl/comp/dowhile.comp @@ -14,6 +14,8 @@ struct SSBO2 float4 out_data[1]; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + kernel void main0(const device SSBO& _28 [[buffer(0)]], device SSBO2& _52 [[buffer(1)]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]]) { uint ident = gl_GlobalInvocationID.x; diff --git a/third_party/spirv-cross/reference/shaders-msl/comp/force-recompile-hooks.swizzle.comp b/third_party/spirv-cross/reference/shaders-msl/comp/force-recompile-hooks.swizzle.comp index f9608de34d..856efeabaf 100644 --- a/third_party/spirv-cross/reference/shaders-msl/comp/force-recompile-hooks.swizzle.comp +++ b/third_party/spirv-cross/reference/shaders-msl/comp/force-recompile-hooks.swizzle.comp @@ -5,17 +5,6 @@ using namespace metal; -enum class spvSwizzle : uint -{ - none = 0, - zero, - one, - red, - green, - blue, - alpha -}; - template struct spvRemoveReference { typedef T type; }; template struct spvRemoveReference { typedef T type; }; template struct spvRemoveReference { typedef T type; }; @@ -28,6 +17,17 @@ template inline constexpr thread T&& spvForward(thread typename spvR return static_cast(x); } +enum class spvSwizzle : uint +{ + none = 0, + zero, + one, + red, + green, + blue, + alpha +}; + template inline T spvGetSwizzle(vec x, T c, spvSwizzle s) { @@ -65,66 +65,6 @@ inline T spvTextureSwizzle(T x, uint s) return spvTextureSwizzle(vec(x, 0, 0, 1), s).x; } -// Wrapper function that swizzles texture gathers. -template -inline vec spvGatherSwizzle(sampler s, const thread Tex& t, Ts... params, component c, uint sw) METAL_CONST_ARG(c) -{ - if (sw) - { - switch (spvSwizzle((sw >> (uint(c) * 8)) & 0xFF)) - { - case spvSwizzle::none: - break; - case spvSwizzle::zero: - return vec(0, 0, 0, 0); - case spvSwizzle::one: - return vec(1, 1, 1, 1); - case spvSwizzle::red: - return t.gather(s, spvForward(params)..., component::x); - case spvSwizzle::green: - return t.gather(s, spvForward(params)..., component::y); - case spvSwizzle::blue: - return t.gather(s, spvForward(params)..., component::z); - case spvSwizzle::alpha: - return t.gather(s, spvForward(params)..., component::w); - } - } - switch (c) - { - case component::x: - return t.gather(s, spvForward(params)..., component::x); - case component::y: - return t.gather(s, spvForward(params)..., component::y); - case component::z: - return t.gather(s, spvForward(params)..., component::z); - case component::w: - return t.gather(s, spvForward(params)..., component::w); - } -} - -// Wrapper function that swizzles depth texture gathers. -template -inline vec spvGatherCompareSwizzle(sampler s, const thread Tex& t, Ts... params, uint sw) -{ - if (sw) - { - switch (spvSwizzle(sw & 0xFF)) - { - case spvSwizzle::none: - case spvSwizzle::red: - break; - case spvSwizzle::zero: - case spvSwizzle::green: - case spvSwizzle::blue: - case spvSwizzle::alpha: - return vec(0, 0, 0, 0); - case spvSwizzle::one: - return vec(1, 1, 1, 1); - } - } - return t.gather_compare(s, spvForward(params)...); -} - kernel void main0(constant uint* spvSwizzleConstants [[buffer(30)]], texture2d foo [[texture(0)]], texture2d bar [[texture(1)]], sampler fooSmplr [[sampler(0)]]) { constant uint& fooSwzl = spvSwizzleConstants[0]; diff --git a/third_party/spirv-cross/reference/shaders-msl/comp/functions.comp b/third_party/spirv-cross/reference/shaders-msl/comp/functions.comp index d8f6e55a46..b107260878 100644 --- a/third_party/spirv-cross/reference/shaders-msl/comp/functions.comp +++ b/third_party/spirv-cross/reference/shaders-msl/comp/functions.comp @@ -5,6 +5,7 @@ using namespace metal; +static inline __attribute__((always_inline)) void myfunc(threadgroup int (&foo)[1337]) { foo[0] = 13; diff --git a/third_party/spirv-cross/reference/shaders-msl/comp/global-invocation-id-writable-ssbo-in-function.comp b/third_party/spirv-cross/reference/shaders-msl/comp/global-invocation-id-writable-ssbo-in-function.comp index 1b525c1f90..dbc5886356 100644 --- a/third_party/spirv-cross/reference/shaders-msl/comp/global-invocation-id-writable-ssbo-in-function.comp +++ b/third_party/spirv-cross/reference/shaders-msl/comp/global-invocation-id-writable-ssbo-in-function.comp @@ -13,11 +13,12 @@ struct myBlock // Implementation of the GLSL mod() function, which is slightly different than Metal fmod() template -Tx mod(Tx x, Ty y) +inline Tx mod(Tx x, Ty y) { return x - y * floor(x / y); } +static inline __attribute__((always_inline)) float getB(device myBlock& myStorage, thread uint3& gl_GlobalInvocationID) { return myStorage.b[gl_GlobalInvocationID.x]; diff --git a/third_party/spirv-cross/reference/shaders-msl/comp/global-invocation-id.comp b/third_party/spirv-cross/reference/shaders-msl/comp/global-invocation-id.comp index fe0212ec3f..9900b59311 100644 --- a/third_party/spirv-cross/reference/shaders-msl/comp/global-invocation-id.comp +++ b/third_party/spirv-cross/reference/shaders-msl/comp/global-invocation-id.comp @@ -13,7 +13,7 @@ struct myBlock // Implementation of the GLSL mod() function, which is slightly different than Metal fmod() template -Tx mod(Tx x, Ty y) +inline Tx mod(Tx x, Ty y) { return x - y * floor(x / y); } diff --git a/third_party/spirv-cross/reference/shaders-msl/comp/image-atomic-automatic-bindings.comp b/third_party/spirv-cross/reference/shaders-msl/comp/image-atomic-automatic-bindings.comp new file mode 100644 index 0000000000..40a8dfcd71 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-msl/comp/image-atomic-automatic-bindings.comp @@ -0,0 +1,26 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wunused-variable" + +#include +#include +#include + +using namespace metal; + +struct SSBO +{ + float4 outdata; +}; + +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + +// Returns buffer coords corresponding to 2D texture coords for emulating 2D texture atomics +#define spvImage2DAtomicCoord(tc, tex) (((tex).get_width() * (tc).x) + (tc).y) + +kernel void main0(device SSBO& _31 [[buffer(1)]], texture2d uImage [[texture(0)]], device atomic_uint* uImage_atomic [[buffer(0)]], texture2d uTexture [[texture(1)]], sampler uTextureSmplr [[sampler(0)]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]]) +{ + uint _26 = atomic_fetch_add_explicit((device atomic_uint*)&uImage_atomic[spvImage2DAtomicCoord(int2(gl_GlobalInvocationID.xy), uImage)], 10u, memory_order_relaxed); + uint ret = _26; + _31.outdata = uTexture.sample(uTextureSmplr, float2(gl_GlobalInvocationID.xy), level(0.0)) + float4(float(ret)); +} + diff --git a/third_party/spirv-cross/reference/shaders-msl/comp/image-cube-array-load-store.comp b/third_party/spirv-cross/reference/shaders-msl/comp/image-cube-array-load-store.comp index ef67a326f5..c0b83c46c8 100644 --- a/third_party/spirv-cross/reference/shaders-msl/comp/image-cube-array-load-store.comp +++ b/third_party/spirv-cross/reference/shaders-msl/comp/image-cube-array-load-store.comp @@ -3,6 +3,8 @@ using namespace metal; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + kernel void main0(texturecube_array uImageIn [[texture(0)]], texturecube_array uImageOut [[texture(1)]]) { int3 coord = int3(9, 7, 11); diff --git a/third_party/spirv-cross/reference/shaders-msl/comp/image.comp b/third_party/spirv-cross/reference/shaders-msl/comp/image.comp index f3bc1455db..e7c9c763a3 100644 --- a/third_party/spirv-cross/reference/shaders-msl/comp/image.comp +++ b/third_party/spirv-cross/reference/shaders-msl/comp/image.comp @@ -3,6 +3,8 @@ using namespace metal; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + kernel void main0(texture2d uImageIn [[texture(0)]], texture2d uImageOut [[texture(1)]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]]) { float4 v = uImageIn.read(uint2((int2(gl_GlobalInvocationID.xy) + int2(uImageIn.get_width(), uImageIn.get_height())))); diff --git a/third_party/spirv-cross/reference/shaders-msl/comp/insert.comp b/third_party/spirv-cross/reference/shaders-msl/comp/insert.comp index 0f56a65153..e3e858a481 100644 --- a/third_party/spirv-cross/reference/shaders-msl/comp/insert.comp +++ b/third_party/spirv-cross/reference/shaders-msl/comp/insert.comp @@ -8,6 +8,8 @@ struct SSBO float4 out_data[1]; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + kernel void main0(device SSBO& _27 [[buffer(0)]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]]) { float4 v; diff --git a/third_party/spirv-cross/reference/shaders-msl/comp/int64.invalid.msl22.comp b/third_party/spirv-cross/reference/shaders-msl/comp/int64.invalid.msl22.comp deleted file mode 100644 index 6eb4a8a8d9..0000000000 --- a/third_party/spirv-cross/reference/shaders-msl/comp/int64.invalid.msl22.comp +++ /dev/null @@ -1,63 +0,0 @@ -#include -#include - -using namespace metal; - -struct M0 -{ - long v; - long2 b[2]; - ulong c; - ulong d[5]; -}; - -struct SSBO0_Type -{ - long4 a; - M0 m0; -}; - -struct SSBO1_Type -{ - ulong4 b; - M0 m0; -}; - -struct SSBO2_Type -{ - long a[4]; - long2 b[4]; -}; - -struct SSBO3_Type -{ - long a[4]; - long2 b[4]; -}; - -struct SSBO -{ - int s32; - uint u32; -}; - -kernel void main0(device SSBO& _96 [[buffer(0)]]) -{ - SSBO0_Type ssbo_0; - ssbo_0.a += long4(10l, 20l, 30l, 40l); - SSBO1_Type ssbo_1; - ssbo_1.b += ulong4(999999999999999999ul, 8888888888888888ul, 77777777777777777ul, 6666666666666666ul); - ssbo_0.a += long4(20l); - ssbo_0.a = abs(ssbo_0.a + long4(ssbo_1.b)); - ssbo_0.a += long4(1l); - ssbo_1.b += ulong4(long4(1l)); - ssbo_0.a -= long4(1l); - ssbo_1.b -= ulong4(long4(1l)); - SSBO2_Type ssbo_2; - ssbo_2.a[0] += 1l; - SSBO3_Type ssbo_3; - ssbo_3.a[0] += 2l; - _96.s32 = int(uint(((ulong(ssbo_0.a.x) + ssbo_1.b.y) + ulong(ssbo_2.a[1])) + ulong(ssbo_3.a[2]))); - _96.u32 = uint(((ulong(ssbo_0.a.y) + ssbo_1.b.z) + ulong(ssbo_2.a[0])) + ulong(ssbo_3.a[1])); -} - diff --git a/third_party/spirv-cross/reference/shaders-msl/comp/inverse.comp b/third_party/spirv-cross/reference/shaders-msl/comp/inverse.comp index f2f499b91e..33aed468f7 100644 --- a/third_party/spirv-cross/reference/shaders-msl/comp/inverse.comp +++ b/third_party/spirv-cross/reference/shaders-msl/comp/inverse.comp @@ -19,20 +19,25 @@ struct MatrixIn float4x4 m4in; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + // Returns the determinant of a 2x2 matrix. -inline float spvDet2x2(float a1, float a2, float b1, float b2) +static inline __attribute__((always_inline)) +float spvDet2x2(float a1, float a2, float b1, float b2) { return a1 * b2 - b1 * a2; } // Returns the determinant of a 3x3 matrix. -inline float spvDet3x3(float a1, float a2, float a3, float b1, float b2, float b3, float c1, float c2, float c3) +static inline __attribute__((always_inline)) +float spvDet3x3(float a1, float a2, float a3, float b1, float b2, float b3, float c1, float c2, float c3) { return a1 * spvDet2x2(b2, b3, c2, c3) - b1 * spvDet2x2(a2, a3, c2, c3) + c1 * spvDet2x2(a2, a3, b2, b3); } // Returns the inverse of a matrix, by using the algorithm of calculating the classical // adjoint and dividing by the determinant. The contents of the matrix are changed. +static inline __attribute__((always_inline)) float4x4 spvInverse4x4(float4x4 m) { float4x4 adj; // The adjoint matrix (inverse after dividing by determinant) @@ -68,6 +73,7 @@ float4x4 spvInverse4x4(float4x4 m) // Returns the inverse of a matrix, by using the algorithm of calculating the classical // adjoint and dividing by the determinant. The contents of the matrix are changed. +static inline __attribute__((always_inline)) float3x3 spvInverse3x3(float3x3 m) { float3x3 adj; // The adjoint matrix (inverse after dividing by determinant) @@ -95,6 +101,7 @@ float3x3 spvInverse3x3(float3x3 m) // Returns the inverse of a matrix, by using the algorithm of calculating the classical // adjoint and dividing by the determinant. The contents of the matrix are changed. +static inline __attribute__((always_inline)) float2x2 spvInverse2x2(float2x2 m) { float2x2 adj; // The adjoint matrix (inverse after dividing by determinant) diff --git a/third_party/spirv-cross/reference/shaders-msl/comp/local-invocation-id.comp b/third_party/spirv-cross/reference/shaders-msl/comp/local-invocation-id.comp index 772e5e0d86..362aaa30c8 100644 --- a/third_party/spirv-cross/reference/shaders-msl/comp/local-invocation-id.comp +++ b/third_party/spirv-cross/reference/shaders-msl/comp/local-invocation-id.comp @@ -13,7 +13,7 @@ struct myBlock // Implementation of the GLSL mod() function, which is slightly different than Metal fmod() template -Tx mod(Tx x, Ty y) +inline Tx mod(Tx x, Ty y) { return x - y * floor(x / y); } diff --git a/third_party/spirv-cross/reference/shaders-msl/comp/local-invocation-index.comp b/third_party/spirv-cross/reference/shaders-msl/comp/local-invocation-index.comp index 41adbdca5c..f8c1550eab 100644 --- a/third_party/spirv-cross/reference/shaders-msl/comp/local-invocation-index.comp +++ b/third_party/spirv-cross/reference/shaders-msl/comp/local-invocation-index.comp @@ -13,7 +13,7 @@ struct myBlock // Implementation of the GLSL mod() function, which is slightly different than Metal fmod() template -Tx mod(Tx x, Ty y) +inline Tx mod(Tx x, Ty y) { return x - y * floor(x / y); } diff --git a/third_party/spirv-cross/reference/shaders-msl/comp/mat3.comp b/third_party/spirv-cross/reference/shaders-msl/comp/mat3.comp index c2d9a7c838..fcb8f7a60f 100644 --- a/third_party/spirv-cross/reference/shaders-msl/comp/mat3.comp +++ b/third_party/spirv-cross/reference/shaders-msl/comp/mat3.comp @@ -8,6 +8,8 @@ struct SSBO2 float3x3 out_data[1]; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + kernel void main0(device SSBO2& _22 [[buffer(0)]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]]) { uint ident = gl_GlobalInvocationID.x; diff --git a/third_party/spirv-cross/reference/shaders-msl/comp/mod.comp b/third_party/spirv-cross/reference/shaders-msl/comp/mod.comp index e0d290259c..96264b05b7 100644 --- a/third_party/spirv-cross/reference/shaders-msl/comp/mod.comp +++ b/third_party/spirv-cross/reference/shaders-msl/comp/mod.comp @@ -15,9 +15,11 @@ struct SSBO2 float4 out_data[1]; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + // Implementation of the GLSL mod() function, which is slightly different than Metal fmod() template -Tx mod(Tx x, Ty y) +inline Tx mod(Tx x, Ty y) { return x - y * floor(x / y); } diff --git a/third_party/spirv-cross/reference/shaders-msl/comp/modf.comp b/third_party/spirv-cross/reference/shaders-msl/comp/modf.comp index ef50a02135..5a5ac3dbd7 100644 --- a/third_party/spirv-cross/reference/shaders-msl/comp/modf.comp +++ b/third_party/spirv-cross/reference/shaders-msl/comp/modf.comp @@ -13,6 +13,8 @@ struct SSBO2 float4 out_data[1]; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + kernel void main0(const device SSBO& _23 [[buffer(0)]], device SSBO2& _35 [[buffer(1)]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]]) { uint ident = gl_GlobalInvocationID.x; diff --git a/third_party/spirv-cross/reference/shaders-msl/comp/outer-product.comp b/third_party/spirv-cross/reference/shaders-msl/comp/outer-product.comp index 8e32db392e..e589642dbd 100644 --- a/third_party/spirv-cross/reference/shaders-msl/comp/outer-product.comp +++ b/third_party/spirv-cross/reference/shaders-msl/comp/outer-product.comp @@ -23,6 +23,8 @@ struct ReadSSBO float4 v4; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + kernel void main0(device SSBO& _21 [[buffer(0)]], const device ReadSSBO& _26 [[buffer(1)]]) { _21.m22 = float2x2(_26.v2 * _26.v2.x, _26.v2 * _26.v2.y); diff --git a/third_party/spirv-cross/reference/shaders-msl/comp/read-write-only.comp b/third_party/spirv-cross/reference/shaders-msl/comp/read-write-only.comp index 7547b417d8..0cf8d8e321 100644 --- a/third_party/spirv-cross/reference/shaders-msl/comp/read-write-only.comp +++ b/third_party/spirv-cross/reference/shaders-msl/comp/read-write-only.comp @@ -21,6 +21,8 @@ struct SSBO1 float4 data3; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + kernel void main0(device SSBO2& _10 [[buffer(0)]], const device SSBO0& _15 [[buffer(1)]], device SSBO1& _21 [[buffer(2)]]) { _10.data4 = _15.data0 + _21.data2; diff --git a/third_party/spirv-cross/reference/shaders-msl/comp/rmw-matrix.comp b/third_party/spirv-cross/reference/shaders-msl/comp/rmw-matrix.comp index 150db7ede9..b53a3a75c2 100644 --- a/third_party/spirv-cross/reference/shaders-msl/comp/rmw-matrix.comp +++ b/third_party/spirv-cross/reference/shaders-msl/comp/rmw-matrix.comp @@ -13,6 +13,8 @@ struct SSBO float4x4 c1; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + kernel void main0(device SSBO& _11 [[buffer(0)]]) { _11.a *= _11.a1; diff --git a/third_party/spirv-cross/reference/shaders-msl/comp/rmw-opt.comp b/third_party/spirv-cross/reference/shaders-msl/comp/rmw-opt.comp index 060f9f9c71..229154fc21 100644 --- a/third_party/spirv-cross/reference/shaders-msl/comp/rmw-opt.comp +++ b/third_party/spirv-cross/reference/shaders-msl/comp/rmw-opt.comp @@ -8,6 +8,8 @@ struct SSBO int a; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + kernel void main0(device SSBO& _9 [[buffer(0)]]) { _9.a += 10; diff --git a/third_party/spirv-cross/reference/shaders-msl/comp/scalar-std450-distance-length-normalize.comp b/third_party/spirv-cross/reference/shaders-msl/comp/scalar-std450-distance-length-normalize.comp index 312a6f9453..0ae6e5562b 100644 --- a/third_party/spirv-cross/reference/shaders-msl/comp/scalar-std450-distance-length-normalize.comp +++ b/third_party/spirv-cross/reference/shaders-msl/comp/scalar-std450-distance-length-normalize.comp @@ -12,6 +12,8 @@ struct SSBO float e; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + kernel void main0(device SSBO& _9 [[buffer(0)]]) { _9.c = abs(_9.a - _9.b); diff --git a/third_party/spirv-cross/reference/shaders-msl/comp/shared-array-of-arrays.comp b/third_party/spirv-cross/reference/shaders-msl/comp/shared-array-of-arrays.comp index 7acb0ab857..8b53236895 100644 --- a/third_party/spirv-cross/reference/shaders-msl/comp/shared-array-of-arrays.comp +++ b/third_party/spirv-cross/reference/shaders-msl/comp/shared-array-of-arrays.comp @@ -12,6 +12,7 @@ struct SSBO constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(4u, 4u, 1u); +static inline __attribute__((always_inline)) void work(threadgroup float (&foo)[4][4], thread uint3& gl_LocalInvocationID, thread uint& gl_LocalInvocationIndex, device SSBO& v_67, thread uint3& gl_GlobalInvocationID) { foo[gl_LocalInvocationID.x][gl_LocalInvocationID.y] = float(gl_LocalInvocationIndex); diff --git a/third_party/spirv-cross/reference/shaders-msl/comp/spec-constant-op-member-array.comp b/third_party/spirv-cross/reference/shaders-msl/comp/spec-constant-op-member-array.comp index d3c8b7dc4a..8f54f0528d 100644 --- a/third_party/spirv-cross/reference/shaders-msl/comp/spec-constant-op-member-array.comp +++ b/third_party/spirv-cross/reference/shaders-msl/comp/spec-constant-op-member-array.comp @@ -40,6 +40,7 @@ struct SSBO constant int e_tmp [[function_constant(3)]]; constant int e = is_function_constant_defined(e_tmp) ? e_tmp : 400; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); kernel void main0(device SSBO& _22 [[buffer(0)]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]]) { diff --git a/third_party/spirv-cross/reference/shaders-msl/comp/spec-constant-work-group-size.comp b/third_party/spirv-cross/reference/shaders-msl/comp/spec-constant-work-group-size.comp index bb796ab95d..de30edec15 100644 --- a/third_party/spirv-cross/reference/shaders-msl/comp/spec-constant-work-group-size.comp +++ b/third_party/spirv-cross/reference/shaders-msl/comp/spec-constant-work-group-size.comp @@ -1,8 +1,49 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + #include #include using namespace metal; +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + #ifndef SPIRV_CROSS_CONSTANT_ID_1 #define SPIRV_CROSS_CONSTANT_ID_1 2 #endif @@ -27,7 +68,7 @@ constant int _32 = (1 - a); kernel void main0(device SSBO& _17 [[buffer(0)]]) { - int spec_const_array_size[b]; + spvUnsafeArray spec_const_array_size; spec_const_array_size[a] = a; _17.v[_30] = b + spec_const_array_size[_32]; } diff --git a/third_party/spirv-cross/reference/shaders-msl/comp/storage-buffer-std140-vector-array.comp b/third_party/spirv-cross/reference/shaders-msl/comp/storage-buffer-std140-vector-array.comp index 6988febfac..b8e086b645 100644 --- a/third_party/spirv-cross/reference/shaders-msl/comp/storage-buffer-std140-vector-array.comp +++ b/third_party/spirv-cross/reference/shaders-msl/comp/storage-buffer-std140-vector-array.comp @@ -1,14 +1,55 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + #include #include using namespace metal; +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + struct Sub { - float f[2]; - float2 f2[2]; - float3 f3[2]; - float4 f4[2]; + spvUnsafeArray f; + spvUnsafeArray f2; + spvUnsafeArray f3; + spvUnsafeArray f4; }; struct Sub_1 @@ -24,6 +65,8 @@ struct SSBO Sub_1 sub[2]; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + kernel void main0(device SSBO& _27 [[buffer(0)]], uint3 gl_WorkGroupID [[threadgroup_position_in_grid]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]]) { Sub foo; diff --git a/third_party/spirv-cross/reference/shaders-msl/comp/struct-layout.comp b/third_party/spirv-cross/reference/shaders-msl/comp/struct-layout.comp index b6ee59f169..8f2ab2d60c 100644 --- a/third_party/spirv-cross/reference/shaders-msl/comp/struct-layout.comp +++ b/third_party/spirv-cross/reference/shaders-msl/comp/struct-layout.comp @@ -18,6 +18,8 @@ struct SSBO Foo in_data[1]; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + kernel void main0(device SSBO2& _23 [[buffer(0)]], const device SSBO& _30 [[buffer(1)]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]]) { uint ident = gl_GlobalInvocationID.x; diff --git a/third_party/spirv-cross/reference/shaders-msl/comp/struct-nested.comp b/third_party/spirv-cross/reference/shaders-msl/comp/struct-nested.comp index 86229e3417..e3d04bedaa 100644 --- a/third_party/spirv-cross/reference/shaders-msl/comp/struct-nested.comp +++ b/third_party/spirv-cross/reference/shaders-msl/comp/struct-nested.comp @@ -28,6 +28,8 @@ struct dstbuffer s2_1 test[1]; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + kernel void main0(device dstbuffer& _19 [[buffer(0)]]) { s2 testVal; diff --git a/third_party/spirv-cross/reference/shaders-msl/comp/struct-packing.comp b/third_party/spirv-cross/reference/shaders-msl/comp/struct-packing.comp index ad22c257ad..775bb34881 100644 --- a/third_party/spirv-cross/reference/shaders-msl/comp/struct-packing.comp +++ b/third_party/spirv-cross/reference/shaders-msl/comp/struct-packing.comp @@ -118,6 +118,8 @@ struct SSBO0 float4 array[1]; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + kernel void main0(device SSBO1& ssbo_430 [[buffer(0)]], device SSBO0& ssbo_140 [[buffer(1)]]) { Content_1 _60 = ssbo_140.content; diff --git a/third_party/spirv-cross/reference/shaders-msl/comp/torture-loop.comp b/third_party/spirv-cross/reference/shaders-msl/comp/torture-loop.comp index 1b65a3afab..e92e71d61d 100644 --- a/third_party/spirv-cross/reference/shaders-msl/comp/torture-loop.comp +++ b/third_party/spirv-cross/reference/shaders-msl/comp/torture-loop.comp @@ -14,6 +14,8 @@ struct SSBO2 float4 out_data[1]; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + kernel void main0(const device SSBO& _24 [[buffer(0)]], device SSBO2& _89 [[buffer(1)]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]]) { uint ident = gl_GlobalInvocationID.x; diff --git a/third_party/spirv-cross/reference/shaders-msl/comp/type-alias.comp b/third_party/spirv-cross/reference/shaders-msl/comp/type-alias.comp index 25a49f59f0..e3ac031668 100644 --- a/third_party/spirv-cross/reference/shaders-msl/comp/type-alias.comp +++ b/third_party/spirv-cross/reference/shaders-msl/comp/type-alias.comp @@ -40,11 +40,15 @@ struct SSBO2 float4 outputs[1]; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + +static inline __attribute__((always_inline)) float4 overload(thread const S0& s0) { return s0.a; } +static inline __attribute__((always_inline)) float4 overload(thread const S1& s1) { return s1.a; diff --git a/third_party/spirv-cross/reference/shaders-msl/comp/udiv.comp b/third_party/spirv-cross/reference/shaders-msl/comp/udiv.comp index 32874ad787..7f7315b882 100644 --- a/third_party/spirv-cross/reference/shaders-msl/comp/udiv.comp +++ b/third_party/spirv-cross/reference/shaders-msl/comp/udiv.comp @@ -13,6 +13,8 @@ struct SSBO uint inputs[1]; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + kernel void main0(device SSBO2& _10 [[buffer(0)]], device SSBO& _23 [[buffer(1)]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]]) { _10.outputs[gl_GlobalInvocationID.x] = _23.inputs[gl_GlobalInvocationID.x] / 29u; diff --git a/third_party/spirv-cross/reference/shaders-msl/comp/writable-ssbo.comp b/third_party/spirv-cross/reference/shaders-msl/comp/writable-ssbo.comp index 9dc53b6dd5..dcec81a369 100644 --- a/third_party/spirv-cross/reference/shaders-msl/comp/writable-ssbo.comp +++ b/third_party/spirv-cross/reference/shaders-msl/comp/writable-ssbo.comp @@ -13,7 +13,7 @@ struct myBlock // Implementation of the GLSL mod() function, which is slightly different than Metal fmod() template -Tx mod(Tx x, Ty y) +inline Tx mod(Tx x, Ty y) { return x - y * floor(x / y); } diff --git a/third_party/spirv-cross/reference/shaders-msl/desktop-only/comp/extended-arithmetic.desktop.comp b/third_party/spirv-cross/reference/shaders-msl/desktop-only/comp/extended-arithmetic.desktop.comp index a37fe519a5..cea12980c6 100644 --- a/third_party/spirv-cross/reference/shaders-msl/desktop-only/comp/extended-arithmetic.desktop.comp +++ b/third_party/spirv-cross/reference/shaders-msl/desktop-only/comp/extended-arithmetic.desktop.comp @@ -91,6 +91,8 @@ struct ResType_7 int4 _m1; }; +constant uint3 gl_WorkGroupSize [[maybe_unused]] = uint3(1u); + kernel void main0(device SSBOUint& u [[buffer(0)]], device SSBOInt& i [[buffer(1)]]) { ResType _25; diff --git a/third_party/spirv-cross/reference/shaders-msl/desktop-only/tesc/arrayed-output.desktop.sso.tesc b/third_party/spirv-cross/reference/shaders-msl/desktop-only/tesc/arrayed-output.desktop.sso.tesc index a5e30b6de1..01fceeb6c7 100644 --- a/third_party/spirv-cross/reference/shaders-msl/desktop-only/tesc/arrayed-output.desktop.sso.tesc +++ b/third_party/spirv-cross/reference/shaders-msl/desktop-only/tesc/arrayed-output.desktop.sso.tesc @@ -1,8 +1,49 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + #include #include using namespace metal; +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + struct main0_out { float3 vVertex; @@ -10,7 +51,7 @@ struct main0_out struct main0_patchOut { - float3 vPatch[2]; + spvUnsafeArray vPatch; }; struct main0_in @@ -28,7 +69,7 @@ kernel void main0(main0_in in [[stage_in]], uint gl_InvocationID [[thread_index_ if (gl_InvocationID >= 4) return; gl_out[gl_InvocationID].vVertex = gl_in[gl_InvocationID].vInput + gl_in[gl_InvocationID ^ 1].vInput; - threadgroup_barrier(mem_flags::mem_device); + threadgroup_barrier(mem_flags::mem_device | mem_flags::mem_threadgroup); if (gl_InvocationID == 0) { patchOut.vPatch[0] = float3(10.0); diff --git a/third_party/spirv-cross/reference/shaders-msl/desktop-only/tesc/basic.desktop.sso.tesc b/third_party/spirv-cross/reference/shaders-msl/desktop-only/tesc/basic.desktop.sso.tesc index 9acece62c6..054b4e7418 100644 --- a/third_party/spirv-cross/reference/shaders-msl/desktop-only/tesc/basic.desktop.sso.tesc +++ b/third_party/spirv-cross/reference/shaders-msl/desktop-only/tesc/basic.desktop.sso.tesc @@ -20,6 +20,7 @@ struct main0_in float4 gl_Position [[attribute(0)]]; }; +static inline __attribute__((always_inline)) void set_position(device main0_out* thread & gl_out, thread uint& gl_InvocationID, threadgroup main0_in* thread & gl_in) { gl_out[gl_InvocationID].gl_Position = gl_in[0].gl_Position + gl_in[1].gl_Position; diff --git a/third_party/spirv-cross/reference/shaders-msl/desktop-only/tesc/struct-copy.desktop.sso.tesc b/third_party/spirv-cross/reference/shaders-msl/desktop-only/tesc/struct-copy.desktop.sso.tesc index cd4d8d80e5..e7e184a980 100644 --- a/third_party/spirv-cross/reference/shaders-msl/desktop-only/tesc/struct-copy.desktop.sso.tesc +++ b/third_party/spirv-cross/reference/shaders-msl/desktop-only/tesc/struct-copy.desktop.sso.tesc @@ -28,10 +28,8 @@ kernel void main0(main0_in in [[stage_in]], uint gl_InvocationID [[thread_index_ threadgroup_barrier(mem_flags::mem_threadgroup); if (gl_InvocationID >= 4) return; - Boo vInput_24; - vInput_24.a = gl_in[gl_InvocationID].Boo_a; - vInput_24.b = gl_in[gl_InvocationID].Boo_b; - gl_out[gl_InvocationID].vVertex = vInput_24; + Boo _25 = Boo{ gl_in[gl_InvocationID].Boo_a, gl_in[gl_InvocationID].Boo_b }; + gl_out[gl_InvocationID].vVertex = _25; spvTessLevel[gl_PrimitiveID].edgeTessellationFactor[0] = half(1.0); spvTessLevel[gl_PrimitiveID].edgeTessellationFactor[1] = half(2.0); spvTessLevel[gl_PrimitiveID].edgeTessellationFactor[2] = half(3.0); diff --git a/third_party/spirv-cross/reference/shaders-msl/desktop-only/vert/clip-cull-distance.desktop.vert b/third_party/spirv-cross/reference/shaders-msl/desktop-only/vert/clip-cull-distance.desktop.vert index a414c98542..2d98929051 100644 --- a/third_party/spirv-cross/reference/shaders-msl/desktop-only/vert/clip-cull-distance.desktop.vert +++ b/third_party/spirv-cross/reference/shaders-msl/desktop-only/vert/clip-cull-distance.desktop.vert @@ -7,6 +7,8 @@ struct main0_out { float4 gl_Position [[position]]; float gl_ClipDistance [[clip_distance]] [2]; + float gl_ClipDistance_0 [[user(clip0)]]; + float gl_ClipDistance_1 [[user(clip1)]]; }; vertex main0_out main0() @@ -15,6 +17,8 @@ vertex main0_out main0() out.gl_Position = float4(10.0); out.gl_ClipDistance[0] = 1.0; out.gl_ClipDistance[1] = 4.0; + out.gl_ClipDistance_0 = out.gl_ClipDistance[0]; + out.gl_ClipDistance_1 = out.gl_ClipDistance[1]; return out; } diff --git a/third_party/spirv-cross/reference/shaders-msl/desktop-only/vert/shader-draw-parameters.desktop.vert b/third_party/spirv-cross/reference/shaders-msl/desktop-only/vert/shader-draw-parameters.desktop.vert index 1d203ba98b..a32c1948f8 100644 --- a/third_party/spirv-cross/reference/shaders-msl/desktop-only/vert/shader-draw-parameters.desktop.vert +++ b/third_party/spirv-cross/reference/shaders-msl/desktop-only/vert/shader-draw-parameters.desktop.vert @@ -11,7 +11,7 @@ struct main0_out vertex main0_out main0(uint gl_BaseVertex [[base_vertex]], uint gl_BaseInstance [[base_instance]]) { main0_out out = {}; - out.gl_Position = float4(float(gl_BaseVertex), float(gl_BaseInstance), 0.0, 1.0); + out.gl_Position = float4(float(int(gl_BaseVertex)), float(int(gl_BaseInstance)), 0.0, 1.0); return out; } diff --git a/third_party/spirv-cross/reference/shaders-msl/frag/argument-buffers.msl2.argument.frag b/third_party/spirv-cross/reference/shaders-msl/frag/argument-buffers.msl2.argument.frag index 1cf9727710..b7005ff981 100644 --- a/third_party/spirv-cross/reference/shaders-msl/frag/argument-buffers.msl2.argument.frag +++ b/third_party/spirv-cross/reference/shaders-msl/frag/argument-buffers.msl2.argument.frag @@ -62,6 +62,7 @@ struct main0_in float2 vUV [[user(locn0)]]; }; +static inline __attribute__((always_inline)) float4 sample_in_function2(thread texture2d uTexture, thread const sampler uTextureSmplr, thread float2& vUV, thread const array, 4> uTexture2, thread const array uSampler, thread const array, 2> uTextures, thread const array uTexturesSmplr, device SSBO& v_60, const device SSBOs* constant (&ssbos)[2], constant Push& registers) { float4 ret = uTexture.sample(uTextureSmplr, vUV); @@ -73,6 +74,7 @@ float4 sample_in_function2(thread texture2d uTexture, thread const sample return ret; } +static inline __attribute__((always_inline)) float4 sample_in_function(thread texture2d uTexture, thread const sampler uTextureSmplr, thread float2& vUV, thread const array, 4> uTexture2, thread const array uSampler, thread const array, 2> uTextures, thread const array uTexturesSmplr, device SSBO& v_60, const device SSBOs* constant (&ssbos)[2], constant Push& registers, constant UBO& v_90, constant UBOs* constant (&ubos)[4]) { float4 ret = sample_in_function2(uTexture, uTextureSmplr, vUV, uTexture2, uSampler, uTextures, uTexturesSmplr, v_60, ssbos, registers); diff --git a/third_party/spirv-cross/reference/shaders-msl/frag/array-lut-no-loop-variable.frag b/third_party/spirv-cross/reference/shaders-msl/frag/array-lut-no-loop-variable.frag index 87158849b6..cdedd73a74 100644 --- a/third_party/spirv-cross/reference/shaders-msl/frag/array-lut-no-loop-variable.frag +++ b/third_party/spirv-cross/reference/shaders-msl/frag/array-lut-no-loop-variable.frag @@ -1,9 +1,50 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + #include #include using namespace metal; -constant float _17[5] = { 1.0, 2.0, 3.0, 4.0, 5.0 }; +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +constant spvUnsafeArray _17 = spvUnsafeArray({ 1.0, 2.0, 3.0, 4.0, 5.0 }); struct main0_out { diff --git a/third_party/spirv-cross/reference/shaders-msl/frag/array-of-array-lut.frag b/third_party/spirv-cross/reference/shaders-msl/frag/array-of-array-lut.frag new file mode 100644 index 0000000000..ba553824e7 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-msl/frag/array-of-array-lut.frag @@ -0,0 +1,68 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + +#include +#include + +using namespace metal; + +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +constant spvUnsafeArray _17 = spvUnsafeArray({ 1.0, 2.0, 3.0 }); +constant spvUnsafeArray _21 = spvUnsafeArray({ 4.0, 5.0, 6.0 }); +constant spvUnsafeArray, 2> _22 = spvUnsafeArray, 2>({ spvUnsafeArray({ 1.0, 2.0, 3.0 }), spvUnsafeArray({ 4.0, 5.0, 6.0 }) }); + +struct main0_out +{ + float vOutput [[color(0)]]; +}; + +struct main0_in +{ + int vIndex1 [[user(locn0)]]; + int vIndex2 [[user(locn1)]]; +}; + +fragment main0_out main0(main0_in in [[stage_in]]) +{ + main0_out out = {}; + out.vOutput = _22[in.vIndex1][in.vIndex2]; + return out; +} + diff --git a/third_party/spirv-cross/reference/shaders-msl/frag/array-of-texture-swizzle.msl2.argument.discrete.swizzle.frag b/third_party/spirv-cross/reference/shaders-msl/frag/array-of-texture-swizzle.msl2.argument.discrete.swizzle.frag index 702409ee7b..833ddec011 100644 --- a/third_party/spirv-cross/reference/shaders-msl/frag/array-of-texture-swizzle.msl2.argument.discrete.swizzle.frag +++ b/third_party/spirv-cross/reference/shaders-msl/frag/array-of-texture-swizzle.msl2.argument.discrete.swizzle.frag @@ -22,17 +22,6 @@ struct main0_in float2 vUV [[user(locn0)]]; }; -enum class spvSwizzle : uint -{ - none = 0, - zero, - one, - red, - green, - blue, - alpha -}; - template struct spvRemoveReference { typedef T type; }; template struct spvRemoveReference { typedef T type; }; template struct spvRemoveReference { typedef T type; }; @@ -45,6 +34,17 @@ template inline constexpr thread T&& spvForward(thread typename spvR return static_cast(x); } +enum class spvSwizzle : uint +{ + none = 0, + zero, + one, + red, + green, + blue, + alpha +}; + template inline T spvGetSwizzle(vec x, T c, spvSwizzle s) { @@ -82,76 +82,19 @@ inline T spvTextureSwizzle(T x, uint s) return spvTextureSwizzle(vec(x, 0, 0, 1), s).x; } -// Wrapper function that swizzles texture gathers. -template -inline vec spvGatherSwizzle(sampler s, const thread Tex& t, Ts... params, component c, uint sw) METAL_CONST_ARG(c) -{ - if (sw) - { - switch (spvSwizzle((sw >> (uint(c) * 8)) & 0xFF)) - { - case spvSwizzle::none: - break; - case spvSwizzle::zero: - return vec(0, 0, 0, 0); - case spvSwizzle::one: - return vec(1, 1, 1, 1); - case spvSwizzle::red: - return t.gather(s, spvForward(params)..., component::x); - case spvSwizzle::green: - return t.gather(s, spvForward(params)..., component::y); - case spvSwizzle::blue: - return t.gather(s, spvForward(params)..., component::z); - case spvSwizzle::alpha: - return t.gather(s, spvForward(params)..., component::w); - } - } - switch (c) - { - case component::x: - return t.gather(s, spvForward(params)..., component::x); - case component::y: - return t.gather(s, spvForward(params)..., component::y); - case component::z: - return t.gather(s, spvForward(params)..., component::z); - case component::w: - return t.gather(s, spvForward(params)..., component::w); - } -} - -// Wrapper function that swizzles depth texture gathers. -template -inline vec spvGatherCompareSwizzle(sampler s, const thread Tex& t, Ts... params, uint sw) -{ - if (sw) - { - switch (spvSwizzle(sw & 0xFF)) - { - case spvSwizzle::none: - case spvSwizzle::red: - break; - case spvSwizzle::zero: - case spvSwizzle::green: - case spvSwizzle::blue: - case spvSwizzle::alpha: - return vec(0, 0, 0, 0); - case spvSwizzle::one: - return vec(1, 1, 1, 1); - } - } - return t.gather_compare(s, spvForward(params)...); -} - +static inline __attribute__((always_inline)) float4 sample_in_func_1(thread const array, 4> uSampler0, thread const array uSampler0Smplr, constant uint* uSampler0Swzl, thread float2& vUV) { return spvTextureSwizzle(uSampler0[2].sample(uSampler0Smplr[2], vUV), uSampler0Swzl[2]); } +static inline __attribute__((always_inline)) float4 sample_in_func_2(thread float2& vUV, thread texture2d uSampler1, thread const sampler uSampler1Smplr, constant uint& uSampler1Swzl) { return spvTextureSwizzle(uSampler1.sample(uSampler1Smplr, vUV), uSampler1Swzl); } +static inline __attribute__((always_inline)) float4 sample_single_in_func(thread const texture2d s, thread const sampler sSmplr, constant uint& sSwzl, thread float2& vUV) { return spvTextureSwizzle(s.sample(sSmplr, vUV), sSwzl); diff --git a/third_party/spirv-cross/reference/shaders-msl/frag/array-of-texture-swizzle.msl2.swizzle.frag b/third_party/spirv-cross/reference/shaders-msl/frag/array-of-texture-swizzle.msl2.swizzle.frag index ebaa28a57e..64b361ec97 100644 --- a/third_party/spirv-cross/reference/shaders-msl/frag/array-of-texture-swizzle.msl2.swizzle.frag +++ b/third_party/spirv-cross/reference/shaders-msl/frag/array-of-texture-swizzle.msl2.swizzle.frag @@ -15,17 +15,6 @@ struct main0_in float2 vUV [[user(locn0)]]; }; -enum class spvSwizzle : uint -{ - none = 0, - zero, - one, - red, - green, - blue, - alpha -}; - template struct spvRemoveReference { typedef T type; }; template struct spvRemoveReference { typedef T type; }; template struct spvRemoveReference { typedef T type; }; @@ -38,6 +27,17 @@ template inline constexpr thread T&& spvForward(thread typename spvR return static_cast(x); } +enum class spvSwizzle : uint +{ + none = 0, + zero, + one, + red, + green, + blue, + alpha +}; + template inline T spvGetSwizzle(vec x, T c, spvSwizzle s) { @@ -75,71 +75,13 @@ inline T spvTextureSwizzle(T x, uint s) return spvTextureSwizzle(vec(x, 0, 0, 1), s).x; } -// Wrapper function that swizzles texture gathers. -template -inline vec spvGatherSwizzle(sampler s, const thread Tex& t, Ts... params, component c, uint sw) METAL_CONST_ARG(c) -{ - if (sw) - { - switch (spvSwizzle((sw >> (uint(c) * 8)) & 0xFF)) - { - case spvSwizzle::none: - break; - case spvSwizzle::zero: - return vec(0, 0, 0, 0); - case spvSwizzle::one: - return vec(1, 1, 1, 1); - case spvSwizzle::red: - return t.gather(s, spvForward(params)..., component::x); - case spvSwizzle::green: - return t.gather(s, spvForward(params)..., component::y); - case spvSwizzle::blue: - return t.gather(s, spvForward(params)..., component::z); - case spvSwizzle::alpha: - return t.gather(s, spvForward(params)..., component::w); - } - } - switch (c) - { - case component::x: - return t.gather(s, spvForward(params)..., component::x); - case component::y: - return t.gather(s, spvForward(params)..., component::y); - case component::z: - return t.gather(s, spvForward(params)..., component::z); - case component::w: - return t.gather(s, spvForward(params)..., component::w); - } -} - -// Wrapper function that swizzles depth texture gathers. -template -inline vec spvGatherCompareSwizzle(sampler s, const thread Tex& t, Ts... params, uint sw) -{ - if (sw) - { - switch (spvSwizzle(sw & 0xFF)) - { - case spvSwizzle::none: - case spvSwizzle::red: - break; - case spvSwizzle::zero: - case spvSwizzle::green: - case spvSwizzle::blue: - case spvSwizzle::alpha: - return vec(0, 0, 0, 0); - case spvSwizzle::one: - return vec(1, 1, 1, 1); - } - } - return t.gather_compare(s, spvForward(params)...); -} - +static inline __attribute__((always_inline)) float4 sample_in_func(thread const array, 4> uSampler, thread const array uSamplerSmplr, constant uint* uSamplerSwzl, thread float2& vUV) { return spvTextureSwizzle(uSampler[2].sample(uSamplerSmplr[2], vUV), uSamplerSwzl[2]); } +static inline __attribute__((always_inline)) float4 sample_single_in_func(thread const texture2d s, thread const sampler sSmplr, constant uint& sSwzl, thread float2& vUV) { return spvTextureSwizzle(s.sample(sSmplr, vUV), sSwzl); diff --git a/third_party/spirv-cross/reference/shaders-msl/frag/buffer-read-write.frag b/third_party/spirv-cross/reference/shaders-msl/frag/buffer-read-write.frag index 2b2ac7f060..166d4311ba 100644 --- a/third_party/spirv-cross/reference/shaders-msl/frag/buffer-read-write.frag +++ b/third_party/spirv-cross/reference/shaders-msl/frag/buffer-read-write.frag @@ -11,6 +11,7 @@ struct main0_out }; // Returns 2D texture coords corresponding to 1D texel buffer coords +static inline __attribute__((always_inline)) uint2 spvTexelBufferCoord(uint tc) { return uint2(tc % 4096, tc / 4096); diff --git a/third_party/spirv-cross/reference/shaders-msl/frag/clip-distance-varying.frag b/third_party/spirv-cross/reference/shaders-msl/frag/clip-distance-varying.frag new file mode 100644 index 0000000000..9a72d5ba39 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-msl/frag/clip-distance-varying.frag @@ -0,0 +1,67 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + +#include +#include + +using namespace metal; + +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +struct main0_out +{ + float4 FragColor [[color(0)]]; +}; + +struct main0_in +{ + float gl_ClipDistance_0 [[user(clip0)]]; + float gl_ClipDistance_1 [[user(clip1)]]; +}; + +fragment main0_out main0(main0_in in [[stage_in]]) +{ + main0_out out = {}; + spvUnsafeArray gl_ClipDistance = {}; + gl_ClipDistance[0] = in.gl_ClipDistance_0; + gl_ClipDistance[1] = in.gl_ClipDistance_1; + out.FragColor = float4((1.0 - gl_ClipDistance[0]) - gl_ClipDistance[1]); + return out; +} + diff --git a/third_party/spirv-cross/reference/shaders-msl/frag/constant-array.frag b/third_party/spirv-cross/reference/shaders-msl/frag/constant-array.frag index c4e87d9872..990860762c 100644 --- a/third_party/spirv-cross/reference/shaders-msl/frag/constant-array.frag +++ b/third_party/spirv-cross/reference/shaders-msl/frag/constant-array.frag @@ -1,21 +1,60 @@ #pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" #include #include using namespace metal; +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + struct Foobar { float a; float b; }; -constant float4 _37[3] = { float4(1.0), float4(2.0), float4(3.0) }; -constant float4 _49[2] = { float4(1.0), float4(2.0) }; -constant float4 _54[2] = { float4(8.0), float4(10.0) }; -constant float4 _55[2][2] = { { float4(1.0), float4(2.0) }, { float4(8.0), float4(10.0) } }; -constant Foobar _75[2] = { Foobar{ 10.0, 40.0 }, Foobar{ 90.0, 70.0 } }; +constant spvUnsafeArray _37 = spvUnsafeArray({ float4(1.0), float4(2.0), float4(3.0) }); +constant spvUnsafeArray _49 = spvUnsafeArray({ float4(1.0), float4(2.0) }); +constant spvUnsafeArray _54 = spvUnsafeArray({ float4(8.0), float4(10.0) }); +constant spvUnsafeArray, 2> _55 = spvUnsafeArray, 2>({ spvUnsafeArray({ float4(1.0), float4(2.0) }), spvUnsafeArray({ float4(8.0), float4(10.0) }) }); +constant spvUnsafeArray _75 = spvUnsafeArray({ Foobar{ 10.0, 40.0 }, Foobar{ 90.0, 70.0 } }); struct main0_out { @@ -27,6 +66,7 @@ struct main0_in int index [[user(locn0)]]; }; +static inline __attribute__((always_inline)) float4 resolve(thread const Foobar& f) { return float4(f.a + f.b); diff --git a/third_party/spirv-cross/reference/shaders-msl/frag/constant-composites.frag b/third_party/spirv-cross/reference/shaders-msl/frag/constant-composites.frag index 504beaa067..e0fa980fb8 100644 --- a/third_party/spirv-cross/reference/shaders-msl/frag/constant-composites.frag +++ b/third_party/spirv-cross/reference/shaders-msl/frag/constant-composites.frag @@ -1,18 +1,56 @@ #pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" #include #include using namespace metal; +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + struct Foo { float a; float b; }; -constant float _16[4] = { 1.0, 4.0, 3.0, 2.0 }; -constant Foo _28[2] = { Foo{ 10.0, 20.0 }, Foo{ 30.0, 40.0 } }; +constant spvUnsafeArray _16 = spvUnsafeArray({ 1.0, 4.0, 3.0, 2.0 }); struct main0_out { @@ -24,21 +62,10 @@ struct main0_in int line [[user(locn0)]]; }; -// Implementation of an array copy function to cover GLSL's ability to copy an array via assignment. -template -void spvArrayCopyFromStack1(thread T (&dst)[N], thread const T (&src)[N]) -{ - for (uint i = 0; i < N; dst[i] = src[i], i++); -} - -template -void spvArrayCopyFromConstant1(thread T (&dst)[N], constant T (&src)[N]) -{ - for (uint i = 0; i < N; dst[i] = src[i], i++); -} - fragment main0_out main0(main0_in in [[stage_in]]) { + spvUnsafeArray _28 = spvUnsafeArray({ Foo{ 10.0, 20.0 }, Foo{ 30.0, 40.0 } }); + main0_out out = {}; out.FragColor = float4(_16[in.line]); out.FragColor += float4(_28[in.line].a * _28[1 - in.line].a); diff --git a/third_party/spirv-cross/reference/shaders-msl/frag/flush_params.frag b/third_party/spirv-cross/reference/shaders-msl/frag/flush_params.frag index e2f2a48cb2..905a179bc6 100644 --- a/third_party/spirv-cross/reference/shaders-msl/frag/flush_params.frag +++ b/third_party/spirv-cross/reference/shaders-msl/frag/flush_params.frag @@ -15,11 +15,13 @@ struct main0_out float4 FragColor [[color(0)]]; }; +static inline __attribute__((always_inline)) void foo2(thread Structy& f) { f.c = float4(10.0); } +static inline __attribute__((always_inline)) Structy foo() { Structy param; diff --git a/third_party/spirv-cross/reference/shaders-msl/frag/fragment-component-padding.pad-fragment.frag b/third_party/spirv-cross/reference/shaders-msl/frag/fragment-component-padding.pad-fragment.frag index 2d339c4735..9a8e14dd56 100644 --- a/third_party/spirv-cross/reference/shaders-msl/frag/fragment-component-padding.pad-fragment.frag +++ b/third_party/spirv-cross/reference/shaders-msl/frag/fragment-component-padding.pad-fragment.frag @@ -1,10 +1,49 @@ #pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" #include #include using namespace metal; +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + struct main0_out { float4 FragColors_0 [[color(0)]]; @@ -18,7 +57,8 @@ struct main0_in float3 vColor [[user(locn0)]]; }; -void set_globals(thread float (&FragColors)[2], thread float3& vColor, thread float2& FragColor2, thread float3& FragColor3) +static inline __attribute__((always_inline)) +void set_globals(thread spvUnsafeArray (&FragColors), thread float3& vColor, thread float2& FragColor2, thread float3& FragColor3) { FragColors[0] = vColor.x; FragColors[1] = vColor.y; @@ -29,14 +69,14 @@ void set_globals(thread float (&FragColors)[2], thread float3& vColor, thread fl fragment main0_out main0(main0_in in [[stage_in]]) { main0_out out = {}; - float FragColors[2] = {}; + spvUnsafeArray FragColors = {}; float2 FragColor2 = {}; float3 FragColor3 = {}; set_globals(FragColors, in.vColor, FragColor2, FragColor3); out.FragColors_0 = float4(FragColors[0]); out.FragColors_1 = float4(FragColors[1]); - out.FragColor2 = FragColor2.xyyy; - out.FragColor3 = FragColor3.xyzz; + out.FragColor2.xy = FragColor2; + out.FragColor3.xyz = FragColor3; return out; } diff --git a/third_party/spirv-cross/reference/shaders-msl/frag/helper-invocation.msl21.frag b/third_party/spirv-cross/reference/shaders-msl/frag/helper-invocation.msl21.frag index 8d32f4860d..97d69e19dc 100644 --- a/third_party/spirv-cross/reference/shaders-msl/frag/helper-invocation.msl21.frag +++ b/third_party/spirv-cross/reference/shaders-msl/frag/helper-invocation.msl21.frag @@ -15,6 +15,7 @@ struct main0_in float2 vUV [[user(locn0)]]; }; +static inline __attribute__((always_inline)) float4 foo(thread bool& gl_HelperInvocation, thread texture2d uSampler, thread const sampler uSamplerSmplr, thread float2& vUV) { float4 color; diff --git a/third_party/spirv-cross/reference/shaders-msl/frag/huge-argument-buffer.device-argument-buffer.argument.msl2.frag b/third_party/spirv-cross/reference/shaders-msl/frag/huge-argument-buffer.device-argument-buffer.argument.msl2.frag new file mode 100644 index 0000000000..0e35c2485a --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-msl/frag/huge-argument-buffer.device-argument-buffer.argument.msl2.frag @@ -0,0 +1,58 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" + +#include +#include + +using namespace metal; + +struct UBO +{ + float4 v; +}; + +struct spvDescriptorSetBuffer0 +{ + array, 10000> uSamplers [[id(0)]]; + array uSamplersSmplr [[id(10000)]]; +}; + +struct spvDescriptorSetBuffer1 +{ + constant UBO* vs [[id(0)]][10000]; +}; + +struct spvDescriptorSetBuffer2 +{ + texture2d uSampler [[id(0)]]; + sampler uSamplerSmplr [[id(1)]]; +}; + +struct main0_out +{ + float4 FragColor [[color(0)]]; +}; + +struct main0_in +{ + float2 vUV [[user(locn0)]]; +}; + +static inline __attribute__((always_inline)) +float4 samp_array(thread const array, 10000> uSamplers, thread const array uSamplersSmplr, thread float2& vUV, constant UBO* const device (&vs)[10000]) +{ + return uSamplers[9999].sample(uSamplersSmplr[9999], vUV) + vs[5000]->v; +} + +static inline __attribute__((always_inline)) +float4 samp_single(thread float2& vUV, thread texture2d uSampler, thread const sampler uSamplerSmplr) +{ + return uSampler.sample(uSamplerSmplr, vUV); +} + +fragment main0_out main0(main0_in in [[stage_in]], const device spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]], const device spvDescriptorSetBuffer1& spvDescriptorSet1 [[buffer(1)]], constant spvDescriptorSetBuffer2& spvDescriptorSet2 [[buffer(2)]]) +{ + main0_out out = {}; + out.FragColor = samp_array(spvDescriptorSet0.uSamplers, spvDescriptorSet0.uSamplersSmplr, in.vUV, spvDescriptorSet1.vs) + samp_single(in.vUV, spvDescriptorSet2.uSampler, spvDescriptorSet2.uSamplerSmplr); + return out; +} + diff --git a/third_party/spirv-cross/reference/shaders-msl/frag/image-query-lod.msl22.frag b/third_party/spirv-cross/reference/shaders-msl/frag/image-query-lod.msl22.frag index 4ec61c24d7..6e7991f28a 100644 --- a/third_party/spirv-cross/reference/shaders-msl/frag/image-query-lod.msl22.frag +++ b/third_party/spirv-cross/reference/shaders-msl/frag/image-query-lod.msl22.frag @@ -15,6 +15,7 @@ struct main0_in float3 vUV [[user(locn0)]]; }; +static inline __attribute__((always_inline)) void from_function(thread float2& FragColor, thread texture2d uSampler2D, thread const sampler uSampler2DSmplr, thread float3& vUV, thread texture3d uSampler3D, thread const sampler uSampler3DSmplr, thread texturecube uSamplerCube, thread const sampler uSamplerCubeSmplr, thread texture2d uTexture2D, thread sampler uSampler, thread texture3d uTexture3D, thread texturecube uTextureCube) { float2 _22; diff --git a/third_party/spirv-cross/reference/shaders-msl/frag/input-attachment-ms.frag b/third_party/spirv-cross/reference/shaders-msl/frag/input-attachment-ms.frag index d38712e91c..6f5c2b94c8 100644 --- a/third_party/spirv-cross/reference/shaders-msl/frag/input-attachment-ms.frag +++ b/third_party/spirv-cross/reference/shaders-msl/frag/input-attachment-ms.frag @@ -10,6 +10,7 @@ struct main0_out float4 FragColor [[color(0)]]; }; +static inline __attribute__((always_inline)) float4 load_subpasses(thread const texture2d_ms uInput, thread uint& gl_SampleID, thread float4& gl_FragCoord) { return uInput.read(uint2(gl_FragCoord.xy), gl_SampleID); diff --git a/third_party/spirv-cross/reference/shaders-msl/frag/input-attachment.frag b/third_party/spirv-cross/reference/shaders-msl/frag/input-attachment.frag index 3cc929182b..d43b0adc4e 100644 --- a/third_party/spirv-cross/reference/shaders-msl/frag/input-attachment.frag +++ b/third_party/spirv-cross/reference/shaders-msl/frag/input-attachment.frag @@ -10,6 +10,7 @@ struct main0_out float4 FragColor [[color(0)]]; }; +static inline __attribute__((always_inline)) float4 load_subpasses(thread const texture2d uInput, thread float4& gl_FragCoord) { return uInput.read(uint2(gl_FragCoord.xy), 0); diff --git a/third_party/spirv-cross/reference/shaders-msl/frag/lut-promotion.frag b/third_party/spirv-cross/reference/shaders-msl/frag/lut-promotion.frag index f7e51edb84..b1e0e7311d 100644 --- a/third_party/spirv-cross/reference/shaders-msl/frag/lut-promotion.frag +++ b/third_party/spirv-cross/reference/shaders-msl/frag/lut-promotion.frag @@ -1,13 +1,52 @@ #pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" #include #include using namespace metal; -constant float _16[16] = { 1.0, 2.0, 3.0, 4.0, 1.0, 2.0, 3.0, 4.0, 1.0, 2.0, 3.0, 4.0, 1.0, 2.0, 3.0, 4.0 }; -constant float4 _60[4] = { float4(0.0), float4(1.0), float4(8.0), float4(5.0) }; -constant float4 _104[4] = { float4(20.0), float4(30.0), float4(50.0), float4(60.0) }; +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +constant spvUnsafeArray _16 = spvUnsafeArray({ 1.0, 2.0, 3.0, 4.0, 1.0, 2.0, 3.0, 4.0, 1.0, 2.0, 3.0, 4.0, 1.0, 2.0, 3.0, 4.0 }); +constant spvUnsafeArray _60 = spvUnsafeArray({ float4(0.0), float4(1.0), float4(8.0), float4(5.0) }); +constant spvUnsafeArray _104 = spvUnsafeArray({ float4(20.0), float4(30.0), float4(50.0), float4(60.0) }); struct main0_out { @@ -19,19 +58,6 @@ struct main0_in int index [[user(locn0)]]; }; -// Implementation of an array copy function to cover GLSL's ability to copy an array via assignment. -template -void spvArrayCopyFromStack1(thread T (&dst)[N], thread const T (&src)[N]) -{ - for (uint i = 0; i < N; dst[i] = src[i], i++); -} - -template -void spvArrayCopyFromConstant1(thread T (&dst)[N], constant T (&src)[N]) -{ - for (uint i = 0; i < N; dst[i] = src[i], i++); -} - fragment main0_out main0(main0_in in [[stage_in]]) { main0_out out = {}; @@ -52,14 +78,14 @@ fragment main0_out main0(main0_in in [[stage_in]]) { out.FragColor += _60[in.index & 1].x; } - float4 foobar[4] = { float4(0.0), float4(1.0), float4(8.0), float4(5.0) }; + spvUnsafeArray foobar = spvUnsafeArray({ float4(0.0), float4(1.0), float4(8.0), float4(5.0) }); if (in.index > 30) { foobar[1].z = 20.0; } out.FragColor += foobar[in.index & 3].z; - float4 baz[4] = { float4(0.0), float4(1.0), float4(8.0), float4(5.0) }; - spvArrayCopyFromConstant1(baz, _104); + spvUnsafeArray baz = spvUnsafeArray({ float4(0.0), float4(1.0), float4(8.0), float4(5.0) }); + baz = _104; out.FragColor += baz[in.index & 3].z; return out; } diff --git a/third_party/spirv-cross/reference/shaders-msl/frag/mrt-array.frag b/third_party/spirv-cross/reference/shaders-msl/frag/mrt-array.frag index daf7edb4cc..2746ad6396 100644 --- a/third_party/spirv-cross/reference/shaders-msl/frag/mrt-array.frag +++ b/third_party/spirv-cross/reference/shaders-msl/frag/mrt-array.frag @@ -1,10 +1,49 @@ #pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" #include #include using namespace metal; +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + struct main0_out { float4 FragColor_0 [[color(0)]]; @@ -21,17 +60,19 @@ struct main0_in // Implementation of the GLSL mod() function, which is slightly different than Metal fmod() template -Tx mod(Tx x, Ty y) +inline Tx mod(Tx x, Ty y) { return x - y * floor(x / y); } -void write_deeper_in_function(thread float4 (&FragColor)[4], thread float4& vA, thread float4& vB) +static inline __attribute__((always_inline)) +void write_deeper_in_function(thread spvUnsafeArray (&FragColor), thread float4& vA, thread float4& vB) { FragColor[3] = vA * vB; } -void write_in_function(thread float4 (&FragColor)[4], thread float4& vA, thread float4& vB) +static inline __attribute__((always_inline)) +void write_in_function(thread spvUnsafeArray (&FragColor), thread float4& vA, thread float4& vB) { FragColor[2] = vA - vB; write_deeper_in_function(FragColor, vA, vB); @@ -40,7 +81,7 @@ void write_in_function(thread float4 (&FragColor)[4], thread float4& vA, thread fragment main0_out main0(main0_in in [[stage_in]]) { main0_out out = {}; - float4 FragColor[4] = {}; + spvUnsafeArray FragColor = {}; FragColor[0] = mod(in.vA, in.vB); FragColor[1] = in.vA + in.vB; write_in_function(FragColor, in.vA, in.vB); diff --git a/third_party/spirv-cross/reference/shaders-msl/frag/packing-test-3.frag b/third_party/spirv-cross/reference/shaders-msl/frag/packing-test-3.frag index d8310d6ac7..cfb0ceae2e 100644 --- a/third_party/spirv-cross/reference/shaders-msl/frag/packing-test-3.frag +++ b/third_party/spirv-cross/reference/shaders-msl/frag/packing-test-3.frag @@ -32,6 +32,7 @@ struct main0_out float4 _entryPointOutput [[color(0)]]; }; +static inline __attribute__((always_inline)) float4 _main(thread const VertexOutput& IN, constant CB0& v_26) { TestStruct st; diff --git a/third_party/spirv-cross/reference/shaders-msl/frag/pixel-interlock-ordered.msl2.argument.frag b/third_party/spirv-cross/reference/shaders-msl/frag/pixel-interlock-ordered.msl2.argument.frag new file mode 100644 index 0000000000..f77b8ed99e --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-msl/frag/pixel-interlock-ordered.msl2.argument.frag @@ -0,0 +1,43 @@ +#pragma clang diagnostic ignored "-Wunused-variable" + +#include +#include +#include + +using namespace metal; + +struct Buffer3 +{ + int baz; +}; + +struct Buffer +{ + int foo; + uint bar; +}; + +struct Buffer2 +{ + uint quux; +}; + +struct spvDescriptorSetBuffer0 +{ + device Buffer3* m_9 [[id(0)]]; + texture2d img4 [[id(1)]]; + texture2d img [[id(2), raster_order_group(0)]]; + texture2d img3 [[id(3), raster_order_group(0)]]; + volatile device Buffer* m_34 [[id(4), raster_order_group(0)]]; + device Buffer2* m_44 [[id(5), raster_order_group(0)]]; +}; + +fragment void main0(constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]]) +{ + (*spvDescriptorSet0.m_9).baz = 0; + spvDescriptorSet0.img4.write(float4(1.0, 0.0, 0.0, 1.0), uint2(int2(1))); + spvDescriptorSet0.img.write(spvDescriptorSet0.img3.read(uint2(int2(0))), uint2(int2(0))); + (*spvDescriptorSet0.m_34).foo += 42; + uint _49 = atomic_fetch_and_explicit((volatile device atomic_uint*)&(*spvDescriptorSet0.m_34).bar, (*spvDescriptorSet0.m_44).quux, memory_order_relaxed); +} + diff --git a/third_party/spirv-cross/reference/shaders-msl/frag/pixel-interlock-ordered.msl2.frag b/third_party/spirv-cross/reference/shaders-msl/frag/pixel-interlock-ordered.msl2.frag new file mode 100644 index 0000000000..803416c669 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-msl/frag/pixel-interlock-ordered.msl2.frag @@ -0,0 +1,33 @@ +#pragma clang diagnostic ignored "-Wunused-variable" + +#include +#include +#include + +using namespace metal; + +struct Buffer3 +{ + int baz; +}; + +struct Buffer +{ + int foo; + uint bar; +}; + +struct Buffer2 +{ + uint quux; +}; + +fragment void main0(device Buffer3& _9 [[buffer(0)]], volatile device Buffer& _34 [[buffer(1), raster_order_group(0)]], device Buffer2& _44 [[buffer(2), raster_order_group(0)]], texture2d img4 [[texture(0)]], texture2d img [[texture(1), raster_order_group(0)]], texture2d img3 [[texture(2), raster_order_group(0)]]) +{ + _9.baz = 0; + img4.write(float4(1.0, 0.0, 0.0, 1.0), uint2(int2(1))); + img.write(img3.read(uint2(int2(0))), uint2(int2(0))); + _34.foo += 42; + uint _49 = atomic_fetch_and_explicit((volatile device atomic_uint*)&_34.bar, _44.quux, memory_order_relaxed); +} + diff --git a/third_party/spirv-cross/reference/shaders-msl/frag/private-variable-prototype-declaration.frag b/third_party/spirv-cross/reference/shaders-msl/frag/private-variable-prototype-declaration.frag index d014623bce..7c11a937a2 100644 --- a/third_party/spirv-cross/reference/shaders-msl/frag/private-variable-prototype-declaration.frag +++ b/third_party/spirv-cross/reference/shaders-msl/frag/private-variable-prototype-declaration.frag @@ -15,11 +15,13 @@ struct main0_out float3 FragColor [[color(0)]]; }; +static inline __attribute__((always_inline)) void someFunction(thread AStruct& s) { s.foobar = float4(1.0); } +static inline __attribute__((always_inline)) void otherFunction(thread float3& global_variable) { global_variable = float3(1.0); diff --git a/third_party/spirv-cross/reference/shaders-msl/frag/readonly-ssbo.frag b/third_party/spirv-cross/reference/shaders-msl/frag/readonly-ssbo.frag index 771c225d6e..7d73da79b2 100644 --- a/third_party/spirv-cross/reference/shaders-msl/frag/readonly-ssbo.frag +++ b/third_party/spirv-cross/reference/shaders-msl/frag/readonly-ssbo.frag @@ -15,6 +15,7 @@ struct main0_out float4 FragColor [[color(0)]]; }; +static inline __attribute__((always_inline)) float4 read_from_function(const device SSBO& v_13) { return v_13.v; diff --git a/third_party/spirv-cross/reference/shaders-msl/frag/sample-depth-propagate-state-from-resource.frag b/third_party/spirv-cross/reference/shaders-msl/frag/sample-depth-propagate-state-from-resource.frag new file mode 100644 index 0000000000..a093d3f489 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-msl/frag/sample-depth-propagate-state-from-resource.frag @@ -0,0 +1,43 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" + +#include +#include + +using namespace metal; + +struct main0_out +{ + float FragColor [[color(0)]]; +}; + +struct main0_in +{ + float3 vUV [[user(locn0)]]; +}; + +static inline __attribute__((always_inline)) +float sample_normal2(thread const depth2d tex, thread sampler uSampler, thread float3& vUV) +{ + return float4(tex.sample(uSampler, vUV.xy)).x; +} + +static inline __attribute__((always_inline)) +float sample_normal(thread const depth2d tex, thread sampler uSampler, thread float3& vUV) +{ + return sample_normal2(tex, uSampler, vUV); +} + +static inline __attribute__((always_inline)) +float sample_comp(thread const depth2d tex, thread float3& vUV, thread sampler uSamplerShadow) +{ + return tex.sample_compare(uSamplerShadow, vUV.xy, vUV.z); +} + +fragment main0_out main0(main0_in in [[stage_in]], depth2d uTexture [[texture(0)]], sampler uSampler [[sampler(0)]], sampler uSamplerShadow [[sampler(1)]]) +{ + main0_out out = {}; + out.FragColor = sample_normal(uTexture, uSampler, in.vUV); + out.FragColor += sample_comp(uTexture, in.vUV, uSamplerShadow); + return out; +} + diff --git a/third_party/spirv-cross/reference/shaders-msl/frag/sample-depth-separate-image-sampler.frag b/third_party/spirv-cross/reference/shaders-msl/frag/sample-depth-separate-image-sampler.frag index a9c0f8b41b..d285941d7a 100644 --- a/third_party/spirv-cross/reference/shaders-msl/frag/sample-depth-separate-image-sampler.frag +++ b/third_party/spirv-cross/reference/shaders-msl/frag/sample-depth-separate-image-sampler.frag @@ -10,11 +10,13 @@ struct main0_out float FragColor [[color(0)]]; }; +static inline __attribute__((always_inline)) float sample_depth_from_function(thread const depth2d uT, thread const sampler uS) { return uT.sample_compare(uS, float3(0.5).xy, float3(0.5).z); } +static inline __attribute__((always_inline)) float sample_color_from_function(thread const texture2d uT, thread const sampler uS) { return uT.sample(uS, float2(0.5)).x; diff --git a/third_party/spirv-cross/reference/shaders-msl/frag/sample-position-func.frag b/third_party/spirv-cross/reference/shaders-msl/frag/sample-position-func.frag index 06fa53063a..025f874d26 100644 --- a/third_party/spirv-cross/reference/shaders-msl/frag/sample-position-func.frag +++ b/third_party/spirv-cross/reference/shaders-msl/frag/sample-position-func.frag @@ -15,6 +15,7 @@ struct main0_in int index [[user(locn0)]]; }; +static inline __attribute__((always_inline)) float4 getColor(thread const int& i, thread float2& gl_SamplePosition) { return float4(gl_SamplePosition, float(i), 1.0); diff --git a/third_party/spirv-cross/reference/shaders-msl/frag/sampler-image-arrays.msl2.frag b/third_party/spirv-cross/reference/shaders-msl/frag/sampler-image-arrays.msl2.frag index 10a7716261..dec6d051ae 100644 --- a/third_party/spirv-cross/reference/shaders-msl/frag/sampler-image-arrays.msl2.frag +++ b/third_party/spirv-cross/reference/shaders-msl/frag/sampler-image-arrays.msl2.frag @@ -16,16 +16,19 @@ struct main0_in int vIndex [[user(locn1)]]; }; +static inline __attribute__((always_inline)) float4 sample_from_global(thread int& vIndex, thread float2& vTex, thread const array, 4> uSampler, thread const array uSamplerSmplr) { return uSampler[vIndex].sample(uSamplerSmplr[vIndex], (vTex + float2(0.100000001490116119384765625))); } +static inline __attribute__((always_inline)) float4 sample_from_argument(thread const array, 4> samplers, thread const array samplersSmplr, thread int& vIndex, thread float2& vTex) { return samplers[vIndex].sample(samplersSmplr[vIndex], (vTex + float2(0.20000000298023223876953125))); } +static inline __attribute__((always_inline)) float4 sample_single_from_argument(thread const texture2d samp, thread const sampler sampSmplr, thread float2& vTex) { return samp.sample(sampSmplr, (vTex + float2(0.300000011920928955078125))); diff --git a/third_party/spirv-cross/reference/shaders-msl/frag/sampler.frag b/third_party/spirv-cross/reference/shaders-msl/frag/sampler.frag index 395854699e..6484161b69 100644 --- a/third_party/spirv-cross/reference/shaders-msl/frag/sampler.frag +++ b/third_party/spirv-cross/reference/shaders-msl/frag/sampler.frag @@ -16,6 +16,7 @@ struct main0_in float2 vTex [[user(locn1)]]; }; +static inline __attribute__((always_inline)) float4 sample_texture(thread const texture2d tex, thread const sampler texSmplr, thread const float2& uv) { return tex.sample(texSmplr, uv); diff --git a/third_party/spirv-cross/reference/shaders-msl/frag/separate-image-sampler-argument.frag b/third_party/spirv-cross/reference/shaders-msl/frag/separate-image-sampler-argument.frag index 46c0524ab7..d196243d4b 100644 --- a/third_party/spirv-cross/reference/shaders-msl/frag/separate-image-sampler-argument.frag +++ b/third_party/spirv-cross/reference/shaders-msl/frag/separate-image-sampler-argument.frag @@ -10,6 +10,7 @@ struct main0_out float4 FragColor [[color(0)]]; }; +static inline __attribute__((always_inline)) float4 samp(thread const texture2d t, thread const sampler s) { return t.sample(s, float2(0.5)); diff --git a/third_party/spirv-cross/reference/shaders-msl/frag/shader-arithmetic-8bit.frag b/third_party/spirv-cross/reference/shaders-msl/frag/shader-arithmetic-8bit.frag index 28ef043726..e9694aa196 100644 --- a/third_party/spirv-cross/reference/shaders-msl/frag/shader-arithmetic-8bit.frag +++ b/third_party/spirv-cross/reference/shaders-msl/frag/shader-arithmetic-8bit.frag @@ -34,9 +34,10 @@ struct main0_in int4 vColor [[user(locn0)]]; }; +static inline __attribute__((always_inline)) void packing_int8(device SSBO& ssbo) { - short i16 = 10; + short i16 = short(10); int i32 = 20; char2 i8_2 = as_type(i16); char4 i8_4 = as_type(i32); @@ -48,9 +49,10 @@ void packing_int8(device SSBO& ssbo) ssbo.i8[3] = i8_4.w; } +static inline __attribute__((always_inline)) void packing_uint8(device SSBO& ssbo) { - ushort u16 = 10u; + ushort u16 = ushort(10); uint u32 = 20u; uchar2 u8_2 = as_type(u16); uchar4 u8_4 = as_type(u32); @@ -62,6 +64,7 @@ void packing_uint8(device SSBO& ssbo) ssbo.u8[3] = u8_4.w; } +static inline __attribute__((always_inline)) void compute_int8(device SSBO& ssbo, thread int4& vColor, constant Push& registers, constant UBO& ubo, thread int4& FragColorInt) { char4 tmp = char4(vColor); @@ -74,6 +77,7 @@ void compute_int8(device SSBO& ssbo, thread int4& vColor, constant Push& registe FragColorInt = int4(tmp); } +static inline __attribute__((always_inline)) void compute_uint8(device SSBO& ssbo, thread int4& vColor, constant Push& registers, constant UBO& ubo, thread uint4& FragColorUint) { uchar4 tmp = uchar4(char4(vColor)); diff --git a/third_party/spirv-cross/reference/shaders-msl/frag/stencil-export.msl21.frag b/third_party/spirv-cross/reference/shaders-msl/frag/stencil-export.msl21.frag index eb85a2158d..f3629e18be 100644 --- a/third_party/spirv-cross/reference/shaders-msl/frag/stencil-export.msl21.frag +++ b/third_party/spirv-cross/reference/shaders-msl/frag/stencil-export.msl21.frag @@ -12,6 +12,7 @@ struct main0_out uint gl_FragStencilRefARB [[stencil]]; }; +static inline __attribute__((always_inline)) void update_stencil(thread uint& gl_FragStencilRefARB) { gl_FragStencilRefARB = uint(int(gl_FragStencilRefARB) + 10); diff --git a/third_party/spirv-cross/reference/shaders-msl/frag/texture-cube-array.frag b/third_party/spirv-cross/reference/shaders-msl/frag/texture-cube-array.frag new file mode 100644 index 0000000000..9f1832ec04 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-msl/frag/texture-cube-array.frag @@ -0,0 +1,25 @@ +#include +#include + +using namespace metal; + +struct main0_out +{ + float4 FragColor [[color(0)]]; +}; + +struct main0_in +{ + float4 vUV [[user(locn0)]]; +}; + +fragment main0_out main0(main0_in in [[stage_in]], texturecube cubeSampler [[texture(0)]], texturecube_array cubeArraySampler [[texture(1)]], texture2d_array texArraySampler [[texture(2)]], sampler cubeSamplerSmplr [[sampler(0)]], sampler cubeArraySamplerSmplr [[sampler(1)]], sampler texArraySamplerSmplr [[sampler(2)]]) +{ + main0_out out = {}; + float4 a = cubeSampler.sample(cubeSamplerSmplr, in.vUV.xyz); + float4 b = cubeArraySampler.sample(cubeArraySamplerSmplr, in.vUV.xyz, uint(round(in.vUV.w))); + float4 c = texArraySampler.sample(texArraySamplerSmplr, in.vUV.xyz.xy, uint(round(in.vUV.xyz.z))); + out.FragColor = (a + b) + c; + return out; +} + diff --git a/third_party/spirv-cross/reference/shaders-msl/frag/texture-cube-array.ios.emulate-cube-array.frag b/third_party/spirv-cross/reference/shaders-msl/frag/texture-cube-array.ios.emulate-cube-array.frag new file mode 100644 index 0000000000..3c4d0adb51 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-msl/frag/texture-cube-array.ios.emulate-cube-array.frag @@ -0,0 +1,61 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" + +#include +#include + +using namespace metal; + +struct main0_out +{ + float4 FragColor [[color(0)]]; +}; + +struct main0_in +{ + float4 vUV [[user(locn0)]]; +}; + +static inline __attribute__((always_inline)) +float3 spvCubemapTo2DArrayFace(float3 P) +{ + float3 Coords = abs(P.xyz); + float CubeFace = 0; + float ProjectionAxis = 0; + float u = 0; + float v = 0; + if (Coords.x >= Coords.y && Coords.x >= Coords.z) + { + CubeFace = P.x >= 0 ? 0 : 1; + ProjectionAxis = Coords.x; + u = P.x >= 0 ? -P.z : P.z; + v = -P.y; + } + else if (Coords.y >= Coords.x && Coords.y >= Coords.z) + { + CubeFace = P.y >= 0 ? 2 : 3; + ProjectionAxis = Coords.y; + u = P.x; + v = P.y >= 0 ? P.z : -P.z; + } + else + { + CubeFace = P.z >= 0 ? 4 : 5; + ProjectionAxis = Coords.z; + u = P.z >= 0 ? P.x : -P.x; + v = -P.y; + } + u = 0.5 * (u/ProjectionAxis + 1); + v = 0.5 * (v/ProjectionAxis + 1); + return float3(u, v, CubeFace); +} + +fragment main0_out main0(main0_in in [[stage_in]], texturecube cubeSampler [[texture(0)]], texture2d_array cubeArraySampler [[texture(1)]], texture2d_array texArraySampler [[texture(2)]], sampler cubeSamplerSmplr [[sampler(0)]], sampler cubeArraySamplerSmplr [[sampler(1)]], sampler texArraySamplerSmplr [[sampler(2)]]) +{ + main0_out out = {}; + float4 a = cubeSampler.sample(cubeSamplerSmplr, in.vUV.xyz); + float4 b = cubeArraySampler.sample(cubeArraySamplerSmplr, spvCubemapTo2DArrayFace(in.vUV.xyz).xy, uint(spvCubemapTo2DArrayFace(in.vUV.xyz).z) + (uint(round(in.vUV.w)) * 6u)); + float4 c = texArraySampler.sample(texArraySamplerSmplr, in.vUV.xyz.xy, uint(round(in.vUV.xyz.z))); + out.FragColor = (a + b) + c; + return out; +} + diff --git a/third_party/spirv-cross/reference/shaders-msl/frag/write-depth-in-function.frag b/third_party/spirv-cross/reference/shaders-msl/frag/write-depth-in-function.frag index 6837a9b3ea..c3ab221fc3 100644 --- a/third_party/spirv-cross/reference/shaders-msl/frag/write-depth-in-function.frag +++ b/third_party/spirv-cross/reference/shaders-msl/frag/write-depth-in-function.frag @@ -11,6 +11,7 @@ struct main0_out float gl_FragDepth [[depth(any)]]; }; +static inline __attribute__((always_inline)) void set_output_depth(thread float& gl_FragDepth) { gl_FragDepth = 0.20000000298023223876953125; diff --git a/third_party/spirv-cross/reference/shaders-msl/tesc/load-control-point-array-of-matrix.tesc b/third_party/spirv-cross/reference/shaders-msl/tesc/load-control-point-array-of-matrix.tesc new file mode 100644 index 0000000000..46d4b4ad58 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-msl/tesc/load-control-point-array-of-matrix.tesc @@ -0,0 +1,73 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + +#include +#include + +using namespace metal; + +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +struct main0_out +{ + float4x4 vOutputs; +}; + +struct main0_in +{ + float4 vInputs_0 [[attribute(0)]]; + float4 vInputs_1 [[attribute(1)]]; + float4 vInputs_2 [[attribute(2)]]; + float4 vInputs_3 [[attribute(3)]]; +}; + +kernel void main0(main0_in in [[stage_in]], uint gl_InvocationID [[thread_index_in_threadgroup]], uint gl_PrimitiveID [[threadgroup_position_in_grid]], device main0_out* spvOut [[buffer(28)]], constant uint* spvIndirectParams [[buffer(29)]], device MTLQuadTessellationFactorsHalf* spvTessLevel [[buffer(26)]], threadgroup main0_in* gl_in [[threadgroup(0)]]) +{ + device main0_out* gl_out = &spvOut[gl_PrimitiveID * 4]; + if (gl_InvocationID < spvIndirectParams[0]) + gl_in[gl_InvocationID] = in; + threadgroup_barrier(mem_flags::mem_threadgroup); + if (gl_InvocationID >= 4) + return; + spvUnsafeArray _16 = spvUnsafeArray({ float4x4(gl_in[0].vInputs_0, gl_in[0].vInputs_1, gl_in[0].vInputs_2, gl_in[0].vInputs_3), float4x4(gl_in[1].vInputs_0, gl_in[1].vInputs_1, gl_in[1].vInputs_2, gl_in[1].vInputs_3), float4x4(gl_in[2].vInputs_0, gl_in[2].vInputs_1, gl_in[2].vInputs_2, gl_in[2].vInputs_3), float4x4(gl_in[3].vInputs_0, gl_in[3].vInputs_1, gl_in[3].vInputs_2, gl_in[3].vInputs_3), float4x4(gl_in[4].vInputs_0, gl_in[4].vInputs_1, gl_in[4].vInputs_2, gl_in[4].vInputs_3), float4x4(gl_in[5].vInputs_0, gl_in[5].vInputs_1, gl_in[5].vInputs_2, gl_in[5].vInputs_3), float4x4(gl_in[6].vInputs_0, gl_in[6].vInputs_1, gl_in[6].vInputs_2, gl_in[6].vInputs_3), float4x4(gl_in[7].vInputs_0, gl_in[7].vInputs_1, gl_in[7].vInputs_2, gl_in[7].vInputs_3), float4x4(gl_in[8].vInputs_0, gl_in[8].vInputs_1, gl_in[8].vInputs_2, gl_in[8].vInputs_3), float4x4(gl_in[9].vInputs_0, gl_in[9].vInputs_1, gl_in[9].vInputs_2, gl_in[9].vInputs_3), float4x4(gl_in[10].vInputs_0, gl_in[10].vInputs_1, gl_in[10].vInputs_2, gl_in[10].vInputs_3), float4x4(gl_in[11].vInputs_0, gl_in[11].vInputs_1, gl_in[11].vInputs_2, gl_in[11].vInputs_3), float4x4(gl_in[12].vInputs_0, gl_in[12].vInputs_1, gl_in[12].vInputs_2, gl_in[12].vInputs_3), float4x4(gl_in[13].vInputs_0, gl_in[13].vInputs_1, gl_in[13].vInputs_2, gl_in[13].vInputs_3), float4x4(gl_in[14].vInputs_0, gl_in[14].vInputs_1, gl_in[14].vInputs_2, gl_in[14].vInputs_3), float4x4(gl_in[15].vInputs_0, gl_in[15].vInputs_1, gl_in[15].vInputs_2, gl_in[15].vInputs_3), float4x4(gl_in[16].vInputs_0, gl_in[16].vInputs_1, gl_in[16].vInputs_2, gl_in[16].vInputs_3), float4x4(gl_in[17].vInputs_0, gl_in[17].vInputs_1, gl_in[17].vInputs_2, gl_in[17].vInputs_3), float4x4(gl_in[18].vInputs_0, gl_in[18].vInputs_1, gl_in[18].vInputs_2, gl_in[18].vInputs_3), float4x4(gl_in[19].vInputs_0, gl_in[19].vInputs_1, gl_in[19].vInputs_2, gl_in[19].vInputs_3), float4x4(gl_in[20].vInputs_0, gl_in[20].vInputs_1, gl_in[20].vInputs_2, gl_in[20].vInputs_3), float4x4(gl_in[21].vInputs_0, gl_in[21].vInputs_1, gl_in[21].vInputs_2, gl_in[21].vInputs_3), float4x4(gl_in[22].vInputs_0, gl_in[22].vInputs_1, gl_in[22].vInputs_2, gl_in[22].vInputs_3), float4x4(gl_in[23].vInputs_0, gl_in[23].vInputs_1, gl_in[23].vInputs_2, gl_in[23].vInputs_3), float4x4(gl_in[24].vInputs_0, gl_in[24].vInputs_1, gl_in[24].vInputs_2, gl_in[24].vInputs_3), float4x4(gl_in[25].vInputs_0, gl_in[25].vInputs_1, gl_in[25].vInputs_2, gl_in[25].vInputs_3), float4x4(gl_in[26].vInputs_0, gl_in[26].vInputs_1, gl_in[26].vInputs_2, gl_in[26].vInputs_3), float4x4(gl_in[27].vInputs_0, gl_in[27].vInputs_1, gl_in[27].vInputs_2, gl_in[27].vInputs_3), float4x4(gl_in[28].vInputs_0, gl_in[28].vInputs_1, gl_in[28].vInputs_2, gl_in[28].vInputs_3), float4x4(gl_in[29].vInputs_0, gl_in[29].vInputs_1, gl_in[29].vInputs_2, gl_in[29].vInputs_3), float4x4(gl_in[30].vInputs_0, gl_in[30].vInputs_1, gl_in[30].vInputs_2, gl_in[30].vInputs_3), float4x4(gl_in[31].vInputs_0, gl_in[31].vInputs_1, gl_in[31].vInputs_2, gl_in[31].vInputs_3) }); + spvUnsafeArray tmp; + tmp = _16; + gl_out[gl_InvocationID].vOutputs = tmp[gl_InvocationID]; +} + diff --git a/third_party/spirv-cross/reference/shaders-msl/tesc/load-control-point-array-of-struct.tesc b/third_party/spirv-cross/reference/shaders-msl/tesc/load-control-point-array-of-struct.tesc new file mode 100644 index 0000000000..91d3521dfa --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-msl/tesc/load-control-point-array-of-struct.tesc @@ -0,0 +1,86 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + +#include +#include + +using namespace metal; + +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +struct VertexData +{ + float4x4 a; + spvUnsafeArray b; + float4 c; +}; + +struct main0_out +{ + float4 vOutputs; +}; + +struct main0_in +{ + float4 VertexData_a_0 [[attribute(0)]]; + float4 VertexData_a_1 [[attribute(1)]]; + float4 VertexData_a_2 [[attribute(2)]]; + float4 VertexData_a_3 [[attribute(3)]]; + float4 VertexData_b_0 [[attribute(4)]]; + float4 VertexData_b_1 [[attribute(5)]]; + float4 VertexData_c [[attribute(6)]]; +}; + +kernel void main0(main0_in in [[stage_in]], uint gl_InvocationID [[thread_index_in_threadgroup]], uint gl_PrimitiveID [[threadgroup_position_in_grid]], device main0_out* spvOut [[buffer(28)]], constant uint* spvIndirectParams [[buffer(29)]], device MTLQuadTessellationFactorsHalf* spvTessLevel [[buffer(26)]], threadgroup main0_in* gl_in [[threadgroup(0)]]) +{ + device main0_out* gl_out = &spvOut[gl_PrimitiveID * 4]; + if (gl_InvocationID < spvIndirectParams[0]) + gl_in[gl_InvocationID] = in; + threadgroup_barrier(mem_flags::mem_threadgroup); + if (gl_InvocationID >= 4) + return; + spvUnsafeArray _19 = spvUnsafeArray({ VertexData{ float4x4(gl_in[0].VertexData_a_0, gl_in[0].VertexData_a_1, gl_in[0].VertexData_a_2, gl_in[0].VertexData_a_3), spvUnsafeArray({ gl_in[0].VertexData_b_0, gl_in[0].VertexData_b_1 }), gl_in[0].VertexData_c }, VertexData{ float4x4(gl_in[1].VertexData_a_0, gl_in[1].VertexData_a_1, gl_in[1].VertexData_a_2, gl_in[1].VertexData_a_3), spvUnsafeArray({ gl_in[1].VertexData_b_0, gl_in[1].VertexData_b_1 }), gl_in[1].VertexData_c }, VertexData{ float4x4(gl_in[2].VertexData_a_0, gl_in[2].VertexData_a_1, gl_in[2].VertexData_a_2, gl_in[2].VertexData_a_3), spvUnsafeArray({ gl_in[2].VertexData_b_0, gl_in[2].VertexData_b_1 }), gl_in[2].VertexData_c }, VertexData{ float4x4(gl_in[3].VertexData_a_0, gl_in[3].VertexData_a_1, gl_in[3].VertexData_a_2, gl_in[3].VertexData_a_3), spvUnsafeArray({ gl_in[3].VertexData_b_0, gl_in[3].VertexData_b_1 }), gl_in[3].VertexData_c }, VertexData{ float4x4(gl_in[4].VertexData_a_0, gl_in[4].VertexData_a_1, gl_in[4].VertexData_a_2, gl_in[4].VertexData_a_3), spvUnsafeArray({ gl_in[4].VertexData_b_0, gl_in[4].VertexData_b_1 }), gl_in[4].VertexData_c }, VertexData{ float4x4(gl_in[5].VertexData_a_0, gl_in[5].VertexData_a_1, gl_in[5].VertexData_a_2, gl_in[5].VertexData_a_3), spvUnsafeArray({ gl_in[5].VertexData_b_0, gl_in[5].VertexData_b_1 }), gl_in[5].VertexData_c }, VertexData{ float4x4(gl_in[6].VertexData_a_0, gl_in[6].VertexData_a_1, gl_in[6].VertexData_a_2, gl_in[6].VertexData_a_3), spvUnsafeArray({ gl_in[6].VertexData_b_0, gl_in[6].VertexData_b_1 }), gl_in[6].VertexData_c }, VertexData{ float4x4(gl_in[7].VertexData_a_0, gl_in[7].VertexData_a_1, gl_in[7].VertexData_a_2, gl_in[7].VertexData_a_3), spvUnsafeArray({ gl_in[7].VertexData_b_0, gl_in[7].VertexData_b_1 }), gl_in[7].VertexData_c }, VertexData{ float4x4(gl_in[8].VertexData_a_0, gl_in[8].VertexData_a_1, gl_in[8].VertexData_a_2, gl_in[8].VertexData_a_3), spvUnsafeArray({ gl_in[8].VertexData_b_0, gl_in[8].VertexData_b_1 }), gl_in[8].VertexData_c }, VertexData{ float4x4(gl_in[9].VertexData_a_0, gl_in[9].VertexData_a_1, gl_in[9].VertexData_a_2, gl_in[9].VertexData_a_3), spvUnsafeArray({ gl_in[9].VertexData_b_0, gl_in[9].VertexData_b_1 }), gl_in[9].VertexData_c }, VertexData{ float4x4(gl_in[10].VertexData_a_0, gl_in[10].VertexData_a_1, gl_in[10].VertexData_a_2, gl_in[10].VertexData_a_3), spvUnsafeArray({ gl_in[10].VertexData_b_0, gl_in[10].VertexData_b_1 }), gl_in[10].VertexData_c }, VertexData{ float4x4(gl_in[11].VertexData_a_0, gl_in[11].VertexData_a_1, gl_in[11].VertexData_a_2, gl_in[11].VertexData_a_3), spvUnsafeArray({ gl_in[11].VertexData_b_0, gl_in[11].VertexData_b_1 }), gl_in[11].VertexData_c }, VertexData{ float4x4(gl_in[12].VertexData_a_0, gl_in[12].VertexData_a_1, gl_in[12].VertexData_a_2, gl_in[12].VertexData_a_3), spvUnsafeArray({ gl_in[12].VertexData_b_0, gl_in[12].VertexData_b_1 }), gl_in[12].VertexData_c }, VertexData{ float4x4(gl_in[13].VertexData_a_0, gl_in[13].VertexData_a_1, gl_in[13].VertexData_a_2, gl_in[13].VertexData_a_3), spvUnsafeArray({ gl_in[13].VertexData_b_0, gl_in[13].VertexData_b_1 }), gl_in[13].VertexData_c }, VertexData{ float4x4(gl_in[14].VertexData_a_0, gl_in[14].VertexData_a_1, gl_in[14].VertexData_a_2, gl_in[14].VertexData_a_3), spvUnsafeArray({ gl_in[14].VertexData_b_0, gl_in[14].VertexData_b_1 }), gl_in[14].VertexData_c }, VertexData{ float4x4(gl_in[15].VertexData_a_0, gl_in[15].VertexData_a_1, gl_in[15].VertexData_a_2, gl_in[15].VertexData_a_3), spvUnsafeArray({ gl_in[15].VertexData_b_0, gl_in[15].VertexData_b_1 }), gl_in[15].VertexData_c }, VertexData{ float4x4(gl_in[16].VertexData_a_0, gl_in[16].VertexData_a_1, gl_in[16].VertexData_a_2, gl_in[16].VertexData_a_3), spvUnsafeArray({ gl_in[16].VertexData_b_0, gl_in[16].VertexData_b_1 }), gl_in[16].VertexData_c }, VertexData{ float4x4(gl_in[17].VertexData_a_0, gl_in[17].VertexData_a_1, gl_in[17].VertexData_a_2, gl_in[17].VertexData_a_3), spvUnsafeArray({ gl_in[17].VertexData_b_0, gl_in[17].VertexData_b_1 }), gl_in[17].VertexData_c }, VertexData{ float4x4(gl_in[18].VertexData_a_0, gl_in[18].VertexData_a_1, gl_in[18].VertexData_a_2, gl_in[18].VertexData_a_3), spvUnsafeArray({ gl_in[18].VertexData_b_0, gl_in[18].VertexData_b_1 }), gl_in[18].VertexData_c }, VertexData{ float4x4(gl_in[19].VertexData_a_0, gl_in[19].VertexData_a_1, gl_in[19].VertexData_a_2, gl_in[19].VertexData_a_3), spvUnsafeArray({ gl_in[19].VertexData_b_0, gl_in[19].VertexData_b_1 }), gl_in[19].VertexData_c }, VertexData{ float4x4(gl_in[20].VertexData_a_0, gl_in[20].VertexData_a_1, gl_in[20].VertexData_a_2, gl_in[20].VertexData_a_3), spvUnsafeArray({ gl_in[20].VertexData_b_0, gl_in[20].VertexData_b_1 }), gl_in[20].VertexData_c }, VertexData{ float4x4(gl_in[21].VertexData_a_0, gl_in[21].VertexData_a_1, gl_in[21].VertexData_a_2, gl_in[21].VertexData_a_3), spvUnsafeArray({ gl_in[21].VertexData_b_0, gl_in[21].VertexData_b_1 }), gl_in[21].VertexData_c }, VertexData{ float4x4(gl_in[22].VertexData_a_0, gl_in[22].VertexData_a_1, gl_in[22].VertexData_a_2, gl_in[22].VertexData_a_3), spvUnsafeArray({ gl_in[22].VertexData_b_0, gl_in[22].VertexData_b_1 }), gl_in[22].VertexData_c }, VertexData{ float4x4(gl_in[23].VertexData_a_0, gl_in[23].VertexData_a_1, gl_in[23].VertexData_a_2, gl_in[23].VertexData_a_3), spvUnsafeArray({ gl_in[23].VertexData_b_0, gl_in[23].VertexData_b_1 }), gl_in[23].VertexData_c }, VertexData{ float4x4(gl_in[24].VertexData_a_0, gl_in[24].VertexData_a_1, gl_in[24].VertexData_a_2, gl_in[24].VertexData_a_3), spvUnsafeArray({ gl_in[24].VertexData_b_0, gl_in[24].VertexData_b_1 }), gl_in[24].VertexData_c }, VertexData{ float4x4(gl_in[25].VertexData_a_0, gl_in[25].VertexData_a_1, gl_in[25].VertexData_a_2, gl_in[25].VertexData_a_3), spvUnsafeArray({ gl_in[25].VertexData_b_0, gl_in[25].VertexData_b_1 }), gl_in[25].VertexData_c }, VertexData{ float4x4(gl_in[26].VertexData_a_0, gl_in[26].VertexData_a_1, gl_in[26].VertexData_a_2, gl_in[26].VertexData_a_3), spvUnsafeArray({ gl_in[26].VertexData_b_0, gl_in[26].VertexData_b_1 }), gl_in[26].VertexData_c }, VertexData{ float4x4(gl_in[27].VertexData_a_0, gl_in[27].VertexData_a_1, gl_in[27].VertexData_a_2, gl_in[27].VertexData_a_3), spvUnsafeArray({ gl_in[27].VertexData_b_0, gl_in[27].VertexData_b_1 }), gl_in[27].VertexData_c }, VertexData{ float4x4(gl_in[28].VertexData_a_0, gl_in[28].VertexData_a_1, gl_in[28].VertexData_a_2, gl_in[28].VertexData_a_3), spvUnsafeArray({ gl_in[28].VertexData_b_0, gl_in[28].VertexData_b_1 }), gl_in[28].VertexData_c }, VertexData{ float4x4(gl_in[29].VertexData_a_0, gl_in[29].VertexData_a_1, gl_in[29].VertexData_a_2, gl_in[29].VertexData_a_3), spvUnsafeArray({ gl_in[29].VertexData_b_0, gl_in[29].VertexData_b_1 }), gl_in[29].VertexData_c }, VertexData{ float4x4(gl_in[30].VertexData_a_0, gl_in[30].VertexData_a_1, gl_in[30].VertexData_a_2, gl_in[30].VertexData_a_3), spvUnsafeArray({ gl_in[30].VertexData_b_0, gl_in[30].VertexData_b_1 }), gl_in[30].VertexData_c }, VertexData{ float4x4(gl_in[31].VertexData_a_0, gl_in[31].VertexData_a_1, gl_in[31].VertexData_a_2, gl_in[31].VertexData_a_3), spvUnsafeArray({ gl_in[31].VertexData_b_0, gl_in[31].VertexData_b_1 }), gl_in[31].VertexData_c } }); + spvUnsafeArray tmp; + tmp = _19; + int _27 = gl_InvocationID ^ 1; + VertexData _30 = VertexData{ float4x4(gl_in[_27].VertexData_a_0, gl_in[_27].VertexData_a_1, gl_in[_27].VertexData_a_2, gl_in[_27].VertexData_a_3), spvUnsafeArray({ gl_in[_27].VertexData_b_0, gl_in[_27].VertexData_b_1 }), gl_in[_27].VertexData_c }; + VertexData tmp_single = _30; + gl_out[gl_InvocationID].vOutputs = ((tmp[gl_InvocationID].a[1] + tmp[gl_InvocationID].b[1]) + tmp[gl_InvocationID].c) + tmp_single.c; +} + diff --git a/third_party/spirv-cross/reference/shaders-msl/tesc/load-control-point-array.tesc b/third_party/spirv-cross/reference/shaders-msl/tesc/load-control-point-array.tesc new file mode 100644 index 0000000000..d04571ae36 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-msl/tesc/load-control-point-array.tesc @@ -0,0 +1,70 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + +#include +#include + +using namespace metal; + +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +struct main0_out +{ + float4 vOutputs; +}; + +struct main0_in +{ + float4 vInputs [[attribute(0)]]; +}; + +kernel void main0(main0_in in [[stage_in]], uint gl_InvocationID [[thread_index_in_threadgroup]], uint gl_PrimitiveID [[threadgroup_position_in_grid]], device main0_out* spvOut [[buffer(28)]], constant uint* spvIndirectParams [[buffer(29)]], device MTLQuadTessellationFactorsHalf* spvTessLevel [[buffer(26)]], threadgroup main0_in* gl_in [[threadgroup(0)]]) +{ + device main0_out* gl_out = &spvOut[gl_PrimitiveID * 4]; + if (gl_InvocationID < spvIndirectParams[0]) + gl_in[gl_InvocationID] = in; + threadgroup_barrier(mem_flags::mem_threadgroup); + if (gl_InvocationID >= 4) + return; + spvUnsafeArray _15 = spvUnsafeArray({ gl_in[0].vInputs, gl_in[1].vInputs, gl_in[2].vInputs, gl_in[3].vInputs, gl_in[4].vInputs, gl_in[5].vInputs, gl_in[6].vInputs, gl_in[7].vInputs, gl_in[8].vInputs, gl_in[9].vInputs, gl_in[10].vInputs, gl_in[11].vInputs, gl_in[12].vInputs, gl_in[13].vInputs, gl_in[14].vInputs, gl_in[15].vInputs, gl_in[16].vInputs, gl_in[17].vInputs, gl_in[18].vInputs, gl_in[19].vInputs, gl_in[20].vInputs, gl_in[21].vInputs, gl_in[22].vInputs, gl_in[23].vInputs, gl_in[24].vInputs, gl_in[25].vInputs, gl_in[26].vInputs, gl_in[27].vInputs, gl_in[28].vInputs, gl_in[29].vInputs, gl_in[30].vInputs, gl_in[31].vInputs }); + spvUnsafeArray tmp; + tmp = _15; + gl_out[gl_InvocationID].vOutputs = tmp[gl_InvocationID]; +} + diff --git a/third_party/spirv-cross/reference/shaders-msl/tesc/water_tess.tesc b/third_party/spirv-cross/reference/shaders-msl/tesc/water_tess.tesc index e984509f2f..d74f5752f8 100644 --- a/third_party/spirv-cross/reference/shaders-msl/tesc/water_tess.tesc +++ b/third_party/spirv-cross/reference/shaders-msl/tesc/water_tess.tesc @@ -26,6 +26,7 @@ struct main0_in float2 vPatchPosBase [[attribute(0)]]; }; +static inline __attribute__((always_inline)) bool frustum_cull(thread const float2& p0, constant UBO& v_41) { float2 min_xz = (p0 - float2(10.0)) * v_41.uScale.xy; @@ -49,6 +50,7 @@ bool frustum_cull(thread const float2& p0, constant UBO& v_41) return !_215; } +static inline __attribute__((always_inline)) float lod_factor(thread const float2& pos_, constant UBO& v_41) { float2 pos = pos_ * v_41.uScale.xy; @@ -57,16 +59,19 @@ float lod_factor(thread const float2& pos_, constant UBO& v_41) return fast::clamp(level, 0.0, v_41.uMaxTessLevel.x); } +static inline __attribute__((always_inline)) float4 tess_level(thread const float4& lod, constant UBO& v_41) { return exp2(-lod) * v_41.uMaxTessLevel.y; } +static inline __attribute__((always_inline)) float tess_level(thread const float& lod, constant UBO& v_41) { return v_41.uMaxTessLevel.y * exp2(-lod); } +static inline __attribute__((always_inline)) void compute_tess_levels(thread const float2& p0, constant UBO& v_41, device float2& vOutPatchPosBase, device float4& vPatchLods, device half (&gl_TessLevelOuter)[4], device half (&gl_TessLevelInner)[2]) { vOutPatchPosBase = p0; diff --git a/third_party/spirv-cross/reference/shaders-msl/tese/input-array.tese b/third_party/spirv-cross/reference/shaders-msl/tese/input-array.tese index 2ac5731fe4..f6cfa2fb90 100644 --- a/third_party/spirv-cross/reference/shaders-msl/tese/input-array.tese +++ b/third_party/spirv-cross/reference/shaders-msl/tese/input-array.tese @@ -21,6 +21,7 @@ struct main0_patchIn patch_control_point gl_in; }; +static inline __attribute__((always_inline)) void set_position(thread float4& gl_Position, thread patch_control_point& gl_in, thread float2& gl_TessCoord) { gl_Position = (gl_in[0].Floats * gl_TessCoord.x) + (gl_in[1].Floats2 * gl_TessCoord.y); diff --git a/third_party/spirv-cross/reference/shaders-msl/tese/input-types.tese b/third_party/spirv-cross/reference/shaders-msl/tese/input-types.tese index 9012a7e1a7..af6db4626c 100644 --- a/third_party/spirv-cross/reference/shaders-msl/tese/input-types.tese +++ b/third_party/spirv-cross/reference/shaders-msl/tese/input-types.tese @@ -47,6 +47,7 @@ struct main0_patchIn patch_control_point gl_in; }; +static inline __attribute__((always_inline)) void set_from_function(thread float4& gl_Position, thread patch_control_point& gl_in, thread PatchBlock& patch_block, thread float4& vColors, thread Foo& vFoo) { gl_Position = gl_in[0].Block_a; @@ -61,16 +62,12 @@ void set_from_function(thread float4& gl_Position, thread patch_control_point +#include + +using namespace metal; + +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +struct main0_out +{ + float4 gl_Position [[position]]; +}; + +struct main0_in +{ + float4 vInputs_0 [[attribute(0)]]; + float4 vInputs_1 [[attribute(1)]]; + float4 vInputs_2 [[attribute(2)]]; + float4 vInputs_3 [[attribute(3)]]; +}; + +struct main0_patchIn +{ + float4 vBoo_0 [[attribute(4)]]; + float4 vBoo_1 [[attribute(5)]]; + float4 vBoo_2 [[attribute(6)]]; + float4 vBoo_3 [[attribute(7)]]; + int vIndex [[attribute(8)]]; + patch_control_point gl_in; +}; + +[[ patch(quad, 0) ]] vertex main0_out main0(main0_patchIn patchIn [[stage_in]]) +{ + main0_out out = {}; + spvUnsafeArray vBoo = {}; + vBoo[0] = patchIn.vBoo_0; + vBoo[1] = patchIn.vBoo_1; + vBoo[2] = patchIn.vBoo_2; + vBoo[3] = patchIn.vBoo_3; + spvUnsafeArray _16 = spvUnsafeArray({ float4x4(patchIn.gl_in[0].vInputs_0, patchIn.gl_in[0].vInputs_1, patchIn.gl_in[0].vInputs_2, patchIn.gl_in[0].vInputs_3), float4x4(patchIn.gl_in[1].vInputs_0, patchIn.gl_in[1].vInputs_1, patchIn.gl_in[1].vInputs_2, patchIn.gl_in[1].vInputs_3), float4x4(patchIn.gl_in[2].vInputs_0, patchIn.gl_in[2].vInputs_1, patchIn.gl_in[2].vInputs_2, patchIn.gl_in[2].vInputs_3), float4x4(patchIn.gl_in[3].vInputs_0, patchIn.gl_in[3].vInputs_1, patchIn.gl_in[3].vInputs_2, patchIn.gl_in[3].vInputs_3), float4x4(patchIn.gl_in[4].vInputs_0, patchIn.gl_in[4].vInputs_1, patchIn.gl_in[4].vInputs_2, patchIn.gl_in[4].vInputs_3), float4x4(patchIn.gl_in[5].vInputs_0, patchIn.gl_in[5].vInputs_1, patchIn.gl_in[5].vInputs_2, patchIn.gl_in[5].vInputs_3), float4x4(patchIn.gl_in[6].vInputs_0, patchIn.gl_in[6].vInputs_1, patchIn.gl_in[6].vInputs_2, patchIn.gl_in[6].vInputs_3), float4x4(patchIn.gl_in[7].vInputs_0, patchIn.gl_in[7].vInputs_1, patchIn.gl_in[7].vInputs_2, patchIn.gl_in[7].vInputs_3), float4x4(patchIn.gl_in[8].vInputs_0, patchIn.gl_in[8].vInputs_1, patchIn.gl_in[8].vInputs_2, patchIn.gl_in[8].vInputs_3), float4x4(patchIn.gl_in[9].vInputs_0, patchIn.gl_in[9].vInputs_1, patchIn.gl_in[9].vInputs_2, patchIn.gl_in[9].vInputs_3), float4x4(patchIn.gl_in[10].vInputs_0, patchIn.gl_in[10].vInputs_1, patchIn.gl_in[10].vInputs_2, patchIn.gl_in[10].vInputs_3), float4x4(patchIn.gl_in[11].vInputs_0, patchIn.gl_in[11].vInputs_1, patchIn.gl_in[11].vInputs_2, patchIn.gl_in[11].vInputs_3), float4x4(patchIn.gl_in[12].vInputs_0, patchIn.gl_in[12].vInputs_1, patchIn.gl_in[12].vInputs_2, patchIn.gl_in[12].vInputs_3), float4x4(patchIn.gl_in[13].vInputs_0, patchIn.gl_in[13].vInputs_1, patchIn.gl_in[13].vInputs_2, patchIn.gl_in[13].vInputs_3), float4x4(patchIn.gl_in[14].vInputs_0, patchIn.gl_in[14].vInputs_1, patchIn.gl_in[14].vInputs_2, patchIn.gl_in[14].vInputs_3), float4x4(patchIn.gl_in[15].vInputs_0, patchIn.gl_in[15].vInputs_1, patchIn.gl_in[15].vInputs_2, patchIn.gl_in[15].vInputs_3), float4x4(patchIn.gl_in[16].vInputs_0, patchIn.gl_in[16].vInputs_1, patchIn.gl_in[16].vInputs_2, patchIn.gl_in[16].vInputs_3), float4x4(patchIn.gl_in[17].vInputs_0, patchIn.gl_in[17].vInputs_1, patchIn.gl_in[17].vInputs_2, patchIn.gl_in[17].vInputs_3), float4x4(patchIn.gl_in[18].vInputs_0, patchIn.gl_in[18].vInputs_1, patchIn.gl_in[18].vInputs_2, patchIn.gl_in[18].vInputs_3), float4x4(patchIn.gl_in[19].vInputs_0, patchIn.gl_in[19].vInputs_1, patchIn.gl_in[19].vInputs_2, patchIn.gl_in[19].vInputs_3), float4x4(patchIn.gl_in[20].vInputs_0, patchIn.gl_in[20].vInputs_1, patchIn.gl_in[20].vInputs_2, patchIn.gl_in[20].vInputs_3), float4x4(patchIn.gl_in[21].vInputs_0, patchIn.gl_in[21].vInputs_1, patchIn.gl_in[21].vInputs_2, patchIn.gl_in[21].vInputs_3), float4x4(patchIn.gl_in[22].vInputs_0, patchIn.gl_in[22].vInputs_1, patchIn.gl_in[22].vInputs_2, patchIn.gl_in[22].vInputs_3), float4x4(patchIn.gl_in[23].vInputs_0, patchIn.gl_in[23].vInputs_1, patchIn.gl_in[23].vInputs_2, patchIn.gl_in[23].vInputs_3), float4x4(patchIn.gl_in[24].vInputs_0, patchIn.gl_in[24].vInputs_1, patchIn.gl_in[24].vInputs_2, patchIn.gl_in[24].vInputs_3), float4x4(patchIn.gl_in[25].vInputs_0, patchIn.gl_in[25].vInputs_1, patchIn.gl_in[25].vInputs_2, patchIn.gl_in[25].vInputs_3), float4x4(patchIn.gl_in[26].vInputs_0, patchIn.gl_in[26].vInputs_1, patchIn.gl_in[26].vInputs_2, patchIn.gl_in[26].vInputs_3), float4x4(patchIn.gl_in[27].vInputs_0, patchIn.gl_in[27].vInputs_1, patchIn.gl_in[27].vInputs_2, patchIn.gl_in[27].vInputs_3), float4x4(patchIn.gl_in[28].vInputs_0, patchIn.gl_in[28].vInputs_1, patchIn.gl_in[28].vInputs_2, patchIn.gl_in[28].vInputs_3), float4x4(patchIn.gl_in[29].vInputs_0, patchIn.gl_in[29].vInputs_1, patchIn.gl_in[29].vInputs_2, patchIn.gl_in[29].vInputs_3), float4x4(patchIn.gl_in[30].vInputs_0, patchIn.gl_in[30].vInputs_1, patchIn.gl_in[30].vInputs_2, patchIn.gl_in[30].vInputs_3), float4x4(patchIn.gl_in[31].vInputs_0, patchIn.gl_in[31].vInputs_1, patchIn.gl_in[31].vInputs_2, patchIn.gl_in[31].vInputs_3) }); + spvUnsafeArray tmp; + tmp = _16; + out.gl_Position = (tmp[0][patchIn.vIndex] + tmp[1][patchIn.vIndex]) + vBoo[patchIn.vIndex]; + return out; +} + diff --git a/third_party/spirv-cross/reference/shaders-msl/tese/load-control-point-array.tese b/third_party/spirv-cross/reference/shaders-msl/tese/load-control-point-array.tese new file mode 100644 index 0000000000..09c19cb47f --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-msl/tese/load-control-point-array.tese @@ -0,0 +1,81 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + +#include +#include + +using namespace metal; + +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +struct main0_out +{ + float4 gl_Position [[position]]; +}; + +struct main0_in +{ + float4 vInputs [[attribute(0)]]; +}; + +struct main0_patchIn +{ + float4 vBoo_0 [[attribute(1)]]; + float4 vBoo_1 [[attribute(2)]]; + float4 vBoo_2 [[attribute(3)]]; + float4 vBoo_3 [[attribute(4)]]; + int vIndex [[attribute(5)]]; + patch_control_point gl_in; +}; + +[[ patch(quad, 0) ]] vertex main0_out main0(main0_patchIn patchIn [[stage_in]]) +{ + main0_out out = {}; + spvUnsafeArray vBoo = {}; + vBoo[0] = patchIn.vBoo_0; + vBoo[1] = patchIn.vBoo_1; + vBoo[2] = patchIn.vBoo_2; + vBoo[3] = patchIn.vBoo_3; + spvUnsafeArray _15 = spvUnsafeArray({ patchIn.gl_in[0].vInputs, patchIn.gl_in[1].vInputs, patchIn.gl_in[2].vInputs, patchIn.gl_in[3].vInputs, patchIn.gl_in[4].vInputs, patchIn.gl_in[5].vInputs, patchIn.gl_in[6].vInputs, patchIn.gl_in[7].vInputs, patchIn.gl_in[8].vInputs, patchIn.gl_in[9].vInputs, patchIn.gl_in[10].vInputs, patchIn.gl_in[11].vInputs, patchIn.gl_in[12].vInputs, patchIn.gl_in[13].vInputs, patchIn.gl_in[14].vInputs, patchIn.gl_in[15].vInputs, patchIn.gl_in[16].vInputs, patchIn.gl_in[17].vInputs, patchIn.gl_in[18].vInputs, patchIn.gl_in[19].vInputs, patchIn.gl_in[20].vInputs, patchIn.gl_in[21].vInputs, patchIn.gl_in[22].vInputs, patchIn.gl_in[23].vInputs, patchIn.gl_in[24].vInputs, patchIn.gl_in[25].vInputs, patchIn.gl_in[26].vInputs, patchIn.gl_in[27].vInputs, patchIn.gl_in[28].vInputs, patchIn.gl_in[29].vInputs, patchIn.gl_in[30].vInputs, patchIn.gl_in[31].vInputs }); + spvUnsafeArray tmp; + tmp = _15; + out.gl_Position = (tmp[0] + tmp[1]) + vBoo[patchIn.vIndex]; + return out; +} + diff --git a/third_party/spirv-cross/reference/shaders-msl/tese/quad.tese b/third_party/spirv-cross/reference/shaders-msl/tese/quad.tese index df3d260fa8..40273582cc 100644 --- a/third_party/spirv-cross/reference/shaders-msl/tese/quad.tese +++ b/third_party/spirv-cross/reference/shaders-msl/tese/quad.tese @@ -16,6 +16,7 @@ struct main0_patchIn float4 gl_TessLevelOuter [[attribute(1)]]; }; +static inline __attribute__((always_inline)) void set_position(thread float4& gl_Position, thread float2& gl_TessCoord, thread float2& gl_TessLevelInner, thread float4& gl_TessLevelOuter) { gl_Position = float4(((gl_TessCoord.x * gl_TessLevelInner.x) * gl_TessLevelOuter.x) + (((1.0 - gl_TessCoord.x) * gl_TessLevelInner.x) * gl_TessLevelOuter.z), ((gl_TessCoord.y * gl_TessLevelInner.y) * gl_TessLevelOuter.y) + (((1.0 - gl_TessCoord.y) * gl_TessLevelInner.y) * gl_TessLevelOuter.w), 0.0, 1.0); diff --git a/third_party/spirv-cross/reference/shaders-msl/tese/set-from-function.tese b/third_party/spirv-cross/reference/shaders-msl/tese/set-from-function.tese index f6e41ee5c8..30bb720c01 100644 --- a/third_party/spirv-cross/reference/shaders-msl/tese/set-from-function.tese +++ b/third_party/spirv-cross/reference/shaders-msl/tese/set-from-function.tese @@ -37,6 +37,7 @@ struct main0_patchIn patch_control_point gl_in; }; +static inline __attribute__((always_inline)) void set_from_function(thread float4& gl_Position, thread patch_control_point& gl_in, thread float4& vColors, thread Foo& vFoo) { gl_Position = gl_in[0].Block_a; diff --git a/third_party/spirv-cross/reference/shaders-msl/tese/triangle-tess-level.tese b/third_party/spirv-cross/reference/shaders-msl/tese/triangle-tess-level.tese index 975e629851..6930e1479d 100644 --- a/third_party/spirv-cross/reference/shaders-msl/tese/triangle-tess-level.tese +++ b/third_party/spirv-cross/reference/shaders-msl/tese/triangle-tess-level.tese @@ -1,8 +1,49 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + #include #include using namespace metal; +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + struct main0_out { float4 gl_Position [[position]]; @@ -16,8 +57,8 @@ struct main0_patchIn [[ patch(triangle, 0) ]] vertex main0_out main0(main0_patchIn patchIn [[stage_in]], float3 gl_TessCoord [[position_in_patch]]) { main0_out out = {}; - float gl_TessLevelInner[2] = {}; - float gl_TessLevelOuter[4] = {}; + spvUnsafeArray gl_TessLevelInner = {}; + spvUnsafeArray gl_TessLevelOuter = {}; gl_TessLevelInner[0] = patchIn.gl_TessLevel.w; gl_TessLevelOuter[0] = patchIn.gl_TessLevel.x; gl_TessLevelOuter[1] = patchIn.gl_TessLevel.y; diff --git a/third_party/spirv-cross/reference/shaders-msl/tese/water_tess.tese b/third_party/spirv-cross/reference/shaders-msl/tese/water_tess.tese index 9b6c0aca84..f0054562b0 100644 --- a/third_party/spirv-cross/reference/shaders-msl/tese/water_tess.tese +++ b/third_party/spirv-cross/reference/shaders-msl/tese/water_tess.tese @@ -28,11 +28,13 @@ struct main0_patchIn float4 vPatchLods [[attribute(1)]]; }; +static inline __attribute__((always_inline)) float2 lerp_vertex(thread const float2& tess_coord, thread float2& vOutPatchPosBase, constant UBO& v_31) { return vOutPatchPosBase + (tess_coord * v_31.uPatchSize); } +static inline __attribute__((always_inline)) float2 lod_factor(thread const float2& tess_coord, thread float4& vPatchLods) { float2 x = mix(vPatchLods.yx, vPatchLods.zw, float2(tess_coord.x)); @@ -42,6 +44,7 @@ float2 lod_factor(thread const float2& tess_coord, thread float4& vPatchLods) return float2(floor_level, fract_level); } +static inline __attribute__((always_inline)) float3 sample_height_displacement(thread const float2& uv, thread const float2& off, thread const float2& lod, thread texture2d uHeightmapDisplacement, thread const sampler uHeightmapDisplacementSmplr) { return mix(uHeightmapDisplacement.sample(uHeightmapDisplacementSmplr, (uv + (off * 0.5)), level(lod.x)).xyz, uHeightmapDisplacement.sample(uHeightmapDisplacementSmplr, (uv + (off * 1.0)), level(lod.x + 1.0)).xyz, float3(lod.y)); diff --git a/third_party/spirv-cross/reference/shaders-msl/vert/clip-distance-block.vert b/third_party/spirv-cross/reference/shaders-msl/vert/clip-distance-block.vert new file mode 100644 index 0000000000..af58f35ff5 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-msl/vert/clip-distance-block.vert @@ -0,0 +1,29 @@ +#include +#include + +using namespace metal; + +struct main0_out +{ + float4 gl_Position [[position]]; + float gl_ClipDistance [[clip_distance]] [2]; + float gl_ClipDistance_0 [[user(clip0)]]; + float gl_ClipDistance_1 [[user(clip1)]]; +}; + +struct main0_in +{ + float4 Position [[attribute(0)]]; +}; + +vertex main0_out main0(main0_in in [[stage_in]]) +{ + main0_out out = {}; + out.gl_Position = in.Position; + out.gl_ClipDistance[0] = in.Position.x; + out.gl_ClipDistance[1] = in.Position.y; + out.gl_ClipDistance_0 = out.gl_ClipDistance[0]; + out.gl_ClipDistance_1 = out.gl_ClipDistance[1]; + return out; +} + diff --git a/third_party/spirv-cross/reference/shaders-msl/vert/float-math.invariant-float-math.vert b/third_party/spirv-cross/reference/shaders-msl/vert/float-math.invariant-float-math.vert new file mode 100644 index 0000000000..d603884cd8 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-msl/vert/float-math.invariant-float-math.vert @@ -0,0 +1,136 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + +#include +#include + +using namespace metal; + +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +struct Matrices +{ + float4x4 vpMatrix; + float4x4 wMatrix; + float4x3 wMatrix4x3; + float3x4 wMatrix3x4; +}; + +struct main0_out +{ + float3 OutNormal [[user(locn0)]]; + float4 OutWorldPos_0 [[user(locn1)]]; + float4 OutWorldPos_1 [[user(locn2)]]; + float4 OutWorldPos_2 [[user(locn3)]]; + float4 OutWorldPos_3 [[user(locn4)]]; + float4 gl_Position [[position]]; +}; + +struct main0_in +{ + float3 InPos [[attribute(0)]]; + float3 InNormal [[attribute(1)]]; +}; + +template +T spvFMul(T l, T r) +{ + return fma(l, r, T(0)); +} + +template +vec spvFMulVectorMatrix(vec v, matrix m) +{ + vec res = vec(0); + for (uint i = Rows; i > 0; --i) + { + vec tmp(0); + for (uint j = 0; j < Cols; ++j) + { + tmp[j] = m[j][i - 1]; + } + res = fma(tmp, vec(v[i - 1]), res); + } + return res; +} + +template +vec spvFMulMatrixVector(matrix m, vec v) +{ + vec res = vec(0); + for (uint i = Cols; i > 0; --i) + { + res = fma(m[i - 1], vec(v[i - 1]), res); + } + return res; +} + +template +matrix spvFMulMatrixMatrix(matrix l, matrix r) +{ + matrix res; + for (uint i = 0; i < RCols; i++) + { + vec tmp(0); + for (uint j = 0; j < LCols; j++) + { + tmp = fma(vec(r[i][j]), l[j], tmp); + } + res[i] = tmp; + } + return res; +} + +vertex main0_out main0(main0_in in [[stage_in]], constant Matrices& _22 [[buffer(0)]]) +{ + main0_out out = {}; + spvUnsafeArray OutWorldPos = {}; + out.gl_Position = spvFMulMatrixVector(spvFMulMatrixMatrix(_22.vpMatrix, _22.wMatrix), float4(in.InPos, 1.0)); + OutWorldPos[0] = spvFMulMatrixVector(_22.wMatrix, float4(in.InPos, 1.0)); + OutWorldPos[1] = spvFMulVectorMatrix(float4(in.InPos, 1.0), _22.wMatrix); + OutWorldPos[2] = spvFMulMatrixVector(_22.wMatrix3x4, in.InPos); + OutWorldPos[3] = spvFMulVectorMatrix(in.InPos, _22.wMatrix4x3); + out.OutNormal = spvFMulMatrixVector(_22.wMatrix, float4(in.InNormal, 0.0)).xyz; + out.OutWorldPos_0 = OutWorldPos[0]; + out.OutWorldPos_1 = OutWorldPos[1]; + out.OutWorldPos_2 = OutWorldPos[2]; + out.OutWorldPos_3 = OutWorldPos[3]; + return out; +} + diff --git a/third_party/spirv-cross/reference/shaders-msl/vert/float-math.vert b/third_party/spirv-cross/reference/shaders-msl/vert/float-math.vert new file mode 100644 index 0000000000..e96fdaedc2 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-msl/vert/float-math.vert @@ -0,0 +1,87 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + +#include +#include + +using namespace metal; + +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +struct Matrices +{ + float4x4 vpMatrix; + float4x4 wMatrix; + float4x3 wMatrix4x3; + float3x4 wMatrix3x4; +}; + +struct main0_out +{ + float3 OutNormal [[user(locn0)]]; + float4 OutWorldPos_0 [[user(locn1)]]; + float4 OutWorldPos_1 [[user(locn2)]]; + float4 OutWorldPos_2 [[user(locn3)]]; + float4 OutWorldPos_3 [[user(locn4)]]; + float4 gl_Position [[position]]; +}; + +struct main0_in +{ + float3 InPos [[attribute(0)]]; + float3 InNormal [[attribute(1)]]; +}; + +vertex main0_out main0(main0_in in [[stage_in]], constant Matrices& _22 [[buffer(0)]]) +{ + main0_out out = {}; + spvUnsafeArray OutWorldPos = {}; + out.gl_Position = (_22.vpMatrix * _22.wMatrix) * float4(in.InPos, 1.0); + OutWorldPos[0] = _22.wMatrix * float4(in.InPos, 1.0); + OutWorldPos[1] = float4(in.InPos, 1.0) * _22.wMatrix; + OutWorldPos[2] = _22.wMatrix3x4 * in.InPos; + OutWorldPos[3] = in.InPos * _22.wMatrix4x3; + out.OutNormal = (_22.wMatrix * float4(in.InNormal, 0.0)).xyz; + out.OutWorldPos_0 = OutWorldPos[0]; + out.OutWorldPos_1 = OutWorldPos[1]; + out.OutWorldPos_2 = OutWorldPos[2]; + out.OutWorldPos_3 = OutWorldPos[3]; + return out; +} + diff --git a/third_party/spirv-cross/reference/shaders-msl/vert/functions.vert b/third_party/spirv-cross/reference/shaders-msl/vert/functions.vert index 9af0f3f356..73eaa8b751 100644 --- a/third_party/spirv-cross/reference/shaders-msl/vert/functions.vert +++ b/third_party/spirv-cross/reference/shaders-msl/vert/functions.vert @@ -31,47 +31,50 @@ struct main0_in // Implementation of the GLSL radians() function template -T radians(T d) +inline T radians(T d) { return d * T(0.01745329251); } // Implementation of the GLSL degrees() function template -T degrees(T r) +inline T degrees(T r) { return r * T(57.2957795131); } // Implementation of the GLSL findLSB() function template -T spvFindLSB(T x) +inline T spvFindLSB(T x) { return select(ctz(x), T(-1), x == T(0)); } // Implementation of the signed GLSL findMSB() function template -T spvFindSMSB(T x) +inline T spvFindSMSB(T x) { T v = select(x, T(-1) - x, x < T(0)); return select(clz(T(0)) - (clz(v) + T(1)), T(-1), v == T(0)); } // Returns the determinant of a 2x2 matrix. -inline float spvDet2x2(float a1, float a2, float b1, float b2) +static inline __attribute__((always_inline)) +float spvDet2x2(float a1, float a2, float b1, float b2) { return a1 * b2 - b1 * a2; } // Returns the determinant of a 3x3 matrix. -inline float spvDet3x3(float a1, float a2, float a3, float b1, float b2, float b3, float c1, float c2, float c3) +static inline __attribute__((always_inline)) +float spvDet3x3(float a1, float a2, float a3, float b1, float b2, float b3, float c1, float c2, float c3) { return a1 * spvDet2x2(b2, b3, c2, c3) - b1 * spvDet2x2(a2, a3, c2, c3) + c1 * spvDet2x2(a2, a3, b2, b3); } // Returns the inverse of a matrix, by using the algorithm of calculating the classical // adjoint and dividing by the determinant. The contents of the matrix are changed. +static inline __attribute__((always_inline)) float4x4 spvInverse4x4(float4x4 m) { float4x4 adj; // The adjoint matrix (inverse after dividing by determinant) diff --git a/third_party/spirv-cross/reference/shaders-msl/vert/in_out_array_mat.vert b/third_party/spirv-cross/reference/shaders-msl/vert/in_out_array_mat.vert index 95be574a51..4fd1365edc 100644 --- a/third_party/spirv-cross/reference/shaders-msl/vert/in_out_array_mat.vert +++ b/third_party/spirv-cross/reference/shaders-msl/vert/in_out_array_mat.vert @@ -1,10 +1,49 @@ #pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" #include #include using namespace metal; +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + struct UBO { float4x4 projection; @@ -38,13 +77,15 @@ struct main0_in float4 inViewMat_3 [[attribute(8)]]; }; -void write_deeper_in_function(thread float4x4& outTransModel, constant UBO& ubo, thread float4& color, thread float4 (&colors)[3]) +static inline __attribute__((always_inline)) +void write_deeper_in_function(thread float4x4& outTransModel, constant UBO& ubo, thread float4& color, thread spvUnsafeArray (&colors)) { outTransModel[1].y = ubo.lodBias; color = colors[2]; } -void write_in_function(thread float4x4& outTransModel, constant UBO& ubo, thread float4& color, thread float4 (&colors)[3], thread float3& inNormal) +static inline __attribute__((always_inline)) +void write_in_function(thread float4x4& outTransModel, constant UBO& ubo, thread float4& color, thread spvUnsafeArray (&colors), thread float3& inNormal) { outTransModel[2] = float4(inNormal, 1.0); write_deeper_in_function(outTransModel, ubo, color, colors); @@ -54,7 +95,7 @@ vertex main0_out main0(main0_in in [[stage_in]], constant UBO& ubo [[buffer(0)]] { main0_out out = {}; float4x4 outTransModel = {}; - float4 colors[3] = {}; + spvUnsafeArray colors = {}; float4x4 inViewMat = {}; colors[0] = in.colors_0; colors[1] = in.colors_1; diff --git a/third_party/spirv-cross/reference/shaders-msl/vert/interface-block-block-composites.frag b/third_party/spirv-cross/reference/shaders-msl/vert/interface-block-block-composites.frag index c42381d004..c160ade2dd 100644 --- a/third_party/spirv-cross/reference/shaders-msl/vert/interface-block-block-composites.frag +++ b/third_party/spirv-cross/reference/shaders-msl/vert/interface-block-block-composites.frag @@ -1,13 +1,54 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + #include #include using namespace metal; +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + struct Vert { float3x3 wMatrix; float4 wTmp; - float arr[4]; + spvUnsafeArray arr; }; struct main0_out diff --git a/third_party/spirv-cross/reference/shaders-msl/vert/interface-block-block-composites.vert b/third_party/spirv-cross/reference/shaders-msl/vert/interface-block-block-composites.vert index 3d97ae6dcf..69f271a83c 100644 --- a/third_party/spirv-cross/reference/shaders-msl/vert/interface-block-block-composites.vert +++ b/third_party/spirv-cross/reference/shaders-msl/vert/interface-block-block-composites.vert @@ -1,11 +1,52 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + #include #include using namespace metal; +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + struct Vert { - float arr[3]; + spvUnsafeArray arr; float3x3 wMatrix; float4 wTmp; }; diff --git a/third_party/spirv-cross/reference/shaders-msl/vert/leaf-function.capture.vert b/third_party/spirv-cross/reference/shaders-msl/vert/leaf-function.capture.vert index 5a8469d1ac..6519e56b8f 100644 --- a/third_party/spirv-cross/reference/shaders-msl/vert/leaf-function.capture.vert +++ b/third_party/spirv-cross/reference/shaders-msl/vert/leaf-function.capture.vert @@ -22,6 +22,7 @@ struct main0_in float3 aNormal [[attribute(1)]]; }; +static inline __attribute__((always_inline)) void set_output(device float4& gl_Position, constant UBO& v_18, thread float4& aVertex, device float3& vNormal, thread float3& aNormal) { gl_Position = v_18.uMVP * aVertex; diff --git a/third_party/spirv-cross/reference/shaders-msl/vert/no_stage_out.vert b/third_party/spirv-cross/reference/shaders-msl/vert/no_stage_out.vert index 28098ee88e..30613cc4b8 100644 --- a/third_party/spirv-cross/reference/shaders-msl/vert/no_stage_out.vert +++ b/third_party/spirv-cross/reference/shaders-msl/vert/no_stage_out.vert @@ -15,6 +15,6 @@ struct main0_in vertex void main0(main0_in in [[stage_in]], device _10& _12 [[buffer(0)]], uint gl_VertexIndex [[vertex_id]]) { - _12._m0[gl_VertexIndex] = in.m_19; + _12._m0[int(gl_VertexIndex)] = in.m_19; } diff --git a/third_party/spirv-cross/reference/shaders-msl/vert/packed_matrix.vert b/third_party/spirv-cross/reference/shaders-msl/vert/packed_matrix.vert index f54519b3a3..9d901d5bc6 100644 --- a/third_party/spirv-cross/reference/shaders-msl/vert/packed_matrix.vert +++ b/third_party/spirv-cross/reference/shaders-msl/vert/packed_matrix.vert @@ -40,11 +40,11 @@ vertex main0_out main0(main0_in in [[stage_in]], constant _15& _17 [[buffer(0)]] main0_out out = {}; float3 _91; float3 _13; - do + for (;;) { _13 = normalize(float4(in.m_25.xyz, 0.0) * _17._m1); break; - } while (false); + } float4 _39 = _44._m0 * float4(float3(_44._m3) + (in.m_25.xyz * (_44._m6 + _44._m7)), 1.0); out.m_72 = _13; float4 _74 = _39; diff --git a/third_party/spirv-cross/reference/shaders-msl/vert/read-from-row-major-array.vert b/third_party/spirv-cross/reference/shaders-msl/vert/read-from-row-major-array.vert index 2d322a69df..d6ade7c38b 100644 --- a/third_party/spirv-cross/reference/shaders-msl/vert/read-from-row-major-array.vert +++ b/third_party/spirv-cross/reference/shaders-msl/vert/read-from-row-major-array.vert @@ -21,11 +21,13 @@ struct main0_in float4 a_position [[attribute(0)]]; }; +static inline __attribute__((always_inline)) float compare_float(thread const float& a, thread const float& b) { return float(abs(a - b) < 0.0500000007450580596923828125); } +static inline __attribute__((always_inline)) float compare_vec3(thread const float3& a, thread const float3& b) { float param = a.x; @@ -37,6 +39,7 @@ float compare_vec3(thread const float3& a, thread const float3& b) return (compare_float(param, param_1) * compare_float(param_2, param_3)) * compare_float(param_4, param_5); } +static inline __attribute__((always_inline)) float compare_mat2x3(thread const float2x3& a, thread const float2x3& b) { float3 param = a[0]; diff --git a/third_party/spirv-cross/reference/shaders-msl/vert/resource-arrays-leaf.ios.vert b/third_party/spirv-cross/reference/shaders-msl/vert/resource-arrays-leaf.ios.vert index 97e97e6fd2..8ab252f535 100644 --- a/third_party/spirv-cross/reference/shaders-msl/vert/resource-arrays-leaf.ios.vert +++ b/third_party/spirv-cross/reference/shaders-msl/vert/resource-arrays-leaf.ios.vert @@ -22,6 +22,7 @@ struct constant_block #endif constant int arraySize = SPIRV_CROSS_CONSTANT_ID_0; +static inline __attribute__((always_inline)) void doWork(device storage_block* (&storage)[2], constant constant_block* (&constants)[4], thread const array, 3> images) { storage[0]->baz = uint4(constants[3]->foo); diff --git a/third_party/spirv-cross/reference/shaders-msl/vert/return-array.force-native-array.vert b/third_party/spirv-cross/reference/shaders-msl/vert/return-array.force-native-array.vert new file mode 100644 index 0000000000..32388cb472 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-msl/vert/return-array.force-native-array.vert @@ -0,0 +1,100 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" + +#include +#include + +using namespace metal; + +constant float4 _20[2] = { float4(10.0), float4(20.0) }; + +struct main0_out +{ + float4 gl_Position [[position]]; +}; + +struct main0_in +{ + float4 vInput0 [[attribute(0)]]; + float4 vInput1 [[attribute(1)]]; +}; + +template +inline void spvArrayCopyFromConstantToStack1(thread T (&dst)[A], constant T (&src)[A]) +{ + for (uint i = 0; i < A; i++) + { + dst[i] = src[i]; + } +} + +template +inline void spvArrayCopyFromConstantToThreadGroup1(threadgroup T (&dst)[A], constant T (&src)[A]) +{ + for (uint i = 0; i < A; i++) + { + dst[i] = src[i]; + } +} + +template +inline void spvArrayCopyFromStackToStack1(thread T (&dst)[A], thread const T (&src)[A]) +{ + for (uint i = 0; i < A; i++) + { + dst[i] = src[i]; + } +} + +template +inline void spvArrayCopyFromStackToThreadGroup1(threadgroup T (&dst)[A], thread const T (&src)[A]) +{ + for (uint i = 0; i < A; i++) + { + dst[i] = src[i]; + } +} + +template +inline void spvArrayCopyFromThreadGroupToStack1(thread T (&dst)[A], threadgroup const T (&src)[A]) +{ + for (uint i = 0; i < A; i++) + { + dst[i] = src[i]; + } +} + +template +inline void spvArrayCopyFromThreadGroupToThreadGroup1(threadgroup T (&dst)[A], threadgroup const T (&src)[A]) +{ + for (uint i = 0; i < A; i++) + { + dst[i] = src[i]; + } +} + +static inline __attribute__((always_inline)) +void test(thread float4 (&SPIRV_Cross_return_value)[2]) +{ + spvArrayCopyFromConstantToStack1(SPIRV_Cross_return_value, _20); +} + +static inline __attribute__((always_inline)) +void test2(thread float4 (&SPIRV_Cross_return_value)[2], thread float4& vInput0, thread float4& vInput1) +{ + float4 foobar[2]; + foobar[0] = vInput0; + foobar[1] = vInput1; + spvArrayCopyFromStackToStack1(SPIRV_Cross_return_value, foobar); +} + +vertex main0_out main0(main0_in in [[stage_in]]) +{ + main0_out out = {}; + float4 _42[2]; + test(_42); + float4 _44[2]; + test2(_44, in.vInput0, in.vInput1); + out.gl_Position = _42[0] + _44[1]; + return out; +} + diff --git a/third_party/spirv-cross/reference/shaders-msl/vert/return-array.vert b/third_party/spirv-cross/reference/shaders-msl/vert/return-array.vert index cd06fddaa8..dacb0ba305 100644 --- a/third_party/spirv-cross/reference/shaders-msl/vert/return-array.vert +++ b/third_party/spirv-cross/reference/shaders-msl/vert/return-array.vert @@ -1,11 +1,50 @@ #pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" #include #include using namespace metal; -constant float4 _20[2] = { float4(10.0), float4(20.0) }; +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +constant spvUnsafeArray _20 = spvUnsafeArray({ float4(10.0), float4(20.0) }); struct main0_out { @@ -18,40 +57,25 @@ struct main0_in float4 vInput1 [[attribute(1)]]; }; -// Implementation of an array copy function to cover GLSL's ability to copy an array via assignment. -template -void spvArrayCopyFromStack1(thread T (&dst)[N], thread const T (&src)[N]) +static inline __attribute__((always_inline)) +spvUnsafeArray test() { - for (uint i = 0; i < N; dst[i] = src[i], i++); + return _20; } -template -void spvArrayCopyFromConstant1(thread T (&dst)[N], constant T (&src)[N]) +static inline __attribute__((always_inline)) +spvUnsafeArray test2(thread float4& vInput0, thread float4& vInput1) { - for (uint i = 0; i < N; dst[i] = src[i], i++); -} - -void test(thread float4 (&SPIRV_Cross_return_value)[2]) -{ - spvArrayCopyFromConstant1(SPIRV_Cross_return_value, _20); -} - -void test2(thread float4 (&SPIRV_Cross_return_value)[2], thread float4& vInput0, thread float4& vInput1) -{ - float4 foobar[2]; + spvUnsafeArray foobar; foobar[0] = vInput0; foobar[1] = vInput1; - spvArrayCopyFromStack1(SPIRV_Cross_return_value, foobar); + return foobar; } vertex main0_out main0(main0_in in [[stage_in]]) { main0_out out = {}; - float4 _42[2]; - test(_42); - float4 _44[2]; - test2(_44, in.vInput0, in.vInput1); - out.gl_Position = _42[0] + _44[1]; + out.gl_Position = test()[0] + test2(in.vInput0, in.vInput1)[1]; return out; } diff --git a/third_party/spirv-cross/reference/shaders-msl/vert/set_builtin_in_func.vert b/third_party/spirv-cross/reference/shaders-msl/vert/set_builtin_in_func.vert index 2952748dc0..91057da2ba 100644 --- a/third_party/spirv-cross/reference/shaders-msl/vert/set_builtin_in_func.vert +++ b/third_party/spirv-cross/reference/shaders-msl/vert/set_builtin_in_func.vert @@ -11,6 +11,7 @@ struct main0_out float gl_PointSize [[point_size]]; }; +static inline __attribute__((always_inline)) void write_outblock(thread float4& gl_Position, thread float& gl_PointSize) { gl_PointSize = 1.0; diff --git a/third_party/spirv-cross/reference/shaders-msl/vert/sign-int-types.vert b/third_party/spirv-cross/reference/shaders-msl/vert/sign-int-types.vert index 2f518b1291..a510645223 100644 --- a/third_party/spirv-cross/reference/shaders-msl/vert/sign-int-types.vert +++ b/third_party/spirv-cross/reference/shaders-msl/vert/sign-int-types.vert @@ -38,7 +38,7 @@ struct main0_in // Implementation of the GLSL sign() function for integer types template::value>::type> -T sign(T x) +inline T sign(T x) { return select(select(select(x, T(0), x == T(0)), T(1), x > T(0)), T(-1), x < T(0)); } diff --git a/third_party/spirv-cross/reference/shaders-msl/vert/texture_buffer.vert b/third_party/spirv-cross/reference/shaders-msl/vert/texture_buffer.vert index ee3956fad8..3b3d92b565 100644 --- a/third_party/spirv-cross/reference/shaders-msl/vert/texture_buffer.vert +++ b/third_party/spirv-cross/reference/shaders-msl/vert/texture_buffer.vert @@ -11,6 +11,7 @@ struct main0_out }; // Returns 2D texture coords corresponding to 1D texel buffer coords +static inline __attribute__((always_inline)) uint2 spvTexelBufferCoord(uint tc) { return uint2(tc % 4096, tc / 4096); diff --git a/third_party/spirv-cross/reference/shaders-msl/vulkan/comp/struct-packing-scalar.nocompat.invalid.vk.comp b/third_party/spirv-cross/reference/shaders-msl/vulkan/comp/struct-packing-scalar.nocompat.invalid.vk.comp deleted file mode 100644 index 2f731356f5..0000000000 --- a/third_party/spirv-cross/reference/shaders-msl/vulkan/comp/struct-packing-scalar.nocompat.invalid.vk.comp +++ /dev/null @@ -1,148 +0,0 @@ -#include -#include - -using namespace metal; - -typedef packed_float2 packed_float2x2[2]; -typedef packed_float3 packed_float2x3[2]; -typedef packed_float3 packed_rm_float3x2[2]; - -struct S0 -{ - packed_float2 a[1]; - float b; -}; - -struct S1 -{ - packed_float3 a; - float b; -}; - -struct S2 -{ - packed_float3 a[1]; - float b; -}; - -struct S3 -{ - packed_float2 a; - float b; -}; - -struct Content -{ - S0 m0s[1]; - S1 m1s[1]; - S2 m2s[1]; - S0 m0; - S1 m1; - S2 m2; - S3 m3; - float m4; -}; - -struct SSBO1 -{ - Content content; - Content content1[2]; - Content content2; - float2x2 m0; - float2x2 m1; - packed_float2x3 m2[4]; - float3x2 m3; - float2x2 m4; - float2x2 m5[9]; - float3x2 m6[4][2]; - packed_rm_float3x2 m7; - float array[1]; -}; - -struct S0_1 -{ - float4 a[1]; - float b; - char _m0_final_padding[12]; -}; - -struct S1_1 -{ - packed_float3 a; - float b; -}; - -struct S2_1 -{ - float3 a[1]; - float b; - char _m0_final_padding[12]; -}; - -struct S3_1 -{ - float2 a; - float b; -}; - -struct Content_1 -{ - S0_1 m0s[1]; - S1_1 m1s[1]; - S2_1 m2s[1]; - S0_1 m0; - S1_1 m1; - S2_1 m2; - S3_1 m3; - float m4; - char _m0_final_padding[12]; -}; - -struct SSBO0 -{ - Content_1 content; - Content_1 content1[2]; - Content_1 content2; - float2x4 m0; - float2x4 m1; - float2x3 m2[4]; - float3x4 m3; - float2x4 m4; - float2x4 m5[9]; - float3x4 m6[4][2]; - float2x3 m7; - float4 array[1]; -}; - -struct SSBO2 -{ - float m0; - packed_float2x2 m1; - packed_rm_float3x2 m2; -}; - -kernel void main0(device SSBO1& ssbo_scalar [[buffer(0)]], device SSBO0& ssbo_140 [[buffer(1)]], device SSBO2& ssbo_scalar2 [[buffer(2)]]) -{ - ssbo_scalar.content.m0s[0].a[0] = ssbo_140.content.m0s[0].a[0].xy; - ssbo_scalar.content.m0s[0].b = ssbo_140.content.m0s[0].b; - ssbo_scalar.content.m1s[0].a = float3(ssbo_140.content.m1s[0].a); - ssbo_scalar.content.m1s[0].b = ssbo_140.content.m1s[0].b; - ssbo_scalar.content.m2s[0].a[0] = ssbo_140.content.m2s[0].a[0]; - ssbo_scalar.content.m2s[0].b = ssbo_140.content.m2s[0].b; - ssbo_scalar.content.m0.a[0] = ssbo_140.content.m0.a[0].xy; - ssbo_scalar.content.m0.b = ssbo_140.content.m0.b; - ssbo_scalar.content.m1.a = float3(ssbo_140.content.m1.a); - ssbo_scalar.content.m1.b = ssbo_140.content.m1.b; - ssbo_scalar.content.m2.a[0] = ssbo_140.content.m2.a[0]; - ssbo_scalar.content.m2.b = ssbo_140.content.m2.b; - ssbo_scalar.content.m3.a = ssbo_140.content.m3.a; - ssbo_scalar.content.m3.b = ssbo_140.content.m3.b; - ssbo_scalar.content.m4 = ssbo_140.content.m4; - ssbo_scalar.content.m1.a = float2x3(float3(ssbo_scalar.m2[1][0]), float3(ssbo_scalar.m2[1][1])) * float2(ssbo_scalar.content.m0.a[0]); - ssbo_scalar.m0 = float2x2(float2(ssbo_scalar2.m1[0]), float2(ssbo_scalar2.m1[1])); - ssbo_scalar2.m1[0] = float2(ssbo_scalar.m4[0][0], ssbo_scalar.m4[1][0]); - ssbo_scalar2.m1[1] = float2(ssbo_scalar.m4[0][1], ssbo_scalar.m4[1][1]); - ssbo_scalar2.m2[0] = float3(ssbo_scalar.m3[0][0], ssbo_scalar.m3[1][0], ssbo_scalar.m3[2][0]); - ssbo_scalar2.m2[1] = float3(ssbo_scalar.m3[0][1], ssbo_scalar.m3[1][1], ssbo_scalar.m3[2][1]); -} - diff --git a/third_party/spirv-cross/reference/shaders-msl/vulkan/frag/basic.multiview.nocompat.vk.frag b/third_party/spirv-cross/reference/shaders-msl/vulkan/frag/basic.multiview.nocompat.vk.frag index 23c554940b..67895e3e92 100644 --- a/third_party/spirv-cross/reference/shaders-msl/vulkan/frag/basic.multiview.nocompat.vk.frag +++ b/third_party/spirv-cross/reference/shaders-msl/vulkan/frag/basic.multiview.nocompat.vk.frag @@ -1,8 +1,49 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + #include #include using namespace metal; +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + struct main0_out { float4 FragColor [[color(0)]]; @@ -20,7 +61,7 @@ struct main0_in fragment main0_out main0(main0_in in [[stage_in]], constant uint* spvViewMask [[buffer(24)]], texture2d uTex [[texture(0)]], sampler uTexSmplr [[sampler(0)]], uint gl_ViewIndex [[render_target_array_index]]) { main0_out out = {}; - float2 vTex[4] = {}; + spvUnsafeArray vTex = {}; vTex[0] = in.vTex_0; vTex[1] = in.vTex_1; vTex[2] = in.vTex_2; diff --git a/third_party/spirv-cross/reference/shaders-msl/vulkan/frag/scalar-block-layout-ubo-std430.vk.nocompat.invalid.frag b/third_party/spirv-cross/reference/shaders-msl/vulkan/frag/scalar-block-layout-ubo-std430.vk.nocompat.invalid.frag deleted file mode 100644 index ec25d06787..0000000000 --- a/third_party/spirv-cross/reference/shaders-msl/vulkan/frag/scalar-block-layout-ubo-std430.vk.nocompat.invalid.frag +++ /dev/null @@ -1,36 +0,0 @@ -#include -#include - -using namespace metal; - -struct UBO -{ - float a[1]; - float2 b[2]; -}; - -struct UBOEnhancedLayout -{ - float c[1]; - float2 d[2]; - char _m2_pad[9976]; - float e; -}; - -struct main0_out -{ - float FragColor [[color(0)]]; -}; - -struct main0_in -{ - int vIndex [[user(locn0)]]; -}; - -fragment main0_out main0(main0_in in [[stage_in]], constant UBO& _17 [[buffer(0)]], constant UBOEnhancedLayout& _30 [[buffer(1)]]) -{ - main0_out out = {}; - out.FragColor = (_17.a[in.vIndex] + _30.c[in.vIndex]) + _30.e; - return out; -} - diff --git a/third_party/spirv-cross/reference/shaders-msl/vulkan/vert/vulkan-vertex.vk.vert b/third_party/spirv-cross/reference/shaders-msl/vulkan/vert/vulkan-vertex.vk.vert index 53e26e4a8e..86a0cea5bb 100644 --- a/third_party/spirv-cross/reference/shaders-msl/vulkan/vert/vulkan-vertex.vk.vert +++ b/third_party/spirv-cross/reference/shaders-msl/vulkan/vert/vulkan-vertex.vk.vert @@ -11,7 +11,7 @@ struct main0_out vertex main0_out main0(uint gl_VertexIndex [[vertex_id]], uint gl_InstanceIndex [[instance_id]]) { main0_out out = {}; - out.gl_Position = float4(1.0, 2.0, 3.0, 4.0) * float(gl_VertexIndex + gl_InstanceIndex); + out.gl_Position = float4(1.0, 2.0, 3.0, 4.0) * float(int(gl_VertexIndex) + int(gl_InstanceIndex)); return out; } diff --git a/third_party/spirv-cross/reference/shaders-no-opt/asm/comp/access-tracking-function-call-result.asm.comp b/third_party/spirv-cross/reference/shaders-no-opt/asm/comp/access-tracking-function-call-result.asm.comp new file mode 100644 index 0000000000..e4dfdb87a8 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-no-opt/asm/comp/access-tracking-function-call-result.asm.comp @@ -0,0 +1,24 @@ +#version 460 +layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in; + +layout(binding = 0, std430) buffer Output +{ + int myout; +} _5; + +int foo() +{ + return 12; +} + +void main() +{ + int _17 = foo(); + while (true) + { + _5.myout = _17; + return; + } + _5.myout = _17; +} + diff --git a/third_party/spirv-cross/reference/shaders-no-opt/asm/comp/aliased-struct-divergent-member-name.asm.comp b/third_party/spirv-cross/reference/shaders-no-opt/asm/comp/aliased-struct-divergent-member-name.asm.comp new file mode 100644 index 0000000000..2d32b401a5 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-no-opt/asm/comp/aliased-struct-divergent-member-name.asm.comp @@ -0,0 +1,30 @@ +#version 450 +layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in; + +struct T +{ + float c; +}; + +struct T_1 +{ + float b; +}; + +layout(binding = 0, std430) buffer SSBO1 +{ + T_1 foo[]; +} _7; + +layout(binding = 1, std140) buffer SSBO2 +{ + T bar[]; +} _10; + +void main() +{ + T v = T(40.0); + _7.foo[10].b = v.c; + _10.bar[30].c = v.c; +} + diff --git a/third_party/spirv-cross/reference/shaders-no-opt/asm/comp/arithmetic-conversion-signs.asm.nocompat.vk.comp.vk b/third_party/spirv-cross/reference/shaders-no-opt/asm/comp/arithmetic-conversion-signs.asm.nocompat.vk.comp.vk index c2fb39907b..5f480728e4 100644 --- a/third_party/spirv-cross/reference/shaders-no-opt/asm/comp/arithmetic-conversion-signs.asm.nocompat.vk.comp.vk +++ b/third_party/spirv-cross/reference/shaders-no-opt/asm/comp/arithmetic-conversion-signs.asm.nocompat.vk.comp.vk @@ -33,8 +33,12 @@ void main() _4.u16 = uint16_t(_30); _4.f32 = float(_31); _4.f32 = float(int16_t(_32)); + _4.f32 = float(_29); + _4.f32 = float(int(_30)); _4.f32 = float(uint16_t(_31)); _4.f32 = float(_32); + _4.f32 = float(uint(_29)); + _4.f32 = float(_30); _4.s16 = int16_t(_33); _4.u16 = uint16_t(int16_t(_33)); _4.u16 = uint16_t(_33); diff --git a/third_party/spirv-cross/reference/shaders-no-opt/asm/comp/bitfield-signed-operations.asm.comp b/third_party/spirv-cross/reference/shaders-no-opt/asm/comp/bitfield-signed-operations.asm.comp new file mode 100644 index 0000000000..f535ba7f49 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-no-opt/asm/comp/bitfield-signed-operations.asm.comp @@ -0,0 +1,27 @@ +#version 450 +layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in; + +layout(binding = 0, std430) buffer SSBO +{ + ivec4 ints; + uvec4 uints; +} _3; + +void main() +{ + ivec4 _19 = _3.ints; + uvec4 _20 = _3.uints; + _3.ints = bitCount(_19); + _3.uints = uvec4(bitCount(_19)); + _3.ints = bitCount(_20); + _3.uints = uvec4(bitCount(_20)); + _3.ints = bitfieldReverse(_19); + _3.uints = bitfieldReverse(_20); + _3.ints = bitfieldExtract(_19, 1, int(11u)); + _3.uints = uvec4(bitfieldExtract(ivec4(_20), int(11u), 1)); + _3.ints = ivec4(bitfieldExtract(uvec4(_19), 1, int(11u))); + _3.uints = bitfieldExtract(_20, int(11u), 1); + _3.ints = bitfieldInsert(_19, _19.wzyx, 1, int(11u)); + _3.uints = bitfieldInsert(_20, _20.wzyx, int(11u), 1); +} + diff --git a/third_party/spirv-cross/reference/shaders-no-opt/asm/comp/copy-logical.spv14.asm.comp b/third_party/spirv-cross/reference/shaders-no-opt/asm/comp/copy-logical.spv14.asm.comp new file mode 100644 index 0000000000..28b2d1d0e9 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-no-opt/asm/comp/copy-logical.spv14.asm.comp @@ -0,0 +1,45 @@ +#version 450 +layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in; + +struct B2 +{ + vec4 elem2; +}; + +struct C +{ + vec4 c; + B2 b2; + B2 b2_array[4]; +}; + +struct B1 +{ + vec4 elem1; +}; + +struct A +{ + vec4 a; + B1 b1; + B1 b1_array[4]; +}; + +layout(binding = 0, std430) buffer _8_3 +{ + A a_block; + C c_block; +} _3; + +void main() +{ + A _27; + _27.a = _3.c_block.c; + _27.b1.elem1 = _3.c_block.b2.elem2; + _27.b1_array[0].elem1 = _3.c_block.b2_array[0].elem2; + _27.b1_array[1].elem1 = _3.c_block.b2_array[1].elem2; + _27.b1_array[2].elem1 = _3.c_block.b2_array[2].elem2; + _27.b1_array[3].elem1 = _3.c_block.b2_array[3].elem2; + _3.a_block = _27; +} + diff --git a/third_party/spirv-cross/reference/opt/shaders/asm/extended-debug-extinst.invalid.asm.comp b/third_party/spirv-cross/reference/shaders-no-opt/asm/comp/extended-debug-extinst.invalid.asm.comp similarity index 100% rename from third_party/spirv-cross/reference/opt/shaders/asm/extended-debug-extinst.invalid.asm.comp rename to third_party/spirv-cross/reference/shaders-no-opt/asm/comp/extended-debug-extinst.invalid.asm.comp diff --git a/third_party/spirv-cross/reference/opt/shaders/asm/comp/phi-temporary-copy-loop-variable.asm.comp b/third_party/spirv-cross/reference/shaders-no-opt/asm/comp/phi-temporary-copy-loop-variable.asm.invalid.comp similarity index 86% rename from third_party/spirv-cross/reference/opt/shaders/asm/comp/phi-temporary-copy-loop-variable.asm.comp rename to third_party/spirv-cross/reference/shaders-no-opt/asm/comp/phi-temporary-copy-loop-variable.asm.invalid.comp index 9ae8d6fd7f..f8650b5e5c 100644 --- a/third_party/spirv-cross/reference/opt/shaders/asm/comp/phi-temporary-copy-loop-variable.asm.comp +++ b/third_party/spirv-cross/reference/shaders-no-opt/asm/comp/phi-temporary-copy-loop-variable.asm.invalid.comp @@ -5,20 +5,15 @@ layout(binding = 1, rgba32f) uniform writeonly image2D outImageTexture; void main() { + int _27_copy; int _30; _30 = 7; - int _27_copy; for (int _27 = 7; _27 >= 0; _27_copy = _27, _27--, _30 = _27_copy) { if (5.0 > float(_27)) { break; } - else - { - continue; - } - continue; } imageStore(outImageTexture, ivec2(gl_GlobalInvocationID.xy), vec4(float(_30 - 1), float(_30), 1.0, 1.0)); } diff --git a/third_party/spirv-cross/reference/opt/shaders/asm/comp/storage-buffer-basic.invalid.asm.comp b/third_party/spirv-cross/reference/shaders-no-opt/asm/comp/storage-buffer-basic.invalid.asm.comp similarity index 100% rename from third_party/spirv-cross/reference/opt/shaders/asm/comp/storage-buffer-basic.invalid.asm.comp rename to third_party/spirv-cross/reference/shaders-no-opt/asm/comp/storage-buffer-basic.invalid.asm.comp diff --git a/third_party/spirv-cross/reference/shaders-no-opt/asm/frag/combined-image-sampler-dxc-min16float.asm.invalid.frag b/third_party/spirv-cross/reference/shaders-no-opt/asm/frag/combined-image-sampler-dxc-min16float.asm.invalid.frag new file mode 100644 index 0000000000..5fa822b39f --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-no-opt/asm/frag/combined-image-sampler-dxc-min16float.asm.invalid.frag @@ -0,0 +1,28 @@ +#version 310 es +precision mediump float; +precision highp int; + +struct PSInput +{ + highp vec4 color; + highp vec2 uv; +}; + +uniform mediump sampler2D SPIRV_Cross_CombinedtexSamp; + +layout(location = 0) in highp vec4 in_var_COLOR; +layout(location = 1) in highp vec2 in_var_TEXCOORD0; +layout(location = 0) out highp vec4 out_var_SV_TARGET; + +highp vec4 src_PSMain(PSInput _input) +{ + vec4 a = _input.color * texture(SPIRV_Cross_CombinedtexSamp, _input.uv); + return a; +} + +void main() +{ + PSInput param_var_input = PSInput(in_var_COLOR, in_var_TEXCOORD0); + out_var_SV_TARGET = src_PSMain(param_var_input); +} + diff --git a/third_party/spirv-cross/reference/shaders-no-opt/asm/frag/demote-impure-function-call.vk.nocompat.asm.frag.vk b/third_party/spirv-cross/reference/shaders-no-opt/asm/frag/demote-impure-function-call.vk.nocompat.asm.frag.vk new file mode 100644 index 0000000000..adde5fcbf4 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-no-opt/asm/frag/demote-impure-function-call.vk.nocompat.asm.frag.vk @@ -0,0 +1,22 @@ +#version 450 +#extension GL_EXT_demote_to_helper_invocation : require + +layout(location = 0) flat in int vA; +layout(location = 0) out vec4 FragColor; + +vec4 foobar(int a) +{ + if (a < 0) + { + demote; + } + return vec4(10.0); +} + +void main() +{ + int param = vA; + vec4 _25 = foobar(param); + FragColor = vec4(10.0); +} + diff --git a/third_party/spirv-cross/reference/shaders-no-opt/asm/frag/discard-impure-function-call.asm.frag b/third_party/spirv-cross/reference/shaders-no-opt/asm/frag/discard-impure-function-call.asm.frag new file mode 100644 index 0000000000..0fe71f64b4 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-no-opt/asm/frag/discard-impure-function-call.asm.frag @@ -0,0 +1,21 @@ +#version 450 + +layout(location = 0) flat in int vA; +layout(location = 0) out vec4 FragColor; + +vec4 foobar(int a) +{ + if (a < 0) + { + discard; + } + return vec4(10.0); +} + +void main() +{ + int param = vA; + vec4 _25 = foobar(param); + FragColor = vec4(10.0); +} + diff --git a/third_party/spirv-cross/reference/shaders-no-opt/asm/frag/do-while-continue-phi.asm.invalid.frag b/third_party/spirv-cross/reference/shaders-no-opt/asm/frag/do-while-continue-phi.asm.invalid.frag new file mode 100644 index 0000000000..2024c302ef --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-no-opt/asm/frag/do-while-continue-phi.asm.invalid.frag @@ -0,0 +1,37 @@ +#version 310 es +precision mediump float; +precision highp int; + +layout(location = 0) out highp vec4 _GLF_color; + +void main() +{ + for (;;) + { + bool _32; + for (;;) + { + if (gl_FragCoord.x != gl_FragCoord.x) + { + _32 = true; + break; + } + if (false) + { + continue; + } + else + { + _32 = false; + break; + } + } + if (_32) + { + break; + } + _GLF_color = vec4(1.0, 0.0, 0.0, 1.0); + break; + } +} + diff --git a/third_party/spirv-cross/reference/shaders-no-opt/asm/frag/empty-struct-in-struct.asm.frag b/third_party/spirv-cross/reference/shaders-no-opt/asm/frag/empty-struct-in-struct.asm.frag new file mode 100644 index 0000000000..0d3958b5b0 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-no-opt/asm/frag/empty-struct-in-struct.asm.frag @@ -0,0 +1,31 @@ +#version 450 + +struct EmptyStructTest +{ + int empty_struct_member; +}; + +struct EmptyStruct2Test +{ + EmptyStructTest _m0; +}; + +float GetValue(EmptyStruct2Test self) +{ + return 0.0; +} + +float GetValue_1(EmptyStruct2Test self) +{ + return 0.0; +} + +void main() +{ + EmptyStructTest _25 = EmptyStructTest(0); + EmptyStruct2Test emptyStruct; + float value = GetValue(emptyStruct); + value = GetValue_1(EmptyStruct2Test(_25)); + value = GetValue_1(EmptyStruct2Test(EmptyStructTest(0))); +} + diff --git a/third_party/spirv-cross/reference/shaders-no-opt/asm/frag/for-loop-dedicated-merge-block-inverted.asm.frag b/third_party/spirv-cross/reference/shaders-no-opt/asm/frag/for-loop-dedicated-merge-block-inverted.asm.invalid.frag similarity index 100% rename from third_party/spirv-cross/reference/shaders-no-opt/asm/frag/for-loop-dedicated-merge-block-inverted.asm.frag rename to third_party/spirv-cross/reference/shaders-no-opt/asm/frag/for-loop-dedicated-merge-block-inverted.asm.invalid.frag diff --git a/third_party/spirv-cross/reference/shaders-no-opt/asm/frag/for-loop-dedicated-merge-block-non-inverted.asm.frag b/third_party/spirv-cross/reference/shaders-no-opt/asm/frag/for-loop-dedicated-merge-block-non-inverted.asm.invalid.frag similarity index 100% rename from third_party/spirv-cross/reference/shaders-no-opt/asm/frag/for-loop-dedicated-merge-block-non-inverted.asm.frag rename to third_party/spirv-cross/reference/shaders-no-opt/asm/frag/for-loop-dedicated-merge-block-non-inverted.asm.invalid.frag diff --git a/third_party/spirv-cross/reference/shaders-no-opt/asm/frag/inliner-dominator-inside-loop.asm.frag b/third_party/spirv-cross/reference/shaders-no-opt/asm/frag/inliner-dominator-inside-loop.asm.frag index 98116cfdc7..29653cbb4b 100644 --- a/third_party/spirv-cross/reference/shaders-no-opt/asm/frag/inliner-dominator-inside-loop.asm.frag +++ b/third_party/spirv-cross/reference/shaders-no-opt/asm/frag/inliner-dominator-inside-loop.asm.frag @@ -130,7 +130,7 @@ void main() vec2 _166 = IN_Uv_EdgeDistance1.xy * 1.0; bool _173; vec4 _193; - do + for (;;) { _173 = 0.0 == 0.0; if (_173) @@ -146,9 +146,9 @@ void main() } _193 = _192; break; - } while (false); + } vec4 _220; - do + for (;;) { if (_173) { @@ -163,7 +163,7 @@ void main() } _220 = _219; break; - } while (false); + } vec2 _223 = vec2(1.0); vec2 _224 = (_220.wy * 2.0) - _223; vec3 _232 = vec3(_224, sqrt(clamp(1.0 + dot(-_224, _224), 0.0, 1.0))); @@ -174,7 +174,7 @@ void main() vec3 _256 = vec3(_255.x, _255.y, _253.z); vec3 _271 = ((IN_Color.xyz * (_193 * 1.0).xyz) * (1.0 + (_256.x * 0.300000011920928955078125))) * (texture(SPIRV_Cross_CombinedStudsMapTextureStudsMapSampler, _156.UvStuds).x * 2.0); vec4 _298; - do + for (;;) { if (0.75 == 0.0) { @@ -189,7 +189,7 @@ void main() } _298 = _297; break; - } while (false); + } vec2 _303 = mix(vec2(0.800000011920928955078125, 120.0), (_298.xy * vec2(2.0, 256.0)) + vec2(0.0, 0.00999999977648258209228515625), vec2(_165)); Surface _304 = _125; _304.albedo = _271; diff --git a/third_party/spirv-cross/reference/shaders-no-opt/asm/frag/ldexp-uint-exponent.asm.frag b/third_party/spirv-cross/reference/shaders-no-opt/asm/frag/ldexp-uint-exponent.asm.frag new file mode 100644 index 0000000000..9acdd0196e --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-no-opt/asm/frag/ldexp-uint-exponent.asm.frag @@ -0,0 +1,11 @@ +#version 310 es +precision mediump float; +precision highp int; + +layout(location = 0) out highp vec4 _GLF_color; + +void main() +{ + _GLF_color = ldexp(vec4(1.0), ivec4(uvec4(bitCount(uvec4(1u))))); +} + diff --git a/third_party/spirv-cross/reference/shaders/asm/frag/loop-merge-to-continue.asm.frag b/third_party/spirv-cross/reference/shaders-no-opt/asm/frag/loop-merge-to-continue.asm.invalid.frag similarity index 100% rename from third_party/spirv-cross/reference/shaders/asm/frag/loop-merge-to-continue.asm.frag rename to third_party/spirv-cross/reference/shaders-no-opt/asm/frag/loop-merge-to-continue.asm.invalid.frag diff --git a/third_party/spirv-cross/reference/shaders-no-opt/asm/frag/pixel-interlock-callstack.asm.frag b/third_party/spirv-cross/reference/shaders-no-opt/asm/frag/pixel-interlock-callstack.asm.frag new file mode 100644 index 0000000000..948803c671 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-no-opt/asm/frag/pixel-interlock-callstack.asm.frag @@ -0,0 +1,39 @@ +#version 450 +#extension GL_ARB_fragment_shader_interlock : require +layout(pixel_interlock_ordered) in; + +layout(binding = 1, std430) buffer SSBO1 +{ + uint values1[]; +} _7; + +layout(binding = 0, std430) buffer SSBO0 +{ + uint values0[]; +} _9; + +void callee2() +{ + int _31 = int(gl_FragCoord.x); + _7.values1[_31]++; +} + +void callee() +{ + int _39 = int(gl_FragCoord.x); + _9.values0[_39]++; + callee2(); +} + +void spvMainInterlockedBody() +{ + callee(); +} + +void main() +{ + // Interlocks were used in a way not compatible with GLSL, this is very slow. + beginInvocationInterlockARB(); + spvMainInterlockedBody(); + endInvocationInterlockARB(); +} diff --git a/third_party/spirv-cross/reference/shaders-no-opt/asm/frag/pixel-interlock-control-flow.asm.frag b/third_party/spirv-cross/reference/shaders-no-opt/asm/frag/pixel-interlock-control-flow.asm.frag new file mode 100644 index 0000000000..72dca0d7f8 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-no-opt/asm/frag/pixel-interlock-control-flow.asm.frag @@ -0,0 +1,53 @@ +#version 450 +#extension GL_ARB_fragment_shader_interlock : require +layout(pixel_interlock_ordered) in; + +layout(binding = 1, std430) buffer SSBO1 +{ + uint values1[]; +} _7; + +layout(binding = 2, std430) buffer _12_13 +{ + uint _m0[]; +} _13; + +layout(binding = 0, std430) buffer SSBO0 +{ + uint values0[]; +} _9; + +void callee2() +{ + int _44 = int(gl_FragCoord.x); + _7.values1[_44]++; +} + +void callee() +{ + int _52 = int(gl_FragCoord.x); + _9.values0[_52]++; + callee2(); + if (true) + { + } +} + +void _35() +{ + _13._m0[int(gl_FragCoord.x)] = 4u; +} + +void spvMainInterlockedBody() +{ + callee(); + _35(); +} + +void main() +{ + // Interlocks were used in a way not compatible with GLSL, this is very slow. + beginInvocationInterlockARB(); + spvMainInterlockedBody(); + endInvocationInterlockARB(); +} diff --git a/third_party/spirv-cross/reference/shaders-no-opt/asm/frag/pixel-interlock-split-functions.asm.frag b/third_party/spirv-cross/reference/shaders-no-opt/asm/frag/pixel-interlock-split-functions.asm.frag new file mode 100644 index 0000000000..b09eb66671 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-no-opt/asm/frag/pixel-interlock-split-functions.asm.frag @@ -0,0 +1,49 @@ +#version 450 +#extension GL_ARB_fragment_shader_interlock : require +layout(pixel_interlock_ordered) in; + +layout(binding = 1, std430) buffer SSBO1 +{ + uint values1[]; +} _7; + +layout(binding = 0, std430) buffer SSBO0 +{ + uint values0[]; +} _9; + +void callee2() +{ + int _37 = int(gl_FragCoord.x); + _7.values1[_37]++; +} + +void callee() +{ + int _45 = int(gl_FragCoord.x); + _9.values0[_45]++; + callee2(); +} + +void _29() +{ +} + +void _31() +{ +} + +void spvMainInterlockedBody() +{ + callee(); + _29(); + _31(); +} + +void main() +{ + // Interlocks were used in a way not compatible with GLSL, this is very slow. + beginInvocationInterlockARB(); + spvMainInterlockedBody(); + endInvocationInterlockARB(); +} diff --git a/third_party/spirv-cross/reference/shaders/asm/frag/selection-merge-to-continue.asm.frag b/third_party/spirv-cross/reference/shaders-no-opt/asm/frag/selection-merge-to-continue.asm.invalid.frag similarity index 88% rename from third_party/spirv-cross/reference/shaders/asm/frag/selection-merge-to-continue.asm.frag rename to third_party/spirv-cross/reference/shaders-no-opt/asm/frag/selection-merge-to-continue.asm.invalid.frag index 82b5973f8a..edbce0ccaf 100644 --- a/third_party/spirv-cross/reference/shaders/asm/frag/selection-merge-to-continue.asm.frag +++ b/third_party/spirv-cross/reference/shaders-no-opt/asm/frag/selection-merge-to-continue.asm.invalid.frag @@ -11,12 +11,10 @@ void main() if (v0.x == 20.0) { FragColor += vec4(v0[i & 3]); - continue; } else { FragColor += vec4(v0[i & 1]); - continue; } } } diff --git a/third_party/spirv-cross/reference/shaders-no-opt/asm/frag/subgroup-arithmetic-cast.nocompat.vk.asm.frag.vk b/third_party/spirv-cross/reference/shaders-no-opt/asm/frag/subgroup-arithmetic-cast.nocompat.vk.asm.frag.vk new file mode 100644 index 0000000000..130cab7d1a --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-no-opt/asm/frag/subgroup-arithmetic-cast.nocompat.vk.asm.frag.vk @@ -0,0 +1,24 @@ +#version 450 +#extension GL_KHR_shader_subgroup_arithmetic : require +#extension GL_KHR_shader_subgroup_clustered : require + +layout(location = 0) flat in int index; +layout(location = 0) out uint FragColor; + +void main() +{ + uint _17 = uint(index); + FragColor = uint(subgroupMin(index)); + FragColor = uint(subgroupMax(int(_17))); + FragColor = subgroupMin(uint(index)); + FragColor = subgroupMax(_17); + FragColor = uint(subgroupInclusiveMax(index)); + FragColor = uint(subgroupInclusiveMin(int(_17))); + FragColor = subgroupExclusiveMax(uint(index)); + FragColor = subgroupExclusiveMin(_17); + FragColor = uint(subgroupClusteredMin(index, 4u)); + FragColor = uint(subgroupClusteredMax(int(_17), 4u)); + FragColor = subgroupClusteredMin(uint(index), 4u); + FragColor = subgroupClusteredMax(_17, 4u); +} + diff --git a/third_party/spirv-cross/reference/shaders-no-opt/asm/frag/switch-block-case-fallthrough.asm.frag b/third_party/spirv-cross/reference/shaders-no-opt/asm/frag/switch-block-case-fallthrough.asm.invalid.frag similarity index 100% rename from third_party/spirv-cross/reference/shaders-no-opt/asm/frag/switch-block-case-fallthrough.asm.frag rename to third_party/spirv-cross/reference/shaders-no-opt/asm/frag/switch-block-case-fallthrough.asm.invalid.frag diff --git a/third_party/spirv-cross/reference/shaders/asm/frag/switch-merge-to-continue.asm.frag b/third_party/spirv-cross/reference/shaders-no-opt/asm/frag/switch-merge-to-continue.asm.invalid.frag similarity index 100% rename from third_party/spirv-cross/reference/shaders/asm/frag/switch-merge-to-continue.asm.frag rename to third_party/spirv-cross/reference/shaders-no-opt/asm/frag/switch-merge-to-continue.asm.invalid.frag diff --git a/third_party/spirv-cross/reference/shaders-no-opt/asm/frag/switch-single-case-multiple-exit-cfg.asm.frag b/third_party/spirv-cross/reference/shaders-no-opt/asm/frag/switch-single-case-multiple-exit-cfg.asm.frag new file mode 100644 index 0000000000..66ac130d9f --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-no-opt/asm/frag/switch-single-case-multiple-exit-cfg.asm.frag @@ -0,0 +1,29 @@ +#version 310 es +precision mediump float; +precision highp int; + +layout(location = 0) out highp vec4 _GLF_color; + +vec2 _19; + +void main() +{ + highp vec2 _30; + switch (0) + { + default: + { + if (gl_FragCoord.x != gl_FragCoord.x) + { + _30 = _19; + break; + } + highp vec2 _29 = _19; + _29.y = _19.y; + _30 = _29; + break; + } + } + _GLF_color = vec4(_30, 1.0, 1.0); +} + diff --git a/third_party/spirv-cross/reference/shaders-no-opt/asm/frag/unordered-compare.asm.frag b/third_party/spirv-cross/reference/shaders-no-opt/asm/frag/unordered-compare.asm.frag new file mode 100644 index 0000000000..2cc8129552 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-no-opt/asm/frag/unordered-compare.asm.frag @@ -0,0 +1,33 @@ +#version 450 + +layout(location = 0) in vec4 A; +layout(location = 1) in vec4 B; +layout(location = 0) out vec4 FragColor; + +vec4 test_vector() +{ + bvec4 le = not(greaterThanEqual(A, B)); + bvec4 leq = not(greaterThan(A, B)); + bvec4 ge = not(lessThanEqual(A, B)); + bvec4 geq = not(lessThan(A, B)); + bvec4 eq = not(notEqual(A, B)); + bvec4 neq = not(equal(A, B)); + return ((((mix(vec4(0.0), vec4(1.0), le) + mix(vec4(0.0), vec4(1.0), leq)) + mix(vec4(0.0), vec4(1.0), ge)) + mix(vec4(0.0), vec4(1.0), geq)) + mix(vec4(0.0), vec4(1.0), eq)) + mix(vec4(0.0), vec4(1.0), neq); +} + +float test_scalar() +{ + bool le = !(A.x >= B.x); + bool leq = !(A.x > B.x); + bool ge = !(A.x <= B.x); + bool geq = !(A.x < B.x); + bool eq = !(A.x != B.x); + bool neq = !(A.x == B.x); + return ((((float(le) + float(leq)) + float(ge)) + float(geq)) + float(eq)) + float(neq); +} + +void main() +{ + FragColor = test_vector() + vec4(test_scalar()); +} + diff --git a/third_party/spirv-cross/reference/shaders-no-opt/asm/frag/vector-extract-dynamic-spec-constant.asm.frag b/third_party/spirv-cross/reference/shaders-no-opt/asm/frag/vector-extract-dynamic-spec-constant.asm.frag new file mode 100644 index 0000000000..d4f3acae09 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-no-opt/asm/frag/vector-extract-dynamic-spec-constant.asm.frag @@ -0,0 +1,27 @@ +#version 450 + +#ifndef SPIRV_CROSS_CONSTANT_ID_0 +#define SPIRV_CROSS_CONSTANT_ID_0 0 +#endif +const int omap_r = SPIRV_CROSS_CONSTANT_ID_0; +#ifndef SPIRV_CROSS_CONSTANT_ID_1 +#define SPIRV_CROSS_CONSTANT_ID_1 1 +#endif +const int omap_g = SPIRV_CROSS_CONSTANT_ID_1; +#ifndef SPIRV_CROSS_CONSTANT_ID_2 +#define SPIRV_CROSS_CONSTANT_ID_2 2 +#endif +const int omap_b = SPIRV_CROSS_CONSTANT_ID_2; +#ifndef SPIRV_CROSS_CONSTANT_ID_3 +#define SPIRV_CROSS_CONSTANT_ID_3 3 +#endif +const int omap_a = SPIRV_CROSS_CONSTANT_ID_3; + +layout(location = 0) out vec4 FragColor; +layout(location = 0) in vec4 vColor; + +void main() +{ + FragColor = vec4(vColor[omap_r], vColor[omap_g], vColor[omap_b], vColor[omap_a]); +} + diff --git a/third_party/spirv-cross/reference/opt/shaders/asm/geom/store-uint-layer.invalid.asm.geom b/third_party/spirv-cross/reference/shaders-no-opt/asm/geom/store-uint-layer.invalid.asm.geom similarity index 100% rename from third_party/spirv-cross/reference/opt/shaders/asm/geom/store-uint-layer.invalid.asm.geom rename to third_party/spirv-cross/reference/shaders-no-opt/asm/geom/store-uint-layer.invalid.asm.geom diff --git a/third_party/spirv-cross/reference/opt/shaders/asm/tesc/tess-fixed-input-array-builtin-array.invalid.asm.tesc b/third_party/spirv-cross/reference/shaders-no-opt/asm/tesc/tess-fixed-input-array-builtin-array.invalid.asm.tesc similarity index 100% rename from third_party/spirv-cross/reference/opt/shaders/asm/tesc/tess-fixed-input-array-builtin-array.invalid.asm.tesc rename to third_party/spirv-cross/reference/shaders-no-opt/asm/tesc/tess-fixed-input-array-builtin-array.invalid.asm.tesc diff --git a/third_party/spirv-cross/reference/opt/shaders/comp/bitcast-16bit-1.invalid.comp b/third_party/spirv-cross/reference/shaders-no-opt/comp/bitcast-16bit-1.invalid.comp similarity index 100% rename from third_party/spirv-cross/reference/opt/shaders/comp/bitcast-16bit-1.invalid.comp rename to third_party/spirv-cross/reference/shaders-no-opt/comp/bitcast-16bit-1.invalid.comp diff --git a/third_party/spirv-cross/reference/opt/shaders/comp/bitcast-16bit-2.invalid.comp b/third_party/spirv-cross/reference/shaders-no-opt/comp/bitcast-16bit-2.invalid.comp similarity index 100% rename from third_party/spirv-cross/reference/opt/shaders/comp/bitcast-16bit-2.invalid.comp rename to third_party/spirv-cross/reference/shaders-no-opt/comp/bitcast-16bit-2.invalid.comp diff --git a/third_party/spirv-cross/reference/shaders-no-opt/comp/illegal-struct-name.asm.comp b/third_party/spirv-cross/reference/shaders-no-opt/comp/illegal-struct-name.asm.comp new file mode 100644 index 0000000000..885dcb3baa --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-no-opt/comp/illegal-struct-name.asm.comp @@ -0,0 +1,22 @@ +#version 450 +layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in; + +struct Foo +{ + float _abs; +}; + +layout(binding = 0, std430) buffer SSBO +{ + Foo foo; + Foo foo2; +} _7; + +void main() +{ + Foo f; + f._abs = _7.foo._abs; + int _abs = 10; + _7.foo2._abs = f._abs; +} + diff --git a/third_party/spirv-cross/reference/opt/shaders/comp/inout-struct.invalid.comp b/third_party/spirv-cross/reference/shaders-no-opt/comp/inout-struct.invalid.comp similarity index 100% rename from third_party/spirv-cross/reference/opt/shaders/comp/inout-struct.invalid.comp rename to third_party/spirv-cross/reference/shaders-no-opt/comp/inout-struct.invalid.comp diff --git a/third_party/spirv-cross/reference/shaders-no-opt/comp/loop.comp b/third_party/spirv-cross/reference/shaders-no-opt/comp/loop.comp index 33888dd754..2ba731cdc7 100644 --- a/third_party/spirv-cross/reference/shaders-no-opt/comp/loop.comp +++ b/third_party/spirv-cross/reference/shaders-no-opt/comp/loop.comp @@ -7,11 +7,6 @@ layout(binding = 0, std430) readonly buffer SSBO vec4 in_data[]; } _24; -layout(binding = 1, std430) writeonly buffer SSBO2 -{ - vec4 out_data[]; -} _177; - void main() { uint ident = gl_GlobalInvocationID.x; @@ -83,25 +78,5 @@ void main() k += 10; continue; } - k = 0; - do - { - k++; - } while (k > 10); - int l = 0; - for (;;) - { - if (l == 5) - { - int _172 = l; - l = _172 + 1; - continue; - } - idat += vec4(1.0); - int _172 = l; - l = _172 + 1; - continue; - } - _177.out_data[ident] = idat; } diff --git a/third_party/spirv-cross/reference/shaders-no-opt/comp/return.comp b/third_party/spirv-cross/reference/shaders-no-opt/comp/return.comp index 4be20e93e4..4802be2244 100644 --- a/third_party/spirv-cross/reference/shaders-no-opt/comp/return.comp +++ b/third_party/spirv-cross/reference/shaders-no-opt/comp/return.comp @@ -21,7 +21,8 @@ void main() return; } } - for (int i = 0; i < 20; i++) + int i = 0; + while (i < 20) { if (i == 10) { diff --git a/third_party/spirv-cross/reference/opt/shaders/amd/shader_ballot_nonuniform_invocations.invalid.comp b/third_party/spirv-cross/reference/shaders-no-opt/comp/shader_ballot_nonuniform_invocations.invalid.comp similarity index 100% rename from third_party/spirv-cross/reference/opt/shaders/amd/shader_ballot_nonuniform_invocations.invalid.comp rename to third_party/spirv-cross/reference/shaders-no-opt/comp/shader_ballot_nonuniform_invocations.invalid.comp diff --git a/third_party/spirv-cross/reference/opt/shaders/vulkan/comp/struct-packing-scalar.nocompat.invalid.vk.comp.vk b/third_party/spirv-cross/reference/shaders-no-opt/comp/struct-packing-scalar.nocompat.invalid.vk.comp.vk similarity index 100% rename from third_party/spirv-cross/reference/opt/shaders/vulkan/comp/struct-packing-scalar.nocompat.invalid.vk.comp.vk rename to third_party/spirv-cross/reference/shaders-no-opt/comp/struct-packing-scalar.nocompat.invalid.vk.comp.vk diff --git a/third_party/spirv-cross/reference/opt/shaders/vulkan/comp/subgroups.nocompat.invalid.vk.comp.vk b/third_party/spirv-cross/reference/shaders-no-opt/comp/subgroups.nocompat.invalid.vk.comp.vk similarity index 100% rename from third_party/spirv-cross/reference/opt/shaders/vulkan/comp/subgroups.nocompat.invalid.vk.comp.vk rename to third_party/spirv-cross/reference/shaders-no-opt/comp/subgroups.nocompat.invalid.vk.comp.vk diff --git a/third_party/spirv-cross/reference/opt/shaders/frag/16bit-constants.invalid.frag b/third_party/spirv-cross/reference/shaders-no-opt/frag/16bit-constants.invalid.frag similarity index 100% rename from third_party/spirv-cross/reference/opt/shaders/frag/16bit-constants.invalid.frag rename to third_party/spirv-cross/reference/shaders-no-opt/frag/16bit-constants.invalid.frag diff --git a/third_party/spirv-cross/reference/opt/shaders/desktop-only/frag/fp16.invalid.desktop.frag b/third_party/spirv-cross/reference/shaders-no-opt/frag/fp16.invalid.desktop.frag similarity index 100% rename from third_party/spirv-cross/reference/opt/shaders/desktop-only/frag/fp16.invalid.desktop.frag rename to third_party/spirv-cross/reference/shaders-no-opt/frag/fp16.invalid.desktop.frag diff --git a/third_party/spirv-cross/reference/opt/shaders/amd/fragmentMaskFetch_subpassInput.vk.nocompat.invalid.frag.vk b/third_party/spirv-cross/reference/shaders-no-opt/frag/fragmentMaskFetch_subpassInput.vk.nocompat.invalid.frag.vk similarity index 100% rename from third_party/spirv-cross/reference/opt/shaders/amd/fragmentMaskFetch_subpassInput.vk.nocompat.invalid.frag.vk rename to third_party/spirv-cross/reference/shaders-no-opt/frag/fragmentMaskFetch_subpassInput.vk.nocompat.invalid.frag.vk diff --git a/third_party/spirv-cross/reference/opt/shaders/amd/fs.invalid.frag b/third_party/spirv-cross/reference/shaders-no-opt/frag/fs.invalid.frag similarity index 100% rename from third_party/spirv-cross/reference/opt/shaders/amd/fs.invalid.frag rename to third_party/spirv-cross/reference/shaders-no-opt/frag/fs.invalid.frag diff --git a/third_party/spirv-cross/reference/opt/shaders/flatten/multi-dimensional.desktop.invalid.flatten_dim.frag b/third_party/spirv-cross/reference/shaders-no-opt/frag/multi-dimensional.desktop.invalid.flatten_dim.frag similarity index 100% rename from third_party/spirv-cross/reference/opt/shaders/flatten/multi-dimensional.desktop.invalid.flatten_dim.frag rename to third_party/spirv-cross/reference/shaders-no-opt/frag/multi-dimensional.desktop.invalid.flatten_dim.frag diff --git a/third_party/spirv-cross/reference/shaders-no-opt/frag/pixel-interlock-simple-callstack.frag b/third_party/spirv-cross/reference/shaders-no-opt/frag/pixel-interlock-simple-callstack.frag new file mode 100644 index 0000000000..151ed01d4b --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-no-opt/frag/pixel-interlock-simple-callstack.frag @@ -0,0 +1,34 @@ +#version 450 +#extension GL_ARB_fragment_shader_interlock : require +layout(pixel_interlock_ordered) in; + +layout(binding = 1, std430) buffer SSBO1 +{ + uint values1[]; +} _14; + +layout(binding = 0, std430) buffer SSBO0 +{ + uint values0[]; +} _35; + +void callee2() +{ + int _25 = int(gl_FragCoord.x); + _14.values1[_25]++; +} + +void callee() +{ + int _38 = int(gl_FragCoord.x); + _35.values0[_38]++; + callee2(); +} + +void main() +{ + beginInvocationInterlockARB(); + callee(); + endInvocationInterlockARB(); +} + diff --git a/third_party/spirv-cross/reference/opt/shaders/vulkan/frag/scalar-block-layout-ubo-std430.vk.nocompat.invalid.frag.vk b/third_party/spirv-cross/reference/shaders-no-opt/frag/scalar-block-layout-ubo-std430.vk.nocompat.invalid.frag.vk similarity index 100% rename from third_party/spirv-cross/reference/opt/shaders/vulkan/frag/scalar-block-layout-ubo-std430.vk.nocompat.invalid.frag.vk rename to third_party/spirv-cross/reference/shaders-no-opt/frag/scalar-block-layout-ubo-std430.vk.nocompat.invalid.frag.vk diff --git a/third_party/spirv-cross/reference/shaders-reflection/asm/aliased-entry-point-names.asm.multi.json b/third_party/spirv-cross/reference/shaders-reflection/asm/aliased-entry-point-names.asm.multi.json index a56a06f35c..666167af4a 100644 --- a/third_party/spirv-cross/reference/shaders-reflection/asm/aliased-entry-point-names.asm.multi.json +++ b/third_party/spirv-cross/reference/shaders-reflection/asm/aliased-entry-point-names.asm.multi.json @@ -34,6 +34,9 @@ "type" : "float", "array" : [ 1 + ], + "array_size_is_literal" : [ + true ] }, { @@ -41,6 +44,9 @@ "type" : "float", "array" : [ 1 + ], + "array_size_is_literal" : [ + true ] } ] diff --git a/third_party/spirv-cross/reference/shaders-reflection/asm/op-source-glsl-ssbo-1.asm.comp.json b/third_party/spirv-cross/reference/shaders-reflection/asm/op-source-glsl-ssbo-1.asm.comp.json index 6cd7f95d76..3b0c9868e5 100644 --- a/third_party/spirv-cross/reference/shaders-reflection/asm/op-source-glsl-ssbo-1.asm.comp.json +++ b/third_party/spirv-cross/reference/shaders-reflection/asm/op-source-glsl-ssbo-1.asm.comp.json @@ -2,7 +2,17 @@ "entryPoints" : [ { "name" : "main", - "mode" : "comp" + "mode" : "comp", + "workgroup_size" : [ + 1, + 1, + 1 + ], + "workgroup_size_is_spec_constant_id" : [ + false, + false, + false + ] } ], "types" : { @@ -15,7 +25,11 @@ "array" : [ 0 ], - "offset" : 0 + "array_size_is_literal" : [ + true + ], + "offset" : 0, + "array_stride" : 16 } ] } diff --git a/third_party/spirv-cross/reference/shaders-reflection/asm/op-source-glsl-ssbo-2.asm.comp.json b/third_party/spirv-cross/reference/shaders-reflection/asm/op-source-glsl-ssbo-2.asm.comp.json index c2fa56405e..80cf862227 100644 --- a/third_party/spirv-cross/reference/shaders-reflection/asm/op-source-glsl-ssbo-2.asm.comp.json +++ b/third_party/spirv-cross/reference/shaders-reflection/asm/op-source-glsl-ssbo-2.asm.comp.json @@ -2,7 +2,17 @@ "entryPoints" : [ { "name" : "main", - "mode" : "comp" + "mode" : "comp", + "workgroup_size" : [ + 1, + 1, + 1 + ], + "workgroup_size_is_spec_constant_id" : [ + false, + false, + false + ] } ], "types" : { @@ -15,7 +25,11 @@ "array" : [ 0 ], - "offset" : 0 + "array_size_is_literal" : [ + true + ], + "offset" : 0, + "array_stride" : 16 } ] }, @@ -28,7 +42,11 @@ "array" : [ 0 ], - "offset" : 0 + "array_size_is_literal" : [ + true + ], + "offset" : 0, + "array_stride" : 16 } ] } diff --git a/third_party/spirv-cross/reference/shaders-reflection/asm/op-source-hlsl-uav-1.asm.comp.json b/third_party/spirv-cross/reference/shaders-reflection/asm/op-source-hlsl-uav-1.asm.comp.json index 12b0677f6d..19feacc49c 100644 --- a/third_party/spirv-cross/reference/shaders-reflection/asm/op-source-hlsl-uav-1.asm.comp.json +++ b/third_party/spirv-cross/reference/shaders-reflection/asm/op-source-hlsl-uav-1.asm.comp.json @@ -2,7 +2,17 @@ "entryPoints" : [ { "name" : "main", - "mode" : "comp" + "mode" : "comp", + "workgroup_size" : [ + 1, + 1, + 1 + ], + "workgroup_size_is_spec_constant_id" : [ + false, + false, + false + ] } ], "types" : { @@ -15,7 +25,11 @@ "array" : [ 0 ], - "offset" : 0 + "array_size_is_literal" : [ + true + ], + "offset" : 0, + "array_stride" : 16 } ] } diff --git a/third_party/spirv-cross/reference/shaders-reflection/asm/op-source-hlsl-uav-2.asm.comp.json b/third_party/spirv-cross/reference/shaders-reflection/asm/op-source-hlsl-uav-2.asm.comp.json index 8da2c74eb5..6d0b685c2d 100644 --- a/third_party/spirv-cross/reference/shaders-reflection/asm/op-source-hlsl-uav-2.asm.comp.json +++ b/third_party/spirv-cross/reference/shaders-reflection/asm/op-source-hlsl-uav-2.asm.comp.json @@ -2,7 +2,17 @@ "entryPoints" : [ { "name" : "main", - "mode" : "comp" + "mode" : "comp", + "workgroup_size" : [ + 1, + 1, + 1 + ], + "workgroup_size_is_spec_constant_id" : [ + false, + false, + false + ] } ], "types" : { @@ -15,7 +25,11 @@ "array" : [ 0 ], - "offset" : 0 + "array_size_is_literal" : [ + true + ], + "offset" : 0, + "array_stride" : 16 } ] } diff --git a/third_party/spirv-cross/reference/shaders-reflection/asm/op-source-none-ssbo-1.asm.comp.json b/third_party/spirv-cross/reference/shaders-reflection/asm/op-source-none-ssbo-1.asm.comp.json index 6cd7f95d76..3b0c9868e5 100644 --- a/third_party/spirv-cross/reference/shaders-reflection/asm/op-source-none-ssbo-1.asm.comp.json +++ b/third_party/spirv-cross/reference/shaders-reflection/asm/op-source-none-ssbo-1.asm.comp.json @@ -2,7 +2,17 @@ "entryPoints" : [ { "name" : "main", - "mode" : "comp" + "mode" : "comp", + "workgroup_size" : [ + 1, + 1, + 1 + ], + "workgroup_size_is_spec_constant_id" : [ + false, + false, + false + ] } ], "types" : { @@ -15,7 +25,11 @@ "array" : [ 0 ], - "offset" : 0 + "array_size_is_literal" : [ + true + ], + "offset" : 0, + "array_stride" : 16 } ] } diff --git a/third_party/spirv-cross/reference/shaders-reflection/asm/op-source-none-ssbo-2.asm.comp.json b/third_party/spirv-cross/reference/shaders-reflection/asm/op-source-none-ssbo-2.asm.comp.json index c2fa56405e..80cf862227 100644 --- a/third_party/spirv-cross/reference/shaders-reflection/asm/op-source-none-ssbo-2.asm.comp.json +++ b/third_party/spirv-cross/reference/shaders-reflection/asm/op-source-none-ssbo-2.asm.comp.json @@ -2,7 +2,17 @@ "entryPoints" : [ { "name" : "main", - "mode" : "comp" + "mode" : "comp", + "workgroup_size" : [ + 1, + 1, + 1 + ], + "workgroup_size_is_spec_constant_id" : [ + false, + false, + false + ] } ], "types" : { @@ -15,7 +25,11 @@ "array" : [ 0 ], - "offset" : 0 + "array_size_is_literal" : [ + true + ], + "offset" : 0, + "array_stride" : 16 } ] }, @@ -28,7 +42,11 @@ "array" : [ 0 ], - "offset" : 0 + "array_size_is_literal" : [ + true + ], + "offset" : 0, + "array_stride" : 16 } ] } diff --git a/third_party/spirv-cross/reference/shaders-reflection/asm/op-source-none-uav-1.asm.comp.json b/third_party/spirv-cross/reference/shaders-reflection/asm/op-source-none-uav-1.asm.comp.json index 12b0677f6d..19feacc49c 100644 --- a/third_party/spirv-cross/reference/shaders-reflection/asm/op-source-none-uav-1.asm.comp.json +++ b/third_party/spirv-cross/reference/shaders-reflection/asm/op-source-none-uav-1.asm.comp.json @@ -2,7 +2,17 @@ "entryPoints" : [ { "name" : "main", - "mode" : "comp" + "mode" : "comp", + "workgroup_size" : [ + 1, + 1, + 1 + ], + "workgroup_size_is_spec_constant_id" : [ + false, + false, + false + ] } ], "types" : { @@ -15,7 +25,11 @@ "array" : [ 0 ], - "offset" : 0 + "array_size_is_literal" : [ + true + ], + "offset" : 0, + "array_stride" : 16 } ] } diff --git a/third_party/spirv-cross/reference/shaders-reflection/asm/op-source-none-uav-2.asm.comp.json b/third_party/spirv-cross/reference/shaders-reflection/asm/op-source-none-uav-2.asm.comp.json index 8da2c74eb5..6d0b685c2d 100644 --- a/third_party/spirv-cross/reference/shaders-reflection/asm/op-source-none-uav-2.asm.comp.json +++ b/third_party/spirv-cross/reference/shaders-reflection/asm/op-source-none-uav-2.asm.comp.json @@ -2,7 +2,17 @@ "entryPoints" : [ { "name" : "main", - "mode" : "comp" + "mode" : "comp", + "workgroup_size" : [ + 1, + 1, + 1 + ], + "workgroup_size_is_spec_constant_id" : [ + false, + false, + false + ] } ], "types" : { @@ -15,7 +25,11 @@ "array" : [ 0 ], - "offset" : 0 + "array_size_is_literal" : [ + true + ], + "offset" : 0, + "array_stride" : 16 } ] } diff --git a/third_party/spirv-cross/reference/shaders-reflection/comp/struct-layout.comp.json b/third_party/spirv-cross/reference/shaders-reflection/comp/struct-layout.comp.json index 3004454b80..e9bf7eea90 100644 --- a/third_party/spirv-cross/reference/shaders-reflection/comp/struct-layout.comp.json +++ b/third_party/spirv-cross/reference/shaders-reflection/comp/struct-layout.comp.json @@ -2,7 +2,17 @@ "entryPoints" : [ { "name" : "main", - "mode" : "comp" + "mode" : "comp", + "workgroup_size" : [ + 1, + 1, + 1 + ], + "workgroup_size_is_spec_constant_id" : [ + false, + false, + false + ] } ], "types" : { @@ -12,7 +22,8 @@ { "name" : "m", "type" : "mat4", - "offset" : 0 + "offset" : 0, + "matrix_stride" : 16 } ] }, @@ -25,7 +36,11 @@ "array" : [ 0 ], - "offset" : 0 + "array_size_is_literal" : [ + true + ], + "offset" : 0, + "array_stride" : 64 } ] }, @@ -38,7 +53,11 @@ "array" : [ 0 ], - "offset" : 0 + "array_size_is_literal" : [ + true + ], + "offset" : 0, + "array_stride" : 64 } ] } diff --git a/third_party/spirv-cross/reference/shaders-reflection/comp/struct-packing.comp.json b/third_party/spirv-cross/reference/shaders-reflection/comp/struct-packing.comp.json index 22a41584d9..12285ae24e 100644 --- a/third_party/spirv-cross/reference/shaders-reflection/comp/struct-packing.comp.json +++ b/third_party/spirv-cross/reference/shaders-reflection/comp/struct-packing.comp.json @@ -2,7 +2,17 @@ "entryPoints" : [ { "name" : "main", - "mode" : "comp" + "mode" : "comp", + "workgroup_size" : [ + 1, + 1, + 1 + ], + "workgroup_size_is_spec_constant_id" : [ + false, + false, + false + ] } ], "types" : { @@ -15,7 +25,11 @@ "array" : [ 1 ], - "offset" : 0 + "array_size_is_literal" : [ + true + ], + "offset" : 0, + "array_stride" : 8 }, { "name" : "b", @@ -48,7 +62,11 @@ "array" : [ 1 ], - "offset" : 0 + "array_size_is_literal" : [ + true + ], + "offset" : 0, + "array_stride" : 16 }, { "name" : "b", @@ -91,7 +109,11 @@ "array" : [ 1 ], - "offset" : 0 + "array_size_is_literal" : [ + true + ], + "offset" : 0, + "array_stride" : 16 }, { "name" : "m1s", @@ -99,7 +121,11 @@ "array" : [ 1 ], - "offset" : 16 + "array_size_is_literal" : [ + true + ], + "offset" : 16, + "array_stride" : 16 }, { "name" : "m2s", @@ -107,7 +133,11 @@ "array" : [ 1 ], - "offset" : 32 + "array_size_is_literal" : [ + true + ], + "offset" : 32, + "array_stride" : 32 }, { "name" : "m0", @@ -140,7 +170,11 @@ "array" : [ 8 ], - "offset" : 152 + "array_size_is_literal" : [ + true + ], + "offset" : 152, + "array_stride" : 8 } ] }, @@ -158,7 +192,11 @@ "array" : [ 2 ], - "offset" : 224 + "array_size_is_literal" : [ + true + ], + "offset" : 224, + "array_stride" : 224 }, { "name" : "content2", @@ -168,12 +206,14 @@ { "name" : "m0", "type" : "mat2", - "offset" : 896 + "offset" : 896, + "matrix_stride" : 8 }, { "name" : "m1", "type" : "mat2", - "offset" : 912 + "offset" : 912, + "matrix_stride" : 8 }, { "name" : "m2", @@ -181,43 +221,62 @@ "array" : [ 4 ], - "offset" : 928 + "array_size_is_literal" : [ + true + ], + "offset" : 928, + "array_stride" : 32, + "matrix_stride" : 16 }, { "name" : "m3", "type" : "mat3x2", - "offset" : 1056 + "offset" : 1056, + "matrix_stride" : 8 }, { "name" : "m4", "type" : "mat2", - "row_major" : true, - "offset" : 1080 + "offset" : 1080, + "matrix_stride" : 8, + "row_major" : true }, { "name" : "m5", "type" : "mat2", - "row_major" : true, "array" : [ 9 ], - "offset" : 1096 + "array_size_is_literal" : [ + true + ], + "offset" : 1096, + "array_stride" : 16, + "matrix_stride" : 8, + "row_major" : true }, { "name" : "m6", "type" : "mat2x3", - "row_major" : true, "array" : [ 2, 4 ], - "offset" : 1240 + "array_size_is_literal" : [ + true, + true + ], + "offset" : 1240, + "array_stride" : 48, + "matrix_stride" : 8, + "row_major" : true }, { "name" : "m7", "type" : "mat3x2", - "row_major" : true, - "offset" : 1440 + "offset" : 1440, + "matrix_stride" : 16, + "row_major" : true }, { "name" : "array", @@ -225,7 +284,11 @@ "array" : [ 0 ], - "offset" : 1472 + "array_size_is_literal" : [ + true + ], + "offset" : 1472, + "array_stride" : 4 } ] }, @@ -238,7 +301,11 @@ "array" : [ 1 ], - "offset" : 0 + "array_size_is_literal" : [ + true + ], + "offset" : 0, + "array_stride" : 16 }, { "name" : "b", @@ -271,7 +338,11 @@ "array" : [ 1 ], - "offset" : 0 + "array_size_is_literal" : [ + true + ], + "offset" : 0, + "array_stride" : 16 }, { "name" : "b", @@ -314,7 +385,11 @@ "array" : [ 1 ], - "offset" : 0 + "array_size_is_literal" : [ + true + ], + "offset" : 0, + "array_stride" : 32 }, { "name" : "m1s", @@ -322,7 +397,11 @@ "array" : [ 1 ], - "offset" : 32 + "array_size_is_literal" : [ + true + ], + "offset" : 32, + "array_stride" : 16 }, { "name" : "m2s", @@ -330,7 +409,11 @@ "array" : [ 1 ], - "offset" : 48 + "array_size_is_literal" : [ + true + ], + "offset" : 48, + "array_stride" : 32 }, { "name" : "m0", @@ -363,7 +446,11 @@ "array" : [ 8 ], - "offset" : 192 + "array_size_is_literal" : [ + true + ], + "offset" : 192, + "array_stride" : 16 } ] }, @@ -381,7 +468,11 @@ "array" : [ 2 ], - "offset" : 320 + "array_size_is_literal" : [ + true + ], + "offset" : 320, + "array_stride" : 320 }, { "name" : "content2", @@ -391,12 +482,14 @@ { "name" : "m0", "type" : "mat2", - "offset" : 1280 + "offset" : 1280, + "matrix_stride" : 16 }, { "name" : "m1", "type" : "mat2", - "offset" : 1312 + "offset" : 1312, + "matrix_stride" : 16 }, { "name" : "m2", @@ -404,43 +497,62 @@ "array" : [ 4 ], - "offset" : 1344 + "array_size_is_literal" : [ + true + ], + "offset" : 1344, + "array_stride" : 32, + "matrix_stride" : 16 }, { "name" : "m3", "type" : "mat3x2", - "offset" : 1472 + "offset" : 1472, + "matrix_stride" : 16 }, { "name" : "m4", "type" : "mat2", - "row_major" : true, - "offset" : 1520 + "offset" : 1520, + "matrix_stride" : 16, + "row_major" : true }, { "name" : "m5", "type" : "mat2", - "row_major" : true, "array" : [ 9 ], - "offset" : 1552 + "array_size_is_literal" : [ + true + ], + "offset" : 1552, + "array_stride" : 32, + "matrix_stride" : 16, + "row_major" : true }, { "name" : "m6", "type" : "mat2x3", - "row_major" : true, "array" : [ 2, 4 ], - "offset" : 1840 + "array_size_is_literal" : [ + true, + true + ], + "offset" : 1840, + "array_stride" : 96, + "matrix_stride" : 16, + "row_major" : true }, { "name" : "m7", "type" : "mat3x2", - "row_major" : true, - "offset" : 2224 + "offset" : 2224, + "matrix_stride" : 16, + "row_major" : true }, { "name" : "array", @@ -448,7 +560,11 @@ "array" : [ 0 ], - "offset" : 2256 + "array_size_is_literal" : [ + true + ], + "offset" : 2256, + "array_stride" : 16 } ] } diff --git a/third_party/spirv-cross/reference/shaders-reflection/comp/workgroup-size-spec-constant.comp.json b/third_party/spirv-cross/reference/shaders-reflection/comp/workgroup-size-spec-constant.comp.json new file mode 100644 index 0000000000..7483f0507b --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-reflection/comp/workgroup-size-spec-constant.comp.json @@ -0,0 +1,59 @@ +{ + "entryPoints" : [ + { + "name" : "main", + "mode" : "comp", + "workgroup_size" : [ + 10, + 40, + 60 + ], + "workgroup_size_is_spec_constant_id" : [ + true, + true, + true + ] + } + ], + "types" : { + "_8" : { + "name" : "SSBO", + "members" : [ + { + "name" : "v", + "type" : "vec4", + "offset" : 0 + } + ] + } + }, + "ssbos" : [ + { + "type" : "_8", + "name" : "SSBO", + "block_size" : 16, + "set" : 0, + "binding" : 0 + } + ], + "specialization_constants" : [ + { + "id" : 10, + "type" : "uint", + "variable_id" : 18, + "default_value" : 1 + }, + { + "id" : 40, + "type" : "uint", + "variable_id" : 19, + "default_value" : 1 + }, + { + "id" : 60, + "type" : "uint", + "variable_id" : 20, + "default_value" : 1 + } + ] +} \ No newline at end of file diff --git a/third_party/spirv-cross/reference/shaders-reflection/frag/separate-sampler-texture-array.vk.frag.json b/third_party/spirv-cross/reference/shaders-reflection/frag/separate-sampler-texture-array.vk.frag.json index 9216d93e5d..e5f2f75624 100644 --- a/third_party/spirv-cross/reference/shaders-reflection/frag/separate-sampler-texture-array.vk.frag.json +++ b/third_party/spirv-cross/reference/shaders-reflection/frag/separate-sampler-texture-array.vk.frag.json @@ -31,6 +31,9 @@ "array" : [ 4 ], + "array_size_is_literal" : [ + true + ], "set" : 0, "binding" : 1 }, @@ -40,6 +43,9 @@ "array" : [ 4 ], + "array_size_is_literal" : [ + true + ], "set" : 0, "binding" : 4 }, @@ -49,6 +55,9 @@ "array" : [ 4 ], + "array_size_is_literal" : [ + true + ], "set" : 0, "binding" : 3 }, @@ -58,6 +67,9 @@ "array" : [ 4 ], + "array_size_is_literal" : [ + true + ], "set" : 0, "binding" : 2 } diff --git a/third_party/spirv-cross/reference/shaders-reflection/frag/spec-constant.vk.frag.json b/third_party/spirv-cross/reference/shaders-reflection/frag/spec-constant.vk.frag.json index 0add298666..42b199c9d2 100644 --- a/third_party/spirv-cross/reference/shaders-reflection/frag/spec-constant.vk.frag.json +++ b/third_party/spirv-cross/reference/shaders-reflection/frag/spec-constant.vk.frag.json @@ -14,6 +14,9 @@ "type" : "float", "array" : [ 135 + ], + "array_size_is_literal" : [ + false ] } ] @@ -30,41 +33,49 @@ { "id" : 1, "type" : "float", + "variable_id" : 9, "default_value" : 1.5 }, { "id" : 2, "type" : "float", + "variable_id" : 11, "default_value" : 2.5 }, { "id" : 3, "type" : "int", + "variable_id" : 16, "default_value" : 3 }, { "id" : 4, "type" : "int", + "variable_id" : 25, "default_value" : 4 }, { "id" : 5, "type" : "uint", + "variable_id" : 34, "default_value" : 5 }, { "id" : 6, "type" : "uint", + "variable_id" : 35, "default_value" : 6 }, { "id" : 7, "type" : "bool", + "variable_id" : 56, "default_value" : false }, { "id" : 8, "type" : "bool", + "variable_id" : 57, "default_value" : true } ] diff --git a/third_party/spirv-cross/reference/shaders-reflection/vert/array-size-reflection.vert.json b/third_party/spirv-cross/reference/shaders-reflection/vert/array-size-reflection.vert.json new file mode 100644 index 0000000000..dc363226db --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-reflection/vert/array-size-reflection.vert.json @@ -0,0 +1,77 @@ +{ + "entryPoints" : [ + { + "name" : "main", + "mode" : "vert" + } + ], + "types" : { + "_11" : { + "name" : "gl_PerVertex", + "members" : [ + { + "name" : "gl_Position", + "type" : "vec4" + }, + { + "name" : "gl_PointSize", + "type" : "float" + }, + { + "name" : "gl_ClipDistance", + "type" : "float", + "array" : [ + 1 + ], + "array_size_is_literal" : [ + true + ] + }, + { + "name" : "gl_CullDistance", + "type" : "float", + "array" : [ + 1 + ], + "array_size_is_literal" : [ + true + ] + } + ] + }, + "_18" : { + "name" : "u_", + "members" : [ + { + "name" : "u_0", + "type" : "vec4", + "array" : [ + 16 + ], + "array_size_is_literal" : [ + false + ], + "offset" : 0, + "array_stride" : 16 + } + ] + } + }, + "ubos" : [ + { + "type" : "_18", + "name" : "u_", + "block_size" : 16, + "set" : 1, + "binding" : 0 + } + ], + "specialization_constants" : [ + { + "id" : 0, + "type" : "int", + "variable_id" : 16, + "default_value" : 1 + } + ] +} \ No newline at end of file diff --git a/third_party/spirv-cross/reference/shaders-reflection/vert/read-from-row-major-array.vert.json b/third_party/spirv-cross/reference/shaders-reflection/vert/read-from-row-major-array.vert.json index d92fb67fb5..cebd66bd9a 100644 --- a/third_party/spirv-cross/reference/shaders-reflection/vert/read-from-row-major-array.vert.json +++ b/third_party/spirv-cross/reference/shaders-reflection/vert/read-from-row-major-array.vert.json @@ -25,12 +25,18 @@ { "name" : "var", "type" : "mat2x3", - "row_major" : true, "array" : [ 4, 3 ], - "offset" : 0 + "array_size_is_literal" : [ + true, + true + ], + "offset" : 0, + "array_stride" : 192, + "matrix_stride" : 16, + "row_major" : true } ] } diff --git a/third_party/spirv-cross/reference/shaders-reflection/vert/stride-reflection.vert.json b/third_party/spirv-cross/reference/shaders-reflection/vert/stride-reflection.vert.json new file mode 100644 index 0000000000..1dd8f18957 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-reflection/vert/stride-reflection.vert.json @@ -0,0 +1,96 @@ +{ + "entryPoints" : [ + { + "name" : "main", + "mode" : "vert" + } + ], + "types" : { + "_11" : { + "name" : "gl_PerVertex", + "members" : [ + { + "name" : "gl_Position", + "type" : "vec4" + }, + { + "name" : "gl_PointSize", + "type" : "float" + }, + { + "name" : "gl_ClipDistance", + "type" : "float", + "array" : [ + 1 + ], + "array_size_is_literal" : [ + true + ] + }, + { + "name" : "gl_CullDistance", + "type" : "float", + "array" : [ + 1 + ], + "array_size_is_literal" : [ + true + ] + } + ] + }, + "_21" : { + "name" : "U", + "members" : [ + { + "name" : "v", + "type" : "vec4", + "array" : [ + 4 + ], + "array_size_is_literal" : [ + true + ], + "offset" : 0, + "array_stride" : 16 + }, + { + "name" : "c", + "type" : "mat4", + "array" : [ + 4 + ], + "array_size_is_literal" : [ + true + ], + "offset" : 64, + "array_stride" : 64, + "matrix_stride" : 16 + }, + { + "name" : "r", + "type" : "mat4", + "array" : [ + 4 + ], + "array_size_is_literal" : [ + true + ], + "offset" : 320, + "array_stride" : 64, + "matrix_stride" : 16, + "row_major" : true + } + ] + } + }, + "ubos" : [ + { + "type" : "_21", + "name" : "U", + "block_size" : 576, + "set" : 0, + "binding" : 0 + } + ] +} \ No newline at end of file diff --git a/third_party/spirv-cross/reference/shaders-ue4-no-opt/asm/frag/accesschain-invalid-expression.asm.invalid.frag b/third_party/spirv-cross/reference/shaders-ue4-no-opt/asm/frag/accesschain-invalid-expression.asm.invalid.frag new file mode 100644 index 0000000000..1af8db7589 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-ue4-no-opt/asm/frag/accesschain-invalid-expression.asm.invalid.frag @@ -0,0 +1,366 @@ +#include +#include + +using namespace metal; + +struct type_View +{ + float4x4 View_TranslatedWorldToClip; + float4x4 View_WorldToClip; + float4x4 View_TranslatedWorldToView; + float4x4 View_ViewToTranslatedWorld; + float4x4 View_TranslatedWorldToCameraView; + float4x4 View_CameraViewToTranslatedWorld; + float4x4 View_ViewToClip; + float4x4 View_ViewToClipNoAA; + float4x4 View_ClipToView; + float4x4 View_ClipToTranslatedWorld; + float4x4 View_SVPositionToTranslatedWorld; + float4x4 View_ScreenToWorld; + float4x4 View_ScreenToTranslatedWorld; + packed_float3 View_ViewForward; + float PrePadding_View_844; + packed_float3 View_ViewUp; + float PrePadding_View_860; + packed_float3 View_ViewRight; + float PrePadding_View_876; + packed_float3 View_HMDViewNoRollUp; + float PrePadding_View_892; + packed_float3 View_HMDViewNoRollRight; + float PrePadding_View_908; + float4 View_InvDeviceZToWorldZTransform; + float4 View_ScreenPositionScaleBias; + packed_float3 View_WorldCameraOrigin; + float PrePadding_View_956; + packed_float3 View_TranslatedWorldCameraOrigin; + float PrePadding_View_972; + packed_float3 View_WorldViewOrigin; + float PrePadding_View_988; + packed_float3 View_PreViewTranslation; + float PrePadding_View_1004; + float4x4 View_PrevProjection; + float4x4 View_PrevViewProj; + float4x4 View_PrevViewRotationProj; + float4x4 View_PrevViewToClip; + float4x4 View_PrevClipToView; + float4x4 View_PrevTranslatedWorldToClip; + float4x4 View_PrevTranslatedWorldToView; + float4x4 View_PrevViewToTranslatedWorld; + float4x4 View_PrevTranslatedWorldToCameraView; + float4x4 View_PrevCameraViewToTranslatedWorld; + packed_float3 View_PrevWorldCameraOrigin; + float PrePadding_View_1660; + packed_float3 View_PrevWorldViewOrigin; + float PrePadding_View_1676; + packed_float3 View_PrevPreViewTranslation; + float PrePadding_View_1692; + float4x4 View_PrevInvViewProj; + float4x4 View_PrevScreenToTranslatedWorld; + float4x4 View_ClipToPrevClip; + float4 View_TemporalAAJitter; + float4 View_GlobalClippingPlane; + float2 View_FieldOfViewWideAngles; + float2 View_PrevFieldOfViewWideAngles; + float4 View_ViewRectMin; + float4 View_ViewSizeAndInvSize; + float4 View_BufferSizeAndInvSize; + float4 View_BufferBilinearUVMinMax; + int View_NumSceneColorMSAASamples; + float View_PreExposure; + float View_OneOverPreExposure; + float PrePadding_View_2012; + float4 View_DiffuseOverrideParameter; + float4 View_SpecularOverrideParameter; + float4 View_NormalOverrideParameter; + float2 View_RoughnessOverrideParameter; + float View_PrevFrameGameTime; + float View_PrevFrameRealTime; + float View_OutOfBoundsMask; + float PrePadding_View_2084; + float PrePadding_View_2088; + float PrePadding_View_2092; + packed_float3 View_WorldCameraMovementSinceLastFrame; + float View_CullingSign; + float View_NearPlane; + float View_AdaptiveTessellationFactor; + float View_GameTime; + float View_RealTime; + float View_DeltaTime; + float View_MaterialTextureMipBias; + float View_MaterialTextureDerivativeMultiply; + uint View_Random; + uint View_FrameNumber; + uint View_StateFrameIndexMod8; + uint View_StateFrameIndex; + float View_CameraCut; + float View_UnlitViewmodeMask; + float PrePadding_View_2164; + float PrePadding_View_2168; + float PrePadding_View_2172; + float4 View_DirectionalLightColor; + packed_float3 View_DirectionalLightDirection; + float PrePadding_View_2204; + float4 View_TranslucencyLightingVolumeMin[2]; + float4 View_TranslucencyLightingVolumeInvSize[2]; + float4 View_TemporalAAParams; + float4 View_CircleDOFParams; + float View_DepthOfFieldSensorWidth; + float View_DepthOfFieldFocalDistance; + float View_DepthOfFieldScale; + float View_DepthOfFieldFocalLength; + float View_DepthOfFieldFocalRegion; + float View_DepthOfFieldNearTransitionRegion; + float View_DepthOfFieldFarTransitionRegion; + float View_MotionBlurNormalizedToPixel; + float View_bSubsurfacePostprocessEnabled; + float View_GeneralPurposeTweak; + float View_DemosaicVposOffset; + float PrePadding_View_2348; + packed_float3 View_IndirectLightingColorScale; + float View_HDR32bppEncodingMode; + packed_float3 View_AtmosphericFogSunDirection; + float View_AtmosphericFogSunPower; + float View_AtmosphericFogPower; + float View_AtmosphericFogDensityScale; + float View_AtmosphericFogDensityOffset; + float View_AtmosphericFogGroundOffset; + float View_AtmosphericFogDistanceScale; + float View_AtmosphericFogAltitudeScale; + float View_AtmosphericFogHeightScaleRayleigh; + float View_AtmosphericFogStartDistance; + float View_AtmosphericFogDistanceOffset; + float View_AtmosphericFogSunDiscScale; + uint View_AtmosphericFogRenderMask; + uint View_AtmosphericFogInscatterAltitudeSampleNum; + float4 View_AtmosphericFogSunColor; + packed_float3 View_NormalCurvatureToRoughnessScaleBias; + float View_RenderingReflectionCaptureMask; + float4 View_AmbientCubemapTint; + float View_AmbientCubemapIntensity; + float View_SkyLightParameters; + float PrePadding_View_2488; + float PrePadding_View_2492; + float4 View_SkyLightColor; + float4 View_SkyIrradianceEnvironmentMap[7]; + float View_MobilePreviewMode; + float View_HMDEyePaddingOffset; + float View_ReflectionCubemapMaxMip; + float View_ShowDecalsMask; + uint View_DistanceFieldAOSpecularOcclusionMode; + float View_IndirectCapsuleSelfShadowingIntensity; + float PrePadding_View_2648; + float PrePadding_View_2652; + packed_float3 View_ReflectionEnvironmentRoughnessMixingScaleBiasAndLargestWeight; + int View_StereoPassIndex; + float4 View_GlobalVolumeCenterAndExtent[4]; + float4 View_GlobalVolumeWorldToUVAddAndMul[4]; + float View_GlobalVolumeDimension; + float View_GlobalVolumeTexelSize; + float View_MaxGlobalDistance; + float View_bCheckerboardSubsurfaceProfileRendering; + packed_float3 View_VolumetricFogInvGridSize; + float PrePadding_View_2828; + packed_float3 View_VolumetricFogGridZParams; + float PrePadding_View_2844; + float2 View_VolumetricFogSVPosToVolumeUV; + float View_VolumetricFogMaxDistance; + float PrePadding_View_2860; + packed_float3 View_VolumetricLightmapWorldToUVScale; + float PrePadding_View_2876; + packed_float3 View_VolumetricLightmapWorldToUVAdd; + float PrePadding_View_2892; + packed_float3 View_VolumetricLightmapIndirectionTextureSize; + float View_VolumetricLightmapBrickSize; + packed_float3 View_VolumetricLightmapBrickTexelSize; + float View_StereoIPD; + float View_IndirectLightingCacheShowFlag; + float View_EyeToPixelSpreadAngle; +}; + +struct type_MobileDirectionalLight +{ + float4 MobileDirectionalLight_DirectionalLightColor; + float4 MobileDirectionalLight_DirectionalLightDirectionAndShadowTransition; + float4 MobileDirectionalLight_DirectionalLightShadowSize; + float4 MobileDirectionalLight_DirectionalLightDistanceFadeMAD; + float4 MobileDirectionalLight_DirectionalLightShadowDistances; + float4x4 MobileDirectionalLight_DirectionalLightScreenToShadow[4]; +}; + +struct type_Globals +{ + int NumDynamicPointLights; + float4 LightPositionAndInvRadius[4]; + float4 LightColorAndFalloffExponent[4]; + float4 MobileReflectionParams; +}; + +constant float3 _136 = {}; +constant float4 _137 = {}; +constant float _138 = {}; +constant float3 _139 = {}; + +struct main0_out +{ + float4 out_var_SV_Target0 [[color(0)]]; +}; + +struct main0_in +{ + float2 in_var_TEXCOORD0 [[user(locn0)]]; + float4 in_var_TEXCOORD7 [[user(locn1)]]; + float4 in_var_TEXCOORD8 [[user(locn2)]]; +}; + +fragment main0_out main0(main0_in in [[stage_in]], constant type_View& View [[buffer(0)]], constant type_MobileDirectionalLight& MobileDirectionalLight [[buffer(1)]], constant type_Globals& _Globals [[buffer(2)]], texture2d MobileDirectionalLight_DirectionalLightShadowTexture [[texture(0)]], texture2d Material_Texture2D_0 [[texture(1)]], texture2d Material_Texture2D_1 [[texture(2)]], texturecube ReflectionCubemap [[texture(3)]], sampler MobileDirectionalLight_DirectionalLightShadowSampler [[sampler(0)]], sampler Material_Texture2D_0Sampler [[sampler(1)]], sampler Material_Texture2D_1Sampler [[sampler(2)]], sampler ReflectionCubemapSampler [[sampler(3)]], float4 gl_FragCoord [[position]]) +{ + main0_out out = {}; + float4 _177 = float4((((gl_FragCoord.xy - View.View_ViewRectMin.xy) * View.View_ViewSizeAndInvSize.zw) - float2(0.5)) * float2(2.0, -2.0), _138, 1.0) * float4(gl_FragCoord.w); + float3 _181 = normalize(-in.in_var_TEXCOORD8.xyz); + float2 _190 = (Material_Texture2D_0.sample(Material_Texture2D_0Sampler, (in.in_var_TEXCOORD0 * float2(10.0))).xy * float2(2.0)) - float2(1.0); + float3 _206 = normalize(float3x3(float3(1.0, 0.0, 0.0), float3(0.0, 1.0, 0.0), float3(0.0, 0.0, 1.0)) * (((float4(_190, sqrt(fast::clamp(1.0 - dot(_190, _190), 0.0, 1.0)), 1.0).xyz * float3(0.300000011920928955078125, 0.300000011920928955078125, 1.0)) * float3(View.View_NormalOverrideParameter.w)) + View.View_NormalOverrideParameter.xyz)); + float _208 = dot(_206, _181); + float _219 = mix(0.4000000059604644775390625, 1.0, Material_Texture2D_1.sample(Material_Texture2D_1Sampler, (in.in_var_TEXCOORD0 * float2(20.0))).x); + float4 _223 = Material_Texture2D_1.sample(Material_Texture2D_1Sampler, (in.in_var_TEXCOORD0 * float2(5.0))); + float _224 = _177.w; + float _228 = fast::min(fast::max((_224 - 24.0) * 0.000666666659526526927947998046875, 0.0), 1.0); + float _229 = _223.y; + float4 _233 = Material_Texture2D_1.sample(Material_Texture2D_1Sampler, (in.in_var_TEXCOORD0 * float2(0.5))); + float _235 = _233.y; + float _253 = fast::clamp((fast::min(fast::max(mix(0.0, 0.5, _235) + mix(mix(0.699999988079071044921875, 1.0, _229), 1.0, _228), 0.0), 1.0) * View.View_RoughnessOverrideParameter.y) + View.View_RoughnessOverrideParameter.x, 0.119999997317790985107421875, 1.0); + float2 _257 = (float2(_253) * float2(-1.0, -0.0274999998509883880615234375)) + float2(1.0, 0.0425000004470348358154296875); + float _258 = _257.x; + float3 _270 = (fast::clamp(float3(mix(_219, 1.0 - _219, mix(_229, 1.0, _228)) * (mix(0.2949999868869781494140625, 0.660000026226043701171875, mix(_235 + mix(_229, 0.0, _228), 0.5, 0.5)) * 0.5)), float3(0.0), float3(1.0)) * float3(View.View_DiffuseOverrideParameter.w)) + View.View_DiffuseOverrideParameter.xyz; + float3 _275 = float3(((fast::min(_258 * _258, exp2((-9.27999973297119140625) * fast::max(_208, 0.0))) * _258) + _257.y) * View.View_SpecularOverrideParameter.w) + View.View_SpecularOverrideParameter.xyz; + float _276 = _275.x; + float4 _303; + int _286 = 0; + for (;;) + { + if (_286 < 2) + { + if (_224 < MobileDirectionalLight.MobileDirectionalLight_DirectionalLightShadowDistances[uint(_286)]) + { + _303 = MobileDirectionalLight.MobileDirectionalLight_DirectionalLightScreenToShadow[_286] * float4(_177.xy, _224, 1.0); + break; + } + _286++; + continue; + } + else + { + _303 = float4(0.0); + break; + } + } + float _423; + if (_303.z > 0.0) + { + float2 _311 = _303.xy * MobileDirectionalLight.MobileDirectionalLight_DirectionalLightShadowSize.xy; + float2 _312 = fract(_311); + float2 _313 = floor(_311); + float3 _320 = _139; + _320.x = MobileDirectionalLight_DirectionalLightShadowTexture.sample(MobileDirectionalLight_DirectionalLightShadowSampler, ((_313 + float2(-0.5)) * MobileDirectionalLight.MobileDirectionalLight_DirectionalLightShadowSize.zw), level(0.0)).x; + float3 _326 = _320; + _326.y = MobileDirectionalLight_DirectionalLightShadowTexture.sample(MobileDirectionalLight_DirectionalLightShadowSampler, ((_313 + float2(0.5, -0.5)) * MobileDirectionalLight.MobileDirectionalLight_DirectionalLightShadowSize.zw), level(0.0)).x; + float3 _332 = _326; + _332.z = MobileDirectionalLight_DirectionalLightShadowTexture.sample(MobileDirectionalLight_DirectionalLightShadowSampler, ((_313 + float2(1.5, -0.5)) * MobileDirectionalLight.MobileDirectionalLight_DirectionalLightShadowSize.zw), level(0.0)).x; + float3 _335 = float3(MobileDirectionalLight.MobileDirectionalLight_DirectionalLightDirectionAndShadowTransition.w); + float3 _337 = float3((fast::min(_303.z, 0.999989986419677734375) * MobileDirectionalLight.MobileDirectionalLight_DirectionalLightDirectionAndShadowTransition.w) - 1.0); + float3 _339 = fast::clamp((_332 * _335) - _337, float3(0.0), float3(1.0)); + float3 _345 = _139; + _345.x = MobileDirectionalLight_DirectionalLightShadowTexture.sample(MobileDirectionalLight_DirectionalLightShadowSampler, ((_313 + float2(-0.5, 0.5)) * MobileDirectionalLight.MobileDirectionalLight_DirectionalLightShadowSize.zw), level(0.0)).x; + float3 _351 = _345; + _351.y = MobileDirectionalLight_DirectionalLightShadowTexture.sample(MobileDirectionalLight_DirectionalLightShadowSampler, ((_313 + float2(0.5)) * MobileDirectionalLight.MobileDirectionalLight_DirectionalLightShadowSize.zw), level(0.0)).x; + float3 _357 = _351; + _357.z = MobileDirectionalLight_DirectionalLightShadowTexture.sample(MobileDirectionalLight_DirectionalLightShadowSampler, ((_313 + float2(1.5, 0.5)) * MobileDirectionalLight.MobileDirectionalLight_DirectionalLightShadowSize.zw), level(0.0)).x; + float3 _360 = fast::clamp((_357 * _335) - _337, float3(0.0), float3(1.0)); + float3 _366 = _139; + _366.x = MobileDirectionalLight_DirectionalLightShadowTexture.sample(MobileDirectionalLight_DirectionalLightShadowSampler, ((_313 + float2(-0.5, 1.5)) * MobileDirectionalLight.MobileDirectionalLight_DirectionalLightShadowSize.zw), level(0.0)).x; + float3 _372 = _366; + _372.y = MobileDirectionalLight_DirectionalLightShadowTexture.sample(MobileDirectionalLight_DirectionalLightShadowSampler, ((_313 + float2(0.5, 1.5)) * MobileDirectionalLight.MobileDirectionalLight_DirectionalLightShadowSize.zw), level(0.0)).x; + float3 _378 = _372; + _378.z = MobileDirectionalLight_DirectionalLightShadowTexture.sample(MobileDirectionalLight_DirectionalLightShadowSampler, ((_313 + float2(1.5)) * MobileDirectionalLight.MobileDirectionalLight_DirectionalLightShadowSize.zw), level(0.0)).x; + float3 _381 = fast::clamp((_378 * _335) - _337, float3(0.0), float3(1.0)); + float _383 = _312.x; + float _384 = 1.0 - _383; + float3 _399 = _136; + _399.x = ((_339.x * _384) + _339.y) + (_339.z * _383); + float3 _403 = _399; + _403.y = ((_360.x * _384) + _360.y) + (_360.z * _383); + float3 _407 = _403; + _407.z = ((_381.x * _384) + _381.y) + (_381.z * _383); + float _408 = _312.y; + float _420 = fast::clamp((_224 * MobileDirectionalLight.MobileDirectionalLight_DirectionalLightDistanceFadeMAD.x) + MobileDirectionalLight.MobileDirectionalLight_DirectionalLightDistanceFadeMAD.y, 0.0, 1.0); + _423 = mix(fast::clamp(0.25 * dot(_407, float3(1.0 - _408, 1.0, _408)), 0.0, 1.0), 1.0, _420 * _420); + } + else + { + _423 = 1.0; + } + float3 _429 = normalize(_181 + MobileDirectionalLight.MobileDirectionalLight_DirectionalLightDirectionAndShadowTransition.xyz); + float _439 = (_253 * 0.25) + 0.25; + float3 _440 = cross(_206, _429); + float _442 = _253 * _253; + float _443 = fast::max(0.0, dot(_206, _429)) * _442; + float _446 = _442 / (dot(_440, _440) + (_443 * _443)); + bool _458 = float(_Globals.MobileReflectionParams.w > 0.0) != 0.0; + float4 _468 = ReflectionCubemap.sample(ReflectionCubemapSampler, ((-_181) + ((_206 * float3(_208)) * float3(2.0))), level(((_458 ? _Globals.MobileReflectionParams.w : View.View_ReflectionCubemapMaxMip) - 1.0) - (1.0 - (1.2000000476837158203125 * log2(_253))))); + float3 _481; + if (_458) + { + _481 = _468.xyz * View.View_SkyLightColor.xyz; + } + else + { + float3 _476 = _468.xyz * float3(_468.w * 16.0); + _481 = _476 * _476; + } + float3 _484 = float3(_276); + float3 _488; + _488 = ((float3(_423 * fast::max(0.0, dot(_206, MobileDirectionalLight.MobileDirectionalLight_DirectionalLightDirectionAndShadowTransition.xyz))) * MobileDirectionalLight.MobileDirectionalLight_DirectionalLightColor.xyz) * (_270 + float3(_276 * (_439 * fast::min(_446 * _446, 65504.0))))) + ((_481 * float3(fast::clamp(1.0, 0.0, 1.0))) * _484); + float3 _507; + float _509; + float _511; + float _537; + int _491 = 0; + for (;;) + { + if (_491 < _Globals.NumDynamicPointLights) + { + float3 _501 = _Globals.LightPositionAndInvRadius[_491].xyz - (in.in_var_TEXCOORD8.xyz - float3(View.View_PreViewTranslation)); + float _502 = dot(_501, _501); + float3 _505 = _501 * float3(rsqrt(_502)); + _507 = normalize(_181 + _505); + _509 = fast::max(0.0, dot(_206, _505)); + _511 = fast::max(0.0, dot(_206, _507)); + if (_Globals.LightColorAndFalloffExponent[_491].w == 0.0) + { + float _531 = _502 * (_Globals.LightPositionAndInvRadius[_491].w * _Globals.LightPositionAndInvRadius[_491].w); + float _534 = fast::clamp(1.0 - (_531 * _531), 0.0, 1.0); + _537 = (1.0 / (_502 + 1.0)) * (_534 * _534); + } + else + { + float3 _521 = _501 * float3(_Globals.LightPositionAndInvRadius[_491].w); + _537 = pow(1.0 - fast::clamp(dot(_521, _521), 0.0, 1.0), _Globals.LightColorAndFalloffExponent[_491].w); + } + float3 _544 = cross(_206, _507); + float _546 = _511 * _442; + float _549 = _442 / (dot(_544, _544) + (_546 * _546)); + _488 += fast::min(float3(65000.0), ((float3(_537 * _509) * _Globals.LightColorAndFalloffExponent[_491].xyz) * float3(0.3183098733425140380859375)) * (_270 + float3(_276 * (_439 * fast::min(_549 * _549, 65504.0))))); + _491++; + continue; + } + else + { + break; + } + } + float3 _567 = (mix(_488 + fast::max(float3(0.0), float3(0.0)), _270 + _484, float3(View.View_UnlitViewmodeMask)) * float3(in.in_var_TEXCOORD7.w)) + in.in_var_TEXCOORD7.xyz; + float4 _571 = float4(_567.x, _567.y, _567.z, _137.w); + _571.w = fast::min(in.in_var_TEXCOORD8.w, 65500.0); + out.out_var_SV_Target0 = _571; + return out; +} + diff --git a/third_party/spirv-cross/reference/shaders-ue4-no-opt/asm/frag/array-copy-error.asm.invalid.frag b/third_party/spirv-cross/reference/shaders-ue4-no-opt/asm/frag/array-copy-error.asm.invalid.frag new file mode 100644 index 0000000000..73dc2eee1b --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-ue4-no-opt/asm/frag/array-copy-error.asm.invalid.frag @@ -0,0 +1,350 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + +#include +#include + +using namespace metal; + +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +struct type_View +{ + float4x4 View_TranslatedWorldToClip; + float4x4 View_WorldToClip; + float4x4 View_ClipToWorld; + float4x4 View_TranslatedWorldToView; + float4x4 View_ViewToTranslatedWorld; + float4x4 View_TranslatedWorldToCameraView; + float4x4 View_CameraViewToTranslatedWorld; + float4x4 View_ViewToClip; + float4x4 View_ViewToClipNoAA; + float4x4 View_ClipToView; + float4x4 View_ClipToTranslatedWorld; + float4x4 View_SVPositionToTranslatedWorld; + float4x4 View_ScreenToWorld; + float4x4 View_ScreenToTranslatedWorld; + packed_float3 View_ViewForward; + float PrePadding_View_908; + packed_float3 View_ViewUp; + float PrePadding_View_924; + packed_float3 View_ViewRight; + float PrePadding_View_940; + packed_float3 View_HMDViewNoRollUp; + float PrePadding_View_956; + packed_float3 View_HMDViewNoRollRight; + float PrePadding_View_972; + float4 View_InvDeviceZToWorldZTransform; + float4 View_ScreenPositionScaleBias; + packed_float3 View_WorldCameraOrigin; + float PrePadding_View_1020; + packed_float3 View_TranslatedWorldCameraOrigin; + float PrePadding_View_1036; + packed_float3 View_WorldViewOrigin; + float PrePadding_View_1052; + packed_float3 View_PreViewTranslation; + float PrePadding_View_1068; + float4x4 View_PrevProjection; + float4x4 View_PrevViewProj; + float4x4 View_PrevViewRotationProj; + float4x4 View_PrevViewToClip; + float4x4 View_PrevClipToView; + float4x4 View_PrevTranslatedWorldToClip; + float4x4 View_PrevTranslatedWorldToView; + float4x4 View_PrevViewToTranslatedWorld; + float4x4 View_PrevTranslatedWorldToCameraView; + float4x4 View_PrevCameraViewToTranslatedWorld; + packed_float3 View_PrevWorldCameraOrigin; + float PrePadding_View_1724; + packed_float3 View_PrevWorldViewOrigin; + float PrePadding_View_1740; + packed_float3 View_PrevPreViewTranslation; + float PrePadding_View_1756; + float4x4 View_PrevInvViewProj; + float4x4 View_PrevScreenToTranslatedWorld; + float4x4 View_ClipToPrevClip; + float4 View_TemporalAAJitter; + float4 View_GlobalClippingPlane; + float2 View_FieldOfViewWideAngles; + float2 View_PrevFieldOfViewWideAngles; + float4 View_ViewRectMin; + float4 View_ViewSizeAndInvSize; + float4 View_BufferSizeAndInvSize; + float4 View_BufferBilinearUVMinMax; + int View_NumSceneColorMSAASamples; + float View_PreExposure; + float View_OneOverPreExposure; + float PrePadding_View_2076; + float4 View_DiffuseOverrideParameter; + float4 View_SpecularOverrideParameter; + float4 View_NormalOverrideParameter; + float2 View_RoughnessOverrideParameter; + float View_PrevFrameGameTime; + float View_PrevFrameRealTime; + float View_OutOfBoundsMask; + float PrePadding_View_2148; + float PrePadding_View_2152; + float PrePadding_View_2156; + packed_float3 View_WorldCameraMovementSinceLastFrame; + float View_CullingSign; + float View_NearPlane; + float View_AdaptiveTessellationFactor; + float View_GameTime; + float View_RealTime; + float View_DeltaTime; + float View_MaterialTextureMipBias; + float View_MaterialTextureDerivativeMultiply; + uint View_Random; + uint View_FrameNumber; + uint View_StateFrameIndexMod8; + uint View_StateFrameIndex; + float View_CameraCut; + float View_UnlitViewmodeMask; + float PrePadding_View_2228; + float PrePadding_View_2232; + float PrePadding_View_2236; + float4 View_DirectionalLightColor; + packed_float3 View_DirectionalLightDirection; + float PrePadding_View_2268; + float4 View_TranslucencyLightingVolumeMin[2]; + float4 View_TranslucencyLightingVolumeInvSize[2]; + float4 View_TemporalAAParams; + float4 View_CircleDOFParams; + float View_DepthOfFieldSensorWidth; + float View_DepthOfFieldFocalDistance; + float View_DepthOfFieldScale; + float View_DepthOfFieldFocalLength; + float View_DepthOfFieldFocalRegion; + float View_DepthOfFieldNearTransitionRegion; + float View_DepthOfFieldFarTransitionRegion; + float View_MotionBlurNormalizedToPixel; + float View_bSubsurfacePostprocessEnabled; + float View_GeneralPurposeTweak; + float View_DemosaicVposOffset; + float PrePadding_View_2412; + packed_float3 View_IndirectLightingColorScale; + float View_HDR32bppEncodingMode; + packed_float3 View_AtmosphericFogSunDirection; + float View_AtmosphericFogSunPower; + float View_AtmosphericFogPower; + float View_AtmosphericFogDensityScale; + float View_AtmosphericFogDensityOffset; + float View_AtmosphericFogGroundOffset; + float View_AtmosphericFogDistanceScale; + float View_AtmosphericFogAltitudeScale; + float View_AtmosphericFogHeightScaleRayleigh; + float View_AtmosphericFogStartDistance; + float View_AtmosphericFogDistanceOffset; + float View_AtmosphericFogSunDiscScale; + float View_AtmosphericFogSunDiscHalfApexAngleRadian; + float PrePadding_View_2492; + float4 View_AtmosphericFogSunDiscLuminance; + uint View_AtmosphericFogRenderMask; + uint View_AtmosphericFogInscatterAltitudeSampleNum; + uint PrePadding_View_2520; + uint PrePadding_View_2524; + float4 View_AtmosphericFogSunColor; + packed_float3 View_NormalCurvatureToRoughnessScaleBias; + float View_RenderingReflectionCaptureMask; + float4 View_AmbientCubemapTint; + float View_AmbientCubemapIntensity; + float View_SkyLightParameters; + float PrePadding_View_2584; + float PrePadding_View_2588; + float4 View_SkyLightColor; + float4 View_SkyIrradianceEnvironmentMap[7]; + float View_MobilePreviewMode; + float View_HMDEyePaddingOffset; + float View_ReflectionCubemapMaxMip; + float View_ShowDecalsMask; + uint View_DistanceFieldAOSpecularOcclusionMode; + float View_IndirectCapsuleSelfShadowingIntensity; + float PrePadding_View_2744; + float PrePadding_View_2748; + packed_float3 View_ReflectionEnvironmentRoughnessMixingScaleBiasAndLargestWeight; + int View_StereoPassIndex; + float4 View_GlobalVolumeCenterAndExtent[4]; + float4 View_GlobalVolumeWorldToUVAddAndMul[4]; + float View_GlobalVolumeDimension; + float View_GlobalVolumeTexelSize; + float View_MaxGlobalDistance; + float PrePadding_View_2908; + int2 View_CursorPosition; + float View_bCheckerboardSubsurfaceProfileRendering; + float PrePadding_View_2924; + packed_float3 View_VolumetricFogInvGridSize; + float PrePadding_View_2940; + packed_float3 View_VolumetricFogGridZParams; + float PrePadding_View_2956; + float2 View_VolumetricFogSVPosToVolumeUV; + float View_VolumetricFogMaxDistance; + float PrePadding_View_2972; + packed_float3 View_VolumetricLightmapWorldToUVScale; + float PrePadding_View_2988; + packed_float3 View_VolumetricLightmapWorldToUVAdd; + float PrePadding_View_3004; + packed_float3 View_VolumetricLightmapIndirectionTextureSize; + float View_VolumetricLightmapBrickSize; + packed_float3 View_VolumetricLightmapBrickTexelSize; + float View_StereoIPD; + float View_IndirectLightingCacheShowFlag; + float View_EyeToPixelSpreadAngle; +}; + +struct type_PrimitiveDither +{ + float PrimitiveDither_LODFactor; +}; + +struct type_PrimitiveFade +{ + float2 PrimitiveFade_FadeTimeScaleBias; +}; + +struct type_Material +{ + float4 Material_VectorExpressions[9]; + float4 Material_ScalarExpressions[3]; +}; + +constant float _98 = {}; +constant float _103 = {}; + +struct main0_out +{ + float4 out_var_SV_Target0 [[color(0)]]; + float gl_FragDepth [[depth(less)]]; +}; + +struct main0_in +{ + float4 in_var_TEXCOORD6 [[user(locn0)]]; + float4 in_var_TEXCOORD7 [[user(locn1)]]; + float4 in_var_TEXCOORD10_centroid [[user(locn2)]]; + float4 in_var_TEXCOORD11_centroid [[user(locn3)]]; + float4 in_var_TEXCOORD0_0 [[user(locn4)]]; +}; + +fragment main0_out main0(main0_in in [[stage_in]], constant type_View& View [[buffer(0)]], constant type_PrimitiveDither& PrimitiveDither [[buffer(1)]], constant type_PrimitiveFade& PrimitiveFade [[buffer(2)]], constant type_Material& Material [[buffer(3)]], texture2d Material_Texture2D_0 [[texture(0)]], texture2d Material_Texture2D_3 [[texture(1)]], sampler Material_Texture2D_0Sampler [[sampler(0)]], sampler Material_Texture2D_3Sampler [[sampler(1)]], float4 gl_FragCoord [[position]]) +{ + main0_out out = {}; + spvUnsafeArray in_var_TEXCOORD0 = {}; + in_var_TEXCOORD0[0] = in.in_var_TEXCOORD0_0; + float2 _135 = gl_FragCoord.xy - View.View_ViewRectMin.xy; + float4 _140 = float4(_103, _103, gl_FragCoord.z, 1.0) * float4(gl_FragCoord.w); + float4 _144 = View.View_SVPositionToTranslatedWorld * float4(gl_FragCoord.xyz, 1.0); + float3 _148 = _144.xyz / float3(_144.w); + float3 _149 = _148 - float3(View.View_PreViewTranslation); + float3 _151 = normalize(-_148); + float3 _152 = _151 * float3x3(in.in_var_TEXCOORD10_centroid.xyz, cross(in.in_var_TEXCOORD11_centroid.xyz, in.in_var_TEXCOORD10_centroid.xyz) * float3(in.in_var_TEXCOORD11_centroid.w), in.in_var_TEXCOORD11_centroid.xyz); + float _170 = mix(Material.Material_ScalarExpressions[0].y, Material.Material_ScalarExpressions[0].z, fast::min(fast::max(abs(dot(_151, in.in_var_TEXCOORD11_centroid.xyz)), 0.0), 1.0)); + float _172 = 1.0 / _170; + float2 _174 = (float2(Material.Material_ScalarExpressions[0].x) * ((_152.xy * float2(-1.0)) / float2(_152.z))) * float2(_172); + float _180_copy; + float2 _183; + _183 = float2(0.0); + float _188; + float _211; + float2 _212; + float _180 = 1.0; + int _185 = 0; + float _187 = 1.0; + float _189 = 1.0; + for (;;) + { + if (float(_185) < (floor(_170) + 2.0)) + { + _188 = Material_Texture2D_0.sample(Material_Texture2D_0Sampler, (float2(in_var_TEXCOORD0[0].x, in_var_TEXCOORD0[0].y) + _183), gradient2d(dfdx(float2(in_var_TEXCOORD0[0].x, in_var_TEXCOORD0[0].y)), dfdy(float2(in_var_TEXCOORD0[0].x, in_var_TEXCOORD0[0].y)))).y; + if (_180 < _188) + { + float _201 = _188 - _180; + float _203 = _201 / ((_189 - _187) + _201); + _211 = (_189 * _203) + (_180 * (1.0 - _203)); + _212 = _183 - (float2(_203) * _174); + break; + } + _180_copy = _180; + _180 -= _172; + _183 += _174; + _185++; + _187 = _188; + _189 = _180_copy; + continue; + } + else + { + _211 = _98; + _212 = _183; + break; + } + } + float4 _218 = Material_Texture2D_0.sample(Material_Texture2D_0Sampler, (float2(in_var_TEXCOORD0[0].x, in_var_TEXCOORD0[0].y) + _212.xy), bias(View.View_MaterialTextureMipBias)); + float2 _229 = _135 + float2(View.View_TemporalAAParams.x); + float _237 = float((uint(_229.x) + (2u * uint(_229.y))) % 5u); + float2 _238 = _135 * float2(0.015625); + float4 _242 = Material_Texture2D_3.sample(Material_Texture2D_3Sampler, _238, bias(View.View_MaterialTextureMipBias)); + float4 _254 = Material_Texture2D_3.sample(Material_Texture2D_3Sampler, _238, bias(View.View_MaterialTextureMipBias)); + float3 _272 = float3(_212, (1.0 - _211) * Material.Material_ScalarExpressions[0].x); + float2 _275 = dfdx(float2(in_var_TEXCOORD0[0].x, in_var_TEXCOORD0[0].y)); + float2 _276 = abs(_275); + float3 _279 = dfdx(_149); + float2 _283 = dfdy(float2(in_var_TEXCOORD0[0].x, in_var_TEXCOORD0[0].y)); + float2 _284 = abs(_283); + float3 _287 = dfdy(_149); + if (PrimitiveDither.PrimitiveDither_LODFactor != 0.0) + { + if (abs(PrimitiveDither.PrimitiveDither_LODFactor) > 0.001000000047497451305389404296875) + { + float _317 = fract(cos(dot(floor(gl_FragCoord.xy), float2(347.834503173828125, 3343.28369140625))) * 1000.0); + if ((float((PrimitiveDither.PrimitiveDither_LODFactor < 0.0) ? ((PrimitiveDither.PrimitiveDither_LODFactor + 1.0) > _317) : (PrimitiveDither.PrimitiveDither_LODFactor < _317)) - 0.001000000047497451305389404296875) < 0.0) + { + discard_fragment(); + } + } + } + if ((((_218.z + ((fast::min(fast::max(1.0 - (_218.x * Material.Material_ScalarExpressions[2].y), 0.0), 1.0) + ((_237 + (_242.x * Material.Material_ScalarExpressions[2].z)) * 0.16666667163372039794921875)) + (-0.5))) * ((fast::clamp((View.View_RealTime * PrimitiveFade.PrimitiveFade_FadeTimeScaleBias.x) + PrimitiveFade.PrimitiveFade_FadeTimeScaleBias.y, 0.0, 1.0) + ((_237 + _254.x) * 0.16666667163372039794921875)) + (-0.5))) - 0.33329999446868896484375) < 0.0) + { + discard_fragment(); + } + float2 _351 = ((((in.in_var_TEXCOORD6.xy / float2(in.in_var_TEXCOORD6.w)) - View.View_TemporalAAJitter.xy) - ((in.in_var_TEXCOORD7.xy / float2(in.in_var_TEXCOORD7.w)) - View.View_TemporalAAJitter.zw)) * float2(0.2495000064373016357421875)) + float2(0.49999237060546875); + out.gl_FragDepth = fast::min(_140.z / (_140.w + (sqrt(dot(_272, _272)) / (fast::max(sqrt(dot(_276, _276)) / sqrt(dot(_279, _279)), sqrt(dot(_284, _284)) / sqrt(dot(_287, _287))) / abs(dot(float3x3(View.View_ViewToTranslatedWorld[0].xyz, View.View_ViewToTranslatedWorld[1].xyz, View.View_ViewToTranslatedWorld[2].xyz) * float3(0.0, 0.0, 1.0), _151))))), gl_FragCoord.z); + out.out_var_SV_Target0 = float4(_351.x, _351.y, float2(0.0).x, float2(0.0).y); + return out; +} + diff --git a/third_party/spirv-cross/reference/shaders-ue4-no-opt/asm/frag/phi-variable-declaration.asm.invalid.frag b/third_party/spirv-cross/reference/shaders-ue4-no-opt/asm/frag/phi-variable-declaration.asm.invalid.frag new file mode 100644 index 0000000000..73dc2eee1b --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-ue4-no-opt/asm/frag/phi-variable-declaration.asm.invalid.frag @@ -0,0 +1,350 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + +#include +#include + +using namespace metal; + +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +struct type_View +{ + float4x4 View_TranslatedWorldToClip; + float4x4 View_WorldToClip; + float4x4 View_ClipToWorld; + float4x4 View_TranslatedWorldToView; + float4x4 View_ViewToTranslatedWorld; + float4x4 View_TranslatedWorldToCameraView; + float4x4 View_CameraViewToTranslatedWorld; + float4x4 View_ViewToClip; + float4x4 View_ViewToClipNoAA; + float4x4 View_ClipToView; + float4x4 View_ClipToTranslatedWorld; + float4x4 View_SVPositionToTranslatedWorld; + float4x4 View_ScreenToWorld; + float4x4 View_ScreenToTranslatedWorld; + packed_float3 View_ViewForward; + float PrePadding_View_908; + packed_float3 View_ViewUp; + float PrePadding_View_924; + packed_float3 View_ViewRight; + float PrePadding_View_940; + packed_float3 View_HMDViewNoRollUp; + float PrePadding_View_956; + packed_float3 View_HMDViewNoRollRight; + float PrePadding_View_972; + float4 View_InvDeviceZToWorldZTransform; + float4 View_ScreenPositionScaleBias; + packed_float3 View_WorldCameraOrigin; + float PrePadding_View_1020; + packed_float3 View_TranslatedWorldCameraOrigin; + float PrePadding_View_1036; + packed_float3 View_WorldViewOrigin; + float PrePadding_View_1052; + packed_float3 View_PreViewTranslation; + float PrePadding_View_1068; + float4x4 View_PrevProjection; + float4x4 View_PrevViewProj; + float4x4 View_PrevViewRotationProj; + float4x4 View_PrevViewToClip; + float4x4 View_PrevClipToView; + float4x4 View_PrevTranslatedWorldToClip; + float4x4 View_PrevTranslatedWorldToView; + float4x4 View_PrevViewToTranslatedWorld; + float4x4 View_PrevTranslatedWorldToCameraView; + float4x4 View_PrevCameraViewToTranslatedWorld; + packed_float3 View_PrevWorldCameraOrigin; + float PrePadding_View_1724; + packed_float3 View_PrevWorldViewOrigin; + float PrePadding_View_1740; + packed_float3 View_PrevPreViewTranslation; + float PrePadding_View_1756; + float4x4 View_PrevInvViewProj; + float4x4 View_PrevScreenToTranslatedWorld; + float4x4 View_ClipToPrevClip; + float4 View_TemporalAAJitter; + float4 View_GlobalClippingPlane; + float2 View_FieldOfViewWideAngles; + float2 View_PrevFieldOfViewWideAngles; + float4 View_ViewRectMin; + float4 View_ViewSizeAndInvSize; + float4 View_BufferSizeAndInvSize; + float4 View_BufferBilinearUVMinMax; + int View_NumSceneColorMSAASamples; + float View_PreExposure; + float View_OneOverPreExposure; + float PrePadding_View_2076; + float4 View_DiffuseOverrideParameter; + float4 View_SpecularOverrideParameter; + float4 View_NormalOverrideParameter; + float2 View_RoughnessOverrideParameter; + float View_PrevFrameGameTime; + float View_PrevFrameRealTime; + float View_OutOfBoundsMask; + float PrePadding_View_2148; + float PrePadding_View_2152; + float PrePadding_View_2156; + packed_float3 View_WorldCameraMovementSinceLastFrame; + float View_CullingSign; + float View_NearPlane; + float View_AdaptiveTessellationFactor; + float View_GameTime; + float View_RealTime; + float View_DeltaTime; + float View_MaterialTextureMipBias; + float View_MaterialTextureDerivativeMultiply; + uint View_Random; + uint View_FrameNumber; + uint View_StateFrameIndexMod8; + uint View_StateFrameIndex; + float View_CameraCut; + float View_UnlitViewmodeMask; + float PrePadding_View_2228; + float PrePadding_View_2232; + float PrePadding_View_2236; + float4 View_DirectionalLightColor; + packed_float3 View_DirectionalLightDirection; + float PrePadding_View_2268; + float4 View_TranslucencyLightingVolumeMin[2]; + float4 View_TranslucencyLightingVolumeInvSize[2]; + float4 View_TemporalAAParams; + float4 View_CircleDOFParams; + float View_DepthOfFieldSensorWidth; + float View_DepthOfFieldFocalDistance; + float View_DepthOfFieldScale; + float View_DepthOfFieldFocalLength; + float View_DepthOfFieldFocalRegion; + float View_DepthOfFieldNearTransitionRegion; + float View_DepthOfFieldFarTransitionRegion; + float View_MotionBlurNormalizedToPixel; + float View_bSubsurfacePostprocessEnabled; + float View_GeneralPurposeTweak; + float View_DemosaicVposOffset; + float PrePadding_View_2412; + packed_float3 View_IndirectLightingColorScale; + float View_HDR32bppEncodingMode; + packed_float3 View_AtmosphericFogSunDirection; + float View_AtmosphericFogSunPower; + float View_AtmosphericFogPower; + float View_AtmosphericFogDensityScale; + float View_AtmosphericFogDensityOffset; + float View_AtmosphericFogGroundOffset; + float View_AtmosphericFogDistanceScale; + float View_AtmosphericFogAltitudeScale; + float View_AtmosphericFogHeightScaleRayleigh; + float View_AtmosphericFogStartDistance; + float View_AtmosphericFogDistanceOffset; + float View_AtmosphericFogSunDiscScale; + float View_AtmosphericFogSunDiscHalfApexAngleRadian; + float PrePadding_View_2492; + float4 View_AtmosphericFogSunDiscLuminance; + uint View_AtmosphericFogRenderMask; + uint View_AtmosphericFogInscatterAltitudeSampleNum; + uint PrePadding_View_2520; + uint PrePadding_View_2524; + float4 View_AtmosphericFogSunColor; + packed_float3 View_NormalCurvatureToRoughnessScaleBias; + float View_RenderingReflectionCaptureMask; + float4 View_AmbientCubemapTint; + float View_AmbientCubemapIntensity; + float View_SkyLightParameters; + float PrePadding_View_2584; + float PrePadding_View_2588; + float4 View_SkyLightColor; + float4 View_SkyIrradianceEnvironmentMap[7]; + float View_MobilePreviewMode; + float View_HMDEyePaddingOffset; + float View_ReflectionCubemapMaxMip; + float View_ShowDecalsMask; + uint View_DistanceFieldAOSpecularOcclusionMode; + float View_IndirectCapsuleSelfShadowingIntensity; + float PrePadding_View_2744; + float PrePadding_View_2748; + packed_float3 View_ReflectionEnvironmentRoughnessMixingScaleBiasAndLargestWeight; + int View_StereoPassIndex; + float4 View_GlobalVolumeCenterAndExtent[4]; + float4 View_GlobalVolumeWorldToUVAddAndMul[4]; + float View_GlobalVolumeDimension; + float View_GlobalVolumeTexelSize; + float View_MaxGlobalDistance; + float PrePadding_View_2908; + int2 View_CursorPosition; + float View_bCheckerboardSubsurfaceProfileRendering; + float PrePadding_View_2924; + packed_float3 View_VolumetricFogInvGridSize; + float PrePadding_View_2940; + packed_float3 View_VolumetricFogGridZParams; + float PrePadding_View_2956; + float2 View_VolumetricFogSVPosToVolumeUV; + float View_VolumetricFogMaxDistance; + float PrePadding_View_2972; + packed_float3 View_VolumetricLightmapWorldToUVScale; + float PrePadding_View_2988; + packed_float3 View_VolumetricLightmapWorldToUVAdd; + float PrePadding_View_3004; + packed_float3 View_VolumetricLightmapIndirectionTextureSize; + float View_VolumetricLightmapBrickSize; + packed_float3 View_VolumetricLightmapBrickTexelSize; + float View_StereoIPD; + float View_IndirectLightingCacheShowFlag; + float View_EyeToPixelSpreadAngle; +}; + +struct type_PrimitiveDither +{ + float PrimitiveDither_LODFactor; +}; + +struct type_PrimitiveFade +{ + float2 PrimitiveFade_FadeTimeScaleBias; +}; + +struct type_Material +{ + float4 Material_VectorExpressions[9]; + float4 Material_ScalarExpressions[3]; +}; + +constant float _98 = {}; +constant float _103 = {}; + +struct main0_out +{ + float4 out_var_SV_Target0 [[color(0)]]; + float gl_FragDepth [[depth(less)]]; +}; + +struct main0_in +{ + float4 in_var_TEXCOORD6 [[user(locn0)]]; + float4 in_var_TEXCOORD7 [[user(locn1)]]; + float4 in_var_TEXCOORD10_centroid [[user(locn2)]]; + float4 in_var_TEXCOORD11_centroid [[user(locn3)]]; + float4 in_var_TEXCOORD0_0 [[user(locn4)]]; +}; + +fragment main0_out main0(main0_in in [[stage_in]], constant type_View& View [[buffer(0)]], constant type_PrimitiveDither& PrimitiveDither [[buffer(1)]], constant type_PrimitiveFade& PrimitiveFade [[buffer(2)]], constant type_Material& Material [[buffer(3)]], texture2d Material_Texture2D_0 [[texture(0)]], texture2d Material_Texture2D_3 [[texture(1)]], sampler Material_Texture2D_0Sampler [[sampler(0)]], sampler Material_Texture2D_3Sampler [[sampler(1)]], float4 gl_FragCoord [[position]]) +{ + main0_out out = {}; + spvUnsafeArray in_var_TEXCOORD0 = {}; + in_var_TEXCOORD0[0] = in.in_var_TEXCOORD0_0; + float2 _135 = gl_FragCoord.xy - View.View_ViewRectMin.xy; + float4 _140 = float4(_103, _103, gl_FragCoord.z, 1.0) * float4(gl_FragCoord.w); + float4 _144 = View.View_SVPositionToTranslatedWorld * float4(gl_FragCoord.xyz, 1.0); + float3 _148 = _144.xyz / float3(_144.w); + float3 _149 = _148 - float3(View.View_PreViewTranslation); + float3 _151 = normalize(-_148); + float3 _152 = _151 * float3x3(in.in_var_TEXCOORD10_centroid.xyz, cross(in.in_var_TEXCOORD11_centroid.xyz, in.in_var_TEXCOORD10_centroid.xyz) * float3(in.in_var_TEXCOORD11_centroid.w), in.in_var_TEXCOORD11_centroid.xyz); + float _170 = mix(Material.Material_ScalarExpressions[0].y, Material.Material_ScalarExpressions[0].z, fast::min(fast::max(abs(dot(_151, in.in_var_TEXCOORD11_centroid.xyz)), 0.0), 1.0)); + float _172 = 1.0 / _170; + float2 _174 = (float2(Material.Material_ScalarExpressions[0].x) * ((_152.xy * float2(-1.0)) / float2(_152.z))) * float2(_172); + float _180_copy; + float2 _183; + _183 = float2(0.0); + float _188; + float _211; + float2 _212; + float _180 = 1.0; + int _185 = 0; + float _187 = 1.0; + float _189 = 1.0; + for (;;) + { + if (float(_185) < (floor(_170) + 2.0)) + { + _188 = Material_Texture2D_0.sample(Material_Texture2D_0Sampler, (float2(in_var_TEXCOORD0[0].x, in_var_TEXCOORD0[0].y) + _183), gradient2d(dfdx(float2(in_var_TEXCOORD0[0].x, in_var_TEXCOORD0[0].y)), dfdy(float2(in_var_TEXCOORD0[0].x, in_var_TEXCOORD0[0].y)))).y; + if (_180 < _188) + { + float _201 = _188 - _180; + float _203 = _201 / ((_189 - _187) + _201); + _211 = (_189 * _203) + (_180 * (1.0 - _203)); + _212 = _183 - (float2(_203) * _174); + break; + } + _180_copy = _180; + _180 -= _172; + _183 += _174; + _185++; + _187 = _188; + _189 = _180_copy; + continue; + } + else + { + _211 = _98; + _212 = _183; + break; + } + } + float4 _218 = Material_Texture2D_0.sample(Material_Texture2D_0Sampler, (float2(in_var_TEXCOORD0[0].x, in_var_TEXCOORD0[0].y) + _212.xy), bias(View.View_MaterialTextureMipBias)); + float2 _229 = _135 + float2(View.View_TemporalAAParams.x); + float _237 = float((uint(_229.x) + (2u * uint(_229.y))) % 5u); + float2 _238 = _135 * float2(0.015625); + float4 _242 = Material_Texture2D_3.sample(Material_Texture2D_3Sampler, _238, bias(View.View_MaterialTextureMipBias)); + float4 _254 = Material_Texture2D_3.sample(Material_Texture2D_3Sampler, _238, bias(View.View_MaterialTextureMipBias)); + float3 _272 = float3(_212, (1.0 - _211) * Material.Material_ScalarExpressions[0].x); + float2 _275 = dfdx(float2(in_var_TEXCOORD0[0].x, in_var_TEXCOORD0[0].y)); + float2 _276 = abs(_275); + float3 _279 = dfdx(_149); + float2 _283 = dfdy(float2(in_var_TEXCOORD0[0].x, in_var_TEXCOORD0[0].y)); + float2 _284 = abs(_283); + float3 _287 = dfdy(_149); + if (PrimitiveDither.PrimitiveDither_LODFactor != 0.0) + { + if (abs(PrimitiveDither.PrimitiveDither_LODFactor) > 0.001000000047497451305389404296875) + { + float _317 = fract(cos(dot(floor(gl_FragCoord.xy), float2(347.834503173828125, 3343.28369140625))) * 1000.0); + if ((float((PrimitiveDither.PrimitiveDither_LODFactor < 0.0) ? ((PrimitiveDither.PrimitiveDither_LODFactor + 1.0) > _317) : (PrimitiveDither.PrimitiveDither_LODFactor < _317)) - 0.001000000047497451305389404296875) < 0.0) + { + discard_fragment(); + } + } + } + if ((((_218.z + ((fast::min(fast::max(1.0 - (_218.x * Material.Material_ScalarExpressions[2].y), 0.0), 1.0) + ((_237 + (_242.x * Material.Material_ScalarExpressions[2].z)) * 0.16666667163372039794921875)) + (-0.5))) * ((fast::clamp((View.View_RealTime * PrimitiveFade.PrimitiveFade_FadeTimeScaleBias.x) + PrimitiveFade.PrimitiveFade_FadeTimeScaleBias.y, 0.0, 1.0) + ((_237 + _254.x) * 0.16666667163372039794921875)) + (-0.5))) - 0.33329999446868896484375) < 0.0) + { + discard_fragment(); + } + float2 _351 = ((((in.in_var_TEXCOORD6.xy / float2(in.in_var_TEXCOORD6.w)) - View.View_TemporalAAJitter.xy) - ((in.in_var_TEXCOORD7.xy / float2(in.in_var_TEXCOORD7.w)) - View.View_TemporalAAJitter.zw)) * float2(0.2495000064373016357421875)) + float2(0.49999237060546875); + out.gl_FragDepth = fast::min(_140.z / (_140.w + (sqrt(dot(_272, _272)) / (fast::max(sqrt(dot(_276, _276)) / sqrt(dot(_279, _279)), sqrt(dot(_284, _284)) / sqrt(dot(_287, _287))) / abs(dot(float3x3(View.View_ViewToTranslatedWorld[0].xyz, View.View_ViewToTranslatedWorld[1].xyz, View.View_ViewToTranslatedWorld[2].xyz) * float3(0.0, 0.0, 1.0), _151))))), gl_FragCoord.z); + out.out_var_SV_Target0 = float4(_351.x, _351.y, float2(0.0).x, float2(0.0).y); + return out; +} + diff --git a/third_party/spirv-cross/reference/shaders-ue4-no-opt/asm/vert/loop-accesschain-writethrough.asm.invalid.vert b/third_party/spirv-cross/reference/shaders-ue4-no-opt/asm/vert/loop-accesschain-writethrough.asm.invalid.vert new file mode 100644 index 0000000000..b1298b7e68 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-ue4-no-opt/asm/vert/loop-accesschain-writethrough.asm.invalid.vert @@ -0,0 +1,122 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + +#include +#include + +using namespace metal; + +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +struct type_Globals +{ + float4 ViewportSize; + float ScatteringScaling; + float CocRadiusToCircumscribedRadius; +}; + +struct type_StructuredBuffer_v4float +{ + float4 _m0[1]; +}; + +struct main0_out +{ + float2 out_var_TEXCOORD0 [[user(locn0)]]; + float4 out_var_TEXCOORD1 [[user(locn1)]]; + float4 out_var_TEXCOORD2 [[user(locn2)]]; + float4 out_var_TEXCOORD3 [[user(locn3)]]; + float4 out_var_TEXCOORD4 [[user(locn4)]]; + float4 out_var_TEXCOORD5 [[user(locn5)]]; + float4 out_var_TEXCOORD6 [[user(locn6)]]; + float4 gl_Position [[position]]; +}; + +vertex main0_out main0(constant type_Globals& _Globals [[buffer(0)]], const device type_StructuredBuffer_v4float& ScatterDrawList [[buffer(1)]], uint gl_VertexIndex [[vertex_id]], uint gl_InstanceIndex [[instance_id]]) +{ + main0_out out = {}; + uint _66 = gl_VertexIndex / 4u; + uint _68 = gl_VertexIndex - (_66 * 4u); + uint _70 = (16u * gl_InstanceIndex) + _66; + float _72; + _72 = 0.0; + spvUnsafeArray _61; + spvUnsafeArray _62; + spvUnsafeArray _63; + float _73; + uint _75 = 0u; + for (;;) + { + if (_75 < 4u) + { + uint _82 = ((5u * _70) + _75) + 1u; + _61[_75] = float4(ScatterDrawList._m0[_82].xyz, 0.0); + _62[_75] = ScatterDrawList._m0[_82].w; + if (_75 == 0u) + { + _73 = _62[_75]; + } + else + { + _73 = fast::max(_72, _62[_75]); + } + _63[_75].x = (-0.5) / _62[_75]; + _63[_75].y = (0.5 * _62[_75]) + 0.5; + _72 = _73; + _75++; + continue; + } + else + { + break; + } + } + float2 _144 = float2(_Globals.ScatteringScaling) * ScatterDrawList._m0[5u * _70].xy; + float2 _173 = (((float2((_72 * _Globals.CocRadiusToCircumscribedRadius) + 1.0) * ((float2(float(_68 % 2u), float(_68 / 2u)) * float2(2.0)) - float2(1.0))) + _144) + float2(0.5)) * _Globals.ViewportSize.zw; + out.out_var_TEXCOORD0 = _144; + out.out_var_TEXCOORD1 = float4(_61[0].xyz, _62[0]); + out.out_var_TEXCOORD2 = float4(_61[1].xyz, _62[1]); + out.out_var_TEXCOORD3 = float4(_61[2].xyz, _62[2]); + out.out_var_TEXCOORD4 = float4(_61[3].xyz, _62[3]); + out.out_var_TEXCOORD5 = float4(_63[0].x, _63[0].y, _63[1].x, _63[1].y); + out.out_var_TEXCOORD6 = float4(_63[2].x, _63[2].y, _63[3].x, _63[3].y); + out.gl_Position = float4((_173.x * 2.0) - 1.0, 1.0 - (_173.y * 2.0), 0.0, 1.0); + return out; +} + diff --git a/third_party/spirv-cross/reference/shaders-ue4/asm/frag/depth-compare.asm.frag b/third_party/spirv-cross/reference/shaders-ue4/asm/frag/depth-compare.asm.frag new file mode 100644 index 0000000000..bdeccc2f55 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-ue4/asm/frag/depth-compare.asm.frag @@ -0,0 +1,314 @@ +#include +#include + +using namespace metal; + +struct type_View +{ + float4x4 View_TranslatedWorldToClip; + float4x4 View_WorldToClip; + float4x4 View_TranslatedWorldToView; + float4x4 View_ViewToTranslatedWorld; + float4x4 View_TranslatedWorldToCameraView; + float4x4 View_CameraViewToTranslatedWorld; + float4x4 View_ViewToClip; + float4x4 View_ViewToClipNoAA; + float4x4 View_ClipToView; + float4x4 View_ClipToTranslatedWorld; + float4x4 View_SVPositionToTranslatedWorld; + float4x4 View_ScreenToWorld; + float4x4 View_ScreenToTranslatedWorld; + packed_float3 View_ViewForward; + float PrePadding_View_844; + packed_float3 View_ViewUp; + float PrePadding_View_860; + packed_float3 View_ViewRight; + float PrePadding_View_876; + packed_float3 View_HMDViewNoRollUp; + float PrePadding_View_892; + packed_float3 View_HMDViewNoRollRight; + float PrePadding_View_908; + float4 View_InvDeviceZToWorldZTransform; + float4 View_ScreenPositionScaleBias; + packed_float3 View_WorldCameraOrigin; + float PrePadding_View_956; + packed_float3 View_TranslatedWorldCameraOrigin; + float PrePadding_View_972; + packed_float3 View_WorldViewOrigin; + float PrePadding_View_988; + packed_float3 View_PreViewTranslation; + float PrePadding_View_1004; + float4x4 View_PrevProjection; + float4x4 View_PrevViewProj; + float4x4 View_PrevViewRotationProj; + float4x4 View_PrevViewToClip; + float4x4 View_PrevClipToView; + float4x4 View_PrevTranslatedWorldToClip; + float4x4 View_PrevTranslatedWorldToView; + float4x4 View_PrevViewToTranslatedWorld; + float4x4 View_PrevTranslatedWorldToCameraView; + float4x4 View_PrevCameraViewToTranslatedWorld; + packed_float3 View_PrevWorldCameraOrigin; + float PrePadding_View_1660; + packed_float3 View_PrevWorldViewOrigin; + float PrePadding_View_1676; + packed_float3 View_PrevPreViewTranslation; + float PrePadding_View_1692; + float4x4 View_PrevInvViewProj; + float4x4 View_PrevScreenToTranslatedWorld; + float4x4 View_ClipToPrevClip; + float4 View_TemporalAAJitter; + float4 View_GlobalClippingPlane; + float2 View_FieldOfViewWideAngles; + float2 View_PrevFieldOfViewWideAngles; + float4 View_ViewRectMin; + float4 View_ViewSizeAndInvSize; + float4 View_BufferSizeAndInvSize; + float4 View_BufferBilinearUVMinMax; + int View_NumSceneColorMSAASamples; + float View_PreExposure; + float View_OneOverPreExposure; + float PrePadding_View_2012; + float4 View_DiffuseOverrideParameter; + float4 View_SpecularOverrideParameter; + float4 View_NormalOverrideParameter; + float2 View_RoughnessOverrideParameter; + float View_PrevFrameGameTime; + float View_PrevFrameRealTime; + float View_OutOfBoundsMask; + float PrePadding_View_2084; + float PrePadding_View_2088; + float PrePadding_View_2092; + packed_float3 View_WorldCameraMovementSinceLastFrame; + float View_CullingSign; + float View_NearPlane; + float View_AdaptiveTessellationFactor; + float View_GameTime; + float View_RealTime; + float View_DeltaTime; + float View_MaterialTextureMipBias; + float View_MaterialTextureDerivativeMultiply; + uint View_Random; + uint View_FrameNumber; + uint View_StateFrameIndexMod8; + uint View_StateFrameIndex; + float View_CameraCut; + float View_UnlitViewmodeMask; + float PrePadding_View_2164; + float PrePadding_View_2168; + float PrePadding_View_2172; + float4 View_DirectionalLightColor; + packed_float3 View_DirectionalLightDirection; + float PrePadding_View_2204; + float4 View_TranslucencyLightingVolumeMin[2]; + float4 View_TranslucencyLightingVolumeInvSize[2]; + float4 View_TemporalAAParams; + float4 View_CircleDOFParams; + float View_DepthOfFieldSensorWidth; + float View_DepthOfFieldFocalDistance; + float View_DepthOfFieldScale; + float View_DepthOfFieldFocalLength; + float View_DepthOfFieldFocalRegion; + float View_DepthOfFieldNearTransitionRegion; + float View_DepthOfFieldFarTransitionRegion; + float View_MotionBlurNormalizedToPixel; + float View_bSubsurfacePostprocessEnabled; + float View_GeneralPurposeTweak; + float View_DemosaicVposOffset; + float PrePadding_View_2348; + packed_float3 View_IndirectLightingColorScale; + float View_HDR32bppEncodingMode; + packed_float3 View_AtmosphericFogSunDirection; + float View_AtmosphericFogSunPower; + float View_AtmosphericFogPower; + float View_AtmosphericFogDensityScale; + float View_AtmosphericFogDensityOffset; + float View_AtmosphericFogGroundOffset; + float View_AtmosphericFogDistanceScale; + float View_AtmosphericFogAltitudeScale; + float View_AtmosphericFogHeightScaleRayleigh; + float View_AtmosphericFogStartDistance; + float View_AtmosphericFogDistanceOffset; + float View_AtmosphericFogSunDiscScale; + uint View_AtmosphericFogRenderMask; + uint View_AtmosphericFogInscatterAltitudeSampleNum; + float4 View_AtmosphericFogSunColor; + packed_float3 View_NormalCurvatureToRoughnessScaleBias; + float View_RenderingReflectionCaptureMask; + float4 View_AmbientCubemapTint; + float View_AmbientCubemapIntensity; + float View_SkyLightParameters; + float PrePadding_View_2488; + float PrePadding_View_2492; + float4 View_SkyLightColor; + float4 View_SkyIrradianceEnvironmentMap[7]; + float View_MobilePreviewMode; + float View_HMDEyePaddingOffset; + float View_ReflectionCubemapMaxMip; + float View_ShowDecalsMask; + uint View_DistanceFieldAOSpecularOcclusionMode; + float View_IndirectCapsuleSelfShadowingIntensity; + float PrePadding_View_2648; + float PrePadding_View_2652; + packed_float3 View_ReflectionEnvironmentRoughnessMixingScaleBiasAndLargestWeight; + int View_StereoPassIndex; + float4 View_GlobalVolumeCenterAndExtent[4]; + float4 View_GlobalVolumeWorldToUVAddAndMul[4]; + float View_GlobalVolumeDimension; + float View_GlobalVolumeTexelSize; + float View_MaxGlobalDistance; + float View_bCheckerboardSubsurfaceProfileRendering; + packed_float3 View_VolumetricFogInvGridSize; + float PrePadding_View_2828; + packed_float3 View_VolumetricFogGridZParams; + float PrePadding_View_2844; + float2 View_VolumetricFogSVPosToVolumeUV; + float View_VolumetricFogMaxDistance; + float PrePadding_View_2860; + packed_float3 View_VolumetricLightmapWorldToUVScale; + float PrePadding_View_2876; + packed_float3 View_VolumetricLightmapWorldToUVAdd; + float PrePadding_View_2892; + packed_float3 View_VolumetricLightmapIndirectionTextureSize; + float View_VolumetricLightmapBrickSize; + packed_float3 View_VolumetricLightmapBrickTexelSize; + float View_StereoIPD; + float View_IndirectLightingCacheShowFlag; + float View_EyeToPixelSpreadAngle; +}; + +struct type_Globals +{ + float3 SoftTransitionScale; + float4x4 ShadowViewProjectionMatrices[6]; + float InvShadowmapResolution; + float ShadowFadeFraction; + float ShadowSharpen; + float4 LightPositionAndInvRadius; + float2 ProjectionDepthBiasParameters; + float4 PointLightDepthBiasAndProjParameters; +}; + +constant float4 _107 = {}; + +struct main0_out +{ + float4 out_var_SV_Target0 [[color(0)]]; +}; + +fragment main0_out main0(constant type_View& View [[buffer(0)]], constant type_Globals& _Globals [[buffer(1)]], texture2d SceneTexturesStruct_SceneDepthTexture [[texture(0)]], texture2d SceneTexturesStruct_GBufferATexture [[texture(1)]], texture2d SceneTexturesStruct_GBufferBTexture [[texture(2)]], texture2d SceneTexturesStruct_GBufferDTexture [[texture(3)]], depthcube ShadowDepthCubeTexture [[texture(4)]], texture2d SSProfilesTexture [[texture(5)]], sampler SceneTexturesStruct_SceneDepthTextureSampler [[sampler(0)]], sampler SceneTexturesStruct_GBufferATextureSampler [[sampler(1)]], sampler SceneTexturesStruct_GBufferBTextureSampler [[sampler(2)]], sampler SceneTexturesStruct_GBufferDTextureSampler [[sampler(3)]], sampler ShadowDepthTextureSampler [[sampler(4)]], sampler ShadowDepthCubeTextureSampler [[sampler(5)]], float4 gl_FragCoord [[position]]) +{ + main0_out out = {}; + float2 _114 = gl_FragCoord.xy * View.View_BufferSizeAndInvSize.zw; + float4 _118 = SceneTexturesStruct_SceneDepthTexture.sample(SceneTexturesStruct_SceneDepthTextureSampler, _114, level(0.0)); + float _119 = _118.x; + float _133 = ((_119 * View.View_InvDeviceZToWorldZTransform.x) + View.View_InvDeviceZToWorldZTransform.y) + (1.0 / ((_119 * View.View_InvDeviceZToWorldZTransform.z) - View.View_InvDeviceZToWorldZTransform.w)); + float4 _147 = View.View_ScreenToWorld * float4(((_114 - View.View_ScreenPositionScaleBias.wz) / View.View_ScreenPositionScaleBias.xy) * float2(_133), _133, 1.0); + float3 _148 = _147.xyz; + float3 _152 = _Globals.LightPositionAndInvRadius.xyz - _148; + float _158 = length(_152); + bool _160 = (_158 * _Globals.LightPositionAndInvRadius.w) < 1.0; + float _207; + if (_160) + { + float3 _165 = abs(_152); + float _166 = _165.x; + float _167 = _165.y; + float _168 = _165.z; + float _170 = fast::max(_166, fast::max(_167, _168)); + int _189; + if (_170 == _166) + { + _189 = (_166 == _152.x) ? 0 : 1; + } + else + { + int _185; + if (_170 == _167) + { + _185 = (_167 == _152.y) ? 2 : 3; + } + else + { + _185 = (_168 == _152.z) ? 4 : 5; + } + _189 = _185; + } + float4 _196 = _Globals.ShadowViewProjectionMatrices[_189] * float4(_147.xyz, 1.0); + float _198 = _196.w; + _207 = ShadowDepthCubeTexture.sample_compare(ShadowDepthCubeTextureSampler, (_152 / float3(_158)), (_196.z / _198) + ((-_Globals.PointLightDepthBiasAndProjParameters.x) / _198), level(0.0)); + } + else + { + _207 = 1.0; + } + float _213 = fast::clamp(((_207 - 0.5) * _Globals.ShadowSharpen) + 0.5, 0.0, 1.0); + float _218 = sqrt(mix(1.0, _213 * _213, _Globals.ShadowFadeFraction)); + float4 _219 = _107; + _219.z = _218; + float3 _236 = normalize((SceneTexturesStruct_GBufferATexture.sample(SceneTexturesStruct_GBufferATextureSampler, _114, level(0.0)).xyz * float3(2.0)) - float3(1.0)); + uint _240 = uint(round(SceneTexturesStruct_GBufferBTexture.sample(SceneTexturesStruct_GBufferBTextureSampler, _114, level(0.0)).w * 255.0)); + bool _248 = (_240 & 15u) == 5u; + float _448; + if (_248) + { + float4 _260 = SSProfilesTexture.read(uint2(int3(1, int(uint((select(float4(0.0), SceneTexturesStruct_GBufferDTexture.sample(SceneTexturesStruct_GBufferDTextureSampler, _114, level(0.0)), bool4(!(((_240 & 4294967280u) & 16u) != 0u))).x * 255.0) + 0.5)), 0).xy), 0); + float _263 = _260.y * 0.5; + float _274 = pow(fast::clamp(dot(-(_152 * float3(rsqrt(dot(_152, _152)))), _236), 0.0, 1.0), 1.0); + float _445; + if (_160) + { + float3 _278 = _152 / float3(_158); + float3 _280 = normalize(cross(_278, float3(0.0, 0.0, 1.0))); + float3 _284 = float3(_Globals.InvShadowmapResolution); + float3 _285 = _280 * _284; + float3 _286 = cross(_280, _278) * _284; + float3 _287 = abs(_278); + float _288 = _287.x; + float _289 = _287.y; + float _290 = _287.z; + float _292 = fast::max(_288, fast::max(_289, _290)); + int _311; + if (_292 == _288) + { + _311 = (_288 == _278.x) ? 0 : 1; + } + else + { + int _307; + if (_292 == _289) + { + _307 = (_289 == _278.y) ? 2 : 3; + } + else + { + _307 = (_290 == _278.z) ? 4 : 5; + } + _311 = _307; + } + float4 _318 = _Globals.ShadowViewProjectionMatrices[_311] * float4(_148 - (_236 * float3(_263)), 1.0); + float _323 = _260.x * (10.0 / _Globals.LightPositionAndInvRadius.w); + float _329 = (1.0 / (((_318.z / _318.w) * _Globals.PointLightDepthBiasAndProjParameters.z) - _Globals.PointLightDepthBiasAndProjParameters.w)) * _Globals.LightPositionAndInvRadius.w; + float _342 = (_329 - ((1.0 / ((float4(ShadowDepthCubeTexture.sample(ShadowDepthTextureSampler, (_278 + (_286 * float3(2.5))), level(0.0))).x * _Globals.PointLightDepthBiasAndProjParameters.z) - _Globals.PointLightDepthBiasAndProjParameters.w)) * _Globals.LightPositionAndInvRadius.w)) * _323; + float _364 = (_329 - ((1.0 / ((float4(ShadowDepthCubeTexture.sample(ShadowDepthTextureSampler, ((_278 + (_285 * float3(2.3776409626007080078125))) + (_286 * float3(0.77254199981689453125))), level(0.0))).x * _Globals.PointLightDepthBiasAndProjParameters.z) - _Globals.PointLightDepthBiasAndProjParameters.w)) * _Globals.LightPositionAndInvRadius.w)) * _323; + float _387 = (_329 - ((1.0 / ((float4(ShadowDepthCubeTexture.sample(ShadowDepthTextureSampler, ((_278 + (_285 * float3(1.46946299076080322265625))) + (_286 * float3(-2.0225429534912109375))), level(0.0))).x * _Globals.PointLightDepthBiasAndProjParameters.z) - _Globals.PointLightDepthBiasAndProjParameters.w)) * _Globals.LightPositionAndInvRadius.w)) * _323; + float _410 = (_329 - ((1.0 / ((float4(ShadowDepthCubeTexture.sample(ShadowDepthTextureSampler, ((_278 + (_285 * float3(-1.46946299076080322265625))) + (_286 * float3(-2.02254199981689453125))), level(0.0))).x * _Globals.PointLightDepthBiasAndProjParameters.z) - _Globals.PointLightDepthBiasAndProjParameters.w)) * _Globals.LightPositionAndInvRadius.w)) * _323; + float _433 = (_329 - ((1.0 / ((float4(ShadowDepthCubeTexture.sample(ShadowDepthTextureSampler, ((_278 + (_285 * float3(-2.3776409626007080078125))) + (_286 * float3(0.772543013095855712890625))), level(0.0))).x * _Globals.PointLightDepthBiasAndProjParameters.z) - _Globals.PointLightDepthBiasAndProjParameters.w)) * _Globals.LightPositionAndInvRadius.w)) * _323; + _445 = (((((fast::clamp(abs((_342 > 0.0) ? (_342 + _263) : fast::max(0.0, (_342 * _274) + _263)), 0.1500000059604644775390625, 5.0) + 0.25) + (fast::clamp(abs((_364 > 0.0) ? (_364 + _263) : fast::max(0.0, (_364 * _274) + _263)), 0.1500000059604644775390625, 5.0) + 0.25)) + (fast::clamp(abs((_387 > 0.0) ? (_387 + _263) : fast::max(0.0, (_387 * _274) + _263)), 0.1500000059604644775390625, 5.0) + 0.25)) + (fast::clamp(abs((_410 > 0.0) ? (_410 + _263) : fast::max(0.0, (_410 * _274) + _263)), 0.1500000059604644775390625, 5.0) + 0.25)) + (fast::clamp(abs((_433 > 0.0) ? (_433 + _263) : fast::max(0.0, (_433 * _274) + _263)), 0.1500000059604644775390625, 5.0) + 0.25)) * 0.20000000298023223876953125; + } + else + { + _445 = 1.0; + } + _448 = 1.0 - (_445 * 0.20000000298023223876953125); + } + else + { + _448 = 1.0; + } + float4 _451 = float4(float3(1.0).x, float3(1.0).y, _219.z, float3(1.0).z); + _451.w = _248 ? sqrt(_448) : _218; + out.out_var_SV_Target0 = _451; + return out; +} + diff --git a/third_party/spirv-cross/reference/shaders-ue4/asm/frag/global-constant-arrays.asm.frag b/third_party/spirv-cross/reference/shaders-ue4/asm/frag/global-constant-arrays.asm.frag new file mode 100644 index 0000000000..210d4f98d1 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-ue4/asm/frag/global-constant-arrays.asm.frag @@ -0,0 +1,1365 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + +#include +#include + +using namespace metal; + +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +struct type_Globals +{ + float4 MappingPolynomial; + float3 InverseGamma; + float4 ColorMatrixR_ColorCurveCd1; + float4 ColorMatrixG_ColorCurveCd3Cm3; + float4 ColorMatrixB_ColorCurveCm2; + float4 ColorCurve_Cm0Cd0_Cd2_Ch0Cm1_Ch3; + float4 ColorCurve_Ch1_Ch2; + float4 ColorShadow_Luma; + float4 ColorShadow_Tint1; + float4 ColorShadow_Tint2; + float FilmSlope; + float FilmToe; + float FilmShoulder; + float FilmBlackClip; + float FilmWhiteClip; + packed_float3 ColorScale; + float4 OverlayColor; + float WhiteTemp; + float WhiteTint; + float4 ColorSaturation; + float4 ColorContrast; + float4 ColorGamma; + float4 ColorGain; + float4 ColorOffset; + float4 ColorSaturationShadows; + float4 ColorContrastShadows; + float4 ColorGammaShadows; + float4 ColorGainShadows; + float4 ColorOffsetShadows; + float4 ColorSaturationMidtones; + float4 ColorContrastMidtones; + float4 ColorGammaMidtones; + float4 ColorGainMidtones; + float4 ColorOffsetMidtones; + float4 ColorSaturationHighlights; + float4 ColorContrastHighlights; + float4 ColorGammaHighlights; + float4 ColorGainHighlights; + float4 ColorOffsetHighlights; + float ColorCorrectionShadowsMax; + float ColorCorrectionHighlightsMin; + uint OutputDevice; + uint OutputGamut; + float BlueCorrection; + float ExpandGamut; +}; + +constant spvUnsafeArray _475 = spvUnsafeArray({ -4.0, -4.0, -3.1573765277862548828125, -0.485249996185302734375, 1.84773242473602294921875, 1.84773242473602294921875 }); +constant spvUnsafeArray _476 = spvUnsafeArray({ -0.718548238277435302734375, 2.0810306072235107421875, 3.66812419891357421875, 4.0, 4.0, 4.0 }); +constant spvUnsafeArray _479 = spvUnsafeArray({ -4.97062206268310546875, -3.0293781757354736328125, -2.1261999607086181640625, -1.5104999542236328125, -1.0578000545501708984375, -0.4668000042438507080078125, 0.11937999725341796875, 0.7088134288787841796875, 1.2911865711212158203125, 1.2911865711212158203125 }); +constant spvUnsafeArray _480 = spvUnsafeArray({ 0.80891323089599609375, 1.19108676910400390625, 1.5683000087738037109375, 1.94830000400543212890625, 2.308300018310546875, 2.63840007781982421875, 2.85949993133544921875, 2.9872608184814453125, 3.0127391815185546875, 3.0127391815185546875 }); +constant spvUnsafeArray _482 = spvUnsafeArray({ -2.3010299205780029296875, -2.3010299205780029296875, -1.9312000274658203125, -1.5204999446868896484375, -1.0578000545501708984375, -0.4668000042438507080078125, 0.11937999725341796875, 0.7088134288787841796875, 1.2911865711212158203125, 1.2911865711212158203125 }); +constant spvUnsafeArray _483 = spvUnsafeArray({ 0.801995217800140380859375, 1.19800484180450439453125, 1.5943000316619873046875, 1.99730002880096435546875, 2.3782999515533447265625, 2.7683999538421630859375, 3.0515000820159912109375, 3.2746293544769287109375, 3.32743072509765625, 3.32743072509765625 }); + +constant float3 _391 = {}; + +struct main0_out +{ + float4 out_var_SV_Target0 [[color(0)]]; +}; + +struct main0_in +{ + float2 in_var_TEXCOORD0 [[user(locn0), center_no_perspective]]; +}; + +fragment main0_out main0(main0_in in [[stage_in]], constant type_Globals& _Globals [[buffer(0)]], uint gl_Layer [[render_target_array_index]]) +{ + main0_out out = {}; + float3x3 _546 = float3x3(float3(0.41245639324188232421875, 0.3575761020183563232421875, 0.180437505245208740234375), float3(0.21267290413379669189453125, 0.715152204036712646484375, 0.072175003588199615478515625), float3(0.01933390088379383087158203125, 0.119191996753215789794921875, 0.950304090976715087890625)) * float3x3(float3(1.01303005218505859375, 0.0061053098179399967193603515625, -0.014971000142395496368408203125), float3(0.0076982299797236919403076171875, 0.99816501140594482421875, -0.005032029934227466583251953125), float3(-0.0028413101099431514739990234375, 0.0046851597726345062255859375, 0.92450702190399169921875)); + float3x3 _547 = _546 * float3x3(float3(1.6410233974456787109375, -0.324803292751312255859375, -0.23642469942569732666015625), float3(-0.663662850856781005859375, 1.6153316497802734375, 0.016756348311901092529296875), float3(0.01172189414501190185546875, -0.008284442126750946044921875, 0.98839485645294189453125)); + float3x3 _548 = float3x3(float3(0.662454187870025634765625, 0.1340042054653167724609375, 0.1561876833438873291015625), float3(0.272228717803955078125, 0.674081742763519287109375, 0.053689517080783843994140625), float3(-0.0055746496655046939849853515625, 0.0040607335977256298065185546875, 1.01033914089202880859375)) * float3x3(float3(0.98722398281097412109375, -0.0061132698319852352142333984375, 0.01595330052077770233154296875), float3(-0.007598360069096088409423828125, 1.00186002254486083984375, 0.0053300200961530208587646484375), float3(0.003072570078074932098388671875, -0.0050959498621523380279541015625, 1.0816800594329833984375)); + float3x3 _549 = _548 * float3x3(float3(3.2409698963165283203125, -1.53738319873809814453125, -0.4986107647418975830078125), float3(-0.96924364566802978515625, 1.875967502593994140625, 0.0415550582110881805419921875), float3(0.055630080401897430419921875, -0.2039769589900970458984375, 1.05697154998779296875)); + float3x3 _550 = float3x3(float3(0.952552378177642822265625, 0.0, 9.25), float3(0.3439664542675018310546875, 0.728166103363037109375, -0.07213254272937774658203125), float3(0.0, 0.0, 1.00882518291473388671875)) * float3x3(float3(1.6410233974456787109375, -0.324803292751312255859375, -0.23642469942569732666015625), float3(-0.663662850856781005859375, 1.6153316497802734375, 0.016756348311901092529296875), float3(0.01172189414501190185546875, -0.008284442126750946044921875, 0.98839485645294189453125)); + float3x3 _551 = float3x3(float3(0.662454187870025634765625, 0.1340042054653167724609375, 0.1561876833438873291015625), float3(0.272228717803955078125, 0.674081742763519287109375, 0.053689517080783843994140625), float3(-0.0055746496655046939849853515625, 0.0040607335977256298065185546875, 1.01033914089202880859375)) * float3x3(float3(1.04981100559234619140625, 0.0, -9.74845024757087230682373046875e-05), float3(-0.49590301513671875, 1.37331306934356689453125, 0.09824003279209136962890625), float3(0.0, 0.0, 0.991252005100250244140625)); + float3x3 _576; + for (;;) + { + if (_Globals.OutputGamut == 1u) + { + _576 = _548 * float3x3(float3(2.493396282196044921875, -0.931345880031585693359375, -0.4026944935321807861328125), float3(-0.829486787319183349609375, 1.76265966892242431640625, 0.02362460084259510040283203125), float3(0.0358506999909877777099609375, -0.076182700693607330322265625, 0.957014024257659912109375)); + break; + } + else + { + if (_Globals.OutputGamut == 2u) + { + _576 = _548 * float3x3(float3(1.71660840511322021484375, -0.3556621074676513671875, -0.253360092639923095703125), float3(-0.666682898998260498046875, 1.61647760868072509765625, 0.01576850004494190216064453125), float3(0.017642199993133544921875, -0.04277630150318145751953125, 0.94222867488861083984375)); + break; + } + else + { + if (_Globals.OutputGamut == 3u) + { + _576 = float3x3(float3(0.695452213287353515625, 0.140678703784942626953125, 0.16386906802654266357421875), float3(0.0447945632040500640869140625, 0.859671115875244140625, 0.095534317195415496826171875), float3(-0.0055258828215301036834716796875, 0.0040252101607620716094970703125, 1.00150072574615478515625)); + break; + } + else + { + if (_Globals.OutputGamut == 4u) + { + _576 = float3x3(float3(1.0, 0.0, 0.0), float3(0.0, 1.0, 0.0), float3(0.0, 0.0, 1.0)); + break; + } + else + { + _576 = _549; + break; + } + } + } + } + } + float3 _577 = float4((in.in_var_TEXCOORD0 - float2(0.015625)) * float2(1.03225803375244140625), float(gl_Layer) * 0.0322580635547637939453125, 0.0).xyz; + float3 _599; + if (_Globals.OutputDevice >= 3u) + { + float3 _591 = pow(_577, float3(0.0126833133399486541748046875)); + _599 = pow(fast::max(float3(0.0), _591 - float3(0.8359375)) / (float3(18.8515625) - (float3(18.6875) * _591)), float3(6.277394771575927734375)) * float3(10000.0); + } + else + { + _599 = (exp2((_577 - float3(0.434017598628997802734375)) * float3(14.0)) * float3(0.180000007152557373046875)) - (exp2(float3(-6.0762462615966796875)) * float3(0.180000007152557373046875)); + } + float _602 = _Globals.WhiteTemp * 1.00055634975433349609375; + float _616 = (_602 <= 7000.0) ? (0.24406300485134124755859375 + ((99.1100006103515625 + ((2967800.0 - (4604438528.0 / _Globals.WhiteTemp)) / _602)) / _602)) : (0.23703999817371368408203125 + ((247.4799957275390625 + ((1901800.0 - (2005284352.0 / _Globals.WhiteTemp)) / _602)) / _602)); + float _633 = ((0.860117733478546142578125 + (0.00015411825734190642833709716796875 * _Globals.WhiteTemp)) + ((1.2864121856637211749330163002014e-07 * _Globals.WhiteTemp) * _Globals.WhiteTemp)) / ((1.0 + (0.0008424202096648514270782470703125 * _Globals.WhiteTemp)) + ((7.0814513719597016461193561553955e-07 * _Globals.WhiteTemp) * _Globals.WhiteTemp)); + float _644 = ((0.317398726940155029296875 + (4.25 * _Globals.WhiteTemp)) + ((4.2048167614439080352894961833954e-08 * _Globals.WhiteTemp) * _Globals.WhiteTemp)) / ((1.0 - (2.8974181986995972692966461181641e-05 * _Globals.WhiteTemp)) + ((1.6145605741257895715534687042236e-07 * _Globals.WhiteTemp) * _Globals.WhiteTemp)); + float _649 = ((2.0 * _633) - (8.0 * _644)) + 4.0; + float2 _653 = float2((3.0 * _633) / _649, (2.0 * _644) / _649); + float2 _660 = normalize(float2(_633, _644)); + float _665 = _633 + (((-_660.y) * _Globals.WhiteTint) * 0.0500000007450580596923828125); + float _669 = _644 + ((_660.x * _Globals.WhiteTint) * 0.0500000007450580596923828125); + float _674 = ((2.0 * _665) - (8.0 * _669)) + 4.0; + float2 _680 = select(float2(_616, ((((-3.0) * _616) * _616) + (2.86999988555908203125 * _616)) - 0.2750000059604644775390625), _653, bool2(_Globals.WhiteTemp < 4000.0)) + (float2((3.0 * _665) / _674, (2.0 * _669) / _674) - _653); + float _681 = _680.x; + float _682 = _680.y; + float _683 = fast::max(_682, 1.0000000133514319600180897396058e-10); + float3 _685 = _391; + _685.x = _681 / _683; + float3 _686 = _685; + _686.y = 1.0; + float3 _690 = _686; + _690.z = ((1.0 - _681) - _682) / _683; + float _691 = fast::max(0.328999996185302734375, 1.0000000133514319600180897396058e-10); + float3 _693 = _391; + _693.x = 0.3127000033855438232421875 / _691; + float3 _694 = _693; + _694.y = 1.0; + float3 _696 = _694; + _696.z = 0.3582999706268310546875 / _691; + float3 _697 = _690 * float3x3(float3(0.89509999752044677734375, 0.2664000093936920166015625, -0.16140000522136688232421875), float3(-0.750199973583221435546875, 1.71350002288818359375, 0.0366999991238117218017578125), float3(0.0388999991118907928466796875, -0.06849999725818634033203125, 1.02960002422332763671875)); + float3 _698 = _696 * float3x3(float3(0.89509999752044677734375, 0.2664000093936920166015625, -0.16140000522136688232421875), float3(-0.750199973583221435546875, 1.71350002288818359375, 0.0366999991238117218017578125), float3(0.0388999991118907928466796875, -0.06849999725818634033203125, 1.02960002422332763671875)); + float3 _717 = (_599 * ((float3x3(float3(0.41245639324188232421875, 0.3575761020183563232421875, 0.180437505245208740234375), float3(0.21267290413379669189453125, 0.715152204036712646484375, 0.072175003588199615478515625), float3(0.01933390088379383087158203125, 0.119191996753215789794921875, 0.950304090976715087890625)) * ((float3x3(float3(0.89509999752044677734375, 0.2664000093936920166015625, -0.16140000522136688232421875), float3(-0.750199973583221435546875, 1.71350002288818359375, 0.0366999991238117218017578125), float3(0.0388999991118907928466796875, -0.06849999725818634033203125, 1.02960002422332763671875)) * float3x3(float3(_698.x / _697.x, 0.0, 0.0), float3(0.0, _698.y / _697.y, 0.0), float3(0.0, 0.0, _698.z / _697.z))) * float3x3(float3(0.986992895603179931640625, -0.14705429971218109130859375, 0.15996269881725311279296875), float3(0.4323053061962127685546875, 0.518360316753387451171875, 0.049291200935840606689453125), float3(-0.00852870009839534759521484375, 0.0400427989661693572998046875, 0.968486726284027099609375)))) * float3x3(float3(3.2409698963165283203125, -1.53738319873809814453125, -0.4986107647418975830078125), float3(-0.96924364566802978515625, 1.875967502593994140625, 0.0415550582110881805419921875), float3(0.055630080401897430419921875, -0.2039769589900970458984375, 1.05697154998779296875)))) * _547; + float3 _745; + if (_Globals.ColorShadow_Tint2.w != 0.0) + { + float _724 = dot(_717, float3(0.272228717803955078125, 0.674081742763519287109375, 0.053689517080783843994140625)); + float3 _727 = (_717 / float3(_724)) - float3(1.0); + _745 = mix(_717, _717 * (_549 * (float3x3(float3(0.544169127941131591796875, 0.23959259688854217529296875, 0.16669429838657379150390625), float3(0.23946559429168701171875, 0.702153027057647705078125, 0.058381401002407073974609375), float3(-0.0023439000360667705535888671875, 0.0361833982169628143310546875, 1.05521833896636962890625)) * float3x3(float3(1.6410233974456787109375, -0.324803292751312255859375, -0.23642469942569732666015625), float3(-0.663662850856781005859375, 1.6153316497802734375, 0.016756348311901092529296875), float3(0.01172189414501190185546875, -0.008284442126750946044921875, 0.98839485645294189453125)))), float3((1.0 - exp2((-4.0) * dot(_727, _727))) * (1.0 - exp2((((-4.0) * _Globals.ExpandGamut) * _724) * _724)))); + } + else + { + _745 = _717; + } + float _746 = dot(_745, float3(0.272228717803955078125, 0.674081742763519287109375, 0.053689517080783843994140625)); + float4 _751 = _Globals.ColorSaturationShadows * _Globals.ColorSaturation; + float4 _756 = _Globals.ColorContrastShadows * _Globals.ColorContrast; + float4 _761 = _Globals.ColorGammaShadows * _Globals.ColorGamma; + float4 _766 = _Globals.ColorGainShadows * _Globals.ColorGain; + float4 _771 = _Globals.ColorOffsetShadows + _Globals.ColorOffset; + float3 _772 = float3(_746); + float _804 = smoothstep(0.0, _Globals.ColorCorrectionShadowsMax, _746); + float4 _808 = _Globals.ColorSaturationHighlights * _Globals.ColorSaturation; + float4 _811 = _Globals.ColorContrastHighlights * _Globals.ColorContrast; + float4 _814 = _Globals.ColorGammaHighlights * _Globals.ColorGamma; + float4 _817 = _Globals.ColorGainHighlights * _Globals.ColorGain; + float4 _820 = _Globals.ColorOffsetHighlights + _Globals.ColorOffset; + float _852 = smoothstep(_Globals.ColorCorrectionHighlightsMin, 1.0, _746); + float4 _855 = _Globals.ColorSaturationMidtones * _Globals.ColorSaturation; + float4 _858 = _Globals.ColorContrastMidtones * _Globals.ColorContrast; + float4 _861 = _Globals.ColorGammaMidtones * _Globals.ColorGamma; + float4 _864 = _Globals.ColorGainMidtones * _Globals.ColorGain; + float4 _867 = _Globals.ColorOffsetMidtones + _Globals.ColorOffset; + float3 _905 = ((((pow(pow(fast::max(float3(0.0), mix(_772, _745, _751.xyz * float3(_751.w))) * float3(5.5555553436279296875), _756.xyz * float3(_756.w)) * float3(0.180000007152557373046875), float3(1.0) / (_761.xyz * float3(_761.w))) * (_766.xyz * float3(_766.w))) + (_771.xyz + float3(_771.w))) * float3(1.0 - _804)) + (((pow(pow(fast::max(float3(0.0), mix(_772, _745, _855.xyz * float3(_855.w))) * float3(5.5555553436279296875), _858.xyz * float3(_858.w)) * float3(0.180000007152557373046875), float3(1.0) / (_861.xyz * float3(_861.w))) * (_864.xyz * float3(_864.w))) + (_867.xyz + float3(_867.w))) * float3(_804 - _852))) + (((pow(pow(fast::max(float3(0.0), mix(_772, _745, _808.xyz * float3(_808.w))) * float3(5.5555553436279296875), _811.xyz * float3(_811.w)) * float3(0.180000007152557373046875), float3(1.0) / (_814.xyz * float3(_814.w))) * (_817.xyz * float3(_817.w))) + (_820.xyz + float3(_820.w))) * float3(_852)); + float3 _906 = _905 * _549; + float3 _914 = float3(_Globals.BlueCorrection); + float3 _916 = mix(_905, _905 * ((_551 * float3x3(float3(0.940437257289886474609375, -0.01830687932670116424560546875, 0.07786960899829864501953125), float3(0.008378696627914905548095703125, 0.82866001129150390625, 0.162961304187774658203125), float3(0.0005471261101774871349334716796875, -0.00088337459601461887359619140625, 1.00033628940582275390625))) * _550), _914) * _551; + float _917 = _916.x; + float _918 = _916.y; + float _920 = _916.z; + float _923 = fast::max(fast::max(_917, _918), _920); + float _928 = (fast::max(_923, 1.0000000133514319600180897396058e-10) - fast::max(fast::min(fast::min(_917, _918), _920), 1.0000000133514319600180897396058e-10)) / fast::max(_923, 0.00999999977648258209228515625); + float _941 = ((_920 + _918) + _917) + (1.75 * sqrt(((_920 * (_920 - _918)) + (_918 * (_918 - _917))) + (_917 * (_917 - _920)))); + float _942 = _941 * 0.3333333432674407958984375; + float _943 = _928 - 0.4000000059604644775390625; + float _948 = fast::max(1.0 - abs(_943 * 2.5), 0.0); + float _956 = (1.0 + (float(int(sign(_943 * 5.0))) * (1.0 - (_948 * _948)))) * 0.02500000037252902984619140625; + float _969; + if (_942 <= 0.053333334624767303466796875) + { + _969 = _956; + } + else + { + float _968; + if (_942 >= 0.1599999964237213134765625) + { + _968 = 0.0; + } + else + { + _968 = _956 * ((0.23999999463558197021484375 / _941) - 0.5); + } + _969 = _968; + } + float3 _972 = _916 * float3(1.0 + _969); + float _973 = _972.x; + float _974 = _972.y; + float _976 = _972.z; + float _990; + if ((_973 == _974) && (_974 == _976)) + { + _990 = 0.0; + } + else + { + _990 = 57.2957763671875 * atan2(sqrt(3.0) * (_974 - _976), ((2.0 * _973) - _974) - _976); + } + float _995; + if (_990 < 0.0) + { + _995 = _990 + 360.0; + } + else + { + _995 = _990; + } + float _996 = fast::clamp(_995, 0.0, 360.0); + float _1001; + if (_996 > 180.0) + { + _1001 = _996 - 360.0; + } + else + { + _1001 = _996; + } + float _1005 = smoothstep(0.0, 1.0, 1.0 - abs(_1001 * 0.01481481455266475677490234375)); + float3 _1012 = _972; + _1012.x = _973 + ((((_1005 * _1005) * _928) * (0.02999999932944774627685546875 - _973)) * 0.180000007152557373046875); + float3 _1014 = fast::max(float3(0.0), _1012 * float3x3(float3(1.45143926143646240234375, -0.236510753631591796875, -0.214928567409515380859375), float3(-0.07655377686023712158203125, 1.1762297153472900390625, -0.0996759235858917236328125), float3(0.0083161480724811553955078125, -0.0060324496589601039886474609375, 0.99771630764007568359375))); + float _1023 = (1.0 + _Globals.FilmBlackClip) - _Globals.FilmToe; + float _1026 = 1.0 + _Globals.FilmWhiteClip; + float _1029 = _1026 - _Globals.FilmShoulder; + float _1056; + if (_Globals.FilmToe > 0.800000011920928955078125) + { + _1056 = ((0.819999992847442626953125 - _Globals.FilmToe) / _Globals.FilmSlope) + (log(0.180000007152557373046875) / log(10.0)); + } + else + { + float _1035 = (0.180000007152557373046875 + _Globals.FilmBlackClip) / _1023; + _1056 = (log(0.180000007152557373046875) / log(10.0)) - ((0.5 * log(_1035 / (2.0 - _1035))) * (_1023 / _Globals.FilmSlope)); + } + float _1061 = ((1.0 - _Globals.FilmToe) / _Globals.FilmSlope) - _1056; + float _1063 = (_Globals.FilmShoulder / _Globals.FilmSlope) - _1061; + float _1065 = log(10.0); + float3 _1067 = log(mix(float3(dot(_1014, float3(0.272228717803955078125, 0.674081742763519287109375, 0.053689517080783843994140625))), _1014, float3(0.959999978542327880859375))) / float3(_1065); + float3 _1071 = float3(_Globals.FilmSlope) * (_1067 + float3(_1061)); + float3 _1079 = float3(_1056); + float3 _1080 = _1067 - _1079; + float3 _1092 = float3(_1063); + float3 _1106 = fast::clamp(_1080 / float3(_1063 - _1056), float3(0.0), float3(1.0)); + float3 _1110 = select(_1106, float3(1.0) - _1106, bool3(_1063 < _1056)); + float3 _1115 = mix(select(_1071, float3(-_Globals.FilmBlackClip) + (float3(2.0 * _1023) / (float3(1.0) + exp(float3(((-2.0) * _Globals.FilmSlope) / _1023) * _1080))), _1067 < _1079), select(_1071, float3(_1026) - (float3(2.0 * _1029) / (float3(1.0) + exp(float3((2.0 * _Globals.FilmSlope) / _1029) * (_1067 - _1092)))), _1067 > _1092), ((float3(3.0) - (float3(2.0) * _1110)) * _1110) * _1110); + float3 _1119 = fast::max(float3(0.0), mix(float3(dot(_1115, float3(0.272228717803955078125, 0.674081742763519287109375, 0.053689517080783843994140625))), _1115, float3(0.930000007152557373046875))); + float3 _1189; + if (_Globals.ColorShadow_Tint2.w == 0.0) + { + float3 _1131 = _391; + _1131.x = dot(_906, _Globals.ColorMatrixR_ColorCurveCd1.xyz); + float3 _1136 = _1131; + _1136.y = dot(_906, _Globals.ColorMatrixG_ColorCurveCd3Cm3.xyz); + float3 _1141 = _1136; + _1141.z = dot(_906, _Globals.ColorMatrixB_ColorCurveCm2.xyz); + float3 _1157 = fast::max(float3(0.0), _1141 * (_Globals.ColorShadow_Tint1.xyz + (_Globals.ColorShadow_Tint2.xyz * float3(1.0 / (dot(_906, _Globals.ColorShadow_Luma.xyz) + 1.0))))); + float3 _1162 = fast::max(float3(0.0), _Globals.ColorCurve_Cm0Cd0_Cd2_Ch0Cm1_Ch3.xxx - _1157); + float3 _1164 = fast::max(_1157, _Globals.ColorCurve_Cm0Cd0_Cd2_Ch0Cm1_Ch3.zzz); + _1189 = ((((_1164 * _Globals.ColorCurve_Ch1_Ch2.xxx) + _Globals.ColorCurve_Ch1_Ch2.yyy) * (float3(1.0) / (_1164 + _Globals.ColorCurve_Cm0Cd0_Cd2_Ch0Cm1_Ch3.www))) + ((fast::clamp(_1157, _Globals.ColorCurve_Cm0Cd0_Cd2_Ch0Cm1_Ch3.xxx, _Globals.ColorCurve_Cm0Cd0_Cd2_Ch0Cm1_Ch3.zzz) * _Globals.ColorMatrixB_ColorCurveCm2.www) + (((_1162 * _Globals.ColorMatrixR_ColorCurveCd1.www) * (float3(1.0) / (_1162 + _Globals.ColorCurve_Cm0Cd0_Cd2_Ch0Cm1_Ch3.yyy))) + _Globals.ColorMatrixG_ColorCurveCd3Cm3.www))) - float3(0.00200000009499490261077880859375); + } + else + { + _1189 = fast::max(float3(0.0), mix(_1119, _1119 * ((_551 * float3x3(float3(1.06317996978759765625, 0.02339559979736804962158203125, -0.08657260239124298095703125), float3(-0.010633699595928192138671875, 1.2063200473785400390625, -0.1956900060176849365234375), float3(-0.0005908869788981974124908447265625, 0.00105247995816171169281005859375, 0.999538004398345947265625))) * _550), _914) * _549); + } + float3 _1218 = pow(fast::max(float3(0.0), mix((((float3(_Globals.MappingPolynomial.x) * (_1189 * _1189)) + (float3(_Globals.MappingPolynomial.y) * _1189)) + float3(_Globals.MappingPolynomial.z)) * float3(_Globals.ColorScale), _Globals.OverlayColor.xyz, float3(_Globals.OverlayColor.w))), float3(_Globals.InverseGamma.y)); + float3 _3001; + if (_Globals.OutputDevice == 0u) + { + float _2961 = _1218.x; + float _2973; + for (;;) + { + if (_2961 < 0.00313066993840038776397705078125) + { + _2973 = _2961 * 12.9200000762939453125; + break; + } + _2973 = (pow(_2961, 0.4166666567325592041015625) * 1.05499994754791259765625) - 0.054999999701976776123046875; + break; + } + float _2974 = _1218.y; + float _2986; + for (;;) + { + if (_2974 < 0.00313066993840038776397705078125) + { + _2986 = _2974 * 12.9200000762939453125; + break; + } + _2986 = (pow(_2974, 0.4166666567325592041015625) * 1.05499994754791259765625) - 0.054999999701976776123046875; + break; + } + float _2987 = _1218.z; + float _2999; + for (;;) + { + if (_2987 < 0.00313066993840038776397705078125) + { + _2999 = _2987 * 12.9200000762939453125; + break; + } + _2999 = (pow(_2987, 0.4166666567325592041015625) * 1.05499994754791259765625) - 0.054999999701976776123046875; + break; + } + _3001 = float3(_2973, _2986, _2999); + } + else + { + float3 _2960; + if (_Globals.OutputDevice == 1u) + { + float3 _2953 = fast::max(float3(6.1035199905745685100555419921875e-05), (_1218 * _547) * _576); + _2960 = fast::min(_2953 * float3(4.5), (pow(fast::max(_2953, float3(0.017999999225139617919921875)), float3(0.449999988079071044921875)) * float3(1.09899997711181640625)) - float3(0.098999999463558197021484375)); + } + else + { + float3 _2950; + if ((_Globals.OutputDevice == 3u) || (_Globals.OutputDevice == 5u)) + { + float3 _2100 = (_906 * float3(1.5)) * (_546 * float3x3(float3(1.04981100559234619140625, 0.0, -9.74845024757087230682373046875e-05), float3(-0.49590301513671875, 1.37331306934356689453125, 0.09824003279209136962890625), float3(0.0, 0.0, 0.991252005100250244140625))); + float _2101 = _2100.x; + float _2102 = _2100.y; + float _2104 = _2100.z; + float _2107 = fast::max(fast::max(_2101, _2102), _2104); + float _2112 = (fast::max(_2107, 1.0000000133514319600180897396058e-10) - fast::max(fast::min(fast::min(_2101, _2102), _2104), 1.0000000133514319600180897396058e-10)) / fast::max(_2107, 0.00999999977648258209228515625); + float _2125 = ((_2104 + _2102) + _2101) + (1.75 * sqrt(((_2104 * (_2104 - _2102)) + (_2102 * (_2102 - _2101))) + (_2101 * (_2101 - _2104)))); + float _2126 = _2125 * 0.3333333432674407958984375; + float _2127 = _2112 - 0.4000000059604644775390625; + float _2132 = fast::max(1.0 - abs(_2127 * 2.5), 0.0); + float _2140 = (1.0 + (float(int(sign(_2127 * 5.0))) * (1.0 - (_2132 * _2132)))) * 0.02500000037252902984619140625; + float _2153; + if (_2126 <= 0.053333334624767303466796875) + { + _2153 = _2140; + } + else + { + float _2152; + if (_2126 >= 0.1599999964237213134765625) + { + _2152 = 0.0; + } + else + { + _2152 = _2140 * ((0.23999999463558197021484375 / _2125) - 0.5); + } + _2153 = _2152; + } + float3 _2156 = _2100 * float3(1.0 + _2153); + float _2157 = _2156.x; + float _2158 = _2156.y; + float _2160 = _2156.z; + float _2174; + if ((_2157 == _2158) && (_2158 == _2160)) + { + _2174 = 0.0; + } + else + { + _2174 = 57.2957763671875 * atan2(sqrt(3.0) * (_2158 - _2160), ((2.0 * _2157) - _2158) - _2160); + } + float _2179; + if (_2174 < 0.0) + { + _2179 = _2174 + 360.0; + } + else + { + _2179 = _2174; + } + float _2180 = fast::clamp(_2179, 0.0, 360.0); + float _2185; + if (_2180 > 180.0) + { + _2185 = _2180 - 360.0; + } + else + { + _2185 = _2180; + } + float _2235; + if ((_2185 > (-67.5)) && (_2185 < 67.5)) + { + float _2192 = (_2185 - (-67.5)) * 0.0296296291053295135498046875; + int _2193 = int(_2192); + float _2195 = _2192 - float(_2193); + float _2196 = _2195 * _2195; + float _2197 = _2196 * _2195; + float _2234; + if (_2193 == 3) + { + _2234 = (((_2197 * (-0.16666667163372039794921875)) + (_2196 * 0.5)) + (_2195 * (-0.5))) + 0.16666667163372039794921875; + } + else + { + float _2227; + if (_2193 == 2) + { + _2227 = ((_2197 * 0.5) + (_2196 * (-1.0))) + 0.666666686534881591796875; + } + else + { + float _2222; + if (_2193 == 1) + { + _2222 = (((_2197 * (-0.5)) + (_2196 * 0.5)) + (_2195 * 0.5)) + 0.16666667163372039794921875; + } + else + { + float _2215; + if (_2193 == 0) + { + _2215 = _2197 * 0.16666667163372039794921875; + } + else + { + _2215 = 0.0; + } + _2222 = _2215; + } + _2227 = _2222; + } + _2234 = _2227; + } + _2235 = _2234; + } + else + { + _2235 = 0.0; + } + float3 _2242 = _2156; + _2242.x = _2157 + ((((_2235 * 1.5) * _2112) * (0.02999999932944774627685546875 - _2157)) * 0.180000007152557373046875); + float3 _2245 = fast::clamp(fast::clamp(_2242, float3(0.0), float3(65535.0)) * float3x3(float3(1.45143926143646240234375, -0.236510753631591796875, -0.214928567409515380859375), float3(-0.07655377686023712158203125, 1.1762297153472900390625, -0.0996759235858917236328125), float3(0.0083161480724811553955078125, -0.0060324496589601039886474609375, 0.99771630764007568359375)), float3(0.0), float3(65535.0)); + float3 _2248 = mix(float3(dot(_2245, float3(0.272228717803955078125, 0.674081742763519287109375, 0.053689517080783843994140625))), _2245, float3(0.959999978542327880859375)); + float _2249 = _2248.x; + float _2253 = 0.17999999225139617919921875 * exp2(18.0); + float _2255 = exp2(-14.0); + float _2258 = log((_2249 <= 0.0) ? _2255 : _2249) / _1065; + float _2260 = log(0.17999999225139617919921875 * exp2(-15.0)) / _1065; + float _2327; + if (_2258 <= _2260) + { + _2327 = log(9.9999997473787516355514526367188e-05) / _1065; + } + else + { + float _2267 = log(0.180000007152557373046875) / _1065; + float _2324; + if ((_2258 > _2260) && (_2258 < _2267)) + { + float _2307 = (3.0 * (_2258 - _2260)) / (_2267 - _2260); + int _2308 = int(_2307); + float _2310 = _2307 - float(_2308); + _2324 = dot(float3(_2310 * _2310, _2310, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_475[_2308], _475[_2308 + 1], _475[_2308 + 2])); + } + else + { + float _2275 = log(_2253) / _1065; + float _2303; + if ((_2258 >= _2267) && (_2258 < _2275)) + { + float _2286 = (3.0 * (_2258 - _2267)) / (_2275 - _2267); + int _2287 = int(_2286); + float _2289 = _2286 - float(_2287); + _2303 = dot(float3(_2289 * _2289, _2289, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_476[_2287], _476[_2287 + 1], _476[_2287 + 2])); + } + else + { + _2303 = log(10000.0) / _1065; + } + _2324 = _2303; + } + _2327 = _2324; + } + float3 _2329 = _391; + _2329.x = pow(10.0, _2327); + float _2330 = _2248.y; + float _2334 = log((_2330 <= 0.0) ? _2255 : _2330) / _1065; + float _2401; + if (_2334 <= _2260) + { + _2401 = log(9.9999997473787516355514526367188e-05) / _1065; + } + else + { + float _2341 = log(0.180000007152557373046875) / _1065; + float _2398; + if ((_2334 > _2260) && (_2334 < _2341)) + { + float _2381 = (3.0 * (_2334 - _2260)) / (_2341 - _2260); + int _2382 = int(_2381); + float _2384 = _2381 - float(_2382); + _2398 = dot(float3(_2384 * _2384, _2384, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_475[_2382], _475[_2382 + 1], _475[_2382 + 2])); + } + else + { + float _2349 = log(_2253) / _1065; + float _2377; + if ((_2334 >= _2341) && (_2334 < _2349)) + { + float _2360 = (3.0 * (_2334 - _2341)) / (_2349 - _2341); + int _2361 = int(_2360); + float _2363 = _2360 - float(_2361); + _2377 = dot(float3(_2363 * _2363, _2363, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_476[_2361], _476[_2361 + 1], _476[_2361 + 2])); + } + else + { + _2377 = log(10000.0) / _1065; + } + _2398 = _2377; + } + _2401 = _2398; + } + float3 _2403 = _2329; + _2403.y = pow(10.0, _2401); + float _2404 = _2248.z; + float _2408 = log((_2404 <= 0.0) ? _2255 : _2404) / _1065; + float _2475; + if (_2408 <= _2260) + { + _2475 = log(9.9999997473787516355514526367188e-05) / _1065; + } + else + { + float _2415 = log(0.180000007152557373046875) / _1065; + float _2472; + if ((_2408 > _2260) && (_2408 < _2415)) + { + float _2455 = (3.0 * (_2408 - _2260)) / (_2415 - _2260); + int _2456 = int(_2455); + float _2458 = _2455 - float(_2456); + _2472 = dot(float3(_2458 * _2458, _2458, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_475[_2456], _475[_2456 + 1], _475[_2456 + 2])); + } + else + { + float _2423 = log(_2253) / _1065; + float _2451; + if ((_2408 >= _2415) && (_2408 < _2423)) + { + float _2434 = (3.0 * (_2408 - _2415)) / (_2423 - _2415); + int _2435 = int(_2434); + float _2437 = _2434 - float(_2435); + _2451 = dot(float3(_2437 * _2437, _2437, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_476[_2435], _476[_2435 + 1], _476[_2435 + 2])); + } + else + { + _2451 = log(10000.0) / _1065; + } + _2472 = _2451; + } + _2475 = _2472; + } + float3 _2477 = _2403; + _2477.z = pow(10.0, _2475); + float3 _2479 = (_2477 * float3x3(float3(0.695452213287353515625, 0.140678703784942626953125, 0.16386906802654266357421875), float3(0.0447945632040500640869140625, 0.859671115875244140625, 0.095534317195415496826171875), float3(-0.0055258828215301036834716796875, 0.0040252101607620716094970703125, 1.00150072574615478515625))) * float3x3(float3(1.45143926143646240234375, -0.236510753631591796875, -0.214928567409515380859375), float3(-0.07655377686023712158203125, 1.1762297153472900390625, -0.0996759235858917236328125), float3(0.0083161480724811553955078125, -0.0060324496589601039886474609375, 0.99771630764007568359375)); + float _2481 = 0.17999999225139617919921875 * pow(2.0, -12.0); + float _2485 = log((_2481 <= 0.0) ? _2255 : _2481) / _1065; + float _2552; + if (_2485 <= _2260) + { + _2552 = log(9.9999997473787516355514526367188e-05) / _1065; + } + else + { + float _2492 = log(0.180000007152557373046875) / _1065; + float _2549; + if ((_2485 > _2260) && (_2485 < _2492)) + { + float _2532 = (3.0 * (_2485 - _2260)) / (_2492 - _2260); + int _2533 = int(_2532); + float _2535 = _2532 - float(_2533); + _2549 = dot(float3(_2535 * _2535, _2535, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_475[_2533], _475[_2533 + 1], _475[_2533 + 2])); + } + else + { + float _2500 = log(_2253) / _1065; + float _2528; + if ((_2485 >= _2492) && (_2485 < _2500)) + { + float _2511 = (3.0 * (_2485 - _2492)) / (_2500 - _2492); + int _2512 = int(_2511); + float _2514 = _2511 - float(_2512); + _2528 = dot(float3(_2514 * _2514, _2514, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_476[_2512], _476[_2512 + 1], _476[_2512 + 2])); + } + else + { + _2528 = log(10000.0) / _1065; + } + _2549 = _2528; + } + _2552 = _2549; + } + float _2555 = log(0.180000007152557373046875) / _1065; + float _2611; + if (_2555 <= _2260) + { + _2611 = log(9.9999997473787516355514526367188e-05) / _1065; + } + else + { + float _2608; + if ((_2555 > _2260) && (_2555 < _2555)) + { + _2608 = (float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_475[3], _475[4], _475[5])).z; + } + else + { + float _2568 = log(_2253) / _1065; + float _2596; + if ((_2555 >= _2555) && (_2555 < _2568)) + { + float _2579 = (3.0 * (_2555 - _2555)) / (_2568 - _2555); + int _2580 = int(_2579); + float _2582 = _2579 - float(_2580); + _2596 = dot(float3(_2582 * _2582, _2582, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_476[_2580], _476[_2580 + 1], _476[_2580 + 2])); + } + else + { + _2596 = log(10000.0) / _1065; + } + _2608 = _2596; + } + _2611 = _2608; + } + float _2612 = pow(10.0, _2611); + float _2614 = 0.17999999225139617919921875 * pow(2.0, 10.0); + float _2618 = log((_2614 <= 0.0) ? _2255 : _2614) / _1065; + float _2683; + if (_2618 <= _2260) + { + _2683 = log(9.9999997473787516355514526367188e-05) / _1065; + } + else + { + float _2680; + if ((_2618 > _2260) && (_2618 < _2555)) + { + float _2663 = (3.0 * (_2618 - _2260)) / (_2555 - _2260); + int _2664 = int(_2663); + float _2666 = _2663 - float(_2664); + _2680 = dot(float3(_2666 * _2666, _2666, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_475[_2664], _475[_2664 + 1], _475[_2664 + 2])); + } + else + { + float _2631 = log(_2253) / _1065; + float _2659; + if ((_2618 >= _2555) && (_2618 < _2631)) + { + float _2642 = (3.0 * (_2618 - _2555)) / (_2631 - _2555); + int _2643 = int(_2642); + float _2645 = _2642 - float(_2643); + _2659 = dot(float3(_2645 * _2645, _2645, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_476[_2643], _476[_2643 + 1], _476[_2643 + 2])); + } + else + { + _2659 = log(10000.0) / _1065; + } + _2680 = _2659; + } + _2683 = _2680; + } + float _2684 = pow(10.0, _2683); + float _2685 = _2479.x; + float _2689 = log((_2685 <= 0.0) ? 9.9999997473787516355514526367188e-05 : _2685) / _1065; + float _2690 = log(pow(10.0, _2552)); + float _2691 = _2690 / _1065; + float _2768; + if (_2689 <= _2691) + { + _2768 = (_2689 * 3.0) + ((log(9.9999997473787516355514526367188e-05) / _1065) - ((3.0 * _2690) / _1065)); + } + else + { + float _2698 = log(_2612) / _1065; + float _2760; + if ((_2689 > _2691) && (_2689 < _2698)) + { + float _2743 = (7.0 * (_2689 - _2691)) / (_2698 - _2691); + int _2744 = int(_2743); + float _2746 = _2743 - float(_2744); + _2760 = dot(float3(_2746 * _2746, _2746, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_479[_2744], _479[_2744 + 1], _479[_2744 + 2])); + } + else + { + float _2705 = log(_2684); + float _2706 = _2705 / _1065; + float _2739; + if ((_2689 >= _2698) && (_2689 < _2706)) + { + float _2722 = (7.0 * (_2689 - _2698)) / (_2706 - _2698); + int _2723 = int(_2722); + float _2725 = _2722 - float(_2723); + _2739 = dot(float3(_2725 * _2725, _2725, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_480[_2723], _480[_2723 + 1], _480[_2723 + 2])); + } + else + { + _2739 = (_2689 * 0.0599999986588954925537109375) + ((log(1000.0) / _1065) - ((0.0599999986588954925537109375 * _2705) / _1065)); + } + _2760 = _2739; + } + _2768 = _2760; + } + float3 _2770 = _391; + _2770.x = pow(10.0, _2768); + float _2771 = _2479.y; + float _2775 = log((_2771 <= 0.0) ? 9.9999997473787516355514526367188e-05 : _2771) / _1065; + float _2852; + if (_2775 <= _2691) + { + _2852 = (_2775 * 3.0) + ((log(9.9999997473787516355514526367188e-05) / _1065) - ((3.0 * _2690) / _1065)); + } + else + { + float _2782 = log(_2612) / _1065; + float _2844; + if ((_2775 > _2691) && (_2775 < _2782)) + { + float _2827 = (7.0 * (_2775 - _2691)) / (_2782 - _2691); + int _2828 = int(_2827); + float _2830 = _2827 - float(_2828); + _2844 = dot(float3(_2830 * _2830, _2830, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_479[_2828], _479[_2828 + 1], _479[_2828 + 2])); + } + else + { + float _2789 = log(_2684); + float _2790 = _2789 / _1065; + float _2823; + if ((_2775 >= _2782) && (_2775 < _2790)) + { + float _2806 = (7.0 * (_2775 - _2782)) / (_2790 - _2782); + int _2807 = int(_2806); + float _2809 = _2806 - float(_2807); + _2823 = dot(float3(_2809 * _2809, _2809, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_480[_2807], _480[_2807 + 1], _480[_2807 + 2])); + } + else + { + _2823 = (_2775 * 0.0599999986588954925537109375) + ((log(1000.0) / _1065) - ((0.0599999986588954925537109375 * _2789) / _1065)); + } + _2844 = _2823; + } + _2852 = _2844; + } + float3 _2854 = _2770; + _2854.y = pow(10.0, _2852); + float _2855 = _2479.z; + float _2859 = log((_2855 <= 0.0) ? 9.9999997473787516355514526367188e-05 : _2855) / _1065; + float _2936; + if (_2859 <= _2691) + { + _2936 = (_2859 * 3.0) + ((log(9.9999997473787516355514526367188e-05) / _1065) - ((3.0 * _2690) / _1065)); + } + else + { + float _2866 = log(_2612) / _1065; + float _2928; + if ((_2859 > _2691) && (_2859 < _2866)) + { + float _2911 = (7.0 * (_2859 - _2691)) / (_2866 - _2691); + int _2912 = int(_2911); + float _2914 = _2911 - float(_2912); + _2928 = dot(float3(_2914 * _2914, _2914, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_479[_2912], _479[_2912 + 1], _479[_2912 + 2])); + } + else + { + float _2873 = log(_2684); + float _2874 = _2873 / _1065; + float _2907; + if ((_2859 >= _2866) && (_2859 < _2874)) + { + float _2890 = (7.0 * (_2859 - _2866)) / (_2874 - _2866); + int _2891 = int(_2890); + float _2893 = _2890 - float(_2891); + _2907 = dot(float3(_2893 * _2893, _2893, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_480[_2891], _480[_2891 + 1], _480[_2891 + 2])); + } + else + { + _2907 = (_2859 * 0.0599999986588954925537109375) + ((log(1000.0) / _1065) - ((0.0599999986588954925537109375 * _2873) / _1065)); + } + _2928 = _2907; + } + _2936 = _2928; + } + float3 _2938 = _2854; + _2938.z = pow(10.0, _2936); + float3 _2942 = pow(((_2938 - float3(3.5073844628641381859779357910156e-05)) * _576) * float3(9.9999997473787516355514526367188e-05), float3(0.1593017578125)); + _2950 = pow((float3(0.8359375) + (float3(18.8515625) * _2942)) * (float3(1.0) / (float3(1.0) + (float3(18.6875) * _2942))), float3(78.84375)); + } + else + { + float3 _2097; + if ((_Globals.OutputDevice == 4u) || (_Globals.OutputDevice == 6u)) + { + float3 _1263 = (_906 * float3(1.5)) * (_546 * float3x3(float3(1.04981100559234619140625, 0.0, -9.74845024757087230682373046875e-05), float3(-0.49590301513671875, 1.37331306934356689453125, 0.09824003279209136962890625), float3(0.0, 0.0, 0.991252005100250244140625))); + float _1264 = _1263.x; + float _1265 = _1263.y; + float _1267 = _1263.z; + float _1270 = fast::max(fast::max(_1264, _1265), _1267); + float _1275 = (fast::max(_1270, 1.0000000133514319600180897396058e-10) - fast::max(fast::min(fast::min(_1264, _1265), _1267), 1.0000000133514319600180897396058e-10)) / fast::max(_1270, 0.00999999977648258209228515625); + float _1288 = ((_1267 + _1265) + _1264) + (1.75 * sqrt(((_1267 * (_1267 - _1265)) + (_1265 * (_1265 - _1264))) + (_1264 * (_1264 - _1267)))); + float _1289 = _1288 * 0.3333333432674407958984375; + float _1290 = _1275 - 0.4000000059604644775390625; + float _1295 = fast::max(1.0 - abs(_1290 * 2.5), 0.0); + float _1303 = (1.0 + (float(int(sign(_1290 * 5.0))) * (1.0 - (_1295 * _1295)))) * 0.02500000037252902984619140625; + float _1316; + if (_1289 <= 0.053333334624767303466796875) + { + _1316 = _1303; + } + else + { + float _1315; + if (_1289 >= 0.1599999964237213134765625) + { + _1315 = 0.0; + } + else + { + _1315 = _1303 * ((0.23999999463558197021484375 / _1288) - 0.5); + } + _1316 = _1315; + } + float3 _1319 = _1263 * float3(1.0 + _1316); + float _1320 = _1319.x; + float _1321 = _1319.y; + float _1323 = _1319.z; + float _1337; + if ((_1320 == _1321) && (_1321 == _1323)) + { + _1337 = 0.0; + } + else + { + _1337 = 57.2957763671875 * atan2(sqrt(3.0) * (_1321 - _1323), ((2.0 * _1320) - _1321) - _1323); + } + float _1342; + if (_1337 < 0.0) + { + _1342 = _1337 + 360.0; + } + else + { + _1342 = _1337; + } + float _1343 = fast::clamp(_1342, 0.0, 360.0); + float _1348; + if (_1343 > 180.0) + { + _1348 = _1343 - 360.0; + } + else + { + _1348 = _1343; + } + float _1398; + if ((_1348 > (-67.5)) && (_1348 < 67.5)) + { + float _1355 = (_1348 - (-67.5)) * 0.0296296291053295135498046875; + int _1356 = int(_1355); + float _1358 = _1355 - float(_1356); + float _1359 = _1358 * _1358; + float _1360 = _1359 * _1358; + float _1397; + if (_1356 == 3) + { + _1397 = (((_1360 * (-0.16666667163372039794921875)) + (_1359 * 0.5)) + (_1358 * (-0.5))) + 0.16666667163372039794921875; + } + else + { + float _1390; + if (_1356 == 2) + { + _1390 = ((_1360 * 0.5) + (_1359 * (-1.0))) + 0.666666686534881591796875; + } + else + { + float _1385; + if (_1356 == 1) + { + _1385 = (((_1360 * (-0.5)) + (_1359 * 0.5)) + (_1358 * 0.5)) + 0.16666667163372039794921875; + } + else + { + float _1378; + if (_1356 == 0) + { + _1378 = _1360 * 0.16666667163372039794921875; + } + else + { + _1378 = 0.0; + } + _1385 = _1378; + } + _1390 = _1385; + } + _1397 = _1390; + } + _1398 = _1397; + } + else + { + _1398 = 0.0; + } + float3 _1405 = _1319; + _1405.x = _1320 + ((((_1398 * 1.5) * _1275) * (0.02999999932944774627685546875 - _1320)) * 0.180000007152557373046875); + float3 _1408 = fast::clamp(fast::clamp(_1405, float3(0.0), float3(65535.0)) * float3x3(float3(1.45143926143646240234375, -0.236510753631591796875, -0.214928567409515380859375), float3(-0.07655377686023712158203125, 1.1762297153472900390625, -0.0996759235858917236328125), float3(0.0083161480724811553955078125, -0.0060324496589601039886474609375, 0.99771630764007568359375)), float3(0.0), float3(65535.0)); + float3 _1411 = mix(float3(dot(_1408, float3(0.272228717803955078125, 0.674081742763519287109375, 0.053689517080783843994140625))), _1408, float3(0.959999978542327880859375)); + float _1412 = _1411.x; + float _1416 = 0.17999999225139617919921875 * exp2(18.0); + float _1418 = exp2(-14.0); + float _1421 = log((_1412 <= 0.0) ? _1418 : _1412) / _1065; + float _1423 = log(0.17999999225139617919921875 * exp2(-15.0)) / _1065; + float _1490; + if (_1421 <= _1423) + { + _1490 = log(9.9999997473787516355514526367188e-05) / _1065; + } + else + { + float _1430 = log(0.180000007152557373046875) / _1065; + float _1487; + if ((_1421 > _1423) && (_1421 < _1430)) + { + float _1470 = (3.0 * (_1421 - _1423)) / (_1430 - _1423); + int _1471 = int(_1470); + float _1473 = _1470 - float(_1471); + _1487 = dot(float3(_1473 * _1473, _1473, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_475[_1471], _475[_1471 + 1], _475[_1471 + 2])); + } + else + { + float _1438 = log(_1416) / _1065; + float _1466; + if ((_1421 >= _1430) && (_1421 < _1438)) + { + float _1449 = (3.0 * (_1421 - _1430)) / (_1438 - _1430); + int _1450 = int(_1449); + float _1452 = _1449 - float(_1450); + _1466 = dot(float3(_1452 * _1452, _1452, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_476[_1450], _476[_1450 + 1], _476[_1450 + 2])); + } + else + { + _1466 = log(10000.0) / _1065; + } + _1487 = _1466; + } + _1490 = _1487; + } + float3 _1492 = _391; + _1492.x = pow(10.0, _1490); + float _1493 = _1411.y; + float _1497 = log((_1493 <= 0.0) ? _1418 : _1493) / _1065; + float _1564; + if (_1497 <= _1423) + { + _1564 = log(9.9999997473787516355514526367188e-05) / _1065; + } + else + { + float _1504 = log(0.180000007152557373046875) / _1065; + float _1561; + if ((_1497 > _1423) && (_1497 < _1504)) + { + float _1544 = (3.0 * (_1497 - _1423)) / (_1504 - _1423); + int _1545 = int(_1544); + float _1547 = _1544 - float(_1545); + _1561 = dot(float3(_1547 * _1547, _1547, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_475[_1545], _475[_1545 + 1], _475[_1545 + 2])); + } + else + { + float _1512 = log(_1416) / _1065; + float _1540; + if ((_1497 >= _1504) && (_1497 < _1512)) + { + float _1523 = (3.0 * (_1497 - _1504)) / (_1512 - _1504); + int _1524 = int(_1523); + float _1526 = _1523 - float(_1524); + _1540 = dot(float3(_1526 * _1526, _1526, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_476[_1524], _476[_1524 + 1], _476[_1524 + 2])); + } + else + { + _1540 = log(10000.0) / _1065; + } + _1561 = _1540; + } + _1564 = _1561; + } + float3 _1566 = _1492; + _1566.y = pow(10.0, _1564); + float _1567 = _1411.z; + float _1571 = log((_1567 <= 0.0) ? _1418 : _1567) / _1065; + float _1638; + if (_1571 <= _1423) + { + _1638 = log(9.9999997473787516355514526367188e-05) / _1065; + } + else + { + float _1578 = log(0.180000007152557373046875) / _1065; + float _1635; + if ((_1571 > _1423) && (_1571 < _1578)) + { + float _1618 = (3.0 * (_1571 - _1423)) / (_1578 - _1423); + int _1619 = int(_1618); + float _1621 = _1618 - float(_1619); + _1635 = dot(float3(_1621 * _1621, _1621, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_475[_1619], _475[_1619 + 1], _475[_1619 + 2])); + } + else + { + float _1586 = log(_1416) / _1065; + float _1614; + if ((_1571 >= _1578) && (_1571 < _1586)) + { + float _1597 = (3.0 * (_1571 - _1578)) / (_1586 - _1578); + int _1598 = int(_1597); + float _1600 = _1597 - float(_1598); + _1614 = dot(float3(_1600 * _1600, _1600, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_476[_1598], _476[_1598 + 1], _476[_1598 + 2])); + } + else + { + _1614 = log(10000.0) / _1065; + } + _1635 = _1614; + } + _1638 = _1635; + } + float3 _1640 = _1566; + _1640.z = pow(10.0, _1638); + float3 _1642 = (_1640 * float3x3(float3(0.695452213287353515625, 0.140678703784942626953125, 0.16386906802654266357421875), float3(0.0447945632040500640869140625, 0.859671115875244140625, 0.095534317195415496826171875), float3(-0.0055258828215301036834716796875, 0.0040252101607620716094970703125, 1.00150072574615478515625))) * float3x3(float3(1.45143926143646240234375, -0.236510753631591796875, -0.214928567409515380859375), float3(-0.07655377686023712158203125, 1.1762297153472900390625, -0.0996759235858917236328125), float3(0.0083161480724811553955078125, -0.0060324496589601039886474609375, 0.99771630764007568359375)); + float _1644 = 0.17999999225139617919921875 * pow(2.0, -12.0); + float _1648 = log((_1644 <= 0.0) ? _1418 : _1644) / _1065; + float _1715; + if (_1648 <= _1423) + { + _1715 = log(9.9999997473787516355514526367188e-05) / _1065; + } + else + { + float _1655 = log(0.180000007152557373046875) / _1065; + float _1712; + if ((_1648 > _1423) && (_1648 < _1655)) + { + float _1695 = (3.0 * (_1648 - _1423)) / (_1655 - _1423); + int _1696 = int(_1695); + float _1698 = _1695 - float(_1696); + _1712 = dot(float3(_1698 * _1698, _1698, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_475[_1696], _475[_1696 + 1], _475[_1696 + 2])); + } + else + { + float _1663 = log(_1416) / _1065; + float _1691; + if ((_1648 >= _1655) && (_1648 < _1663)) + { + float _1674 = (3.0 * (_1648 - _1655)) / (_1663 - _1655); + int _1675 = int(_1674); + float _1677 = _1674 - float(_1675); + _1691 = dot(float3(_1677 * _1677, _1677, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_476[_1675], _476[_1675 + 1], _476[_1675 + 2])); + } + else + { + _1691 = log(10000.0) / _1065; + } + _1712 = _1691; + } + _1715 = _1712; + } + float _1718 = log(0.180000007152557373046875) / _1065; + float _1774; + if (_1718 <= _1423) + { + _1774 = log(9.9999997473787516355514526367188e-05) / _1065; + } + else + { + float _1771; + if ((_1718 > _1423) && (_1718 < _1718)) + { + _1771 = (float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_475[3], _475[4], _475[5])).z; + } + else + { + float _1731 = log(_1416) / _1065; + float _1759; + if ((_1718 >= _1718) && (_1718 < _1731)) + { + float _1742 = (3.0 * (_1718 - _1718)) / (_1731 - _1718); + int _1743 = int(_1742); + float _1745 = _1742 - float(_1743); + _1759 = dot(float3(_1745 * _1745, _1745, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_476[_1743], _476[_1743 + 1], _476[_1743 + 2])); + } + else + { + _1759 = log(10000.0) / _1065; + } + _1771 = _1759; + } + _1774 = _1771; + } + float _1775 = pow(10.0, _1774); + float _1777 = 0.17999999225139617919921875 * pow(2.0, 11.0); + float _1781 = log((_1777 <= 0.0) ? _1418 : _1777) / _1065; + float _1846; + if (_1781 <= _1423) + { + _1846 = log(9.9999997473787516355514526367188e-05) / _1065; + } + else + { + float _1843; + if ((_1781 > _1423) && (_1781 < _1718)) + { + float _1826 = (3.0 * (_1781 - _1423)) / (_1718 - _1423); + int _1827 = int(_1826); + float _1829 = _1826 - float(_1827); + _1843 = dot(float3(_1829 * _1829, _1829, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_475[_1827], _475[_1827 + 1], _475[_1827 + 2])); + } + else + { + float _1794 = log(_1416) / _1065; + float _1822; + if ((_1781 >= _1718) && (_1781 < _1794)) + { + float _1805 = (3.0 * (_1781 - _1718)) / (_1794 - _1718); + int _1806 = int(_1805); + float _1808 = _1805 - float(_1806); + _1822 = dot(float3(_1808 * _1808, _1808, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_476[_1806], _476[_1806 + 1], _476[_1806 + 2])); + } + else + { + _1822 = log(10000.0) / _1065; + } + _1843 = _1822; + } + _1846 = _1843; + } + float _1847 = pow(10.0, _1846); + float _1848 = _1642.x; + float _1852 = log((_1848 <= 0.0) ? 9.9999997473787516355514526367188e-05 : _1848) / _1065; + float _1854 = log(pow(10.0, _1715)) / _1065; + float _1926; + if (_1852 <= _1854) + { + _1926 = log(0.004999999888241291046142578125) / _1065; + } + else + { + float _1861 = log(_1775) / _1065; + float _1923; + if ((_1852 > _1854) && (_1852 < _1861)) + { + float _1906 = (7.0 * (_1852 - _1854)) / (_1861 - _1854); + int _1907 = int(_1906); + float _1909 = _1906 - float(_1907); + _1923 = dot(float3(_1909 * _1909, _1909, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_482[_1907], _482[_1907 + 1], _482[_1907 + 2])); + } + else + { + float _1868 = log(_1847); + float _1869 = _1868 / _1065; + float _1902; + if ((_1852 >= _1861) && (_1852 < _1869)) + { + float _1885 = (7.0 * (_1852 - _1861)) / (_1869 - _1861); + int _1886 = int(_1885); + float _1888 = _1885 - float(_1886); + _1902 = dot(float3(_1888 * _1888, _1888, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_483[_1886], _483[_1886 + 1], _483[_1886 + 2])); + } + else + { + _1902 = (_1852 * 0.119999997317790985107421875) + ((log(2000.0) / _1065) - ((0.119999997317790985107421875 * _1868) / _1065)); + } + _1923 = _1902; + } + _1926 = _1923; + } + float3 _1928 = _391; + _1928.x = pow(10.0, _1926); + float _1929 = _1642.y; + float _1933 = log((_1929 <= 0.0) ? 9.9999997473787516355514526367188e-05 : _1929) / _1065; + float _2005; + if (_1933 <= _1854) + { + _2005 = log(0.004999999888241291046142578125) / _1065; + } + else + { + float _1940 = log(_1775) / _1065; + float _2002; + if ((_1933 > _1854) && (_1933 < _1940)) + { + float _1985 = (7.0 * (_1933 - _1854)) / (_1940 - _1854); + int _1986 = int(_1985); + float _1988 = _1985 - float(_1986); + _2002 = dot(float3(_1988 * _1988, _1988, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_482[_1986], _482[_1986 + 1], _482[_1986 + 2])); + } + else + { + float _1947 = log(_1847); + float _1948 = _1947 / _1065; + float _1981; + if ((_1933 >= _1940) && (_1933 < _1948)) + { + float _1964 = (7.0 * (_1933 - _1940)) / (_1948 - _1940); + int _1965 = int(_1964); + float _1967 = _1964 - float(_1965); + _1981 = dot(float3(_1967 * _1967, _1967, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_483[_1965], _483[_1965 + 1], _483[_1965 + 2])); + } + else + { + _1981 = (_1933 * 0.119999997317790985107421875) + ((log(2000.0) / _1065) - ((0.119999997317790985107421875 * _1947) / _1065)); + } + _2002 = _1981; + } + _2005 = _2002; + } + float3 _2007 = _1928; + _2007.y = pow(10.0, _2005); + float _2008 = _1642.z; + float _2012 = log((_2008 <= 0.0) ? 9.9999997473787516355514526367188e-05 : _2008) / _1065; + float _2084; + if (_2012 <= _1854) + { + _2084 = log(0.004999999888241291046142578125) / _1065; + } + else + { + float _2019 = log(_1775) / _1065; + float _2081; + if ((_2012 > _1854) && (_2012 < _2019)) + { + float _2064 = (7.0 * (_2012 - _1854)) / (_2019 - _1854); + int _2065 = int(_2064); + float _2067 = _2064 - float(_2065); + _2081 = dot(float3(_2067 * _2067, _2067, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_482[_2065], _482[_2065 + 1], _482[_2065 + 2])); + } + else + { + float _2026 = log(_1847); + float _2027 = _2026 / _1065; + float _2060; + if ((_2012 >= _2019) && (_2012 < _2027)) + { + float _2043 = (7.0 * (_2012 - _2019)) / (_2027 - _2019); + int _2044 = int(_2043); + float _2046 = _2043 - float(_2044); + _2060 = dot(float3(_2046 * _2046, _2046, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_483[_2044], _483[_2044 + 1], _483[_2044 + 2])); + } + else + { + _2060 = (_2012 * 0.119999997317790985107421875) + ((log(2000.0) / _1065) - ((0.119999997317790985107421875 * _2026) / _1065)); + } + _2081 = _2060; + } + _2084 = _2081; + } + float3 _2086 = _2007; + _2086.z = pow(10.0, _2084); + float3 _2089 = pow((_2086 * _576) * float3(9.9999997473787516355514526367188e-05), float3(0.1593017578125)); + _2097 = pow((float3(0.8359375) + (float3(18.8515625) * _2089)) * (float3(1.0) / (float3(1.0) + (float3(18.6875) * _2089))), float3(78.84375)); + } + else + { + float3 _1260; + if (_Globals.OutputDevice == 7u) + { + float3 _1252 = pow(((_906 * _547) * _576) * float3(9.9999997473787516355514526367188e-05), float3(0.1593017578125)); + _1260 = pow((float3(0.8359375) + (float3(18.8515625) * _1252)) * (float3(1.0) / (float3(1.0) + (float3(18.6875) * _1252))), float3(78.84375)); + } + else + { + _1260 = pow((_1218 * _547) * _576, float3(_Globals.InverseGamma.z)); + } + _2097 = _1260; + } + _2950 = _2097; + } + _2960 = _2950; + } + _3001 = _2960; + } + float3 _3002 = _3001 * float3(0.95238101482391357421875); + float4 _3004 = float4(_3002.x, _3002.y, _3002.z, float4(0.0).w); + _3004.w = 0.0; + out.out_var_SV_Target0 = _3004; + return out; +} + diff --git a/third_party/spirv-cross/reference/shaders-ue4/asm/frag/padded-float-array-member-defef.asm.frag b/third_party/spirv-cross/reference/shaders-ue4/asm/frag/padded-float-array-member-defef.asm.frag new file mode 100644 index 0000000000..67fa21aadd --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-ue4/asm/frag/padded-float-array-member-defef.asm.frag @@ -0,0 +1,1414 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + +#include +#include + +using namespace metal; + +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +struct type_Globals +{ + float4 MappingPolynomial; + float3 InverseGamma; + float4 ColorMatrixR_ColorCurveCd1; + float4 ColorMatrixG_ColorCurveCd3Cm3; + float4 ColorMatrixB_ColorCurveCm2; + float4 ColorCurve_Cm0Cd0_Cd2_Ch0Cm1_Ch3; + float4 ColorCurve_Ch1_Ch2; + float4 ColorShadow_Luma; + float4 ColorShadow_Tint1; + float4 ColorShadow_Tint2; + float FilmSlope; + float FilmToe; + float FilmShoulder; + float FilmBlackClip; + float FilmWhiteClip; + float4 LUTWeights[5]; + float3 ColorScale; + float4 OverlayColor; + float WhiteTemp; + float WhiteTint; + float4 ColorSaturation; + float4 ColorContrast; + float4 ColorGamma; + float4 ColorGain; + float4 ColorOffset; + float4 ColorSaturationShadows; + float4 ColorContrastShadows; + float4 ColorGammaShadows; + float4 ColorGainShadows; + float4 ColorOffsetShadows; + float4 ColorSaturationMidtones; + float4 ColorContrastMidtones; + float4 ColorGammaMidtones; + float4 ColorGainMidtones; + float4 ColorOffsetMidtones; + float4 ColorSaturationHighlights; + float4 ColorContrastHighlights; + float4 ColorGammaHighlights; + float4 ColorGainHighlights; + float4 ColorOffsetHighlights; + float ColorCorrectionShadowsMax; + float ColorCorrectionHighlightsMin; + uint OutputDevice; + uint OutputGamut; + float BlueCorrection; + float ExpandGamut; +}; + +constant spvUnsafeArray _499 = spvUnsafeArray({ -4.0, -4.0, -3.1573765277862548828125, -0.485249996185302734375, 1.84773242473602294921875, 1.84773242473602294921875 }); +constant spvUnsafeArray _500 = spvUnsafeArray({ -0.718548238277435302734375, 2.0810306072235107421875, 3.66812419891357421875, 4.0, 4.0, 4.0 }); +constant spvUnsafeArray _503 = spvUnsafeArray({ -4.97062206268310546875, -3.0293781757354736328125, -2.1261999607086181640625, -1.5104999542236328125, -1.0578000545501708984375, -0.4668000042438507080078125, 0.11937999725341796875, 0.7088134288787841796875, 1.2911865711212158203125, 1.2911865711212158203125 }); +constant spvUnsafeArray _504 = spvUnsafeArray({ 0.80891323089599609375, 1.19108676910400390625, 1.5683000087738037109375, 1.94830000400543212890625, 2.308300018310546875, 2.63840007781982421875, 2.85949993133544921875, 2.9872608184814453125, 3.0127391815185546875, 3.0127391815185546875 }); +constant spvUnsafeArray _506 = spvUnsafeArray({ -2.3010299205780029296875, -2.3010299205780029296875, -1.9312000274658203125, -1.5204999446868896484375, -1.0578000545501708984375, -0.4668000042438507080078125, 0.11937999725341796875, 0.7088134288787841796875, 1.2911865711212158203125, 1.2911865711212158203125 }); +constant spvUnsafeArray _507 = spvUnsafeArray({ 0.801995217800140380859375, 1.19800484180450439453125, 1.5943000316619873046875, 1.99730002880096435546875, 2.3782999515533447265625, 2.7683999538421630859375, 3.0515000820159912109375, 3.2746293544769287109375, 3.32743072509765625, 3.32743072509765625 }); + +constant float3 _523 = {}; +constant float3 _525 = {}; + +struct main0_out +{ + float4 out_var_SV_Target0 [[color(0)]]; +}; + +struct main0_in +{ + float2 in_var_TEXCOORD0 [[user(locn0), center_no_perspective]]; +}; + +fragment main0_out main0(main0_in in [[stage_in]], constant type_Globals& _Globals [[buffer(0)]], texture2d Texture1 [[texture(0)]], sampler Texture1Sampler [[sampler(0)]], uint gl_Layer [[render_target_array_index]]) +{ + main0_out out = {}; + float3x3 _572 = float3x3(float3(0.41245639324188232421875, 0.3575761020183563232421875, 0.180437505245208740234375), float3(0.21267290413379669189453125, 0.715152204036712646484375, 0.072175003588199615478515625), float3(0.01933390088379383087158203125, 0.119191996753215789794921875, 0.950304090976715087890625)) * float3x3(float3(1.01303005218505859375, 0.0061053098179399967193603515625, -0.014971000142395496368408203125), float3(0.0076982299797236919403076171875, 0.99816501140594482421875, -0.005032029934227466583251953125), float3(-0.0028413101099431514739990234375, 0.0046851597726345062255859375, 0.92450702190399169921875)); + float3x3 _573 = _572 * float3x3(float3(1.6410233974456787109375, -0.324803292751312255859375, -0.23642469942569732666015625), float3(-0.663662850856781005859375, 1.6153316497802734375, 0.016756348311901092529296875), float3(0.01172189414501190185546875, -0.008284442126750946044921875, 0.98839485645294189453125)); + float3x3 _574 = float3x3(float3(0.662454187870025634765625, 0.1340042054653167724609375, 0.1561876833438873291015625), float3(0.272228717803955078125, 0.674081742763519287109375, 0.053689517080783843994140625), float3(-0.0055746496655046939849853515625, 0.0040607335977256298065185546875, 1.01033914089202880859375)) * float3x3(float3(0.98722398281097412109375, -0.0061132698319852352142333984375, 0.01595330052077770233154296875), float3(-0.007598360069096088409423828125, 1.00186002254486083984375, 0.0053300200961530208587646484375), float3(0.003072570078074932098388671875, -0.0050959498621523380279541015625, 1.0816800594329833984375)); + float3x3 _575 = _574 * float3x3(float3(3.2409698963165283203125, -1.53738319873809814453125, -0.4986107647418975830078125), float3(-0.96924364566802978515625, 1.875967502593994140625, 0.0415550582110881805419921875), float3(0.055630080401897430419921875, -0.2039769589900970458984375, 1.05697154998779296875)); + float3x3 _576 = float3x3(float3(0.952552378177642822265625, 0.0, 9.25), float3(0.3439664542675018310546875, 0.728166103363037109375, -0.07213254272937774658203125), float3(0.0, 0.0, 1.00882518291473388671875)) * float3x3(float3(1.6410233974456787109375, -0.324803292751312255859375, -0.23642469942569732666015625), float3(-0.663662850856781005859375, 1.6153316497802734375, 0.016756348311901092529296875), float3(0.01172189414501190185546875, -0.008284442126750946044921875, 0.98839485645294189453125)); + float3x3 _577 = float3x3(float3(0.662454187870025634765625, 0.1340042054653167724609375, 0.1561876833438873291015625), float3(0.272228717803955078125, 0.674081742763519287109375, 0.053689517080783843994140625), float3(-0.0055746496655046939849853515625, 0.0040607335977256298065185546875, 1.01033914089202880859375)) * float3x3(float3(1.04981100559234619140625, 0.0, -9.74845024757087230682373046875e-05), float3(-0.49590301513671875, 1.37331306934356689453125, 0.09824003279209136962890625), float3(0.0, 0.0, 0.991252005100250244140625)); + float3x3 _602; + for (;;) + { + if (_Globals.OutputGamut == 1u) + { + _602 = _574 * float3x3(float3(2.493396282196044921875, -0.931345880031585693359375, -0.4026944935321807861328125), float3(-0.829486787319183349609375, 1.76265966892242431640625, 0.02362460084259510040283203125), float3(0.0358506999909877777099609375, -0.076182700693607330322265625, 0.957014024257659912109375)); + break; + } + else + { + if (_Globals.OutputGamut == 2u) + { + _602 = _574 * float3x3(float3(1.71660840511322021484375, -0.3556621074676513671875, -0.253360092639923095703125), float3(-0.666682898998260498046875, 1.61647760868072509765625, 0.01576850004494190216064453125), float3(0.017642199993133544921875, -0.04277630150318145751953125, 0.94222867488861083984375)); + break; + } + else + { + if (_Globals.OutputGamut == 3u) + { + _602 = float3x3(float3(0.695452213287353515625, 0.140678703784942626953125, 0.16386906802654266357421875), float3(0.0447945632040500640869140625, 0.859671115875244140625, 0.095534317195415496826171875), float3(-0.0055258828215301036834716796875, 0.0040252101607620716094970703125, 1.00150072574615478515625)); + break; + } + else + { + if (_Globals.OutputGamut == 4u) + { + _602 = float3x3(float3(1.0, 0.0, 0.0), float3(0.0, 1.0, 0.0), float3(0.0, 0.0, 1.0)); + break; + } + else + { + _602 = _575; + break; + } + } + } + } + } + float3 _603 = float4((in.in_var_TEXCOORD0 - float2(0.015625)) * float2(1.03225803375244140625), float(gl_Layer) * 0.0322580635547637939453125, 0.0).xyz; + float3 _625; + if (_Globals.OutputDevice >= 3u) + { + float3 _617 = pow(_603, float3(0.0126833133399486541748046875)); + _625 = pow(fast::max(float3(0.0), _617 - float3(0.8359375)) / (float3(18.8515625) - (float3(18.6875) * _617)), float3(6.277394771575927734375)) * float3(10000.0); + } + else + { + _625 = (exp2((_603 - float3(0.434017598628997802734375)) * float3(14.0)) * float3(0.180000007152557373046875)) - (exp2(float3(-6.0762462615966796875)) * float3(0.180000007152557373046875)); + } + float _628 = _Globals.WhiteTemp * 1.00055634975433349609375; + float _642 = (_628 <= 7000.0) ? (0.24406300485134124755859375 + ((99.1100006103515625 + ((2967800.0 - (4604438528.0 / _Globals.WhiteTemp)) / _628)) / _628)) : (0.23703999817371368408203125 + ((247.4799957275390625 + ((1901800.0 - (2005284352.0 / _Globals.WhiteTemp)) / _628)) / _628)); + float _659 = ((0.860117733478546142578125 + (0.00015411825734190642833709716796875 * _Globals.WhiteTemp)) + ((1.2864121856637211749330163002014e-07 * _Globals.WhiteTemp) * _Globals.WhiteTemp)) / ((1.0 + (0.0008424202096648514270782470703125 * _Globals.WhiteTemp)) + ((7.0814513719597016461193561553955e-07 * _Globals.WhiteTemp) * _Globals.WhiteTemp)); + float _670 = ((0.317398726940155029296875 + (4.25 * _Globals.WhiteTemp)) + ((4.2048167614439080352894961833954e-08 * _Globals.WhiteTemp) * _Globals.WhiteTemp)) / ((1.0 - (2.8974181986995972692966461181641e-05 * _Globals.WhiteTemp)) + ((1.6145605741257895715534687042236e-07 * _Globals.WhiteTemp) * _Globals.WhiteTemp)); + float _675 = ((2.0 * _659) - (8.0 * _670)) + 4.0; + float2 _679 = float2((3.0 * _659) / _675, (2.0 * _670) / _675); + float2 _686 = normalize(float2(_659, _670)); + float _691 = _659 + (((-_686.y) * _Globals.WhiteTint) * 0.0500000007450580596923828125); + float _695 = _670 + ((_686.x * _Globals.WhiteTint) * 0.0500000007450580596923828125); + float _700 = ((2.0 * _691) - (8.0 * _695)) + 4.0; + float2 _706 = select(float2(_642, ((((-3.0) * _642) * _642) + (2.86999988555908203125 * _642)) - 0.2750000059604644775390625), _679, bool2(_Globals.WhiteTemp < 4000.0)) + (float2((3.0 * _691) / _700, (2.0 * _695) / _700) - _679); + float _707 = _706.x; + float _708 = _706.y; + float _709 = fast::max(_708, 1.0000000133514319600180897396058e-10); + float3 _711 = _523; + _711.x = _707 / _709; + float3 _712 = _711; + _712.y = 1.0; + float3 _716 = _712; + _716.z = ((1.0 - _707) - _708) / _709; + float _717 = fast::max(0.328999996185302734375, 1.0000000133514319600180897396058e-10); + float3 _719 = _523; + _719.x = 0.3127000033855438232421875 / _717; + float3 _720 = _719; + _720.y = 1.0; + float3 _722 = _720; + _722.z = 0.3582999706268310546875 / _717; + float3 _723 = _716 * float3x3(float3(0.89509999752044677734375, 0.2664000093936920166015625, -0.16140000522136688232421875), float3(-0.750199973583221435546875, 1.71350002288818359375, 0.0366999991238117218017578125), float3(0.0388999991118907928466796875, -0.06849999725818634033203125, 1.02960002422332763671875)); + float3 _724 = _722 * float3x3(float3(0.89509999752044677734375, 0.2664000093936920166015625, -0.16140000522136688232421875), float3(-0.750199973583221435546875, 1.71350002288818359375, 0.0366999991238117218017578125), float3(0.0388999991118907928466796875, -0.06849999725818634033203125, 1.02960002422332763671875)); + float3 _743 = (_625 * ((float3x3(float3(0.41245639324188232421875, 0.3575761020183563232421875, 0.180437505245208740234375), float3(0.21267290413379669189453125, 0.715152204036712646484375, 0.072175003588199615478515625), float3(0.01933390088379383087158203125, 0.119191996753215789794921875, 0.950304090976715087890625)) * ((float3x3(float3(0.89509999752044677734375, 0.2664000093936920166015625, -0.16140000522136688232421875), float3(-0.750199973583221435546875, 1.71350002288818359375, 0.0366999991238117218017578125), float3(0.0388999991118907928466796875, -0.06849999725818634033203125, 1.02960002422332763671875)) * float3x3(float3(_724.x / _723.x, 0.0, 0.0), float3(0.0, _724.y / _723.y, 0.0), float3(0.0, 0.0, _724.z / _723.z))) * float3x3(float3(0.986992895603179931640625, -0.14705429971218109130859375, 0.15996269881725311279296875), float3(0.4323053061962127685546875, 0.518360316753387451171875, 0.049291200935840606689453125), float3(-0.00852870009839534759521484375, 0.0400427989661693572998046875, 0.968486726284027099609375)))) * float3x3(float3(3.2409698963165283203125, -1.53738319873809814453125, -0.4986107647418975830078125), float3(-0.96924364566802978515625, 1.875967502593994140625, 0.0415550582110881805419921875), float3(0.055630080401897430419921875, -0.2039769589900970458984375, 1.05697154998779296875)))) * _573; + float3 _771; + if (_Globals.ColorShadow_Tint2.w != 0.0) + { + float _750 = dot(_743, float3(0.272228717803955078125, 0.674081742763519287109375, 0.053689517080783843994140625)); + float3 _753 = (_743 / float3(_750)) - float3(1.0); + _771 = mix(_743, _743 * (_575 * (float3x3(float3(0.544169127941131591796875, 0.23959259688854217529296875, 0.16669429838657379150390625), float3(0.23946559429168701171875, 0.702153027057647705078125, 0.058381401002407073974609375), float3(-0.0023439000360667705535888671875, 0.0361833982169628143310546875, 1.05521833896636962890625)) * float3x3(float3(1.6410233974456787109375, -0.324803292751312255859375, -0.23642469942569732666015625), float3(-0.663662850856781005859375, 1.6153316497802734375, 0.016756348311901092529296875), float3(0.01172189414501190185546875, -0.008284442126750946044921875, 0.98839485645294189453125)))), float3((1.0 - exp2((-4.0) * dot(_753, _753))) * (1.0 - exp2((((-4.0) * _Globals.ExpandGamut) * _750) * _750)))); + } + else + { + _771 = _743; + } + float _772 = dot(_771, float3(0.272228717803955078125, 0.674081742763519287109375, 0.053689517080783843994140625)); + float4 _777 = _Globals.ColorSaturationShadows * _Globals.ColorSaturation; + float4 _782 = _Globals.ColorContrastShadows * _Globals.ColorContrast; + float4 _787 = _Globals.ColorGammaShadows * _Globals.ColorGamma; + float4 _792 = _Globals.ColorGainShadows * _Globals.ColorGain; + float4 _797 = _Globals.ColorOffsetShadows + _Globals.ColorOffset; + float3 _798 = float3(_772); + float _830 = smoothstep(0.0, _Globals.ColorCorrectionShadowsMax, _772); + float4 _834 = _Globals.ColorSaturationHighlights * _Globals.ColorSaturation; + float4 _837 = _Globals.ColorContrastHighlights * _Globals.ColorContrast; + float4 _840 = _Globals.ColorGammaHighlights * _Globals.ColorGamma; + float4 _843 = _Globals.ColorGainHighlights * _Globals.ColorGain; + float4 _846 = _Globals.ColorOffsetHighlights + _Globals.ColorOffset; + float _878 = smoothstep(_Globals.ColorCorrectionHighlightsMin, 1.0, _772); + float4 _881 = _Globals.ColorSaturationMidtones * _Globals.ColorSaturation; + float4 _884 = _Globals.ColorContrastMidtones * _Globals.ColorContrast; + float4 _887 = _Globals.ColorGammaMidtones * _Globals.ColorGamma; + float4 _890 = _Globals.ColorGainMidtones * _Globals.ColorGain; + float4 _893 = _Globals.ColorOffsetMidtones + _Globals.ColorOffset; + float3 _931 = ((((pow(pow(fast::max(float3(0.0), mix(_798, _771, _777.xyz * float3(_777.w))) * float3(5.5555553436279296875), _782.xyz * float3(_782.w)) * float3(0.180000007152557373046875), float3(1.0) / (_787.xyz * float3(_787.w))) * (_792.xyz * float3(_792.w))) + (_797.xyz + float3(_797.w))) * float3(1.0 - _830)) + (((pow(pow(fast::max(float3(0.0), mix(_798, _771, _881.xyz * float3(_881.w))) * float3(5.5555553436279296875), _884.xyz * float3(_884.w)) * float3(0.180000007152557373046875), float3(1.0) / (_887.xyz * float3(_887.w))) * (_890.xyz * float3(_890.w))) + (_893.xyz + float3(_893.w))) * float3(_830 - _878))) + (((pow(pow(fast::max(float3(0.0), mix(_798, _771, _834.xyz * float3(_834.w))) * float3(5.5555553436279296875), _837.xyz * float3(_837.w)) * float3(0.180000007152557373046875), float3(1.0) / (_840.xyz * float3(_840.w))) * (_843.xyz * float3(_843.w))) + (_846.xyz + float3(_846.w))) * float3(_878)); + float3 _932 = _931 * _575; + float3 _940 = float3(_Globals.BlueCorrection); + float3 _942 = mix(_931, _931 * ((_577 * float3x3(float3(0.940437257289886474609375, -0.01830687932670116424560546875, 0.07786960899829864501953125), float3(0.008378696627914905548095703125, 0.82866001129150390625, 0.162961304187774658203125), float3(0.0005471261101774871349334716796875, -0.00088337459601461887359619140625, 1.00033628940582275390625))) * _576), _940) * _577; + float _943 = _942.x; + float _944 = _942.y; + float _946 = _942.z; + float _949 = fast::max(fast::max(_943, _944), _946); + float _954 = (fast::max(_949, 1.0000000133514319600180897396058e-10) - fast::max(fast::min(fast::min(_943, _944), _946), 1.0000000133514319600180897396058e-10)) / fast::max(_949, 0.00999999977648258209228515625); + float _967 = ((_946 + _944) + _943) + (1.75 * sqrt(((_946 * (_946 - _944)) + (_944 * (_944 - _943))) + (_943 * (_943 - _946)))); + float _968 = _967 * 0.3333333432674407958984375; + float _969 = _954 - 0.4000000059604644775390625; + float _974 = fast::max(1.0 - abs(_969 * 2.5), 0.0); + float _982 = (1.0 + (float(int(sign(_969 * 5.0))) * (1.0 - (_974 * _974)))) * 0.02500000037252902984619140625; + float _995; + if (_968 <= 0.053333334624767303466796875) + { + _995 = _982; + } + else + { + float _994; + if (_968 >= 0.1599999964237213134765625) + { + _994 = 0.0; + } + else + { + _994 = _982 * ((0.23999999463558197021484375 / _967) - 0.5); + } + _995 = _994; + } + float3 _998 = _942 * float3(1.0 + _995); + float _999 = _998.x; + float _1000 = _998.y; + float _1002 = _998.z; + float _1016; + if ((_999 == _1000) && (_1000 == _1002)) + { + _1016 = 0.0; + } + else + { + _1016 = 57.2957763671875 * atan2(sqrt(3.0) * (_1000 - _1002), ((2.0 * _999) - _1000) - _1002); + } + float _1021; + if (_1016 < 0.0) + { + _1021 = _1016 + 360.0; + } + else + { + _1021 = _1016; + } + float _1022 = fast::clamp(_1021, 0.0, 360.0); + float _1027; + if (_1022 > 180.0) + { + _1027 = _1022 - 360.0; + } + else + { + _1027 = _1022; + } + float _1031 = smoothstep(0.0, 1.0, 1.0 - abs(_1027 * 0.01481481455266475677490234375)); + float3 _1038 = _998; + _1038.x = _999 + ((((_1031 * _1031) * _954) * (0.02999999932944774627685546875 - _999)) * 0.180000007152557373046875); + float3 _1040 = fast::max(float3(0.0), _1038 * float3x3(float3(1.45143926143646240234375, -0.236510753631591796875, -0.214928567409515380859375), float3(-0.07655377686023712158203125, 1.1762297153472900390625, -0.0996759235858917236328125), float3(0.0083161480724811553955078125, -0.0060324496589601039886474609375, 0.99771630764007568359375))); + float _1049 = (1.0 + _Globals.FilmBlackClip) - _Globals.FilmToe; + float _1052 = 1.0 + _Globals.FilmWhiteClip; + float _1055 = _1052 - _Globals.FilmShoulder; + float _1082; + if (_Globals.FilmToe > 0.800000011920928955078125) + { + _1082 = ((0.819999992847442626953125 - _Globals.FilmToe) / _Globals.FilmSlope) + (log(0.180000007152557373046875) / log(10.0)); + } + else + { + float _1061 = (0.180000007152557373046875 + _Globals.FilmBlackClip) / _1049; + _1082 = (log(0.180000007152557373046875) / log(10.0)) - ((0.5 * log(_1061 / (2.0 - _1061))) * (_1049 / _Globals.FilmSlope)); + } + float _1087 = ((1.0 - _Globals.FilmToe) / _Globals.FilmSlope) - _1082; + float _1089 = (_Globals.FilmShoulder / _Globals.FilmSlope) - _1087; + float _1091 = log(10.0); + float3 _1093 = log(mix(float3(dot(_1040, float3(0.272228717803955078125, 0.674081742763519287109375, 0.053689517080783843994140625))), _1040, float3(0.959999978542327880859375))) / float3(_1091); + float3 _1097 = float3(_Globals.FilmSlope) * (_1093 + float3(_1087)); + float3 _1105 = float3(_1082); + float3 _1106 = _1093 - _1105; + float3 _1118 = float3(_1089); + float3 _1132 = fast::clamp(_1106 / float3(_1089 - _1082), float3(0.0), float3(1.0)); + float3 _1136 = select(_1132, float3(1.0) - _1132, bool3(_1089 < _1082)); + float3 _1141 = mix(select(_1097, float3(-_Globals.FilmBlackClip) + (float3(2.0 * _1049) / (float3(1.0) + exp(float3(((-2.0) * _Globals.FilmSlope) / _1049) * _1106))), _1093 < _1105), select(_1097, float3(_1052) - (float3(2.0 * _1055) / (float3(1.0) + exp(float3((2.0 * _Globals.FilmSlope) / _1055) * (_1093 - _1118)))), _1093 > _1118), ((float3(3.0) - (float3(2.0) * _1136)) * _1136) * _1136); + float3 _1145 = fast::max(float3(0.0), mix(float3(dot(_1141, float3(0.272228717803955078125, 0.674081742763519287109375, 0.053689517080783843994140625))), _1141, float3(0.930000007152557373046875))); + float3 _1215; + if (_Globals.ColorShadow_Tint2.w == 0.0) + { + float3 _1157 = _525; + _1157.x = dot(_932, _Globals.ColorMatrixR_ColorCurveCd1.xyz); + float3 _1162 = _1157; + _1162.y = dot(_932, _Globals.ColorMatrixG_ColorCurveCd3Cm3.xyz); + float3 _1167 = _1162; + _1167.z = dot(_932, _Globals.ColorMatrixB_ColorCurveCm2.xyz); + float3 _1183 = fast::max(float3(0.0), _1167 * (_Globals.ColorShadow_Tint1.xyz + (_Globals.ColorShadow_Tint2.xyz * float3(1.0 / (dot(_932, _Globals.ColorShadow_Luma.xyz) + 1.0))))); + float3 _1188 = fast::max(float3(0.0), _Globals.ColorCurve_Cm0Cd0_Cd2_Ch0Cm1_Ch3.xxx - _1183); + float3 _1190 = fast::max(_1183, _Globals.ColorCurve_Cm0Cd0_Cd2_Ch0Cm1_Ch3.zzz); + _1215 = ((((_1190 * _Globals.ColorCurve_Ch1_Ch2.xxx) + _Globals.ColorCurve_Ch1_Ch2.yyy) * (float3(1.0) / (_1190 + _Globals.ColorCurve_Cm0Cd0_Cd2_Ch0Cm1_Ch3.www))) + ((fast::clamp(_1183, _Globals.ColorCurve_Cm0Cd0_Cd2_Ch0Cm1_Ch3.xxx, _Globals.ColorCurve_Cm0Cd0_Cd2_Ch0Cm1_Ch3.zzz) * _Globals.ColorMatrixB_ColorCurveCm2.www) + (((_1188 * _Globals.ColorMatrixR_ColorCurveCd1.www) * (float3(1.0) / (_1188 + _Globals.ColorCurve_Cm0Cd0_Cd2_Ch0Cm1_Ch3.yyy))) + _Globals.ColorMatrixG_ColorCurveCd3Cm3.www))) - float3(0.00200000009499490261077880859375); + } + else + { + _1215 = fast::max(float3(0.0), mix(_1145, _1145 * ((_577 * float3x3(float3(1.06317996978759765625, 0.02339559979736804962158203125, -0.08657260239124298095703125), float3(-0.010633699595928192138671875, 1.2063200473785400390625, -0.1956900060176849365234375), float3(-0.0005908869788981974124908447265625, 0.00105247995816171169281005859375, 0.999538004398345947265625))) * _576), _940) * _575); + } + float3 _1216 = fast::clamp(_1215, float3(0.0), float3(1.0)); + float _1217 = _1216.x; + float _1229; + for (;;) + { + if (_1217 < 0.00313066993840038776397705078125) + { + _1229 = _1217 * 12.9200000762939453125; + break; + } + _1229 = (pow(_1217, 0.4166666567325592041015625) * 1.05499994754791259765625) - 0.054999999701976776123046875; + break; + } + float _1230 = _1216.y; + float _1242; + for (;;) + { + if (_1230 < 0.00313066993840038776397705078125) + { + _1242 = _1230 * 12.9200000762939453125; + break; + } + _1242 = (pow(_1230, 0.4166666567325592041015625) * 1.05499994754791259765625) - 0.054999999701976776123046875; + break; + } + float _1243 = _1216.z; + float _1255; + for (;;) + { + if (_1243 < 0.00313066993840038776397705078125) + { + _1255 = _1243 * 12.9200000762939453125; + break; + } + _1255 = (pow(_1243, 0.4166666567325592041015625) * 1.05499994754791259765625) - 0.054999999701976776123046875; + break; + } + float3 _1256 = float3(_1229, _1242, _1255); + float3 _1258 = (_1256 * float3(0.9375)) + float3(0.03125); + float _1270 = (_1258.z * 16.0) - 0.5; + float _1271 = floor(_1270); + float _1275 = (_1258.x + _1271) * 0.0625; + float _1276 = _1258.y; + float4 _1279 = Texture1.sample(Texture1Sampler, float2(_1275, _1276)); + float4 _1283 = Texture1.sample(Texture1Sampler, float2(_1275 + 0.0625, _1276)); + float3 _1289 = fast::max(float3(6.1035199905745685100555419921875e-05), (float3(_Globals.LUTWeights[0].x) * _1256) + (float3(_Globals.LUTWeights[1].x) * mix(_1279, _1283, float4(_1270 - _1271)).xyz)); + float3 _1295 = select(_1289 * float3(0.077399380505084991455078125), pow((_1289 * float3(0.94786727428436279296875)) + float3(0.0521326996386051177978515625), float3(2.400000095367431640625)), _1289 > float3(0.040449999272823333740234375)); + float3 _1324 = pow(fast::max(float3(0.0), mix((((float3(_Globals.MappingPolynomial.x) * (_1295 * _1295)) + (float3(_Globals.MappingPolynomial.y) * _1295)) + float3(_Globals.MappingPolynomial.z)) * _Globals.ColorScale, _Globals.OverlayColor.xyz, float3(_Globals.OverlayColor.w))), float3(_Globals.InverseGamma.y)); + float3 _3103; + if (_Globals.OutputDevice == 0u) + { + float _3063 = _1324.x; + float _3075; + for (;;) + { + if (_3063 < 0.00313066993840038776397705078125) + { + _3075 = _3063 * 12.9200000762939453125; + break; + } + _3075 = (pow(_3063, 0.4166666567325592041015625) * 1.05499994754791259765625) - 0.054999999701976776123046875; + break; + } + float _3076 = _1324.y; + float _3088; + for (;;) + { + if (_3076 < 0.00313066993840038776397705078125) + { + _3088 = _3076 * 12.9200000762939453125; + break; + } + _3088 = (pow(_3076, 0.4166666567325592041015625) * 1.05499994754791259765625) - 0.054999999701976776123046875; + break; + } + float _3089 = _1324.z; + float _3101; + for (;;) + { + if (_3089 < 0.00313066993840038776397705078125) + { + _3101 = _3089 * 12.9200000762939453125; + break; + } + _3101 = (pow(_3089, 0.4166666567325592041015625) * 1.05499994754791259765625) - 0.054999999701976776123046875; + break; + } + _3103 = float3(_3075, _3088, _3101); + } + else + { + float3 _3062; + if (_Globals.OutputDevice == 1u) + { + float3 _3055 = fast::max(float3(6.1035199905745685100555419921875e-05), (_1324 * _573) * _602); + _3062 = fast::min(_3055 * float3(4.5), (pow(fast::max(_3055, float3(0.017999999225139617919921875)), float3(0.449999988079071044921875)) * float3(1.09899997711181640625)) - float3(0.098999999463558197021484375)); + } + else + { + float3 _3052; + if ((_Globals.OutputDevice == 3u) || (_Globals.OutputDevice == 5u)) + { + float3 _2204 = (_932 * float3(1.5)) * (_572 * float3x3(float3(1.04981100559234619140625, 0.0, -9.74845024757087230682373046875e-05), float3(-0.49590301513671875, 1.37331306934356689453125, 0.09824003279209136962890625), float3(0.0, 0.0, 0.991252005100250244140625))); + float _2205 = _2204.x; + float _2206 = _2204.y; + float _2208 = _2204.z; + float _2211 = fast::max(fast::max(_2205, _2206), _2208); + float _2216 = (fast::max(_2211, 1.0000000133514319600180897396058e-10) - fast::max(fast::min(fast::min(_2205, _2206), _2208), 1.0000000133514319600180897396058e-10)) / fast::max(_2211, 0.00999999977648258209228515625); + float _2229 = ((_2208 + _2206) + _2205) + (1.75 * sqrt(((_2208 * (_2208 - _2206)) + (_2206 * (_2206 - _2205))) + (_2205 * (_2205 - _2208)))); + float _2230 = _2229 * 0.3333333432674407958984375; + float _2231 = _2216 - 0.4000000059604644775390625; + float _2236 = fast::max(1.0 - abs(_2231 * 2.5), 0.0); + float _2244 = (1.0 + (float(int(sign(_2231 * 5.0))) * (1.0 - (_2236 * _2236)))) * 0.02500000037252902984619140625; + float _2257; + if (_2230 <= 0.053333334624767303466796875) + { + _2257 = _2244; + } + else + { + float _2256; + if (_2230 >= 0.1599999964237213134765625) + { + _2256 = 0.0; + } + else + { + _2256 = _2244 * ((0.23999999463558197021484375 / _2229) - 0.5); + } + _2257 = _2256; + } + float3 _2260 = _2204 * float3(1.0 + _2257); + float _2261 = _2260.x; + float _2262 = _2260.y; + float _2264 = _2260.z; + float _2278; + if ((_2261 == _2262) && (_2262 == _2264)) + { + _2278 = 0.0; + } + else + { + _2278 = 57.2957763671875 * atan2(sqrt(3.0) * (_2262 - _2264), ((2.0 * _2261) - _2262) - _2264); + } + float _2283; + if (_2278 < 0.0) + { + _2283 = _2278 + 360.0; + } + else + { + _2283 = _2278; + } + float _2284 = fast::clamp(_2283, 0.0, 360.0); + float _2289; + if (_2284 > 180.0) + { + _2289 = _2284 - 360.0; + } + else + { + _2289 = _2284; + } + float _2339; + if ((_2289 > (-67.5)) && (_2289 < 67.5)) + { + float _2296 = (_2289 - (-67.5)) * 0.0296296291053295135498046875; + int _2297 = int(_2296); + float _2299 = _2296 - float(_2297); + float _2300 = _2299 * _2299; + float _2301 = _2300 * _2299; + float _2338; + if (_2297 == 3) + { + _2338 = (((_2301 * (-0.16666667163372039794921875)) + (_2300 * 0.5)) + (_2299 * (-0.5))) + 0.16666667163372039794921875; + } + else + { + float _2331; + if (_2297 == 2) + { + _2331 = ((_2301 * 0.5) + (_2300 * (-1.0))) + 0.666666686534881591796875; + } + else + { + float _2326; + if (_2297 == 1) + { + _2326 = (((_2301 * (-0.5)) + (_2300 * 0.5)) + (_2299 * 0.5)) + 0.16666667163372039794921875; + } + else + { + float _2319; + if (_2297 == 0) + { + _2319 = _2301 * 0.16666667163372039794921875; + } + else + { + _2319 = 0.0; + } + _2326 = _2319; + } + _2331 = _2326; + } + _2338 = _2331; + } + _2339 = _2338; + } + else + { + _2339 = 0.0; + } + float3 _2346 = _2260; + _2346.x = _2261 + ((((_2339 * 1.5) * _2216) * (0.02999999932944774627685546875 - _2261)) * 0.180000007152557373046875); + float3 _2349 = fast::clamp(fast::clamp(_2346, float3(0.0), float3(65535.0)) * float3x3(float3(1.45143926143646240234375, -0.236510753631591796875, -0.214928567409515380859375), float3(-0.07655377686023712158203125, 1.1762297153472900390625, -0.0996759235858917236328125), float3(0.0083161480724811553955078125, -0.0060324496589601039886474609375, 0.99771630764007568359375)), float3(0.0), float3(65535.0)); + float3 _2352 = mix(float3(dot(_2349, float3(0.272228717803955078125, 0.674081742763519287109375, 0.053689517080783843994140625))), _2349, float3(0.959999978542327880859375)); + float _2353 = _2352.x; + float _2357 = 0.17999999225139617919921875 * exp2(18.0); + float _2359 = exp2(-14.0); + float _2362 = log((_2353 <= 0.0) ? _2359 : _2353) / _1091; + float _2364 = log(0.17999999225139617919921875 * exp2(-15.0)) / _1091; + float _2431; + if (_2362 <= _2364) + { + _2431 = log(9.9999997473787516355514526367188e-05) / _1091; + } + else + { + float _2371 = log(0.180000007152557373046875) / _1091; + float _2428; + if ((_2362 > _2364) && (_2362 < _2371)) + { + float _2411 = (3.0 * (_2362 - _2364)) / (_2371 - _2364); + int _2412 = int(_2411); + float _2414 = _2411 - float(_2412); + _2428 = dot(float3(_2414 * _2414, _2414, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_499[_2412], _499[_2412 + 1], _499[_2412 + 2])); + } + else + { + float _2379 = log(_2357) / _1091; + float _2407; + if ((_2362 >= _2371) && (_2362 < _2379)) + { + float _2390 = (3.0 * (_2362 - _2371)) / (_2379 - _2371); + int _2391 = int(_2390); + float _2393 = _2390 - float(_2391); + _2407 = dot(float3(_2393 * _2393, _2393, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_500[_2391], _500[_2391 + 1], _500[_2391 + 2])); + } + else + { + _2407 = log(10000.0) / _1091; + } + _2428 = _2407; + } + _2431 = _2428; + } + float3 _2433 = _523; + _2433.x = pow(10.0, _2431); + float _2434 = _2352.y; + float _2438 = log((_2434 <= 0.0) ? _2359 : _2434) / _1091; + float _2505; + if (_2438 <= _2364) + { + _2505 = log(9.9999997473787516355514526367188e-05) / _1091; + } + else + { + float _2445 = log(0.180000007152557373046875) / _1091; + float _2502; + if ((_2438 > _2364) && (_2438 < _2445)) + { + float _2485 = (3.0 * (_2438 - _2364)) / (_2445 - _2364); + int _2486 = int(_2485); + float _2488 = _2485 - float(_2486); + _2502 = dot(float3(_2488 * _2488, _2488, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_499[_2486], _499[_2486 + 1], _499[_2486 + 2])); + } + else + { + float _2453 = log(_2357) / _1091; + float _2481; + if ((_2438 >= _2445) && (_2438 < _2453)) + { + float _2464 = (3.0 * (_2438 - _2445)) / (_2453 - _2445); + int _2465 = int(_2464); + float _2467 = _2464 - float(_2465); + _2481 = dot(float3(_2467 * _2467, _2467, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_500[_2465], _500[_2465 + 1], _500[_2465 + 2])); + } + else + { + _2481 = log(10000.0) / _1091; + } + _2502 = _2481; + } + _2505 = _2502; + } + float3 _2507 = _2433; + _2507.y = pow(10.0, _2505); + float _2508 = _2352.z; + float _2512 = log((_2508 <= 0.0) ? _2359 : _2508) / _1091; + float _2579; + if (_2512 <= _2364) + { + _2579 = log(9.9999997473787516355514526367188e-05) / _1091; + } + else + { + float _2519 = log(0.180000007152557373046875) / _1091; + float _2576; + if ((_2512 > _2364) && (_2512 < _2519)) + { + float _2559 = (3.0 * (_2512 - _2364)) / (_2519 - _2364); + int _2560 = int(_2559); + float _2562 = _2559 - float(_2560); + _2576 = dot(float3(_2562 * _2562, _2562, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_499[_2560], _499[_2560 + 1], _499[_2560 + 2])); + } + else + { + float _2527 = log(_2357) / _1091; + float _2555; + if ((_2512 >= _2519) && (_2512 < _2527)) + { + float _2538 = (3.0 * (_2512 - _2519)) / (_2527 - _2519); + int _2539 = int(_2538); + float _2541 = _2538 - float(_2539); + _2555 = dot(float3(_2541 * _2541, _2541, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_500[_2539], _500[_2539 + 1], _500[_2539 + 2])); + } + else + { + _2555 = log(10000.0) / _1091; + } + _2576 = _2555; + } + _2579 = _2576; + } + float3 _2581 = _2507; + _2581.z = pow(10.0, _2579); + float3 _2583 = (_2581 * float3x3(float3(0.695452213287353515625, 0.140678703784942626953125, 0.16386906802654266357421875), float3(0.0447945632040500640869140625, 0.859671115875244140625, 0.095534317195415496826171875), float3(-0.0055258828215301036834716796875, 0.0040252101607620716094970703125, 1.00150072574615478515625))) * float3x3(float3(1.45143926143646240234375, -0.236510753631591796875, -0.214928567409515380859375), float3(-0.07655377686023712158203125, 1.1762297153472900390625, -0.0996759235858917236328125), float3(0.0083161480724811553955078125, -0.0060324496589601039886474609375, 0.99771630764007568359375)); + float _2585 = 0.17999999225139617919921875 * pow(2.0, -12.0); + float _2589 = log((_2585 <= 0.0) ? _2359 : _2585) / _1091; + float _2656; + if (_2589 <= _2364) + { + _2656 = log(9.9999997473787516355514526367188e-05) / _1091; + } + else + { + float _2596 = log(0.180000007152557373046875) / _1091; + float _2653; + if ((_2589 > _2364) && (_2589 < _2596)) + { + float _2636 = (3.0 * (_2589 - _2364)) / (_2596 - _2364); + int _2637 = int(_2636); + float _2639 = _2636 - float(_2637); + _2653 = dot(float3(_2639 * _2639, _2639, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_499[_2637], _499[_2637 + 1], _499[_2637 + 2])); + } + else + { + float _2604 = log(_2357) / _1091; + float _2632; + if ((_2589 >= _2596) && (_2589 < _2604)) + { + float _2615 = (3.0 * (_2589 - _2596)) / (_2604 - _2596); + int _2616 = int(_2615); + float _2618 = _2615 - float(_2616); + _2632 = dot(float3(_2618 * _2618, _2618, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_500[_2616], _500[_2616 + 1], _500[_2616 + 2])); + } + else + { + _2632 = log(10000.0) / _1091; + } + _2653 = _2632; + } + _2656 = _2653; + } + float _2659 = log(0.180000007152557373046875) / _1091; + float _2713; + if (_2659 <= _2364) + { + _2713 = log(9.9999997473787516355514526367188e-05) / _1091; + } + else + { + float _2710; + if ((_2659 > _2364) && (_2659 < _2659)) + { + _2710 = (float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_499[3], _499[4], _499[5])).z; + } + else + { + float _2672 = log(_2357) / _1091; + float _2700; + if ((_2659 >= _2659) && (_2659 < _2672)) + { + float _2683 = (3.0 * (_2659 - _2659)) / (_2672 - _2659); + int _2684 = int(_2683); + float _2686 = _2683 - float(_2684); + _2700 = dot(float3(_2686 * _2686, _2686, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_500[_2684], _500[_2684 + 1], _500[_2684 + 2])); + } + else + { + _2700 = log(10000.0) / _1091; + } + _2710 = _2700; + } + _2713 = _2710; + } + float _2714 = pow(10.0, _2713); + float _2716 = 0.17999999225139617919921875 * pow(2.0, 10.0); + float _2720 = log((_2716 <= 0.0) ? _2359 : _2716) / _1091; + float _2785; + if (_2720 <= _2364) + { + _2785 = log(9.9999997473787516355514526367188e-05) / _1091; + } + else + { + float _2782; + if ((_2720 > _2364) && (_2720 < _2659)) + { + float _2765 = (3.0 * (_2720 - _2364)) / (_2659 - _2364); + int _2766 = int(_2765); + float _2768 = _2765 - float(_2766); + _2782 = dot(float3(_2768 * _2768, _2768, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_499[_2766], _499[_2766 + 1], _499[_2766 + 2])); + } + else + { + float _2733 = log(_2357) / _1091; + float _2761; + if ((_2720 >= _2659) && (_2720 < _2733)) + { + float _2744 = (3.0 * (_2720 - _2659)) / (_2733 - _2659); + int _2745 = int(_2744); + float _2747 = _2744 - float(_2745); + _2761 = dot(float3(_2747 * _2747, _2747, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_500[_2745], _500[_2745 + 1], _500[_2745 + 2])); + } + else + { + _2761 = log(10000.0) / _1091; + } + _2782 = _2761; + } + _2785 = _2782; + } + float _2786 = pow(10.0, _2785); + float _2787 = _2583.x; + float _2791 = log((_2787 <= 0.0) ? 9.9999997473787516355514526367188e-05 : _2787) / _1091; + float _2792 = log(pow(10.0, _2656)); + float _2793 = _2792 / _1091; + float _2870; + if (_2791 <= _2793) + { + _2870 = (_2791 * 3.0) + ((log(9.9999997473787516355514526367188e-05) / _1091) - ((3.0 * _2792) / _1091)); + } + else + { + float _2800 = log(_2714) / _1091; + float _2862; + if ((_2791 > _2793) && (_2791 < _2800)) + { + float _2845 = (7.0 * (_2791 - _2793)) / (_2800 - _2793); + int _2846 = int(_2845); + float _2848 = _2845 - float(_2846); + _2862 = dot(float3(_2848 * _2848, _2848, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_503[_2846], _503[_2846 + 1], _503[_2846 + 2])); + } + else + { + float _2807 = log(_2786); + float _2808 = _2807 / _1091; + float _2841; + if ((_2791 >= _2800) && (_2791 < _2808)) + { + float _2824 = (7.0 * (_2791 - _2800)) / (_2808 - _2800); + int _2825 = int(_2824); + float _2827 = _2824 - float(_2825); + _2841 = dot(float3(_2827 * _2827, _2827, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_504[_2825], _504[_2825 + 1], _504[_2825 + 2])); + } + else + { + _2841 = (_2791 * 0.0599999986588954925537109375) + ((log(1000.0) / _1091) - ((0.0599999986588954925537109375 * _2807) / _1091)); + } + _2862 = _2841; + } + _2870 = _2862; + } + float3 _2872 = _523; + _2872.x = pow(10.0, _2870); + float _2873 = _2583.y; + float _2877 = log((_2873 <= 0.0) ? 9.9999997473787516355514526367188e-05 : _2873) / _1091; + float _2954; + if (_2877 <= _2793) + { + _2954 = (_2877 * 3.0) + ((log(9.9999997473787516355514526367188e-05) / _1091) - ((3.0 * _2792) / _1091)); + } + else + { + float _2884 = log(_2714) / _1091; + float _2946; + if ((_2877 > _2793) && (_2877 < _2884)) + { + float _2929 = (7.0 * (_2877 - _2793)) / (_2884 - _2793); + int _2930 = int(_2929); + float _2932 = _2929 - float(_2930); + _2946 = dot(float3(_2932 * _2932, _2932, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_503[_2930], _503[_2930 + 1], _503[_2930 + 2])); + } + else + { + float _2891 = log(_2786); + float _2892 = _2891 / _1091; + float _2925; + if ((_2877 >= _2884) && (_2877 < _2892)) + { + float _2908 = (7.0 * (_2877 - _2884)) / (_2892 - _2884); + int _2909 = int(_2908); + float _2911 = _2908 - float(_2909); + _2925 = dot(float3(_2911 * _2911, _2911, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_504[_2909], _504[_2909 + 1], _504[_2909 + 2])); + } + else + { + _2925 = (_2877 * 0.0599999986588954925537109375) + ((log(1000.0) / _1091) - ((0.0599999986588954925537109375 * _2891) / _1091)); + } + _2946 = _2925; + } + _2954 = _2946; + } + float3 _2956 = _2872; + _2956.y = pow(10.0, _2954); + float _2957 = _2583.z; + float _2961 = log((_2957 <= 0.0) ? 9.9999997473787516355514526367188e-05 : _2957) / _1091; + float _3038; + if (_2961 <= _2793) + { + _3038 = (_2961 * 3.0) + ((log(9.9999997473787516355514526367188e-05) / _1091) - ((3.0 * _2792) / _1091)); + } + else + { + float _2968 = log(_2714) / _1091; + float _3030; + if ((_2961 > _2793) && (_2961 < _2968)) + { + float _3013 = (7.0 * (_2961 - _2793)) / (_2968 - _2793); + int _3014 = int(_3013); + float _3016 = _3013 - float(_3014); + _3030 = dot(float3(_3016 * _3016, _3016, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_503[_3014], _503[_3014 + 1], _503[_3014 + 2])); + } + else + { + float _2975 = log(_2786); + float _2976 = _2975 / _1091; + float _3009; + if ((_2961 >= _2968) && (_2961 < _2976)) + { + float _2992 = (7.0 * (_2961 - _2968)) / (_2976 - _2968); + int _2993 = int(_2992); + float _2995 = _2992 - float(_2993); + _3009 = dot(float3(_2995 * _2995, _2995, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_504[_2993], _504[_2993 + 1], _504[_2993 + 2])); + } + else + { + _3009 = (_2961 * 0.0599999986588954925537109375) + ((log(1000.0) / _1091) - ((0.0599999986588954925537109375 * _2975) / _1091)); + } + _3030 = _3009; + } + _3038 = _3030; + } + float3 _3040 = _2956; + _3040.z = pow(10.0, _3038); + float3 _3044 = pow(((_3040 - float3(3.5073844628641381859779357910156e-05)) * _602) * float3(9.9999997473787516355514526367188e-05), float3(0.1593017578125)); + _3052 = pow((float3(0.8359375) + (float3(18.8515625) * _3044)) * (float3(1.0) / (float3(1.0) + (float3(18.6875) * _3044))), float3(78.84375)); + } + else + { + float3 _2201; + if ((_Globals.OutputDevice == 4u) || (_Globals.OutputDevice == 6u)) + { + float3 _1369 = (_932 * float3(1.5)) * (_572 * float3x3(float3(1.04981100559234619140625, 0.0, -9.74845024757087230682373046875e-05), float3(-0.49590301513671875, 1.37331306934356689453125, 0.09824003279209136962890625), float3(0.0, 0.0, 0.991252005100250244140625))); + float _1370 = _1369.x; + float _1371 = _1369.y; + float _1373 = _1369.z; + float _1376 = fast::max(fast::max(_1370, _1371), _1373); + float _1381 = (fast::max(_1376, 1.0000000133514319600180897396058e-10) - fast::max(fast::min(fast::min(_1370, _1371), _1373), 1.0000000133514319600180897396058e-10)) / fast::max(_1376, 0.00999999977648258209228515625); + float _1394 = ((_1373 + _1371) + _1370) + (1.75 * sqrt(((_1373 * (_1373 - _1371)) + (_1371 * (_1371 - _1370))) + (_1370 * (_1370 - _1373)))); + float _1395 = _1394 * 0.3333333432674407958984375; + float _1396 = _1381 - 0.4000000059604644775390625; + float _1401 = fast::max(1.0 - abs(_1396 * 2.5), 0.0); + float _1409 = (1.0 + (float(int(sign(_1396 * 5.0))) * (1.0 - (_1401 * _1401)))) * 0.02500000037252902984619140625; + float _1422; + if (_1395 <= 0.053333334624767303466796875) + { + _1422 = _1409; + } + else + { + float _1421; + if (_1395 >= 0.1599999964237213134765625) + { + _1421 = 0.0; + } + else + { + _1421 = _1409 * ((0.23999999463558197021484375 / _1394) - 0.5); + } + _1422 = _1421; + } + float3 _1425 = _1369 * float3(1.0 + _1422); + float _1426 = _1425.x; + float _1427 = _1425.y; + float _1429 = _1425.z; + float _1443; + if ((_1426 == _1427) && (_1427 == _1429)) + { + _1443 = 0.0; + } + else + { + _1443 = 57.2957763671875 * atan2(sqrt(3.0) * (_1427 - _1429), ((2.0 * _1426) - _1427) - _1429); + } + float _1448; + if (_1443 < 0.0) + { + _1448 = _1443 + 360.0; + } + else + { + _1448 = _1443; + } + float _1449 = fast::clamp(_1448, 0.0, 360.0); + float _1454; + if (_1449 > 180.0) + { + _1454 = _1449 - 360.0; + } + else + { + _1454 = _1449; + } + float _1504; + if ((_1454 > (-67.5)) && (_1454 < 67.5)) + { + float _1461 = (_1454 - (-67.5)) * 0.0296296291053295135498046875; + int _1462 = int(_1461); + float _1464 = _1461 - float(_1462); + float _1465 = _1464 * _1464; + float _1466 = _1465 * _1464; + float _1503; + if (_1462 == 3) + { + _1503 = (((_1466 * (-0.16666667163372039794921875)) + (_1465 * 0.5)) + (_1464 * (-0.5))) + 0.16666667163372039794921875; + } + else + { + float _1496; + if (_1462 == 2) + { + _1496 = ((_1466 * 0.5) + (_1465 * (-1.0))) + 0.666666686534881591796875; + } + else + { + float _1491; + if (_1462 == 1) + { + _1491 = (((_1466 * (-0.5)) + (_1465 * 0.5)) + (_1464 * 0.5)) + 0.16666667163372039794921875; + } + else + { + float _1484; + if (_1462 == 0) + { + _1484 = _1466 * 0.16666667163372039794921875; + } + else + { + _1484 = 0.0; + } + _1491 = _1484; + } + _1496 = _1491; + } + _1503 = _1496; + } + _1504 = _1503; + } + else + { + _1504 = 0.0; + } + float3 _1511 = _1425; + _1511.x = _1426 + ((((_1504 * 1.5) * _1381) * (0.02999999932944774627685546875 - _1426)) * 0.180000007152557373046875); + float3 _1514 = fast::clamp(fast::clamp(_1511, float3(0.0), float3(65535.0)) * float3x3(float3(1.45143926143646240234375, -0.236510753631591796875, -0.214928567409515380859375), float3(-0.07655377686023712158203125, 1.1762297153472900390625, -0.0996759235858917236328125), float3(0.0083161480724811553955078125, -0.0060324496589601039886474609375, 0.99771630764007568359375)), float3(0.0), float3(65535.0)); + float3 _1517 = mix(float3(dot(_1514, float3(0.272228717803955078125, 0.674081742763519287109375, 0.053689517080783843994140625))), _1514, float3(0.959999978542327880859375)); + float _1518 = _1517.x; + float _1522 = 0.17999999225139617919921875 * exp2(18.0); + float _1524 = exp2(-14.0); + float _1527 = log((_1518 <= 0.0) ? _1524 : _1518) / _1091; + float _1529 = log(0.17999999225139617919921875 * exp2(-15.0)) / _1091; + float _1596; + if (_1527 <= _1529) + { + _1596 = log(9.9999997473787516355514526367188e-05) / _1091; + } + else + { + float _1536 = log(0.180000007152557373046875) / _1091; + float _1593; + if ((_1527 > _1529) && (_1527 < _1536)) + { + float _1576 = (3.0 * (_1527 - _1529)) / (_1536 - _1529); + int _1577 = int(_1576); + float _1579 = _1576 - float(_1577); + _1593 = dot(float3(_1579 * _1579, _1579, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_499[_1577], _499[_1577 + 1], _499[_1577 + 2])); + } + else + { + float _1544 = log(_1522) / _1091; + float _1572; + if ((_1527 >= _1536) && (_1527 < _1544)) + { + float _1555 = (3.0 * (_1527 - _1536)) / (_1544 - _1536); + int _1556 = int(_1555); + float _1558 = _1555 - float(_1556); + _1572 = dot(float3(_1558 * _1558, _1558, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_500[_1556], _500[_1556 + 1], _500[_1556 + 2])); + } + else + { + _1572 = log(10000.0) / _1091; + } + _1593 = _1572; + } + _1596 = _1593; + } + float3 _1598 = _523; + _1598.x = pow(10.0, _1596); + float _1599 = _1517.y; + float _1603 = log((_1599 <= 0.0) ? _1524 : _1599) / _1091; + float _1670; + if (_1603 <= _1529) + { + _1670 = log(9.9999997473787516355514526367188e-05) / _1091; + } + else + { + float _1610 = log(0.180000007152557373046875) / _1091; + float _1667; + if ((_1603 > _1529) && (_1603 < _1610)) + { + float _1650 = (3.0 * (_1603 - _1529)) / (_1610 - _1529); + int _1651 = int(_1650); + float _1653 = _1650 - float(_1651); + _1667 = dot(float3(_1653 * _1653, _1653, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_499[_1651], _499[_1651 + 1], _499[_1651 + 2])); + } + else + { + float _1618 = log(_1522) / _1091; + float _1646; + if ((_1603 >= _1610) && (_1603 < _1618)) + { + float _1629 = (3.0 * (_1603 - _1610)) / (_1618 - _1610); + int _1630 = int(_1629); + float _1632 = _1629 - float(_1630); + _1646 = dot(float3(_1632 * _1632, _1632, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_500[_1630], _500[_1630 + 1], _500[_1630 + 2])); + } + else + { + _1646 = log(10000.0) / _1091; + } + _1667 = _1646; + } + _1670 = _1667; + } + float3 _1672 = _1598; + _1672.y = pow(10.0, _1670); + float _1673 = _1517.z; + float _1677 = log((_1673 <= 0.0) ? _1524 : _1673) / _1091; + float _1744; + if (_1677 <= _1529) + { + _1744 = log(9.9999997473787516355514526367188e-05) / _1091; + } + else + { + float _1684 = log(0.180000007152557373046875) / _1091; + float _1741; + if ((_1677 > _1529) && (_1677 < _1684)) + { + float _1724 = (3.0 * (_1677 - _1529)) / (_1684 - _1529); + int _1725 = int(_1724); + float _1727 = _1724 - float(_1725); + _1741 = dot(float3(_1727 * _1727, _1727, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_499[_1725], _499[_1725 + 1], _499[_1725 + 2])); + } + else + { + float _1692 = log(_1522) / _1091; + float _1720; + if ((_1677 >= _1684) && (_1677 < _1692)) + { + float _1703 = (3.0 * (_1677 - _1684)) / (_1692 - _1684); + int _1704 = int(_1703); + float _1706 = _1703 - float(_1704); + _1720 = dot(float3(_1706 * _1706, _1706, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_500[_1704], _500[_1704 + 1], _500[_1704 + 2])); + } + else + { + _1720 = log(10000.0) / _1091; + } + _1741 = _1720; + } + _1744 = _1741; + } + float3 _1746 = _1672; + _1746.z = pow(10.0, _1744); + float3 _1748 = (_1746 * float3x3(float3(0.695452213287353515625, 0.140678703784942626953125, 0.16386906802654266357421875), float3(0.0447945632040500640869140625, 0.859671115875244140625, 0.095534317195415496826171875), float3(-0.0055258828215301036834716796875, 0.0040252101607620716094970703125, 1.00150072574615478515625))) * float3x3(float3(1.45143926143646240234375, -0.236510753631591796875, -0.214928567409515380859375), float3(-0.07655377686023712158203125, 1.1762297153472900390625, -0.0996759235858917236328125), float3(0.0083161480724811553955078125, -0.0060324496589601039886474609375, 0.99771630764007568359375)); + float _1750 = 0.17999999225139617919921875 * pow(2.0, -12.0); + float _1754 = log((_1750 <= 0.0) ? _1524 : _1750) / _1091; + float _1821; + if (_1754 <= _1529) + { + _1821 = log(9.9999997473787516355514526367188e-05) / _1091; + } + else + { + float _1761 = log(0.180000007152557373046875) / _1091; + float _1818; + if ((_1754 > _1529) && (_1754 < _1761)) + { + float _1801 = (3.0 * (_1754 - _1529)) / (_1761 - _1529); + int _1802 = int(_1801); + float _1804 = _1801 - float(_1802); + _1818 = dot(float3(_1804 * _1804, _1804, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_499[_1802], _499[_1802 + 1], _499[_1802 + 2])); + } + else + { + float _1769 = log(_1522) / _1091; + float _1797; + if ((_1754 >= _1761) && (_1754 < _1769)) + { + float _1780 = (3.0 * (_1754 - _1761)) / (_1769 - _1761); + int _1781 = int(_1780); + float _1783 = _1780 - float(_1781); + _1797 = dot(float3(_1783 * _1783, _1783, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_500[_1781], _500[_1781 + 1], _500[_1781 + 2])); + } + else + { + _1797 = log(10000.0) / _1091; + } + _1818 = _1797; + } + _1821 = _1818; + } + float _1824 = log(0.180000007152557373046875) / _1091; + float _1878; + if (_1824 <= _1529) + { + _1878 = log(9.9999997473787516355514526367188e-05) / _1091; + } + else + { + float _1875; + if ((_1824 > _1529) && (_1824 < _1824)) + { + _1875 = (float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_499[3], _499[4], _499[5])).z; + } + else + { + float _1837 = log(_1522) / _1091; + float _1865; + if ((_1824 >= _1824) && (_1824 < _1837)) + { + float _1848 = (3.0 * (_1824 - _1824)) / (_1837 - _1824); + int _1849 = int(_1848); + float _1851 = _1848 - float(_1849); + _1865 = dot(float3(_1851 * _1851, _1851, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_500[_1849], _500[_1849 + 1], _500[_1849 + 2])); + } + else + { + _1865 = log(10000.0) / _1091; + } + _1875 = _1865; + } + _1878 = _1875; + } + float _1879 = pow(10.0, _1878); + float _1881 = 0.17999999225139617919921875 * pow(2.0, 11.0); + float _1885 = log((_1881 <= 0.0) ? _1524 : _1881) / _1091; + float _1950; + if (_1885 <= _1529) + { + _1950 = log(9.9999997473787516355514526367188e-05) / _1091; + } + else + { + float _1947; + if ((_1885 > _1529) && (_1885 < _1824)) + { + float _1930 = (3.0 * (_1885 - _1529)) / (_1824 - _1529); + int _1931 = int(_1930); + float _1933 = _1930 - float(_1931); + _1947 = dot(float3(_1933 * _1933, _1933, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_499[_1931], _499[_1931 + 1], _499[_1931 + 2])); + } + else + { + float _1898 = log(_1522) / _1091; + float _1926; + if ((_1885 >= _1824) && (_1885 < _1898)) + { + float _1909 = (3.0 * (_1885 - _1824)) / (_1898 - _1824); + int _1910 = int(_1909); + float _1912 = _1909 - float(_1910); + _1926 = dot(float3(_1912 * _1912, _1912, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_500[_1910], _500[_1910 + 1], _500[_1910 + 2])); + } + else + { + _1926 = log(10000.0) / _1091; + } + _1947 = _1926; + } + _1950 = _1947; + } + float _1951 = pow(10.0, _1950); + float _1952 = _1748.x; + float _1956 = log((_1952 <= 0.0) ? 9.9999997473787516355514526367188e-05 : _1952) / _1091; + float _1958 = log(pow(10.0, _1821)) / _1091; + float _2030; + if (_1956 <= _1958) + { + _2030 = log(0.004999999888241291046142578125) / _1091; + } + else + { + float _1965 = log(_1879) / _1091; + float _2027; + if ((_1956 > _1958) && (_1956 < _1965)) + { + float _2010 = (7.0 * (_1956 - _1958)) / (_1965 - _1958); + int _2011 = int(_2010); + float _2013 = _2010 - float(_2011); + _2027 = dot(float3(_2013 * _2013, _2013, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_506[_2011], _506[_2011 + 1], _506[_2011 + 2])); + } + else + { + float _1972 = log(_1951); + float _1973 = _1972 / _1091; + float _2006; + if ((_1956 >= _1965) && (_1956 < _1973)) + { + float _1989 = (7.0 * (_1956 - _1965)) / (_1973 - _1965); + int _1990 = int(_1989); + float _1992 = _1989 - float(_1990); + _2006 = dot(float3(_1992 * _1992, _1992, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_507[_1990], _507[_1990 + 1], _507[_1990 + 2])); + } + else + { + _2006 = (_1956 * 0.119999997317790985107421875) + ((log(2000.0) / _1091) - ((0.119999997317790985107421875 * _1972) / _1091)); + } + _2027 = _2006; + } + _2030 = _2027; + } + float3 _2032 = _523; + _2032.x = pow(10.0, _2030); + float _2033 = _1748.y; + float _2037 = log((_2033 <= 0.0) ? 9.9999997473787516355514526367188e-05 : _2033) / _1091; + float _2109; + if (_2037 <= _1958) + { + _2109 = log(0.004999999888241291046142578125) / _1091; + } + else + { + float _2044 = log(_1879) / _1091; + float _2106; + if ((_2037 > _1958) && (_2037 < _2044)) + { + float _2089 = (7.0 * (_2037 - _1958)) / (_2044 - _1958); + int _2090 = int(_2089); + float _2092 = _2089 - float(_2090); + _2106 = dot(float3(_2092 * _2092, _2092, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_506[_2090], _506[_2090 + 1], _506[_2090 + 2])); + } + else + { + float _2051 = log(_1951); + float _2052 = _2051 / _1091; + float _2085; + if ((_2037 >= _2044) && (_2037 < _2052)) + { + float _2068 = (7.0 * (_2037 - _2044)) / (_2052 - _2044); + int _2069 = int(_2068); + float _2071 = _2068 - float(_2069); + _2085 = dot(float3(_2071 * _2071, _2071, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_507[_2069], _507[_2069 + 1], _507[_2069 + 2])); + } + else + { + _2085 = (_2037 * 0.119999997317790985107421875) + ((log(2000.0) / _1091) - ((0.119999997317790985107421875 * _2051) / _1091)); + } + _2106 = _2085; + } + _2109 = _2106; + } + float3 _2111 = _2032; + _2111.y = pow(10.0, _2109); + float _2112 = _1748.z; + float _2116 = log((_2112 <= 0.0) ? 9.9999997473787516355514526367188e-05 : _2112) / _1091; + float _2188; + if (_2116 <= _1958) + { + _2188 = log(0.004999999888241291046142578125) / _1091; + } + else + { + float _2123 = log(_1879) / _1091; + float _2185; + if ((_2116 > _1958) && (_2116 < _2123)) + { + float _2168 = (7.0 * (_2116 - _1958)) / (_2123 - _1958); + int _2169 = int(_2168); + float _2171 = _2168 - float(_2169); + _2185 = dot(float3(_2171 * _2171, _2171, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_506[_2169], _506[_2169 + 1], _506[_2169 + 2])); + } + else + { + float _2130 = log(_1951); + float _2131 = _2130 / _1091; + float _2164; + if ((_2116 >= _2123) && (_2116 < _2131)) + { + float _2147 = (7.0 * (_2116 - _2123)) / (_2131 - _2123); + int _2148 = int(_2147); + float _2150 = _2147 - float(_2148); + _2164 = dot(float3(_2150 * _2150, _2150, 1.0), float3x3(float3(0.5, -1.0, 0.5), float3(-1.0, 1.0, 0.5), float3(0.5, 0.0, 0.0)) * float3(_507[_2148], _507[_2148 + 1], _507[_2148 + 2])); + } + else + { + _2164 = (_2116 * 0.119999997317790985107421875) + ((log(2000.0) / _1091) - ((0.119999997317790985107421875 * _2130) / _1091)); + } + _2185 = _2164; + } + _2188 = _2185; + } + float3 _2190 = _2111; + _2190.z = pow(10.0, _2188); + float3 _2193 = pow((_2190 * _602) * float3(9.9999997473787516355514526367188e-05), float3(0.1593017578125)); + _2201 = pow((float3(0.8359375) + (float3(18.8515625) * _2193)) * (float3(1.0) / (float3(1.0) + (float3(18.6875) * _2193))), float3(78.84375)); + } + else + { + float3 _1366; + if (_Globals.OutputDevice == 7u) + { + float3 _1358 = pow(((_932 * _573) * _602) * float3(9.9999997473787516355514526367188e-05), float3(0.1593017578125)); + _1366 = pow((float3(0.8359375) + (float3(18.8515625) * _1358)) * (float3(1.0) / (float3(1.0) + (float3(18.6875) * _1358))), float3(78.84375)); + } + else + { + _1366 = pow((_1324 * _573) * _602, float3(_Globals.InverseGamma.z)); + } + _2201 = _1366; + } + _3052 = _2201; + } + _3062 = _3052; + } + _3103 = _3062; + } + float3 _3104 = _3103 * float3(0.95238101482391357421875); + float4 _3106 = float4(_3104.x, _3104.y, _3104.z, float4(0.0).w); + _3106.w = 0.0; + out.out_var_SV_Target0 = _3106; + return out; +} + diff --git a/third_party/spirv-cross/reference/shaders-ue4/asm/frag/sample-mask-not-array.asm.frag b/third_party/spirv-cross/reference/shaders-ue4/asm/frag/sample-mask-not-array.asm.frag new file mode 100644 index 0000000000..dd54893a24 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-ue4/asm/frag/sample-mask-not-array.asm.frag @@ -0,0 +1,503 @@ +#include +#include + +using namespace metal; + +struct type_View +{ + float4x4 View_TranslatedWorldToClip; + float4x4 View_WorldToClip; + float4x4 View_TranslatedWorldToView; + float4x4 View_ViewToTranslatedWorld; + float4x4 View_TranslatedWorldToCameraView; + float4x4 View_CameraViewToTranslatedWorld; + float4x4 View_ViewToClip; + float4x4 View_ViewToClipNoAA; + float4x4 View_ClipToView; + float4x4 View_ClipToTranslatedWorld; + float4x4 View_SVPositionToTranslatedWorld; + float4x4 View_ScreenToWorld; + float4x4 View_ScreenToTranslatedWorld; + packed_float3 View_ViewForward; + float PrePadding_View_844; + packed_float3 View_ViewUp; + float PrePadding_View_860; + packed_float3 View_ViewRight; + float PrePadding_View_876; + packed_float3 View_HMDViewNoRollUp; + float PrePadding_View_892; + packed_float3 View_HMDViewNoRollRight; + float PrePadding_View_908; + float4 View_InvDeviceZToWorldZTransform; + float4 View_ScreenPositionScaleBias; + packed_float3 View_WorldCameraOrigin; + float PrePadding_View_956; + packed_float3 View_TranslatedWorldCameraOrigin; + float PrePadding_View_972; + packed_float3 View_WorldViewOrigin; + float PrePadding_View_988; + packed_float3 View_PreViewTranslation; + float PrePadding_View_1004; + float4x4 View_PrevProjection; + float4x4 View_PrevViewProj; + float4x4 View_PrevViewRotationProj; + float4x4 View_PrevViewToClip; + float4x4 View_PrevClipToView; + float4x4 View_PrevTranslatedWorldToClip; + float4x4 View_PrevTranslatedWorldToView; + float4x4 View_PrevViewToTranslatedWorld; + float4x4 View_PrevTranslatedWorldToCameraView; + float4x4 View_PrevCameraViewToTranslatedWorld; + packed_float3 View_PrevWorldCameraOrigin; + float PrePadding_View_1660; + packed_float3 View_PrevWorldViewOrigin; + float PrePadding_View_1676; + packed_float3 View_PrevPreViewTranslation; + float PrePadding_View_1692; + float4x4 View_PrevInvViewProj; + float4x4 View_PrevScreenToTranslatedWorld; + float4x4 View_ClipToPrevClip; + float4 View_TemporalAAJitter; + float4 View_GlobalClippingPlane; + float2 View_FieldOfViewWideAngles; + float2 View_PrevFieldOfViewWideAngles; + float4 View_ViewRectMin; + float4 View_ViewSizeAndInvSize; + float4 View_BufferSizeAndInvSize; + float4 View_BufferBilinearUVMinMax; + int View_NumSceneColorMSAASamples; + float View_PreExposure; + float View_OneOverPreExposure; + float PrePadding_View_2012; + float4 View_DiffuseOverrideParameter; + float4 View_SpecularOverrideParameter; + float4 View_NormalOverrideParameter; + float2 View_RoughnessOverrideParameter; + float View_PrevFrameGameTime; + float View_PrevFrameRealTime; + float View_OutOfBoundsMask; + float PrePadding_View_2084; + float PrePadding_View_2088; + float PrePadding_View_2092; + packed_float3 View_WorldCameraMovementSinceLastFrame; + float View_CullingSign; + float View_NearPlane; + float View_AdaptiveTessellationFactor; + float View_GameTime; + float View_RealTime; + float View_DeltaTime; + float View_MaterialTextureMipBias; + float View_MaterialTextureDerivativeMultiply; + uint View_Random; + uint View_FrameNumber; + uint View_StateFrameIndexMod8; + uint View_StateFrameIndex; + float View_CameraCut; + float View_UnlitViewmodeMask; + float PrePadding_View_2164; + float PrePadding_View_2168; + float PrePadding_View_2172; + float4 View_DirectionalLightColor; + packed_float3 View_DirectionalLightDirection; + float PrePadding_View_2204; + float4 View_TranslucencyLightingVolumeMin[2]; + float4 View_TranslucencyLightingVolumeInvSize[2]; + float4 View_TemporalAAParams; + float4 View_CircleDOFParams; + float View_DepthOfFieldSensorWidth; + float View_DepthOfFieldFocalDistance; + float View_DepthOfFieldScale; + float View_DepthOfFieldFocalLength; + float View_DepthOfFieldFocalRegion; + float View_DepthOfFieldNearTransitionRegion; + float View_DepthOfFieldFarTransitionRegion; + float View_MotionBlurNormalizedToPixel; + float View_bSubsurfacePostprocessEnabled; + float View_GeneralPurposeTweak; + float View_DemosaicVposOffset; + float PrePadding_View_2348; + packed_float3 View_IndirectLightingColorScale; + float View_HDR32bppEncodingMode; + packed_float3 View_AtmosphericFogSunDirection; + float View_AtmosphericFogSunPower; + float View_AtmosphericFogPower; + float View_AtmosphericFogDensityScale; + float View_AtmosphericFogDensityOffset; + float View_AtmosphericFogGroundOffset; + float View_AtmosphericFogDistanceScale; + float View_AtmosphericFogAltitudeScale; + float View_AtmosphericFogHeightScaleRayleigh; + float View_AtmosphericFogStartDistance; + float View_AtmosphericFogDistanceOffset; + float View_AtmosphericFogSunDiscScale; + uint View_AtmosphericFogRenderMask; + uint View_AtmosphericFogInscatterAltitudeSampleNum; + float4 View_AtmosphericFogSunColor; + packed_float3 View_NormalCurvatureToRoughnessScaleBias; + float View_RenderingReflectionCaptureMask; + float4 View_AmbientCubemapTint; + float View_AmbientCubemapIntensity; + float View_SkyLightParameters; + float PrePadding_View_2488; + float PrePadding_View_2492; + float4 View_SkyLightColor; + float4 View_SkyIrradianceEnvironmentMap[7]; + float View_MobilePreviewMode; + float View_HMDEyePaddingOffset; + float View_ReflectionCubemapMaxMip; + float View_ShowDecalsMask; + uint View_DistanceFieldAOSpecularOcclusionMode; + float View_IndirectCapsuleSelfShadowingIntensity; + float PrePadding_View_2648; + float PrePadding_View_2652; + packed_float3 View_ReflectionEnvironmentRoughnessMixingScaleBiasAndLargestWeight; + int View_StereoPassIndex; + float4 View_GlobalVolumeCenterAndExtent[4]; + float4 View_GlobalVolumeWorldToUVAddAndMul[4]; + float View_GlobalVolumeDimension; + float View_GlobalVolumeTexelSize; + float View_MaxGlobalDistance; + float View_bCheckerboardSubsurfaceProfileRendering; + packed_float3 View_VolumetricFogInvGridSize; + float PrePadding_View_2828; + packed_float3 View_VolumetricFogGridZParams; + float PrePadding_View_2844; + float2 View_VolumetricFogSVPosToVolumeUV; + float View_VolumetricFogMaxDistance; + float PrePadding_View_2860; + packed_float3 View_VolumetricLightmapWorldToUVScale; + float PrePadding_View_2876; + packed_float3 View_VolumetricLightmapWorldToUVAdd; + float PrePadding_View_2892; + packed_float3 View_VolumetricLightmapIndirectionTextureSize; + float View_VolumetricLightmapBrickSize; + packed_float3 View_VolumetricLightmapBrickTexelSize; + float View_StereoIPD; + float View_IndirectLightingCacheShowFlag; + float View_EyeToPixelSpreadAngle; +}; + +struct type_StructuredBuffer_v4float +{ + float4 _m0[1]; +}; + +struct type_TranslucentBasePass +{ + uint TranslucentBasePass_Shared_Forward_NumLocalLights; + uint TranslucentBasePass_Shared_Forward_NumReflectionCaptures; + uint TranslucentBasePass_Shared_Forward_HasDirectionalLight; + uint TranslucentBasePass_Shared_Forward_NumGridCells; + packed_int3 TranslucentBasePass_Shared_Forward_CulledGridSize; + uint TranslucentBasePass_Shared_Forward_MaxCulledLightsPerCell; + uint TranslucentBasePass_Shared_Forward_LightGridPixelSizeShift; + uint PrePadding_TranslucentBasePass_Shared_Forward_36; + uint PrePadding_TranslucentBasePass_Shared_Forward_40; + uint PrePadding_TranslucentBasePass_Shared_Forward_44; + packed_float3 TranslucentBasePass_Shared_Forward_LightGridZParams; + float PrePadding_TranslucentBasePass_Shared_Forward_60; + packed_float3 TranslucentBasePass_Shared_Forward_DirectionalLightDirection; + float PrePadding_TranslucentBasePass_Shared_Forward_76; + packed_float3 TranslucentBasePass_Shared_Forward_DirectionalLightColor; + float TranslucentBasePass_Shared_Forward_DirectionalLightVolumetricScatteringIntensity; + uint TranslucentBasePass_Shared_Forward_DirectionalLightShadowMapChannelMask; + uint PrePadding_TranslucentBasePass_Shared_Forward_100; + float2 TranslucentBasePass_Shared_Forward_DirectionalLightDistanceFadeMAD; + uint TranslucentBasePass_Shared_Forward_NumDirectionalLightCascades; + uint PrePadding_TranslucentBasePass_Shared_Forward_116; + uint PrePadding_TranslucentBasePass_Shared_Forward_120; + uint PrePadding_TranslucentBasePass_Shared_Forward_124; + float4 TranslucentBasePass_Shared_Forward_CascadeEndDepths; + float4x4 TranslucentBasePass_Shared_Forward_DirectionalLightWorldToShadowMatrix[4]; + float4 TranslucentBasePass_Shared_Forward_DirectionalLightShadowmapMinMax[4]; + float4 TranslucentBasePass_Shared_Forward_DirectionalLightShadowmapAtlasBufferSize; + float TranslucentBasePass_Shared_Forward_DirectionalLightDepthBias; + uint TranslucentBasePass_Shared_Forward_DirectionalLightUseStaticShadowing; + uint PrePadding_TranslucentBasePass_Shared_Forward_488; + uint PrePadding_TranslucentBasePass_Shared_Forward_492; + float4 TranslucentBasePass_Shared_Forward_DirectionalLightStaticShadowBufferSize; + float4x4 TranslucentBasePass_Shared_Forward_DirectionalLightWorldToStaticShadow; + float PrePadding_TranslucentBasePass_Shared_ForwardISR_576; + float PrePadding_TranslucentBasePass_Shared_ForwardISR_580; + float PrePadding_TranslucentBasePass_Shared_ForwardISR_584; + float PrePadding_TranslucentBasePass_Shared_ForwardISR_588; + float PrePadding_TranslucentBasePass_Shared_ForwardISR_592; + float PrePadding_TranslucentBasePass_Shared_ForwardISR_596; + float PrePadding_TranslucentBasePass_Shared_ForwardISR_600; + float PrePadding_TranslucentBasePass_Shared_ForwardISR_604; + float PrePadding_TranslucentBasePass_Shared_ForwardISR_608; + float PrePadding_TranslucentBasePass_Shared_ForwardISR_612; + float PrePadding_TranslucentBasePass_Shared_ForwardISR_616; + float PrePadding_TranslucentBasePass_Shared_ForwardISR_620; + float PrePadding_TranslucentBasePass_Shared_ForwardISR_624; + float PrePadding_TranslucentBasePass_Shared_ForwardISR_628; + float PrePadding_TranslucentBasePass_Shared_ForwardISR_632; + float PrePadding_TranslucentBasePass_Shared_ForwardISR_636; + uint TranslucentBasePass_Shared_ForwardISR_NumLocalLights; + uint TranslucentBasePass_Shared_ForwardISR_NumReflectionCaptures; + uint TranslucentBasePass_Shared_ForwardISR_HasDirectionalLight; + uint TranslucentBasePass_Shared_ForwardISR_NumGridCells; + packed_int3 TranslucentBasePass_Shared_ForwardISR_CulledGridSize; + uint TranslucentBasePass_Shared_ForwardISR_MaxCulledLightsPerCell; + uint TranslucentBasePass_Shared_ForwardISR_LightGridPixelSizeShift; + uint PrePadding_TranslucentBasePass_Shared_ForwardISR_676; + uint PrePadding_TranslucentBasePass_Shared_ForwardISR_680; + uint PrePadding_TranslucentBasePass_Shared_ForwardISR_684; + packed_float3 TranslucentBasePass_Shared_ForwardISR_LightGridZParams; + float PrePadding_TranslucentBasePass_Shared_ForwardISR_700; + packed_float3 TranslucentBasePass_Shared_ForwardISR_DirectionalLightDirection; + float PrePadding_TranslucentBasePass_Shared_ForwardISR_716; + packed_float3 TranslucentBasePass_Shared_ForwardISR_DirectionalLightColor; + float TranslucentBasePass_Shared_ForwardISR_DirectionalLightVolumetricScatteringIntensity; + uint TranslucentBasePass_Shared_ForwardISR_DirectionalLightShadowMapChannelMask; + uint PrePadding_TranslucentBasePass_Shared_ForwardISR_740; + float2 TranslucentBasePass_Shared_ForwardISR_DirectionalLightDistanceFadeMAD; + uint TranslucentBasePass_Shared_ForwardISR_NumDirectionalLightCascades; + uint PrePadding_TranslucentBasePass_Shared_ForwardISR_756; + uint PrePadding_TranslucentBasePass_Shared_ForwardISR_760; + uint PrePadding_TranslucentBasePass_Shared_ForwardISR_764; + float4 TranslucentBasePass_Shared_ForwardISR_CascadeEndDepths; + float4x4 TranslucentBasePass_Shared_ForwardISR_DirectionalLightWorldToShadowMatrix[4]; + float4 TranslucentBasePass_Shared_ForwardISR_DirectionalLightShadowmapMinMax[4]; + float4 TranslucentBasePass_Shared_ForwardISR_DirectionalLightShadowmapAtlasBufferSize; + float TranslucentBasePass_Shared_ForwardISR_DirectionalLightDepthBias; + uint TranslucentBasePass_Shared_ForwardISR_DirectionalLightUseStaticShadowing; + uint PrePadding_TranslucentBasePass_Shared_ForwardISR_1128; + uint PrePadding_TranslucentBasePass_Shared_ForwardISR_1132; + float4 TranslucentBasePass_Shared_ForwardISR_DirectionalLightStaticShadowBufferSize; + float4x4 TranslucentBasePass_Shared_ForwardISR_DirectionalLightWorldToStaticShadow; + float PrePadding_TranslucentBasePass_Shared_Reflection_1216; + float PrePadding_TranslucentBasePass_Shared_Reflection_1220; + float PrePadding_TranslucentBasePass_Shared_Reflection_1224; + float PrePadding_TranslucentBasePass_Shared_Reflection_1228; + float PrePadding_TranslucentBasePass_Shared_Reflection_1232; + float PrePadding_TranslucentBasePass_Shared_Reflection_1236; + float PrePadding_TranslucentBasePass_Shared_Reflection_1240; + float PrePadding_TranslucentBasePass_Shared_Reflection_1244; + float PrePadding_TranslucentBasePass_Shared_Reflection_1248; + float PrePadding_TranslucentBasePass_Shared_Reflection_1252; + float PrePadding_TranslucentBasePass_Shared_Reflection_1256; + float PrePadding_TranslucentBasePass_Shared_Reflection_1260; + float PrePadding_TranslucentBasePass_Shared_Reflection_1264; + float PrePadding_TranslucentBasePass_Shared_Reflection_1268; + float PrePadding_TranslucentBasePass_Shared_Reflection_1272; + float PrePadding_TranslucentBasePass_Shared_Reflection_1276; + float4 TranslucentBasePass_Shared_Reflection_SkyLightParameters; + float TranslucentBasePass_Shared_Reflection_SkyLightCubemapBrightness; + float PrePadding_TranslucentBasePass_Shared_PlanarReflection_1300; + float PrePadding_TranslucentBasePass_Shared_PlanarReflection_1304; + float PrePadding_TranslucentBasePass_Shared_PlanarReflection_1308; + float PrePadding_TranslucentBasePass_Shared_PlanarReflection_1312; + float PrePadding_TranslucentBasePass_Shared_PlanarReflection_1316; + float PrePadding_TranslucentBasePass_Shared_PlanarReflection_1320; + float PrePadding_TranslucentBasePass_Shared_PlanarReflection_1324; + float PrePadding_TranslucentBasePass_Shared_PlanarReflection_1328; + float PrePadding_TranslucentBasePass_Shared_PlanarReflection_1332; + float PrePadding_TranslucentBasePass_Shared_PlanarReflection_1336; + float PrePadding_TranslucentBasePass_Shared_PlanarReflection_1340; + float PrePadding_TranslucentBasePass_Shared_PlanarReflection_1344; + float PrePadding_TranslucentBasePass_Shared_PlanarReflection_1348; + float PrePadding_TranslucentBasePass_Shared_PlanarReflection_1352; + float PrePadding_TranslucentBasePass_Shared_PlanarReflection_1356; + float4 TranslucentBasePass_Shared_PlanarReflection_ReflectionPlane; + float4 TranslucentBasePass_Shared_PlanarReflection_PlanarReflectionOrigin; + float4 TranslucentBasePass_Shared_PlanarReflection_PlanarReflectionXAxis; + float4 TranslucentBasePass_Shared_PlanarReflection_PlanarReflectionYAxis; + float3x4 TranslucentBasePass_Shared_PlanarReflection_InverseTransposeMirrorMatrix; + packed_float3 TranslucentBasePass_Shared_PlanarReflection_PlanarReflectionParameters; + float PrePadding_TranslucentBasePass_Shared_PlanarReflection_1484; + float2 TranslucentBasePass_Shared_PlanarReflection_PlanarReflectionParameters2; + float PrePadding_TranslucentBasePass_Shared_PlanarReflection_1496; + float PrePadding_TranslucentBasePass_Shared_PlanarReflection_1500; + float4x4 TranslucentBasePass_Shared_PlanarReflection_ProjectionWithExtraFOV[2]; + float4 TranslucentBasePass_Shared_PlanarReflection_PlanarReflectionScreenScaleBias[2]; + float2 TranslucentBasePass_Shared_PlanarReflection_PlanarReflectionScreenBound; + uint TranslucentBasePass_Shared_PlanarReflection_bIsStereo; + float PrePadding_TranslucentBasePass_Shared_Fog_1676; + float PrePadding_TranslucentBasePass_Shared_Fog_1680; + float PrePadding_TranslucentBasePass_Shared_Fog_1684; + float PrePadding_TranslucentBasePass_Shared_Fog_1688; + float PrePadding_TranslucentBasePass_Shared_Fog_1692; + float4 TranslucentBasePass_Shared_Fog_ExponentialFogParameters; + float4 TranslucentBasePass_Shared_Fog_ExponentialFogParameters2; + float4 TranslucentBasePass_Shared_Fog_ExponentialFogColorParameter; + float4 TranslucentBasePass_Shared_Fog_ExponentialFogParameters3; + float4 TranslucentBasePass_Shared_Fog_InscatteringLightDirection; + float4 TranslucentBasePass_Shared_Fog_DirectionalInscatteringColor; + float2 TranslucentBasePass_Shared_Fog_SinCosInscatteringColorCubemapRotation; + float PrePadding_TranslucentBasePass_Shared_Fog_1800; + float PrePadding_TranslucentBasePass_Shared_Fog_1804; + packed_float3 TranslucentBasePass_Shared_Fog_FogInscatteringTextureParameters; + float TranslucentBasePass_Shared_Fog_ApplyVolumetricFog; + float PrePadding_TranslucentBasePass_1824; + float PrePadding_TranslucentBasePass_1828; + float PrePadding_TranslucentBasePass_1832; + float PrePadding_TranslucentBasePass_1836; + float PrePadding_TranslucentBasePass_1840; + float PrePadding_TranslucentBasePass_1844; + float PrePadding_TranslucentBasePass_1848; + float PrePadding_TranslucentBasePass_1852; + float PrePadding_TranslucentBasePass_1856; + float PrePadding_TranslucentBasePass_1860; + float PrePadding_TranslucentBasePass_1864; + float PrePadding_TranslucentBasePass_1868; + float PrePadding_TranslucentBasePass_1872; + float PrePadding_TranslucentBasePass_1876; + float PrePadding_TranslucentBasePass_1880; + float PrePadding_TranslucentBasePass_1884; + float PrePadding_TranslucentBasePass_1888; + float PrePadding_TranslucentBasePass_1892; + float PrePadding_TranslucentBasePass_1896; + float PrePadding_TranslucentBasePass_1900; + float PrePadding_TranslucentBasePass_1904; + float PrePadding_TranslucentBasePass_1908; + float PrePadding_TranslucentBasePass_1912; + float PrePadding_TranslucentBasePass_1916; + float PrePadding_TranslucentBasePass_1920; + float PrePadding_TranslucentBasePass_1924; + float PrePadding_TranslucentBasePass_1928; + float PrePadding_TranslucentBasePass_1932; + float PrePadding_TranslucentBasePass_1936; + float PrePadding_TranslucentBasePass_1940; + float PrePadding_TranslucentBasePass_1944; + float PrePadding_TranslucentBasePass_1948; + float PrePadding_TranslucentBasePass_1952; + float PrePadding_TranslucentBasePass_1956; + float PrePadding_TranslucentBasePass_1960; + float PrePadding_TranslucentBasePass_1964; + float PrePadding_TranslucentBasePass_1968; + float PrePadding_TranslucentBasePass_1972; + float PrePadding_TranslucentBasePass_1976; + float PrePadding_TranslucentBasePass_1980; + float PrePadding_TranslucentBasePass_1984; + float PrePadding_TranslucentBasePass_1988; + float PrePadding_TranslucentBasePass_1992; + float PrePadding_TranslucentBasePass_1996; + float PrePadding_TranslucentBasePass_2000; + float PrePadding_TranslucentBasePass_2004; + float PrePadding_TranslucentBasePass_2008; + float PrePadding_TranslucentBasePass_2012; + float PrePadding_TranslucentBasePass_2016; + float PrePadding_TranslucentBasePass_2020; + float PrePadding_TranslucentBasePass_2024; + float PrePadding_TranslucentBasePass_2028; + float PrePadding_TranslucentBasePass_2032; + float PrePadding_TranslucentBasePass_2036; + float PrePadding_TranslucentBasePass_2040; + float PrePadding_TranslucentBasePass_2044; + float PrePadding_TranslucentBasePass_2048; + float PrePadding_TranslucentBasePass_2052; + float PrePadding_TranslucentBasePass_2056; + float PrePadding_TranslucentBasePass_2060; + float PrePadding_TranslucentBasePass_2064; + float PrePadding_TranslucentBasePass_2068; + float PrePadding_TranslucentBasePass_2072; + float PrePadding_TranslucentBasePass_2076; + float PrePadding_TranslucentBasePass_2080; + float PrePadding_TranslucentBasePass_2084; + float PrePadding_TranslucentBasePass_2088; + float PrePadding_TranslucentBasePass_2092; + float PrePadding_TranslucentBasePass_2096; + float PrePadding_TranslucentBasePass_2100; + float PrePadding_TranslucentBasePass_2104; + float PrePadding_TranslucentBasePass_2108; + float PrePadding_TranslucentBasePass_2112; + float PrePadding_TranslucentBasePass_2116; + float PrePadding_TranslucentBasePass_2120; + float PrePadding_TranslucentBasePass_2124; + float PrePadding_TranslucentBasePass_2128; + float PrePadding_TranslucentBasePass_2132; + float PrePadding_TranslucentBasePass_2136; + float PrePadding_TranslucentBasePass_2140; + float4 TranslucentBasePass_HZBUvFactorAndInvFactor; + float4 TranslucentBasePass_PrevScreenPositionScaleBias; + float TranslucentBasePass_PrevSceneColorPreExposureInv; +}; + +struct type_Material +{ + float4 Material_VectorExpressions[2]; + float4 Material_ScalarExpressions[1]; +}; + +constant float _108 = {}; + +struct main0_out +{ + float4 out_var_SV_Target0 [[color(0)]]; + uint gl_SampleMask [[sample_mask]]; +}; + +struct main0_in +{ + float4 in_var_TEXCOORD10_centroid [[user(locn0)]]; + float4 in_var_TEXCOORD11_centroid [[user(locn1)]]; + uint in_var_PRIMITIVE_ID [[user(locn2)]]; + float4 in_var_TEXCOORD7 [[user(locn3)]]; +}; + +fragment main0_out main0(main0_in in [[stage_in]], constant type_View& View [[buffer(0)]], const device type_StructuredBuffer_v4float& View_PrimitiveSceneData [[buffer(1)]], constant type_TranslucentBasePass& TranslucentBasePass [[buffer(2)]], constant type_Material& Material [[buffer(3)]], texture3d TranslucentBasePass_Shared_Fog_IntegratedLightScattering [[texture(0)]], sampler View_SharedBilinearClampedSampler [[sampler(0)]], float4 gl_FragCoord [[position]], uint gl_SampleMaskIn [[sample_mask]]) +{ + main0_out out = {}; + float4 _137 = View.View_SVPositionToTranslatedWorld * float4(gl_FragCoord.xyz, 1.0); + float3 _142 = (_137.xyz / float3(_137.w)) - float3(View.View_PreViewTranslation); + bool _165 = TranslucentBasePass.TranslucentBasePass_Shared_Fog_ApplyVolumetricFog > 0.0; + float4 _215; + if (_165) + { + float4 _172 = View.View_WorldToClip * float4(_142, 1.0); + float _173 = _172.w; + float4 _202; + if (_165) + { + _202 = TranslucentBasePass_Shared_Fog_IntegratedLightScattering.sample(View_SharedBilinearClampedSampler, float3(((_172.xy / float2(_173)).xy * float2(0.5, -0.5)) + float2(0.5), (log2((_173 * View.View_VolumetricFogGridZParams[0]) + View.View_VolumetricFogGridZParams[1]) * View.View_VolumetricFogGridZParams[2]) * View.View_VolumetricFogInvGridSize[2]), level(0.0)); + } + else + { + _202 = float4(0.0, 0.0, 0.0, 1.0); + } + _215 = float4(_202.xyz + (in.in_var_TEXCOORD7.xyz * float3(_202.w)), _202.w * in.in_var_TEXCOORD7.w); + } + else + { + _215 = in.in_var_TEXCOORD7; + } + float3 _216 = fast::max(Material.Material_VectorExpressions[1].xyz * float3(((1.0 + dot(float3(-1.0, -1.5, 3.0) / float3(sqrt(12.25)), normalize(float3x3(in.in_var_TEXCOORD10_centroid.xyz, cross(in.in_var_TEXCOORD11_centroid.xyz, in.in_var_TEXCOORD10_centroid.xyz) * float3(in.in_var_TEXCOORD11_centroid.w), in.in_var_TEXCOORD11_centroid.xyz) * normalize((float3(0.0, 0.0, 1.0) * float3(View.View_NormalOverrideParameter.w)) + View.View_NormalOverrideParameter.xyz)))) * 0.5) + 0.20000000298023223876953125), float3(0.0)); + float3 _246; + if (View.View_OutOfBoundsMask > 0.0) + { + uint _222 = in.in_var_PRIMITIVE_ID * 26u; + float3 _245; + if (any(abs(_142 - View_PrimitiveSceneData._m0[_222 + 5u].xyz) > (View_PrimitiveSceneData._m0[_222 + 19u].xyz + float3(1.0)))) + { + _245 = mix(float3(1.0, 1.0, 0.0), float3(0.0, 1.0, 1.0), select(float3(0.0), float3(1.0), float3(fract(dot(_142, float3(0.57700002193450927734375)) * 0.00200000009499490261077880859375)) > float3(0.5))); + } + else + { + _245 = _216; + } + _246 = _245; + } + else + { + _246 = _216; + } + float4 _256 = float4((_246 * float3(_215.w)) + _215.xyz, _108); + _256.w = 1.0; + float4 _268; + uint _269; + if (View.View_NumSceneColorMSAASamples > 1) + { + _268 = _256 * float4(float(View.View_NumSceneColorMSAASamples) * 0.25); + _269 = gl_SampleMaskIn & 15u; + } + else + { + _268 = _256; + _269 = gl_SampleMaskIn; + } + out.out_var_SV_Target0 = _268; + out.gl_SampleMask = _269; + return out; +} + diff --git a/third_party/spirv-cross/reference/shaders-ue4/asm/frag/subpass-input.ios.framebuffer-fetch.asm.frag b/third_party/spirv-cross/reference/shaders-ue4/asm/frag/subpass-input.ios.framebuffer-fetch.asm.frag new file mode 100644 index 0000000000..02cfc88294 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-ue4/asm/frag/subpass-input.ios.framebuffer-fetch.asm.frag @@ -0,0 +1,213 @@ +#include +#include + +using namespace metal; + +struct type_View +{ + float4x4 View_TranslatedWorldToClip; + float4x4 View_WorldToClip; + float4x4 View_TranslatedWorldToView; + float4x4 View_ViewToTranslatedWorld; + float4x4 View_TranslatedWorldToCameraView; + float4x4 View_CameraViewToTranslatedWorld; + float4x4 View_ViewToClip; + float4x4 View_ViewToClipNoAA; + float4x4 View_ClipToView; + float4x4 View_ClipToTranslatedWorld; + float4x4 View_SVPositionToTranslatedWorld; + float4x4 View_ScreenToWorld; + float4x4 View_ScreenToTranslatedWorld; + packed_float3 View_ViewForward; + float PrePadding_View_844; + packed_float3 View_ViewUp; + float PrePadding_View_860; + packed_float3 View_ViewRight; + float PrePadding_View_876; + packed_float3 View_HMDViewNoRollUp; + float PrePadding_View_892; + packed_float3 View_HMDViewNoRollRight; + float PrePadding_View_908; + float4 View_InvDeviceZToWorldZTransform; + float4 View_ScreenPositionScaleBias; + packed_float3 View_WorldCameraOrigin; + float PrePadding_View_956; + packed_float3 View_TranslatedWorldCameraOrigin; + float PrePadding_View_972; + packed_float3 View_WorldViewOrigin; + float PrePadding_View_988; + packed_float3 View_PreViewTranslation; + float PrePadding_View_1004; + float4x4 View_PrevProjection; + float4x4 View_PrevViewProj; + float4x4 View_PrevViewRotationProj; + float4x4 View_PrevViewToClip; + float4x4 View_PrevClipToView; + float4x4 View_PrevTranslatedWorldToClip; + float4x4 View_PrevTranslatedWorldToView; + float4x4 View_PrevViewToTranslatedWorld; + float4x4 View_PrevTranslatedWorldToCameraView; + float4x4 View_PrevCameraViewToTranslatedWorld; + packed_float3 View_PrevWorldCameraOrigin; + float PrePadding_View_1660; + packed_float3 View_PrevWorldViewOrigin; + float PrePadding_View_1676; + packed_float3 View_PrevPreViewTranslation; + float PrePadding_View_1692; + float4x4 View_PrevInvViewProj; + float4x4 View_PrevScreenToTranslatedWorld; + float4x4 View_ClipToPrevClip; + float4 View_TemporalAAJitter; + float4 View_GlobalClippingPlane; + float2 View_FieldOfViewWideAngles; + float2 View_PrevFieldOfViewWideAngles; + float4 View_ViewRectMin; + float4 View_ViewSizeAndInvSize; + float4 View_BufferSizeAndInvSize; + float4 View_BufferBilinearUVMinMax; + int View_NumSceneColorMSAASamples; + float View_PreExposure; + float View_OneOverPreExposure; + float PrePadding_View_2012; + float4 View_DiffuseOverrideParameter; + float4 View_SpecularOverrideParameter; + float4 View_NormalOverrideParameter; + float2 View_RoughnessOverrideParameter; + float View_PrevFrameGameTime; + float View_PrevFrameRealTime; + float View_OutOfBoundsMask; + float PrePadding_View_2084; + float PrePadding_View_2088; + float PrePadding_View_2092; + packed_float3 View_WorldCameraMovementSinceLastFrame; + float View_CullingSign; + float View_NearPlane; + float View_AdaptiveTessellationFactor; + float View_GameTime; + float View_RealTime; + float View_DeltaTime; + float View_MaterialTextureMipBias; + float View_MaterialTextureDerivativeMultiply; + uint View_Random; + uint View_FrameNumber; + uint View_StateFrameIndexMod8; + uint View_StateFrameIndex; + float View_CameraCut; + float View_UnlitViewmodeMask; + float PrePadding_View_2164; + float PrePadding_View_2168; + float PrePadding_View_2172; + float4 View_DirectionalLightColor; + packed_float3 View_DirectionalLightDirection; + float PrePadding_View_2204; + float4 View_TranslucencyLightingVolumeMin[2]; + float4 View_TranslucencyLightingVolumeInvSize[2]; + float4 View_TemporalAAParams; + float4 View_CircleDOFParams; + float View_DepthOfFieldSensorWidth; + float View_DepthOfFieldFocalDistance; + float View_DepthOfFieldScale; + float View_DepthOfFieldFocalLength; + float View_DepthOfFieldFocalRegion; + float View_DepthOfFieldNearTransitionRegion; + float View_DepthOfFieldFarTransitionRegion; + float View_MotionBlurNormalizedToPixel; + float View_bSubsurfacePostprocessEnabled; + float View_GeneralPurposeTweak; + float View_DemosaicVposOffset; + float PrePadding_View_2348; + packed_float3 View_IndirectLightingColorScale; + float View_HDR32bppEncodingMode; + packed_float3 View_AtmosphericFogSunDirection; + float View_AtmosphericFogSunPower; + float View_AtmosphericFogPower; + float View_AtmosphericFogDensityScale; + float View_AtmosphericFogDensityOffset; + float View_AtmosphericFogGroundOffset; + float View_AtmosphericFogDistanceScale; + float View_AtmosphericFogAltitudeScale; + float View_AtmosphericFogHeightScaleRayleigh; + float View_AtmosphericFogStartDistance; + float View_AtmosphericFogDistanceOffset; + float View_AtmosphericFogSunDiscScale; + uint View_AtmosphericFogRenderMask; + uint View_AtmosphericFogInscatterAltitudeSampleNum; + float4 View_AtmosphericFogSunColor; + packed_float3 View_NormalCurvatureToRoughnessScaleBias; + float View_RenderingReflectionCaptureMask; + float4 View_AmbientCubemapTint; + float View_AmbientCubemapIntensity; + float View_SkyLightParameters; + float PrePadding_View_2488; + float PrePadding_View_2492; + float4 View_SkyLightColor; + float4 View_SkyIrradianceEnvironmentMap[7]; + float View_MobilePreviewMode; + float View_HMDEyePaddingOffset; + float View_ReflectionCubemapMaxMip; + float View_ShowDecalsMask; + uint View_DistanceFieldAOSpecularOcclusionMode; + float View_IndirectCapsuleSelfShadowingIntensity; + float PrePadding_View_2648; + float PrePadding_View_2652; + packed_float3 View_ReflectionEnvironmentRoughnessMixingScaleBiasAndLargestWeight; + int View_StereoPassIndex; + float4 View_GlobalVolumeCenterAndExtent[4]; + float4 View_GlobalVolumeWorldToUVAddAndMul[4]; + float View_GlobalVolumeDimension; + float View_GlobalVolumeTexelSize; + float View_MaxGlobalDistance; + float View_bCheckerboardSubsurfaceProfileRendering; + packed_float3 View_VolumetricFogInvGridSize; + float PrePadding_View_2828; + packed_float3 View_VolumetricFogGridZParams; + float PrePadding_View_2844; + float2 View_VolumetricFogSVPosToVolumeUV; + float View_VolumetricFogMaxDistance; + float PrePadding_View_2860; + packed_float3 View_VolumetricLightmapWorldToUVScale; + float PrePadding_View_2876; + packed_float3 View_VolumetricLightmapWorldToUVAdd; + float PrePadding_View_2892; + packed_float3 View_VolumetricLightmapIndirectionTextureSize; + float View_VolumetricLightmapBrickSize; + packed_float3 View_VolumetricLightmapBrickTexelSize; + float View_StereoIPD; + float View_IndirectLightingCacheShowFlag; + float View_EyeToPixelSpreadAngle; +}; + +struct type_Globals +{ + float3 SoftTransitionScale; + float4 ShadowBufferSize; + float ShadowFadeFraction; + float ShadowSharpen; + float4 LightPositionAndInvRadius; + float4x4 ScreenToShadowMatrix; + float2 ProjectionDepthBiasParameters; + float4 ModulatedShadowColor; + float4 ShadowTileOffsetAndSize; +}; + +constant float4 _58 = {}; + +struct main0_out +{ + float4 out_var_SV_Target0 [[color(0)]]; +}; + +fragment main0_out main0(constant type_View& View [[buffer(0)]], constant type_Globals& _Globals [[buffer(1)]], float4 _gl_LastFragData [[color(0)]], texture2d ShadowDepthTexture [[texture(1)]], sampler ShadowDepthTextureSampler [[sampler(0)]], float4 gl_FragCoord [[position]]) +{ + main0_out out = {}; + float4 _67 = _gl_LastFragData; + float _68 = _67.w; + float4 _82 = _Globals.ScreenToShadowMatrix * float4((((gl_FragCoord.xy * View.View_BufferSizeAndInvSize.zw) - View.View_ScreenPositionScaleBias.wz) / View.View_ScreenPositionScaleBias.xy) * float2(_68), _68, 1.0); + float _118 = fast::clamp(((fast::clamp((ShadowDepthTexture.sample(ShadowDepthTextureSampler, (((_82.xyz / float3(_82.w)).xy * _Globals.ShadowTileOffsetAndSize.zw).xy + _Globals.ShadowTileOffsetAndSize.xy).xy, level(0.0)).xxx * float3(_Globals.SoftTransitionScale.z)) - float3((fast::min(_82.z, 0.999989986419677734375) * _Globals.SoftTransitionScale.z) - 1.0), float3(0.0), float3(1.0)).x - 0.5) * _Globals.ShadowSharpen) + 0.5, 0.0, 1.0); + float3 _127 = mix(_Globals.ModulatedShadowColor.xyz, float3(1.0), float3(mix(1.0, _118 * _118, _Globals.ShadowFadeFraction))); + float4 _129 = float4(_127.x, _127.y, _127.z, _58.w); + _129.w = 0.0; + out.out_var_SV_Target0 = _129; + return out; +} + diff --git a/third_party/spirv-cross/reference/shaders-ue4/asm/frag/texture-atomics.asm.frag b/third_party/spirv-cross/reference/shaders-ue4/asm/frag/texture-atomics.asm.frag new file mode 100644 index 0000000000..98cdda44d7 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-ue4/asm/frag/texture-atomics.asm.frag @@ -0,0 +1,121 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" +#pragma clang diagnostic ignored "-Wunused-variable" + +#include +#include +#include + +using namespace metal; + +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +struct type_StructuredBuffer_v4float +{ + float4 _m0[1]; +}; + +struct type_Globals +{ + uint2 ShadowTileListGroupSize; +}; + +constant float3 _70 = {}; + +struct main0_out +{ + float4 out_var_SV_Target0 [[color(0)]]; +}; + +struct main0_in +{ + uint in_var_TEXCOORD0 [[user(locn0)]]; +}; + +fragment main0_out main0(main0_in in [[stage_in]], const device type_StructuredBuffer_v4float& CulledObjectBoxBounds [[buffer(0)]], constant type_Globals& _Globals [[buffer(1)]], texture2d RWShadowTileNumCulledObjects [[texture(0)]], device atomic_uint* RWShadowTileNumCulledObjects_atomic [[buffer(2)]], float4 gl_FragCoord [[position]]) +{ + main0_out out = {}; + uint2 _77 = uint2(gl_FragCoord.xy); + uint _78 = _77.y; + uint _83 = _77.x; + float2 _91 = float2(float(_83), float((_Globals.ShadowTileListGroupSize.y - 1u) - _78)); + float2 _93 = float2(_Globals.ShadowTileListGroupSize); + float2 _96 = ((_91 / _93) * float2(2.0)) - float2(1.0); + float2 _100 = (((_91 + float2(1.0)) / _93) * float2(2.0)) - float2(1.0); + float3 _102 = float3(_100.x, _100.y, _70.z); + _102.z = 1.0; + uint _103 = in.in_var_TEXCOORD0 * 5u; + uint _107 = _103 + 1u; + if (all(CulledObjectBoxBounds._m0[_107].xy > _96.xy) && all(CulledObjectBoxBounds._m0[_103].xyz < _102)) + { + float _122 = _96.x; + float _123 = _96.y; + spvUnsafeArray _73; + _73[0] = float3(_122, _123, -1000.0); + float _126 = _100.x; + _73[1] = float3(_126, _123, -1000.0); + float _129 = _100.y; + _73[2] = float3(_122, _129, -1000.0); + _73[3] = float3(_126, _129, -1000.0); + _73[4] = float3(_122, _123, 1.0); + _73[5] = float3(_126, _123, 1.0); + _73[6] = float3(_122, _129, 1.0); + _73[7] = float3(_126, _129, 1.0); + float3 _155; + float3 _158; + _155 = float3(-500000.0); + _158 = float3(500000.0); + for (int _160 = 0; _160 < 8; ) + { + float3 _166 = _73[_160] - (float3(0.5) * (CulledObjectBoxBounds._m0[_103].xyz + CulledObjectBoxBounds._m0[_107].xyz)); + float3 _170 = float3(dot(_166, CulledObjectBoxBounds._m0[_103 + 2u].xyz), dot(_166, CulledObjectBoxBounds._m0[_103 + 3u].xyz), dot(_166, CulledObjectBoxBounds._m0[_103 + 4u].xyz)); + _155 = fast::max(_155, _170); + _158 = fast::min(_158, _170); + _160++; + continue; + } + if (all(_158 < float3(1.0)) && all(_155 > float3(-1.0))) + { + uint _179 = atomic_fetch_add_explicit((device atomic_uint*)&RWShadowTileNumCulledObjects_atomic[(_78 * _Globals.ShadowTileListGroupSize.x) + _83], 1u, memory_order_relaxed); + } + } + out.out_var_SV_Target0 = float4(0.0); + return out; +} + diff --git a/third_party/spirv-cross/reference/shaders-ue4/asm/frag/texture-atomics.asm.graphics-robust-access.frag b/third_party/spirv-cross/reference/shaders-ue4/asm/frag/texture-atomics.asm.graphics-robust-access.frag new file mode 100644 index 0000000000..98cdda44d7 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-ue4/asm/frag/texture-atomics.asm.graphics-robust-access.frag @@ -0,0 +1,121 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" +#pragma clang diagnostic ignored "-Wunused-variable" + +#include +#include +#include + +using namespace metal; + +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +struct type_StructuredBuffer_v4float +{ + float4 _m0[1]; +}; + +struct type_Globals +{ + uint2 ShadowTileListGroupSize; +}; + +constant float3 _70 = {}; + +struct main0_out +{ + float4 out_var_SV_Target0 [[color(0)]]; +}; + +struct main0_in +{ + uint in_var_TEXCOORD0 [[user(locn0)]]; +}; + +fragment main0_out main0(main0_in in [[stage_in]], const device type_StructuredBuffer_v4float& CulledObjectBoxBounds [[buffer(0)]], constant type_Globals& _Globals [[buffer(1)]], texture2d RWShadowTileNumCulledObjects [[texture(0)]], device atomic_uint* RWShadowTileNumCulledObjects_atomic [[buffer(2)]], float4 gl_FragCoord [[position]]) +{ + main0_out out = {}; + uint2 _77 = uint2(gl_FragCoord.xy); + uint _78 = _77.y; + uint _83 = _77.x; + float2 _91 = float2(float(_83), float((_Globals.ShadowTileListGroupSize.y - 1u) - _78)); + float2 _93 = float2(_Globals.ShadowTileListGroupSize); + float2 _96 = ((_91 / _93) * float2(2.0)) - float2(1.0); + float2 _100 = (((_91 + float2(1.0)) / _93) * float2(2.0)) - float2(1.0); + float3 _102 = float3(_100.x, _100.y, _70.z); + _102.z = 1.0; + uint _103 = in.in_var_TEXCOORD0 * 5u; + uint _107 = _103 + 1u; + if (all(CulledObjectBoxBounds._m0[_107].xy > _96.xy) && all(CulledObjectBoxBounds._m0[_103].xyz < _102)) + { + float _122 = _96.x; + float _123 = _96.y; + spvUnsafeArray _73; + _73[0] = float3(_122, _123, -1000.0); + float _126 = _100.x; + _73[1] = float3(_126, _123, -1000.0); + float _129 = _100.y; + _73[2] = float3(_122, _129, -1000.0); + _73[3] = float3(_126, _129, -1000.0); + _73[4] = float3(_122, _123, 1.0); + _73[5] = float3(_126, _123, 1.0); + _73[6] = float3(_122, _129, 1.0); + _73[7] = float3(_126, _129, 1.0); + float3 _155; + float3 _158; + _155 = float3(-500000.0); + _158 = float3(500000.0); + for (int _160 = 0; _160 < 8; ) + { + float3 _166 = _73[_160] - (float3(0.5) * (CulledObjectBoxBounds._m0[_103].xyz + CulledObjectBoxBounds._m0[_107].xyz)); + float3 _170 = float3(dot(_166, CulledObjectBoxBounds._m0[_103 + 2u].xyz), dot(_166, CulledObjectBoxBounds._m0[_103 + 3u].xyz), dot(_166, CulledObjectBoxBounds._m0[_103 + 4u].xyz)); + _155 = fast::max(_155, _170); + _158 = fast::min(_158, _170); + _160++; + continue; + } + if (all(_158 < float3(1.0)) && all(_155 > float3(-1.0))) + { + uint _179 = atomic_fetch_add_explicit((device atomic_uint*)&RWShadowTileNumCulledObjects_atomic[(_78 * _Globals.ShadowTileListGroupSize.x) + _83], 1u, memory_order_relaxed); + } + } + out.out_var_SV_Target0 = float4(0.0); + return out; +} + diff --git a/third_party/spirv-cross/reference/shaders-ue4/asm/tesc/hs-incorrect-base-type.asm.tesc b/third_party/spirv-cross/reference/shaders-ue4/asm/tesc/hs-incorrect-base-type.asm.tesc new file mode 100644 index 0000000000..70d17d47f2 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-ue4/asm/tesc/hs-incorrect-base-type.asm.tesc @@ -0,0 +1,399 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + +#include +#include + +using namespace metal; + +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +struct FVertexFactoryInterpolantsVSToPS +{ + float4 TangentToWorld0; + float4 TangentToWorld2; + float4 Color; + spvUnsafeArray TexCoords; + float4 LightMapCoordinate; + uint PrimitiveId; + uint LightmapDataIndex; +}; + +struct FVertexFactoryInterpolantsVSToDS +{ + FVertexFactoryInterpolantsVSToPS InterpolantsVSToPS; +}; + +struct FSharedBasePassInterpolants +{ +}; +struct FBasePassInterpolantsVSToDS +{ + FSharedBasePassInterpolants _m0; +}; + +struct FBasePassVSToDS +{ + FVertexFactoryInterpolantsVSToDS FactoryInterpolants; + FBasePassInterpolantsVSToDS BasePassInterpolants; + float4 Position; +}; + +struct FPNTessellationHSToDS +{ + FBasePassVSToDS PassSpecificData; + spvUnsafeArray WorldPosition; + float3 DisplacementScale; + float TessellationMultiplier; + float WorldDisplacementMultiplier; +}; + +struct type_View +{ + float4x4 View_TranslatedWorldToClip; + float4x4 View_WorldToClip; + float4x4 View_TranslatedWorldToView; + float4x4 View_ViewToTranslatedWorld; + float4x4 View_TranslatedWorldToCameraView; + float4x4 View_CameraViewToTranslatedWorld; + float4x4 View_ViewToClip; + float4x4 View_ViewToClipNoAA; + float4x4 View_ClipToView; + float4x4 View_ClipToTranslatedWorld; + float4x4 View_SVPositionToTranslatedWorld; + float4x4 View_ScreenToWorld; + float4x4 View_ScreenToTranslatedWorld; + packed_float3 View_ViewForward; + float PrePadding_View_844; + packed_float3 View_ViewUp; + float PrePadding_View_860; + packed_float3 View_ViewRight; + float PrePadding_View_876; + packed_float3 View_HMDViewNoRollUp; + float PrePadding_View_892; + packed_float3 View_HMDViewNoRollRight; + float PrePadding_View_908; + float4 View_InvDeviceZToWorldZTransform; + float4 View_ScreenPositionScaleBias; + packed_float3 View_WorldCameraOrigin; + float PrePadding_View_956; + packed_float3 View_TranslatedWorldCameraOrigin; + float PrePadding_View_972; + packed_float3 View_WorldViewOrigin; + float PrePadding_View_988; + packed_float3 View_PreViewTranslation; + float PrePadding_View_1004; + float4x4 View_PrevProjection; + float4x4 View_PrevViewProj; + float4x4 View_PrevViewRotationProj; + float4x4 View_PrevViewToClip; + float4x4 View_PrevClipToView; + float4x4 View_PrevTranslatedWorldToClip; + float4x4 View_PrevTranslatedWorldToView; + float4x4 View_PrevViewToTranslatedWorld; + float4x4 View_PrevTranslatedWorldToCameraView; + float4x4 View_PrevCameraViewToTranslatedWorld; + packed_float3 View_PrevWorldCameraOrigin; + float PrePadding_View_1660; + packed_float3 View_PrevWorldViewOrigin; + float PrePadding_View_1676; + packed_float3 View_PrevPreViewTranslation; + float PrePadding_View_1692; + float4x4 View_PrevInvViewProj; + float4x4 View_PrevScreenToTranslatedWorld; + float4x4 View_ClipToPrevClip; + float4 View_TemporalAAJitter; + float4 View_GlobalClippingPlane; + float2 View_FieldOfViewWideAngles; + float2 View_PrevFieldOfViewWideAngles; + float4 View_ViewRectMin; + float4 View_ViewSizeAndInvSize; + float4 View_BufferSizeAndInvSize; + float4 View_BufferBilinearUVMinMax; + int View_NumSceneColorMSAASamples; + float View_PreExposure; + float View_OneOverPreExposure; + float PrePadding_View_2012; + float4 View_DiffuseOverrideParameter; + float4 View_SpecularOverrideParameter; + float4 View_NormalOverrideParameter; + float2 View_RoughnessOverrideParameter; + float View_PrevFrameGameTime; + float View_PrevFrameRealTime; + float View_OutOfBoundsMask; + float PrePadding_View_2084; + float PrePadding_View_2088; + float PrePadding_View_2092; + packed_float3 View_WorldCameraMovementSinceLastFrame; + float View_CullingSign; + float View_NearPlane; + float View_AdaptiveTessellationFactor; + float View_GameTime; + float View_RealTime; + float View_DeltaTime; + float View_MaterialTextureMipBias; + float View_MaterialTextureDerivativeMultiply; + uint View_Random; + uint View_FrameNumber; + uint View_StateFrameIndexMod8; + uint View_StateFrameIndex; + float View_CameraCut; + float View_UnlitViewmodeMask; + float PrePadding_View_2164; + float PrePadding_View_2168; + float PrePadding_View_2172; + float4 View_DirectionalLightColor; + packed_float3 View_DirectionalLightDirection; + float PrePadding_View_2204; + float4 View_TranslucencyLightingVolumeMin[2]; + float4 View_TranslucencyLightingVolumeInvSize[2]; + float4 View_TemporalAAParams; + float4 View_CircleDOFParams; + float View_DepthOfFieldSensorWidth; + float View_DepthOfFieldFocalDistance; + float View_DepthOfFieldScale; + float View_DepthOfFieldFocalLength; + float View_DepthOfFieldFocalRegion; + float View_DepthOfFieldNearTransitionRegion; + float View_DepthOfFieldFarTransitionRegion; + float View_MotionBlurNormalizedToPixel; + float View_bSubsurfacePostprocessEnabled; + float View_GeneralPurposeTweak; + float View_DemosaicVposOffset; + float PrePadding_View_2348; + packed_float3 View_IndirectLightingColorScale; + float View_HDR32bppEncodingMode; + packed_float3 View_AtmosphericFogSunDirection; + float View_AtmosphericFogSunPower; + float View_AtmosphericFogPower; + float View_AtmosphericFogDensityScale; + float View_AtmosphericFogDensityOffset; + float View_AtmosphericFogGroundOffset; + float View_AtmosphericFogDistanceScale; + float View_AtmosphericFogAltitudeScale; + float View_AtmosphericFogHeightScaleRayleigh; + float View_AtmosphericFogStartDistance; + float View_AtmosphericFogDistanceOffset; + float View_AtmosphericFogSunDiscScale; + uint View_AtmosphericFogRenderMask; + uint View_AtmosphericFogInscatterAltitudeSampleNum; + float4 View_AtmosphericFogSunColor; + packed_float3 View_NormalCurvatureToRoughnessScaleBias; + float View_RenderingReflectionCaptureMask; + float4 View_AmbientCubemapTint; + float View_AmbientCubemapIntensity; + float View_SkyLightParameters; + float PrePadding_View_2488; + float PrePadding_View_2492; + float4 View_SkyLightColor; + float4 View_SkyIrradianceEnvironmentMap[7]; + float View_MobilePreviewMode; + float View_HMDEyePaddingOffset; + float View_ReflectionCubemapMaxMip; + float View_ShowDecalsMask; + uint View_DistanceFieldAOSpecularOcclusionMode; + float View_IndirectCapsuleSelfShadowingIntensity; + float PrePadding_View_2648; + float PrePadding_View_2652; + packed_float3 View_ReflectionEnvironmentRoughnessMixingScaleBiasAndLargestWeight; + int View_StereoPassIndex; + float4 View_GlobalVolumeCenterAndExtent[4]; + float4 View_GlobalVolumeWorldToUVAddAndMul[4]; + float View_GlobalVolumeDimension; + float View_GlobalVolumeTexelSize; + float View_MaxGlobalDistance; + float View_bCheckerboardSubsurfaceProfileRendering; + packed_float3 View_VolumetricFogInvGridSize; + float PrePadding_View_2828; + packed_float3 View_VolumetricFogGridZParams; + float PrePadding_View_2844; + float2 View_VolumetricFogSVPosToVolumeUV; + float View_VolumetricFogMaxDistance; + float PrePadding_View_2860; + packed_float3 View_VolumetricLightmapWorldToUVScale; + float PrePadding_View_2876; + packed_float3 View_VolumetricLightmapWorldToUVAdd; + float PrePadding_View_2892; + packed_float3 View_VolumetricLightmapIndirectionTextureSize; + float View_VolumetricLightmapBrickSize; + packed_float3 View_VolumetricLightmapBrickTexelSize; + float View_StereoIPD; + float View_IndirectLightingCacheShowFlag; + float View_EyeToPixelSpreadAngle; +}; + +struct type_StructuredBuffer_v4float +{ + float4 _m0[1]; +}; + +constant float4 _142 = {}; + +struct main0_out +{ + float4 out_var_COLOR0; + uint out_var_LIGHTMAP_ID; + float3 out_var_PN_DisplacementScales; + spvUnsafeArray out_var_PN_POSITION; + float out_var_PN_TessellationMultiplier; + float out_var_PN_WorldDisplacementMultiplier; + uint out_var_PRIMITIVE_ID; + spvUnsafeArray out_var_TEXCOORD0; + float4 out_var_TEXCOORD10_centroid; + float4 out_var_TEXCOORD11_centroid; + float4 out_var_TEXCOORD4; + float4 out_var_VS_To_DS_Position; +}; + +struct main0_patchOut +{ + float4 out_var_PN_POSITION9; +}; + +struct main0_in +{ + float4 in_var_TEXCOORD10_centroid [[attribute(0)]]; + float4 in_var_TEXCOORD11_centroid [[attribute(1)]]; + float4 in_var_COLOR0 [[attribute(2)]]; + float4 in_var_TEXCOORD0_0 [[attribute(3)]]; + float4 in_var_TEXCOORD4 [[attribute(4)]]; + uint in_var_PRIMITIVE_ID [[attribute(5)]]; + uint in_var_LIGHTMAP_ID [[attribute(6)]]; + float4 in_var_VS_To_DS_Position [[attribute(7)]]; +}; + +kernel void main0(main0_in in [[stage_in]], constant type_View& View [[buffer(0)]], const device type_StructuredBuffer_v4float& View_PrimitiveSceneData [[buffer(1)]], uint gl_InvocationID [[thread_index_in_threadgroup]], uint gl_PrimitiveID [[threadgroup_position_in_grid]], device main0_out* spvOut [[buffer(28)]], constant uint* spvIndirectParams [[buffer(29)]], device main0_patchOut* spvPatchOut [[buffer(27)]], device MTLTriangleTessellationFactorsHalf* spvTessLevel [[buffer(26)]], threadgroup main0_in* gl_in [[threadgroup(0)]]) +{ + threadgroup FPNTessellationHSToDS temp_var_hullMainRetVal[3]; + device main0_out* gl_out = &spvOut[gl_PrimitiveID * 3]; + device main0_patchOut& patchOut = spvPatchOut[gl_PrimitiveID]; + if (gl_InvocationID < spvIndirectParams[0]) + gl_in[gl_InvocationID] = in; + threadgroup_barrier(mem_flags::mem_threadgroup); + if (gl_InvocationID >= 3) + return; + spvUnsafeArray _144 = spvUnsafeArray({ gl_in[0].in_var_TEXCOORD10_centroid, gl_in[1].in_var_TEXCOORD10_centroid, gl_in[2].in_var_TEXCOORD10_centroid, gl_in[3].in_var_TEXCOORD10_centroid, gl_in[4].in_var_TEXCOORD10_centroid, gl_in[5].in_var_TEXCOORD10_centroid, gl_in[6].in_var_TEXCOORD10_centroid, gl_in[7].in_var_TEXCOORD10_centroid, gl_in[8].in_var_TEXCOORD10_centroid, gl_in[9].in_var_TEXCOORD10_centroid, gl_in[10].in_var_TEXCOORD10_centroid, gl_in[11].in_var_TEXCOORD10_centroid }); + spvUnsafeArray _145 = spvUnsafeArray({ gl_in[0].in_var_TEXCOORD11_centroid, gl_in[1].in_var_TEXCOORD11_centroid, gl_in[2].in_var_TEXCOORD11_centroid, gl_in[3].in_var_TEXCOORD11_centroid, gl_in[4].in_var_TEXCOORD11_centroid, gl_in[5].in_var_TEXCOORD11_centroid, gl_in[6].in_var_TEXCOORD11_centroid, gl_in[7].in_var_TEXCOORD11_centroid, gl_in[8].in_var_TEXCOORD11_centroid, gl_in[9].in_var_TEXCOORD11_centroid, gl_in[10].in_var_TEXCOORD11_centroid, gl_in[11].in_var_TEXCOORD11_centroid }); + spvUnsafeArray _146 = spvUnsafeArray({ gl_in[0].in_var_COLOR0, gl_in[1].in_var_COLOR0, gl_in[2].in_var_COLOR0, gl_in[3].in_var_COLOR0, gl_in[4].in_var_COLOR0, gl_in[5].in_var_COLOR0, gl_in[6].in_var_COLOR0, gl_in[7].in_var_COLOR0, gl_in[8].in_var_COLOR0, gl_in[9].in_var_COLOR0, gl_in[10].in_var_COLOR0, gl_in[11].in_var_COLOR0 }); + spvUnsafeArray, 12> _147 = spvUnsafeArray, 12>({ spvUnsafeArray({ gl_in[0].in_var_TEXCOORD0_0 }), spvUnsafeArray({ gl_in[1].in_var_TEXCOORD0_0 }), spvUnsafeArray({ gl_in[2].in_var_TEXCOORD0_0 }), spvUnsafeArray({ gl_in[3].in_var_TEXCOORD0_0 }), spvUnsafeArray({ gl_in[4].in_var_TEXCOORD0_0 }), spvUnsafeArray({ gl_in[5].in_var_TEXCOORD0_0 }), spvUnsafeArray({ gl_in[6].in_var_TEXCOORD0_0 }), spvUnsafeArray({ gl_in[7].in_var_TEXCOORD0_0 }), spvUnsafeArray({ gl_in[8].in_var_TEXCOORD0_0 }), spvUnsafeArray({ gl_in[9].in_var_TEXCOORD0_0 }), spvUnsafeArray({ gl_in[10].in_var_TEXCOORD0_0 }), spvUnsafeArray({ gl_in[11].in_var_TEXCOORD0_0 }) }); + spvUnsafeArray _148 = spvUnsafeArray({ gl_in[0].in_var_TEXCOORD4, gl_in[1].in_var_TEXCOORD4, gl_in[2].in_var_TEXCOORD4, gl_in[3].in_var_TEXCOORD4, gl_in[4].in_var_TEXCOORD4, gl_in[5].in_var_TEXCOORD4, gl_in[6].in_var_TEXCOORD4, gl_in[7].in_var_TEXCOORD4, gl_in[8].in_var_TEXCOORD4, gl_in[9].in_var_TEXCOORD4, gl_in[10].in_var_TEXCOORD4, gl_in[11].in_var_TEXCOORD4 }); + spvUnsafeArray _149 = spvUnsafeArray({ gl_in[0].in_var_PRIMITIVE_ID, gl_in[1].in_var_PRIMITIVE_ID, gl_in[2].in_var_PRIMITIVE_ID, gl_in[3].in_var_PRIMITIVE_ID, gl_in[4].in_var_PRIMITIVE_ID, gl_in[5].in_var_PRIMITIVE_ID, gl_in[6].in_var_PRIMITIVE_ID, gl_in[7].in_var_PRIMITIVE_ID, gl_in[8].in_var_PRIMITIVE_ID, gl_in[9].in_var_PRIMITIVE_ID, gl_in[10].in_var_PRIMITIVE_ID, gl_in[11].in_var_PRIMITIVE_ID }); + spvUnsafeArray _150 = spvUnsafeArray({ gl_in[0].in_var_LIGHTMAP_ID, gl_in[1].in_var_LIGHTMAP_ID, gl_in[2].in_var_LIGHTMAP_ID, gl_in[3].in_var_LIGHTMAP_ID, gl_in[4].in_var_LIGHTMAP_ID, gl_in[5].in_var_LIGHTMAP_ID, gl_in[6].in_var_LIGHTMAP_ID, gl_in[7].in_var_LIGHTMAP_ID, gl_in[8].in_var_LIGHTMAP_ID, gl_in[9].in_var_LIGHTMAP_ID, gl_in[10].in_var_LIGHTMAP_ID, gl_in[11].in_var_LIGHTMAP_ID }); + spvUnsafeArray _259 = spvUnsafeArray({ gl_in[0].in_var_VS_To_DS_Position, gl_in[1].in_var_VS_To_DS_Position, gl_in[2].in_var_VS_To_DS_Position, gl_in[3].in_var_VS_To_DS_Position, gl_in[4].in_var_VS_To_DS_Position, gl_in[5].in_var_VS_To_DS_Position, gl_in[6].in_var_VS_To_DS_Position, gl_in[7].in_var_VS_To_DS_Position, gl_in[8].in_var_VS_To_DS_Position, gl_in[9].in_var_VS_To_DS_Position, gl_in[10].in_var_VS_To_DS_Position, gl_in[11].in_var_VS_To_DS_Position }); + spvUnsafeArray _284 = spvUnsafeArray({ FBasePassVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _144[0], _145[0], _146[0], _147[0], _148[0], _149[0], _150[0] } }, FBasePassInterpolantsVSToDS{ { } }, _259[0] }, FBasePassVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _144[1], _145[1], _146[1], _147[1], _148[1], _149[1], _150[1] } }, FBasePassInterpolantsVSToDS{ { } }, _259[1] }, FBasePassVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _144[2], _145[2], _146[2], _147[2], _148[2], _149[2], _150[2] } }, FBasePassInterpolantsVSToDS{ { } }, _259[2] }, FBasePassVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _144[3], _145[3], _146[3], _147[3], _148[3], _149[3], _150[3] } }, FBasePassInterpolantsVSToDS{ { } }, _259[3] }, FBasePassVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _144[4], _145[4], _146[4], _147[4], _148[4], _149[4], _150[4] } }, FBasePassInterpolantsVSToDS{ { } }, _259[4] }, FBasePassVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _144[5], _145[5], _146[5], _147[5], _148[5], _149[5], _150[5] } }, FBasePassInterpolantsVSToDS{ { } }, _259[5] }, FBasePassVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _144[6], _145[6], _146[6], _147[6], _148[6], _149[6], _150[6] } }, FBasePassInterpolantsVSToDS{ { } }, _259[6] }, FBasePassVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _144[7], _145[7], _146[7], _147[7], _148[7], _149[7], _150[7] } }, FBasePassInterpolantsVSToDS{ { } }, _259[7] }, FBasePassVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _144[8], _145[8], _146[8], _147[8], _148[8], _149[8], _150[8] } }, FBasePassInterpolantsVSToDS{ { } }, _259[8] }, FBasePassVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _144[9], _145[9], _146[9], _147[9], _148[9], _149[9], _150[9] } }, FBasePassInterpolantsVSToDS{ { } }, _259[9] }, FBasePassVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _144[10], _145[10], _146[10], _147[10], _148[10], _149[10], _150[10] } }, FBasePassInterpolantsVSToDS{ { } }, _259[10] }, FBasePassVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _144[11], _145[11], _146[11], _147[11], _148[11], _149[11], _150[11] } }, FBasePassInterpolantsVSToDS{ { } }, _259[11] } }); + spvUnsafeArray param_var_I; + param_var_I = _284; + float4 _301 = float4(param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld2.xyz, 0.0); + float3 _310 = View_PrimitiveSceneData._m0[(param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.PrimitiveId * 26u) + 22u].xyz * float3x3(param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld0.xyz, cross(param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld2.xyz, param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld0.xyz) * float3(param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld2.w), param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld2.xyz); + uint _313 = (gl_InvocationID < 2u) ? (gl_InvocationID + 1u) : 0u; + uint _314 = 2u * gl_InvocationID; + uint _315 = 3u + _314; + uint _316 = _314 + 4u; + float4 _328 = float4(param_var_I[_313].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld2.xyz, 0.0); + float4 _336 = float4(param_var_I[_315].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld2.xyz, 0.0); + float4 _344 = float4(param_var_I[_316].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld2.xyz, 0.0); + spvUnsafeArray _392 = spvUnsafeArray({ param_var_I[gl_InvocationID].Position, (((((float4(2.0) * param_var_I[gl_InvocationID].Position) + param_var_I[_313].Position) - (float4(dot(param_var_I[_313].Position - param_var_I[gl_InvocationID].Position, _301)) * _301)) * float4(0.3333333432674407958984375)) + ((((float4(2.0) * param_var_I[_315].Position) + param_var_I[_316].Position) - (float4(dot(param_var_I[_316].Position - param_var_I[_315].Position, _336)) * _336)) * float4(0.3333333432674407958984375))) * float4(0.5), (((((float4(2.0) * param_var_I[_313].Position) + param_var_I[gl_InvocationID].Position) - (float4(dot(param_var_I[gl_InvocationID].Position - param_var_I[_313].Position, _328)) * _328)) * float4(0.3333333432674407958984375)) + ((((float4(2.0) * param_var_I[_316].Position) + param_var_I[_315].Position) - (float4(dot(param_var_I[_315].Position - param_var_I[_316].Position, _344)) * _344)) * float4(0.3333333432674407958984375))) * float4(0.5) }); + gl_out[gl_InvocationID].out_var_TEXCOORD10_centroid = param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld0; + gl_out[gl_InvocationID].out_var_TEXCOORD11_centroid = param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld2; + gl_out[gl_InvocationID].out_var_COLOR0 = param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.Color; + gl_out[gl_InvocationID].out_var_TEXCOORD0 = param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TexCoords; + gl_out[gl_InvocationID].out_var_TEXCOORD4 = param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.LightMapCoordinate; + gl_out[gl_InvocationID].out_var_PRIMITIVE_ID = param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.PrimitiveId; + gl_out[gl_InvocationID].out_var_LIGHTMAP_ID = param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.LightmapDataIndex; + gl_out[gl_InvocationID].out_var_VS_To_DS_Position = param_var_I[gl_InvocationID].Position; + gl_out[gl_InvocationID].out_var_PN_POSITION = _392; + gl_out[gl_InvocationID].out_var_PN_DisplacementScales = _310; + gl_out[gl_InvocationID].out_var_PN_TessellationMultiplier = 1.0; + gl_out[gl_InvocationID].out_var_PN_WorldDisplacementMultiplier = 1.0; + temp_var_hullMainRetVal[gl_InvocationID] = FPNTessellationHSToDS{ param_var_I[gl_InvocationID], _392, _310, 1.0, 1.0 }; + threadgroup_barrier(mem_flags::mem_device | mem_flags::mem_threadgroup); + if (gl_InvocationID == 0u) + { + float4 _450 = (((((temp_var_hullMainRetVal[0u].WorldPosition[1] + temp_var_hullMainRetVal[0u].WorldPosition[2]) + temp_var_hullMainRetVal[1u].WorldPosition[1]) + temp_var_hullMainRetVal[1u].WorldPosition[2]) + temp_var_hullMainRetVal[2u].WorldPosition[1]) + temp_var_hullMainRetVal[2u].WorldPosition[2]) * float4(0.16666667163372039794921875); + float4 _463 = _142; + _463.x = 0.5 * (temp_var_hullMainRetVal[1u].TessellationMultiplier + temp_var_hullMainRetVal[2u].TessellationMultiplier); + float4 _469 = _463; + _469.y = 0.5 * (temp_var_hullMainRetVal[2u].TessellationMultiplier + temp_var_hullMainRetVal[0u].TessellationMultiplier); + float4 _474 = _469; + _474.z = 0.5 * (temp_var_hullMainRetVal[0u].TessellationMultiplier + temp_var_hullMainRetVal[1u].TessellationMultiplier); + float4 _481 = _474; + _481.w = 0.333000004291534423828125 * ((temp_var_hullMainRetVal[0u].TessellationMultiplier + temp_var_hullMainRetVal[1u].TessellationMultiplier) + temp_var_hullMainRetVal[2u].TessellationMultiplier); + float4 _589; + for (;;) + { + float4 _489 = View.View_ViewToClip * float4(0.0); + float4 _494 = View.View_TranslatedWorldToClip * float4(temp_var_hullMainRetVal[0u].WorldPosition[0].xyz, 1.0); + float3 _495 = _494.xyz; + float3 _496 = _489.xyz; + float _498 = _494.w; + float _499 = _489.w; + float4 _516 = View.View_TranslatedWorldToClip * float4(temp_var_hullMainRetVal[1u].WorldPosition[0].xyz, 1.0); + float3 _517 = _516.xyz; + float _519 = _516.w; + float4 _537 = View.View_TranslatedWorldToClip * float4(temp_var_hullMainRetVal[2u].WorldPosition[0].xyz, 1.0); + float3 _538 = _537.xyz; + float _540 = _537.w; + if (any((((select(int3(0), int3(1), (_495 - _496) < float3(_498 + _499)) + (int3(2) * select(int3(0), int3(1), (_495 + _496) > float3((-_498) - _499)))) | (select(int3(0), int3(1), (_517 - _496) < float3(_519 + _499)) + (int3(2) * select(int3(0), int3(1), (_517 + _496) > float3((-_519) - _499))))) | (select(int3(0), int3(1), (_538 - _496) < float3(_540 + _499)) + (int3(2) * select(int3(0), int3(1), (_538 + _496) > float3((-_540) - _499))))) != int3(3))) + { + _589 = float4(0.0); + break; + } + float3 _558 = temp_var_hullMainRetVal[0u].WorldPosition[0].xyz - temp_var_hullMainRetVal[1u].WorldPosition[0].xyz; + float3 _559 = temp_var_hullMainRetVal[1u].WorldPosition[0].xyz - temp_var_hullMainRetVal[2u].WorldPosition[0].xyz; + float3 _560 = temp_var_hullMainRetVal[2u].WorldPosition[0].xyz - temp_var_hullMainRetVal[0u].WorldPosition[0].xyz; + float3 _563 = (float3(0.5) * (temp_var_hullMainRetVal[0u].WorldPosition[0].xyz + temp_var_hullMainRetVal[1u].WorldPosition[0].xyz)) - float3(View.View_TranslatedWorldCameraOrigin); + float3 _566 = (float3(0.5) * (temp_var_hullMainRetVal[1u].WorldPosition[0].xyz + temp_var_hullMainRetVal[2u].WorldPosition[0].xyz)) - float3(View.View_TranslatedWorldCameraOrigin); + float3 _569 = (float3(0.5) * (temp_var_hullMainRetVal[2u].WorldPosition[0].xyz + temp_var_hullMainRetVal[0u].WorldPosition[0].xyz)) - float3(View.View_TranslatedWorldCameraOrigin); + float _573 = sqrt(dot(_559, _559) / dot(_566, _566)); + float _577 = sqrt(dot(_560, _560) / dot(_569, _569)); + float _581 = sqrt(dot(_558, _558) / dot(_563, _563)); + float4 _586 = float4(_573, _577, _581, 1.0); + _586.w = 0.333000004291534423828125 * ((_573 + _577) + _581); + _589 = float4(View.View_AdaptiveTessellationFactor) * _586; + break; + } + float4 _591 = fast::clamp(_481 * _589, float4(1.0), float4(15.0)); + spvTessLevel[gl_PrimitiveID].edgeTessellationFactor[0u] = half(_591.x); + spvTessLevel[gl_PrimitiveID].edgeTessellationFactor[1u] = half(_591.y); + spvTessLevel[gl_PrimitiveID].edgeTessellationFactor[2u] = half(_591.z); + spvTessLevel[gl_PrimitiveID].insideTessellationFactor = half(_591.w); + patchOut.out_var_PN_POSITION9 = _450 + ((_450 - (((temp_var_hullMainRetVal[2u].WorldPosition[0] + temp_var_hullMainRetVal[1u].WorldPosition[0]) + temp_var_hullMainRetVal[0u].WorldPosition[0]) * float4(0.3333333432674407958984375))) * float4(0.5)); + } +} + diff --git a/third_party/spirv-cross/reference/shaders-ue4/asm/tesc/hs-input-array-access.asm.tesc b/third_party/spirv-cross/reference/shaders-ue4/asm/tesc/hs-input-array-access.asm.tesc new file mode 100644 index 0000000000..2ec930609f --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-ue4/asm/tesc/hs-input-array-access.asm.tesc @@ -0,0 +1,467 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + +#include +#include + +using namespace metal; + +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +struct FVertexFactoryInterpolantsVSToPS +{ + float4 TangentToWorld0; + float4 TangentToWorld2; +}; + +struct FVertexFactoryInterpolantsVSToDS +{ + FVertexFactoryInterpolantsVSToPS InterpolantsVSToPS; +}; + +struct FHitProxyVSToDS +{ + FVertexFactoryInterpolantsVSToDS FactoryInterpolants; + float4 Position; + uint VertexID; +}; + +struct FHullShaderConstantDominantVertexData +{ + float2 UV; + float4 Normal; + float3 Tangent; +}; + +struct FHullShaderConstantDominantEdgeData +{ + float2 UV0; + float2 UV1; + float4 Normal0; + float4 Normal1; + float3 Tangent0; + float3 Tangent1; +}; + +struct FPNTessellationHSToDS +{ + FHitProxyVSToDS PassSpecificData; + spvUnsafeArray WorldPosition; + float3 DisplacementScale; + float TessellationMultiplier; + float WorldDisplacementMultiplier; + FHullShaderConstantDominantVertexData DominantVertex; + FHullShaderConstantDominantEdgeData DominantEdge; +}; + +struct type_View +{ + float4x4 View_TranslatedWorldToClip; + float4x4 View_WorldToClip; + float4x4 View_ClipToWorld; + float4x4 View_TranslatedWorldToView; + float4x4 View_ViewToTranslatedWorld; + float4x4 View_TranslatedWorldToCameraView; + float4x4 View_CameraViewToTranslatedWorld; + float4x4 View_ViewToClip; + float4x4 View_ViewToClipNoAA; + float4x4 View_ClipToView; + float4x4 View_ClipToTranslatedWorld; + float4x4 View_SVPositionToTranslatedWorld; + float4x4 View_ScreenToWorld; + float4x4 View_ScreenToTranslatedWorld; + packed_float3 View_ViewForward; + float PrePadding_View_908; + packed_float3 View_ViewUp; + float PrePadding_View_924; + packed_float3 View_ViewRight; + float PrePadding_View_940; + packed_float3 View_HMDViewNoRollUp; + float PrePadding_View_956; + packed_float3 View_HMDViewNoRollRight; + float PrePadding_View_972; + float4 View_InvDeviceZToWorldZTransform; + float4 View_ScreenPositionScaleBias; + packed_float3 View_WorldCameraOrigin; + float PrePadding_View_1020; + packed_float3 View_TranslatedWorldCameraOrigin; + float PrePadding_View_1036; + packed_float3 View_WorldViewOrigin; + float PrePadding_View_1052; + packed_float3 View_PreViewTranslation; + float PrePadding_View_1068; + float4x4 View_PrevProjection; + float4x4 View_PrevViewProj; + float4x4 View_PrevViewRotationProj; + float4x4 View_PrevViewToClip; + float4x4 View_PrevClipToView; + float4x4 View_PrevTranslatedWorldToClip; + float4x4 View_PrevTranslatedWorldToView; + float4x4 View_PrevViewToTranslatedWorld; + float4x4 View_PrevTranslatedWorldToCameraView; + float4x4 View_PrevCameraViewToTranslatedWorld; + packed_float3 View_PrevWorldCameraOrigin; + float PrePadding_View_1724; + packed_float3 View_PrevWorldViewOrigin; + float PrePadding_View_1740; + packed_float3 View_PrevPreViewTranslation; + float PrePadding_View_1756; + float4x4 View_PrevInvViewProj; + float4x4 View_PrevScreenToTranslatedWorld; + float4x4 View_ClipToPrevClip; + float4 View_TemporalAAJitter; + float4 View_GlobalClippingPlane; + float2 View_FieldOfViewWideAngles; + float2 View_PrevFieldOfViewWideAngles; + float4 View_ViewRectMin; + float4 View_ViewSizeAndInvSize; + float4 View_BufferSizeAndInvSize; + float4 View_BufferBilinearUVMinMax; + int View_NumSceneColorMSAASamples; + float View_PreExposure; + float View_OneOverPreExposure; + float PrePadding_View_2076; + float4 View_DiffuseOverrideParameter; + float4 View_SpecularOverrideParameter; + float4 View_NormalOverrideParameter; + float2 View_RoughnessOverrideParameter; + float View_PrevFrameGameTime; + float View_PrevFrameRealTime; + float View_OutOfBoundsMask; + float PrePadding_View_2148; + float PrePadding_View_2152; + float PrePadding_View_2156; + packed_float3 View_WorldCameraMovementSinceLastFrame; + float View_CullingSign; + float View_NearPlane; + float View_AdaptiveTessellationFactor; + float View_GameTime; + float View_RealTime; + float View_DeltaTime; + float View_MaterialTextureMipBias; + float View_MaterialTextureDerivativeMultiply; + uint View_Random; + uint View_FrameNumber; + uint View_StateFrameIndexMod8; + uint View_StateFrameIndex; + float View_CameraCut; + float View_UnlitViewmodeMask; + float PrePadding_View_2228; + float PrePadding_View_2232; + float PrePadding_View_2236; + float4 View_DirectionalLightColor; + packed_float3 View_DirectionalLightDirection; + float PrePadding_View_2268; + float4 View_TranslucencyLightingVolumeMin[2]; + float4 View_TranslucencyLightingVolumeInvSize[2]; + float4 View_TemporalAAParams; + float4 View_CircleDOFParams; + float View_DepthOfFieldSensorWidth; + float View_DepthOfFieldFocalDistance; + float View_DepthOfFieldScale; + float View_DepthOfFieldFocalLength; + float View_DepthOfFieldFocalRegion; + float View_DepthOfFieldNearTransitionRegion; + float View_DepthOfFieldFarTransitionRegion; + float View_MotionBlurNormalizedToPixel; + float View_bSubsurfacePostprocessEnabled; + float View_GeneralPurposeTweak; + float View_DemosaicVposOffset; + float PrePadding_View_2412; + packed_float3 View_IndirectLightingColorScale; + float View_HDR32bppEncodingMode; + packed_float3 View_AtmosphericFogSunDirection; + float View_AtmosphericFogSunPower; + float View_AtmosphericFogPower; + float View_AtmosphericFogDensityScale; + float View_AtmosphericFogDensityOffset; + float View_AtmosphericFogGroundOffset; + float View_AtmosphericFogDistanceScale; + float View_AtmosphericFogAltitudeScale; + float View_AtmosphericFogHeightScaleRayleigh; + float View_AtmosphericFogStartDistance; + float View_AtmosphericFogDistanceOffset; + float View_AtmosphericFogSunDiscScale; + float View_AtmosphericFogSunDiscHalfApexAngleRadian; + float PrePadding_View_2492; + float4 View_AtmosphericFogSunDiscLuminance; + uint View_AtmosphericFogRenderMask; + uint View_AtmosphericFogInscatterAltitudeSampleNum; + uint PrePadding_View_2520; + uint PrePadding_View_2524; + float4 View_AtmosphericFogSunColor; + packed_float3 View_NormalCurvatureToRoughnessScaleBias; + float View_RenderingReflectionCaptureMask; + float4 View_AmbientCubemapTint; + float View_AmbientCubemapIntensity; + float View_SkyLightParameters; + float PrePadding_View_2584; + float PrePadding_View_2588; + float4 View_SkyLightColor; + float4 View_SkyIrradianceEnvironmentMap[7]; + float View_MobilePreviewMode; + float View_HMDEyePaddingOffset; + float View_ReflectionCubemapMaxMip; + float View_ShowDecalsMask; + uint View_DistanceFieldAOSpecularOcclusionMode; + float View_IndirectCapsuleSelfShadowingIntensity; + float PrePadding_View_2744; + float PrePadding_View_2748; + packed_float3 View_ReflectionEnvironmentRoughnessMixingScaleBiasAndLargestWeight; + int View_StereoPassIndex; + float4 View_GlobalVolumeCenterAndExtent[4]; + float4 View_GlobalVolumeWorldToUVAddAndMul[4]; + float View_GlobalVolumeDimension; + float View_GlobalVolumeTexelSize; + float View_MaxGlobalDistance; + float PrePadding_View_2908; + int2 View_CursorPosition; + float View_bCheckerboardSubsurfaceProfileRendering; + float PrePadding_View_2924; + packed_float3 View_VolumetricFogInvGridSize; + float PrePadding_View_2940; + packed_float3 View_VolumetricFogGridZParams; + float PrePadding_View_2956; + float2 View_VolumetricFogSVPosToVolumeUV; + float View_VolumetricFogMaxDistance; + float PrePadding_View_2972; + packed_float3 View_VolumetricLightmapWorldToUVScale; + float PrePadding_View_2988; + packed_float3 View_VolumetricLightmapWorldToUVAdd; + float PrePadding_View_3004; + packed_float3 View_VolumetricLightmapIndirectionTextureSize; + float View_VolumetricLightmapBrickSize; + packed_float3 View_VolumetricLightmapBrickTexelSize; + float View_StereoIPD; + float View_IndirectLightingCacheShowFlag; + float View_EyeToPixelSpreadAngle; +}; + +struct type_Primitive +{ + float4x4 Primitive_LocalToWorld; + float4 Primitive_InvNonUniformScaleAndDeterminantSign; + float4 Primitive_ObjectWorldPositionAndRadius; + float4x4 Primitive_WorldToLocal; + float4x4 Primitive_PreviousLocalToWorld; + float4x4 Primitive_PreviousWorldToLocal; + packed_float3 Primitive_ActorWorldPosition; + float Primitive_UseSingleSampleShadowFromStationaryLights; + packed_float3 Primitive_ObjectBounds; + float Primitive_LpvBiasMultiplier; + float Primitive_DecalReceiverMask; + float Primitive_PerObjectGBufferData; + float Primitive_UseVolumetricLightmapShadowFromStationaryLights; + float Primitive_DrawsVelocity; + float4 Primitive_ObjectOrientation; + float4 Primitive_NonUniformScale; + packed_float3 Primitive_LocalObjectBoundsMin; + uint Primitive_LightingChannelMask; + packed_float3 Primitive_LocalObjectBoundsMax; + uint Primitive_LightmapDataIndex; + packed_float3 Primitive_PreSkinnedLocalBounds; + int Primitive_SingleCaptureIndex; + uint Primitive_OutputVelocity; + uint PrePadding_Primitive_420; + uint PrePadding_Primitive_424; + uint PrePadding_Primitive_428; + float4 Primitive_CustomPrimitiveData[4]; +}; + +constant float4 _140 = {}; + +struct main0_out +{ + float3 out_var_PN_DisplacementScales; + float2 out_var_PN_DominantEdge; + float2 out_var_PN_DominantEdge1; + float4 out_var_PN_DominantEdge2; + float4 out_var_PN_DominantEdge3; + float3 out_var_PN_DominantEdge4; + float3 out_var_PN_DominantEdge5; + float2 out_var_PN_DominantVertex; + float4 out_var_PN_DominantVertex1; + float3 out_var_PN_DominantVertex2; + spvUnsafeArray out_var_PN_POSITION; + float out_var_PN_TessellationMultiplier; + float out_var_PN_WorldDisplacementMultiplier; + float4 out_var_TEXCOORD10_centroid; + float4 out_var_TEXCOORD11_centroid; + float4 out_var_VS_To_DS_Position; + uint out_var_VS_To_DS_VertexID; +}; + +struct main0_patchOut +{ + float4 out_var_PN_POSITION9; +}; + +struct main0_in +{ + float4 in_var_TEXCOORD10_centroid [[attribute(0)]]; + float4 in_var_TEXCOORD11_centroid [[attribute(1)]]; + float4 in_var_VS_To_DS_Position [[attribute(2)]]; + uint in_var_VS_To_DS_VertexID [[attribute(3)]]; +}; + +kernel void main0(main0_in in [[stage_in]], constant type_View& View [[buffer(0)]], constant type_Primitive& Primitive [[buffer(1)]], uint gl_InvocationID [[thread_index_in_threadgroup]], uint gl_PrimitiveID [[threadgroup_position_in_grid]], device main0_out* spvOut [[buffer(28)]], constant uint* spvIndirectParams [[buffer(29)]], device main0_patchOut* spvPatchOut [[buffer(27)]], device MTLTriangleTessellationFactorsHalf* spvTessLevel [[buffer(26)]], threadgroup main0_in* gl_in [[threadgroup(0)]]) +{ + threadgroup FPNTessellationHSToDS temp_var_hullMainRetVal[3]; + device main0_out* gl_out = &spvOut[gl_PrimitiveID * 3]; + device main0_patchOut& patchOut = spvPatchOut[gl_PrimitiveID]; + if (gl_InvocationID < spvIndirectParams[0]) + gl_in[gl_InvocationID] = in; + threadgroup_barrier(mem_flags::mem_threadgroup); + if (gl_InvocationID >= 3) + return; + spvUnsafeArray _142 = spvUnsafeArray({ gl_in[0].in_var_TEXCOORD10_centroid, gl_in[1].in_var_TEXCOORD10_centroid, gl_in[2].in_var_TEXCOORD10_centroid, gl_in[3].in_var_TEXCOORD10_centroid, gl_in[4].in_var_TEXCOORD10_centroid, gl_in[5].in_var_TEXCOORD10_centroid, gl_in[6].in_var_TEXCOORD10_centroid, gl_in[7].in_var_TEXCOORD10_centroid, gl_in[8].in_var_TEXCOORD10_centroid, gl_in[9].in_var_TEXCOORD10_centroid, gl_in[10].in_var_TEXCOORD10_centroid, gl_in[11].in_var_TEXCOORD10_centroid }); + spvUnsafeArray _143 = spvUnsafeArray({ gl_in[0].in_var_TEXCOORD11_centroid, gl_in[1].in_var_TEXCOORD11_centroid, gl_in[2].in_var_TEXCOORD11_centroid, gl_in[3].in_var_TEXCOORD11_centroid, gl_in[4].in_var_TEXCOORD11_centroid, gl_in[5].in_var_TEXCOORD11_centroid, gl_in[6].in_var_TEXCOORD11_centroid, gl_in[7].in_var_TEXCOORD11_centroid, gl_in[8].in_var_TEXCOORD11_centroid, gl_in[9].in_var_TEXCOORD11_centroid, gl_in[10].in_var_TEXCOORD11_centroid, gl_in[11].in_var_TEXCOORD11_centroid }); + spvUnsafeArray _192 = spvUnsafeArray({ gl_in[0].in_var_VS_To_DS_Position, gl_in[1].in_var_VS_To_DS_Position, gl_in[2].in_var_VS_To_DS_Position, gl_in[3].in_var_VS_To_DS_Position, gl_in[4].in_var_VS_To_DS_Position, gl_in[5].in_var_VS_To_DS_Position, gl_in[6].in_var_VS_To_DS_Position, gl_in[7].in_var_VS_To_DS_Position, gl_in[8].in_var_VS_To_DS_Position, gl_in[9].in_var_VS_To_DS_Position, gl_in[10].in_var_VS_To_DS_Position, gl_in[11].in_var_VS_To_DS_Position }); + spvUnsafeArray _193 = spvUnsafeArray({ gl_in[0].in_var_VS_To_DS_VertexID, gl_in[1].in_var_VS_To_DS_VertexID, gl_in[2].in_var_VS_To_DS_VertexID, gl_in[3].in_var_VS_To_DS_VertexID, gl_in[4].in_var_VS_To_DS_VertexID, gl_in[5].in_var_VS_To_DS_VertexID, gl_in[6].in_var_VS_To_DS_VertexID, gl_in[7].in_var_VS_To_DS_VertexID, gl_in[8].in_var_VS_To_DS_VertexID, gl_in[9].in_var_VS_To_DS_VertexID, gl_in[10].in_var_VS_To_DS_VertexID, gl_in[11].in_var_VS_To_DS_VertexID }); + spvUnsafeArray _230 = spvUnsafeArray({ FHitProxyVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _142[0], _143[0] } }, _192[0], _193[0] }, FHitProxyVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _142[1], _143[1] } }, _192[1], _193[1] }, FHitProxyVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _142[2], _143[2] } }, _192[2], _193[2] }, FHitProxyVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _142[3], _143[3] } }, _192[3], _193[3] }, FHitProxyVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _142[4], _143[4] } }, _192[4], _193[4] }, FHitProxyVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _142[5], _143[5] } }, _192[5], _193[5] }, FHitProxyVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _142[6], _143[6] } }, _192[6], _193[6] }, FHitProxyVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _142[7], _143[7] } }, _192[7], _193[7] }, FHitProxyVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _142[8], _143[8] } }, _192[8], _193[8] }, FHitProxyVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _142[9], _143[9] } }, _192[9], _193[9] }, FHitProxyVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _142[10], _143[10] } }, _192[10], _193[10] }, FHitProxyVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _142[11], _143[11] } }, _192[11], _193[11] } }); + spvUnsafeArray param_var_I; + param_var_I = _230; + float4 _247 = float4(param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld2.xyz, 0.0); + float3 _251 = Primitive.Primitive_NonUniformScale.xyz * float3x3(param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld0.xyz, cross(param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld2.xyz, param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld0.xyz) * float3(param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld2.w), param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld2.xyz); + uint _254 = (gl_InvocationID < 2u) ? (gl_InvocationID + 1u) : 0u; + uint _255 = 2u * gl_InvocationID; + uint _256 = 3u + _255; + uint _257 = _255 + 4u; + uint _264 = (_254 < 2u) ? (_254 + 1u) : 0u; + uint _265 = 2u * _254; + uint _266 = 3u + _265; + uint _267 = _265 + 4u; + float4 _279 = float4(param_var_I[9u + gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld2.xyz, 0.0); + float4 _315; + float4 _316; + float4 _317; + float4 _318; + if ((param_var_I[_266].VertexID < param_var_I[_254].VertexID) || ((param_var_I[_266].VertexID == param_var_I[_254].VertexID) && (param_var_I[_267].VertexID < param_var_I[_264].VertexID))) + { + _315 = param_var_I[_267].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld0; + _316 = param_var_I[_267].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld2; + _317 = param_var_I[_266].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld0; + _318 = param_var_I[_266].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld2; + } + else + { + _315 = param_var_I[_264].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld0; + _316 = param_var_I[_264].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld2; + _317 = param_var_I[_254].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld0; + _318 = param_var_I[_254].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld2; + } + float4 _324 = float4(_318.xyz, 0.0); + float4 _328 = float4(_316.xyz, 0.0); + float4 _336 = float4(param_var_I[_254].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld2.xyz, 0.0); + float4 _344 = float4(param_var_I[_256].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld2.xyz, 0.0); + float4 _352 = float4(param_var_I[_257].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld2.xyz, 0.0); + spvUnsafeArray _402 = spvUnsafeArray({ param_var_I[gl_InvocationID].Position, (((((float4(2.0) * param_var_I[gl_InvocationID].Position) + param_var_I[_254].Position) - (float4(dot(param_var_I[_254].Position - param_var_I[gl_InvocationID].Position, _247)) * _247)) * float4(0.3333333432674407958984375)) + ((((float4(2.0) * param_var_I[_256].Position) + param_var_I[_257].Position) - (float4(dot(param_var_I[_257].Position - param_var_I[_256].Position, _344)) * _344)) * float4(0.3333333432674407958984375))) * float4(0.5), (((((float4(2.0) * param_var_I[_254].Position) + param_var_I[gl_InvocationID].Position) - (float4(dot(param_var_I[gl_InvocationID].Position - param_var_I[_254].Position, _336)) * _336)) * float4(0.3333333432674407958984375)) + ((((float4(2.0) * param_var_I[_257].Position) + param_var_I[_256].Position) - (float4(dot(param_var_I[_256].Position - param_var_I[_257].Position, _352)) * _352)) * float4(0.3333333432674407958984375))) * float4(0.5) }); + gl_out[gl_InvocationID].out_var_TEXCOORD10_centroid = param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld0; + gl_out[gl_InvocationID].out_var_TEXCOORD11_centroid = param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld2; + gl_out[gl_InvocationID].out_var_VS_To_DS_Position = param_var_I[gl_InvocationID].Position; + gl_out[gl_InvocationID].out_var_VS_To_DS_VertexID = param_var_I[gl_InvocationID].VertexID; + gl_out[gl_InvocationID].out_var_PN_POSITION = _402; + gl_out[gl_InvocationID].out_var_PN_DisplacementScales = _251; + gl_out[gl_InvocationID].out_var_PN_TessellationMultiplier = 1.0; + gl_out[gl_InvocationID].out_var_PN_WorldDisplacementMultiplier = 1.0; + gl_out[gl_InvocationID].out_var_PN_DominantVertex = float2(0.0); + gl_out[gl_InvocationID].out_var_PN_DominantVertex1 = _279; + gl_out[gl_InvocationID].out_var_PN_DominantVertex2 = param_var_I[9u + gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld0.xyz; + gl_out[gl_InvocationID].out_var_PN_DominantEdge = float2(0.0); + gl_out[gl_InvocationID].out_var_PN_DominantEdge1 = float2(0.0); + gl_out[gl_InvocationID].out_var_PN_DominantEdge2 = _324; + gl_out[gl_InvocationID].out_var_PN_DominantEdge3 = _328; + gl_out[gl_InvocationID].out_var_PN_DominantEdge4 = _317.xyz; + gl_out[gl_InvocationID].out_var_PN_DominantEdge5 = _315.xyz; + temp_var_hullMainRetVal[gl_InvocationID] = FPNTessellationHSToDS{ param_var_I[gl_InvocationID], _402, _251, 1.0, 1.0, FHullShaderConstantDominantVertexData{ float2(0.0), _279, param_var_I[9u + gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld0.xyz }, FHullShaderConstantDominantEdgeData{ float2(0.0), float2(0.0), _324, _328, _317.xyz, _315.xyz } }; + threadgroup_barrier(mem_flags::mem_device | mem_flags::mem_threadgroup); + if (gl_InvocationID == 0u) + { + float4 _461 = (((((temp_var_hullMainRetVal[0u].WorldPosition[1] + temp_var_hullMainRetVal[0u].WorldPosition[2]) + temp_var_hullMainRetVal[1u].WorldPosition[1]) + temp_var_hullMainRetVal[1u].WorldPosition[2]) + temp_var_hullMainRetVal[2u].WorldPosition[1]) + temp_var_hullMainRetVal[2u].WorldPosition[2]) * float4(0.16666667163372039794921875); + float4 _474 = _140; + _474.x = 0.5 * (temp_var_hullMainRetVal[1u].TessellationMultiplier + temp_var_hullMainRetVal[2u].TessellationMultiplier); + float4 _480 = _474; + _480.y = 0.5 * (temp_var_hullMainRetVal[2u].TessellationMultiplier + temp_var_hullMainRetVal[0u].TessellationMultiplier); + float4 _485 = _480; + _485.z = 0.5 * (temp_var_hullMainRetVal[0u].TessellationMultiplier + temp_var_hullMainRetVal[1u].TessellationMultiplier); + float4 _492 = _485; + _492.w = 0.333000004291534423828125 * ((temp_var_hullMainRetVal[0u].TessellationMultiplier + temp_var_hullMainRetVal[1u].TessellationMultiplier) + temp_var_hullMainRetVal[2u].TessellationMultiplier); + float4 _600; + for (;;) + { + float4 _500 = View.View_ViewToClip * float4(0.0); + float4 _505 = View.View_TranslatedWorldToClip * float4(temp_var_hullMainRetVal[0u].WorldPosition[0].xyz, 1.0); + float3 _506 = _505.xyz; + float3 _507 = _500.xyz; + float _509 = _505.w; + float _510 = _500.w; + float4 _527 = View.View_TranslatedWorldToClip * float4(temp_var_hullMainRetVal[1u].WorldPosition[0].xyz, 1.0); + float3 _528 = _527.xyz; + float _530 = _527.w; + float4 _548 = View.View_TranslatedWorldToClip * float4(temp_var_hullMainRetVal[2u].WorldPosition[0].xyz, 1.0); + float3 _549 = _548.xyz; + float _551 = _548.w; + if (any((((select(int3(0), int3(1), (_506 - _507) < float3(_509 + _510)) + (int3(2) * select(int3(0), int3(1), (_506 + _507) > float3((-_509) - _510)))) | (select(int3(0), int3(1), (_528 - _507) < float3(_530 + _510)) + (int3(2) * select(int3(0), int3(1), (_528 + _507) > float3((-_530) - _510))))) | (select(int3(0), int3(1), (_549 - _507) < float3(_551 + _510)) + (int3(2) * select(int3(0), int3(1), (_549 + _507) > float3((-_551) - _510))))) != int3(3))) + { + _600 = float4(0.0); + break; + } + float3 _569 = temp_var_hullMainRetVal[0u].WorldPosition[0].xyz - temp_var_hullMainRetVal[1u].WorldPosition[0].xyz; + float3 _570 = temp_var_hullMainRetVal[1u].WorldPosition[0].xyz - temp_var_hullMainRetVal[2u].WorldPosition[0].xyz; + float3 _571 = temp_var_hullMainRetVal[2u].WorldPosition[0].xyz - temp_var_hullMainRetVal[0u].WorldPosition[0].xyz; + float3 _574 = (float3(0.5) * (temp_var_hullMainRetVal[0u].WorldPosition[0].xyz + temp_var_hullMainRetVal[1u].WorldPosition[0].xyz)) - float3(View.View_TranslatedWorldCameraOrigin); + float3 _577 = (float3(0.5) * (temp_var_hullMainRetVal[1u].WorldPosition[0].xyz + temp_var_hullMainRetVal[2u].WorldPosition[0].xyz)) - float3(View.View_TranslatedWorldCameraOrigin); + float3 _580 = (float3(0.5) * (temp_var_hullMainRetVal[2u].WorldPosition[0].xyz + temp_var_hullMainRetVal[0u].WorldPosition[0].xyz)) - float3(View.View_TranslatedWorldCameraOrigin); + float _584 = sqrt(dot(_570, _570) / dot(_577, _577)); + float _588 = sqrt(dot(_571, _571) / dot(_580, _580)); + float _592 = sqrt(dot(_569, _569) / dot(_574, _574)); + float4 _597 = float4(_584, _588, _592, 1.0); + _597.w = 0.333000004291534423828125 * ((_584 + _588) + _592); + _600 = float4(View.View_AdaptiveTessellationFactor) * _597; + break; + } + float4 _602 = fast::clamp(_492 * _600, float4(1.0), float4(15.0)); + spvTessLevel[gl_PrimitiveID].edgeTessellationFactor[0u] = half(_602.x); + spvTessLevel[gl_PrimitiveID].edgeTessellationFactor[1u] = half(_602.y); + spvTessLevel[gl_PrimitiveID].edgeTessellationFactor[2u] = half(_602.z); + spvTessLevel[gl_PrimitiveID].insideTessellationFactor = half(_602.w); + patchOut.out_var_PN_POSITION9 = _461 + ((_461 - (((temp_var_hullMainRetVal[2u].WorldPosition[0] + temp_var_hullMainRetVal[1u].WorldPosition[0]) + temp_var_hullMainRetVal[0u].WorldPosition[0]) * float4(0.3333333432674407958984375))) * float4(0.5)); + } +} + diff --git a/third_party/spirv-cross/reference/shaders-ue4/asm/tesc/hs-texcoord-array.asm.tesc b/third_party/spirv-cross/reference/shaders-ue4/asm/tesc/hs-texcoord-array.asm.tesc new file mode 100644 index 0000000000..833122cde5 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-ue4/asm/tesc/hs-texcoord-array.asm.tesc @@ -0,0 +1,411 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + +#include +#include + +using namespace metal; + +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +struct FVertexFactoryInterpolantsVSToPS +{ + float4 TangentToWorld0; + float4 TangentToWorld2; + float4 Color; + spvUnsafeArray TexCoords; +}; + +struct FVertexFactoryInterpolantsVSToDS +{ + FVertexFactoryInterpolantsVSToPS InterpolantsVSToPS; +}; + +struct FHitProxyVSToDS +{ + FVertexFactoryInterpolantsVSToDS FactoryInterpolants; + float4 Position; +}; + +struct FPNTessellationHSToDS +{ + FHitProxyVSToDS PassSpecificData; + spvUnsafeArray WorldPosition; + float3 DisplacementScale; + float TessellationMultiplier; + float WorldDisplacementMultiplier; +}; + +struct type_View +{ + float4x4 View_TranslatedWorldToClip; + float4x4 View_WorldToClip; + float4x4 View_ClipToWorld; + float4x4 View_TranslatedWorldToView; + float4x4 View_ViewToTranslatedWorld; + float4x4 View_TranslatedWorldToCameraView; + float4x4 View_CameraViewToTranslatedWorld; + float4x4 View_ViewToClip; + float4x4 View_ViewToClipNoAA; + float4x4 View_ClipToView; + float4x4 View_ClipToTranslatedWorld; + float4x4 View_SVPositionToTranslatedWorld; + float4x4 View_ScreenToWorld; + float4x4 View_ScreenToTranslatedWorld; + packed_float3 View_ViewForward; + float PrePadding_View_908; + packed_float3 View_ViewUp; + float PrePadding_View_924; + packed_float3 View_ViewRight; + float PrePadding_View_940; + packed_float3 View_HMDViewNoRollUp; + float PrePadding_View_956; + packed_float3 View_HMDViewNoRollRight; + float PrePadding_View_972; + float4 View_InvDeviceZToWorldZTransform; + float4 View_ScreenPositionScaleBias; + packed_float3 View_WorldCameraOrigin; + float PrePadding_View_1020; + packed_float3 View_TranslatedWorldCameraOrigin; + float PrePadding_View_1036; + packed_float3 View_WorldViewOrigin; + float PrePadding_View_1052; + packed_float3 View_PreViewTranslation; + float PrePadding_View_1068; + float4x4 View_PrevProjection; + float4x4 View_PrevViewProj; + float4x4 View_PrevViewRotationProj; + float4x4 View_PrevViewToClip; + float4x4 View_PrevClipToView; + float4x4 View_PrevTranslatedWorldToClip; + float4x4 View_PrevTranslatedWorldToView; + float4x4 View_PrevViewToTranslatedWorld; + float4x4 View_PrevTranslatedWorldToCameraView; + float4x4 View_PrevCameraViewToTranslatedWorld; + packed_float3 View_PrevWorldCameraOrigin; + float PrePadding_View_1724; + packed_float3 View_PrevWorldViewOrigin; + float PrePadding_View_1740; + packed_float3 View_PrevPreViewTranslation; + float PrePadding_View_1756; + float4x4 View_PrevInvViewProj; + float4x4 View_PrevScreenToTranslatedWorld; + float4x4 View_ClipToPrevClip; + float4 View_TemporalAAJitter; + float4 View_GlobalClippingPlane; + float2 View_FieldOfViewWideAngles; + float2 View_PrevFieldOfViewWideAngles; + float4 View_ViewRectMin; + float4 View_ViewSizeAndInvSize; + float4 View_BufferSizeAndInvSize; + float4 View_BufferBilinearUVMinMax; + int View_NumSceneColorMSAASamples; + float View_PreExposure; + float View_OneOverPreExposure; + float PrePadding_View_2076; + float4 View_DiffuseOverrideParameter; + float4 View_SpecularOverrideParameter; + float4 View_NormalOverrideParameter; + float2 View_RoughnessOverrideParameter; + float View_PrevFrameGameTime; + float View_PrevFrameRealTime; + float View_OutOfBoundsMask; + float PrePadding_View_2148; + float PrePadding_View_2152; + float PrePadding_View_2156; + packed_float3 View_WorldCameraMovementSinceLastFrame; + float View_CullingSign; + float View_NearPlane; + float View_AdaptiveTessellationFactor; + float View_GameTime; + float View_RealTime; + float View_DeltaTime; + float View_MaterialTextureMipBias; + float View_MaterialTextureDerivativeMultiply; + uint View_Random; + uint View_FrameNumber; + uint View_StateFrameIndexMod8; + uint View_StateFrameIndex; + float View_CameraCut; + float View_UnlitViewmodeMask; + float PrePadding_View_2228; + float PrePadding_View_2232; + float PrePadding_View_2236; + float4 View_DirectionalLightColor; + packed_float3 View_DirectionalLightDirection; + float PrePadding_View_2268; + float4 View_TranslucencyLightingVolumeMin[2]; + float4 View_TranslucencyLightingVolumeInvSize[2]; + float4 View_TemporalAAParams; + float4 View_CircleDOFParams; + float View_DepthOfFieldSensorWidth; + float View_DepthOfFieldFocalDistance; + float View_DepthOfFieldScale; + float View_DepthOfFieldFocalLength; + float View_DepthOfFieldFocalRegion; + float View_DepthOfFieldNearTransitionRegion; + float View_DepthOfFieldFarTransitionRegion; + float View_MotionBlurNormalizedToPixel; + float View_bSubsurfacePostprocessEnabled; + float View_GeneralPurposeTweak; + float View_DemosaicVposOffset; + float PrePadding_View_2412; + packed_float3 View_IndirectLightingColorScale; + float View_HDR32bppEncodingMode; + packed_float3 View_AtmosphericFogSunDirection; + float View_AtmosphericFogSunPower; + float View_AtmosphericFogPower; + float View_AtmosphericFogDensityScale; + float View_AtmosphericFogDensityOffset; + float View_AtmosphericFogGroundOffset; + float View_AtmosphericFogDistanceScale; + float View_AtmosphericFogAltitudeScale; + float View_AtmosphericFogHeightScaleRayleigh; + float View_AtmosphericFogStartDistance; + float View_AtmosphericFogDistanceOffset; + float View_AtmosphericFogSunDiscScale; + float View_AtmosphericFogSunDiscHalfApexAngleRadian; + float PrePadding_View_2492; + float4 View_AtmosphericFogSunDiscLuminance; + uint View_AtmosphericFogRenderMask; + uint View_AtmosphericFogInscatterAltitudeSampleNum; + uint PrePadding_View_2520; + uint PrePadding_View_2524; + float4 View_AtmosphericFogSunColor; + packed_float3 View_NormalCurvatureToRoughnessScaleBias; + float View_RenderingReflectionCaptureMask; + float4 View_AmbientCubemapTint; + float View_AmbientCubemapIntensity; + float View_SkyLightParameters; + float PrePadding_View_2584; + float PrePadding_View_2588; + float4 View_SkyLightColor; + float4 View_SkyIrradianceEnvironmentMap[7]; + float View_MobilePreviewMode; + float View_HMDEyePaddingOffset; + float View_ReflectionCubemapMaxMip; + float View_ShowDecalsMask; + uint View_DistanceFieldAOSpecularOcclusionMode; + float View_IndirectCapsuleSelfShadowingIntensity; + float PrePadding_View_2744; + float PrePadding_View_2748; + packed_float3 View_ReflectionEnvironmentRoughnessMixingScaleBiasAndLargestWeight; + int View_StereoPassIndex; + float4 View_GlobalVolumeCenterAndExtent[4]; + float4 View_GlobalVolumeWorldToUVAddAndMul[4]; + float View_GlobalVolumeDimension; + float View_GlobalVolumeTexelSize; + float View_MaxGlobalDistance; + float PrePadding_View_2908; + int2 View_CursorPosition; + float View_bCheckerboardSubsurfaceProfileRendering; + float PrePadding_View_2924; + packed_float3 View_VolumetricFogInvGridSize; + float PrePadding_View_2940; + packed_float3 View_VolumetricFogGridZParams; + float PrePadding_View_2956; + float2 View_VolumetricFogSVPosToVolumeUV; + float View_VolumetricFogMaxDistance; + float PrePadding_View_2972; + packed_float3 View_VolumetricLightmapWorldToUVScale; + float PrePadding_View_2988; + packed_float3 View_VolumetricLightmapWorldToUVAdd; + float PrePadding_View_3004; + packed_float3 View_VolumetricLightmapIndirectionTextureSize; + float View_VolumetricLightmapBrickSize; + packed_float3 View_VolumetricLightmapBrickTexelSize; + float View_StereoIPD; + float View_IndirectLightingCacheShowFlag; + float View_EyeToPixelSpreadAngle; +}; + +struct type_Primitive +{ + float4x4 Primitive_LocalToWorld; + float4 Primitive_InvNonUniformScaleAndDeterminantSign; + float4 Primitive_ObjectWorldPositionAndRadius; + float4x4 Primitive_WorldToLocal; + float4x4 Primitive_PreviousLocalToWorld; + float4x4 Primitive_PreviousWorldToLocal; + packed_float3 Primitive_ActorWorldPosition; + float Primitive_UseSingleSampleShadowFromStationaryLights; + packed_float3 Primitive_ObjectBounds; + float Primitive_LpvBiasMultiplier; + float Primitive_DecalReceiverMask; + float Primitive_PerObjectGBufferData; + float Primitive_UseVolumetricLightmapShadowFromStationaryLights; + float Primitive_DrawsVelocity; + float4 Primitive_ObjectOrientation; + float4 Primitive_NonUniformScale; + packed_float3 Primitive_LocalObjectBoundsMin; + uint Primitive_LightingChannelMask; + packed_float3 Primitive_LocalObjectBoundsMax; + uint Primitive_LightmapDataIndex; + packed_float3 Primitive_PreSkinnedLocalBounds; + int Primitive_SingleCaptureIndex; + uint Primitive_OutputVelocity; + uint PrePadding_Primitive_420; + uint PrePadding_Primitive_424; + uint PrePadding_Primitive_428; + float4 Primitive_CustomPrimitiveData[4]; +}; + +constant float4 _127 = {}; + +struct main0_out +{ + float4 out_var_COLOR0; + float3 out_var_PN_DisplacementScales; + spvUnsafeArray out_var_PN_POSITION; + float out_var_PN_TessellationMultiplier; + float out_var_PN_WorldDisplacementMultiplier; + spvUnsafeArray out_var_TEXCOORD0; + float4 out_var_TEXCOORD10_centroid; + float4 out_var_TEXCOORD11_centroid; + float4 out_var_VS_To_DS_Position; +}; + +struct main0_patchOut +{ + float4 out_var_PN_POSITION9; +}; + +struct main0_in +{ + float4 in_var_TEXCOORD10_centroid [[attribute(0)]]; + float4 in_var_TEXCOORD11_centroid [[attribute(1)]]; + float4 in_var_COLOR0 [[attribute(2)]]; + float2 in_var_TEXCOORD0_0 [[attribute(3)]]; + float2 in_var_TEXCOORD0_1 [[attribute(4)]]; + float4 in_var_VS_To_DS_Position [[attribute(5)]]; +}; + +kernel void main0(main0_in in [[stage_in]], constant type_View& View [[buffer(0)]], constant type_Primitive& Primitive [[buffer(1)]], uint gl_InvocationID [[thread_index_in_threadgroup]], uint gl_PrimitiveID [[threadgroup_position_in_grid]], device main0_out* spvOut [[buffer(28)]], constant uint* spvIndirectParams [[buffer(29)]], device main0_patchOut* spvPatchOut [[buffer(27)]], device MTLTriangleTessellationFactorsHalf* spvTessLevel [[buffer(26)]], threadgroup main0_in* gl_in [[threadgroup(0)]]) +{ + threadgroup FPNTessellationHSToDS temp_var_hullMainRetVal[3]; + device main0_out* gl_out = &spvOut[gl_PrimitiveID * 3]; + device main0_patchOut& patchOut = spvPatchOut[gl_PrimitiveID]; + if (gl_InvocationID < spvIndirectParams[0]) + gl_in[gl_InvocationID] = in; + threadgroup_barrier(mem_flags::mem_threadgroup); + if (gl_InvocationID >= 3) + return; + spvUnsafeArray _129 = spvUnsafeArray({ gl_in[0].in_var_TEXCOORD10_centroid, gl_in[1].in_var_TEXCOORD10_centroid, gl_in[2].in_var_TEXCOORD10_centroid, gl_in[3].in_var_TEXCOORD10_centroid, gl_in[4].in_var_TEXCOORD10_centroid, gl_in[5].in_var_TEXCOORD10_centroid, gl_in[6].in_var_TEXCOORD10_centroid, gl_in[7].in_var_TEXCOORD10_centroid, gl_in[8].in_var_TEXCOORD10_centroid, gl_in[9].in_var_TEXCOORD10_centroid, gl_in[10].in_var_TEXCOORD10_centroid, gl_in[11].in_var_TEXCOORD10_centroid }); + spvUnsafeArray _130 = spvUnsafeArray({ gl_in[0].in_var_TEXCOORD11_centroid, gl_in[1].in_var_TEXCOORD11_centroid, gl_in[2].in_var_TEXCOORD11_centroid, gl_in[3].in_var_TEXCOORD11_centroid, gl_in[4].in_var_TEXCOORD11_centroid, gl_in[5].in_var_TEXCOORD11_centroid, gl_in[6].in_var_TEXCOORD11_centroid, gl_in[7].in_var_TEXCOORD11_centroid, gl_in[8].in_var_TEXCOORD11_centroid, gl_in[9].in_var_TEXCOORD11_centroid, gl_in[10].in_var_TEXCOORD11_centroid, gl_in[11].in_var_TEXCOORD11_centroid }); + spvUnsafeArray _131 = spvUnsafeArray({ gl_in[0].in_var_COLOR0, gl_in[1].in_var_COLOR0, gl_in[2].in_var_COLOR0, gl_in[3].in_var_COLOR0, gl_in[4].in_var_COLOR0, gl_in[5].in_var_COLOR0, gl_in[6].in_var_COLOR0, gl_in[7].in_var_COLOR0, gl_in[8].in_var_COLOR0, gl_in[9].in_var_COLOR0, gl_in[10].in_var_COLOR0, gl_in[11].in_var_COLOR0 }); + spvUnsafeArray, 12> _132 = spvUnsafeArray, 12>({ spvUnsafeArray({ gl_in[0].in_var_TEXCOORD0_0, gl_in[0].in_var_TEXCOORD0_1 }), spvUnsafeArray({ gl_in[1].in_var_TEXCOORD0_0, gl_in[1].in_var_TEXCOORD0_1 }), spvUnsafeArray({ gl_in[2].in_var_TEXCOORD0_0, gl_in[2].in_var_TEXCOORD0_1 }), spvUnsafeArray({ gl_in[3].in_var_TEXCOORD0_0, gl_in[3].in_var_TEXCOORD0_1 }), spvUnsafeArray({ gl_in[4].in_var_TEXCOORD0_0, gl_in[4].in_var_TEXCOORD0_1 }), spvUnsafeArray({ gl_in[5].in_var_TEXCOORD0_0, gl_in[5].in_var_TEXCOORD0_1 }), spvUnsafeArray({ gl_in[6].in_var_TEXCOORD0_0, gl_in[6].in_var_TEXCOORD0_1 }), spvUnsafeArray({ gl_in[7].in_var_TEXCOORD0_0, gl_in[7].in_var_TEXCOORD0_1 }), spvUnsafeArray({ gl_in[8].in_var_TEXCOORD0_0, gl_in[8].in_var_TEXCOORD0_1 }), spvUnsafeArray({ gl_in[9].in_var_TEXCOORD0_0, gl_in[9].in_var_TEXCOORD0_1 }), spvUnsafeArray({ gl_in[10].in_var_TEXCOORD0_0, gl_in[10].in_var_TEXCOORD0_1 }), spvUnsafeArray({ gl_in[11].in_var_TEXCOORD0_0, gl_in[11].in_var_TEXCOORD0_1 }) }); + spvUnsafeArray _205 = spvUnsafeArray({ gl_in[0].in_var_VS_To_DS_Position, gl_in[1].in_var_VS_To_DS_Position, gl_in[2].in_var_VS_To_DS_Position, gl_in[3].in_var_VS_To_DS_Position, gl_in[4].in_var_VS_To_DS_Position, gl_in[5].in_var_VS_To_DS_Position, gl_in[6].in_var_VS_To_DS_Position, gl_in[7].in_var_VS_To_DS_Position, gl_in[8].in_var_VS_To_DS_Position, gl_in[9].in_var_VS_To_DS_Position, gl_in[10].in_var_VS_To_DS_Position, gl_in[11].in_var_VS_To_DS_Position }); + spvUnsafeArray _230 = spvUnsafeArray({ FHitProxyVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _129[0], _130[0], _131[0], _132[0] } }, _205[0] }, FHitProxyVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _129[1], _130[1], _131[1], _132[1] } }, _205[1] }, FHitProxyVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _129[2], _130[2], _131[2], _132[2] } }, _205[2] }, FHitProxyVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _129[3], _130[3], _131[3], _132[3] } }, _205[3] }, FHitProxyVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _129[4], _130[4], _131[4], _132[4] } }, _205[4] }, FHitProxyVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _129[5], _130[5], _131[5], _132[5] } }, _205[5] }, FHitProxyVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _129[6], _130[6], _131[6], _132[6] } }, _205[6] }, FHitProxyVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _129[7], _130[7], _131[7], _132[7] } }, _205[7] }, FHitProxyVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _129[8], _130[8], _131[8], _132[8] } }, _205[8] }, FHitProxyVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _129[9], _130[9], _131[9], _132[9] } }, _205[9] }, FHitProxyVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _129[10], _130[10], _131[10], _132[10] } }, _205[10] }, FHitProxyVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _129[11], _130[11], _131[11], _132[11] } }, _205[11] } }); + spvUnsafeArray param_var_I; + param_var_I = _230; + float4 _247 = float4(param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld2.xyz, 0.0); + float3 _251 = Primitive.Primitive_NonUniformScale.xyz * float3x3(param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld0.xyz, cross(param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld2.xyz, param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld0.xyz) * float3(param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld2.w), param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld2.xyz); + uint _254 = (gl_InvocationID < 2u) ? (gl_InvocationID + 1u) : 0u; + uint _255 = 2u * gl_InvocationID; + uint _256 = 3u + _255; + uint _257 = _255 + 4u; + float4 _269 = float4(param_var_I[_254].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld2.xyz, 0.0); + float4 _277 = float4(param_var_I[_256].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld2.xyz, 0.0); + float4 _285 = float4(param_var_I[_257].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld2.xyz, 0.0); + spvUnsafeArray _333 = spvUnsafeArray({ param_var_I[gl_InvocationID].Position, (((((float4(2.0) * param_var_I[gl_InvocationID].Position) + param_var_I[_254].Position) - (float4(dot(param_var_I[_254].Position - param_var_I[gl_InvocationID].Position, _247)) * _247)) * float4(0.3333333432674407958984375)) + ((((float4(2.0) * param_var_I[_256].Position) + param_var_I[_257].Position) - (float4(dot(param_var_I[_257].Position - param_var_I[_256].Position, _277)) * _277)) * float4(0.3333333432674407958984375))) * float4(0.5), (((((float4(2.0) * param_var_I[_254].Position) + param_var_I[gl_InvocationID].Position) - (float4(dot(param_var_I[gl_InvocationID].Position - param_var_I[_254].Position, _269)) * _269)) * float4(0.3333333432674407958984375)) + ((((float4(2.0) * param_var_I[_257].Position) + param_var_I[_256].Position) - (float4(dot(param_var_I[_256].Position - param_var_I[_257].Position, _285)) * _285)) * float4(0.3333333432674407958984375))) * float4(0.5) }); + gl_out[gl_InvocationID].out_var_TEXCOORD10_centroid = param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld0; + gl_out[gl_InvocationID].out_var_TEXCOORD11_centroid = param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld2; + gl_out[gl_InvocationID].out_var_COLOR0 = param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.Color; + gl_out[gl_InvocationID].out_var_TEXCOORD0 = param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TexCoords; + gl_out[gl_InvocationID].out_var_VS_To_DS_Position = param_var_I[gl_InvocationID].Position; + gl_out[gl_InvocationID].out_var_PN_POSITION = _333; + gl_out[gl_InvocationID].out_var_PN_DisplacementScales = _251; + gl_out[gl_InvocationID].out_var_PN_TessellationMultiplier = 1.0; + gl_out[gl_InvocationID].out_var_PN_WorldDisplacementMultiplier = 1.0; + temp_var_hullMainRetVal[gl_InvocationID] = FPNTessellationHSToDS{ param_var_I[gl_InvocationID], _333, _251, 1.0, 1.0 }; + threadgroup_barrier(mem_flags::mem_device | mem_flags::mem_threadgroup); + if (gl_InvocationID == 0u) + { + float4 _385 = (((((temp_var_hullMainRetVal[0u].WorldPosition[1] + temp_var_hullMainRetVal[0u].WorldPosition[2]) + temp_var_hullMainRetVal[1u].WorldPosition[1]) + temp_var_hullMainRetVal[1u].WorldPosition[2]) + temp_var_hullMainRetVal[2u].WorldPosition[1]) + temp_var_hullMainRetVal[2u].WorldPosition[2]) * float4(0.16666667163372039794921875); + float4 _398 = _127; + _398.x = 0.5 * (temp_var_hullMainRetVal[1u].TessellationMultiplier + temp_var_hullMainRetVal[2u].TessellationMultiplier); + float4 _404 = _398; + _404.y = 0.5 * (temp_var_hullMainRetVal[2u].TessellationMultiplier + temp_var_hullMainRetVal[0u].TessellationMultiplier); + float4 _409 = _404; + _409.z = 0.5 * (temp_var_hullMainRetVal[0u].TessellationMultiplier + temp_var_hullMainRetVal[1u].TessellationMultiplier); + float4 _416 = _409; + _416.w = 0.333000004291534423828125 * ((temp_var_hullMainRetVal[0u].TessellationMultiplier + temp_var_hullMainRetVal[1u].TessellationMultiplier) + temp_var_hullMainRetVal[2u].TessellationMultiplier); + float4 _524; + for (;;) + { + float4 _424 = View.View_ViewToClip * float4(0.0); + float4 _429 = View.View_TranslatedWorldToClip * float4(temp_var_hullMainRetVal[0u].WorldPosition[0].xyz, 1.0); + float3 _430 = _429.xyz; + float3 _431 = _424.xyz; + float _433 = _429.w; + float _434 = _424.w; + float4 _451 = View.View_TranslatedWorldToClip * float4(temp_var_hullMainRetVal[1u].WorldPosition[0].xyz, 1.0); + float3 _452 = _451.xyz; + float _454 = _451.w; + float4 _472 = View.View_TranslatedWorldToClip * float4(temp_var_hullMainRetVal[2u].WorldPosition[0].xyz, 1.0); + float3 _473 = _472.xyz; + float _475 = _472.w; + if (any((((select(int3(0), int3(1), (_430 - _431) < float3(_433 + _434)) + (int3(2) * select(int3(0), int3(1), (_430 + _431) > float3((-_433) - _434)))) | (select(int3(0), int3(1), (_452 - _431) < float3(_454 + _434)) + (int3(2) * select(int3(0), int3(1), (_452 + _431) > float3((-_454) - _434))))) | (select(int3(0), int3(1), (_473 - _431) < float3(_475 + _434)) + (int3(2) * select(int3(0), int3(1), (_473 + _431) > float3((-_475) - _434))))) != int3(3))) + { + _524 = float4(0.0); + break; + } + float3 _493 = temp_var_hullMainRetVal[0u].WorldPosition[0].xyz - temp_var_hullMainRetVal[1u].WorldPosition[0].xyz; + float3 _494 = temp_var_hullMainRetVal[1u].WorldPosition[0].xyz - temp_var_hullMainRetVal[2u].WorldPosition[0].xyz; + float3 _495 = temp_var_hullMainRetVal[2u].WorldPosition[0].xyz - temp_var_hullMainRetVal[0u].WorldPosition[0].xyz; + float3 _498 = (float3(0.5) * (temp_var_hullMainRetVal[0u].WorldPosition[0].xyz + temp_var_hullMainRetVal[1u].WorldPosition[0].xyz)) - float3(View.View_TranslatedWorldCameraOrigin); + float3 _501 = (float3(0.5) * (temp_var_hullMainRetVal[1u].WorldPosition[0].xyz + temp_var_hullMainRetVal[2u].WorldPosition[0].xyz)) - float3(View.View_TranslatedWorldCameraOrigin); + float3 _504 = (float3(0.5) * (temp_var_hullMainRetVal[2u].WorldPosition[0].xyz + temp_var_hullMainRetVal[0u].WorldPosition[0].xyz)) - float3(View.View_TranslatedWorldCameraOrigin); + float _508 = sqrt(dot(_494, _494) / dot(_501, _501)); + float _512 = sqrt(dot(_495, _495) / dot(_504, _504)); + float _516 = sqrt(dot(_493, _493) / dot(_498, _498)); + float4 _521 = float4(_508, _512, _516, 1.0); + _521.w = 0.333000004291534423828125 * ((_508 + _512) + _516); + _524 = float4(View.View_AdaptiveTessellationFactor) * _521; + break; + } + float4 _526 = fast::clamp(_416 * _524, float4(1.0), float4(15.0)); + spvTessLevel[gl_PrimitiveID].edgeTessellationFactor[0u] = half(_526.x); + spvTessLevel[gl_PrimitiveID].edgeTessellationFactor[1u] = half(_526.y); + spvTessLevel[gl_PrimitiveID].edgeTessellationFactor[2u] = half(_526.z); + spvTessLevel[gl_PrimitiveID].insideTessellationFactor = half(_526.w); + patchOut.out_var_PN_POSITION9 = _385 + ((_385 - (((temp_var_hullMainRetVal[2u].WorldPosition[0] + temp_var_hullMainRetVal[1u].WorldPosition[0]) + temp_var_hullMainRetVal[0u].WorldPosition[0]) * float4(0.3333333432674407958984375))) * float4(0.5)); + } +} + diff --git a/third_party/spirv-cross/reference/shaders-ue4/asm/tesc/tess-factor-must-be-threadgroup.asm.tesc b/third_party/spirv-cross/reference/shaders-ue4/asm/tesc/tess-factor-must-be-threadgroup.asm.tesc new file mode 100644 index 0000000000..04f5a1d384 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-ue4/asm/tesc/tess-factor-must-be-threadgroup.asm.tesc @@ -0,0 +1,178 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + +#include +#include + +using namespace metal; + +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +struct FVertexFactoryInterpolantsVSToPS +{ + float4 TangentToWorld0; + float4 TangentToWorld2; +}; + +struct FVertexFactoryInterpolantsVSToDS +{ + FVertexFactoryInterpolantsVSToPS InterpolantsVSToPS; +}; + +struct FSharedBasePassInterpolants +{ +}; +struct FBasePassInterpolantsVSToDS +{ + FSharedBasePassInterpolants _m0; +}; + +struct FBasePassVSToDS +{ + FVertexFactoryInterpolantsVSToDS FactoryInterpolants; + FBasePassInterpolantsVSToDS BasePassInterpolants; + float4 Position; +}; + +struct FFlatTessellationHSToDS +{ + FBasePassVSToDS PassSpecificData; + float3 DisplacementScale; + float TessellationMultiplier; + float WorldDisplacementMultiplier; +}; + +struct type_Primitive +{ + float4x4 Primitive_LocalToWorld; + float4 Primitive_InvNonUniformScaleAndDeterminantSign; + float4 Primitive_ObjectWorldPositionAndRadius; + float4x4 Primitive_WorldToLocal; + float4x4 Primitive_PreviousLocalToWorld; + float4x4 Primitive_PreviousWorldToLocal; + packed_float3 Primitive_ActorWorldPosition; + float Primitive_UseSingleSampleShadowFromStationaryLights; + packed_float3 Primitive_ObjectBounds; + float Primitive_LpvBiasMultiplier; + float Primitive_DecalReceiverMask; + float Primitive_PerObjectGBufferData; + float Primitive_UseVolumetricLightmapShadowFromStationaryLights; + float Primitive_DrawsVelocity; + float4 Primitive_ObjectOrientation; + float4 Primitive_NonUniformScale; + packed_float3 Primitive_LocalObjectBoundsMin; + uint Primitive_LightingChannelMask; + packed_float3 Primitive_LocalObjectBoundsMax; + uint Primitive_LightmapDataIndex; + packed_float3 Primitive_PreSkinnedLocalBounds; + int Primitive_SingleCaptureIndex; + uint Primitive_OutputVelocity; + uint PrePadding_Primitive_420; + uint PrePadding_Primitive_424; + uint PrePadding_Primitive_428; + float4 Primitive_CustomPrimitiveData[4]; +}; + +struct type_Material +{ + float4 Material_VectorExpressions[3]; + float4 Material_ScalarExpressions[1]; +}; + +constant float4 _88 = {}; + +struct main0_out +{ + float3 out_var_Flat_DisplacementScales; + float out_var_Flat_TessellationMultiplier; + float out_var_Flat_WorldDisplacementMultiplier; + float4 out_var_TEXCOORD10_centroid; + float4 out_var_TEXCOORD11_centroid; + float4 out_var_VS_To_DS_Position; +}; + +struct main0_in +{ + float4 in_var_TEXCOORD10_centroid [[attribute(0)]]; + float4 in_var_TEXCOORD11_centroid [[attribute(1)]]; + float4 in_var_VS_To_DS_Position [[attribute(2)]]; +}; + +kernel void main0(main0_in in [[stage_in]], constant type_Primitive& Primitive [[buffer(0)]], constant type_Material& Material [[buffer(1)]], uint gl_InvocationID [[thread_index_in_threadgroup]], uint gl_PrimitiveID [[threadgroup_position_in_grid]], device main0_out* spvOut [[buffer(28)]], constant uint* spvIndirectParams [[buffer(29)]], device MTLTriangleTessellationFactorsHalf* spvTessLevel [[buffer(26)]], threadgroup main0_in* gl_in [[threadgroup(0)]]) +{ + threadgroup FFlatTessellationHSToDS temp_var_hullMainRetVal[3]; + device main0_out* gl_out = &spvOut[gl_PrimitiveID * 3]; + if (gl_InvocationID < spvIndirectParams[0]) + gl_in[gl_InvocationID] = in; + threadgroup_barrier(mem_flags::mem_threadgroup); + if (gl_InvocationID >= 3) + return; + spvUnsafeArray _90 = spvUnsafeArray({ gl_in[0].in_var_TEXCOORD10_centroid, gl_in[1].in_var_TEXCOORD10_centroid, gl_in[2].in_var_TEXCOORD10_centroid }); + spvUnsafeArray _91 = spvUnsafeArray({ gl_in[0].in_var_TEXCOORD11_centroid, gl_in[1].in_var_TEXCOORD11_centroid, gl_in[2].in_var_TEXCOORD11_centroid }); + spvUnsafeArray _104 = spvUnsafeArray({ gl_in[0].in_var_VS_To_DS_Position, gl_in[1].in_var_VS_To_DS_Position, gl_in[2].in_var_VS_To_DS_Position }); + spvUnsafeArray _111 = spvUnsafeArray({ FBasePassVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _90[0], _91[0] } }, FBasePassInterpolantsVSToDS{ { } }, _104[0] }, FBasePassVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _90[1], _91[1] } }, FBasePassInterpolantsVSToDS{ { } }, _104[1] }, FBasePassVSToDS{ FVertexFactoryInterpolantsVSToDS{ FVertexFactoryInterpolantsVSToPS{ _90[2], _91[2] } }, FBasePassInterpolantsVSToDS{ { } }, _104[2] } }); + spvUnsafeArray param_var_I; + param_var_I = _111; + float3 _128 = Primitive.Primitive_NonUniformScale.xyz * float3x3(param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld0.xyz, cross(param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld2.xyz, param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld0.xyz) * float3(param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld2.w), param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld2.xyz); + gl_out[gl_InvocationID].out_var_TEXCOORD10_centroid = param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld0; + gl_out[gl_InvocationID].out_var_TEXCOORD11_centroid = param_var_I[gl_InvocationID].FactoryInterpolants.InterpolantsVSToPS.TangentToWorld2; + gl_out[gl_InvocationID].out_var_VS_To_DS_Position = param_var_I[gl_InvocationID].Position; + gl_out[gl_InvocationID].out_var_Flat_DisplacementScales = _128; + gl_out[gl_InvocationID].out_var_Flat_TessellationMultiplier = Material.Material_ScalarExpressions[0].x; + gl_out[gl_InvocationID].out_var_Flat_WorldDisplacementMultiplier = 1.0; + temp_var_hullMainRetVal[gl_InvocationID] = FFlatTessellationHSToDS{ param_var_I[gl_InvocationID], _128, Material.Material_ScalarExpressions[0].x, 1.0 }; + threadgroup_barrier(mem_flags::mem_device | mem_flags::mem_threadgroup); + if (gl_InvocationID == 0u) + { + float4 _154 = _88; + _154.x = 0.5 * (temp_var_hullMainRetVal[1u].TessellationMultiplier + temp_var_hullMainRetVal[2u].TessellationMultiplier); + float4 _160 = _154; + _160.y = 0.5 * (temp_var_hullMainRetVal[2u].TessellationMultiplier + temp_var_hullMainRetVal[0u].TessellationMultiplier); + float4 _165 = _160; + _165.z = 0.5 * (temp_var_hullMainRetVal[0u].TessellationMultiplier + temp_var_hullMainRetVal[1u].TessellationMultiplier); + float4 _172 = _165; + _172.w = 0.333000004291534423828125 * ((temp_var_hullMainRetVal[0u].TessellationMultiplier + temp_var_hullMainRetVal[1u].TessellationMultiplier) + temp_var_hullMainRetVal[2u].TessellationMultiplier); + float4 _173 = fast::clamp(_172, float4(1.0), float4(15.0)); + spvTessLevel[gl_PrimitiveID].edgeTessellationFactor[0u] = half(_173.x); + spvTessLevel[gl_PrimitiveID].edgeTessellationFactor[1u] = half(_173.y); + spvTessLevel[gl_PrimitiveID].edgeTessellationFactor[2u] = half(_173.z); + spvTessLevel[gl_PrimitiveID].insideTessellationFactor = half(_173.w); + } +} + diff --git a/third_party/spirv-cross/reference/shaders-ue4/asm/tese/ds-double-gl-in-deref.asm.tese b/third_party/spirv-cross/reference/shaders-ue4/asm/tese/ds-double-gl-in-deref.asm.tese new file mode 100644 index 0000000000..b2e5eccac2 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-ue4/asm/tese/ds-double-gl-in-deref.asm.tese @@ -0,0 +1,420 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + +#include +#include + +using namespace metal; + +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +struct type_View +{ + float4x4 View_TranslatedWorldToClip; + float4x4 View_WorldToClip; + float4x4 View_ClipToWorld; + float4x4 View_TranslatedWorldToView; + float4x4 View_ViewToTranslatedWorld; + float4x4 View_TranslatedWorldToCameraView; + float4x4 View_CameraViewToTranslatedWorld; + float4x4 View_ViewToClip; + float4x4 View_ViewToClipNoAA; + float4x4 View_ClipToView; + float4x4 View_ClipToTranslatedWorld; + float4x4 View_SVPositionToTranslatedWorld; + float4x4 View_ScreenToWorld; + float4x4 View_ScreenToTranslatedWorld; + packed_float3 View_ViewForward; + float PrePadding_View_908; + packed_float3 View_ViewUp; + float PrePadding_View_924; + packed_float3 View_ViewRight; + float PrePadding_View_940; + packed_float3 View_HMDViewNoRollUp; + float PrePadding_View_956; + packed_float3 View_HMDViewNoRollRight; + float PrePadding_View_972; + float4 View_InvDeviceZToWorldZTransform; + float4 View_ScreenPositionScaleBias; + packed_float3 View_WorldCameraOrigin; + float PrePadding_View_1020; + packed_float3 View_TranslatedWorldCameraOrigin; + float PrePadding_View_1036; + packed_float3 View_WorldViewOrigin; + float PrePadding_View_1052; + packed_float3 View_PreViewTranslation; + float PrePadding_View_1068; + float4x4 View_PrevProjection; + float4x4 View_PrevViewProj; + float4x4 View_PrevViewRotationProj; + float4x4 View_PrevViewToClip; + float4x4 View_PrevClipToView; + float4x4 View_PrevTranslatedWorldToClip; + float4x4 View_PrevTranslatedWorldToView; + float4x4 View_PrevViewToTranslatedWorld; + float4x4 View_PrevTranslatedWorldToCameraView; + float4x4 View_PrevCameraViewToTranslatedWorld; + packed_float3 View_PrevWorldCameraOrigin; + float PrePadding_View_1724; + packed_float3 View_PrevWorldViewOrigin; + float PrePadding_View_1740; + packed_float3 View_PrevPreViewTranslation; + float PrePadding_View_1756; + float4x4 View_PrevInvViewProj; + float4x4 View_PrevScreenToTranslatedWorld; + float4x4 View_ClipToPrevClip; + float4 View_TemporalAAJitter; + float4 View_GlobalClippingPlane; + float2 View_FieldOfViewWideAngles; + float2 View_PrevFieldOfViewWideAngles; + float4 View_ViewRectMin; + float4 View_ViewSizeAndInvSize; + float4 View_BufferSizeAndInvSize; + float4 View_BufferBilinearUVMinMax; + int View_NumSceneColorMSAASamples; + float View_PreExposure; + float View_OneOverPreExposure; + float PrePadding_View_2076; + float4 View_DiffuseOverrideParameter; + float4 View_SpecularOverrideParameter; + float4 View_NormalOverrideParameter; + float2 View_RoughnessOverrideParameter; + float View_PrevFrameGameTime; + float View_PrevFrameRealTime; + float View_OutOfBoundsMask; + float PrePadding_View_2148; + float PrePadding_View_2152; + float PrePadding_View_2156; + packed_float3 View_WorldCameraMovementSinceLastFrame; + float View_CullingSign; + float View_NearPlane; + float View_AdaptiveTessellationFactor; + float View_GameTime; + float View_RealTime; + float View_DeltaTime; + float View_MaterialTextureMipBias; + float View_MaterialTextureDerivativeMultiply; + uint View_Random; + uint View_FrameNumber; + uint View_StateFrameIndexMod8; + uint View_StateFrameIndex; + float View_CameraCut; + float View_UnlitViewmodeMask; + float PrePadding_View_2228; + float PrePadding_View_2232; + float PrePadding_View_2236; + float4 View_DirectionalLightColor; + packed_float3 View_DirectionalLightDirection; + float PrePadding_View_2268; + float4 View_TranslucencyLightingVolumeMin[2]; + float4 View_TranslucencyLightingVolumeInvSize[2]; + float4 View_TemporalAAParams; + float4 View_CircleDOFParams; + float View_DepthOfFieldSensorWidth; + float View_DepthOfFieldFocalDistance; + float View_DepthOfFieldScale; + float View_DepthOfFieldFocalLength; + float View_DepthOfFieldFocalRegion; + float View_DepthOfFieldNearTransitionRegion; + float View_DepthOfFieldFarTransitionRegion; + float View_MotionBlurNormalizedToPixel; + float View_bSubsurfacePostprocessEnabled; + float View_GeneralPurposeTweak; + float View_DemosaicVposOffset; + float PrePadding_View_2412; + packed_float3 View_IndirectLightingColorScale; + float View_HDR32bppEncodingMode; + packed_float3 View_AtmosphericFogSunDirection; + float View_AtmosphericFogSunPower; + float View_AtmosphericFogPower; + float View_AtmosphericFogDensityScale; + float View_AtmosphericFogDensityOffset; + float View_AtmosphericFogGroundOffset; + float View_AtmosphericFogDistanceScale; + float View_AtmosphericFogAltitudeScale; + float View_AtmosphericFogHeightScaleRayleigh; + float View_AtmosphericFogStartDistance; + float View_AtmosphericFogDistanceOffset; + float View_AtmosphericFogSunDiscScale; + float View_AtmosphericFogSunDiscHalfApexAngleRadian; + float PrePadding_View_2492; + float4 View_AtmosphericFogSunDiscLuminance; + uint View_AtmosphericFogRenderMask; + uint View_AtmosphericFogInscatterAltitudeSampleNum; + uint PrePadding_View_2520; + uint PrePadding_View_2524; + float4 View_AtmosphericFogSunColor; + packed_float3 View_NormalCurvatureToRoughnessScaleBias; + float View_RenderingReflectionCaptureMask; + float4 View_AmbientCubemapTint; + float View_AmbientCubemapIntensity; + float View_SkyLightParameters; + float PrePadding_View_2584; + float PrePadding_View_2588; + float4 View_SkyLightColor; + float4 View_SkyIrradianceEnvironmentMap[7]; + float View_MobilePreviewMode; + float View_HMDEyePaddingOffset; + float View_ReflectionCubemapMaxMip; + float View_ShowDecalsMask; + uint View_DistanceFieldAOSpecularOcclusionMode; + float View_IndirectCapsuleSelfShadowingIntensity; + float PrePadding_View_2744; + float PrePadding_View_2748; + packed_float3 View_ReflectionEnvironmentRoughnessMixingScaleBiasAndLargestWeight; + int View_StereoPassIndex; + float4 View_GlobalVolumeCenterAndExtent[4]; + float4 View_GlobalVolumeWorldToUVAddAndMul[4]; + float View_GlobalVolumeDimension; + float View_GlobalVolumeTexelSize; + float View_MaxGlobalDistance; + float PrePadding_View_2908; + int2 View_CursorPosition; + float View_bCheckerboardSubsurfaceProfileRendering; + float PrePadding_View_2924; + packed_float3 View_VolumetricFogInvGridSize; + float PrePadding_View_2940; + packed_float3 View_VolumetricFogGridZParams; + float PrePadding_View_2956; + float2 View_VolumetricFogSVPosToVolumeUV; + float View_VolumetricFogMaxDistance; + float PrePadding_View_2972; + packed_float3 View_VolumetricLightmapWorldToUVScale; + float PrePadding_View_2988; + packed_float3 View_VolumetricLightmapWorldToUVAdd; + float PrePadding_View_3004; + packed_float3 View_VolumetricLightmapIndirectionTextureSize; + float View_VolumetricLightmapBrickSize; + packed_float3 View_VolumetricLightmapBrickTexelSize; + float View_StereoIPD; + float View_IndirectLightingCacheShowFlag; + float View_EyeToPixelSpreadAngle; +}; + +struct type_ShadowDepthPass +{ + float PrePadding_ShadowDepthPass_LPV_0; + float PrePadding_ShadowDepthPass_LPV_4; + float PrePadding_ShadowDepthPass_LPV_8; + float PrePadding_ShadowDepthPass_LPV_12; + float PrePadding_ShadowDepthPass_LPV_16; + float PrePadding_ShadowDepthPass_LPV_20; + float PrePadding_ShadowDepthPass_LPV_24; + float PrePadding_ShadowDepthPass_LPV_28; + float PrePadding_ShadowDepthPass_LPV_32; + float PrePadding_ShadowDepthPass_LPV_36; + float PrePadding_ShadowDepthPass_LPV_40; + float PrePadding_ShadowDepthPass_LPV_44; + float PrePadding_ShadowDepthPass_LPV_48; + float PrePadding_ShadowDepthPass_LPV_52; + float PrePadding_ShadowDepthPass_LPV_56; + float PrePadding_ShadowDepthPass_LPV_60; + float PrePadding_ShadowDepthPass_LPV_64; + float PrePadding_ShadowDepthPass_LPV_68; + float PrePadding_ShadowDepthPass_LPV_72; + float PrePadding_ShadowDepthPass_LPV_76; + float PrePadding_ShadowDepthPass_LPV_80; + float PrePadding_ShadowDepthPass_LPV_84; + float PrePadding_ShadowDepthPass_LPV_88; + float PrePadding_ShadowDepthPass_LPV_92; + float PrePadding_ShadowDepthPass_LPV_96; + float PrePadding_ShadowDepthPass_LPV_100; + float PrePadding_ShadowDepthPass_LPV_104; + float PrePadding_ShadowDepthPass_LPV_108; + float PrePadding_ShadowDepthPass_LPV_112; + float PrePadding_ShadowDepthPass_LPV_116; + float PrePadding_ShadowDepthPass_LPV_120; + float PrePadding_ShadowDepthPass_LPV_124; + float PrePadding_ShadowDepthPass_LPV_128; + float PrePadding_ShadowDepthPass_LPV_132; + float PrePadding_ShadowDepthPass_LPV_136; + float PrePadding_ShadowDepthPass_LPV_140; + float PrePadding_ShadowDepthPass_LPV_144; + float PrePadding_ShadowDepthPass_LPV_148; + float PrePadding_ShadowDepthPass_LPV_152; + float PrePadding_ShadowDepthPass_LPV_156; + float PrePadding_ShadowDepthPass_LPV_160; + float PrePadding_ShadowDepthPass_LPV_164; + float PrePadding_ShadowDepthPass_LPV_168; + float PrePadding_ShadowDepthPass_LPV_172; + float PrePadding_ShadowDepthPass_LPV_176; + float PrePadding_ShadowDepthPass_LPV_180; + float PrePadding_ShadowDepthPass_LPV_184; + float PrePadding_ShadowDepthPass_LPV_188; + float PrePadding_ShadowDepthPass_LPV_192; + float PrePadding_ShadowDepthPass_LPV_196; + float PrePadding_ShadowDepthPass_LPV_200; + float PrePadding_ShadowDepthPass_LPV_204; + float PrePadding_ShadowDepthPass_LPV_208; + float PrePadding_ShadowDepthPass_LPV_212; + float PrePadding_ShadowDepthPass_LPV_216; + float PrePadding_ShadowDepthPass_LPV_220; + float PrePadding_ShadowDepthPass_LPV_224; + float PrePadding_ShadowDepthPass_LPV_228; + float PrePadding_ShadowDepthPass_LPV_232; + float PrePadding_ShadowDepthPass_LPV_236; + float PrePadding_ShadowDepthPass_LPV_240; + float PrePadding_ShadowDepthPass_LPV_244; + float PrePadding_ShadowDepthPass_LPV_248; + float PrePadding_ShadowDepthPass_LPV_252; + float PrePadding_ShadowDepthPass_LPV_256; + float PrePadding_ShadowDepthPass_LPV_260; + float PrePadding_ShadowDepthPass_LPV_264; + float PrePadding_ShadowDepthPass_LPV_268; + float4x4 ShadowDepthPass_LPV_mRsmToWorld; + float4 ShadowDepthPass_LPV_mLightColour; + float4 ShadowDepthPass_LPV_GeometryVolumeCaptureLightDirection; + float4 ShadowDepthPass_LPV_mEyePos; + packed_int3 ShadowDepthPass_LPV_mOldGridOffset; + int PrePadding_ShadowDepthPass_LPV_396; + packed_int3 ShadowDepthPass_LPV_mLpvGridOffset; + float ShadowDepthPass_LPV_ClearMultiplier; + float ShadowDepthPass_LPV_LpvScale; + float ShadowDepthPass_LPV_OneOverLpvScale; + float ShadowDepthPass_LPV_DirectionalOcclusionIntensity; + float ShadowDepthPass_LPV_DirectionalOcclusionRadius; + float ShadowDepthPass_LPV_RsmAreaIntensityMultiplier; + float ShadowDepthPass_LPV_RsmPixelToTexcoordMultiplier; + float ShadowDepthPass_LPV_SecondaryOcclusionStrength; + float ShadowDepthPass_LPV_SecondaryBounceStrength; + float ShadowDepthPass_LPV_VplInjectionBias; + float ShadowDepthPass_LPV_GeometryVolumeInjectionBias; + float ShadowDepthPass_LPV_EmissiveInjectionMultiplier; + int ShadowDepthPass_LPV_PropagationIndex; + float4x4 ShadowDepthPass_ProjectionMatrix; + float4x4 ShadowDepthPass_ViewMatrix; + float4 ShadowDepthPass_ShadowParams; + float ShadowDepthPass_bClampToNearPlane; + float PrePadding_ShadowDepthPass_612; + float PrePadding_ShadowDepthPass_616; + float PrePadding_ShadowDepthPass_620; + float4x4 ShadowDepthPass_ShadowViewProjectionMatrices[6]; + float4x4 ShadowDepthPass_ShadowViewMatrices[6]; +}; + +constant float4 _113 = {}; + +struct main0_out +{ + float4 out_var_TEXCOORD10_centroid [[user(locn0)]]; + float4 out_var_TEXCOORD11_centroid [[user(locn1)]]; + float4 out_var_COLOR0 [[user(locn2)]]; + float4 out_var_TEXCOORD0_0 [[user(locn3)]]; + uint out_var_PRIMITIVE_ID [[user(locn4)]]; + float out_var_TEXCOORD6 [[user(locn5)]]; + float out_var_TEXCOORD8 [[user(locn6)]]; + float3 out_var_TEXCOORD7 [[user(locn7)]]; + float4 gl_Position [[position]]; +}; + +struct main0_in +{ + float4 in_var_COLOR0 [[attribute(0)]]; + float4 in_var_PN_POSITION_0 [[attribute(2)]]; + float4 in_var_PN_POSITION_1 [[attribute(3)]]; + float4 in_var_PN_POSITION_2 [[attribute(4)]]; + float in_var_PN_WorldDisplacementMultiplier [[attribute(7)]]; + uint in_var_PRIMITIVE_ID [[attribute(8)]]; + float4 in_var_TEXCOORD0_0 [[attribute(9)]]; + float4 in_var_TEXCOORD10_centroid [[attribute(10)]]; + float4 in_var_TEXCOORD11_centroid [[attribute(11)]]; +}; + +struct main0_patchIn +{ + float4 in_var_PN_POSITION9 [[attribute(5)]]; + patch_control_point gl_in; +}; + +[[ patch(triangle, 0) ]] vertex main0_out main0(main0_patchIn patchIn [[stage_in]], constant type_View& View [[buffer(0)]], constant type_ShadowDepthPass& ShadowDepthPass [[buffer(1)]], texture2d Material_Texture2D_3 [[texture(0)]], sampler Material_Texture2D_3Sampler [[sampler(0)]], float3 gl_TessCoord [[position_in_patch]]) +{ + main0_out out = {}; + spvUnsafeArray out_var_TEXCOORD0 = {}; + spvUnsafeArray _117 = spvUnsafeArray({ patchIn.gl_in[0].in_var_TEXCOORD10_centroid, patchIn.gl_in[1].in_var_TEXCOORD10_centroid, patchIn.gl_in[2].in_var_TEXCOORD10_centroid }); + spvUnsafeArray _118 = spvUnsafeArray({ patchIn.gl_in[0].in_var_TEXCOORD11_centroid, patchIn.gl_in[1].in_var_TEXCOORD11_centroid, patchIn.gl_in[2].in_var_TEXCOORD11_centroid }); + spvUnsafeArray _119 = spvUnsafeArray({ patchIn.gl_in[0].in_var_COLOR0, patchIn.gl_in[1].in_var_COLOR0, patchIn.gl_in[2].in_var_COLOR0 }); + spvUnsafeArray, 3> _120 = spvUnsafeArray, 3>({ spvUnsafeArray({ patchIn.gl_in[0].in_var_TEXCOORD0_0 }), spvUnsafeArray({ patchIn.gl_in[1].in_var_TEXCOORD0_0 }), spvUnsafeArray({ patchIn.gl_in[2].in_var_TEXCOORD0_0 }) }); + spvUnsafeArray, 3> _135 = spvUnsafeArray, 3>({ spvUnsafeArray({ patchIn.gl_in[0].in_var_PN_POSITION_0, patchIn.gl_in[0].in_var_PN_POSITION_1, patchIn.gl_in[0].in_var_PN_POSITION_2 }), spvUnsafeArray({ patchIn.gl_in[1].in_var_PN_POSITION_0, patchIn.gl_in[1].in_var_PN_POSITION_1, patchIn.gl_in[1].in_var_PN_POSITION_2 }), spvUnsafeArray({ patchIn.gl_in[2].in_var_PN_POSITION_0, patchIn.gl_in[2].in_var_PN_POSITION_1, patchIn.gl_in[2].in_var_PN_POSITION_2 }) }); + spvUnsafeArray _136 = spvUnsafeArray({ patchIn.gl_in[0].in_var_PN_WorldDisplacementMultiplier, patchIn.gl_in[1].in_var_PN_WorldDisplacementMultiplier, patchIn.gl_in[2].in_var_PN_WorldDisplacementMultiplier }); + float _157 = gl_TessCoord.x * gl_TessCoord.x; + float _158 = gl_TessCoord.y * gl_TessCoord.y; + float _159 = gl_TessCoord.z * gl_TessCoord.z; + float4 _165 = float4(gl_TessCoord.x); + float4 _169 = float4(gl_TessCoord.y); + float4 _174 = float4(gl_TessCoord.z); + float4 _177 = float4(_157 * 3.0); + float4 _181 = float4(_158 * 3.0); + float4 _188 = float4(_159 * 3.0); + float4 _202 = ((((((((((_135[0][0] * float4(_157)) * _165) + ((_135[1][0] * float4(_158)) * _169)) + ((_135[2][0] * float4(_159)) * _174)) + ((_135[0][1] * _177) * _169)) + ((_135[0][2] * _181) * _165)) + ((_135[1][1] * _181) * _174)) + ((_135[1][2] * _188) * _169)) + ((_135[2][1] * _188) * _165)) + ((_135[2][2] * _177) * _174)) + ((((patchIn.in_var_PN_POSITION9 * float4(6.0)) * _174) * _165) * _169); + float3 _226 = ((_117[0].xyz * float3(gl_TessCoord.x)) + (_117[1].xyz * float3(gl_TessCoord.y))).xyz + (_117[2].xyz * float3(gl_TessCoord.z)); + float4 _229 = ((_118[0] * _165) + (_118[1] * _169)) + (_118[2] * _174); + float4 _231 = ((_119[0] * _165) + (_119[1] * _169)) + (_119[2] * _174); + float4 _233 = ((_120[0][0] * _165) + (_120[1][0] * _169)) + (_120[2][0] * _174); + spvUnsafeArray _234 = spvUnsafeArray({ _233 }); + float3 _236 = _229.xyz; + float3 _264 = _202.xyz + (((float3((Material_Texture2D_3.sample(Material_Texture2D_3Sampler, (float2(View.View_GameTime * 0.20000000298023223876953125, View.View_GameTime * (-0.699999988079071044921875)) + (_233.zw * float2(1.0, 2.0))), level(-1.0)).x * 10.0) * (1.0 - _231.x)) * _236) * float3(0.5)) * float3(((_136[0] * gl_TessCoord.x) + (_136[1] * gl_TessCoord.y)) + (_136[2] * gl_TessCoord.z))); + float4x4 _116 = ShadowDepthPass.ShadowDepthPass_ViewMatrix; + float4 _270 = ShadowDepthPass.ShadowDepthPass_ProjectionMatrix * float4(_264.x, _264.y, _264.z, _202.w); + float4 _281; + if ((ShadowDepthPass.ShadowDepthPass_bClampToNearPlane > 0.0) && (_270.z < 0.0)) + { + float4 _279 = _270; + _279.z = 9.9999999747524270787835121154785e-07; + float4 _280 = _279; + _280.w = 1.0; + _281 = _280; + } + else + { + _281 = _270; + } + float _290 = abs(dot(float3(_116[0u].z, _116[1u].z, _116[2u].z), _236)); + out.out_var_TEXCOORD10_centroid = float4(_226.x, _226.y, _226.z, _113.w); + out.out_var_TEXCOORD11_centroid = _229; + out.out_var_COLOR0 = _231; + out_var_TEXCOORD0 = _234; + out.out_var_PRIMITIVE_ID = patchIn.gl_in[0u].in_var_PRIMITIVE_ID; + out.out_var_TEXCOORD6 = _281.z; + out.out_var_TEXCOORD8 = (ShadowDepthPass.ShadowDepthPass_ShadowParams.y * fast::clamp((abs(_290) > 0.0) ? (sqrt(fast::clamp(1.0 - (_290 * _290), 0.0, 1.0)) / _290) : ShadowDepthPass.ShadowDepthPass_ShadowParams.z, 0.0, ShadowDepthPass.ShadowDepthPass_ShadowParams.z)) + ShadowDepthPass.ShadowDepthPass_ShadowParams.x; + out.out_var_TEXCOORD7 = _264.xyz; + out.gl_Position = _281; + out.out_var_TEXCOORD0_0 = out_var_TEXCOORD0[0]; + return out; +} + diff --git a/third_party/spirv-cross/reference/shaders-ue4/asm/tese/ds-patch-input-fixes.asm.tese b/third_party/spirv-cross/reference/shaders-ue4/asm/tese/ds-patch-input-fixes.asm.tese new file mode 100644 index 0000000000..738b073a1d --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-ue4/asm/tese/ds-patch-input-fixes.asm.tese @@ -0,0 +1,417 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + +#include +#include + +using namespace metal; + +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +struct type_View +{ + float4x4 View_TranslatedWorldToClip; + float4x4 View_WorldToClip; + float4x4 View_ClipToWorld; + float4x4 View_TranslatedWorldToView; + float4x4 View_ViewToTranslatedWorld; + float4x4 View_TranslatedWorldToCameraView; + float4x4 View_CameraViewToTranslatedWorld; + float4x4 View_ViewToClip; + float4x4 View_ViewToClipNoAA; + float4x4 View_ClipToView; + float4x4 View_ClipToTranslatedWorld; + float4x4 View_SVPositionToTranslatedWorld; + float4x4 View_ScreenToWorld; + float4x4 View_ScreenToTranslatedWorld; + packed_float3 View_ViewForward; + float PrePadding_View_908; + packed_float3 View_ViewUp; + float PrePadding_View_924; + packed_float3 View_ViewRight; + float PrePadding_View_940; + packed_float3 View_HMDViewNoRollUp; + float PrePadding_View_956; + packed_float3 View_HMDViewNoRollRight; + float PrePadding_View_972; + float4 View_InvDeviceZToWorldZTransform; + float4 View_ScreenPositionScaleBias; + packed_float3 View_WorldCameraOrigin; + float PrePadding_View_1020; + packed_float3 View_TranslatedWorldCameraOrigin; + float PrePadding_View_1036; + packed_float3 View_WorldViewOrigin; + float PrePadding_View_1052; + packed_float3 View_PreViewTranslation; + float PrePadding_View_1068; + float4x4 View_PrevProjection; + float4x4 View_PrevViewProj; + float4x4 View_PrevViewRotationProj; + float4x4 View_PrevViewToClip; + float4x4 View_PrevClipToView; + float4x4 View_PrevTranslatedWorldToClip; + float4x4 View_PrevTranslatedWorldToView; + float4x4 View_PrevViewToTranslatedWorld; + float4x4 View_PrevTranslatedWorldToCameraView; + float4x4 View_PrevCameraViewToTranslatedWorld; + packed_float3 View_PrevWorldCameraOrigin; + float PrePadding_View_1724; + packed_float3 View_PrevWorldViewOrigin; + float PrePadding_View_1740; + packed_float3 View_PrevPreViewTranslation; + float PrePadding_View_1756; + float4x4 View_PrevInvViewProj; + float4x4 View_PrevScreenToTranslatedWorld; + float4x4 View_ClipToPrevClip; + float4 View_TemporalAAJitter; + float4 View_GlobalClippingPlane; + float2 View_FieldOfViewWideAngles; + float2 View_PrevFieldOfViewWideAngles; + float4 View_ViewRectMin; + float4 View_ViewSizeAndInvSize; + float4 View_BufferSizeAndInvSize; + float4 View_BufferBilinearUVMinMax; + int View_NumSceneColorMSAASamples; + float View_PreExposure; + float View_OneOverPreExposure; + float PrePadding_View_2076; + float4 View_DiffuseOverrideParameter; + float4 View_SpecularOverrideParameter; + float4 View_NormalOverrideParameter; + float2 View_RoughnessOverrideParameter; + float View_PrevFrameGameTime; + float View_PrevFrameRealTime; + float View_OutOfBoundsMask; + float PrePadding_View_2148; + float PrePadding_View_2152; + float PrePadding_View_2156; + packed_float3 View_WorldCameraMovementSinceLastFrame; + float View_CullingSign; + float View_NearPlane; + float View_AdaptiveTessellationFactor; + float View_GameTime; + float View_RealTime; + float View_DeltaTime; + float View_MaterialTextureMipBias; + float View_MaterialTextureDerivativeMultiply; + uint View_Random; + uint View_FrameNumber; + uint View_StateFrameIndexMod8; + uint View_StateFrameIndex; + float View_CameraCut; + float View_UnlitViewmodeMask; + float PrePadding_View_2228; + float PrePadding_View_2232; + float PrePadding_View_2236; + float4 View_DirectionalLightColor; + packed_float3 View_DirectionalLightDirection; + float PrePadding_View_2268; + float4 View_TranslucencyLightingVolumeMin[2]; + float4 View_TranslucencyLightingVolumeInvSize[2]; + float4 View_TemporalAAParams; + float4 View_CircleDOFParams; + float View_DepthOfFieldSensorWidth; + float View_DepthOfFieldFocalDistance; + float View_DepthOfFieldScale; + float View_DepthOfFieldFocalLength; + float View_DepthOfFieldFocalRegion; + float View_DepthOfFieldNearTransitionRegion; + float View_DepthOfFieldFarTransitionRegion; + float View_MotionBlurNormalizedToPixel; + float View_bSubsurfacePostprocessEnabled; + float View_GeneralPurposeTweak; + float View_DemosaicVposOffset; + float PrePadding_View_2412; + packed_float3 View_IndirectLightingColorScale; + float View_HDR32bppEncodingMode; + packed_float3 View_AtmosphericFogSunDirection; + float View_AtmosphericFogSunPower; + float View_AtmosphericFogPower; + float View_AtmosphericFogDensityScale; + float View_AtmosphericFogDensityOffset; + float View_AtmosphericFogGroundOffset; + float View_AtmosphericFogDistanceScale; + float View_AtmosphericFogAltitudeScale; + float View_AtmosphericFogHeightScaleRayleigh; + float View_AtmosphericFogStartDistance; + float View_AtmosphericFogDistanceOffset; + float View_AtmosphericFogSunDiscScale; + float View_AtmosphericFogSunDiscHalfApexAngleRadian; + float PrePadding_View_2492; + float4 View_AtmosphericFogSunDiscLuminance; + uint View_AtmosphericFogRenderMask; + uint View_AtmosphericFogInscatterAltitudeSampleNum; + uint PrePadding_View_2520; + uint PrePadding_View_2524; + float4 View_AtmosphericFogSunColor; + packed_float3 View_NormalCurvatureToRoughnessScaleBias; + float View_RenderingReflectionCaptureMask; + float4 View_AmbientCubemapTint; + float View_AmbientCubemapIntensity; + float View_SkyLightParameters; + float PrePadding_View_2584; + float PrePadding_View_2588; + float4 View_SkyLightColor; + float4 View_SkyIrradianceEnvironmentMap[7]; + float View_MobilePreviewMode; + float View_HMDEyePaddingOffset; + float View_ReflectionCubemapMaxMip; + float View_ShowDecalsMask; + uint View_DistanceFieldAOSpecularOcclusionMode; + float View_IndirectCapsuleSelfShadowingIntensity; + float PrePadding_View_2744; + float PrePadding_View_2748; + packed_float3 View_ReflectionEnvironmentRoughnessMixingScaleBiasAndLargestWeight; + int View_StereoPassIndex; + float4 View_GlobalVolumeCenterAndExtent[4]; + float4 View_GlobalVolumeWorldToUVAddAndMul[4]; + float View_GlobalVolumeDimension; + float View_GlobalVolumeTexelSize; + float View_MaxGlobalDistance; + float PrePadding_View_2908; + int2 View_CursorPosition; + float View_bCheckerboardSubsurfaceProfileRendering; + float PrePadding_View_2924; + packed_float3 View_VolumetricFogInvGridSize; + float PrePadding_View_2940; + packed_float3 View_VolumetricFogGridZParams; + float PrePadding_View_2956; + float2 View_VolumetricFogSVPosToVolumeUV; + float View_VolumetricFogMaxDistance; + float PrePadding_View_2972; + packed_float3 View_VolumetricLightmapWorldToUVScale; + float PrePadding_View_2988; + packed_float3 View_VolumetricLightmapWorldToUVAdd; + float PrePadding_View_3004; + packed_float3 View_VolumetricLightmapIndirectionTextureSize; + float View_VolumetricLightmapBrickSize; + packed_float3 View_VolumetricLightmapBrickTexelSize; + float View_StereoIPD; + float View_IndirectLightingCacheShowFlag; + float View_EyeToPixelSpreadAngle; + float PrePadding_View_3048; + float PrePadding_View_3052; + float4x4 View_WorldToVirtualTexture; + float4 View_VirtualTextureParams; + float4 View_XRPassthroughCameraUVs[2]; +}; + +struct type_Material +{ + float4 Material_VectorExpressions[5]; + float4 Material_ScalarExpressions[2]; +}; + +constant float4 _118 = {}; + +struct main0_out +{ + float4 out_var_TEXCOORD6 [[user(locn0)]]; + float4 out_var_TEXCOORD7 [[user(locn1)]]; + float4 out_var_TEXCOORD10_centroid [[user(locn2)]]; + float4 out_var_TEXCOORD11_centroid [[user(locn3)]]; + float gl_ClipDistance [[clip_distance]] [1]; + float gl_ClipDistance_0 [[user(clip0)]]; + float4 gl_Position [[position]]; +}; + +struct main0_in +{ + float4 in_var_PN_DominantEdge2 [[attribute(3)]]; + float4 in_var_PN_DominantEdge3 [[attribute(4)]]; + float3 in_var_PN_DominantEdge4 [[attribute(5)]]; + float3 in_var_PN_DominantEdge5 [[attribute(6)]]; + float4 in_var_PN_DominantVertex1 [[attribute(8)]]; + float3 in_var_PN_DominantVertex2 [[attribute(9)]]; + float4 in_var_PN_POSITION_0 [[attribute(10)]]; + float4 in_var_PN_POSITION_1 [[attribute(11)]]; + float4 in_var_PN_POSITION_2 [[attribute(12)]]; + float in_var_PN_WorldDisplacementMultiplier [[attribute(15)]]; + float4 in_var_TEXCOORD10_centroid [[attribute(16)]]; + float4 in_var_TEXCOORD11_centroid [[attribute(17)]]; + float4 in_var_TEXCOORD6 [[attribute(18)]]; + float4 in_var_TEXCOORD8 [[attribute(19)]]; +}; + +struct main0_patchIn +{ + float4 in_var_PN_POSITION9 [[attribute(13)]]; + patch_control_point gl_in; +}; + +[[ patch(triangle, 0) ]] vertex main0_out main0(main0_patchIn patchIn [[stage_in]], constant type_View& View [[buffer(0)]], constant type_Material& Material [[buffer(1)]], texture3d View_GlobalDistanceFieldTexture0 [[texture(0)]], texture3d View_GlobalDistanceFieldTexture1 [[texture(1)]], texture3d View_GlobalDistanceFieldTexture2 [[texture(2)]], texture3d View_GlobalDistanceFieldTexture3 [[texture(3)]], sampler View_GlobalDistanceFieldSampler0 [[sampler(0)]], float3 gl_TessCoord [[position_in_patch]]) +{ + main0_out out = {}; + spvUnsafeArray _120 = spvUnsafeArray({ patchIn.gl_in[0].in_var_TEXCOORD6, patchIn.gl_in[1].in_var_TEXCOORD6, patchIn.gl_in[2].in_var_TEXCOORD6 }); + spvUnsafeArray _121 = spvUnsafeArray({ patchIn.gl_in[0].in_var_TEXCOORD8, patchIn.gl_in[1].in_var_TEXCOORD8, patchIn.gl_in[2].in_var_TEXCOORD8 }); + spvUnsafeArray _128 = spvUnsafeArray({ patchIn.gl_in[0].in_var_TEXCOORD10_centroid, patchIn.gl_in[1].in_var_TEXCOORD10_centroid, patchIn.gl_in[2].in_var_TEXCOORD10_centroid }); + spvUnsafeArray _129 = spvUnsafeArray({ patchIn.gl_in[0].in_var_TEXCOORD11_centroid, patchIn.gl_in[1].in_var_TEXCOORD11_centroid, patchIn.gl_in[2].in_var_TEXCOORD11_centroid }); + spvUnsafeArray, 3> _136 = spvUnsafeArray, 3>({ spvUnsafeArray({ patchIn.gl_in[0].in_var_PN_POSITION_0, patchIn.gl_in[0].in_var_PN_POSITION_1, patchIn.gl_in[0].in_var_PN_POSITION_2 }), spvUnsafeArray({ patchIn.gl_in[1].in_var_PN_POSITION_0, patchIn.gl_in[1].in_var_PN_POSITION_1, patchIn.gl_in[1].in_var_PN_POSITION_2 }), spvUnsafeArray({ patchIn.gl_in[2].in_var_PN_POSITION_0, patchIn.gl_in[2].in_var_PN_POSITION_1, patchIn.gl_in[2].in_var_PN_POSITION_2 }) }); + spvUnsafeArray _137 = spvUnsafeArray({ patchIn.gl_in[0].in_var_PN_WorldDisplacementMultiplier, patchIn.gl_in[1].in_var_PN_WorldDisplacementMultiplier, patchIn.gl_in[2].in_var_PN_WorldDisplacementMultiplier }); + spvUnsafeArray _138 = spvUnsafeArray({ patchIn.gl_in[0].in_var_PN_DominantVertex1, patchIn.gl_in[1].in_var_PN_DominantVertex1, patchIn.gl_in[2].in_var_PN_DominantVertex1 }); + spvUnsafeArray _139 = spvUnsafeArray({ patchIn.gl_in[0].in_var_PN_DominantVertex2, patchIn.gl_in[1].in_var_PN_DominantVertex2, patchIn.gl_in[2].in_var_PN_DominantVertex2 }); + spvUnsafeArray _146 = spvUnsafeArray({ patchIn.gl_in[0].in_var_PN_DominantEdge2, patchIn.gl_in[1].in_var_PN_DominantEdge2, patchIn.gl_in[2].in_var_PN_DominantEdge2 }); + spvUnsafeArray _147 = spvUnsafeArray({ patchIn.gl_in[0].in_var_PN_DominantEdge3, patchIn.gl_in[1].in_var_PN_DominantEdge3, patchIn.gl_in[2].in_var_PN_DominantEdge3 }); + spvUnsafeArray _148 = spvUnsafeArray({ patchIn.gl_in[0].in_var_PN_DominantEdge4, patchIn.gl_in[1].in_var_PN_DominantEdge4, patchIn.gl_in[2].in_var_PN_DominantEdge4 }); + spvUnsafeArray _149 = spvUnsafeArray({ patchIn.gl_in[0].in_var_PN_DominantEdge5, patchIn.gl_in[1].in_var_PN_DominantEdge5, patchIn.gl_in[2].in_var_PN_DominantEdge5 }); + float _190 = gl_TessCoord.x * gl_TessCoord.x; + float _191 = gl_TessCoord.y * gl_TessCoord.y; + float _192 = gl_TessCoord.z * gl_TessCoord.z; + float4 _198 = float4(gl_TessCoord.x); + float4 _202 = float4(gl_TessCoord.y); + float4 _207 = float4(gl_TessCoord.z); + float4 _210 = float4(_190 * 3.0); + float4 _214 = float4(_191 * 3.0); + float4 _221 = float4(_192 * 3.0); + float4 _235 = ((((((((((_136[0][0] * float4(_190)) * _198) + ((_136[1][0] * float4(_191)) * _202)) + ((_136[2][0] * float4(_192)) * _207)) + ((_136[0][1] * _210) * _202)) + ((_136[0][2] * _214) * _198)) + ((_136[1][1] * _214) * _207)) + ((_136[1][2] * _221) * _202)) + ((_136[2][1] * _221) * _198)) + ((_136[2][2] * _210) * _207)) + ((((patchIn.in_var_PN_POSITION9 * float4(6.0)) * _207) * _198) * _202); + float3 _237 = float3(gl_TessCoord.x); + float3 _240 = float3(gl_TessCoord.y); + float3 _254 = float3(gl_TessCoord.z); + float3 _256 = ((_128[0].xyz * _237) + (_128[1].xyz * _240)).xyz + (_128[2].xyz * _254); + float4 _259 = ((_129[0] * _198) + (_129[1] * _202)) + (_129[2] * _207); + float3 _264 = _235.xyz; + float3 _265 = _256.xyz; + float3 _266 = _259.xyz; + float3 _272 = _264 + float3(View.View_WorldCameraOrigin); + float _279 = float(int(gl_TessCoord.x == 0.0)); + float _282 = float(int(gl_TessCoord.y == 0.0)); + float _285 = float(int(gl_TessCoord.z == 0.0)); + float _286 = _279 + _282; + float _287 = _286 + _285; + float4 _387; + float3 _388; + if (float(int(_287 == 2.0)) == 1.0) + { + float _363 = float(int((_282 + _285) == 2.0)); + float _367 = float(int((_285 + _279) == 2.0)); + float _370 = float(int(_286 == 2.0)); + _387 = ((float4(_363) * _138[0]) + (float4(_367) * _138[1])) + (float4(_370) * _138[2]); + _388 = ((float3(_363) * _139[0]) + (float3(_367) * _139[1])) + (float3(_370) * _139[2]); + } + else + { + float4 _358; + float3 _359; + if (float(int(_287 == 1.0)) != 0.0) + { + float4 _304 = float4(_279); + float4 _306 = float4(_282); + float4 _309 = float4(_285); + float4 _311 = ((_304 * _146[0]) + (_306 * _146[1])) + (_309 * _146[2]); + float4 _316 = ((_304 * _147[0]) + (_306 * _147[1])) + (_309 * _147[2]); + float3 _331 = float3(_279); + float3 _333 = float3(_282); + float3 _336 = float3(_285); + float3 _338 = ((_331 * _148[0]) + (_333 * _148[1])) + (_336 * _148[2]); + float3 _343 = ((_331 * _149[0]) + (_333 * _149[1])) + (_336 * _149[2]); + _358 = ((_304 * ((_202 * _311) + (_207 * _316))) + (_306 * ((_207 * _311) + (_198 * _316)))) + (_309 * ((_198 * _311) + (_202 * _316))); + _359 = ((_331 * ((_240 * _338) + (_254 * _343))) + (_333 * ((_254 * _338) + (_237 * _343)))) + (_336 * ((_237 * _338) + (_240 * _343))); + } + else + { + _358 = float4(_259.xyz, 0.0); + _359 = _265; + } + _387 = _358; + _388 = _359; + } + float3x3 _398; + if (float(int(_287 == 0.0)) == 0.0) + { + _398 = float3x3(_388, cross(_387.xyz, _388) * float3(_387.w), _387.xyz); + } + else + { + _398 = float3x3(_265, cross(_266, _265) * float3(_259.w), _266); + } + float3 _411 = fast::min(fast::max((_272 - View.View_GlobalVolumeCenterAndExtent[0].xyz) + View.View_GlobalVolumeCenterAndExtent[0].www, float3(0.0)), fast::max((View.View_GlobalVolumeCenterAndExtent[0].xyz + View.View_GlobalVolumeCenterAndExtent[0].www) - _272, float3(0.0))); + float _547; + if (fast::min(_411.x, fast::min(_411.y, _411.z)) > (View.View_GlobalVolumeCenterAndExtent[0].w * View.View_GlobalVolumeTexelSize)) + { + _547 = View_GlobalDistanceFieldTexture0.sample(View_GlobalDistanceFieldSampler0, ((_272 * View.View_GlobalVolumeWorldToUVAddAndMul[0u].www) + View.View_GlobalVolumeWorldToUVAddAndMul[0u].xyz), level(0.0)).x; + } + else + { + float3 _436 = fast::min(fast::max((_272 - View.View_GlobalVolumeCenterAndExtent[1].xyz) + View.View_GlobalVolumeCenterAndExtent[1].www, float3(0.0)), fast::max((View.View_GlobalVolumeCenterAndExtent[1].xyz + View.View_GlobalVolumeCenterAndExtent[1].www) - _272, float3(0.0))); + float _535; + if (fast::min(_436.x, fast::min(_436.y, _436.z)) > (View.View_GlobalVolumeCenterAndExtent[1].w * View.View_GlobalVolumeTexelSize)) + { + _535 = View_GlobalDistanceFieldTexture1.sample(View_GlobalDistanceFieldSampler0, ((_272 * View.View_GlobalVolumeWorldToUVAddAndMul[1u].www) + View.View_GlobalVolumeWorldToUVAddAndMul[1u].xyz), level(0.0)).x; + } + else + { + float3 _459 = fast::min(fast::max((_272 - View.View_GlobalVolumeCenterAndExtent[2].xyz) + View.View_GlobalVolumeCenterAndExtent[2].www, float3(0.0)), fast::max((View.View_GlobalVolumeCenterAndExtent[2].xyz + View.View_GlobalVolumeCenterAndExtent[2].www) - _272, float3(0.0))); + float3 _475 = fast::min(fast::max((_272 - View.View_GlobalVolumeCenterAndExtent[3].xyz) + View.View_GlobalVolumeCenterAndExtent[3].www, float3(0.0)), fast::max((View.View_GlobalVolumeCenterAndExtent[3].xyz + View.View_GlobalVolumeCenterAndExtent[3].www) - _272, float3(0.0))); + float _480 = fast::min(_475.x, fast::min(_475.y, _475.z)); + float _523; + if (fast::min(_459.x, fast::min(_459.y, _459.z)) > (View.View_GlobalVolumeCenterAndExtent[2].w * View.View_GlobalVolumeTexelSize)) + { + _523 = View_GlobalDistanceFieldTexture2.sample(View_GlobalDistanceFieldSampler0, ((_272 * View.View_GlobalVolumeWorldToUVAddAndMul[2u].www) + View.View_GlobalVolumeWorldToUVAddAndMul[2u].xyz), level(0.0)).x; + } + else + { + float _511; + if (_480 > (View.View_GlobalVolumeCenterAndExtent[3].w * View.View_GlobalVolumeTexelSize)) + { + _511 = mix(View.View_MaxGlobalDistance, View_GlobalDistanceFieldTexture3.sample(View_GlobalDistanceFieldSampler0, ((_272 * View.View_GlobalVolumeWorldToUVAddAndMul[3u].www) + View.View_GlobalVolumeWorldToUVAddAndMul[3u].xyz), level(0.0)).x, fast::clamp((_480 * 10.0) * View.View_GlobalVolumeWorldToUVAddAndMul[3].w, 0.0, 1.0)); + } + else + { + _511 = View.View_MaxGlobalDistance; + } + _523 = _511; + } + _535 = _523; + } + _547 = _535; + } + float3 _565 = _264 + ((_398[2] * float3(fast::min(_547 + Material.Material_ScalarExpressions[0].z, 0.0) * Material.Material_ScalarExpressions[0].w)) * float3(((_137[0] * gl_TessCoord.x) + (_137[1] * gl_TessCoord.y)) + (_137[2] * gl_TessCoord.z))); + float4 _574 = View.View_TranslatedWorldToClip * float4(_565.x, _565.y, _565.z, _235.w); + float4 _579 = _574; + _579.z = _574.z + (0.001000000047497451305389404296875 * _574.w); + out.gl_Position = _579; + out.out_var_TEXCOORD6 = ((_120[0] * _198) + (_120[1] * _202)) + (_120[2] * _207); + out.out_var_TEXCOORD7 = ((_121[0] * _198) + (_121[1] * _202)) + (_121[2] * _207); + out.out_var_TEXCOORD10_centroid = float4(_256.x, _256.y, _256.z, _118.w); + out.out_var_TEXCOORD11_centroid = _259; + out.gl_ClipDistance[0u] = dot(View.View_GlobalClippingPlane, float4(_565.xyz - float3(View.View_PreViewTranslation), 1.0)); + out.gl_ClipDistance_0 = out.gl_ClipDistance[0]; + return out; +} + diff --git a/third_party/spirv-cross/reference/shaders-ue4/asm/tese/ds-patch-inputs.asm.tese b/third_party/spirv-cross/reference/shaders-ue4/asm/tese/ds-patch-inputs.asm.tese new file mode 100644 index 0000000000..d0b6fbdd9a --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-ue4/asm/tese/ds-patch-inputs.asm.tese @@ -0,0 +1,217 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + +#include +#include + +using namespace metal; + +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +struct type_ShadowDepthPass +{ + float PrePadding_ShadowDepthPass_LPV_0; + float PrePadding_ShadowDepthPass_LPV_4; + float PrePadding_ShadowDepthPass_LPV_8; + float PrePadding_ShadowDepthPass_LPV_12; + float PrePadding_ShadowDepthPass_LPV_16; + float PrePadding_ShadowDepthPass_LPV_20; + float PrePadding_ShadowDepthPass_LPV_24; + float PrePadding_ShadowDepthPass_LPV_28; + float PrePadding_ShadowDepthPass_LPV_32; + float PrePadding_ShadowDepthPass_LPV_36; + float PrePadding_ShadowDepthPass_LPV_40; + float PrePadding_ShadowDepthPass_LPV_44; + float PrePadding_ShadowDepthPass_LPV_48; + float PrePadding_ShadowDepthPass_LPV_52; + float PrePadding_ShadowDepthPass_LPV_56; + float PrePadding_ShadowDepthPass_LPV_60; + float PrePadding_ShadowDepthPass_LPV_64; + float PrePadding_ShadowDepthPass_LPV_68; + float PrePadding_ShadowDepthPass_LPV_72; + float PrePadding_ShadowDepthPass_LPV_76; + float PrePadding_ShadowDepthPass_LPV_80; + float PrePadding_ShadowDepthPass_LPV_84; + float PrePadding_ShadowDepthPass_LPV_88; + float PrePadding_ShadowDepthPass_LPV_92; + float PrePadding_ShadowDepthPass_LPV_96; + float PrePadding_ShadowDepthPass_LPV_100; + float PrePadding_ShadowDepthPass_LPV_104; + float PrePadding_ShadowDepthPass_LPV_108; + float PrePadding_ShadowDepthPass_LPV_112; + float PrePadding_ShadowDepthPass_LPV_116; + float PrePadding_ShadowDepthPass_LPV_120; + float PrePadding_ShadowDepthPass_LPV_124; + float PrePadding_ShadowDepthPass_LPV_128; + float PrePadding_ShadowDepthPass_LPV_132; + float PrePadding_ShadowDepthPass_LPV_136; + float PrePadding_ShadowDepthPass_LPV_140; + float PrePadding_ShadowDepthPass_LPV_144; + float PrePadding_ShadowDepthPass_LPV_148; + float PrePadding_ShadowDepthPass_LPV_152; + float PrePadding_ShadowDepthPass_LPV_156; + float PrePadding_ShadowDepthPass_LPV_160; + float PrePadding_ShadowDepthPass_LPV_164; + float PrePadding_ShadowDepthPass_LPV_168; + float PrePadding_ShadowDepthPass_LPV_172; + float PrePadding_ShadowDepthPass_LPV_176; + float PrePadding_ShadowDepthPass_LPV_180; + float PrePadding_ShadowDepthPass_LPV_184; + float PrePadding_ShadowDepthPass_LPV_188; + float PrePadding_ShadowDepthPass_LPV_192; + float PrePadding_ShadowDepthPass_LPV_196; + float PrePadding_ShadowDepthPass_LPV_200; + float PrePadding_ShadowDepthPass_LPV_204; + float PrePadding_ShadowDepthPass_LPV_208; + float PrePadding_ShadowDepthPass_LPV_212; + float PrePadding_ShadowDepthPass_LPV_216; + float PrePadding_ShadowDepthPass_LPV_220; + float PrePadding_ShadowDepthPass_LPV_224; + float PrePadding_ShadowDepthPass_LPV_228; + float PrePadding_ShadowDepthPass_LPV_232; + float PrePadding_ShadowDepthPass_LPV_236; + float PrePadding_ShadowDepthPass_LPV_240; + float PrePadding_ShadowDepthPass_LPV_244; + float PrePadding_ShadowDepthPass_LPV_248; + float PrePadding_ShadowDepthPass_LPV_252; + float PrePadding_ShadowDepthPass_LPV_256; + float PrePadding_ShadowDepthPass_LPV_260; + float PrePadding_ShadowDepthPass_LPV_264; + float PrePadding_ShadowDepthPass_LPV_268; + float4x4 ShadowDepthPass_LPV_mRsmToWorld; + float4 ShadowDepthPass_LPV_mLightColour; + float4 ShadowDepthPass_LPV_GeometryVolumeCaptureLightDirection; + float4 ShadowDepthPass_LPV_mEyePos; + packed_int3 ShadowDepthPass_LPV_mOldGridOffset; + int PrePadding_ShadowDepthPass_LPV_396; + packed_int3 ShadowDepthPass_LPV_mLpvGridOffset; + float ShadowDepthPass_LPV_ClearMultiplier; + float ShadowDepthPass_LPV_LpvScale; + float ShadowDepthPass_LPV_OneOverLpvScale; + float ShadowDepthPass_LPV_DirectionalOcclusionIntensity; + float ShadowDepthPass_LPV_DirectionalOcclusionRadius; + float ShadowDepthPass_LPV_RsmAreaIntensityMultiplier; + float ShadowDepthPass_LPV_RsmPixelToTexcoordMultiplier; + float ShadowDepthPass_LPV_SecondaryOcclusionStrength; + float ShadowDepthPass_LPV_SecondaryBounceStrength; + float ShadowDepthPass_LPV_VplInjectionBias; + float ShadowDepthPass_LPV_GeometryVolumeInjectionBias; + float ShadowDepthPass_LPV_EmissiveInjectionMultiplier; + int ShadowDepthPass_LPV_PropagationIndex; + float4x4 ShadowDepthPass_ProjectionMatrix; + float4x4 ShadowDepthPass_ViewMatrix; + float4 ShadowDepthPass_ShadowParams; + float ShadowDepthPass_bClampToNearPlane; + float PrePadding_ShadowDepthPass_612; + float PrePadding_ShadowDepthPass_616; + float PrePadding_ShadowDepthPass_620; + float4x4 ShadowDepthPass_ShadowViewProjectionMatrices[6]; + float4x4 ShadowDepthPass_ShadowViewMatrices[6]; +}; + +constant float4 _90 = {}; + +struct main0_out +{ + float4 out_var_TEXCOORD10_centroid [[user(locn0)]]; + float4 out_var_TEXCOORD11_centroid [[user(locn1)]]; + float out_var_TEXCOORD6 [[user(locn2)]]; + float3 out_var_TEXCOORD7 [[user(locn3)]]; + float4 gl_Position [[position]]; +}; + +struct main0_in +{ + float4 in_var_PN_POSITION_0 [[attribute(10)]]; + float4 in_var_PN_POSITION_1 [[attribute(11)]]; + float4 in_var_PN_POSITION_2 [[attribute(12)]]; + float4 in_var_TEXCOORD10_centroid [[attribute(16)]]; + float4 in_var_TEXCOORD11_centroid [[attribute(17)]]; +}; + +struct main0_patchIn +{ + float4 in_var_PN_POSITION9 [[attribute(13)]]; + patch_control_point gl_in; +}; + +[[ patch(triangle, 0) ]] vertex main0_out main0(main0_patchIn patchIn [[stage_in]], constant type_ShadowDepthPass& ShadowDepthPass [[buffer(0)]], float3 gl_TessCoord [[position_in_patch]]) +{ + main0_out out = {}; + spvUnsafeArray _93 = spvUnsafeArray({ patchIn.gl_in[0].in_var_TEXCOORD10_centroid, patchIn.gl_in[1].in_var_TEXCOORD10_centroid, patchIn.gl_in[2].in_var_TEXCOORD10_centroid }); + spvUnsafeArray _94 = spvUnsafeArray({ patchIn.gl_in[0].in_var_TEXCOORD11_centroid, patchIn.gl_in[1].in_var_TEXCOORD11_centroid, patchIn.gl_in[2].in_var_TEXCOORD11_centroid }); + spvUnsafeArray, 3> _101 = spvUnsafeArray, 3>({ spvUnsafeArray({ patchIn.gl_in[0].in_var_PN_POSITION_0, patchIn.gl_in[0].in_var_PN_POSITION_1, patchIn.gl_in[0].in_var_PN_POSITION_2 }), spvUnsafeArray({ patchIn.gl_in[1].in_var_PN_POSITION_0, patchIn.gl_in[1].in_var_PN_POSITION_1, patchIn.gl_in[1].in_var_PN_POSITION_2 }), spvUnsafeArray({ patchIn.gl_in[2].in_var_PN_POSITION_0, patchIn.gl_in[2].in_var_PN_POSITION_1, patchIn.gl_in[2].in_var_PN_POSITION_2 }) }); + float _119 = gl_TessCoord.x * gl_TessCoord.x; + float _120 = gl_TessCoord.y * gl_TessCoord.y; + float _121 = gl_TessCoord.z * gl_TessCoord.z; + float4 _127 = float4(gl_TessCoord.x); + float4 _131 = float4(gl_TessCoord.y); + float4 _136 = float4(gl_TessCoord.z); + float4 _139 = float4(_119 * 3.0); + float4 _143 = float4(_120 * 3.0); + float4 _150 = float4(_121 * 3.0); + float4 _164 = ((((((((((_101[0][0] * float4(_119)) * _127) + ((_101[1][0] * float4(_120)) * _131)) + ((_101[2][0] * float4(_121)) * _136)) + ((_101[0][1] * _139) * _131)) + ((_101[0][2] * _143) * _127)) + ((_101[1][1] * _143) * _136)) + ((_101[1][2] * _150) * _131)) + ((_101[2][1] * _150) * _127)) + ((_101[2][2] * _139) * _136)) + ((((patchIn.in_var_PN_POSITION9 * float4(6.0)) * _136) * _127) * _131); + float3 _179 = ((_93[0].xyz * float3(gl_TessCoord.x)) + (_93[1].xyz * float3(gl_TessCoord.y))).xyz + (_93[2].xyz * float3(gl_TessCoord.z)); + float4 _182 = ((_94[0] * _127) + (_94[1] * _131)) + (_94[2] * _136); + float4x4 _92 = ShadowDepthPass.ShadowDepthPass_ViewMatrix; + float4 _189 = ShadowDepthPass.ShadowDepthPass_ProjectionMatrix * float4(_164.x, _164.y, _164.z, _164.w); + float4 _200; + if ((ShadowDepthPass.ShadowDepthPass_bClampToNearPlane > 0.0) && (_189.z < 0.0)) + { + float4 _198 = _189; + _198.z = 9.9999999747524270787835121154785e-07; + float4 _199 = _198; + _199.w = 1.0; + _200 = _199; + } + else + { + _200 = _189; + } + float _209 = abs(dot(float3(_92[0u].z, _92[1u].z, _92[2u].z), _182.xyz)); + float4 _234 = _200; + _234.z = ((_200.z * ShadowDepthPass.ShadowDepthPass_ShadowParams.w) + ((ShadowDepthPass.ShadowDepthPass_ShadowParams.y * fast::clamp((abs(_209) > 0.0) ? (sqrt(fast::clamp(1.0 - (_209 * _209), 0.0, 1.0)) / _209) : ShadowDepthPass.ShadowDepthPass_ShadowParams.z, 0.0, ShadowDepthPass.ShadowDepthPass_ShadowParams.z)) + ShadowDepthPass.ShadowDepthPass_ShadowParams.x)) * _200.w; + out.out_var_TEXCOORD10_centroid = float4(_179.x, _179.y, _179.z, _90.w); + out.out_var_TEXCOORD11_centroid = _182; + out.out_var_TEXCOORD6 = 0.0; + out.out_var_TEXCOORD7 = _164.xyz; + out.gl_Position = _234; + return out; +} + diff --git a/third_party/spirv-cross/reference/shaders-ue4/asm/tese/ds-texcoord-array.asm.tese b/third_party/spirv-cross/reference/shaders-ue4/asm/tese/ds-texcoord-array.asm.tese new file mode 100644 index 0000000000..346d7e3fc9 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-ue4/asm/tese/ds-texcoord-array.asm.tese @@ -0,0 +1,318 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + +#include +#include + +using namespace metal; + +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +struct type_View +{ + float4x4 View_TranslatedWorldToClip; + float4x4 View_WorldToClip; + float4x4 View_ClipToWorld; + float4x4 View_TranslatedWorldToView; + float4x4 View_ViewToTranslatedWorld; + float4x4 View_TranslatedWorldToCameraView; + float4x4 View_CameraViewToTranslatedWorld; + float4x4 View_ViewToClip; + float4x4 View_ViewToClipNoAA; + float4x4 View_ClipToView; + float4x4 View_ClipToTranslatedWorld; + float4x4 View_SVPositionToTranslatedWorld; + float4x4 View_ScreenToWorld; + float4x4 View_ScreenToTranslatedWorld; + packed_float3 View_ViewForward; + float PrePadding_View_908; + packed_float3 View_ViewUp; + float PrePadding_View_924; + packed_float3 View_ViewRight; + float PrePadding_View_940; + packed_float3 View_HMDViewNoRollUp; + float PrePadding_View_956; + packed_float3 View_HMDViewNoRollRight; + float PrePadding_View_972; + float4 View_InvDeviceZToWorldZTransform; + float4 View_ScreenPositionScaleBias; + packed_float3 View_WorldCameraOrigin; + float PrePadding_View_1020; + packed_float3 View_TranslatedWorldCameraOrigin; + float PrePadding_View_1036; + packed_float3 View_WorldViewOrigin; + float PrePadding_View_1052; + packed_float3 View_PreViewTranslation; + float PrePadding_View_1068; + float4x4 View_PrevProjection; + float4x4 View_PrevViewProj; + float4x4 View_PrevViewRotationProj; + float4x4 View_PrevViewToClip; + float4x4 View_PrevClipToView; + float4x4 View_PrevTranslatedWorldToClip; + float4x4 View_PrevTranslatedWorldToView; + float4x4 View_PrevViewToTranslatedWorld; + float4x4 View_PrevTranslatedWorldToCameraView; + float4x4 View_PrevCameraViewToTranslatedWorld; + packed_float3 View_PrevWorldCameraOrigin; + float PrePadding_View_1724; + packed_float3 View_PrevWorldViewOrigin; + float PrePadding_View_1740; + packed_float3 View_PrevPreViewTranslation; + float PrePadding_View_1756; + float4x4 View_PrevInvViewProj; + float4x4 View_PrevScreenToTranslatedWorld; + float4x4 View_ClipToPrevClip; + float4 View_TemporalAAJitter; + float4 View_GlobalClippingPlane; + float2 View_FieldOfViewWideAngles; + float2 View_PrevFieldOfViewWideAngles; + float4 View_ViewRectMin; + float4 View_ViewSizeAndInvSize; + float4 View_BufferSizeAndInvSize; + float4 View_BufferBilinearUVMinMax; + int View_NumSceneColorMSAASamples; + float View_PreExposure; + float View_OneOverPreExposure; + float PrePadding_View_2076; + float4 View_DiffuseOverrideParameter; + float4 View_SpecularOverrideParameter; + float4 View_NormalOverrideParameter; + float2 View_RoughnessOverrideParameter; + float View_PrevFrameGameTime; + float View_PrevFrameRealTime; + float View_OutOfBoundsMask; + float PrePadding_View_2148; + float PrePadding_View_2152; + float PrePadding_View_2156; + packed_float3 View_WorldCameraMovementSinceLastFrame; + float View_CullingSign; + float View_NearPlane; + float View_AdaptiveTessellationFactor; + float View_GameTime; + float View_RealTime; + float View_DeltaTime; + float View_MaterialTextureMipBias; + float View_MaterialTextureDerivativeMultiply; + uint View_Random; + uint View_FrameNumber; + uint View_StateFrameIndexMod8; + uint View_StateFrameIndex; + float View_CameraCut; + float View_UnlitViewmodeMask; + float PrePadding_View_2228; + float PrePadding_View_2232; + float PrePadding_View_2236; + float4 View_DirectionalLightColor; + packed_float3 View_DirectionalLightDirection; + float PrePadding_View_2268; + float4 View_TranslucencyLightingVolumeMin[2]; + float4 View_TranslucencyLightingVolumeInvSize[2]; + float4 View_TemporalAAParams; + float4 View_CircleDOFParams; + float View_DepthOfFieldSensorWidth; + float View_DepthOfFieldFocalDistance; + float View_DepthOfFieldScale; + float View_DepthOfFieldFocalLength; + float View_DepthOfFieldFocalRegion; + float View_DepthOfFieldNearTransitionRegion; + float View_DepthOfFieldFarTransitionRegion; + float View_MotionBlurNormalizedToPixel; + float View_bSubsurfacePostprocessEnabled; + float View_GeneralPurposeTweak; + float View_DemosaicVposOffset; + float PrePadding_View_2412; + packed_float3 View_IndirectLightingColorScale; + float View_HDR32bppEncodingMode; + packed_float3 View_AtmosphericFogSunDirection; + float View_AtmosphericFogSunPower; + float View_AtmosphericFogPower; + float View_AtmosphericFogDensityScale; + float View_AtmosphericFogDensityOffset; + float View_AtmosphericFogGroundOffset; + float View_AtmosphericFogDistanceScale; + float View_AtmosphericFogAltitudeScale; + float View_AtmosphericFogHeightScaleRayleigh; + float View_AtmosphericFogStartDistance; + float View_AtmosphericFogDistanceOffset; + float View_AtmosphericFogSunDiscScale; + float View_AtmosphericFogSunDiscHalfApexAngleRadian; + float PrePadding_View_2492; + float4 View_AtmosphericFogSunDiscLuminance; + uint View_AtmosphericFogRenderMask; + uint View_AtmosphericFogInscatterAltitudeSampleNum; + uint PrePadding_View_2520; + uint PrePadding_View_2524; + float4 View_AtmosphericFogSunColor; + packed_float3 View_NormalCurvatureToRoughnessScaleBias; + float View_RenderingReflectionCaptureMask; + float4 View_AmbientCubemapTint; + float View_AmbientCubemapIntensity; + float View_SkyLightParameters; + float PrePadding_View_2584; + float PrePadding_View_2588; + float4 View_SkyLightColor; + float4 View_SkyIrradianceEnvironmentMap[7]; + float View_MobilePreviewMode; + float View_HMDEyePaddingOffset; + float View_ReflectionCubemapMaxMip; + float View_ShowDecalsMask; + uint View_DistanceFieldAOSpecularOcclusionMode; + float View_IndirectCapsuleSelfShadowingIntensity; + float PrePadding_View_2744; + float PrePadding_View_2748; + packed_float3 View_ReflectionEnvironmentRoughnessMixingScaleBiasAndLargestWeight; + int View_StereoPassIndex; + float4 View_GlobalVolumeCenterAndExtent[4]; + float4 View_GlobalVolumeWorldToUVAddAndMul[4]; + float View_GlobalVolumeDimension; + float View_GlobalVolumeTexelSize; + float View_MaxGlobalDistance; + float PrePadding_View_2908; + int2 View_CursorPosition; + float View_bCheckerboardSubsurfaceProfileRendering; + float PrePadding_View_2924; + packed_float3 View_VolumetricFogInvGridSize; + float PrePadding_View_2940; + packed_float3 View_VolumetricFogGridZParams; + float PrePadding_View_2956; + float2 View_VolumetricFogSVPosToVolumeUV; + float View_VolumetricFogMaxDistance; + float PrePadding_View_2972; + packed_float3 View_VolumetricLightmapWorldToUVScale; + float PrePadding_View_2988; + packed_float3 View_VolumetricLightmapWorldToUVAdd; + float PrePadding_View_3004; + packed_float3 View_VolumetricLightmapIndirectionTextureSize; + float View_VolumetricLightmapBrickSize; + packed_float3 View_VolumetricLightmapBrickTexelSize; + float View_StereoIPD; + float View_IndirectLightingCacheShowFlag; + float View_EyeToPixelSpreadAngle; + float PrePadding_View_3048; + float PrePadding_View_3052; + float4x4 View_WorldToVirtualTexture; + float4 View_VirtualTextureParams; + float4 View_XRPassthroughCameraUVs[2]; +}; + +constant float4 _68 = {}; + +struct main0_out +{ + float4 out_var_TEXCOORD10_centroid [[user(locn0)]]; + float4 out_var_TEXCOORD11_centroid [[user(locn1)]]; + float4 out_var_TEXCOORD0_0 [[user(locn2)]]; + float4 out_var_COLOR1 [[user(locn3)]]; + float4 out_var_COLOR2 [[user(locn4)]]; + float4 out_var_TEXCOORD6 [[user(locn5)]]; + float3 out_var_TEXCOORD7 [[user(locn6)]]; + float4 gl_Position [[position]]; +}; + +struct main0_in +{ + float4 in_var_COLOR1 [[attribute(0)]]; + float4 in_var_COLOR2 [[attribute(1)]]; + float4 in_var_TEXCOORD0_0 [[attribute(5)]]; + float4 in_var_TEXCOORD10_centroid [[attribute(6)]]; + float4 in_var_TEXCOORD11_centroid [[attribute(7)]]; + float3 in_var_TEXCOORD7 [[attribute(8)]]; + float4 in_var_VS_To_DS_Position [[attribute(9)]]; +}; + +struct main0_patchIn +{ + patch_control_point gl_in; +}; + +[[ patch(triangle, 0) ]] vertex main0_out main0(main0_patchIn patchIn [[stage_in]], constant type_View& View [[buffer(0)]], float3 gl_TessCoord [[position_in_patch]]) +{ + main0_out out = {}; + spvUnsafeArray out_var_TEXCOORD0 = {}; + spvUnsafeArray _77 = spvUnsafeArray({ patchIn.gl_in[0].in_var_TEXCOORD10_centroid, patchIn.gl_in[1].in_var_TEXCOORD10_centroid, patchIn.gl_in[2].in_var_TEXCOORD10_centroid }); + spvUnsafeArray _78 = spvUnsafeArray({ patchIn.gl_in[0].in_var_TEXCOORD11_centroid, patchIn.gl_in[1].in_var_TEXCOORD11_centroid, patchIn.gl_in[2].in_var_TEXCOORD11_centroid }); + spvUnsafeArray, 3> _79 = spvUnsafeArray, 3>({ spvUnsafeArray({ patchIn.gl_in[0].in_var_TEXCOORD0_0 }), spvUnsafeArray({ patchIn.gl_in[1].in_var_TEXCOORD0_0 }), spvUnsafeArray({ patchIn.gl_in[2].in_var_TEXCOORD0_0 }) }); + spvUnsafeArray _80 = spvUnsafeArray({ patchIn.gl_in[0].in_var_COLOR1, patchIn.gl_in[1].in_var_COLOR1, patchIn.gl_in[2].in_var_COLOR1 }); + spvUnsafeArray _81 = spvUnsafeArray({ patchIn.gl_in[0].in_var_COLOR2, patchIn.gl_in[1].in_var_COLOR2, patchIn.gl_in[2].in_var_COLOR2 }); + spvUnsafeArray _97 = spvUnsafeArray({ patchIn.gl_in[0].in_var_VS_To_DS_Position, patchIn.gl_in[1].in_var_VS_To_DS_Position, patchIn.gl_in[2].in_var_VS_To_DS_Position }); + spvUnsafeArray _98 = spvUnsafeArray({ patchIn.gl_in[0].in_var_TEXCOORD7, patchIn.gl_in[1].in_var_TEXCOORD7, patchIn.gl_in[2].in_var_TEXCOORD7 }); + float4 _111 = float4(gl_TessCoord.x); + float4 _113 = float4(gl_TessCoord.y); + float4 _116 = float4(gl_TessCoord.z); + float4 _118 = ((_97[0] * _111) + (_97[1] * _113)) + (_97[2] * _116); + spvUnsafeArray _72; + _72 = _79[0]; + spvUnsafeArray _71; + _71 = _79[1]; + float3 _120 = float3(gl_TessCoord.x); + float3 _123 = float3(gl_TessCoord.y); + spvUnsafeArray _73; + for (int _133 = 0; _133 < 1; ) + { + _73[_133] = (_72[_133] * _111) + (_71[_133] * _113); + _133++; + continue; + } + spvUnsafeArray _75; + _75 = _73; + spvUnsafeArray _74; + _74 = _79[2]; + float3 _155 = float3(gl_TessCoord.z); + float3 _157 = ((_77[0].xyz * _120) + (_77[1].xyz * _123)).xyz + (_77[2].xyz * _155); + spvUnsafeArray _76; + for (int _164 = 0; _164 < 1; ) + { + _76[_164] = _75[_164] + (_74[_164] * _116); + _164++; + continue; + } + float4 _181 = float4(_118.x, _118.y, _118.z, _118.w); + out.out_var_TEXCOORD10_centroid = float4(_157.x, _157.y, _157.z, _68.w); + out.out_var_TEXCOORD11_centroid = ((_78[0] * _111) + (_78[1] * _113)) + (_78[2] * _116); + out_var_TEXCOORD0 = _76; + out.out_var_COLOR1 = ((_80[0] * _111) + (_80[1] * _113)) + (_80[2] * _116); + out.out_var_COLOR2 = ((_81[0] * _111) + (_81[1] * _113)) + (_81[2] * _116); + out.out_var_TEXCOORD6 = _181; + out.out_var_TEXCOORD7 = ((_98[0] * _120) + (_98[1] * _123)) + (_98[2] * _155); + out.gl_Position = View.View_TranslatedWorldToClip * _181; + out.out_var_TEXCOORD0_0 = out_var_TEXCOORD0[0]; + return out; +} + diff --git a/third_party/spirv-cross/reference/shaders-ue4/asm/vert/array-missing-copies.asm.vert b/third_party/spirv-cross/reference/shaders-ue4/asm/vert/array-missing-copies.asm.vert new file mode 100644 index 0000000000..3d3e0e51f5 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-ue4/asm/vert/array-missing-copies.asm.vert @@ -0,0 +1,466 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#pragma clang diagnostic ignored "-Wmissing-braces" + +#include +#include + +using namespace metal; + +template +struct spvUnsafeArray +{ + T elements[Num ? Num : 1]; + + thread T& operator [] (size_t pos) thread + { + return elements[pos]; + } + constexpr const thread T& operator [] (size_t pos) const thread + { + return elements[pos]; + } + + device T& operator [] (size_t pos) device + { + return elements[pos]; + } + constexpr const device T& operator [] (size_t pos) const device + { + return elements[pos]; + } + + constexpr const constant T& operator [] (size_t pos) const constant + { + return elements[pos]; + } + + threadgroup T& operator [] (size_t pos) threadgroup + { + return elements[pos]; + } + constexpr const threadgroup T& operator [] (size_t pos) const threadgroup + { + return elements[pos]; + } +}; + +struct type_View +{ + float4x4 View_TranslatedWorldToClip; + float4x4 View_WorldToClip; + float4x4 View_TranslatedWorldToView; + float4x4 View_ViewToTranslatedWorld; + float4x4 View_TranslatedWorldToCameraView; + float4x4 View_CameraViewToTranslatedWorld; + float4x4 View_ViewToClip; + float4x4 View_ViewToClipNoAA; + float4x4 View_ClipToView; + float4x4 View_ClipToTranslatedWorld; + float4x4 View_SVPositionToTranslatedWorld; + float4x4 View_ScreenToWorld; + float4x4 View_ScreenToTranslatedWorld; + packed_float3 View_ViewForward; + float PrePadding_View_844; + packed_float3 View_ViewUp; + float PrePadding_View_860; + packed_float3 View_ViewRight; + float PrePadding_View_876; + packed_float3 View_HMDViewNoRollUp; + float PrePadding_View_892; + packed_float3 View_HMDViewNoRollRight; + float PrePadding_View_908; + float4 View_InvDeviceZToWorldZTransform; + float4 View_ScreenPositionScaleBias; + packed_float3 View_WorldCameraOrigin; + float PrePadding_View_956; + packed_float3 View_TranslatedWorldCameraOrigin; + float PrePadding_View_972; + packed_float3 View_WorldViewOrigin; + float PrePadding_View_988; + packed_float3 View_PreViewTranslation; + float PrePadding_View_1004; + float4x4 View_PrevProjection; + float4x4 View_PrevViewProj; + float4x4 View_PrevViewRotationProj; + float4x4 View_PrevViewToClip; + float4x4 View_PrevClipToView; + float4x4 View_PrevTranslatedWorldToClip; + float4x4 View_PrevTranslatedWorldToView; + float4x4 View_PrevViewToTranslatedWorld; + float4x4 View_PrevTranslatedWorldToCameraView; + float4x4 View_PrevCameraViewToTranslatedWorld; + packed_float3 View_PrevWorldCameraOrigin; + float PrePadding_View_1660; + packed_float3 View_PrevWorldViewOrigin; + float PrePadding_View_1676; + packed_float3 View_PrevPreViewTranslation; + float PrePadding_View_1692; + float4x4 View_PrevInvViewProj; + float4x4 View_PrevScreenToTranslatedWorld; + float4x4 View_ClipToPrevClip; + float4 View_TemporalAAJitter; + float4 View_GlobalClippingPlane; + float2 View_FieldOfViewWideAngles; + float2 View_PrevFieldOfViewWideAngles; + float4 View_ViewRectMin; + float4 View_ViewSizeAndInvSize; + float4 View_BufferSizeAndInvSize; + float4 View_BufferBilinearUVMinMax; + int View_NumSceneColorMSAASamples; + float View_PreExposure; + float View_OneOverPreExposure; + float PrePadding_View_2012; + float4 View_DiffuseOverrideParameter; + float4 View_SpecularOverrideParameter; + float4 View_NormalOverrideParameter; + float2 View_RoughnessOverrideParameter; + float View_PrevFrameGameTime; + float View_PrevFrameRealTime; + float View_OutOfBoundsMask; + float PrePadding_View_2084; + float PrePadding_View_2088; + float PrePadding_View_2092; + packed_float3 View_WorldCameraMovementSinceLastFrame; + float View_CullingSign; + float View_NearPlane; + float View_AdaptiveTessellationFactor; + float View_GameTime; + float View_RealTime; + float View_DeltaTime; + float View_MaterialTextureMipBias; + float View_MaterialTextureDerivativeMultiply; + uint View_Random; + uint View_FrameNumber; + uint View_StateFrameIndexMod8; + uint View_StateFrameIndex; + float View_CameraCut; + float View_UnlitViewmodeMask; + float PrePadding_View_2164; + float PrePadding_View_2168; + float PrePadding_View_2172; + float4 View_DirectionalLightColor; + packed_float3 View_DirectionalLightDirection; + float PrePadding_View_2204; + float4 View_TranslucencyLightingVolumeMin[2]; + float4 View_TranslucencyLightingVolumeInvSize[2]; + float4 View_TemporalAAParams; + float4 View_CircleDOFParams; + float View_DepthOfFieldSensorWidth; + float View_DepthOfFieldFocalDistance; + float View_DepthOfFieldScale; + float View_DepthOfFieldFocalLength; + float View_DepthOfFieldFocalRegion; + float View_DepthOfFieldNearTransitionRegion; + float View_DepthOfFieldFarTransitionRegion; + float View_MotionBlurNormalizedToPixel; + float View_bSubsurfacePostprocessEnabled; + float View_GeneralPurposeTweak; + float View_DemosaicVposOffset; + float PrePadding_View_2348; + packed_float3 View_IndirectLightingColorScale; + float View_HDR32bppEncodingMode; + packed_float3 View_AtmosphericFogSunDirection; + float View_AtmosphericFogSunPower; + float View_AtmosphericFogPower; + float View_AtmosphericFogDensityScale; + float View_AtmosphericFogDensityOffset; + float View_AtmosphericFogGroundOffset; + float View_AtmosphericFogDistanceScale; + float View_AtmosphericFogAltitudeScale; + float View_AtmosphericFogHeightScaleRayleigh; + float View_AtmosphericFogStartDistance; + float View_AtmosphericFogDistanceOffset; + float View_AtmosphericFogSunDiscScale; + uint View_AtmosphericFogRenderMask; + uint View_AtmosphericFogInscatterAltitudeSampleNum; + float4 View_AtmosphericFogSunColor; + packed_float3 View_NormalCurvatureToRoughnessScaleBias; + float View_RenderingReflectionCaptureMask; + float4 View_AmbientCubemapTint; + float View_AmbientCubemapIntensity; + float View_SkyLightParameters; + float PrePadding_View_2488; + float PrePadding_View_2492; + float4 View_SkyLightColor; + float4 View_SkyIrradianceEnvironmentMap[7]; + float View_MobilePreviewMode; + float View_HMDEyePaddingOffset; + float View_ReflectionCubemapMaxMip; + float View_ShowDecalsMask; + uint View_DistanceFieldAOSpecularOcclusionMode; + float View_IndirectCapsuleSelfShadowingIntensity; + float PrePadding_View_2648; + float PrePadding_View_2652; + packed_float3 View_ReflectionEnvironmentRoughnessMixingScaleBiasAndLargestWeight; + int View_StereoPassIndex; + float4 View_GlobalVolumeCenterAndExtent[4]; + float4 View_GlobalVolumeWorldToUVAddAndMul[4]; + float View_GlobalVolumeDimension; + float View_GlobalVolumeTexelSize; + float View_MaxGlobalDistance; + float View_bCheckerboardSubsurfaceProfileRendering; + packed_float3 View_VolumetricFogInvGridSize; + float PrePadding_View_2828; + packed_float3 View_VolumetricFogGridZParams; + float PrePadding_View_2844; + float2 View_VolumetricFogSVPosToVolumeUV; + float View_VolumetricFogMaxDistance; + float PrePadding_View_2860; + packed_float3 View_VolumetricLightmapWorldToUVScale; + float PrePadding_View_2876; + packed_float3 View_VolumetricLightmapWorldToUVAdd; + float PrePadding_View_2892; + packed_float3 View_VolumetricLightmapIndirectionTextureSize; + float View_VolumetricLightmapBrickSize; + packed_float3 View_VolumetricLightmapBrickTexelSize; + float View_StereoIPD; + float View_IndirectLightingCacheShowFlag; + float View_EyeToPixelSpreadAngle; +}; + +struct type_MobileBasePass +{ + float4 MobileBasePass_Fog_ExponentialFogParameters; + float4 MobileBasePass_Fog_ExponentialFogParameters2; + float4 MobileBasePass_Fog_ExponentialFogColorParameter; + float4 MobileBasePass_Fog_ExponentialFogParameters3; + float4 MobileBasePass_Fog_InscatteringLightDirection; + float4 MobileBasePass_Fog_DirectionalInscatteringColor; + float2 MobileBasePass_Fog_SinCosInscatteringColorCubemapRotation; + float PrePadding_MobileBasePass_Fog_104; + float PrePadding_MobileBasePass_Fog_108; + packed_float3 MobileBasePass_Fog_FogInscatteringTextureParameters; + float MobileBasePass_Fog_ApplyVolumetricFog; + float PrePadding_MobileBasePass_PlanarReflection_128; + float PrePadding_MobileBasePass_PlanarReflection_132; + float PrePadding_MobileBasePass_PlanarReflection_136; + float PrePadding_MobileBasePass_PlanarReflection_140; + float PrePadding_MobileBasePass_PlanarReflection_144; + float PrePadding_MobileBasePass_PlanarReflection_148; + float PrePadding_MobileBasePass_PlanarReflection_152; + float PrePadding_MobileBasePass_PlanarReflection_156; + float4 MobileBasePass_PlanarReflection_ReflectionPlane; + float4 MobileBasePass_PlanarReflection_PlanarReflectionOrigin; + float4 MobileBasePass_PlanarReflection_PlanarReflectionXAxis; + float4 MobileBasePass_PlanarReflection_PlanarReflectionYAxis; + float3x4 MobileBasePass_PlanarReflection_InverseTransposeMirrorMatrix; + packed_float3 MobileBasePass_PlanarReflection_PlanarReflectionParameters; + float PrePadding_MobileBasePass_PlanarReflection_284; + float2 MobileBasePass_PlanarReflection_PlanarReflectionParameters2; + float PrePadding_MobileBasePass_PlanarReflection_296; + float PrePadding_MobileBasePass_PlanarReflection_300; + float4x4 MobileBasePass_PlanarReflection_ProjectionWithExtraFOV[2]; + float4 MobileBasePass_PlanarReflection_PlanarReflectionScreenScaleBias[2]; + float2 MobileBasePass_PlanarReflection_PlanarReflectionScreenBound; + uint MobileBasePass_PlanarReflection_bIsStereo; +}; + +struct type_Primitive +{ + float4x4 Primitive_LocalToWorld; + float4 Primitive_InvNonUniformScaleAndDeterminantSign; + float4 Primitive_ObjectWorldPositionAndRadius; + float4x4 Primitive_WorldToLocal; + float4x4 Primitive_PreviousLocalToWorld; + float4x4 Primitive_PreviousWorldToLocal; + packed_float3 Primitive_ActorWorldPosition; + float Primitive_UseSingleSampleShadowFromStationaryLights; + packed_float3 Primitive_ObjectBounds; + float Primitive_LpvBiasMultiplier; + float Primitive_DecalReceiverMask; + float Primitive_PerObjectGBufferData; + float Primitive_UseVolumetricLightmapShadowFromStationaryLights; + float Primitive_UseEditorDepthTest; + float4 Primitive_ObjectOrientation; + float4 Primitive_NonUniformScale; + packed_float3 Primitive_LocalObjectBoundsMin; + float PrePadding_Primitive_380; + packed_float3 Primitive_LocalObjectBoundsMax; + uint Primitive_LightingChannelMask; + uint Primitive_LightmapDataIndex; + int Primitive_SingleCaptureIndex; +}; + +struct type_LandscapeParameters +{ + float4 LandscapeParameters_HeightmapUVScaleBias; + float4 LandscapeParameters_WeightmapUVScaleBias; + float4 LandscapeParameters_LandscapeLightmapScaleBias; + float4 LandscapeParameters_SubsectionSizeVertsLayerUVPan; + float4 LandscapeParameters_SubsectionOffsetParams; + float4 LandscapeParameters_LightmapSubsectionOffsetParams; + float4x4 LandscapeParameters_LocalToWorldNoScaling; +}; + +struct type_Globals +{ + float4 LodBias; + float4 LodValues; + float4 SectionLods; + float4 NeighborSectionLod[4]; +}; + +struct main0_out +{ + float2 out_var_TEXCOORD0 [[user(locn0)]]; + float2 out_var_TEXCOORD1 [[user(locn1)]]; + float4 out_var_TEXCOORD2 [[user(locn2)]]; + float4 out_var_TEXCOORD3 [[user(locn3)]]; + float4 out_var_TEXCOORD8 [[user(locn4)]]; + float4 gl_Position [[position]]; +}; + +struct main0_in +{ + float4 in_var_ATTRIBUTE0 [[attribute(0)]]; + float4 in_var_ATTRIBUTE1_0 [[attribute(1)]]; + float4 in_var_ATTRIBUTE1_1 [[attribute(2)]]; +}; + +vertex main0_out main0(main0_in in [[stage_in]], constant type_View& View [[buffer(0)]], constant type_MobileBasePass& MobileBasePass [[buffer(1)]], constant type_Primitive& Primitive [[buffer(2)]], constant type_LandscapeParameters& LandscapeParameters [[buffer(3)]], constant type_Globals& _Globals [[buffer(4)]]) +{ + main0_out out = {}; + spvUnsafeArray in_var_ATTRIBUTE1 = {}; + in_var_ATTRIBUTE1[0] = in.in_var_ATTRIBUTE1_0; + in_var_ATTRIBUTE1[1] = in.in_var_ATTRIBUTE1_1; + spvUnsafeArray _97; + for (int _107 = 0; _107 < 1; ) + { + _97[_107] = float4(0.0); + _107++; + continue; + } + float4 _115 = in.in_var_ATTRIBUTE0 * float4(255.0); + float2 _116 = _115.zw; + float2 _119 = fract(_116 * float2(0.5)) * float2(2.0); + float2 _121 = (_116 - _119) * float2(0.0039215688593685626983642578125); + float2 _122 = _115.xy; + float2 _126 = _122 * float2(_Globals.LodValues.w); + float _127 = _126.y; + float _128 = _126.x; + float4 _132 = float4(_127, _128, 1.0 - _128, 1.0 - _127) * float4(2.0); + float4 _186; + if (_119.y > 0.5) + { + float4 _161; + if (_119.x > 0.5) + { + _161 = (_132 * float4(_Globals.SectionLods.w)) + ((float4(1.0) - _132) * _Globals.NeighborSectionLod[3]); + } + else + { + _161 = (_132 * float4(_Globals.SectionLods.z)) + ((float4(1.0) - _132) * _Globals.NeighborSectionLod[2]); + } + _186 = _161; + } + else + { + float4 _185; + if (_119.x > 0.5) + { + _185 = (_132 * float4(_Globals.SectionLods.y)) + ((float4(1.0) - _132) * _Globals.NeighborSectionLod[1]); + } + else + { + _185 = (_132 * float4(_Globals.SectionLods.x)) + ((float4(1.0) - _132) * _Globals.NeighborSectionLod[0]); + } + _186 = _185; + } + float _206; + if ((_128 + _127) > 1.0) + { + float _198; + if (_128 < _127) + { + _198 = _186.w; + } + else + { + _198 = _186.z; + } + _206 = _198; + } + else + { + float _205; + if (_128 < _127) + { + _205 = _186.y; + } + else + { + _205 = _186.x; + } + _206 = _205; + } + float _207 = floor(_206); + float _220 = _121.x; + float3 _235 = select(select(select(select(select(float3(0.03125, _121.yy), float3(0.0625, _220, _121.y), bool3(_207 < 5.0)), float3(0.125, in_var_ATTRIBUTE1[1].w, _220), bool3(_207 < 4.0)), float3(0.25, in_var_ATTRIBUTE1[1].zw), bool3(_207 < 3.0)), float3(0.5, in_var_ATTRIBUTE1[1].yz), bool3(_207 < 2.0)), float3(1.0, in_var_ATTRIBUTE1[1].xy), bool3(_207 < 1.0)); + float _236 = _235.x; + float _245 = (((in_var_ATTRIBUTE1[0].x * 65280.0) + (in_var_ATTRIBUTE1[0].y * 255.0)) - 32768.0) * 0.0078125; + float _252 = (((in_var_ATTRIBUTE1[0].z * 65280.0) + (in_var_ATTRIBUTE1[0].w * 255.0)) - 32768.0) * 0.0078125; + float2 _257 = floor(_122 * float2(_236)); + float2 _271 = float2((LandscapeParameters.LandscapeParameters_SubsectionSizeVertsLayerUVPan.x * _236) - 1.0, fast::max((LandscapeParameters.LandscapeParameters_SubsectionSizeVertsLayerUVPan.x * 0.5) * _236, 2.0) - 1.0) * float2(LandscapeParameters.LandscapeParameters_SubsectionSizeVertsLayerUVPan.y); + float3 _287 = mix(float3(_257 / float2(_271.x), mix(_245, _252, _235.y)), float3(floor(_257 * float2(0.5)) / float2(_271.y), mix(_245, _252, _235.z)), float3(_206 - _207)); + float2 _288 = _119.xy; + float2 _292 = _288 * LandscapeParameters.LandscapeParameters_SubsectionOffsetParams.ww; + float3 _296 = _287 + float3(_292, 0.0); + float4 _322 = float4((((Primitive.Primitive_LocalToWorld[0u].xyz * _296.xxx) + (Primitive.Primitive_LocalToWorld[1u].xyz * _296.yyy)) + (Primitive.Primitive_LocalToWorld[2u].xyz * _296.zzz)) + (Primitive.Primitive_LocalToWorld[3u].xyz + float3(View.View_PreViewTranslation)), 1.0); + float2 _323 = _287.xy; + float4 _338 = float4(_322.x, _322.y, _322.z, _322.w); + float4 _339 = View.View_TranslatedWorldToClip * _338; + float3 _341 = _322.xyz - float3(View.View_TranslatedWorldCameraOrigin); + float _345 = dot(_341, _341); + float _346 = rsqrt(_345); + float _347 = _345 * _346; + float _354 = _341.z; + float _357 = fast::max(0.0, MobileBasePass.MobileBasePass_Fog_ExponentialFogParameters.w); + float _393; + float _394; + float _395; + float _396; + if (_357 > 0.0) + { + float _361 = _357 * _346; + float _362 = _361 * _354; + float _365 = View.View_WorldCameraOrigin[2] + _362; + _393 = (1.0 - _361) * _347; + _394 = MobileBasePass.MobileBasePass_Fog_ExponentialFogParameters2.z * exp2(-fast::max(-127.0, MobileBasePass.MobileBasePass_Fog_ExponentialFogParameters2.y * (_365 - MobileBasePass.MobileBasePass_Fog_ExponentialFogParameters2.w))); + _395 = MobileBasePass.MobileBasePass_Fog_ExponentialFogParameters3.x * exp2(-fast::max(-127.0, MobileBasePass.MobileBasePass_Fog_ExponentialFogParameters.y * (_365 - MobileBasePass.MobileBasePass_Fog_ExponentialFogParameters3.y))); + _396 = _354 - _362; + } + else + { + _393 = _347; + _394 = MobileBasePass.MobileBasePass_Fog_ExponentialFogParameters2.x; + _395 = MobileBasePass.MobileBasePass_Fog_ExponentialFogParameters.x; + _396 = _354; + } + float _400 = fast::max(-127.0, MobileBasePass.MobileBasePass_Fog_ExponentialFogParameters.y * _396); + float _405 = log(2.0); + float _407 = 0.5 * (_405 * _405); + float _417 = fast::max(-127.0, MobileBasePass.MobileBasePass_Fog_ExponentialFogParameters2.y * _396); + float _428 = (_395 * ((abs(_400) > 0.00999999977648258209228515625) ? ((1.0 - exp2(-_400)) / _400) : (_405 - (_407 * _400)))) + (_394 * ((abs(_417) > 0.00999999977648258209228515625) ? ((1.0 - exp2(-_417)) / _417) : (_405 - (_407 * _417)))); + float3 _459; + if (MobileBasePass.MobileBasePass_Fog_InscatteringLightDirection.w >= 0.0) + { + _459 = (MobileBasePass.MobileBasePass_Fog_DirectionalInscatteringColor.xyz * float3(pow(fast::clamp(dot(_341 * float3(_346), MobileBasePass.MobileBasePass_Fog_InscatteringLightDirection.xyz), 0.0, 1.0), MobileBasePass.MobileBasePass_Fog_DirectionalInscatteringColor.w))) * float3(1.0 - fast::clamp(exp2(-(_428 * fast::max(_393 - MobileBasePass.MobileBasePass_Fog_InscatteringLightDirection.w, 0.0))), 0.0, 1.0)); + } + else + { + _459 = float3(0.0); + } + bool _468 = (MobileBasePass.MobileBasePass_Fog_ExponentialFogParameters3.w > 0.0) && (_347 > MobileBasePass.MobileBasePass_Fog_ExponentialFogParameters3.w); + float _471 = _468 ? 1.0 : fast::max(fast::clamp(exp2(-(_428 * _393)), 0.0, 1.0), MobileBasePass.MobileBasePass_Fog_ExponentialFogColorParameter.w); + _97[0] = float4((MobileBasePass.MobileBasePass_Fog_ExponentialFogColorParameter.xyz * float3(1.0 - _471)) + select(_459, float3(0.0), bool3(_468)), _471); + float4 _482 = _338; + _482.w = _339.w; + out.out_var_TEXCOORD0 = ((_323 + LandscapeParameters.LandscapeParameters_SubsectionSizeVertsLayerUVPan.zw) + _292).xy; + out.out_var_TEXCOORD1 = ((_323 * LandscapeParameters.LandscapeParameters_WeightmapUVScaleBias.xy) + LandscapeParameters.LandscapeParameters_WeightmapUVScaleBias.zw) + (_288 * LandscapeParameters.LandscapeParameters_SubsectionOffsetParams.zz); + out.out_var_TEXCOORD2 = float4(float4(0.0).x, float4(0.0).y, _97[0].x, _97[0].y); + out.out_var_TEXCOORD3 = float4(float4(0.0).x, float4(0.0).y, _97[0].z, _97[0].w); + out.out_var_TEXCOORD8 = _482; + out.gl_Position = _339; + return out; +} + diff --git a/third_party/spirv-cross/reference/shaders-ue4/asm/vert/texture-buffer.asm.vert b/third_party/spirv-cross/reference/shaders-ue4/asm/vert/texture-buffer.asm.vert new file mode 100644 index 0000000000..6384e1b9d4 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders-ue4/asm/vert/texture-buffer.asm.vert @@ -0,0 +1,387 @@ +#pragma clang diagnostic ignored "-Wmissing-prototypes" + +#include +#include + +using namespace metal; + +struct type_View +{ + float4x4 View_TranslatedWorldToClip; + float4x4 View_WorldToClip; + float4x4 View_TranslatedWorldToView; + float4x4 View_ViewToTranslatedWorld; + float4x4 View_TranslatedWorldToCameraView; + float4x4 View_CameraViewToTranslatedWorld; + float4x4 View_ViewToClip; + float4x4 View_ViewToClipNoAA; + float4x4 View_ClipToView; + float4x4 View_ClipToTranslatedWorld; + float4x4 View_SVPositionToTranslatedWorld; + float4x4 View_ScreenToWorld; + float4x4 View_ScreenToTranslatedWorld; + packed_float3 View_ViewForward; + float PrePadding_View_844; + packed_float3 View_ViewUp; + float PrePadding_View_860; + packed_float3 View_ViewRight; + float PrePadding_View_876; + packed_float3 View_HMDViewNoRollUp; + float PrePadding_View_892; + packed_float3 View_HMDViewNoRollRight; + float PrePadding_View_908; + float4 View_InvDeviceZToWorldZTransform; + float4 View_ScreenPositionScaleBias; + packed_float3 View_WorldCameraOrigin; + float PrePadding_View_956; + packed_float3 View_TranslatedWorldCameraOrigin; + float PrePadding_View_972; + packed_float3 View_WorldViewOrigin; + float PrePadding_View_988; + packed_float3 View_PreViewTranslation; + float PrePadding_View_1004; + float4x4 View_PrevProjection; + float4x4 View_PrevViewProj; + float4x4 View_PrevViewRotationProj; + float4x4 View_PrevViewToClip; + float4x4 View_PrevClipToView; + float4x4 View_PrevTranslatedWorldToClip; + float4x4 View_PrevTranslatedWorldToView; + float4x4 View_PrevViewToTranslatedWorld; + float4x4 View_PrevTranslatedWorldToCameraView; + float4x4 View_PrevCameraViewToTranslatedWorld; + packed_float3 View_PrevWorldCameraOrigin; + float PrePadding_View_1660; + packed_float3 View_PrevWorldViewOrigin; + float PrePadding_View_1676; + packed_float3 View_PrevPreViewTranslation; + float PrePadding_View_1692; + float4x4 View_PrevInvViewProj; + float4x4 View_PrevScreenToTranslatedWorld; + float4x4 View_ClipToPrevClip; + float4 View_TemporalAAJitter; + float4 View_GlobalClippingPlane; + float2 View_FieldOfViewWideAngles; + float2 View_PrevFieldOfViewWideAngles; + float4 View_ViewRectMin; + float4 View_ViewSizeAndInvSize; + float4 View_BufferSizeAndInvSize; + float4 View_BufferBilinearUVMinMax; + int View_NumSceneColorMSAASamples; + float View_PreExposure; + float View_OneOverPreExposure; + float PrePadding_View_2012; + float4 View_DiffuseOverrideParameter; + float4 View_SpecularOverrideParameter; + float4 View_NormalOverrideParameter; + float2 View_RoughnessOverrideParameter; + float View_PrevFrameGameTime; + float View_PrevFrameRealTime; + float View_OutOfBoundsMask; + float PrePadding_View_2084; + float PrePadding_View_2088; + float PrePadding_View_2092; + packed_float3 View_WorldCameraMovementSinceLastFrame; + float View_CullingSign; + float View_NearPlane; + float View_AdaptiveTessellationFactor; + float View_GameTime; + float View_RealTime; + float View_DeltaTime; + float View_MaterialTextureMipBias; + float View_MaterialTextureDerivativeMultiply; + uint View_Random; + uint View_FrameNumber; + uint View_StateFrameIndexMod8; + uint View_StateFrameIndex; + float View_CameraCut; + float View_UnlitViewmodeMask; + float PrePadding_View_2164; + float PrePadding_View_2168; + float PrePadding_View_2172; + float4 View_DirectionalLightColor; + packed_float3 View_DirectionalLightDirection; + float PrePadding_View_2204; + float4 View_TranslucencyLightingVolumeMin[2]; + float4 View_TranslucencyLightingVolumeInvSize[2]; + float4 View_TemporalAAParams; + float4 View_CircleDOFParams; + float View_DepthOfFieldSensorWidth; + float View_DepthOfFieldFocalDistance; + float View_DepthOfFieldScale; + float View_DepthOfFieldFocalLength; + float View_DepthOfFieldFocalRegion; + float View_DepthOfFieldNearTransitionRegion; + float View_DepthOfFieldFarTransitionRegion; + float View_MotionBlurNormalizedToPixel; + float View_bSubsurfacePostprocessEnabled; + float View_GeneralPurposeTweak; + float View_DemosaicVposOffset; + float PrePadding_View_2348; + packed_float3 View_IndirectLightingColorScale; + float View_HDR32bppEncodingMode; + packed_float3 View_AtmosphericFogSunDirection; + float View_AtmosphericFogSunPower; + float View_AtmosphericFogPower; + float View_AtmosphericFogDensityScale; + float View_AtmosphericFogDensityOffset; + float View_AtmosphericFogGroundOffset; + float View_AtmosphericFogDistanceScale; + float View_AtmosphericFogAltitudeScale; + float View_AtmosphericFogHeightScaleRayleigh; + float View_AtmosphericFogStartDistance; + float View_AtmosphericFogDistanceOffset; + float View_AtmosphericFogSunDiscScale; + uint View_AtmosphericFogRenderMask; + uint View_AtmosphericFogInscatterAltitudeSampleNum; + float4 View_AtmosphericFogSunColor; + packed_float3 View_NormalCurvatureToRoughnessScaleBias; + float View_RenderingReflectionCaptureMask; + float4 View_AmbientCubemapTint; + float View_AmbientCubemapIntensity; + float View_SkyLightParameters; + float PrePadding_View_2488; + float PrePadding_View_2492; + float4 View_SkyLightColor; + float4 View_SkyIrradianceEnvironmentMap[7]; + float View_MobilePreviewMode; + float View_HMDEyePaddingOffset; + float View_ReflectionCubemapMaxMip; + float View_ShowDecalsMask; + uint View_DistanceFieldAOSpecularOcclusionMode; + float View_IndirectCapsuleSelfShadowingIntensity; + float PrePadding_View_2648; + float PrePadding_View_2652; + packed_float3 View_ReflectionEnvironmentRoughnessMixingScaleBiasAndLargestWeight; + int View_StereoPassIndex; + float4 View_GlobalVolumeCenterAndExtent[4]; + float4 View_GlobalVolumeWorldToUVAddAndMul[4]; + float View_GlobalVolumeDimension; + float View_GlobalVolumeTexelSize; + float View_MaxGlobalDistance; + float View_bCheckerboardSubsurfaceProfileRendering; + packed_float3 View_VolumetricFogInvGridSize; + float PrePadding_View_2828; + packed_float3 View_VolumetricFogGridZParams; + float PrePadding_View_2844; + float2 View_VolumetricFogSVPosToVolumeUV; + float View_VolumetricFogMaxDistance; + float PrePadding_View_2860; + packed_float3 View_VolumetricLightmapWorldToUVScale; + float PrePadding_View_2876; + packed_float3 View_VolumetricLightmapWorldToUVAdd; + float PrePadding_View_2892; + packed_float3 View_VolumetricLightmapIndirectionTextureSize; + float View_VolumetricLightmapBrickSize; + packed_float3 View_VolumetricLightmapBrickTexelSize; + float View_StereoIPD; + float View_IndirectLightingCacheShowFlag; + float View_EyeToPixelSpreadAngle; +}; + +struct type_Primitive +{ + float4x4 Primitive_LocalToWorld; + float4 Primitive_InvNonUniformScaleAndDeterminantSign; + float4 Primitive_ObjectWorldPositionAndRadius; + float4x4 Primitive_WorldToLocal; + float4x4 Primitive_PreviousLocalToWorld; + float4x4 Primitive_PreviousWorldToLocal; + packed_float3 Primitive_ActorWorldPosition; + float Primitive_UseSingleSampleShadowFromStationaryLights; + packed_float3 Primitive_ObjectBounds; + float Primitive_LpvBiasMultiplier; + float Primitive_DecalReceiverMask; + float Primitive_PerObjectGBufferData; + float Primitive_UseVolumetricLightmapShadowFromStationaryLights; + float Primitive_UseEditorDepthTest; + float4 Primitive_ObjectOrientation; + float4 Primitive_NonUniformScale; + packed_float3 Primitive_LocalObjectBoundsMin; + float PrePadding_Primitive_380; + packed_float3 Primitive_LocalObjectBoundsMax; + uint Primitive_LightingChannelMask; + uint Primitive_LightmapDataIndex; + int Primitive_SingleCaptureIndex; +}; + +struct type_MobileShadowDepthPass +{ + float PrePadding_MobileShadowDepthPass_0; + float PrePadding_MobileShadowDepthPass_4; + float PrePadding_MobileShadowDepthPass_8; + float PrePadding_MobileShadowDepthPass_12; + float PrePadding_MobileShadowDepthPass_16; + float PrePadding_MobileShadowDepthPass_20; + float PrePadding_MobileShadowDepthPass_24; + float PrePadding_MobileShadowDepthPass_28; + float PrePadding_MobileShadowDepthPass_32; + float PrePadding_MobileShadowDepthPass_36; + float PrePadding_MobileShadowDepthPass_40; + float PrePadding_MobileShadowDepthPass_44; + float PrePadding_MobileShadowDepthPass_48; + float PrePadding_MobileShadowDepthPass_52; + float PrePadding_MobileShadowDepthPass_56; + float PrePadding_MobileShadowDepthPass_60; + float PrePadding_MobileShadowDepthPass_64; + float PrePadding_MobileShadowDepthPass_68; + float PrePadding_MobileShadowDepthPass_72; + float PrePadding_MobileShadowDepthPass_76; + float4x4 MobileShadowDepthPass_ProjectionMatrix; + float2 MobileShadowDepthPass_ShadowParams; + float MobileShadowDepthPass_bClampToNearPlane; + float PrePadding_MobileShadowDepthPass_156; + float4x4 MobileShadowDepthPass_ShadowViewProjectionMatrices[6]; +}; + +struct type_EmitterDynamicUniforms +{ + float2 EmitterDynamicUniforms_LocalToWorldScale; + float EmitterDynamicUniforms_EmitterInstRandom; + float PrePadding_EmitterDynamicUniforms_12; + float4 EmitterDynamicUniforms_AxisLockRight; + float4 EmitterDynamicUniforms_AxisLockUp; + float4 EmitterDynamicUniforms_DynamicColor; + float4 EmitterDynamicUniforms_MacroUVParameters; +}; + +struct type_EmitterUniforms +{ + float4 EmitterUniforms_ColorCurve; + float4 EmitterUniforms_ColorScale; + float4 EmitterUniforms_ColorBias; + float4 EmitterUniforms_MiscCurve; + float4 EmitterUniforms_MiscScale; + float4 EmitterUniforms_MiscBias; + float4 EmitterUniforms_SizeBySpeed; + float4 EmitterUniforms_SubImageSize; + float4 EmitterUniforms_TangentSelector; + packed_float3 EmitterUniforms_CameraFacingBlend; + float EmitterUniforms_RemoveHMDRoll; + float EmitterUniforms_RotationRateScale; + float EmitterUniforms_RotationBias; + float EmitterUniforms_CameraMotionBlurAmount; + float PrePadding_EmitterUniforms_172; + float2 EmitterUniforms_PivotOffset; +}; + +struct type_Globals +{ + uint ParticleIndicesOffset; +}; + +struct main0_out +{ + float out_var_TEXCOORD6 [[user(locn0)]]; + float4 gl_Position [[position]]; +}; + +struct main0_in +{ + float2 in_var_ATTRIBUTE0 [[attribute(0)]]; +}; + +// Returns 2D texture coords corresponding to 1D texel buffer coords +static inline __attribute__((always_inline)) +uint2 spvTexelBufferCoord(uint tc) +{ + return uint2(tc % 4096, tc / 4096); +} + +vertex main0_out main0(main0_in in [[stage_in]], constant type_View& View [[buffer(0)]], constant type_Primitive& Primitive [[buffer(1)]], constant type_MobileShadowDepthPass& MobileShadowDepthPass [[buffer(2)]], constant type_EmitterDynamicUniforms& EmitterDynamicUniforms [[buffer(3)]], constant type_EmitterUniforms& EmitterUniforms [[buffer(4)]], constant type_Globals& _Globals [[buffer(5)]], texture2d ParticleIndices [[texture(0)]], texture2d PositionTexture [[texture(1)]], texture2d VelocityTexture [[texture(2)]], texture2d AttributesTexture [[texture(3)]], texture2d CurveTexture [[texture(4)]], sampler PositionTextureSampler [[sampler(0)]], sampler VelocityTextureSampler [[sampler(1)]], sampler AttributesTextureSampler [[sampler(2)]], sampler CurveTextureSampler [[sampler(3)]], uint gl_VertexIndex [[vertex_id]], uint gl_InstanceIndex [[instance_id]]) +{ + main0_out out = {}; + float2 _133 = ParticleIndices.read(spvTexelBufferCoord((_Globals.ParticleIndicesOffset + ((gl_InstanceIndex * 16u) + (gl_VertexIndex / 4u))))).xy; + float4 _137 = PositionTexture.sample(PositionTextureSampler, _133, level(0.0)); + float4 _145 = AttributesTexture.sample(AttributesTextureSampler, _133, level(0.0)); + float _146 = _137.w; + float3 _158 = float3x3(Primitive.Primitive_LocalToWorld[0].xyz, Primitive.Primitive_LocalToWorld[1].xyz, Primitive.Primitive_LocalToWorld[2].xyz) * VelocityTexture.sample(VelocityTextureSampler, _133, level(0.0)).xyz; + float3 _160 = normalize(_158 + float3(0.0, 0.0, 9.9999997473787516355514526367188e-05)); + float2 _204 = ((((_145.xy + float2((_145.x < 0.5) ? 0.0 : (-0.5), (_145.y < 0.5) ? 0.0 : (-0.5))) * float2(2.0)) * (((CurveTexture.sample(CurveTextureSampler, (EmitterUniforms.EmitterUniforms_MiscCurve.xy + (EmitterUniforms.EmitterUniforms_MiscCurve.zw * float2(_146))), level(0.0)) * EmitterUniforms.EmitterUniforms_MiscScale) + EmitterUniforms.EmitterUniforms_MiscBias).xy * EmitterDynamicUniforms.EmitterDynamicUniforms_LocalToWorldScale)) * fast::min(fast::max(EmitterUniforms.EmitterUniforms_SizeBySpeed.xy * float2(length(_158)), float2(1.0)), EmitterUniforms.EmitterUniforms_SizeBySpeed.zw)) * float2(step(_146, 1.0)); + float3 _239 = float4((((Primitive.Primitive_LocalToWorld[0u].xyz * _137.xxx) + (Primitive.Primitive_LocalToWorld[1u].xyz * _137.yyy)) + (Primitive.Primitive_LocalToWorld[2u].xyz * _137.zzz)) + (Primitive.Primitive_LocalToWorld[3u].xyz + float3(View.View_PreViewTranslation)), 1.0).xyz; + float3 _242 = float3(EmitterUniforms.EmitterUniforms_RemoveHMDRoll); + float3 _251 = mix(mix(float3(View.View_ViewRight), float3(View.View_HMDViewNoRollRight), _242), EmitterDynamicUniforms.EmitterDynamicUniforms_AxisLockRight.xyz, float3(EmitterDynamicUniforms.EmitterDynamicUniforms_AxisLockRight.w)); + float3 _259 = mix(-mix(float3(View.View_ViewUp), float3(View.View_HMDViewNoRollUp), _242), EmitterDynamicUniforms.EmitterDynamicUniforms_AxisLockUp.xyz, float3(EmitterDynamicUniforms.EmitterDynamicUniforms_AxisLockUp.w)); + float3 _260 = float3(View.View_TranslatedWorldCameraOrigin) - _239; + float _261 = dot(_260, _260); + float3 _265 = _260 / float3(sqrt(fast::max(_261, 0.00999999977648258209228515625))); + float3 _335; + float3 _336; + if (EmitterUniforms.EmitterUniforms_CameraFacingBlend[0] > 0.0) + { + float3 _279 = cross(_265, float3(0.0, 0.0, 1.0)); + float3 _284 = _279 / float3(sqrt(fast::max(dot(_279, _279), 0.00999999977648258209228515625))); + float3 _286 = float3(fast::clamp((_261 * EmitterUniforms.EmitterUniforms_CameraFacingBlend[1]) - EmitterUniforms.EmitterUniforms_CameraFacingBlend[2], 0.0, 1.0)); + _335 = normalize(mix(_251, _284, _286)); + _336 = normalize(mix(_259, cross(_265, _284), _286)); + } + else + { + float3 _333; + float3 _334; + if (EmitterUniforms.EmitterUniforms_TangentSelector.y > 0.0) + { + float3 _297 = cross(_265, _160); + _333 = _297 / float3(sqrt(fast::max(dot(_297, _297), 0.00999999977648258209228515625))); + _334 = -_160; + } + else + { + float3 _331; + float3 _332; + if (EmitterUniforms.EmitterUniforms_TangentSelector.z > 0.0) + { + float3 _310 = cross(EmitterDynamicUniforms.EmitterDynamicUniforms_AxisLockRight.xyz, _265); + _331 = EmitterDynamicUniforms.EmitterDynamicUniforms_AxisLockRight.xyz; + _332 = -(_310 / float3(sqrt(fast::max(dot(_310, _310), 0.00999999977648258209228515625)))); + } + else + { + float3 _329; + float3 _330; + if (EmitterUniforms.EmitterUniforms_TangentSelector.w > 0.0) + { + float3 _322 = cross(_265, float3(0.0, 0.0, 1.0)); + float3 _327 = _322 / float3(sqrt(fast::max(dot(_322, _322), 0.00999999977648258209228515625))); + _329 = _327; + _330 = cross(_265, _327); + } + else + { + _329 = _251; + _330 = _259; + } + _331 = _329; + _332 = _330; + } + _333 = _331; + _334 = _332; + } + _335 = _333; + _336 = _334; + } + float _339 = ((_145.z + ((_145.w * EmitterUniforms.EmitterUniforms_RotationRateScale) * _146)) * 6.283185482025146484375) + EmitterUniforms.EmitterUniforms_RotationBias; + float3 _342 = float3(sin(_339)); + float3 _344 = float3(cos(_339)); + float4 _371 = float4(_239 + ((float3(_204.x * (in.in_var_ATTRIBUTE0.x + EmitterUniforms.EmitterUniforms_PivotOffset.x)) * ((_342 * _336) + (_344 * _335))) + (float3(_204.y * (in.in_var_ATTRIBUTE0.y + EmitterUniforms.EmitterUniforms_PivotOffset.y)) * ((_344 * _336) - (_342 * _335)))), 1.0); + float4 _375 = MobileShadowDepthPass.MobileShadowDepthPass_ProjectionMatrix * float4(_371.x, _371.y, _371.z, _371.w); + float4 _386; + if ((MobileShadowDepthPass.MobileShadowDepthPass_bClampToNearPlane > 0.0) && (_375.z < 0.0)) + { + float4 _384 = _375; + _384.z = 9.9999999747524270787835121154785e-07; + float4 _385 = _384; + _385.w = 1.0; + _386 = _385; + } + else + { + _386 = _375; + } + float4 _396 = _386; + _396.z = ((_386.z * MobileShadowDepthPass.MobileShadowDepthPass_ShadowParams.y) + MobileShadowDepthPass.MobileShadowDepthPass_ShadowParams.x) * _386.w; + out.out_var_TEXCOORD6 = 0.0; + out.gl_Position = _396; + return out; +} + diff --git a/third_party/spirv-cross/reference/shaders/amd/fragmentMaskFetch_subpassInput.vk.nocompat.invalid.frag.vk b/third_party/spirv-cross/reference/shaders/amd/fragmentMaskFetch_subpassInput.vk.nocompat.invalid.frag.vk deleted file mode 100644 index 4aaf397a0f..0000000000 --- a/third_party/spirv-cross/reference/shaders/amd/fragmentMaskFetch_subpassInput.vk.nocompat.invalid.frag.vk +++ /dev/null @@ -1,11 +0,0 @@ -#version 450 -#extension GL_AMD_shader_fragment_mask : require - -layout(input_attachment_index = 0, set = 0, binding = 0) uniform subpassInputMS t; - -void main() -{ - vec4 test2 = fragmentFetchAMD(t, 4u); - uint testi2 = fragmentMaskFetchAMD(t); -} - diff --git a/third_party/spirv-cross/reference/shaders/amd/fs.invalid.frag b/third_party/spirv-cross/reference/shaders/amd/fs.invalid.frag deleted file mode 100644 index aecf69eba7..0000000000 --- a/third_party/spirv-cross/reference/shaders/amd/fs.invalid.frag +++ /dev/null @@ -1,15 +0,0 @@ -#version 450 -#extension GL_AMD_shader_fragment_mask : require -#extension GL_AMD_shader_explicit_vertex_parameter : require - -layout(binding = 0) uniform sampler2DMS texture1; - -layout(location = 0) __explicitInterpAMD in vec4 vary; - -void main() -{ - uint testi1 = fragmentMaskFetchAMD(texture1, ivec2(0)); - vec4 test1 = fragmentFetchAMD(texture1, ivec2(1), 2u); - vec4 pos = interpolateAtVertexAMD(vary, 0u); -} - diff --git a/third_party/spirv-cross/reference/shaders/amd/shader_ballot_nonuniform_invocations.invalid.comp b/third_party/spirv-cross/reference/shaders/amd/shader_ballot_nonuniform_invocations.invalid.comp deleted file mode 100644 index a14343ae12..0000000000 --- a/third_party/spirv-cross/reference/shaders/amd/shader_ballot_nonuniform_invocations.invalid.comp +++ /dev/null @@ -1,11 +0,0 @@ -#version 450 -#extension GL_AMD_shader_ballot : require -layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in; - -void main() -{ - float addInvocations = addInvocationsNonUniformAMD(0.0); - int minInvocations = minInvocationsNonUniformAMD(1); - uint maxInvocations = uint(maxInvocationsNonUniformAMD(4)); -} - diff --git a/third_party/spirv-cross/reference/shaders/asm/comp/bitcast_icmp.asm.comp b/third_party/spirv-cross/reference/shaders/asm/comp/bitcast_icmp.asm.comp new file mode 100644 index 0000000000..bed3b90a7b --- /dev/null +++ b/third_party/spirv-cross/reference/shaders/asm/comp/bitcast_icmp.asm.comp @@ -0,0 +1,27 @@ +#version 310 es +layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in; + +layout(binding = 0, std430) restrict buffer _3_5 +{ + ivec4 _m0; + uvec4 _m1; +} _5; + +layout(binding = 1, std430) restrict buffer _4_6 +{ + uvec4 _m0; + ivec4 _m1; +} _6; + +void main() +{ + _6._m0 = mix(uvec4(0u), uvec4(1u), lessThan(ivec4(_5._m1), _5._m0)); + _6._m0 = mix(uvec4(0u), uvec4(1u), lessThanEqual(ivec4(_5._m1), _5._m0)); + _6._m0 = mix(uvec4(0u), uvec4(1u), lessThan(_5._m1, uvec4(_5._m0))); + _6._m0 = mix(uvec4(0u), uvec4(1u), lessThanEqual(_5._m1, uvec4(_5._m0))); + _6._m0 = mix(uvec4(0u), uvec4(1u), greaterThan(ivec4(_5._m1), _5._m0)); + _6._m0 = mix(uvec4(0u), uvec4(1u), greaterThanEqual(ivec4(_5._m1), _5._m0)); + _6._m0 = mix(uvec4(0u), uvec4(1u), greaterThan(_5._m1, uvec4(_5._m0))); + _6._m0 = mix(uvec4(0u), uvec4(1u), greaterThanEqual(_5._m1, uvec4(_5._m0))); +} + diff --git a/third_party/spirv-cross/reference/shaders/asm/comp/phi-temporary-copy-loop-variable.asm.comp b/third_party/spirv-cross/reference/shaders/asm/comp/phi-temporary-copy-loop-variable.asm.comp deleted file mode 100644 index 9ae8d6fd7f..0000000000 --- a/third_party/spirv-cross/reference/shaders/asm/comp/phi-temporary-copy-loop-variable.asm.comp +++ /dev/null @@ -1,25 +0,0 @@ -#version 450 -layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; - -layout(binding = 1, rgba32f) uniform writeonly image2D outImageTexture; - -void main() -{ - int _30; - _30 = 7; - int _27_copy; - for (int _27 = 7; _27 >= 0; _27_copy = _27, _27--, _30 = _27_copy) - { - if (5.0 > float(_27)) - { - break; - } - else - { - continue; - } - continue; - } - imageStore(outImageTexture, ivec2(gl_GlobalInvocationID.xy), vec4(float(_30 - 1), float(_30), 1.0, 1.0)); -} - diff --git a/third_party/spirv-cross/reference/shaders/asm/comp/storage-buffer-basic.invalid.asm.comp b/third_party/spirv-cross/reference/shaders/asm/comp/storage-buffer-basic.invalid.asm.comp deleted file mode 100644 index 482cfd8a06..0000000000 --- a/third_party/spirv-cross/reference/shaders/asm/comp/storage-buffer-basic.invalid.asm.comp +++ /dev/null @@ -1,28 +0,0 @@ -#version 450 - -#ifndef SPIRV_CROSS_CONSTANT_ID_0 -#define SPIRV_CROSS_CONSTANT_ID_0 1u -#endif -#ifndef SPIRV_CROSS_CONSTANT_ID_2 -#define SPIRV_CROSS_CONSTANT_ID_2 3u -#endif - -layout(local_size_x = SPIRV_CROSS_CONSTANT_ID_0, local_size_y = 2, local_size_z = SPIRV_CROSS_CONSTANT_ID_2) in; - -layout(binding = 0, std430) buffer _6_8 -{ - float _m0[]; -} _8; - -layout(binding = 1, std430) buffer _6_9 -{ - float _m0[]; -} _9; - -uvec3 _22 = gl_WorkGroupSize; - -void main() -{ - _8._m0[gl_WorkGroupID.x] = _9._m0[gl_WorkGroupID.x] + _8._m0[gl_WorkGroupID.x]; -} - diff --git a/third_party/spirv-cross/reference/shaders/asm/extended-debug-extinst.invalid.asm.comp b/third_party/spirv-cross/reference/shaders/asm/extended-debug-extinst.invalid.asm.comp deleted file mode 100644 index 7755593f57..0000000000 --- a/third_party/spirv-cross/reference/shaders/asm/extended-debug-extinst.invalid.asm.comp +++ /dev/null @@ -1,18 +0,0 @@ -#version 430 -layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in; - -layout(binding = 0, std430) buffer _8_9 -{ - float _m0[]; -} _9; - -layout(binding = 1, std430) buffer _8_10 -{ - float _m0[]; -} _10; - -void main() -{ - _10._m0[gl_GlobalInvocationID.x] = -_9._m0[gl_GlobalInvocationID.x]; -} - diff --git a/third_party/spirv-cross/reference/shaders/asm/frag/for-loop-phi-only-continue.asm.frag b/third_party/spirv-cross/reference/shaders/asm/frag/for-loop-phi-only-continue.asm.frag index feb45db440..3101142944 100644 --- a/third_party/spirv-cross/reference/shaders/asm/frag/for-loop-phi-only-continue.asm.frag +++ b/third_party/spirv-cross/reference/shaders/asm/frag/for-loop-phi-only-continue.asm.frag @@ -12,7 +12,6 @@ void main() { _20 = _19 + 1.0; _23 = _22 + 1; - continue; } FragColor = vec4(_19); } diff --git a/third_party/spirv-cross/reference/shaders/asm/frag/image-fetch-no-sampler.no-samplerless.asm.vk.frag b/third_party/spirv-cross/reference/shaders/asm/frag/image-fetch-no-sampler.no-samplerless.asm.vk.frag new file mode 100644 index 0000000000..60bb78aa5c --- /dev/null +++ b/third_party/spirv-cross/reference/shaders/asm/frag/image-fetch-no-sampler.no-samplerless.asm.vk.frag @@ -0,0 +1,38 @@ +#version 450 + +uniform sampler2D SPIRV_Cross_CombinedparamSPIRV_Cross_DummySampler; +uniform sampler2D SPIRV_Cross_CombinedSampledImageSPIRV_Cross_DummySampler; +uniform sampler2D SPIRV_Cross_CombinedparamSampler; +uniform sampler2D SPIRV_Cross_CombinedSampledImageSampler; + +layout(location = 0) out vec4 _entryPointOutput; + +vec4 sample_fetch(ivec3 UV, sampler2D SPIRV_Cross_CombinedtexSPIRV_Cross_DummySampler) +{ + return texelFetch(SPIRV_Cross_CombinedtexSPIRV_Cross_DummySampler, UV.xy, UV.z); +} + +vec4 sample_sampler(vec2 UV, sampler2D SPIRV_Cross_CombinedtexSampler) +{ + return texture(SPIRV_Cross_CombinedtexSampler, UV); +} + +vec4 _main(vec4 xIn) +{ + ivec3 coord = ivec3(int(xIn.x * 1280.0), int(xIn.y * 720.0), 0); + ivec3 param = coord; + vec4 value = sample_fetch(param, SPIRV_Cross_CombinedparamSPIRV_Cross_DummySampler); + value += texelFetch(SPIRV_Cross_CombinedSampledImageSPIRV_Cross_DummySampler, coord.xy, coord.z); + vec2 param_1 = xIn.xy; + value += sample_sampler(param_1, SPIRV_Cross_CombinedparamSampler); + value += texture(SPIRV_Cross_CombinedSampledImageSampler, xIn.xy); + return value; +} + +void main() +{ + vec4 xIn = gl_FragCoord; + vec4 param = xIn; + _entryPointOutput = _main(param); +} + diff --git a/third_party/spirv-cross/reference/shaders/asm/frag/image-fetch-no-sampler.no-samplerless.asm.vk.frag.vk b/third_party/spirv-cross/reference/shaders/asm/frag/image-fetch-no-sampler.no-samplerless.asm.vk.frag.vk new file mode 100644 index 0000000000..e4d9fc4543 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders/asm/frag/image-fetch-no-sampler.no-samplerless.asm.vk.frag.vk @@ -0,0 +1,37 @@ +#version 450 + +layout(set = 0, binding = 0) uniform sampler Sampler; +layout(set = 0, binding = 0) uniform texture2D SampledImage; +layout(set = 0, binding = 0) uniform sampler SPIRV_Cross_DummySampler; + +layout(location = 0) out vec4 _entryPointOutput; + +vec4 sample_fetch(texture2D tex, ivec3 UV) +{ + return texelFetch(sampler2D(tex, SPIRV_Cross_DummySampler), UV.xy, UV.z); +} + +vec4 sample_sampler(texture2D tex, vec2 UV) +{ + return texture(sampler2D(tex, Sampler), UV); +} + +vec4 _main(vec4 xIn) +{ + ivec3 coord = ivec3(int(xIn.x * 1280.0), int(xIn.y * 720.0), 0); + ivec3 param = coord; + vec4 value = sample_fetch(SampledImage, param); + value += texelFetch(sampler2D(SampledImage, SPIRV_Cross_DummySampler), coord.xy, coord.z); + vec2 param_1 = xIn.xy; + value += sample_sampler(SampledImage, param_1); + value += texture(sampler2D(SampledImage, Sampler), xIn.xy); + return value; +} + +void main() +{ + vec4 xIn = gl_FragCoord; + vec4 param = xIn; + _entryPointOutput = _main(param); +} + diff --git a/third_party/spirv-cross/reference/shaders/asm/frag/image-query-no-sampler.no-samplerless.vk.asm.frag b/third_party/spirv-cross/reference/shaders/asm/frag/image-query-no-sampler.no-samplerless.vk.asm.frag new file mode 100644 index 0000000000..2040dd1afb --- /dev/null +++ b/third_party/spirv-cross/reference/shaders/asm/frag/image-query-no-sampler.no-samplerless.vk.asm.frag @@ -0,0 +1,13 @@ +#version 450 + +uniform sampler2D SPIRV_Cross_CombineduSampler2DSPIRV_Cross_DummySampler; +uniform sampler2DMS SPIRV_Cross_CombineduSampler2DMSSPIRV_Cross_DummySampler; + +void main() +{ + ivec2 b = textureSize(SPIRV_Cross_CombineduSampler2DSPIRV_Cross_DummySampler, 0); + ivec2 c = textureSize(SPIRV_Cross_CombineduSampler2DMSSPIRV_Cross_DummySampler); + int l1 = textureQueryLevels(SPIRV_Cross_CombineduSampler2DSPIRV_Cross_DummySampler); + int s0 = textureSamples(SPIRV_Cross_CombineduSampler2DMSSPIRV_Cross_DummySampler); +} + diff --git a/third_party/spirv-cross/reference/shaders/asm/frag/image-query-no-sampler.no-samplerless.vk.asm.frag.vk b/third_party/spirv-cross/reference/shaders/asm/frag/image-query-no-sampler.no-samplerless.vk.asm.frag.vk new file mode 100644 index 0000000000..828d2a8727 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders/asm/frag/image-query-no-sampler.no-samplerless.vk.asm.frag.vk @@ -0,0 +1,14 @@ +#version 450 + +layout(set = 0, binding = 0) uniform texture2D uSampler2D; +layout(set = 0, binding = 0) uniform texture2DMS uSampler2DMS; +layout(set = 0, binding = 0) uniform sampler SPIRV_Cross_DummySampler; + +void main() +{ + ivec2 b = textureSize(sampler2D(uSampler2D, SPIRV_Cross_DummySampler), 0); + ivec2 c = textureSize(sampler2DMS(uSampler2DMS, SPIRV_Cross_DummySampler)); + int l1 = textureQueryLevels(sampler2D(uSampler2D, SPIRV_Cross_DummySampler)); + int s0 = textureSamples(sampler2DMS(uSampler2DMS, SPIRV_Cross_DummySampler)); +} + diff --git a/third_party/spirv-cross/reference/shaders/asm/frag/op-phi-swap-continue-block.asm.frag b/third_party/spirv-cross/reference/shaders/asm/frag/op-phi-swap-continue-block.asm.frag index 3dae3e161c..d62b63a0e0 100644 --- a/third_party/spirv-cross/reference/shaders/asm/frag/op-phi-swap-continue-block.asm.frag +++ b/third_party/spirv-cross/reference/shaders/asm/frag/op-phi-swap-continue-block.asm.frag @@ -18,7 +18,6 @@ void main() _24 = _5.uJ; for (int _26 = 0; _26 < _5.uCount; _23_copy = _23, _23 = _24, _24 = _23_copy, _26++) { - continue; } FragColor = float(_24 - _23) * float(_5.uJ * _5.uK); } diff --git a/third_party/spirv-cross/reference/shaders/asm/geom/store-uint-layer.invalid.asm.geom b/third_party/spirv-cross/reference/shaders/asm/geom/store-uint-layer.invalid.asm.geom deleted file mode 100644 index c768d5da86..0000000000 --- a/third_party/spirv-cross/reference/shaders/asm/geom/store-uint-layer.invalid.asm.geom +++ /dev/null @@ -1,41 +0,0 @@ -#version 450 -layout(triangles) in; -layout(max_vertices = 3, triangle_strip) out; - -struct VertexOutput -{ - vec4 pos; -}; - -struct GeometryOutput -{ - vec4 pos; - uint layer; -}; - -void _main(VertexOutput _input[3], GeometryOutput stream) -{ - GeometryOutput _output; - _output.layer = 1u; - for (int v = 0; v < 3; v++) - { - _output.pos = _input[v].pos; - gl_Position = _output.pos; - gl_Layer = int(_output.layer); - EmitVertex(); - } - EndPrimitive(); -} - -void main() -{ - VertexOutput _input[3]; - _input[0].pos = gl_in[0].gl_Position; - _input[1].pos = gl_in[1].gl_Position; - _input[2].pos = gl_in[2].gl_Position; - VertexOutput param[3] = _input; - GeometryOutput param_1; - _main(param, param_1); - GeometryOutput stream = param_1; -} - diff --git a/third_party/spirv-cross/reference/shaders/asm/tesc/tess-fixed-input-array-builtin-array.invalid.asm.tesc b/third_party/spirv-cross/reference/shaders/asm/tesc/tess-fixed-input-array-builtin-array.invalid.asm.tesc deleted file mode 100644 index 8cb7a4e64c..0000000000 --- a/third_party/spirv-cross/reference/shaders/asm/tesc/tess-fixed-input-array-builtin-array.invalid.asm.tesc +++ /dev/null @@ -1,79 +0,0 @@ -#version 450 -layout(vertices = 3) out; - -struct VertexOutput -{ - vec4 pos; - vec2 uv; -}; - -struct HSOut -{ - vec4 pos; - vec2 uv; -}; - -struct HSConstantOut -{ - float EdgeTess[3]; - float InsideTess; -}; - -struct VertexOutput_1 -{ - vec2 uv; -}; - -struct HSOut_1 -{ - vec2 uv; -}; - -layout(location = 0) in VertexOutput_1 p[]; -layout(location = 0) out HSOut_1 _entryPointOutput[3]; - -HSOut _hs_main(VertexOutput p_1[3], uint i) -{ - HSOut _output; - _output.pos = p_1[i].pos; - _output.uv = p_1[i].uv; - return _output; -} - -HSConstantOut PatchHS(VertexOutput _patch[3]) -{ - HSConstantOut _output; - _output.EdgeTess[0] = (vec2(1.0) + _patch[0].uv).x; - _output.EdgeTess[1] = (vec2(1.0) + _patch[0].uv).x; - _output.EdgeTess[2] = (vec2(1.0) + _patch[0].uv).x; - _output.InsideTess = (vec2(1.0) + _patch[0].uv).x; - return _output; -} - -void main() -{ - VertexOutput p_1[3]; - p_1[0].pos = gl_in[0].gl_Position; - p_1[0].uv = p[0].uv; - p_1[1].pos = gl_in[1].gl_Position; - p_1[1].uv = p[1].uv; - p_1[2].pos = gl_in[2].gl_Position; - p_1[2].uv = p[2].uv; - uint i = gl_InvocationID; - VertexOutput param[3] = p_1; - uint param_1 = i; - HSOut flattenTemp = _hs_main(param, param_1); - gl_out[gl_InvocationID].gl_Position = flattenTemp.pos; - _entryPointOutput[gl_InvocationID].uv = flattenTemp.uv; - barrier(); - if (int(gl_InvocationID) == 0) - { - VertexOutput param_2[3] = p_1; - HSConstantOut _patchConstantResult = PatchHS(param_2); - gl_TessLevelOuter[0] = _patchConstantResult.EdgeTess[0]; - gl_TessLevelOuter[1] = _patchConstantResult.EdgeTess[1]; - gl_TessLevelOuter[2] = _patchConstantResult.EdgeTess[2]; - gl_TessLevelInner[0] = _patchConstantResult.InsideTess; - } -} - diff --git a/third_party/spirv-cross/reference/shaders/comp/barriers.comp b/third_party/spirv-cross/reference/shaders/comp/barriers.comp index a1b975de83..1102c91e28 100644 --- a/third_party/spirv-cross/reference/shaders/comp/barriers.comp +++ b/third_party/spirv-cross/reference/shaders/comp/barriers.comp @@ -28,41 +28,35 @@ void group_barrier() void barrier_shared_exec() { - memoryBarrierShared(); barrier(); } void full_barrier_exec() { memoryBarrier(); - memoryBarrierShared(); barrier(); } void image_barrier_exec() { memoryBarrierImage(); - memoryBarrierShared(); barrier(); } void buffer_barrier_exec() { memoryBarrierBuffer(); - memoryBarrierShared(); barrier(); } void group_barrier_exec() { groupMemoryBarrier(); - memoryBarrierShared(); barrier(); } void exec_barrier() { - memoryBarrierShared(); barrier(); } diff --git a/third_party/spirv-cross/reference/shaders/comp/bitcast-16bit-1.invalid.comp b/third_party/spirv-cross/reference/shaders/comp/bitcast-16bit-1.invalid.comp deleted file mode 100644 index 501f97955f..0000000000 --- a/third_party/spirv-cross/reference/shaders/comp/bitcast-16bit-1.invalid.comp +++ /dev/null @@ -1,34 +0,0 @@ -#version 450 -#if defined(GL_AMD_gpu_shader_half_float) -#extension GL_AMD_gpu_shader_half_float : require -#elif defined(GL_NV_gpu_shader5) -#extension GL_NV_gpu_shader5 : require -#else -#error No extension available for FP16. -#endif -#if defined(GL_AMD_gpu_shader_int16) -#extension GL_AMD_gpu_shader_int16 : require -#else -#error No extension available for Int16. -#endif -layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in; - -layout(binding = 0, std430) buffer SSBO0 -{ - i16vec4 inputs[]; -} _25; - -layout(binding = 1, std430) buffer SSBO1 -{ - ivec4 outputs[]; -} _39; - -void main() -{ - uint ident = gl_GlobalInvocationID.x; - f16vec2 a = int16BitsToFloat16(_25.inputs[ident].xy); - _39.outputs[ident].x = int(packFloat2x16(a + f16vec2(float16_t(1.0)))); - _39.outputs[ident].y = packInt2x16(_25.inputs[ident].zw); - _39.outputs[ident].z = int(packUint2x16(u16vec2(_25.inputs[ident].xy))); -} - diff --git a/third_party/spirv-cross/reference/shaders/comp/bitcast-16bit-2.invalid.comp b/third_party/spirv-cross/reference/shaders/comp/bitcast-16bit-2.invalid.comp deleted file mode 100644 index bddc16d62b..0000000000 --- a/third_party/spirv-cross/reference/shaders/comp/bitcast-16bit-2.invalid.comp +++ /dev/null @@ -1,39 +0,0 @@ -#version 450 -#if defined(GL_AMD_gpu_shader_int16) -#extension GL_AMD_gpu_shader_int16 : require -#else -#error No extension available for Int16. -#endif -#if defined(GL_AMD_gpu_shader_half_float) -#extension GL_AMD_gpu_shader_half_float : require -#elif defined(GL_NV_gpu_shader5) -#extension GL_NV_gpu_shader5 : require -#else -#error No extension available for FP16. -#endif -layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in; - -layout(binding = 1, std430) buffer SSBO1 -{ - i16vec4 outputs[]; -} _21; - -layout(binding = 0, std430) buffer SSBO0 -{ - ivec4 inputs[]; -} _29; - -layout(binding = 2, std140) uniform UBO -{ - f16vec4 const0; -} _40; - -void main() -{ - uint ident = gl_GlobalInvocationID.x; - i16vec2 _47 = unpackInt2x16(_29.inputs[ident].x) + float16BitsToInt16(_40.const0.xy); - _21.outputs[ident] = i16vec4(_47.x, _47.y, _21.outputs[ident].z, _21.outputs[ident].w); - i16vec2 _66 = i16vec2(unpackUint2x16(uint(_29.inputs[ident].y)) - float16BitsToUint16(_40.const0.zw)); - _21.outputs[ident] = i16vec4(_21.outputs[ident].x, _21.outputs[ident].y, _66.x, _66.y); -} - diff --git a/third_party/spirv-cross/reference/shaders/comp/inout-struct.invalid.comp b/third_party/spirv-cross/reference/shaders/comp/inout-struct.invalid.comp deleted file mode 100644 index 640e25bb95..0000000000 --- a/third_party/spirv-cross/reference/shaders/comp/inout-struct.invalid.comp +++ /dev/null @@ -1,65 +0,0 @@ -#version 310 es -layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in; - -struct Foo -{ - vec4 a; - vec4 b; - vec4 c; - vec4 d; -}; - -layout(binding = 1, std430) readonly buffer SSBO2 -{ - vec4 data[]; -} indata; - -layout(binding = 0, std430) writeonly buffer SSBO -{ - vec4 data[]; -} outdata; - -layout(binding = 2, std430) readonly buffer SSBO3 -{ - Foo foos[]; -} foobar; - -void baz(inout Foo foo) -{ - uint ident = gl_GlobalInvocationID.x; - foo.a = indata.data[(4u * ident) + 0u]; - foo.b = indata.data[(4u * ident) + 1u]; - foo.c = indata.data[(4u * ident) + 2u]; - foo.d = indata.data[(4u * ident) + 3u]; -} - -void meow(inout Foo foo) -{ - foo.a += vec4(10.0); - foo.b += vec4(20.0); - foo.c += vec4(30.0); - foo.d += vec4(40.0); -} - -vec4 bar(Foo foo) -{ - return ((foo.a + foo.b) + foo.c) + foo.d; -} - -void main() -{ - Foo param; - baz(param); - Foo foo = param; - Foo param_1 = foo; - meow(param_1); - foo = param_1; - Foo param_2 = foo; - Foo param_3; - param_3.a = foobar.foos[gl_GlobalInvocationID.x].a; - param_3.b = foobar.foos[gl_GlobalInvocationID.x].b; - param_3.c = foobar.foos[gl_GlobalInvocationID.x].c; - param_3.d = foobar.foos[gl_GlobalInvocationID.x].d; - outdata.data[gl_GlobalInvocationID.x] = bar(param_2) + bar(param_3); -} - diff --git a/third_party/spirv-cross/reference/shaders/comp/shared.comp b/third_party/spirv-cross/reference/shaders/comp/shared.comp index d0987a6528..545ef22e61 100644 --- a/third_party/spirv-cross/reference/shaders/comp/shared.comp +++ b/third_party/spirv-cross/reference/shaders/comp/shared.comp @@ -18,7 +18,6 @@ void main() uint ident = gl_GlobalInvocationID.x; float idata = _22.in_data[ident]; sShared[gl_LocalInvocationIndex] = idata; - memoryBarrierShared(); barrier(); _44.out_data[ident] = sShared[(4u - gl_LocalInvocationIndex) - 1u]; } diff --git a/third_party/spirv-cross/reference/shaders/desktop-only/frag/fp16.invalid.desktop.frag b/third_party/spirv-cross/reference/shaders/desktop-only/frag/fp16.invalid.desktop.frag deleted file mode 100644 index faf79b2b44..0000000000 --- a/third_party/spirv-cross/reference/shaders/desktop-only/frag/fp16.invalid.desktop.frag +++ /dev/null @@ -1,159 +0,0 @@ -#version 450 -#if defined(GL_AMD_gpu_shader_half_float) -#extension GL_AMD_gpu_shader_half_float : require -#elif defined(GL_NV_gpu_shader5) -#extension GL_NV_gpu_shader5 : require -#else -#error No extension available for FP16. -#endif - -struct ResType -{ - f16vec4 _m0; - ivec4 _m1; -}; - -layout(location = 3) in f16vec4 v4; -layout(location = 2) in f16vec3 v3; -layout(location = 0) in float16_t v1; -layout(location = 1) in f16vec2 v2; - -f16mat2 test_mat2(f16vec2 a, f16vec2 b, f16vec2 c, f16vec2 d) -{ - return f16mat2(f16vec2(a), f16vec2(b)) * f16mat2(f16vec2(c), f16vec2(d)); -} - -f16mat3 test_mat3(f16vec3 a, f16vec3 b, f16vec3 c, f16vec3 d, f16vec3 e, f16vec3 f) -{ - return f16mat3(f16vec3(a), f16vec3(b), f16vec3(c)) * f16mat3(f16vec3(d), f16vec3(e), f16vec3(f)); -} - -void test_constants() -{ - float16_t a = float16_t(1.0); - float16_t b = float16_t(1.5); - float16_t c = float16_t(-1.5); - float16_t d = float16_t(0.0 / 0.0); - float16_t e = float16_t(1.0 / 0.0); - float16_t f = float16_t(-1.0 / 0.0); - float16_t g = float16_t(1014.0); - float16_t h = float16_t(9.5367431640625e-07); -} - -float16_t test_result() -{ - return float16_t(1.0); -} - -void test_conversions() -{ - float16_t one = test_result(); - int a = int(one); - uint b = uint(one); - bool c = one != float16_t(0.0); - float d = float(one); - double e = double(one); - float16_t a2 = float16_t(a); - float16_t b2 = float16_t(b); - float16_t c2 = float16_t(c); - float16_t d2 = float16_t(d); - float16_t e2 = float16_t(e); -} - -void test_builtins() -{ - f16vec4 res = radians(v4); - res = degrees(v4); - res = sin(v4); - res = cos(v4); - res = tan(v4); - res = asin(v4); - res = atan(v4, v3.xyzz); - res = atan(v4); - res = sinh(v4); - res = cosh(v4); - res = tanh(v4); - res = asinh(v4); - res = acosh(v4); - res = atanh(v4); - res = pow(v4, v4); - res = exp(v4); - res = log(v4); - res = exp2(v4); - res = log2(v4); - res = sqrt(v4); - res = inversesqrt(v4); - res = abs(v4); - res = sign(v4); - res = floor(v4); - res = trunc(v4); - res = round(v4); - res = roundEven(v4); - res = ceil(v4); - res = fract(v4); - res = mod(v4, v4); - f16vec4 tmp; - f16vec4 _231 = modf(v4, tmp); - res = _231; - res = min(v4, v4); - res = max(v4, v4); - res = clamp(v4, v4, v4); - res = mix(v4, v4, v4); - res = mix(v4, v4, lessThan(v4, v4)); - res = step(v4, v4); - res = smoothstep(v4, v4, v4); - bvec4 btmp = isnan(v4); - btmp = isinf(v4); - res = fma(v4, v4, v4); - ResType _275; - _275._m0 = frexp(v4, _275._m1); - ivec4 itmp = _275._m1; - res = _275._m0; - res = ldexp(res, itmp); - uint pack0 = packFloat2x16(v4.xy); - uint pack1 = packFloat2x16(v4.zw); - res = f16vec4(unpackFloat2x16(pack0), unpackFloat2x16(pack1)); - float16_t t0 = length(v4); - t0 = distance(v4, v4); - t0 = dot(v4, v4); - f16vec3 res3 = cross(v3, v3); - res = normalize(v4); - res = faceforward(v4, v4, v4); - res = reflect(v4, v4); - res = refract(v4, v4, v1); - btmp = lessThan(v4, v4); - btmp = lessThanEqual(v4, v4); - btmp = greaterThan(v4, v4); - btmp = greaterThanEqual(v4, v4); - btmp = equal(v4, v4); - btmp = notEqual(v4, v4); - res = dFdx(v4); - res = dFdy(v4); - res = dFdxFine(v4); - res = dFdyFine(v4); - res = dFdxCoarse(v4); - res = dFdyCoarse(v4); - res = fwidth(v4); - res = fwidthFine(v4); - res = fwidthCoarse(v4); -} - -void main() -{ - f16vec2 param = v2; - f16vec2 param_1 = v2; - f16vec2 param_2 = v3.xy; - f16vec2 param_3 = v3.xy; - f16mat2 m0 = test_mat2(param, param_1, param_2, param_3); - f16vec3 param_4 = v3; - f16vec3 param_5 = v3; - f16vec3 param_6 = v3; - f16vec3 param_7 = v4.xyz; - f16vec3 param_8 = v4.xyz; - f16vec3 param_9 = v4.yzw; - f16mat3 m1 = test_mat3(param_4, param_5, param_6, param_7, param_8, param_9); - test_constants(); - test_conversions(); - test_builtins(); -} - diff --git a/third_party/spirv-cross/reference/shaders/desktop-only/frag/image-size.frag b/third_party/spirv-cross/reference/shaders/desktop-only/frag/image-size.frag new file mode 100644 index 0000000000..5bb060398e --- /dev/null +++ b/third_party/spirv-cross/reference/shaders/desktop-only/frag/image-size.frag @@ -0,0 +1,12 @@ +#version 450 + +layout(binding = 0, r32f) uniform readonly writeonly image2D uImage1; +layout(binding = 1, r32f) uniform readonly writeonly image2D uImage2; + +layout(location = 0) out vec4 FragColor; + +void main() +{ + FragColor = vec4(vec2(imageSize(uImage1)), vec2(imageSize(uImage2))); +} + diff --git a/third_party/spirv-cross/reference/shaders/desktop-only/frag/image-size.no-qualifier-deduction.frag b/third_party/spirv-cross/reference/shaders/desktop-only/frag/image-size.no-qualifier-deduction.frag new file mode 100644 index 0000000000..1d9062064a --- /dev/null +++ b/third_party/spirv-cross/reference/shaders/desktop-only/frag/image-size.no-qualifier-deduction.frag @@ -0,0 +1,12 @@ +#version 450 + +layout(binding = 0, r32f) uniform image2D uImage1; +layout(binding = 1, r32f) uniform image2D uImage2; + +layout(location = 0) out vec4 FragColor; + +void main() +{ + FragColor = vec4(vec2(imageSize(uImage1)), vec2(imageSize(uImage2))); +} + diff --git a/third_party/spirv-cross/reference/shaders/desktop-only/tesc/basic.desktop.sso.tesc b/third_party/spirv-cross/reference/shaders/desktop-only/tesc/basic.desktop.sso.tesc index 5e958256af..c51699db6d 100644 --- a/third_party/spirv-cross/reference/shaders/desktop-only/tesc/basic.desktop.sso.tesc +++ b/third_party/spirv-cross/reference/shaders/desktop-only/tesc/basic.desktop.sso.tesc @@ -4,7 +4,7 @@ layout(vertices = 1) out; in gl_PerVertex { vec4 gl_Position; -} gl_in[gl_MaxPatchVertices]; +} gl_in[]; out gl_PerVertex { diff --git a/third_party/spirv-cross/reference/shaders/desktop-only/tese/triangle.desktop.sso.tese b/third_party/spirv-cross/reference/shaders/desktop-only/tese/triangle.desktop.sso.tese index 31027dae80..c9bacd464e 100644 --- a/third_party/spirv-cross/reference/shaders/desktop-only/tese/triangle.desktop.sso.tese +++ b/third_party/spirv-cross/reference/shaders/desktop-only/tese/triangle.desktop.sso.tese @@ -4,7 +4,7 @@ layout(triangles, cw, fractional_even_spacing) in; in gl_PerVertex { vec4 gl_Position; -} gl_in[gl_MaxPatchVertices]; +} gl_in[]; out gl_PerVertex { diff --git a/third_party/spirv-cross/reference/shaders/flatten/multi-dimensional.desktop.invalid.flatten_dim.frag b/third_party/spirv-cross/reference/shaders/flatten/multi-dimensional.desktop.invalid.flatten_dim.frag deleted file mode 100644 index ef6bb526ab..0000000000 --- a/third_party/spirv-cross/reference/shaders/flatten/multi-dimensional.desktop.invalid.flatten_dim.frag +++ /dev/null @@ -1,24 +0,0 @@ -#version 450 - -layout(binding = 0) uniform sampler2D uTextures[2 * 3 * 1]; - -layout(location = 1) in vec2 vUV; -layout(location = 0) out vec4 FragColor; -layout(location = 0) flat in int vIndex; - -void main() -{ - vec4 values3[2 * 3 * 1]; - for (int z = 0; z < 2; z++) - { - for (int y = 0; y < 3; y++) - { - for (int x = 0; x < 1; x++) - { - values3[z * 3 * 1 + y * 1 + x] = texture(uTextures[z * 3 * 1 + y * 1 + x], vUV); - } - } - } - FragColor = (values3[1 * 3 * 1 + 2 * 1 + 0] + values3[0 * 3 * 1 + 2 * 1 + 0]) + values3[(vIndex + 1) * 3 * 1 + 2 * 1 + vIndex]; -} - diff --git a/third_party/spirv-cross/reference/shaders/frag/16bit-constants.invalid.frag b/third_party/spirv-cross/reference/shaders/frag/16bit-constants.invalid.frag deleted file mode 100644 index 57d8256138..0000000000 --- a/third_party/spirv-cross/reference/shaders/frag/16bit-constants.invalid.frag +++ /dev/null @@ -1,25 +0,0 @@ -#version 450 -#if defined(GL_AMD_gpu_shader_half_float) -#extension GL_AMD_gpu_shader_half_float : require -#elif defined(GL_NV_gpu_shader5) -#extension GL_NV_gpu_shader5 : require -#else -#error No extension available for FP16. -#endif -#if defined(GL_AMD_gpu_shader_int16) -#extension GL_AMD_gpu_shader_int16 : require -#else -#error No extension available for Int16. -#endif - -layout(location = 0) out float16_t foo; -layout(location = 1) out int16_t bar; -layout(location = 2) out uint16_t baz; - -void main() -{ - foo = float16_t(1.0); - bar = 2s; - baz = 3us; -} - diff --git a/third_party/spirv-cross/reference/shaders/frag/pixel-interlock-ordered.frag b/third_party/spirv-cross/reference/shaders/frag/pixel-interlock-ordered.frag new file mode 100644 index 0000000000..46cca96c6a --- /dev/null +++ b/third_party/spirv-cross/reference/shaders/frag/pixel-interlock-ordered.frag @@ -0,0 +1,23 @@ +#version 450 +#extension GL_ARB_fragment_shader_interlock : require +layout(pixel_interlock_ordered) in; + +layout(binding = 2, std430) coherent buffer Buffer +{ + int foo; + uint bar; +} _30; + +layout(binding = 0, rgba8) uniform writeonly image2D img; +layout(binding = 1, r32ui) uniform uimage2D img2; + +void main() +{ + beginInvocationInterlockARB(); + imageStore(img, ivec2(0), vec4(1.0, 0.0, 0.0, 1.0)); + uint _27 = imageAtomicAdd(img2, ivec2(0), 1u); + _30.foo += 42; + uint _41 = atomicAnd(_30.bar, 255u); + endInvocationInterlockARB(); +} + diff --git a/third_party/spirv-cross/reference/shaders/frag/pixel-interlock-unordered.frag b/third_party/spirv-cross/reference/shaders/frag/pixel-interlock-unordered.frag new file mode 100644 index 0000000000..d60cd14518 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders/frag/pixel-interlock-unordered.frag @@ -0,0 +1,23 @@ +#version 450 +#extension GL_ARB_fragment_shader_interlock : require +layout(pixel_interlock_unordered) in; + +layout(binding = 2, std430) coherent buffer Buffer +{ + int foo; + uint bar; +} _30; + +layout(binding = 0, rgba8) uniform writeonly image2D img; +layout(binding = 1, r32ui) uniform uimage2D img2; + +void main() +{ + beginInvocationInterlockARB(); + imageStore(img, ivec2(0), vec4(1.0, 0.0, 0.0, 1.0)); + uint _27 = imageAtomicAdd(img2, ivec2(0), 1u); + _30.foo += 42; + uint _41 = atomicAnd(_30.bar, 255u); + endInvocationInterlockARB(); +} + diff --git a/third_party/spirv-cross/reference/shaders/frag/post-depth-coverage-es.frag b/third_party/spirv-cross/reference/shaders/frag/post-depth-coverage-es.frag new file mode 100644 index 0000000000..d086560e5d --- /dev/null +++ b/third_party/spirv-cross/reference/shaders/frag/post-depth-coverage-es.frag @@ -0,0 +1,14 @@ +#version 310 es +#extension GL_EXT_post_depth_coverage : require +#extension GL_OES_sample_variables : require +precision mediump float; +precision highp int; +layout(early_fragment_tests, post_depth_coverage) in; + +layout(location = 0) out vec4 FragColor; + +void main() +{ + FragColor = vec4(float(gl_SampleMaskIn[0])); +} + diff --git a/third_party/spirv-cross/reference/shaders/frag/post-depth-coverage.frag b/third_party/spirv-cross/reference/shaders/frag/post-depth-coverage.frag index 3e78fcd0a7..caca9c03cb 100644 --- a/third_party/spirv-cross/reference/shaders/frag/post-depth-coverage.frag +++ b/third_party/spirv-cross/reference/shaders/frag/post-depth-coverage.frag @@ -1,5 +1,9 @@ #version 450 +#if defined(GL_ARB_post_depth_coverge) #extension GL_ARB_post_depth_coverage : require +#else +#extension GL_EXT_post_depth_coverage : require +#endif layout(early_fragment_tests, post_depth_coverage) in; layout(location = 0) out vec4 FragColor; diff --git a/third_party/spirv-cross/reference/shaders/frag/sample-interlock-ordered.frag b/third_party/spirv-cross/reference/shaders/frag/sample-interlock-ordered.frag new file mode 100644 index 0000000000..67ca5560e3 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders/frag/sample-interlock-ordered.frag @@ -0,0 +1,23 @@ +#version 450 +#extension GL_ARB_fragment_shader_interlock : require +layout(sample_interlock_ordered) in; + +layout(binding = 2, std430) coherent buffer Buffer +{ + int foo; + uint bar; +} _30; + +layout(binding = 0, rgba8) uniform writeonly image2D img; +layout(binding = 1, r32ui) uniform uimage2D img2; + +void main() +{ + beginInvocationInterlockARB(); + imageStore(img, ivec2(0), vec4(1.0, 0.0, 0.0, 1.0)); + uint _27 = imageAtomicAdd(img2, ivec2(0), 1u); + _30.foo += 42; + uint _47 = atomicAnd(_30.bar, uint(gl_SampleMaskIn[0])); + endInvocationInterlockARB(); +} + diff --git a/third_party/spirv-cross/reference/shaders/frag/sample-interlock-unordered.frag b/third_party/spirv-cross/reference/shaders/frag/sample-interlock-unordered.frag new file mode 100644 index 0000000000..ea74397d63 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders/frag/sample-interlock-unordered.frag @@ -0,0 +1,23 @@ +#version 450 +#extension GL_ARB_fragment_shader_interlock : require +layout(sample_interlock_unordered) in; + +layout(binding = 2, std430) coherent buffer Buffer +{ + int foo; + uint bar; +} _30; + +layout(binding = 0, rgba8) uniform writeonly image2D img; +layout(binding = 1, r32ui) uniform uimage2D img2; + +void main() +{ + beginInvocationInterlockARB(); + imageStore(img, ivec2(0), vec4(1.0, 0.0, 0.0, 1.0)); + uint _27 = imageAtomicAdd(img2, ivec2(0), 1u); + _30.foo += 42; + uint _41 = atomicAnd(_30.bar, 255u); + endInvocationInterlockARB(); +} + diff --git a/third_party/spirv-cross/reference/shaders/frag/struct-type-unrelated-alias.frag b/third_party/spirv-cross/reference/shaders/frag/struct-type-unrelated-alias.frag new file mode 100644 index 0000000000..524a8d3c0b --- /dev/null +++ b/third_party/spirv-cross/reference/shaders/frag/struct-type-unrelated-alias.frag @@ -0,0 +1,23 @@ +#version 450 + +struct T +{ + float a; +}; + +struct T_1 +{ + float b; +}; + +layout(location = 0) out float FragColor; + +void main() +{ + T foo; + foo.a = 10.0; + T_1 bar; + bar.b = 20.0; + FragColor = foo.a + bar.b; +} + diff --git a/third_party/spirv-cross/reference/shaders/geom/geometry-passthrough.geom b/third_party/spirv-cross/reference/shaders/geom/geometry-passthrough.geom new file mode 100644 index 0000000000..d0d8806ad2 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders/geom/geometry-passthrough.geom @@ -0,0 +1,27 @@ +#version 450 +#extension GL_NV_geometry_shader_passthrough : require +layout(triangles) in; + +layout(passthrough) in gl_PerVertex +{ + vec4 gl_Position; +} gl_in[]; + +layout(passthrough, location = 0) in VertexBlock +{ + int a; + int b; +} v1[3]; + +layout(location = 2) in VertexBlock2 +{ + int a; + layout(passthrough) int b; +} v2[3]; + + +void main() +{ + gl_Layer = (gl_InvocationID + v1[0].a) + v2[1].b; +} + diff --git a/third_party/spirv-cross/reference/shaders/geom/multi-stream.geom b/third_party/spirv-cross/reference/shaders/geom/multi-stream.geom new file mode 100644 index 0000000000..548164d780 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders/geom/multi-stream.geom @@ -0,0 +1,14 @@ +#version 450 +layout(triangles) in; +layout(max_vertices = 2, points) out; + +void main() +{ + gl_Position = gl_in[0].gl_Position; + EmitStreamVertex(0); + EndStreamPrimitive(0); + gl_Position = gl_in[0].gl_Position + vec4(2.0); + EmitStreamVertex(1); + EndStreamPrimitive(1); +} + diff --git a/third_party/spirv-cross/reference/shaders/tese/load-array-of-array.tese b/third_party/spirv-cross/reference/shaders/tese/load-array-of-array.tese new file mode 100644 index 0000000000..7fab08ef66 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders/tese/load-array-of-array.tese @@ -0,0 +1,16 @@ +#version 450 +layout(quads, ccw, equal_spacing) in; + +layout(location = 0) in vec4 vTexCoord[][1]; + +void main() +{ + vec4 _17_unrolled[32][1]; + for (int i = 0; i < int(32); i++) + { + _17_unrolled[i] = vTexCoord[i]; + } + vec4 tmp[32][1] = _17_unrolled; + gl_Position = (tmp[0][0] + tmp[2][0]) + tmp[3][0]; +} + diff --git a/third_party/spirv-cross/reference/shaders/tese/patch-input-array.tese b/third_party/spirv-cross/reference/shaders/tese/patch-input-array.tese new file mode 100644 index 0000000000..413d8b391f --- /dev/null +++ b/third_party/spirv-cross/reference/shaders/tese/patch-input-array.tese @@ -0,0 +1,10 @@ +#version 450 +layout(quads, ccw, equal_spacing) in; + +layout(location = 0) patch in float P[4]; + +void main() +{ + gl_Position = vec4(P[0], P[1], P[2], P[3]); +} + diff --git a/third_party/spirv-cross/reference/shaders/vert/transform-feedback-decorations.vert b/third_party/spirv-cross/reference/shaders/vert/transform-feedback-decorations.vert new file mode 100644 index 0000000000..23e7cf3c19 --- /dev/null +++ b/third_party/spirv-cross/reference/shaders/vert/transform-feedback-decorations.vert @@ -0,0 +1,22 @@ +#version 450 + +layout(xfb_buffer = 1, xfb_stride = 20) out gl_PerVertex +{ + layout(xfb_offset = 4) vec4 gl_Position; + float gl_PointSize; +}; + +layout(location = 0, xfb_buffer = 2, xfb_stride = 32, xfb_offset = 16) out vec4 vFoo; +layout(xfb_buffer = 3, xfb_stride = 16) out VertOut +{ + layout(location = 1, xfb_offset = 0) vec4 vBar; +} _22; + + +void main() +{ + gl_Position = vec4(1.0); + vFoo = vec4(3.0); + _22.vBar = vec4(5.0); +} + diff --git a/third_party/spirv-cross/reference/shaders/vulkan/comp/struct-packing-scalar.nocompat.invalid.vk.comp.vk b/third_party/spirv-cross/reference/shaders/vulkan/comp/struct-packing-scalar.nocompat.invalid.vk.comp.vk deleted file mode 100644 index d67e0beeb6..0000000000 --- a/third_party/spirv-cross/reference/shaders/vulkan/comp/struct-packing-scalar.nocompat.invalid.vk.comp.vk +++ /dev/null @@ -1,147 +0,0 @@ -#version 310 es -#extension GL_EXT_scalar_block_layout : require -layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in; - -struct S0 -{ - vec2 a[1]; - float b; -}; - -struct S1 -{ - vec3 a; - float b; -}; - -struct S2 -{ - vec3 a[1]; - float b; -}; - -struct S3 -{ - vec2 a; - float b; -}; - -struct S4 -{ - vec2 c; -}; - -struct Content -{ - S0 m0s[1]; - S1 m1s[1]; - S2 m2s[1]; - S0 m0; - S1 m1; - S2 m2; - S3 m3; - float m4; - S4 m3s[8]; -}; - -struct S0_1 -{ - vec2 a[1]; - float b; -}; - -struct S1_1 -{ - vec3 a; - float b; -}; - -struct S2_1 -{ - vec3 a[1]; - float b; -}; - -struct S3_1 -{ - vec2 a; - float b; -}; - -struct S4_1 -{ - vec2 c; -}; - -struct Content_1 -{ - S0_1 m0s[1]; - S1_1 m1s[1]; - S2_1 m2s[1]; - S0_1 m0; - S1_1 m1; - S2_1 m2; - S3_1 m3; - float m4; - S4_1 m3s[8]; -}; - -layout(set = 0, binding = 1, scalar) restrict buffer SSBO1 -{ - Content content; - Content content1[2]; - Content content2; - mat2 m0; - mat2 m1; - mat2x3 m2[4]; - mat3x2 m3; - layout(row_major) mat2 m4; - layout(row_major) mat2 m5[9]; - layout(row_major) mat2x3 m6[4][2]; - layout(row_major) mat3x2 m7; - float array[]; -} ssbo_430; - -layout(set = 0, binding = 0, std140) restrict buffer SSBO0 -{ - Content_1 content; - Content_1 content1[2]; - Content_1 content2; - mat2 m0; - mat2 m1; - mat2x3 m2[4]; - mat3x2 m3; - layout(row_major) mat2 m4; - layout(row_major) mat2 m5[9]; - layout(row_major) mat2x3 m6[4][2]; - layout(row_major) mat3x2 m7; - float array[]; -} ssbo_140; - -void main() -{ - ssbo_430.content.m0s[0].a[0] = ssbo_140.content.m0s[0].a[0]; - ssbo_430.content.m0s[0].b = ssbo_140.content.m0s[0].b; - ssbo_430.content.m1s[0].a = ssbo_140.content.m1s[0].a; - ssbo_430.content.m1s[0].b = ssbo_140.content.m1s[0].b; - ssbo_430.content.m2s[0].a[0] = ssbo_140.content.m2s[0].a[0]; - ssbo_430.content.m2s[0].b = ssbo_140.content.m2s[0].b; - ssbo_430.content.m0.a[0] = ssbo_140.content.m0.a[0]; - ssbo_430.content.m0.b = ssbo_140.content.m0.b; - ssbo_430.content.m1.a = ssbo_140.content.m1.a; - ssbo_430.content.m1.b = ssbo_140.content.m1.b; - ssbo_430.content.m2.a[0] = ssbo_140.content.m2.a[0]; - ssbo_430.content.m2.b = ssbo_140.content.m2.b; - ssbo_430.content.m3.a = ssbo_140.content.m3.a; - ssbo_430.content.m3.b = ssbo_140.content.m3.b; - ssbo_430.content.m4 = ssbo_140.content.m4; - ssbo_430.content.m3s[0].c = ssbo_140.content.m3s[0].c; - ssbo_430.content.m3s[1].c = ssbo_140.content.m3s[1].c; - ssbo_430.content.m3s[2].c = ssbo_140.content.m3s[2].c; - ssbo_430.content.m3s[3].c = ssbo_140.content.m3s[3].c; - ssbo_430.content.m3s[4].c = ssbo_140.content.m3s[4].c; - ssbo_430.content.m3s[5].c = ssbo_140.content.m3s[5].c; - ssbo_430.content.m3s[6].c = ssbo_140.content.m3s[6].c; - ssbo_430.content.m3s[7].c = ssbo_140.content.m3s[7].c; -} - diff --git a/third_party/spirv-cross/reference/shaders/vulkan/comp/subgroups.nocompat.invalid.vk.comp.vk b/third_party/spirv-cross/reference/shaders/vulkan/comp/subgroups.nocompat.invalid.vk.comp.vk deleted file mode 100644 index 6d288574f7..0000000000 --- a/third_party/spirv-cross/reference/shaders/vulkan/comp/subgroups.nocompat.invalid.vk.comp.vk +++ /dev/null @@ -1,110 +0,0 @@ -#version 450 -#extension GL_KHR_shader_subgroup_basic : require -#extension GL_KHR_shader_subgroup_ballot : require -#extension GL_KHR_shader_subgroup_shuffle : require -#extension GL_KHR_shader_subgroup_shuffle_relative : require -#extension GL_KHR_shader_subgroup_vote : require -#extension GL_KHR_shader_subgroup_arithmetic : require -#extension GL_KHR_shader_subgroup_clustered : require -#extension GL_KHR_shader_subgroup_quad : require -layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in; - -layout(set = 0, binding = 0, std430) buffer SSBO -{ - float FragColor; -} _9; - -void main() -{ - _9.FragColor = float(gl_NumSubgroups); - _9.FragColor = float(gl_SubgroupID); - _9.FragColor = float(gl_SubgroupSize); - _9.FragColor = float(gl_SubgroupInvocationID); - subgroupMemoryBarrier(); - subgroupBarrier(); - subgroupMemoryBarrier(); - subgroupMemoryBarrierBuffer(); - subgroupMemoryBarrierShared(); - subgroupMemoryBarrierImage(); - bool elected = subgroupElect(); - _9.FragColor = vec4(gl_SubgroupEqMask).x; - _9.FragColor = vec4(gl_SubgroupGeMask).x; - _9.FragColor = vec4(gl_SubgroupGtMask).x; - _9.FragColor = vec4(gl_SubgroupLeMask).x; - _9.FragColor = vec4(gl_SubgroupLtMask).x; - vec4 broadcasted = subgroupBroadcast(vec4(10.0), 8u); - vec3 first = subgroupBroadcastFirst(vec3(20.0)); - uvec4 ballot_value = subgroupBallot(true); - bool inverse_ballot_value = subgroupInverseBallot(ballot_value); - bool bit_extracted = subgroupBallotBitExtract(uvec4(10u), 8u); - uint bit_count = subgroupBallotBitCount(ballot_value); - uint inclusive_bit_count = subgroupBallotInclusiveBitCount(ballot_value); - uint exclusive_bit_count = subgroupBallotExclusiveBitCount(ballot_value); - uint lsb = subgroupBallotFindLSB(ballot_value); - uint msb = subgroupBallotFindMSB(ballot_value); - uint shuffled = subgroupShuffle(10u, 8u); - uint shuffled_xor = subgroupShuffleXor(30u, 8u); - uint shuffled_up = subgroupShuffleUp(20u, 4u); - uint shuffled_down = subgroupShuffleDown(20u, 4u); - bool has_all = subgroupAll(true); - bool has_any = subgroupAny(true); - bool has_equal = subgroupAllEqual(true); - vec4 added = subgroupAdd(vec4(20.0)); - ivec4 iadded = subgroupAdd(ivec4(20)); - vec4 multiplied = subgroupMul(vec4(20.0)); - ivec4 imultiplied = subgroupMul(ivec4(20)); - vec4 lo = subgroupMin(vec4(20.0)); - vec4 hi = subgroupMax(vec4(20.0)); - ivec4 slo = subgroupMin(ivec4(20)); - ivec4 shi = subgroupMax(ivec4(20)); - uvec4 ulo = subgroupMin(uvec4(20u)); - uvec4 uhi = subgroupMax(uvec4(20u)); - uvec4 anded = subgroupAnd(ballot_value); - uvec4 ored = subgroupOr(ballot_value); - uvec4 xored = subgroupXor(ballot_value); - added = subgroupInclusiveAdd(added); - iadded = subgroupInclusiveAdd(iadded); - multiplied = subgroupInclusiveMul(multiplied); - imultiplied = subgroupInclusiveMul(imultiplied); - lo = subgroupInclusiveMin(lo); - hi = subgroupInclusiveMax(hi); - slo = subgroupInclusiveMin(slo); - shi = subgroupInclusiveMax(shi); - ulo = subgroupInclusiveMin(ulo); - uhi = subgroupInclusiveMax(uhi); - anded = subgroupInclusiveAnd(anded); - ored = subgroupInclusiveOr(ored); - xored = subgroupInclusiveXor(ored); - added = subgroupExclusiveAdd(lo); - added = subgroupExclusiveAdd(multiplied); - multiplied = subgroupExclusiveMul(multiplied); - iadded = subgroupExclusiveAdd(imultiplied); - imultiplied = subgroupExclusiveMul(imultiplied); - lo = subgroupExclusiveMin(lo); - hi = subgroupExclusiveMax(hi); - ulo = subgroupExclusiveMin(ulo); - uhi = subgroupExclusiveMax(uhi); - slo = subgroupExclusiveMin(slo); - shi = subgroupExclusiveMax(shi); - anded = subgroupExclusiveAnd(anded); - ored = subgroupExclusiveOr(ored); - xored = subgroupExclusiveXor(ored); - added = subgroupClusteredAdd(added, 4u); - multiplied = subgroupClusteredMul(multiplied, 4u); - iadded = subgroupClusteredAdd(iadded, 4u); - imultiplied = subgroupClusteredMul(imultiplied, 4u); - lo = subgroupClusteredMin(lo, 4u); - hi = subgroupClusteredMax(hi, 4u); - ulo = subgroupClusteredMin(ulo, 4u); - uhi = subgroupClusteredMax(uhi, 4u); - slo = subgroupClusteredMin(slo, 4u); - shi = subgroupClusteredMax(shi, 4u); - anded = subgroupClusteredAnd(anded, 4u); - ored = subgroupClusteredOr(ored, 4u); - xored = subgroupClusteredXor(xored, 4u); - vec4 swap_horiz = subgroupQuadSwapHorizontal(vec4(20.0)); - vec4 swap_vertical = subgroupQuadSwapVertical(vec4(20.0)); - vec4 swap_diagonal = subgroupQuadSwapDiagonal(vec4(20.0)); - vec4 quad_broadcast = subgroupQuadBroadcast(vec4(20.0), 3u); -} - diff --git a/third_party/spirv-cross/reference/shaders/vulkan/frag/scalar-block-layout-ubo-std430.vk.nocompat.invalid.frag.vk b/third_party/spirv-cross/reference/shaders/vulkan/frag/scalar-block-layout-ubo-std430.vk.nocompat.invalid.frag.vk deleted file mode 100644 index 434cb3d3d9..0000000000 --- a/third_party/spirv-cross/reference/shaders/vulkan/frag/scalar-block-layout-ubo-std430.vk.nocompat.invalid.frag.vk +++ /dev/null @@ -1,24 +0,0 @@ -#version 450 -#extension GL_EXT_scalar_block_layout : require - -layout(set = 0, binding = 0, std430) uniform UBO -{ - float a[1024]; - vec3 b[2]; -} _17; - -layout(set = 0, binding = 1, std430) uniform UBOEnhancedLayout -{ - layout(offset = 0) float c[1024]; - layout(offset = 4096) vec3 d[2]; - layout(offset = 10000) float e; -} _30; - -layout(location = 0) out float FragColor; -layout(location = 0) flat in int vIndex; - -void main() -{ - FragColor = (_17.a[vIndex] + _30.c[vIndex]) + _30.e; -} - diff --git a/third_party/spirv-cross/shaders-hlsl-no-opt/asm/comp/access-chain-load-store-composite.asm.comp b/third_party/spirv-cross/shaders-hlsl-no-opt/asm/comp/access-chain-load-store-composite.asm.comp new file mode 100644 index 0000000000..3371e3af21 --- /dev/null +++ b/third_party/spirv-cross/shaders-hlsl-no-opt/asm/comp/access-chain-load-store-composite.asm.comp @@ -0,0 +1,118 @@ +; SPIR-V +; Version: 1.0 +; Generator: Khronos Glslang Reference Front End; 8 +; Bound: 437 +; Schema: 0 + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" + OpExecutionMode %main LocalSize 1 1 1 + OpSource GLSL 450 + OpName %main "main" + OpName %Baz "Baz" + OpMemberName %Baz 0 "c" + OpName %Bar "Bar" + OpMemberName %Bar 0 "d" + OpMemberName %Bar 1 "baz" + OpName %Foo "Foo" + OpMemberName %Foo 0 "a" + OpMemberName %Foo 1 "b" + OpMemberName %Foo 2 "c" + OpName %Baz_0 "Baz" + OpMemberName %Baz_0 0 "c" + OpName %Bar_0 "Bar" + OpMemberName %Bar_0 0 "d" + OpMemberName %Bar_0 1 "baz" + OpName %Foo_0 "Foo" + OpMemberName %Foo_0 0 "a" + OpMemberName %Foo_0 1 "b" + OpMemberName %Foo_0 2 "c" + OpName %SSBO "SSBO" + OpMemberName %SSBO 0 "foo" + OpMemberName %SSBO 1 "foo2" + OpName %_ "" + OpDecorate %_arr_float_uint_4_0 ArrayStride 4 + OpDecorate %_arr__arr_float_uint_4_0_uint_2 ArrayStride 16 + OpMemberDecorate %Baz_0 0 Offset 0 + OpDecorate %_arr_Baz_0_uint_2 ArrayStride 4 + OpMemberDecorate %Bar_0 0 Offset 0 + OpMemberDecorate %Bar_0 1 Offset 32 + OpDecorate %_arr_Bar_0_uint_5 ArrayStride 40 + OpMemberDecorate %Foo_0 0 RowMajor + OpMemberDecorate %Foo_0 0 Offset 0 + OpMemberDecorate %Foo_0 0 MatrixStride 8 + OpMemberDecorate %Foo_0 1 Offset 16 + OpMemberDecorate %Foo_0 2 Offset 24 + OpMemberDecorate %SSBO 0 Offset 0 + OpMemberDecorate %SSBO 1 Offset 224 + OpDecorate %SSBO BufferBlock + OpDecorate %_ DescriptorSet 0 + OpDecorate %_ Binding 0 + OpDecorate %gl_WorkGroupSize BuiltIn WorkgroupSize + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %v2float = OpTypeVector %float 2 +%mat2v2float = OpTypeMatrix %v2float 2 + %uint = OpTypeInt 32 0 + %uint_4 = OpConstant %uint 4 +%_arr_float_uint_4 = OpTypeArray %float %uint_4 + %uint_2 = OpConstant %uint 2 +%_arr__arr_float_uint_4_uint_2 = OpTypeArray %_arr_float_uint_4 %uint_2 + %Baz = OpTypeStruct %float +%_arr_Baz_uint_2 = OpTypeArray %Baz %uint_2 + %Bar = OpTypeStruct %_arr__arr_float_uint_4_uint_2 %_arr_Baz_uint_2 + %uint_5 = OpConstant %uint 5 +%_arr_Bar_uint_5 = OpTypeArray %Bar %uint_5 + %Foo = OpTypeStruct %mat2v2float %v2float %_arr_Bar_uint_5 +%_ptr_Function_Foo = OpTypePointer Function %Foo +%_arr_float_uint_4_0 = OpTypeArray %float %uint_4 +%_arr__arr_float_uint_4_0_uint_2 = OpTypeArray %_arr_float_uint_4_0 %uint_2 + %Baz_0 = OpTypeStruct %float +%_arr_Baz_0_uint_2 = OpTypeArray %Baz_0 %uint_2 + %Bar_0 = OpTypeStruct %_arr__arr_float_uint_4_0_uint_2 %_arr_Baz_0_uint_2 +%_arr_Bar_0_uint_5 = OpTypeArray %Bar_0 %uint_5 + %Foo_0 = OpTypeStruct %mat2v2float %v2float %_arr_Bar_0_uint_5 + %SSBO = OpTypeStruct %Foo_0 %Foo_0 +%_ptr_Uniform_SSBO = OpTypePointer Uniform %SSBO + %_ = OpVariable %_ptr_Uniform_SSBO Uniform + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 +%_ptr_Uniform_Foo_0 = OpTypePointer Uniform %Foo_0 +%_ptr_Function_mat2v2float = OpTypePointer Function %mat2v2float + %int_1 = OpConstant %int 1 +%_ptr_Function_v2float = OpTypePointer Function %v2float + %int_2 = OpConstant %int 2 +%_ptr_Function__arr_Bar_uint_5 = OpTypePointer Function %_arr_Bar_uint_5 +%_ptr_Function_Bar = OpTypePointer Function %Bar +%_ptr_Function__arr__arr_float_uint_4_uint_2 = OpTypePointer Function %_arr__arr_float_uint_4_uint_2 +%_ptr_Function__arr_float_uint_4 = OpTypePointer Function %_arr_float_uint_4 +%_ptr_Function_float = OpTypePointer Function %float + %int_3 = OpConstant %int 3 +%_ptr_Function__arr_Baz_uint_2 = OpTypePointer Function %_arr_Baz_uint_2 +%_ptr_Function_Baz = OpTypePointer Function %Baz + %int_4 = OpConstant %int 4 + %float_1 = OpConstant %float 1 + %float_2 = OpConstant %float 2 + %float_5 = OpConstant %float 5 +%_ptr_Uniform_mat2v2float = OpTypePointer Uniform %mat2v2float +%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float +%_ptr_Uniform__arr_Bar_0_uint_5 = OpTypePointer Uniform %_arr_Bar_0_uint_5 +%_ptr_Uniform_Bar_0 = OpTypePointer Uniform %Bar_0 +%_ptr_Uniform__arr__arr_float_uint_4_0_uint_2 = OpTypePointer Uniform %_arr__arr_float_uint_4_0_uint_2 +%_ptr_Uniform__arr_float_uint_4_0 = OpTypePointer Uniform %_arr_float_uint_4_0 +%_ptr_Uniform_float = OpTypePointer Uniform %float +%_ptr_Uniform__arr_Baz_0_uint_2 = OpTypePointer Uniform %_arr_Baz_0_uint_2 +%_ptr_Uniform_Baz_0 = OpTypePointer Uniform %Baz_0 + %v3uint = OpTypeVector %uint 3 + %uint_1 = OpConstant %uint 1 +%gl_WorkGroupSize = OpConstantComposite %v3uint %uint_1 %uint_1 %uint_1 + %main = OpFunction %void None %3 + %5 = OpLabel + %ptr_load = OpAccessChain %_ptr_Uniform_Foo_0 %_ %int_0 + %ptr_store = OpAccessChain %_ptr_Uniform_Foo_0 %_ %int_1 + %loaded = OpLoad %Foo_0 %ptr_load + OpStore %ptr_store %loaded + OpReturn + OpFunctionEnd diff --git a/third_party/spirv-cross/shaders-hlsl-no-opt/asm/comp/aliased-struct-divergent-member-name.asm.comp b/third_party/spirv-cross/shaders-hlsl-no-opt/asm/comp/aliased-struct-divergent-member-name.asm.comp new file mode 100644 index 0000000000..87aee2db54 --- /dev/null +++ b/third_party/spirv-cross/shaders-hlsl-no-opt/asm/comp/aliased-struct-divergent-member-name.asm.comp @@ -0,0 +1,77 @@ +; SPIR-V +; Version: 1.0 +; Generator: Khronos Glslang Reference Front End; 7 +; Bound: 37 +; Schema: 0 + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" + OpExecutionMode %main LocalSize 1 1 1 + OpSource GLSL 450 + OpName %main "main" + OpName %T "T" + OpMemberName %T 0 "a" + OpName %v "v" + OpName %T_0 "T" + OpMemberName %T_0 0 "b" + OpName %SSBO1 "SSBO1" + OpMemberName %SSBO1 0 "foo" + OpName %_ "" + OpName %T_1 "T" + OpMemberName %T_1 0 "c" + OpName %SSBO2 "SSBO2" + OpMemberName %SSBO2 0 "bar" + OpName %__0 "" + OpMemberDecorate %T_0 0 Offset 0 + OpDecorate %_runtimearr_T_0 ArrayStride 4 + OpMemberDecorate %SSBO1 0 Offset 0 + OpDecorate %SSBO1 BufferBlock + OpDecorate %_ DescriptorSet 0 + OpDecorate %_ Binding 0 + OpMemberDecorate %T_1 0 Offset 0 + OpDecorate %_runtimearr_T_1 ArrayStride 16 + OpMemberDecorate %SSBO2 0 Offset 0 + OpDecorate %SSBO2 BufferBlock + OpDecorate %__0 DescriptorSet 0 + OpDecorate %__0 Binding 1 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %T = OpTypeStruct %float +%_ptr_Function_T = OpTypePointer Function %T + %float_40 = OpConstant %float 40 + %11 = OpConstantComposite %T %float_40 + %T_0 = OpTypeStruct %float +%_runtimearr_T_0 = OpTypeRuntimeArray %T_0 + %SSBO1 = OpTypeStruct %_runtimearr_T_0 +%_ptr_Uniform_SSBO1 = OpTypePointer Uniform %SSBO1 + %_ = OpVariable %_ptr_Uniform_SSBO1 Uniform + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 + %int_10 = OpConstant %int 10 +%_ptr_Uniform_T_0 = OpTypePointer Uniform %T_0 +%_ptr_Uniform_float = OpTypePointer Uniform %float + %T_1 = OpTypeStruct %float +%_runtimearr_T_1 = OpTypeRuntimeArray %T_1 + %SSBO2 = OpTypeStruct %_runtimearr_T_1 +%_ptr_Uniform_SSBO2 = OpTypePointer Uniform %SSBO2 + %__0 = OpVariable %_ptr_Uniform_SSBO2 Uniform + %int_30 = OpConstant %int 30 +%_ptr_Uniform_T_1 = OpTypePointer Uniform %T_1 + %main = OpFunction %void None %3 + %5 = OpLabel + %v = OpVariable %_ptr_Function_T Function + OpStore %v %11 + %20 = OpLoad %T %v + %22 = OpAccessChain %_ptr_Uniform_T_0 %_ %int_0 %int_10 + %23 = OpCompositeExtract %float %20 0 + %25 = OpAccessChain %_ptr_Uniform_float %22 %int_0 + OpStore %25 %23 + %32 = OpLoad %T %v + %34 = OpAccessChain %_ptr_Uniform_T_1 %__0 %int_0 %int_30 + %35 = OpCompositeExtract %float %32 0 + %36 = OpAccessChain %_ptr_Uniform_float %34 %int_0 + OpStore %36 %35 + OpReturn + OpFunctionEnd diff --git a/third_party/spirv-cross/shaders-hlsl-no-opt/asm/comp/bitfield-signed-operations.asm.comp b/third_party/spirv-cross/shaders-hlsl-no-opt/asm/comp/bitfield-signed-operations.asm.comp new file mode 100644 index 0000000000..435fa32221 --- /dev/null +++ b/third_party/spirv-cross/shaders-hlsl-no-opt/asm/comp/bitfield-signed-operations.asm.comp @@ -0,0 +1,97 @@ +; SPIR-V +; Version: 1.0 +; Generator: Khronos Glslang Reference Front End; 7 +; Bound: 26 +; Schema: 0 + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" + OpExecutionMode %main LocalSize 1 1 1 + OpSource GLSL 450 + OpName %main "main" + OpName %SSBO "SSBO" + OpMemberName %SSBO 0 "ints" + OpMemberName %SSBO 1 "uints" + OpName %_ "" + OpMemberDecorate %SSBO 0 Offset 0 + OpMemberDecorate %SSBO 1 Offset 16 + OpDecorate %SSBO BufferBlock + OpDecorate %_ DescriptorSet 0 + OpDecorate %_ Binding 0 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %int = OpTypeInt 32 1 + %v4int = OpTypeVector %int 4 + %uint = OpTypeInt 32 0 + %v4uint = OpTypeVector %uint 4 + + %int_1 = OpConstant %int 1 + %uint_11 = OpConstant %uint 11 + + %SSBO = OpTypeStruct %v4int %v4uint +%_ptr_Uniform_SSBO = OpTypePointer Uniform %SSBO + %_ = OpVariable %_ptr_Uniform_SSBO Uniform + %int_0 = OpConstant %int 0 +%_ptr_Uniform_v4int = OpTypePointer Uniform %v4int +%_ptr_Uniform_v4uint = OpTypePointer Uniform %v4uint + %main = OpFunction %void None %3 + %5 = OpLabel + %ints_ptr = OpAccessChain %_ptr_Uniform_v4int %_ %int_0 + %uints_ptr = OpAccessChain %_ptr_Uniform_v4uint %_ %int_1 + %ints = OpLoad %v4int %ints_ptr + %uints = OpLoad %v4uint %uints_ptr + + %ints_alt = OpVectorShuffle %v4int %ints %ints 3 2 1 0 + %uints_alt = OpVectorShuffle %v4uint %uints %uints 3 2 1 0 + + %int_to_int_popcount = OpBitCount %v4int %ints + %int_to_uint_popcount = OpBitCount %v4uint %ints + %uint_to_int_popcount = OpBitCount %v4int %uints + %uint_to_uint_popcount = OpBitCount %v4uint %uints + + ; BitReverse must have matching types w.r.t. sign, yay. + %int_to_int_reverse = OpBitReverse %v4int %ints + ;%int_to_uint_reverse = OpBitReverse %v4uint %ints + ;%uint_to_int_reverse = OpBitReverse %v4int %uints + %uint_to_uint_reverse = OpBitReverse %v4uint %uints + + ; Base and Result must match. + %int_to_int_sbit = OpBitFieldSExtract %v4int %ints %int_1 %uint_11 + ;%int_to_uint_sbit = OpBitFieldSExtract %v4uint %ints %offset %count + ;%uint_to_int_sbit = OpBitFieldSExtract %v4int %uints %offset %count + %uint_to_uint_sbit = OpBitFieldSExtract %v4uint %uints %uint_11 %int_1 + + ; Base and Result must match. + %int_to_int_ubit = OpBitFieldUExtract %v4int %ints %int_1 %uint_11 + ;%int_to_uint_ubit = OpBitFieldUExtract %v4uint %ints %offset %count + ;%uint_to_int_ubit = OpBitFieldUExtract %v4int %uints %offset %count + %uint_to_uint_ubit = OpBitFieldUExtract %v4uint %uints %uint_11 %int_1 + + %int_to_int_insert = OpBitFieldInsert %v4int %ints %ints_alt %int_1 %uint_11 + %uint_to_uint_insert = OpBitFieldInsert %v4uint %uints %uints_alt %uint_11 %int_1 + + OpStore %ints_ptr %int_to_int_popcount + OpStore %uints_ptr %int_to_uint_popcount + OpStore %ints_ptr %uint_to_int_popcount + OpStore %uints_ptr %uint_to_uint_popcount + + OpStore %ints_ptr %int_to_int_reverse + ;OpStore %uints_ptr %int_to_uint_reverse + ;OpStore %ints_ptr %uint_to_int_reverse + OpStore %uints_ptr %uint_to_uint_reverse + + OpStore %ints_ptr %int_to_int_sbit + ;OpStore %uints_ptr %int_to_uint_sbit + ;OpStore %ints_ptr %uint_to_int_sbit + OpStore %uints_ptr %uint_to_uint_sbit + + OpStore %ints_ptr %int_to_int_ubit + ;OpStore %uints_ptr %int_to_uint_ubit + ;OpStore %ints_ptr %uint_to_int_ubit + OpStore %uints_ptr %uint_to_uint_ubit + + OpStore %ints_ptr %int_to_int_insert + OpStore %uints_ptr %uint_to_uint_insert + + OpReturn + OpFunctionEnd diff --git a/third_party/spirv-cross/shaders-hlsl/asm/comp/storage-buffer-basic.invalid.nofxc.asm.comp b/third_party/spirv-cross/shaders-hlsl-no-opt/asm/comp/storage-buffer-basic.invalid.nofxc.asm.comp similarity index 100% rename from third_party/spirv-cross/shaders-hlsl/asm/comp/storage-buffer-basic.invalid.nofxc.asm.comp rename to third_party/spirv-cross/shaders-hlsl-no-opt/asm/comp/storage-buffer-basic.invalid.nofxc.asm.comp diff --git a/third_party/spirv-cross/shaders-hlsl-no-opt/asm/frag/empty-struct-in-struct.asm.frag b/third_party/spirv-cross/shaders-hlsl-no-opt/asm/frag/empty-struct-in-struct.asm.frag new file mode 100644 index 0000000000..a9650ddbb6 --- /dev/null +++ b/third_party/spirv-cross/shaders-hlsl-no-opt/asm/frag/empty-struct-in-struct.asm.frag @@ -0,0 +1,61 @@ +; SPIR-V +; Version: 1.2 +; Generator: Khronos; 0 +; Bound: 43 +; Schema: 0 + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %EntryPoint_Main "main" + OpExecutionMode %EntryPoint_Main OriginUpperLeft + OpSource Unknown 100 + OpName %EmptyStructTest "EmptyStructTest" + OpName %EmptyStruct2Test "EmptyStruct2Test" + OpName %GetValue "GetValue" + OpName %GetValue2 "GetValue" + OpName %self "self" + OpName %self2 "self" + OpName %emptyStruct "emptyStruct" + OpName %value "value" + OpName %EntryPoint_Main "EntryPoint_Main" + +%EmptyStructTest = OpTypeStruct +%EmptyStruct2Test = OpTypeStruct %EmptyStructTest +%_ptr_Function_EmptyStruct2Test = OpTypePointer Function %EmptyStruct2Test + %float = OpTypeFloat 32 +%_ptr_Function_float = OpTypePointer Function %float + %5 = OpTypeFunction %float %_ptr_Function_EmptyStruct2Test + %6 = OpTypeFunction %float %EmptyStruct2Test + %void = OpTypeVoid +%_ptr_Function_void = OpTypePointer Function %void + %8 = OpTypeFunction %void %_ptr_Function_EmptyStruct2Test + %9 = OpTypeFunction %void + %float_0 = OpConstant %float 0 + %value4 = OpConstantNull %EmptyStruct2Test + + %GetValue = OpFunction %float None %5 + %self = OpFunctionParameter %_ptr_Function_EmptyStruct2Test + %13 = OpLabel + OpReturnValue %float_0 + OpFunctionEnd + + %GetValue2 = OpFunction %float None %6 + %self2 = OpFunctionParameter %EmptyStruct2Test + %14 = OpLabel + OpReturnValue %float_0 + OpFunctionEnd + +%EntryPoint_Main = OpFunction %void None %9 + %37 = OpLabel + %emptyStruct = OpVariable %_ptr_Function_EmptyStruct2Test Function + %18 = OpVariable %_ptr_Function_EmptyStruct2Test Function + %value = OpVariable %_ptr_Function_float Function + %value2 = OpCompositeConstruct %EmptyStructTest + %value3 = OpCompositeConstruct %EmptyStruct2Test %value2 + %22 = OpFunctionCall %float %GetValue %emptyStruct + %23 = OpFunctionCall %float %GetValue2 %value3 + %24 = OpFunctionCall %float %GetValue2 %value4 + OpStore %value %22 + OpStore %value %23 + OpStore %value %24 + OpReturn + OpFunctionEnd diff --git a/third_party/spirv-cross/shaders-hlsl-no-opt/asm/frag/pixel-interlock-callstack.sm51.fxconly.asm.frag b/third_party/spirv-cross/shaders-hlsl-no-opt/asm/frag/pixel-interlock-callstack.sm51.fxconly.asm.frag new file mode 100644 index 0000000000..ebd8d6bab7 --- /dev/null +++ b/third_party/spirv-cross/shaders-hlsl-no-opt/asm/frag/pixel-interlock-callstack.sm51.fxconly.asm.frag @@ -0,0 +1,89 @@ +; SPIR-V +; Version: 1.0 +; Generator: Khronos Glslang Reference Front End; 7 +; Bound: 45 +; Schema: 0 + OpCapability Shader + OpCapability FragmentShaderPixelInterlockEXT + OpExtension "SPV_EXT_fragment_shader_interlock" + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %gl_FragCoord + OpExecutionMode %main OriginUpperLeft + OpExecutionMode %main PixelInterlockOrderedEXT + OpSource GLSL 450 + OpSourceExtension "GL_ARB_fragment_shader_interlock" + OpName %main "main" + OpName %callee2_ "callee2(" + OpName %callee_ "callee(" + OpName %SSBO1 "SSBO1" + OpMemberName %SSBO1 0 "values1" + OpName %_ "" + OpName %gl_FragCoord "gl_FragCoord" + OpName %SSBO0 "SSBO0" + OpMemberName %SSBO0 0 "values0" + OpName %__0 "" + OpDecorate %_runtimearr_uint ArrayStride 4 + OpMemberDecorate %SSBO1 0 Offset 0 + OpDecorate %SSBO1 BufferBlock + OpDecorate %_ DescriptorSet 0 + OpDecorate %_ Binding 1 + OpDecorate %gl_FragCoord BuiltIn FragCoord + OpDecorate %_runtimearr_uint_0 ArrayStride 4 + OpMemberDecorate %SSBO0 0 Offset 0 + OpDecorate %SSBO0 BufferBlock + OpDecorate %__0 DescriptorSet 0 + OpDecorate %__0 Binding 0 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %uint = OpTypeInt 32 0 +%_runtimearr_uint = OpTypeRuntimeArray %uint + %SSBO1 = OpTypeStruct %_runtimearr_uint +%_ptr_Uniform_SSBO1 = OpTypePointer Uniform %SSBO1 + %_ = OpVariable %_ptr_Uniform_SSBO1 Uniform + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 +%_ptr_Input_v4float = OpTypePointer Input %v4float +%gl_FragCoord = OpVariable %_ptr_Input_v4float Input + %uint_0 = OpConstant %uint 0 +%_ptr_Input_float = OpTypePointer Input %float + %uint_1 = OpConstant %uint 1 +%_ptr_Uniform_uint = OpTypePointer Uniform %uint +%_runtimearr_uint_0 = OpTypeRuntimeArray %uint + %SSBO0 = OpTypeStruct %_runtimearr_uint_0 +%_ptr_Uniform_SSBO0 = OpTypePointer Uniform %SSBO0 + %__0 = OpVariable %_ptr_Uniform_SSBO0 Uniform + %main = OpFunction %void None %3 + %5 = OpLabel + %44 = OpFunctionCall %void %callee_ + OpReturn + OpFunctionEnd + %callee2_ = OpFunction %void None %3 + %7 = OpLabel + %23 = OpAccessChain %_ptr_Input_float %gl_FragCoord %uint_0 + %24 = OpLoad %float %23 + %25 = OpConvertFToS %int %24 + %28 = OpAccessChain %_ptr_Uniform_uint %_ %int_0 %25 + %29 = OpLoad %uint %28 + %30 = OpIAdd %uint %29 %uint_1 + %31 = OpAccessChain %_ptr_Uniform_uint %_ %int_0 %25 + OpStore %31 %30 + OpReturn + OpFunctionEnd + %callee_ = OpFunction %void None %3 + %9 = OpLabel + %36 = OpAccessChain %_ptr_Input_float %gl_FragCoord %uint_0 + %37 = OpLoad %float %36 + %38 = OpConvertFToS %int %37 + %39 = OpAccessChain %_ptr_Uniform_uint %__0 %int_0 %38 + %40 = OpLoad %uint %39 + %41 = OpIAdd %uint %40 %uint_1 + %42 = OpAccessChain %_ptr_Uniform_uint %__0 %int_0 %38 + OpStore %42 %41 + OpBeginInvocationInterlockEXT + %43 = OpFunctionCall %void %callee2_ + OpEndInvocationInterlockEXT + OpReturn + OpFunctionEnd diff --git a/third_party/spirv-cross/shaders-hlsl-no-opt/asm/frag/pixel-interlock-control-flow.sm51.fxconly.asm.frag b/third_party/spirv-cross/shaders-hlsl-no-opt/asm/frag/pixel-interlock-control-flow.sm51.fxconly.asm.frag new file mode 100644 index 0000000000..69b8f91120 --- /dev/null +++ b/third_party/spirv-cross/shaders-hlsl-no-opt/asm/frag/pixel-interlock-control-flow.sm51.fxconly.asm.frag @@ -0,0 +1,121 @@ +; SPIR-V +; Version: 1.0 +; Generator: Khronos Glslang Reference Front End; 7 +; Bound: 45 +; Schema: 0 + OpCapability Shader + OpCapability FragmentShaderPixelInterlockEXT + OpExtension "SPV_EXT_fragment_shader_interlock" + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %gl_FragCoord + OpExecutionMode %main OriginUpperLeft + OpExecutionMode %main PixelInterlockOrderedEXT + OpSource GLSL 450 + OpSourceExtension "GL_ARB_fragment_shader_interlock" + OpName %main "main" + OpName %callee2_ "callee2(" + OpName %callee_ "callee(" + OpName %SSBO1 "SSBO1" + OpMemberName %SSBO1 0 "values1" + OpName %_ "" + OpName %gl_FragCoord "gl_FragCoord" + OpName %SSBO0 "SSBO0" + OpMemberName %SSBO0 0 "values0" + OpName %__0 "" + OpDecorate %_runtimearr_uint ArrayStride 4 + OpMemberDecorate %SSBO1 0 Offset 0 + OpDecorate %SSBO1 BufferBlock + OpDecorate %_ DescriptorSet 0 + OpDecorate %_ Binding 1 + OpDecorate %gl_FragCoord BuiltIn FragCoord + OpDecorate %_runtimearr_uint_0 ArrayStride 4 + OpMemberDecorate %SSBO0 0 Offset 0 + OpDecorate %SSBO0 BufferBlock + OpDecorate %__0 DescriptorSet 0 + OpDecorate %__0 Binding 0 + + OpMemberDecorate %SSBO2 0 Offset 0 + OpDecorate %SSBO2 BufferBlock + OpDecorate %ssbo2 DescriptorSet 0 + OpDecorate %ssbo2 Binding 2 + + %void = OpTypeVoid + %3 = OpTypeFunction %void + %uint = OpTypeInt 32 0 +%_runtimearr_uint = OpTypeRuntimeArray %uint + %SSBO1 = OpTypeStruct %_runtimearr_uint + %SSBO2 = OpTypeStruct %_runtimearr_uint +%_ptr_Uniform_SSBO1 = OpTypePointer Uniform %SSBO1 +%_ptr_Uniform_SSBO2 = OpTypePointer Uniform %SSBO2 + %_ = OpVariable %_ptr_Uniform_SSBO1 Uniform + %ssbo2 = OpVariable %_ptr_Uniform_SSBO2 Uniform + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 + %uint_4 = OpConstant %uint 4 + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 + %bool = OpTypeBool + %true = OpConstantTrue %bool +%_ptr_Input_v4float = OpTypePointer Input %v4float +%gl_FragCoord = OpVariable %_ptr_Input_v4float Input + %uint_0 = OpConstant %uint 0 +%_ptr_Input_float = OpTypePointer Input %float + %uint_1 = OpConstant %uint 1 +%_ptr_Uniform_uint = OpTypePointer Uniform %uint +%_runtimearr_uint_0 = OpTypeRuntimeArray %uint + %SSBO0 = OpTypeStruct %_runtimearr_uint_0 +%_ptr_Uniform_SSBO0 = OpTypePointer Uniform %SSBO0 + %__0 = OpVariable %_ptr_Uniform_SSBO0 Uniform + %main = OpFunction %void None %3 + %5 = OpLabel + %44 = OpFunctionCall %void %callee_ + %callee3_res = OpFunctionCall %void %callee3_ + OpReturn + OpFunctionEnd + + %callee3_ = OpFunction %void None %3 + %calle3_block = OpLabel + %frag_coord_x_ptr = OpAccessChain %_ptr_Input_float %gl_FragCoord %uint_0 + %frag_coord_x = OpLoad %float %frag_coord_x_ptr + %frag_coord_int = OpConvertFToS %int %frag_coord_x + %ssbo_ptr = OpAccessChain %_ptr_Uniform_uint %ssbo2 %int_0 %frag_coord_int + OpStore %ssbo_ptr %uint_4 + OpReturn + OpFunctionEnd + + %callee2_ = OpFunction %void None %3 + %7 = OpLabel + %23 = OpAccessChain %_ptr_Input_float %gl_FragCoord %uint_0 + %24 = OpLoad %float %23 + %25 = OpConvertFToS %int %24 + %28 = OpAccessChain %_ptr_Uniform_uint %_ %int_0 %25 + %29 = OpLoad %uint %28 + %30 = OpIAdd %uint %29 %uint_1 + %31 = OpAccessChain %_ptr_Uniform_uint %_ %int_0 %25 + OpStore %31 %30 + OpReturn + OpFunctionEnd + %callee_ = OpFunction %void None %3 + %9 = OpLabel + %36 = OpAccessChain %_ptr_Input_float %gl_FragCoord %uint_0 + %37 = OpLoad %float %36 + %38 = OpConvertFToS %int %37 + %39 = OpAccessChain %_ptr_Uniform_uint %__0 %int_0 %38 + %40 = OpLoad %uint %39 + %41 = OpIAdd %uint %40 %uint_1 + %42 = OpAccessChain %_ptr_Uniform_uint %__0 %int_0 %38 + OpStore %42 %41 + %43 = OpFunctionCall %void %callee2_ + + OpSelectionMerge %merged_block None + OpBranchConditional %true %dummy_block %merged_block + %dummy_block = OpLabel + OpBeginInvocationInterlockEXT + OpEndInvocationInterlockEXT + OpBranch %merged_block + + %merged_block = OpLabel + OpReturn + + OpFunctionEnd diff --git a/third_party/spirv-cross/shaders-hlsl-no-opt/asm/frag/pixel-interlock-split-functions.sm51.fxconly.asm.frag b/third_party/spirv-cross/shaders-hlsl-no-opt/asm/frag/pixel-interlock-split-functions.sm51.fxconly.asm.frag new file mode 100644 index 0000000000..7c0fe9a2b2 --- /dev/null +++ b/third_party/spirv-cross/shaders-hlsl-no-opt/asm/frag/pixel-interlock-split-functions.sm51.fxconly.asm.frag @@ -0,0 +1,102 @@ +; SPIR-V +; Version: 1.0 +; Generator: Khronos Glslang Reference Front End; 7 +; Bound: 45 +; Schema: 0 + OpCapability Shader + OpCapability FragmentShaderPixelInterlockEXT + OpExtension "SPV_EXT_fragment_shader_interlock" + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %gl_FragCoord + OpExecutionMode %main OriginUpperLeft + OpExecutionMode %main PixelInterlockOrderedEXT + OpSource GLSL 450 + OpSourceExtension "GL_ARB_fragment_shader_interlock" + OpName %main "main" + OpName %callee2_ "callee2(" + OpName %callee_ "callee(" + OpName %SSBO1 "SSBO1" + OpMemberName %SSBO1 0 "values1" + OpName %_ "" + OpName %gl_FragCoord "gl_FragCoord" + OpName %SSBO0 "SSBO0" + OpMemberName %SSBO0 0 "values0" + OpName %__0 "" + OpDecorate %_runtimearr_uint ArrayStride 4 + OpMemberDecorate %SSBO1 0 Offset 0 + OpDecorate %SSBO1 BufferBlock + OpDecorate %_ DescriptorSet 0 + OpDecorate %_ Binding 1 + OpDecorate %gl_FragCoord BuiltIn FragCoord + OpDecorate %_runtimearr_uint_0 ArrayStride 4 + OpMemberDecorate %SSBO0 0 Offset 0 + OpDecorate %SSBO0 BufferBlock + OpDecorate %__0 DescriptorSet 0 + OpDecorate %__0 Binding 0 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %uint = OpTypeInt 32 0 +%_runtimearr_uint = OpTypeRuntimeArray %uint + %SSBO1 = OpTypeStruct %_runtimearr_uint +%_ptr_Uniform_SSBO1 = OpTypePointer Uniform %SSBO1 + %_ = OpVariable %_ptr_Uniform_SSBO1 Uniform + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 +%_ptr_Input_v4float = OpTypePointer Input %v4float +%gl_FragCoord = OpVariable %_ptr_Input_v4float Input + %uint_0 = OpConstant %uint 0 +%_ptr_Input_float = OpTypePointer Input %float + %uint_1 = OpConstant %uint 1 +%_ptr_Uniform_uint = OpTypePointer Uniform %uint +%_runtimearr_uint_0 = OpTypeRuntimeArray %uint + %SSBO0 = OpTypeStruct %_runtimearr_uint_0 +%_ptr_Uniform_SSBO0 = OpTypePointer Uniform %SSBO0 + %__0 = OpVariable %_ptr_Uniform_SSBO0 Uniform + %main = OpFunction %void None %3 + %5 = OpLabel + %44 = OpFunctionCall %void %callee_ + %call3res = OpFunctionCall %void %callee3_ + %call4res = OpFunctionCall %void %callee4_ + OpReturn + OpFunctionEnd + + %callee3_ = OpFunction %void None %3 + %begin3 = OpLabel + OpBeginInvocationInterlockEXT + OpReturn + OpFunctionEnd + + %callee4_ = OpFunction %void None %3 + %begin4 = OpLabel + OpEndInvocationInterlockEXT + OpReturn + OpFunctionEnd + + %callee2_ = OpFunction %void None %3 + %7 = OpLabel + %23 = OpAccessChain %_ptr_Input_float %gl_FragCoord %uint_0 + %24 = OpLoad %float %23 + %25 = OpConvertFToS %int %24 + %28 = OpAccessChain %_ptr_Uniform_uint %_ %int_0 %25 + %29 = OpLoad %uint %28 + %30 = OpIAdd %uint %29 %uint_1 + %31 = OpAccessChain %_ptr_Uniform_uint %_ %int_0 %25 + OpStore %31 %30 + OpReturn + OpFunctionEnd + %callee_ = OpFunction %void None %3 + %9 = OpLabel + %36 = OpAccessChain %_ptr_Input_float %gl_FragCoord %uint_0 + %37 = OpLoad %float %36 + %38 = OpConvertFToS %int %37 + %39 = OpAccessChain %_ptr_Uniform_uint %__0 %int_0 %38 + %40 = OpLoad %uint %39 + %41 = OpIAdd %uint %40 %uint_1 + %42 = OpAccessChain %_ptr_Uniform_uint %__0 %int_0 %38 + OpStore %42 %41 + %43 = OpFunctionCall %void %callee2_ + OpReturn + OpFunctionEnd diff --git a/third_party/spirv-cross/shaders-hlsl-no-opt/asm/frag/subgroup-arithmetic-cast.invalid.nofxc.sm60.asm.frag b/third_party/spirv-cross/shaders-hlsl-no-opt/asm/frag/subgroup-arithmetic-cast.invalid.nofxc.sm60.asm.frag new file mode 100644 index 0000000000..a9b34893c8 --- /dev/null +++ b/third_party/spirv-cross/shaders-hlsl-no-opt/asm/frag/subgroup-arithmetic-cast.invalid.nofxc.sm60.asm.frag @@ -0,0 +1,65 @@ +; SPIR-V +; Version: 1.3 +; Generator: Khronos Glslang Reference Front End; 8 +; Bound: 78 +; Schema: 0 + OpCapability Shader + OpCapability GroupNonUniform + OpCapability GroupNonUniformArithmetic + OpCapability GroupNonUniformClustered + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %index %FragColor + OpExecutionMode %main OriginUpperLeft + OpSource GLSL 450 + OpSourceExtension "GL_KHR_shader_subgroup_arithmetic" + OpSourceExtension "GL_KHR_shader_subgroup_basic" + OpSourceExtension "GL_KHR_shader_subgroup_clustered" + OpName %main "main" + OpName %index "index" + OpName %FragColor "FragColor" + OpDecorate %index Flat + OpDecorate %index Location 0 + OpDecorate %FragColor Location 0 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %uint = OpTypeInt 32 0 +%_ptr_Function_uint = OpTypePointer Function %uint + %uint_0 = OpConstant %uint 0 + %int = OpTypeInt 32 1 +%_ptr_Input_int = OpTypePointer Input %int + %index = OpVariable %_ptr_Input_int Input + %uint_3 = OpConstant %uint 3 + %uint_4 = OpConstant %uint 4 +%_ptr_Output_uint = OpTypePointer Output %uint + %FragColor = OpVariable %_ptr_Output_uint Output + %main = OpFunction %void None %3 + %5 = OpLabel + %i = OpLoad %int %index + %u = OpBitcast %uint %i + %res0 = OpGroupNonUniformSMin %uint %uint_3 Reduce %i + %res1 = OpGroupNonUniformSMax %uint %uint_3 Reduce %u + %res2 = OpGroupNonUniformUMin %uint %uint_3 Reduce %i + %res3 = OpGroupNonUniformUMax %uint %uint_3 Reduce %u + ;%res4 = OpGroupNonUniformSMax %uint %uint_3 InclusiveScan %i + ;%res5 = OpGroupNonUniformSMin %uint %uint_3 InclusiveScan %u + ;%res6 = OpGroupNonUniformUMax %uint %uint_3 ExclusiveScan %i + ;%res7 = OpGroupNonUniformUMin %uint %uint_3 ExclusiveScan %u + ;%res8 = OpGroupNonUniformSMin %uint %uint_3 ClusteredReduce %i %uint_4 + ;%res9 = OpGroupNonUniformSMax %uint %uint_3 ClusteredReduce %u %uint_4 + ;%res10 = OpGroupNonUniformUMin %uint %uint_3 ClusteredReduce %i %uint_4 + ;%res11 = OpGroupNonUniformUMax %uint %uint_3 ClusteredReduce %u %uint_4 + OpStore %FragColor %res0 + OpStore %FragColor %res1 + OpStore %FragColor %res2 + OpStore %FragColor %res3 + ;OpStore %FragColor %res4 + ;OpStore %FragColor %res5 + ;OpStore %FragColor %res6 + ;OpStore %FragColor %res7 + ;OpStore %FragColor %res8 + ;OpStore %FragColor %res9 + ;OpStore %FragColor %res10 + ;OpStore %FragColor %res11 + OpReturn + OpFunctionEnd diff --git a/third_party/spirv-cross/shaders-hlsl-no-opt/asm/frag/switch-block-case-fallthrough.asm.frag b/third_party/spirv-cross/shaders-hlsl-no-opt/asm/frag/switch-block-case-fallthrough.asm.invalid.frag similarity index 100% rename from third_party/spirv-cross/shaders-hlsl-no-opt/asm/frag/switch-block-case-fallthrough.asm.frag rename to third_party/spirv-cross/shaders-hlsl-no-opt/asm/frag/switch-block-case-fallthrough.asm.invalid.frag diff --git a/third_party/spirv-cross/shaders-hlsl-no-opt/asm/frag/unordered-compare.asm.frag b/third_party/spirv-cross/shaders-hlsl-no-opt/asm/frag/unordered-compare.asm.frag new file mode 100644 index 0000000000..4ad8fc5abb --- /dev/null +++ b/third_party/spirv-cross/shaders-hlsl-no-opt/asm/frag/unordered-compare.asm.frag @@ -0,0 +1,177 @@ +; SPIR-V +; Version: 1.0 +; Generator: Khronos Glslang Reference Front End; 7 +; Bound: 132 +; Schema: 0 + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %A %B %FragColor + OpExecutionMode %main OriginUpperLeft + OpSource GLSL 450 + OpName %main "main" + OpName %test_vector_ "test_vector(" + OpName %test_scalar_ "test_scalar(" + OpName %le "le" + OpName %A "A" + OpName %B "B" + OpName %leq "leq" + OpName %ge "ge" + OpName %geq "geq" + OpName %eq "eq" + OpName %neq "neq" + OpName %le_0 "le" + OpName %leq_0 "leq" + OpName %ge_0 "ge" + OpName %geq_0 "geq" + OpName %eq_0 "eq" + OpName %neq_0 "neq" + OpName %FragColor "FragColor" + OpDecorate %A Location 0 + OpDecorate %B Location 1 + OpDecorate %FragColor Location 0 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 + %8 = OpTypeFunction %v4float + %11 = OpTypeFunction %float + %bool = OpTypeBool + %v4bool = OpTypeVector %bool 4 +%_ptr_Function_v4bool = OpTypePointer Function %v4bool +%_ptr_Input_v4float = OpTypePointer Input %v4float + %A = OpVariable %_ptr_Input_v4float Input + %B = OpVariable %_ptr_Input_v4float Input + %float_0 = OpConstant %float 0 + %float_1 = OpConstant %float 1 + %47 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0 + %48 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1 +%_ptr_Function_bool = OpTypePointer Function %bool + %uint = OpTypeInt 32 0 + %uint_0 = OpConstant %uint 0 +%_ptr_Input_float = OpTypePointer Input %float +%_ptr_Output_v4float = OpTypePointer Output %v4float + %FragColor = OpVariable %_ptr_Output_v4float Output + %main = OpFunction %void None %3 + %5 = OpLabel + %128 = OpFunctionCall %v4float %test_vector_ + %129 = OpFunctionCall %float %test_scalar_ + %130 = OpCompositeConstruct %v4float %129 %129 %129 %129 + %131 = OpFAdd %v4float %128 %130 + OpStore %FragColor %131 + OpReturn + OpFunctionEnd +%test_vector_ = OpFunction %v4float None %8 + %10 = OpLabel + %le = OpVariable %_ptr_Function_v4bool Function + %leq = OpVariable %_ptr_Function_v4bool Function + %ge = OpVariable %_ptr_Function_v4bool Function + %geq = OpVariable %_ptr_Function_v4bool Function + %eq = OpVariable %_ptr_Function_v4bool Function + %neq = OpVariable %_ptr_Function_v4bool Function + %20 = OpLoad %v4float %A + %22 = OpLoad %v4float %B + %23 = OpFUnordLessThan %v4bool %20 %22 + OpStore %le %23 + %25 = OpLoad %v4float %A + %26 = OpLoad %v4float %B + %27 = OpFUnordLessThanEqual %v4bool %25 %26 + OpStore %leq %27 + %29 = OpLoad %v4float %A + %30 = OpLoad %v4float %B + %31 = OpFUnordGreaterThan %v4bool %29 %30 + OpStore %ge %31 + %33 = OpLoad %v4float %A + %34 = OpLoad %v4float %B + %35 = OpFUnordGreaterThanEqual %v4bool %33 %34 + OpStore %geq %35 + %37 = OpLoad %v4float %A + %38 = OpLoad %v4float %B + %39 = OpFUnordEqual %v4bool %37 %38 + OpStore %eq %39 + %41 = OpLoad %v4float %A + %42 = OpLoad %v4float %B + %43 = OpFUnordNotEqual %v4bool %41 %42 + OpStore %neq %43 + %44 = OpLoad %v4bool %le + %49 = OpSelect %v4float %44 %48 %47 + %50 = OpLoad %v4bool %leq + %51 = OpSelect %v4float %50 %48 %47 + %52 = OpFAdd %v4float %49 %51 + %53 = OpLoad %v4bool %ge + %54 = OpSelect %v4float %53 %48 %47 + %55 = OpFAdd %v4float %52 %54 + %56 = OpLoad %v4bool %geq + %57 = OpSelect %v4float %56 %48 %47 + %58 = OpFAdd %v4float %55 %57 + %59 = OpLoad %v4bool %eq + %60 = OpSelect %v4float %59 %48 %47 + %61 = OpFAdd %v4float %58 %60 + %62 = OpLoad %v4bool %neq + %63 = OpSelect %v4float %62 %48 %47 + %64 = OpFAdd %v4float %61 %63 + OpReturnValue %64 + OpFunctionEnd +%test_scalar_ = OpFunction %float None %11 + %13 = OpLabel + %le_0 = OpVariable %_ptr_Function_bool Function + %leq_0 = OpVariable %_ptr_Function_bool Function + %ge_0 = OpVariable %_ptr_Function_bool Function + %geq_0 = OpVariable %_ptr_Function_bool Function + %eq_0 = OpVariable %_ptr_Function_bool Function + %neq_0 = OpVariable %_ptr_Function_bool Function + %72 = OpAccessChain %_ptr_Input_float %A %uint_0 + %73 = OpLoad %float %72 + %74 = OpAccessChain %_ptr_Input_float %B %uint_0 + %75 = OpLoad %float %74 + %76 = OpFUnordLessThan %bool %73 %75 + OpStore %le_0 %76 + %78 = OpAccessChain %_ptr_Input_float %A %uint_0 + %79 = OpLoad %float %78 + %80 = OpAccessChain %_ptr_Input_float %B %uint_0 + %81 = OpLoad %float %80 + %82 = OpFUnordLessThanEqual %bool %79 %81 + OpStore %leq_0 %82 + %84 = OpAccessChain %_ptr_Input_float %A %uint_0 + %85 = OpLoad %float %84 + %86 = OpAccessChain %_ptr_Input_float %B %uint_0 + %87 = OpLoad %float %86 + %88 = OpFUnordGreaterThan %bool %85 %87 + OpStore %ge_0 %88 + %90 = OpAccessChain %_ptr_Input_float %A %uint_0 + %91 = OpLoad %float %90 + %92 = OpAccessChain %_ptr_Input_float %B %uint_0 + %93 = OpLoad %float %92 + %94 = OpFUnordGreaterThanEqual %bool %91 %93 + OpStore %geq_0 %94 + %96 = OpAccessChain %_ptr_Input_float %A %uint_0 + %97 = OpLoad %float %96 + %98 = OpAccessChain %_ptr_Input_float %B %uint_0 + %99 = OpLoad %float %98 + %100 = OpFUnordEqual %bool %97 %99 + OpStore %eq_0 %100 + %102 = OpAccessChain %_ptr_Input_float %A %uint_0 + %103 = OpLoad %float %102 + %104 = OpAccessChain %_ptr_Input_float %B %uint_0 + %105 = OpLoad %float %104 + %106 = OpFUnordNotEqual %bool %103 %105 + OpStore %neq_0 %106 + %107 = OpLoad %bool %le_0 + %108 = OpSelect %float %107 %float_1 %float_0 + %109 = OpLoad %bool %leq_0 + %110 = OpSelect %float %109 %float_1 %float_0 + %111 = OpFAdd %float %108 %110 + %112 = OpLoad %bool %ge_0 + %113 = OpSelect %float %112 %float_1 %float_0 + %114 = OpFAdd %float %111 %113 + %115 = OpLoad %bool %geq_0 + %116 = OpSelect %float %115 %float_1 %float_0 + %117 = OpFAdd %float %114 %116 + %118 = OpLoad %bool %eq_0 + %119 = OpSelect %float %118 %float_1 %float_0 + %120 = OpFAdd %float %117 %119 + %121 = OpLoad %bool %neq_0 + %122 = OpSelect %float %121 %float_1 %float_0 + %123 = OpFAdd %float %120 %122 + OpReturnValue %123 + OpFunctionEnd diff --git a/third_party/spirv-cross/shaders-hlsl-no-opt/comp/illegal-struct-name.asm.comp b/third_party/spirv-cross/shaders-hlsl-no-opt/comp/illegal-struct-name.asm.comp new file mode 100644 index 0000000000..f7a8787d3d --- /dev/null +++ b/third_party/spirv-cross/shaders-hlsl-no-opt/comp/illegal-struct-name.asm.comp @@ -0,0 +1,62 @@ +; SPIR-V +; Version: 1.0 +; Generator: Khronos Glslang Reference Front End; 8 +; Bound: 31 +; Schema: 0 + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" + OpExecutionMode %main LocalSize 1 1 1 + OpSource GLSL 450 + OpName %main "main" + OpName %Foo "Foo" + OpMemberName %Foo 0 "abs" + OpName %f "f" + OpName %Foo_0 "Foo" + OpMemberName %Foo_0 0 "abs" + OpName %SSBO "SSBO" + OpMemberName %SSBO 0 "foo" + OpMemberName %SSBO 1 "foo2" + OpName %_ "" + OpName %linear "abs" + OpMemberDecorate %Foo_0 0 Offset 0 + OpMemberDecorate %SSBO 0 Offset 0 + OpMemberDecorate %SSBO 1 Offset 4 + OpDecorate %SSBO BufferBlock + OpDecorate %_ DescriptorSet 0 + OpDecorate %_ Binding 0 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %Foo = OpTypeStruct %float +%_ptr_Function_Foo = OpTypePointer Function %Foo + %Foo_0 = OpTypeStruct %float + %SSBO = OpTypeStruct %Foo_0 %Foo_0 +%_ptr_Uniform_SSBO = OpTypePointer Uniform %SSBO + %_ = OpVariable %_ptr_Uniform_SSBO Uniform + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 +%_ptr_Uniform_Foo_0 = OpTypePointer Uniform %Foo_0 +%_ptr_Function_float = OpTypePointer Function %float +%_ptr_Function_int = OpTypePointer Function %int + %int_10 = OpConstant %int 10 + %int_1 = OpConstant %int 1 +%_ptr_Uniform_float = OpTypePointer Uniform %float + %main = OpFunction %void None %3 + %5 = OpLabel + %f = OpVariable %_ptr_Function_Foo Function + %linear = OpVariable %_ptr_Function_int Function + %17 = OpAccessChain %_ptr_Uniform_Foo_0 %_ %int_0 + %18 = OpLoad %Foo_0 %17 + %19 = OpCompositeExtract %float %18 0 + %21 = OpAccessChain %_ptr_Function_float %f %int_0 + OpStore %21 %19 + OpStore %linear %int_10 + %26 = OpLoad %Foo %f + %27 = OpAccessChain %_ptr_Uniform_Foo_0 %_ %int_1 + %28 = OpCompositeExtract %float %26 0 + %30 = OpAccessChain %_ptr_Uniform_float %27 %int_0 + OpStore %30 %28 + OpReturn + OpFunctionEnd diff --git a/third_party/spirv-cross/shaders-hlsl/comp/subgroups.invalid.nofxc.sm60.comp b/third_party/spirv-cross/shaders-hlsl-no-opt/comp/subgroups.invalid.nofxc.sm60.comp similarity index 100% rename from third_party/spirv-cross/shaders-hlsl/comp/subgroups.invalid.nofxc.sm60.comp rename to third_party/spirv-cross/shaders-hlsl-no-opt/comp/subgroups.invalid.nofxc.sm60.comp diff --git a/third_party/spirv-cross/shaders-hlsl/frag/constant-buffer-array.invalid.sm51.frag b/third_party/spirv-cross/shaders-hlsl-no-opt/frag/constant-buffer-array.invalid.sm51.frag similarity index 100% rename from third_party/spirv-cross/shaders-hlsl/frag/constant-buffer-array.invalid.sm51.frag rename to third_party/spirv-cross/shaders-hlsl-no-opt/frag/constant-buffer-array.invalid.sm51.frag diff --git a/third_party/spirv-cross/shaders-hlsl/frag/fp16.invalid.desktop.frag b/third_party/spirv-cross/shaders-hlsl-no-opt/frag/fp16.invalid.desktop.frag similarity index 100% rename from third_party/spirv-cross/shaders-hlsl/frag/fp16.invalid.desktop.frag rename to third_party/spirv-cross/shaders-hlsl-no-opt/frag/fp16.invalid.desktop.frag diff --git a/third_party/spirv-cross/shaders-hlsl-no-opt/frag/pixel-interlock-simple-callstack.sm51.fxconly.frag b/third_party/spirv-cross/shaders-hlsl-no-opt/frag/pixel-interlock-simple-callstack.sm51.fxconly.frag new file mode 100644 index 0000000000..59079fe58b --- /dev/null +++ b/third_party/spirv-cross/shaders-hlsl-no-opt/frag/pixel-interlock-simple-callstack.sm51.fxconly.frag @@ -0,0 +1,31 @@ +#version 450 +#extension GL_ARB_fragment_shader_interlock : require +layout(pixel_interlock_ordered) in; + +layout(set = 0, binding = 0, std430) buffer SSBO0 +{ + uint values0[]; +}; + +layout(set = 0, binding = 1, std430) buffer SSBO1 +{ + uint values1[]; +}; + +void callee2() +{ + values1[int(gl_FragCoord.x)] += 1; +} + +void callee() +{ + values0[int(gl_FragCoord.x)] += 1; + callee2(); +} + +void main() +{ + beginInvocationInterlockARB(); + callee(); + endInvocationInterlockARB(); +} diff --git a/third_party/spirv-cross/shaders-hlsl/asm/comp/bitcast_icmp.asm.comp b/third_party/spirv-cross/shaders-hlsl/asm/comp/bitcast_icmp.asm.comp new file mode 100644 index 0000000000..b7b4e0b2e1 --- /dev/null +++ b/third_party/spirv-cross/shaders-hlsl/asm/comp/bitcast_icmp.asm.comp @@ -0,0 +1,101 @@ +; SPIR-V +; Version: 1.0 +; Generator: Khronos Glslang Reference Front End; 1 +; Bound: 30 +; Schema: 0 + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %func "main" + OpExecutionMode %func LocalSize 1 1 1 + OpSource ESSL 310 + OpSourceExtension "GL_GOOGLE_cpp_style_line_directive" + OpSourceExtension "GL_GOOGLE_include_directive" + OpMemberDecorate %input_struct 0 Offset 0 + OpMemberDecorate %input_struct 1 Offset 16 + OpMemberDecorate %output_struct 0 Offset 0 + OpMemberDecorate %output_struct 1 Offset 16 + OpDecorate %input_struct BufferBlock + OpDecorate %inputs DescriptorSet 0 + OpDecorate %inputs Binding 0 + OpDecorate %inputs Restrict + OpDecorate %output_struct BufferBlock + OpDecorate %outputs DescriptorSet 0 + OpDecorate %outputs Binding 1 + OpDecorate %outputs Restrict + + %void = OpTypeVoid + %main_func = OpTypeFunction %void + + %bool = OpTypeBool + %bvec4 = OpTypeVector %bool 4 + + %uint = OpTypeInt 32 0 + %uvec4 = OpTypeVector %uint 4 + + %int = OpTypeInt 32 1 + %ivec4 = OpTypeVector %int 4 + + %ivec4_ptr = OpTypePointer Uniform %ivec4 + %uvec4_ptr = OpTypePointer Uniform %uvec4 + + %zero = OpConstant %int 0 + %one = OpConstant %int 1 + %uzero = OpConstant %uint 0 + %uone = OpConstant %uint 1 + %utrue = OpConstantComposite %uvec4 %uone %uone %uone %uone + %ufalse = OpConstantComposite %uvec4 %uzero %uzero %uzero %uzero + + %input_struct = OpTypeStruct %ivec4 %uvec4 + %input_struct_ptr = OpTypePointer Uniform %input_struct + %inputs = OpVariable %input_struct_ptr Uniform + %output_struct = OpTypeStruct %uvec4 %ivec4 + %output_struct_ptr = OpTypePointer Uniform %output_struct + %outputs = OpVariable %output_struct_ptr Uniform + + %func = OpFunction %void None %main_func + %block = OpLabel + + %input1_ptr = OpAccessChain %ivec4_ptr %inputs %zero + %input0_ptr = OpAccessChain %uvec4_ptr %inputs %one + %input1 = OpLoad %ivec4 %input1_ptr + %input0 = OpLoad %uvec4 %input0_ptr + + %output_ptr_uvec4 = OpAccessChain %uvec4_ptr %outputs %zero + + %result_slt = OpSLessThan %bvec4 %input0 %input1 + %result_sle = OpSLessThanEqual %bvec4 %input0 %input1 + %result_ult = OpULessThan %bvec4 %input0 %input1 + %result_ule = OpULessThanEqual %bvec4 %input0 %input1 + %result_sgt = OpSGreaterThan %bvec4 %input0 %input1 + %result_sge = OpSGreaterThanEqual %bvec4 %input0 %input1 + %result_ugt = OpUGreaterThan %bvec4 %input0 %input1 + %result_uge = OpUGreaterThanEqual %bvec4 %input0 %input1 + + %int_slt = OpSelect %uvec4 %result_slt %utrue %ufalse + OpStore %output_ptr_uvec4 %int_slt + + %int_sle = OpSelect %uvec4 %result_sle %utrue %ufalse + OpStore %output_ptr_uvec4 %int_sle + + %int_ult = OpSelect %uvec4 %result_ult %utrue %ufalse + OpStore %output_ptr_uvec4 %int_ult + + %int_ule = OpSelect %uvec4 %result_ule %utrue %ufalse + OpStore %output_ptr_uvec4 %int_ule + + %int_sgt = OpSelect %uvec4 %result_sgt %utrue %ufalse + OpStore %output_ptr_uvec4 %int_sgt + + %int_sge = OpSelect %uvec4 %result_sge %utrue %ufalse + OpStore %output_ptr_uvec4 %int_sge + + %int_ugt = OpSelect %uvec4 %result_ugt %utrue %ufalse + OpStore %output_ptr_uvec4 %int_ugt + + %int_uge = OpSelect %uvec4 %result_uge %utrue %ufalse + OpStore %output_ptr_uvec4 %int_uge + + + OpReturn + OpFunctionEnd diff --git a/third_party/spirv-cross/shaders-hlsl/comp/access-chain-load-composite.comp b/third_party/spirv-cross/shaders-hlsl/comp/access-chain-load-composite.comp new file mode 100644 index 0000000000..69cc7a13be --- /dev/null +++ b/third_party/spirv-cross/shaders-hlsl/comp/access-chain-load-composite.comp @@ -0,0 +1,35 @@ +#version 450 +layout(local_size_x = 1) in; + +struct Baz +{ + float c; +}; + +struct Bar +{ + float d[2][4]; + Baz baz[2]; +}; + +struct Foo +{ + mat2 a; + vec2 b; + Bar c[5]; +}; + +layout(row_major, std430, set = 0, binding = 0) buffer SSBO +{ + Foo foo; + Foo foo2; +}; + +void main() +{ + Foo f = foo; + f.a += 1.0; + f.b += 2.0; + f.c[3].d[1][1] += 5.0; + foo2 = f; +} diff --git a/third_party/spirv-cross/shaders-hlsl/comp/access-chains.force-uav.comp b/third_party/spirv-cross/shaders-hlsl/comp/access-chains.force-uav.comp new file mode 100644 index 0000000000..639f3cac15 --- /dev/null +++ b/third_party/spirv-cross/shaders-hlsl/comp/access-chains.force-uav.comp @@ -0,0 +1,24 @@ +#version 310 es +layout(local_size_x = 1) in; + +// TODO: Read structs, matrices and arrays. + +layout(std430, binding = 0) readonly buffer SSBO +{ + vec4 a[3][2][4]; + float b[3][2][4]; + vec4 unsized[]; +} ro; + +layout(std430, binding = 1) writeonly buffer SSBO1 +{ + vec4 c[3][2][4]; + float d[3][2][4]; + vec4 unsized[]; +} wo; + +void main() +{ + wo.c[2][gl_GlobalInvocationID.x][1] = ro.a[1][gl_GlobalInvocationID.x][2]; + wo.unsized[gl_GlobalInvocationID.x] = ro.unsized[gl_GlobalInvocationID.x]; +} diff --git a/third_party/spirv-cross/shaders-hlsl/frag/pixel-interlock-ordered.sm51.fxconly.frag b/third_party/spirv-cross/shaders-hlsl/frag/pixel-interlock-ordered.sm51.fxconly.frag new file mode 100644 index 0000000000..ceac8cc50e --- /dev/null +++ b/third_party/spirv-cross/shaders-hlsl/frag/pixel-interlock-ordered.sm51.fxconly.frag @@ -0,0 +1,36 @@ +#version 450 +#extension GL_ARB_fragment_shader_interlock : require + +layout(pixel_interlock_ordered) in; + +layout(binding = 0, rgba8) uniform writeonly image2D img; +layout(binding = 1, r32ui) uniform uimage2D img2; +layout(binding = 2, rgba8) uniform readonly image2D img3; +layout(binding = 3) coherent buffer Buffer +{ + int foo; + uint bar; +}; +layout(binding = 4) buffer Buffer2 +{ + uint quux; +}; + +layout(binding = 5, rgba8) uniform writeonly image2D img4; +layout(binding = 6) buffer Buffer3 +{ + int baz; +}; + +void main() +{ + // Deliberately outside the critical section to test usage tracking. + baz = 0; + imageStore(img4, ivec2(1, 1), vec4(1.0, 0.0, 0.0, 1.0)); + beginInvocationInterlockARB(); + imageStore(img, ivec2(0, 0), imageLoad(img3, ivec2(0, 0))); + imageAtomicAdd(img2, ivec2(0, 0), 1u); + foo += 42; + atomicAnd(bar, quux); + endInvocationInterlockARB(); +} diff --git a/third_party/spirv-cross/shaders-hlsl/frag/readonly-coherent-ssbo.force-uav.frag b/third_party/spirv-cross/shaders-hlsl/frag/readonly-coherent-ssbo.force-uav.frag new file mode 100644 index 0000000000..cd035467be --- /dev/null +++ b/third_party/spirv-cross/shaders-hlsl/frag/readonly-coherent-ssbo.force-uav.frag @@ -0,0 +1,12 @@ +#version 450 + +layout(set = 0, binding = 0) coherent readonly buffer SSBO +{ + vec4 a; +}; +layout(location = 0) out vec4 FragColor; + +void main() +{ + FragColor = a; +} diff --git a/third_party/spirv-cross/shaders-hlsl/frag/readonly-coherent-ssbo.frag b/third_party/spirv-cross/shaders-hlsl/frag/readonly-coherent-ssbo.frag new file mode 100644 index 0000000000..cd035467be --- /dev/null +++ b/third_party/spirv-cross/shaders-hlsl/frag/readonly-coherent-ssbo.frag @@ -0,0 +1,12 @@ +#version 450 + +layout(set = 0, binding = 0) coherent readonly buffer SSBO +{ + vec4 a; +}; +layout(location = 0) out vec4 FragColor; + +void main() +{ + FragColor = a; +} diff --git a/third_party/spirv-cross/shaders-msl-no-opt/asm/comp/aliased-struct-divergent-member-name.asm.comp b/third_party/spirv-cross/shaders-msl-no-opt/asm/comp/aliased-struct-divergent-member-name.asm.comp new file mode 100644 index 0000000000..87aee2db54 --- /dev/null +++ b/third_party/spirv-cross/shaders-msl-no-opt/asm/comp/aliased-struct-divergent-member-name.asm.comp @@ -0,0 +1,77 @@ +; SPIR-V +; Version: 1.0 +; Generator: Khronos Glslang Reference Front End; 7 +; Bound: 37 +; Schema: 0 + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" + OpExecutionMode %main LocalSize 1 1 1 + OpSource GLSL 450 + OpName %main "main" + OpName %T "T" + OpMemberName %T 0 "a" + OpName %v "v" + OpName %T_0 "T" + OpMemberName %T_0 0 "b" + OpName %SSBO1 "SSBO1" + OpMemberName %SSBO1 0 "foo" + OpName %_ "" + OpName %T_1 "T" + OpMemberName %T_1 0 "c" + OpName %SSBO2 "SSBO2" + OpMemberName %SSBO2 0 "bar" + OpName %__0 "" + OpMemberDecorate %T_0 0 Offset 0 + OpDecorate %_runtimearr_T_0 ArrayStride 4 + OpMemberDecorate %SSBO1 0 Offset 0 + OpDecorate %SSBO1 BufferBlock + OpDecorate %_ DescriptorSet 0 + OpDecorate %_ Binding 0 + OpMemberDecorate %T_1 0 Offset 0 + OpDecorate %_runtimearr_T_1 ArrayStride 16 + OpMemberDecorate %SSBO2 0 Offset 0 + OpDecorate %SSBO2 BufferBlock + OpDecorate %__0 DescriptorSet 0 + OpDecorate %__0 Binding 1 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %T = OpTypeStruct %float +%_ptr_Function_T = OpTypePointer Function %T + %float_40 = OpConstant %float 40 + %11 = OpConstantComposite %T %float_40 + %T_0 = OpTypeStruct %float +%_runtimearr_T_0 = OpTypeRuntimeArray %T_0 + %SSBO1 = OpTypeStruct %_runtimearr_T_0 +%_ptr_Uniform_SSBO1 = OpTypePointer Uniform %SSBO1 + %_ = OpVariable %_ptr_Uniform_SSBO1 Uniform + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 + %int_10 = OpConstant %int 10 +%_ptr_Uniform_T_0 = OpTypePointer Uniform %T_0 +%_ptr_Uniform_float = OpTypePointer Uniform %float + %T_1 = OpTypeStruct %float +%_runtimearr_T_1 = OpTypeRuntimeArray %T_1 + %SSBO2 = OpTypeStruct %_runtimearr_T_1 +%_ptr_Uniform_SSBO2 = OpTypePointer Uniform %SSBO2 + %__0 = OpVariable %_ptr_Uniform_SSBO2 Uniform + %int_30 = OpConstant %int 30 +%_ptr_Uniform_T_1 = OpTypePointer Uniform %T_1 + %main = OpFunction %void None %3 + %5 = OpLabel + %v = OpVariable %_ptr_Function_T Function + OpStore %v %11 + %20 = OpLoad %T %v + %22 = OpAccessChain %_ptr_Uniform_T_0 %_ %int_0 %int_10 + %23 = OpCompositeExtract %float %20 0 + %25 = OpAccessChain %_ptr_Uniform_float %22 %int_0 + OpStore %25 %23 + %32 = OpLoad %T %v + %34 = OpAccessChain %_ptr_Uniform_T_1 %__0 %int_0 %int_30 + %35 = OpCompositeExtract %float %32 0 + %36 = OpAccessChain %_ptr_Uniform_float %34 %int_0 + OpStore %36 %35 + OpReturn + OpFunctionEnd diff --git a/third_party/spirv-cross/shaders-msl-no-opt/asm/comp/bitfield-signed-operations.asm.comp b/third_party/spirv-cross/shaders-msl-no-opt/asm/comp/bitfield-signed-operations.asm.comp new file mode 100644 index 0000000000..435fa32221 --- /dev/null +++ b/third_party/spirv-cross/shaders-msl-no-opt/asm/comp/bitfield-signed-operations.asm.comp @@ -0,0 +1,97 @@ +; SPIR-V +; Version: 1.0 +; Generator: Khronos Glslang Reference Front End; 7 +; Bound: 26 +; Schema: 0 + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" + OpExecutionMode %main LocalSize 1 1 1 + OpSource GLSL 450 + OpName %main "main" + OpName %SSBO "SSBO" + OpMemberName %SSBO 0 "ints" + OpMemberName %SSBO 1 "uints" + OpName %_ "" + OpMemberDecorate %SSBO 0 Offset 0 + OpMemberDecorate %SSBO 1 Offset 16 + OpDecorate %SSBO BufferBlock + OpDecorate %_ DescriptorSet 0 + OpDecorate %_ Binding 0 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %int = OpTypeInt 32 1 + %v4int = OpTypeVector %int 4 + %uint = OpTypeInt 32 0 + %v4uint = OpTypeVector %uint 4 + + %int_1 = OpConstant %int 1 + %uint_11 = OpConstant %uint 11 + + %SSBO = OpTypeStruct %v4int %v4uint +%_ptr_Uniform_SSBO = OpTypePointer Uniform %SSBO + %_ = OpVariable %_ptr_Uniform_SSBO Uniform + %int_0 = OpConstant %int 0 +%_ptr_Uniform_v4int = OpTypePointer Uniform %v4int +%_ptr_Uniform_v4uint = OpTypePointer Uniform %v4uint + %main = OpFunction %void None %3 + %5 = OpLabel + %ints_ptr = OpAccessChain %_ptr_Uniform_v4int %_ %int_0 + %uints_ptr = OpAccessChain %_ptr_Uniform_v4uint %_ %int_1 + %ints = OpLoad %v4int %ints_ptr + %uints = OpLoad %v4uint %uints_ptr + + %ints_alt = OpVectorShuffle %v4int %ints %ints 3 2 1 0 + %uints_alt = OpVectorShuffle %v4uint %uints %uints 3 2 1 0 + + %int_to_int_popcount = OpBitCount %v4int %ints + %int_to_uint_popcount = OpBitCount %v4uint %ints + %uint_to_int_popcount = OpBitCount %v4int %uints + %uint_to_uint_popcount = OpBitCount %v4uint %uints + + ; BitReverse must have matching types w.r.t. sign, yay. + %int_to_int_reverse = OpBitReverse %v4int %ints + ;%int_to_uint_reverse = OpBitReverse %v4uint %ints + ;%uint_to_int_reverse = OpBitReverse %v4int %uints + %uint_to_uint_reverse = OpBitReverse %v4uint %uints + + ; Base and Result must match. + %int_to_int_sbit = OpBitFieldSExtract %v4int %ints %int_1 %uint_11 + ;%int_to_uint_sbit = OpBitFieldSExtract %v4uint %ints %offset %count + ;%uint_to_int_sbit = OpBitFieldSExtract %v4int %uints %offset %count + %uint_to_uint_sbit = OpBitFieldSExtract %v4uint %uints %uint_11 %int_1 + + ; Base and Result must match. + %int_to_int_ubit = OpBitFieldUExtract %v4int %ints %int_1 %uint_11 + ;%int_to_uint_ubit = OpBitFieldUExtract %v4uint %ints %offset %count + ;%uint_to_int_ubit = OpBitFieldUExtract %v4int %uints %offset %count + %uint_to_uint_ubit = OpBitFieldUExtract %v4uint %uints %uint_11 %int_1 + + %int_to_int_insert = OpBitFieldInsert %v4int %ints %ints_alt %int_1 %uint_11 + %uint_to_uint_insert = OpBitFieldInsert %v4uint %uints %uints_alt %uint_11 %int_1 + + OpStore %ints_ptr %int_to_int_popcount + OpStore %uints_ptr %int_to_uint_popcount + OpStore %ints_ptr %uint_to_int_popcount + OpStore %uints_ptr %uint_to_uint_popcount + + OpStore %ints_ptr %int_to_int_reverse + ;OpStore %uints_ptr %int_to_uint_reverse + ;OpStore %ints_ptr %uint_to_int_reverse + OpStore %uints_ptr %uint_to_uint_reverse + + OpStore %ints_ptr %int_to_int_sbit + ;OpStore %uints_ptr %int_to_uint_sbit + ;OpStore %ints_ptr %uint_to_int_sbit + OpStore %uints_ptr %uint_to_uint_sbit + + OpStore %ints_ptr %int_to_int_ubit + ;OpStore %uints_ptr %int_to_uint_ubit + ;OpStore %ints_ptr %uint_to_int_ubit + OpStore %uints_ptr %uint_to_uint_ubit + + OpStore %ints_ptr %int_to_int_insert + OpStore %uints_ptr %uint_to_uint_insert + + OpReturn + OpFunctionEnd diff --git a/third_party/spirv-cross/shaders-msl-no-opt/asm/comp/copy-logical-2.spv14.asm.comp b/third_party/spirv-cross/shaders-msl-no-opt/asm/comp/copy-logical-2.spv14.asm.comp new file mode 100644 index 0000000000..6a7065a6fb --- /dev/null +++ b/third_party/spirv-cross/shaders-msl-no-opt/asm/comp/copy-logical-2.spv14.asm.comp @@ -0,0 +1,81 @@ +; SPIR-V +; Version: 1.0 +; Generator: Khronos Glslang Reference Front End; 8 +; Bound: 48 +; Schema: 0 + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" %ssbo + OpExecutionMode %main LocalSize 1 1 1 + OpSource GLSL 450 + OpName %B1 "B1" + OpName %A "A" + OpName %C "C" + OpName %B2 "B2" + OpMemberName %A 0 "a" + OpMemberName %A 1 "b1" + OpMemberName %A 2 "b1_array" + OpMemberName %C 0 "c" + OpMemberName %C 1 "b2" + OpMemberName %C 2 "b2_array" + OpMemberName %B1 0 "elem1" + OpMemberName %B2 0 "elem2" + OpMemberName %SSBO 0 "a_block" + OpMemberName %SSBO 1 "c_block" + OpDecorate %B1Array ArrayStride 16 + OpDecorate %B2Array ArrayStride 16 + OpMemberDecorate %B1 0 Offset 0 + OpMemberDecorate %A 0 Offset 0 + OpMemberDecorate %A 1 Offset 16 + OpMemberDecorate %A 2 Offset 32 + OpMemberDecorate %A 3 Offset 96 + OpMemberDecorate %B2 0 Offset 0 + OpMemberDecorate %C 0 Offset 0 + OpMemberDecorate %C 1 Offset 16 + OpMemberDecorate %C 2 Offset 32 + OpMemberDecorate %C 3 Offset 96 + OpMemberDecorate %SSBO 0 Offset 0 + OpMemberDecorate %SSBO 1 Offset 112 + OpMemberDecorate %A0 0 Offset 0 + OpMemberDecorate %C0 0 Offset 0 + OpMemberDecorate %A0 0 RowMajor + OpMemberDecorate %A0 0 MatrixStride 8 + OpMemberDecorate %C0 0 ColMajor + OpMemberDecorate %C0 0 MatrixStride 16 + OpDecorate %SSBO Block + OpDecorate %ssbo DescriptorSet 0 + OpDecorate %ssbo Binding 0 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %uint = OpTypeInt 32 0 + %uint_4 = OpConstant %uint 4 + %v4float = OpTypeVector %float 4 + %v2float = OpTypeVector %float 2 + %m2float = OpTypeMatrix %v2float 2 + %A0 = OpTypeStruct %m2float + %C0 = OpTypeStruct %m2float + %B2 = OpTypeStruct %v4float + %B2Array = OpTypeArray %B2 %uint_4 + %C = OpTypeStruct %v4float %B2 %B2Array %C0 + %B1 = OpTypeStruct %v4float + %B1Array = OpTypeArray %B1 %uint_4 + %A = OpTypeStruct %v4float %B1 %B1Array %A0 + %SSBO = OpTypeStruct %A %C +%_ptr_Uniform_SSBO = OpTypePointer StorageBuffer %SSBO + %ssbo = OpVariable %_ptr_Uniform_SSBO StorageBuffer + %int = OpTypeInt 32 1 + %int_1 = OpConstant %int 1 +%_ptr_Uniform_C = OpTypePointer StorageBuffer %C + %int_0 = OpConstant %int 0 +%_ptr_Uniform_A = OpTypePointer StorageBuffer %A + %main = OpFunction %void None %3 + %5 = OpLabel + %22 = OpAccessChain %_ptr_Uniform_C %ssbo %int_1 + %39 = OpAccessChain %_ptr_Uniform_A %ssbo %int_0 + %23 = OpLoad %C %22 + %24 = OpCopyLogical %A %23 + OpStore %39 %24 + OpReturn + OpFunctionEnd diff --git a/third_party/spirv-cross/shaders-msl-no-opt/asm/comp/copy-logical.spv14.asm.comp b/third_party/spirv-cross/shaders-msl-no-opt/asm/comp/copy-logical.spv14.asm.comp new file mode 100644 index 0000000000..20fa0b099b --- /dev/null +++ b/third_party/spirv-cross/shaders-msl-no-opt/asm/comp/copy-logical.spv14.asm.comp @@ -0,0 +1,69 @@ +; SPIR-V +; Version: 1.0 +; Generator: Khronos Glslang Reference Front End; 8 +; Bound: 48 +; Schema: 0 + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" %ssbo + OpExecutionMode %main LocalSize 1 1 1 + OpSource GLSL 450 + OpName %B1 "B1" + OpName %A "A" + OpName %C "C" + OpName %B2 "B2" + OpMemberName %A 0 "a" + OpMemberName %A 1 "b1" + OpMemberName %A 2 "b1_array" + OpMemberName %C 0 "c" + OpMemberName %C 1 "b2" + OpMemberName %C 2 "b2_array" + OpMemberName %B1 0 "elem1" + OpMemberName %B2 0 "elem2" + OpMemberName %SSBO 0 "a_block" + OpMemberName %SSBO 1 "c_block" + OpDecorate %B1Array ArrayStride 16 + OpDecorate %B2Array ArrayStride 16 + OpMemberDecorate %B1 0 Offset 0 + OpMemberDecorate %A 0 Offset 0 + OpMemberDecorate %A 1 Offset 16 + OpMemberDecorate %A 2 Offset 32 + OpMemberDecorate %B2 0 Offset 0 + OpMemberDecorate %C 0 Offset 0 + OpMemberDecorate %C 1 Offset 16 + OpMemberDecorate %C 2 Offset 32 + OpMemberDecorate %SSBO 0 Offset 0 + OpMemberDecorate %SSBO 1 Offset 96 + OpDecorate %SSBO Block + OpDecorate %ssbo DescriptorSet 0 + OpDecorate %ssbo Binding 0 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %uint = OpTypeInt 32 0 + %uint_4 = OpConstant %uint 4 + %v4float = OpTypeVector %float 4 + %B2 = OpTypeStruct %v4float + %B2Array = OpTypeArray %B2 %uint_4 + %C = OpTypeStruct %v4float %B2 %B2Array + %B1 = OpTypeStruct %v4float + %B1Array = OpTypeArray %B1 %uint_4 + %A = OpTypeStruct %v4float %B1 %B1Array + %SSBO = OpTypeStruct %A %C +%_ptr_Uniform_SSBO = OpTypePointer StorageBuffer %SSBO + %ssbo = OpVariable %_ptr_Uniform_SSBO StorageBuffer + %int = OpTypeInt 32 1 + %int_1 = OpConstant %int 1 +%_ptr_Uniform_C = OpTypePointer StorageBuffer %C + %int_0 = OpConstant %int 0 +%_ptr_Uniform_A = OpTypePointer StorageBuffer %A + %main = OpFunction %void None %3 + %5 = OpLabel + %22 = OpAccessChain %_ptr_Uniform_C %ssbo %int_1 + %39 = OpAccessChain %_ptr_Uniform_A %ssbo %int_0 + %23 = OpLoad %C %22 + %24 = OpCopyLogical %A %23 + OpStore %39 %24 + OpReturn + OpFunctionEnd diff --git a/third_party/spirv-cross/shaders-msl/asm/comp/storage-buffer-basic.invalid.asm.comp b/third_party/spirv-cross/shaders-msl-no-opt/asm/comp/storage-buffer-basic.invalid.asm.comp similarity index 100% rename from third_party/spirv-cross/shaders-msl/asm/comp/storage-buffer-basic.invalid.asm.comp rename to third_party/spirv-cross/shaders-msl-no-opt/asm/comp/storage-buffer-basic.invalid.asm.comp diff --git a/third_party/spirv-cross/shaders-msl-no-opt/asm/frag/empty-struct-in-struct.asm.frag b/third_party/spirv-cross/shaders-msl-no-opt/asm/frag/empty-struct-in-struct.asm.frag new file mode 100644 index 0000000000..a9650ddbb6 --- /dev/null +++ b/third_party/spirv-cross/shaders-msl-no-opt/asm/frag/empty-struct-in-struct.asm.frag @@ -0,0 +1,61 @@ +; SPIR-V +; Version: 1.2 +; Generator: Khronos; 0 +; Bound: 43 +; Schema: 0 + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %EntryPoint_Main "main" + OpExecutionMode %EntryPoint_Main OriginUpperLeft + OpSource Unknown 100 + OpName %EmptyStructTest "EmptyStructTest" + OpName %EmptyStruct2Test "EmptyStruct2Test" + OpName %GetValue "GetValue" + OpName %GetValue2 "GetValue" + OpName %self "self" + OpName %self2 "self" + OpName %emptyStruct "emptyStruct" + OpName %value "value" + OpName %EntryPoint_Main "EntryPoint_Main" + +%EmptyStructTest = OpTypeStruct +%EmptyStruct2Test = OpTypeStruct %EmptyStructTest +%_ptr_Function_EmptyStruct2Test = OpTypePointer Function %EmptyStruct2Test + %float = OpTypeFloat 32 +%_ptr_Function_float = OpTypePointer Function %float + %5 = OpTypeFunction %float %_ptr_Function_EmptyStruct2Test + %6 = OpTypeFunction %float %EmptyStruct2Test + %void = OpTypeVoid +%_ptr_Function_void = OpTypePointer Function %void + %8 = OpTypeFunction %void %_ptr_Function_EmptyStruct2Test + %9 = OpTypeFunction %void + %float_0 = OpConstant %float 0 + %value4 = OpConstantNull %EmptyStruct2Test + + %GetValue = OpFunction %float None %5 + %self = OpFunctionParameter %_ptr_Function_EmptyStruct2Test + %13 = OpLabel + OpReturnValue %float_0 + OpFunctionEnd + + %GetValue2 = OpFunction %float None %6 + %self2 = OpFunctionParameter %EmptyStruct2Test + %14 = OpLabel + OpReturnValue %float_0 + OpFunctionEnd + +%EntryPoint_Main = OpFunction %void None %9 + %37 = OpLabel + %emptyStruct = OpVariable %_ptr_Function_EmptyStruct2Test Function + %18 = OpVariable %_ptr_Function_EmptyStruct2Test Function + %value = OpVariable %_ptr_Function_float Function + %value2 = OpCompositeConstruct %EmptyStructTest + %value3 = OpCompositeConstruct %EmptyStruct2Test %value2 + %22 = OpFunctionCall %float %GetValue %emptyStruct + %23 = OpFunctionCall %float %GetValue2 %value3 + %24 = OpFunctionCall %float %GetValue2 %value4 + OpStore %value %22 + OpStore %value %23 + OpStore %value %24 + OpReturn + OpFunctionEnd diff --git a/third_party/spirv-cross/shaders-msl-no-opt/asm/frag/inliner-dominator-inside-loop.asm.frag b/third_party/spirv-cross/shaders-msl-no-opt/asm/frag/inliner-dominator-inside-loop.asm.frag deleted file mode 100644 index 8b09e5b68f..0000000000 --- a/third_party/spirv-cross/shaders-msl-no-opt/asm/frag/inliner-dominator-inside-loop.asm.frag +++ /dev/null @@ -1,646 +0,0 @@ -; SPIR-V -; Version: 1.0 -; Generator: Khronos Glslang Reference Front End; 3 -; Bound: 1532 -; Schema: 0 - OpCapability Shader - %1 = OpExtInstImport "GLSL.std.450" - OpMemoryModel Logical GLSL450 - OpEntryPoint Fragment %main "main" %IN_HPosition %IN_Uv_EdgeDistance1 %IN_UvStuds_EdgeDistance2 %IN_Color %IN_LightPosition_Fog %IN_View_Depth %IN_Normal_SpecPower %IN_Tangent %IN_PosLightSpace_Reflectance %IN_studIndex %_entryPointOutput - OpExecutionMode %main OriginUpperLeft - OpSource HLSL 500 - OpName %main "main" - OpName %VertexOutput "VertexOutput" - OpMemberName %VertexOutput 0 "HPosition" - OpMemberName %VertexOutput 1 "Uv_EdgeDistance1" - OpMemberName %VertexOutput 2 "UvStuds_EdgeDistance2" - OpMemberName %VertexOutput 3 "Color" - OpMemberName %VertexOutput 4 "LightPosition_Fog" - OpMemberName %VertexOutput 5 "View_Depth" - OpMemberName %VertexOutput 6 "Normal_SpecPower" - OpMemberName %VertexOutput 7 "Tangent" - OpMemberName %VertexOutput 8 "PosLightSpace_Reflectance" - OpMemberName %VertexOutput 9 "studIndex" - OpName %Surface "Surface" - OpMemberName %Surface 0 "albedo" - OpMemberName %Surface 1 "normal" - OpMemberName %Surface 2 "specular" - OpMemberName %Surface 3 "gloss" - OpMemberName %Surface 4 "reflectance" - OpMemberName %Surface 5 "opacity" - OpName %SurfaceInput "SurfaceInput" - OpMemberName %SurfaceInput 0 "Color" - OpMemberName %SurfaceInput 1 "Uv" - OpMemberName %SurfaceInput 2 "UvStuds" - OpName %Globals "Globals" - OpMemberName %Globals 0 "ViewProjection" - OpMemberName %Globals 1 "ViewRight" - OpMemberName %Globals 2 "ViewUp" - OpMemberName %Globals 3 "ViewDir" - OpMemberName %Globals 4 "CameraPosition" - OpMemberName %Globals 5 "AmbientColor" - OpMemberName %Globals 6 "Lamp0Color" - OpMemberName %Globals 7 "Lamp0Dir" - OpMemberName %Globals 8 "Lamp1Color" - OpMemberName %Globals 9 "FogParams" - OpMemberName %Globals 10 "FogColor" - OpMemberName %Globals 11 "LightBorder" - OpMemberName %Globals 12 "LightConfig0" - OpMemberName %Globals 13 "LightConfig1" - OpMemberName %Globals 14 "LightConfig2" - OpMemberName %Globals 15 "LightConfig3" - OpMemberName %Globals 16 "RefractionBias_FadeDistance_GlowFactor" - OpMemberName %Globals 17 "OutlineBrightness_ShadowInfo" - OpMemberName %Globals 18 "ShadowMatrix0" - OpMemberName %Globals 19 "ShadowMatrix1" - OpMemberName %Globals 20 "ShadowMatrix2" - OpName %CB0 "CB0" - OpMemberName %CB0 0 "CB0" - OpName %_ "" - OpName %LightMapTexture "LightMapTexture" - OpName %LightMapSampler "LightMapSampler" - OpName %ShadowMapSampler "ShadowMapSampler" - OpName %ShadowMapTexture "ShadowMapTexture" - OpName %EnvironmentMapTexture "EnvironmentMapTexture" - OpName %EnvironmentMapSampler "EnvironmentMapSampler" - OpName %IN_HPosition "IN.HPosition" - OpName %IN_Uv_EdgeDistance1 "IN.Uv_EdgeDistance1" - OpName %IN_UvStuds_EdgeDistance2 "IN.UvStuds_EdgeDistance2" - OpName %IN_Color "IN.Color" - OpName %IN_LightPosition_Fog "IN.LightPosition_Fog" - OpName %IN_View_Depth "IN.View_Depth" - OpName %IN_Normal_SpecPower "IN.Normal_SpecPower" - OpName %IN_Tangent "IN.Tangent" - OpName %IN_PosLightSpace_Reflectance "IN.PosLightSpace_Reflectance" - OpName %IN_studIndex "IN.studIndex" - OpName %_entryPointOutput "@entryPointOutput" - OpName %DiffuseMapSampler "DiffuseMapSampler" - OpName %DiffuseMapTexture "DiffuseMapTexture" - OpName %NormalMapSampler "NormalMapSampler" - OpName %NormalMapTexture "NormalMapTexture" - OpName %NormalDetailMapTexture "NormalDetailMapTexture" - OpName %NormalDetailMapSampler "NormalDetailMapSampler" - OpName %StudsMapTexture "StudsMapTexture" - OpName %StudsMapSampler "StudsMapSampler" - OpName %SpecularMapSampler "SpecularMapSampler" - OpName %SpecularMapTexture "SpecularMapTexture" - OpName %Params "Params" - OpMemberName %Params 0 "LqmatFarTilingFactor" - OpName %CB2 "CB2" - OpMemberName %CB2 0 "CB2" - OpMemberDecorate %Globals 0 ColMajor - OpMemberDecorate %Globals 0 Offset 0 - OpMemberDecorate %Globals 0 MatrixStride 16 - OpMemberDecorate %Globals 1 Offset 64 - OpMemberDecorate %Globals 2 Offset 80 - OpMemberDecorate %Globals 3 Offset 96 - OpMemberDecorate %Globals 4 Offset 112 - OpMemberDecorate %Globals 5 Offset 128 - OpMemberDecorate %Globals 6 Offset 144 - OpMemberDecorate %Globals 7 Offset 160 - OpMemberDecorate %Globals 8 Offset 176 - OpMemberDecorate %Globals 9 Offset 192 - OpMemberDecorate %Globals 10 Offset 208 - OpMemberDecorate %Globals 11 Offset 224 - OpMemberDecorate %Globals 12 Offset 240 - OpMemberDecorate %Globals 13 Offset 256 - OpMemberDecorate %Globals 14 Offset 272 - OpMemberDecorate %Globals 15 Offset 288 - OpMemberDecorate %Globals 16 Offset 304 - OpMemberDecorate %Globals 17 Offset 320 - OpMemberDecorate %Globals 18 Offset 336 - OpMemberDecorate %Globals 19 Offset 352 - OpMemberDecorate %Globals 20 Offset 368 - OpMemberDecorate %CB0 0 Offset 0 - OpDecorate %CB0 Block - OpDecorate %_ DescriptorSet 0 - OpDecorate %_ Binding 0 - OpDecorate %LightMapTexture DescriptorSet 1 - OpDecorate %LightMapTexture Binding 6 - OpDecorate %LightMapSampler DescriptorSet 1 - OpDecorate %LightMapSampler Binding 6 - OpDecorate %ShadowMapSampler DescriptorSet 1 - OpDecorate %ShadowMapSampler Binding 1 - OpDecorate %ShadowMapTexture DescriptorSet 1 - OpDecorate %ShadowMapTexture Binding 1 - OpDecorate %EnvironmentMapTexture DescriptorSet 1 - OpDecorate %EnvironmentMapTexture Binding 2 - OpDecorate %EnvironmentMapSampler DescriptorSet 1 - OpDecorate %EnvironmentMapSampler Binding 2 - OpDecorate %IN_HPosition BuiltIn FragCoord - OpDecorate %IN_Uv_EdgeDistance1 Location 0 - OpDecorate %IN_UvStuds_EdgeDistance2 Location 1 - OpDecorate %IN_Color Location 2 - OpDecorate %IN_LightPosition_Fog Location 3 - OpDecorate %IN_View_Depth Location 4 - OpDecorate %IN_Normal_SpecPower Location 5 - OpDecorate %IN_Tangent Location 6 - OpDecorate %IN_PosLightSpace_Reflectance Location 7 - OpDecorate %IN_studIndex Location 8 - OpDecorate %_entryPointOutput Location 0 - OpDecorate %DiffuseMapSampler DescriptorSet 1 - OpDecorate %DiffuseMapSampler Binding 3 - OpDecorate %DiffuseMapTexture DescriptorSet 1 - OpDecorate %DiffuseMapTexture Binding 3 - OpDecorate %NormalMapSampler DescriptorSet 1 - OpDecorate %NormalMapSampler Binding 4 - OpDecorate %NormalMapTexture DescriptorSet 1 - OpDecorate %NormalMapTexture Binding 4 - OpDecorate %NormalDetailMapTexture DescriptorSet 1 - OpDecorate %NormalDetailMapTexture Binding 8 - OpDecorate %NormalDetailMapSampler DescriptorSet 1 - OpDecorate %NormalDetailMapSampler Binding 8 - OpDecorate %StudsMapTexture DescriptorSet 1 - OpDecorate %StudsMapTexture Binding 0 - OpDecorate %StudsMapSampler DescriptorSet 1 - OpDecorate %StudsMapSampler Binding 0 - OpDecorate %SpecularMapSampler DescriptorSet 1 - OpDecorate %SpecularMapSampler Binding 5 - OpDecorate %SpecularMapTexture DescriptorSet 1 - OpDecorate %SpecularMapTexture Binding 5 - OpMemberDecorate %Params 0 Offset 0 - OpMemberDecorate %CB2 0 Offset 0 - OpDecorate %CB2 Block - %void = OpTypeVoid - %3 = OpTypeFunction %void - %float = OpTypeFloat 32 -%_ptr_Function_float = OpTypePointer Function %float - %8 = OpTypeFunction %float %_ptr_Function_float - %v4float = OpTypeVector %float 4 -%_ptr_Function_v4float = OpTypePointer Function %v4float - %v3float = OpTypeVector %float 3 - %18 = OpTypeFunction %v3float %_ptr_Function_v4float -%_ptr_Function_v3float = OpTypePointer Function %v3float - %23 = OpTypeFunction %v4float %_ptr_Function_v3float - %27 = OpTypeFunction %float %_ptr_Function_v3float - %31 = OpTypeFunction %float %_ptr_Function_float %_ptr_Function_float - %36 = OpTypeSampler -%_ptr_Function_36 = OpTypePointer Function %36 - %38 = OpTypeImage %float 2D 0 0 0 1 Unknown -%_ptr_Function_38 = OpTypePointer Function %38 - %40 = OpTypeFunction %float %_ptr_Function_36 %_ptr_Function_38 %_ptr_Function_v3float %_ptr_Function_float -%VertexOutput = OpTypeStruct %v4float %v4float %v4float %v4float %v4float %v4float %v4float %v3float %v4float %float -%_ptr_Function_VertexOutput = OpTypePointer Function %VertexOutput - %Surface = OpTypeStruct %v3float %v3float %float %float %float %float - %50 = OpTypeFunction %Surface %_ptr_Function_VertexOutput - %54 = OpTypeFunction %v4float %_ptr_Function_VertexOutput - %v2float = OpTypeVector %float 2 -%_ptr_Function_v2float = OpTypePointer Function %v2float - %60 = OpTypeFunction %v4float %_ptr_Function_36 %_ptr_Function_38 %_ptr_Function_v2float %_ptr_Function_float %_ptr_Function_float -%SurfaceInput = OpTypeStruct %v4float %v2float %v2float -%_ptr_Function_SurfaceInput = OpTypePointer Function %SurfaceInput - %70 = OpTypeFunction %Surface %_ptr_Function_SurfaceInput %_ptr_Function_v2float - %float_0 = OpConstant %float 0 - %float_1 = OpConstant %float 1 - %float_2 = OpConstant %float 2 -%mat4v4float = OpTypeMatrix %v4float 4 - %Globals = OpTypeStruct %mat4v4float %v4float %v4float %v4float %v3float %v3float %v3float %v3float %v3float %v4float %v3float %v4float %v4float %v4float %v4float %v4float %v4float %v4float %v4float %v4float %v4float - %CB0 = OpTypeStruct %Globals -%_ptr_Uniform_CB0 = OpTypePointer Uniform %CB0 - %_ = OpVariable %_ptr_Uniform_CB0 Uniform - %int = OpTypeInt 32 1 - %int_0 = OpConstant %int 0 - %int_15 = OpConstant %int 15 -%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float - %int_14 = OpConstant %int 14 - %128 = OpConstantComposite %v3float %float_1 %float_1 %float_1 - %133 = OpTypeImage %float 3D 0 0 0 1 Unknown -%_ptr_UniformConstant_133 = OpTypePointer UniformConstant %133 -%LightMapTexture = OpVariable %_ptr_UniformConstant_133 UniformConstant -%_ptr_UniformConstant_36 = OpTypePointer UniformConstant %36 -%LightMapSampler = OpVariable %_ptr_UniformConstant_36 UniformConstant - %140 = OpTypeSampledImage %133 - %int_11 = OpConstant %int 11 - %uint = OpTypeInt 32 0 - %float_9 = OpConstant %float 9 - %float_20 = OpConstant %float 20 - %float_0_5 = OpConstant %float 0.5 - %183 = OpTypeSampledImage %38 - %uint_0 = OpConstant %uint 0 - %uint_1 = OpConstant %uint 1 - %int_17 = OpConstant %int 17 - %uint_3 = OpConstant %uint 3 -%_ptr_Uniform_float = OpTypePointer Uniform %float - %float_0_25 = OpConstant %float 0.25 - %int_5 = OpConstant %int 5 -%float_0_00333333 = OpConstant %float 0.00333333 - %int_16 = OpConstant %int 16 -%_ptr_Function_Surface = OpTypePointer Function %Surface - %int_6 = OpConstant %int 6 - %int_7 = OpConstant %int 7 -%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float - %int_8 = OpConstant %int 8 -%ShadowMapSampler = OpVariable %_ptr_UniformConstant_36 UniformConstant -%_ptr_UniformConstant_38 = OpTypePointer UniformConstant %38 -%ShadowMapTexture = OpVariable %_ptr_UniformConstant_38 UniformConstant - %367 = OpTypeImage %float Cube 0 0 0 1 Unknown -%_ptr_UniformConstant_367 = OpTypePointer UniformConstant %367 -%EnvironmentMapTexture = OpVariable %_ptr_UniformConstant_367 UniformConstant -%EnvironmentMapSampler = OpVariable %_ptr_UniformConstant_36 UniformConstant - %373 = OpTypeSampledImage %367 - %float_1_5 = OpConstant %float 1.5 - %int_10 = OpConstant %int 10 -%_ptr_Input_v4float = OpTypePointer Input %v4float -%IN_HPosition = OpVariable %_ptr_Input_v4float Input -%IN_Uv_EdgeDistance1 = OpVariable %_ptr_Input_v4float Input -%IN_UvStuds_EdgeDistance2 = OpVariable %_ptr_Input_v4float Input - %IN_Color = OpVariable %_ptr_Input_v4float Input -%IN_LightPosition_Fog = OpVariable %_ptr_Input_v4float Input -%IN_View_Depth = OpVariable %_ptr_Input_v4float Input -%IN_Normal_SpecPower = OpVariable %_ptr_Input_v4float Input -%_ptr_Input_v3float = OpTypePointer Input %v3float - %IN_Tangent = OpVariable %_ptr_Input_v3float Input -%IN_PosLightSpace_Reflectance = OpVariable %_ptr_Input_v4float Input -%_ptr_Input_float = OpTypePointer Input %float -%IN_studIndex = OpVariable %_ptr_Input_float Input -%_ptr_Output_v4float = OpTypePointer Output %v4float -%_entryPointOutput = OpVariable %_ptr_Output_v4float Output - %bool = OpTypeBool -%DiffuseMapSampler = OpVariable %_ptr_UniformConstant_36 UniformConstant -%DiffuseMapTexture = OpVariable %_ptr_UniformConstant_38 UniformConstant -%NormalMapSampler = OpVariable %_ptr_UniformConstant_36 UniformConstant -%NormalMapTexture = OpVariable %_ptr_UniformConstant_38 UniformConstant -%NormalDetailMapTexture = OpVariable %_ptr_UniformConstant_38 UniformConstant -%NormalDetailMapSampler = OpVariable %_ptr_UniformConstant_36 UniformConstant - %float_0_3 = OpConstant %float 0.3 -%StudsMapTexture = OpVariable %_ptr_UniformConstant_38 UniformConstant -%StudsMapSampler = OpVariable %_ptr_UniformConstant_36 UniformConstant -%SpecularMapSampler = OpVariable %_ptr_UniformConstant_36 UniformConstant -%SpecularMapTexture = OpVariable %_ptr_UniformConstant_38 UniformConstant - %float_0_75 = OpConstant %float 0.75 - %float_256 = OpConstant %float 256 - %689 = OpConstantComposite %v2float %float_2 %float_256 - %float_0_01 = OpConstant %float 0.01 - %692 = OpConstantComposite %v2float %float_0 %float_0_01 - %float_0_8 = OpConstant %float 0.8 - %float_120 = OpConstant %float 120 - %697 = OpConstantComposite %v2float %float_0_8 %float_120 - %Params = OpTypeStruct %v4float - %CB2 = OpTypeStruct %Params -%_ptr_Uniform_CB2 = OpTypePointer Uniform %CB2 - %false = OpConstantFalse %bool - %1509 = OpUndef %VertexOutput - %1510 = OpUndef %SurfaceInput - %1511 = OpUndef %v2float - %1512 = OpUndef %v4float - %1531 = OpUndef %Surface - %main = OpFunction %void None %3 - %5 = OpLabel - %501 = OpLoad %v4float %IN_HPosition - %1378 = OpCompositeInsert %VertexOutput %501 %1509 0 - %504 = OpLoad %v4float %IN_Uv_EdgeDistance1 - %1380 = OpCompositeInsert %VertexOutput %504 %1378 1 - %507 = OpLoad %v4float %IN_UvStuds_EdgeDistance2 - %1382 = OpCompositeInsert %VertexOutput %507 %1380 2 - %510 = OpLoad %v4float %IN_Color - %1384 = OpCompositeInsert %VertexOutput %510 %1382 3 - %513 = OpLoad %v4float %IN_LightPosition_Fog - %1386 = OpCompositeInsert %VertexOutput %513 %1384 4 - %516 = OpLoad %v4float %IN_View_Depth - %1388 = OpCompositeInsert %VertexOutput %516 %1386 5 - %519 = OpLoad %v4float %IN_Normal_SpecPower - %1390 = OpCompositeInsert %VertexOutput %519 %1388 6 - %523 = OpLoad %v3float %IN_Tangent - %1392 = OpCompositeInsert %VertexOutput %523 %1390 7 - %526 = OpLoad %v4float %IN_PosLightSpace_Reflectance - %1394 = OpCompositeInsert %VertexOutput %526 %1392 8 - %530 = OpLoad %float %IN_studIndex - %1396 = OpCompositeInsert %VertexOutput %530 %1394 9 - %1400 = OpCompositeInsert %SurfaceInput %510 %1510 0 - %954 = OpVectorShuffle %v2float %504 %504 0 1 - %1404 = OpCompositeInsert %SurfaceInput %954 %1400 1 - %958 = OpVectorShuffle %v2float %507 %507 0 1 - %1408 = OpCompositeInsert %SurfaceInput %958 %1404 2 - %1410 = OpCompositeExtract %float %1408 2 1 - %962 = OpExtInst %float %1 Fract %1410 - %965 = OpFAdd %float %962 %530 - %966 = OpFMul %float %965 %float_0_25 - %1414 = OpCompositeInsert %SurfaceInput %966 %1408 2 1 - %1416 = OpCompositeExtract %float %1396 5 3 - %970 = OpFMul %float %1416 %float_0_00333333 - %971 = OpFSub %float %float_1 %970 - %987 = OpExtInst %float %1 FClamp %971 %float_0 %float_1 - %976 = OpAccessChain %_ptr_Uniform_float %_ %int_0 %int_16 %uint_1 - %977 = OpLoad %float %976 - %978 = OpFMul %float %1416 %977 - %979 = OpFSub %float %float_1 %978 - %990 = OpExtInst %float %1 FClamp %979 %float_0 %float_1 - %1024 = OpVectorTimesScalar %v2float %954 %float_1 - %1029 = OpLoad %36 %DiffuseMapSampler - %1030 = OpLoad %38 %DiffuseMapTexture - OpBranch %1119 - %1119 = OpLabel - OpLoopMerge %1120 %1121 None - OpBranch %1122 - %1122 = OpLabel - %1124 = OpFOrdEqual %bool %float_0 %float_0 - OpSelectionMerge %1125 None - OpBranchConditional %1124 %1126 %1127 - %1126 = OpLabel - %1130 = OpSampledImage %183 %1030 %1029 - %1132 = OpImageSampleImplicitLod %v4float %1130 %1024 - OpBranch %1120 - %1127 = OpLabel - %1134 = OpFSub %float %float_1 %float_0 - %1135 = OpFDiv %float %float_1 %1134 - %1138 = OpSampledImage %183 %1030 %1029 - %1140 = OpVectorTimesScalar %v2float %1024 %float_0_25 - %1141 = OpImageSampleImplicitLod %v4float %1138 %1140 - %1144 = OpSampledImage %183 %1030 %1029 - %1146 = OpImageSampleImplicitLod %v4float %1144 %1024 - %1149 = OpFMul %float %987 %1135 - %1152 = OpFMul %float %float_0 %1135 - %1153 = OpFSub %float %1149 %1152 - %1161 = OpExtInst %float %1 FClamp %1153 %float_0 %float_1 - %1155 = OpCompositeConstruct %v4float %1161 %1161 %1161 %1161 - %1156 = OpExtInst %v4float %1 FMix %1141 %1146 %1155 - OpBranch %1120 - %1125 = OpLabel - %1157 = OpUndef %v4float - OpBranch %1120 - %1121 = OpLabel - OpBranchConditional %false %1119 %1120 - %1120 = OpLabel - %1517 = OpPhi %v4float %1132 %1126 %1156 %1127 %1157 %1125 %1512 %1121 - %1035 = OpVectorTimesScalar %v4float %1517 %float_1 - %1036 = OpLoad %36 %NormalMapSampler - %1037 = OpLoad %38 %NormalMapTexture - OpBranch %1165 - %1165 = OpLabel - OpLoopMerge %1166 %1167 None - OpBranch %1168 - %1168 = OpLabel - OpSelectionMerge %1171 None - OpBranchConditional %1124 %1172 %1173 - %1172 = OpLabel - %1176 = OpSampledImage %183 %1037 %1036 - %1178 = OpImageSampleImplicitLod %v4float %1176 %1024 - OpBranch %1166 - %1173 = OpLabel - %1180 = OpFSub %float %float_1 %float_0 - %1181 = OpFDiv %float %float_1 %1180 - %1184 = OpSampledImage %183 %1037 %1036 - %1186 = OpVectorTimesScalar %v2float %1024 %float_0_25 - %1187 = OpImageSampleImplicitLod %v4float %1184 %1186 - %1190 = OpSampledImage %183 %1037 %1036 - %1192 = OpImageSampleImplicitLod %v4float %1190 %1024 - %1195 = OpFMul %float %990 %1181 - %1198 = OpFMul %float %float_0 %1181 - %1199 = OpFSub %float %1195 %1198 - %1206 = OpExtInst %float %1 FClamp %1199 %float_0 %float_1 - %1201 = OpCompositeConstruct %v4float %1206 %1206 %1206 %1206 - %1202 = OpExtInst %v4float %1 FMix %1187 %1192 %1201 - OpBranch %1166 - %1171 = OpLabel - %1203 = OpUndef %v4float - OpBranch %1166 - %1167 = OpLabel - OpBranchConditional %false %1165 %1166 - %1166 = OpLabel - %1523 = OpPhi %v4float %1178 %1172 %1202 %1173 %1203 %1171 %1512 %1167 - %1210 = OpVectorShuffle %v2float %1523 %1523 3 1 - %1211 = OpVectorTimesScalar %v2float %1210 %float_2 - %1212 = OpCompositeConstruct %v2float %float_1 %float_1 - %1213 = OpFSub %v2float %1211 %1212 - %1216 = OpFNegate %v2float %1213 - %1218 = OpDot %float %1216 %1213 - %1219 = OpFAdd %float %float_1 %1218 - %1220 = OpExtInst %float %1 FClamp %1219 %float_0 %float_1 - %1221 = OpExtInst %float %1 Sqrt %1220 - %1222 = OpCompositeExtract %float %1213 0 - %1223 = OpCompositeExtract %float %1213 1 - %1224 = OpCompositeConstruct %v3float %1222 %1223 %1221 - %1042 = OpLoad %38 %NormalDetailMapTexture - %1043 = OpLoad %36 %NormalDetailMapSampler - %1044 = OpSampledImage %183 %1042 %1043 - %1046 = OpVectorTimesScalar %v2float %1024 %float_0 - %1047 = OpImageSampleImplicitLod %v4float %1044 %1046 - %1228 = OpVectorShuffle %v2float %1047 %1047 3 1 - %1229 = OpVectorTimesScalar %v2float %1228 %float_2 - %1231 = OpFSub %v2float %1229 %1212 - %1234 = OpFNegate %v2float %1231 - %1236 = OpDot %float %1234 %1231 - %1237 = OpFAdd %float %float_1 %1236 - %1238 = OpExtInst %float %1 FClamp %1237 %float_0 %float_1 - %1239 = OpExtInst %float %1 Sqrt %1238 - %1240 = OpCompositeExtract %float %1231 0 - %1241 = OpCompositeExtract %float %1231 1 - %1242 = OpCompositeConstruct %v3float %1240 %1241 %1239 - %1050 = OpVectorShuffle %v2float %1242 %1242 0 1 - %1051 = OpVectorTimesScalar %v2float %1050 %float_0 - %1053 = OpVectorShuffle %v2float %1224 %1224 0 1 - %1054 = OpFAdd %v2float %1053 %1051 - %1056 = OpVectorShuffle %v3float %1224 %1054 3 4 2 - %1059 = OpVectorShuffle %v2float %1056 %1056 0 1 - %1060 = OpVectorTimesScalar %v2float %1059 %990 - %1062 = OpVectorShuffle %v3float %1056 %1060 3 4 2 - %1430 = OpCompositeExtract %float %1062 0 - %1065 = OpFMul %float %1430 %float_0_3 - %1066 = OpFAdd %float %float_1 %1065 - %1069 = OpVectorShuffle %v3float %510 %510 0 1 2 - %1071 = OpVectorShuffle %v3float %1035 %1035 0 1 2 - %1072 = OpFMul %v3float %1069 %1071 - %1074 = OpVectorTimesScalar %v3float %1072 %1066 - %1075 = OpLoad %38 %StudsMapTexture - %1076 = OpLoad %36 %StudsMapSampler - %1077 = OpSampledImage %183 %1075 %1076 - %1434 = OpCompositeExtract %v2float %1414 2 - %1080 = OpImageSampleImplicitLod %v4float %1077 %1434 - %1436 = OpCompositeExtract %float %1080 0 - %1083 = OpFMul %float %1436 %float_2 - %1085 = OpVectorTimesScalar %v3float %1074 %1083 - %1086 = OpLoad %36 %SpecularMapSampler - %1087 = OpLoad %38 %SpecularMapTexture - OpBranch %1246 - %1246 = OpLabel - OpLoopMerge %1247 %1248 None - OpBranch %1249 - %1249 = OpLabel - %1251 = OpFOrdEqual %bool %float_0_75 %float_0 - OpSelectionMerge %1252 None - OpBranchConditional %1251 %1253 %1254 - %1253 = OpLabel - %1257 = OpSampledImage %183 %1087 %1086 - %1259 = OpImageSampleImplicitLod %v4float %1257 %1024 - OpBranch %1247 - %1254 = OpLabel - %1261 = OpFSub %float %float_1 %float_0_75 - %1262 = OpFDiv %float %float_1 %1261 - %1265 = OpSampledImage %183 %1087 %1086 - %1267 = OpVectorTimesScalar %v2float %1024 %float_0_25 - %1268 = OpImageSampleImplicitLod %v4float %1265 %1267 - %1271 = OpSampledImage %183 %1087 %1086 - %1273 = OpImageSampleImplicitLod %v4float %1271 %1024 - %1276 = OpFMul %float %990 %1262 - %1279 = OpFMul %float %float_0_75 %1262 - %1280 = OpFSub %float %1276 %1279 - %1287 = OpExtInst %float %1 FClamp %1280 %float_0 %float_1 - %1282 = OpCompositeConstruct %v4float %1287 %1287 %1287 %1287 - %1283 = OpExtInst %v4float %1 FMix %1268 %1273 %1282 - OpBranch %1247 - %1252 = OpLabel - %1284 = OpUndef %v4float - OpBranch %1247 - %1248 = OpLabel - OpBranchConditional %false %1246 %1247 - %1247 = OpLabel - %1530 = OpPhi %v4float %1259 %1253 %1283 %1254 %1284 %1252 %1512 %1248 - %1091 = OpVectorShuffle %v2float %1530 %1530 0 1 - %1093 = OpFMul %v2float %1091 %689 - %1094 = OpFAdd %v2float %1093 %692 - %1097 = OpCompositeConstruct %v2float %990 %990 - %1098 = OpExtInst %v2float %1 FMix %697 %1094 %1097 - %1438 = OpCompositeInsert %Surface %1085 %1531 0 - %1440 = OpCompositeInsert %Surface %1062 %1438 1 - %1442 = OpCompositeExtract %float %1098 0 - %1444 = OpCompositeInsert %Surface %1442 %1440 2 - %1446 = OpCompositeExtract %float %1098 1 - %1448 = OpCompositeInsert %Surface %1446 %1444 3 - %1450 = OpCompositeExtract %float %1091 1 - %1112 = OpFMul %float %1450 %990 - %1113 = OpFMul %float %1112 %float_0 - %1452 = OpCompositeInsert %Surface %1113 %1448 4 - %1456 = OpCompositeExtract %float %1396 3 3 - %764 = OpCompositeExtract %float %1085 0 - %765 = OpCompositeExtract %float %1085 1 - %766 = OpCompositeExtract %float %1085 2 - %767 = OpCompositeConstruct %v4float %764 %765 %766 %1456 - %770 = OpVectorShuffle %v3float %519 %519 0 1 2 - %773 = OpExtInst %v3float %1 Cross %770 %523 - %1462 = OpCompositeExtract %float %1452 1 0 - %778 = OpVectorTimesScalar %v3float %523 %1462 - %1466 = OpCompositeExtract %float %1452 1 1 - %782 = OpVectorTimesScalar %v3float %773 %1466 - %783 = OpFAdd %v3float %778 %782 - %1468 = OpCompositeExtract %float %1452 1 2 - %789 = OpVectorTimesScalar %v3float %770 %1468 - %790 = OpFAdd %v3float %783 %789 - %791 = OpExtInst %v3float %1 Normalize %790 - %793 = OpAccessChain %_ptr_Uniform_v3float %_ %int_0 %int_7 - %794 = OpLoad %v3float %793 - %795 = OpFNegate %v3float %794 - %796 = OpDot %float %791 %795 - %1290 = OpExtInst %float %1 FClamp %796 %float_0 %float_1 - %799 = OpAccessChain %_ptr_Uniform_v3float %_ %int_0 %int_6 - %800 = OpLoad %v3float %799 - %801 = OpVectorTimesScalar %v3float %800 %1290 - %803 = OpFNegate %float %796 - %804 = OpExtInst %float %1 FMax %803 %float_0 - %805 = OpAccessChain %_ptr_Uniform_v3float %_ %int_0 %int_8 - %806 = OpLoad %v3float %805 - %807 = OpVectorTimesScalar %v3float %806 %804 - %808 = OpFAdd %v3float %801 %807 - %810 = OpExtInst %float %1 Step %float_0 %796 - %813 = OpFMul %float %810 %1442 - %820 = OpVectorShuffle %v3float %513 %513 0 1 2 - %1296 = OpAccessChain %_ptr_Uniform_v4float %_ %int_0 %int_15 - %1297 = OpLoad %v4float %1296 - %1298 = OpVectorShuffle %v3float %1297 %1297 0 1 2 - %1300 = OpAccessChain %_ptr_Uniform_v4float %_ %int_0 %int_14 - %1301 = OpLoad %v4float %1300 - %1302 = OpVectorShuffle %v3float %1301 %1301 0 1 2 - %1303 = OpFSub %v3float %820 %1302 - %1304 = OpExtInst %v3float %1 FAbs %1303 - %1305 = OpExtInst %v3float %1 Step %1298 %1304 - %1307 = OpDot %float %1305 %128 - %1328 = OpExtInst %float %1 FClamp %1307 %float_0 %float_1 - %1309 = OpLoad %133 %LightMapTexture - %1310 = OpLoad %36 %LightMapSampler - %1311 = OpSampledImage %140 %1309 %1310 - %1313 = OpVectorShuffle %v3float %820 %820 1 2 0 - %1317 = OpVectorTimesScalar %v3float %1313 %1328 - %1318 = OpFSub %v3float %1313 %1317 - %1319 = OpImageSampleImplicitLod %v4float %1311 %1318 - %1321 = OpAccessChain %_ptr_Uniform_v4float %_ %int_0 %int_11 - %1322 = OpLoad %v4float %1321 - %1324 = OpCompositeConstruct %v4float %1328 %1328 %1328 %1328 - %1325 = OpExtInst %v4float %1 FMix %1319 %1322 %1324 - %822 = OpLoad %36 %ShadowMapSampler - %823 = OpLoad %38 %ShadowMapTexture - %826 = OpVectorShuffle %v3float %526 %526 0 1 2 - %1482 = OpCompositeExtract %float %1325 3 - %1337 = OpSampledImage %183 %823 %822 - %1339 = OpVectorShuffle %v2float %826 %826 0 1 - %1340 = OpImageSampleImplicitLod %v4float %1337 %1339 - %1341 = OpVectorShuffle %v2float %1340 %1340 0 1 - %1484 = OpCompositeExtract %float %826 2 - %1486 = OpCompositeExtract %float %1341 0 - %1363 = OpExtInst %float %1 Step %1486 %1484 - %1365 = OpFSub %float %1484 %float_0_5 - %1366 = OpExtInst %float %1 FAbs %1365 - %1367 = OpFMul %float %float_20 %1366 - %1368 = OpFSub %float %float_9 %1367 - %1369 = OpExtInst %float %1 FClamp %1368 %float_0 %float_1 - %1370 = OpFMul %float %1363 %1369 - %1488 = OpCompositeExtract %float %1341 1 - %1350 = OpFMul %float %1370 %1488 - %1351 = OpAccessChain %_ptr_Uniform_float %_ %int_0 %int_17 %uint_3 - %1352 = OpLoad %float %1351 - %1353 = OpFMul %float %1350 %1352 - %1354 = OpFSub %float %float_1 %1353 - %1356 = OpFMul %float %1354 %1482 - %830 = OpLoad %367 %EnvironmentMapTexture - %831 = OpLoad %36 %EnvironmentMapSampler - %832 = OpSampledImage %373 %830 %831 - %835 = OpVectorShuffle %v3float %516 %516 0 1 2 - %836 = OpFNegate %v3float %835 - %838 = OpExtInst %v3float %1 Reflect %836 %791 - %839 = OpImageSampleImplicitLod %v4float %832 %838 - %840 = OpVectorShuffle %v3float %839 %839 0 1 2 - %842 = OpVectorShuffle %v3float %767 %767 0 1 2 - %845 = OpCompositeConstruct %v3float %1113 %1113 %1113 - %846 = OpExtInst %v3float %1 FMix %842 %840 %845 - %848 = OpVectorShuffle %v4float %767 %846 4 5 6 3 - %849 = OpAccessChain %_ptr_Uniform_v3float %_ %int_0 %int_5 - %850 = OpLoad %v3float %849 - %853 = OpVectorTimesScalar %v3float %808 %1356 - %854 = OpFAdd %v3float %850 %853 - %856 = OpVectorShuffle %v3float %1325 %1325 0 1 2 - %857 = OpFAdd %v3float %854 %856 - %859 = OpVectorShuffle %v3float %848 %848 0 1 2 - %860 = OpFMul %v3float %857 %859 - %865 = OpFMul %float %813 %1356 - %873 = OpExtInst %v3float %1 Normalize %835 - %874 = OpFAdd %v3float %795 %873 - %875 = OpExtInst %v3float %1 Normalize %874 - %876 = OpDot %float %791 %875 - %877 = OpExtInst %float %1 FClamp %876 %float_0 %float_1 - %879 = OpExtInst %float %1 Pow %877 %1446 - %880 = OpFMul %float %865 %879 - %881 = OpVectorTimesScalar %v3float %800 %880 - %884 = OpFAdd %v3float %860 %881 - %886 = OpVectorShuffle %v4float %1512 %884 4 5 6 3 - %1494 = OpCompositeExtract %float %848 3 - %1496 = OpCompositeInsert %v4float %1494 %886 3 - %896 = OpAccessChain %_ptr_Uniform_float %_ %int_0 %int_17 %uint_0 - %897 = OpLoad %float %896 - %898 = OpFMul %float %978 %897 - %899 = OpAccessChain %_ptr_Uniform_float %_ %int_0 %int_17 %uint_1 - %900 = OpLoad %float %899 - %901 = OpFAdd %float %898 %900 - %1373 = OpExtInst %float %1 FClamp %901 %float_0 %float_1 - %905 = OpVectorShuffle %v2float %504 %504 3 2 - %908 = OpVectorShuffle %v2float %507 %507 3 2 - %909 = OpExtInst %v2float %1 FMin %905 %908 - %1504 = OpCompositeExtract %float %909 0 - %1506 = OpCompositeExtract %float %909 1 - %914 = OpExtInst %float %1 FMin %1504 %1506 - %916 = OpFDiv %float %914 %978 - %919 = OpFSub %float %float_1_5 %916 - %920 = OpFMul %float %1373 %919 - %922 = OpFAdd %float %920 %916 - %1376 = OpExtInst %float %1 FClamp %922 %float_0 %float_1 - %925 = OpVectorShuffle %v3float %1496 %1496 0 1 2 - %926 = OpVectorTimesScalar %v3float %925 %1376 - %928 = OpVectorShuffle %v4float %1496 %926 4 5 6 3 - %1508 = OpCompositeExtract %float %1396 4 3 - %931 = OpExtInst %float %1 FClamp %1508 %float_0 %float_1 - %932 = OpAccessChain %_ptr_Uniform_v3float %_ %int_0 %int_10 - %933 = OpLoad %v3float %932 - %935 = OpVectorShuffle %v3float %928 %928 0 1 2 - %937 = OpCompositeConstruct %v3float %931 %931 %931 - %938 = OpExtInst %v3float %1 FMix %933 %935 %937 - %940 = OpVectorShuffle %v4float %928 %938 4 5 6 3 - OpStore %_entryPointOutput %940 - OpReturn - OpFunctionEnd diff --git a/third_party/spirv-cross/shaders-msl-no-opt/asm/frag/modf-frexp-scalar-access-chain-output.asm.frag b/third_party/spirv-cross/shaders-msl-no-opt/asm/frag/modf-frexp-scalar-access-chain-output.asm.frag new file mode 100644 index 0000000000..707fa550b9 --- /dev/null +++ b/third_party/spirv-cross/shaders-msl-no-opt/asm/frag/modf-frexp-scalar-access-chain-output.asm.frag @@ -0,0 +1,36 @@ +; SPIR-V +; Version: 1.0 +; Generator: Khronos Glslang Reference Front End; 7 +; Bound: 17 +; Schema: 0 + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" + OpExecutionMode %main OriginUpperLeft + OpSource ESSL 310 + OpName %main "main" + OpName %col "col" + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 +%_ptr_Function_float = OpTypePointer Function %float +%float_0_150000006 = OpConstant %float 0.150000006 + %v3float = OpTypeVector %float 3 +%_ptr_Function_v3float = OpTypePointer Function %v3float + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 + %int_1 = OpConstant %int 1 + %v2int = OpTypeVector %int 2 +%_ptr_Function_v2int = OpTypePointer Function %v2int +%_ptr_Function_int = OpTypePointer Function %int + %main = OpFunction %void None %3 + %5 = OpLabel + %col = OpVariable %_ptr_Function_v3float Function + %icol = OpVariable %_ptr_Function_v2int Function + %ptr_x = OpAccessChain %_ptr_Function_float %col %int_0 + %ptr_y = OpAccessChain %_ptr_Function_int %icol %int_1 + %16 = OpExtInst %float %1 Modf %float_0_150000006 %ptr_x + %17 = OpExtInst %float %1 Frexp %float_0_150000006 %ptr_y + OpReturn + OpFunctionEnd diff --git a/third_party/spirv-cross/shaders-msl-no-opt/asm/frag/pixel-interlock-callstack.msl2.asm.frag b/third_party/spirv-cross/shaders-msl-no-opt/asm/frag/pixel-interlock-callstack.msl2.asm.frag new file mode 100644 index 0000000000..ebd8d6bab7 --- /dev/null +++ b/third_party/spirv-cross/shaders-msl-no-opt/asm/frag/pixel-interlock-callstack.msl2.asm.frag @@ -0,0 +1,89 @@ +; SPIR-V +; Version: 1.0 +; Generator: Khronos Glslang Reference Front End; 7 +; Bound: 45 +; Schema: 0 + OpCapability Shader + OpCapability FragmentShaderPixelInterlockEXT + OpExtension "SPV_EXT_fragment_shader_interlock" + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %gl_FragCoord + OpExecutionMode %main OriginUpperLeft + OpExecutionMode %main PixelInterlockOrderedEXT + OpSource GLSL 450 + OpSourceExtension "GL_ARB_fragment_shader_interlock" + OpName %main "main" + OpName %callee2_ "callee2(" + OpName %callee_ "callee(" + OpName %SSBO1 "SSBO1" + OpMemberName %SSBO1 0 "values1" + OpName %_ "" + OpName %gl_FragCoord "gl_FragCoord" + OpName %SSBO0 "SSBO0" + OpMemberName %SSBO0 0 "values0" + OpName %__0 "" + OpDecorate %_runtimearr_uint ArrayStride 4 + OpMemberDecorate %SSBO1 0 Offset 0 + OpDecorate %SSBO1 BufferBlock + OpDecorate %_ DescriptorSet 0 + OpDecorate %_ Binding 1 + OpDecorate %gl_FragCoord BuiltIn FragCoord + OpDecorate %_runtimearr_uint_0 ArrayStride 4 + OpMemberDecorate %SSBO0 0 Offset 0 + OpDecorate %SSBO0 BufferBlock + OpDecorate %__0 DescriptorSet 0 + OpDecorate %__0 Binding 0 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %uint = OpTypeInt 32 0 +%_runtimearr_uint = OpTypeRuntimeArray %uint + %SSBO1 = OpTypeStruct %_runtimearr_uint +%_ptr_Uniform_SSBO1 = OpTypePointer Uniform %SSBO1 + %_ = OpVariable %_ptr_Uniform_SSBO1 Uniform + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 +%_ptr_Input_v4float = OpTypePointer Input %v4float +%gl_FragCoord = OpVariable %_ptr_Input_v4float Input + %uint_0 = OpConstant %uint 0 +%_ptr_Input_float = OpTypePointer Input %float + %uint_1 = OpConstant %uint 1 +%_ptr_Uniform_uint = OpTypePointer Uniform %uint +%_runtimearr_uint_0 = OpTypeRuntimeArray %uint + %SSBO0 = OpTypeStruct %_runtimearr_uint_0 +%_ptr_Uniform_SSBO0 = OpTypePointer Uniform %SSBO0 + %__0 = OpVariable %_ptr_Uniform_SSBO0 Uniform + %main = OpFunction %void None %3 + %5 = OpLabel + %44 = OpFunctionCall %void %callee_ + OpReturn + OpFunctionEnd + %callee2_ = OpFunction %void None %3 + %7 = OpLabel + %23 = OpAccessChain %_ptr_Input_float %gl_FragCoord %uint_0 + %24 = OpLoad %float %23 + %25 = OpConvertFToS %int %24 + %28 = OpAccessChain %_ptr_Uniform_uint %_ %int_0 %25 + %29 = OpLoad %uint %28 + %30 = OpIAdd %uint %29 %uint_1 + %31 = OpAccessChain %_ptr_Uniform_uint %_ %int_0 %25 + OpStore %31 %30 + OpReturn + OpFunctionEnd + %callee_ = OpFunction %void None %3 + %9 = OpLabel + %36 = OpAccessChain %_ptr_Input_float %gl_FragCoord %uint_0 + %37 = OpLoad %float %36 + %38 = OpConvertFToS %int %37 + %39 = OpAccessChain %_ptr_Uniform_uint %__0 %int_0 %38 + %40 = OpLoad %uint %39 + %41 = OpIAdd %uint %40 %uint_1 + %42 = OpAccessChain %_ptr_Uniform_uint %__0 %int_0 %38 + OpStore %42 %41 + OpBeginInvocationInterlockEXT + %43 = OpFunctionCall %void %callee2_ + OpEndInvocationInterlockEXT + OpReturn + OpFunctionEnd diff --git a/third_party/spirv-cross/shaders-msl-no-opt/asm/frag/pixel-interlock-control-flow.msl2.asm.frag b/third_party/spirv-cross/shaders-msl-no-opt/asm/frag/pixel-interlock-control-flow.msl2.asm.frag new file mode 100644 index 0000000000..69b8f91120 --- /dev/null +++ b/third_party/spirv-cross/shaders-msl-no-opt/asm/frag/pixel-interlock-control-flow.msl2.asm.frag @@ -0,0 +1,121 @@ +; SPIR-V +; Version: 1.0 +; Generator: Khronos Glslang Reference Front End; 7 +; Bound: 45 +; Schema: 0 + OpCapability Shader + OpCapability FragmentShaderPixelInterlockEXT + OpExtension "SPV_EXT_fragment_shader_interlock" + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %gl_FragCoord + OpExecutionMode %main OriginUpperLeft + OpExecutionMode %main PixelInterlockOrderedEXT + OpSource GLSL 450 + OpSourceExtension "GL_ARB_fragment_shader_interlock" + OpName %main "main" + OpName %callee2_ "callee2(" + OpName %callee_ "callee(" + OpName %SSBO1 "SSBO1" + OpMemberName %SSBO1 0 "values1" + OpName %_ "" + OpName %gl_FragCoord "gl_FragCoord" + OpName %SSBO0 "SSBO0" + OpMemberName %SSBO0 0 "values0" + OpName %__0 "" + OpDecorate %_runtimearr_uint ArrayStride 4 + OpMemberDecorate %SSBO1 0 Offset 0 + OpDecorate %SSBO1 BufferBlock + OpDecorate %_ DescriptorSet 0 + OpDecorate %_ Binding 1 + OpDecorate %gl_FragCoord BuiltIn FragCoord + OpDecorate %_runtimearr_uint_0 ArrayStride 4 + OpMemberDecorate %SSBO0 0 Offset 0 + OpDecorate %SSBO0 BufferBlock + OpDecorate %__0 DescriptorSet 0 + OpDecorate %__0 Binding 0 + + OpMemberDecorate %SSBO2 0 Offset 0 + OpDecorate %SSBO2 BufferBlock + OpDecorate %ssbo2 DescriptorSet 0 + OpDecorate %ssbo2 Binding 2 + + %void = OpTypeVoid + %3 = OpTypeFunction %void + %uint = OpTypeInt 32 0 +%_runtimearr_uint = OpTypeRuntimeArray %uint + %SSBO1 = OpTypeStruct %_runtimearr_uint + %SSBO2 = OpTypeStruct %_runtimearr_uint +%_ptr_Uniform_SSBO1 = OpTypePointer Uniform %SSBO1 +%_ptr_Uniform_SSBO2 = OpTypePointer Uniform %SSBO2 + %_ = OpVariable %_ptr_Uniform_SSBO1 Uniform + %ssbo2 = OpVariable %_ptr_Uniform_SSBO2 Uniform + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 + %uint_4 = OpConstant %uint 4 + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 + %bool = OpTypeBool + %true = OpConstantTrue %bool +%_ptr_Input_v4float = OpTypePointer Input %v4float +%gl_FragCoord = OpVariable %_ptr_Input_v4float Input + %uint_0 = OpConstant %uint 0 +%_ptr_Input_float = OpTypePointer Input %float + %uint_1 = OpConstant %uint 1 +%_ptr_Uniform_uint = OpTypePointer Uniform %uint +%_runtimearr_uint_0 = OpTypeRuntimeArray %uint + %SSBO0 = OpTypeStruct %_runtimearr_uint_0 +%_ptr_Uniform_SSBO0 = OpTypePointer Uniform %SSBO0 + %__0 = OpVariable %_ptr_Uniform_SSBO0 Uniform + %main = OpFunction %void None %3 + %5 = OpLabel + %44 = OpFunctionCall %void %callee_ + %callee3_res = OpFunctionCall %void %callee3_ + OpReturn + OpFunctionEnd + + %callee3_ = OpFunction %void None %3 + %calle3_block = OpLabel + %frag_coord_x_ptr = OpAccessChain %_ptr_Input_float %gl_FragCoord %uint_0 + %frag_coord_x = OpLoad %float %frag_coord_x_ptr + %frag_coord_int = OpConvertFToS %int %frag_coord_x + %ssbo_ptr = OpAccessChain %_ptr_Uniform_uint %ssbo2 %int_0 %frag_coord_int + OpStore %ssbo_ptr %uint_4 + OpReturn + OpFunctionEnd + + %callee2_ = OpFunction %void None %3 + %7 = OpLabel + %23 = OpAccessChain %_ptr_Input_float %gl_FragCoord %uint_0 + %24 = OpLoad %float %23 + %25 = OpConvertFToS %int %24 + %28 = OpAccessChain %_ptr_Uniform_uint %_ %int_0 %25 + %29 = OpLoad %uint %28 + %30 = OpIAdd %uint %29 %uint_1 + %31 = OpAccessChain %_ptr_Uniform_uint %_ %int_0 %25 + OpStore %31 %30 + OpReturn + OpFunctionEnd + %callee_ = OpFunction %void None %3 + %9 = OpLabel + %36 = OpAccessChain %_ptr_Input_float %gl_FragCoord %uint_0 + %37 = OpLoad %float %36 + %38 = OpConvertFToS %int %37 + %39 = OpAccessChain %_ptr_Uniform_uint %__0 %int_0 %38 + %40 = OpLoad %uint %39 + %41 = OpIAdd %uint %40 %uint_1 + %42 = OpAccessChain %_ptr_Uniform_uint %__0 %int_0 %38 + OpStore %42 %41 + %43 = OpFunctionCall %void %callee2_ + + OpSelectionMerge %merged_block None + OpBranchConditional %true %dummy_block %merged_block + %dummy_block = OpLabel + OpBeginInvocationInterlockEXT + OpEndInvocationInterlockEXT + OpBranch %merged_block + + %merged_block = OpLabel + OpReturn + + OpFunctionEnd diff --git a/third_party/spirv-cross/shaders-msl-no-opt/asm/frag/pixel-interlock-split-functions.msl2.asm.frag b/third_party/spirv-cross/shaders-msl-no-opt/asm/frag/pixel-interlock-split-functions.msl2.asm.frag new file mode 100644 index 0000000000..7c0fe9a2b2 --- /dev/null +++ b/third_party/spirv-cross/shaders-msl-no-opt/asm/frag/pixel-interlock-split-functions.msl2.asm.frag @@ -0,0 +1,102 @@ +; SPIR-V +; Version: 1.0 +; Generator: Khronos Glslang Reference Front End; 7 +; Bound: 45 +; Schema: 0 + OpCapability Shader + OpCapability FragmentShaderPixelInterlockEXT + OpExtension "SPV_EXT_fragment_shader_interlock" + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %gl_FragCoord + OpExecutionMode %main OriginUpperLeft + OpExecutionMode %main PixelInterlockOrderedEXT + OpSource GLSL 450 + OpSourceExtension "GL_ARB_fragment_shader_interlock" + OpName %main "main" + OpName %callee2_ "callee2(" + OpName %callee_ "callee(" + OpName %SSBO1 "SSBO1" + OpMemberName %SSBO1 0 "values1" + OpName %_ "" + OpName %gl_FragCoord "gl_FragCoord" + OpName %SSBO0 "SSBO0" + OpMemberName %SSBO0 0 "values0" + OpName %__0 "" + OpDecorate %_runtimearr_uint ArrayStride 4 + OpMemberDecorate %SSBO1 0 Offset 0 + OpDecorate %SSBO1 BufferBlock + OpDecorate %_ DescriptorSet 0 + OpDecorate %_ Binding 1 + OpDecorate %gl_FragCoord BuiltIn FragCoord + OpDecorate %_runtimearr_uint_0 ArrayStride 4 + OpMemberDecorate %SSBO0 0 Offset 0 + OpDecorate %SSBO0 BufferBlock + OpDecorate %__0 DescriptorSet 0 + OpDecorate %__0 Binding 0 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %uint = OpTypeInt 32 0 +%_runtimearr_uint = OpTypeRuntimeArray %uint + %SSBO1 = OpTypeStruct %_runtimearr_uint +%_ptr_Uniform_SSBO1 = OpTypePointer Uniform %SSBO1 + %_ = OpVariable %_ptr_Uniform_SSBO1 Uniform + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 +%_ptr_Input_v4float = OpTypePointer Input %v4float +%gl_FragCoord = OpVariable %_ptr_Input_v4float Input + %uint_0 = OpConstant %uint 0 +%_ptr_Input_float = OpTypePointer Input %float + %uint_1 = OpConstant %uint 1 +%_ptr_Uniform_uint = OpTypePointer Uniform %uint +%_runtimearr_uint_0 = OpTypeRuntimeArray %uint + %SSBO0 = OpTypeStruct %_runtimearr_uint_0 +%_ptr_Uniform_SSBO0 = OpTypePointer Uniform %SSBO0 + %__0 = OpVariable %_ptr_Uniform_SSBO0 Uniform + %main = OpFunction %void None %3 + %5 = OpLabel + %44 = OpFunctionCall %void %callee_ + %call3res = OpFunctionCall %void %callee3_ + %call4res = OpFunctionCall %void %callee4_ + OpReturn + OpFunctionEnd + + %callee3_ = OpFunction %void None %3 + %begin3 = OpLabel + OpBeginInvocationInterlockEXT + OpReturn + OpFunctionEnd + + %callee4_ = OpFunction %void None %3 + %begin4 = OpLabel + OpEndInvocationInterlockEXT + OpReturn + OpFunctionEnd + + %callee2_ = OpFunction %void None %3 + %7 = OpLabel + %23 = OpAccessChain %_ptr_Input_float %gl_FragCoord %uint_0 + %24 = OpLoad %float %23 + %25 = OpConvertFToS %int %24 + %28 = OpAccessChain %_ptr_Uniform_uint %_ %int_0 %25 + %29 = OpLoad %uint %28 + %30 = OpIAdd %uint %29 %uint_1 + %31 = OpAccessChain %_ptr_Uniform_uint %_ %int_0 %25 + OpStore %31 %30 + OpReturn + OpFunctionEnd + %callee_ = OpFunction %void None %3 + %9 = OpLabel + %36 = OpAccessChain %_ptr_Input_float %gl_FragCoord %uint_0 + %37 = OpLoad %float %36 + %38 = OpConvertFToS %int %37 + %39 = OpAccessChain %_ptr_Uniform_uint %__0 %int_0 %38 + %40 = OpLoad %uint %39 + %41 = OpIAdd %uint %40 %uint_1 + %42 = OpAccessChain %_ptr_Uniform_uint %__0 %int_0 %38 + OpStore %42 %41 + %43 = OpFunctionCall %void %callee2_ + OpReturn + OpFunctionEnd diff --git a/third_party/spirv-cross/shaders-msl-no-opt/asm/frag/subgroup-arithmetic-cast.msl21.asm.frag b/third_party/spirv-cross/shaders-msl-no-opt/asm/frag/subgroup-arithmetic-cast.msl21.asm.frag new file mode 100644 index 0000000000..5f0734062d --- /dev/null +++ b/third_party/spirv-cross/shaders-msl-no-opt/asm/frag/subgroup-arithmetic-cast.msl21.asm.frag @@ -0,0 +1,65 @@ +; SPIR-V +; Version: 1.3 +; Generator: Khronos Glslang Reference Front End; 8 +; Bound: 78 +; Schema: 0 + OpCapability Shader + OpCapability GroupNonUniform + OpCapability GroupNonUniformArithmetic + OpCapability GroupNonUniformClustered + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %index %FragColor + OpExecutionMode %main OriginUpperLeft + OpSource GLSL 450 + OpSourceExtension "GL_KHR_shader_subgroup_arithmetic" + OpSourceExtension "GL_KHR_shader_subgroup_basic" + OpSourceExtension "GL_KHR_shader_subgroup_clustered" + OpName %main "main" + OpName %index "index" + OpName %FragColor "FragColor" + OpDecorate %index Flat + OpDecorate %index Location 0 + OpDecorate %FragColor Location 0 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %uint = OpTypeInt 32 0 +%_ptr_Function_uint = OpTypePointer Function %uint + %uint_0 = OpConstant %uint 0 + %int = OpTypeInt 32 1 +%_ptr_Input_int = OpTypePointer Input %int + %index = OpVariable %_ptr_Input_int Input + %uint_3 = OpConstant %uint 3 + %uint_4 = OpConstant %uint 4 +%_ptr_Output_uint = OpTypePointer Output %uint + %FragColor = OpVariable %_ptr_Output_uint Output + %main = OpFunction %void None %3 + %5 = OpLabel + %i = OpLoad %int %index + %u = OpBitcast %uint %i + %res0 = OpGroupNonUniformSMin %uint %uint_3 Reduce %i + %res1 = OpGroupNonUniformSMax %uint %uint_3 Reduce %u + %res2 = OpGroupNonUniformUMin %uint %uint_3 Reduce %i + %res3 = OpGroupNonUniformUMax %uint %uint_3 Reduce %u + ;%res4 = OpGroupNonUniformSMax %uint %uint_3 InclusiveScan %i + ;%res5 = OpGroupNonUniformSMin %uint %uint_3 InclusiveScan %u + ;%res6 = OpGroupNonUniformUMax %uint %uint_3 ExclusiveScan %i + ;%res7 = OpGroupNonUniformUMin %uint %uint_3 ExclusiveScan %u + %res8 = OpGroupNonUniformSMin %uint %uint_3 ClusteredReduce %i %uint_4 + %res9 = OpGroupNonUniformSMax %uint %uint_3 ClusteredReduce %u %uint_4 + %res10 = OpGroupNonUniformUMin %uint %uint_3 ClusteredReduce %i %uint_4 + %res11 = OpGroupNonUniformUMax %uint %uint_3 ClusteredReduce %u %uint_4 + OpStore %FragColor %res0 + OpStore %FragColor %res1 + OpStore %FragColor %res2 + OpStore %FragColor %res3 + ;OpStore %FragColor %res4 + ;OpStore %FragColor %res5 + ;OpStore %FragColor %res6 + ;OpStore %FragColor %res7 + OpStore %FragColor %res8 + OpStore %FragColor %res9 + OpStore %FragColor %res10 + OpStore %FragColor %res11 + OpReturn + OpFunctionEnd diff --git a/third_party/spirv-cross/shaders-msl-no-opt/asm/frag/switch-block-case-fallthrough.asm.frag b/third_party/spirv-cross/shaders-msl-no-opt/asm/frag/switch-block-case-fallthrough.asm.invalid.frag similarity index 100% rename from third_party/spirv-cross/shaders-msl-no-opt/asm/frag/switch-block-case-fallthrough.asm.frag rename to third_party/spirv-cross/shaders-msl-no-opt/asm/frag/switch-block-case-fallthrough.asm.invalid.frag diff --git a/third_party/spirv-cross/shaders-msl/asm/tesc/tess-fixed-input-array-builtin-array.invalid.asm.tesc b/third_party/spirv-cross/shaders-msl-no-opt/asm/tesc/tess-fixed-input-array-builtin-array.invalid.asm.tesc similarity index 100% rename from third_party/spirv-cross/shaders-msl/asm/tesc/tess-fixed-input-array-builtin-array.invalid.asm.tesc rename to third_party/spirv-cross/shaders-msl-no-opt/asm/tesc/tess-fixed-input-array-builtin-array.invalid.asm.tesc diff --git a/third_party/spirv-cross/shaders-msl-no-opt/comp/array-copy-threadgroup-memory.comp b/third_party/spirv-cross/shaders-msl-no-opt/comp/array-copy-threadgroup-memory.comp new file mode 100644 index 0000000000..081c39626d --- /dev/null +++ b/third_party/spirv-cross/shaders-msl-no-opt/comp/array-copy-threadgroup-memory.comp @@ -0,0 +1,18 @@ +#version 450 +layout(local_size_x = 8) in; + +shared float shared_group[8][8]; +shared float shared_group_alt[8][8]; + +void main() +{ + float blob[8]; + for (int i = 0; i < 8; i++) + blob[i] = float(i); + shared_group[gl_LocalInvocationIndex] = blob; + + barrier(); + + float copied_blob[8] = shared_group[gl_LocalInvocationIndex ^ 1u]; + shared_group_alt[gl_LocalInvocationIndex] = shared_group[gl_LocalInvocationIndex]; +} diff --git a/third_party/spirv-cross/shaders-msl-no-opt/comp/basic.dynamic-buffer.msl2.invalid.comp b/third_party/spirv-cross/shaders-msl-no-opt/comp/basic.dynamic-buffer.msl2.invalid.comp new file mode 100644 index 0000000000..c2965731e9 --- /dev/null +++ b/third_party/spirv-cross/shaders-msl-no-opt/comp/basic.dynamic-buffer.msl2.invalid.comp @@ -0,0 +1,27 @@ +#version 450 +layout(local_size_x = 3, local_size_y = 3, local_size_z = 2) in; + +layout(set = 0, binding = 0) uniform Foo +{ + int a; + int b; +}; + +layout(set = 0, binding = 1) uniform Bar +{ + int c; + int d; +}; + +layout(set = 1, binding = 2) buffer Baz +{ + int e; + int f; +} baz[3][3][2]; + +void main() +{ + uvec3 coords = gl_GlobalInvocationID; + baz[coords.x][coords.y][coords.z].e = a + c; + baz[coords.x][coords.y][coords.z].f = b * d; +} diff --git a/third_party/spirv-cross/shaders-msl/comp/bitcast-16bit-1.invalid.comp b/third_party/spirv-cross/shaders-msl-no-opt/comp/bitcast-16bit-1.invalid.comp similarity index 100% rename from third_party/spirv-cross/shaders-msl/comp/bitcast-16bit-1.invalid.comp rename to third_party/spirv-cross/shaders-msl-no-opt/comp/bitcast-16bit-1.invalid.comp diff --git a/third_party/spirv-cross/shaders-msl/comp/bitcast-16bit-2.invalid.comp b/third_party/spirv-cross/shaders-msl-no-opt/comp/bitcast-16bit-2.invalid.comp similarity index 100% rename from third_party/spirv-cross/shaders-msl/comp/bitcast-16bit-2.invalid.comp rename to third_party/spirv-cross/shaders-msl-no-opt/comp/bitcast-16bit-2.invalid.comp diff --git a/third_party/spirv-cross/shaders-msl-no-opt/comp/illegal-struct-name.asm.comp b/third_party/spirv-cross/shaders-msl-no-opt/comp/illegal-struct-name.asm.comp new file mode 100644 index 0000000000..f7a8787d3d --- /dev/null +++ b/third_party/spirv-cross/shaders-msl-no-opt/comp/illegal-struct-name.asm.comp @@ -0,0 +1,62 @@ +; SPIR-V +; Version: 1.0 +; Generator: Khronos Glslang Reference Front End; 8 +; Bound: 31 +; Schema: 0 + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" + OpExecutionMode %main LocalSize 1 1 1 + OpSource GLSL 450 + OpName %main "main" + OpName %Foo "Foo" + OpMemberName %Foo 0 "abs" + OpName %f "f" + OpName %Foo_0 "Foo" + OpMemberName %Foo_0 0 "abs" + OpName %SSBO "SSBO" + OpMemberName %SSBO 0 "foo" + OpMemberName %SSBO 1 "foo2" + OpName %_ "" + OpName %linear "abs" + OpMemberDecorate %Foo_0 0 Offset 0 + OpMemberDecorate %SSBO 0 Offset 0 + OpMemberDecorate %SSBO 1 Offset 4 + OpDecorate %SSBO BufferBlock + OpDecorate %_ DescriptorSet 0 + OpDecorate %_ Binding 0 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %Foo = OpTypeStruct %float +%_ptr_Function_Foo = OpTypePointer Function %Foo + %Foo_0 = OpTypeStruct %float + %SSBO = OpTypeStruct %Foo_0 %Foo_0 +%_ptr_Uniform_SSBO = OpTypePointer Uniform %SSBO + %_ = OpVariable %_ptr_Uniform_SSBO Uniform + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 +%_ptr_Uniform_Foo_0 = OpTypePointer Uniform %Foo_0 +%_ptr_Function_float = OpTypePointer Function %float +%_ptr_Function_int = OpTypePointer Function %int + %int_10 = OpConstant %int 10 + %int_1 = OpConstant %int 1 +%_ptr_Uniform_float = OpTypePointer Uniform %float + %main = OpFunction %void None %3 + %5 = OpLabel + %f = OpVariable %_ptr_Function_Foo Function + %linear = OpVariable %_ptr_Function_int Function + %17 = OpAccessChain %_ptr_Uniform_Foo_0 %_ %int_0 + %18 = OpLoad %Foo_0 %17 + %19 = OpCompositeExtract %float %18 0 + %21 = OpAccessChain %_ptr_Function_float %f %int_0 + OpStore %21 %19 + OpStore %linear %int_10 + %26 = OpLoad %Foo %f + %27 = OpAccessChain %_ptr_Uniform_Foo_0 %_ %int_1 + %28 = OpCompositeExtract %float %26 0 + %30 = OpAccessChain %_ptr_Uniform_float %27 %int_0 + OpStore %30 %28 + OpReturn + OpFunctionEnd diff --git a/third_party/spirv-cross/shaders-msl/comp/int64.invalid.msl22.comp b/third_party/spirv-cross/shaders-msl-no-opt/comp/int64.invalid.msl22.comp similarity index 100% rename from third_party/spirv-cross/shaders-msl/comp/int64.invalid.msl22.comp rename to third_party/spirv-cross/shaders-msl-no-opt/comp/int64.invalid.msl22.comp diff --git a/third_party/spirv-cross/shaders-msl-no-opt/comp/std140-array-load-composite-construct.comp b/third_party/spirv-cross/shaders-msl-no-opt/comp/std140-array-load-composite-construct.comp new file mode 100644 index 0000000000..af1c47b32c --- /dev/null +++ b/third_party/spirv-cross/shaders-msl-no-opt/comp/std140-array-load-composite-construct.comp @@ -0,0 +1,13 @@ +#version 450 +layout(local_size_x = 1) in; + +layout(std140, binding = 0) buffer SSBO +{ + float a[16]; + vec4 b[16]; +}; + +void main() +{ + b[gl_GlobalInvocationID.x] = vec4(a[gl_GlobalInvocationID.x]); +} diff --git a/third_party/spirv-cross/shaders-msl/vulkan/comp/struct-packing-scalar.nocompat.invalid.vk.comp b/third_party/spirv-cross/shaders-msl-no-opt/comp/struct-packing-scalar.nocompat.invalid.vk.comp similarity index 100% rename from third_party/spirv-cross/shaders-msl/vulkan/comp/struct-packing-scalar.nocompat.invalid.vk.comp rename to third_party/spirv-cross/shaders-msl-no-opt/comp/struct-packing-scalar.nocompat.invalid.vk.comp diff --git a/third_party/spirv-cross/shaders-msl/vulkan/comp/subgroups.nocompat.invalid.vk.msl21.comp b/third_party/spirv-cross/shaders-msl-no-opt/comp/subgroups.nocompat.invalid.vk.msl21.comp similarity index 100% rename from third_party/spirv-cross/shaders-msl/vulkan/comp/subgroups.nocompat.invalid.vk.msl21.comp rename to third_party/spirv-cross/shaders-msl-no-opt/comp/subgroups.nocompat.invalid.vk.msl21.comp diff --git a/third_party/spirv-cross/shaders-msl/vulkan/comp/subgroups.nocompat.invalid.vk.msl21.ios.comp b/third_party/spirv-cross/shaders-msl-no-opt/comp/subgroups.nocompat.invalid.vk.msl21.ios.comp similarity index 100% rename from third_party/spirv-cross/shaders-msl/vulkan/comp/subgroups.nocompat.invalid.vk.msl21.ios.comp rename to third_party/spirv-cross/shaders-msl-no-opt/comp/subgroups.nocompat.invalid.vk.msl21.ios.comp diff --git a/third_party/spirv-cross/shaders-msl-no-opt/components/fragment-input-component.frag b/third_party/spirv-cross/shaders-msl-no-opt/components/fragment-input-component.frag new file mode 100644 index 0000000000..60d48bef7e --- /dev/null +++ b/third_party/spirv-cross/shaders-msl-no-opt/components/fragment-input-component.frag @@ -0,0 +1,10 @@ +#version 450 + +layout(location = 0, component = 3) in float Foo1; +layout(location = 0, component = 0) in vec3 Foo3; +layout(location = 0) out vec4 FragColor; + +void main() +{ + FragColor = vec4(Foo3, Foo1); +} diff --git a/third_party/spirv-cross/shaders-msl-no-opt/components/fragment-output-component.frag b/third_party/spirv-cross/shaders-msl-no-opt/components/fragment-output-component.frag new file mode 100644 index 0000000000..29a57dfa1f --- /dev/null +++ b/third_party/spirv-cross/shaders-msl-no-opt/components/fragment-output-component.frag @@ -0,0 +1,12 @@ +#version 450 + +layout(location = 0, component = 0) out float FragColor0; +layout(location = 0, component = 1) out vec2 FragColor1; +layout(location = 0, component = 3) out float FragColor3; + +void main() +{ + FragColor0 = 1.0; + FragColor1 = vec2(2.0, 3.0); + FragColor3 = 4.0; +} diff --git a/third_party/spirv-cross/shaders-msl-no-opt/components/fragment-output-component.pad-fragment.frag b/third_party/spirv-cross/shaders-msl-no-opt/components/fragment-output-component.pad-fragment.frag new file mode 100644 index 0000000000..ae9b7f75e7 --- /dev/null +++ b/third_party/spirv-cross/shaders-msl-no-opt/components/fragment-output-component.pad-fragment.frag @@ -0,0 +1,10 @@ +#version 450 + +layout(location = 0, component = 0) out float FragColor0; +layout(location = 0, component = 1) out vec2 FragColor1; + +void main() +{ + FragColor0 = 1.0; + FragColor1 = vec2(2.0, 3.0); +} diff --git a/third_party/spirv-cross/shaders-msl-no-opt/components/vertex-input-component.vert b/third_party/spirv-cross/shaders-msl-no-opt/components/vertex-input-component.vert new file mode 100644 index 0000000000..7ba31bf655 --- /dev/null +++ b/third_party/spirv-cross/shaders-msl-no-opt/components/vertex-input-component.vert @@ -0,0 +1,11 @@ +#version 450 + +layout(location = 0, component = 0) in vec3 Foo3; +layout(location = 0, component = 3) in float Foo1; +layout(location = 0) out vec3 Foo; + +void main() +{ + gl_Position = vec4(Foo3, Foo1); + Foo = Foo3 + Foo1; +} diff --git a/third_party/spirv-cross/shaders-msl-no-opt/components/vertex-output-component.vert b/third_party/spirv-cross/shaders-msl-no-opt/components/vertex-output-component.vert new file mode 100644 index 0000000000..5abd8dc6ff --- /dev/null +++ b/third_party/spirv-cross/shaders-msl-no-opt/components/vertex-output-component.vert @@ -0,0 +1,12 @@ +#version 450 + +layout(location = 0) in vec4 vFoo; +layout(location = 0) out vec3 Foo3; +layout(location = 0, component = 3) out float Foo1; + +void main() +{ + gl_Position = vFoo; + Foo3 = vFoo.xyz; + Foo1 = vFoo.w; +} diff --git a/third_party/spirv-cross/shaders-msl/frag/16bit-constants.invalid.frag b/third_party/spirv-cross/shaders-msl-no-opt/frag/16bit-constants.invalid.frag similarity index 100% rename from third_party/spirv-cross/shaders-msl/frag/16bit-constants.invalid.frag rename to third_party/spirv-cross/shaders-msl-no-opt/frag/16bit-constants.invalid.frag diff --git a/third_party/spirv-cross/shaders-msl/vulkan/frag/demote-to-helper.vk.nocompat.msl21.invalid.frag b/third_party/spirv-cross/shaders-msl-no-opt/frag/demote-to-helper.vk.nocompat.msl21.invalid.frag similarity index 100% rename from third_party/spirv-cross/shaders-msl/vulkan/frag/demote-to-helper.vk.nocompat.msl21.invalid.frag rename to third_party/spirv-cross/shaders-msl-no-opt/frag/demote-to-helper.vk.nocompat.msl21.invalid.frag diff --git a/third_party/spirv-cross/shaders-msl-no-opt/frag/force-active-resources.msl2.argument..force-active.discrete.frag b/third_party/spirv-cross/shaders-msl-no-opt/frag/force-active-resources.msl2.argument..force-active.discrete.frag new file mode 100644 index 0000000000..b1b058d014 --- /dev/null +++ b/third_party/spirv-cross/shaders-msl-no-opt/frag/force-active-resources.msl2.argument..force-active.discrete.frag @@ -0,0 +1,15 @@ +#version 450 + +layout(location = 0) in vec2 vUV; +layout(location = 0) out vec4 FragColor; + +layout(set = 0, binding = 0) uniform sampler2D uTexture1; +layout(set = 0, binding = 1) uniform sampler2D uTexture2; +layout(set = 2, binding = 0) uniform sampler2D uTextureDiscrete1; +layout(set = 2, binding = 1) uniform sampler2D uTextureDiscrete2; + +void main() +{ + FragColor = texture(uTexture2, vUV); + FragColor += texture(uTextureDiscrete2, vUV); +} diff --git a/third_party/spirv-cross/shaders-msl/frag/fp16.desktop.invalid.frag b/third_party/spirv-cross/shaders-msl-no-opt/frag/fp16.desktop.invalid.frag similarity index 100% rename from third_party/spirv-cross/shaders-msl/frag/fp16.desktop.invalid.frag rename to third_party/spirv-cross/shaders-msl-no-opt/frag/fp16.desktop.invalid.frag diff --git a/third_party/spirv-cross/shaders-msl/asm/frag/min-max-clamp.invalid.asm.frag b/third_party/spirv-cross/shaders-msl-no-opt/frag/min-max-clamp.invalid.asm.frag similarity index 100% rename from third_party/spirv-cross/shaders-msl/asm/frag/min-max-clamp.invalid.asm.frag rename to third_party/spirv-cross/shaders-msl-no-opt/frag/min-max-clamp.invalid.asm.frag diff --git a/third_party/spirv-cross/shaders-msl-no-opt/frag/pixel-interlock-simple-callstack.msl2.frag b/third_party/spirv-cross/shaders-msl-no-opt/frag/pixel-interlock-simple-callstack.msl2.frag new file mode 100644 index 0000000000..59079fe58b --- /dev/null +++ b/third_party/spirv-cross/shaders-msl-no-opt/frag/pixel-interlock-simple-callstack.msl2.frag @@ -0,0 +1,31 @@ +#version 450 +#extension GL_ARB_fragment_shader_interlock : require +layout(pixel_interlock_ordered) in; + +layout(set = 0, binding = 0, std430) buffer SSBO0 +{ + uint values0[]; +}; + +layout(set = 0, binding = 1, std430) buffer SSBO1 +{ + uint values1[]; +}; + +void callee2() +{ + values1[int(gl_FragCoord.x)] += 1; +} + +void callee() +{ + values0[int(gl_FragCoord.x)] += 1; + callee2(); +} + +void main() +{ + beginInvocationInterlockARB(); + callee(); + endInvocationInterlockARB(); +} diff --git a/third_party/spirv-cross/shaders-msl/vulkan/frag/scalar-block-layout-ubo-std430.vk.nocompat.invalid.frag b/third_party/spirv-cross/shaders-msl-no-opt/frag/scalar-block-layout-ubo-std430.vk.nocompat.invalid.frag similarity index 100% rename from third_party/spirv-cross/shaders-msl/vulkan/frag/scalar-block-layout-ubo-std430.vk.nocompat.invalid.frag rename to third_party/spirv-cross/shaders-msl-no-opt/frag/scalar-block-layout-ubo-std430.vk.nocompat.invalid.frag diff --git a/third_party/spirv-cross/shaders-msl/frag/shadow-compare-global-alias.invalid.frag b/third_party/spirv-cross/shaders-msl-no-opt/frag/shadow-compare-global-alias.invalid.frag similarity index 100% rename from third_party/spirv-cross/shaders-msl/frag/shadow-compare-global-alias.invalid.frag rename to third_party/spirv-cross/shaders-msl-no-opt/frag/shadow-compare-global-alias.invalid.frag diff --git a/third_party/spirv-cross/shaders-msl/vulkan/frag/subgroups.nocompat.invalid.vk.msl21.frag b/third_party/spirv-cross/shaders-msl-no-opt/frag/subgroups.nocompat.invalid.vk.msl21.frag similarity index 100% rename from third_party/spirv-cross/shaders-msl/vulkan/frag/subgroups.nocompat.invalid.vk.msl21.frag rename to third_party/spirv-cross/shaders-msl-no-opt/frag/subgroups.nocompat.invalid.vk.msl21.frag diff --git a/third_party/spirv-cross/shaders-msl-no-opt/packing/array-of-vec3.comp b/third_party/spirv-cross/shaders-msl-no-opt/packing/array-of-vec3.comp new file mode 100644 index 0000000000..6157212222 --- /dev/null +++ b/third_party/spirv-cross/shaders-msl-no-opt/packing/array-of-vec3.comp @@ -0,0 +1,13 @@ +#version 450 +#extension GL_EXT_scalar_block_layout : require +layout(local_size_x = 1) in; + +layout(set = 0, binding = 0, scalar) buffer SSBO +{ + vec3 v[16]; +}; + +void main() +{ + v[1] = v[0]; +} diff --git a/third_party/spirv-cross/shaders-msl-no-opt/packing/array-of-vec4.comp b/third_party/spirv-cross/shaders-msl-no-opt/packing/array-of-vec4.comp new file mode 100644 index 0000000000..c5bf5e8a3f --- /dev/null +++ b/third_party/spirv-cross/shaders-msl-no-opt/packing/array-of-vec4.comp @@ -0,0 +1,13 @@ +#version 450 +#extension GL_EXT_scalar_block_layout : require +layout(local_size_x = 1) in; + +layout(set = 0, binding = 0, scalar) buffer SSBO +{ + vec4 v[16]; +}; + +void main() +{ + v[1] = v[0]; +} diff --git a/third_party/spirv-cross/shaders-msl-no-opt/packing/load-store-col-rows.comp b/third_party/spirv-cross/shaders-msl-no-opt/packing/load-store-col-rows.comp new file mode 100644 index 0000000000..b3f2897034 --- /dev/null +++ b/third_party/spirv-cross/shaders-msl-no-opt/packing/load-store-col-rows.comp @@ -0,0 +1,59 @@ +#version 450 +#extension GL_EXT_scalar_block_layout : require +layout(local_size_x = 1) in; + +layout(binding = 0, std140) buffer SSBO1 +{ + mat2 a; + layout(row_major) mat2 a2; +}; + +layout(scalar, binding = 1) buffer SSBO2 +{ + mat2x3 b; + layout(row_major) mat3x2 b2; +}; + +void load_store_column() +{ + vec2 u = a[0]; + vec2 v = a[1]; + u += v; + a[0] = u; + a[1] = v; +} + +void load_store_row() +{ + vec2 u = a2[0]; + vec2 v = a2[1]; + u += v; + a2[0] = u; + a2[1] = v; +} + +void load_store_packed_column() +{ + vec3 u = b[0]; + vec3 v = b[1]; + u += v; + b[0] = u; + b[1] = v; +} + +void load_store_packed_row() +{ + vec2 u = b2[0]; + vec2 v = b2[1]; + u += v; + b2[0] = u; + b2[1] = v; +} + +void main() +{ + load_store_column(); + load_store_row(); + load_store_packed_column(); + load_store_packed_row(); +} diff --git a/third_party/spirv-cross/shaders-msl/vert/layer.msl11.invalid.vert b/third_party/spirv-cross/shaders-msl-no-opt/vert/layer.msl11.invalid.vert similarity index 100% rename from third_party/spirv-cross/shaders-msl/vert/layer.msl11.invalid.vert rename to third_party/spirv-cross/shaders-msl-no-opt/vert/layer.msl11.invalid.vert diff --git a/third_party/spirv-cross/shaders-msl-no-opt/vert/pass-array-by-value.force-native-array.vert b/third_party/spirv-cross/shaders-msl-no-opt/vert/pass-array-by-value.force-native-array.vert new file mode 100644 index 0000000000..2c142a7810 --- /dev/null +++ b/third_party/spirv-cross/shaders-msl-no-opt/vert/pass-array-by-value.force-native-array.vert @@ -0,0 +1,26 @@ +#version 310 es + +layout(location = 0) in int Index1; +layout(location = 1) in int Index2; + +vec4 consume_constant_arrays2(const vec4 positions[4], const vec4 positions2[4]) +{ + return positions[Index1] + positions2[Index2]; +} + +vec4 consume_constant_arrays(const vec4 positions[4], const vec4 positions2[4]) +{ + return consume_constant_arrays2(positions, positions2); +} + +const vec4 LUT1[] = vec4[](vec4(0.0), vec4(1.0), vec4(2.0), vec4(3.0)); + +void main() +{ + vec4 LUT2[4]; + LUT2[0] = vec4(10.0); + LUT2[1] = vec4(11.0); + LUT2[2] = vec4(12.0); + LUT2[3] = vec4(13.0); + gl_Position = consume_constant_arrays(LUT1, LUT2); +} diff --git a/third_party/spirv-cross/shaders-msl/vert/viewport-index.msl2.invalid.vert b/third_party/spirv-cross/shaders-msl-no-opt/vert/viewport-index.msl2.invalid.vert similarity index 100% rename from third_party/spirv-cross/shaders-msl/vert/viewport-index.msl2.invalid.vert rename to third_party/spirv-cross/shaders-msl-no-opt/vert/viewport-index.msl2.invalid.vert diff --git a/third_party/spirv-cross/shaders-msl/asm/comp/bitcast_icmp.asm.comp b/third_party/spirv-cross/shaders-msl/asm/comp/bitcast_icmp.asm.comp new file mode 100644 index 0000000000..b7b4e0b2e1 --- /dev/null +++ b/third_party/spirv-cross/shaders-msl/asm/comp/bitcast_icmp.asm.comp @@ -0,0 +1,101 @@ +; SPIR-V +; Version: 1.0 +; Generator: Khronos Glslang Reference Front End; 1 +; Bound: 30 +; Schema: 0 + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %func "main" + OpExecutionMode %func LocalSize 1 1 1 + OpSource ESSL 310 + OpSourceExtension "GL_GOOGLE_cpp_style_line_directive" + OpSourceExtension "GL_GOOGLE_include_directive" + OpMemberDecorate %input_struct 0 Offset 0 + OpMemberDecorate %input_struct 1 Offset 16 + OpMemberDecorate %output_struct 0 Offset 0 + OpMemberDecorate %output_struct 1 Offset 16 + OpDecorate %input_struct BufferBlock + OpDecorate %inputs DescriptorSet 0 + OpDecorate %inputs Binding 0 + OpDecorate %inputs Restrict + OpDecorate %output_struct BufferBlock + OpDecorate %outputs DescriptorSet 0 + OpDecorate %outputs Binding 1 + OpDecorate %outputs Restrict + + %void = OpTypeVoid + %main_func = OpTypeFunction %void + + %bool = OpTypeBool + %bvec4 = OpTypeVector %bool 4 + + %uint = OpTypeInt 32 0 + %uvec4 = OpTypeVector %uint 4 + + %int = OpTypeInt 32 1 + %ivec4 = OpTypeVector %int 4 + + %ivec4_ptr = OpTypePointer Uniform %ivec4 + %uvec4_ptr = OpTypePointer Uniform %uvec4 + + %zero = OpConstant %int 0 + %one = OpConstant %int 1 + %uzero = OpConstant %uint 0 + %uone = OpConstant %uint 1 + %utrue = OpConstantComposite %uvec4 %uone %uone %uone %uone + %ufalse = OpConstantComposite %uvec4 %uzero %uzero %uzero %uzero + + %input_struct = OpTypeStruct %ivec4 %uvec4 + %input_struct_ptr = OpTypePointer Uniform %input_struct + %inputs = OpVariable %input_struct_ptr Uniform + %output_struct = OpTypeStruct %uvec4 %ivec4 + %output_struct_ptr = OpTypePointer Uniform %output_struct + %outputs = OpVariable %output_struct_ptr Uniform + + %func = OpFunction %void None %main_func + %block = OpLabel + + %input1_ptr = OpAccessChain %ivec4_ptr %inputs %zero + %input0_ptr = OpAccessChain %uvec4_ptr %inputs %one + %input1 = OpLoad %ivec4 %input1_ptr + %input0 = OpLoad %uvec4 %input0_ptr + + %output_ptr_uvec4 = OpAccessChain %uvec4_ptr %outputs %zero + + %result_slt = OpSLessThan %bvec4 %input0 %input1 + %result_sle = OpSLessThanEqual %bvec4 %input0 %input1 + %result_ult = OpULessThan %bvec4 %input0 %input1 + %result_ule = OpULessThanEqual %bvec4 %input0 %input1 + %result_sgt = OpSGreaterThan %bvec4 %input0 %input1 + %result_sge = OpSGreaterThanEqual %bvec4 %input0 %input1 + %result_ugt = OpUGreaterThan %bvec4 %input0 %input1 + %result_uge = OpUGreaterThanEqual %bvec4 %input0 %input1 + + %int_slt = OpSelect %uvec4 %result_slt %utrue %ufalse + OpStore %output_ptr_uvec4 %int_slt + + %int_sle = OpSelect %uvec4 %result_sle %utrue %ufalse + OpStore %output_ptr_uvec4 %int_sle + + %int_ult = OpSelect %uvec4 %result_ult %utrue %ufalse + OpStore %output_ptr_uvec4 %int_ult + + %int_ule = OpSelect %uvec4 %result_ule %utrue %ufalse + OpStore %output_ptr_uvec4 %int_ule + + %int_sgt = OpSelect %uvec4 %result_sgt %utrue %ufalse + OpStore %output_ptr_uvec4 %int_sgt + + %int_sge = OpSelect %uvec4 %result_sge %utrue %ufalse + OpStore %output_ptr_uvec4 %int_sge + + %int_ugt = OpSelect %uvec4 %result_ugt %utrue %ufalse + OpStore %output_ptr_uvec4 %int_ugt + + %int_uge = OpSelect %uvec4 %result_uge %utrue %ufalse + OpStore %output_ptr_uvec4 %int_uge + + + OpReturn + OpFunctionEnd diff --git a/third_party/spirv-cross/shaders-msl/asm/vert/clip-distance-plain-variable.asm.vert b/third_party/spirv-cross/shaders-msl/asm/vert/clip-distance-plain-variable.asm.vert new file mode 100644 index 0000000000..59ec3f9198 --- /dev/null +++ b/third_party/spirv-cross/shaders-msl/asm/vert/clip-distance-plain-variable.asm.vert @@ -0,0 +1,91 @@ +; SPIR-V +; Version: 1.0 +; Generator: Khronos Glslang Reference Front End; 8 +; Bound: 56 +; Schema: 0 + OpCapability Shader + OpCapability ClipDistance + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %main "main" %pos_1 %_entryPointOutput_pos %_entryPointOutput_clip + OpSource HLSL 500 + OpName %main "main" + OpName %VSOut "VSOut" + OpMemberName %VSOut 0 "pos" + OpMemberName %VSOut 1 "clip" + OpName %_main_vf4_ "@main(vf4;" + OpName %pos "pos" + OpName %vout "vout" + OpName %pos_0 "pos" + OpName %pos_1 "pos" + OpName %flattenTemp "flattenTemp" + OpName %param "param" + OpName %_entryPointOutput_pos "@entryPointOutput.pos" + OpName %_entryPointOutput_clip "@entryPointOutput.clip" + OpDecorate %pos_1 Location 0 + OpDecorate %_entryPointOutput_pos BuiltIn Position + OpDecorate %_entryPointOutput_clip BuiltIn ClipDistance + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 +%_ptr_Function_v4float = OpTypePointer Function %v4float + %v2float = OpTypeVector %float 2 + %VSOut = OpTypeStruct %v4float %v2float + %11 = OpTypeFunction %VSOut %_ptr_Function_v4float +%_ptr_Function_VSOut = OpTypePointer Function %VSOut + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 + %int_1 = OpConstant %int 1 +%_ptr_Function_v2float = OpTypePointer Function %v2float +%_ptr_Input_v4float = OpTypePointer Input %v4float + %pos_1 = OpVariable %_ptr_Input_v4float Input +%_ptr_Output_v4float = OpTypePointer Output %v4float +%_entryPointOutput_pos = OpVariable %_ptr_Output_v4float Output + %uint = OpTypeInt 32 0 + %uint_2 = OpConstant %uint 2 +%_arr_float_uint_2 = OpTypeArray %float %uint_2 +%_ptr_Output__arr_float_uint_2 = OpTypePointer Output %_arr_float_uint_2 +%_entryPointOutput_clip = OpVariable %_ptr_Output__arr_float_uint_2 Output + %uint_0 = OpConstant %uint 0 +%_ptr_Function_float = OpTypePointer Function %float +%_ptr_Output_float = OpTypePointer Output %float + %uint_1 = OpConstant %uint 1 + %main = OpFunction %void None %3 + %5 = OpLabel + %pos_0 = OpVariable %_ptr_Function_v4float Function +%flattenTemp = OpVariable %_ptr_Function_VSOut Function + %param = OpVariable %_ptr_Function_v4float Function + %32 = OpLoad %v4float %pos_1 + OpStore %pos_0 %32 + %35 = OpLoad %v4float %pos_0 + OpStore %param %35 + %36 = OpFunctionCall %VSOut %_main_vf4_ %param + OpStore %flattenTemp %36 + %39 = OpAccessChain %_ptr_Function_v4float %flattenTemp %int_0 + %40 = OpLoad %v4float %39 + OpStore %_entryPointOutput_pos %40 + %48 = OpAccessChain %_ptr_Function_float %flattenTemp %int_1 %uint_0 + %49 = OpLoad %float %48 + %51 = OpAccessChain %_ptr_Output_float %_entryPointOutput_clip %int_0 + OpStore %51 %49 + %53 = OpAccessChain %_ptr_Function_float %flattenTemp %int_1 %uint_1 + %54 = OpLoad %float %53 + %55 = OpAccessChain %_ptr_Output_float %_entryPointOutput_clip %int_1 + OpStore %55 %54 + OpReturn + OpFunctionEnd + %_main_vf4_ = OpFunction %VSOut None %11 + %pos = OpFunctionParameter %_ptr_Function_v4float + %14 = OpLabel + %vout = OpVariable %_ptr_Function_VSOut Function + %19 = OpLoad %v4float %pos + %20 = OpAccessChain %_ptr_Function_v4float %vout %int_0 + OpStore %20 %19 + %22 = OpLoad %v4float %pos + %23 = OpVectorShuffle %v2float %22 %22 0 1 + %25 = OpAccessChain %_ptr_Function_v2float %vout %int_1 + OpStore %25 %23 + %26 = OpLoad %VSOut %vout + OpReturnValue %26 + OpFunctionEnd diff --git a/third_party/spirv-cross/shaders-msl/comp/argument-buffers-image-load-store.ios.msl2.argument.comp b/third_party/spirv-cross/shaders-msl/comp/argument-buffers-image-load-store.ios.msl2.argument.comp new file mode 100644 index 0000000000..72ca8899ad --- /dev/null +++ b/third_party/spirv-cross/shaders-msl/comp/argument-buffers-image-load-store.ios.msl2.argument.comp @@ -0,0 +1,10 @@ +#version 450 + +layout(set = 0, binding = 1, r32f) writeonly uniform image2D uImage; +layout(set = 0, binding = 2, r32f) readonly uniform image2D uImageRead; + +void main() +{ + ivec2 coord = ivec2(gl_GlobalInvocationID.xy); + imageStore(uImage, coord, imageLoad(uImageRead, coord)); +} diff --git a/third_party/spirv-cross/shaders-msl/comp/basic.dispatchbase.comp b/third_party/spirv-cross/shaders-msl/comp/basic.dispatchbase.comp new file mode 100644 index 0000000000..2c873468cc --- /dev/null +++ b/third_party/spirv-cross/shaders-msl/comp/basic.dispatchbase.comp @@ -0,0 +1,29 @@ +#version 310 es +layout(local_size_x_id = 10) in; + +layout(std430, binding = 0) readonly buffer SSBO +{ + vec4 in_data[]; +}; + +layout(std430, binding = 1) writeonly buffer SSBO2 +{ + vec4 out_data[]; +}; + +layout(std430, binding = 2) buffer SSBO3 +{ + uint counter; +}; + +void main() +{ + uint ident = gl_GlobalInvocationID.x; + uint workgroup = gl_WorkGroupID.x; + vec4 idata = in_data[ident]; + if (dot(idata, vec4(1.0, 5.0, 6.0, 2.0)) > 8.2) + { + out_data[atomicAdd(counter, 1u)] = idata; + } +} + diff --git a/third_party/spirv-cross/shaders-msl/comp/basic.dispatchbase.msl11.comp b/third_party/spirv-cross/shaders-msl/comp/basic.dispatchbase.msl11.comp new file mode 100644 index 0000000000..91453332aa --- /dev/null +++ b/third_party/spirv-cross/shaders-msl/comp/basic.dispatchbase.msl11.comp @@ -0,0 +1,29 @@ +#version 310 es +layout(local_size_x = 1) in; + +layout(std430, binding = 0) readonly buffer SSBO +{ + vec4 in_data[]; +}; + +layout(std430, binding = 1) writeonly buffer SSBO2 +{ + vec4 out_data[]; +}; + +layout(std430, binding = 2) buffer SSBO3 +{ + uint counter; +}; + +void main() +{ + uint ident = gl_GlobalInvocationID.x; + uint workgroup = gl_WorkGroupID.x; + vec4 idata = in_data[ident]; + if (dot(idata, vec4(1.0, 5.0, 6.0, 2.0)) > 8.2) + { + out_data[atomicAdd(counter, 1u)] = idata; + } +} + diff --git a/third_party/spirv-cross/shaders-msl/comp/basic.inline-block.msl2.comp b/third_party/spirv-cross/shaders-msl/comp/basic.inline-block.msl2.comp new file mode 100644 index 0000000000..8e1144a98e --- /dev/null +++ b/third_party/spirv-cross/shaders-msl/comp/basic.inline-block.msl2.comp @@ -0,0 +1,37 @@ +#version 450 +#extension GL_EXT_scalar_block_layout : require +layout(local_size_x = 3, local_size_y = 3, local_size_z = 2) in; + +struct X +{ + int x; + int y; + float z; +}; + +layout(set = 0, binding = 0, scalar) uniform Foo +{ + int a; + int b; + mat4 c; + X x[2]; +}; + +layout(set = 0, binding = 1) uniform Bar +{ + int d; + int e; +}; + +layout(set = 1, binding = 2) buffer Baz +{ + int f; + int g; +} baz[3]; + +void main() +{ + uvec3 coords = gl_GlobalInvocationID; + baz[coords.x].f = a + d; + baz[coords.x].g = b * e; +} diff --git a/third_party/spirv-cross/shaders-msl/comp/complex-composite-constant-array.comp b/third_party/spirv-cross/shaders-msl/comp/complex-composite-constant-array.comp new file mode 100644 index 0000000000..96a3f8951d --- /dev/null +++ b/third_party/spirv-cross/shaders-msl/comp/complex-composite-constant-array.comp @@ -0,0 +1,19 @@ +#version 450 + +layout(std430, set = 0, binding = 0) buffer SSBO +{ + mat4 a; + uint index; +}; + +const mat4 as[] = mat4[](mat4(1.0), mat4(2.0)); + +void write_global() +{ + a = as[index]; +} + +void main() +{ + write_global(); +} diff --git a/third_party/spirv-cross/shaders-msl/comp/composite-array-initialization.force-native-array.comp b/third_party/spirv-cross/shaders-msl/comp/composite-array-initialization.force-native-array.comp new file mode 100644 index 0000000000..1ecf4bcd40 --- /dev/null +++ b/third_party/spirv-cross/shaders-msl/comp/composite-array-initialization.force-native-array.comp @@ -0,0 +1,28 @@ +#version 450 +layout(local_size_x = 2) in; + +struct Data +{ + float a; + float b; +}; + +layout(std430, binding = 0) buffer SSBO +{ + Data outdata[]; +}; + +layout(constant_id = 0) const float X = 4.0; + +Data data[2] = Data[](Data(1.0, 2.0), Data(3.0, 4.0)); +Data data2[2] = Data[](Data(X, 2.0), Data(3.0, 5.0)); + +Data combine(Data a, Data b) +{ + return Data(a.a + b.a, a.b + b.b); +} + +void main() +{ + outdata[gl_WorkGroupID.x] = combine(data[gl_LocalInvocationID.x], data2[gl_LocalInvocationID.x]); +} diff --git a/third_party/spirv-cross/shaders-msl/comp/copy-array-of-arrays.force-native-array.comp b/third_party/spirv-cross/shaders-msl/comp/copy-array-of-arrays.force-native-array.comp new file mode 100644 index 0000000000..edf87195b8 --- /dev/null +++ b/third_party/spirv-cross/shaders-msl/comp/copy-array-of-arrays.force-native-array.comp @@ -0,0 +1,21 @@ +#version 450 +layout(local_size_x = 1) in; + +layout(set = 0, binding = 0, std430) buffer BUF +{ + int a; + float b; + float c; +} o; + +void main() +{ + const float a[2][2][2] = float[][][](float[][](float[](1.0, 2.0), float[](3.0, 4.0)), float[][](float[](1.0, 2.0), float[](3.0, 4.0))); + float b[2][2][2] = a; + float c[2][2][2] = b; + o.a = int(c[1][1][1]); + + float d[2][2][2] = float[][][](float[][](float[](o.b, o.c), float[](o.b, o.b)), float[][](float[](o.c, o.c), float[](o.c, o.b))); + float e[2][2][2] = d; + o.b = e[1][0][1]; +} diff --git a/third_party/spirv-cross/shaders-msl/comp/image-atomic-automatic-bindings.comp b/third_party/spirv-cross/shaders-msl/comp/image-atomic-automatic-bindings.comp new file mode 100644 index 0000000000..862cd21297 --- /dev/null +++ b/third_party/spirv-cross/shaders-msl/comp/image-atomic-automatic-bindings.comp @@ -0,0 +1,16 @@ +#version 450 +layout(local_size_x = 1) in; + +layout(set = 0, binding = 0, r32ui) uniform uimage2D uImage; +layout(set = 0, binding = 1) uniform sampler2D uTexture; + +layout(set = 0, binding = 2) buffer SSBO +{ + vec4 outdata; +}; + +void main() +{ + uint ret = imageAtomicAdd(uImage, ivec2(gl_GlobalInvocationID.xy), 10u); + outdata = textureLod(uTexture, vec2(gl_GlobalInvocationID.xy), 0.0) + float(ret); +} diff --git a/third_party/spirv-cross/shaders-msl/frag/array-of-array-lut.frag b/third_party/spirv-cross/shaders-msl/frag/array-of-array-lut.frag new file mode 100644 index 0000000000..c401a3fe37 --- /dev/null +++ b/third_party/spirv-cross/shaders-msl/frag/array-of-array-lut.frag @@ -0,0 +1,12 @@ +#version 450 + +layout(location = 0) out float vOutput; +layout(location = 0) flat in int vIndex1; +layout(location = 1) flat in int vIndex2; + +const float FOO[2][3] = float[][](float[](1.0, 2.0, 3.0), float[](4.0, 5.0, 6.0)); + +void main() +{ + vOutput = FOO[vIndex1][vIndex2]; +} diff --git a/third_party/spirv-cross/shaders-msl/frag/clip-distance-varying.frag b/third_party/spirv-cross/shaders-msl/frag/clip-distance-varying.frag new file mode 100644 index 0000000000..df49bd515c --- /dev/null +++ b/third_party/spirv-cross/shaders-msl/frag/clip-distance-varying.frag @@ -0,0 +1,10 @@ +#version 450 + +in float gl_ClipDistance[2]; + +layout(location = 0) out vec4 FragColor; + +void main() +{ + FragColor = vec4(1.0 - gl_ClipDistance[0] - gl_ClipDistance[1]); +} diff --git a/third_party/spirv-cross/shaders-msl/frag/huge-argument-buffer.device-argument-buffer.argument.msl2.frag b/third_party/spirv-cross/shaders-msl/frag/huge-argument-buffer.device-argument-buffer.argument.msl2.frag new file mode 100644 index 0000000000..28d2b4ae8d --- /dev/null +++ b/third_party/spirv-cross/shaders-msl/frag/huge-argument-buffer.device-argument-buffer.argument.msl2.frag @@ -0,0 +1,26 @@ +#version 450 + +layout(location = 0) out vec4 FragColor; +layout(location = 0) in vec2 vUV; +layout(set = 0, binding = 0) uniform sampler2D uSamplers[10000]; +layout(set = 2, binding = 0) uniform sampler2D uSampler; + +layout(set = 1, binding = 0) uniform UBO +{ + vec4 v; +} vs[10000]; + +vec4 samp_array() +{ + return texture(uSamplers[9999], vUV) + vs[5000].v; +} + +vec4 samp_single() +{ + return texture(uSampler, vUV); +} + +void main() +{ + FragColor = samp_array() + samp_single(); +} diff --git a/third_party/spirv-cross/shaders-msl/frag/pixel-interlock-ordered.msl2.argument.frag b/third_party/spirv-cross/shaders-msl/frag/pixel-interlock-ordered.msl2.argument.frag new file mode 100644 index 0000000000..04886a6729 --- /dev/null +++ b/third_party/spirv-cross/shaders-msl/frag/pixel-interlock-ordered.msl2.argument.frag @@ -0,0 +1,36 @@ +#version 450 +#extension GL_ARB_fragment_shader_interlock : require + +layout(pixel_interlock_ordered) in; + +layout(binding = 0, rgba8) uniform writeonly image2D img; +//layout(binding = 1, r32ui) uniform uimage2D img2; +layout(binding = 2, rgba8) uniform readonly image2D img3; +layout(binding = 3) coherent buffer Buffer +{ + int foo; + uint bar; +}; +layout(binding = 4) buffer Buffer2 +{ + uint quux; +}; + +layout(binding = 5, rgba8) uniform writeonly image2D img4; +layout(binding = 6) buffer Buffer3 +{ + int baz; +}; + +void main() +{ + // Deliberately outside the critical section to test usage tracking. + baz = 0; + imageStore(img4, ivec2(1, 1), vec4(1.0, 0.0, 0.0, 1.0)); + beginInvocationInterlockARB(); + imageStore(img, ivec2(0, 0), imageLoad(img3, ivec2(0, 0))); + //imageAtomicAdd(img2, ivec2(0, 0), 1u); + foo += 42; + atomicAnd(bar, quux); + endInvocationInterlockARB(); +} diff --git a/third_party/spirv-cross/shaders-msl/frag/pixel-interlock-ordered.msl2.frag b/third_party/spirv-cross/shaders-msl/frag/pixel-interlock-ordered.msl2.frag new file mode 100644 index 0000000000..04886a6729 --- /dev/null +++ b/third_party/spirv-cross/shaders-msl/frag/pixel-interlock-ordered.msl2.frag @@ -0,0 +1,36 @@ +#version 450 +#extension GL_ARB_fragment_shader_interlock : require + +layout(pixel_interlock_ordered) in; + +layout(binding = 0, rgba8) uniform writeonly image2D img; +//layout(binding = 1, r32ui) uniform uimage2D img2; +layout(binding = 2, rgba8) uniform readonly image2D img3; +layout(binding = 3) coherent buffer Buffer +{ + int foo; + uint bar; +}; +layout(binding = 4) buffer Buffer2 +{ + uint quux; +}; + +layout(binding = 5, rgba8) uniform writeonly image2D img4; +layout(binding = 6) buffer Buffer3 +{ + int baz; +}; + +void main() +{ + // Deliberately outside the critical section to test usage tracking. + baz = 0; + imageStore(img4, ivec2(1, 1), vec4(1.0, 0.0, 0.0, 1.0)); + beginInvocationInterlockARB(); + imageStore(img, ivec2(0, 0), imageLoad(img3, ivec2(0, 0))); + //imageAtomicAdd(img2, ivec2(0, 0), 1u); + foo += 42; + atomicAnd(bar, quux); + endInvocationInterlockARB(); +} diff --git a/third_party/spirv-cross/shaders-msl/frag/sample-depth-propagate-state-from-resource.frag b/third_party/spirv-cross/shaders-msl/frag/sample-depth-propagate-state-from-resource.frag new file mode 100644 index 0000000000..9a855ac7a8 --- /dev/null +++ b/third_party/spirv-cross/shaders-msl/frag/sample-depth-propagate-state-from-resource.frag @@ -0,0 +1,29 @@ +#version 450 + +layout(set = 0, binding = 0) uniform texture2D uTexture; +layout(set = 0, binding = 1) uniform sampler uSampler; +layout(set = 0, binding = 2) uniform samplerShadow uSamplerShadow; + +layout(location = 0) out float FragColor; +layout(location = 0) in vec3 vUV; + +float sample_normal2(texture2D tex) +{ + return texture(sampler2D(tex, uSampler), vUV.xy).x; +} + +float sample_normal(texture2D tex) +{ + return sample_normal2(tex); +} + +float sample_comp(texture2D tex) +{ + return texture(sampler2DShadow(tex, uSamplerShadow), vUV); +} + +void main() +{ + FragColor = sample_normal(uTexture); + FragColor += sample_comp(uTexture); +} diff --git a/third_party/spirv-cross/shaders-msl/frag/texture-cube-array.frag b/third_party/spirv-cross/shaders-msl/frag/texture-cube-array.frag new file mode 100644 index 0000000000..91a55f933b --- /dev/null +++ b/third_party/spirv-cross/shaders-msl/frag/texture-cube-array.frag @@ -0,0 +1,16 @@ +#version 450 + +layout(set = 0, binding = 0) uniform samplerCube cubeSampler; +layout(set = 0, binding = 1) uniform samplerCubeArray cubeArraySampler; +layout(set = 0, binding = 2) uniform sampler2DArray texArraySampler; + +layout(location = 0) in vec4 vUV; +layout(location = 0) out vec4 FragColor; + +void main() +{ + vec4 a = texture(cubeSampler, vUV.xyz); + vec4 b = texture(cubeArraySampler, vUV); + vec4 c = texture(texArraySampler, vUV.xyz); + FragColor = a + b + c; +} diff --git a/third_party/spirv-cross/shaders-msl/frag/texture-cube-array.ios.emulate-cube-array.frag b/third_party/spirv-cross/shaders-msl/frag/texture-cube-array.ios.emulate-cube-array.frag new file mode 100644 index 0000000000..91a55f933b --- /dev/null +++ b/third_party/spirv-cross/shaders-msl/frag/texture-cube-array.ios.emulate-cube-array.frag @@ -0,0 +1,16 @@ +#version 450 + +layout(set = 0, binding = 0) uniform samplerCube cubeSampler; +layout(set = 0, binding = 1) uniform samplerCubeArray cubeArraySampler; +layout(set = 0, binding = 2) uniform sampler2DArray texArraySampler; + +layout(location = 0) in vec4 vUV; +layout(location = 0) out vec4 FragColor; + +void main() +{ + vec4 a = texture(cubeSampler, vUV.xyz); + vec4 b = texture(cubeArraySampler, vUV); + vec4 c = texture(texArraySampler, vUV.xyz); + FragColor = a + b + c; +} diff --git a/third_party/spirv-cross/shaders-msl/tesc/load-control-point-array-of-matrix.tesc b/third_party/spirv-cross/shaders-msl/tesc/load-control-point-array-of-matrix.tesc new file mode 100644 index 0000000000..36b16681e2 --- /dev/null +++ b/third_party/spirv-cross/shaders-msl/tesc/load-control-point-array-of-matrix.tesc @@ -0,0 +1,12 @@ +#version 450 + +layout(vertices = 4) out; + +layout(location = 0) in mat4 vInputs[gl_MaxPatchVertices]; +layout(location = 0) out mat4 vOutputs[4]; + +void main() +{ + mat4 tmp[gl_MaxPatchVertices] = vInputs; + vOutputs[gl_InvocationID] = tmp[gl_InvocationID]; +} diff --git a/third_party/spirv-cross/shaders-msl/tesc/load-control-point-array-of-struct.tesc b/third_party/spirv-cross/shaders-msl/tesc/load-control-point-array-of-struct.tesc new file mode 100644 index 0000000000..4b4d5bfcd1 --- /dev/null +++ b/third_party/spirv-cross/shaders-msl/tesc/load-control-point-array-of-struct.tesc @@ -0,0 +1,21 @@ +#version 450 + +layout(vertices = 4) out; + +struct VertexData +{ + mat4 a; + vec4 b[2]; + vec4 c; +}; + +layout(location = 0) in VertexData vInputs[gl_MaxPatchVertices]; +layout(location = 0) out vec4 vOutputs[4]; + +void main() +{ + VertexData tmp[gl_MaxPatchVertices] = vInputs; + VertexData tmp_single = vInputs[gl_InvocationID ^ 1]; + + vOutputs[gl_InvocationID] = tmp[gl_InvocationID].a[1] + tmp[gl_InvocationID].b[1] + tmp[gl_InvocationID].c + tmp_single.c; +} diff --git a/third_party/spirv-cross/shaders-msl/tesc/load-control-point-array.tesc b/third_party/spirv-cross/shaders-msl/tesc/load-control-point-array.tesc new file mode 100644 index 0000000000..1a5924b895 --- /dev/null +++ b/third_party/spirv-cross/shaders-msl/tesc/load-control-point-array.tesc @@ -0,0 +1,12 @@ +#version 450 + +layout(vertices = 4) out; + +layout(location = 0) in vec4 vInputs[gl_MaxPatchVertices]; +layout(location = 0) out vec4 vOutputs[4]; + +void main() +{ + vec4 tmp[gl_MaxPatchVertices] = vInputs; + vOutputs[gl_InvocationID] = tmp[gl_InvocationID]; +} diff --git a/third_party/spirv-cross/shaders-msl/tese/load-control-point-array-of-matrix.tese b/third_party/spirv-cross/shaders-msl/tese/load-control-point-array-of-matrix.tese new file mode 100644 index 0000000000..479b3e651b --- /dev/null +++ b/third_party/spirv-cross/shaders-msl/tese/load-control-point-array-of-matrix.tese @@ -0,0 +1,13 @@ +#version 450 + +layout(cw, quads) in; +layout(location = 0) in mat4 vInputs[gl_MaxPatchVertices]; +layout(location = 4) patch in vec4 vBoo[4]; +layout(location = 8) patch in int vIndex; + +void main() +{ + mat4 tmp[gl_MaxPatchVertices] = vInputs; + gl_Position = tmp[0][vIndex] + tmp[1][vIndex] + vBoo[vIndex]; + +} diff --git a/third_party/spirv-cross/shaders-msl/tese/load-control-point-array.tese b/third_party/spirv-cross/shaders-msl/tese/load-control-point-array.tese new file mode 100644 index 0000000000..4fa0bb1242 --- /dev/null +++ b/third_party/spirv-cross/shaders-msl/tese/load-control-point-array.tese @@ -0,0 +1,13 @@ +#version 450 + +layout(cw, quads) in; +layout(location = 0) in vec4 vInputs[gl_MaxPatchVertices]; +layout(location = 1) patch in vec4 vBoo[4]; +layout(location = 5) patch in int vIndex; + +void main() +{ + vec4 tmp[gl_MaxPatchVertices] = vInputs; + gl_Position = tmp[0] + tmp[1] + vBoo[vIndex]; + +} diff --git a/third_party/spirv-cross/shaders-msl/vert/clip-distance-block.vert b/third_party/spirv-cross/shaders-msl/vert/clip-distance-block.vert new file mode 100644 index 0000000000..93ed31150c --- /dev/null +++ b/third_party/spirv-cross/shaders-msl/vert/clip-distance-block.vert @@ -0,0 +1,15 @@ +#version 450 + +layout(location = 0) in vec4 Position; +out gl_PerVertex +{ + vec4 gl_Position; + float gl_ClipDistance[2]; +}; + +void main() +{ + gl_Position = Position; + gl_ClipDistance[0] = Position.x; + gl_ClipDistance[1] = Position.y; +} diff --git a/third_party/spirv-cross/shaders-msl/vert/float-math.invariant-float-math.vert b/third_party/spirv-cross/shaders-msl/vert/float-math.invariant-float-math.vert new file mode 100644 index 0000000000..caa8639a89 --- /dev/null +++ b/third_party/spirv-cross/shaders-msl/vert/float-math.invariant-float-math.vert @@ -0,0 +1,25 @@ +#version 450 + +layout(set = 0, binding = 0) uniform Matrices +{ + mat4 vpMatrix; + mat4 wMatrix; + mat4x3 wMatrix4x3; + mat3x4 wMatrix3x4; +}; + +layout(location = 0) in vec3 InPos; +layout(location = 1) in vec3 InNormal; + +layout(location = 0) out vec3 OutNormal; +layout(location = 1) out vec4 OutWorldPos[4]; + +void main() +{ + gl_Position = vpMatrix * wMatrix * vec4(InPos, 1); + OutWorldPos[0] = wMatrix * vec4(InPos, 1); + OutWorldPos[1] = vec4(InPos, 1) * wMatrix; + OutWorldPos[2] = wMatrix3x4 * InPos; + OutWorldPos[3] = InPos * wMatrix4x3; + OutNormal = (wMatrix * vec4(InNormal, 0)).xyz; +} diff --git a/third_party/spirv-cross/shaders-msl/vert/float-math.vert b/third_party/spirv-cross/shaders-msl/vert/float-math.vert new file mode 100644 index 0000000000..caa8639a89 --- /dev/null +++ b/third_party/spirv-cross/shaders-msl/vert/float-math.vert @@ -0,0 +1,25 @@ +#version 450 + +layout(set = 0, binding = 0) uniform Matrices +{ + mat4 vpMatrix; + mat4 wMatrix; + mat4x3 wMatrix4x3; + mat3x4 wMatrix3x4; +}; + +layout(location = 0) in vec3 InPos; +layout(location = 1) in vec3 InNormal; + +layout(location = 0) out vec3 OutNormal; +layout(location = 1) out vec4 OutWorldPos[4]; + +void main() +{ + gl_Position = vpMatrix * wMatrix * vec4(InPos, 1); + OutWorldPos[0] = wMatrix * vec4(InPos, 1); + OutWorldPos[1] = vec4(InPos, 1) * wMatrix; + OutWorldPos[2] = wMatrix3x4 * InPos; + OutWorldPos[3] = InPos * wMatrix4x3; + OutNormal = (wMatrix * vec4(InNormal, 0)).xyz; +} diff --git a/third_party/spirv-cross/shaders-msl/vert/return-array.force-native-array.vert b/third_party/spirv-cross/shaders-msl/vert/return-array.force-native-array.vert new file mode 100644 index 0000000000..708460114e --- /dev/null +++ b/third_party/spirv-cross/shaders-msl/vert/return-array.force-native-array.vert @@ -0,0 +1,22 @@ +#version 310 es + +layout(location = 0) in vec4 vInput0; +layout(location = 1) in vec4 vInput1; + +vec4[2] test() +{ + return vec4[](vec4(10.0), vec4(20.0)); +} + +vec4[2] test2() +{ + vec4 foobar[2]; + foobar[0] = vInput0; + foobar[1] = vInput1; + return foobar; +} + +void main() +{ + gl_Position = test()[0] + test2()[1]; +} diff --git a/third_party/spirv-cross/shaders-no-opt/asm/comp/access-tracking-function-call-result.asm.comp b/third_party/spirv-cross/shaders-no-opt/asm/comp/access-tracking-function-call-result.asm.comp new file mode 100644 index 0000000000..c11d4cdd0a --- /dev/null +++ b/third_party/spirv-cross/shaders-no-opt/asm/comp/access-tracking-function-call-result.asm.comp @@ -0,0 +1,54 @@ +; SPIR-V +; Version: 1.5 +; Generator: Khronos SPIR-V Tools Assembler; 0 +; Bound: 25 +; Schema: 0 + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" + OpExecutionMode %main LocalSize 1 1 1 + OpSource GLSL 460 + OpName %main "main" + OpName %foo_ "foo(" + OpName %Output "Output" + OpMemberName %Output 0 "myout" + OpName %_ "" + OpMemberDecorate %Output 0 Offset 0 + OpDecorate %Output BufferBlock + OpDecorate %_ DescriptorSet 0 + OpDecorate %_ Binding 0 + %void = OpTypeVoid + %7 = OpTypeFunction %void + %int = OpTypeInt 32 1 + %9 = OpTypeFunction %int + %int_12 = OpConstant %int 12 + %bool = OpTypeBool + %true = OpConstantTrue %bool + %Output = OpTypeStruct %int +%_ptr_Uniform_Output = OpTypePointer Uniform %Output + %_ = OpVariable %_ptr_Uniform_Output Uniform + %int_0 = OpConstant %int 0 +%_ptr_Uniform_int = OpTypePointer Uniform %int + %main = OpFunction %void None %7 + %16 = OpLabel + %17 = OpFunctionCall %int %foo_ + OpBranch %18 + %18 = OpLabel + OpLoopMerge %19 %20 None + OpBranchConditional %true %21 %19 + %21 = OpLabel + %22 = OpAccessChain %_ptr_Uniform_int %_ %int_0 + OpStore %22 %17 + OpReturn + %20 = OpLabel + OpBranch %18 + %19 = OpLabel + %23 = OpAccessChain %_ptr_Uniform_int %_ %int_0 + OpStore %23 %17 + OpReturn + OpFunctionEnd + %foo_ = OpFunction %int None %9 + %24 = OpLabel + OpReturnValue %int_12 + OpFunctionEnd diff --git a/third_party/spirv-cross/shaders-no-opt/asm/comp/aliased-struct-divergent-member-name.asm.comp b/third_party/spirv-cross/shaders-no-opt/asm/comp/aliased-struct-divergent-member-name.asm.comp new file mode 100644 index 0000000000..87aee2db54 --- /dev/null +++ b/third_party/spirv-cross/shaders-no-opt/asm/comp/aliased-struct-divergent-member-name.asm.comp @@ -0,0 +1,77 @@ +; SPIR-V +; Version: 1.0 +; Generator: Khronos Glslang Reference Front End; 7 +; Bound: 37 +; Schema: 0 + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" + OpExecutionMode %main LocalSize 1 1 1 + OpSource GLSL 450 + OpName %main "main" + OpName %T "T" + OpMemberName %T 0 "a" + OpName %v "v" + OpName %T_0 "T" + OpMemberName %T_0 0 "b" + OpName %SSBO1 "SSBO1" + OpMemberName %SSBO1 0 "foo" + OpName %_ "" + OpName %T_1 "T" + OpMemberName %T_1 0 "c" + OpName %SSBO2 "SSBO2" + OpMemberName %SSBO2 0 "bar" + OpName %__0 "" + OpMemberDecorate %T_0 0 Offset 0 + OpDecorate %_runtimearr_T_0 ArrayStride 4 + OpMemberDecorate %SSBO1 0 Offset 0 + OpDecorate %SSBO1 BufferBlock + OpDecorate %_ DescriptorSet 0 + OpDecorate %_ Binding 0 + OpMemberDecorate %T_1 0 Offset 0 + OpDecorate %_runtimearr_T_1 ArrayStride 16 + OpMemberDecorate %SSBO2 0 Offset 0 + OpDecorate %SSBO2 BufferBlock + OpDecorate %__0 DescriptorSet 0 + OpDecorate %__0 Binding 1 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %T = OpTypeStruct %float +%_ptr_Function_T = OpTypePointer Function %T + %float_40 = OpConstant %float 40 + %11 = OpConstantComposite %T %float_40 + %T_0 = OpTypeStruct %float +%_runtimearr_T_0 = OpTypeRuntimeArray %T_0 + %SSBO1 = OpTypeStruct %_runtimearr_T_0 +%_ptr_Uniform_SSBO1 = OpTypePointer Uniform %SSBO1 + %_ = OpVariable %_ptr_Uniform_SSBO1 Uniform + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 + %int_10 = OpConstant %int 10 +%_ptr_Uniform_T_0 = OpTypePointer Uniform %T_0 +%_ptr_Uniform_float = OpTypePointer Uniform %float + %T_1 = OpTypeStruct %float +%_runtimearr_T_1 = OpTypeRuntimeArray %T_1 + %SSBO2 = OpTypeStruct %_runtimearr_T_1 +%_ptr_Uniform_SSBO2 = OpTypePointer Uniform %SSBO2 + %__0 = OpVariable %_ptr_Uniform_SSBO2 Uniform + %int_30 = OpConstant %int 30 +%_ptr_Uniform_T_1 = OpTypePointer Uniform %T_1 + %main = OpFunction %void None %3 + %5 = OpLabel + %v = OpVariable %_ptr_Function_T Function + OpStore %v %11 + %20 = OpLoad %T %v + %22 = OpAccessChain %_ptr_Uniform_T_0 %_ %int_0 %int_10 + %23 = OpCompositeExtract %float %20 0 + %25 = OpAccessChain %_ptr_Uniform_float %22 %int_0 + OpStore %25 %23 + %32 = OpLoad %T %v + %34 = OpAccessChain %_ptr_Uniform_T_1 %__0 %int_0 %int_30 + %35 = OpCompositeExtract %float %32 0 + %36 = OpAccessChain %_ptr_Uniform_float %34 %int_0 + OpStore %36 %35 + OpReturn + OpFunctionEnd diff --git a/third_party/spirv-cross/shaders-no-opt/asm/comp/arithmetic-conversion-signs.asm.nocompat.vk.comp b/third_party/spirv-cross/shaders-no-opt/asm/comp/arithmetic-conversion-signs.asm.nocompat.vk.comp index 0e1ce235d2..504a9546c5 100644 --- a/third_party/spirv-cross/shaders-no-opt/asm/comp/arithmetic-conversion-signs.asm.nocompat.vk.comp +++ b/third_party/spirv-cross/shaders-no-opt/asm/comp/arithmetic-conversion-signs.asm.nocompat.vk.comp @@ -111,11 +111,23 @@ OpStore %ptr_f32 %s16_to_f32_signed %u16_to_f32_signed = OpConvertSToF %float %u16 OpStore %ptr_f32 %u16_to_f32_signed + + %s32_to_f32_signed = OpConvertSToF %float %s32 + OpStore %ptr_f32 %s32_to_f32_signed + %u32_to_f32_signed = OpConvertSToF %float %u32 + OpStore %ptr_f32 %u32_to_f32_signed + + ; UToF %s16_to_f32_unsigned = OpConvertUToF %float %s16 OpStore %ptr_f32 %s16_to_f32_unsigned %u16_to_f32_unsigned = OpConvertUToF %float %u16 OpStore %ptr_f32 %u16_to_f32_unsigned + %s32_to_f32_unsigned = OpConvertUToF %float %s32 + OpStore %ptr_f32 %s32_to_f32_unsigned + %u32_to_f32_unsigned = OpConvertUToF %float %u32 + OpStore %ptr_f32 %u32_to_f32_unsigned + ; FToS %f32_to_s16_signed = OpConvertFToS %short %f32 OpStore %ptr_s16 %f32_to_s16_signed diff --git a/third_party/spirv-cross/shaders-no-opt/asm/comp/bitfield-signed-operations.asm.comp b/third_party/spirv-cross/shaders-no-opt/asm/comp/bitfield-signed-operations.asm.comp new file mode 100644 index 0000000000..435fa32221 --- /dev/null +++ b/third_party/spirv-cross/shaders-no-opt/asm/comp/bitfield-signed-operations.asm.comp @@ -0,0 +1,97 @@ +; SPIR-V +; Version: 1.0 +; Generator: Khronos Glslang Reference Front End; 7 +; Bound: 26 +; Schema: 0 + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" + OpExecutionMode %main LocalSize 1 1 1 + OpSource GLSL 450 + OpName %main "main" + OpName %SSBO "SSBO" + OpMemberName %SSBO 0 "ints" + OpMemberName %SSBO 1 "uints" + OpName %_ "" + OpMemberDecorate %SSBO 0 Offset 0 + OpMemberDecorate %SSBO 1 Offset 16 + OpDecorate %SSBO BufferBlock + OpDecorate %_ DescriptorSet 0 + OpDecorate %_ Binding 0 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %int = OpTypeInt 32 1 + %v4int = OpTypeVector %int 4 + %uint = OpTypeInt 32 0 + %v4uint = OpTypeVector %uint 4 + + %int_1 = OpConstant %int 1 + %uint_11 = OpConstant %uint 11 + + %SSBO = OpTypeStruct %v4int %v4uint +%_ptr_Uniform_SSBO = OpTypePointer Uniform %SSBO + %_ = OpVariable %_ptr_Uniform_SSBO Uniform + %int_0 = OpConstant %int 0 +%_ptr_Uniform_v4int = OpTypePointer Uniform %v4int +%_ptr_Uniform_v4uint = OpTypePointer Uniform %v4uint + %main = OpFunction %void None %3 + %5 = OpLabel + %ints_ptr = OpAccessChain %_ptr_Uniform_v4int %_ %int_0 + %uints_ptr = OpAccessChain %_ptr_Uniform_v4uint %_ %int_1 + %ints = OpLoad %v4int %ints_ptr + %uints = OpLoad %v4uint %uints_ptr + + %ints_alt = OpVectorShuffle %v4int %ints %ints 3 2 1 0 + %uints_alt = OpVectorShuffle %v4uint %uints %uints 3 2 1 0 + + %int_to_int_popcount = OpBitCount %v4int %ints + %int_to_uint_popcount = OpBitCount %v4uint %ints + %uint_to_int_popcount = OpBitCount %v4int %uints + %uint_to_uint_popcount = OpBitCount %v4uint %uints + + ; BitReverse must have matching types w.r.t. sign, yay. + %int_to_int_reverse = OpBitReverse %v4int %ints + ;%int_to_uint_reverse = OpBitReverse %v4uint %ints + ;%uint_to_int_reverse = OpBitReverse %v4int %uints + %uint_to_uint_reverse = OpBitReverse %v4uint %uints + + ; Base and Result must match. + %int_to_int_sbit = OpBitFieldSExtract %v4int %ints %int_1 %uint_11 + ;%int_to_uint_sbit = OpBitFieldSExtract %v4uint %ints %offset %count + ;%uint_to_int_sbit = OpBitFieldSExtract %v4int %uints %offset %count + %uint_to_uint_sbit = OpBitFieldSExtract %v4uint %uints %uint_11 %int_1 + + ; Base and Result must match. + %int_to_int_ubit = OpBitFieldUExtract %v4int %ints %int_1 %uint_11 + ;%int_to_uint_ubit = OpBitFieldUExtract %v4uint %ints %offset %count + ;%uint_to_int_ubit = OpBitFieldUExtract %v4int %uints %offset %count + %uint_to_uint_ubit = OpBitFieldUExtract %v4uint %uints %uint_11 %int_1 + + %int_to_int_insert = OpBitFieldInsert %v4int %ints %ints_alt %int_1 %uint_11 + %uint_to_uint_insert = OpBitFieldInsert %v4uint %uints %uints_alt %uint_11 %int_1 + + OpStore %ints_ptr %int_to_int_popcount + OpStore %uints_ptr %int_to_uint_popcount + OpStore %ints_ptr %uint_to_int_popcount + OpStore %uints_ptr %uint_to_uint_popcount + + OpStore %ints_ptr %int_to_int_reverse + ;OpStore %uints_ptr %int_to_uint_reverse + ;OpStore %ints_ptr %uint_to_int_reverse + OpStore %uints_ptr %uint_to_uint_reverse + + OpStore %ints_ptr %int_to_int_sbit + ;OpStore %uints_ptr %int_to_uint_sbit + ;OpStore %ints_ptr %uint_to_int_sbit + OpStore %uints_ptr %uint_to_uint_sbit + + OpStore %ints_ptr %int_to_int_ubit + ;OpStore %uints_ptr %int_to_uint_ubit + ;OpStore %ints_ptr %uint_to_int_ubit + OpStore %uints_ptr %uint_to_uint_ubit + + OpStore %ints_ptr %int_to_int_insert + OpStore %uints_ptr %uint_to_uint_insert + + OpReturn + OpFunctionEnd diff --git a/third_party/spirv-cross/shaders-no-opt/asm/comp/copy-logical.spv14.asm.comp b/third_party/spirv-cross/shaders-no-opt/asm/comp/copy-logical.spv14.asm.comp new file mode 100644 index 0000000000..20fa0b099b --- /dev/null +++ b/third_party/spirv-cross/shaders-no-opt/asm/comp/copy-logical.spv14.asm.comp @@ -0,0 +1,69 @@ +; SPIR-V +; Version: 1.0 +; Generator: Khronos Glslang Reference Front End; 8 +; Bound: 48 +; Schema: 0 + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" %ssbo + OpExecutionMode %main LocalSize 1 1 1 + OpSource GLSL 450 + OpName %B1 "B1" + OpName %A "A" + OpName %C "C" + OpName %B2 "B2" + OpMemberName %A 0 "a" + OpMemberName %A 1 "b1" + OpMemberName %A 2 "b1_array" + OpMemberName %C 0 "c" + OpMemberName %C 1 "b2" + OpMemberName %C 2 "b2_array" + OpMemberName %B1 0 "elem1" + OpMemberName %B2 0 "elem2" + OpMemberName %SSBO 0 "a_block" + OpMemberName %SSBO 1 "c_block" + OpDecorate %B1Array ArrayStride 16 + OpDecorate %B2Array ArrayStride 16 + OpMemberDecorate %B1 0 Offset 0 + OpMemberDecorate %A 0 Offset 0 + OpMemberDecorate %A 1 Offset 16 + OpMemberDecorate %A 2 Offset 32 + OpMemberDecorate %B2 0 Offset 0 + OpMemberDecorate %C 0 Offset 0 + OpMemberDecorate %C 1 Offset 16 + OpMemberDecorate %C 2 Offset 32 + OpMemberDecorate %SSBO 0 Offset 0 + OpMemberDecorate %SSBO 1 Offset 96 + OpDecorate %SSBO Block + OpDecorate %ssbo DescriptorSet 0 + OpDecorate %ssbo Binding 0 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %uint = OpTypeInt 32 0 + %uint_4 = OpConstant %uint 4 + %v4float = OpTypeVector %float 4 + %B2 = OpTypeStruct %v4float + %B2Array = OpTypeArray %B2 %uint_4 + %C = OpTypeStruct %v4float %B2 %B2Array + %B1 = OpTypeStruct %v4float + %B1Array = OpTypeArray %B1 %uint_4 + %A = OpTypeStruct %v4float %B1 %B1Array + %SSBO = OpTypeStruct %A %C +%_ptr_Uniform_SSBO = OpTypePointer StorageBuffer %SSBO + %ssbo = OpVariable %_ptr_Uniform_SSBO StorageBuffer + %int = OpTypeInt 32 1 + %int_1 = OpConstant %int 1 +%_ptr_Uniform_C = OpTypePointer StorageBuffer %C + %int_0 = OpConstant %int 0 +%_ptr_Uniform_A = OpTypePointer StorageBuffer %A + %main = OpFunction %void None %3 + %5 = OpLabel + %22 = OpAccessChain %_ptr_Uniform_C %ssbo %int_1 + %39 = OpAccessChain %_ptr_Uniform_A %ssbo %int_0 + %23 = OpLoad %C %22 + %24 = OpCopyLogical %A %23 + OpStore %39 %24 + OpReturn + OpFunctionEnd diff --git a/third_party/spirv-cross/shaders/asm/extended-debug-extinst.invalid.asm.comp b/third_party/spirv-cross/shaders-no-opt/asm/comp/extended-debug-extinst.invalid.asm.comp similarity index 100% rename from third_party/spirv-cross/shaders/asm/extended-debug-extinst.invalid.asm.comp rename to third_party/spirv-cross/shaders-no-opt/asm/comp/extended-debug-extinst.invalid.asm.comp diff --git a/third_party/spirv-cross/shaders/asm/comp/phi-temporary-copy-loop-variable.asm.comp b/third_party/spirv-cross/shaders-no-opt/asm/comp/phi-temporary-copy-loop-variable.asm.invalid.comp similarity index 100% rename from third_party/spirv-cross/shaders/asm/comp/phi-temporary-copy-loop-variable.asm.comp rename to third_party/spirv-cross/shaders-no-opt/asm/comp/phi-temporary-copy-loop-variable.asm.invalid.comp diff --git a/third_party/spirv-cross/shaders/asm/comp/storage-buffer-basic.invalid.asm.comp b/third_party/spirv-cross/shaders-no-opt/asm/comp/storage-buffer-basic.invalid.asm.comp similarity index 100% rename from third_party/spirv-cross/shaders/asm/comp/storage-buffer-basic.invalid.asm.comp rename to third_party/spirv-cross/shaders-no-opt/asm/comp/storage-buffer-basic.invalid.asm.comp diff --git a/third_party/spirv-cross/shaders-no-opt/asm/frag/combined-image-sampler-dxc-min16float.asm.invalid.frag b/third_party/spirv-cross/shaders-no-opt/asm/frag/combined-image-sampler-dxc-min16float.asm.invalid.frag new file mode 100644 index 0000000000..dda2f0279c --- /dev/null +++ b/third_party/spirv-cross/shaders-no-opt/asm/frag/combined-image-sampler-dxc-min16float.asm.invalid.frag @@ -0,0 +1,95 @@ +; SPIR-V +; Version: 1.0 +; Generator: Google spiregg; 0 +; Bound: 48 +; Schema: 0 + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %PSMain "main" %in_var_COLOR %in_var_TEXCOORD0 %out_var_SV_TARGET + OpExecutionMode %PSMain OriginUpperLeft + ; Not actually ESSL, but makes testing easier. + OpSource ESSL 310 + OpName %type_2d_image "type.2d.image" + OpName %tex "tex" + OpName %type_sampler "type.sampler" + OpName %Samp "Samp" + OpName %in_var_COLOR "in.var.COLOR" + OpName %in_var_TEXCOORD0 "in.var.TEXCOORD0" + OpName %out_var_SV_TARGET "out.var.SV_TARGET" + OpName %PSMain "PSMain" + OpName %PSInput "PSInput" + OpMemberName %PSInput 0 "color" + OpMemberName %PSInput 1 "uv" + OpName %param_var_input "param.var.input" + OpName %src_PSMain "src.PSMain" + OpName %input "input" + OpName %bb_entry "bb.entry" + OpName %a "a" + OpName %type_sampled_image "type.sampled.image" + OpDecorate %in_var_COLOR Location 0 + OpDecorate %in_var_TEXCOORD0 Location 1 + OpDecorate %out_var_SV_TARGET Location 0 + OpDecorate %tex DescriptorSet 0 + OpDecorate %tex Binding 0 + OpDecorate %Samp DescriptorSet 0 + OpDecorate %Samp Binding 1 + OpDecorate %tex RelaxedPrecision + OpDecorate %a RelaxedPrecision + OpDecorate %38 RelaxedPrecision + OpDecorate %45 RelaxedPrecision + OpDecorate %47 RelaxedPrecision + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 + %int_1 = OpConstant %int 1 + %float = OpTypeFloat 32 +%type_2d_image = OpTypeImage %float 2D 2 0 0 1 Unknown +%_ptr_UniformConstant_type_2d_image = OpTypePointer UniformConstant %type_2d_image +%type_sampler = OpTypeSampler +%_ptr_UniformConstant_type_sampler = OpTypePointer UniformConstant %type_sampler + %v4float = OpTypeVector %float 4 +%_ptr_Input_v4float = OpTypePointer Input %v4float + %v2float = OpTypeVector %float 2 +%_ptr_Input_v2float = OpTypePointer Input %v2float +%_ptr_Output_v4float = OpTypePointer Output %v4float + %void = OpTypeVoid + %21 = OpTypeFunction %void + %PSInput = OpTypeStruct %v4float %v2float +%_ptr_Function_PSInput = OpTypePointer Function %PSInput + %31 = OpTypeFunction %v4float %_ptr_Function_PSInput +%_ptr_Function_v4float = OpTypePointer Function %v4float +%_ptr_Function_v2float = OpTypePointer Function %v2float +%type_sampled_image = OpTypeSampledImage %type_2d_image + %tex = OpVariable %_ptr_UniformConstant_type_2d_image UniformConstant + %Samp = OpVariable %_ptr_UniformConstant_type_sampler UniformConstant +%in_var_COLOR = OpVariable %_ptr_Input_v4float Input +%in_var_TEXCOORD0 = OpVariable %_ptr_Input_v2float Input +%out_var_SV_TARGET = OpVariable %_ptr_Output_v4float Output + %PSMain = OpFunction %void None %21 + %22 = OpLabel +%param_var_input = OpVariable %_ptr_Function_PSInput Function + %26 = OpLoad %v4float %in_var_COLOR + %27 = OpLoad %v2float %in_var_TEXCOORD0 + %28 = OpCompositeConstruct %PSInput %26 %27 + OpStore %param_var_input %28 + %29 = OpFunctionCall %v4float %src_PSMain %param_var_input + OpStore %out_var_SV_TARGET %29 + OpReturn + OpFunctionEnd + %src_PSMain = OpFunction %v4float None %31 + %input = OpFunctionParameter %_ptr_Function_PSInput + %bb_entry = OpLabel + %a = OpVariable %_ptr_Function_v4float Function + %36 = OpAccessChain %_ptr_Function_v4float %input %int_0 + %37 = OpLoad %v4float %36 + %38 = OpLoad %type_2d_image %tex + %39 = OpLoad %type_sampler %Samp + %41 = OpAccessChain %_ptr_Function_v2float %input %int_1 + %42 = OpLoad %v2float %41 + %44 = OpSampledImage %type_sampled_image %38 %39 + %45 = OpImageSampleImplicitLod %v4float %44 %42 None + %46 = OpFMul %v4float %37 %45 + OpStore %a %46 + %47 = OpLoad %v4float %a + OpReturnValue %47 + OpFunctionEnd + diff --git a/third_party/spirv-cross/shaders-no-opt/asm/frag/demote-impure-function-call.vk.nocompat.asm.frag b/third_party/spirv-cross/shaders-no-opt/asm/frag/demote-impure-function-call.vk.nocompat.asm.frag new file mode 100644 index 0000000000..9f1a4573dd --- /dev/null +++ b/third_party/spirv-cross/shaders-no-opt/asm/frag/demote-impure-function-call.vk.nocompat.asm.frag @@ -0,0 +1,63 @@ +; SPIR-V +; Version: 1.0 +; Generator: Khronos Glslang Reference Front End; 7 +; Bound: 33 +; Schema: 0 + OpCapability Shader + OpCapability DemoteToHelperInvocationEXT + OpExtension "SPV_EXT_demote_to_helper_invocation" + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %vA %FragColor + OpExecutionMode %main OriginUpperLeft + OpSource GLSL 450 + OpSourceExtension "GL_EXT_demote_to_helper_invocation" + OpName %main "main" + OpName %foobar_i1_ "foobar(i1;" + OpName %a "a" + OpName %a_0 "a" + OpName %vA "vA" + OpName %param "param" + OpName %FragColor "FragColor" + OpDecorate %vA Flat + OpDecorate %vA Location 0 + OpDecorate %FragColor Location 0 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %int = OpTypeInt 32 1 +%_ptr_Function_int = OpTypePointer Function %int + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 + %10 = OpTypeFunction %v4float %_ptr_Function_int + %int_0 = OpConstant %int 0 + %bool = OpTypeBool + %float_10 = OpConstant %float 10 + %21 = OpConstantComposite %v4float %float_10 %float_10 %float_10 %float_10 +%_ptr_Function_v4float = OpTypePointer Function %v4float +%_ptr_Input_int = OpTypePointer Input %int + %vA = OpVariable %_ptr_Input_int Input +%_ptr_Output_v4float = OpTypePointer Output %v4float + %FragColor = OpVariable %_ptr_Output_v4float Output + %main = OpFunction %void None %3 + %5 = OpLabel + %a_0 = OpVariable %_ptr_Function_v4float Function + %param = OpVariable %_ptr_Function_int Function + %29 = OpLoad %int %vA + OpStore %param %29 + %30 = OpFunctionCall %v4float %foobar_i1_ %param + OpStore %FragColor %21 + OpReturn + OpFunctionEnd + %foobar_i1_ = OpFunction %v4float None %10 + %a = OpFunctionParameter %_ptr_Function_int + %13 = OpLabel + %14 = OpLoad %int %a + %17 = OpSLessThan %bool %14 %int_0 + OpSelectionMerge %19 None + OpBranchConditional %17 %18 %19 + %18 = OpLabel + OpDemoteToHelperInvocationEXT + OpBranch %19 + %19 = OpLabel + OpReturnValue %21 + OpFunctionEnd diff --git a/third_party/spirv-cross/shaders-no-opt/asm/frag/discard-impure-function-call.asm.frag b/third_party/spirv-cross/shaders-no-opt/asm/frag/discard-impure-function-call.asm.frag new file mode 100644 index 0000000000..0f039166b0 --- /dev/null +++ b/third_party/spirv-cross/shaders-no-opt/asm/frag/discard-impure-function-call.asm.frag @@ -0,0 +1,59 @@ +; SPIR-V +; Version: 1.0 +; Generator: Khronos Glslang Reference Front End; 7 +; Bound: 34 +; Schema: 0 + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %vA %FragColor + OpExecutionMode %main OriginUpperLeft + OpSource GLSL 450 + OpName %main "main" + OpName %foobar_i1_ "foobar(i1;" + OpName %a "a" + OpName %a_0 "a" + OpName %vA "vA" + OpName %param "param" + OpName %FragColor "FragColor" + OpDecorate %vA Flat + OpDecorate %vA Location 0 + OpDecorate %FragColor Location 0 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %int = OpTypeInt 32 1 +%_ptr_Function_int = OpTypePointer Function %int + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 + %10 = OpTypeFunction %v4float %_ptr_Function_int + %int_0 = OpConstant %int 0 + %bool = OpTypeBool + %float_10 = OpConstant %float 10 + %22 = OpConstantComposite %v4float %float_10 %float_10 %float_10 %float_10 +%_ptr_Function_v4float = OpTypePointer Function %v4float +%_ptr_Input_int = OpTypePointer Input %int + %vA = OpVariable %_ptr_Input_int Input +%_ptr_Output_v4float = OpTypePointer Output %v4float + %FragColor = OpVariable %_ptr_Output_v4float Output + %main = OpFunction %void None %3 + %5 = OpLabel + %a_0 = OpVariable %_ptr_Function_v4float Function + %param = OpVariable %_ptr_Function_int Function + %30 = OpLoad %int %vA + OpStore %param %30 + %31 = OpFunctionCall %v4float %foobar_i1_ %param + OpStore %FragColor %22 + OpReturn + OpFunctionEnd + %foobar_i1_ = OpFunction %v4float None %10 + %a = OpFunctionParameter %_ptr_Function_int + %13 = OpLabel + %14 = OpLoad %int %a + %17 = OpSLessThan %bool %14 %int_0 + OpSelectionMerge %19 None + OpBranchConditional %17 %18 %19 + %18 = OpLabel + OpKill + %19 = OpLabel + OpReturnValue %22 + OpFunctionEnd diff --git a/third_party/spirv-cross/shaders-no-opt/asm/frag/do-while-continue-phi.asm.invalid.frag b/third_party/spirv-cross/shaders-no-opt/asm/frag/do-while-continue-phi.asm.invalid.frag new file mode 100644 index 0000000000..97400dfb16 --- /dev/null +++ b/third_party/spirv-cross/shaders-no-opt/asm/frag/do-while-continue-phi.asm.invalid.frag @@ -0,0 +1,64 @@ +; SPIR-V +; Version: 1.0 +; Generator: Khronos Glslang Reference Front End; 7 +; Bound: 42 +; Schema: 0 + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %gl_FragCoord %_GLF_color + OpExecutionMode %main OriginUpperLeft + OpSource ESSL 310 + OpName %main "main" + OpName %gl_FragCoord "gl_FragCoord" + OpName %_GLF_color "_GLF_color" + OpDecorate %gl_FragCoord BuiltIn FragCoord + OpDecorate %_GLF_color Location 0 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 +%_ptr_Input_v4float = OpTypePointer Input %v4float +%gl_FragCoord = OpVariable %_ptr_Input_v4float Input + %uint = OpTypeInt 32 0 + %uint_0 = OpConstant %uint 0 +%_ptr_Input_float = OpTypePointer Input %float + %bool = OpTypeBool + %false = OpConstantFalse %bool +%_ptr_Output_v4float = OpTypePointer Output %v4float + %_GLF_color = OpVariable %_ptr_Output_v4float Output + %float_1 = OpConstant %float 1 + %float_0 = OpConstant %float 0 + %31 = OpConstantComposite %v4float %float_1 %float_0 %float_0 %float_1 + %true = OpConstantTrue %bool + %main = OpFunction %void None %3 + %5 = OpLabel + OpBranch %33 + %33 = OpLabel + OpLoopMerge %32 %35 None + OpBranch %6 + %6 = OpLabel + OpLoopMerge %8 %24 None + OpBranch %7 + %7 = OpLabel + %17 = OpAccessChain %_ptr_Input_float %gl_FragCoord %uint_0 + %18 = OpLoad %float %17 + %22 = OpFOrdNotEqual %bool %18 %18 + OpSelectionMerge %24 None + OpBranchConditional %22 %23 %24 + %23 = OpLabel + OpBranch %8 + %24 = OpLabel + OpBranchConditional %false %6 %8 + %8 = OpLabel + %41 = OpPhi %bool %true %23 %false %24 + OpSelectionMerge %39 None + OpBranchConditional %41 %32 %39 + %39 = OpLabel + OpStore %_GLF_color %31 + OpBranch %32 + %35 = OpLabel + OpBranch %33 + %32 = OpLabel + OpReturn + OpFunctionEnd diff --git a/third_party/spirv-cross/shaders-no-opt/asm/frag/empty-struct-in-struct.asm.frag b/third_party/spirv-cross/shaders-no-opt/asm/frag/empty-struct-in-struct.asm.frag new file mode 100644 index 0000000000..a9650ddbb6 --- /dev/null +++ b/third_party/spirv-cross/shaders-no-opt/asm/frag/empty-struct-in-struct.asm.frag @@ -0,0 +1,61 @@ +; SPIR-V +; Version: 1.2 +; Generator: Khronos; 0 +; Bound: 43 +; Schema: 0 + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %EntryPoint_Main "main" + OpExecutionMode %EntryPoint_Main OriginUpperLeft + OpSource Unknown 100 + OpName %EmptyStructTest "EmptyStructTest" + OpName %EmptyStruct2Test "EmptyStruct2Test" + OpName %GetValue "GetValue" + OpName %GetValue2 "GetValue" + OpName %self "self" + OpName %self2 "self" + OpName %emptyStruct "emptyStruct" + OpName %value "value" + OpName %EntryPoint_Main "EntryPoint_Main" + +%EmptyStructTest = OpTypeStruct +%EmptyStruct2Test = OpTypeStruct %EmptyStructTest +%_ptr_Function_EmptyStruct2Test = OpTypePointer Function %EmptyStruct2Test + %float = OpTypeFloat 32 +%_ptr_Function_float = OpTypePointer Function %float + %5 = OpTypeFunction %float %_ptr_Function_EmptyStruct2Test + %6 = OpTypeFunction %float %EmptyStruct2Test + %void = OpTypeVoid +%_ptr_Function_void = OpTypePointer Function %void + %8 = OpTypeFunction %void %_ptr_Function_EmptyStruct2Test + %9 = OpTypeFunction %void + %float_0 = OpConstant %float 0 + %value4 = OpConstantNull %EmptyStruct2Test + + %GetValue = OpFunction %float None %5 + %self = OpFunctionParameter %_ptr_Function_EmptyStruct2Test + %13 = OpLabel + OpReturnValue %float_0 + OpFunctionEnd + + %GetValue2 = OpFunction %float None %6 + %self2 = OpFunctionParameter %EmptyStruct2Test + %14 = OpLabel + OpReturnValue %float_0 + OpFunctionEnd + +%EntryPoint_Main = OpFunction %void None %9 + %37 = OpLabel + %emptyStruct = OpVariable %_ptr_Function_EmptyStruct2Test Function + %18 = OpVariable %_ptr_Function_EmptyStruct2Test Function + %value = OpVariable %_ptr_Function_float Function + %value2 = OpCompositeConstruct %EmptyStructTest + %value3 = OpCompositeConstruct %EmptyStruct2Test %value2 + %22 = OpFunctionCall %float %GetValue %emptyStruct + %23 = OpFunctionCall %float %GetValue2 %value3 + %24 = OpFunctionCall %float %GetValue2 %value4 + OpStore %value %22 + OpStore %value %23 + OpStore %value %24 + OpReturn + OpFunctionEnd diff --git a/third_party/spirv-cross/shaders-no-opt/asm/frag/for-loop-dedicated-merge-block-inverted.asm.frag b/third_party/spirv-cross/shaders-no-opt/asm/frag/for-loop-dedicated-merge-block-inverted.asm.invalid.frag similarity index 100% rename from third_party/spirv-cross/shaders-no-opt/asm/frag/for-loop-dedicated-merge-block-inverted.asm.frag rename to third_party/spirv-cross/shaders-no-opt/asm/frag/for-loop-dedicated-merge-block-inverted.asm.invalid.frag diff --git a/third_party/spirv-cross/shaders-no-opt/asm/frag/for-loop-dedicated-merge-block-non-inverted.asm.frag b/third_party/spirv-cross/shaders-no-opt/asm/frag/for-loop-dedicated-merge-block-non-inverted.asm.invalid.frag similarity index 100% rename from third_party/spirv-cross/shaders-no-opt/asm/frag/for-loop-dedicated-merge-block-non-inverted.asm.frag rename to third_party/spirv-cross/shaders-no-opt/asm/frag/for-loop-dedicated-merge-block-non-inverted.asm.invalid.frag diff --git a/third_party/spirv-cross/shaders-no-opt/asm/frag/ldexp-uint-exponent.asm.frag b/third_party/spirv-cross/shaders-no-opt/asm/frag/ldexp-uint-exponent.asm.frag new file mode 100644 index 0000000000..9baebc20f4 --- /dev/null +++ b/third_party/spirv-cross/shaders-no-opt/asm/frag/ldexp-uint-exponent.asm.frag @@ -0,0 +1,36 @@ +; SPIR-V +; Version: 1.0 +; Generator: Khronos Glslang Reference Front End; 7 +; Bound: 20 +; Schema: 0 + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %_GLF_color + OpExecutionMode %main OriginUpperLeft + OpSource ESSL 310 + OpName %main "main" + OpName %_GLF_color "_GLF_color" + OpDecorate %_GLF_color Location 0 + OpDecorate %18 RelaxedPrecision + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 +%_ptr_Output_v4float = OpTypePointer Output %v4float + %_GLF_color = OpVariable %_ptr_Output_v4float Output + %float_1 = OpConstant %float 1 + %11 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1 + %uint = OpTypeInt 32 0 + %v4uint = OpTypeVector %uint 4 + %uint_1 = OpConstant %uint 1 + %15 = OpConstantComposite %v4uint %uint_1 %uint_1 %uint_1 %uint_1 + %int = OpTypeInt 32 1 + %v4int = OpTypeVector %int 4 + %main = OpFunction %void None %3 + %5 = OpLabel + %18 = OpBitCount %v4uint %15 + %19 = OpExtInst %v4float %1 Ldexp %11 %18 + OpStore %_GLF_color %19 + OpReturn + OpFunctionEnd diff --git a/third_party/spirv-cross/shaders/asm/frag/loop-merge-to-continue.asm.frag b/third_party/spirv-cross/shaders-no-opt/asm/frag/loop-merge-to-continue.asm.invalid.frag similarity index 100% rename from third_party/spirv-cross/shaders/asm/frag/loop-merge-to-continue.asm.frag rename to third_party/spirv-cross/shaders-no-opt/asm/frag/loop-merge-to-continue.asm.invalid.frag diff --git a/third_party/spirv-cross/shaders-no-opt/asm/frag/pixel-interlock-callstack.asm.frag b/third_party/spirv-cross/shaders-no-opt/asm/frag/pixel-interlock-callstack.asm.frag new file mode 100644 index 0000000000..ebd8d6bab7 --- /dev/null +++ b/third_party/spirv-cross/shaders-no-opt/asm/frag/pixel-interlock-callstack.asm.frag @@ -0,0 +1,89 @@ +; SPIR-V +; Version: 1.0 +; Generator: Khronos Glslang Reference Front End; 7 +; Bound: 45 +; Schema: 0 + OpCapability Shader + OpCapability FragmentShaderPixelInterlockEXT + OpExtension "SPV_EXT_fragment_shader_interlock" + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %gl_FragCoord + OpExecutionMode %main OriginUpperLeft + OpExecutionMode %main PixelInterlockOrderedEXT + OpSource GLSL 450 + OpSourceExtension "GL_ARB_fragment_shader_interlock" + OpName %main "main" + OpName %callee2_ "callee2(" + OpName %callee_ "callee(" + OpName %SSBO1 "SSBO1" + OpMemberName %SSBO1 0 "values1" + OpName %_ "" + OpName %gl_FragCoord "gl_FragCoord" + OpName %SSBO0 "SSBO0" + OpMemberName %SSBO0 0 "values0" + OpName %__0 "" + OpDecorate %_runtimearr_uint ArrayStride 4 + OpMemberDecorate %SSBO1 0 Offset 0 + OpDecorate %SSBO1 BufferBlock + OpDecorate %_ DescriptorSet 0 + OpDecorate %_ Binding 1 + OpDecorate %gl_FragCoord BuiltIn FragCoord + OpDecorate %_runtimearr_uint_0 ArrayStride 4 + OpMemberDecorate %SSBO0 0 Offset 0 + OpDecorate %SSBO0 BufferBlock + OpDecorate %__0 DescriptorSet 0 + OpDecorate %__0 Binding 0 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %uint = OpTypeInt 32 0 +%_runtimearr_uint = OpTypeRuntimeArray %uint + %SSBO1 = OpTypeStruct %_runtimearr_uint +%_ptr_Uniform_SSBO1 = OpTypePointer Uniform %SSBO1 + %_ = OpVariable %_ptr_Uniform_SSBO1 Uniform + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 +%_ptr_Input_v4float = OpTypePointer Input %v4float +%gl_FragCoord = OpVariable %_ptr_Input_v4float Input + %uint_0 = OpConstant %uint 0 +%_ptr_Input_float = OpTypePointer Input %float + %uint_1 = OpConstant %uint 1 +%_ptr_Uniform_uint = OpTypePointer Uniform %uint +%_runtimearr_uint_0 = OpTypeRuntimeArray %uint + %SSBO0 = OpTypeStruct %_runtimearr_uint_0 +%_ptr_Uniform_SSBO0 = OpTypePointer Uniform %SSBO0 + %__0 = OpVariable %_ptr_Uniform_SSBO0 Uniform + %main = OpFunction %void None %3 + %5 = OpLabel + %44 = OpFunctionCall %void %callee_ + OpReturn + OpFunctionEnd + %callee2_ = OpFunction %void None %3 + %7 = OpLabel + %23 = OpAccessChain %_ptr_Input_float %gl_FragCoord %uint_0 + %24 = OpLoad %float %23 + %25 = OpConvertFToS %int %24 + %28 = OpAccessChain %_ptr_Uniform_uint %_ %int_0 %25 + %29 = OpLoad %uint %28 + %30 = OpIAdd %uint %29 %uint_1 + %31 = OpAccessChain %_ptr_Uniform_uint %_ %int_0 %25 + OpStore %31 %30 + OpReturn + OpFunctionEnd + %callee_ = OpFunction %void None %3 + %9 = OpLabel + %36 = OpAccessChain %_ptr_Input_float %gl_FragCoord %uint_0 + %37 = OpLoad %float %36 + %38 = OpConvertFToS %int %37 + %39 = OpAccessChain %_ptr_Uniform_uint %__0 %int_0 %38 + %40 = OpLoad %uint %39 + %41 = OpIAdd %uint %40 %uint_1 + %42 = OpAccessChain %_ptr_Uniform_uint %__0 %int_0 %38 + OpStore %42 %41 + OpBeginInvocationInterlockEXT + %43 = OpFunctionCall %void %callee2_ + OpEndInvocationInterlockEXT + OpReturn + OpFunctionEnd diff --git a/third_party/spirv-cross/shaders-no-opt/asm/frag/pixel-interlock-control-flow.asm.frag b/third_party/spirv-cross/shaders-no-opt/asm/frag/pixel-interlock-control-flow.asm.frag new file mode 100644 index 0000000000..69b8f91120 --- /dev/null +++ b/third_party/spirv-cross/shaders-no-opt/asm/frag/pixel-interlock-control-flow.asm.frag @@ -0,0 +1,121 @@ +; SPIR-V +; Version: 1.0 +; Generator: Khronos Glslang Reference Front End; 7 +; Bound: 45 +; Schema: 0 + OpCapability Shader + OpCapability FragmentShaderPixelInterlockEXT + OpExtension "SPV_EXT_fragment_shader_interlock" + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %gl_FragCoord + OpExecutionMode %main OriginUpperLeft + OpExecutionMode %main PixelInterlockOrderedEXT + OpSource GLSL 450 + OpSourceExtension "GL_ARB_fragment_shader_interlock" + OpName %main "main" + OpName %callee2_ "callee2(" + OpName %callee_ "callee(" + OpName %SSBO1 "SSBO1" + OpMemberName %SSBO1 0 "values1" + OpName %_ "" + OpName %gl_FragCoord "gl_FragCoord" + OpName %SSBO0 "SSBO0" + OpMemberName %SSBO0 0 "values0" + OpName %__0 "" + OpDecorate %_runtimearr_uint ArrayStride 4 + OpMemberDecorate %SSBO1 0 Offset 0 + OpDecorate %SSBO1 BufferBlock + OpDecorate %_ DescriptorSet 0 + OpDecorate %_ Binding 1 + OpDecorate %gl_FragCoord BuiltIn FragCoord + OpDecorate %_runtimearr_uint_0 ArrayStride 4 + OpMemberDecorate %SSBO0 0 Offset 0 + OpDecorate %SSBO0 BufferBlock + OpDecorate %__0 DescriptorSet 0 + OpDecorate %__0 Binding 0 + + OpMemberDecorate %SSBO2 0 Offset 0 + OpDecorate %SSBO2 BufferBlock + OpDecorate %ssbo2 DescriptorSet 0 + OpDecorate %ssbo2 Binding 2 + + %void = OpTypeVoid + %3 = OpTypeFunction %void + %uint = OpTypeInt 32 0 +%_runtimearr_uint = OpTypeRuntimeArray %uint + %SSBO1 = OpTypeStruct %_runtimearr_uint + %SSBO2 = OpTypeStruct %_runtimearr_uint +%_ptr_Uniform_SSBO1 = OpTypePointer Uniform %SSBO1 +%_ptr_Uniform_SSBO2 = OpTypePointer Uniform %SSBO2 + %_ = OpVariable %_ptr_Uniform_SSBO1 Uniform + %ssbo2 = OpVariable %_ptr_Uniform_SSBO2 Uniform + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 + %uint_4 = OpConstant %uint 4 + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 + %bool = OpTypeBool + %true = OpConstantTrue %bool +%_ptr_Input_v4float = OpTypePointer Input %v4float +%gl_FragCoord = OpVariable %_ptr_Input_v4float Input + %uint_0 = OpConstant %uint 0 +%_ptr_Input_float = OpTypePointer Input %float + %uint_1 = OpConstant %uint 1 +%_ptr_Uniform_uint = OpTypePointer Uniform %uint +%_runtimearr_uint_0 = OpTypeRuntimeArray %uint + %SSBO0 = OpTypeStruct %_runtimearr_uint_0 +%_ptr_Uniform_SSBO0 = OpTypePointer Uniform %SSBO0 + %__0 = OpVariable %_ptr_Uniform_SSBO0 Uniform + %main = OpFunction %void None %3 + %5 = OpLabel + %44 = OpFunctionCall %void %callee_ + %callee3_res = OpFunctionCall %void %callee3_ + OpReturn + OpFunctionEnd + + %callee3_ = OpFunction %void None %3 + %calle3_block = OpLabel + %frag_coord_x_ptr = OpAccessChain %_ptr_Input_float %gl_FragCoord %uint_0 + %frag_coord_x = OpLoad %float %frag_coord_x_ptr + %frag_coord_int = OpConvertFToS %int %frag_coord_x + %ssbo_ptr = OpAccessChain %_ptr_Uniform_uint %ssbo2 %int_0 %frag_coord_int + OpStore %ssbo_ptr %uint_4 + OpReturn + OpFunctionEnd + + %callee2_ = OpFunction %void None %3 + %7 = OpLabel + %23 = OpAccessChain %_ptr_Input_float %gl_FragCoord %uint_0 + %24 = OpLoad %float %23 + %25 = OpConvertFToS %int %24 + %28 = OpAccessChain %_ptr_Uniform_uint %_ %int_0 %25 + %29 = OpLoad %uint %28 + %30 = OpIAdd %uint %29 %uint_1 + %31 = OpAccessChain %_ptr_Uniform_uint %_ %int_0 %25 + OpStore %31 %30 + OpReturn + OpFunctionEnd + %callee_ = OpFunction %void None %3 + %9 = OpLabel + %36 = OpAccessChain %_ptr_Input_float %gl_FragCoord %uint_0 + %37 = OpLoad %float %36 + %38 = OpConvertFToS %int %37 + %39 = OpAccessChain %_ptr_Uniform_uint %__0 %int_0 %38 + %40 = OpLoad %uint %39 + %41 = OpIAdd %uint %40 %uint_1 + %42 = OpAccessChain %_ptr_Uniform_uint %__0 %int_0 %38 + OpStore %42 %41 + %43 = OpFunctionCall %void %callee2_ + + OpSelectionMerge %merged_block None + OpBranchConditional %true %dummy_block %merged_block + %dummy_block = OpLabel + OpBeginInvocationInterlockEXT + OpEndInvocationInterlockEXT + OpBranch %merged_block + + %merged_block = OpLabel + OpReturn + + OpFunctionEnd diff --git a/third_party/spirv-cross/shaders-no-opt/asm/frag/pixel-interlock-split-functions.asm.frag b/third_party/spirv-cross/shaders-no-opt/asm/frag/pixel-interlock-split-functions.asm.frag new file mode 100644 index 0000000000..7c0fe9a2b2 --- /dev/null +++ b/third_party/spirv-cross/shaders-no-opt/asm/frag/pixel-interlock-split-functions.asm.frag @@ -0,0 +1,102 @@ +; SPIR-V +; Version: 1.0 +; Generator: Khronos Glslang Reference Front End; 7 +; Bound: 45 +; Schema: 0 + OpCapability Shader + OpCapability FragmentShaderPixelInterlockEXT + OpExtension "SPV_EXT_fragment_shader_interlock" + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %gl_FragCoord + OpExecutionMode %main OriginUpperLeft + OpExecutionMode %main PixelInterlockOrderedEXT + OpSource GLSL 450 + OpSourceExtension "GL_ARB_fragment_shader_interlock" + OpName %main "main" + OpName %callee2_ "callee2(" + OpName %callee_ "callee(" + OpName %SSBO1 "SSBO1" + OpMemberName %SSBO1 0 "values1" + OpName %_ "" + OpName %gl_FragCoord "gl_FragCoord" + OpName %SSBO0 "SSBO0" + OpMemberName %SSBO0 0 "values0" + OpName %__0 "" + OpDecorate %_runtimearr_uint ArrayStride 4 + OpMemberDecorate %SSBO1 0 Offset 0 + OpDecorate %SSBO1 BufferBlock + OpDecorate %_ DescriptorSet 0 + OpDecorate %_ Binding 1 + OpDecorate %gl_FragCoord BuiltIn FragCoord + OpDecorate %_runtimearr_uint_0 ArrayStride 4 + OpMemberDecorate %SSBO0 0 Offset 0 + OpDecorate %SSBO0 BufferBlock + OpDecorate %__0 DescriptorSet 0 + OpDecorate %__0 Binding 0 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %uint = OpTypeInt 32 0 +%_runtimearr_uint = OpTypeRuntimeArray %uint + %SSBO1 = OpTypeStruct %_runtimearr_uint +%_ptr_Uniform_SSBO1 = OpTypePointer Uniform %SSBO1 + %_ = OpVariable %_ptr_Uniform_SSBO1 Uniform + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 +%_ptr_Input_v4float = OpTypePointer Input %v4float +%gl_FragCoord = OpVariable %_ptr_Input_v4float Input + %uint_0 = OpConstant %uint 0 +%_ptr_Input_float = OpTypePointer Input %float + %uint_1 = OpConstant %uint 1 +%_ptr_Uniform_uint = OpTypePointer Uniform %uint +%_runtimearr_uint_0 = OpTypeRuntimeArray %uint + %SSBO0 = OpTypeStruct %_runtimearr_uint_0 +%_ptr_Uniform_SSBO0 = OpTypePointer Uniform %SSBO0 + %__0 = OpVariable %_ptr_Uniform_SSBO0 Uniform + %main = OpFunction %void None %3 + %5 = OpLabel + %44 = OpFunctionCall %void %callee_ + %call3res = OpFunctionCall %void %callee3_ + %call4res = OpFunctionCall %void %callee4_ + OpReturn + OpFunctionEnd + + %callee3_ = OpFunction %void None %3 + %begin3 = OpLabel + OpBeginInvocationInterlockEXT + OpReturn + OpFunctionEnd + + %callee4_ = OpFunction %void None %3 + %begin4 = OpLabel + OpEndInvocationInterlockEXT + OpReturn + OpFunctionEnd + + %callee2_ = OpFunction %void None %3 + %7 = OpLabel + %23 = OpAccessChain %_ptr_Input_float %gl_FragCoord %uint_0 + %24 = OpLoad %float %23 + %25 = OpConvertFToS %int %24 + %28 = OpAccessChain %_ptr_Uniform_uint %_ %int_0 %25 + %29 = OpLoad %uint %28 + %30 = OpIAdd %uint %29 %uint_1 + %31 = OpAccessChain %_ptr_Uniform_uint %_ %int_0 %25 + OpStore %31 %30 + OpReturn + OpFunctionEnd + %callee_ = OpFunction %void None %3 + %9 = OpLabel + %36 = OpAccessChain %_ptr_Input_float %gl_FragCoord %uint_0 + %37 = OpLoad %float %36 + %38 = OpConvertFToS %int %37 + %39 = OpAccessChain %_ptr_Uniform_uint %__0 %int_0 %38 + %40 = OpLoad %uint %39 + %41 = OpIAdd %uint %40 %uint_1 + %42 = OpAccessChain %_ptr_Uniform_uint %__0 %int_0 %38 + OpStore %42 %41 + %43 = OpFunctionCall %void %callee2_ + OpReturn + OpFunctionEnd diff --git a/third_party/spirv-cross/shaders/asm/frag/selection-merge-to-continue.asm.frag b/third_party/spirv-cross/shaders-no-opt/asm/frag/selection-merge-to-continue.asm.invalid.frag similarity index 100% rename from third_party/spirv-cross/shaders/asm/frag/selection-merge-to-continue.asm.frag rename to third_party/spirv-cross/shaders-no-opt/asm/frag/selection-merge-to-continue.asm.invalid.frag diff --git a/third_party/spirv-cross/shaders-no-opt/asm/frag/subgroup-arithmetic-cast.nocompat.vk.asm.frag b/third_party/spirv-cross/shaders-no-opt/asm/frag/subgroup-arithmetic-cast.nocompat.vk.asm.frag new file mode 100644 index 0000000000..a47c6b785f --- /dev/null +++ b/third_party/spirv-cross/shaders-no-opt/asm/frag/subgroup-arithmetic-cast.nocompat.vk.asm.frag @@ -0,0 +1,65 @@ +; SPIR-V +; Version: 1.3 +; Generator: Khronos Glslang Reference Front End; 8 +; Bound: 78 +; Schema: 0 + OpCapability Shader + OpCapability GroupNonUniform + OpCapability GroupNonUniformArithmetic + OpCapability GroupNonUniformClustered + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %index %FragColor + OpExecutionMode %main OriginUpperLeft + OpSource GLSL 450 + OpSourceExtension "GL_KHR_shader_subgroup_arithmetic" + OpSourceExtension "GL_KHR_shader_subgroup_basic" + OpSourceExtension "GL_KHR_shader_subgroup_clustered" + OpName %main "main" + OpName %index "index" + OpName %FragColor "FragColor" + OpDecorate %index Flat + OpDecorate %index Location 0 + OpDecorate %FragColor Location 0 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %uint = OpTypeInt 32 0 +%_ptr_Function_uint = OpTypePointer Function %uint + %uint_0 = OpConstant %uint 0 + %int = OpTypeInt 32 1 +%_ptr_Input_int = OpTypePointer Input %int + %index = OpVariable %_ptr_Input_int Input + %uint_3 = OpConstant %uint 3 + %uint_4 = OpConstant %uint 4 +%_ptr_Output_uint = OpTypePointer Output %uint + %FragColor = OpVariable %_ptr_Output_uint Output + %main = OpFunction %void None %3 + %5 = OpLabel + %i = OpLoad %int %index + %u = OpBitcast %uint %i + %res0 = OpGroupNonUniformSMin %uint %uint_3 Reduce %i + %res1 = OpGroupNonUniformSMax %uint %uint_3 Reduce %u + %res2 = OpGroupNonUniformUMin %uint %uint_3 Reduce %i + %res3 = OpGroupNonUniformUMax %uint %uint_3 Reduce %u + %res4 = OpGroupNonUniformSMax %uint %uint_3 InclusiveScan %i + %res5 = OpGroupNonUniformSMin %uint %uint_3 InclusiveScan %u + %res6 = OpGroupNonUniformUMax %uint %uint_3 ExclusiveScan %i + %res7 = OpGroupNonUniformUMin %uint %uint_3 ExclusiveScan %u + %res8 = OpGroupNonUniformSMin %uint %uint_3 ClusteredReduce %i %uint_4 + %res9 = OpGroupNonUniformSMax %uint %uint_3 ClusteredReduce %u %uint_4 + %res10 = OpGroupNonUniformUMin %uint %uint_3 ClusteredReduce %i %uint_4 + %res11 = OpGroupNonUniformUMax %uint %uint_3 ClusteredReduce %u %uint_4 + OpStore %FragColor %res0 + OpStore %FragColor %res1 + OpStore %FragColor %res2 + OpStore %FragColor %res3 + OpStore %FragColor %res4 + OpStore %FragColor %res5 + OpStore %FragColor %res6 + OpStore %FragColor %res7 + OpStore %FragColor %res8 + OpStore %FragColor %res9 + OpStore %FragColor %res10 + OpStore %FragColor %res11 + OpReturn + OpFunctionEnd diff --git a/third_party/spirv-cross/shaders-no-opt/asm/frag/switch-block-case-fallthrough.asm.frag b/third_party/spirv-cross/shaders-no-opt/asm/frag/switch-block-case-fallthrough.asm.invalid.frag similarity index 100% rename from third_party/spirv-cross/shaders-no-opt/asm/frag/switch-block-case-fallthrough.asm.frag rename to third_party/spirv-cross/shaders-no-opt/asm/frag/switch-block-case-fallthrough.asm.invalid.frag diff --git a/third_party/spirv-cross/shaders/asm/frag/switch-merge-to-continue.asm.frag b/third_party/spirv-cross/shaders-no-opt/asm/frag/switch-merge-to-continue.asm.invalid.frag similarity index 100% rename from third_party/spirv-cross/shaders/asm/frag/switch-merge-to-continue.asm.frag rename to third_party/spirv-cross/shaders-no-opt/asm/frag/switch-merge-to-continue.asm.invalid.frag diff --git a/third_party/spirv-cross/shaders-no-opt/asm/frag/switch-single-case-multiple-exit-cfg.asm.frag b/third_party/spirv-cross/shaders-no-opt/asm/frag/switch-single-case-multiple-exit-cfg.asm.frag new file mode 100644 index 0000000000..d2bd15a978 --- /dev/null +++ b/third_party/spirv-cross/shaders-no-opt/asm/frag/switch-single-case-multiple-exit-cfg.asm.frag @@ -0,0 +1,57 @@ +; SPIR-V +; Version: 1.0 +; Generator: Khronos Glslang Reference Front End; 7 +; Bound: 54 +; Schema: 0 + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %gl_FragCoord %_GLF_color + OpExecutionMode %main OriginUpperLeft + OpSource ESSL 310 + OpName %main "main" + OpName %gl_FragCoord "gl_FragCoord" + OpName %_GLF_color "_GLF_color" + OpDecorate %gl_FragCoord BuiltIn FragCoord + OpDecorate %_GLF_color Location 0 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 +%_ptr_Input_v4float = OpTypePointer Input %v4float +%gl_FragCoord = OpVariable %_ptr_Input_v4float Input + %uint = OpTypeInt 32 0 + %uint_0 = OpConstant %uint 0 +%_ptr_Input_float = OpTypePointer Input %float + %bool = OpTypeBool + %v2float = OpTypeVector %float 2 +%_ptr_Output_v4float = OpTypePointer Output %v4float + %_GLF_color = OpVariable %_ptr_Output_v4float Output + %float_1 = OpConstant %float 1 + %52 = OpUndef %v2float + %main = OpFunction %void None %3 + %5 = OpLabel + OpSelectionMerge %9 None + OpSwitch %int_0 %8 + %8 = OpLabel + %17 = OpAccessChain %_ptr_Input_float %gl_FragCoord %uint_0 + %18 = OpLoad %float %17 + %22 = OpFOrdNotEqual %bool %18 %18 + OpSelectionMerge %24 None + OpBranchConditional %22 %23 %24 + %23 = OpLabel + OpBranch %9 + %24 = OpLabel + %33 = OpCompositeExtract %float %52 1 + %51 = OpCompositeInsert %v2float %33 %52 1 + OpBranch %9 + %9 = OpLabel + %53 = OpPhi %v2float %52 %23 %51 %24 + %42 = OpCompositeExtract %float %53 0 + %43 = OpCompositeExtract %float %53 1 + %48 = OpCompositeConstruct %v4float %42 %43 %float_1 %float_1 + OpStore %_GLF_color %48 + OpReturn + OpFunctionEnd diff --git a/third_party/spirv-cross/shaders-no-opt/asm/frag/unordered-compare.asm.frag b/third_party/spirv-cross/shaders-no-opt/asm/frag/unordered-compare.asm.frag new file mode 100644 index 0000000000..4ad8fc5abb --- /dev/null +++ b/third_party/spirv-cross/shaders-no-opt/asm/frag/unordered-compare.asm.frag @@ -0,0 +1,177 @@ +; SPIR-V +; Version: 1.0 +; Generator: Khronos Glslang Reference Front End; 7 +; Bound: 132 +; Schema: 0 + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %A %B %FragColor + OpExecutionMode %main OriginUpperLeft + OpSource GLSL 450 + OpName %main "main" + OpName %test_vector_ "test_vector(" + OpName %test_scalar_ "test_scalar(" + OpName %le "le" + OpName %A "A" + OpName %B "B" + OpName %leq "leq" + OpName %ge "ge" + OpName %geq "geq" + OpName %eq "eq" + OpName %neq "neq" + OpName %le_0 "le" + OpName %leq_0 "leq" + OpName %ge_0 "ge" + OpName %geq_0 "geq" + OpName %eq_0 "eq" + OpName %neq_0 "neq" + OpName %FragColor "FragColor" + OpDecorate %A Location 0 + OpDecorate %B Location 1 + OpDecorate %FragColor Location 0 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 + %8 = OpTypeFunction %v4float + %11 = OpTypeFunction %float + %bool = OpTypeBool + %v4bool = OpTypeVector %bool 4 +%_ptr_Function_v4bool = OpTypePointer Function %v4bool +%_ptr_Input_v4float = OpTypePointer Input %v4float + %A = OpVariable %_ptr_Input_v4float Input + %B = OpVariable %_ptr_Input_v4float Input + %float_0 = OpConstant %float 0 + %float_1 = OpConstant %float 1 + %47 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0 + %48 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1 +%_ptr_Function_bool = OpTypePointer Function %bool + %uint = OpTypeInt 32 0 + %uint_0 = OpConstant %uint 0 +%_ptr_Input_float = OpTypePointer Input %float +%_ptr_Output_v4float = OpTypePointer Output %v4float + %FragColor = OpVariable %_ptr_Output_v4float Output + %main = OpFunction %void None %3 + %5 = OpLabel + %128 = OpFunctionCall %v4float %test_vector_ + %129 = OpFunctionCall %float %test_scalar_ + %130 = OpCompositeConstruct %v4float %129 %129 %129 %129 + %131 = OpFAdd %v4float %128 %130 + OpStore %FragColor %131 + OpReturn + OpFunctionEnd +%test_vector_ = OpFunction %v4float None %8 + %10 = OpLabel + %le = OpVariable %_ptr_Function_v4bool Function + %leq = OpVariable %_ptr_Function_v4bool Function + %ge = OpVariable %_ptr_Function_v4bool Function + %geq = OpVariable %_ptr_Function_v4bool Function + %eq = OpVariable %_ptr_Function_v4bool Function + %neq = OpVariable %_ptr_Function_v4bool Function + %20 = OpLoad %v4float %A + %22 = OpLoad %v4float %B + %23 = OpFUnordLessThan %v4bool %20 %22 + OpStore %le %23 + %25 = OpLoad %v4float %A + %26 = OpLoad %v4float %B + %27 = OpFUnordLessThanEqual %v4bool %25 %26 + OpStore %leq %27 + %29 = OpLoad %v4float %A + %30 = OpLoad %v4float %B + %31 = OpFUnordGreaterThan %v4bool %29 %30 + OpStore %ge %31 + %33 = OpLoad %v4float %A + %34 = OpLoad %v4float %B + %35 = OpFUnordGreaterThanEqual %v4bool %33 %34 + OpStore %geq %35 + %37 = OpLoad %v4float %A + %38 = OpLoad %v4float %B + %39 = OpFUnordEqual %v4bool %37 %38 + OpStore %eq %39 + %41 = OpLoad %v4float %A + %42 = OpLoad %v4float %B + %43 = OpFUnordNotEqual %v4bool %41 %42 + OpStore %neq %43 + %44 = OpLoad %v4bool %le + %49 = OpSelect %v4float %44 %48 %47 + %50 = OpLoad %v4bool %leq + %51 = OpSelect %v4float %50 %48 %47 + %52 = OpFAdd %v4float %49 %51 + %53 = OpLoad %v4bool %ge + %54 = OpSelect %v4float %53 %48 %47 + %55 = OpFAdd %v4float %52 %54 + %56 = OpLoad %v4bool %geq + %57 = OpSelect %v4float %56 %48 %47 + %58 = OpFAdd %v4float %55 %57 + %59 = OpLoad %v4bool %eq + %60 = OpSelect %v4float %59 %48 %47 + %61 = OpFAdd %v4float %58 %60 + %62 = OpLoad %v4bool %neq + %63 = OpSelect %v4float %62 %48 %47 + %64 = OpFAdd %v4float %61 %63 + OpReturnValue %64 + OpFunctionEnd +%test_scalar_ = OpFunction %float None %11 + %13 = OpLabel + %le_0 = OpVariable %_ptr_Function_bool Function + %leq_0 = OpVariable %_ptr_Function_bool Function + %ge_0 = OpVariable %_ptr_Function_bool Function + %geq_0 = OpVariable %_ptr_Function_bool Function + %eq_0 = OpVariable %_ptr_Function_bool Function + %neq_0 = OpVariable %_ptr_Function_bool Function + %72 = OpAccessChain %_ptr_Input_float %A %uint_0 + %73 = OpLoad %float %72 + %74 = OpAccessChain %_ptr_Input_float %B %uint_0 + %75 = OpLoad %float %74 + %76 = OpFUnordLessThan %bool %73 %75 + OpStore %le_0 %76 + %78 = OpAccessChain %_ptr_Input_float %A %uint_0 + %79 = OpLoad %float %78 + %80 = OpAccessChain %_ptr_Input_float %B %uint_0 + %81 = OpLoad %float %80 + %82 = OpFUnordLessThanEqual %bool %79 %81 + OpStore %leq_0 %82 + %84 = OpAccessChain %_ptr_Input_float %A %uint_0 + %85 = OpLoad %float %84 + %86 = OpAccessChain %_ptr_Input_float %B %uint_0 + %87 = OpLoad %float %86 + %88 = OpFUnordGreaterThan %bool %85 %87 + OpStore %ge_0 %88 + %90 = OpAccessChain %_ptr_Input_float %A %uint_0 + %91 = OpLoad %float %90 + %92 = OpAccessChain %_ptr_Input_float %B %uint_0 + %93 = OpLoad %float %92 + %94 = OpFUnordGreaterThanEqual %bool %91 %93 + OpStore %geq_0 %94 + %96 = OpAccessChain %_ptr_Input_float %A %uint_0 + %97 = OpLoad %float %96 + %98 = OpAccessChain %_ptr_Input_float %B %uint_0 + %99 = OpLoad %float %98 + %100 = OpFUnordEqual %bool %97 %99 + OpStore %eq_0 %100 + %102 = OpAccessChain %_ptr_Input_float %A %uint_0 + %103 = OpLoad %float %102 + %104 = OpAccessChain %_ptr_Input_float %B %uint_0 + %105 = OpLoad %float %104 + %106 = OpFUnordNotEqual %bool %103 %105 + OpStore %neq_0 %106 + %107 = OpLoad %bool %le_0 + %108 = OpSelect %float %107 %float_1 %float_0 + %109 = OpLoad %bool %leq_0 + %110 = OpSelect %float %109 %float_1 %float_0 + %111 = OpFAdd %float %108 %110 + %112 = OpLoad %bool %ge_0 + %113 = OpSelect %float %112 %float_1 %float_0 + %114 = OpFAdd %float %111 %113 + %115 = OpLoad %bool %geq_0 + %116 = OpSelect %float %115 %float_1 %float_0 + %117 = OpFAdd %float %114 %116 + %118 = OpLoad %bool %eq_0 + %119 = OpSelect %float %118 %float_1 %float_0 + %120 = OpFAdd %float %117 %119 + %121 = OpLoad %bool %neq_0 + %122 = OpSelect %float %121 %float_1 %float_0 + %123 = OpFAdd %float %120 %122 + OpReturnValue %123 + OpFunctionEnd diff --git a/third_party/spirv-cross/shaders-no-opt/asm/frag/vector-extract-dynamic-spec-constant.asm.frag b/third_party/spirv-cross/shaders-no-opt/asm/frag/vector-extract-dynamic-spec-constant.asm.frag new file mode 100644 index 0000000000..dda5fc4034 --- /dev/null +++ b/third_party/spirv-cross/shaders-no-opt/asm/frag/vector-extract-dynamic-spec-constant.asm.frag @@ -0,0 +1,49 @@ +; SPIR-V +; Version: 1.0 +; Generator: Khronos Glslang Reference Front End; 7 +; Bound: 27 +; Schema: 0 + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %FragColor %vColor + OpExecutionMode %main OriginUpperLeft + OpSource GLSL 450 + OpName %main "main" + OpName %FragColor "FragColor" + OpName %vColor "vColor" + OpName %omap_r "omap_r" + OpName %omap_g "omap_g" + OpName %omap_b "omap_b" + OpName %omap_a "omap_a" + OpDecorate %FragColor Location 0 + OpDecorate %vColor Location 0 + OpDecorate %omap_r SpecId 0 + OpDecorate %omap_g SpecId 1 + OpDecorate %omap_b SpecId 2 + OpDecorate %omap_a SpecId 3 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 +%_ptr_Output_v4float = OpTypePointer Output %v4float + %FragColor = OpVariable %_ptr_Output_v4float Output +%_ptr_Input_v4float = OpTypePointer Input %v4float + %vColor = OpVariable %_ptr_Input_v4float Input + %int = OpTypeInt 32 1 + %omap_r = OpSpecConstant %int 0 +%_ptr_Input_float = OpTypePointer Input %float + %omap_g = OpSpecConstant %int 1 + %omap_b = OpSpecConstant %int 2 + %omap_a = OpSpecConstant %int 3 + %main = OpFunction %void None %3 + %5 = OpLabel + %loaded = OpLoad %v4float %vColor + %r = OpVectorExtractDynamic %float %loaded %omap_r + %g = OpVectorExtractDynamic %float %loaded %omap_g + %b = OpVectorExtractDynamic %float %loaded %omap_b + %a = OpVectorExtractDynamic %float %loaded %omap_a + %rgba = OpCompositeConstruct %v4float %r %g %b %a + OpStore %FragColor %rgba + OpReturn + OpFunctionEnd diff --git a/third_party/spirv-cross/shaders/asm/geom/store-uint-layer.invalid.asm.geom b/third_party/spirv-cross/shaders-no-opt/asm/geom/store-uint-layer.invalid.asm.geom similarity index 100% rename from third_party/spirv-cross/shaders/asm/geom/store-uint-layer.invalid.asm.geom rename to third_party/spirv-cross/shaders-no-opt/asm/geom/store-uint-layer.invalid.asm.geom diff --git a/third_party/spirv-cross/shaders/asm/tesc/tess-fixed-input-array-builtin-array.invalid.asm.tesc b/third_party/spirv-cross/shaders-no-opt/asm/tesc/tess-fixed-input-array-builtin-array.invalid.asm.tesc similarity index 100% rename from third_party/spirv-cross/shaders/asm/tesc/tess-fixed-input-array-builtin-array.invalid.asm.tesc rename to third_party/spirv-cross/shaders-no-opt/asm/tesc/tess-fixed-input-array-builtin-array.invalid.asm.tesc diff --git a/third_party/spirv-cross/shaders/comp/bitcast-16bit-1.invalid.comp b/third_party/spirv-cross/shaders-no-opt/comp/bitcast-16bit-1.invalid.comp similarity index 100% rename from third_party/spirv-cross/shaders/comp/bitcast-16bit-1.invalid.comp rename to third_party/spirv-cross/shaders-no-opt/comp/bitcast-16bit-1.invalid.comp diff --git a/third_party/spirv-cross/shaders/comp/bitcast-16bit-2.invalid.comp b/third_party/spirv-cross/shaders-no-opt/comp/bitcast-16bit-2.invalid.comp similarity index 100% rename from third_party/spirv-cross/shaders/comp/bitcast-16bit-2.invalid.comp rename to third_party/spirv-cross/shaders-no-opt/comp/bitcast-16bit-2.invalid.comp diff --git a/third_party/spirv-cross/shaders-no-opt/comp/illegal-struct-name.asm.comp b/third_party/spirv-cross/shaders-no-opt/comp/illegal-struct-name.asm.comp new file mode 100644 index 0000000000..f7a8787d3d --- /dev/null +++ b/third_party/spirv-cross/shaders-no-opt/comp/illegal-struct-name.asm.comp @@ -0,0 +1,62 @@ +; SPIR-V +; Version: 1.0 +; Generator: Khronos Glslang Reference Front End; 8 +; Bound: 31 +; Schema: 0 + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" + OpExecutionMode %main LocalSize 1 1 1 + OpSource GLSL 450 + OpName %main "main" + OpName %Foo "Foo" + OpMemberName %Foo 0 "abs" + OpName %f "f" + OpName %Foo_0 "Foo" + OpMemberName %Foo_0 0 "abs" + OpName %SSBO "SSBO" + OpMemberName %SSBO 0 "foo" + OpMemberName %SSBO 1 "foo2" + OpName %_ "" + OpName %linear "abs" + OpMemberDecorate %Foo_0 0 Offset 0 + OpMemberDecorate %SSBO 0 Offset 0 + OpMemberDecorate %SSBO 1 Offset 4 + OpDecorate %SSBO BufferBlock + OpDecorate %_ DescriptorSet 0 + OpDecorate %_ Binding 0 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %Foo = OpTypeStruct %float +%_ptr_Function_Foo = OpTypePointer Function %Foo + %Foo_0 = OpTypeStruct %float + %SSBO = OpTypeStruct %Foo_0 %Foo_0 +%_ptr_Uniform_SSBO = OpTypePointer Uniform %SSBO + %_ = OpVariable %_ptr_Uniform_SSBO Uniform + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 +%_ptr_Uniform_Foo_0 = OpTypePointer Uniform %Foo_0 +%_ptr_Function_float = OpTypePointer Function %float +%_ptr_Function_int = OpTypePointer Function %int + %int_10 = OpConstant %int 10 + %int_1 = OpConstant %int 1 +%_ptr_Uniform_float = OpTypePointer Uniform %float + %main = OpFunction %void None %3 + %5 = OpLabel + %f = OpVariable %_ptr_Function_Foo Function + %linear = OpVariable %_ptr_Function_int Function + %17 = OpAccessChain %_ptr_Uniform_Foo_0 %_ %int_0 + %18 = OpLoad %Foo_0 %17 + %19 = OpCompositeExtract %float %18 0 + %21 = OpAccessChain %_ptr_Function_float %f %int_0 + OpStore %21 %19 + OpStore %linear %int_10 + %26 = OpLoad %Foo %f + %27 = OpAccessChain %_ptr_Uniform_Foo_0 %_ %int_1 + %28 = OpCompositeExtract %float %26 0 + %30 = OpAccessChain %_ptr_Uniform_float %27 %int_0 + OpStore %30 %28 + OpReturn + OpFunctionEnd diff --git a/third_party/spirv-cross/shaders/comp/inout-struct.invalid.comp b/third_party/spirv-cross/shaders-no-opt/comp/inout-struct.invalid.comp similarity index 100% rename from third_party/spirv-cross/shaders/comp/inout-struct.invalid.comp rename to third_party/spirv-cross/shaders-no-opt/comp/inout-struct.invalid.comp diff --git a/third_party/spirv-cross/shaders/amd/shader_ballot_nonuniform_invocations.invalid.comp b/third_party/spirv-cross/shaders-no-opt/comp/shader_ballot_nonuniform_invocations.invalid.comp similarity index 100% rename from third_party/spirv-cross/shaders/amd/shader_ballot_nonuniform_invocations.invalid.comp rename to third_party/spirv-cross/shaders-no-opt/comp/shader_ballot_nonuniform_invocations.invalid.comp diff --git a/third_party/spirv-cross/shaders/vulkan/comp/struct-packing-scalar.nocompat.invalid.vk.comp b/third_party/spirv-cross/shaders-no-opt/comp/struct-packing-scalar.nocompat.invalid.vk.comp similarity index 100% rename from third_party/spirv-cross/shaders/vulkan/comp/struct-packing-scalar.nocompat.invalid.vk.comp rename to third_party/spirv-cross/shaders-no-opt/comp/struct-packing-scalar.nocompat.invalid.vk.comp diff --git a/third_party/spirv-cross/shaders/vulkan/comp/subgroups.nocompat.invalid.vk.comp b/third_party/spirv-cross/shaders-no-opt/comp/subgroups.nocompat.invalid.vk.comp similarity index 100% rename from third_party/spirv-cross/shaders/vulkan/comp/subgroups.nocompat.invalid.vk.comp rename to third_party/spirv-cross/shaders-no-opt/comp/subgroups.nocompat.invalid.vk.comp diff --git a/third_party/spirv-cross/shaders/frag/16bit-constants.invalid.frag b/third_party/spirv-cross/shaders-no-opt/frag/16bit-constants.invalid.frag similarity index 100% rename from third_party/spirv-cross/shaders/frag/16bit-constants.invalid.frag rename to third_party/spirv-cross/shaders-no-opt/frag/16bit-constants.invalid.frag diff --git a/third_party/spirv-cross/shaders/desktop-only/frag/fp16.invalid.desktop.frag b/third_party/spirv-cross/shaders-no-opt/frag/fp16.invalid.desktop.frag similarity index 100% rename from third_party/spirv-cross/shaders/desktop-only/frag/fp16.invalid.desktop.frag rename to third_party/spirv-cross/shaders-no-opt/frag/fp16.invalid.desktop.frag diff --git a/third_party/spirv-cross/shaders/amd/fragmentMaskFetch_subpassInput.vk.nocompat.invalid.frag b/third_party/spirv-cross/shaders-no-opt/frag/fragmentMaskFetch_subpassInput.vk.nocompat.invalid.frag similarity index 100% rename from third_party/spirv-cross/shaders/amd/fragmentMaskFetch_subpassInput.vk.nocompat.invalid.frag rename to third_party/spirv-cross/shaders-no-opt/frag/fragmentMaskFetch_subpassInput.vk.nocompat.invalid.frag diff --git a/third_party/spirv-cross/shaders/amd/fs.invalid.frag b/third_party/spirv-cross/shaders-no-opt/frag/fs.invalid.frag similarity index 100% rename from third_party/spirv-cross/shaders/amd/fs.invalid.frag rename to third_party/spirv-cross/shaders-no-opt/frag/fs.invalid.frag diff --git a/third_party/spirv-cross/shaders/flatten/multi-dimensional.desktop.invalid.flatten_dim.frag b/third_party/spirv-cross/shaders-no-opt/frag/multi-dimensional.desktop.invalid.flatten_dim.frag similarity index 100% rename from third_party/spirv-cross/shaders/flatten/multi-dimensional.desktop.invalid.flatten_dim.frag rename to third_party/spirv-cross/shaders-no-opt/frag/multi-dimensional.desktop.invalid.flatten_dim.frag diff --git a/third_party/spirv-cross/shaders-no-opt/frag/pixel-interlock-simple-callstack.frag b/third_party/spirv-cross/shaders-no-opt/frag/pixel-interlock-simple-callstack.frag new file mode 100644 index 0000000000..59079fe58b --- /dev/null +++ b/third_party/spirv-cross/shaders-no-opt/frag/pixel-interlock-simple-callstack.frag @@ -0,0 +1,31 @@ +#version 450 +#extension GL_ARB_fragment_shader_interlock : require +layout(pixel_interlock_ordered) in; + +layout(set = 0, binding = 0, std430) buffer SSBO0 +{ + uint values0[]; +}; + +layout(set = 0, binding = 1, std430) buffer SSBO1 +{ + uint values1[]; +}; + +void callee2() +{ + values1[int(gl_FragCoord.x)] += 1; +} + +void callee() +{ + values0[int(gl_FragCoord.x)] += 1; + callee2(); +} + +void main() +{ + beginInvocationInterlockARB(); + callee(); + endInvocationInterlockARB(); +} diff --git a/third_party/spirv-cross/shaders/vulkan/frag/scalar-block-layout-ubo-std430.vk.nocompat.invalid.frag b/third_party/spirv-cross/shaders-no-opt/frag/scalar-block-layout-ubo-std430.vk.nocompat.invalid.frag similarity index 100% rename from third_party/spirv-cross/shaders/vulkan/frag/scalar-block-layout-ubo-std430.vk.nocompat.invalid.frag rename to third_party/spirv-cross/shaders-no-opt/frag/scalar-block-layout-ubo-std430.vk.nocompat.invalid.frag diff --git a/third_party/spirv-cross/shaders-reflection/comp/workgroup-size-spec-constant.comp b/third_party/spirv-cross/shaders-reflection/comp/workgroup-size-spec-constant.comp new file mode 100644 index 0000000000..376a351622 --- /dev/null +++ b/third_party/spirv-cross/shaders-reflection/comp/workgroup-size-spec-constant.comp @@ -0,0 +1,13 @@ +#version 450 + +layout(local_size_x_id = 10, local_size_y_id = 40, local_size_z_id = 60) in; + +layout(std430, set = 0, binding = 0) buffer SSBO +{ + vec4 v; +}; + +void main() +{ + v = vec4(10.0); +} diff --git a/third_party/spirv-cross/shaders-reflection/vert/array-size-reflection.vert b/third_party/spirv-cross/shaders-reflection/vert/array-size-reflection.vert new file mode 100644 index 0000000000..24a4a43831 --- /dev/null +++ b/third_party/spirv-cross/shaders-reflection/vert/array-size-reflection.vert @@ -0,0 +1,13 @@ +#version 450 +layout(constant_id = 0) const int ARR_SIZE = 1; + +layout(binding = 0, set = 1, std140) uniform u_ +{ + vec4 u_0[ARR_SIZE]; +}; + +void main() +{ + gl_Position = u_0[0]; +} + diff --git a/third_party/spirv-cross/shaders-reflection/vert/stride-reflection.vert b/third_party/spirv-cross/shaders-reflection/vert/stride-reflection.vert new file mode 100644 index 0000000000..6e7d96df44 --- /dev/null +++ b/third_party/spirv-cross/shaders-reflection/vert/stride-reflection.vert @@ -0,0 +1,14 @@ +#version 450 + +layout(binding = 0, set = 0, std140) uniform U +{ + vec4 v[4]; + mat4 c[4]; + layout(row_major) mat4 r[4]; +}; + +void main() +{ + gl_Position = v[0]; +} + diff --git a/third_party/spirv-cross/shaders-ue4-no-opt/asm/frag/accesschain-invalid-expression.asm.invalid.frag b/third_party/spirv-cross/shaders-ue4-no-opt/asm/frag/accesschain-invalid-expression.asm.invalid.frag new file mode 100644 index 0000000000..fae211f278 --- /dev/null +++ b/third_party/spirv-cross/shaders-ue4-no-opt/asm/frag/accesschain-invalid-expression.asm.invalid.frag @@ -0,0 +1,1087 @@ +; SPIR-V +; Version: 1.0 +; Generator: Google spiregg; 0 +; Bound: 572 +; Schema: 0 + OpCapability Shader + OpExtension "SPV_GOOGLE_hlsl_functionality1" + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %Main "main" %in_var_TEXCOORD0 %in_var_TEXCOORD7 %in_var_TEXCOORD8 %gl_FragCoord %gl_FrontFacing %out_var_SV_Target0 + OpExecutionMode %Main OriginUpperLeft + OpSource HLSL 600 + OpName %type_View "type.View" + OpMemberName %type_View 0 "View_TranslatedWorldToClip" + OpMemberName %type_View 1 "View_WorldToClip" + OpMemberName %type_View 2 "View_TranslatedWorldToView" + OpMemberName %type_View 3 "View_ViewToTranslatedWorld" + OpMemberName %type_View 4 "View_TranslatedWorldToCameraView" + OpMemberName %type_View 5 "View_CameraViewToTranslatedWorld" + OpMemberName %type_View 6 "View_ViewToClip" + OpMemberName %type_View 7 "View_ViewToClipNoAA" + OpMemberName %type_View 8 "View_ClipToView" + OpMemberName %type_View 9 "View_ClipToTranslatedWorld" + OpMemberName %type_View 10 "View_SVPositionToTranslatedWorld" + OpMemberName %type_View 11 "View_ScreenToWorld" + OpMemberName %type_View 12 "View_ScreenToTranslatedWorld" + OpMemberName %type_View 13 "View_ViewForward" + OpMemberName %type_View 14 "PrePadding_View_844" + OpMemberName %type_View 15 "View_ViewUp" + OpMemberName %type_View 16 "PrePadding_View_860" + OpMemberName %type_View 17 "View_ViewRight" + OpMemberName %type_View 18 "PrePadding_View_876" + OpMemberName %type_View 19 "View_HMDViewNoRollUp" + OpMemberName %type_View 20 "PrePadding_View_892" + OpMemberName %type_View 21 "View_HMDViewNoRollRight" + OpMemberName %type_View 22 "PrePadding_View_908" + OpMemberName %type_View 23 "View_InvDeviceZToWorldZTransform" + OpMemberName %type_View 24 "View_ScreenPositionScaleBias" + OpMemberName %type_View 25 "View_WorldCameraOrigin" + OpMemberName %type_View 26 "PrePadding_View_956" + OpMemberName %type_View 27 "View_TranslatedWorldCameraOrigin" + OpMemberName %type_View 28 "PrePadding_View_972" + OpMemberName %type_View 29 "View_WorldViewOrigin" + OpMemberName %type_View 30 "PrePadding_View_988" + OpMemberName %type_View 31 "View_PreViewTranslation" + OpMemberName %type_View 32 "PrePadding_View_1004" + OpMemberName %type_View 33 "View_PrevProjection" + OpMemberName %type_View 34 "View_PrevViewProj" + OpMemberName %type_View 35 "View_PrevViewRotationProj" + OpMemberName %type_View 36 "View_PrevViewToClip" + OpMemberName %type_View 37 "View_PrevClipToView" + OpMemberName %type_View 38 "View_PrevTranslatedWorldToClip" + OpMemberName %type_View 39 "View_PrevTranslatedWorldToView" + OpMemberName %type_View 40 "View_PrevViewToTranslatedWorld" + OpMemberName %type_View 41 "View_PrevTranslatedWorldToCameraView" + OpMemberName %type_View 42 "View_PrevCameraViewToTranslatedWorld" + OpMemberName %type_View 43 "View_PrevWorldCameraOrigin" + OpMemberName %type_View 44 "PrePadding_View_1660" + OpMemberName %type_View 45 "View_PrevWorldViewOrigin" + OpMemberName %type_View 46 "PrePadding_View_1676" + OpMemberName %type_View 47 "View_PrevPreViewTranslation" + OpMemberName %type_View 48 "PrePadding_View_1692" + OpMemberName %type_View 49 "View_PrevInvViewProj" + OpMemberName %type_View 50 "View_PrevScreenToTranslatedWorld" + OpMemberName %type_View 51 "View_ClipToPrevClip" + OpMemberName %type_View 52 "View_TemporalAAJitter" + OpMemberName %type_View 53 "View_GlobalClippingPlane" + OpMemberName %type_View 54 "View_FieldOfViewWideAngles" + OpMemberName %type_View 55 "View_PrevFieldOfViewWideAngles" + OpMemberName %type_View 56 "View_ViewRectMin" + OpMemberName %type_View 57 "View_ViewSizeAndInvSize" + OpMemberName %type_View 58 "View_BufferSizeAndInvSize" + OpMemberName %type_View 59 "View_BufferBilinearUVMinMax" + OpMemberName %type_View 60 "View_NumSceneColorMSAASamples" + OpMemberName %type_View 61 "View_PreExposure" + OpMemberName %type_View 62 "View_OneOverPreExposure" + OpMemberName %type_View 63 "PrePadding_View_2012" + OpMemberName %type_View 64 "View_DiffuseOverrideParameter" + OpMemberName %type_View 65 "View_SpecularOverrideParameter" + OpMemberName %type_View 66 "View_NormalOverrideParameter" + OpMemberName %type_View 67 "View_RoughnessOverrideParameter" + OpMemberName %type_View 68 "View_PrevFrameGameTime" + OpMemberName %type_View 69 "View_PrevFrameRealTime" + OpMemberName %type_View 70 "View_OutOfBoundsMask" + OpMemberName %type_View 71 "PrePadding_View_2084" + OpMemberName %type_View 72 "PrePadding_View_2088" + OpMemberName %type_View 73 "PrePadding_View_2092" + OpMemberName %type_View 74 "View_WorldCameraMovementSinceLastFrame" + OpMemberName %type_View 75 "View_CullingSign" + OpMemberName %type_View 76 "View_NearPlane" + OpMemberName %type_View 77 "View_AdaptiveTessellationFactor" + OpMemberName %type_View 78 "View_GameTime" + OpMemberName %type_View 79 "View_RealTime" + OpMemberName %type_View 80 "View_DeltaTime" + OpMemberName %type_View 81 "View_MaterialTextureMipBias" + OpMemberName %type_View 82 "View_MaterialTextureDerivativeMultiply" + OpMemberName %type_View 83 "View_Random" + OpMemberName %type_View 84 "View_FrameNumber" + OpMemberName %type_View 85 "View_StateFrameIndexMod8" + OpMemberName %type_View 86 "View_StateFrameIndex" + OpMemberName %type_View 87 "View_CameraCut" + OpMemberName %type_View 88 "View_UnlitViewmodeMask" + OpMemberName %type_View 89 "PrePadding_View_2164" + OpMemberName %type_View 90 "PrePadding_View_2168" + OpMemberName %type_View 91 "PrePadding_View_2172" + OpMemberName %type_View 92 "View_DirectionalLightColor" + OpMemberName %type_View 93 "View_DirectionalLightDirection" + OpMemberName %type_View 94 "PrePadding_View_2204" + OpMemberName %type_View 95 "View_TranslucencyLightingVolumeMin" + OpMemberName %type_View 96 "View_TranslucencyLightingVolumeInvSize" + OpMemberName %type_View 97 "View_TemporalAAParams" + OpMemberName %type_View 98 "View_CircleDOFParams" + OpMemberName %type_View 99 "View_DepthOfFieldSensorWidth" + OpMemberName %type_View 100 "View_DepthOfFieldFocalDistance" + OpMemberName %type_View 101 "View_DepthOfFieldScale" + OpMemberName %type_View 102 "View_DepthOfFieldFocalLength" + OpMemberName %type_View 103 "View_DepthOfFieldFocalRegion" + OpMemberName %type_View 104 "View_DepthOfFieldNearTransitionRegion" + OpMemberName %type_View 105 "View_DepthOfFieldFarTransitionRegion" + OpMemberName %type_View 106 "View_MotionBlurNormalizedToPixel" + OpMemberName %type_View 107 "View_bSubsurfacePostprocessEnabled" + OpMemberName %type_View 108 "View_GeneralPurposeTweak" + OpMemberName %type_View 109 "View_DemosaicVposOffset" + OpMemberName %type_View 110 "PrePadding_View_2348" + OpMemberName %type_View 111 "View_IndirectLightingColorScale" + OpMemberName %type_View 112 "View_HDR32bppEncodingMode" + OpMemberName %type_View 113 "View_AtmosphericFogSunDirection" + OpMemberName %type_View 114 "View_AtmosphericFogSunPower" + OpMemberName %type_View 115 "View_AtmosphericFogPower" + OpMemberName %type_View 116 "View_AtmosphericFogDensityScale" + OpMemberName %type_View 117 "View_AtmosphericFogDensityOffset" + OpMemberName %type_View 118 "View_AtmosphericFogGroundOffset" + OpMemberName %type_View 119 "View_AtmosphericFogDistanceScale" + OpMemberName %type_View 120 "View_AtmosphericFogAltitudeScale" + OpMemberName %type_View 121 "View_AtmosphericFogHeightScaleRayleigh" + OpMemberName %type_View 122 "View_AtmosphericFogStartDistance" + OpMemberName %type_View 123 "View_AtmosphericFogDistanceOffset" + OpMemberName %type_View 124 "View_AtmosphericFogSunDiscScale" + OpMemberName %type_View 125 "View_AtmosphericFogRenderMask" + OpMemberName %type_View 126 "View_AtmosphericFogInscatterAltitudeSampleNum" + OpMemberName %type_View 127 "View_AtmosphericFogSunColor" + OpMemberName %type_View 128 "View_NormalCurvatureToRoughnessScaleBias" + OpMemberName %type_View 129 "View_RenderingReflectionCaptureMask" + OpMemberName %type_View 130 "View_AmbientCubemapTint" + OpMemberName %type_View 131 "View_AmbientCubemapIntensity" + OpMemberName %type_View 132 "View_SkyLightParameters" + OpMemberName %type_View 133 "PrePadding_View_2488" + OpMemberName %type_View 134 "PrePadding_View_2492" + OpMemberName %type_View 135 "View_SkyLightColor" + OpMemberName %type_View 136 "View_SkyIrradianceEnvironmentMap" + OpMemberName %type_View 137 "View_MobilePreviewMode" + OpMemberName %type_View 138 "View_HMDEyePaddingOffset" + OpMemberName %type_View 139 "View_ReflectionCubemapMaxMip" + OpMemberName %type_View 140 "View_ShowDecalsMask" + OpMemberName %type_View 141 "View_DistanceFieldAOSpecularOcclusionMode" + OpMemberName %type_View 142 "View_IndirectCapsuleSelfShadowingIntensity" + OpMemberName %type_View 143 "PrePadding_View_2648" + OpMemberName %type_View 144 "PrePadding_View_2652" + OpMemberName %type_View 145 "View_ReflectionEnvironmentRoughnessMixingScaleBiasAndLargestWeight" + OpMemberName %type_View 146 "View_StereoPassIndex" + OpMemberName %type_View 147 "View_GlobalVolumeCenterAndExtent" + OpMemberName %type_View 148 "View_GlobalVolumeWorldToUVAddAndMul" + OpMemberName %type_View 149 "View_GlobalVolumeDimension" + OpMemberName %type_View 150 "View_GlobalVolumeTexelSize" + OpMemberName %type_View 151 "View_MaxGlobalDistance" + OpMemberName %type_View 152 "View_bCheckerboardSubsurfaceProfileRendering" + OpMemberName %type_View 153 "View_VolumetricFogInvGridSize" + OpMemberName %type_View 154 "PrePadding_View_2828" + OpMemberName %type_View 155 "View_VolumetricFogGridZParams" + OpMemberName %type_View 156 "PrePadding_View_2844" + OpMemberName %type_View 157 "View_VolumetricFogSVPosToVolumeUV" + OpMemberName %type_View 158 "View_VolumetricFogMaxDistance" + OpMemberName %type_View 159 "PrePadding_View_2860" + OpMemberName %type_View 160 "View_VolumetricLightmapWorldToUVScale" + OpMemberName %type_View 161 "PrePadding_View_2876" + OpMemberName %type_View 162 "View_VolumetricLightmapWorldToUVAdd" + OpMemberName %type_View 163 "PrePadding_View_2892" + OpMemberName %type_View 164 "View_VolumetricLightmapIndirectionTextureSize" + OpMemberName %type_View 165 "View_VolumetricLightmapBrickSize" + OpMemberName %type_View 166 "View_VolumetricLightmapBrickTexelSize" + OpMemberName %type_View 167 "View_StereoIPD" + OpMemberName %type_View 168 "View_IndirectLightingCacheShowFlag" + OpMemberName %type_View 169 "View_EyeToPixelSpreadAngle" + OpName %View "View" + OpName %type_MobileDirectionalLight "type.MobileDirectionalLight" + OpMemberName %type_MobileDirectionalLight 0 "MobileDirectionalLight_DirectionalLightColor" + OpMemberName %type_MobileDirectionalLight 1 "MobileDirectionalLight_DirectionalLightDirectionAndShadowTransition" + OpMemberName %type_MobileDirectionalLight 2 "MobileDirectionalLight_DirectionalLightShadowSize" + OpMemberName %type_MobileDirectionalLight 3 "MobileDirectionalLight_DirectionalLightDistanceFadeMAD" + OpMemberName %type_MobileDirectionalLight 4 "MobileDirectionalLight_DirectionalLightShadowDistances" + OpMemberName %type_MobileDirectionalLight 5 "MobileDirectionalLight_DirectionalLightScreenToShadow" + OpName %MobileDirectionalLight "MobileDirectionalLight" + OpName %type_2d_image "type.2d.image" + OpName %MobileDirectionalLight_DirectionalLightShadowTexture "MobileDirectionalLight_DirectionalLightShadowTexture" + OpName %type_sampler "type.sampler" + OpName %MobileDirectionalLight_DirectionalLightShadowSampler "MobileDirectionalLight_DirectionalLightShadowSampler" + OpName %Material_Texture2D_0 "Material_Texture2D_0" + OpName %Material_Texture2D_0Sampler "Material_Texture2D_0Sampler" + OpName %Material_Texture2D_1 "Material_Texture2D_1" + OpName %Material_Texture2D_1Sampler "Material_Texture2D_1Sampler" + OpName %type__Globals "type.$Globals" + OpMemberName %type__Globals 0 "NumDynamicPointLights" + OpMemberName %type__Globals 1 "LightPositionAndInvRadius" + OpMemberName %type__Globals 2 "LightColorAndFalloffExponent" + OpMemberName %type__Globals 3 "MobileReflectionParams" + OpName %_Globals "$Globals" + OpName %type_cube_image "type.cube.image" + OpName %ReflectionCubemap "ReflectionCubemap" + OpName %ReflectionCubemapSampler "ReflectionCubemapSampler" + OpName %in_var_TEXCOORD0 "in.var.TEXCOORD0" + OpName %in_var_TEXCOORD7 "in.var.TEXCOORD7" + OpName %in_var_TEXCOORD8 "in.var.TEXCOORD8" + OpName %out_var_SV_Target0 "out.var.SV_Target0" + OpName %Main "Main" + OpName %type_sampled_image "type.sampled.image" + OpName %type_sampled_image_0 "type.sampled.image" + OpDecorateString %in_var_TEXCOORD0 UserSemantic "TEXCOORD0" + OpDecorateString %in_var_TEXCOORD7 UserSemantic "TEXCOORD7" + OpDecorateString %in_var_TEXCOORD8 UserSemantic "TEXCOORD8" + OpDecorate %gl_FragCoord BuiltIn FragCoord + OpDecorateString %gl_FragCoord UserSemantic "SV_Position" + OpDecorate %gl_FrontFacing BuiltIn FrontFacing + OpDecorateString %gl_FrontFacing UserSemantic "SV_IsFrontFace" + OpDecorate %gl_FrontFacing Flat + OpDecorateString %out_var_SV_Target0 UserSemantic "SV_Target0" + OpDecorate %in_var_TEXCOORD0 Location 0 + OpDecorate %in_var_TEXCOORD7 Location 1 + OpDecorate %in_var_TEXCOORD8 Location 2 + OpDecorate %out_var_SV_Target0 Location 0 + OpDecorate %View DescriptorSet 0 + OpDecorate %View Binding 0 + OpDecorate %MobileDirectionalLight DescriptorSet 0 + OpDecorate %MobileDirectionalLight Binding 1 + OpDecorate %MobileDirectionalLight_DirectionalLightShadowTexture DescriptorSet 0 + OpDecorate %MobileDirectionalLight_DirectionalLightShadowTexture Binding 0 + OpDecorate %MobileDirectionalLight_DirectionalLightShadowSampler DescriptorSet 0 + OpDecorate %MobileDirectionalLight_DirectionalLightShadowSampler Binding 0 + OpDecorate %Material_Texture2D_0 DescriptorSet 0 + OpDecorate %Material_Texture2D_0 Binding 1 + OpDecorate %Material_Texture2D_0Sampler DescriptorSet 0 + OpDecorate %Material_Texture2D_0Sampler Binding 1 + OpDecorate %Material_Texture2D_1 DescriptorSet 0 + OpDecorate %Material_Texture2D_1 Binding 2 + OpDecorate %Material_Texture2D_1Sampler DescriptorSet 0 + OpDecorate %Material_Texture2D_1Sampler Binding 2 + OpDecorate %_Globals DescriptorSet 0 + OpDecorate %_Globals Binding 2 + OpDecorate %ReflectionCubemap DescriptorSet 0 + OpDecorate %ReflectionCubemap Binding 3 + OpDecorate %ReflectionCubemapSampler DescriptorSet 0 + OpDecorate %ReflectionCubemapSampler Binding 3 + OpDecorate %_arr_v4float_uint_2 ArrayStride 16 + OpDecorate %_arr_v4float_uint_7 ArrayStride 16 + OpDecorate %_arr_v4float_uint_4 ArrayStride 16 + OpMemberDecorate %type_View 0 Offset 0 + OpMemberDecorate %type_View 0 MatrixStride 16 + OpMemberDecorate %type_View 0 ColMajor + OpMemberDecorate %type_View 1 Offset 64 + OpMemberDecorate %type_View 1 MatrixStride 16 + OpMemberDecorate %type_View 1 ColMajor + OpMemberDecorate %type_View 2 Offset 128 + OpMemberDecorate %type_View 2 MatrixStride 16 + OpMemberDecorate %type_View 2 ColMajor + OpMemberDecorate %type_View 3 Offset 192 + OpMemberDecorate %type_View 3 MatrixStride 16 + OpMemberDecorate %type_View 3 ColMajor + OpMemberDecorate %type_View 4 Offset 256 + OpMemberDecorate %type_View 4 MatrixStride 16 + OpMemberDecorate %type_View 4 ColMajor + OpMemberDecorate %type_View 5 Offset 320 + OpMemberDecorate %type_View 5 MatrixStride 16 + OpMemberDecorate %type_View 5 ColMajor + OpMemberDecorate %type_View 6 Offset 384 + OpMemberDecorate %type_View 6 MatrixStride 16 + OpMemberDecorate %type_View 6 ColMajor + OpMemberDecorate %type_View 7 Offset 448 + OpMemberDecorate %type_View 7 MatrixStride 16 + OpMemberDecorate %type_View 7 ColMajor + OpMemberDecorate %type_View 8 Offset 512 + OpMemberDecorate %type_View 8 MatrixStride 16 + OpMemberDecorate %type_View 8 ColMajor + OpMemberDecorate %type_View 9 Offset 576 + OpMemberDecorate %type_View 9 MatrixStride 16 + OpMemberDecorate %type_View 9 ColMajor + OpMemberDecorate %type_View 10 Offset 640 + OpMemberDecorate %type_View 10 MatrixStride 16 + OpMemberDecorate %type_View 10 ColMajor + OpMemberDecorate %type_View 11 Offset 704 + OpMemberDecorate %type_View 11 MatrixStride 16 + OpMemberDecorate %type_View 11 ColMajor + OpMemberDecorate %type_View 12 Offset 768 + OpMemberDecorate %type_View 12 MatrixStride 16 + OpMemberDecorate %type_View 12 ColMajor + OpMemberDecorate %type_View 13 Offset 832 + OpMemberDecorate %type_View 14 Offset 844 + OpMemberDecorate %type_View 15 Offset 848 + OpMemberDecorate %type_View 16 Offset 860 + OpMemberDecorate %type_View 17 Offset 864 + OpMemberDecorate %type_View 18 Offset 876 + OpMemberDecorate %type_View 19 Offset 880 + OpMemberDecorate %type_View 20 Offset 892 + OpMemberDecorate %type_View 21 Offset 896 + OpMemberDecorate %type_View 22 Offset 908 + OpMemberDecorate %type_View 23 Offset 912 + OpMemberDecorate %type_View 24 Offset 928 + OpMemberDecorate %type_View 25 Offset 944 + OpMemberDecorate %type_View 26 Offset 956 + OpMemberDecorate %type_View 27 Offset 960 + OpMemberDecorate %type_View 28 Offset 972 + OpMemberDecorate %type_View 29 Offset 976 + OpMemberDecorate %type_View 30 Offset 988 + OpMemberDecorate %type_View 31 Offset 992 + OpMemberDecorate %type_View 32 Offset 1004 + OpMemberDecorate %type_View 33 Offset 1008 + OpMemberDecorate %type_View 33 MatrixStride 16 + OpMemberDecorate %type_View 33 ColMajor + OpMemberDecorate %type_View 34 Offset 1072 + OpMemberDecorate %type_View 34 MatrixStride 16 + OpMemberDecorate %type_View 34 ColMajor + OpMemberDecorate %type_View 35 Offset 1136 + OpMemberDecorate %type_View 35 MatrixStride 16 + OpMemberDecorate %type_View 35 ColMajor + OpMemberDecorate %type_View 36 Offset 1200 + OpMemberDecorate %type_View 36 MatrixStride 16 + OpMemberDecorate %type_View 36 ColMajor + OpMemberDecorate %type_View 37 Offset 1264 + OpMemberDecorate %type_View 37 MatrixStride 16 + OpMemberDecorate %type_View 37 ColMajor + OpMemberDecorate %type_View 38 Offset 1328 + OpMemberDecorate %type_View 38 MatrixStride 16 + OpMemberDecorate %type_View 38 ColMajor + OpMemberDecorate %type_View 39 Offset 1392 + OpMemberDecorate %type_View 39 MatrixStride 16 + OpMemberDecorate %type_View 39 ColMajor + OpMemberDecorate %type_View 40 Offset 1456 + OpMemberDecorate %type_View 40 MatrixStride 16 + OpMemberDecorate %type_View 40 ColMajor + OpMemberDecorate %type_View 41 Offset 1520 + OpMemberDecorate %type_View 41 MatrixStride 16 + OpMemberDecorate %type_View 41 ColMajor + OpMemberDecorate %type_View 42 Offset 1584 + OpMemberDecorate %type_View 42 MatrixStride 16 + OpMemberDecorate %type_View 42 ColMajor + OpMemberDecorate %type_View 43 Offset 1648 + OpMemberDecorate %type_View 44 Offset 1660 + OpMemberDecorate %type_View 45 Offset 1664 + OpMemberDecorate %type_View 46 Offset 1676 + OpMemberDecorate %type_View 47 Offset 1680 + OpMemberDecorate %type_View 48 Offset 1692 + OpMemberDecorate %type_View 49 Offset 1696 + OpMemberDecorate %type_View 49 MatrixStride 16 + OpMemberDecorate %type_View 49 ColMajor + OpMemberDecorate %type_View 50 Offset 1760 + OpMemberDecorate %type_View 50 MatrixStride 16 + OpMemberDecorate %type_View 50 ColMajor + OpMemberDecorate %type_View 51 Offset 1824 + OpMemberDecorate %type_View 51 MatrixStride 16 + OpMemberDecorate %type_View 51 ColMajor + OpMemberDecorate %type_View 52 Offset 1888 + OpMemberDecorate %type_View 53 Offset 1904 + OpMemberDecorate %type_View 54 Offset 1920 + OpMemberDecorate %type_View 55 Offset 1928 + OpMemberDecorate %type_View 56 Offset 1936 + OpMemberDecorate %type_View 57 Offset 1952 + OpMemberDecorate %type_View 58 Offset 1968 + OpMemberDecorate %type_View 59 Offset 1984 + OpMemberDecorate %type_View 60 Offset 2000 + OpMemberDecorate %type_View 61 Offset 2004 + OpMemberDecorate %type_View 62 Offset 2008 + OpMemberDecorate %type_View 63 Offset 2012 + OpMemberDecorate %type_View 64 Offset 2016 + OpMemberDecorate %type_View 65 Offset 2032 + OpMemberDecorate %type_View 66 Offset 2048 + OpMemberDecorate %type_View 67 Offset 2064 + OpMemberDecorate %type_View 68 Offset 2072 + OpMemberDecorate %type_View 69 Offset 2076 + OpMemberDecorate %type_View 70 Offset 2080 + OpMemberDecorate %type_View 71 Offset 2084 + OpMemberDecorate %type_View 72 Offset 2088 + OpMemberDecorate %type_View 73 Offset 2092 + OpMemberDecorate %type_View 74 Offset 2096 + OpMemberDecorate %type_View 75 Offset 2108 + OpMemberDecorate %type_View 76 Offset 2112 + OpMemberDecorate %type_View 77 Offset 2116 + OpMemberDecorate %type_View 78 Offset 2120 + OpMemberDecorate %type_View 79 Offset 2124 + OpMemberDecorate %type_View 80 Offset 2128 + OpMemberDecorate %type_View 81 Offset 2132 + OpMemberDecorate %type_View 82 Offset 2136 + OpMemberDecorate %type_View 83 Offset 2140 + OpMemberDecorate %type_View 84 Offset 2144 + OpMemberDecorate %type_View 85 Offset 2148 + OpMemberDecorate %type_View 86 Offset 2152 + OpMemberDecorate %type_View 87 Offset 2156 + OpMemberDecorate %type_View 88 Offset 2160 + OpMemberDecorate %type_View 89 Offset 2164 + OpMemberDecorate %type_View 90 Offset 2168 + OpMemberDecorate %type_View 91 Offset 2172 + OpMemberDecorate %type_View 92 Offset 2176 + OpMemberDecorate %type_View 93 Offset 2192 + OpMemberDecorate %type_View 94 Offset 2204 + OpMemberDecorate %type_View 95 Offset 2208 + OpMemberDecorate %type_View 96 Offset 2240 + OpMemberDecorate %type_View 97 Offset 2272 + OpMemberDecorate %type_View 98 Offset 2288 + OpMemberDecorate %type_View 99 Offset 2304 + OpMemberDecorate %type_View 100 Offset 2308 + OpMemberDecorate %type_View 101 Offset 2312 + OpMemberDecorate %type_View 102 Offset 2316 + OpMemberDecorate %type_View 103 Offset 2320 + OpMemberDecorate %type_View 104 Offset 2324 + OpMemberDecorate %type_View 105 Offset 2328 + OpMemberDecorate %type_View 106 Offset 2332 + OpMemberDecorate %type_View 107 Offset 2336 + OpMemberDecorate %type_View 108 Offset 2340 + OpMemberDecorate %type_View 109 Offset 2344 + OpMemberDecorate %type_View 110 Offset 2348 + OpMemberDecorate %type_View 111 Offset 2352 + OpMemberDecorate %type_View 112 Offset 2364 + OpMemberDecorate %type_View 113 Offset 2368 + OpMemberDecorate %type_View 114 Offset 2380 + OpMemberDecorate %type_View 115 Offset 2384 + OpMemberDecorate %type_View 116 Offset 2388 + OpMemberDecorate %type_View 117 Offset 2392 + OpMemberDecorate %type_View 118 Offset 2396 + OpMemberDecorate %type_View 119 Offset 2400 + OpMemberDecorate %type_View 120 Offset 2404 + OpMemberDecorate %type_View 121 Offset 2408 + OpMemberDecorate %type_View 122 Offset 2412 + OpMemberDecorate %type_View 123 Offset 2416 + OpMemberDecorate %type_View 124 Offset 2420 + OpMemberDecorate %type_View 125 Offset 2424 + OpMemberDecorate %type_View 126 Offset 2428 + OpMemberDecorate %type_View 127 Offset 2432 + OpMemberDecorate %type_View 128 Offset 2448 + OpMemberDecorate %type_View 129 Offset 2460 + OpMemberDecorate %type_View 130 Offset 2464 + OpMemberDecorate %type_View 131 Offset 2480 + OpMemberDecorate %type_View 132 Offset 2484 + OpMemberDecorate %type_View 133 Offset 2488 + OpMemberDecorate %type_View 134 Offset 2492 + OpMemberDecorate %type_View 135 Offset 2496 + OpMemberDecorate %type_View 136 Offset 2512 + OpMemberDecorate %type_View 137 Offset 2624 + OpMemberDecorate %type_View 138 Offset 2628 + OpMemberDecorate %type_View 139 Offset 2632 + OpMemberDecorate %type_View 140 Offset 2636 + OpMemberDecorate %type_View 141 Offset 2640 + OpMemberDecorate %type_View 142 Offset 2644 + OpMemberDecorate %type_View 143 Offset 2648 + OpMemberDecorate %type_View 144 Offset 2652 + OpMemberDecorate %type_View 145 Offset 2656 + OpMemberDecorate %type_View 146 Offset 2668 + OpMemberDecorate %type_View 147 Offset 2672 + OpMemberDecorate %type_View 148 Offset 2736 + OpMemberDecorate %type_View 149 Offset 2800 + OpMemberDecorate %type_View 150 Offset 2804 + OpMemberDecorate %type_View 151 Offset 2808 + OpMemberDecorate %type_View 152 Offset 2812 + OpMemberDecorate %type_View 153 Offset 2816 + OpMemberDecorate %type_View 154 Offset 2828 + OpMemberDecorate %type_View 155 Offset 2832 + OpMemberDecorate %type_View 156 Offset 2844 + OpMemberDecorate %type_View 157 Offset 2848 + OpMemberDecorate %type_View 158 Offset 2856 + OpMemberDecorate %type_View 159 Offset 2860 + OpMemberDecorate %type_View 160 Offset 2864 + OpMemberDecorate %type_View 161 Offset 2876 + OpMemberDecorate %type_View 162 Offset 2880 + OpMemberDecorate %type_View 163 Offset 2892 + OpMemberDecorate %type_View 164 Offset 2896 + OpMemberDecorate %type_View 165 Offset 2908 + OpMemberDecorate %type_View 166 Offset 2912 + OpMemberDecorate %type_View 167 Offset 2924 + OpMemberDecorate %type_View 168 Offset 2928 + OpMemberDecorate %type_View 169 Offset 2932 + OpDecorate %type_View Block + OpDecorate %_arr_mat4v4float_uint_4 ArrayStride 64 + OpMemberDecorate %type_MobileDirectionalLight 0 Offset 0 + OpMemberDecorate %type_MobileDirectionalLight 1 Offset 16 + OpMemberDecorate %type_MobileDirectionalLight 2 Offset 32 + OpMemberDecorate %type_MobileDirectionalLight 3 Offset 48 + OpMemberDecorate %type_MobileDirectionalLight 4 Offset 64 + OpMemberDecorate %type_MobileDirectionalLight 5 Offset 80 + OpMemberDecorate %type_MobileDirectionalLight 5 MatrixStride 16 + OpMemberDecorate %type_MobileDirectionalLight 5 ColMajor + OpDecorate %type_MobileDirectionalLight Block + OpMemberDecorate %type__Globals 0 Offset 0 + OpMemberDecorate %type__Globals 1 Offset 16 + OpMemberDecorate %type__Globals 2 Offset 80 + OpMemberDecorate %type__Globals 3 Offset 144 + OpDecorate %type__Globals Block + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 +%mat4v4float = OpTypeMatrix %v4float 4 + %v3float = OpTypeVector %float 3 + %v2float = OpTypeVector %float 2 + %int = OpTypeInt 32 1 + %uint = OpTypeInt 32 0 + %uint_2 = OpConstant %uint 2 + %uint_7 = OpConstant %uint 7 + %uint_4 = OpConstant %uint 4 + %int_1 = OpConstant %int 1 + %int_2 = OpConstant %int 2 + %int_4 = OpConstant %int 4 + %float_0 = OpConstant %float 0 + %int_3 = OpConstant %int 3 + %47 = OpConstantComposite %v3float %float_0 %float_0 %float_0 + %float_1 = OpConstant %float 1 + %int_0 = OpConstant %int 0 + %bool = OpTypeBool + %int_5 = OpConstant %int 5 + %52 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0 +%float_0_999989986 = OpConstant %float 0.999989986 +%float_65000 = OpConstant %float 65000 + %55 = OpConstantComposite %v3float %float_65000 %float_65000 %float_65000 +%float_0_318309873 = OpConstant %float 0.318309873 + %57 = OpConstantComposite %v3float %float_0_318309873 %float_0_318309873 %float_0_318309873 +%float_65500 = OpConstant %float 65500 + %float_0_5 = OpConstant %float 0.5 + %60 = OpConstantComposite %v2float %float_0_5 %float_0_5 + %float_2 = OpConstant %float 2 + %float_n2 = OpConstant %float -2 + %63 = OpConstantComposite %v2float %float_2 %float_n2 + %64 = OpConstantComposite %v3float %float_1 %float_1 %float_1 +%float_0_119999997 = OpConstant %float 0.119999997 + %float_n1 = OpConstant %float -1 +%float_n0_0274999999 = OpConstant %float -0.0274999999 + %68 = OpConstantComposite %v2float %float_n1 %float_n0_0274999999 +%float_0_0425000004 = OpConstant %float 0.0425000004 + %70 = OpConstantComposite %v2float %float_1 %float_0_0425000004 +%float_n9_27999973 = OpConstant %float -9.27999973 + %72 = OpConstantComposite %v2float %float_1 %float_1 + %float_0_25 = OpConstant %float 0.25 + %float_16 = OpConstant %float 16 + %int_31 = OpConstant %int 31 + %int_56 = OpConstant %int 56 + %int_57 = OpConstant %int 57 + %int_64 = OpConstant %int 64 + %int_65 = OpConstant %int 65 + %int_66 = OpConstant %int 66 + %int_67 = OpConstant %int 67 + %int_88 = OpConstant %int 88 + %int_135 = OpConstant %int 135 + %int_139 = OpConstant %int 139 +%mat3v3float = OpTypeMatrix %v3float 3 + %86 = OpConstantComposite %v2float %float_2 %float_2 +%float_0_300000012 = OpConstant %float 0.300000012 + %88 = OpConstantComposite %v3float %float_0_300000012 %float_0_300000012 %float_1 + %float_20 = OpConstant %float 20 + %90 = OpConstantComposite %v2float %float_20 %float_20 +%float_0_400000006 = OpConstant %float 0.400000006 + %float_24 = OpConstant %float 24 +%float_0_294999987 = OpConstant %float 0.294999987 +%float_0_660000026 = OpConstant %float 0.660000026 +%float_0_699999988 = OpConstant %float 0.699999988 +%float_65504 = OpConstant %float 65504 +%float_1_20000005 = OpConstant %float 1.20000005 + %98 = OpConstantComposite %v3float %float_2 %float_2 %float_2 +%_arr_v4float_uint_2 = OpTypeArray %v4float %uint_2 +%_arr_v4float_uint_7 = OpTypeArray %v4float %uint_7 +%_arr_v4float_uint_4 = OpTypeArray %v4float %uint_4 + %type_View = OpTypeStruct %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %v3float %float %v3float %float %v3float %float %v3float %float %v3float %float %v4float %v4float %v3float %float %v3float %float %v3float %float %v3float %float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %v3float %float %v3float %float %v3float %float %mat4v4float %mat4v4float %mat4v4float %v4float %v4float %v2float %v2float %v4float %v4float %v4float %v4float %int %float %float %float %v4float %v4float %v4float %v2float %float %float %float %float %float %float %v3float %float %float %float %float %float %float %float %float %uint %uint %uint %uint %float %float %float %float %float %v4float %v3float %float %_arr_v4float_uint_2 %_arr_v4float_uint_2 %v4float %v4float %float %float %float %float %float %float %float %float %float %float %float %float %v3float %float %v3float %float %float %float %float %float %float %float %float %float %float %float %uint %uint %v4float %v3float %float %v4float %float %float %float %float %v4float %_arr_v4float_uint_7 %float %float %float %float %uint %float %float %float %v3float %int %_arr_v4float_uint_4 %_arr_v4float_uint_4 %float %float %float %float %v3float %float %v3float %float %v2float %float %float %v3float %float %v3float %float %v3float %float %v3float %float %float %float +%_ptr_Uniform_type_View = OpTypePointer Uniform %type_View +%_arr_mat4v4float_uint_4 = OpTypeArray %mat4v4float %uint_4 +%type_MobileDirectionalLight = OpTypeStruct %v4float %v4float %v4float %v4float %v4float %_arr_mat4v4float_uint_4 +%_ptr_Uniform_type_MobileDirectionalLight = OpTypePointer Uniform %type_MobileDirectionalLight +%type_2d_image = OpTypeImage %float 2D 2 0 0 1 Unknown +%_ptr_UniformConstant_type_2d_image = OpTypePointer UniformConstant %type_2d_image +%type_sampler = OpTypeSampler +%_ptr_UniformConstant_type_sampler = OpTypePointer UniformConstant %type_sampler +%type__Globals = OpTypeStruct %int %_arr_v4float_uint_4 %_arr_v4float_uint_4 %v4float +%_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals +%type_cube_image = OpTypeImage %float Cube 2 0 0 1 Unknown +%_ptr_UniformConstant_type_cube_image = OpTypePointer UniformConstant %type_cube_image +%_ptr_Input_v2float = OpTypePointer Input %v2float +%_ptr_Input_v4float = OpTypePointer Input %v4float +%_ptr_Input_bool = OpTypePointer Input %bool +%_ptr_Output_v4float = OpTypePointer Output %v4float + %void = OpTypeVoid + %110 = OpTypeFunction %void +%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float +%_ptr_Uniform_float = OpTypePointer Uniform %float +%_ptr_Uniform_mat4v4float = OpTypePointer Uniform %mat4v4float +%_ptr_Uniform_int = OpTypePointer Uniform %int +%type_sampled_image = OpTypeSampledImage %type_cube_image +%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float +%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float +%type_sampled_image_0 = OpTypeSampledImage %type_2d_image + %View = OpVariable %_ptr_Uniform_type_View Uniform +%MobileDirectionalLight = OpVariable %_ptr_Uniform_type_MobileDirectionalLight Uniform +%MobileDirectionalLight_DirectionalLightShadowTexture = OpVariable %_ptr_UniformConstant_type_2d_image UniformConstant +%MobileDirectionalLight_DirectionalLightShadowSampler = OpVariable %_ptr_UniformConstant_type_sampler UniformConstant +%Material_Texture2D_0 = OpVariable %_ptr_UniformConstant_type_2d_image UniformConstant +%Material_Texture2D_0Sampler = OpVariable %_ptr_UniformConstant_type_sampler UniformConstant +%Material_Texture2D_1 = OpVariable %_ptr_UniformConstant_type_2d_image UniformConstant +%Material_Texture2D_1Sampler = OpVariable %_ptr_UniformConstant_type_sampler UniformConstant + %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform +%ReflectionCubemap = OpVariable %_ptr_UniformConstant_type_cube_image UniformConstant +%ReflectionCubemapSampler = OpVariable %_ptr_UniformConstant_type_sampler UniformConstant +%in_var_TEXCOORD0 = OpVariable %_ptr_Input_v2float Input +%in_var_TEXCOORD7 = OpVariable %_ptr_Input_v4float Input +%in_var_TEXCOORD8 = OpVariable %_ptr_Input_v4float Input +%gl_FragCoord = OpVariable %_ptr_Input_v4float Input +%gl_FrontFacing = OpVariable %_ptr_Input_bool Input +%out_var_SV_Target0 = OpVariable %_ptr_Output_v4float Output + %117 = OpConstantComposite %v3float %float_1 %float_0 %float_0 + %118 = OpConstantComposite %v3float %float_0 %float_1 %float_0 + %119 = OpConstantComposite %v3float %float_0 %float_0 %float_1 + %120 = OpConstantComposite %mat3v3float %117 %118 %119 + %float_10 = OpConstant %float 10 + %122 = OpConstantComposite %v2float %float_10 %float_10 + %float_5 = OpConstant %float 5 + %124 = OpConstantComposite %v2float %float_5 %float_5 +%float_0_00066666666 = OpConstant %float 0.00066666666 + %float_n0_5 = OpConstant %float -0.5 + %127 = OpConstantComposite %v2float %float_n0_5 %float_n0_5 + %128 = OpConstantComposite %v2float %float_0_5 %float_n0_5 + %float_1_5 = OpConstant %float 1.5 + %130 = OpConstantComposite %v2float %float_1_5 %float_n0_5 + %131 = OpConstantComposite %v2float %float_n0_5 %float_0_5 + %132 = OpConstantComposite %v2float %float_1_5 %float_0_5 + %133 = OpConstantComposite %v2float %float_n0_5 %float_1_5 + %134 = OpConstantComposite %v2float %float_0_5 %float_1_5 + %135 = OpConstantComposite %v2float %float_1_5 %float_1_5 + %136 = OpUndef %v3float + %137 = OpUndef %v4float + %138 = OpUndef %float + %139 = OpUndef %v3float + %Main = OpFunction %void None %110 + %140 = OpLabel + %141 = OpLoad %v2float %in_var_TEXCOORD0 + %142 = OpLoad %v4float %in_var_TEXCOORD7 + %143 = OpLoad %v4float %in_var_TEXCOORD8 + %144 = OpLoad %v4float %gl_FragCoord + %145 = OpAccessChain %_ptr_Uniform_v3float %View %int_31 + %146 = OpLoad %v3float %145 + %147 = OpAccessChain %_ptr_Uniform_v4float %View %int_56 + %148 = OpLoad %v4float %147 + %149 = OpAccessChain %_ptr_Uniform_v4float %View %int_57 + %150 = OpLoad %v4float %149 + %151 = OpAccessChain %_ptr_Uniform_v4float %View %int_64 + %152 = OpLoad %v4float %151 + %153 = OpAccessChain %_ptr_Uniform_v4float %View %int_65 + %154 = OpLoad %v4float %153 + %155 = OpAccessChain %_ptr_Uniform_v4float %View %int_66 + %156 = OpLoad %v4float %155 + %157 = OpAccessChain %_ptr_Uniform_v2float %View %int_67 + %158 = OpLoad %v2float %157 + %159 = OpAccessChain %_ptr_Uniform_float %View %int_88 + %160 = OpLoad %float %159 + %161 = OpAccessChain %_ptr_Uniform_v4float %View %int_135 + %162 = OpLoad %v4float %161 + %163 = OpAccessChain %_ptr_Uniform_float %View %int_139 + %164 = OpLoad %float %163 + %165 = OpVectorShuffle %v2float %144 %144 0 1 + %166 = OpVectorShuffle %v2float %148 %148 0 1 + %167 = OpFSub %v2float %165 %166 + %168 = OpVectorShuffle %v2float %150 %150 2 3 + %169 = OpFMul %v2float %167 %168 + %170 = OpFSub %v2float %169 %60 + %171 = OpFMul %v2float %170 %63 + %172 = OpCompositeExtract %float %171 0 + %173 = OpCompositeExtract %float %171 1 + %174 = OpCompositeConstruct %v4float %172 %173 %138 %float_1 + %175 = OpCompositeExtract %float %144 3 + %176 = OpCompositeConstruct %v4float %175 %175 %175 %175 + %177 = OpFMul %v4float %174 %176 + %178 = OpVectorShuffle %v3float %143 %143 0 1 2 + %179 = OpFSub %v3float %178 %146 + %180 = OpFNegate %v3float %178 + %181 = OpExtInst %v3float %1 Normalize %180 + %182 = OpFMul %v2float %141 %60 + %183 = OpFMul %v2float %141 %122 + %184 = OpLoad %type_2d_image %Material_Texture2D_0 + %185 = OpLoad %type_sampler %Material_Texture2D_0Sampler + %186 = OpSampledImage %type_sampled_image_0 %184 %185 + %187 = OpImageSampleImplicitLod %v4float %186 %183 None + %188 = OpVectorShuffle %v2float %187 %187 0 1 + %189 = OpFMul %v2float %188 %86 + %190 = OpFSub %v2float %189 %72 + %191 = OpDot %float %190 %190 + %192 = OpFSub %float %float_1 %191 + %193 = OpExtInst %float %1 FClamp %192 %float_0 %float_1 + %194 = OpExtInst %float %1 Sqrt %193 + %195 = OpCompositeExtract %float %190 0 + %196 = OpCompositeExtract %float %190 1 + %197 = OpCompositeConstruct %v4float %195 %196 %194 %float_1 + %198 = OpVectorShuffle %v3float %197 %197 0 1 2 + %199 = OpFMul %v3float %198 %88 + %200 = OpVectorShuffle %v3float %156 %156 0 1 2 + %201 = OpCompositeExtract %float %156 3 + %202 = OpCompositeConstruct %v3float %201 %201 %201 + %203 = OpFMul %v3float %199 %202 + %204 = OpFAdd %v3float %203 %200 + %205 = OpMatrixTimesVector %v3float %120 %204 + %206 = OpExtInst %v3float %1 Normalize %205 + %207 = OpFNegate %v3float %181 + %208 = OpDot %float %206 %181 + %209 = OpCompositeConstruct %v3float %208 %208 %208 + %210 = OpFMul %v3float %206 %209 + %211 = OpFMul %v3float %210 %98 + %212 = OpFAdd %v3float %207 %211 + %213 = OpFMul %v2float %141 %90 + %214 = OpLoad %type_2d_image %Material_Texture2D_1 + %215 = OpLoad %type_sampler %Material_Texture2D_1Sampler + %216 = OpSampledImage %type_sampled_image_0 %214 %215 + %217 = OpImageSampleImplicitLod %v4float %216 %213 None + %218 = OpCompositeExtract %float %217 0 + %219 = OpExtInst %float %1 FMix %float_0_400000006 %float_1 %218 + %220 = OpFSub %float %float_1 %219 + %221 = OpFMul %v2float %141 %124 + %222 = OpSampledImage %type_sampled_image_0 %214 %215 + %223 = OpImageSampleImplicitLod %v4float %222 %221 None + %224 = OpCompositeExtract %float %177 3 + %225 = OpFSub %float %224 %float_24 + %226 = OpFMul %float %225 %float_0_00066666666 + %227 = OpExtInst %float %1 FMax %226 %float_0 + %228 = OpExtInst %float %1 FMin %227 %float_1 + %229 = OpCompositeExtract %float %223 1 + %230 = OpExtInst %float %1 FMix %229 %float_1 %228 + %231 = OpExtInst %float %1 FMix %219 %220 %230 + %232 = OpSampledImage %type_sampled_image_0 %214 %215 + %233 = OpImageSampleImplicitLod %v4float %232 %182 None + %234 = OpExtInst %float %1 FMix %229 %float_0 %228 + %235 = OpCompositeExtract %float %233 1 + %236 = OpFAdd %float %235 %234 + %237 = OpExtInst %float %1 FMix %236 %float_0_5 %float_0_5 + %238 = OpExtInst %float %1 FMix %float_0_294999987 %float_0_660000026 %237 + %239 = OpFMul %float %238 %float_0_5 + %240 = OpFMul %float %231 %239 + %241 = OpExtInst %float %1 FMix %float_0 %float_0_5 %235 + %242 = OpExtInst %float %1 FMix %float_0_699999988 %float_1 %229 + %243 = OpExtInst %float %1 FMix %242 %float_1 %228 + %244 = OpFAdd %float %241 %243 + %245 = OpExtInst %float %1 FMax %244 %float_0 + %246 = OpExtInst %float %1 FMin %245 %float_1 + %247 = OpCompositeConstruct %v3float %240 %240 %240 + %248 = OpExtInst %v3float %1 FClamp %247 %47 %64 + %249 = OpCompositeExtract %float %158 1 + %250 = OpFMul %float %246 %249 + %251 = OpCompositeExtract %float %158 0 + %252 = OpFAdd %float %250 %251 + %253 = OpExtInst %float %1 FClamp %252 %float_0_119999997 %float_1 + %254 = OpExtInst %float %1 FMax %208 %float_0 + %255 = OpCompositeConstruct %v2float %253 %253 + %256 = OpFMul %v2float %255 %68 + %257 = OpFAdd %v2float %256 %70 + %258 = OpCompositeExtract %float %257 0 + %259 = OpFMul %float %258 %258 + %260 = OpFMul %float %float_n9_27999973 %254 + %261 = OpExtInst %float %1 Exp2 %260 + %262 = OpExtInst %float %1 FMin %259 %261 + %263 = OpFMul %float %262 %258 + %264 = OpCompositeExtract %float %257 1 + %265 = OpFAdd %float %263 %264 + %266 = OpCompositeExtract %float %152 3 + %267 = OpCompositeConstruct %v3float %266 %266 %266 + %268 = OpFMul %v3float %248 %267 + %269 = OpVectorShuffle %v3float %152 %152 0 1 2 + %270 = OpFAdd %v3float %268 %269 + %271 = OpCompositeExtract %float %154 3 + %272 = OpFMul %float %265 %271 + %273 = OpCompositeConstruct %v3float %272 %272 %272 + %274 = OpVectorShuffle %v3float %154 %154 0 1 2 + %275 = OpFAdd %v3float %273 %274 + %276 = OpCompositeExtract %float %275 0 + %277 = OpExtInst %float %1 FClamp %float_1 %float_0 %float_1 + %278 = OpLoad %type_2d_image %MobileDirectionalLight_DirectionalLightShadowTexture + %279 = OpLoad %type_sampler %MobileDirectionalLight_DirectionalLightShadowSampler + %280 = OpAccessChain %_ptr_Uniform_v4float %MobileDirectionalLight %int_1 + %281 = OpAccessChain %_ptr_Uniform_float %MobileDirectionalLight %int_1 %int_3 + %282 = OpLoad %float %281 + %283 = OpAccessChain %_ptr_Uniform_v4float %MobileDirectionalLight %int_2 + %284 = OpLoad %v4float %283 + OpBranch %285 + %285 = OpLabel + %286 = OpPhi %int %int_0 %140 %287 %288 + %289 = OpSLessThan %bool %286 %int_2 + OpLoopMerge %290 %288 None + OpBranchConditional %289 %291 %290 + %291 = OpLabel + %292 = OpBitcast %uint %286 + %293 = OpAccessChain %_ptr_Uniform_float %MobileDirectionalLight %int_4 %292 + %294 = OpLoad %float %293 + %295 = OpFOrdLessThan %bool %224 %294 + OpSelectionMerge %288 None + OpBranchConditional %295 %296 %288 + %296 = OpLabel + %297 = OpCompositeExtract %float %177 0 + %298 = OpCompositeExtract %float %177 1 + %299 = OpCompositeConstruct %v4float %297 %298 %224 %float_1 + %300 = OpAccessChain %_ptr_Uniform_mat4v4float %MobileDirectionalLight %int_5 %286 + %301 = OpLoad %mat4v4float %300 + %302 = OpMatrixTimesVector %v4float %301 %299 + OpBranch %290 + %288 = OpLabel + %287 = OpIAdd %int %286 %int_1 + OpBranch %285 + %290 = OpLabel + %303 = OpPhi %v4float %52 %285 %302 %296 + %304 = OpCompositeExtract %float %303 2 + %305 = OpFOrdGreaterThan %bool %304 %float_0 + OpSelectionMerge %306 None + OpBranchConditional %305 %307 %306 + %307 = OpLabel + %308 = OpExtInst %float %1 FMin %304 %float_0_999989986 + %309 = OpVectorShuffle %v2float %303 %303 0 1 + %310 = OpVectorShuffle %v2float %284 %284 0 1 + %311 = OpFMul %v2float %309 %310 + %312 = OpExtInst %v2float %1 Fract %311 + %313 = OpExtInst %v2float %1 Floor %311 + %314 = OpFAdd %v2float %313 %127 + %315 = OpVectorShuffle %v2float %284 %284 2 3 + %316 = OpFMul %v2float %314 %315 + %317 = OpSampledImage %type_sampled_image_0 %278 %279 + %318 = OpImageSampleExplicitLod %v4float %317 %316 Lod %float_0 + %319 = OpCompositeExtract %float %318 0 + %320 = OpCompositeInsert %v3float %319 %139 0 + %321 = OpFAdd %v2float %313 %128 + %322 = OpFMul %v2float %321 %315 + %323 = OpSampledImage %type_sampled_image_0 %278 %279 + %324 = OpImageSampleExplicitLod %v4float %323 %322 Lod %float_0 + %325 = OpCompositeExtract %float %324 0 + %326 = OpCompositeInsert %v3float %325 %320 1 + %327 = OpFAdd %v2float %313 %130 + %328 = OpFMul %v2float %327 %315 + %329 = OpSampledImage %type_sampled_image_0 %278 %279 + %330 = OpImageSampleExplicitLod %v4float %329 %328 Lod %float_0 + %331 = OpCompositeExtract %float %330 0 + %332 = OpCompositeInsert %v3float %331 %326 2 + %333 = OpFMul %float %308 %282 + %334 = OpFSub %float %333 %float_1 + %335 = OpCompositeConstruct %v3float %282 %282 %282 + %336 = OpFMul %v3float %332 %335 + %337 = OpCompositeConstruct %v3float %334 %334 %334 + %338 = OpFSub %v3float %336 %337 + %339 = OpExtInst %v3float %1 FClamp %338 %47 %64 + %340 = OpFAdd %v2float %313 %131 + %341 = OpFMul %v2float %340 %315 + %342 = OpSampledImage %type_sampled_image_0 %278 %279 + %343 = OpImageSampleExplicitLod %v4float %342 %341 Lod %float_0 + %344 = OpCompositeExtract %float %343 0 + %345 = OpCompositeInsert %v3float %344 %139 0 + %346 = OpFAdd %v2float %313 %60 + %347 = OpFMul %v2float %346 %315 + %348 = OpSampledImage %type_sampled_image_0 %278 %279 + %349 = OpImageSampleExplicitLod %v4float %348 %347 Lod %float_0 + %350 = OpCompositeExtract %float %349 0 + %351 = OpCompositeInsert %v3float %350 %345 1 + %352 = OpFAdd %v2float %313 %132 + %353 = OpFMul %v2float %352 %315 + %354 = OpSampledImage %type_sampled_image_0 %278 %279 + %355 = OpImageSampleExplicitLod %v4float %354 %353 Lod %float_0 + %356 = OpCompositeExtract %float %355 0 + %357 = OpCompositeInsert %v3float %356 %351 2 + %358 = OpFMul %v3float %357 %335 + %359 = OpFSub %v3float %358 %337 + %360 = OpExtInst %v3float %1 FClamp %359 %47 %64 + %361 = OpFAdd %v2float %313 %133 + %362 = OpFMul %v2float %361 %315 + %363 = OpSampledImage %type_sampled_image_0 %278 %279 + %364 = OpImageSampleExplicitLod %v4float %363 %362 Lod %float_0 + %365 = OpCompositeExtract %float %364 0 + %366 = OpCompositeInsert %v3float %365 %139 0 + %367 = OpFAdd %v2float %313 %134 + %368 = OpFMul %v2float %367 %315 + %369 = OpSampledImage %type_sampled_image_0 %278 %279 + %370 = OpImageSampleExplicitLod %v4float %369 %368 Lod %float_0 + %371 = OpCompositeExtract %float %370 0 + %372 = OpCompositeInsert %v3float %371 %366 1 + %373 = OpFAdd %v2float %313 %135 + %374 = OpFMul %v2float %373 %315 + %375 = OpSampledImage %type_sampled_image_0 %278 %279 + %376 = OpImageSampleExplicitLod %v4float %375 %374 Lod %float_0 + %377 = OpCompositeExtract %float %376 0 + %378 = OpCompositeInsert %v3float %377 %372 2 + %379 = OpFMul %v3float %378 %335 + %380 = OpFSub %v3float %379 %337 + %381 = OpExtInst %v3float %1 FClamp %380 %47 %64 + %382 = OpCompositeExtract %float %339 0 + %383 = OpCompositeExtract %float %312 0 + %384 = OpFSub %float %float_1 %383 + %385 = OpFMul %float %382 %384 + %386 = OpCompositeExtract %float %360 0 + %387 = OpFMul %float %386 %384 + %388 = OpCompositeExtract %float %381 0 + %389 = OpFMul %float %388 %384 + %390 = OpCompositeExtract %float %339 1 + %391 = OpFAdd %float %385 %390 + %392 = OpCompositeExtract %float %360 1 + %393 = OpFAdd %float %387 %392 + %394 = OpCompositeExtract %float %381 1 + %395 = OpFAdd %float %389 %394 + %396 = OpCompositeExtract %float %339 2 + %397 = OpFMul %float %396 %383 + %398 = OpFAdd %float %391 %397 + %399 = OpCompositeInsert %v3float %398 %136 0 + %400 = OpCompositeExtract %float %360 2 + %401 = OpFMul %float %400 %383 + %402 = OpFAdd %float %393 %401 + %403 = OpCompositeInsert %v3float %402 %399 1 + %404 = OpCompositeExtract %float %381 2 + %405 = OpFMul %float %404 %383 + %406 = OpFAdd %float %395 %405 + %407 = OpCompositeInsert %v3float %406 %403 2 + %408 = OpCompositeExtract %float %312 1 + %409 = OpFSub %float %float_1 %408 + %410 = OpCompositeConstruct %v3float %409 %float_1 %408 + %411 = OpDot %float %407 %410 + %412 = OpFMul %float %float_0_25 %411 + %413 = OpExtInst %float %1 FClamp %412 %float_0 %float_1 + %414 = OpAccessChain %_ptr_Uniform_float %MobileDirectionalLight %int_3 %int_0 + %415 = OpLoad %float %414 + %416 = OpFMul %float %224 %415 + %417 = OpAccessChain %_ptr_Uniform_float %MobileDirectionalLight %int_3 %int_1 + %418 = OpLoad %float %417 + %419 = OpFAdd %float %416 %418 + %420 = OpExtInst %float %1 FClamp %419 %float_0 %float_1 + %421 = OpFMul %float %420 %420 + %422 = OpExtInst %float %1 FMix %413 %float_1 %421 + OpBranch %306 + %306 = OpLabel + %423 = OpPhi %float %float_1 %290 %422 %307 + %424 = OpLoad %v4float %280 + %425 = OpVectorShuffle %v3float %424 %424 0 1 2 + %426 = OpDot %float %206 %425 + %427 = OpExtInst %float %1 FMax %float_0 %426 + %428 = OpFAdd %v3float %181 %425 + %429 = OpExtInst %v3float %1 Normalize %428 + %430 = OpDot %float %206 %429 + %431 = OpExtInst %float %1 FMax %float_0 %430 + %432 = OpFMul %float %423 %427 + %433 = OpCompositeConstruct %v3float %432 %432 %432 + %434 = OpAccessChain %_ptr_Uniform_v4float %MobileDirectionalLight %int_0 + %435 = OpLoad %v4float %434 + %436 = OpVectorShuffle %v3float %435 %435 0 1 2 + %437 = OpFMul %v3float %433 %436 + %438 = OpFMul %float %253 %float_0_25 + %439 = OpFAdd %float %438 %float_0_25 + %440 = OpExtInst %v3float %1 Cross %206 %429 + %441 = OpDot %float %440 %440 + %442 = OpFMul %float %253 %253 + %443 = OpFMul %float %431 %442 + %444 = OpFMul %float %443 %443 + %445 = OpFAdd %float %441 %444 + %446 = OpFDiv %float %442 %445 + %447 = OpFMul %float %446 %446 + %448 = OpExtInst %float %1 FMin %447 %float_65504 + %449 = OpFMul %float %439 %448 + %450 = OpFMul %float %276 %449 + %451 = OpCompositeConstruct %v3float %450 %450 %450 + %452 = OpFAdd %v3float %270 %451 + %453 = OpFMul %v3float %437 %452 + %454 = OpAccessChain %_ptr_Uniform_float %_Globals %int_3 %int_3 + %455 = OpLoad %float %454 + %456 = OpFOrdGreaterThan %bool %455 %float_0 + %457 = OpSelect %float %456 %float_1 %float_0 + %458 = OpFOrdNotEqual %bool %457 %float_0 + %459 = OpSelect %float %458 %455 %164 + %460 = OpExtInst %float %1 Log2 %253 + %461 = OpFMul %float %float_1_20000005 %460 + %462 = OpFSub %float %float_1 %461 + %463 = OpFSub %float %459 %float_1 + %464 = OpFSub %float %463 %462 + %465 = OpLoad %type_cube_image %ReflectionCubemap + %466 = OpLoad %type_sampler %ReflectionCubemapSampler + %467 = OpSampledImage %type_sampled_image %465 %466 + %468 = OpImageSampleExplicitLod %v4float %467 %212 Lod %464 + OpSelectionMerge %469 None + OpBranchConditional %458 %470 %471 + %471 = OpLabel + %472 = OpVectorShuffle %v3float %468 %468 0 1 2 + %473 = OpCompositeExtract %float %468 3 + %474 = OpFMul %float %473 %float_16 + %475 = OpCompositeConstruct %v3float %474 %474 %474 + %476 = OpFMul %v3float %472 %475 + %477 = OpFMul %v3float %476 %476 + OpBranch %469 + %470 = OpLabel + %478 = OpVectorShuffle %v3float %468 %468 0 1 2 + %479 = OpVectorShuffle %v3float %162 %162 0 1 2 + %480 = OpFMul %v3float %478 %479 + OpBranch %469 + %469 = OpLabel + %481 = OpPhi %v3float %477 %471 %480 %470 + %482 = OpCompositeConstruct %v3float %277 %277 %277 + %483 = OpFMul %v3float %481 %482 + %484 = OpCompositeConstruct %v3float %276 %276 %276 + %485 = OpFMul %v3float %483 %484 + %486 = OpFAdd %v3float %453 %485 + OpBranch %487 + %487 = OpLabel + %488 = OpPhi %v3float %486 %469 %489 %490 + %491 = OpPhi %int %int_0 %469 %492 %490 + %493 = OpAccessChain %_ptr_Uniform_int %_Globals %int_0 + %494 = OpLoad %int %493 + %495 = OpSLessThan %bool %491 %494 + OpLoopMerge %496 %490 None + OpBranchConditional %495 %497 %496 + %497 = OpLabel + %498 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_1 %491 + %499 = OpLoad %v4float %498 + %500 = OpVectorShuffle %v3float %499 %499 0 1 2 + %501 = OpFSub %v3float %500 %179 + %502 = OpDot %float %501 %501 + %503 = OpExtInst %float %1 InverseSqrt %502 + %504 = OpCompositeConstruct %v3float %503 %503 %503 + %505 = OpFMul %v3float %501 %504 + %506 = OpFAdd %v3float %181 %505 + %507 = OpExtInst %v3float %1 Normalize %506 + %508 = OpDot %float %206 %505 + %509 = OpExtInst %float %1 FMax %float_0 %508 + %510 = OpDot %float %206 %507 + %511 = OpExtInst %float %1 FMax %float_0 %510 + %512 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_2 %491 + %513 = OpAccessChain %_ptr_Uniform_float %_Globals %int_2 %491 %int_3 + %514 = OpLoad %float %513 + %515 = OpFOrdEqual %bool %514 %float_0 + OpSelectionMerge %490 None + OpBranchConditional %515 %516 %517 + %517 = OpLabel + %518 = OpAccessChain %_ptr_Uniform_float %_Globals %int_1 %491 %int_3 + %519 = OpLoad %float %518 + %520 = OpCompositeConstruct %v3float %519 %519 %519 + %521 = OpFMul %v3float %501 %520 + %522 = OpDot %float %521 %521 + %523 = OpExtInst %float %1 FClamp %522 %float_0 %float_1 + %524 = OpFSub %float %float_1 %523 + %525 = OpExtInst %float %1 Pow %524 %514 + OpBranch %490 + %516 = OpLabel + %526 = OpFAdd %float %502 %float_1 + %527 = OpFDiv %float %float_1 %526 + %528 = OpAccessChain %_ptr_Uniform_float %_Globals %int_1 %491 %int_3 + %529 = OpLoad %float %528 + %530 = OpFMul %float %529 %529 + %531 = OpFMul %float %502 %530 + %532 = OpFMul %float %531 %531 + %533 = OpFSub %float %float_1 %532 + %534 = OpExtInst %float %1 FClamp %533 %float_0 %float_1 + %535 = OpFMul %float %534 %534 + %536 = OpFMul %float %527 %535 + OpBranch %490 + %490 = OpLabel + %537 = OpPhi %float %525 %517 %536 %516 + %538 = OpFMul %float %537 %509 + %539 = OpCompositeConstruct %v3float %538 %538 %538 + %540 = OpLoad %v4float %512 + %541 = OpVectorShuffle %v3float %540 %540 0 1 2 + %542 = OpFMul %v3float %539 %541 + %543 = OpFMul %v3float %542 %57 + %544 = OpExtInst %v3float %1 Cross %206 %507 + %545 = OpDot %float %544 %544 + %546 = OpFMul %float %511 %442 + %547 = OpFMul %float %546 %546 + %548 = OpFAdd %float %545 %547 + %549 = OpFDiv %float %442 %548 + %550 = OpFMul %float %549 %549 + %551 = OpExtInst %float %1 FMin %550 %float_65504 + %552 = OpFMul %float %439 %551 + %553 = OpFMul %float %276 %552 + %554 = OpCompositeConstruct %v3float %553 %553 %553 + %555 = OpFAdd %v3float %270 %554 + %556 = OpFMul %v3float %543 %555 + %557 = OpExtInst %v3float %1 FMin %55 %556 + %489 = OpFAdd %v3float %488 %557 + %492 = OpIAdd %int %491 %int_1 + OpBranch %487 + %496 = OpLabel + %558 = OpExtInst %v3float %1 FMax %47 %47 + %559 = OpFAdd %v3float %488 %558 + %560 = OpFAdd %v3float %270 %484 + %561 = OpCompositeConstruct %v3float %160 %160 %160 + %562 = OpExtInst %v3float %1 FMix %559 %560 %561 + %563 = OpCompositeExtract %float %142 3 + %564 = OpCompositeConstruct %v3float %563 %563 %563 + %565 = OpFMul %v3float %562 %564 + %566 = OpVectorShuffle %v3float %142 %142 0 1 2 + %567 = OpFAdd %v3float %565 %566 + %568 = OpVectorShuffle %v4float %137 %567 4 5 6 3 + %569 = OpCompositeExtract %float %143 3 + %570 = OpExtInst %float %1 FMin %569 %float_65500 + %571 = OpCompositeInsert %v4float %570 %568 3 + OpStore %out_var_SV_Target0 %571 + OpReturn + OpFunctionEnd diff --git a/third_party/spirv-cross/shaders-ue4-no-opt/asm/frag/array-copy-error.asm.invalid.frag b/third_party/spirv-cross/shaders-ue4-no-opt/asm/frag/array-copy-error.asm.invalid.frag new file mode 100644 index 0000000000..eba220ba4e --- /dev/null +++ b/third_party/spirv-cross/shaders-ue4-no-opt/asm/frag/array-copy-error.asm.invalid.frag @@ -0,0 +1,878 @@ +; SPIR-V +; Version: 1.0 +; Generator: Google spiregg; 0 +; Bound: 353 +; Schema: 0 + OpCapability Shader + OpExtension "SPV_GOOGLE_hlsl_functionality1" + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %MainPixelShader "main" %gl_FragCoord %in_var_TEXCOORD6 %in_var_TEXCOORD7 %in_var_TEXCOORD10_centroid %in_var_TEXCOORD11_centroid %in_var_TEXCOORD0 %in_var_PRIMITIVE_ID %gl_FrontFacing %gl_FragDepth %out_var_SV_Target0 + OpExecutionMode %MainPixelShader OriginUpperLeft + OpExecutionMode %MainPixelShader DepthReplacing + OpExecutionMode %MainPixelShader DepthLess + OpSource HLSL 600 + OpName %type_View "type.View" + OpMemberName %type_View 0 "View_TranslatedWorldToClip" + OpMemberName %type_View 1 "View_WorldToClip" + OpMemberName %type_View 2 "View_ClipToWorld" + OpMemberName %type_View 3 "View_TranslatedWorldToView" + OpMemberName %type_View 4 "View_ViewToTranslatedWorld" + OpMemberName %type_View 5 "View_TranslatedWorldToCameraView" + OpMemberName %type_View 6 "View_CameraViewToTranslatedWorld" + OpMemberName %type_View 7 "View_ViewToClip" + OpMemberName %type_View 8 "View_ViewToClipNoAA" + OpMemberName %type_View 9 "View_ClipToView" + OpMemberName %type_View 10 "View_ClipToTranslatedWorld" + OpMemberName %type_View 11 "View_SVPositionToTranslatedWorld" + OpMemberName %type_View 12 "View_ScreenToWorld" + OpMemberName %type_View 13 "View_ScreenToTranslatedWorld" + OpMemberName %type_View 14 "View_ViewForward" + OpMemberName %type_View 15 "PrePadding_View_908" + OpMemberName %type_View 16 "View_ViewUp" + OpMemberName %type_View 17 "PrePadding_View_924" + OpMemberName %type_View 18 "View_ViewRight" + OpMemberName %type_View 19 "PrePadding_View_940" + OpMemberName %type_View 20 "View_HMDViewNoRollUp" + OpMemberName %type_View 21 "PrePadding_View_956" + OpMemberName %type_View 22 "View_HMDViewNoRollRight" + OpMemberName %type_View 23 "PrePadding_View_972" + OpMemberName %type_View 24 "View_InvDeviceZToWorldZTransform" + OpMemberName %type_View 25 "View_ScreenPositionScaleBias" + OpMemberName %type_View 26 "View_WorldCameraOrigin" + OpMemberName %type_View 27 "PrePadding_View_1020" + OpMemberName %type_View 28 "View_TranslatedWorldCameraOrigin" + OpMemberName %type_View 29 "PrePadding_View_1036" + OpMemberName %type_View 30 "View_WorldViewOrigin" + OpMemberName %type_View 31 "PrePadding_View_1052" + OpMemberName %type_View 32 "View_PreViewTranslation" + OpMemberName %type_View 33 "PrePadding_View_1068" + OpMemberName %type_View 34 "View_PrevProjection" + OpMemberName %type_View 35 "View_PrevViewProj" + OpMemberName %type_View 36 "View_PrevViewRotationProj" + OpMemberName %type_View 37 "View_PrevViewToClip" + OpMemberName %type_View 38 "View_PrevClipToView" + OpMemberName %type_View 39 "View_PrevTranslatedWorldToClip" + OpMemberName %type_View 40 "View_PrevTranslatedWorldToView" + OpMemberName %type_View 41 "View_PrevViewToTranslatedWorld" + OpMemberName %type_View 42 "View_PrevTranslatedWorldToCameraView" + OpMemberName %type_View 43 "View_PrevCameraViewToTranslatedWorld" + OpMemberName %type_View 44 "View_PrevWorldCameraOrigin" + OpMemberName %type_View 45 "PrePadding_View_1724" + OpMemberName %type_View 46 "View_PrevWorldViewOrigin" + OpMemberName %type_View 47 "PrePadding_View_1740" + OpMemberName %type_View 48 "View_PrevPreViewTranslation" + OpMemberName %type_View 49 "PrePadding_View_1756" + OpMemberName %type_View 50 "View_PrevInvViewProj" + OpMemberName %type_View 51 "View_PrevScreenToTranslatedWorld" + OpMemberName %type_View 52 "View_ClipToPrevClip" + OpMemberName %type_View 53 "View_TemporalAAJitter" + OpMemberName %type_View 54 "View_GlobalClippingPlane" + OpMemberName %type_View 55 "View_FieldOfViewWideAngles" + OpMemberName %type_View 56 "View_PrevFieldOfViewWideAngles" + OpMemberName %type_View 57 "View_ViewRectMin" + OpMemberName %type_View 58 "View_ViewSizeAndInvSize" + OpMemberName %type_View 59 "View_BufferSizeAndInvSize" + OpMemberName %type_View 60 "View_BufferBilinearUVMinMax" + OpMemberName %type_View 61 "View_NumSceneColorMSAASamples" + OpMemberName %type_View 62 "View_PreExposure" + OpMemberName %type_View 63 "View_OneOverPreExposure" + OpMemberName %type_View 64 "PrePadding_View_2076" + OpMemberName %type_View 65 "View_DiffuseOverrideParameter" + OpMemberName %type_View 66 "View_SpecularOverrideParameter" + OpMemberName %type_View 67 "View_NormalOverrideParameter" + OpMemberName %type_View 68 "View_RoughnessOverrideParameter" + OpMemberName %type_View 69 "View_PrevFrameGameTime" + OpMemberName %type_View 70 "View_PrevFrameRealTime" + OpMemberName %type_View 71 "View_OutOfBoundsMask" + OpMemberName %type_View 72 "PrePadding_View_2148" + OpMemberName %type_View 73 "PrePadding_View_2152" + OpMemberName %type_View 74 "PrePadding_View_2156" + OpMemberName %type_View 75 "View_WorldCameraMovementSinceLastFrame" + OpMemberName %type_View 76 "View_CullingSign" + OpMemberName %type_View 77 "View_NearPlane" + OpMemberName %type_View 78 "View_AdaptiveTessellationFactor" + OpMemberName %type_View 79 "View_GameTime" + OpMemberName %type_View 80 "View_RealTime" + OpMemberName %type_View 81 "View_DeltaTime" + OpMemberName %type_View 82 "View_MaterialTextureMipBias" + OpMemberName %type_View 83 "View_MaterialTextureDerivativeMultiply" + OpMemberName %type_View 84 "View_Random" + OpMemberName %type_View 85 "View_FrameNumber" + OpMemberName %type_View 86 "View_StateFrameIndexMod8" + OpMemberName %type_View 87 "View_StateFrameIndex" + OpMemberName %type_View 88 "View_CameraCut" + OpMemberName %type_View 89 "View_UnlitViewmodeMask" + OpMemberName %type_View 90 "PrePadding_View_2228" + OpMemberName %type_View 91 "PrePadding_View_2232" + OpMemberName %type_View 92 "PrePadding_View_2236" + OpMemberName %type_View 93 "View_DirectionalLightColor" + OpMemberName %type_View 94 "View_DirectionalLightDirection" + OpMemberName %type_View 95 "PrePadding_View_2268" + OpMemberName %type_View 96 "View_TranslucencyLightingVolumeMin" + OpMemberName %type_View 97 "View_TranslucencyLightingVolumeInvSize" + OpMemberName %type_View 98 "View_TemporalAAParams" + OpMemberName %type_View 99 "View_CircleDOFParams" + OpMemberName %type_View 100 "View_DepthOfFieldSensorWidth" + OpMemberName %type_View 101 "View_DepthOfFieldFocalDistance" + OpMemberName %type_View 102 "View_DepthOfFieldScale" + OpMemberName %type_View 103 "View_DepthOfFieldFocalLength" + OpMemberName %type_View 104 "View_DepthOfFieldFocalRegion" + OpMemberName %type_View 105 "View_DepthOfFieldNearTransitionRegion" + OpMemberName %type_View 106 "View_DepthOfFieldFarTransitionRegion" + OpMemberName %type_View 107 "View_MotionBlurNormalizedToPixel" + OpMemberName %type_View 108 "View_bSubsurfacePostprocessEnabled" + OpMemberName %type_View 109 "View_GeneralPurposeTweak" + OpMemberName %type_View 110 "View_DemosaicVposOffset" + OpMemberName %type_View 111 "PrePadding_View_2412" + OpMemberName %type_View 112 "View_IndirectLightingColorScale" + OpMemberName %type_View 113 "View_HDR32bppEncodingMode" + OpMemberName %type_View 114 "View_AtmosphericFogSunDirection" + OpMemberName %type_View 115 "View_AtmosphericFogSunPower" + OpMemberName %type_View 116 "View_AtmosphericFogPower" + OpMemberName %type_View 117 "View_AtmosphericFogDensityScale" + OpMemberName %type_View 118 "View_AtmosphericFogDensityOffset" + OpMemberName %type_View 119 "View_AtmosphericFogGroundOffset" + OpMemberName %type_View 120 "View_AtmosphericFogDistanceScale" + OpMemberName %type_View 121 "View_AtmosphericFogAltitudeScale" + OpMemberName %type_View 122 "View_AtmosphericFogHeightScaleRayleigh" + OpMemberName %type_View 123 "View_AtmosphericFogStartDistance" + OpMemberName %type_View 124 "View_AtmosphericFogDistanceOffset" + OpMemberName %type_View 125 "View_AtmosphericFogSunDiscScale" + OpMemberName %type_View 126 "View_AtmosphericFogSunDiscHalfApexAngleRadian" + OpMemberName %type_View 127 "PrePadding_View_2492" + OpMemberName %type_View 128 "View_AtmosphericFogSunDiscLuminance" + OpMemberName %type_View 129 "View_AtmosphericFogRenderMask" + OpMemberName %type_View 130 "View_AtmosphericFogInscatterAltitudeSampleNum" + OpMemberName %type_View 131 "PrePadding_View_2520" + OpMemberName %type_View 132 "PrePadding_View_2524" + OpMemberName %type_View 133 "View_AtmosphericFogSunColor" + OpMemberName %type_View 134 "View_NormalCurvatureToRoughnessScaleBias" + OpMemberName %type_View 135 "View_RenderingReflectionCaptureMask" + OpMemberName %type_View 136 "View_AmbientCubemapTint" + OpMemberName %type_View 137 "View_AmbientCubemapIntensity" + OpMemberName %type_View 138 "View_SkyLightParameters" + OpMemberName %type_View 139 "PrePadding_View_2584" + OpMemberName %type_View 140 "PrePadding_View_2588" + OpMemberName %type_View 141 "View_SkyLightColor" + OpMemberName %type_View 142 "View_SkyIrradianceEnvironmentMap" + OpMemberName %type_View 143 "View_MobilePreviewMode" + OpMemberName %type_View 144 "View_HMDEyePaddingOffset" + OpMemberName %type_View 145 "View_ReflectionCubemapMaxMip" + OpMemberName %type_View 146 "View_ShowDecalsMask" + OpMemberName %type_View 147 "View_DistanceFieldAOSpecularOcclusionMode" + OpMemberName %type_View 148 "View_IndirectCapsuleSelfShadowingIntensity" + OpMemberName %type_View 149 "PrePadding_View_2744" + OpMemberName %type_View 150 "PrePadding_View_2748" + OpMemberName %type_View 151 "View_ReflectionEnvironmentRoughnessMixingScaleBiasAndLargestWeight" + OpMemberName %type_View 152 "View_StereoPassIndex" + OpMemberName %type_View 153 "View_GlobalVolumeCenterAndExtent" + OpMemberName %type_View 154 "View_GlobalVolumeWorldToUVAddAndMul" + OpMemberName %type_View 155 "View_GlobalVolumeDimension" + OpMemberName %type_View 156 "View_GlobalVolumeTexelSize" + OpMemberName %type_View 157 "View_MaxGlobalDistance" + OpMemberName %type_View 158 "PrePadding_View_2908" + OpMemberName %type_View 159 "View_CursorPosition" + OpMemberName %type_View 160 "View_bCheckerboardSubsurfaceProfileRendering" + OpMemberName %type_View 161 "PrePadding_View_2924" + OpMemberName %type_View 162 "View_VolumetricFogInvGridSize" + OpMemberName %type_View 163 "PrePadding_View_2940" + OpMemberName %type_View 164 "View_VolumetricFogGridZParams" + OpMemberName %type_View 165 "PrePadding_View_2956" + OpMemberName %type_View 166 "View_VolumetricFogSVPosToVolumeUV" + OpMemberName %type_View 167 "View_VolumetricFogMaxDistance" + OpMemberName %type_View 168 "PrePadding_View_2972" + OpMemberName %type_View 169 "View_VolumetricLightmapWorldToUVScale" + OpMemberName %type_View 170 "PrePadding_View_2988" + OpMemberName %type_View 171 "View_VolumetricLightmapWorldToUVAdd" + OpMemberName %type_View 172 "PrePadding_View_3004" + OpMemberName %type_View 173 "View_VolumetricLightmapIndirectionTextureSize" + OpMemberName %type_View 174 "View_VolumetricLightmapBrickSize" + OpMemberName %type_View 175 "View_VolumetricLightmapBrickTexelSize" + OpMemberName %type_View 176 "View_StereoIPD" + OpMemberName %type_View 177 "View_IndirectLightingCacheShowFlag" + OpMemberName %type_View 178 "View_EyeToPixelSpreadAngle" + OpName %View "View" + OpName %type_PrimitiveDither "type.PrimitiveDither" + OpMemberName %type_PrimitiveDither 0 "PrimitiveDither_LODFactor" + OpName %PrimitiveDither "PrimitiveDither" + OpName %type_PrimitiveFade "type.PrimitiveFade" + OpMemberName %type_PrimitiveFade 0 "PrimitiveFade_FadeTimeScaleBias" + OpName %PrimitiveFade "PrimitiveFade" + OpName %type_Material "type.Material" + OpMemberName %type_Material 0 "Material_VectorExpressions" + OpMemberName %type_Material 1 "Material_ScalarExpressions" + OpName %Material "Material" + OpName %type_2d_image "type.2d.image" + OpName %Material_Texture2D_0 "Material_Texture2D_0" + OpName %type_sampler "type.sampler" + OpName %Material_Texture2D_0Sampler "Material_Texture2D_0Sampler" + OpName %Material_Texture2D_3 "Material_Texture2D_3" + OpName %Material_Texture2D_3Sampler "Material_Texture2D_3Sampler" + OpName %in_var_TEXCOORD6 "in.var.TEXCOORD6" + OpName %in_var_TEXCOORD7 "in.var.TEXCOORD7" + OpName %in_var_TEXCOORD10_centroid "in.var.TEXCOORD10_centroid" + OpName %in_var_TEXCOORD11_centroid "in.var.TEXCOORD11_centroid" + OpName %in_var_TEXCOORD0 "in.var.TEXCOORD0" + OpName %in_var_PRIMITIVE_ID "in.var.PRIMITIVE_ID" + OpName %out_var_SV_Target0 "out.var.SV_Target0" + OpName %MainPixelShader "MainPixelShader" + OpName %type_sampled_image "type.sampled.image" + OpDecorate %gl_FragCoord BuiltIn FragCoord + OpDecorateString %gl_FragCoord UserSemantic "SV_Position" + OpDecorateString %in_var_TEXCOORD6 UserSemantic "TEXCOORD6" + OpDecorateString %in_var_TEXCOORD7 UserSemantic "TEXCOORD7" + OpDecorateString %in_var_TEXCOORD10_centroid UserSemantic "TEXCOORD10_centroid" + OpDecorateString %in_var_TEXCOORD11_centroid UserSemantic "TEXCOORD11_centroid" + OpDecorateString %in_var_TEXCOORD0 UserSemantic "TEXCOORD0" + OpDecorateString %in_var_PRIMITIVE_ID UserSemantic "PRIMITIVE_ID" + OpDecorate %in_var_PRIMITIVE_ID Flat + OpDecorate %gl_FrontFacing BuiltIn FrontFacing + OpDecorateString %gl_FrontFacing UserSemantic "SV_IsFrontFace" + OpDecorate %gl_FrontFacing Flat + OpDecorate %gl_FragDepth BuiltIn FragDepth + OpDecorateString %gl_FragDepth UserSemantic "SV_DepthLessEqual" + OpDecorateString %out_var_SV_Target0 UserSemantic "SV_Target0" + OpDecorate %in_var_TEXCOORD6 Location 0 + OpDecorate %in_var_TEXCOORD7 Location 1 + OpDecorate %in_var_TEXCOORD10_centroid Location 2 + OpDecorate %in_var_TEXCOORD11_centroid Location 3 + OpDecorate %in_var_TEXCOORD0 Location 4 + OpDecorate %in_var_PRIMITIVE_ID Location 5 + OpDecorate %out_var_SV_Target0 Location 0 + OpDecorate %View DescriptorSet 0 + OpDecorate %View Binding 0 + OpDecorate %PrimitiveDither DescriptorSet 0 + OpDecorate %PrimitiveDither Binding 1 + OpDecorate %PrimitiveFade DescriptorSet 0 + OpDecorate %PrimitiveFade Binding 2 + OpDecorate %Material DescriptorSet 0 + OpDecorate %Material Binding 3 + OpDecorate %Material_Texture2D_0 DescriptorSet 0 + OpDecorate %Material_Texture2D_0 Binding 0 + OpDecorate %Material_Texture2D_0Sampler DescriptorSet 0 + OpDecorate %Material_Texture2D_0Sampler Binding 0 + OpDecorate %Material_Texture2D_3 DescriptorSet 0 + OpDecorate %Material_Texture2D_3 Binding 1 + OpDecorate %Material_Texture2D_3Sampler DescriptorSet 0 + OpDecorate %Material_Texture2D_3Sampler Binding 1 + OpDecorate %_arr_v4float_uint_2 ArrayStride 16 + OpDecorate %_arr_v4float_uint_7 ArrayStride 16 + OpDecorate %_arr_v4float_uint_4 ArrayStride 16 + OpMemberDecorate %type_View 0 Offset 0 + OpMemberDecorate %type_View 0 MatrixStride 16 + OpMemberDecorate %type_View 0 ColMajor + OpMemberDecorate %type_View 1 Offset 64 + OpMemberDecorate %type_View 1 MatrixStride 16 + OpMemberDecorate %type_View 1 ColMajor + OpMemberDecorate %type_View 2 Offset 128 + OpMemberDecorate %type_View 2 MatrixStride 16 + OpMemberDecorate %type_View 2 ColMajor + OpMemberDecorate %type_View 3 Offset 192 + OpMemberDecorate %type_View 3 MatrixStride 16 + OpMemberDecorate %type_View 3 ColMajor + OpMemberDecorate %type_View 4 Offset 256 + OpMemberDecorate %type_View 4 MatrixStride 16 + OpMemberDecorate %type_View 4 ColMajor + OpMemberDecorate %type_View 5 Offset 320 + OpMemberDecorate %type_View 5 MatrixStride 16 + OpMemberDecorate %type_View 5 ColMajor + OpMemberDecorate %type_View 6 Offset 384 + OpMemberDecorate %type_View 6 MatrixStride 16 + OpMemberDecorate %type_View 6 ColMajor + OpMemberDecorate %type_View 7 Offset 448 + OpMemberDecorate %type_View 7 MatrixStride 16 + OpMemberDecorate %type_View 7 ColMajor + OpMemberDecorate %type_View 8 Offset 512 + OpMemberDecorate %type_View 8 MatrixStride 16 + OpMemberDecorate %type_View 8 ColMajor + OpMemberDecorate %type_View 9 Offset 576 + OpMemberDecorate %type_View 9 MatrixStride 16 + OpMemberDecorate %type_View 9 ColMajor + OpMemberDecorate %type_View 10 Offset 640 + OpMemberDecorate %type_View 10 MatrixStride 16 + OpMemberDecorate %type_View 10 ColMajor + OpMemberDecorate %type_View 11 Offset 704 + OpMemberDecorate %type_View 11 MatrixStride 16 + OpMemberDecorate %type_View 11 ColMajor + OpMemberDecorate %type_View 12 Offset 768 + OpMemberDecorate %type_View 12 MatrixStride 16 + OpMemberDecorate %type_View 12 ColMajor + OpMemberDecorate %type_View 13 Offset 832 + OpMemberDecorate %type_View 13 MatrixStride 16 + OpMemberDecorate %type_View 13 ColMajor + OpMemberDecorate %type_View 14 Offset 896 + OpMemberDecorate %type_View 15 Offset 908 + OpMemberDecorate %type_View 16 Offset 912 + OpMemberDecorate %type_View 17 Offset 924 + OpMemberDecorate %type_View 18 Offset 928 + OpMemberDecorate %type_View 19 Offset 940 + OpMemberDecorate %type_View 20 Offset 944 + OpMemberDecorate %type_View 21 Offset 956 + OpMemberDecorate %type_View 22 Offset 960 + OpMemberDecorate %type_View 23 Offset 972 + OpMemberDecorate %type_View 24 Offset 976 + OpMemberDecorate %type_View 25 Offset 992 + OpMemberDecorate %type_View 26 Offset 1008 + OpMemberDecorate %type_View 27 Offset 1020 + OpMemberDecorate %type_View 28 Offset 1024 + OpMemberDecorate %type_View 29 Offset 1036 + OpMemberDecorate %type_View 30 Offset 1040 + OpMemberDecorate %type_View 31 Offset 1052 + OpMemberDecorate %type_View 32 Offset 1056 + OpMemberDecorate %type_View 33 Offset 1068 + OpMemberDecorate %type_View 34 Offset 1072 + OpMemberDecorate %type_View 34 MatrixStride 16 + OpMemberDecorate %type_View 34 ColMajor + OpMemberDecorate %type_View 35 Offset 1136 + OpMemberDecorate %type_View 35 MatrixStride 16 + OpMemberDecorate %type_View 35 ColMajor + OpMemberDecorate %type_View 36 Offset 1200 + OpMemberDecorate %type_View 36 MatrixStride 16 + OpMemberDecorate %type_View 36 ColMajor + OpMemberDecorate %type_View 37 Offset 1264 + OpMemberDecorate %type_View 37 MatrixStride 16 + OpMemberDecorate %type_View 37 ColMajor + OpMemberDecorate %type_View 38 Offset 1328 + OpMemberDecorate %type_View 38 MatrixStride 16 + OpMemberDecorate %type_View 38 ColMajor + OpMemberDecorate %type_View 39 Offset 1392 + OpMemberDecorate %type_View 39 MatrixStride 16 + OpMemberDecorate %type_View 39 ColMajor + OpMemberDecorate %type_View 40 Offset 1456 + OpMemberDecorate %type_View 40 MatrixStride 16 + OpMemberDecorate %type_View 40 ColMajor + OpMemberDecorate %type_View 41 Offset 1520 + OpMemberDecorate %type_View 41 MatrixStride 16 + OpMemberDecorate %type_View 41 ColMajor + OpMemberDecorate %type_View 42 Offset 1584 + OpMemberDecorate %type_View 42 MatrixStride 16 + OpMemberDecorate %type_View 42 ColMajor + OpMemberDecorate %type_View 43 Offset 1648 + OpMemberDecorate %type_View 43 MatrixStride 16 + OpMemberDecorate %type_View 43 ColMajor + OpMemberDecorate %type_View 44 Offset 1712 + OpMemberDecorate %type_View 45 Offset 1724 + OpMemberDecorate %type_View 46 Offset 1728 + OpMemberDecorate %type_View 47 Offset 1740 + OpMemberDecorate %type_View 48 Offset 1744 + OpMemberDecorate %type_View 49 Offset 1756 + OpMemberDecorate %type_View 50 Offset 1760 + OpMemberDecorate %type_View 50 MatrixStride 16 + OpMemberDecorate %type_View 50 ColMajor + OpMemberDecorate %type_View 51 Offset 1824 + OpMemberDecorate %type_View 51 MatrixStride 16 + OpMemberDecorate %type_View 51 ColMajor + OpMemberDecorate %type_View 52 Offset 1888 + OpMemberDecorate %type_View 52 MatrixStride 16 + OpMemberDecorate %type_View 52 ColMajor + OpMemberDecorate %type_View 53 Offset 1952 + OpMemberDecorate %type_View 54 Offset 1968 + OpMemberDecorate %type_View 55 Offset 1984 + OpMemberDecorate %type_View 56 Offset 1992 + OpMemberDecorate %type_View 57 Offset 2000 + OpMemberDecorate %type_View 58 Offset 2016 + OpMemberDecorate %type_View 59 Offset 2032 + OpMemberDecorate %type_View 60 Offset 2048 + OpMemberDecorate %type_View 61 Offset 2064 + OpMemberDecorate %type_View 62 Offset 2068 + OpMemberDecorate %type_View 63 Offset 2072 + OpMemberDecorate %type_View 64 Offset 2076 + OpMemberDecorate %type_View 65 Offset 2080 + OpMemberDecorate %type_View 66 Offset 2096 + OpMemberDecorate %type_View 67 Offset 2112 + OpMemberDecorate %type_View 68 Offset 2128 + OpMemberDecorate %type_View 69 Offset 2136 + OpMemberDecorate %type_View 70 Offset 2140 + OpMemberDecorate %type_View 71 Offset 2144 + OpMemberDecorate %type_View 72 Offset 2148 + OpMemberDecorate %type_View 73 Offset 2152 + OpMemberDecorate %type_View 74 Offset 2156 + OpMemberDecorate %type_View 75 Offset 2160 + OpMemberDecorate %type_View 76 Offset 2172 + OpMemberDecorate %type_View 77 Offset 2176 + OpMemberDecorate %type_View 78 Offset 2180 + OpMemberDecorate %type_View 79 Offset 2184 + OpMemberDecorate %type_View 80 Offset 2188 + OpMemberDecorate %type_View 81 Offset 2192 + OpMemberDecorate %type_View 82 Offset 2196 + OpMemberDecorate %type_View 83 Offset 2200 + OpMemberDecorate %type_View 84 Offset 2204 + OpMemberDecorate %type_View 85 Offset 2208 + OpMemberDecorate %type_View 86 Offset 2212 + OpMemberDecorate %type_View 87 Offset 2216 + OpMemberDecorate %type_View 88 Offset 2220 + OpMemberDecorate %type_View 89 Offset 2224 + OpMemberDecorate %type_View 90 Offset 2228 + OpMemberDecorate %type_View 91 Offset 2232 + OpMemberDecorate %type_View 92 Offset 2236 + OpMemberDecorate %type_View 93 Offset 2240 + OpMemberDecorate %type_View 94 Offset 2256 + OpMemberDecorate %type_View 95 Offset 2268 + OpMemberDecorate %type_View 96 Offset 2272 + OpMemberDecorate %type_View 97 Offset 2304 + OpMemberDecorate %type_View 98 Offset 2336 + OpMemberDecorate %type_View 99 Offset 2352 + OpMemberDecorate %type_View 100 Offset 2368 + OpMemberDecorate %type_View 101 Offset 2372 + OpMemberDecorate %type_View 102 Offset 2376 + OpMemberDecorate %type_View 103 Offset 2380 + OpMemberDecorate %type_View 104 Offset 2384 + OpMemberDecorate %type_View 105 Offset 2388 + OpMemberDecorate %type_View 106 Offset 2392 + OpMemberDecorate %type_View 107 Offset 2396 + OpMemberDecorate %type_View 108 Offset 2400 + OpMemberDecorate %type_View 109 Offset 2404 + OpMemberDecorate %type_View 110 Offset 2408 + OpMemberDecorate %type_View 111 Offset 2412 + OpMemberDecorate %type_View 112 Offset 2416 + OpMemberDecorate %type_View 113 Offset 2428 + OpMemberDecorate %type_View 114 Offset 2432 + OpMemberDecorate %type_View 115 Offset 2444 + OpMemberDecorate %type_View 116 Offset 2448 + OpMemberDecorate %type_View 117 Offset 2452 + OpMemberDecorate %type_View 118 Offset 2456 + OpMemberDecorate %type_View 119 Offset 2460 + OpMemberDecorate %type_View 120 Offset 2464 + OpMemberDecorate %type_View 121 Offset 2468 + OpMemberDecorate %type_View 122 Offset 2472 + OpMemberDecorate %type_View 123 Offset 2476 + OpMemberDecorate %type_View 124 Offset 2480 + OpMemberDecorate %type_View 125 Offset 2484 + OpMemberDecorate %type_View 126 Offset 2488 + OpMemberDecorate %type_View 127 Offset 2492 + OpMemberDecorate %type_View 128 Offset 2496 + OpMemberDecorate %type_View 129 Offset 2512 + OpMemberDecorate %type_View 130 Offset 2516 + OpMemberDecorate %type_View 131 Offset 2520 + OpMemberDecorate %type_View 132 Offset 2524 + OpMemberDecorate %type_View 133 Offset 2528 + OpMemberDecorate %type_View 134 Offset 2544 + OpMemberDecorate %type_View 135 Offset 2556 + OpMemberDecorate %type_View 136 Offset 2560 + OpMemberDecorate %type_View 137 Offset 2576 + OpMemberDecorate %type_View 138 Offset 2580 + OpMemberDecorate %type_View 139 Offset 2584 + OpMemberDecorate %type_View 140 Offset 2588 + OpMemberDecorate %type_View 141 Offset 2592 + OpMemberDecorate %type_View 142 Offset 2608 + OpMemberDecorate %type_View 143 Offset 2720 + OpMemberDecorate %type_View 144 Offset 2724 + OpMemberDecorate %type_View 145 Offset 2728 + OpMemberDecorate %type_View 146 Offset 2732 + OpMemberDecorate %type_View 147 Offset 2736 + OpMemberDecorate %type_View 148 Offset 2740 + OpMemberDecorate %type_View 149 Offset 2744 + OpMemberDecorate %type_View 150 Offset 2748 + OpMemberDecorate %type_View 151 Offset 2752 + OpMemberDecorate %type_View 152 Offset 2764 + OpMemberDecorate %type_View 153 Offset 2768 + OpMemberDecorate %type_View 154 Offset 2832 + OpMemberDecorate %type_View 155 Offset 2896 + OpMemberDecorate %type_View 156 Offset 2900 + OpMemberDecorate %type_View 157 Offset 2904 + OpMemberDecorate %type_View 158 Offset 2908 + OpMemberDecorate %type_View 159 Offset 2912 + OpMemberDecorate %type_View 160 Offset 2920 + OpMemberDecorate %type_View 161 Offset 2924 + OpMemberDecorate %type_View 162 Offset 2928 + OpMemberDecorate %type_View 163 Offset 2940 + OpMemberDecorate %type_View 164 Offset 2944 + OpMemberDecorate %type_View 165 Offset 2956 + OpMemberDecorate %type_View 166 Offset 2960 + OpMemberDecorate %type_View 167 Offset 2968 + OpMemberDecorate %type_View 168 Offset 2972 + OpMemberDecorate %type_View 169 Offset 2976 + OpMemberDecorate %type_View 170 Offset 2988 + OpMemberDecorate %type_View 171 Offset 2992 + OpMemberDecorate %type_View 172 Offset 3004 + OpMemberDecorate %type_View 173 Offset 3008 + OpMemberDecorate %type_View 174 Offset 3020 + OpMemberDecorate %type_View 175 Offset 3024 + OpMemberDecorate %type_View 176 Offset 3036 + OpMemberDecorate %type_View 177 Offset 3040 + OpMemberDecorate %type_View 178 Offset 3044 + OpDecorate %type_View Block + OpMemberDecorate %type_PrimitiveDither 0 Offset 0 + OpDecorate %type_PrimitiveDither Block + OpMemberDecorate %type_PrimitiveFade 0 Offset 0 + OpDecorate %type_PrimitiveFade Block + OpDecorate %_arr_v4float_uint_9 ArrayStride 16 + OpDecorate %_arr_v4float_uint_3 ArrayStride 16 + OpMemberDecorate %type_Material 0 Offset 0 + OpMemberDecorate %type_Material 1 Offset 144 + OpDecorate %type_Material Block + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 +%mat4v4float = OpTypeMatrix %v4float 4 + %v3float = OpTypeVector %float 3 + %v2float = OpTypeVector %float 2 + %int = OpTypeInt 32 1 + %uint = OpTypeInt 32 0 + %uint_2 = OpConstant %uint 2 + %uint_7 = OpConstant %uint 7 + %uint_4 = OpConstant %uint 4 + %v2int = OpTypeVector %int 2 +%float_0_00100000005 = OpConstant %float 0.00100000005 + %int_2 = OpConstant %int 2 + %int_0 = OpConstant %int 0 + %int_1 = OpConstant %int 1 + %float_0 = OpConstant %float 0 + %49 = OpConstantComposite %v2float %float_0 %float_0 + %float_1 = OpConstant %float 1 + %int_4 = OpConstant %int 4 + %int_11 = OpConstant %int 11 +%float_0_249500006 = OpConstant %float 0.249500006 + %54 = OpConstantComposite %v2float %float_0_249500006 %float_0_249500006 +%float_0_499992371 = OpConstant %float 0.499992371 + %56 = OpConstantComposite %v2float %float_0_499992371 %float_0_499992371 + %int_32 = OpConstant %int 32 + %int_53 = OpConstant %int 53 + %int_57 = OpConstant %int 57 + %int_80 = OpConstant %int 80 + %int_82 = OpConstant %int 82 + %int_98 = OpConstant %int 98 + %uint_1 = OpConstant %uint 1 +%mat3v3float = OpTypeMatrix %v3float 3 + %float_2 = OpConstant %float 2 + %float_n1 = OpConstant %float -1 + %67 = OpConstantComposite %v2float %float_n1 %float_n1 + %bool = OpTypeBool + %float_n0_5 = OpConstant %float -0.5 + %70 = OpConstantComposite %v3float %float_0 %float_0 %float_1 +%float_0_333299994 = OpConstant %float 0.333299994 + %uint_5 = OpConstant %uint 5 +%float_347_834503 = OpConstant %float 347.834503 +%float_3343_28369 = OpConstant %float 3343.28369 + %75 = OpConstantComposite %v2float %float_347_834503 %float_3343_28369 + %float_1000 = OpConstant %float 1000 +%_arr_v4float_uint_2 = OpTypeArray %v4float %uint_2 +%_arr_v4float_uint_7 = OpTypeArray %v4float %uint_7 +%_arr_v4float_uint_4 = OpTypeArray %v4float %uint_4 + %type_View = OpTypeStruct %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %v3float %float %v3float %float %v3float %float %v3float %float %v3float %float %v4float %v4float %v3float %float %v3float %float %v3float %float %v3float %float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %v3float %float %v3float %float %v3float %float %mat4v4float %mat4v4float %mat4v4float %v4float %v4float %v2float %v2float %v4float %v4float %v4float %v4float %int %float %float %float %v4float %v4float %v4float %v2float %float %float %float %float %float %float %v3float %float %float %float %float %float %float %float %float %uint %uint %uint %uint %float %float %float %float %float %v4float %v3float %float %_arr_v4float_uint_2 %_arr_v4float_uint_2 %v4float %v4float %float %float %float %float %float %float %float %float %float %float %float %float %v3float %float %v3float %float %float %float %float %float %float %float %float %float %float %float %float %float %v4float %uint %uint %uint %uint %v4float %v3float %float %v4float %float %float %float %float %v4float %_arr_v4float_uint_7 %float %float %float %float %uint %float %float %float %v3float %int %_arr_v4float_uint_4 %_arr_v4float_uint_4 %float %float %float %float %v2int %float %float %v3float %float %v3float %float %v2float %float %float %v3float %float %v3float %float %v3float %float %v3float %float %float %float +%_ptr_Uniform_type_View = OpTypePointer Uniform %type_View +%type_PrimitiveDither = OpTypeStruct %float +%_ptr_Uniform_type_PrimitiveDither = OpTypePointer Uniform %type_PrimitiveDither +%type_PrimitiveFade = OpTypeStruct %v2float +%_ptr_Uniform_type_PrimitiveFade = OpTypePointer Uniform %type_PrimitiveFade + %uint_9 = OpConstant %uint 9 +%_arr_v4float_uint_9 = OpTypeArray %v4float %uint_9 + %uint_3 = OpConstant %uint 3 +%_arr_v4float_uint_3 = OpTypeArray %v4float %uint_3 +%type_Material = OpTypeStruct %_arr_v4float_uint_9 %_arr_v4float_uint_3 +%_ptr_Uniform_type_Material = OpTypePointer Uniform %type_Material +%type_2d_image = OpTypeImage %float 2D 2 0 0 1 Unknown +%_ptr_UniformConstant_type_2d_image = OpTypePointer UniformConstant %type_2d_image +%type_sampler = OpTypeSampler +%_ptr_UniformConstant_type_sampler = OpTypePointer UniformConstant %type_sampler +%_ptr_Input_v4float = OpTypePointer Input %v4float +%_arr_v4float_uint_1 = OpTypeArray %v4float %uint_1 +%_ptr_Input__arr_v4float_uint_1 = OpTypePointer Input %_arr_v4float_uint_1 +%_ptr_Input_uint = OpTypePointer Input %uint +%_ptr_Input_bool = OpTypePointer Input %bool +%_ptr_Output_float = OpTypePointer Output %float +%_ptr_Output_v4float = OpTypePointer Output %v4float + %void = OpTypeVoid + %93 = OpTypeFunction %void +%_ptr_Uniform_mat4v4float = OpTypePointer Uniform %mat4v4float +%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float +%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float +%_ptr_Uniform_float = OpTypePointer Uniform %float +%type_sampled_image = OpTypeSampledImage %type_2d_image + %View = OpVariable %_ptr_Uniform_type_View Uniform +%PrimitiveDither = OpVariable %_ptr_Uniform_type_PrimitiveDither Uniform +%PrimitiveFade = OpVariable %_ptr_Uniform_type_PrimitiveFade Uniform + %Material = OpVariable %_ptr_Uniform_type_Material Uniform +%Material_Texture2D_0 = OpVariable %_ptr_UniformConstant_type_2d_image UniformConstant +%Material_Texture2D_0Sampler = OpVariable %_ptr_UniformConstant_type_sampler UniformConstant +%Material_Texture2D_3 = OpVariable %_ptr_UniformConstant_type_2d_image UniformConstant +%Material_Texture2D_3Sampler = OpVariable %_ptr_UniformConstant_type_sampler UniformConstant +%gl_FragCoord = OpVariable %_ptr_Input_v4float Input +%in_var_TEXCOORD6 = OpVariable %_ptr_Input_v4float Input +%in_var_TEXCOORD7 = OpVariable %_ptr_Input_v4float Input +%in_var_TEXCOORD10_centroid = OpVariable %_ptr_Input_v4float Input +%in_var_TEXCOORD11_centroid = OpVariable %_ptr_Input_v4float Input +%in_var_TEXCOORD0 = OpVariable %_ptr_Input__arr_v4float_uint_1 Input +%in_var_PRIMITIVE_ID = OpVariable %_ptr_Input_uint Input +%gl_FrontFacing = OpVariable %_ptr_Input_bool Input +%gl_FragDepth = OpVariable %_ptr_Output_float Output +%out_var_SV_Target0 = OpVariable %_ptr_Output_v4float Output + %98 = OpUndef %float + %99 = OpConstantNull %v2float +%float_0_015625 = OpConstant %float 0.015625 + %101 = OpConstantComposite %v2float %float_0_015625 %float_0_015625 +%float_0_166666672 = OpConstant %float 0.166666672 + %103 = OpUndef %float + %104 = OpConstantNull %v3float +%MainPixelShader = OpFunction %void None %93 + %105 = OpLabel + %106 = OpLoad %v4float %gl_FragCoord + %107 = OpLoad %v4float %in_var_TEXCOORD6 + %108 = OpLoad %v4float %in_var_TEXCOORD7 + %109 = OpLoad %v4float %in_var_TEXCOORD10_centroid + %110 = OpLoad %v4float %in_var_TEXCOORD11_centroid + %111 = OpLoad %_arr_v4float_uint_1 %in_var_TEXCOORD0 + %112 = OpAccessChain %_ptr_Uniform_mat4v4float %View %int_4 + %113 = OpLoad %mat4v4float %112 + %114 = OpAccessChain %_ptr_Uniform_mat4v4float %View %int_11 + %115 = OpLoad %mat4v4float %114 + %116 = OpAccessChain %_ptr_Uniform_v3float %View %int_32 + %117 = OpLoad %v3float %116 + %118 = OpAccessChain %_ptr_Uniform_v4float %View %int_53 + %119 = OpLoad %v4float %118 + %120 = OpAccessChain %_ptr_Uniform_v4float %View %int_57 + %121 = OpLoad %v4float %120 + %122 = OpAccessChain %_ptr_Uniform_float %View %int_80 + %123 = OpLoad %float %122 + %124 = OpCompositeExtract %v4float %111 0 + %125 = OpVectorShuffle %v2float %99 %124 2 3 + %126 = OpVectorShuffle %v3float %109 %109 0 1 2 + %127 = OpVectorShuffle %v3float %110 %110 0 1 2 + %128 = OpExtInst %v3float %1 Cross %127 %126 + %129 = OpCompositeExtract %float %110 3 + %130 = OpCompositeConstruct %v3float %129 %129 %129 + %131 = OpFMul %v3float %128 %130 + %132 = OpCompositeConstruct %mat3v3float %126 %131 %127 + %133 = OpVectorShuffle %v2float %106 %106 0 1 + %134 = OpVectorShuffle %v2float %121 %121 0 1 + %135 = OpFSub %v2float %133 %134 + %136 = OpCompositeExtract %float %106 2 + %137 = OpCompositeConstruct %v4float %103 %103 %136 %float_1 + %138 = OpCompositeExtract %float %106 3 + %139 = OpCompositeConstruct %v4float %138 %138 %138 %138 + %140 = OpFMul %v4float %137 %139 + %141 = OpCompositeExtract %float %106 0 + %142 = OpCompositeExtract %float %106 1 + %143 = OpCompositeConstruct %v4float %141 %142 %136 %float_1 + %144 = OpMatrixTimesVector %v4float %115 %143 + %145 = OpVectorShuffle %v3float %144 %144 0 1 2 + %146 = OpCompositeExtract %float %144 3 + %147 = OpCompositeConstruct %v3float %146 %146 %146 + %148 = OpFDiv %v3float %145 %147 + %149 = OpFSub %v3float %148 %117 + %150 = OpFNegate %v3float %148 + %151 = OpExtInst %v3float %1 Normalize %150 + %152 = OpVectorTimesMatrix %v3float %151 %132 + %153 = OpVectorShuffle %v2float %152 %152 0 1 + %154 = OpFMul %v2float %153 %67 + %155 = OpCompositeExtract %float %152 2 + %156 = OpCompositeConstruct %v2float %155 %155 + %157 = OpFDiv %v2float %154 %156 + %158 = OpAccessChain %_ptr_Uniform_float %Material %int_1 %int_0 %int_0 + %159 = OpLoad %float %158 + %160 = OpCompositeConstruct %v2float %159 %159 + %161 = OpFMul %v2float %160 %157 + %162 = OpDot %float %151 %127 + %163 = OpExtInst %float %1 FAbs %162 + %164 = OpExtInst %float %1 FMax %163 %float_0 + %165 = OpExtInst %float %1 FMin %164 %float_1 + %166 = OpAccessChain %_ptr_Uniform_float %Material %int_1 %int_0 %int_1 + %167 = OpLoad %float %166 + %168 = OpAccessChain %_ptr_Uniform_float %Material %int_1 %int_0 %int_2 + %169 = OpLoad %float %168 + %170 = OpExtInst %float %1 FMix %167 %169 %165 + %171 = OpExtInst %float %1 Floor %170 + %172 = OpFDiv %float %float_1 %170 + %173 = OpCompositeConstruct %v2float %172 %172 + %174 = OpFMul %v2float %161 %173 + %175 = OpDPdx %v2float %125 + %176 = OpDPdy %v2float %125 + %177 = OpLoad %type_2d_image %Material_Texture2D_0 + %178 = OpLoad %type_sampler %Material_Texture2D_0Sampler + OpBranch %179 + %179 = OpLabel + %180 = OpPhi %float %float_1 %105 %181 %182 + %183 = OpPhi %v2float %49 %105 %184 %182 + %185 = OpPhi %int %int_0 %105 %186 %182 + %187 = OpPhi %float %float_1 %105 %188 %182 + %189 = OpPhi %float %float_1 %105 %180 %182 + %190 = OpConvertSToF %float %185 + %191 = OpFAdd %float %171 %float_2 + %192 = OpFOrdLessThan %bool %190 %191 + OpLoopMerge %193 %182 None + OpBranchConditional %192 %194 %193 + %194 = OpLabel + %195 = OpFAdd %v2float %125 %183 + %196 = OpSampledImage %type_sampled_image %177 %178 + %197 = OpImageSampleExplicitLod %v4float %196 %195 Grad %175 %176 + %188 = OpCompositeExtract %float %197 1 + %198 = OpFOrdLessThan %bool %180 %188 + OpSelectionMerge %182 None + OpBranchConditional %198 %199 %182 + %199 = OpLabel + %200 = OpFSub %float %189 %187 + %201 = OpFSub %float %188 %180 + %202 = OpFAdd %float %200 %201 + %203 = OpFDiv %float %201 %202 + %204 = OpFMul %float %189 %203 + %205 = OpFSub %float %float_1 %203 + %206 = OpFMul %float %180 %205 + %207 = OpFAdd %float %204 %206 + %208 = OpCompositeConstruct %v2float %203 %203 + %209 = OpFMul %v2float %208 %174 + %210 = OpFSub %v2float %183 %209 + OpBranch %193 + %182 = OpLabel + %181 = OpFSub %float %180 %172 + %184 = OpFAdd %v2float %183 %174 + %186 = OpIAdd %int %185 %int_1 + OpBranch %179 + %193 = OpLabel + %211 = OpPhi %float %98 %179 %207 %199 + %212 = OpPhi %v2float %183 %179 %210 %199 + %213 = OpVectorShuffle %v2float %212 %104 0 1 + %214 = OpFAdd %v2float %125 %213 + %215 = OpAccessChain %_ptr_Uniform_float %View %int_82 + %216 = OpLoad %float %215 + %217 = OpSampledImage %type_sampled_image %177 %178 + %218 = OpImageSampleImplicitLod %v4float %217 %214 Bias %216 + %219 = OpCompositeExtract %float %218 0 + %220 = OpAccessChain %_ptr_Uniform_float %Material %int_1 %int_2 %int_1 + %221 = OpLoad %float %220 + %222 = OpFMul %float %219 %221 + %223 = OpFSub %float %float_1 %222 + %224 = OpExtInst %float %1 FMax %223 %float_0 + %225 = OpExtInst %float %1 FMin %224 %float_1 + %226 = OpAccessChain %_ptr_Uniform_float %View %int_98 %int_0 + %227 = OpLoad %float %226 + %228 = OpCompositeConstruct %v2float %227 %227 + %229 = OpFAdd %v2float %135 %228 + %230 = OpCompositeExtract %float %229 0 + %231 = OpConvertFToU %uint %230 + %232 = OpCompositeExtract %float %229 1 + %233 = OpConvertFToU %uint %232 + %234 = OpIMul %uint %uint_2 %233 + %235 = OpIAdd %uint %231 %234 + %236 = OpUMod %uint %235 %uint_5 + %237 = OpConvertUToF %float %236 + %238 = OpFMul %v2float %135 %101 + %239 = OpLoad %type_2d_image %Material_Texture2D_3 + %240 = OpLoad %type_sampler %Material_Texture2D_3Sampler + %241 = OpSampledImage %type_sampled_image %239 %240 + %242 = OpImageSampleImplicitLod %v4float %241 %238 Bias %216 + %243 = OpCompositeExtract %float %242 0 + %244 = OpAccessChain %_ptr_Uniform_float %Material %int_1 %int_2 %int_2 + %245 = OpLoad %float %244 + %246 = OpFMul %float %243 %245 + %247 = OpFAdd %float %237 %246 + %248 = OpFMul %float %247 %float_0_166666672 + %249 = OpFAdd %float %225 %248 + %250 = OpFAdd %float %249 %float_n0_5 + %251 = OpCompositeExtract %float %218 2 + %252 = OpFAdd %float %251 %250 + %253 = OpSampledImage %type_sampled_image %239 %240 + %254 = OpImageSampleImplicitLod %v4float %253 %238 Bias %216 + %255 = OpCompositeExtract %float %254 0 + %256 = OpFAdd %float %237 %255 + %257 = OpFMul %float %256 %float_0_166666672 + %258 = OpAccessChain %_ptr_Uniform_float %PrimitiveFade %int_0 %int_0 + %259 = OpLoad %float %258 + %260 = OpFMul %float %123 %259 + %261 = OpAccessChain %_ptr_Uniform_float %PrimitiveFade %int_0 %int_1 + %262 = OpLoad %float %261 + %263 = OpFAdd %float %260 %262 + %264 = OpExtInst %float %1 FClamp %263 %float_0 %float_1 + %265 = OpFAdd %float %264 %257 + %266 = OpFAdd %float %265 %float_n0_5 + %267 = OpFMul %float %252 %266 + %268 = OpFSub %float %float_1 %211 + %269 = OpFMul %float %268 %159 + %270 = OpCompositeExtract %float %212 0 + %271 = OpCompositeExtract %float %212 1 + %272 = OpCompositeConstruct %v3float %270 %271 %269 + %273 = OpDot %float %272 %272 + %274 = OpExtInst %float %1 Sqrt %273 + %275 = OpDPdx %v2float %125 + %276 = OpExtInst %v2float %1 FAbs %275 + %277 = OpDot %float %276 %276 + %278 = OpExtInst %float %1 Sqrt %277 + %279 = OpDPdx %v3float %149 + %280 = OpDot %float %279 %279 + %281 = OpExtInst %float %1 Sqrt %280 + %282 = OpFDiv %float %278 %281 + %283 = OpDPdy %v2float %125 + %284 = OpExtInst %v2float %1 FAbs %283 + %285 = OpDot %float %284 %284 + %286 = OpExtInst %float %1 Sqrt %285 + %287 = OpDPdy %v3float %149 + %288 = OpDot %float %287 %287 + %289 = OpExtInst %float %1 Sqrt %288 + %290 = OpFDiv %float %286 %289 + %291 = OpExtInst %float %1 FMax %282 %290 + %292 = OpCompositeExtract %v4float %113 0 + %293 = OpVectorShuffle %v3float %292 %292 0 1 2 + %294 = OpCompositeExtract %v4float %113 1 + %295 = OpVectorShuffle %v3float %294 %294 0 1 2 + %296 = OpCompositeExtract %v4float %113 2 + %297 = OpVectorShuffle %v3float %296 %296 0 1 2 + %298 = OpCompositeConstruct %mat3v3float %293 %295 %297 + %299 = OpMatrixTimesVector %v3float %298 %70 + %300 = OpDot %float %299 %151 + %301 = OpExtInst %float %1 FAbs %300 + %302 = OpFDiv %float %291 %301 + %303 = OpFDiv %float %274 %302 + %304 = OpAccessChain %_ptr_Uniform_float %PrimitiveDither %int_0 + %305 = OpLoad %float %304 + %306 = OpFOrdNotEqual %bool %305 %float_0 + OpSelectionMerge %307 None + OpBranchConditional %306 %308 %307 + %308 = OpLabel + %309 = OpExtInst %float %1 FAbs %305 + %310 = OpFOrdGreaterThan %bool %309 %float_0_00100000005 + OpSelectionMerge %311 None + OpBranchConditional %310 %312 %311 + %312 = OpLabel + %313 = OpExtInst %v2float %1 Floor %133 + %314 = OpDot %float %313 %75 + %315 = OpExtInst %float %1 Cos %314 + %316 = OpFMul %float %315 %float_1000 + %317 = OpExtInst %float %1 Fract %316 + %318 = OpFOrdLessThan %bool %305 %float_0 + %319 = OpFAdd %float %305 %float_1 + %320 = OpFOrdGreaterThan %bool %319 %317 + %321 = OpFOrdLessThan %bool %305 %317 + %322 = OpSelect %bool %318 %320 %321 + %323 = OpSelect %float %322 %float_1 %float_0 + %324 = OpFSub %float %323 %float_0_00100000005 + %325 = OpFOrdLessThan %bool %324 %float_0 + OpSelectionMerge %326 None + OpBranchConditional %325 %327 %326 + %327 = OpLabel + OpKill + %326 = OpLabel + OpBranch %311 + %311 = OpLabel + OpBranch %307 + %307 = OpLabel + %328 = OpFSub %float %267 %float_0_333299994 + %329 = OpFOrdLessThan %bool %328 %float_0 + OpSelectionMerge %330 None + OpBranchConditional %329 %331 %330 + %331 = OpLabel + OpKill + %330 = OpLabel + %332 = OpCompositeExtract %float %140 2 + %333 = OpCompositeExtract %float %140 3 + %334 = OpFAdd %float %333 %303 + %335 = OpFDiv %float %332 %334 + %336 = OpExtInst %float %1 FMin %335 %136 + %337 = OpVectorShuffle %v2float %107 %107 0 1 + %338 = OpCompositeExtract %float %107 3 + %339 = OpCompositeConstruct %v2float %338 %338 + %340 = OpFDiv %v2float %337 %339 + %341 = OpVectorShuffle %v2float %119 %119 0 1 + %342 = OpFSub %v2float %340 %341 + %343 = OpVectorShuffle %v2float %108 %108 0 1 + %344 = OpCompositeExtract %float %108 3 + %345 = OpCompositeConstruct %v2float %344 %344 + %346 = OpFDiv %v2float %343 %345 + %347 = OpVectorShuffle %v2float %119 %119 2 3 + %348 = OpFSub %v2float %346 %347 + %349 = OpFSub %v2float %342 %348 + %350 = OpFMul %v2float %349 %54 + %351 = OpFAdd %v2float %350 %56 + %352 = OpVectorShuffle %v4float %351 %49 0 1 2 3 + OpStore %gl_FragDepth %336 + OpStore %out_var_SV_Target0 %352 + OpReturn + OpFunctionEnd diff --git a/third_party/spirv-cross/shaders-ue4-no-opt/asm/frag/phi-variable-declaration.asm.invalid.frag b/third_party/spirv-cross/shaders-ue4-no-opt/asm/frag/phi-variable-declaration.asm.invalid.frag new file mode 100644 index 0000000000..eba220ba4e --- /dev/null +++ b/third_party/spirv-cross/shaders-ue4-no-opt/asm/frag/phi-variable-declaration.asm.invalid.frag @@ -0,0 +1,878 @@ +; SPIR-V +; Version: 1.0 +; Generator: Google spiregg; 0 +; Bound: 353 +; Schema: 0 + OpCapability Shader + OpExtension "SPV_GOOGLE_hlsl_functionality1" + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %MainPixelShader "main" %gl_FragCoord %in_var_TEXCOORD6 %in_var_TEXCOORD7 %in_var_TEXCOORD10_centroid %in_var_TEXCOORD11_centroid %in_var_TEXCOORD0 %in_var_PRIMITIVE_ID %gl_FrontFacing %gl_FragDepth %out_var_SV_Target0 + OpExecutionMode %MainPixelShader OriginUpperLeft + OpExecutionMode %MainPixelShader DepthReplacing + OpExecutionMode %MainPixelShader DepthLess + OpSource HLSL 600 + OpName %type_View "type.View" + OpMemberName %type_View 0 "View_TranslatedWorldToClip" + OpMemberName %type_View 1 "View_WorldToClip" + OpMemberName %type_View 2 "View_ClipToWorld" + OpMemberName %type_View 3 "View_TranslatedWorldToView" + OpMemberName %type_View 4 "View_ViewToTranslatedWorld" + OpMemberName %type_View 5 "View_TranslatedWorldToCameraView" + OpMemberName %type_View 6 "View_CameraViewToTranslatedWorld" + OpMemberName %type_View 7 "View_ViewToClip" + OpMemberName %type_View 8 "View_ViewToClipNoAA" + OpMemberName %type_View 9 "View_ClipToView" + OpMemberName %type_View 10 "View_ClipToTranslatedWorld" + OpMemberName %type_View 11 "View_SVPositionToTranslatedWorld" + OpMemberName %type_View 12 "View_ScreenToWorld" + OpMemberName %type_View 13 "View_ScreenToTranslatedWorld" + OpMemberName %type_View 14 "View_ViewForward" + OpMemberName %type_View 15 "PrePadding_View_908" + OpMemberName %type_View 16 "View_ViewUp" + OpMemberName %type_View 17 "PrePadding_View_924" + OpMemberName %type_View 18 "View_ViewRight" + OpMemberName %type_View 19 "PrePadding_View_940" + OpMemberName %type_View 20 "View_HMDViewNoRollUp" + OpMemberName %type_View 21 "PrePadding_View_956" + OpMemberName %type_View 22 "View_HMDViewNoRollRight" + OpMemberName %type_View 23 "PrePadding_View_972" + OpMemberName %type_View 24 "View_InvDeviceZToWorldZTransform" + OpMemberName %type_View 25 "View_ScreenPositionScaleBias" + OpMemberName %type_View 26 "View_WorldCameraOrigin" + OpMemberName %type_View 27 "PrePadding_View_1020" + OpMemberName %type_View 28 "View_TranslatedWorldCameraOrigin" + OpMemberName %type_View 29 "PrePadding_View_1036" + OpMemberName %type_View 30 "View_WorldViewOrigin" + OpMemberName %type_View 31 "PrePadding_View_1052" + OpMemberName %type_View 32 "View_PreViewTranslation" + OpMemberName %type_View 33 "PrePadding_View_1068" + OpMemberName %type_View 34 "View_PrevProjection" + OpMemberName %type_View 35 "View_PrevViewProj" + OpMemberName %type_View 36 "View_PrevViewRotationProj" + OpMemberName %type_View 37 "View_PrevViewToClip" + OpMemberName %type_View 38 "View_PrevClipToView" + OpMemberName %type_View 39 "View_PrevTranslatedWorldToClip" + OpMemberName %type_View 40 "View_PrevTranslatedWorldToView" + OpMemberName %type_View 41 "View_PrevViewToTranslatedWorld" + OpMemberName %type_View 42 "View_PrevTranslatedWorldToCameraView" + OpMemberName %type_View 43 "View_PrevCameraViewToTranslatedWorld" + OpMemberName %type_View 44 "View_PrevWorldCameraOrigin" + OpMemberName %type_View 45 "PrePadding_View_1724" + OpMemberName %type_View 46 "View_PrevWorldViewOrigin" + OpMemberName %type_View 47 "PrePadding_View_1740" + OpMemberName %type_View 48 "View_PrevPreViewTranslation" + OpMemberName %type_View 49 "PrePadding_View_1756" + OpMemberName %type_View 50 "View_PrevInvViewProj" + OpMemberName %type_View 51 "View_PrevScreenToTranslatedWorld" + OpMemberName %type_View 52 "View_ClipToPrevClip" + OpMemberName %type_View 53 "View_TemporalAAJitter" + OpMemberName %type_View 54 "View_GlobalClippingPlane" + OpMemberName %type_View 55 "View_FieldOfViewWideAngles" + OpMemberName %type_View 56 "View_PrevFieldOfViewWideAngles" + OpMemberName %type_View 57 "View_ViewRectMin" + OpMemberName %type_View 58 "View_ViewSizeAndInvSize" + OpMemberName %type_View 59 "View_BufferSizeAndInvSize" + OpMemberName %type_View 60 "View_BufferBilinearUVMinMax" + OpMemberName %type_View 61 "View_NumSceneColorMSAASamples" + OpMemberName %type_View 62 "View_PreExposure" + OpMemberName %type_View 63 "View_OneOverPreExposure" + OpMemberName %type_View 64 "PrePadding_View_2076" + OpMemberName %type_View 65 "View_DiffuseOverrideParameter" + OpMemberName %type_View 66 "View_SpecularOverrideParameter" + OpMemberName %type_View 67 "View_NormalOverrideParameter" + OpMemberName %type_View 68 "View_RoughnessOverrideParameter" + OpMemberName %type_View 69 "View_PrevFrameGameTime" + OpMemberName %type_View 70 "View_PrevFrameRealTime" + OpMemberName %type_View 71 "View_OutOfBoundsMask" + OpMemberName %type_View 72 "PrePadding_View_2148" + OpMemberName %type_View 73 "PrePadding_View_2152" + OpMemberName %type_View 74 "PrePadding_View_2156" + OpMemberName %type_View 75 "View_WorldCameraMovementSinceLastFrame" + OpMemberName %type_View 76 "View_CullingSign" + OpMemberName %type_View 77 "View_NearPlane" + OpMemberName %type_View 78 "View_AdaptiveTessellationFactor" + OpMemberName %type_View 79 "View_GameTime" + OpMemberName %type_View 80 "View_RealTime" + OpMemberName %type_View 81 "View_DeltaTime" + OpMemberName %type_View 82 "View_MaterialTextureMipBias" + OpMemberName %type_View 83 "View_MaterialTextureDerivativeMultiply" + OpMemberName %type_View 84 "View_Random" + OpMemberName %type_View 85 "View_FrameNumber" + OpMemberName %type_View 86 "View_StateFrameIndexMod8" + OpMemberName %type_View 87 "View_StateFrameIndex" + OpMemberName %type_View 88 "View_CameraCut" + OpMemberName %type_View 89 "View_UnlitViewmodeMask" + OpMemberName %type_View 90 "PrePadding_View_2228" + OpMemberName %type_View 91 "PrePadding_View_2232" + OpMemberName %type_View 92 "PrePadding_View_2236" + OpMemberName %type_View 93 "View_DirectionalLightColor" + OpMemberName %type_View 94 "View_DirectionalLightDirection" + OpMemberName %type_View 95 "PrePadding_View_2268" + OpMemberName %type_View 96 "View_TranslucencyLightingVolumeMin" + OpMemberName %type_View 97 "View_TranslucencyLightingVolumeInvSize" + OpMemberName %type_View 98 "View_TemporalAAParams" + OpMemberName %type_View 99 "View_CircleDOFParams" + OpMemberName %type_View 100 "View_DepthOfFieldSensorWidth" + OpMemberName %type_View 101 "View_DepthOfFieldFocalDistance" + OpMemberName %type_View 102 "View_DepthOfFieldScale" + OpMemberName %type_View 103 "View_DepthOfFieldFocalLength" + OpMemberName %type_View 104 "View_DepthOfFieldFocalRegion" + OpMemberName %type_View 105 "View_DepthOfFieldNearTransitionRegion" + OpMemberName %type_View 106 "View_DepthOfFieldFarTransitionRegion" + OpMemberName %type_View 107 "View_MotionBlurNormalizedToPixel" + OpMemberName %type_View 108 "View_bSubsurfacePostprocessEnabled" + OpMemberName %type_View 109 "View_GeneralPurposeTweak" + OpMemberName %type_View 110 "View_DemosaicVposOffset" + OpMemberName %type_View 111 "PrePadding_View_2412" + OpMemberName %type_View 112 "View_IndirectLightingColorScale" + OpMemberName %type_View 113 "View_HDR32bppEncodingMode" + OpMemberName %type_View 114 "View_AtmosphericFogSunDirection" + OpMemberName %type_View 115 "View_AtmosphericFogSunPower" + OpMemberName %type_View 116 "View_AtmosphericFogPower" + OpMemberName %type_View 117 "View_AtmosphericFogDensityScale" + OpMemberName %type_View 118 "View_AtmosphericFogDensityOffset" + OpMemberName %type_View 119 "View_AtmosphericFogGroundOffset" + OpMemberName %type_View 120 "View_AtmosphericFogDistanceScale" + OpMemberName %type_View 121 "View_AtmosphericFogAltitudeScale" + OpMemberName %type_View 122 "View_AtmosphericFogHeightScaleRayleigh" + OpMemberName %type_View 123 "View_AtmosphericFogStartDistance" + OpMemberName %type_View 124 "View_AtmosphericFogDistanceOffset" + OpMemberName %type_View 125 "View_AtmosphericFogSunDiscScale" + OpMemberName %type_View 126 "View_AtmosphericFogSunDiscHalfApexAngleRadian" + OpMemberName %type_View 127 "PrePadding_View_2492" + OpMemberName %type_View 128 "View_AtmosphericFogSunDiscLuminance" + OpMemberName %type_View 129 "View_AtmosphericFogRenderMask" + OpMemberName %type_View 130 "View_AtmosphericFogInscatterAltitudeSampleNum" + OpMemberName %type_View 131 "PrePadding_View_2520" + OpMemberName %type_View 132 "PrePadding_View_2524" + OpMemberName %type_View 133 "View_AtmosphericFogSunColor" + OpMemberName %type_View 134 "View_NormalCurvatureToRoughnessScaleBias" + OpMemberName %type_View 135 "View_RenderingReflectionCaptureMask" + OpMemberName %type_View 136 "View_AmbientCubemapTint" + OpMemberName %type_View 137 "View_AmbientCubemapIntensity" + OpMemberName %type_View 138 "View_SkyLightParameters" + OpMemberName %type_View 139 "PrePadding_View_2584" + OpMemberName %type_View 140 "PrePadding_View_2588" + OpMemberName %type_View 141 "View_SkyLightColor" + OpMemberName %type_View 142 "View_SkyIrradianceEnvironmentMap" + OpMemberName %type_View 143 "View_MobilePreviewMode" + OpMemberName %type_View 144 "View_HMDEyePaddingOffset" + OpMemberName %type_View 145 "View_ReflectionCubemapMaxMip" + OpMemberName %type_View 146 "View_ShowDecalsMask" + OpMemberName %type_View 147 "View_DistanceFieldAOSpecularOcclusionMode" + OpMemberName %type_View 148 "View_IndirectCapsuleSelfShadowingIntensity" + OpMemberName %type_View 149 "PrePadding_View_2744" + OpMemberName %type_View 150 "PrePadding_View_2748" + OpMemberName %type_View 151 "View_ReflectionEnvironmentRoughnessMixingScaleBiasAndLargestWeight" + OpMemberName %type_View 152 "View_StereoPassIndex" + OpMemberName %type_View 153 "View_GlobalVolumeCenterAndExtent" + OpMemberName %type_View 154 "View_GlobalVolumeWorldToUVAddAndMul" + OpMemberName %type_View 155 "View_GlobalVolumeDimension" + OpMemberName %type_View 156 "View_GlobalVolumeTexelSize" + OpMemberName %type_View 157 "View_MaxGlobalDistance" + OpMemberName %type_View 158 "PrePadding_View_2908" + OpMemberName %type_View 159 "View_CursorPosition" + OpMemberName %type_View 160 "View_bCheckerboardSubsurfaceProfileRendering" + OpMemberName %type_View 161 "PrePadding_View_2924" + OpMemberName %type_View 162 "View_VolumetricFogInvGridSize" + OpMemberName %type_View 163 "PrePadding_View_2940" + OpMemberName %type_View 164 "View_VolumetricFogGridZParams" + OpMemberName %type_View 165 "PrePadding_View_2956" + OpMemberName %type_View 166 "View_VolumetricFogSVPosToVolumeUV" + OpMemberName %type_View 167 "View_VolumetricFogMaxDistance" + OpMemberName %type_View 168 "PrePadding_View_2972" + OpMemberName %type_View 169 "View_VolumetricLightmapWorldToUVScale" + OpMemberName %type_View 170 "PrePadding_View_2988" + OpMemberName %type_View 171 "View_VolumetricLightmapWorldToUVAdd" + OpMemberName %type_View 172 "PrePadding_View_3004" + OpMemberName %type_View 173 "View_VolumetricLightmapIndirectionTextureSize" + OpMemberName %type_View 174 "View_VolumetricLightmapBrickSize" + OpMemberName %type_View 175 "View_VolumetricLightmapBrickTexelSize" + OpMemberName %type_View 176 "View_StereoIPD" + OpMemberName %type_View 177 "View_IndirectLightingCacheShowFlag" + OpMemberName %type_View 178 "View_EyeToPixelSpreadAngle" + OpName %View "View" + OpName %type_PrimitiveDither "type.PrimitiveDither" + OpMemberName %type_PrimitiveDither 0 "PrimitiveDither_LODFactor" + OpName %PrimitiveDither "PrimitiveDither" + OpName %type_PrimitiveFade "type.PrimitiveFade" + OpMemberName %type_PrimitiveFade 0 "PrimitiveFade_FadeTimeScaleBias" + OpName %PrimitiveFade "PrimitiveFade" + OpName %type_Material "type.Material" + OpMemberName %type_Material 0 "Material_VectorExpressions" + OpMemberName %type_Material 1 "Material_ScalarExpressions" + OpName %Material "Material" + OpName %type_2d_image "type.2d.image" + OpName %Material_Texture2D_0 "Material_Texture2D_0" + OpName %type_sampler "type.sampler" + OpName %Material_Texture2D_0Sampler "Material_Texture2D_0Sampler" + OpName %Material_Texture2D_3 "Material_Texture2D_3" + OpName %Material_Texture2D_3Sampler "Material_Texture2D_3Sampler" + OpName %in_var_TEXCOORD6 "in.var.TEXCOORD6" + OpName %in_var_TEXCOORD7 "in.var.TEXCOORD7" + OpName %in_var_TEXCOORD10_centroid "in.var.TEXCOORD10_centroid" + OpName %in_var_TEXCOORD11_centroid "in.var.TEXCOORD11_centroid" + OpName %in_var_TEXCOORD0 "in.var.TEXCOORD0" + OpName %in_var_PRIMITIVE_ID "in.var.PRIMITIVE_ID" + OpName %out_var_SV_Target0 "out.var.SV_Target0" + OpName %MainPixelShader "MainPixelShader" + OpName %type_sampled_image "type.sampled.image" + OpDecorate %gl_FragCoord BuiltIn FragCoord + OpDecorateString %gl_FragCoord UserSemantic "SV_Position" + OpDecorateString %in_var_TEXCOORD6 UserSemantic "TEXCOORD6" + OpDecorateString %in_var_TEXCOORD7 UserSemantic "TEXCOORD7" + OpDecorateString %in_var_TEXCOORD10_centroid UserSemantic "TEXCOORD10_centroid" + OpDecorateString %in_var_TEXCOORD11_centroid UserSemantic "TEXCOORD11_centroid" + OpDecorateString %in_var_TEXCOORD0 UserSemantic "TEXCOORD0" + OpDecorateString %in_var_PRIMITIVE_ID UserSemantic "PRIMITIVE_ID" + OpDecorate %in_var_PRIMITIVE_ID Flat + OpDecorate %gl_FrontFacing BuiltIn FrontFacing + OpDecorateString %gl_FrontFacing UserSemantic "SV_IsFrontFace" + OpDecorate %gl_FrontFacing Flat + OpDecorate %gl_FragDepth BuiltIn FragDepth + OpDecorateString %gl_FragDepth UserSemantic "SV_DepthLessEqual" + OpDecorateString %out_var_SV_Target0 UserSemantic "SV_Target0" + OpDecorate %in_var_TEXCOORD6 Location 0 + OpDecorate %in_var_TEXCOORD7 Location 1 + OpDecorate %in_var_TEXCOORD10_centroid Location 2 + OpDecorate %in_var_TEXCOORD11_centroid Location 3 + OpDecorate %in_var_TEXCOORD0 Location 4 + OpDecorate %in_var_PRIMITIVE_ID Location 5 + OpDecorate %out_var_SV_Target0 Location 0 + OpDecorate %View DescriptorSet 0 + OpDecorate %View Binding 0 + OpDecorate %PrimitiveDither DescriptorSet 0 + OpDecorate %PrimitiveDither Binding 1 + OpDecorate %PrimitiveFade DescriptorSet 0 + OpDecorate %PrimitiveFade Binding 2 + OpDecorate %Material DescriptorSet 0 + OpDecorate %Material Binding 3 + OpDecorate %Material_Texture2D_0 DescriptorSet 0 + OpDecorate %Material_Texture2D_0 Binding 0 + OpDecorate %Material_Texture2D_0Sampler DescriptorSet 0 + OpDecorate %Material_Texture2D_0Sampler Binding 0 + OpDecorate %Material_Texture2D_3 DescriptorSet 0 + OpDecorate %Material_Texture2D_3 Binding 1 + OpDecorate %Material_Texture2D_3Sampler DescriptorSet 0 + OpDecorate %Material_Texture2D_3Sampler Binding 1 + OpDecorate %_arr_v4float_uint_2 ArrayStride 16 + OpDecorate %_arr_v4float_uint_7 ArrayStride 16 + OpDecorate %_arr_v4float_uint_4 ArrayStride 16 + OpMemberDecorate %type_View 0 Offset 0 + OpMemberDecorate %type_View 0 MatrixStride 16 + OpMemberDecorate %type_View 0 ColMajor + OpMemberDecorate %type_View 1 Offset 64 + OpMemberDecorate %type_View 1 MatrixStride 16 + OpMemberDecorate %type_View 1 ColMajor + OpMemberDecorate %type_View 2 Offset 128 + OpMemberDecorate %type_View 2 MatrixStride 16 + OpMemberDecorate %type_View 2 ColMajor + OpMemberDecorate %type_View 3 Offset 192 + OpMemberDecorate %type_View 3 MatrixStride 16 + OpMemberDecorate %type_View 3 ColMajor + OpMemberDecorate %type_View 4 Offset 256 + OpMemberDecorate %type_View 4 MatrixStride 16 + OpMemberDecorate %type_View 4 ColMajor + OpMemberDecorate %type_View 5 Offset 320 + OpMemberDecorate %type_View 5 MatrixStride 16 + OpMemberDecorate %type_View 5 ColMajor + OpMemberDecorate %type_View 6 Offset 384 + OpMemberDecorate %type_View 6 MatrixStride 16 + OpMemberDecorate %type_View 6 ColMajor + OpMemberDecorate %type_View 7 Offset 448 + OpMemberDecorate %type_View 7 MatrixStride 16 + OpMemberDecorate %type_View 7 ColMajor + OpMemberDecorate %type_View 8 Offset 512 + OpMemberDecorate %type_View 8 MatrixStride 16 + OpMemberDecorate %type_View 8 ColMajor + OpMemberDecorate %type_View 9 Offset 576 + OpMemberDecorate %type_View 9 MatrixStride 16 + OpMemberDecorate %type_View 9 ColMajor + OpMemberDecorate %type_View 10 Offset 640 + OpMemberDecorate %type_View 10 MatrixStride 16 + OpMemberDecorate %type_View 10 ColMajor + OpMemberDecorate %type_View 11 Offset 704 + OpMemberDecorate %type_View 11 MatrixStride 16 + OpMemberDecorate %type_View 11 ColMajor + OpMemberDecorate %type_View 12 Offset 768 + OpMemberDecorate %type_View 12 MatrixStride 16 + OpMemberDecorate %type_View 12 ColMajor + OpMemberDecorate %type_View 13 Offset 832 + OpMemberDecorate %type_View 13 MatrixStride 16 + OpMemberDecorate %type_View 13 ColMajor + OpMemberDecorate %type_View 14 Offset 896 + OpMemberDecorate %type_View 15 Offset 908 + OpMemberDecorate %type_View 16 Offset 912 + OpMemberDecorate %type_View 17 Offset 924 + OpMemberDecorate %type_View 18 Offset 928 + OpMemberDecorate %type_View 19 Offset 940 + OpMemberDecorate %type_View 20 Offset 944 + OpMemberDecorate %type_View 21 Offset 956 + OpMemberDecorate %type_View 22 Offset 960 + OpMemberDecorate %type_View 23 Offset 972 + OpMemberDecorate %type_View 24 Offset 976 + OpMemberDecorate %type_View 25 Offset 992 + OpMemberDecorate %type_View 26 Offset 1008 + OpMemberDecorate %type_View 27 Offset 1020 + OpMemberDecorate %type_View 28 Offset 1024 + OpMemberDecorate %type_View 29 Offset 1036 + OpMemberDecorate %type_View 30 Offset 1040 + OpMemberDecorate %type_View 31 Offset 1052 + OpMemberDecorate %type_View 32 Offset 1056 + OpMemberDecorate %type_View 33 Offset 1068 + OpMemberDecorate %type_View 34 Offset 1072 + OpMemberDecorate %type_View 34 MatrixStride 16 + OpMemberDecorate %type_View 34 ColMajor + OpMemberDecorate %type_View 35 Offset 1136 + OpMemberDecorate %type_View 35 MatrixStride 16 + OpMemberDecorate %type_View 35 ColMajor + OpMemberDecorate %type_View 36 Offset 1200 + OpMemberDecorate %type_View 36 MatrixStride 16 + OpMemberDecorate %type_View 36 ColMajor + OpMemberDecorate %type_View 37 Offset 1264 + OpMemberDecorate %type_View 37 MatrixStride 16 + OpMemberDecorate %type_View 37 ColMajor + OpMemberDecorate %type_View 38 Offset 1328 + OpMemberDecorate %type_View 38 MatrixStride 16 + OpMemberDecorate %type_View 38 ColMajor + OpMemberDecorate %type_View 39 Offset 1392 + OpMemberDecorate %type_View 39 MatrixStride 16 + OpMemberDecorate %type_View 39 ColMajor + OpMemberDecorate %type_View 40 Offset 1456 + OpMemberDecorate %type_View 40 MatrixStride 16 + OpMemberDecorate %type_View 40 ColMajor + OpMemberDecorate %type_View 41 Offset 1520 + OpMemberDecorate %type_View 41 MatrixStride 16 + OpMemberDecorate %type_View 41 ColMajor + OpMemberDecorate %type_View 42 Offset 1584 + OpMemberDecorate %type_View 42 MatrixStride 16 + OpMemberDecorate %type_View 42 ColMajor + OpMemberDecorate %type_View 43 Offset 1648 + OpMemberDecorate %type_View 43 MatrixStride 16 + OpMemberDecorate %type_View 43 ColMajor + OpMemberDecorate %type_View 44 Offset 1712 + OpMemberDecorate %type_View 45 Offset 1724 + OpMemberDecorate %type_View 46 Offset 1728 + OpMemberDecorate %type_View 47 Offset 1740 + OpMemberDecorate %type_View 48 Offset 1744 + OpMemberDecorate %type_View 49 Offset 1756 + OpMemberDecorate %type_View 50 Offset 1760 + OpMemberDecorate %type_View 50 MatrixStride 16 + OpMemberDecorate %type_View 50 ColMajor + OpMemberDecorate %type_View 51 Offset 1824 + OpMemberDecorate %type_View 51 MatrixStride 16 + OpMemberDecorate %type_View 51 ColMajor + OpMemberDecorate %type_View 52 Offset 1888 + OpMemberDecorate %type_View 52 MatrixStride 16 + OpMemberDecorate %type_View 52 ColMajor + OpMemberDecorate %type_View 53 Offset 1952 + OpMemberDecorate %type_View 54 Offset 1968 + OpMemberDecorate %type_View 55 Offset 1984 + OpMemberDecorate %type_View 56 Offset 1992 + OpMemberDecorate %type_View 57 Offset 2000 + OpMemberDecorate %type_View 58 Offset 2016 + OpMemberDecorate %type_View 59 Offset 2032 + OpMemberDecorate %type_View 60 Offset 2048 + OpMemberDecorate %type_View 61 Offset 2064 + OpMemberDecorate %type_View 62 Offset 2068 + OpMemberDecorate %type_View 63 Offset 2072 + OpMemberDecorate %type_View 64 Offset 2076 + OpMemberDecorate %type_View 65 Offset 2080 + OpMemberDecorate %type_View 66 Offset 2096 + OpMemberDecorate %type_View 67 Offset 2112 + OpMemberDecorate %type_View 68 Offset 2128 + OpMemberDecorate %type_View 69 Offset 2136 + OpMemberDecorate %type_View 70 Offset 2140 + OpMemberDecorate %type_View 71 Offset 2144 + OpMemberDecorate %type_View 72 Offset 2148 + OpMemberDecorate %type_View 73 Offset 2152 + OpMemberDecorate %type_View 74 Offset 2156 + OpMemberDecorate %type_View 75 Offset 2160 + OpMemberDecorate %type_View 76 Offset 2172 + OpMemberDecorate %type_View 77 Offset 2176 + OpMemberDecorate %type_View 78 Offset 2180 + OpMemberDecorate %type_View 79 Offset 2184 + OpMemberDecorate %type_View 80 Offset 2188 + OpMemberDecorate %type_View 81 Offset 2192 + OpMemberDecorate %type_View 82 Offset 2196 + OpMemberDecorate %type_View 83 Offset 2200 + OpMemberDecorate %type_View 84 Offset 2204 + OpMemberDecorate %type_View 85 Offset 2208 + OpMemberDecorate %type_View 86 Offset 2212 + OpMemberDecorate %type_View 87 Offset 2216 + OpMemberDecorate %type_View 88 Offset 2220 + OpMemberDecorate %type_View 89 Offset 2224 + OpMemberDecorate %type_View 90 Offset 2228 + OpMemberDecorate %type_View 91 Offset 2232 + OpMemberDecorate %type_View 92 Offset 2236 + OpMemberDecorate %type_View 93 Offset 2240 + OpMemberDecorate %type_View 94 Offset 2256 + OpMemberDecorate %type_View 95 Offset 2268 + OpMemberDecorate %type_View 96 Offset 2272 + OpMemberDecorate %type_View 97 Offset 2304 + OpMemberDecorate %type_View 98 Offset 2336 + OpMemberDecorate %type_View 99 Offset 2352 + OpMemberDecorate %type_View 100 Offset 2368 + OpMemberDecorate %type_View 101 Offset 2372 + OpMemberDecorate %type_View 102 Offset 2376 + OpMemberDecorate %type_View 103 Offset 2380 + OpMemberDecorate %type_View 104 Offset 2384 + OpMemberDecorate %type_View 105 Offset 2388 + OpMemberDecorate %type_View 106 Offset 2392 + OpMemberDecorate %type_View 107 Offset 2396 + OpMemberDecorate %type_View 108 Offset 2400 + OpMemberDecorate %type_View 109 Offset 2404 + OpMemberDecorate %type_View 110 Offset 2408 + OpMemberDecorate %type_View 111 Offset 2412 + OpMemberDecorate %type_View 112 Offset 2416 + OpMemberDecorate %type_View 113 Offset 2428 + OpMemberDecorate %type_View 114 Offset 2432 + OpMemberDecorate %type_View 115 Offset 2444 + OpMemberDecorate %type_View 116 Offset 2448 + OpMemberDecorate %type_View 117 Offset 2452 + OpMemberDecorate %type_View 118 Offset 2456 + OpMemberDecorate %type_View 119 Offset 2460 + OpMemberDecorate %type_View 120 Offset 2464 + OpMemberDecorate %type_View 121 Offset 2468 + OpMemberDecorate %type_View 122 Offset 2472 + OpMemberDecorate %type_View 123 Offset 2476 + OpMemberDecorate %type_View 124 Offset 2480 + OpMemberDecorate %type_View 125 Offset 2484 + OpMemberDecorate %type_View 126 Offset 2488 + OpMemberDecorate %type_View 127 Offset 2492 + OpMemberDecorate %type_View 128 Offset 2496 + OpMemberDecorate %type_View 129 Offset 2512 + OpMemberDecorate %type_View 130 Offset 2516 + OpMemberDecorate %type_View 131 Offset 2520 + OpMemberDecorate %type_View 132 Offset 2524 + OpMemberDecorate %type_View 133 Offset 2528 + OpMemberDecorate %type_View 134 Offset 2544 + OpMemberDecorate %type_View 135 Offset 2556 + OpMemberDecorate %type_View 136 Offset 2560 + OpMemberDecorate %type_View 137 Offset 2576 + OpMemberDecorate %type_View 138 Offset 2580 + OpMemberDecorate %type_View 139 Offset 2584 + OpMemberDecorate %type_View 140 Offset 2588 + OpMemberDecorate %type_View 141 Offset 2592 + OpMemberDecorate %type_View 142 Offset 2608 + OpMemberDecorate %type_View 143 Offset 2720 + OpMemberDecorate %type_View 144 Offset 2724 + OpMemberDecorate %type_View 145 Offset 2728 + OpMemberDecorate %type_View 146 Offset 2732 + OpMemberDecorate %type_View 147 Offset 2736 + OpMemberDecorate %type_View 148 Offset 2740 + OpMemberDecorate %type_View 149 Offset 2744 + OpMemberDecorate %type_View 150 Offset 2748 + OpMemberDecorate %type_View 151 Offset 2752 + OpMemberDecorate %type_View 152 Offset 2764 + OpMemberDecorate %type_View 153 Offset 2768 + OpMemberDecorate %type_View 154 Offset 2832 + OpMemberDecorate %type_View 155 Offset 2896 + OpMemberDecorate %type_View 156 Offset 2900 + OpMemberDecorate %type_View 157 Offset 2904 + OpMemberDecorate %type_View 158 Offset 2908 + OpMemberDecorate %type_View 159 Offset 2912 + OpMemberDecorate %type_View 160 Offset 2920 + OpMemberDecorate %type_View 161 Offset 2924 + OpMemberDecorate %type_View 162 Offset 2928 + OpMemberDecorate %type_View 163 Offset 2940 + OpMemberDecorate %type_View 164 Offset 2944 + OpMemberDecorate %type_View 165 Offset 2956 + OpMemberDecorate %type_View 166 Offset 2960 + OpMemberDecorate %type_View 167 Offset 2968 + OpMemberDecorate %type_View 168 Offset 2972 + OpMemberDecorate %type_View 169 Offset 2976 + OpMemberDecorate %type_View 170 Offset 2988 + OpMemberDecorate %type_View 171 Offset 2992 + OpMemberDecorate %type_View 172 Offset 3004 + OpMemberDecorate %type_View 173 Offset 3008 + OpMemberDecorate %type_View 174 Offset 3020 + OpMemberDecorate %type_View 175 Offset 3024 + OpMemberDecorate %type_View 176 Offset 3036 + OpMemberDecorate %type_View 177 Offset 3040 + OpMemberDecorate %type_View 178 Offset 3044 + OpDecorate %type_View Block + OpMemberDecorate %type_PrimitiveDither 0 Offset 0 + OpDecorate %type_PrimitiveDither Block + OpMemberDecorate %type_PrimitiveFade 0 Offset 0 + OpDecorate %type_PrimitiveFade Block + OpDecorate %_arr_v4float_uint_9 ArrayStride 16 + OpDecorate %_arr_v4float_uint_3 ArrayStride 16 + OpMemberDecorate %type_Material 0 Offset 0 + OpMemberDecorate %type_Material 1 Offset 144 + OpDecorate %type_Material Block + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 +%mat4v4float = OpTypeMatrix %v4float 4 + %v3float = OpTypeVector %float 3 + %v2float = OpTypeVector %float 2 + %int = OpTypeInt 32 1 + %uint = OpTypeInt 32 0 + %uint_2 = OpConstant %uint 2 + %uint_7 = OpConstant %uint 7 + %uint_4 = OpConstant %uint 4 + %v2int = OpTypeVector %int 2 +%float_0_00100000005 = OpConstant %float 0.00100000005 + %int_2 = OpConstant %int 2 + %int_0 = OpConstant %int 0 + %int_1 = OpConstant %int 1 + %float_0 = OpConstant %float 0 + %49 = OpConstantComposite %v2float %float_0 %float_0 + %float_1 = OpConstant %float 1 + %int_4 = OpConstant %int 4 + %int_11 = OpConstant %int 11 +%float_0_249500006 = OpConstant %float 0.249500006 + %54 = OpConstantComposite %v2float %float_0_249500006 %float_0_249500006 +%float_0_499992371 = OpConstant %float 0.499992371 + %56 = OpConstantComposite %v2float %float_0_499992371 %float_0_499992371 + %int_32 = OpConstant %int 32 + %int_53 = OpConstant %int 53 + %int_57 = OpConstant %int 57 + %int_80 = OpConstant %int 80 + %int_82 = OpConstant %int 82 + %int_98 = OpConstant %int 98 + %uint_1 = OpConstant %uint 1 +%mat3v3float = OpTypeMatrix %v3float 3 + %float_2 = OpConstant %float 2 + %float_n1 = OpConstant %float -1 + %67 = OpConstantComposite %v2float %float_n1 %float_n1 + %bool = OpTypeBool + %float_n0_5 = OpConstant %float -0.5 + %70 = OpConstantComposite %v3float %float_0 %float_0 %float_1 +%float_0_333299994 = OpConstant %float 0.333299994 + %uint_5 = OpConstant %uint 5 +%float_347_834503 = OpConstant %float 347.834503 +%float_3343_28369 = OpConstant %float 3343.28369 + %75 = OpConstantComposite %v2float %float_347_834503 %float_3343_28369 + %float_1000 = OpConstant %float 1000 +%_arr_v4float_uint_2 = OpTypeArray %v4float %uint_2 +%_arr_v4float_uint_7 = OpTypeArray %v4float %uint_7 +%_arr_v4float_uint_4 = OpTypeArray %v4float %uint_4 + %type_View = OpTypeStruct %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %v3float %float %v3float %float %v3float %float %v3float %float %v3float %float %v4float %v4float %v3float %float %v3float %float %v3float %float %v3float %float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %v3float %float %v3float %float %v3float %float %mat4v4float %mat4v4float %mat4v4float %v4float %v4float %v2float %v2float %v4float %v4float %v4float %v4float %int %float %float %float %v4float %v4float %v4float %v2float %float %float %float %float %float %float %v3float %float %float %float %float %float %float %float %float %uint %uint %uint %uint %float %float %float %float %float %v4float %v3float %float %_arr_v4float_uint_2 %_arr_v4float_uint_2 %v4float %v4float %float %float %float %float %float %float %float %float %float %float %float %float %v3float %float %v3float %float %float %float %float %float %float %float %float %float %float %float %float %float %v4float %uint %uint %uint %uint %v4float %v3float %float %v4float %float %float %float %float %v4float %_arr_v4float_uint_7 %float %float %float %float %uint %float %float %float %v3float %int %_arr_v4float_uint_4 %_arr_v4float_uint_4 %float %float %float %float %v2int %float %float %v3float %float %v3float %float %v2float %float %float %v3float %float %v3float %float %v3float %float %v3float %float %float %float +%_ptr_Uniform_type_View = OpTypePointer Uniform %type_View +%type_PrimitiveDither = OpTypeStruct %float +%_ptr_Uniform_type_PrimitiveDither = OpTypePointer Uniform %type_PrimitiveDither +%type_PrimitiveFade = OpTypeStruct %v2float +%_ptr_Uniform_type_PrimitiveFade = OpTypePointer Uniform %type_PrimitiveFade + %uint_9 = OpConstant %uint 9 +%_arr_v4float_uint_9 = OpTypeArray %v4float %uint_9 + %uint_3 = OpConstant %uint 3 +%_arr_v4float_uint_3 = OpTypeArray %v4float %uint_3 +%type_Material = OpTypeStruct %_arr_v4float_uint_9 %_arr_v4float_uint_3 +%_ptr_Uniform_type_Material = OpTypePointer Uniform %type_Material +%type_2d_image = OpTypeImage %float 2D 2 0 0 1 Unknown +%_ptr_UniformConstant_type_2d_image = OpTypePointer UniformConstant %type_2d_image +%type_sampler = OpTypeSampler +%_ptr_UniformConstant_type_sampler = OpTypePointer UniformConstant %type_sampler +%_ptr_Input_v4float = OpTypePointer Input %v4float +%_arr_v4float_uint_1 = OpTypeArray %v4float %uint_1 +%_ptr_Input__arr_v4float_uint_1 = OpTypePointer Input %_arr_v4float_uint_1 +%_ptr_Input_uint = OpTypePointer Input %uint +%_ptr_Input_bool = OpTypePointer Input %bool +%_ptr_Output_float = OpTypePointer Output %float +%_ptr_Output_v4float = OpTypePointer Output %v4float + %void = OpTypeVoid + %93 = OpTypeFunction %void +%_ptr_Uniform_mat4v4float = OpTypePointer Uniform %mat4v4float +%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float +%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float +%_ptr_Uniform_float = OpTypePointer Uniform %float +%type_sampled_image = OpTypeSampledImage %type_2d_image + %View = OpVariable %_ptr_Uniform_type_View Uniform +%PrimitiveDither = OpVariable %_ptr_Uniform_type_PrimitiveDither Uniform +%PrimitiveFade = OpVariable %_ptr_Uniform_type_PrimitiveFade Uniform + %Material = OpVariable %_ptr_Uniform_type_Material Uniform +%Material_Texture2D_0 = OpVariable %_ptr_UniformConstant_type_2d_image UniformConstant +%Material_Texture2D_0Sampler = OpVariable %_ptr_UniformConstant_type_sampler UniformConstant +%Material_Texture2D_3 = OpVariable %_ptr_UniformConstant_type_2d_image UniformConstant +%Material_Texture2D_3Sampler = OpVariable %_ptr_UniformConstant_type_sampler UniformConstant +%gl_FragCoord = OpVariable %_ptr_Input_v4float Input +%in_var_TEXCOORD6 = OpVariable %_ptr_Input_v4float Input +%in_var_TEXCOORD7 = OpVariable %_ptr_Input_v4float Input +%in_var_TEXCOORD10_centroid = OpVariable %_ptr_Input_v4float Input +%in_var_TEXCOORD11_centroid = OpVariable %_ptr_Input_v4float Input +%in_var_TEXCOORD0 = OpVariable %_ptr_Input__arr_v4float_uint_1 Input +%in_var_PRIMITIVE_ID = OpVariable %_ptr_Input_uint Input +%gl_FrontFacing = OpVariable %_ptr_Input_bool Input +%gl_FragDepth = OpVariable %_ptr_Output_float Output +%out_var_SV_Target0 = OpVariable %_ptr_Output_v4float Output + %98 = OpUndef %float + %99 = OpConstantNull %v2float +%float_0_015625 = OpConstant %float 0.015625 + %101 = OpConstantComposite %v2float %float_0_015625 %float_0_015625 +%float_0_166666672 = OpConstant %float 0.166666672 + %103 = OpUndef %float + %104 = OpConstantNull %v3float +%MainPixelShader = OpFunction %void None %93 + %105 = OpLabel + %106 = OpLoad %v4float %gl_FragCoord + %107 = OpLoad %v4float %in_var_TEXCOORD6 + %108 = OpLoad %v4float %in_var_TEXCOORD7 + %109 = OpLoad %v4float %in_var_TEXCOORD10_centroid + %110 = OpLoad %v4float %in_var_TEXCOORD11_centroid + %111 = OpLoad %_arr_v4float_uint_1 %in_var_TEXCOORD0 + %112 = OpAccessChain %_ptr_Uniform_mat4v4float %View %int_4 + %113 = OpLoad %mat4v4float %112 + %114 = OpAccessChain %_ptr_Uniform_mat4v4float %View %int_11 + %115 = OpLoad %mat4v4float %114 + %116 = OpAccessChain %_ptr_Uniform_v3float %View %int_32 + %117 = OpLoad %v3float %116 + %118 = OpAccessChain %_ptr_Uniform_v4float %View %int_53 + %119 = OpLoad %v4float %118 + %120 = OpAccessChain %_ptr_Uniform_v4float %View %int_57 + %121 = OpLoad %v4float %120 + %122 = OpAccessChain %_ptr_Uniform_float %View %int_80 + %123 = OpLoad %float %122 + %124 = OpCompositeExtract %v4float %111 0 + %125 = OpVectorShuffle %v2float %99 %124 2 3 + %126 = OpVectorShuffle %v3float %109 %109 0 1 2 + %127 = OpVectorShuffle %v3float %110 %110 0 1 2 + %128 = OpExtInst %v3float %1 Cross %127 %126 + %129 = OpCompositeExtract %float %110 3 + %130 = OpCompositeConstruct %v3float %129 %129 %129 + %131 = OpFMul %v3float %128 %130 + %132 = OpCompositeConstruct %mat3v3float %126 %131 %127 + %133 = OpVectorShuffle %v2float %106 %106 0 1 + %134 = OpVectorShuffle %v2float %121 %121 0 1 + %135 = OpFSub %v2float %133 %134 + %136 = OpCompositeExtract %float %106 2 + %137 = OpCompositeConstruct %v4float %103 %103 %136 %float_1 + %138 = OpCompositeExtract %float %106 3 + %139 = OpCompositeConstruct %v4float %138 %138 %138 %138 + %140 = OpFMul %v4float %137 %139 + %141 = OpCompositeExtract %float %106 0 + %142 = OpCompositeExtract %float %106 1 + %143 = OpCompositeConstruct %v4float %141 %142 %136 %float_1 + %144 = OpMatrixTimesVector %v4float %115 %143 + %145 = OpVectorShuffle %v3float %144 %144 0 1 2 + %146 = OpCompositeExtract %float %144 3 + %147 = OpCompositeConstruct %v3float %146 %146 %146 + %148 = OpFDiv %v3float %145 %147 + %149 = OpFSub %v3float %148 %117 + %150 = OpFNegate %v3float %148 + %151 = OpExtInst %v3float %1 Normalize %150 + %152 = OpVectorTimesMatrix %v3float %151 %132 + %153 = OpVectorShuffle %v2float %152 %152 0 1 + %154 = OpFMul %v2float %153 %67 + %155 = OpCompositeExtract %float %152 2 + %156 = OpCompositeConstruct %v2float %155 %155 + %157 = OpFDiv %v2float %154 %156 + %158 = OpAccessChain %_ptr_Uniform_float %Material %int_1 %int_0 %int_0 + %159 = OpLoad %float %158 + %160 = OpCompositeConstruct %v2float %159 %159 + %161 = OpFMul %v2float %160 %157 + %162 = OpDot %float %151 %127 + %163 = OpExtInst %float %1 FAbs %162 + %164 = OpExtInst %float %1 FMax %163 %float_0 + %165 = OpExtInst %float %1 FMin %164 %float_1 + %166 = OpAccessChain %_ptr_Uniform_float %Material %int_1 %int_0 %int_1 + %167 = OpLoad %float %166 + %168 = OpAccessChain %_ptr_Uniform_float %Material %int_1 %int_0 %int_2 + %169 = OpLoad %float %168 + %170 = OpExtInst %float %1 FMix %167 %169 %165 + %171 = OpExtInst %float %1 Floor %170 + %172 = OpFDiv %float %float_1 %170 + %173 = OpCompositeConstruct %v2float %172 %172 + %174 = OpFMul %v2float %161 %173 + %175 = OpDPdx %v2float %125 + %176 = OpDPdy %v2float %125 + %177 = OpLoad %type_2d_image %Material_Texture2D_0 + %178 = OpLoad %type_sampler %Material_Texture2D_0Sampler + OpBranch %179 + %179 = OpLabel + %180 = OpPhi %float %float_1 %105 %181 %182 + %183 = OpPhi %v2float %49 %105 %184 %182 + %185 = OpPhi %int %int_0 %105 %186 %182 + %187 = OpPhi %float %float_1 %105 %188 %182 + %189 = OpPhi %float %float_1 %105 %180 %182 + %190 = OpConvertSToF %float %185 + %191 = OpFAdd %float %171 %float_2 + %192 = OpFOrdLessThan %bool %190 %191 + OpLoopMerge %193 %182 None + OpBranchConditional %192 %194 %193 + %194 = OpLabel + %195 = OpFAdd %v2float %125 %183 + %196 = OpSampledImage %type_sampled_image %177 %178 + %197 = OpImageSampleExplicitLod %v4float %196 %195 Grad %175 %176 + %188 = OpCompositeExtract %float %197 1 + %198 = OpFOrdLessThan %bool %180 %188 + OpSelectionMerge %182 None + OpBranchConditional %198 %199 %182 + %199 = OpLabel + %200 = OpFSub %float %189 %187 + %201 = OpFSub %float %188 %180 + %202 = OpFAdd %float %200 %201 + %203 = OpFDiv %float %201 %202 + %204 = OpFMul %float %189 %203 + %205 = OpFSub %float %float_1 %203 + %206 = OpFMul %float %180 %205 + %207 = OpFAdd %float %204 %206 + %208 = OpCompositeConstruct %v2float %203 %203 + %209 = OpFMul %v2float %208 %174 + %210 = OpFSub %v2float %183 %209 + OpBranch %193 + %182 = OpLabel + %181 = OpFSub %float %180 %172 + %184 = OpFAdd %v2float %183 %174 + %186 = OpIAdd %int %185 %int_1 + OpBranch %179 + %193 = OpLabel + %211 = OpPhi %float %98 %179 %207 %199 + %212 = OpPhi %v2float %183 %179 %210 %199 + %213 = OpVectorShuffle %v2float %212 %104 0 1 + %214 = OpFAdd %v2float %125 %213 + %215 = OpAccessChain %_ptr_Uniform_float %View %int_82 + %216 = OpLoad %float %215 + %217 = OpSampledImage %type_sampled_image %177 %178 + %218 = OpImageSampleImplicitLod %v4float %217 %214 Bias %216 + %219 = OpCompositeExtract %float %218 0 + %220 = OpAccessChain %_ptr_Uniform_float %Material %int_1 %int_2 %int_1 + %221 = OpLoad %float %220 + %222 = OpFMul %float %219 %221 + %223 = OpFSub %float %float_1 %222 + %224 = OpExtInst %float %1 FMax %223 %float_0 + %225 = OpExtInst %float %1 FMin %224 %float_1 + %226 = OpAccessChain %_ptr_Uniform_float %View %int_98 %int_0 + %227 = OpLoad %float %226 + %228 = OpCompositeConstruct %v2float %227 %227 + %229 = OpFAdd %v2float %135 %228 + %230 = OpCompositeExtract %float %229 0 + %231 = OpConvertFToU %uint %230 + %232 = OpCompositeExtract %float %229 1 + %233 = OpConvertFToU %uint %232 + %234 = OpIMul %uint %uint_2 %233 + %235 = OpIAdd %uint %231 %234 + %236 = OpUMod %uint %235 %uint_5 + %237 = OpConvertUToF %float %236 + %238 = OpFMul %v2float %135 %101 + %239 = OpLoad %type_2d_image %Material_Texture2D_3 + %240 = OpLoad %type_sampler %Material_Texture2D_3Sampler + %241 = OpSampledImage %type_sampled_image %239 %240 + %242 = OpImageSampleImplicitLod %v4float %241 %238 Bias %216 + %243 = OpCompositeExtract %float %242 0 + %244 = OpAccessChain %_ptr_Uniform_float %Material %int_1 %int_2 %int_2 + %245 = OpLoad %float %244 + %246 = OpFMul %float %243 %245 + %247 = OpFAdd %float %237 %246 + %248 = OpFMul %float %247 %float_0_166666672 + %249 = OpFAdd %float %225 %248 + %250 = OpFAdd %float %249 %float_n0_5 + %251 = OpCompositeExtract %float %218 2 + %252 = OpFAdd %float %251 %250 + %253 = OpSampledImage %type_sampled_image %239 %240 + %254 = OpImageSampleImplicitLod %v4float %253 %238 Bias %216 + %255 = OpCompositeExtract %float %254 0 + %256 = OpFAdd %float %237 %255 + %257 = OpFMul %float %256 %float_0_166666672 + %258 = OpAccessChain %_ptr_Uniform_float %PrimitiveFade %int_0 %int_0 + %259 = OpLoad %float %258 + %260 = OpFMul %float %123 %259 + %261 = OpAccessChain %_ptr_Uniform_float %PrimitiveFade %int_0 %int_1 + %262 = OpLoad %float %261 + %263 = OpFAdd %float %260 %262 + %264 = OpExtInst %float %1 FClamp %263 %float_0 %float_1 + %265 = OpFAdd %float %264 %257 + %266 = OpFAdd %float %265 %float_n0_5 + %267 = OpFMul %float %252 %266 + %268 = OpFSub %float %float_1 %211 + %269 = OpFMul %float %268 %159 + %270 = OpCompositeExtract %float %212 0 + %271 = OpCompositeExtract %float %212 1 + %272 = OpCompositeConstruct %v3float %270 %271 %269 + %273 = OpDot %float %272 %272 + %274 = OpExtInst %float %1 Sqrt %273 + %275 = OpDPdx %v2float %125 + %276 = OpExtInst %v2float %1 FAbs %275 + %277 = OpDot %float %276 %276 + %278 = OpExtInst %float %1 Sqrt %277 + %279 = OpDPdx %v3float %149 + %280 = OpDot %float %279 %279 + %281 = OpExtInst %float %1 Sqrt %280 + %282 = OpFDiv %float %278 %281 + %283 = OpDPdy %v2float %125 + %284 = OpExtInst %v2float %1 FAbs %283 + %285 = OpDot %float %284 %284 + %286 = OpExtInst %float %1 Sqrt %285 + %287 = OpDPdy %v3float %149 + %288 = OpDot %float %287 %287 + %289 = OpExtInst %float %1 Sqrt %288 + %290 = OpFDiv %float %286 %289 + %291 = OpExtInst %float %1 FMax %282 %290 + %292 = OpCompositeExtract %v4float %113 0 + %293 = OpVectorShuffle %v3float %292 %292 0 1 2 + %294 = OpCompositeExtract %v4float %113 1 + %295 = OpVectorShuffle %v3float %294 %294 0 1 2 + %296 = OpCompositeExtract %v4float %113 2 + %297 = OpVectorShuffle %v3float %296 %296 0 1 2 + %298 = OpCompositeConstruct %mat3v3float %293 %295 %297 + %299 = OpMatrixTimesVector %v3float %298 %70 + %300 = OpDot %float %299 %151 + %301 = OpExtInst %float %1 FAbs %300 + %302 = OpFDiv %float %291 %301 + %303 = OpFDiv %float %274 %302 + %304 = OpAccessChain %_ptr_Uniform_float %PrimitiveDither %int_0 + %305 = OpLoad %float %304 + %306 = OpFOrdNotEqual %bool %305 %float_0 + OpSelectionMerge %307 None + OpBranchConditional %306 %308 %307 + %308 = OpLabel + %309 = OpExtInst %float %1 FAbs %305 + %310 = OpFOrdGreaterThan %bool %309 %float_0_00100000005 + OpSelectionMerge %311 None + OpBranchConditional %310 %312 %311 + %312 = OpLabel + %313 = OpExtInst %v2float %1 Floor %133 + %314 = OpDot %float %313 %75 + %315 = OpExtInst %float %1 Cos %314 + %316 = OpFMul %float %315 %float_1000 + %317 = OpExtInst %float %1 Fract %316 + %318 = OpFOrdLessThan %bool %305 %float_0 + %319 = OpFAdd %float %305 %float_1 + %320 = OpFOrdGreaterThan %bool %319 %317 + %321 = OpFOrdLessThan %bool %305 %317 + %322 = OpSelect %bool %318 %320 %321 + %323 = OpSelect %float %322 %float_1 %float_0 + %324 = OpFSub %float %323 %float_0_00100000005 + %325 = OpFOrdLessThan %bool %324 %float_0 + OpSelectionMerge %326 None + OpBranchConditional %325 %327 %326 + %327 = OpLabel + OpKill + %326 = OpLabel + OpBranch %311 + %311 = OpLabel + OpBranch %307 + %307 = OpLabel + %328 = OpFSub %float %267 %float_0_333299994 + %329 = OpFOrdLessThan %bool %328 %float_0 + OpSelectionMerge %330 None + OpBranchConditional %329 %331 %330 + %331 = OpLabel + OpKill + %330 = OpLabel + %332 = OpCompositeExtract %float %140 2 + %333 = OpCompositeExtract %float %140 3 + %334 = OpFAdd %float %333 %303 + %335 = OpFDiv %float %332 %334 + %336 = OpExtInst %float %1 FMin %335 %136 + %337 = OpVectorShuffle %v2float %107 %107 0 1 + %338 = OpCompositeExtract %float %107 3 + %339 = OpCompositeConstruct %v2float %338 %338 + %340 = OpFDiv %v2float %337 %339 + %341 = OpVectorShuffle %v2float %119 %119 0 1 + %342 = OpFSub %v2float %340 %341 + %343 = OpVectorShuffle %v2float %108 %108 0 1 + %344 = OpCompositeExtract %float %108 3 + %345 = OpCompositeConstruct %v2float %344 %344 + %346 = OpFDiv %v2float %343 %345 + %347 = OpVectorShuffle %v2float %119 %119 2 3 + %348 = OpFSub %v2float %346 %347 + %349 = OpFSub %v2float %342 %348 + %350 = OpFMul %v2float %349 %54 + %351 = OpFAdd %v2float %350 %56 + %352 = OpVectorShuffle %v4float %351 %49 0 1 2 3 + OpStore %gl_FragDepth %336 + OpStore %out_var_SV_Target0 %352 + OpReturn + OpFunctionEnd diff --git a/third_party/spirv-cross/shaders-ue4-no-opt/asm/vert/loop-accesschain-writethrough.asm.invalid.vert b/third_party/spirv-cross/shaders-ue4-no-opt/asm/vert/loop-accesschain-writethrough.asm.invalid.vert new file mode 100644 index 0000000000..693f16c009 --- /dev/null +++ b/third_party/spirv-cross/shaders-ue4-no-opt/asm/vert/loop-accesschain-writethrough.asm.invalid.vert @@ -0,0 +1,259 @@ +; SPIR-V +; Version: 1.0 +; Generator: Google spiregg; 0 +; Bound: 181 +; Schema: 0 + OpCapability Shader + OpExtension "SPV_GOOGLE_hlsl_functionality1" + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %ScatterMainVS "main" %gl_VertexIndex %gl_InstanceIndex %out_var_TEXCOORD0 %out_var_TEXCOORD1 %out_var_TEXCOORD2 %out_var_TEXCOORD3 %out_var_TEXCOORD4 %out_var_TEXCOORD5 %out_var_TEXCOORD6 %gl_Position + OpSource HLSL 600 + OpName %type__Globals "type.$Globals" + OpMemberName %type__Globals 0 "ViewportSize" + OpMemberName %type__Globals 1 "ScatteringScaling" + OpMemberName %type__Globals 2 "CocRadiusToCircumscribedRadius" + OpName %_Globals "$Globals" + OpName %type_StructuredBuffer_v4float "type.StructuredBuffer.v4float" + OpName %ScatterDrawList "ScatterDrawList" + OpName %out_var_TEXCOORD0 "out.var.TEXCOORD0" + OpName %out_var_TEXCOORD1 "out.var.TEXCOORD1" + OpName %out_var_TEXCOORD2 "out.var.TEXCOORD2" + OpName %out_var_TEXCOORD3 "out.var.TEXCOORD3" + OpName %out_var_TEXCOORD4 "out.var.TEXCOORD4" + OpName %out_var_TEXCOORD5 "out.var.TEXCOORD5" + OpName %out_var_TEXCOORD6 "out.var.TEXCOORD6" + OpName %ScatterMainVS "ScatterMainVS" + OpDecorate %gl_VertexIndex BuiltIn VertexIndex + OpDecorateString %gl_VertexIndex UserSemantic "SV_VertexID" + OpDecorate %gl_InstanceIndex BuiltIn InstanceIndex + OpDecorateString %gl_InstanceIndex UserSemantic "SV_InstanceID" + OpDecorateString %out_var_TEXCOORD0 UserSemantic "TEXCOORD0" + OpDecorateString %out_var_TEXCOORD1 UserSemantic "TEXCOORD1" + OpDecorateString %out_var_TEXCOORD2 UserSemantic "TEXCOORD2" + OpDecorateString %out_var_TEXCOORD3 UserSemantic "TEXCOORD3" + OpDecorateString %out_var_TEXCOORD4 UserSemantic "TEXCOORD4" + OpDecorateString %out_var_TEXCOORD5 UserSemantic "TEXCOORD5" + OpDecorateString %out_var_TEXCOORD6 UserSemantic "TEXCOORD6" + OpDecorate %gl_Position BuiltIn Position + OpDecorateString %gl_Position UserSemantic "SV_POSITION" + OpDecorate %out_var_TEXCOORD0 Location 0 + OpDecorate %out_var_TEXCOORD1 Location 1 + OpDecorate %out_var_TEXCOORD2 Location 2 + OpDecorate %out_var_TEXCOORD3 Location 3 + OpDecorate %out_var_TEXCOORD4 Location 4 + OpDecorate %out_var_TEXCOORD5 Location 5 + OpDecorate %out_var_TEXCOORD6 Location 6 + OpDecorate %_Globals DescriptorSet 0 + OpDecorate %_Globals Binding 1 + OpDecorate %ScatterDrawList DescriptorSet 0 + OpDecorate %ScatterDrawList Binding 0 + OpMemberDecorate %type__Globals 0 Offset 0 + OpMemberDecorate %type__Globals 1 Offset 16 + OpMemberDecorate %type__Globals 2 Offset 20 + OpDecorate %type__Globals Block + OpDecorate %_runtimearr_v4float ArrayStride 16 + OpMemberDecorate %type_StructuredBuffer_v4float 0 Offset 0 + OpMemberDecorate %type_StructuredBuffer_v4float 0 NonWritable + OpDecorate %type_StructuredBuffer_v4float BufferBlock + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 + %v2float = OpTypeVector %float 2 + %int = OpTypeInt 32 1 + %uint = OpTypeInt 32 0 + %uint_2 = OpConstant %uint 2 + %uint_4 = OpConstant %uint 4 +%_arr_v4float_uint_4 = OpTypeArray %v4float %uint_4 + %float_0_5 = OpConstant %float 0.5 + %int_0 = OpConstant %int 0 + %int_1 = OpConstant %int 1 + %float_1 = OpConstant %float 1 + %uint_16 = OpConstant %uint 16 + %float_0 = OpConstant %float 0 + %uint_0 = OpConstant %uint 0 + %uint_5 = OpConstant %uint 5 + %uint_1 = OpConstant %uint 1 + %int_3 = OpConstant %int 3 + %float_n0_5 = OpConstant %float -0.5 + %int_2 = OpConstant %int 2 + %float_2 = OpConstant %float 2 + %39 = OpConstantComposite %v2float %float_2 %float_2 + %40 = OpConstantComposite %v2float %float_1 %float_1 + %41 = OpConstantComposite %v2float %float_0_5 %float_0_5 +%type__Globals = OpTypeStruct %v4float %float %float +%_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals +%_runtimearr_v4float = OpTypeRuntimeArray %v4float +%type_StructuredBuffer_v4float = OpTypeStruct %_runtimearr_v4float +%_ptr_Uniform_type_StructuredBuffer_v4float = OpTypePointer Uniform %type_StructuredBuffer_v4float +%_ptr_Input_uint = OpTypePointer Input %uint +%_ptr_Output_v2float = OpTypePointer Output %v2float +%_ptr_Output_v4float = OpTypePointer Output %v4float + %void = OpTypeVoid + %48 = OpTypeFunction %void +%_ptr_Function_v2float = OpTypePointer Function %v2float +%_ptr_Function_v4float = OpTypePointer Function %v4float +%_ptr_Function__arr_v4float_uint_4 = OpTypePointer Function %_arr_v4float_uint_4 +%_arr_float_uint_4 = OpTypeArray %float %uint_4 +%_ptr_Function__arr_float_uint_4 = OpTypePointer Function %_arr_float_uint_4 +%_arr_v2float_uint_4 = OpTypeArray %v2float %uint_4 +%_ptr_Function__arr_v2float_uint_4 = OpTypePointer Function %_arr_v2float_uint_4 +%_ptr_Function_float = OpTypePointer Function %float + %bool = OpTypeBool +%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float +%_ptr_Uniform_float = OpTypePointer Uniform %float + %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform +%ScatterDrawList = OpVariable %_ptr_Uniform_type_StructuredBuffer_v4float Uniform +%gl_VertexIndex = OpVariable %_ptr_Input_uint Input +%gl_InstanceIndex = OpVariable %_ptr_Input_uint Input +%out_var_TEXCOORD0 = OpVariable %_ptr_Output_v2float Output +%out_var_TEXCOORD1 = OpVariable %_ptr_Output_v4float Output +%out_var_TEXCOORD2 = OpVariable %_ptr_Output_v4float Output +%out_var_TEXCOORD3 = OpVariable %_ptr_Output_v4float Output +%out_var_TEXCOORD4 = OpVariable %_ptr_Output_v4float Output +%out_var_TEXCOORD5 = OpVariable %_ptr_Output_v4float Output +%out_var_TEXCOORD6 = OpVariable %_ptr_Output_v4float Output +%gl_Position = OpVariable %_ptr_Output_v4float Output +%ScatterMainVS = OpFunction %void None %48 + %60 = OpLabel + %61 = OpVariable %_ptr_Function__arr_v4float_uint_4 Function + %62 = OpVariable %_ptr_Function__arr_float_uint_4 Function + %63 = OpVariable %_ptr_Function__arr_v2float_uint_4 Function + %64 = OpLoad %uint %gl_VertexIndex + %65 = OpLoad %uint %gl_InstanceIndex + %66 = OpUDiv %uint %64 %uint_4 + %67 = OpIMul %uint %66 %uint_4 + %68 = OpISub %uint %64 %67 + %69 = OpIMul %uint %uint_16 %65 + %70 = OpIAdd %uint %69 %66 + OpBranch %71 + %71 = OpLabel + %72 = OpPhi %float %float_0 %60 %73 %74 + %75 = OpPhi %uint %uint_0 %60 %76 %74 + %77 = OpULessThan %bool %75 %uint_4 + OpLoopMerge %78 %74 Unroll + OpBranchConditional %77 %79 %78 + %79 = OpLabel + %80 = OpIMul %uint %uint_5 %70 + %81 = OpIAdd %uint %80 %75 + %82 = OpIAdd %uint %81 %uint_1 + %83 = OpAccessChain %_ptr_Uniform_v4float %ScatterDrawList %int_0 %82 + %84 = OpLoad %v4float %83 + %85 = OpCompositeExtract %float %84 0 + %86 = OpCompositeExtract %float %84 1 + %87 = OpCompositeExtract %float %84 2 + %88 = OpCompositeConstruct %v4float %85 %86 %87 %float_0 + %89 = OpAccessChain %_ptr_Function_v4float %61 %75 + OpStore %89 %88 + %90 = OpCompositeExtract %float %84 3 + %91 = OpAccessChain %_ptr_Function_float %62 %75 + OpStore %91 %90 + %92 = OpIEqual %bool %75 %uint_0 + OpSelectionMerge %74 None + OpBranchConditional %92 %93 %94 + %93 = OpLabel + %95 = OpLoad %float %91 + OpBranch %74 + %94 = OpLabel + %96 = OpLoad %float %91 + %97 = OpExtInst %float %1 FMax %72 %96 + OpBranch %74 + %74 = OpLabel + %73 = OpPhi %float %95 %93 %97 %94 + %98 = OpLoad %float %91 + %99 = OpFDiv %float %float_n0_5 %98 + %100 = OpAccessChain %_ptr_Function_float %63 %75 %int_0 + OpStore %100 %99 + %101 = OpLoad %float %91 + %102 = OpFMul %float %float_0_5 %101 + %103 = OpFAdd %float %102 %float_0_5 + %104 = OpAccessChain %_ptr_Function_float %63 %75 %int_1 + OpStore %104 %103 + %76 = OpIAdd %uint %75 %uint_1 + OpBranch %71 + %78 = OpLabel + %105 = OpAccessChain %_ptr_Function_v4float %61 %int_0 + %106 = OpLoad %v4float %105 + %107 = OpCompositeExtract %float %106 0 + %108 = OpCompositeExtract %float %106 1 + %109 = OpCompositeExtract %float %106 2 + %110 = OpAccessChain %_ptr_Function_float %62 %int_0 + %111 = OpLoad %float %110 + %112 = OpCompositeConstruct %v4float %107 %108 %109 %111 + %113 = OpAccessChain %_ptr_Function_v4float %61 %int_1 + %114 = OpLoad %v4float %113 + %115 = OpCompositeExtract %float %114 0 + %116 = OpCompositeExtract %float %114 1 + %117 = OpCompositeExtract %float %114 2 + %118 = OpAccessChain %_ptr_Function_float %62 %int_1 + %119 = OpLoad %float %118 + %120 = OpCompositeConstruct %v4float %115 %116 %117 %119 + %121 = OpAccessChain %_ptr_Function_v4float %61 %int_2 + %122 = OpLoad %v4float %121 + %123 = OpCompositeExtract %float %122 0 + %124 = OpCompositeExtract %float %122 1 + %125 = OpCompositeExtract %float %122 2 + %126 = OpAccessChain %_ptr_Function_float %62 %int_2 + %127 = OpLoad %float %126 + %128 = OpCompositeConstruct %v4float %123 %124 %125 %127 + %129 = OpAccessChain %_ptr_Function_v4float %61 %int_3 + %130 = OpLoad %v4float %129 + %131 = OpCompositeExtract %float %130 0 + %132 = OpCompositeExtract %float %130 1 + %133 = OpCompositeExtract %float %130 2 + %134 = OpAccessChain %_ptr_Function_float %62 %int_3 + %135 = OpLoad %float %134 + %136 = OpCompositeConstruct %v4float %131 %132 %133 %135 + %137 = OpAccessChain %_ptr_Uniform_float %_Globals %int_1 + %138 = OpLoad %float %137 + %139 = OpCompositeConstruct %v2float %138 %138 + %140 = OpIMul %uint %uint_5 %70 + %141 = OpAccessChain %_ptr_Uniform_v4float %ScatterDrawList %int_0 %140 + %142 = OpLoad %v4float %141 + %143 = OpVectorShuffle %v2float %142 %142 0 1 + %144 = OpFMul %v2float %139 %143 + %145 = OpAccessChain %_ptr_Function_v2float %63 %int_0 + %146 = OpLoad %v2float %145 + %147 = OpAccessChain %_ptr_Function_v2float %63 %int_1 + %148 = OpLoad %v2float %147 + %149 = OpVectorShuffle %v4float %146 %148 0 1 2 3 + %150 = OpAccessChain %_ptr_Function_v2float %63 %int_2 + %151 = OpLoad %v2float %150 + %152 = OpAccessChain %_ptr_Function_v2float %63 %int_3 + %153 = OpLoad %v2float %152 + %154 = OpVectorShuffle %v4float %151 %153 0 1 2 3 + %155 = OpUMod %uint %68 %uint_2 + %156 = OpConvertUToF %float %155 + %157 = OpUDiv %uint %68 %uint_2 + %158 = OpConvertUToF %float %157 + %159 = OpCompositeConstruct %v2float %156 %158 + %160 = OpFMul %v2float %159 %39 + %161 = OpFSub %v2float %160 %40 + %162 = OpAccessChain %_ptr_Uniform_float %_Globals %int_2 + %163 = OpLoad %float %162 + %164 = OpFMul %float %72 %163 + %165 = OpFAdd %float %164 %float_1 + %166 = OpCompositeConstruct %v2float %165 %165 + %167 = OpFMul %v2float %166 %161 + %168 = OpFAdd %v2float %167 %144 + %169 = OpFAdd %v2float %168 %41 + %170 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_0 + %171 = OpLoad %v4float %170 + %172 = OpVectorShuffle %v2float %171 %171 2 3 + %173 = OpFMul %v2float %169 %172 + %174 = OpCompositeExtract %float %173 0 + %175 = OpFMul %float %174 %float_2 + %176 = OpFSub %float %175 %float_1 + %177 = OpCompositeExtract %float %173 1 + %178 = OpFMul %float %177 %float_2 + %179 = OpFSub %float %float_1 %178 + %180 = OpCompositeConstruct %v4float %176 %179 %float_0 %float_1 + OpStore %out_var_TEXCOORD0 %144 + OpStore %out_var_TEXCOORD1 %112 + OpStore %out_var_TEXCOORD2 %120 + OpStore %out_var_TEXCOORD3 %128 + OpStore %out_var_TEXCOORD4 %136 + OpStore %out_var_TEXCOORD5 %149 + OpStore %out_var_TEXCOORD6 %154 + OpStore %gl_Position %180 + OpReturn + OpFunctionEnd diff --git a/third_party/spirv-cross/shaders-ue4/asm/frag/depth-compare.asm.frag b/third_party/spirv-cross/shaders-ue4/asm/frag/depth-compare.asm.frag new file mode 100644 index 0000000000..603d4f28c4 --- /dev/null +++ b/third_party/spirv-cross/shaders-ue4/asm/frag/depth-compare.asm.frag @@ -0,0 +1,961 @@ +; SPIR-V +; Version: 1.0 +; Generator: Google spiregg; 0 +; Bound: 452 +; Schema: 0 + OpCapability Shader + OpExtension "SPV_GOOGLE_hlsl_functionality1" + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %MainOnePassPointLightPS "main" %gl_FragCoord %out_var_SV_Target0 + OpExecutionMode %MainOnePassPointLightPS OriginUpperLeft + OpSource HLSL 600 + OpName %type_View "type.View" + OpMemberName %type_View 0 "View_TranslatedWorldToClip" + OpMemberName %type_View 1 "View_WorldToClip" + OpMemberName %type_View 2 "View_TranslatedWorldToView" + OpMemberName %type_View 3 "View_ViewToTranslatedWorld" + OpMemberName %type_View 4 "View_TranslatedWorldToCameraView" + OpMemberName %type_View 5 "View_CameraViewToTranslatedWorld" + OpMemberName %type_View 6 "View_ViewToClip" + OpMemberName %type_View 7 "View_ViewToClipNoAA" + OpMemberName %type_View 8 "View_ClipToView" + OpMemberName %type_View 9 "View_ClipToTranslatedWorld" + OpMemberName %type_View 10 "View_SVPositionToTranslatedWorld" + OpMemberName %type_View 11 "View_ScreenToWorld" + OpMemberName %type_View 12 "View_ScreenToTranslatedWorld" + OpMemberName %type_View 13 "View_ViewForward" + OpMemberName %type_View 14 "PrePadding_View_844" + OpMemberName %type_View 15 "View_ViewUp" + OpMemberName %type_View 16 "PrePadding_View_860" + OpMemberName %type_View 17 "View_ViewRight" + OpMemberName %type_View 18 "PrePadding_View_876" + OpMemberName %type_View 19 "View_HMDViewNoRollUp" + OpMemberName %type_View 20 "PrePadding_View_892" + OpMemberName %type_View 21 "View_HMDViewNoRollRight" + OpMemberName %type_View 22 "PrePadding_View_908" + OpMemberName %type_View 23 "View_InvDeviceZToWorldZTransform" + OpMemberName %type_View 24 "View_ScreenPositionScaleBias" + OpMemberName %type_View 25 "View_WorldCameraOrigin" + OpMemberName %type_View 26 "PrePadding_View_956" + OpMemberName %type_View 27 "View_TranslatedWorldCameraOrigin" + OpMemberName %type_View 28 "PrePadding_View_972" + OpMemberName %type_View 29 "View_WorldViewOrigin" + OpMemberName %type_View 30 "PrePadding_View_988" + OpMemberName %type_View 31 "View_PreViewTranslation" + OpMemberName %type_View 32 "PrePadding_View_1004" + OpMemberName %type_View 33 "View_PrevProjection" + OpMemberName %type_View 34 "View_PrevViewProj" + OpMemberName %type_View 35 "View_PrevViewRotationProj" + OpMemberName %type_View 36 "View_PrevViewToClip" + OpMemberName %type_View 37 "View_PrevClipToView" + OpMemberName %type_View 38 "View_PrevTranslatedWorldToClip" + OpMemberName %type_View 39 "View_PrevTranslatedWorldToView" + OpMemberName %type_View 40 "View_PrevViewToTranslatedWorld" + OpMemberName %type_View 41 "View_PrevTranslatedWorldToCameraView" + OpMemberName %type_View 42 "View_PrevCameraViewToTranslatedWorld" + OpMemberName %type_View 43 "View_PrevWorldCameraOrigin" + OpMemberName %type_View 44 "PrePadding_View_1660" + OpMemberName %type_View 45 "View_PrevWorldViewOrigin" + OpMemberName %type_View 46 "PrePadding_View_1676" + OpMemberName %type_View 47 "View_PrevPreViewTranslation" + OpMemberName %type_View 48 "PrePadding_View_1692" + OpMemberName %type_View 49 "View_PrevInvViewProj" + OpMemberName %type_View 50 "View_PrevScreenToTranslatedWorld" + OpMemberName %type_View 51 "View_ClipToPrevClip" + OpMemberName %type_View 52 "View_TemporalAAJitter" + OpMemberName %type_View 53 "View_GlobalClippingPlane" + OpMemberName %type_View 54 "View_FieldOfViewWideAngles" + OpMemberName %type_View 55 "View_PrevFieldOfViewWideAngles" + OpMemberName %type_View 56 "View_ViewRectMin" + OpMemberName %type_View 57 "View_ViewSizeAndInvSize" + OpMemberName %type_View 58 "View_BufferSizeAndInvSize" + OpMemberName %type_View 59 "View_BufferBilinearUVMinMax" + OpMemberName %type_View 60 "View_NumSceneColorMSAASamples" + OpMemberName %type_View 61 "View_PreExposure" + OpMemberName %type_View 62 "View_OneOverPreExposure" + OpMemberName %type_View 63 "PrePadding_View_2012" + OpMemberName %type_View 64 "View_DiffuseOverrideParameter" + OpMemberName %type_View 65 "View_SpecularOverrideParameter" + OpMemberName %type_View 66 "View_NormalOverrideParameter" + OpMemberName %type_View 67 "View_RoughnessOverrideParameter" + OpMemberName %type_View 68 "View_PrevFrameGameTime" + OpMemberName %type_View 69 "View_PrevFrameRealTime" + OpMemberName %type_View 70 "View_OutOfBoundsMask" + OpMemberName %type_View 71 "PrePadding_View_2084" + OpMemberName %type_View 72 "PrePadding_View_2088" + OpMemberName %type_View 73 "PrePadding_View_2092" + OpMemberName %type_View 74 "View_WorldCameraMovementSinceLastFrame" + OpMemberName %type_View 75 "View_CullingSign" + OpMemberName %type_View 76 "View_NearPlane" + OpMemberName %type_View 77 "View_AdaptiveTessellationFactor" + OpMemberName %type_View 78 "View_GameTime" + OpMemberName %type_View 79 "View_RealTime" + OpMemberName %type_View 80 "View_DeltaTime" + OpMemberName %type_View 81 "View_MaterialTextureMipBias" + OpMemberName %type_View 82 "View_MaterialTextureDerivativeMultiply" + OpMemberName %type_View 83 "View_Random" + OpMemberName %type_View 84 "View_FrameNumber" + OpMemberName %type_View 85 "View_StateFrameIndexMod8" + OpMemberName %type_View 86 "View_StateFrameIndex" + OpMemberName %type_View 87 "View_CameraCut" + OpMemberName %type_View 88 "View_UnlitViewmodeMask" + OpMemberName %type_View 89 "PrePadding_View_2164" + OpMemberName %type_View 90 "PrePadding_View_2168" + OpMemberName %type_View 91 "PrePadding_View_2172" + OpMemberName %type_View 92 "View_DirectionalLightColor" + OpMemberName %type_View 93 "View_DirectionalLightDirection" + OpMemberName %type_View 94 "PrePadding_View_2204" + OpMemberName %type_View 95 "View_TranslucencyLightingVolumeMin" + OpMemberName %type_View 96 "View_TranslucencyLightingVolumeInvSize" + OpMemberName %type_View 97 "View_TemporalAAParams" + OpMemberName %type_View 98 "View_CircleDOFParams" + OpMemberName %type_View 99 "View_DepthOfFieldSensorWidth" + OpMemberName %type_View 100 "View_DepthOfFieldFocalDistance" + OpMemberName %type_View 101 "View_DepthOfFieldScale" + OpMemberName %type_View 102 "View_DepthOfFieldFocalLength" + OpMemberName %type_View 103 "View_DepthOfFieldFocalRegion" + OpMemberName %type_View 104 "View_DepthOfFieldNearTransitionRegion" + OpMemberName %type_View 105 "View_DepthOfFieldFarTransitionRegion" + OpMemberName %type_View 106 "View_MotionBlurNormalizedToPixel" + OpMemberName %type_View 107 "View_bSubsurfacePostprocessEnabled" + OpMemberName %type_View 108 "View_GeneralPurposeTweak" + OpMemberName %type_View 109 "View_DemosaicVposOffset" + OpMemberName %type_View 110 "PrePadding_View_2348" + OpMemberName %type_View 111 "View_IndirectLightingColorScale" + OpMemberName %type_View 112 "View_HDR32bppEncodingMode" + OpMemberName %type_View 113 "View_AtmosphericFogSunDirection" + OpMemberName %type_View 114 "View_AtmosphericFogSunPower" + OpMemberName %type_View 115 "View_AtmosphericFogPower" + OpMemberName %type_View 116 "View_AtmosphericFogDensityScale" + OpMemberName %type_View 117 "View_AtmosphericFogDensityOffset" + OpMemberName %type_View 118 "View_AtmosphericFogGroundOffset" + OpMemberName %type_View 119 "View_AtmosphericFogDistanceScale" + OpMemberName %type_View 120 "View_AtmosphericFogAltitudeScale" + OpMemberName %type_View 121 "View_AtmosphericFogHeightScaleRayleigh" + OpMemberName %type_View 122 "View_AtmosphericFogStartDistance" + OpMemberName %type_View 123 "View_AtmosphericFogDistanceOffset" + OpMemberName %type_View 124 "View_AtmosphericFogSunDiscScale" + OpMemberName %type_View 125 "View_AtmosphericFogRenderMask" + OpMemberName %type_View 126 "View_AtmosphericFogInscatterAltitudeSampleNum" + OpMemberName %type_View 127 "View_AtmosphericFogSunColor" + OpMemberName %type_View 128 "View_NormalCurvatureToRoughnessScaleBias" + OpMemberName %type_View 129 "View_RenderingReflectionCaptureMask" + OpMemberName %type_View 130 "View_AmbientCubemapTint" + OpMemberName %type_View 131 "View_AmbientCubemapIntensity" + OpMemberName %type_View 132 "View_SkyLightParameters" + OpMemberName %type_View 133 "PrePadding_View_2488" + OpMemberName %type_View 134 "PrePadding_View_2492" + OpMemberName %type_View 135 "View_SkyLightColor" + OpMemberName %type_View 136 "View_SkyIrradianceEnvironmentMap" + OpMemberName %type_View 137 "View_MobilePreviewMode" + OpMemberName %type_View 138 "View_HMDEyePaddingOffset" + OpMemberName %type_View 139 "View_ReflectionCubemapMaxMip" + OpMemberName %type_View 140 "View_ShowDecalsMask" + OpMemberName %type_View 141 "View_DistanceFieldAOSpecularOcclusionMode" + OpMemberName %type_View 142 "View_IndirectCapsuleSelfShadowingIntensity" + OpMemberName %type_View 143 "PrePadding_View_2648" + OpMemberName %type_View 144 "PrePadding_View_2652" + OpMemberName %type_View 145 "View_ReflectionEnvironmentRoughnessMixingScaleBiasAndLargestWeight" + OpMemberName %type_View 146 "View_StereoPassIndex" + OpMemberName %type_View 147 "View_GlobalVolumeCenterAndExtent" + OpMemberName %type_View 148 "View_GlobalVolumeWorldToUVAddAndMul" + OpMemberName %type_View 149 "View_GlobalVolumeDimension" + OpMemberName %type_View 150 "View_GlobalVolumeTexelSize" + OpMemberName %type_View 151 "View_MaxGlobalDistance" + OpMemberName %type_View 152 "View_bCheckerboardSubsurfaceProfileRendering" + OpMemberName %type_View 153 "View_VolumetricFogInvGridSize" + OpMemberName %type_View 154 "PrePadding_View_2828" + OpMemberName %type_View 155 "View_VolumetricFogGridZParams" + OpMemberName %type_View 156 "PrePadding_View_2844" + OpMemberName %type_View 157 "View_VolumetricFogSVPosToVolumeUV" + OpMemberName %type_View 158 "View_VolumetricFogMaxDistance" + OpMemberName %type_View 159 "PrePadding_View_2860" + OpMemberName %type_View 160 "View_VolumetricLightmapWorldToUVScale" + OpMemberName %type_View 161 "PrePadding_View_2876" + OpMemberName %type_View 162 "View_VolumetricLightmapWorldToUVAdd" + OpMemberName %type_View 163 "PrePadding_View_2892" + OpMemberName %type_View 164 "View_VolumetricLightmapIndirectionTextureSize" + OpMemberName %type_View 165 "View_VolumetricLightmapBrickSize" + OpMemberName %type_View 166 "View_VolumetricLightmapBrickTexelSize" + OpMemberName %type_View 167 "View_StereoIPD" + OpMemberName %type_View 168 "View_IndirectLightingCacheShowFlag" + OpMemberName %type_View 169 "View_EyeToPixelSpreadAngle" + OpName %View "View" + OpName %type_2d_image "type.2d.image" + OpName %SceneTexturesStruct_SceneDepthTexture "SceneTexturesStruct_SceneDepthTexture" + OpName %type_sampler "type.sampler" + OpName %SceneTexturesStruct_SceneDepthTextureSampler "SceneTexturesStruct_SceneDepthTextureSampler" + OpName %SceneTexturesStruct_GBufferATexture "SceneTexturesStruct_GBufferATexture" + OpName %SceneTexturesStruct_GBufferBTexture "SceneTexturesStruct_GBufferBTexture" + OpName %SceneTexturesStruct_GBufferDTexture "SceneTexturesStruct_GBufferDTexture" + OpName %SceneTexturesStruct_GBufferATextureSampler "SceneTexturesStruct_GBufferATextureSampler" + OpName %SceneTexturesStruct_GBufferBTextureSampler "SceneTexturesStruct_GBufferBTextureSampler" + OpName %SceneTexturesStruct_GBufferDTextureSampler "SceneTexturesStruct_GBufferDTextureSampler" + OpName %ShadowDepthTextureSampler "ShadowDepthTextureSampler" + OpName %type__Globals "type.$Globals" + OpMemberName %type__Globals 0 "SoftTransitionScale" + OpMemberName %type__Globals 1 "ShadowViewProjectionMatrices" + OpMemberName %type__Globals 2 "InvShadowmapResolution" + OpMemberName %type__Globals 3 "ShadowFadeFraction" + OpMemberName %type__Globals 4 "ShadowSharpen" + OpMemberName %type__Globals 5 "LightPositionAndInvRadius" + OpMemberName %type__Globals 6 "ProjectionDepthBiasParameters" + OpMemberName %type__Globals 7 "PointLightDepthBiasAndProjParameters" + OpName %_Globals "$Globals" + OpName %type_cube_image "type.cube.image" + OpName %ShadowDepthCubeTexture "ShadowDepthCubeTexture" + OpName %ShadowDepthCubeTextureSampler "ShadowDepthCubeTextureSampler" + OpName %SSProfilesTexture "SSProfilesTexture" + OpName %out_var_SV_Target0 "out.var.SV_Target0" + OpName %MainOnePassPointLightPS "MainOnePassPointLightPS" + OpName %type_sampled_image "type.sampled.image" + OpName %type_sampled_image_0 "type.sampled.image" + OpDecorate %gl_FragCoord BuiltIn FragCoord + OpDecorateString %gl_FragCoord UserSemantic "SV_POSITION" + OpDecorateString %out_var_SV_Target0 UserSemantic "SV_Target0" + OpDecorate %out_var_SV_Target0 Location 0 + OpDecorate %View DescriptorSet 0 + OpDecorate %View Binding 0 + OpDecorate %SceneTexturesStruct_SceneDepthTexture DescriptorSet 0 + OpDecorate %SceneTexturesStruct_SceneDepthTexture Binding 0 + OpDecorate %SceneTexturesStruct_SceneDepthTextureSampler DescriptorSet 0 + OpDecorate %SceneTexturesStruct_SceneDepthTextureSampler Binding 0 + OpDecorate %SceneTexturesStruct_GBufferATexture DescriptorSet 0 + OpDecorate %SceneTexturesStruct_GBufferATexture Binding 1 + OpDecorate %SceneTexturesStruct_GBufferBTexture DescriptorSet 0 + OpDecorate %SceneTexturesStruct_GBufferBTexture Binding 2 + OpDecorate %SceneTexturesStruct_GBufferDTexture DescriptorSet 0 + OpDecorate %SceneTexturesStruct_GBufferDTexture Binding 3 + OpDecorate %SceneTexturesStruct_GBufferATextureSampler DescriptorSet 0 + OpDecorate %SceneTexturesStruct_GBufferATextureSampler Binding 1 + OpDecorate %SceneTexturesStruct_GBufferBTextureSampler DescriptorSet 0 + OpDecorate %SceneTexturesStruct_GBufferBTextureSampler Binding 2 + OpDecorate %SceneTexturesStruct_GBufferDTextureSampler DescriptorSet 0 + OpDecorate %SceneTexturesStruct_GBufferDTextureSampler Binding 3 + OpDecorate %ShadowDepthTextureSampler DescriptorSet 0 + OpDecorate %ShadowDepthTextureSampler Binding 4 + OpDecorate %_Globals DescriptorSet 0 + OpDecorate %_Globals Binding 1 + OpDecorate %ShadowDepthCubeTexture DescriptorSet 0 + OpDecorate %ShadowDepthCubeTexture Binding 4 + OpDecorate %ShadowDepthCubeTextureSampler DescriptorSet 0 + OpDecorate %ShadowDepthCubeTextureSampler Binding 5 + OpDecorate %SSProfilesTexture DescriptorSet 0 + OpDecorate %SSProfilesTexture Binding 5 + OpDecorate %_arr_v4float_uint_2 ArrayStride 16 + OpDecorate %_arr_v4float_uint_7 ArrayStride 16 + OpDecorate %_arr_v4float_uint_4 ArrayStride 16 + OpMemberDecorate %type_View 0 Offset 0 + OpMemberDecorate %type_View 0 MatrixStride 16 + OpMemberDecorate %type_View 0 ColMajor + OpMemberDecorate %type_View 1 Offset 64 + OpMemberDecorate %type_View 1 MatrixStride 16 + OpMemberDecorate %type_View 1 ColMajor + OpMemberDecorate %type_View 2 Offset 128 + OpMemberDecorate %type_View 2 MatrixStride 16 + OpMemberDecorate %type_View 2 ColMajor + OpMemberDecorate %type_View 3 Offset 192 + OpMemberDecorate %type_View 3 MatrixStride 16 + OpMemberDecorate %type_View 3 ColMajor + OpMemberDecorate %type_View 4 Offset 256 + OpMemberDecorate %type_View 4 MatrixStride 16 + OpMemberDecorate %type_View 4 ColMajor + OpMemberDecorate %type_View 5 Offset 320 + OpMemberDecorate %type_View 5 MatrixStride 16 + OpMemberDecorate %type_View 5 ColMajor + OpMemberDecorate %type_View 6 Offset 384 + OpMemberDecorate %type_View 6 MatrixStride 16 + OpMemberDecorate %type_View 6 ColMajor + OpMemberDecorate %type_View 7 Offset 448 + OpMemberDecorate %type_View 7 MatrixStride 16 + OpMemberDecorate %type_View 7 ColMajor + OpMemberDecorate %type_View 8 Offset 512 + OpMemberDecorate %type_View 8 MatrixStride 16 + OpMemberDecorate %type_View 8 ColMajor + OpMemberDecorate %type_View 9 Offset 576 + OpMemberDecorate %type_View 9 MatrixStride 16 + OpMemberDecorate %type_View 9 ColMajor + OpMemberDecorate %type_View 10 Offset 640 + OpMemberDecorate %type_View 10 MatrixStride 16 + OpMemberDecorate %type_View 10 ColMajor + OpMemberDecorate %type_View 11 Offset 704 + OpMemberDecorate %type_View 11 MatrixStride 16 + OpMemberDecorate %type_View 11 ColMajor + OpMemberDecorate %type_View 12 Offset 768 + OpMemberDecorate %type_View 12 MatrixStride 16 + OpMemberDecorate %type_View 12 ColMajor + OpMemberDecorate %type_View 13 Offset 832 + OpMemberDecorate %type_View 14 Offset 844 + OpMemberDecorate %type_View 15 Offset 848 + OpMemberDecorate %type_View 16 Offset 860 + OpMemberDecorate %type_View 17 Offset 864 + OpMemberDecorate %type_View 18 Offset 876 + OpMemberDecorate %type_View 19 Offset 880 + OpMemberDecorate %type_View 20 Offset 892 + OpMemberDecorate %type_View 21 Offset 896 + OpMemberDecorate %type_View 22 Offset 908 + OpMemberDecorate %type_View 23 Offset 912 + OpMemberDecorate %type_View 24 Offset 928 + OpMemberDecorate %type_View 25 Offset 944 + OpMemberDecorate %type_View 26 Offset 956 + OpMemberDecorate %type_View 27 Offset 960 + OpMemberDecorate %type_View 28 Offset 972 + OpMemberDecorate %type_View 29 Offset 976 + OpMemberDecorate %type_View 30 Offset 988 + OpMemberDecorate %type_View 31 Offset 992 + OpMemberDecorate %type_View 32 Offset 1004 + OpMemberDecorate %type_View 33 Offset 1008 + OpMemberDecorate %type_View 33 MatrixStride 16 + OpMemberDecorate %type_View 33 ColMajor + OpMemberDecorate %type_View 34 Offset 1072 + OpMemberDecorate %type_View 34 MatrixStride 16 + OpMemberDecorate %type_View 34 ColMajor + OpMemberDecorate %type_View 35 Offset 1136 + OpMemberDecorate %type_View 35 MatrixStride 16 + OpMemberDecorate %type_View 35 ColMajor + OpMemberDecorate %type_View 36 Offset 1200 + OpMemberDecorate %type_View 36 MatrixStride 16 + OpMemberDecorate %type_View 36 ColMajor + OpMemberDecorate %type_View 37 Offset 1264 + OpMemberDecorate %type_View 37 MatrixStride 16 + OpMemberDecorate %type_View 37 ColMajor + OpMemberDecorate %type_View 38 Offset 1328 + OpMemberDecorate %type_View 38 MatrixStride 16 + OpMemberDecorate %type_View 38 ColMajor + OpMemberDecorate %type_View 39 Offset 1392 + OpMemberDecorate %type_View 39 MatrixStride 16 + OpMemberDecorate %type_View 39 ColMajor + OpMemberDecorate %type_View 40 Offset 1456 + OpMemberDecorate %type_View 40 MatrixStride 16 + OpMemberDecorate %type_View 40 ColMajor + OpMemberDecorate %type_View 41 Offset 1520 + OpMemberDecorate %type_View 41 MatrixStride 16 + OpMemberDecorate %type_View 41 ColMajor + OpMemberDecorate %type_View 42 Offset 1584 + OpMemberDecorate %type_View 42 MatrixStride 16 + OpMemberDecorate %type_View 42 ColMajor + OpMemberDecorate %type_View 43 Offset 1648 + OpMemberDecorate %type_View 44 Offset 1660 + OpMemberDecorate %type_View 45 Offset 1664 + OpMemberDecorate %type_View 46 Offset 1676 + OpMemberDecorate %type_View 47 Offset 1680 + OpMemberDecorate %type_View 48 Offset 1692 + OpMemberDecorate %type_View 49 Offset 1696 + OpMemberDecorate %type_View 49 MatrixStride 16 + OpMemberDecorate %type_View 49 ColMajor + OpMemberDecorate %type_View 50 Offset 1760 + OpMemberDecorate %type_View 50 MatrixStride 16 + OpMemberDecorate %type_View 50 ColMajor + OpMemberDecorate %type_View 51 Offset 1824 + OpMemberDecorate %type_View 51 MatrixStride 16 + OpMemberDecorate %type_View 51 ColMajor + OpMemberDecorate %type_View 52 Offset 1888 + OpMemberDecorate %type_View 53 Offset 1904 + OpMemberDecorate %type_View 54 Offset 1920 + OpMemberDecorate %type_View 55 Offset 1928 + OpMemberDecorate %type_View 56 Offset 1936 + OpMemberDecorate %type_View 57 Offset 1952 + OpMemberDecorate %type_View 58 Offset 1968 + OpMemberDecorate %type_View 59 Offset 1984 + OpMemberDecorate %type_View 60 Offset 2000 + OpMemberDecorate %type_View 61 Offset 2004 + OpMemberDecorate %type_View 62 Offset 2008 + OpMemberDecorate %type_View 63 Offset 2012 + OpMemberDecorate %type_View 64 Offset 2016 + OpMemberDecorate %type_View 65 Offset 2032 + OpMemberDecorate %type_View 66 Offset 2048 + OpMemberDecorate %type_View 67 Offset 2064 + OpMemberDecorate %type_View 68 Offset 2072 + OpMemberDecorate %type_View 69 Offset 2076 + OpMemberDecorate %type_View 70 Offset 2080 + OpMemberDecorate %type_View 71 Offset 2084 + OpMemberDecorate %type_View 72 Offset 2088 + OpMemberDecorate %type_View 73 Offset 2092 + OpMemberDecorate %type_View 74 Offset 2096 + OpMemberDecorate %type_View 75 Offset 2108 + OpMemberDecorate %type_View 76 Offset 2112 + OpMemberDecorate %type_View 77 Offset 2116 + OpMemberDecorate %type_View 78 Offset 2120 + OpMemberDecorate %type_View 79 Offset 2124 + OpMemberDecorate %type_View 80 Offset 2128 + OpMemberDecorate %type_View 81 Offset 2132 + OpMemberDecorate %type_View 82 Offset 2136 + OpMemberDecorate %type_View 83 Offset 2140 + OpMemberDecorate %type_View 84 Offset 2144 + OpMemberDecorate %type_View 85 Offset 2148 + OpMemberDecorate %type_View 86 Offset 2152 + OpMemberDecorate %type_View 87 Offset 2156 + OpMemberDecorate %type_View 88 Offset 2160 + OpMemberDecorate %type_View 89 Offset 2164 + OpMemberDecorate %type_View 90 Offset 2168 + OpMemberDecorate %type_View 91 Offset 2172 + OpMemberDecorate %type_View 92 Offset 2176 + OpMemberDecorate %type_View 93 Offset 2192 + OpMemberDecorate %type_View 94 Offset 2204 + OpMemberDecorate %type_View 95 Offset 2208 + OpMemberDecorate %type_View 96 Offset 2240 + OpMemberDecorate %type_View 97 Offset 2272 + OpMemberDecorate %type_View 98 Offset 2288 + OpMemberDecorate %type_View 99 Offset 2304 + OpMemberDecorate %type_View 100 Offset 2308 + OpMemberDecorate %type_View 101 Offset 2312 + OpMemberDecorate %type_View 102 Offset 2316 + OpMemberDecorate %type_View 103 Offset 2320 + OpMemberDecorate %type_View 104 Offset 2324 + OpMemberDecorate %type_View 105 Offset 2328 + OpMemberDecorate %type_View 106 Offset 2332 + OpMemberDecorate %type_View 107 Offset 2336 + OpMemberDecorate %type_View 108 Offset 2340 + OpMemberDecorate %type_View 109 Offset 2344 + OpMemberDecorate %type_View 110 Offset 2348 + OpMemberDecorate %type_View 111 Offset 2352 + OpMemberDecorate %type_View 112 Offset 2364 + OpMemberDecorate %type_View 113 Offset 2368 + OpMemberDecorate %type_View 114 Offset 2380 + OpMemberDecorate %type_View 115 Offset 2384 + OpMemberDecorate %type_View 116 Offset 2388 + OpMemberDecorate %type_View 117 Offset 2392 + OpMemberDecorate %type_View 118 Offset 2396 + OpMemberDecorate %type_View 119 Offset 2400 + OpMemberDecorate %type_View 120 Offset 2404 + OpMemberDecorate %type_View 121 Offset 2408 + OpMemberDecorate %type_View 122 Offset 2412 + OpMemberDecorate %type_View 123 Offset 2416 + OpMemberDecorate %type_View 124 Offset 2420 + OpMemberDecorate %type_View 125 Offset 2424 + OpMemberDecorate %type_View 126 Offset 2428 + OpMemberDecorate %type_View 127 Offset 2432 + OpMemberDecorate %type_View 128 Offset 2448 + OpMemberDecorate %type_View 129 Offset 2460 + OpMemberDecorate %type_View 130 Offset 2464 + OpMemberDecorate %type_View 131 Offset 2480 + OpMemberDecorate %type_View 132 Offset 2484 + OpMemberDecorate %type_View 133 Offset 2488 + OpMemberDecorate %type_View 134 Offset 2492 + OpMemberDecorate %type_View 135 Offset 2496 + OpMemberDecorate %type_View 136 Offset 2512 + OpMemberDecorate %type_View 137 Offset 2624 + OpMemberDecorate %type_View 138 Offset 2628 + OpMemberDecorate %type_View 139 Offset 2632 + OpMemberDecorate %type_View 140 Offset 2636 + OpMemberDecorate %type_View 141 Offset 2640 + OpMemberDecorate %type_View 142 Offset 2644 + OpMemberDecorate %type_View 143 Offset 2648 + OpMemberDecorate %type_View 144 Offset 2652 + OpMemberDecorate %type_View 145 Offset 2656 + OpMemberDecorate %type_View 146 Offset 2668 + OpMemberDecorate %type_View 147 Offset 2672 + OpMemberDecorate %type_View 148 Offset 2736 + OpMemberDecorate %type_View 149 Offset 2800 + OpMemberDecorate %type_View 150 Offset 2804 + OpMemberDecorate %type_View 151 Offset 2808 + OpMemberDecorate %type_View 152 Offset 2812 + OpMemberDecorate %type_View 153 Offset 2816 + OpMemberDecorate %type_View 154 Offset 2828 + OpMemberDecorate %type_View 155 Offset 2832 + OpMemberDecorate %type_View 156 Offset 2844 + OpMemberDecorate %type_View 157 Offset 2848 + OpMemberDecorate %type_View 158 Offset 2856 + OpMemberDecorate %type_View 159 Offset 2860 + OpMemberDecorate %type_View 160 Offset 2864 + OpMemberDecorate %type_View 161 Offset 2876 + OpMemberDecorate %type_View 162 Offset 2880 + OpMemberDecorate %type_View 163 Offset 2892 + OpMemberDecorate %type_View 164 Offset 2896 + OpMemberDecorate %type_View 165 Offset 2908 + OpMemberDecorate %type_View 166 Offset 2912 + OpMemberDecorate %type_View 167 Offset 2924 + OpMemberDecorate %type_View 168 Offset 2928 + OpMemberDecorate %type_View 169 Offset 2932 + OpDecorate %type_View Block + OpDecorate %_arr_mat4v4float_uint_6 ArrayStride 64 + OpMemberDecorate %type__Globals 0 Offset 0 + OpMemberDecorate %type__Globals 1 Offset 16 + OpMemberDecorate %type__Globals 1 MatrixStride 16 + OpMemberDecorate %type__Globals 1 ColMajor + OpMemberDecorate %type__Globals 2 Offset 400 + OpMemberDecorate %type__Globals 3 Offset 404 + OpMemberDecorate %type__Globals 4 Offset 408 + OpMemberDecorate %type__Globals 5 Offset 416 + OpMemberDecorate %type__Globals 6 Offset 432 + OpMemberDecorate %type__Globals 7 Offset 448 + OpDecorate %type__Globals Block + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 +%mat4v4float = OpTypeMatrix %v4float 4 + %v3float = OpTypeVector %float 3 + %v2float = OpTypeVector %float 2 + %int = OpTypeInt 32 1 + %uint = OpTypeInt 32 0 + %uint_2 = OpConstant %uint 2 + %uint_7 = OpConstant %uint 7 + %uint_4 = OpConstant %uint 4 + %float_0 = OpConstant %float 0 + %float_2_5 = OpConstant %float 2.5 +%float_2_37764096 = OpConstant %float 2.37764096 +%float_0_772542 = OpConstant %float 0.772542 +%float_1_46946299 = OpConstant %float 1.46946299 +%float_n2_02254295 = OpConstant %float -2.02254295 +%float_n1_46946299 = OpConstant %float -1.46946299 +%float_n2_022542 = OpConstant %float -2.022542 +%float_n2_37764096 = OpConstant %float -2.37764096 +%float_0_772543013 = OpConstant %float 0.772543013 + %float_1 = OpConstant %float 1 + %int_0 = OpConstant %int 0 + %int_1 = OpConstant %int 1 + %int_3 = OpConstant %int 3 + %int_7 = OpConstant %int 7 + %int_58 = OpConstant %int 58 + %int_24 = OpConstant %int 24 + %int_11 = OpConstant %int 11 + %int_5 = OpConstant %int 5 + %float_0_5 = OpConstant %float 0.5 + %int_4 = OpConstant %int 4 + %int_2 = OpConstant %int 2 + %62 = OpConstantComposite %v3float %float_1 %float_1 %float_1 + %bool = OpTypeBool + %uint_5 = OpConstant %uint 5 + %65 = OpConstantComposite %v3float %float_0 %float_0 %float_1 + %66 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0 + %float_10 = OpConstant %float 10 + %float_5 = OpConstant %float 5 + %uint_0 = OpConstant %uint 0 + %int_23 = OpConstant %int 23 + %uint_1 = OpConstant %uint 1 + %uint_3 = OpConstant %uint 3 + %uint_16 = OpConstant %uint 16 +%float_0_150000006 = OpConstant %float 0.150000006 + %float_0_25 = OpConstant %float 0.25 + %float_2 = OpConstant %float 2 + %77 = OpConstantComposite %v3float %float_2 %float_2 %float_2 + %float_255 = OpConstant %float 255 + %uint_15 = OpConstant %uint 15 +%uint_4294967280 = OpConstant %uint 4294967280 +%_arr_v4float_uint_2 = OpTypeArray %v4float %uint_2 +%_arr_v4float_uint_7 = OpTypeArray %v4float %uint_7 +%_arr_v4float_uint_4 = OpTypeArray %v4float %uint_4 + %type_View = OpTypeStruct %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %v3float %float %v3float %float %v3float %float %v3float %float %v3float %float %v4float %v4float %v3float %float %v3float %float %v3float %float %v3float %float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %v3float %float %v3float %float %v3float %float %mat4v4float %mat4v4float %mat4v4float %v4float %v4float %v2float %v2float %v4float %v4float %v4float %v4float %int %float %float %float %v4float %v4float %v4float %v2float %float %float %float %float %float %float %v3float %float %float %float %float %float %float %float %float %uint %uint %uint %uint %float %float %float %float %float %v4float %v3float %float %_arr_v4float_uint_2 %_arr_v4float_uint_2 %v4float %v4float %float %float %float %float %float %float %float %float %float %float %float %float %v3float %float %v3float %float %float %float %float %float %float %float %float %float %float %float %uint %uint %v4float %v3float %float %v4float %float %float %float %float %v4float %_arr_v4float_uint_7 %float %float %float %float %uint %float %float %float %v3float %int %_arr_v4float_uint_4 %_arr_v4float_uint_4 %float %float %float %float %v3float %float %v3float %float %v2float %float %float %v3float %float %v3float %float %v3float %float %v3float %float %float %float +%_ptr_Uniform_type_View = OpTypePointer Uniform %type_View +%type_2d_image = OpTypeImage %float 2D 2 0 0 1 Unknown +%_ptr_UniformConstant_type_2d_image = OpTypePointer UniformConstant %type_2d_image +%type_sampler = OpTypeSampler +%_ptr_UniformConstant_type_sampler = OpTypePointer UniformConstant %type_sampler + %uint_6 = OpConstant %uint 6 +%_arr_mat4v4float_uint_6 = OpTypeArray %mat4v4float %uint_6 +%type__Globals = OpTypeStruct %v3float %_arr_mat4v4float_uint_6 %float %float %float %v4float %v2float %v4float +%_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals +%type_cube_image = OpTypeImage %float Cube 2 0 0 1 Unknown +%_ptr_UniformConstant_type_cube_image = OpTypePointer UniformConstant %type_cube_image + %v2int = OpTypeVector %int 2 +%_ptr_Input_v4float = OpTypePointer Input %v4float +%_ptr_Output_v4float = OpTypePointer Output %v4float + %void = OpTypeVoid + %91 = OpTypeFunction %void +%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float +%_ptr_Uniform_mat4v4float = OpTypePointer Uniform %mat4v4float +%_ptr_Uniform_float = OpTypePointer Uniform %float +%type_sampled_image = OpTypeSampledImage %type_cube_image + %v3int = OpTypeVector %int 3 +%type_sampled_image_0 = OpTypeSampledImage %type_2d_image + %v4bool = OpTypeVector %bool 4 + %View = OpVariable %_ptr_Uniform_type_View Uniform +%SceneTexturesStruct_SceneDepthTexture = OpVariable %_ptr_UniformConstant_type_2d_image UniformConstant +%SceneTexturesStruct_SceneDepthTextureSampler = OpVariable %_ptr_UniformConstant_type_sampler UniformConstant +%SceneTexturesStruct_GBufferATexture = OpVariable %_ptr_UniformConstant_type_2d_image UniformConstant +%SceneTexturesStruct_GBufferBTexture = OpVariable %_ptr_UniformConstant_type_2d_image UniformConstant +%SceneTexturesStruct_GBufferDTexture = OpVariable %_ptr_UniformConstant_type_2d_image UniformConstant +%SceneTexturesStruct_GBufferATextureSampler = OpVariable %_ptr_UniformConstant_type_sampler UniformConstant +%SceneTexturesStruct_GBufferBTextureSampler = OpVariable %_ptr_UniformConstant_type_sampler UniformConstant +%SceneTexturesStruct_GBufferDTextureSampler = OpVariable %_ptr_UniformConstant_type_sampler UniformConstant +%ShadowDepthTextureSampler = OpVariable %_ptr_UniformConstant_type_sampler UniformConstant + %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform +%ShadowDepthCubeTexture = OpVariable %_ptr_UniformConstant_type_cube_image UniformConstant +%ShadowDepthCubeTextureSampler = OpVariable %_ptr_UniformConstant_type_sampler UniformConstant +%SSProfilesTexture = OpVariable %_ptr_UniformConstant_type_2d_image UniformConstant +%gl_FragCoord = OpVariable %_ptr_Input_v4float Input +%out_var_SV_Target0 = OpVariable %_ptr_Output_v4float Output +%float_0_200000003 = OpConstant %float 0.200000003 + %98 = OpConstantComposite %v3float %float_2_5 %float_2_5 %float_2_5 + %99 = OpConstantComposite %v3float %float_2_37764096 %float_2_37764096 %float_2_37764096 + %100 = OpConstantComposite %v3float %float_0_772542 %float_0_772542 %float_0_772542 + %101 = OpConstantComposite %v3float %float_1_46946299 %float_1_46946299 %float_1_46946299 + %102 = OpConstantComposite %v3float %float_n2_02254295 %float_n2_02254295 %float_n2_02254295 + %103 = OpConstantComposite %v3float %float_n1_46946299 %float_n1_46946299 %float_n1_46946299 + %104 = OpConstantComposite %v3float %float_n2_022542 %float_n2_022542 %float_n2_022542 + %105 = OpConstantComposite %v3float %float_n2_37764096 %float_n2_37764096 %float_n2_37764096 + %106 = OpConstantComposite %v3float %float_0_772543013 %float_0_772543013 %float_0_772543013 + %107 = OpUndef %v4float +%MainOnePassPointLightPS = OpFunction %void None %91 + %108 = OpLabel + %109 = OpLoad %v4float %gl_FragCoord + %110 = OpVectorShuffle %v2float %109 %109 0 1 + %111 = OpAccessChain %_ptr_Uniform_v4float %View %int_58 + %112 = OpLoad %v4float %111 + %113 = OpVectorShuffle %v2float %112 %112 2 3 + %114 = OpFMul %v2float %110 %113 + %115 = OpLoad %type_2d_image %SceneTexturesStruct_SceneDepthTexture + %116 = OpLoad %type_sampler %SceneTexturesStruct_SceneDepthTextureSampler + %117 = OpSampledImage %type_sampled_image_0 %115 %116 + %118 = OpImageSampleExplicitLod %v4float %117 %114 Lod %float_0 + %119 = OpCompositeExtract %float %118 0 + %120 = OpAccessChain %_ptr_Uniform_float %View %int_23 %uint_0 + %121 = OpLoad %float %120 + %122 = OpFMul %float %119 %121 + %123 = OpAccessChain %_ptr_Uniform_float %View %int_23 %uint_1 + %124 = OpLoad %float %123 + %125 = OpFAdd %float %122 %124 + %126 = OpAccessChain %_ptr_Uniform_float %View %int_23 %uint_2 + %127 = OpLoad %float %126 + %128 = OpFMul %float %119 %127 + %129 = OpAccessChain %_ptr_Uniform_float %View %int_23 %uint_3 + %130 = OpLoad %float %129 + %131 = OpFSub %float %128 %130 + %132 = OpFDiv %float %float_1 %131 + %133 = OpFAdd %float %125 %132 + %134 = OpAccessChain %_ptr_Uniform_v4float %View %int_24 + %135 = OpLoad %v4float %134 + %136 = OpVectorShuffle %v2float %135 %135 3 2 + %137 = OpFSub %v2float %114 %136 + %138 = OpVectorShuffle %v2float %135 %135 0 1 + %139 = OpFDiv %v2float %137 %138 + %140 = OpCompositeConstruct %v2float %133 %133 + %141 = OpFMul %v2float %139 %140 + %142 = OpCompositeExtract %float %141 0 + %143 = OpCompositeExtract %float %141 1 + %144 = OpCompositeConstruct %v4float %142 %143 %133 %float_1 + %145 = OpAccessChain %_ptr_Uniform_mat4v4float %View %int_11 + %146 = OpLoad %mat4v4float %145 + %147 = OpMatrixTimesVector %v4float %146 %144 + %148 = OpVectorShuffle %v3float %147 %147 0 1 2 + %149 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_5 + %150 = OpLoad %v4float %149 + %151 = OpVectorShuffle %v3float %150 %150 0 1 2 + %152 = OpFSub %v3float %151 %148 + %153 = OpAccessChain %_ptr_Uniform_float %_Globals %int_5 %int_3 + %154 = OpLoad %float %153 + %155 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_7 + %156 = OpAccessChain %_ptr_Uniform_float %_Globals %int_7 %int_0 + %157 = OpLoad %float %156 + %158 = OpExtInst %float %1 Length %152 + %159 = OpFMul %float %158 %154 + %160 = OpFOrdLessThan %bool %159 %float_1 + OpSelectionMerge %161 DontFlatten + OpBranchConditional %160 %162 %161 + %162 = OpLabel + %163 = OpCompositeConstruct %v3float %158 %158 %158 + %164 = OpFDiv %v3float %152 %163 + %165 = OpExtInst %v3float %1 FAbs %152 + %166 = OpCompositeExtract %float %165 0 + %167 = OpCompositeExtract %float %165 1 + %168 = OpCompositeExtract %float %165 2 + %169 = OpExtInst %float %1 FMax %167 %168 + %170 = OpExtInst %float %1 FMax %166 %169 + %171 = OpFOrdEqual %bool %170 %166 + OpSelectionMerge %172 None + OpBranchConditional %171 %173 %174 + %174 = OpLabel + %175 = OpFOrdEqual %bool %170 %167 + OpSelectionMerge %176 None + OpBranchConditional %175 %177 %178 + %178 = OpLabel + %179 = OpCompositeExtract %float %152 2 + %180 = OpFOrdEqual %bool %168 %179 + %181 = OpSelect %int %180 %int_4 %int_5 + OpBranch %176 + %177 = OpLabel + %182 = OpCompositeExtract %float %152 1 + %183 = OpFOrdEqual %bool %167 %182 + %184 = OpSelect %int %183 %int_2 %int_3 + OpBranch %176 + %176 = OpLabel + %185 = OpPhi %int %184 %177 %181 %178 + OpBranch %172 + %173 = OpLabel + %186 = OpCompositeExtract %float %152 0 + %187 = OpFOrdEqual %bool %166 %186 + %188 = OpSelect %int %187 %int_0 %int_1 + OpBranch %172 + %172 = OpLabel + %189 = OpPhi %int %188 %173 %185 %176 + %190 = OpCompositeExtract %float %147 0 + %191 = OpCompositeExtract %float %147 1 + %192 = OpCompositeExtract %float %147 2 + %193 = OpCompositeConstruct %v4float %190 %191 %192 %float_1 + %194 = OpAccessChain %_ptr_Uniform_mat4v4float %_Globals %int_1 %189 + %195 = OpLoad %mat4v4float %194 + %196 = OpMatrixTimesVector %v4float %195 %193 + %197 = OpCompositeExtract %float %196 2 + %198 = OpCompositeExtract %float %196 3 + %199 = OpFDiv %float %197 %198 + %200 = OpFNegate %float %157 + %201 = OpFDiv %float %200 %198 + %202 = OpLoad %type_cube_image %ShadowDepthCubeTexture + %203 = OpLoad %type_sampler %ShadowDepthCubeTextureSampler + %204 = OpFAdd %float %199 %201 + %205 = OpSampledImage %type_sampled_image %202 %203 + %206 = OpImageSampleDrefExplicitLod %float %205 %164 %204 Lod %float_0 + OpBranch %161 + %161 = OpLabel + %207 = OpPhi %float %float_1 %108 %206 %172 + %208 = OpFSub %float %207 %float_0_5 + %209 = OpAccessChain %_ptr_Uniform_float %_Globals %int_4 + %210 = OpLoad %float %209 + %211 = OpFMul %float %208 %210 + %212 = OpFAdd %float %211 %float_0_5 + %213 = OpExtInst %float %1 FClamp %212 %float_0 %float_1 + %214 = OpFMul %float %213 %213 + %215 = OpAccessChain %_ptr_Uniform_float %_Globals %int_3 + %216 = OpLoad %float %215 + %217 = OpExtInst %float %1 FMix %float_1 %214 %216 + %218 = OpExtInst %float %1 Sqrt %217 + %219 = OpCompositeInsert %v4float %218 %107 2 + %220 = OpVectorShuffle %v4float %219 %62 4 5 2 6 + %221 = OpLoad %type_2d_image %SceneTexturesStruct_GBufferATexture + %222 = OpLoad %type_sampler %SceneTexturesStruct_GBufferATextureSampler + %223 = OpSampledImage %type_sampled_image_0 %221 %222 + %224 = OpImageSampleExplicitLod %v4float %223 %114 Lod %float_0 + %225 = OpLoad %type_2d_image %SceneTexturesStruct_GBufferBTexture + %226 = OpLoad %type_sampler %SceneTexturesStruct_GBufferBTextureSampler + %227 = OpSampledImage %type_sampled_image_0 %225 %226 + %228 = OpImageSampleExplicitLod %v4float %227 %114 Lod %float_0 + %229 = OpLoad %type_2d_image %SceneTexturesStruct_GBufferDTexture + %230 = OpLoad %type_sampler %SceneTexturesStruct_GBufferDTextureSampler + %231 = OpSampledImage %type_sampled_image_0 %229 %230 + %232 = OpImageSampleExplicitLod %v4float %231 %114 Lod %float_0 + %233 = OpVectorShuffle %v3float %224 %224 0 1 2 + %234 = OpFMul %v3float %233 %77 + %235 = OpFSub %v3float %234 %62 + %236 = OpExtInst %v3float %1 Normalize %235 + %237 = OpCompositeExtract %float %228 3 + %238 = OpFMul %float %237 %float_255 + %239 = OpExtInst %float %1 Round %238 + %240 = OpConvertFToU %uint %239 + %241 = OpBitwiseAnd %uint %240 %uint_15 + %242 = OpBitwiseAnd %uint %240 %uint_4294967280 + %243 = OpBitwiseAnd %uint %242 %uint_16 + %244 = OpINotEqual %bool %243 %uint_0 + %245 = OpLogicalNot %bool %244 + %246 = OpCompositeConstruct %v4bool %245 %245 %245 %245 + %247 = OpSelect %v4float %246 %232 %66 + %248 = OpIEqual %bool %241 %uint_5 + OpSelectionMerge %249 None + OpBranchConditional %248 %250 %249 + %250 = OpLabel + %251 = OpLoad %v4float %155 + %252 = OpCompositeExtract %float %247 0 + %253 = OpFMul %float %252 %float_255 + %254 = OpFAdd %float %253 %float_0_5 + %255 = OpConvertFToU %uint %254 + %256 = OpBitcast %int %255 + %257 = OpCompositeConstruct %v3int %int_1 %256 %int_0 + %258 = OpVectorShuffle %v2int %257 %257 0 1 + %259 = OpLoad %type_2d_image %SSProfilesTexture + %260 = OpImageFetch %v4float %259 %258 Lod %int_0 + %261 = OpCompositeExtract %float %260 0 + %262 = OpCompositeExtract %float %260 1 + %263 = OpFMul %float %262 %float_0_5 + %264 = OpCompositeConstruct %v3float %263 %263 %263 + %265 = OpFMul %v3float %236 %264 + %266 = OpFSub %v3float %148 %265 + %267 = OpDot %float %152 %152 + %268 = OpExtInst %float %1 InverseSqrt %267 + %269 = OpCompositeConstruct %v3float %268 %268 %268 + %270 = OpFMul %v3float %152 %269 + %271 = OpFNegate %v3float %270 + %272 = OpDot %float %271 %236 + %273 = OpExtInst %float %1 FClamp %272 %float_0 %float_1 + %274 = OpExtInst %float %1 Pow %273 %float_1 + OpSelectionMerge %275 DontFlatten + OpBranchConditional %160 %276 %275 + %276 = OpLabel + %277 = OpCompositeConstruct %v3float %158 %158 %158 + %278 = OpFDiv %v3float %152 %277 + %279 = OpExtInst %v3float %1 Cross %278 %65 + %280 = OpExtInst %v3float %1 Normalize %279 + %281 = OpExtInst %v3float %1 Cross %280 %278 + %282 = OpAccessChain %_ptr_Uniform_float %_Globals %int_2 + %283 = OpLoad %float %282 + %284 = OpCompositeConstruct %v3float %283 %283 %283 + %285 = OpFMul %v3float %280 %284 + %286 = OpFMul %v3float %281 %284 + %287 = OpExtInst %v3float %1 FAbs %278 + %288 = OpCompositeExtract %float %287 0 + %289 = OpCompositeExtract %float %287 1 + %290 = OpCompositeExtract %float %287 2 + %291 = OpExtInst %float %1 FMax %289 %290 + %292 = OpExtInst %float %1 FMax %288 %291 + %293 = OpFOrdEqual %bool %292 %288 + OpSelectionMerge %294 None + OpBranchConditional %293 %295 %296 + %296 = OpLabel + %297 = OpFOrdEqual %bool %292 %289 + OpSelectionMerge %298 None + OpBranchConditional %297 %299 %300 + %300 = OpLabel + %301 = OpCompositeExtract %float %278 2 + %302 = OpFOrdEqual %bool %290 %301 + %303 = OpSelect %int %302 %int_4 %int_5 + OpBranch %298 + %299 = OpLabel + %304 = OpCompositeExtract %float %278 1 + %305 = OpFOrdEqual %bool %289 %304 + %306 = OpSelect %int %305 %int_2 %int_3 + OpBranch %298 + %298 = OpLabel + %307 = OpPhi %int %306 %299 %303 %300 + OpBranch %294 + %295 = OpLabel + %308 = OpCompositeExtract %float %278 0 + %309 = OpFOrdEqual %bool %288 %308 + %310 = OpSelect %int %309 %int_0 %int_1 + OpBranch %294 + %294 = OpLabel + %311 = OpPhi %int %310 %295 %307 %298 + %312 = OpCompositeExtract %float %266 0 + %313 = OpCompositeExtract %float %266 1 + %314 = OpCompositeExtract %float %266 2 + %315 = OpCompositeConstruct %v4float %312 %313 %314 %float_1 + %316 = OpAccessChain %_ptr_Uniform_mat4v4float %_Globals %int_1 %311 + %317 = OpLoad %mat4v4float %316 + %318 = OpMatrixTimesVector %v4float %317 %315 + %319 = OpCompositeExtract %float %318 2 + %320 = OpCompositeExtract %float %318 3 + %321 = OpFDiv %float %319 %320 + %322 = OpFDiv %float %float_10 %154 + %323 = OpFMul %float %261 %322 + %324 = OpCompositeExtract %float %251 2 + %325 = OpFMul %float %321 %324 + %326 = OpCompositeExtract %float %251 3 + %327 = OpFSub %float %325 %326 + %328 = OpFDiv %float %float_1 %327 + %329 = OpFMul %float %328 %154 + %330 = OpFMul %v3float %286 %98 + %331 = OpFAdd %v3float %278 %330 + %332 = OpLoad %type_cube_image %ShadowDepthCubeTexture + %333 = OpLoad %type_sampler %ShadowDepthTextureSampler + %334 = OpSampledImage %type_sampled_image %332 %333 + %335 = OpImageSampleExplicitLod %v4float %334 %331 Lod %float_0 + %336 = OpCompositeExtract %float %335 0 + %337 = OpFMul %float %336 %324 + %338 = OpFSub %float %337 %326 + %339 = OpFDiv %float %float_1 %338 + %340 = OpFMul %float %339 %154 + %341 = OpFSub %float %329 %340 + %342 = OpFMul %float %341 %323 + %343 = OpFOrdGreaterThan %bool %342 %float_0 + %344 = OpFAdd %float %342 %263 + %345 = OpFMul %float %342 %274 + %346 = OpFAdd %float %345 %263 + %347 = OpExtInst %float %1 FMax %float_0 %346 + %348 = OpSelect %float %343 %344 %347 + %349 = OpExtInst %float %1 FAbs %348 + %350 = OpExtInst %float %1 FClamp %349 %float_0_150000006 %float_5 + %351 = OpFAdd %float %350 %float_0_25 + %352 = OpFMul %v3float %285 %99 + %353 = OpFAdd %v3float %278 %352 + %354 = OpFMul %v3float %286 %100 + %355 = OpFAdd %v3float %353 %354 + %356 = OpSampledImage %type_sampled_image %332 %333 + %357 = OpImageSampleExplicitLod %v4float %356 %355 Lod %float_0 + %358 = OpCompositeExtract %float %357 0 + %359 = OpFMul %float %358 %324 + %360 = OpFSub %float %359 %326 + %361 = OpFDiv %float %float_1 %360 + %362 = OpFMul %float %361 %154 + %363 = OpFSub %float %329 %362 + %364 = OpFMul %float %363 %323 + %365 = OpFOrdGreaterThan %bool %364 %float_0 + %366 = OpFAdd %float %364 %263 + %367 = OpFMul %float %364 %274 + %368 = OpFAdd %float %367 %263 + %369 = OpExtInst %float %1 FMax %float_0 %368 + %370 = OpSelect %float %365 %366 %369 + %371 = OpExtInst %float %1 FAbs %370 + %372 = OpExtInst %float %1 FClamp %371 %float_0_150000006 %float_5 + %373 = OpFAdd %float %372 %float_0_25 + %374 = OpFAdd %float %351 %373 + %375 = OpFMul %v3float %285 %101 + %376 = OpFAdd %v3float %278 %375 + %377 = OpFMul %v3float %286 %102 + %378 = OpFAdd %v3float %376 %377 + %379 = OpSampledImage %type_sampled_image %332 %333 + %380 = OpImageSampleExplicitLod %v4float %379 %378 Lod %float_0 + %381 = OpCompositeExtract %float %380 0 + %382 = OpFMul %float %381 %324 + %383 = OpFSub %float %382 %326 + %384 = OpFDiv %float %float_1 %383 + %385 = OpFMul %float %384 %154 + %386 = OpFSub %float %329 %385 + %387 = OpFMul %float %386 %323 + %388 = OpFOrdGreaterThan %bool %387 %float_0 + %389 = OpFAdd %float %387 %263 + %390 = OpFMul %float %387 %274 + %391 = OpFAdd %float %390 %263 + %392 = OpExtInst %float %1 FMax %float_0 %391 + %393 = OpSelect %float %388 %389 %392 + %394 = OpExtInst %float %1 FAbs %393 + %395 = OpExtInst %float %1 FClamp %394 %float_0_150000006 %float_5 + %396 = OpFAdd %float %395 %float_0_25 + %397 = OpFAdd %float %374 %396 + %398 = OpFMul %v3float %285 %103 + %399 = OpFAdd %v3float %278 %398 + %400 = OpFMul %v3float %286 %104 + %401 = OpFAdd %v3float %399 %400 + %402 = OpSampledImage %type_sampled_image %332 %333 + %403 = OpImageSampleExplicitLod %v4float %402 %401 Lod %float_0 + %404 = OpCompositeExtract %float %403 0 + %405 = OpFMul %float %404 %324 + %406 = OpFSub %float %405 %326 + %407 = OpFDiv %float %float_1 %406 + %408 = OpFMul %float %407 %154 + %409 = OpFSub %float %329 %408 + %410 = OpFMul %float %409 %323 + %411 = OpFOrdGreaterThan %bool %410 %float_0 + %412 = OpFAdd %float %410 %263 + %413 = OpFMul %float %410 %274 + %414 = OpFAdd %float %413 %263 + %415 = OpExtInst %float %1 FMax %float_0 %414 + %416 = OpSelect %float %411 %412 %415 + %417 = OpExtInst %float %1 FAbs %416 + %418 = OpExtInst %float %1 FClamp %417 %float_0_150000006 %float_5 + %419 = OpFAdd %float %418 %float_0_25 + %420 = OpFAdd %float %397 %419 + %421 = OpFMul %v3float %285 %105 + %422 = OpFAdd %v3float %278 %421 + %423 = OpFMul %v3float %286 %106 + %424 = OpFAdd %v3float %422 %423 + %425 = OpSampledImage %type_sampled_image %332 %333 + %426 = OpImageSampleExplicitLod %v4float %425 %424 Lod %float_0 + %427 = OpCompositeExtract %float %426 0 + %428 = OpFMul %float %427 %324 + %429 = OpFSub %float %428 %326 + %430 = OpFDiv %float %float_1 %429 + %431 = OpFMul %float %430 %154 + %432 = OpFSub %float %329 %431 + %433 = OpFMul %float %432 %323 + %434 = OpFOrdGreaterThan %bool %433 %float_0 + %435 = OpFAdd %float %433 %263 + %436 = OpFMul %float %433 %274 + %437 = OpFAdd %float %436 %263 + %438 = OpExtInst %float %1 FMax %float_0 %437 + %439 = OpSelect %float %434 %435 %438 + %440 = OpExtInst %float %1 FAbs %439 + %441 = OpExtInst %float %1 FClamp %440 %float_0_150000006 %float_5 + %442 = OpFAdd %float %441 %float_0_25 + %443 = OpFAdd %float %420 %442 + %444 = OpFMul %float %443 %float_0_200000003 + OpBranch %275 + %275 = OpLabel + %445 = OpPhi %float %float_1 %250 %444 %294 + %446 = OpFMul %float %445 %float_0_200000003 + %447 = OpFSub %float %float_1 %446 + OpBranch %249 + %249 = OpLabel + %448 = OpPhi %float %float_1 %161 %447 %275 + %449 = OpExtInst %float %1 Sqrt %448 + %450 = OpSelect %float %248 %449 %218 + %451 = OpCompositeInsert %v4float %450 %220 3 + OpStore %out_var_SV_Target0 %451 + OpReturn + OpFunctionEnd diff --git a/third_party/spirv-cross/shaders-ue4/asm/frag/global-constant-arrays.asm.frag b/third_party/spirv-cross/shaders-ue4/asm/frag/global-constant-arrays.asm.frag new file mode 100644 index 0000000000..47db9ebc51 --- /dev/null +++ b/third_party/spirv-cross/shaders-ue4/asm/frag/global-constant-arrays.asm.frag @@ -0,0 +1,3556 @@ +; SPIR-V +; Version: 1.0 +; Generator: Google spiregg; 0 +; Bound: 3005 +; Schema: 0 + OpCapability Shader + OpCapability Geometry + OpExtension "SPV_GOOGLE_hlsl_functionality1" + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %MainPS "main" %in_var_TEXCOORD0 %gl_FragCoord %gl_Layer %out_var_SV_Target0 + OpExecutionMode %MainPS OriginUpperLeft + OpSource HLSL 600 + OpName %type__Globals "type.$Globals" + OpMemberName %type__Globals 0 "MappingPolynomial" + OpMemberName %type__Globals 1 "InverseGamma" + OpMemberName %type__Globals 2 "ColorMatrixR_ColorCurveCd1" + OpMemberName %type__Globals 3 "ColorMatrixG_ColorCurveCd3Cm3" + OpMemberName %type__Globals 4 "ColorMatrixB_ColorCurveCm2" + OpMemberName %type__Globals 5 "ColorCurve_Cm0Cd0_Cd2_Ch0Cm1_Ch3" + OpMemberName %type__Globals 6 "ColorCurve_Ch1_Ch2" + OpMemberName %type__Globals 7 "ColorShadow_Luma" + OpMemberName %type__Globals 8 "ColorShadow_Tint1" + OpMemberName %type__Globals 9 "ColorShadow_Tint2" + OpMemberName %type__Globals 10 "FilmSlope" + OpMemberName %type__Globals 11 "FilmToe" + OpMemberName %type__Globals 12 "FilmShoulder" + OpMemberName %type__Globals 13 "FilmBlackClip" + OpMemberName %type__Globals 14 "FilmWhiteClip" + OpMemberName %type__Globals 15 "ColorScale" + OpMemberName %type__Globals 16 "OverlayColor" + OpMemberName %type__Globals 17 "WhiteTemp" + OpMemberName %type__Globals 18 "WhiteTint" + OpMemberName %type__Globals 19 "ColorSaturation" + OpMemberName %type__Globals 20 "ColorContrast" + OpMemberName %type__Globals 21 "ColorGamma" + OpMemberName %type__Globals 22 "ColorGain" + OpMemberName %type__Globals 23 "ColorOffset" + OpMemberName %type__Globals 24 "ColorSaturationShadows" + OpMemberName %type__Globals 25 "ColorContrastShadows" + OpMemberName %type__Globals 26 "ColorGammaShadows" + OpMemberName %type__Globals 27 "ColorGainShadows" + OpMemberName %type__Globals 28 "ColorOffsetShadows" + OpMemberName %type__Globals 29 "ColorSaturationMidtones" + OpMemberName %type__Globals 30 "ColorContrastMidtones" + OpMemberName %type__Globals 31 "ColorGammaMidtones" + OpMemberName %type__Globals 32 "ColorGainMidtones" + OpMemberName %type__Globals 33 "ColorOffsetMidtones" + OpMemberName %type__Globals 34 "ColorSaturationHighlights" + OpMemberName %type__Globals 35 "ColorContrastHighlights" + OpMemberName %type__Globals 36 "ColorGammaHighlights" + OpMemberName %type__Globals 37 "ColorGainHighlights" + OpMemberName %type__Globals 38 "ColorOffsetHighlights" + OpMemberName %type__Globals 39 "ColorCorrectionShadowsMax" + OpMemberName %type__Globals 40 "ColorCorrectionHighlightsMin" + OpMemberName %type__Globals 41 "OutputDevice" + OpMemberName %type__Globals 42 "OutputGamut" + OpMemberName %type__Globals 43 "BlueCorrection" + OpMemberName %type__Globals 44 "ExpandGamut" + OpName %_Globals "$Globals" + OpName %in_var_TEXCOORD0 "in.var.TEXCOORD0" + OpName %out_var_SV_Target0 "out.var.SV_Target0" + OpName %MainPS "MainPS" + OpDecorateString %in_var_TEXCOORD0 UserSemantic "TEXCOORD0" + OpDecorate %in_var_TEXCOORD0 NoPerspective + OpDecorate %gl_FragCoord BuiltIn FragCoord + OpDecorateString %gl_FragCoord UserSemantic "SV_POSITION" + OpDecorate %gl_Layer BuiltIn Layer + OpDecorateString %gl_Layer UserSemantic "SV_RenderTargetArrayIndex" + OpDecorate %gl_Layer Flat + OpDecorateString %out_var_SV_Target0 UserSemantic "SV_Target0" + OpDecorate %in_var_TEXCOORD0 Location 0 + OpDecorate %out_var_SV_Target0 Location 0 + OpDecorate %_Globals DescriptorSet 0 + OpDecorate %_Globals Binding 0 + OpMemberDecorate %type__Globals 0 Offset 0 + OpMemberDecorate %type__Globals 1 Offset 16 + OpMemberDecorate %type__Globals 2 Offset 32 + OpMemberDecorate %type__Globals 3 Offset 48 + OpMemberDecorate %type__Globals 4 Offset 64 + OpMemberDecorate %type__Globals 5 Offset 80 + OpMemberDecorate %type__Globals 6 Offset 96 + OpMemberDecorate %type__Globals 7 Offset 112 + OpMemberDecorate %type__Globals 8 Offset 128 + OpMemberDecorate %type__Globals 9 Offset 144 + OpMemberDecorate %type__Globals 10 Offset 160 + OpMemberDecorate %type__Globals 11 Offset 164 + OpMemberDecorate %type__Globals 12 Offset 168 + OpMemberDecorate %type__Globals 13 Offset 172 + OpMemberDecorate %type__Globals 14 Offset 176 + OpMemberDecorate %type__Globals 15 Offset 180 + OpMemberDecorate %type__Globals 16 Offset 192 + OpMemberDecorate %type__Globals 17 Offset 208 + OpMemberDecorate %type__Globals 18 Offset 212 + OpMemberDecorate %type__Globals 19 Offset 224 + OpMemberDecorate %type__Globals 20 Offset 240 + OpMemberDecorate %type__Globals 21 Offset 256 + OpMemberDecorate %type__Globals 22 Offset 272 + OpMemberDecorate %type__Globals 23 Offset 288 + OpMemberDecorate %type__Globals 24 Offset 304 + OpMemberDecorate %type__Globals 25 Offset 320 + OpMemberDecorate %type__Globals 26 Offset 336 + OpMemberDecorate %type__Globals 27 Offset 352 + OpMemberDecorate %type__Globals 28 Offset 368 + OpMemberDecorate %type__Globals 29 Offset 384 + OpMemberDecorate %type__Globals 30 Offset 400 + OpMemberDecorate %type__Globals 31 Offset 416 + OpMemberDecorate %type__Globals 32 Offset 432 + OpMemberDecorate %type__Globals 33 Offset 448 + OpMemberDecorate %type__Globals 34 Offset 464 + OpMemberDecorate %type__Globals 35 Offset 480 + OpMemberDecorate %type__Globals 36 Offset 496 + OpMemberDecorate %type__Globals 37 Offset 512 + OpMemberDecorate %type__Globals 38 Offset 528 + OpMemberDecorate %type__Globals 39 Offset 544 + OpMemberDecorate %type__Globals 40 Offset 548 + OpMemberDecorate %type__Globals 41 Offset 552 + OpMemberDecorate %type__Globals 42 Offset 556 + OpMemberDecorate %type__Globals 43 Offset 560 + OpMemberDecorate %type__Globals 44 Offset 564 + OpDecorate %type__Globals Block + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 + %v3float = OpTypeVector %float 3 + %v2float = OpTypeVector %float 2 + %int = OpTypeInt 32 1 + %uint = OpTypeInt 32 0 + %uint_2 = OpConstant %uint 2 + %uint_7 = OpConstant %uint 7 + %uint_4 = OpConstant %uint 4 +%float_0_952552378 = OpConstant %float 0.952552378 + %float_0 = OpConstant %float 0 + +; HACK: Needed to hack this constant since MSVC and GNU libc are off by 1 ULP when converting to string (it probably still works fine though in a roundtrip ...) +%float_9_36786018en05 = OpConstant %float 9.25 + +%float_0_343966454 = OpConstant %float 0.343966454 +%float_0_728166103 = OpConstant %float 0.728166103 +%float_n0_0721325427 = OpConstant %float -0.0721325427 +%float_1_00882518 = OpConstant %float 1.00882518 +%float_1_04981101 = OpConstant %float 1.04981101 +%float_n9_74845025en05 = OpConstant %float -9.74845025e-05 +%float_n0_495903015 = OpConstant %float -0.495903015 +%float_1_37331307 = OpConstant %float 1.37331307 +%float_0_0982400328 = OpConstant %float 0.0982400328 +%float_0_991252005 = OpConstant %float 0.991252005 +%float_0_662454188 = OpConstant %float 0.662454188 +%float_0_134004205 = OpConstant %float 0.134004205 +%float_0_156187683 = OpConstant %float 0.156187683 +%float_0_272228718 = OpConstant %float 0.272228718 +%float_0_674081743 = OpConstant %float 0.674081743 +%float_0_0536895171 = OpConstant %float 0.0536895171 +%float_n0_00557464967 = OpConstant %float -0.00557464967 +%float_0_0040607336 = OpConstant %float 0.0040607336 +%float_1_01033914 = OpConstant %float 1.01033914 +%float_1_6410234 = OpConstant %float 1.6410234 +%float_n0_324803293 = OpConstant %float -0.324803293 +%float_n0_236424699 = OpConstant %float -0.236424699 +%float_n0_663662851 = OpConstant %float -0.663662851 +%float_1_61533165 = OpConstant %float 1.61533165 +%float_0_0167563483 = OpConstant %float 0.0167563483 +%float_0_0117218941 = OpConstant %float 0.0117218941 +%float_n0_00828444213 = OpConstant %float -0.00828444213 +%float_0_988394856 = OpConstant %float 0.988394856 +%float_1_45143926 = OpConstant %float 1.45143926 +%float_n0_236510754 = OpConstant %float -0.236510754 +%float_n0_214928567 = OpConstant %float -0.214928567 +%float_n0_0765537769 = OpConstant %float -0.0765537769 +%float_1_17622972 = OpConstant %float 1.17622972 +%float_n0_0996759236 = OpConstant %float -0.0996759236 +%float_0_00831614807 = OpConstant %float 0.00831614807 +%float_n0_00603244966 = OpConstant %float -0.00603244966 +%float_0_997716308 = OpConstant %float 0.997716308 +%float_0_695452213 = OpConstant %float 0.695452213 +%float_0_140678704 = OpConstant %float 0.140678704 +%float_0_163869068 = OpConstant %float 0.163869068 +%float_0_0447945632 = OpConstant %float 0.0447945632 +%float_0_859671116 = OpConstant %float 0.859671116 +%float_0_0955343172 = OpConstant %float 0.0955343172 +%float_n0_00552588282 = OpConstant %float -0.00552588282 +%float_0_00402521016 = OpConstant %float 0.00402521016 +%float_1_00150073 = OpConstant %float 1.00150073 + %67 = OpConstantComposite %v3float %float_0_272228718 %float_0_674081743 %float_0_0536895171 +%float_3_2409699 = OpConstant %float 3.2409699 +%float_n1_5373832 = OpConstant %float -1.5373832 +%float_n0_498610765 = OpConstant %float -0.498610765 +%float_n0_969243646 = OpConstant %float -0.969243646 +%float_1_8759675 = OpConstant %float 1.8759675 +%float_0_0415550582 = OpConstant %float 0.0415550582 +%float_0_0556300804 = OpConstant %float 0.0556300804 +%float_n0_203976959 = OpConstant %float -0.203976959 +%float_1_05697155 = OpConstant %float 1.05697155 +%float_0_412456393 = OpConstant %float 0.412456393 +%float_0_357576102 = OpConstant %float 0.357576102 +%float_0_180437505 = OpConstant %float 0.180437505 +%float_0_212672904 = OpConstant %float 0.212672904 +%float_0_715152204 = OpConstant %float 0.715152204 +%float_0_0721750036 = OpConstant %float 0.0721750036 +%float_0_0193339009 = OpConstant %float 0.0193339009 +%float_0_119191997 = OpConstant %float 0.119191997 +%float_0_950304091 = OpConstant %float 0.950304091 +%float_1_71660841 = OpConstant %float 1.71660841 +%float_n0_355662107 = OpConstant %float -0.355662107 +%float_n0_253360093 = OpConstant %float -0.253360093 +%float_n0_666682899 = OpConstant %float -0.666682899 +%float_1_61647761 = OpConstant %float 1.61647761 +%float_0_0157685 = OpConstant %float 0.0157685 +%float_0_0176422 = OpConstant %float 0.0176422 +%float_n0_0427763015 = OpConstant %float -0.0427763015 +%float_0_942228675 = OpConstant %float 0.942228675 +%float_2_49339628 = OpConstant %float 2.49339628 +%float_n0_93134588 = OpConstant %float -0.93134588 +%float_n0_402694494 = OpConstant %float -0.402694494 +%float_n0_829486787 = OpConstant %float -0.829486787 +%float_1_76265967 = OpConstant %float 1.76265967 +%float_0_0236246008 = OpConstant %float 0.0236246008 +%float_0_0358507 = OpConstant %float 0.0358507 +%float_n0_0761827007 = OpConstant %float -0.0761827007 +%float_0_957014024 = OpConstant %float 0.957014024 +%float_1_01303005 = OpConstant %float 1.01303005 +%float_0_00610530982 = OpConstant %float 0.00610530982 +%float_n0_0149710001 = OpConstant %float -0.0149710001 +%float_0_00769822998 = OpConstant %float 0.00769822998 +%float_0_998165011 = OpConstant %float 0.998165011 +%float_n0_00503202993 = OpConstant %float -0.00503202993 +%float_n0_00284131011 = OpConstant %float -0.00284131011 +%float_0_00468515977 = OpConstant %float 0.00468515977 +%float_0_924507022 = OpConstant %float 0.924507022 +%float_0_987223983 = OpConstant %float 0.987223983 +%float_n0_00611326983 = OpConstant %float -0.00611326983 +%float_0_0159533005 = OpConstant %float 0.0159533005 +%float_n0_00759836007 = OpConstant %float -0.00759836007 +%float_1_00186002 = OpConstant %float 1.00186002 +%float_0_0053300201 = OpConstant %float 0.0053300201 +%float_0_00307257008 = OpConstant %float 0.00307257008 +%float_n0_00509594986 = OpConstant %float -0.00509594986 +%float_1_08168006 = OpConstant %float 1.08168006 + %float_0_5 = OpConstant %float 0.5 + %float_n1 = OpConstant %float -1 + %float_1 = OpConstant %float 1 + %int_0 = OpConstant %int 0 + %int_1 = OpConstant %int 1 +%float_0_015625 = OpConstant %float 0.015625 + %128 = OpConstantComposite %v2float %float_0_015625 %float_0_015625 + %129 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0 + %int_42 = OpConstant %int 42 + %uint_3 = OpConstant %uint 3 + %132 = OpConstantComposite %v3float %float_0 %float_0 %float_0 + %int_9 = OpConstant %int 9 + %int_3 = OpConstant %int 3 + %135 = OpConstantComposite %v3float %float_1 %float_1 %float_1 + %float_n4 = OpConstant %float -4 + %int_44 = OpConstant %int 44 +%float_0_544169128 = OpConstant %float 0.544169128 +%float_0_239592597 = OpConstant %float 0.239592597 +%float_0_166694298 = OpConstant %float 0.166694298 +%float_0_239465594 = OpConstant %float 0.239465594 +%float_0_702153027 = OpConstant %float 0.702153027 +%float_0_058381401 = OpConstant %float 0.058381401 +%float_n0_00234390004 = OpConstant %float -0.00234390004 +%float_0_0361833982 = OpConstant %float 0.0361833982 +%float_1_05521834 = OpConstant %float 1.05521834 +%float_0_940437257 = OpConstant %float 0.940437257 +%float_n0_0183068793 = OpConstant %float -0.0183068793 +%float_0_077869609 = OpConstant %float 0.077869609 +%float_0_00837869663 = OpConstant %float 0.00837869663 +%float_0_828660011 = OpConstant %float 0.828660011 +%float_0_162961304 = OpConstant %float 0.162961304 +%float_0_00054712611 = OpConstant %float 0.00054712611 +%float_n0_000883374596 = OpConstant %float -0.000883374596 +%float_1_00033629 = OpConstant %float 1.00033629 +%float_1_06317997 = OpConstant %float 1.06317997 +%float_0_0233955998 = OpConstant %float 0.0233955998 +%float_n0_0865726024 = OpConstant %float -0.0865726024 +%float_n0_0106336996 = OpConstant %float -0.0106336996 +%float_1_20632005 = OpConstant %float 1.20632005 +%float_n0_195690006 = OpConstant %float -0.195690006 +%float_n0_000590886979 = OpConstant %float -0.000590886979 +%float_0_00105247996 = OpConstant %float 0.00105247996 +%float_0_999538004 = OpConstant %float 0.999538004 + %int_43 = OpConstant %int 43 + %int_15 = OpConstant %int 15 + %int_16 = OpConstant %int 16 + %uint_0 = OpConstant %uint 0 + %uint_1 = OpConstant %uint 1 + %uint_5 = OpConstant %uint 5 + %uint_6 = OpConstant %uint 6 + %int_2 = OpConstant %int 2 +%mat3v3float = OpTypeMatrix %v3float 3 + %int_41 = OpConstant %int 41 +%float_0_159301758 = OpConstant %float 0.159301758 +%float_78_84375 = OpConstant %float 78.84375 +%float_0_8359375 = OpConstant %float 0.8359375 +%float_18_8515625 = OpConstant %float 18.8515625 +%float_18_6875 = OpConstant %float 18.6875 +%float_10000 = OpConstant %float 10000 +%float_0_0126833133 = OpConstant %float 0.0126833133 + %182 = OpConstantComposite %v3float %float_0_0126833133 %float_0_0126833133 %float_0_0126833133 + %183 = OpConstantComposite %v3float %float_0_8359375 %float_0_8359375 %float_0_8359375 + %184 = OpConstantComposite %v3float %float_18_8515625 %float_18_8515625 %float_18_8515625 + %185 = OpConstantComposite %v3float %float_18_6875 %float_18_6875 %float_18_6875 +%float_6_27739477 = OpConstant %float 6.27739477 + %187 = OpConstantComposite %v3float %float_6_27739477 %float_6_27739477 %float_6_27739477 + %188 = OpConstantComposite %v3float %float_10000 %float_10000 %float_10000 + %float_14 = OpConstant %float 14 +%float_0_180000007 = OpConstant %float 0.180000007 +%float_0_434017599 = OpConstant %float 0.434017599 + %192 = OpConstantComposite %v3float %float_0_434017599 %float_0_434017599 %float_0_434017599 + %193 = OpConstantComposite %v3float %float_14 %float_14 %float_14 + %194 = OpConstantComposite %v3float %float_0_180000007 %float_0_180000007 %float_0_180000007 + %int_17 = OpConstant %int 17 + %float_4000 = OpConstant %float 4000 +%float_0_312700003 = OpConstant %float 0.312700003 +%float_0_328999996 = OpConstant %float 0.328999996 + %int_18 = OpConstant %int 18 + %int_24 = OpConstant %int 24 + %int_19 = OpConstant %int 19 + %int_25 = OpConstant %int 25 + %int_20 = OpConstant %int 20 + %int_26 = OpConstant %int 26 + %int_21 = OpConstant %int 21 + %int_27 = OpConstant %int 27 + %int_22 = OpConstant %int 22 + %int_28 = OpConstant %int 28 + %int_23 = OpConstant %int 23 + %int_39 = OpConstant %int 39 + %int_34 = OpConstant %int 34 + %int_35 = OpConstant %int 35 + %int_36 = OpConstant %int 36 + %int_37 = OpConstant %int 37 + %int_38 = OpConstant %int 38 + %int_40 = OpConstant %int 40 + %int_29 = OpConstant %int 29 + %int_30 = OpConstant %int 30 + %int_31 = OpConstant %int 31 + %int_32 = OpConstant %int 32 + %int_33 = OpConstant %int 33 +%float_0_0500000007 = OpConstant %float 0.0500000007 + %float_1_75 = OpConstant %float 1.75 +%float_0_400000006 = OpConstant %float 0.400000006 +%float_0_0299999993 = OpConstant %float 0.0299999993 + %float_2 = OpConstant %float 2 +%float_0_959999979 = OpConstant %float 0.959999979 + %228 = OpConstantComposite %v3float %float_0_959999979 %float_0_959999979 %float_0_959999979 + %int_13 = OpConstant %int 13 + %int_11 = OpConstant %int 11 + %int_14 = OpConstant %int 14 + %int_12 = OpConstant %int 12 +%float_0_800000012 = OpConstant %float 0.800000012 + %int_10 = OpConstant %int 10 + %float_10 = OpConstant %float 10 + %float_n2 = OpConstant %float -2 + %float_3 = OpConstant %float 3 + %238 = OpConstantComposite %v3float %float_3 %float_3 %float_3 + %239 = OpConstantComposite %v3float %float_2 %float_2 %float_2 +%float_0_930000007 = OpConstant %float 0.930000007 + %241 = OpConstantComposite %v3float %float_0_930000007 %float_0_930000007 %float_0_930000007 + %int_4 = OpConstant %int 4 + %int_8 = OpConstant %int 8 + %int_7 = OpConstant %int 7 + %int_5 = OpConstant %int 5 + %int_6 = OpConstant %int 6 +%float_0_00200000009 = OpConstant %float 0.00200000009 + %248 = OpConstantComposite %v3float %float_0_00200000009 %float_0_00200000009 %float_0_00200000009 +%float_6_10351999en05 = OpConstant %float 6.10351999e-05 + %250 = OpConstantComposite %v3float %float_6_10351999en05 %float_6_10351999en05 %float_6_10351999en05 + %float_4_5 = OpConstant %float 4.5 + %252 = OpConstantComposite %v3float %float_4_5 %float_4_5 %float_4_5 +%float_0_0179999992 = OpConstant %float 0.0179999992 + %254 = OpConstantComposite %v3float %float_0_0179999992 %float_0_0179999992 %float_0_0179999992 +%float_0_449999988 = OpConstant %float 0.449999988 + %256 = OpConstantComposite %v3float %float_0_449999988 %float_0_449999988 %float_0_449999988 +%float_1_09899998 = OpConstant %float 1.09899998 + %258 = OpConstantComposite %v3float %float_1_09899998 %float_1_09899998 %float_1_09899998 +%float_0_0989999995 = OpConstant %float 0.0989999995 + %260 = OpConstantComposite %v3float %float_0_0989999995 %float_0_0989999995 %float_0_0989999995 + %float_1_5 = OpConstant %float 1.5 + %262 = OpConstantComposite %v3float %float_1_5 %float_1_5 %float_1_5 + %263 = OpConstantComposite %v3float %float_0_159301758 %float_0_159301758 %float_0_159301758 + %264 = OpConstantComposite %v3float %float_78_84375 %float_78_84375 %float_78_84375 +%float_1_00055635 = OpConstant %float 1.00055635 + %float_7000 = OpConstant %float 7000 +%float_0_244063005 = OpConstant %float 0.244063005 +%float_99_1100006 = OpConstant %float 99.1100006 +%float_2967800 = OpConstant %float 2967800 +%float_0_237039998 = OpConstant %float 0.237039998 +%float_247_479996 = OpConstant %float 247.479996 +%float_1901800 = OpConstant %float 1901800 + %float_n3 = OpConstant %float -3 +%float_2_86999989 = OpConstant %float 2.86999989 +%float_0_275000006 = OpConstant %float 0.275000006 +%float_0_860117733 = OpConstant %float 0.860117733 +%float_0_000154118257 = OpConstant %float 0.000154118257 +%float_1_28641219en07 = OpConstant %float 1.28641219e-07 +%float_0_00084242021 = OpConstant %float 0.00084242021 +%float_7_08145137en07 = OpConstant %float 7.08145137e-07 +%float_0_317398727 = OpConstant %float 0.317398727 + +; HACK: Needed to hack this constant since MSVC and GNU libc are off by 1 ULP when converting to string (it probably still works fine though in a roundtrip ...) +%float_4_22806261en05 = OpConstant %float 4.25 + +%float_4_20481676en08 = OpConstant %float 4.20481676e-08 +%float_2_8974182en05 = OpConstant %float 2.8974182e-05 +%float_1_61456057en07 = OpConstant %float 1.61456057e-07 + %float_8 = OpConstant %float 8 + %float_4 = OpConstant %float 4 +%float_0_895099998 = OpConstant %float 0.895099998 +%float_0_266400009 = OpConstant %float 0.266400009 +%float_n0_161400005 = OpConstant %float -0.161400005 +%float_n0_750199974 = OpConstant %float -0.750199974 +%float_1_71350002 = OpConstant %float 1.71350002 +%float_0_0366999991 = OpConstant %float 0.0366999991 +%float_0_0388999991 = OpConstant %float 0.0388999991 +%float_n0_0684999973 = OpConstant %float -0.0684999973 +%float_1_02960002 = OpConstant %float 1.02960002 +%float_0_986992896 = OpConstant %float 0.986992896 +%float_n0_1470543 = OpConstant %float -0.1470543 +%float_0_159962699 = OpConstant %float 0.159962699 +%float_0_432305306 = OpConstant %float 0.432305306 +%float_0_518360317 = OpConstant %float 0.518360317 +%float_0_0492912009 = OpConstant %float 0.0492912009 +%float_n0_0085287001 = OpConstant %float -0.0085287001 +%float_0_040042799 = OpConstant %float 0.040042799 +%float_0_968486726 = OpConstant %float 0.968486726 +%float_5_55555534 = OpConstant %float 5.55555534 + %307 = OpConstantComposite %v3float %float_5_55555534 %float_5_55555534 %float_5_55555534 +%float_1_00000001en10 = OpConstant %float 1.00000001e-10 +%float_0_00999999978 = OpConstant %float 0.00999999978 +%float_0_666666687 = OpConstant %float 0.666666687 + %float_180 = OpConstant %float 180 + %float_360 = OpConstant %float 360 +%float_65535 = OpConstant %float 65535 + %314 = OpConstantComposite %v3float %float_65535 %float_65535 %float_65535 +%float_n4_97062206 = OpConstant %float -4.97062206 +%float_n3_02937818 = OpConstant %float -3.02937818 +%float_n2_12619996 = OpConstant %float -2.12619996 +%float_n1_51049995 = OpConstant %float -1.51049995 +%float_n1_05780005 = OpConstant %float -1.05780005 +%float_n0_466800004 = OpConstant %float -0.466800004 +%float_0_119379997 = OpConstant %float 0.119379997 +%float_0_708813429 = OpConstant %float 0.708813429 +%float_1_29118657 = OpConstant %float 1.29118657 +%float_0_808913231 = OpConstant %float 0.808913231 +%float_1_19108677 = OpConstant %float 1.19108677 +%float_1_56830001 = OpConstant %float 1.56830001 +%float_1_9483 = OpConstant %float 1.9483 +%float_2_30830002 = OpConstant %float 2.30830002 +%float_2_63840008 = OpConstant %float 2.63840008 +%float_2_85949993 = OpConstant %float 2.85949993 +%float_2_98726082 = OpConstant %float 2.98726082 +%float_3_01273918 = OpConstant %float 3.01273918 +%float_0_179999992 = OpConstant %float 0.179999992 +%float_9_99999975en05 = OpConstant %float 9.99999975e-05 + %float_1000 = OpConstant %float 1000 +%float_0_0599999987 = OpConstant %float 0.0599999987 +%float_3_50738446en05 = OpConstant %float 3.50738446e-05 + %338 = OpConstantComposite %v3float %float_3_50738446en05 %float_3_50738446en05 %float_3_50738446en05 +%float_n2_30102992 = OpConstant %float -2.30102992 +%float_n1_93120003 = OpConstant %float -1.93120003 +%float_n1_52049994 = OpConstant %float -1.52049994 +%float_0_801995218 = OpConstant %float 0.801995218 +%float_1_19800484 = OpConstant %float 1.19800484 +%float_1_59430003 = OpConstant %float 1.59430003 +%float_1_99730003 = OpConstant %float 1.99730003 +%float_2_37829995 = OpConstant %float 2.37829995 +%float_2_76839995 = OpConstant %float 2.76839995 +%float_3_05150008 = OpConstant %float 3.05150008 +%float_3_27462935 = OpConstant %float 3.27462935 +%float_3_32743073 = OpConstant %float 3.32743073 +%float_0_00499999989 = OpConstant %float 0.00499999989 + %float_11 = OpConstant %float 11 + %float_2000 = OpConstant %float 2000 +%float_0_119999997 = OpConstant %float 0.119999997 +%float_0_00313066994 = OpConstant %float 0.00313066994 +%float_12_9200001 = OpConstant %float 12.9200001 +%float_0_416666657 = OpConstant %float 0.416666657 +%float_1_05499995 = OpConstant %float 1.05499995 +%float_0_0549999997 = OpConstant %float 0.0549999997 +%float_n0_166666672 = OpConstant %float -0.166666672 + %float_n0_5 = OpConstant %float -0.5 +%float_0_166666672 = OpConstant %float 0.166666672 +%float_n3_15737653 = OpConstant %float -3.15737653 +%float_n0_485249996 = OpConstant %float -0.485249996 +%float_1_84773242 = OpConstant %float 1.84773242 +%float_n0_718548238 = OpConstant %float -0.718548238 +%float_2_08103061 = OpConstant %float 2.08103061 +%float_3_6681242 = OpConstant %float 3.6681242 + %float_18 = OpConstant %float 18 + %float_7 = OpConstant %float 7 +%type__Globals = OpTypeStruct %v4float %v3float %v4float %v4float %v4float %v4float %v4float %v4float %v4float %v4float %float %float %float %float %float %v3float %v4float %float %float %v4float %v4float %v4float %v4float %v4float %v4float %v4float %v4float %v4float %v4float %v4float %v4float %v4float %v4float %v4float %v4float %v4float %v4float %v4float %v4float %float %float %uint %uint %float %float +%_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals +%_ptr_Input_v2float = OpTypePointer Input %v2float +%_ptr_Input_v4float = OpTypePointer Input %v4float +%_ptr_Input_uint = OpTypePointer Input %uint +%_ptr_Output_v4float = OpTypePointer Output %v4float + %void = OpTypeVoid + %377 = OpTypeFunction %void +%_ptr_Function_float = OpTypePointer Function %float +%_ptr_Uniform_uint = OpTypePointer Uniform %uint + %bool = OpTypeBool +%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float +%_ptr_Uniform_float = OpTypePointer Uniform %float +%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float + %v2bool = OpTypeVector %bool 2 + %v3bool = OpTypeVector %bool 3 + %uint_10 = OpConstant %uint 10 +%_arr_float_uint_10 = OpTypeArray %float %uint_10 +%_arr_float_uint_6 = OpTypeArray %float %uint_6 + %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform +%in_var_TEXCOORD0 = OpVariable %_ptr_Input_v2float Input +%gl_FragCoord = OpVariable %_ptr_Input_v4float Input + %gl_Layer = OpVariable %_ptr_Input_uint Input +%out_var_SV_Target0 = OpVariable %_ptr_Output_v4float Output +%_ptr_Function__arr_float_uint_6 = OpTypePointer Function %_arr_float_uint_6 +%_ptr_Function__arr_float_uint_10 = OpTypePointer Function %_arr_float_uint_10 + %391 = OpUndef %v3float + %392 = OpConstantComposite %v3float %float_0_952552378 %float_0 %float_9_36786018en05 + %393 = OpConstantComposite %v3float %float_0_343966454 %float_0_728166103 %float_n0_0721325427 + %394 = OpConstantComposite %v3float %float_0 %float_0 %float_1_00882518 + %395 = OpConstantComposite %mat3v3float %392 %393 %394 + %396 = OpConstantComposite %v3float %float_1_04981101 %float_0 %float_n9_74845025en05 + %397 = OpConstantComposite %v3float %float_n0_495903015 %float_1_37331307 %float_0_0982400328 + %398 = OpConstantComposite %v3float %float_0 %float_0 %float_0_991252005 + %399 = OpConstantComposite %mat3v3float %396 %397 %398 + %400 = OpConstantComposite %v3float %float_0_662454188 %float_0_134004205 %float_0_156187683 + %401 = OpConstantComposite %v3float %float_n0_00557464967 %float_0_0040607336 %float_1_01033914 + %402 = OpConstantComposite %mat3v3float %400 %67 %401 + %403 = OpConstantComposite %v3float %float_1_6410234 %float_n0_324803293 %float_n0_236424699 + %404 = OpConstantComposite %v3float %float_n0_663662851 %float_1_61533165 %float_0_0167563483 + %405 = OpConstantComposite %v3float %float_0_0117218941 %float_n0_00828444213 %float_0_988394856 + %406 = OpConstantComposite %mat3v3float %403 %404 %405 + %407 = OpConstantComposite %v3float %float_1_45143926 %float_n0_236510754 %float_n0_214928567 + %408 = OpConstantComposite %v3float %float_n0_0765537769 %float_1_17622972 %float_n0_0996759236 + %409 = OpConstantComposite %v3float %float_0_00831614807 %float_n0_00603244966 %float_0_997716308 + %410 = OpConstantComposite %mat3v3float %407 %408 %409 + %411 = OpConstantComposite %v3float %float_0_695452213 %float_0_140678704 %float_0_163869068 + %412 = OpConstantComposite %v3float %float_0_0447945632 %float_0_859671116 %float_0_0955343172 + %413 = OpConstantComposite %v3float %float_n0_00552588282 %float_0_00402521016 %float_1_00150073 + %414 = OpConstantComposite %mat3v3float %411 %412 %413 + %415 = OpConstantComposite %v3float %float_3_2409699 %float_n1_5373832 %float_n0_498610765 + %416 = OpConstantComposite %v3float %float_n0_969243646 %float_1_8759675 %float_0_0415550582 + %417 = OpConstantComposite %v3float %float_0_0556300804 %float_n0_203976959 %float_1_05697155 + %418 = OpConstantComposite %mat3v3float %415 %416 %417 + %419 = OpConstantComposite %v3float %float_0_412456393 %float_0_357576102 %float_0_180437505 + %420 = OpConstantComposite %v3float %float_0_212672904 %float_0_715152204 %float_0_0721750036 + %421 = OpConstantComposite %v3float %float_0_0193339009 %float_0_119191997 %float_0_950304091 + %422 = OpConstantComposite %mat3v3float %419 %420 %421 + %423 = OpConstantComposite %v3float %float_1_71660841 %float_n0_355662107 %float_n0_253360093 + %424 = OpConstantComposite %v3float %float_n0_666682899 %float_1_61647761 %float_0_0157685 + %425 = OpConstantComposite %v3float %float_0_0176422 %float_n0_0427763015 %float_0_942228675 + %426 = OpConstantComposite %mat3v3float %423 %424 %425 + %427 = OpConstantComposite %v3float %float_2_49339628 %float_n0_93134588 %float_n0_402694494 + %428 = OpConstantComposite %v3float %float_n0_829486787 %float_1_76265967 %float_0_0236246008 + %429 = OpConstantComposite %v3float %float_0_0358507 %float_n0_0761827007 %float_0_957014024 + %430 = OpConstantComposite %mat3v3float %427 %428 %429 + %431 = OpConstantComposite %v3float %float_1_01303005 %float_0_00610530982 %float_n0_0149710001 + %432 = OpConstantComposite %v3float %float_0_00769822998 %float_0_998165011 %float_n0_00503202993 + %433 = OpConstantComposite %v3float %float_n0_00284131011 %float_0_00468515977 %float_0_924507022 + %434 = OpConstantComposite %mat3v3float %431 %432 %433 + %435 = OpConstantComposite %v3float %float_0_987223983 %float_n0_00611326983 %float_0_0159533005 + %436 = OpConstantComposite %v3float %float_n0_00759836007 %float_1_00186002 %float_0_0053300201 + %437 = OpConstantComposite %v3float %float_0_00307257008 %float_n0_00509594986 %float_1_08168006 + %438 = OpConstantComposite %mat3v3float %435 %436 %437 + %439 = OpConstantComposite %v3float %float_0_5 %float_n1 %float_0_5 + %440 = OpConstantComposite %v3float %float_n1 %float_1 %float_0_5 + %441 = OpConstantComposite %v3float %float_0_5 %float_0 %float_0 + %442 = OpConstantComposite %mat3v3float %439 %440 %441 + %443 = OpConstantComposite %v3float %float_1 %float_0 %float_0 + %444 = OpConstantComposite %v3float %float_0 %float_1 %float_0 + %445 = OpConstantComposite %v3float %float_0 %float_0 %float_1 + %446 = OpConstantComposite %mat3v3float %443 %444 %445 +%float_n6_07624626 = OpConstant %float -6.07624626 + %448 = OpConstantComposite %v3float %float_n6_07624626 %float_n6_07624626 %float_n6_07624626 + %449 = OpConstantComposite %v3float %float_0_895099998 %float_0_266400009 %float_n0_161400005 + %450 = OpConstantComposite %v3float %float_n0_750199974 %float_1_71350002 %float_0_0366999991 + %451 = OpConstantComposite %v3float %float_0_0388999991 %float_n0_0684999973 %float_1_02960002 + %452 = OpConstantComposite %mat3v3float %449 %450 %451 + %453 = OpConstantComposite %v3float %float_0_986992896 %float_n0_1470543 %float_0_159962699 + %454 = OpConstantComposite %v3float %float_0_432305306 %float_0_518360317 %float_0_0492912009 + %455 = OpConstantComposite %v3float %float_n0_0085287001 %float_0_040042799 %float_0_968486726 + %456 = OpConstantComposite %mat3v3float %453 %454 %455 +%float_0_358299971 = OpConstant %float 0.358299971 + %458 = OpConstantComposite %v3float %float_0_544169128 %float_0_239592597 %float_0_166694298 + %459 = OpConstantComposite %v3float %float_0_239465594 %float_0_702153027 %float_0_058381401 + %460 = OpConstantComposite %v3float %float_n0_00234390004 %float_0_0361833982 %float_1_05521834 + %461 = OpConstantComposite %mat3v3float %458 %459 %460 + %462 = OpConstantComposite %v3float %float_0_940437257 %float_n0_0183068793 %float_0_077869609 + %463 = OpConstantComposite %v3float %float_0_00837869663 %float_0_828660011 %float_0_162961304 + %464 = OpConstantComposite %v3float %float_0_00054712611 %float_n0_000883374596 %float_1_00033629 + %465 = OpConstantComposite %mat3v3float %462 %463 %464 + %466 = OpConstantComposite %v3float %float_1_06317997 %float_0_0233955998 %float_n0_0865726024 + %467 = OpConstantComposite %v3float %float_n0_0106336996 %float_1_20632005 %float_n0_195690006 + %468 = OpConstantComposite %v3float %float_n0_000590886979 %float_0_00105247996 %float_0_999538004 + %469 = OpConstantComposite %mat3v3float %466 %467 %468 +%float_0_0533333346 = OpConstant %float 0.0533333346 +%float_0_159999996 = OpConstant %float 0.159999996 +%float_57_2957764 = OpConstant %float 57.2957764 +%float_n67_5 = OpConstant %float -67.5 + %float_67_5 = OpConstant %float 67.5 + %475 = OpConstantComposite %_arr_float_uint_6 %float_n4 %float_n4 %float_n3_15737653 %float_n0_485249996 %float_1_84773242 %float_1_84773242 + %476 = OpConstantComposite %_arr_float_uint_6 %float_n0_718548238 %float_2_08103061 %float_3_6681242 %float_4 %float_4 %float_4 + %float_n15 = OpConstant %float -15 + %float_n14 = OpConstant %float -14 + %479 = OpConstantComposite %_arr_float_uint_10 %float_n4_97062206 %float_n3_02937818 %float_n2_12619996 %float_n1_51049995 %float_n1_05780005 %float_n0_466800004 %float_0_119379997 %float_0_708813429 %float_1_29118657 %float_1_29118657 + %480 = OpConstantComposite %_arr_float_uint_10 %float_0_808913231 %float_1_19108677 %float_1_56830001 %float_1_9483 %float_2_30830002 %float_2_63840008 %float_2_85949993 %float_2_98726082 %float_3_01273918 %float_3_01273918 + %float_n12 = OpConstant %float -12 + %482 = OpConstantComposite %_arr_float_uint_10 %float_n2_30102992 %float_n2_30102992 %float_n1_93120003 %float_n1_52049994 %float_n1_05780005 %float_n0_466800004 %float_0_119379997 %float_0_708813429 %float_1_29118657 %float_1_29118657 + %483 = OpConstantComposite %_arr_float_uint_10 %float_0_801995218 %float_1_19800484 %float_1_59430003 %float_1_99730003 %float_2_37829995 %float_2_76839995 %float_3_05150008 %float_3_27462935 %float_3_32743073 %float_3_32743073 +%float_0_0322580636 = OpConstant %float 0.0322580636 +%float_1_03225803 = OpConstant %float 1.03225803 + %486 = OpConstantComposite %v2float %float_1_03225803 %float_1_03225803 +%float_4_60443853e_09 = OpConstant %float 4.60443853e+09 +%float_2_00528435e_09 = OpConstant %float 2.00528435e+09 +%float_0_333333343 = OpConstant %float 0.333333343 + %float_5 = OpConstant %float 5 + %float_2_5 = OpConstant %float 2.5 +%float_0_0250000004 = OpConstant %float 0.0250000004 +%float_0_239999995 = OpConstant %float 0.239999995 +%float_0_0148148146 = OpConstant %float 0.0148148146 +%float_0_819999993 = OpConstant %float 0.819999993 + %496 = OpConstantComposite %v3float %float_9_99999975en05 %float_9_99999975en05 %float_9_99999975en05 +%float_0_0296296291 = OpConstant %float 0.0296296291 +%float_0_952381015 = OpConstant %float 0.952381015 + %499 = OpConstantComposite %v3float %float_0_952381015 %float_0_952381015 %float_0_952381015 + %MainPS = OpFunction %void None %377 + %500 = OpLabel + %501 = OpVariable %_ptr_Function__arr_float_uint_6 Function + %502 = OpVariable %_ptr_Function__arr_float_uint_6 Function + %503 = OpVariable %_ptr_Function__arr_float_uint_6 Function + %504 = OpVariable %_ptr_Function__arr_float_uint_6 Function + %505 = OpVariable %_ptr_Function__arr_float_uint_6 Function + %506 = OpVariable %_ptr_Function__arr_float_uint_6 Function + %507 = OpVariable %_ptr_Function__arr_float_uint_10 Function + %508 = OpVariable %_ptr_Function__arr_float_uint_10 Function + %509 = OpVariable %_ptr_Function__arr_float_uint_10 Function + %510 = OpVariable %_ptr_Function__arr_float_uint_10 Function + %511 = OpVariable %_ptr_Function__arr_float_uint_10 Function + %512 = OpVariable %_ptr_Function__arr_float_uint_10 Function + %513 = OpVariable %_ptr_Function__arr_float_uint_6 Function + %514 = OpVariable %_ptr_Function__arr_float_uint_6 Function + %515 = OpVariable %_ptr_Function__arr_float_uint_6 Function + %516 = OpVariable %_ptr_Function__arr_float_uint_6 Function + %517 = OpVariable %_ptr_Function__arr_float_uint_6 Function + %518 = OpVariable %_ptr_Function__arr_float_uint_6 Function + %519 = OpVariable %_ptr_Function__arr_float_uint_6 Function + %520 = OpVariable %_ptr_Function__arr_float_uint_6 Function + %521 = OpVariable %_ptr_Function__arr_float_uint_6 Function + %522 = OpVariable %_ptr_Function__arr_float_uint_6 Function + %523 = OpVariable %_ptr_Function__arr_float_uint_6 Function + %524 = OpVariable %_ptr_Function__arr_float_uint_6 Function + %525 = OpVariable %_ptr_Function__arr_float_uint_10 Function + %526 = OpVariable %_ptr_Function__arr_float_uint_10 Function + %527 = OpVariable %_ptr_Function__arr_float_uint_10 Function + %528 = OpVariable %_ptr_Function__arr_float_uint_10 Function + %529 = OpVariable %_ptr_Function__arr_float_uint_10 Function + %530 = OpVariable %_ptr_Function__arr_float_uint_10 Function + %531 = OpVariable %_ptr_Function__arr_float_uint_6 Function + %532 = OpVariable %_ptr_Function__arr_float_uint_6 Function + %533 = OpVariable %_ptr_Function__arr_float_uint_6 Function + %534 = OpVariable %_ptr_Function__arr_float_uint_6 Function + %535 = OpVariable %_ptr_Function__arr_float_uint_6 Function + %536 = OpVariable %_ptr_Function__arr_float_uint_6 Function + %537 = OpLoad %v2float %in_var_TEXCOORD0 + %538 = OpLoad %uint %gl_Layer + %539 = OpFSub %v2float %537 %128 + %540 = OpFMul %v2float %539 %486 + %541 = OpCompositeExtract %float %540 0 + %542 = OpCompositeExtract %float %540 1 + %543 = OpConvertUToF %float %538 + %544 = OpFMul %float %543 %float_0_0322580636 + %545 = OpCompositeConstruct %v4float %541 %542 %544 %float_0 + %546 = OpMatrixTimesMatrix %mat3v3float %422 %434 + %547 = OpMatrixTimesMatrix %mat3v3float %546 %406 + %548 = OpMatrixTimesMatrix %mat3v3float %402 %438 + %549 = OpMatrixTimesMatrix %mat3v3float %548 %418 + %550 = OpMatrixTimesMatrix %mat3v3float %395 %406 + %551 = OpMatrixTimesMatrix %mat3v3float %402 %399 + %552 = OpAccessChain %_ptr_Uniform_uint %_Globals %int_42 + %553 = OpLoad %uint %552 + OpBranch %554 + %554 = OpLabel + OpLoopMerge %555 %556 None + OpBranch %557 + %557 = OpLabel + %558 = OpMatrixTimesMatrix %mat3v3float %548 %430 + %559 = OpMatrixTimesMatrix %mat3v3float %548 %426 + %560 = OpIEqual %bool %553 %uint_1 + OpSelectionMerge %561 None + OpBranchConditional %560 %562 %563 + %563 = OpLabel + %564 = OpIEqual %bool %553 %uint_2 + OpSelectionMerge %565 None + OpBranchConditional %564 %566 %567 + %567 = OpLabel + %568 = OpIEqual %bool %553 %uint_3 + OpSelectionMerge %569 None + OpBranchConditional %568 %570 %571 + %571 = OpLabel + %572 = OpIEqual %bool %553 %uint_4 + OpSelectionMerge %573 None + OpBranchConditional %572 %574 %575 + %575 = OpLabel + OpBranch %555 + %574 = OpLabel + OpBranch %555 + %573 = OpLabel + OpUnreachable + %570 = OpLabel + OpBranch %555 + %569 = OpLabel + OpUnreachable + %566 = OpLabel + OpBranch %555 + %565 = OpLabel + OpUnreachable + %562 = OpLabel + OpBranch %555 + %561 = OpLabel + OpUnreachable + %556 = OpLabel + OpBranch %554 + %555 = OpLabel + %576 = OpPhi %mat3v3float %549 %575 %446 %574 %414 %570 %559 %566 %558 %562 + %577 = OpVectorShuffle %v3float %545 %545 0 1 2 + %578 = OpAccessChain %_ptr_Uniform_uint %_Globals %int_41 + %579 = OpLoad %uint %578 + %580 = OpUGreaterThanEqual %bool %579 %uint_3 + OpSelectionMerge %581 None + OpBranchConditional %580 %582 %583 + %583 = OpLabel + %584 = OpFSub %v3float %577 %192 + %585 = OpFMul %v3float %584 %193 + %586 = OpExtInst %v3float %1 Exp2 %585 + %587 = OpFMul %v3float %586 %194 + %588 = OpExtInst %v3float %1 Exp2 %448 + %589 = OpFMul %v3float %588 %194 + %590 = OpFSub %v3float %587 %589 + OpBranch %581 + %582 = OpLabel + %591 = OpExtInst %v3float %1 Pow %577 %182 + %592 = OpFSub %v3float %591 %183 + %593 = OpExtInst %v3float %1 FMax %132 %592 + %594 = OpFMul %v3float %185 %591 + %595 = OpFSub %v3float %184 %594 + %596 = OpFDiv %v3float %593 %595 + %597 = OpExtInst %v3float %1 Pow %596 %187 + %598 = OpFMul %v3float %597 %188 + OpBranch %581 + %581 = OpLabel + %599 = OpPhi %v3float %590 %583 %598 %582 + %600 = OpAccessChain %_ptr_Uniform_float %_Globals %int_17 + %601 = OpLoad %float %600 + %602 = OpFMul %float %601 %float_1_00055635 + %603 = OpFOrdLessThanEqual %bool %602 %float_7000 + %604 = OpFDiv %float %float_4_60443853e_09 %601 + %605 = OpFSub %float %float_2967800 %604 + %606 = OpFDiv %float %605 %602 + %607 = OpFAdd %float %float_99_1100006 %606 + %608 = OpFDiv %float %607 %602 + %609 = OpFAdd %float %float_0_244063005 %608 + %610 = OpFDiv %float %float_2_00528435e_09 %601 + %611 = OpFSub %float %float_1901800 %610 + %612 = OpFDiv %float %611 %602 + %613 = OpFAdd %float %float_247_479996 %612 + %614 = OpFDiv %float %613 %602 + %615 = OpFAdd %float %float_0_237039998 %614 + %616 = OpSelect %float %603 %609 %615 + %617 = OpFMul %float %float_n3 %616 + %618 = OpFMul %float %617 %616 + %619 = OpFMul %float %float_2_86999989 %616 + %620 = OpFAdd %float %618 %619 + %621 = OpFSub %float %620 %float_0_275000006 + %622 = OpCompositeConstruct %v2float %616 %621 + %623 = OpFMul %float %float_0_000154118257 %601 + %624 = OpFAdd %float %float_0_860117733 %623 + %625 = OpFMul %float %float_1_28641219en07 %601 + %626 = OpFMul %float %625 %601 + %627 = OpFAdd %float %624 %626 + %628 = OpFMul %float %float_0_00084242021 %601 + %629 = OpFAdd %float %float_1 %628 + %630 = OpFMul %float %float_7_08145137en07 %601 + %631 = OpFMul %float %630 %601 + %632 = OpFAdd %float %629 %631 + %633 = OpFDiv %float %627 %632 + %634 = OpFMul %float %float_4_22806261en05 %601 + %635 = OpFAdd %float %float_0_317398727 %634 + %636 = OpFMul %float %float_4_20481676en08 %601 + %637 = OpFMul %float %636 %601 + %638 = OpFAdd %float %635 %637 + %639 = OpFMul %float %float_2_8974182en05 %601 + %640 = OpFSub %float %float_1 %639 + %641 = OpFMul %float %float_1_61456057en07 %601 + %642 = OpFMul %float %641 %601 + %643 = OpFAdd %float %640 %642 + %644 = OpFDiv %float %638 %643 + %645 = OpFMul %float %float_3 %633 + %646 = OpFMul %float %float_2 %633 + %647 = OpFMul %float %float_8 %644 + %648 = OpFSub %float %646 %647 + %649 = OpFAdd %float %648 %float_4 + %650 = OpFDiv %float %645 %649 + %651 = OpFMul %float %float_2 %644 + %652 = OpFDiv %float %651 %649 + %653 = OpCompositeConstruct %v2float %650 %652 + %654 = OpFOrdLessThan %bool %601 %float_4000 + %655 = OpCompositeConstruct %v2bool %654 %654 + %656 = OpSelect %v2float %655 %653 %622 + %657 = OpAccessChain %_ptr_Uniform_float %_Globals %int_18 + %658 = OpLoad %float %657 + %659 = OpCompositeConstruct %v2float %633 %644 + %660 = OpExtInst %v2float %1 Normalize %659 + %661 = OpCompositeExtract %float %660 1 + %662 = OpFNegate %float %661 + %663 = OpFMul %float %662 %658 + %664 = OpFMul %float %663 %float_0_0500000007 + %665 = OpFAdd %float %633 %664 + %666 = OpCompositeExtract %float %660 0 + %667 = OpFMul %float %666 %658 + %668 = OpFMul %float %667 %float_0_0500000007 + %669 = OpFAdd %float %644 %668 + %670 = OpFMul %float %float_3 %665 + %671 = OpFMul %float %float_2 %665 + %672 = OpFMul %float %float_8 %669 + %673 = OpFSub %float %671 %672 + %674 = OpFAdd %float %673 %float_4 + %675 = OpFDiv %float %670 %674 + %676 = OpFMul %float %float_2 %669 + %677 = OpFDiv %float %676 %674 + %678 = OpCompositeConstruct %v2float %675 %677 + %679 = OpFSub %v2float %678 %653 + %680 = OpFAdd %v2float %656 %679 + %681 = OpCompositeExtract %float %680 0 + %682 = OpCompositeExtract %float %680 1 + %683 = OpExtInst %float %1 FMax %682 %float_1_00000001en10 + %684 = OpFDiv %float %681 %683 + %685 = OpCompositeInsert %v3float %684 %391 0 + %686 = OpCompositeInsert %v3float %float_1 %685 1 + %687 = OpFSub %float %float_1 %681 + %688 = OpFSub %float %687 %682 + %689 = OpFDiv %float %688 %683 + %690 = OpCompositeInsert %v3float %689 %686 2 + %691 = OpExtInst %float %1 FMax %float_0_328999996 %float_1_00000001en10 + %692 = OpFDiv %float %float_0_312700003 %691 + %693 = OpCompositeInsert %v3float %692 %391 0 + %694 = OpCompositeInsert %v3float %float_1 %693 1 + %695 = OpFDiv %float %float_0_358299971 %691 + %696 = OpCompositeInsert %v3float %695 %694 2 + %697 = OpVectorTimesMatrix %v3float %690 %452 + %698 = OpVectorTimesMatrix %v3float %696 %452 + %699 = OpCompositeExtract %float %698 0 + %700 = OpCompositeExtract %float %697 0 + %701 = OpFDiv %float %699 %700 + %702 = OpCompositeConstruct %v3float %701 %float_0 %float_0 + %703 = OpCompositeExtract %float %698 1 + %704 = OpCompositeExtract %float %697 1 + %705 = OpFDiv %float %703 %704 + %706 = OpCompositeConstruct %v3float %float_0 %705 %float_0 + %707 = OpCompositeExtract %float %698 2 + %708 = OpCompositeExtract %float %697 2 + %709 = OpFDiv %float %707 %708 + %710 = OpCompositeConstruct %v3float %float_0 %float_0 %709 + %711 = OpCompositeConstruct %mat3v3float %702 %706 %710 + %712 = OpMatrixTimesMatrix %mat3v3float %452 %711 + %713 = OpMatrixTimesMatrix %mat3v3float %712 %456 + %714 = OpMatrixTimesMatrix %mat3v3float %422 %713 + %715 = OpMatrixTimesMatrix %mat3v3float %714 %418 + %716 = OpVectorTimesMatrix %v3float %599 %715 + %717 = OpVectorTimesMatrix %v3float %716 %547 + %718 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_9 + %719 = OpAccessChain %_ptr_Uniform_float %_Globals %int_9 %int_3 + %720 = OpLoad %float %719 + %721 = OpFOrdNotEqual %bool %720 %float_0 + OpSelectionMerge %722 None + OpBranchConditional %721 %723 %722 + %723 = OpLabel + %724 = OpDot %float %717 %67 + %725 = OpCompositeConstruct %v3float %724 %724 %724 + %726 = OpFDiv %v3float %717 %725 + %727 = OpFSub %v3float %726 %135 + %728 = OpDot %float %727 %727 + %729 = OpFMul %float %float_n4 %728 + %730 = OpExtInst %float %1 Exp2 %729 + %731 = OpFSub %float %float_1 %730 + %732 = OpAccessChain %_ptr_Uniform_float %_Globals %int_44 + %733 = OpLoad %float %732 + %734 = OpFMul %float %float_n4 %733 + %735 = OpFMul %float %734 %724 + %736 = OpFMul %float %735 %724 + %737 = OpExtInst %float %1 Exp2 %736 + %738 = OpFSub %float %float_1 %737 + %739 = OpFMul %float %731 %738 + %740 = OpMatrixTimesMatrix %mat3v3float %461 %406 + %741 = OpMatrixTimesMatrix %mat3v3float %549 %740 + %742 = OpVectorTimesMatrix %v3float %717 %741 + %743 = OpCompositeConstruct %v3float %739 %739 %739 + %744 = OpExtInst %v3float %1 FMix %717 %742 %743 + OpBranch %722 + %722 = OpLabel + %745 = OpPhi %v3float %717 %581 %744 %723 + %746 = OpDot %float %745 %67 + %747 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_24 + %748 = OpLoad %v4float %747 + %749 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_19 + %750 = OpLoad %v4float %749 + %751 = OpFMul %v4float %748 %750 + %752 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_25 + %753 = OpLoad %v4float %752 + %754 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_20 + %755 = OpLoad %v4float %754 + %756 = OpFMul %v4float %753 %755 + %757 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_26 + %758 = OpLoad %v4float %757 + %759 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_21 + %760 = OpLoad %v4float %759 + %761 = OpFMul %v4float %758 %760 + %762 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_27 + %763 = OpLoad %v4float %762 + %764 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_22 + %765 = OpLoad %v4float %764 + %766 = OpFMul %v4float %763 %765 + %767 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_28 + %768 = OpLoad %v4float %767 + %769 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_23 + %770 = OpLoad %v4float %769 + %771 = OpFAdd %v4float %768 %770 + %772 = OpCompositeConstruct %v3float %746 %746 %746 + %773 = OpVectorShuffle %v3float %751 %751 0 1 2 + %774 = OpCompositeExtract %float %751 3 + %775 = OpCompositeConstruct %v3float %774 %774 %774 + %776 = OpFMul %v3float %773 %775 + %777 = OpExtInst %v3float %1 FMix %772 %745 %776 + %778 = OpExtInst %v3float %1 FMax %132 %777 + %779 = OpFMul %v3float %778 %307 + %780 = OpVectorShuffle %v3float %756 %756 0 1 2 + %781 = OpCompositeExtract %float %756 3 + %782 = OpCompositeConstruct %v3float %781 %781 %781 + %783 = OpFMul %v3float %780 %782 + %784 = OpExtInst %v3float %1 Pow %779 %783 + %785 = OpFMul %v3float %784 %194 + %786 = OpVectorShuffle %v3float %761 %761 0 1 2 + %787 = OpCompositeExtract %float %761 3 + %788 = OpCompositeConstruct %v3float %787 %787 %787 + %789 = OpFMul %v3float %786 %788 + %790 = OpFDiv %v3float %135 %789 + %791 = OpExtInst %v3float %1 Pow %785 %790 + %792 = OpVectorShuffle %v3float %766 %766 0 1 2 + %793 = OpCompositeExtract %float %766 3 + %794 = OpCompositeConstruct %v3float %793 %793 %793 + %795 = OpFMul %v3float %792 %794 + %796 = OpFMul %v3float %791 %795 + %797 = OpVectorShuffle %v3float %771 %771 0 1 2 + %798 = OpCompositeExtract %float %771 3 + %799 = OpCompositeConstruct %v3float %798 %798 %798 + %800 = OpFAdd %v3float %797 %799 + %801 = OpFAdd %v3float %796 %800 + %802 = OpAccessChain %_ptr_Uniform_float %_Globals %int_39 + %803 = OpLoad %float %802 + %804 = OpExtInst %float %1 SmoothStep %float_0 %803 %746 + %805 = OpFSub %float %float_1 %804 + %806 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_34 + %807 = OpLoad %v4float %806 + %808 = OpFMul %v4float %807 %750 + %809 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_35 + %810 = OpLoad %v4float %809 + %811 = OpFMul %v4float %810 %755 + %812 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_36 + %813 = OpLoad %v4float %812 + %814 = OpFMul %v4float %813 %760 + %815 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_37 + %816 = OpLoad %v4float %815 + %817 = OpFMul %v4float %816 %765 + %818 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_38 + %819 = OpLoad %v4float %818 + %820 = OpFAdd %v4float %819 %770 + %821 = OpVectorShuffle %v3float %808 %808 0 1 2 + %822 = OpCompositeExtract %float %808 3 + %823 = OpCompositeConstruct %v3float %822 %822 %822 + %824 = OpFMul %v3float %821 %823 + %825 = OpExtInst %v3float %1 FMix %772 %745 %824 + %826 = OpExtInst %v3float %1 FMax %132 %825 + %827 = OpFMul %v3float %826 %307 + %828 = OpVectorShuffle %v3float %811 %811 0 1 2 + %829 = OpCompositeExtract %float %811 3 + %830 = OpCompositeConstruct %v3float %829 %829 %829 + %831 = OpFMul %v3float %828 %830 + %832 = OpExtInst %v3float %1 Pow %827 %831 + %833 = OpFMul %v3float %832 %194 + %834 = OpVectorShuffle %v3float %814 %814 0 1 2 + %835 = OpCompositeExtract %float %814 3 + %836 = OpCompositeConstruct %v3float %835 %835 %835 + %837 = OpFMul %v3float %834 %836 + %838 = OpFDiv %v3float %135 %837 + %839 = OpExtInst %v3float %1 Pow %833 %838 + %840 = OpVectorShuffle %v3float %817 %817 0 1 2 + %841 = OpCompositeExtract %float %817 3 + %842 = OpCompositeConstruct %v3float %841 %841 %841 + %843 = OpFMul %v3float %840 %842 + %844 = OpFMul %v3float %839 %843 + %845 = OpVectorShuffle %v3float %820 %820 0 1 2 + %846 = OpCompositeExtract %float %820 3 + %847 = OpCompositeConstruct %v3float %846 %846 %846 + %848 = OpFAdd %v3float %845 %847 + %849 = OpFAdd %v3float %844 %848 + %850 = OpAccessChain %_ptr_Uniform_float %_Globals %int_40 + %851 = OpLoad %float %850 + %852 = OpExtInst %float %1 SmoothStep %851 %float_1 %746 + %853 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_29 + %854 = OpLoad %v4float %853 + %855 = OpFMul %v4float %854 %750 + %856 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_30 + %857 = OpLoad %v4float %856 + %858 = OpFMul %v4float %857 %755 + %859 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_31 + %860 = OpLoad %v4float %859 + %861 = OpFMul %v4float %860 %760 + %862 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_32 + %863 = OpLoad %v4float %862 + %864 = OpFMul %v4float %863 %765 + %865 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_33 + %866 = OpLoad %v4float %865 + %867 = OpFAdd %v4float %866 %770 + %868 = OpVectorShuffle %v3float %855 %855 0 1 2 + %869 = OpCompositeExtract %float %855 3 + %870 = OpCompositeConstruct %v3float %869 %869 %869 + %871 = OpFMul %v3float %868 %870 + %872 = OpExtInst %v3float %1 FMix %772 %745 %871 + %873 = OpExtInst %v3float %1 FMax %132 %872 + %874 = OpFMul %v3float %873 %307 + %875 = OpVectorShuffle %v3float %858 %858 0 1 2 + %876 = OpCompositeExtract %float %858 3 + %877 = OpCompositeConstruct %v3float %876 %876 %876 + %878 = OpFMul %v3float %875 %877 + %879 = OpExtInst %v3float %1 Pow %874 %878 + %880 = OpFMul %v3float %879 %194 + %881 = OpVectorShuffle %v3float %861 %861 0 1 2 + %882 = OpCompositeExtract %float %861 3 + %883 = OpCompositeConstruct %v3float %882 %882 %882 + %884 = OpFMul %v3float %881 %883 + %885 = OpFDiv %v3float %135 %884 + %886 = OpExtInst %v3float %1 Pow %880 %885 + %887 = OpVectorShuffle %v3float %864 %864 0 1 2 + %888 = OpCompositeExtract %float %864 3 + %889 = OpCompositeConstruct %v3float %888 %888 %888 + %890 = OpFMul %v3float %887 %889 + %891 = OpFMul %v3float %886 %890 + %892 = OpVectorShuffle %v3float %867 %867 0 1 2 + %893 = OpCompositeExtract %float %867 3 + %894 = OpCompositeConstruct %v3float %893 %893 %893 + %895 = OpFAdd %v3float %892 %894 + %896 = OpFAdd %v3float %891 %895 + %897 = OpFSub %float %804 %852 + %898 = OpCompositeConstruct %v3float %805 %805 %805 + %899 = OpFMul %v3float %801 %898 + %900 = OpCompositeConstruct %v3float %897 %897 %897 + %901 = OpFMul %v3float %896 %900 + %902 = OpFAdd %v3float %899 %901 + %903 = OpCompositeConstruct %v3float %852 %852 %852 + %904 = OpFMul %v3float %849 %903 + %905 = OpFAdd %v3float %902 %904 + %906 = OpVectorTimesMatrix %v3float %905 %549 + %907 = OpMatrixTimesMatrix %mat3v3float %551 %465 + %908 = OpMatrixTimesMatrix %mat3v3float %907 %550 + %909 = OpMatrixTimesMatrix %mat3v3float %551 %469 + %910 = OpMatrixTimesMatrix %mat3v3float %909 %550 + %911 = OpVectorTimesMatrix %v3float %905 %908 + %912 = OpAccessChain %_ptr_Uniform_float %_Globals %int_43 + %913 = OpLoad %float %912 + %914 = OpCompositeConstruct %v3float %913 %913 %913 + %915 = OpExtInst %v3float %1 FMix %905 %911 %914 + %916 = OpVectorTimesMatrix %v3float %915 %551 + %917 = OpCompositeExtract %float %916 0 + %918 = OpCompositeExtract %float %916 1 + %919 = OpExtInst %float %1 FMin %917 %918 + %920 = OpCompositeExtract %float %916 2 + %921 = OpExtInst %float %1 FMin %919 %920 + %922 = OpExtInst %float %1 FMax %917 %918 + %923 = OpExtInst %float %1 FMax %922 %920 + %924 = OpExtInst %float %1 FMax %923 %float_1_00000001en10 + %925 = OpExtInst %float %1 FMax %921 %float_1_00000001en10 + %926 = OpFSub %float %924 %925 + %927 = OpExtInst %float %1 FMax %923 %float_0_00999999978 + %928 = OpFDiv %float %926 %927 + %929 = OpFSub %float %920 %918 + %930 = OpFMul %float %920 %929 + %931 = OpFSub %float %918 %917 + %932 = OpFMul %float %918 %931 + %933 = OpFAdd %float %930 %932 + %934 = OpFSub %float %917 %920 + %935 = OpFMul %float %917 %934 + %936 = OpFAdd %float %933 %935 + %937 = OpExtInst %float %1 Sqrt %936 + %938 = OpFAdd %float %920 %918 + %939 = OpFAdd %float %938 %917 + %940 = OpFMul %float %float_1_75 %937 + %941 = OpFAdd %float %939 %940 + %942 = OpFMul %float %941 %float_0_333333343 + %943 = OpFSub %float %928 %float_0_400000006 + %944 = OpFMul %float %943 %float_5 + %945 = OpFMul %float %943 %float_2_5 + %946 = OpExtInst %float %1 FAbs %945 + %947 = OpFSub %float %float_1 %946 + %948 = OpExtInst %float %1 FMax %947 %float_0 + %949 = OpExtInst %float %1 FSign %944 + %950 = OpConvertFToS %int %949 + %951 = OpConvertSToF %float %950 + %952 = OpFMul %float %948 %948 + %953 = OpFSub %float %float_1 %952 + %954 = OpFMul %float %951 %953 + %955 = OpFAdd %float %float_1 %954 + %956 = OpFMul %float %955 %float_0_0250000004 + %957 = OpFOrdLessThanEqual %bool %942 %float_0_0533333346 + OpSelectionMerge %958 None + OpBranchConditional %957 %959 %960 + %960 = OpLabel + %961 = OpFOrdGreaterThanEqual %bool %942 %float_0_159999996 + OpSelectionMerge %962 None + OpBranchConditional %961 %963 %964 + %964 = OpLabel + %965 = OpFDiv %float %float_0_239999995 %941 + %966 = OpFSub %float %965 %float_0_5 + %967 = OpFMul %float %956 %966 + OpBranch %962 + %963 = OpLabel + OpBranch %962 + %962 = OpLabel + %968 = OpPhi %float %967 %964 %float_0 %963 + OpBranch %958 + %959 = OpLabel + OpBranch %958 + %958 = OpLabel + %969 = OpPhi %float %968 %962 %956 %959 + %970 = OpFAdd %float %float_1 %969 + %971 = OpCompositeConstruct %v3float %970 %970 %970 + %972 = OpFMul %v3float %916 %971 + %973 = OpCompositeExtract %float %972 0 + %974 = OpCompositeExtract %float %972 1 + %975 = OpFOrdEqual %bool %973 %974 + %976 = OpCompositeExtract %float %972 2 + %977 = OpFOrdEqual %bool %974 %976 + %978 = OpLogicalAnd %bool %975 %977 + OpSelectionMerge %979 None + OpBranchConditional %978 %980 %981 + %981 = OpLabel + %982 = OpExtInst %float %1 Sqrt %float_3 + %983 = OpFSub %float %974 %976 + %984 = OpFMul %float %982 %983 + %985 = OpFMul %float %float_2 %973 + %986 = OpFSub %float %985 %974 + %987 = OpFSub %float %986 %976 + %988 = OpExtInst %float %1 Atan2 %984 %987 + %989 = OpFMul %float %float_57_2957764 %988 + OpBranch %979 + %980 = OpLabel + OpBranch %979 + %979 = OpLabel + %990 = OpPhi %float %989 %981 %float_0 %980 + %991 = OpFOrdLessThan %bool %990 %float_0 + OpSelectionMerge %992 None + OpBranchConditional %991 %993 %992 + %993 = OpLabel + %994 = OpFAdd %float %990 %float_360 + OpBranch %992 + %992 = OpLabel + %995 = OpPhi %float %990 %979 %994 %993 + %996 = OpExtInst %float %1 FClamp %995 %float_0 %float_360 + %997 = OpFOrdGreaterThan %bool %996 %float_180 + OpSelectionMerge %998 None + OpBranchConditional %997 %999 %998 + %999 = OpLabel + %1000 = OpFSub %float %996 %float_360 + OpBranch %998 + %998 = OpLabel + %1001 = OpPhi %float %996 %992 %1000 %999 + %1002 = OpFMul %float %1001 %float_0_0148148146 + %1003 = OpExtInst %float %1 FAbs %1002 + %1004 = OpFSub %float %float_1 %1003 + %1005 = OpExtInst %float %1 SmoothStep %float_0 %float_1 %1004 + %1006 = OpFMul %float %1005 %1005 + %1007 = OpFMul %float %1006 %928 + %1008 = OpFSub %float %float_0_0299999993 %973 + %1009 = OpFMul %float %1007 %1008 + %1010 = OpFMul %float %1009 %float_0_180000007 + %1011 = OpFAdd %float %973 %1010 + %1012 = OpCompositeInsert %v3float %1011 %972 0 + %1013 = OpVectorTimesMatrix %v3float %1012 %410 + %1014 = OpExtInst %v3float %1 FMax %132 %1013 + %1015 = OpDot %float %1014 %67 + %1016 = OpCompositeConstruct %v3float %1015 %1015 %1015 + %1017 = OpExtInst %v3float %1 FMix %1016 %1014 %228 + %1018 = OpAccessChain %_ptr_Uniform_float %_Globals %int_13 + %1019 = OpLoad %float %1018 + %1020 = OpFAdd %float %float_1 %1019 + %1021 = OpAccessChain %_ptr_Uniform_float %_Globals %int_11 + %1022 = OpLoad %float %1021 + %1023 = OpFSub %float %1020 %1022 + %1024 = OpAccessChain %_ptr_Uniform_float %_Globals %int_14 + %1025 = OpLoad %float %1024 + %1026 = OpFAdd %float %float_1 %1025 + %1027 = OpAccessChain %_ptr_Uniform_float %_Globals %int_12 + %1028 = OpLoad %float %1027 + %1029 = OpFSub %float %1026 %1028 + %1030 = OpFOrdGreaterThan %bool %1022 %float_0_800000012 + OpSelectionMerge %1031 None + OpBranchConditional %1030 %1032 %1033 + %1033 = OpLabel + %1034 = OpFAdd %float %float_0_180000007 %1019 + %1035 = OpFDiv %float %1034 %1023 + %1036 = OpExtInst %float %1 Log %float_0_180000007 + %1037 = OpExtInst %float %1 Log %float_10 + %1038 = OpFDiv %float %1036 %1037 + %1039 = OpFSub %float %float_2 %1035 + %1040 = OpFDiv %float %1035 %1039 + %1041 = OpExtInst %float %1 Log %1040 + %1042 = OpFMul %float %float_0_5 %1041 + %1043 = OpAccessChain %_ptr_Uniform_float %_Globals %int_10 + %1044 = OpLoad %float %1043 + %1045 = OpFDiv %float %1023 %1044 + %1046 = OpFMul %float %1042 %1045 + %1047 = OpFSub %float %1038 %1046 + OpBranch %1031 + %1032 = OpLabel + %1048 = OpFSub %float %float_0_819999993 %1022 + %1049 = OpAccessChain %_ptr_Uniform_float %_Globals %int_10 + %1050 = OpLoad %float %1049 + %1051 = OpFDiv %float %1048 %1050 + %1052 = OpExtInst %float %1 Log %float_0_180000007 + %1053 = OpExtInst %float %1 Log %float_10 + %1054 = OpFDiv %float %1052 %1053 + %1055 = OpFAdd %float %1051 %1054 + OpBranch %1031 + %1031 = OpLabel + %1056 = OpPhi %float %1047 %1033 %1055 %1032 + %1057 = OpFSub %float %float_1 %1022 + %1058 = OpAccessChain %_ptr_Uniform_float %_Globals %int_10 + %1059 = OpLoad %float %1058 + %1060 = OpFDiv %float %1057 %1059 + %1061 = OpFSub %float %1060 %1056 + %1062 = OpFDiv %float %1028 %1059 + %1063 = OpFSub %float %1062 %1061 + %1064 = OpExtInst %v3float %1 Log %1017 + %1065 = OpExtInst %float %1 Log %float_10 + %1066 = OpCompositeConstruct %v3float %1065 %1065 %1065 + %1067 = OpFDiv %v3float %1064 %1066 + %1068 = OpCompositeConstruct %v3float %1059 %1059 %1059 + %1069 = OpCompositeConstruct %v3float %1061 %1061 %1061 + %1070 = OpFAdd %v3float %1067 %1069 + %1071 = OpFMul %v3float %1068 %1070 + %1072 = OpFNegate %float %1019 + %1073 = OpCompositeConstruct %v3float %1072 %1072 %1072 + %1074 = OpFMul %float %float_2 %1023 + %1075 = OpCompositeConstruct %v3float %1074 %1074 %1074 + %1076 = OpFMul %float %float_n2 %1059 + %1077 = OpFDiv %float %1076 %1023 + %1078 = OpCompositeConstruct %v3float %1077 %1077 %1077 + %1079 = OpCompositeConstruct %v3float %1056 %1056 %1056 + %1080 = OpFSub %v3float %1067 %1079 + %1081 = OpFMul %v3float %1078 %1080 + %1082 = OpExtInst %v3float %1 Exp %1081 + %1083 = OpFAdd %v3float %135 %1082 + %1084 = OpFDiv %v3float %1075 %1083 + %1085 = OpFAdd %v3float %1073 %1084 + %1086 = OpCompositeConstruct %v3float %1026 %1026 %1026 + %1087 = OpFMul %float %float_2 %1029 + %1088 = OpCompositeConstruct %v3float %1087 %1087 %1087 + %1089 = OpFMul %float %float_2 %1059 + %1090 = OpFDiv %float %1089 %1029 + %1091 = OpCompositeConstruct %v3float %1090 %1090 %1090 + %1092 = OpCompositeConstruct %v3float %1063 %1063 %1063 + %1093 = OpFSub %v3float %1067 %1092 + %1094 = OpFMul %v3float %1091 %1093 + %1095 = OpExtInst %v3float %1 Exp %1094 + %1096 = OpFAdd %v3float %135 %1095 + %1097 = OpFDiv %v3float %1088 %1096 + %1098 = OpFSub %v3float %1086 %1097 + %1099 = OpFOrdLessThan %v3bool %1067 %1079 + %1100 = OpSelect %v3float %1099 %1085 %1071 + %1101 = OpFOrdGreaterThan %v3bool %1067 %1092 + %1102 = OpSelect %v3float %1101 %1098 %1071 + %1103 = OpFSub %float %1063 %1056 + %1104 = OpCompositeConstruct %v3float %1103 %1103 %1103 + %1105 = OpFDiv %v3float %1080 %1104 + %1106 = OpExtInst %v3float %1 FClamp %1105 %132 %135 + %1107 = OpFOrdLessThan %bool %1063 %1056 + %1108 = OpFSub %v3float %135 %1106 + %1109 = OpCompositeConstruct %v3bool %1107 %1107 %1107 + %1110 = OpSelect %v3float %1109 %1108 %1106 + %1111 = OpFMul %v3float %239 %1110 + %1112 = OpFSub %v3float %238 %1111 + %1113 = OpFMul %v3float %1112 %1110 + %1114 = OpFMul %v3float %1113 %1110 + %1115 = OpExtInst %v3float %1 FMix %1100 %1102 %1114 + %1116 = OpDot %float %1115 %67 + %1117 = OpCompositeConstruct %v3float %1116 %1116 %1116 + %1118 = OpExtInst %v3float %1 FMix %1117 %1115 %241 + %1119 = OpExtInst %v3float %1 FMax %132 %1118 + %1120 = OpVectorTimesMatrix %v3float %1119 %910 + %1121 = OpExtInst %v3float %1 FMix %1119 %1120 %914 + %1122 = OpVectorTimesMatrix %v3float %1121 %549 + %1123 = OpExtInst %v3float %1 FMax %132 %1122 + %1124 = OpFOrdEqual %bool %720 %float_0 + OpSelectionMerge %1125 DontFlatten + OpBranchConditional %1124 %1126 %1125 + %1126 = OpLabel + %1127 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_2 + %1128 = OpLoad %v4float %1127 + %1129 = OpVectorShuffle %v3float %1128 %1128 0 1 2 + %1130 = OpDot %float %906 %1129 + %1131 = OpCompositeInsert %v3float %1130 %391 0 + %1132 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_3 + %1133 = OpLoad %v4float %1132 + %1134 = OpVectorShuffle %v3float %1133 %1133 0 1 2 + %1135 = OpDot %float %906 %1134 + %1136 = OpCompositeInsert %v3float %1135 %1131 1 + %1137 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_4 + %1138 = OpLoad %v4float %1137 + %1139 = OpVectorShuffle %v3float %1138 %1138 0 1 2 + %1140 = OpDot %float %906 %1139 + %1141 = OpCompositeInsert %v3float %1140 %1136 2 + %1142 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_8 + %1143 = OpLoad %v4float %1142 + %1144 = OpVectorShuffle %v3float %1143 %1143 0 1 2 + %1145 = OpLoad %v4float %718 + %1146 = OpVectorShuffle %v3float %1145 %1145 0 1 2 + %1147 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_7 + %1148 = OpLoad %v4float %1147 + %1149 = OpVectorShuffle %v3float %1148 %1148 0 1 2 + %1150 = OpDot %float %906 %1149 + %1151 = OpFAdd %float %1150 %float_1 + %1152 = OpFDiv %float %float_1 %1151 + %1153 = OpCompositeConstruct %v3float %1152 %1152 %1152 + %1154 = OpFMul %v3float %1146 %1153 + %1155 = OpFAdd %v3float %1144 %1154 + %1156 = OpFMul %v3float %1141 %1155 + %1157 = OpExtInst %v3float %1 FMax %132 %1156 + %1158 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_5 + %1159 = OpLoad %v4float %1158 + %1160 = OpVectorShuffle %v3float %1159 %1159 0 0 0 + %1161 = OpFSub %v3float %1160 %1157 + %1162 = OpExtInst %v3float %1 FMax %132 %1161 + %1163 = OpVectorShuffle %v3float %1159 %1159 2 2 2 + %1164 = OpExtInst %v3float %1 FMax %1157 %1163 + %1165 = OpExtInst %v3float %1 FClamp %1157 %1160 %1163 + %1166 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_6 + %1167 = OpLoad %v4float %1166 + %1168 = OpVectorShuffle %v3float %1167 %1167 0 0 0 + %1169 = OpFMul %v3float %1164 %1168 + %1170 = OpVectorShuffle %v3float %1167 %1167 1 1 1 + %1171 = OpFAdd %v3float %1169 %1170 + %1172 = OpVectorShuffle %v3float %1159 %1159 3 3 3 + %1173 = OpFAdd %v3float %1164 %1172 + %1174 = OpFDiv %v3float %135 %1173 + %1175 = OpFMul %v3float %1171 %1174 + %1176 = OpVectorShuffle %v3float %1138 %1138 3 3 3 + %1177 = OpFMul %v3float %1165 %1176 + %1178 = OpVectorShuffle %v3float %1128 %1128 3 3 3 + %1179 = OpFMul %v3float %1162 %1178 + %1180 = OpVectorShuffle %v3float %1159 %1159 1 1 1 + %1181 = OpFAdd %v3float %1162 %1180 + %1182 = OpFDiv %v3float %135 %1181 + %1183 = OpFMul %v3float %1179 %1182 + %1184 = OpVectorShuffle %v3float %1133 %1133 3 3 3 + %1185 = OpFAdd %v3float %1183 %1184 + %1186 = OpFAdd %v3float %1177 %1185 + %1187 = OpFAdd %v3float %1175 %1186 + %1188 = OpFSub %v3float %1187 %248 + OpBranch %1125 + %1125 = OpLabel + %1189 = OpPhi %v3float %1123 %1031 %1188 %1126 + %1190 = OpAccessChain %_ptr_Uniform_float %_Globals %int_0 %int_0 + %1191 = OpLoad %float %1190 + %1192 = OpCompositeConstruct %v3float %1191 %1191 %1191 + %1193 = OpFMul %v3float %1189 %1189 + %1194 = OpFMul %v3float %1192 %1193 + %1195 = OpAccessChain %_ptr_Uniform_float %_Globals %int_0 %int_1 + %1196 = OpLoad %float %1195 + %1197 = OpCompositeConstruct %v3float %1196 %1196 %1196 + %1198 = OpFMul %v3float %1197 %1189 + %1199 = OpFAdd %v3float %1194 %1198 + %1200 = OpAccessChain %_ptr_Uniform_float %_Globals %int_0 %int_2 + %1201 = OpLoad %float %1200 + %1202 = OpCompositeConstruct %v3float %1201 %1201 %1201 + %1203 = OpFAdd %v3float %1199 %1202 + %1204 = OpAccessChain %_ptr_Uniform_v3float %_Globals %int_15 + %1205 = OpLoad %v3float %1204 + %1206 = OpFMul %v3float %1203 %1205 + %1207 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_16 + %1208 = OpLoad %v4float %1207 + %1209 = OpVectorShuffle %v3float %1208 %1208 0 1 2 + %1210 = OpAccessChain %_ptr_Uniform_float %_Globals %int_16 %int_3 + %1211 = OpLoad %float %1210 + %1212 = OpCompositeConstruct %v3float %1211 %1211 %1211 + %1213 = OpExtInst %v3float %1 FMix %1206 %1209 %1212 + %1214 = OpExtInst %v3float %1 FMax %132 %1213 + %1215 = OpAccessChain %_ptr_Uniform_float %_Globals %int_1 %int_1 + %1216 = OpLoad %float %1215 + %1217 = OpCompositeConstruct %v3float %1216 %1216 %1216 + %1218 = OpExtInst %v3float %1 Pow %1214 %1217 + %1219 = OpIEqual %bool %579 %uint_0 + OpSelectionMerge %1220 DontFlatten + OpBranchConditional %1219 %1221 %1222 + %1222 = OpLabel + %1223 = OpIEqual %bool %579 %uint_1 + OpSelectionMerge %1224 None + OpBranchConditional %1223 %1225 %1226 + %1226 = OpLabel + %1227 = OpIEqual %bool %579 %uint_3 + %1228 = OpIEqual %bool %579 %uint_5 + %1229 = OpLogicalOr %bool %1227 %1228 + OpSelectionMerge %1230 None + OpBranchConditional %1229 %1231 %1232 + %1232 = OpLabel + %1233 = OpIEqual %bool %579 %uint_4 + %1234 = OpIEqual %bool %579 %uint_6 + %1235 = OpLogicalOr %bool %1233 %1234 + OpSelectionMerge %1236 None + OpBranchConditional %1235 %1237 %1238 + %1238 = OpLabel + %1239 = OpIEqual %bool %579 %uint_7 + OpSelectionMerge %1240 None + OpBranchConditional %1239 %1241 %1242 + %1242 = OpLabel + %1243 = OpVectorTimesMatrix %v3float %1218 %547 + %1244 = OpVectorTimesMatrix %v3float %1243 %576 + %1245 = OpAccessChain %_ptr_Uniform_float %_Globals %int_1 %int_2 + %1246 = OpLoad %float %1245 + %1247 = OpCompositeConstruct %v3float %1246 %1246 %1246 + %1248 = OpExtInst %v3float %1 Pow %1244 %1247 + OpBranch %1240 + %1241 = OpLabel + %1249 = OpVectorTimesMatrix %v3float %906 %547 + %1250 = OpVectorTimesMatrix %v3float %1249 %576 + %1251 = OpFMul %v3float %1250 %496 + %1252 = OpExtInst %v3float %1 Pow %1251 %263 + %1253 = OpFMul %v3float %184 %1252 + %1254 = OpFAdd %v3float %183 %1253 + %1255 = OpFMul %v3float %185 %1252 + %1256 = OpFAdd %v3float %135 %1255 + %1257 = OpFDiv %v3float %135 %1256 + %1258 = OpFMul %v3float %1254 %1257 + %1259 = OpExtInst %v3float %1 Pow %1258 %264 + OpBranch %1240 + %1240 = OpLabel + %1260 = OpPhi %v3float %1248 %1242 %1259 %1241 + OpBranch %1236 + %1237 = OpLabel + %1261 = OpMatrixTimesMatrix %mat3v3float %546 %399 + %1262 = OpFMul %v3float %906 %262 + %1263 = OpVectorTimesMatrix %v3float %1262 %1261 + %1264 = OpCompositeExtract %float %1263 0 + %1265 = OpCompositeExtract %float %1263 1 + %1266 = OpExtInst %float %1 FMin %1264 %1265 + %1267 = OpCompositeExtract %float %1263 2 + %1268 = OpExtInst %float %1 FMin %1266 %1267 + %1269 = OpExtInst %float %1 FMax %1264 %1265 + %1270 = OpExtInst %float %1 FMax %1269 %1267 + %1271 = OpExtInst %float %1 FMax %1270 %float_1_00000001en10 + %1272 = OpExtInst %float %1 FMax %1268 %float_1_00000001en10 + %1273 = OpFSub %float %1271 %1272 + %1274 = OpExtInst %float %1 FMax %1270 %float_0_00999999978 + %1275 = OpFDiv %float %1273 %1274 + %1276 = OpFSub %float %1267 %1265 + %1277 = OpFMul %float %1267 %1276 + %1278 = OpFSub %float %1265 %1264 + %1279 = OpFMul %float %1265 %1278 + %1280 = OpFAdd %float %1277 %1279 + %1281 = OpFSub %float %1264 %1267 + %1282 = OpFMul %float %1264 %1281 + %1283 = OpFAdd %float %1280 %1282 + %1284 = OpExtInst %float %1 Sqrt %1283 + %1285 = OpFAdd %float %1267 %1265 + %1286 = OpFAdd %float %1285 %1264 + %1287 = OpFMul %float %float_1_75 %1284 + %1288 = OpFAdd %float %1286 %1287 + %1289 = OpFMul %float %1288 %float_0_333333343 + %1290 = OpFSub %float %1275 %float_0_400000006 + %1291 = OpFMul %float %1290 %float_5 + %1292 = OpFMul %float %1290 %float_2_5 + %1293 = OpExtInst %float %1 FAbs %1292 + %1294 = OpFSub %float %float_1 %1293 + %1295 = OpExtInst %float %1 FMax %1294 %float_0 + %1296 = OpExtInst %float %1 FSign %1291 + %1297 = OpConvertFToS %int %1296 + %1298 = OpConvertSToF %float %1297 + %1299 = OpFMul %float %1295 %1295 + %1300 = OpFSub %float %float_1 %1299 + %1301 = OpFMul %float %1298 %1300 + %1302 = OpFAdd %float %float_1 %1301 + %1303 = OpFMul %float %1302 %float_0_0250000004 + %1304 = OpFOrdLessThanEqual %bool %1289 %float_0_0533333346 + OpSelectionMerge %1305 None + OpBranchConditional %1304 %1306 %1307 + %1307 = OpLabel + %1308 = OpFOrdGreaterThanEqual %bool %1289 %float_0_159999996 + OpSelectionMerge %1309 None + OpBranchConditional %1308 %1310 %1311 + %1311 = OpLabel + %1312 = OpFDiv %float %float_0_239999995 %1288 + %1313 = OpFSub %float %1312 %float_0_5 + %1314 = OpFMul %float %1303 %1313 + OpBranch %1309 + %1310 = OpLabel + OpBranch %1309 + %1309 = OpLabel + %1315 = OpPhi %float %1314 %1311 %float_0 %1310 + OpBranch %1305 + %1306 = OpLabel + OpBranch %1305 + %1305 = OpLabel + %1316 = OpPhi %float %1315 %1309 %1303 %1306 + %1317 = OpFAdd %float %float_1 %1316 + %1318 = OpCompositeConstruct %v3float %1317 %1317 %1317 + %1319 = OpFMul %v3float %1263 %1318 + %1320 = OpCompositeExtract %float %1319 0 + %1321 = OpCompositeExtract %float %1319 1 + %1322 = OpFOrdEqual %bool %1320 %1321 + %1323 = OpCompositeExtract %float %1319 2 + %1324 = OpFOrdEqual %bool %1321 %1323 + %1325 = OpLogicalAnd %bool %1322 %1324 + OpSelectionMerge %1326 None + OpBranchConditional %1325 %1327 %1328 + %1328 = OpLabel + %1329 = OpExtInst %float %1 Sqrt %float_3 + %1330 = OpFSub %float %1321 %1323 + %1331 = OpFMul %float %1329 %1330 + %1332 = OpFMul %float %float_2 %1320 + %1333 = OpFSub %float %1332 %1321 + %1334 = OpFSub %float %1333 %1323 + %1335 = OpExtInst %float %1 Atan2 %1331 %1334 + %1336 = OpFMul %float %float_57_2957764 %1335 + OpBranch %1326 + %1327 = OpLabel + OpBranch %1326 + %1326 = OpLabel + %1337 = OpPhi %float %1336 %1328 %float_0 %1327 + %1338 = OpFOrdLessThan %bool %1337 %float_0 + OpSelectionMerge %1339 None + OpBranchConditional %1338 %1340 %1339 + %1340 = OpLabel + %1341 = OpFAdd %float %1337 %float_360 + OpBranch %1339 + %1339 = OpLabel + %1342 = OpPhi %float %1337 %1326 %1341 %1340 + %1343 = OpExtInst %float %1 FClamp %1342 %float_0 %float_360 + %1344 = OpFOrdGreaterThan %bool %1343 %float_180 + OpSelectionMerge %1345 None + OpBranchConditional %1344 %1346 %1345 + %1346 = OpLabel + %1347 = OpFSub %float %1343 %float_360 + OpBranch %1345 + %1345 = OpLabel + %1348 = OpPhi %float %1343 %1339 %1347 %1346 + %1349 = OpFOrdGreaterThan %bool %1348 %float_n67_5 + %1350 = OpFOrdLessThan %bool %1348 %float_67_5 + %1351 = OpLogicalAnd %bool %1349 %1350 + OpSelectionMerge %1352 None + OpBranchConditional %1351 %1353 %1352 + %1353 = OpLabel + %1354 = OpFSub %float %1348 %float_n67_5 + %1355 = OpFMul %float %1354 %float_0_0296296291 + %1356 = OpConvertFToS %int %1355 + %1357 = OpConvertSToF %float %1356 + %1358 = OpFSub %float %1355 %1357 + %1359 = OpFMul %float %1358 %1358 + %1360 = OpFMul %float %1359 %1358 + %1361 = OpIEqual %bool %1356 %int_3 + OpSelectionMerge %1362 None + OpBranchConditional %1361 %1363 %1364 + %1364 = OpLabel + %1365 = OpIEqual %bool %1356 %int_2 + OpSelectionMerge %1366 None + OpBranchConditional %1365 %1367 %1368 + %1368 = OpLabel + %1369 = OpIEqual %bool %1356 %int_1 + OpSelectionMerge %1370 None + OpBranchConditional %1369 %1371 %1372 + %1372 = OpLabel + %1373 = OpIEqual %bool %1356 %int_0 + OpSelectionMerge %1374 None + OpBranchConditional %1373 %1375 %1376 + %1376 = OpLabel + OpBranch %1374 + %1375 = OpLabel + %1377 = OpFMul %float %1360 %float_0_166666672 + OpBranch %1374 + %1374 = OpLabel + %1378 = OpPhi %float %float_0 %1376 %1377 %1375 + OpBranch %1370 + %1371 = OpLabel + %1379 = OpFMul %float %1360 %float_n0_5 + %1380 = OpFMul %float %1359 %float_0_5 + %1381 = OpFAdd %float %1379 %1380 + %1382 = OpFMul %float %1358 %float_0_5 + %1383 = OpFAdd %float %1381 %1382 + %1384 = OpFAdd %float %1383 %float_0_166666672 + OpBranch %1370 + %1370 = OpLabel + %1385 = OpPhi %float %1378 %1374 %1384 %1371 + OpBranch %1366 + %1367 = OpLabel + %1386 = OpFMul %float %1360 %float_0_5 + %1387 = OpFMul %float %1359 %float_n1 + %1388 = OpFAdd %float %1386 %1387 + %1389 = OpFAdd %float %1388 %float_0_666666687 + OpBranch %1366 + %1366 = OpLabel + %1390 = OpPhi %float %1385 %1370 %1389 %1367 + OpBranch %1362 + %1363 = OpLabel + %1391 = OpFMul %float %1360 %float_n0_166666672 + %1392 = OpFMul %float %1359 %float_0_5 + %1393 = OpFAdd %float %1391 %1392 + %1394 = OpFMul %float %1358 %float_n0_5 + %1395 = OpFAdd %float %1393 %1394 + %1396 = OpFAdd %float %1395 %float_0_166666672 + OpBranch %1362 + %1362 = OpLabel + %1397 = OpPhi %float %1390 %1366 %1396 %1363 + OpBranch %1352 + %1352 = OpLabel + %1398 = OpPhi %float %float_0 %1345 %1397 %1362 + %1399 = OpFMul %float %1398 %float_1_5 + %1400 = OpFMul %float %1399 %1275 + %1401 = OpFSub %float %float_0_0299999993 %1320 + %1402 = OpFMul %float %1400 %1401 + %1403 = OpFMul %float %1402 %float_0_180000007 + %1404 = OpFAdd %float %1320 %1403 + %1405 = OpCompositeInsert %v3float %1404 %1319 0 + %1406 = OpExtInst %v3float %1 FClamp %1405 %132 %314 + %1407 = OpVectorTimesMatrix %v3float %1406 %410 + %1408 = OpExtInst %v3float %1 FClamp %1407 %132 %314 + %1409 = OpDot %float %1408 %67 + %1410 = OpCompositeConstruct %v3float %1409 %1409 %1409 + %1411 = OpExtInst %v3float %1 FMix %1410 %1408 %228 + %1412 = OpCompositeExtract %float %1411 0 + %1413 = OpExtInst %float %1 Exp2 %float_n15 + %1414 = OpFMul %float %float_0_179999992 %1413 + %1415 = OpExtInst %float %1 Exp2 %float_18 + %1416 = OpFMul %float %float_0_179999992 %1415 + OpStore %502 %475 + OpStore %501 %476 + %1417 = OpFOrdLessThanEqual %bool %1412 %float_0 + %1418 = OpExtInst %float %1 Exp2 %float_n14 + %1419 = OpSelect %float %1417 %1418 %1412 + %1420 = OpExtInst %float %1 Log %1419 + %1421 = OpFDiv %float %1420 %1065 + %1422 = OpExtInst %float %1 Log %1414 + %1423 = OpFDiv %float %1422 %1065 + %1424 = OpFOrdLessThanEqual %bool %1421 %1423 + OpSelectionMerge %1425 None + OpBranchConditional %1424 %1426 %1427 + %1427 = OpLabel + %1428 = OpFOrdGreaterThan %bool %1421 %1423 + %1429 = OpExtInst %float %1 Log %float_0_180000007 + %1430 = OpFDiv %float %1429 %1065 + %1431 = OpFOrdLessThan %bool %1421 %1430 + %1432 = OpLogicalAnd %bool %1428 %1431 + OpSelectionMerge %1433 None + OpBranchConditional %1432 %1434 %1435 + %1435 = OpLabel + %1436 = OpFOrdGreaterThanEqual %bool %1421 %1430 + %1437 = OpExtInst %float %1 Log %1416 + %1438 = OpFDiv %float %1437 %1065 + %1439 = OpFOrdLessThan %bool %1421 %1438 + %1440 = OpLogicalAnd %bool %1436 %1439 + OpSelectionMerge %1441 None + OpBranchConditional %1440 %1442 %1443 + %1443 = OpLabel + %1444 = OpExtInst %float %1 Log %float_10000 + %1445 = OpFDiv %float %1444 %1065 + OpBranch %1441 + %1442 = OpLabel + %1446 = OpFSub %float %1421 %1430 + %1447 = OpFMul %float %float_3 %1446 + %1448 = OpFSub %float %1438 %1430 + %1449 = OpFDiv %float %1447 %1448 + %1450 = OpConvertFToS %int %1449 + %1451 = OpConvertSToF %float %1450 + %1452 = OpFSub %float %1449 %1451 + %1453 = OpAccessChain %_ptr_Function_float %501 %1450 + %1454 = OpLoad %float %1453 + %1455 = OpIAdd %int %1450 %int_1 + %1456 = OpAccessChain %_ptr_Function_float %501 %1455 + %1457 = OpLoad %float %1456 + %1458 = OpIAdd %int %1450 %int_2 + %1459 = OpAccessChain %_ptr_Function_float %501 %1458 + %1460 = OpLoad %float %1459 + %1461 = OpCompositeConstruct %v3float %1454 %1457 %1460 + %1462 = OpFMul %float %1452 %1452 + %1463 = OpCompositeConstruct %v3float %1462 %1452 %float_1 + %1464 = OpMatrixTimesVector %v3float %442 %1461 + %1465 = OpDot %float %1463 %1464 + OpBranch %1441 + %1441 = OpLabel + %1466 = OpPhi %float %1445 %1443 %1465 %1442 + OpBranch %1433 + %1434 = OpLabel + %1467 = OpFSub %float %1421 %1423 + %1468 = OpFMul %float %float_3 %1467 + %1469 = OpFSub %float %1430 %1423 + %1470 = OpFDiv %float %1468 %1469 + %1471 = OpConvertFToS %int %1470 + %1472 = OpConvertSToF %float %1471 + %1473 = OpFSub %float %1470 %1472 + %1474 = OpAccessChain %_ptr_Function_float %502 %1471 + %1475 = OpLoad %float %1474 + %1476 = OpIAdd %int %1471 %int_1 + %1477 = OpAccessChain %_ptr_Function_float %502 %1476 + %1478 = OpLoad %float %1477 + %1479 = OpIAdd %int %1471 %int_2 + %1480 = OpAccessChain %_ptr_Function_float %502 %1479 + %1481 = OpLoad %float %1480 + %1482 = OpCompositeConstruct %v3float %1475 %1478 %1481 + %1483 = OpFMul %float %1473 %1473 + %1484 = OpCompositeConstruct %v3float %1483 %1473 %float_1 + %1485 = OpMatrixTimesVector %v3float %442 %1482 + %1486 = OpDot %float %1484 %1485 + OpBranch %1433 + %1433 = OpLabel + %1487 = OpPhi %float %1466 %1441 %1486 %1434 + OpBranch %1425 + %1426 = OpLabel + %1488 = OpExtInst %float %1 Log %float_9_99999975en05 + %1489 = OpFDiv %float %1488 %1065 + OpBranch %1425 + %1425 = OpLabel + %1490 = OpPhi %float %1487 %1433 %1489 %1426 + %1491 = OpExtInst %float %1 Pow %float_10 %1490 + %1492 = OpCompositeInsert %v3float %1491 %391 0 + %1493 = OpCompositeExtract %float %1411 1 + OpStore %504 %475 + OpStore %503 %476 + %1494 = OpFOrdLessThanEqual %bool %1493 %float_0 + %1495 = OpSelect %float %1494 %1418 %1493 + %1496 = OpExtInst %float %1 Log %1495 + %1497 = OpFDiv %float %1496 %1065 + %1498 = OpFOrdLessThanEqual %bool %1497 %1423 + OpSelectionMerge %1499 None + OpBranchConditional %1498 %1500 %1501 + %1501 = OpLabel + %1502 = OpFOrdGreaterThan %bool %1497 %1423 + %1503 = OpExtInst %float %1 Log %float_0_180000007 + %1504 = OpFDiv %float %1503 %1065 + %1505 = OpFOrdLessThan %bool %1497 %1504 + %1506 = OpLogicalAnd %bool %1502 %1505 + OpSelectionMerge %1507 None + OpBranchConditional %1506 %1508 %1509 + %1509 = OpLabel + %1510 = OpFOrdGreaterThanEqual %bool %1497 %1504 + %1511 = OpExtInst %float %1 Log %1416 + %1512 = OpFDiv %float %1511 %1065 + %1513 = OpFOrdLessThan %bool %1497 %1512 + %1514 = OpLogicalAnd %bool %1510 %1513 + OpSelectionMerge %1515 None + OpBranchConditional %1514 %1516 %1517 + %1517 = OpLabel + %1518 = OpExtInst %float %1 Log %float_10000 + %1519 = OpFDiv %float %1518 %1065 + OpBranch %1515 + %1516 = OpLabel + %1520 = OpFSub %float %1497 %1504 + %1521 = OpFMul %float %float_3 %1520 + %1522 = OpFSub %float %1512 %1504 + %1523 = OpFDiv %float %1521 %1522 + %1524 = OpConvertFToS %int %1523 + %1525 = OpConvertSToF %float %1524 + %1526 = OpFSub %float %1523 %1525 + %1527 = OpAccessChain %_ptr_Function_float %503 %1524 + %1528 = OpLoad %float %1527 + %1529 = OpIAdd %int %1524 %int_1 + %1530 = OpAccessChain %_ptr_Function_float %503 %1529 + %1531 = OpLoad %float %1530 + %1532 = OpIAdd %int %1524 %int_2 + %1533 = OpAccessChain %_ptr_Function_float %503 %1532 + %1534 = OpLoad %float %1533 + %1535 = OpCompositeConstruct %v3float %1528 %1531 %1534 + %1536 = OpFMul %float %1526 %1526 + %1537 = OpCompositeConstruct %v3float %1536 %1526 %float_1 + %1538 = OpMatrixTimesVector %v3float %442 %1535 + %1539 = OpDot %float %1537 %1538 + OpBranch %1515 + %1515 = OpLabel + %1540 = OpPhi %float %1519 %1517 %1539 %1516 + OpBranch %1507 + %1508 = OpLabel + %1541 = OpFSub %float %1497 %1423 + %1542 = OpFMul %float %float_3 %1541 + %1543 = OpFSub %float %1504 %1423 + %1544 = OpFDiv %float %1542 %1543 + %1545 = OpConvertFToS %int %1544 + %1546 = OpConvertSToF %float %1545 + %1547 = OpFSub %float %1544 %1546 + %1548 = OpAccessChain %_ptr_Function_float %504 %1545 + %1549 = OpLoad %float %1548 + %1550 = OpIAdd %int %1545 %int_1 + %1551 = OpAccessChain %_ptr_Function_float %504 %1550 + %1552 = OpLoad %float %1551 + %1553 = OpIAdd %int %1545 %int_2 + %1554 = OpAccessChain %_ptr_Function_float %504 %1553 + %1555 = OpLoad %float %1554 + %1556 = OpCompositeConstruct %v3float %1549 %1552 %1555 + %1557 = OpFMul %float %1547 %1547 + %1558 = OpCompositeConstruct %v3float %1557 %1547 %float_1 + %1559 = OpMatrixTimesVector %v3float %442 %1556 + %1560 = OpDot %float %1558 %1559 + OpBranch %1507 + %1507 = OpLabel + %1561 = OpPhi %float %1540 %1515 %1560 %1508 + OpBranch %1499 + %1500 = OpLabel + %1562 = OpExtInst %float %1 Log %float_9_99999975en05 + %1563 = OpFDiv %float %1562 %1065 + OpBranch %1499 + %1499 = OpLabel + %1564 = OpPhi %float %1561 %1507 %1563 %1500 + %1565 = OpExtInst %float %1 Pow %float_10 %1564 + %1566 = OpCompositeInsert %v3float %1565 %1492 1 + %1567 = OpCompositeExtract %float %1411 2 + OpStore %506 %475 + OpStore %505 %476 + %1568 = OpFOrdLessThanEqual %bool %1567 %float_0 + %1569 = OpSelect %float %1568 %1418 %1567 + %1570 = OpExtInst %float %1 Log %1569 + %1571 = OpFDiv %float %1570 %1065 + %1572 = OpFOrdLessThanEqual %bool %1571 %1423 + OpSelectionMerge %1573 None + OpBranchConditional %1572 %1574 %1575 + %1575 = OpLabel + %1576 = OpFOrdGreaterThan %bool %1571 %1423 + %1577 = OpExtInst %float %1 Log %float_0_180000007 + %1578 = OpFDiv %float %1577 %1065 + %1579 = OpFOrdLessThan %bool %1571 %1578 + %1580 = OpLogicalAnd %bool %1576 %1579 + OpSelectionMerge %1581 None + OpBranchConditional %1580 %1582 %1583 + %1583 = OpLabel + %1584 = OpFOrdGreaterThanEqual %bool %1571 %1578 + %1585 = OpExtInst %float %1 Log %1416 + %1586 = OpFDiv %float %1585 %1065 + %1587 = OpFOrdLessThan %bool %1571 %1586 + %1588 = OpLogicalAnd %bool %1584 %1587 + OpSelectionMerge %1589 None + OpBranchConditional %1588 %1590 %1591 + %1591 = OpLabel + %1592 = OpExtInst %float %1 Log %float_10000 + %1593 = OpFDiv %float %1592 %1065 + OpBranch %1589 + %1590 = OpLabel + %1594 = OpFSub %float %1571 %1578 + %1595 = OpFMul %float %float_3 %1594 + %1596 = OpFSub %float %1586 %1578 + %1597 = OpFDiv %float %1595 %1596 + %1598 = OpConvertFToS %int %1597 + %1599 = OpConvertSToF %float %1598 + %1600 = OpFSub %float %1597 %1599 + %1601 = OpAccessChain %_ptr_Function_float %505 %1598 + %1602 = OpLoad %float %1601 + %1603 = OpIAdd %int %1598 %int_1 + %1604 = OpAccessChain %_ptr_Function_float %505 %1603 + %1605 = OpLoad %float %1604 + %1606 = OpIAdd %int %1598 %int_2 + %1607 = OpAccessChain %_ptr_Function_float %505 %1606 + %1608 = OpLoad %float %1607 + %1609 = OpCompositeConstruct %v3float %1602 %1605 %1608 + %1610 = OpFMul %float %1600 %1600 + %1611 = OpCompositeConstruct %v3float %1610 %1600 %float_1 + %1612 = OpMatrixTimesVector %v3float %442 %1609 + %1613 = OpDot %float %1611 %1612 + OpBranch %1589 + %1589 = OpLabel + %1614 = OpPhi %float %1593 %1591 %1613 %1590 + OpBranch %1581 + %1582 = OpLabel + %1615 = OpFSub %float %1571 %1423 + %1616 = OpFMul %float %float_3 %1615 + %1617 = OpFSub %float %1578 %1423 + %1618 = OpFDiv %float %1616 %1617 + %1619 = OpConvertFToS %int %1618 + %1620 = OpConvertSToF %float %1619 + %1621 = OpFSub %float %1618 %1620 + %1622 = OpAccessChain %_ptr_Function_float %506 %1619 + %1623 = OpLoad %float %1622 + %1624 = OpIAdd %int %1619 %int_1 + %1625 = OpAccessChain %_ptr_Function_float %506 %1624 + %1626 = OpLoad %float %1625 + %1627 = OpIAdd %int %1619 %int_2 + %1628 = OpAccessChain %_ptr_Function_float %506 %1627 + %1629 = OpLoad %float %1628 + %1630 = OpCompositeConstruct %v3float %1623 %1626 %1629 + %1631 = OpFMul %float %1621 %1621 + %1632 = OpCompositeConstruct %v3float %1631 %1621 %float_1 + %1633 = OpMatrixTimesVector %v3float %442 %1630 + %1634 = OpDot %float %1632 %1633 + OpBranch %1581 + %1581 = OpLabel + %1635 = OpPhi %float %1614 %1589 %1634 %1582 + OpBranch %1573 + %1574 = OpLabel + %1636 = OpExtInst %float %1 Log %float_9_99999975en05 + %1637 = OpFDiv %float %1636 %1065 + OpBranch %1573 + %1573 = OpLabel + %1638 = OpPhi %float %1635 %1581 %1637 %1574 + %1639 = OpExtInst %float %1 Pow %float_10 %1638 + %1640 = OpCompositeInsert %v3float %1639 %1566 2 + %1641 = OpVectorTimesMatrix %v3float %1640 %414 + %1642 = OpVectorTimesMatrix %v3float %1641 %410 + %1643 = OpExtInst %float %1 Pow %float_2 %float_n12 + %1644 = OpFMul %float %float_0_179999992 %1643 + OpStore %514 %475 + OpStore %513 %476 + %1645 = OpFOrdLessThanEqual %bool %1644 %float_0 + %1646 = OpSelect %float %1645 %1418 %1644 + %1647 = OpExtInst %float %1 Log %1646 + %1648 = OpFDiv %float %1647 %1065 + %1649 = OpFOrdLessThanEqual %bool %1648 %1423 + OpSelectionMerge %1650 None + OpBranchConditional %1649 %1651 %1652 + %1652 = OpLabel + %1653 = OpFOrdGreaterThan %bool %1648 %1423 + %1654 = OpExtInst %float %1 Log %float_0_180000007 + %1655 = OpFDiv %float %1654 %1065 + %1656 = OpFOrdLessThan %bool %1648 %1655 + %1657 = OpLogicalAnd %bool %1653 %1656 + OpSelectionMerge %1658 None + OpBranchConditional %1657 %1659 %1660 + %1660 = OpLabel + %1661 = OpFOrdGreaterThanEqual %bool %1648 %1655 + %1662 = OpExtInst %float %1 Log %1416 + %1663 = OpFDiv %float %1662 %1065 + %1664 = OpFOrdLessThan %bool %1648 %1663 + %1665 = OpLogicalAnd %bool %1661 %1664 + OpSelectionMerge %1666 None + OpBranchConditional %1665 %1667 %1668 + %1668 = OpLabel + %1669 = OpExtInst %float %1 Log %float_10000 + %1670 = OpFDiv %float %1669 %1065 + OpBranch %1666 + %1667 = OpLabel + %1671 = OpFSub %float %1648 %1655 + %1672 = OpFMul %float %float_3 %1671 + %1673 = OpFSub %float %1663 %1655 + %1674 = OpFDiv %float %1672 %1673 + %1675 = OpConvertFToS %int %1674 + %1676 = OpConvertSToF %float %1675 + %1677 = OpFSub %float %1674 %1676 + %1678 = OpAccessChain %_ptr_Function_float %513 %1675 + %1679 = OpLoad %float %1678 + %1680 = OpIAdd %int %1675 %int_1 + %1681 = OpAccessChain %_ptr_Function_float %513 %1680 + %1682 = OpLoad %float %1681 + %1683 = OpIAdd %int %1675 %int_2 + %1684 = OpAccessChain %_ptr_Function_float %513 %1683 + %1685 = OpLoad %float %1684 + %1686 = OpCompositeConstruct %v3float %1679 %1682 %1685 + %1687 = OpFMul %float %1677 %1677 + %1688 = OpCompositeConstruct %v3float %1687 %1677 %float_1 + %1689 = OpMatrixTimesVector %v3float %442 %1686 + %1690 = OpDot %float %1688 %1689 + OpBranch %1666 + %1666 = OpLabel + %1691 = OpPhi %float %1670 %1668 %1690 %1667 + OpBranch %1658 + %1659 = OpLabel + %1692 = OpFSub %float %1648 %1423 + %1693 = OpFMul %float %float_3 %1692 + %1694 = OpFSub %float %1655 %1423 + %1695 = OpFDiv %float %1693 %1694 + %1696 = OpConvertFToS %int %1695 + %1697 = OpConvertSToF %float %1696 + %1698 = OpFSub %float %1695 %1697 + %1699 = OpAccessChain %_ptr_Function_float %514 %1696 + %1700 = OpLoad %float %1699 + %1701 = OpIAdd %int %1696 %int_1 + %1702 = OpAccessChain %_ptr_Function_float %514 %1701 + %1703 = OpLoad %float %1702 + %1704 = OpIAdd %int %1696 %int_2 + %1705 = OpAccessChain %_ptr_Function_float %514 %1704 + %1706 = OpLoad %float %1705 + %1707 = OpCompositeConstruct %v3float %1700 %1703 %1706 + %1708 = OpFMul %float %1698 %1698 + %1709 = OpCompositeConstruct %v3float %1708 %1698 %float_1 + %1710 = OpMatrixTimesVector %v3float %442 %1707 + %1711 = OpDot %float %1709 %1710 + OpBranch %1658 + %1658 = OpLabel + %1712 = OpPhi %float %1691 %1666 %1711 %1659 + OpBranch %1650 + %1651 = OpLabel + %1713 = OpExtInst %float %1 Log %float_9_99999975en05 + %1714 = OpFDiv %float %1713 %1065 + OpBranch %1650 + %1650 = OpLabel + %1715 = OpPhi %float %1712 %1658 %1714 %1651 + %1716 = OpExtInst %float %1 Pow %float_10 %1715 + OpStore %516 %475 + OpStore %515 %476 + %1717 = OpExtInst %float %1 Log %float_0_180000007 + %1718 = OpFDiv %float %1717 %1065 + %1719 = OpFOrdLessThanEqual %bool %1718 %1423 + OpSelectionMerge %1720 None + OpBranchConditional %1719 %1721 %1722 + %1722 = OpLabel + %1723 = OpFOrdGreaterThan %bool %1718 %1423 + %1724 = OpFOrdLessThan %bool %1718 %1718 + %1725 = OpLogicalAnd %bool %1723 %1724 + OpSelectionMerge %1726 None + OpBranchConditional %1725 %1727 %1728 + %1728 = OpLabel + %1729 = OpFOrdGreaterThanEqual %bool %1718 %1718 + %1730 = OpExtInst %float %1 Log %1416 + %1731 = OpFDiv %float %1730 %1065 + %1732 = OpFOrdLessThan %bool %1718 %1731 + %1733 = OpLogicalAnd %bool %1729 %1732 + OpSelectionMerge %1734 None + OpBranchConditional %1733 %1735 %1736 + %1736 = OpLabel + %1737 = OpExtInst %float %1 Log %float_10000 + %1738 = OpFDiv %float %1737 %1065 + OpBranch %1734 + %1735 = OpLabel + %1739 = OpFSub %float %1718 %1718 + %1740 = OpFMul %float %float_3 %1739 + %1741 = OpFSub %float %1731 %1718 + %1742 = OpFDiv %float %1740 %1741 + %1743 = OpConvertFToS %int %1742 + %1744 = OpConvertSToF %float %1743 + %1745 = OpFSub %float %1742 %1744 + %1746 = OpAccessChain %_ptr_Function_float %515 %1743 + %1747 = OpLoad %float %1746 + %1748 = OpIAdd %int %1743 %int_1 + %1749 = OpAccessChain %_ptr_Function_float %515 %1748 + %1750 = OpLoad %float %1749 + %1751 = OpIAdd %int %1743 %int_2 + %1752 = OpAccessChain %_ptr_Function_float %515 %1751 + %1753 = OpLoad %float %1752 + %1754 = OpCompositeConstruct %v3float %1747 %1750 %1753 + %1755 = OpFMul %float %1745 %1745 + %1756 = OpCompositeConstruct %v3float %1755 %1745 %float_1 + %1757 = OpMatrixTimesVector %v3float %442 %1754 + %1758 = OpDot %float %1756 %1757 + OpBranch %1734 + %1734 = OpLabel + %1759 = OpPhi %float %1738 %1736 %1758 %1735 + OpBranch %1726 + %1727 = OpLabel + %1760 = OpFSub %float %1718 %1423 + %1761 = OpFMul %float %float_3 %1760 + %1762 = OpAccessChain %_ptr_Function_float %516 %int_3 + %1763 = OpLoad %float %1762 + %1764 = OpAccessChain %_ptr_Function_float %516 %int_4 + %1765 = OpLoad %float %1764 + %1766 = OpAccessChain %_ptr_Function_float %516 %int_5 + %1767 = OpLoad %float %1766 + %1768 = OpCompositeConstruct %v3float %1763 %1765 %1767 + %1769 = OpMatrixTimesVector %v3float %442 %1768 + %1770 = OpCompositeExtract %float %1769 2 + OpBranch %1726 + %1726 = OpLabel + %1771 = OpPhi %float %1759 %1734 %1770 %1727 + OpBranch %1720 + %1721 = OpLabel + %1772 = OpExtInst %float %1 Log %float_9_99999975en05 + %1773 = OpFDiv %float %1772 %1065 + OpBranch %1720 + %1720 = OpLabel + %1774 = OpPhi %float %1771 %1726 %1773 %1721 + %1775 = OpExtInst %float %1 Pow %float_10 %1774 + %1776 = OpExtInst %float %1 Pow %float_2 %float_11 + %1777 = OpFMul %float %float_0_179999992 %1776 + OpStore %518 %475 + OpStore %517 %476 + %1778 = OpFOrdLessThanEqual %bool %1777 %float_0 + %1779 = OpSelect %float %1778 %1418 %1777 + %1780 = OpExtInst %float %1 Log %1779 + %1781 = OpFDiv %float %1780 %1065 + %1782 = OpFOrdLessThanEqual %bool %1781 %1423 + OpSelectionMerge %1783 None + OpBranchConditional %1782 %1784 %1785 + %1785 = OpLabel + %1786 = OpFOrdGreaterThan %bool %1781 %1423 + %1787 = OpFOrdLessThan %bool %1781 %1718 + %1788 = OpLogicalAnd %bool %1786 %1787 + OpSelectionMerge %1789 None + OpBranchConditional %1788 %1790 %1791 + %1791 = OpLabel + %1792 = OpFOrdGreaterThanEqual %bool %1781 %1718 + %1793 = OpExtInst %float %1 Log %1416 + %1794 = OpFDiv %float %1793 %1065 + %1795 = OpFOrdLessThan %bool %1781 %1794 + %1796 = OpLogicalAnd %bool %1792 %1795 + OpSelectionMerge %1797 None + OpBranchConditional %1796 %1798 %1799 + %1799 = OpLabel + %1800 = OpExtInst %float %1 Log %float_10000 + %1801 = OpFDiv %float %1800 %1065 + OpBranch %1797 + %1798 = OpLabel + %1802 = OpFSub %float %1781 %1718 + %1803 = OpFMul %float %float_3 %1802 + %1804 = OpFSub %float %1794 %1718 + %1805 = OpFDiv %float %1803 %1804 + %1806 = OpConvertFToS %int %1805 + %1807 = OpConvertSToF %float %1806 + %1808 = OpFSub %float %1805 %1807 + %1809 = OpAccessChain %_ptr_Function_float %517 %1806 + %1810 = OpLoad %float %1809 + %1811 = OpIAdd %int %1806 %int_1 + %1812 = OpAccessChain %_ptr_Function_float %517 %1811 + %1813 = OpLoad %float %1812 + %1814 = OpIAdd %int %1806 %int_2 + %1815 = OpAccessChain %_ptr_Function_float %517 %1814 + %1816 = OpLoad %float %1815 + %1817 = OpCompositeConstruct %v3float %1810 %1813 %1816 + %1818 = OpFMul %float %1808 %1808 + %1819 = OpCompositeConstruct %v3float %1818 %1808 %float_1 + %1820 = OpMatrixTimesVector %v3float %442 %1817 + %1821 = OpDot %float %1819 %1820 + OpBranch %1797 + %1797 = OpLabel + %1822 = OpPhi %float %1801 %1799 %1821 %1798 + OpBranch %1789 + %1790 = OpLabel + %1823 = OpFSub %float %1781 %1423 + %1824 = OpFMul %float %float_3 %1823 + %1825 = OpFSub %float %1718 %1423 + %1826 = OpFDiv %float %1824 %1825 + %1827 = OpConvertFToS %int %1826 + %1828 = OpConvertSToF %float %1827 + %1829 = OpFSub %float %1826 %1828 + %1830 = OpAccessChain %_ptr_Function_float %518 %1827 + %1831 = OpLoad %float %1830 + %1832 = OpIAdd %int %1827 %int_1 + %1833 = OpAccessChain %_ptr_Function_float %518 %1832 + %1834 = OpLoad %float %1833 + %1835 = OpIAdd %int %1827 %int_2 + %1836 = OpAccessChain %_ptr_Function_float %518 %1835 + %1837 = OpLoad %float %1836 + %1838 = OpCompositeConstruct %v3float %1831 %1834 %1837 + %1839 = OpFMul %float %1829 %1829 + %1840 = OpCompositeConstruct %v3float %1839 %1829 %float_1 + %1841 = OpMatrixTimesVector %v3float %442 %1838 + %1842 = OpDot %float %1840 %1841 + OpBranch %1789 + %1789 = OpLabel + %1843 = OpPhi %float %1822 %1797 %1842 %1790 + OpBranch %1783 + %1784 = OpLabel + %1844 = OpExtInst %float %1 Log %float_9_99999975en05 + %1845 = OpFDiv %float %1844 %1065 + OpBranch %1783 + %1783 = OpLabel + %1846 = OpPhi %float %1843 %1789 %1845 %1784 + %1847 = OpExtInst %float %1 Pow %float_10 %1846 + %1848 = OpCompositeExtract %float %1642 0 + OpStore %512 %482 + OpStore %511 %483 + %1849 = OpFOrdLessThanEqual %bool %1848 %float_0 + %1850 = OpSelect %float %1849 %float_9_99999975en05 %1848 + %1851 = OpExtInst %float %1 Log %1850 + %1852 = OpFDiv %float %1851 %1065 + %1853 = OpExtInst %float %1 Log %1716 + %1854 = OpFDiv %float %1853 %1065 + %1855 = OpFOrdLessThanEqual %bool %1852 %1854 + OpSelectionMerge %1856 None + OpBranchConditional %1855 %1857 %1858 + %1858 = OpLabel + %1859 = OpFOrdGreaterThan %bool %1852 %1854 + %1860 = OpExtInst %float %1 Log %1775 + %1861 = OpFDiv %float %1860 %1065 + %1862 = OpFOrdLessThan %bool %1852 %1861 + %1863 = OpLogicalAnd %bool %1859 %1862 + OpSelectionMerge %1864 None + OpBranchConditional %1863 %1865 %1866 + %1866 = OpLabel + %1867 = OpFOrdGreaterThanEqual %bool %1852 %1861 + %1868 = OpExtInst %float %1 Log %1847 + %1869 = OpFDiv %float %1868 %1065 + %1870 = OpFOrdLessThan %bool %1852 %1869 + %1871 = OpLogicalAnd %bool %1867 %1870 + OpSelectionMerge %1872 None + OpBranchConditional %1871 %1873 %1874 + %1874 = OpLabel + %1875 = OpFMul %float %1852 %float_0_119999997 + %1876 = OpExtInst %float %1 Log %float_2000 + %1877 = OpFDiv %float %1876 %1065 + %1878 = OpFMul %float %float_0_119999997 %1868 + %1879 = OpFDiv %float %1878 %1065 + %1880 = OpFSub %float %1877 %1879 + %1881 = OpFAdd %float %1875 %1880 + OpBranch %1872 + %1873 = OpLabel + %1882 = OpFSub %float %1852 %1861 + %1883 = OpFMul %float %float_7 %1882 + %1884 = OpFSub %float %1869 %1861 + %1885 = OpFDiv %float %1883 %1884 + %1886 = OpConvertFToS %int %1885 + %1887 = OpConvertSToF %float %1886 + %1888 = OpFSub %float %1885 %1887 + %1889 = OpAccessChain %_ptr_Function_float %511 %1886 + %1890 = OpLoad %float %1889 + %1891 = OpIAdd %int %1886 %int_1 + %1892 = OpAccessChain %_ptr_Function_float %511 %1891 + %1893 = OpLoad %float %1892 + %1894 = OpIAdd %int %1886 %int_2 + %1895 = OpAccessChain %_ptr_Function_float %511 %1894 + %1896 = OpLoad %float %1895 + %1897 = OpCompositeConstruct %v3float %1890 %1893 %1896 + %1898 = OpFMul %float %1888 %1888 + %1899 = OpCompositeConstruct %v3float %1898 %1888 %float_1 + %1900 = OpMatrixTimesVector %v3float %442 %1897 + %1901 = OpDot %float %1899 %1900 + OpBranch %1872 + %1872 = OpLabel + %1902 = OpPhi %float %1881 %1874 %1901 %1873 + OpBranch %1864 + %1865 = OpLabel + %1903 = OpFSub %float %1852 %1854 + %1904 = OpFMul %float %float_7 %1903 + %1905 = OpFSub %float %1861 %1854 + %1906 = OpFDiv %float %1904 %1905 + %1907 = OpConvertFToS %int %1906 + %1908 = OpConvertSToF %float %1907 + %1909 = OpFSub %float %1906 %1908 + %1910 = OpAccessChain %_ptr_Function_float %512 %1907 + %1911 = OpLoad %float %1910 + %1912 = OpIAdd %int %1907 %int_1 + %1913 = OpAccessChain %_ptr_Function_float %512 %1912 + %1914 = OpLoad %float %1913 + %1915 = OpIAdd %int %1907 %int_2 + %1916 = OpAccessChain %_ptr_Function_float %512 %1915 + %1917 = OpLoad %float %1916 + %1918 = OpCompositeConstruct %v3float %1911 %1914 %1917 + %1919 = OpFMul %float %1909 %1909 + %1920 = OpCompositeConstruct %v3float %1919 %1909 %float_1 + %1921 = OpMatrixTimesVector %v3float %442 %1918 + %1922 = OpDot %float %1920 %1921 + OpBranch %1864 + %1864 = OpLabel + %1923 = OpPhi %float %1902 %1872 %1922 %1865 + OpBranch %1856 + %1857 = OpLabel + %1924 = OpExtInst %float %1 Log %float_0_00499999989 + %1925 = OpFDiv %float %1924 %1065 + OpBranch %1856 + %1856 = OpLabel + %1926 = OpPhi %float %1923 %1864 %1925 %1857 + %1927 = OpExtInst %float %1 Pow %float_10 %1926 + %1928 = OpCompositeInsert %v3float %1927 %391 0 + %1929 = OpCompositeExtract %float %1642 1 + OpStore %510 %482 + OpStore %509 %483 + %1930 = OpFOrdLessThanEqual %bool %1929 %float_0 + %1931 = OpSelect %float %1930 %float_9_99999975en05 %1929 + %1932 = OpExtInst %float %1 Log %1931 + %1933 = OpFDiv %float %1932 %1065 + %1934 = OpFOrdLessThanEqual %bool %1933 %1854 + OpSelectionMerge %1935 None + OpBranchConditional %1934 %1936 %1937 + %1937 = OpLabel + %1938 = OpFOrdGreaterThan %bool %1933 %1854 + %1939 = OpExtInst %float %1 Log %1775 + %1940 = OpFDiv %float %1939 %1065 + %1941 = OpFOrdLessThan %bool %1933 %1940 + %1942 = OpLogicalAnd %bool %1938 %1941 + OpSelectionMerge %1943 None + OpBranchConditional %1942 %1944 %1945 + %1945 = OpLabel + %1946 = OpFOrdGreaterThanEqual %bool %1933 %1940 + %1947 = OpExtInst %float %1 Log %1847 + %1948 = OpFDiv %float %1947 %1065 + %1949 = OpFOrdLessThan %bool %1933 %1948 + %1950 = OpLogicalAnd %bool %1946 %1949 + OpSelectionMerge %1951 None + OpBranchConditional %1950 %1952 %1953 + %1953 = OpLabel + %1954 = OpFMul %float %1933 %float_0_119999997 + %1955 = OpExtInst %float %1 Log %float_2000 + %1956 = OpFDiv %float %1955 %1065 + %1957 = OpFMul %float %float_0_119999997 %1947 + %1958 = OpFDiv %float %1957 %1065 + %1959 = OpFSub %float %1956 %1958 + %1960 = OpFAdd %float %1954 %1959 + OpBranch %1951 + %1952 = OpLabel + %1961 = OpFSub %float %1933 %1940 + %1962 = OpFMul %float %float_7 %1961 + %1963 = OpFSub %float %1948 %1940 + %1964 = OpFDiv %float %1962 %1963 + %1965 = OpConvertFToS %int %1964 + %1966 = OpConvertSToF %float %1965 + %1967 = OpFSub %float %1964 %1966 + %1968 = OpAccessChain %_ptr_Function_float %509 %1965 + %1969 = OpLoad %float %1968 + %1970 = OpIAdd %int %1965 %int_1 + %1971 = OpAccessChain %_ptr_Function_float %509 %1970 + %1972 = OpLoad %float %1971 + %1973 = OpIAdd %int %1965 %int_2 + %1974 = OpAccessChain %_ptr_Function_float %509 %1973 + %1975 = OpLoad %float %1974 + %1976 = OpCompositeConstruct %v3float %1969 %1972 %1975 + %1977 = OpFMul %float %1967 %1967 + %1978 = OpCompositeConstruct %v3float %1977 %1967 %float_1 + %1979 = OpMatrixTimesVector %v3float %442 %1976 + %1980 = OpDot %float %1978 %1979 + OpBranch %1951 + %1951 = OpLabel + %1981 = OpPhi %float %1960 %1953 %1980 %1952 + OpBranch %1943 + %1944 = OpLabel + %1982 = OpFSub %float %1933 %1854 + %1983 = OpFMul %float %float_7 %1982 + %1984 = OpFSub %float %1940 %1854 + %1985 = OpFDiv %float %1983 %1984 + %1986 = OpConvertFToS %int %1985 + %1987 = OpConvertSToF %float %1986 + %1988 = OpFSub %float %1985 %1987 + %1989 = OpAccessChain %_ptr_Function_float %510 %1986 + %1990 = OpLoad %float %1989 + %1991 = OpIAdd %int %1986 %int_1 + %1992 = OpAccessChain %_ptr_Function_float %510 %1991 + %1993 = OpLoad %float %1992 + %1994 = OpIAdd %int %1986 %int_2 + %1995 = OpAccessChain %_ptr_Function_float %510 %1994 + %1996 = OpLoad %float %1995 + %1997 = OpCompositeConstruct %v3float %1990 %1993 %1996 + %1998 = OpFMul %float %1988 %1988 + %1999 = OpCompositeConstruct %v3float %1998 %1988 %float_1 + %2000 = OpMatrixTimesVector %v3float %442 %1997 + %2001 = OpDot %float %1999 %2000 + OpBranch %1943 + %1943 = OpLabel + %2002 = OpPhi %float %1981 %1951 %2001 %1944 + OpBranch %1935 + %1936 = OpLabel + %2003 = OpExtInst %float %1 Log %float_0_00499999989 + %2004 = OpFDiv %float %2003 %1065 + OpBranch %1935 + %1935 = OpLabel + %2005 = OpPhi %float %2002 %1943 %2004 %1936 + %2006 = OpExtInst %float %1 Pow %float_10 %2005 + %2007 = OpCompositeInsert %v3float %2006 %1928 1 + %2008 = OpCompositeExtract %float %1642 2 + OpStore %508 %482 + OpStore %507 %483 + %2009 = OpFOrdLessThanEqual %bool %2008 %float_0 + %2010 = OpSelect %float %2009 %float_9_99999975en05 %2008 + %2011 = OpExtInst %float %1 Log %2010 + %2012 = OpFDiv %float %2011 %1065 + %2013 = OpFOrdLessThanEqual %bool %2012 %1854 + OpSelectionMerge %2014 None + OpBranchConditional %2013 %2015 %2016 + %2016 = OpLabel + %2017 = OpFOrdGreaterThan %bool %2012 %1854 + %2018 = OpExtInst %float %1 Log %1775 + %2019 = OpFDiv %float %2018 %1065 + %2020 = OpFOrdLessThan %bool %2012 %2019 + %2021 = OpLogicalAnd %bool %2017 %2020 + OpSelectionMerge %2022 None + OpBranchConditional %2021 %2023 %2024 + %2024 = OpLabel + %2025 = OpFOrdGreaterThanEqual %bool %2012 %2019 + %2026 = OpExtInst %float %1 Log %1847 + %2027 = OpFDiv %float %2026 %1065 + %2028 = OpFOrdLessThan %bool %2012 %2027 + %2029 = OpLogicalAnd %bool %2025 %2028 + OpSelectionMerge %2030 None + OpBranchConditional %2029 %2031 %2032 + %2032 = OpLabel + %2033 = OpFMul %float %2012 %float_0_119999997 + %2034 = OpExtInst %float %1 Log %float_2000 + %2035 = OpFDiv %float %2034 %1065 + %2036 = OpFMul %float %float_0_119999997 %2026 + %2037 = OpFDiv %float %2036 %1065 + %2038 = OpFSub %float %2035 %2037 + %2039 = OpFAdd %float %2033 %2038 + OpBranch %2030 + %2031 = OpLabel + %2040 = OpFSub %float %2012 %2019 + %2041 = OpFMul %float %float_7 %2040 + %2042 = OpFSub %float %2027 %2019 + %2043 = OpFDiv %float %2041 %2042 + %2044 = OpConvertFToS %int %2043 + %2045 = OpConvertSToF %float %2044 + %2046 = OpFSub %float %2043 %2045 + %2047 = OpAccessChain %_ptr_Function_float %507 %2044 + %2048 = OpLoad %float %2047 + %2049 = OpIAdd %int %2044 %int_1 + %2050 = OpAccessChain %_ptr_Function_float %507 %2049 + %2051 = OpLoad %float %2050 + %2052 = OpIAdd %int %2044 %int_2 + %2053 = OpAccessChain %_ptr_Function_float %507 %2052 + %2054 = OpLoad %float %2053 + %2055 = OpCompositeConstruct %v3float %2048 %2051 %2054 + %2056 = OpFMul %float %2046 %2046 + %2057 = OpCompositeConstruct %v3float %2056 %2046 %float_1 + %2058 = OpMatrixTimesVector %v3float %442 %2055 + %2059 = OpDot %float %2057 %2058 + OpBranch %2030 + %2030 = OpLabel + %2060 = OpPhi %float %2039 %2032 %2059 %2031 + OpBranch %2022 + %2023 = OpLabel + %2061 = OpFSub %float %2012 %1854 + %2062 = OpFMul %float %float_7 %2061 + %2063 = OpFSub %float %2019 %1854 + %2064 = OpFDiv %float %2062 %2063 + %2065 = OpConvertFToS %int %2064 + %2066 = OpConvertSToF %float %2065 + %2067 = OpFSub %float %2064 %2066 + %2068 = OpAccessChain %_ptr_Function_float %508 %2065 + %2069 = OpLoad %float %2068 + %2070 = OpIAdd %int %2065 %int_1 + %2071 = OpAccessChain %_ptr_Function_float %508 %2070 + %2072 = OpLoad %float %2071 + %2073 = OpIAdd %int %2065 %int_2 + %2074 = OpAccessChain %_ptr_Function_float %508 %2073 + %2075 = OpLoad %float %2074 + %2076 = OpCompositeConstruct %v3float %2069 %2072 %2075 + %2077 = OpFMul %float %2067 %2067 + %2078 = OpCompositeConstruct %v3float %2077 %2067 %float_1 + %2079 = OpMatrixTimesVector %v3float %442 %2076 + %2080 = OpDot %float %2078 %2079 + OpBranch %2022 + %2022 = OpLabel + %2081 = OpPhi %float %2060 %2030 %2080 %2023 + OpBranch %2014 + %2015 = OpLabel + %2082 = OpExtInst %float %1 Log %float_0_00499999989 + %2083 = OpFDiv %float %2082 %1065 + OpBranch %2014 + %2014 = OpLabel + %2084 = OpPhi %float %2081 %2022 %2083 %2015 + %2085 = OpExtInst %float %1 Pow %float_10 %2084 + %2086 = OpCompositeInsert %v3float %2085 %2007 2 + %2087 = OpVectorTimesMatrix %v3float %2086 %576 + %2088 = OpFMul %v3float %2087 %496 + %2089 = OpExtInst %v3float %1 Pow %2088 %263 + %2090 = OpFMul %v3float %184 %2089 + %2091 = OpFAdd %v3float %183 %2090 + %2092 = OpFMul %v3float %185 %2089 + %2093 = OpFAdd %v3float %135 %2092 + %2094 = OpFDiv %v3float %135 %2093 + %2095 = OpFMul %v3float %2091 %2094 + %2096 = OpExtInst %v3float %1 Pow %2095 %264 + OpBranch %1236 + %1236 = OpLabel + %2097 = OpPhi %v3float %1260 %1240 %2096 %2014 + OpBranch %1230 + %1231 = OpLabel + %2098 = OpMatrixTimesMatrix %mat3v3float %546 %399 + %2099 = OpFMul %v3float %906 %262 + %2100 = OpVectorTimesMatrix %v3float %2099 %2098 + %2101 = OpCompositeExtract %float %2100 0 + %2102 = OpCompositeExtract %float %2100 1 + %2103 = OpExtInst %float %1 FMin %2101 %2102 + %2104 = OpCompositeExtract %float %2100 2 + %2105 = OpExtInst %float %1 FMin %2103 %2104 + %2106 = OpExtInst %float %1 FMax %2101 %2102 + %2107 = OpExtInst %float %1 FMax %2106 %2104 + %2108 = OpExtInst %float %1 FMax %2107 %float_1_00000001en10 + %2109 = OpExtInst %float %1 FMax %2105 %float_1_00000001en10 + %2110 = OpFSub %float %2108 %2109 + %2111 = OpExtInst %float %1 FMax %2107 %float_0_00999999978 + %2112 = OpFDiv %float %2110 %2111 + %2113 = OpFSub %float %2104 %2102 + %2114 = OpFMul %float %2104 %2113 + %2115 = OpFSub %float %2102 %2101 + %2116 = OpFMul %float %2102 %2115 + %2117 = OpFAdd %float %2114 %2116 + %2118 = OpFSub %float %2101 %2104 + %2119 = OpFMul %float %2101 %2118 + %2120 = OpFAdd %float %2117 %2119 + %2121 = OpExtInst %float %1 Sqrt %2120 + %2122 = OpFAdd %float %2104 %2102 + %2123 = OpFAdd %float %2122 %2101 + %2124 = OpFMul %float %float_1_75 %2121 + %2125 = OpFAdd %float %2123 %2124 + %2126 = OpFMul %float %2125 %float_0_333333343 + %2127 = OpFSub %float %2112 %float_0_400000006 + %2128 = OpFMul %float %2127 %float_5 + %2129 = OpFMul %float %2127 %float_2_5 + %2130 = OpExtInst %float %1 FAbs %2129 + %2131 = OpFSub %float %float_1 %2130 + %2132 = OpExtInst %float %1 FMax %2131 %float_0 + %2133 = OpExtInst %float %1 FSign %2128 + %2134 = OpConvertFToS %int %2133 + %2135 = OpConvertSToF %float %2134 + %2136 = OpFMul %float %2132 %2132 + %2137 = OpFSub %float %float_1 %2136 + %2138 = OpFMul %float %2135 %2137 + %2139 = OpFAdd %float %float_1 %2138 + %2140 = OpFMul %float %2139 %float_0_0250000004 + %2141 = OpFOrdLessThanEqual %bool %2126 %float_0_0533333346 + OpSelectionMerge %2142 None + OpBranchConditional %2141 %2143 %2144 + %2144 = OpLabel + %2145 = OpFOrdGreaterThanEqual %bool %2126 %float_0_159999996 + OpSelectionMerge %2146 None + OpBranchConditional %2145 %2147 %2148 + %2148 = OpLabel + %2149 = OpFDiv %float %float_0_239999995 %2125 + %2150 = OpFSub %float %2149 %float_0_5 + %2151 = OpFMul %float %2140 %2150 + OpBranch %2146 + %2147 = OpLabel + OpBranch %2146 + %2146 = OpLabel + %2152 = OpPhi %float %2151 %2148 %float_0 %2147 + OpBranch %2142 + %2143 = OpLabel + OpBranch %2142 + %2142 = OpLabel + %2153 = OpPhi %float %2152 %2146 %2140 %2143 + %2154 = OpFAdd %float %float_1 %2153 + %2155 = OpCompositeConstruct %v3float %2154 %2154 %2154 + %2156 = OpFMul %v3float %2100 %2155 + %2157 = OpCompositeExtract %float %2156 0 + %2158 = OpCompositeExtract %float %2156 1 + %2159 = OpFOrdEqual %bool %2157 %2158 + %2160 = OpCompositeExtract %float %2156 2 + %2161 = OpFOrdEqual %bool %2158 %2160 + %2162 = OpLogicalAnd %bool %2159 %2161 + OpSelectionMerge %2163 None + OpBranchConditional %2162 %2164 %2165 + %2165 = OpLabel + %2166 = OpExtInst %float %1 Sqrt %float_3 + %2167 = OpFSub %float %2158 %2160 + %2168 = OpFMul %float %2166 %2167 + %2169 = OpFMul %float %float_2 %2157 + %2170 = OpFSub %float %2169 %2158 + %2171 = OpFSub %float %2170 %2160 + %2172 = OpExtInst %float %1 Atan2 %2168 %2171 + %2173 = OpFMul %float %float_57_2957764 %2172 + OpBranch %2163 + %2164 = OpLabel + OpBranch %2163 + %2163 = OpLabel + %2174 = OpPhi %float %2173 %2165 %float_0 %2164 + %2175 = OpFOrdLessThan %bool %2174 %float_0 + OpSelectionMerge %2176 None + OpBranchConditional %2175 %2177 %2176 + %2177 = OpLabel + %2178 = OpFAdd %float %2174 %float_360 + OpBranch %2176 + %2176 = OpLabel + %2179 = OpPhi %float %2174 %2163 %2178 %2177 + %2180 = OpExtInst %float %1 FClamp %2179 %float_0 %float_360 + %2181 = OpFOrdGreaterThan %bool %2180 %float_180 + OpSelectionMerge %2182 None + OpBranchConditional %2181 %2183 %2182 + %2183 = OpLabel + %2184 = OpFSub %float %2180 %float_360 + OpBranch %2182 + %2182 = OpLabel + %2185 = OpPhi %float %2180 %2176 %2184 %2183 + %2186 = OpFOrdGreaterThan %bool %2185 %float_n67_5 + %2187 = OpFOrdLessThan %bool %2185 %float_67_5 + %2188 = OpLogicalAnd %bool %2186 %2187 + OpSelectionMerge %2189 None + OpBranchConditional %2188 %2190 %2189 + %2190 = OpLabel + %2191 = OpFSub %float %2185 %float_n67_5 + %2192 = OpFMul %float %2191 %float_0_0296296291 + %2193 = OpConvertFToS %int %2192 + %2194 = OpConvertSToF %float %2193 + %2195 = OpFSub %float %2192 %2194 + %2196 = OpFMul %float %2195 %2195 + %2197 = OpFMul %float %2196 %2195 + %2198 = OpIEqual %bool %2193 %int_3 + OpSelectionMerge %2199 None + OpBranchConditional %2198 %2200 %2201 + %2201 = OpLabel + %2202 = OpIEqual %bool %2193 %int_2 + OpSelectionMerge %2203 None + OpBranchConditional %2202 %2204 %2205 + %2205 = OpLabel + %2206 = OpIEqual %bool %2193 %int_1 + OpSelectionMerge %2207 None + OpBranchConditional %2206 %2208 %2209 + %2209 = OpLabel + %2210 = OpIEqual %bool %2193 %int_0 + OpSelectionMerge %2211 None + OpBranchConditional %2210 %2212 %2213 + %2213 = OpLabel + OpBranch %2211 + %2212 = OpLabel + %2214 = OpFMul %float %2197 %float_0_166666672 + OpBranch %2211 + %2211 = OpLabel + %2215 = OpPhi %float %float_0 %2213 %2214 %2212 + OpBranch %2207 + %2208 = OpLabel + %2216 = OpFMul %float %2197 %float_n0_5 + %2217 = OpFMul %float %2196 %float_0_5 + %2218 = OpFAdd %float %2216 %2217 + %2219 = OpFMul %float %2195 %float_0_5 + %2220 = OpFAdd %float %2218 %2219 + %2221 = OpFAdd %float %2220 %float_0_166666672 + OpBranch %2207 + %2207 = OpLabel + %2222 = OpPhi %float %2215 %2211 %2221 %2208 + OpBranch %2203 + %2204 = OpLabel + %2223 = OpFMul %float %2197 %float_0_5 + %2224 = OpFMul %float %2196 %float_n1 + %2225 = OpFAdd %float %2223 %2224 + %2226 = OpFAdd %float %2225 %float_0_666666687 + OpBranch %2203 + %2203 = OpLabel + %2227 = OpPhi %float %2222 %2207 %2226 %2204 + OpBranch %2199 + %2200 = OpLabel + %2228 = OpFMul %float %2197 %float_n0_166666672 + %2229 = OpFMul %float %2196 %float_0_5 + %2230 = OpFAdd %float %2228 %2229 + %2231 = OpFMul %float %2195 %float_n0_5 + %2232 = OpFAdd %float %2230 %2231 + %2233 = OpFAdd %float %2232 %float_0_166666672 + OpBranch %2199 + %2199 = OpLabel + %2234 = OpPhi %float %2227 %2203 %2233 %2200 + OpBranch %2189 + %2189 = OpLabel + %2235 = OpPhi %float %float_0 %2182 %2234 %2199 + %2236 = OpFMul %float %2235 %float_1_5 + %2237 = OpFMul %float %2236 %2112 + %2238 = OpFSub %float %float_0_0299999993 %2157 + %2239 = OpFMul %float %2237 %2238 + %2240 = OpFMul %float %2239 %float_0_180000007 + %2241 = OpFAdd %float %2157 %2240 + %2242 = OpCompositeInsert %v3float %2241 %2156 0 + %2243 = OpExtInst %v3float %1 FClamp %2242 %132 %314 + %2244 = OpVectorTimesMatrix %v3float %2243 %410 + %2245 = OpExtInst %v3float %1 FClamp %2244 %132 %314 + %2246 = OpDot %float %2245 %67 + %2247 = OpCompositeConstruct %v3float %2246 %2246 %2246 + %2248 = OpExtInst %v3float %1 FMix %2247 %2245 %228 + %2249 = OpCompositeExtract %float %2248 0 + %2250 = OpExtInst %float %1 Exp2 %float_n15 + %2251 = OpFMul %float %float_0_179999992 %2250 + %2252 = OpExtInst %float %1 Exp2 %float_18 + %2253 = OpFMul %float %float_0_179999992 %2252 + OpStore %520 %475 + OpStore %519 %476 + %2254 = OpFOrdLessThanEqual %bool %2249 %float_0 + %2255 = OpExtInst %float %1 Exp2 %float_n14 + %2256 = OpSelect %float %2254 %2255 %2249 + %2257 = OpExtInst %float %1 Log %2256 + %2258 = OpFDiv %float %2257 %1065 + %2259 = OpExtInst %float %1 Log %2251 + %2260 = OpFDiv %float %2259 %1065 + %2261 = OpFOrdLessThanEqual %bool %2258 %2260 + OpSelectionMerge %2262 None + OpBranchConditional %2261 %2263 %2264 + %2264 = OpLabel + %2265 = OpFOrdGreaterThan %bool %2258 %2260 + %2266 = OpExtInst %float %1 Log %float_0_180000007 + %2267 = OpFDiv %float %2266 %1065 + %2268 = OpFOrdLessThan %bool %2258 %2267 + %2269 = OpLogicalAnd %bool %2265 %2268 + OpSelectionMerge %2270 None + OpBranchConditional %2269 %2271 %2272 + %2272 = OpLabel + %2273 = OpFOrdGreaterThanEqual %bool %2258 %2267 + %2274 = OpExtInst %float %1 Log %2253 + %2275 = OpFDiv %float %2274 %1065 + %2276 = OpFOrdLessThan %bool %2258 %2275 + %2277 = OpLogicalAnd %bool %2273 %2276 + OpSelectionMerge %2278 None + OpBranchConditional %2277 %2279 %2280 + %2280 = OpLabel + %2281 = OpExtInst %float %1 Log %float_10000 + %2282 = OpFDiv %float %2281 %1065 + OpBranch %2278 + %2279 = OpLabel + %2283 = OpFSub %float %2258 %2267 + %2284 = OpFMul %float %float_3 %2283 + %2285 = OpFSub %float %2275 %2267 + %2286 = OpFDiv %float %2284 %2285 + %2287 = OpConvertFToS %int %2286 + %2288 = OpConvertSToF %float %2287 + %2289 = OpFSub %float %2286 %2288 + %2290 = OpAccessChain %_ptr_Function_float %519 %2287 + %2291 = OpLoad %float %2290 + %2292 = OpIAdd %int %2287 %int_1 + %2293 = OpAccessChain %_ptr_Function_float %519 %2292 + %2294 = OpLoad %float %2293 + %2295 = OpIAdd %int %2287 %int_2 + %2296 = OpAccessChain %_ptr_Function_float %519 %2295 + %2297 = OpLoad %float %2296 + %2298 = OpCompositeConstruct %v3float %2291 %2294 %2297 + %2299 = OpFMul %float %2289 %2289 + %2300 = OpCompositeConstruct %v3float %2299 %2289 %float_1 + %2301 = OpMatrixTimesVector %v3float %442 %2298 + %2302 = OpDot %float %2300 %2301 + OpBranch %2278 + %2278 = OpLabel + %2303 = OpPhi %float %2282 %2280 %2302 %2279 + OpBranch %2270 + %2271 = OpLabel + %2304 = OpFSub %float %2258 %2260 + %2305 = OpFMul %float %float_3 %2304 + %2306 = OpFSub %float %2267 %2260 + %2307 = OpFDiv %float %2305 %2306 + %2308 = OpConvertFToS %int %2307 + %2309 = OpConvertSToF %float %2308 + %2310 = OpFSub %float %2307 %2309 + %2311 = OpAccessChain %_ptr_Function_float %520 %2308 + %2312 = OpLoad %float %2311 + %2313 = OpIAdd %int %2308 %int_1 + %2314 = OpAccessChain %_ptr_Function_float %520 %2313 + %2315 = OpLoad %float %2314 + %2316 = OpIAdd %int %2308 %int_2 + %2317 = OpAccessChain %_ptr_Function_float %520 %2316 + %2318 = OpLoad %float %2317 + %2319 = OpCompositeConstruct %v3float %2312 %2315 %2318 + %2320 = OpFMul %float %2310 %2310 + %2321 = OpCompositeConstruct %v3float %2320 %2310 %float_1 + %2322 = OpMatrixTimesVector %v3float %442 %2319 + %2323 = OpDot %float %2321 %2322 + OpBranch %2270 + %2270 = OpLabel + %2324 = OpPhi %float %2303 %2278 %2323 %2271 + OpBranch %2262 + %2263 = OpLabel + %2325 = OpExtInst %float %1 Log %float_9_99999975en05 + %2326 = OpFDiv %float %2325 %1065 + OpBranch %2262 + %2262 = OpLabel + %2327 = OpPhi %float %2324 %2270 %2326 %2263 + %2328 = OpExtInst %float %1 Pow %float_10 %2327 + %2329 = OpCompositeInsert %v3float %2328 %391 0 + %2330 = OpCompositeExtract %float %2248 1 + OpStore %522 %475 + OpStore %521 %476 + %2331 = OpFOrdLessThanEqual %bool %2330 %float_0 + %2332 = OpSelect %float %2331 %2255 %2330 + %2333 = OpExtInst %float %1 Log %2332 + %2334 = OpFDiv %float %2333 %1065 + %2335 = OpFOrdLessThanEqual %bool %2334 %2260 + OpSelectionMerge %2336 None + OpBranchConditional %2335 %2337 %2338 + %2338 = OpLabel + %2339 = OpFOrdGreaterThan %bool %2334 %2260 + %2340 = OpExtInst %float %1 Log %float_0_180000007 + %2341 = OpFDiv %float %2340 %1065 + %2342 = OpFOrdLessThan %bool %2334 %2341 + %2343 = OpLogicalAnd %bool %2339 %2342 + OpSelectionMerge %2344 None + OpBranchConditional %2343 %2345 %2346 + %2346 = OpLabel + %2347 = OpFOrdGreaterThanEqual %bool %2334 %2341 + %2348 = OpExtInst %float %1 Log %2253 + %2349 = OpFDiv %float %2348 %1065 + %2350 = OpFOrdLessThan %bool %2334 %2349 + %2351 = OpLogicalAnd %bool %2347 %2350 + OpSelectionMerge %2352 None + OpBranchConditional %2351 %2353 %2354 + %2354 = OpLabel + %2355 = OpExtInst %float %1 Log %float_10000 + %2356 = OpFDiv %float %2355 %1065 + OpBranch %2352 + %2353 = OpLabel + %2357 = OpFSub %float %2334 %2341 + %2358 = OpFMul %float %float_3 %2357 + %2359 = OpFSub %float %2349 %2341 + %2360 = OpFDiv %float %2358 %2359 + %2361 = OpConvertFToS %int %2360 + %2362 = OpConvertSToF %float %2361 + %2363 = OpFSub %float %2360 %2362 + %2364 = OpAccessChain %_ptr_Function_float %521 %2361 + %2365 = OpLoad %float %2364 + %2366 = OpIAdd %int %2361 %int_1 + %2367 = OpAccessChain %_ptr_Function_float %521 %2366 + %2368 = OpLoad %float %2367 + %2369 = OpIAdd %int %2361 %int_2 + %2370 = OpAccessChain %_ptr_Function_float %521 %2369 + %2371 = OpLoad %float %2370 + %2372 = OpCompositeConstruct %v3float %2365 %2368 %2371 + %2373 = OpFMul %float %2363 %2363 + %2374 = OpCompositeConstruct %v3float %2373 %2363 %float_1 + %2375 = OpMatrixTimesVector %v3float %442 %2372 + %2376 = OpDot %float %2374 %2375 + OpBranch %2352 + %2352 = OpLabel + %2377 = OpPhi %float %2356 %2354 %2376 %2353 + OpBranch %2344 + %2345 = OpLabel + %2378 = OpFSub %float %2334 %2260 + %2379 = OpFMul %float %float_3 %2378 + %2380 = OpFSub %float %2341 %2260 + %2381 = OpFDiv %float %2379 %2380 + %2382 = OpConvertFToS %int %2381 + %2383 = OpConvertSToF %float %2382 + %2384 = OpFSub %float %2381 %2383 + %2385 = OpAccessChain %_ptr_Function_float %522 %2382 + %2386 = OpLoad %float %2385 + %2387 = OpIAdd %int %2382 %int_1 + %2388 = OpAccessChain %_ptr_Function_float %522 %2387 + %2389 = OpLoad %float %2388 + %2390 = OpIAdd %int %2382 %int_2 + %2391 = OpAccessChain %_ptr_Function_float %522 %2390 + %2392 = OpLoad %float %2391 + %2393 = OpCompositeConstruct %v3float %2386 %2389 %2392 + %2394 = OpFMul %float %2384 %2384 + %2395 = OpCompositeConstruct %v3float %2394 %2384 %float_1 + %2396 = OpMatrixTimesVector %v3float %442 %2393 + %2397 = OpDot %float %2395 %2396 + OpBranch %2344 + %2344 = OpLabel + %2398 = OpPhi %float %2377 %2352 %2397 %2345 + OpBranch %2336 + %2337 = OpLabel + %2399 = OpExtInst %float %1 Log %float_9_99999975en05 + %2400 = OpFDiv %float %2399 %1065 + OpBranch %2336 + %2336 = OpLabel + %2401 = OpPhi %float %2398 %2344 %2400 %2337 + %2402 = OpExtInst %float %1 Pow %float_10 %2401 + %2403 = OpCompositeInsert %v3float %2402 %2329 1 + %2404 = OpCompositeExtract %float %2248 2 + OpStore %524 %475 + OpStore %523 %476 + %2405 = OpFOrdLessThanEqual %bool %2404 %float_0 + %2406 = OpSelect %float %2405 %2255 %2404 + %2407 = OpExtInst %float %1 Log %2406 + %2408 = OpFDiv %float %2407 %1065 + %2409 = OpFOrdLessThanEqual %bool %2408 %2260 + OpSelectionMerge %2410 None + OpBranchConditional %2409 %2411 %2412 + %2412 = OpLabel + %2413 = OpFOrdGreaterThan %bool %2408 %2260 + %2414 = OpExtInst %float %1 Log %float_0_180000007 + %2415 = OpFDiv %float %2414 %1065 + %2416 = OpFOrdLessThan %bool %2408 %2415 + %2417 = OpLogicalAnd %bool %2413 %2416 + OpSelectionMerge %2418 None + OpBranchConditional %2417 %2419 %2420 + %2420 = OpLabel + %2421 = OpFOrdGreaterThanEqual %bool %2408 %2415 + %2422 = OpExtInst %float %1 Log %2253 + %2423 = OpFDiv %float %2422 %1065 + %2424 = OpFOrdLessThan %bool %2408 %2423 + %2425 = OpLogicalAnd %bool %2421 %2424 + OpSelectionMerge %2426 None + OpBranchConditional %2425 %2427 %2428 + %2428 = OpLabel + %2429 = OpExtInst %float %1 Log %float_10000 + %2430 = OpFDiv %float %2429 %1065 + OpBranch %2426 + %2427 = OpLabel + %2431 = OpFSub %float %2408 %2415 + %2432 = OpFMul %float %float_3 %2431 + %2433 = OpFSub %float %2423 %2415 + %2434 = OpFDiv %float %2432 %2433 + %2435 = OpConvertFToS %int %2434 + %2436 = OpConvertSToF %float %2435 + %2437 = OpFSub %float %2434 %2436 + %2438 = OpAccessChain %_ptr_Function_float %523 %2435 + %2439 = OpLoad %float %2438 + %2440 = OpIAdd %int %2435 %int_1 + %2441 = OpAccessChain %_ptr_Function_float %523 %2440 + %2442 = OpLoad %float %2441 + %2443 = OpIAdd %int %2435 %int_2 + %2444 = OpAccessChain %_ptr_Function_float %523 %2443 + %2445 = OpLoad %float %2444 + %2446 = OpCompositeConstruct %v3float %2439 %2442 %2445 + %2447 = OpFMul %float %2437 %2437 + %2448 = OpCompositeConstruct %v3float %2447 %2437 %float_1 + %2449 = OpMatrixTimesVector %v3float %442 %2446 + %2450 = OpDot %float %2448 %2449 + OpBranch %2426 + %2426 = OpLabel + %2451 = OpPhi %float %2430 %2428 %2450 %2427 + OpBranch %2418 + %2419 = OpLabel + %2452 = OpFSub %float %2408 %2260 + %2453 = OpFMul %float %float_3 %2452 + %2454 = OpFSub %float %2415 %2260 + %2455 = OpFDiv %float %2453 %2454 + %2456 = OpConvertFToS %int %2455 + %2457 = OpConvertSToF %float %2456 + %2458 = OpFSub %float %2455 %2457 + %2459 = OpAccessChain %_ptr_Function_float %524 %2456 + %2460 = OpLoad %float %2459 + %2461 = OpIAdd %int %2456 %int_1 + %2462 = OpAccessChain %_ptr_Function_float %524 %2461 + %2463 = OpLoad %float %2462 + %2464 = OpIAdd %int %2456 %int_2 + %2465 = OpAccessChain %_ptr_Function_float %524 %2464 + %2466 = OpLoad %float %2465 + %2467 = OpCompositeConstruct %v3float %2460 %2463 %2466 + %2468 = OpFMul %float %2458 %2458 + %2469 = OpCompositeConstruct %v3float %2468 %2458 %float_1 + %2470 = OpMatrixTimesVector %v3float %442 %2467 + %2471 = OpDot %float %2469 %2470 + OpBranch %2418 + %2418 = OpLabel + %2472 = OpPhi %float %2451 %2426 %2471 %2419 + OpBranch %2410 + %2411 = OpLabel + %2473 = OpExtInst %float %1 Log %float_9_99999975en05 + %2474 = OpFDiv %float %2473 %1065 + OpBranch %2410 + %2410 = OpLabel + %2475 = OpPhi %float %2472 %2418 %2474 %2411 + %2476 = OpExtInst %float %1 Pow %float_10 %2475 + %2477 = OpCompositeInsert %v3float %2476 %2403 2 + %2478 = OpVectorTimesMatrix %v3float %2477 %414 + %2479 = OpVectorTimesMatrix %v3float %2478 %410 + %2480 = OpExtInst %float %1 Pow %float_2 %float_n12 + %2481 = OpFMul %float %float_0_179999992 %2480 + OpStore %532 %475 + OpStore %531 %476 + %2482 = OpFOrdLessThanEqual %bool %2481 %float_0 + %2483 = OpSelect %float %2482 %2255 %2481 + %2484 = OpExtInst %float %1 Log %2483 + %2485 = OpFDiv %float %2484 %1065 + %2486 = OpFOrdLessThanEqual %bool %2485 %2260 + OpSelectionMerge %2487 None + OpBranchConditional %2486 %2488 %2489 + %2489 = OpLabel + %2490 = OpFOrdGreaterThan %bool %2485 %2260 + %2491 = OpExtInst %float %1 Log %float_0_180000007 + %2492 = OpFDiv %float %2491 %1065 + %2493 = OpFOrdLessThan %bool %2485 %2492 + %2494 = OpLogicalAnd %bool %2490 %2493 + OpSelectionMerge %2495 None + OpBranchConditional %2494 %2496 %2497 + %2497 = OpLabel + %2498 = OpFOrdGreaterThanEqual %bool %2485 %2492 + %2499 = OpExtInst %float %1 Log %2253 + %2500 = OpFDiv %float %2499 %1065 + %2501 = OpFOrdLessThan %bool %2485 %2500 + %2502 = OpLogicalAnd %bool %2498 %2501 + OpSelectionMerge %2503 None + OpBranchConditional %2502 %2504 %2505 + %2505 = OpLabel + %2506 = OpExtInst %float %1 Log %float_10000 + %2507 = OpFDiv %float %2506 %1065 + OpBranch %2503 + %2504 = OpLabel + %2508 = OpFSub %float %2485 %2492 + %2509 = OpFMul %float %float_3 %2508 + %2510 = OpFSub %float %2500 %2492 + %2511 = OpFDiv %float %2509 %2510 + %2512 = OpConvertFToS %int %2511 + %2513 = OpConvertSToF %float %2512 + %2514 = OpFSub %float %2511 %2513 + %2515 = OpAccessChain %_ptr_Function_float %531 %2512 + %2516 = OpLoad %float %2515 + %2517 = OpIAdd %int %2512 %int_1 + %2518 = OpAccessChain %_ptr_Function_float %531 %2517 + %2519 = OpLoad %float %2518 + %2520 = OpIAdd %int %2512 %int_2 + %2521 = OpAccessChain %_ptr_Function_float %531 %2520 + %2522 = OpLoad %float %2521 + %2523 = OpCompositeConstruct %v3float %2516 %2519 %2522 + %2524 = OpFMul %float %2514 %2514 + %2525 = OpCompositeConstruct %v3float %2524 %2514 %float_1 + %2526 = OpMatrixTimesVector %v3float %442 %2523 + %2527 = OpDot %float %2525 %2526 + OpBranch %2503 + %2503 = OpLabel + %2528 = OpPhi %float %2507 %2505 %2527 %2504 + OpBranch %2495 + %2496 = OpLabel + %2529 = OpFSub %float %2485 %2260 + %2530 = OpFMul %float %float_3 %2529 + %2531 = OpFSub %float %2492 %2260 + %2532 = OpFDiv %float %2530 %2531 + %2533 = OpConvertFToS %int %2532 + %2534 = OpConvertSToF %float %2533 + %2535 = OpFSub %float %2532 %2534 + %2536 = OpAccessChain %_ptr_Function_float %532 %2533 + %2537 = OpLoad %float %2536 + %2538 = OpIAdd %int %2533 %int_1 + %2539 = OpAccessChain %_ptr_Function_float %532 %2538 + %2540 = OpLoad %float %2539 + %2541 = OpIAdd %int %2533 %int_2 + %2542 = OpAccessChain %_ptr_Function_float %532 %2541 + %2543 = OpLoad %float %2542 + %2544 = OpCompositeConstruct %v3float %2537 %2540 %2543 + %2545 = OpFMul %float %2535 %2535 + %2546 = OpCompositeConstruct %v3float %2545 %2535 %float_1 + %2547 = OpMatrixTimesVector %v3float %442 %2544 + %2548 = OpDot %float %2546 %2547 + OpBranch %2495 + %2495 = OpLabel + %2549 = OpPhi %float %2528 %2503 %2548 %2496 + OpBranch %2487 + %2488 = OpLabel + %2550 = OpExtInst %float %1 Log %float_9_99999975en05 + %2551 = OpFDiv %float %2550 %1065 + OpBranch %2487 + %2487 = OpLabel + %2552 = OpPhi %float %2549 %2495 %2551 %2488 + %2553 = OpExtInst %float %1 Pow %float_10 %2552 + OpStore %534 %475 + OpStore %533 %476 + %2554 = OpExtInst %float %1 Log %float_0_180000007 + %2555 = OpFDiv %float %2554 %1065 + %2556 = OpFOrdLessThanEqual %bool %2555 %2260 + OpSelectionMerge %2557 None + OpBranchConditional %2556 %2558 %2559 + %2559 = OpLabel + %2560 = OpFOrdGreaterThan %bool %2555 %2260 + %2561 = OpFOrdLessThan %bool %2555 %2555 + %2562 = OpLogicalAnd %bool %2560 %2561 + OpSelectionMerge %2563 None + OpBranchConditional %2562 %2564 %2565 + %2565 = OpLabel + %2566 = OpFOrdGreaterThanEqual %bool %2555 %2555 + %2567 = OpExtInst %float %1 Log %2253 + %2568 = OpFDiv %float %2567 %1065 + %2569 = OpFOrdLessThan %bool %2555 %2568 + %2570 = OpLogicalAnd %bool %2566 %2569 + OpSelectionMerge %2571 None + OpBranchConditional %2570 %2572 %2573 + %2573 = OpLabel + %2574 = OpExtInst %float %1 Log %float_10000 + %2575 = OpFDiv %float %2574 %1065 + OpBranch %2571 + %2572 = OpLabel + %2576 = OpFSub %float %2555 %2555 + %2577 = OpFMul %float %float_3 %2576 + %2578 = OpFSub %float %2568 %2555 + %2579 = OpFDiv %float %2577 %2578 + %2580 = OpConvertFToS %int %2579 + %2581 = OpConvertSToF %float %2580 + %2582 = OpFSub %float %2579 %2581 + %2583 = OpAccessChain %_ptr_Function_float %533 %2580 + %2584 = OpLoad %float %2583 + %2585 = OpIAdd %int %2580 %int_1 + %2586 = OpAccessChain %_ptr_Function_float %533 %2585 + %2587 = OpLoad %float %2586 + %2588 = OpIAdd %int %2580 %int_2 + %2589 = OpAccessChain %_ptr_Function_float %533 %2588 + %2590 = OpLoad %float %2589 + %2591 = OpCompositeConstruct %v3float %2584 %2587 %2590 + %2592 = OpFMul %float %2582 %2582 + %2593 = OpCompositeConstruct %v3float %2592 %2582 %float_1 + %2594 = OpMatrixTimesVector %v3float %442 %2591 + %2595 = OpDot %float %2593 %2594 + OpBranch %2571 + %2571 = OpLabel + %2596 = OpPhi %float %2575 %2573 %2595 %2572 + OpBranch %2563 + %2564 = OpLabel + %2597 = OpFSub %float %2555 %2260 + %2598 = OpFMul %float %float_3 %2597 + %2599 = OpAccessChain %_ptr_Function_float %534 %int_3 + %2600 = OpLoad %float %2599 + %2601 = OpAccessChain %_ptr_Function_float %534 %int_4 + %2602 = OpLoad %float %2601 + %2603 = OpAccessChain %_ptr_Function_float %534 %int_5 + %2604 = OpLoad %float %2603 + %2605 = OpCompositeConstruct %v3float %2600 %2602 %2604 + %2606 = OpMatrixTimesVector %v3float %442 %2605 + %2607 = OpCompositeExtract %float %2606 2 + OpBranch %2563 + %2563 = OpLabel + %2608 = OpPhi %float %2596 %2571 %2607 %2564 + OpBranch %2557 + %2558 = OpLabel + %2609 = OpExtInst %float %1 Log %float_9_99999975en05 + %2610 = OpFDiv %float %2609 %1065 + OpBranch %2557 + %2557 = OpLabel + %2611 = OpPhi %float %2608 %2563 %2610 %2558 + %2612 = OpExtInst %float %1 Pow %float_10 %2611 + %2613 = OpExtInst %float %1 Pow %float_2 %float_10 + %2614 = OpFMul %float %float_0_179999992 %2613 + OpStore %536 %475 + OpStore %535 %476 + %2615 = OpFOrdLessThanEqual %bool %2614 %float_0 + %2616 = OpSelect %float %2615 %2255 %2614 + %2617 = OpExtInst %float %1 Log %2616 + %2618 = OpFDiv %float %2617 %1065 + %2619 = OpFOrdLessThanEqual %bool %2618 %2260 + OpSelectionMerge %2620 None + OpBranchConditional %2619 %2621 %2622 + %2622 = OpLabel + %2623 = OpFOrdGreaterThan %bool %2618 %2260 + %2624 = OpFOrdLessThan %bool %2618 %2555 + %2625 = OpLogicalAnd %bool %2623 %2624 + OpSelectionMerge %2626 None + OpBranchConditional %2625 %2627 %2628 + %2628 = OpLabel + %2629 = OpFOrdGreaterThanEqual %bool %2618 %2555 + %2630 = OpExtInst %float %1 Log %2253 + %2631 = OpFDiv %float %2630 %1065 + %2632 = OpFOrdLessThan %bool %2618 %2631 + %2633 = OpLogicalAnd %bool %2629 %2632 + OpSelectionMerge %2634 None + OpBranchConditional %2633 %2635 %2636 + %2636 = OpLabel + %2637 = OpExtInst %float %1 Log %float_10000 + %2638 = OpFDiv %float %2637 %1065 + OpBranch %2634 + %2635 = OpLabel + %2639 = OpFSub %float %2618 %2555 + %2640 = OpFMul %float %float_3 %2639 + %2641 = OpFSub %float %2631 %2555 + %2642 = OpFDiv %float %2640 %2641 + %2643 = OpConvertFToS %int %2642 + %2644 = OpConvertSToF %float %2643 + %2645 = OpFSub %float %2642 %2644 + %2646 = OpAccessChain %_ptr_Function_float %535 %2643 + %2647 = OpLoad %float %2646 + %2648 = OpIAdd %int %2643 %int_1 + %2649 = OpAccessChain %_ptr_Function_float %535 %2648 + %2650 = OpLoad %float %2649 + %2651 = OpIAdd %int %2643 %int_2 + %2652 = OpAccessChain %_ptr_Function_float %535 %2651 + %2653 = OpLoad %float %2652 + %2654 = OpCompositeConstruct %v3float %2647 %2650 %2653 + %2655 = OpFMul %float %2645 %2645 + %2656 = OpCompositeConstruct %v3float %2655 %2645 %float_1 + %2657 = OpMatrixTimesVector %v3float %442 %2654 + %2658 = OpDot %float %2656 %2657 + OpBranch %2634 + %2634 = OpLabel + %2659 = OpPhi %float %2638 %2636 %2658 %2635 + OpBranch %2626 + %2627 = OpLabel + %2660 = OpFSub %float %2618 %2260 + %2661 = OpFMul %float %float_3 %2660 + %2662 = OpFSub %float %2555 %2260 + %2663 = OpFDiv %float %2661 %2662 + %2664 = OpConvertFToS %int %2663 + %2665 = OpConvertSToF %float %2664 + %2666 = OpFSub %float %2663 %2665 + %2667 = OpAccessChain %_ptr_Function_float %536 %2664 + %2668 = OpLoad %float %2667 + %2669 = OpIAdd %int %2664 %int_1 + %2670 = OpAccessChain %_ptr_Function_float %536 %2669 + %2671 = OpLoad %float %2670 + %2672 = OpIAdd %int %2664 %int_2 + %2673 = OpAccessChain %_ptr_Function_float %536 %2672 + %2674 = OpLoad %float %2673 + %2675 = OpCompositeConstruct %v3float %2668 %2671 %2674 + %2676 = OpFMul %float %2666 %2666 + %2677 = OpCompositeConstruct %v3float %2676 %2666 %float_1 + %2678 = OpMatrixTimesVector %v3float %442 %2675 + %2679 = OpDot %float %2677 %2678 + OpBranch %2626 + %2626 = OpLabel + %2680 = OpPhi %float %2659 %2634 %2679 %2627 + OpBranch %2620 + %2621 = OpLabel + %2681 = OpExtInst %float %1 Log %float_9_99999975en05 + %2682 = OpFDiv %float %2681 %1065 + OpBranch %2620 + %2620 = OpLabel + %2683 = OpPhi %float %2680 %2626 %2682 %2621 + %2684 = OpExtInst %float %1 Pow %float_10 %2683 + %2685 = OpCompositeExtract %float %2479 0 + OpStore %530 %479 + OpStore %529 %480 + %2686 = OpFOrdLessThanEqual %bool %2685 %float_0 + %2687 = OpSelect %float %2686 %float_9_99999975en05 %2685 + %2688 = OpExtInst %float %1 Log %2687 + %2689 = OpFDiv %float %2688 %1065 + %2690 = OpExtInst %float %1 Log %2553 + %2691 = OpFDiv %float %2690 %1065 + %2692 = OpFOrdLessThanEqual %bool %2689 %2691 + OpSelectionMerge %2693 None + OpBranchConditional %2692 %2694 %2695 + %2695 = OpLabel + %2696 = OpFOrdGreaterThan %bool %2689 %2691 + %2697 = OpExtInst %float %1 Log %2612 + %2698 = OpFDiv %float %2697 %1065 + %2699 = OpFOrdLessThan %bool %2689 %2698 + %2700 = OpLogicalAnd %bool %2696 %2699 + OpSelectionMerge %2701 None + OpBranchConditional %2700 %2702 %2703 + %2703 = OpLabel + %2704 = OpFOrdGreaterThanEqual %bool %2689 %2698 + %2705 = OpExtInst %float %1 Log %2684 + %2706 = OpFDiv %float %2705 %1065 + %2707 = OpFOrdLessThan %bool %2689 %2706 + %2708 = OpLogicalAnd %bool %2704 %2707 + OpSelectionMerge %2709 None + OpBranchConditional %2708 %2710 %2711 + %2711 = OpLabel + %2712 = OpFMul %float %2689 %float_0_0599999987 + %2713 = OpExtInst %float %1 Log %float_1000 + %2714 = OpFDiv %float %2713 %1065 + %2715 = OpFMul %float %float_0_0599999987 %2705 + %2716 = OpFDiv %float %2715 %1065 + %2717 = OpFSub %float %2714 %2716 + %2718 = OpFAdd %float %2712 %2717 + OpBranch %2709 + %2710 = OpLabel + %2719 = OpFSub %float %2689 %2698 + %2720 = OpFMul %float %float_7 %2719 + %2721 = OpFSub %float %2706 %2698 + %2722 = OpFDiv %float %2720 %2721 + %2723 = OpConvertFToS %int %2722 + %2724 = OpConvertSToF %float %2723 + %2725 = OpFSub %float %2722 %2724 + %2726 = OpAccessChain %_ptr_Function_float %529 %2723 + %2727 = OpLoad %float %2726 + %2728 = OpIAdd %int %2723 %int_1 + %2729 = OpAccessChain %_ptr_Function_float %529 %2728 + %2730 = OpLoad %float %2729 + %2731 = OpIAdd %int %2723 %int_2 + %2732 = OpAccessChain %_ptr_Function_float %529 %2731 + %2733 = OpLoad %float %2732 + %2734 = OpCompositeConstruct %v3float %2727 %2730 %2733 + %2735 = OpFMul %float %2725 %2725 + %2736 = OpCompositeConstruct %v3float %2735 %2725 %float_1 + %2737 = OpMatrixTimesVector %v3float %442 %2734 + %2738 = OpDot %float %2736 %2737 + OpBranch %2709 + %2709 = OpLabel + %2739 = OpPhi %float %2718 %2711 %2738 %2710 + OpBranch %2701 + %2702 = OpLabel + %2740 = OpFSub %float %2689 %2691 + %2741 = OpFMul %float %float_7 %2740 + %2742 = OpFSub %float %2698 %2691 + %2743 = OpFDiv %float %2741 %2742 + %2744 = OpConvertFToS %int %2743 + %2745 = OpConvertSToF %float %2744 + %2746 = OpFSub %float %2743 %2745 + %2747 = OpAccessChain %_ptr_Function_float %530 %2744 + %2748 = OpLoad %float %2747 + %2749 = OpIAdd %int %2744 %int_1 + %2750 = OpAccessChain %_ptr_Function_float %530 %2749 + %2751 = OpLoad %float %2750 + %2752 = OpIAdd %int %2744 %int_2 + %2753 = OpAccessChain %_ptr_Function_float %530 %2752 + %2754 = OpLoad %float %2753 + %2755 = OpCompositeConstruct %v3float %2748 %2751 %2754 + %2756 = OpFMul %float %2746 %2746 + %2757 = OpCompositeConstruct %v3float %2756 %2746 %float_1 + %2758 = OpMatrixTimesVector %v3float %442 %2755 + %2759 = OpDot %float %2757 %2758 + OpBranch %2701 + %2701 = OpLabel + %2760 = OpPhi %float %2739 %2709 %2759 %2702 + OpBranch %2693 + %2694 = OpLabel + %2761 = OpFMul %float %2689 %float_3 + %2762 = OpExtInst %float %1 Log %float_9_99999975en05 + %2763 = OpFDiv %float %2762 %1065 + %2764 = OpFMul %float %float_3 %2690 + %2765 = OpFDiv %float %2764 %1065 + %2766 = OpFSub %float %2763 %2765 + %2767 = OpFAdd %float %2761 %2766 + OpBranch %2693 + %2693 = OpLabel + %2768 = OpPhi %float %2760 %2701 %2767 %2694 + %2769 = OpExtInst %float %1 Pow %float_10 %2768 + %2770 = OpCompositeInsert %v3float %2769 %391 0 + %2771 = OpCompositeExtract %float %2479 1 + OpStore %528 %479 + OpStore %527 %480 + %2772 = OpFOrdLessThanEqual %bool %2771 %float_0 + %2773 = OpSelect %float %2772 %float_9_99999975en05 %2771 + %2774 = OpExtInst %float %1 Log %2773 + %2775 = OpFDiv %float %2774 %1065 + %2776 = OpFOrdLessThanEqual %bool %2775 %2691 + OpSelectionMerge %2777 None + OpBranchConditional %2776 %2778 %2779 + %2779 = OpLabel + %2780 = OpFOrdGreaterThan %bool %2775 %2691 + %2781 = OpExtInst %float %1 Log %2612 + %2782 = OpFDiv %float %2781 %1065 + %2783 = OpFOrdLessThan %bool %2775 %2782 + %2784 = OpLogicalAnd %bool %2780 %2783 + OpSelectionMerge %2785 None + OpBranchConditional %2784 %2786 %2787 + %2787 = OpLabel + %2788 = OpFOrdGreaterThanEqual %bool %2775 %2782 + %2789 = OpExtInst %float %1 Log %2684 + %2790 = OpFDiv %float %2789 %1065 + %2791 = OpFOrdLessThan %bool %2775 %2790 + %2792 = OpLogicalAnd %bool %2788 %2791 + OpSelectionMerge %2793 None + OpBranchConditional %2792 %2794 %2795 + %2795 = OpLabel + %2796 = OpFMul %float %2775 %float_0_0599999987 + %2797 = OpExtInst %float %1 Log %float_1000 + %2798 = OpFDiv %float %2797 %1065 + %2799 = OpFMul %float %float_0_0599999987 %2789 + %2800 = OpFDiv %float %2799 %1065 + %2801 = OpFSub %float %2798 %2800 + %2802 = OpFAdd %float %2796 %2801 + OpBranch %2793 + %2794 = OpLabel + %2803 = OpFSub %float %2775 %2782 + %2804 = OpFMul %float %float_7 %2803 + %2805 = OpFSub %float %2790 %2782 + %2806 = OpFDiv %float %2804 %2805 + %2807 = OpConvertFToS %int %2806 + %2808 = OpConvertSToF %float %2807 + %2809 = OpFSub %float %2806 %2808 + %2810 = OpAccessChain %_ptr_Function_float %527 %2807 + %2811 = OpLoad %float %2810 + %2812 = OpIAdd %int %2807 %int_1 + %2813 = OpAccessChain %_ptr_Function_float %527 %2812 + %2814 = OpLoad %float %2813 + %2815 = OpIAdd %int %2807 %int_2 + %2816 = OpAccessChain %_ptr_Function_float %527 %2815 + %2817 = OpLoad %float %2816 + %2818 = OpCompositeConstruct %v3float %2811 %2814 %2817 + %2819 = OpFMul %float %2809 %2809 + %2820 = OpCompositeConstruct %v3float %2819 %2809 %float_1 + %2821 = OpMatrixTimesVector %v3float %442 %2818 + %2822 = OpDot %float %2820 %2821 + OpBranch %2793 + %2793 = OpLabel + %2823 = OpPhi %float %2802 %2795 %2822 %2794 + OpBranch %2785 + %2786 = OpLabel + %2824 = OpFSub %float %2775 %2691 + %2825 = OpFMul %float %float_7 %2824 + %2826 = OpFSub %float %2782 %2691 + %2827 = OpFDiv %float %2825 %2826 + %2828 = OpConvertFToS %int %2827 + %2829 = OpConvertSToF %float %2828 + %2830 = OpFSub %float %2827 %2829 + %2831 = OpAccessChain %_ptr_Function_float %528 %2828 + %2832 = OpLoad %float %2831 + %2833 = OpIAdd %int %2828 %int_1 + %2834 = OpAccessChain %_ptr_Function_float %528 %2833 + %2835 = OpLoad %float %2834 + %2836 = OpIAdd %int %2828 %int_2 + %2837 = OpAccessChain %_ptr_Function_float %528 %2836 + %2838 = OpLoad %float %2837 + %2839 = OpCompositeConstruct %v3float %2832 %2835 %2838 + %2840 = OpFMul %float %2830 %2830 + %2841 = OpCompositeConstruct %v3float %2840 %2830 %float_1 + %2842 = OpMatrixTimesVector %v3float %442 %2839 + %2843 = OpDot %float %2841 %2842 + OpBranch %2785 + %2785 = OpLabel + %2844 = OpPhi %float %2823 %2793 %2843 %2786 + OpBranch %2777 + %2778 = OpLabel + %2845 = OpFMul %float %2775 %float_3 + %2846 = OpExtInst %float %1 Log %float_9_99999975en05 + %2847 = OpFDiv %float %2846 %1065 + %2848 = OpFMul %float %float_3 %2690 + %2849 = OpFDiv %float %2848 %1065 + %2850 = OpFSub %float %2847 %2849 + %2851 = OpFAdd %float %2845 %2850 + OpBranch %2777 + %2777 = OpLabel + %2852 = OpPhi %float %2844 %2785 %2851 %2778 + %2853 = OpExtInst %float %1 Pow %float_10 %2852 + %2854 = OpCompositeInsert %v3float %2853 %2770 1 + %2855 = OpCompositeExtract %float %2479 2 + OpStore %526 %479 + OpStore %525 %480 + %2856 = OpFOrdLessThanEqual %bool %2855 %float_0 + %2857 = OpSelect %float %2856 %float_9_99999975en05 %2855 + %2858 = OpExtInst %float %1 Log %2857 + %2859 = OpFDiv %float %2858 %1065 + %2860 = OpFOrdLessThanEqual %bool %2859 %2691 + OpSelectionMerge %2861 None + OpBranchConditional %2860 %2862 %2863 + %2863 = OpLabel + %2864 = OpFOrdGreaterThan %bool %2859 %2691 + %2865 = OpExtInst %float %1 Log %2612 + %2866 = OpFDiv %float %2865 %1065 + %2867 = OpFOrdLessThan %bool %2859 %2866 + %2868 = OpLogicalAnd %bool %2864 %2867 + OpSelectionMerge %2869 None + OpBranchConditional %2868 %2870 %2871 + %2871 = OpLabel + %2872 = OpFOrdGreaterThanEqual %bool %2859 %2866 + %2873 = OpExtInst %float %1 Log %2684 + %2874 = OpFDiv %float %2873 %1065 + %2875 = OpFOrdLessThan %bool %2859 %2874 + %2876 = OpLogicalAnd %bool %2872 %2875 + OpSelectionMerge %2877 None + OpBranchConditional %2876 %2878 %2879 + %2879 = OpLabel + %2880 = OpFMul %float %2859 %float_0_0599999987 + %2881 = OpExtInst %float %1 Log %float_1000 + %2882 = OpFDiv %float %2881 %1065 + %2883 = OpFMul %float %float_0_0599999987 %2873 + %2884 = OpFDiv %float %2883 %1065 + %2885 = OpFSub %float %2882 %2884 + %2886 = OpFAdd %float %2880 %2885 + OpBranch %2877 + %2878 = OpLabel + %2887 = OpFSub %float %2859 %2866 + %2888 = OpFMul %float %float_7 %2887 + %2889 = OpFSub %float %2874 %2866 + %2890 = OpFDiv %float %2888 %2889 + %2891 = OpConvertFToS %int %2890 + %2892 = OpConvertSToF %float %2891 + %2893 = OpFSub %float %2890 %2892 + %2894 = OpAccessChain %_ptr_Function_float %525 %2891 + %2895 = OpLoad %float %2894 + %2896 = OpIAdd %int %2891 %int_1 + %2897 = OpAccessChain %_ptr_Function_float %525 %2896 + %2898 = OpLoad %float %2897 + %2899 = OpIAdd %int %2891 %int_2 + %2900 = OpAccessChain %_ptr_Function_float %525 %2899 + %2901 = OpLoad %float %2900 + %2902 = OpCompositeConstruct %v3float %2895 %2898 %2901 + %2903 = OpFMul %float %2893 %2893 + %2904 = OpCompositeConstruct %v3float %2903 %2893 %float_1 + %2905 = OpMatrixTimesVector %v3float %442 %2902 + %2906 = OpDot %float %2904 %2905 + OpBranch %2877 + %2877 = OpLabel + %2907 = OpPhi %float %2886 %2879 %2906 %2878 + OpBranch %2869 + %2870 = OpLabel + %2908 = OpFSub %float %2859 %2691 + %2909 = OpFMul %float %float_7 %2908 + %2910 = OpFSub %float %2866 %2691 + %2911 = OpFDiv %float %2909 %2910 + %2912 = OpConvertFToS %int %2911 + %2913 = OpConvertSToF %float %2912 + %2914 = OpFSub %float %2911 %2913 + %2915 = OpAccessChain %_ptr_Function_float %526 %2912 + %2916 = OpLoad %float %2915 + %2917 = OpIAdd %int %2912 %int_1 + %2918 = OpAccessChain %_ptr_Function_float %526 %2917 + %2919 = OpLoad %float %2918 + %2920 = OpIAdd %int %2912 %int_2 + %2921 = OpAccessChain %_ptr_Function_float %526 %2920 + %2922 = OpLoad %float %2921 + %2923 = OpCompositeConstruct %v3float %2916 %2919 %2922 + %2924 = OpFMul %float %2914 %2914 + %2925 = OpCompositeConstruct %v3float %2924 %2914 %float_1 + %2926 = OpMatrixTimesVector %v3float %442 %2923 + %2927 = OpDot %float %2925 %2926 + OpBranch %2869 + %2869 = OpLabel + %2928 = OpPhi %float %2907 %2877 %2927 %2870 + OpBranch %2861 + %2862 = OpLabel + %2929 = OpFMul %float %2859 %float_3 + %2930 = OpExtInst %float %1 Log %float_9_99999975en05 + %2931 = OpFDiv %float %2930 %1065 + %2932 = OpFMul %float %float_3 %2690 + %2933 = OpFDiv %float %2932 %1065 + %2934 = OpFSub %float %2931 %2933 + %2935 = OpFAdd %float %2929 %2934 + OpBranch %2861 + %2861 = OpLabel + %2936 = OpPhi %float %2928 %2869 %2935 %2862 + %2937 = OpExtInst %float %1 Pow %float_10 %2936 + %2938 = OpCompositeInsert %v3float %2937 %2854 2 + %2939 = OpFSub %v3float %2938 %338 + %2940 = OpVectorTimesMatrix %v3float %2939 %576 + %2941 = OpFMul %v3float %2940 %496 + %2942 = OpExtInst %v3float %1 Pow %2941 %263 + %2943 = OpFMul %v3float %184 %2942 + %2944 = OpFAdd %v3float %183 %2943 + %2945 = OpFMul %v3float %185 %2942 + %2946 = OpFAdd %v3float %135 %2945 + %2947 = OpFDiv %v3float %135 %2946 + %2948 = OpFMul %v3float %2944 %2947 + %2949 = OpExtInst %v3float %1 Pow %2948 %264 + OpBranch %1230 + %1230 = OpLabel + %2950 = OpPhi %v3float %2097 %1236 %2949 %2861 + OpBranch %1224 + %1225 = OpLabel + %2951 = OpVectorTimesMatrix %v3float %1218 %547 + %2952 = OpVectorTimesMatrix %v3float %2951 %576 + %2953 = OpExtInst %v3float %1 FMax %250 %2952 + %2954 = OpFMul %v3float %2953 %252 + %2955 = OpExtInst %v3float %1 FMax %2953 %254 + %2956 = OpExtInst %v3float %1 Pow %2955 %256 + %2957 = OpFMul %v3float %2956 %258 + %2958 = OpFSub %v3float %2957 %260 + %2959 = OpExtInst %v3float %1 FMin %2954 %2958 + OpBranch %1224 + %1224 = OpLabel + %2960 = OpPhi %v3float %2950 %1230 %2959 %1225 + OpBranch %1220 + %1221 = OpLabel + %2961 = OpCompositeExtract %float %1218 0 + OpBranch %2962 + %2962 = OpLabel + OpLoopMerge %2963 %2964 None + OpBranch %2965 + %2965 = OpLabel + %2966 = OpFOrdLessThan %bool %2961 %float_0_00313066994 + OpSelectionMerge %2967 None + OpBranchConditional %2966 %2968 %2967 + %2968 = OpLabel + %2969 = OpFMul %float %2961 %float_12_9200001 + OpBranch %2963 + %2967 = OpLabel + %2970 = OpExtInst %float %1 Pow %2961 %float_0_416666657 + %2971 = OpFMul %float %2970 %float_1_05499995 + %2972 = OpFSub %float %2971 %float_0_0549999997 + OpBranch %2963 + %2964 = OpLabel + OpBranch %2962 + %2963 = OpLabel + %2973 = OpPhi %float %2969 %2968 %2972 %2967 + %2974 = OpCompositeExtract %float %1218 1 + OpBranch %2975 + %2975 = OpLabel + OpLoopMerge %2976 %2977 None + OpBranch %2978 + %2978 = OpLabel + %2979 = OpFOrdLessThan %bool %2974 %float_0_00313066994 + OpSelectionMerge %2980 None + OpBranchConditional %2979 %2981 %2980 + %2981 = OpLabel + %2982 = OpFMul %float %2974 %float_12_9200001 + OpBranch %2976 + %2980 = OpLabel + %2983 = OpExtInst %float %1 Pow %2974 %float_0_416666657 + %2984 = OpFMul %float %2983 %float_1_05499995 + %2985 = OpFSub %float %2984 %float_0_0549999997 + OpBranch %2976 + %2977 = OpLabel + OpBranch %2975 + %2976 = OpLabel + %2986 = OpPhi %float %2982 %2981 %2985 %2980 + %2987 = OpCompositeExtract %float %1218 2 + OpBranch %2988 + %2988 = OpLabel + OpLoopMerge %2989 %2990 None + OpBranch %2991 + %2991 = OpLabel + %2992 = OpFOrdLessThan %bool %2987 %float_0_00313066994 + OpSelectionMerge %2993 None + OpBranchConditional %2992 %2994 %2993 + %2994 = OpLabel + %2995 = OpFMul %float %2987 %float_12_9200001 + OpBranch %2989 + %2993 = OpLabel + %2996 = OpExtInst %float %1 Pow %2987 %float_0_416666657 + %2997 = OpFMul %float %2996 %float_1_05499995 + %2998 = OpFSub %float %2997 %float_0_0549999997 + OpBranch %2989 + %2990 = OpLabel + OpBranch %2988 + %2989 = OpLabel + %2999 = OpPhi %float %2995 %2994 %2998 %2993 + %3000 = OpCompositeConstruct %v3float %2973 %2986 %2999 + OpBranch %1220 + %1220 = OpLabel + %3001 = OpPhi %v3float %2960 %1224 %3000 %2989 + %3002 = OpFMul %v3float %3001 %499 + %3003 = OpVectorShuffle %v4float %129 %3002 4 5 6 3 + %3004 = OpCompositeInsert %v4float %float_0 %3003 3 + OpStore %out_var_SV_Target0 %3004 + OpReturn + OpFunctionEnd diff --git a/third_party/spirv-cross/shaders-ue4/asm/frag/padded-float-array-member-defef.asm.frag b/third_party/spirv-cross/shaders-ue4/asm/frag/padded-float-array-member-defef.asm.frag new file mode 100644 index 0000000000..e0359bfdd3 --- /dev/null +++ b/third_party/spirv-cross/shaders-ue4/asm/frag/padded-float-array-member-defef.asm.frag @@ -0,0 +1,3694 @@ +; SPIR-V +; Version: 1.0 +; Generator: Google spiregg; 0 +; Bound: 3107 +; Schema: 0 + OpCapability Shader + OpCapability Geometry + OpExtension "SPV_GOOGLE_hlsl_functionality1" + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %MainPS "main" %in_var_TEXCOORD0 %gl_FragCoord %gl_Layer %out_var_SV_Target0 + OpExecutionMode %MainPS OriginUpperLeft + OpSource HLSL 600 + OpName %type__Globals "type.$Globals" + OpMemberName %type__Globals 0 "MappingPolynomial" + OpMemberName %type__Globals 1 "InverseGamma" + OpMemberName %type__Globals 2 "ColorMatrixR_ColorCurveCd1" + OpMemberName %type__Globals 3 "ColorMatrixG_ColorCurveCd3Cm3" + OpMemberName %type__Globals 4 "ColorMatrixB_ColorCurveCm2" + OpMemberName %type__Globals 5 "ColorCurve_Cm0Cd0_Cd2_Ch0Cm1_Ch3" + OpMemberName %type__Globals 6 "ColorCurve_Ch1_Ch2" + OpMemberName %type__Globals 7 "ColorShadow_Luma" + OpMemberName %type__Globals 8 "ColorShadow_Tint1" + OpMemberName %type__Globals 9 "ColorShadow_Tint2" + OpMemberName %type__Globals 10 "FilmSlope" + OpMemberName %type__Globals 11 "FilmToe" + OpMemberName %type__Globals 12 "FilmShoulder" + OpMemberName %type__Globals 13 "FilmBlackClip" + OpMemberName %type__Globals 14 "FilmWhiteClip" + OpMemberName %type__Globals 15 "LUTWeights" + OpMemberName %type__Globals 16 "ColorScale" + OpMemberName %type__Globals 17 "OverlayColor" + OpMemberName %type__Globals 18 "WhiteTemp" + OpMemberName %type__Globals 19 "WhiteTint" + OpMemberName %type__Globals 20 "ColorSaturation" + OpMemberName %type__Globals 21 "ColorContrast" + OpMemberName %type__Globals 22 "ColorGamma" + OpMemberName %type__Globals 23 "ColorGain" + OpMemberName %type__Globals 24 "ColorOffset" + OpMemberName %type__Globals 25 "ColorSaturationShadows" + OpMemberName %type__Globals 26 "ColorContrastShadows" + OpMemberName %type__Globals 27 "ColorGammaShadows" + OpMemberName %type__Globals 28 "ColorGainShadows" + OpMemberName %type__Globals 29 "ColorOffsetShadows" + OpMemberName %type__Globals 30 "ColorSaturationMidtones" + OpMemberName %type__Globals 31 "ColorContrastMidtones" + OpMemberName %type__Globals 32 "ColorGammaMidtones" + OpMemberName %type__Globals 33 "ColorGainMidtones" + OpMemberName %type__Globals 34 "ColorOffsetMidtones" + OpMemberName %type__Globals 35 "ColorSaturationHighlights" + OpMemberName %type__Globals 36 "ColorContrastHighlights" + OpMemberName %type__Globals 37 "ColorGammaHighlights" + OpMemberName %type__Globals 38 "ColorGainHighlights" + OpMemberName %type__Globals 39 "ColorOffsetHighlights" + OpMemberName %type__Globals 40 "ColorCorrectionShadowsMax" + OpMemberName %type__Globals 41 "ColorCorrectionHighlightsMin" + OpMemberName %type__Globals 42 "OutputDevice" + OpMemberName %type__Globals 43 "OutputGamut" + OpMemberName %type__Globals 44 "BlueCorrection" + OpMemberName %type__Globals 45 "ExpandGamut" + OpName %_Globals "$Globals" + OpName %type_2d_image "type.2d.image" + OpName %Texture1 "Texture1" + OpName %type_sampler "type.sampler" + OpName %Texture1Sampler "Texture1Sampler" + OpName %in_var_TEXCOORD0 "in.var.TEXCOORD0" + OpName %out_var_SV_Target0 "out.var.SV_Target0" + OpName %MainPS "MainPS" + OpName %type_sampled_image "type.sampled.image" + OpDecorateString %in_var_TEXCOORD0 UserSemantic "TEXCOORD0" + OpDecorate %in_var_TEXCOORD0 NoPerspective + OpDecorate %gl_FragCoord BuiltIn FragCoord + OpDecorateString %gl_FragCoord UserSemantic "SV_POSITION" + OpDecorate %gl_Layer BuiltIn Layer + OpDecorateString %gl_Layer UserSemantic "SV_RenderTargetArrayIndex" + OpDecorate %gl_Layer Flat + OpDecorateString %out_var_SV_Target0 UserSemantic "SV_Target0" + OpDecorate %in_var_TEXCOORD0 Location 0 + OpDecorate %out_var_SV_Target0 Location 0 + OpDecorate %_Globals DescriptorSet 0 + OpDecorate %_Globals Binding 0 + OpDecorate %Texture1 DescriptorSet 0 + OpDecorate %Texture1 Binding 0 + OpDecorate %Texture1Sampler DescriptorSet 0 + OpDecorate %Texture1Sampler Binding 0 + OpDecorate %_arr_float_uint_5 ArrayStride 16 + OpMemberDecorate %type__Globals 0 Offset 0 + OpMemberDecorate %type__Globals 1 Offset 16 + OpMemberDecorate %type__Globals 2 Offset 32 + OpMemberDecorate %type__Globals 3 Offset 48 + OpMemberDecorate %type__Globals 4 Offset 64 + OpMemberDecorate %type__Globals 5 Offset 80 + OpMemberDecorate %type__Globals 6 Offset 96 + OpMemberDecorate %type__Globals 7 Offset 112 + OpMemberDecorate %type__Globals 8 Offset 128 + OpMemberDecorate %type__Globals 9 Offset 144 + OpMemberDecorate %type__Globals 10 Offset 160 + OpMemberDecorate %type__Globals 11 Offset 164 + OpMemberDecorate %type__Globals 12 Offset 168 + OpMemberDecorate %type__Globals 13 Offset 172 + OpMemberDecorate %type__Globals 14 Offset 176 + OpMemberDecorate %type__Globals 15 Offset 192 + OpMemberDecorate %type__Globals 16 Offset 272 + OpMemberDecorate %type__Globals 17 Offset 288 + OpMemberDecorate %type__Globals 18 Offset 304 + OpMemberDecorate %type__Globals 19 Offset 308 + OpMemberDecorate %type__Globals 20 Offset 320 + OpMemberDecorate %type__Globals 21 Offset 336 + OpMemberDecorate %type__Globals 22 Offset 352 + OpMemberDecorate %type__Globals 23 Offset 368 + OpMemberDecorate %type__Globals 24 Offset 384 + OpMemberDecorate %type__Globals 25 Offset 400 + OpMemberDecorate %type__Globals 26 Offset 416 + OpMemberDecorate %type__Globals 27 Offset 432 + OpMemberDecorate %type__Globals 28 Offset 448 + OpMemberDecorate %type__Globals 29 Offset 464 + OpMemberDecorate %type__Globals 30 Offset 480 + OpMemberDecorate %type__Globals 31 Offset 496 + OpMemberDecorate %type__Globals 32 Offset 512 + OpMemberDecorate %type__Globals 33 Offset 528 + OpMemberDecorate %type__Globals 34 Offset 544 + OpMemberDecorate %type__Globals 35 Offset 560 + OpMemberDecorate %type__Globals 36 Offset 576 + OpMemberDecorate %type__Globals 37 Offset 592 + OpMemberDecorate %type__Globals 38 Offset 608 + OpMemberDecorate %type__Globals 39 Offset 624 + OpMemberDecorate %type__Globals 40 Offset 640 + OpMemberDecorate %type__Globals 41 Offset 644 + OpMemberDecorate %type__Globals 42 Offset 648 + OpMemberDecorate %type__Globals 43 Offset 652 + OpMemberDecorate %type__Globals 44 Offset 656 + OpMemberDecorate %type__Globals 45 Offset 660 + OpDecorate %type__Globals Block + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 + %v3float = OpTypeVector %float 3 + %v2float = OpTypeVector %float 2 + %int = OpTypeInt 32 1 + %uint = OpTypeInt 32 0 + %uint_2 = OpConstant %uint 2 + %uint_7 = OpConstant %uint 7 + %uint_4 = OpConstant %uint 4 +%float_0_952552378 = OpConstant %float 0.952552378 + %float_0 = OpConstant %float 0 + +; HACK: Needed to hack this constant since MSVC and GNU libc are off by 1 ULP when converting to string (it probably still works fine though in a roundtrip ...) +%float_9_36786018en05 = OpConstant %float 9.25 + +%float_0_343966454 = OpConstant %float 0.343966454 +%float_0_728166103 = OpConstant %float 0.728166103 +%float_n0_0721325427 = OpConstant %float -0.0721325427 +%float_1_00882518 = OpConstant %float 1.00882518 +%float_1_04981101 = OpConstant %float 1.04981101 +%float_n9_74845025en05 = OpConstant %float -9.74845025e-05 +%float_n0_495903015 = OpConstant %float -0.495903015 +%float_1_37331307 = OpConstant %float 1.37331307 +%float_0_0982400328 = OpConstant %float 0.0982400328 +%float_0_991252005 = OpConstant %float 0.991252005 +%float_0_662454188 = OpConstant %float 0.662454188 +%float_0_134004205 = OpConstant %float 0.134004205 +%float_0_156187683 = OpConstant %float 0.156187683 +%float_0_272228718 = OpConstant %float 0.272228718 +%float_0_674081743 = OpConstant %float 0.674081743 +%float_0_0536895171 = OpConstant %float 0.0536895171 +%float_n0_00557464967 = OpConstant %float -0.00557464967 +%float_0_0040607336 = OpConstant %float 0.0040607336 +%float_1_01033914 = OpConstant %float 1.01033914 +%float_1_6410234 = OpConstant %float 1.6410234 +%float_n0_324803293 = OpConstant %float -0.324803293 +%float_n0_236424699 = OpConstant %float -0.236424699 +%float_n0_663662851 = OpConstant %float -0.663662851 +%float_1_61533165 = OpConstant %float 1.61533165 +%float_0_0167563483 = OpConstant %float 0.0167563483 +%float_0_0117218941 = OpConstant %float 0.0117218941 +%float_n0_00828444213 = OpConstant %float -0.00828444213 +%float_0_988394856 = OpConstant %float 0.988394856 +%float_1_45143926 = OpConstant %float 1.45143926 +%float_n0_236510754 = OpConstant %float -0.236510754 +%float_n0_214928567 = OpConstant %float -0.214928567 +%float_n0_0765537769 = OpConstant %float -0.0765537769 +%float_1_17622972 = OpConstant %float 1.17622972 +%float_n0_0996759236 = OpConstant %float -0.0996759236 +%float_0_00831614807 = OpConstant %float 0.00831614807 +%float_n0_00603244966 = OpConstant %float -0.00603244966 +%float_0_997716308 = OpConstant %float 0.997716308 +%float_0_695452213 = OpConstant %float 0.695452213 +%float_0_140678704 = OpConstant %float 0.140678704 +%float_0_163869068 = OpConstant %float 0.163869068 +%float_0_0447945632 = OpConstant %float 0.0447945632 +%float_0_859671116 = OpConstant %float 0.859671116 +%float_0_0955343172 = OpConstant %float 0.0955343172 +%float_n0_00552588282 = OpConstant %float -0.00552588282 +%float_0_00402521016 = OpConstant %float 0.00402521016 +%float_1_00150073 = OpConstant %float 1.00150073 + %73 = OpConstantComposite %v3float %float_0_272228718 %float_0_674081743 %float_0_0536895171 +%float_3_2409699 = OpConstant %float 3.2409699 +%float_n1_5373832 = OpConstant %float -1.5373832 +%float_n0_498610765 = OpConstant %float -0.498610765 +%float_n0_969243646 = OpConstant %float -0.969243646 +%float_1_8759675 = OpConstant %float 1.8759675 +%float_0_0415550582 = OpConstant %float 0.0415550582 +%float_0_0556300804 = OpConstant %float 0.0556300804 +%float_n0_203976959 = OpConstant %float -0.203976959 +%float_1_05697155 = OpConstant %float 1.05697155 +%float_0_412456393 = OpConstant %float 0.412456393 +%float_0_357576102 = OpConstant %float 0.357576102 +%float_0_180437505 = OpConstant %float 0.180437505 +%float_0_212672904 = OpConstant %float 0.212672904 +%float_0_715152204 = OpConstant %float 0.715152204 +%float_0_0721750036 = OpConstant %float 0.0721750036 +%float_0_0193339009 = OpConstant %float 0.0193339009 +%float_0_119191997 = OpConstant %float 0.119191997 +%float_0_950304091 = OpConstant %float 0.950304091 +%float_1_71660841 = OpConstant %float 1.71660841 +%float_n0_355662107 = OpConstant %float -0.355662107 +%float_n0_253360093 = OpConstant %float -0.253360093 +%float_n0_666682899 = OpConstant %float -0.666682899 +%float_1_61647761 = OpConstant %float 1.61647761 +%float_0_0157685 = OpConstant %float 0.0157685 +%float_0_0176422 = OpConstant %float 0.0176422 +%float_n0_0427763015 = OpConstant %float -0.0427763015 +%float_0_942228675 = OpConstant %float 0.942228675 +%float_2_49339628 = OpConstant %float 2.49339628 +%float_n0_93134588 = OpConstant %float -0.93134588 +%float_n0_402694494 = OpConstant %float -0.402694494 +%float_n0_829486787 = OpConstant %float -0.829486787 +%float_1_76265967 = OpConstant %float 1.76265967 +%float_0_0236246008 = OpConstant %float 0.0236246008 +%float_0_0358507 = OpConstant %float 0.0358507 +%float_n0_0761827007 = OpConstant %float -0.0761827007 +%float_0_957014024 = OpConstant %float 0.957014024 +%float_1_01303005 = OpConstant %float 1.01303005 +%float_0_00610530982 = OpConstant %float 0.00610530982 +%float_n0_0149710001 = OpConstant %float -0.0149710001 +%float_0_00769822998 = OpConstant %float 0.00769822998 +%float_0_998165011 = OpConstant %float 0.998165011 +%float_n0_00503202993 = OpConstant %float -0.00503202993 +%float_n0_00284131011 = OpConstant %float -0.00284131011 +%float_0_00468515977 = OpConstant %float 0.00468515977 +%float_0_924507022 = OpConstant %float 0.924507022 +%float_0_987223983 = OpConstant %float 0.987223983 +%float_n0_00611326983 = OpConstant %float -0.00611326983 +%float_0_0159533005 = OpConstant %float 0.0159533005 +%float_n0_00759836007 = OpConstant %float -0.00759836007 +%float_1_00186002 = OpConstant %float 1.00186002 +%float_0_0053300201 = OpConstant %float 0.0053300201 +%float_0_00307257008 = OpConstant %float 0.00307257008 +%float_n0_00509594986 = OpConstant %float -0.00509594986 +%float_1_08168006 = OpConstant %float 1.08168006 + %float_0_5 = OpConstant %float 0.5 + %float_n1 = OpConstant %float -1 + %float_1 = OpConstant %float 1 + %int_0 = OpConstant %int 0 + %int_1 = OpConstant %int 1 +%float_0_015625 = OpConstant %float 0.015625 + %134 = OpConstantComposite %v2float %float_0_015625 %float_0_015625 + %135 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0 + %int_43 = OpConstant %int 43 + %uint_3 = OpConstant %uint 3 + %138 = OpConstantComposite %v3float %float_0 %float_0 %float_0 + %int_9 = OpConstant %int 9 + %int_3 = OpConstant %int 3 + %141 = OpConstantComposite %v3float %float_1 %float_1 %float_1 + %float_n4 = OpConstant %float -4 + %int_45 = OpConstant %int 45 +%float_0_544169128 = OpConstant %float 0.544169128 +%float_0_239592597 = OpConstant %float 0.239592597 +%float_0_166694298 = OpConstant %float 0.166694298 +%float_0_239465594 = OpConstant %float 0.239465594 +%float_0_702153027 = OpConstant %float 0.702153027 +%float_0_058381401 = OpConstant %float 0.058381401 +%float_n0_00234390004 = OpConstant %float -0.00234390004 +%float_0_0361833982 = OpConstant %float 0.0361833982 +%float_1_05521834 = OpConstant %float 1.05521834 +%float_0_940437257 = OpConstant %float 0.940437257 +%float_n0_0183068793 = OpConstant %float -0.0183068793 +%float_0_077869609 = OpConstant %float 0.077869609 +%float_0_00837869663 = OpConstant %float 0.00837869663 +%float_0_828660011 = OpConstant %float 0.828660011 +%float_0_162961304 = OpConstant %float 0.162961304 +%float_0_00054712611 = OpConstant %float 0.00054712611 +%float_n0_000883374596 = OpConstant %float -0.000883374596 +%float_1_00033629 = OpConstant %float 1.00033629 +%float_1_06317997 = OpConstant %float 1.06317997 +%float_0_0233955998 = OpConstant %float 0.0233955998 +%float_n0_0865726024 = OpConstant %float -0.0865726024 +%float_n0_0106336996 = OpConstant %float -0.0106336996 +%float_1_20632005 = OpConstant %float 1.20632005 +%float_n0_195690006 = OpConstant %float -0.195690006 +%float_n0_000590886979 = OpConstant %float -0.000590886979 +%float_0_00105247996 = OpConstant %float 0.00105247996 +%float_0_999538004 = OpConstant %float 0.999538004 + %int_44 = OpConstant %int 44 +%float_0_9375 = OpConstant %float 0.9375 + %173 = OpConstantComposite %v3float %float_0_9375 %float_0_9375 %float_0_9375 +%float_0_03125 = OpConstant %float 0.03125 + %175 = OpConstantComposite %v3float %float_0_03125 %float_0_03125 %float_0_03125 + %int_15 = OpConstant %int 15 + %float_16 = OpConstant %float 16 + %int_16 = OpConstant %int 16 + %int_17 = OpConstant %int 17 + %uint_0 = OpConstant %uint 0 + %uint_1 = OpConstant %uint 1 + %uint_5 = OpConstant %uint 5 + %uint_6 = OpConstant %uint 6 + %int_2 = OpConstant %int 2 +%mat3v3float = OpTypeMatrix %v3float 3 + %int_42 = OpConstant %int 42 +%float_0_159301758 = OpConstant %float 0.159301758 +%float_78_84375 = OpConstant %float 78.84375 +%float_0_8359375 = OpConstant %float 0.8359375 +%float_18_8515625 = OpConstant %float 18.8515625 +%float_18_6875 = OpConstant %float 18.6875 +%float_10000 = OpConstant %float 10000 +%float_0_0126833133 = OpConstant %float 0.0126833133 + %194 = OpConstantComposite %v3float %float_0_0126833133 %float_0_0126833133 %float_0_0126833133 + %195 = OpConstantComposite %v3float %float_0_8359375 %float_0_8359375 %float_0_8359375 + %196 = OpConstantComposite %v3float %float_18_8515625 %float_18_8515625 %float_18_8515625 + %197 = OpConstantComposite %v3float %float_18_6875 %float_18_6875 %float_18_6875 +%float_6_27739477 = OpConstant %float 6.27739477 + %199 = OpConstantComposite %v3float %float_6_27739477 %float_6_27739477 %float_6_27739477 + %200 = OpConstantComposite %v3float %float_10000 %float_10000 %float_10000 + %float_14 = OpConstant %float 14 +%float_0_180000007 = OpConstant %float 0.180000007 +%float_0_434017599 = OpConstant %float 0.434017599 + %204 = OpConstantComposite %v3float %float_0_434017599 %float_0_434017599 %float_0_434017599 + %205 = OpConstantComposite %v3float %float_14 %float_14 %float_14 + %206 = OpConstantComposite %v3float %float_0_180000007 %float_0_180000007 %float_0_180000007 + %int_18 = OpConstant %int 18 + %float_4000 = OpConstant %float 4000 +%float_0_312700003 = OpConstant %float 0.312700003 +%float_0_328999996 = OpConstant %float 0.328999996 + %int_19 = OpConstant %int 19 + %int_25 = OpConstant %int 25 + %int_20 = OpConstant %int 20 + %int_26 = OpConstant %int 26 + %int_21 = OpConstant %int 21 + %int_27 = OpConstant %int 27 + %int_22 = OpConstant %int 22 + %int_28 = OpConstant %int 28 + %int_23 = OpConstant %int 23 + %int_29 = OpConstant %int 29 + %int_24 = OpConstant %int 24 + %int_40 = OpConstant %int 40 + %int_35 = OpConstant %int 35 + %int_36 = OpConstant %int 36 + %int_37 = OpConstant %int 37 + %int_38 = OpConstant %int 38 + %int_39 = OpConstant %int 39 + %int_41 = OpConstant %int 41 + %int_30 = OpConstant %int 30 + %int_31 = OpConstant %int 31 + %int_32 = OpConstant %int 32 + %int_33 = OpConstant %int 33 + %int_34 = OpConstant %int 34 +%float_0_0500000007 = OpConstant %float 0.0500000007 + %float_1_75 = OpConstant %float 1.75 +%float_0_400000006 = OpConstant %float 0.400000006 +%float_0_819999993 = OpConstant %float 0.819999993 +%float_0_0299999993 = OpConstant %float 0.0299999993 + %float_2 = OpConstant %float 2 +%float_0_959999979 = OpConstant %float 0.959999979 + %241 = OpConstantComposite %v3float %float_0_959999979 %float_0_959999979 %float_0_959999979 + %int_13 = OpConstant %int 13 + %int_11 = OpConstant %int 11 + %int_14 = OpConstant %int 14 + %int_12 = OpConstant %int 12 +%float_0_800000012 = OpConstant %float 0.800000012 + %int_10 = OpConstant %int 10 + %float_10 = OpConstant %float 10 + %float_n2 = OpConstant %float -2 + %float_3 = OpConstant %float 3 + %251 = OpConstantComposite %v3float %float_3 %float_3 %float_3 + %252 = OpConstantComposite %v3float %float_2 %float_2 %float_2 +%float_0_930000007 = OpConstant %float 0.930000007 + %254 = OpConstantComposite %v3float %float_0_930000007 %float_0_930000007 %float_0_930000007 + %int_4 = OpConstant %int 4 + %int_8 = OpConstant %int 8 + %int_7 = OpConstant %int 7 + %int_5 = OpConstant %int 5 + %int_6 = OpConstant %int 6 +%float_0_00200000009 = OpConstant %float 0.00200000009 + %261 = OpConstantComposite %v3float %float_0_00200000009 %float_0_00200000009 %float_0_00200000009 +%float_6_10351999en05 = OpConstant %float 6.10351999e-05 + %263 = OpConstantComposite %v3float %float_6_10351999en05 %float_6_10351999en05 %float_6_10351999en05 +%float_0_0404499993 = OpConstant %float 0.0404499993 + %265 = OpConstantComposite %v3float %float_0_0404499993 %float_0_0404499993 %float_0_0404499993 +%float_0_947867274 = OpConstant %float 0.947867274 + %267 = OpConstantComposite %v3float %float_0_947867274 %float_0_947867274 %float_0_947867274 +%float_0_0521326996 = OpConstant %float 0.0521326996 + %269 = OpConstantComposite %v3float %float_0_0521326996 %float_0_0521326996 %float_0_0521326996 +%float_2_4000001 = OpConstant %float 2.4000001 + %271 = OpConstantComposite %v3float %float_2_4000001 %float_2_4000001 %float_2_4000001 +%float_0_0773993805 = OpConstant %float 0.0773993805 + %273 = OpConstantComposite %v3float %float_0_0773993805 %float_0_0773993805 %float_0_0773993805 + %float_4_5 = OpConstant %float 4.5 + %275 = OpConstantComposite %v3float %float_4_5 %float_4_5 %float_4_5 +%float_0_0179999992 = OpConstant %float 0.0179999992 + %277 = OpConstantComposite %v3float %float_0_0179999992 %float_0_0179999992 %float_0_0179999992 +%float_0_449999988 = OpConstant %float 0.449999988 + %279 = OpConstantComposite %v3float %float_0_449999988 %float_0_449999988 %float_0_449999988 +%float_1_09899998 = OpConstant %float 1.09899998 + %281 = OpConstantComposite %v3float %float_1_09899998 %float_1_09899998 %float_1_09899998 +%float_0_0989999995 = OpConstant %float 0.0989999995 + %283 = OpConstantComposite %v3float %float_0_0989999995 %float_0_0989999995 %float_0_0989999995 + %float_1_5 = OpConstant %float 1.5 + %285 = OpConstantComposite %v3float %float_1_5 %float_1_5 %float_1_5 + %286 = OpConstantComposite %v3float %float_0_159301758 %float_0_159301758 %float_0_159301758 + %287 = OpConstantComposite %v3float %float_78_84375 %float_78_84375 %float_78_84375 +%float_1_00055635 = OpConstant %float 1.00055635 + %float_7000 = OpConstant %float 7000 +%float_0_244063005 = OpConstant %float 0.244063005 +%float_99_1100006 = OpConstant %float 99.1100006 +%float_2967800 = OpConstant %float 2967800 +%float_0_237039998 = OpConstant %float 0.237039998 +%float_247_479996 = OpConstant %float 247.479996 +%float_1901800 = OpConstant %float 1901800 + %float_n3 = OpConstant %float -3 +%float_2_86999989 = OpConstant %float 2.86999989 +%float_0_275000006 = OpConstant %float 0.275000006 +%float_0_860117733 = OpConstant %float 0.860117733 +%float_0_000154118257 = OpConstant %float 0.000154118257 +%float_1_28641219en07 = OpConstant %float 1.28641219e-07 +%float_0_00084242021 = OpConstant %float 0.00084242021 +%float_7_08145137en07 = OpConstant %float 7.08145137e-07 +%float_0_317398727 = OpConstant %float 0.317398727 + +; HACK: Needed to hack this constant since MSVC and GNU libc are off by 1 ULP when converting to string (it probably still works fine though in a roundtrip ...) +%float_4_22806261en05 = OpConstant %float 4.25 + +%float_4_20481676en08 = OpConstant %float 4.20481676e-08 +%float_2_8974182en05 = OpConstant %float 2.8974182e-05 +%float_1_61456057en07 = OpConstant %float 1.61456057e-07 + %float_8 = OpConstant %float 8 + %float_4 = OpConstant %float 4 +%float_0_895099998 = OpConstant %float 0.895099998 +%float_0_266400009 = OpConstant %float 0.266400009 +%float_n0_161400005 = OpConstant %float -0.161400005 +%float_n0_750199974 = OpConstant %float -0.750199974 +%float_1_71350002 = OpConstant %float 1.71350002 +%float_0_0366999991 = OpConstant %float 0.0366999991 +%float_0_0388999991 = OpConstant %float 0.0388999991 +%float_n0_0684999973 = OpConstant %float -0.0684999973 +%float_1_02960002 = OpConstant %float 1.02960002 +%float_0_986992896 = OpConstant %float 0.986992896 +%float_n0_1470543 = OpConstant %float -0.1470543 +%float_0_159962699 = OpConstant %float 0.159962699 +%float_0_432305306 = OpConstant %float 0.432305306 +%float_0_518360317 = OpConstant %float 0.518360317 +%float_0_0492912009 = OpConstant %float 0.0492912009 +%float_n0_0085287001 = OpConstant %float -0.0085287001 +%float_0_040042799 = OpConstant %float 0.040042799 +%float_0_968486726 = OpConstant %float 0.968486726 +%float_5_55555534 = OpConstant %float 5.55555534 + %330 = OpConstantComposite %v3float %float_5_55555534 %float_5_55555534 %float_5_55555534 +%float_1_00000001en10 = OpConstant %float 1.00000001e-10 +%float_0_00999999978 = OpConstant %float 0.00999999978 +%float_0_666666687 = OpConstant %float 0.666666687 + %float_180 = OpConstant %float 180 + %float_360 = OpConstant %float 360 +%float_65535 = OpConstant %float 65535 + %337 = OpConstantComposite %v3float %float_65535 %float_65535 %float_65535 +%float_n4_97062206 = OpConstant %float -4.97062206 +%float_n3_02937818 = OpConstant %float -3.02937818 +%float_n2_12619996 = OpConstant %float -2.12619996 +%float_n1_51049995 = OpConstant %float -1.51049995 +%float_n1_05780005 = OpConstant %float -1.05780005 +%float_n0_466800004 = OpConstant %float -0.466800004 +%float_0_119379997 = OpConstant %float 0.119379997 +%float_0_708813429 = OpConstant %float 0.708813429 +%float_1_29118657 = OpConstant %float 1.29118657 +%float_0_808913231 = OpConstant %float 0.808913231 +%float_1_19108677 = OpConstant %float 1.19108677 +%float_1_56830001 = OpConstant %float 1.56830001 +%float_1_9483 = OpConstant %float 1.9483 +%float_2_30830002 = OpConstant %float 2.30830002 +%float_2_63840008 = OpConstant %float 2.63840008 +%float_2_85949993 = OpConstant %float 2.85949993 +%float_2_98726082 = OpConstant %float 2.98726082 +%float_3_01273918 = OpConstant %float 3.01273918 +%float_0_179999992 = OpConstant %float 0.179999992 +%float_9_99999975en05 = OpConstant %float 9.99999975e-05 + %float_1000 = OpConstant %float 1000 +%float_0_0599999987 = OpConstant %float 0.0599999987 +%float_3_50738446en05 = OpConstant %float 3.50738446e-05 + %361 = OpConstantComposite %v3float %float_3_50738446en05 %float_3_50738446en05 %float_3_50738446en05 +%float_n2_30102992 = OpConstant %float -2.30102992 +%float_n1_93120003 = OpConstant %float -1.93120003 +%float_n1_52049994 = OpConstant %float -1.52049994 +%float_0_801995218 = OpConstant %float 0.801995218 +%float_1_19800484 = OpConstant %float 1.19800484 +%float_1_59430003 = OpConstant %float 1.59430003 +%float_1_99730003 = OpConstant %float 1.99730003 +%float_2_37829995 = OpConstant %float 2.37829995 +%float_2_76839995 = OpConstant %float 2.76839995 +%float_3_05150008 = OpConstant %float 3.05150008 +%float_3_27462935 = OpConstant %float 3.27462935 +%float_3_32743073 = OpConstant %float 3.32743073 +%float_0_00499999989 = OpConstant %float 0.00499999989 + %float_11 = OpConstant %float 11 + %float_2000 = OpConstant %float 2000 +%float_0_119999997 = OpConstant %float 0.119999997 +%float_0_00313066994 = OpConstant %float 0.00313066994 +%float_12_9200001 = OpConstant %float 12.9200001 +%float_0_416666657 = OpConstant %float 0.416666657 +%float_1_05499995 = OpConstant %float 1.05499995 +%float_0_0549999997 = OpConstant %float 0.0549999997 +%float_n0_166666672 = OpConstant %float -0.166666672 + %float_n0_5 = OpConstant %float -0.5 +%float_0_166666672 = OpConstant %float 0.166666672 +%float_n3_15737653 = OpConstant %float -3.15737653 +%float_n0_485249996 = OpConstant %float -0.485249996 +%float_1_84773242 = OpConstant %float 1.84773242 +%float_n0_718548238 = OpConstant %float -0.718548238 +%float_2_08103061 = OpConstant %float 2.08103061 +%float_3_6681242 = OpConstant %float 3.6681242 + %float_18 = OpConstant %float 18 + %float_7 = OpConstant %float 7 +%_arr_float_uint_5 = OpTypeArray %float %uint_5 +%type__Globals = OpTypeStruct %v4float %v3float %v4float %v4float %v4float %v4float %v4float %v4float %v4float %v4float %float %float %float %float %float %_arr_float_uint_5 %v3float %v4float %float %float %v4float %v4float %v4float %v4float %v4float %v4float %v4float %v4float %v4float %v4float %v4float %v4float %v4float %v4float %v4float %v4float %v4float %v4float %v4float %v4float %float %float %uint %uint %float %float +%_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals +%type_2d_image = OpTypeImage %float 2D 2 0 0 1 Unknown +%_ptr_UniformConstant_type_2d_image = OpTypePointer UniformConstant %type_2d_image +%type_sampler = OpTypeSampler +%_ptr_UniformConstant_type_sampler = OpTypePointer UniformConstant %type_sampler +%_ptr_Input_v2float = OpTypePointer Input %v2float +%_ptr_Input_v4float = OpTypePointer Input %v4float +%_ptr_Input_uint = OpTypePointer Input %uint +%_ptr_Output_v4float = OpTypePointer Output %v4float + %void = OpTypeVoid + %402 = OpTypeFunction %void +%_ptr_Function_float = OpTypePointer Function %float +%_ptr_Uniform_uint = OpTypePointer Uniform %uint + %bool = OpTypeBool +%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float +%_ptr_Uniform_float = OpTypePointer Uniform %float +%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float + %v2bool = OpTypeVector %bool 2 + %v3bool = OpTypeVector %bool 3 +%type_sampled_image = OpTypeSampledImage %type_2d_image + %uint_10 = OpConstant %uint 10 +%_arr_float_uint_10 = OpTypeArray %float %uint_10 +%_arr_float_uint_6 = OpTypeArray %float %uint_6 + %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform + %Texture1 = OpVariable %_ptr_UniformConstant_type_2d_image UniformConstant +%Texture1Sampler = OpVariable %_ptr_UniformConstant_type_sampler UniformConstant +%in_var_TEXCOORD0 = OpVariable %_ptr_Input_v2float Input +%gl_FragCoord = OpVariable %_ptr_Input_v4float Input + %gl_Layer = OpVariable %_ptr_Input_uint Input +%out_var_SV_Target0 = OpVariable %_ptr_Output_v4float Output +%_ptr_Function__arr_float_uint_6 = OpTypePointer Function %_arr_float_uint_6 +%_ptr_Function__arr_float_uint_10 = OpTypePointer Function %_arr_float_uint_10 + %416 = OpConstantComposite %v3float %float_0_952552378 %float_0 %float_9_36786018en05 + %417 = OpConstantComposite %v3float %float_0_343966454 %float_0_728166103 %float_n0_0721325427 + %418 = OpConstantComposite %v3float %float_0 %float_0 %float_1_00882518 + %419 = OpConstantComposite %mat3v3float %416 %417 %418 + %420 = OpConstantComposite %v3float %float_1_04981101 %float_0 %float_n9_74845025en05 + %421 = OpConstantComposite %v3float %float_n0_495903015 %float_1_37331307 %float_0_0982400328 + %422 = OpConstantComposite %v3float %float_0 %float_0 %float_0_991252005 + %423 = OpConstantComposite %mat3v3float %420 %421 %422 + %424 = OpConstantComposite %v3float %float_0_662454188 %float_0_134004205 %float_0_156187683 + %425 = OpConstantComposite %v3float %float_n0_00557464967 %float_0_0040607336 %float_1_01033914 + %426 = OpConstantComposite %mat3v3float %424 %73 %425 + %427 = OpConstantComposite %v3float %float_1_6410234 %float_n0_324803293 %float_n0_236424699 + %428 = OpConstantComposite %v3float %float_n0_663662851 %float_1_61533165 %float_0_0167563483 + %429 = OpConstantComposite %v3float %float_0_0117218941 %float_n0_00828444213 %float_0_988394856 + %430 = OpConstantComposite %mat3v3float %427 %428 %429 + %431 = OpConstantComposite %v3float %float_1_45143926 %float_n0_236510754 %float_n0_214928567 + %432 = OpConstantComposite %v3float %float_n0_0765537769 %float_1_17622972 %float_n0_0996759236 + %433 = OpConstantComposite %v3float %float_0_00831614807 %float_n0_00603244966 %float_0_997716308 + %434 = OpConstantComposite %mat3v3float %431 %432 %433 + %435 = OpConstantComposite %v3float %float_0_695452213 %float_0_140678704 %float_0_163869068 + %436 = OpConstantComposite %v3float %float_0_0447945632 %float_0_859671116 %float_0_0955343172 + %437 = OpConstantComposite %v3float %float_n0_00552588282 %float_0_00402521016 %float_1_00150073 + %438 = OpConstantComposite %mat3v3float %435 %436 %437 + %439 = OpConstantComposite %v3float %float_3_2409699 %float_n1_5373832 %float_n0_498610765 + %440 = OpConstantComposite %v3float %float_n0_969243646 %float_1_8759675 %float_0_0415550582 + %441 = OpConstantComposite %v3float %float_0_0556300804 %float_n0_203976959 %float_1_05697155 + %442 = OpConstantComposite %mat3v3float %439 %440 %441 + %443 = OpConstantComposite %v3float %float_0_412456393 %float_0_357576102 %float_0_180437505 + %444 = OpConstantComposite %v3float %float_0_212672904 %float_0_715152204 %float_0_0721750036 + %445 = OpConstantComposite %v3float %float_0_0193339009 %float_0_119191997 %float_0_950304091 + %446 = OpConstantComposite %mat3v3float %443 %444 %445 + %447 = OpConstantComposite %v3float %float_1_71660841 %float_n0_355662107 %float_n0_253360093 + %448 = OpConstantComposite %v3float %float_n0_666682899 %float_1_61647761 %float_0_0157685 + %449 = OpConstantComposite %v3float %float_0_0176422 %float_n0_0427763015 %float_0_942228675 + %450 = OpConstantComposite %mat3v3float %447 %448 %449 + %451 = OpConstantComposite %v3float %float_2_49339628 %float_n0_93134588 %float_n0_402694494 + %452 = OpConstantComposite %v3float %float_n0_829486787 %float_1_76265967 %float_0_0236246008 + %453 = OpConstantComposite %v3float %float_0_0358507 %float_n0_0761827007 %float_0_957014024 + %454 = OpConstantComposite %mat3v3float %451 %452 %453 + %455 = OpConstantComposite %v3float %float_1_01303005 %float_0_00610530982 %float_n0_0149710001 + %456 = OpConstantComposite %v3float %float_0_00769822998 %float_0_998165011 %float_n0_00503202993 + %457 = OpConstantComposite %v3float %float_n0_00284131011 %float_0_00468515977 %float_0_924507022 + %458 = OpConstantComposite %mat3v3float %455 %456 %457 + %459 = OpConstantComposite %v3float %float_0_987223983 %float_n0_00611326983 %float_0_0159533005 + %460 = OpConstantComposite %v3float %float_n0_00759836007 %float_1_00186002 %float_0_0053300201 + %461 = OpConstantComposite %v3float %float_0_00307257008 %float_n0_00509594986 %float_1_08168006 + %462 = OpConstantComposite %mat3v3float %459 %460 %461 + %463 = OpConstantComposite %v3float %float_0_5 %float_n1 %float_0_5 + %464 = OpConstantComposite %v3float %float_n1 %float_1 %float_0_5 + %465 = OpConstantComposite %v3float %float_0_5 %float_0 %float_0 + %466 = OpConstantComposite %mat3v3float %463 %464 %465 + %467 = OpConstantComposite %v3float %float_1 %float_0 %float_0 + %468 = OpConstantComposite %v3float %float_0 %float_1 %float_0 + %469 = OpConstantComposite %v3float %float_0 %float_0 %float_1 + %470 = OpConstantComposite %mat3v3float %467 %468 %469 +%float_n6_07624626 = OpConstant %float -6.07624626 + %472 = OpConstantComposite %v3float %float_n6_07624626 %float_n6_07624626 %float_n6_07624626 + %473 = OpConstantComposite %v3float %float_0_895099998 %float_0_266400009 %float_n0_161400005 + %474 = OpConstantComposite %v3float %float_n0_750199974 %float_1_71350002 %float_0_0366999991 + %475 = OpConstantComposite %v3float %float_0_0388999991 %float_n0_0684999973 %float_1_02960002 + %476 = OpConstantComposite %mat3v3float %473 %474 %475 + %477 = OpConstantComposite %v3float %float_0_986992896 %float_n0_1470543 %float_0_159962699 + %478 = OpConstantComposite %v3float %float_0_432305306 %float_0_518360317 %float_0_0492912009 + %479 = OpConstantComposite %v3float %float_n0_0085287001 %float_0_040042799 %float_0_968486726 + %480 = OpConstantComposite %mat3v3float %477 %478 %479 + %481 = OpConstantComposite %v3float %float_0_544169128 %float_0_239592597 %float_0_166694298 + %482 = OpConstantComposite %v3float %float_0_239465594 %float_0_702153027 %float_0_058381401 + %483 = OpConstantComposite %v3float %float_n0_00234390004 %float_0_0361833982 %float_1_05521834 + %484 = OpConstantComposite %mat3v3float %481 %482 %483 + %485 = OpConstantComposite %v3float %float_0_940437257 %float_n0_0183068793 %float_0_077869609 + %486 = OpConstantComposite %v3float %float_0_00837869663 %float_0_828660011 %float_0_162961304 + %487 = OpConstantComposite %v3float %float_0_00054712611 %float_n0_000883374596 %float_1_00033629 + %488 = OpConstantComposite %mat3v3float %485 %486 %487 + %489 = OpConstantComposite %v3float %float_1_06317997 %float_0_0233955998 %float_n0_0865726024 + %490 = OpConstantComposite %v3float %float_n0_0106336996 %float_1_20632005 %float_n0_195690006 + %491 = OpConstantComposite %v3float %float_n0_000590886979 %float_0_00105247996 %float_0_999538004 + %492 = OpConstantComposite %mat3v3float %489 %490 %491 +%float_0_0533333346 = OpConstant %float 0.0533333346 +%float_0_159999996 = OpConstant %float 0.159999996 +%float_57_2957764 = OpConstant %float 57.2957764 +%float_0_0625 = OpConstant %float 0.0625 +%float_n67_5 = OpConstant %float -67.5 + %float_67_5 = OpConstant %float 67.5 + %499 = OpConstantComposite %_arr_float_uint_6 %float_n4 %float_n4 %float_n3_15737653 %float_n0_485249996 %float_1_84773242 %float_1_84773242 + %500 = OpConstantComposite %_arr_float_uint_6 %float_n0_718548238 %float_2_08103061 %float_3_6681242 %float_4 %float_4 %float_4 + %float_n15 = OpConstant %float -15 + %float_n14 = OpConstant %float -14 + %503 = OpConstantComposite %_arr_float_uint_10 %float_n4_97062206 %float_n3_02937818 %float_n2_12619996 %float_n1_51049995 %float_n1_05780005 %float_n0_466800004 %float_0_119379997 %float_0_708813429 %float_1_29118657 %float_1_29118657 + %504 = OpConstantComposite %_arr_float_uint_10 %float_0_808913231 %float_1_19108677 %float_1_56830001 %float_1_9483 %float_2_30830002 %float_2_63840008 %float_2_85949993 %float_2_98726082 %float_3_01273918 %float_3_01273918 + %float_n12 = OpConstant %float -12 + %506 = OpConstantComposite %_arr_float_uint_10 %float_n2_30102992 %float_n2_30102992 %float_n1_93120003 %float_n1_52049994 %float_n1_05780005 %float_n0_466800004 %float_0_119379997 %float_0_708813429 %float_1_29118657 %float_1_29118657 + %507 = OpConstantComposite %_arr_float_uint_10 %float_0_801995218 %float_1_19800484 %float_1_59430003 %float_1_99730003 %float_2_37829995 %float_2_76839995 %float_3_05150008 %float_3_27462935 %float_3_32743073 %float_3_32743073 +%float_0_0322580636 = OpConstant %float 0.0322580636 +%float_1_03225803 = OpConstant %float 1.03225803 + %510 = OpConstantComposite %v2float %float_1_03225803 %float_1_03225803 +%float_4_60443853e_09 = OpConstant %float 4.60443853e+09 +%float_2_00528435e_09 = OpConstant %float 2.00528435e+09 +%float_0_333333343 = OpConstant %float 0.333333343 + %float_5 = OpConstant %float 5 + %float_2_5 = OpConstant %float 2.5 +%float_0_0250000004 = OpConstant %float 0.0250000004 +%float_0_239999995 = OpConstant %float 0.239999995 +%float_0_0148148146 = OpConstant %float 0.0148148146 + %519 = OpConstantComposite %v3float %float_9_99999975en05 %float_9_99999975en05 %float_9_99999975en05 +%float_0_0296296291 = OpConstant %float 0.0296296291 +%float_0_952381015 = OpConstant %float 0.952381015 + %522 = OpConstantComposite %v3float %float_0_952381015 %float_0_952381015 %float_0_952381015 + %523 = OpUndef %v3float +%float_0_358299971 = OpConstant %float 0.358299971 + %525 = OpUndef %v3float + %MainPS = OpFunction %void None %402 + %526 = OpLabel + %527 = OpVariable %_ptr_Function__arr_float_uint_6 Function + %528 = OpVariable %_ptr_Function__arr_float_uint_6 Function + %529 = OpVariable %_ptr_Function__arr_float_uint_6 Function + %530 = OpVariable %_ptr_Function__arr_float_uint_6 Function + %531 = OpVariable %_ptr_Function__arr_float_uint_6 Function + %532 = OpVariable %_ptr_Function__arr_float_uint_6 Function + %533 = OpVariable %_ptr_Function__arr_float_uint_10 Function + %534 = OpVariable %_ptr_Function__arr_float_uint_10 Function + %535 = OpVariable %_ptr_Function__arr_float_uint_10 Function + %536 = OpVariable %_ptr_Function__arr_float_uint_10 Function + %537 = OpVariable %_ptr_Function__arr_float_uint_10 Function + %538 = OpVariable %_ptr_Function__arr_float_uint_10 Function + %539 = OpVariable %_ptr_Function__arr_float_uint_6 Function + %540 = OpVariable %_ptr_Function__arr_float_uint_6 Function + %541 = OpVariable %_ptr_Function__arr_float_uint_6 Function + %542 = OpVariable %_ptr_Function__arr_float_uint_6 Function + %543 = OpVariable %_ptr_Function__arr_float_uint_6 Function + %544 = OpVariable %_ptr_Function__arr_float_uint_6 Function + %545 = OpVariable %_ptr_Function__arr_float_uint_6 Function + %546 = OpVariable %_ptr_Function__arr_float_uint_6 Function + %547 = OpVariable %_ptr_Function__arr_float_uint_6 Function + %548 = OpVariable %_ptr_Function__arr_float_uint_6 Function + %549 = OpVariable %_ptr_Function__arr_float_uint_6 Function + %550 = OpVariable %_ptr_Function__arr_float_uint_6 Function + %551 = OpVariable %_ptr_Function__arr_float_uint_10 Function + %552 = OpVariable %_ptr_Function__arr_float_uint_10 Function + %553 = OpVariable %_ptr_Function__arr_float_uint_10 Function + %554 = OpVariable %_ptr_Function__arr_float_uint_10 Function + %555 = OpVariable %_ptr_Function__arr_float_uint_10 Function + %556 = OpVariable %_ptr_Function__arr_float_uint_10 Function + %557 = OpVariable %_ptr_Function__arr_float_uint_6 Function + %558 = OpVariable %_ptr_Function__arr_float_uint_6 Function + %559 = OpVariable %_ptr_Function__arr_float_uint_6 Function + %560 = OpVariable %_ptr_Function__arr_float_uint_6 Function + %561 = OpVariable %_ptr_Function__arr_float_uint_6 Function + %562 = OpVariable %_ptr_Function__arr_float_uint_6 Function + %563 = OpLoad %v2float %in_var_TEXCOORD0 + %564 = OpLoad %uint %gl_Layer + %565 = OpFSub %v2float %563 %134 + %566 = OpFMul %v2float %565 %510 + %567 = OpCompositeExtract %float %566 0 + %568 = OpCompositeExtract %float %566 1 + %569 = OpConvertUToF %float %564 + %570 = OpFMul %float %569 %float_0_0322580636 + %571 = OpCompositeConstruct %v4float %567 %568 %570 %float_0 + %572 = OpMatrixTimesMatrix %mat3v3float %446 %458 + %573 = OpMatrixTimesMatrix %mat3v3float %572 %430 + %574 = OpMatrixTimesMatrix %mat3v3float %426 %462 + %575 = OpMatrixTimesMatrix %mat3v3float %574 %442 + %576 = OpMatrixTimesMatrix %mat3v3float %419 %430 + %577 = OpMatrixTimesMatrix %mat3v3float %426 %423 + %578 = OpAccessChain %_ptr_Uniform_uint %_Globals %int_43 + %579 = OpLoad %uint %578 + OpBranch %580 + %580 = OpLabel + OpLoopMerge %581 %582 None + OpBranch %583 + %583 = OpLabel + %584 = OpMatrixTimesMatrix %mat3v3float %574 %454 + %585 = OpMatrixTimesMatrix %mat3v3float %574 %450 + %586 = OpIEqual %bool %579 %uint_1 + OpSelectionMerge %587 None + OpBranchConditional %586 %588 %589 + %589 = OpLabel + %590 = OpIEqual %bool %579 %uint_2 + OpSelectionMerge %591 None + OpBranchConditional %590 %592 %593 + %593 = OpLabel + %594 = OpIEqual %bool %579 %uint_3 + OpSelectionMerge %595 None + OpBranchConditional %594 %596 %597 + %597 = OpLabel + %598 = OpIEqual %bool %579 %uint_4 + OpSelectionMerge %599 None + OpBranchConditional %598 %600 %601 + %601 = OpLabel + OpBranch %581 + %600 = OpLabel + OpBranch %581 + %599 = OpLabel + OpUnreachable + %596 = OpLabel + OpBranch %581 + %595 = OpLabel + OpUnreachable + %592 = OpLabel + OpBranch %581 + %591 = OpLabel + OpUnreachable + %588 = OpLabel + OpBranch %581 + %587 = OpLabel + OpUnreachable + %582 = OpLabel + OpBranch %580 + %581 = OpLabel + %602 = OpPhi %mat3v3float %575 %601 %470 %600 %438 %596 %585 %592 %584 %588 + %603 = OpVectorShuffle %v3float %571 %571 0 1 2 + %604 = OpAccessChain %_ptr_Uniform_uint %_Globals %int_42 + %605 = OpLoad %uint %604 + %606 = OpUGreaterThanEqual %bool %605 %uint_3 + OpSelectionMerge %607 None + OpBranchConditional %606 %608 %609 + %609 = OpLabel + %610 = OpFSub %v3float %603 %204 + %611 = OpFMul %v3float %610 %205 + %612 = OpExtInst %v3float %1 Exp2 %611 + %613 = OpFMul %v3float %612 %206 + %614 = OpExtInst %v3float %1 Exp2 %472 + %615 = OpFMul %v3float %614 %206 + %616 = OpFSub %v3float %613 %615 + OpBranch %607 + %608 = OpLabel + %617 = OpExtInst %v3float %1 Pow %603 %194 + %618 = OpFSub %v3float %617 %195 + %619 = OpExtInst %v3float %1 FMax %138 %618 + %620 = OpFMul %v3float %197 %617 + %621 = OpFSub %v3float %196 %620 + %622 = OpFDiv %v3float %619 %621 + %623 = OpExtInst %v3float %1 Pow %622 %199 + %624 = OpFMul %v3float %623 %200 + OpBranch %607 + %607 = OpLabel + %625 = OpPhi %v3float %616 %609 %624 %608 + %626 = OpAccessChain %_ptr_Uniform_float %_Globals %int_18 + %627 = OpLoad %float %626 + %628 = OpFMul %float %627 %float_1_00055635 + %629 = OpFOrdLessThanEqual %bool %628 %float_7000 + %630 = OpFDiv %float %float_4_60443853e_09 %627 + %631 = OpFSub %float %float_2967800 %630 + %632 = OpFDiv %float %631 %628 + %633 = OpFAdd %float %float_99_1100006 %632 + %634 = OpFDiv %float %633 %628 + %635 = OpFAdd %float %float_0_244063005 %634 + %636 = OpFDiv %float %float_2_00528435e_09 %627 + %637 = OpFSub %float %float_1901800 %636 + %638 = OpFDiv %float %637 %628 + %639 = OpFAdd %float %float_247_479996 %638 + %640 = OpFDiv %float %639 %628 + %641 = OpFAdd %float %float_0_237039998 %640 + %642 = OpSelect %float %629 %635 %641 + %643 = OpFMul %float %float_n3 %642 + %644 = OpFMul %float %643 %642 + %645 = OpFMul %float %float_2_86999989 %642 + %646 = OpFAdd %float %644 %645 + %647 = OpFSub %float %646 %float_0_275000006 + %648 = OpCompositeConstruct %v2float %642 %647 + %649 = OpFMul %float %float_0_000154118257 %627 + %650 = OpFAdd %float %float_0_860117733 %649 + %651 = OpFMul %float %float_1_28641219en07 %627 + %652 = OpFMul %float %651 %627 + %653 = OpFAdd %float %650 %652 + %654 = OpFMul %float %float_0_00084242021 %627 + %655 = OpFAdd %float %float_1 %654 + %656 = OpFMul %float %float_7_08145137en07 %627 + %657 = OpFMul %float %656 %627 + %658 = OpFAdd %float %655 %657 + %659 = OpFDiv %float %653 %658 + %660 = OpFMul %float %float_4_22806261en05 %627 + %661 = OpFAdd %float %float_0_317398727 %660 + %662 = OpFMul %float %float_4_20481676en08 %627 + %663 = OpFMul %float %662 %627 + %664 = OpFAdd %float %661 %663 + %665 = OpFMul %float %float_2_8974182en05 %627 + %666 = OpFSub %float %float_1 %665 + %667 = OpFMul %float %float_1_61456057en07 %627 + %668 = OpFMul %float %667 %627 + %669 = OpFAdd %float %666 %668 + %670 = OpFDiv %float %664 %669 + %671 = OpFMul %float %float_3 %659 + %672 = OpFMul %float %float_2 %659 + %673 = OpFMul %float %float_8 %670 + %674 = OpFSub %float %672 %673 + %675 = OpFAdd %float %674 %float_4 + %676 = OpFDiv %float %671 %675 + %677 = OpFMul %float %float_2 %670 + %678 = OpFDiv %float %677 %675 + %679 = OpCompositeConstruct %v2float %676 %678 + %680 = OpFOrdLessThan %bool %627 %float_4000 + %681 = OpCompositeConstruct %v2bool %680 %680 + %682 = OpSelect %v2float %681 %679 %648 + %683 = OpAccessChain %_ptr_Uniform_float %_Globals %int_19 + %684 = OpLoad %float %683 + %685 = OpCompositeConstruct %v2float %659 %670 + %686 = OpExtInst %v2float %1 Normalize %685 + %687 = OpCompositeExtract %float %686 1 + %688 = OpFNegate %float %687 + %689 = OpFMul %float %688 %684 + %690 = OpFMul %float %689 %float_0_0500000007 + %691 = OpFAdd %float %659 %690 + %692 = OpCompositeExtract %float %686 0 + %693 = OpFMul %float %692 %684 + %694 = OpFMul %float %693 %float_0_0500000007 + %695 = OpFAdd %float %670 %694 + %696 = OpFMul %float %float_3 %691 + %697 = OpFMul %float %float_2 %691 + %698 = OpFMul %float %float_8 %695 + %699 = OpFSub %float %697 %698 + %700 = OpFAdd %float %699 %float_4 + %701 = OpFDiv %float %696 %700 + %702 = OpFMul %float %float_2 %695 + %703 = OpFDiv %float %702 %700 + %704 = OpCompositeConstruct %v2float %701 %703 + %705 = OpFSub %v2float %704 %679 + %706 = OpFAdd %v2float %682 %705 + %707 = OpCompositeExtract %float %706 0 + %708 = OpCompositeExtract %float %706 1 + %709 = OpExtInst %float %1 FMax %708 %float_1_00000001en10 + %710 = OpFDiv %float %707 %709 + %711 = OpCompositeInsert %v3float %710 %523 0 + %712 = OpCompositeInsert %v3float %float_1 %711 1 + %713 = OpFSub %float %float_1 %707 + %714 = OpFSub %float %713 %708 + %715 = OpFDiv %float %714 %709 + %716 = OpCompositeInsert %v3float %715 %712 2 + %717 = OpExtInst %float %1 FMax %float_0_328999996 %float_1_00000001en10 + %718 = OpFDiv %float %float_0_312700003 %717 + %719 = OpCompositeInsert %v3float %718 %523 0 + %720 = OpCompositeInsert %v3float %float_1 %719 1 + %721 = OpFDiv %float %float_0_358299971 %717 + %722 = OpCompositeInsert %v3float %721 %720 2 + %723 = OpVectorTimesMatrix %v3float %716 %476 + %724 = OpVectorTimesMatrix %v3float %722 %476 + %725 = OpCompositeExtract %float %724 0 + %726 = OpCompositeExtract %float %723 0 + %727 = OpFDiv %float %725 %726 + %728 = OpCompositeConstruct %v3float %727 %float_0 %float_0 + %729 = OpCompositeExtract %float %724 1 + %730 = OpCompositeExtract %float %723 1 + %731 = OpFDiv %float %729 %730 + %732 = OpCompositeConstruct %v3float %float_0 %731 %float_0 + %733 = OpCompositeExtract %float %724 2 + %734 = OpCompositeExtract %float %723 2 + %735 = OpFDiv %float %733 %734 + %736 = OpCompositeConstruct %v3float %float_0 %float_0 %735 + %737 = OpCompositeConstruct %mat3v3float %728 %732 %736 + %738 = OpMatrixTimesMatrix %mat3v3float %476 %737 + %739 = OpMatrixTimesMatrix %mat3v3float %738 %480 + %740 = OpMatrixTimesMatrix %mat3v3float %446 %739 + %741 = OpMatrixTimesMatrix %mat3v3float %740 %442 + %742 = OpVectorTimesMatrix %v3float %625 %741 + %743 = OpVectorTimesMatrix %v3float %742 %573 + %744 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_9 + %745 = OpAccessChain %_ptr_Uniform_float %_Globals %int_9 %int_3 + %746 = OpLoad %float %745 + %747 = OpFOrdNotEqual %bool %746 %float_0 + OpSelectionMerge %748 None + OpBranchConditional %747 %749 %748 + %749 = OpLabel + %750 = OpDot %float %743 %73 + %751 = OpCompositeConstruct %v3float %750 %750 %750 + %752 = OpFDiv %v3float %743 %751 + %753 = OpFSub %v3float %752 %141 + %754 = OpDot %float %753 %753 + %755 = OpFMul %float %float_n4 %754 + %756 = OpExtInst %float %1 Exp2 %755 + %757 = OpFSub %float %float_1 %756 + %758 = OpAccessChain %_ptr_Uniform_float %_Globals %int_45 + %759 = OpLoad %float %758 + %760 = OpFMul %float %float_n4 %759 + %761 = OpFMul %float %760 %750 + %762 = OpFMul %float %761 %750 + %763 = OpExtInst %float %1 Exp2 %762 + %764 = OpFSub %float %float_1 %763 + %765 = OpFMul %float %757 %764 + %766 = OpMatrixTimesMatrix %mat3v3float %484 %430 + %767 = OpMatrixTimesMatrix %mat3v3float %575 %766 + %768 = OpVectorTimesMatrix %v3float %743 %767 + %769 = OpCompositeConstruct %v3float %765 %765 %765 + %770 = OpExtInst %v3float %1 FMix %743 %768 %769 + OpBranch %748 + %748 = OpLabel + %771 = OpPhi %v3float %743 %607 %770 %749 + %772 = OpDot %float %771 %73 + %773 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_25 + %774 = OpLoad %v4float %773 + %775 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_20 + %776 = OpLoad %v4float %775 + %777 = OpFMul %v4float %774 %776 + %778 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_26 + %779 = OpLoad %v4float %778 + %780 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_21 + %781 = OpLoad %v4float %780 + %782 = OpFMul %v4float %779 %781 + %783 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_27 + %784 = OpLoad %v4float %783 + %785 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_22 + %786 = OpLoad %v4float %785 + %787 = OpFMul %v4float %784 %786 + %788 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_28 + %789 = OpLoad %v4float %788 + %790 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_23 + %791 = OpLoad %v4float %790 + %792 = OpFMul %v4float %789 %791 + %793 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_29 + %794 = OpLoad %v4float %793 + %795 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_24 + %796 = OpLoad %v4float %795 + %797 = OpFAdd %v4float %794 %796 + %798 = OpCompositeConstruct %v3float %772 %772 %772 + %799 = OpVectorShuffle %v3float %777 %777 0 1 2 + %800 = OpCompositeExtract %float %777 3 + %801 = OpCompositeConstruct %v3float %800 %800 %800 + %802 = OpFMul %v3float %799 %801 + %803 = OpExtInst %v3float %1 FMix %798 %771 %802 + %804 = OpExtInst %v3float %1 FMax %138 %803 + %805 = OpFMul %v3float %804 %330 + %806 = OpVectorShuffle %v3float %782 %782 0 1 2 + %807 = OpCompositeExtract %float %782 3 + %808 = OpCompositeConstruct %v3float %807 %807 %807 + %809 = OpFMul %v3float %806 %808 + %810 = OpExtInst %v3float %1 Pow %805 %809 + %811 = OpFMul %v3float %810 %206 + %812 = OpVectorShuffle %v3float %787 %787 0 1 2 + %813 = OpCompositeExtract %float %787 3 + %814 = OpCompositeConstruct %v3float %813 %813 %813 + %815 = OpFMul %v3float %812 %814 + %816 = OpFDiv %v3float %141 %815 + %817 = OpExtInst %v3float %1 Pow %811 %816 + %818 = OpVectorShuffle %v3float %792 %792 0 1 2 + %819 = OpCompositeExtract %float %792 3 + %820 = OpCompositeConstruct %v3float %819 %819 %819 + %821 = OpFMul %v3float %818 %820 + %822 = OpFMul %v3float %817 %821 + %823 = OpVectorShuffle %v3float %797 %797 0 1 2 + %824 = OpCompositeExtract %float %797 3 + %825 = OpCompositeConstruct %v3float %824 %824 %824 + %826 = OpFAdd %v3float %823 %825 + %827 = OpFAdd %v3float %822 %826 + %828 = OpAccessChain %_ptr_Uniform_float %_Globals %int_40 + %829 = OpLoad %float %828 + %830 = OpExtInst %float %1 SmoothStep %float_0 %829 %772 + %831 = OpFSub %float %float_1 %830 + %832 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_35 + %833 = OpLoad %v4float %832 + %834 = OpFMul %v4float %833 %776 + %835 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_36 + %836 = OpLoad %v4float %835 + %837 = OpFMul %v4float %836 %781 + %838 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_37 + %839 = OpLoad %v4float %838 + %840 = OpFMul %v4float %839 %786 + %841 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_38 + %842 = OpLoad %v4float %841 + %843 = OpFMul %v4float %842 %791 + %844 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_39 + %845 = OpLoad %v4float %844 + %846 = OpFAdd %v4float %845 %796 + %847 = OpVectorShuffle %v3float %834 %834 0 1 2 + %848 = OpCompositeExtract %float %834 3 + %849 = OpCompositeConstruct %v3float %848 %848 %848 + %850 = OpFMul %v3float %847 %849 + %851 = OpExtInst %v3float %1 FMix %798 %771 %850 + %852 = OpExtInst %v3float %1 FMax %138 %851 + %853 = OpFMul %v3float %852 %330 + %854 = OpVectorShuffle %v3float %837 %837 0 1 2 + %855 = OpCompositeExtract %float %837 3 + %856 = OpCompositeConstruct %v3float %855 %855 %855 + %857 = OpFMul %v3float %854 %856 + %858 = OpExtInst %v3float %1 Pow %853 %857 + %859 = OpFMul %v3float %858 %206 + %860 = OpVectorShuffle %v3float %840 %840 0 1 2 + %861 = OpCompositeExtract %float %840 3 + %862 = OpCompositeConstruct %v3float %861 %861 %861 + %863 = OpFMul %v3float %860 %862 + %864 = OpFDiv %v3float %141 %863 + %865 = OpExtInst %v3float %1 Pow %859 %864 + %866 = OpVectorShuffle %v3float %843 %843 0 1 2 + %867 = OpCompositeExtract %float %843 3 + %868 = OpCompositeConstruct %v3float %867 %867 %867 + %869 = OpFMul %v3float %866 %868 + %870 = OpFMul %v3float %865 %869 + %871 = OpVectorShuffle %v3float %846 %846 0 1 2 + %872 = OpCompositeExtract %float %846 3 + %873 = OpCompositeConstruct %v3float %872 %872 %872 + %874 = OpFAdd %v3float %871 %873 + %875 = OpFAdd %v3float %870 %874 + %876 = OpAccessChain %_ptr_Uniform_float %_Globals %int_41 + %877 = OpLoad %float %876 + %878 = OpExtInst %float %1 SmoothStep %877 %float_1 %772 + %879 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_30 + %880 = OpLoad %v4float %879 + %881 = OpFMul %v4float %880 %776 + %882 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_31 + %883 = OpLoad %v4float %882 + %884 = OpFMul %v4float %883 %781 + %885 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_32 + %886 = OpLoad %v4float %885 + %887 = OpFMul %v4float %886 %786 + %888 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_33 + %889 = OpLoad %v4float %888 + %890 = OpFMul %v4float %889 %791 + %891 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_34 + %892 = OpLoad %v4float %891 + %893 = OpFAdd %v4float %892 %796 + %894 = OpVectorShuffle %v3float %881 %881 0 1 2 + %895 = OpCompositeExtract %float %881 3 + %896 = OpCompositeConstruct %v3float %895 %895 %895 + %897 = OpFMul %v3float %894 %896 + %898 = OpExtInst %v3float %1 FMix %798 %771 %897 + %899 = OpExtInst %v3float %1 FMax %138 %898 + %900 = OpFMul %v3float %899 %330 + %901 = OpVectorShuffle %v3float %884 %884 0 1 2 + %902 = OpCompositeExtract %float %884 3 + %903 = OpCompositeConstruct %v3float %902 %902 %902 + %904 = OpFMul %v3float %901 %903 + %905 = OpExtInst %v3float %1 Pow %900 %904 + %906 = OpFMul %v3float %905 %206 + %907 = OpVectorShuffle %v3float %887 %887 0 1 2 + %908 = OpCompositeExtract %float %887 3 + %909 = OpCompositeConstruct %v3float %908 %908 %908 + %910 = OpFMul %v3float %907 %909 + %911 = OpFDiv %v3float %141 %910 + %912 = OpExtInst %v3float %1 Pow %906 %911 + %913 = OpVectorShuffle %v3float %890 %890 0 1 2 + %914 = OpCompositeExtract %float %890 3 + %915 = OpCompositeConstruct %v3float %914 %914 %914 + %916 = OpFMul %v3float %913 %915 + %917 = OpFMul %v3float %912 %916 + %918 = OpVectorShuffle %v3float %893 %893 0 1 2 + %919 = OpCompositeExtract %float %893 3 + %920 = OpCompositeConstruct %v3float %919 %919 %919 + %921 = OpFAdd %v3float %918 %920 + %922 = OpFAdd %v3float %917 %921 + %923 = OpFSub %float %830 %878 + %924 = OpCompositeConstruct %v3float %831 %831 %831 + %925 = OpFMul %v3float %827 %924 + %926 = OpCompositeConstruct %v3float %923 %923 %923 + %927 = OpFMul %v3float %922 %926 + %928 = OpFAdd %v3float %925 %927 + %929 = OpCompositeConstruct %v3float %878 %878 %878 + %930 = OpFMul %v3float %875 %929 + %931 = OpFAdd %v3float %928 %930 + %932 = OpVectorTimesMatrix %v3float %931 %575 + %933 = OpMatrixTimesMatrix %mat3v3float %577 %488 + %934 = OpMatrixTimesMatrix %mat3v3float %933 %576 + %935 = OpMatrixTimesMatrix %mat3v3float %577 %492 + %936 = OpMatrixTimesMatrix %mat3v3float %935 %576 + %937 = OpVectorTimesMatrix %v3float %931 %934 + %938 = OpAccessChain %_ptr_Uniform_float %_Globals %int_44 + %939 = OpLoad %float %938 + %940 = OpCompositeConstruct %v3float %939 %939 %939 + %941 = OpExtInst %v3float %1 FMix %931 %937 %940 + %942 = OpVectorTimesMatrix %v3float %941 %577 + %943 = OpCompositeExtract %float %942 0 + %944 = OpCompositeExtract %float %942 1 + %945 = OpExtInst %float %1 FMin %943 %944 + %946 = OpCompositeExtract %float %942 2 + %947 = OpExtInst %float %1 FMin %945 %946 + %948 = OpExtInst %float %1 FMax %943 %944 + %949 = OpExtInst %float %1 FMax %948 %946 + %950 = OpExtInst %float %1 FMax %949 %float_1_00000001en10 + %951 = OpExtInst %float %1 FMax %947 %float_1_00000001en10 + %952 = OpFSub %float %950 %951 + %953 = OpExtInst %float %1 FMax %949 %float_0_00999999978 + %954 = OpFDiv %float %952 %953 + %955 = OpFSub %float %946 %944 + %956 = OpFMul %float %946 %955 + %957 = OpFSub %float %944 %943 + %958 = OpFMul %float %944 %957 + %959 = OpFAdd %float %956 %958 + %960 = OpFSub %float %943 %946 + %961 = OpFMul %float %943 %960 + %962 = OpFAdd %float %959 %961 + %963 = OpExtInst %float %1 Sqrt %962 + %964 = OpFAdd %float %946 %944 + %965 = OpFAdd %float %964 %943 + %966 = OpFMul %float %float_1_75 %963 + %967 = OpFAdd %float %965 %966 + %968 = OpFMul %float %967 %float_0_333333343 + %969 = OpFSub %float %954 %float_0_400000006 + %970 = OpFMul %float %969 %float_5 + %971 = OpFMul %float %969 %float_2_5 + %972 = OpExtInst %float %1 FAbs %971 + %973 = OpFSub %float %float_1 %972 + %974 = OpExtInst %float %1 FMax %973 %float_0 + %975 = OpExtInst %float %1 FSign %970 + %976 = OpConvertFToS %int %975 + %977 = OpConvertSToF %float %976 + %978 = OpFMul %float %974 %974 + %979 = OpFSub %float %float_1 %978 + %980 = OpFMul %float %977 %979 + %981 = OpFAdd %float %float_1 %980 + %982 = OpFMul %float %981 %float_0_0250000004 + %983 = OpFOrdLessThanEqual %bool %968 %float_0_0533333346 + OpSelectionMerge %984 None + OpBranchConditional %983 %985 %986 + %986 = OpLabel + %987 = OpFOrdGreaterThanEqual %bool %968 %float_0_159999996 + OpSelectionMerge %988 None + OpBranchConditional %987 %989 %990 + %990 = OpLabel + %991 = OpFDiv %float %float_0_239999995 %967 + %992 = OpFSub %float %991 %float_0_5 + %993 = OpFMul %float %982 %992 + OpBranch %988 + %989 = OpLabel + OpBranch %988 + %988 = OpLabel + %994 = OpPhi %float %993 %990 %float_0 %989 + OpBranch %984 + %985 = OpLabel + OpBranch %984 + %984 = OpLabel + %995 = OpPhi %float %994 %988 %982 %985 + %996 = OpFAdd %float %float_1 %995 + %997 = OpCompositeConstruct %v3float %996 %996 %996 + %998 = OpFMul %v3float %942 %997 + %999 = OpCompositeExtract %float %998 0 + %1000 = OpCompositeExtract %float %998 1 + %1001 = OpFOrdEqual %bool %999 %1000 + %1002 = OpCompositeExtract %float %998 2 + %1003 = OpFOrdEqual %bool %1000 %1002 + %1004 = OpLogicalAnd %bool %1001 %1003 + OpSelectionMerge %1005 None + OpBranchConditional %1004 %1006 %1007 + %1007 = OpLabel + %1008 = OpExtInst %float %1 Sqrt %float_3 + %1009 = OpFSub %float %1000 %1002 + %1010 = OpFMul %float %1008 %1009 + %1011 = OpFMul %float %float_2 %999 + %1012 = OpFSub %float %1011 %1000 + %1013 = OpFSub %float %1012 %1002 + %1014 = OpExtInst %float %1 Atan2 %1010 %1013 + %1015 = OpFMul %float %float_57_2957764 %1014 + OpBranch %1005 + %1006 = OpLabel + OpBranch %1005 + %1005 = OpLabel + %1016 = OpPhi %float %1015 %1007 %float_0 %1006 + %1017 = OpFOrdLessThan %bool %1016 %float_0 + OpSelectionMerge %1018 None + OpBranchConditional %1017 %1019 %1018 + %1019 = OpLabel + %1020 = OpFAdd %float %1016 %float_360 + OpBranch %1018 + %1018 = OpLabel + %1021 = OpPhi %float %1016 %1005 %1020 %1019 + %1022 = OpExtInst %float %1 FClamp %1021 %float_0 %float_360 + %1023 = OpFOrdGreaterThan %bool %1022 %float_180 + OpSelectionMerge %1024 None + OpBranchConditional %1023 %1025 %1024 + %1025 = OpLabel + %1026 = OpFSub %float %1022 %float_360 + OpBranch %1024 + %1024 = OpLabel + %1027 = OpPhi %float %1022 %1018 %1026 %1025 + %1028 = OpFMul %float %1027 %float_0_0148148146 + %1029 = OpExtInst %float %1 FAbs %1028 + %1030 = OpFSub %float %float_1 %1029 + %1031 = OpExtInst %float %1 SmoothStep %float_0 %float_1 %1030 + %1032 = OpFMul %float %1031 %1031 + %1033 = OpFMul %float %1032 %954 + %1034 = OpFSub %float %float_0_0299999993 %999 + %1035 = OpFMul %float %1033 %1034 + %1036 = OpFMul %float %1035 %float_0_180000007 + %1037 = OpFAdd %float %999 %1036 + %1038 = OpCompositeInsert %v3float %1037 %998 0 + %1039 = OpVectorTimesMatrix %v3float %1038 %434 + %1040 = OpExtInst %v3float %1 FMax %138 %1039 + %1041 = OpDot %float %1040 %73 + %1042 = OpCompositeConstruct %v3float %1041 %1041 %1041 + %1043 = OpExtInst %v3float %1 FMix %1042 %1040 %241 + %1044 = OpAccessChain %_ptr_Uniform_float %_Globals %int_13 + %1045 = OpLoad %float %1044 + %1046 = OpFAdd %float %float_1 %1045 + %1047 = OpAccessChain %_ptr_Uniform_float %_Globals %int_11 + %1048 = OpLoad %float %1047 + %1049 = OpFSub %float %1046 %1048 + %1050 = OpAccessChain %_ptr_Uniform_float %_Globals %int_14 + %1051 = OpLoad %float %1050 + %1052 = OpFAdd %float %float_1 %1051 + %1053 = OpAccessChain %_ptr_Uniform_float %_Globals %int_12 + %1054 = OpLoad %float %1053 + %1055 = OpFSub %float %1052 %1054 + %1056 = OpFOrdGreaterThan %bool %1048 %float_0_800000012 + OpSelectionMerge %1057 None + OpBranchConditional %1056 %1058 %1059 + %1059 = OpLabel + %1060 = OpFAdd %float %float_0_180000007 %1045 + %1061 = OpFDiv %float %1060 %1049 + %1062 = OpExtInst %float %1 Log %float_0_180000007 + %1063 = OpExtInst %float %1 Log %float_10 + %1064 = OpFDiv %float %1062 %1063 + %1065 = OpFSub %float %float_2 %1061 + %1066 = OpFDiv %float %1061 %1065 + %1067 = OpExtInst %float %1 Log %1066 + %1068 = OpFMul %float %float_0_5 %1067 + %1069 = OpAccessChain %_ptr_Uniform_float %_Globals %int_10 + %1070 = OpLoad %float %1069 + %1071 = OpFDiv %float %1049 %1070 + %1072 = OpFMul %float %1068 %1071 + %1073 = OpFSub %float %1064 %1072 + OpBranch %1057 + %1058 = OpLabel + %1074 = OpFSub %float %float_0_819999993 %1048 + %1075 = OpAccessChain %_ptr_Uniform_float %_Globals %int_10 + %1076 = OpLoad %float %1075 + %1077 = OpFDiv %float %1074 %1076 + %1078 = OpExtInst %float %1 Log %float_0_180000007 + %1079 = OpExtInst %float %1 Log %float_10 + %1080 = OpFDiv %float %1078 %1079 + %1081 = OpFAdd %float %1077 %1080 + OpBranch %1057 + %1057 = OpLabel + %1082 = OpPhi %float %1073 %1059 %1081 %1058 + %1083 = OpFSub %float %float_1 %1048 + %1084 = OpAccessChain %_ptr_Uniform_float %_Globals %int_10 + %1085 = OpLoad %float %1084 + %1086 = OpFDiv %float %1083 %1085 + %1087 = OpFSub %float %1086 %1082 + %1088 = OpFDiv %float %1054 %1085 + %1089 = OpFSub %float %1088 %1087 + %1090 = OpExtInst %v3float %1 Log %1043 + %1091 = OpExtInst %float %1 Log %float_10 + %1092 = OpCompositeConstruct %v3float %1091 %1091 %1091 + %1093 = OpFDiv %v3float %1090 %1092 + %1094 = OpCompositeConstruct %v3float %1085 %1085 %1085 + %1095 = OpCompositeConstruct %v3float %1087 %1087 %1087 + %1096 = OpFAdd %v3float %1093 %1095 + %1097 = OpFMul %v3float %1094 %1096 + %1098 = OpFNegate %float %1045 + %1099 = OpCompositeConstruct %v3float %1098 %1098 %1098 + %1100 = OpFMul %float %float_2 %1049 + %1101 = OpCompositeConstruct %v3float %1100 %1100 %1100 + %1102 = OpFMul %float %float_n2 %1085 + %1103 = OpFDiv %float %1102 %1049 + %1104 = OpCompositeConstruct %v3float %1103 %1103 %1103 + %1105 = OpCompositeConstruct %v3float %1082 %1082 %1082 + %1106 = OpFSub %v3float %1093 %1105 + %1107 = OpFMul %v3float %1104 %1106 + %1108 = OpExtInst %v3float %1 Exp %1107 + %1109 = OpFAdd %v3float %141 %1108 + %1110 = OpFDiv %v3float %1101 %1109 + %1111 = OpFAdd %v3float %1099 %1110 + %1112 = OpCompositeConstruct %v3float %1052 %1052 %1052 + %1113 = OpFMul %float %float_2 %1055 + %1114 = OpCompositeConstruct %v3float %1113 %1113 %1113 + %1115 = OpFMul %float %float_2 %1085 + %1116 = OpFDiv %float %1115 %1055 + %1117 = OpCompositeConstruct %v3float %1116 %1116 %1116 + %1118 = OpCompositeConstruct %v3float %1089 %1089 %1089 + %1119 = OpFSub %v3float %1093 %1118 + %1120 = OpFMul %v3float %1117 %1119 + %1121 = OpExtInst %v3float %1 Exp %1120 + %1122 = OpFAdd %v3float %141 %1121 + %1123 = OpFDiv %v3float %1114 %1122 + %1124 = OpFSub %v3float %1112 %1123 + %1125 = OpFOrdLessThan %v3bool %1093 %1105 + %1126 = OpSelect %v3float %1125 %1111 %1097 + %1127 = OpFOrdGreaterThan %v3bool %1093 %1118 + %1128 = OpSelect %v3float %1127 %1124 %1097 + %1129 = OpFSub %float %1089 %1082 + %1130 = OpCompositeConstruct %v3float %1129 %1129 %1129 + %1131 = OpFDiv %v3float %1106 %1130 + %1132 = OpExtInst %v3float %1 FClamp %1131 %138 %141 + %1133 = OpFOrdLessThan %bool %1089 %1082 + %1134 = OpFSub %v3float %141 %1132 + %1135 = OpCompositeConstruct %v3bool %1133 %1133 %1133 + %1136 = OpSelect %v3float %1135 %1134 %1132 + %1137 = OpFMul %v3float %252 %1136 + %1138 = OpFSub %v3float %251 %1137 + %1139 = OpFMul %v3float %1138 %1136 + %1140 = OpFMul %v3float %1139 %1136 + %1141 = OpExtInst %v3float %1 FMix %1126 %1128 %1140 + %1142 = OpDot %float %1141 %73 + %1143 = OpCompositeConstruct %v3float %1142 %1142 %1142 + %1144 = OpExtInst %v3float %1 FMix %1143 %1141 %254 + %1145 = OpExtInst %v3float %1 FMax %138 %1144 + %1146 = OpVectorTimesMatrix %v3float %1145 %936 + %1147 = OpExtInst %v3float %1 FMix %1145 %1146 %940 + %1148 = OpVectorTimesMatrix %v3float %1147 %575 + %1149 = OpExtInst %v3float %1 FMax %138 %1148 + %1150 = OpFOrdEqual %bool %746 %float_0 + OpSelectionMerge %1151 DontFlatten + OpBranchConditional %1150 %1152 %1151 + %1152 = OpLabel + %1153 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_2 + %1154 = OpLoad %v4float %1153 + %1155 = OpVectorShuffle %v3float %1154 %1154 0 1 2 + %1156 = OpDot %float %932 %1155 + %1157 = OpCompositeInsert %v3float %1156 %525 0 + %1158 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_3 + %1159 = OpLoad %v4float %1158 + %1160 = OpVectorShuffle %v3float %1159 %1159 0 1 2 + %1161 = OpDot %float %932 %1160 + %1162 = OpCompositeInsert %v3float %1161 %1157 1 + %1163 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_4 + %1164 = OpLoad %v4float %1163 + %1165 = OpVectorShuffle %v3float %1164 %1164 0 1 2 + %1166 = OpDot %float %932 %1165 + %1167 = OpCompositeInsert %v3float %1166 %1162 2 + %1168 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_8 + %1169 = OpLoad %v4float %1168 + %1170 = OpVectorShuffle %v3float %1169 %1169 0 1 2 + %1171 = OpLoad %v4float %744 + %1172 = OpVectorShuffle %v3float %1171 %1171 0 1 2 + %1173 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_7 + %1174 = OpLoad %v4float %1173 + %1175 = OpVectorShuffle %v3float %1174 %1174 0 1 2 + %1176 = OpDot %float %932 %1175 + %1177 = OpFAdd %float %1176 %float_1 + %1178 = OpFDiv %float %float_1 %1177 + %1179 = OpCompositeConstruct %v3float %1178 %1178 %1178 + %1180 = OpFMul %v3float %1172 %1179 + %1181 = OpFAdd %v3float %1170 %1180 + %1182 = OpFMul %v3float %1167 %1181 + %1183 = OpExtInst %v3float %1 FMax %138 %1182 + %1184 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_5 + %1185 = OpLoad %v4float %1184 + %1186 = OpVectorShuffle %v3float %1185 %1185 0 0 0 + %1187 = OpFSub %v3float %1186 %1183 + %1188 = OpExtInst %v3float %1 FMax %138 %1187 + %1189 = OpVectorShuffle %v3float %1185 %1185 2 2 2 + %1190 = OpExtInst %v3float %1 FMax %1183 %1189 + %1191 = OpExtInst %v3float %1 FClamp %1183 %1186 %1189 + %1192 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_6 + %1193 = OpLoad %v4float %1192 + %1194 = OpVectorShuffle %v3float %1193 %1193 0 0 0 + %1195 = OpFMul %v3float %1190 %1194 + %1196 = OpVectorShuffle %v3float %1193 %1193 1 1 1 + %1197 = OpFAdd %v3float %1195 %1196 + %1198 = OpVectorShuffle %v3float %1185 %1185 3 3 3 + %1199 = OpFAdd %v3float %1190 %1198 + %1200 = OpFDiv %v3float %141 %1199 + %1201 = OpFMul %v3float %1197 %1200 + %1202 = OpVectorShuffle %v3float %1164 %1164 3 3 3 + %1203 = OpFMul %v3float %1191 %1202 + %1204 = OpVectorShuffle %v3float %1154 %1154 3 3 3 + %1205 = OpFMul %v3float %1188 %1204 + %1206 = OpVectorShuffle %v3float %1185 %1185 1 1 1 + %1207 = OpFAdd %v3float %1188 %1206 + %1208 = OpFDiv %v3float %141 %1207 + %1209 = OpFMul %v3float %1205 %1208 + %1210 = OpVectorShuffle %v3float %1159 %1159 3 3 3 + %1211 = OpFAdd %v3float %1209 %1210 + %1212 = OpFAdd %v3float %1203 %1211 + %1213 = OpFAdd %v3float %1201 %1212 + %1214 = OpFSub %v3float %1213 %261 + OpBranch %1151 + %1151 = OpLabel + %1215 = OpPhi %v3float %1149 %1057 %1214 %1152 + %1216 = OpExtInst %v3float %1 FClamp %1215 %138 %141 + %1217 = OpCompositeExtract %float %1216 0 + OpBranch %1218 + %1218 = OpLabel + OpLoopMerge %1219 %1220 None + OpBranch %1221 + %1221 = OpLabel + %1222 = OpFOrdLessThan %bool %1217 %float_0_00313066994 + OpSelectionMerge %1223 None + OpBranchConditional %1222 %1224 %1223 + %1224 = OpLabel + %1225 = OpFMul %float %1217 %float_12_9200001 + OpBranch %1219 + %1223 = OpLabel + %1226 = OpExtInst %float %1 Pow %1217 %float_0_416666657 + %1227 = OpFMul %float %1226 %float_1_05499995 + %1228 = OpFSub %float %1227 %float_0_0549999997 + OpBranch %1219 + %1220 = OpLabel + OpBranch %1218 + %1219 = OpLabel + %1229 = OpPhi %float %1225 %1224 %1228 %1223 + %1230 = OpCompositeExtract %float %1216 1 + OpBranch %1231 + %1231 = OpLabel + OpLoopMerge %1232 %1233 None + OpBranch %1234 + %1234 = OpLabel + %1235 = OpFOrdLessThan %bool %1230 %float_0_00313066994 + OpSelectionMerge %1236 None + OpBranchConditional %1235 %1237 %1236 + %1237 = OpLabel + %1238 = OpFMul %float %1230 %float_12_9200001 + OpBranch %1232 + %1236 = OpLabel + %1239 = OpExtInst %float %1 Pow %1230 %float_0_416666657 + %1240 = OpFMul %float %1239 %float_1_05499995 + %1241 = OpFSub %float %1240 %float_0_0549999997 + OpBranch %1232 + %1233 = OpLabel + OpBranch %1231 + %1232 = OpLabel + %1242 = OpPhi %float %1238 %1237 %1241 %1236 + %1243 = OpCompositeExtract %float %1216 2 + OpBranch %1244 + %1244 = OpLabel + OpLoopMerge %1245 %1246 None + OpBranch %1247 + %1247 = OpLabel + %1248 = OpFOrdLessThan %bool %1243 %float_0_00313066994 + OpSelectionMerge %1249 None + OpBranchConditional %1248 %1250 %1249 + %1250 = OpLabel + %1251 = OpFMul %float %1243 %float_12_9200001 + OpBranch %1245 + %1249 = OpLabel + %1252 = OpExtInst %float %1 Pow %1243 %float_0_416666657 + %1253 = OpFMul %float %1252 %float_1_05499995 + %1254 = OpFSub %float %1253 %float_0_0549999997 + OpBranch %1245 + %1246 = OpLabel + OpBranch %1244 + %1245 = OpLabel + %1255 = OpPhi %float %1251 %1250 %1254 %1249 + %1256 = OpCompositeConstruct %v3float %1229 %1242 %1255 + %1257 = OpFMul %v3float %1256 %173 + %1258 = OpFAdd %v3float %1257 %175 + %1259 = OpAccessChain %_ptr_Uniform_float %_Globals %int_15 %int_0 + %1260 = OpLoad %float %1259 + %1261 = OpCompositeConstruct %v3float %1260 %1260 %1260 + %1262 = OpFMul %v3float %1261 %1256 + %1263 = OpAccessChain %_ptr_Uniform_float %_Globals %int_15 %int_1 + %1264 = OpLoad %float %1263 + %1265 = OpCompositeConstruct %v3float %1264 %1264 %1264 + %1266 = OpLoad %type_2d_image %Texture1 + %1267 = OpLoad %type_sampler %Texture1Sampler + %1268 = OpCompositeExtract %float %1258 2 + %1269 = OpFMul %float %1268 %float_16 + %1270 = OpFSub %float %1269 %float_0_5 + %1271 = OpExtInst %float %1 Floor %1270 + %1272 = OpFSub %float %1270 %1271 + %1273 = OpCompositeExtract %float %1258 0 + %1274 = OpFAdd %float %1273 %1271 + %1275 = OpFMul %float %1274 %float_0_0625 + %1276 = OpCompositeExtract %float %1258 1 + %1277 = OpCompositeConstruct %v2float %1275 %1276 + %1278 = OpSampledImage %type_sampled_image %1266 %1267 + %1279 = OpImageSampleImplicitLod %v4float %1278 %1277 None + %1280 = OpFAdd %float %1275 %float_0_0625 + %1281 = OpCompositeConstruct %v2float %1280 %1276 + %1282 = OpSampledImage %type_sampled_image %1266 %1267 + %1283 = OpImageSampleImplicitLod %v4float %1282 %1281 None + %1284 = OpCompositeConstruct %v4float %1272 %1272 %1272 %1272 + %1285 = OpExtInst %v4float %1 FMix %1279 %1283 %1284 + %1286 = OpVectorShuffle %v3float %1285 %1285 0 1 2 + %1287 = OpFMul %v3float %1265 %1286 + %1288 = OpFAdd %v3float %1262 %1287 + %1289 = OpExtInst %v3float %1 FMax %263 %1288 + %1290 = OpFOrdGreaterThan %v3bool %1289 %265 + %1291 = OpFMul %v3float %1289 %267 + %1292 = OpFAdd %v3float %1291 %269 + %1293 = OpExtInst %v3float %1 Pow %1292 %271 + %1294 = OpFMul %v3float %1289 %273 + %1295 = OpSelect %v3float %1290 %1293 %1294 + %1296 = OpAccessChain %_ptr_Uniform_float %_Globals %int_0 %int_0 + %1297 = OpLoad %float %1296 + %1298 = OpCompositeConstruct %v3float %1297 %1297 %1297 + %1299 = OpFMul %v3float %1295 %1295 + %1300 = OpFMul %v3float %1298 %1299 + %1301 = OpAccessChain %_ptr_Uniform_float %_Globals %int_0 %int_1 + %1302 = OpLoad %float %1301 + %1303 = OpCompositeConstruct %v3float %1302 %1302 %1302 + %1304 = OpFMul %v3float %1303 %1295 + %1305 = OpFAdd %v3float %1300 %1304 + %1306 = OpAccessChain %_ptr_Uniform_float %_Globals %int_0 %int_2 + %1307 = OpLoad %float %1306 + %1308 = OpCompositeConstruct %v3float %1307 %1307 %1307 + %1309 = OpFAdd %v3float %1305 %1308 + %1310 = OpAccessChain %_ptr_Uniform_v3float %_Globals %int_16 + %1311 = OpLoad %v3float %1310 + %1312 = OpFMul %v3float %1309 %1311 + %1313 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_17 + %1314 = OpLoad %v4float %1313 + %1315 = OpVectorShuffle %v3float %1314 %1314 0 1 2 + %1316 = OpAccessChain %_ptr_Uniform_float %_Globals %int_17 %int_3 + %1317 = OpLoad %float %1316 + %1318 = OpCompositeConstruct %v3float %1317 %1317 %1317 + %1319 = OpExtInst %v3float %1 FMix %1312 %1315 %1318 + %1320 = OpExtInst %v3float %1 FMax %138 %1319 + %1321 = OpAccessChain %_ptr_Uniform_float %_Globals %int_1 %int_1 + %1322 = OpLoad %float %1321 + %1323 = OpCompositeConstruct %v3float %1322 %1322 %1322 + %1324 = OpExtInst %v3float %1 Pow %1320 %1323 + %1325 = OpIEqual %bool %605 %uint_0 + OpSelectionMerge %1326 DontFlatten + OpBranchConditional %1325 %1327 %1328 + %1328 = OpLabel + %1329 = OpIEqual %bool %605 %uint_1 + OpSelectionMerge %1330 None + OpBranchConditional %1329 %1331 %1332 + %1332 = OpLabel + %1333 = OpIEqual %bool %605 %uint_3 + %1334 = OpIEqual %bool %605 %uint_5 + %1335 = OpLogicalOr %bool %1333 %1334 + OpSelectionMerge %1336 None + OpBranchConditional %1335 %1337 %1338 + %1338 = OpLabel + %1339 = OpIEqual %bool %605 %uint_4 + %1340 = OpIEqual %bool %605 %uint_6 + %1341 = OpLogicalOr %bool %1339 %1340 + OpSelectionMerge %1342 None + OpBranchConditional %1341 %1343 %1344 + %1344 = OpLabel + %1345 = OpIEqual %bool %605 %uint_7 + OpSelectionMerge %1346 None + OpBranchConditional %1345 %1347 %1348 + %1348 = OpLabel + %1349 = OpVectorTimesMatrix %v3float %1324 %573 + %1350 = OpVectorTimesMatrix %v3float %1349 %602 + %1351 = OpAccessChain %_ptr_Uniform_float %_Globals %int_1 %int_2 + %1352 = OpLoad %float %1351 + %1353 = OpCompositeConstruct %v3float %1352 %1352 %1352 + %1354 = OpExtInst %v3float %1 Pow %1350 %1353 + OpBranch %1346 + %1347 = OpLabel + %1355 = OpVectorTimesMatrix %v3float %932 %573 + %1356 = OpVectorTimesMatrix %v3float %1355 %602 + %1357 = OpFMul %v3float %1356 %519 + %1358 = OpExtInst %v3float %1 Pow %1357 %286 + %1359 = OpFMul %v3float %196 %1358 + %1360 = OpFAdd %v3float %195 %1359 + %1361 = OpFMul %v3float %197 %1358 + %1362 = OpFAdd %v3float %141 %1361 + %1363 = OpFDiv %v3float %141 %1362 + %1364 = OpFMul %v3float %1360 %1363 + %1365 = OpExtInst %v3float %1 Pow %1364 %287 + OpBranch %1346 + %1346 = OpLabel + %1366 = OpPhi %v3float %1354 %1348 %1365 %1347 + OpBranch %1342 + %1343 = OpLabel + %1367 = OpMatrixTimesMatrix %mat3v3float %572 %423 + %1368 = OpFMul %v3float %932 %285 + %1369 = OpVectorTimesMatrix %v3float %1368 %1367 + %1370 = OpCompositeExtract %float %1369 0 + %1371 = OpCompositeExtract %float %1369 1 + %1372 = OpExtInst %float %1 FMin %1370 %1371 + %1373 = OpCompositeExtract %float %1369 2 + %1374 = OpExtInst %float %1 FMin %1372 %1373 + %1375 = OpExtInst %float %1 FMax %1370 %1371 + %1376 = OpExtInst %float %1 FMax %1375 %1373 + %1377 = OpExtInst %float %1 FMax %1376 %float_1_00000001en10 + %1378 = OpExtInst %float %1 FMax %1374 %float_1_00000001en10 + %1379 = OpFSub %float %1377 %1378 + %1380 = OpExtInst %float %1 FMax %1376 %float_0_00999999978 + %1381 = OpFDiv %float %1379 %1380 + %1382 = OpFSub %float %1373 %1371 + %1383 = OpFMul %float %1373 %1382 + %1384 = OpFSub %float %1371 %1370 + %1385 = OpFMul %float %1371 %1384 + %1386 = OpFAdd %float %1383 %1385 + %1387 = OpFSub %float %1370 %1373 + %1388 = OpFMul %float %1370 %1387 + %1389 = OpFAdd %float %1386 %1388 + %1390 = OpExtInst %float %1 Sqrt %1389 + %1391 = OpFAdd %float %1373 %1371 + %1392 = OpFAdd %float %1391 %1370 + %1393 = OpFMul %float %float_1_75 %1390 + %1394 = OpFAdd %float %1392 %1393 + %1395 = OpFMul %float %1394 %float_0_333333343 + %1396 = OpFSub %float %1381 %float_0_400000006 + %1397 = OpFMul %float %1396 %float_5 + %1398 = OpFMul %float %1396 %float_2_5 + %1399 = OpExtInst %float %1 FAbs %1398 + %1400 = OpFSub %float %float_1 %1399 + %1401 = OpExtInst %float %1 FMax %1400 %float_0 + %1402 = OpExtInst %float %1 FSign %1397 + %1403 = OpConvertFToS %int %1402 + %1404 = OpConvertSToF %float %1403 + %1405 = OpFMul %float %1401 %1401 + %1406 = OpFSub %float %float_1 %1405 + %1407 = OpFMul %float %1404 %1406 + %1408 = OpFAdd %float %float_1 %1407 + %1409 = OpFMul %float %1408 %float_0_0250000004 + %1410 = OpFOrdLessThanEqual %bool %1395 %float_0_0533333346 + OpSelectionMerge %1411 None + OpBranchConditional %1410 %1412 %1413 + %1413 = OpLabel + %1414 = OpFOrdGreaterThanEqual %bool %1395 %float_0_159999996 + OpSelectionMerge %1415 None + OpBranchConditional %1414 %1416 %1417 + %1417 = OpLabel + %1418 = OpFDiv %float %float_0_239999995 %1394 + %1419 = OpFSub %float %1418 %float_0_5 + %1420 = OpFMul %float %1409 %1419 + OpBranch %1415 + %1416 = OpLabel + OpBranch %1415 + %1415 = OpLabel + %1421 = OpPhi %float %1420 %1417 %float_0 %1416 + OpBranch %1411 + %1412 = OpLabel + OpBranch %1411 + %1411 = OpLabel + %1422 = OpPhi %float %1421 %1415 %1409 %1412 + %1423 = OpFAdd %float %float_1 %1422 + %1424 = OpCompositeConstruct %v3float %1423 %1423 %1423 + %1425 = OpFMul %v3float %1369 %1424 + %1426 = OpCompositeExtract %float %1425 0 + %1427 = OpCompositeExtract %float %1425 1 + %1428 = OpFOrdEqual %bool %1426 %1427 + %1429 = OpCompositeExtract %float %1425 2 + %1430 = OpFOrdEqual %bool %1427 %1429 + %1431 = OpLogicalAnd %bool %1428 %1430 + OpSelectionMerge %1432 None + OpBranchConditional %1431 %1433 %1434 + %1434 = OpLabel + %1435 = OpExtInst %float %1 Sqrt %float_3 + %1436 = OpFSub %float %1427 %1429 + %1437 = OpFMul %float %1435 %1436 + %1438 = OpFMul %float %float_2 %1426 + %1439 = OpFSub %float %1438 %1427 + %1440 = OpFSub %float %1439 %1429 + %1441 = OpExtInst %float %1 Atan2 %1437 %1440 + %1442 = OpFMul %float %float_57_2957764 %1441 + OpBranch %1432 + %1433 = OpLabel + OpBranch %1432 + %1432 = OpLabel + %1443 = OpPhi %float %1442 %1434 %float_0 %1433 + %1444 = OpFOrdLessThan %bool %1443 %float_0 + OpSelectionMerge %1445 None + OpBranchConditional %1444 %1446 %1445 + %1446 = OpLabel + %1447 = OpFAdd %float %1443 %float_360 + OpBranch %1445 + %1445 = OpLabel + %1448 = OpPhi %float %1443 %1432 %1447 %1446 + %1449 = OpExtInst %float %1 FClamp %1448 %float_0 %float_360 + %1450 = OpFOrdGreaterThan %bool %1449 %float_180 + OpSelectionMerge %1451 None + OpBranchConditional %1450 %1452 %1451 + %1452 = OpLabel + %1453 = OpFSub %float %1449 %float_360 + OpBranch %1451 + %1451 = OpLabel + %1454 = OpPhi %float %1449 %1445 %1453 %1452 + %1455 = OpFOrdGreaterThan %bool %1454 %float_n67_5 + %1456 = OpFOrdLessThan %bool %1454 %float_67_5 + %1457 = OpLogicalAnd %bool %1455 %1456 + OpSelectionMerge %1458 None + OpBranchConditional %1457 %1459 %1458 + %1459 = OpLabel + %1460 = OpFSub %float %1454 %float_n67_5 + %1461 = OpFMul %float %1460 %float_0_0296296291 + %1462 = OpConvertFToS %int %1461 + %1463 = OpConvertSToF %float %1462 + %1464 = OpFSub %float %1461 %1463 + %1465 = OpFMul %float %1464 %1464 + %1466 = OpFMul %float %1465 %1464 + %1467 = OpIEqual %bool %1462 %int_3 + OpSelectionMerge %1468 None + OpBranchConditional %1467 %1469 %1470 + %1470 = OpLabel + %1471 = OpIEqual %bool %1462 %int_2 + OpSelectionMerge %1472 None + OpBranchConditional %1471 %1473 %1474 + %1474 = OpLabel + %1475 = OpIEqual %bool %1462 %int_1 + OpSelectionMerge %1476 None + OpBranchConditional %1475 %1477 %1478 + %1478 = OpLabel + %1479 = OpIEqual %bool %1462 %int_0 + OpSelectionMerge %1480 None + OpBranchConditional %1479 %1481 %1482 + %1482 = OpLabel + OpBranch %1480 + %1481 = OpLabel + %1483 = OpFMul %float %1466 %float_0_166666672 + OpBranch %1480 + %1480 = OpLabel + %1484 = OpPhi %float %float_0 %1482 %1483 %1481 + OpBranch %1476 + %1477 = OpLabel + %1485 = OpFMul %float %1466 %float_n0_5 + %1486 = OpFMul %float %1465 %float_0_5 + %1487 = OpFAdd %float %1485 %1486 + %1488 = OpFMul %float %1464 %float_0_5 + %1489 = OpFAdd %float %1487 %1488 + %1490 = OpFAdd %float %1489 %float_0_166666672 + OpBranch %1476 + %1476 = OpLabel + %1491 = OpPhi %float %1484 %1480 %1490 %1477 + OpBranch %1472 + %1473 = OpLabel + %1492 = OpFMul %float %1466 %float_0_5 + %1493 = OpFMul %float %1465 %float_n1 + %1494 = OpFAdd %float %1492 %1493 + %1495 = OpFAdd %float %1494 %float_0_666666687 + OpBranch %1472 + %1472 = OpLabel + %1496 = OpPhi %float %1491 %1476 %1495 %1473 + OpBranch %1468 + %1469 = OpLabel + %1497 = OpFMul %float %1466 %float_n0_166666672 + %1498 = OpFMul %float %1465 %float_0_5 + %1499 = OpFAdd %float %1497 %1498 + %1500 = OpFMul %float %1464 %float_n0_5 + %1501 = OpFAdd %float %1499 %1500 + %1502 = OpFAdd %float %1501 %float_0_166666672 + OpBranch %1468 + %1468 = OpLabel + %1503 = OpPhi %float %1496 %1472 %1502 %1469 + OpBranch %1458 + %1458 = OpLabel + %1504 = OpPhi %float %float_0 %1451 %1503 %1468 + %1505 = OpFMul %float %1504 %float_1_5 + %1506 = OpFMul %float %1505 %1381 + %1507 = OpFSub %float %float_0_0299999993 %1426 + %1508 = OpFMul %float %1506 %1507 + %1509 = OpFMul %float %1508 %float_0_180000007 + %1510 = OpFAdd %float %1426 %1509 + %1511 = OpCompositeInsert %v3float %1510 %1425 0 + %1512 = OpExtInst %v3float %1 FClamp %1511 %138 %337 + %1513 = OpVectorTimesMatrix %v3float %1512 %434 + %1514 = OpExtInst %v3float %1 FClamp %1513 %138 %337 + %1515 = OpDot %float %1514 %73 + %1516 = OpCompositeConstruct %v3float %1515 %1515 %1515 + %1517 = OpExtInst %v3float %1 FMix %1516 %1514 %241 + %1518 = OpCompositeExtract %float %1517 0 + %1519 = OpExtInst %float %1 Exp2 %float_n15 + %1520 = OpFMul %float %float_0_179999992 %1519 + %1521 = OpExtInst %float %1 Exp2 %float_18 + %1522 = OpFMul %float %float_0_179999992 %1521 + OpStore %528 %499 + OpStore %527 %500 + %1523 = OpFOrdLessThanEqual %bool %1518 %float_0 + %1524 = OpExtInst %float %1 Exp2 %float_n14 + %1525 = OpSelect %float %1523 %1524 %1518 + %1526 = OpExtInst %float %1 Log %1525 + %1527 = OpFDiv %float %1526 %1091 + %1528 = OpExtInst %float %1 Log %1520 + %1529 = OpFDiv %float %1528 %1091 + %1530 = OpFOrdLessThanEqual %bool %1527 %1529 + OpSelectionMerge %1531 None + OpBranchConditional %1530 %1532 %1533 + %1533 = OpLabel + %1534 = OpFOrdGreaterThan %bool %1527 %1529 + %1535 = OpExtInst %float %1 Log %float_0_180000007 + %1536 = OpFDiv %float %1535 %1091 + %1537 = OpFOrdLessThan %bool %1527 %1536 + %1538 = OpLogicalAnd %bool %1534 %1537 + OpSelectionMerge %1539 None + OpBranchConditional %1538 %1540 %1541 + %1541 = OpLabel + %1542 = OpFOrdGreaterThanEqual %bool %1527 %1536 + %1543 = OpExtInst %float %1 Log %1522 + %1544 = OpFDiv %float %1543 %1091 + %1545 = OpFOrdLessThan %bool %1527 %1544 + %1546 = OpLogicalAnd %bool %1542 %1545 + OpSelectionMerge %1547 None + OpBranchConditional %1546 %1548 %1549 + %1549 = OpLabel + %1550 = OpExtInst %float %1 Log %float_10000 + %1551 = OpFDiv %float %1550 %1091 + OpBranch %1547 + %1548 = OpLabel + %1552 = OpFSub %float %1527 %1536 + %1553 = OpFMul %float %float_3 %1552 + %1554 = OpFSub %float %1544 %1536 + %1555 = OpFDiv %float %1553 %1554 + %1556 = OpConvertFToS %int %1555 + %1557 = OpConvertSToF %float %1556 + %1558 = OpFSub %float %1555 %1557 + %1559 = OpAccessChain %_ptr_Function_float %527 %1556 + %1560 = OpLoad %float %1559 + %1561 = OpIAdd %int %1556 %int_1 + %1562 = OpAccessChain %_ptr_Function_float %527 %1561 + %1563 = OpLoad %float %1562 + %1564 = OpIAdd %int %1556 %int_2 + %1565 = OpAccessChain %_ptr_Function_float %527 %1564 + %1566 = OpLoad %float %1565 + %1567 = OpCompositeConstruct %v3float %1560 %1563 %1566 + %1568 = OpFMul %float %1558 %1558 + %1569 = OpCompositeConstruct %v3float %1568 %1558 %float_1 + %1570 = OpMatrixTimesVector %v3float %466 %1567 + %1571 = OpDot %float %1569 %1570 + OpBranch %1547 + %1547 = OpLabel + %1572 = OpPhi %float %1551 %1549 %1571 %1548 + OpBranch %1539 + %1540 = OpLabel + %1573 = OpFSub %float %1527 %1529 + %1574 = OpFMul %float %float_3 %1573 + %1575 = OpFSub %float %1536 %1529 + %1576 = OpFDiv %float %1574 %1575 + %1577 = OpConvertFToS %int %1576 + %1578 = OpConvertSToF %float %1577 + %1579 = OpFSub %float %1576 %1578 + %1580 = OpAccessChain %_ptr_Function_float %528 %1577 + %1581 = OpLoad %float %1580 + %1582 = OpIAdd %int %1577 %int_1 + %1583 = OpAccessChain %_ptr_Function_float %528 %1582 + %1584 = OpLoad %float %1583 + %1585 = OpIAdd %int %1577 %int_2 + %1586 = OpAccessChain %_ptr_Function_float %528 %1585 + %1587 = OpLoad %float %1586 + %1588 = OpCompositeConstruct %v3float %1581 %1584 %1587 + %1589 = OpFMul %float %1579 %1579 + %1590 = OpCompositeConstruct %v3float %1589 %1579 %float_1 + %1591 = OpMatrixTimesVector %v3float %466 %1588 + %1592 = OpDot %float %1590 %1591 + OpBranch %1539 + %1539 = OpLabel + %1593 = OpPhi %float %1572 %1547 %1592 %1540 + OpBranch %1531 + %1532 = OpLabel + %1594 = OpExtInst %float %1 Log %float_9_99999975en05 + %1595 = OpFDiv %float %1594 %1091 + OpBranch %1531 + %1531 = OpLabel + %1596 = OpPhi %float %1593 %1539 %1595 %1532 + %1597 = OpExtInst %float %1 Pow %float_10 %1596 + %1598 = OpCompositeInsert %v3float %1597 %523 0 + %1599 = OpCompositeExtract %float %1517 1 + OpStore %530 %499 + OpStore %529 %500 + %1600 = OpFOrdLessThanEqual %bool %1599 %float_0 + %1601 = OpSelect %float %1600 %1524 %1599 + %1602 = OpExtInst %float %1 Log %1601 + %1603 = OpFDiv %float %1602 %1091 + %1604 = OpFOrdLessThanEqual %bool %1603 %1529 + OpSelectionMerge %1605 None + OpBranchConditional %1604 %1606 %1607 + %1607 = OpLabel + %1608 = OpFOrdGreaterThan %bool %1603 %1529 + %1609 = OpExtInst %float %1 Log %float_0_180000007 + %1610 = OpFDiv %float %1609 %1091 + %1611 = OpFOrdLessThan %bool %1603 %1610 + %1612 = OpLogicalAnd %bool %1608 %1611 + OpSelectionMerge %1613 None + OpBranchConditional %1612 %1614 %1615 + %1615 = OpLabel + %1616 = OpFOrdGreaterThanEqual %bool %1603 %1610 + %1617 = OpExtInst %float %1 Log %1522 + %1618 = OpFDiv %float %1617 %1091 + %1619 = OpFOrdLessThan %bool %1603 %1618 + %1620 = OpLogicalAnd %bool %1616 %1619 + OpSelectionMerge %1621 None + OpBranchConditional %1620 %1622 %1623 + %1623 = OpLabel + %1624 = OpExtInst %float %1 Log %float_10000 + %1625 = OpFDiv %float %1624 %1091 + OpBranch %1621 + %1622 = OpLabel + %1626 = OpFSub %float %1603 %1610 + %1627 = OpFMul %float %float_3 %1626 + %1628 = OpFSub %float %1618 %1610 + %1629 = OpFDiv %float %1627 %1628 + %1630 = OpConvertFToS %int %1629 + %1631 = OpConvertSToF %float %1630 + %1632 = OpFSub %float %1629 %1631 + %1633 = OpAccessChain %_ptr_Function_float %529 %1630 + %1634 = OpLoad %float %1633 + %1635 = OpIAdd %int %1630 %int_1 + %1636 = OpAccessChain %_ptr_Function_float %529 %1635 + %1637 = OpLoad %float %1636 + %1638 = OpIAdd %int %1630 %int_2 + %1639 = OpAccessChain %_ptr_Function_float %529 %1638 + %1640 = OpLoad %float %1639 + %1641 = OpCompositeConstruct %v3float %1634 %1637 %1640 + %1642 = OpFMul %float %1632 %1632 + %1643 = OpCompositeConstruct %v3float %1642 %1632 %float_1 + %1644 = OpMatrixTimesVector %v3float %466 %1641 + %1645 = OpDot %float %1643 %1644 + OpBranch %1621 + %1621 = OpLabel + %1646 = OpPhi %float %1625 %1623 %1645 %1622 + OpBranch %1613 + %1614 = OpLabel + %1647 = OpFSub %float %1603 %1529 + %1648 = OpFMul %float %float_3 %1647 + %1649 = OpFSub %float %1610 %1529 + %1650 = OpFDiv %float %1648 %1649 + %1651 = OpConvertFToS %int %1650 + %1652 = OpConvertSToF %float %1651 + %1653 = OpFSub %float %1650 %1652 + %1654 = OpAccessChain %_ptr_Function_float %530 %1651 + %1655 = OpLoad %float %1654 + %1656 = OpIAdd %int %1651 %int_1 + %1657 = OpAccessChain %_ptr_Function_float %530 %1656 + %1658 = OpLoad %float %1657 + %1659 = OpIAdd %int %1651 %int_2 + %1660 = OpAccessChain %_ptr_Function_float %530 %1659 + %1661 = OpLoad %float %1660 + %1662 = OpCompositeConstruct %v3float %1655 %1658 %1661 + %1663 = OpFMul %float %1653 %1653 + %1664 = OpCompositeConstruct %v3float %1663 %1653 %float_1 + %1665 = OpMatrixTimesVector %v3float %466 %1662 + %1666 = OpDot %float %1664 %1665 + OpBranch %1613 + %1613 = OpLabel + %1667 = OpPhi %float %1646 %1621 %1666 %1614 + OpBranch %1605 + %1606 = OpLabel + %1668 = OpExtInst %float %1 Log %float_9_99999975en05 + %1669 = OpFDiv %float %1668 %1091 + OpBranch %1605 + %1605 = OpLabel + %1670 = OpPhi %float %1667 %1613 %1669 %1606 + %1671 = OpExtInst %float %1 Pow %float_10 %1670 + %1672 = OpCompositeInsert %v3float %1671 %1598 1 + %1673 = OpCompositeExtract %float %1517 2 + OpStore %532 %499 + OpStore %531 %500 + %1674 = OpFOrdLessThanEqual %bool %1673 %float_0 + %1675 = OpSelect %float %1674 %1524 %1673 + %1676 = OpExtInst %float %1 Log %1675 + %1677 = OpFDiv %float %1676 %1091 + %1678 = OpFOrdLessThanEqual %bool %1677 %1529 + OpSelectionMerge %1679 None + OpBranchConditional %1678 %1680 %1681 + %1681 = OpLabel + %1682 = OpFOrdGreaterThan %bool %1677 %1529 + %1683 = OpExtInst %float %1 Log %float_0_180000007 + %1684 = OpFDiv %float %1683 %1091 + %1685 = OpFOrdLessThan %bool %1677 %1684 + %1686 = OpLogicalAnd %bool %1682 %1685 + OpSelectionMerge %1687 None + OpBranchConditional %1686 %1688 %1689 + %1689 = OpLabel + %1690 = OpFOrdGreaterThanEqual %bool %1677 %1684 + %1691 = OpExtInst %float %1 Log %1522 + %1692 = OpFDiv %float %1691 %1091 + %1693 = OpFOrdLessThan %bool %1677 %1692 + %1694 = OpLogicalAnd %bool %1690 %1693 + OpSelectionMerge %1695 None + OpBranchConditional %1694 %1696 %1697 + %1697 = OpLabel + %1698 = OpExtInst %float %1 Log %float_10000 + %1699 = OpFDiv %float %1698 %1091 + OpBranch %1695 + %1696 = OpLabel + %1700 = OpFSub %float %1677 %1684 + %1701 = OpFMul %float %float_3 %1700 + %1702 = OpFSub %float %1692 %1684 + %1703 = OpFDiv %float %1701 %1702 + %1704 = OpConvertFToS %int %1703 + %1705 = OpConvertSToF %float %1704 + %1706 = OpFSub %float %1703 %1705 + %1707 = OpAccessChain %_ptr_Function_float %531 %1704 + %1708 = OpLoad %float %1707 + %1709 = OpIAdd %int %1704 %int_1 + %1710 = OpAccessChain %_ptr_Function_float %531 %1709 + %1711 = OpLoad %float %1710 + %1712 = OpIAdd %int %1704 %int_2 + %1713 = OpAccessChain %_ptr_Function_float %531 %1712 + %1714 = OpLoad %float %1713 + %1715 = OpCompositeConstruct %v3float %1708 %1711 %1714 + %1716 = OpFMul %float %1706 %1706 + %1717 = OpCompositeConstruct %v3float %1716 %1706 %float_1 + %1718 = OpMatrixTimesVector %v3float %466 %1715 + %1719 = OpDot %float %1717 %1718 + OpBranch %1695 + %1695 = OpLabel + %1720 = OpPhi %float %1699 %1697 %1719 %1696 + OpBranch %1687 + %1688 = OpLabel + %1721 = OpFSub %float %1677 %1529 + %1722 = OpFMul %float %float_3 %1721 + %1723 = OpFSub %float %1684 %1529 + %1724 = OpFDiv %float %1722 %1723 + %1725 = OpConvertFToS %int %1724 + %1726 = OpConvertSToF %float %1725 + %1727 = OpFSub %float %1724 %1726 + %1728 = OpAccessChain %_ptr_Function_float %532 %1725 + %1729 = OpLoad %float %1728 + %1730 = OpIAdd %int %1725 %int_1 + %1731 = OpAccessChain %_ptr_Function_float %532 %1730 + %1732 = OpLoad %float %1731 + %1733 = OpIAdd %int %1725 %int_2 + %1734 = OpAccessChain %_ptr_Function_float %532 %1733 + %1735 = OpLoad %float %1734 + %1736 = OpCompositeConstruct %v3float %1729 %1732 %1735 + %1737 = OpFMul %float %1727 %1727 + %1738 = OpCompositeConstruct %v3float %1737 %1727 %float_1 + %1739 = OpMatrixTimesVector %v3float %466 %1736 + %1740 = OpDot %float %1738 %1739 + OpBranch %1687 + %1687 = OpLabel + %1741 = OpPhi %float %1720 %1695 %1740 %1688 + OpBranch %1679 + %1680 = OpLabel + %1742 = OpExtInst %float %1 Log %float_9_99999975en05 + %1743 = OpFDiv %float %1742 %1091 + OpBranch %1679 + %1679 = OpLabel + %1744 = OpPhi %float %1741 %1687 %1743 %1680 + %1745 = OpExtInst %float %1 Pow %float_10 %1744 + %1746 = OpCompositeInsert %v3float %1745 %1672 2 + %1747 = OpVectorTimesMatrix %v3float %1746 %438 + %1748 = OpVectorTimesMatrix %v3float %1747 %434 + %1749 = OpExtInst %float %1 Pow %float_2 %float_n12 + %1750 = OpFMul %float %float_0_179999992 %1749 + OpStore %540 %499 + OpStore %539 %500 + %1751 = OpFOrdLessThanEqual %bool %1750 %float_0 + %1752 = OpSelect %float %1751 %1524 %1750 + %1753 = OpExtInst %float %1 Log %1752 + %1754 = OpFDiv %float %1753 %1091 + %1755 = OpFOrdLessThanEqual %bool %1754 %1529 + OpSelectionMerge %1756 None + OpBranchConditional %1755 %1757 %1758 + %1758 = OpLabel + %1759 = OpFOrdGreaterThan %bool %1754 %1529 + %1760 = OpExtInst %float %1 Log %float_0_180000007 + %1761 = OpFDiv %float %1760 %1091 + %1762 = OpFOrdLessThan %bool %1754 %1761 + %1763 = OpLogicalAnd %bool %1759 %1762 + OpSelectionMerge %1764 None + OpBranchConditional %1763 %1765 %1766 + %1766 = OpLabel + %1767 = OpFOrdGreaterThanEqual %bool %1754 %1761 + %1768 = OpExtInst %float %1 Log %1522 + %1769 = OpFDiv %float %1768 %1091 + %1770 = OpFOrdLessThan %bool %1754 %1769 + %1771 = OpLogicalAnd %bool %1767 %1770 + OpSelectionMerge %1772 None + OpBranchConditional %1771 %1773 %1774 + %1774 = OpLabel + %1775 = OpExtInst %float %1 Log %float_10000 + %1776 = OpFDiv %float %1775 %1091 + OpBranch %1772 + %1773 = OpLabel + %1777 = OpFSub %float %1754 %1761 + %1778 = OpFMul %float %float_3 %1777 + %1779 = OpFSub %float %1769 %1761 + %1780 = OpFDiv %float %1778 %1779 + %1781 = OpConvertFToS %int %1780 + %1782 = OpConvertSToF %float %1781 + %1783 = OpFSub %float %1780 %1782 + %1784 = OpAccessChain %_ptr_Function_float %539 %1781 + %1785 = OpLoad %float %1784 + %1786 = OpIAdd %int %1781 %int_1 + %1787 = OpAccessChain %_ptr_Function_float %539 %1786 + %1788 = OpLoad %float %1787 + %1789 = OpIAdd %int %1781 %int_2 + %1790 = OpAccessChain %_ptr_Function_float %539 %1789 + %1791 = OpLoad %float %1790 + %1792 = OpCompositeConstruct %v3float %1785 %1788 %1791 + %1793 = OpFMul %float %1783 %1783 + %1794 = OpCompositeConstruct %v3float %1793 %1783 %float_1 + %1795 = OpMatrixTimesVector %v3float %466 %1792 + %1796 = OpDot %float %1794 %1795 + OpBranch %1772 + %1772 = OpLabel + %1797 = OpPhi %float %1776 %1774 %1796 %1773 + OpBranch %1764 + %1765 = OpLabel + %1798 = OpFSub %float %1754 %1529 + %1799 = OpFMul %float %float_3 %1798 + %1800 = OpFSub %float %1761 %1529 + %1801 = OpFDiv %float %1799 %1800 + %1802 = OpConvertFToS %int %1801 + %1803 = OpConvertSToF %float %1802 + %1804 = OpFSub %float %1801 %1803 + %1805 = OpAccessChain %_ptr_Function_float %540 %1802 + %1806 = OpLoad %float %1805 + %1807 = OpIAdd %int %1802 %int_1 + %1808 = OpAccessChain %_ptr_Function_float %540 %1807 + %1809 = OpLoad %float %1808 + %1810 = OpIAdd %int %1802 %int_2 + %1811 = OpAccessChain %_ptr_Function_float %540 %1810 + %1812 = OpLoad %float %1811 + %1813 = OpCompositeConstruct %v3float %1806 %1809 %1812 + %1814 = OpFMul %float %1804 %1804 + %1815 = OpCompositeConstruct %v3float %1814 %1804 %float_1 + %1816 = OpMatrixTimesVector %v3float %466 %1813 + %1817 = OpDot %float %1815 %1816 + OpBranch %1764 + %1764 = OpLabel + %1818 = OpPhi %float %1797 %1772 %1817 %1765 + OpBranch %1756 + %1757 = OpLabel + %1819 = OpExtInst %float %1 Log %float_9_99999975en05 + %1820 = OpFDiv %float %1819 %1091 + OpBranch %1756 + %1756 = OpLabel + %1821 = OpPhi %float %1818 %1764 %1820 %1757 + %1822 = OpExtInst %float %1 Pow %float_10 %1821 + OpStore %542 %499 + OpStore %541 %500 + %1823 = OpExtInst %float %1 Log %float_0_180000007 + %1824 = OpFDiv %float %1823 %1091 + %1825 = OpFOrdLessThanEqual %bool %1824 %1529 + OpSelectionMerge %1826 None + OpBranchConditional %1825 %1827 %1828 + %1828 = OpLabel + %1829 = OpFOrdGreaterThan %bool %1824 %1529 + %1830 = OpFOrdLessThan %bool %1824 %1824 + %1831 = OpLogicalAnd %bool %1829 %1830 + OpSelectionMerge %1832 None + OpBranchConditional %1831 %1833 %1834 + %1834 = OpLabel + %1835 = OpFOrdGreaterThanEqual %bool %1824 %1824 + %1836 = OpExtInst %float %1 Log %1522 + %1837 = OpFDiv %float %1836 %1091 + %1838 = OpFOrdLessThan %bool %1824 %1837 + %1839 = OpLogicalAnd %bool %1835 %1838 + OpSelectionMerge %1840 None + OpBranchConditional %1839 %1841 %1842 + %1842 = OpLabel + %1843 = OpExtInst %float %1 Log %float_10000 + %1844 = OpFDiv %float %1843 %1091 + OpBranch %1840 + %1841 = OpLabel + %1845 = OpFSub %float %1824 %1824 + %1846 = OpFMul %float %float_3 %1845 + %1847 = OpFSub %float %1837 %1824 + %1848 = OpFDiv %float %1846 %1847 + %1849 = OpConvertFToS %int %1848 + %1850 = OpConvertSToF %float %1849 + %1851 = OpFSub %float %1848 %1850 + %1852 = OpAccessChain %_ptr_Function_float %541 %1849 + %1853 = OpLoad %float %1852 + %1854 = OpIAdd %int %1849 %int_1 + %1855 = OpAccessChain %_ptr_Function_float %541 %1854 + %1856 = OpLoad %float %1855 + %1857 = OpIAdd %int %1849 %int_2 + %1858 = OpAccessChain %_ptr_Function_float %541 %1857 + %1859 = OpLoad %float %1858 + %1860 = OpCompositeConstruct %v3float %1853 %1856 %1859 + %1861 = OpFMul %float %1851 %1851 + %1862 = OpCompositeConstruct %v3float %1861 %1851 %float_1 + %1863 = OpMatrixTimesVector %v3float %466 %1860 + %1864 = OpDot %float %1862 %1863 + OpBranch %1840 + %1840 = OpLabel + %1865 = OpPhi %float %1844 %1842 %1864 %1841 + OpBranch %1832 + %1833 = OpLabel + %1866 = OpAccessChain %_ptr_Function_float %542 %int_3 + %1867 = OpLoad %float %1866 + %1868 = OpAccessChain %_ptr_Function_float %542 %int_4 + %1869 = OpLoad %float %1868 + %1870 = OpAccessChain %_ptr_Function_float %542 %int_5 + %1871 = OpLoad %float %1870 + %1872 = OpCompositeConstruct %v3float %1867 %1869 %1871 + %1873 = OpMatrixTimesVector %v3float %466 %1872 + %1874 = OpCompositeExtract %float %1873 2 + OpBranch %1832 + %1832 = OpLabel + %1875 = OpPhi %float %1865 %1840 %1874 %1833 + OpBranch %1826 + %1827 = OpLabel + %1876 = OpExtInst %float %1 Log %float_9_99999975en05 + %1877 = OpFDiv %float %1876 %1091 + OpBranch %1826 + %1826 = OpLabel + %1878 = OpPhi %float %1875 %1832 %1877 %1827 + %1879 = OpExtInst %float %1 Pow %float_10 %1878 + %1880 = OpExtInst %float %1 Pow %float_2 %float_11 + %1881 = OpFMul %float %float_0_179999992 %1880 + OpStore %544 %499 + OpStore %543 %500 + %1882 = OpFOrdLessThanEqual %bool %1881 %float_0 + %1883 = OpSelect %float %1882 %1524 %1881 + %1884 = OpExtInst %float %1 Log %1883 + %1885 = OpFDiv %float %1884 %1091 + %1886 = OpFOrdLessThanEqual %bool %1885 %1529 + OpSelectionMerge %1887 None + OpBranchConditional %1886 %1888 %1889 + %1889 = OpLabel + %1890 = OpFOrdGreaterThan %bool %1885 %1529 + %1891 = OpFOrdLessThan %bool %1885 %1824 + %1892 = OpLogicalAnd %bool %1890 %1891 + OpSelectionMerge %1893 None + OpBranchConditional %1892 %1894 %1895 + %1895 = OpLabel + %1896 = OpFOrdGreaterThanEqual %bool %1885 %1824 + %1897 = OpExtInst %float %1 Log %1522 + %1898 = OpFDiv %float %1897 %1091 + %1899 = OpFOrdLessThan %bool %1885 %1898 + %1900 = OpLogicalAnd %bool %1896 %1899 + OpSelectionMerge %1901 None + OpBranchConditional %1900 %1902 %1903 + %1903 = OpLabel + %1904 = OpExtInst %float %1 Log %float_10000 + %1905 = OpFDiv %float %1904 %1091 + OpBranch %1901 + %1902 = OpLabel + %1906 = OpFSub %float %1885 %1824 + %1907 = OpFMul %float %float_3 %1906 + %1908 = OpFSub %float %1898 %1824 + %1909 = OpFDiv %float %1907 %1908 + %1910 = OpConvertFToS %int %1909 + %1911 = OpConvertSToF %float %1910 + %1912 = OpFSub %float %1909 %1911 + %1913 = OpAccessChain %_ptr_Function_float %543 %1910 + %1914 = OpLoad %float %1913 + %1915 = OpIAdd %int %1910 %int_1 + %1916 = OpAccessChain %_ptr_Function_float %543 %1915 + %1917 = OpLoad %float %1916 + %1918 = OpIAdd %int %1910 %int_2 + %1919 = OpAccessChain %_ptr_Function_float %543 %1918 + %1920 = OpLoad %float %1919 + %1921 = OpCompositeConstruct %v3float %1914 %1917 %1920 + %1922 = OpFMul %float %1912 %1912 + %1923 = OpCompositeConstruct %v3float %1922 %1912 %float_1 + %1924 = OpMatrixTimesVector %v3float %466 %1921 + %1925 = OpDot %float %1923 %1924 + OpBranch %1901 + %1901 = OpLabel + %1926 = OpPhi %float %1905 %1903 %1925 %1902 + OpBranch %1893 + %1894 = OpLabel + %1927 = OpFSub %float %1885 %1529 + %1928 = OpFMul %float %float_3 %1927 + %1929 = OpFSub %float %1824 %1529 + %1930 = OpFDiv %float %1928 %1929 + %1931 = OpConvertFToS %int %1930 + %1932 = OpConvertSToF %float %1931 + %1933 = OpFSub %float %1930 %1932 + %1934 = OpAccessChain %_ptr_Function_float %544 %1931 + %1935 = OpLoad %float %1934 + %1936 = OpIAdd %int %1931 %int_1 + %1937 = OpAccessChain %_ptr_Function_float %544 %1936 + %1938 = OpLoad %float %1937 + %1939 = OpIAdd %int %1931 %int_2 + %1940 = OpAccessChain %_ptr_Function_float %544 %1939 + %1941 = OpLoad %float %1940 + %1942 = OpCompositeConstruct %v3float %1935 %1938 %1941 + %1943 = OpFMul %float %1933 %1933 + %1944 = OpCompositeConstruct %v3float %1943 %1933 %float_1 + %1945 = OpMatrixTimesVector %v3float %466 %1942 + %1946 = OpDot %float %1944 %1945 + OpBranch %1893 + %1893 = OpLabel + %1947 = OpPhi %float %1926 %1901 %1946 %1894 + OpBranch %1887 + %1888 = OpLabel + %1948 = OpExtInst %float %1 Log %float_9_99999975en05 + %1949 = OpFDiv %float %1948 %1091 + OpBranch %1887 + %1887 = OpLabel + %1950 = OpPhi %float %1947 %1893 %1949 %1888 + %1951 = OpExtInst %float %1 Pow %float_10 %1950 + %1952 = OpCompositeExtract %float %1748 0 + OpStore %538 %506 + OpStore %537 %507 + %1953 = OpFOrdLessThanEqual %bool %1952 %float_0 + %1954 = OpSelect %float %1953 %float_9_99999975en05 %1952 + %1955 = OpExtInst %float %1 Log %1954 + %1956 = OpFDiv %float %1955 %1091 + %1957 = OpExtInst %float %1 Log %1822 + %1958 = OpFDiv %float %1957 %1091 + %1959 = OpFOrdLessThanEqual %bool %1956 %1958 + OpSelectionMerge %1960 None + OpBranchConditional %1959 %1961 %1962 + %1962 = OpLabel + %1963 = OpFOrdGreaterThan %bool %1956 %1958 + %1964 = OpExtInst %float %1 Log %1879 + %1965 = OpFDiv %float %1964 %1091 + %1966 = OpFOrdLessThan %bool %1956 %1965 + %1967 = OpLogicalAnd %bool %1963 %1966 + OpSelectionMerge %1968 None + OpBranchConditional %1967 %1969 %1970 + %1970 = OpLabel + %1971 = OpFOrdGreaterThanEqual %bool %1956 %1965 + %1972 = OpExtInst %float %1 Log %1951 + %1973 = OpFDiv %float %1972 %1091 + %1974 = OpFOrdLessThan %bool %1956 %1973 + %1975 = OpLogicalAnd %bool %1971 %1974 + OpSelectionMerge %1976 None + OpBranchConditional %1975 %1977 %1978 + %1978 = OpLabel + %1979 = OpFMul %float %1956 %float_0_119999997 + %1980 = OpExtInst %float %1 Log %float_2000 + %1981 = OpFDiv %float %1980 %1091 + %1982 = OpFMul %float %float_0_119999997 %1972 + %1983 = OpFDiv %float %1982 %1091 + %1984 = OpFSub %float %1981 %1983 + %1985 = OpFAdd %float %1979 %1984 + OpBranch %1976 + %1977 = OpLabel + %1986 = OpFSub %float %1956 %1965 + %1987 = OpFMul %float %float_7 %1986 + %1988 = OpFSub %float %1973 %1965 + %1989 = OpFDiv %float %1987 %1988 + %1990 = OpConvertFToS %int %1989 + %1991 = OpConvertSToF %float %1990 + %1992 = OpFSub %float %1989 %1991 + %1993 = OpAccessChain %_ptr_Function_float %537 %1990 + %1994 = OpLoad %float %1993 + %1995 = OpIAdd %int %1990 %int_1 + %1996 = OpAccessChain %_ptr_Function_float %537 %1995 + %1997 = OpLoad %float %1996 + %1998 = OpIAdd %int %1990 %int_2 + %1999 = OpAccessChain %_ptr_Function_float %537 %1998 + %2000 = OpLoad %float %1999 + %2001 = OpCompositeConstruct %v3float %1994 %1997 %2000 + %2002 = OpFMul %float %1992 %1992 + %2003 = OpCompositeConstruct %v3float %2002 %1992 %float_1 + %2004 = OpMatrixTimesVector %v3float %466 %2001 + %2005 = OpDot %float %2003 %2004 + OpBranch %1976 + %1976 = OpLabel + %2006 = OpPhi %float %1985 %1978 %2005 %1977 + OpBranch %1968 + %1969 = OpLabel + %2007 = OpFSub %float %1956 %1958 + %2008 = OpFMul %float %float_7 %2007 + %2009 = OpFSub %float %1965 %1958 + %2010 = OpFDiv %float %2008 %2009 + %2011 = OpConvertFToS %int %2010 + %2012 = OpConvertSToF %float %2011 + %2013 = OpFSub %float %2010 %2012 + %2014 = OpAccessChain %_ptr_Function_float %538 %2011 + %2015 = OpLoad %float %2014 + %2016 = OpIAdd %int %2011 %int_1 + %2017 = OpAccessChain %_ptr_Function_float %538 %2016 + %2018 = OpLoad %float %2017 + %2019 = OpIAdd %int %2011 %int_2 + %2020 = OpAccessChain %_ptr_Function_float %538 %2019 + %2021 = OpLoad %float %2020 + %2022 = OpCompositeConstruct %v3float %2015 %2018 %2021 + %2023 = OpFMul %float %2013 %2013 + %2024 = OpCompositeConstruct %v3float %2023 %2013 %float_1 + %2025 = OpMatrixTimesVector %v3float %466 %2022 + %2026 = OpDot %float %2024 %2025 + OpBranch %1968 + %1968 = OpLabel + %2027 = OpPhi %float %2006 %1976 %2026 %1969 + OpBranch %1960 + %1961 = OpLabel + %2028 = OpExtInst %float %1 Log %float_0_00499999989 + %2029 = OpFDiv %float %2028 %1091 + OpBranch %1960 + %1960 = OpLabel + %2030 = OpPhi %float %2027 %1968 %2029 %1961 + %2031 = OpExtInst %float %1 Pow %float_10 %2030 + %2032 = OpCompositeInsert %v3float %2031 %523 0 + %2033 = OpCompositeExtract %float %1748 1 + OpStore %536 %506 + OpStore %535 %507 + %2034 = OpFOrdLessThanEqual %bool %2033 %float_0 + %2035 = OpSelect %float %2034 %float_9_99999975en05 %2033 + %2036 = OpExtInst %float %1 Log %2035 + %2037 = OpFDiv %float %2036 %1091 + %2038 = OpFOrdLessThanEqual %bool %2037 %1958 + OpSelectionMerge %2039 None + OpBranchConditional %2038 %2040 %2041 + %2041 = OpLabel + %2042 = OpFOrdGreaterThan %bool %2037 %1958 + %2043 = OpExtInst %float %1 Log %1879 + %2044 = OpFDiv %float %2043 %1091 + %2045 = OpFOrdLessThan %bool %2037 %2044 + %2046 = OpLogicalAnd %bool %2042 %2045 + OpSelectionMerge %2047 None + OpBranchConditional %2046 %2048 %2049 + %2049 = OpLabel + %2050 = OpFOrdGreaterThanEqual %bool %2037 %2044 + %2051 = OpExtInst %float %1 Log %1951 + %2052 = OpFDiv %float %2051 %1091 + %2053 = OpFOrdLessThan %bool %2037 %2052 + %2054 = OpLogicalAnd %bool %2050 %2053 + OpSelectionMerge %2055 None + OpBranchConditional %2054 %2056 %2057 + %2057 = OpLabel + %2058 = OpFMul %float %2037 %float_0_119999997 + %2059 = OpExtInst %float %1 Log %float_2000 + %2060 = OpFDiv %float %2059 %1091 + %2061 = OpFMul %float %float_0_119999997 %2051 + %2062 = OpFDiv %float %2061 %1091 + %2063 = OpFSub %float %2060 %2062 + %2064 = OpFAdd %float %2058 %2063 + OpBranch %2055 + %2056 = OpLabel + %2065 = OpFSub %float %2037 %2044 + %2066 = OpFMul %float %float_7 %2065 + %2067 = OpFSub %float %2052 %2044 + %2068 = OpFDiv %float %2066 %2067 + %2069 = OpConvertFToS %int %2068 + %2070 = OpConvertSToF %float %2069 + %2071 = OpFSub %float %2068 %2070 + %2072 = OpAccessChain %_ptr_Function_float %535 %2069 + %2073 = OpLoad %float %2072 + %2074 = OpIAdd %int %2069 %int_1 + %2075 = OpAccessChain %_ptr_Function_float %535 %2074 + %2076 = OpLoad %float %2075 + %2077 = OpIAdd %int %2069 %int_2 + %2078 = OpAccessChain %_ptr_Function_float %535 %2077 + %2079 = OpLoad %float %2078 + %2080 = OpCompositeConstruct %v3float %2073 %2076 %2079 + %2081 = OpFMul %float %2071 %2071 + %2082 = OpCompositeConstruct %v3float %2081 %2071 %float_1 + %2083 = OpMatrixTimesVector %v3float %466 %2080 + %2084 = OpDot %float %2082 %2083 + OpBranch %2055 + %2055 = OpLabel + %2085 = OpPhi %float %2064 %2057 %2084 %2056 + OpBranch %2047 + %2048 = OpLabel + %2086 = OpFSub %float %2037 %1958 + %2087 = OpFMul %float %float_7 %2086 + %2088 = OpFSub %float %2044 %1958 + %2089 = OpFDiv %float %2087 %2088 + %2090 = OpConvertFToS %int %2089 + %2091 = OpConvertSToF %float %2090 + %2092 = OpFSub %float %2089 %2091 + %2093 = OpAccessChain %_ptr_Function_float %536 %2090 + %2094 = OpLoad %float %2093 + %2095 = OpIAdd %int %2090 %int_1 + %2096 = OpAccessChain %_ptr_Function_float %536 %2095 + %2097 = OpLoad %float %2096 + %2098 = OpIAdd %int %2090 %int_2 + %2099 = OpAccessChain %_ptr_Function_float %536 %2098 + %2100 = OpLoad %float %2099 + %2101 = OpCompositeConstruct %v3float %2094 %2097 %2100 + %2102 = OpFMul %float %2092 %2092 + %2103 = OpCompositeConstruct %v3float %2102 %2092 %float_1 + %2104 = OpMatrixTimesVector %v3float %466 %2101 + %2105 = OpDot %float %2103 %2104 + OpBranch %2047 + %2047 = OpLabel + %2106 = OpPhi %float %2085 %2055 %2105 %2048 + OpBranch %2039 + %2040 = OpLabel + %2107 = OpExtInst %float %1 Log %float_0_00499999989 + %2108 = OpFDiv %float %2107 %1091 + OpBranch %2039 + %2039 = OpLabel + %2109 = OpPhi %float %2106 %2047 %2108 %2040 + %2110 = OpExtInst %float %1 Pow %float_10 %2109 + %2111 = OpCompositeInsert %v3float %2110 %2032 1 + %2112 = OpCompositeExtract %float %1748 2 + OpStore %534 %506 + OpStore %533 %507 + %2113 = OpFOrdLessThanEqual %bool %2112 %float_0 + %2114 = OpSelect %float %2113 %float_9_99999975en05 %2112 + %2115 = OpExtInst %float %1 Log %2114 + %2116 = OpFDiv %float %2115 %1091 + %2117 = OpFOrdLessThanEqual %bool %2116 %1958 + OpSelectionMerge %2118 None + OpBranchConditional %2117 %2119 %2120 + %2120 = OpLabel + %2121 = OpFOrdGreaterThan %bool %2116 %1958 + %2122 = OpExtInst %float %1 Log %1879 + %2123 = OpFDiv %float %2122 %1091 + %2124 = OpFOrdLessThan %bool %2116 %2123 + %2125 = OpLogicalAnd %bool %2121 %2124 + OpSelectionMerge %2126 None + OpBranchConditional %2125 %2127 %2128 + %2128 = OpLabel + %2129 = OpFOrdGreaterThanEqual %bool %2116 %2123 + %2130 = OpExtInst %float %1 Log %1951 + %2131 = OpFDiv %float %2130 %1091 + %2132 = OpFOrdLessThan %bool %2116 %2131 + %2133 = OpLogicalAnd %bool %2129 %2132 + OpSelectionMerge %2134 None + OpBranchConditional %2133 %2135 %2136 + %2136 = OpLabel + %2137 = OpFMul %float %2116 %float_0_119999997 + %2138 = OpExtInst %float %1 Log %float_2000 + %2139 = OpFDiv %float %2138 %1091 + %2140 = OpFMul %float %float_0_119999997 %2130 + %2141 = OpFDiv %float %2140 %1091 + %2142 = OpFSub %float %2139 %2141 + %2143 = OpFAdd %float %2137 %2142 + OpBranch %2134 + %2135 = OpLabel + %2144 = OpFSub %float %2116 %2123 + %2145 = OpFMul %float %float_7 %2144 + %2146 = OpFSub %float %2131 %2123 + %2147 = OpFDiv %float %2145 %2146 + %2148 = OpConvertFToS %int %2147 + %2149 = OpConvertSToF %float %2148 + %2150 = OpFSub %float %2147 %2149 + %2151 = OpAccessChain %_ptr_Function_float %533 %2148 + %2152 = OpLoad %float %2151 + %2153 = OpIAdd %int %2148 %int_1 + %2154 = OpAccessChain %_ptr_Function_float %533 %2153 + %2155 = OpLoad %float %2154 + %2156 = OpIAdd %int %2148 %int_2 + %2157 = OpAccessChain %_ptr_Function_float %533 %2156 + %2158 = OpLoad %float %2157 + %2159 = OpCompositeConstruct %v3float %2152 %2155 %2158 + %2160 = OpFMul %float %2150 %2150 + %2161 = OpCompositeConstruct %v3float %2160 %2150 %float_1 + %2162 = OpMatrixTimesVector %v3float %466 %2159 + %2163 = OpDot %float %2161 %2162 + OpBranch %2134 + %2134 = OpLabel + %2164 = OpPhi %float %2143 %2136 %2163 %2135 + OpBranch %2126 + %2127 = OpLabel + %2165 = OpFSub %float %2116 %1958 + %2166 = OpFMul %float %float_7 %2165 + %2167 = OpFSub %float %2123 %1958 + %2168 = OpFDiv %float %2166 %2167 + %2169 = OpConvertFToS %int %2168 + %2170 = OpConvertSToF %float %2169 + %2171 = OpFSub %float %2168 %2170 + %2172 = OpAccessChain %_ptr_Function_float %534 %2169 + %2173 = OpLoad %float %2172 + %2174 = OpIAdd %int %2169 %int_1 + %2175 = OpAccessChain %_ptr_Function_float %534 %2174 + %2176 = OpLoad %float %2175 + %2177 = OpIAdd %int %2169 %int_2 + %2178 = OpAccessChain %_ptr_Function_float %534 %2177 + %2179 = OpLoad %float %2178 + %2180 = OpCompositeConstruct %v3float %2173 %2176 %2179 + %2181 = OpFMul %float %2171 %2171 + %2182 = OpCompositeConstruct %v3float %2181 %2171 %float_1 + %2183 = OpMatrixTimesVector %v3float %466 %2180 + %2184 = OpDot %float %2182 %2183 + OpBranch %2126 + %2126 = OpLabel + %2185 = OpPhi %float %2164 %2134 %2184 %2127 + OpBranch %2118 + %2119 = OpLabel + %2186 = OpExtInst %float %1 Log %float_0_00499999989 + %2187 = OpFDiv %float %2186 %1091 + OpBranch %2118 + %2118 = OpLabel + %2188 = OpPhi %float %2185 %2126 %2187 %2119 + %2189 = OpExtInst %float %1 Pow %float_10 %2188 + %2190 = OpCompositeInsert %v3float %2189 %2111 2 + %2191 = OpVectorTimesMatrix %v3float %2190 %602 + %2192 = OpFMul %v3float %2191 %519 + %2193 = OpExtInst %v3float %1 Pow %2192 %286 + %2194 = OpFMul %v3float %196 %2193 + %2195 = OpFAdd %v3float %195 %2194 + %2196 = OpFMul %v3float %197 %2193 + %2197 = OpFAdd %v3float %141 %2196 + %2198 = OpFDiv %v3float %141 %2197 + %2199 = OpFMul %v3float %2195 %2198 + %2200 = OpExtInst %v3float %1 Pow %2199 %287 + OpBranch %1342 + %1342 = OpLabel + %2201 = OpPhi %v3float %1366 %1346 %2200 %2118 + OpBranch %1336 + %1337 = OpLabel + %2202 = OpMatrixTimesMatrix %mat3v3float %572 %423 + %2203 = OpFMul %v3float %932 %285 + %2204 = OpVectorTimesMatrix %v3float %2203 %2202 + %2205 = OpCompositeExtract %float %2204 0 + %2206 = OpCompositeExtract %float %2204 1 + %2207 = OpExtInst %float %1 FMin %2205 %2206 + %2208 = OpCompositeExtract %float %2204 2 + %2209 = OpExtInst %float %1 FMin %2207 %2208 + %2210 = OpExtInst %float %1 FMax %2205 %2206 + %2211 = OpExtInst %float %1 FMax %2210 %2208 + %2212 = OpExtInst %float %1 FMax %2211 %float_1_00000001en10 + %2213 = OpExtInst %float %1 FMax %2209 %float_1_00000001en10 + %2214 = OpFSub %float %2212 %2213 + %2215 = OpExtInst %float %1 FMax %2211 %float_0_00999999978 + %2216 = OpFDiv %float %2214 %2215 + %2217 = OpFSub %float %2208 %2206 + %2218 = OpFMul %float %2208 %2217 + %2219 = OpFSub %float %2206 %2205 + %2220 = OpFMul %float %2206 %2219 + %2221 = OpFAdd %float %2218 %2220 + %2222 = OpFSub %float %2205 %2208 + %2223 = OpFMul %float %2205 %2222 + %2224 = OpFAdd %float %2221 %2223 + %2225 = OpExtInst %float %1 Sqrt %2224 + %2226 = OpFAdd %float %2208 %2206 + %2227 = OpFAdd %float %2226 %2205 + %2228 = OpFMul %float %float_1_75 %2225 + %2229 = OpFAdd %float %2227 %2228 + %2230 = OpFMul %float %2229 %float_0_333333343 + %2231 = OpFSub %float %2216 %float_0_400000006 + %2232 = OpFMul %float %2231 %float_5 + %2233 = OpFMul %float %2231 %float_2_5 + %2234 = OpExtInst %float %1 FAbs %2233 + %2235 = OpFSub %float %float_1 %2234 + %2236 = OpExtInst %float %1 FMax %2235 %float_0 + %2237 = OpExtInst %float %1 FSign %2232 + %2238 = OpConvertFToS %int %2237 + %2239 = OpConvertSToF %float %2238 + %2240 = OpFMul %float %2236 %2236 + %2241 = OpFSub %float %float_1 %2240 + %2242 = OpFMul %float %2239 %2241 + %2243 = OpFAdd %float %float_1 %2242 + %2244 = OpFMul %float %2243 %float_0_0250000004 + %2245 = OpFOrdLessThanEqual %bool %2230 %float_0_0533333346 + OpSelectionMerge %2246 None + OpBranchConditional %2245 %2247 %2248 + %2248 = OpLabel + %2249 = OpFOrdGreaterThanEqual %bool %2230 %float_0_159999996 + OpSelectionMerge %2250 None + OpBranchConditional %2249 %2251 %2252 + %2252 = OpLabel + %2253 = OpFDiv %float %float_0_239999995 %2229 + %2254 = OpFSub %float %2253 %float_0_5 + %2255 = OpFMul %float %2244 %2254 + OpBranch %2250 + %2251 = OpLabel + OpBranch %2250 + %2250 = OpLabel + %2256 = OpPhi %float %2255 %2252 %float_0 %2251 + OpBranch %2246 + %2247 = OpLabel + OpBranch %2246 + %2246 = OpLabel + %2257 = OpPhi %float %2256 %2250 %2244 %2247 + %2258 = OpFAdd %float %float_1 %2257 + %2259 = OpCompositeConstruct %v3float %2258 %2258 %2258 + %2260 = OpFMul %v3float %2204 %2259 + %2261 = OpCompositeExtract %float %2260 0 + %2262 = OpCompositeExtract %float %2260 1 + %2263 = OpFOrdEqual %bool %2261 %2262 + %2264 = OpCompositeExtract %float %2260 2 + %2265 = OpFOrdEqual %bool %2262 %2264 + %2266 = OpLogicalAnd %bool %2263 %2265 + OpSelectionMerge %2267 None + OpBranchConditional %2266 %2268 %2269 + %2269 = OpLabel + %2270 = OpExtInst %float %1 Sqrt %float_3 + %2271 = OpFSub %float %2262 %2264 + %2272 = OpFMul %float %2270 %2271 + %2273 = OpFMul %float %float_2 %2261 + %2274 = OpFSub %float %2273 %2262 + %2275 = OpFSub %float %2274 %2264 + %2276 = OpExtInst %float %1 Atan2 %2272 %2275 + %2277 = OpFMul %float %float_57_2957764 %2276 + OpBranch %2267 + %2268 = OpLabel + OpBranch %2267 + %2267 = OpLabel + %2278 = OpPhi %float %2277 %2269 %float_0 %2268 + %2279 = OpFOrdLessThan %bool %2278 %float_0 + OpSelectionMerge %2280 None + OpBranchConditional %2279 %2281 %2280 + %2281 = OpLabel + %2282 = OpFAdd %float %2278 %float_360 + OpBranch %2280 + %2280 = OpLabel + %2283 = OpPhi %float %2278 %2267 %2282 %2281 + %2284 = OpExtInst %float %1 FClamp %2283 %float_0 %float_360 + %2285 = OpFOrdGreaterThan %bool %2284 %float_180 + OpSelectionMerge %2286 None + OpBranchConditional %2285 %2287 %2286 + %2287 = OpLabel + %2288 = OpFSub %float %2284 %float_360 + OpBranch %2286 + %2286 = OpLabel + %2289 = OpPhi %float %2284 %2280 %2288 %2287 + %2290 = OpFOrdGreaterThan %bool %2289 %float_n67_5 + %2291 = OpFOrdLessThan %bool %2289 %float_67_5 + %2292 = OpLogicalAnd %bool %2290 %2291 + OpSelectionMerge %2293 None + OpBranchConditional %2292 %2294 %2293 + %2294 = OpLabel + %2295 = OpFSub %float %2289 %float_n67_5 + %2296 = OpFMul %float %2295 %float_0_0296296291 + %2297 = OpConvertFToS %int %2296 + %2298 = OpConvertSToF %float %2297 + %2299 = OpFSub %float %2296 %2298 + %2300 = OpFMul %float %2299 %2299 + %2301 = OpFMul %float %2300 %2299 + %2302 = OpIEqual %bool %2297 %int_3 + OpSelectionMerge %2303 None + OpBranchConditional %2302 %2304 %2305 + %2305 = OpLabel + %2306 = OpIEqual %bool %2297 %int_2 + OpSelectionMerge %2307 None + OpBranchConditional %2306 %2308 %2309 + %2309 = OpLabel + %2310 = OpIEqual %bool %2297 %int_1 + OpSelectionMerge %2311 None + OpBranchConditional %2310 %2312 %2313 + %2313 = OpLabel + %2314 = OpIEqual %bool %2297 %int_0 + OpSelectionMerge %2315 None + OpBranchConditional %2314 %2316 %2317 + %2317 = OpLabel + OpBranch %2315 + %2316 = OpLabel + %2318 = OpFMul %float %2301 %float_0_166666672 + OpBranch %2315 + %2315 = OpLabel + %2319 = OpPhi %float %float_0 %2317 %2318 %2316 + OpBranch %2311 + %2312 = OpLabel + %2320 = OpFMul %float %2301 %float_n0_5 + %2321 = OpFMul %float %2300 %float_0_5 + %2322 = OpFAdd %float %2320 %2321 + %2323 = OpFMul %float %2299 %float_0_5 + %2324 = OpFAdd %float %2322 %2323 + %2325 = OpFAdd %float %2324 %float_0_166666672 + OpBranch %2311 + %2311 = OpLabel + %2326 = OpPhi %float %2319 %2315 %2325 %2312 + OpBranch %2307 + %2308 = OpLabel + %2327 = OpFMul %float %2301 %float_0_5 + %2328 = OpFMul %float %2300 %float_n1 + %2329 = OpFAdd %float %2327 %2328 + %2330 = OpFAdd %float %2329 %float_0_666666687 + OpBranch %2307 + %2307 = OpLabel + %2331 = OpPhi %float %2326 %2311 %2330 %2308 + OpBranch %2303 + %2304 = OpLabel + %2332 = OpFMul %float %2301 %float_n0_166666672 + %2333 = OpFMul %float %2300 %float_0_5 + %2334 = OpFAdd %float %2332 %2333 + %2335 = OpFMul %float %2299 %float_n0_5 + %2336 = OpFAdd %float %2334 %2335 + %2337 = OpFAdd %float %2336 %float_0_166666672 + OpBranch %2303 + %2303 = OpLabel + %2338 = OpPhi %float %2331 %2307 %2337 %2304 + OpBranch %2293 + %2293 = OpLabel + %2339 = OpPhi %float %float_0 %2286 %2338 %2303 + %2340 = OpFMul %float %2339 %float_1_5 + %2341 = OpFMul %float %2340 %2216 + %2342 = OpFSub %float %float_0_0299999993 %2261 + %2343 = OpFMul %float %2341 %2342 + %2344 = OpFMul %float %2343 %float_0_180000007 + %2345 = OpFAdd %float %2261 %2344 + %2346 = OpCompositeInsert %v3float %2345 %2260 0 + %2347 = OpExtInst %v3float %1 FClamp %2346 %138 %337 + %2348 = OpVectorTimesMatrix %v3float %2347 %434 + %2349 = OpExtInst %v3float %1 FClamp %2348 %138 %337 + %2350 = OpDot %float %2349 %73 + %2351 = OpCompositeConstruct %v3float %2350 %2350 %2350 + %2352 = OpExtInst %v3float %1 FMix %2351 %2349 %241 + %2353 = OpCompositeExtract %float %2352 0 + %2354 = OpExtInst %float %1 Exp2 %float_n15 + %2355 = OpFMul %float %float_0_179999992 %2354 + %2356 = OpExtInst %float %1 Exp2 %float_18 + %2357 = OpFMul %float %float_0_179999992 %2356 + OpStore %546 %499 + OpStore %545 %500 + %2358 = OpFOrdLessThanEqual %bool %2353 %float_0 + %2359 = OpExtInst %float %1 Exp2 %float_n14 + %2360 = OpSelect %float %2358 %2359 %2353 + %2361 = OpExtInst %float %1 Log %2360 + %2362 = OpFDiv %float %2361 %1091 + %2363 = OpExtInst %float %1 Log %2355 + %2364 = OpFDiv %float %2363 %1091 + %2365 = OpFOrdLessThanEqual %bool %2362 %2364 + OpSelectionMerge %2366 None + OpBranchConditional %2365 %2367 %2368 + %2368 = OpLabel + %2369 = OpFOrdGreaterThan %bool %2362 %2364 + %2370 = OpExtInst %float %1 Log %float_0_180000007 + %2371 = OpFDiv %float %2370 %1091 + %2372 = OpFOrdLessThan %bool %2362 %2371 + %2373 = OpLogicalAnd %bool %2369 %2372 + OpSelectionMerge %2374 None + OpBranchConditional %2373 %2375 %2376 + %2376 = OpLabel + %2377 = OpFOrdGreaterThanEqual %bool %2362 %2371 + %2378 = OpExtInst %float %1 Log %2357 + %2379 = OpFDiv %float %2378 %1091 + %2380 = OpFOrdLessThan %bool %2362 %2379 + %2381 = OpLogicalAnd %bool %2377 %2380 + OpSelectionMerge %2382 None + OpBranchConditional %2381 %2383 %2384 + %2384 = OpLabel + %2385 = OpExtInst %float %1 Log %float_10000 + %2386 = OpFDiv %float %2385 %1091 + OpBranch %2382 + %2383 = OpLabel + %2387 = OpFSub %float %2362 %2371 + %2388 = OpFMul %float %float_3 %2387 + %2389 = OpFSub %float %2379 %2371 + %2390 = OpFDiv %float %2388 %2389 + %2391 = OpConvertFToS %int %2390 + %2392 = OpConvertSToF %float %2391 + %2393 = OpFSub %float %2390 %2392 + %2394 = OpAccessChain %_ptr_Function_float %545 %2391 + %2395 = OpLoad %float %2394 + %2396 = OpIAdd %int %2391 %int_1 + %2397 = OpAccessChain %_ptr_Function_float %545 %2396 + %2398 = OpLoad %float %2397 + %2399 = OpIAdd %int %2391 %int_2 + %2400 = OpAccessChain %_ptr_Function_float %545 %2399 + %2401 = OpLoad %float %2400 + %2402 = OpCompositeConstruct %v3float %2395 %2398 %2401 + %2403 = OpFMul %float %2393 %2393 + %2404 = OpCompositeConstruct %v3float %2403 %2393 %float_1 + %2405 = OpMatrixTimesVector %v3float %466 %2402 + %2406 = OpDot %float %2404 %2405 + OpBranch %2382 + %2382 = OpLabel + %2407 = OpPhi %float %2386 %2384 %2406 %2383 + OpBranch %2374 + %2375 = OpLabel + %2408 = OpFSub %float %2362 %2364 + %2409 = OpFMul %float %float_3 %2408 + %2410 = OpFSub %float %2371 %2364 + %2411 = OpFDiv %float %2409 %2410 + %2412 = OpConvertFToS %int %2411 + %2413 = OpConvertSToF %float %2412 + %2414 = OpFSub %float %2411 %2413 + %2415 = OpAccessChain %_ptr_Function_float %546 %2412 + %2416 = OpLoad %float %2415 + %2417 = OpIAdd %int %2412 %int_1 + %2418 = OpAccessChain %_ptr_Function_float %546 %2417 + %2419 = OpLoad %float %2418 + %2420 = OpIAdd %int %2412 %int_2 + %2421 = OpAccessChain %_ptr_Function_float %546 %2420 + %2422 = OpLoad %float %2421 + %2423 = OpCompositeConstruct %v3float %2416 %2419 %2422 + %2424 = OpFMul %float %2414 %2414 + %2425 = OpCompositeConstruct %v3float %2424 %2414 %float_1 + %2426 = OpMatrixTimesVector %v3float %466 %2423 + %2427 = OpDot %float %2425 %2426 + OpBranch %2374 + %2374 = OpLabel + %2428 = OpPhi %float %2407 %2382 %2427 %2375 + OpBranch %2366 + %2367 = OpLabel + %2429 = OpExtInst %float %1 Log %float_9_99999975en05 + %2430 = OpFDiv %float %2429 %1091 + OpBranch %2366 + %2366 = OpLabel + %2431 = OpPhi %float %2428 %2374 %2430 %2367 + %2432 = OpExtInst %float %1 Pow %float_10 %2431 + %2433 = OpCompositeInsert %v3float %2432 %523 0 + %2434 = OpCompositeExtract %float %2352 1 + OpStore %548 %499 + OpStore %547 %500 + %2435 = OpFOrdLessThanEqual %bool %2434 %float_0 + %2436 = OpSelect %float %2435 %2359 %2434 + %2437 = OpExtInst %float %1 Log %2436 + %2438 = OpFDiv %float %2437 %1091 + %2439 = OpFOrdLessThanEqual %bool %2438 %2364 + OpSelectionMerge %2440 None + OpBranchConditional %2439 %2441 %2442 + %2442 = OpLabel + %2443 = OpFOrdGreaterThan %bool %2438 %2364 + %2444 = OpExtInst %float %1 Log %float_0_180000007 + %2445 = OpFDiv %float %2444 %1091 + %2446 = OpFOrdLessThan %bool %2438 %2445 + %2447 = OpLogicalAnd %bool %2443 %2446 + OpSelectionMerge %2448 None + OpBranchConditional %2447 %2449 %2450 + %2450 = OpLabel + %2451 = OpFOrdGreaterThanEqual %bool %2438 %2445 + %2452 = OpExtInst %float %1 Log %2357 + %2453 = OpFDiv %float %2452 %1091 + %2454 = OpFOrdLessThan %bool %2438 %2453 + %2455 = OpLogicalAnd %bool %2451 %2454 + OpSelectionMerge %2456 None + OpBranchConditional %2455 %2457 %2458 + %2458 = OpLabel + %2459 = OpExtInst %float %1 Log %float_10000 + %2460 = OpFDiv %float %2459 %1091 + OpBranch %2456 + %2457 = OpLabel + %2461 = OpFSub %float %2438 %2445 + %2462 = OpFMul %float %float_3 %2461 + %2463 = OpFSub %float %2453 %2445 + %2464 = OpFDiv %float %2462 %2463 + %2465 = OpConvertFToS %int %2464 + %2466 = OpConvertSToF %float %2465 + %2467 = OpFSub %float %2464 %2466 + %2468 = OpAccessChain %_ptr_Function_float %547 %2465 + %2469 = OpLoad %float %2468 + %2470 = OpIAdd %int %2465 %int_1 + %2471 = OpAccessChain %_ptr_Function_float %547 %2470 + %2472 = OpLoad %float %2471 + %2473 = OpIAdd %int %2465 %int_2 + %2474 = OpAccessChain %_ptr_Function_float %547 %2473 + %2475 = OpLoad %float %2474 + %2476 = OpCompositeConstruct %v3float %2469 %2472 %2475 + %2477 = OpFMul %float %2467 %2467 + %2478 = OpCompositeConstruct %v3float %2477 %2467 %float_1 + %2479 = OpMatrixTimesVector %v3float %466 %2476 + %2480 = OpDot %float %2478 %2479 + OpBranch %2456 + %2456 = OpLabel + %2481 = OpPhi %float %2460 %2458 %2480 %2457 + OpBranch %2448 + %2449 = OpLabel + %2482 = OpFSub %float %2438 %2364 + %2483 = OpFMul %float %float_3 %2482 + %2484 = OpFSub %float %2445 %2364 + %2485 = OpFDiv %float %2483 %2484 + %2486 = OpConvertFToS %int %2485 + %2487 = OpConvertSToF %float %2486 + %2488 = OpFSub %float %2485 %2487 + %2489 = OpAccessChain %_ptr_Function_float %548 %2486 + %2490 = OpLoad %float %2489 + %2491 = OpIAdd %int %2486 %int_1 + %2492 = OpAccessChain %_ptr_Function_float %548 %2491 + %2493 = OpLoad %float %2492 + %2494 = OpIAdd %int %2486 %int_2 + %2495 = OpAccessChain %_ptr_Function_float %548 %2494 + %2496 = OpLoad %float %2495 + %2497 = OpCompositeConstruct %v3float %2490 %2493 %2496 + %2498 = OpFMul %float %2488 %2488 + %2499 = OpCompositeConstruct %v3float %2498 %2488 %float_1 + %2500 = OpMatrixTimesVector %v3float %466 %2497 + %2501 = OpDot %float %2499 %2500 + OpBranch %2448 + %2448 = OpLabel + %2502 = OpPhi %float %2481 %2456 %2501 %2449 + OpBranch %2440 + %2441 = OpLabel + %2503 = OpExtInst %float %1 Log %float_9_99999975en05 + %2504 = OpFDiv %float %2503 %1091 + OpBranch %2440 + %2440 = OpLabel + %2505 = OpPhi %float %2502 %2448 %2504 %2441 + %2506 = OpExtInst %float %1 Pow %float_10 %2505 + %2507 = OpCompositeInsert %v3float %2506 %2433 1 + %2508 = OpCompositeExtract %float %2352 2 + OpStore %550 %499 + OpStore %549 %500 + %2509 = OpFOrdLessThanEqual %bool %2508 %float_0 + %2510 = OpSelect %float %2509 %2359 %2508 + %2511 = OpExtInst %float %1 Log %2510 + %2512 = OpFDiv %float %2511 %1091 + %2513 = OpFOrdLessThanEqual %bool %2512 %2364 + OpSelectionMerge %2514 None + OpBranchConditional %2513 %2515 %2516 + %2516 = OpLabel + %2517 = OpFOrdGreaterThan %bool %2512 %2364 + %2518 = OpExtInst %float %1 Log %float_0_180000007 + %2519 = OpFDiv %float %2518 %1091 + %2520 = OpFOrdLessThan %bool %2512 %2519 + %2521 = OpLogicalAnd %bool %2517 %2520 + OpSelectionMerge %2522 None + OpBranchConditional %2521 %2523 %2524 + %2524 = OpLabel + %2525 = OpFOrdGreaterThanEqual %bool %2512 %2519 + %2526 = OpExtInst %float %1 Log %2357 + %2527 = OpFDiv %float %2526 %1091 + %2528 = OpFOrdLessThan %bool %2512 %2527 + %2529 = OpLogicalAnd %bool %2525 %2528 + OpSelectionMerge %2530 None + OpBranchConditional %2529 %2531 %2532 + %2532 = OpLabel + %2533 = OpExtInst %float %1 Log %float_10000 + %2534 = OpFDiv %float %2533 %1091 + OpBranch %2530 + %2531 = OpLabel + %2535 = OpFSub %float %2512 %2519 + %2536 = OpFMul %float %float_3 %2535 + %2537 = OpFSub %float %2527 %2519 + %2538 = OpFDiv %float %2536 %2537 + %2539 = OpConvertFToS %int %2538 + %2540 = OpConvertSToF %float %2539 + %2541 = OpFSub %float %2538 %2540 + %2542 = OpAccessChain %_ptr_Function_float %549 %2539 + %2543 = OpLoad %float %2542 + %2544 = OpIAdd %int %2539 %int_1 + %2545 = OpAccessChain %_ptr_Function_float %549 %2544 + %2546 = OpLoad %float %2545 + %2547 = OpIAdd %int %2539 %int_2 + %2548 = OpAccessChain %_ptr_Function_float %549 %2547 + %2549 = OpLoad %float %2548 + %2550 = OpCompositeConstruct %v3float %2543 %2546 %2549 + %2551 = OpFMul %float %2541 %2541 + %2552 = OpCompositeConstruct %v3float %2551 %2541 %float_1 + %2553 = OpMatrixTimesVector %v3float %466 %2550 + %2554 = OpDot %float %2552 %2553 + OpBranch %2530 + %2530 = OpLabel + %2555 = OpPhi %float %2534 %2532 %2554 %2531 + OpBranch %2522 + %2523 = OpLabel + %2556 = OpFSub %float %2512 %2364 + %2557 = OpFMul %float %float_3 %2556 + %2558 = OpFSub %float %2519 %2364 + %2559 = OpFDiv %float %2557 %2558 + %2560 = OpConvertFToS %int %2559 + %2561 = OpConvertSToF %float %2560 + %2562 = OpFSub %float %2559 %2561 + %2563 = OpAccessChain %_ptr_Function_float %550 %2560 + %2564 = OpLoad %float %2563 + %2565 = OpIAdd %int %2560 %int_1 + %2566 = OpAccessChain %_ptr_Function_float %550 %2565 + %2567 = OpLoad %float %2566 + %2568 = OpIAdd %int %2560 %int_2 + %2569 = OpAccessChain %_ptr_Function_float %550 %2568 + %2570 = OpLoad %float %2569 + %2571 = OpCompositeConstruct %v3float %2564 %2567 %2570 + %2572 = OpFMul %float %2562 %2562 + %2573 = OpCompositeConstruct %v3float %2572 %2562 %float_1 + %2574 = OpMatrixTimesVector %v3float %466 %2571 + %2575 = OpDot %float %2573 %2574 + OpBranch %2522 + %2522 = OpLabel + %2576 = OpPhi %float %2555 %2530 %2575 %2523 + OpBranch %2514 + %2515 = OpLabel + %2577 = OpExtInst %float %1 Log %float_9_99999975en05 + %2578 = OpFDiv %float %2577 %1091 + OpBranch %2514 + %2514 = OpLabel + %2579 = OpPhi %float %2576 %2522 %2578 %2515 + %2580 = OpExtInst %float %1 Pow %float_10 %2579 + %2581 = OpCompositeInsert %v3float %2580 %2507 2 + %2582 = OpVectorTimesMatrix %v3float %2581 %438 + %2583 = OpVectorTimesMatrix %v3float %2582 %434 + %2584 = OpExtInst %float %1 Pow %float_2 %float_n12 + %2585 = OpFMul %float %float_0_179999992 %2584 + OpStore %558 %499 + OpStore %557 %500 + %2586 = OpFOrdLessThanEqual %bool %2585 %float_0 + %2587 = OpSelect %float %2586 %2359 %2585 + %2588 = OpExtInst %float %1 Log %2587 + %2589 = OpFDiv %float %2588 %1091 + %2590 = OpFOrdLessThanEqual %bool %2589 %2364 + OpSelectionMerge %2591 None + OpBranchConditional %2590 %2592 %2593 + %2593 = OpLabel + %2594 = OpFOrdGreaterThan %bool %2589 %2364 + %2595 = OpExtInst %float %1 Log %float_0_180000007 + %2596 = OpFDiv %float %2595 %1091 + %2597 = OpFOrdLessThan %bool %2589 %2596 + %2598 = OpLogicalAnd %bool %2594 %2597 + OpSelectionMerge %2599 None + OpBranchConditional %2598 %2600 %2601 + %2601 = OpLabel + %2602 = OpFOrdGreaterThanEqual %bool %2589 %2596 + %2603 = OpExtInst %float %1 Log %2357 + %2604 = OpFDiv %float %2603 %1091 + %2605 = OpFOrdLessThan %bool %2589 %2604 + %2606 = OpLogicalAnd %bool %2602 %2605 + OpSelectionMerge %2607 None + OpBranchConditional %2606 %2608 %2609 + %2609 = OpLabel + %2610 = OpExtInst %float %1 Log %float_10000 + %2611 = OpFDiv %float %2610 %1091 + OpBranch %2607 + %2608 = OpLabel + %2612 = OpFSub %float %2589 %2596 + %2613 = OpFMul %float %float_3 %2612 + %2614 = OpFSub %float %2604 %2596 + %2615 = OpFDiv %float %2613 %2614 + %2616 = OpConvertFToS %int %2615 + %2617 = OpConvertSToF %float %2616 + %2618 = OpFSub %float %2615 %2617 + %2619 = OpAccessChain %_ptr_Function_float %557 %2616 + %2620 = OpLoad %float %2619 + %2621 = OpIAdd %int %2616 %int_1 + %2622 = OpAccessChain %_ptr_Function_float %557 %2621 + %2623 = OpLoad %float %2622 + %2624 = OpIAdd %int %2616 %int_2 + %2625 = OpAccessChain %_ptr_Function_float %557 %2624 + %2626 = OpLoad %float %2625 + %2627 = OpCompositeConstruct %v3float %2620 %2623 %2626 + %2628 = OpFMul %float %2618 %2618 + %2629 = OpCompositeConstruct %v3float %2628 %2618 %float_1 + %2630 = OpMatrixTimesVector %v3float %466 %2627 + %2631 = OpDot %float %2629 %2630 + OpBranch %2607 + %2607 = OpLabel + %2632 = OpPhi %float %2611 %2609 %2631 %2608 + OpBranch %2599 + %2600 = OpLabel + %2633 = OpFSub %float %2589 %2364 + %2634 = OpFMul %float %float_3 %2633 + %2635 = OpFSub %float %2596 %2364 + %2636 = OpFDiv %float %2634 %2635 + %2637 = OpConvertFToS %int %2636 + %2638 = OpConvertSToF %float %2637 + %2639 = OpFSub %float %2636 %2638 + %2640 = OpAccessChain %_ptr_Function_float %558 %2637 + %2641 = OpLoad %float %2640 + %2642 = OpIAdd %int %2637 %int_1 + %2643 = OpAccessChain %_ptr_Function_float %558 %2642 + %2644 = OpLoad %float %2643 + %2645 = OpIAdd %int %2637 %int_2 + %2646 = OpAccessChain %_ptr_Function_float %558 %2645 + %2647 = OpLoad %float %2646 + %2648 = OpCompositeConstruct %v3float %2641 %2644 %2647 + %2649 = OpFMul %float %2639 %2639 + %2650 = OpCompositeConstruct %v3float %2649 %2639 %float_1 + %2651 = OpMatrixTimesVector %v3float %466 %2648 + %2652 = OpDot %float %2650 %2651 + OpBranch %2599 + %2599 = OpLabel + %2653 = OpPhi %float %2632 %2607 %2652 %2600 + OpBranch %2591 + %2592 = OpLabel + %2654 = OpExtInst %float %1 Log %float_9_99999975en05 + %2655 = OpFDiv %float %2654 %1091 + OpBranch %2591 + %2591 = OpLabel + %2656 = OpPhi %float %2653 %2599 %2655 %2592 + %2657 = OpExtInst %float %1 Pow %float_10 %2656 + OpStore %560 %499 + OpStore %559 %500 + %2658 = OpExtInst %float %1 Log %float_0_180000007 + %2659 = OpFDiv %float %2658 %1091 + %2660 = OpFOrdLessThanEqual %bool %2659 %2364 + OpSelectionMerge %2661 None + OpBranchConditional %2660 %2662 %2663 + %2663 = OpLabel + %2664 = OpFOrdGreaterThan %bool %2659 %2364 + %2665 = OpFOrdLessThan %bool %2659 %2659 + %2666 = OpLogicalAnd %bool %2664 %2665 + OpSelectionMerge %2667 None + OpBranchConditional %2666 %2668 %2669 + %2669 = OpLabel + %2670 = OpFOrdGreaterThanEqual %bool %2659 %2659 + %2671 = OpExtInst %float %1 Log %2357 + %2672 = OpFDiv %float %2671 %1091 + %2673 = OpFOrdLessThan %bool %2659 %2672 + %2674 = OpLogicalAnd %bool %2670 %2673 + OpSelectionMerge %2675 None + OpBranchConditional %2674 %2676 %2677 + %2677 = OpLabel + %2678 = OpExtInst %float %1 Log %float_10000 + %2679 = OpFDiv %float %2678 %1091 + OpBranch %2675 + %2676 = OpLabel + %2680 = OpFSub %float %2659 %2659 + %2681 = OpFMul %float %float_3 %2680 + %2682 = OpFSub %float %2672 %2659 + %2683 = OpFDiv %float %2681 %2682 + %2684 = OpConvertFToS %int %2683 + %2685 = OpConvertSToF %float %2684 + %2686 = OpFSub %float %2683 %2685 + %2687 = OpAccessChain %_ptr_Function_float %559 %2684 + %2688 = OpLoad %float %2687 + %2689 = OpIAdd %int %2684 %int_1 + %2690 = OpAccessChain %_ptr_Function_float %559 %2689 + %2691 = OpLoad %float %2690 + %2692 = OpIAdd %int %2684 %int_2 + %2693 = OpAccessChain %_ptr_Function_float %559 %2692 + %2694 = OpLoad %float %2693 + %2695 = OpCompositeConstruct %v3float %2688 %2691 %2694 + %2696 = OpFMul %float %2686 %2686 + %2697 = OpCompositeConstruct %v3float %2696 %2686 %float_1 + %2698 = OpMatrixTimesVector %v3float %466 %2695 + %2699 = OpDot %float %2697 %2698 + OpBranch %2675 + %2675 = OpLabel + %2700 = OpPhi %float %2679 %2677 %2699 %2676 + OpBranch %2667 + %2668 = OpLabel + %2701 = OpAccessChain %_ptr_Function_float %560 %int_3 + %2702 = OpLoad %float %2701 + %2703 = OpAccessChain %_ptr_Function_float %560 %int_4 + %2704 = OpLoad %float %2703 + %2705 = OpAccessChain %_ptr_Function_float %560 %int_5 + %2706 = OpLoad %float %2705 + %2707 = OpCompositeConstruct %v3float %2702 %2704 %2706 + %2708 = OpMatrixTimesVector %v3float %466 %2707 + %2709 = OpCompositeExtract %float %2708 2 + OpBranch %2667 + %2667 = OpLabel + %2710 = OpPhi %float %2700 %2675 %2709 %2668 + OpBranch %2661 + %2662 = OpLabel + %2711 = OpExtInst %float %1 Log %float_9_99999975en05 + %2712 = OpFDiv %float %2711 %1091 + OpBranch %2661 + %2661 = OpLabel + %2713 = OpPhi %float %2710 %2667 %2712 %2662 + %2714 = OpExtInst %float %1 Pow %float_10 %2713 + %2715 = OpExtInst %float %1 Pow %float_2 %float_10 + %2716 = OpFMul %float %float_0_179999992 %2715 + OpStore %562 %499 + OpStore %561 %500 + %2717 = OpFOrdLessThanEqual %bool %2716 %float_0 + %2718 = OpSelect %float %2717 %2359 %2716 + %2719 = OpExtInst %float %1 Log %2718 + %2720 = OpFDiv %float %2719 %1091 + %2721 = OpFOrdLessThanEqual %bool %2720 %2364 + OpSelectionMerge %2722 None + OpBranchConditional %2721 %2723 %2724 + %2724 = OpLabel + %2725 = OpFOrdGreaterThan %bool %2720 %2364 + %2726 = OpFOrdLessThan %bool %2720 %2659 + %2727 = OpLogicalAnd %bool %2725 %2726 + OpSelectionMerge %2728 None + OpBranchConditional %2727 %2729 %2730 + %2730 = OpLabel + %2731 = OpFOrdGreaterThanEqual %bool %2720 %2659 + %2732 = OpExtInst %float %1 Log %2357 + %2733 = OpFDiv %float %2732 %1091 + %2734 = OpFOrdLessThan %bool %2720 %2733 + %2735 = OpLogicalAnd %bool %2731 %2734 + OpSelectionMerge %2736 None + OpBranchConditional %2735 %2737 %2738 + %2738 = OpLabel + %2739 = OpExtInst %float %1 Log %float_10000 + %2740 = OpFDiv %float %2739 %1091 + OpBranch %2736 + %2737 = OpLabel + %2741 = OpFSub %float %2720 %2659 + %2742 = OpFMul %float %float_3 %2741 + %2743 = OpFSub %float %2733 %2659 + %2744 = OpFDiv %float %2742 %2743 + %2745 = OpConvertFToS %int %2744 + %2746 = OpConvertSToF %float %2745 + %2747 = OpFSub %float %2744 %2746 + %2748 = OpAccessChain %_ptr_Function_float %561 %2745 + %2749 = OpLoad %float %2748 + %2750 = OpIAdd %int %2745 %int_1 + %2751 = OpAccessChain %_ptr_Function_float %561 %2750 + %2752 = OpLoad %float %2751 + %2753 = OpIAdd %int %2745 %int_2 + %2754 = OpAccessChain %_ptr_Function_float %561 %2753 + %2755 = OpLoad %float %2754 + %2756 = OpCompositeConstruct %v3float %2749 %2752 %2755 + %2757 = OpFMul %float %2747 %2747 + %2758 = OpCompositeConstruct %v3float %2757 %2747 %float_1 + %2759 = OpMatrixTimesVector %v3float %466 %2756 + %2760 = OpDot %float %2758 %2759 + OpBranch %2736 + %2736 = OpLabel + %2761 = OpPhi %float %2740 %2738 %2760 %2737 + OpBranch %2728 + %2729 = OpLabel + %2762 = OpFSub %float %2720 %2364 + %2763 = OpFMul %float %float_3 %2762 + %2764 = OpFSub %float %2659 %2364 + %2765 = OpFDiv %float %2763 %2764 + %2766 = OpConvertFToS %int %2765 + %2767 = OpConvertSToF %float %2766 + %2768 = OpFSub %float %2765 %2767 + %2769 = OpAccessChain %_ptr_Function_float %562 %2766 + %2770 = OpLoad %float %2769 + %2771 = OpIAdd %int %2766 %int_1 + %2772 = OpAccessChain %_ptr_Function_float %562 %2771 + %2773 = OpLoad %float %2772 + %2774 = OpIAdd %int %2766 %int_2 + %2775 = OpAccessChain %_ptr_Function_float %562 %2774 + %2776 = OpLoad %float %2775 + %2777 = OpCompositeConstruct %v3float %2770 %2773 %2776 + %2778 = OpFMul %float %2768 %2768 + %2779 = OpCompositeConstruct %v3float %2778 %2768 %float_1 + %2780 = OpMatrixTimesVector %v3float %466 %2777 + %2781 = OpDot %float %2779 %2780 + OpBranch %2728 + %2728 = OpLabel + %2782 = OpPhi %float %2761 %2736 %2781 %2729 + OpBranch %2722 + %2723 = OpLabel + %2783 = OpExtInst %float %1 Log %float_9_99999975en05 + %2784 = OpFDiv %float %2783 %1091 + OpBranch %2722 + %2722 = OpLabel + %2785 = OpPhi %float %2782 %2728 %2784 %2723 + %2786 = OpExtInst %float %1 Pow %float_10 %2785 + %2787 = OpCompositeExtract %float %2583 0 + OpStore %556 %503 + OpStore %555 %504 + %2788 = OpFOrdLessThanEqual %bool %2787 %float_0 + %2789 = OpSelect %float %2788 %float_9_99999975en05 %2787 + %2790 = OpExtInst %float %1 Log %2789 + %2791 = OpFDiv %float %2790 %1091 + %2792 = OpExtInst %float %1 Log %2657 + %2793 = OpFDiv %float %2792 %1091 + %2794 = OpFOrdLessThanEqual %bool %2791 %2793 + OpSelectionMerge %2795 None + OpBranchConditional %2794 %2796 %2797 + %2797 = OpLabel + %2798 = OpFOrdGreaterThan %bool %2791 %2793 + %2799 = OpExtInst %float %1 Log %2714 + %2800 = OpFDiv %float %2799 %1091 + %2801 = OpFOrdLessThan %bool %2791 %2800 + %2802 = OpLogicalAnd %bool %2798 %2801 + OpSelectionMerge %2803 None + OpBranchConditional %2802 %2804 %2805 + %2805 = OpLabel + %2806 = OpFOrdGreaterThanEqual %bool %2791 %2800 + %2807 = OpExtInst %float %1 Log %2786 + %2808 = OpFDiv %float %2807 %1091 + %2809 = OpFOrdLessThan %bool %2791 %2808 + %2810 = OpLogicalAnd %bool %2806 %2809 + OpSelectionMerge %2811 None + OpBranchConditional %2810 %2812 %2813 + %2813 = OpLabel + %2814 = OpFMul %float %2791 %float_0_0599999987 + %2815 = OpExtInst %float %1 Log %float_1000 + %2816 = OpFDiv %float %2815 %1091 + %2817 = OpFMul %float %float_0_0599999987 %2807 + %2818 = OpFDiv %float %2817 %1091 + %2819 = OpFSub %float %2816 %2818 + %2820 = OpFAdd %float %2814 %2819 + OpBranch %2811 + %2812 = OpLabel + %2821 = OpFSub %float %2791 %2800 + %2822 = OpFMul %float %float_7 %2821 + %2823 = OpFSub %float %2808 %2800 + %2824 = OpFDiv %float %2822 %2823 + %2825 = OpConvertFToS %int %2824 + %2826 = OpConvertSToF %float %2825 + %2827 = OpFSub %float %2824 %2826 + %2828 = OpAccessChain %_ptr_Function_float %555 %2825 + %2829 = OpLoad %float %2828 + %2830 = OpIAdd %int %2825 %int_1 + %2831 = OpAccessChain %_ptr_Function_float %555 %2830 + %2832 = OpLoad %float %2831 + %2833 = OpIAdd %int %2825 %int_2 + %2834 = OpAccessChain %_ptr_Function_float %555 %2833 + %2835 = OpLoad %float %2834 + %2836 = OpCompositeConstruct %v3float %2829 %2832 %2835 + %2837 = OpFMul %float %2827 %2827 + %2838 = OpCompositeConstruct %v3float %2837 %2827 %float_1 + %2839 = OpMatrixTimesVector %v3float %466 %2836 + %2840 = OpDot %float %2838 %2839 + OpBranch %2811 + %2811 = OpLabel + %2841 = OpPhi %float %2820 %2813 %2840 %2812 + OpBranch %2803 + %2804 = OpLabel + %2842 = OpFSub %float %2791 %2793 + %2843 = OpFMul %float %float_7 %2842 + %2844 = OpFSub %float %2800 %2793 + %2845 = OpFDiv %float %2843 %2844 + %2846 = OpConvertFToS %int %2845 + %2847 = OpConvertSToF %float %2846 + %2848 = OpFSub %float %2845 %2847 + %2849 = OpAccessChain %_ptr_Function_float %556 %2846 + %2850 = OpLoad %float %2849 + %2851 = OpIAdd %int %2846 %int_1 + %2852 = OpAccessChain %_ptr_Function_float %556 %2851 + %2853 = OpLoad %float %2852 + %2854 = OpIAdd %int %2846 %int_2 + %2855 = OpAccessChain %_ptr_Function_float %556 %2854 + %2856 = OpLoad %float %2855 + %2857 = OpCompositeConstruct %v3float %2850 %2853 %2856 + %2858 = OpFMul %float %2848 %2848 + %2859 = OpCompositeConstruct %v3float %2858 %2848 %float_1 + %2860 = OpMatrixTimesVector %v3float %466 %2857 + %2861 = OpDot %float %2859 %2860 + OpBranch %2803 + %2803 = OpLabel + %2862 = OpPhi %float %2841 %2811 %2861 %2804 + OpBranch %2795 + %2796 = OpLabel + %2863 = OpFMul %float %2791 %float_3 + %2864 = OpExtInst %float %1 Log %float_9_99999975en05 + %2865 = OpFDiv %float %2864 %1091 + %2866 = OpFMul %float %float_3 %2792 + %2867 = OpFDiv %float %2866 %1091 + %2868 = OpFSub %float %2865 %2867 + %2869 = OpFAdd %float %2863 %2868 + OpBranch %2795 + %2795 = OpLabel + %2870 = OpPhi %float %2862 %2803 %2869 %2796 + %2871 = OpExtInst %float %1 Pow %float_10 %2870 + %2872 = OpCompositeInsert %v3float %2871 %523 0 + %2873 = OpCompositeExtract %float %2583 1 + OpStore %554 %503 + OpStore %553 %504 + %2874 = OpFOrdLessThanEqual %bool %2873 %float_0 + %2875 = OpSelect %float %2874 %float_9_99999975en05 %2873 + %2876 = OpExtInst %float %1 Log %2875 + %2877 = OpFDiv %float %2876 %1091 + %2878 = OpFOrdLessThanEqual %bool %2877 %2793 + OpSelectionMerge %2879 None + OpBranchConditional %2878 %2880 %2881 + %2881 = OpLabel + %2882 = OpFOrdGreaterThan %bool %2877 %2793 + %2883 = OpExtInst %float %1 Log %2714 + %2884 = OpFDiv %float %2883 %1091 + %2885 = OpFOrdLessThan %bool %2877 %2884 + %2886 = OpLogicalAnd %bool %2882 %2885 + OpSelectionMerge %2887 None + OpBranchConditional %2886 %2888 %2889 + %2889 = OpLabel + %2890 = OpFOrdGreaterThanEqual %bool %2877 %2884 + %2891 = OpExtInst %float %1 Log %2786 + %2892 = OpFDiv %float %2891 %1091 + %2893 = OpFOrdLessThan %bool %2877 %2892 + %2894 = OpLogicalAnd %bool %2890 %2893 + OpSelectionMerge %2895 None + OpBranchConditional %2894 %2896 %2897 + %2897 = OpLabel + %2898 = OpFMul %float %2877 %float_0_0599999987 + %2899 = OpExtInst %float %1 Log %float_1000 + %2900 = OpFDiv %float %2899 %1091 + %2901 = OpFMul %float %float_0_0599999987 %2891 + %2902 = OpFDiv %float %2901 %1091 + %2903 = OpFSub %float %2900 %2902 + %2904 = OpFAdd %float %2898 %2903 + OpBranch %2895 + %2896 = OpLabel + %2905 = OpFSub %float %2877 %2884 + %2906 = OpFMul %float %float_7 %2905 + %2907 = OpFSub %float %2892 %2884 + %2908 = OpFDiv %float %2906 %2907 + %2909 = OpConvertFToS %int %2908 + %2910 = OpConvertSToF %float %2909 + %2911 = OpFSub %float %2908 %2910 + %2912 = OpAccessChain %_ptr_Function_float %553 %2909 + %2913 = OpLoad %float %2912 + %2914 = OpIAdd %int %2909 %int_1 + %2915 = OpAccessChain %_ptr_Function_float %553 %2914 + %2916 = OpLoad %float %2915 + %2917 = OpIAdd %int %2909 %int_2 + %2918 = OpAccessChain %_ptr_Function_float %553 %2917 + %2919 = OpLoad %float %2918 + %2920 = OpCompositeConstruct %v3float %2913 %2916 %2919 + %2921 = OpFMul %float %2911 %2911 + %2922 = OpCompositeConstruct %v3float %2921 %2911 %float_1 + %2923 = OpMatrixTimesVector %v3float %466 %2920 + %2924 = OpDot %float %2922 %2923 + OpBranch %2895 + %2895 = OpLabel + %2925 = OpPhi %float %2904 %2897 %2924 %2896 + OpBranch %2887 + %2888 = OpLabel + %2926 = OpFSub %float %2877 %2793 + %2927 = OpFMul %float %float_7 %2926 + %2928 = OpFSub %float %2884 %2793 + %2929 = OpFDiv %float %2927 %2928 + %2930 = OpConvertFToS %int %2929 + %2931 = OpConvertSToF %float %2930 + %2932 = OpFSub %float %2929 %2931 + %2933 = OpAccessChain %_ptr_Function_float %554 %2930 + %2934 = OpLoad %float %2933 + %2935 = OpIAdd %int %2930 %int_1 + %2936 = OpAccessChain %_ptr_Function_float %554 %2935 + %2937 = OpLoad %float %2936 + %2938 = OpIAdd %int %2930 %int_2 + %2939 = OpAccessChain %_ptr_Function_float %554 %2938 + %2940 = OpLoad %float %2939 + %2941 = OpCompositeConstruct %v3float %2934 %2937 %2940 + %2942 = OpFMul %float %2932 %2932 + %2943 = OpCompositeConstruct %v3float %2942 %2932 %float_1 + %2944 = OpMatrixTimesVector %v3float %466 %2941 + %2945 = OpDot %float %2943 %2944 + OpBranch %2887 + %2887 = OpLabel + %2946 = OpPhi %float %2925 %2895 %2945 %2888 + OpBranch %2879 + %2880 = OpLabel + %2947 = OpFMul %float %2877 %float_3 + %2948 = OpExtInst %float %1 Log %float_9_99999975en05 + %2949 = OpFDiv %float %2948 %1091 + %2950 = OpFMul %float %float_3 %2792 + %2951 = OpFDiv %float %2950 %1091 + %2952 = OpFSub %float %2949 %2951 + %2953 = OpFAdd %float %2947 %2952 + OpBranch %2879 + %2879 = OpLabel + %2954 = OpPhi %float %2946 %2887 %2953 %2880 + %2955 = OpExtInst %float %1 Pow %float_10 %2954 + %2956 = OpCompositeInsert %v3float %2955 %2872 1 + %2957 = OpCompositeExtract %float %2583 2 + OpStore %552 %503 + OpStore %551 %504 + %2958 = OpFOrdLessThanEqual %bool %2957 %float_0 + %2959 = OpSelect %float %2958 %float_9_99999975en05 %2957 + %2960 = OpExtInst %float %1 Log %2959 + %2961 = OpFDiv %float %2960 %1091 + %2962 = OpFOrdLessThanEqual %bool %2961 %2793 + OpSelectionMerge %2963 None + OpBranchConditional %2962 %2964 %2965 + %2965 = OpLabel + %2966 = OpFOrdGreaterThan %bool %2961 %2793 + %2967 = OpExtInst %float %1 Log %2714 + %2968 = OpFDiv %float %2967 %1091 + %2969 = OpFOrdLessThan %bool %2961 %2968 + %2970 = OpLogicalAnd %bool %2966 %2969 + OpSelectionMerge %2971 None + OpBranchConditional %2970 %2972 %2973 + %2973 = OpLabel + %2974 = OpFOrdGreaterThanEqual %bool %2961 %2968 + %2975 = OpExtInst %float %1 Log %2786 + %2976 = OpFDiv %float %2975 %1091 + %2977 = OpFOrdLessThan %bool %2961 %2976 + %2978 = OpLogicalAnd %bool %2974 %2977 + OpSelectionMerge %2979 None + OpBranchConditional %2978 %2980 %2981 + %2981 = OpLabel + %2982 = OpFMul %float %2961 %float_0_0599999987 + %2983 = OpExtInst %float %1 Log %float_1000 + %2984 = OpFDiv %float %2983 %1091 + %2985 = OpFMul %float %float_0_0599999987 %2975 + %2986 = OpFDiv %float %2985 %1091 + %2987 = OpFSub %float %2984 %2986 + %2988 = OpFAdd %float %2982 %2987 + OpBranch %2979 + %2980 = OpLabel + %2989 = OpFSub %float %2961 %2968 + %2990 = OpFMul %float %float_7 %2989 + %2991 = OpFSub %float %2976 %2968 + %2992 = OpFDiv %float %2990 %2991 + %2993 = OpConvertFToS %int %2992 + %2994 = OpConvertSToF %float %2993 + %2995 = OpFSub %float %2992 %2994 + %2996 = OpAccessChain %_ptr_Function_float %551 %2993 + %2997 = OpLoad %float %2996 + %2998 = OpIAdd %int %2993 %int_1 + %2999 = OpAccessChain %_ptr_Function_float %551 %2998 + %3000 = OpLoad %float %2999 + %3001 = OpIAdd %int %2993 %int_2 + %3002 = OpAccessChain %_ptr_Function_float %551 %3001 + %3003 = OpLoad %float %3002 + %3004 = OpCompositeConstruct %v3float %2997 %3000 %3003 + %3005 = OpFMul %float %2995 %2995 + %3006 = OpCompositeConstruct %v3float %3005 %2995 %float_1 + %3007 = OpMatrixTimesVector %v3float %466 %3004 + %3008 = OpDot %float %3006 %3007 + OpBranch %2979 + %2979 = OpLabel + %3009 = OpPhi %float %2988 %2981 %3008 %2980 + OpBranch %2971 + %2972 = OpLabel + %3010 = OpFSub %float %2961 %2793 + %3011 = OpFMul %float %float_7 %3010 + %3012 = OpFSub %float %2968 %2793 + %3013 = OpFDiv %float %3011 %3012 + %3014 = OpConvertFToS %int %3013 + %3015 = OpConvertSToF %float %3014 + %3016 = OpFSub %float %3013 %3015 + %3017 = OpAccessChain %_ptr_Function_float %552 %3014 + %3018 = OpLoad %float %3017 + %3019 = OpIAdd %int %3014 %int_1 + %3020 = OpAccessChain %_ptr_Function_float %552 %3019 + %3021 = OpLoad %float %3020 + %3022 = OpIAdd %int %3014 %int_2 + %3023 = OpAccessChain %_ptr_Function_float %552 %3022 + %3024 = OpLoad %float %3023 + %3025 = OpCompositeConstruct %v3float %3018 %3021 %3024 + %3026 = OpFMul %float %3016 %3016 + %3027 = OpCompositeConstruct %v3float %3026 %3016 %float_1 + %3028 = OpMatrixTimesVector %v3float %466 %3025 + %3029 = OpDot %float %3027 %3028 + OpBranch %2971 + %2971 = OpLabel + %3030 = OpPhi %float %3009 %2979 %3029 %2972 + OpBranch %2963 + %2964 = OpLabel + %3031 = OpFMul %float %2961 %float_3 + %3032 = OpExtInst %float %1 Log %float_9_99999975en05 + %3033 = OpFDiv %float %3032 %1091 + %3034 = OpFMul %float %float_3 %2792 + %3035 = OpFDiv %float %3034 %1091 + %3036 = OpFSub %float %3033 %3035 + %3037 = OpFAdd %float %3031 %3036 + OpBranch %2963 + %2963 = OpLabel + %3038 = OpPhi %float %3030 %2971 %3037 %2964 + %3039 = OpExtInst %float %1 Pow %float_10 %3038 + %3040 = OpCompositeInsert %v3float %3039 %2956 2 + %3041 = OpFSub %v3float %3040 %361 + %3042 = OpVectorTimesMatrix %v3float %3041 %602 + %3043 = OpFMul %v3float %3042 %519 + %3044 = OpExtInst %v3float %1 Pow %3043 %286 + %3045 = OpFMul %v3float %196 %3044 + %3046 = OpFAdd %v3float %195 %3045 + %3047 = OpFMul %v3float %197 %3044 + %3048 = OpFAdd %v3float %141 %3047 + %3049 = OpFDiv %v3float %141 %3048 + %3050 = OpFMul %v3float %3046 %3049 + %3051 = OpExtInst %v3float %1 Pow %3050 %287 + OpBranch %1336 + %1336 = OpLabel + %3052 = OpPhi %v3float %2201 %1342 %3051 %2963 + OpBranch %1330 + %1331 = OpLabel + %3053 = OpVectorTimesMatrix %v3float %1324 %573 + %3054 = OpVectorTimesMatrix %v3float %3053 %602 + %3055 = OpExtInst %v3float %1 FMax %263 %3054 + %3056 = OpFMul %v3float %3055 %275 + %3057 = OpExtInst %v3float %1 FMax %3055 %277 + %3058 = OpExtInst %v3float %1 Pow %3057 %279 + %3059 = OpFMul %v3float %3058 %281 + %3060 = OpFSub %v3float %3059 %283 + %3061 = OpExtInst %v3float %1 FMin %3056 %3060 + OpBranch %1330 + %1330 = OpLabel + %3062 = OpPhi %v3float %3052 %1336 %3061 %1331 + OpBranch %1326 + %1327 = OpLabel + %3063 = OpCompositeExtract %float %1324 0 + OpBranch %3064 + %3064 = OpLabel + OpLoopMerge %3065 %3066 None + OpBranch %3067 + %3067 = OpLabel + %3068 = OpFOrdLessThan %bool %3063 %float_0_00313066994 + OpSelectionMerge %3069 None + OpBranchConditional %3068 %3070 %3069 + %3070 = OpLabel + %3071 = OpFMul %float %3063 %float_12_9200001 + OpBranch %3065 + %3069 = OpLabel + %3072 = OpExtInst %float %1 Pow %3063 %float_0_416666657 + %3073 = OpFMul %float %3072 %float_1_05499995 + %3074 = OpFSub %float %3073 %float_0_0549999997 + OpBranch %3065 + %3066 = OpLabel + OpBranch %3064 + %3065 = OpLabel + %3075 = OpPhi %float %3071 %3070 %3074 %3069 + %3076 = OpCompositeExtract %float %1324 1 + OpBranch %3077 + %3077 = OpLabel + OpLoopMerge %3078 %3079 None + OpBranch %3080 + %3080 = OpLabel + %3081 = OpFOrdLessThan %bool %3076 %float_0_00313066994 + OpSelectionMerge %3082 None + OpBranchConditional %3081 %3083 %3082 + %3083 = OpLabel + %3084 = OpFMul %float %3076 %float_12_9200001 + OpBranch %3078 + %3082 = OpLabel + %3085 = OpExtInst %float %1 Pow %3076 %float_0_416666657 + %3086 = OpFMul %float %3085 %float_1_05499995 + %3087 = OpFSub %float %3086 %float_0_0549999997 + OpBranch %3078 + %3079 = OpLabel + OpBranch %3077 + %3078 = OpLabel + %3088 = OpPhi %float %3084 %3083 %3087 %3082 + %3089 = OpCompositeExtract %float %1324 2 + OpBranch %3090 + %3090 = OpLabel + OpLoopMerge %3091 %3092 None + OpBranch %3093 + %3093 = OpLabel + %3094 = OpFOrdLessThan %bool %3089 %float_0_00313066994 + OpSelectionMerge %3095 None + OpBranchConditional %3094 %3096 %3095 + %3096 = OpLabel + %3097 = OpFMul %float %3089 %float_12_9200001 + OpBranch %3091 + %3095 = OpLabel + %3098 = OpExtInst %float %1 Pow %3089 %float_0_416666657 + %3099 = OpFMul %float %3098 %float_1_05499995 + %3100 = OpFSub %float %3099 %float_0_0549999997 + OpBranch %3091 + %3092 = OpLabel + OpBranch %3090 + %3091 = OpLabel + %3101 = OpPhi %float %3097 %3096 %3100 %3095 + %3102 = OpCompositeConstruct %v3float %3075 %3088 %3101 + OpBranch %1326 + %1326 = OpLabel + %3103 = OpPhi %v3float %3062 %1330 %3102 %3091 + %3104 = OpFMul %v3float %3103 %522 + %3105 = OpVectorShuffle %v4float %135 %3104 4 5 6 3 + %3106 = OpCompositeInsert %v4float %float_0 %3105 3 + OpStore %out_var_SV_Target0 %3106 + OpReturn + OpFunctionEnd diff --git a/third_party/spirv-cross/shaders-ue4/asm/frag/sample-mask-not-array.asm.frag b/third_party/spirv-cross/shaders-ue4/asm/frag/sample-mask-not-array.asm.frag new file mode 100644 index 0000000000..097eb6354d --- /dev/null +++ b/third_party/spirv-cross/shaders-ue4/asm/frag/sample-mask-not-array.asm.frag @@ -0,0 +1,1230 @@ +; SPIR-V +; Version: 1.0 +; Generator: Google spiregg; 0 +; Bound: 271 +; Schema: 0 + OpCapability Shader + OpExtension "SPV_GOOGLE_hlsl_functionality1" + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %MainPS "main" %in_var_TEXCOORD10_centroid %in_var_TEXCOORD11_centroid %in_var_PRIMITIVE_ID %in_var_TEXCOORD7 %gl_FragCoord %gl_FrontFacing %gl_SampleMask %out_var_SV_Target0 %gl_SampleMask_0 + OpExecutionMode %MainPS OriginUpperLeft + OpSource HLSL 600 + OpName %type_View "type.View" + OpMemberName %type_View 0 "View_TranslatedWorldToClip" + OpMemberName %type_View 1 "View_WorldToClip" + OpMemberName %type_View 2 "View_TranslatedWorldToView" + OpMemberName %type_View 3 "View_ViewToTranslatedWorld" + OpMemberName %type_View 4 "View_TranslatedWorldToCameraView" + OpMemberName %type_View 5 "View_CameraViewToTranslatedWorld" + OpMemberName %type_View 6 "View_ViewToClip" + OpMemberName %type_View 7 "View_ViewToClipNoAA" + OpMemberName %type_View 8 "View_ClipToView" + OpMemberName %type_View 9 "View_ClipToTranslatedWorld" + OpMemberName %type_View 10 "View_SVPositionToTranslatedWorld" + OpMemberName %type_View 11 "View_ScreenToWorld" + OpMemberName %type_View 12 "View_ScreenToTranslatedWorld" + OpMemberName %type_View 13 "View_ViewForward" + OpMemberName %type_View 14 "PrePadding_View_844" + OpMemberName %type_View 15 "View_ViewUp" + OpMemberName %type_View 16 "PrePadding_View_860" + OpMemberName %type_View 17 "View_ViewRight" + OpMemberName %type_View 18 "PrePadding_View_876" + OpMemberName %type_View 19 "View_HMDViewNoRollUp" + OpMemberName %type_View 20 "PrePadding_View_892" + OpMemberName %type_View 21 "View_HMDViewNoRollRight" + OpMemberName %type_View 22 "PrePadding_View_908" + OpMemberName %type_View 23 "View_InvDeviceZToWorldZTransform" + OpMemberName %type_View 24 "View_ScreenPositionScaleBias" + OpMemberName %type_View 25 "View_WorldCameraOrigin" + OpMemberName %type_View 26 "PrePadding_View_956" + OpMemberName %type_View 27 "View_TranslatedWorldCameraOrigin" + OpMemberName %type_View 28 "PrePadding_View_972" + OpMemberName %type_View 29 "View_WorldViewOrigin" + OpMemberName %type_View 30 "PrePadding_View_988" + OpMemberName %type_View 31 "View_PreViewTranslation" + OpMemberName %type_View 32 "PrePadding_View_1004" + OpMemberName %type_View 33 "View_PrevProjection" + OpMemberName %type_View 34 "View_PrevViewProj" + OpMemberName %type_View 35 "View_PrevViewRotationProj" + OpMemberName %type_View 36 "View_PrevViewToClip" + OpMemberName %type_View 37 "View_PrevClipToView" + OpMemberName %type_View 38 "View_PrevTranslatedWorldToClip" + OpMemberName %type_View 39 "View_PrevTranslatedWorldToView" + OpMemberName %type_View 40 "View_PrevViewToTranslatedWorld" + OpMemberName %type_View 41 "View_PrevTranslatedWorldToCameraView" + OpMemberName %type_View 42 "View_PrevCameraViewToTranslatedWorld" + OpMemberName %type_View 43 "View_PrevWorldCameraOrigin" + OpMemberName %type_View 44 "PrePadding_View_1660" + OpMemberName %type_View 45 "View_PrevWorldViewOrigin" + OpMemberName %type_View 46 "PrePadding_View_1676" + OpMemberName %type_View 47 "View_PrevPreViewTranslation" + OpMemberName %type_View 48 "PrePadding_View_1692" + OpMemberName %type_View 49 "View_PrevInvViewProj" + OpMemberName %type_View 50 "View_PrevScreenToTranslatedWorld" + OpMemberName %type_View 51 "View_ClipToPrevClip" + OpMemberName %type_View 52 "View_TemporalAAJitter" + OpMemberName %type_View 53 "View_GlobalClippingPlane" + OpMemberName %type_View 54 "View_FieldOfViewWideAngles" + OpMemberName %type_View 55 "View_PrevFieldOfViewWideAngles" + OpMemberName %type_View 56 "View_ViewRectMin" + OpMemberName %type_View 57 "View_ViewSizeAndInvSize" + OpMemberName %type_View 58 "View_BufferSizeAndInvSize" + OpMemberName %type_View 59 "View_BufferBilinearUVMinMax" + OpMemberName %type_View 60 "View_NumSceneColorMSAASamples" + OpMemberName %type_View 61 "View_PreExposure" + OpMemberName %type_View 62 "View_OneOverPreExposure" + OpMemberName %type_View 63 "PrePadding_View_2012" + OpMemberName %type_View 64 "View_DiffuseOverrideParameter" + OpMemberName %type_View 65 "View_SpecularOverrideParameter" + OpMemberName %type_View 66 "View_NormalOverrideParameter" + OpMemberName %type_View 67 "View_RoughnessOverrideParameter" + OpMemberName %type_View 68 "View_PrevFrameGameTime" + OpMemberName %type_View 69 "View_PrevFrameRealTime" + OpMemberName %type_View 70 "View_OutOfBoundsMask" + OpMemberName %type_View 71 "PrePadding_View_2084" + OpMemberName %type_View 72 "PrePadding_View_2088" + OpMemberName %type_View 73 "PrePadding_View_2092" + OpMemberName %type_View 74 "View_WorldCameraMovementSinceLastFrame" + OpMemberName %type_View 75 "View_CullingSign" + OpMemberName %type_View 76 "View_NearPlane" + OpMemberName %type_View 77 "View_AdaptiveTessellationFactor" + OpMemberName %type_View 78 "View_GameTime" + OpMemberName %type_View 79 "View_RealTime" + OpMemberName %type_View 80 "View_DeltaTime" + OpMemberName %type_View 81 "View_MaterialTextureMipBias" + OpMemberName %type_View 82 "View_MaterialTextureDerivativeMultiply" + OpMemberName %type_View 83 "View_Random" + OpMemberName %type_View 84 "View_FrameNumber" + OpMemberName %type_View 85 "View_StateFrameIndexMod8" + OpMemberName %type_View 86 "View_StateFrameIndex" + OpMemberName %type_View 87 "View_CameraCut" + OpMemberName %type_View 88 "View_UnlitViewmodeMask" + OpMemberName %type_View 89 "PrePadding_View_2164" + OpMemberName %type_View 90 "PrePadding_View_2168" + OpMemberName %type_View 91 "PrePadding_View_2172" + OpMemberName %type_View 92 "View_DirectionalLightColor" + OpMemberName %type_View 93 "View_DirectionalLightDirection" + OpMemberName %type_View 94 "PrePadding_View_2204" + OpMemberName %type_View 95 "View_TranslucencyLightingVolumeMin" + OpMemberName %type_View 96 "View_TranslucencyLightingVolumeInvSize" + OpMemberName %type_View 97 "View_TemporalAAParams" + OpMemberName %type_View 98 "View_CircleDOFParams" + OpMemberName %type_View 99 "View_DepthOfFieldSensorWidth" + OpMemberName %type_View 100 "View_DepthOfFieldFocalDistance" + OpMemberName %type_View 101 "View_DepthOfFieldScale" + OpMemberName %type_View 102 "View_DepthOfFieldFocalLength" + OpMemberName %type_View 103 "View_DepthOfFieldFocalRegion" + OpMemberName %type_View 104 "View_DepthOfFieldNearTransitionRegion" + OpMemberName %type_View 105 "View_DepthOfFieldFarTransitionRegion" + OpMemberName %type_View 106 "View_MotionBlurNormalizedToPixel" + OpMemberName %type_View 107 "View_bSubsurfacePostprocessEnabled" + OpMemberName %type_View 108 "View_GeneralPurposeTweak" + OpMemberName %type_View 109 "View_DemosaicVposOffset" + OpMemberName %type_View 110 "PrePadding_View_2348" + OpMemberName %type_View 111 "View_IndirectLightingColorScale" + OpMemberName %type_View 112 "View_HDR32bppEncodingMode" + OpMemberName %type_View 113 "View_AtmosphericFogSunDirection" + OpMemberName %type_View 114 "View_AtmosphericFogSunPower" + OpMemberName %type_View 115 "View_AtmosphericFogPower" + OpMemberName %type_View 116 "View_AtmosphericFogDensityScale" + OpMemberName %type_View 117 "View_AtmosphericFogDensityOffset" + OpMemberName %type_View 118 "View_AtmosphericFogGroundOffset" + OpMemberName %type_View 119 "View_AtmosphericFogDistanceScale" + OpMemberName %type_View 120 "View_AtmosphericFogAltitudeScale" + OpMemberName %type_View 121 "View_AtmosphericFogHeightScaleRayleigh" + OpMemberName %type_View 122 "View_AtmosphericFogStartDistance" + OpMemberName %type_View 123 "View_AtmosphericFogDistanceOffset" + OpMemberName %type_View 124 "View_AtmosphericFogSunDiscScale" + OpMemberName %type_View 125 "View_AtmosphericFogRenderMask" + OpMemberName %type_View 126 "View_AtmosphericFogInscatterAltitudeSampleNum" + OpMemberName %type_View 127 "View_AtmosphericFogSunColor" + OpMemberName %type_View 128 "View_NormalCurvatureToRoughnessScaleBias" + OpMemberName %type_View 129 "View_RenderingReflectionCaptureMask" + OpMemberName %type_View 130 "View_AmbientCubemapTint" + OpMemberName %type_View 131 "View_AmbientCubemapIntensity" + OpMemberName %type_View 132 "View_SkyLightParameters" + OpMemberName %type_View 133 "PrePadding_View_2488" + OpMemberName %type_View 134 "PrePadding_View_2492" + OpMemberName %type_View 135 "View_SkyLightColor" + OpMemberName %type_View 136 "View_SkyIrradianceEnvironmentMap" + OpMemberName %type_View 137 "View_MobilePreviewMode" + OpMemberName %type_View 138 "View_HMDEyePaddingOffset" + OpMemberName %type_View 139 "View_ReflectionCubemapMaxMip" + OpMemberName %type_View 140 "View_ShowDecalsMask" + OpMemberName %type_View 141 "View_DistanceFieldAOSpecularOcclusionMode" + OpMemberName %type_View 142 "View_IndirectCapsuleSelfShadowingIntensity" + OpMemberName %type_View 143 "PrePadding_View_2648" + OpMemberName %type_View 144 "PrePadding_View_2652" + OpMemberName %type_View 145 "View_ReflectionEnvironmentRoughnessMixingScaleBiasAndLargestWeight" + OpMemberName %type_View 146 "View_StereoPassIndex" + OpMemberName %type_View 147 "View_GlobalVolumeCenterAndExtent" + OpMemberName %type_View 148 "View_GlobalVolumeWorldToUVAddAndMul" + OpMemberName %type_View 149 "View_GlobalVolumeDimension" + OpMemberName %type_View 150 "View_GlobalVolumeTexelSize" + OpMemberName %type_View 151 "View_MaxGlobalDistance" + OpMemberName %type_View 152 "View_bCheckerboardSubsurfaceProfileRendering" + OpMemberName %type_View 153 "View_VolumetricFogInvGridSize" + OpMemberName %type_View 154 "PrePadding_View_2828" + OpMemberName %type_View 155 "View_VolumetricFogGridZParams" + OpMemberName %type_View 156 "PrePadding_View_2844" + OpMemberName %type_View 157 "View_VolumetricFogSVPosToVolumeUV" + OpMemberName %type_View 158 "View_VolumetricFogMaxDistance" + OpMemberName %type_View 159 "PrePadding_View_2860" + OpMemberName %type_View 160 "View_VolumetricLightmapWorldToUVScale" + OpMemberName %type_View 161 "PrePadding_View_2876" + OpMemberName %type_View 162 "View_VolumetricLightmapWorldToUVAdd" + OpMemberName %type_View 163 "PrePadding_View_2892" + OpMemberName %type_View 164 "View_VolumetricLightmapIndirectionTextureSize" + OpMemberName %type_View 165 "View_VolumetricLightmapBrickSize" + OpMemberName %type_View 166 "View_VolumetricLightmapBrickTexelSize" + OpMemberName %type_View 167 "View_StereoIPD" + OpMemberName %type_View 168 "View_IndirectLightingCacheShowFlag" + OpMemberName %type_View 169 "View_EyeToPixelSpreadAngle" + OpName %View "View" + OpName %type_3d_image "type.3d.image" + OpName %type_sampler "type.sampler" + OpName %View_SharedBilinearClampedSampler "View_SharedBilinearClampedSampler" + OpName %type_StructuredBuffer_v4float "type.StructuredBuffer.v4float" + OpName %View_PrimitiveSceneData "View_PrimitiveSceneData" + OpName %type_TranslucentBasePass "type.TranslucentBasePass" + OpMemberName %type_TranslucentBasePass 0 "TranslucentBasePass_Shared_Forward_NumLocalLights" + OpMemberName %type_TranslucentBasePass 1 "TranslucentBasePass_Shared_Forward_NumReflectionCaptures" + OpMemberName %type_TranslucentBasePass 2 "TranslucentBasePass_Shared_Forward_HasDirectionalLight" + OpMemberName %type_TranslucentBasePass 3 "TranslucentBasePass_Shared_Forward_NumGridCells" + OpMemberName %type_TranslucentBasePass 4 "TranslucentBasePass_Shared_Forward_CulledGridSize" + OpMemberName %type_TranslucentBasePass 5 "TranslucentBasePass_Shared_Forward_MaxCulledLightsPerCell" + OpMemberName %type_TranslucentBasePass 6 "TranslucentBasePass_Shared_Forward_LightGridPixelSizeShift" + OpMemberName %type_TranslucentBasePass 7 "PrePadding_TranslucentBasePass_Shared_Forward_36" + OpMemberName %type_TranslucentBasePass 8 "PrePadding_TranslucentBasePass_Shared_Forward_40" + OpMemberName %type_TranslucentBasePass 9 "PrePadding_TranslucentBasePass_Shared_Forward_44" + OpMemberName %type_TranslucentBasePass 10 "TranslucentBasePass_Shared_Forward_LightGridZParams" + OpMemberName %type_TranslucentBasePass 11 "PrePadding_TranslucentBasePass_Shared_Forward_60" + OpMemberName %type_TranslucentBasePass 12 "TranslucentBasePass_Shared_Forward_DirectionalLightDirection" + OpMemberName %type_TranslucentBasePass 13 "PrePadding_TranslucentBasePass_Shared_Forward_76" + OpMemberName %type_TranslucentBasePass 14 "TranslucentBasePass_Shared_Forward_DirectionalLightColor" + OpMemberName %type_TranslucentBasePass 15 "TranslucentBasePass_Shared_Forward_DirectionalLightVolumetricScatteringIntensity" + OpMemberName %type_TranslucentBasePass 16 "TranslucentBasePass_Shared_Forward_DirectionalLightShadowMapChannelMask" + OpMemberName %type_TranslucentBasePass 17 "PrePadding_TranslucentBasePass_Shared_Forward_100" + OpMemberName %type_TranslucentBasePass 18 "TranslucentBasePass_Shared_Forward_DirectionalLightDistanceFadeMAD" + OpMemberName %type_TranslucentBasePass 19 "TranslucentBasePass_Shared_Forward_NumDirectionalLightCascades" + OpMemberName %type_TranslucentBasePass 20 "PrePadding_TranslucentBasePass_Shared_Forward_116" + OpMemberName %type_TranslucentBasePass 21 "PrePadding_TranslucentBasePass_Shared_Forward_120" + OpMemberName %type_TranslucentBasePass 22 "PrePadding_TranslucentBasePass_Shared_Forward_124" + OpMemberName %type_TranslucentBasePass 23 "TranslucentBasePass_Shared_Forward_CascadeEndDepths" + OpMemberName %type_TranslucentBasePass 24 "TranslucentBasePass_Shared_Forward_DirectionalLightWorldToShadowMatrix" + OpMemberName %type_TranslucentBasePass 25 "TranslucentBasePass_Shared_Forward_DirectionalLightShadowmapMinMax" + OpMemberName %type_TranslucentBasePass 26 "TranslucentBasePass_Shared_Forward_DirectionalLightShadowmapAtlasBufferSize" + OpMemberName %type_TranslucentBasePass 27 "TranslucentBasePass_Shared_Forward_DirectionalLightDepthBias" + OpMemberName %type_TranslucentBasePass 28 "TranslucentBasePass_Shared_Forward_DirectionalLightUseStaticShadowing" + OpMemberName %type_TranslucentBasePass 29 "PrePadding_TranslucentBasePass_Shared_Forward_488" + OpMemberName %type_TranslucentBasePass 30 "PrePadding_TranslucentBasePass_Shared_Forward_492" + OpMemberName %type_TranslucentBasePass 31 "TranslucentBasePass_Shared_Forward_DirectionalLightStaticShadowBufferSize" + OpMemberName %type_TranslucentBasePass 32 "TranslucentBasePass_Shared_Forward_DirectionalLightWorldToStaticShadow" + OpMemberName %type_TranslucentBasePass 33 "PrePadding_TranslucentBasePass_Shared_ForwardISR_576" + OpMemberName %type_TranslucentBasePass 34 "PrePadding_TranslucentBasePass_Shared_ForwardISR_580" + OpMemberName %type_TranslucentBasePass 35 "PrePadding_TranslucentBasePass_Shared_ForwardISR_584" + OpMemberName %type_TranslucentBasePass 36 "PrePadding_TranslucentBasePass_Shared_ForwardISR_588" + OpMemberName %type_TranslucentBasePass 37 "PrePadding_TranslucentBasePass_Shared_ForwardISR_592" + OpMemberName %type_TranslucentBasePass 38 "PrePadding_TranslucentBasePass_Shared_ForwardISR_596" + OpMemberName %type_TranslucentBasePass 39 "PrePadding_TranslucentBasePass_Shared_ForwardISR_600" + OpMemberName %type_TranslucentBasePass 40 "PrePadding_TranslucentBasePass_Shared_ForwardISR_604" + OpMemberName %type_TranslucentBasePass 41 "PrePadding_TranslucentBasePass_Shared_ForwardISR_608" + OpMemberName %type_TranslucentBasePass 42 "PrePadding_TranslucentBasePass_Shared_ForwardISR_612" + OpMemberName %type_TranslucentBasePass 43 "PrePadding_TranslucentBasePass_Shared_ForwardISR_616" + OpMemberName %type_TranslucentBasePass 44 "PrePadding_TranslucentBasePass_Shared_ForwardISR_620" + OpMemberName %type_TranslucentBasePass 45 "PrePadding_TranslucentBasePass_Shared_ForwardISR_624" + OpMemberName %type_TranslucentBasePass 46 "PrePadding_TranslucentBasePass_Shared_ForwardISR_628" + OpMemberName %type_TranslucentBasePass 47 "PrePadding_TranslucentBasePass_Shared_ForwardISR_632" + OpMemberName %type_TranslucentBasePass 48 "PrePadding_TranslucentBasePass_Shared_ForwardISR_636" + OpMemberName %type_TranslucentBasePass 49 "TranslucentBasePass_Shared_ForwardISR_NumLocalLights" + OpMemberName %type_TranslucentBasePass 50 "TranslucentBasePass_Shared_ForwardISR_NumReflectionCaptures" + OpMemberName %type_TranslucentBasePass 51 "TranslucentBasePass_Shared_ForwardISR_HasDirectionalLight" + OpMemberName %type_TranslucentBasePass 52 "TranslucentBasePass_Shared_ForwardISR_NumGridCells" + OpMemberName %type_TranslucentBasePass 53 "TranslucentBasePass_Shared_ForwardISR_CulledGridSize" + OpMemberName %type_TranslucentBasePass 54 "TranslucentBasePass_Shared_ForwardISR_MaxCulledLightsPerCell" + OpMemberName %type_TranslucentBasePass 55 "TranslucentBasePass_Shared_ForwardISR_LightGridPixelSizeShift" + OpMemberName %type_TranslucentBasePass 56 "PrePadding_TranslucentBasePass_Shared_ForwardISR_676" + OpMemberName %type_TranslucentBasePass 57 "PrePadding_TranslucentBasePass_Shared_ForwardISR_680" + OpMemberName %type_TranslucentBasePass 58 "PrePadding_TranslucentBasePass_Shared_ForwardISR_684" + OpMemberName %type_TranslucentBasePass 59 "TranslucentBasePass_Shared_ForwardISR_LightGridZParams" + OpMemberName %type_TranslucentBasePass 60 "PrePadding_TranslucentBasePass_Shared_ForwardISR_700" + OpMemberName %type_TranslucentBasePass 61 "TranslucentBasePass_Shared_ForwardISR_DirectionalLightDirection" + OpMemberName %type_TranslucentBasePass 62 "PrePadding_TranslucentBasePass_Shared_ForwardISR_716" + OpMemberName %type_TranslucentBasePass 63 "TranslucentBasePass_Shared_ForwardISR_DirectionalLightColor" + OpMemberName %type_TranslucentBasePass 64 "TranslucentBasePass_Shared_ForwardISR_DirectionalLightVolumetricScatteringIntensity" + OpMemberName %type_TranslucentBasePass 65 "TranslucentBasePass_Shared_ForwardISR_DirectionalLightShadowMapChannelMask" + OpMemberName %type_TranslucentBasePass 66 "PrePadding_TranslucentBasePass_Shared_ForwardISR_740" + OpMemberName %type_TranslucentBasePass 67 "TranslucentBasePass_Shared_ForwardISR_DirectionalLightDistanceFadeMAD" + OpMemberName %type_TranslucentBasePass 68 "TranslucentBasePass_Shared_ForwardISR_NumDirectionalLightCascades" + OpMemberName %type_TranslucentBasePass 69 "PrePadding_TranslucentBasePass_Shared_ForwardISR_756" + OpMemberName %type_TranslucentBasePass 70 "PrePadding_TranslucentBasePass_Shared_ForwardISR_760" + OpMemberName %type_TranslucentBasePass 71 "PrePadding_TranslucentBasePass_Shared_ForwardISR_764" + OpMemberName %type_TranslucentBasePass 72 "TranslucentBasePass_Shared_ForwardISR_CascadeEndDepths" + OpMemberName %type_TranslucentBasePass 73 "TranslucentBasePass_Shared_ForwardISR_DirectionalLightWorldToShadowMatrix" + OpMemberName %type_TranslucentBasePass 74 "TranslucentBasePass_Shared_ForwardISR_DirectionalLightShadowmapMinMax" + OpMemberName %type_TranslucentBasePass 75 "TranslucentBasePass_Shared_ForwardISR_DirectionalLightShadowmapAtlasBufferSize" + OpMemberName %type_TranslucentBasePass 76 "TranslucentBasePass_Shared_ForwardISR_DirectionalLightDepthBias" + OpMemberName %type_TranslucentBasePass 77 "TranslucentBasePass_Shared_ForwardISR_DirectionalLightUseStaticShadowing" + OpMemberName %type_TranslucentBasePass 78 "PrePadding_TranslucentBasePass_Shared_ForwardISR_1128" + OpMemberName %type_TranslucentBasePass 79 "PrePadding_TranslucentBasePass_Shared_ForwardISR_1132" + OpMemberName %type_TranslucentBasePass 80 "TranslucentBasePass_Shared_ForwardISR_DirectionalLightStaticShadowBufferSize" + OpMemberName %type_TranslucentBasePass 81 "TranslucentBasePass_Shared_ForwardISR_DirectionalLightWorldToStaticShadow" + OpMemberName %type_TranslucentBasePass 82 "PrePadding_TranslucentBasePass_Shared_Reflection_1216" + OpMemberName %type_TranslucentBasePass 83 "PrePadding_TranslucentBasePass_Shared_Reflection_1220" + OpMemberName %type_TranslucentBasePass 84 "PrePadding_TranslucentBasePass_Shared_Reflection_1224" + OpMemberName %type_TranslucentBasePass 85 "PrePadding_TranslucentBasePass_Shared_Reflection_1228" + OpMemberName %type_TranslucentBasePass 86 "PrePadding_TranslucentBasePass_Shared_Reflection_1232" + OpMemberName %type_TranslucentBasePass 87 "PrePadding_TranslucentBasePass_Shared_Reflection_1236" + OpMemberName %type_TranslucentBasePass 88 "PrePadding_TranslucentBasePass_Shared_Reflection_1240" + OpMemberName %type_TranslucentBasePass 89 "PrePadding_TranslucentBasePass_Shared_Reflection_1244" + OpMemberName %type_TranslucentBasePass 90 "PrePadding_TranslucentBasePass_Shared_Reflection_1248" + OpMemberName %type_TranslucentBasePass 91 "PrePadding_TranslucentBasePass_Shared_Reflection_1252" + OpMemberName %type_TranslucentBasePass 92 "PrePadding_TranslucentBasePass_Shared_Reflection_1256" + OpMemberName %type_TranslucentBasePass 93 "PrePadding_TranslucentBasePass_Shared_Reflection_1260" + OpMemberName %type_TranslucentBasePass 94 "PrePadding_TranslucentBasePass_Shared_Reflection_1264" + OpMemberName %type_TranslucentBasePass 95 "PrePadding_TranslucentBasePass_Shared_Reflection_1268" + OpMemberName %type_TranslucentBasePass 96 "PrePadding_TranslucentBasePass_Shared_Reflection_1272" + OpMemberName %type_TranslucentBasePass 97 "PrePadding_TranslucentBasePass_Shared_Reflection_1276" + OpMemberName %type_TranslucentBasePass 98 "TranslucentBasePass_Shared_Reflection_SkyLightParameters" + OpMemberName %type_TranslucentBasePass 99 "TranslucentBasePass_Shared_Reflection_SkyLightCubemapBrightness" + OpMemberName %type_TranslucentBasePass 100 "PrePadding_TranslucentBasePass_Shared_PlanarReflection_1300" + OpMemberName %type_TranslucentBasePass 101 "PrePadding_TranslucentBasePass_Shared_PlanarReflection_1304" + OpMemberName %type_TranslucentBasePass 102 "PrePadding_TranslucentBasePass_Shared_PlanarReflection_1308" + OpMemberName %type_TranslucentBasePass 103 "PrePadding_TranslucentBasePass_Shared_PlanarReflection_1312" + OpMemberName %type_TranslucentBasePass 104 "PrePadding_TranslucentBasePass_Shared_PlanarReflection_1316" + OpMemberName %type_TranslucentBasePass 105 "PrePadding_TranslucentBasePass_Shared_PlanarReflection_1320" + OpMemberName %type_TranslucentBasePass 106 "PrePadding_TranslucentBasePass_Shared_PlanarReflection_1324" + OpMemberName %type_TranslucentBasePass 107 "PrePadding_TranslucentBasePass_Shared_PlanarReflection_1328" + OpMemberName %type_TranslucentBasePass 108 "PrePadding_TranslucentBasePass_Shared_PlanarReflection_1332" + OpMemberName %type_TranslucentBasePass 109 "PrePadding_TranslucentBasePass_Shared_PlanarReflection_1336" + OpMemberName %type_TranslucentBasePass 110 "PrePadding_TranslucentBasePass_Shared_PlanarReflection_1340" + OpMemberName %type_TranslucentBasePass 111 "PrePadding_TranslucentBasePass_Shared_PlanarReflection_1344" + OpMemberName %type_TranslucentBasePass 112 "PrePadding_TranslucentBasePass_Shared_PlanarReflection_1348" + OpMemberName %type_TranslucentBasePass 113 "PrePadding_TranslucentBasePass_Shared_PlanarReflection_1352" + OpMemberName %type_TranslucentBasePass 114 "PrePadding_TranslucentBasePass_Shared_PlanarReflection_1356" + OpMemberName %type_TranslucentBasePass 115 "TranslucentBasePass_Shared_PlanarReflection_ReflectionPlane" + OpMemberName %type_TranslucentBasePass 116 "TranslucentBasePass_Shared_PlanarReflection_PlanarReflectionOrigin" + OpMemberName %type_TranslucentBasePass 117 "TranslucentBasePass_Shared_PlanarReflection_PlanarReflectionXAxis" + OpMemberName %type_TranslucentBasePass 118 "TranslucentBasePass_Shared_PlanarReflection_PlanarReflectionYAxis" + OpMemberName %type_TranslucentBasePass 119 "TranslucentBasePass_Shared_PlanarReflection_InverseTransposeMirrorMatrix" + OpMemberName %type_TranslucentBasePass 120 "TranslucentBasePass_Shared_PlanarReflection_PlanarReflectionParameters" + OpMemberName %type_TranslucentBasePass 121 "PrePadding_TranslucentBasePass_Shared_PlanarReflection_1484" + OpMemberName %type_TranslucentBasePass 122 "TranslucentBasePass_Shared_PlanarReflection_PlanarReflectionParameters2" + OpMemberName %type_TranslucentBasePass 123 "PrePadding_TranslucentBasePass_Shared_PlanarReflection_1496" + OpMemberName %type_TranslucentBasePass 124 "PrePadding_TranslucentBasePass_Shared_PlanarReflection_1500" + OpMemberName %type_TranslucentBasePass 125 "TranslucentBasePass_Shared_PlanarReflection_ProjectionWithExtraFOV" + OpMemberName %type_TranslucentBasePass 126 "TranslucentBasePass_Shared_PlanarReflection_PlanarReflectionScreenScaleBias" + OpMemberName %type_TranslucentBasePass 127 "TranslucentBasePass_Shared_PlanarReflection_PlanarReflectionScreenBound" + OpMemberName %type_TranslucentBasePass 128 "TranslucentBasePass_Shared_PlanarReflection_bIsStereo" + OpMemberName %type_TranslucentBasePass 129 "PrePadding_TranslucentBasePass_Shared_Fog_1676" + OpMemberName %type_TranslucentBasePass 130 "PrePadding_TranslucentBasePass_Shared_Fog_1680" + OpMemberName %type_TranslucentBasePass 131 "PrePadding_TranslucentBasePass_Shared_Fog_1684" + OpMemberName %type_TranslucentBasePass 132 "PrePadding_TranslucentBasePass_Shared_Fog_1688" + OpMemberName %type_TranslucentBasePass 133 "PrePadding_TranslucentBasePass_Shared_Fog_1692" + OpMemberName %type_TranslucentBasePass 134 "TranslucentBasePass_Shared_Fog_ExponentialFogParameters" + OpMemberName %type_TranslucentBasePass 135 "TranslucentBasePass_Shared_Fog_ExponentialFogParameters2" + OpMemberName %type_TranslucentBasePass 136 "TranslucentBasePass_Shared_Fog_ExponentialFogColorParameter" + OpMemberName %type_TranslucentBasePass 137 "TranslucentBasePass_Shared_Fog_ExponentialFogParameters3" + OpMemberName %type_TranslucentBasePass 138 "TranslucentBasePass_Shared_Fog_InscatteringLightDirection" + OpMemberName %type_TranslucentBasePass 139 "TranslucentBasePass_Shared_Fog_DirectionalInscatteringColor" + OpMemberName %type_TranslucentBasePass 140 "TranslucentBasePass_Shared_Fog_SinCosInscatteringColorCubemapRotation" + OpMemberName %type_TranslucentBasePass 141 "PrePadding_TranslucentBasePass_Shared_Fog_1800" + OpMemberName %type_TranslucentBasePass 142 "PrePadding_TranslucentBasePass_Shared_Fog_1804" + OpMemberName %type_TranslucentBasePass 143 "TranslucentBasePass_Shared_Fog_FogInscatteringTextureParameters" + OpMemberName %type_TranslucentBasePass 144 "TranslucentBasePass_Shared_Fog_ApplyVolumetricFog" + OpMemberName %type_TranslucentBasePass 145 "PrePadding_TranslucentBasePass_1824" + OpMemberName %type_TranslucentBasePass 146 "PrePadding_TranslucentBasePass_1828" + OpMemberName %type_TranslucentBasePass 147 "PrePadding_TranslucentBasePass_1832" + OpMemberName %type_TranslucentBasePass 148 "PrePadding_TranslucentBasePass_1836" + OpMemberName %type_TranslucentBasePass 149 "PrePadding_TranslucentBasePass_1840" + OpMemberName %type_TranslucentBasePass 150 "PrePadding_TranslucentBasePass_1844" + OpMemberName %type_TranslucentBasePass 151 "PrePadding_TranslucentBasePass_1848" + OpMemberName %type_TranslucentBasePass 152 "PrePadding_TranslucentBasePass_1852" + OpMemberName %type_TranslucentBasePass 153 "PrePadding_TranslucentBasePass_1856" + OpMemberName %type_TranslucentBasePass 154 "PrePadding_TranslucentBasePass_1860" + OpMemberName %type_TranslucentBasePass 155 "PrePadding_TranslucentBasePass_1864" + OpMemberName %type_TranslucentBasePass 156 "PrePadding_TranslucentBasePass_1868" + OpMemberName %type_TranslucentBasePass 157 "PrePadding_TranslucentBasePass_1872" + OpMemberName %type_TranslucentBasePass 158 "PrePadding_TranslucentBasePass_1876" + OpMemberName %type_TranslucentBasePass 159 "PrePadding_TranslucentBasePass_1880" + OpMemberName %type_TranslucentBasePass 160 "PrePadding_TranslucentBasePass_1884" + OpMemberName %type_TranslucentBasePass 161 "PrePadding_TranslucentBasePass_1888" + OpMemberName %type_TranslucentBasePass 162 "PrePadding_TranslucentBasePass_1892" + OpMemberName %type_TranslucentBasePass 163 "PrePadding_TranslucentBasePass_1896" + OpMemberName %type_TranslucentBasePass 164 "PrePadding_TranslucentBasePass_1900" + OpMemberName %type_TranslucentBasePass 165 "PrePadding_TranslucentBasePass_1904" + OpMemberName %type_TranslucentBasePass 166 "PrePadding_TranslucentBasePass_1908" + OpMemberName %type_TranslucentBasePass 167 "PrePadding_TranslucentBasePass_1912" + OpMemberName %type_TranslucentBasePass 168 "PrePadding_TranslucentBasePass_1916" + OpMemberName %type_TranslucentBasePass 169 "PrePadding_TranslucentBasePass_1920" + OpMemberName %type_TranslucentBasePass 170 "PrePadding_TranslucentBasePass_1924" + OpMemberName %type_TranslucentBasePass 171 "PrePadding_TranslucentBasePass_1928" + OpMemberName %type_TranslucentBasePass 172 "PrePadding_TranslucentBasePass_1932" + OpMemberName %type_TranslucentBasePass 173 "PrePadding_TranslucentBasePass_1936" + OpMemberName %type_TranslucentBasePass 174 "PrePadding_TranslucentBasePass_1940" + OpMemberName %type_TranslucentBasePass 175 "PrePadding_TranslucentBasePass_1944" + OpMemberName %type_TranslucentBasePass 176 "PrePadding_TranslucentBasePass_1948" + OpMemberName %type_TranslucentBasePass 177 "PrePadding_TranslucentBasePass_1952" + OpMemberName %type_TranslucentBasePass 178 "PrePadding_TranslucentBasePass_1956" + OpMemberName %type_TranslucentBasePass 179 "PrePadding_TranslucentBasePass_1960" + OpMemberName %type_TranslucentBasePass 180 "PrePadding_TranslucentBasePass_1964" + OpMemberName %type_TranslucentBasePass 181 "PrePadding_TranslucentBasePass_1968" + OpMemberName %type_TranslucentBasePass 182 "PrePadding_TranslucentBasePass_1972" + OpMemberName %type_TranslucentBasePass 183 "PrePadding_TranslucentBasePass_1976" + OpMemberName %type_TranslucentBasePass 184 "PrePadding_TranslucentBasePass_1980" + OpMemberName %type_TranslucentBasePass 185 "PrePadding_TranslucentBasePass_1984" + OpMemberName %type_TranslucentBasePass 186 "PrePadding_TranslucentBasePass_1988" + OpMemberName %type_TranslucentBasePass 187 "PrePadding_TranslucentBasePass_1992" + OpMemberName %type_TranslucentBasePass 188 "PrePadding_TranslucentBasePass_1996" + OpMemberName %type_TranslucentBasePass 189 "PrePadding_TranslucentBasePass_2000" + OpMemberName %type_TranslucentBasePass 190 "PrePadding_TranslucentBasePass_2004" + OpMemberName %type_TranslucentBasePass 191 "PrePadding_TranslucentBasePass_2008" + OpMemberName %type_TranslucentBasePass 192 "PrePadding_TranslucentBasePass_2012" + OpMemberName %type_TranslucentBasePass 193 "PrePadding_TranslucentBasePass_2016" + OpMemberName %type_TranslucentBasePass 194 "PrePadding_TranslucentBasePass_2020" + OpMemberName %type_TranslucentBasePass 195 "PrePadding_TranslucentBasePass_2024" + OpMemberName %type_TranslucentBasePass 196 "PrePadding_TranslucentBasePass_2028" + OpMemberName %type_TranslucentBasePass 197 "PrePadding_TranslucentBasePass_2032" + OpMemberName %type_TranslucentBasePass 198 "PrePadding_TranslucentBasePass_2036" + OpMemberName %type_TranslucentBasePass 199 "PrePadding_TranslucentBasePass_2040" + OpMemberName %type_TranslucentBasePass 200 "PrePadding_TranslucentBasePass_2044" + OpMemberName %type_TranslucentBasePass 201 "PrePadding_TranslucentBasePass_2048" + OpMemberName %type_TranslucentBasePass 202 "PrePadding_TranslucentBasePass_2052" + OpMemberName %type_TranslucentBasePass 203 "PrePadding_TranslucentBasePass_2056" + OpMemberName %type_TranslucentBasePass 204 "PrePadding_TranslucentBasePass_2060" + OpMemberName %type_TranslucentBasePass 205 "PrePadding_TranslucentBasePass_2064" + OpMemberName %type_TranslucentBasePass 206 "PrePadding_TranslucentBasePass_2068" + OpMemberName %type_TranslucentBasePass 207 "PrePadding_TranslucentBasePass_2072" + OpMemberName %type_TranslucentBasePass 208 "PrePadding_TranslucentBasePass_2076" + OpMemberName %type_TranslucentBasePass 209 "PrePadding_TranslucentBasePass_2080" + OpMemberName %type_TranslucentBasePass 210 "PrePadding_TranslucentBasePass_2084" + OpMemberName %type_TranslucentBasePass 211 "PrePadding_TranslucentBasePass_2088" + OpMemberName %type_TranslucentBasePass 212 "PrePadding_TranslucentBasePass_2092" + OpMemberName %type_TranslucentBasePass 213 "PrePadding_TranslucentBasePass_2096" + OpMemberName %type_TranslucentBasePass 214 "PrePadding_TranslucentBasePass_2100" + OpMemberName %type_TranslucentBasePass 215 "PrePadding_TranslucentBasePass_2104" + OpMemberName %type_TranslucentBasePass 216 "PrePadding_TranslucentBasePass_2108" + OpMemberName %type_TranslucentBasePass 217 "PrePadding_TranslucentBasePass_2112" + OpMemberName %type_TranslucentBasePass 218 "PrePadding_TranslucentBasePass_2116" + OpMemberName %type_TranslucentBasePass 219 "PrePadding_TranslucentBasePass_2120" + OpMemberName %type_TranslucentBasePass 220 "PrePadding_TranslucentBasePass_2124" + OpMemberName %type_TranslucentBasePass 221 "PrePadding_TranslucentBasePass_2128" + OpMemberName %type_TranslucentBasePass 222 "PrePadding_TranslucentBasePass_2132" + OpMemberName %type_TranslucentBasePass 223 "PrePadding_TranslucentBasePass_2136" + OpMemberName %type_TranslucentBasePass 224 "PrePadding_TranslucentBasePass_2140" + OpMemberName %type_TranslucentBasePass 225 "TranslucentBasePass_HZBUvFactorAndInvFactor" + OpMemberName %type_TranslucentBasePass 226 "TranslucentBasePass_PrevScreenPositionScaleBias" + OpMemberName %type_TranslucentBasePass 227 "TranslucentBasePass_PrevSceneColorPreExposureInv" + OpName %TranslucentBasePass "TranslucentBasePass" + OpName %TranslucentBasePass_Shared_Fog_IntegratedLightScattering "TranslucentBasePass_Shared_Fog_IntegratedLightScattering" + OpName %type_Material "type.Material" + OpMemberName %type_Material 0 "Material_VectorExpressions" + OpMemberName %type_Material 1 "Material_ScalarExpressions" + OpName %Material "Material" + OpName %in_var_TEXCOORD10_centroid "in.var.TEXCOORD10_centroid" + OpName %in_var_TEXCOORD11_centroid "in.var.TEXCOORD11_centroid" + OpName %in_var_PRIMITIVE_ID "in.var.PRIMITIVE_ID" + OpName %in_var_TEXCOORD7 "in.var.TEXCOORD7" + OpName %out_var_SV_Target0 "out.var.SV_Target0" + OpName %MainPS "MainPS" + OpName %type_sampled_image "type.sampled.image" + OpDecorateString %in_var_TEXCOORD10_centroid UserSemantic "TEXCOORD10_centroid" + OpDecorateString %in_var_TEXCOORD11_centroid UserSemantic "TEXCOORD11_centroid" + OpDecorateString %in_var_PRIMITIVE_ID UserSemantic "PRIMITIVE_ID" + OpDecorate %in_var_PRIMITIVE_ID Flat + OpDecorateString %in_var_TEXCOORD7 UserSemantic "TEXCOORD7" + OpDecorate %gl_FragCoord BuiltIn FragCoord + OpDecorateString %gl_FragCoord UserSemantic "SV_Position" + OpDecorate %gl_FrontFacing BuiltIn FrontFacing + OpDecorateString %gl_FrontFacing UserSemantic "SV_IsFrontFace" + OpDecorate %gl_FrontFacing Flat + OpDecorate %gl_SampleMask BuiltIn SampleMask + OpDecorateString %gl_SampleMask UserSemantic "SV_Coverage" + OpDecorate %gl_SampleMask Flat + OpDecorateString %out_var_SV_Target0 UserSemantic "SV_Target0" + OpDecorate %gl_SampleMask_0 BuiltIn SampleMask + OpDecorateString %gl_SampleMask_0 UserSemantic "SV_Coverage" + OpDecorate %in_var_TEXCOORD10_centroid Location 0 + OpDecorate %in_var_TEXCOORD11_centroid Location 1 + OpDecorate %in_var_PRIMITIVE_ID Location 2 + OpDecorate %in_var_TEXCOORD7 Location 3 + OpDecorate %out_var_SV_Target0 Location 0 + OpDecorate %View DescriptorSet 0 + OpDecorate %View Binding 1 + OpDecorate %View_SharedBilinearClampedSampler DescriptorSet 0 + OpDecorate %View_SharedBilinearClampedSampler Binding 0 + OpDecorate %View_PrimitiveSceneData DescriptorSet 0 + OpDecorate %View_PrimitiveSceneData Binding 0 + OpDecorate %TranslucentBasePass DescriptorSet 0 + OpDecorate %TranslucentBasePass Binding 2 + OpDecorate %TranslucentBasePass_Shared_Fog_IntegratedLightScattering DescriptorSet 0 + OpDecorate %TranslucentBasePass_Shared_Fog_IntegratedLightScattering Binding 0 + OpDecorate %Material DescriptorSet 0 + OpDecorate %Material Binding 3 + OpDecorate %_arr_v4float_uint_2 ArrayStride 16 + OpDecorate %_arr_v4float_uint_7 ArrayStride 16 + OpDecorate %_arr_v4float_uint_4 ArrayStride 16 + OpMemberDecorate %type_View 0 Offset 0 + OpMemberDecorate %type_View 0 MatrixStride 16 + OpMemberDecorate %type_View 0 ColMajor + OpMemberDecorate %type_View 1 Offset 64 + OpMemberDecorate %type_View 1 MatrixStride 16 + OpMemberDecorate %type_View 1 ColMajor + OpMemberDecorate %type_View 2 Offset 128 + OpMemberDecorate %type_View 2 MatrixStride 16 + OpMemberDecorate %type_View 2 ColMajor + OpMemberDecorate %type_View 3 Offset 192 + OpMemberDecorate %type_View 3 MatrixStride 16 + OpMemberDecorate %type_View 3 ColMajor + OpMemberDecorate %type_View 4 Offset 256 + OpMemberDecorate %type_View 4 MatrixStride 16 + OpMemberDecorate %type_View 4 ColMajor + OpMemberDecorate %type_View 5 Offset 320 + OpMemberDecorate %type_View 5 MatrixStride 16 + OpMemberDecorate %type_View 5 ColMajor + OpMemberDecorate %type_View 6 Offset 384 + OpMemberDecorate %type_View 6 MatrixStride 16 + OpMemberDecorate %type_View 6 ColMajor + OpMemberDecorate %type_View 7 Offset 448 + OpMemberDecorate %type_View 7 MatrixStride 16 + OpMemberDecorate %type_View 7 ColMajor + OpMemberDecorate %type_View 8 Offset 512 + OpMemberDecorate %type_View 8 MatrixStride 16 + OpMemberDecorate %type_View 8 ColMajor + OpMemberDecorate %type_View 9 Offset 576 + OpMemberDecorate %type_View 9 MatrixStride 16 + OpMemberDecorate %type_View 9 ColMajor + OpMemberDecorate %type_View 10 Offset 640 + OpMemberDecorate %type_View 10 MatrixStride 16 + OpMemberDecorate %type_View 10 ColMajor + OpMemberDecorate %type_View 11 Offset 704 + OpMemberDecorate %type_View 11 MatrixStride 16 + OpMemberDecorate %type_View 11 ColMajor + OpMemberDecorate %type_View 12 Offset 768 + OpMemberDecorate %type_View 12 MatrixStride 16 + OpMemberDecorate %type_View 12 ColMajor + OpMemberDecorate %type_View 13 Offset 832 + OpMemberDecorate %type_View 14 Offset 844 + OpMemberDecorate %type_View 15 Offset 848 + OpMemberDecorate %type_View 16 Offset 860 + OpMemberDecorate %type_View 17 Offset 864 + OpMemberDecorate %type_View 18 Offset 876 + OpMemberDecorate %type_View 19 Offset 880 + OpMemberDecorate %type_View 20 Offset 892 + OpMemberDecorate %type_View 21 Offset 896 + OpMemberDecorate %type_View 22 Offset 908 + OpMemberDecorate %type_View 23 Offset 912 + OpMemberDecorate %type_View 24 Offset 928 + OpMemberDecorate %type_View 25 Offset 944 + OpMemberDecorate %type_View 26 Offset 956 + OpMemberDecorate %type_View 27 Offset 960 + OpMemberDecorate %type_View 28 Offset 972 + OpMemberDecorate %type_View 29 Offset 976 + OpMemberDecorate %type_View 30 Offset 988 + OpMemberDecorate %type_View 31 Offset 992 + OpMemberDecorate %type_View 32 Offset 1004 + OpMemberDecorate %type_View 33 Offset 1008 + OpMemberDecorate %type_View 33 MatrixStride 16 + OpMemberDecorate %type_View 33 ColMajor + OpMemberDecorate %type_View 34 Offset 1072 + OpMemberDecorate %type_View 34 MatrixStride 16 + OpMemberDecorate %type_View 34 ColMajor + OpMemberDecorate %type_View 35 Offset 1136 + OpMemberDecorate %type_View 35 MatrixStride 16 + OpMemberDecorate %type_View 35 ColMajor + OpMemberDecorate %type_View 36 Offset 1200 + OpMemberDecorate %type_View 36 MatrixStride 16 + OpMemberDecorate %type_View 36 ColMajor + OpMemberDecorate %type_View 37 Offset 1264 + OpMemberDecorate %type_View 37 MatrixStride 16 + OpMemberDecorate %type_View 37 ColMajor + OpMemberDecorate %type_View 38 Offset 1328 + OpMemberDecorate %type_View 38 MatrixStride 16 + OpMemberDecorate %type_View 38 ColMajor + OpMemberDecorate %type_View 39 Offset 1392 + OpMemberDecorate %type_View 39 MatrixStride 16 + OpMemberDecorate %type_View 39 ColMajor + OpMemberDecorate %type_View 40 Offset 1456 + OpMemberDecorate %type_View 40 MatrixStride 16 + OpMemberDecorate %type_View 40 ColMajor + OpMemberDecorate %type_View 41 Offset 1520 + OpMemberDecorate %type_View 41 MatrixStride 16 + OpMemberDecorate %type_View 41 ColMajor + OpMemberDecorate %type_View 42 Offset 1584 + OpMemberDecorate %type_View 42 MatrixStride 16 + OpMemberDecorate %type_View 42 ColMajor + OpMemberDecorate %type_View 43 Offset 1648 + OpMemberDecorate %type_View 44 Offset 1660 + OpMemberDecorate %type_View 45 Offset 1664 + OpMemberDecorate %type_View 46 Offset 1676 + OpMemberDecorate %type_View 47 Offset 1680 + OpMemberDecorate %type_View 48 Offset 1692 + OpMemberDecorate %type_View 49 Offset 1696 + OpMemberDecorate %type_View 49 MatrixStride 16 + OpMemberDecorate %type_View 49 ColMajor + OpMemberDecorate %type_View 50 Offset 1760 + OpMemberDecorate %type_View 50 MatrixStride 16 + OpMemberDecorate %type_View 50 ColMajor + OpMemberDecorate %type_View 51 Offset 1824 + OpMemberDecorate %type_View 51 MatrixStride 16 + OpMemberDecorate %type_View 51 ColMajor + OpMemberDecorate %type_View 52 Offset 1888 + OpMemberDecorate %type_View 53 Offset 1904 + OpMemberDecorate %type_View 54 Offset 1920 + OpMemberDecorate %type_View 55 Offset 1928 + OpMemberDecorate %type_View 56 Offset 1936 + OpMemberDecorate %type_View 57 Offset 1952 + OpMemberDecorate %type_View 58 Offset 1968 + OpMemberDecorate %type_View 59 Offset 1984 + OpMemberDecorate %type_View 60 Offset 2000 + OpMemberDecorate %type_View 61 Offset 2004 + OpMemberDecorate %type_View 62 Offset 2008 + OpMemberDecorate %type_View 63 Offset 2012 + OpMemberDecorate %type_View 64 Offset 2016 + OpMemberDecorate %type_View 65 Offset 2032 + OpMemberDecorate %type_View 66 Offset 2048 + OpMemberDecorate %type_View 67 Offset 2064 + OpMemberDecorate %type_View 68 Offset 2072 + OpMemberDecorate %type_View 69 Offset 2076 + OpMemberDecorate %type_View 70 Offset 2080 + OpMemberDecorate %type_View 71 Offset 2084 + OpMemberDecorate %type_View 72 Offset 2088 + OpMemberDecorate %type_View 73 Offset 2092 + OpMemberDecorate %type_View 74 Offset 2096 + OpMemberDecorate %type_View 75 Offset 2108 + OpMemberDecorate %type_View 76 Offset 2112 + OpMemberDecorate %type_View 77 Offset 2116 + OpMemberDecorate %type_View 78 Offset 2120 + OpMemberDecorate %type_View 79 Offset 2124 + OpMemberDecorate %type_View 80 Offset 2128 + OpMemberDecorate %type_View 81 Offset 2132 + OpMemberDecorate %type_View 82 Offset 2136 + OpMemberDecorate %type_View 83 Offset 2140 + OpMemberDecorate %type_View 84 Offset 2144 + OpMemberDecorate %type_View 85 Offset 2148 + OpMemberDecorate %type_View 86 Offset 2152 + OpMemberDecorate %type_View 87 Offset 2156 + OpMemberDecorate %type_View 88 Offset 2160 + OpMemberDecorate %type_View 89 Offset 2164 + OpMemberDecorate %type_View 90 Offset 2168 + OpMemberDecorate %type_View 91 Offset 2172 + OpMemberDecorate %type_View 92 Offset 2176 + OpMemberDecorate %type_View 93 Offset 2192 + OpMemberDecorate %type_View 94 Offset 2204 + OpMemberDecorate %type_View 95 Offset 2208 + OpMemberDecorate %type_View 96 Offset 2240 + OpMemberDecorate %type_View 97 Offset 2272 + OpMemberDecorate %type_View 98 Offset 2288 + OpMemberDecorate %type_View 99 Offset 2304 + OpMemberDecorate %type_View 100 Offset 2308 + OpMemberDecorate %type_View 101 Offset 2312 + OpMemberDecorate %type_View 102 Offset 2316 + OpMemberDecorate %type_View 103 Offset 2320 + OpMemberDecorate %type_View 104 Offset 2324 + OpMemberDecorate %type_View 105 Offset 2328 + OpMemberDecorate %type_View 106 Offset 2332 + OpMemberDecorate %type_View 107 Offset 2336 + OpMemberDecorate %type_View 108 Offset 2340 + OpMemberDecorate %type_View 109 Offset 2344 + OpMemberDecorate %type_View 110 Offset 2348 + OpMemberDecorate %type_View 111 Offset 2352 + OpMemberDecorate %type_View 112 Offset 2364 + OpMemberDecorate %type_View 113 Offset 2368 + OpMemberDecorate %type_View 114 Offset 2380 + OpMemberDecorate %type_View 115 Offset 2384 + OpMemberDecorate %type_View 116 Offset 2388 + OpMemberDecorate %type_View 117 Offset 2392 + OpMemberDecorate %type_View 118 Offset 2396 + OpMemberDecorate %type_View 119 Offset 2400 + OpMemberDecorate %type_View 120 Offset 2404 + OpMemberDecorate %type_View 121 Offset 2408 + OpMemberDecorate %type_View 122 Offset 2412 + OpMemberDecorate %type_View 123 Offset 2416 + OpMemberDecorate %type_View 124 Offset 2420 + OpMemberDecorate %type_View 125 Offset 2424 + OpMemberDecorate %type_View 126 Offset 2428 + OpMemberDecorate %type_View 127 Offset 2432 + OpMemberDecorate %type_View 128 Offset 2448 + OpMemberDecorate %type_View 129 Offset 2460 + OpMemberDecorate %type_View 130 Offset 2464 + OpMemberDecorate %type_View 131 Offset 2480 + OpMemberDecorate %type_View 132 Offset 2484 + OpMemberDecorate %type_View 133 Offset 2488 + OpMemberDecorate %type_View 134 Offset 2492 + OpMemberDecorate %type_View 135 Offset 2496 + OpMemberDecorate %type_View 136 Offset 2512 + OpMemberDecorate %type_View 137 Offset 2624 + OpMemberDecorate %type_View 138 Offset 2628 + OpMemberDecorate %type_View 139 Offset 2632 + OpMemberDecorate %type_View 140 Offset 2636 + OpMemberDecorate %type_View 141 Offset 2640 + OpMemberDecorate %type_View 142 Offset 2644 + OpMemberDecorate %type_View 143 Offset 2648 + OpMemberDecorate %type_View 144 Offset 2652 + OpMemberDecorate %type_View 145 Offset 2656 + OpMemberDecorate %type_View 146 Offset 2668 + OpMemberDecorate %type_View 147 Offset 2672 + OpMemberDecorate %type_View 148 Offset 2736 + OpMemberDecorate %type_View 149 Offset 2800 + OpMemberDecorate %type_View 150 Offset 2804 + OpMemberDecorate %type_View 151 Offset 2808 + OpMemberDecorate %type_View 152 Offset 2812 + OpMemberDecorate %type_View 153 Offset 2816 + OpMemberDecorate %type_View 154 Offset 2828 + OpMemberDecorate %type_View 155 Offset 2832 + OpMemberDecorate %type_View 156 Offset 2844 + OpMemberDecorate %type_View 157 Offset 2848 + OpMemberDecorate %type_View 158 Offset 2856 + OpMemberDecorate %type_View 159 Offset 2860 + OpMemberDecorate %type_View 160 Offset 2864 + OpMemberDecorate %type_View 161 Offset 2876 + OpMemberDecorate %type_View 162 Offset 2880 + OpMemberDecorate %type_View 163 Offset 2892 + OpMemberDecorate %type_View 164 Offset 2896 + OpMemberDecorate %type_View 165 Offset 2908 + OpMemberDecorate %type_View 166 Offset 2912 + OpMemberDecorate %type_View 167 Offset 2924 + OpMemberDecorate %type_View 168 Offset 2928 + OpMemberDecorate %type_View 169 Offset 2932 + OpDecorate %type_View Block + OpDecorate %_runtimearr_v4float ArrayStride 16 + OpMemberDecorate %type_StructuredBuffer_v4float 0 Offset 0 + OpMemberDecorate %type_StructuredBuffer_v4float 0 NonWritable + OpDecorate %type_StructuredBuffer_v4float BufferBlock + OpDecorate %_arr_mat4v4float_uint_4 ArrayStride 64 + OpDecorate %_arr_mat4v4float_uint_2 ArrayStride 64 + OpMemberDecorate %type_TranslucentBasePass 0 Offset 0 + OpMemberDecorate %type_TranslucentBasePass 1 Offset 4 + OpMemberDecorate %type_TranslucentBasePass 2 Offset 8 + OpMemberDecorate %type_TranslucentBasePass 3 Offset 12 + OpMemberDecorate %type_TranslucentBasePass 4 Offset 16 + OpMemberDecorate %type_TranslucentBasePass 5 Offset 28 + OpMemberDecorate %type_TranslucentBasePass 6 Offset 32 + OpMemberDecorate %type_TranslucentBasePass 7 Offset 36 + OpMemberDecorate %type_TranslucentBasePass 8 Offset 40 + OpMemberDecorate %type_TranslucentBasePass 9 Offset 44 + OpMemberDecorate %type_TranslucentBasePass 10 Offset 48 + OpMemberDecorate %type_TranslucentBasePass 11 Offset 60 + OpMemberDecorate %type_TranslucentBasePass 12 Offset 64 + OpMemberDecorate %type_TranslucentBasePass 13 Offset 76 + OpMemberDecorate %type_TranslucentBasePass 14 Offset 80 + OpMemberDecorate %type_TranslucentBasePass 15 Offset 92 + OpMemberDecorate %type_TranslucentBasePass 16 Offset 96 + OpMemberDecorate %type_TranslucentBasePass 17 Offset 100 + OpMemberDecorate %type_TranslucentBasePass 18 Offset 104 + OpMemberDecorate %type_TranslucentBasePass 19 Offset 112 + OpMemberDecorate %type_TranslucentBasePass 20 Offset 116 + OpMemberDecorate %type_TranslucentBasePass 21 Offset 120 + OpMemberDecorate %type_TranslucentBasePass 22 Offset 124 + OpMemberDecorate %type_TranslucentBasePass 23 Offset 128 + OpMemberDecorate %type_TranslucentBasePass 24 Offset 144 + OpMemberDecorate %type_TranslucentBasePass 24 MatrixStride 16 + OpMemberDecorate %type_TranslucentBasePass 24 ColMajor + OpMemberDecorate %type_TranslucentBasePass 25 Offset 400 + OpMemberDecorate %type_TranslucentBasePass 26 Offset 464 + OpMemberDecorate %type_TranslucentBasePass 27 Offset 480 + OpMemberDecorate %type_TranslucentBasePass 28 Offset 484 + OpMemberDecorate %type_TranslucentBasePass 29 Offset 488 + OpMemberDecorate %type_TranslucentBasePass 30 Offset 492 + OpMemberDecorate %type_TranslucentBasePass 31 Offset 496 + OpMemberDecorate %type_TranslucentBasePass 32 Offset 512 + OpMemberDecorate %type_TranslucentBasePass 32 MatrixStride 16 + OpMemberDecorate %type_TranslucentBasePass 32 ColMajor + OpMemberDecorate %type_TranslucentBasePass 33 Offset 576 + OpMemberDecorate %type_TranslucentBasePass 34 Offset 580 + OpMemberDecorate %type_TranslucentBasePass 35 Offset 584 + OpMemberDecorate %type_TranslucentBasePass 36 Offset 588 + OpMemberDecorate %type_TranslucentBasePass 37 Offset 592 + OpMemberDecorate %type_TranslucentBasePass 38 Offset 596 + OpMemberDecorate %type_TranslucentBasePass 39 Offset 600 + OpMemberDecorate %type_TranslucentBasePass 40 Offset 604 + OpMemberDecorate %type_TranslucentBasePass 41 Offset 608 + OpMemberDecorate %type_TranslucentBasePass 42 Offset 612 + OpMemberDecorate %type_TranslucentBasePass 43 Offset 616 + OpMemberDecorate %type_TranslucentBasePass 44 Offset 620 + OpMemberDecorate %type_TranslucentBasePass 45 Offset 624 + OpMemberDecorate %type_TranslucentBasePass 46 Offset 628 + OpMemberDecorate %type_TranslucentBasePass 47 Offset 632 + OpMemberDecorate %type_TranslucentBasePass 48 Offset 636 + OpMemberDecorate %type_TranslucentBasePass 49 Offset 640 + OpMemberDecorate %type_TranslucentBasePass 50 Offset 644 + OpMemberDecorate %type_TranslucentBasePass 51 Offset 648 + OpMemberDecorate %type_TranslucentBasePass 52 Offset 652 + OpMemberDecorate %type_TranslucentBasePass 53 Offset 656 + OpMemberDecorate %type_TranslucentBasePass 54 Offset 668 + OpMemberDecorate %type_TranslucentBasePass 55 Offset 672 + OpMemberDecorate %type_TranslucentBasePass 56 Offset 676 + OpMemberDecorate %type_TranslucentBasePass 57 Offset 680 + OpMemberDecorate %type_TranslucentBasePass 58 Offset 684 + OpMemberDecorate %type_TranslucentBasePass 59 Offset 688 + OpMemberDecorate %type_TranslucentBasePass 60 Offset 700 + OpMemberDecorate %type_TranslucentBasePass 61 Offset 704 + OpMemberDecorate %type_TranslucentBasePass 62 Offset 716 + OpMemberDecorate %type_TranslucentBasePass 63 Offset 720 + OpMemberDecorate %type_TranslucentBasePass 64 Offset 732 + OpMemberDecorate %type_TranslucentBasePass 65 Offset 736 + OpMemberDecorate %type_TranslucentBasePass 66 Offset 740 + OpMemberDecorate %type_TranslucentBasePass 67 Offset 744 + OpMemberDecorate %type_TranslucentBasePass 68 Offset 752 + OpMemberDecorate %type_TranslucentBasePass 69 Offset 756 + OpMemberDecorate %type_TranslucentBasePass 70 Offset 760 + OpMemberDecorate %type_TranslucentBasePass 71 Offset 764 + OpMemberDecorate %type_TranslucentBasePass 72 Offset 768 + OpMemberDecorate %type_TranslucentBasePass 73 Offset 784 + OpMemberDecorate %type_TranslucentBasePass 73 MatrixStride 16 + OpMemberDecorate %type_TranslucentBasePass 73 ColMajor + OpMemberDecorate %type_TranslucentBasePass 74 Offset 1040 + OpMemberDecorate %type_TranslucentBasePass 75 Offset 1104 + OpMemberDecorate %type_TranslucentBasePass 76 Offset 1120 + OpMemberDecorate %type_TranslucentBasePass 77 Offset 1124 + OpMemberDecorate %type_TranslucentBasePass 78 Offset 1128 + OpMemberDecorate %type_TranslucentBasePass 79 Offset 1132 + OpMemberDecorate %type_TranslucentBasePass 80 Offset 1136 + OpMemberDecorate %type_TranslucentBasePass 81 Offset 1152 + OpMemberDecorate %type_TranslucentBasePass 81 MatrixStride 16 + OpMemberDecorate %type_TranslucentBasePass 81 ColMajor + OpMemberDecorate %type_TranslucentBasePass 82 Offset 1216 + OpMemberDecorate %type_TranslucentBasePass 83 Offset 1220 + OpMemberDecorate %type_TranslucentBasePass 84 Offset 1224 + OpMemberDecorate %type_TranslucentBasePass 85 Offset 1228 + OpMemberDecorate %type_TranslucentBasePass 86 Offset 1232 + OpMemberDecorate %type_TranslucentBasePass 87 Offset 1236 + OpMemberDecorate %type_TranslucentBasePass 88 Offset 1240 + OpMemberDecorate %type_TranslucentBasePass 89 Offset 1244 + OpMemberDecorate %type_TranslucentBasePass 90 Offset 1248 + OpMemberDecorate %type_TranslucentBasePass 91 Offset 1252 + OpMemberDecorate %type_TranslucentBasePass 92 Offset 1256 + OpMemberDecorate %type_TranslucentBasePass 93 Offset 1260 + OpMemberDecorate %type_TranslucentBasePass 94 Offset 1264 + OpMemberDecorate %type_TranslucentBasePass 95 Offset 1268 + OpMemberDecorate %type_TranslucentBasePass 96 Offset 1272 + OpMemberDecorate %type_TranslucentBasePass 97 Offset 1276 + OpMemberDecorate %type_TranslucentBasePass 98 Offset 1280 + OpMemberDecorate %type_TranslucentBasePass 99 Offset 1296 + OpMemberDecorate %type_TranslucentBasePass 100 Offset 1300 + OpMemberDecorate %type_TranslucentBasePass 101 Offset 1304 + OpMemberDecorate %type_TranslucentBasePass 102 Offset 1308 + OpMemberDecorate %type_TranslucentBasePass 103 Offset 1312 + OpMemberDecorate %type_TranslucentBasePass 104 Offset 1316 + OpMemberDecorate %type_TranslucentBasePass 105 Offset 1320 + OpMemberDecorate %type_TranslucentBasePass 106 Offset 1324 + OpMemberDecorate %type_TranslucentBasePass 107 Offset 1328 + OpMemberDecorate %type_TranslucentBasePass 108 Offset 1332 + OpMemberDecorate %type_TranslucentBasePass 109 Offset 1336 + OpMemberDecorate %type_TranslucentBasePass 110 Offset 1340 + OpMemberDecorate %type_TranslucentBasePass 111 Offset 1344 + OpMemberDecorate %type_TranslucentBasePass 112 Offset 1348 + OpMemberDecorate %type_TranslucentBasePass 113 Offset 1352 + OpMemberDecorate %type_TranslucentBasePass 114 Offset 1356 + OpMemberDecorate %type_TranslucentBasePass 115 Offset 1360 + OpMemberDecorate %type_TranslucentBasePass 116 Offset 1376 + OpMemberDecorate %type_TranslucentBasePass 117 Offset 1392 + OpMemberDecorate %type_TranslucentBasePass 118 Offset 1408 + OpMemberDecorate %type_TranslucentBasePass 119 Offset 1424 + OpMemberDecorate %type_TranslucentBasePass 119 MatrixStride 16 + OpMemberDecorate %type_TranslucentBasePass 119 ColMajor + OpMemberDecorate %type_TranslucentBasePass 120 Offset 1472 + OpMemberDecorate %type_TranslucentBasePass 121 Offset 1484 + OpMemberDecorate %type_TranslucentBasePass 122 Offset 1488 + OpMemberDecorate %type_TranslucentBasePass 123 Offset 1496 + OpMemberDecorate %type_TranslucentBasePass 124 Offset 1500 + OpMemberDecorate %type_TranslucentBasePass 125 Offset 1504 + OpMemberDecorate %type_TranslucentBasePass 125 MatrixStride 16 + OpMemberDecorate %type_TranslucentBasePass 125 ColMajor + OpMemberDecorate %type_TranslucentBasePass 126 Offset 1632 + OpMemberDecorate %type_TranslucentBasePass 127 Offset 1664 + OpMemberDecorate %type_TranslucentBasePass 128 Offset 1672 + OpMemberDecorate %type_TranslucentBasePass 129 Offset 1676 + OpMemberDecorate %type_TranslucentBasePass 130 Offset 1680 + OpMemberDecorate %type_TranslucentBasePass 131 Offset 1684 + OpMemberDecorate %type_TranslucentBasePass 132 Offset 1688 + OpMemberDecorate %type_TranslucentBasePass 133 Offset 1692 + OpMemberDecorate %type_TranslucentBasePass 134 Offset 1696 + OpMemberDecorate %type_TranslucentBasePass 135 Offset 1712 + OpMemberDecorate %type_TranslucentBasePass 136 Offset 1728 + OpMemberDecorate %type_TranslucentBasePass 137 Offset 1744 + OpMemberDecorate %type_TranslucentBasePass 138 Offset 1760 + OpMemberDecorate %type_TranslucentBasePass 139 Offset 1776 + OpMemberDecorate %type_TranslucentBasePass 140 Offset 1792 + OpMemberDecorate %type_TranslucentBasePass 141 Offset 1800 + OpMemberDecorate %type_TranslucentBasePass 142 Offset 1804 + OpMemberDecorate %type_TranslucentBasePass 143 Offset 1808 + OpMemberDecorate %type_TranslucentBasePass 144 Offset 1820 + OpMemberDecorate %type_TranslucentBasePass 145 Offset 1824 + OpMemberDecorate %type_TranslucentBasePass 146 Offset 1828 + OpMemberDecorate %type_TranslucentBasePass 147 Offset 1832 + OpMemberDecorate %type_TranslucentBasePass 148 Offset 1836 + OpMemberDecorate %type_TranslucentBasePass 149 Offset 1840 + OpMemberDecorate %type_TranslucentBasePass 150 Offset 1844 + OpMemberDecorate %type_TranslucentBasePass 151 Offset 1848 + OpMemberDecorate %type_TranslucentBasePass 152 Offset 1852 + OpMemberDecorate %type_TranslucentBasePass 153 Offset 1856 + OpMemberDecorate %type_TranslucentBasePass 154 Offset 1860 + OpMemberDecorate %type_TranslucentBasePass 155 Offset 1864 + OpMemberDecorate %type_TranslucentBasePass 156 Offset 1868 + OpMemberDecorate %type_TranslucentBasePass 157 Offset 1872 + OpMemberDecorate %type_TranslucentBasePass 158 Offset 1876 + OpMemberDecorate %type_TranslucentBasePass 159 Offset 1880 + OpMemberDecorate %type_TranslucentBasePass 160 Offset 1884 + OpMemberDecorate %type_TranslucentBasePass 161 Offset 1888 + OpMemberDecorate %type_TranslucentBasePass 162 Offset 1892 + OpMemberDecorate %type_TranslucentBasePass 163 Offset 1896 + OpMemberDecorate %type_TranslucentBasePass 164 Offset 1900 + OpMemberDecorate %type_TranslucentBasePass 165 Offset 1904 + OpMemberDecorate %type_TranslucentBasePass 166 Offset 1908 + OpMemberDecorate %type_TranslucentBasePass 167 Offset 1912 + OpMemberDecorate %type_TranslucentBasePass 168 Offset 1916 + OpMemberDecorate %type_TranslucentBasePass 169 Offset 1920 + OpMemberDecorate %type_TranslucentBasePass 170 Offset 1924 + OpMemberDecorate %type_TranslucentBasePass 171 Offset 1928 + OpMemberDecorate %type_TranslucentBasePass 172 Offset 1932 + OpMemberDecorate %type_TranslucentBasePass 173 Offset 1936 + OpMemberDecorate %type_TranslucentBasePass 174 Offset 1940 + OpMemberDecorate %type_TranslucentBasePass 175 Offset 1944 + OpMemberDecorate %type_TranslucentBasePass 176 Offset 1948 + OpMemberDecorate %type_TranslucentBasePass 177 Offset 1952 + OpMemberDecorate %type_TranslucentBasePass 178 Offset 1956 + OpMemberDecorate %type_TranslucentBasePass 179 Offset 1960 + OpMemberDecorate %type_TranslucentBasePass 180 Offset 1964 + OpMemberDecorate %type_TranslucentBasePass 181 Offset 1968 + OpMemberDecorate %type_TranslucentBasePass 182 Offset 1972 + OpMemberDecorate %type_TranslucentBasePass 183 Offset 1976 + OpMemberDecorate %type_TranslucentBasePass 184 Offset 1980 + OpMemberDecorate %type_TranslucentBasePass 185 Offset 1984 + OpMemberDecorate %type_TranslucentBasePass 186 Offset 1988 + OpMemberDecorate %type_TranslucentBasePass 187 Offset 1992 + OpMemberDecorate %type_TranslucentBasePass 188 Offset 1996 + OpMemberDecorate %type_TranslucentBasePass 189 Offset 2000 + OpMemberDecorate %type_TranslucentBasePass 190 Offset 2004 + OpMemberDecorate %type_TranslucentBasePass 191 Offset 2008 + OpMemberDecorate %type_TranslucentBasePass 192 Offset 2012 + OpMemberDecorate %type_TranslucentBasePass 193 Offset 2016 + OpMemberDecorate %type_TranslucentBasePass 194 Offset 2020 + OpMemberDecorate %type_TranslucentBasePass 195 Offset 2024 + OpMemberDecorate %type_TranslucentBasePass 196 Offset 2028 + OpMemberDecorate %type_TranslucentBasePass 197 Offset 2032 + OpMemberDecorate %type_TranslucentBasePass 198 Offset 2036 + OpMemberDecorate %type_TranslucentBasePass 199 Offset 2040 + OpMemberDecorate %type_TranslucentBasePass 200 Offset 2044 + OpMemberDecorate %type_TranslucentBasePass 201 Offset 2048 + OpMemberDecorate %type_TranslucentBasePass 202 Offset 2052 + OpMemberDecorate %type_TranslucentBasePass 203 Offset 2056 + OpMemberDecorate %type_TranslucentBasePass 204 Offset 2060 + OpMemberDecorate %type_TranslucentBasePass 205 Offset 2064 + OpMemberDecorate %type_TranslucentBasePass 206 Offset 2068 + OpMemberDecorate %type_TranslucentBasePass 207 Offset 2072 + OpMemberDecorate %type_TranslucentBasePass 208 Offset 2076 + OpMemberDecorate %type_TranslucentBasePass 209 Offset 2080 + OpMemberDecorate %type_TranslucentBasePass 210 Offset 2084 + OpMemberDecorate %type_TranslucentBasePass 211 Offset 2088 + OpMemberDecorate %type_TranslucentBasePass 212 Offset 2092 + OpMemberDecorate %type_TranslucentBasePass 213 Offset 2096 + OpMemberDecorate %type_TranslucentBasePass 214 Offset 2100 + OpMemberDecorate %type_TranslucentBasePass 215 Offset 2104 + OpMemberDecorate %type_TranslucentBasePass 216 Offset 2108 + OpMemberDecorate %type_TranslucentBasePass 217 Offset 2112 + OpMemberDecorate %type_TranslucentBasePass 218 Offset 2116 + OpMemberDecorate %type_TranslucentBasePass 219 Offset 2120 + OpMemberDecorate %type_TranslucentBasePass 220 Offset 2124 + OpMemberDecorate %type_TranslucentBasePass 221 Offset 2128 + OpMemberDecorate %type_TranslucentBasePass 222 Offset 2132 + OpMemberDecorate %type_TranslucentBasePass 223 Offset 2136 + OpMemberDecorate %type_TranslucentBasePass 224 Offset 2140 + OpMemberDecorate %type_TranslucentBasePass 225 Offset 2144 + OpMemberDecorate %type_TranslucentBasePass 226 Offset 2160 + OpMemberDecorate %type_TranslucentBasePass 227 Offset 2176 + OpDecorate %type_TranslucentBasePass Block + OpDecorate %_arr_v4float_uint_1 ArrayStride 16 + OpMemberDecorate %type_Material 0 Offset 0 + OpMemberDecorate %type_Material 1 Offset 32 + OpDecorate %type_Material Block + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 +%mat4v4float = OpTypeMatrix %v4float 4 + %v3float = OpTypeVector %float 3 + %v2float = OpTypeVector %float 2 + %int = OpTypeInt 32 1 + %uint = OpTypeInt 32 0 + %uint_2 = OpConstant %uint 2 + %uint_7 = OpConstant %uint 7 + %uint_4 = OpConstant %uint 4 + %uint_0 = OpConstant %uint 0 + %bool = OpTypeBool + %int_1 = OpConstant %int 1 + %int_0 = OpConstant %int 0 + %int_2 = OpConstant %int 2 + %float_0 = OpConstant %float 0 + %48 = OpConstantComposite %v3float %float_0 %float_0 %float_0 + %int_10 = OpConstant %int 10 + %int_144 = OpConstant %int 144 + %int_70 = OpConstant %int 70 + %float_1 = OpConstant %float 1 + %53 = OpConstantComposite %v3float %float_1 %float_1 %float_1 +%float_0_577000022 = OpConstant %float 0.577000022 + %55 = OpConstantComposite %v3float %float_0_577000022 %float_0_577000022 %float_0_577000022 + %56 = OpConstantComposite %v3float %float_1 %float_1 %float_0 + %57 = OpConstantComposite %v3float %float_0 %float_1 %float_1 + %float_0_5 = OpConstant %float 0.5 + %59 = OpConstantComposite %v3float %float_0_5 %float_0_5 %float_0_5 + %int_60 = OpConstant %int 60 + %61 = OpConstantComposite %v2float %float_0_5 %float_0_5 + %uint_26 = OpConstant %uint 26 + %uint_1 = OpConstant %uint 1 + %uint_5 = OpConstant %uint 5 + %uint_19 = OpConstant %uint 19 + %float_n0_5 = OpConstant %float -0.5 + %67 = OpConstantComposite %v2float %float_0_5 %float_n0_5 + %68 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_1 + %float_0_25 = OpConstant %float 0.25 + %int_31 = OpConstant %int 31 + %int_66 = OpConstant %int 66 + %int_153 = OpConstant %int 153 + %int_155 = OpConstant %int 155 +%mat3v3float = OpTypeMatrix %v3float 3 + %75 = OpConstantComposite %v3float %float_0 %float_0 %float_1 + %float_n1 = OpConstant %float -1 +%float_0_200000003 = OpConstant %float 0.200000003 +%_arr_v4float_uint_2 = OpTypeArray %v4float %uint_2 +%_arr_v4float_uint_7 = OpTypeArray %v4float %uint_7 +%_arr_v4float_uint_4 = OpTypeArray %v4float %uint_4 + %type_View = OpTypeStruct %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %v3float %float %v3float %float %v3float %float %v3float %float %v3float %float %v4float %v4float %v3float %float %v3float %float %v3float %float %v3float %float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %v3float %float %v3float %float %v3float %float %mat4v4float %mat4v4float %mat4v4float %v4float %v4float %v2float %v2float %v4float %v4float %v4float %v4float %int %float %float %float %v4float %v4float %v4float %v2float %float %float %float %float %float %float %v3float %float %float %float %float %float %float %float %float %uint %uint %uint %uint %float %float %float %float %float %v4float %v3float %float %_arr_v4float_uint_2 %_arr_v4float_uint_2 %v4float %v4float %float %float %float %float %float %float %float %float %float %float %float %float %v3float %float %v3float %float %float %float %float %float %float %float %float %float %float %float %uint %uint %v4float %v3float %float %v4float %float %float %float %float %v4float %_arr_v4float_uint_7 %float %float %float %float %uint %float %float %float %v3float %int %_arr_v4float_uint_4 %_arr_v4float_uint_4 %float %float %float %float %v3float %float %v3float %float %v2float %float %float %v3float %float %v3float %float %v3float %float %v3float %float %float %float +%_ptr_Uniform_type_View = OpTypePointer Uniform %type_View +%type_3d_image = OpTypeImage %float 3D 2 0 0 1 Unknown +%_ptr_UniformConstant_type_3d_image = OpTypePointer UniformConstant %type_3d_image +%type_sampler = OpTypeSampler +%_ptr_UniformConstant_type_sampler = OpTypePointer UniformConstant %type_sampler +%_runtimearr_v4float = OpTypeRuntimeArray %v4float +%type_StructuredBuffer_v4float = OpTypeStruct %_runtimearr_v4float +%_ptr_Uniform_type_StructuredBuffer_v4float = OpTypePointer Uniform %type_StructuredBuffer_v4float + %v3int = OpTypeVector %int 3 +%_arr_mat4v4float_uint_4 = OpTypeArray %mat4v4float %uint_4 +%mat3v4float = OpTypeMatrix %v4float 3 +%_arr_mat4v4float_uint_2 = OpTypeArray %mat4v4float %uint_2 +%type_TranslucentBasePass = OpTypeStruct %uint %uint %uint %uint %v3int %uint %uint %uint %uint %uint %v3float %float %v3float %float %v3float %float %uint %uint %v2float %uint %uint %uint %uint %v4float %_arr_mat4v4float_uint_4 %_arr_v4float_uint_4 %v4float %float %uint %uint %uint %v4float %mat4v4float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %uint %uint %uint %uint %v3int %uint %uint %uint %uint %uint %v3float %float %v3float %float %v3float %float %uint %uint %v2float %uint %uint %uint %uint %v4float %_arr_mat4v4float_uint_4 %_arr_v4float_uint_4 %v4float %float %uint %uint %uint %v4float %mat4v4float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %v4float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %v4float %v4float %v4float %v4float %mat3v4float %v3float %float %v2float %float %float %_arr_mat4v4float_uint_2 %_arr_v4float_uint_2 %v2float %uint %float %float %float %float %float %v4float %v4float %v4float %v4float %v4float %v4float %v2float %float %float %v3float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %v4float %v4float %float +%_ptr_Uniform_type_TranslucentBasePass = OpTypePointer Uniform %type_TranslucentBasePass +%_arr_v4float_uint_1 = OpTypeArray %v4float %uint_1 +%type_Material = OpTypeStruct %_arr_v4float_uint_2 %_arr_v4float_uint_1 +%_ptr_Uniform_type_Material = OpTypePointer Uniform %type_Material +%_ptr_Input_v4float = OpTypePointer Input %v4float +%_ptr_Input_uint = OpTypePointer Input %uint +%_ptr_Input_bool = OpTypePointer Input %bool +%_arr_uint_uint_1 = OpTypeArray %uint %uint_1 +%_ptr_Input__arr_uint_uint_1 = OpTypePointer Input %_arr_uint_uint_1 +%_ptr_Output_v4float = OpTypePointer Output %v4float +%_ptr_Output__arr_uint_uint_1 = OpTypePointer Output %_arr_uint_uint_1 + %void = OpTypeVoid + %94 = OpTypeFunction %void +%_ptr_Output_uint = OpTypePointer Output %uint +%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float +%_ptr_Uniform_float = OpTypePointer Uniform %float + %v3bool = OpTypeVector %bool 3 +%_ptr_Uniform_int = OpTypePointer Uniform %int +%_ptr_Uniform_mat4v4float = OpTypePointer Uniform %mat4v4float +%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float +%type_sampled_image = OpTypeSampledImage %type_3d_image + %View = OpVariable %_ptr_Uniform_type_View Uniform +%View_SharedBilinearClampedSampler = OpVariable %_ptr_UniformConstant_type_sampler UniformConstant +%View_PrimitiveSceneData = OpVariable %_ptr_Uniform_type_StructuredBuffer_v4float Uniform +%TranslucentBasePass = OpVariable %_ptr_Uniform_type_TranslucentBasePass Uniform +%TranslucentBasePass_Shared_Fog_IntegratedLightScattering = OpVariable %_ptr_UniformConstant_type_3d_image UniformConstant + %Material = OpVariable %_ptr_Uniform_type_Material Uniform +%in_var_TEXCOORD10_centroid = OpVariable %_ptr_Input_v4float Input +%in_var_TEXCOORD11_centroid = OpVariable %_ptr_Input_v4float Input +%in_var_PRIMITIVE_ID = OpVariable %_ptr_Input_uint Input +%in_var_TEXCOORD7 = OpVariable %_ptr_Input_v4float Input +%gl_FragCoord = OpVariable %_ptr_Input_v4float Input +%gl_FrontFacing = OpVariable %_ptr_Input_bool Input +%gl_SampleMask = OpVariable %_ptr_Input__arr_uint_uint_1 Input +%out_var_SV_Target0 = OpVariable %_ptr_Output_v4float Output +%gl_SampleMask_0 = OpVariable %_ptr_Output__arr_uint_uint_1 Output + %102 = OpConstantNull %v4float + %float_n1_5 = OpConstant %float -1.5 + %float_3 = OpConstant %float 3 + %105 = OpConstantComposite %v3float %float_n1 %float_n1_5 %float_3 +%float_12_25 = OpConstant %float 12.25 +%float_0_00200000009 = OpConstant %float 0.00200000009 + %108 = OpUndef %float + %uint_15 = OpConstant %uint 15 + %MainPS = OpFunction %void None %94 + %110 = OpLabel + %111 = OpLoad %v4float %in_var_TEXCOORD10_centroid + %112 = OpLoad %v4float %in_var_TEXCOORD11_centroid + %113 = OpLoad %uint %in_var_PRIMITIVE_ID + %114 = OpLoad %v4float %in_var_TEXCOORD7 + %115 = OpLoad %v4float %gl_FragCoord + %116 = OpLoad %_arr_uint_uint_1 %gl_SampleMask + %117 = OpCompositeExtract %uint %116 0 + %118 = OpAccessChain %_ptr_Uniform_mat4v4float %View %int_1 + %119 = OpLoad %mat4v4float %118 + %120 = OpAccessChain %_ptr_Uniform_mat4v4float %View %int_10 + %121 = OpLoad %mat4v4float %120 + %122 = OpAccessChain %_ptr_Uniform_v3float %View %int_31 + %123 = OpLoad %v3float %122 + %124 = OpAccessChain %_ptr_Uniform_v4float %View %int_66 + %125 = OpLoad %v4float %124 + %126 = OpVectorShuffle %v3float %111 %111 0 1 2 + %127 = OpVectorShuffle %v3float %112 %112 0 1 2 + %128 = OpExtInst %v3float %1 Cross %127 %126 + %129 = OpCompositeExtract %float %112 3 + %130 = OpCompositeConstruct %v3float %129 %129 %129 + %131 = OpFMul %v3float %128 %130 + %132 = OpCompositeConstruct %mat3v3float %126 %131 %127 + %133 = OpCompositeExtract %float %115 0 + %134 = OpCompositeExtract %float %115 1 + %135 = OpCompositeExtract %float %115 2 + %136 = OpCompositeConstruct %v4float %133 %134 %135 %float_1 + %137 = OpMatrixTimesVector %v4float %121 %136 + %138 = OpVectorShuffle %v3float %137 %137 0 1 2 + %139 = OpCompositeExtract %float %137 3 + %140 = OpCompositeConstruct %v3float %139 %139 %139 + %141 = OpFDiv %v3float %138 %140 + %142 = OpFSub %v3float %141 %123 + %143 = OpVectorShuffle %v3float %125 %125 0 1 2 + %144 = OpCompositeExtract %float %125 3 + %145 = OpCompositeConstruct %v3float %144 %144 %144 + %146 = OpFMul %v3float %75 %145 + %147 = OpFAdd %v3float %146 %143 + %148 = OpExtInst %v3float %1 Normalize %147 + %149 = OpMatrixTimesVector %v3float %132 %148 + %150 = OpExtInst %v3float %1 Normalize %149 + %151 = OpExtInst %float %1 Sqrt %float_12_25 + %152 = OpCompositeConstruct %v3float %151 %151 %151 + %153 = OpFDiv %v3float %105 %152 + %154 = OpDot %float %153 %150 + %155 = OpFAdd %float %float_1 %154 + %156 = OpFMul %float %155 %float_0_5 + %157 = OpFAdd %float %156 %float_0_200000003 + %158 = OpAccessChain %_ptr_Uniform_v4float %Material %int_0 %int_1 + %159 = OpLoad %v4float %158 + %160 = OpVectorShuffle %v3float %159 %159 0 1 2 + %161 = OpCompositeConstruct %v3float %157 %157 %157 + %162 = OpFMul %v3float %160 %161 + %163 = OpAccessChain %_ptr_Uniform_float %TranslucentBasePass %int_144 + %164 = OpLoad %float %163 + %165 = OpFOrdGreaterThan %bool %164 %float_0 + OpSelectionMerge %166 None + OpBranchConditional %165 %167 %166 + %167 = OpLabel + %168 = OpCompositeExtract %float %142 0 + %169 = OpCompositeExtract %float %142 1 + %170 = OpCompositeExtract %float %142 2 + %171 = OpCompositeConstruct %v4float %168 %169 %170 %float_1 + %172 = OpMatrixTimesVector %v4float %119 %171 + %173 = OpCompositeExtract %float %172 3 + %174 = OpCompositeConstruct %v2float %173 %173 + %175 = OpVectorShuffle %v2float %172 %172 0 1 + %176 = OpFDiv %v2float %175 %174 + %177 = OpVectorShuffle %v2float %176 %102 0 1 + %178 = OpFMul %v2float %177 %67 + %179 = OpFAdd %v2float %178 %61 + %180 = OpCompositeExtract %float %179 0 + %181 = OpCompositeExtract %float %179 1 + %182 = OpAccessChain %_ptr_Uniform_float %View %int_155 %int_0 + %183 = OpLoad %float %182 + %184 = OpFMul %float %173 %183 + %185 = OpAccessChain %_ptr_Uniform_float %View %int_155 %int_1 + %186 = OpLoad %float %185 + %187 = OpFAdd %float %184 %186 + %188 = OpExtInst %float %1 Log2 %187 + %189 = OpAccessChain %_ptr_Uniform_float %View %int_155 %int_2 + %190 = OpLoad %float %189 + %191 = OpFMul %float %188 %190 + %192 = OpAccessChain %_ptr_Uniform_float %View %int_153 %int_2 + %193 = OpLoad %float %192 + %194 = OpFMul %float %191 %193 + %195 = OpCompositeConstruct %v3float %180 %181 %194 + OpSelectionMerge %196 None + OpBranchConditional %165 %197 %196 + %197 = OpLabel + %198 = OpLoad %type_3d_image %TranslucentBasePass_Shared_Fog_IntegratedLightScattering + %199 = OpLoad %type_sampler %View_SharedBilinearClampedSampler + %200 = OpSampledImage %type_sampled_image %198 %199 + %201 = OpImageSampleExplicitLod %v4float %200 %195 Lod %float_0 + OpBranch %196 + %196 = OpLabel + %202 = OpPhi %v4float %68 %167 %201 %197 + %203 = OpVectorShuffle %v3float %202 %202 0 1 2 + %204 = OpVectorShuffle %v3float %114 %114 0 1 2 + %205 = OpCompositeExtract %float %202 3 + %206 = OpCompositeConstruct %v3float %205 %205 %205 + %207 = OpFMul %v3float %204 %206 + %208 = OpFAdd %v3float %203 %207 + %209 = OpCompositeExtract %float %208 0 + %210 = OpCompositeExtract %float %208 1 + %211 = OpCompositeExtract %float %208 2 + %212 = OpCompositeExtract %float %114 3 + %213 = OpFMul %float %205 %212 + %214 = OpCompositeConstruct %v4float %209 %210 %211 %213 + OpBranch %166 + %166 = OpLabel + %215 = OpPhi %v4float %114 %110 %214 %196 + %216 = OpExtInst %v3float %1 FMax %162 %48 + %217 = OpAccessChain %_ptr_Uniform_float %View %int_70 + %218 = OpLoad %float %217 + %219 = OpFOrdGreaterThan %bool %218 %float_0 + OpSelectionMerge %220 DontFlatten + OpBranchConditional %219 %221 %220 + %221 = OpLabel + %222 = OpIMul %uint %113 %uint_26 + %223 = OpIAdd %uint %222 %uint_5 + %224 = OpAccessChain %_ptr_Uniform_v4float %View_PrimitiveSceneData %int_0 %223 + %225 = OpLoad %v4float %224 + %226 = OpVectorShuffle %v3float %225 %225 0 1 2 + %227 = OpFSub %v3float %142 %226 + %228 = OpExtInst %v3float %1 FAbs %227 + %229 = OpIAdd %uint %222 %uint_19 + %230 = OpAccessChain %_ptr_Uniform_v4float %View_PrimitiveSceneData %int_0 %229 + %231 = OpLoad %v4float %230 + %232 = OpVectorShuffle %v3float %231 %231 0 1 2 + %233 = OpFAdd %v3float %232 %53 + %234 = OpFOrdGreaterThan %v3bool %228 %233 + %235 = OpAny %bool %234 + OpSelectionMerge %236 None + OpBranchConditional %235 %237 %236 + %237 = OpLabel + %238 = OpDot %float %142 %55 + %239 = OpFMul %float %238 %float_0_00200000009 + %240 = OpExtInst %float %1 Fract %239 + %241 = OpCompositeConstruct %v3float %240 %240 %240 + %242 = OpFOrdGreaterThan %v3bool %241 %59 + %243 = OpSelect %v3float %242 %53 %48 + %244 = OpExtInst %v3float %1 FMix %56 %57 %243 + OpBranch %236 + %236 = OpLabel + %245 = OpPhi %v3float %216 %221 %244 %237 + OpBranch %220 + %220 = OpLabel + %246 = OpPhi %v3float %216 %166 %245 %236 + %247 = OpCompositeExtract %float %215 3 + %248 = OpCompositeConstruct %v3float %247 %247 %247 + %249 = OpFMul %v3float %246 %248 + %250 = OpVectorShuffle %v3float %215 %215 0 1 2 + %251 = OpFAdd %v3float %249 %250 + %252 = OpCompositeExtract %float %251 0 + %253 = OpCompositeExtract %float %251 1 + %254 = OpCompositeExtract %float %251 2 + %255 = OpCompositeConstruct %v4float %252 %253 %254 %108 + %256 = OpCompositeInsert %v4float %float_1 %255 3 + %257 = OpAccessChain %_ptr_Uniform_int %View %int_60 + %258 = OpLoad %int %257 + %259 = OpSGreaterThan %bool %258 %int_1 + OpSelectionMerge %260 None + OpBranchConditional %259 %261 %262 + %262 = OpLabel + OpBranch %260 + %261 = OpLabel + %263 = OpConvertSToF %float %258 + %264 = OpFMul %float %263 %float_0_25 + %265 = OpCompositeConstruct %v4float %264 %264 %264 %264 + %266 = OpFMul %v4float %256 %265 + %267 = OpBitwiseAnd %uint %117 %uint_15 + OpBranch %260 + %260 = OpLabel + %268 = OpPhi %v4float %266 %261 %256 %262 + %269 = OpPhi %uint %267 %261 %117 %262 + OpStore %out_var_SV_Target0 %268 + %270 = OpAccessChain %_ptr_Output_uint %gl_SampleMask_0 %uint_0 + OpStore %270 %269 + OpReturn + OpFunctionEnd diff --git a/third_party/spirv-cross/shaders-ue4/asm/frag/subpass-input.ios.framebuffer-fetch.asm.frag b/third_party/spirv-cross/shaders-ue4/asm/frag/subpass-input.ios.framebuffer-fetch.asm.frag new file mode 100644 index 0000000000..e6565873a0 --- /dev/null +++ b/third_party/spirv-cross/shaders-ue4/asm/frag/subpass-input.ios.framebuffer-fetch.asm.frag @@ -0,0 +1,589 @@ +; SPIR-V +; Version: 1.0 +; Generator: Google spiregg; 0 +; Bound: 130 +; Schema: 0 + OpCapability Shader + OpCapability InputAttachment + OpExtension "SPV_GOOGLE_hlsl_functionality1" + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %Main "main" %gl_FragCoord %out_var_SV_Target0 + OpExecutionMode %Main OriginUpperLeft + OpSource HLSL 600 + OpName %type_subpass_image "type.subpass.image" + OpName %gl_LastFragData "gl_LastFragData" + OpName %type_View "type.View" + OpMemberName %type_View 0 "View_TranslatedWorldToClip" + OpMemberName %type_View 1 "View_WorldToClip" + OpMemberName %type_View 2 "View_TranslatedWorldToView" + OpMemberName %type_View 3 "View_ViewToTranslatedWorld" + OpMemberName %type_View 4 "View_TranslatedWorldToCameraView" + OpMemberName %type_View 5 "View_CameraViewToTranslatedWorld" + OpMemberName %type_View 6 "View_ViewToClip" + OpMemberName %type_View 7 "View_ViewToClipNoAA" + OpMemberName %type_View 8 "View_ClipToView" + OpMemberName %type_View 9 "View_ClipToTranslatedWorld" + OpMemberName %type_View 10 "View_SVPositionToTranslatedWorld" + OpMemberName %type_View 11 "View_ScreenToWorld" + OpMemberName %type_View 12 "View_ScreenToTranslatedWorld" + OpMemberName %type_View 13 "View_ViewForward" + OpMemberName %type_View 14 "PrePadding_View_844" + OpMemberName %type_View 15 "View_ViewUp" + OpMemberName %type_View 16 "PrePadding_View_860" + OpMemberName %type_View 17 "View_ViewRight" + OpMemberName %type_View 18 "PrePadding_View_876" + OpMemberName %type_View 19 "View_HMDViewNoRollUp" + OpMemberName %type_View 20 "PrePadding_View_892" + OpMemberName %type_View 21 "View_HMDViewNoRollRight" + OpMemberName %type_View 22 "PrePadding_View_908" + OpMemberName %type_View 23 "View_InvDeviceZToWorldZTransform" + OpMemberName %type_View 24 "View_ScreenPositionScaleBias" + OpMemberName %type_View 25 "View_WorldCameraOrigin" + OpMemberName %type_View 26 "PrePadding_View_956" + OpMemberName %type_View 27 "View_TranslatedWorldCameraOrigin" + OpMemberName %type_View 28 "PrePadding_View_972" + OpMemberName %type_View 29 "View_WorldViewOrigin" + OpMemberName %type_View 30 "PrePadding_View_988" + OpMemberName %type_View 31 "View_PreViewTranslation" + OpMemberName %type_View 32 "PrePadding_View_1004" + OpMemberName %type_View 33 "View_PrevProjection" + OpMemberName %type_View 34 "View_PrevViewProj" + OpMemberName %type_View 35 "View_PrevViewRotationProj" + OpMemberName %type_View 36 "View_PrevViewToClip" + OpMemberName %type_View 37 "View_PrevClipToView" + OpMemberName %type_View 38 "View_PrevTranslatedWorldToClip" + OpMemberName %type_View 39 "View_PrevTranslatedWorldToView" + OpMemberName %type_View 40 "View_PrevViewToTranslatedWorld" + OpMemberName %type_View 41 "View_PrevTranslatedWorldToCameraView" + OpMemberName %type_View 42 "View_PrevCameraViewToTranslatedWorld" + OpMemberName %type_View 43 "View_PrevWorldCameraOrigin" + OpMemberName %type_View 44 "PrePadding_View_1660" + OpMemberName %type_View 45 "View_PrevWorldViewOrigin" + OpMemberName %type_View 46 "PrePadding_View_1676" + OpMemberName %type_View 47 "View_PrevPreViewTranslation" + OpMemberName %type_View 48 "PrePadding_View_1692" + OpMemberName %type_View 49 "View_PrevInvViewProj" + OpMemberName %type_View 50 "View_PrevScreenToTranslatedWorld" + OpMemberName %type_View 51 "View_ClipToPrevClip" + OpMemberName %type_View 52 "View_TemporalAAJitter" + OpMemberName %type_View 53 "View_GlobalClippingPlane" + OpMemberName %type_View 54 "View_FieldOfViewWideAngles" + OpMemberName %type_View 55 "View_PrevFieldOfViewWideAngles" + OpMemberName %type_View 56 "View_ViewRectMin" + OpMemberName %type_View 57 "View_ViewSizeAndInvSize" + OpMemberName %type_View 58 "View_BufferSizeAndInvSize" + OpMemberName %type_View 59 "View_BufferBilinearUVMinMax" + OpMemberName %type_View 60 "View_NumSceneColorMSAASamples" + OpMemberName %type_View 61 "View_PreExposure" + OpMemberName %type_View 62 "View_OneOverPreExposure" + OpMemberName %type_View 63 "PrePadding_View_2012" + OpMemberName %type_View 64 "View_DiffuseOverrideParameter" + OpMemberName %type_View 65 "View_SpecularOverrideParameter" + OpMemberName %type_View 66 "View_NormalOverrideParameter" + OpMemberName %type_View 67 "View_RoughnessOverrideParameter" + OpMemberName %type_View 68 "View_PrevFrameGameTime" + OpMemberName %type_View 69 "View_PrevFrameRealTime" + OpMemberName %type_View 70 "View_OutOfBoundsMask" + OpMemberName %type_View 71 "PrePadding_View_2084" + OpMemberName %type_View 72 "PrePadding_View_2088" + OpMemberName %type_View 73 "PrePadding_View_2092" + OpMemberName %type_View 74 "View_WorldCameraMovementSinceLastFrame" + OpMemberName %type_View 75 "View_CullingSign" + OpMemberName %type_View 76 "View_NearPlane" + OpMemberName %type_View 77 "View_AdaptiveTessellationFactor" + OpMemberName %type_View 78 "View_GameTime" + OpMemberName %type_View 79 "View_RealTime" + OpMemberName %type_View 80 "View_DeltaTime" + OpMemberName %type_View 81 "View_MaterialTextureMipBias" + OpMemberName %type_View 82 "View_MaterialTextureDerivativeMultiply" + OpMemberName %type_View 83 "View_Random" + OpMemberName %type_View 84 "View_FrameNumber" + OpMemberName %type_View 85 "View_StateFrameIndexMod8" + OpMemberName %type_View 86 "View_StateFrameIndex" + OpMemberName %type_View 87 "View_CameraCut" + OpMemberName %type_View 88 "View_UnlitViewmodeMask" + OpMemberName %type_View 89 "PrePadding_View_2164" + OpMemberName %type_View 90 "PrePadding_View_2168" + OpMemberName %type_View 91 "PrePadding_View_2172" + OpMemberName %type_View 92 "View_DirectionalLightColor" + OpMemberName %type_View 93 "View_DirectionalLightDirection" + OpMemberName %type_View 94 "PrePadding_View_2204" + OpMemberName %type_View 95 "View_TranslucencyLightingVolumeMin" + OpMemberName %type_View 96 "View_TranslucencyLightingVolumeInvSize" + OpMemberName %type_View 97 "View_TemporalAAParams" + OpMemberName %type_View 98 "View_CircleDOFParams" + OpMemberName %type_View 99 "View_DepthOfFieldSensorWidth" + OpMemberName %type_View 100 "View_DepthOfFieldFocalDistance" + OpMemberName %type_View 101 "View_DepthOfFieldScale" + OpMemberName %type_View 102 "View_DepthOfFieldFocalLength" + OpMemberName %type_View 103 "View_DepthOfFieldFocalRegion" + OpMemberName %type_View 104 "View_DepthOfFieldNearTransitionRegion" + OpMemberName %type_View 105 "View_DepthOfFieldFarTransitionRegion" + OpMemberName %type_View 106 "View_MotionBlurNormalizedToPixel" + OpMemberName %type_View 107 "View_bSubsurfacePostprocessEnabled" + OpMemberName %type_View 108 "View_GeneralPurposeTweak" + OpMemberName %type_View 109 "View_DemosaicVposOffset" + OpMemberName %type_View 110 "PrePadding_View_2348" + OpMemberName %type_View 111 "View_IndirectLightingColorScale" + OpMemberName %type_View 112 "View_HDR32bppEncodingMode" + OpMemberName %type_View 113 "View_AtmosphericFogSunDirection" + OpMemberName %type_View 114 "View_AtmosphericFogSunPower" + OpMemberName %type_View 115 "View_AtmosphericFogPower" + OpMemberName %type_View 116 "View_AtmosphericFogDensityScale" + OpMemberName %type_View 117 "View_AtmosphericFogDensityOffset" + OpMemberName %type_View 118 "View_AtmosphericFogGroundOffset" + OpMemberName %type_View 119 "View_AtmosphericFogDistanceScale" + OpMemberName %type_View 120 "View_AtmosphericFogAltitudeScale" + OpMemberName %type_View 121 "View_AtmosphericFogHeightScaleRayleigh" + OpMemberName %type_View 122 "View_AtmosphericFogStartDistance" + OpMemberName %type_View 123 "View_AtmosphericFogDistanceOffset" + OpMemberName %type_View 124 "View_AtmosphericFogSunDiscScale" + OpMemberName %type_View 125 "View_AtmosphericFogRenderMask" + OpMemberName %type_View 126 "View_AtmosphericFogInscatterAltitudeSampleNum" + OpMemberName %type_View 127 "View_AtmosphericFogSunColor" + OpMemberName %type_View 128 "View_NormalCurvatureToRoughnessScaleBias" + OpMemberName %type_View 129 "View_RenderingReflectionCaptureMask" + OpMemberName %type_View 130 "View_AmbientCubemapTint" + OpMemberName %type_View 131 "View_AmbientCubemapIntensity" + OpMemberName %type_View 132 "View_SkyLightParameters" + OpMemberName %type_View 133 "PrePadding_View_2488" + OpMemberName %type_View 134 "PrePadding_View_2492" + OpMemberName %type_View 135 "View_SkyLightColor" + OpMemberName %type_View 136 "View_SkyIrradianceEnvironmentMap" + OpMemberName %type_View 137 "View_MobilePreviewMode" + OpMemberName %type_View 138 "View_HMDEyePaddingOffset" + OpMemberName %type_View 139 "View_ReflectionCubemapMaxMip" + OpMemberName %type_View 140 "View_ShowDecalsMask" + OpMemberName %type_View 141 "View_DistanceFieldAOSpecularOcclusionMode" + OpMemberName %type_View 142 "View_IndirectCapsuleSelfShadowingIntensity" + OpMemberName %type_View 143 "PrePadding_View_2648" + OpMemberName %type_View 144 "PrePadding_View_2652" + OpMemberName %type_View 145 "View_ReflectionEnvironmentRoughnessMixingScaleBiasAndLargestWeight" + OpMemberName %type_View 146 "View_StereoPassIndex" + OpMemberName %type_View 147 "View_GlobalVolumeCenterAndExtent" + OpMemberName %type_View 148 "View_GlobalVolumeWorldToUVAddAndMul" + OpMemberName %type_View 149 "View_GlobalVolumeDimension" + OpMemberName %type_View 150 "View_GlobalVolumeTexelSize" + OpMemberName %type_View 151 "View_MaxGlobalDistance" + OpMemberName %type_View 152 "View_bCheckerboardSubsurfaceProfileRendering" + OpMemberName %type_View 153 "View_VolumetricFogInvGridSize" + OpMemberName %type_View 154 "PrePadding_View_2828" + OpMemberName %type_View 155 "View_VolumetricFogGridZParams" + OpMemberName %type_View 156 "PrePadding_View_2844" + OpMemberName %type_View 157 "View_VolumetricFogSVPosToVolumeUV" + OpMemberName %type_View 158 "View_VolumetricFogMaxDistance" + OpMemberName %type_View 159 "PrePadding_View_2860" + OpMemberName %type_View 160 "View_VolumetricLightmapWorldToUVScale" + OpMemberName %type_View 161 "PrePadding_View_2876" + OpMemberName %type_View 162 "View_VolumetricLightmapWorldToUVAdd" + OpMemberName %type_View 163 "PrePadding_View_2892" + OpMemberName %type_View 164 "View_VolumetricLightmapIndirectionTextureSize" + OpMemberName %type_View 165 "View_VolumetricLightmapBrickSize" + OpMemberName %type_View 166 "View_VolumetricLightmapBrickTexelSize" + OpMemberName %type_View 167 "View_StereoIPD" + OpMemberName %type_View 168 "View_IndirectLightingCacheShowFlag" + OpMemberName %type_View 169 "View_EyeToPixelSpreadAngle" + OpName %View "View" + OpName %type_sampler "type.sampler" + OpName %type_2d_image "type.2d.image" + OpName %ShadowDepthTexture "ShadowDepthTexture" + OpName %ShadowDepthTextureSampler "ShadowDepthTextureSampler" + OpName %type__Globals "type.$Globals" + OpMemberName %type__Globals 0 "SoftTransitionScale" + OpMemberName %type__Globals 1 "ShadowBufferSize" + OpMemberName %type__Globals 2 "ShadowFadeFraction" + OpMemberName %type__Globals 3 "ShadowSharpen" + OpMemberName %type__Globals 4 "LightPositionAndInvRadius" + OpMemberName %type__Globals 5 "ScreenToShadowMatrix" + OpMemberName %type__Globals 6 "ProjectionDepthBiasParameters" + OpMemberName %type__Globals 7 "ModulatedShadowColor" + OpMemberName %type__Globals 8 "ShadowTileOffsetAndSize" + OpName %_Globals "$Globals" + OpName %out_var_SV_Target0 "out.var.SV_Target0" + OpName %Main "Main" + OpName %type_sampled_image "type.sampled.image" + OpDecorate %gl_LastFragData InputAttachmentIndex 0 + OpDecorate %gl_FragCoord BuiltIn FragCoord + OpDecorateString %gl_FragCoord UserSemantic "SV_POSITION" + OpDecorateString %out_var_SV_Target0 UserSemantic "SV_Target0" + OpDecorate %out_var_SV_Target0 Location 0 + OpDecorate %gl_LastFragData DescriptorSet 0 + OpDecorate %gl_LastFragData Binding 0 + OpDecorate %View DescriptorSet 0 + OpDecorate %View Binding 0 + OpDecorate %ShadowDepthTexture DescriptorSet 0 + OpDecorate %ShadowDepthTexture Binding 0 + OpDecorate %ShadowDepthTextureSampler DescriptorSet 0 + OpDecorate %ShadowDepthTextureSampler Binding 0 + OpDecorate %_Globals DescriptorSet 0 + OpDecorate %_Globals Binding 1 + OpDecorate %_arr_v4float_uint_2 ArrayStride 16 + OpDecorate %_arr_v4float_uint_7 ArrayStride 16 + OpDecorate %_arr_v4float_uint_4 ArrayStride 16 + OpMemberDecorate %type_View 0 Offset 0 + OpMemberDecorate %type_View 0 MatrixStride 16 + OpMemberDecorate %type_View 0 ColMajor + OpMemberDecorate %type_View 1 Offset 64 + OpMemberDecorate %type_View 1 MatrixStride 16 + OpMemberDecorate %type_View 1 ColMajor + OpMemberDecorate %type_View 2 Offset 128 + OpMemberDecorate %type_View 2 MatrixStride 16 + OpMemberDecorate %type_View 2 ColMajor + OpMemberDecorate %type_View 3 Offset 192 + OpMemberDecorate %type_View 3 MatrixStride 16 + OpMemberDecorate %type_View 3 ColMajor + OpMemberDecorate %type_View 4 Offset 256 + OpMemberDecorate %type_View 4 MatrixStride 16 + OpMemberDecorate %type_View 4 ColMajor + OpMemberDecorate %type_View 5 Offset 320 + OpMemberDecorate %type_View 5 MatrixStride 16 + OpMemberDecorate %type_View 5 ColMajor + OpMemberDecorate %type_View 6 Offset 384 + OpMemberDecorate %type_View 6 MatrixStride 16 + OpMemberDecorate %type_View 6 ColMajor + OpMemberDecorate %type_View 7 Offset 448 + OpMemberDecorate %type_View 7 MatrixStride 16 + OpMemberDecorate %type_View 7 ColMajor + OpMemberDecorate %type_View 8 Offset 512 + OpMemberDecorate %type_View 8 MatrixStride 16 + OpMemberDecorate %type_View 8 ColMajor + OpMemberDecorate %type_View 9 Offset 576 + OpMemberDecorate %type_View 9 MatrixStride 16 + OpMemberDecorate %type_View 9 ColMajor + OpMemberDecorate %type_View 10 Offset 640 + OpMemberDecorate %type_View 10 MatrixStride 16 + OpMemberDecorate %type_View 10 ColMajor + OpMemberDecorate %type_View 11 Offset 704 + OpMemberDecorate %type_View 11 MatrixStride 16 + OpMemberDecorate %type_View 11 ColMajor + OpMemberDecorate %type_View 12 Offset 768 + OpMemberDecorate %type_View 12 MatrixStride 16 + OpMemberDecorate %type_View 12 ColMajor + OpMemberDecorate %type_View 13 Offset 832 + OpMemberDecorate %type_View 14 Offset 844 + OpMemberDecorate %type_View 15 Offset 848 + OpMemberDecorate %type_View 16 Offset 860 + OpMemberDecorate %type_View 17 Offset 864 + OpMemberDecorate %type_View 18 Offset 876 + OpMemberDecorate %type_View 19 Offset 880 + OpMemberDecorate %type_View 20 Offset 892 + OpMemberDecorate %type_View 21 Offset 896 + OpMemberDecorate %type_View 22 Offset 908 + OpMemberDecorate %type_View 23 Offset 912 + OpMemberDecorate %type_View 24 Offset 928 + OpMemberDecorate %type_View 25 Offset 944 + OpMemberDecorate %type_View 26 Offset 956 + OpMemberDecorate %type_View 27 Offset 960 + OpMemberDecorate %type_View 28 Offset 972 + OpMemberDecorate %type_View 29 Offset 976 + OpMemberDecorate %type_View 30 Offset 988 + OpMemberDecorate %type_View 31 Offset 992 + OpMemberDecorate %type_View 32 Offset 1004 + OpMemberDecorate %type_View 33 Offset 1008 + OpMemberDecorate %type_View 33 MatrixStride 16 + OpMemberDecorate %type_View 33 ColMajor + OpMemberDecorate %type_View 34 Offset 1072 + OpMemberDecorate %type_View 34 MatrixStride 16 + OpMemberDecorate %type_View 34 ColMajor + OpMemberDecorate %type_View 35 Offset 1136 + OpMemberDecorate %type_View 35 MatrixStride 16 + OpMemberDecorate %type_View 35 ColMajor + OpMemberDecorate %type_View 36 Offset 1200 + OpMemberDecorate %type_View 36 MatrixStride 16 + OpMemberDecorate %type_View 36 ColMajor + OpMemberDecorate %type_View 37 Offset 1264 + OpMemberDecorate %type_View 37 MatrixStride 16 + OpMemberDecorate %type_View 37 ColMajor + OpMemberDecorate %type_View 38 Offset 1328 + OpMemberDecorate %type_View 38 MatrixStride 16 + OpMemberDecorate %type_View 38 ColMajor + OpMemberDecorate %type_View 39 Offset 1392 + OpMemberDecorate %type_View 39 MatrixStride 16 + OpMemberDecorate %type_View 39 ColMajor + OpMemberDecorate %type_View 40 Offset 1456 + OpMemberDecorate %type_View 40 MatrixStride 16 + OpMemberDecorate %type_View 40 ColMajor + OpMemberDecorate %type_View 41 Offset 1520 + OpMemberDecorate %type_View 41 MatrixStride 16 + OpMemberDecorate %type_View 41 ColMajor + OpMemberDecorate %type_View 42 Offset 1584 + OpMemberDecorate %type_View 42 MatrixStride 16 + OpMemberDecorate %type_View 42 ColMajor + OpMemberDecorate %type_View 43 Offset 1648 + OpMemberDecorate %type_View 44 Offset 1660 + OpMemberDecorate %type_View 45 Offset 1664 + OpMemberDecorate %type_View 46 Offset 1676 + OpMemberDecorate %type_View 47 Offset 1680 + OpMemberDecorate %type_View 48 Offset 1692 + OpMemberDecorate %type_View 49 Offset 1696 + OpMemberDecorate %type_View 49 MatrixStride 16 + OpMemberDecorate %type_View 49 ColMajor + OpMemberDecorate %type_View 50 Offset 1760 + OpMemberDecorate %type_View 50 MatrixStride 16 + OpMemberDecorate %type_View 50 ColMajor + OpMemberDecorate %type_View 51 Offset 1824 + OpMemberDecorate %type_View 51 MatrixStride 16 + OpMemberDecorate %type_View 51 ColMajor + OpMemberDecorate %type_View 52 Offset 1888 + OpMemberDecorate %type_View 53 Offset 1904 + OpMemberDecorate %type_View 54 Offset 1920 + OpMemberDecorate %type_View 55 Offset 1928 + OpMemberDecorate %type_View 56 Offset 1936 + OpMemberDecorate %type_View 57 Offset 1952 + OpMemberDecorate %type_View 58 Offset 1968 + OpMemberDecorate %type_View 59 Offset 1984 + OpMemberDecorate %type_View 60 Offset 2000 + OpMemberDecorate %type_View 61 Offset 2004 + OpMemberDecorate %type_View 62 Offset 2008 + OpMemberDecorate %type_View 63 Offset 2012 + OpMemberDecorate %type_View 64 Offset 2016 + OpMemberDecorate %type_View 65 Offset 2032 + OpMemberDecorate %type_View 66 Offset 2048 + OpMemberDecorate %type_View 67 Offset 2064 + OpMemberDecorate %type_View 68 Offset 2072 + OpMemberDecorate %type_View 69 Offset 2076 + OpMemberDecorate %type_View 70 Offset 2080 + OpMemberDecorate %type_View 71 Offset 2084 + OpMemberDecorate %type_View 72 Offset 2088 + OpMemberDecorate %type_View 73 Offset 2092 + OpMemberDecorate %type_View 74 Offset 2096 + OpMemberDecorate %type_View 75 Offset 2108 + OpMemberDecorate %type_View 76 Offset 2112 + OpMemberDecorate %type_View 77 Offset 2116 + OpMemberDecorate %type_View 78 Offset 2120 + OpMemberDecorate %type_View 79 Offset 2124 + OpMemberDecorate %type_View 80 Offset 2128 + OpMemberDecorate %type_View 81 Offset 2132 + OpMemberDecorate %type_View 82 Offset 2136 + OpMemberDecorate %type_View 83 Offset 2140 + OpMemberDecorate %type_View 84 Offset 2144 + OpMemberDecorate %type_View 85 Offset 2148 + OpMemberDecorate %type_View 86 Offset 2152 + OpMemberDecorate %type_View 87 Offset 2156 + OpMemberDecorate %type_View 88 Offset 2160 + OpMemberDecorate %type_View 89 Offset 2164 + OpMemberDecorate %type_View 90 Offset 2168 + OpMemberDecorate %type_View 91 Offset 2172 + OpMemberDecorate %type_View 92 Offset 2176 + OpMemberDecorate %type_View 93 Offset 2192 + OpMemberDecorate %type_View 94 Offset 2204 + OpMemberDecorate %type_View 95 Offset 2208 + OpMemberDecorate %type_View 96 Offset 2240 + OpMemberDecorate %type_View 97 Offset 2272 + OpMemberDecorate %type_View 98 Offset 2288 + OpMemberDecorate %type_View 99 Offset 2304 + OpMemberDecorate %type_View 100 Offset 2308 + OpMemberDecorate %type_View 101 Offset 2312 + OpMemberDecorate %type_View 102 Offset 2316 + OpMemberDecorate %type_View 103 Offset 2320 + OpMemberDecorate %type_View 104 Offset 2324 + OpMemberDecorate %type_View 105 Offset 2328 + OpMemberDecorate %type_View 106 Offset 2332 + OpMemberDecorate %type_View 107 Offset 2336 + OpMemberDecorate %type_View 108 Offset 2340 + OpMemberDecorate %type_View 109 Offset 2344 + OpMemberDecorate %type_View 110 Offset 2348 + OpMemberDecorate %type_View 111 Offset 2352 + OpMemberDecorate %type_View 112 Offset 2364 + OpMemberDecorate %type_View 113 Offset 2368 + OpMemberDecorate %type_View 114 Offset 2380 + OpMemberDecorate %type_View 115 Offset 2384 + OpMemberDecorate %type_View 116 Offset 2388 + OpMemberDecorate %type_View 117 Offset 2392 + OpMemberDecorate %type_View 118 Offset 2396 + OpMemberDecorate %type_View 119 Offset 2400 + OpMemberDecorate %type_View 120 Offset 2404 + OpMemberDecorate %type_View 121 Offset 2408 + OpMemberDecorate %type_View 122 Offset 2412 + OpMemberDecorate %type_View 123 Offset 2416 + OpMemberDecorate %type_View 124 Offset 2420 + OpMemberDecorate %type_View 125 Offset 2424 + OpMemberDecorate %type_View 126 Offset 2428 + OpMemberDecorate %type_View 127 Offset 2432 + OpMemberDecorate %type_View 128 Offset 2448 + OpMemberDecorate %type_View 129 Offset 2460 + OpMemberDecorate %type_View 130 Offset 2464 + OpMemberDecorate %type_View 131 Offset 2480 + OpMemberDecorate %type_View 132 Offset 2484 + OpMemberDecorate %type_View 133 Offset 2488 + OpMemberDecorate %type_View 134 Offset 2492 + OpMemberDecorate %type_View 135 Offset 2496 + OpMemberDecorate %type_View 136 Offset 2512 + OpMemberDecorate %type_View 137 Offset 2624 + OpMemberDecorate %type_View 138 Offset 2628 + OpMemberDecorate %type_View 139 Offset 2632 + OpMemberDecorate %type_View 140 Offset 2636 + OpMemberDecorate %type_View 141 Offset 2640 + OpMemberDecorate %type_View 142 Offset 2644 + OpMemberDecorate %type_View 143 Offset 2648 + OpMemberDecorate %type_View 144 Offset 2652 + OpMemberDecorate %type_View 145 Offset 2656 + OpMemberDecorate %type_View 146 Offset 2668 + OpMemberDecorate %type_View 147 Offset 2672 + OpMemberDecorate %type_View 148 Offset 2736 + OpMemberDecorate %type_View 149 Offset 2800 + OpMemberDecorate %type_View 150 Offset 2804 + OpMemberDecorate %type_View 151 Offset 2808 + OpMemberDecorate %type_View 152 Offset 2812 + OpMemberDecorate %type_View 153 Offset 2816 + OpMemberDecorate %type_View 154 Offset 2828 + OpMemberDecorate %type_View 155 Offset 2832 + OpMemberDecorate %type_View 156 Offset 2844 + OpMemberDecorate %type_View 157 Offset 2848 + OpMemberDecorate %type_View 158 Offset 2856 + OpMemberDecorate %type_View 159 Offset 2860 + OpMemberDecorate %type_View 160 Offset 2864 + OpMemberDecorate %type_View 161 Offset 2876 + OpMemberDecorate %type_View 162 Offset 2880 + OpMemberDecorate %type_View 163 Offset 2892 + OpMemberDecorate %type_View 164 Offset 2896 + OpMemberDecorate %type_View 165 Offset 2908 + OpMemberDecorate %type_View 166 Offset 2912 + OpMemberDecorate %type_View 167 Offset 2924 + OpMemberDecorate %type_View 168 Offset 2928 + OpMemberDecorate %type_View 169 Offset 2932 + OpDecorate %type_View Block + OpMemberDecorate %type__Globals 0 Offset 0 + OpMemberDecorate %type__Globals 1 Offset 16 + OpMemberDecorate %type__Globals 2 Offset 32 + OpMemberDecorate %type__Globals 3 Offset 36 + OpMemberDecorate %type__Globals 4 Offset 48 + OpMemberDecorate %type__Globals 5 Offset 64 + OpMemberDecorate %type__Globals 5 MatrixStride 16 + OpMemberDecorate %type__Globals 5 ColMajor + OpMemberDecorate %type__Globals 6 Offset 128 + OpMemberDecorate %type__Globals 7 Offset 144 + OpMemberDecorate %type__Globals 8 Offset 160 + OpDecorate %type__Globals Block + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 +%mat4v4float = OpTypeMatrix %v4float 4 + %v3float = OpTypeVector %float 3 + %v2float = OpTypeVector %float 2 + %int = OpTypeInt 32 1 + %uint = OpTypeInt 32 0 + %uint_2 = OpConstant %uint 2 + %uint_7 = OpConstant %uint 7 + %uint_4 = OpConstant %uint 4 + %float_1 = OpConstant %float 1 + %int_58 = OpConstant %int 58 + %int_24 = OpConstant %int 24 + %int_5 = OpConstant %int 5 + %int_2 = OpConstant %int 2 + %int_3 = OpConstant %int 3 + %int_8 = OpConstant %int 8 +%float_0_999989986 = OpConstant %float 0.999989986 + %int_0 = OpConstant %int 0 + %float_0 = OpConstant %float 0 + %int_7 = OpConstant %int 7 + %float_0_5 = OpConstant %float 0.5 + %41 = OpConstantComposite %v3float %float_1 %float_1 %float_1 + %v2int = OpTypeVector %int 2 + %43 = OpConstantComposite %v2int %int_0 %int_0 + %44 = OpConstantComposite %v3float %float_0 %float_0 %float_0 +%type_subpass_image = OpTypeImage %float SubpassData 2 0 0 2 Unknown +%_ptr_UniformConstant_type_subpass_image = OpTypePointer UniformConstant %type_subpass_image +%_arr_v4float_uint_2 = OpTypeArray %v4float %uint_2 +%_arr_v4float_uint_7 = OpTypeArray %v4float %uint_7 +%_arr_v4float_uint_4 = OpTypeArray %v4float %uint_4 + %type_View = OpTypeStruct %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %v3float %float %v3float %float %v3float %float %v3float %float %v3float %float %v4float %v4float %v3float %float %v3float %float %v3float %float %v3float %float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %v3float %float %v3float %float %v3float %float %mat4v4float %mat4v4float %mat4v4float %v4float %v4float %v2float %v2float %v4float %v4float %v4float %v4float %int %float %float %float %v4float %v4float %v4float %v2float %float %float %float %float %float %float %v3float %float %float %float %float %float %float %float %float %uint %uint %uint %uint %float %float %float %float %float %v4float %v3float %float %_arr_v4float_uint_2 %_arr_v4float_uint_2 %v4float %v4float %float %float %float %float %float %float %float %float %float %float %float %float %v3float %float %v3float %float %float %float %float %float %float %float %float %float %float %float %uint %uint %v4float %v3float %float %v4float %float %float %float %float %v4float %_arr_v4float_uint_7 %float %float %float %float %uint %float %float %float %v3float %int %_arr_v4float_uint_4 %_arr_v4float_uint_4 %float %float %float %float %v3float %float %v3float %float %v2float %float %float %v3float %float %v3float %float %v3float %float %v3float %float %float %float +%_ptr_Uniform_type_View = OpTypePointer Uniform %type_View +%type_sampler = OpTypeSampler +%_ptr_UniformConstant_type_sampler = OpTypePointer UniformConstant %type_sampler +%type_2d_image = OpTypeImage %float 2D 2 0 0 1 Unknown +%_ptr_UniformConstant_type_2d_image = OpTypePointer UniformConstant %type_2d_image +%type__Globals = OpTypeStruct %v3float %v4float %float %float %v4float %mat4v4float %v2float %v4float %v4float +%_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals +%_ptr_Input_v4float = OpTypePointer Input %v4float +%_ptr_Output_v4float = OpTypePointer Output %v4float + %void = OpTypeVoid + %53 = OpTypeFunction %void +%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float +%_ptr_Uniform_mat4v4float = OpTypePointer Uniform %mat4v4float +%_ptr_Uniform_float = OpTypePointer Uniform %float +%type_sampled_image = OpTypeSampledImage %type_2d_image +%gl_LastFragData = OpVariable %_ptr_UniformConstant_type_subpass_image UniformConstant + %View = OpVariable %_ptr_Uniform_type_View Uniform +%ShadowDepthTexture = OpVariable %_ptr_UniformConstant_type_2d_image UniformConstant +%ShadowDepthTextureSampler = OpVariable %_ptr_UniformConstant_type_sampler UniformConstant + %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform +%gl_FragCoord = OpVariable %_ptr_Input_v4float Input +%out_var_SV_Target0 = OpVariable %_ptr_Output_v4float Output + %57 = OpConstantNull %v4float + %58 = OpUndef %v4float + %Main = OpFunction %void None %53 + %59 = OpLabel + %60 = OpLoad %v4float %gl_FragCoord + %61 = OpVectorShuffle %v2float %60 %60 0 1 + %62 = OpAccessChain %_ptr_Uniform_v4float %View %int_58 + %63 = OpLoad %v4float %62 + %64 = OpVectorShuffle %v2float %63 %63 2 3 + %65 = OpFMul %v2float %61 %64 + %66 = OpLoad %type_subpass_image %gl_LastFragData + %67 = OpImageRead %v4float %66 %43 None + %68 = OpCompositeExtract %float %67 3 + %69 = OpAccessChain %_ptr_Uniform_v4float %View %int_24 + %70 = OpLoad %v4float %69 + %71 = OpVectorShuffle %v2float %70 %70 3 2 + %72 = OpFSub %v2float %65 %71 + %73 = OpVectorShuffle %v2float %70 %70 0 1 + %74 = OpFDiv %v2float %72 %73 + %75 = OpCompositeConstruct %v2float %68 %68 + %76 = OpFMul %v2float %74 %75 + %77 = OpCompositeExtract %float %76 0 + %78 = OpCompositeExtract %float %76 1 + %79 = OpCompositeConstruct %v4float %77 %78 %68 %float_1 + %80 = OpAccessChain %_ptr_Uniform_mat4v4float %_Globals %int_5 + %81 = OpLoad %mat4v4float %80 + %82 = OpMatrixTimesVector %v4float %81 %79 + %83 = OpCompositeExtract %float %82 2 + %84 = OpCompositeExtract %float %82 3 + %85 = OpCompositeConstruct %v3float %84 %84 %84 + %86 = OpVectorShuffle %v3float %82 %82 0 1 2 + %87 = OpFDiv %v3float %86 %85 + %88 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_8 + %89 = OpLoad %v4float %88 + %90 = OpVectorShuffle %v2float %89 %89 2 3 + %91 = OpVectorShuffle %v2float %87 %57 0 1 + %92 = OpFMul %v2float %91 %90 + %93 = OpVectorShuffle %v2float %89 %89 0 1 + %94 = OpVectorShuffle %v2float %92 %57 0 1 + %95 = OpFAdd %v2float %94 %93 + %96 = OpExtInst %float %1 FMin %83 %float_0_999989986 + %97 = OpLoad %type_2d_image %ShadowDepthTexture + %98 = OpLoad %type_sampler %ShadowDepthTextureSampler + %99 = OpAccessChain %_ptr_Uniform_float %_Globals %int_0 %int_2 + %100 = OpLoad %float %99 + %101 = OpVectorShuffle %v2float %95 %57 0 1 + %102 = OpSampledImage %type_sampled_image %97 %98 + %103 = OpImageSampleExplicitLod %v4float %102 %101 Lod %float_0 + %104 = OpVectorShuffle %v3float %103 %103 0 0 0 + %105 = OpFMul %float %96 %100 + %106 = OpFSub %float %105 %float_1 + %107 = OpCompositeConstruct %v3float %100 %100 %100 + %108 = OpFMul %v3float %104 %107 + %109 = OpCompositeConstruct %v3float %106 %106 %106 + %110 = OpFSub %v3float %108 %109 + %111 = OpExtInst %v3float %1 FClamp %110 %44 %41 + %112 = OpCompositeExtract %float %111 0 + %113 = OpFSub %float %112 %float_0_5 + %114 = OpAccessChain %_ptr_Uniform_float %_Globals %int_3 + %115 = OpLoad %float %114 + %116 = OpFMul %float %113 %115 + %117 = OpFAdd %float %116 %float_0_5 + %118 = OpExtInst %float %1 FClamp %117 %float_0 %float_1 + %119 = OpFMul %float %118 %118 + %120 = OpAccessChain %_ptr_Uniform_float %_Globals %int_2 + %121 = OpLoad %float %120 + %122 = OpExtInst %float %1 FMix %float_1 %119 %121 + %123 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_7 + %124 = OpLoad %v4float %123 + %125 = OpVectorShuffle %v3float %124 %124 0 1 2 + %126 = OpCompositeConstruct %v3float %122 %122 %122 + %127 = OpExtInst %v3float %1 FMix %125 %41 %126 + %128 = OpVectorShuffle %v4float %58 %127 4 5 6 3 + %129 = OpCompositeInsert %v4float %float_0 %128 3 + OpStore %out_var_SV_Target0 %129 + OpReturn + OpFunctionEnd diff --git a/third_party/spirv-cross/shaders-ue4/asm/frag/texture-atomics.asm.frag b/third_party/spirv-cross/shaders-ue4/asm/frag/texture-atomics.asm.frag new file mode 100644 index 0000000000..270a1978fc --- /dev/null +++ b/third_party/spirv-cross/shaders-ue4/asm/frag/texture-atomics.asm.frag @@ -0,0 +1,242 @@ +; SPIR-V +; Version: 1.0 +; Generator: Google spiregg; 0 +; Bound: 180 +; Schema: 0 + OpCapability Shader + OpCapability SampledBuffer + OpCapability ImageBuffer + OpExtension "SPV_GOOGLE_hlsl_functionality1" + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %ShadowObjectCullPS "main" %in_var_TEXCOORD0 %gl_FragCoord %out_var_SV_Target0 + OpExecutionMode %ShadowObjectCullPS OriginUpperLeft + OpSource HLSL 600 + OpName %type_StructuredBuffer_v4float "type.StructuredBuffer.v4float" + OpName %CulledObjectBoxBounds "CulledObjectBoxBounds" + OpName %type__Globals "type.$Globals" + OpMemberName %type__Globals 0 "ShadowTileListGroupSize" + OpName %_Globals "$Globals" + OpName %type_buffer_image "type.buffer.image" + OpName %RWShadowTileNumCulledObjects "RWShadowTileNumCulledObjects" + OpName %in_var_TEXCOORD0 "in.var.TEXCOORD0" + OpName %out_var_SV_Target0 "out.var.SV_Target0" + OpName %ShadowObjectCullPS "ShadowObjectCullPS" + OpDecorateString %in_var_TEXCOORD0 UserSemantic "TEXCOORD0" + OpDecorate %in_var_TEXCOORD0 Flat + OpDecorate %gl_FragCoord BuiltIn FragCoord + OpDecorateString %gl_FragCoord UserSemantic "SV_POSITION" + OpDecorateString %out_var_SV_Target0 UserSemantic "SV_Target0" + OpDecorate %in_var_TEXCOORD0 Location 0 + OpDecorate %out_var_SV_Target0 Location 0 + OpDecorate %CulledObjectBoxBounds DescriptorSet 0 + OpDecorate %CulledObjectBoxBounds Binding 1 + OpDecorate %_Globals DescriptorSet 0 + OpDecorate %_Globals Binding 2 + OpDecorate %RWShadowTileNumCulledObjects DescriptorSet 0 + OpDecorate %RWShadowTileNumCulledObjects Binding 0 + OpDecorate %_runtimearr_v4float ArrayStride 16 + OpMemberDecorate %type_StructuredBuffer_v4float 0 Offset 0 + OpMemberDecorate %type_StructuredBuffer_v4float 0 NonWritable + OpDecorate %type_StructuredBuffer_v4float BufferBlock + OpMemberDecorate %type__Globals 0 Offset 0 + OpDecorate %type__Globals Block + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 + %v3float = OpTypeVector %float 3 + %v2float = OpTypeVector %float 2 + %int = OpTypeInt 32 1 + %uint = OpTypeInt 32 0 + %uint_2 = OpConstant %uint 2 + %uint_4 = OpConstant %uint 4 + %float_0 = OpConstant %float 0 + %22 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0 + %int_1 = OpConstant %int 1 + %int_0 = OpConstant %int 0 + %uint_1 = OpConstant %uint 1 + %float_2 = OpConstant %float 2 + %27 = OpConstantComposite %v2float %float_2 %float_2 + %float_1 = OpConstant %float 1 + %29 = OpConstantComposite %v2float %float_1 %float_1 +%float_n1000 = OpConstant %float -1000 + %int_2 = OpConstant %int 2 + %float_0_5 = OpConstant %float 0.5 + %33 = OpConstantComposite %v3float %float_0_5 %float_0_5 %float_0_5 +%float_500000 = OpConstant %float 500000 + %35 = OpConstantComposite %v3float %float_500000 %float_500000 %float_500000 +%float_n500000 = OpConstant %float -500000 + %37 = OpConstantComposite %v3float %float_n500000 %float_n500000 %float_n500000 + %int_3 = OpConstant %int 3 + %int_4 = OpConstant %int 4 + %int_5 = OpConstant %int 5 + %int_6 = OpConstant %int 6 + %int_7 = OpConstant %int 7 + %int_8 = OpConstant %int 8 + %44 = OpConstantComposite %v3float %float_1 %float_1 %float_1 + %float_n1 = OpConstant %float -1 + %46 = OpConstantComposite %v3float %float_n1 %float_n1 %float_n1 + %uint_5 = OpConstant %uint 5 + %uint_0 = OpConstant %uint 0 + %uint_3 = OpConstant %uint 3 +%_runtimearr_v4float = OpTypeRuntimeArray %v4float +%type_StructuredBuffer_v4float = OpTypeStruct %_runtimearr_v4float +%_ptr_Uniform_type_StructuredBuffer_v4float = OpTypePointer Uniform %type_StructuredBuffer_v4float + %v2uint = OpTypeVector %uint 2 +%type__Globals = OpTypeStruct %v2uint +%_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals +%type_buffer_image = OpTypeImage %uint Buffer 2 0 0 2 R32ui +%_ptr_UniformConstant_type_buffer_image = OpTypePointer UniformConstant %type_buffer_image +%_ptr_Input_uint = OpTypePointer Input %uint +%_ptr_Input_v4float = OpTypePointer Input %v4float +%_ptr_Output_v4float = OpTypePointer Output %v4float + %void = OpTypeVoid + %58 = OpTypeFunction %void +%_ptr_Function_v3float = OpTypePointer Function %v3float + %uint_8 = OpConstant %uint 8 +%_arr_v3float_uint_8 = OpTypeArray %v3float %uint_8 +%_ptr_Function__arr_v3float_uint_8 = OpTypePointer Function %_arr_v3float_uint_8 +%_ptr_Uniform_v2uint = OpTypePointer Uniform %v2uint +%_ptr_Uniform_uint = OpTypePointer Uniform %uint + %bool = OpTypeBool + %v2bool = OpTypeVector %bool 2 + %v3bool = OpTypeVector %bool 3 +%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float +%_ptr_Image_uint = OpTypePointer Image %uint +%CulledObjectBoxBounds = OpVariable %_ptr_Uniform_type_StructuredBuffer_v4float Uniform + %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform +%RWShadowTileNumCulledObjects = OpVariable %_ptr_UniformConstant_type_buffer_image UniformConstant +%in_var_TEXCOORD0 = OpVariable %_ptr_Input_uint Input +%gl_FragCoord = OpVariable %_ptr_Input_v4float Input +%out_var_SV_Target0 = OpVariable %_ptr_Output_v4float Output + %70 = OpUndef %v3float + %71 = OpConstantNull %v3float +%ShadowObjectCullPS = OpFunction %void None %58 + %72 = OpLabel + %73 = OpVariable %_ptr_Function__arr_v3float_uint_8 Function + %74 = OpLoad %uint %in_var_TEXCOORD0 + %75 = OpLoad %v4float %gl_FragCoord + %76 = OpVectorShuffle %v2float %75 %75 0 1 + %77 = OpConvertFToU %v2uint %76 + %78 = OpCompositeExtract %uint %77 1 + %79 = OpAccessChain %_ptr_Uniform_v2uint %_Globals %int_0 + %80 = OpAccessChain %_ptr_Uniform_uint %_Globals %int_0 %int_0 + %81 = OpLoad %uint %80 + %82 = OpIMul %uint %78 %81 + %83 = OpCompositeExtract %uint %77 0 + %84 = OpIAdd %uint %82 %83 + %85 = OpConvertUToF %float %83 + %86 = OpAccessChain %_ptr_Uniform_uint %_Globals %int_0 %int_1 + %87 = OpLoad %uint %86 + %88 = OpISub %uint %87 %uint_1 + %89 = OpISub %uint %88 %78 + %90 = OpConvertUToF %float %89 + %91 = OpCompositeConstruct %v2float %85 %90 + %92 = OpLoad %v2uint %79 + %93 = OpConvertUToF %v2float %92 + %94 = OpFDiv %v2float %91 %93 + %95 = OpFMul %v2float %94 %27 + %96 = OpFSub %v2float %95 %29 + %97 = OpFAdd %v2float %91 %29 + %98 = OpFDiv %v2float %97 %93 + %99 = OpFMul %v2float %98 %27 + %100 = OpFSub %v2float %99 %29 + %101 = OpVectorShuffle %v3float %70 %100 3 4 2 + %102 = OpCompositeInsert %v3float %float_1 %101 2 + %103 = OpIMul %uint %74 %uint_5 + %104 = OpAccessChain %_ptr_Uniform_v4float %CulledObjectBoxBounds %int_0 %103 + %105 = OpLoad %v4float %104 + %106 = OpVectorShuffle %v3float %105 %105 0 1 2 + %107 = OpIAdd %uint %103 %uint_1 + %108 = OpAccessChain %_ptr_Uniform_v4float %CulledObjectBoxBounds %int_0 %107 + %109 = OpLoad %v4float %108 + %110 = OpVectorShuffle %v3float %109 %109 0 1 2 + %111 = OpVectorShuffle %v2float %109 %71 0 1 + %112 = OpVectorShuffle %v2float %96 %71 0 1 + %113 = OpFOrdGreaterThan %v2bool %111 %112 + %114 = OpAll %bool %113 + %115 = OpFOrdLessThan %v3bool %106 %102 + %116 = OpAll %bool %115 + %117 = OpLogicalAnd %bool %114 %116 + OpSelectionMerge %118 DontFlatten + OpBranchConditional %117 %119 %118 + %119 = OpLabel + %120 = OpFAdd %v3float %106 %110 + %121 = OpFMul %v3float %33 %120 + %122 = OpCompositeExtract %float %96 0 + %123 = OpCompositeExtract %float %96 1 + %124 = OpCompositeConstruct %v3float %122 %123 %float_n1000 + %125 = OpAccessChain %_ptr_Function_v3float %73 %int_0 + OpStore %125 %124 + %126 = OpCompositeExtract %float %100 0 + %127 = OpCompositeConstruct %v3float %126 %123 %float_n1000 + %128 = OpAccessChain %_ptr_Function_v3float %73 %int_1 + OpStore %128 %127 + %129 = OpCompositeExtract %float %100 1 + %130 = OpCompositeConstruct %v3float %122 %129 %float_n1000 + %131 = OpAccessChain %_ptr_Function_v3float %73 %int_2 + OpStore %131 %130 + %132 = OpCompositeConstruct %v3float %126 %129 %float_n1000 + %133 = OpAccessChain %_ptr_Function_v3float %73 %int_3 + OpStore %133 %132 + %134 = OpCompositeConstruct %v3float %122 %123 %float_1 + %135 = OpAccessChain %_ptr_Function_v3float %73 %int_4 + OpStore %135 %134 + %136 = OpCompositeConstruct %v3float %126 %123 %float_1 + %137 = OpAccessChain %_ptr_Function_v3float %73 %int_5 + OpStore %137 %136 + %138 = OpCompositeConstruct %v3float %122 %129 %float_1 + %139 = OpAccessChain %_ptr_Function_v3float %73 %int_6 + OpStore %139 %138 + %140 = OpCompositeConstruct %v3float %126 %129 %float_1 + %141 = OpAccessChain %_ptr_Function_v3float %73 %int_7 + OpStore %141 %140 + %142 = OpIAdd %uint %103 %uint_2 + %143 = OpAccessChain %_ptr_Uniform_v4float %CulledObjectBoxBounds %int_0 %142 + %144 = OpLoad %v4float %143 + %145 = OpVectorShuffle %v3float %144 %144 0 1 2 + %146 = OpIAdd %uint %103 %uint_3 + %147 = OpAccessChain %_ptr_Uniform_v4float %CulledObjectBoxBounds %int_0 %146 + %148 = OpLoad %v4float %147 + %149 = OpVectorShuffle %v3float %148 %148 0 1 2 + %150 = OpIAdd %uint %103 %uint_4 + %151 = OpAccessChain %_ptr_Uniform_v4float %CulledObjectBoxBounds %int_0 %150 + %152 = OpLoad %v4float %151 + %153 = OpVectorShuffle %v3float %152 %152 0 1 2 + OpBranch %154 + %154 = OpLabel + %155 = OpPhi %v3float %37 %119 %156 %157 + %158 = OpPhi %v3float %35 %119 %159 %157 + %160 = OpPhi %int %int_0 %119 %161 %157 + %162 = OpSLessThan %bool %160 %int_8 + OpLoopMerge %163 %157 Unroll + OpBranchConditional %162 %157 %163 + %157 = OpLabel + %164 = OpAccessChain %_ptr_Function_v3float %73 %160 + %165 = OpLoad %v3float %164 + %166 = OpFSub %v3float %165 %121 + %167 = OpDot %float %166 %145 + %168 = OpDot %float %166 %149 + %169 = OpDot %float %166 %153 + %170 = OpCompositeConstruct %v3float %167 %168 %169 + %159 = OpExtInst %v3float %1 FMin %158 %170 + %156 = OpExtInst %v3float %1 FMax %155 %170 + %161 = OpIAdd %int %160 %int_1 + OpBranch %154 + %163 = OpLabel + %171 = OpFOrdLessThan %v3bool %158 %44 + %172 = OpAll %bool %171 + %173 = OpFOrdGreaterThan %v3bool %155 %46 + %174 = OpAll %bool %173 + %175 = OpLogicalAnd %bool %172 %174 + OpSelectionMerge %176 DontFlatten + OpBranchConditional %175 %177 %176 + %177 = OpLabel + %178 = OpImageTexelPointer %_ptr_Image_uint %RWShadowTileNumCulledObjects %84 %uint_0 + %179 = OpAtomicIAdd %uint %178 %uint_1 %uint_0 %uint_1 + OpBranch %176 + %176 = OpLabel + OpBranch %118 + %118 = OpLabel + OpStore %out_var_SV_Target0 %22 + OpReturn + OpFunctionEnd diff --git a/third_party/spirv-cross/shaders-ue4/asm/frag/texture-atomics.asm.graphics-robust-access.frag b/third_party/spirv-cross/shaders-ue4/asm/frag/texture-atomics.asm.graphics-robust-access.frag new file mode 100644 index 0000000000..270a1978fc --- /dev/null +++ b/third_party/spirv-cross/shaders-ue4/asm/frag/texture-atomics.asm.graphics-robust-access.frag @@ -0,0 +1,242 @@ +; SPIR-V +; Version: 1.0 +; Generator: Google spiregg; 0 +; Bound: 180 +; Schema: 0 + OpCapability Shader + OpCapability SampledBuffer + OpCapability ImageBuffer + OpExtension "SPV_GOOGLE_hlsl_functionality1" + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %ShadowObjectCullPS "main" %in_var_TEXCOORD0 %gl_FragCoord %out_var_SV_Target0 + OpExecutionMode %ShadowObjectCullPS OriginUpperLeft + OpSource HLSL 600 + OpName %type_StructuredBuffer_v4float "type.StructuredBuffer.v4float" + OpName %CulledObjectBoxBounds "CulledObjectBoxBounds" + OpName %type__Globals "type.$Globals" + OpMemberName %type__Globals 0 "ShadowTileListGroupSize" + OpName %_Globals "$Globals" + OpName %type_buffer_image "type.buffer.image" + OpName %RWShadowTileNumCulledObjects "RWShadowTileNumCulledObjects" + OpName %in_var_TEXCOORD0 "in.var.TEXCOORD0" + OpName %out_var_SV_Target0 "out.var.SV_Target0" + OpName %ShadowObjectCullPS "ShadowObjectCullPS" + OpDecorateString %in_var_TEXCOORD0 UserSemantic "TEXCOORD0" + OpDecorate %in_var_TEXCOORD0 Flat + OpDecorate %gl_FragCoord BuiltIn FragCoord + OpDecorateString %gl_FragCoord UserSemantic "SV_POSITION" + OpDecorateString %out_var_SV_Target0 UserSemantic "SV_Target0" + OpDecorate %in_var_TEXCOORD0 Location 0 + OpDecorate %out_var_SV_Target0 Location 0 + OpDecorate %CulledObjectBoxBounds DescriptorSet 0 + OpDecorate %CulledObjectBoxBounds Binding 1 + OpDecorate %_Globals DescriptorSet 0 + OpDecorate %_Globals Binding 2 + OpDecorate %RWShadowTileNumCulledObjects DescriptorSet 0 + OpDecorate %RWShadowTileNumCulledObjects Binding 0 + OpDecorate %_runtimearr_v4float ArrayStride 16 + OpMemberDecorate %type_StructuredBuffer_v4float 0 Offset 0 + OpMemberDecorate %type_StructuredBuffer_v4float 0 NonWritable + OpDecorate %type_StructuredBuffer_v4float BufferBlock + OpMemberDecorate %type__Globals 0 Offset 0 + OpDecorate %type__Globals Block + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 + %v3float = OpTypeVector %float 3 + %v2float = OpTypeVector %float 2 + %int = OpTypeInt 32 1 + %uint = OpTypeInt 32 0 + %uint_2 = OpConstant %uint 2 + %uint_4 = OpConstant %uint 4 + %float_0 = OpConstant %float 0 + %22 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0 + %int_1 = OpConstant %int 1 + %int_0 = OpConstant %int 0 + %uint_1 = OpConstant %uint 1 + %float_2 = OpConstant %float 2 + %27 = OpConstantComposite %v2float %float_2 %float_2 + %float_1 = OpConstant %float 1 + %29 = OpConstantComposite %v2float %float_1 %float_1 +%float_n1000 = OpConstant %float -1000 + %int_2 = OpConstant %int 2 + %float_0_5 = OpConstant %float 0.5 + %33 = OpConstantComposite %v3float %float_0_5 %float_0_5 %float_0_5 +%float_500000 = OpConstant %float 500000 + %35 = OpConstantComposite %v3float %float_500000 %float_500000 %float_500000 +%float_n500000 = OpConstant %float -500000 + %37 = OpConstantComposite %v3float %float_n500000 %float_n500000 %float_n500000 + %int_3 = OpConstant %int 3 + %int_4 = OpConstant %int 4 + %int_5 = OpConstant %int 5 + %int_6 = OpConstant %int 6 + %int_7 = OpConstant %int 7 + %int_8 = OpConstant %int 8 + %44 = OpConstantComposite %v3float %float_1 %float_1 %float_1 + %float_n1 = OpConstant %float -1 + %46 = OpConstantComposite %v3float %float_n1 %float_n1 %float_n1 + %uint_5 = OpConstant %uint 5 + %uint_0 = OpConstant %uint 0 + %uint_3 = OpConstant %uint 3 +%_runtimearr_v4float = OpTypeRuntimeArray %v4float +%type_StructuredBuffer_v4float = OpTypeStruct %_runtimearr_v4float +%_ptr_Uniform_type_StructuredBuffer_v4float = OpTypePointer Uniform %type_StructuredBuffer_v4float + %v2uint = OpTypeVector %uint 2 +%type__Globals = OpTypeStruct %v2uint +%_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals +%type_buffer_image = OpTypeImage %uint Buffer 2 0 0 2 R32ui +%_ptr_UniformConstant_type_buffer_image = OpTypePointer UniformConstant %type_buffer_image +%_ptr_Input_uint = OpTypePointer Input %uint +%_ptr_Input_v4float = OpTypePointer Input %v4float +%_ptr_Output_v4float = OpTypePointer Output %v4float + %void = OpTypeVoid + %58 = OpTypeFunction %void +%_ptr_Function_v3float = OpTypePointer Function %v3float + %uint_8 = OpConstant %uint 8 +%_arr_v3float_uint_8 = OpTypeArray %v3float %uint_8 +%_ptr_Function__arr_v3float_uint_8 = OpTypePointer Function %_arr_v3float_uint_8 +%_ptr_Uniform_v2uint = OpTypePointer Uniform %v2uint +%_ptr_Uniform_uint = OpTypePointer Uniform %uint + %bool = OpTypeBool + %v2bool = OpTypeVector %bool 2 + %v3bool = OpTypeVector %bool 3 +%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float +%_ptr_Image_uint = OpTypePointer Image %uint +%CulledObjectBoxBounds = OpVariable %_ptr_Uniform_type_StructuredBuffer_v4float Uniform + %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform +%RWShadowTileNumCulledObjects = OpVariable %_ptr_UniformConstant_type_buffer_image UniformConstant +%in_var_TEXCOORD0 = OpVariable %_ptr_Input_uint Input +%gl_FragCoord = OpVariable %_ptr_Input_v4float Input +%out_var_SV_Target0 = OpVariable %_ptr_Output_v4float Output + %70 = OpUndef %v3float + %71 = OpConstantNull %v3float +%ShadowObjectCullPS = OpFunction %void None %58 + %72 = OpLabel + %73 = OpVariable %_ptr_Function__arr_v3float_uint_8 Function + %74 = OpLoad %uint %in_var_TEXCOORD0 + %75 = OpLoad %v4float %gl_FragCoord + %76 = OpVectorShuffle %v2float %75 %75 0 1 + %77 = OpConvertFToU %v2uint %76 + %78 = OpCompositeExtract %uint %77 1 + %79 = OpAccessChain %_ptr_Uniform_v2uint %_Globals %int_0 + %80 = OpAccessChain %_ptr_Uniform_uint %_Globals %int_0 %int_0 + %81 = OpLoad %uint %80 + %82 = OpIMul %uint %78 %81 + %83 = OpCompositeExtract %uint %77 0 + %84 = OpIAdd %uint %82 %83 + %85 = OpConvertUToF %float %83 + %86 = OpAccessChain %_ptr_Uniform_uint %_Globals %int_0 %int_1 + %87 = OpLoad %uint %86 + %88 = OpISub %uint %87 %uint_1 + %89 = OpISub %uint %88 %78 + %90 = OpConvertUToF %float %89 + %91 = OpCompositeConstruct %v2float %85 %90 + %92 = OpLoad %v2uint %79 + %93 = OpConvertUToF %v2float %92 + %94 = OpFDiv %v2float %91 %93 + %95 = OpFMul %v2float %94 %27 + %96 = OpFSub %v2float %95 %29 + %97 = OpFAdd %v2float %91 %29 + %98 = OpFDiv %v2float %97 %93 + %99 = OpFMul %v2float %98 %27 + %100 = OpFSub %v2float %99 %29 + %101 = OpVectorShuffle %v3float %70 %100 3 4 2 + %102 = OpCompositeInsert %v3float %float_1 %101 2 + %103 = OpIMul %uint %74 %uint_5 + %104 = OpAccessChain %_ptr_Uniform_v4float %CulledObjectBoxBounds %int_0 %103 + %105 = OpLoad %v4float %104 + %106 = OpVectorShuffle %v3float %105 %105 0 1 2 + %107 = OpIAdd %uint %103 %uint_1 + %108 = OpAccessChain %_ptr_Uniform_v4float %CulledObjectBoxBounds %int_0 %107 + %109 = OpLoad %v4float %108 + %110 = OpVectorShuffle %v3float %109 %109 0 1 2 + %111 = OpVectorShuffle %v2float %109 %71 0 1 + %112 = OpVectorShuffle %v2float %96 %71 0 1 + %113 = OpFOrdGreaterThan %v2bool %111 %112 + %114 = OpAll %bool %113 + %115 = OpFOrdLessThan %v3bool %106 %102 + %116 = OpAll %bool %115 + %117 = OpLogicalAnd %bool %114 %116 + OpSelectionMerge %118 DontFlatten + OpBranchConditional %117 %119 %118 + %119 = OpLabel + %120 = OpFAdd %v3float %106 %110 + %121 = OpFMul %v3float %33 %120 + %122 = OpCompositeExtract %float %96 0 + %123 = OpCompositeExtract %float %96 1 + %124 = OpCompositeConstruct %v3float %122 %123 %float_n1000 + %125 = OpAccessChain %_ptr_Function_v3float %73 %int_0 + OpStore %125 %124 + %126 = OpCompositeExtract %float %100 0 + %127 = OpCompositeConstruct %v3float %126 %123 %float_n1000 + %128 = OpAccessChain %_ptr_Function_v3float %73 %int_1 + OpStore %128 %127 + %129 = OpCompositeExtract %float %100 1 + %130 = OpCompositeConstruct %v3float %122 %129 %float_n1000 + %131 = OpAccessChain %_ptr_Function_v3float %73 %int_2 + OpStore %131 %130 + %132 = OpCompositeConstruct %v3float %126 %129 %float_n1000 + %133 = OpAccessChain %_ptr_Function_v3float %73 %int_3 + OpStore %133 %132 + %134 = OpCompositeConstruct %v3float %122 %123 %float_1 + %135 = OpAccessChain %_ptr_Function_v3float %73 %int_4 + OpStore %135 %134 + %136 = OpCompositeConstruct %v3float %126 %123 %float_1 + %137 = OpAccessChain %_ptr_Function_v3float %73 %int_5 + OpStore %137 %136 + %138 = OpCompositeConstruct %v3float %122 %129 %float_1 + %139 = OpAccessChain %_ptr_Function_v3float %73 %int_6 + OpStore %139 %138 + %140 = OpCompositeConstruct %v3float %126 %129 %float_1 + %141 = OpAccessChain %_ptr_Function_v3float %73 %int_7 + OpStore %141 %140 + %142 = OpIAdd %uint %103 %uint_2 + %143 = OpAccessChain %_ptr_Uniform_v4float %CulledObjectBoxBounds %int_0 %142 + %144 = OpLoad %v4float %143 + %145 = OpVectorShuffle %v3float %144 %144 0 1 2 + %146 = OpIAdd %uint %103 %uint_3 + %147 = OpAccessChain %_ptr_Uniform_v4float %CulledObjectBoxBounds %int_0 %146 + %148 = OpLoad %v4float %147 + %149 = OpVectorShuffle %v3float %148 %148 0 1 2 + %150 = OpIAdd %uint %103 %uint_4 + %151 = OpAccessChain %_ptr_Uniform_v4float %CulledObjectBoxBounds %int_0 %150 + %152 = OpLoad %v4float %151 + %153 = OpVectorShuffle %v3float %152 %152 0 1 2 + OpBranch %154 + %154 = OpLabel + %155 = OpPhi %v3float %37 %119 %156 %157 + %158 = OpPhi %v3float %35 %119 %159 %157 + %160 = OpPhi %int %int_0 %119 %161 %157 + %162 = OpSLessThan %bool %160 %int_8 + OpLoopMerge %163 %157 Unroll + OpBranchConditional %162 %157 %163 + %157 = OpLabel + %164 = OpAccessChain %_ptr_Function_v3float %73 %160 + %165 = OpLoad %v3float %164 + %166 = OpFSub %v3float %165 %121 + %167 = OpDot %float %166 %145 + %168 = OpDot %float %166 %149 + %169 = OpDot %float %166 %153 + %170 = OpCompositeConstruct %v3float %167 %168 %169 + %159 = OpExtInst %v3float %1 FMin %158 %170 + %156 = OpExtInst %v3float %1 FMax %155 %170 + %161 = OpIAdd %int %160 %int_1 + OpBranch %154 + %163 = OpLabel + %171 = OpFOrdLessThan %v3bool %158 %44 + %172 = OpAll %bool %171 + %173 = OpFOrdGreaterThan %v3bool %155 %46 + %174 = OpAll %bool %173 + %175 = OpLogicalAnd %bool %172 %174 + OpSelectionMerge %176 DontFlatten + OpBranchConditional %175 %177 %176 + %177 = OpLabel + %178 = OpImageTexelPointer %_ptr_Image_uint %RWShadowTileNumCulledObjects %84 %uint_0 + %179 = OpAtomicIAdd %uint %178 %uint_1 %uint_0 %uint_1 + OpBranch %176 + %176 = OpLabel + OpBranch %118 + %118 = OpLabel + OpStore %out_var_SV_Target0 %22 + OpReturn + OpFunctionEnd diff --git a/third_party/spirv-cross/shaders-ue4/asm/tesc/hs-incorrect-base-type.asm.tesc b/third_party/spirv-cross/shaders-ue4/asm/tesc/hs-incorrect-base-type.asm.tesc new file mode 100644 index 0000000000..4c70e14cb7 --- /dev/null +++ b/third_party/spirv-cross/shaders-ue4/asm/tesc/hs-incorrect-base-type.asm.tesc @@ -0,0 +1,1158 @@ +; SPIR-V +; Version: 1.0 +; Generator: Google spiregg; 0 +; Bound: 598 +; Schema: 0 + OpCapability Tessellation + OpCapability SampledBuffer + OpCapability StorageImageExtendedFormats + OpExtension "SPV_GOOGLE_hlsl_functionality1" + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint TessellationControl %MainHull "main" %in_var_TEXCOORD10_centroid %in_var_TEXCOORD11_centroid %in_var_COLOR0 %in_var_TEXCOORD0 %in_var_TEXCOORD4 %in_var_PRIMITIVE_ID %in_var_LIGHTMAP_ID %in_var_VS_To_DS_Position %gl_InvocationID %out_var_TEXCOORD10_centroid %out_var_TEXCOORD11_centroid %out_var_COLOR0 %out_var_TEXCOORD0 %out_var_TEXCOORD4 %out_var_PRIMITIVE_ID %out_var_LIGHTMAP_ID %out_var_VS_To_DS_Position %out_var_PN_POSITION %out_var_PN_DisplacementScales %out_var_PN_TessellationMultiplier %out_var_PN_WorldDisplacementMultiplier %gl_TessLevelOuter %gl_TessLevelInner %out_var_PN_POSITION9 + OpExecutionMode %MainHull Triangles + OpExecutionMode %MainHull SpacingFractionalOdd + OpExecutionMode %MainHull VertexOrderCw + OpExecutionMode %MainHull OutputVertices 3 + OpSource HLSL 600 + OpName %FPNTessellationHSToDS "FPNTessellationHSToDS" + OpMemberName %FPNTessellationHSToDS 0 "PassSpecificData" + OpMemberName %FPNTessellationHSToDS 1 "WorldPosition" + OpMemberName %FPNTessellationHSToDS 2 "DisplacementScale" + OpMemberName %FPNTessellationHSToDS 3 "TessellationMultiplier" + OpMemberName %FPNTessellationHSToDS 4 "WorldDisplacementMultiplier" + OpName %FBasePassVSToDS "FBasePassVSToDS" + OpMemberName %FBasePassVSToDS 0 "FactoryInterpolants" + OpMemberName %FBasePassVSToDS 1 "BasePassInterpolants" + OpMemberName %FBasePassVSToDS 2 "Position" + OpName %FVertexFactoryInterpolantsVSToDS "FVertexFactoryInterpolantsVSToDS" + OpMemberName %FVertexFactoryInterpolantsVSToDS 0 "InterpolantsVSToPS" + OpName %FVertexFactoryInterpolantsVSToPS "FVertexFactoryInterpolantsVSToPS" + OpMemberName %FVertexFactoryInterpolantsVSToPS 0 "TangentToWorld0" + OpMemberName %FVertexFactoryInterpolantsVSToPS 1 "TangentToWorld2" + OpMemberName %FVertexFactoryInterpolantsVSToPS 2 "Color" + OpMemberName %FVertexFactoryInterpolantsVSToPS 3 "TexCoords" + OpMemberName %FVertexFactoryInterpolantsVSToPS 4 "LightMapCoordinate" + OpMemberName %FVertexFactoryInterpolantsVSToPS 5 "PrimitiveId" + OpMemberName %FVertexFactoryInterpolantsVSToPS 6 "LightmapDataIndex" + OpName %FBasePassInterpolantsVSToDS "FBasePassInterpolantsVSToDS" + OpName %FSharedBasePassInterpolants "FSharedBasePassInterpolants" + OpName %type_View "type.View" + OpMemberName %type_View 0 "View_TranslatedWorldToClip" + OpMemberName %type_View 1 "View_WorldToClip" + OpMemberName %type_View 2 "View_TranslatedWorldToView" + OpMemberName %type_View 3 "View_ViewToTranslatedWorld" + OpMemberName %type_View 4 "View_TranslatedWorldToCameraView" + OpMemberName %type_View 5 "View_CameraViewToTranslatedWorld" + OpMemberName %type_View 6 "View_ViewToClip" + OpMemberName %type_View 7 "View_ViewToClipNoAA" + OpMemberName %type_View 8 "View_ClipToView" + OpMemberName %type_View 9 "View_ClipToTranslatedWorld" + OpMemberName %type_View 10 "View_SVPositionToTranslatedWorld" + OpMemberName %type_View 11 "View_ScreenToWorld" + OpMemberName %type_View 12 "View_ScreenToTranslatedWorld" + OpMemberName %type_View 13 "View_ViewForward" + OpMemberName %type_View 14 "PrePadding_View_844" + OpMemberName %type_View 15 "View_ViewUp" + OpMemberName %type_View 16 "PrePadding_View_860" + OpMemberName %type_View 17 "View_ViewRight" + OpMemberName %type_View 18 "PrePadding_View_876" + OpMemberName %type_View 19 "View_HMDViewNoRollUp" + OpMemberName %type_View 20 "PrePadding_View_892" + OpMemberName %type_View 21 "View_HMDViewNoRollRight" + OpMemberName %type_View 22 "PrePadding_View_908" + OpMemberName %type_View 23 "View_InvDeviceZToWorldZTransform" + OpMemberName %type_View 24 "View_ScreenPositionScaleBias" + OpMemberName %type_View 25 "View_WorldCameraOrigin" + OpMemberName %type_View 26 "PrePadding_View_956" + OpMemberName %type_View 27 "View_TranslatedWorldCameraOrigin" + OpMemberName %type_View 28 "PrePadding_View_972" + OpMemberName %type_View 29 "View_WorldViewOrigin" + OpMemberName %type_View 30 "PrePadding_View_988" + OpMemberName %type_View 31 "View_PreViewTranslation" + OpMemberName %type_View 32 "PrePadding_View_1004" + OpMemberName %type_View 33 "View_PrevProjection" + OpMemberName %type_View 34 "View_PrevViewProj" + OpMemberName %type_View 35 "View_PrevViewRotationProj" + OpMemberName %type_View 36 "View_PrevViewToClip" + OpMemberName %type_View 37 "View_PrevClipToView" + OpMemberName %type_View 38 "View_PrevTranslatedWorldToClip" + OpMemberName %type_View 39 "View_PrevTranslatedWorldToView" + OpMemberName %type_View 40 "View_PrevViewToTranslatedWorld" + OpMemberName %type_View 41 "View_PrevTranslatedWorldToCameraView" + OpMemberName %type_View 42 "View_PrevCameraViewToTranslatedWorld" + OpMemberName %type_View 43 "View_PrevWorldCameraOrigin" + OpMemberName %type_View 44 "PrePadding_View_1660" + OpMemberName %type_View 45 "View_PrevWorldViewOrigin" + OpMemberName %type_View 46 "PrePadding_View_1676" + OpMemberName %type_View 47 "View_PrevPreViewTranslation" + OpMemberName %type_View 48 "PrePadding_View_1692" + OpMemberName %type_View 49 "View_PrevInvViewProj" + OpMemberName %type_View 50 "View_PrevScreenToTranslatedWorld" + OpMemberName %type_View 51 "View_ClipToPrevClip" + OpMemberName %type_View 52 "View_TemporalAAJitter" + OpMemberName %type_View 53 "View_GlobalClippingPlane" + OpMemberName %type_View 54 "View_FieldOfViewWideAngles" + OpMemberName %type_View 55 "View_PrevFieldOfViewWideAngles" + OpMemberName %type_View 56 "View_ViewRectMin" + OpMemberName %type_View 57 "View_ViewSizeAndInvSize" + OpMemberName %type_View 58 "View_BufferSizeAndInvSize" + OpMemberName %type_View 59 "View_BufferBilinearUVMinMax" + OpMemberName %type_View 60 "View_NumSceneColorMSAASamples" + OpMemberName %type_View 61 "View_PreExposure" + OpMemberName %type_View 62 "View_OneOverPreExposure" + OpMemberName %type_View 63 "PrePadding_View_2012" + OpMemberName %type_View 64 "View_DiffuseOverrideParameter" + OpMemberName %type_View 65 "View_SpecularOverrideParameter" + OpMemberName %type_View 66 "View_NormalOverrideParameter" + OpMemberName %type_View 67 "View_RoughnessOverrideParameter" + OpMemberName %type_View 68 "View_PrevFrameGameTime" + OpMemberName %type_View 69 "View_PrevFrameRealTime" + OpMemberName %type_View 70 "View_OutOfBoundsMask" + OpMemberName %type_View 71 "PrePadding_View_2084" + OpMemberName %type_View 72 "PrePadding_View_2088" + OpMemberName %type_View 73 "PrePadding_View_2092" + OpMemberName %type_View 74 "View_WorldCameraMovementSinceLastFrame" + OpMemberName %type_View 75 "View_CullingSign" + OpMemberName %type_View 76 "View_NearPlane" + OpMemberName %type_View 77 "View_AdaptiveTessellationFactor" + OpMemberName %type_View 78 "View_GameTime" + OpMemberName %type_View 79 "View_RealTime" + OpMemberName %type_View 80 "View_DeltaTime" + OpMemberName %type_View 81 "View_MaterialTextureMipBias" + OpMemberName %type_View 82 "View_MaterialTextureDerivativeMultiply" + OpMemberName %type_View 83 "View_Random" + OpMemberName %type_View 84 "View_FrameNumber" + OpMemberName %type_View 85 "View_StateFrameIndexMod8" + OpMemberName %type_View 86 "View_StateFrameIndex" + OpMemberName %type_View 87 "View_CameraCut" + OpMemberName %type_View 88 "View_UnlitViewmodeMask" + OpMemberName %type_View 89 "PrePadding_View_2164" + OpMemberName %type_View 90 "PrePadding_View_2168" + OpMemberName %type_View 91 "PrePadding_View_2172" + OpMemberName %type_View 92 "View_DirectionalLightColor" + OpMemberName %type_View 93 "View_DirectionalLightDirection" + OpMemberName %type_View 94 "PrePadding_View_2204" + OpMemberName %type_View 95 "View_TranslucencyLightingVolumeMin" + OpMemberName %type_View 96 "View_TranslucencyLightingVolumeInvSize" + OpMemberName %type_View 97 "View_TemporalAAParams" + OpMemberName %type_View 98 "View_CircleDOFParams" + OpMemberName %type_View 99 "View_DepthOfFieldSensorWidth" + OpMemberName %type_View 100 "View_DepthOfFieldFocalDistance" + OpMemberName %type_View 101 "View_DepthOfFieldScale" + OpMemberName %type_View 102 "View_DepthOfFieldFocalLength" + OpMemberName %type_View 103 "View_DepthOfFieldFocalRegion" + OpMemberName %type_View 104 "View_DepthOfFieldNearTransitionRegion" + OpMemberName %type_View 105 "View_DepthOfFieldFarTransitionRegion" + OpMemberName %type_View 106 "View_MotionBlurNormalizedToPixel" + OpMemberName %type_View 107 "View_bSubsurfacePostprocessEnabled" + OpMemberName %type_View 108 "View_GeneralPurposeTweak" + OpMemberName %type_View 109 "View_DemosaicVposOffset" + OpMemberName %type_View 110 "PrePadding_View_2348" + OpMemberName %type_View 111 "View_IndirectLightingColorScale" + OpMemberName %type_View 112 "View_HDR32bppEncodingMode" + OpMemberName %type_View 113 "View_AtmosphericFogSunDirection" + OpMemberName %type_View 114 "View_AtmosphericFogSunPower" + OpMemberName %type_View 115 "View_AtmosphericFogPower" + OpMemberName %type_View 116 "View_AtmosphericFogDensityScale" + OpMemberName %type_View 117 "View_AtmosphericFogDensityOffset" + OpMemberName %type_View 118 "View_AtmosphericFogGroundOffset" + OpMemberName %type_View 119 "View_AtmosphericFogDistanceScale" + OpMemberName %type_View 120 "View_AtmosphericFogAltitudeScale" + OpMemberName %type_View 121 "View_AtmosphericFogHeightScaleRayleigh" + OpMemberName %type_View 122 "View_AtmosphericFogStartDistance" + OpMemberName %type_View 123 "View_AtmosphericFogDistanceOffset" + OpMemberName %type_View 124 "View_AtmosphericFogSunDiscScale" + OpMemberName %type_View 125 "View_AtmosphericFogRenderMask" + OpMemberName %type_View 126 "View_AtmosphericFogInscatterAltitudeSampleNum" + OpMemberName %type_View 127 "View_AtmosphericFogSunColor" + OpMemberName %type_View 128 "View_NormalCurvatureToRoughnessScaleBias" + OpMemberName %type_View 129 "View_RenderingReflectionCaptureMask" + OpMemberName %type_View 130 "View_AmbientCubemapTint" + OpMemberName %type_View 131 "View_AmbientCubemapIntensity" + OpMemberName %type_View 132 "View_SkyLightParameters" + OpMemberName %type_View 133 "PrePadding_View_2488" + OpMemberName %type_View 134 "PrePadding_View_2492" + OpMemberName %type_View 135 "View_SkyLightColor" + OpMemberName %type_View 136 "View_SkyIrradianceEnvironmentMap" + OpMemberName %type_View 137 "View_MobilePreviewMode" + OpMemberName %type_View 138 "View_HMDEyePaddingOffset" + OpMemberName %type_View 139 "View_ReflectionCubemapMaxMip" + OpMemberName %type_View 140 "View_ShowDecalsMask" + OpMemberName %type_View 141 "View_DistanceFieldAOSpecularOcclusionMode" + OpMemberName %type_View 142 "View_IndirectCapsuleSelfShadowingIntensity" + OpMemberName %type_View 143 "PrePadding_View_2648" + OpMemberName %type_View 144 "PrePadding_View_2652" + OpMemberName %type_View 145 "View_ReflectionEnvironmentRoughnessMixingScaleBiasAndLargestWeight" + OpMemberName %type_View 146 "View_StereoPassIndex" + OpMemberName %type_View 147 "View_GlobalVolumeCenterAndExtent" + OpMemberName %type_View 148 "View_GlobalVolumeWorldToUVAddAndMul" + OpMemberName %type_View 149 "View_GlobalVolumeDimension" + OpMemberName %type_View 150 "View_GlobalVolumeTexelSize" + OpMemberName %type_View 151 "View_MaxGlobalDistance" + OpMemberName %type_View 152 "View_bCheckerboardSubsurfaceProfileRendering" + OpMemberName %type_View 153 "View_VolumetricFogInvGridSize" + OpMemberName %type_View 154 "PrePadding_View_2828" + OpMemberName %type_View 155 "View_VolumetricFogGridZParams" + OpMemberName %type_View 156 "PrePadding_View_2844" + OpMemberName %type_View 157 "View_VolumetricFogSVPosToVolumeUV" + OpMemberName %type_View 158 "View_VolumetricFogMaxDistance" + OpMemberName %type_View 159 "PrePadding_View_2860" + OpMemberName %type_View 160 "View_VolumetricLightmapWorldToUVScale" + OpMemberName %type_View 161 "PrePadding_View_2876" + OpMemberName %type_View 162 "View_VolumetricLightmapWorldToUVAdd" + OpMemberName %type_View 163 "PrePadding_View_2892" + OpMemberName %type_View 164 "View_VolumetricLightmapIndirectionTextureSize" + OpMemberName %type_View 165 "View_VolumetricLightmapBrickSize" + OpMemberName %type_View 166 "View_VolumetricLightmapBrickTexelSize" + OpMemberName %type_View 167 "View_StereoIPD" + OpMemberName %type_View 168 "View_IndirectLightingCacheShowFlag" + OpMemberName %type_View 169 "View_EyeToPixelSpreadAngle" + OpName %View "View" + OpName %type_StructuredBuffer_v4float "type.StructuredBuffer.v4float" + OpName %View_PrimitiveSceneData "View_PrimitiveSceneData" + OpName %in_var_TEXCOORD10_centroid "in.var.TEXCOORD10_centroid" + OpName %in_var_TEXCOORD11_centroid "in.var.TEXCOORD11_centroid" + OpName %in_var_COLOR0 "in.var.COLOR0" + OpName %in_var_TEXCOORD0 "in.var.TEXCOORD0" + OpName %in_var_TEXCOORD4 "in.var.TEXCOORD4" + OpName %in_var_PRIMITIVE_ID "in.var.PRIMITIVE_ID" + OpName %in_var_LIGHTMAP_ID "in.var.LIGHTMAP_ID" + OpName %in_var_VS_To_DS_Position "in.var.VS_To_DS_Position" + OpName %out_var_TEXCOORD10_centroid "out.var.TEXCOORD10_centroid" + OpName %out_var_TEXCOORD11_centroid "out.var.TEXCOORD11_centroid" + OpName %out_var_COLOR0 "out.var.COLOR0" + OpName %out_var_TEXCOORD0 "out.var.TEXCOORD0" + OpName %out_var_TEXCOORD4 "out.var.TEXCOORD4" + OpName %out_var_PRIMITIVE_ID "out.var.PRIMITIVE_ID" + OpName %out_var_LIGHTMAP_ID "out.var.LIGHTMAP_ID" + OpName %out_var_VS_To_DS_Position "out.var.VS_To_DS_Position" + OpName %out_var_PN_POSITION "out.var.PN_POSITION" + OpName %out_var_PN_DisplacementScales "out.var.PN_DisplacementScales" + OpName %out_var_PN_TessellationMultiplier "out.var.PN_TessellationMultiplier" + OpName %out_var_PN_WorldDisplacementMultiplier "out.var.PN_WorldDisplacementMultiplier" + OpName %out_var_PN_POSITION9 "out.var.PN_POSITION9" + OpName %MainHull "MainHull" + OpName %param_var_I "param.var.I" + OpName %temp_var_hullMainRetVal "temp.var.hullMainRetVal" + OpName %if_merge "if.merge" + OpDecorateString %in_var_TEXCOORD10_centroid UserSemantic "TEXCOORD10_centroid" + OpDecorateString %in_var_TEXCOORD11_centroid UserSemantic "TEXCOORD11_centroid" + OpDecorateString %in_var_COLOR0 UserSemantic "COLOR0" + OpDecorateString %in_var_TEXCOORD0 UserSemantic "TEXCOORD0" + OpDecorateString %in_var_TEXCOORD4 UserSemantic "TEXCOORD4" + OpDecorateString %in_var_PRIMITIVE_ID UserSemantic "PRIMITIVE_ID" + OpDecorateString %in_var_LIGHTMAP_ID UserSemantic "LIGHTMAP_ID" + OpDecorateString %in_var_VS_To_DS_Position UserSemantic "VS_To_DS_Position" + OpDecorate %gl_InvocationID BuiltIn InvocationId + OpDecorateString %gl_InvocationID UserSemantic "SV_OutputControlPointID" + OpDecorateString %out_var_TEXCOORD10_centroid UserSemantic "TEXCOORD10_centroid" + OpDecorateString %out_var_TEXCOORD11_centroid UserSemantic "TEXCOORD11_centroid" + OpDecorateString %out_var_COLOR0 UserSemantic "COLOR0" + OpDecorateString %out_var_TEXCOORD0 UserSemantic "TEXCOORD0" + OpDecorateString %out_var_TEXCOORD4 UserSemantic "TEXCOORD4" + OpDecorateString %out_var_PRIMITIVE_ID UserSemantic "PRIMITIVE_ID" + OpDecorateString %out_var_LIGHTMAP_ID UserSemantic "LIGHTMAP_ID" + OpDecorateString %out_var_VS_To_DS_Position UserSemantic "VS_To_DS_Position" + OpDecorateString %out_var_PN_POSITION UserSemantic "PN_POSITION" + OpDecorateString %out_var_PN_DisplacementScales UserSemantic "PN_DisplacementScales" + OpDecorateString %out_var_PN_TessellationMultiplier UserSemantic "PN_TessellationMultiplier" + OpDecorateString %out_var_PN_WorldDisplacementMultiplier UserSemantic "PN_WorldDisplacementMultiplier" + OpDecorate %gl_TessLevelOuter BuiltIn TessLevelOuter + OpDecorateString %gl_TessLevelOuter UserSemantic "SV_TessFactor" + OpDecorate %gl_TessLevelOuter Patch + OpDecorate %gl_TessLevelInner BuiltIn TessLevelInner + OpDecorateString %gl_TessLevelInner UserSemantic "SV_InsideTessFactor" + OpDecorate %gl_TessLevelInner Patch + OpDecorateString %out_var_PN_POSITION9 UserSemantic "PN_POSITION9" + OpDecorate %out_var_PN_POSITION9 Patch + OpDecorate %in_var_TEXCOORD10_centroid Location 0 + OpDecorate %in_var_TEXCOORD11_centroid Location 1 + OpDecorate %in_var_COLOR0 Location 2 + OpDecorate %in_var_TEXCOORD0 Location 3 + OpDecorate %in_var_TEXCOORD4 Location 4 + OpDecorate %in_var_PRIMITIVE_ID Location 5 + OpDecorate %in_var_LIGHTMAP_ID Location 6 + OpDecorate %in_var_VS_To_DS_Position Location 7 + OpDecorate %out_var_COLOR0 Location 0 + OpDecorate %out_var_LIGHTMAP_ID Location 1 + OpDecorate %out_var_PN_DisplacementScales Location 2 + OpDecorate %out_var_PN_POSITION Location 3 + OpDecorate %out_var_PN_POSITION9 Location 6 + OpDecorate %out_var_PN_TessellationMultiplier Location 7 + OpDecorate %out_var_PN_WorldDisplacementMultiplier Location 8 + OpDecorate %out_var_PRIMITIVE_ID Location 9 + OpDecorate %out_var_TEXCOORD0 Location 10 + OpDecorate %out_var_TEXCOORD10_centroid Location 11 + OpDecorate %out_var_TEXCOORD11_centroid Location 12 + OpDecorate %out_var_TEXCOORD4 Location 13 + OpDecorate %out_var_VS_To_DS_Position Location 14 + OpDecorate %View DescriptorSet 0 + OpDecorate %View Binding 1 + OpDecorate %View_PrimitiveSceneData DescriptorSet 0 + OpDecorate %View_PrimitiveSceneData Binding 0 + OpDecorate %_arr_v4float_uint_4 ArrayStride 16 + OpDecorate %_arr_v4float_uint_2 ArrayStride 16 + OpDecorate %_arr_v4float_uint_7 ArrayStride 16 + OpMemberDecorate %type_View 0 Offset 0 + OpMemberDecorate %type_View 0 MatrixStride 16 + OpMemberDecorate %type_View 0 ColMajor + OpMemberDecorate %type_View 1 Offset 64 + OpMemberDecorate %type_View 1 MatrixStride 16 + OpMemberDecorate %type_View 1 ColMajor + OpMemberDecorate %type_View 2 Offset 128 + OpMemberDecorate %type_View 2 MatrixStride 16 + OpMemberDecorate %type_View 2 ColMajor + OpMemberDecorate %type_View 3 Offset 192 + OpMemberDecorate %type_View 3 MatrixStride 16 + OpMemberDecorate %type_View 3 ColMajor + OpMemberDecorate %type_View 4 Offset 256 + OpMemberDecorate %type_View 4 MatrixStride 16 + OpMemberDecorate %type_View 4 ColMajor + OpMemberDecorate %type_View 5 Offset 320 + OpMemberDecorate %type_View 5 MatrixStride 16 + OpMemberDecorate %type_View 5 ColMajor + OpMemberDecorate %type_View 6 Offset 384 + OpMemberDecorate %type_View 6 MatrixStride 16 + OpMemberDecorate %type_View 6 ColMajor + OpMemberDecorate %type_View 7 Offset 448 + OpMemberDecorate %type_View 7 MatrixStride 16 + OpMemberDecorate %type_View 7 ColMajor + OpMemberDecorate %type_View 8 Offset 512 + OpMemberDecorate %type_View 8 MatrixStride 16 + OpMemberDecorate %type_View 8 ColMajor + OpMemberDecorate %type_View 9 Offset 576 + OpMemberDecorate %type_View 9 MatrixStride 16 + OpMemberDecorate %type_View 9 ColMajor + OpMemberDecorate %type_View 10 Offset 640 + OpMemberDecorate %type_View 10 MatrixStride 16 + OpMemberDecorate %type_View 10 ColMajor + OpMemberDecorate %type_View 11 Offset 704 + OpMemberDecorate %type_View 11 MatrixStride 16 + OpMemberDecorate %type_View 11 ColMajor + OpMemberDecorate %type_View 12 Offset 768 + OpMemberDecorate %type_View 12 MatrixStride 16 + OpMemberDecorate %type_View 12 ColMajor + OpMemberDecorate %type_View 13 Offset 832 + OpMemberDecorate %type_View 14 Offset 844 + OpMemberDecorate %type_View 15 Offset 848 + OpMemberDecorate %type_View 16 Offset 860 + OpMemberDecorate %type_View 17 Offset 864 + OpMemberDecorate %type_View 18 Offset 876 + OpMemberDecorate %type_View 19 Offset 880 + OpMemberDecorate %type_View 20 Offset 892 + OpMemberDecorate %type_View 21 Offset 896 + OpMemberDecorate %type_View 22 Offset 908 + OpMemberDecorate %type_View 23 Offset 912 + OpMemberDecorate %type_View 24 Offset 928 + OpMemberDecorate %type_View 25 Offset 944 + OpMemberDecorate %type_View 26 Offset 956 + OpMemberDecorate %type_View 27 Offset 960 + OpMemberDecorate %type_View 28 Offset 972 + OpMemberDecorate %type_View 29 Offset 976 + OpMemberDecorate %type_View 30 Offset 988 + OpMemberDecorate %type_View 31 Offset 992 + OpMemberDecorate %type_View 32 Offset 1004 + OpMemberDecorate %type_View 33 Offset 1008 + OpMemberDecorate %type_View 33 MatrixStride 16 + OpMemberDecorate %type_View 33 ColMajor + OpMemberDecorate %type_View 34 Offset 1072 + OpMemberDecorate %type_View 34 MatrixStride 16 + OpMemberDecorate %type_View 34 ColMajor + OpMemberDecorate %type_View 35 Offset 1136 + OpMemberDecorate %type_View 35 MatrixStride 16 + OpMemberDecorate %type_View 35 ColMajor + OpMemberDecorate %type_View 36 Offset 1200 + OpMemberDecorate %type_View 36 MatrixStride 16 + OpMemberDecorate %type_View 36 ColMajor + OpMemberDecorate %type_View 37 Offset 1264 + OpMemberDecorate %type_View 37 MatrixStride 16 + OpMemberDecorate %type_View 37 ColMajor + OpMemberDecorate %type_View 38 Offset 1328 + OpMemberDecorate %type_View 38 MatrixStride 16 + OpMemberDecorate %type_View 38 ColMajor + OpMemberDecorate %type_View 39 Offset 1392 + OpMemberDecorate %type_View 39 MatrixStride 16 + OpMemberDecorate %type_View 39 ColMajor + OpMemberDecorate %type_View 40 Offset 1456 + OpMemberDecorate %type_View 40 MatrixStride 16 + OpMemberDecorate %type_View 40 ColMajor + OpMemberDecorate %type_View 41 Offset 1520 + OpMemberDecorate %type_View 41 MatrixStride 16 + OpMemberDecorate %type_View 41 ColMajor + OpMemberDecorate %type_View 42 Offset 1584 + OpMemberDecorate %type_View 42 MatrixStride 16 + OpMemberDecorate %type_View 42 ColMajor + OpMemberDecorate %type_View 43 Offset 1648 + OpMemberDecorate %type_View 44 Offset 1660 + OpMemberDecorate %type_View 45 Offset 1664 + OpMemberDecorate %type_View 46 Offset 1676 + OpMemberDecorate %type_View 47 Offset 1680 + OpMemberDecorate %type_View 48 Offset 1692 + OpMemberDecorate %type_View 49 Offset 1696 + OpMemberDecorate %type_View 49 MatrixStride 16 + OpMemberDecorate %type_View 49 ColMajor + OpMemberDecorate %type_View 50 Offset 1760 + OpMemberDecorate %type_View 50 MatrixStride 16 + OpMemberDecorate %type_View 50 ColMajor + OpMemberDecorate %type_View 51 Offset 1824 + OpMemberDecorate %type_View 51 MatrixStride 16 + OpMemberDecorate %type_View 51 ColMajor + OpMemberDecorate %type_View 52 Offset 1888 + OpMemberDecorate %type_View 53 Offset 1904 + OpMemberDecorate %type_View 54 Offset 1920 + OpMemberDecorate %type_View 55 Offset 1928 + OpMemberDecorate %type_View 56 Offset 1936 + OpMemberDecorate %type_View 57 Offset 1952 + OpMemberDecorate %type_View 58 Offset 1968 + OpMemberDecorate %type_View 59 Offset 1984 + OpMemberDecorate %type_View 60 Offset 2000 + OpMemberDecorate %type_View 61 Offset 2004 + OpMemberDecorate %type_View 62 Offset 2008 + OpMemberDecorate %type_View 63 Offset 2012 + OpMemberDecorate %type_View 64 Offset 2016 + OpMemberDecorate %type_View 65 Offset 2032 + OpMemberDecorate %type_View 66 Offset 2048 + OpMemberDecorate %type_View 67 Offset 2064 + OpMemberDecorate %type_View 68 Offset 2072 + OpMemberDecorate %type_View 69 Offset 2076 + OpMemberDecorate %type_View 70 Offset 2080 + OpMemberDecorate %type_View 71 Offset 2084 + OpMemberDecorate %type_View 72 Offset 2088 + OpMemberDecorate %type_View 73 Offset 2092 + OpMemberDecorate %type_View 74 Offset 2096 + OpMemberDecorate %type_View 75 Offset 2108 + OpMemberDecorate %type_View 76 Offset 2112 + OpMemberDecorate %type_View 77 Offset 2116 + OpMemberDecorate %type_View 78 Offset 2120 + OpMemberDecorate %type_View 79 Offset 2124 + OpMemberDecorate %type_View 80 Offset 2128 + OpMemberDecorate %type_View 81 Offset 2132 + OpMemberDecorate %type_View 82 Offset 2136 + OpMemberDecorate %type_View 83 Offset 2140 + OpMemberDecorate %type_View 84 Offset 2144 + OpMemberDecorate %type_View 85 Offset 2148 + OpMemberDecorate %type_View 86 Offset 2152 + OpMemberDecorate %type_View 87 Offset 2156 + OpMemberDecorate %type_View 88 Offset 2160 + OpMemberDecorate %type_View 89 Offset 2164 + OpMemberDecorate %type_View 90 Offset 2168 + OpMemberDecorate %type_View 91 Offset 2172 + OpMemberDecorate %type_View 92 Offset 2176 + OpMemberDecorate %type_View 93 Offset 2192 + OpMemberDecorate %type_View 94 Offset 2204 + OpMemberDecorate %type_View 95 Offset 2208 + OpMemberDecorate %type_View 96 Offset 2240 + OpMemberDecorate %type_View 97 Offset 2272 + OpMemberDecorate %type_View 98 Offset 2288 + OpMemberDecorate %type_View 99 Offset 2304 + OpMemberDecorate %type_View 100 Offset 2308 + OpMemberDecorate %type_View 101 Offset 2312 + OpMemberDecorate %type_View 102 Offset 2316 + OpMemberDecorate %type_View 103 Offset 2320 + OpMemberDecorate %type_View 104 Offset 2324 + OpMemberDecorate %type_View 105 Offset 2328 + OpMemberDecorate %type_View 106 Offset 2332 + OpMemberDecorate %type_View 107 Offset 2336 + OpMemberDecorate %type_View 108 Offset 2340 + OpMemberDecorate %type_View 109 Offset 2344 + OpMemberDecorate %type_View 110 Offset 2348 + OpMemberDecorate %type_View 111 Offset 2352 + OpMemberDecorate %type_View 112 Offset 2364 + OpMemberDecorate %type_View 113 Offset 2368 + OpMemberDecorate %type_View 114 Offset 2380 + OpMemberDecorate %type_View 115 Offset 2384 + OpMemberDecorate %type_View 116 Offset 2388 + OpMemberDecorate %type_View 117 Offset 2392 + OpMemberDecorate %type_View 118 Offset 2396 + OpMemberDecorate %type_View 119 Offset 2400 + OpMemberDecorate %type_View 120 Offset 2404 + OpMemberDecorate %type_View 121 Offset 2408 + OpMemberDecorate %type_View 122 Offset 2412 + OpMemberDecorate %type_View 123 Offset 2416 + OpMemberDecorate %type_View 124 Offset 2420 + OpMemberDecorate %type_View 125 Offset 2424 + OpMemberDecorate %type_View 126 Offset 2428 + OpMemberDecorate %type_View 127 Offset 2432 + OpMemberDecorate %type_View 128 Offset 2448 + OpMemberDecorate %type_View 129 Offset 2460 + OpMemberDecorate %type_View 130 Offset 2464 + OpMemberDecorate %type_View 131 Offset 2480 + OpMemberDecorate %type_View 132 Offset 2484 + OpMemberDecorate %type_View 133 Offset 2488 + OpMemberDecorate %type_View 134 Offset 2492 + OpMemberDecorate %type_View 135 Offset 2496 + OpMemberDecorate %type_View 136 Offset 2512 + OpMemberDecorate %type_View 137 Offset 2624 + OpMemberDecorate %type_View 138 Offset 2628 + OpMemberDecorate %type_View 139 Offset 2632 + OpMemberDecorate %type_View 140 Offset 2636 + OpMemberDecorate %type_View 141 Offset 2640 + OpMemberDecorate %type_View 142 Offset 2644 + OpMemberDecorate %type_View 143 Offset 2648 + OpMemberDecorate %type_View 144 Offset 2652 + OpMemberDecorate %type_View 145 Offset 2656 + OpMemberDecorate %type_View 146 Offset 2668 + OpMemberDecorate %type_View 147 Offset 2672 + OpMemberDecorate %type_View 148 Offset 2736 + OpMemberDecorate %type_View 149 Offset 2800 + OpMemberDecorate %type_View 150 Offset 2804 + OpMemberDecorate %type_View 151 Offset 2808 + OpMemberDecorate %type_View 152 Offset 2812 + OpMemberDecorate %type_View 153 Offset 2816 + OpMemberDecorate %type_View 154 Offset 2828 + OpMemberDecorate %type_View 155 Offset 2832 + OpMemberDecorate %type_View 156 Offset 2844 + OpMemberDecorate %type_View 157 Offset 2848 + OpMemberDecorate %type_View 158 Offset 2856 + OpMemberDecorate %type_View 159 Offset 2860 + OpMemberDecorate %type_View 160 Offset 2864 + OpMemberDecorate %type_View 161 Offset 2876 + OpMemberDecorate %type_View 162 Offset 2880 + OpMemberDecorate %type_View 163 Offset 2892 + OpMemberDecorate %type_View 164 Offset 2896 + OpMemberDecorate %type_View 165 Offset 2908 + OpMemberDecorate %type_View 166 Offset 2912 + OpMemberDecorate %type_View 167 Offset 2924 + OpMemberDecorate %type_View 168 Offset 2928 + OpMemberDecorate %type_View 169 Offset 2932 + OpDecorate %type_View Block + OpDecorate %_runtimearr_v4float ArrayStride 16 + OpMemberDecorate %type_StructuredBuffer_v4float 0 Offset 0 + OpMemberDecorate %type_StructuredBuffer_v4float 0 NonWritable + OpDecorate %type_StructuredBuffer_v4float BufferBlock + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 +%mat4v4float = OpTypeMatrix %v4float 4 + %v3float = OpTypeVector %float 3 + %v2float = OpTypeVector %float 2 + %int = OpTypeInt 32 1 + %uint = OpTypeInt 32 0 + %uint_2 = OpConstant %uint 2 + %uint_7 = OpConstant %uint 7 + %uint_4 = OpConstant %uint 4 + %uint_0 = OpConstant %uint 0 + %uint_1 = OpConstant %uint 1 + %uint_3 = OpConstant %uint 3 +%_arr_float_uint_3 = OpTypeArray %float %uint_3 + %int_1 = OpConstant %int 1 + %int_0 = OpConstant %int 0 + %int_2 = OpConstant %int 2 + %float_2 = OpConstant %float 2 + %62 = OpConstantComposite %v4float %float_2 %float_2 %float_2 %float_2 + %float_0_5 = OpConstant %float 0.5 + %int_3 = OpConstant %int 3 +%float_0_333000004 = OpConstant %float 0.333000004 + %float_1 = OpConstant %float 1 + %67 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1 + %float_15 = OpConstant %float 15 + %69 = OpConstantComposite %v4float %float_15 %float_15 %float_15 %float_15 +%_arr_v4float_uint_1 = OpTypeArray %v4float %uint_1 +%FVertexFactoryInterpolantsVSToPS = OpTypeStruct %v4float %v4float %v4float %_arr_v4float_uint_1 %v4float %uint %uint +%FVertexFactoryInterpolantsVSToDS = OpTypeStruct %FVertexFactoryInterpolantsVSToPS +%FSharedBasePassInterpolants = OpTypeStruct +%FBasePassInterpolantsVSToDS = OpTypeStruct %FSharedBasePassInterpolants +%FBasePassVSToDS = OpTypeStruct %FVertexFactoryInterpolantsVSToDS %FBasePassInterpolantsVSToDS %v4float +%_arr_v4float_uint_3 = OpTypeArray %v4float %uint_3 +%FPNTessellationHSToDS = OpTypeStruct %FBasePassVSToDS %_arr_v4float_uint_3 %v3float %float %float + %v3int = OpTypeVector %int 3 + %73 = OpConstantComposite %v3int %int_0 %int_0 %int_0 + %74 = OpConstantComposite %v3int %int_3 %int_3 %int_3 + %float_0 = OpConstant %float 0 + %76 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0 + %77 = OpConstantComposite %v3float %float_0_5 %float_0_5 %float_0_5 + %int_77 = OpConstant %int 77 + %int_6 = OpConstant %int 6 + %int_27 = OpConstant %int 27 + %81 = OpConstantComposite %v3int %int_1 %int_1 %int_1 + %82 = OpConstantComposite %v3int %int_2 %int_2 %int_2 + %uint_26 = OpConstant %uint 26 + %uint_12 = OpConstant %uint 12 + %uint_22 = OpConstant %uint 22 +%_arr_v4float_uint_4 = OpTypeArray %v4float %uint_4 +%_arr_v4float_uint_2 = OpTypeArray %v4float %uint_2 +%_arr_v4float_uint_7 = OpTypeArray %v4float %uint_7 + %type_View = OpTypeStruct %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %v3float %float %v3float %float %v3float %float %v3float %float %v3float %float %v4float %v4float %v3float %float %v3float %float %v3float %float %v3float %float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %v3float %float %v3float %float %v3float %float %mat4v4float %mat4v4float %mat4v4float %v4float %v4float %v2float %v2float %v4float %v4float %v4float %v4float %int %float %float %float %v4float %v4float %v4float %v2float %float %float %float %float %float %float %v3float %float %float %float %float %float %float %float %float %uint %uint %uint %uint %float %float %float %float %float %v4float %v3float %float %_arr_v4float_uint_2 %_arr_v4float_uint_2 %v4float %v4float %float %float %float %float %float %float %float %float %float %float %float %float %v3float %float %v3float %float %float %float %float %float %float %float %float %float %float %float %uint %uint %v4float %v3float %float %v4float %float %float %float %float %v4float %_arr_v4float_uint_7 %float %float %float %float %uint %float %float %float %v3float %int %_arr_v4float_uint_4 %_arr_v4float_uint_4 %float %float %float %float %v3float %float %v3float %float %v2float %float %float %v3float %float %v3float %float %v3float %float %v3float %float %float %float +%_ptr_Uniform_type_View = OpTypePointer Uniform %type_View +%_runtimearr_v4float = OpTypeRuntimeArray %v4float +%type_StructuredBuffer_v4float = OpTypeStruct %_runtimearr_v4float +%_ptr_Uniform_type_StructuredBuffer_v4float = OpTypePointer Uniform %type_StructuredBuffer_v4float +%_arr_v4float_uint_12 = OpTypeArray %v4float %uint_12 +%_ptr_Input__arr_v4float_uint_12 = OpTypePointer Input %_arr_v4float_uint_12 +%_arr__arr_v4float_uint_1_uint_12 = OpTypeArray %_arr_v4float_uint_1 %uint_12 +%_ptr_Input__arr__arr_v4float_uint_1_uint_12 = OpTypePointer Input %_arr__arr_v4float_uint_1_uint_12 +%_arr_uint_uint_12 = OpTypeArray %uint %uint_12 +%_ptr_Input__arr_uint_uint_12 = OpTypePointer Input %_arr_uint_uint_12 +%_ptr_Input_uint = OpTypePointer Input %uint +%_ptr_Output__arr_v4float_uint_3 = OpTypePointer Output %_arr_v4float_uint_3 +%_arr__arr_v4float_uint_1_uint_3 = OpTypeArray %_arr_v4float_uint_1 %uint_3 +%_ptr_Output__arr__arr_v4float_uint_1_uint_3 = OpTypePointer Output %_arr__arr_v4float_uint_1_uint_3 +%_arr_uint_uint_3 = OpTypeArray %uint %uint_3 +%_ptr_Output__arr_uint_uint_3 = OpTypePointer Output %_arr_uint_uint_3 +%_arr__arr_v4float_uint_3_uint_3 = OpTypeArray %_arr_v4float_uint_3 %uint_3 +%_ptr_Output__arr__arr_v4float_uint_3_uint_3 = OpTypePointer Output %_arr__arr_v4float_uint_3_uint_3 +%_arr_v3float_uint_3 = OpTypeArray %v3float %uint_3 +%_ptr_Output__arr_v3float_uint_3 = OpTypePointer Output %_arr_v3float_uint_3 +%_ptr_Output__arr_float_uint_3 = OpTypePointer Output %_arr_float_uint_3 +%_arr_float_uint_4 = OpTypeArray %float %uint_4 +%_ptr_Output__arr_float_uint_4 = OpTypePointer Output %_arr_float_uint_4 +%_arr_float_uint_2 = OpTypeArray %float %uint_2 +%_ptr_Output__arr_float_uint_2 = OpTypePointer Output %_arr_float_uint_2 +%_ptr_Output_v4float = OpTypePointer Output %v4float + %void = OpTypeVoid + %111 = OpTypeFunction %void +%_arr_FBasePassVSToDS_uint_12 = OpTypeArray %FBasePassVSToDS %uint_12 +%_ptr_Function__arr_FBasePassVSToDS_uint_12 = OpTypePointer Function %_arr_FBasePassVSToDS_uint_12 +%_arr_FPNTessellationHSToDS_uint_3 = OpTypeArray %FPNTessellationHSToDS %uint_3 +%_ptr_Workgroup__arr_FPNTessellationHSToDS_uint_3 = OpTypePointer Workgroup %_arr_FPNTessellationHSToDS_uint_3 +%_ptr_Output__arr_v4float_uint_1 = OpTypePointer Output %_arr_v4float_uint_1 +%_ptr_Output_uint = OpTypePointer Output %uint +%_ptr_Output_v3float = OpTypePointer Output %v3float +%_ptr_Output_float = OpTypePointer Output %float +%_ptr_Workgroup_FPNTessellationHSToDS = OpTypePointer Workgroup %FPNTessellationHSToDS + %bool = OpTypeBool +%_ptr_Function_v4float = OpTypePointer Function %v4float +%_ptr_Workgroup_v4float = OpTypePointer Workgroup %v4float +%_ptr_Function_float = OpTypePointer Function %float +%_ptr_Workgroup_float = OpTypePointer Workgroup %float +%mat3v3float = OpTypeMatrix %v3float 3 +%_ptr_Function_FVertexFactoryInterpolantsVSToDS = OpTypePointer Function %FVertexFactoryInterpolantsVSToDS +%_ptr_Function_FVertexFactoryInterpolantsVSToPS = OpTypePointer Function %FVertexFactoryInterpolantsVSToPS +%_ptr_Function_FBasePassVSToDS = OpTypePointer Function %FBasePassVSToDS + %v3bool = OpTypeVector %bool 3 +%_ptr_Uniform_float = OpTypePointer Uniform %float +%_ptr_Uniform_mat4v4float = OpTypePointer Uniform %mat4v4float +%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float +%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float + %View = OpVariable %_ptr_Uniform_type_View Uniform +%View_PrimitiveSceneData = OpVariable %_ptr_Uniform_type_StructuredBuffer_v4float Uniform +%in_var_TEXCOORD10_centroid = OpVariable %_ptr_Input__arr_v4float_uint_12 Input +%in_var_TEXCOORD11_centroid = OpVariable %_ptr_Input__arr_v4float_uint_12 Input +%in_var_COLOR0 = OpVariable %_ptr_Input__arr_v4float_uint_12 Input +%in_var_TEXCOORD0 = OpVariable %_ptr_Input__arr__arr_v4float_uint_1_uint_12 Input +%in_var_TEXCOORD4 = OpVariable %_ptr_Input__arr_v4float_uint_12 Input +%in_var_PRIMITIVE_ID = OpVariable %_ptr_Input__arr_uint_uint_12 Input +%in_var_LIGHTMAP_ID = OpVariable %_ptr_Input__arr_uint_uint_12 Input +%in_var_VS_To_DS_Position = OpVariable %_ptr_Input__arr_v4float_uint_12 Input +%gl_InvocationID = OpVariable %_ptr_Input_uint Input +%out_var_TEXCOORD10_centroid = OpVariable %_ptr_Output__arr_v4float_uint_3 Output +%out_var_TEXCOORD11_centroid = OpVariable %_ptr_Output__arr_v4float_uint_3 Output +%out_var_COLOR0 = OpVariable %_ptr_Output__arr_v4float_uint_3 Output +%out_var_TEXCOORD0 = OpVariable %_ptr_Output__arr__arr_v4float_uint_1_uint_3 Output +%out_var_TEXCOORD4 = OpVariable %_ptr_Output__arr_v4float_uint_3 Output +%out_var_PRIMITIVE_ID = OpVariable %_ptr_Output__arr_uint_uint_3 Output +%out_var_LIGHTMAP_ID = OpVariable %_ptr_Output__arr_uint_uint_3 Output +%out_var_VS_To_DS_Position = OpVariable %_ptr_Output__arr_v4float_uint_3 Output +%out_var_PN_POSITION = OpVariable %_ptr_Output__arr__arr_v4float_uint_3_uint_3 Output +%out_var_PN_DisplacementScales = OpVariable %_ptr_Output__arr_v3float_uint_3 Output +%out_var_PN_TessellationMultiplier = OpVariable %_ptr_Output__arr_float_uint_3 Output +%out_var_PN_WorldDisplacementMultiplier = OpVariable %_ptr_Output__arr_float_uint_3 Output +%gl_TessLevelOuter = OpVariable %_ptr_Output__arr_float_uint_4 Output +%gl_TessLevelInner = OpVariable %_ptr_Output__arr_float_uint_2 Output +%out_var_PN_POSITION9 = OpVariable %_ptr_Output_v4float Output + %133 = OpConstantNull %FSharedBasePassInterpolants + %134 = OpConstantComposite %FBasePassInterpolantsVSToDS %133 +%float_0_333333343 = OpConstant %float 0.333333343 + %136 = OpConstantComposite %v4float %float_0_333333343 %float_0_333333343 %float_0_333333343 %float_0_333333343 + %137 = OpConstantComposite %v4float %float_0_5 %float_0_5 %float_0_5 %float_0_5 +%float_0_166666672 = OpConstant %float 0.166666672 + %139 = OpConstantComposite %v4float %float_0_166666672 %float_0_166666672 %float_0_166666672 %float_0_166666672 + %140 = OpUndef %v4float + +; XXX: Original asm used Function here, which is wrong. +; This patches the SPIR-V to be correct. +%temp_var_hullMainRetVal = OpVariable %_ptr_Workgroup__arr_FPNTessellationHSToDS_uint_3 Workgroup + + %MainHull = OpFunction %void None %111 + %141 = OpLabel +%param_var_I = OpVariable %_ptr_Function__arr_FBasePassVSToDS_uint_12 Function + %142 = OpLoad %_arr_v4float_uint_12 %in_var_TEXCOORD10_centroid + %143 = OpLoad %_arr_v4float_uint_12 %in_var_TEXCOORD11_centroid + %144 = OpLoad %_arr_v4float_uint_12 %in_var_COLOR0 + %145 = OpLoad %_arr__arr_v4float_uint_1_uint_12 %in_var_TEXCOORD0 + %146 = OpLoad %_arr_v4float_uint_12 %in_var_TEXCOORD4 + %147 = OpLoad %_arr_uint_uint_12 %in_var_PRIMITIVE_ID + %148 = OpLoad %_arr_uint_uint_12 %in_var_LIGHTMAP_ID + %149 = OpCompositeExtract %v4float %142 0 + %150 = OpCompositeExtract %v4float %143 0 + %151 = OpCompositeExtract %v4float %144 0 + %152 = OpCompositeExtract %_arr_v4float_uint_1 %145 0 + %153 = OpCompositeExtract %v4float %146 0 + %154 = OpCompositeExtract %uint %147 0 + %155 = OpCompositeExtract %uint %148 0 + %156 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToPS %149 %150 %151 %152 %153 %154 %155 + %157 = OpCompositeExtract %v4float %142 1 + %158 = OpCompositeExtract %v4float %143 1 + %159 = OpCompositeExtract %v4float %144 1 + %160 = OpCompositeExtract %_arr_v4float_uint_1 %145 1 + %161 = OpCompositeExtract %v4float %146 1 + %162 = OpCompositeExtract %uint %147 1 + %163 = OpCompositeExtract %uint %148 1 + %164 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToPS %157 %158 %159 %160 %161 %162 %163 + %165 = OpCompositeExtract %v4float %142 2 + %166 = OpCompositeExtract %v4float %143 2 + %167 = OpCompositeExtract %v4float %144 2 + %168 = OpCompositeExtract %_arr_v4float_uint_1 %145 2 + %169 = OpCompositeExtract %v4float %146 2 + %170 = OpCompositeExtract %uint %147 2 + %171 = OpCompositeExtract %uint %148 2 + %172 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToPS %165 %166 %167 %168 %169 %170 %171 + %173 = OpCompositeExtract %v4float %142 3 + %174 = OpCompositeExtract %v4float %143 3 + %175 = OpCompositeExtract %v4float %144 3 + %176 = OpCompositeExtract %_arr_v4float_uint_1 %145 3 + %177 = OpCompositeExtract %v4float %146 3 + %178 = OpCompositeExtract %uint %147 3 + %179 = OpCompositeExtract %uint %148 3 + %180 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToPS %173 %174 %175 %176 %177 %178 %179 + %181 = OpCompositeExtract %v4float %142 4 + %182 = OpCompositeExtract %v4float %143 4 + %183 = OpCompositeExtract %v4float %144 4 + %184 = OpCompositeExtract %_arr_v4float_uint_1 %145 4 + %185 = OpCompositeExtract %v4float %146 4 + %186 = OpCompositeExtract %uint %147 4 + %187 = OpCompositeExtract %uint %148 4 + %188 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToPS %181 %182 %183 %184 %185 %186 %187 + %189 = OpCompositeExtract %v4float %142 5 + %190 = OpCompositeExtract %v4float %143 5 + %191 = OpCompositeExtract %v4float %144 5 + %192 = OpCompositeExtract %_arr_v4float_uint_1 %145 5 + %193 = OpCompositeExtract %v4float %146 5 + %194 = OpCompositeExtract %uint %147 5 + %195 = OpCompositeExtract %uint %148 5 + %196 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToPS %189 %190 %191 %192 %193 %194 %195 + %197 = OpCompositeExtract %v4float %142 6 + %198 = OpCompositeExtract %v4float %143 6 + %199 = OpCompositeExtract %v4float %144 6 + %200 = OpCompositeExtract %_arr_v4float_uint_1 %145 6 + %201 = OpCompositeExtract %v4float %146 6 + %202 = OpCompositeExtract %uint %147 6 + %203 = OpCompositeExtract %uint %148 6 + %204 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToPS %197 %198 %199 %200 %201 %202 %203 + %205 = OpCompositeExtract %v4float %142 7 + %206 = OpCompositeExtract %v4float %143 7 + %207 = OpCompositeExtract %v4float %144 7 + %208 = OpCompositeExtract %_arr_v4float_uint_1 %145 7 + %209 = OpCompositeExtract %v4float %146 7 + %210 = OpCompositeExtract %uint %147 7 + %211 = OpCompositeExtract %uint %148 7 + %212 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToPS %205 %206 %207 %208 %209 %210 %211 + %213 = OpCompositeExtract %v4float %142 8 + %214 = OpCompositeExtract %v4float %143 8 + %215 = OpCompositeExtract %v4float %144 8 + %216 = OpCompositeExtract %_arr_v4float_uint_1 %145 8 + %217 = OpCompositeExtract %v4float %146 8 + %218 = OpCompositeExtract %uint %147 8 + %219 = OpCompositeExtract %uint %148 8 + %220 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToPS %213 %214 %215 %216 %217 %218 %219 + %221 = OpCompositeExtract %v4float %142 9 + %222 = OpCompositeExtract %v4float %143 9 + %223 = OpCompositeExtract %v4float %144 9 + %224 = OpCompositeExtract %_arr_v4float_uint_1 %145 9 + %225 = OpCompositeExtract %v4float %146 9 + %226 = OpCompositeExtract %uint %147 9 + %227 = OpCompositeExtract %uint %148 9 + %228 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToPS %221 %222 %223 %224 %225 %226 %227 + %229 = OpCompositeExtract %v4float %142 10 + %230 = OpCompositeExtract %v4float %143 10 + %231 = OpCompositeExtract %v4float %144 10 + %232 = OpCompositeExtract %_arr_v4float_uint_1 %145 10 + %233 = OpCompositeExtract %v4float %146 10 + %234 = OpCompositeExtract %uint %147 10 + %235 = OpCompositeExtract %uint %148 10 + %236 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToPS %229 %230 %231 %232 %233 %234 %235 + %237 = OpCompositeExtract %v4float %142 11 + %238 = OpCompositeExtract %v4float %143 11 + %239 = OpCompositeExtract %v4float %144 11 + %240 = OpCompositeExtract %_arr_v4float_uint_1 %145 11 + %241 = OpCompositeExtract %v4float %146 11 + %242 = OpCompositeExtract %uint %147 11 + %243 = OpCompositeExtract %uint %148 11 + %244 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToPS %237 %238 %239 %240 %241 %242 %243 + %245 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToDS %156 + %246 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToDS %164 + %247 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToDS %172 + %248 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToDS %180 + %249 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToDS %188 + %250 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToDS %196 + %251 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToDS %204 + %252 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToDS %212 + %253 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToDS %220 + %254 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToDS %228 + %255 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToDS %236 + %256 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToDS %244 + %257 = OpLoad %_arr_v4float_uint_12 %in_var_VS_To_DS_Position + %258 = OpCompositeExtract %v4float %257 0 + %259 = OpCompositeConstruct %FBasePassVSToDS %245 %134 %258 + %260 = OpCompositeExtract %v4float %257 1 + %261 = OpCompositeConstruct %FBasePassVSToDS %246 %134 %260 + %262 = OpCompositeExtract %v4float %257 2 + %263 = OpCompositeConstruct %FBasePassVSToDS %247 %134 %262 + %264 = OpCompositeExtract %v4float %257 3 + %265 = OpCompositeConstruct %FBasePassVSToDS %248 %134 %264 + %266 = OpCompositeExtract %v4float %257 4 + %267 = OpCompositeConstruct %FBasePassVSToDS %249 %134 %266 + %268 = OpCompositeExtract %v4float %257 5 + %269 = OpCompositeConstruct %FBasePassVSToDS %250 %134 %268 + %270 = OpCompositeExtract %v4float %257 6 + %271 = OpCompositeConstruct %FBasePassVSToDS %251 %134 %270 + %272 = OpCompositeExtract %v4float %257 7 + %273 = OpCompositeConstruct %FBasePassVSToDS %252 %134 %272 + %274 = OpCompositeExtract %v4float %257 8 + %275 = OpCompositeConstruct %FBasePassVSToDS %253 %134 %274 + %276 = OpCompositeExtract %v4float %257 9 + %277 = OpCompositeConstruct %FBasePassVSToDS %254 %134 %276 + %278 = OpCompositeExtract %v4float %257 10 + %279 = OpCompositeConstruct %FBasePassVSToDS %255 %134 %278 + %280 = OpCompositeExtract %v4float %257 11 + %281 = OpCompositeConstruct %FBasePassVSToDS %256 %134 %280 + %282 = OpCompositeConstruct %_arr_FBasePassVSToDS_uint_12 %259 %261 %263 %265 %267 %269 %271 %273 %275 %277 %279 %281 + OpStore %param_var_I %282 + %283 = OpLoad %uint %gl_InvocationID + %284 = OpAccessChain %_ptr_Function_FVertexFactoryInterpolantsVSToDS %param_var_I %283 %int_0 + %285 = OpLoad %FVertexFactoryInterpolantsVSToDS %284 + %286 = OpCompositeExtract %FVertexFactoryInterpolantsVSToPS %285 0 + %287 = OpCompositeExtract %v4float %286 0 + %288 = OpCompositeExtract %v4float %286 1 + %289 = OpVectorShuffle %v3float %287 %287 0 1 2 + %290 = OpVectorShuffle %v3float %288 %288 0 1 2 + %291 = OpExtInst %v3float %1 Cross %290 %289 + %292 = OpCompositeExtract %float %288 3 + %293 = OpCompositeConstruct %v3float %292 %292 %292 + %294 = OpFMul %v3float %291 %293 + %295 = OpCompositeConstruct %mat3v3float %289 %294 %290 + %296 = OpCompositeExtract %float %288 0 + %297 = OpCompositeExtract %float %288 1 + %298 = OpCompositeExtract %float %288 2 + %299 = OpCompositeConstruct %v4float %296 %297 %298 %float_0 + %300 = OpAccessChain %_ptr_Function_FVertexFactoryInterpolantsVSToPS %param_var_I %283 %int_0 %int_0 + %301 = OpLoad %FVertexFactoryInterpolantsVSToPS %300 + %302 = OpCompositeExtract %uint %301 5 + %303 = OpIMul %uint %302 %uint_26 + %304 = OpIAdd %uint %303 %uint_22 + %305 = OpAccessChain %_ptr_Uniform_v4float %View_PrimitiveSceneData %int_0 %304 + %306 = OpLoad %v4float %305 + %307 = OpVectorShuffle %v3float %306 %306 0 1 2 + %308 = OpVectorTimesMatrix %v3float %307 %295 + %309 = OpULessThan %bool %283 %uint_2 + %310 = OpIAdd %uint %283 %uint_1 + %311 = OpSelect %uint %309 %310 %uint_0 + %312 = OpIMul %uint %uint_2 %283 + %313 = OpIAdd %uint %uint_3 %312 + %314 = OpIAdd %uint %312 %uint_4 + %315 = OpAccessChain %_ptr_Function_FBasePassVSToDS %param_var_I %283 + %316 = OpLoad %FBasePassVSToDS %315 + %317 = OpAccessChain %_ptr_Function_v4float %param_var_I %283 %int_2 + %318 = OpLoad %v4float %317 + %319 = OpAccessChain %_ptr_Function_FVertexFactoryInterpolantsVSToDS %param_var_I %311 %int_0 + %320 = OpLoad %FVertexFactoryInterpolantsVSToDS %319 + %321 = OpCompositeExtract %FVertexFactoryInterpolantsVSToPS %320 0 + %322 = OpCompositeExtract %v4float %321 1 + %323 = OpCompositeExtract %float %322 0 + %324 = OpCompositeExtract %float %322 1 + %325 = OpCompositeExtract %float %322 2 + %326 = OpCompositeConstruct %v4float %323 %324 %325 %float_0 + %327 = OpAccessChain %_ptr_Function_FVertexFactoryInterpolantsVSToDS %param_var_I %313 %int_0 + %328 = OpLoad %FVertexFactoryInterpolantsVSToDS %327 + %329 = OpCompositeExtract %FVertexFactoryInterpolantsVSToPS %328 0 + %330 = OpCompositeExtract %v4float %329 1 + %331 = OpCompositeExtract %float %330 0 + %332 = OpCompositeExtract %float %330 1 + %333 = OpCompositeExtract %float %330 2 + %334 = OpCompositeConstruct %v4float %331 %332 %333 %float_0 + %335 = OpAccessChain %_ptr_Function_FVertexFactoryInterpolantsVSToDS %param_var_I %314 %int_0 + %336 = OpLoad %FVertexFactoryInterpolantsVSToDS %335 + %337 = OpCompositeExtract %FVertexFactoryInterpolantsVSToPS %336 0 + %338 = OpCompositeExtract %v4float %337 1 + %339 = OpCompositeExtract %float %338 0 + %340 = OpCompositeExtract %float %338 1 + %341 = OpCompositeExtract %float %338 2 + %342 = OpCompositeConstruct %v4float %339 %340 %341 %float_0 + %343 = OpLoad %v4float %317 + %344 = OpAccessChain %_ptr_Function_v4float %param_var_I %311 %int_2 + %345 = OpLoad %v4float %344 + %346 = OpFMul %v4float %62 %343 + %347 = OpFAdd %v4float %346 %345 + %348 = OpFSub %v4float %345 %343 + %349 = OpDot %float %348 %299 + %350 = OpCompositeConstruct %v4float %349 %349 %349 %349 + %351 = OpFMul %v4float %350 %299 + %352 = OpFSub %v4float %347 %351 + %353 = OpFMul %v4float %352 %136 + %354 = OpAccessChain %_ptr_Function_v4float %param_var_I %313 %int_2 + %355 = OpLoad %v4float %354 + %356 = OpAccessChain %_ptr_Function_v4float %param_var_I %314 %int_2 + %357 = OpLoad %v4float %356 + %358 = OpFMul %v4float %62 %355 + %359 = OpFAdd %v4float %358 %357 + %360 = OpFSub %v4float %357 %355 + %361 = OpDot %float %360 %334 + %362 = OpCompositeConstruct %v4float %361 %361 %361 %361 + %363 = OpFMul %v4float %362 %334 + %364 = OpFSub %v4float %359 %363 + %365 = OpFMul %v4float %364 %136 + %366 = OpFAdd %v4float %353 %365 + %367 = OpFMul %v4float %366 %137 + %368 = OpLoad %v4float %344 + %369 = OpLoad %v4float %317 + %370 = OpFMul %v4float %62 %368 + %371 = OpFAdd %v4float %370 %369 + %372 = OpFSub %v4float %369 %368 + %373 = OpDot %float %372 %326 + %374 = OpCompositeConstruct %v4float %373 %373 %373 %373 + %375 = OpFMul %v4float %374 %326 + %376 = OpFSub %v4float %371 %375 + %377 = OpFMul %v4float %376 %136 + %378 = OpLoad %v4float %356 + %379 = OpLoad %v4float %354 + %380 = OpFMul %v4float %62 %378 + %381 = OpFAdd %v4float %380 %379 + %382 = OpFSub %v4float %379 %378 + %383 = OpDot %float %382 %342 + %384 = OpCompositeConstruct %v4float %383 %383 %383 %383 + %385 = OpFMul %v4float %384 %342 + %386 = OpFSub %v4float %381 %385 + %387 = OpFMul %v4float %386 %136 + %388 = OpFAdd %v4float %377 %387 + %389 = OpFMul %v4float %388 %137 + %390 = OpCompositeConstruct %_arr_v4float_uint_3 %318 %367 %389 + %391 = OpCompositeConstruct %FPNTessellationHSToDS %316 %390 %308 %float_1 %float_1 + %392 = OpCompositeExtract %FVertexFactoryInterpolantsVSToDS %316 0 + %393 = OpCompositeExtract %FVertexFactoryInterpolantsVSToPS %392 0 + %394 = OpCompositeExtract %v4float %393 0 + %395 = OpAccessChain %_ptr_Output_v4float %out_var_TEXCOORD10_centroid %283 + OpStore %395 %394 + %396 = OpCompositeExtract %v4float %393 1 + %397 = OpAccessChain %_ptr_Output_v4float %out_var_TEXCOORD11_centroid %283 + OpStore %397 %396 + %398 = OpCompositeExtract %v4float %393 2 + %399 = OpAccessChain %_ptr_Output_v4float %out_var_COLOR0 %283 + OpStore %399 %398 + %400 = OpCompositeExtract %_arr_v4float_uint_1 %393 3 + %401 = OpAccessChain %_ptr_Output__arr_v4float_uint_1 %out_var_TEXCOORD0 %283 + OpStore %401 %400 + %402 = OpCompositeExtract %v4float %393 4 + %403 = OpAccessChain %_ptr_Output_v4float %out_var_TEXCOORD4 %283 + OpStore %403 %402 + %404 = OpCompositeExtract %uint %393 5 + %405 = OpAccessChain %_ptr_Output_uint %out_var_PRIMITIVE_ID %283 + OpStore %405 %404 + %406 = OpCompositeExtract %uint %393 6 + %407 = OpAccessChain %_ptr_Output_uint %out_var_LIGHTMAP_ID %283 + OpStore %407 %406 + %408 = OpCompositeExtract %v4float %316 2 + %409 = OpAccessChain %_ptr_Output_v4float %out_var_VS_To_DS_Position %283 + OpStore %409 %408 + %410 = OpAccessChain %_ptr_Output__arr_v4float_uint_3 %out_var_PN_POSITION %283 + OpStore %410 %390 + %411 = OpAccessChain %_ptr_Output_v3float %out_var_PN_DisplacementScales %283 + OpStore %411 %308 + %412 = OpAccessChain %_ptr_Output_float %out_var_PN_TessellationMultiplier %283 + OpStore %412 %float_1 + %413 = OpAccessChain %_ptr_Output_float %out_var_PN_WorldDisplacementMultiplier %283 + OpStore %413 %float_1 + %414 = OpAccessChain %_ptr_Workgroup_FPNTessellationHSToDS %temp_var_hullMainRetVal %283 + OpStore %414 %391 + OpControlBarrier %uint_2 %uint_4 %uint_0 + %415 = OpIEqual %bool %283 %uint_0 + OpSelectionMerge %if_merge None + OpBranchConditional %415 %416 %if_merge + %416 = OpLabel + %417 = OpAccessChain %_ptr_Uniform_mat4v4float %View %int_0 + %418 = OpLoad %mat4v4float %417 + %419 = OpAccessChain %_ptr_Uniform_mat4v4float %View %int_6 + %420 = OpLoad %mat4v4float %419 + %421 = OpAccessChain %_ptr_Uniform_v3float %View %int_27 + %422 = OpLoad %v3float %421 + %423 = OpAccessChain %_ptr_Uniform_float %View %int_77 + %424 = OpLoad %float %423 + %425 = OpAccessChain %_ptr_Workgroup_v4float %temp_var_hullMainRetVal %uint_0 %int_1 %int_0 + %426 = OpLoad %v4float %425 + %427 = OpAccessChain %_ptr_Workgroup_v4float %temp_var_hullMainRetVal %uint_0 %int_1 %int_1 + %428 = OpLoad %v4float %427 + %429 = OpAccessChain %_ptr_Workgroup_v4float %temp_var_hullMainRetVal %uint_0 %int_1 %int_2 + %430 = OpLoad %v4float %429 + %431 = OpAccessChain %_ptr_Workgroup_v4float %temp_var_hullMainRetVal %uint_1 %int_1 %int_0 + %432 = OpLoad %v4float %431 + %433 = OpAccessChain %_ptr_Workgroup_v4float %temp_var_hullMainRetVal %uint_1 %int_1 %int_1 + %434 = OpLoad %v4float %433 + %435 = OpAccessChain %_ptr_Workgroup_v4float %temp_var_hullMainRetVal %uint_1 %int_1 %int_2 + %436 = OpLoad %v4float %435 + %437 = OpAccessChain %_ptr_Workgroup_v4float %temp_var_hullMainRetVal %uint_2 %int_1 %int_0 + %438 = OpLoad %v4float %437 + %439 = OpAccessChain %_ptr_Workgroup_v4float %temp_var_hullMainRetVal %uint_2 %int_1 %int_1 + %440 = OpLoad %v4float %439 + %441 = OpAccessChain %_ptr_Workgroup_v4float %temp_var_hullMainRetVal %uint_2 %int_1 %int_2 + %442 = OpLoad %v4float %441 + %443 = OpFAdd %v4float %428 %430 + %444 = OpFAdd %v4float %443 %434 + %445 = OpFAdd %v4float %444 %436 + %446 = OpFAdd %v4float %445 %440 + %447 = OpFAdd %v4float %446 %442 + %448 = OpFMul %v4float %447 %139 + %449 = OpFAdd %v4float %438 %432 + %450 = OpFAdd %v4float %449 %426 + %451 = OpFMul %v4float %450 %136 + %452 = OpFSub %v4float %448 %451 + %453 = OpFMul %v4float %452 %137 + %454 = OpFAdd %v4float %448 %453 + %455 = OpAccessChain %_ptr_Workgroup_float %temp_var_hullMainRetVal %uint_1 %int_3 + %456 = OpLoad %float %455 + %457 = OpAccessChain %_ptr_Workgroup_float %temp_var_hullMainRetVal %uint_2 %int_3 + %458 = OpLoad %float %457 + %459 = OpFAdd %float %456 %458 + %460 = OpFMul %float %float_0_5 %459 + %461 = OpCompositeInsert %v4float %460 %140 0 + %462 = OpLoad %float %457 + %463 = OpAccessChain %_ptr_Workgroup_float %temp_var_hullMainRetVal %uint_0 %int_3 + %464 = OpLoad %float %463 + %465 = OpFAdd %float %462 %464 + %466 = OpFMul %float %float_0_5 %465 + %467 = OpCompositeInsert %v4float %466 %461 1 + %468 = OpLoad %float %463 + %469 = OpLoad %float %455 + %470 = OpFAdd %float %468 %469 + %471 = OpFMul %float %float_0_5 %470 + %472 = OpCompositeInsert %v4float %471 %467 2 + %473 = OpLoad %float %463 + %474 = OpLoad %float %455 + %475 = OpFAdd %float %473 %474 + %476 = OpLoad %float %457 + %477 = OpFAdd %float %475 %476 + %478 = OpFMul %float %float_0_333000004 %477 + %479 = OpCompositeInsert %v4float %478 %472 3 + %480 = OpVectorShuffle %v3float %426 %426 0 1 2 + %481 = OpVectorShuffle %v3float %432 %432 0 1 2 + %482 = OpVectorShuffle %v3float %438 %438 0 1 2 + OpBranch %483 + %483 = OpLabel + OpLoopMerge %484 %485 None + OpBranch %486 + %486 = OpLabel + %487 = OpMatrixTimesVector %v4float %420 %76 + %488 = OpCompositeExtract %float %426 0 + %489 = OpCompositeExtract %float %426 1 + %490 = OpCompositeExtract %float %426 2 + %491 = OpCompositeConstruct %v4float %488 %489 %490 %float_1 + %492 = OpMatrixTimesVector %v4float %418 %491 + %493 = OpVectorShuffle %v3float %492 %492 0 1 2 + %494 = OpVectorShuffle %v3float %487 %487 0 1 2 + %495 = OpFSub %v3float %493 %494 + %496 = OpCompositeExtract %float %492 3 + %497 = OpCompositeExtract %float %487 3 + %498 = OpFAdd %float %496 %497 + %499 = OpCompositeConstruct %v3float %498 %498 %498 + %500 = OpFOrdLessThan %v3bool %495 %499 + %501 = OpSelect %v3int %500 %81 %73 + %502 = OpFAdd %v3float %493 %494 + %503 = OpFNegate %float %496 + %504 = OpFSub %float %503 %497 + %505 = OpCompositeConstruct %v3float %504 %504 %504 + %506 = OpFOrdGreaterThan %v3bool %502 %505 + %507 = OpSelect %v3int %506 %81 %73 + %508 = OpIMul %v3int %82 %507 + %509 = OpIAdd %v3int %501 %508 + %510 = OpCompositeExtract %float %432 0 + %511 = OpCompositeExtract %float %432 1 + %512 = OpCompositeExtract %float %432 2 + %513 = OpCompositeConstruct %v4float %510 %511 %512 %float_1 + %514 = OpMatrixTimesVector %v4float %418 %513 + %515 = OpVectorShuffle %v3float %514 %514 0 1 2 + %516 = OpFSub %v3float %515 %494 + %517 = OpCompositeExtract %float %514 3 + %518 = OpFAdd %float %517 %497 + %519 = OpCompositeConstruct %v3float %518 %518 %518 + %520 = OpFOrdLessThan %v3bool %516 %519 + %521 = OpSelect %v3int %520 %81 %73 + %522 = OpFAdd %v3float %515 %494 + %523 = OpFNegate %float %517 + %524 = OpFSub %float %523 %497 + %525 = OpCompositeConstruct %v3float %524 %524 %524 + %526 = OpFOrdGreaterThan %v3bool %522 %525 + %527 = OpSelect %v3int %526 %81 %73 + %528 = OpIMul %v3int %82 %527 + %529 = OpIAdd %v3int %521 %528 + %530 = OpBitwiseOr %v3int %509 %529 + %531 = OpCompositeExtract %float %438 0 + %532 = OpCompositeExtract %float %438 1 + %533 = OpCompositeExtract %float %438 2 + %534 = OpCompositeConstruct %v4float %531 %532 %533 %float_1 + %535 = OpMatrixTimesVector %v4float %418 %534 + %536 = OpVectorShuffle %v3float %535 %535 0 1 2 + %537 = OpFSub %v3float %536 %494 + %538 = OpCompositeExtract %float %535 3 + %539 = OpFAdd %float %538 %497 + %540 = OpCompositeConstruct %v3float %539 %539 %539 + %541 = OpFOrdLessThan %v3bool %537 %540 + %542 = OpSelect %v3int %541 %81 %73 + %543 = OpFAdd %v3float %536 %494 + %544 = OpFNegate %float %538 + %545 = OpFSub %float %544 %497 + %546 = OpCompositeConstruct %v3float %545 %545 %545 + %547 = OpFOrdGreaterThan %v3bool %543 %546 + %548 = OpSelect %v3int %547 %81 %73 + %549 = OpIMul %v3int %82 %548 + %550 = OpIAdd %v3int %542 %549 + %551 = OpBitwiseOr %v3int %530 %550 + %552 = OpINotEqual %v3bool %551 %74 + %553 = OpAny %bool %552 + OpSelectionMerge %554 None + OpBranchConditional %553 %555 %554 + %555 = OpLabel + OpBranch %484 + %554 = OpLabel + %556 = OpFSub %v3float %480 %481 + %557 = OpFSub %v3float %481 %482 + %558 = OpFSub %v3float %482 %480 + %559 = OpFAdd %v3float %480 %481 + %560 = OpFMul %v3float %77 %559 + %561 = OpFSub %v3float %560 %422 + %562 = OpFAdd %v3float %481 %482 + %563 = OpFMul %v3float %77 %562 + %564 = OpFSub %v3float %563 %422 + %565 = OpFAdd %v3float %482 %480 + %566 = OpFMul %v3float %77 %565 + %567 = OpFSub %v3float %566 %422 + %568 = OpDot %float %557 %557 + %569 = OpDot %float %564 %564 + %570 = OpFDiv %float %568 %569 + %571 = OpExtInst %float %1 Sqrt %570 + %572 = OpDot %float %558 %558 + %573 = OpDot %float %567 %567 + %574 = OpFDiv %float %572 %573 + %575 = OpExtInst %float %1 Sqrt %574 + %576 = OpDot %float %556 %556 + %577 = OpDot %float %561 %561 + %578 = OpFDiv %float %576 %577 + %579 = OpExtInst %float %1 Sqrt %578 + %580 = OpCompositeConstruct %v4float %571 %575 %579 %float_1 + %581 = OpFAdd %float %571 %575 + %582 = OpFAdd %float %581 %579 + %583 = OpFMul %float %float_0_333000004 %582 + %584 = OpCompositeInsert %v4float %583 %580 3 + %585 = OpCompositeConstruct %v4float %424 %424 %424 %424 + %586 = OpFMul %v4float %585 %584 + OpBranch %484 + %485 = OpLabel + OpBranch %483 + %484 = OpLabel + %587 = OpPhi %v4float %76 %555 %586 %554 + %588 = OpFMul %v4float %479 %587 + %589 = OpExtInst %v4float %1 FClamp %588 %67 %69 + %590 = OpCompositeExtract %float %589 0 + %591 = OpCompositeExtract %float %589 1 + %592 = OpCompositeExtract %float %589 2 + %593 = OpCompositeExtract %float %589 3 + %594 = OpAccessChain %_ptr_Output_float %gl_TessLevelOuter %uint_0 + OpStore %594 %590 + %595 = OpAccessChain %_ptr_Output_float %gl_TessLevelOuter %uint_1 + OpStore %595 %591 + %596 = OpAccessChain %_ptr_Output_float %gl_TessLevelOuter %uint_2 + OpStore %596 %592 + %597 = OpAccessChain %_ptr_Output_float %gl_TessLevelInner %uint_0 + OpStore %597 %593 + OpStore %out_var_PN_POSITION9 %454 + OpBranch %if_merge + %if_merge = OpLabel + OpReturn + OpFunctionEnd diff --git a/third_party/spirv-cross/shaders-ue4/asm/tesc/hs-input-array-access.asm.tesc b/third_party/spirv-cross/shaders-ue4/asm/tesc/hs-input-array-access.asm.tesc new file mode 100644 index 0000000000..a146896b90 --- /dev/null +++ b/third_party/spirv-cross/shaders-ue4/asm/tesc/hs-input-array-access.asm.tesc @@ -0,0 +1,1264 @@ +; SPIR-V +; Version: 1.0 +; Generator: Google spiregg; 0 +; Bound: 607 +; Schema: 0 + OpCapability Tessellation + OpCapability SampledBuffer + OpExtension "SPV_GOOGLE_hlsl_functionality1" + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint TessellationControl %MainHull "main" %in_var_TEXCOORD10_centroid %in_var_TEXCOORD11_centroid %in_var_VS_To_DS_Position %in_var_VS_To_DS_VertexID %gl_InvocationID %out_var_TEXCOORD10_centroid %out_var_TEXCOORD11_centroid %out_var_VS_To_DS_Position %out_var_VS_To_DS_VertexID %out_var_PN_POSITION %out_var_PN_DisplacementScales %out_var_PN_TessellationMultiplier %out_var_PN_WorldDisplacementMultiplier %out_var_PN_DominantVertex %out_var_PN_DominantVertex1 %out_var_PN_DominantVertex2 %out_var_PN_DominantEdge %out_var_PN_DominantEdge1 %out_var_PN_DominantEdge2 %out_var_PN_DominantEdge3 %out_var_PN_DominantEdge4 %out_var_PN_DominantEdge5 %gl_TessLevelOuter %gl_TessLevelInner %out_var_PN_POSITION9 + OpExecutionMode %MainHull Triangles + OpExecutionMode %MainHull SpacingFractionalOdd + OpExecutionMode %MainHull VertexOrderCw + OpExecutionMode %MainHull OutputVertices 3 + OpSource HLSL 600 + OpName %FPNTessellationHSToDS "FPNTessellationHSToDS" + OpMemberName %FPNTessellationHSToDS 0 "PassSpecificData" + OpMemberName %FPNTessellationHSToDS 1 "WorldPosition" + OpMemberName %FPNTessellationHSToDS 2 "DisplacementScale" + OpMemberName %FPNTessellationHSToDS 3 "TessellationMultiplier" + OpMemberName %FPNTessellationHSToDS 4 "WorldDisplacementMultiplier" + OpMemberName %FPNTessellationHSToDS 5 "DominantVertex" + OpMemberName %FPNTessellationHSToDS 6 "DominantEdge" + OpName %FHitProxyVSToDS "FHitProxyVSToDS" + OpMemberName %FHitProxyVSToDS 0 "FactoryInterpolants" + OpMemberName %FHitProxyVSToDS 1 "Position" + OpMemberName %FHitProxyVSToDS 2 "VertexID" + OpName %FVertexFactoryInterpolantsVSToDS "FVertexFactoryInterpolantsVSToDS" + OpMemberName %FVertexFactoryInterpolantsVSToDS 0 "InterpolantsVSToPS" + OpName %FVertexFactoryInterpolantsVSToPS "FVertexFactoryInterpolantsVSToPS" + OpMemberName %FVertexFactoryInterpolantsVSToPS 0 "TangentToWorld0" + OpMemberName %FVertexFactoryInterpolantsVSToPS 1 "TangentToWorld2" + OpName %FHullShaderConstantDominantVertexData "FHullShaderConstantDominantVertexData" + OpMemberName %FHullShaderConstantDominantVertexData 0 "UV" + OpMemberName %FHullShaderConstantDominantVertexData 1 "Normal" + OpMemberName %FHullShaderConstantDominantVertexData 2 "Tangent" + OpName %FHullShaderConstantDominantEdgeData "FHullShaderConstantDominantEdgeData" + OpMemberName %FHullShaderConstantDominantEdgeData 0 "UV0" + OpMemberName %FHullShaderConstantDominantEdgeData 1 "UV1" + OpMemberName %FHullShaderConstantDominantEdgeData 2 "Normal0" + OpMemberName %FHullShaderConstantDominantEdgeData 3 "Normal1" + OpMemberName %FHullShaderConstantDominantEdgeData 4 "Tangent0" + OpMemberName %FHullShaderConstantDominantEdgeData 5 "Tangent1" + OpName %type_View "type.View" + OpMemberName %type_View 0 "View_TranslatedWorldToClip" + OpMemberName %type_View 1 "View_WorldToClip" + OpMemberName %type_View 2 "View_ClipToWorld" + OpMemberName %type_View 3 "View_TranslatedWorldToView" + OpMemberName %type_View 4 "View_ViewToTranslatedWorld" + OpMemberName %type_View 5 "View_TranslatedWorldToCameraView" + OpMemberName %type_View 6 "View_CameraViewToTranslatedWorld" + OpMemberName %type_View 7 "View_ViewToClip" + OpMemberName %type_View 8 "View_ViewToClipNoAA" + OpMemberName %type_View 9 "View_ClipToView" + OpMemberName %type_View 10 "View_ClipToTranslatedWorld" + OpMemberName %type_View 11 "View_SVPositionToTranslatedWorld" + OpMemberName %type_View 12 "View_ScreenToWorld" + OpMemberName %type_View 13 "View_ScreenToTranslatedWorld" + OpMemberName %type_View 14 "View_ViewForward" + OpMemberName %type_View 15 "PrePadding_View_908" + OpMemberName %type_View 16 "View_ViewUp" + OpMemberName %type_View 17 "PrePadding_View_924" + OpMemberName %type_View 18 "View_ViewRight" + OpMemberName %type_View 19 "PrePadding_View_940" + OpMemberName %type_View 20 "View_HMDViewNoRollUp" + OpMemberName %type_View 21 "PrePadding_View_956" + OpMemberName %type_View 22 "View_HMDViewNoRollRight" + OpMemberName %type_View 23 "PrePadding_View_972" + OpMemberName %type_View 24 "View_InvDeviceZToWorldZTransform" + OpMemberName %type_View 25 "View_ScreenPositionScaleBias" + OpMemberName %type_View 26 "View_WorldCameraOrigin" + OpMemberName %type_View 27 "PrePadding_View_1020" + OpMemberName %type_View 28 "View_TranslatedWorldCameraOrigin" + OpMemberName %type_View 29 "PrePadding_View_1036" + OpMemberName %type_View 30 "View_WorldViewOrigin" + OpMemberName %type_View 31 "PrePadding_View_1052" + OpMemberName %type_View 32 "View_PreViewTranslation" + OpMemberName %type_View 33 "PrePadding_View_1068" + OpMemberName %type_View 34 "View_PrevProjection" + OpMemberName %type_View 35 "View_PrevViewProj" + OpMemberName %type_View 36 "View_PrevViewRotationProj" + OpMemberName %type_View 37 "View_PrevViewToClip" + OpMemberName %type_View 38 "View_PrevClipToView" + OpMemberName %type_View 39 "View_PrevTranslatedWorldToClip" + OpMemberName %type_View 40 "View_PrevTranslatedWorldToView" + OpMemberName %type_View 41 "View_PrevViewToTranslatedWorld" + OpMemberName %type_View 42 "View_PrevTranslatedWorldToCameraView" + OpMemberName %type_View 43 "View_PrevCameraViewToTranslatedWorld" + OpMemberName %type_View 44 "View_PrevWorldCameraOrigin" + OpMemberName %type_View 45 "PrePadding_View_1724" + OpMemberName %type_View 46 "View_PrevWorldViewOrigin" + OpMemberName %type_View 47 "PrePadding_View_1740" + OpMemberName %type_View 48 "View_PrevPreViewTranslation" + OpMemberName %type_View 49 "PrePadding_View_1756" + OpMemberName %type_View 50 "View_PrevInvViewProj" + OpMemberName %type_View 51 "View_PrevScreenToTranslatedWorld" + OpMemberName %type_View 52 "View_ClipToPrevClip" + OpMemberName %type_View 53 "View_TemporalAAJitter" + OpMemberName %type_View 54 "View_GlobalClippingPlane" + OpMemberName %type_View 55 "View_FieldOfViewWideAngles" + OpMemberName %type_View 56 "View_PrevFieldOfViewWideAngles" + OpMemberName %type_View 57 "View_ViewRectMin" + OpMemberName %type_View 58 "View_ViewSizeAndInvSize" + OpMemberName %type_View 59 "View_BufferSizeAndInvSize" + OpMemberName %type_View 60 "View_BufferBilinearUVMinMax" + OpMemberName %type_View 61 "View_NumSceneColorMSAASamples" + OpMemberName %type_View 62 "View_PreExposure" + OpMemberName %type_View 63 "View_OneOverPreExposure" + OpMemberName %type_View 64 "PrePadding_View_2076" + OpMemberName %type_View 65 "View_DiffuseOverrideParameter" + OpMemberName %type_View 66 "View_SpecularOverrideParameter" + OpMemberName %type_View 67 "View_NormalOverrideParameter" + OpMemberName %type_View 68 "View_RoughnessOverrideParameter" + OpMemberName %type_View 69 "View_PrevFrameGameTime" + OpMemberName %type_View 70 "View_PrevFrameRealTime" + OpMemberName %type_View 71 "View_OutOfBoundsMask" + OpMemberName %type_View 72 "PrePadding_View_2148" + OpMemberName %type_View 73 "PrePadding_View_2152" + OpMemberName %type_View 74 "PrePadding_View_2156" + OpMemberName %type_View 75 "View_WorldCameraMovementSinceLastFrame" + OpMemberName %type_View 76 "View_CullingSign" + OpMemberName %type_View 77 "View_NearPlane" + OpMemberName %type_View 78 "View_AdaptiveTessellationFactor" + OpMemberName %type_View 79 "View_GameTime" + OpMemberName %type_View 80 "View_RealTime" + OpMemberName %type_View 81 "View_DeltaTime" + OpMemberName %type_View 82 "View_MaterialTextureMipBias" + OpMemberName %type_View 83 "View_MaterialTextureDerivativeMultiply" + OpMemberName %type_View 84 "View_Random" + OpMemberName %type_View 85 "View_FrameNumber" + OpMemberName %type_View 86 "View_StateFrameIndexMod8" + OpMemberName %type_View 87 "View_StateFrameIndex" + OpMemberName %type_View 88 "View_CameraCut" + OpMemberName %type_View 89 "View_UnlitViewmodeMask" + OpMemberName %type_View 90 "PrePadding_View_2228" + OpMemberName %type_View 91 "PrePadding_View_2232" + OpMemberName %type_View 92 "PrePadding_View_2236" + OpMemberName %type_View 93 "View_DirectionalLightColor" + OpMemberName %type_View 94 "View_DirectionalLightDirection" + OpMemberName %type_View 95 "PrePadding_View_2268" + OpMemberName %type_View 96 "View_TranslucencyLightingVolumeMin" + OpMemberName %type_View 97 "View_TranslucencyLightingVolumeInvSize" + OpMemberName %type_View 98 "View_TemporalAAParams" + OpMemberName %type_View 99 "View_CircleDOFParams" + OpMemberName %type_View 100 "View_DepthOfFieldSensorWidth" + OpMemberName %type_View 101 "View_DepthOfFieldFocalDistance" + OpMemberName %type_View 102 "View_DepthOfFieldScale" + OpMemberName %type_View 103 "View_DepthOfFieldFocalLength" + OpMemberName %type_View 104 "View_DepthOfFieldFocalRegion" + OpMemberName %type_View 105 "View_DepthOfFieldNearTransitionRegion" + OpMemberName %type_View 106 "View_DepthOfFieldFarTransitionRegion" + OpMemberName %type_View 107 "View_MotionBlurNormalizedToPixel" + OpMemberName %type_View 108 "View_bSubsurfacePostprocessEnabled" + OpMemberName %type_View 109 "View_GeneralPurposeTweak" + OpMemberName %type_View 110 "View_DemosaicVposOffset" + OpMemberName %type_View 111 "PrePadding_View_2412" + OpMemberName %type_View 112 "View_IndirectLightingColorScale" + OpMemberName %type_View 113 "View_HDR32bppEncodingMode" + OpMemberName %type_View 114 "View_AtmosphericFogSunDirection" + OpMemberName %type_View 115 "View_AtmosphericFogSunPower" + OpMemberName %type_View 116 "View_AtmosphericFogPower" + OpMemberName %type_View 117 "View_AtmosphericFogDensityScale" + OpMemberName %type_View 118 "View_AtmosphericFogDensityOffset" + OpMemberName %type_View 119 "View_AtmosphericFogGroundOffset" + OpMemberName %type_View 120 "View_AtmosphericFogDistanceScale" + OpMemberName %type_View 121 "View_AtmosphericFogAltitudeScale" + OpMemberName %type_View 122 "View_AtmosphericFogHeightScaleRayleigh" + OpMemberName %type_View 123 "View_AtmosphericFogStartDistance" + OpMemberName %type_View 124 "View_AtmosphericFogDistanceOffset" + OpMemberName %type_View 125 "View_AtmosphericFogSunDiscScale" + OpMemberName %type_View 126 "View_AtmosphericFogSunDiscHalfApexAngleRadian" + OpMemberName %type_View 127 "PrePadding_View_2492" + OpMemberName %type_View 128 "View_AtmosphericFogSunDiscLuminance" + OpMemberName %type_View 129 "View_AtmosphericFogRenderMask" + OpMemberName %type_View 130 "View_AtmosphericFogInscatterAltitudeSampleNum" + OpMemberName %type_View 131 "PrePadding_View_2520" + OpMemberName %type_View 132 "PrePadding_View_2524" + OpMemberName %type_View 133 "View_AtmosphericFogSunColor" + OpMemberName %type_View 134 "View_NormalCurvatureToRoughnessScaleBias" + OpMemberName %type_View 135 "View_RenderingReflectionCaptureMask" + OpMemberName %type_View 136 "View_AmbientCubemapTint" + OpMemberName %type_View 137 "View_AmbientCubemapIntensity" + OpMemberName %type_View 138 "View_SkyLightParameters" + OpMemberName %type_View 139 "PrePadding_View_2584" + OpMemberName %type_View 140 "PrePadding_View_2588" + OpMemberName %type_View 141 "View_SkyLightColor" + OpMemberName %type_View 142 "View_SkyIrradianceEnvironmentMap" + OpMemberName %type_View 143 "View_MobilePreviewMode" + OpMemberName %type_View 144 "View_HMDEyePaddingOffset" + OpMemberName %type_View 145 "View_ReflectionCubemapMaxMip" + OpMemberName %type_View 146 "View_ShowDecalsMask" + OpMemberName %type_View 147 "View_DistanceFieldAOSpecularOcclusionMode" + OpMemberName %type_View 148 "View_IndirectCapsuleSelfShadowingIntensity" + OpMemberName %type_View 149 "PrePadding_View_2744" + OpMemberName %type_View 150 "PrePadding_View_2748" + OpMemberName %type_View 151 "View_ReflectionEnvironmentRoughnessMixingScaleBiasAndLargestWeight" + OpMemberName %type_View 152 "View_StereoPassIndex" + OpMemberName %type_View 153 "View_GlobalVolumeCenterAndExtent" + OpMemberName %type_View 154 "View_GlobalVolumeWorldToUVAddAndMul" + OpMemberName %type_View 155 "View_GlobalVolumeDimension" + OpMemberName %type_View 156 "View_GlobalVolumeTexelSize" + OpMemberName %type_View 157 "View_MaxGlobalDistance" + OpMemberName %type_View 158 "PrePadding_View_2908" + OpMemberName %type_View 159 "View_CursorPosition" + OpMemberName %type_View 160 "View_bCheckerboardSubsurfaceProfileRendering" + OpMemberName %type_View 161 "PrePadding_View_2924" + OpMemberName %type_View 162 "View_VolumetricFogInvGridSize" + OpMemberName %type_View 163 "PrePadding_View_2940" + OpMemberName %type_View 164 "View_VolumetricFogGridZParams" + OpMemberName %type_View 165 "PrePadding_View_2956" + OpMemberName %type_View 166 "View_VolumetricFogSVPosToVolumeUV" + OpMemberName %type_View 167 "View_VolumetricFogMaxDistance" + OpMemberName %type_View 168 "PrePadding_View_2972" + OpMemberName %type_View 169 "View_VolumetricLightmapWorldToUVScale" + OpMemberName %type_View 170 "PrePadding_View_2988" + OpMemberName %type_View 171 "View_VolumetricLightmapWorldToUVAdd" + OpMemberName %type_View 172 "PrePadding_View_3004" + OpMemberName %type_View 173 "View_VolumetricLightmapIndirectionTextureSize" + OpMemberName %type_View 174 "View_VolumetricLightmapBrickSize" + OpMemberName %type_View 175 "View_VolumetricLightmapBrickTexelSize" + OpMemberName %type_View 176 "View_StereoIPD" + OpMemberName %type_View 177 "View_IndirectLightingCacheShowFlag" + OpMemberName %type_View 178 "View_EyeToPixelSpreadAngle" + OpName %View "View" + OpName %type_Primitive "type.Primitive" + OpMemberName %type_Primitive 0 "Primitive_LocalToWorld" + OpMemberName %type_Primitive 1 "Primitive_InvNonUniformScaleAndDeterminantSign" + OpMemberName %type_Primitive 2 "Primitive_ObjectWorldPositionAndRadius" + OpMemberName %type_Primitive 3 "Primitive_WorldToLocal" + OpMemberName %type_Primitive 4 "Primitive_PreviousLocalToWorld" + OpMemberName %type_Primitive 5 "Primitive_PreviousWorldToLocal" + OpMemberName %type_Primitive 6 "Primitive_ActorWorldPosition" + OpMemberName %type_Primitive 7 "Primitive_UseSingleSampleShadowFromStationaryLights" + OpMemberName %type_Primitive 8 "Primitive_ObjectBounds" + OpMemberName %type_Primitive 9 "Primitive_LpvBiasMultiplier" + OpMemberName %type_Primitive 10 "Primitive_DecalReceiverMask" + OpMemberName %type_Primitive 11 "Primitive_PerObjectGBufferData" + OpMemberName %type_Primitive 12 "Primitive_UseVolumetricLightmapShadowFromStationaryLights" + OpMemberName %type_Primitive 13 "Primitive_DrawsVelocity" + OpMemberName %type_Primitive 14 "Primitive_ObjectOrientation" + OpMemberName %type_Primitive 15 "Primitive_NonUniformScale" + OpMemberName %type_Primitive 16 "Primitive_LocalObjectBoundsMin" + OpMemberName %type_Primitive 17 "Primitive_LightingChannelMask" + OpMemberName %type_Primitive 18 "Primitive_LocalObjectBoundsMax" + OpMemberName %type_Primitive 19 "Primitive_LightmapDataIndex" + OpMemberName %type_Primitive 20 "Primitive_PreSkinnedLocalBounds" + OpMemberName %type_Primitive 21 "Primitive_SingleCaptureIndex" + OpMemberName %type_Primitive 22 "Primitive_OutputVelocity" + OpMemberName %type_Primitive 23 "PrePadding_Primitive_420" + OpMemberName %type_Primitive 24 "PrePadding_Primitive_424" + OpMemberName %type_Primitive 25 "PrePadding_Primitive_428" + OpMemberName %type_Primitive 26 "Primitive_CustomPrimitiveData" + OpName %Primitive "Primitive" + OpName %in_var_TEXCOORD10_centroid "in.var.TEXCOORD10_centroid" + OpName %in_var_TEXCOORD11_centroid "in.var.TEXCOORD11_centroid" + OpName %in_var_VS_To_DS_Position "in.var.VS_To_DS_Position" + OpName %in_var_VS_To_DS_VertexID "in.var.VS_To_DS_VertexID" + OpName %out_var_TEXCOORD10_centroid "out.var.TEXCOORD10_centroid" + OpName %out_var_TEXCOORD11_centroid "out.var.TEXCOORD11_centroid" + OpName %out_var_VS_To_DS_Position "out.var.VS_To_DS_Position" + OpName %out_var_VS_To_DS_VertexID "out.var.VS_To_DS_VertexID" + OpName %out_var_PN_POSITION "out.var.PN_POSITION" + OpName %out_var_PN_DisplacementScales "out.var.PN_DisplacementScales" + OpName %out_var_PN_TessellationMultiplier "out.var.PN_TessellationMultiplier" + OpName %out_var_PN_WorldDisplacementMultiplier "out.var.PN_WorldDisplacementMultiplier" + OpName %out_var_PN_DominantVertex "out.var.PN_DominantVertex" + OpName %out_var_PN_DominantVertex1 "out.var.PN_DominantVertex1" + OpName %out_var_PN_DominantVertex2 "out.var.PN_DominantVertex2" + OpName %out_var_PN_DominantEdge "out.var.PN_DominantEdge" + OpName %out_var_PN_DominantEdge1 "out.var.PN_DominantEdge1" + OpName %out_var_PN_DominantEdge2 "out.var.PN_DominantEdge2" + OpName %out_var_PN_DominantEdge3 "out.var.PN_DominantEdge3" + OpName %out_var_PN_DominantEdge4 "out.var.PN_DominantEdge4" + OpName %out_var_PN_DominantEdge5 "out.var.PN_DominantEdge5" + OpName %out_var_PN_POSITION9 "out.var.PN_POSITION9" + OpName %MainHull "MainHull" + OpName %param_var_I "param.var.I" + OpName %temp_var_hullMainRetVal "temp.var.hullMainRetVal" + OpName %if_merge "if.merge" + OpDecorateString %in_var_TEXCOORD10_centroid UserSemantic "TEXCOORD10_centroid" + OpDecorateString %in_var_TEXCOORD11_centroid UserSemantic "TEXCOORD11_centroid" + OpDecorateString %in_var_VS_To_DS_Position UserSemantic "VS_To_DS_Position" + OpDecorateString %in_var_VS_To_DS_VertexID UserSemantic "VS_To_DS_VertexID" + OpDecorate %gl_InvocationID BuiltIn InvocationId + OpDecorateString %gl_InvocationID UserSemantic "SV_OutputControlPointID" + OpDecorateString %out_var_TEXCOORD10_centroid UserSemantic "TEXCOORD10_centroid" + OpDecorateString %out_var_TEXCOORD11_centroid UserSemantic "TEXCOORD11_centroid" + OpDecorateString %out_var_VS_To_DS_Position UserSemantic "VS_To_DS_Position" + OpDecorateString %out_var_VS_To_DS_VertexID UserSemantic "VS_To_DS_VertexID" + OpDecorateString %out_var_PN_POSITION UserSemantic "PN_POSITION" + OpDecorateString %out_var_PN_DisplacementScales UserSemantic "PN_DisplacementScales" + OpDecorateString %out_var_PN_TessellationMultiplier UserSemantic "PN_TessellationMultiplier" + OpDecorateString %out_var_PN_WorldDisplacementMultiplier UserSemantic "PN_WorldDisplacementMultiplier" + OpDecorateString %out_var_PN_DominantVertex UserSemantic "PN_DominantVertex" + OpDecorateString %out_var_PN_DominantVertex1 UserSemantic "PN_DominantVertex" + OpDecorateString %out_var_PN_DominantVertex2 UserSemantic "PN_DominantVertex" + OpDecorateString %out_var_PN_DominantEdge UserSemantic "PN_DominantEdge" + OpDecorateString %out_var_PN_DominantEdge1 UserSemantic "PN_DominantEdge" + OpDecorateString %out_var_PN_DominantEdge2 UserSemantic "PN_DominantEdge" + OpDecorateString %out_var_PN_DominantEdge3 UserSemantic "PN_DominantEdge" + OpDecorateString %out_var_PN_DominantEdge4 UserSemantic "PN_DominantEdge" + OpDecorateString %out_var_PN_DominantEdge5 UserSemantic "PN_DominantEdge" + OpDecorate %gl_TessLevelOuter BuiltIn TessLevelOuter + OpDecorateString %gl_TessLevelOuter UserSemantic "SV_TessFactor" + OpDecorate %gl_TessLevelOuter Patch + OpDecorate %gl_TessLevelInner BuiltIn TessLevelInner + OpDecorateString %gl_TessLevelInner UserSemantic "SV_InsideTessFactor" + OpDecorate %gl_TessLevelInner Patch + OpDecorateString %out_var_PN_POSITION9 UserSemantic "PN_POSITION9" + OpDecorate %out_var_PN_POSITION9 Patch + OpDecorate %in_var_TEXCOORD10_centroid Location 0 + OpDecorate %in_var_TEXCOORD11_centroid Location 1 + OpDecorate %in_var_VS_To_DS_Position Location 2 + OpDecorate %in_var_VS_To_DS_VertexID Location 3 + OpDecorate %out_var_PN_DisplacementScales Location 0 + OpDecorate %out_var_PN_DominantEdge Location 1 + OpDecorate %out_var_PN_DominantEdge1 Location 2 + OpDecorate %out_var_PN_DominantEdge2 Location 3 + OpDecorate %out_var_PN_DominantEdge3 Location 4 + OpDecorate %out_var_PN_DominantEdge4 Location 5 + OpDecorate %out_var_PN_DominantEdge5 Location 6 + OpDecorate %out_var_PN_DominantVertex Location 7 + OpDecorate %out_var_PN_DominantVertex1 Location 8 + OpDecorate %out_var_PN_DominantVertex2 Location 9 + OpDecorate %out_var_PN_POSITION Location 10 + OpDecorate %out_var_PN_POSITION9 Location 13 + OpDecorate %out_var_PN_TessellationMultiplier Location 14 + OpDecorate %out_var_PN_WorldDisplacementMultiplier Location 15 + OpDecorate %out_var_TEXCOORD10_centroid Location 16 + OpDecorate %out_var_TEXCOORD11_centroid Location 17 + OpDecorate %out_var_VS_To_DS_Position Location 18 + OpDecorate %out_var_VS_To_DS_VertexID Location 19 + OpDecorate %View DescriptorSet 0 + OpDecorate %View Binding 0 + OpDecorate %Primitive DescriptorSet 0 + OpDecorate %Primitive Binding 1 + OpDecorate %_arr_v4float_uint_2 ArrayStride 16 + OpDecorate %_arr_v4float_uint_7 ArrayStride 16 + OpDecorate %_arr_v4float_uint_4 ArrayStride 16 + OpMemberDecorate %type_View 0 Offset 0 + OpMemberDecorate %type_View 0 MatrixStride 16 + OpMemberDecorate %type_View 0 ColMajor + OpMemberDecorate %type_View 1 Offset 64 + OpMemberDecorate %type_View 1 MatrixStride 16 + OpMemberDecorate %type_View 1 ColMajor + OpMemberDecorate %type_View 2 Offset 128 + OpMemberDecorate %type_View 2 MatrixStride 16 + OpMemberDecorate %type_View 2 ColMajor + OpMemberDecorate %type_View 3 Offset 192 + OpMemberDecorate %type_View 3 MatrixStride 16 + OpMemberDecorate %type_View 3 ColMajor + OpMemberDecorate %type_View 4 Offset 256 + OpMemberDecorate %type_View 4 MatrixStride 16 + OpMemberDecorate %type_View 4 ColMajor + OpMemberDecorate %type_View 5 Offset 320 + OpMemberDecorate %type_View 5 MatrixStride 16 + OpMemberDecorate %type_View 5 ColMajor + OpMemberDecorate %type_View 6 Offset 384 + OpMemberDecorate %type_View 6 MatrixStride 16 + OpMemberDecorate %type_View 6 ColMajor + OpMemberDecorate %type_View 7 Offset 448 + OpMemberDecorate %type_View 7 MatrixStride 16 + OpMemberDecorate %type_View 7 ColMajor + OpMemberDecorate %type_View 8 Offset 512 + OpMemberDecorate %type_View 8 MatrixStride 16 + OpMemberDecorate %type_View 8 ColMajor + OpMemberDecorate %type_View 9 Offset 576 + OpMemberDecorate %type_View 9 MatrixStride 16 + OpMemberDecorate %type_View 9 ColMajor + OpMemberDecorate %type_View 10 Offset 640 + OpMemberDecorate %type_View 10 MatrixStride 16 + OpMemberDecorate %type_View 10 ColMajor + OpMemberDecorate %type_View 11 Offset 704 + OpMemberDecorate %type_View 11 MatrixStride 16 + OpMemberDecorate %type_View 11 ColMajor + OpMemberDecorate %type_View 12 Offset 768 + OpMemberDecorate %type_View 12 MatrixStride 16 + OpMemberDecorate %type_View 12 ColMajor + OpMemberDecorate %type_View 13 Offset 832 + OpMemberDecorate %type_View 13 MatrixStride 16 + OpMemberDecorate %type_View 13 ColMajor + OpMemberDecorate %type_View 14 Offset 896 + OpMemberDecorate %type_View 15 Offset 908 + OpMemberDecorate %type_View 16 Offset 912 + OpMemberDecorate %type_View 17 Offset 924 + OpMemberDecorate %type_View 18 Offset 928 + OpMemberDecorate %type_View 19 Offset 940 + OpMemberDecorate %type_View 20 Offset 944 + OpMemberDecorate %type_View 21 Offset 956 + OpMemberDecorate %type_View 22 Offset 960 + OpMemberDecorate %type_View 23 Offset 972 + OpMemberDecorate %type_View 24 Offset 976 + OpMemberDecorate %type_View 25 Offset 992 + OpMemberDecorate %type_View 26 Offset 1008 + OpMemberDecorate %type_View 27 Offset 1020 + OpMemberDecorate %type_View 28 Offset 1024 + OpMemberDecorate %type_View 29 Offset 1036 + OpMemberDecorate %type_View 30 Offset 1040 + OpMemberDecorate %type_View 31 Offset 1052 + OpMemberDecorate %type_View 32 Offset 1056 + OpMemberDecorate %type_View 33 Offset 1068 + OpMemberDecorate %type_View 34 Offset 1072 + OpMemberDecorate %type_View 34 MatrixStride 16 + OpMemberDecorate %type_View 34 ColMajor + OpMemberDecorate %type_View 35 Offset 1136 + OpMemberDecorate %type_View 35 MatrixStride 16 + OpMemberDecorate %type_View 35 ColMajor + OpMemberDecorate %type_View 36 Offset 1200 + OpMemberDecorate %type_View 36 MatrixStride 16 + OpMemberDecorate %type_View 36 ColMajor + OpMemberDecorate %type_View 37 Offset 1264 + OpMemberDecorate %type_View 37 MatrixStride 16 + OpMemberDecorate %type_View 37 ColMajor + OpMemberDecorate %type_View 38 Offset 1328 + OpMemberDecorate %type_View 38 MatrixStride 16 + OpMemberDecorate %type_View 38 ColMajor + OpMemberDecorate %type_View 39 Offset 1392 + OpMemberDecorate %type_View 39 MatrixStride 16 + OpMemberDecorate %type_View 39 ColMajor + OpMemberDecorate %type_View 40 Offset 1456 + OpMemberDecorate %type_View 40 MatrixStride 16 + OpMemberDecorate %type_View 40 ColMajor + OpMemberDecorate %type_View 41 Offset 1520 + OpMemberDecorate %type_View 41 MatrixStride 16 + OpMemberDecorate %type_View 41 ColMajor + OpMemberDecorate %type_View 42 Offset 1584 + OpMemberDecorate %type_View 42 MatrixStride 16 + OpMemberDecorate %type_View 42 ColMajor + OpMemberDecorate %type_View 43 Offset 1648 + OpMemberDecorate %type_View 43 MatrixStride 16 + OpMemberDecorate %type_View 43 ColMajor + OpMemberDecorate %type_View 44 Offset 1712 + OpMemberDecorate %type_View 45 Offset 1724 + OpMemberDecorate %type_View 46 Offset 1728 + OpMemberDecorate %type_View 47 Offset 1740 + OpMemberDecorate %type_View 48 Offset 1744 + OpMemberDecorate %type_View 49 Offset 1756 + OpMemberDecorate %type_View 50 Offset 1760 + OpMemberDecorate %type_View 50 MatrixStride 16 + OpMemberDecorate %type_View 50 ColMajor + OpMemberDecorate %type_View 51 Offset 1824 + OpMemberDecorate %type_View 51 MatrixStride 16 + OpMemberDecorate %type_View 51 ColMajor + OpMemberDecorate %type_View 52 Offset 1888 + OpMemberDecorate %type_View 52 MatrixStride 16 + OpMemberDecorate %type_View 52 ColMajor + OpMemberDecorate %type_View 53 Offset 1952 + OpMemberDecorate %type_View 54 Offset 1968 + OpMemberDecorate %type_View 55 Offset 1984 + OpMemberDecorate %type_View 56 Offset 1992 + OpMemberDecorate %type_View 57 Offset 2000 + OpMemberDecorate %type_View 58 Offset 2016 + OpMemberDecorate %type_View 59 Offset 2032 + OpMemberDecorate %type_View 60 Offset 2048 + OpMemberDecorate %type_View 61 Offset 2064 + OpMemberDecorate %type_View 62 Offset 2068 + OpMemberDecorate %type_View 63 Offset 2072 + OpMemberDecorate %type_View 64 Offset 2076 + OpMemberDecorate %type_View 65 Offset 2080 + OpMemberDecorate %type_View 66 Offset 2096 + OpMemberDecorate %type_View 67 Offset 2112 + OpMemberDecorate %type_View 68 Offset 2128 + OpMemberDecorate %type_View 69 Offset 2136 + OpMemberDecorate %type_View 70 Offset 2140 + OpMemberDecorate %type_View 71 Offset 2144 + OpMemberDecorate %type_View 72 Offset 2148 + OpMemberDecorate %type_View 73 Offset 2152 + OpMemberDecorate %type_View 74 Offset 2156 + OpMemberDecorate %type_View 75 Offset 2160 + OpMemberDecorate %type_View 76 Offset 2172 + OpMemberDecorate %type_View 77 Offset 2176 + OpMemberDecorate %type_View 78 Offset 2180 + OpMemberDecorate %type_View 79 Offset 2184 + OpMemberDecorate %type_View 80 Offset 2188 + OpMemberDecorate %type_View 81 Offset 2192 + OpMemberDecorate %type_View 82 Offset 2196 + OpMemberDecorate %type_View 83 Offset 2200 + OpMemberDecorate %type_View 84 Offset 2204 + OpMemberDecorate %type_View 85 Offset 2208 + OpMemberDecorate %type_View 86 Offset 2212 + OpMemberDecorate %type_View 87 Offset 2216 + OpMemberDecorate %type_View 88 Offset 2220 + OpMemberDecorate %type_View 89 Offset 2224 + OpMemberDecorate %type_View 90 Offset 2228 + OpMemberDecorate %type_View 91 Offset 2232 + OpMemberDecorate %type_View 92 Offset 2236 + OpMemberDecorate %type_View 93 Offset 2240 + OpMemberDecorate %type_View 94 Offset 2256 + OpMemberDecorate %type_View 95 Offset 2268 + OpMemberDecorate %type_View 96 Offset 2272 + OpMemberDecorate %type_View 97 Offset 2304 + OpMemberDecorate %type_View 98 Offset 2336 + OpMemberDecorate %type_View 99 Offset 2352 + OpMemberDecorate %type_View 100 Offset 2368 + OpMemberDecorate %type_View 101 Offset 2372 + OpMemberDecorate %type_View 102 Offset 2376 + OpMemberDecorate %type_View 103 Offset 2380 + OpMemberDecorate %type_View 104 Offset 2384 + OpMemberDecorate %type_View 105 Offset 2388 + OpMemberDecorate %type_View 106 Offset 2392 + OpMemberDecorate %type_View 107 Offset 2396 + OpMemberDecorate %type_View 108 Offset 2400 + OpMemberDecorate %type_View 109 Offset 2404 + OpMemberDecorate %type_View 110 Offset 2408 + OpMemberDecorate %type_View 111 Offset 2412 + OpMemberDecorate %type_View 112 Offset 2416 + OpMemberDecorate %type_View 113 Offset 2428 + OpMemberDecorate %type_View 114 Offset 2432 + OpMemberDecorate %type_View 115 Offset 2444 + OpMemberDecorate %type_View 116 Offset 2448 + OpMemberDecorate %type_View 117 Offset 2452 + OpMemberDecorate %type_View 118 Offset 2456 + OpMemberDecorate %type_View 119 Offset 2460 + OpMemberDecorate %type_View 120 Offset 2464 + OpMemberDecorate %type_View 121 Offset 2468 + OpMemberDecorate %type_View 122 Offset 2472 + OpMemberDecorate %type_View 123 Offset 2476 + OpMemberDecorate %type_View 124 Offset 2480 + OpMemberDecorate %type_View 125 Offset 2484 + OpMemberDecorate %type_View 126 Offset 2488 + OpMemberDecorate %type_View 127 Offset 2492 + OpMemberDecorate %type_View 128 Offset 2496 + OpMemberDecorate %type_View 129 Offset 2512 + OpMemberDecorate %type_View 130 Offset 2516 + OpMemberDecorate %type_View 131 Offset 2520 + OpMemberDecorate %type_View 132 Offset 2524 + OpMemberDecorate %type_View 133 Offset 2528 + OpMemberDecorate %type_View 134 Offset 2544 + OpMemberDecorate %type_View 135 Offset 2556 + OpMemberDecorate %type_View 136 Offset 2560 + OpMemberDecorate %type_View 137 Offset 2576 + OpMemberDecorate %type_View 138 Offset 2580 + OpMemberDecorate %type_View 139 Offset 2584 + OpMemberDecorate %type_View 140 Offset 2588 + OpMemberDecorate %type_View 141 Offset 2592 + OpMemberDecorate %type_View 142 Offset 2608 + OpMemberDecorate %type_View 143 Offset 2720 + OpMemberDecorate %type_View 144 Offset 2724 + OpMemberDecorate %type_View 145 Offset 2728 + OpMemberDecorate %type_View 146 Offset 2732 + OpMemberDecorate %type_View 147 Offset 2736 + OpMemberDecorate %type_View 148 Offset 2740 + OpMemberDecorate %type_View 149 Offset 2744 + OpMemberDecorate %type_View 150 Offset 2748 + OpMemberDecorate %type_View 151 Offset 2752 + OpMemberDecorate %type_View 152 Offset 2764 + OpMemberDecorate %type_View 153 Offset 2768 + OpMemberDecorate %type_View 154 Offset 2832 + OpMemberDecorate %type_View 155 Offset 2896 + OpMemberDecorate %type_View 156 Offset 2900 + OpMemberDecorate %type_View 157 Offset 2904 + OpMemberDecorate %type_View 158 Offset 2908 + OpMemberDecorate %type_View 159 Offset 2912 + OpMemberDecorate %type_View 160 Offset 2920 + OpMemberDecorate %type_View 161 Offset 2924 + OpMemberDecorate %type_View 162 Offset 2928 + OpMemberDecorate %type_View 163 Offset 2940 + OpMemberDecorate %type_View 164 Offset 2944 + OpMemberDecorate %type_View 165 Offset 2956 + OpMemberDecorate %type_View 166 Offset 2960 + OpMemberDecorate %type_View 167 Offset 2968 + OpMemberDecorate %type_View 168 Offset 2972 + OpMemberDecorate %type_View 169 Offset 2976 + OpMemberDecorate %type_View 170 Offset 2988 + OpMemberDecorate %type_View 171 Offset 2992 + OpMemberDecorate %type_View 172 Offset 3004 + OpMemberDecorate %type_View 173 Offset 3008 + OpMemberDecorate %type_View 174 Offset 3020 + OpMemberDecorate %type_View 175 Offset 3024 + OpMemberDecorate %type_View 176 Offset 3036 + OpMemberDecorate %type_View 177 Offset 3040 + OpMemberDecorate %type_View 178 Offset 3044 + OpDecorate %type_View Block + OpMemberDecorate %type_Primitive 0 Offset 0 + OpMemberDecorate %type_Primitive 0 MatrixStride 16 + OpMemberDecorate %type_Primitive 0 ColMajor + OpMemberDecorate %type_Primitive 1 Offset 64 + OpMemberDecorate %type_Primitive 2 Offset 80 + OpMemberDecorate %type_Primitive 3 Offset 96 + OpMemberDecorate %type_Primitive 3 MatrixStride 16 + OpMemberDecorate %type_Primitive 3 ColMajor + OpMemberDecorate %type_Primitive 4 Offset 160 + OpMemberDecorate %type_Primitive 4 MatrixStride 16 + OpMemberDecorate %type_Primitive 4 ColMajor + OpMemberDecorate %type_Primitive 5 Offset 224 + OpMemberDecorate %type_Primitive 5 MatrixStride 16 + OpMemberDecorate %type_Primitive 5 ColMajor + OpMemberDecorate %type_Primitive 6 Offset 288 + OpMemberDecorate %type_Primitive 7 Offset 300 + OpMemberDecorate %type_Primitive 8 Offset 304 + OpMemberDecorate %type_Primitive 9 Offset 316 + OpMemberDecorate %type_Primitive 10 Offset 320 + OpMemberDecorate %type_Primitive 11 Offset 324 + OpMemberDecorate %type_Primitive 12 Offset 328 + OpMemberDecorate %type_Primitive 13 Offset 332 + OpMemberDecorate %type_Primitive 14 Offset 336 + OpMemberDecorate %type_Primitive 15 Offset 352 + OpMemberDecorate %type_Primitive 16 Offset 368 + OpMemberDecorate %type_Primitive 17 Offset 380 + OpMemberDecorate %type_Primitive 18 Offset 384 + OpMemberDecorate %type_Primitive 19 Offset 396 + OpMemberDecorate %type_Primitive 20 Offset 400 + OpMemberDecorate %type_Primitive 21 Offset 412 + OpMemberDecorate %type_Primitive 22 Offset 416 + OpMemberDecorate %type_Primitive 23 Offset 420 + OpMemberDecorate %type_Primitive 24 Offset 424 + OpMemberDecorate %type_Primitive 25 Offset 428 + OpMemberDecorate %type_Primitive 26 Offset 432 + OpDecorate %type_Primitive Block + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 +%mat4v4float = OpTypeMatrix %v4float 4 + %v3float = OpTypeVector %float 3 + %v2float = OpTypeVector %float 2 + %int = OpTypeInt 32 1 + %uint = OpTypeInt 32 0 + %uint_2 = OpConstant %uint 2 + %uint_7 = OpConstant %uint 7 + %uint_4 = OpConstant %uint 4 + %v2int = OpTypeVector %int 2 + %uint_0 = OpConstant %uint 0 + %uint_1 = OpConstant %uint 1 + %uint_3 = OpConstant %uint 3 +%_arr_float_uint_3 = OpTypeArray %float %uint_3 + %int_1 = OpConstant %int 1 + %int_0 = OpConstant %int 0 + %int_2 = OpConstant %int 2 + %float_2 = OpConstant %float 2 + %63 = OpConstantComposite %v4float %float_2 %float_2 %float_2 %float_2 + %float_0_5 = OpConstant %float 0.5 + %int_3 = OpConstant %int 3 +%float_0_333000004 = OpConstant %float 0.333000004 + %float_1 = OpConstant %float 1 + %68 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1 + %float_15 = OpConstant %float 15 + %70 = OpConstantComposite %v4float %float_15 %float_15 %float_15 %float_15 +%FVertexFactoryInterpolantsVSToPS = OpTypeStruct %v4float %v4float +%FVertexFactoryInterpolantsVSToDS = OpTypeStruct %FVertexFactoryInterpolantsVSToPS +%FHitProxyVSToDS = OpTypeStruct %FVertexFactoryInterpolantsVSToDS %v4float %uint +%_arr_v4float_uint_3 = OpTypeArray %v4float %uint_3 +%FHullShaderConstantDominantVertexData = OpTypeStruct %v2float %v4float %v3float +%FHullShaderConstantDominantEdgeData = OpTypeStruct %v2float %v2float %v4float %v4float %v3float %v3float +%FPNTessellationHSToDS = OpTypeStruct %FHitProxyVSToDS %_arr_v4float_uint_3 %v3float %float %float %FHullShaderConstantDominantVertexData %FHullShaderConstantDominantEdgeData + %uint_9 = OpConstant %uint 9 + %v3int = OpTypeVector %int 3 + %74 = OpConstantComposite %v3int %int_0 %int_0 %int_0 + %75 = OpConstantComposite %v3int %int_3 %int_3 %int_3 + %float_0 = OpConstant %float 0 + %77 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0 + %78 = OpConstantComposite %v3float %float_0_5 %float_0_5 %float_0_5 + %int_78 = OpConstant %int 78 + %int_15 = OpConstant %int 15 + %int_7 = OpConstant %int 7 + %int_28 = OpConstant %int 28 + %83 = OpConstantComposite %v3int %int_1 %int_1 %int_1 + %84 = OpConstantComposite %v3int %int_2 %int_2 %int_2 +%_arr_v4float_uint_2 = OpTypeArray %v4float %uint_2 +%_arr_v4float_uint_7 = OpTypeArray %v4float %uint_7 +%_arr_v4float_uint_4 = OpTypeArray %v4float %uint_4 + %type_View = OpTypeStruct %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %v3float %float %v3float %float %v3float %float %v3float %float %v3float %float %v4float %v4float %v3float %float %v3float %float %v3float %float %v3float %float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %v3float %float %v3float %float %v3float %float %mat4v4float %mat4v4float %mat4v4float %v4float %v4float %v2float %v2float %v4float %v4float %v4float %v4float %int %float %float %float %v4float %v4float %v4float %v2float %float %float %float %float %float %float %v3float %float %float %float %float %float %float %float %float %uint %uint %uint %uint %float %float %float %float %float %v4float %v3float %float %_arr_v4float_uint_2 %_arr_v4float_uint_2 %v4float %v4float %float %float %float %float %float %float %float %float %float %float %float %float %v3float %float %v3float %float %float %float %float %float %float %float %float %float %float %float %float %float %v4float %uint %uint %uint %uint %v4float %v3float %float %v4float %float %float %float %float %v4float %_arr_v4float_uint_7 %float %float %float %float %uint %float %float %float %v3float %int %_arr_v4float_uint_4 %_arr_v4float_uint_4 %float %float %float %float %v2int %float %float %v3float %float %v3float %float %v2float %float %float %v3float %float %v3float %float %v3float %float %v3float %float %float %float +%_ptr_Uniform_type_View = OpTypePointer Uniform %type_View +%type_Primitive = OpTypeStruct %mat4v4float %v4float %v4float %mat4v4float %mat4v4float %mat4v4float %v3float %float %v3float %float %float %float %float %float %v4float %v4float %v3float %uint %v3float %uint %v3float %int %uint %uint %uint %uint %_arr_v4float_uint_4 +%_ptr_Uniform_type_Primitive = OpTypePointer Uniform %type_Primitive + %uint_12 = OpConstant %uint 12 +%_arr_v4float_uint_12 = OpTypeArray %v4float %uint_12 +%_ptr_Input__arr_v4float_uint_12 = OpTypePointer Input %_arr_v4float_uint_12 +%_arr_uint_uint_12 = OpTypeArray %uint %uint_12 +%_ptr_Input__arr_uint_uint_12 = OpTypePointer Input %_arr_uint_uint_12 +%_ptr_Input_uint = OpTypePointer Input %uint +%_ptr_Output__arr_v4float_uint_3 = OpTypePointer Output %_arr_v4float_uint_3 +%_arr_uint_uint_3 = OpTypeArray %uint %uint_3 +%_ptr_Output__arr_uint_uint_3 = OpTypePointer Output %_arr_uint_uint_3 +%_arr__arr_v4float_uint_3_uint_3 = OpTypeArray %_arr_v4float_uint_3 %uint_3 +%_ptr_Output__arr__arr_v4float_uint_3_uint_3 = OpTypePointer Output %_arr__arr_v4float_uint_3_uint_3 +%_arr_v3float_uint_3 = OpTypeArray %v3float %uint_3 +%_ptr_Output__arr_v3float_uint_3 = OpTypePointer Output %_arr_v3float_uint_3 +%_ptr_Output__arr_float_uint_3 = OpTypePointer Output %_arr_float_uint_3 +%_arr_v2float_uint_3 = OpTypeArray %v2float %uint_3 +%_ptr_Output__arr_v2float_uint_3 = OpTypePointer Output %_arr_v2float_uint_3 +%_arr_float_uint_4 = OpTypeArray %float %uint_4 +%_ptr_Output__arr_float_uint_4 = OpTypePointer Output %_arr_float_uint_4 +%_arr_float_uint_2 = OpTypeArray %float %uint_2 +%_ptr_Output__arr_float_uint_2 = OpTypePointer Output %_arr_float_uint_2 +%_ptr_Output_v4float = OpTypePointer Output %v4float + %void = OpTypeVoid + %109 = OpTypeFunction %void +%_arr_FHitProxyVSToDS_uint_12 = OpTypeArray %FHitProxyVSToDS %uint_12 +%_ptr_Function__arr_FHitProxyVSToDS_uint_12 = OpTypePointer Function %_arr_FHitProxyVSToDS_uint_12 +%_arr_FPNTessellationHSToDS_uint_3 = OpTypeArray %FPNTessellationHSToDS %uint_3 +%_ptr_Function__arr_FPNTessellationHSToDS_uint_3 = OpTypePointer Function %_arr_FPNTessellationHSToDS_uint_3 +%_ptr_Workgroup__arr_FPNTessellationHSToDS_uint_3 = OpTypePointer Workgroup %_arr_FPNTessellationHSToDS_uint_3 +%_ptr_Output_uint = OpTypePointer Output %uint +%_ptr_Output_v3float = OpTypePointer Output %v3float +%_ptr_Output_float = OpTypePointer Output %float +%_ptr_Output_v2float = OpTypePointer Output %v2float +%_ptr_Function_FPNTessellationHSToDS = OpTypePointer Function %FPNTessellationHSToDS +%_ptr_Workgroup_FPNTessellationHSToDS = OpTypePointer Workgroup %FPNTessellationHSToDS + %bool = OpTypeBool +%_ptr_Function_v4float = OpTypePointer Function %v4float +%_ptr_Function_float = OpTypePointer Function %float +%_ptr_Workgroup_v4float = OpTypePointer Workgroup %v4float +%_ptr_Workgroup_float = OpTypePointer Workgroup %float +%mat3v3float = OpTypeMatrix %v3float 3 +%_ptr_Function_FVertexFactoryInterpolantsVSToDS = OpTypePointer Function %FVertexFactoryInterpolantsVSToDS +%_ptr_Function_FHitProxyVSToDS = OpTypePointer Function %FHitProxyVSToDS + %v3bool = OpTypeVector %bool 3 +%_ptr_Uniform_float = OpTypePointer Uniform %float +%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float +%_ptr_Uniform_mat4v4float = OpTypePointer Uniform %mat4v4float +%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float + %View = OpVariable %_ptr_Uniform_type_View Uniform + %Primitive = OpVariable %_ptr_Uniform_type_Primitive Uniform +%in_var_TEXCOORD10_centroid = OpVariable %_ptr_Input__arr_v4float_uint_12 Input +%in_var_TEXCOORD11_centroid = OpVariable %_ptr_Input__arr_v4float_uint_12 Input +%in_var_VS_To_DS_Position = OpVariable %_ptr_Input__arr_v4float_uint_12 Input +%in_var_VS_To_DS_VertexID = OpVariable %_ptr_Input__arr_uint_uint_12 Input +%gl_InvocationID = OpVariable %_ptr_Input_uint Input +%out_var_TEXCOORD10_centroid = OpVariable %_ptr_Output__arr_v4float_uint_3 Output +%out_var_TEXCOORD11_centroid = OpVariable %_ptr_Output__arr_v4float_uint_3 Output +%out_var_VS_To_DS_Position = OpVariable %_ptr_Output__arr_v4float_uint_3 Output +%out_var_VS_To_DS_VertexID = OpVariable %_ptr_Output__arr_uint_uint_3 Output +%out_var_PN_POSITION = OpVariable %_ptr_Output__arr__arr_v4float_uint_3_uint_3 Output +%out_var_PN_DisplacementScales = OpVariable %_ptr_Output__arr_v3float_uint_3 Output +%out_var_PN_TessellationMultiplier = OpVariable %_ptr_Output__arr_float_uint_3 Output +%out_var_PN_WorldDisplacementMultiplier = OpVariable %_ptr_Output__arr_float_uint_3 Output +%out_var_PN_DominantVertex = OpVariable %_ptr_Output__arr_v2float_uint_3 Output +%out_var_PN_DominantVertex1 = OpVariable %_ptr_Output__arr_v4float_uint_3 Output +%out_var_PN_DominantVertex2 = OpVariable %_ptr_Output__arr_v3float_uint_3 Output +%out_var_PN_DominantEdge = OpVariable %_ptr_Output__arr_v2float_uint_3 Output +%out_var_PN_DominantEdge1 = OpVariable %_ptr_Output__arr_v2float_uint_3 Output +%out_var_PN_DominantEdge2 = OpVariable %_ptr_Output__arr_v4float_uint_3 Output +%out_var_PN_DominantEdge3 = OpVariable %_ptr_Output__arr_v4float_uint_3 Output +%out_var_PN_DominantEdge4 = OpVariable %_ptr_Output__arr_v3float_uint_3 Output +%out_var_PN_DominantEdge5 = OpVariable %_ptr_Output__arr_v3float_uint_3 Output +%gl_TessLevelOuter = OpVariable %_ptr_Output__arr_float_uint_4 Output +%gl_TessLevelInner = OpVariable %_ptr_Output__arr_float_uint_2 Output +%out_var_PN_POSITION9 = OpVariable %_ptr_Output_v4float Output + %130 = OpConstantNull %v2float +%float_0_333333343 = OpConstant %float 0.333333343 + %132 = OpConstantComposite %v4float %float_0_333333343 %float_0_333333343 %float_0_333333343 %float_0_333333343 + %133 = OpConstantComposite %v4float %float_0_5 %float_0_5 %float_0_5 %float_0_5 +%float_0_166666672 = OpConstant %float 0.166666672 + %135 = OpConstantComposite %v4float %float_0_166666672 %float_0_166666672 %float_0_166666672 %float_0_166666672 + %136 = OpUndef %v4float + +; XXX: Original asm used Function here, which is wrong. +; This patches the SPIR-V to be correct. +%temp_var_hullMainRetVal = OpVariable %_ptr_Workgroup__arr_FPNTessellationHSToDS_uint_3 Workgroup + + %MainHull = OpFunction %void None %109 + %137 = OpLabel +%param_var_I = OpVariable %_ptr_Function__arr_FHitProxyVSToDS_uint_12 Function + %138 = OpLoad %_arr_v4float_uint_12 %in_var_TEXCOORD10_centroid + %139 = OpLoad %_arr_v4float_uint_12 %in_var_TEXCOORD11_centroid + %140 = OpCompositeExtract %v4float %138 0 + %141 = OpCompositeExtract %v4float %139 0 + %142 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToPS %140 %141 + %143 = OpCompositeExtract %v4float %138 1 + %144 = OpCompositeExtract %v4float %139 1 + %145 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToPS %143 %144 + %146 = OpCompositeExtract %v4float %138 2 + %147 = OpCompositeExtract %v4float %139 2 + %148 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToPS %146 %147 + %149 = OpCompositeExtract %v4float %138 3 + %150 = OpCompositeExtract %v4float %139 3 + %151 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToPS %149 %150 + %152 = OpCompositeExtract %v4float %138 4 + %153 = OpCompositeExtract %v4float %139 4 + %154 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToPS %152 %153 + %155 = OpCompositeExtract %v4float %138 5 + %156 = OpCompositeExtract %v4float %139 5 + %157 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToPS %155 %156 + %158 = OpCompositeExtract %v4float %138 6 + %159 = OpCompositeExtract %v4float %139 6 + %160 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToPS %158 %159 + %161 = OpCompositeExtract %v4float %138 7 + %162 = OpCompositeExtract %v4float %139 7 + %163 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToPS %161 %162 + %164 = OpCompositeExtract %v4float %138 8 + %165 = OpCompositeExtract %v4float %139 8 + %166 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToPS %164 %165 + %167 = OpCompositeExtract %v4float %138 9 + %168 = OpCompositeExtract %v4float %139 9 + %169 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToPS %167 %168 + %170 = OpCompositeExtract %v4float %138 10 + %171 = OpCompositeExtract %v4float %139 10 + %172 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToPS %170 %171 + %173 = OpCompositeExtract %v4float %138 11 + %174 = OpCompositeExtract %v4float %139 11 + %175 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToPS %173 %174 + %176 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToDS %142 + %177 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToDS %145 + %178 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToDS %148 + %179 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToDS %151 + %180 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToDS %154 + %181 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToDS %157 + %182 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToDS %160 + %183 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToDS %163 + %184 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToDS %166 + %185 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToDS %169 + %186 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToDS %172 + %187 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToDS %175 + %188 = OpLoad %_arr_v4float_uint_12 %in_var_VS_To_DS_Position + %189 = OpLoad %_arr_uint_uint_12 %in_var_VS_To_DS_VertexID + %190 = OpCompositeExtract %v4float %188 0 + %191 = OpCompositeExtract %uint %189 0 + %192 = OpCompositeConstruct %FHitProxyVSToDS %176 %190 %191 + %193 = OpCompositeExtract %v4float %188 1 + %194 = OpCompositeExtract %uint %189 1 + %195 = OpCompositeConstruct %FHitProxyVSToDS %177 %193 %194 + %196 = OpCompositeExtract %v4float %188 2 + %197 = OpCompositeExtract %uint %189 2 + %198 = OpCompositeConstruct %FHitProxyVSToDS %178 %196 %197 + %199 = OpCompositeExtract %v4float %188 3 + %200 = OpCompositeExtract %uint %189 3 + %201 = OpCompositeConstruct %FHitProxyVSToDS %179 %199 %200 + %202 = OpCompositeExtract %v4float %188 4 + %203 = OpCompositeExtract %uint %189 4 + %204 = OpCompositeConstruct %FHitProxyVSToDS %180 %202 %203 + %205 = OpCompositeExtract %v4float %188 5 + %206 = OpCompositeExtract %uint %189 5 + %207 = OpCompositeConstruct %FHitProxyVSToDS %181 %205 %206 + %208 = OpCompositeExtract %v4float %188 6 + %209 = OpCompositeExtract %uint %189 6 + %210 = OpCompositeConstruct %FHitProxyVSToDS %182 %208 %209 + %211 = OpCompositeExtract %v4float %188 7 + %212 = OpCompositeExtract %uint %189 7 + %213 = OpCompositeConstruct %FHitProxyVSToDS %183 %211 %212 + %214 = OpCompositeExtract %v4float %188 8 + %215 = OpCompositeExtract %uint %189 8 + %216 = OpCompositeConstruct %FHitProxyVSToDS %184 %214 %215 + %217 = OpCompositeExtract %v4float %188 9 + %218 = OpCompositeExtract %uint %189 9 + %219 = OpCompositeConstruct %FHitProxyVSToDS %185 %217 %218 + %220 = OpCompositeExtract %v4float %188 10 + %221 = OpCompositeExtract %uint %189 10 + %222 = OpCompositeConstruct %FHitProxyVSToDS %186 %220 %221 + %223 = OpCompositeExtract %v4float %188 11 + %224 = OpCompositeExtract %uint %189 11 + %225 = OpCompositeConstruct %FHitProxyVSToDS %187 %223 %224 + %226 = OpCompositeConstruct %_arr_FHitProxyVSToDS_uint_12 %192 %195 %198 %201 %204 %207 %210 %213 %216 %219 %222 %225 + OpStore %param_var_I %226 + %227 = OpLoad %uint %gl_InvocationID + %228 = OpAccessChain %_ptr_Function_FVertexFactoryInterpolantsVSToDS %param_var_I %227 %int_0 + %229 = OpLoad %FVertexFactoryInterpolantsVSToDS %228 + %230 = OpCompositeExtract %FVertexFactoryInterpolantsVSToPS %229 0 + %231 = OpCompositeExtract %v4float %230 0 + %232 = OpCompositeExtract %v4float %230 1 + %233 = OpVectorShuffle %v3float %231 %231 0 1 2 + %234 = OpVectorShuffle %v3float %232 %232 0 1 2 + %235 = OpExtInst %v3float %1 Cross %234 %233 + %236 = OpCompositeExtract %float %232 3 + %237 = OpCompositeConstruct %v3float %236 %236 %236 + %238 = OpFMul %v3float %235 %237 + %239 = OpCompositeConstruct %mat3v3float %233 %238 %234 + %240 = OpCompositeExtract %float %232 0 + %241 = OpCompositeExtract %float %232 1 + %242 = OpCompositeExtract %float %232 2 + %243 = OpCompositeConstruct %v4float %240 %241 %242 %float_0 + %244 = OpAccessChain %_ptr_Uniform_v4float %Primitive %int_15 + %245 = OpLoad %v4float %244 + %246 = OpVectorShuffle %v3float %245 %245 0 1 2 + %247 = OpVectorTimesMatrix %v3float %246 %239 + %248 = OpULessThan %bool %227 %uint_2 + %249 = OpIAdd %uint %227 %uint_1 + %250 = OpSelect %uint %248 %249 %uint_0 + %251 = OpIMul %uint %uint_2 %227 + %252 = OpIAdd %uint %uint_3 %251 + %253 = OpIAdd %uint %251 %uint_4 + %254 = OpAccessChain %_ptr_Function_FHitProxyVSToDS %param_var_I %227 + %255 = OpLoad %FHitProxyVSToDS %254 + %256 = OpAccessChain %_ptr_Function_v4float %param_var_I %227 %int_1 + %257 = OpLoad %v4float %256 + %258 = OpULessThan %bool %250 %uint_2 + %259 = OpIAdd %uint %250 %uint_1 + %260 = OpSelect %uint %258 %259 %uint_0 + %261 = OpIMul %uint %uint_2 %250 + %262 = OpIAdd %uint %uint_3 %261 + %263 = OpIAdd %uint %261 %uint_4 + %264 = OpIAdd %uint %uint_9 %227 + %265 = OpAccessChain %_ptr_Function_FHitProxyVSToDS %param_var_I %264 + %266 = OpLoad %FHitProxyVSToDS %265 + %267 = OpCompositeExtract %FVertexFactoryInterpolantsVSToDS %266 0 + %268 = OpCompositeExtract %FVertexFactoryInterpolantsVSToPS %267 0 + %269 = OpCompositeExtract %v4float %268 0 + %270 = OpCompositeExtract %v4float %268 1 + %271 = OpVectorShuffle %v3float %269 %269 0 1 2 + %272 = OpCompositeExtract %float %270 0 + %273 = OpCompositeExtract %float %270 1 + %274 = OpCompositeExtract %float %270 2 + %275 = OpCompositeConstruct %v4float %272 %273 %274 %float_0 + %276 = OpAccessChain %_ptr_Function_FHitProxyVSToDS %param_var_I %250 + %277 = OpLoad %FHitProxyVSToDS %276 + %278 = OpCompositeExtract %uint %277 2 + %279 = OpAccessChain %_ptr_Function_FHitProxyVSToDS %param_var_I %260 + %280 = OpLoad %FHitProxyVSToDS %279 + %281 = OpCompositeExtract %uint %280 2 + %282 = OpAccessChain %_ptr_Function_FHitProxyVSToDS %param_var_I %262 + %283 = OpLoad %FHitProxyVSToDS %282 + %284 = OpCompositeExtract %uint %283 2 + %285 = OpAccessChain %_ptr_Function_FHitProxyVSToDS %param_var_I %263 + %286 = OpLoad %FHitProxyVSToDS %285 + %287 = OpCompositeExtract %uint %286 2 + %288 = OpCompositeExtract %FVertexFactoryInterpolantsVSToDS %277 0 + %289 = OpCompositeExtract %FVertexFactoryInterpolantsVSToPS %288 0 + %290 = OpCompositeExtract %v4float %289 0 + %291 = OpCompositeExtract %v4float %289 1 + %292 = OpCompositeExtract %FVertexFactoryInterpolantsVSToDS %280 0 + %293 = OpCompositeExtract %FVertexFactoryInterpolantsVSToPS %292 0 + %294 = OpCompositeExtract %v4float %293 0 + %295 = OpCompositeExtract %v4float %293 1 + %296 = OpULessThan %bool %284 %278 + %297 = OpIEqual %bool %284 %278 + %298 = OpULessThan %bool %287 %281 + %299 = OpLogicalAnd %bool %297 %298 + %300 = OpLogicalOr %bool %296 %299 + OpSelectionMerge %301 None + OpBranchConditional %300 %302 %301 + %302 = OpLabel + %303 = OpCompositeExtract %FVertexFactoryInterpolantsVSToDS %283 0 + %304 = OpCompositeExtract %FVertexFactoryInterpolantsVSToPS %303 0 + %305 = OpCompositeExtract %v4float %304 0 + %306 = OpCompositeExtract %v4float %304 1 + %307 = OpCompositeExtract %FVertexFactoryInterpolantsVSToDS %286 0 + %308 = OpCompositeExtract %FVertexFactoryInterpolantsVSToPS %307 0 + %309 = OpCompositeExtract %v4float %308 0 + %310 = OpCompositeExtract %v4float %308 1 + OpBranch %301 + %301 = OpLabel + %311 = OpPhi %v4float %294 %137 %309 %302 + %312 = OpPhi %v4float %295 %137 %310 %302 + %313 = OpPhi %v4float %290 %137 %305 %302 + %314 = OpPhi %v4float %291 %137 %306 %302 + %315 = OpVectorShuffle %v3float %313 %313 0 1 2 + %316 = OpVectorShuffle %v3float %311 %311 0 1 2 + %317 = OpCompositeExtract %float %314 0 + %318 = OpCompositeExtract %float %314 1 + %319 = OpCompositeExtract %float %314 2 + %320 = OpCompositeConstruct %v4float %317 %318 %319 %float_0 + %321 = OpCompositeExtract %float %312 0 + %322 = OpCompositeExtract %float %312 1 + %323 = OpCompositeExtract %float %312 2 + %324 = OpCompositeConstruct %v4float %321 %322 %323 %float_0 + %325 = OpAccessChain %_ptr_Function_FVertexFactoryInterpolantsVSToDS %param_var_I %250 %int_0 + %326 = OpLoad %FVertexFactoryInterpolantsVSToDS %325 + %327 = OpCompositeExtract %FVertexFactoryInterpolantsVSToPS %326 0 + %328 = OpCompositeExtract %v4float %327 1 + %329 = OpCompositeExtract %float %328 0 + %330 = OpCompositeExtract %float %328 1 + %331 = OpCompositeExtract %float %328 2 + %332 = OpCompositeConstruct %v4float %329 %330 %331 %float_0 + %333 = OpAccessChain %_ptr_Function_FVertexFactoryInterpolantsVSToDS %param_var_I %252 %int_0 + %334 = OpLoad %FVertexFactoryInterpolantsVSToDS %333 + %335 = OpCompositeExtract %FVertexFactoryInterpolantsVSToPS %334 0 + %336 = OpCompositeExtract %v4float %335 1 + %337 = OpCompositeExtract %float %336 0 + %338 = OpCompositeExtract %float %336 1 + %339 = OpCompositeExtract %float %336 2 + %340 = OpCompositeConstruct %v4float %337 %338 %339 %float_0 + %341 = OpAccessChain %_ptr_Function_FVertexFactoryInterpolantsVSToDS %param_var_I %253 %int_0 + %342 = OpLoad %FVertexFactoryInterpolantsVSToDS %341 + %343 = OpCompositeExtract %FVertexFactoryInterpolantsVSToPS %342 0 + %344 = OpCompositeExtract %v4float %343 1 + %345 = OpCompositeExtract %float %344 0 + %346 = OpCompositeExtract %float %344 1 + %347 = OpCompositeExtract %float %344 2 + %348 = OpCompositeConstruct %v4float %345 %346 %347 %float_0 + %349 = OpLoad %v4float %256 + %350 = OpAccessChain %_ptr_Function_v4float %param_var_I %250 %int_1 + %351 = OpLoad %v4float %350 + %352 = OpFMul %v4float %63 %349 + %353 = OpFAdd %v4float %352 %351 + %354 = OpFSub %v4float %351 %349 + %355 = OpDot %float %354 %243 + %356 = OpCompositeConstruct %v4float %355 %355 %355 %355 + %357 = OpFMul %v4float %356 %243 + %358 = OpFSub %v4float %353 %357 + %359 = OpFMul %v4float %358 %132 + %360 = OpAccessChain %_ptr_Function_v4float %param_var_I %252 %int_1 + %361 = OpLoad %v4float %360 + %362 = OpAccessChain %_ptr_Function_v4float %param_var_I %253 %int_1 + %363 = OpLoad %v4float %362 + %364 = OpFMul %v4float %63 %361 + %365 = OpFAdd %v4float %364 %363 + %366 = OpFSub %v4float %363 %361 + %367 = OpDot %float %366 %340 + %368 = OpCompositeConstruct %v4float %367 %367 %367 %367 + %369 = OpFMul %v4float %368 %340 + %370 = OpFSub %v4float %365 %369 + %371 = OpFMul %v4float %370 %132 + %372 = OpFAdd %v4float %359 %371 + %373 = OpFMul %v4float %372 %133 + %374 = OpLoad %v4float %350 + %375 = OpLoad %v4float %256 + %376 = OpFMul %v4float %63 %374 + %377 = OpFAdd %v4float %376 %375 + %378 = OpFSub %v4float %375 %374 + %379 = OpDot %float %378 %332 + %380 = OpCompositeConstruct %v4float %379 %379 %379 %379 + %381 = OpFMul %v4float %380 %332 + %382 = OpFSub %v4float %377 %381 + %383 = OpFMul %v4float %382 %132 + %384 = OpLoad %v4float %362 + %385 = OpLoad %v4float %360 + %386 = OpFMul %v4float %63 %384 + %387 = OpFAdd %v4float %386 %385 + %388 = OpFSub %v4float %385 %384 + %389 = OpDot %float %388 %348 + %390 = OpCompositeConstruct %v4float %389 %389 %389 %389 + %391 = OpFMul %v4float %390 %348 + %392 = OpFSub %v4float %387 %391 + %393 = OpFMul %v4float %392 %132 + %394 = OpFAdd %v4float %383 %393 + %395 = OpFMul %v4float %394 %133 + %396 = OpCompositeConstruct %FHullShaderConstantDominantEdgeData %130 %130 %320 %324 %315 %316 + %397 = OpCompositeConstruct %FHullShaderConstantDominantVertexData %130 %275 %271 + %398 = OpCompositeConstruct %_arr_v4float_uint_3 %257 %373 %395 + %399 = OpCompositeConstruct %FPNTessellationHSToDS %255 %398 %247 %float_1 %float_1 %397 %396 + %400 = OpCompositeExtract %FVertexFactoryInterpolantsVSToDS %255 0 + %401 = OpCompositeExtract %FVertexFactoryInterpolantsVSToPS %400 0 + %402 = OpCompositeExtract %v4float %401 0 + %403 = OpAccessChain %_ptr_Output_v4float %out_var_TEXCOORD10_centroid %227 + OpStore %403 %402 + %404 = OpCompositeExtract %v4float %401 1 + %405 = OpAccessChain %_ptr_Output_v4float %out_var_TEXCOORD11_centroid %227 + OpStore %405 %404 + %406 = OpCompositeExtract %v4float %255 1 + %407 = OpAccessChain %_ptr_Output_v4float %out_var_VS_To_DS_Position %227 + OpStore %407 %406 + %408 = OpCompositeExtract %uint %255 2 + %409 = OpAccessChain %_ptr_Output_uint %out_var_VS_To_DS_VertexID %227 + OpStore %409 %408 + %410 = OpAccessChain %_ptr_Output__arr_v4float_uint_3 %out_var_PN_POSITION %227 + OpStore %410 %398 + %411 = OpAccessChain %_ptr_Output_v3float %out_var_PN_DisplacementScales %227 + OpStore %411 %247 + %412 = OpAccessChain %_ptr_Output_float %out_var_PN_TessellationMultiplier %227 + OpStore %412 %float_1 + %413 = OpAccessChain %_ptr_Output_float %out_var_PN_WorldDisplacementMultiplier %227 + OpStore %413 %float_1 + %414 = OpAccessChain %_ptr_Output_v2float %out_var_PN_DominantVertex %227 + OpStore %414 %130 + %415 = OpAccessChain %_ptr_Output_v4float %out_var_PN_DominantVertex1 %227 + OpStore %415 %275 + %416 = OpAccessChain %_ptr_Output_v3float %out_var_PN_DominantVertex2 %227 + OpStore %416 %271 + %417 = OpAccessChain %_ptr_Output_v2float %out_var_PN_DominantEdge %227 + OpStore %417 %130 + %418 = OpAccessChain %_ptr_Output_v2float %out_var_PN_DominantEdge1 %227 + OpStore %418 %130 + %419 = OpAccessChain %_ptr_Output_v4float %out_var_PN_DominantEdge2 %227 + OpStore %419 %320 + %420 = OpAccessChain %_ptr_Output_v4float %out_var_PN_DominantEdge3 %227 + OpStore %420 %324 + %421 = OpAccessChain %_ptr_Output_v3float %out_var_PN_DominantEdge4 %227 + OpStore %421 %315 + %422 = OpAccessChain %_ptr_Output_v3float %out_var_PN_DominantEdge5 %227 + OpStore %422 %316 + %423 = OpAccessChain %_ptr_Workgroup_FPNTessellationHSToDS %temp_var_hullMainRetVal %227 + OpStore %423 %399 + OpControlBarrier %uint_2 %uint_4 %uint_0 + %424 = OpIEqual %bool %227 %uint_0 + OpSelectionMerge %if_merge None + OpBranchConditional %424 %425 %if_merge + %425 = OpLabel + %426 = OpAccessChain %_ptr_Uniform_mat4v4float %View %int_0 + %427 = OpLoad %mat4v4float %426 + %428 = OpAccessChain %_ptr_Uniform_mat4v4float %View %int_7 + %429 = OpLoad %mat4v4float %428 + %430 = OpAccessChain %_ptr_Uniform_v3float %View %int_28 + %431 = OpLoad %v3float %430 + %432 = OpAccessChain %_ptr_Uniform_float %View %int_78 + %433 = OpLoad %float %432 + %434 = OpAccessChain %_ptr_Workgroup_v4float %temp_var_hullMainRetVal %uint_0 %int_1 %int_0 + %435 = OpLoad %v4float %434 + %436 = OpAccessChain %_ptr_Workgroup_v4float %temp_var_hullMainRetVal %uint_0 %int_1 %int_1 + %437 = OpLoad %v4float %436 + %438 = OpAccessChain %_ptr_Workgroup_v4float %temp_var_hullMainRetVal %uint_0 %int_1 %int_2 + %439 = OpLoad %v4float %438 + %440 = OpAccessChain %_ptr_Workgroup_v4float %temp_var_hullMainRetVal %uint_1 %int_1 %int_0 + %441 = OpLoad %v4float %440 + %442 = OpAccessChain %_ptr_Workgroup_v4float %temp_var_hullMainRetVal %uint_1 %int_1 %int_1 + %443 = OpLoad %v4float %442 + %444 = OpAccessChain %_ptr_Workgroup_v4float %temp_var_hullMainRetVal %uint_1 %int_1 %int_2 + %445 = OpLoad %v4float %444 + %446 = OpAccessChain %_ptr_Workgroup_v4float %temp_var_hullMainRetVal %uint_2 %int_1 %int_0 + %447 = OpLoad %v4float %446 + %448 = OpAccessChain %_ptr_Workgroup_v4float %temp_var_hullMainRetVal %uint_2 %int_1 %int_1 + %449 = OpLoad %v4float %448 + %450 = OpAccessChain %_ptr_Workgroup_v4float %temp_var_hullMainRetVal %uint_2 %int_1 %int_2 + %451 = OpLoad %v4float %450 + %452 = OpFAdd %v4float %437 %439 + %453 = OpFAdd %v4float %452 %443 + %454 = OpFAdd %v4float %453 %445 + %455 = OpFAdd %v4float %454 %449 + %456 = OpFAdd %v4float %455 %451 + %457 = OpFMul %v4float %456 %135 + %458 = OpFAdd %v4float %447 %441 + %459 = OpFAdd %v4float %458 %435 + %460 = OpFMul %v4float %459 %132 + %461 = OpFSub %v4float %457 %460 + %462 = OpFMul %v4float %461 %133 + %463 = OpFAdd %v4float %457 %462 + %464 = OpAccessChain %_ptr_Workgroup_float %temp_var_hullMainRetVal %uint_1 %int_3 + %465 = OpLoad %float %464 + %466 = OpAccessChain %_ptr_Workgroup_float %temp_var_hullMainRetVal %uint_2 %int_3 + %467 = OpLoad %float %466 + %468 = OpFAdd %float %465 %467 + %469 = OpFMul %float %float_0_5 %468 + %470 = OpCompositeInsert %v4float %469 %136 0 + %471 = OpLoad %float %466 + %472 = OpAccessChain %_ptr_Workgroup_float %temp_var_hullMainRetVal %uint_0 %int_3 + %473 = OpLoad %float %472 + %474 = OpFAdd %float %471 %473 + %475 = OpFMul %float %float_0_5 %474 + %476 = OpCompositeInsert %v4float %475 %470 1 + %477 = OpLoad %float %472 + %478 = OpLoad %float %464 + %479 = OpFAdd %float %477 %478 + %480 = OpFMul %float %float_0_5 %479 + %481 = OpCompositeInsert %v4float %480 %476 2 + %482 = OpLoad %float %472 + %483 = OpLoad %float %464 + %484 = OpFAdd %float %482 %483 + %485 = OpLoad %float %466 + %486 = OpFAdd %float %484 %485 + %487 = OpFMul %float %float_0_333000004 %486 + %488 = OpCompositeInsert %v4float %487 %481 3 + %489 = OpVectorShuffle %v3float %435 %435 0 1 2 + %490 = OpVectorShuffle %v3float %441 %441 0 1 2 + %491 = OpVectorShuffle %v3float %447 %447 0 1 2 + OpBranch %492 + %492 = OpLabel + OpLoopMerge %493 %494 None + OpBranch %495 + %495 = OpLabel + %496 = OpMatrixTimesVector %v4float %429 %77 + %497 = OpCompositeExtract %float %435 0 + %498 = OpCompositeExtract %float %435 1 + %499 = OpCompositeExtract %float %435 2 + %500 = OpCompositeConstruct %v4float %497 %498 %499 %float_1 + %501 = OpMatrixTimesVector %v4float %427 %500 + %502 = OpVectorShuffle %v3float %501 %501 0 1 2 + %503 = OpVectorShuffle %v3float %496 %496 0 1 2 + %504 = OpFSub %v3float %502 %503 + %505 = OpCompositeExtract %float %501 3 + %506 = OpCompositeExtract %float %496 3 + %507 = OpFAdd %float %505 %506 + %508 = OpCompositeConstruct %v3float %507 %507 %507 + %509 = OpFOrdLessThan %v3bool %504 %508 + %510 = OpSelect %v3int %509 %83 %74 + %511 = OpFAdd %v3float %502 %503 + %512 = OpFNegate %float %505 + %513 = OpFSub %float %512 %506 + %514 = OpCompositeConstruct %v3float %513 %513 %513 + %515 = OpFOrdGreaterThan %v3bool %511 %514 + %516 = OpSelect %v3int %515 %83 %74 + %517 = OpIMul %v3int %84 %516 + %518 = OpIAdd %v3int %510 %517 + %519 = OpCompositeExtract %float %441 0 + %520 = OpCompositeExtract %float %441 1 + %521 = OpCompositeExtract %float %441 2 + %522 = OpCompositeConstruct %v4float %519 %520 %521 %float_1 + %523 = OpMatrixTimesVector %v4float %427 %522 + %524 = OpVectorShuffle %v3float %523 %523 0 1 2 + %525 = OpFSub %v3float %524 %503 + %526 = OpCompositeExtract %float %523 3 + %527 = OpFAdd %float %526 %506 + %528 = OpCompositeConstruct %v3float %527 %527 %527 + %529 = OpFOrdLessThan %v3bool %525 %528 + %530 = OpSelect %v3int %529 %83 %74 + %531 = OpFAdd %v3float %524 %503 + %532 = OpFNegate %float %526 + %533 = OpFSub %float %532 %506 + %534 = OpCompositeConstruct %v3float %533 %533 %533 + %535 = OpFOrdGreaterThan %v3bool %531 %534 + %536 = OpSelect %v3int %535 %83 %74 + %537 = OpIMul %v3int %84 %536 + %538 = OpIAdd %v3int %530 %537 + %539 = OpBitwiseOr %v3int %518 %538 + %540 = OpCompositeExtract %float %447 0 + %541 = OpCompositeExtract %float %447 1 + %542 = OpCompositeExtract %float %447 2 + %543 = OpCompositeConstruct %v4float %540 %541 %542 %float_1 + %544 = OpMatrixTimesVector %v4float %427 %543 + %545 = OpVectorShuffle %v3float %544 %544 0 1 2 + %546 = OpFSub %v3float %545 %503 + %547 = OpCompositeExtract %float %544 3 + %548 = OpFAdd %float %547 %506 + %549 = OpCompositeConstruct %v3float %548 %548 %548 + %550 = OpFOrdLessThan %v3bool %546 %549 + %551 = OpSelect %v3int %550 %83 %74 + %552 = OpFAdd %v3float %545 %503 + %553 = OpFNegate %float %547 + %554 = OpFSub %float %553 %506 + %555 = OpCompositeConstruct %v3float %554 %554 %554 + %556 = OpFOrdGreaterThan %v3bool %552 %555 + %557 = OpSelect %v3int %556 %83 %74 + %558 = OpIMul %v3int %84 %557 + %559 = OpIAdd %v3int %551 %558 + %560 = OpBitwiseOr %v3int %539 %559 + %561 = OpINotEqual %v3bool %560 %75 + %562 = OpAny %bool %561 + OpSelectionMerge %563 None + OpBranchConditional %562 %564 %563 + %564 = OpLabel + OpBranch %493 + %563 = OpLabel + %565 = OpFSub %v3float %489 %490 + %566 = OpFSub %v3float %490 %491 + %567 = OpFSub %v3float %491 %489 + %568 = OpFAdd %v3float %489 %490 + %569 = OpFMul %v3float %78 %568 + %570 = OpFSub %v3float %569 %431 + %571 = OpFAdd %v3float %490 %491 + %572 = OpFMul %v3float %78 %571 + %573 = OpFSub %v3float %572 %431 + %574 = OpFAdd %v3float %491 %489 + %575 = OpFMul %v3float %78 %574 + %576 = OpFSub %v3float %575 %431 + %577 = OpDot %float %566 %566 + %578 = OpDot %float %573 %573 + %579 = OpFDiv %float %577 %578 + %580 = OpExtInst %float %1 Sqrt %579 + %581 = OpDot %float %567 %567 + %582 = OpDot %float %576 %576 + %583 = OpFDiv %float %581 %582 + %584 = OpExtInst %float %1 Sqrt %583 + %585 = OpDot %float %565 %565 + %586 = OpDot %float %570 %570 + %587 = OpFDiv %float %585 %586 + %588 = OpExtInst %float %1 Sqrt %587 + %589 = OpCompositeConstruct %v4float %580 %584 %588 %float_1 + %590 = OpFAdd %float %580 %584 + %591 = OpFAdd %float %590 %588 + %592 = OpFMul %float %float_0_333000004 %591 + %593 = OpCompositeInsert %v4float %592 %589 3 + %594 = OpCompositeConstruct %v4float %433 %433 %433 %433 + %595 = OpFMul %v4float %594 %593 + OpBranch %493 + %494 = OpLabel + OpBranch %492 + %493 = OpLabel + %596 = OpPhi %v4float %77 %564 %595 %563 + %597 = OpFMul %v4float %488 %596 + %598 = OpExtInst %v4float %1 FClamp %597 %68 %70 + %599 = OpCompositeExtract %float %598 0 + %600 = OpCompositeExtract %float %598 1 + %601 = OpCompositeExtract %float %598 2 + %602 = OpCompositeExtract %float %598 3 + %603 = OpAccessChain %_ptr_Output_float %gl_TessLevelOuter %uint_0 + OpStore %603 %599 + %604 = OpAccessChain %_ptr_Output_float %gl_TessLevelOuter %uint_1 + OpStore %604 %600 + %605 = OpAccessChain %_ptr_Output_float %gl_TessLevelOuter %uint_2 + OpStore %605 %601 + %606 = OpAccessChain %_ptr_Output_float %gl_TessLevelInner %uint_0 + OpStore %606 %602 + OpStore %out_var_PN_POSITION9 %463 + OpBranch %if_merge + %if_merge = OpLabel + OpReturn + OpFunctionEnd diff --git a/third_party/spirv-cross/shaders-ue4/asm/tesc/hs-texcoord-array.asm.tesc b/third_party/spirv-cross/shaders-ue4/asm/tesc/hs-texcoord-array.asm.tesc new file mode 100644 index 0000000000..1a9b95e085 --- /dev/null +++ b/third_party/spirv-cross/shaders-ue4/asm/tesc/hs-texcoord-array.asm.tesc @@ -0,0 +1,1144 @@ +; SPIR-V +; Version: 1.0 +; Generator: Google spiregg; 0 +; Bound: 531 +; Schema: 0 + OpCapability Tessellation + OpCapability SampledBuffer + OpExtension "SPV_GOOGLE_hlsl_functionality1" + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint TessellationControl %MainHull "main" %in_var_TEXCOORD10_centroid %in_var_TEXCOORD11_centroid %in_var_COLOR0 %in_var_TEXCOORD0 %in_var_VS_To_DS_Position %gl_InvocationID %out_var_TEXCOORD10_centroid %out_var_TEXCOORD11_centroid %out_var_COLOR0 %out_var_TEXCOORD0 %out_var_VS_To_DS_Position %out_var_PN_POSITION %out_var_PN_DisplacementScales %out_var_PN_TessellationMultiplier %out_var_PN_WorldDisplacementMultiplier %gl_TessLevelOuter %gl_TessLevelInner %out_var_PN_POSITION9 + OpExecutionMode %MainHull Triangles + OpExecutionMode %MainHull SpacingFractionalOdd + OpExecutionMode %MainHull VertexOrderCw + OpExecutionMode %MainHull OutputVertices 3 + OpSource HLSL 600 + OpName %FPNTessellationHSToDS "FPNTessellationHSToDS" + OpMemberName %FPNTessellationHSToDS 0 "PassSpecificData" + OpMemberName %FPNTessellationHSToDS 1 "WorldPosition" + OpMemberName %FPNTessellationHSToDS 2 "DisplacementScale" + OpMemberName %FPNTessellationHSToDS 3 "TessellationMultiplier" + OpMemberName %FPNTessellationHSToDS 4 "WorldDisplacementMultiplier" + OpName %FHitProxyVSToDS "FHitProxyVSToDS" + OpMemberName %FHitProxyVSToDS 0 "FactoryInterpolants" + OpMemberName %FHitProxyVSToDS 1 "Position" + OpName %FVertexFactoryInterpolantsVSToDS "FVertexFactoryInterpolantsVSToDS" + OpMemberName %FVertexFactoryInterpolantsVSToDS 0 "InterpolantsVSToPS" + OpName %FVertexFactoryInterpolantsVSToPS "FVertexFactoryInterpolantsVSToPS" + OpMemberName %FVertexFactoryInterpolantsVSToPS 0 "TangentToWorld0" + OpMemberName %FVertexFactoryInterpolantsVSToPS 1 "TangentToWorld2" + OpMemberName %FVertexFactoryInterpolantsVSToPS 2 "Color" + OpMemberName %FVertexFactoryInterpolantsVSToPS 3 "TexCoords" + OpName %type_View "type.View" + OpMemberName %type_View 0 "View_TranslatedWorldToClip" + OpMemberName %type_View 1 "View_WorldToClip" + OpMemberName %type_View 2 "View_ClipToWorld" + OpMemberName %type_View 3 "View_TranslatedWorldToView" + OpMemberName %type_View 4 "View_ViewToTranslatedWorld" + OpMemberName %type_View 5 "View_TranslatedWorldToCameraView" + OpMemberName %type_View 6 "View_CameraViewToTranslatedWorld" + OpMemberName %type_View 7 "View_ViewToClip" + OpMemberName %type_View 8 "View_ViewToClipNoAA" + OpMemberName %type_View 9 "View_ClipToView" + OpMemberName %type_View 10 "View_ClipToTranslatedWorld" + OpMemberName %type_View 11 "View_SVPositionToTranslatedWorld" + OpMemberName %type_View 12 "View_ScreenToWorld" + OpMemberName %type_View 13 "View_ScreenToTranslatedWorld" + OpMemberName %type_View 14 "View_ViewForward" + OpMemberName %type_View 15 "PrePadding_View_908" + OpMemberName %type_View 16 "View_ViewUp" + OpMemberName %type_View 17 "PrePadding_View_924" + OpMemberName %type_View 18 "View_ViewRight" + OpMemberName %type_View 19 "PrePadding_View_940" + OpMemberName %type_View 20 "View_HMDViewNoRollUp" + OpMemberName %type_View 21 "PrePadding_View_956" + OpMemberName %type_View 22 "View_HMDViewNoRollRight" + OpMemberName %type_View 23 "PrePadding_View_972" + OpMemberName %type_View 24 "View_InvDeviceZToWorldZTransform" + OpMemberName %type_View 25 "View_ScreenPositionScaleBias" + OpMemberName %type_View 26 "View_WorldCameraOrigin" + OpMemberName %type_View 27 "PrePadding_View_1020" + OpMemberName %type_View 28 "View_TranslatedWorldCameraOrigin" + OpMemberName %type_View 29 "PrePadding_View_1036" + OpMemberName %type_View 30 "View_WorldViewOrigin" + OpMemberName %type_View 31 "PrePadding_View_1052" + OpMemberName %type_View 32 "View_PreViewTranslation" + OpMemberName %type_View 33 "PrePadding_View_1068" + OpMemberName %type_View 34 "View_PrevProjection" + OpMemberName %type_View 35 "View_PrevViewProj" + OpMemberName %type_View 36 "View_PrevViewRotationProj" + OpMemberName %type_View 37 "View_PrevViewToClip" + OpMemberName %type_View 38 "View_PrevClipToView" + OpMemberName %type_View 39 "View_PrevTranslatedWorldToClip" + OpMemberName %type_View 40 "View_PrevTranslatedWorldToView" + OpMemberName %type_View 41 "View_PrevViewToTranslatedWorld" + OpMemberName %type_View 42 "View_PrevTranslatedWorldToCameraView" + OpMemberName %type_View 43 "View_PrevCameraViewToTranslatedWorld" + OpMemberName %type_View 44 "View_PrevWorldCameraOrigin" + OpMemberName %type_View 45 "PrePadding_View_1724" + OpMemberName %type_View 46 "View_PrevWorldViewOrigin" + OpMemberName %type_View 47 "PrePadding_View_1740" + OpMemberName %type_View 48 "View_PrevPreViewTranslation" + OpMemberName %type_View 49 "PrePadding_View_1756" + OpMemberName %type_View 50 "View_PrevInvViewProj" + OpMemberName %type_View 51 "View_PrevScreenToTranslatedWorld" + OpMemberName %type_View 52 "View_ClipToPrevClip" + OpMemberName %type_View 53 "View_TemporalAAJitter" + OpMemberName %type_View 54 "View_GlobalClippingPlane" + OpMemberName %type_View 55 "View_FieldOfViewWideAngles" + OpMemberName %type_View 56 "View_PrevFieldOfViewWideAngles" + OpMemberName %type_View 57 "View_ViewRectMin" + OpMemberName %type_View 58 "View_ViewSizeAndInvSize" + OpMemberName %type_View 59 "View_BufferSizeAndInvSize" + OpMemberName %type_View 60 "View_BufferBilinearUVMinMax" + OpMemberName %type_View 61 "View_NumSceneColorMSAASamples" + OpMemberName %type_View 62 "View_PreExposure" + OpMemberName %type_View 63 "View_OneOverPreExposure" + OpMemberName %type_View 64 "PrePadding_View_2076" + OpMemberName %type_View 65 "View_DiffuseOverrideParameter" + OpMemberName %type_View 66 "View_SpecularOverrideParameter" + OpMemberName %type_View 67 "View_NormalOverrideParameter" + OpMemberName %type_View 68 "View_RoughnessOverrideParameter" + OpMemberName %type_View 69 "View_PrevFrameGameTime" + OpMemberName %type_View 70 "View_PrevFrameRealTime" + OpMemberName %type_View 71 "View_OutOfBoundsMask" + OpMemberName %type_View 72 "PrePadding_View_2148" + OpMemberName %type_View 73 "PrePadding_View_2152" + OpMemberName %type_View 74 "PrePadding_View_2156" + OpMemberName %type_View 75 "View_WorldCameraMovementSinceLastFrame" + OpMemberName %type_View 76 "View_CullingSign" + OpMemberName %type_View 77 "View_NearPlane" + OpMemberName %type_View 78 "View_AdaptiveTessellationFactor" + OpMemberName %type_View 79 "View_GameTime" + OpMemberName %type_View 80 "View_RealTime" + OpMemberName %type_View 81 "View_DeltaTime" + OpMemberName %type_View 82 "View_MaterialTextureMipBias" + OpMemberName %type_View 83 "View_MaterialTextureDerivativeMultiply" + OpMemberName %type_View 84 "View_Random" + OpMemberName %type_View 85 "View_FrameNumber" + OpMemberName %type_View 86 "View_StateFrameIndexMod8" + OpMemberName %type_View 87 "View_StateFrameIndex" + OpMemberName %type_View 88 "View_CameraCut" + OpMemberName %type_View 89 "View_UnlitViewmodeMask" + OpMemberName %type_View 90 "PrePadding_View_2228" + OpMemberName %type_View 91 "PrePadding_View_2232" + OpMemberName %type_View 92 "PrePadding_View_2236" + OpMemberName %type_View 93 "View_DirectionalLightColor" + OpMemberName %type_View 94 "View_DirectionalLightDirection" + OpMemberName %type_View 95 "PrePadding_View_2268" + OpMemberName %type_View 96 "View_TranslucencyLightingVolumeMin" + OpMemberName %type_View 97 "View_TranslucencyLightingVolumeInvSize" + OpMemberName %type_View 98 "View_TemporalAAParams" + OpMemberName %type_View 99 "View_CircleDOFParams" + OpMemberName %type_View 100 "View_DepthOfFieldSensorWidth" + OpMemberName %type_View 101 "View_DepthOfFieldFocalDistance" + OpMemberName %type_View 102 "View_DepthOfFieldScale" + OpMemberName %type_View 103 "View_DepthOfFieldFocalLength" + OpMemberName %type_View 104 "View_DepthOfFieldFocalRegion" + OpMemberName %type_View 105 "View_DepthOfFieldNearTransitionRegion" + OpMemberName %type_View 106 "View_DepthOfFieldFarTransitionRegion" + OpMemberName %type_View 107 "View_MotionBlurNormalizedToPixel" + OpMemberName %type_View 108 "View_bSubsurfacePostprocessEnabled" + OpMemberName %type_View 109 "View_GeneralPurposeTweak" + OpMemberName %type_View 110 "View_DemosaicVposOffset" + OpMemberName %type_View 111 "PrePadding_View_2412" + OpMemberName %type_View 112 "View_IndirectLightingColorScale" + OpMemberName %type_View 113 "View_HDR32bppEncodingMode" + OpMemberName %type_View 114 "View_AtmosphericFogSunDirection" + OpMemberName %type_View 115 "View_AtmosphericFogSunPower" + OpMemberName %type_View 116 "View_AtmosphericFogPower" + OpMemberName %type_View 117 "View_AtmosphericFogDensityScale" + OpMemberName %type_View 118 "View_AtmosphericFogDensityOffset" + OpMemberName %type_View 119 "View_AtmosphericFogGroundOffset" + OpMemberName %type_View 120 "View_AtmosphericFogDistanceScale" + OpMemberName %type_View 121 "View_AtmosphericFogAltitudeScale" + OpMemberName %type_View 122 "View_AtmosphericFogHeightScaleRayleigh" + OpMemberName %type_View 123 "View_AtmosphericFogStartDistance" + OpMemberName %type_View 124 "View_AtmosphericFogDistanceOffset" + OpMemberName %type_View 125 "View_AtmosphericFogSunDiscScale" + OpMemberName %type_View 126 "View_AtmosphericFogSunDiscHalfApexAngleRadian" + OpMemberName %type_View 127 "PrePadding_View_2492" + OpMemberName %type_View 128 "View_AtmosphericFogSunDiscLuminance" + OpMemberName %type_View 129 "View_AtmosphericFogRenderMask" + OpMemberName %type_View 130 "View_AtmosphericFogInscatterAltitudeSampleNum" + OpMemberName %type_View 131 "PrePadding_View_2520" + OpMemberName %type_View 132 "PrePadding_View_2524" + OpMemberName %type_View 133 "View_AtmosphericFogSunColor" + OpMemberName %type_View 134 "View_NormalCurvatureToRoughnessScaleBias" + OpMemberName %type_View 135 "View_RenderingReflectionCaptureMask" + OpMemberName %type_View 136 "View_AmbientCubemapTint" + OpMemberName %type_View 137 "View_AmbientCubemapIntensity" + OpMemberName %type_View 138 "View_SkyLightParameters" + OpMemberName %type_View 139 "PrePadding_View_2584" + OpMemberName %type_View 140 "PrePadding_View_2588" + OpMemberName %type_View 141 "View_SkyLightColor" + OpMemberName %type_View 142 "View_SkyIrradianceEnvironmentMap" + OpMemberName %type_View 143 "View_MobilePreviewMode" + OpMemberName %type_View 144 "View_HMDEyePaddingOffset" + OpMemberName %type_View 145 "View_ReflectionCubemapMaxMip" + OpMemberName %type_View 146 "View_ShowDecalsMask" + OpMemberName %type_View 147 "View_DistanceFieldAOSpecularOcclusionMode" + OpMemberName %type_View 148 "View_IndirectCapsuleSelfShadowingIntensity" + OpMemberName %type_View 149 "PrePadding_View_2744" + OpMemberName %type_View 150 "PrePadding_View_2748" + OpMemberName %type_View 151 "View_ReflectionEnvironmentRoughnessMixingScaleBiasAndLargestWeight" + OpMemberName %type_View 152 "View_StereoPassIndex" + OpMemberName %type_View 153 "View_GlobalVolumeCenterAndExtent" + OpMemberName %type_View 154 "View_GlobalVolumeWorldToUVAddAndMul" + OpMemberName %type_View 155 "View_GlobalVolumeDimension" + OpMemberName %type_View 156 "View_GlobalVolumeTexelSize" + OpMemberName %type_View 157 "View_MaxGlobalDistance" + OpMemberName %type_View 158 "PrePadding_View_2908" + OpMemberName %type_View 159 "View_CursorPosition" + OpMemberName %type_View 160 "View_bCheckerboardSubsurfaceProfileRendering" + OpMemberName %type_View 161 "PrePadding_View_2924" + OpMemberName %type_View 162 "View_VolumetricFogInvGridSize" + OpMemberName %type_View 163 "PrePadding_View_2940" + OpMemberName %type_View 164 "View_VolumetricFogGridZParams" + OpMemberName %type_View 165 "PrePadding_View_2956" + OpMemberName %type_View 166 "View_VolumetricFogSVPosToVolumeUV" + OpMemberName %type_View 167 "View_VolumetricFogMaxDistance" + OpMemberName %type_View 168 "PrePadding_View_2972" + OpMemberName %type_View 169 "View_VolumetricLightmapWorldToUVScale" + OpMemberName %type_View 170 "PrePadding_View_2988" + OpMemberName %type_View 171 "View_VolumetricLightmapWorldToUVAdd" + OpMemberName %type_View 172 "PrePadding_View_3004" + OpMemberName %type_View 173 "View_VolumetricLightmapIndirectionTextureSize" + OpMemberName %type_View 174 "View_VolumetricLightmapBrickSize" + OpMemberName %type_View 175 "View_VolumetricLightmapBrickTexelSize" + OpMemberName %type_View 176 "View_StereoIPD" + OpMemberName %type_View 177 "View_IndirectLightingCacheShowFlag" + OpMemberName %type_View 178 "View_EyeToPixelSpreadAngle" + OpName %View "View" + OpName %type_Primitive "type.Primitive" + OpMemberName %type_Primitive 0 "Primitive_LocalToWorld" + OpMemberName %type_Primitive 1 "Primitive_InvNonUniformScaleAndDeterminantSign" + OpMemberName %type_Primitive 2 "Primitive_ObjectWorldPositionAndRadius" + OpMemberName %type_Primitive 3 "Primitive_WorldToLocal" + OpMemberName %type_Primitive 4 "Primitive_PreviousLocalToWorld" + OpMemberName %type_Primitive 5 "Primitive_PreviousWorldToLocal" + OpMemberName %type_Primitive 6 "Primitive_ActorWorldPosition" + OpMemberName %type_Primitive 7 "Primitive_UseSingleSampleShadowFromStationaryLights" + OpMemberName %type_Primitive 8 "Primitive_ObjectBounds" + OpMemberName %type_Primitive 9 "Primitive_LpvBiasMultiplier" + OpMemberName %type_Primitive 10 "Primitive_DecalReceiverMask" + OpMemberName %type_Primitive 11 "Primitive_PerObjectGBufferData" + OpMemberName %type_Primitive 12 "Primitive_UseVolumetricLightmapShadowFromStationaryLights" + OpMemberName %type_Primitive 13 "Primitive_DrawsVelocity" + OpMemberName %type_Primitive 14 "Primitive_ObjectOrientation" + OpMemberName %type_Primitive 15 "Primitive_NonUniformScale" + OpMemberName %type_Primitive 16 "Primitive_LocalObjectBoundsMin" + OpMemberName %type_Primitive 17 "Primitive_LightingChannelMask" + OpMemberName %type_Primitive 18 "Primitive_LocalObjectBoundsMax" + OpMemberName %type_Primitive 19 "Primitive_LightmapDataIndex" + OpMemberName %type_Primitive 20 "Primitive_PreSkinnedLocalBounds" + OpMemberName %type_Primitive 21 "Primitive_SingleCaptureIndex" + OpMemberName %type_Primitive 22 "Primitive_OutputVelocity" + OpMemberName %type_Primitive 23 "PrePadding_Primitive_420" + OpMemberName %type_Primitive 24 "PrePadding_Primitive_424" + OpMemberName %type_Primitive 25 "PrePadding_Primitive_428" + OpMemberName %type_Primitive 26 "Primitive_CustomPrimitiveData" + OpName %Primitive "Primitive" + OpName %in_var_TEXCOORD10_centroid "in.var.TEXCOORD10_centroid" + OpName %in_var_TEXCOORD11_centroid "in.var.TEXCOORD11_centroid" + OpName %in_var_COLOR0 "in.var.COLOR0" + OpName %in_var_TEXCOORD0 "in.var.TEXCOORD0" + OpName %in_var_VS_To_DS_Position "in.var.VS_To_DS_Position" + OpName %out_var_TEXCOORD10_centroid "out.var.TEXCOORD10_centroid" + OpName %out_var_TEXCOORD11_centroid "out.var.TEXCOORD11_centroid" + OpName %out_var_COLOR0 "out.var.COLOR0" + OpName %out_var_TEXCOORD0 "out.var.TEXCOORD0" + OpName %out_var_VS_To_DS_Position "out.var.VS_To_DS_Position" + OpName %out_var_PN_POSITION "out.var.PN_POSITION" + OpName %out_var_PN_DisplacementScales "out.var.PN_DisplacementScales" + OpName %out_var_PN_TessellationMultiplier "out.var.PN_TessellationMultiplier" + OpName %out_var_PN_WorldDisplacementMultiplier "out.var.PN_WorldDisplacementMultiplier" + OpName %out_var_PN_POSITION9 "out.var.PN_POSITION9" + OpName %MainHull "MainHull" + OpName %param_var_I "param.var.I" + OpName %temp_var_hullMainRetVal "temp.var.hullMainRetVal" + OpName %if_merge "if.merge" + OpDecorateString %in_var_TEXCOORD10_centroid UserSemantic "TEXCOORD10_centroid" + OpDecorateString %in_var_TEXCOORD11_centroid UserSemantic "TEXCOORD11_centroid" + OpDecorateString %in_var_COLOR0 UserSemantic "COLOR0" + OpDecorateString %in_var_TEXCOORD0 UserSemantic "TEXCOORD0" + OpDecorateString %in_var_VS_To_DS_Position UserSemantic "VS_To_DS_Position" + OpDecorate %gl_InvocationID BuiltIn InvocationId + OpDecorateString %gl_InvocationID UserSemantic "SV_OutputControlPointID" + OpDecorateString %out_var_TEXCOORD10_centroid UserSemantic "TEXCOORD10_centroid" + OpDecorateString %out_var_TEXCOORD11_centroid UserSemantic "TEXCOORD11_centroid" + OpDecorateString %out_var_COLOR0 UserSemantic "COLOR0" + OpDecorateString %out_var_TEXCOORD0 UserSemantic "TEXCOORD0" + OpDecorateString %out_var_VS_To_DS_Position UserSemantic "VS_To_DS_Position" + OpDecorateString %out_var_PN_POSITION UserSemantic "PN_POSITION" + OpDecorateString %out_var_PN_DisplacementScales UserSemantic "PN_DisplacementScales" + OpDecorateString %out_var_PN_TessellationMultiplier UserSemantic "PN_TessellationMultiplier" + OpDecorateString %out_var_PN_WorldDisplacementMultiplier UserSemantic "PN_WorldDisplacementMultiplier" + OpDecorate %gl_TessLevelOuter BuiltIn TessLevelOuter + OpDecorateString %gl_TessLevelOuter UserSemantic "SV_TessFactor" + OpDecorate %gl_TessLevelOuter Patch + OpDecorate %gl_TessLevelInner BuiltIn TessLevelInner + OpDecorateString %gl_TessLevelInner UserSemantic "SV_InsideTessFactor" + OpDecorate %gl_TessLevelInner Patch + OpDecorateString %out_var_PN_POSITION9 UserSemantic "PN_POSITION9" + OpDecorate %out_var_PN_POSITION9 Patch + OpDecorate %in_var_TEXCOORD10_centroid Location 0 + OpDecorate %in_var_TEXCOORD11_centroid Location 1 + OpDecorate %in_var_COLOR0 Location 2 + OpDecorate %in_var_TEXCOORD0 Location 3 + OpDecorate %in_var_VS_To_DS_Position Location 5 + OpDecorate %out_var_COLOR0 Location 0 + OpDecorate %out_var_PN_DisplacementScales Location 1 + OpDecorate %out_var_PN_POSITION Location 2 + OpDecorate %out_var_PN_POSITION9 Location 5 + OpDecorate %out_var_PN_TessellationMultiplier Location 6 + OpDecorate %out_var_PN_WorldDisplacementMultiplier Location 7 + OpDecorate %out_var_TEXCOORD0 Location 8 + OpDecorate %out_var_TEXCOORD10_centroid Location 10 + OpDecorate %out_var_TEXCOORD11_centroid Location 11 + OpDecorate %out_var_VS_To_DS_Position Location 12 + OpDecorate %View DescriptorSet 0 + OpDecorate %View Binding 0 + OpDecorate %Primitive DescriptorSet 0 + OpDecorate %Primitive Binding 1 + OpDecorate %_arr_v4float_uint_2 ArrayStride 16 + OpDecorate %_arr_v4float_uint_7 ArrayStride 16 + OpDecorate %_arr_v4float_uint_4 ArrayStride 16 + OpMemberDecorate %type_View 0 Offset 0 + OpMemberDecorate %type_View 0 MatrixStride 16 + OpMemberDecorate %type_View 0 ColMajor + OpMemberDecorate %type_View 1 Offset 64 + OpMemberDecorate %type_View 1 MatrixStride 16 + OpMemberDecorate %type_View 1 ColMajor + OpMemberDecorate %type_View 2 Offset 128 + OpMemberDecorate %type_View 2 MatrixStride 16 + OpMemberDecorate %type_View 2 ColMajor + OpMemberDecorate %type_View 3 Offset 192 + OpMemberDecorate %type_View 3 MatrixStride 16 + OpMemberDecorate %type_View 3 ColMajor + OpMemberDecorate %type_View 4 Offset 256 + OpMemberDecorate %type_View 4 MatrixStride 16 + OpMemberDecorate %type_View 4 ColMajor + OpMemberDecorate %type_View 5 Offset 320 + OpMemberDecorate %type_View 5 MatrixStride 16 + OpMemberDecorate %type_View 5 ColMajor + OpMemberDecorate %type_View 6 Offset 384 + OpMemberDecorate %type_View 6 MatrixStride 16 + OpMemberDecorate %type_View 6 ColMajor + OpMemberDecorate %type_View 7 Offset 448 + OpMemberDecorate %type_View 7 MatrixStride 16 + OpMemberDecorate %type_View 7 ColMajor + OpMemberDecorate %type_View 8 Offset 512 + OpMemberDecorate %type_View 8 MatrixStride 16 + OpMemberDecorate %type_View 8 ColMajor + OpMemberDecorate %type_View 9 Offset 576 + OpMemberDecorate %type_View 9 MatrixStride 16 + OpMemberDecorate %type_View 9 ColMajor + OpMemberDecorate %type_View 10 Offset 640 + OpMemberDecorate %type_View 10 MatrixStride 16 + OpMemberDecorate %type_View 10 ColMajor + OpMemberDecorate %type_View 11 Offset 704 + OpMemberDecorate %type_View 11 MatrixStride 16 + OpMemberDecorate %type_View 11 ColMajor + OpMemberDecorate %type_View 12 Offset 768 + OpMemberDecorate %type_View 12 MatrixStride 16 + OpMemberDecorate %type_View 12 ColMajor + OpMemberDecorate %type_View 13 Offset 832 + OpMemberDecorate %type_View 13 MatrixStride 16 + OpMemberDecorate %type_View 13 ColMajor + OpMemberDecorate %type_View 14 Offset 896 + OpMemberDecorate %type_View 15 Offset 908 + OpMemberDecorate %type_View 16 Offset 912 + OpMemberDecorate %type_View 17 Offset 924 + OpMemberDecorate %type_View 18 Offset 928 + OpMemberDecorate %type_View 19 Offset 940 + OpMemberDecorate %type_View 20 Offset 944 + OpMemberDecorate %type_View 21 Offset 956 + OpMemberDecorate %type_View 22 Offset 960 + OpMemberDecorate %type_View 23 Offset 972 + OpMemberDecorate %type_View 24 Offset 976 + OpMemberDecorate %type_View 25 Offset 992 + OpMemberDecorate %type_View 26 Offset 1008 + OpMemberDecorate %type_View 27 Offset 1020 + OpMemberDecorate %type_View 28 Offset 1024 + OpMemberDecorate %type_View 29 Offset 1036 + OpMemberDecorate %type_View 30 Offset 1040 + OpMemberDecorate %type_View 31 Offset 1052 + OpMemberDecorate %type_View 32 Offset 1056 + OpMemberDecorate %type_View 33 Offset 1068 + OpMemberDecorate %type_View 34 Offset 1072 + OpMemberDecorate %type_View 34 MatrixStride 16 + OpMemberDecorate %type_View 34 ColMajor + OpMemberDecorate %type_View 35 Offset 1136 + OpMemberDecorate %type_View 35 MatrixStride 16 + OpMemberDecorate %type_View 35 ColMajor + OpMemberDecorate %type_View 36 Offset 1200 + OpMemberDecorate %type_View 36 MatrixStride 16 + OpMemberDecorate %type_View 36 ColMajor + OpMemberDecorate %type_View 37 Offset 1264 + OpMemberDecorate %type_View 37 MatrixStride 16 + OpMemberDecorate %type_View 37 ColMajor + OpMemberDecorate %type_View 38 Offset 1328 + OpMemberDecorate %type_View 38 MatrixStride 16 + OpMemberDecorate %type_View 38 ColMajor + OpMemberDecorate %type_View 39 Offset 1392 + OpMemberDecorate %type_View 39 MatrixStride 16 + OpMemberDecorate %type_View 39 ColMajor + OpMemberDecorate %type_View 40 Offset 1456 + OpMemberDecorate %type_View 40 MatrixStride 16 + OpMemberDecorate %type_View 40 ColMajor + OpMemberDecorate %type_View 41 Offset 1520 + OpMemberDecorate %type_View 41 MatrixStride 16 + OpMemberDecorate %type_View 41 ColMajor + OpMemberDecorate %type_View 42 Offset 1584 + OpMemberDecorate %type_View 42 MatrixStride 16 + OpMemberDecorate %type_View 42 ColMajor + OpMemberDecorate %type_View 43 Offset 1648 + OpMemberDecorate %type_View 43 MatrixStride 16 + OpMemberDecorate %type_View 43 ColMajor + OpMemberDecorate %type_View 44 Offset 1712 + OpMemberDecorate %type_View 45 Offset 1724 + OpMemberDecorate %type_View 46 Offset 1728 + OpMemberDecorate %type_View 47 Offset 1740 + OpMemberDecorate %type_View 48 Offset 1744 + OpMemberDecorate %type_View 49 Offset 1756 + OpMemberDecorate %type_View 50 Offset 1760 + OpMemberDecorate %type_View 50 MatrixStride 16 + OpMemberDecorate %type_View 50 ColMajor + OpMemberDecorate %type_View 51 Offset 1824 + OpMemberDecorate %type_View 51 MatrixStride 16 + OpMemberDecorate %type_View 51 ColMajor + OpMemberDecorate %type_View 52 Offset 1888 + OpMemberDecorate %type_View 52 MatrixStride 16 + OpMemberDecorate %type_View 52 ColMajor + OpMemberDecorate %type_View 53 Offset 1952 + OpMemberDecorate %type_View 54 Offset 1968 + OpMemberDecorate %type_View 55 Offset 1984 + OpMemberDecorate %type_View 56 Offset 1992 + OpMemberDecorate %type_View 57 Offset 2000 + OpMemberDecorate %type_View 58 Offset 2016 + OpMemberDecorate %type_View 59 Offset 2032 + OpMemberDecorate %type_View 60 Offset 2048 + OpMemberDecorate %type_View 61 Offset 2064 + OpMemberDecorate %type_View 62 Offset 2068 + OpMemberDecorate %type_View 63 Offset 2072 + OpMemberDecorate %type_View 64 Offset 2076 + OpMemberDecorate %type_View 65 Offset 2080 + OpMemberDecorate %type_View 66 Offset 2096 + OpMemberDecorate %type_View 67 Offset 2112 + OpMemberDecorate %type_View 68 Offset 2128 + OpMemberDecorate %type_View 69 Offset 2136 + OpMemberDecorate %type_View 70 Offset 2140 + OpMemberDecorate %type_View 71 Offset 2144 + OpMemberDecorate %type_View 72 Offset 2148 + OpMemberDecorate %type_View 73 Offset 2152 + OpMemberDecorate %type_View 74 Offset 2156 + OpMemberDecorate %type_View 75 Offset 2160 + OpMemberDecorate %type_View 76 Offset 2172 + OpMemberDecorate %type_View 77 Offset 2176 + OpMemberDecorate %type_View 78 Offset 2180 + OpMemberDecorate %type_View 79 Offset 2184 + OpMemberDecorate %type_View 80 Offset 2188 + OpMemberDecorate %type_View 81 Offset 2192 + OpMemberDecorate %type_View 82 Offset 2196 + OpMemberDecorate %type_View 83 Offset 2200 + OpMemberDecorate %type_View 84 Offset 2204 + OpMemberDecorate %type_View 85 Offset 2208 + OpMemberDecorate %type_View 86 Offset 2212 + OpMemberDecorate %type_View 87 Offset 2216 + OpMemberDecorate %type_View 88 Offset 2220 + OpMemberDecorate %type_View 89 Offset 2224 + OpMemberDecorate %type_View 90 Offset 2228 + OpMemberDecorate %type_View 91 Offset 2232 + OpMemberDecorate %type_View 92 Offset 2236 + OpMemberDecorate %type_View 93 Offset 2240 + OpMemberDecorate %type_View 94 Offset 2256 + OpMemberDecorate %type_View 95 Offset 2268 + OpMemberDecorate %type_View 96 Offset 2272 + OpMemberDecorate %type_View 97 Offset 2304 + OpMemberDecorate %type_View 98 Offset 2336 + OpMemberDecorate %type_View 99 Offset 2352 + OpMemberDecorate %type_View 100 Offset 2368 + OpMemberDecorate %type_View 101 Offset 2372 + OpMemberDecorate %type_View 102 Offset 2376 + OpMemberDecorate %type_View 103 Offset 2380 + OpMemberDecorate %type_View 104 Offset 2384 + OpMemberDecorate %type_View 105 Offset 2388 + OpMemberDecorate %type_View 106 Offset 2392 + OpMemberDecorate %type_View 107 Offset 2396 + OpMemberDecorate %type_View 108 Offset 2400 + OpMemberDecorate %type_View 109 Offset 2404 + OpMemberDecorate %type_View 110 Offset 2408 + OpMemberDecorate %type_View 111 Offset 2412 + OpMemberDecorate %type_View 112 Offset 2416 + OpMemberDecorate %type_View 113 Offset 2428 + OpMemberDecorate %type_View 114 Offset 2432 + OpMemberDecorate %type_View 115 Offset 2444 + OpMemberDecorate %type_View 116 Offset 2448 + OpMemberDecorate %type_View 117 Offset 2452 + OpMemberDecorate %type_View 118 Offset 2456 + OpMemberDecorate %type_View 119 Offset 2460 + OpMemberDecorate %type_View 120 Offset 2464 + OpMemberDecorate %type_View 121 Offset 2468 + OpMemberDecorate %type_View 122 Offset 2472 + OpMemberDecorate %type_View 123 Offset 2476 + OpMemberDecorate %type_View 124 Offset 2480 + OpMemberDecorate %type_View 125 Offset 2484 + OpMemberDecorate %type_View 126 Offset 2488 + OpMemberDecorate %type_View 127 Offset 2492 + OpMemberDecorate %type_View 128 Offset 2496 + OpMemberDecorate %type_View 129 Offset 2512 + OpMemberDecorate %type_View 130 Offset 2516 + OpMemberDecorate %type_View 131 Offset 2520 + OpMemberDecorate %type_View 132 Offset 2524 + OpMemberDecorate %type_View 133 Offset 2528 + OpMemberDecorate %type_View 134 Offset 2544 + OpMemberDecorate %type_View 135 Offset 2556 + OpMemberDecorate %type_View 136 Offset 2560 + OpMemberDecorate %type_View 137 Offset 2576 + OpMemberDecorate %type_View 138 Offset 2580 + OpMemberDecorate %type_View 139 Offset 2584 + OpMemberDecorate %type_View 140 Offset 2588 + OpMemberDecorate %type_View 141 Offset 2592 + OpMemberDecorate %type_View 142 Offset 2608 + OpMemberDecorate %type_View 143 Offset 2720 + OpMemberDecorate %type_View 144 Offset 2724 + OpMemberDecorate %type_View 145 Offset 2728 + OpMemberDecorate %type_View 146 Offset 2732 + OpMemberDecorate %type_View 147 Offset 2736 + OpMemberDecorate %type_View 148 Offset 2740 + OpMemberDecorate %type_View 149 Offset 2744 + OpMemberDecorate %type_View 150 Offset 2748 + OpMemberDecorate %type_View 151 Offset 2752 + OpMemberDecorate %type_View 152 Offset 2764 + OpMemberDecorate %type_View 153 Offset 2768 + OpMemberDecorate %type_View 154 Offset 2832 + OpMemberDecorate %type_View 155 Offset 2896 + OpMemberDecorate %type_View 156 Offset 2900 + OpMemberDecorate %type_View 157 Offset 2904 + OpMemberDecorate %type_View 158 Offset 2908 + OpMemberDecorate %type_View 159 Offset 2912 + OpMemberDecorate %type_View 160 Offset 2920 + OpMemberDecorate %type_View 161 Offset 2924 + OpMemberDecorate %type_View 162 Offset 2928 + OpMemberDecorate %type_View 163 Offset 2940 + OpMemberDecorate %type_View 164 Offset 2944 + OpMemberDecorate %type_View 165 Offset 2956 + OpMemberDecorate %type_View 166 Offset 2960 + OpMemberDecorate %type_View 167 Offset 2968 + OpMemberDecorate %type_View 168 Offset 2972 + OpMemberDecorate %type_View 169 Offset 2976 + OpMemberDecorate %type_View 170 Offset 2988 + OpMemberDecorate %type_View 171 Offset 2992 + OpMemberDecorate %type_View 172 Offset 3004 + OpMemberDecorate %type_View 173 Offset 3008 + OpMemberDecorate %type_View 174 Offset 3020 + OpMemberDecorate %type_View 175 Offset 3024 + OpMemberDecorate %type_View 176 Offset 3036 + OpMemberDecorate %type_View 177 Offset 3040 + OpMemberDecorate %type_View 178 Offset 3044 + OpDecorate %type_View Block + OpMemberDecorate %type_Primitive 0 Offset 0 + OpMemberDecorate %type_Primitive 0 MatrixStride 16 + OpMemberDecorate %type_Primitive 0 ColMajor + OpMemberDecorate %type_Primitive 1 Offset 64 + OpMemberDecorate %type_Primitive 2 Offset 80 + OpMemberDecorate %type_Primitive 3 Offset 96 + OpMemberDecorate %type_Primitive 3 MatrixStride 16 + OpMemberDecorate %type_Primitive 3 ColMajor + OpMemberDecorate %type_Primitive 4 Offset 160 + OpMemberDecorate %type_Primitive 4 MatrixStride 16 + OpMemberDecorate %type_Primitive 4 ColMajor + OpMemberDecorate %type_Primitive 5 Offset 224 + OpMemberDecorate %type_Primitive 5 MatrixStride 16 + OpMemberDecorate %type_Primitive 5 ColMajor + OpMemberDecorate %type_Primitive 6 Offset 288 + OpMemberDecorate %type_Primitive 7 Offset 300 + OpMemberDecorate %type_Primitive 8 Offset 304 + OpMemberDecorate %type_Primitive 9 Offset 316 + OpMemberDecorate %type_Primitive 10 Offset 320 + OpMemberDecorate %type_Primitive 11 Offset 324 + OpMemberDecorate %type_Primitive 12 Offset 328 + OpMemberDecorate %type_Primitive 13 Offset 332 + OpMemberDecorate %type_Primitive 14 Offset 336 + OpMemberDecorate %type_Primitive 15 Offset 352 + OpMemberDecorate %type_Primitive 16 Offset 368 + OpMemberDecorate %type_Primitive 17 Offset 380 + OpMemberDecorate %type_Primitive 18 Offset 384 + OpMemberDecorate %type_Primitive 19 Offset 396 + OpMemberDecorate %type_Primitive 20 Offset 400 + OpMemberDecorate %type_Primitive 21 Offset 412 + OpMemberDecorate %type_Primitive 22 Offset 416 + OpMemberDecorate %type_Primitive 23 Offset 420 + OpMemberDecorate %type_Primitive 24 Offset 424 + OpMemberDecorate %type_Primitive 25 Offset 428 + OpMemberDecorate %type_Primitive 26 Offset 432 + OpDecorate %type_Primitive Block + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 +%mat4v4float = OpTypeMatrix %v4float 4 + %v3float = OpTypeVector %float 3 + %v2float = OpTypeVector %float 2 + %int = OpTypeInt 32 1 + %uint = OpTypeInt 32 0 + %uint_2 = OpConstant %uint 2 + %uint_7 = OpConstant %uint 7 + %uint_4 = OpConstant %uint 4 + %v2int = OpTypeVector %int 2 + %uint_0 = OpConstant %uint 0 + %uint_1 = OpConstant %uint 1 + %uint_3 = OpConstant %uint 3 +%_arr_float_uint_3 = OpTypeArray %float %uint_3 + %int_1 = OpConstant %int 1 + %int_0 = OpConstant %int 0 + %int_2 = OpConstant %int 2 + %float_2 = OpConstant %float 2 + %54 = OpConstantComposite %v4float %float_2 %float_2 %float_2 %float_2 + %float_0_5 = OpConstant %float 0.5 + %int_3 = OpConstant %int 3 +%float_0_333000004 = OpConstant %float 0.333000004 + %float_1 = OpConstant %float 1 + %59 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1 + %float_15 = OpConstant %float 15 + %61 = OpConstantComposite %v4float %float_15 %float_15 %float_15 %float_15 +%_arr_v2float_uint_2 = OpTypeArray %v2float %uint_2 +%FVertexFactoryInterpolantsVSToPS = OpTypeStruct %v4float %v4float %v4float %_arr_v2float_uint_2 +%FVertexFactoryInterpolantsVSToDS = OpTypeStruct %FVertexFactoryInterpolantsVSToPS +%FHitProxyVSToDS = OpTypeStruct %FVertexFactoryInterpolantsVSToDS %v4float +%_arr_v4float_uint_3 = OpTypeArray %v4float %uint_3 +%FPNTessellationHSToDS = OpTypeStruct %FHitProxyVSToDS %_arr_v4float_uint_3 %v3float %float %float + %v3int = OpTypeVector %int 3 + %65 = OpConstantComposite %v3int %int_0 %int_0 %int_0 + %66 = OpConstantComposite %v3int %int_3 %int_3 %int_3 + %float_0 = OpConstant %float 0 + %68 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0 + %69 = OpConstantComposite %v3float %float_0_5 %float_0_5 %float_0_5 + %int_78 = OpConstant %int 78 + %int_15 = OpConstant %int 15 + %int_7 = OpConstant %int 7 + %int_28 = OpConstant %int 28 + %74 = OpConstantComposite %v3int %int_1 %int_1 %int_1 + %75 = OpConstantComposite %v3int %int_2 %int_2 %int_2 +%_arr_v4float_uint_2 = OpTypeArray %v4float %uint_2 +%_arr_v4float_uint_7 = OpTypeArray %v4float %uint_7 +%_arr_v4float_uint_4 = OpTypeArray %v4float %uint_4 + %type_View = OpTypeStruct %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %v3float %float %v3float %float %v3float %float %v3float %float %v3float %float %v4float %v4float %v3float %float %v3float %float %v3float %float %v3float %float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %v3float %float %v3float %float %v3float %float %mat4v4float %mat4v4float %mat4v4float %v4float %v4float %v2float %v2float %v4float %v4float %v4float %v4float %int %float %float %float %v4float %v4float %v4float %v2float %float %float %float %float %float %float %v3float %float %float %float %float %float %float %float %float %uint %uint %uint %uint %float %float %float %float %float %v4float %v3float %float %_arr_v4float_uint_2 %_arr_v4float_uint_2 %v4float %v4float %float %float %float %float %float %float %float %float %float %float %float %float %v3float %float %v3float %float %float %float %float %float %float %float %float %float %float %float %float %float %v4float %uint %uint %uint %uint %v4float %v3float %float %v4float %float %float %float %float %v4float %_arr_v4float_uint_7 %float %float %float %float %uint %float %float %float %v3float %int %_arr_v4float_uint_4 %_arr_v4float_uint_4 %float %float %float %float %v2int %float %float %v3float %float %v3float %float %v2float %float %float %v3float %float %v3float %float %v3float %float %v3float %float %float %float +%_ptr_Uniform_type_View = OpTypePointer Uniform %type_View +%type_Primitive = OpTypeStruct %mat4v4float %v4float %v4float %mat4v4float %mat4v4float %mat4v4float %v3float %float %v3float %float %float %float %float %float %v4float %v4float %v3float %uint %v3float %uint %v3float %int %uint %uint %uint %uint %_arr_v4float_uint_4 +%_ptr_Uniform_type_Primitive = OpTypePointer Uniform %type_Primitive + %uint_12 = OpConstant %uint 12 +%_arr_v4float_uint_12 = OpTypeArray %v4float %uint_12 +%_ptr_Input__arr_v4float_uint_12 = OpTypePointer Input %_arr_v4float_uint_12 +%_arr__arr_v2float_uint_2_uint_12 = OpTypeArray %_arr_v2float_uint_2 %uint_12 +%_ptr_Input__arr__arr_v2float_uint_2_uint_12 = OpTypePointer Input %_arr__arr_v2float_uint_2_uint_12 +%_ptr_Input_uint = OpTypePointer Input %uint +%_ptr_Output__arr_v4float_uint_3 = OpTypePointer Output %_arr_v4float_uint_3 +%_arr__arr_v2float_uint_2_uint_3 = OpTypeArray %_arr_v2float_uint_2 %uint_3 +%_ptr_Output__arr__arr_v2float_uint_2_uint_3 = OpTypePointer Output %_arr__arr_v2float_uint_2_uint_3 +%_arr__arr_v4float_uint_3_uint_3 = OpTypeArray %_arr_v4float_uint_3 %uint_3 +%_ptr_Output__arr__arr_v4float_uint_3_uint_3 = OpTypePointer Output %_arr__arr_v4float_uint_3_uint_3 +%_arr_v3float_uint_3 = OpTypeArray %v3float %uint_3 +%_ptr_Output__arr_v3float_uint_3 = OpTypePointer Output %_arr_v3float_uint_3 +%_ptr_Output__arr_float_uint_3 = OpTypePointer Output %_arr_float_uint_3 +%_arr_float_uint_4 = OpTypeArray %float %uint_4 +%_ptr_Output__arr_float_uint_4 = OpTypePointer Output %_arr_float_uint_4 +%_arr_float_uint_2 = OpTypeArray %float %uint_2 +%_ptr_Output__arr_float_uint_2 = OpTypePointer Output %_arr_float_uint_2 +%_ptr_Output_v4float = OpTypePointer Output %v4float + %void = OpTypeVoid + %98 = OpTypeFunction %void +%_arr_FHitProxyVSToDS_uint_12 = OpTypeArray %FHitProxyVSToDS %uint_12 +%_ptr_Function__arr_FHitProxyVSToDS_uint_12 = OpTypePointer Function %_arr_FHitProxyVSToDS_uint_12 +%_arr_FPNTessellationHSToDS_uint_3 = OpTypeArray %FPNTessellationHSToDS %uint_3 +%_ptr_Function__arr_FPNTessellationHSToDS_uint_3 = OpTypePointer Function %_arr_FPNTessellationHSToDS_uint_3 +%_ptr_Workgroup__arr_FPNTessellationHSToDS_uint_3 = OpTypePointer Workgroup %_arr_FPNTessellationHSToDS_uint_3 +%_ptr_Output__arr_v2float_uint_2 = OpTypePointer Output %_arr_v2float_uint_2 +%_ptr_Output_v3float = OpTypePointer Output %v3float +%_ptr_Output_float = OpTypePointer Output %float +%_ptr_Function_FPNTessellationHSToDS = OpTypePointer Function %FPNTessellationHSToDS +%_ptr_Workgroup_FPNTessellationHSToDS = OpTypePointer Workgroup %FPNTessellationHSToDS + %bool = OpTypeBool +%_ptr_Function_v4float = OpTypePointer Function %v4float +%_ptr_Function_float = OpTypePointer Function %float +%_ptr_Workgroup_v4float = OpTypePointer Workgroup %v4float +%_ptr_Workgroup_float = OpTypePointer Workgroup %float +%mat3v3float = OpTypeMatrix %v3float 3 +%_ptr_Function_FVertexFactoryInterpolantsVSToDS = OpTypePointer Function %FVertexFactoryInterpolantsVSToDS +%_ptr_Function_FHitProxyVSToDS = OpTypePointer Function %FHitProxyVSToDS + %v3bool = OpTypeVector %bool 3 +%_ptr_Uniform_float = OpTypePointer Uniform %float +%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float +%_ptr_Uniform_mat4v4float = OpTypePointer Uniform %mat4v4float +%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float + %View = OpVariable %_ptr_Uniform_type_View Uniform + %Primitive = OpVariable %_ptr_Uniform_type_Primitive Uniform +%in_var_TEXCOORD10_centroid = OpVariable %_ptr_Input__arr_v4float_uint_12 Input +%in_var_TEXCOORD11_centroid = OpVariable %_ptr_Input__arr_v4float_uint_12 Input +%in_var_COLOR0 = OpVariable %_ptr_Input__arr_v4float_uint_12 Input +%in_var_TEXCOORD0 = OpVariable %_ptr_Input__arr__arr_v2float_uint_2_uint_12 Input +%in_var_VS_To_DS_Position = OpVariable %_ptr_Input__arr_v4float_uint_12 Input +%gl_InvocationID = OpVariable %_ptr_Input_uint Input +%out_var_TEXCOORD10_centroid = OpVariable %_ptr_Output__arr_v4float_uint_3 Output +%out_var_TEXCOORD11_centroid = OpVariable %_ptr_Output__arr_v4float_uint_3 Output +%out_var_COLOR0 = OpVariable %_ptr_Output__arr_v4float_uint_3 Output +%out_var_TEXCOORD0 = OpVariable %_ptr_Output__arr__arr_v2float_uint_2_uint_3 Output +%out_var_VS_To_DS_Position = OpVariable %_ptr_Output__arr_v4float_uint_3 Output +%out_var_PN_POSITION = OpVariable %_ptr_Output__arr__arr_v4float_uint_3_uint_3 Output +%out_var_PN_DisplacementScales = OpVariable %_ptr_Output__arr_v3float_uint_3 Output +%out_var_PN_TessellationMultiplier = OpVariable %_ptr_Output__arr_float_uint_3 Output +%out_var_PN_WorldDisplacementMultiplier = OpVariable %_ptr_Output__arr_float_uint_3 Output +%gl_TessLevelOuter = OpVariable %_ptr_Output__arr_float_uint_4 Output +%gl_TessLevelInner = OpVariable %_ptr_Output__arr_float_uint_2 Output +%out_var_PN_POSITION9 = OpVariable %_ptr_Output_v4float Output +%float_0_333333343 = OpConstant %float 0.333333343 + %119 = OpConstantComposite %v4float %float_0_333333343 %float_0_333333343 %float_0_333333343 %float_0_333333343 + %120 = OpConstantComposite %v4float %float_0_5 %float_0_5 %float_0_5 %float_0_5 +%float_0_166666672 = OpConstant %float 0.166666672 + %122 = OpConstantComposite %v4float %float_0_166666672 %float_0_166666672 %float_0_166666672 %float_0_166666672 + %123 = OpUndef %v4float + +; XXX: Original asm used Function here, which is wrong. +; This patches the SPIR-V to be correct. +%temp_var_hullMainRetVal = OpVariable %_ptr_Workgroup__arr_FPNTessellationHSToDS_uint_3 Workgroup + + %MainHull = OpFunction %void None %98 + %124 = OpLabel +%param_var_I = OpVariable %_ptr_Function__arr_FHitProxyVSToDS_uint_12 Function + %125 = OpLoad %_arr_v4float_uint_12 %in_var_TEXCOORD10_centroid + %126 = OpLoad %_arr_v4float_uint_12 %in_var_TEXCOORD11_centroid + %127 = OpLoad %_arr_v4float_uint_12 %in_var_COLOR0 + %128 = OpLoad %_arr__arr_v2float_uint_2_uint_12 %in_var_TEXCOORD0 + %129 = OpCompositeExtract %v4float %125 0 + %130 = OpCompositeExtract %v4float %126 0 + %131 = OpCompositeExtract %v4float %127 0 + %132 = OpCompositeExtract %_arr_v2float_uint_2 %128 0 + %133 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToPS %129 %130 %131 %132 + %134 = OpCompositeExtract %v4float %125 1 + %135 = OpCompositeExtract %v4float %126 1 + %136 = OpCompositeExtract %v4float %127 1 + %137 = OpCompositeExtract %_arr_v2float_uint_2 %128 1 + %138 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToPS %134 %135 %136 %137 + %139 = OpCompositeExtract %v4float %125 2 + %140 = OpCompositeExtract %v4float %126 2 + %141 = OpCompositeExtract %v4float %127 2 + %142 = OpCompositeExtract %_arr_v2float_uint_2 %128 2 + %143 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToPS %139 %140 %141 %142 + %144 = OpCompositeExtract %v4float %125 3 + %145 = OpCompositeExtract %v4float %126 3 + %146 = OpCompositeExtract %v4float %127 3 + %147 = OpCompositeExtract %_arr_v2float_uint_2 %128 3 + %148 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToPS %144 %145 %146 %147 + %149 = OpCompositeExtract %v4float %125 4 + %150 = OpCompositeExtract %v4float %126 4 + %151 = OpCompositeExtract %v4float %127 4 + %152 = OpCompositeExtract %_arr_v2float_uint_2 %128 4 + %153 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToPS %149 %150 %151 %152 + %154 = OpCompositeExtract %v4float %125 5 + %155 = OpCompositeExtract %v4float %126 5 + %156 = OpCompositeExtract %v4float %127 5 + %157 = OpCompositeExtract %_arr_v2float_uint_2 %128 5 + %158 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToPS %154 %155 %156 %157 + %159 = OpCompositeExtract %v4float %125 6 + %160 = OpCompositeExtract %v4float %126 6 + %161 = OpCompositeExtract %v4float %127 6 + %162 = OpCompositeExtract %_arr_v2float_uint_2 %128 6 + %163 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToPS %159 %160 %161 %162 + %164 = OpCompositeExtract %v4float %125 7 + %165 = OpCompositeExtract %v4float %126 7 + %166 = OpCompositeExtract %v4float %127 7 + %167 = OpCompositeExtract %_arr_v2float_uint_2 %128 7 + %168 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToPS %164 %165 %166 %167 + %169 = OpCompositeExtract %v4float %125 8 + %170 = OpCompositeExtract %v4float %126 8 + %171 = OpCompositeExtract %v4float %127 8 + %172 = OpCompositeExtract %_arr_v2float_uint_2 %128 8 + %173 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToPS %169 %170 %171 %172 + %174 = OpCompositeExtract %v4float %125 9 + %175 = OpCompositeExtract %v4float %126 9 + %176 = OpCompositeExtract %v4float %127 9 + %177 = OpCompositeExtract %_arr_v2float_uint_2 %128 9 + %178 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToPS %174 %175 %176 %177 + %179 = OpCompositeExtract %v4float %125 10 + %180 = OpCompositeExtract %v4float %126 10 + %181 = OpCompositeExtract %v4float %127 10 + %182 = OpCompositeExtract %_arr_v2float_uint_2 %128 10 + %183 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToPS %179 %180 %181 %182 + %184 = OpCompositeExtract %v4float %125 11 + %185 = OpCompositeExtract %v4float %126 11 + %186 = OpCompositeExtract %v4float %127 11 + %187 = OpCompositeExtract %_arr_v2float_uint_2 %128 11 + %188 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToPS %184 %185 %186 %187 + %189 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToDS %133 + %190 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToDS %138 + %191 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToDS %143 + %192 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToDS %148 + %193 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToDS %153 + %194 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToDS %158 + %195 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToDS %163 + %196 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToDS %168 + %197 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToDS %173 + %198 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToDS %178 + %199 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToDS %183 + %200 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToDS %188 + %201 = OpLoad %_arr_v4float_uint_12 %in_var_VS_To_DS_Position + %202 = OpCompositeExtract %v4float %201 0 + %203 = OpCompositeConstruct %FHitProxyVSToDS %189 %202 + %204 = OpCompositeExtract %v4float %201 1 + %205 = OpCompositeConstruct %FHitProxyVSToDS %190 %204 + %206 = OpCompositeExtract %v4float %201 2 + %207 = OpCompositeConstruct %FHitProxyVSToDS %191 %206 + %208 = OpCompositeExtract %v4float %201 3 + %209 = OpCompositeConstruct %FHitProxyVSToDS %192 %208 + %210 = OpCompositeExtract %v4float %201 4 + %211 = OpCompositeConstruct %FHitProxyVSToDS %193 %210 + %212 = OpCompositeExtract %v4float %201 5 + %213 = OpCompositeConstruct %FHitProxyVSToDS %194 %212 + %214 = OpCompositeExtract %v4float %201 6 + %215 = OpCompositeConstruct %FHitProxyVSToDS %195 %214 + %216 = OpCompositeExtract %v4float %201 7 + %217 = OpCompositeConstruct %FHitProxyVSToDS %196 %216 + %218 = OpCompositeExtract %v4float %201 8 + %219 = OpCompositeConstruct %FHitProxyVSToDS %197 %218 + %220 = OpCompositeExtract %v4float %201 9 + %221 = OpCompositeConstruct %FHitProxyVSToDS %198 %220 + %222 = OpCompositeExtract %v4float %201 10 + %223 = OpCompositeConstruct %FHitProxyVSToDS %199 %222 + %224 = OpCompositeExtract %v4float %201 11 + %225 = OpCompositeConstruct %FHitProxyVSToDS %200 %224 + %226 = OpCompositeConstruct %_arr_FHitProxyVSToDS_uint_12 %203 %205 %207 %209 %211 %213 %215 %217 %219 %221 %223 %225 + OpStore %param_var_I %226 + %227 = OpLoad %uint %gl_InvocationID + %228 = OpAccessChain %_ptr_Function_FVertexFactoryInterpolantsVSToDS %param_var_I %227 %int_0 + %229 = OpLoad %FVertexFactoryInterpolantsVSToDS %228 + %230 = OpCompositeExtract %FVertexFactoryInterpolantsVSToPS %229 0 + %231 = OpCompositeExtract %v4float %230 0 + %232 = OpCompositeExtract %v4float %230 1 + %233 = OpVectorShuffle %v3float %231 %231 0 1 2 + %234 = OpVectorShuffle %v3float %232 %232 0 1 2 + %235 = OpExtInst %v3float %1 Cross %234 %233 + %236 = OpCompositeExtract %float %232 3 + %237 = OpCompositeConstruct %v3float %236 %236 %236 + %238 = OpFMul %v3float %235 %237 + %239 = OpCompositeConstruct %mat3v3float %233 %238 %234 + %240 = OpCompositeExtract %float %232 0 + %241 = OpCompositeExtract %float %232 1 + %242 = OpCompositeExtract %float %232 2 + %243 = OpCompositeConstruct %v4float %240 %241 %242 %float_0 + %244 = OpAccessChain %_ptr_Uniform_v4float %Primitive %int_15 + %245 = OpLoad %v4float %244 + %246 = OpVectorShuffle %v3float %245 %245 0 1 2 + %247 = OpVectorTimesMatrix %v3float %246 %239 + %248 = OpULessThan %bool %227 %uint_2 + %249 = OpIAdd %uint %227 %uint_1 + %250 = OpSelect %uint %248 %249 %uint_0 + %251 = OpIMul %uint %uint_2 %227 + %252 = OpIAdd %uint %uint_3 %251 + %253 = OpIAdd %uint %251 %uint_4 + %254 = OpAccessChain %_ptr_Function_FHitProxyVSToDS %param_var_I %227 + %255 = OpLoad %FHitProxyVSToDS %254 + %256 = OpAccessChain %_ptr_Function_v4float %param_var_I %227 %int_1 + %257 = OpLoad %v4float %256 + %258 = OpAccessChain %_ptr_Function_FVertexFactoryInterpolantsVSToDS %param_var_I %250 %int_0 + %259 = OpLoad %FVertexFactoryInterpolantsVSToDS %258 + %260 = OpCompositeExtract %FVertexFactoryInterpolantsVSToPS %259 0 + %261 = OpCompositeExtract %v4float %260 1 + %262 = OpCompositeExtract %float %261 0 + %263 = OpCompositeExtract %float %261 1 + %264 = OpCompositeExtract %float %261 2 + %265 = OpCompositeConstruct %v4float %262 %263 %264 %float_0 + %266 = OpAccessChain %_ptr_Function_FVertexFactoryInterpolantsVSToDS %param_var_I %252 %int_0 + %267 = OpLoad %FVertexFactoryInterpolantsVSToDS %266 + %268 = OpCompositeExtract %FVertexFactoryInterpolantsVSToPS %267 0 + %269 = OpCompositeExtract %v4float %268 1 + %270 = OpCompositeExtract %float %269 0 + %271 = OpCompositeExtract %float %269 1 + %272 = OpCompositeExtract %float %269 2 + %273 = OpCompositeConstruct %v4float %270 %271 %272 %float_0 + %274 = OpAccessChain %_ptr_Function_FVertexFactoryInterpolantsVSToDS %param_var_I %253 %int_0 + %275 = OpLoad %FVertexFactoryInterpolantsVSToDS %274 + %276 = OpCompositeExtract %FVertexFactoryInterpolantsVSToPS %275 0 + %277 = OpCompositeExtract %v4float %276 1 + %278 = OpCompositeExtract %float %277 0 + %279 = OpCompositeExtract %float %277 1 + %280 = OpCompositeExtract %float %277 2 + %281 = OpCompositeConstruct %v4float %278 %279 %280 %float_0 + %282 = OpLoad %v4float %256 + %283 = OpAccessChain %_ptr_Function_v4float %param_var_I %250 %int_1 + %284 = OpLoad %v4float %283 + %285 = OpFMul %v4float %54 %282 + %286 = OpFAdd %v4float %285 %284 + %287 = OpFSub %v4float %284 %282 + %288 = OpDot %float %287 %243 + %289 = OpCompositeConstruct %v4float %288 %288 %288 %288 + %290 = OpFMul %v4float %289 %243 + %291 = OpFSub %v4float %286 %290 + %292 = OpFMul %v4float %291 %119 + %293 = OpAccessChain %_ptr_Function_v4float %param_var_I %252 %int_1 + %294 = OpLoad %v4float %293 + %295 = OpAccessChain %_ptr_Function_v4float %param_var_I %253 %int_1 + %296 = OpLoad %v4float %295 + %297 = OpFMul %v4float %54 %294 + %298 = OpFAdd %v4float %297 %296 + %299 = OpFSub %v4float %296 %294 + %300 = OpDot %float %299 %273 + %301 = OpCompositeConstruct %v4float %300 %300 %300 %300 + %302 = OpFMul %v4float %301 %273 + %303 = OpFSub %v4float %298 %302 + %304 = OpFMul %v4float %303 %119 + %305 = OpFAdd %v4float %292 %304 + %306 = OpFMul %v4float %305 %120 + %307 = OpLoad %v4float %283 + %308 = OpLoad %v4float %256 + %309 = OpFMul %v4float %54 %307 + %310 = OpFAdd %v4float %309 %308 + %311 = OpFSub %v4float %308 %307 + %312 = OpDot %float %311 %265 + %313 = OpCompositeConstruct %v4float %312 %312 %312 %312 + %314 = OpFMul %v4float %313 %265 + %315 = OpFSub %v4float %310 %314 + %316 = OpFMul %v4float %315 %119 + %317 = OpLoad %v4float %295 + %318 = OpLoad %v4float %293 + %319 = OpFMul %v4float %54 %317 + %320 = OpFAdd %v4float %319 %318 + %321 = OpFSub %v4float %318 %317 + %322 = OpDot %float %321 %281 + %323 = OpCompositeConstruct %v4float %322 %322 %322 %322 + %324 = OpFMul %v4float %323 %281 + %325 = OpFSub %v4float %320 %324 + %326 = OpFMul %v4float %325 %119 + %327 = OpFAdd %v4float %316 %326 + %328 = OpFMul %v4float %327 %120 + %329 = OpCompositeConstruct %_arr_v4float_uint_3 %257 %306 %328 + %330 = OpCompositeConstruct %FPNTessellationHSToDS %255 %329 %247 %float_1 %float_1 + %331 = OpCompositeExtract %FVertexFactoryInterpolantsVSToDS %255 0 + %332 = OpCompositeExtract %FVertexFactoryInterpolantsVSToPS %331 0 + %333 = OpCompositeExtract %v4float %332 0 + %334 = OpAccessChain %_ptr_Output_v4float %out_var_TEXCOORD10_centroid %227 + OpStore %334 %333 + %335 = OpCompositeExtract %v4float %332 1 + %336 = OpAccessChain %_ptr_Output_v4float %out_var_TEXCOORD11_centroid %227 + OpStore %336 %335 + %337 = OpCompositeExtract %v4float %332 2 + %338 = OpAccessChain %_ptr_Output_v4float %out_var_COLOR0 %227 + OpStore %338 %337 + %339 = OpCompositeExtract %_arr_v2float_uint_2 %332 3 + %340 = OpAccessChain %_ptr_Output__arr_v2float_uint_2 %out_var_TEXCOORD0 %227 + OpStore %340 %339 + %341 = OpCompositeExtract %v4float %255 1 + %342 = OpAccessChain %_ptr_Output_v4float %out_var_VS_To_DS_Position %227 + OpStore %342 %341 + %343 = OpAccessChain %_ptr_Output__arr_v4float_uint_3 %out_var_PN_POSITION %227 + OpStore %343 %329 + %344 = OpAccessChain %_ptr_Output_v3float %out_var_PN_DisplacementScales %227 + OpStore %344 %247 + %345 = OpAccessChain %_ptr_Output_float %out_var_PN_TessellationMultiplier %227 + OpStore %345 %float_1 + %346 = OpAccessChain %_ptr_Output_float %out_var_PN_WorldDisplacementMultiplier %227 + OpStore %346 %float_1 + %347 = OpAccessChain %_ptr_Workgroup_FPNTessellationHSToDS %temp_var_hullMainRetVal %227 + OpStore %347 %330 + OpControlBarrier %uint_2 %uint_4 %uint_0 + %348 = OpIEqual %bool %227 %uint_0 + OpSelectionMerge %if_merge None + OpBranchConditional %348 %349 %if_merge + %349 = OpLabel + %350 = OpAccessChain %_ptr_Uniform_mat4v4float %View %int_0 + %351 = OpLoad %mat4v4float %350 + %352 = OpAccessChain %_ptr_Uniform_mat4v4float %View %int_7 + %353 = OpLoad %mat4v4float %352 + %354 = OpAccessChain %_ptr_Uniform_v3float %View %int_28 + %355 = OpLoad %v3float %354 + %356 = OpAccessChain %_ptr_Uniform_float %View %int_78 + %357 = OpLoad %float %356 + %358 = OpAccessChain %_ptr_Workgroup_v4float %temp_var_hullMainRetVal %uint_0 %int_1 %int_0 + %359 = OpLoad %v4float %358 + %360 = OpAccessChain %_ptr_Workgroup_v4float %temp_var_hullMainRetVal %uint_0 %int_1 %int_1 + %361 = OpLoad %v4float %360 + %362 = OpAccessChain %_ptr_Workgroup_v4float %temp_var_hullMainRetVal %uint_0 %int_1 %int_2 + %363 = OpLoad %v4float %362 + %364 = OpAccessChain %_ptr_Workgroup_v4float %temp_var_hullMainRetVal %uint_1 %int_1 %int_0 + %365 = OpLoad %v4float %364 + %366 = OpAccessChain %_ptr_Workgroup_v4float %temp_var_hullMainRetVal %uint_1 %int_1 %int_1 + %367 = OpLoad %v4float %366 + %368 = OpAccessChain %_ptr_Workgroup_v4float %temp_var_hullMainRetVal %uint_1 %int_1 %int_2 + %369 = OpLoad %v4float %368 + %370 = OpAccessChain %_ptr_Workgroup_v4float %temp_var_hullMainRetVal %uint_2 %int_1 %int_0 + %371 = OpLoad %v4float %370 + %372 = OpAccessChain %_ptr_Workgroup_v4float %temp_var_hullMainRetVal %uint_2 %int_1 %int_1 + %373 = OpLoad %v4float %372 + %374 = OpAccessChain %_ptr_Workgroup_v4float %temp_var_hullMainRetVal %uint_2 %int_1 %int_2 + %375 = OpLoad %v4float %374 + %376 = OpFAdd %v4float %361 %363 + %377 = OpFAdd %v4float %376 %367 + %378 = OpFAdd %v4float %377 %369 + %379 = OpFAdd %v4float %378 %373 + %380 = OpFAdd %v4float %379 %375 + %381 = OpFMul %v4float %380 %122 + %382 = OpFAdd %v4float %371 %365 + %383 = OpFAdd %v4float %382 %359 + %384 = OpFMul %v4float %383 %119 + %385 = OpFSub %v4float %381 %384 + %386 = OpFMul %v4float %385 %120 + %387 = OpFAdd %v4float %381 %386 + %388 = OpAccessChain %_ptr_Workgroup_float %temp_var_hullMainRetVal %uint_1 %int_3 + %389 = OpLoad %float %388 + %390 = OpAccessChain %_ptr_Workgroup_float %temp_var_hullMainRetVal %uint_2 %int_3 + %391 = OpLoad %float %390 + %392 = OpFAdd %float %389 %391 + %393 = OpFMul %float %float_0_5 %392 + %394 = OpCompositeInsert %v4float %393 %123 0 + %395 = OpLoad %float %390 + %396 = OpAccessChain %_ptr_Workgroup_float %temp_var_hullMainRetVal %uint_0 %int_3 + %397 = OpLoad %float %396 + %398 = OpFAdd %float %395 %397 + %399 = OpFMul %float %float_0_5 %398 + %400 = OpCompositeInsert %v4float %399 %394 1 + %401 = OpLoad %float %396 + %402 = OpLoad %float %388 + %403 = OpFAdd %float %401 %402 + %404 = OpFMul %float %float_0_5 %403 + %405 = OpCompositeInsert %v4float %404 %400 2 + %406 = OpLoad %float %396 + %407 = OpLoad %float %388 + %408 = OpFAdd %float %406 %407 + %409 = OpLoad %float %390 + %410 = OpFAdd %float %408 %409 + %411 = OpFMul %float %float_0_333000004 %410 + %412 = OpCompositeInsert %v4float %411 %405 3 + %413 = OpVectorShuffle %v3float %359 %359 0 1 2 + %414 = OpVectorShuffle %v3float %365 %365 0 1 2 + %415 = OpVectorShuffle %v3float %371 %371 0 1 2 + OpBranch %416 + %416 = OpLabel + OpLoopMerge %417 %418 None + OpBranch %419 + %419 = OpLabel + %420 = OpMatrixTimesVector %v4float %353 %68 + %421 = OpCompositeExtract %float %359 0 + %422 = OpCompositeExtract %float %359 1 + %423 = OpCompositeExtract %float %359 2 + %424 = OpCompositeConstruct %v4float %421 %422 %423 %float_1 + %425 = OpMatrixTimesVector %v4float %351 %424 + %426 = OpVectorShuffle %v3float %425 %425 0 1 2 + %427 = OpVectorShuffle %v3float %420 %420 0 1 2 + %428 = OpFSub %v3float %426 %427 + %429 = OpCompositeExtract %float %425 3 + %430 = OpCompositeExtract %float %420 3 + %431 = OpFAdd %float %429 %430 + %432 = OpCompositeConstruct %v3float %431 %431 %431 + %433 = OpFOrdLessThan %v3bool %428 %432 + %434 = OpSelect %v3int %433 %74 %65 + %435 = OpFAdd %v3float %426 %427 + %436 = OpFNegate %float %429 + %437 = OpFSub %float %436 %430 + %438 = OpCompositeConstruct %v3float %437 %437 %437 + %439 = OpFOrdGreaterThan %v3bool %435 %438 + %440 = OpSelect %v3int %439 %74 %65 + %441 = OpIMul %v3int %75 %440 + %442 = OpIAdd %v3int %434 %441 + %443 = OpCompositeExtract %float %365 0 + %444 = OpCompositeExtract %float %365 1 + %445 = OpCompositeExtract %float %365 2 + %446 = OpCompositeConstruct %v4float %443 %444 %445 %float_1 + %447 = OpMatrixTimesVector %v4float %351 %446 + %448 = OpVectorShuffle %v3float %447 %447 0 1 2 + %449 = OpFSub %v3float %448 %427 + %450 = OpCompositeExtract %float %447 3 + %451 = OpFAdd %float %450 %430 + %452 = OpCompositeConstruct %v3float %451 %451 %451 + %453 = OpFOrdLessThan %v3bool %449 %452 + %454 = OpSelect %v3int %453 %74 %65 + %455 = OpFAdd %v3float %448 %427 + %456 = OpFNegate %float %450 + %457 = OpFSub %float %456 %430 + %458 = OpCompositeConstruct %v3float %457 %457 %457 + %459 = OpFOrdGreaterThan %v3bool %455 %458 + %460 = OpSelect %v3int %459 %74 %65 + %461 = OpIMul %v3int %75 %460 + %462 = OpIAdd %v3int %454 %461 + %463 = OpBitwiseOr %v3int %442 %462 + %464 = OpCompositeExtract %float %371 0 + %465 = OpCompositeExtract %float %371 1 + %466 = OpCompositeExtract %float %371 2 + %467 = OpCompositeConstruct %v4float %464 %465 %466 %float_1 + %468 = OpMatrixTimesVector %v4float %351 %467 + %469 = OpVectorShuffle %v3float %468 %468 0 1 2 + %470 = OpFSub %v3float %469 %427 + %471 = OpCompositeExtract %float %468 3 + %472 = OpFAdd %float %471 %430 + %473 = OpCompositeConstruct %v3float %472 %472 %472 + %474 = OpFOrdLessThan %v3bool %470 %473 + %475 = OpSelect %v3int %474 %74 %65 + %476 = OpFAdd %v3float %469 %427 + %477 = OpFNegate %float %471 + %478 = OpFSub %float %477 %430 + %479 = OpCompositeConstruct %v3float %478 %478 %478 + %480 = OpFOrdGreaterThan %v3bool %476 %479 + %481 = OpSelect %v3int %480 %74 %65 + %482 = OpIMul %v3int %75 %481 + %483 = OpIAdd %v3int %475 %482 + %484 = OpBitwiseOr %v3int %463 %483 + %485 = OpINotEqual %v3bool %484 %66 + %486 = OpAny %bool %485 + OpSelectionMerge %487 None + OpBranchConditional %486 %488 %487 + %488 = OpLabel + OpBranch %417 + %487 = OpLabel + %489 = OpFSub %v3float %413 %414 + %490 = OpFSub %v3float %414 %415 + %491 = OpFSub %v3float %415 %413 + %492 = OpFAdd %v3float %413 %414 + %493 = OpFMul %v3float %69 %492 + %494 = OpFSub %v3float %493 %355 + %495 = OpFAdd %v3float %414 %415 + %496 = OpFMul %v3float %69 %495 + %497 = OpFSub %v3float %496 %355 + %498 = OpFAdd %v3float %415 %413 + %499 = OpFMul %v3float %69 %498 + %500 = OpFSub %v3float %499 %355 + %501 = OpDot %float %490 %490 + %502 = OpDot %float %497 %497 + %503 = OpFDiv %float %501 %502 + %504 = OpExtInst %float %1 Sqrt %503 + %505 = OpDot %float %491 %491 + %506 = OpDot %float %500 %500 + %507 = OpFDiv %float %505 %506 + %508 = OpExtInst %float %1 Sqrt %507 + %509 = OpDot %float %489 %489 + %510 = OpDot %float %494 %494 + %511 = OpFDiv %float %509 %510 + %512 = OpExtInst %float %1 Sqrt %511 + %513 = OpCompositeConstruct %v4float %504 %508 %512 %float_1 + %514 = OpFAdd %float %504 %508 + %515 = OpFAdd %float %514 %512 + %516 = OpFMul %float %float_0_333000004 %515 + %517 = OpCompositeInsert %v4float %516 %513 3 + %518 = OpCompositeConstruct %v4float %357 %357 %357 %357 + %519 = OpFMul %v4float %518 %517 + OpBranch %417 + %418 = OpLabel + OpBranch %416 + %417 = OpLabel + %520 = OpPhi %v4float %68 %488 %519 %487 + %521 = OpFMul %v4float %412 %520 + %522 = OpExtInst %v4float %1 FClamp %521 %59 %61 + %523 = OpCompositeExtract %float %522 0 + %524 = OpCompositeExtract %float %522 1 + %525 = OpCompositeExtract %float %522 2 + %526 = OpCompositeExtract %float %522 3 + %527 = OpAccessChain %_ptr_Output_float %gl_TessLevelOuter %uint_0 + OpStore %527 %523 + %528 = OpAccessChain %_ptr_Output_float %gl_TessLevelOuter %uint_1 + OpStore %528 %524 + %529 = OpAccessChain %_ptr_Output_float %gl_TessLevelOuter %uint_2 + OpStore %529 %525 + %530 = OpAccessChain %_ptr_Output_float %gl_TessLevelInner %uint_0 + OpStore %530 %526 + OpStore %out_var_PN_POSITION9 %387 + OpBranch %if_merge + %if_merge = OpLabel + OpReturn + OpFunctionEnd diff --git a/third_party/spirv-cross/shaders-ue4/asm/tesc/tess-factor-must-be-threadgroup.asm.tesc b/third_party/spirv-cross/shaders-ue4/asm/tesc/tess-factor-must-be-threadgroup.asm.tesc new file mode 100644 index 0000000000..98216e7924 --- /dev/null +++ b/third_party/spirv-cross/shaders-ue4/asm/tesc/tess-factor-must-be-threadgroup.asm.tesc @@ -0,0 +1,352 @@ +; SPIR-V +; Version: 1.0 +; Generator: Google spiregg; 0 +; Bound: 179 +; Schema: 0 + OpCapability Tessellation + OpCapability SampledBuffer + OpExtension "SPV_GOOGLE_hlsl_functionality1" + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint TessellationControl %MainHull "main" %in_var_TEXCOORD10_centroid %in_var_TEXCOORD11_centroid %in_var_VS_To_DS_Position %gl_InvocationID %out_var_TEXCOORD10_centroid %out_var_TEXCOORD11_centroid %out_var_VS_To_DS_Position %out_var_Flat_DisplacementScales %out_var_Flat_TessellationMultiplier %out_var_Flat_WorldDisplacementMultiplier %gl_TessLevelOuter %gl_TessLevelInner + OpExecutionMode %MainHull Triangles + OpExecutionMode %MainHull SpacingFractionalOdd + OpExecutionMode %MainHull VertexOrderCw + OpExecutionMode %MainHull OutputVertices 3 + OpSource HLSL 600 + OpName %FFlatTessellationHSToDS "FFlatTessellationHSToDS" + OpMemberName %FFlatTessellationHSToDS 0 "PassSpecificData" + OpMemberName %FFlatTessellationHSToDS 1 "DisplacementScale" + OpMemberName %FFlatTessellationHSToDS 2 "TessellationMultiplier" + OpMemberName %FFlatTessellationHSToDS 3 "WorldDisplacementMultiplier" + OpName %FBasePassVSToDS "FBasePassVSToDS" + OpMemberName %FBasePassVSToDS 0 "FactoryInterpolants" + OpMemberName %FBasePassVSToDS 1 "BasePassInterpolants" + OpMemberName %FBasePassVSToDS 2 "Position" + OpName %FVertexFactoryInterpolantsVSToDS "FVertexFactoryInterpolantsVSToDS" + OpMemberName %FVertexFactoryInterpolantsVSToDS 0 "InterpolantsVSToPS" + OpName %FVertexFactoryInterpolantsVSToPS "FVertexFactoryInterpolantsVSToPS" + OpMemberName %FVertexFactoryInterpolantsVSToPS 0 "TangentToWorld0" + OpMemberName %FVertexFactoryInterpolantsVSToPS 1 "TangentToWorld2" + OpName %FBasePassInterpolantsVSToDS "FBasePassInterpolantsVSToDS" + OpName %FSharedBasePassInterpolants "FSharedBasePassInterpolants" + OpName %type_Primitive "type.Primitive" + OpMemberName %type_Primitive 0 "Primitive_LocalToWorld" + OpMemberName %type_Primitive 1 "Primitive_InvNonUniformScaleAndDeterminantSign" + OpMemberName %type_Primitive 2 "Primitive_ObjectWorldPositionAndRadius" + OpMemberName %type_Primitive 3 "Primitive_WorldToLocal" + OpMemberName %type_Primitive 4 "Primitive_PreviousLocalToWorld" + OpMemberName %type_Primitive 5 "Primitive_PreviousWorldToLocal" + OpMemberName %type_Primitive 6 "Primitive_ActorWorldPosition" + OpMemberName %type_Primitive 7 "Primitive_UseSingleSampleShadowFromStationaryLights" + OpMemberName %type_Primitive 8 "Primitive_ObjectBounds" + OpMemberName %type_Primitive 9 "Primitive_LpvBiasMultiplier" + OpMemberName %type_Primitive 10 "Primitive_DecalReceiverMask" + OpMemberName %type_Primitive 11 "Primitive_PerObjectGBufferData" + OpMemberName %type_Primitive 12 "Primitive_UseVolumetricLightmapShadowFromStationaryLights" + OpMemberName %type_Primitive 13 "Primitive_DrawsVelocity" + OpMemberName %type_Primitive 14 "Primitive_ObjectOrientation" + OpMemberName %type_Primitive 15 "Primitive_NonUniformScale" + OpMemberName %type_Primitive 16 "Primitive_LocalObjectBoundsMin" + OpMemberName %type_Primitive 17 "Primitive_LightingChannelMask" + OpMemberName %type_Primitive 18 "Primitive_LocalObjectBoundsMax" + OpMemberName %type_Primitive 19 "Primitive_LightmapDataIndex" + OpMemberName %type_Primitive 20 "Primitive_PreSkinnedLocalBounds" + OpMemberName %type_Primitive 21 "Primitive_SingleCaptureIndex" + OpMemberName %type_Primitive 22 "Primitive_OutputVelocity" + OpMemberName %type_Primitive 23 "PrePadding_Primitive_420" + OpMemberName %type_Primitive 24 "PrePadding_Primitive_424" + OpMemberName %type_Primitive 25 "PrePadding_Primitive_428" + OpMemberName %type_Primitive 26 "Primitive_CustomPrimitiveData" + OpName %Primitive "Primitive" + OpName %type_Material "type.Material" + OpMemberName %type_Material 0 "Material_VectorExpressions" + OpMemberName %type_Material 1 "Material_ScalarExpressions" + OpName %Material "Material" + OpName %in_var_TEXCOORD10_centroid "in.var.TEXCOORD10_centroid" + OpName %in_var_TEXCOORD11_centroid "in.var.TEXCOORD11_centroid" + OpName %in_var_VS_To_DS_Position "in.var.VS_To_DS_Position" + OpName %out_var_TEXCOORD10_centroid "out.var.TEXCOORD10_centroid" + OpName %out_var_TEXCOORD11_centroid "out.var.TEXCOORD11_centroid" + OpName %out_var_VS_To_DS_Position "out.var.VS_To_DS_Position" + OpName %out_var_Flat_DisplacementScales "out.var.Flat_DisplacementScales" + OpName %out_var_Flat_TessellationMultiplier "out.var.Flat_TessellationMultiplier" + OpName %out_var_Flat_WorldDisplacementMultiplier "out.var.Flat_WorldDisplacementMultiplier" + OpName %MainHull "MainHull" + OpName %param_var_I "param.var.I" + OpName %temp_var_hullMainRetVal "temp.var.hullMainRetVal" + OpName %if_merge "if.merge" + OpDecorateString %in_var_TEXCOORD10_centroid UserSemantic "TEXCOORD10_centroid" + OpDecorateString %in_var_TEXCOORD11_centroid UserSemantic "TEXCOORD11_centroid" + OpDecorateString %in_var_VS_To_DS_Position UserSemantic "VS_To_DS_Position" + OpDecorate %gl_InvocationID BuiltIn InvocationId + OpDecorateString %gl_InvocationID UserSemantic "SV_OutputControlPointID" + OpDecorateString %out_var_TEXCOORD10_centroid UserSemantic "TEXCOORD10_centroid" + OpDecorateString %out_var_TEXCOORD11_centroid UserSemantic "TEXCOORD11_centroid" + OpDecorateString %out_var_VS_To_DS_Position UserSemantic "VS_To_DS_Position" + OpDecorateString %out_var_Flat_DisplacementScales UserSemantic "Flat_DisplacementScales" + OpDecorateString %out_var_Flat_TessellationMultiplier UserSemantic "Flat_TessellationMultiplier" + OpDecorateString %out_var_Flat_WorldDisplacementMultiplier UserSemantic "Flat_WorldDisplacementMultiplier" + OpDecorate %gl_TessLevelOuter BuiltIn TessLevelOuter + OpDecorateString %gl_TessLevelOuter UserSemantic "SV_TessFactor" + OpDecorate %gl_TessLevelOuter Patch + OpDecorate %gl_TessLevelInner BuiltIn TessLevelInner + OpDecorateString %gl_TessLevelInner UserSemantic "SV_InsideTessFactor" + OpDecorate %gl_TessLevelInner Patch + OpDecorate %in_var_TEXCOORD10_centroid Location 0 + OpDecorate %in_var_TEXCOORD11_centroid Location 1 + OpDecorate %in_var_VS_To_DS_Position Location 2 + OpDecorate %out_var_Flat_DisplacementScales Location 0 + OpDecorate %out_var_Flat_TessellationMultiplier Location 1 + OpDecorate %out_var_Flat_WorldDisplacementMultiplier Location 2 + OpDecorate %out_var_TEXCOORD10_centroid Location 3 + OpDecorate %out_var_TEXCOORD11_centroid Location 4 + OpDecorate %out_var_VS_To_DS_Position Location 5 + OpDecorate %Primitive DescriptorSet 0 + OpDecorate %Primitive Binding 0 + OpDecorate %Material DescriptorSet 0 + OpDecorate %Material Binding 1 + OpDecorate %_arr_v4float_uint_4 ArrayStride 16 + OpMemberDecorate %type_Primitive 0 Offset 0 + OpMemberDecorate %type_Primitive 0 MatrixStride 16 + OpMemberDecorate %type_Primitive 0 ColMajor + OpMemberDecorate %type_Primitive 1 Offset 64 + OpMemberDecorate %type_Primitive 2 Offset 80 + OpMemberDecorate %type_Primitive 3 Offset 96 + OpMemberDecorate %type_Primitive 3 MatrixStride 16 + OpMemberDecorate %type_Primitive 3 ColMajor + OpMemberDecorate %type_Primitive 4 Offset 160 + OpMemberDecorate %type_Primitive 4 MatrixStride 16 + OpMemberDecorate %type_Primitive 4 ColMajor + OpMemberDecorate %type_Primitive 5 Offset 224 + OpMemberDecorate %type_Primitive 5 MatrixStride 16 + OpMemberDecorate %type_Primitive 5 ColMajor + OpMemberDecorate %type_Primitive 6 Offset 288 + OpMemberDecorate %type_Primitive 7 Offset 300 + OpMemberDecorate %type_Primitive 8 Offset 304 + OpMemberDecorate %type_Primitive 9 Offset 316 + OpMemberDecorate %type_Primitive 10 Offset 320 + OpMemberDecorate %type_Primitive 11 Offset 324 + OpMemberDecorate %type_Primitive 12 Offset 328 + OpMemberDecorate %type_Primitive 13 Offset 332 + OpMemberDecorate %type_Primitive 14 Offset 336 + OpMemberDecorate %type_Primitive 15 Offset 352 + OpMemberDecorate %type_Primitive 16 Offset 368 + OpMemberDecorate %type_Primitive 17 Offset 380 + OpMemberDecorate %type_Primitive 18 Offset 384 + OpMemberDecorate %type_Primitive 19 Offset 396 + OpMemberDecorate %type_Primitive 20 Offset 400 + OpMemberDecorate %type_Primitive 21 Offset 412 + OpMemberDecorate %type_Primitive 22 Offset 416 + OpMemberDecorate %type_Primitive 23 Offset 420 + OpMemberDecorate %type_Primitive 24 Offset 424 + OpMemberDecorate %type_Primitive 25 Offset 428 + OpMemberDecorate %type_Primitive 26 Offset 432 + OpDecorate %type_Primitive Block + OpDecorate %_arr_v4float_uint_3 ArrayStride 16 + OpDecorate %_arr_v4float_uint_1 ArrayStride 16 + OpMemberDecorate %type_Material 0 Offset 0 + OpMemberDecorate %type_Material 1 Offset 48 + OpDecorate %type_Material Block + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 +%mat4v4float = OpTypeMatrix %v4float 4 + %v3float = OpTypeVector %float 3 + %int = OpTypeInt 32 1 + %uint = OpTypeInt 32 0 + %uint_2 = OpConstant %uint 2 + %uint_4 = OpConstant %uint 4 + %uint_0 = OpConstant %uint 0 + %uint_1 = OpConstant %uint 1 + %uint_3 = OpConstant %uint 3 +%_arr_float_uint_3 = OpTypeArray %float %uint_3 + %int_0 = OpConstant %int 0 + %int_2 = OpConstant %int 2 + %float_0_5 = OpConstant %float 0.5 + %int_1 = OpConstant %int 1 +%float_0_333000004 = OpConstant %float 0.333000004 + %float_1 = OpConstant %float 1 + %49 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1 + %float_15 = OpConstant %float 15 + %51 = OpConstantComposite %v4float %float_15 %float_15 %float_15 %float_15 +%FVertexFactoryInterpolantsVSToPS = OpTypeStruct %v4float %v4float +%FVertexFactoryInterpolantsVSToDS = OpTypeStruct %FVertexFactoryInterpolantsVSToPS +%FSharedBasePassInterpolants = OpTypeStruct +%FBasePassInterpolantsVSToDS = OpTypeStruct %FSharedBasePassInterpolants +%FBasePassVSToDS = OpTypeStruct %FVertexFactoryInterpolantsVSToDS %FBasePassInterpolantsVSToDS %v4float +%FFlatTessellationHSToDS = OpTypeStruct %FBasePassVSToDS %v3float %float %float + %int_15 = OpConstant %int 15 +%_arr_v4float_uint_4 = OpTypeArray %v4float %uint_4 +%type_Primitive = OpTypeStruct %mat4v4float %v4float %v4float %mat4v4float %mat4v4float %mat4v4float %v3float %float %v3float %float %float %float %float %float %v4float %v4float %v3float %uint %v3float %uint %v3float %int %uint %uint %uint %uint %_arr_v4float_uint_4 +%_ptr_Uniform_type_Primitive = OpTypePointer Uniform %type_Primitive +%_arr_v4float_uint_3 = OpTypeArray %v4float %uint_3 +%_arr_v4float_uint_1 = OpTypeArray %v4float %uint_1 +%type_Material = OpTypeStruct %_arr_v4float_uint_3 %_arr_v4float_uint_1 +%_ptr_Uniform_type_Material = OpTypePointer Uniform %type_Material +%_arr_v4float_uint_3_0 = OpTypeArray %v4float %uint_3 +%_ptr_Input__arr_v4float_uint_3_0 = OpTypePointer Input %_arr_v4float_uint_3_0 +%_ptr_Input_uint = OpTypePointer Input %uint +%_ptr_Output__arr_v4float_uint_3_0 = OpTypePointer Output %_arr_v4float_uint_3_0 +%_arr_v3float_uint_3 = OpTypeArray %v3float %uint_3 +%_ptr_Output__arr_v3float_uint_3 = OpTypePointer Output %_arr_v3float_uint_3 +%_ptr_Output__arr_float_uint_3 = OpTypePointer Output %_arr_float_uint_3 +%_arr_float_uint_4 = OpTypeArray %float %uint_4 +%_ptr_Output__arr_float_uint_4 = OpTypePointer Output %_arr_float_uint_4 +%_arr_float_uint_2 = OpTypeArray %float %uint_2 +%_ptr_Output__arr_float_uint_2 = OpTypePointer Output %_arr_float_uint_2 + %void = OpTypeVoid + %67 = OpTypeFunction %void +%_arr_FBasePassVSToDS_uint_3 = OpTypeArray %FBasePassVSToDS %uint_3 +%_ptr_Function__arr_FBasePassVSToDS_uint_3 = OpTypePointer Function %_arr_FBasePassVSToDS_uint_3 +%_arr_FFlatTessellationHSToDS_uint_3 = OpTypeArray %FFlatTessellationHSToDS %uint_3 +%_ptr_Function__arr_FFlatTessellationHSToDS_uint_3 = OpTypePointer Function %_arr_FFlatTessellationHSToDS_uint_3 +%_ptr_Workgroup__arr_FFlatTessellationHSToDS_uint_3 = OpTypePointer Workgroup %_arr_FFlatTessellationHSToDS_uint_3 +%_ptr_Output_v4float = OpTypePointer Output %v4float +%_ptr_Output_v3float = OpTypePointer Output %v3float +%_ptr_Output_float = OpTypePointer Output %float +%_ptr_Function_FFlatTessellationHSToDS = OpTypePointer Function %FFlatTessellationHSToDS +%_ptr_Workgroup_FFlatTessellationHSToDS = OpTypePointer Workgroup %FFlatTessellationHSToDS + %bool = OpTypeBool +%_ptr_Function_float = OpTypePointer Function %float +%_ptr_Workgroup_float = OpTypePointer Workgroup %float +%mat3v3float = OpTypeMatrix %v3float 3 +%_ptr_Function_FVertexFactoryInterpolantsVSToDS = OpTypePointer Function %FVertexFactoryInterpolantsVSToDS +%_ptr_Function_FBasePassVSToDS = OpTypePointer Function %FBasePassVSToDS +%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float +%_ptr_Uniform_float = OpTypePointer Uniform %float + %Primitive = OpVariable %_ptr_Uniform_type_Primitive Uniform + %Material = OpVariable %_ptr_Uniform_type_Material Uniform +%in_var_TEXCOORD10_centroid = OpVariable %_ptr_Input__arr_v4float_uint_3_0 Input +%in_var_TEXCOORD11_centroid = OpVariable %_ptr_Input__arr_v4float_uint_3_0 Input +%in_var_VS_To_DS_Position = OpVariable %_ptr_Input__arr_v4float_uint_3_0 Input +%gl_InvocationID = OpVariable %_ptr_Input_uint Input +%out_var_TEXCOORD10_centroid = OpVariable %_ptr_Output__arr_v4float_uint_3_0 Output +%out_var_TEXCOORD11_centroid = OpVariable %_ptr_Output__arr_v4float_uint_3_0 Output +%out_var_VS_To_DS_Position = OpVariable %_ptr_Output__arr_v4float_uint_3_0 Output +%out_var_Flat_DisplacementScales = OpVariable %_ptr_Output__arr_v3float_uint_3 Output +%out_var_Flat_TessellationMultiplier = OpVariable %_ptr_Output__arr_float_uint_3 Output +%out_var_Flat_WorldDisplacementMultiplier = OpVariable %_ptr_Output__arr_float_uint_3 Output +%gl_TessLevelOuter = OpVariable %_ptr_Output__arr_float_uint_4 Output +%gl_TessLevelInner = OpVariable %_ptr_Output__arr_float_uint_2 Output + %83 = OpConstantNull %FSharedBasePassInterpolants + %84 = OpConstantComposite %FBasePassInterpolantsVSToDS %83 + %85 = OpUndef %v4float + +; XXX: Original asm used Function here, which is wrong. +; This patches the SPIR-V to be correct. +%temp_var_hullMainRetVal = OpVariable %_ptr_Workgroup__arr_FFlatTessellationHSToDS_uint_3 Workgroup + + %MainHull = OpFunction %void None %67 + %86 = OpLabel +%param_var_I = OpVariable %_ptr_Function__arr_FBasePassVSToDS_uint_3 Function + %87 = OpLoad %_arr_v4float_uint_3_0 %in_var_TEXCOORD10_centroid + %88 = OpLoad %_arr_v4float_uint_3_0 %in_var_TEXCOORD11_centroid + %89 = OpCompositeExtract %v4float %87 0 + %90 = OpCompositeExtract %v4float %88 0 + %91 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToPS %89 %90 + %92 = OpCompositeExtract %v4float %87 1 + %93 = OpCompositeExtract %v4float %88 1 + %94 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToPS %92 %93 + %95 = OpCompositeExtract %v4float %87 2 + %96 = OpCompositeExtract %v4float %88 2 + %97 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToPS %95 %96 + %98 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToDS %91 + %99 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToDS %94 + %100 = OpCompositeConstruct %FVertexFactoryInterpolantsVSToDS %97 + %101 = OpLoad %_arr_v4float_uint_3_0 %in_var_VS_To_DS_Position + %102 = OpCompositeExtract %v4float %101 0 + %103 = OpCompositeConstruct %FBasePassVSToDS %98 %84 %102 + %104 = OpCompositeExtract %v4float %101 1 + %105 = OpCompositeConstruct %FBasePassVSToDS %99 %84 %104 + %106 = OpCompositeExtract %v4float %101 2 + %107 = OpCompositeConstruct %FBasePassVSToDS %100 %84 %106 + %108 = OpCompositeConstruct %_arr_FBasePassVSToDS_uint_3 %103 %105 %107 + OpStore %param_var_I %108 + %109 = OpLoad %uint %gl_InvocationID + %110 = OpAccessChain %_ptr_Function_FVertexFactoryInterpolantsVSToDS %param_var_I %109 %int_0 + %111 = OpLoad %FVertexFactoryInterpolantsVSToDS %110 + %112 = OpCompositeExtract %FVertexFactoryInterpolantsVSToPS %111 0 + %113 = OpCompositeExtract %v4float %112 0 + %114 = OpCompositeExtract %v4float %112 1 + %115 = OpVectorShuffle %v3float %113 %113 0 1 2 + %116 = OpVectorShuffle %v3float %114 %114 0 1 2 + %117 = OpExtInst %v3float %1 Cross %116 %115 + %118 = OpCompositeExtract %float %114 3 + %119 = OpCompositeConstruct %v3float %118 %118 %118 + %120 = OpFMul %v3float %117 %119 + %121 = OpCompositeConstruct %mat3v3float %115 %120 %116 + %122 = OpAccessChain %_ptr_Uniform_v4float %Primitive %int_15 + %123 = OpLoad %v4float %122 + %124 = OpVectorShuffle %v3float %123 %123 0 1 2 + %125 = OpVectorTimesMatrix %v3float %124 %121 + %126 = OpAccessChain %_ptr_Function_FBasePassVSToDS %param_var_I %109 + %127 = OpLoad %FBasePassVSToDS %126 + %128 = OpAccessChain %_ptr_Uniform_float %Material %int_1 %int_0 %int_0 + %129 = OpLoad %float %128 + %130 = OpCompositeConstruct %FFlatTessellationHSToDS %127 %125 %129 %float_1 + %131 = OpCompositeExtract %FVertexFactoryInterpolantsVSToDS %127 0 + %132 = OpCompositeExtract %FVertexFactoryInterpolantsVSToPS %131 0 + %133 = OpCompositeExtract %v4float %132 0 + %134 = OpAccessChain %_ptr_Output_v4float %out_var_TEXCOORD10_centroid %109 + OpStore %134 %133 + %135 = OpCompositeExtract %v4float %132 1 + %136 = OpAccessChain %_ptr_Output_v4float %out_var_TEXCOORD11_centroid %109 + OpStore %136 %135 + %137 = OpCompositeExtract %v4float %127 2 + %138 = OpAccessChain %_ptr_Output_v4float %out_var_VS_To_DS_Position %109 + OpStore %138 %137 + %139 = OpAccessChain %_ptr_Output_v3float %out_var_Flat_DisplacementScales %109 + OpStore %139 %125 + %140 = OpAccessChain %_ptr_Output_float %out_var_Flat_TessellationMultiplier %109 + OpStore %140 %129 + %141 = OpAccessChain %_ptr_Output_float %out_var_Flat_WorldDisplacementMultiplier %109 + OpStore %141 %float_1 + %142 = OpAccessChain %_ptr_Workgroup_FFlatTessellationHSToDS %temp_var_hullMainRetVal %109 + OpStore %142 %130 + OpControlBarrier %uint_2 %uint_4 %uint_0 + %143 = OpIEqual %bool %109 %uint_0 + OpSelectionMerge %if_merge None + OpBranchConditional %143 %144 %if_merge + %144 = OpLabel + %145 = OpAccessChain %_ptr_Workgroup_float %temp_var_hullMainRetVal %uint_1 %int_2 + %146 = OpLoad %float %145 + %147 = OpAccessChain %_ptr_Workgroup_float %temp_var_hullMainRetVal %uint_2 %int_2 + %148 = OpLoad %float %147 + %149 = OpFAdd %float %146 %148 + %150 = OpFMul %float %float_0_5 %149 + %151 = OpCompositeInsert %v4float %150 %85 0 + %152 = OpLoad %float %147 + %153 = OpAccessChain %_ptr_Workgroup_float %temp_var_hullMainRetVal %uint_0 %int_2 + %154 = OpLoad %float %153 + %155 = OpFAdd %float %152 %154 + %156 = OpFMul %float %float_0_5 %155 + %157 = OpCompositeInsert %v4float %156 %151 1 + %158 = OpLoad %float %153 + %159 = OpLoad %float %145 + %160 = OpFAdd %float %158 %159 + %161 = OpFMul %float %float_0_5 %160 + %162 = OpCompositeInsert %v4float %161 %157 2 + %163 = OpLoad %float %153 + %164 = OpLoad %float %145 + %165 = OpFAdd %float %163 %164 + %166 = OpLoad %float %147 + %167 = OpFAdd %float %165 %166 + %168 = OpFMul %float %float_0_333000004 %167 + %169 = OpCompositeInsert %v4float %168 %162 3 + %170 = OpExtInst %v4float %1 FClamp %169 %49 %51 + %171 = OpCompositeExtract %float %170 0 + %172 = OpCompositeExtract %float %170 1 + %173 = OpCompositeExtract %float %170 2 + %174 = OpCompositeExtract %float %170 3 + %175 = OpAccessChain %_ptr_Output_float %gl_TessLevelOuter %uint_0 + OpStore %175 %171 + %176 = OpAccessChain %_ptr_Output_float %gl_TessLevelOuter %uint_1 + OpStore %176 %172 + %177 = OpAccessChain %_ptr_Output_float %gl_TessLevelOuter %uint_2 + OpStore %177 %173 + %178 = OpAccessChain %_ptr_Output_float %gl_TessLevelInner %uint_0 + OpStore %178 %174 + OpBranch %if_merge + %if_merge = OpLabel + OpReturn + OpFunctionEnd diff --git a/third_party/spirv-cross/shaders-ue4/asm/tese/ds-double-gl-in-deref.asm.tese b/third_party/spirv-cross/shaders-ue4/asm/tese/ds-double-gl-in-deref.asm.tese new file mode 100644 index 0000000000..dc543d1f86 --- /dev/null +++ b/third_party/spirv-cross/shaders-ue4/asm/tese/ds-double-gl-in-deref.asm.tese @@ -0,0 +1,1046 @@ +; SPIR-V +; Version: 1.0 +; Generator: Google spiregg; 0 +; Bound: 310 +; Schema: 0 + OpCapability Tessellation + OpCapability SampledBuffer + OpCapability StorageImageExtendedFormats + OpExtension "SPV_GOOGLE_hlsl_functionality1" + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint TessellationEvaluation %MainDomain "main" %in_var_TEXCOORD10_centroid %in_var_TEXCOORD11_centroid %in_var_COLOR0 %in_var_TEXCOORD0 %in_var_PRIMITIVE_ID %in_var_VS_to_DS_Position %in_var_PN_POSITION %in_var_PN_DisplacementScales %in_var_PN_TessellationMultiplier %in_var_PN_WorldDisplacementMultiplier %gl_TessLevelOuter %gl_TessLevelInner %in_var_PN_POSITION9 %gl_TessCoord %out_var_TEXCOORD10_centroid %out_var_TEXCOORD11_centroid %out_var_COLOR0 %out_var_TEXCOORD0 %out_var_PRIMITIVE_ID %out_var_TEXCOORD6 %out_var_TEXCOORD8 %out_var_TEXCOORD7 %gl_Position + OpExecutionMode %MainDomain Triangles + OpSource HLSL 600 + OpName %type_View "type.View" + OpMemberName %type_View 0 "View_TranslatedWorldToClip" + OpMemberName %type_View 1 "View_WorldToClip" + OpMemberName %type_View 2 "View_ClipToWorld" + OpMemberName %type_View 3 "View_TranslatedWorldToView" + OpMemberName %type_View 4 "View_ViewToTranslatedWorld" + OpMemberName %type_View 5 "View_TranslatedWorldToCameraView" + OpMemberName %type_View 6 "View_CameraViewToTranslatedWorld" + OpMemberName %type_View 7 "View_ViewToClip" + OpMemberName %type_View 8 "View_ViewToClipNoAA" + OpMemberName %type_View 9 "View_ClipToView" + OpMemberName %type_View 10 "View_ClipToTranslatedWorld" + OpMemberName %type_View 11 "View_SVPositionToTranslatedWorld" + OpMemberName %type_View 12 "View_ScreenToWorld" + OpMemberName %type_View 13 "View_ScreenToTranslatedWorld" + OpMemberName %type_View 14 "View_ViewForward" + OpMemberName %type_View 15 "PrePadding_View_908" + OpMemberName %type_View 16 "View_ViewUp" + OpMemberName %type_View 17 "PrePadding_View_924" + OpMemberName %type_View 18 "View_ViewRight" + OpMemberName %type_View 19 "PrePadding_View_940" + OpMemberName %type_View 20 "View_HMDViewNoRollUp" + OpMemberName %type_View 21 "PrePadding_View_956" + OpMemberName %type_View 22 "View_HMDViewNoRollRight" + OpMemberName %type_View 23 "PrePadding_View_972" + OpMemberName %type_View 24 "View_InvDeviceZToWorldZTransform" + OpMemberName %type_View 25 "View_ScreenPositionScaleBias" + OpMemberName %type_View 26 "View_WorldCameraOrigin" + OpMemberName %type_View 27 "PrePadding_View_1020" + OpMemberName %type_View 28 "View_TranslatedWorldCameraOrigin" + OpMemberName %type_View 29 "PrePadding_View_1036" + OpMemberName %type_View 30 "View_WorldViewOrigin" + OpMemberName %type_View 31 "PrePadding_View_1052" + OpMemberName %type_View 32 "View_PreViewTranslation" + OpMemberName %type_View 33 "PrePadding_View_1068" + OpMemberName %type_View 34 "View_PrevProjection" + OpMemberName %type_View 35 "View_PrevViewProj" + OpMemberName %type_View 36 "View_PrevViewRotationProj" + OpMemberName %type_View 37 "View_PrevViewToClip" + OpMemberName %type_View 38 "View_PrevClipToView" + OpMemberName %type_View 39 "View_PrevTranslatedWorldToClip" + OpMemberName %type_View 40 "View_PrevTranslatedWorldToView" + OpMemberName %type_View 41 "View_PrevViewToTranslatedWorld" + OpMemberName %type_View 42 "View_PrevTranslatedWorldToCameraView" + OpMemberName %type_View 43 "View_PrevCameraViewToTranslatedWorld" + OpMemberName %type_View 44 "View_PrevWorldCameraOrigin" + OpMemberName %type_View 45 "PrePadding_View_1724" + OpMemberName %type_View 46 "View_PrevWorldViewOrigin" + OpMemberName %type_View 47 "PrePadding_View_1740" + OpMemberName %type_View 48 "View_PrevPreViewTranslation" + OpMemberName %type_View 49 "PrePadding_View_1756" + OpMemberName %type_View 50 "View_PrevInvViewProj" + OpMemberName %type_View 51 "View_PrevScreenToTranslatedWorld" + OpMemberName %type_View 52 "View_ClipToPrevClip" + OpMemberName %type_View 53 "View_TemporalAAJitter" + OpMemberName %type_View 54 "View_GlobalClippingPlane" + OpMemberName %type_View 55 "View_FieldOfViewWideAngles" + OpMemberName %type_View 56 "View_PrevFieldOfViewWideAngles" + OpMemberName %type_View 57 "View_ViewRectMin" + OpMemberName %type_View 58 "View_ViewSizeAndInvSize" + OpMemberName %type_View 59 "View_BufferSizeAndInvSize" + OpMemberName %type_View 60 "View_BufferBilinearUVMinMax" + OpMemberName %type_View 61 "View_NumSceneColorMSAASamples" + OpMemberName %type_View 62 "View_PreExposure" + OpMemberName %type_View 63 "View_OneOverPreExposure" + OpMemberName %type_View 64 "PrePadding_View_2076" + OpMemberName %type_View 65 "View_DiffuseOverrideParameter" + OpMemberName %type_View 66 "View_SpecularOverrideParameter" + OpMemberName %type_View 67 "View_NormalOverrideParameter" + OpMemberName %type_View 68 "View_RoughnessOverrideParameter" + OpMemberName %type_View 69 "View_PrevFrameGameTime" + OpMemberName %type_View 70 "View_PrevFrameRealTime" + OpMemberName %type_View 71 "View_OutOfBoundsMask" + OpMemberName %type_View 72 "PrePadding_View_2148" + OpMemberName %type_View 73 "PrePadding_View_2152" + OpMemberName %type_View 74 "PrePadding_View_2156" + OpMemberName %type_View 75 "View_WorldCameraMovementSinceLastFrame" + OpMemberName %type_View 76 "View_CullingSign" + OpMemberName %type_View 77 "View_NearPlane" + OpMemberName %type_View 78 "View_AdaptiveTessellationFactor" + OpMemberName %type_View 79 "View_GameTime" + OpMemberName %type_View 80 "View_RealTime" + OpMemberName %type_View 81 "View_DeltaTime" + OpMemberName %type_View 82 "View_MaterialTextureMipBias" + OpMemberName %type_View 83 "View_MaterialTextureDerivativeMultiply" + OpMemberName %type_View 84 "View_Random" + OpMemberName %type_View 85 "View_FrameNumber" + OpMemberName %type_View 86 "View_StateFrameIndexMod8" + OpMemberName %type_View 87 "View_StateFrameIndex" + OpMemberName %type_View 88 "View_CameraCut" + OpMemberName %type_View 89 "View_UnlitViewmodeMask" + OpMemberName %type_View 90 "PrePadding_View_2228" + OpMemberName %type_View 91 "PrePadding_View_2232" + OpMemberName %type_View 92 "PrePadding_View_2236" + OpMemberName %type_View 93 "View_DirectionalLightColor" + OpMemberName %type_View 94 "View_DirectionalLightDirection" + OpMemberName %type_View 95 "PrePadding_View_2268" + OpMemberName %type_View 96 "View_TranslucencyLightingVolumeMin" + OpMemberName %type_View 97 "View_TranslucencyLightingVolumeInvSize" + OpMemberName %type_View 98 "View_TemporalAAParams" + OpMemberName %type_View 99 "View_CircleDOFParams" + OpMemberName %type_View 100 "View_DepthOfFieldSensorWidth" + OpMemberName %type_View 101 "View_DepthOfFieldFocalDistance" + OpMemberName %type_View 102 "View_DepthOfFieldScale" + OpMemberName %type_View 103 "View_DepthOfFieldFocalLength" + OpMemberName %type_View 104 "View_DepthOfFieldFocalRegion" + OpMemberName %type_View 105 "View_DepthOfFieldNearTransitionRegion" + OpMemberName %type_View 106 "View_DepthOfFieldFarTransitionRegion" + OpMemberName %type_View 107 "View_MotionBlurNormalizedToPixel" + OpMemberName %type_View 108 "View_bSubsurfacePostprocessEnabled" + OpMemberName %type_View 109 "View_GeneralPurposeTweak" + OpMemberName %type_View 110 "View_DemosaicVposOffset" + OpMemberName %type_View 111 "PrePadding_View_2412" + OpMemberName %type_View 112 "View_IndirectLightingColorScale" + OpMemberName %type_View 113 "View_HDR32bppEncodingMode" + OpMemberName %type_View 114 "View_AtmosphericFogSunDirection" + OpMemberName %type_View 115 "View_AtmosphericFogSunPower" + OpMemberName %type_View 116 "View_AtmosphericFogPower" + OpMemberName %type_View 117 "View_AtmosphericFogDensityScale" + OpMemberName %type_View 118 "View_AtmosphericFogDensityOffset" + OpMemberName %type_View 119 "View_AtmosphericFogGroundOffset" + OpMemberName %type_View 120 "View_AtmosphericFogDistanceScale" + OpMemberName %type_View 121 "View_AtmosphericFogAltitudeScale" + OpMemberName %type_View 122 "View_AtmosphericFogHeightScaleRayleigh" + OpMemberName %type_View 123 "View_AtmosphericFogStartDistance" + OpMemberName %type_View 124 "View_AtmosphericFogDistanceOffset" + OpMemberName %type_View 125 "View_AtmosphericFogSunDiscScale" + OpMemberName %type_View 126 "View_AtmosphericFogSunDiscHalfApexAngleRadian" + OpMemberName %type_View 127 "PrePadding_View_2492" + OpMemberName %type_View 128 "View_AtmosphericFogSunDiscLuminance" + OpMemberName %type_View 129 "View_AtmosphericFogRenderMask" + OpMemberName %type_View 130 "View_AtmosphericFogInscatterAltitudeSampleNum" + OpMemberName %type_View 131 "PrePadding_View_2520" + OpMemberName %type_View 132 "PrePadding_View_2524" + OpMemberName %type_View 133 "View_AtmosphericFogSunColor" + OpMemberName %type_View 134 "View_NormalCurvatureToRoughnessScaleBias" + OpMemberName %type_View 135 "View_RenderingReflectionCaptureMask" + OpMemberName %type_View 136 "View_AmbientCubemapTint" + OpMemberName %type_View 137 "View_AmbientCubemapIntensity" + OpMemberName %type_View 138 "View_SkyLightParameters" + OpMemberName %type_View 139 "PrePadding_View_2584" + OpMemberName %type_View 140 "PrePadding_View_2588" + OpMemberName %type_View 141 "View_SkyLightColor" + OpMemberName %type_View 142 "View_SkyIrradianceEnvironmentMap" + OpMemberName %type_View 143 "View_MobilePreviewMode" + OpMemberName %type_View 144 "View_HMDEyePaddingOffset" + OpMemberName %type_View 145 "View_ReflectionCubemapMaxMip" + OpMemberName %type_View 146 "View_ShowDecalsMask" + OpMemberName %type_View 147 "View_DistanceFieldAOSpecularOcclusionMode" + OpMemberName %type_View 148 "View_IndirectCapsuleSelfShadowingIntensity" + OpMemberName %type_View 149 "PrePadding_View_2744" + OpMemberName %type_View 150 "PrePadding_View_2748" + OpMemberName %type_View 151 "View_ReflectionEnvironmentRoughnessMixingScaleBiasAndLargestWeight" + OpMemberName %type_View 152 "View_StereoPassIndex" + OpMemberName %type_View 153 "View_GlobalVolumeCenterAndExtent" + OpMemberName %type_View 154 "View_GlobalVolumeWorldToUVAddAndMul" + OpMemberName %type_View 155 "View_GlobalVolumeDimension" + OpMemberName %type_View 156 "View_GlobalVolumeTexelSize" + OpMemberName %type_View 157 "View_MaxGlobalDistance" + OpMemberName %type_View 158 "PrePadding_View_2908" + OpMemberName %type_View 159 "View_CursorPosition" + OpMemberName %type_View 160 "View_bCheckerboardSubsurfaceProfileRendering" + OpMemberName %type_View 161 "PrePadding_View_2924" + OpMemberName %type_View 162 "View_VolumetricFogInvGridSize" + OpMemberName %type_View 163 "PrePadding_View_2940" + OpMemberName %type_View 164 "View_VolumetricFogGridZParams" + OpMemberName %type_View 165 "PrePadding_View_2956" + OpMemberName %type_View 166 "View_VolumetricFogSVPosToVolumeUV" + OpMemberName %type_View 167 "View_VolumetricFogMaxDistance" + OpMemberName %type_View 168 "PrePadding_View_2972" + OpMemberName %type_View 169 "View_VolumetricLightmapWorldToUVScale" + OpMemberName %type_View 170 "PrePadding_View_2988" + OpMemberName %type_View 171 "View_VolumetricLightmapWorldToUVAdd" + OpMemberName %type_View 172 "PrePadding_View_3004" + OpMemberName %type_View 173 "View_VolumetricLightmapIndirectionTextureSize" + OpMemberName %type_View 174 "View_VolumetricLightmapBrickSize" + OpMemberName %type_View 175 "View_VolumetricLightmapBrickTexelSize" + OpMemberName %type_View 176 "View_StereoIPD" + OpMemberName %type_View 177 "View_IndirectLightingCacheShowFlag" + OpMemberName %type_View 178 "View_EyeToPixelSpreadAngle" + OpName %View "View" + OpName %type_sampler "type.sampler" + OpName %type_2d_image "type.2d.image" + OpName %type_ShadowDepthPass "type.ShadowDepthPass" + OpMemberName %type_ShadowDepthPass 0 "PrePadding_ShadowDepthPass_LPV_0" + OpMemberName %type_ShadowDepthPass 1 "PrePadding_ShadowDepthPass_LPV_4" + OpMemberName %type_ShadowDepthPass 2 "PrePadding_ShadowDepthPass_LPV_8" + OpMemberName %type_ShadowDepthPass 3 "PrePadding_ShadowDepthPass_LPV_12" + OpMemberName %type_ShadowDepthPass 4 "PrePadding_ShadowDepthPass_LPV_16" + OpMemberName %type_ShadowDepthPass 5 "PrePadding_ShadowDepthPass_LPV_20" + OpMemberName %type_ShadowDepthPass 6 "PrePadding_ShadowDepthPass_LPV_24" + OpMemberName %type_ShadowDepthPass 7 "PrePadding_ShadowDepthPass_LPV_28" + OpMemberName %type_ShadowDepthPass 8 "PrePadding_ShadowDepthPass_LPV_32" + OpMemberName %type_ShadowDepthPass 9 "PrePadding_ShadowDepthPass_LPV_36" + OpMemberName %type_ShadowDepthPass 10 "PrePadding_ShadowDepthPass_LPV_40" + OpMemberName %type_ShadowDepthPass 11 "PrePadding_ShadowDepthPass_LPV_44" + OpMemberName %type_ShadowDepthPass 12 "PrePadding_ShadowDepthPass_LPV_48" + OpMemberName %type_ShadowDepthPass 13 "PrePadding_ShadowDepthPass_LPV_52" + OpMemberName %type_ShadowDepthPass 14 "PrePadding_ShadowDepthPass_LPV_56" + OpMemberName %type_ShadowDepthPass 15 "PrePadding_ShadowDepthPass_LPV_60" + OpMemberName %type_ShadowDepthPass 16 "PrePadding_ShadowDepthPass_LPV_64" + OpMemberName %type_ShadowDepthPass 17 "PrePadding_ShadowDepthPass_LPV_68" + OpMemberName %type_ShadowDepthPass 18 "PrePadding_ShadowDepthPass_LPV_72" + OpMemberName %type_ShadowDepthPass 19 "PrePadding_ShadowDepthPass_LPV_76" + OpMemberName %type_ShadowDepthPass 20 "PrePadding_ShadowDepthPass_LPV_80" + OpMemberName %type_ShadowDepthPass 21 "PrePadding_ShadowDepthPass_LPV_84" + OpMemberName %type_ShadowDepthPass 22 "PrePadding_ShadowDepthPass_LPV_88" + OpMemberName %type_ShadowDepthPass 23 "PrePadding_ShadowDepthPass_LPV_92" + OpMemberName %type_ShadowDepthPass 24 "PrePadding_ShadowDepthPass_LPV_96" + OpMemberName %type_ShadowDepthPass 25 "PrePadding_ShadowDepthPass_LPV_100" + OpMemberName %type_ShadowDepthPass 26 "PrePadding_ShadowDepthPass_LPV_104" + OpMemberName %type_ShadowDepthPass 27 "PrePadding_ShadowDepthPass_LPV_108" + OpMemberName %type_ShadowDepthPass 28 "PrePadding_ShadowDepthPass_LPV_112" + OpMemberName %type_ShadowDepthPass 29 "PrePadding_ShadowDepthPass_LPV_116" + OpMemberName %type_ShadowDepthPass 30 "PrePadding_ShadowDepthPass_LPV_120" + OpMemberName %type_ShadowDepthPass 31 "PrePadding_ShadowDepthPass_LPV_124" + OpMemberName %type_ShadowDepthPass 32 "PrePadding_ShadowDepthPass_LPV_128" + OpMemberName %type_ShadowDepthPass 33 "PrePadding_ShadowDepthPass_LPV_132" + OpMemberName %type_ShadowDepthPass 34 "PrePadding_ShadowDepthPass_LPV_136" + OpMemberName %type_ShadowDepthPass 35 "PrePadding_ShadowDepthPass_LPV_140" + OpMemberName %type_ShadowDepthPass 36 "PrePadding_ShadowDepthPass_LPV_144" + OpMemberName %type_ShadowDepthPass 37 "PrePadding_ShadowDepthPass_LPV_148" + OpMemberName %type_ShadowDepthPass 38 "PrePadding_ShadowDepthPass_LPV_152" + OpMemberName %type_ShadowDepthPass 39 "PrePadding_ShadowDepthPass_LPV_156" + OpMemberName %type_ShadowDepthPass 40 "PrePadding_ShadowDepthPass_LPV_160" + OpMemberName %type_ShadowDepthPass 41 "PrePadding_ShadowDepthPass_LPV_164" + OpMemberName %type_ShadowDepthPass 42 "PrePadding_ShadowDepthPass_LPV_168" + OpMemberName %type_ShadowDepthPass 43 "PrePadding_ShadowDepthPass_LPV_172" + OpMemberName %type_ShadowDepthPass 44 "PrePadding_ShadowDepthPass_LPV_176" + OpMemberName %type_ShadowDepthPass 45 "PrePadding_ShadowDepthPass_LPV_180" + OpMemberName %type_ShadowDepthPass 46 "PrePadding_ShadowDepthPass_LPV_184" + OpMemberName %type_ShadowDepthPass 47 "PrePadding_ShadowDepthPass_LPV_188" + OpMemberName %type_ShadowDepthPass 48 "PrePadding_ShadowDepthPass_LPV_192" + OpMemberName %type_ShadowDepthPass 49 "PrePadding_ShadowDepthPass_LPV_196" + OpMemberName %type_ShadowDepthPass 50 "PrePadding_ShadowDepthPass_LPV_200" + OpMemberName %type_ShadowDepthPass 51 "PrePadding_ShadowDepthPass_LPV_204" + OpMemberName %type_ShadowDepthPass 52 "PrePadding_ShadowDepthPass_LPV_208" + OpMemberName %type_ShadowDepthPass 53 "PrePadding_ShadowDepthPass_LPV_212" + OpMemberName %type_ShadowDepthPass 54 "PrePadding_ShadowDepthPass_LPV_216" + OpMemberName %type_ShadowDepthPass 55 "PrePadding_ShadowDepthPass_LPV_220" + OpMemberName %type_ShadowDepthPass 56 "PrePadding_ShadowDepthPass_LPV_224" + OpMemberName %type_ShadowDepthPass 57 "PrePadding_ShadowDepthPass_LPV_228" + OpMemberName %type_ShadowDepthPass 58 "PrePadding_ShadowDepthPass_LPV_232" + OpMemberName %type_ShadowDepthPass 59 "PrePadding_ShadowDepthPass_LPV_236" + OpMemberName %type_ShadowDepthPass 60 "PrePadding_ShadowDepthPass_LPV_240" + OpMemberName %type_ShadowDepthPass 61 "PrePadding_ShadowDepthPass_LPV_244" + OpMemberName %type_ShadowDepthPass 62 "PrePadding_ShadowDepthPass_LPV_248" + OpMemberName %type_ShadowDepthPass 63 "PrePadding_ShadowDepthPass_LPV_252" + OpMemberName %type_ShadowDepthPass 64 "PrePadding_ShadowDepthPass_LPV_256" + OpMemberName %type_ShadowDepthPass 65 "PrePadding_ShadowDepthPass_LPV_260" + OpMemberName %type_ShadowDepthPass 66 "PrePadding_ShadowDepthPass_LPV_264" + OpMemberName %type_ShadowDepthPass 67 "PrePadding_ShadowDepthPass_LPV_268" + OpMemberName %type_ShadowDepthPass 68 "ShadowDepthPass_LPV_mRsmToWorld" + OpMemberName %type_ShadowDepthPass 69 "ShadowDepthPass_LPV_mLightColour" + OpMemberName %type_ShadowDepthPass 70 "ShadowDepthPass_LPV_GeometryVolumeCaptureLightDirection" + OpMemberName %type_ShadowDepthPass 71 "ShadowDepthPass_LPV_mEyePos" + OpMemberName %type_ShadowDepthPass 72 "ShadowDepthPass_LPV_mOldGridOffset" + OpMemberName %type_ShadowDepthPass 73 "PrePadding_ShadowDepthPass_LPV_396" + OpMemberName %type_ShadowDepthPass 74 "ShadowDepthPass_LPV_mLpvGridOffset" + OpMemberName %type_ShadowDepthPass 75 "ShadowDepthPass_LPV_ClearMultiplier" + OpMemberName %type_ShadowDepthPass 76 "ShadowDepthPass_LPV_LpvScale" + OpMemberName %type_ShadowDepthPass 77 "ShadowDepthPass_LPV_OneOverLpvScale" + OpMemberName %type_ShadowDepthPass 78 "ShadowDepthPass_LPV_DirectionalOcclusionIntensity" + OpMemberName %type_ShadowDepthPass 79 "ShadowDepthPass_LPV_DirectionalOcclusionRadius" + OpMemberName %type_ShadowDepthPass 80 "ShadowDepthPass_LPV_RsmAreaIntensityMultiplier" + OpMemberName %type_ShadowDepthPass 81 "ShadowDepthPass_LPV_RsmPixelToTexcoordMultiplier" + OpMemberName %type_ShadowDepthPass 82 "ShadowDepthPass_LPV_SecondaryOcclusionStrength" + OpMemberName %type_ShadowDepthPass 83 "ShadowDepthPass_LPV_SecondaryBounceStrength" + OpMemberName %type_ShadowDepthPass 84 "ShadowDepthPass_LPV_VplInjectionBias" + OpMemberName %type_ShadowDepthPass 85 "ShadowDepthPass_LPV_GeometryVolumeInjectionBias" + OpMemberName %type_ShadowDepthPass 86 "ShadowDepthPass_LPV_EmissiveInjectionMultiplier" + OpMemberName %type_ShadowDepthPass 87 "ShadowDepthPass_LPV_PropagationIndex" + OpMemberName %type_ShadowDepthPass 88 "ShadowDepthPass_ProjectionMatrix" + OpMemberName %type_ShadowDepthPass 89 "ShadowDepthPass_ViewMatrix" + OpMemberName %type_ShadowDepthPass 90 "ShadowDepthPass_ShadowParams" + OpMemberName %type_ShadowDepthPass 91 "ShadowDepthPass_bClampToNearPlane" + OpMemberName %type_ShadowDepthPass 92 "PrePadding_ShadowDepthPass_612" + OpMemberName %type_ShadowDepthPass 93 "PrePadding_ShadowDepthPass_616" + OpMemberName %type_ShadowDepthPass 94 "PrePadding_ShadowDepthPass_620" + OpMemberName %type_ShadowDepthPass 95 "ShadowDepthPass_ShadowViewProjectionMatrices" + OpMemberName %type_ShadowDepthPass 96 "ShadowDepthPass_ShadowViewMatrices" + OpName %ShadowDepthPass "ShadowDepthPass" + OpName %Material_Texture2D_3 "Material_Texture2D_3" + OpName %Material_Texture2D_3Sampler "Material_Texture2D_3Sampler" + OpName %in_var_TEXCOORD10_centroid "in.var.TEXCOORD10_centroid" + OpName %in_var_TEXCOORD11_centroid "in.var.TEXCOORD11_centroid" + OpName %in_var_COLOR0 "in.var.COLOR0" + OpName %in_var_TEXCOORD0 "in.var.TEXCOORD0" + OpName %in_var_PRIMITIVE_ID "in.var.PRIMITIVE_ID" + OpName %in_var_VS_to_DS_Position "in.var.VS_to_DS_Position" + OpName %in_var_PN_POSITION "in.var.PN_POSITION" + OpName %in_var_PN_DisplacementScales "in.var.PN_DisplacementScales" + OpName %in_var_PN_TessellationMultiplier "in.var.PN_TessellationMultiplier" + OpName %in_var_PN_WorldDisplacementMultiplier "in.var.PN_WorldDisplacementMultiplier" + OpName %in_var_PN_POSITION9 "in.var.PN_POSITION9" + OpName %out_var_TEXCOORD10_centroid "out.var.TEXCOORD10_centroid" + OpName %out_var_TEXCOORD11_centroid "out.var.TEXCOORD11_centroid" + OpName %out_var_COLOR0 "out.var.COLOR0" + OpName %out_var_TEXCOORD0 "out.var.TEXCOORD0" + OpName %out_var_PRIMITIVE_ID "out.var.PRIMITIVE_ID" + OpName %out_var_TEXCOORD6 "out.var.TEXCOORD6" + OpName %out_var_TEXCOORD8 "out.var.TEXCOORD8" + OpName %out_var_TEXCOORD7 "out.var.TEXCOORD7" + OpName %MainDomain "MainDomain" + OpName %type_sampled_image "type.sampled.image" + OpDecorateString %in_var_TEXCOORD10_centroid UserSemantic "TEXCOORD10_centroid" + OpDecorateString %in_var_TEXCOORD11_centroid UserSemantic "TEXCOORD11_centroid" + OpDecorateString %in_var_COLOR0 UserSemantic "COLOR0" + OpDecorateString %in_var_TEXCOORD0 UserSemantic "TEXCOORD0" + OpDecorateString %in_var_PRIMITIVE_ID UserSemantic "PRIMITIVE_ID" + OpDecorateString %in_var_VS_to_DS_Position UserSemantic "VS_to_DS_Position" + OpDecorateString %in_var_PN_POSITION UserSemantic "PN_POSITION" + OpDecorateString %in_var_PN_DisplacementScales UserSemantic "PN_DisplacementScales" + OpDecorateString %in_var_PN_TessellationMultiplier UserSemantic "PN_TessellationMultiplier" + OpDecorateString %in_var_PN_WorldDisplacementMultiplier UserSemantic "PN_WorldDisplacementMultiplier" + OpDecorate %gl_TessLevelOuter BuiltIn TessLevelOuter + OpDecorateString %gl_TessLevelOuter UserSemantic "SV_TessFactor" + OpDecorate %gl_TessLevelOuter Patch + OpDecorate %gl_TessLevelInner BuiltIn TessLevelInner + OpDecorateString %gl_TessLevelInner UserSemantic "SV_InsideTessFactor" + OpDecorate %gl_TessLevelInner Patch + OpDecorateString %in_var_PN_POSITION9 UserSemantic "PN_POSITION9" + OpDecorate %in_var_PN_POSITION9 Patch + OpDecorate %gl_TessCoord BuiltIn TessCoord + OpDecorateString %gl_TessCoord UserSemantic "SV_DomainLocation" + OpDecorate %gl_TessCoord Patch + OpDecorateString %out_var_TEXCOORD10_centroid UserSemantic "TEXCOORD10_centroid" + OpDecorateString %out_var_TEXCOORD11_centroid UserSemantic "TEXCOORD11_centroid" + OpDecorateString %out_var_COLOR0 UserSemantic "COLOR0" + OpDecorateString %out_var_TEXCOORD0 UserSemantic "TEXCOORD0" + OpDecorateString %out_var_PRIMITIVE_ID UserSemantic "PRIMITIVE_ID" + OpDecorateString %out_var_TEXCOORD6 UserSemantic "TEXCOORD6" + OpDecorateString %out_var_TEXCOORD8 UserSemantic "TEXCOORD8" + OpDecorateString %out_var_TEXCOORD7 UserSemantic "TEXCOORD7" + OpDecorate %gl_Position BuiltIn Position + OpDecorateString %gl_Position UserSemantic "SV_POSITION" + OpDecorate %in_var_COLOR0 Location 0 + OpDecorate %in_var_PN_DisplacementScales Location 1 + OpDecorate %in_var_PN_POSITION Location 2 + OpDecorate %in_var_PN_POSITION9 Location 5 + OpDecorate %in_var_PN_TessellationMultiplier Location 6 + OpDecorate %in_var_PN_WorldDisplacementMultiplier Location 7 + OpDecorate %in_var_PRIMITIVE_ID Location 8 + OpDecorate %in_var_TEXCOORD0 Location 9 + OpDecorate %in_var_TEXCOORD10_centroid Location 10 + OpDecorate %in_var_TEXCOORD11_centroid Location 11 + OpDecorate %in_var_VS_to_DS_Position Location 12 + OpDecorate %out_var_TEXCOORD10_centroid Location 0 + OpDecorate %out_var_TEXCOORD11_centroid Location 1 + OpDecorate %out_var_COLOR0 Location 2 + OpDecorate %out_var_TEXCOORD0 Location 3 + OpDecorate %out_var_PRIMITIVE_ID Location 4 + OpDecorate %out_var_TEXCOORD6 Location 5 + OpDecorate %out_var_TEXCOORD8 Location 6 + OpDecorate %out_var_TEXCOORD7 Location 7 + OpDecorate %View DescriptorSet 0 + OpDecorate %View Binding 0 + OpDecorate %ShadowDepthPass DescriptorSet 0 + OpDecorate %ShadowDepthPass Binding 1 + OpDecorate %Material_Texture2D_3 DescriptorSet 0 + OpDecorate %Material_Texture2D_3 Binding 0 + OpDecorate %Material_Texture2D_3Sampler DescriptorSet 0 + OpDecorate %Material_Texture2D_3Sampler Binding 0 + OpDecorate %_arr_v4float_uint_2 ArrayStride 16 + OpDecorate %_arr_v4float_uint_7 ArrayStride 16 + OpDecorate %_arr_v4float_uint_4 ArrayStride 16 + OpMemberDecorate %type_View 0 Offset 0 + OpMemberDecorate %type_View 0 MatrixStride 16 + OpMemberDecorate %type_View 0 ColMajor + OpMemberDecorate %type_View 1 Offset 64 + OpMemberDecorate %type_View 1 MatrixStride 16 + OpMemberDecorate %type_View 1 ColMajor + OpMemberDecorate %type_View 2 Offset 128 + OpMemberDecorate %type_View 2 MatrixStride 16 + OpMemberDecorate %type_View 2 ColMajor + OpMemberDecorate %type_View 3 Offset 192 + OpMemberDecorate %type_View 3 MatrixStride 16 + OpMemberDecorate %type_View 3 ColMajor + OpMemberDecorate %type_View 4 Offset 256 + OpMemberDecorate %type_View 4 MatrixStride 16 + OpMemberDecorate %type_View 4 ColMajor + OpMemberDecorate %type_View 5 Offset 320 + OpMemberDecorate %type_View 5 MatrixStride 16 + OpMemberDecorate %type_View 5 ColMajor + OpMemberDecorate %type_View 6 Offset 384 + OpMemberDecorate %type_View 6 MatrixStride 16 + OpMemberDecorate %type_View 6 ColMajor + OpMemberDecorate %type_View 7 Offset 448 + OpMemberDecorate %type_View 7 MatrixStride 16 + OpMemberDecorate %type_View 7 ColMajor + OpMemberDecorate %type_View 8 Offset 512 + OpMemberDecorate %type_View 8 MatrixStride 16 + OpMemberDecorate %type_View 8 ColMajor + OpMemberDecorate %type_View 9 Offset 576 + OpMemberDecorate %type_View 9 MatrixStride 16 + OpMemberDecorate %type_View 9 ColMajor + OpMemberDecorate %type_View 10 Offset 640 + OpMemberDecorate %type_View 10 MatrixStride 16 + OpMemberDecorate %type_View 10 ColMajor + OpMemberDecorate %type_View 11 Offset 704 + OpMemberDecorate %type_View 11 MatrixStride 16 + OpMemberDecorate %type_View 11 ColMajor + OpMemberDecorate %type_View 12 Offset 768 + OpMemberDecorate %type_View 12 MatrixStride 16 + OpMemberDecorate %type_View 12 ColMajor + OpMemberDecorate %type_View 13 Offset 832 + OpMemberDecorate %type_View 13 MatrixStride 16 + OpMemberDecorate %type_View 13 ColMajor + OpMemberDecorate %type_View 14 Offset 896 + OpMemberDecorate %type_View 15 Offset 908 + OpMemberDecorate %type_View 16 Offset 912 + OpMemberDecorate %type_View 17 Offset 924 + OpMemberDecorate %type_View 18 Offset 928 + OpMemberDecorate %type_View 19 Offset 940 + OpMemberDecorate %type_View 20 Offset 944 + OpMemberDecorate %type_View 21 Offset 956 + OpMemberDecorate %type_View 22 Offset 960 + OpMemberDecorate %type_View 23 Offset 972 + OpMemberDecorate %type_View 24 Offset 976 + OpMemberDecorate %type_View 25 Offset 992 + OpMemberDecorate %type_View 26 Offset 1008 + OpMemberDecorate %type_View 27 Offset 1020 + OpMemberDecorate %type_View 28 Offset 1024 + OpMemberDecorate %type_View 29 Offset 1036 + OpMemberDecorate %type_View 30 Offset 1040 + OpMemberDecorate %type_View 31 Offset 1052 + OpMemberDecorate %type_View 32 Offset 1056 + OpMemberDecorate %type_View 33 Offset 1068 + OpMemberDecorate %type_View 34 Offset 1072 + OpMemberDecorate %type_View 34 MatrixStride 16 + OpMemberDecorate %type_View 34 ColMajor + OpMemberDecorate %type_View 35 Offset 1136 + OpMemberDecorate %type_View 35 MatrixStride 16 + OpMemberDecorate %type_View 35 ColMajor + OpMemberDecorate %type_View 36 Offset 1200 + OpMemberDecorate %type_View 36 MatrixStride 16 + OpMemberDecorate %type_View 36 ColMajor + OpMemberDecorate %type_View 37 Offset 1264 + OpMemberDecorate %type_View 37 MatrixStride 16 + OpMemberDecorate %type_View 37 ColMajor + OpMemberDecorate %type_View 38 Offset 1328 + OpMemberDecorate %type_View 38 MatrixStride 16 + OpMemberDecorate %type_View 38 ColMajor + OpMemberDecorate %type_View 39 Offset 1392 + OpMemberDecorate %type_View 39 MatrixStride 16 + OpMemberDecorate %type_View 39 ColMajor + OpMemberDecorate %type_View 40 Offset 1456 + OpMemberDecorate %type_View 40 MatrixStride 16 + OpMemberDecorate %type_View 40 ColMajor + OpMemberDecorate %type_View 41 Offset 1520 + OpMemberDecorate %type_View 41 MatrixStride 16 + OpMemberDecorate %type_View 41 ColMajor + OpMemberDecorate %type_View 42 Offset 1584 + OpMemberDecorate %type_View 42 MatrixStride 16 + OpMemberDecorate %type_View 42 ColMajor + OpMemberDecorate %type_View 43 Offset 1648 + OpMemberDecorate %type_View 43 MatrixStride 16 + OpMemberDecorate %type_View 43 ColMajor + OpMemberDecorate %type_View 44 Offset 1712 + OpMemberDecorate %type_View 45 Offset 1724 + OpMemberDecorate %type_View 46 Offset 1728 + OpMemberDecorate %type_View 47 Offset 1740 + OpMemberDecorate %type_View 48 Offset 1744 + OpMemberDecorate %type_View 49 Offset 1756 + OpMemberDecorate %type_View 50 Offset 1760 + OpMemberDecorate %type_View 50 MatrixStride 16 + OpMemberDecorate %type_View 50 ColMajor + OpMemberDecorate %type_View 51 Offset 1824 + OpMemberDecorate %type_View 51 MatrixStride 16 + OpMemberDecorate %type_View 51 ColMajor + OpMemberDecorate %type_View 52 Offset 1888 + OpMemberDecorate %type_View 52 MatrixStride 16 + OpMemberDecorate %type_View 52 ColMajor + OpMemberDecorate %type_View 53 Offset 1952 + OpMemberDecorate %type_View 54 Offset 1968 + OpMemberDecorate %type_View 55 Offset 1984 + OpMemberDecorate %type_View 56 Offset 1992 + OpMemberDecorate %type_View 57 Offset 2000 + OpMemberDecorate %type_View 58 Offset 2016 + OpMemberDecorate %type_View 59 Offset 2032 + OpMemberDecorate %type_View 60 Offset 2048 + OpMemberDecorate %type_View 61 Offset 2064 + OpMemberDecorate %type_View 62 Offset 2068 + OpMemberDecorate %type_View 63 Offset 2072 + OpMemberDecorate %type_View 64 Offset 2076 + OpMemberDecorate %type_View 65 Offset 2080 + OpMemberDecorate %type_View 66 Offset 2096 + OpMemberDecorate %type_View 67 Offset 2112 + OpMemberDecorate %type_View 68 Offset 2128 + OpMemberDecorate %type_View 69 Offset 2136 + OpMemberDecorate %type_View 70 Offset 2140 + OpMemberDecorate %type_View 71 Offset 2144 + OpMemberDecorate %type_View 72 Offset 2148 + OpMemberDecorate %type_View 73 Offset 2152 + OpMemberDecorate %type_View 74 Offset 2156 + OpMemberDecorate %type_View 75 Offset 2160 + OpMemberDecorate %type_View 76 Offset 2172 + OpMemberDecorate %type_View 77 Offset 2176 + OpMemberDecorate %type_View 78 Offset 2180 + OpMemberDecorate %type_View 79 Offset 2184 + OpMemberDecorate %type_View 80 Offset 2188 + OpMemberDecorate %type_View 81 Offset 2192 + OpMemberDecorate %type_View 82 Offset 2196 + OpMemberDecorate %type_View 83 Offset 2200 + OpMemberDecorate %type_View 84 Offset 2204 + OpMemberDecorate %type_View 85 Offset 2208 + OpMemberDecorate %type_View 86 Offset 2212 + OpMemberDecorate %type_View 87 Offset 2216 + OpMemberDecorate %type_View 88 Offset 2220 + OpMemberDecorate %type_View 89 Offset 2224 + OpMemberDecorate %type_View 90 Offset 2228 + OpMemberDecorate %type_View 91 Offset 2232 + OpMemberDecorate %type_View 92 Offset 2236 + OpMemberDecorate %type_View 93 Offset 2240 + OpMemberDecorate %type_View 94 Offset 2256 + OpMemberDecorate %type_View 95 Offset 2268 + OpMemberDecorate %type_View 96 Offset 2272 + OpMemberDecorate %type_View 97 Offset 2304 + OpMemberDecorate %type_View 98 Offset 2336 + OpMemberDecorate %type_View 99 Offset 2352 + OpMemberDecorate %type_View 100 Offset 2368 + OpMemberDecorate %type_View 101 Offset 2372 + OpMemberDecorate %type_View 102 Offset 2376 + OpMemberDecorate %type_View 103 Offset 2380 + OpMemberDecorate %type_View 104 Offset 2384 + OpMemberDecorate %type_View 105 Offset 2388 + OpMemberDecorate %type_View 106 Offset 2392 + OpMemberDecorate %type_View 107 Offset 2396 + OpMemberDecorate %type_View 108 Offset 2400 + OpMemberDecorate %type_View 109 Offset 2404 + OpMemberDecorate %type_View 110 Offset 2408 + OpMemberDecorate %type_View 111 Offset 2412 + OpMemberDecorate %type_View 112 Offset 2416 + OpMemberDecorate %type_View 113 Offset 2428 + OpMemberDecorate %type_View 114 Offset 2432 + OpMemberDecorate %type_View 115 Offset 2444 + OpMemberDecorate %type_View 116 Offset 2448 + OpMemberDecorate %type_View 117 Offset 2452 + OpMemberDecorate %type_View 118 Offset 2456 + OpMemberDecorate %type_View 119 Offset 2460 + OpMemberDecorate %type_View 120 Offset 2464 + OpMemberDecorate %type_View 121 Offset 2468 + OpMemberDecorate %type_View 122 Offset 2472 + OpMemberDecorate %type_View 123 Offset 2476 + OpMemberDecorate %type_View 124 Offset 2480 + OpMemberDecorate %type_View 125 Offset 2484 + OpMemberDecorate %type_View 126 Offset 2488 + OpMemberDecorate %type_View 127 Offset 2492 + OpMemberDecorate %type_View 128 Offset 2496 + OpMemberDecorate %type_View 129 Offset 2512 + OpMemberDecorate %type_View 130 Offset 2516 + OpMemberDecorate %type_View 131 Offset 2520 + OpMemberDecorate %type_View 132 Offset 2524 + OpMemberDecorate %type_View 133 Offset 2528 + OpMemberDecorate %type_View 134 Offset 2544 + OpMemberDecorate %type_View 135 Offset 2556 + OpMemberDecorate %type_View 136 Offset 2560 + OpMemberDecorate %type_View 137 Offset 2576 + OpMemberDecorate %type_View 138 Offset 2580 + OpMemberDecorate %type_View 139 Offset 2584 + OpMemberDecorate %type_View 140 Offset 2588 + OpMemberDecorate %type_View 141 Offset 2592 + OpMemberDecorate %type_View 142 Offset 2608 + OpMemberDecorate %type_View 143 Offset 2720 + OpMemberDecorate %type_View 144 Offset 2724 + OpMemberDecorate %type_View 145 Offset 2728 + OpMemberDecorate %type_View 146 Offset 2732 + OpMemberDecorate %type_View 147 Offset 2736 + OpMemberDecorate %type_View 148 Offset 2740 + OpMemberDecorate %type_View 149 Offset 2744 + OpMemberDecorate %type_View 150 Offset 2748 + OpMemberDecorate %type_View 151 Offset 2752 + OpMemberDecorate %type_View 152 Offset 2764 + OpMemberDecorate %type_View 153 Offset 2768 + OpMemberDecorate %type_View 154 Offset 2832 + OpMemberDecorate %type_View 155 Offset 2896 + OpMemberDecorate %type_View 156 Offset 2900 + OpMemberDecorate %type_View 157 Offset 2904 + OpMemberDecorate %type_View 158 Offset 2908 + OpMemberDecorate %type_View 159 Offset 2912 + OpMemberDecorate %type_View 160 Offset 2920 + OpMemberDecorate %type_View 161 Offset 2924 + OpMemberDecorate %type_View 162 Offset 2928 + OpMemberDecorate %type_View 163 Offset 2940 + OpMemberDecorate %type_View 164 Offset 2944 + OpMemberDecorate %type_View 165 Offset 2956 + OpMemberDecorate %type_View 166 Offset 2960 + OpMemberDecorate %type_View 167 Offset 2968 + OpMemberDecorate %type_View 168 Offset 2972 + OpMemberDecorate %type_View 169 Offset 2976 + OpMemberDecorate %type_View 170 Offset 2988 + OpMemberDecorate %type_View 171 Offset 2992 + OpMemberDecorate %type_View 172 Offset 3004 + OpMemberDecorate %type_View 173 Offset 3008 + OpMemberDecorate %type_View 174 Offset 3020 + OpMemberDecorate %type_View 175 Offset 3024 + OpMemberDecorate %type_View 176 Offset 3036 + OpMemberDecorate %type_View 177 Offset 3040 + OpMemberDecorate %type_View 178 Offset 3044 + OpDecorate %type_View Block + OpDecorate %_arr_mat4v4float_uint_6 ArrayStride 64 + OpMemberDecorate %type_ShadowDepthPass 0 Offset 0 + OpMemberDecorate %type_ShadowDepthPass 1 Offset 4 + OpMemberDecorate %type_ShadowDepthPass 2 Offset 8 + OpMemberDecorate %type_ShadowDepthPass 3 Offset 12 + OpMemberDecorate %type_ShadowDepthPass 4 Offset 16 + OpMemberDecorate %type_ShadowDepthPass 5 Offset 20 + OpMemberDecorate %type_ShadowDepthPass 6 Offset 24 + OpMemberDecorate %type_ShadowDepthPass 7 Offset 28 + OpMemberDecorate %type_ShadowDepthPass 8 Offset 32 + OpMemberDecorate %type_ShadowDepthPass 9 Offset 36 + OpMemberDecorate %type_ShadowDepthPass 10 Offset 40 + OpMemberDecorate %type_ShadowDepthPass 11 Offset 44 + OpMemberDecorate %type_ShadowDepthPass 12 Offset 48 + OpMemberDecorate %type_ShadowDepthPass 13 Offset 52 + OpMemberDecorate %type_ShadowDepthPass 14 Offset 56 + OpMemberDecorate %type_ShadowDepthPass 15 Offset 60 + OpMemberDecorate %type_ShadowDepthPass 16 Offset 64 + OpMemberDecorate %type_ShadowDepthPass 17 Offset 68 + OpMemberDecorate %type_ShadowDepthPass 18 Offset 72 + OpMemberDecorate %type_ShadowDepthPass 19 Offset 76 + OpMemberDecorate %type_ShadowDepthPass 20 Offset 80 + OpMemberDecorate %type_ShadowDepthPass 21 Offset 84 + OpMemberDecorate %type_ShadowDepthPass 22 Offset 88 + OpMemberDecorate %type_ShadowDepthPass 23 Offset 92 + OpMemberDecorate %type_ShadowDepthPass 24 Offset 96 + OpMemberDecorate %type_ShadowDepthPass 25 Offset 100 + OpMemberDecorate %type_ShadowDepthPass 26 Offset 104 + OpMemberDecorate %type_ShadowDepthPass 27 Offset 108 + OpMemberDecorate %type_ShadowDepthPass 28 Offset 112 + OpMemberDecorate %type_ShadowDepthPass 29 Offset 116 + OpMemberDecorate %type_ShadowDepthPass 30 Offset 120 + OpMemberDecorate %type_ShadowDepthPass 31 Offset 124 + OpMemberDecorate %type_ShadowDepthPass 32 Offset 128 + OpMemberDecorate %type_ShadowDepthPass 33 Offset 132 + OpMemberDecorate %type_ShadowDepthPass 34 Offset 136 + OpMemberDecorate %type_ShadowDepthPass 35 Offset 140 + OpMemberDecorate %type_ShadowDepthPass 36 Offset 144 + OpMemberDecorate %type_ShadowDepthPass 37 Offset 148 + OpMemberDecorate %type_ShadowDepthPass 38 Offset 152 + OpMemberDecorate %type_ShadowDepthPass 39 Offset 156 + OpMemberDecorate %type_ShadowDepthPass 40 Offset 160 + OpMemberDecorate %type_ShadowDepthPass 41 Offset 164 + OpMemberDecorate %type_ShadowDepthPass 42 Offset 168 + OpMemberDecorate %type_ShadowDepthPass 43 Offset 172 + OpMemberDecorate %type_ShadowDepthPass 44 Offset 176 + OpMemberDecorate %type_ShadowDepthPass 45 Offset 180 + OpMemberDecorate %type_ShadowDepthPass 46 Offset 184 + OpMemberDecorate %type_ShadowDepthPass 47 Offset 188 + OpMemberDecorate %type_ShadowDepthPass 48 Offset 192 + OpMemberDecorate %type_ShadowDepthPass 49 Offset 196 + OpMemberDecorate %type_ShadowDepthPass 50 Offset 200 + OpMemberDecorate %type_ShadowDepthPass 51 Offset 204 + OpMemberDecorate %type_ShadowDepthPass 52 Offset 208 + OpMemberDecorate %type_ShadowDepthPass 53 Offset 212 + OpMemberDecorate %type_ShadowDepthPass 54 Offset 216 + OpMemberDecorate %type_ShadowDepthPass 55 Offset 220 + OpMemberDecorate %type_ShadowDepthPass 56 Offset 224 + OpMemberDecorate %type_ShadowDepthPass 57 Offset 228 + OpMemberDecorate %type_ShadowDepthPass 58 Offset 232 + OpMemberDecorate %type_ShadowDepthPass 59 Offset 236 + OpMemberDecorate %type_ShadowDepthPass 60 Offset 240 + OpMemberDecorate %type_ShadowDepthPass 61 Offset 244 + OpMemberDecorate %type_ShadowDepthPass 62 Offset 248 + OpMemberDecorate %type_ShadowDepthPass 63 Offset 252 + OpMemberDecorate %type_ShadowDepthPass 64 Offset 256 + OpMemberDecorate %type_ShadowDepthPass 65 Offset 260 + OpMemberDecorate %type_ShadowDepthPass 66 Offset 264 + OpMemberDecorate %type_ShadowDepthPass 67 Offset 268 + OpMemberDecorate %type_ShadowDepthPass 68 Offset 272 + OpMemberDecorate %type_ShadowDepthPass 68 MatrixStride 16 + OpMemberDecorate %type_ShadowDepthPass 68 ColMajor + OpMemberDecorate %type_ShadowDepthPass 69 Offset 336 + OpMemberDecorate %type_ShadowDepthPass 70 Offset 352 + OpMemberDecorate %type_ShadowDepthPass 71 Offset 368 + OpMemberDecorate %type_ShadowDepthPass 72 Offset 384 + OpMemberDecorate %type_ShadowDepthPass 73 Offset 396 + OpMemberDecorate %type_ShadowDepthPass 74 Offset 400 + OpMemberDecorate %type_ShadowDepthPass 75 Offset 412 + OpMemberDecorate %type_ShadowDepthPass 76 Offset 416 + OpMemberDecorate %type_ShadowDepthPass 77 Offset 420 + OpMemberDecorate %type_ShadowDepthPass 78 Offset 424 + OpMemberDecorate %type_ShadowDepthPass 79 Offset 428 + OpMemberDecorate %type_ShadowDepthPass 80 Offset 432 + OpMemberDecorate %type_ShadowDepthPass 81 Offset 436 + OpMemberDecorate %type_ShadowDepthPass 82 Offset 440 + OpMemberDecorate %type_ShadowDepthPass 83 Offset 444 + OpMemberDecorate %type_ShadowDepthPass 84 Offset 448 + OpMemberDecorate %type_ShadowDepthPass 85 Offset 452 + OpMemberDecorate %type_ShadowDepthPass 86 Offset 456 + OpMemberDecorate %type_ShadowDepthPass 87 Offset 460 + OpMemberDecorate %type_ShadowDepthPass 88 Offset 464 + OpMemberDecorate %type_ShadowDepthPass 88 MatrixStride 16 + OpMemberDecorate %type_ShadowDepthPass 88 ColMajor + OpMemberDecorate %type_ShadowDepthPass 89 Offset 528 + OpMemberDecorate %type_ShadowDepthPass 89 MatrixStride 16 + OpMemberDecorate %type_ShadowDepthPass 89 ColMajor + OpMemberDecorate %type_ShadowDepthPass 90 Offset 592 + OpMemberDecorate %type_ShadowDepthPass 91 Offset 608 + OpMemberDecorate %type_ShadowDepthPass 92 Offset 612 + OpMemberDecorate %type_ShadowDepthPass 93 Offset 616 + OpMemberDecorate %type_ShadowDepthPass 94 Offset 620 + OpMemberDecorate %type_ShadowDepthPass 95 Offset 624 + OpMemberDecorate %type_ShadowDepthPass 95 MatrixStride 16 + OpMemberDecorate %type_ShadowDepthPass 95 ColMajor + OpMemberDecorate %type_ShadowDepthPass 96 Offset 1008 + OpMemberDecorate %type_ShadowDepthPass 96 MatrixStride 16 + OpMemberDecorate %type_ShadowDepthPass 96 ColMajor + OpDecorate %type_ShadowDepthPass Block + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 +%mat4v4float = OpTypeMatrix %v4float 4 + %v3float = OpTypeVector %float 3 + %v2float = OpTypeVector %float 2 + %int = OpTypeInt 32 1 + %uint = OpTypeInt 32 0 + %uint_2 = OpConstant %uint 2 + %uint_7 = OpConstant %uint 7 + %uint_4 = OpConstant %uint 4 + %v2int = OpTypeVector %int 2 + %int_0 = OpConstant %int 0 + %int_1 = OpConstant %int 1 + %int_2 = OpConstant %int 2 + %float_3 = OpConstant %float 3 + %uint_0 = OpConstant %uint 0 + %uint_1 = OpConstant %uint 1 + %float_6 = OpConstant %float 6 + %57 = OpConstantComposite %v4float %float_6 %float_6 %float_6 %float_6 + %float_1 = OpConstant %float 1 + %int_79 = OpConstant %int 79 +%float_0_200000003 = OpConstant %float 0.200000003 +%float_n0_699999988 = OpConstant %float -0.699999988 + %float_2 = OpConstant %float 2 + %63 = OpConstantComposite %v2float %float_1 %float_2 + %float_n1 = OpConstant %float -1 + %float_10 = OpConstant %float 10 + %float_0_5 = OpConstant %float 0.5 + %67 = OpConstantComposite %v3float %float_0_5 %float_0_5 %float_0_5 + %int_88 = OpConstant %int 88 + %int_89 = OpConstant %int 89 + %int_90 = OpConstant %int 90 + %int_91 = OpConstant %int 91 + %float_0 = OpConstant %float 0 +%float_9_99999997en07 = OpConstant %float 9.99999997e-07 +%_arr_v4float_uint_2 = OpTypeArray %v4float %uint_2 +%_arr_v4float_uint_7 = OpTypeArray %v4float %uint_7 +%_arr_v4float_uint_4 = OpTypeArray %v4float %uint_4 + %type_View = OpTypeStruct %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %v3float %float %v3float %float %v3float %float %v3float %float %v3float %float %v4float %v4float %v3float %float %v3float %float %v3float %float %v3float %float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %v3float %float %v3float %float %v3float %float %mat4v4float %mat4v4float %mat4v4float %v4float %v4float %v2float %v2float %v4float %v4float %v4float %v4float %int %float %float %float %v4float %v4float %v4float %v2float %float %float %float %float %float %float %v3float %float %float %float %float %float %float %float %float %uint %uint %uint %uint %float %float %float %float %float %v4float %v3float %float %_arr_v4float_uint_2 %_arr_v4float_uint_2 %v4float %v4float %float %float %float %float %float %float %float %float %float %float %float %float %v3float %float %v3float %float %float %float %float %float %float %float %float %float %float %float %float %float %v4float %uint %uint %uint %uint %v4float %v3float %float %v4float %float %float %float %float %v4float %_arr_v4float_uint_7 %float %float %float %float %uint %float %float %float %v3float %int %_arr_v4float_uint_4 %_arr_v4float_uint_4 %float %float %float %float %v2int %float %float %v3float %float %v3float %float %v2float %float %float %v3float %float %v3float %float %v3float %float %v3float %float %float %float +%_ptr_Uniform_type_View = OpTypePointer Uniform %type_View +%type_sampler = OpTypeSampler +%_ptr_UniformConstant_type_sampler = OpTypePointer UniformConstant %type_sampler +%type_2d_image = OpTypeImage %float 2D 2 0 0 1 Unknown +%_ptr_UniformConstant_type_2d_image = OpTypePointer UniformConstant %type_2d_image + %uint_6 = OpConstant %uint 6 +%_arr_mat4v4float_uint_6 = OpTypeArray %mat4v4float %uint_6 + %v3int = OpTypeVector %int 3 +%type_ShadowDepthPass = OpTypeStruct %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %mat4v4float %v4float %v4float %v4float %v3int %int %v3int %float %float %float %float %float %float %float %float %float %float %float %float %int %mat4v4float %mat4v4float %v4float %float %float %float %float %_arr_mat4v4float_uint_6 %_arr_mat4v4float_uint_6 +%_ptr_Uniform_type_ShadowDepthPass = OpTypePointer Uniform %type_ShadowDepthPass + %uint_3 = OpConstant %uint 3 +%_arr_v4float_uint_3 = OpTypeArray %v4float %uint_3 +%_ptr_Input__arr_v4float_uint_3 = OpTypePointer Input %_arr_v4float_uint_3 +%_arr_v4float_uint_1 = OpTypeArray %v4float %uint_1 +%_arr__arr_v4float_uint_1_uint_3 = OpTypeArray %_arr_v4float_uint_1 %uint_3 +%_ptr_Input__arr__arr_v4float_uint_1_uint_3 = OpTypePointer Input %_arr__arr_v4float_uint_1_uint_3 +%_arr_uint_uint_3 = OpTypeArray %uint %uint_3 +%_ptr_Input__arr_uint_uint_3 = OpTypePointer Input %_arr_uint_uint_3 +%_arr__arr_v4float_uint_3_uint_3 = OpTypeArray %_arr_v4float_uint_3 %uint_3 +%_ptr_Input__arr__arr_v4float_uint_3_uint_3 = OpTypePointer Input %_arr__arr_v4float_uint_3_uint_3 +%_arr_v3float_uint_3 = OpTypeArray %v3float %uint_3 +%_ptr_Input__arr_v3float_uint_3 = OpTypePointer Input %_arr_v3float_uint_3 +%_arr_float_uint_3 = OpTypeArray %float %uint_3 +%_ptr_Input__arr_float_uint_3 = OpTypePointer Input %_arr_float_uint_3 +%_arr_float_uint_4 = OpTypeArray %float %uint_4 +%_ptr_Input__arr_float_uint_4 = OpTypePointer Input %_arr_float_uint_4 +%_arr_float_uint_2 = OpTypeArray %float %uint_2 +%_ptr_Input__arr_float_uint_2 = OpTypePointer Input %_arr_float_uint_2 +%_ptr_Input_v4float = OpTypePointer Input %v4float +%_ptr_Input_v3float = OpTypePointer Input %v3float +%_ptr_Output_v4float = OpTypePointer Output %v4float +%_ptr_Output__arr_v4float_uint_1 = OpTypePointer Output %_arr_v4float_uint_1 +%_ptr_Output_uint = OpTypePointer Output %uint +%_ptr_Output_float = OpTypePointer Output %float +%_ptr_Output_v3float = OpTypePointer Output %v3float + %void = OpTypeVoid + %106 = OpTypeFunction %void +%_ptr_Function_float = OpTypePointer Function %float + %bool = OpTypeBool +%_ptr_Uniform_float = OpTypePointer Uniform %float +%_ptr_Function_mat4v4float = OpTypePointer Function %mat4v4float +%_ptr_Uniform_mat4v4float = OpTypePointer Uniform %mat4v4float +%type_sampled_image = OpTypeSampledImage %type_2d_image + %View = OpVariable %_ptr_Uniform_type_View Uniform +%ShadowDepthPass = OpVariable %_ptr_Uniform_type_ShadowDepthPass Uniform +%Material_Texture2D_3 = OpVariable %_ptr_UniformConstant_type_2d_image UniformConstant +%Material_Texture2D_3Sampler = OpVariable %_ptr_UniformConstant_type_sampler UniformConstant +%in_var_TEXCOORD10_centroid = OpVariable %_ptr_Input__arr_v4float_uint_3 Input +%in_var_TEXCOORD11_centroid = OpVariable %_ptr_Input__arr_v4float_uint_3 Input +%in_var_COLOR0 = OpVariable %_ptr_Input__arr_v4float_uint_3 Input +%in_var_TEXCOORD0 = OpVariable %_ptr_Input__arr__arr_v4float_uint_1_uint_3 Input +%in_var_PRIMITIVE_ID = OpVariable %_ptr_Input__arr_uint_uint_3 Input +%in_var_VS_to_DS_Position = OpVariable %_ptr_Input__arr_v4float_uint_3 Input +%in_var_PN_POSITION = OpVariable %_ptr_Input__arr__arr_v4float_uint_3_uint_3 Input +%in_var_PN_DisplacementScales = OpVariable %_ptr_Input__arr_v3float_uint_3 Input +%in_var_PN_TessellationMultiplier = OpVariable %_ptr_Input__arr_float_uint_3 Input +%in_var_PN_WorldDisplacementMultiplier = OpVariable %_ptr_Input__arr_float_uint_3 Input +%gl_TessLevelOuter = OpVariable %_ptr_Input__arr_float_uint_4 Input +%gl_TessLevelInner = OpVariable %_ptr_Input__arr_float_uint_2 Input +%in_var_PN_POSITION9 = OpVariable %_ptr_Input_v4float Input +%gl_TessCoord = OpVariable %_ptr_Input_v3float Input +%out_var_TEXCOORD10_centroid = OpVariable %_ptr_Output_v4float Output +%out_var_TEXCOORD11_centroid = OpVariable %_ptr_Output_v4float Output +%out_var_COLOR0 = OpVariable %_ptr_Output_v4float Output +%out_var_TEXCOORD0 = OpVariable %_ptr_Output__arr_v4float_uint_1 Output +%out_var_PRIMITIVE_ID = OpVariable %_ptr_Output_uint Output +%out_var_TEXCOORD6 = OpVariable %_ptr_Output_float Output +%out_var_TEXCOORD8 = OpVariable %_ptr_Output_float Output +%out_var_TEXCOORD7 = OpVariable %_ptr_Output_v3float Output +%gl_Position = OpVariable %_ptr_Output_v4float Output + %112 = OpConstantNull %v4float + %113 = OpUndef %v4float +%_ptr_Input_uint = OpTypePointer Input %uint + %MainDomain = OpFunction %void None %106 + %115 = OpLabel + %116 = OpVariable %_ptr_Function_mat4v4float Function + %117 = OpLoad %_arr_v4float_uint_3 %in_var_TEXCOORD10_centroid + %118 = OpLoad %_arr_v4float_uint_3 %in_var_TEXCOORD11_centroid + %119 = OpLoad %_arr_v4float_uint_3 %in_var_COLOR0 + %120 = OpLoad %_arr__arr_v4float_uint_1_uint_3 %in_var_TEXCOORD0 + %121 = OpAccessChain %_ptr_Input_uint %in_var_PRIMITIVE_ID %uint_0 + %122 = OpLoad %uint %121 + %123 = OpCompositeExtract %v4float %117 0 + %124 = OpCompositeExtract %v4float %118 0 + %125 = OpCompositeExtract %v4float %119 0 + %126 = OpCompositeExtract %_arr_v4float_uint_1 %120 0 + %127 = OpCompositeExtract %v4float %117 1 + %128 = OpCompositeExtract %v4float %118 1 + %129 = OpCompositeExtract %v4float %119 1 + %130 = OpCompositeExtract %_arr_v4float_uint_1 %120 1 + %131 = OpCompositeExtract %v4float %117 2 + %132 = OpCompositeExtract %v4float %118 2 + %133 = OpCompositeExtract %v4float %119 2 + %134 = OpCompositeExtract %_arr_v4float_uint_1 %120 2 + %135 = OpLoad %_arr__arr_v4float_uint_3_uint_3 %in_var_PN_POSITION + %136 = OpLoad %_arr_float_uint_3 %in_var_PN_WorldDisplacementMultiplier + %137 = OpCompositeExtract %_arr_v4float_uint_3 %135 0 + %138 = OpCompositeExtract %float %136 0 + %139 = OpCompositeExtract %_arr_v4float_uint_3 %135 1 + %140 = OpCompositeExtract %float %136 1 + %141 = OpCompositeExtract %_arr_v4float_uint_3 %135 2 + %142 = OpCompositeExtract %float %136 2 + %143 = OpCompositeExtract %v4float %137 0 + %144 = OpCompositeExtract %v4float %137 1 + %145 = OpCompositeExtract %v4float %137 2 + %146 = OpCompositeExtract %v4float %139 0 + %147 = OpCompositeExtract %v4float %139 1 + %148 = OpCompositeExtract %v4float %139 2 + %149 = OpCompositeExtract %v4float %141 0 + %150 = OpCompositeExtract %v4float %141 1 + %151 = OpCompositeExtract %v4float %141 2 + %152 = OpLoad %v4float %in_var_PN_POSITION9 + %153 = OpLoad %v3float %gl_TessCoord + %154 = OpCompositeExtract %float %153 0 + %155 = OpCompositeExtract %float %153 1 + %156 = OpCompositeExtract %float %153 2 + %157 = OpFMul %float %154 %154 + %158 = OpFMul %float %155 %155 + %159 = OpFMul %float %156 %156 + %160 = OpFMul %float %157 %float_3 + %161 = OpFMul %float %158 %float_3 + %162 = OpFMul %float %159 %float_3 + %163 = OpCompositeConstruct %v4float %157 %157 %157 %157 + %164 = OpFMul %v4float %143 %163 + %165 = OpCompositeConstruct %v4float %154 %154 %154 %154 + %166 = OpFMul %v4float %164 %165 + %167 = OpCompositeConstruct %v4float %158 %158 %158 %158 + %168 = OpFMul %v4float %146 %167 + %169 = OpCompositeConstruct %v4float %155 %155 %155 %155 + %170 = OpFMul %v4float %168 %169 + %171 = OpFAdd %v4float %166 %170 + %172 = OpCompositeConstruct %v4float %159 %159 %159 %159 + %173 = OpFMul %v4float %149 %172 + %174 = OpCompositeConstruct %v4float %156 %156 %156 %156 + %175 = OpFMul %v4float %173 %174 + %176 = OpFAdd %v4float %171 %175 + %177 = OpCompositeConstruct %v4float %160 %160 %160 %160 + %178 = OpFMul %v4float %144 %177 + %179 = OpFMul %v4float %178 %169 + %180 = OpFAdd %v4float %176 %179 + %181 = OpCompositeConstruct %v4float %161 %161 %161 %161 + %182 = OpFMul %v4float %145 %181 + %183 = OpFMul %v4float %182 %165 + %184 = OpFAdd %v4float %180 %183 + %185 = OpFMul %v4float %147 %181 + %186 = OpFMul %v4float %185 %174 + %187 = OpFAdd %v4float %184 %186 + %188 = OpCompositeConstruct %v4float %162 %162 %162 %162 + %189 = OpFMul %v4float %148 %188 + %190 = OpFMul %v4float %189 %169 + %191 = OpFAdd %v4float %187 %190 + %192 = OpFMul %v4float %150 %188 + %193 = OpFMul %v4float %192 %165 + %194 = OpFAdd %v4float %191 %193 + %195 = OpFMul %v4float %151 %177 + %196 = OpFMul %v4float %195 %174 + %197 = OpFAdd %v4float %194 %196 + %198 = OpFMul %v4float %152 %57 + %199 = OpFMul %v4float %198 %174 + %200 = OpFMul %v4float %199 %165 + %201 = OpFMul %v4float %200 %169 + %202 = OpFAdd %v4float %197 %201 + %203 = OpCompositeExtract %v4float %126 0 + %204 = OpCompositeExtract %v4float %130 0 + %205 = OpVectorShuffle %v3float %123 %123 0 1 2 + %206 = OpCompositeConstruct %v3float %154 %154 %154 + %207 = OpFMul %v3float %205 %206 + %208 = OpVectorShuffle %v3float %127 %127 0 1 2 + %209 = OpCompositeConstruct %v3float %155 %155 %155 + %210 = OpFMul %v3float %208 %209 + %211 = OpFAdd %v3float %207 %210 + %212 = OpFMul %v4float %124 %165 + %213 = OpFMul %v4float %128 %169 + %214 = OpFAdd %v4float %212 %213 + %215 = OpFMul %v4float %125 %165 + %216 = OpFMul %v4float %129 %169 + %217 = OpFAdd %v4float %215 %216 + %218 = OpFMul %v4float %203 %165 + %219 = OpFMul %v4float %204 %169 + %220 = OpFAdd %v4float %218 %219 + %221 = OpCompositeExtract %v4float %134 0 + %222 = OpVectorShuffle %v3float %211 %112 0 1 2 + %223 = OpVectorShuffle %v3float %131 %131 0 1 2 + %224 = OpCompositeConstruct %v3float %156 %156 %156 + %225 = OpFMul %v3float %223 %224 + %226 = OpFAdd %v3float %222 %225 + %227 = OpVectorShuffle %v4float %113 %226 4 5 6 3 + %228 = OpFMul %v4float %132 %174 + %229 = OpFAdd %v4float %214 %228 + %230 = OpFMul %v4float %133 %174 + %231 = OpFAdd %v4float %217 %230 + %232 = OpFMul %v4float %221 %174 + %233 = OpFAdd %v4float %220 %232 + %234 = OpCompositeConstruct %_arr_v4float_uint_1 %233 + %235 = OpVectorShuffle %v2float %233 %233 2 3 + %236 = OpVectorShuffle %v3float %229 %229 0 1 2 + %237 = OpAccessChain %_ptr_Uniform_float %View %int_79 + %238 = OpLoad %float %237 + %239 = OpFMul %float %238 %float_0_200000003 + %240 = OpFMul %float %238 %float_n0_699999988 + %241 = OpFMul %v2float %235 %63 + %242 = OpCompositeConstruct %v2float %239 %240 + %243 = OpFAdd %v2float %242 %241 + %244 = OpLoad %type_2d_image %Material_Texture2D_3 + %245 = OpLoad %type_sampler %Material_Texture2D_3Sampler + %246 = OpSampledImage %type_sampled_image %244 %245 + %247 = OpImageSampleExplicitLod %v4float %246 %243 Lod %float_n1 + %248 = OpCompositeExtract %float %247 0 + %249 = OpFMul %float %248 %float_10 + %250 = OpCompositeExtract %float %231 0 + %251 = OpFSub %float %float_1 %250 + %252 = OpFMul %float %249 %251 + %253 = OpCompositeConstruct %v3float %252 %252 %252 + %254 = OpFMul %v3float %253 %236 + %255 = OpFMul %v3float %254 %67 + %256 = OpFMul %float %138 %154 + %257 = OpFMul %float %140 %155 + %258 = OpFAdd %float %256 %257 + %259 = OpFMul %float %142 %156 + %260 = OpFAdd %float %258 %259 + %261 = OpCompositeConstruct %v3float %260 %260 %260 + %262 = OpFMul %v3float %255 %261 + %263 = OpVectorShuffle %v3float %202 %202 0 1 2 + %264 = OpFAdd %v3float %263 %262 + %265 = OpVectorShuffle %v4float %202 %264 4 5 6 3 + %266 = OpAccessChain %_ptr_Uniform_mat4v4float %ShadowDepthPass %int_88 + %267 = OpLoad %mat4v4float %266 + %268 = OpAccessChain %_ptr_Uniform_mat4v4float %ShadowDepthPass %int_89 + %269 = OpLoad %mat4v4float %268 + OpStore %116 %269 + %270 = OpMatrixTimesVector %v4float %267 %265 + %271 = OpAccessChain %_ptr_Uniform_float %ShadowDepthPass %int_91 + %272 = OpLoad %float %271 + %273 = OpFOrdGreaterThan %bool %272 %float_0 + %274 = OpCompositeExtract %float %270 2 + %275 = OpFOrdLessThan %bool %274 %float_0 + %276 = OpLogicalAnd %bool %273 %275 + OpSelectionMerge %277 None + OpBranchConditional %276 %278 %277 + %278 = OpLabel + %279 = OpCompositeInsert %v4float %float_9_99999997en07 %270 2 + %280 = OpCompositeInsert %v4float %float_1 %279 3 + OpBranch %277 + %277 = OpLabel + %281 = OpPhi %v4float %270 %115 %280 %278 + %282 = OpAccessChain %_ptr_Function_float %116 %uint_0 %int_2 + %283 = OpLoad %float %282 + %284 = OpAccessChain %_ptr_Function_float %116 %uint_1 %int_2 + %285 = OpLoad %float %284 + %286 = OpAccessChain %_ptr_Function_float %116 %uint_2 %int_2 + %287 = OpLoad %float %286 + %288 = OpCompositeConstruct %v3float %283 %285 %287 + %289 = OpDot %float %288 %236 + %290 = OpExtInst %float %1 FAbs %289 + %291 = OpAccessChain %_ptr_Uniform_float %ShadowDepthPass %int_90 %int_2 + %292 = OpLoad %float %291 + %293 = OpExtInst %float %1 FAbs %290 + %294 = OpFOrdGreaterThan %bool %293 %float_0 + %295 = OpFMul %float %290 %290 + %296 = OpFSub %float %float_1 %295 + %297 = OpExtInst %float %1 FClamp %296 %float_0 %float_1 + %298 = OpExtInst %float %1 Sqrt %297 + %299 = OpFDiv %float %298 %290 + %300 = OpSelect %float %294 %299 %292 + %301 = OpExtInst %float %1 FClamp %300 %float_0 %292 + %302 = OpAccessChain %_ptr_Uniform_float %ShadowDepthPass %int_90 %int_1 + %303 = OpLoad %float %302 + %304 = OpFMul %float %303 %301 + %305 = OpAccessChain %_ptr_Uniform_float %ShadowDepthPass %int_90 %int_0 + %306 = OpLoad %float %305 + %307 = OpFAdd %float %304 %306 + %308 = OpCompositeExtract %float %281 2 + %309 = OpVectorShuffle %v3float %264 %112 0 1 2 + OpStore %out_var_TEXCOORD10_centroid %227 + OpStore %out_var_TEXCOORD11_centroid %229 + OpStore %out_var_COLOR0 %231 + OpStore %out_var_TEXCOORD0 %234 + OpStore %out_var_PRIMITIVE_ID %122 + OpStore %out_var_TEXCOORD6 %308 + OpStore %out_var_TEXCOORD8 %307 + OpStore %out_var_TEXCOORD7 %309 + OpStore %gl_Position %281 + OpReturn + OpFunctionEnd diff --git a/third_party/spirv-cross/shaders-ue4/asm/tese/ds-patch-input-fixes.asm.tese b/third_party/spirv-cross/shaders-ue4/asm/tese/ds-patch-input-fixes.asm.tese new file mode 100644 index 0000000000..cb55bb4250 --- /dev/null +++ b/third_party/spirv-cross/shaders-ue4/asm/tese/ds-patch-input-fixes.asm.tese @@ -0,0 +1,1175 @@ +; SPIR-V +; Version: 1.0 +; Generator: Google spiregg; 0 +; Bound: 581 +; Schema: 0 + OpCapability Tessellation + OpCapability ClipDistance + OpCapability SampledBuffer + OpExtension "SPV_GOOGLE_hlsl_functionality1" + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint TessellationEvaluation %MainDomain "main" %gl_ClipDistance %in_var_TEXCOORD6 %in_var_TEXCOORD8 %in_var_TEXCOORD10_centroid %in_var_TEXCOORD11_centroid %in_var_VS_To_DS_Position %in_var_VS_To_DS_VertexID %in_var_PN_POSITION %in_var_PN_DisplacementScales %in_var_PN_TessellationMultiplier %in_var_PN_WorldDisplacementMultiplier %in_var_PN_DominantVertex %in_var_PN_DominantVertex1 %in_var_PN_DominantVertex2 %in_var_PN_DominantEdge %in_var_PN_DominantEdge1 %in_var_PN_DominantEdge2 %in_var_PN_DominantEdge3 %in_var_PN_DominantEdge4 %in_var_PN_DominantEdge5 %gl_TessLevelOuter %gl_TessLevelInner %in_var_PN_POSITION9 %gl_TessCoord %gl_Position %out_var_TEXCOORD6 %out_var_TEXCOORD7 %out_var_TEXCOORD10_centroid %out_var_TEXCOORD11_centroid + OpExecutionMode %MainDomain Triangles + OpExecutionMode %MainDomain SpacingFractionalOdd + OpExecutionMode %MainDomain VertexOrderCw + OpSource HLSL 600 + OpName %type_View "type.View" + OpMemberName %type_View 0 "View_TranslatedWorldToClip" + OpMemberName %type_View 1 "View_WorldToClip" + OpMemberName %type_View 2 "View_ClipToWorld" + OpMemberName %type_View 3 "View_TranslatedWorldToView" + OpMemberName %type_View 4 "View_ViewToTranslatedWorld" + OpMemberName %type_View 5 "View_TranslatedWorldToCameraView" + OpMemberName %type_View 6 "View_CameraViewToTranslatedWorld" + OpMemberName %type_View 7 "View_ViewToClip" + OpMemberName %type_View 8 "View_ViewToClipNoAA" + OpMemberName %type_View 9 "View_ClipToView" + OpMemberName %type_View 10 "View_ClipToTranslatedWorld" + OpMemberName %type_View 11 "View_SVPositionToTranslatedWorld" + OpMemberName %type_View 12 "View_ScreenToWorld" + OpMemberName %type_View 13 "View_ScreenToTranslatedWorld" + OpMemberName %type_View 14 "View_ViewForward" + OpMemberName %type_View 15 "PrePadding_View_908" + OpMemberName %type_View 16 "View_ViewUp" + OpMemberName %type_View 17 "PrePadding_View_924" + OpMemberName %type_View 18 "View_ViewRight" + OpMemberName %type_View 19 "PrePadding_View_940" + OpMemberName %type_View 20 "View_HMDViewNoRollUp" + OpMemberName %type_View 21 "PrePadding_View_956" + OpMemberName %type_View 22 "View_HMDViewNoRollRight" + OpMemberName %type_View 23 "PrePadding_View_972" + OpMemberName %type_View 24 "View_InvDeviceZToWorldZTransform" + OpMemberName %type_View 25 "View_ScreenPositionScaleBias" + OpMemberName %type_View 26 "View_WorldCameraOrigin" + OpMemberName %type_View 27 "PrePadding_View_1020" + OpMemberName %type_View 28 "View_TranslatedWorldCameraOrigin" + OpMemberName %type_View 29 "PrePadding_View_1036" + OpMemberName %type_View 30 "View_WorldViewOrigin" + OpMemberName %type_View 31 "PrePadding_View_1052" + OpMemberName %type_View 32 "View_PreViewTranslation" + OpMemberName %type_View 33 "PrePadding_View_1068" + OpMemberName %type_View 34 "View_PrevProjection" + OpMemberName %type_View 35 "View_PrevViewProj" + OpMemberName %type_View 36 "View_PrevViewRotationProj" + OpMemberName %type_View 37 "View_PrevViewToClip" + OpMemberName %type_View 38 "View_PrevClipToView" + OpMemberName %type_View 39 "View_PrevTranslatedWorldToClip" + OpMemberName %type_View 40 "View_PrevTranslatedWorldToView" + OpMemberName %type_View 41 "View_PrevViewToTranslatedWorld" + OpMemberName %type_View 42 "View_PrevTranslatedWorldToCameraView" + OpMemberName %type_View 43 "View_PrevCameraViewToTranslatedWorld" + OpMemberName %type_View 44 "View_PrevWorldCameraOrigin" + OpMemberName %type_View 45 "PrePadding_View_1724" + OpMemberName %type_View 46 "View_PrevWorldViewOrigin" + OpMemberName %type_View 47 "PrePadding_View_1740" + OpMemberName %type_View 48 "View_PrevPreViewTranslation" + OpMemberName %type_View 49 "PrePadding_View_1756" + OpMemberName %type_View 50 "View_PrevInvViewProj" + OpMemberName %type_View 51 "View_PrevScreenToTranslatedWorld" + OpMemberName %type_View 52 "View_ClipToPrevClip" + OpMemberName %type_View 53 "View_TemporalAAJitter" + OpMemberName %type_View 54 "View_GlobalClippingPlane" + OpMemberName %type_View 55 "View_FieldOfViewWideAngles" + OpMemberName %type_View 56 "View_PrevFieldOfViewWideAngles" + OpMemberName %type_View 57 "View_ViewRectMin" + OpMemberName %type_View 58 "View_ViewSizeAndInvSize" + OpMemberName %type_View 59 "View_BufferSizeAndInvSize" + OpMemberName %type_View 60 "View_BufferBilinearUVMinMax" + OpMemberName %type_View 61 "View_NumSceneColorMSAASamples" + OpMemberName %type_View 62 "View_PreExposure" + OpMemberName %type_View 63 "View_OneOverPreExposure" + OpMemberName %type_View 64 "PrePadding_View_2076" + OpMemberName %type_View 65 "View_DiffuseOverrideParameter" + OpMemberName %type_View 66 "View_SpecularOverrideParameter" + OpMemberName %type_View 67 "View_NormalOverrideParameter" + OpMemberName %type_View 68 "View_RoughnessOverrideParameter" + OpMemberName %type_View 69 "View_PrevFrameGameTime" + OpMemberName %type_View 70 "View_PrevFrameRealTime" + OpMemberName %type_View 71 "View_OutOfBoundsMask" + OpMemberName %type_View 72 "PrePadding_View_2148" + OpMemberName %type_View 73 "PrePadding_View_2152" + OpMemberName %type_View 74 "PrePadding_View_2156" + OpMemberName %type_View 75 "View_WorldCameraMovementSinceLastFrame" + OpMemberName %type_View 76 "View_CullingSign" + OpMemberName %type_View 77 "View_NearPlane" + OpMemberName %type_View 78 "View_AdaptiveTessellationFactor" + OpMemberName %type_View 79 "View_GameTime" + OpMemberName %type_View 80 "View_RealTime" + OpMemberName %type_View 81 "View_DeltaTime" + OpMemberName %type_View 82 "View_MaterialTextureMipBias" + OpMemberName %type_View 83 "View_MaterialTextureDerivativeMultiply" + OpMemberName %type_View 84 "View_Random" + OpMemberName %type_View 85 "View_FrameNumber" + OpMemberName %type_View 86 "View_StateFrameIndexMod8" + OpMemberName %type_View 87 "View_StateFrameIndex" + OpMemberName %type_View 88 "View_CameraCut" + OpMemberName %type_View 89 "View_UnlitViewmodeMask" + OpMemberName %type_View 90 "PrePadding_View_2228" + OpMemberName %type_View 91 "PrePadding_View_2232" + OpMemberName %type_View 92 "PrePadding_View_2236" + OpMemberName %type_View 93 "View_DirectionalLightColor" + OpMemberName %type_View 94 "View_DirectionalLightDirection" + OpMemberName %type_View 95 "PrePadding_View_2268" + OpMemberName %type_View 96 "View_TranslucencyLightingVolumeMin" + OpMemberName %type_View 97 "View_TranslucencyLightingVolumeInvSize" + OpMemberName %type_View 98 "View_TemporalAAParams" + OpMemberName %type_View 99 "View_CircleDOFParams" + OpMemberName %type_View 100 "View_DepthOfFieldSensorWidth" + OpMemberName %type_View 101 "View_DepthOfFieldFocalDistance" + OpMemberName %type_View 102 "View_DepthOfFieldScale" + OpMemberName %type_View 103 "View_DepthOfFieldFocalLength" + OpMemberName %type_View 104 "View_DepthOfFieldFocalRegion" + OpMemberName %type_View 105 "View_DepthOfFieldNearTransitionRegion" + OpMemberName %type_View 106 "View_DepthOfFieldFarTransitionRegion" + OpMemberName %type_View 107 "View_MotionBlurNormalizedToPixel" + OpMemberName %type_View 108 "View_bSubsurfacePostprocessEnabled" + OpMemberName %type_View 109 "View_GeneralPurposeTweak" + OpMemberName %type_View 110 "View_DemosaicVposOffset" + OpMemberName %type_View 111 "PrePadding_View_2412" + OpMemberName %type_View 112 "View_IndirectLightingColorScale" + OpMemberName %type_View 113 "View_HDR32bppEncodingMode" + OpMemberName %type_View 114 "View_AtmosphericFogSunDirection" + OpMemberName %type_View 115 "View_AtmosphericFogSunPower" + OpMemberName %type_View 116 "View_AtmosphericFogPower" + OpMemberName %type_View 117 "View_AtmosphericFogDensityScale" + OpMemberName %type_View 118 "View_AtmosphericFogDensityOffset" + OpMemberName %type_View 119 "View_AtmosphericFogGroundOffset" + OpMemberName %type_View 120 "View_AtmosphericFogDistanceScale" + OpMemberName %type_View 121 "View_AtmosphericFogAltitudeScale" + OpMemberName %type_View 122 "View_AtmosphericFogHeightScaleRayleigh" + OpMemberName %type_View 123 "View_AtmosphericFogStartDistance" + OpMemberName %type_View 124 "View_AtmosphericFogDistanceOffset" + OpMemberName %type_View 125 "View_AtmosphericFogSunDiscScale" + OpMemberName %type_View 126 "View_AtmosphericFogSunDiscHalfApexAngleRadian" + OpMemberName %type_View 127 "PrePadding_View_2492" + OpMemberName %type_View 128 "View_AtmosphericFogSunDiscLuminance" + OpMemberName %type_View 129 "View_AtmosphericFogRenderMask" + OpMemberName %type_View 130 "View_AtmosphericFogInscatterAltitudeSampleNum" + OpMemberName %type_View 131 "PrePadding_View_2520" + OpMemberName %type_View 132 "PrePadding_View_2524" + OpMemberName %type_View 133 "View_AtmosphericFogSunColor" + OpMemberName %type_View 134 "View_NormalCurvatureToRoughnessScaleBias" + OpMemberName %type_View 135 "View_RenderingReflectionCaptureMask" + OpMemberName %type_View 136 "View_AmbientCubemapTint" + OpMemberName %type_View 137 "View_AmbientCubemapIntensity" + OpMemberName %type_View 138 "View_SkyLightParameters" + OpMemberName %type_View 139 "PrePadding_View_2584" + OpMemberName %type_View 140 "PrePadding_View_2588" + OpMemberName %type_View 141 "View_SkyLightColor" + OpMemberName %type_View 142 "View_SkyIrradianceEnvironmentMap" + OpMemberName %type_View 143 "View_MobilePreviewMode" + OpMemberName %type_View 144 "View_HMDEyePaddingOffset" + OpMemberName %type_View 145 "View_ReflectionCubemapMaxMip" + OpMemberName %type_View 146 "View_ShowDecalsMask" + OpMemberName %type_View 147 "View_DistanceFieldAOSpecularOcclusionMode" + OpMemberName %type_View 148 "View_IndirectCapsuleSelfShadowingIntensity" + OpMemberName %type_View 149 "PrePadding_View_2744" + OpMemberName %type_View 150 "PrePadding_View_2748" + OpMemberName %type_View 151 "View_ReflectionEnvironmentRoughnessMixingScaleBiasAndLargestWeight" + OpMemberName %type_View 152 "View_StereoPassIndex" + OpMemberName %type_View 153 "View_GlobalVolumeCenterAndExtent" + OpMemberName %type_View 154 "View_GlobalVolumeWorldToUVAddAndMul" + OpMemberName %type_View 155 "View_GlobalVolumeDimension" + OpMemberName %type_View 156 "View_GlobalVolumeTexelSize" + OpMemberName %type_View 157 "View_MaxGlobalDistance" + OpMemberName %type_View 158 "PrePadding_View_2908" + OpMemberName %type_View 159 "View_CursorPosition" + OpMemberName %type_View 160 "View_bCheckerboardSubsurfaceProfileRendering" + OpMemberName %type_View 161 "PrePadding_View_2924" + OpMemberName %type_View 162 "View_VolumetricFogInvGridSize" + OpMemberName %type_View 163 "PrePadding_View_2940" + OpMemberName %type_View 164 "View_VolumetricFogGridZParams" + OpMemberName %type_View 165 "PrePadding_View_2956" + OpMemberName %type_View 166 "View_VolumetricFogSVPosToVolumeUV" + OpMemberName %type_View 167 "View_VolumetricFogMaxDistance" + OpMemberName %type_View 168 "PrePadding_View_2972" + OpMemberName %type_View 169 "View_VolumetricLightmapWorldToUVScale" + OpMemberName %type_View 170 "PrePadding_View_2988" + OpMemberName %type_View 171 "View_VolumetricLightmapWorldToUVAdd" + OpMemberName %type_View 172 "PrePadding_View_3004" + OpMemberName %type_View 173 "View_VolumetricLightmapIndirectionTextureSize" + OpMemberName %type_View 174 "View_VolumetricLightmapBrickSize" + OpMemberName %type_View 175 "View_VolumetricLightmapBrickTexelSize" + OpMemberName %type_View 176 "View_StereoIPD" + OpMemberName %type_View 177 "View_IndirectLightingCacheShowFlag" + OpMemberName %type_View 178 "View_EyeToPixelSpreadAngle" + OpMemberName %type_View 179 "PrePadding_View_3048" + OpMemberName %type_View 180 "PrePadding_View_3052" + OpMemberName %type_View 181 "View_WorldToVirtualTexture" + OpMemberName %type_View 182 "View_VirtualTextureParams" + OpMemberName %type_View 183 "View_XRPassthroughCameraUVs" + OpName %View "View" + OpName %type_sampler "type.sampler" + OpName %type_3d_image "type.3d.image" + OpName %View_GlobalDistanceFieldTexture0 "View_GlobalDistanceFieldTexture0" + OpName %View_GlobalDistanceFieldSampler0 "View_GlobalDistanceFieldSampler0" + OpName %View_GlobalDistanceFieldTexture1 "View_GlobalDistanceFieldTexture1" + OpName %View_GlobalDistanceFieldTexture2 "View_GlobalDistanceFieldTexture2" + OpName %View_GlobalDistanceFieldTexture3 "View_GlobalDistanceFieldTexture3" + OpName %type_Material "type.Material" + OpMemberName %type_Material 0 "Material_VectorExpressions" + OpMemberName %type_Material 1 "Material_ScalarExpressions" + OpName %Material "Material" + OpName %in_var_TEXCOORD6 "in.var.TEXCOORD6" + OpName %in_var_TEXCOORD8 "in.var.TEXCOORD8" + OpName %in_var_TEXCOORD10_centroid "in.var.TEXCOORD10_centroid" + OpName %in_var_TEXCOORD11_centroid "in.var.TEXCOORD11_centroid" + OpName %in_var_VS_To_DS_Position "in.var.VS_To_DS_Position" + OpName %in_var_VS_To_DS_VertexID "in.var.VS_To_DS_VertexID" + OpName %in_var_PN_POSITION "in.var.PN_POSITION" + OpName %in_var_PN_DisplacementScales "in.var.PN_DisplacementScales" + OpName %in_var_PN_TessellationMultiplier "in.var.PN_TessellationMultiplier" + OpName %in_var_PN_WorldDisplacementMultiplier "in.var.PN_WorldDisplacementMultiplier" + OpName %in_var_PN_DominantVertex "in.var.PN_DominantVertex" + OpName %in_var_PN_DominantVertex1 "in.var.PN_DominantVertex1" + OpName %in_var_PN_DominantVertex2 "in.var.PN_DominantVertex2" + OpName %in_var_PN_DominantEdge "in.var.PN_DominantEdge" + OpName %in_var_PN_DominantEdge1 "in.var.PN_DominantEdge1" + OpName %in_var_PN_DominantEdge2 "in.var.PN_DominantEdge2" + OpName %in_var_PN_DominantEdge3 "in.var.PN_DominantEdge3" + OpName %in_var_PN_DominantEdge4 "in.var.PN_DominantEdge4" + OpName %in_var_PN_DominantEdge5 "in.var.PN_DominantEdge5" + OpName %in_var_PN_POSITION9 "in.var.PN_POSITION9" + OpName %out_var_TEXCOORD6 "out.var.TEXCOORD6" + OpName %out_var_TEXCOORD7 "out.var.TEXCOORD7" + OpName %out_var_TEXCOORD10_centroid "out.var.TEXCOORD10_centroid" + OpName %out_var_TEXCOORD11_centroid "out.var.TEXCOORD11_centroid" + OpName %MainDomain "MainDomain" + OpName %type_sampled_image "type.sampled.image" + OpDecorate %gl_ClipDistance BuiltIn ClipDistance + OpDecorateString %gl_ClipDistance UserSemantic "SV_ClipDistance" + OpDecorateString %in_var_TEXCOORD6 UserSemantic "TEXCOORD6" + OpDecorateString %in_var_TEXCOORD8 UserSemantic "TEXCOORD8" + OpDecorateString %in_var_TEXCOORD10_centroid UserSemantic "TEXCOORD10_centroid" + OpDecorateString %in_var_TEXCOORD11_centroid UserSemantic "TEXCOORD11_centroid" + OpDecorateString %in_var_VS_To_DS_Position UserSemantic "VS_To_DS_Position" + OpDecorateString %in_var_VS_To_DS_VertexID UserSemantic "VS_To_DS_VertexID" + OpDecorateString %in_var_PN_POSITION UserSemantic "PN_POSITION" + OpDecorateString %in_var_PN_DisplacementScales UserSemantic "PN_DisplacementScales" + OpDecorateString %in_var_PN_TessellationMultiplier UserSemantic "PN_TessellationMultiplier" + OpDecorateString %in_var_PN_WorldDisplacementMultiplier UserSemantic "PN_WorldDisplacementMultiplier" + OpDecorateString %in_var_PN_DominantVertex UserSemantic "PN_DominantVertex" + OpDecorateString %in_var_PN_DominantVertex1 UserSemantic "PN_DominantVertex" + OpDecorateString %in_var_PN_DominantVertex2 UserSemantic "PN_DominantVertex" + OpDecorateString %in_var_PN_DominantEdge UserSemantic "PN_DominantEdge" + OpDecorateString %in_var_PN_DominantEdge1 UserSemantic "PN_DominantEdge" + OpDecorateString %in_var_PN_DominantEdge2 UserSemantic "PN_DominantEdge" + OpDecorateString %in_var_PN_DominantEdge3 UserSemantic "PN_DominantEdge" + OpDecorateString %in_var_PN_DominantEdge4 UserSemantic "PN_DominantEdge" + OpDecorateString %in_var_PN_DominantEdge5 UserSemantic "PN_DominantEdge" + OpDecorate %gl_TessLevelOuter BuiltIn TessLevelOuter + OpDecorateString %gl_TessLevelOuter UserSemantic "SV_TessFactor" + OpDecorate %gl_TessLevelOuter Patch + OpDecorate %gl_TessLevelInner BuiltIn TessLevelInner + OpDecorateString %gl_TessLevelInner UserSemantic "SV_InsideTessFactor" + OpDecorate %gl_TessLevelInner Patch + OpDecorateString %in_var_PN_POSITION9 UserSemantic "PN_POSITION9" + OpDecorate %in_var_PN_POSITION9 Patch + OpDecorate %gl_TessCoord BuiltIn TessCoord + OpDecorateString %gl_TessCoord UserSemantic "SV_DomainLocation" + OpDecorate %gl_TessCoord Patch + OpDecorate %gl_Position BuiltIn Position + OpDecorateString %gl_Position UserSemantic "SV_POSITION" + OpDecorateString %out_var_TEXCOORD6 UserSemantic "TEXCOORD6" + OpDecorateString %out_var_TEXCOORD7 UserSemantic "TEXCOORD7" + OpDecorateString %out_var_TEXCOORD10_centroid UserSemantic "TEXCOORD10_centroid" + OpDecorateString %out_var_TEXCOORD11_centroid UserSemantic "TEXCOORD11_centroid" + OpDecorate %in_var_PN_DisplacementScales Location 0 + OpDecorate %in_var_PN_DominantEdge Location 1 + OpDecorate %in_var_PN_DominantEdge1 Location 2 + OpDecorate %in_var_PN_DominantEdge2 Location 3 + OpDecorate %in_var_PN_DominantEdge3 Location 4 + OpDecorate %in_var_PN_DominantEdge4 Location 5 + OpDecorate %in_var_PN_DominantEdge5 Location 6 + OpDecorate %in_var_PN_DominantVertex Location 7 + OpDecorate %in_var_PN_DominantVertex1 Location 8 + OpDecorate %in_var_PN_DominantVertex2 Location 9 + OpDecorate %in_var_PN_POSITION Location 10 + OpDecorate %in_var_PN_POSITION9 Location 13 + OpDecorate %in_var_PN_TessellationMultiplier Location 14 + OpDecorate %in_var_PN_WorldDisplacementMultiplier Location 15 + OpDecorate %in_var_TEXCOORD10_centroid Location 16 + OpDecorate %in_var_TEXCOORD11_centroid Location 17 + OpDecorate %in_var_TEXCOORD6 Location 18 + OpDecorate %in_var_TEXCOORD8 Location 19 + OpDecorate %in_var_VS_To_DS_Position Location 20 + OpDecorate %in_var_VS_To_DS_VertexID Location 21 + OpDecorate %out_var_TEXCOORD6 Location 0 + OpDecorate %out_var_TEXCOORD7 Location 1 + OpDecorate %out_var_TEXCOORD10_centroid Location 2 + OpDecorate %out_var_TEXCOORD11_centroid Location 3 + OpDecorate %View DescriptorSet 0 + OpDecorate %View Binding 0 + OpDecorate %View_GlobalDistanceFieldTexture0 DescriptorSet 0 + OpDecorate %View_GlobalDistanceFieldTexture0 Binding 0 + OpDecorate %View_GlobalDistanceFieldSampler0 DescriptorSet 0 + OpDecorate %View_GlobalDistanceFieldSampler0 Binding 0 + OpDecorate %View_GlobalDistanceFieldTexture1 DescriptorSet 0 + OpDecorate %View_GlobalDistanceFieldTexture1 Binding 1 + OpDecorate %View_GlobalDistanceFieldTexture2 DescriptorSet 0 + OpDecorate %View_GlobalDistanceFieldTexture2 Binding 2 + OpDecorate %View_GlobalDistanceFieldTexture3 DescriptorSet 0 + OpDecorate %View_GlobalDistanceFieldTexture3 Binding 3 + OpDecorate %Material DescriptorSet 0 + OpDecorate %Material Binding 1 + OpDecorate %_arr_v4float_uint_2 ArrayStride 16 + OpDecorate %_arr_v4float_uint_7 ArrayStride 16 + OpDecorate %_arr_v4float_uint_4 ArrayStride 16 + OpMemberDecorate %type_View 0 Offset 0 + OpMemberDecorate %type_View 0 MatrixStride 16 + OpMemberDecorate %type_View 0 ColMajor + OpMemberDecorate %type_View 1 Offset 64 + OpMemberDecorate %type_View 1 MatrixStride 16 + OpMemberDecorate %type_View 1 ColMajor + OpMemberDecorate %type_View 2 Offset 128 + OpMemberDecorate %type_View 2 MatrixStride 16 + OpMemberDecorate %type_View 2 ColMajor + OpMemberDecorate %type_View 3 Offset 192 + OpMemberDecorate %type_View 3 MatrixStride 16 + OpMemberDecorate %type_View 3 ColMajor + OpMemberDecorate %type_View 4 Offset 256 + OpMemberDecorate %type_View 4 MatrixStride 16 + OpMemberDecorate %type_View 4 ColMajor + OpMemberDecorate %type_View 5 Offset 320 + OpMemberDecorate %type_View 5 MatrixStride 16 + OpMemberDecorate %type_View 5 ColMajor + OpMemberDecorate %type_View 6 Offset 384 + OpMemberDecorate %type_View 6 MatrixStride 16 + OpMemberDecorate %type_View 6 ColMajor + OpMemberDecorate %type_View 7 Offset 448 + OpMemberDecorate %type_View 7 MatrixStride 16 + OpMemberDecorate %type_View 7 ColMajor + OpMemberDecorate %type_View 8 Offset 512 + OpMemberDecorate %type_View 8 MatrixStride 16 + OpMemberDecorate %type_View 8 ColMajor + OpMemberDecorate %type_View 9 Offset 576 + OpMemberDecorate %type_View 9 MatrixStride 16 + OpMemberDecorate %type_View 9 ColMajor + OpMemberDecorate %type_View 10 Offset 640 + OpMemberDecorate %type_View 10 MatrixStride 16 + OpMemberDecorate %type_View 10 ColMajor + OpMemberDecorate %type_View 11 Offset 704 + OpMemberDecorate %type_View 11 MatrixStride 16 + OpMemberDecorate %type_View 11 ColMajor + OpMemberDecorate %type_View 12 Offset 768 + OpMemberDecorate %type_View 12 MatrixStride 16 + OpMemberDecorate %type_View 12 ColMajor + OpMemberDecorate %type_View 13 Offset 832 + OpMemberDecorate %type_View 13 MatrixStride 16 + OpMemberDecorate %type_View 13 ColMajor + OpMemberDecorate %type_View 14 Offset 896 + OpMemberDecorate %type_View 15 Offset 908 + OpMemberDecorate %type_View 16 Offset 912 + OpMemberDecorate %type_View 17 Offset 924 + OpMemberDecorate %type_View 18 Offset 928 + OpMemberDecorate %type_View 19 Offset 940 + OpMemberDecorate %type_View 20 Offset 944 + OpMemberDecorate %type_View 21 Offset 956 + OpMemberDecorate %type_View 22 Offset 960 + OpMemberDecorate %type_View 23 Offset 972 + OpMemberDecorate %type_View 24 Offset 976 + OpMemberDecorate %type_View 25 Offset 992 + OpMemberDecorate %type_View 26 Offset 1008 + OpMemberDecorate %type_View 27 Offset 1020 + OpMemberDecorate %type_View 28 Offset 1024 + OpMemberDecorate %type_View 29 Offset 1036 + OpMemberDecorate %type_View 30 Offset 1040 + OpMemberDecorate %type_View 31 Offset 1052 + OpMemberDecorate %type_View 32 Offset 1056 + OpMemberDecorate %type_View 33 Offset 1068 + OpMemberDecorate %type_View 34 Offset 1072 + OpMemberDecorate %type_View 34 MatrixStride 16 + OpMemberDecorate %type_View 34 ColMajor + OpMemberDecorate %type_View 35 Offset 1136 + OpMemberDecorate %type_View 35 MatrixStride 16 + OpMemberDecorate %type_View 35 ColMajor + OpMemberDecorate %type_View 36 Offset 1200 + OpMemberDecorate %type_View 36 MatrixStride 16 + OpMemberDecorate %type_View 36 ColMajor + OpMemberDecorate %type_View 37 Offset 1264 + OpMemberDecorate %type_View 37 MatrixStride 16 + OpMemberDecorate %type_View 37 ColMajor + OpMemberDecorate %type_View 38 Offset 1328 + OpMemberDecorate %type_View 38 MatrixStride 16 + OpMemberDecorate %type_View 38 ColMajor + OpMemberDecorate %type_View 39 Offset 1392 + OpMemberDecorate %type_View 39 MatrixStride 16 + OpMemberDecorate %type_View 39 ColMajor + OpMemberDecorate %type_View 40 Offset 1456 + OpMemberDecorate %type_View 40 MatrixStride 16 + OpMemberDecorate %type_View 40 ColMajor + OpMemberDecorate %type_View 41 Offset 1520 + OpMemberDecorate %type_View 41 MatrixStride 16 + OpMemberDecorate %type_View 41 ColMajor + OpMemberDecorate %type_View 42 Offset 1584 + OpMemberDecorate %type_View 42 MatrixStride 16 + OpMemberDecorate %type_View 42 ColMajor + OpMemberDecorate %type_View 43 Offset 1648 + OpMemberDecorate %type_View 43 MatrixStride 16 + OpMemberDecorate %type_View 43 ColMajor + OpMemberDecorate %type_View 44 Offset 1712 + OpMemberDecorate %type_View 45 Offset 1724 + OpMemberDecorate %type_View 46 Offset 1728 + OpMemberDecorate %type_View 47 Offset 1740 + OpMemberDecorate %type_View 48 Offset 1744 + OpMemberDecorate %type_View 49 Offset 1756 + OpMemberDecorate %type_View 50 Offset 1760 + OpMemberDecorate %type_View 50 MatrixStride 16 + OpMemberDecorate %type_View 50 ColMajor + OpMemberDecorate %type_View 51 Offset 1824 + OpMemberDecorate %type_View 51 MatrixStride 16 + OpMemberDecorate %type_View 51 ColMajor + OpMemberDecorate %type_View 52 Offset 1888 + OpMemberDecorate %type_View 52 MatrixStride 16 + OpMemberDecorate %type_View 52 ColMajor + OpMemberDecorate %type_View 53 Offset 1952 + OpMemberDecorate %type_View 54 Offset 1968 + OpMemberDecorate %type_View 55 Offset 1984 + OpMemberDecorate %type_View 56 Offset 1992 + OpMemberDecorate %type_View 57 Offset 2000 + OpMemberDecorate %type_View 58 Offset 2016 + OpMemberDecorate %type_View 59 Offset 2032 + OpMemberDecorate %type_View 60 Offset 2048 + OpMemberDecorate %type_View 61 Offset 2064 + OpMemberDecorate %type_View 62 Offset 2068 + OpMemberDecorate %type_View 63 Offset 2072 + OpMemberDecorate %type_View 64 Offset 2076 + OpMemberDecorate %type_View 65 Offset 2080 + OpMemberDecorate %type_View 66 Offset 2096 + OpMemberDecorate %type_View 67 Offset 2112 + OpMemberDecorate %type_View 68 Offset 2128 + OpMemberDecorate %type_View 69 Offset 2136 + OpMemberDecorate %type_View 70 Offset 2140 + OpMemberDecorate %type_View 71 Offset 2144 + OpMemberDecorate %type_View 72 Offset 2148 + OpMemberDecorate %type_View 73 Offset 2152 + OpMemberDecorate %type_View 74 Offset 2156 + OpMemberDecorate %type_View 75 Offset 2160 + OpMemberDecorate %type_View 76 Offset 2172 + OpMemberDecorate %type_View 77 Offset 2176 + OpMemberDecorate %type_View 78 Offset 2180 + OpMemberDecorate %type_View 79 Offset 2184 + OpMemberDecorate %type_View 80 Offset 2188 + OpMemberDecorate %type_View 81 Offset 2192 + OpMemberDecorate %type_View 82 Offset 2196 + OpMemberDecorate %type_View 83 Offset 2200 + OpMemberDecorate %type_View 84 Offset 2204 + OpMemberDecorate %type_View 85 Offset 2208 + OpMemberDecorate %type_View 86 Offset 2212 + OpMemberDecorate %type_View 87 Offset 2216 + OpMemberDecorate %type_View 88 Offset 2220 + OpMemberDecorate %type_View 89 Offset 2224 + OpMemberDecorate %type_View 90 Offset 2228 + OpMemberDecorate %type_View 91 Offset 2232 + OpMemberDecorate %type_View 92 Offset 2236 + OpMemberDecorate %type_View 93 Offset 2240 + OpMemberDecorate %type_View 94 Offset 2256 + OpMemberDecorate %type_View 95 Offset 2268 + OpMemberDecorate %type_View 96 Offset 2272 + OpMemberDecorate %type_View 97 Offset 2304 + OpMemberDecorate %type_View 98 Offset 2336 + OpMemberDecorate %type_View 99 Offset 2352 + OpMemberDecorate %type_View 100 Offset 2368 + OpMemberDecorate %type_View 101 Offset 2372 + OpMemberDecorate %type_View 102 Offset 2376 + OpMemberDecorate %type_View 103 Offset 2380 + OpMemberDecorate %type_View 104 Offset 2384 + OpMemberDecorate %type_View 105 Offset 2388 + OpMemberDecorate %type_View 106 Offset 2392 + OpMemberDecorate %type_View 107 Offset 2396 + OpMemberDecorate %type_View 108 Offset 2400 + OpMemberDecorate %type_View 109 Offset 2404 + OpMemberDecorate %type_View 110 Offset 2408 + OpMemberDecorate %type_View 111 Offset 2412 + OpMemberDecorate %type_View 112 Offset 2416 + OpMemberDecorate %type_View 113 Offset 2428 + OpMemberDecorate %type_View 114 Offset 2432 + OpMemberDecorate %type_View 115 Offset 2444 + OpMemberDecorate %type_View 116 Offset 2448 + OpMemberDecorate %type_View 117 Offset 2452 + OpMemberDecorate %type_View 118 Offset 2456 + OpMemberDecorate %type_View 119 Offset 2460 + OpMemberDecorate %type_View 120 Offset 2464 + OpMemberDecorate %type_View 121 Offset 2468 + OpMemberDecorate %type_View 122 Offset 2472 + OpMemberDecorate %type_View 123 Offset 2476 + OpMemberDecorate %type_View 124 Offset 2480 + OpMemberDecorate %type_View 125 Offset 2484 + OpMemberDecorate %type_View 126 Offset 2488 + OpMemberDecorate %type_View 127 Offset 2492 + OpMemberDecorate %type_View 128 Offset 2496 + OpMemberDecorate %type_View 129 Offset 2512 + OpMemberDecorate %type_View 130 Offset 2516 + OpMemberDecorate %type_View 131 Offset 2520 + OpMemberDecorate %type_View 132 Offset 2524 + OpMemberDecorate %type_View 133 Offset 2528 + OpMemberDecorate %type_View 134 Offset 2544 + OpMemberDecorate %type_View 135 Offset 2556 + OpMemberDecorate %type_View 136 Offset 2560 + OpMemberDecorate %type_View 137 Offset 2576 + OpMemberDecorate %type_View 138 Offset 2580 + OpMemberDecorate %type_View 139 Offset 2584 + OpMemberDecorate %type_View 140 Offset 2588 + OpMemberDecorate %type_View 141 Offset 2592 + OpMemberDecorate %type_View 142 Offset 2608 + OpMemberDecorate %type_View 143 Offset 2720 + OpMemberDecorate %type_View 144 Offset 2724 + OpMemberDecorate %type_View 145 Offset 2728 + OpMemberDecorate %type_View 146 Offset 2732 + OpMemberDecorate %type_View 147 Offset 2736 + OpMemberDecorate %type_View 148 Offset 2740 + OpMemberDecorate %type_View 149 Offset 2744 + OpMemberDecorate %type_View 150 Offset 2748 + OpMemberDecorate %type_View 151 Offset 2752 + OpMemberDecorate %type_View 152 Offset 2764 + OpMemberDecorate %type_View 153 Offset 2768 + OpMemberDecorate %type_View 154 Offset 2832 + OpMemberDecorate %type_View 155 Offset 2896 + OpMemberDecorate %type_View 156 Offset 2900 + OpMemberDecorate %type_View 157 Offset 2904 + OpMemberDecorate %type_View 158 Offset 2908 + OpMemberDecorate %type_View 159 Offset 2912 + OpMemberDecorate %type_View 160 Offset 2920 + OpMemberDecorate %type_View 161 Offset 2924 + OpMemberDecorate %type_View 162 Offset 2928 + OpMemberDecorate %type_View 163 Offset 2940 + OpMemberDecorate %type_View 164 Offset 2944 + OpMemberDecorate %type_View 165 Offset 2956 + OpMemberDecorate %type_View 166 Offset 2960 + OpMemberDecorate %type_View 167 Offset 2968 + OpMemberDecorate %type_View 168 Offset 2972 + OpMemberDecorate %type_View 169 Offset 2976 + OpMemberDecorate %type_View 170 Offset 2988 + OpMemberDecorate %type_View 171 Offset 2992 + OpMemberDecorate %type_View 172 Offset 3004 + OpMemberDecorate %type_View 173 Offset 3008 + OpMemberDecorate %type_View 174 Offset 3020 + OpMemberDecorate %type_View 175 Offset 3024 + OpMemberDecorate %type_View 176 Offset 3036 + OpMemberDecorate %type_View 177 Offset 3040 + OpMemberDecorate %type_View 178 Offset 3044 + OpMemberDecorate %type_View 179 Offset 3048 + OpMemberDecorate %type_View 180 Offset 3052 + OpMemberDecorate %type_View 181 Offset 3056 + OpMemberDecorate %type_View 181 MatrixStride 16 + OpMemberDecorate %type_View 181 ColMajor + OpMemberDecorate %type_View 182 Offset 3120 + OpMemberDecorate %type_View 183 Offset 3136 + OpDecorate %type_View Block + OpDecorate %_arr_v4float_uint_5 ArrayStride 16 + OpMemberDecorate %type_Material 0 Offset 0 + OpMemberDecorate %type_Material 1 Offset 80 + OpDecorate %type_Material Block + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 +%mat4v4float = OpTypeMatrix %v4float 4 + %v3float = OpTypeVector %float 3 + %v2float = OpTypeVector %float 2 + %int = OpTypeInt 32 1 + %uint = OpTypeInt 32 0 + %uint_2 = OpConstant %uint 2 + %uint_7 = OpConstant %uint 7 + %uint_4 = OpConstant %uint 4 + %v2int = OpTypeVector %int 2 +%float_0_00100000005 = OpConstant %float 0.00100000005 + %uint_0 = OpConstant %uint 0 + %int_0 = OpConstant %int 0 + %int_1 = OpConstant %int 1 + %int_2 = OpConstant %int 2 + %float_3 = OpConstant %float 3 + %uint_1 = OpConstant %uint 1 + %float_6 = OpConstant %float 6 + %67 = OpConstantComposite %v4float %float_6 %float_6 %float_6 %float_6 + %float_1 = OpConstant %float 1 + %float_0 = OpConstant %float 0 + %int_3 = OpConstant %int 3 + %float_2 = OpConstant %float 2 + %int_26 = OpConstant %int 26 + %int_32 = OpConstant %int 32 + %int_54 = OpConstant %int 54 + %int_153 = OpConstant %int 153 + %int_154 = OpConstant %int 154 + %int_156 = OpConstant %int 156 + %int_157 = OpConstant %int 157 + %float_10 = OpConstant %float 10 + %uint_3 = OpConstant %uint 3 + %81 = OpConstantComposite %v3float %float_0 %float_0 %float_0 +%_arr_v4float_uint_2 = OpTypeArray %v4float %uint_2 +%_arr_v4float_uint_7 = OpTypeArray %v4float %uint_7 +%_arr_v4float_uint_4 = OpTypeArray %v4float %uint_4 + %type_View = OpTypeStruct %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %v3float %float %v3float %float %v3float %float %v3float %float %v3float %float %v4float %v4float %v3float %float %v3float %float %v3float %float %v3float %float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %v3float %float %v3float %float %v3float %float %mat4v4float %mat4v4float %mat4v4float %v4float %v4float %v2float %v2float %v4float %v4float %v4float %v4float %int %float %float %float %v4float %v4float %v4float %v2float %float %float %float %float %float %float %v3float %float %float %float %float %float %float %float %float %uint %uint %uint %uint %float %float %float %float %float %v4float %v3float %float %_arr_v4float_uint_2 %_arr_v4float_uint_2 %v4float %v4float %float %float %float %float %float %float %float %float %float %float %float %float %v3float %float %v3float %float %float %float %float %float %float %float %float %float %float %float %float %float %v4float %uint %uint %uint %uint %v4float %v3float %float %v4float %float %float %float %float %v4float %_arr_v4float_uint_7 %float %float %float %float %uint %float %float %float %v3float %int %_arr_v4float_uint_4 %_arr_v4float_uint_4 %float %float %float %float %v2int %float %float %v3float %float %v3float %float %v2float %float %float %v3float %float %v3float %float %v3float %float %v3float %float %float %float %float %float %mat4v4float %v4float %_arr_v4float_uint_2 +%_ptr_Uniform_type_View = OpTypePointer Uniform %type_View +%type_sampler = OpTypeSampler +%_ptr_UniformConstant_type_sampler = OpTypePointer UniformConstant %type_sampler +%type_3d_image = OpTypeImage %float 3D 2 0 0 1 Unknown +%_ptr_UniformConstant_type_3d_image = OpTypePointer UniformConstant %type_3d_image + %uint_5 = OpConstant %uint 5 +%_arr_v4float_uint_5 = OpTypeArray %v4float %uint_5 +%type_Material = OpTypeStruct %_arr_v4float_uint_5 %_arr_v4float_uint_2 +%_ptr_Uniform_type_Material = OpTypePointer Uniform %type_Material +%_arr_float_uint_1 = OpTypeArray %float %uint_1 +%_ptr_Output__arr_float_uint_1 = OpTypePointer Output %_arr_float_uint_1 +%_arr_v4float_uint_3 = OpTypeArray %v4float %uint_3 +%_ptr_Input__arr_v4float_uint_3 = OpTypePointer Input %_arr_v4float_uint_3 +%_arr_uint_uint_3 = OpTypeArray %uint %uint_3 +%_ptr_Input__arr_uint_uint_3 = OpTypePointer Input %_arr_uint_uint_3 +%_arr__arr_v4float_uint_3_uint_3 = OpTypeArray %_arr_v4float_uint_3 %uint_3 +%_ptr_Input__arr__arr_v4float_uint_3_uint_3 = OpTypePointer Input %_arr__arr_v4float_uint_3_uint_3 +%_arr_v3float_uint_3 = OpTypeArray %v3float %uint_3 +%_ptr_Input__arr_v3float_uint_3 = OpTypePointer Input %_arr_v3float_uint_3 +%_arr_float_uint_3 = OpTypeArray %float %uint_3 +%_ptr_Input__arr_float_uint_3 = OpTypePointer Input %_arr_float_uint_3 +%_arr_v2float_uint_3 = OpTypeArray %v2float %uint_3 +%_ptr_Input__arr_v2float_uint_3 = OpTypePointer Input %_arr_v2float_uint_3 +%_arr_float_uint_4 = OpTypeArray %float %uint_4 +%_ptr_Input__arr_float_uint_4 = OpTypePointer Input %_arr_float_uint_4 +%_arr_float_uint_2 = OpTypeArray %float %uint_2 +%_ptr_Input__arr_float_uint_2 = OpTypePointer Input %_arr_float_uint_2 +%_ptr_Input_v4float = OpTypePointer Input %v4float +%_ptr_Input_v3float = OpTypePointer Input %v3float +%_ptr_Output_v4float = OpTypePointer Output %v4float + %void = OpTypeVoid + %109 = OpTypeFunction %void +%_ptr_Output_float = OpTypePointer Output %float +%mat3v3float = OpTypeMatrix %v3float 3 + %bool = OpTypeBool +%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float +%_ptr_Uniform_float = OpTypePointer Uniform %float +%_ptr_Uniform_mat4v4float = OpTypePointer Uniform %mat4v4float +%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float +%type_sampled_image = OpTypeSampledImage %type_3d_image + %View = OpVariable %_ptr_Uniform_type_View Uniform +%View_GlobalDistanceFieldTexture0 = OpVariable %_ptr_UniformConstant_type_3d_image UniformConstant +%View_GlobalDistanceFieldSampler0 = OpVariable %_ptr_UniformConstant_type_sampler UniformConstant +%View_GlobalDistanceFieldTexture1 = OpVariable %_ptr_UniformConstant_type_3d_image UniformConstant +%View_GlobalDistanceFieldTexture2 = OpVariable %_ptr_UniformConstant_type_3d_image UniformConstant +%View_GlobalDistanceFieldTexture3 = OpVariable %_ptr_UniformConstant_type_3d_image UniformConstant + %Material = OpVariable %_ptr_Uniform_type_Material Uniform +%gl_ClipDistance = OpVariable %_ptr_Output__arr_float_uint_1 Output +%in_var_TEXCOORD6 = OpVariable %_ptr_Input__arr_v4float_uint_3 Input +%in_var_TEXCOORD8 = OpVariable %_ptr_Input__arr_v4float_uint_3 Input +%in_var_TEXCOORD10_centroid = OpVariable %_ptr_Input__arr_v4float_uint_3 Input +%in_var_TEXCOORD11_centroid = OpVariable %_ptr_Input__arr_v4float_uint_3 Input +%in_var_VS_To_DS_Position = OpVariable %_ptr_Input__arr_v4float_uint_3 Input +%in_var_VS_To_DS_VertexID = OpVariable %_ptr_Input__arr_uint_uint_3 Input +%in_var_PN_POSITION = OpVariable %_ptr_Input__arr__arr_v4float_uint_3_uint_3 Input +%in_var_PN_DisplacementScales = OpVariable %_ptr_Input__arr_v3float_uint_3 Input +%in_var_PN_TessellationMultiplier = OpVariable %_ptr_Input__arr_float_uint_3 Input +%in_var_PN_WorldDisplacementMultiplier = OpVariable %_ptr_Input__arr_float_uint_3 Input +%in_var_PN_DominantVertex = OpVariable %_ptr_Input__arr_v2float_uint_3 Input +%in_var_PN_DominantVertex1 = OpVariable %_ptr_Input__arr_v4float_uint_3 Input +%in_var_PN_DominantVertex2 = OpVariable %_ptr_Input__arr_v3float_uint_3 Input +%in_var_PN_DominantEdge = OpVariable %_ptr_Input__arr_v2float_uint_3 Input +%in_var_PN_DominantEdge1 = OpVariable %_ptr_Input__arr_v2float_uint_3 Input +%in_var_PN_DominantEdge2 = OpVariable %_ptr_Input__arr_v4float_uint_3 Input +%in_var_PN_DominantEdge3 = OpVariable %_ptr_Input__arr_v4float_uint_3 Input +%in_var_PN_DominantEdge4 = OpVariable %_ptr_Input__arr_v3float_uint_3 Input +%in_var_PN_DominantEdge5 = OpVariable %_ptr_Input__arr_v3float_uint_3 Input +%gl_TessLevelOuter = OpVariable %_ptr_Input__arr_float_uint_4 Input +%gl_TessLevelInner = OpVariable %_ptr_Input__arr_float_uint_2 Input +%in_var_PN_POSITION9 = OpVariable %_ptr_Input_v4float Input +%gl_TessCoord = OpVariable %_ptr_Input_v3float Input +%gl_Position = OpVariable %_ptr_Output_v4float Output +%out_var_TEXCOORD6 = OpVariable %_ptr_Output_v4float Output +%out_var_TEXCOORD7 = OpVariable %_ptr_Output_v4float Output +%out_var_TEXCOORD10_centroid = OpVariable %_ptr_Output_v4float Output +%out_var_TEXCOORD11_centroid = OpVariable %_ptr_Output_v4float Output + %117 = OpConstantNull %v4float + %118 = OpUndef %v4float + %MainDomain = OpFunction %void None %109 + %119 = OpLabel + %120 = OpLoad %_arr_v4float_uint_3 %in_var_TEXCOORD6 + %121 = OpLoad %_arr_v4float_uint_3 %in_var_TEXCOORD8 + %122 = OpCompositeExtract %v4float %120 0 + %123 = OpCompositeExtract %v4float %121 0 + %124 = OpCompositeExtract %v4float %120 1 + %125 = OpCompositeExtract %v4float %121 1 + %126 = OpCompositeExtract %v4float %120 2 + %127 = OpCompositeExtract %v4float %121 2 + %128 = OpLoad %_arr_v4float_uint_3 %in_var_TEXCOORD10_centroid + %129 = OpLoad %_arr_v4float_uint_3 %in_var_TEXCOORD11_centroid + %130 = OpCompositeExtract %v4float %128 0 + %131 = OpCompositeExtract %v4float %129 0 + %132 = OpCompositeExtract %v4float %128 1 + %133 = OpCompositeExtract %v4float %129 1 + %134 = OpCompositeExtract %v4float %128 2 + %135 = OpCompositeExtract %v4float %129 2 + %136 = OpLoad %_arr__arr_v4float_uint_3_uint_3 %in_var_PN_POSITION + %137 = OpLoad %_arr_float_uint_3 %in_var_PN_WorldDisplacementMultiplier + %138 = OpLoad %_arr_v4float_uint_3 %in_var_PN_DominantVertex1 + %139 = OpLoad %_arr_v3float_uint_3 %in_var_PN_DominantVertex2 + %140 = OpCompositeExtract %v4float %138 0 + %141 = OpCompositeExtract %v3float %139 0 + %142 = OpCompositeExtract %v4float %138 1 + %143 = OpCompositeExtract %v3float %139 1 + %144 = OpCompositeExtract %v4float %138 2 + %145 = OpCompositeExtract %v3float %139 2 + %146 = OpLoad %_arr_v4float_uint_3 %in_var_PN_DominantEdge2 + %147 = OpLoad %_arr_v4float_uint_3 %in_var_PN_DominantEdge3 + %148 = OpLoad %_arr_v3float_uint_3 %in_var_PN_DominantEdge4 + %149 = OpLoad %_arr_v3float_uint_3 %in_var_PN_DominantEdge5 + %150 = OpCompositeExtract %v4float %146 0 + %151 = OpCompositeExtract %v4float %147 0 + %152 = OpCompositeExtract %v3float %148 0 + %153 = OpCompositeExtract %v3float %149 0 + %154 = OpCompositeExtract %v4float %146 1 + %155 = OpCompositeExtract %v4float %147 1 + %156 = OpCompositeExtract %v3float %148 1 + %157 = OpCompositeExtract %v3float %149 1 + %158 = OpCompositeExtract %v4float %146 2 + %159 = OpCompositeExtract %v4float %147 2 + %160 = OpCompositeExtract %v3float %148 2 + %161 = OpCompositeExtract %v3float %149 2 + %162 = OpCompositeExtract %_arr_v4float_uint_3 %136 0 + %163 = OpCompositeExtract %float %137 0 + %164 = OpCompositeExtract %_arr_v4float_uint_3 %136 1 + %165 = OpCompositeExtract %float %137 1 + %166 = OpCompositeExtract %_arr_v4float_uint_3 %136 2 + %167 = OpCompositeExtract %float %137 2 + %168 = OpCompositeExtract %v4float %162 0 + %169 = OpCompositeExtract %v4float %162 1 + %170 = OpCompositeExtract %v4float %162 2 + %171 = OpCompositeExtract %v4float %164 0 + %172 = OpCompositeExtract %v4float %164 1 + %173 = OpCompositeExtract %v4float %164 2 + %174 = OpCompositeExtract %v4float %166 0 + %175 = OpCompositeExtract %v4float %166 1 + %176 = OpCompositeExtract %v4float %166 2 + %177 = OpLoad %v4float %in_var_PN_POSITION9 + %178 = OpLoad %v3float %gl_TessCoord + %179 = OpAccessChain %_ptr_Uniform_mat4v4float %View %int_0 + %180 = OpLoad %mat4v4float %179 + %181 = OpAccessChain %_ptr_Uniform_v3float %View %int_26 + %182 = OpLoad %v3float %181 + %183 = OpAccessChain %_ptr_Uniform_v3float %View %int_32 + %184 = OpLoad %v3float %183 + %185 = OpAccessChain %_ptr_Uniform_v4float %View %int_54 + %186 = OpLoad %v4float %185 + %187 = OpCompositeExtract %float %178 0 + %188 = OpCompositeExtract %float %178 1 + %189 = OpCompositeExtract %float %178 2 + %190 = OpFMul %float %187 %187 + %191 = OpFMul %float %188 %188 + %192 = OpFMul %float %189 %189 + %193 = OpFMul %float %190 %float_3 + %194 = OpFMul %float %191 %float_3 + %195 = OpFMul %float %192 %float_3 + %196 = OpCompositeConstruct %v4float %190 %190 %190 %190 + %197 = OpFMul %v4float %168 %196 + %198 = OpCompositeConstruct %v4float %187 %187 %187 %187 + %199 = OpFMul %v4float %197 %198 + %200 = OpCompositeConstruct %v4float %191 %191 %191 %191 + %201 = OpFMul %v4float %171 %200 + %202 = OpCompositeConstruct %v4float %188 %188 %188 %188 + %203 = OpFMul %v4float %201 %202 + %204 = OpFAdd %v4float %199 %203 + %205 = OpCompositeConstruct %v4float %192 %192 %192 %192 + %206 = OpFMul %v4float %174 %205 + %207 = OpCompositeConstruct %v4float %189 %189 %189 %189 + %208 = OpFMul %v4float %206 %207 + %209 = OpFAdd %v4float %204 %208 + %210 = OpCompositeConstruct %v4float %193 %193 %193 %193 + %211 = OpFMul %v4float %169 %210 + %212 = OpFMul %v4float %211 %202 + %213 = OpFAdd %v4float %209 %212 + %214 = OpCompositeConstruct %v4float %194 %194 %194 %194 + %215 = OpFMul %v4float %170 %214 + %216 = OpFMul %v4float %215 %198 + %217 = OpFAdd %v4float %213 %216 + %218 = OpFMul %v4float %172 %214 + %219 = OpFMul %v4float %218 %207 + %220 = OpFAdd %v4float %217 %219 + %221 = OpCompositeConstruct %v4float %195 %195 %195 %195 + %222 = OpFMul %v4float %173 %221 + %223 = OpFMul %v4float %222 %202 + %224 = OpFAdd %v4float %220 %223 + %225 = OpFMul %v4float %175 %221 + %226 = OpFMul %v4float %225 %198 + %227 = OpFAdd %v4float %224 %226 + %228 = OpFMul %v4float %176 %210 + %229 = OpFMul %v4float %228 %207 + %230 = OpFAdd %v4float %227 %229 + %231 = OpFMul %v4float %177 %67 + %232 = OpFMul %v4float %231 %207 + %233 = OpFMul %v4float %232 %198 + %234 = OpFMul %v4float %233 %202 + %235 = OpFAdd %v4float %230 %234 + %236 = OpVectorShuffle %v3float %130 %130 0 1 2 + %237 = OpCompositeConstruct %v3float %187 %187 %187 + %238 = OpFMul %v3float %236 %237 + %239 = OpVectorShuffle %v3float %132 %132 0 1 2 + %240 = OpCompositeConstruct %v3float %188 %188 %188 + %241 = OpFMul %v3float %239 %240 + %242 = OpFAdd %v3float %238 %241 + %243 = OpFMul %v4float %131 %198 + %244 = OpFMul %v4float %133 %202 + %245 = OpFAdd %v4float %243 %244 + %246 = OpFMul %v4float %122 %198 + %247 = OpFMul %v4float %124 %202 + %248 = OpFAdd %v4float %246 %247 + %249 = OpFMul %v4float %123 %198 + %250 = OpFMul %v4float %125 %202 + %251 = OpFAdd %v4float %249 %250 + %252 = OpVectorShuffle %v3float %242 %117 0 1 2 + %253 = OpVectorShuffle %v3float %134 %134 0 1 2 + %254 = OpCompositeConstruct %v3float %189 %189 %189 + %255 = OpFMul %v3float %253 %254 + %256 = OpFAdd %v3float %252 %255 + %257 = OpVectorShuffle %v4float %118 %256 4 5 6 3 + %258 = OpFMul %v4float %135 %207 + %259 = OpFAdd %v4float %245 %258 + %260 = OpFMul %v4float %126 %207 + %261 = OpFAdd %v4float %248 %260 + %262 = OpFMul %v4float %127 %207 + %263 = OpFAdd %v4float %251 %262 + %264 = OpVectorShuffle %v3float %235 %235 0 1 2 + %265 = OpVectorShuffle %v3float %256 %117 0 1 2 + %266 = OpVectorShuffle %v3float %259 %259 0 1 2 + %267 = OpExtInst %v3float %1 Cross %266 %265 + %268 = OpCompositeExtract %float %259 3 + %269 = OpCompositeConstruct %v3float %268 %268 %268 + %270 = OpFMul %v3float %267 %269 + %271 = OpCompositeConstruct %mat3v3float %265 %270 %266 + %272 = OpFAdd %v3float %264 %182 + %273 = OpCompositeExtract %float %259 0 + %274 = OpCompositeExtract %float %259 1 + %275 = OpCompositeExtract %float %259 2 + %276 = OpCompositeConstruct %v4float %273 %274 %275 %float_0 + %277 = OpFOrdEqual %bool %187 %float_0 + %278 = OpSelect %int %277 %int_1 %int_0 + %279 = OpConvertSToF %float %278 + %280 = OpFOrdEqual %bool %188 %float_0 + %281 = OpSelect %int %280 %int_1 %int_0 + %282 = OpConvertSToF %float %281 + %283 = OpFOrdEqual %bool %189 %float_0 + %284 = OpSelect %int %283 %int_1 %int_0 + %285 = OpConvertSToF %float %284 + %286 = OpFAdd %float %279 %282 + %287 = OpFAdd %float %286 %285 + %288 = OpFOrdEqual %bool %287 %float_2 + %289 = OpSelect %int %288 %int_1 %int_0 + %290 = OpConvertSToF %float %289 + %291 = OpFOrdEqual %bool %287 %float_1 + %292 = OpSelect %int %291 %int_1 %int_0 + %293 = OpConvertSToF %float %292 + %294 = OpFOrdEqual %bool %287 %float_0 + %295 = OpSelect %int %294 %int_1 %int_0 + %296 = OpConvertSToF %float %295 + %297 = OpFOrdEqual %bool %290 %float_1 + OpSelectionMerge %298 None + OpBranchConditional %297 %299 %300 + %300 = OpLabel + %301 = OpFOrdNotEqual %bool %293 %float_0 + OpSelectionMerge %302 None + OpBranchConditional %301 %303 %302 + %303 = OpLabel + %304 = OpCompositeConstruct %v4float %279 %279 %279 %279 + %305 = OpFMul %v4float %304 %150 + %306 = OpCompositeConstruct %v4float %282 %282 %282 %282 + %307 = OpFMul %v4float %306 %154 + %308 = OpFAdd %v4float %305 %307 + %309 = OpCompositeConstruct %v4float %285 %285 %285 %285 + %310 = OpFMul %v4float %309 %158 + %311 = OpFAdd %v4float %308 %310 + %312 = OpFMul %v4float %304 %151 + %313 = OpFMul %v4float %306 %155 + %314 = OpFAdd %v4float %312 %313 + %315 = OpFMul %v4float %309 %159 + %316 = OpFAdd %v4float %314 %315 + %317 = OpFMul %v4float %202 %311 + %318 = OpFMul %v4float %207 %316 + %319 = OpFAdd %v4float %317 %318 + %320 = OpFMul %v4float %304 %319 + %321 = OpFMul %v4float %207 %311 + %322 = OpFMul %v4float %198 %316 + %323 = OpFAdd %v4float %321 %322 + %324 = OpFMul %v4float %306 %323 + %325 = OpFAdd %v4float %320 %324 + %326 = OpFMul %v4float %198 %311 + %327 = OpFMul %v4float %202 %316 + %328 = OpFAdd %v4float %326 %327 + %329 = OpFMul %v4float %309 %328 + %330 = OpFAdd %v4float %325 %329 + %331 = OpCompositeConstruct %v3float %279 %279 %279 + %332 = OpFMul %v3float %331 %152 + %333 = OpCompositeConstruct %v3float %282 %282 %282 + %334 = OpFMul %v3float %333 %156 + %335 = OpFAdd %v3float %332 %334 + %336 = OpCompositeConstruct %v3float %285 %285 %285 + %337 = OpFMul %v3float %336 %160 + %338 = OpFAdd %v3float %335 %337 + %339 = OpFMul %v3float %331 %153 + %340 = OpFMul %v3float %333 %157 + %341 = OpFAdd %v3float %339 %340 + %342 = OpFMul %v3float %336 %161 + %343 = OpFAdd %v3float %341 %342 + %344 = OpFMul %v3float %240 %338 + %345 = OpFMul %v3float %254 %343 + %346 = OpFAdd %v3float %344 %345 + %347 = OpFMul %v3float %331 %346 + %348 = OpFMul %v3float %254 %338 + %349 = OpFMul %v3float %237 %343 + %350 = OpFAdd %v3float %348 %349 + %351 = OpFMul %v3float %333 %350 + %352 = OpFAdd %v3float %347 %351 + %353 = OpFMul %v3float %237 %338 + %354 = OpFMul %v3float %240 %343 + %355 = OpFAdd %v3float %353 %354 + %356 = OpFMul %v3float %336 %355 + %357 = OpFAdd %v3float %352 %356 + OpBranch %302 + %302 = OpLabel + %358 = OpPhi %v4float %276 %300 %330 %303 + %359 = OpPhi %v3float %265 %300 %357 %303 + OpBranch %298 + %299 = OpLabel + %360 = OpFAdd %float %282 %285 + %361 = OpFOrdEqual %bool %360 %float_2 + %362 = OpSelect %int %361 %int_1 %int_0 + %363 = OpConvertSToF %float %362 + %364 = OpFAdd %float %285 %279 + %365 = OpFOrdEqual %bool %364 %float_2 + %366 = OpSelect %int %365 %int_1 %int_0 + %367 = OpConvertSToF %float %366 + %368 = OpFOrdEqual %bool %286 %float_2 + %369 = OpSelect %int %368 %int_1 %int_0 + %370 = OpConvertSToF %float %369 + %371 = OpCompositeConstruct %v4float %363 %363 %363 %363 + %372 = OpFMul %v4float %371 %140 + %373 = OpCompositeConstruct %v4float %367 %367 %367 %367 + %374 = OpFMul %v4float %373 %142 + %375 = OpFAdd %v4float %372 %374 + %376 = OpCompositeConstruct %v4float %370 %370 %370 %370 + %377 = OpFMul %v4float %376 %144 + %378 = OpFAdd %v4float %375 %377 + %379 = OpCompositeConstruct %v3float %363 %363 %363 + %380 = OpFMul %v3float %379 %141 + %381 = OpCompositeConstruct %v3float %367 %367 %367 + %382 = OpFMul %v3float %381 %143 + %383 = OpFAdd %v3float %380 %382 + %384 = OpCompositeConstruct %v3float %370 %370 %370 + %385 = OpFMul %v3float %384 %145 + %386 = OpFAdd %v3float %383 %385 + OpBranch %298 + %298 = OpLabel + %387 = OpPhi %v4float %378 %299 %358 %302 + %388 = OpPhi %v3float %386 %299 %359 %302 + %389 = OpFOrdEqual %bool %296 %float_0 + OpSelectionMerge %390 None + OpBranchConditional %389 %391 %390 + %391 = OpLabel + %392 = OpVectorShuffle %v3float %387 %387 0 1 2 + %393 = OpExtInst %v3float %1 Cross %392 %388 + %394 = OpCompositeExtract %float %387 3 + %395 = OpCompositeConstruct %v3float %394 %394 %394 + %396 = OpFMul %v3float %393 %395 + %397 = OpCompositeConstruct %mat3v3float %388 %396 %392 + OpBranch %390 + %390 = OpLabel + %398 = OpPhi %mat3v3float %271 %298 %397 %391 + %399 = OpAccessChain %_ptr_Uniform_float %View %int_157 + %400 = OpLoad %float %399 + %401 = OpAccessChain %_ptr_Uniform_v4float %View %int_153 %int_0 + %402 = OpLoad %v4float %401 + %403 = OpVectorShuffle %v3float %402 %402 0 1 2 + %404 = OpVectorShuffle %v3float %402 %402 3 3 3 + %405 = OpFSub %v3float %272 %403 + %406 = OpFAdd %v3float %405 %404 + %407 = OpExtInst %v3float %1 FMax %406 %81 + %408 = OpFAdd %v3float %403 %404 + %409 = OpFSub %v3float %408 %272 + %410 = OpExtInst %v3float %1 FMax %409 %81 + %411 = OpExtInst %v3float %1 FMin %407 %410 + %412 = OpCompositeExtract %float %411 0 + %413 = OpCompositeExtract %float %411 1 + %414 = OpCompositeExtract %float %411 2 + %415 = OpExtInst %float %1 FMin %413 %414 + %416 = OpExtInst %float %1 FMin %412 %415 + %417 = OpAccessChain %_ptr_Uniform_float %View %int_153 %int_0 %int_3 + %418 = OpLoad %float %417 + %419 = OpAccessChain %_ptr_Uniform_float %View %int_156 + %420 = OpLoad %float %419 + %421 = OpFMul %float %418 %420 + %422 = OpFOrdGreaterThan %bool %416 %421 + OpSelectionMerge %423 DontFlatten + OpBranchConditional %422 %424 %425 + %425 = OpLabel + %426 = OpAccessChain %_ptr_Uniform_v4float %View %int_153 %int_1 + %427 = OpLoad %v4float %426 + %428 = OpVectorShuffle %v3float %427 %427 0 1 2 + %429 = OpVectorShuffle %v3float %427 %427 3 3 3 + %430 = OpFSub %v3float %272 %428 + %431 = OpFAdd %v3float %430 %429 + %432 = OpExtInst %v3float %1 FMax %431 %81 + %433 = OpFAdd %v3float %428 %429 + %434 = OpFSub %v3float %433 %272 + %435 = OpExtInst %v3float %1 FMax %434 %81 + %436 = OpExtInst %v3float %1 FMin %432 %435 + %437 = OpCompositeExtract %float %436 0 + %438 = OpCompositeExtract %float %436 1 + %439 = OpCompositeExtract %float %436 2 + %440 = OpExtInst %float %1 FMin %438 %439 + %441 = OpExtInst %float %1 FMin %437 %440 + %442 = OpAccessChain %_ptr_Uniform_float %View %int_153 %int_1 %int_3 + %443 = OpLoad %float %442 + %444 = OpFMul %float %443 %420 + %445 = OpFOrdGreaterThan %bool %441 %444 + OpSelectionMerge %446 DontFlatten + OpBranchConditional %445 %447 %448 + %448 = OpLabel + %449 = OpAccessChain %_ptr_Uniform_v4float %View %int_153 %int_2 + %450 = OpLoad %v4float %449 + %451 = OpVectorShuffle %v3float %450 %450 0 1 2 + %452 = OpVectorShuffle %v3float %450 %450 3 3 3 + %453 = OpFSub %v3float %272 %451 + %454 = OpFAdd %v3float %453 %452 + %455 = OpExtInst %v3float %1 FMax %454 %81 + %456 = OpFAdd %v3float %451 %452 + %457 = OpFSub %v3float %456 %272 + %458 = OpExtInst %v3float %1 FMax %457 %81 + %459 = OpExtInst %v3float %1 FMin %455 %458 + %460 = OpCompositeExtract %float %459 0 + %461 = OpCompositeExtract %float %459 1 + %462 = OpCompositeExtract %float %459 2 + %463 = OpExtInst %float %1 FMin %461 %462 + %464 = OpExtInst %float %1 FMin %460 %463 + %465 = OpAccessChain %_ptr_Uniform_v4float %View %int_153 %int_3 + %466 = OpLoad %v4float %465 + %467 = OpVectorShuffle %v3float %466 %466 0 1 2 + %468 = OpVectorShuffle %v3float %466 %466 3 3 3 + %469 = OpFSub %v3float %272 %467 + %470 = OpFAdd %v3float %469 %468 + %471 = OpExtInst %v3float %1 FMax %470 %81 + %472 = OpFAdd %v3float %467 %468 + %473 = OpFSub %v3float %472 %272 + %474 = OpExtInst %v3float %1 FMax %473 %81 + %475 = OpExtInst %v3float %1 FMin %471 %474 + %476 = OpCompositeExtract %float %475 0 + %477 = OpCompositeExtract %float %475 1 + %478 = OpCompositeExtract %float %475 2 + %479 = OpExtInst %float %1 FMin %477 %478 + %480 = OpExtInst %float %1 FMin %476 %479 + %481 = OpAccessChain %_ptr_Uniform_float %View %int_153 %int_2 %int_3 + %482 = OpLoad %float %481 + %483 = OpFMul %float %482 %420 + %484 = OpFOrdGreaterThan %bool %464 %483 + OpSelectionMerge %485 DontFlatten + OpBranchConditional %484 %486 %487 + %487 = OpLabel + %488 = OpAccessChain %_ptr_Uniform_float %View %int_153 %int_3 %int_3 + %489 = OpLoad %float %488 + %490 = OpFMul %float %489 %420 + %491 = OpFOrdGreaterThan %bool %480 %490 + OpSelectionMerge %492 None + OpBranchConditional %491 %493 %492 + %493 = OpLabel + %494 = OpFMul %float %480 %float_10 + %495 = OpAccessChain %_ptr_Uniform_float %View %int_154 %int_3 %int_3 + %496 = OpLoad %float %495 + %497 = OpFMul %float %494 %496 + %498 = OpExtInst %float %1 FClamp %497 %float_0 %float_1 + %499 = OpAccessChain %_ptr_Uniform_v4float %View %int_154 %uint_3 + %500 = OpLoad %v4float %499 + %501 = OpVectorShuffle %v3float %500 %500 3 3 3 + %502 = OpFMul %v3float %272 %501 + %503 = OpVectorShuffle %v3float %500 %500 0 1 2 + %504 = OpFAdd %v3float %502 %503 + %505 = OpLoad %type_3d_image %View_GlobalDistanceFieldTexture3 + %506 = OpLoad %type_sampler %View_GlobalDistanceFieldSampler0 + %507 = OpSampledImage %type_sampled_image %505 %506 + %508 = OpImageSampleExplicitLod %v4float %507 %504 Lod %float_0 + %509 = OpCompositeExtract %float %508 0 + %510 = OpExtInst %float %1 FMix %400 %509 %498 + OpBranch %492 + %492 = OpLabel + %511 = OpPhi %float %400 %487 %510 %493 + OpBranch %485 + %486 = OpLabel + %512 = OpAccessChain %_ptr_Uniform_v4float %View %int_154 %uint_2 + %513 = OpLoad %v4float %512 + %514 = OpVectorShuffle %v3float %513 %513 3 3 3 + %515 = OpFMul %v3float %272 %514 + %516 = OpVectorShuffle %v3float %513 %513 0 1 2 + %517 = OpFAdd %v3float %515 %516 + %518 = OpLoad %type_3d_image %View_GlobalDistanceFieldTexture2 + %519 = OpLoad %type_sampler %View_GlobalDistanceFieldSampler0 + %520 = OpSampledImage %type_sampled_image %518 %519 + %521 = OpImageSampleExplicitLod %v4float %520 %517 Lod %float_0 + %522 = OpCompositeExtract %float %521 0 + OpBranch %485 + %485 = OpLabel + %523 = OpPhi %float %522 %486 %511 %492 + OpBranch %446 + %447 = OpLabel + %524 = OpAccessChain %_ptr_Uniform_v4float %View %int_154 %uint_1 + %525 = OpLoad %v4float %524 + %526 = OpVectorShuffle %v3float %525 %525 3 3 3 + %527 = OpFMul %v3float %272 %526 + %528 = OpVectorShuffle %v3float %525 %525 0 1 2 + %529 = OpFAdd %v3float %527 %528 + %530 = OpLoad %type_3d_image %View_GlobalDistanceFieldTexture1 + %531 = OpLoad %type_sampler %View_GlobalDistanceFieldSampler0 + %532 = OpSampledImage %type_sampled_image %530 %531 + %533 = OpImageSampleExplicitLod %v4float %532 %529 Lod %float_0 + %534 = OpCompositeExtract %float %533 0 + OpBranch %446 + %446 = OpLabel + %535 = OpPhi %float %534 %447 %523 %485 + OpBranch %423 + %424 = OpLabel + %536 = OpAccessChain %_ptr_Uniform_v4float %View %int_154 %uint_0 + %537 = OpLoad %v4float %536 + %538 = OpVectorShuffle %v3float %537 %537 3 3 3 + %539 = OpFMul %v3float %272 %538 + %540 = OpVectorShuffle %v3float %537 %537 0 1 2 + %541 = OpFAdd %v3float %539 %540 + %542 = OpLoad %type_3d_image %View_GlobalDistanceFieldTexture0 + %543 = OpLoad %type_sampler %View_GlobalDistanceFieldSampler0 + %544 = OpSampledImage %type_sampled_image %542 %543 + %545 = OpImageSampleExplicitLod %v4float %544 %541 Lod %float_0 + %546 = OpCompositeExtract %float %545 0 + OpBranch %423 + %423 = OpLabel + %547 = OpPhi %float %546 %424 %535 %446 + %548 = OpAccessChain %_ptr_Uniform_float %Material %int_1 %int_0 %int_2 + %549 = OpLoad %float %548 + %550 = OpFAdd %float %547 %549 + %551 = OpExtInst %float %1 FMin %550 %float_0 + %552 = OpAccessChain %_ptr_Uniform_float %Material %int_1 %int_0 %int_3 + %553 = OpLoad %float %552 + %554 = OpFMul %float %551 %553 + %555 = OpCompositeExtract %v3float %398 2 + %556 = OpCompositeConstruct %v3float %554 %554 %554 + %557 = OpFMul %v3float %555 %556 + %558 = OpFMul %float %163 %187 + %559 = OpFMul %float %165 %188 + %560 = OpFAdd %float %558 %559 + %561 = OpFMul %float %167 %189 + %562 = OpFAdd %float %560 %561 + %563 = OpCompositeConstruct %v3float %562 %562 %562 + %564 = OpFMul %v3float %557 %563 + %565 = OpFAdd %v3float %264 %564 + %566 = OpVectorShuffle %v4float %235 %565 4 5 6 3 + %567 = OpVectorShuffle %v3float %565 %117 0 1 2 + %568 = OpFSub %v3float %567 %184 + %569 = OpCompositeExtract %float %568 0 + %570 = OpCompositeExtract %float %568 1 + %571 = OpCompositeExtract %float %568 2 + %572 = OpCompositeConstruct %v4float %569 %570 %571 %float_1 + %573 = OpDot %float %186 %572 + %574 = OpMatrixTimesVector %v4float %180 %566 + %575 = OpCompositeExtract %float %574 3 + %576 = OpFMul %float %float_0_00100000005 %575 + %577 = OpCompositeExtract %float %574 2 + %578 = OpFAdd %float %577 %576 + %579 = OpCompositeInsert %v4float %578 %574 2 + OpStore %gl_Position %579 + OpStore %out_var_TEXCOORD6 %261 + OpStore %out_var_TEXCOORD7 %263 + OpStore %out_var_TEXCOORD10_centroid %257 + OpStore %out_var_TEXCOORD11_centroid %259 + %580 = OpAccessChain %_ptr_Output_float %gl_ClipDistance %uint_0 + OpStore %580 %573 + OpReturn + OpFunctionEnd diff --git a/third_party/spirv-cross/shaders-ue4/asm/tese/ds-patch-inputs.asm.tese b/third_party/spirv-cross/shaders-ue4/asm/tese/ds-patch-inputs.asm.tese new file mode 100644 index 0000000000..e792c7e116 --- /dev/null +++ b/third_party/spirv-cross/shaders-ue4/asm/tese/ds-patch-inputs.asm.tese @@ -0,0 +1,547 @@ +; SPIR-V +; Version: 1.0 +; Generator: Google spiregg; 0 +; Bound: 236 +; Schema: 0 + OpCapability Tessellation + OpCapability SampledBuffer + OpExtension "SPV_GOOGLE_hlsl_functionality1" + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint TessellationEvaluation %MainDomain "main" %in_var_TEXCOORD10_centroid %in_var_TEXCOORD11_centroid %in_var_VS_to_DS_Position %in_var_VS_To_DS_VertexID %in_var_PN_POSITION %in_var_PN_DisplacementScales %in_var_PN_TessellationMultiplier %in_var_PN_WorldDisplacementMultiplier %in_var_PN_DominantVertex %in_var_PN_DominantVertex1 %in_var_PN_DominantVertex2 %in_var_PN_DominantEdge %in_var_PN_DominantEdge1 %in_var_PN_DominantEdge2 %in_var_PN_DominantEdge3 %in_var_PN_DominantEdge4 %in_var_PN_DominantEdge5 %gl_TessLevelOuter %gl_TessLevelInner %in_var_PN_POSITION9 %gl_TessCoord %out_var_TEXCOORD10_centroid %out_var_TEXCOORD11_centroid %out_var_TEXCOORD6 %out_var_TEXCOORD7 %gl_Position + OpExecutionMode %MainDomain Triangles + OpSource HLSL 600 + OpName %type_ShadowDepthPass "type.ShadowDepthPass" + OpMemberName %type_ShadowDepthPass 0 "PrePadding_ShadowDepthPass_LPV_0" + OpMemberName %type_ShadowDepthPass 1 "PrePadding_ShadowDepthPass_LPV_4" + OpMemberName %type_ShadowDepthPass 2 "PrePadding_ShadowDepthPass_LPV_8" + OpMemberName %type_ShadowDepthPass 3 "PrePadding_ShadowDepthPass_LPV_12" + OpMemberName %type_ShadowDepthPass 4 "PrePadding_ShadowDepthPass_LPV_16" + OpMemberName %type_ShadowDepthPass 5 "PrePadding_ShadowDepthPass_LPV_20" + OpMemberName %type_ShadowDepthPass 6 "PrePadding_ShadowDepthPass_LPV_24" + OpMemberName %type_ShadowDepthPass 7 "PrePadding_ShadowDepthPass_LPV_28" + OpMemberName %type_ShadowDepthPass 8 "PrePadding_ShadowDepthPass_LPV_32" + OpMemberName %type_ShadowDepthPass 9 "PrePadding_ShadowDepthPass_LPV_36" + OpMemberName %type_ShadowDepthPass 10 "PrePadding_ShadowDepthPass_LPV_40" + OpMemberName %type_ShadowDepthPass 11 "PrePadding_ShadowDepthPass_LPV_44" + OpMemberName %type_ShadowDepthPass 12 "PrePadding_ShadowDepthPass_LPV_48" + OpMemberName %type_ShadowDepthPass 13 "PrePadding_ShadowDepthPass_LPV_52" + OpMemberName %type_ShadowDepthPass 14 "PrePadding_ShadowDepthPass_LPV_56" + OpMemberName %type_ShadowDepthPass 15 "PrePadding_ShadowDepthPass_LPV_60" + OpMemberName %type_ShadowDepthPass 16 "PrePadding_ShadowDepthPass_LPV_64" + OpMemberName %type_ShadowDepthPass 17 "PrePadding_ShadowDepthPass_LPV_68" + OpMemberName %type_ShadowDepthPass 18 "PrePadding_ShadowDepthPass_LPV_72" + OpMemberName %type_ShadowDepthPass 19 "PrePadding_ShadowDepthPass_LPV_76" + OpMemberName %type_ShadowDepthPass 20 "PrePadding_ShadowDepthPass_LPV_80" + OpMemberName %type_ShadowDepthPass 21 "PrePadding_ShadowDepthPass_LPV_84" + OpMemberName %type_ShadowDepthPass 22 "PrePadding_ShadowDepthPass_LPV_88" + OpMemberName %type_ShadowDepthPass 23 "PrePadding_ShadowDepthPass_LPV_92" + OpMemberName %type_ShadowDepthPass 24 "PrePadding_ShadowDepthPass_LPV_96" + OpMemberName %type_ShadowDepthPass 25 "PrePadding_ShadowDepthPass_LPV_100" + OpMemberName %type_ShadowDepthPass 26 "PrePadding_ShadowDepthPass_LPV_104" + OpMemberName %type_ShadowDepthPass 27 "PrePadding_ShadowDepthPass_LPV_108" + OpMemberName %type_ShadowDepthPass 28 "PrePadding_ShadowDepthPass_LPV_112" + OpMemberName %type_ShadowDepthPass 29 "PrePadding_ShadowDepthPass_LPV_116" + OpMemberName %type_ShadowDepthPass 30 "PrePadding_ShadowDepthPass_LPV_120" + OpMemberName %type_ShadowDepthPass 31 "PrePadding_ShadowDepthPass_LPV_124" + OpMemberName %type_ShadowDepthPass 32 "PrePadding_ShadowDepthPass_LPV_128" + OpMemberName %type_ShadowDepthPass 33 "PrePadding_ShadowDepthPass_LPV_132" + OpMemberName %type_ShadowDepthPass 34 "PrePadding_ShadowDepthPass_LPV_136" + OpMemberName %type_ShadowDepthPass 35 "PrePadding_ShadowDepthPass_LPV_140" + OpMemberName %type_ShadowDepthPass 36 "PrePadding_ShadowDepthPass_LPV_144" + OpMemberName %type_ShadowDepthPass 37 "PrePadding_ShadowDepthPass_LPV_148" + OpMemberName %type_ShadowDepthPass 38 "PrePadding_ShadowDepthPass_LPV_152" + OpMemberName %type_ShadowDepthPass 39 "PrePadding_ShadowDepthPass_LPV_156" + OpMemberName %type_ShadowDepthPass 40 "PrePadding_ShadowDepthPass_LPV_160" + OpMemberName %type_ShadowDepthPass 41 "PrePadding_ShadowDepthPass_LPV_164" + OpMemberName %type_ShadowDepthPass 42 "PrePadding_ShadowDepthPass_LPV_168" + OpMemberName %type_ShadowDepthPass 43 "PrePadding_ShadowDepthPass_LPV_172" + OpMemberName %type_ShadowDepthPass 44 "PrePadding_ShadowDepthPass_LPV_176" + OpMemberName %type_ShadowDepthPass 45 "PrePadding_ShadowDepthPass_LPV_180" + OpMemberName %type_ShadowDepthPass 46 "PrePadding_ShadowDepthPass_LPV_184" + OpMemberName %type_ShadowDepthPass 47 "PrePadding_ShadowDepthPass_LPV_188" + OpMemberName %type_ShadowDepthPass 48 "PrePadding_ShadowDepthPass_LPV_192" + OpMemberName %type_ShadowDepthPass 49 "PrePadding_ShadowDepthPass_LPV_196" + OpMemberName %type_ShadowDepthPass 50 "PrePadding_ShadowDepthPass_LPV_200" + OpMemberName %type_ShadowDepthPass 51 "PrePadding_ShadowDepthPass_LPV_204" + OpMemberName %type_ShadowDepthPass 52 "PrePadding_ShadowDepthPass_LPV_208" + OpMemberName %type_ShadowDepthPass 53 "PrePadding_ShadowDepthPass_LPV_212" + OpMemberName %type_ShadowDepthPass 54 "PrePadding_ShadowDepthPass_LPV_216" + OpMemberName %type_ShadowDepthPass 55 "PrePadding_ShadowDepthPass_LPV_220" + OpMemberName %type_ShadowDepthPass 56 "PrePadding_ShadowDepthPass_LPV_224" + OpMemberName %type_ShadowDepthPass 57 "PrePadding_ShadowDepthPass_LPV_228" + OpMemberName %type_ShadowDepthPass 58 "PrePadding_ShadowDepthPass_LPV_232" + OpMemberName %type_ShadowDepthPass 59 "PrePadding_ShadowDepthPass_LPV_236" + OpMemberName %type_ShadowDepthPass 60 "PrePadding_ShadowDepthPass_LPV_240" + OpMemberName %type_ShadowDepthPass 61 "PrePadding_ShadowDepthPass_LPV_244" + OpMemberName %type_ShadowDepthPass 62 "PrePadding_ShadowDepthPass_LPV_248" + OpMemberName %type_ShadowDepthPass 63 "PrePadding_ShadowDepthPass_LPV_252" + OpMemberName %type_ShadowDepthPass 64 "PrePadding_ShadowDepthPass_LPV_256" + OpMemberName %type_ShadowDepthPass 65 "PrePadding_ShadowDepthPass_LPV_260" + OpMemberName %type_ShadowDepthPass 66 "PrePadding_ShadowDepthPass_LPV_264" + OpMemberName %type_ShadowDepthPass 67 "PrePadding_ShadowDepthPass_LPV_268" + OpMemberName %type_ShadowDepthPass 68 "ShadowDepthPass_LPV_mRsmToWorld" + OpMemberName %type_ShadowDepthPass 69 "ShadowDepthPass_LPV_mLightColour" + OpMemberName %type_ShadowDepthPass 70 "ShadowDepthPass_LPV_GeometryVolumeCaptureLightDirection" + OpMemberName %type_ShadowDepthPass 71 "ShadowDepthPass_LPV_mEyePos" + OpMemberName %type_ShadowDepthPass 72 "ShadowDepthPass_LPV_mOldGridOffset" + OpMemberName %type_ShadowDepthPass 73 "PrePadding_ShadowDepthPass_LPV_396" + OpMemberName %type_ShadowDepthPass 74 "ShadowDepthPass_LPV_mLpvGridOffset" + OpMemberName %type_ShadowDepthPass 75 "ShadowDepthPass_LPV_ClearMultiplier" + OpMemberName %type_ShadowDepthPass 76 "ShadowDepthPass_LPV_LpvScale" + OpMemberName %type_ShadowDepthPass 77 "ShadowDepthPass_LPV_OneOverLpvScale" + OpMemberName %type_ShadowDepthPass 78 "ShadowDepthPass_LPV_DirectionalOcclusionIntensity" + OpMemberName %type_ShadowDepthPass 79 "ShadowDepthPass_LPV_DirectionalOcclusionRadius" + OpMemberName %type_ShadowDepthPass 80 "ShadowDepthPass_LPV_RsmAreaIntensityMultiplier" + OpMemberName %type_ShadowDepthPass 81 "ShadowDepthPass_LPV_RsmPixelToTexcoordMultiplier" + OpMemberName %type_ShadowDepthPass 82 "ShadowDepthPass_LPV_SecondaryOcclusionStrength" + OpMemberName %type_ShadowDepthPass 83 "ShadowDepthPass_LPV_SecondaryBounceStrength" + OpMemberName %type_ShadowDepthPass 84 "ShadowDepthPass_LPV_VplInjectionBias" + OpMemberName %type_ShadowDepthPass 85 "ShadowDepthPass_LPV_GeometryVolumeInjectionBias" + OpMemberName %type_ShadowDepthPass 86 "ShadowDepthPass_LPV_EmissiveInjectionMultiplier" + OpMemberName %type_ShadowDepthPass 87 "ShadowDepthPass_LPV_PropagationIndex" + OpMemberName %type_ShadowDepthPass 88 "ShadowDepthPass_ProjectionMatrix" + OpMemberName %type_ShadowDepthPass 89 "ShadowDepthPass_ViewMatrix" + OpMemberName %type_ShadowDepthPass 90 "ShadowDepthPass_ShadowParams" + OpMemberName %type_ShadowDepthPass 91 "ShadowDepthPass_bClampToNearPlane" + OpMemberName %type_ShadowDepthPass 92 "PrePadding_ShadowDepthPass_612" + OpMemberName %type_ShadowDepthPass 93 "PrePadding_ShadowDepthPass_616" + OpMemberName %type_ShadowDepthPass 94 "PrePadding_ShadowDepthPass_620" + OpMemberName %type_ShadowDepthPass 95 "ShadowDepthPass_ShadowViewProjectionMatrices" + OpMemberName %type_ShadowDepthPass 96 "ShadowDepthPass_ShadowViewMatrices" + OpName %ShadowDepthPass "ShadowDepthPass" + OpName %in_var_TEXCOORD10_centroid "in.var.TEXCOORD10_centroid" + OpName %in_var_TEXCOORD11_centroid "in.var.TEXCOORD11_centroid" + OpName %in_var_VS_to_DS_Position "in.var.VS_to_DS_Position" + OpName %in_var_VS_To_DS_VertexID "in.var.VS_To_DS_VertexID" + OpName %in_var_PN_POSITION "in.var.PN_POSITION" + OpName %in_var_PN_DisplacementScales "in.var.PN_DisplacementScales" + OpName %in_var_PN_TessellationMultiplier "in.var.PN_TessellationMultiplier" + OpName %in_var_PN_WorldDisplacementMultiplier "in.var.PN_WorldDisplacementMultiplier" + OpName %in_var_PN_DominantVertex "in.var.PN_DominantVertex" + OpName %in_var_PN_DominantVertex1 "in.var.PN_DominantVertex1" + OpName %in_var_PN_DominantVertex2 "in.var.PN_DominantVertex2" + OpName %in_var_PN_DominantEdge "in.var.PN_DominantEdge" + OpName %in_var_PN_DominantEdge1 "in.var.PN_DominantEdge1" + OpName %in_var_PN_DominantEdge2 "in.var.PN_DominantEdge2" + OpName %in_var_PN_DominantEdge3 "in.var.PN_DominantEdge3" + OpName %in_var_PN_DominantEdge4 "in.var.PN_DominantEdge4" + OpName %in_var_PN_DominantEdge5 "in.var.PN_DominantEdge5" + OpName %in_var_PN_POSITION9 "in.var.PN_POSITION9" + OpName %out_var_TEXCOORD10_centroid "out.var.TEXCOORD10_centroid" + OpName %out_var_TEXCOORD11_centroid "out.var.TEXCOORD11_centroid" + OpName %out_var_TEXCOORD6 "out.var.TEXCOORD6" + OpName %out_var_TEXCOORD7 "out.var.TEXCOORD7" + OpName %MainDomain "MainDomain" + OpDecorateString %in_var_TEXCOORD10_centroid UserSemantic "TEXCOORD10_centroid" + OpDecorateString %in_var_TEXCOORD11_centroid UserSemantic "TEXCOORD11_centroid" + OpDecorateString %in_var_VS_to_DS_Position UserSemantic "VS_to_DS_Position" + OpDecorateString %in_var_VS_To_DS_VertexID UserSemantic "VS_To_DS_VertexID" + OpDecorateString %in_var_PN_POSITION UserSemantic "PN_POSITION" + OpDecorateString %in_var_PN_DisplacementScales UserSemantic "PN_DisplacementScales" + OpDecorateString %in_var_PN_TessellationMultiplier UserSemantic "PN_TessellationMultiplier" + OpDecorateString %in_var_PN_WorldDisplacementMultiplier UserSemantic "PN_WorldDisplacementMultiplier" + OpDecorateString %in_var_PN_DominantVertex UserSemantic "PN_DominantVertex" + OpDecorateString %in_var_PN_DominantVertex1 UserSemantic "PN_DominantVertex" + OpDecorateString %in_var_PN_DominantVertex2 UserSemantic "PN_DominantVertex" + OpDecorateString %in_var_PN_DominantEdge UserSemantic "PN_DominantEdge" + OpDecorateString %in_var_PN_DominantEdge1 UserSemantic "PN_DominantEdge" + OpDecorateString %in_var_PN_DominantEdge2 UserSemantic "PN_DominantEdge" + OpDecorateString %in_var_PN_DominantEdge3 UserSemantic "PN_DominantEdge" + OpDecorateString %in_var_PN_DominantEdge4 UserSemantic "PN_DominantEdge" + OpDecorateString %in_var_PN_DominantEdge5 UserSemantic "PN_DominantEdge" + OpDecorate %gl_TessLevelOuter BuiltIn TessLevelOuter + OpDecorateString %gl_TessLevelOuter UserSemantic "SV_TessFactor" + OpDecorate %gl_TessLevelOuter Patch + OpDecorate %gl_TessLevelInner BuiltIn TessLevelInner + OpDecorateString %gl_TessLevelInner UserSemantic "SV_InsideTessFactor" + OpDecorate %gl_TessLevelInner Patch + OpDecorateString %in_var_PN_POSITION9 UserSemantic "PN_POSITION9" + OpDecorate %in_var_PN_POSITION9 Patch + OpDecorate %gl_TessCoord BuiltIn TessCoord + OpDecorateString %gl_TessCoord UserSemantic "SV_DomainLocation" + OpDecorate %gl_TessCoord Patch + OpDecorateString %out_var_TEXCOORD10_centroid UserSemantic "TEXCOORD10_centroid" + OpDecorateString %out_var_TEXCOORD11_centroid UserSemantic "TEXCOORD11_centroid" + OpDecorateString %out_var_TEXCOORD6 UserSemantic "TEXCOORD6" + OpDecorateString %out_var_TEXCOORD7 UserSemantic "TEXCOORD7" + OpDecorate %gl_Position BuiltIn Position + OpDecorateString %gl_Position UserSemantic "SV_POSITION" + OpDecorate %in_var_PN_DisplacementScales Location 0 + OpDecorate %in_var_PN_DominantEdge Location 1 + OpDecorate %in_var_PN_DominantEdge1 Location 2 + OpDecorate %in_var_PN_DominantEdge2 Location 3 + OpDecorate %in_var_PN_DominantEdge3 Location 4 + OpDecorate %in_var_PN_DominantEdge4 Location 5 + OpDecorate %in_var_PN_DominantEdge5 Location 6 + OpDecorate %in_var_PN_DominantVertex Location 7 + OpDecorate %in_var_PN_DominantVertex1 Location 8 + OpDecorate %in_var_PN_DominantVertex2 Location 9 + OpDecorate %in_var_PN_POSITION Location 10 + OpDecorate %in_var_PN_POSITION9 Location 13 + OpDecorate %in_var_PN_TessellationMultiplier Location 14 + OpDecorate %in_var_PN_WorldDisplacementMultiplier Location 15 + OpDecorate %in_var_TEXCOORD10_centroid Location 16 + OpDecorate %in_var_TEXCOORD11_centroid Location 17 + OpDecorate %in_var_VS_To_DS_VertexID Location 18 + OpDecorate %in_var_VS_to_DS_Position Location 19 + OpDecorate %out_var_TEXCOORD10_centroid Location 0 + OpDecorate %out_var_TEXCOORD11_centroid Location 1 + OpDecorate %out_var_TEXCOORD6 Location 2 + OpDecorate %out_var_TEXCOORD7 Location 3 + OpDecorate %ShadowDepthPass DescriptorSet 0 + OpDecorate %ShadowDepthPass Binding 0 + OpDecorate %_arr_mat4v4float_uint_6 ArrayStride 64 + OpMemberDecorate %type_ShadowDepthPass 0 Offset 0 + OpMemberDecorate %type_ShadowDepthPass 1 Offset 4 + OpMemberDecorate %type_ShadowDepthPass 2 Offset 8 + OpMemberDecorate %type_ShadowDepthPass 3 Offset 12 + OpMemberDecorate %type_ShadowDepthPass 4 Offset 16 + OpMemberDecorate %type_ShadowDepthPass 5 Offset 20 + OpMemberDecorate %type_ShadowDepthPass 6 Offset 24 + OpMemberDecorate %type_ShadowDepthPass 7 Offset 28 + OpMemberDecorate %type_ShadowDepthPass 8 Offset 32 + OpMemberDecorate %type_ShadowDepthPass 9 Offset 36 + OpMemberDecorate %type_ShadowDepthPass 10 Offset 40 + OpMemberDecorate %type_ShadowDepthPass 11 Offset 44 + OpMemberDecorate %type_ShadowDepthPass 12 Offset 48 + OpMemberDecorate %type_ShadowDepthPass 13 Offset 52 + OpMemberDecorate %type_ShadowDepthPass 14 Offset 56 + OpMemberDecorate %type_ShadowDepthPass 15 Offset 60 + OpMemberDecorate %type_ShadowDepthPass 16 Offset 64 + OpMemberDecorate %type_ShadowDepthPass 17 Offset 68 + OpMemberDecorate %type_ShadowDepthPass 18 Offset 72 + OpMemberDecorate %type_ShadowDepthPass 19 Offset 76 + OpMemberDecorate %type_ShadowDepthPass 20 Offset 80 + OpMemberDecorate %type_ShadowDepthPass 21 Offset 84 + OpMemberDecorate %type_ShadowDepthPass 22 Offset 88 + OpMemberDecorate %type_ShadowDepthPass 23 Offset 92 + OpMemberDecorate %type_ShadowDepthPass 24 Offset 96 + OpMemberDecorate %type_ShadowDepthPass 25 Offset 100 + OpMemberDecorate %type_ShadowDepthPass 26 Offset 104 + OpMemberDecorate %type_ShadowDepthPass 27 Offset 108 + OpMemberDecorate %type_ShadowDepthPass 28 Offset 112 + OpMemberDecorate %type_ShadowDepthPass 29 Offset 116 + OpMemberDecorate %type_ShadowDepthPass 30 Offset 120 + OpMemberDecorate %type_ShadowDepthPass 31 Offset 124 + OpMemberDecorate %type_ShadowDepthPass 32 Offset 128 + OpMemberDecorate %type_ShadowDepthPass 33 Offset 132 + OpMemberDecorate %type_ShadowDepthPass 34 Offset 136 + OpMemberDecorate %type_ShadowDepthPass 35 Offset 140 + OpMemberDecorate %type_ShadowDepthPass 36 Offset 144 + OpMemberDecorate %type_ShadowDepthPass 37 Offset 148 + OpMemberDecorate %type_ShadowDepthPass 38 Offset 152 + OpMemberDecorate %type_ShadowDepthPass 39 Offset 156 + OpMemberDecorate %type_ShadowDepthPass 40 Offset 160 + OpMemberDecorate %type_ShadowDepthPass 41 Offset 164 + OpMemberDecorate %type_ShadowDepthPass 42 Offset 168 + OpMemberDecorate %type_ShadowDepthPass 43 Offset 172 + OpMemberDecorate %type_ShadowDepthPass 44 Offset 176 + OpMemberDecorate %type_ShadowDepthPass 45 Offset 180 + OpMemberDecorate %type_ShadowDepthPass 46 Offset 184 + OpMemberDecorate %type_ShadowDepthPass 47 Offset 188 + OpMemberDecorate %type_ShadowDepthPass 48 Offset 192 + OpMemberDecorate %type_ShadowDepthPass 49 Offset 196 + OpMemberDecorate %type_ShadowDepthPass 50 Offset 200 + OpMemberDecorate %type_ShadowDepthPass 51 Offset 204 + OpMemberDecorate %type_ShadowDepthPass 52 Offset 208 + OpMemberDecorate %type_ShadowDepthPass 53 Offset 212 + OpMemberDecorate %type_ShadowDepthPass 54 Offset 216 + OpMemberDecorate %type_ShadowDepthPass 55 Offset 220 + OpMemberDecorate %type_ShadowDepthPass 56 Offset 224 + OpMemberDecorate %type_ShadowDepthPass 57 Offset 228 + OpMemberDecorate %type_ShadowDepthPass 58 Offset 232 + OpMemberDecorate %type_ShadowDepthPass 59 Offset 236 + OpMemberDecorate %type_ShadowDepthPass 60 Offset 240 + OpMemberDecorate %type_ShadowDepthPass 61 Offset 244 + OpMemberDecorate %type_ShadowDepthPass 62 Offset 248 + OpMemberDecorate %type_ShadowDepthPass 63 Offset 252 + OpMemberDecorate %type_ShadowDepthPass 64 Offset 256 + OpMemberDecorate %type_ShadowDepthPass 65 Offset 260 + OpMemberDecorate %type_ShadowDepthPass 66 Offset 264 + OpMemberDecorate %type_ShadowDepthPass 67 Offset 268 + OpMemberDecorate %type_ShadowDepthPass 68 Offset 272 + OpMemberDecorate %type_ShadowDepthPass 68 MatrixStride 16 + OpMemberDecorate %type_ShadowDepthPass 68 ColMajor + OpMemberDecorate %type_ShadowDepthPass 69 Offset 336 + OpMemberDecorate %type_ShadowDepthPass 70 Offset 352 + OpMemberDecorate %type_ShadowDepthPass 71 Offset 368 + OpMemberDecorate %type_ShadowDepthPass 72 Offset 384 + OpMemberDecorate %type_ShadowDepthPass 73 Offset 396 + OpMemberDecorate %type_ShadowDepthPass 74 Offset 400 + OpMemberDecorate %type_ShadowDepthPass 75 Offset 412 + OpMemberDecorate %type_ShadowDepthPass 76 Offset 416 + OpMemberDecorate %type_ShadowDepthPass 77 Offset 420 + OpMemberDecorate %type_ShadowDepthPass 78 Offset 424 + OpMemberDecorate %type_ShadowDepthPass 79 Offset 428 + OpMemberDecorate %type_ShadowDepthPass 80 Offset 432 + OpMemberDecorate %type_ShadowDepthPass 81 Offset 436 + OpMemberDecorate %type_ShadowDepthPass 82 Offset 440 + OpMemberDecorate %type_ShadowDepthPass 83 Offset 444 + OpMemberDecorate %type_ShadowDepthPass 84 Offset 448 + OpMemberDecorate %type_ShadowDepthPass 85 Offset 452 + OpMemberDecorate %type_ShadowDepthPass 86 Offset 456 + OpMemberDecorate %type_ShadowDepthPass 87 Offset 460 + OpMemberDecorate %type_ShadowDepthPass 88 Offset 464 + OpMemberDecorate %type_ShadowDepthPass 88 MatrixStride 16 + OpMemberDecorate %type_ShadowDepthPass 88 ColMajor + OpMemberDecorate %type_ShadowDepthPass 89 Offset 528 + OpMemberDecorate %type_ShadowDepthPass 89 MatrixStride 16 + OpMemberDecorate %type_ShadowDepthPass 89 ColMajor + OpMemberDecorate %type_ShadowDepthPass 90 Offset 592 + OpMemberDecorate %type_ShadowDepthPass 91 Offset 608 + OpMemberDecorate %type_ShadowDepthPass 92 Offset 612 + OpMemberDecorate %type_ShadowDepthPass 93 Offset 616 + OpMemberDecorate %type_ShadowDepthPass 94 Offset 620 + OpMemberDecorate %type_ShadowDepthPass 95 Offset 624 + OpMemberDecorate %type_ShadowDepthPass 95 MatrixStride 16 + OpMemberDecorate %type_ShadowDepthPass 95 ColMajor + OpMemberDecorate %type_ShadowDepthPass 96 Offset 1008 + OpMemberDecorate %type_ShadowDepthPass 96 MatrixStride 16 + OpMemberDecorate %type_ShadowDepthPass 96 ColMajor + OpDecorate %type_ShadowDepthPass Block + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 +%mat4v4float = OpTypeMatrix %v4float 4 + %v3float = OpTypeVector %float 3 + %v2float = OpTypeVector %float 2 + %int = OpTypeInt 32 1 + %uint = OpTypeInt 32 0 + %uint_2 = OpConstant %uint 2 + %uint_4 = OpConstant %uint 4 + %int_0 = OpConstant %int 0 + %int_1 = OpConstant %int 1 + %int_2 = OpConstant %int 2 + %float_3 = OpConstant %float 3 + %uint_0 = OpConstant %uint 0 + %uint_1 = OpConstant %uint 1 + %float_6 = OpConstant %float 6 + %48 = OpConstantComposite %v4float %float_6 %float_6 %float_6 %float_6 + %float_1 = OpConstant %float 1 + %float_0 = OpConstant %float 0 + %int_3 = OpConstant %int 3 + %int_88 = OpConstant %int 88 + %int_89 = OpConstant %int 89 + %int_90 = OpConstant %int 90 + %int_91 = OpConstant %int 91 +%float_9_99999997en07 = OpConstant %float 9.99999997e-07 + %uint_6 = OpConstant %uint 6 +%_arr_mat4v4float_uint_6 = OpTypeArray %mat4v4float %uint_6 + %v3int = OpTypeVector %int 3 +%type_ShadowDepthPass = OpTypeStruct %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %mat4v4float %v4float %v4float %v4float %v3int %int %v3int %float %float %float %float %float %float %float %float %float %float %float %float %int %mat4v4float %mat4v4float %v4float %float %float %float %float %_arr_mat4v4float_uint_6 %_arr_mat4v4float_uint_6 +%_ptr_Uniform_type_ShadowDepthPass = OpTypePointer Uniform %type_ShadowDepthPass + %uint_3 = OpConstant %uint 3 +%_arr_v4float_uint_3 = OpTypeArray %v4float %uint_3 +%_ptr_Input__arr_v4float_uint_3 = OpTypePointer Input %_arr_v4float_uint_3 +%_arr_uint_uint_3 = OpTypeArray %uint %uint_3 +%_ptr_Input__arr_uint_uint_3 = OpTypePointer Input %_arr_uint_uint_3 +%_arr__arr_v4float_uint_3_uint_3 = OpTypeArray %_arr_v4float_uint_3 %uint_3 +%_ptr_Input__arr__arr_v4float_uint_3_uint_3 = OpTypePointer Input %_arr__arr_v4float_uint_3_uint_3 +%_arr_v3float_uint_3 = OpTypeArray %v3float %uint_3 +%_ptr_Input__arr_v3float_uint_3 = OpTypePointer Input %_arr_v3float_uint_3 +%_arr_float_uint_3 = OpTypeArray %float %uint_3 +%_ptr_Input__arr_float_uint_3 = OpTypePointer Input %_arr_float_uint_3 +%_arr_v2float_uint_3 = OpTypeArray %v2float %uint_3 +%_ptr_Input__arr_v2float_uint_3 = OpTypePointer Input %_arr_v2float_uint_3 +%_arr_float_uint_4 = OpTypeArray %float %uint_4 +%_ptr_Input__arr_float_uint_4 = OpTypePointer Input %_arr_float_uint_4 +%_arr_float_uint_2 = OpTypeArray %float %uint_2 +%_ptr_Input__arr_float_uint_2 = OpTypePointer Input %_arr_float_uint_2 +%_ptr_Input_v4float = OpTypePointer Input %v4float +%_ptr_Input_v3float = OpTypePointer Input %v3float +%_ptr_Output_v4float = OpTypePointer Output %v4float +%_ptr_Output_float = OpTypePointer Output %float +%_ptr_Output_v3float = OpTypePointer Output %v3float + %void = OpTypeVoid + %83 = OpTypeFunction %void +%_ptr_Function_float = OpTypePointer Function %float + %bool = OpTypeBool +%_ptr_Function_mat4v4float = OpTypePointer Function %mat4v4float +%_ptr_Uniform_mat4v4float = OpTypePointer Uniform %mat4v4float +%_ptr_Uniform_float = OpTypePointer Uniform %float +%ShadowDepthPass = OpVariable %_ptr_Uniform_type_ShadowDepthPass Uniform +%in_var_TEXCOORD10_centroid = OpVariable %_ptr_Input__arr_v4float_uint_3 Input +%in_var_TEXCOORD11_centroid = OpVariable %_ptr_Input__arr_v4float_uint_3 Input +%in_var_VS_to_DS_Position = OpVariable %_ptr_Input__arr_v4float_uint_3 Input +%in_var_VS_To_DS_VertexID = OpVariable %_ptr_Input__arr_uint_uint_3 Input +%in_var_PN_POSITION = OpVariable %_ptr_Input__arr__arr_v4float_uint_3_uint_3 Input +%in_var_PN_DisplacementScales = OpVariable %_ptr_Input__arr_v3float_uint_3 Input +%in_var_PN_TessellationMultiplier = OpVariable %_ptr_Input__arr_float_uint_3 Input +%in_var_PN_WorldDisplacementMultiplier = OpVariable %_ptr_Input__arr_float_uint_3 Input +%in_var_PN_DominantVertex = OpVariable %_ptr_Input__arr_v2float_uint_3 Input +%in_var_PN_DominantVertex1 = OpVariable %_ptr_Input__arr_v4float_uint_3 Input +%in_var_PN_DominantVertex2 = OpVariable %_ptr_Input__arr_v3float_uint_3 Input +%in_var_PN_DominantEdge = OpVariable %_ptr_Input__arr_v2float_uint_3 Input +%in_var_PN_DominantEdge1 = OpVariable %_ptr_Input__arr_v2float_uint_3 Input +%in_var_PN_DominantEdge2 = OpVariable %_ptr_Input__arr_v4float_uint_3 Input +%in_var_PN_DominantEdge3 = OpVariable %_ptr_Input__arr_v4float_uint_3 Input +%in_var_PN_DominantEdge4 = OpVariable %_ptr_Input__arr_v3float_uint_3 Input +%in_var_PN_DominantEdge5 = OpVariable %_ptr_Input__arr_v3float_uint_3 Input +%gl_TessLevelOuter = OpVariable %_ptr_Input__arr_float_uint_4 Input +%gl_TessLevelInner = OpVariable %_ptr_Input__arr_float_uint_2 Input +%in_var_PN_POSITION9 = OpVariable %_ptr_Input_v4float Input +%gl_TessCoord = OpVariable %_ptr_Input_v3float Input +%out_var_TEXCOORD10_centroid = OpVariable %_ptr_Output_v4float Output +%out_var_TEXCOORD11_centroid = OpVariable %_ptr_Output_v4float Output +%out_var_TEXCOORD6 = OpVariable %_ptr_Output_float Output +%out_var_TEXCOORD7 = OpVariable %_ptr_Output_v3float Output +%gl_Position = OpVariable %_ptr_Output_v4float Output + %89 = OpConstantNull %v4float + %90 = OpUndef %v4float + %MainDomain = OpFunction %void None %83 + %91 = OpLabel + %92 = OpVariable %_ptr_Function_mat4v4float Function + %93 = OpLoad %_arr_v4float_uint_3 %in_var_TEXCOORD10_centroid + %94 = OpLoad %_arr_v4float_uint_3 %in_var_TEXCOORD11_centroid + %95 = OpCompositeExtract %v4float %93 0 + %96 = OpCompositeExtract %v4float %94 0 + %97 = OpCompositeExtract %v4float %93 1 + %98 = OpCompositeExtract %v4float %94 1 + %99 = OpCompositeExtract %v4float %93 2 + %100 = OpCompositeExtract %v4float %94 2 + %101 = OpLoad %_arr__arr_v4float_uint_3_uint_3 %in_var_PN_POSITION + %102 = OpCompositeExtract %_arr_v4float_uint_3 %101 0 + %103 = OpCompositeExtract %_arr_v4float_uint_3 %101 1 + %104 = OpCompositeExtract %_arr_v4float_uint_3 %101 2 + %105 = OpCompositeExtract %v4float %102 0 + %106 = OpCompositeExtract %v4float %102 1 + %107 = OpCompositeExtract %v4float %102 2 + %108 = OpCompositeExtract %v4float %103 0 + %109 = OpCompositeExtract %v4float %103 1 + %110 = OpCompositeExtract %v4float %103 2 + %111 = OpCompositeExtract %v4float %104 0 + %112 = OpCompositeExtract %v4float %104 1 + %113 = OpCompositeExtract %v4float %104 2 + %114 = OpLoad %v4float %in_var_PN_POSITION9 + %115 = OpLoad %v3float %gl_TessCoord + %116 = OpCompositeExtract %float %115 0 + %117 = OpCompositeExtract %float %115 1 + %118 = OpCompositeExtract %float %115 2 + %119 = OpFMul %float %116 %116 + %120 = OpFMul %float %117 %117 + %121 = OpFMul %float %118 %118 + %122 = OpFMul %float %119 %float_3 + %123 = OpFMul %float %120 %float_3 + %124 = OpFMul %float %121 %float_3 + %125 = OpCompositeConstruct %v4float %119 %119 %119 %119 + %126 = OpFMul %v4float %105 %125 + %127 = OpCompositeConstruct %v4float %116 %116 %116 %116 + %128 = OpFMul %v4float %126 %127 + %129 = OpCompositeConstruct %v4float %120 %120 %120 %120 + %130 = OpFMul %v4float %108 %129 + %131 = OpCompositeConstruct %v4float %117 %117 %117 %117 + %132 = OpFMul %v4float %130 %131 + %133 = OpFAdd %v4float %128 %132 + %134 = OpCompositeConstruct %v4float %121 %121 %121 %121 + %135 = OpFMul %v4float %111 %134 + %136 = OpCompositeConstruct %v4float %118 %118 %118 %118 + %137 = OpFMul %v4float %135 %136 + %138 = OpFAdd %v4float %133 %137 + %139 = OpCompositeConstruct %v4float %122 %122 %122 %122 + %140 = OpFMul %v4float %106 %139 + %141 = OpFMul %v4float %140 %131 + %142 = OpFAdd %v4float %138 %141 + %143 = OpCompositeConstruct %v4float %123 %123 %123 %123 + %144 = OpFMul %v4float %107 %143 + %145 = OpFMul %v4float %144 %127 + %146 = OpFAdd %v4float %142 %145 + %147 = OpFMul %v4float %109 %143 + %148 = OpFMul %v4float %147 %136 + %149 = OpFAdd %v4float %146 %148 + %150 = OpCompositeConstruct %v4float %124 %124 %124 %124 + %151 = OpFMul %v4float %110 %150 + %152 = OpFMul %v4float %151 %131 + %153 = OpFAdd %v4float %149 %152 + %154 = OpFMul %v4float %112 %150 + %155 = OpFMul %v4float %154 %127 + %156 = OpFAdd %v4float %153 %155 + %157 = OpFMul %v4float %113 %139 + %158 = OpFMul %v4float %157 %136 + %159 = OpFAdd %v4float %156 %158 + %160 = OpFMul %v4float %114 %48 + %161 = OpFMul %v4float %160 %136 + %162 = OpFMul %v4float %161 %127 + %163 = OpFMul %v4float %162 %131 + %164 = OpFAdd %v4float %159 %163 + %165 = OpVectorShuffle %v3float %95 %95 0 1 2 + %166 = OpCompositeConstruct %v3float %116 %116 %116 + %167 = OpFMul %v3float %165 %166 + %168 = OpVectorShuffle %v3float %97 %97 0 1 2 + %169 = OpCompositeConstruct %v3float %117 %117 %117 + %170 = OpFMul %v3float %168 %169 + %171 = OpFAdd %v3float %167 %170 + %172 = OpFMul %v4float %96 %127 + %173 = OpFMul %v4float %98 %131 + %174 = OpFAdd %v4float %172 %173 + %175 = OpVectorShuffle %v3float %171 %89 0 1 2 + %176 = OpVectorShuffle %v3float %99 %99 0 1 2 + %177 = OpCompositeConstruct %v3float %118 %118 %118 + %178 = OpFMul %v3float %176 %177 + %179 = OpFAdd %v3float %175 %178 + %180 = OpVectorShuffle %v4float %90 %179 4 5 6 3 + %181 = OpFMul %v4float %100 %136 + %182 = OpFAdd %v4float %174 %181 + %183 = OpVectorShuffle %v3float %182 %182 0 1 2 + %184 = OpVectorShuffle %v4float %164 %164 4 5 6 3 + %185 = OpAccessChain %_ptr_Uniform_mat4v4float %ShadowDepthPass %int_88 + %186 = OpLoad %mat4v4float %185 + %187 = OpAccessChain %_ptr_Uniform_mat4v4float %ShadowDepthPass %int_89 + %188 = OpLoad %mat4v4float %187 + OpStore %92 %188 + %189 = OpMatrixTimesVector %v4float %186 %184 + %190 = OpAccessChain %_ptr_Uniform_float %ShadowDepthPass %int_91 + %191 = OpLoad %float %190 + %192 = OpFOrdGreaterThan %bool %191 %float_0 + %193 = OpCompositeExtract %float %189 2 + %194 = OpFOrdLessThan %bool %193 %float_0 + %195 = OpLogicalAnd %bool %192 %194 + OpSelectionMerge %196 None + OpBranchConditional %195 %197 %196 + %197 = OpLabel + %198 = OpCompositeInsert %v4float %float_9_99999997en07 %189 2 + %199 = OpCompositeInsert %v4float %float_1 %198 3 + OpBranch %196 + %196 = OpLabel + %200 = OpPhi %v4float %189 %91 %199 %197 + %201 = OpAccessChain %_ptr_Function_float %92 %uint_0 %int_2 + %202 = OpLoad %float %201 + %203 = OpAccessChain %_ptr_Function_float %92 %uint_1 %int_2 + %204 = OpLoad %float %203 + %205 = OpAccessChain %_ptr_Function_float %92 %uint_2 %int_2 + %206 = OpLoad %float %205 + %207 = OpCompositeConstruct %v3float %202 %204 %206 + %208 = OpDot %float %207 %183 + %209 = OpExtInst %float %1 FAbs %208 + %210 = OpAccessChain %_ptr_Uniform_float %ShadowDepthPass %int_90 %int_2 + %211 = OpLoad %float %210 + %212 = OpExtInst %float %1 FAbs %209 + %213 = OpFOrdGreaterThan %bool %212 %float_0 + %214 = OpFMul %float %209 %209 + %215 = OpFSub %float %float_1 %214 + %216 = OpExtInst %float %1 FClamp %215 %float_0 %float_1 + %217 = OpExtInst %float %1 Sqrt %216 + %218 = OpFDiv %float %217 %209 + %219 = OpSelect %float %213 %218 %211 + %220 = OpExtInst %float %1 FClamp %219 %float_0 %211 + %221 = OpAccessChain %_ptr_Uniform_float %ShadowDepthPass %int_90 %int_1 + %222 = OpLoad %float %221 + %223 = OpFMul %float %222 %220 + %224 = OpAccessChain %_ptr_Uniform_float %ShadowDepthPass %int_90 %int_0 + %225 = OpLoad %float %224 + %226 = OpFAdd %float %223 %225 + %227 = OpAccessChain %_ptr_Uniform_float %ShadowDepthPass %int_90 %int_3 + %228 = OpLoad %float %227 + %229 = OpCompositeExtract %float %200 2 + %230 = OpFMul %float %229 %228 + %231 = OpFAdd %float %230 %226 + %232 = OpCompositeExtract %float %200 3 + %233 = OpFMul %float %231 %232 + %234 = OpCompositeInsert %v4float %233 %200 2 + %235 = OpVectorShuffle %v3float %164 %89 0 1 2 + OpStore %out_var_TEXCOORD10_centroid %180 + OpStore %out_var_TEXCOORD11_centroid %182 + OpStore %out_var_TEXCOORD6 %float_0 + OpStore %out_var_TEXCOORD7 %235 + OpStore %gl_Position %234 + OpReturn + OpFunctionEnd diff --git a/third_party/spirv-cross/shaders-ue4/asm/tese/ds-texcoord-array.asm.tese b/third_party/spirv-cross/shaders-ue4/asm/tese/ds-texcoord-array.asm.tese new file mode 100644 index 0000000000..778e93d39a --- /dev/null +++ b/third_party/spirv-cross/shaders-ue4/asm/tese/ds-texcoord-array.asm.tese @@ -0,0 +1,715 @@ +; SPIR-V +; Version: 1.0 +; Generator: Google spiregg; 0 +; Bound: 183 +; Schema: 0 + OpCapability Tessellation + OpCapability SampledBuffer + OpExtension "SPV_GOOGLE_hlsl_functionality1" + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint TessellationEvaluation %MainDomain "main" %gl_TessLevelOuter %gl_TessLevelInner %in_var_TEXCOORD10_centroid %in_var_TEXCOORD11_centroid %in_var_TEXCOORD0 %in_var_COLOR1 %in_var_COLOR2 %in_var_VS_To_DS_Position %in_var_TEXCOORD7 %in_var_Flat_DisplacementScales %in_var_Flat_TessellationMultiplier %in_var_Flat_WorldDisplacementMultiplier %gl_TessCoord %out_var_TEXCOORD10_centroid %out_var_TEXCOORD11_centroid %out_var_TEXCOORD0 %out_var_COLOR1 %out_var_COLOR2 %out_var_TEXCOORD6 %out_var_TEXCOORD7 %gl_Position + OpExecutionMode %MainDomain Triangles + OpExecutionMode %MainDomain SpacingFractionalOdd + OpExecutionMode %MainDomain VertexOrderCw + OpSource HLSL 600 + OpName %type_View "type.View" + OpMemberName %type_View 0 "View_TranslatedWorldToClip" + OpMemberName %type_View 1 "View_WorldToClip" + OpMemberName %type_View 2 "View_ClipToWorld" + OpMemberName %type_View 3 "View_TranslatedWorldToView" + OpMemberName %type_View 4 "View_ViewToTranslatedWorld" + OpMemberName %type_View 5 "View_TranslatedWorldToCameraView" + OpMemberName %type_View 6 "View_CameraViewToTranslatedWorld" + OpMemberName %type_View 7 "View_ViewToClip" + OpMemberName %type_View 8 "View_ViewToClipNoAA" + OpMemberName %type_View 9 "View_ClipToView" + OpMemberName %type_View 10 "View_ClipToTranslatedWorld" + OpMemberName %type_View 11 "View_SVPositionToTranslatedWorld" + OpMemberName %type_View 12 "View_ScreenToWorld" + OpMemberName %type_View 13 "View_ScreenToTranslatedWorld" + OpMemberName %type_View 14 "View_ViewForward" + OpMemberName %type_View 15 "PrePadding_View_908" + OpMemberName %type_View 16 "View_ViewUp" + OpMemberName %type_View 17 "PrePadding_View_924" + OpMemberName %type_View 18 "View_ViewRight" + OpMemberName %type_View 19 "PrePadding_View_940" + OpMemberName %type_View 20 "View_HMDViewNoRollUp" + OpMemberName %type_View 21 "PrePadding_View_956" + OpMemberName %type_View 22 "View_HMDViewNoRollRight" + OpMemberName %type_View 23 "PrePadding_View_972" + OpMemberName %type_View 24 "View_InvDeviceZToWorldZTransform" + OpMemberName %type_View 25 "View_ScreenPositionScaleBias" + OpMemberName %type_View 26 "View_WorldCameraOrigin" + OpMemberName %type_View 27 "PrePadding_View_1020" + OpMemberName %type_View 28 "View_TranslatedWorldCameraOrigin" + OpMemberName %type_View 29 "PrePadding_View_1036" + OpMemberName %type_View 30 "View_WorldViewOrigin" + OpMemberName %type_View 31 "PrePadding_View_1052" + OpMemberName %type_View 32 "View_PreViewTranslation" + OpMemberName %type_View 33 "PrePadding_View_1068" + OpMemberName %type_View 34 "View_PrevProjection" + OpMemberName %type_View 35 "View_PrevViewProj" + OpMemberName %type_View 36 "View_PrevViewRotationProj" + OpMemberName %type_View 37 "View_PrevViewToClip" + OpMemberName %type_View 38 "View_PrevClipToView" + OpMemberName %type_View 39 "View_PrevTranslatedWorldToClip" + OpMemberName %type_View 40 "View_PrevTranslatedWorldToView" + OpMemberName %type_View 41 "View_PrevViewToTranslatedWorld" + OpMemberName %type_View 42 "View_PrevTranslatedWorldToCameraView" + OpMemberName %type_View 43 "View_PrevCameraViewToTranslatedWorld" + OpMemberName %type_View 44 "View_PrevWorldCameraOrigin" + OpMemberName %type_View 45 "PrePadding_View_1724" + OpMemberName %type_View 46 "View_PrevWorldViewOrigin" + OpMemberName %type_View 47 "PrePadding_View_1740" + OpMemberName %type_View 48 "View_PrevPreViewTranslation" + OpMemberName %type_View 49 "PrePadding_View_1756" + OpMemberName %type_View 50 "View_PrevInvViewProj" + OpMemberName %type_View 51 "View_PrevScreenToTranslatedWorld" + OpMemberName %type_View 52 "View_ClipToPrevClip" + OpMemberName %type_View 53 "View_TemporalAAJitter" + OpMemberName %type_View 54 "View_GlobalClippingPlane" + OpMemberName %type_View 55 "View_FieldOfViewWideAngles" + OpMemberName %type_View 56 "View_PrevFieldOfViewWideAngles" + OpMemberName %type_View 57 "View_ViewRectMin" + OpMemberName %type_View 58 "View_ViewSizeAndInvSize" + OpMemberName %type_View 59 "View_BufferSizeAndInvSize" + OpMemberName %type_View 60 "View_BufferBilinearUVMinMax" + OpMemberName %type_View 61 "View_NumSceneColorMSAASamples" + OpMemberName %type_View 62 "View_PreExposure" + OpMemberName %type_View 63 "View_OneOverPreExposure" + OpMemberName %type_View 64 "PrePadding_View_2076" + OpMemberName %type_View 65 "View_DiffuseOverrideParameter" + OpMemberName %type_View 66 "View_SpecularOverrideParameter" + OpMemberName %type_View 67 "View_NormalOverrideParameter" + OpMemberName %type_View 68 "View_RoughnessOverrideParameter" + OpMemberName %type_View 69 "View_PrevFrameGameTime" + OpMemberName %type_View 70 "View_PrevFrameRealTime" + OpMemberName %type_View 71 "View_OutOfBoundsMask" + OpMemberName %type_View 72 "PrePadding_View_2148" + OpMemberName %type_View 73 "PrePadding_View_2152" + OpMemberName %type_View 74 "PrePadding_View_2156" + OpMemberName %type_View 75 "View_WorldCameraMovementSinceLastFrame" + OpMemberName %type_View 76 "View_CullingSign" + OpMemberName %type_View 77 "View_NearPlane" + OpMemberName %type_View 78 "View_AdaptiveTessellationFactor" + OpMemberName %type_View 79 "View_GameTime" + OpMemberName %type_View 80 "View_RealTime" + OpMemberName %type_View 81 "View_DeltaTime" + OpMemberName %type_View 82 "View_MaterialTextureMipBias" + OpMemberName %type_View 83 "View_MaterialTextureDerivativeMultiply" + OpMemberName %type_View 84 "View_Random" + OpMemberName %type_View 85 "View_FrameNumber" + OpMemberName %type_View 86 "View_StateFrameIndexMod8" + OpMemberName %type_View 87 "View_StateFrameIndex" + OpMemberName %type_View 88 "View_CameraCut" + OpMemberName %type_View 89 "View_UnlitViewmodeMask" + OpMemberName %type_View 90 "PrePadding_View_2228" + OpMemberName %type_View 91 "PrePadding_View_2232" + OpMemberName %type_View 92 "PrePadding_View_2236" + OpMemberName %type_View 93 "View_DirectionalLightColor" + OpMemberName %type_View 94 "View_DirectionalLightDirection" + OpMemberName %type_View 95 "PrePadding_View_2268" + OpMemberName %type_View 96 "View_TranslucencyLightingVolumeMin" + OpMemberName %type_View 97 "View_TranslucencyLightingVolumeInvSize" + OpMemberName %type_View 98 "View_TemporalAAParams" + OpMemberName %type_View 99 "View_CircleDOFParams" + OpMemberName %type_View 100 "View_DepthOfFieldSensorWidth" + OpMemberName %type_View 101 "View_DepthOfFieldFocalDistance" + OpMemberName %type_View 102 "View_DepthOfFieldScale" + OpMemberName %type_View 103 "View_DepthOfFieldFocalLength" + OpMemberName %type_View 104 "View_DepthOfFieldFocalRegion" + OpMemberName %type_View 105 "View_DepthOfFieldNearTransitionRegion" + OpMemberName %type_View 106 "View_DepthOfFieldFarTransitionRegion" + OpMemberName %type_View 107 "View_MotionBlurNormalizedToPixel" + OpMemberName %type_View 108 "View_bSubsurfacePostprocessEnabled" + OpMemberName %type_View 109 "View_GeneralPurposeTweak" + OpMemberName %type_View 110 "View_DemosaicVposOffset" + OpMemberName %type_View 111 "PrePadding_View_2412" + OpMemberName %type_View 112 "View_IndirectLightingColorScale" + OpMemberName %type_View 113 "View_HDR32bppEncodingMode" + OpMemberName %type_View 114 "View_AtmosphericFogSunDirection" + OpMemberName %type_View 115 "View_AtmosphericFogSunPower" + OpMemberName %type_View 116 "View_AtmosphericFogPower" + OpMemberName %type_View 117 "View_AtmosphericFogDensityScale" + OpMemberName %type_View 118 "View_AtmosphericFogDensityOffset" + OpMemberName %type_View 119 "View_AtmosphericFogGroundOffset" + OpMemberName %type_View 120 "View_AtmosphericFogDistanceScale" + OpMemberName %type_View 121 "View_AtmosphericFogAltitudeScale" + OpMemberName %type_View 122 "View_AtmosphericFogHeightScaleRayleigh" + OpMemberName %type_View 123 "View_AtmosphericFogStartDistance" + OpMemberName %type_View 124 "View_AtmosphericFogDistanceOffset" + OpMemberName %type_View 125 "View_AtmosphericFogSunDiscScale" + OpMemberName %type_View 126 "View_AtmosphericFogSunDiscHalfApexAngleRadian" + OpMemberName %type_View 127 "PrePadding_View_2492" + OpMemberName %type_View 128 "View_AtmosphericFogSunDiscLuminance" + OpMemberName %type_View 129 "View_AtmosphericFogRenderMask" + OpMemberName %type_View 130 "View_AtmosphericFogInscatterAltitudeSampleNum" + OpMemberName %type_View 131 "PrePadding_View_2520" + OpMemberName %type_View 132 "PrePadding_View_2524" + OpMemberName %type_View 133 "View_AtmosphericFogSunColor" + OpMemberName %type_View 134 "View_NormalCurvatureToRoughnessScaleBias" + OpMemberName %type_View 135 "View_RenderingReflectionCaptureMask" + OpMemberName %type_View 136 "View_AmbientCubemapTint" + OpMemberName %type_View 137 "View_AmbientCubemapIntensity" + OpMemberName %type_View 138 "View_SkyLightParameters" + OpMemberName %type_View 139 "PrePadding_View_2584" + OpMemberName %type_View 140 "PrePadding_View_2588" + OpMemberName %type_View 141 "View_SkyLightColor" + OpMemberName %type_View 142 "View_SkyIrradianceEnvironmentMap" + OpMemberName %type_View 143 "View_MobilePreviewMode" + OpMemberName %type_View 144 "View_HMDEyePaddingOffset" + OpMemberName %type_View 145 "View_ReflectionCubemapMaxMip" + OpMemberName %type_View 146 "View_ShowDecalsMask" + OpMemberName %type_View 147 "View_DistanceFieldAOSpecularOcclusionMode" + OpMemberName %type_View 148 "View_IndirectCapsuleSelfShadowingIntensity" + OpMemberName %type_View 149 "PrePadding_View_2744" + OpMemberName %type_View 150 "PrePadding_View_2748" + OpMemberName %type_View 151 "View_ReflectionEnvironmentRoughnessMixingScaleBiasAndLargestWeight" + OpMemberName %type_View 152 "View_StereoPassIndex" + OpMemberName %type_View 153 "View_GlobalVolumeCenterAndExtent" + OpMemberName %type_View 154 "View_GlobalVolumeWorldToUVAddAndMul" + OpMemberName %type_View 155 "View_GlobalVolumeDimension" + OpMemberName %type_View 156 "View_GlobalVolumeTexelSize" + OpMemberName %type_View 157 "View_MaxGlobalDistance" + OpMemberName %type_View 158 "PrePadding_View_2908" + OpMemberName %type_View 159 "View_CursorPosition" + OpMemberName %type_View 160 "View_bCheckerboardSubsurfaceProfileRendering" + OpMemberName %type_View 161 "PrePadding_View_2924" + OpMemberName %type_View 162 "View_VolumetricFogInvGridSize" + OpMemberName %type_View 163 "PrePadding_View_2940" + OpMemberName %type_View 164 "View_VolumetricFogGridZParams" + OpMemberName %type_View 165 "PrePadding_View_2956" + OpMemberName %type_View 166 "View_VolumetricFogSVPosToVolumeUV" + OpMemberName %type_View 167 "View_VolumetricFogMaxDistance" + OpMemberName %type_View 168 "PrePadding_View_2972" + OpMemberName %type_View 169 "View_VolumetricLightmapWorldToUVScale" + OpMemberName %type_View 170 "PrePadding_View_2988" + OpMemberName %type_View 171 "View_VolumetricLightmapWorldToUVAdd" + OpMemberName %type_View 172 "PrePadding_View_3004" + OpMemberName %type_View 173 "View_VolumetricLightmapIndirectionTextureSize" + OpMemberName %type_View 174 "View_VolumetricLightmapBrickSize" + OpMemberName %type_View 175 "View_VolumetricLightmapBrickTexelSize" + OpMemberName %type_View 176 "View_StereoIPD" + OpMemberName %type_View 177 "View_IndirectLightingCacheShowFlag" + OpMemberName %type_View 178 "View_EyeToPixelSpreadAngle" + OpMemberName %type_View 179 "PrePadding_View_3048" + OpMemberName %type_View 180 "PrePadding_View_3052" + OpMemberName %type_View 181 "View_WorldToVirtualTexture" + OpMemberName %type_View 182 "View_VirtualTextureParams" + OpMemberName %type_View 183 "View_XRPassthroughCameraUVs" + OpName %View "View" + OpName %in_var_TEXCOORD10_centroid "in.var.TEXCOORD10_centroid" + OpName %in_var_TEXCOORD11_centroid "in.var.TEXCOORD11_centroid" + OpName %in_var_TEXCOORD0 "in.var.TEXCOORD0" + OpName %in_var_COLOR1 "in.var.COLOR1" + OpName %in_var_COLOR2 "in.var.COLOR2" + OpName %in_var_VS_To_DS_Position "in.var.VS_To_DS_Position" + OpName %in_var_TEXCOORD7 "in.var.TEXCOORD7" + OpName %in_var_Flat_DisplacementScales "in.var.Flat_DisplacementScales" + OpName %in_var_Flat_TessellationMultiplier "in.var.Flat_TessellationMultiplier" + OpName %in_var_Flat_WorldDisplacementMultiplier "in.var.Flat_WorldDisplacementMultiplier" + OpName %out_var_TEXCOORD10_centroid "out.var.TEXCOORD10_centroid" + OpName %out_var_TEXCOORD11_centroid "out.var.TEXCOORD11_centroid" + OpName %out_var_TEXCOORD0 "out.var.TEXCOORD0" + OpName %out_var_COLOR1 "out.var.COLOR1" + OpName %out_var_COLOR2 "out.var.COLOR2" + OpName %out_var_TEXCOORD6 "out.var.TEXCOORD6" + OpName %out_var_TEXCOORD7 "out.var.TEXCOORD7" + OpName %MainDomain "MainDomain" + OpDecorate %gl_TessLevelOuter BuiltIn TessLevelOuter + OpDecorateString %gl_TessLevelOuter UserSemantic "SV_TessFactor" + OpDecorate %gl_TessLevelOuter Patch + OpDecorate %gl_TessLevelInner BuiltIn TessLevelInner + OpDecorateString %gl_TessLevelInner UserSemantic "SV_InsideTessFactor" + OpDecorate %gl_TessLevelInner Patch + OpDecorateString %in_var_TEXCOORD10_centroid UserSemantic "TEXCOORD10_centroid" + OpDecorateString %in_var_TEXCOORD11_centroid UserSemantic "TEXCOORD11_centroid" + OpDecorateString %in_var_TEXCOORD0 UserSemantic "TEXCOORD0" + OpDecorateString %in_var_COLOR1 UserSemantic "COLOR1" + OpDecorateString %in_var_COLOR2 UserSemantic "COLOR2" + OpDecorateString %in_var_VS_To_DS_Position UserSemantic "VS_To_DS_Position" + OpDecorateString %in_var_TEXCOORD7 UserSemantic "TEXCOORD7" + OpDecorateString %in_var_Flat_DisplacementScales UserSemantic "Flat_DisplacementScales" + OpDecorateString %in_var_Flat_TessellationMultiplier UserSemantic "Flat_TessellationMultiplier" + OpDecorateString %in_var_Flat_WorldDisplacementMultiplier UserSemantic "Flat_WorldDisplacementMultiplier" + OpDecorate %gl_TessCoord BuiltIn TessCoord + OpDecorateString %gl_TessCoord UserSemantic "SV_DomainLocation" + OpDecorate %gl_TessCoord Patch + OpDecorateString %out_var_TEXCOORD10_centroid UserSemantic "TEXCOORD10_centroid" + OpDecorateString %out_var_TEXCOORD11_centroid UserSemantic "TEXCOORD11_centroid" + OpDecorateString %out_var_TEXCOORD0 UserSemantic "TEXCOORD0" + OpDecorateString %out_var_COLOR1 UserSemantic "COLOR1" + OpDecorateString %out_var_COLOR2 UserSemantic "COLOR2" + OpDecorateString %out_var_TEXCOORD6 UserSemantic "TEXCOORD6" + OpDecorateString %out_var_TEXCOORD7 UserSemantic "TEXCOORD7" + OpDecorate %gl_Position BuiltIn Position + OpDecorateString %gl_Position UserSemantic "SV_POSITION" + OpDecorate %in_var_COLOR1 Location 0 + OpDecorate %in_var_COLOR2 Location 1 + OpDecorate %in_var_Flat_DisplacementScales Location 2 + OpDecorate %in_var_Flat_TessellationMultiplier Location 3 + OpDecorate %in_var_Flat_WorldDisplacementMultiplier Location 4 + OpDecorate %in_var_TEXCOORD0 Location 5 + OpDecorate %in_var_TEXCOORD10_centroid Location 6 + OpDecorate %in_var_TEXCOORD11_centroid Location 7 + OpDecorate %in_var_TEXCOORD7 Location 8 + OpDecorate %in_var_VS_To_DS_Position Location 9 + OpDecorate %out_var_TEXCOORD10_centroid Location 0 + OpDecorate %out_var_TEXCOORD11_centroid Location 1 + OpDecorate %out_var_TEXCOORD0 Location 2 + OpDecorate %out_var_COLOR1 Location 3 + OpDecorate %out_var_COLOR2 Location 4 + OpDecorate %out_var_TEXCOORD6 Location 5 + OpDecorate %out_var_TEXCOORD7 Location 6 + OpDecorate %View DescriptorSet 0 + OpDecorate %View Binding 0 + OpDecorate %_arr_v4float_uint_2 ArrayStride 16 + OpDecorate %_arr_v4float_uint_7 ArrayStride 16 + OpDecorate %_arr_v4float_uint_4 ArrayStride 16 + OpMemberDecorate %type_View 0 Offset 0 + OpMemberDecorate %type_View 0 MatrixStride 16 + OpMemberDecorate %type_View 0 ColMajor + OpMemberDecorate %type_View 1 Offset 64 + OpMemberDecorate %type_View 1 MatrixStride 16 + OpMemberDecorate %type_View 1 ColMajor + OpMemberDecorate %type_View 2 Offset 128 + OpMemberDecorate %type_View 2 MatrixStride 16 + OpMemberDecorate %type_View 2 ColMajor + OpMemberDecorate %type_View 3 Offset 192 + OpMemberDecorate %type_View 3 MatrixStride 16 + OpMemberDecorate %type_View 3 ColMajor + OpMemberDecorate %type_View 4 Offset 256 + OpMemberDecorate %type_View 4 MatrixStride 16 + OpMemberDecorate %type_View 4 ColMajor + OpMemberDecorate %type_View 5 Offset 320 + OpMemberDecorate %type_View 5 MatrixStride 16 + OpMemberDecorate %type_View 5 ColMajor + OpMemberDecorate %type_View 6 Offset 384 + OpMemberDecorate %type_View 6 MatrixStride 16 + OpMemberDecorate %type_View 6 ColMajor + OpMemberDecorate %type_View 7 Offset 448 + OpMemberDecorate %type_View 7 MatrixStride 16 + OpMemberDecorate %type_View 7 ColMajor + OpMemberDecorate %type_View 8 Offset 512 + OpMemberDecorate %type_View 8 MatrixStride 16 + OpMemberDecorate %type_View 8 ColMajor + OpMemberDecorate %type_View 9 Offset 576 + OpMemberDecorate %type_View 9 MatrixStride 16 + OpMemberDecorate %type_View 9 ColMajor + OpMemberDecorate %type_View 10 Offset 640 + OpMemberDecorate %type_View 10 MatrixStride 16 + OpMemberDecorate %type_View 10 ColMajor + OpMemberDecorate %type_View 11 Offset 704 + OpMemberDecorate %type_View 11 MatrixStride 16 + OpMemberDecorate %type_View 11 ColMajor + OpMemberDecorate %type_View 12 Offset 768 + OpMemberDecorate %type_View 12 MatrixStride 16 + OpMemberDecorate %type_View 12 ColMajor + OpMemberDecorate %type_View 13 Offset 832 + OpMemberDecorate %type_View 13 MatrixStride 16 + OpMemberDecorate %type_View 13 ColMajor + OpMemberDecorate %type_View 14 Offset 896 + OpMemberDecorate %type_View 15 Offset 908 + OpMemberDecorate %type_View 16 Offset 912 + OpMemberDecorate %type_View 17 Offset 924 + OpMemberDecorate %type_View 18 Offset 928 + OpMemberDecorate %type_View 19 Offset 940 + OpMemberDecorate %type_View 20 Offset 944 + OpMemberDecorate %type_View 21 Offset 956 + OpMemberDecorate %type_View 22 Offset 960 + OpMemberDecorate %type_View 23 Offset 972 + OpMemberDecorate %type_View 24 Offset 976 + OpMemberDecorate %type_View 25 Offset 992 + OpMemberDecorate %type_View 26 Offset 1008 + OpMemberDecorate %type_View 27 Offset 1020 + OpMemberDecorate %type_View 28 Offset 1024 + OpMemberDecorate %type_View 29 Offset 1036 + OpMemberDecorate %type_View 30 Offset 1040 + OpMemberDecorate %type_View 31 Offset 1052 + OpMemberDecorate %type_View 32 Offset 1056 + OpMemberDecorate %type_View 33 Offset 1068 + OpMemberDecorate %type_View 34 Offset 1072 + OpMemberDecorate %type_View 34 MatrixStride 16 + OpMemberDecorate %type_View 34 ColMajor + OpMemberDecorate %type_View 35 Offset 1136 + OpMemberDecorate %type_View 35 MatrixStride 16 + OpMemberDecorate %type_View 35 ColMajor + OpMemberDecorate %type_View 36 Offset 1200 + OpMemberDecorate %type_View 36 MatrixStride 16 + OpMemberDecorate %type_View 36 ColMajor + OpMemberDecorate %type_View 37 Offset 1264 + OpMemberDecorate %type_View 37 MatrixStride 16 + OpMemberDecorate %type_View 37 ColMajor + OpMemberDecorate %type_View 38 Offset 1328 + OpMemberDecorate %type_View 38 MatrixStride 16 + OpMemberDecorate %type_View 38 ColMajor + OpMemberDecorate %type_View 39 Offset 1392 + OpMemberDecorate %type_View 39 MatrixStride 16 + OpMemberDecorate %type_View 39 ColMajor + OpMemberDecorate %type_View 40 Offset 1456 + OpMemberDecorate %type_View 40 MatrixStride 16 + OpMemberDecorate %type_View 40 ColMajor + OpMemberDecorate %type_View 41 Offset 1520 + OpMemberDecorate %type_View 41 MatrixStride 16 + OpMemberDecorate %type_View 41 ColMajor + OpMemberDecorate %type_View 42 Offset 1584 + OpMemberDecorate %type_View 42 MatrixStride 16 + OpMemberDecorate %type_View 42 ColMajor + OpMemberDecorate %type_View 43 Offset 1648 + OpMemberDecorate %type_View 43 MatrixStride 16 + OpMemberDecorate %type_View 43 ColMajor + OpMemberDecorate %type_View 44 Offset 1712 + OpMemberDecorate %type_View 45 Offset 1724 + OpMemberDecorate %type_View 46 Offset 1728 + OpMemberDecorate %type_View 47 Offset 1740 + OpMemberDecorate %type_View 48 Offset 1744 + OpMemberDecorate %type_View 49 Offset 1756 + OpMemberDecorate %type_View 50 Offset 1760 + OpMemberDecorate %type_View 50 MatrixStride 16 + OpMemberDecorate %type_View 50 ColMajor + OpMemberDecorate %type_View 51 Offset 1824 + OpMemberDecorate %type_View 51 MatrixStride 16 + OpMemberDecorate %type_View 51 ColMajor + OpMemberDecorate %type_View 52 Offset 1888 + OpMemberDecorate %type_View 52 MatrixStride 16 + OpMemberDecorate %type_View 52 ColMajor + OpMemberDecorate %type_View 53 Offset 1952 + OpMemberDecorate %type_View 54 Offset 1968 + OpMemberDecorate %type_View 55 Offset 1984 + OpMemberDecorate %type_View 56 Offset 1992 + OpMemberDecorate %type_View 57 Offset 2000 + OpMemberDecorate %type_View 58 Offset 2016 + OpMemberDecorate %type_View 59 Offset 2032 + OpMemberDecorate %type_View 60 Offset 2048 + OpMemberDecorate %type_View 61 Offset 2064 + OpMemberDecorate %type_View 62 Offset 2068 + OpMemberDecorate %type_View 63 Offset 2072 + OpMemberDecorate %type_View 64 Offset 2076 + OpMemberDecorate %type_View 65 Offset 2080 + OpMemberDecorate %type_View 66 Offset 2096 + OpMemberDecorate %type_View 67 Offset 2112 + OpMemberDecorate %type_View 68 Offset 2128 + OpMemberDecorate %type_View 69 Offset 2136 + OpMemberDecorate %type_View 70 Offset 2140 + OpMemberDecorate %type_View 71 Offset 2144 + OpMemberDecorate %type_View 72 Offset 2148 + OpMemberDecorate %type_View 73 Offset 2152 + OpMemberDecorate %type_View 74 Offset 2156 + OpMemberDecorate %type_View 75 Offset 2160 + OpMemberDecorate %type_View 76 Offset 2172 + OpMemberDecorate %type_View 77 Offset 2176 + OpMemberDecorate %type_View 78 Offset 2180 + OpMemberDecorate %type_View 79 Offset 2184 + OpMemberDecorate %type_View 80 Offset 2188 + OpMemberDecorate %type_View 81 Offset 2192 + OpMemberDecorate %type_View 82 Offset 2196 + OpMemberDecorate %type_View 83 Offset 2200 + OpMemberDecorate %type_View 84 Offset 2204 + OpMemberDecorate %type_View 85 Offset 2208 + OpMemberDecorate %type_View 86 Offset 2212 + OpMemberDecorate %type_View 87 Offset 2216 + OpMemberDecorate %type_View 88 Offset 2220 + OpMemberDecorate %type_View 89 Offset 2224 + OpMemberDecorate %type_View 90 Offset 2228 + OpMemberDecorate %type_View 91 Offset 2232 + OpMemberDecorate %type_View 92 Offset 2236 + OpMemberDecorate %type_View 93 Offset 2240 + OpMemberDecorate %type_View 94 Offset 2256 + OpMemberDecorate %type_View 95 Offset 2268 + OpMemberDecorate %type_View 96 Offset 2272 + OpMemberDecorate %type_View 97 Offset 2304 + OpMemberDecorate %type_View 98 Offset 2336 + OpMemberDecorate %type_View 99 Offset 2352 + OpMemberDecorate %type_View 100 Offset 2368 + OpMemberDecorate %type_View 101 Offset 2372 + OpMemberDecorate %type_View 102 Offset 2376 + OpMemberDecorate %type_View 103 Offset 2380 + OpMemberDecorate %type_View 104 Offset 2384 + OpMemberDecorate %type_View 105 Offset 2388 + OpMemberDecorate %type_View 106 Offset 2392 + OpMemberDecorate %type_View 107 Offset 2396 + OpMemberDecorate %type_View 108 Offset 2400 + OpMemberDecorate %type_View 109 Offset 2404 + OpMemberDecorate %type_View 110 Offset 2408 + OpMemberDecorate %type_View 111 Offset 2412 + OpMemberDecorate %type_View 112 Offset 2416 + OpMemberDecorate %type_View 113 Offset 2428 + OpMemberDecorate %type_View 114 Offset 2432 + OpMemberDecorate %type_View 115 Offset 2444 + OpMemberDecorate %type_View 116 Offset 2448 + OpMemberDecorate %type_View 117 Offset 2452 + OpMemberDecorate %type_View 118 Offset 2456 + OpMemberDecorate %type_View 119 Offset 2460 + OpMemberDecorate %type_View 120 Offset 2464 + OpMemberDecorate %type_View 121 Offset 2468 + OpMemberDecorate %type_View 122 Offset 2472 + OpMemberDecorate %type_View 123 Offset 2476 + OpMemberDecorate %type_View 124 Offset 2480 + OpMemberDecorate %type_View 125 Offset 2484 + OpMemberDecorate %type_View 126 Offset 2488 + OpMemberDecorate %type_View 127 Offset 2492 + OpMemberDecorate %type_View 128 Offset 2496 + OpMemberDecorate %type_View 129 Offset 2512 + OpMemberDecorate %type_View 130 Offset 2516 + OpMemberDecorate %type_View 131 Offset 2520 + OpMemberDecorate %type_View 132 Offset 2524 + OpMemberDecorate %type_View 133 Offset 2528 + OpMemberDecorate %type_View 134 Offset 2544 + OpMemberDecorate %type_View 135 Offset 2556 + OpMemberDecorate %type_View 136 Offset 2560 + OpMemberDecorate %type_View 137 Offset 2576 + OpMemberDecorate %type_View 138 Offset 2580 + OpMemberDecorate %type_View 139 Offset 2584 + OpMemberDecorate %type_View 140 Offset 2588 + OpMemberDecorate %type_View 141 Offset 2592 + OpMemberDecorate %type_View 142 Offset 2608 + OpMemberDecorate %type_View 143 Offset 2720 + OpMemberDecorate %type_View 144 Offset 2724 + OpMemberDecorate %type_View 145 Offset 2728 + OpMemberDecorate %type_View 146 Offset 2732 + OpMemberDecorate %type_View 147 Offset 2736 + OpMemberDecorate %type_View 148 Offset 2740 + OpMemberDecorate %type_View 149 Offset 2744 + OpMemberDecorate %type_View 150 Offset 2748 + OpMemberDecorate %type_View 151 Offset 2752 + OpMemberDecorate %type_View 152 Offset 2764 + OpMemberDecorate %type_View 153 Offset 2768 + OpMemberDecorate %type_View 154 Offset 2832 + OpMemberDecorate %type_View 155 Offset 2896 + OpMemberDecorate %type_View 156 Offset 2900 + OpMemberDecorate %type_View 157 Offset 2904 + OpMemberDecorate %type_View 158 Offset 2908 + OpMemberDecorate %type_View 159 Offset 2912 + OpMemberDecorate %type_View 160 Offset 2920 + OpMemberDecorate %type_View 161 Offset 2924 + OpMemberDecorate %type_View 162 Offset 2928 + OpMemberDecorate %type_View 163 Offset 2940 + OpMemberDecorate %type_View 164 Offset 2944 + OpMemberDecorate %type_View 165 Offset 2956 + OpMemberDecorate %type_View 166 Offset 2960 + OpMemberDecorate %type_View 167 Offset 2968 + OpMemberDecorate %type_View 168 Offset 2972 + OpMemberDecorate %type_View 169 Offset 2976 + OpMemberDecorate %type_View 170 Offset 2988 + OpMemberDecorate %type_View 171 Offset 2992 + OpMemberDecorate %type_View 172 Offset 3004 + OpMemberDecorate %type_View 173 Offset 3008 + OpMemberDecorate %type_View 174 Offset 3020 + OpMemberDecorate %type_View 175 Offset 3024 + OpMemberDecorate %type_View 176 Offset 3036 + OpMemberDecorate %type_View 177 Offset 3040 + OpMemberDecorate %type_View 178 Offset 3044 + OpMemberDecorate %type_View 179 Offset 3048 + OpMemberDecorate %type_View 180 Offset 3052 + OpMemberDecorate %type_View 181 Offset 3056 + OpMemberDecorate %type_View 181 MatrixStride 16 + OpMemberDecorate %type_View 181 ColMajor + OpMemberDecorate %type_View 182 Offset 3120 + OpMemberDecorate %type_View 183 Offset 3136 + OpDecorate %type_View Block + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 +%mat4v4float = OpTypeMatrix %v4float 4 + %v3float = OpTypeVector %float 3 + %v2float = OpTypeVector %float 2 + %int = OpTypeInt 32 1 + %uint = OpTypeInt 32 0 + %uint_2 = OpConstant %uint 2 + %uint_7 = OpConstant %uint 7 + %uint_4 = OpConstant %uint 4 + %v2int = OpTypeVector %int 2 + %int_0 = OpConstant %int 0 + %int_1 = OpConstant %int 1 + %uint_1 = OpConstant %uint 1 +%_arr_v4float_uint_2 = OpTypeArray %v4float %uint_2 +%_arr_v4float_uint_7 = OpTypeArray %v4float %uint_7 +%_arr_v4float_uint_4 = OpTypeArray %v4float %uint_4 + %type_View = OpTypeStruct %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %v3float %float %v3float %float %v3float %float %v3float %float %v3float %float %v4float %v4float %v3float %float %v3float %float %v3float %float %v3float %float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %v3float %float %v3float %float %v3float %float %mat4v4float %mat4v4float %mat4v4float %v4float %v4float %v2float %v2float %v4float %v4float %v4float %v4float %int %float %float %float %v4float %v4float %v4float %v2float %float %float %float %float %float %float %v3float %float %float %float %float %float %float %float %float %uint %uint %uint %uint %float %float %float %float %float %v4float %v3float %float %_arr_v4float_uint_2 %_arr_v4float_uint_2 %v4float %v4float %float %float %float %float %float %float %float %float %float %float %float %float %v3float %float %v3float %float %float %float %float %float %float %float %float %float %float %float %float %float %v4float %uint %uint %uint %uint %v4float %v3float %float %v4float %float %float %float %float %v4float %_arr_v4float_uint_7 %float %float %float %float %uint %float %float %float %v3float %int %_arr_v4float_uint_4 %_arr_v4float_uint_4 %float %float %float %float %v2int %float %float %v3float %float %v3float %float %v2float %float %float %v3float %float %v3float %float %v3float %float %v3float %float %float %float %float %float %mat4v4float %v4float %_arr_v4float_uint_2 +%_ptr_Uniform_type_View = OpTypePointer Uniform %type_View +%_arr_float_uint_4 = OpTypeArray %float %uint_4 +%_ptr_Input__arr_float_uint_4 = OpTypePointer Input %_arr_float_uint_4 +%_arr_float_uint_2 = OpTypeArray %float %uint_2 +%_ptr_Input__arr_float_uint_2 = OpTypePointer Input %_arr_float_uint_2 + %uint_3 = OpConstant %uint 3 +%_arr_v4float_uint_3 = OpTypeArray %v4float %uint_3 +%_ptr_Input__arr_v4float_uint_3 = OpTypePointer Input %_arr_v4float_uint_3 +%_arr_v4float_uint_1 = OpTypeArray %v4float %uint_1 +%_arr__arr_v4float_uint_1_uint_3 = OpTypeArray %_arr_v4float_uint_1 %uint_3 +%_ptr_Input__arr__arr_v4float_uint_1_uint_3 = OpTypePointer Input %_arr__arr_v4float_uint_1_uint_3 +%_arr_v3float_uint_3 = OpTypeArray %v3float %uint_3 +%_ptr_Input__arr_v3float_uint_3 = OpTypePointer Input %_arr_v3float_uint_3 +%_arr_float_uint_3 = OpTypeArray %float %uint_3 +%_ptr_Input__arr_float_uint_3 = OpTypePointer Input %_arr_float_uint_3 +%_ptr_Input_v3float = OpTypePointer Input %v3float +%_ptr_Output_v4float = OpTypePointer Output %v4float +%_ptr_Output__arr_v4float_uint_1 = OpTypePointer Output %_arr_v4float_uint_1 +%_ptr_Output_v3float = OpTypePointer Output %v3float + %void = OpTypeVoid + %63 = OpTypeFunction %void +%_ptr_Function_v4float = OpTypePointer Function %v4float + %bool = OpTypeBool +%_ptr_Uniform_mat4v4float = OpTypePointer Uniform %mat4v4float + %View = OpVariable %_ptr_Uniform_type_View Uniform +%gl_TessLevelOuter = OpVariable %_ptr_Input__arr_float_uint_4 Input +%gl_TessLevelInner = OpVariable %_ptr_Input__arr_float_uint_2 Input +%in_var_TEXCOORD10_centroid = OpVariable %_ptr_Input__arr_v4float_uint_3 Input +%in_var_TEXCOORD11_centroid = OpVariable %_ptr_Input__arr_v4float_uint_3 Input +%in_var_TEXCOORD0 = OpVariable %_ptr_Input__arr__arr_v4float_uint_1_uint_3 Input +%in_var_COLOR1 = OpVariable %_ptr_Input__arr_v4float_uint_3 Input +%in_var_COLOR2 = OpVariable %_ptr_Input__arr_v4float_uint_3 Input +%in_var_VS_To_DS_Position = OpVariable %_ptr_Input__arr_v4float_uint_3 Input +%in_var_TEXCOORD7 = OpVariable %_ptr_Input__arr_v3float_uint_3 Input +%in_var_Flat_DisplacementScales = OpVariable %_ptr_Input__arr_v3float_uint_3 Input +%in_var_Flat_TessellationMultiplier = OpVariable %_ptr_Input__arr_float_uint_3 Input +%in_var_Flat_WorldDisplacementMultiplier = OpVariable %_ptr_Input__arr_float_uint_3 Input +%gl_TessCoord = OpVariable %_ptr_Input_v3float Input +%out_var_TEXCOORD10_centroid = OpVariable %_ptr_Output_v4float Output +%out_var_TEXCOORD11_centroid = OpVariable %_ptr_Output_v4float Output +%out_var_TEXCOORD0 = OpVariable %_ptr_Output__arr_v4float_uint_1 Output +%out_var_COLOR1 = OpVariable %_ptr_Output_v4float Output +%out_var_COLOR2 = OpVariable %_ptr_Output_v4float Output +%out_var_TEXCOORD6 = OpVariable %_ptr_Output_v4float Output +%out_var_TEXCOORD7 = OpVariable %_ptr_Output_v3float Output +%gl_Position = OpVariable %_ptr_Output_v4float Output +%_ptr_Function__arr_v4float_uint_1 = OpTypePointer Function %_arr_v4float_uint_1 + %68 = OpUndef %v4float + %69 = OpConstantNull %v4float + %MainDomain = OpFunction %void None %63 + %70 = OpLabel + %71 = OpVariable %_ptr_Function__arr_v4float_uint_1 Function + %72 = OpVariable %_ptr_Function__arr_v4float_uint_1 Function + %73 = OpVariable %_ptr_Function__arr_v4float_uint_1 Function + %74 = OpVariable %_ptr_Function__arr_v4float_uint_1 Function + %75 = OpVariable %_ptr_Function__arr_v4float_uint_1 Function + %76 = OpVariable %_ptr_Function__arr_v4float_uint_1 Function + %77 = OpLoad %_arr_v4float_uint_3 %in_var_TEXCOORD10_centroid + %78 = OpLoad %_arr_v4float_uint_3 %in_var_TEXCOORD11_centroid + %79 = OpLoad %_arr__arr_v4float_uint_1_uint_3 %in_var_TEXCOORD0 + %80 = OpLoad %_arr_v4float_uint_3 %in_var_COLOR1 + %81 = OpLoad %_arr_v4float_uint_3 %in_var_COLOR2 + %82 = OpCompositeExtract %v4float %77 0 + %83 = OpCompositeExtract %v4float %78 0 + %84 = OpCompositeExtract %_arr_v4float_uint_1 %79 0 + %85 = OpCompositeExtract %v4float %80 0 + %86 = OpCompositeExtract %v4float %81 0 + %87 = OpCompositeExtract %v4float %77 1 + %88 = OpCompositeExtract %v4float %78 1 + %89 = OpCompositeExtract %_arr_v4float_uint_1 %79 1 + %90 = OpCompositeExtract %v4float %80 1 + %91 = OpCompositeExtract %v4float %81 1 + %92 = OpCompositeExtract %v4float %77 2 + %93 = OpCompositeExtract %v4float %78 2 + %94 = OpCompositeExtract %_arr_v4float_uint_1 %79 2 + %95 = OpCompositeExtract %v4float %80 2 + %96 = OpCompositeExtract %v4float %81 2 + %97 = OpLoad %_arr_v4float_uint_3 %in_var_VS_To_DS_Position + %98 = OpLoad %_arr_v3float_uint_3 %in_var_TEXCOORD7 + %99 = OpCompositeExtract %v4float %97 0 + %100 = OpCompositeExtract %v3float %98 0 + %101 = OpCompositeExtract %v4float %97 1 + %102 = OpCompositeExtract %v3float %98 1 + %103 = OpCompositeExtract %v4float %97 2 + %104 = OpCompositeExtract %v3float %98 2 + %105 = OpLoad %v3float %gl_TessCoord + %106 = OpAccessChain %_ptr_Uniform_mat4v4float %View %int_0 + %107 = OpLoad %mat4v4float %106 + %108 = OpCompositeExtract %float %105 0 + %109 = OpCompositeExtract %float %105 1 + %110 = OpCompositeExtract %float %105 2 + %111 = OpCompositeConstruct %v4float %108 %108 %108 %108 + %112 = OpFMul %v4float %99 %111 + %113 = OpCompositeConstruct %v4float %109 %109 %109 %109 + %114 = OpFMul %v4float %101 %113 + %115 = OpFAdd %v4float %112 %114 + %116 = OpCompositeConstruct %v4float %110 %110 %110 %110 + %117 = OpFMul %v4float %103 %116 + %118 = OpFAdd %v4float %115 %117 + OpStore %72 %84 + OpStore %71 %89 + %119 = OpVectorShuffle %v3float %82 %82 0 1 2 + %120 = OpCompositeConstruct %v3float %108 %108 %108 + %121 = OpFMul %v3float %119 %120 + %122 = OpVectorShuffle %v3float %87 %87 0 1 2 + %123 = OpCompositeConstruct %v3float %109 %109 %109 + %124 = OpFMul %v3float %122 %123 + %125 = OpFAdd %v3float %121 %124 + %126 = OpFMul %v4float %83 %111 + %127 = OpFMul %v4float %88 %113 + %128 = OpFAdd %v4float %126 %127 + %129 = OpFMul %v4float %85 %111 + %130 = OpFMul %v4float %90 %113 + %131 = OpFAdd %v4float %129 %130 + OpBranch %132 + %132 = OpLabel + %133 = OpPhi %int %int_0 %70 %134 %135 + %136 = OpSLessThan %bool %133 %int_1 + OpLoopMerge %137 %135 None + OpBranchConditional %136 %135 %137 + %135 = OpLabel + %138 = OpAccessChain %_ptr_Function_v4float %72 %133 + %139 = OpLoad %v4float %138 + %140 = OpFMul %v4float %139 %111 + %141 = OpAccessChain %_ptr_Function_v4float %71 %133 + %142 = OpLoad %v4float %141 + %143 = OpFMul %v4float %142 %113 + %144 = OpFAdd %v4float %140 %143 + %145 = OpAccessChain %_ptr_Function_v4float %73 %133 + OpStore %145 %144 + %134 = OpIAdd %int %133 %int_1 + OpBranch %132 + %137 = OpLabel + %146 = OpFMul %v4float %86 %111 + %147 = OpFMul %v4float %91 %113 + %148 = OpFAdd %v4float %146 %147 + %149 = OpLoad %_arr_v4float_uint_1 %73 + %150 = OpFMul %v3float %100 %120 + %151 = OpFMul %v3float %102 %123 + %152 = OpFAdd %v3float %150 %151 + OpStore %75 %149 + OpStore %74 %94 + %153 = OpVectorShuffle %v3float %125 %69 0 1 2 + %154 = OpVectorShuffle %v3float %92 %92 0 1 2 + %155 = OpCompositeConstruct %v3float %110 %110 %110 + %156 = OpFMul %v3float %154 %155 + %157 = OpFAdd %v3float %153 %156 + %158 = OpVectorShuffle %v4float %68 %157 4 5 6 3 + %159 = OpFMul %v4float %93 %116 + %160 = OpFAdd %v4float %128 %159 + %161 = OpFMul %v4float %95 %116 + %162 = OpFAdd %v4float %131 %161 + OpBranch %163 + %163 = OpLabel + %164 = OpPhi %int %int_0 %137 %165 %166 + %167 = OpSLessThan %bool %164 %int_1 + OpLoopMerge %168 %166 None + OpBranchConditional %167 %166 %168 + %166 = OpLabel + %169 = OpAccessChain %_ptr_Function_v4float %75 %164 + %170 = OpLoad %v4float %169 + %171 = OpAccessChain %_ptr_Function_v4float %74 %164 + %172 = OpLoad %v4float %171 + %173 = OpFMul %v4float %172 %116 + %174 = OpFAdd %v4float %170 %173 + %175 = OpAccessChain %_ptr_Function_v4float %76 %164 + OpStore %175 %174 + %165 = OpIAdd %int %164 %int_1 + OpBranch %163 + %168 = OpLabel + %176 = OpFMul %v4float %96 %116 + %177 = OpFAdd %v4float %148 %176 + %178 = OpLoad %_arr_v4float_uint_1 %76 + %179 = OpFMul %v3float %104 %155 + %180 = OpFAdd %v3float %152 %179 + %181 = OpVectorShuffle %v4float %118 %118 4 5 6 3 + %182 = OpMatrixTimesVector %v4float %107 %181 + OpStore %out_var_TEXCOORD10_centroid %158 + OpStore %out_var_TEXCOORD11_centroid %160 + OpStore %out_var_TEXCOORD0 %178 + OpStore %out_var_COLOR1 %162 + OpStore %out_var_COLOR2 %177 + OpStore %out_var_TEXCOORD6 %181 + OpStore %out_var_TEXCOORD7 %180 + OpStore %gl_Position %182 + OpReturn + OpFunctionEnd diff --git a/third_party/spirv-cross/shaders-ue4/asm/vert/array-missing-copies.asm.vert b/third_party/spirv-cross/shaders-ue4/asm/vert/array-missing-copies.asm.vert new file mode 100644 index 0000000000..23dc727560 --- /dev/null +++ b/third_party/spirv-cross/shaders-ue4/asm/vert/array-missing-copies.asm.vert @@ -0,0 +1,1131 @@ +; SPIR-V +; Version: 1.0 +; Generator: Google spiregg; 0 +; Bound: 487 +; Schema: 0 + OpCapability Shader + OpExtension "SPV_GOOGLE_hlsl_functionality1" + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %Main "main" %in_var_ATTRIBUTE0 %in_var_ATTRIBUTE1 %out_var_TEXCOORD0 %out_var_TEXCOORD1 %out_var_TEXCOORD2 %out_var_TEXCOORD3 %out_var_TEXCOORD8 %gl_Position + OpSource HLSL 600 + OpName %type_View "type.View" + OpMemberName %type_View 0 "View_TranslatedWorldToClip" + OpMemberName %type_View 1 "View_WorldToClip" + OpMemberName %type_View 2 "View_TranslatedWorldToView" + OpMemberName %type_View 3 "View_ViewToTranslatedWorld" + OpMemberName %type_View 4 "View_TranslatedWorldToCameraView" + OpMemberName %type_View 5 "View_CameraViewToTranslatedWorld" + OpMemberName %type_View 6 "View_ViewToClip" + OpMemberName %type_View 7 "View_ViewToClipNoAA" + OpMemberName %type_View 8 "View_ClipToView" + OpMemberName %type_View 9 "View_ClipToTranslatedWorld" + OpMemberName %type_View 10 "View_SVPositionToTranslatedWorld" + OpMemberName %type_View 11 "View_ScreenToWorld" + OpMemberName %type_View 12 "View_ScreenToTranslatedWorld" + OpMemberName %type_View 13 "View_ViewForward" + OpMemberName %type_View 14 "PrePadding_View_844" + OpMemberName %type_View 15 "View_ViewUp" + OpMemberName %type_View 16 "PrePadding_View_860" + OpMemberName %type_View 17 "View_ViewRight" + OpMemberName %type_View 18 "PrePadding_View_876" + OpMemberName %type_View 19 "View_HMDViewNoRollUp" + OpMemberName %type_View 20 "PrePadding_View_892" + OpMemberName %type_View 21 "View_HMDViewNoRollRight" + OpMemberName %type_View 22 "PrePadding_View_908" + OpMemberName %type_View 23 "View_InvDeviceZToWorldZTransform" + OpMemberName %type_View 24 "View_ScreenPositionScaleBias" + OpMemberName %type_View 25 "View_WorldCameraOrigin" + OpMemberName %type_View 26 "PrePadding_View_956" + OpMemberName %type_View 27 "View_TranslatedWorldCameraOrigin" + OpMemberName %type_View 28 "PrePadding_View_972" + OpMemberName %type_View 29 "View_WorldViewOrigin" + OpMemberName %type_View 30 "PrePadding_View_988" + OpMemberName %type_View 31 "View_PreViewTranslation" + OpMemberName %type_View 32 "PrePadding_View_1004" + OpMemberName %type_View 33 "View_PrevProjection" + OpMemberName %type_View 34 "View_PrevViewProj" + OpMemberName %type_View 35 "View_PrevViewRotationProj" + OpMemberName %type_View 36 "View_PrevViewToClip" + OpMemberName %type_View 37 "View_PrevClipToView" + OpMemberName %type_View 38 "View_PrevTranslatedWorldToClip" + OpMemberName %type_View 39 "View_PrevTranslatedWorldToView" + OpMemberName %type_View 40 "View_PrevViewToTranslatedWorld" + OpMemberName %type_View 41 "View_PrevTranslatedWorldToCameraView" + OpMemberName %type_View 42 "View_PrevCameraViewToTranslatedWorld" + OpMemberName %type_View 43 "View_PrevWorldCameraOrigin" + OpMemberName %type_View 44 "PrePadding_View_1660" + OpMemberName %type_View 45 "View_PrevWorldViewOrigin" + OpMemberName %type_View 46 "PrePadding_View_1676" + OpMemberName %type_View 47 "View_PrevPreViewTranslation" + OpMemberName %type_View 48 "PrePadding_View_1692" + OpMemberName %type_View 49 "View_PrevInvViewProj" + OpMemberName %type_View 50 "View_PrevScreenToTranslatedWorld" + OpMemberName %type_View 51 "View_ClipToPrevClip" + OpMemberName %type_View 52 "View_TemporalAAJitter" + OpMemberName %type_View 53 "View_GlobalClippingPlane" + OpMemberName %type_View 54 "View_FieldOfViewWideAngles" + OpMemberName %type_View 55 "View_PrevFieldOfViewWideAngles" + OpMemberName %type_View 56 "View_ViewRectMin" + OpMemberName %type_View 57 "View_ViewSizeAndInvSize" + OpMemberName %type_View 58 "View_BufferSizeAndInvSize" + OpMemberName %type_View 59 "View_BufferBilinearUVMinMax" + OpMemberName %type_View 60 "View_NumSceneColorMSAASamples" + OpMemberName %type_View 61 "View_PreExposure" + OpMemberName %type_View 62 "View_OneOverPreExposure" + OpMemberName %type_View 63 "PrePadding_View_2012" + OpMemberName %type_View 64 "View_DiffuseOverrideParameter" + OpMemberName %type_View 65 "View_SpecularOverrideParameter" + OpMemberName %type_View 66 "View_NormalOverrideParameter" + OpMemberName %type_View 67 "View_RoughnessOverrideParameter" + OpMemberName %type_View 68 "View_PrevFrameGameTime" + OpMemberName %type_View 69 "View_PrevFrameRealTime" + OpMemberName %type_View 70 "View_OutOfBoundsMask" + OpMemberName %type_View 71 "PrePadding_View_2084" + OpMemberName %type_View 72 "PrePadding_View_2088" + OpMemberName %type_View 73 "PrePadding_View_2092" + OpMemberName %type_View 74 "View_WorldCameraMovementSinceLastFrame" + OpMemberName %type_View 75 "View_CullingSign" + OpMemberName %type_View 76 "View_NearPlane" + OpMemberName %type_View 77 "View_AdaptiveTessellationFactor" + OpMemberName %type_View 78 "View_GameTime" + OpMemberName %type_View 79 "View_RealTime" + OpMemberName %type_View 80 "View_DeltaTime" + OpMemberName %type_View 81 "View_MaterialTextureMipBias" + OpMemberName %type_View 82 "View_MaterialTextureDerivativeMultiply" + OpMemberName %type_View 83 "View_Random" + OpMemberName %type_View 84 "View_FrameNumber" + OpMemberName %type_View 85 "View_StateFrameIndexMod8" + OpMemberName %type_View 86 "View_StateFrameIndex" + OpMemberName %type_View 87 "View_CameraCut" + OpMemberName %type_View 88 "View_UnlitViewmodeMask" + OpMemberName %type_View 89 "PrePadding_View_2164" + OpMemberName %type_View 90 "PrePadding_View_2168" + OpMemberName %type_View 91 "PrePadding_View_2172" + OpMemberName %type_View 92 "View_DirectionalLightColor" + OpMemberName %type_View 93 "View_DirectionalLightDirection" + OpMemberName %type_View 94 "PrePadding_View_2204" + OpMemberName %type_View 95 "View_TranslucencyLightingVolumeMin" + OpMemberName %type_View 96 "View_TranslucencyLightingVolumeInvSize" + OpMemberName %type_View 97 "View_TemporalAAParams" + OpMemberName %type_View 98 "View_CircleDOFParams" + OpMemberName %type_View 99 "View_DepthOfFieldSensorWidth" + OpMemberName %type_View 100 "View_DepthOfFieldFocalDistance" + OpMemberName %type_View 101 "View_DepthOfFieldScale" + OpMemberName %type_View 102 "View_DepthOfFieldFocalLength" + OpMemberName %type_View 103 "View_DepthOfFieldFocalRegion" + OpMemberName %type_View 104 "View_DepthOfFieldNearTransitionRegion" + OpMemberName %type_View 105 "View_DepthOfFieldFarTransitionRegion" + OpMemberName %type_View 106 "View_MotionBlurNormalizedToPixel" + OpMemberName %type_View 107 "View_bSubsurfacePostprocessEnabled" + OpMemberName %type_View 108 "View_GeneralPurposeTweak" + OpMemberName %type_View 109 "View_DemosaicVposOffset" + OpMemberName %type_View 110 "PrePadding_View_2348" + OpMemberName %type_View 111 "View_IndirectLightingColorScale" + OpMemberName %type_View 112 "View_HDR32bppEncodingMode" + OpMemberName %type_View 113 "View_AtmosphericFogSunDirection" + OpMemberName %type_View 114 "View_AtmosphericFogSunPower" + OpMemberName %type_View 115 "View_AtmosphericFogPower" + OpMemberName %type_View 116 "View_AtmosphericFogDensityScale" + OpMemberName %type_View 117 "View_AtmosphericFogDensityOffset" + OpMemberName %type_View 118 "View_AtmosphericFogGroundOffset" + OpMemberName %type_View 119 "View_AtmosphericFogDistanceScale" + OpMemberName %type_View 120 "View_AtmosphericFogAltitudeScale" + OpMemberName %type_View 121 "View_AtmosphericFogHeightScaleRayleigh" + OpMemberName %type_View 122 "View_AtmosphericFogStartDistance" + OpMemberName %type_View 123 "View_AtmosphericFogDistanceOffset" + OpMemberName %type_View 124 "View_AtmosphericFogSunDiscScale" + OpMemberName %type_View 125 "View_AtmosphericFogRenderMask" + OpMemberName %type_View 126 "View_AtmosphericFogInscatterAltitudeSampleNum" + OpMemberName %type_View 127 "View_AtmosphericFogSunColor" + OpMemberName %type_View 128 "View_NormalCurvatureToRoughnessScaleBias" + OpMemberName %type_View 129 "View_RenderingReflectionCaptureMask" + OpMemberName %type_View 130 "View_AmbientCubemapTint" + OpMemberName %type_View 131 "View_AmbientCubemapIntensity" + OpMemberName %type_View 132 "View_SkyLightParameters" + OpMemberName %type_View 133 "PrePadding_View_2488" + OpMemberName %type_View 134 "PrePadding_View_2492" + OpMemberName %type_View 135 "View_SkyLightColor" + OpMemberName %type_View 136 "View_SkyIrradianceEnvironmentMap" + OpMemberName %type_View 137 "View_MobilePreviewMode" + OpMemberName %type_View 138 "View_HMDEyePaddingOffset" + OpMemberName %type_View 139 "View_ReflectionCubemapMaxMip" + OpMemberName %type_View 140 "View_ShowDecalsMask" + OpMemberName %type_View 141 "View_DistanceFieldAOSpecularOcclusionMode" + OpMemberName %type_View 142 "View_IndirectCapsuleSelfShadowingIntensity" + OpMemberName %type_View 143 "PrePadding_View_2648" + OpMemberName %type_View 144 "PrePadding_View_2652" + OpMemberName %type_View 145 "View_ReflectionEnvironmentRoughnessMixingScaleBiasAndLargestWeight" + OpMemberName %type_View 146 "View_StereoPassIndex" + OpMemberName %type_View 147 "View_GlobalVolumeCenterAndExtent" + OpMemberName %type_View 148 "View_GlobalVolumeWorldToUVAddAndMul" + OpMemberName %type_View 149 "View_GlobalVolumeDimension" + OpMemberName %type_View 150 "View_GlobalVolumeTexelSize" + OpMemberName %type_View 151 "View_MaxGlobalDistance" + OpMemberName %type_View 152 "View_bCheckerboardSubsurfaceProfileRendering" + OpMemberName %type_View 153 "View_VolumetricFogInvGridSize" + OpMemberName %type_View 154 "PrePadding_View_2828" + OpMemberName %type_View 155 "View_VolumetricFogGridZParams" + OpMemberName %type_View 156 "PrePadding_View_2844" + OpMemberName %type_View 157 "View_VolumetricFogSVPosToVolumeUV" + OpMemberName %type_View 158 "View_VolumetricFogMaxDistance" + OpMemberName %type_View 159 "PrePadding_View_2860" + OpMemberName %type_View 160 "View_VolumetricLightmapWorldToUVScale" + OpMemberName %type_View 161 "PrePadding_View_2876" + OpMemberName %type_View 162 "View_VolumetricLightmapWorldToUVAdd" + OpMemberName %type_View 163 "PrePadding_View_2892" + OpMemberName %type_View 164 "View_VolumetricLightmapIndirectionTextureSize" + OpMemberName %type_View 165 "View_VolumetricLightmapBrickSize" + OpMemberName %type_View 166 "View_VolumetricLightmapBrickTexelSize" + OpMemberName %type_View 167 "View_StereoIPD" + OpMemberName %type_View 168 "View_IndirectLightingCacheShowFlag" + OpMemberName %type_View 169 "View_EyeToPixelSpreadAngle" + OpName %View "View" + OpName %type_MobileBasePass "type.MobileBasePass" + OpMemberName %type_MobileBasePass 0 "MobileBasePass_Fog_ExponentialFogParameters" + OpMemberName %type_MobileBasePass 1 "MobileBasePass_Fog_ExponentialFogParameters2" + OpMemberName %type_MobileBasePass 2 "MobileBasePass_Fog_ExponentialFogColorParameter" + OpMemberName %type_MobileBasePass 3 "MobileBasePass_Fog_ExponentialFogParameters3" + OpMemberName %type_MobileBasePass 4 "MobileBasePass_Fog_InscatteringLightDirection" + OpMemberName %type_MobileBasePass 5 "MobileBasePass_Fog_DirectionalInscatteringColor" + OpMemberName %type_MobileBasePass 6 "MobileBasePass_Fog_SinCosInscatteringColorCubemapRotation" + OpMemberName %type_MobileBasePass 7 "PrePadding_MobileBasePass_Fog_104" + OpMemberName %type_MobileBasePass 8 "PrePadding_MobileBasePass_Fog_108" + OpMemberName %type_MobileBasePass 9 "MobileBasePass_Fog_FogInscatteringTextureParameters" + OpMemberName %type_MobileBasePass 10 "MobileBasePass_Fog_ApplyVolumetricFog" + OpMemberName %type_MobileBasePass 11 "PrePadding_MobileBasePass_PlanarReflection_128" + OpMemberName %type_MobileBasePass 12 "PrePadding_MobileBasePass_PlanarReflection_132" + OpMemberName %type_MobileBasePass 13 "PrePadding_MobileBasePass_PlanarReflection_136" + OpMemberName %type_MobileBasePass 14 "PrePadding_MobileBasePass_PlanarReflection_140" + OpMemberName %type_MobileBasePass 15 "PrePadding_MobileBasePass_PlanarReflection_144" + OpMemberName %type_MobileBasePass 16 "PrePadding_MobileBasePass_PlanarReflection_148" + OpMemberName %type_MobileBasePass 17 "PrePadding_MobileBasePass_PlanarReflection_152" + OpMemberName %type_MobileBasePass 18 "PrePadding_MobileBasePass_PlanarReflection_156" + OpMemberName %type_MobileBasePass 19 "MobileBasePass_PlanarReflection_ReflectionPlane" + OpMemberName %type_MobileBasePass 20 "MobileBasePass_PlanarReflection_PlanarReflectionOrigin" + OpMemberName %type_MobileBasePass 21 "MobileBasePass_PlanarReflection_PlanarReflectionXAxis" + OpMemberName %type_MobileBasePass 22 "MobileBasePass_PlanarReflection_PlanarReflectionYAxis" + OpMemberName %type_MobileBasePass 23 "MobileBasePass_PlanarReflection_InverseTransposeMirrorMatrix" + OpMemberName %type_MobileBasePass 24 "MobileBasePass_PlanarReflection_PlanarReflectionParameters" + OpMemberName %type_MobileBasePass 25 "PrePadding_MobileBasePass_PlanarReflection_284" + OpMemberName %type_MobileBasePass 26 "MobileBasePass_PlanarReflection_PlanarReflectionParameters2" + OpMemberName %type_MobileBasePass 27 "PrePadding_MobileBasePass_PlanarReflection_296" + OpMemberName %type_MobileBasePass 28 "PrePadding_MobileBasePass_PlanarReflection_300" + OpMemberName %type_MobileBasePass 29 "MobileBasePass_PlanarReflection_ProjectionWithExtraFOV" + OpMemberName %type_MobileBasePass 30 "MobileBasePass_PlanarReflection_PlanarReflectionScreenScaleBias" + OpMemberName %type_MobileBasePass 31 "MobileBasePass_PlanarReflection_PlanarReflectionScreenBound" + OpMemberName %type_MobileBasePass 32 "MobileBasePass_PlanarReflection_bIsStereo" + OpName %MobileBasePass "MobileBasePass" + OpName %type_Primitive "type.Primitive" + OpMemberName %type_Primitive 0 "Primitive_LocalToWorld" + OpMemberName %type_Primitive 1 "Primitive_InvNonUniformScaleAndDeterminantSign" + OpMemberName %type_Primitive 2 "Primitive_ObjectWorldPositionAndRadius" + OpMemberName %type_Primitive 3 "Primitive_WorldToLocal" + OpMemberName %type_Primitive 4 "Primitive_PreviousLocalToWorld" + OpMemberName %type_Primitive 5 "Primitive_PreviousWorldToLocal" + OpMemberName %type_Primitive 6 "Primitive_ActorWorldPosition" + OpMemberName %type_Primitive 7 "Primitive_UseSingleSampleShadowFromStationaryLights" + OpMemberName %type_Primitive 8 "Primitive_ObjectBounds" + OpMemberName %type_Primitive 9 "Primitive_LpvBiasMultiplier" + OpMemberName %type_Primitive 10 "Primitive_DecalReceiverMask" + OpMemberName %type_Primitive 11 "Primitive_PerObjectGBufferData" + OpMemberName %type_Primitive 12 "Primitive_UseVolumetricLightmapShadowFromStationaryLights" + OpMemberName %type_Primitive 13 "Primitive_UseEditorDepthTest" + OpMemberName %type_Primitive 14 "Primitive_ObjectOrientation" + OpMemberName %type_Primitive 15 "Primitive_NonUniformScale" + OpMemberName %type_Primitive 16 "Primitive_LocalObjectBoundsMin" + OpMemberName %type_Primitive 17 "PrePadding_Primitive_380" + OpMemberName %type_Primitive 18 "Primitive_LocalObjectBoundsMax" + OpMemberName %type_Primitive 19 "Primitive_LightingChannelMask" + OpMemberName %type_Primitive 20 "Primitive_LightmapDataIndex" + OpMemberName %type_Primitive 21 "Primitive_SingleCaptureIndex" + OpName %Primitive "Primitive" + OpName %type_LandscapeParameters "type.LandscapeParameters" + OpMemberName %type_LandscapeParameters 0 "LandscapeParameters_HeightmapUVScaleBias" + OpMemberName %type_LandscapeParameters 1 "LandscapeParameters_WeightmapUVScaleBias" + OpMemberName %type_LandscapeParameters 2 "LandscapeParameters_LandscapeLightmapScaleBias" + OpMemberName %type_LandscapeParameters 3 "LandscapeParameters_SubsectionSizeVertsLayerUVPan" + OpMemberName %type_LandscapeParameters 4 "LandscapeParameters_SubsectionOffsetParams" + OpMemberName %type_LandscapeParameters 5 "LandscapeParameters_LightmapSubsectionOffsetParams" + OpMemberName %type_LandscapeParameters 6 "LandscapeParameters_LocalToWorldNoScaling" + OpName %LandscapeParameters "LandscapeParameters" + OpName %type__Globals "type.$Globals" + OpMemberName %type__Globals 0 "LodBias" + OpMemberName %type__Globals 1 "LodValues" + OpMemberName %type__Globals 2 "SectionLods" + OpMemberName %type__Globals 3 "NeighborSectionLod" + OpName %_Globals "$Globals" + OpName %in_var_ATTRIBUTE0 "in.var.ATTRIBUTE0" + OpName %in_var_ATTRIBUTE1 "in.var.ATTRIBUTE1" + OpName %out_var_TEXCOORD0 "out.var.TEXCOORD0" + OpName %out_var_TEXCOORD1 "out.var.TEXCOORD1" + OpName %out_var_TEXCOORD2 "out.var.TEXCOORD2" + OpName %out_var_TEXCOORD3 "out.var.TEXCOORD3" + OpName %out_var_TEXCOORD8 "out.var.TEXCOORD8" + OpName %Main "Main" + OpDecorateString %in_var_ATTRIBUTE0 UserSemantic "ATTRIBUTE0" + OpDecorateString %in_var_ATTRIBUTE1 UserSemantic "ATTRIBUTE1" + OpDecorateString %out_var_TEXCOORD0 UserSemantic "TEXCOORD0" + OpDecorateString %out_var_TEXCOORD1 UserSemantic "TEXCOORD1" + OpDecorateString %out_var_TEXCOORD2 UserSemantic "TEXCOORD2" + OpDecorateString %out_var_TEXCOORD3 UserSemantic "TEXCOORD3" + OpDecorateString %out_var_TEXCOORD8 UserSemantic "TEXCOORD8" + OpDecorate %gl_Position BuiltIn Position + OpDecorateString %gl_Position UserSemantic "SV_POSITION" + OpDecorate %in_var_ATTRIBUTE0 Location 0 + OpDecorate %in_var_ATTRIBUTE1 Location 1 + OpDecorate %out_var_TEXCOORD0 Location 0 + OpDecorate %out_var_TEXCOORD1 Location 1 + OpDecorate %out_var_TEXCOORD2 Location 2 + OpDecorate %out_var_TEXCOORD3 Location 3 + OpDecorate %out_var_TEXCOORD8 Location 4 + OpDecorate %View DescriptorSet 0 + OpDecorate %View Binding 0 + OpDecorate %MobileBasePass DescriptorSet 0 + OpDecorate %MobileBasePass Binding 1 + OpDecorate %Primitive DescriptorSet 0 + OpDecorate %Primitive Binding 2 + OpDecorate %LandscapeParameters DescriptorSet 0 + OpDecorate %LandscapeParameters Binding 3 + OpDecorate %_Globals DescriptorSet 0 + OpDecorate %_Globals Binding 4 + OpDecorate %_arr_v4float_uint_2_0 ArrayStride 16 + OpDecorate %_arr_v4float_uint_7 ArrayStride 16 + OpDecorate %_arr_v4float_uint_4 ArrayStride 16 + OpMemberDecorate %type_View 0 Offset 0 + OpMemberDecorate %type_View 0 MatrixStride 16 + OpMemberDecorate %type_View 0 ColMajor + OpMemberDecorate %type_View 1 Offset 64 + OpMemberDecorate %type_View 1 MatrixStride 16 + OpMemberDecorate %type_View 1 ColMajor + OpMemberDecorate %type_View 2 Offset 128 + OpMemberDecorate %type_View 2 MatrixStride 16 + OpMemberDecorate %type_View 2 ColMajor + OpMemberDecorate %type_View 3 Offset 192 + OpMemberDecorate %type_View 3 MatrixStride 16 + OpMemberDecorate %type_View 3 ColMajor + OpMemberDecorate %type_View 4 Offset 256 + OpMemberDecorate %type_View 4 MatrixStride 16 + OpMemberDecorate %type_View 4 ColMajor + OpMemberDecorate %type_View 5 Offset 320 + OpMemberDecorate %type_View 5 MatrixStride 16 + OpMemberDecorate %type_View 5 ColMajor + OpMemberDecorate %type_View 6 Offset 384 + OpMemberDecorate %type_View 6 MatrixStride 16 + OpMemberDecorate %type_View 6 ColMajor + OpMemberDecorate %type_View 7 Offset 448 + OpMemberDecorate %type_View 7 MatrixStride 16 + OpMemberDecorate %type_View 7 ColMajor + OpMemberDecorate %type_View 8 Offset 512 + OpMemberDecorate %type_View 8 MatrixStride 16 + OpMemberDecorate %type_View 8 ColMajor + OpMemberDecorate %type_View 9 Offset 576 + OpMemberDecorate %type_View 9 MatrixStride 16 + OpMemberDecorate %type_View 9 ColMajor + OpMemberDecorate %type_View 10 Offset 640 + OpMemberDecorate %type_View 10 MatrixStride 16 + OpMemberDecorate %type_View 10 ColMajor + OpMemberDecorate %type_View 11 Offset 704 + OpMemberDecorate %type_View 11 MatrixStride 16 + OpMemberDecorate %type_View 11 ColMajor + OpMemberDecorate %type_View 12 Offset 768 + OpMemberDecorate %type_View 12 MatrixStride 16 + OpMemberDecorate %type_View 12 ColMajor + OpMemberDecorate %type_View 13 Offset 832 + OpMemberDecorate %type_View 14 Offset 844 + OpMemberDecorate %type_View 15 Offset 848 + OpMemberDecorate %type_View 16 Offset 860 + OpMemberDecorate %type_View 17 Offset 864 + OpMemberDecorate %type_View 18 Offset 876 + OpMemberDecorate %type_View 19 Offset 880 + OpMemberDecorate %type_View 20 Offset 892 + OpMemberDecorate %type_View 21 Offset 896 + OpMemberDecorate %type_View 22 Offset 908 + OpMemberDecorate %type_View 23 Offset 912 + OpMemberDecorate %type_View 24 Offset 928 + OpMemberDecorate %type_View 25 Offset 944 + OpMemberDecorate %type_View 26 Offset 956 + OpMemberDecorate %type_View 27 Offset 960 + OpMemberDecorate %type_View 28 Offset 972 + OpMemberDecorate %type_View 29 Offset 976 + OpMemberDecorate %type_View 30 Offset 988 + OpMemberDecorate %type_View 31 Offset 992 + OpMemberDecorate %type_View 32 Offset 1004 + OpMemberDecorate %type_View 33 Offset 1008 + OpMemberDecorate %type_View 33 MatrixStride 16 + OpMemberDecorate %type_View 33 ColMajor + OpMemberDecorate %type_View 34 Offset 1072 + OpMemberDecorate %type_View 34 MatrixStride 16 + OpMemberDecorate %type_View 34 ColMajor + OpMemberDecorate %type_View 35 Offset 1136 + OpMemberDecorate %type_View 35 MatrixStride 16 + OpMemberDecorate %type_View 35 ColMajor + OpMemberDecorate %type_View 36 Offset 1200 + OpMemberDecorate %type_View 36 MatrixStride 16 + OpMemberDecorate %type_View 36 ColMajor + OpMemberDecorate %type_View 37 Offset 1264 + OpMemberDecorate %type_View 37 MatrixStride 16 + OpMemberDecorate %type_View 37 ColMajor + OpMemberDecorate %type_View 38 Offset 1328 + OpMemberDecorate %type_View 38 MatrixStride 16 + OpMemberDecorate %type_View 38 ColMajor + OpMemberDecorate %type_View 39 Offset 1392 + OpMemberDecorate %type_View 39 MatrixStride 16 + OpMemberDecorate %type_View 39 ColMajor + OpMemberDecorate %type_View 40 Offset 1456 + OpMemberDecorate %type_View 40 MatrixStride 16 + OpMemberDecorate %type_View 40 ColMajor + OpMemberDecorate %type_View 41 Offset 1520 + OpMemberDecorate %type_View 41 MatrixStride 16 + OpMemberDecorate %type_View 41 ColMajor + OpMemberDecorate %type_View 42 Offset 1584 + OpMemberDecorate %type_View 42 MatrixStride 16 + OpMemberDecorate %type_View 42 ColMajor + OpMemberDecorate %type_View 43 Offset 1648 + OpMemberDecorate %type_View 44 Offset 1660 + OpMemberDecorate %type_View 45 Offset 1664 + OpMemberDecorate %type_View 46 Offset 1676 + OpMemberDecorate %type_View 47 Offset 1680 + OpMemberDecorate %type_View 48 Offset 1692 + OpMemberDecorate %type_View 49 Offset 1696 + OpMemberDecorate %type_View 49 MatrixStride 16 + OpMemberDecorate %type_View 49 ColMajor + OpMemberDecorate %type_View 50 Offset 1760 + OpMemberDecorate %type_View 50 MatrixStride 16 + OpMemberDecorate %type_View 50 ColMajor + OpMemberDecorate %type_View 51 Offset 1824 + OpMemberDecorate %type_View 51 MatrixStride 16 + OpMemberDecorate %type_View 51 ColMajor + OpMemberDecorate %type_View 52 Offset 1888 + OpMemberDecorate %type_View 53 Offset 1904 + OpMemberDecorate %type_View 54 Offset 1920 + OpMemberDecorate %type_View 55 Offset 1928 + OpMemberDecorate %type_View 56 Offset 1936 + OpMemberDecorate %type_View 57 Offset 1952 + OpMemberDecorate %type_View 58 Offset 1968 + OpMemberDecorate %type_View 59 Offset 1984 + OpMemberDecorate %type_View 60 Offset 2000 + OpMemberDecorate %type_View 61 Offset 2004 + OpMemberDecorate %type_View 62 Offset 2008 + OpMemberDecorate %type_View 63 Offset 2012 + OpMemberDecorate %type_View 64 Offset 2016 + OpMemberDecorate %type_View 65 Offset 2032 + OpMemberDecorate %type_View 66 Offset 2048 + OpMemberDecorate %type_View 67 Offset 2064 + OpMemberDecorate %type_View 68 Offset 2072 + OpMemberDecorate %type_View 69 Offset 2076 + OpMemberDecorate %type_View 70 Offset 2080 + OpMemberDecorate %type_View 71 Offset 2084 + OpMemberDecorate %type_View 72 Offset 2088 + OpMemberDecorate %type_View 73 Offset 2092 + OpMemberDecorate %type_View 74 Offset 2096 + OpMemberDecorate %type_View 75 Offset 2108 + OpMemberDecorate %type_View 76 Offset 2112 + OpMemberDecorate %type_View 77 Offset 2116 + OpMemberDecorate %type_View 78 Offset 2120 + OpMemberDecorate %type_View 79 Offset 2124 + OpMemberDecorate %type_View 80 Offset 2128 + OpMemberDecorate %type_View 81 Offset 2132 + OpMemberDecorate %type_View 82 Offset 2136 + OpMemberDecorate %type_View 83 Offset 2140 + OpMemberDecorate %type_View 84 Offset 2144 + OpMemberDecorate %type_View 85 Offset 2148 + OpMemberDecorate %type_View 86 Offset 2152 + OpMemberDecorate %type_View 87 Offset 2156 + OpMemberDecorate %type_View 88 Offset 2160 + OpMemberDecorate %type_View 89 Offset 2164 + OpMemberDecorate %type_View 90 Offset 2168 + OpMemberDecorate %type_View 91 Offset 2172 + OpMemberDecorate %type_View 92 Offset 2176 + OpMemberDecorate %type_View 93 Offset 2192 + OpMemberDecorate %type_View 94 Offset 2204 + OpMemberDecorate %type_View 95 Offset 2208 + OpMemberDecorate %type_View 96 Offset 2240 + OpMemberDecorate %type_View 97 Offset 2272 + OpMemberDecorate %type_View 98 Offset 2288 + OpMemberDecorate %type_View 99 Offset 2304 + OpMemberDecorate %type_View 100 Offset 2308 + OpMemberDecorate %type_View 101 Offset 2312 + OpMemberDecorate %type_View 102 Offset 2316 + OpMemberDecorate %type_View 103 Offset 2320 + OpMemberDecorate %type_View 104 Offset 2324 + OpMemberDecorate %type_View 105 Offset 2328 + OpMemberDecorate %type_View 106 Offset 2332 + OpMemberDecorate %type_View 107 Offset 2336 + OpMemberDecorate %type_View 108 Offset 2340 + OpMemberDecorate %type_View 109 Offset 2344 + OpMemberDecorate %type_View 110 Offset 2348 + OpMemberDecorate %type_View 111 Offset 2352 + OpMemberDecorate %type_View 112 Offset 2364 + OpMemberDecorate %type_View 113 Offset 2368 + OpMemberDecorate %type_View 114 Offset 2380 + OpMemberDecorate %type_View 115 Offset 2384 + OpMemberDecorate %type_View 116 Offset 2388 + OpMemberDecorate %type_View 117 Offset 2392 + OpMemberDecorate %type_View 118 Offset 2396 + OpMemberDecorate %type_View 119 Offset 2400 + OpMemberDecorate %type_View 120 Offset 2404 + OpMemberDecorate %type_View 121 Offset 2408 + OpMemberDecorate %type_View 122 Offset 2412 + OpMemberDecorate %type_View 123 Offset 2416 + OpMemberDecorate %type_View 124 Offset 2420 + OpMemberDecorate %type_View 125 Offset 2424 + OpMemberDecorate %type_View 126 Offset 2428 + OpMemberDecorate %type_View 127 Offset 2432 + OpMemberDecorate %type_View 128 Offset 2448 + OpMemberDecorate %type_View 129 Offset 2460 + OpMemberDecorate %type_View 130 Offset 2464 + OpMemberDecorate %type_View 131 Offset 2480 + OpMemberDecorate %type_View 132 Offset 2484 + OpMemberDecorate %type_View 133 Offset 2488 + OpMemberDecorate %type_View 134 Offset 2492 + OpMemberDecorate %type_View 135 Offset 2496 + OpMemberDecorate %type_View 136 Offset 2512 + OpMemberDecorate %type_View 137 Offset 2624 + OpMemberDecorate %type_View 138 Offset 2628 + OpMemberDecorate %type_View 139 Offset 2632 + OpMemberDecorate %type_View 140 Offset 2636 + OpMemberDecorate %type_View 141 Offset 2640 + OpMemberDecorate %type_View 142 Offset 2644 + OpMemberDecorate %type_View 143 Offset 2648 + OpMemberDecorate %type_View 144 Offset 2652 + OpMemberDecorate %type_View 145 Offset 2656 + OpMemberDecorate %type_View 146 Offset 2668 + OpMemberDecorate %type_View 147 Offset 2672 + OpMemberDecorate %type_View 148 Offset 2736 + OpMemberDecorate %type_View 149 Offset 2800 + OpMemberDecorate %type_View 150 Offset 2804 + OpMemberDecorate %type_View 151 Offset 2808 + OpMemberDecorate %type_View 152 Offset 2812 + OpMemberDecorate %type_View 153 Offset 2816 + OpMemberDecorate %type_View 154 Offset 2828 + OpMemberDecorate %type_View 155 Offset 2832 + OpMemberDecorate %type_View 156 Offset 2844 + OpMemberDecorate %type_View 157 Offset 2848 + OpMemberDecorate %type_View 158 Offset 2856 + OpMemberDecorate %type_View 159 Offset 2860 + OpMemberDecorate %type_View 160 Offset 2864 + OpMemberDecorate %type_View 161 Offset 2876 + OpMemberDecorate %type_View 162 Offset 2880 + OpMemberDecorate %type_View 163 Offset 2892 + OpMemberDecorate %type_View 164 Offset 2896 + OpMemberDecorate %type_View 165 Offset 2908 + OpMemberDecorate %type_View 166 Offset 2912 + OpMemberDecorate %type_View 167 Offset 2924 + OpMemberDecorate %type_View 168 Offset 2928 + OpMemberDecorate %type_View 169 Offset 2932 + OpDecorate %type_View Block + OpDecorate %_arr_mat4v4float_uint_2 ArrayStride 64 + OpMemberDecorate %type_MobileBasePass 0 Offset 0 + OpMemberDecorate %type_MobileBasePass 1 Offset 16 + OpMemberDecorate %type_MobileBasePass 2 Offset 32 + OpMemberDecorate %type_MobileBasePass 3 Offset 48 + OpMemberDecorate %type_MobileBasePass 4 Offset 64 + OpMemberDecorate %type_MobileBasePass 5 Offset 80 + OpMemberDecorate %type_MobileBasePass 6 Offset 96 + OpMemberDecorate %type_MobileBasePass 7 Offset 104 + OpMemberDecorate %type_MobileBasePass 8 Offset 108 + OpMemberDecorate %type_MobileBasePass 9 Offset 112 + OpMemberDecorate %type_MobileBasePass 10 Offset 124 + OpMemberDecorate %type_MobileBasePass 11 Offset 128 + OpMemberDecorate %type_MobileBasePass 12 Offset 132 + OpMemberDecorate %type_MobileBasePass 13 Offset 136 + OpMemberDecorate %type_MobileBasePass 14 Offset 140 + OpMemberDecorate %type_MobileBasePass 15 Offset 144 + OpMemberDecorate %type_MobileBasePass 16 Offset 148 + OpMemberDecorate %type_MobileBasePass 17 Offset 152 + OpMemberDecorate %type_MobileBasePass 18 Offset 156 + OpMemberDecorate %type_MobileBasePass 19 Offset 160 + OpMemberDecorate %type_MobileBasePass 20 Offset 176 + OpMemberDecorate %type_MobileBasePass 21 Offset 192 + OpMemberDecorate %type_MobileBasePass 22 Offset 208 + OpMemberDecorate %type_MobileBasePass 23 Offset 224 + OpMemberDecorate %type_MobileBasePass 23 MatrixStride 16 + OpMemberDecorate %type_MobileBasePass 23 ColMajor + OpMemberDecorate %type_MobileBasePass 24 Offset 272 + OpMemberDecorate %type_MobileBasePass 25 Offset 284 + OpMemberDecorate %type_MobileBasePass 26 Offset 288 + OpMemberDecorate %type_MobileBasePass 27 Offset 296 + OpMemberDecorate %type_MobileBasePass 28 Offset 300 + OpMemberDecorate %type_MobileBasePass 29 Offset 304 + OpMemberDecorate %type_MobileBasePass 29 MatrixStride 16 + OpMemberDecorate %type_MobileBasePass 29 ColMajor + OpMemberDecorate %type_MobileBasePass 30 Offset 432 + OpMemberDecorate %type_MobileBasePass 31 Offset 464 + OpMemberDecorate %type_MobileBasePass 32 Offset 472 + OpDecorate %type_MobileBasePass Block + OpMemberDecorate %type_Primitive 0 Offset 0 + OpMemberDecorate %type_Primitive 0 MatrixStride 16 + OpMemberDecorate %type_Primitive 0 ColMajor + OpMemberDecorate %type_Primitive 1 Offset 64 + OpMemberDecorate %type_Primitive 2 Offset 80 + OpMemberDecorate %type_Primitive 3 Offset 96 + OpMemberDecorate %type_Primitive 3 MatrixStride 16 + OpMemberDecorate %type_Primitive 3 ColMajor + OpMemberDecorate %type_Primitive 4 Offset 160 + OpMemberDecorate %type_Primitive 4 MatrixStride 16 + OpMemberDecorate %type_Primitive 4 ColMajor + OpMemberDecorate %type_Primitive 5 Offset 224 + OpMemberDecorate %type_Primitive 5 MatrixStride 16 + OpMemberDecorate %type_Primitive 5 ColMajor + OpMemberDecorate %type_Primitive 6 Offset 288 + OpMemberDecorate %type_Primitive 7 Offset 300 + OpMemberDecorate %type_Primitive 8 Offset 304 + OpMemberDecorate %type_Primitive 9 Offset 316 + OpMemberDecorate %type_Primitive 10 Offset 320 + OpMemberDecorate %type_Primitive 11 Offset 324 + OpMemberDecorate %type_Primitive 12 Offset 328 + OpMemberDecorate %type_Primitive 13 Offset 332 + OpMemberDecorate %type_Primitive 14 Offset 336 + OpMemberDecorate %type_Primitive 15 Offset 352 + OpMemberDecorate %type_Primitive 16 Offset 368 + OpMemberDecorate %type_Primitive 17 Offset 380 + OpMemberDecorate %type_Primitive 18 Offset 384 + OpMemberDecorate %type_Primitive 19 Offset 396 + OpMemberDecorate %type_Primitive 20 Offset 400 + OpMemberDecorate %type_Primitive 21 Offset 404 + OpDecorate %type_Primitive Block + OpMemberDecorate %type_LandscapeParameters 0 Offset 0 + OpMemberDecorate %type_LandscapeParameters 1 Offset 16 + OpMemberDecorate %type_LandscapeParameters 2 Offset 32 + OpMemberDecorate %type_LandscapeParameters 3 Offset 48 + OpMemberDecorate %type_LandscapeParameters 4 Offset 64 + OpMemberDecorate %type_LandscapeParameters 5 Offset 80 + OpMemberDecorate %type_LandscapeParameters 6 Offset 96 + OpMemberDecorate %type_LandscapeParameters 6 MatrixStride 16 + OpMemberDecorate %type_LandscapeParameters 6 ColMajor + OpDecorate %type_LandscapeParameters Block + OpMemberDecorate %type__Globals 0 Offset 0 + OpMemberDecorate %type__Globals 1 Offset 16 + OpMemberDecorate %type__Globals 2 Offset 32 + OpMemberDecorate %type__Globals 3 Offset 48 + OpDecorate %type__Globals Block + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 +%mat4v4float = OpTypeMatrix %v4float 4 + %v3float = OpTypeVector %float 3 + %v2float = OpTypeVector %float 2 + %int = OpTypeInt 32 1 + %uint = OpTypeInt 32 0 + %uint_2 = OpConstant %uint 2 +%_arr_v4float_uint_2 = OpTypeArray %v4float %uint_2 + %uint_7 = OpConstant %uint 7 + %uint_4 = OpConstant %uint 4 +%float_0_00999999978 = OpConstant %float 0.00999999978 + %int_0 = OpConstant %int 0 + %int_1 = OpConstant %int 1 + %float_0 = OpConstant %float 0 + %40 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0 + %int_2 = OpConstant %int 2 + %int_3 = OpConstant %int 3 + %float_255 = OpConstant %float 255 + %44 = OpConstantComposite %v4float %float_255 %float_255 %float_255 %float_255 + %float_0_5 = OpConstant %float 0.5 + %46 = OpConstantComposite %v2float %float_0_5 %float_0_5 + %float_2 = OpConstant %float 2 + %48 = OpConstantComposite %v2float %float_2 %float_2 + %float_1 = OpConstant %float 1 + %uint_0 = OpConstant %uint 0 + %uint_1 = OpConstant %uint 1 + %float_3 = OpConstant %float 3 + %float_0_25 = OpConstant %float 0.25 + %uint_3 = OpConstant %uint 3 + %float_4 = OpConstant %float 4 +%float_0_125 = OpConstant %float 0.125 + %float_5 = OpConstant %float 5 +%float_0_0625 = OpConstant %float 0.0625 +%float_0_03125 = OpConstant %float 0.03125 + %60 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1 + %int_5 = OpConstant %int 5 + %int_4 = OpConstant %int 4 + %63 = OpConstantComposite %v3float %float_0 %float_0 %float_0 + %int_25 = OpConstant %int 25 + %int_27 = OpConstant %int 27 + %int_31 = OpConstant %int 31 + %67 = OpConstantComposite %v4float %float_2 %float_2 %float_2 %float_2 +%float_32768 = OpConstant %float 32768 +%_arr_v4float_uint_2_0 = OpTypeArray %v4float %uint_2 +%_arr_v4float_uint_7 = OpTypeArray %v4float %uint_7 +%_arr_v4float_uint_4 = OpTypeArray %v4float %uint_4 + %type_View = OpTypeStruct %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %v3float %float %v3float %float %v3float %float %v3float %float %v3float %float %v4float %v4float %v3float %float %v3float %float %v3float %float %v3float %float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %v3float %float %v3float %float %v3float %float %mat4v4float %mat4v4float %mat4v4float %v4float %v4float %v2float %v2float %v4float %v4float %v4float %v4float %int %float %float %float %v4float %v4float %v4float %v2float %float %float %float %float %float %float %v3float %float %float %float %float %float %float %float %float %uint %uint %uint %uint %float %float %float %float %float %v4float %v3float %float %_arr_v4float_uint_2_0 %_arr_v4float_uint_2_0 %v4float %v4float %float %float %float %float %float %float %float %float %float %float %float %float %v3float %float %v3float %float %float %float %float %float %float %float %float %float %float %float %uint %uint %v4float %v3float %float %v4float %float %float %float %float %v4float %_arr_v4float_uint_7 %float %float %float %float %uint %float %float %float %v3float %int %_arr_v4float_uint_4 %_arr_v4float_uint_4 %float %float %float %float %v3float %float %v3float %float %v2float %float %float %v3float %float %v3float %float %v3float %float %v3float %float %float %float +%_ptr_Uniform_type_View = OpTypePointer Uniform %type_View +%mat3v4float = OpTypeMatrix %v4float 3 +%_arr_mat4v4float_uint_2 = OpTypeArray %mat4v4float %uint_2 +%type_MobileBasePass = OpTypeStruct %v4float %v4float %v4float %v4float %v4float %v4float %v2float %float %float %v3float %float %float %float %float %float %float %float %float %float %v4float %v4float %v4float %v4float %mat3v4float %v3float %float %v2float %float %float %_arr_mat4v4float_uint_2 %_arr_v4float_uint_2_0 %v2float %uint +%_ptr_Uniform_type_MobileBasePass = OpTypePointer Uniform %type_MobileBasePass +%type_Primitive = OpTypeStruct %mat4v4float %v4float %v4float %mat4v4float %mat4v4float %mat4v4float %v3float %float %v3float %float %float %float %float %float %v4float %v4float %v3float %float %v3float %uint %uint %int +%_ptr_Uniform_type_Primitive = OpTypePointer Uniform %type_Primitive +%type_LandscapeParameters = OpTypeStruct %v4float %v4float %v4float %v4float %v4float %v4float %mat4v4float +%_ptr_Uniform_type_LandscapeParameters = OpTypePointer Uniform %type_LandscapeParameters +%type__Globals = OpTypeStruct %v4float %v4float %v4float %_arr_v4float_uint_4 +%_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals +%_ptr_Input_v4float = OpTypePointer Input %v4float +%_ptr_Input__arr_v4float_uint_2 = OpTypePointer Input %_arr_v4float_uint_2 +%_ptr_Output_v2float = OpTypePointer Output %v2float +%_ptr_Output_v4float = OpTypePointer Output %v4float + %void = OpTypeVoid + %80 = OpTypeFunction %void +%_arr_v4float_uint_1 = OpTypeArray %v4float %uint_1 +%_ptr_Function__arr_v4float_uint_1 = OpTypePointer Function %_arr_v4float_uint_1 +%_ptr_Function_v4float = OpTypePointer Function %v4float + %bool = OpTypeBool +%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float +%_ptr_Uniform_float = OpTypePointer Uniform %float + %v3bool = OpTypeVector %bool 3 +%_ptr_Uniform_mat4v4float = OpTypePointer Uniform %mat4v4float +%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float + %View = OpVariable %_ptr_Uniform_type_View Uniform +%MobileBasePass = OpVariable %_ptr_Uniform_type_MobileBasePass Uniform + %Primitive = OpVariable %_ptr_Uniform_type_Primitive Uniform +%LandscapeParameters = OpVariable %_ptr_Uniform_type_LandscapeParameters Uniform + %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform +%in_var_ATTRIBUTE0 = OpVariable %_ptr_Input_v4float Input +%in_var_ATTRIBUTE1 = OpVariable %_ptr_Input__arr_v4float_uint_2 Input +%out_var_TEXCOORD0 = OpVariable %_ptr_Output_v2float Output +%out_var_TEXCOORD1 = OpVariable %_ptr_Output_v2float Output +%out_var_TEXCOORD2 = OpVariable %_ptr_Output_v4float Output +%out_var_TEXCOORD3 = OpVariable %_ptr_Output_v4float Output +%out_var_TEXCOORD8 = OpVariable %_ptr_Output_v4float Output +%gl_Position = OpVariable %_ptr_Output_v4float Output +%float_0_0078125 = OpConstant %float 0.0078125 + %float_n127 = OpConstant %float -127 + %92 = OpConstantNull %v4float +%float_0_00392156886 = OpConstant %float 0.00392156886 + %94 = OpConstantComposite %v2float %float_0_00392156886 %float_0_00392156886 +%float_65280 = OpConstant %float 65280 + %Main = OpFunction %void None %80 + %96 = OpLabel + %97 = OpVariable %_ptr_Function__arr_v4float_uint_1 Function + %98 = OpLoad %v4float %in_var_ATTRIBUTE0 + %99 = OpLoad %_arr_v4float_uint_2 %in_var_ATTRIBUTE1 + %100 = OpAccessChain %_ptr_Uniform_mat4v4float %View %int_0 + %101 = OpLoad %mat4v4float %100 + %102 = OpAccessChain %_ptr_Uniform_v3float %View %int_27 + %103 = OpLoad %v3float %102 + %104 = OpAccessChain %_ptr_Uniform_v3float %View %int_31 + %105 = OpLoad %v3float %104 + OpBranch %106 + %106 = OpLabel + %107 = OpPhi %int %int_0 %96 %108 %109 + %110 = OpSLessThan %bool %107 %int_1 + OpLoopMerge %111 %109 Unroll + OpBranchConditional %110 %109 %111 + %109 = OpLabel + %112 = OpAccessChain %_ptr_Function_v4float %97 %107 + OpStore %112 %40 + %108 = OpIAdd %int %107 %int_1 + OpBranch %106 + %111 = OpLabel + %113 = OpCompositeExtract %v4float %99 0 + %114 = OpCompositeExtract %v4float %99 1 + %115 = OpFMul %v4float %98 %44 + %116 = OpVectorShuffle %v2float %115 %115 2 3 + %117 = OpFMul %v2float %116 %46 + %118 = OpExtInst %v2float %1 Fract %117 + %119 = OpFMul %v2float %118 %48 + %120 = OpFSub %v2float %116 %119 + %121 = OpFMul %v2float %120 %94 + %122 = OpVectorShuffle %v2float %115 %92 0 1 + %123 = OpAccessChain %_ptr_Uniform_float %_Globals %int_1 %int_3 + %124 = OpLoad %float %123 + %125 = OpCompositeConstruct %v2float %124 %124 + %126 = OpFMul %v2float %122 %125 + %127 = OpCompositeExtract %float %126 1 + %128 = OpCompositeExtract %float %126 0 + %129 = OpFSub %float %float_1 %128 + %130 = OpFSub %float %float_1 %127 + %131 = OpCompositeConstruct %v4float %127 %128 %129 %130 + %132 = OpFMul %v4float %131 %67 + %133 = OpCompositeExtract %float %119 1 + %134 = OpFOrdGreaterThan %bool %133 %float_0_5 + OpSelectionMerge %135 None + OpBranchConditional %134 %136 %137 + %136 = OpLabel + %138 = OpCompositeExtract %float %119 0 + %139 = OpFOrdGreaterThan %bool %138 %float_0_5 + OpSelectionMerge %140 None + OpBranchConditional %139 %141 %142 + %141 = OpLabel + %143 = OpAccessChain %_ptr_Uniform_float %_Globals %int_2 %int_3 + %144 = OpLoad %float %143 + %145 = OpCompositeConstruct %v4float %144 %144 %144 %144 + %146 = OpFMul %v4float %132 %145 + %147 = OpFSub %v4float %60 %132 + %148 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_3 %int_3 + %149 = OpLoad %v4float %148 + %150 = OpFMul %v4float %147 %149 + %151 = OpFAdd %v4float %146 %150 + OpBranch %140 + %142 = OpLabel + %152 = OpAccessChain %_ptr_Uniform_float %_Globals %int_2 %int_2 + %153 = OpLoad %float %152 + %154 = OpCompositeConstruct %v4float %153 %153 %153 %153 + %155 = OpFMul %v4float %132 %154 + %156 = OpFSub %v4float %60 %132 + %157 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_3 %int_2 + %158 = OpLoad %v4float %157 + %159 = OpFMul %v4float %156 %158 + %160 = OpFAdd %v4float %155 %159 + OpBranch %140 + %140 = OpLabel + %161 = OpPhi %v4float %151 %141 %160 %142 + OpBranch %135 + %137 = OpLabel + %162 = OpCompositeExtract %float %119 0 + %163 = OpFOrdGreaterThan %bool %162 %float_0_5 + OpSelectionMerge %164 None + OpBranchConditional %163 %165 %166 + %165 = OpLabel + %167 = OpAccessChain %_ptr_Uniform_float %_Globals %int_2 %int_1 + %168 = OpLoad %float %167 + %169 = OpCompositeConstruct %v4float %168 %168 %168 %168 + %170 = OpFMul %v4float %132 %169 + %171 = OpFSub %v4float %60 %132 + %172 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_3 %int_1 + %173 = OpLoad %v4float %172 + %174 = OpFMul %v4float %171 %173 + %175 = OpFAdd %v4float %170 %174 + OpBranch %164 + %166 = OpLabel + %176 = OpAccessChain %_ptr_Uniform_float %_Globals %int_2 %int_0 + %177 = OpLoad %float %176 + %178 = OpCompositeConstruct %v4float %177 %177 %177 %177 + %179 = OpFMul %v4float %132 %178 + %180 = OpFSub %v4float %60 %132 + %181 = OpAccessChain %_ptr_Uniform_v4float %_Globals %int_3 %int_0 + %182 = OpLoad %v4float %181 + %183 = OpFMul %v4float %180 %182 + %184 = OpFAdd %v4float %179 %183 + OpBranch %164 + %164 = OpLabel + %185 = OpPhi %v4float %175 %165 %184 %166 + OpBranch %135 + %135 = OpLabel + %186 = OpPhi %v4float %161 %140 %185 %164 + %187 = OpFAdd %float %128 %127 + %188 = OpFOrdGreaterThan %bool %187 %float_1 + OpSelectionMerge %189 None + OpBranchConditional %188 %190 %191 + %190 = OpLabel + %192 = OpFOrdLessThan %bool %128 %127 + OpSelectionMerge %193 None + OpBranchConditional %192 %194 %195 + %194 = OpLabel + %196 = OpCompositeExtract %float %186 3 + OpBranch %193 + %195 = OpLabel + %197 = OpCompositeExtract %float %186 2 + OpBranch %193 + %193 = OpLabel + %198 = OpPhi %float %196 %194 %197 %195 + OpBranch %189 + %191 = OpLabel + %199 = OpFOrdLessThan %bool %128 %127 + OpSelectionMerge %200 None + OpBranchConditional %199 %201 %202 + %201 = OpLabel + %203 = OpCompositeExtract %float %186 1 + OpBranch %200 + %202 = OpLabel + %204 = OpCompositeExtract %float %186 0 + OpBranch %200 + %200 = OpLabel + %205 = OpPhi %float %203 %201 %204 %202 + OpBranch %189 + %189 = OpLabel + %206 = OpPhi %float %198 %193 %205 %200 + %207 = OpExtInst %float %1 Floor %206 + %208 = OpFSub %float %206 %207 + %209 = OpFOrdLessThan %bool %207 %float_1 + %210 = OpCompositeExtract %float %114 0 + %211 = OpCompositeExtract %float %114 1 + %212 = OpCompositeConstruct %v3float %float_1 %210 %211 + %213 = OpFOrdLessThan %bool %207 %float_2 + %214 = OpCompositeExtract %float %114 2 + %215 = OpCompositeConstruct %v3float %float_0_5 %211 %214 + %216 = OpFOrdLessThan %bool %207 %float_3 + %217 = OpCompositeExtract %float %114 3 + %218 = OpCompositeConstruct %v3float %float_0_25 %214 %217 + %219 = OpFOrdLessThan %bool %207 %float_4 + %220 = OpCompositeExtract %float %121 0 + %221 = OpCompositeConstruct %v3float %float_0_125 %217 %220 + %222 = OpFOrdLessThan %bool %207 %float_5 + %223 = OpCompositeExtract %float %121 1 + %224 = OpCompositeConstruct %v3float %float_0_0625 %220 %223 + %225 = OpCompositeConstruct %v3float %float_0_03125 %223 %223 + %226 = OpCompositeConstruct %v3bool %222 %222 %222 + %227 = OpSelect %v3float %226 %224 %225 + %228 = OpCompositeConstruct %v3bool %219 %219 %219 + %229 = OpSelect %v3float %228 %221 %227 + %230 = OpCompositeConstruct %v3bool %216 %216 %216 + %231 = OpSelect %v3float %230 %218 %229 + %232 = OpCompositeConstruct %v3bool %213 %213 %213 + %233 = OpSelect %v3float %232 %215 %231 + %234 = OpCompositeConstruct %v3bool %209 %209 %209 + %235 = OpSelect %v3float %234 %212 %233 + %236 = OpCompositeExtract %float %235 0 + %237 = OpCompositeExtract %float %235 1 + %238 = OpCompositeExtract %float %235 2 + %239 = OpCompositeExtract %float %113 0 + %240 = OpFMul %float %239 %float_65280 + %241 = OpCompositeExtract %float %113 1 + %242 = OpFMul %float %241 %float_255 + %243 = OpFAdd %float %240 %242 + %244 = OpFSub %float %243 %float_32768 + %245 = OpFMul %float %244 %float_0_0078125 + %246 = OpCompositeExtract %float %113 2 + %247 = OpFMul %float %246 %float_65280 + %248 = OpCompositeExtract %float %113 3 + %249 = OpFMul %float %248 %float_255 + %250 = OpFAdd %float %247 %249 + %251 = OpFSub %float %250 %float_32768 + %252 = OpFMul %float %251 %float_0_0078125 + %253 = OpExtInst %float %1 FMix %245 %252 %237 + %254 = OpExtInst %float %1 FMix %245 %252 %238 + %255 = OpCompositeConstruct %v2float %236 %236 + %256 = OpFMul %v2float %122 %255 + %257 = OpExtInst %v2float %1 Floor %256 + %258 = OpAccessChain %_ptr_Uniform_v4float %LandscapeParameters %int_3 + %259 = OpAccessChain %_ptr_Uniform_float %LandscapeParameters %int_3 %int_0 + %260 = OpLoad %float %259 + %261 = OpFMul %float %260 %236 + %262 = OpFSub %float %261 %float_1 + %263 = OpFMul %float %260 %float_0_5 + %264 = OpFMul %float %263 %236 + %265 = OpExtInst %float %1 FMax %264 %float_2 + %266 = OpFSub %float %265 %float_1 + %267 = OpCompositeConstruct %v2float %262 %266 + %268 = OpAccessChain %_ptr_Uniform_float %LandscapeParameters %int_3 %int_1 + %269 = OpLoad %float %268 + %270 = OpCompositeConstruct %v2float %269 %269 + %271 = OpFMul %v2float %267 %270 + %272 = OpCompositeExtract %float %271 0 + %273 = OpCompositeConstruct %v2float %272 %272 + %274 = OpFDiv %v2float %257 %273 + %275 = OpFMul %v2float %257 %46 + %276 = OpExtInst %v2float %1 Floor %275 + %277 = OpCompositeExtract %float %271 1 + %278 = OpCompositeConstruct %v2float %277 %277 + %279 = OpFDiv %v2float %276 %278 + %280 = OpCompositeExtract %float %274 0 + %281 = OpCompositeExtract %float %274 1 + %282 = OpCompositeConstruct %v3float %280 %281 %253 + %283 = OpCompositeExtract %float %279 0 + %284 = OpCompositeExtract %float %279 1 + %285 = OpCompositeConstruct %v3float %283 %284 %254 + %286 = OpCompositeConstruct %v3float %208 %208 %208 + %287 = OpExtInst %v3float %1 FMix %282 %285 %286 + %288 = OpVectorShuffle %v2float %119 %92 0 1 + %289 = OpAccessChain %_ptr_Uniform_v4float %LandscapeParameters %int_4 + %290 = OpLoad %v4float %289 + %291 = OpVectorShuffle %v2float %290 %290 3 3 + %292 = OpFMul %v2float %288 %291 + %293 = OpCompositeExtract %float %292 0 + %294 = OpCompositeExtract %float %292 1 + %295 = OpCompositeConstruct %v3float %293 %294 %float_0 + %296 = OpFAdd %v3float %287 %295 + %297 = OpAccessChain %_ptr_Uniform_v4float %Primitive %int_0 %uint_0 + %298 = OpLoad %v4float %297 + %299 = OpVectorShuffle %v3float %298 %298 0 1 2 + %300 = OpVectorShuffle %v3float %296 %296 0 0 0 + %301 = OpFMul %v3float %299 %300 + %302 = OpAccessChain %_ptr_Uniform_v4float %Primitive %int_0 %uint_1 + %303 = OpLoad %v4float %302 + %304 = OpVectorShuffle %v3float %303 %303 0 1 2 + %305 = OpVectorShuffle %v3float %296 %296 1 1 1 + %306 = OpFMul %v3float %304 %305 + %307 = OpFAdd %v3float %301 %306 + %308 = OpAccessChain %_ptr_Uniform_v4float %Primitive %int_0 %uint_2 + %309 = OpLoad %v4float %308 + %310 = OpVectorShuffle %v3float %309 %309 0 1 2 + %311 = OpVectorShuffle %v3float %296 %296 2 2 2 + %312 = OpFMul %v3float %310 %311 + %313 = OpFAdd %v3float %307 %312 + %314 = OpAccessChain %_ptr_Uniform_v4float %Primitive %int_0 %uint_3 + %315 = OpLoad %v4float %314 + %316 = OpVectorShuffle %v3float %315 %315 0 1 2 + %317 = OpFAdd %v3float %316 %105 + %318 = OpFAdd %v3float %313 %317 + %319 = OpCompositeExtract %float %318 0 + %320 = OpCompositeExtract %float %318 1 + %321 = OpCompositeExtract %float %318 2 + %322 = OpCompositeConstruct %v4float %319 %320 %321 %float_1 + %323 = OpVectorShuffle %v2float %287 %287 0 1 + %324 = OpLoad %v4float %258 + %325 = OpVectorShuffle %v2float %324 %324 2 3 + %326 = OpFAdd %v2float %323 %325 + %327 = OpFAdd %v2float %326 %292 + %328 = OpAccessChain %_ptr_Uniform_v4float %LandscapeParameters %int_1 + %329 = OpLoad %v4float %328 + %330 = OpVectorShuffle %v2float %329 %329 0 1 + %331 = OpFMul %v2float %323 %330 + %332 = OpVectorShuffle %v2float %329 %329 2 3 + %333 = OpFAdd %v2float %331 %332 + %334 = OpVectorShuffle %v2float %290 %290 2 2 + %335 = OpFMul %v2float %288 %334 + %336 = OpFAdd %v2float %333 %335 + %337 = OpVectorShuffle %v2float %327 %92 0 1 + %338 = OpVectorShuffle %v4float %322 %322 4 5 6 3 + %339 = OpMatrixTimesVector %v4float %101 %338 + %340 = OpVectorShuffle %v3float %322 %92 0 1 2 + %341 = OpFSub %v3float %340 %103 + %342 = OpAccessChain %_ptr_Uniform_v4float %MobileBasePass %int_2 + %343 = OpAccessChain %_ptr_Uniform_float %MobileBasePass %int_2 %int_3 + %344 = OpLoad %float %343 + %345 = OpDot %float %341 %341 + %346 = OpExtInst %float %1 InverseSqrt %345 + %347 = OpFMul %float %345 %346 + %348 = OpCompositeConstruct %v3float %346 %346 %346 + %349 = OpFMul %v3float %341 %348 + %350 = OpAccessChain %_ptr_Uniform_float %MobileBasePass %int_0 %int_0 + %351 = OpLoad %float %350 + %352 = OpAccessChain %_ptr_Uniform_float %MobileBasePass %int_1 %int_0 + %353 = OpLoad %float %352 + %354 = OpCompositeExtract %float %341 2 + %355 = OpAccessChain %_ptr_Uniform_float %MobileBasePass %int_0 %int_3 + %356 = OpLoad %float %355 + %357 = OpExtInst %float %1 FMax %float_0 %356 + %358 = OpFOrdGreaterThan %bool %357 %float_0 + OpSelectionMerge %359 None + OpBranchConditional %358 %360 %359 + %360 = OpLabel + %361 = OpFMul %float %357 %346 + %362 = OpFMul %float %361 %354 + %363 = OpAccessChain %_ptr_Uniform_float %View %int_25 %int_2 + %364 = OpLoad %float %363 + %365 = OpFAdd %float %364 %362 + %366 = OpFSub %float %354 %362 + %367 = OpFSub %float %float_1 %361 + %368 = OpFMul %float %367 %347 + %369 = OpAccessChain %_ptr_Uniform_float %MobileBasePass %int_0 %int_1 + %370 = OpLoad %float %369 + %371 = OpAccessChain %_ptr_Uniform_float %MobileBasePass %int_3 %int_1 + %372 = OpLoad %float %371 + %373 = OpFSub %float %365 %372 + %374 = OpFMul %float %370 %373 + %375 = OpExtInst %float %1 FMax %float_n127 %374 + %376 = OpAccessChain %_ptr_Uniform_float %MobileBasePass %int_3 %int_0 + %377 = OpLoad %float %376 + %378 = OpFNegate %float %375 + %379 = OpExtInst %float %1 Exp2 %378 + %380 = OpFMul %float %377 %379 + %381 = OpAccessChain %_ptr_Uniform_float %MobileBasePass %int_1 %int_1 + %382 = OpLoad %float %381 + %383 = OpAccessChain %_ptr_Uniform_float %MobileBasePass %int_1 %int_3 + %384 = OpLoad %float %383 + %385 = OpFSub %float %365 %384 + %386 = OpFMul %float %382 %385 + %387 = OpExtInst %float %1 FMax %float_n127 %386 + %388 = OpAccessChain %_ptr_Uniform_float %MobileBasePass %int_1 %int_2 + %389 = OpLoad %float %388 + %390 = OpFNegate %float %387 + %391 = OpExtInst %float %1 Exp2 %390 + %392 = OpFMul %float %389 %391 + OpBranch %359 + %359 = OpLabel + %393 = OpPhi %float %347 %189 %368 %360 + %394 = OpPhi %float %353 %189 %392 %360 + %395 = OpPhi %float %351 %189 %380 %360 + %396 = OpPhi %float %354 %189 %366 %360 + %397 = OpAccessChain %_ptr_Uniform_float %MobileBasePass %int_0 %int_1 + %398 = OpLoad %float %397 + %399 = OpFMul %float %398 %396 + %400 = OpExtInst %float %1 FMax %float_n127 %399 + %401 = OpFNegate %float %400 + %402 = OpExtInst %float %1 Exp2 %401 + %403 = OpFSub %float %float_1 %402 + %404 = OpFDiv %float %403 %400 + %405 = OpExtInst %float %1 Log %float_2 + %406 = OpFMul %float %405 %405 + %407 = OpFMul %float %float_0_5 %406 + %408 = OpFMul %float %407 %400 + %409 = OpFSub %float %405 %408 + %410 = OpExtInst %float %1 FAbs %400 + %411 = OpFOrdGreaterThan %bool %410 %float_0_00999999978 + %412 = OpSelect %float %411 %404 %409 + %413 = OpFMul %float %395 %412 + %414 = OpAccessChain %_ptr_Uniform_float %MobileBasePass %int_1 %int_1 + %415 = OpLoad %float %414 + %416 = OpFMul %float %415 %396 + %417 = OpExtInst %float %1 FMax %float_n127 %416 + %418 = OpFNegate %float %417 + %419 = OpExtInst %float %1 Exp2 %418 + %420 = OpFSub %float %float_1 %419 + %421 = OpFDiv %float %420 %417 + %422 = OpFMul %float %407 %417 + %423 = OpFSub %float %405 %422 + %424 = OpExtInst %float %1 FAbs %417 + %425 = OpFOrdGreaterThan %bool %424 %float_0_00999999978 + %426 = OpSelect %float %425 %421 %423 + %427 = OpFMul %float %394 %426 + %428 = OpFAdd %float %413 %427 + %429 = OpFMul %float %428 %393 + %430 = OpLoad %v4float %342 + %431 = OpVectorShuffle %v3float %430 %430 0 1 2 + %432 = OpAccessChain %_ptr_Uniform_v4float %MobileBasePass %int_4 + %433 = OpAccessChain %_ptr_Uniform_float %MobileBasePass %int_4 %int_3 + %434 = OpLoad %float %433 + %435 = OpFOrdGreaterThanEqual %bool %434 %float_0 + OpSelectionMerge %436 DontFlatten + OpBranchConditional %435 %437 %436 + %437 = OpLabel + %438 = OpAccessChain %_ptr_Uniform_v4float %MobileBasePass %int_5 + %439 = OpLoad %v4float %438 + %440 = OpVectorShuffle %v3float %439 %439 0 1 2 + %441 = OpLoad %v4float %432 + %442 = OpVectorShuffle %v3float %441 %441 0 1 2 + %443 = OpDot %float %349 %442 + %444 = OpExtInst %float %1 FClamp %443 %float_0 %float_1 + %445 = OpAccessChain %_ptr_Uniform_float %MobileBasePass %int_5 %int_3 + %446 = OpLoad %float %445 + %447 = OpExtInst %float %1 Pow %444 %446 + %448 = OpCompositeConstruct %v3float %447 %447 %447 + %449 = OpFMul %v3float %440 %448 + %450 = OpFSub %float %393 %434 + %451 = OpExtInst %float %1 FMax %450 %float_0 + %452 = OpFMul %float %428 %451 + %453 = OpFNegate %float %452 + %454 = OpExtInst %float %1 Exp2 %453 + %455 = OpExtInst %float %1 FClamp %454 %float_0 %float_1 + %456 = OpFSub %float %float_1 %455 + %457 = OpCompositeConstruct %v3float %456 %456 %456 + %458 = OpFMul %v3float %449 %457 + OpBranch %436 + %436 = OpLabel + %459 = OpPhi %v3float %63 %359 %458 %437 + %460 = OpFNegate %float %429 + %461 = OpExtInst %float %1 Exp2 %460 + %462 = OpExtInst %float %1 FClamp %461 %float_0 %float_1 + %463 = OpExtInst %float %1 FMax %462 %344 + %464 = OpAccessChain %_ptr_Uniform_float %MobileBasePass %int_3 %int_3 + %465 = OpLoad %float %464 + %466 = OpFOrdGreaterThan %bool %465 %float_0 + %467 = OpFOrdGreaterThan %bool %347 %465 + %468 = OpLogicalAnd %bool %466 %467 + %469 = OpCompositeConstruct %v3bool %468 %468 %468 + %470 = OpSelect %v3float %469 %63 %459 + %471 = OpSelect %float %468 %float_1 %463 + %472 = OpFSub %float %float_1 %471 + %473 = OpCompositeConstruct %v3float %472 %472 %472 + %474 = OpFMul %v3float %431 %473 + %475 = OpFAdd %v3float %474 %470 + %476 = OpCompositeExtract %float %475 0 + %477 = OpCompositeExtract %float %475 1 + %478 = OpCompositeExtract %float %475 2 + %479 = OpCompositeConstruct %v4float %476 %477 %478 %471 + %480 = OpAccessChain %_ptr_Function_v4float %97 %int_0 + OpStore %480 %479 + %481 = OpCompositeExtract %float %339 3 + %482 = OpCompositeInsert %v4float %481 %338 3 + %483 = OpLoad %_arr_v4float_uint_1 %97 + %484 = OpCompositeExtract %v4float %483 0 + %485 = OpVectorShuffle %v4float %92 %484 0 1 4 5 + %486 = OpVectorShuffle %v4float %92 %484 0 1 6 7 + OpStore %out_var_TEXCOORD0 %337 + OpStore %out_var_TEXCOORD1 %336 + OpStore %out_var_TEXCOORD2 %485 + OpStore %out_var_TEXCOORD3 %486 + OpStore %out_var_TEXCOORD8 %482 + OpStore %gl_Position %339 + OpReturn + OpFunctionEnd diff --git a/third_party/spirv-cross/shaders-ue4/asm/vert/texture-buffer.asm.vert b/third_party/spirv-cross/shaders-ue4/asm/vert/texture-buffer.asm.vert new file mode 100644 index 0000000000..6d52623a14 --- /dev/null +++ b/third_party/spirv-cross/shaders-ue4/asm/vert/texture-buffer.asm.vert @@ -0,0 +1,1054 @@ +; SPIR-V +; Version: 1.0 +; Generator: Google spiregg; 0 +; Bound: 397 +; Schema: 0 + OpCapability Shader + OpCapability SampledBuffer + OpCapability StorageImageExtendedFormats + OpExtension "SPV_GOOGLE_hlsl_functionality1" + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %Main "main" %gl_VertexIndex %gl_InstanceIndex %in_var_ATTRIBUTE0 %out_var_TEXCOORD6 %gl_Position + OpSource HLSL 600 + OpName %type_View "type.View" + OpMemberName %type_View 0 "View_TranslatedWorldToClip" + OpMemberName %type_View 1 "View_WorldToClip" + OpMemberName %type_View 2 "View_TranslatedWorldToView" + OpMemberName %type_View 3 "View_ViewToTranslatedWorld" + OpMemberName %type_View 4 "View_TranslatedWorldToCameraView" + OpMemberName %type_View 5 "View_CameraViewToTranslatedWorld" + OpMemberName %type_View 6 "View_ViewToClip" + OpMemberName %type_View 7 "View_ViewToClipNoAA" + OpMemberName %type_View 8 "View_ClipToView" + OpMemberName %type_View 9 "View_ClipToTranslatedWorld" + OpMemberName %type_View 10 "View_SVPositionToTranslatedWorld" + OpMemberName %type_View 11 "View_ScreenToWorld" + OpMemberName %type_View 12 "View_ScreenToTranslatedWorld" + OpMemberName %type_View 13 "View_ViewForward" + OpMemberName %type_View 14 "PrePadding_View_844" + OpMemberName %type_View 15 "View_ViewUp" + OpMemberName %type_View 16 "PrePadding_View_860" + OpMemberName %type_View 17 "View_ViewRight" + OpMemberName %type_View 18 "PrePadding_View_876" + OpMemberName %type_View 19 "View_HMDViewNoRollUp" + OpMemberName %type_View 20 "PrePadding_View_892" + OpMemberName %type_View 21 "View_HMDViewNoRollRight" + OpMemberName %type_View 22 "PrePadding_View_908" + OpMemberName %type_View 23 "View_InvDeviceZToWorldZTransform" + OpMemberName %type_View 24 "View_ScreenPositionScaleBias" + OpMemberName %type_View 25 "View_WorldCameraOrigin" + OpMemberName %type_View 26 "PrePadding_View_956" + OpMemberName %type_View 27 "View_TranslatedWorldCameraOrigin" + OpMemberName %type_View 28 "PrePadding_View_972" + OpMemberName %type_View 29 "View_WorldViewOrigin" + OpMemberName %type_View 30 "PrePadding_View_988" + OpMemberName %type_View 31 "View_PreViewTranslation" + OpMemberName %type_View 32 "PrePadding_View_1004" + OpMemberName %type_View 33 "View_PrevProjection" + OpMemberName %type_View 34 "View_PrevViewProj" + OpMemberName %type_View 35 "View_PrevViewRotationProj" + OpMemberName %type_View 36 "View_PrevViewToClip" + OpMemberName %type_View 37 "View_PrevClipToView" + OpMemberName %type_View 38 "View_PrevTranslatedWorldToClip" + OpMemberName %type_View 39 "View_PrevTranslatedWorldToView" + OpMemberName %type_View 40 "View_PrevViewToTranslatedWorld" + OpMemberName %type_View 41 "View_PrevTranslatedWorldToCameraView" + OpMemberName %type_View 42 "View_PrevCameraViewToTranslatedWorld" + OpMemberName %type_View 43 "View_PrevWorldCameraOrigin" + OpMemberName %type_View 44 "PrePadding_View_1660" + OpMemberName %type_View 45 "View_PrevWorldViewOrigin" + OpMemberName %type_View 46 "PrePadding_View_1676" + OpMemberName %type_View 47 "View_PrevPreViewTranslation" + OpMemberName %type_View 48 "PrePadding_View_1692" + OpMemberName %type_View 49 "View_PrevInvViewProj" + OpMemberName %type_View 50 "View_PrevScreenToTranslatedWorld" + OpMemberName %type_View 51 "View_ClipToPrevClip" + OpMemberName %type_View 52 "View_TemporalAAJitter" + OpMemberName %type_View 53 "View_GlobalClippingPlane" + OpMemberName %type_View 54 "View_FieldOfViewWideAngles" + OpMemberName %type_View 55 "View_PrevFieldOfViewWideAngles" + OpMemberName %type_View 56 "View_ViewRectMin" + OpMemberName %type_View 57 "View_ViewSizeAndInvSize" + OpMemberName %type_View 58 "View_BufferSizeAndInvSize" + OpMemberName %type_View 59 "View_BufferBilinearUVMinMax" + OpMemberName %type_View 60 "View_NumSceneColorMSAASamples" + OpMemberName %type_View 61 "View_PreExposure" + OpMemberName %type_View 62 "View_OneOverPreExposure" + OpMemberName %type_View 63 "PrePadding_View_2012" + OpMemberName %type_View 64 "View_DiffuseOverrideParameter" + OpMemberName %type_View 65 "View_SpecularOverrideParameter" + OpMemberName %type_View 66 "View_NormalOverrideParameter" + OpMemberName %type_View 67 "View_RoughnessOverrideParameter" + OpMemberName %type_View 68 "View_PrevFrameGameTime" + OpMemberName %type_View 69 "View_PrevFrameRealTime" + OpMemberName %type_View 70 "View_OutOfBoundsMask" + OpMemberName %type_View 71 "PrePadding_View_2084" + OpMemberName %type_View 72 "PrePadding_View_2088" + OpMemberName %type_View 73 "PrePadding_View_2092" + OpMemberName %type_View 74 "View_WorldCameraMovementSinceLastFrame" + OpMemberName %type_View 75 "View_CullingSign" + OpMemberName %type_View 76 "View_NearPlane" + OpMemberName %type_View 77 "View_AdaptiveTessellationFactor" + OpMemberName %type_View 78 "View_GameTime" + OpMemberName %type_View 79 "View_RealTime" + OpMemberName %type_View 80 "View_DeltaTime" + OpMemberName %type_View 81 "View_MaterialTextureMipBias" + OpMemberName %type_View 82 "View_MaterialTextureDerivativeMultiply" + OpMemberName %type_View 83 "View_Random" + OpMemberName %type_View 84 "View_FrameNumber" + OpMemberName %type_View 85 "View_StateFrameIndexMod8" + OpMemberName %type_View 86 "View_StateFrameIndex" + OpMemberName %type_View 87 "View_CameraCut" + OpMemberName %type_View 88 "View_UnlitViewmodeMask" + OpMemberName %type_View 89 "PrePadding_View_2164" + OpMemberName %type_View 90 "PrePadding_View_2168" + OpMemberName %type_View 91 "PrePadding_View_2172" + OpMemberName %type_View 92 "View_DirectionalLightColor" + OpMemberName %type_View 93 "View_DirectionalLightDirection" + OpMemberName %type_View 94 "PrePadding_View_2204" + OpMemberName %type_View 95 "View_TranslucencyLightingVolumeMin" + OpMemberName %type_View 96 "View_TranslucencyLightingVolumeInvSize" + OpMemberName %type_View 97 "View_TemporalAAParams" + OpMemberName %type_View 98 "View_CircleDOFParams" + OpMemberName %type_View 99 "View_DepthOfFieldSensorWidth" + OpMemberName %type_View 100 "View_DepthOfFieldFocalDistance" + OpMemberName %type_View 101 "View_DepthOfFieldScale" + OpMemberName %type_View 102 "View_DepthOfFieldFocalLength" + OpMemberName %type_View 103 "View_DepthOfFieldFocalRegion" + OpMemberName %type_View 104 "View_DepthOfFieldNearTransitionRegion" + OpMemberName %type_View 105 "View_DepthOfFieldFarTransitionRegion" + OpMemberName %type_View 106 "View_MotionBlurNormalizedToPixel" + OpMemberName %type_View 107 "View_bSubsurfacePostprocessEnabled" + OpMemberName %type_View 108 "View_GeneralPurposeTweak" + OpMemberName %type_View 109 "View_DemosaicVposOffset" + OpMemberName %type_View 110 "PrePadding_View_2348" + OpMemberName %type_View 111 "View_IndirectLightingColorScale" + OpMemberName %type_View 112 "View_HDR32bppEncodingMode" + OpMemberName %type_View 113 "View_AtmosphericFogSunDirection" + OpMemberName %type_View 114 "View_AtmosphericFogSunPower" + OpMemberName %type_View 115 "View_AtmosphericFogPower" + OpMemberName %type_View 116 "View_AtmosphericFogDensityScale" + OpMemberName %type_View 117 "View_AtmosphericFogDensityOffset" + OpMemberName %type_View 118 "View_AtmosphericFogGroundOffset" + OpMemberName %type_View 119 "View_AtmosphericFogDistanceScale" + OpMemberName %type_View 120 "View_AtmosphericFogAltitudeScale" + OpMemberName %type_View 121 "View_AtmosphericFogHeightScaleRayleigh" + OpMemberName %type_View 122 "View_AtmosphericFogStartDistance" + OpMemberName %type_View 123 "View_AtmosphericFogDistanceOffset" + OpMemberName %type_View 124 "View_AtmosphericFogSunDiscScale" + OpMemberName %type_View 125 "View_AtmosphericFogRenderMask" + OpMemberName %type_View 126 "View_AtmosphericFogInscatterAltitudeSampleNum" + OpMemberName %type_View 127 "View_AtmosphericFogSunColor" + OpMemberName %type_View 128 "View_NormalCurvatureToRoughnessScaleBias" + OpMemberName %type_View 129 "View_RenderingReflectionCaptureMask" + OpMemberName %type_View 130 "View_AmbientCubemapTint" + OpMemberName %type_View 131 "View_AmbientCubemapIntensity" + OpMemberName %type_View 132 "View_SkyLightParameters" + OpMemberName %type_View 133 "PrePadding_View_2488" + OpMemberName %type_View 134 "PrePadding_View_2492" + OpMemberName %type_View 135 "View_SkyLightColor" + OpMemberName %type_View 136 "View_SkyIrradianceEnvironmentMap" + OpMemberName %type_View 137 "View_MobilePreviewMode" + OpMemberName %type_View 138 "View_HMDEyePaddingOffset" + OpMemberName %type_View 139 "View_ReflectionCubemapMaxMip" + OpMemberName %type_View 140 "View_ShowDecalsMask" + OpMemberName %type_View 141 "View_DistanceFieldAOSpecularOcclusionMode" + OpMemberName %type_View 142 "View_IndirectCapsuleSelfShadowingIntensity" + OpMemberName %type_View 143 "PrePadding_View_2648" + OpMemberName %type_View 144 "PrePadding_View_2652" + OpMemberName %type_View 145 "View_ReflectionEnvironmentRoughnessMixingScaleBiasAndLargestWeight" + OpMemberName %type_View 146 "View_StereoPassIndex" + OpMemberName %type_View 147 "View_GlobalVolumeCenterAndExtent" + OpMemberName %type_View 148 "View_GlobalVolumeWorldToUVAddAndMul" + OpMemberName %type_View 149 "View_GlobalVolumeDimension" + OpMemberName %type_View 150 "View_GlobalVolumeTexelSize" + OpMemberName %type_View 151 "View_MaxGlobalDistance" + OpMemberName %type_View 152 "View_bCheckerboardSubsurfaceProfileRendering" + OpMemberName %type_View 153 "View_VolumetricFogInvGridSize" + OpMemberName %type_View 154 "PrePadding_View_2828" + OpMemberName %type_View 155 "View_VolumetricFogGridZParams" + OpMemberName %type_View 156 "PrePadding_View_2844" + OpMemberName %type_View 157 "View_VolumetricFogSVPosToVolumeUV" + OpMemberName %type_View 158 "View_VolumetricFogMaxDistance" + OpMemberName %type_View 159 "PrePadding_View_2860" + OpMemberName %type_View 160 "View_VolumetricLightmapWorldToUVScale" + OpMemberName %type_View 161 "PrePadding_View_2876" + OpMemberName %type_View 162 "View_VolumetricLightmapWorldToUVAdd" + OpMemberName %type_View 163 "PrePadding_View_2892" + OpMemberName %type_View 164 "View_VolumetricLightmapIndirectionTextureSize" + OpMemberName %type_View 165 "View_VolumetricLightmapBrickSize" + OpMemberName %type_View 166 "View_VolumetricLightmapBrickTexelSize" + OpMemberName %type_View 167 "View_StereoIPD" + OpMemberName %type_View 168 "View_IndirectLightingCacheShowFlag" + OpMemberName %type_View 169 "View_EyeToPixelSpreadAngle" + OpName %View "View" + OpName %type_Primitive "type.Primitive" + OpMemberName %type_Primitive 0 "Primitive_LocalToWorld" + OpMemberName %type_Primitive 1 "Primitive_InvNonUniformScaleAndDeterminantSign" + OpMemberName %type_Primitive 2 "Primitive_ObjectWorldPositionAndRadius" + OpMemberName %type_Primitive 3 "Primitive_WorldToLocal" + OpMemberName %type_Primitive 4 "Primitive_PreviousLocalToWorld" + OpMemberName %type_Primitive 5 "Primitive_PreviousWorldToLocal" + OpMemberName %type_Primitive 6 "Primitive_ActorWorldPosition" + OpMemberName %type_Primitive 7 "Primitive_UseSingleSampleShadowFromStationaryLights" + OpMemberName %type_Primitive 8 "Primitive_ObjectBounds" + OpMemberName %type_Primitive 9 "Primitive_LpvBiasMultiplier" + OpMemberName %type_Primitive 10 "Primitive_DecalReceiverMask" + OpMemberName %type_Primitive 11 "Primitive_PerObjectGBufferData" + OpMemberName %type_Primitive 12 "Primitive_UseVolumetricLightmapShadowFromStationaryLights" + OpMemberName %type_Primitive 13 "Primitive_UseEditorDepthTest" + OpMemberName %type_Primitive 14 "Primitive_ObjectOrientation" + OpMemberName %type_Primitive 15 "Primitive_NonUniformScale" + OpMemberName %type_Primitive 16 "Primitive_LocalObjectBoundsMin" + OpMemberName %type_Primitive 17 "PrePadding_Primitive_380" + OpMemberName %type_Primitive 18 "Primitive_LocalObjectBoundsMax" + OpMemberName %type_Primitive 19 "Primitive_LightingChannelMask" + OpMemberName %type_Primitive 20 "Primitive_LightmapDataIndex" + OpMemberName %type_Primitive 21 "Primitive_SingleCaptureIndex" + OpName %Primitive "Primitive" + OpName %type_MobileShadowDepthPass "type.MobileShadowDepthPass" + OpMemberName %type_MobileShadowDepthPass 0 "PrePadding_MobileShadowDepthPass_0" + OpMemberName %type_MobileShadowDepthPass 1 "PrePadding_MobileShadowDepthPass_4" + OpMemberName %type_MobileShadowDepthPass 2 "PrePadding_MobileShadowDepthPass_8" + OpMemberName %type_MobileShadowDepthPass 3 "PrePadding_MobileShadowDepthPass_12" + OpMemberName %type_MobileShadowDepthPass 4 "PrePadding_MobileShadowDepthPass_16" + OpMemberName %type_MobileShadowDepthPass 5 "PrePadding_MobileShadowDepthPass_20" + OpMemberName %type_MobileShadowDepthPass 6 "PrePadding_MobileShadowDepthPass_24" + OpMemberName %type_MobileShadowDepthPass 7 "PrePadding_MobileShadowDepthPass_28" + OpMemberName %type_MobileShadowDepthPass 8 "PrePadding_MobileShadowDepthPass_32" + OpMemberName %type_MobileShadowDepthPass 9 "PrePadding_MobileShadowDepthPass_36" + OpMemberName %type_MobileShadowDepthPass 10 "PrePadding_MobileShadowDepthPass_40" + OpMemberName %type_MobileShadowDepthPass 11 "PrePadding_MobileShadowDepthPass_44" + OpMemberName %type_MobileShadowDepthPass 12 "PrePadding_MobileShadowDepthPass_48" + OpMemberName %type_MobileShadowDepthPass 13 "PrePadding_MobileShadowDepthPass_52" + OpMemberName %type_MobileShadowDepthPass 14 "PrePadding_MobileShadowDepthPass_56" + OpMemberName %type_MobileShadowDepthPass 15 "PrePadding_MobileShadowDepthPass_60" + OpMemberName %type_MobileShadowDepthPass 16 "PrePadding_MobileShadowDepthPass_64" + OpMemberName %type_MobileShadowDepthPass 17 "PrePadding_MobileShadowDepthPass_68" + OpMemberName %type_MobileShadowDepthPass 18 "PrePadding_MobileShadowDepthPass_72" + OpMemberName %type_MobileShadowDepthPass 19 "PrePadding_MobileShadowDepthPass_76" + OpMemberName %type_MobileShadowDepthPass 20 "MobileShadowDepthPass_ProjectionMatrix" + OpMemberName %type_MobileShadowDepthPass 21 "MobileShadowDepthPass_ShadowParams" + OpMemberName %type_MobileShadowDepthPass 22 "MobileShadowDepthPass_bClampToNearPlane" + OpMemberName %type_MobileShadowDepthPass 23 "PrePadding_MobileShadowDepthPass_156" + OpMemberName %type_MobileShadowDepthPass 24 "MobileShadowDepthPass_ShadowViewProjectionMatrices" + OpName %MobileShadowDepthPass "MobileShadowDepthPass" + OpName %type_EmitterDynamicUniforms "type.EmitterDynamicUniforms" + OpMemberName %type_EmitterDynamicUniforms 0 "EmitterDynamicUniforms_LocalToWorldScale" + OpMemberName %type_EmitterDynamicUniforms 1 "EmitterDynamicUniforms_EmitterInstRandom" + OpMemberName %type_EmitterDynamicUniforms 2 "PrePadding_EmitterDynamicUniforms_12" + OpMemberName %type_EmitterDynamicUniforms 3 "EmitterDynamicUniforms_AxisLockRight" + OpMemberName %type_EmitterDynamicUniforms 4 "EmitterDynamicUniforms_AxisLockUp" + OpMemberName %type_EmitterDynamicUniforms 5 "EmitterDynamicUniforms_DynamicColor" + OpMemberName %type_EmitterDynamicUniforms 6 "EmitterDynamicUniforms_MacroUVParameters" + OpName %EmitterDynamicUniforms "EmitterDynamicUniforms" + OpName %type_EmitterUniforms "type.EmitterUniforms" + OpMemberName %type_EmitterUniforms 0 "EmitterUniforms_ColorCurve" + OpMemberName %type_EmitterUniforms 1 "EmitterUniforms_ColorScale" + OpMemberName %type_EmitterUniforms 2 "EmitterUniforms_ColorBias" + OpMemberName %type_EmitterUniforms 3 "EmitterUniforms_MiscCurve" + OpMemberName %type_EmitterUniforms 4 "EmitterUniforms_MiscScale" + OpMemberName %type_EmitterUniforms 5 "EmitterUniforms_MiscBias" + OpMemberName %type_EmitterUniforms 6 "EmitterUniforms_SizeBySpeed" + OpMemberName %type_EmitterUniforms 7 "EmitterUniforms_SubImageSize" + OpMemberName %type_EmitterUniforms 8 "EmitterUniforms_TangentSelector" + OpMemberName %type_EmitterUniforms 9 "EmitterUniforms_CameraFacingBlend" + OpMemberName %type_EmitterUniforms 10 "EmitterUniforms_RemoveHMDRoll" + OpMemberName %type_EmitterUniforms 11 "EmitterUniforms_RotationRateScale" + OpMemberName %type_EmitterUniforms 12 "EmitterUniforms_RotationBias" + OpMemberName %type_EmitterUniforms 13 "EmitterUniforms_CameraMotionBlurAmount" + OpMemberName %type_EmitterUniforms 14 "PrePadding_EmitterUniforms_172" + OpMemberName %type_EmitterUniforms 15 "EmitterUniforms_PivotOffset" + OpName %EmitterUniforms "EmitterUniforms" + OpName %type_buffer_image "type.buffer.image" + OpName %ParticleIndices "ParticleIndices" + OpName %type__Globals "type.$Globals" + OpMemberName %type__Globals 0 "ParticleIndicesOffset" + OpName %_Globals "$Globals" + OpName %type_2d_image "type.2d.image" + OpName %PositionTexture "PositionTexture" + OpName %type_sampler "type.sampler" + OpName %PositionTextureSampler "PositionTextureSampler" + OpName %VelocityTexture "VelocityTexture" + OpName %VelocityTextureSampler "VelocityTextureSampler" + OpName %AttributesTexture "AttributesTexture" + OpName %AttributesTextureSampler "AttributesTextureSampler" + OpName %CurveTexture "CurveTexture" + OpName %CurveTextureSampler "CurveTextureSampler" + OpName %in_var_ATTRIBUTE0 "in.var.ATTRIBUTE0" + OpName %out_var_TEXCOORD6 "out.var.TEXCOORD6" + OpName %Main "Main" + OpName %type_sampled_image "type.sampled.image" + OpDecorate %gl_VertexIndex BuiltIn VertexIndex + OpDecorateString %gl_VertexIndex UserSemantic "SV_VertexID" + OpDecorate %gl_InstanceIndex BuiltIn InstanceIndex + OpDecorateString %gl_InstanceIndex UserSemantic "SV_InstanceID" + OpDecorateString %in_var_ATTRIBUTE0 UserSemantic "ATTRIBUTE0" + OpDecorateString %out_var_TEXCOORD6 UserSemantic "TEXCOORD6" + OpDecorate %gl_Position BuiltIn Position + OpDecorateString %gl_Position UserSemantic "SV_POSITION" + OpDecorate %in_var_ATTRIBUTE0 Location 0 + OpDecorate %out_var_TEXCOORD6 Location 0 + OpDecorate %View DescriptorSet 0 + OpDecorate %View Binding 1 + OpDecorate %Primitive DescriptorSet 0 + OpDecorate %Primitive Binding 2 + OpDecorate %MobileShadowDepthPass DescriptorSet 0 + OpDecorate %MobileShadowDepthPass Binding 3 + OpDecorate %EmitterDynamicUniforms DescriptorSet 0 + OpDecorate %EmitterDynamicUniforms Binding 4 + OpDecorate %EmitterUniforms DescriptorSet 0 + OpDecorate %EmitterUniforms Binding 5 + OpDecorate %ParticleIndices DescriptorSet 0 + OpDecorate %ParticleIndices Binding 0 + OpDecorate %_Globals DescriptorSet 0 + OpDecorate %_Globals Binding 6 + OpDecorate %PositionTexture DescriptorSet 0 + OpDecorate %PositionTexture Binding 1 + OpDecorate %PositionTextureSampler DescriptorSet 0 + OpDecorate %PositionTextureSampler Binding 0 + OpDecorate %VelocityTexture DescriptorSet 0 + OpDecorate %VelocityTexture Binding 2 + OpDecorate %VelocityTextureSampler DescriptorSet 0 + OpDecorate %VelocityTextureSampler Binding 1 + OpDecorate %AttributesTexture DescriptorSet 0 + OpDecorate %AttributesTexture Binding 3 + OpDecorate %AttributesTextureSampler DescriptorSet 0 + OpDecorate %AttributesTextureSampler Binding 2 + OpDecorate %CurveTexture DescriptorSet 0 + OpDecorate %CurveTexture Binding 4 + OpDecorate %CurveTextureSampler DescriptorSet 0 + OpDecorate %CurveTextureSampler Binding 3 + OpDecorate %_arr_v4float_uint_2 ArrayStride 16 + OpDecorate %_arr_v4float_uint_7 ArrayStride 16 + OpDecorate %_arr_v4float_uint_4 ArrayStride 16 + OpMemberDecorate %type_View 0 Offset 0 + OpMemberDecorate %type_View 0 MatrixStride 16 + OpMemberDecorate %type_View 0 ColMajor + OpMemberDecorate %type_View 1 Offset 64 + OpMemberDecorate %type_View 1 MatrixStride 16 + OpMemberDecorate %type_View 1 ColMajor + OpMemberDecorate %type_View 2 Offset 128 + OpMemberDecorate %type_View 2 MatrixStride 16 + OpMemberDecorate %type_View 2 ColMajor + OpMemberDecorate %type_View 3 Offset 192 + OpMemberDecorate %type_View 3 MatrixStride 16 + OpMemberDecorate %type_View 3 ColMajor + OpMemberDecorate %type_View 4 Offset 256 + OpMemberDecorate %type_View 4 MatrixStride 16 + OpMemberDecorate %type_View 4 ColMajor + OpMemberDecorate %type_View 5 Offset 320 + OpMemberDecorate %type_View 5 MatrixStride 16 + OpMemberDecorate %type_View 5 ColMajor + OpMemberDecorate %type_View 6 Offset 384 + OpMemberDecorate %type_View 6 MatrixStride 16 + OpMemberDecorate %type_View 6 ColMajor + OpMemberDecorate %type_View 7 Offset 448 + OpMemberDecorate %type_View 7 MatrixStride 16 + OpMemberDecorate %type_View 7 ColMajor + OpMemberDecorate %type_View 8 Offset 512 + OpMemberDecorate %type_View 8 MatrixStride 16 + OpMemberDecorate %type_View 8 ColMajor + OpMemberDecorate %type_View 9 Offset 576 + OpMemberDecorate %type_View 9 MatrixStride 16 + OpMemberDecorate %type_View 9 ColMajor + OpMemberDecorate %type_View 10 Offset 640 + OpMemberDecorate %type_View 10 MatrixStride 16 + OpMemberDecorate %type_View 10 ColMajor + OpMemberDecorate %type_View 11 Offset 704 + OpMemberDecorate %type_View 11 MatrixStride 16 + OpMemberDecorate %type_View 11 ColMajor + OpMemberDecorate %type_View 12 Offset 768 + OpMemberDecorate %type_View 12 MatrixStride 16 + OpMemberDecorate %type_View 12 ColMajor + OpMemberDecorate %type_View 13 Offset 832 + OpMemberDecorate %type_View 14 Offset 844 + OpMemberDecorate %type_View 15 Offset 848 + OpMemberDecorate %type_View 16 Offset 860 + OpMemberDecorate %type_View 17 Offset 864 + OpMemberDecorate %type_View 18 Offset 876 + OpMemberDecorate %type_View 19 Offset 880 + OpMemberDecorate %type_View 20 Offset 892 + OpMemberDecorate %type_View 21 Offset 896 + OpMemberDecorate %type_View 22 Offset 908 + OpMemberDecorate %type_View 23 Offset 912 + OpMemberDecorate %type_View 24 Offset 928 + OpMemberDecorate %type_View 25 Offset 944 + OpMemberDecorate %type_View 26 Offset 956 + OpMemberDecorate %type_View 27 Offset 960 + OpMemberDecorate %type_View 28 Offset 972 + OpMemberDecorate %type_View 29 Offset 976 + OpMemberDecorate %type_View 30 Offset 988 + OpMemberDecorate %type_View 31 Offset 992 + OpMemberDecorate %type_View 32 Offset 1004 + OpMemberDecorate %type_View 33 Offset 1008 + OpMemberDecorate %type_View 33 MatrixStride 16 + OpMemberDecorate %type_View 33 ColMajor + OpMemberDecorate %type_View 34 Offset 1072 + OpMemberDecorate %type_View 34 MatrixStride 16 + OpMemberDecorate %type_View 34 ColMajor + OpMemberDecorate %type_View 35 Offset 1136 + OpMemberDecorate %type_View 35 MatrixStride 16 + OpMemberDecorate %type_View 35 ColMajor + OpMemberDecorate %type_View 36 Offset 1200 + OpMemberDecorate %type_View 36 MatrixStride 16 + OpMemberDecorate %type_View 36 ColMajor + OpMemberDecorate %type_View 37 Offset 1264 + OpMemberDecorate %type_View 37 MatrixStride 16 + OpMemberDecorate %type_View 37 ColMajor + OpMemberDecorate %type_View 38 Offset 1328 + OpMemberDecorate %type_View 38 MatrixStride 16 + OpMemberDecorate %type_View 38 ColMajor + OpMemberDecorate %type_View 39 Offset 1392 + OpMemberDecorate %type_View 39 MatrixStride 16 + OpMemberDecorate %type_View 39 ColMajor + OpMemberDecorate %type_View 40 Offset 1456 + OpMemberDecorate %type_View 40 MatrixStride 16 + OpMemberDecorate %type_View 40 ColMajor + OpMemberDecorate %type_View 41 Offset 1520 + OpMemberDecorate %type_View 41 MatrixStride 16 + OpMemberDecorate %type_View 41 ColMajor + OpMemberDecorate %type_View 42 Offset 1584 + OpMemberDecorate %type_View 42 MatrixStride 16 + OpMemberDecorate %type_View 42 ColMajor + OpMemberDecorate %type_View 43 Offset 1648 + OpMemberDecorate %type_View 44 Offset 1660 + OpMemberDecorate %type_View 45 Offset 1664 + OpMemberDecorate %type_View 46 Offset 1676 + OpMemberDecorate %type_View 47 Offset 1680 + OpMemberDecorate %type_View 48 Offset 1692 + OpMemberDecorate %type_View 49 Offset 1696 + OpMemberDecorate %type_View 49 MatrixStride 16 + OpMemberDecorate %type_View 49 ColMajor + OpMemberDecorate %type_View 50 Offset 1760 + OpMemberDecorate %type_View 50 MatrixStride 16 + OpMemberDecorate %type_View 50 ColMajor + OpMemberDecorate %type_View 51 Offset 1824 + OpMemberDecorate %type_View 51 MatrixStride 16 + OpMemberDecorate %type_View 51 ColMajor + OpMemberDecorate %type_View 52 Offset 1888 + OpMemberDecorate %type_View 53 Offset 1904 + OpMemberDecorate %type_View 54 Offset 1920 + OpMemberDecorate %type_View 55 Offset 1928 + OpMemberDecorate %type_View 56 Offset 1936 + OpMemberDecorate %type_View 57 Offset 1952 + OpMemberDecorate %type_View 58 Offset 1968 + OpMemberDecorate %type_View 59 Offset 1984 + OpMemberDecorate %type_View 60 Offset 2000 + OpMemberDecorate %type_View 61 Offset 2004 + OpMemberDecorate %type_View 62 Offset 2008 + OpMemberDecorate %type_View 63 Offset 2012 + OpMemberDecorate %type_View 64 Offset 2016 + OpMemberDecorate %type_View 65 Offset 2032 + OpMemberDecorate %type_View 66 Offset 2048 + OpMemberDecorate %type_View 67 Offset 2064 + OpMemberDecorate %type_View 68 Offset 2072 + OpMemberDecorate %type_View 69 Offset 2076 + OpMemberDecorate %type_View 70 Offset 2080 + OpMemberDecorate %type_View 71 Offset 2084 + OpMemberDecorate %type_View 72 Offset 2088 + OpMemberDecorate %type_View 73 Offset 2092 + OpMemberDecorate %type_View 74 Offset 2096 + OpMemberDecorate %type_View 75 Offset 2108 + OpMemberDecorate %type_View 76 Offset 2112 + OpMemberDecorate %type_View 77 Offset 2116 + OpMemberDecorate %type_View 78 Offset 2120 + OpMemberDecorate %type_View 79 Offset 2124 + OpMemberDecorate %type_View 80 Offset 2128 + OpMemberDecorate %type_View 81 Offset 2132 + OpMemberDecorate %type_View 82 Offset 2136 + OpMemberDecorate %type_View 83 Offset 2140 + OpMemberDecorate %type_View 84 Offset 2144 + OpMemberDecorate %type_View 85 Offset 2148 + OpMemberDecorate %type_View 86 Offset 2152 + OpMemberDecorate %type_View 87 Offset 2156 + OpMemberDecorate %type_View 88 Offset 2160 + OpMemberDecorate %type_View 89 Offset 2164 + OpMemberDecorate %type_View 90 Offset 2168 + OpMemberDecorate %type_View 91 Offset 2172 + OpMemberDecorate %type_View 92 Offset 2176 + OpMemberDecorate %type_View 93 Offset 2192 + OpMemberDecorate %type_View 94 Offset 2204 + OpMemberDecorate %type_View 95 Offset 2208 + OpMemberDecorate %type_View 96 Offset 2240 + OpMemberDecorate %type_View 97 Offset 2272 + OpMemberDecorate %type_View 98 Offset 2288 + OpMemberDecorate %type_View 99 Offset 2304 + OpMemberDecorate %type_View 100 Offset 2308 + OpMemberDecorate %type_View 101 Offset 2312 + OpMemberDecorate %type_View 102 Offset 2316 + OpMemberDecorate %type_View 103 Offset 2320 + OpMemberDecorate %type_View 104 Offset 2324 + OpMemberDecorate %type_View 105 Offset 2328 + OpMemberDecorate %type_View 106 Offset 2332 + OpMemberDecorate %type_View 107 Offset 2336 + OpMemberDecorate %type_View 108 Offset 2340 + OpMemberDecorate %type_View 109 Offset 2344 + OpMemberDecorate %type_View 110 Offset 2348 + OpMemberDecorate %type_View 111 Offset 2352 + OpMemberDecorate %type_View 112 Offset 2364 + OpMemberDecorate %type_View 113 Offset 2368 + OpMemberDecorate %type_View 114 Offset 2380 + OpMemberDecorate %type_View 115 Offset 2384 + OpMemberDecorate %type_View 116 Offset 2388 + OpMemberDecorate %type_View 117 Offset 2392 + OpMemberDecorate %type_View 118 Offset 2396 + OpMemberDecorate %type_View 119 Offset 2400 + OpMemberDecorate %type_View 120 Offset 2404 + OpMemberDecorate %type_View 121 Offset 2408 + OpMemberDecorate %type_View 122 Offset 2412 + OpMemberDecorate %type_View 123 Offset 2416 + OpMemberDecorate %type_View 124 Offset 2420 + OpMemberDecorate %type_View 125 Offset 2424 + OpMemberDecorate %type_View 126 Offset 2428 + OpMemberDecorate %type_View 127 Offset 2432 + OpMemberDecorate %type_View 128 Offset 2448 + OpMemberDecorate %type_View 129 Offset 2460 + OpMemberDecorate %type_View 130 Offset 2464 + OpMemberDecorate %type_View 131 Offset 2480 + OpMemberDecorate %type_View 132 Offset 2484 + OpMemberDecorate %type_View 133 Offset 2488 + OpMemberDecorate %type_View 134 Offset 2492 + OpMemberDecorate %type_View 135 Offset 2496 + OpMemberDecorate %type_View 136 Offset 2512 + OpMemberDecorate %type_View 137 Offset 2624 + OpMemberDecorate %type_View 138 Offset 2628 + OpMemberDecorate %type_View 139 Offset 2632 + OpMemberDecorate %type_View 140 Offset 2636 + OpMemberDecorate %type_View 141 Offset 2640 + OpMemberDecorate %type_View 142 Offset 2644 + OpMemberDecorate %type_View 143 Offset 2648 + OpMemberDecorate %type_View 144 Offset 2652 + OpMemberDecorate %type_View 145 Offset 2656 + OpMemberDecorate %type_View 146 Offset 2668 + OpMemberDecorate %type_View 147 Offset 2672 + OpMemberDecorate %type_View 148 Offset 2736 + OpMemberDecorate %type_View 149 Offset 2800 + OpMemberDecorate %type_View 150 Offset 2804 + OpMemberDecorate %type_View 151 Offset 2808 + OpMemberDecorate %type_View 152 Offset 2812 + OpMemberDecorate %type_View 153 Offset 2816 + OpMemberDecorate %type_View 154 Offset 2828 + OpMemberDecorate %type_View 155 Offset 2832 + OpMemberDecorate %type_View 156 Offset 2844 + OpMemberDecorate %type_View 157 Offset 2848 + OpMemberDecorate %type_View 158 Offset 2856 + OpMemberDecorate %type_View 159 Offset 2860 + OpMemberDecorate %type_View 160 Offset 2864 + OpMemberDecorate %type_View 161 Offset 2876 + OpMemberDecorate %type_View 162 Offset 2880 + OpMemberDecorate %type_View 163 Offset 2892 + OpMemberDecorate %type_View 164 Offset 2896 + OpMemberDecorate %type_View 165 Offset 2908 + OpMemberDecorate %type_View 166 Offset 2912 + OpMemberDecorate %type_View 167 Offset 2924 + OpMemberDecorate %type_View 168 Offset 2928 + OpMemberDecorate %type_View 169 Offset 2932 + OpDecorate %type_View Block + OpMemberDecorate %type_Primitive 0 Offset 0 + OpMemberDecorate %type_Primitive 0 MatrixStride 16 + OpMemberDecorate %type_Primitive 0 ColMajor + OpMemberDecorate %type_Primitive 1 Offset 64 + OpMemberDecorate %type_Primitive 2 Offset 80 + OpMemberDecorate %type_Primitive 3 Offset 96 + OpMemberDecorate %type_Primitive 3 MatrixStride 16 + OpMemberDecorate %type_Primitive 3 ColMajor + OpMemberDecorate %type_Primitive 4 Offset 160 + OpMemberDecorate %type_Primitive 4 MatrixStride 16 + OpMemberDecorate %type_Primitive 4 ColMajor + OpMemberDecorate %type_Primitive 5 Offset 224 + OpMemberDecorate %type_Primitive 5 MatrixStride 16 + OpMemberDecorate %type_Primitive 5 ColMajor + OpMemberDecorate %type_Primitive 6 Offset 288 + OpMemberDecorate %type_Primitive 7 Offset 300 + OpMemberDecorate %type_Primitive 8 Offset 304 + OpMemberDecorate %type_Primitive 9 Offset 316 + OpMemberDecorate %type_Primitive 10 Offset 320 + OpMemberDecorate %type_Primitive 11 Offset 324 + OpMemberDecorate %type_Primitive 12 Offset 328 + OpMemberDecorate %type_Primitive 13 Offset 332 + OpMemberDecorate %type_Primitive 14 Offset 336 + OpMemberDecorate %type_Primitive 15 Offset 352 + OpMemberDecorate %type_Primitive 16 Offset 368 + OpMemberDecorate %type_Primitive 17 Offset 380 + OpMemberDecorate %type_Primitive 18 Offset 384 + OpMemberDecorate %type_Primitive 19 Offset 396 + OpMemberDecorate %type_Primitive 20 Offset 400 + OpMemberDecorate %type_Primitive 21 Offset 404 + OpDecorate %type_Primitive Block + OpDecorate %_arr_mat4v4float_uint_6 ArrayStride 64 + OpMemberDecorate %type_MobileShadowDepthPass 0 Offset 0 + OpMemberDecorate %type_MobileShadowDepthPass 1 Offset 4 + OpMemberDecorate %type_MobileShadowDepthPass 2 Offset 8 + OpMemberDecorate %type_MobileShadowDepthPass 3 Offset 12 + OpMemberDecorate %type_MobileShadowDepthPass 4 Offset 16 + OpMemberDecorate %type_MobileShadowDepthPass 5 Offset 20 + OpMemberDecorate %type_MobileShadowDepthPass 6 Offset 24 + OpMemberDecorate %type_MobileShadowDepthPass 7 Offset 28 + OpMemberDecorate %type_MobileShadowDepthPass 8 Offset 32 + OpMemberDecorate %type_MobileShadowDepthPass 9 Offset 36 + OpMemberDecorate %type_MobileShadowDepthPass 10 Offset 40 + OpMemberDecorate %type_MobileShadowDepthPass 11 Offset 44 + OpMemberDecorate %type_MobileShadowDepthPass 12 Offset 48 + OpMemberDecorate %type_MobileShadowDepthPass 13 Offset 52 + OpMemberDecorate %type_MobileShadowDepthPass 14 Offset 56 + OpMemberDecorate %type_MobileShadowDepthPass 15 Offset 60 + OpMemberDecorate %type_MobileShadowDepthPass 16 Offset 64 + OpMemberDecorate %type_MobileShadowDepthPass 17 Offset 68 + OpMemberDecorate %type_MobileShadowDepthPass 18 Offset 72 + OpMemberDecorate %type_MobileShadowDepthPass 19 Offset 76 + OpMemberDecorate %type_MobileShadowDepthPass 20 Offset 80 + OpMemberDecorate %type_MobileShadowDepthPass 20 MatrixStride 16 + OpMemberDecorate %type_MobileShadowDepthPass 20 ColMajor + OpMemberDecorate %type_MobileShadowDepthPass 21 Offset 144 + OpMemberDecorate %type_MobileShadowDepthPass 22 Offset 152 + OpMemberDecorate %type_MobileShadowDepthPass 23 Offset 156 + OpMemberDecorate %type_MobileShadowDepthPass 24 Offset 160 + OpMemberDecorate %type_MobileShadowDepthPass 24 MatrixStride 16 + OpMemberDecorate %type_MobileShadowDepthPass 24 ColMajor + OpDecorate %type_MobileShadowDepthPass Block + OpMemberDecorate %type_EmitterDynamicUniforms 0 Offset 0 + OpMemberDecorate %type_EmitterDynamicUniforms 1 Offset 8 + OpMemberDecorate %type_EmitterDynamicUniforms 2 Offset 12 + OpMemberDecorate %type_EmitterDynamicUniforms 3 Offset 16 + OpMemberDecorate %type_EmitterDynamicUniforms 4 Offset 32 + OpMemberDecorate %type_EmitterDynamicUniforms 5 Offset 48 + OpMemberDecorate %type_EmitterDynamicUniforms 6 Offset 64 + OpDecorate %type_EmitterDynamicUniforms Block + OpMemberDecorate %type_EmitterUniforms 0 Offset 0 + OpMemberDecorate %type_EmitterUniforms 1 Offset 16 + OpMemberDecorate %type_EmitterUniforms 2 Offset 32 + OpMemberDecorate %type_EmitterUniforms 3 Offset 48 + OpMemberDecorate %type_EmitterUniforms 4 Offset 64 + OpMemberDecorate %type_EmitterUniforms 5 Offset 80 + OpMemberDecorate %type_EmitterUniforms 6 Offset 96 + OpMemberDecorate %type_EmitterUniforms 7 Offset 112 + OpMemberDecorate %type_EmitterUniforms 8 Offset 128 + OpMemberDecorate %type_EmitterUniforms 9 Offset 144 + OpMemberDecorate %type_EmitterUniforms 10 Offset 156 + OpMemberDecorate %type_EmitterUniforms 11 Offset 160 + OpMemberDecorate %type_EmitterUniforms 12 Offset 164 + OpMemberDecorate %type_EmitterUniforms 13 Offset 168 + OpMemberDecorate %type_EmitterUniforms 14 Offset 172 + OpMemberDecorate %type_EmitterUniforms 15 Offset 176 + OpDecorate %type_EmitterUniforms Block + OpMemberDecorate %type__Globals 0 Offset 0 + OpDecorate %type__Globals Block + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 +%mat4v4float = OpTypeMatrix %v4float 4 + %v3float = OpTypeVector %float 3 + %v2float = OpTypeVector %float 2 + %int = OpTypeInt 32 1 + %uint = OpTypeInt 32 0 + %uint_2 = OpConstant %uint 2 + %uint_7 = OpConstant %uint 7 + %uint_4 = OpConstant %uint 4 + %float_0 = OpConstant %float 0 + %int_0 = OpConstant %int 0 + %int_1 = OpConstant %int 1 + %uint_16 = OpConstant %uint 16 + %int_3 = OpConstant %int 3 + %float_1 = OpConstant %float 1 +%float_9_99999975en05 = OpConstant %float 9.99999975e-05 + %54 = OpConstantComposite %v3float %float_0 %float_0 %float_9_99999975en05 + %int_2 = OpConstant %int 2 + %int_5 = OpConstant %int 5 + %int_4 = OpConstant %int 4 + %float_0_5 = OpConstant %float 0.5 + %float_n0_5 = OpConstant %float -0.5 + %float_2 = OpConstant %float 2 + %61 = OpConstantComposite %v2float %float_2 %float_2 + %int_6 = OpConstant %int 6 + %63 = OpConstantComposite %v2float %float_1 %float_1 + %int_11 = OpConstant %int 11 + %int_15 = OpConstant %int 15 + %int_8 = OpConstant %int 8 + %int_9 = OpConstant %int 9 + %int_10 = OpConstant %int 10 + %int_12 = OpConstant %int 12 + %uint_0 = OpConstant %uint 0 + %uint_1 = OpConstant %uint 1 +%mat3v3float = OpTypeMatrix %v3float 3 + %int_20 = OpConstant %int 20 + %int_22 = OpConstant %int 22 +%float_9_99999997en07 = OpConstant %float 9.99999997e-07 + %int_21 = OpConstant %int 21 + %int_17 = OpConstant %int 17 + %int_19 = OpConstant %int 19 + %int_27 = OpConstant %int 27 + %int_31 = OpConstant %int 31 + %uint_3 = OpConstant %uint 3 + %82 = OpConstantComposite %v3float %float_0 %float_0 %float_1 +%float_0_00999999978 = OpConstant %float 0.00999999978 +%_arr_v4float_uint_2 = OpTypeArray %v4float %uint_2 +%_arr_v4float_uint_7 = OpTypeArray %v4float %uint_7 +%_arr_v4float_uint_4 = OpTypeArray %v4float %uint_4 + %type_View = OpTypeStruct %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %v3float %float %v3float %float %v3float %float %v3float %float %v3float %float %v4float %v4float %v3float %float %v3float %float %v3float %float %v3float %float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %mat4v4float %v3float %float %v3float %float %v3float %float %mat4v4float %mat4v4float %mat4v4float %v4float %v4float %v2float %v2float %v4float %v4float %v4float %v4float %int %float %float %float %v4float %v4float %v4float %v2float %float %float %float %float %float %float %v3float %float %float %float %float %float %float %float %float %uint %uint %uint %uint %float %float %float %float %float %v4float %v3float %float %_arr_v4float_uint_2 %_arr_v4float_uint_2 %v4float %v4float %float %float %float %float %float %float %float %float %float %float %float %float %v3float %float %v3float %float %float %float %float %float %float %float %float %float %float %float %uint %uint %v4float %v3float %float %v4float %float %float %float %float %v4float %_arr_v4float_uint_7 %float %float %float %float %uint %float %float %float %v3float %int %_arr_v4float_uint_4 %_arr_v4float_uint_4 %float %float %float %float %v3float %float %v3float %float %v2float %float %float %v3float %float %v3float %float %v3float %float %v3float %float %float %float +%_ptr_Uniform_type_View = OpTypePointer Uniform %type_View +%type_Primitive = OpTypeStruct %mat4v4float %v4float %v4float %mat4v4float %mat4v4float %mat4v4float %v3float %float %v3float %float %float %float %float %float %v4float %v4float %v3float %float %v3float %uint %uint %int +%_ptr_Uniform_type_Primitive = OpTypePointer Uniform %type_Primitive + %uint_6 = OpConstant %uint 6 +%_arr_mat4v4float_uint_6 = OpTypeArray %mat4v4float %uint_6 +%type_MobileShadowDepthPass = OpTypeStruct %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %float %mat4v4float %v2float %float %float %_arr_mat4v4float_uint_6 +%_ptr_Uniform_type_MobileShadowDepthPass = OpTypePointer Uniform %type_MobileShadowDepthPass +%type_EmitterDynamicUniforms = OpTypeStruct %v2float %float %float %v4float %v4float %v4float %v4float +%_ptr_Uniform_type_EmitterDynamicUniforms = OpTypePointer Uniform %type_EmitterDynamicUniforms +%type_EmitterUniforms = OpTypeStruct %v4float %v4float %v4float %v4float %v4float %v4float %v4float %v4float %v4float %v3float %float %float %float %float %float %v2float +%_ptr_Uniform_type_EmitterUniforms = OpTypePointer Uniform %type_EmitterUniforms +%type_buffer_image = OpTypeImage %float Buffer 2 0 0 1 Rg32f +%_ptr_UniformConstant_type_buffer_image = OpTypePointer UniformConstant %type_buffer_image +%type__Globals = OpTypeStruct %uint +%_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals +%type_2d_image = OpTypeImage %float 2D 2 0 0 1 Unknown +%_ptr_UniformConstant_type_2d_image = OpTypePointer UniformConstant %type_2d_image +%type_sampler = OpTypeSampler +%_ptr_UniformConstant_type_sampler = OpTypePointer UniformConstant %type_sampler +%_ptr_Input_uint = OpTypePointer Input %uint +%_ptr_Input_v2float = OpTypePointer Input %v2float +%_ptr_Output_float = OpTypePointer Output %float +%_ptr_Output_v4float = OpTypePointer Output %v4float + %void = OpTypeVoid + %99 = OpTypeFunction %void +%_ptr_Uniform_uint = OpTypePointer Uniform %uint +%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float + %bool = OpTypeBool +%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float +%_ptr_Uniform_float = OpTypePointer Uniform %float +%_ptr_Uniform_mat4v4float = OpTypePointer Uniform %mat4v4float +%_ptr_Uniform_v3float = OpTypePointer Uniform %v3float +%type_sampled_image = OpTypeSampledImage %type_2d_image + %View = OpVariable %_ptr_Uniform_type_View Uniform + %Primitive = OpVariable %_ptr_Uniform_type_Primitive Uniform +%MobileShadowDepthPass = OpVariable %_ptr_Uniform_type_MobileShadowDepthPass Uniform +%EmitterDynamicUniforms = OpVariable %_ptr_Uniform_type_EmitterDynamicUniforms Uniform +%EmitterUniforms = OpVariable %_ptr_Uniform_type_EmitterUniforms Uniform +%ParticleIndices = OpVariable %_ptr_UniformConstant_type_buffer_image UniformConstant + %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform +%PositionTexture = OpVariable %_ptr_UniformConstant_type_2d_image UniformConstant +%PositionTextureSampler = OpVariable %_ptr_UniformConstant_type_sampler UniformConstant +%VelocityTexture = OpVariable %_ptr_UniformConstant_type_2d_image UniformConstant +%VelocityTextureSampler = OpVariable %_ptr_UniformConstant_type_sampler UniformConstant +%AttributesTexture = OpVariable %_ptr_UniformConstant_type_2d_image UniformConstant +%AttributesTextureSampler = OpVariable %_ptr_UniformConstant_type_sampler UniformConstant +%CurveTexture = OpVariable %_ptr_UniformConstant_type_2d_image UniformConstant +%CurveTextureSampler = OpVariable %_ptr_UniformConstant_type_sampler UniformConstant +%gl_VertexIndex = OpVariable %_ptr_Input_uint Input +%gl_InstanceIndex = OpVariable %_ptr_Input_uint Input +%in_var_ATTRIBUTE0 = OpVariable %_ptr_Input_v2float Input +%out_var_TEXCOORD6 = OpVariable %_ptr_Output_float Output +%gl_Position = OpVariable %_ptr_Output_v4float Output +%float_6_28318548 = OpConstant %float 6.28318548 + %108 = OpConstantNull %v3float + %Main = OpFunction %void None %99 + %109 = OpLabel + %110 = OpLoad %uint %gl_VertexIndex + %111 = OpLoad %uint %gl_InstanceIndex + %112 = OpLoad %v2float %in_var_ATTRIBUTE0 + %113 = OpAccessChain %_ptr_Uniform_v3float %View %int_15 + %114 = OpLoad %v3float %113 + %115 = OpAccessChain %_ptr_Uniform_v3float %View %int_17 + %116 = OpLoad %v3float %115 + %117 = OpAccessChain %_ptr_Uniform_v3float %View %int_19 + %118 = OpLoad %v3float %117 + %119 = OpAccessChain %_ptr_Uniform_v3float %View %int_21 + %120 = OpLoad %v3float %119 + %121 = OpAccessChain %_ptr_Uniform_v3float %View %int_27 + %122 = OpLoad %v3float %121 + %123 = OpAccessChain %_ptr_Uniform_v3float %View %int_31 + %124 = OpLoad %v3float %123 + %125 = OpIMul %uint %111 %uint_16 + %126 = OpUDiv %uint %110 %uint_4 + %127 = OpIAdd %uint %125 %126 + %128 = OpAccessChain %_ptr_Uniform_uint %_Globals %int_0 + %129 = OpLoad %uint %128 + %130 = OpIAdd %uint %129 %127 + %131 = OpLoad %type_buffer_image %ParticleIndices + %132 = OpImageFetch %v4float %131 %130 None + %133 = OpVectorShuffle %v2float %132 %132 0 1 + %134 = OpLoad %type_2d_image %PositionTexture + %135 = OpLoad %type_sampler %PositionTextureSampler + %136 = OpSampledImage %type_sampled_image %134 %135 + %137 = OpImageSampleExplicitLod %v4float %136 %133 Lod %float_0 + %138 = OpLoad %type_2d_image %VelocityTexture + %139 = OpLoad %type_sampler %VelocityTextureSampler + %140 = OpSampledImage %type_sampled_image %138 %139 + %141 = OpImageSampleExplicitLod %v4float %140 %133 Lod %float_0 + %142 = OpLoad %type_2d_image %AttributesTexture + %143 = OpLoad %type_sampler %AttributesTextureSampler + %144 = OpSampledImage %type_sampled_image %142 %143 + %145 = OpImageSampleExplicitLod %v4float %144 %133 Lod %float_0 + %146 = OpCompositeExtract %float %137 3 + %147 = OpExtInst %float %1 Step %146 %float_1 + %148 = OpVectorShuffle %v3float %141 %141 0 1 2 + %149 = OpAccessChain %_ptr_Uniform_mat4v4float %Primitive %int_0 + %150 = OpLoad %mat4v4float %149 + %151 = OpCompositeExtract %v4float %150 0 + %152 = OpVectorShuffle %v3float %151 %151 0 1 2 + %153 = OpCompositeExtract %v4float %150 1 + %154 = OpVectorShuffle %v3float %153 %153 0 1 2 + %155 = OpCompositeExtract %v4float %150 2 + %156 = OpVectorShuffle %v3float %155 %155 0 1 2 + %157 = OpCompositeConstruct %mat3v3float %152 %154 %156 + %158 = OpMatrixTimesVector %v3float %157 %148 + %159 = OpFAdd %v3float %158 %54 + %160 = OpExtInst %v3float %1 Normalize %159 + %161 = OpExtInst %float %1 Length %158 + %162 = OpAccessChain %_ptr_Uniform_v4float %EmitterUniforms %int_3 + %163 = OpLoad %v4float %162 + %164 = OpVectorShuffle %v2float %163 %163 0 1 + %165 = OpVectorShuffle %v2float %163 %163 2 3 + %166 = OpCompositeConstruct %v2float %146 %146 + %167 = OpFMul %v2float %165 %166 + %168 = OpFAdd %v2float %164 %167 + %169 = OpLoad %type_2d_image %CurveTexture + %170 = OpLoad %type_sampler %CurveTextureSampler + %171 = OpSampledImage %type_sampled_image %169 %170 + %172 = OpImageSampleExplicitLod %v4float %171 %168 Lod %float_0 + %173 = OpAccessChain %_ptr_Uniform_v4float %EmitterUniforms %int_4 + %174 = OpLoad %v4float %173 + %175 = OpFMul %v4float %172 %174 + %176 = OpAccessChain %_ptr_Uniform_v4float %EmitterUniforms %int_5 + %177 = OpLoad %v4float %176 + %178 = OpFAdd %v4float %175 %177 + %179 = OpCompositeExtract %float %145 0 + %180 = OpFOrdLessThan %bool %179 %float_0_5 + %181 = OpSelect %float %180 %float_0 %float_n0_5 + %182 = OpCompositeExtract %float %145 1 + %183 = OpFOrdLessThan %bool %182 %float_0_5 + %184 = OpSelect %float %183 %float_0 %float_n0_5 + %185 = OpCompositeConstruct %v2float %181 %184 + %186 = OpVectorShuffle %v2float %145 %145 0 1 + %187 = OpFAdd %v2float %186 %185 + %188 = OpFMul %v2float %187 %61 + %189 = OpVectorShuffle %v2float %178 %178 0 1 + %190 = OpAccessChain %_ptr_Uniform_v2float %EmitterDynamicUniforms %int_0 + %191 = OpLoad %v2float %190 + %192 = OpFMul %v2float %189 %191 + %193 = OpAccessChain %_ptr_Uniform_v4float %EmitterUniforms %int_6 + %194 = OpLoad %v4float %193 + %195 = OpVectorShuffle %v2float %194 %194 0 1 + %196 = OpCompositeConstruct %v2float %161 %161 + %197 = OpFMul %v2float %195 %196 + %198 = OpExtInst %v2float %1 FMax %197 %63 + %199 = OpVectorShuffle %v2float %194 %194 2 3 + %200 = OpExtInst %v2float %1 FMin %198 %199 + %201 = OpFMul %v2float %188 %192 + %202 = OpFMul %v2float %201 %200 + %203 = OpCompositeConstruct %v2float %147 %147 + %204 = OpFMul %v2float %202 %203 + %205 = OpCompositeExtract %float %145 3 + %206 = OpAccessChain %_ptr_Uniform_float %EmitterUniforms %int_11 + %207 = OpLoad %float %206 + %208 = OpFMul %float %205 %207 + %209 = OpCompositeExtract %float %145 2 + %210 = OpFMul %float %208 %146 + %211 = OpFAdd %float %209 %210 + %212 = OpFMul %float %211 %float_6_28318548 + %213 = OpAccessChain %_ptr_Uniform_v4float %Primitive %int_0 %uint_0 + %214 = OpLoad %v4float %213 + %215 = OpVectorShuffle %v3float %214 %214 0 1 2 + %216 = OpVectorShuffle %v3float %137 %108 0 0 0 + %217 = OpFMul %v3float %215 %216 + %218 = OpAccessChain %_ptr_Uniform_v4float %Primitive %int_0 %uint_1 + %219 = OpLoad %v4float %218 + %220 = OpVectorShuffle %v3float %219 %219 0 1 2 + %221 = OpVectorShuffle %v3float %137 %108 1 1 1 + %222 = OpFMul %v3float %220 %221 + %223 = OpFAdd %v3float %217 %222 + %224 = OpAccessChain %_ptr_Uniform_v4float %Primitive %int_0 %uint_2 + %225 = OpLoad %v4float %224 + %226 = OpVectorShuffle %v3float %225 %225 0 1 2 + %227 = OpVectorShuffle %v3float %137 %108 2 2 2 + %228 = OpFMul %v3float %226 %227 + %229 = OpFAdd %v3float %223 %228 + %230 = OpAccessChain %_ptr_Uniform_v4float %Primitive %int_0 %uint_3 + %231 = OpLoad %v4float %230 + %232 = OpVectorShuffle %v3float %231 %231 0 1 2 + %233 = OpFAdd %v3float %232 %124 + %234 = OpFAdd %v3float %229 %233 + %235 = OpCompositeExtract %float %234 0 + %236 = OpCompositeExtract %float %234 1 + %237 = OpCompositeExtract %float %234 2 + %238 = OpCompositeConstruct %v4float %235 %236 %237 %float_1 + %239 = OpVectorShuffle %v3float %238 %238 0 1 2 + %240 = OpAccessChain %_ptr_Uniform_float %EmitterUniforms %int_10 + %241 = OpLoad %float %240 + %242 = OpCompositeConstruct %v3float %241 %241 %241 + %243 = OpExtInst %v3float %1 FMix %116 %120 %242 + %244 = OpExtInst %v3float %1 FMix %114 %118 %242 + %245 = OpAccessChain %_ptr_Uniform_v4float %EmitterDynamicUniforms %int_3 + %246 = OpLoad %v4float %245 + %247 = OpVectorShuffle %v3float %246 %246 0 1 2 + %248 = OpAccessChain %_ptr_Uniform_float %EmitterDynamicUniforms %int_3 %int_3 + %249 = OpLoad %float %248 + %250 = OpCompositeConstruct %v3float %249 %249 %249 + %251 = OpExtInst %v3float %1 FMix %243 %247 %250 + %252 = OpFNegate %v3float %244 + %253 = OpAccessChain %_ptr_Uniform_v4float %EmitterDynamicUniforms %int_4 + %254 = OpLoad %v4float %253 + %255 = OpVectorShuffle %v3float %254 %254 0 1 2 + %256 = OpAccessChain %_ptr_Uniform_float %EmitterDynamicUniforms %int_4 %int_3 + %257 = OpLoad %float %256 + %258 = OpCompositeConstruct %v3float %257 %257 %257 + %259 = OpExtInst %v3float %1 FMix %252 %255 %258 + %260 = OpFSub %v3float %122 %239 + %261 = OpDot %float %260 %260 + %262 = OpExtInst %float %1 FMax %261 %float_0_00999999978 + %263 = OpExtInst %float %1 Sqrt %262 + %264 = OpCompositeConstruct %v3float %263 %263 %263 + %265 = OpFDiv %v3float %260 %264 + %266 = OpAccessChain %_ptr_Uniform_float %EmitterUniforms %int_9 %int_0 + %267 = OpLoad %float %266 + %268 = OpFOrdGreaterThan %bool %267 %float_0 + OpSelectionMerge %269 DontFlatten + OpBranchConditional %268 %270 %271 + %270 = OpLabel + %272 = OpAccessChain %_ptr_Uniform_float %EmitterUniforms %int_9 %int_1 + %273 = OpLoad %float %272 + %274 = OpFMul %float %261 %273 + %275 = OpAccessChain %_ptr_Uniform_float %EmitterUniforms %int_9 %int_2 + %276 = OpLoad %float %275 + %277 = OpFSub %float %274 %276 + %278 = OpExtInst %float %1 FClamp %277 %float_0 %float_1 + %279 = OpExtInst %v3float %1 Cross %265 %82 + %280 = OpDot %float %279 %279 + %281 = OpExtInst %float %1 FMax %280 %float_0_00999999978 + %282 = OpExtInst %float %1 Sqrt %281 + %283 = OpCompositeConstruct %v3float %282 %282 %282 + %284 = OpFDiv %v3float %279 %283 + %285 = OpExtInst %v3float %1 Cross %265 %284 + %286 = OpCompositeConstruct %v3float %278 %278 %278 + %287 = OpExtInst %v3float %1 FMix %251 %284 %286 + %288 = OpExtInst %v3float %1 Normalize %287 + %289 = OpExtInst %v3float %1 FMix %259 %285 %286 + %290 = OpExtInst %v3float %1 Normalize %289 + OpBranch %269 + %271 = OpLabel + %291 = OpAccessChain %_ptr_Uniform_float %EmitterUniforms %int_8 %int_1 + %292 = OpLoad %float %291 + %293 = OpFOrdGreaterThan %bool %292 %float_0 + OpSelectionMerge %294 Flatten + OpBranchConditional %293 %295 %296 + %295 = OpLabel + %297 = OpExtInst %v3float %1 Cross %265 %160 + %298 = OpDot %float %297 %297 + %299 = OpExtInst %float %1 FMax %298 %float_0_00999999978 + %300 = OpExtInst %float %1 Sqrt %299 + %301 = OpCompositeConstruct %v3float %300 %300 %300 + %302 = OpFDiv %v3float %297 %301 + %303 = OpFNegate %v3float %160 + OpBranch %294 + %296 = OpLabel + %304 = OpAccessChain %_ptr_Uniform_float %EmitterUniforms %int_8 %int_2 + %305 = OpLoad %float %304 + %306 = OpFOrdGreaterThan %bool %305 %float_0 + OpSelectionMerge %307 None + OpBranchConditional %306 %308 %309 + %308 = OpLabel + %310 = OpExtInst %v3float %1 Cross %247 %265 + %311 = OpDot %float %310 %310 + %312 = OpExtInst %float %1 FMax %311 %float_0_00999999978 + %313 = OpExtInst %float %1 Sqrt %312 + %314 = OpCompositeConstruct %v3float %313 %313 %313 + %315 = OpFDiv %v3float %310 %314 + %316 = OpFNegate %v3float %315 + OpBranch %307 + %309 = OpLabel + %317 = OpAccessChain %_ptr_Uniform_float %EmitterUniforms %int_8 %int_3 + %318 = OpLoad %float %317 + %319 = OpFOrdGreaterThan %bool %318 %float_0 + OpSelectionMerge %320 None + OpBranchConditional %319 %321 %320 + %321 = OpLabel + %322 = OpExtInst %v3float %1 Cross %265 %82 + %323 = OpDot %float %322 %322 + %324 = OpExtInst %float %1 FMax %323 %float_0_00999999978 + %325 = OpExtInst %float %1 Sqrt %324 + %326 = OpCompositeConstruct %v3float %325 %325 %325 + %327 = OpFDiv %v3float %322 %326 + %328 = OpExtInst %v3float %1 Cross %265 %327 + OpBranch %320 + %320 = OpLabel + %329 = OpPhi %v3float %251 %309 %327 %321 + %330 = OpPhi %v3float %259 %309 %328 %321 + OpBranch %307 + %307 = OpLabel + %331 = OpPhi %v3float %247 %308 %329 %320 + %332 = OpPhi %v3float %316 %308 %330 %320 + OpBranch %294 + %294 = OpLabel + %333 = OpPhi %v3float %302 %295 %331 %307 + %334 = OpPhi %v3float %303 %295 %332 %307 + OpBranch %269 + %269 = OpLabel + %335 = OpPhi %v3float %288 %270 %333 %294 + %336 = OpPhi %v3float %290 %270 %334 %294 + %337 = OpAccessChain %_ptr_Uniform_float %EmitterUniforms %int_12 + %338 = OpLoad %float %337 + %339 = OpFAdd %float %212 %338 + %340 = OpExtInst %float %1 Sin %339 + %341 = OpExtInst %float %1 Cos %339 + %342 = OpCompositeConstruct %v3float %340 %340 %340 + %343 = OpFMul %v3float %342 %336 + %344 = OpCompositeConstruct %v3float %341 %341 %341 + %345 = OpFMul %v3float %344 %335 + %346 = OpFAdd %v3float %343 %345 + %347 = OpFMul %v3float %344 %336 + %348 = OpFMul %v3float %342 %335 + %349 = OpFSub %v3float %347 %348 + %350 = OpCompositeExtract %float %204 0 + %351 = OpCompositeExtract %float %112 0 + %352 = OpAccessChain %_ptr_Uniform_float %EmitterUniforms %int_15 %int_0 + %353 = OpLoad %float %352 + %354 = OpFAdd %float %351 %353 + %355 = OpFMul %float %350 %354 + %356 = OpCompositeConstruct %v3float %355 %355 %355 + %357 = OpFMul %v3float %356 %346 + %358 = OpCompositeExtract %float %204 1 + %359 = OpCompositeExtract %float %112 1 + %360 = OpAccessChain %_ptr_Uniform_float %EmitterUniforms %int_15 %int_1 + %361 = OpLoad %float %360 + %362 = OpFAdd %float %359 %361 + %363 = OpFMul %float %358 %362 + %364 = OpCompositeConstruct %v3float %363 %363 %363 + %365 = OpFMul %v3float %364 %349 + %366 = OpFAdd %v3float %357 %365 + %367 = OpFAdd %v3float %239 %366 + %368 = OpCompositeExtract %float %367 0 + %369 = OpCompositeExtract %float %367 1 + %370 = OpCompositeExtract %float %367 2 + %371 = OpCompositeConstruct %v4float %368 %369 %370 %float_1 + %372 = OpVectorShuffle %v4float %371 %371 4 5 6 3 + %373 = OpAccessChain %_ptr_Uniform_mat4v4float %MobileShadowDepthPass %int_20 + %374 = OpLoad %mat4v4float %373 + %375 = OpMatrixTimesVector %v4float %374 %372 + %376 = OpAccessChain %_ptr_Uniform_float %MobileShadowDepthPass %int_22 + %377 = OpLoad %float %376 + %378 = OpFOrdGreaterThan %bool %377 %float_0 + %379 = OpCompositeExtract %float %375 2 + %380 = OpFOrdLessThan %bool %379 %float_0 + %381 = OpLogicalAnd %bool %378 %380 + OpSelectionMerge %382 None + OpBranchConditional %381 %383 %382 + %383 = OpLabel + %384 = OpCompositeInsert %v4float %float_9_99999997en07 %375 2 + %385 = OpCompositeInsert %v4float %float_1 %384 3 + OpBranch %382 + %382 = OpLabel + %386 = OpPhi %v4float %375 %269 %385 %383 + %387 = OpAccessChain %_ptr_Uniform_float %MobileShadowDepthPass %int_21 %int_0 + %388 = OpLoad %float %387 + %389 = OpAccessChain %_ptr_Uniform_float %MobileShadowDepthPass %int_21 %int_1 + %390 = OpLoad %float %389 + %391 = OpCompositeExtract %float %386 2 + %392 = OpFMul %float %391 %390 + %393 = OpFAdd %float %392 %388 + %394 = OpCompositeExtract %float %386 3 + %395 = OpFMul %float %393 %394 + %396 = OpCompositeInsert %v4float %395 %386 2 + OpStore %out_var_TEXCOORD6 %float_0 + OpStore %gl_Position %396 + OpReturn + OpFunctionEnd diff --git a/third_party/spirv-cross/shaders/asm/comp/bitcast_icmp.asm.comp b/third_party/spirv-cross/shaders/asm/comp/bitcast_icmp.asm.comp new file mode 100644 index 0000000000..b7b4e0b2e1 --- /dev/null +++ b/third_party/spirv-cross/shaders/asm/comp/bitcast_icmp.asm.comp @@ -0,0 +1,101 @@ +; SPIR-V +; Version: 1.0 +; Generator: Khronos Glslang Reference Front End; 1 +; Bound: 30 +; Schema: 0 + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %func "main" + OpExecutionMode %func LocalSize 1 1 1 + OpSource ESSL 310 + OpSourceExtension "GL_GOOGLE_cpp_style_line_directive" + OpSourceExtension "GL_GOOGLE_include_directive" + OpMemberDecorate %input_struct 0 Offset 0 + OpMemberDecorate %input_struct 1 Offset 16 + OpMemberDecorate %output_struct 0 Offset 0 + OpMemberDecorate %output_struct 1 Offset 16 + OpDecorate %input_struct BufferBlock + OpDecorate %inputs DescriptorSet 0 + OpDecorate %inputs Binding 0 + OpDecorate %inputs Restrict + OpDecorate %output_struct BufferBlock + OpDecorate %outputs DescriptorSet 0 + OpDecorate %outputs Binding 1 + OpDecorate %outputs Restrict + + %void = OpTypeVoid + %main_func = OpTypeFunction %void + + %bool = OpTypeBool + %bvec4 = OpTypeVector %bool 4 + + %uint = OpTypeInt 32 0 + %uvec4 = OpTypeVector %uint 4 + + %int = OpTypeInt 32 1 + %ivec4 = OpTypeVector %int 4 + + %ivec4_ptr = OpTypePointer Uniform %ivec4 + %uvec4_ptr = OpTypePointer Uniform %uvec4 + + %zero = OpConstant %int 0 + %one = OpConstant %int 1 + %uzero = OpConstant %uint 0 + %uone = OpConstant %uint 1 + %utrue = OpConstantComposite %uvec4 %uone %uone %uone %uone + %ufalse = OpConstantComposite %uvec4 %uzero %uzero %uzero %uzero + + %input_struct = OpTypeStruct %ivec4 %uvec4 + %input_struct_ptr = OpTypePointer Uniform %input_struct + %inputs = OpVariable %input_struct_ptr Uniform + %output_struct = OpTypeStruct %uvec4 %ivec4 + %output_struct_ptr = OpTypePointer Uniform %output_struct + %outputs = OpVariable %output_struct_ptr Uniform + + %func = OpFunction %void None %main_func + %block = OpLabel + + %input1_ptr = OpAccessChain %ivec4_ptr %inputs %zero + %input0_ptr = OpAccessChain %uvec4_ptr %inputs %one + %input1 = OpLoad %ivec4 %input1_ptr + %input0 = OpLoad %uvec4 %input0_ptr + + %output_ptr_uvec4 = OpAccessChain %uvec4_ptr %outputs %zero + + %result_slt = OpSLessThan %bvec4 %input0 %input1 + %result_sle = OpSLessThanEqual %bvec4 %input0 %input1 + %result_ult = OpULessThan %bvec4 %input0 %input1 + %result_ule = OpULessThanEqual %bvec4 %input0 %input1 + %result_sgt = OpSGreaterThan %bvec4 %input0 %input1 + %result_sge = OpSGreaterThanEqual %bvec4 %input0 %input1 + %result_ugt = OpUGreaterThan %bvec4 %input0 %input1 + %result_uge = OpUGreaterThanEqual %bvec4 %input0 %input1 + + %int_slt = OpSelect %uvec4 %result_slt %utrue %ufalse + OpStore %output_ptr_uvec4 %int_slt + + %int_sle = OpSelect %uvec4 %result_sle %utrue %ufalse + OpStore %output_ptr_uvec4 %int_sle + + %int_ult = OpSelect %uvec4 %result_ult %utrue %ufalse + OpStore %output_ptr_uvec4 %int_ult + + %int_ule = OpSelect %uvec4 %result_ule %utrue %ufalse + OpStore %output_ptr_uvec4 %int_ule + + %int_sgt = OpSelect %uvec4 %result_sgt %utrue %ufalse + OpStore %output_ptr_uvec4 %int_sgt + + %int_sge = OpSelect %uvec4 %result_sge %utrue %ufalse + OpStore %output_ptr_uvec4 %int_sge + + %int_ugt = OpSelect %uvec4 %result_ugt %utrue %ufalse + OpStore %output_ptr_uvec4 %int_ugt + + %int_uge = OpSelect %uvec4 %result_uge %utrue %ufalse + OpStore %output_ptr_uvec4 %int_uge + + + OpReturn + OpFunctionEnd diff --git a/third_party/spirv-cross/shaders/asm/frag/image-fetch-no-sampler.no-samplerless.asm.vk.frag b/third_party/spirv-cross/shaders/asm/frag/image-fetch-no-sampler.no-samplerless.asm.vk.frag new file mode 100644 index 0000000000..a3d64c09d7 --- /dev/null +++ b/third_party/spirv-cross/shaders/asm/frag/image-fetch-no-sampler.no-samplerless.asm.vk.frag @@ -0,0 +1,163 @@ +; SPIR-V +; Version: 1.0 +; Generator: Khronos Glslang Reference Front End; 2 +; Bound: 113 +; Schema: 0 + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %xIn_1 %_entryPointOutput + OpExecutionMode %main OriginUpperLeft + OpSource HLSL 500 + OpName %main "main" + OpName %sample_fetch_t21_vi3_ "sample_fetch(t21;vi3;" + OpName %tex "tex" + OpName %UV "UV" + OpName %sample_sampler_t21_vf2_ "sample_sampler(t21;vf2;" + OpName %tex_0 "tex" + OpName %UV_0 "UV" + OpName %_main_vf4_ "@main(vf4;" + OpName %xIn "xIn" + OpName %Sampler "Sampler" + OpName %coord "coord" + OpName %value "value" + OpName %SampledImage "SampledImage" + OpName %param "param" + OpName %param_0 "param" + OpName %param_1 "param" + OpName %param_2 "param" + OpName %xIn_0 "xIn" + OpName %xIn_1 "xIn" + OpName %_entryPointOutput "@entryPointOutput" + OpName %param_3 "param" + OpDecorate %Sampler DescriptorSet 0 + OpDecorate %Sampler Binding 0 + OpDecorate %SampledImage DescriptorSet 0 + OpDecorate %SampledImage Binding 0 + OpDecorate %xIn_1 BuiltIn FragCoord + OpDecorate %_entryPointOutput Location 0 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %7 = OpTypeImage %float 2D 0 0 0 1 Unknown +%_ptr_Function_7 = OpTypePointer Function %7 + %int = OpTypeInt 32 1 + %v3int = OpTypeVector %int 3 +%_ptr_Function_v3int = OpTypePointer Function %v3int + %v4float = OpTypeVector %float 4 + %13 = OpTypeFunction %v4float %_ptr_Function_7 %_ptr_Function_v3int + %v2float = OpTypeVector %float 2 +%_ptr_Function_v2float = OpTypePointer Function %v2float + %20 = OpTypeFunction %v4float %_ptr_Function_7 %_ptr_Function_v2float +%_ptr_Function_v4float = OpTypePointer Function %v4float + %26 = OpTypeFunction %v4float %_ptr_Function_v4float + %v2int = OpTypeVector %int 2 + %uint = OpTypeInt 32 0 + %uint_2 = OpConstant %uint 2 +%_ptr_Function_int = OpTypePointer Function %int + %43 = OpTypeSampler +%_ptr_UniformConstant_43 = OpTypePointer UniformConstant %43 + %Sampler = OpVariable %_ptr_UniformConstant_43 UniformConstant + %47 = OpTypeSampledImage %7 + %uint_0 = OpConstant %uint 0 +%_ptr_Function_float = OpTypePointer Function %float + %float_1280 = OpConstant %float 1280 + %uint_1 = OpConstant %uint 1 + %float_720 = OpConstant %float 720 + %int_0 = OpConstant %int 0 +%_ptr_UniformConstant_7 = OpTypePointer UniformConstant %7 +%SampledImage = OpVariable %_ptr_UniformConstant_7 UniformConstant +%_ptr_Input_v4float = OpTypePointer Input %v4float + %xIn_1 = OpVariable %_ptr_Input_v4float Input +%_ptr_Output_v4float = OpTypePointer Output %v4float +%_entryPointOutput = OpVariable %_ptr_Output_v4float Output + %main = OpFunction %void None %3 + %5 = OpLabel + %xIn_0 = OpVariable %_ptr_Function_v4float Function + %param_3 = OpVariable %_ptr_Function_v4float Function + %107 = OpLoad %v4float %xIn_1 + OpStore %xIn_0 %107 + %111 = OpLoad %v4float %xIn_0 + OpStore %param_3 %111 + %112 = OpFunctionCall %v4float %_main_vf4_ %param_3 + OpStore %_entryPointOutput %112 + OpReturn + OpFunctionEnd +%sample_fetch_t21_vi3_ = OpFunction %v4float None %13 + %tex = OpFunctionParameter %_ptr_Function_7 + %UV = OpFunctionParameter %_ptr_Function_v3int + %17 = OpLabel + %30 = OpLoad %7 %tex + %32 = OpLoad %v3int %UV + %33 = OpVectorShuffle %v2int %32 %32 0 1 + %37 = OpAccessChain %_ptr_Function_int %UV %uint_2 + %38 = OpLoad %int %37 + %39 = OpImageFetch %v4float %30 %33 Lod %38 + OpReturnValue %39 + OpFunctionEnd +%sample_sampler_t21_vf2_ = OpFunction %v4float None %20 + %tex_0 = OpFunctionParameter %_ptr_Function_7 + %UV_0 = OpFunctionParameter %_ptr_Function_v2float + %24 = OpLabel + %42 = OpLoad %7 %tex_0 + %46 = OpLoad %43 %Sampler + %48 = OpSampledImage %47 %42 %46 + %49 = OpLoad %v2float %UV_0 + %50 = OpImageSampleImplicitLod %v4float %48 %49 + OpReturnValue %50 + OpFunctionEnd + %_main_vf4_ = OpFunction %v4float None %26 + %xIn = OpFunctionParameter %_ptr_Function_v4float + %29 = OpLabel + %coord = OpVariable %_ptr_Function_v3int Function + %value = OpVariable %_ptr_Function_v4float Function + %param = OpVariable %_ptr_Function_7 Function + %param_0 = OpVariable %_ptr_Function_v3int Function + %param_1 = OpVariable %_ptr_Function_7 Function + %param_2 = OpVariable %_ptr_Function_v2float Function + %56 = OpAccessChain %_ptr_Function_float %xIn %uint_0 + %57 = OpLoad %float %56 + %59 = OpFMul %float %57 %float_1280 + %60 = OpConvertFToS %int %59 + %62 = OpAccessChain %_ptr_Function_float %xIn %uint_1 + %63 = OpLoad %float %62 + %65 = OpFMul %float %63 %float_720 + %66 = OpConvertFToS %int %65 + %68 = OpCompositeConstruct %v3int %60 %66 %int_0 + OpStore %coord %68 + %73 = OpLoad %7 %SampledImage + OpStore %param %73 + %75 = OpLoad %v3int %coord + OpStore %param_0 %75 + %76 = OpFunctionCall %v4float %sample_fetch_t21_vi3_ %param %param_0 + OpStore %value %76 + %77 = OpLoad %7 %SampledImage + %78 = OpLoad %v3int %coord + %79 = OpVectorShuffle %v2int %78 %78 0 1 + %80 = OpAccessChain %_ptr_Function_int %coord %uint_2 + %81 = OpLoad %int %80 + %82 = OpImageFetch %v4float %77 %79 Lod %81 + %83 = OpLoad %v4float %value + %84 = OpFAdd %v4float %83 %82 + OpStore %value %84 + %86 = OpLoad %7 %SampledImage + OpStore %param_1 %86 + %88 = OpLoad %v4float %xIn + %89 = OpVectorShuffle %v2float %88 %88 0 1 + OpStore %param_2 %89 + %90 = OpFunctionCall %v4float %sample_sampler_t21_vf2_ %param_1 %param_2 + %91 = OpLoad %v4float %value + %92 = OpFAdd %v4float %91 %90 + OpStore %value %92 + %93 = OpLoad %7 %SampledImage + %94 = OpLoad %43 %Sampler + %95 = OpSampledImage %47 %93 %94 + %96 = OpLoad %v4float %xIn + %97 = OpVectorShuffle %v2float %96 %96 0 1 + %98 = OpImageSampleImplicitLod %v4float %95 %97 + %99 = OpLoad %v4float %value + %100 = OpFAdd %v4float %99 %98 + OpStore %value %100 + %101 = OpLoad %v4float %value + OpReturnValue %101 + OpFunctionEnd diff --git a/third_party/spirv-cross/shaders/asm/frag/image-query-no-sampler.no-samplerless.vk.asm.frag b/third_party/spirv-cross/shaders/asm/frag/image-query-no-sampler.no-samplerless.vk.asm.frag new file mode 100644 index 0000000000..a232bd4898 --- /dev/null +++ b/third_party/spirv-cross/shaders/asm/frag/image-query-no-sampler.no-samplerless.vk.asm.frag @@ -0,0 +1,57 @@ +; SPIR-V +; Version: 1.0 +; Generator: Khronos Glslang Reference Front End; 6 +; Bound: 36 +; Schema: 0 + OpCapability Shader + OpCapability ImageQuery + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" + OpExecutionMode %main OriginUpperLeft + OpSource GLSL 450 + OpName %main "main" + OpName %b "b" + OpName %uSampler2D "uSampler2D" + OpName %c "c" + OpName %uSampler2DMS "uSampler2DMS" + OpName %l1 "l1" + OpName %s0 "s0" + OpDecorate %uSampler2D DescriptorSet 0 + OpDecorate %uSampler2D Binding 0 + OpDecorate %uSampler2DMS DescriptorSet 0 + OpDecorate %uSampler2DMS Binding 0 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %int = OpTypeInt 32 1 + %v2int = OpTypeVector %int 2 +%_ptr_Function_v2int = OpTypePointer Function %v2int + %float = OpTypeFloat 32 + %11 = OpTypeImage %float 2D 0 0 0 1 Unknown +%_ptr_UniformConstant_12 = OpTypePointer UniformConstant %11 + %uSampler2D = OpVariable %_ptr_UniformConstant_12 UniformConstant + %int_0 = OpConstant %int 0 + %20 = OpTypeImage %float 2D 0 0 1 1 Unknown +%_ptr_UniformConstant_21 = OpTypePointer UniformConstant %20 +%uSampler2DMS = OpVariable %_ptr_UniformConstant_21 UniformConstant +%_ptr_Function_int = OpTypePointer Function %int + %main = OpFunction %void None %3 + %5 = OpLabel + %b = OpVariable %_ptr_Function_v2int Function + %c = OpVariable %_ptr_Function_v2int Function + %l1 = OpVariable %_ptr_Function_int Function + %s0 = OpVariable %_ptr_Function_int Function + %15 = OpLoad %11 %uSampler2D + %18 = OpImageQuerySizeLod %v2int %15 %int_0 + OpStore %b %18 + %24 = OpLoad %20 %uSampler2DMS + %26 = OpImageQuerySize %v2int %24 + OpStore %c %26 + %29 = OpLoad %11 %uSampler2D + %31 = OpImageQueryLevels %int %29 + OpStore %l1 %31 + %33 = OpLoad %20 %uSampler2DMS + %35 = OpImageQuerySamples %int %33 + OpStore %s0 %35 + OpReturn + OpFunctionEnd diff --git a/third_party/spirv-cross/shaders/desktop-only/frag/image-size.frag b/third_party/spirv-cross/shaders/desktop-only/frag/image-size.frag new file mode 100644 index 0000000000..ffd0bfa20d --- /dev/null +++ b/third_party/spirv-cross/shaders/desktop-only/frag/image-size.frag @@ -0,0 +1,10 @@ +#version 450 + +layout(location = 0) out vec4 FragColor; +layout(r32f, set = 0, binding = 0) uniform image2D uImage1; +layout(r32f, set = 0, binding = 1) uniform image2D uImage2; + +void main() +{ + FragColor = vec4(imageSize(uImage1), imageSize(uImage2)); +} diff --git a/third_party/spirv-cross/shaders/desktop-only/frag/image-size.no-qualifier-deduction.frag b/third_party/spirv-cross/shaders/desktop-only/frag/image-size.no-qualifier-deduction.frag new file mode 100644 index 0000000000..ffd0bfa20d --- /dev/null +++ b/third_party/spirv-cross/shaders/desktop-only/frag/image-size.no-qualifier-deduction.frag @@ -0,0 +1,10 @@ +#version 450 + +layout(location = 0) out vec4 FragColor; +layout(r32f, set = 0, binding = 0) uniform image2D uImage1; +layout(r32f, set = 0, binding = 1) uniform image2D uImage2; + +void main() +{ + FragColor = vec4(imageSize(uImage1), imageSize(uImage2)); +} diff --git a/third_party/spirv-cross/shaders/frag/pixel-interlock-ordered.frag b/third_party/spirv-cross/shaders/frag/pixel-interlock-ordered.frag new file mode 100644 index 0000000000..4439f0672b --- /dev/null +++ b/third_party/spirv-cross/shaders/frag/pixel-interlock-ordered.frag @@ -0,0 +1,22 @@ +#version 450 +#extension GL_ARB_fragment_shader_interlock : require + +layout(pixel_interlock_ordered) in; + +layout(binding = 0, rgba8) uniform writeonly image2D img; +layout(binding = 1, r32ui) uniform uimage2D img2; +layout(binding = 2) coherent buffer Buffer +{ + int foo; + uint bar; +}; + +void main() +{ + beginInvocationInterlockARB(); + imageStore(img, ivec2(0, 0), vec4(1.0, 0.0, 0.0, 1.0)); + imageAtomicAdd(img2, ivec2(0, 0), 1u); + foo += 42; + atomicAnd(bar, 0xff); + endInvocationInterlockARB(); +} diff --git a/third_party/spirv-cross/shaders/frag/pixel-interlock-unordered.frag b/third_party/spirv-cross/shaders/frag/pixel-interlock-unordered.frag new file mode 100644 index 0000000000..f8fd468c1b --- /dev/null +++ b/third_party/spirv-cross/shaders/frag/pixel-interlock-unordered.frag @@ -0,0 +1,22 @@ +#version 450 +#extension GL_ARB_fragment_shader_interlock : require + +layout(pixel_interlock_unordered) in; + +layout(binding = 0, rgba8) uniform writeonly image2D img; +layout(binding = 1, r32ui) uniform uimage2D img2; +layout(binding = 2) coherent buffer Buffer +{ + int foo; + uint bar; +}; + +void main() +{ + beginInvocationInterlockARB(); + imageStore(img, ivec2(0, 0), vec4(1.0, 0.0, 0.0, 1.0)); + imageAtomicAdd(img2, ivec2(0, 0), 1u); + foo += 42; + atomicAnd(bar, 0xff); + endInvocationInterlockARB(); +} diff --git a/third_party/spirv-cross/shaders/frag/post-depth-coverage-es.frag b/third_party/spirv-cross/shaders/frag/post-depth-coverage-es.frag new file mode 100644 index 0000000000..ecc57e4a8f --- /dev/null +++ b/third_party/spirv-cross/shaders/frag/post-depth-coverage-es.frag @@ -0,0 +1,13 @@ +#version 310 es +#extension GL_EXT_post_depth_coverage : require +#extension GL_OES_sample_variables : require +precision mediump float; + +layout(early_fragment_tests, post_depth_coverage) in; + +layout(location = 0) out vec4 FragColor; + +void main() +{ + FragColor = vec4(gl_SampleMaskIn[0]); +} diff --git a/third_party/spirv-cross/shaders/frag/sample-interlock-ordered.frag b/third_party/spirv-cross/shaders/frag/sample-interlock-ordered.frag new file mode 100644 index 0000000000..fa80dc9f82 --- /dev/null +++ b/third_party/spirv-cross/shaders/frag/sample-interlock-ordered.frag @@ -0,0 +1,22 @@ +#version 450 +#extension GL_ARB_fragment_shader_interlock : require + +layout(sample_interlock_ordered) in; + +layout(binding = 0, rgba8) uniform writeonly image2D img; +layout(binding = 1, r32ui) uniform uimage2D img2; +layout(binding = 2) coherent buffer Buffer +{ + int foo; + uint bar; +}; + +void main() +{ + beginInvocationInterlockARB(); + imageStore(img, ivec2(0, 0), vec4(1.0, 0.0, 0.0, 1.0)); + imageAtomicAdd(img2, ivec2(0, 0), 1u); + foo += 42; + atomicAnd(bar, gl_SampleMaskIn[0]); + endInvocationInterlockARB(); +} diff --git a/third_party/spirv-cross/shaders/frag/sample-interlock-unordered.frag b/third_party/spirv-cross/shaders/frag/sample-interlock-unordered.frag new file mode 100644 index 0000000000..6fe5437f3a --- /dev/null +++ b/third_party/spirv-cross/shaders/frag/sample-interlock-unordered.frag @@ -0,0 +1,22 @@ +#version 450 +#extension GL_ARB_fragment_shader_interlock : require + +layout(sample_interlock_unordered) in; + +layout(binding = 0, rgba8) uniform writeonly image2D img; +layout(binding = 1, r32ui) uniform uimage2D img2; +layout(binding = 2) coherent buffer Buffer +{ + int foo; + uint bar; +}; + +void main() +{ + beginInvocationInterlockARB(); + imageStore(img, ivec2(0, 0), vec4(1.0, 0.0, 0.0, 1.0)); + imageAtomicAdd(img2, ivec2(0, 0), 1u); + foo += 42; + atomicAnd(bar, 0xff); + endInvocationInterlockARB(); +} diff --git a/third_party/spirv-cross/shaders/frag/struct-type-unrelated-alias.frag b/third_party/spirv-cross/shaders/frag/struct-type-unrelated-alias.frag new file mode 100644 index 0000000000..d1c7905225 --- /dev/null +++ b/third_party/spirv-cross/shaders/frag/struct-type-unrelated-alias.frag @@ -0,0 +1,19 @@ +#version 450 + +layout(location = 0) out float FragColor; + +struct T +{ + float a; +}; + +void main() +{ + T foo; + struct T { float b; }; + T bar; + + foo.a = 10.0; + bar.b = 20.0; + FragColor = foo.a + bar.b; +} diff --git a/third_party/spirv-cross/shaders/geom/geometry-passthrough.geom b/third_party/spirv-cross/shaders/geom/geometry-passthrough.geom new file mode 100644 index 0000000000..7f1997c76a --- /dev/null +++ b/third_party/spirv-cross/shaders/geom/geometry-passthrough.geom @@ -0,0 +1,28 @@ +#version 450 +#extension GL_NV_geometry_shader_passthrough : require + +layout(triangles) in; + +layout(passthrough) in gl_PerVertex +{ + vec4 gl_Position; +} gl_in[]; + +layout(passthrough, location = 0) in VertexBlock +{ + int a; + int b; +} v1[]; + +layout(location = 2) in VertexBlock2 +{ + int a; + layout(passthrough) int b; +} v2[]; + +layout(passthrough, location = 4) in vec4 vPoint[]; + +void main() +{ + gl_Layer = gl_InvocationID + v1[0].a + v2[1].b; +} diff --git a/third_party/spirv-cross/shaders/geom/multi-stream.geom b/third_party/spirv-cross/shaders/geom/multi-stream.geom new file mode 100644 index 0000000000..19b3bbb9c2 --- /dev/null +++ b/third_party/spirv-cross/shaders/geom/multi-stream.geom @@ -0,0 +1,15 @@ +#version 450 + +layout(triangles) in; +layout(points, max_vertices = 2) out; + +void main() +{ + gl_Position = gl_in[0].gl_Position; + EmitStreamVertex(0); + EndStreamPrimitive(0); + gl_Position = gl_in[0].gl_Position + 2; + EmitStreamVertex(1); + EndStreamPrimitive(1); +} + diff --git a/third_party/spirv-cross/shaders/tese/load-array-of-array.tese b/third_party/spirv-cross/shaders/tese/load-array-of-array.tese new file mode 100644 index 0000000000..7383f7086e --- /dev/null +++ b/third_party/spirv-cross/shaders/tese/load-array-of-array.tese @@ -0,0 +1,10 @@ +#version 450 +layout(ccw, quads) in; + +layout(location = 0) in vec4 vTexCoord[][1]; + +void main() +{ + vec4 tmp[gl_MaxPatchVertices][1] = vTexCoord; + gl_Position = tmp[0][0] + tmp[2][0] + tmp[3][0]; +} diff --git a/third_party/spirv-cross/shaders/tese/patch-input-array.tese b/third_party/spirv-cross/shaders/tese/patch-input-array.tese new file mode 100644 index 0000000000..741b2c3b9b --- /dev/null +++ b/third_party/spirv-cross/shaders/tese/patch-input-array.tese @@ -0,0 +1,9 @@ +#version 450 + +layout(quads) in; +layout(location = 0) patch in float P[4]; + +void main() +{ + gl_Position = vec4(P[0], P[1], P[2], P[3]); +} diff --git a/third_party/spirv-cross/shaders/vert/transform-feedback-decorations.vert b/third_party/spirv-cross/shaders/vert/transform-feedback-decorations.vert new file mode 100644 index 0000000000..b825dd112d --- /dev/null +++ b/third_party/spirv-cross/shaders/vert/transform-feedback-decorations.vert @@ -0,0 +1,20 @@ +#version 450 +layout(xfb_stride = 32, xfb_offset = 16, xfb_buffer = 2, location = 0) out vec4 vFoo; + +layout(xfb_buffer = 1, xfb_stride = 20) out gl_PerVertex +{ + layout(xfb_offset = 4) vec4 gl_Position; + float gl_PointSize; +}; + +layout(xfb_buffer = 3) out VertOut +{ + layout(xfb_stride = 16, xfb_offset = 0, location = 1) vec4 vBar; +}; + +void main() +{ + gl_Position = vec4(1.0); + vFoo = vec4(3.0); + vBar = vec4(5.0); +} diff --git a/third_party/spirv-cross/spirv.h b/third_party/spirv-cross/spirv.h index 4b6d9dc49a..1b67617bfd 100644 --- a/third_party/spirv-cross/spirv.h +++ b/third_party/spirv-cross/spirv.h @@ -53,7 +53,7 @@ typedef unsigned int SpvId; -#define SPV_VERSION 0x10400 +#define SPV_VERSION 0x10500 #define SPV_REVISION 1 static const unsigned int SpvMagicNumber = 0x07230203; @@ -95,6 +95,7 @@ typedef enum SpvAddressingModel_ { SpvAddressingModelLogical = 0, SpvAddressingModelPhysical32 = 1, SpvAddressingModelPhysical64 = 2, + SpvAddressingModelPhysicalStorageBuffer64 = 5348, SpvAddressingModelPhysicalStorageBuffer64EXT = 5348, SpvAddressingModelMax = 0x7fffffff, } SpvAddressingModel; @@ -103,6 +104,7 @@ typedef enum SpvMemoryModel_ { SpvMemoryModelSimple = 0, SpvMemoryModelGLSL450 = 1, SpvMemoryModelOpenCL = 2, + SpvMemoryModelVulkan = 3, SpvMemoryModelVulkanKHR = 3, SpvMemoryModelMax = 0x7fffffff, } SpvMemoryModel; @@ -187,6 +189,7 @@ typedef enum SpvStorageClass_ { SpvStorageClassHitAttributeNV = 5339, SpvStorageClassIncomingRayPayloadNV = 5342, SpvStorageClassShaderRecordBufferNV = 5343, + SpvStorageClassPhysicalStorageBuffer = 5349, SpvStorageClassPhysicalStorageBufferEXT = 5349, SpvStorageClassMax = 0x7fffffff, } SpvStorageClass; @@ -315,9 +318,13 @@ typedef enum SpvImageOperandsShift_ { SpvImageOperandsConstOffsetsShift = 5, SpvImageOperandsSampleShift = 6, SpvImageOperandsMinLodShift = 7, + SpvImageOperandsMakeTexelAvailableShift = 8, SpvImageOperandsMakeTexelAvailableKHRShift = 8, + SpvImageOperandsMakeTexelVisibleShift = 9, SpvImageOperandsMakeTexelVisibleKHRShift = 9, + SpvImageOperandsNonPrivateTexelShift = 10, SpvImageOperandsNonPrivateTexelKHRShift = 10, + SpvImageOperandsVolatileTexelShift = 11, SpvImageOperandsVolatileTexelKHRShift = 11, SpvImageOperandsSignExtendShift = 12, SpvImageOperandsZeroExtendShift = 13, @@ -334,9 +341,13 @@ typedef enum SpvImageOperandsMask_ { SpvImageOperandsConstOffsetsMask = 0x00000020, SpvImageOperandsSampleMask = 0x00000040, SpvImageOperandsMinLodMask = 0x00000080, + SpvImageOperandsMakeTexelAvailableMask = 0x00000100, SpvImageOperandsMakeTexelAvailableKHRMask = 0x00000100, + SpvImageOperandsMakeTexelVisibleMask = 0x00000200, SpvImageOperandsMakeTexelVisibleKHRMask = 0x00000200, + SpvImageOperandsNonPrivateTexelMask = 0x00000400, SpvImageOperandsNonPrivateTexelKHRMask = 0x00000400, + SpvImageOperandsVolatileTexelMask = 0x00000800, SpvImageOperandsVolatileTexelKHRMask = 0x00000800, SpvImageOperandsSignExtendMask = 0x00001000, SpvImageOperandsZeroExtendMask = 0x00002000, @@ -452,8 +463,11 @@ typedef enum SpvDecoration_ { SpvDecorationPerViewNV = 5272, SpvDecorationPerTaskNV = 5273, SpvDecorationPerVertexNV = 5285, + SpvDecorationNonUniform = 5300, SpvDecorationNonUniformEXT = 5300, + SpvDecorationRestrictPointer = 5355, SpvDecorationRestrictPointerEXT = 5355, + SpvDecorationAliasedPointer = 5356, SpvDecorationAliasedPointerEXT = 5356, SpvDecorationCounterBuffer = 5634, SpvDecorationHlslCounterBufferGOOGLE = 5634, @@ -634,8 +648,11 @@ typedef enum SpvMemorySemanticsShift_ { SpvMemorySemanticsCrossWorkgroupMemoryShift = 9, SpvMemorySemanticsAtomicCounterMemoryShift = 10, SpvMemorySemanticsImageMemoryShift = 11, + SpvMemorySemanticsOutputMemoryShift = 12, SpvMemorySemanticsOutputMemoryKHRShift = 12, + SpvMemorySemanticsMakeAvailableShift = 13, SpvMemorySemanticsMakeAvailableKHRShift = 13, + SpvMemorySemanticsMakeVisibleShift = 14, SpvMemorySemanticsMakeVisibleKHRShift = 14, SpvMemorySemanticsVolatileShift = 15, SpvMemorySemanticsMax = 0x7fffffff, @@ -653,8 +670,11 @@ typedef enum SpvMemorySemanticsMask_ { SpvMemorySemanticsCrossWorkgroupMemoryMask = 0x00000200, SpvMemorySemanticsAtomicCounterMemoryMask = 0x00000400, SpvMemorySemanticsImageMemoryMask = 0x00000800, + SpvMemorySemanticsOutputMemoryMask = 0x00001000, SpvMemorySemanticsOutputMemoryKHRMask = 0x00001000, + SpvMemorySemanticsMakeAvailableMask = 0x00002000, SpvMemorySemanticsMakeAvailableKHRMask = 0x00002000, + SpvMemorySemanticsMakeVisibleMask = 0x00004000, SpvMemorySemanticsMakeVisibleKHRMask = 0x00004000, SpvMemorySemanticsVolatileMask = 0x00008000, } SpvMemorySemanticsMask; @@ -663,8 +683,11 @@ typedef enum SpvMemoryAccessShift_ { SpvMemoryAccessVolatileShift = 0, SpvMemoryAccessAlignedShift = 1, SpvMemoryAccessNontemporalShift = 2, + SpvMemoryAccessMakePointerAvailableShift = 3, SpvMemoryAccessMakePointerAvailableKHRShift = 3, + SpvMemoryAccessMakePointerVisibleShift = 4, SpvMemoryAccessMakePointerVisibleKHRShift = 4, + SpvMemoryAccessNonPrivatePointerShift = 5, SpvMemoryAccessNonPrivatePointerKHRShift = 5, SpvMemoryAccessMax = 0x7fffffff, } SpvMemoryAccessShift; @@ -674,8 +697,11 @@ typedef enum SpvMemoryAccessMask_ { SpvMemoryAccessVolatileMask = 0x00000001, SpvMemoryAccessAlignedMask = 0x00000002, SpvMemoryAccessNontemporalMask = 0x00000004, + SpvMemoryAccessMakePointerAvailableMask = 0x00000008, SpvMemoryAccessMakePointerAvailableKHRMask = 0x00000008, + SpvMemoryAccessMakePointerVisibleMask = 0x00000010, SpvMemoryAccessMakePointerVisibleKHRMask = 0x00000010, + SpvMemoryAccessNonPrivatePointerMask = 0x00000020, SpvMemoryAccessNonPrivatePointerKHRMask = 0x00000020, } SpvMemoryAccessMask; @@ -685,6 +711,7 @@ typedef enum SpvScope_ { SpvScopeWorkgroup = 2, SpvScopeSubgroup = 3, SpvScopeInvocation = 4, + SpvScopeQueueFamily = 5, SpvScopeQueueFamilyKHR = 5, SpvScopeMax = 0x7fffffff, } SpvScope; @@ -785,6 +812,8 @@ typedef enum SpvCapability_ { SpvCapabilityGroupNonUniformShuffleRelative = 66, SpvCapabilityGroupNonUniformClustered = 67, SpvCapabilityGroupNonUniformQuad = 68, + SpvCapabilityShaderLayer = 69, + SpvCapabilityShaderViewportIndex = 70, SpvCapabilitySubgroupBallotKHR = 4423, SpvCapabilityDrawParameters = 4427, SpvCapabilitySubgroupVoteKHR = 4431, @@ -813,6 +842,7 @@ typedef enum SpvCapability_ { SpvCapabilityFragmentMaskAMD = 5010, SpvCapabilityStencilExportEXT = 5013, SpvCapabilityImageReadWriteLodAMD = 5015, + SpvCapabilityShaderClockKHR = 5055, SpvCapabilitySampleMaskOverrideCoverageNV = 5249, SpvCapabilityGeometryShaderPassthroughNV = 5251, SpvCapabilityShaderViewportIndexLayerEXT = 5254, @@ -828,21 +858,36 @@ typedef enum SpvCapability_ { SpvCapabilityFragmentDensityEXT = 5291, SpvCapabilityShadingRateNV = 5291, SpvCapabilityGroupNonUniformPartitionedNV = 5297, + SpvCapabilityShaderNonUniform = 5301, SpvCapabilityShaderNonUniformEXT = 5301, + SpvCapabilityRuntimeDescriptorArray = 5302, SpvCapabilityRuntimeDescriptorArrayEXT = 5302, + SpvCapabilityInputAttachmentArrayDynamicIndexing = 5303, SpvCapabilityInputAttachmentArrayDynamicIndexingEXT = 5303, + SpvCapabilityUniformTexelBufferArrayDynamicIndexing = 5304, SpvCapabilityUniformTexelBufferArrayDynamicIndexingEXT = 5304, + SpvCapabilityStorageTexelBufferArrayDynamicIndexing = 5305, SpvCapabilityStorageTexelBufferArrayDynamicIndexingEXT = 5305, + SpvCapabilityUniformBufferArrayNonUniformIndexing = 5306, SpvCapabilityUniformBufferArrayNonUniformIndexingEXT = 5306, + SpvCapabilitySampledImageArrayNonUniformIndexing = 5307, SpvCapabilitySampledImageArrayNonUniformIndexingEXT = 5307, + SpvCapabilityStorageBufferArrayNonUniformIndexing = 5308, SpvCapabilityStorageBufferArrayNonUniformIndexingEXT = 5308, + SpvCapabilityStorageImageArrayNonUniformIndexing = 5309, SpvCapabilityStorageImageArrayNonUniformIndexingEXT = 5309, + SpvCapabilityInputAttachmentArrayNonUniformIndexing = 5310, SpvCapabilityInputAttachmentArrayNonUniformIndexingEXT = 5310, + SpvCapabilityUniformTexelBufferArrayNonUniformIndexing = 5311, SpvCapabilityUniformTexelBufferArrayNonUniformIndexingEXT = 5311, + SpvCapabilityStorageTexelBufferArrayNonUniformIndexing = 5312, SpvCapabilityStorageTexelBufferArrayNonUniformIndexingEXT = 5312, SpvCapabilityRayTracingNV = 5340, + SpvCapabilityVulkanMemoryModel = 5345, SpvCapabilityVulkanMemoryModelKHR = 5345, + SpvCapabilityVulkanMemoryModelDeviceScope = 5346, SpvCapabilityVulkanMemoryModelDeviceScopeKHR = 5346, + SpvCapabilityPhysicalStorageBufferAddresses = 5347, SpvCapabilityPhysicalStorageBufferAddressesEXT = 5347, SpvCapabilityComputeDerivativeGroupLinearNV = 5350, SpvCapabilityCooperativeMatrixNV = 5357, @@ -1223,6 +1268,7 @@ typedef enum SpvOp_ { SpvOpGroupSMaxNonUniformAMD = 5007, SpvOpFragmentMaskFetchAMD = 5011, SpvOpFragmentFetchAMD = 5012, + SpvOpReadClockKHR = 5056, SpvOpImageSampleFootprintNV = 5283, SpvOpGroupNonUniformPartitionNV = 5296, SpvOpWritePackedPrimitiveIndices4x8NV = 5299, @@ -1755,6 +1801,7 @@ inline void SpvHasResultAndType(SpvOp opcode, bool *hasResult, bool *hasResultTy case SpvOpGroupSMaxNonUniformAMD: *hasResult = true; *hasResultType = true; break; case SpvOpFragmentMaskFetchAMD: *hasResult = true; *hasResultType = true; break; case SpvOpFragmentFetchAMD: *hasResult = true; *hasResultType = true; break; + case SpvOpReadClockKHR: *hasResult = true; *hasResultType = true; break; case SpvOpImageSampleFootprintNV: *hasResult = true; *hasResultType = true; break; case SpvOpGroupNonUniformPartitionNV: *hasResult = true; *hasResultType = true; break; case SpvOpWritePackedPrimitiveIndices4x8NV: *hasResult = false; *hasResultType = false; break; diff --git a/third_party/spirv-cross/spirv.hpp b/third_party/spirv-cross/spirv.hpp index 50cc20da32..f5cbda1bb8 100644 --- a/third_party/spirv-cross/spirv.hpp +++ b/third_party/spirv-cross/spirv.hpp @@ -49,7 +49,7 @@ namespace spv { typedef unsigned int Id; -#define SPV_VERSION 0x10400 +#define SPV_VERSION 0x10500 #define SPV_REVISION 1 static const unsigned int MagicNumber = 0x07230203; @@ -91,6 +91,7 @@ enum AddressingModel { AddressingModelLogical = 0, AddressingModelPhysical32 = 1, AddressingModelPhysical64 = 2, + AddressingModelPhysicalStorageBuffer64 = 5348, AddressingModelPhysicalStorageBuffer64EXT = 5348, AddressingModelMax = 0x7fffffff, }; @@ -99,6 +100,7 @@ enum MemoryModel { MemoryModelSimple = 0, MemoryModelGLSL450 = 1, MemoryModelOpenCL = 2, + MemoryModelVulkan = 3, MemoryModelVulkanKHR = 3, MemoryModelMax = 0x7fffffff, }; @@ -183,6 +185,7 @@ enum StorageClass { StorageClassHitAttributeNV = 5339, StorageClassIncomingRayPayloadNV = 5342, StorageClassShaderRecordBufferNV = 5343, + StorageClassPhysicalStorageBuffer = 5349, StorageClassPhysicalStorageBufferEXT = 5349, StorageClassMax = 0x7fffffff, }; @@ -311,9 +314,13 @@ enum ImageOperandsShift { ImageOperandsConstOffsetsShift = 5, ImageOperandsSampleShift = 6, ImageOperandsMinLodShift = 7, + ImageOperandsMakeTexelAvailableShift = 8, ImageOperandsMakeTexelAvailableKHRShift = 8, + ImageOperandsMakeTexelVisibleShift = 9, ImageOperandsMakeTexelVisibleKHRShift = 9, + ImageOperandsNonPrivateTexelShift = 10, ImageOperandsNonPrivateTexelKHRShift = 10, + ImageOperandsVolatileTexelShift = 11, ImageOperandsVolatileTexelKHRShift = 11, ImageOperandsSignExtendShift = 12, ImageOperandsZeroExtendShift = 13, @@ -330,9 +337,13 @@ enum ImageOperandsMask { ImageOperandsConstOffsetsMask = 0x00000020, ImageOperandsSampleMask = 0x00000040, ImageOperandsMinLodMask = 0x00000080, + ImageOperandsMakeTexelAvailableMask = 0x00000100, ImageOperandsMakeTexelAvailableKHRMask = 0x00000100, + ImageOperandsMakeTexelVisibleMask = 0x00000200, ImageOperandsMakeTexelVisibleKHRMask = 0x00000200, + ImageOperandsNonPrivateTexelMask = 0x00000400, ImageOperandsNonPrivateTexelKHRMask = 0x00000400, + ImageOperandsVolatileTexelMask = 0x00000800, ImageOperandsVolatileTexelKHRMask = 0x00000800, ImageOperandsSignExtendMask = 0x00001000, ImageOperandsZeroExtendMask = 0x00002000, @@ -448,8 +459,11 @@ enum Decoration { DecorationPerViewNV = 5272, DecorationPerTaskNV = 5273, DecorationPerVertexNV = 5285, + DecorationNonUniform = 5300, DecorationNonUniformEXT = 5300, + DecorationRestrictPointer = 5355, DecorationRestrictPointerEXT = 5355, + DecorationAliasedPointer = 5356, DecorationAliasedPointerEXT = 5356, DecorationCounterBuffer = 5634, DecorationHlslCounterBufferGOOGLE = 5634, @@ -630,8 +644,11 @@ enum MemorySemanticsShift { MemorySemanticsCrossWorkgroupMemoryShift = 9, MemorySemanticsAtomicCounterMemoryShift = 10, MemorySemanticsImageMemoryShift = 11, + MemorySemanticsOutputMemoryShift = 12, MemorySemanticsOutputMemoryKHRShift = 12, + MemorySemanticsMakeAvailableShift = 13, MemorySemanticsMakeAvailableKHRShift = 13, + MemorySemanticsMakeVisibleShift = 14, MemorySemanticsMakeVisibleKHRShift = 14, MemorySemanticsVolatileShift = 15, MemorySemanticsMax = 0x7fffffff, @@ -649,8 +666,11 @@ enum MemorySemanticsMask { MemorySemanticsCrossWorkgroupMemoryMask = 0x00000200, MemorySemanticsAtomicCounterMemoryMask = 0x00000400, MemorySemanticsImageMemoryMask = 0x00000800, + MemorySemanticsOutputMemoryMask = 0x00001000, MemorySemanticsOutputMemoryKHRMask = 0x00001000, + MemorySemanticsMakeAvailableMask = 0x00002000, MemorySemanticsMakeAvailableKHRMask = 0x00002000, + MemorySemanticsMakeVisibleMask = 0x00004000, MemorySemanticsMakeVisibleKHRMask = 0x00004000, MemorySemanticsVolatileMask = 0x00008000, }; @@ -659,8 +679,11 @@ enum MemoryAccessShift { MemoryAccessVolatileShift = 0, MemoryAccessAlignedShift = 1, MemoryAccessNontemporalShift = 2, + MemoryAccessMakePointerAvailableShift = 3, MemoryAccessMakePointerAvailableKHRShift = 3, + MemoryAccessMakePointerVisibleShift = 4, MemoryAccessMakePointerVisibleKHRShift = 4, + MemoryAccessNonPrivatePointerShift = 5, MemoryAccessNonPrivatePointerKHRShift = 5, MemoryAccessMax = 0x7fffffff, }; @@ -670,8 +693,11 @@ enum MemoryAccessMask { MemoryAccessVolatileMask = 0x00000001, MemoryAccessAlignedMask = 0x00000002, MemoryAccessNontemporalMask = 0x00000004, + MemoryAccessMakePointerAvailableMask = 0x00000008, MemoryAccessMakePointerAvailableKHRMask = 0x00000008, + MemoryAccessMakePointerVisibleMask = 0x00000010, MemoryAccessMakePointerVisibleKHRMask = 0x00000010, + MemoryAccessNonPrivatePointerMask = 0x00000020, MemoryAccessNonPrivatePointerKHRMask = 0x00000020, }; @@ -681,6 +707,7 @@ enum Scope { ScopeWorkgroup = 2, ScopeSubgroup = 3, ScopeInvocation = 4, + ScopeQueueFamily = 5, ScopeQueueFamilyKHR = 5, ScopeMax = 0x7fffffff, }; @@ -781,6 +808,8 @@ enum Capability { CapabilityGroupNonUniformShuffleRelative = 66, CapabilityGroupNonUniformClustered = 67, CapabilityGroupNonUniformQuad = 68, + CapabilityShaderLayer = 69, + CapabilityShaderViewportIndex = 70, CapabilitySubgroupBallotKHR = 4423, CapabilityDrawParameters = 4427, CapabilitySubgroupVoteKHR = 4431, @@ -809,6 +838,7 @@ enum Capability { CapabilityFragmentMaskAMD = 5010, CapabilityStencilExportEXT = 5013, CapabilityImageReadWriteLodAMD = 5015, + CapabilityShaderClockKHR = 5055, CapabilitySampleMaskOverrideCoverageNV = 5249, CapabilityGeometryShaderPassthroughNV = 5251, CapabilityShaderViewportIndexLayerEXT = 5254, @@ -824,21 +854,36 @@ enum Capability { CapabilityFragmentDensityEXT = 5291, CapabilityShadingRateNV = 5291, CapabilityGroupNonUniformPartitionedNV = 5297, + CapabilityShaderNonUniform = 5301, CapabilityShaderNonUniformEXT = 5301, + CapabilityRuntimeDescriptorArray = 5302, CapabilityRuntimeDescriptorArrayEXT = 5302, + CapabilityInputAttachmentArrayDynamicIndexing = 5303, CapabilityInputAttachmentArrayDynamicIndexingEXT = 5303, + CapabilityUniformTexelBufferArrayDynamicIndexing = 5304, CapabilityUniformTexelBufferArrayDynamicIndexingEXT = 5304, + CapabilityStorageTexelBufferArrayDynamicIndexing = 5305, CapabilityStorageTexelBufferArrayDynamicIndexingEXT = 5305, + CapabilityUniformBufferArrayNonUniformIndexing = 5306, CapabilityUniformBufferArrayNonUniformIndexingEXT = 5306, + CapabilitySampledImageArrayNonUniformIndexing = 5307, CapabilitySampledImageArrayNonUniformIndexingEXT = 5307, + CapabilityStorageBufferArrayNonUniformIndexing = 5308, CapabilityStorageBufferArrayNonUniformIndexingEXT = 5308, + CapabilityStorageImageArrayNonUniformIndexing = 5309, CapabilityStorageImageArrayNonUniformIndexingEXT = 5309, + CapabilityInputAttachmentArrayNonUniformIndexing = 5310, CapabilityInputAttachmentArrayNonUniformIndexingEXT = 5310, + CapabilityUniformTexelBufferArrayNonUniformIndexing = 5311, CapabilityUniformTexelBufferArrayNonUniformIndexingEXT = 5311, + CapabilityStorageTexelBufferArrayNonUniformIndexing = 5312, CapabilityStorageTexelBufferArrayNonUniformIndexingEXT = 5312, CapabilityRayTracingNV = 5340, + CapabilityVulkanMemoryModel = 5345, CapabilityVulkanMemoryModelKHR = 5345, + CapabilityVulkanMemoryModelDeviceScope = 5346, CapabilityVulkanMemoryModelDeviceScopeKHR = 5346, + CapabilityPhysicalStorageBufferAddresses = 5347, CapabilityPhysicalStorageBufferAddressesEXT = 5347, CapabilityComputeDerivativeGroupLinearNV = 5350, CapabilityCooperativeMatrixNV = 5357, @@ -1219,6 +1264,7 @@ enum Op { OpGroupSMaxNonUniformAMD = 5007, OpFragmentMaskFetchAMD = 5011, OpFragmentFetchAMD = 5012, + OpReadClockKHR = 5056, OpImageSampleFootprintNV = 5283, OpGroupNonUniformPartitionNV = 5296, OpWritePackedPrimitiveIndices4x8NV = 5299, @@ -1751,6 +1797,7 @@ inline void HasResultAndType(Op opcode, bool *hasResult, bool *hasResultType) { case OpGroupSMaxNonUniformAMD: *hasResult = true; *hasResultType = true; break; case OpFragmentMaskFetchAMD: *hasResult = true; *hasResultType = true; break; case OpFragmentFetchAMD: *hasResult = true; *hasResultType = true; break; + case OpReadClockKHR: *hasResult = true; *hasResultType = true; break; case OpImageSampleFootprintNV: *hasResult = true; *hasResultType = true; break; case OpGroupNonUniformPartitionNV: *hasResult = true; *hasResultType = true; break; case OpWritePackedPrimitiveIndices4x8NV: *hasResult = false; *hasResultType = false; break; diff --git a/third_party/spirv-cross/spirv_cfg.cpp b/third_party/spirv-cross/spirv_cfg.cpp index ed31f23679..9973fbae1f 100644 --- a/third_party/spirv-cross/spirv_cfg.cpp +++ b/third_party/spirv-cross/spirv_cfg.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2016-2019 Arm Limited + * Copyright 2016-2020 Arm Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -61,7 +61,7 @@ void CFG::build_immediate_dominators() if (immediate_dominators[block]) { assert(immediate_dominators[edge]); - immediate_dominators[block] = find_common_dominator(block, edge); + immediate_dominators[block] = find_common_dominator(immediate_dominators[block], edge); } else immediate_dominators[block] = edge; @@ -97,8 +97,22 @@ bool CFG::post_order_visit(uint32_t block_id) // Block back-edges from recursively revisiting ourselves. visit_order[block_id].get() = 0; - // First visit our branch targets. auto &block = compiler.get(block_id); + + // If this is a loop header, add an implied branch to the merge target. + // This is needed to avoid annoying cases with do { ... } while(false) loops often generated by inliners. + // To the CFG, this is linear control flow, but we risk picking the do/while scope as our dominating block. + // This makes sure that if we are accessing a variable outside the do/while, we choose the loop header as dominator. + // We could use has_visited_forward_edge, but this break code-gen where the merge block is unreachable in the CFG. + + // Make a point out of visiting merge target first. This is to make sure that post visit order outside the loop + // is lower than inside the loop, which is going to be key for some traversal algorithms like post-dominance analysis. + // For selection constructs true/false blocks will end up visiting the merge block directly and it works out fine, + // but for loops, only the header might end up actually branching to merge block. + if (block.merge == SPIRBlock::MergeLoop && post_order_visit(block.merge_block)) + add_branch(block_id, block.merge_block); + + // First visit our branch targets. switch (block.terminator) { case SPIRBlock::Direct: @@ -127,14 +141,6 @@ bool CFG::post_order_visit(uint32_t block_id) break; } - // If this is a loop header, add an implied branch to the merge target. - // This is needed to avoid annoying cases with do { ... } while(false) loops often generated by inliners. - // To the CFG, this is linear control flow, but we risk picking the do/while scope as our dominating block. - // This makes sure that if we are accessing a variable outside the do/while, we choose the loop header as dominator. - // We could use has_visited_forward_edge, but this break code-gen where the merge block is unreachable in the CFG. - if (block.merge == SPIRBlock::MergeLoop && post_order_visit(block.merge_block)) - add_branch(block_id, block.merge_block); - // If this is a selection merge, add an implied branch to the merge target. // This is needed to avoid cases where an inner branch dominates the outer branch. // This can happen if one of the branches exit early, e.g.: @@ -148,14 +154,35 @@ bool CFG::post_order_visit(uint32_t block_id) // Add a fake branch so any dominator in either the if (), or else () block, or a lone case statement // will be hoisted out to outside the selection merge. // If size > 1, the variable will be automatically hoisted, so we should not mess with it. + // The exception here is switch blocks, where we can have multiple edges to merge block, + // all coming from same scope, so be more conservative in this case. // Adding fake branches unconditionally breaks parameter preservation analysis, // which looks at how variables are accessed through the CFG. auto pred_itr = preceding_edges.find(block.next_block); if (pred_itr != end(preceding_edges)) { auto &pred = pred_itr->second; - if (pred.size() == 1 && *pred.begin() != block_id) - add_branch(block_id, block.next_block); + auto succ_itr = succeeding_edges.find(block_id); + size_t num_succeeding_edges = 0; + if (succ_itr != end(succeeding_edges)) + num_succeeding_edges = succ_itr->second.size(); + + if (block.terminator == SPIRBlock::MultiSelect && num_succeeding_edges == 1) + { + // Multiple branches can come from the same scope due to "break;", so we need to assume that all branches + // come from same case scope in worst case, even if there are multiple preceding edges. + // If we have more than one succeeding edge from the block header, it should be impossible + // to have a dominator be inside the block. + // Only case this can go wrong is if we have 2 or more edges from block header and + // 2 or more edges to merge block, and still have dominator be inside a case label. + if (!pred.empty()) + add_branch(block_id, block.next_block); + } + else + { + if (pred.size() == 1 && *pred.begin() != block_id) + add_branch(block_id, block.next_block); + } } else { @@ -210,13 +237,13 @@ uint32_t CFG::find_loop_dominator(uint32_t block_id) const for (auto &pred : itr->second) { auto &pred_block = compiler.get(pred); - if (pred_block.merge == SPIRBlock::MergeLoop && pred_block.merge_block == block_id) + if (pred_block.merge == SPIRBlock::MergeLoop && pred_block.merge_block == ID(block_id)) { pred_block_id = pred; ignore_loop_header = true; break; } - else if (pred_block.merge == SPIRBlock::MergeSelection && pred_block.next_block == block_id) + else if (pred_block.merge == SPIRBlock::MergeSelection && pred_block.next_block == ID(block_id)) { pred_block_id = pred; break; @@ -241,6 +268,61 @@ uint32_t CFG::find_loop_dominator(uint32_t block_id) const return block_id; } +bool CFG::node_terminates_control_flow_in_sub_graph(BlockID from, BlockID to) const +{ + // Walk backwards, starting from "to" block. + // Only follow pred edges if they have a 1:1 relationship, or a merge relationship. + // If we cannot find a path to "from", we must assume that to is inside control flow in some way. + + auto &from_block = compiler.get(from); + BlockID ignore_block_id = 0; + if (from_block.merge == SPIRBlock::MergeLoop) + ignore_block_id = from_block.merge_block; + + while (to != from) + { + auto pred_itr = preceding_edges.find(to); + if (pred_itr == end(preceding_edges)) + return false; + + DominatorBuilder builder(*this); + for (auto &edge : pred_itr->second) + builder.add_block(edge); + + uint32_t dominator = builder.get_dominator(); + if (dominator == 0) + return false; + + auto &dom = compiler.get(dominator); + + bool true_path_ignore = false; + bool false_path_ignore = false; + if (ignore_block_id && dom.terminator == SPIRBlock::Select) + { + auto &true_block = compiler.get(dom.true_block); + auto &false_block = compiler.get(dom.false_block); + auto &ignore_block = compiler.get(ignore_block_id); + true_path_ignore = compiler.execution_is_branchless(true_block, ignore_block); + false_path_ignore = compiler.execution_is_branchless(false_block, ignore_block); + } + + if ((dom.merge == SPIRBlock::MergeSelection && dom.next_block == to) || + (dom.merge == SPIRBlock::MergeLoop && dom.merge_block == to) || + (dom.terminator == SPIRBlock::Direct && dom.next_block == to) || + (dom.terminator == SPIRBlock::Select && dom.true_block == to && false_path_ignore) || + (dom.terminator == SPIRBlock::Select && dom.false_block == to && true_path_ignore)) + { + // Allow walking selection constructs if the other branch reaches out of a loop construct. + // It cannot be in-scope anymore. + to = dominator; + } + else + return false; + } + + return true; +} + DominatorBuilder::DominatorBuilder(const CFG &cfg_) : cfg(cfg_) { diff --git a/third_party/spirv-cross/spirv_cfg.hpp b/third_party/spirv-cross/spirv_cfg.hpp index 7d07d48410..9f3e62a1bf 100644 --- a/third_party/spirv-cross/spirv_cfg.hpp +++ b/third_party/spirv-cross/spirv_cfg.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2016-2019 Arm Limited + * Copyright 2016-2020 Arm Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -88,13 +88,17 @@ public: return; seen_blocks.insert(block); - op(block); - for (auto b : get_succeeding_edges(block)) - walk_from(seen_blocks, b, op); + if (op(block)) + { + for (auto b : get_succeeding_edges(block)) + walk_from(seen_blocks, b, op); + } } uint32_t find_loop_dominator(uint32_t block) const; + bool node_terminates_control_flow_in_sub_graph(BlockID from, BlockID to) const; + private: struct VisitOrder { diff --git a/third_party/spirv-cross/spirv_common.hpp b/third_party/spirv-cross/spirv_common.hpp index bc626436af..24ae4e2e01 100644 --- a/third_party/spirv-cross/spirv_common.hpp +++ b/third_party/spirv-cross/spirv_common.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2015-2019 Arm Limited + * Copyright 2015-2020 Arm Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ #include "spirv.hpp" #include "spirv_cross_containers.hpp" #include "spirv_cross_error_handling.hpp" +#include // A bit crude, but allows projects which embed SPIRV-Cross statically to // effectively hide all the symbols from other projects. @@ -270,20 +271,6 @@ struct Instruction uint32_t length = 0; }; -// Helper for Variant interface. -struct IVariant -{ - virtual ~IVariant() = default; - virtual IVariant *clone(ObjectPoolBase *pool) = 0; - uint32_t self = 0; -}; - -#define SPIRV_CROSS_DECLARE_CLONE(T) \ - IVariant *clone(ObjectPoolBase *pool) override \ - { \ - return static_cast *>(pool)->allocate(*this); \ - } - enum Types { TypeNone, @@ -303,6 +290,136 @@ enum Types TypeCount }; +template +class TypedID; + +template <> +class TypedID +{ +public: + TypedID() = default; + TypedID(uint32_t id_) + : id(id_) + { + } + + template + TypedID(const TypedID &other) + { + *this = other; + } + + template + TypedID &operator=(const TypedID &other) + { + id = uint32_t(other); + return *this; + } + + // Implicit conversion to u32 is desired here. + // As long as we block implicit conversion between TypedID and TypedID we're good. + operator uint32_t() const + { + return id; + } + + template + operator TypedID() const + { + return TypedID(*this); + } + + bool operator==(const TypedID &other) const + { + return id == other.id; + } + + bool operator!=(const TypedID &other) const + { + return id != other.id; + } + + template + bool operator==(const TypedID &other) const + { + return id == uint32_t(other); + } + + template + bool operator!=(const TypedID &other) const + { + return id != uint32_t(other); + } + +private: + uint32_t id = 0; +}; + +template +class TypedID +{ +public: + TypedID() = default; + TypedID(uint32_t id_) + : id(id_) + { + } + + explicit TypedID(const TypedID &other) + : id(uint32_t(other)) + { + } + + operator uint32_t() const + { + return id; + } + + bool operator==(const TypedID &other) const + { + return id == other.id; + } + + bool operator!=(const TypedID &other) const + { + return id != other.id; + } + + bool operator==(const TypedID &other) const + { + return id == uint32_t(other); + } + + bool operator!=(const TypedID &other) const + { + return id != uint32_t(other); + } + +private: + uint32_t id = 0; +}; + +using VariableID = TypedID; +using TypeID = TypedID; +using ConstantID = TypedID; +using FunctionID = TypedID; +using BlockID = TypedID; +using ID = TypedID; + +// Helper for Variant interface. +struct IVariant +{ + virtual ~IVariant() = default; + virtual IVariant *clone(ObjectPoolBase *pool) = 0; + ID self = 0; +}; + +#define SPIRV_CROSS_DECLARE_CLONE(T) \ + IVariant *clone(ObjectPoolBase *pool) override \ + { \ + return static_cast *>(pool)->allocate(*this); \ + } + struct SPIRUndef : IVariant { enum @@ -310,11 +427,11 @@ struct SPIRUndef : IVariant type = TypeUndef }; - explicit SPIRUndef(uint32_t basetype_) + explicit SPIRUndef(TypeID basetype_) : basetype(basetype_) { } - uint32_t basetype; + TypeID basetype; SPIRV_CROSS_DECLARE_CLONE(SPIRUndef) }; @@ -344,15 +461,15 @@ struct SPIRCombinedImageSampler : IVariant { type = TypeCombinedImageSampler }; - SPIRCombinedImageSampler(uint32_t type_, uint32_t image_, uint32_t sampler_) + SPIRCombinedImageSampler(TypeID type_, VariableID image_, VariableID sampler_) : combined_type(type_) , image(image_) , sampler(sampler_) { } - uint32_t combined_type; - uint32_t image; - uint32_t sampler; + TypeID combined_type; + VariableID image; + VariableID sampler; SPIRV_CROSS_DECLARE_CLONE(SPIRCombinedImageSampler) }; @@ -364,16 +481,18 @@ struct SPIRConstantOp : IVariant type = TypeConstantOp }; - SPIRConstantOp(uint32_t result_type, spv::Op op, const uint32_t *args, uint32_t length) + SPIRConstantOp(TypeID result_type, spv::Op op, const uint32_t *args, uint32_t length) : opcode(op) - , arguments(args, args + length) , basetype(result_type) { + arguments.reserve(length); + for (uint32_t i = 0; i < length; i++) + arguments.push_back(args[i]); } spv::Op opcode; SmallVector arguments; - uint32_t basetype; + TypeID basetype; SPIRV_CROSS_DECLARE_CLONE(SPIRConstantOp) }; @@ -436,11 +555,11 @@ struct SPIRType : IVariant spv::StorageClass storage = spv::StorageClassGeneric; - SmallVector member_types; + SmallVector member_types; struct ImageType { - uint32_t type; + TypeID type; spv::Dim dim; bool depth; bool arrayed; @@ -453,11 +572,11 @@ struct SPIRType : IVariant // Structs can be declared multiple times if they are used as part of interface blocks. // We want to detect this so that we only emit the struct definition once. // Since we cannot rely on OpName to be equal, we need to figure out aliases. - uint32_t type_alias = 0; + TypeID type_alias = 0; // Denotes the type which this type is based on. // Allows the backend to traverse how a complex type is built up during access chains. - uint32_t parent_type = 0; + TypeID parent_type = 0; // Used in backends to avoid emitting members with conflicting names. std::unordered_set member_name_cache; @@ -496,7 +615,7 @@ struct SPIRExtension : IVariant // so in order to avoid conflicts, we can't stick them in the ids array. struct SPIREntryPoint { - SPIREntryPoint(uint32_t self_, spv::ExecutionModel execution_model, const std::string &entry_name) + SPIREntryPoint(FunctionID self_, spv::ExecutionModel execution_model, const std::string &entry_name) : self(self_) , name(entry_name) , orig_name(entry_name) @@ -505,10 +624,10 @@ struct SPIREntryPoint } SPIREntryPoint() = default; - uint32_t self = 0; + FunctionID self = 0; std::string name; std::string orig_name; - SmallVector interface_variables; + SmallVector interface_variables; Bitset flags; struct @@ -519,6 +638,7 @@ struct SPIREntryPoint uint32_t invocations = 0; uint32_t output_vertices = 0; spv::ExecutionModel model = spv::ExecutionModelMax; + bool geometry_passthrough = false; }; struct SPIRExpression : IVariant @@ -529,7 +649,7 @@ struct SPIRExpression : IVariant }; // Only created by the backend target to avoid creating tons of temporaries. - SPIRExpression(std::string expr, uint32_t expression_type_, bool immutable_) + SPIRExpression(std::string expr, TypeID expression_type_, bool immutable_) : expression(move(expr)) , expression_type(expression_type_) , immutable(immutable_) @@ -539,14 +659,14 @@ struct SPIRExpression : IVariant // If non-zero, prepend expression with to_expression(base_expression). // Used in amortizing multiple calls to to_expression() // where in certain cases that would quickly force a temporary when not needed. - uint32_t base_expression = 0; + ID base_expression = 0; std::string expression; - uint32_t expression_type = 0; + TypeID expression_type = 0; // If this expression is a forwarded load, // allow us to reference the original variable. - uint32_t loaded_from = 0; + ID loaded_from = 0; // If this expression will never change, we can avoid lots of temporaries // in high level source. @@ -562,11 +682,11 @@ struct SPIRExpression : IVariant bool access_chain = false; // A list of expressions which this expression depends on. - SmallVector expression_dependencies; + SmallVector expression_dependencies; // By reading this expression, we implicitly read these expressions as well. // Used by access chain Store and Load since we read multiple expressions in this case. - SmallVector implied_read_expressions; + SmallVector implied_read_expressions; SPIRV_CROSS_DECLARE_CLONE(SPIRExpression) }; @@ -578,12 +698,12 @@ struct SPIRFunctionPrototype : IVariant type = TypeFunctionPrototype }; - explicit SPIRFunctionPrototype(uint32_t return_type_) + explicit SPIRFunctionPrototype(TypeID return_type_) : return_type(return_type_) { } - uint32_t return_type; + TypeID return_type; SmallVector parameter_types; SPIRV_CROSS_DECLARE_CLONE(SPIRFunctionPrototype) @@ -658,23 +778,23 @@ struct SPIRBlock : IVariant Terminator terminator = Unknown; Merge merge = MergeNone; Hints hint = HintNone; - uint32_t next_block = 0; - uint32_t merge_block = 0; - uint32_t continue_block = 0; + BlockID next_block = 0; + BlockID merge_block = 0; + BlockID continue_block = 0; - uint32_t return_value = 0; // If 0, return nothing (void). - uint32_t condition = 0; - uint32_t true_block = 0; - uint32_t false_block = 0; - uint32_t default_block = 0; + ID return_value = 0; // If 0, return nothing (void). + ID condition = 0; + BlockID true_block = 0; + BlockID false_block = 0; + BlockID default_block = 0; SmallVector ops; struct Phi { - uint32_t local_variable; // flush local variable ... - uint32_t parent; // If we're in from_block and want to branch into this block ... - uint32_t function_variable; // to this function-global "phi" variable first. + ID local_variable; // flush local variable ... + BlockID parent; // If we're in from_block and want to branch into this block ... + VariableID function_variable; // to this function-global "phi" variable first. }; // Before entering this block flush out local variables to magical "phi" variables. @@ -682,16 +802,16 @@ struct SPIRBlock : IVariant // Declare these temporaries before beginning the block. // Used for handling complex continue blocks which have side effects. - SmallVector> declare_temporary; + SmallVector> declare_temporary; // Declare these temporaries, but only conditionally if this block turns out to be // a complex loop header. - SmallVector> potential_declare_temporary; + SmallVector> potential_declare_temporary; struct Case { uint32_t value; - uint32_t block; + BlockID block; }; SmallVector cases; @@ -707,25 +827,25 @@ struct SPIRBlock : IVariant // If marked, we have explicitly handled Phi from this block, so skip any flushes related to that on a branch. // Used to handle an edge case with switch and case-label fallthrough where fall-through writes to Phi. - uint32_t ignore_phi_from_block = 0; + BlockID ignore_phi_from_block = 0; // The dominating block which this block might be within. // Used in continue; blocks to determine if we really need to write continue. - uint32_t loop_dominator = 0; + BlockID loop_dominator = 0; // All access to these variables are dominated by this block, // so before branching anywhere we need to make sure that we declare these variables. - SmallVector dominated_variables; + SmallVector dominated_variables; // These are variables which should be declared in a for loop header, if we // fail to use a classic for-loop, // we remove these variables, and fall back to regular variables outside the loop. - SmallVector loop_variables; + SmallVector loop_variables; // Some expressions are control-flow dependent, i.e. any instruction which relies on derivatives or // sub-group-like operations. // Make sure that we only use these expressions in the original block. - SmallVector invalidate_expressions; + SmallVector invalidate_expressions; SPIRV_CROSS_DECLARE_CLONE(SPIRBlock) }; @@ -737,7 +857,7 @@ struct SPIRFunction : IVariant type = TypeFunction }; - SPIRFunction(uint32_t return_type_, uint32_t function_type_) + SPIRFunction(TypeID return_type_, TypeID function_type_) : return_type(return_type_) , function_type(function_type_) { @@ -745,8 +865,8 @@ struct SPIRFunction : IVariant struct Parameter { - uint32_t type; - uint32_t id; + TypeID type; + ID id; uint32_t read_count; uint32_t write_count; @@ -768,25 +888,25 @@ struct SPIRFunction : IVariant // or a global ID. struct CombinedImageSamplerParameter { - uint32_t id; - uint32_t image_id; - uint32_t sampler_id; + VariableID id; + VariableID image_id; + VariableID sampler_id; bool global_image; bool global_sampler; bool depth; }; - uint32_t return_type; - uint32_t function_type; + TypeID return_type; + TypeID function_type; SmallVector arguments; // Can be used by backends to add magic arguments. // Currently used by combined image/sampler implementation. SmallVector shadow_arguments; - SmallVector local_variables; - uint32_t entry_block = 0; - SmallVector blocks; + SmallVector local_variables; + BlockID entry_block = 0; + SmallVector blocks; SmallVector combined_parameters; struct EntryLine @@ -796,12 +916,12 @@ struct SPIRFunction : IVariant }; EntryLine entry_line; - void add_local_variable(uint32_t id) + void add_local_variable(VariableID id) { local_variables.push_back(id); } - void add_parameter(uint32_t parameter_type, uint32_t id, bool alias_global_variable = false) + void add_parameter(TypeID parameter_type, ID id, bool alias_global_variable = false) { // Arguments are read-only until proven otherwise. arguments.push_back({ parameter_type, id, 0u, 0u, alias_global_variable }); @@ -822,7 +942,7 @@ struct SPIRFunction : IVariant // On function entry, make sure to copy a constant array into thread addr space to work around // the case where we are passing a constant array by value to a function on backends which do not // consider arrays value types. - SmallVector constant_arrays_needed_on_stack; + SmallVector constant_arrays_needed_on_stack; bool active = false; bool flush_undeclared = true; @@ -838,7 +958,7 @@ struct SPIRAccessChain : IVariant type = TypeAccessChain }; - SPIRAccessChain(uint32_t basetype_, spv::StorageClass storage_, std::string base_, std::string dynamic_index_, + SPIRAccessChain(TypeID basetype_, spv::StorageClass storage_, std::string base_, std::string dynamic_index_, int32_t static_index_) : basetype(basetype_) , storage(storage_) @@ -853,20 +973,21 @@ struct SPIRAccessChain : IVariant // which has no usable buffer type ala GLSL SSBOs. // StructuredBuffer is too limited, so our only option is to deal with ByteAddressBuffer which works with raw addresses. - uint32_t basetype; + TypeID basetype; spv::StorageClass storage; std::string base; std::string dynamic_index; int32_t static_index; - uint32_t loaded_from = 0; + VariableID loaded_from = 0; uint32_t matrix_stride = 0; + uint32_t array_stride = 0; bool row_major_matrix = false; bool immutable = false; // By reading this expression, we implicitly read these expressions as well. // Used by access chain Store and Load since we read multiple expressions in this case. - SmallVector implied_read_expressions; + SmallVector implied_read_expressions; SPIRV_CROSS_DECLARE_CLONE(SPIRAccessChain) }; @@ -879,7 +1000,7 @@ struct SPIRVariable : IVariant }; SPIRVariable() = default; - SPIRVariable(uint32_t basetype_, spv::StorageClass storage_, uint32_t initializer_ = 0, uint32_t basevariable_ = 0) + SPIRVariable(TypeID basetype_, spv::StorageClass storage_, ID initializer_ = 0, VariableID basevariable_ = 0) : basetype(basetype_) , storage(storage_) , initializer(initializer_) @@ -887,11 +1008,11 @@ struct SPIRVariable : IVariant { } - uint32_t basetype = 0; + TypeID basetype = 0; spv::StorageClass storage = spv::StorageClassGeneric; uint32_t decoration = 0; - uint32_t initializer = 0; - uint32_t basevariable = 0; + ID initializer = 0; + VariableID basevariable = 0; SmallVector dereference_chain; bool compat_builtin = false; @@ -901,10 +1022,10 @@ struct SPIRVariable : IVariant // When we read the variable as an expression, just forward // shadowed_id as the expression. bool statically_assigned = false; - uint32_t static_expression = 0; + ID static_expression = 0; // Temporaries which can remain forwarded as long as this variable is not modified. - SmallVector dependees; + SmallVector dependees; bool forwardable = true; bool deferred_declaration = false; @@ -917,7 +1038,7 @@ struct SPIRVariable : IVariant uint32_t remapped_components = 0; // The block which dominates all access to this variable. - uint32_t dominator = 0; + BlockID dominator = 0; // If true, this variable is a loop variable, when accessing the variable // outside a loop, // we should statically forward it. @@ -951,15 +1072,12 @@ struct SPIRConstant : IVariant { Constant r[4]; // If != 0, this element is a specialization constant, and we should keep track of it as such. - uint32_t id[4]; + ID id[4]; uint32_t vecsize = 1; - // Workaround for MSVC 2013, initializing an array breaks. ConstantVector() { memset(r, 0, sizeof(r)); - for (unsigned i = 0; i < 4; i++) - id[i] = 0; } }; @@ -967,15 +1085,8 @@ struct SPIRConstant : IVariant { ConstantVector c[4]; // If != 0, this column is a specialization constant, and we should keep track of it as such. - uint32_t id[4]; + ID id[4]; uint32_t columns = 1; - - // Workaround for MSVC 2013, initializing an array breaks. - ConstantMatrix() - { - for (unsigned i = 0; i < 4; i++) - id[i] = 0; - } }; static inline float f16_to_f32(uint16_t u16_value) @@ -1139,16 +1250,18 @@ struct SPIRConstant : IVariant SPIRConstant() = default; - SPIRConstant(uint32_t constant_type_, const uint32_t *elements, uint32_t num_elements, bool specialized) + SPIRConstant(TypeID constant_type_, const uint32_t *elements, uint32_t num_elements, bool specialized) : constant_type(constant_type_) , specialization(specialized) { - subconstants.insert(std::end(subconstants), elements, elements + num_elements); + subconstants.reserve(num_elements); + for (uint32_t i = 0; i < num_elements; i++) + subconstants.push_back(elements[i]); specialization = specialized; } // Construct scalar (32-bit). - SPIRConstant(uint32_t constant_type_, uint32_t v0, bool specialized) + SPIRConstant(TypeID constant_type_, uint32_t v0, bool specialized) : constant_type(constant_type_) , specialization(specialized) { @@ -1158,7 +1271,7 @@ struct SPIRConstant : IVariant } // Construct scalar (64-bit). - SPIRConstant(uint32_t constant_type_, uint64_t v0, bool specialized) + SPIRConstant(TypeID constant_type_, uint64_t v0, bool specialized) : constant_type(constant_type_) , specialization(specialized) { @@ -1168,7 +1281,7 @@ struct SPIRConstant : IVariant } // Construct vectors and matrices. - SPIRConstant(uint32_t constant_type_, const SPIRConstant *const *vector_elements, uint32_t num_elements, + SPIRConstant(TypeID constant_type_, const SPIRConstant *const *vector_elements, uint32_t num_elements, bool specialized) : constant_type(constant_type_) , specialization(specialized) @@ -1200,7 +1313,7 @@ struct SPIRConstant : IVariant } } - uint32_t constant_type = 0; + TypeID constant_type = 0; ConstantMatrix m; // If this constant is a specialization constant (i.e. created with OpSpecConstant*). @@ -1212,7 +1325,7 @@ struct SPIRConstant : IVariant bool is_used_as_lut = false; // For composites which are constant arrays, etc. - SmallVector subconstants; + SmallVector subconstants; // Non-Vulkan GLSL, HLSL and sometimes MSL emits defines for each specialization constant, // and uses them to initialize the constant. This allows the user @@ -1347,9 +1460,9 @@ public: return type; } - uint32_t get_id() const + ID get_id() const { - return holder ? holder->self : 0; + return holder ? holder->self : ID(0); } bool empty() const @@ -1429,10 +1542,23 @@ enum ExtendedDecorations // Used for decorations like resource indices for samplers when part of combined image samplers. // A variable might need to hold two resource indices in this case. SPIRVCrossDecorationResourceIndexSecondary, + // Used for resource indices for multiplanar images when part of combined image samplers. + SPIRVCrossDecorationResourceIndexTertiary, + SPIRVCrossDecorationResourceIndexQuaternary, // Marks a buffer block for using explicit offsets (GLSL/HLSL). SPIRVCrossDecorationExplicitOffset, + // Apply to a variable in the Input storage class; marks it as holding the base group passed to vkCmdDispatchBase(). + // In MSL, this is used to adjust the WorkgroupId and GlobalInvocationId variables. + SPIRVCrossDecorationBuiltInDispatchBase, + + // Apply to a variable that is a function parameter; marks it as being a "dynamic" + // combined image-sampler. In MSL, this is used when a function parameter might hold + // either a regular combined image-sampler or one that has an attached sampler + // Y'CbCr conversion. + SPIRVCrossDecorationDynamicImageSampler, + SPIRVCrossDecorationCount }; @@ -1450,6 +1576,8 @@ struct Meta uint32_t set = 0; uint32_t binding = 0; uint32_t offset = 0; + uint32_t xfb_buffer = 0; + uint32_t xfb_stride = 0; uint32_t array_stride = 0; uint32_t matrix_stride = 0; uint32_t input_attachment = 0; @@ -1574,6 +1702,74 @@ static inline bool opcode_is_sign_invariant(spv::Op opcode) return false; } } + +struct SetBindingPair +{ + uint32_t desc_set; + uint32_t binding; + + inline bool operator==(const SetBindingPair &other) const + { + return desc_set == other.desc_set && binding == other.binding; + } + + inline bool operator<(const SetBindingPair &other) const + { + return desc_set < other.desc_set || (desc_set == other.desc_set && binding < other.binding); + } +}; + +struct StageSetBinding +{ + spv::ExecutionModel model; + uint32_t desc_set; + uint32_t binding; + + inline bool operator==(const StageSetBinding &other) const + { + return model == other.model && desc_set == other.desc_set && binding == other.binding; + } +}; + +struct InternalHasher +{ + inline size_t operator()(const SetBindingPair &value) const + { + // Quality of hash doesn't really matter here. + auto hash_set = std::hash()(value.desc_set); + auto hash_binding = std::hash()(value.binding); + return (hash_set * 0x10001b31) ^ hash_binding; + } + + inline size_t operator()(const StageSetBinding &value) const + { + // Quality of hash doesn't really matter here. + auto hash_model = std::hash()(value.model); + auto hash_set = std::hash()(value.desc_set); + auto tmp_hash = (hash_model * 0x10001b31) ^ hash_set; + return (tmp_hash * 0x10001b31) ^ value.binding; + } +}; + +// Special constant used in a {MSL,HLSL}ResourceBinding desc_set +// element to indicate the bindings for the push constants. +static const uint32_t ResourceBindingPushConstantDescriptorSet = ~(0u); + +// Special constant used in a {MSL,HLSL}ResourceBinding binding +// element to indicate the bindings for the push constants. +static const uint32_t ResourceBindingPushConstantBinding = 0; } // namespace SPIRV_CROSS_NAMESPACE +namespace std +{ +template +struct hash> +{ + size_t operator()(const SPIRV_CROSS_NAMESPACE::TypedID &value) const + { + return std::hash()(value); + } +}; +} // namespace std + #endif diff --git a/third_party/spirv-cross/spirv_cpp.cpp b/third_party/spirv-cross/spirv_cpp.cpp index 25966b32ad..53094d4e18 100644 --- a/third_party/spirv-cross/spirv_cpp.cpp +++ b/third_party/spirv-cross/spirv_cpp.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2015-2019 Arm Limited + * Copyright 2015-2020 Arm Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/third_party/spirv-cross/spirv_cpp.hpp b/third_party/spirv-cross/spirv_cpp.hpp index 4c20aa37b8..e78d0369f1 100644 --- a/third_party/spirv-cross/spirv_cpp.hpp +++ b/third_party/spirv-cross/spirv_cpp.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2015-2019 Arm Limited + * Copyright 2015-2020 Arm Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/third_party/spirv-cross/spirv_cross.cpp b/third_party/spirv-cross/spirv_cross.cpp index 715e514d59..071b8fb572 100644 --- a/third_party/spirv-cross/spirv_cross.cpp +++ b/third_party/spirv-cross/spirv_cross.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2015-2019 Arm Limited + * Copyright 2015-2020 Arm Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -88,6 +88,10 @@ bool Compiler::variable_storage_is_aliased(const SPIRVariable &v) bool Compiler::block_is_pure(const SPIRBlock &block) { + // This is a global side effect of the function. + if (block.terminator == SPIRBlock::Kill) + return false; + for (auto &i : block.ops) { auto ops = stream(i); @@ -156,6 +160,10 @@ bool Compiler::block_is_pure(const SPIRBlock &block) // OpExtInst is potentially impure depending on extension, but GLSL builtins are at least pure. + case OpDemoteToHelperInvocationEXT: + // This is a global side effect of the function. + return false; + default: break; } @@ -265,6 +273,15 @@ SPIRVariable *Compiler::maybe_get_backing_variable(uint32_t chain) return var; } +StorageClass Compiler::get_backing_variable_storage(uint32_t ptr) +{ + auto *var = maybe_get_backing_variable(ptr); + if (var) + return var->storage; + else + return expression_type(ptr).storage; +} + void Compiler::register_read(uint32_t expr, uint32_t chain, bool forwarded) { auto &e = get(expr); @@ -300,6 +317,8 @@ void Compiler::register_write(uint32_t chain) var = maybe_get(access_chain->loaded_from); } + auto &chain_type = expression_type(chain); + if (var) { bool check_argument_storage_qualifier = true; @@ -342,7 +361,7 @@ void Compiler::register_write(uint32_t chain) force_recompile(); } } - else + else if (chain_type.pointer) { // If we stored through a variable pointer, then we don't know which // variable we stored to. So *all* expressions after this point need to @@ -351,6 +370,9 @@ void Compiler::register_write(uint32_t chain) // only certain variables, we can invalidate only those. flush_all_active_variables(); } + + // If chain_type.pointer is false, we're not writing to memory backed variables, but temporaries instead. + // This can happen in copy_logical_type where we unroll complex reads and writes to temporaries. } void Compiler::flush_dependees(SPIRVariable &var) @@ -569,7 +591,7 @@ ShaderResources Compiler::get_shader_resources() const return get_shader_resources(nullptr); } -ShaderResources Compiler::get_shader_resources(const unordered_set &active_variables) const +ShaderResources Compiler::get_shader_resources(const unordered_set &active_variables) const { return get_shader_resources(&active_variables); } @@ -726,16 +748,16 @@ bool Compiler::InterfaceVariableAccessHandler::handle(Op opcode, const uint32_t return true; } -unordered_set Compiler::get_active_interface_variables() const +unordered_set Compiler::get_active_interface_variables() const { // Traverse the call graph and find all interface variables which are in use. - unordered_set variables; + unordered_set variables; InterfaceVariableAccessHandler handler(*this, variables); traverse_all_reachable_opcodes(get(ir.default_entry_point), handler); // Make sure we preserve output variables which are only initialized, but never accessed by any code. ir.for_each_typed_id([&](uint32_t, const SPIRVariable &var) { - if (var.storage == StorageClassOutput && var.initializer != 0) + if (var.storage == StorageClassOutput && var.initializer != ID(0)) variables.insert(var.self); }); @@ -746,13 +768,13 @@ unordered_set Compiler::get_active_interface_variables() const return variables; } -void Compiler::set_enabled_interface_variables(std::unordered_set active_variables) +void Compiler::set_enabled_interface_variables(std::unordered_set active_variables) { active_interface_variables = move(active_variables); check_active_interface_variables = true; } -ShaderResources Compiler::get_shader_resources(const unordered_set *active_variables) const +ShaderResources Compiler::get_shader_resources(const unordered_set *active_variables) const { ShaderResources res; @@ -969,17 +991,17 @@ void Compiler::update_name_cache(unordered_set &cache, string &name) update_name_cache(cache, cache, name); } -void Compiler::set_name(uint32_t id, const std::string &name) +void Compiler::set_name(ID id, const std::string &name) { ir.set_name(id, name); } -const SPIRType &Compiler::get_type(uint32_t id) const +const SPIRType &Compiler::get_type(TypeID id) const { return get(id); } -const SPIRType &Compiler::get_type_from_variable(uint32_t id) const +const SPIRType &Compiler::get_type_from_variable(VariableID id) const { return get(get(id).basetype); } @@ -1050,23 +1072,23 @@ bool Compiler::is_sampled_image_type(const SPIRType &type) type.image.dim != DimBuffer; } -void Compiler::set_member_decoration_string(uint32_t id, uint32_t index, spv::Decoration decoration, +void Compiler::set_member_decoration_string(TypeID id, uint32_t index, spv::Decoration decoration, const std::string &argument) { ir.set_member_decoration_string(id, index, decoration, argument); } -void Compiler::set_member_decoration(uint32_t id, uint32_t index, Decoration decoration, uint32_t argument) +void Compiler::set_member_decoration(TypeID id, uint32_t index, Decoration decoration, uint32_t argument) { ir.set_member_decoration(id, index, decoration, argument); } -void Compiler::set_member_name(uint32_t id, uint32_t index, const std::string &name) +void Compiler::set_member_name(TypeID id, uint32_t index, const std::string &name) { ir.set_member_name(id, index, name); } -const std::string &Compiler::get_member_name(uint32_t id, uint32_t index) const +const std::string &Compiler::get_member_name(TypeID id, uint32_t index) const { return ir.get_member_name(id, index); } @@ -1082,7 +1104,7 @@ void Compiler::set_member_qualified_name(uint32_t type_id, uint32_t index, const ir.meta[type_id].members[index].qualified_alias = name; } -const string &Compiler::get_member_qualified_name(uint32_t type_id, uint32_t index) const +const string &Compiler::get_member_qualified_name(TypeID type_id, uint32_t index) const { auto *m = ir.find_meta(type_id); if (m && index < m->members.size()) @@ -1091,32 +1113,32 @@ const string &Compiler::get_member_qualified_name(uint32_t type_id, uint32_t ind return ir.get_empty_string(); } -uint32_t Compiler::get_member_decoration(uint32_t id, uint32_t index, Decoration decoration) const +uint32_t Compiler::get_member_decoration(TypeID id, uint32_t index, Decoration decoration) const { return ir.get_member_decoration(id, index, decoration); } -const Bitset &Compiler::get_member_decoration_bitset(uint32_t id, uint32_t index) const +const Bitset &Compiler::get_member_decoration_bitset(TypeID id, uint32_t index) const { return ir.get_member_decoration_bitset(id, index); } -bool Compiler::has_member_decoration(uint32_t id, uint32_t index, Decoration decoration) const +bool Compiler::has_member_decoration(TypeID id, uint32_t index, Decoration decoration) const { return ir.has_member_decoration(id, index, decoration); } -void Compiler::unset_member_decoration(uint32_t id, uint32_t index, Decoration decoration) +void Compiler::unset_member_decoration(TypeID id, uint32_t index, Decoration decoration) { ir.unset_member_decoration(id, index, decoration); } -void Compiler::set_decoration_string(uint32_t id, spv::Decoration decoration, const std::string &argument) +void Compiler::set_decoration_string(ID id, spv::Decoration decoration, const std::string &argument) { ir.set_decoration_string(id, decoration, argument); } -void Compiler::set_decoration(uint32_t id, Decoration decoration, uint32_t argument) +void Compiler::set_decoration(ID id, Decoration decoration, uint32_t argument) { ir.set_decoration(id, decoration, argument); } @@ -1143,6 +1165,8 @@ static uint32_t get_default_extended_decoration(ExtendedDecorations decoration) { case SPIRVCrossDecorationResourceIndexPrimary: case SPIRVCrossDecorationResourceIndexSecondary: + case SPIRVCrossDecorationResourceIndexTertiary: + case SPIRVCrossDecorationResourceIndexQuaternary: case SPIRVCrossDecorationInterfaceMemberIndex: return ~(0u); @@ -1218,22 +1242,22 @@ void Compiler::unset_extended_member_decoration(uint32_t type, uint32_t index, E dec.extended.values[decoration] = 0; } -StorageClass Compiler::get_storage_class(uint32_t id) const +StorageClass Compiler::get_storage_class(VariableID id) const { return get(id).storage; } -const std::string &Compiler::get_name(uint32_t id) const +const std::string &Compiler::get_name(ID id) const { return ir.get_name(id); } -const std::string Compiler::get_fallback_name(uint32_t id) const +const std::string Compiler::get_fallback_name(ID id) const { return join("_", id); } -const std::string Compiler::get_block_fallback_name(uint32_t id) const +const std::string Compiler::get_block_fallback_name(VariableID id) const { auto &var = get(id); if (get_name(id).empty()) @@ -1242,37 +1266,37 @@ const std::string Compiler::get_block_fallback_name(uint32_t id) const return get_name(id); } -const Bitset &Compiler::get_decoration_bitset(uint32_t id) const +const Bitset &Compiler::get_decoration_bitset(ID id) const { return ir.get_decoration_bitset(id); } -bool Compiler::has_decoration(uint32_t id, Decoration decoration) const +bool Compiler::has_decoration(ID id, Decoration decoration) const { return ir.has_decoration(id, decoration); } -const string &Compiler::get_decoration_string(uint32_t id, Decoration decoration) const +const string &Compiler::get_decoration_string(ID id, Decoration decoration) const { return ir.get_decoration_string(id, decoration); } -const string &Compiler::get_member_decoration_string(uint32_t id, uint32_t index, Decoration decoration) const +const string &Compiler::get_member_decoration_string(TypeID id, uint32_t index, Decoration decoration) const { return ir.get_member_decoration_string(id, index, decoration); } -uint32_t Compiler::get_decoration(uint32_t id, Decoration decoration) const +uint32_t Compiler::get_decoration(ID id, Decoration decoration) const { return ir.get_decoration(id, decoration); } -void Compiler::unset_decoration(uint32_t id, Decoration decoration) +void Compiler::unset_decoration(ID id, Decoration decoration) { ir.unset_decoration(id, decoration); } -bool Compiler::get_binary_offset_for_decoration(uint32_t id, spv::Decoration decoration, uint32_t &word_offset) const +bool Compiler::get_binary_offset_for_decoration(VariableID id, spv::Decoration decoration, uint32_t &word_offset) const { auto *m = ir.find_meta(id); if (!m) @@ -1396,38 +1420,6 @@ bool Compiler::block_is_loop_candidate(const SPIRBlock &block, SPIRBlock::Method return false; } -bool Compiler::block_is_outside_flow_control_from_block(const SPIRBlock &from, const SPIRBlock &to) -{ - auto *start = &from; - - if (start->self == to.self) - return true; - - // Break cycles. - if (is_continue(start->self)) - return false; - - // If our select block doesn't merge, we must break or continue in these blocks, - // so if continues occur branchless within these blocks, consider them branchless as well. - // This is typically used for loop control. - if (start->terminator == SPIRBlock::Select && start->merge == SPIRBlock::MergeNone && - (block_is_outside_flow_control_from_block(get(start->true_block), to) || - block_is_outside_flow_control_from_block(get(start->false_block), to))) - { - return true; - } - else if (start->merge_block && block_is_outside_flow_control_from_block(get(start->merge_block), to)) - { - return true; - } - else if (start->next_block && block_is_outside_flow_control_from_block(get(start->next_block), to)) - { - return true; - } - else - return false; -} - bool Compiler::execution_is_noop(const SPIRBlock &from, const SPIRBlock &to) const { if (!execution_is_branchless(from, to)) @@ -1483,7 +1475,7 @@ SPIRBlock::ContinueBlockType Compiler::continue_block_type(const SPIRBlock &bloc if (block.merge == SPIRBlock::MergeLoop) return SPIRBlock::WhileLoop; - if (block.loop_dominator == SPIRBlock::NoDominator) + if (block.loop_dominator == BlockID(SPIRBlock::NoDominator)) { // Continue block is never reached from CFG. return SPIRBlock::ComplexLoop; @@ -1501,6 +1493,12 @@ SPIRBlock::ContinueBlockType Compiler::continue_block_type(const SPIRBlock &bloc const auto *true_block = maybe_get(block.true_block); const auto *merge_block = maybe_get(dominator.merge_block); + // If we need to flush Phi in this block, we cannot have a DoWhile loop. + bool flush_phi_to_false = false_block && flush_phi_required(block.self, block.false_block); + bool flush_phi_to_true = true_block && flush_phi_required(block.self, block.true_block); + if (flush_phi_to_false || flush_phi_to_true) + return SPIRBlock::ComplexLoop; + bool positive_do_while = block.true_block == dominator.self && (block.false_block == dominator.merge_block || (false_block && merge_block && execution_is_noop(*false_block, *merge_block))); @@ -1522,6 +1520,7 @@ SPIRBlock::ContinueBlockType Compiler::continue_block_type(const SPIRBlock &bloc bool Compiler::traverse_all_reachable_opcodes(const SPIRBlock &block, OpcodeHandler &handler) const { handler.set_current_block(block); + handler.rearm_current_block(block); // Ideally, perhaps traverse the CFG instead of all blocks in order to eliminate dead blocks, // but this shouldn't be a problem in practice unless the SPIR-V is doing insane things like recursing @@ -1545,6 +1544,8 @@ bool Compiler::traverse_all_reachable_opcodes(const SPIRBlock &block, OpcodeHand return false; if (!handler.end_function_scope(ops, i.length)) return false; + + handler.rearm_current_block(block); } } } @@ -1741,7 +1742,7 @@ bool Compiler::BufferAccessHandler::handle(Op opcode, const uint32_t *args, uint return true; } -SmallVector Compiler::get_active_buffer_ranges(uint32_t id) const +SmallVector Compiler::get_active_buffer_ranges(VariableID id) const { SmallVector ranges; BufferAccessHandler handler(*this, ranges, id); @@ -1834,19 +1835,19 @@ uint32_t Compiler::get_work_group_size_specialization_constants(SpecializationCo { auto &c = get(execution.workgroup_size.constant); - if (c.m.c[0].id[0] != 0) + if (c.m.c[0].id[0] != ID(0)) { x.id = c.m.c[0].id[0]; x.constant_id = get_decoration(c.m.c[0].id[0], DecorationSpecId); } - if (c.m.c[0].id[1] != 0) + if (c.m.c[0].id[1] != ID(0)) { y.id = c.m.c[0].id[1]; y.constant_id = get_decoration(c.m.c[0].id[1], DecorationSpecId); } - if (c.m.c[0].id[2] != 0) + if (c.m.c[0].id[2] != ID(0)) { z.id = c.m.c[0].id[2]; z.constant_id = get_decoration(c.m.c[0].id[2], DecorationSpecId); @@ -1901,36 +1902,36 @@ bool Compiler::is_tessellation_shader() const return is_tessellation_shader(get_execution_model()); } -void Compiler::set_remapped_variable_state(uint32_t id, bool remap_enable) +void Compiler::set_remapped_variable_state(VariableID id, bool remap_enable) { get(id).remapped_variable = remap_enable; } -bool Compiler::get_remapped_variable_state(uint32_t id) const +bool Compiler::get_remapped_variable_state(VariableID id) const { return get(id).remapped_variable; } -void Compiler::set_subpass_input_remapped_components(uint32_t id, uint32_t components) +void Compiler::set_subpass_input_remapped_components(VariableID id, uint32_t components) { get(id).remapped_components = components; } -uint32_t Compiler::get_subpass_input_remapped_components(uint32_t id) const +uint32_t Compiler::get_subpass_input_remapped_components(VariableID id) const { return get(id).remapped_components; } void Compiler::add_implied_read_expression(SPIRExpression &e, uint32_t source) { - auto itr = find(begin(e.implied_read_expressions), end(e.implied_read_expressions), source); + auto itr = find(begin(e.implied_read_expressions), end(e.implied_read_expressions), ID(source)); if (itr == end(e.implied_read_expressions)) e.implied_read_expressions.push_back(source); } void Compiler::add_implied_read_expression(SPIRAccessChain &e, uint32_t source) { - auto itr = find(begin(e.implied_read_expressions), end(e.implied_read_expressions), source); + auto itr = find(begin(e.implied_read_expressions), end(e.implied_read_expressions), ID(source)); if (itr == end(e.implied_read_expressions)) e.implied_read_expressions.push_back(source); } @@ -2071,7 +2072,7 @@ bool Compiler::interface_variable_exists_in_entry_point(uint32_t id) const return true; auto &execution = get_entry_point(); - return find(begin(execution.interface_variables), end(execution.interface_variables), id) != + return find(begin(execution.interface_variables), end(execution.interface_variables), VariableID(id)) != end(execution.interface_variables); } @@ -2151,8 +2152,8 @@ bool Compiler::CombinedImageSamplerHandler::end_function_scope(const uint32_t *a { for (auto ¶m : params) { - uint32_t image_id = param.global_image ? param.image_id : args[param.image_id]; - uint32_t sampler_id = param.global_sampler ? param.sampler_id : args[param.sampler_id]; + VariableID image_id = param.global_image ? param.image_id : VariableID(args[param.image_id]); + VariableID sampler_id = param.global_sampler ? param.sampler_id : VariableID(args[param.sampler_id]); auto *i = compiler.maybe_get_backing_variable(image_id); auto *s = compiler.maybe_get_backing_variable(sampler_id); @@ -2161,15 +2162,17 @@ bool Compiler::CombinedImageSamplerHandler::end_function_scope(const uint32_t *a if (s) sampler_id = s->self; - register_combined_image_sampler(caller, image_id, sampler_id, param.depth); + register_combined_image_sampler(caller, 0, image_id, sampler_id, param.depth); } } return true; } -void Compiler::CombinedImageSamplerHandler::register_combined_image_sampler(SPIRFunction &caller, uint32_t image_id, - uint32_t sampler_id, bool depth) +void Compiler::CombinedImageSamplerHandler::register_combined_image_sampler(SPIRFunction &caller, + VariableID combined_module_id, + VariableID image_id, VariableID sampler_id, + bool depth) { // We now have a texture ID and a sampler ID which will either be found as a global // or a parameter in our own function. If both are global, they will not need a parameter, @@ -2229,12 +2232,15 @@ void Compiler::CombinedImageSamplerHandler::register_combined_image_sampler(SPIR // Build new variable. compiler.set(combined_id, ptr_type_id, StorageClassFunction, 0); - // Inherit RelaxedPrecision (and potentially other useful flags if deemed relevant). - auto &new_flags = compiler.ir.meta[combined_id].decoration.decoration_flags; - auto &old_flags = compiler.ir.meta[sampler_id].decoration.decoration_flags; - new_flags.reset(); - if (old_flags.get(DecorationRelaxedPrecision)) - new_flags.set(DecorationRelaxedPrecision); + // Inherit RelaxedPrecision. + // If any of OpSampledImage, underlying image or sampler are marked, inherit the decoration. + bool relaxed_precision = + compiler.has_decoration(sampler_id, DecorationRelaxedPrecision) || + compiler.has_decoration(image_id, DecorationRelaxedPrecision) || + (combined_module_id && compiler.has_decoration(combined_module_id, DecorationRelaxedPrecision)); + + if (relaxed_precision) + compiler.set_decoration(combined_id, DecorationRelaxedPrecision); param.id = combined_id; @@ -2441,8 +2447,10 @@ bool Compiler::CombinedImageSamplerHandler::handle(Op opcode, const uint32_t *ar if (sampler) sampler_id = sampler->self; + uint32_t combined_id = args[1]; + auto &combined_type = compiler.get(args[0]); - register_combined_image_sampler(callee, image_id, sampler_id, combined_type.image.depth); + register_combined_image_sampler(callee, combined_id, image_id, sampler_id, combined_type.image.depth); } } @@ -2450,8 +2458,8 @@ bool Compiler::CombinedImageSamplerHandler::handle(Op opcode, const uint32_t *ar // This information is statically known from the current place in the call stack. // Function parameters are not necessarily pointers, so if we don't have a backing variable, remapping will know // which backing variable the image/sample came from. - uint32_t image_id = remap_parameter(args[2]); - uint32_t sampler_id = is_fetch ? compiler.dummy_sampler_id : remap_parameter(args[3]); + VariableID image_id = remap_parameter(args[2]); + VariableID sampler_id = is_fetch ? compiler.dummy_sampler_id : remap_parameter(args[3]); auto itr = find_if(begin(compiler.combined_image_samplers), end(compiler.combined_image_samplers), [image_id, sampler_id](const CombinedImageSampler &combined) { @@ -2461,6 +2469,7 @@ bool Compiler::CombinedImageSamplerHandler::handle(Op opcode, const uint32_t *ar if (itr == end(compiler.combined_image_samplers)) { uint32_t sampled_type; + uint32_t combined_module_id; if (is_fetch) { // Have to invent the sampled image type. @@ -2470,10 +2479,12 @@ bool Compiler::CombinedImageSamplerHandler::handle(Op opcode, const uint32_t *ar type.self = sampled_type; type.basetype = SPIRType::SampledImage; type.image.depth = false; + combined_module_id = 0; } else { sampled_type = args[0]; + combined_module_id = args[1]; } auto id = compiler.ir.increase_bound_by(2); @@ -2493,12 +2504,14 @@ bool Compiler::CombinedImageSamplerHandler::handle(Op opcode, const uint32_t *ar compiler.set(combined_id, type_id, StorageClassUniformConstant, 0); // Inherit RelaxedPrecision (and potentially other useful flags if deemed relevant). - auto &new_flags = compiler.ir.meta[combined_id].decoration.decoration_flags; - // Fetch inherits precision from the image, not sampler (there is no sampler). - auto &old_flags = compiler.ir.meta[is_fetch ? image_id : sampler_id].decoration.decoration_flags; - new_flags.reset(); - if (old_flags.get(DecorationRelaxedPrecision)) - new_flags.set(DecorationRelaxedPrecision); + // If any of OpSampledImage, underlying image or sampler are marked, inherit the decoration. + bool relaxed_precision = + (sampler_id && compiler.has_decoration(sampler_id, DecorationRelaxedPrecision)) || + (image_id && compiler.has_decoration(image_id, DecorationRelaxedPrecision)) || + (combined_module_id && compiler.has_decoration(combined_module_id, DecorationRelaxedPrecision)); + + if (relaxed_precision) + compiler.set_decoration(combined_id, DecorationRelaxedPrecision); // Propagate the array type for the original image as well. auto *var = compiler.maybe_get_backing_variable(image_id); @@ -2515,7 +2528,7 @@ bool Compiler::CombinedImageSamplerHandler::handle(Op opcode, const uint32_t *ar return true; } -uint32_t Compiler::build_dummy_sampler_for_combined_images() +VariableID Compiler::build_dummy_sampler_for_combined_images() { DummySamplerForCombinedImageHandler handler(*this); traverse_all_reachable_opcodes(get(ir.default_entry_point), handler); @@ -2569,12 +2582,12 @@ SmallVector Compiler::get_specialization_constants() con return spec_consts; } -SPIRConstant &Compiler::get_constant(uint32_t id) +SPIRConstant &Compiler::get_constant(ConstantID id) { return get(id); } -const SPIRConstant &Compiler::get_constant(uint32_t id) const +const SPIRConstant &Compiler::get_constant(ConstantID id) const { return get(id); } @@ -2721,6 +2734,12 @@ void Compiler::AnalyzeVariableScopeAccessHandler::notify_variable_access(uint32_ if (id == 0) return; + // Access chains used in multiple blocks mean hoisting all the variables used to construct the access chain as not all backends can use pointers. + auto itr = access_chain_children.find(id); + if (itr != end(access_chain_children)) + for (auto child_id : itr->second) + notify_variable_access(child_id, block); + if (id_is_phi_variable(id)) accessed_variables_to_block[id].insert(block); else if (id_is_potential_temporary(id)) @@ -2758,7 +2777,7 @@ bool Compiler::AnalyzeVariableScopeAccessHandler::handle(spv::Op op, const uint3 if (length < 2) return false; - uint32_t ptr = args[0]; + ID ptr = args[0]; auto *var = compiler.maybe_get_backing_variable(ptr); // If we store through an access chain, we have a partial write. @@ -2785,14 +2804,21 @@ bool Compiler::AnalyzeVariableScopeAccessHandler::handle(spv::Op op, const uint3 if (length < 3) return false; + // Access chains used in multiple blocks mean hoisting all the variables used to construct the access chain as not all backends can use pointers. uint32_t ptr = args[2]; auto *var = compiler.maybe_get(ptr); if (var) + { accessed_variables_to_block[var->self].insert(current_block->self); + access_chain_children[args[1]].insert(var->self); + } // args[2] might be another access chain we have to track use of. for (uint32_t i = 2; i < length; i++) + { notify_variable_access(args[i], current_block->self); + access_chain_children[args[1]].insert(args[i]); + } // Also keep track of the access chain pointer itself. // In exceptionally rare cases, we can end up with a case where @@ -2803,7 +2829,7 @@ bool Compiler::AnalyzeVariableScopeAccessHandler::handle(spv::Op op, const uint3 // The result of an access chain is a fixed expression and is not really considered a temporary. auto &e = compiler.set(args[1], "", args[0], true); auto *backing_variable = compiler.maybe_get_backing_variable(ptr); - e.loaded_from = backing_variable ? backing_variable->self : 0; + e.loaded_from = backing_variable ? VariableID(backing_variable->self) : VariableID(0); // Other backends might use SPIRAccessChain for this later. compiler.ir.ids[args[1]].set_allow_type_rewrite(); @@ -2816,8 +2842,8 @@ bool Compiler::AnalyzeVariableScopeAccessHandler::handle(spv::Op op, const uint3 if (length < 2) return false; - uint32_t lhs = args[0]; - uint32_t rhs = args[1]; + ID lhs = args[0]; + ID rhs = args[1]; auto *var = compiler.maybe_get_backing_variable(lhs); // If we store through an access chain, we have a partial write. @@ -2881,6 +2907,10 @@ bool Compiler::AnalyzeVariableScopeAccessHandler::handle(spv::Op op, const uint3 if (length < 3) return false; + // Return value may be a temporary. + if (compiler.get_type(args[0]).basetype != SPIRType::Void) + notify_variable_access(args[1], current_block->self); + length -= 3; args += 3; @@ -2901,9 +2931,6 @@ bool Compiler::AnalyzeVariableScopeAccessHandler::handle(spv::Op op, const uint3 // Might try to copy a Phi variable here. notify_variable_access(args[i], current_block->self); } - - // Return value may be a temporary. - notify_variable_access(args[1], current_block->self); break; } @@ -3182,7 +3209,8 @@ void Compiler::analyze_variable_scope(SPIRFunction &entry, AnalyzeVariableScopeA for (auto &var : handler.accessed_variables_to_block) { // Only deal with variables which are considered local variables in this function. - if (find(begin(entry.local_variables), end(entry.local_variables), var.first) == end(entry.local_variables)) + if (find(begin(entry.local_variables), end(entry.local_variables), VariableID(var.first)) == + end(entry.local_variables)) continue; DominatorBuilder builder(cfg); @@ -3223,7 +3251,7 @@ void Compiler::analyze_variable_scope(SPIRFunction &entry, AnalyzeVariableScopeA builder.lift_continue_block_dominator(); // Add it to a per-block list of variables. - uint32_t dominating_block = builder.get_dominator(); + BlockID dominating_block = builder.get_dominator(); // For variables whose dominating block is inside a loop, there is a risk that these variables // actually need to be preserved across loop iterations. We can express this by adding @@ -3241,7 +3269,7 @@ void Compiler::analyze_variable_scope(SPIRFunction &entry, AnalyzeVariableScopeA if (preserve) { // Find the outermost loop scope. - while (block->loop_dominator != SPIRBlock::NoDominator) + while (block->loop_dominator != BlockID(SPIRBlock::NoDominator)) block = &get(block->loop_dominator); if (block->self != dominating_block) @@ -3281,6 +3309,7 @@ void Compiler::analyze_variable_scope(SPIRFunction &entry, AnalyzeVariableScopeA DominatorBuilder builder(cfg); bool force_temporary = false; + bool used_in_header_hoisted_continue_block = false; // Figure out which block is dominating all accesses of those temporaries. auto &blocks = var.second; @@ -3288,25 +3317,27 @@ void Compiler::analyze_variable_scope(SPIRFunction &entry, AnalyzeVariableScopeA { builder.add_block(block); - // If a temporary is used in more than one block, we might have to lift continue block - // access up to loop header like we did for variables. if (blocks.size() != 1 && is_continue(block)) { + // The risk here is that inner loop can dominate the continue block. + // Any temporary we access in the continue block must be declared before the loop. + // This is moot for complex loops however. auto &loop_header_block = get(ir.continue_block_to_loop_header[block]); assert(loop_header_block.merge == SPIRBlock::MergeLoop); - - // Only relevant if the loop is not marked as complex. - if (!loop_header_block.complex_continue) - builder.add_block(loop_header_block.self); - } - else if (blocks.size() != 1 && is_single_block_loop(block)) - { - // Awkward case, because the loop header is also the continue block. - force_temporary = true; + builder.add_block(loop_header_block.self); + used_in_header_hoisted_continue_block = true; } } uint32_t dominating_block = builder.get_dominator(); + + if (blocks.size() != 1 && is_single_block_loop(dominating_block)) + { + // Awkward case, because the loop header is also the continue block, + // so hoisting to loop header does not help. + force_temporary = true; + } + if (dominating_block) { // If we touch a variable in the dominating block, this is the expected setup. @@ -3319,11 +3350,22 @@ void Compiler::analyze_variable_scope(SPIRFunction &entry, AnalyzeVariableScopeA { // Exceptionally rare case. // We cannot declare temporaries of access chains (except on MSL perhaps with pointers). - // Rather than do that, we force a complex loop to make sure access chains are created and consumed - // in expected order. - auto &loop_header_block = get(dominating_block); - assert(loop_header_block.merge == SPIRBlock::MergeLoop); - loop_header_block.complex_continue = true; + // Rather than do that, we force the indexing expressions to be declared in the right scope by + // tracking their usage to that end. There is no temporary to hoist. + // However, we still need to observe declaration order of the access chain. + + if (used_in_header_hoisted_continue_block) + { + // For this scenario, we used an access chain inside a continue block where we also registered an access to header block. + // This is a problem as we need to declare an access chain properly first with full definition. + // We cannot use temporaries for these expressions, + // so we must make sure the access chain is declared ahead of time. + // Force a complex for loop to deal with this. + // TODO: Out-of-order declaring for loops where continue blocks are emitted last might be another option. + auto &loop_header_block = get(dominating_block); + assert(loop_header_block.merge == SPIRBlock::MergeLoop); + loop_header_block.complex_continue = true; + } } else { @@ -3357,17 +3399,17 @@ void Compiler::analyze_variable_scope(SPIRFunction &entry, AnalyzeVariableScopeA { auto &var = get(loop_variable.first); auto dominator = var.dominator; - auto block = loop_variable.second; + BlockID block = loop_variable.second; // The variable was accessed in multiple continue blocks, ignore. - if (block == ~(0u) || block == 0) + if (block == BlockID(~(0u)) || block == BlockID(0)) continue; // Dead code. - if (dominator == 0) + if (dominator == ID(0)) continue; - uint32_t header = 0; + BlockID header = 0; // Find the loop header for this block if we are a continue block. { @@ -3426,10 +3468,11 @@ void Compiler::analyze_variable_scope(SPIRFunction &entry, AnalyzeVariableScopeA // merge can occur. Walk the CFG to see if we find anything. seen_blocks.clear(); - cfg.walk_from(seen_blocks, header_block.merge_block, [&](uint32_t walk_block) { + cfg.walk_from(seen_blocks, header_block.merge_block, [&](uint32_t walk_block) -> bool { // We found a block which accesses the variable outside the loop. if (blocks.find(walk_block) != end(blocks)) static_loop_init = false; + return true; }); if (!static_loop_init) @@ -3517,7 +3560,7 @@ bool Compiler::may_read_undefined_variable_in_block(const SPIRBlock &block, uint return true; } -Bitset Compiler::get_buffer_block_flags(uint32_t id) const +Bitset Compiler::get_buffer_block_flags(VariableID id) const { return ir.get_buffer_block_flags(get(id)); } @@ -3759,6 +3802,13 @@ void Compiler::analyze_image_and_sampler_usage() CombinedImageSamplerUsageHandler handler(*this, dref_handler.dref_combined_samplers); traverse_all_reachable_opcodes(get(ir.default_entry_point), handler); + + // Need to run this traversal twice. First time, we propagate any comparison sampler usage from leaf functions + // down to main(). + // In the second pass, we can propagate up forced depth state coming from main() up into leaf functions. + handler.dependency_hierarchy.clear(); + traverse_all_reachable_opcodes(get(ir.default_entry_point), handler); + comparison_ids = move(handler.comparison_ids); need_subpass_input = handler.need_subpass_input; @@ -3793,6 +3843,20 @@ bool Compiler::CombinedImageSamplerDrefHandler::handle(spv::Op opcode, const uin return true; } +const CFG &Compiler::get_cfg_for_current_function() const +{ + assert(current_function); + return get_cfg_for_function(current_function->self); +} + +const CFG &Compiler::get_cfg_for_function(uint32_t id) const +{ + auto cfg_itr = function_cfgs.find(id); + assert(cfg_itr != end(function_cfgs)); + assert(cfg_itr->second); + return *cfg_itr->second; +} + void Compiler::build_function_control_flow_graphs_and_analyze() { CFGBuilder handler(*this); @@ -3860,6 +3924,14 @@ bool Compiler::CFGBuilder::follow_function_call(const SPIRFunction &func) return false; } +void Compiler::CombinedImageSamplerUsageHandler::add_dependency(uint32_t dst, uint32_t src) +{ + dependency_hierarchy[dst].insert(src); + // Propagate up any comparison state if we're loading from one such variable. + if (comparison_ids.count(src)) + comparison_ids.insert(dst); +} + bool Compiler::CombinedImageSamplerUsageHandler::begin_function_scope(const uint32_t *args, uint32_t length) { if (length < 3) @@ -3872,7 +3944,7 @@ bool Compiler::CombinedImageSamplerUsageHandler::begin_function_scope(const uint for (uint32_t i = 0; i < length; i++) { auto &argument = func.arguments[i]; - dependency_hierarchy[argument.id].insert(arg[i]); + add_dependency(argument.id, arg[i]); } return true; @@ -3882,6 +3954,7 @@ void Compiler::CombinedImageSamplerUsageHandler::add_hierarchy_to_comparison_ids { // Traverse the variable dependency hierarchy and tag everything in its path with comparison ids. comparison_ids.insert(id); + for (auto &dep_id : dependency_hierarchy[id]) add_hierarchy_to_comparison_ids(dep_id); } @@ -3897,7 +3970,8 @@ bool Compiler::CombinedImageSamplerUsageHandler::handle(Op opcode, const uint32_ { if (length < 3) return false; - dependency_hierarchy[args[1]].insert(args[2]); + + add_dependency(args[1], args[2]); // Ideally defer this to OpImageRead, but then we'd need to track loaded IDs. // If we load an image, we're going to use it and there is little harm in declaring an unused gl_FragCoord. @@ -3919,14 +3993,17 @@ bool Compiler::CombinedImageSamplerUsageHandler::handle(Op opcode, const uint32_ uint32_t result_type = args[0]; uint32_t result_id = args[1]; auto &type = compiler.get(result_type); + + // If the underlying resource has been used for comparison then duplicate loads of that resource must be too. + // This image must be a depth image. + uint32_t image = args[2]; + uint32_t sampler = args[3]; + if (type.image.depth || dref_combined_samplers.count(result_id) != 0) { - // This image must be a depth image. - uint32_t image = args[2]; add_hierarchy_to_comparison_ids(image); // This sampler must be a SamplerComparisonState, and not a regular SamplerState. - uint32_t sampler = args[3]; add_hierarchy_to_comparison_ids(sampler); // Mark the OpSampledImage itself as being comparison state. @@ -3942,13 +4019,13 @@ bool Compiler::CombinedImageSamplerUsageHandler::handle(Op opcode, const uint32_ return true; } -bool Compiler::buffer_is_hlsl_counter_buffer(uint32_t id) const +bool Compiler::buffer_is_hlsl_counter_buffer(VariableID id) const { auto *m = ir.find_meta(id); return m && m->hlsl_is_magic_counter_buffer; } -bool Compiler::buffer_get_hlsl_counter_buffer(uint32_t id, uint32_t &counter_id) const +bool Compiler::buffer_get_hlsl_counter_buffer(VariableID id, uint32_t &counter_id) const { auto *m = ir.find_meta(id); @@ -4013,7 +4090,7 @@ const SmallVector &Compiler::get_declared_extensions() const return ir.declared_extensions; } -std::string Compiler::get_remapped_declared_block_name(uint32_t id) const +std::string Compiler::get_remapped_declared_block_name(VariableID id) const { return get_remapped_declared_block_name(id, false); } @@ -4238,6 +4315,316 @@ void Compiler::analyze_non_block_pointer_types() sort(begin(physical_storage_non_block_pointer_types), end(physical_storage_non_block_pointer_types)); } +bool Compiler::InterlockedResourceAccessPrepassHandler::handle(Op op, const uint32_t *, uint32_t) +{ + if (op == OpBeginInvocationInterlockEXT || op == OpEndInvocationInterlockEXT) + { + if (interlock_function_id != 0 && interlock_function_id != call_stack.back()) + { + // Most complex case, we have no sensible way of dealing with this + // other than taking the 100% conservative approach, exit early. + split_function_case = true; + return false; + } + else + { + interlock_function_id = call_stack.back(); + // If this call is performed inside control flow we have a problem. + auto &cfg = compiler.get_cfg_for_function(interlock_function_id); + + uint32_t from_block_id = compiler.get(interlock_function_id).entry_block; + bool outside_control_flow = cfg.node_terminates_control_flow_in_sub_graph(from_block_id, current_block_id); + if (!outside_control_flow) + control_flow_interlock = true; + } + } + return true; +} + +void Compiler::InterlockedResourceAccessPrepassHandler::rearm_current_block(const SPIRBlock &block) +{ + current_block_id = block.self; +} + +bool Compiler::InterlockedResourceAccessPrepassHandler::begin_function_scope(const uint32_t *args, uint32_t length) +{ + if (length < 3) + return false; + call_stack.push_back(args[2]); + return true; +} + +bool Compiler::InterlockedResourceAccessPrepassHandler::end_function_scope(const uint32_t *, uint32_t) +{ + call_stack.pop_back(); + return true; +} + +bool Compiler::InterlockedResourceAccessHandler::begin_function_scope(const uint32_t *args, uint32_t length) +{ + if (length < 3) + return false; + + if (args[2] == interlock_function_id) + call_stack_is_interlocked = true; + + call_stack.push_back(args[2]); + return true; +} + +bool Compiler::InterlockedResourceAccessHandler::end_function_scope(const uint32_t *, uint32_t) +{ + if (call_stack.back() == interlock_function_id) + call_stack_is_interlocked = false; + + call_stack.pop_back(); + return true; +} + +void Compiler::InterlockedResourceAccessHandler::access_potential_resource(uint32_t id) +{ + if ((use_critical_section && in_crit_sec) || (control_flow_interlock && call_stack_is_interlocked) || + split_function_case) + { + compiler.interlocked_resources.insert(id); + } +} + +bool Compiler::InterlockedResourceAccessHandler::handle(Op opcode, const uint32_t *args, uint32_t length) +{ + // Only care about critical section analysis if we have simple case. + if (use_critical_section) + { + if (opcode == OpBeginInvocationInterlockEXT) + { + in_crit_sec = true; + return true; + } + + if (opcode == OpEndInvocationInterlockEXT) + { + // End critical section--nothing more to do. + return false; + } + } + + // We need to figure out where images and buffers are loaded from, so do only the bare bones compilation we need. + switch (opcode) + { + case OpLoad: + { + if (length < 3) + return false; + + uint32_t ptr = args[2]; + auto *var = compiler.maybe_get_backing_variable(ptr); + + // We're only concerned with buffer and image memory here. + if (!var) + break; + + switch (var->storage) + { + default: + break; + + case StorageClassUniformConstant: + { + uint32_t result_type = args[0]; + uint32_t id = args[1]; + compiler.set(id, "", result_type, true); + compiler.register_read(id, ptr, true); + break; + } + + case StorageClassUniform: + // Must have BufferBlock; we only care about SSBOs. + if (!compiler.has_decoration(compiler.get(var->basetype).self, DecorationBufferBlock)) + break; + // fallthrough + case StorageClassStorageBuffer: + access_potential_resource(var->self); + break; + } + break; + } + + case OpInBoundsAccessChain: + case OpAccessChain: + case OpPtrAccessChain: + { + if (length < 3) + return false; + + uint32_t result_type = args[0]; + + auto &type = compiler.get(result_type); + if (type.storage == StorageClassUniform || type.storage == StorageClassUniformConstant || + type.storage == StorageClassStorageBuffer) + { + uint32_t id = args[1]; + uint32_t ptr = args[2]; + compiler.set(id, "", result_type, true); + compiler.register_read(id, ptr, true); + compiler.ir.ids[id].set_allow_type_rewrite(); + } + break; + } + + case OpImageTexelPointer: + { + if (length < 3) + return false; + + uint32_t result_type = args[0]; + uint32_t id = args[1]; + uint32_t ptr = args[2]; + auto &e = compiler.set(id, "", result_type, true); + auto *var = compiler.maybe_get_backing_variable(ptr); + if (var) + e.loaded_from = var->self; + break; + } + + case OpStore: + case OpImageWrite: + case OpAtomicStore: + { + if (length < 1) + return false; + + uint32_t ptr = args[0]; + auto *var = compiler.maybe_get_backing_variable(ptr); + if (var && (var->storage == StorageClassUniform || var->storage == StorageClassUniformConstant || + var->storage == StorageClassStorageBuffer)) + { + access_potential_resource(var->self); + } + + break; + } + + case OpCopyMemory: + { + if (length < 2) + return false; + + uint32_t dst = args[0]; + uint32_t src = args[1]; + auto *dst_var = compiler.maybe_get_backing_variable(dst); + auto *src_var = compiler.maybe_get_backing_variable(src); + + if (dst_var && (dst_var->storage == StorageClassUniform || dst_var->storage == StorageClassStorageBuffer)) + access_potential_resource(dst_var->self); + + if (src_var) + { + if (src_var->storage != StorageClassUniform && src_var->storage != StorageClassStorageBuffer) + break; + + if (src_var->storage == StorageClassUniform && + !compiler.has_decoration(compiler.get(src_var->basetype).self, DecorationBufferBlock)) + { + break; + } + + access_potential_resource(src_var->self); + } + + break; + } + + case OpImageRead: + case OpAtomicLoad: + { + if (length < 3) + return false; + + uint32_t ptr = args[2]; + auto *var = compiler.maybe_get_backing_variable(ptr); + + // We're only concerned with buffer and image memory here. + if (!var) + break; + + switch (var->storage) + { + default: + break; + + case StorageClassUniform: + // Must have BufferBlock; we only care about SSBOs. + if (!compiler.has_decoration(compiler.get(var->basetype).self, DecorationBufferBlock)) + break; + // fallthrough + case StorageClassUniformConstant: + case StorageClassStorageBuffer: + access_potential_resource(var->self); + break; + } + break; + } + + case OpAtomicExchange: + case OpAtomicCompareExchange: + case OpAtomicIIncrement: + case OpAtomicIDecrement: + case OpAtomicIAdd: + case OpAtomicISub: + case OpAtomicSMin: + case OpAtomicUMin: + case OpAtomicSMax: + case OpAtomicUMax: + case OpAtomicAnd: + case OpAtomicOr: + case OpAtomicXor: + { + if (length < 3) + return false; + + uint32_t ptr = args[2]; + auto *var = compiler.maybe_get_backing_variable(ptr); + if (var && (var->storage == StorageClassUniform || var->storage == StorageClassUniformConstant || + var->storage == StorageClassStorageBuffer)) + { + access_potential_resource(var->self); + } + + break; + } + + default: + break; + } + + return true; +} + +void Compiler::analyze_interlocked_resource_usage() +{ + if (get_execution_model() == ExecutionModelFragment && + (get_entry_point().flags.get(ExecutionModePixelInterlockOrderedEXT) || + get_entry_point().flags.get(ExecutionModePixelInterlockUnorderedEXT) || + get_entry_point().flags.get(ExecutionModeSampleInterlockOrderedEXT) || + get_entry_point().flags.get(ExecutionModeSampleInterlockUnorderedEXT))) + { + InterlockedResourceAccessPrepassHandler prepass_handler(*this, ir.default_entry_point); + traverse_all_reachable_opcodes(get(ir.default_entry_point), prepass_handler); + + InterlockedResourceAccessHandler handler(*this, ir.default_entry_point); + handler.interlock_function_id = prepass_handler.interlock_function_id; + handler.split_function_case = prepass_handler.split_function_case; + handler.control_flow_interlock = prepass_handler.control_flow_interlock; + handler.use_critical_section = !handler.split_function_case && !handler.control_flow_interlock; + + traverse_all_reachable_opcodes(get(ir.default_entry_point), handler); + + // For GLSL. If we hit any of these cases, we have to fall back to conservative approach. + interlocked_is_complex = + !handler.use_critical_section || handler.interlock_function_id != ir.default_entry_point; + } +} + bool Compiler::type_is_array_of_pointers(const SPIRType &type) const { if (!type.pointer) @@ -4246,3 +4633,12 @@ bool Compiler::type_is_array_of_pointers(const SPIRType &type) const // If parent type has same pointer depth, we must have an array of pointers. return type.pointer_depth == get(type.parent_type).pointer_depth; } + +bool Compiler::flush_phi_required(BlockID from, BlockID to) const +{ + auto &child = get(to); + for (auto &phi : child.phi_variables) + if (phi.parent == from) + return true; + return false; +} diff --git a/third_party/spirv-cross/spirv_cross.hpp b/third_party/spirv-cross/spirv_cross.hpp index deb757afe4..373f997627 100644 --- a/third_party/spirv-cross/spirv_cross.hpp +++ b/third_party/spirv-cross/spirv_cross.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2015-2019 Arm Limited + * Copyright 2015-2020 Arm Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,18 +27,18 @@ struct Resource { // Resources are identified with their SPIR-V ID. // This is the ID of the OpVariable. - uint32_t id; + ID id; // The type ID of the variable which includes arrays and all type modifications. // This type ID is not suitable for parsing OpMemberDecoration of a struct and other decorations in general // since these modifications typically happen on the base_type_id. - uint32_t type_id; + TypeID type_id; // The base type of the declared resource. // This type is the base type which ignores pointers and arrays of the type_id. // This is mostly useful to parse decorations of the underlying type. // base_type_id can also be obtained with get_type(get_type(type_id).self). - uint32_t base_type_id; + TypeID base_type_id; // The declared name (OpName) of the resource. // For Buffer blocks, the name actually reflects the externally @@ -77,17 +77,17 @@ struct ShaderResources struct CombinedImageSampler { // The ID of the sampler2D variable. - uint32_t combined_id; + VariableID combined_id; // The ID of the texture2D variable. - uint32_t image_id; + VariableID image_id; // The ID of the sampler variable. - uint32_t sampler_id; + VariableID sampler_id; }; struct SpecializationConstant { // The ID of the specialization constant. - uint32_t id; + ConstantID id; // The constant ID of the constant, used in Vulkan during pipeline creation. uint32_t constant_id; }; @@ -142,81 +142,81 @@ public: virtual std::string compile(); // Gets the identifier (OpName) of an ID. If not defined, an empty string will be returned. - const std::string &get_name(uint32_t id) const; + const std::string &get_name(ID id) const; // Applies a decoration to an ID. Effectively injects OpDecorate. - void set_decoration(uint32_t id, spv::Decoration decoration, uint32_t argument = 0); - void set_decoration_string(uint32_t id, spv::Decoration decoration, const std::string &argument); + void set_decoration(ID id, spv::Decoration decoration, uint32_t argument = 0); + void set_decoration_string(ID id, spv::Decoration decoration, const std::string &argument); // Overrides the identifier OpName of an ID. // Identifiers beginning with underscores or identifiers which contain double underscores // are reserved by the implementation. - void set_name(uint32_t id, const std::string &name); + void set_name(ID id, const std::string &name); // Gets a bitmask for the decorations which are applied to ID. // I.e. (1ull << spv::DecorationFoo) | (1ull << spv::DecorationBar) - const Bitset &get_decoration_bitset(uint32_t id) const; + const Bitset &get_decoration_bitset(ID id) const; // Returns whether the decoration has been applied to the ID. - bool has_decoration(uint32_t id, spv::Decoration decoration) const; + bool has_decoration(ID id, spv::Decoration decoration) const; // Gets the value for decorations which take arguments. // If the decoration is a boolean (i.e. spv::DecorationNonWritable), // 1 will be returned. // If decoration doesn't exist or decoration is not recognized, // 0 will be returned. - uint32_t get_decoration(uint32_t id, spv::Decoration decoration) const; - const std::string &get_decoration_string(uint32_t id, spv::Decoration decoration) const; + uint32_t get_decoration(ID id, spv::Decoration decoration) const; + const std::string &get_decoration_string(ID id, spv::Decoration decoration) const; // Removes the decoration for an ID. - void unset_decoration(uint32_t id, spv::Decoration decoration); + void unset_decoration(ID id, spv::Decoration decoration); // Gets the SPIR-V type associated with ID. // Mostly used with Resource::type_id and Resource::base_type_id to parse the underlying type of a resource. - const SPIRType &get_type(uint32_t id) const; + const SPIRType &get_type(TypeID id) const; // Gets the SPIR-V type of a variable. - const SPIRType &get_type_from_variable(uint32_t id) const; + const SPIRType &get_type_from_variable(VariableID id) const; // Gets the underlying storage class for an OpVariable. - spv::StorageClass get_storage_class(uint32_t id) const; + spv::StorageClass get_storage_class(VariableID id) const; // If get_name() is an empty string, get the fallback name which will be used // instead in the disassembled source. - virtual const std::string get_fallback_name(uint32_t id) const; + virtual const std::string get_fallback_name(ID id) const; // If get_name() of a Block struct is an empty string, get the fallback name. // This needs to be per-variable as multiple variables can use the same block type. - virtual const std::string get_block_fallback_name(uint32_t id) const; + virtual const std::string get_block_fallback_name(VariableID id) const; // Given an OpTypeStruct in ID, obtain the identifier for member number "index". // This may be an empty string. - const std::string &get_member_name(uint32_t id, uint32_t index) const; + const std::string &get_member_name(TypeID id, uint32_t index) const; // Given an OpTypeStruct in ID, obtain the OpMemberDecoration for member number "index". - uint32_t get_member_decoration(uint32_t id, uint32_t index, spv::Decoration decoration) const; - const std::string &get_member_decoration_string(uint32_t id, uint32_t index, spv::Decoration decoration) const; + uint32_t get_member_decoration(TypeID id, uint32_t index, spv::Decoration decoration) const; + const std::string &get_member_decoration_string(TypeID id, uint32_t index, spv::Decoration decoration) const; // Sets the member identifier for OpTypeStruct ID, member number "index". - void set_member_name(uint32_t id, uint32_t index, const std::string &name); + void set_member_name(TypeID id, uint32_t index, const std::string &name); // Returns the qualified member identifier for OpTypeStruct ID, member number "index", // or an empty string if no qualified alias exists - const std::string &get_member_qualified_name(uint32_t type_id, uint32_t index) const; + const std::string &get_member_qualified_name(TypeID type_id, uint32_t index) const; // Gets the decoration mask for a member of a struct, similar to get_decoration_mask. - const Bitset &get_member_decoration_bitset(uint32_t id, uint32_t index) const; + const Bitset &get_member_decoration_bitset(TypeID id, uint32_t index) const; // Returns whether the decoration has been applied to a member of a struct. - bool has_member_decoration(uint32_t id, uint32_t index, spv::Decoration decoration) const; + bool has_member_decoration(TypeID id, uint32_t index, spv::Decoration decoration) const; // Similar to set_decoration, but for struct members. - void set_member_decoration(uint32_t id, uint32_t index, spv::Decoration decoration, uint32_t argument = 0); - void set_member_decoration_string(uint32_t id, uint32_t index, spv::Decoration decoration, + void set_member_decoration(TypeID id, uint32_t index, spv::Decoration decoration, uint32_t argument = 0); + void set_member_decoration_string(TypeID id, uint32_t index, spv::Decoration decoration, const std::string &argument); // Unsets a member decoration, similar to unset_decoration. - void unset_member_decoration(uint32_t id, uint32_t index, spv::Decoration decoration); + void unset_member_decoration(TypeID id, uint32_t index, spv::Decoration decoration); // Gets the fallback name for a member, similar to get_fallback_name. virtual const std::string get_fallback_member_name(uint32_t index) const @@ -228,7 +228,7 @@ public: // SPIR-V shader. The granularity of this analysis is per-member of a struct. // This can be used for Buffer (UBO), BufferBlock/StorageBuffer (SSBO) and PushConstant blocks. // ID is the Resource::id obtained from get_shader_resources(). - SmallVector get_active_buffer_ranges(uint32_t id) const; + SmallVector get_active_buffer_ranges(VariableID id) const; // Returns the effective size of a buffer block. size_t get_declared_struct_size(const SPIRType &struct_type) const; @@ -256,12 +256,12 @@ public: // // To use the returned set as the filter for which variables are used during compilation, // this set can be moved to set_enabled_interface_variables(). - std::unordered_set get_active_interface_variables() const; + std::unordered_set get_active_interface_variables() const; // Sets the interface variables which are used during compilation. // By default, all variables are used. // Once set, compile() will only consider the set in active_variables. - void set_enabled_interface_variables(std::unordered_set active_variables); + void set_enabled_interface_variables(std::unordered_set active_variables); // Query shader resources, use ids with reflection interface to modify or query binding points, etc. ShaderResources get_shader_resources() const; @@ -269,19 +269,19 @@ public: // Query shader resources, but only return the variables which are part of active_variables. // E.g.: get_shader_resources(get_active_variables()) to only return the variables which are statically // accessed. - ShaderResources get_shader_resources(const std::unordered_set &active_variables) const; + ShaderResources get_shader_resources(const std::unordered_set &active_variables) const; // Remapped variables are considered built-in variables and a backend will // not emit a declaration for this variable. // This is mostly useful for making use of builtins which are dependent on extensions. - void set_remapped_variable_state(uint32_t id, bool remap_enable); - bool get_remapped_variable_state(uint32_t id) const; + void set_remapped_variable_state(VariableID id, bool remap_enable); + bool get_remapped_variable_state(VariableID id) const; // For subpassInput variables which are remapped to plain variables, // the number of components in the remapped // variable must be specified as the backing type of subpass inputs are opaque. - void set_subpass_input_remapped_components(uint32_t id, uint32_t components); - uint32_t get_subpass_input_remapped_components(uint32_t id) const; + void set_subpass_input_remapped_components(VariableID id, uint32_t components); + uint32_t get_subpass_input_remapped_components(VariableID id) const; // All operations work on the current entry point. // Entry points can be swapped out with set_entry_point(). @@ -315,6 +315,10 @@ public: const std::string &get_cleansed_entry_point_name(const std::string &name, spv::ExecutionModel execution_model) const; + // Traverses all reachable opcodes and sets active_builtins to a bitmask of all builtin variables which are accessed in the shader. + void update_active_builtins(); + bool has_active_builtin(spv::BuiltIn builtin, spv::StorageClass storage); + // Query and modify OpExecutionMode. const Bitset &get_execution_mode_bitset() const; @@ -362,7 +366,7 @@ public: // If the returned ID is non-zero, it can be decorated with set/bindings as desired before calling compile(). // Calling this function also invalidates get_active_interface_variables(), so this should be called // before that function. - uint32_t build_dummy_sampler_for_combined_images(); + VariableID build_dummy_sampler_for_combined_images(); // Analyzes all separate image and samplers used from the currently selected entry point, // and re-routes them all to a combined image sampler instead. @@ -411,8 +415,8 @@ public: // constant_type is the SPIRType for the specialization constant, // which can be queried to determine which fields in the unions should be poked at. SmallVector get_specialization_constants() const; - SPIRConstant &get_constant(uint32_t id); - const SPIRConstant &get_constant(uint32_t id) const; + SPIRConstant &get_constant(ConstantID id); + const SPIRConstant &get_constant(ConstantID id) const; uint32_t get_current_id_bound() const { @@ -435,7 +439,7 @@ public: // If the decoration was declared, sets the word_offset to an offset into the provided SPIR-V binary buffer and returns true, // otherwise, returns false. // If the decoration does not have any value attached to it (e.g. DecorationRelaxedPrecision), this function will also return false. - bool get_binary_offset_for_decoration(uint32_t id, spv::Decoration decoration, uint32_t &word_offset) const; + bool get_binary_offset_for_decoration(VariableID id, spv::Decoration decoration, uint32_t &word_offset) const; // HLSL counter buffer reflection interface. // Append/Consume/Increment/Decrement in HLSL is implemented as two "neighbor" buffer objects where @@ -450,7 +454,7 @@ public: // only return true if OpSource was reported HLSL. // To rely on this functionality, ensure that the SPIR-V module is not stripped. - bool buffer_is_hlsl_counter_buffer(uint32_t id) const; + bool buffer_is_hlsl_counter_buffer(VariableID id) const; // Queries if a buffer object has a neighbor "counter" buffer. // If so, the ID of that counter buffer will be returned in counter_id. @@ -458,7 +462,7 @@ public: // Otherwise, this query is purely based on OpName identifiers as found in the SPIR-V module, and will // only return true if OpSource was reported HLSL. // To rely on this functionality, ensure that the SPIR-V module is not stripped. - bool buffer_get_hlsl_counter_buffer(uint32_t id, uint32_t &counter_id) const; + bool buffer_get_hlsl_counter_buffer(VariableID id, uint32_t &counter_id) const; // Gets the list of all SPIR-V Capabilities which were declared in the SPIR-V module. const SmallVector &get_declared_capabilities() const; @@ -479,13 +483,13 @@ public: // ID is the name of a variable as returned by Resource::id, and must be a variable with a Block-like type. // // This also applies to HLSL cbuffers. - std::string get_remapped_declared_block_name(uint32_t id) const; + std::string get_remapped_declared_block_name(VariableID id) const; // For buffer block variables, get the decorations for that variable. // Sometimes, decorations for buffer blocks are found in member decorations instead // of direct decorations on the variable itself. // The most common use here is to check if a buffer is readonly or writeonly. - Bitset get_buffer_block_flags(uint32_t id) const; + Bitset get_buffer_block_flags(VariableID id) const; protected: const uint32_t *stream(const Instruction &instr) const @@ -509,7 +513,7 @@ protected: SPIRFunction *current_function = nullptr; SPIRBlock *current_block = nullptr; - std::unordered_set active_interface_variables; + std::unordered_set active_interface_variables; bool check_active_interface_variables = false; // If our IDs are out of range here as part of opcodes, throw instead of @@ -549,7 +553,9 @@ protected: template const T *maybe_get(uint32_t id) const { - if (ir.ids[id].get_type() == static_cast(T::type)) + if (id >= ir.ids.size()) + return nullptr; + else if (ir.ids[id].get_type() == static_cast(T::type)) return &get(id); else return nullptr; @@ -605,6 +611,7 @@ protected: bool expression_is_lvalue(uint32_t id) const; bool variable_storage_is_aliased(const SPIRVariable &var); SPIRVariable *maybe_get_backing_variable(uint32_t chain); + spv::StorageClass get_backing_variable_storage(uint32_t ptr); void register_read(uint32_t expr, uint32_t chain, bool forwarded); void register_write(uint32_t chain); @@ -617,7 +624,7 @@ protected: inline bool is_single_block_loop(uint32_t next) const { auto &block = get(next); - return block.merge == SPIRBlock::MergeLoop && block.continue_block == next; + return block.merge == SPIRBlock::MergeLoop && block.continue_block == ID(next); } inline bool is_break(uint32_t next) const @@ -657,7 +664,6 @@ protected: bool function_is_pure(const SPIRFunction &func); bool block_is_pure(const SPIRBlock &block); - bool block_is_outside_flow_control_from_block(const SPIRBlock &from, const SPIRBlock &to); bool execution_is_branchless(const SPIRBlock &from, const SPIRBlock &to) const; bool execution_is_direct_branch(const SPIRBlock &from, const SPIRBlock &to) const; @@ -710,6 +716,13 @@ protected: { } + // Called after returning from a function or when entering a block, + // can be called multiple times per block, + // while set_current_block is only called on block entry. + virtual void rearm_current_block(const SPIRBlock &) + { + } + virtual bool begin_function_scope(const uint32_t *, uint32_t) { return true; @@ -741,7 +754,7 @@ protected: struct InterfaceVariableAccessHandler : OpcodeHandler { - InterfaceVariableAccessHandler(const Compiler &compiler_, std::unordered_set &variables_) + InterfaceVariableAccessHandler(const Compiler &compiler_, std::unordered_set &variables_) : compiler(compiler_) , variables(variables_) { @@ -750,7 +763,7 @@ protected: bool handle(spv::Op opcode, const uint32_t *args, uint32_t length) override; const Compiler &compiler; - std::unordered_set &variables; + std::unordered_set &variables; }; struct CombinedImageSamplerHandler : OpcodeHandler @@ -772,8 +785,8 @@ protected: uint32_t remap_parameter(uint32_t id); void push_remap_parameters(const SPIRFunction &func, const uint32_t *args, uint32_t length); void pop_remap_parameters(); - void register_combined_image_sampler(SPIRFunction &caller, uint32_t texture_id, uint32_t sampler_id, - bool depth); + void register_combined_image_sampler(SPIRFunction &caller, VariableID combined_id, VariableID texture_id, + VariableID sampler_id, bool depth); }; struct DummySamplerForCombinedImageHandler : OpcodeHandler @@ -806,7 +819,7 @@ protected: // This must be an ordered data structure so we always pick the same type aliases. SmallVector global_struct_cache; - ShaderResources get_shader_resources(const std::unordered_set *active_variables) const; + ShaderResources get_shader_resources(const std::unordered_set *active_variables) const; VariableTypeRemapCallback variable_remap_callback; @@ -816,6 +829,7 @@ protected: std::unordered_set forwarded_temporaries; std::unordered_set suppressed_usage_tracking; std::unordered_set hoisted_temporaries; + std::unordered_set forced_invariant_temporaries; Bitset active_input_builtins; Bitset active_output_builtins; @@ -823,10 +837,6 @@ protected: uint32_t cull_distance_count = 0; bool position_invariant = false; - // Traverses all reachable opcodes and sets active_builtins to a bitmask of all builtin variables which are accessed in the shader. - void update_active_builtins(); - bool has_active_builtin(spv::BuiltIn builtin, spv::StorageClass storage); - void analyze_parameter_preservation( SPIRFunction &entry, const CFG &cfg, const std::unordered_map> &variable_to_blocks, @@ -878,13 +888,17 @@ protected: void add_hierarchy_to_comparison_ids(uint32_t ids); bool need_subpass_input = false; + void add_dependency(uint32_t dst, uint32_t src); }; void build_function_control_flow_graphs_and_analyze(); std::unordered_map> function_cfgs; + const CFG &get_cfg_for_current_function() const; + const CFG &get_cfg_for_function(uint32_t id) const; + struct CFGBuilder : OpcodeHandler { - CFGBuilder(Compiler &compiler_); + explicit CFGBuilder(Compiler &compiler_); bool follow_function_call(const SPIRFunction &func) override; bool handle(spv::Op op, const uint32_t *args, uint32_t length) override; @@ -912,6 +926,8 @@ protected: std::unordered_map> complete_write_variables_to_block; std::unordered_map> partial_write_variables_to_block; std::unordered_set access_chain_expressions; + // Access chains used in multiple blocks mean hoisting all the variables used to construct the access chain as not all backends can use pointers. + std::unordered_map> access_chain_children; const SPIRBlock *current_block = nullptr; }; @@ -929,7 +945,7 @@ protected: struct PhysicalStorageBufferPointerHandler : OpcodeHandler { - PhysicalStorageBufferPointerHandler(Compiler &compiler_); + explicit PhysicalStorageBufferPointerHandler(Compiler &compiler_); bool handle(spv::Op op, const uint32_t *args, uint32_t length) override; Compiler &compiler; std::unordered_set types; @@ -942,6 +958,61 @@ protected: bool single_function); bool may_read_undefined_variable_in_block(const SPIRBlock &block, uint32_t var); + // Finds all resources that are written to from inside the critical section, if present. + // The critical section is delimited by OpBeginInvocationInterlockEXT and + // OpEndInvocationInterlockEXT instructions. In MSL and HLSL, any resources written + // while inside the critical section must be placed in a raster order group. + struct InterlockedResourceAccessHandler : OpcodeHandler + { + InterlockedResourceAccessHandler(Compiler &compiler_, uint32_t entry_point_id) + : compiler(compiler_) + { + call_stack.push_back(entry_point_id); + } + + bool handle(spv::Op op, const uint32_t *args, uint32_t length) override; + bool begin_function_scope(const uint32_t *args, uint32_t length) override; + bool end_function_scope(const uint32_t *args, uint32_t length) override; + + Compiler &compiler; + bool in_crit_sec = false; + + uint32_t interlock_function_id = 0; + bool split_function_case = false; + bool control_flow_interlock = false; + bool use_critical_section = false; + bool call_stack_is_interlocked = false; + SmallVector call_stack; + + void access_potential_resource(uint32_t id); + }; + + struct InterlockedResourceAccessPrepassHandler : OpcodeHandler + { + InterlockedResourceAccessPrepassHandler(Compiler &compiler_, uint32_t entry_point_id) + : compiler(compiler_) + { + call_stack.push_back(entry_point_id); + } + + void rearm_current_block(const SPIRBlock &block) override; + bool handle(spv::Op op, const uint32_t *args, uint32_t length) override; + bool begin_function_scope(const uint32_t *args, uint32_t length) override; + bool end_function_scope(const uint32_t *args, uint32_t length) override; + + Compiler &compiler; + uint32_t interlock_function_id = 0; + uint32_t current_block_id = 0; + bool split_function_case = false; + bool control_flow_interlock = false; + SmallVector call_stack; + }; + + void analyze_interlocked_resource_usage(); + // The set of all resources written while inside the critical section, if present. + std::unordered_set interlocked_resources; + bool interlocked_is_complex = false; + void make_constant_null(uint32_t id, uint32_t type); std::unordered_map declared_block_names; @@ -972,6 +1043,8 @@ protected: bool reflection_ssbo_instance_name_is_significant() const; std::string get_remapped_declared_block_name(uint32_t id, bool fallback_prefer_instance_name) const; + bool flush_phi_required(BlockID from, BlockID to) const; + private: // Used only to implement the old deprecated get_entry_point() interface. const SPIREntryPoint &get_first_entry_point(const std::string &name) const; diff --git a/third_party/spirv-cross/spirv_cross_c.cpp b/third_party/spirv-cross/spirv_cross_c.cpp index 7add2685e9..3b1139f3ef 100644 --- a/third_party/spirv-cross/spirv_cross_c.cpp +++ b/third_party/spirv-cross/spirv_cross_c.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2019 Hans-Kristian Arntzen + * Copyright 2019-2020 Hans-Kristian Arntzen * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -162,7 +162,7 @@ struct spvc_compiler_options_s : ScratchMemoryAllocation struct spvc_set_s : ScratchMemoryAllocation { - std::unordered_set set; + std::unordered_set set; }; // Dummy-inherit to we can keep our opaque type handle type safe in C-land as well, @@ -420,6 +420,9 @@ spvc_result spvc_compiler_options_set_uint(spvc_compiler_options options, spvc_c case SPVC_COMPILER_OPTION_EMIT_LINE_DIRECTIVES: options->glsl.emit_line_directives = value != 0; break; + case SPVC_COMPILER_OPTION_ENABLE_STORAGE_IMAGE_QUALIFIER_DEDUCTION: + options->glsl.enable_storage_image_qualifier_deduction = value != 0; + break; case SPVC_COMPILER_OPTION_GLSL_SUPPORT_NONZERO_BASE_INSTANCE: options->glsl.vertex.support_nonzero_base_instance = value != 0; @@ -471,6 +474,10 @@ spvc_result spvc_compiler_options_set_uint(spvc_compiler_options options, spvc_c case SPVC_COMPILER_OPTION_HLSL_SUPPORT_NONZERO_BASE_VERTEX_BASE_INSTANCE: options->hlsl.support_nonzero_base_vertex_base_instance = value != 0; break; + + case SPVC_COMPILER_OPTION_HLSL_FORCE_STORAGE_BUFFER_AS_UAV: + options->hlsl.force_storage_buffer_as_uav = value != 0; + break; #endif #if SPIRV_CROSS_C_API_MSL @@ -545,6 +552,62 @@ spvc_result spvc_compiler_options_set_uint(spvc_compiler_options options, spvc_c case SPVC_COMPILER_OPTION_MSL_BUFFER_SIZE_BUFFER_INDEX: options->msl.buffer_size_buffer_index = value; break; + + case SPVC_COMPILER_OPTION_MSL_MULTIVIEW: + options->msl.multiview = value != 0; + break; + + case SPVC_COMPILER_OPTION_MSL_VIEW_MASK_BUFFER_INDEX: + options->msl.view_mask_buffer_index = value; + break; + + case SPVC_COMPILER_OPTION_MSL_DEVICE_INDEX: + options->msl.device_index = value; + break; + + case SPVC_COMPILER_OPTION_MSL_VIEW_INDEX_FROM_DEVICE_INDEX: + options->msl.view_index_from_device_index = value != 0; + break; + + case SPVC_COMPILER_OPTION_MSL_DISPATCH_BASE: + options->msl.dispatch_base = value != 0; + break; + + case SPVC_COMPILER_OPTION_MSL_DYNAMIC_OFFSETS_BUFFER_INDEX: + options->msl.dynamic_offsets_buffer_index = value; + break; + + case SPVC_COMPILER_OPTION_MSL_TEXTURE_1D_AS_2D: + options->msl.texture_1D_as_2D = value != 0; + break; + + case SPVC_COMPILER_OPTION_MSL_ENABLE_BASE_INDEX_ZERO: + options->msl.enable_base_index_zero = value != 0; + break; + + case SPVC_COMPILER_OPTION_MSL_IOS_FRAMEBUFFER_FETCH_SUBPASS: + options->msl.ios_use_framebuffer_fetch_subpasses = value != 0; + break; + + case SPVC_COMPILER_OPTION_MSL_INVARIANT_FP_MATH: + options->msl.invariant_float_math = value != 0; + break; + + case SPVC_COMPILER_OPTION_MSL_EMULATE_CUBEMAP_ARRAY: + options->msl.emulate_cube_array = value != 0; + break; + + case SPVC_COMPILER_OPTION_MSL_ENABLE_DECORATION_BINDING: + options->msl.enable_decoration_binding = value != 0; + break; + + case SPVC_COMPILER_OPTION_MSL_FORCE_ACTIVE_ARGUMENT_BUFFER_RESOURCES: + options->msl.force_active_argument_buffer_resources = value != 0; + break; + + case SPVC_COMPILER_OPTION_MSL_FORCE_NATIVE_ARRAYS: + options->msl.force_native_arrays = value != 0; + break; #endif default: @@ -721,6 +784,80 @@ spvc_variable_id spvc_compiler_hlsl_remap_num_workgroups_builtin(spvc_compiler c #endif } +spvc_result spvc_compiler_hlsl_set_resource_binding_flags(spvc_compiler compiler, + spvc_hlsl_binding_flags flags) +{ +#if SPIRV_CROSS_C_API_HLSL + if (compiler->backend != SPVC_BACKEND_HLSL) + { + compiler->context->report_error("HLSL function used on a non-HLSL backend."); + return SPVC_ERROR_INVALID_ARGUMENT; + } + + auto &hlsl = *static_cast(compiler->compiler.get()); + hlsl.set_resource_binding_flags(flags); + return SPVC_SUCCESS; +#else + (void)flags; + compiler->context->report_error("HLSL function used on a non-HLSL backend."); + return SPVC_ERROR_INVALID_ARGUMENT; +#endif +} + +spvc_result spvc_compiler_hlsl_add_resource_binding(spvc_compiler compiler, + const spvc_hlsl_resource_binding *binding) +{ +#if SPIRV_CROSS_C_API_HLSL + if (compiler->backend != SPVC_BACKEND_HLSL) + { + compiler->context->report_error("HLSL function used on a non-HLSL backend."); + return SPVC_ERROR_INVALID_ARGUMENT; + } + + auto &hlsl = *static_cast(compiler->compiler.get()); + HLSLResourceBinding bind; + bind.binding = binding->binding; + bind.desc_set = binding->desc_set; + bind.stage = static_cast(binding->stage); + bind.cbv.register_binding = binding->cbv.register_binding; + bind.cbv.register_space = binding->cbv.register_space; + bind.uav.register_binding = binding->uav.register_binding; + bind.uav.register_space = binding->uav.register_space; + bind.srv.register_binding = binding->srv.register_binding; + bind.srv.register_space = binding->srv.register_space; + bind.sampler.register_binding = binding->sampler.register_binding; + bind.sampler.register_space = binding->sampler.register_space; + hlsl.add_hlsl_resource_binding(bind); + return SPVC_SUCCESS; +#else + (void)binding; + compiler->context->report_error("HLSL function used on a non-HLSL backend."); + return SPVC_ERROR_INVALID_ARGUMENT; +#endif +} + +spvc_bool spvc_compiler_hlsl_is_resource_used(spvc_compiler compiler, SpvExecutionModel model, unsigned set, + unsigned binding) +{ +#if SPIRV_CROSS_C_API_HLSL + if (compiler->backend != SPVC_BACKEND_HLSL) + { + compiler->context->report_error("HLSL function used on a non-HLSL backend."); + return SPVC_FALSE; + } + + auto &hlsl = *static_cast(compiler->compiler.get()); + return hlsl.is_hlsl_resource_binding_used(static_cast(model), set, binding) ? SPVC_TRUE : + SPVC_FALSE; +#else + (void)model; + (void)set; + (void)binding; + compiler->context->report_error("HLSL function used on a non-HLSL backend."); + return SPVC_FALSE; +#endif +} + spvc_bool spvc_compiler_msl_is_rasterization_disabled(spvc_compiler compiler) { #if SPIRV_CROSS_C_API_MSL @@ -882,6 +1019,47 @@ spvc_result spvc_compiler_msl_add_resource_binding(spvc_compiler compiler, #endif } +spvc_result spvc_compiler_msl_add_dynamic_buffer(spvc_compiler compiler, unsigned desc_set, unsigned binding, unsigned index) +{ +#if SPIRV_CROSS_C_API_MSL + if (compiler->backend != SPVC_BACKEND_MSL) + { + compiler->context->report_error("MSL function used on a non-MSL backend."); + return SPVC_ERROR_INVALID_ARGUMENT; + } + + auto &msl = *static_cast(compiler->compiler.get()); + msl.add_dynamic_buffer(desc_set, binding, index); + return SPVC_SUCCESS; +#else + (void)binding; + (void)desc_set; + (void)index; + compiler->context->report_error("MSL function used on a non-MSL backend."); + return SPVC_ERROR_INVALID_ARGUMENT; +#endif +} + +spvc_result spvc_compiler_msl_add_inline_uniform_block(spvc_compiler compiler, unsigned desc_set, unsigned binding) +{ +#if SPIRV_CROSS_C_API_MSL + if (compiler->backend != SPVC_BACKEND_MSL) + { + compiler->context->report_error("MSL function used on a non-MSL backend."); + return SPVC_ERROR_INVALID_ARGUMENT; + } + + auto &msl = *static_cast(compiler->compiler.get()); + msl.add_inline_uniform_block(desc_set, binding); + return SPVC_SUCCESS; +#else + (void)binding; + (void)desc_set; + compiler->context->report_error("MSL function used on a non-MSL backend."); + return SPVC_ERROR_INVALID_ARGUMENT; +#endif +} + spvc_result spvc_compiler_msl_add_discrete_descriptor_set(spvc_compiler compiler, unsigned desc_set) { #if SPIRV_CROSS_C_API_MSL @@ -901,6 +1079,26 @@ spvc_result spvc_compiler_msl_add_discrete_descriptor_set(spvc_compiler compiler #endif } +spvc_result spvc_compiler_msl_set_argument_buffer_device_address_space(spvc_compiler compiler, unsigned desc_set, spvc_bool device_address) +{ +#if SPIRV_CROSS_C_API_MSL + if (compiler->backend != SPVC_BACKEND_MSL) + { + compiler->context->report_error("MSL function used on a non-MSL backend."); + return SPVC_ERROR_INVALID_ARGUMENT; + } + + auto &msl = *static_cast(compiler->compiler.get()); + msl.set_argument_buffer_device_address_space(desc_set, bool(device_address)); + return SPVC_SUCCESS; +#else + (void)desc_set; + (void)device_address; + compiler->context->report_error("MSL function used on a non-MSL backend."); + return SPVC_ERROR_INVALID_ARGUMENT; +#endif +} + spvc_bool spvc_compiler_msl_is_vertex_attribute_used(spvc_compiler compiler, unsigned location) { #if SPIRV_CROSS_C_API_MSL @@ -960,6 +1158,22 @@ static void spvc_convert_msl_sampler(MSLConstexprSampler &samp, const spvc_msl_c samp.coord = static_cast(sampler->coord); samp.border_color = static_cast(sampler->border_color); } + +static void spvc_convert_msl_sampler_ycbcr_conversion(MSLConstexprSampler &samp, const spvc_msl_sampler_ycbcr_conversion *conv) +{ + samp.ycbcr_conversion_enable = conv != nullptr; + if (conv == nullptr) return; + samp.planes = conv->planes; + samp.resolution = static_cast(conv->resolution); + samp.chroma_filter = static_cast(conv->chroma_filter); + samp.x_chroma_offset = static_cast(conv->x_chroma_offset); + samp.y_chroma_offset = static_cast(conv->y_chroma_offset); + for (int i = 0; i < 4; i++) + samp.swizzle[i] = static_cast(conv->swizzle[i]); + samp.ycbcr_model = static_cast(conv->ycbcr_model); + samp.ycbcr_range = static_cast(conv->ycbcr_range); + samp.bpc = conv->bpc; +} #endif spvc_result spvc_compiler_msl_remap_constexpr_sampler(spvc_compiler compiler, spvc_variable_id id, @@ -1010,6 +1224,60 @@ spvc_result spvc_compiler_msl_remap_constexpr_sampler_by_binding(spvc_compiler c #endif } +spvc_result spvc_compiler_msl_remap_constexpr_sampler_ycbcr(spvc_compiler compiler, spvc_variable_id id, + const spvc_msl_constexpr_sampler *sampler, + const spvc_msl_sampler_ycbcr_conversion *conv) +{ +#if SPIRV_CROSS_C_API_MSL + if (compiler->backend != SPVC_BACKEND_MSL) + { + compiler->context->report_error("MSL function used on a non-MSL backend."); + return SPVC_ERROR_INVALID_ARGUMENT; + } + + auto &msl = *static_cast(compiler->compiler.get()); + MSLConstexprSampler samp; + spvc_convert_msl_sampler(samp, sampler); + spvc_convert_msl_sampler_ycbcr_conversion(samp, conv); + msl.remap_constexpr_sampler(id, samp); + return SPVC_SUCCESS; +#else + (void)id; + (void)sampler; + (void)conv; + compiler->context->report_error("MSL function used on a non-MSL backend."); + return SPVC_ERROR_INVALID_ARGUMENT; +#endif +} + +spvc_result spvc_compiler_msl_remap_constexpr_sampler_by_binding_ycbcr(spvc_compiler compiler, + unsigned desc_set, unsigned binding, + const spvc_msl_constexpr_sampler *sampler, + const spvc_msl_sampler_ycbcr_conversion *conv) +{ +#if SPIRV_CROSS_C_API_MSL + if (compiler->backend != SPVC_BACKEND_MSL) + { + compiler->context->report_error("MSL function used on a non-MSL backend."); + return SPVC_ERROR_INVALID_ARGUMENT; + } + + auto &msl = *static_cast(compiler->compiler.get()); + MSLConstexprSampler samp; + spvc_convert_msl_sampler(samp, sampler); + spvc_convert_msl_sampler_ycbcr_conversion(samp, conv); + msl.remap_constexpr_sampler_by_binding(desc_set, binding, samp); + return SPVC_SUCCESS; +#else + (void)desc_set; + (void)binding; + (void)sampler; + (void)conv; + compiler->context->report_error("MSL function used on a non-MSL backend."); + return SPVC_ERROR_INVALID_ARGUMENT; +#endif +} + spvc_result spvc_compiler_msl_set_fragment_output_components(spvc_compiler compiler, unsigned location, unsigned components) { @@ -1504,6 +1772,11 @@ spvc_type spvc_compiler_get_type_handle(spvc_compiler compiler, spvc_type_id id) SPVC_END_SAFE_SCOPE(compiler->context, nullptr) } +spvc_type_id spvc_type_get_base_type_id(spvc_type type) +{ + return type->self; +} + static spvc_basetype convert_basetype(SPIRType::BaseType type) { // For now the enums match up. @@ -1973,6 +2246,26 @@ void spvc_msl_resource_binding_init(spvc_msl_resource_binding *binding) #endif } +void spvc_hlsl_resource_binding_init(spvc_hlsl_resource_binding *binding) +{ +#if SPIRV_CROSS_C_API_HLSL + HLSLResourceBinding binding_default; + binding->desc_set = binding_default.desc_set; + binding->binding = binding_default.binding; + binding->cbv.register_binding = binding_default.cbv.register_binding; + binding->cbv.register_space = binding_default.cbv.register_space; + binding->srv.register_binding = binding_default.srv.register_binding; + binding->srv.register_space = binding_default.srv.register_space; + binding->uav.register_binding = binding_default.uav.register_binding; + binding->uav.register_space = binding_default.uav.register_space; + binding->sampler.register_binding = binding_default.sampler.register_binding; + binding->sampler.register_space = binding_default.sampler.register_space; + binding->stage = static_cast(binding_default.stage); +#else + memset(binding, 0, sizeof(*binding)); +#endif +} + void spvc_msl_constexpr_sampler_init(spvc_msl_constexpr_sampler *sampler) { #if SPIRV_CROSS_C_API_MSL @@ -1997,6 +2290,24 @@ void spvc_msl_constexpr_sampler_init(spvc_msl_constexpr_sampler *sampler) #endif } +void spvc_msl_sampler_ycbcr_conversion_init(spvc_msl_sampler_ycbcr_conversion *conv) +{ +#if SPIRV_CROSS_C_API_MSL + MSLConstexprSampler defaults; + conv->planes = defaults.planes; + conv->resolution = static_cast(defaults.resolution); + conv->chroma_filter = static_cast(defaults.chroma_filter); + conv->x_chroma_offset = static_cast(defaults.x_chroma_offset); + conv->y_chroma_offset = static_cast(defaults.y_chroma_offset); + for (int i = 0; i < 4; i++) + conv->swizzle[i] = static_cast(defaults.swizzle[i]); + conv->ycbcr_model = static_cast(defaults.ycbcr_model); + conv->ycbcr_range = static_cast(defaults.ycbcr_range); +#else + memset(conv, 0, sizeof(*conv)); +#endif +} + unsigned spvc_compiler_get_current_id_bound(spvc_compiler compiler) { return compiler->compiler->get_current_id_bound(); diff --git a/third_party/spirv-cross/spirv_cross_c.h b/third_party/spirv-cross/spirv_cross_c.h index 6efaf8543e..405ff616b4 100644 --- a/third_party/spirv-cross/spirv_cross_c.h +++ b/third_party/spirv-cross/spirv_cross_c.h @@ -1,5 +1,5 @@ /* - * Copyright 2019 Hans-Kristian Arntzen + * Copyright 2019-2020 Hans-Kristian Arntzen * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -33,7 +33,7 @@ extern "C" { /* Bumped if ABI or API breaks backwards compatibility. */ #define SPVC_C_API_VERSION_MAJOR 0 /* Bumped if APIs or enumerations are added in a backwards compatible way. */ -#define SPVC_C_API_VERSION_MINOR 16 +#define SPVC_C_API_VERSION_MINOR 27 /* Bumped if internal implementation details change. */ #define SPVC_C_API_VERSION_PATCH 0 @@ -370,6 +370,55 @@ typedef enum spvc_msl_sampler_border_color SPVC_MSL_SAMPLER_BORDER_COLOR_INT_MAX = 0x7fffffff } spvc_msl_sampler_border_color; +/* Maps to C++ API. */ +typedef enum spvc_msl_format_resolution +{ + SPVC_MSL_FORMAT_RESOLUTION_444 = 0, + SPVC_MSL_FORMAT_RESOLUTION_422, + SPVC_MSL_FORMAT_RESOLUTION_420, + SPVC_MSL_FORMAT_RESOLUTION_INT_MAX = 0x7fffffff +} spvc_msl_format_resolution; + +/* Maps to C++ API. */ +typedef enum spvc_msl_chroma_location +{ + SPVC_MSL_CHROMA_LOCATION_COSITED_EVEN = 0, + SPVC_MSL_CHROMA_LOCATION_MIDPOINT, + SPVC_MSL_CHROMA_LOCATION_INT_MAX = 0x7fffffff +} spvc_msl_chroma_location; + +/* Maps to C++ API. */ +typedef enum spvc_msl_component_swizzle +{ + SPVC_MSL_COMPONENT_SWIZZLE_IDENTITY = 0, + SPVC_MSL_COMPONENT_SWIZZLE_ZERO, + SPVC_MSL_COMPONENT_SWIZZLE_ONE, + SPVC_MSL_COMPONENT_SWIZZLE_R, + SPVC_MSL_COMPONENT_SWIZZLE_G, + SPVC_MSL_COMPONENT_SWIZZLE_B, + SPVC_MSL_COMPONENT_SWIZZLE_A, + SPVC_MSL_COMPONENT_SWIZZLE_INT_MAX = 0x7fffffff +} spvc_msl_component_swizzle; + +/* Maps to C++ API. */ +typedef enum spvc_msl_sampler_ycbcr_model_conversion +{ + SPVC_MSL_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY = 0, + SPVC_MSL_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY, + SPVC_MSL_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_BT_709, + SPVC_MSL_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_BT_601, + SPVC_MSL_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_BT_2020, + SPVC_MSL_SAMPLER_YCBCR_MODEL_CONVERSION_INT_MAX = 0x7fffffff +} spvc_msl_sampler_ycbcr_model_conversion; + +/* Maps to C+ API. */ +typedef enum spvc_msl_sampler_ycbcr_range +{ + SPVC_MSL_SAMPLER_YCBCR_RANGE_ITU_FULL = 0, + SPVC_MSL_SAMPLER_YCBCR_RANGE_ITU_NARROW, + SPVC_MSL_SAMPLER_YCBCR_RANGE_INT_MAX = 0x7fffffff +} spvc_msl_sampler_ycbcr_range; + /* Maps to C++ API. */ typedef struct spvc_msl_constexpr_sampler { @@ -397,6 +446,64 @@ typedef struct spvc_msl_constexpr_sampler */ SPVC_PUBLIC_API void spvc_msl_constexpr_sampler_init(spvc_msl_constexpr_sampler *sampler); +/* Maps to the sampler Y'CbCr conversion-related portions of MSLConstexprSampler. See C++ API for defaults and details. */ +typedef struct spvc_msl_sampler_ycbcr_conversion +{ + unsigned planes; + spvc_msl_format_resolution resolution; + spvc_msl_sampler_filter chroma_filter; + spvc_msl_chroma_location x_chroma_offset; + spvc_msl_chroma_location y_chroma_offset; + spvc_msl_component_swizzle swizzle[4]; + spvc_msl_sampler_ycbcr_model_conversion ycbcr_model; + spvc_msl_sampler_ycbcr_range ycbcr_range; + unsigned bpc; +} spvc_msl_sampler_ycbcr_conversion; + +/* + * Initializes the constexpr sampler struct. + * The defaults are non-zero. + */ +SPVC_PUBLIC_API void spvc_msl_sampler_ycbcr_conversion_init(spvc_msl_sampler_ycbcr_conversion *conv); + +/* Maps to C++ API. */ +typedef enum spvc_hlsl_binding_flag_bits +{ + SPVC_HLSL_BINDING_AUTO_NONE_BIT = 0, + SPVC_HLSL_BINDING_AUTO_PUSH_CONSTANT_BIT = 1 << 0, + SPVC_HLSL_BINDING_AUTO_CBV_BIT = 1 << 1, + SPVC_HLSL_BINDING_AUTO_SRV_BIT = 1 << 2, + SPVC_HLSL_BINDING_AUTO_UAV_BIT = 1 << 3, + SPVC_HLSL_BINDING_AUTO_SAMPLER_BIT = 1 << 4, + SPVC_HLSL_BINDING_AUTO_ALL = 0x7fffffff +} spvc_hlsl_binding_flag_bits; +typedef unsigned spvc_hlsl_binding_flags; + +#define SPVC_HLSL_PUSH_CONSTANT_DESC_SET (~(0u)) +#define SPVC_HLSL_PUSH_CONSTANT_BINDING (0) + +/* Maps to C++ API. */ +typedef struct spvc_hlsl_resource_binding_mapping +{ + unsigned register_space; + unsigned register_binding; +} spvc_hlsl_resource_binding_mapping; + +typedef struct spvc_hlsl_resource_binding +{ + SpvExecutionModel stage; + unsigned desc_set; + unsigned binding; + + spvc_hlsl_resource_binding_mapping cbv, uav, srv, sampler; +} spvc_hlsl_resource_binding; + +/* + * Initializes the resource binding struct. + * The defaults are non-zero. + */ +SPVC_PUBLIC_API void spvc_hlsl_resource_binding_init(spvc_hlsl_resource_binding *binding); + /* Maps to the various spirv_cross::Compiler*::Option structures. See C++ API for defaults and details. */ typedef enum spvc_compiler_option { @@ -452,6 +559,25 @@ typedef enum spvc_compiler_option SPVC_COMPILER_OPTION_EMIT_LINE_DIRECTIVES = 37 | SPVC_COMPILER_OPTION_COMMON_BIT, + SPVC_COMPILER_OPTION_MSL_MULTIVIEW = 38 | SPVC_COMPILER_OPTION_MSL_BIT, + SPVC_COMPILER_OPTION_MSL_VIEW_MASK_BUFFER_INDEX = 39 | SPVC_COMPILER_OPTION_MSL_BIT, + SPVC_COMPILER_OPTION_MSL_DEVICE_INDEX = 40 | SPVC_COMPILER_OPTION_MSL_BIT, + SPVC_COMPILER_OPTION_MSL_VIEW_INDEX_FROM_DEVICE_INDEX = 41 | SPVC_COMPILER_OPTION_MSL_BIT, + SPVC_COMPILER_OPTION_MSL_DISPATCH_BASE = 42 | SPVC_COMPILER_OPTION_MSL_BIT, + SPVC_COMPILER_OPTION_MSL_DYNAMIC_OFFSETS_BUFFER_INDEX = 43 | SPVC_COMPILER_OPTION_MSL_BIT, + SPVC_COMPILER_OPTION_MSL_TEXTURE_1D_AS_2D = 44 | SPVC_COMPILER_OPTION_MSL_BIT, + SPVC_COMPILER_OPTION_MSL_ENABLE_BASE_INDEX_ZERO = 45 | SPVC_COMPILER_OPTION_MSL_BIT, + SPVC_COMPILER_OPTION_MSL_IOS_FRAMEBUFFER_FETCH_SUBPASS = 46 | SPVC_COMPILER_OPTION_MSL_BIT, + SPVC_COMPILER_OPTION_MSL_INVARIANT_FP_MATH = 47 | SPVC_COMPILER_OPTION_MSL_BIT, + SPVC_COMPILER_OPTION_MSL_EMULATE_CUBEMAP_ARRAY = 48 | SPVC_COMPILER_OPTION_MSL_BIT, + SPVC_COMPILER_OPTION_MSL_ENABLE_DECORATION_BINDING = 49 | SPVC_COMPILER_OPTION_MSL_BIT, + SPVC_COMPILER_OPTION_MSL_FORCE_ACTIVE_ARGUMENT_BUFFER_RESOURCES = 50 | SPVC_COMPILER_OPTION_MSL_BIT, + SPVC_COMPILER_OPTION_MSL_FORCE_NATIVE_ARRAYS = 51 | SPVC_COMPILER_OPTION_MSL_BIT, + + SPVC_COMPILER_OPTION_ENABLE_STORAGE_IMAGE_QUALIFIER_DEDUCTION = 52 | SPVC_COMPILER_OPTION_COMMON_BIT, + + SPVC_COMPILER_OPTION_HLSL_FORCE_STORAGE_BUFFER_AS_UAV = 53 | SPVC_COMPILER_OPTION_HLSL_BIT, + SPVC_COMPILER_OPTION_INT_MAX = 0x7fffffff } spvc_compiler_option; @@ -524,6 +650,16 @@ SPVC_PUBLIC_API spvc_result spvc_compiler_hlsl_add_vertex_attribute_remap(spvc_c size_t remaps); SPVC_PUBLIC_API spvc_variable_id spvc_compiler_hlsl_remap_num_workgroups_builtin(spvc_compiler compiler); +SPVC_PUBLIC_API spvc_result spvc_compiler_hlsl_set_resource_binding_flags(spvc_compiler compiler, + spvc_hlsl_binding_flags flags); + +SPVC_PUBLIC_API spvc_result spvc_compiler_hlsl_add_resource_binding(spvc_compiler compiler, + const spvc_hlsl_resource_binding *binding); +SPVC_PUBLIC_API spvc_bool spvc_compiler_hlsl_is_resource_used(spvc_compiler compiler, + SpvExecutionModel model, + unsigned set, + unsigned binding); + /* * MSL specifics. * Maps to C++ API. @@ -543,6 +679,7 @@ SPVC_PUBLIC_API spvc_result spvc_compiler_msl_add_vertex_attribute(spvc_compiler SPVC_PUBLIC_API spvc_result spvc_compiler_msl_add_resource_binding(spvc_compiler compiler, const spvc_msl_resource_binding *binding); SPVC_PUBLIC_API spvc_result spvc_compiler_msl_add_discrete_descriptor_set(spvc_compiler compiler, unsigned desc_set); +SPVC_PUBLIC_API spvc_result spvc_compiler_msl_set_argument_buffer_device_address_space(spvc_compiler compiler, unsigned desc_set, spvc_bool device_address); SPVC_PUBLIC_API spvc_bool spvc_compiler_msl_is_vertex_attribute_used(spvc_compiler compiler, unsigned location); SPVC_PUBLIC_API spvc_bool spvc_compiler_msl_is_resource_used(spvc_compiler compiler, SpvExecutionModel model, @@ -550,11 +687,17 @@ SPVC_PUBLIC_API spvc_bool spvc_compiler_msl_is_resource_used(spvc_compiler compi unsigned binding); SPVC_PUBLIC_API spvc_result spvc_compiler_msl_remap_constexpr_sampler(spvc_compiler compiler, spvc_variable_id id, const spvc_msl_constexpr_sampler *sampler); SPVC_PUBLIC_API spvc_result spvc_compiler_msl_remap_constexpr_sampler_by_binding(spvc_compiler compiler, unsigned desc_set, unsigned binding, const spvc_msl_constexpr_sampler *sampler); +SPVC_PUBLIC_API spvc_result spvc_compiler_msl_remap_constexpr_sampler_ycbcr(spvc_compiler compiler, spvc_variable_id id, const spvc_msl_constexpr_sampler *sampler, const spvc_msl_sampler_ycbcr_conversion *conv); +SPVC_PUBLIC_API spvc_result spvc_compiler_msl_remap_constexpr_sampler_by_binding_ycbcr(spvc_compiler compiler, unsigned desc_set, unsigned binding, const spvc_msl_constexpr_sampler *sampler, const spvc_msl_sampler_ycbcr_conversion *conv); SPVC_PUBLIC_API spvc_result spvc_compiler_msl_set_fragment_output_components(spvc_compiler compiler, unsigned location, unsigned components); SPVC_PUBLIC_API unsigned spvc_compiler_msl_get_automatic_resource_binding(spvc_compiler compiler, spvc_variable_id id); SPVC_PUBLIC_API unsigned spvc_compiler_msl_get_automatic_resource_binding_secondary(spvc_compiler compiler, spvc_variable_id id); +SPVC_PUBLIC_API spvc_result spvc_compiler_msl_add_dynamic_buffer(spvc_compiler compiler, unsigned desc_set, unsigned binding, unsigned index); + +SPVC_PUBLIC_API spvc_result spvc_compiler_msl_add_inline_uniform_block(spvc_compiler compiler, unsigned desc_set, unsigned binding); + /* * Reflect resources. * Maps almost 1:1 to C++ API. @@ -632,6 +775,12 @@ SPVC_PUBLIC_API SpvExecutionModel spvc_compiler_get_execution_model(spvc_compile */ SPVC_PUBLIC_API spvc_type spvc_compiler_get_type_handle(spvc_compiler compiler, spvc_type_id id); +/* Pulls out SPIRType::self. This effectively gives the type ID without array or pointer qualifiers. + * This is necessary when reflecting decoration/name information on members of a struct, + * which are placed in the base type, not the qualified type. + * This is similar to spvc_reflected_resource::base_type_id. */ +SPVC_PUBLIC_API spvc_type_id spvc_type_get_base_type_id(spvc_type type); + SPVC_PUBLIC_API spvc_basetype spvc_type_get_basetype(spvc_type type); SPVC_PUBLIC_API unsigned spvc_type_get_bit_width(spvc_type type); SPVC_PUBLIC_API unsigned spvc_type_get_vector_size(spvc_type type); diff --git a/third_party/spirv-cross/spirv_cross_containers.hpp b/third_party/spirv-cross/spirv_cross_containers.hpp index 31a8abbd0d..327d6b6cae 100644 --- a/third_party/spirv-cross/spirv_cross_containers.hpp +++ b/third_party/spirv-cross/spirv_cross_containers.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2019 Hans-Kristian Arntzen + * Copyright 2019-2020 Hans-Kristian Arntzen * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,8 +21,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -85,72 +87,72 @@ template class VectorView { public: - T &operator[](size_t i) + T &operator[](size_t i) SPIRV_CROSS_NOEXCEPT { return ptr[i]; } - const T &operator[](size_t i) const + const T &operator[](size_t i) const SPIRV_CROSS_NOEXCEPT { return ptr[i]; } - bool empty() const + bool empty() const SPIRV_CROSS_NOEXCEPT { return buffer_size == 0; } - size_t size() const + size_t size() const SPIRV_CROSS_NOEXCEPT { return buffer_size; } - T *data() + T *data() SPIRV_CROSS_NOEXCEPT { return ptr; } - const T *data() const + const T *data() const SPIRV_CROSS_NOEXCEPT { return ptr; } - T *begin() + T *begin() SPIRV_CROSS_NOEXCEPT { return ptr; } - T *end() + T *end() SPIRV_CROSS_NOEXCEPT { return ptr + buffer_size; } - const T *begin() const + const T *begin() const SPIRV_CROSS_NOEXCEPT { return ptr; } - const T *end() const + const T *end() const SPIRV_CROSS_NOEXCEPT { return ptr + buffer_size; } - T &front() + T &front() SPIRV_CROSS_NOEXCEPT { return ptr[0]; } - const T &front() const + const T &front() const SPIRV_CROSS_NOEXCEPT { return ptr[0]; } - T &back() + T &back() SPIRV_CROSS_NOEXCEPT { return ptr[buffer_size - 1]; } - const T &back() const + const T &back() const SPIRV_CROSS_NOEXCEPT { return ptr[buffer_size - 1]; } @@ -194,13 +196,13 @@ template class SmallVector : public VectorView { public: - SmallVector() + SmallVector() SPIRV_CROSS_NOEXCEPT { this->ptr = stack_storage.data(); buffer_capacity = N; } - SmallVector(const T *arg_list_begin, const T *arg_list_end) + SmallVector(const T *arg_list_begin, const T *arg_list_end) SPIRV_CROSS_NOEXCEPT : SmallVector() { auto count = size_t(arg_list_end - arg_list_begin); @@ -245,14 +247,17 @@ public: return *this; } - SmallVector(const SmallVector &other) + SmallVector(const SmallVector &other) SPIRV_CROSS_NOEXCEPT : SmallVector() { *this = other; } - SmallVector &operator=(const SmallVector &other) + SmallVector &operator=(const SmallVector &other) SPIRV_CROSS_NOEXCEPT { + if (this == &other) + return *this; + clear(); reserve(other.buffer_size); for (size_t i = 0; i < other.buffer_size; i++) @@ -261,7 +266,7 @@ public: return *this; } - explicit SmallVector(size_t count) + explicit SmallVector(size_t count) SPIRV_CROSS_NOEXCEPT : SmallVector() { resize(count); @@ -274,28 +279,28 @@ public: free(this->ptr); } - void clear() + void clear() SPIRV_CROSS_NOEXCEPT { for (size_t i = 0; i < this->buffer_size; i++) this->ptr[i].~T(); this->buffer_size = 0; } - void push_back(const T &t) + void push_back(const T &t) SPIRV_CROSS_NOEXCEPT { reserve(this->buffer_size + 1); new (&this->ptr[this->buffer_size]) T(t); this->buffer_size++; } - void push_back(T &&t) + void push_back(T &&t) SPIRV_CROSS_NOEXCEPT { reserve(this->buffer_size + 1); new (&this->ptr[this->buffer_size]) T(std::move(t)); this->buffer_size++; } - void pop_back() + void pop_back() SPIRV_CROSS_NOEXCEPT { // Work around false positive warning on GCC 8.3. // Calling pop_back on empty vector is undefined. @@ -304,15 +309,22 @@ public: } template - void emplace_back(Ts &&... ts) + void emplace_back(Ts &&... ts) SPIRV_CROSS_NOEXCEPT { reserve(this->buffer_size + 1); new (&this->ptr[this->buffer_size]) T(std::forward(ts)...); this->buffer_size++; } - void reserve(size_t count) + void reserve(size_t count) SPIRV_CROSS_NOEXCEPT { + if ((count > std::numeric_limits::max() / sizeof(T)) || + (count > std::numeric_limits::max() / 2)) + { + // Only way this should ever happen is with garbage input, terminate. + std::terminate(); + } + if (count > buffer_capacity) { size_t target_capacity = buffer_capacity; @@ -321,14 +333,17 @@ public: if (target_capacity < N) target_capacity = N; + // Need to ensure there is a POT value of target capacity which is larger than count, + // otherwise this will overflow. while (target_capacity < count) target_capacity <<= 1u; T *new_buffer = target_capacity > N ? static_cast(malloc(target_capacity * sizeof(T))) : stack_storage.data(); + // If we actually fail this malloc, we are hosed anyways, there is no reason to attempt recovery. if (!new_buffer) - SPIRV_CROSS_THROW("Out of memory."); + std::terminate(); // In case for some reason two allocations both come from same stack. if (new_buffer != this->ptr) @@ -348,7 +363,7 @@ public: } } - void insert(T *itr, const T *insert_begin, const T *insert_end) + void insert(T *itr, const T *insert_begin, const T *insert_end) SPIRV_CROSS_NOEXCEPT { auto count = size_t(insert_end - insert_begin); if (itr == this->end()) @@ -374,8 +389,10 @@ public: // Need to allocate new buffer. Move everything to a new buffer. T *new_buffer = target_capacity > N ? static_cast(malloc(target_capacity * sizeof(T))) : stack_storage.data(); + + // If we actually fail this malloc, we are hosed anyways, there is no reason to attempt recovery. if (!new_buffer) - SPIRV_CROSS_THROW("Out of memory."); + std::terminate(); // First, move elements from source buffer to new buffer. // We don't deal with types which can throw in move constructor. @@ -447,19 +464,19 @@ public: } } - void insert(T *itr, const T &value) + void insert(T *itr, const T &value) SPIRV_CROSS_NOEXCEPT { insert(itr, &value, &value + 1); } - T *erase(T *itr) + T *erase(T *itr) SPIRV_CROSS_NOEXCEPT { std::move(itr + 1, this->end(), itr); this->ptr[--this->buffer_size].~T(); return itr; } - void erase(T *start_erase, T *end_erase) + void erase(T *start_erase, T *end_erase) SPIRV_CROSS_NOEXCEPT { if (end_erase == this->end()) { @@ -473,7 +490,7 @@ public: } } - void resize(size_t new_size) + void resize(size_t new_size) SPIRV_CROSS_NOEXCEPT { if (new_size < this->buffer_size) { diff --git a/third_party/spirv-cross/spirv_cross_error_handling.hpp b/third_party/spirv-cross/spirv_cross_error_handling.hpp index e821c043d5..fa90610b59 100644 --- a/third_party/spirv-cross/spirv_cross_error_handling.hpp +++ b/third_party/spirv-cross/spirv_cross_error_handling.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2015-2019 Arm Limited + * Copyright 2015-2020 Arm Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,10 +17,12 @@ #ifndef SPIRV_CROSS_ERROR_HANDLING #define SPIRV_CROSS_ERROR_HANDLING -#include #include #include #include +#ifndef SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS +#include +#endif #ifdef SPIRV_CROSS_NAMESPACE_OVERRIDE #define SPIRV_CROSS_NAMESPACE SPIRV_CROSS_NAMESPACE_OVERRIDE @@ -33,6 +35,8 @@ namespace SPIRV_CROSS_NAMESPACE #ifdef SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS #if !defined(_MSC_VER) || defined(__clang__) [[noreturn]] +#elif defined(_MSC_VER) +__declspec(noreturn) #endif inline void report_and_abort(const std::string &msg) diff --git a/third_party/spirv-cross/spirv_cross_parsed_ir.cpp b/third_party/spirv-cross/spirv_cross_parsed_ir.cpp index a5c87f45cf..b49a0574c5 100644 --- a/third_party/spirv-cross/spirv_cross_parsed_ir.cpp +++ b/third_party/spirv-cross/spirv_cross_parsed_ir.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2018-2019 Arm Limited + * Copyright 2018-2020 Arm Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -128,6 +128,17 @@ void ParsedIR::set_id_bounds(uint32_t bounds) block_meta.resize(bounds); } +// Roll our own versions of these functions to avoid potential locale shenanigans. +static bool is_alpha(char c) +{ + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); +} + +static bool is_alphanumeric(char c) +{ + return is_alpha(c) || (c >= '0' && c <= '9'); +} + static string ensure_valid_identifier(const string &name, bool member) { // Functions in glslangValidator are mangled with name( stuff. @@ -143,26 +154,26 @@ static string ensure_valid_identifier(const string &name, bool member) // _m variables are reserved by the internal implementation, // otherwise, make sure the name is a valid identifier. if (i == 0) - c = isalpha(c) ? c : '_'; + c = is_alpha(c) ? c : '_'; else if (i == 2 && str[0] == '_' && str[1] == 'm') - c = isalpha(c) ? c : '_'; + c = is_alpha(c) ? c : '_'; else - c = isalnum(c) ? c : '_'; + c = is_alphanumeric(c) ? c : '_'; } else { // _ variables are reserved by the internal implementation, // otherwise, make sure the name is a valid identifier. if (i == 0 || (str[0] == '_' && i == 1)) - c = isalpha(c) ? c : '_'; + c = is_alpha(c) ? c : '_'; else - c = isalnum(c) ? c : '_'; + c = is_alphanumeric(c) ? c : '_'; } } return str; } -const string &ParsedIR::get_name(uint32_t id) const +const string &ParsedIR::get_name(ID id) const { auto *m = find_meta(id); if (m) @@ -171,7 +182,7 @@ const string &ParsedIR::get_name(uint32_t id) const return empty_string; } -const string &ParsedIR::get_member_name(uint32_t id, uint32_t index) const +const string &ParsedIR::get_member_name(TypeID id, uint32_t index) const { auto *m = find_meta(id); if (m) @@ -184,7 +195,7 @@ const string &ParsedIR::get_member_name(uint32_t id, uint32_t index) const return empty_string; } -void ParsedIR::set_name(uint32_t id, const string &name) +void ParsedIR::set_name(ID id, const string &name) { auto &str = meta[id].decoration.alias; str.clear(); @@ -199,7 +210,7 @@ void ParsedIR::set_name(uint32_t id, const string &name) str = ensure_valid_identifier(name, false); } -void ParsedIR::set_member_name(uint32_t id, uint32_t index, const string &name) +void ParsedIR::set_member_name(TypeID id, uint32_t index, const string &name) { meta[id].members.resize(max(meta[id].members.size(), size_t(index) + 1)); @@ -215,7 +226,7 @@ void ParsedIR::set_member_name(uint32_t id, uint32_t index, const string &name) str = ensure_valid_identifier(name, true); } -void ParsedIR::set_decoration_string(uint32_t id, Decoration decoration, const string &argument) +void ParsedIR::set_decoration_string(ID id, Decoration decoration, const string &argument) { auto &dec = meta[id].decoration; dec.decoration_flags.set(decoration); @@ -231,7 +242,7 @@ void ParsedIR::set_decoration_string(uint32_t id, Decoration decoration, const s } } -void ParsedIR::set_decoration(uint32_t id, Decoration decoration, uint32_t argument) +void ParsedIR::set_decoration(ID id, Decoration decoration, uint32_t argument) { auto &dec = meta[id].decoration; dec.decoration_flags.set(decoration); @@ -255,6 +266,14 @@ void ParsedIR::set_decoration(uint32_t id, Decoration decoration, uint32_t argum dec.offset = argument; break; + case DecorationXfbBuffer: + dec.xfb_buffer = argument; + break; + + case DecorationXfbStride: + dec.xfb_stride = argument; + break; + case DecorationArrayStride: dec.array_stride = argument; break; @@ -297,7 +316,7 @@ void ParsedIR::set_decoration(uint32_t id, Decoration decoration, uint32_t argum } } -void ParsedIR::set_member_decoration(uint32_t id, uint32_t index, Decoration decoration, uint32_t argument) +void ParsedIR::set_member_decoration(TypeID id, uint32_t index, Decoration decoration, uint32_t argument) { meta[id].members.resize(max(meta[id].members.size(), size_t(index) + 1)); auto &dec = meta[id].members[index]; @@ -326,6 +345,14 @@ void ParsedIR::set_member_decoration(uint32_t id, uint32_t index, Decoration dec dec.offset = argument; break; + case DecorationXfbBuffer: + dec.xfb_buffer = argument; + break; + + case DecorationXfbStride: + dec.xfb_stride = argument; + break; + case DecorationSpecId: dec.spec_id = argument; break; @@ -345,7 +372,7 @@ void ParsedIR::set_member_decoration(uint32_t id, uint32_t index, Decoration dec // Recursively marks any constants referenced by the specified constant instruction as being used // as an array length. The id must be a constant instruction (SPIRConstant or SPIRConstantOp). -void ParsedIR::mark_used_as_array_length(uint32_t id) +void ParsedIR::mark_used_as_array_length(ID id) { switch (ids[id].get_type()) { @@ -356,8 +383,16 @@ void ParsedIR::mark_used_as_array_length(uint32_t id) case TypeConstantOp: { auto &cop = get(id); - for (uint32_t arg_id : cop.arguments) - mark_used_as_array_length(arg_id); + if (cop.opcode == OpCompositeExtract) + mark_used_as_array_length(cop.arguments[0]); + else if (cop.opcode == OpCompositeInsert) + { + mark_used_as_array_length(cop.arguments[0]); + mark_used_as_array_length(cop.arguments[1]); + } + else + for (uint32_t arg_id : cop.arguments) + mark_used_as_array_length(arg_id); break; } @@ -393,7 +428,7 @@ Bitset ParsedIR::get_buffer_block_flags(const SPIRVariable &var) const return base_flags; } -const Bitset &ParsedIR::get_member_decoration_bitset(uint32_t id, uint32_t index) const +const Bitset &ParsedIR::get_member_decoration_bitset(TypeID id, uint32_t index) const { auto *m = find_meta(id); if (m) @@ -406,12 +441,12 @@ const Bitset &ParsedIR::get_member_decoration_bitset(uint32_t id, uint32_t index return cleared_bitset; } -bool ParsedIR::has_decoration(uint32_t id, Decoration decoration) const +bool ParsedIR::has_decoration(ID id, Decoration decoration) const { return get_decoration_bitset(id).get(decoration); } -uint32_t ParsedIR::get_decoration(uint32_t id, Decoration decoration) const +uint32_t ParsedIR::get_decoration(ID id, Decoration decoration) const { auto *m = find_meta(id); if (!m) @@ -431,6 +466,10 @@ uint32_t ParsedIR::get_decoration(uint32_t id, Decoration decoration) const return dec.component; case DecorationOffset: return dec.offset; + case DecorationXfbBuffer: + return dec.xfb_buffer; + case DecorationXfbStride: + return dec.xfb_stride; case DecorationBinding: return dec.binding; case DecorationDescriptorSet: @@ -452,7 +491,7 @@ uint32_t ParsedIR::get_decoration(uint32_t id, Decoration decoration) const } } -const string &ParsedIR::get_decoration_string(uint32_t id, Decoration decoration) const +const string &ParsedIR::get_decoration_string(ID id, Decoration decoration) const { auto *m = find_meta(id); if (!m) @@ -473,7 +512,7 @@ const string &ParsedIR::get_decoration_string(uint32_t id, Decoration decoration } } -void ParsedIR::unset_decoration(uint32_t id, Decoration decoration) +void ParsedIR::unset_decoration(ID id, Decoration decoration) { auto &dec = meta[id].decoration; dec.decoration_flags.clear(decoration); @@ -495,6 +534,14 @@ void ParsedIR::unset_decoration(uint32_t id, Decoration decoration) dec.offset = 0; break; + case DecorationXfbBuffer: + dec.xfb_buffer = 0; + break; + + case DecorationXfbStride: + dec.xfb_stride = 0; + break; + case DecorationBinding: dec.binding = 0; break; @@ -535,12 +582,12 @@ void ParsedIR::unset_decoration(uint32_t id, Decoration decoration) } } -bool ParsedIR::has_member_decoration(uint32_t id, uint32_t index, Decoration decoration) const +bool ParsedIR::has_member_decoration(TypeID id, uint32_t index, Decoration decoration) const { return get_member_decoration_bitset(id, index).get(decoration); } -uint32_t ParsedIR::get_member_decoration(uint32_t id, uint32_t index, Decoration decoration) const +uint32_t ParsedIR::get_member_decoration(TypeID id, uint32_t index, Decoration decoration) const { auto *m = find_meta(id); if (!m) @@ -565,6 +612,10 @@ uint32_t ParsedIR::get_member_decoration(uint32_t id, uint32_t index, Decoration return dec.binding; case DecorationOffset: return dec.offset; + case DecorationXfbBuffer: + return dec.xfb_buffer; + case DecorationXfbStride: + return dec.xfb_stride; case DecorationSpecId: return dec.spec_id; case DecorationIndex: @@ -574,7 +625,7 @@ uint32_t ParsedIR::get_member_decoration(uint32_t id, uint32_t index, Decoration } } -const Bitset &ParsedIR::get_decoration_bitset(uint32_t id) const +const Bitset &ParsedIR::get_decoration_bitset(ID id) const { auto *m = find_meta(id); if (m) @@ -586,7 +637,7 @@ const Bitset &ParsedIR::get_decoration_bitset(uint32_t id) const return cleared_bitset; } -void ParsedIR::set_member_decoration_string(uint32_t id, uint32_t index, Decoration decoration, const string &argument) +void ParsedIR::set_member_decoration_string(TypeID id, uint32_t index, Decoration decoration, const string &argument) { meta[id].members.resize(max(meta[id].members.size(), size_t(index) + 1)); auto &dec = meta[id].members[index]; @@ -603,7 +654,7 @@ void ParsedIR::set_member_decoration_string(uint32_t id, uint32_t index, Decorat } } -const string &ParsedIR::get_member_decoration_string(uint32_t id, uint32_t index, Decoration decoration) const +const string &ParsedIR::get_member_decoration_string(TypeID id, uint32_t index, Decoration decoration) const { auto *m = find_meta(id); if (m) @@ -626,7 +677,7 @@ const string &ParsedIR::get_member_decoration_string(uint32_t id, uint32_t index return empty_string; } -void ParsedIR::unset_member_decoration(uint32_t id, uint32_t index, Decoration decoration) +void ParsedIR::unset_member_decoration(TypeID id, uint32_t index, Decoration decoration) { auto &m = meta[id]; if (index >= m.members.size()) @@ -653,6 +704,14 @@ void ParsedIR::unset_member_decoration(uint32_t id, uint32_t index, Decoration d dec.offset = 0; break; + case DecorationXfbBuffer: + dec.xfb_buffer = 0; + break; + + case DecorationXfbStride: + dec.xfb_stride = 0; + break; + case DecorationSpecId: dec.spec_id = 0; break; @@ -679,7 +738,7 @@ uint32_t ParsedIR::increase_bound_by(uint32_t incr_amount) return uint32_t(curr_bound); } -void ParsedIR::remove_typed_id(Types type, uint32_t id) +void ParsedIR::remove_typed_id(Types type, ID id) { auto &type_ids = ids_for_type[type]; type_ids.erase(remove(begin(type_ids), end(type_ids), id), end(type_ids)); @@ -694,7 +753,7 @@ void ParsedIR::reset_all_of_type(Types type) ids_for_type[type].clear(); } -void ParsedIR::add_typed_id(Types type, uint32_t id) +void ParsedIR::add_typed_id(Types type, ID id) { if (loop_iteration_depth_hard != 0) SPIRV_CROSS_THROW("Cannot add typed ID while looping over it."); @@ -740,7 +799,7 @@ void ParsedIR::add_typed_id(Types type, uint32_t id) } } -const Meta *ParsedIR::find_meta(uint32_t id) const +const Meta *ParsedIR::find_meta(ID id) const { auto itr = meta.find(id); if (itr != end(meta)) @@ -749,7 +808,7 @@ const Meta *ParsedIR::find_meta(uint32_t id) const return nullptr; } -Meta *ParsedIR::find_meta(uint32_t id) +Meta *ParsedIR::find_meta(ID id) { auto itr = meta.find(id); if (itr != end(meta)) diff --git a/third_party/spirv-cross/spirv_cross_parsed_ir.hpp b/third_party/spirv-cross/spirv_cross_parsed_ir.hpp index c4ea28b495..7cff915f56 100644 --- a/third_party/spirv-cross/spirv_cross_parsed_ir.hpp +++ b/third_party/spirv-cross/spirv_cross_parsed_ir.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2018-2019 Arm Limited + * Copyright 2018-2020 Arm Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -57,19 +57,19 @@ public: SmallVector ids; // Various meta data for IDs, decorations, names, etc. - std::unordered_map meta; + std::unordered_map meta; // Holds all IDs which have a certain type. // This is needed so we can iterate through a specific kind of resource quickly, // and in-order of module declaration. - SmallVector ids_for_type[TypeCount]; + SmallVector ids_for_type[TypeCount]; // Special purpose lists which contain a union of types. // This is needed so we can declare specialization constants and structs in an interleaved fashion, // among other things. // Constants can be of struct type, and struct array sizes can use specialization constants. - SmallVector ids_for_constant_or_type; - SmallVector ids_for_constant_or_variable; + SmallVector ids_for_constant_or_type; + SmallVector ids_for_constant_or_variable; // Declared capabilities and extensions in the SPIR-V module. // Not really used except for reflection at the moment. @@ -88,12 +88,12 @@ public: }; using BlockMetaFlags = uint8_t; SmallVector block_meta; - std::unordered_map continue_block_to_loop_header; + std::unordered_map continue_block_to_loop_header; // Normally, we'd stick SPIREntryPoint in ids array, but it conflicts with SPIRFunction. // Entry points can therefore be seen as some sort of meta structure. - std::unordered_map entry_points; - uint32_t default_entry_point = 0; + std::unordered_map entry_points; + FunctionID default_entry_point = 0; struct Source { @@ -114,34 +114,34 @@ public: // Can be useful for simple "raw" reflection. // However, most members are here because the Parser needs most of these, // and might as well just have the whole suite of decoration/name handling in one place. - void set_name(uint32_t id, const std::string &name); - const std::string &get_name(uint32_t id) const; - void set_decoration(uint32_t id, spv::Decoration decoration, uint32_t argument = 0); - void set_decoration_string(uint32_t id, spv::Decoration decoration, const std::string &argument); - bool has_decoration(uint32_t id, spv::Decoration decoration) const; - uint32_t get_decoration(uint32_t id, spv::Decoration decoration) const; - const std::string &get_decoration_string(uint32_t id, spv::Decoration decoration) const; - const Bitset &get_decoration_bitset(uint32_t id) const; - void unset_decoration(uint32_t id, spv::Decoration decoration); + void set_name(ID id, const std::string &name); + const std::string &get_name(ID id) const; + void set_decoration(ID id, spv::Decoration decoration, uint32_t argument = 0); + void set_decoration_string(ID id, spv::Decoration decoration, const std::string &argument); + bool has_decoration(ID id, spv::Decoration decoration) const; + uint32_t get_decoration(ID id, spv::Decoration decoration) const; + const std::string &get_decoration_string(ID id, spv::Decoration decoration) const; + const Bitset &get_decoration_bitset(ID id) const; + void unset_decoration(ID id, spv::Decoration decoration); // Decoration handling methods (for members of a struct). - void set_member_name(uint32_t id, uint32_t index, const std::string &name); - const std::string &get_member_name(uint32_t id, uint32_t index) const; - void set_member_decoration(uint32_t id, uint32_t index, spv::Decoration decoration, uint32_t argument = 0); - void set_member_decoration_string(uint32_t id, uint32_t index, spv::Decoration decoration, + void set_member_name(TypeID id, uint32_t index, const std::string &name); + const std::string &get_member_name(TypeID id, uint32_t index) const; + void set_member_decoration(TypeID id, uint32_t index, spv::Decoration decoration, uint32_t argument = 0); + void set_member_decoration_string(TypeID id, uint32_t index, spv::Decoration decoration, const std::string &argument); - uint32_t get_member_decoration(uint32_t id, uint32_t index, spv::Decoration decoration) const; - const std::string &get_member_decoration_string(uint32_t id, uint32_t index, spv::Decoration decoration) const; - bool has_member_decoration(uint32_t id, uint32_t index, spv::Decoration decoration) const; - const Bitset &get_member_decoration_bitset(uint32_t id, uint32_t index) const; - void unset_member_decoration(uint32_t id, uint32_t index, spv::Decoration decoration); + uint32_t get_member_decoration(TypeID id, uint32_t index, spv::Decoration decoration) const; + const std::string &get_member_decoration_string(TypeID id, uint32_t index, spv::Decoration decoration) const; + bool has_member_decoration(TypeID id, uint32_t index, spv::Decoration decoration) const; + const Bitset &get_member_decoration_bitset(TypeID id, uint32_t index) const; + void unset_member_decoration(TypeID id, uint32_t index, spv::Decoration decoration); - void mark_used_as_array_length(uint32_t id); + void mark_used_as_array_length(ID id); uint32_t increase_bound_by(uint32_t count); Bitset get_buffer_block_flags(const SPIRVariable &var) const; - void add_typed_id(Types type, uint32_t id); - void remove_typed_id(Types type, uint32_t id); + void add_typed_id(Types type, ID id); + void remove_typed_id(Types type, ID id); class LoopLock { @@ -198,8 +198,8 @@ public: void reset_all_of_type(Types type); - Meta *find_meta(uint32_t id); - const Meta *find_meta(uint32_t id) const; + Meta *find_meta(ID id); + const Meta *find_meta(ID id) const; const std::string &get_empty_string() const { diff --git a/third_party/spirv-cross/spirv_cross_util.cpp b/third_party/spirv-cross/spirv_cross_util.cpp index 6ab5d26456..cfad676ec1 100644 --- a/third_party/spirv-cross/spirv_cross_util.cpp +++ b/third_party/spirv-cross/spirv_cross_util.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2015-2019 Arm Limited + * Copyright 2015-2020 Arm Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/third_party/spirv-cross/spirv_cross_util.hpp b/third_party/spirv-cross/spirv_cross_util.hpp index 7c4030b0b2..708b7cb568 100644 --- a/third_party/spirv-cross/spirv_cross_util.hpp +++ b/third_party/spirv-cross/spirv_cross_util.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2015-2019 Arm Limited + * Copyright 2015-2020 Arm Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/third_party/spirv-cross/spirv_glsl.cpp b/third_party/spirv-cross/spirv_glsl.cpp index 4fe7d58892..0afd9cef98 100644 --- a/third_party/spirv-cross/spirv_glsl.cpp +++ b/third_party/spirv-cross/spirv_glsl.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2015-2019 Arm Limited + * Copyright 2015-2020 Arm Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -286,7 +286,7 @@ static uint32_t pls_format_to_components(PlsFormat format) } } -static const char *vector_swizzle(int vecsize, int index) +const char *CompilerGLSL::vector_swizzle(int vecsize, int index) { static const char *const swizzle[4][4] = { { ".x", ".y", ".z", ".w" }, @@ -324,6 +324,9 @@ void CompilerGLSL::reset() forwarded_temporaries.clear(); suppressed_usage_tracking.clear(); + // Ensure that we declare phi-variable copies even if the original declaration isn't deferred + flushed_phi_variables.clear(); + reset_name_caches(); ir.for_each_typed_id([&](uint32_t, SPIRFunction &func) { @@ -472,11 +475,10 @@ void CompilerGLSL::find_static_extensions() SPIRV_CROSS_THROW("Only Logical and PhysicalStorageBuffer64EXT addressing models are supported."); } - // Check for nonuniform qualifier. + // Check for nonuniform qualifier and passthrough. // Instead of looping over all decorations to find this, just look at capabilities. for (auto &cap : ir.declared_capabilities) { - bool nonuniform_indexing = false; switch (cap) { case CapabilityShaderNonUniformEXT: @@ -484,15 +486,19 @@ void CompilerGLSL::find_static_extensions() if (!options.vulkan_semantics) SPIRV_CROSS_THROW("GL_EXT_nonuniform_qualifier is only supported in Vulkan GLSL."); require_extension_internal("GL_EXT_nonuniform_qualifier"); - nonuniform_indexing = true; + break; + + case CapabilityGeometryShaderPassthroughNV: + if (execution.model == ExecutionModelGeometry) + { + require_extension_internal("GL_NV_geometry_shader_passthrough"); + execution.geometry_passthrough = true; + } break; default: break; } - - if (nonuniform_indexing) - break; } } @@ -502,6 +508,7 @@ string CompilerGLSL::compile() backend.allow_precision_qualifiers = true; backend.force_gl_in_out_block = true; backend.supports_extensions = true; + backend.use_array_constructor = true; // Scan the SPIR-V to find trivial uses of extensions. fixup_type_alias(); @@ -511,6 +518,7 @@ string CompilerGLSL::compile() fixup_image_load_store_access(); update_active_builtins(); analyze_image_and_sampler_usage(); + analyze_interlocked_resource_usage(); // Shaders might cast unrelated data to pointers of non-block types. // Find all such instances and make sure we can cast the pointers to a synthesized block type. @@ -535,6 +543,25 @@ string CompilerGLSL::compile() pass_count++; } while (is_forcing_recompilation()); + // Implement the interlocked wrapper function at the end. + // The body was implemented in lieu of main(). + if (interlocked_is_complex) + { + statement("void main()"); + begin_scope(); + statement("// Interlocks were used in a way not compatible with GLSL, this is very slow."); + if (options.es) + statement("beginInvocationInterlockNV();"); + else + statement("beginInvocationInterlockARB();"); + statement("spvMainInterlockedBody();"); + if (options.es) + statement("endInvocationInterlockNV();"); + else + statement("endInvocationInterlockARB();"); + end_scope(); + } + // Entry point in GLSL is always main(). get_entry_point().name = "main"; @@ -605,6 +632,26 @@ void CompilerGLSL::emit_header() if (execution.flags.get(ExecutionModePostDepthCoverage)) require_extension_internal("GL_ARB_post_depth_coverage"); + // Needed for: layout({pixel,sample}_interlock_[un]ordered) in; + if (execution.flags.get(ExecutionModePixelInterlockOrderedEXT) || + execution.flags.get(ExecutionModePixelInterlockUnorderedEXT) || + execution.flags.get(ExecutionModeSampleInterlockOrderedEXT) || + execution.flags.get(ExecutionModeSampleInterlockUnorderedEXT)) + { + if (options.es) + { + if (options.version < 310) + SPIRV_CROSS_THROW("At least ESSL 3.10 required for fragment shader interlock."); + require_extension_internal("GL_NV_fragment_shader_interlock"); + } + else + { + if (options.version < 420) + require_extension_internal("GL_ARB_shader_image_load_store"); + require_extension_internal("GL_ARB_fragment_shader_interlock"); + } + } + for (auto &ext : forced_extensions) { if (ext == "GL_EXT_shader_explicit_arithmetic_types_float16") @@ -640,6 +687,19 @@ void CompilerGLSL::emit_header() statement("#endif"); } } + else if (ext == "GL_ARB_post_depth_coverage") + { + if (options.es) + statement("#extension GL_EXT_post_depth_coverage : require"); + else + { + statement("#if defined(GL_ARB_post_depth_coverge)"); + statement("#extension GL_ARB_post_depth_coverage : require"); + statement("#else"); + statement("#extension GL_EXT_post_depth_coverage : require"); + statement("#endif"); + } + } else statement("#extension ", ext, " : require"); } @@ -653,7 +713,6 @@ void CompilerGLSL::emit_header() switch (execution.model) { case ExecutionModelGeometry: - outputs.push_back(join("max_vertices = ", execution.output_vertices)); if ((execution.flags.get(ExecutionModeInvocations)) && execution.invocations != 1) inputs.push_back(join("invocations = ", execution.invocations)); if (execution.flags.get(ExecutionModeInputPoints)) @@ -666,12 +725,18 @@ void CompilerGLSL::emit_header() inputs.push_back("triangles"); if (execution.flags.get(ExecutionModeInputTrianglesAdjacency)) inputs.push_back("triangles_adjacency"); - if (execution.flags.get(ExecutionModeOutputTriangleStrip)) - outputs.push_back("triangle_strip"); - if (execution.flags.get(ExecutionModeOutputPoints)) - outputs.push_back("points"); - if (execution.flags.get(ExecutionModeOutputLineStrip)) - outputs.push_back("line_strip"); + + if (!execution.geometry_passthrough) + { + // For passthrough, these are implies and cannot be declared in shader. + outputs.push_back(join("max_vertices = ", execution.output_vertices)); + if (execution.flags.get(ExecutionModeOutputTriangleStrip)) + outputs.push_back("triangle_strip"); + if (execution.flags.get(ExecutionModeOutputPoints)) + outputs.push_back("points"); + if (execution.flags.get(ExecutionModeOutputLineStrip)) + outputs.push_back("line_strip"); + } break; case ExecutionModelTessellationControl: @@ -714,7 +779,8 @@ void CompilerGLSL::emit_header() // If there are any spec constants on legacy GLSL, defer declaration, we need to set up macro // declarations before we can emit the work group size. - if (options.vulkan_semantics || ((wg_x.id == 0) && (wg_y.id == 0) && (wg_z.id == 0))) + if (options.vulkan_semantics || + ((wg_x.id == ConstantID(0)) && (wg_y.id == ConstantID(0)) && (wg_z.id == ConstantID(0)))) build_workgroup_size(inputs, wg_x, wg_y, wg_z); } else @@ -771,6 +837,15 @@ void CompilerGLSL::emit_header() if (execution.flags.get(ExecutionModePostDepthCoverage)) inputs.push_back("post_depth_coverage"); + if (execution.flags.get(ExecutionModePixelInterlockOrderedEXT)) + inputs.push_back("pixel_interlock_ordered"); + else if (execution.flags.get(ExecutionModePixelInterlockUnorderedEXT)) + inputs.push_back("pixel_interlock_unordered"); + else if (execution.flags.get(ExecutionModeSampleInterlockOrderedEXT)) + inputs.push_back("sample_interlock_ordered"); + else if (execution.flags.get(ExecutionModeSampleInterlockUnorderedEXT)) + inputs.push_back("sample_interlock_unordered"); + if (!options.es && execution.flags.get(ExecutionModeDepthGreater)) statement("layout(depth_greater) out float gl_FragDepth;"); else if (!options.es && execution.flags.get(ExecutionModeDepthLess)) @@ -802,7 +877,8 @@ void CompilerGLSL::emit_struct(SPIRType &type) // Type-punning with these types is legal, which complicates things // when we are storing struct and array types in an SSBO for example. // If the type master is packed however, we can no longer assume that the struct declaration will be redundant. - if (type.type_alias != 0 && !has_extended_decoration(type.type_alias, SPIRVCrossDecorationBufferBlockRepacked)) + if (type.type_alias != TypeID(0) && + !has_extended_decoration(type.type_alias, SPIRVCrossDecorationBufferBlockRepacked)) return; add_resource_name(type.self); @@ -879,6 +955,9 @@ string CompilerGLSL::layout_for_member(const SPIRType &type, uint32_t index) SmallVector attr; + if (has_member_decoration(type.self, index, DecorationPassthroughNV)) + attr.push_back("passthrough"); + // We can only apply layouts on members in block interfaces. // This is a bit problematic because in SPIR-V decorations are applied on the struct types directly. // This is not supported on GLSL, so we have to make the assumption that if a struct within our buffer block struct @@ -924,6 +1003,8 @@ string CompilerGLSL::layout_for_member(const SPIRType &type, uint32_t index) if (has_extended_decoration(type.self, SPIRVCrossDecorationExplicitOffset) && dec.decoration_flags.get(DecorationOffset)) attr.push_back(join("offset = ", dec.offset)); + else if (type.storage == StorageClassOutput && dec.decoration_flags.get(DecorationOffset)) + attr.push_back(join("xfb_offset = ", dec.offset)); if (attr.empty()) return ""; @@ -1268,7 +1349,8 @@ uint32_t CompilerGLSL::type_to_packed_size(const SPIRType &type, const Bitset &f } bool CompilerGLSL::buffer_is_packing_standard(const SPIRType &type, BufferPackingStandard packing, - uint32_t start_offset, uint32_t end_offset) + uint32_t *failed_validation_index, uint32_t start_offset, + uint32_t end_offset) { // This is very tricky and error prone, but try to be exhaustive and correct here. // SPIR-V doesn't directly say if we're using std430 or std140. @@ -1349,18 +1431,28 @@ bool CompilerGLSL::buffer_is_packing_standard(const SPIRType &type, BufferPackin if (!packing_has_flexible_offset(packing)) { if (actual_offset != offset) // This cannot be the packing we're looking for. + { + if (failed_validation_index) + *failed_validation_index = i; return false; + } } else if ((actual_offset & (alignment - 1)) != 0) { // We still need to verify that alignment rules are observed, even if we have explicit offset. + if (failed_validation_index) + *failed_validation_index = i; return false; } // Verify array stride rules. if (!memb_type.array.empty() && type_to_packed_array_stride(memb_type, member_flags, packing) != type_struct_member_array_stride(type, i)) + { + if (failed_validation_index) + *failed_validation_index = i; return false; + } // Verify that sub-structs also follow packing rules. // We cannot use enhanced layouts on substructs, so they better be up to spec. @@ -1369,6 +1461,8 @@ bool CompilerGLSL::buffer_is_packing_standard(const SPIRType &type, BufferPackin if (!memb_type.pointer && !memb_type.member_types.empty() && !buffer_is_packing_standard(memb_type, substruct_packing)) { + if (failed_validation_index) + *failed_validation_index = i; return false; } } @@ -1427,10 +1521,12 @@ string CompilerGLSL::layout_for_variable(const SPIRVariable &var) SmallVector attr; - auto &dec = ir.meta[var.self].decoration; auto &type = get(var.basetype); - auto &flags = dec.decoration_flags; - auto typeflags = ir.meta[type.self].decoration.decoration_flags; + auto &flags = get_decoration_bitset(var.self); + auto &typeflags = get_decoration_bitset(type.self); + + if (flags.get(DecorationPassthroughNV)) + attr.push_back("passthrough"); if (options.vulkan_semantics && var.storage == StorageClassPushConstant) attr.push_back("push_constant"); @@ -1445,7 +1541,7 @@ string CompilerGLSL::layout_for_variable(const SPIRVariable &var) if (options.vulkan_semantics) { if (flags.get(DecorationInputAttachmentIndex)) - attr.push_back(join("input_attachment_index = ", dec.input_attachment)); + attr.push_back(join("input_attachment_index = ", get_decoration(var.self, DecorationInputAttachmentIndex))); } bool is_block = has_decoration(type.self, DecorationBlock); @@ -1458,33 +1554,103 @@ string CompilerGLSL::layout_for_variable(const SPIRVariable &var) // If our members have location decorations, we don't need to // emit location decorations at the top as well (looks weird). if (!combined_decoration.get(DecorationLocation)) - attr.push_back(join("location = ", dec.location)); + attr.push_back(join("location = ", get_decoration(var.self, DecorationLocation))); + } + + // Transform feedback + bool uses_enhanced_layouts = false; + if (is_block && var.storage == StorageClassOutput) + { + // For blocks, there is a restriction where xfb_stride/xfb_buffer must only be declared on the block itself, + // since all members must match the same xfb_buffer. The only thing we will declare for members of the block + // is the xfb_offset. + uint32_t member_count = uint32_t(type.member_types.size()); + bool have_xfb_buffer_stride = false; + bool have_any_xfb_offset = false; + uint32_t xfb_stride = 0, xfb_buffer = 0; + + if (flags.get(DecorationXfbBuffer) && flags.get(DecorationXfbStride)) + { + have_xfb_buffer_stride = true; + xfb_buffer = get_decoration(var.self, DecorationXfbBuffer); + xfb_stride = get_decoration(var.self, DecorationXfbStride); + } + + // Verify that none of the members violate our assumption. + for (uint32_t i = 0; i < member_count; i++) + { + // Only members with an Offset decoration participate in XFB. + if (!has_member_decoration(type.self, i, DecorationOffset)) + continue; + have_any_xfb_offset = true; + + if (has_member_decoration(type.self, i, DecorationXfbBuffer)) + { + uint32_t buffer_index = get_member_decoration(type.self, i, DecorationXfbBuffer); + if (have_xfb_buffer_stride && buffer_index != xfb_buffer) + SPIRV_CROSS_THROW("IO block member XfbBuffer mismatch."); + have_xfb_buffer_stride = true; + xfb_buffer = buffer_index; + } + + if (has_member_decoration(type.self, i, DecorationXfbStride)) + { + uint32_t stride = get_member_decoration(type.self, i, DecorationXfbStride); + if (have_xfb_buffer_stride && stride != xfb_stride) + SPIRV_CROSS_THROW("IO block member XfbStride mismatch."); + have_xfb_buffer_stride = true; + xfb_stride = stride; + } + } + + if (have_xfb_buffer_stride && have_any_xfb_offset) + { + attr.push_back(join("xfb_buffer = ", xfb_buffer)); + attr.push_back(join("xfb_stride = ", xfb_stride)); + uses_enhanced_layouts = true; + } + } + else if (var.storage == StorageClassOutput && flags.get(DecorationXfbBuffer) && flags.get(DecorationXfbStride) && + flags.get(DecorationOffset)) + { + // XFB for standalone variables, we can emit all decorations. + attr.push_back(join("xfb_buffer = ", get_decoration(var.self, DecorationXfbBuffer))); + attr.push_back(join("xfb_stride = ", get_decoration(var.self, DecorationXfbStride))); + attr.push_back(join("xfb_offset = ", get_decoration(var.self, DecorationOffset))); + uses_enhanced_layouts = true; } // Can only declare Component if we can declare location. if (flags.get(DecorationComponent) && can_use_io_location(var.storage, is_block)) + { + uses_enhanced_layouts = true; + attr.push_back(join("component = ", get_decoration(var.self, DecorationComponent))); + } + + if (uses_enhanced_layouts) { if (!options.es) { if (options.version < 440 && options.version >= 140) require_extension_internal("GL_ARB_enhanced_layouts"); else if (options.version < 140) - SPIRV_CROSS_THROW("Component decoration is not supported in targets below GLSL 1.40."); - attr.push_back(join("component = ", dec.component)); + SPIRV_CROSS_THROW("GL_ARB_enhanced_layouts is not supported in targets below GLSL 1.40."); + if (!options.es && options.version < 440) + require_extension_internal("GL_ARB_enhanced_layouts"); } - else - SPIRV_CROSS_THROW("Component decoration is not supported in ES targets."); + else if (options.es) + SPIRV_CROSS_THROW("GL_ARB_enhanced_layouts is not supported in ESSL."); } if (flags.get(DecorationIndex)) - attr.push_back(join("index = ", dec.index)); + attr.push_back(join("index = ", get_decoration(var.self, DecorationIndex))); // Do not emit set = decoration in regular GLSL output, but // we need to preserve it in Vulkan GLSL mode. if (var.storage != StorageClassPushConstant && var.storage != StorageClassShaderRecordBufferNV) { if (flags.get(DecorationDescriptorSet) && options.vulkan_semantics) - attr.push_back(join("set = ", dec.set)); + attr.push_back(join("set = ", get_decoration(var.self, DecorationDescriptorSet))); } bool push_constant_block = options.vulkan_semantics && var.storage == StorageClassPushConstant; @@ -1514,10 +1680,10 @@ string CompilerGLSL::layout_for_variable(const SPIRVariable &var) can_use_binding = false; if (can_use_binding && flags.get(DecorationBinding)) - attr.push_back(join("binding = ", dec.binding)); + attr.push_back(join("binding = ", get_decoration(var.self, DecorationBinding))); - if (flags.get(DecorationOffset)) - attr.push_back(join("offset = ", dec.offset)); + if (var.storage != StorageClassOutput && flags.get(DecorationOffset)) + attr.push_back(join("offset = ", get_decoration(var.self, DecorationOffset))); // Instead of adding explicit offsets for every element here, just assume we're using std140 or std430. // If SPIR-V does not comply with either layout, we cannot really work around it. @@ -2023,9 +2189,32 @@ void CompilerGLSL::emit_interface_block(const SPIRVariable &var) else { add_resource_name(var.self); + + // Tessellation control and evaluation shaders must have either gl_MaxPatchVertices or unsized arrays for input arrays. + // Opt for unsized as it's the more "correct" variant to use. + bool control_point_input_array = type.storage == StorageClassInput && !type.array.empty() && + !has_decoration(var.self, DecorationPatch) && + (get_entry_point().model == ExecutionModelTessellationControl || + get_entry_point().model == ExecutionModelTessellationEvaluation); + + uint32_t old_array_size = 0; + bool old_array_size_literal = true; + + if (control_point_input_array) + { + swap(type.array.back(), old_array_size); + swap(type.array_size_literal.back(), old_array_size_literal); + } + statement(layout_for_variable(var), to_qualifiers_glsl(var.self), variable_decl(type, to_name(var.self), var.self), ";"); + if (control_point_input_array) + { + swap(type.array.back(), old_array_size); + swap(type.array_size_literal.back(), old_array_size_literal); + } + // If a StorageClassOutput variable has an initializer, we need to initialize it in main(). if (var.storage == StorageClassOutput && var.initializer) { @@ -2070,7 +2259,7 @@ void CompilerGLSL::emit_constant(const SPIRConstant &constant) auto name = to_name(constant.self); SpecializationConstant wg_x, wg_y, wg_z; - uint32_t workgroup_size_id = get_work_group_size_specialization_constants(wg_x, wg_y, wg_z); + ID workgroup_size_id = get_work_group_size_specialization_constants(wg_x, wg_y, wg_z); // This specialization constant is implicitly declared by emitting layout() in; if (constant.self == workgroup_size_id) @@ -2079,7 +2268,8 @@ void CompilerGLSL::emit_constant(const SPIRConstant &constant) // These specialization constants are implicitly declared by emitting layout() in; // In legacy GLSL, we will still need to emit macros for these, so a layout() in; declaration // later can use macro overrides for work group size. - bool is_workgroup_size_constant = constant.self == wg_x.id || constant.self == wg_y.id || constant.self == wg_z.id; + bool is_workgroup_size_constant = ConstantID(constant.self) == wg_x.id || ConstantID(constant.self) == wg_y.id || + ConstantID(constant.self) == wg_z.id; if (options.vulkan_semantics && is_workgroup_size_constant) { @@ -2123,6 +2313,36 @@ void CompilerGLSL::emit_entry_point_declarations() { } +void CompilerGLSL::replace_illegal_names(const unordered_set &keywords) +{ + ir.for_each_typed_id([&](uint32_t, const SPIRVariable &var) { + if (is_hidden_variable(var)) + return; + + auto *meta = ir.find_meta(var.self); + if (!meta) + return; + + auto &m = meta->decoration; + if (m.alias.compare(0, 3, "gl_") == 0 || keywords.find(m.alias) != end(keywords)) + m.alias = join("_", m.alias); + }); + + ir.for_each_typed_id([&](uint32_t, const SPIRType &type) { + auto *meta = ir.find_meta(type.self); + if (!meta) + return; + + auto &m = meta->decoration; + if (m.alias.compare(0, 3, "gl_") == 0 || keywords.find(m.alias) != end(keywords)) + m.alias = join("_", m.alias); + + for (auto &memb : meta->members) + if (memb.alias.compare(0, 3, "gl_") == 0 || keywords.find(memb.alias) != end(keywords)) + memb.alias = join("_", memb.alias); + }); +} + void CompilerGLSL::replace_illegal_names() { // clang-format off @@ -2177,14 +2397,7 @@ void CompilerGLSL::replace_illegal_names() }; // clang-format on - ir.for_each_typed_id([&](uint32_t, const SPIRVariable &var) { - if (!is_hidden_variable(var)) - { - auto &m = ir.meta[var.self].decoration; - if (m.alias.compare(0, 3, "gl_") == 0 || keywords.find(m.alias) != end(keywords)) - m.alias = join("_", m.alias); - } - }); + replace_illegal_names(keywords); } void CompilerGLSL::replace_fragment_output(SPIRVariable &var) @@ -2291,11 +2504,14 @@ void CompilerGLSL::emit_pls() void CompilerGLSL::fixup_image_load_store_access() { + if (!options.enable_storage_image_qualifier_deduction) + return; + ir.for_each_typed_id([&](uint32_t var, const SPIRVariable &) { auto &vartype = expression_type(var); if (vartype.basetype == SPIRType::Image) { - // Older glslangValidator does not emit required qualifiers here. + // Very old glslangValidator and HLSL compilers do not emit required qualifiers here. // Solve this by making the image access as restricted as possible and loosen up if we need to. // If any no-read/no-write flags are actually set, assume that the compiler knows what it's doing. @@ -2309,6 +2525,52 @@ void CompilerGLSL::fixup_image_load_store_access() }); } +static bool is_block_builtin(BuiltIn builtin) +{ + return builtin == BuiltInPosition || builtin == BuiltInPointSize || builtin == BuiltInClipDistance || + builtin == BuiltInCullDistance; +} + +bool CompilerGLSL::should_force_emit_builtin_block(StorageClass storage) +{ + // If the builtin block uses XFB, we need to force explicit redeclaration of the builtin block. + + if (storage != StorageClassOutput) + return false; + bool should_force = false; + + ir.for_each_typed_id([&](uint32_t, SPIRVariable &var) { + if (should_force) + return; + + auto &type = this->get(var.basetype); + bool block = has_decoration(type.self, DecorationBlock); + if (var.storage == storage && block && is_builtin_variable(var)) + { + uint32_t member_count = uint32_t(type.member_types.size()); + for (uint32_t i = 0; i < member_count; i++) + { + if (has_member_decoration(type.self, i, DecorationBuiltIn) && + is_block_builtin(BuiltIn(get_member_decoration(type.self, i, DecorationBuiltIn))) && + has_member_decoration(type.self, i, DecorationOffset)) + { + should_force = true; + } + } + } + else if (var.storage == storage && !block && is_builtin_variable(var)) + { + if (is_block_builtin(BuiltIn(get_decoration(type.self, DecorationBuiltIn))) && + has_decoration(var.self, DecorationOffset)) + { + should_force = true; + } + } + }); + + return should_force; +} + void CompilerGLSL::emit_declared_builtin_block(StorageClass storage, ExecutionModel model) { Bitset emitted_builtins; @@ -2322,6 +2584,11 @@ void CompilerGLSL::emit_declared_builtin_block(StorageClass storage, ExecutionMo uint32_t cull_distance_size = 0; uint32_t clip_distance_size = 0; + bool have_xfb_buffer_stride = false; + bool have_any_xfb_offset = false; + uint32_t xfb_stride = 0, xfb_buffer = 0; + std::unordered_map builtin_xfb_offsets; + ir.for_each_typed_id([&](uint32_t, SPIRVariable &var) { auto &type = this->get(var.basetype); bool block = has_decoration(type.self, DecorationBlock); @@ -2339,9 +2606,29 @@ void CompilerGLSL::emit_declared_builtin_block(StorageClass storage, ExecutionMo cull_distance_size = this->get(type.member_types[index]).array.front(); else if (m.builtin_type == BuiltInClipDistance) clip_distance_size = this->get(type.member_types[index]).array.front(); + + if (is_block_builtin(m.builtin_type) && m.decoration_flags.get(DecorationOffset)) + { + have_any_xfb_offset = true; + builtin_xfb_offsets[m.builtin_type] = m.offset; + } } index++; } + + if (storage == StorageClassOutput && has_decoration(var.self, DecorationXfbBuffer) && + has_decoration(var.self, DecorationXfbStride)) + { + uint32_t buffer_index = get_decoration(var.self, DecorationXfbBuffer); + uint32_t stride = get_decoration(var.self, DecorationXfbStride); + if (have_xfb_buffer_stride && buffer_index != xfb_buffer) + SPIRV_CROSS_THROW("IO block member XfbBuffer mismatch."); + if (have_xfb_buffer_stride && stride != xfb_stride) + SPIRV_CROSS_THROW("IO block member XfbBuffer mismatch."); + have_xfb_buffer_stride = true; + xfb_buffer = buffer_index; + xfb_stride = stride; + } } else if (var.storage == storage && !block && is_builtin_variable(var)) { @@ -2354,6 +2641,22 @@ void CompilerGLSL::emit_declared_builtin_block(StorageClass storage, ExecutionMo cull_distance_size = type.array.front(); else if (m.builtin_type == BuiltInClipDistance) clip_distance_size = type.array.front(); + + if (is_block_builtin(m.builtin_type) && m.decoration_flags.get(DecorationXfbStride) && + m.decoration_flags.get(DecorationXfbBuffer) && m.decoration_flags.get(DecorationOffset)) + { + have_any_xfb_offset = true; + builtin_xfb_offsets[m.builtin_type] = m.offset; + uint32_t buffer_index = m.xfb_buffer; + uint32_t stride = m.xfb_stride; + if (have_xfb_buffer_stride && buffer_index != xfb_buffer) + SPIRV_CROSS_THROW("IO block member XfbBuffer mismatch."); + if (have_xfb_buffer_stride && stride != xfb_stride) + SPIRV_CROSS_THROW("IO block member XfbBuffer mismatch."); + have_xfb_buffer_stride = true; + xfb_buffer = buffer_index; + xfb_stride = stride; + } } } @@ -2382,21 +2685,71 @@ void CompilerGLSL::emit_declared_builtin_block(StorageClass storage, ExecutionMo return; if (storage == StorageClassOutput) - statement("out gl_PerVertex"); + { + if (have_xfb_buffer_stride && have_any_xfb_offset) + { + statement("layout(xfb_buffer = ", xfb_buffer, ", xfb_stride = ", xfb_stride, ") out gl_PerVertex"); + if (!options.es) + { + if (options.version < 440 && options.version >= 140) + require_extension_internal("GL_ARB_enhanced_layouts"); + else if (options.version < 140) + SPIRV_CROSS_THROW("Component decoration is not supported in targets below GLSL 1.40."); + if (!options.es && options.version < 440) + require_extension_internal("GL_ARB_enhanced_layouts"); + } + else if (options.es) + SPIRV_CROSS_THROW("Need GL_ARB_enhanced_layouts for xfb_stride or xfb_buffer."); + } + else + statement("out gl_PerVertex"); + } else - statement("in gl_PerVertex"); + { + // If we have passthrough, there is no way PerVertex cannot be passthrough. + if (get_entry_point().geometry_passthrough) + statement("layout(passthrough) in gl_PerVertex"); + else + statement("in gl_PerVertex"); + } begin_scope(); if (emitted_builtins.get(BuiltInPosition)) - statement("vec4 gl_Position;"); - if (emitted_builtins.get(BuiltInPointSize)) - statement("float gl_PointSize;"); - if (emitted_builtins.get(BuiltInClipDistance)) - statement("float gl_ClipDistance[", clip_distance_size, "];"); - if (emitted_builtins.get(BuiltInCullDistance)) - statement("float gl_CullDistance[", cull_distance_size, "];"); + { + auto itr = builtin_xfb_offsets.find(BuiltInPosition); + if (itr != end(builtin_xfb_offsets)) + statement("layout(xfb_offset = ", itr->second, ") vec4 gl_Position;"); + else + statement("vec4 gl_Position;"); + } + + if (emitted_builtins.get(BuiltInPointSize)) + { + auto itr = builtin_xfb_offsets.find(BuiltInPointSize); + if (itr != end(builtin_xfb_offsets)) + statement("layout(xfb_offset = ", itr->second, ") float gl_PointSize;"); + else + statement("float gl_PointSize;"); + } + + if (emitted_builtins.get(BuiltInClipDistance)) + { + auto itr = builtin_xfb_offsets.find(BuiltInClipDistance); + if (itr != end(builtin_xfb_offsets)) + statement("layout(xfb_offset = ", itr->second, ") float gl_ClipDistance[", clip_distance_size, "];"); + else + statement("float gl_ClipDistance[", clip_distance_size, "];"); + } + + if (emitted_builtins.get(BuiltInCullDistance)) + { + auto itr = builtin_xfb_offsets.find(BuiltInCullDistance); + if (itr != end(builtin_xfb_offsets)) + statement("layout(xfb_offset = ", itr->second, ") float gl_CullDistance[", cull_distance_size, "];"); + else + statement("float gl_CullDistance[", cull_distance_size, "];"); + } - bool tessellation = model == ExecutionModelTessellationEvaluation || model == ExecutionModelTessellationControl; if (builtin_array) { // Make sure the array has a supported name in the code. @@ -2408,7 +2761,7 @@ void CompilerGLSL::emit_declared_builtin_block(StorageClass storage, ExecutionMo if (model == ExecutionModelTessellationControl && storage == StorageClassOutput) end_scope_decl(join(to_name(block_var->self), "[", get_entry_point().output_vertices, "]")); else - end_scope_decl(join(to_name(block_var->self), tessellation ? "[gl_MaxPatchVertices]" : "[]")); + end_scope_decl(join(to_name(block_var->self), "[]")); } else end_scope_decl(); @@ -2429,7 +2782,7 @@ void CompilerGLSL::declare_undefined_values() bool CompilerGLSL::variable_is_lut(const SPIRVariable &var) const { - bool statically_assigned = var.statically_assigned && var.static_expression != 0 && var.remapped_variable; + bool statically_assigned = var.statically_assigned && var.static_expression != ID(0) && var.remapped_variable; if (statically_assigned) { @@ -2476,6 +2829,16 @@ void CompilerGLSL::emit_resources() break; } } + else if (should_force_emit_builtin_block(StorageClassOutput)) + { + emit_declared_builtin_block(StorageClassOutput, execution.model); + } + else if (execution.geometry_passthrough) + { + // Need to declare gl_in with Passthrough. + // If we're doing passthrough, we cannot emit an output block, so the output block test above will never pass. + emit_declared_builtin_block(StorageClassInput, execution.model); + } else { // Need to redeclare clip/cull distance with explicit size to use them. @@ -2558,7 +2921,7 @@ void CompilerGLSL::emit_resources() SpecializationConstant wg_x, wg_y, wg_z; get_work_group_size_specialization_constants(wg_x, wg_y, wg_z); - if ((wg_x.id != 0) || (wg_y.id != 0) || (wg_z.id != 0)) + if ((wg_x.id != ConstantID(0)) || (wg_y.id != ConstantID(0)) || (wg_z.id != ConstantID(0))) { SmallVector inputs; build_workgroup_size(inputs, wg_x, wg_y, wg_z); @@ -2706,7 +3069,7 @@ void CompilerGLSL::emit_resources() // Returns a string representation of the ID, usable as a function arg. // Default is to simply return the expression representation fo the arg ID. // Subclasses may override to modify the return value. -string CompilerGLSL::to_func_call_arg(uint32_t id) +string CompilerGLSL::to_func_call_arg(const SPIRFunction::Parameter &, uint32_t id) { // Make sure that we use the name of the original variable, and not the parameter alias. uint32_t name_id = id; @@ -2967,7 +3330,7 @@ string CompilerGLSL::to_composite_constructor_expression(uint32_t id) return to_rerolled_array_expression(to_enclosed_expression(id), type); } else - return to_expression(id); + return to_unpacked_expression(id); } string CompilerGLSL::to_expression(uint32_t id, bool register_expression_read) @@ -3329,11 +3692,19 @@ string CompilerGLSL::constant_expression(const SPIRConstant &c) { // Handles Arrays and structures. string res; + + // Allow Metal to use the array template to make arrays a value type + bool needs_trailing_tracket = false; if (backend.use_initializer_list && backend.use_typed_initializer_list && type.basetype == SPIRType::Struct && type.array.empty()) { res = type_to_glsl_constructor(type) + "{ "; } + else if (backend.use_initializer_list && backend.use_typed_initializer_list && backend.array_is_value_type && !type.array.empty()) + { + res = type_to_glsl_constructor(type) + "({ "; + needs_trailing_tracket = true; + } else if (backend.use_initializer_list) { res = "{ "; @@ -3356,8 +3727,23 @@ string CompilerGLSL::constant_expression(const SPIRConstant &c) } res += backend.use_initializer_list ? " }" : ")"; + if (needs_trailing_tracket) + res += ")"; + return res; } + else if (type.basetype == SPIRType::Struct && type.member_types.size() == 0) + { + // Metal tessellation likes empty structs which are then constant expressions. + if (backend.supports_empty_struct) + return "{ }"; + else if (backend.use_typed_initializer_list) + return join(type_to_glsl(get(c.constant_type)), "{ 0 }"); + else if (backend.use_initializer_list) + return "{ 0 }"; + else + return join(type_to_glsl(get(c.constant_type)), "(0)"); + } else if (c.columns() == 1) { return constant_expression_vector(c, 0); @@ -3812,15 +4198,6 @@ string CompilerGLSL::constant_expression_vector(const SPIRConstant &c, uint32_t if (splat) { res += convert_to_string(c.scalar(vector, 0)); - if (is_legacy()) - { - // Fake unsigned constant literals with signed ones if possible. - // Things like array sizes, etc, tend to be unsigned even though they could just as easily be signed. - if (c.scalar_i16(vector, 0) < 0) - SPIRV_CROSS_THROW("Tried to convert uint literal into int, but this made the literal negative."); - } - else - res += backend.uint16_t_literal_suffix; } else { @@ -3830,17 +4207,19 @@ string CompilerGLSL::constant_expression_vector(const SPIRConstant &c, uint32_t res += to_name(c.specialization_constant_id(vector, i)); else { - res += convert_to_string(c.scalar(vector, i)); - if (is_legacy()) + if (*backend.uint16_t_literal_suffix) { - // Fake unsigned constant literals with signed ones if possible. - // Things like array sizes, etc, tend to be unsigned even though they could just as easily be signed. - if (c.scalar_i16(vector, i) < 0) - SPIRV_CROSS_THROW( - "Tried to convert uint literal into int, but this made the literal negative."); + res += convert_to_string(c.scalar_u16(vector, i)); + res += backend.uint16_t_literal_suffix; } else - res += backend.uint16_t_literal_suffix; + { + // If backend doesn't have a literal suffix, we need to value cast. + res += type_to_glsl(scalar_type); + res += "("; + res += convert_to_string(c.scalar_u16(vector, i)); + res += ")"; + } } if (i + 1 < c.vector_size()) @@ -3853,7 +4232,6 @@ string CompilerGLSL::constant_expression_vector(const SPIRConstant &c, uint32_t if (splat) { res += convert_to_string(c.scalar_i16(vector, 0)); - res += backend.int16_t_literal_suffix; } else { @@ -3863,9 +4241,21 @@ string CompilerGLSL::constant_expression_vector(const SPIRConstant &c, uint32_t res += to_name(c.specialization_constant_id(vector, i)); else { - res += convert_to_string(c.scalar_i16(vector, i)); - res += backend.int16_t_literal_suffix; + if (*backend.int16_t_literal_suffix) + { + res += convert_to_string(c.scalar_i16(vector, i)); + res += backend.int16_t_literal_suffix; + } + else + { + // If backend doesn't have a literal suffix, we need to value cast. + res += type_to_glsl(scalar_type); + res += "("; + res += convert_to_string(c.scalar_i16(vector, i)); + res += ")"; + } } + if (i + 1 < c.vector_size()) res += ", "; } @@ -4090,8 +4480,18 @@ void CompilerGLSL::emit_unrolled_unary_op(uint32_t result_type, uint32_t result_ } void CompilerGLSL::emit_unrolled_binary_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, - const char *op) + const char *op, bool negate, SPIRType::BaseType expected_type) { + auto &type0 = expression_type(op0); + auto &type1 = expression_type(op1); + + SPIRType target_type0 = type0; + SPIRType target_type1 = type1; + target_type0.basetype = expected_type; + target_type1.basetype = expected_type; + target_type0.vecsize = 1; + target_type1.vecsize = 1; + auto &type = get(result_type); auto expr = type_to_glsl_constructor(type); expr += '('; @@ -4099,11 +4499,25 @@ void CompilerGLSL::emit_unrolled_binary_op(uint32_t result_type, uint32_t result { // Make sure to call to_expression multiple times to ensure // that these expressions are properly flushed to temporaries if needed. - expr += to_extract_component_expression(op0, i); + if (negate) + expr += "!("; + + if (expected_type != SPIRType::Unknown && type0.basetype != expected_type) + expr += bitcast_expression(target_type0, type0.basetype, to_extract_component_expression(op0, i)); + else + expr += to_extract_component_expression(op0, i); + expr += ' '; expr += op; expr += ' '; - expr += to_extract_component_expression(op1, i); + + if (expected_type != SPIRType::Unknown && type1.basetype != expected_type) + expr += bitcast_expression(target_type1, type1.basetype, to_extract_component_expression(op1, i)); + else + expr += to_extract_component_expression(op1, i); + + if (negate) + expr += ")"; if (i + 1 < type.vecsize) expr += ", "; @@ -4225,6 +4639,58 @@ void CompilerGLSL::emit_unary_func_op_cast(uint32_t result_type, uint32_t result inherit_expression_dependencies(result_id, op0); } +// Very special case. Handling bitfieldExtract requires us to deal with different bitcasts of different signs +// and different vector sizes all at once. Need a special purpose method here. +void CompilerGLSL::emit_trinary_func_op_bitextract(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, + uint32_t op2, const char *op, + SPIRType::BaseType expected_result_type, + SPIRType::BaseType input_type0, SPIRType::BaseType input_type1, + SPIRType::BaseType input_type2) +{ + auto &out_type = get(result_type); + auto expected_type = out_type; + expected_type.basetype = input_type0; + + string cast_op0 = + expression_type(op0).basetype != input_type0 ? bitcast_glsl(expected_type, op0) : to_unpacked_expression(op0); + + auto op1_expr = to_unpacked_expression(op1); + auto op2_expr = to_unpacked_expression(op2); + + // Use value casts here instead. Input must be exactly int or uint, but SPIR-V might be 16-bit. + expected_type.basetype = input_type1; + expected_type.vecsize = 1; + string cast_op1 = expression_type(op1).basetype != input_type1 ? + join(type_to_glsl_constructor(expected_type), "(", op1_expr, ")") : + op1_expr; + + expected_type.basetype = input_type2; + expected_type.vecsize = 1; + string cast_op2 = expression_type(op2).basetype != input_type2 ? + join(type_to_glsl_constructor(expected_type), "(", op2_expr, ")") : + op2_expr; + + string expr; + if (out_type.basetype != expected_result_type) + { + expected_type.vecsize = out_type.vecsize; + expected_type.basetype = expected_result_type; + expr = bitcast_glsl_op(out_type, expected_type); + expr += '('; + expr += join(op, "(", cast_op0, ", ", cast_op1, ", ", cast_op2, ")"); + expr += ')'; + } + else + { + expr += join(op, "(", cast_op0, ", ", cast_op1, ", ", cast_op2, ")"); + } + + emit_op(result_type, result_id, expr, should_forward(op0) && should_forward(op1) && should_forward(op2)); + inherit_expression_dependencies(result_id, op0); + inherit_expression_dependencies(result_id, op1); + inherit_expression_dependencies(result_id, op2); +} + void CompilerGLSL::emit_trinary_func_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, uint32_t op2, const char *op, SPIRType::BaseType input_type) { @@ -4257,6 +4723,34 @@ void CompilerGLSL::emit_trinary_func_op_cast(uint32_t result_type, uint32_t resu inherit_expression_dependencies(result_id, op2); } +void CompilerGLSL::emit_binary_func_op_cast_clustered(uint32_t result_type, uint32_t result_id, uint32_t op0, + uint32_t op1, const char *op, SPIRType::BaseType input_type) +{ + // Special purpose method for implementing clustered subgroup opcodes. + // Main difference is that op1 does not participate in any casting, it needs to be a literal. + auto &out_type = get(result_type); + auto expected_type = out_type; + expected_type.basetype = input_type; + string cast_op0 = + expression_type(op0).basetype != input_type ? bitcast_glsl(expected_type, op0) : to_unpacked_expression(op0); + + string expr; + if (out_type.basetype != input_type) + { + expr = bitcast_glsl_op(out_type, expected_type); + expr += '('; + expr += join(op, "(", cast_op0, ", ", to_expression(op1), ")"); + expr += ')'; + } + else + { + expr += join(op, "(", cast_op0, ", ", to_expression(op1), ")"); + } + + emit_op(result_type, result_id, expr, should_forward(op0)); + inherit_expression_dependencies(result_id, op0); +} + void CompilerGLSL::emit_binary_func_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, const char *op, SPIRType::BaseType input_type, bool skip_cast_if_equal_type) { @@ -4313,6 +4807,44 @@ void CompilerGLSL::emit_quaternary_func_op(uint32_t result_type, uint32_t result inherit_expression_dependencies(result_id, op3); } +void CompilerGLSL::emit_bitfield_insert_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, + uint32_t op2, uint32_t op3, const char *op, + SPIRType::BaseType offset_count_type) +{ + // Only need to cast offset/count arguments. Types of base/insert must be same as result type, + // and bitfieldInsert is sign invariant. + bool forward = should_forward(op0) && should_forward(op1) && should_forward(op2) && should_forward(op3); + + auto op0_expr = to_unpacked_expression(op0); + auto op1_expr = to_unpacked_expression(op1); + auto op2_expr = to_unpacked_expression(op2); + auto op3_expr = to_unpacked_expression(op3); + + SPIRType target_type; + target_type.vecsize = 1; + target_type.basetype = offset_count_type; + + if (expression_type(op2).basetype != offset_count_type) + { + // Value-cast here. Input might be 16-bit. GLSL requires int. + op2_expr = join(type_to_glsl_constructor(target_type), "(", op2_expr, ")"); + } + + if (expression_type(op3).basetype != offset_count_type) + { + // Value-cast here. Input might be 16-bit. GLSL requires int. + op3_expr = join(type_to_glsl_constructor(target_type), "(", op3_expr, ")"); + } + + emit_op(result_type, result_id, join(op, "(", op0_expr, ", ", op1_expr, ", ", op2_expr, ", ", op3_expr, ")"), + forward); + + inherit_expression_dependencies(result_id, op0); + inherit_expression_dependencies(result_id, op1); + inherit_expression_dependencies(result_id, op2); + inherit_expression_dependencies(result_id, op3); +} + // EXT_shader_texture_lod only concerns fragment shaders so lod tex functions // are not allowed in ES 2 vertex shaders. But SPIR-V only supports lod tex // functions in vertex shaders so we revert those back to plain calls when @@ -4580,7 +5112,7 @@ void CompilerGLSL::emit_mix_op(uint32_t result_type, uint32_t id, uint32_t left, emit_trinary_func_op(result_type, id, left, right, lerp, "mix"); } -string CompilerGLSL::to_combined_image_sampler(uint32_t image_id, uint32_t samp_id) +string CompilerGLSL::to_combined_image_sampler(VariableID image_id, VariableID samp_id) { // Keep track of the array indices we have used to load the image. // We'll need to use the same array index into the combined image sampler array. @@ -4602,18 +5134,18 @@ string CompilerGLSL::to_combined_image_sampler(uint32_t image_id, uint32_t samp_ samp_id = samp->self; auto image_itr = find_if(begin(args), end(args), - [image_id](const SPIRFunction::Parameter ¶m) { return param.id == image_id; }); + [image_id](const SPIRFunction::Parameter ¶m) { return image_id == param.id; }); auto sampler_itr = find_if(begin(args), end(args), - [samp_id](const SPIRFunction::Parameter ¶m) { return param.id == samp_id; }); + [samp_id](const SPIRFunction::Parameter ¶m) { return samp_id == param.id; }); if (image_itr != end(args) || sampler_itr != end(args)) { // If any parameter originates from a parameter, we will find it in our argument list. bool global_image = image_itr == end(args); bool global_sampler = sampler_itr == end(args); - uint32_t iid = global_image ? image_id : uint32_t(image_itr - begin(args)); - uint32_t sid = global_sampler ? samp_id : uint32_t(sampler_itr - begin(args)); + VariableID iid = global_image ? image_id : VariableID(uint32_t(image_itr - begin(args))); + VariableID sid = global_sampler ? samp_id : VariableID(uint32_t(sampler_itr - begin(args))); auto &combined = current_function->combined_parameters; auto itr = find_if(begin(combined), end(combined), [=](const SPIRFunction::CombinedImageSamplerParameter &p) { @@ -4654,16 +5186,16 @@ void CompilerGLSL::emit_sampled_image_op(uint32_t result_type, uint32_t result_i { emit_binary_func_op(result_type, result_id, image_id, samp_id, type_to_glsl(get(result_type), result_id).c_str()); - - // Make sure to suppress usage tracking and any expression invalidation. - // It is illegal to create temporaries of opaque types. - forwarded_temporaries.erase(result_id); } else { // Make sure to suppress usage tracking. It is illegal to create temporaries of opaque types. emit_op(result_type, result_id, to_combined_image_sampler(image_id, samp_id), true, true); } + + // Make sure to suppress usage tracking and any expression invalidation. + // It is illegal to create temporaries of opaque types. + forwarded_temporaries.erase(result_id); } static inline bool image_opcode_is_sample_no_dref(Op op) @@ -4693,13 +5225,41 @@ void CompilerGLSL::emit_texture_op(const Instruction &i) { auto *ops = stream(i); auto op = static_cast(i.op); - uint32_t length = i.length; SmallVector inherited_expressions; uint32_t result_type_id = ops[0]; uint32_t id = ops[1]; - uint32_t img = ops[2]; + + bool forward = false; + string expr = to_texture_op(i, &forward, inherited_expressions); + emit_op(result_type_id, id, expr, forward); + for (auto &inherit : inherited_expressions) + inherit_expression_dependencies(id, inherit); + + switch (op) + { + case OpImageSampleDrefImplicitLod: + case OpImageSampleImplicitLod: + case OpImageSampleProjImplicitLod: + case OpImageSampleProjDrefImplicitLod: + register_control_dependent_expression(id); + break; + + default: + break; + } +} + +std::string CompilerGLSL::to_texture_op(const Instruction &i, bool *forward, + SmallVector &inherited_expressions) +{ + auto *ops = stream(i); + auto op = static_cast(i.op); + uint32_t length = i.length; + + uint32_t result_type_id = ops[0]; + VariableID img = ops[2]; uint32_t coord = ops[3]; uint32_t dref = 0; uint32_t comp = 0; @@ -4839,12 +5399,11 @@ void CompilerGLSL::emit_texture_op(const Instruction &i) test(minlod, ImageOperandsMinLodMask); string expr; - bool forward = false; expr += to_function_name(img, imgtype, !!fetch, !!gather, !!proj, !!coffsets, (!!coffset || !!offset), (!!grad_x || !!grad_y), !!dref, lod, minlod); expr += "("; expr += to_function_args(img, imgtype, fetch, gather, proj, coord, coord_components, dref, grad_x, grad_y, lod, - coffset, offset, bias, comp, sample, minlod, &forward); + coffset, offset, bias, comp, sample, minlod, forward); expr += ")"; // texture(samplerXShadow) returns float. shadowX() returns vec4. Swizzle here. @@ -4857,7 +5416,7 @@ void CompilerGLSL::emit_texture_op(const Instruction &i) { bool image_is_depth = false; const auto *combined = maybe_get(img); - uint32_t image_id = combined ? combined->image : img; + VariableID image_id = combined ? combined->image : img; if (combined && image_is_comparison(imgtype, combined->image)) image_is_depth = true; @@ -4886,22 +5445,7 @@ void CompilerGLSL::emit_texture_op(const Instruction &i) if (op == OpImageRead) expr = remap_swizzle(result_type, 4, expr); - emit_op(result_type_id, id, expr, forward); - for (auto &inherit : inherited_expressions) - inherit_expression_dependencies(id, inherit); - - switch (op) - { - case OpImageSampleDrefImplicitLod: - case OpImageSampleImplicitLod: - case OpImageSampleProjImplicitLod: - case OpImageSampleProjDrefImplicitLod: - register_control_dependent_expression(id); - break; - - default: - break; - } + return expr; } bool CompilerGLSL::expression_is_constant_null(uint32_t id) const @@ -4914,7 +5458,7 @@ bool CompilerGLSL::expression_is_constant_null(uint32_t id) const // Returns the function name for a texture sampling function for the specified image and sampling characteristics. // For some subclasses, the function is a method on the specified image. -string CompilerGLSL::to_function_name(uint32_t tex, const SPIRType &imgtype, bool is_fetch, bool is_gather, +string CompilerGLSL::to_function_name(VariableID tex, const SPIRType &imgtype, bool is_fetch, bool is_gather, bool is_proj, bool has_array_offsets, bool has_offset, bool has_grad, bool, uint32_t lod, uint32_t minlod) { @@ -4976,10 +5520,19 @@ std::string CompilerGLSL::convert_separate_image_to_expression(uint32_t id) { if (options.vulkan_semantics) { - // Newer glslang supports this extension to deal with texture2D as argument to texture functions. if (dummy_sampler_id) - SPIRV_CROSS_THROW("Vulkan GLSL should not have a dummy sampler for combining."); - require_extension_internal("GL_EXT_samplerless_texture_functions"); + { + // Don't need to consider Shadow state since the dummy sampler is always non-shadow. + auto sampled_type = type; + sampled_type.basetype = SPIRType::SampledImage; + return join(type_to_glsl(sampled_type), "(", to_expression(id), ", ", + to_expression(dummy_sampler_id), ")"); + } + else + { + // Newer glslang supports this extension to deal with texture2D as argument to texture functions. + require_extension_internal("GL_EXT_samplerless_texture_functions"); + } } else { @@ -4996,7 +5549,7 @@ std::string CompilerGLSL::convert_separate_image_to_expression(uint32_t id) } // Returns the function args for a texture sampling function for the specified image and sampling characteristics. -string CompilerGLSL::to_function_args(uint32_t img, const SPIRType &imgtype, bool is_fetch, bool is_gather, +string CompilerGLSL::to_function_args(VariableID img, const SPIRType &imgtype, bool is_fetch, bool is_gather, bool is_proj, uint32_t coord, uint32_t coord_components, uint32_t dref, uint32_t grad_x, uint32_t grad_y, uint32_t lod, uint32_t coffset, uint32_t offset, uint32_t bias, uint32_t comp, uint32_t sample, uint32_t /*minlod*/, @@ -5277,7 +5830,6 @@ void CompilerGLSL::emit_glsl_op(uint32_t result_type, uint32_t id, uint32_t eop, case GLSLstd450ModfStruct: { - forced_temporaries.insert(id); auto &type = get(result_type); emit_uninitialized_temporary_expression(result_type, id); statement(to_expression(id), ".", to_member_name(type, 0), " = ", "modf(", to_expression(args[0]), ", ", @@ -5417,7 +5969,6 @@ void CompilerGLSL::emit_glsl_op(uint32_t result_type, uint32_t id, uint32_t eop, case GLSLstd450FrexpStruct: { - forced_temporaries.insert(id); auto &type = get(result_type); emit_uninitialized_temporary_expression(result_type, id); statement(to_expression(id), ".", to_member_name(type, 0), " = ", "frexp(", to_expression(args[0]), ", ", @@ -5426,8 +5977,28 @@ void CompilerGLSL::emit_glsl_op(uint32_t result_type, uint32_t id, uint32_t eop, } case GLSLstd450Ldexp: - emit_binary_func_op(result_type, id, args[0], args[1], "ldexp"); + { + bool forward = should_forward(args[0]) && should_forward(args[1]); + + auto op0 = to_unpacked_expression(args[0]); + auto op1 = to_unpacked_expression(args[1]); + auto &op1_type = expression_type(args[1]); + if (op1_type.basetype != SPIRType::Int) + { + // Need a value cast here. + auto target_type = op1_type; + target_type.basetype = SPIRType::Int; + op1 = join(type_to_glsl_constructor(target_type), "(", op1, ")"); + } + + auto expr = join("ldexp(", op0, ", ", op1, ")"); + + emit_op(result_type, id, expr, forward); + inherit_expression_dependencies(id, args[0]); + inherit_expression_dependencies(id, args[1]); break; + } + case GLSLstd450PackSnorm4x8: emit_unary_func_op(result_type, id, args[0], "packSnorm4x8"); break; @@ -5730,6 +6301,11 @@ void CompilerGLSL::emit_subgroup_op(const Instruction &i) if (!options.vulkan_semantics) SPIRV_CROSS_THROW("Can only use subgroup operations in Vulkan semantics."); + // If we need to do implicit bitcasts, make sure we do it with the correct type. + uint32_t integer_width = get_integer_width_for_instruction(i); + auto int_type = to_signed_basetype(integer_width); + auto uint_type = to_unsigned_basetype(integer_width); + switch (op) { case OpGroupNonUniformElect: @@ -5901,20 +6477,39 @@ case OpGroupNonUniform##op: \ SPIRV_CROSS_THROW("Invalid group operation."); \ break; \ } + +#define GLSL_GROUP_OP_CAST(op, glsl_op, type) \ +case OpGroupNonUniform##op: \ + { \ + auto operation = static_cast(ops[3]); \ + if (operation == GroupOperationReduce) \ + emit_unary_func_op_cast(result_type, id, ops[4], "subgroup" #glsl_op, type, type); \ + else if (operation == GroupOperationInclusiveScan) \ + emit_unary_func_op_cast(result_type, id, ops[4], "subgroupInclusive" #glsl_op, type, type); \ + else if (operation == GroupOperationExclusiveScan) \ + emit_unary_func_op_cast(result_type, id, ops[4], "subgroupExclusive" #glsl_op, type, type); \ + else if (operation == GroupOperationClusteredReduce) \ + emit_binary_func_op_cast_clustered(result_type, id, ops[4], ops[5], "subgroupClustered" #glsl_op, type); \ + else \ + SPIRV_CROSS_THROW("Invalid group operation."); \ + break; \ + } + GLSL_GROUP_OP(FAdd, Add) GLSL_GROUP_OP(FMul, Mul) GLSL_GROUP_OP(FMin, Min) GLSL_GROUP_OP(FMax, Max) GLSL_GROUP_OP(IAdd, Add) GLSL_GROUP_OP(IMul, Mul) - GLSL_GROUP_OP(SMin, Min) - GLSL_GROUP_OP(SMax, Max) - GLSL_GROUP_OP(UMin, Min) - GLSL_GROUP_OP(UMax, Max) + GLSL_GROUP_OP_CAST(SMin, Min, int_type) + GLSL_GROUP_OP_CAST(SMax, Max, int_type) + GLSL_GROUP_OP_CAST(UMin, Min, uint_type) + GLSL_GROUP_OP_CAST(UMax, Max, uint_type) GLSL_GROUP_OP(BitwiseAnd, And) GLSL_GROUP_OP(BitwiseOr, Or) GLSL_GROUP_OP(BitwiseXor, Xor) #undef GLSL_GROUP_OP +#undef GLSL_GROUP_OP_CAST // clang-format on case OpGroupNonUniformQuadSwap: @@ -6364,12 +6959,43 @@ const char *CompilerGLSL::index_to_swizzle(uint32_t index) } } +void CompilerGLSL::access_chain_internal_append_index(std::string &expr, uint32_t /*base*/, const SPIRType *type, + AccessChainFlags flags, bool & /*access_chain_is_arrayed*/, + uint32_t index) +{ + bool index_is_literal = (flags & ACCESS_CHAIN_INDEX_IS_LITERAL_BIT) != 0; + bool register_expression_read = (flags & ACCESS_CHAIN_SKIP_REGISTER_EXPRESSION_READ_BIT) == 0; + + expr += "["; + + // If we are indexing into an array of SSBOs or UBOs, we need to index it with a non-uniform qualifier. + bool nonuniform_index = + has_decoration(index, DecorationNonUniformEXT) && + (has_decoration(type->self, DecorationBlock) || has_decoration(type->self, DecorationBufferBlock)); + if (nonuniform_index) + { + expr += backend.nonuniform_qualifier; + expr += "("; + } + + if (index_is_literal) + expr += convert_to_string(index); + else + expr += to_expression(index, register_expression_read); + + if (nonuniform_index) + expr += ")"; + + expr += "]"; +} + string CompilerGLSL::access_chain_internal(uint32_t base, const uint32_t *indices, uint32_t count, AccessChainFlags flags, AccessChainMeta *meta) { string expr; bool index_is_literal = (flags & ACCESS_CHAIN_INDEX_IS_LITERAL_BIT) != 0; + bool msb_is_id = (flags & ACCESS_CHAIN_LITERAL_MSB_FORCE_ID) != 0; bool chain_only = (flags & ACCESS_CHAIN_CHAIN_ONLY_BIT) != 0; bool ptr_chain = (flags & ACCESS_CHAIN_PTR_CHAIN_BIT) != 0; bool register_expression_read = (flags & ACCESS_CHAIN_SKIP_REGISTER_EXPRESSION_READ_BIT) == 0; @@ -6414,34 +7040,24 @@ string CompilerGLSL::access_chain_internal(uint32_t base, const uint32_t *indice bool pending_array_enclose = false; bool dimension_flatten = false; - const auto append_index = [&](uint32_t index) { - expr += "["; - - // If we are indexing into an array of SSBOs or UBOs, we need to index it with a non-uniform qualifier. - bool nonuniform_index = - has_decoration(index, DecorationNonUniformEXT) && - (has_decoration(type->self, DecorationBlock) || has_decoration(type->self, DecorationBufferBlock)); - if (nonuniform_index) - { - expr += backend.nonuniform_qualifier; - expr += "("; - } - - if (index_is_literal) - expr += convert_to_string(index); - else - expr += to_expression(index, register_expression_read); - - if (nonuniform_index) - expr += ")"; - - expr += "]"; + const auto append_index = [&](uint32_t index, bool is_literal) { + AccessChainFlags mod_flags = flags; + if (!is_literal) + mod_flags &= ~ACCESS_CHAIN_INDEX_IS_LITERAL_BIT; + access_chain_internal_append_index(expr, base, type, mod_flags, access_chain_is_arrayed, index); }; for (uint32_t i = 0; i < count; i++) { uint32_t index = indices[i]; + bool is_literal = index_is_literal; + if (is_literal && msb_is_id && (index >> 31u) != 0u) + { + is_literal = false; + index &= 0x7fffffffu; + } + // Pointer chains if (ptr_chain && i == 0) { @@ -6458,7 +7074,7 @@ string CompilerGLSL::access_chain_internal(uint32_t base, const uint32_t *indice if (options.flatten_multidimensional_arrays && dimension_flatten) { // If we are flattening multidimensional arrays, do manual stride computation. - if (index_is_literal) + if (is_literal) expr += convert_to_string(index); else expr += to_enclosed_expression(index, register_expression_read); @@ -6479,7 +7095,7 @@ string CompilerGLSL::access_chain_internal(uint32_t base, const uint32_t *indice } else { - append_index(index); + append_index(index, is_literal); } if (type->basetype == SPIRType::ControlPointArray) @@ -6526,11 +7142,11 @@ string CompilerGLSL::access_chain_internal(uint32_t base, const uint32_t *indice else if (var->storage == StorageClassOutput) expr = join("gl_out[", to_expression(index, register_expression_read), "].", expr); else - append_index(index); + append_index(index, is_literal); break; default: - append_index(index); + append_index(index, is_literal); break; } } @@ -6539,7 +7155,7 @@ string CompilerGLSL::access_chain_internal(uint32_t base, const uint32_t *indice // If we are flattening multidimensional arrays, do manual stride computation. auto &parent_type = get(type->parent_type); - if (index_is_literal) + if (is_literal) expr += convert_to_string(index); else expr += to_enclosed_expression(index, register_expression_read); @@ -6558,9 +7174,11 @@ string CompilerGLSL::access_chain_internal(uint32_t base, const uint32_t *indice if (!pending_array_enclose) expr += "]"; } - else + // Some builtins are arrays in SPIR-V but not in other languages, e.g. gl_SampleMask[] is an array in SPIR-V but not in Metal. + // By throwing away the index, we imply the index was 0, which it must be for gl_SampleMask. + else if (!builtin_translates_to_nonarray(BuiltIn(get_decoration(base, DecorationBuiltIn)))) { - append_index(index); + append_index(index, is_literal); } type_id = type->parent_type; @@ -6572,7 +7190,7 @@ string CompilerGLSL::access_chain_internal(uint32_t base, const uint32_t *indice // We also check if this member is a builtin, since we then replace the entire expression with the builtin one. else if (type->basetype == SPIRType::Struct) { - if (!index_is_literal) + if (!is_literal) index = get(index).scalar(); if (index >= type->member_types.size()) @@ -6619,7 +7237,7 @@ string CompilerGLSL::access_chain_internal(uint32_t base, const uint32_t *indice // by flipping indexing order of the matrix. expr += "["; - if (index_is_literal) + if (is_literal) expr += convert_to_string(index); else expr += to_expression(index, register_expression_read); @@ -6643,7 +7261,7 @@ string CompilerGLSL::access_chain_internal(uint32_t base, const uint32_t *indice } } - if (index_is_literal && !is_packed && !row_major_matrix_needs_conversion) + if (is_literal && !is_packed && !row_major_matrix_needs_conversion) { expr += "."; expr += index_to_swizzle(index); @@ -6651,10 +7269,18 @@ string CompilerGLSL::access_chain_internal(uint32_t base, const uint32_t *indice else if (ir.ids[index].get_type() == TypeConstant && !is_packed && !row_major_matrix_needs_conversion) { auto &c = get(index); - expr += "."; - expr += index_to_swizzle(c.scalar()); + if (c.specialization) + { + // If the index is a spec constant, we cannot turn extract into a swizzle. + expr += join("[", to_expression(index), "]"); + } + else + { + expr += "."; + expr += index_to_swizzle(c.scalar()); + } } - else if (index_is_literal) + else if (is_literal) { // For packed vectors, we can only access them as an array, not by swizzle. expr += join("[", index, "]"); @@ -6708,9 +7334,10 @@ string CompilerGLSL::access_chain(uint32_t base, const uint32_t *indices, uint32 if (flattened_buffer_blocks.count(base)) { uint32_t matrix_stride = 0; + uint32_t array_stride = 0; bool need_transpose = false; flattened_access_chain_offset(expression_type(base), indices, count, 0, 16, &need_transpose, &matrix_stride, - ptr_chain); + &array_stride, ptr_chain); if (meta) { @@ -6718,7 +7345,8 @@ string CompilerGLSL::access_chain(uint32_t base, const uint32_t *indices, uint32 meta->storage_is_packed = false; } - return flattened_access_chain(base, indices, count, target_type, 0, matrix_stride, need_transpose); + return flattened_access_chain(base, indices, count, target_type, 0, matrix_stride, array_stride, + need_transpose); } else if (flattened_structs.count(base) && count > 0) { @@ -6789,7 +7417,7 @@ void CompilerGLSL::store_flattened_struct(SPIRVariable &var, uint32_t value) std::string CompilerGLSL::flattened_access_chain(uint32_t base, const uint32_t *indices, uint32_t count, const SPIRType &target_type, uint32_t offset, uint32_t matrix_stride, - bool need_transpose) + uint32_t /* array_stride */, bool need_transpose) { if (!target_type.array.empty()) SPIRV_CROSS_THROW("Access chains that result in an array can not be flattened"); @@ -6828,7 +7456,7 @@ std::string CompilerGLSL::flattened_access_chain_struct(uint32_t base, const uin } auto tmp = flattened_access_chain(base, indices, count, member_type, offset + member_offset, matrix_stride, - need_transpose); + 0 /* array_stride */, need_transpose); // Cannot forward transpositions, so resolve them here. if (need_transpose) @@ -6935,24 +7563,17 @@ std::string CompilerGLSL::flattened_access_chain_vector(uint32_t base, const uin std::pair CompilerGLSL::flattened_access_chain_offset( const SPIRType &basetype, const uint32_t *indices, uint32_t count, uint32_t offset, uint32_t word_stride, - bool *need_transpose, uint32_t *out_matrix_stride, bool ptr_chain) + bool *need_transpose, uint32_t *out_matrix_stride, uint32_t *out_array_stride, bool ptr_chain) { // Start traversing type hierarchy at the proper non-pointer types. const auto *type = &get_pointee_type(basetype); - // This holds the type of the current pointer which we are traversing through. - // We always start out from a struct type which is the block. - // This is primarily used to reflect the array strides and matrix strides later. - // For the first access chain index, type_id won't be needed, so just keep it as 0, it will be set - // accordingly as members of structs are accessed. - assert(type->basetype == SPIRType::Struct); - uint32_t type_id = 0; - std::string expr; // Inherit matrix information in case we are access chaining a vector which might have come from a row major layout. bool row_major_matrix_needs_conversion = need_transpose ? *need_transpose : false; uint32_t matrix_stride = out_matrix_stride ? *out_matrix_stride : 0; + uint32_t array_stride = out_array_stride ? *out_array_stride : 0; for (uint32_t i = 0; i < count; i++) { @@ -6962,7 +7583,7 @@ std::pair CompilerGLSL::flattened_access_chain_offset( if (ptr_chain && i == 0) { // Here, the pointer type will be decorated with an array stride. - uint32_t array_stride = get_decoration(basetype.self, DecorationArrayStride); + array_stride = get_decoration(basetype.self, DecorationArrayStride); if (!array_stride) SPIRV_CROSS_THROW("SPIR-V does not define ArrayStride for buffer block."); @@ -6988,16 +7609,10 @@ std::pair CompilerGLSL::flattened_access_chain_offset( expr += convert_to_string(array_stride / word_stride); expr += " + "; } - // Type ID is unchanged. } // Arrays else if (!type->array.empty()) { - // Here, the type_id will be a type ID for the array type itself. - uint32_t array_stride = get_decoration(type_id, DecorationArrayStride); - if (!array_stride) - SPIRV_CROSS_THROW("SPIR-V does not define ArrayStride for buffer block."); - auto *constant = maybe_get(index); if (constant) { @@ -7023,9 +7638,9 @@ std::pair CompilerGLSL::flattened_access_chain_offset( uint32_t parent_type = type->parent_type; type = &get(parent_type); - type_id = parent_type; - // Type ID now refers to the array type with one less dimension. + if (!type->array.empty()) + array_stride = get_decoration(parent_type, DecorationArrayStride); } // For structs, the index refers to a constant, which indexes into the members. // We also check if this member is a builtin, since we then replace the entire expression with the builtin one. @@ -7037,7 +7652,6 @@ std::pair CompilerGLSL::flattened_access_chain_offset( SPIRV_CROSS_THROW("Member index is out of bounds!"); offset += type_struct_member_offset(*type, index); - type_id = type->member_types[index]; auto &struct_type = *type; type = &get(type->member_types[index]); @@ -7050,6 +7664,9 @@ std::pair CompilerGLSL::flattened_access_chain_offset( } else row_major_matrix_needs_conversion = false; + + if (!type->array.empty()) + array_stride = type_struct_member_array_stride(struct_type, index); } // Matrix -> Vector else if (type->columns > 1) @@ -7078,9 +7695,7 @@ std::pair CompilerGLSL::flattened_access_chain_offset( expr += " + "; } - uint32_t parent_type = type->parent_type; type = &get(type->parent_type); - type_id = parent_type; } // Vector -> Scalar else if (type->vecsize > 1) @@ -7109,9 +7724,7 @@ std::pair CompilerGLSL::flattened_access_chain_offset( expr += " + "; } - uint32_t parent_type = type->parent_type; type = &get(type->parent_type); - type_id = parent_type; } else SPIRV_CROSS_THROW("Cannot subdivide a scalar value!"); @@ -7121,6 +7734,8 @@ std::pair CompilerGLSL::flattened_access_chain_offset( *need_transpose = row_major_matrix_needs_conversion; if (out_matrix_stride) *out_matrix_stride = matrix_stride; + if (out_array_stride) + *out_array_stride = array_stride; return std::make_pair(expr, offset); } @@ -7272,23 +7887,29 @@ string CompilerGLSL::variable_decl_function_local(SPIRVariable &var) void CompilerGLSL::emit_variable_temporary_copies(const SPIRVariable &var) { - if (var.allocate_temporary_copy) + // Ensure that we declare phi-variable copies even if the original declaration isn't deferred + if (var.allocate_temporary_copy && !flushed_phi_variables.count(var.self)) { auto &type = get(var.basetype); auto &flags = get_decoration_bitset(var.self); statement(flags_to_qualifiers_glsl(type, flags), variable_decl(type, join("_", var.self, "_copy")), ";"); + flushed_phi_variables.insert(var.self); } } void CompilerGLSL::flush_variable_declaration(uint32_t id) { + // Ensure that we declare phi-variable copies even if the original declaration isn't deferred auto *var = maybe_get(id); if (var && var->deferred_declaration) { statement(variable_decl_function_local(*var), ";"); - emit_variable_temporary_copies(*var); var->deferred_declaration = false; } + if (var) + { + emit_variable_temporary_copies(*var); + } } bool CompilerGLSL::remove_duplicate_swizzle(string &op) @@ -7396,7 +8017,7 @@ bool CompilerGLSL::remove_unity_swizzle(uint32_t base, string &op) string CompilerGLSL::build_composite_combiner(uint32_t return_type, const uint32_t *elems, uint32_t length) { - uint32_t base = 0; + ID base = 0; string op; string subop; @@ -7457,7 +8078,7 @@ string CompilerGLSL::build_composite_combiner(uint32_t return_type, const uint32 subop = to_composite_constructor_expression(elems[i]); } - base = e ? e->base_expression : 0; + base = e ? e->base_expression : ID(0); } if (swizzle_optimization) @@ -7544,14 +8165,16 @@ void CompilerGLSL::disallow_forwarding_in_expression_chain(const SPIRExpression // Allow trivially forwarded expressions like OpLoad or trivial shuffles, // these will be marked as having suppressed usage tracking. // Our only concern is to make sure arithmetic operations are done in similar ways. - if (expression_is_forwarded(expr.self) && !expression_suppresses_usage_tracking(expr.self)) + if (expression_is_forwarded(expr.self) && !expression_suppresses_usage_tracking(expr.self) && + forced_invariant_temporaries.count(expr.self) == 0) { forced_temporaries.insert(expr.self); + forced_invariant_temporaries.insert(expr.self); force_recompile(); - } - for (auto &dependent : expr.expression_dependencies) - disallow_forwarding_in_expression_chain(get(dependent)); + for (auto &dependent : expr.expression_dependencies) + disallow_forwarding_in_expression_chain(get(dependent)); + } } void CompilerGLSL::handle_store_to_invariant_variable(uint32_t store_id, uint32_t value_id) @@ -7616,6 +8239,10 @@ uint32_t CompilerGLSL::get_integer_width_for_instruction(const Instruction &inst case OpSLessThanEqual: case OpSGreaterThan: case OpSGreaterThanEqual: + case OpULessThan: + case OpULessThanEqual: + case OpUGreaterThan: + case OpUGreaterThanEqual: return expression_type(ops[2]).width; default: @@ -7768,7 +8395,7 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) // it is an array, and our backend does not support arrays as value types. // Emit the temporary, and copy it explicitly. e = &emit_uninitialized_temporary_expression(result_type, id); - emit_array_copy(to_expression(id), ptr); + emit_array_copy(to_expression(id), ptr, StorageClassFunction, get_backing_variable_storage(ptr)); } else e = &emit_op(result_type, id, expr, forward, !usage_tracking); @@ -7817,7 +8444,7 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) auto &expr = set(ops[1], move(e), ops[0], should_forward(ops[2])); auto *backing_variable = maybe_get_backing_variable(ops[2]); - expr.loaded_from = backing_variable ? backing_variable->self : ops[2]; + expr.loaded_from = backing_variable ? backing_variable->self : ID(ops[2]); expr.need_transpose = meta.need_transpose; expr.access_chain = true; @@ -7946,13 +8573,13 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) if (skip_argument(arg[i])) continue; - arglist.push_back(to_func_call_arg(arg[i])); + arglist.push_back(to_func_call_arg(callee.arguments[i], arg[i])); } for (auto &combined : callee.combined_parameters) { - uint32_t image_id = combined.global_image ? combined.image_id : arg[combined.image_id]; - uint32_t sampler_id = combined.global_sampler ? combined.sampler_id : arg[combined.sampler_id]; + auto image_id = combined.global_image ? combined.image_id : VariableID(arg[combined.image_id]); + auto sampler_id = combined.global_sampler ? combined.sampler_id : VariableID(arg[combined.sampler_id]); arglist.push_back(to_combined_image_sampler(image_id, sampler_id)); } @@ -8057,22 +8684,32 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) string constructor_op; if (backend.use_initializer_list && composite) { + bool needs_trailing_tracket = false; // Only use this path if we are building composites. // This path cannot be used for arithmetic. if (backend.use_typed_initializer_list && out_type.basetype == SPIRType::Struct && out_type.array.empty()) constructor_op += type_to_glsl_constructor(get(result_type)); + else if (backend.use_typed_initializer_list && backend.array_is_value_type && !out_type.array.empty()) + { + // MSL path. Array constructor is baked into type here, do not use _constructor variant. + constructor_op += type_to_glsl_constructor(get(result_type)) + "("; + needs_trailing_tracket = true; + } constructor_op += "{ "; + if (type_is_empty(out_type) && !backend.supports_empty_struct) constructor_op += "0"; else if (splat) - constructor_op += to_expression(elems[0]); + constructor_op += to_unpacked_expression(elems[0]); else constructor_op += build_composite_combiner(result_type, elems, length); constructor_op += " }"; + if (needs_trailing_tracket) + constructor_op += ")"; } else if (swizzle_splat && !composite) { - constructor_op = remap_swizzle(get(result_type), 1, to_expression(elems[0])); + constructor_op = remap_swizzle(get(result_type), 1, to_unpacked_expression(elems[0])); } else { @@ -8080,7 +8717,7 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) if (type_is_empty(out_type) && !backend.supports_empty_struct) constructor_op += "0"; else if (splat) - constructor_op += to_expression(elems[0]); + constructor_op += to_unpacked_expression(elems[0]); else constructor_op += build_composite_combiner(result_type, elems, length); constructor_op += ")"; @@ -8145,6 +8782,11 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) if (has_extended_decoration(ops[2], SPIRVCrossDecorationPhysicalTypePacked)) allow_base_expression = false; + // Cannot use base expression for row-major matrix row-extraction since we need to interleave access pattern + // into the base expression. + if (is_non_native_row_major_matrix(ops[2])) + allow_base_expression = false; + AccessChainMeta meta; SPIRExpression *e = nullptr; @@ -8224,6 +8866,19 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) break; } + case OpCopyLogical: + { + // This is used for copying object of different types, arrays and structs. + // We need to unroll the copy, element-by-element. + uint32_t result_type = ops[0]; + uint32_t id = ops[1]; + uint32_t rhs = ops[2]; + + emit_uninitialized_temporary_expression(result_type, id); + emit_copy_logical_type(id, result_type, rhs, expression_type_id(rhs), {}); + break; + } + case OpCopyObject: { uint32_t result_type = ops[0]; @@ -8254,7 +8909,7 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) if (pointer) { auto *var = maybe_get_backing_variable(rhs); - e.loaded_from = var ? var->self : 0; + e.loaded_from = var ? var->self : ID(0); } // If we're copying an access chain, need to inherit the read expressions. @@ -8309,7 +8964,7 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) // a value we might not need, and bog down codegen. SPIRConstant c; c.constant_type = type0.parent_type; - assert(type0.parent_type != 0); + assert(type0.parent_type != ID(0)); args.push_back(constant_expression(c)); } else if (elems[i] >= type0.vecsize) @@ -8525,7 +9180,6 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) uint32_t result_id = ops[1]; uint32_t op0 = ops[2]; uint32_t op1 = ops[3]; - forced_temporaries.insert(result_id); auto &type = get(result_type); emit_uninitialized_temporary_expression(result_type, result_id); const char *op = opcode == OpUMulExtended ? "umulExtended" : "imulExtended"; @@ -8634,7 +9288,7 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) auto &type = get(result_type); if (type.vecsize > 1) - emit_unrolled_binary_op(result_type, id, ops[2], ops[3], "||"); + emit_unrolled_binary_op(result_type, id, ops[2], ops[3], "||", false, SPIRType::Unknown); else GLSL_BOP(||); break; @@ -8648,7 +9302,7 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) auto &type = get(result_type); if (type.vecsize > 1) - emit_unrolled_binary_op(result_type, id, ops[2], ops[3], "&&"); + emit_unrolled_binary_op(result_type, id, ops[2], ops[3], "&&", false, SPIRType::Unknown); else GLSL_BOP(&&); break; @@ -8705,7 +9359,7 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) case OpUGreaterThan: case OpSGreaterThan: { - auto type = opcode == OpUGreaterThan ? SPIRType::UInt : SPIRType::Int; + auto type = opcode == OpUGreaterThan ? uint_type : int_type; if (expression_type(ops[2]).vecsize > 1) GLSL_BFOP_CAST(greaterThan, type); else @@ -8725,7 +9379,7 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) case OpUGreaterThanEqual: case OpSGreaterThanEqual: { - auto type = opcode == OpUGreaterThanEqual ? SPIRType::UInt : SPIRType::Int; + auto type = opcode == OpUGreaterThanEqual ? uint_type : int_type; if (expression_type(ops[2]).vecsize > 1) GLSL_BFOP_CAST(greaterThanEqual, type); else @@ -8745,7 +9399,7 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) case OpULessThan: case OpSLessThan: { - auto type = opcode == OpULessThan ? SPIRType::UInt : SPIRType::Int; + auto type = opcode == OpULessThan ? uint_type : int_type; if (expression_type(ops[2]).vecsize > 1) GLSL_BFOP_CAST(lessThan, type); else @@ -8765,7 +9419,7 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) case OpULessThanEqual: case OpSLessThanEqual: { - auto type = opcode == OpULessThanEqual ? SPIRType::UInt : SPIRType::Int; + auto type = opcode == OpULessThanEqual ? uint_type : int_type; if (expression_type(ops[2]).vecsize > 1) GLSL_BFOP_CAST(lessThanEqual, type); else @@ -8796,9 +9450,7 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) auto &arg_type = expression_type(ops[2]); auto func = type_to_glsl_constructor(type); - // If we're sign-extending or zero-extending, we need to make sure we cast from the correct type. - // For truncation, it does not matter, so don't emit useless casts. - if (arg_type.width < type.width) + if (arg_type.width < type.width || type_is_floating_point(type)) emit_unary_func_op_cast(result_type, id, ops[2], func.c_str(), input_type, type.basetype); else emit_unary_func_op(result_type, id, ops[2], func.c_str()); @@ -8973,23 +9625,36 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) // Bitfield case OpBitFieldInsert: - // TODO: The signedness of inputs is strict in GLSL, but not in SPIR-V, bitcast if necessary. - GLSL_QFOP(bitfieldInsert); + { + emit_bitfield_insert_op(ops[0], ops[1], ops[2], ops[3], ops[4], ops[5], "bitfieldInsert", SPIRType::Int); break; + } case OpBitFieldSExtract: - case OpBitFieldUExtract: - // TODO: The signedness of inputs is strict in GLSL, but not in SPIR-V, bitcast if necessary. - GLSL_TFOP(bitfieldExtract); + { + emit_trinary_func_op_bitextract(ops[0], ops[1], ops[2], ops[3], ops[4], "bitfieldExtract", int_type, int_type, + SPIRType::Int, SPIRType::Int); break; + } + + case OpBitFieldUExtract: + { + emit_trinary_func_op_bitextract(ops[0], ops[1], ops[2], ops[3], ops[4], "bitfieldExtract", uint_type, uint_type, + SPIRType::Int, SPIRType::Int); + break; + } case OpBitReverse: + // BitReverse does not have issues with sign since result type must match input type. GLSL_UFOP(bitfieldReverse); break; case OpBitCount: - GLSL_UFOP(bitCount); + { + auto basetype = expression_type(ops[2]).basetype; + emit_unary_func_op_cast(ops[0], ops[1], ops[2], "bitCount", basetype, int_type); break; + } // Atomics case OpAtomicExchange: @@ -9145,12 +9810,32 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) break; case OpEmitStreamVertex: - statement("EmitStreamVertex();"); + { + if (options.es) + SPIRV_CROSS_THROW("Multi-stream geometry shaders not supported in ES."); + else if (!options.es && options.version < 400) + SPIRV_CROSS_THROW("Multi-stream geometry shaders only supported in GLSL 400."); + + auto stream_expr = to_expression(ops[0]); + if (expression_type(ops[0]).basetype != SPIRType::Int) + stream_expr = join("int(", stream_expr, ")"); + statement("EmitStreamVertex(", stream_expr, ");"); break; + } case OpEndStreamPrimitive: - statement("EndStreamPrimitive();"); + { + if (options.es) + SPIRV_CROSS_THROW("Multi-stream geometry shaders not supported in ES."); + else if (!options.es && options.version < 400) + SPIRV_CROSS_THROW("Multi-stream geometry shaders only supported in GLSL 400."); + + auto stream_expr = to_expression(ops[0]); + if (expression_type(ops[0]).basetype != SPIRType::Int) + stream_expr = join("int(", stream_expr, ")"); + statement("EndStreamPrimitive(", stream_expr, ");"); break; + } // Textures case OpImageSampleExplicitLod: @@ -9178,7 +9863,7 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) // When using the image, we need to know which variable it is actually loaded from. auto *var = maybe_get_backing_variable(ops[2]); - e.loaded_from = var ? var->self : 0; + e.loaded_from = var ? var->self : ID(0); break; } @@ -9397,11 +10082,18 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) { uint32_t result_type = ops[0]; uint32_t id = ops[1]; - auto &e = set(id, join(to_expression(ops[2]), ", ", to_expression(ops[3])), result_type, true); + + auto coord_expr = to_expression(ops[3]); + auto target_coord_type = expression_type(ops[3]); + target_coord_type.basetype = SPIRType::Int; + coord_expr = bitcast_expression(target_coord_type, expression_type(ops[3]).basetype, coord_expr); + + auto &e = set(id, join(to_expression(ops[2]), ", ", coord_expr), result_type, true); // When using the pointer, we need to know which variable it is actually loaded from. auto *var = maybe_get_backing_variable(ops[2]); - e.loaded_from = var ? var->self : 0; + e.loaded_from = var ? var->self : ID(0); + inherit_expression_dependencies(id, ops[3]); break; } @@ -9566,7 +10258,12 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) if (memory == ScopeWorkgroup) // Only need to consider memory within a group { if (semantics == MemorySemanticsWorkgroupMemoryMask) - statement("memoryBarrierShared();"); + { + // OpControlBarrier implies a memory barrier for shared memory as well. + bool implies_shared_barrier = opcode == OpControlBarrier && execution_scope == ScopeWorkgroup; + if (!implies_shared_barrier) + statement("memoryBarrierShared();"); + } else if (semantics != 0) statement("groupMemoryBarrier();"); } @@ -9599,8 +10296,8 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) } else { - const uint32_t all_barriers = MemorySemanticsWorkgroupMemoryMask | MemorySemanticsUniformMemoryMask | - MemorySemanticsImageMemoryMask | MemorySemanticsAtomicCounterMemoryMask; + const uint32_t all_barriers = + MemorySemanticsWorkgroupMemoryMask | MemorySemanticsUniformMemoryMask | MemorySemanticsImageMemoryMask; if (semantics & (MemorySemanticsCrossWorkgroupMemoryMask | MemorySemanticsSubgroupMemoryMask)) { @@ -9622,8 +10319,6 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) statement("memoryBarrierBuffer();"); if (semantics & MemorySemanticsImageMemoryMask) statement("memoryBarrierImage();"); - if (semantics & MemorySemanticsAtomicCounterMemoryMask) - statement("memoryBarrierAtomicCounter();"); } } @@ -9856,28 +10551,98 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) break; case OpFUnordEqual: - GLSL_BFOP(unsupported_FUnordEqual); - break; - case OpFUnordNotEqual: - GLSL_BFOP(unsupported_FUnordNotEqual); - break; - case OpFUnordLessThan: - GLSL_BFOP(unsupported_FUnordLessThan); - break; - case OpFUnordGreaterThan: - GLSL_BFOP(unsupported_FUnordGreaterThan); - break; - case OpFUnordLessThanEqual: - GLSL_BFOP(unsupported_FUnordLessThanEqual); - break; - case OpFUnordGreaterThanEqual: - GLSL_BFOP(unsupported_FUnordGreaterThanEqual); + { + // GLSL doesn't specify if floating point comparisons are ordered or unordered, + // but glslang always emits ordered floating point compares for GLSL. + // To get unordered compares, we can test the opposite thing and invert the result. + // This way, we force true when there is any NaN present. + uint32_t op0 = ops[2]; + uint32_t op1 = ops[3]; + + string expr; + if (expression_type(op0).vecsize > 1) + { + const char *comp_op = nullptr; + switch (opcode) + { + case OpFUnordEqual: + comp_op = "notEqual"; + break; + + case OpFUnordNotEqual: + comp_op = "equal"; + break; + + case OpFUnordLessThan: + comp_op = "greaterThanEqual"; + break; + + case OpFUnordLessThanEqual: + comp_op = "greaterThan"; + break; + + case OpFUnordGreaterThan: + comp_op = "lessThanEqual"; + break; + + case OpFUnordGreaterThanEqual: + comp_op = "lessThan"; + break; + + default: + assert(0); + break; + } + + expr = join("not(", comp_op, "(", to_unpacked_expression(op0), ", ", to_unpacked_expression(op1), "))"); + } + else + { + const char *comp_op = nullptr; + switch (opcode) + { + case OpFUnordEqual: + comp_op = " != "; + break; + + case OpFUnordNotEqual: + comp_op = " == "; + break; + + case OpFUnordLessThan: + comp_op = " >= "; + break; + + case OpFUnordLessThanEqual: + comp_op = " > "; + break; + + case OpFUnordGreaterThan: + comp_op = " <= "; + break; + + case OpFUnordGreaterThanEqual: + comp_op = " < "; + break; + + default: + assert(0); + break; + } + + expr = join("!(", to_enclosed_unpacked_expression(op0), comp_op, to_enclosed_unpacked_expression(op1), ")"); + } + + emit_op(ops[0], ops[1], expr, should_forward(op0) && should_forward(op1)); + inherit_expression_dependencies(ops[1], op0); + inherit_expression_dependencies(ops[1], op1); break; + } case OpReportIntersectionNV: statement("reportIntersectionNV(", to_expression(ops[0]), ", ", to_expression(ops[1]), ");"); @@ -9948,6 +10713,34 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) emit_op(ops[0], ops[1], "helperInvocationEXT()", false); break; + case OpBeginInvocationInterlockEXT: + // If the interlock is complex, we emit this elsewhere. + if (!interlocked_is_complex) + { + if (options.es) + statement("beginInvocationInterlockNV();"); + else + statement("beginInvocationInterlockARB();"); + + flush_all_active_variables(); + // Make sure forwarding doesn't propagate outside interlock region. + } + break; + + case OpEndInvocationInterlockEXT: + // If the interlock is complex, we emit this elsewhere. + if (!interlocked_is_complex) + { + if (options.es) + statement("endInvocationInterlockNV();"); + else + statement("endInvocationInterlockARB();"); + + flush_all_active_variables(); + // Make sure forwarding doesn't propagate outside interlock region. + } + break; + default: statement("// unimplemented op ", instruction.op); break; @@ -9977,12 +10770,18 @@ void CompilerGLSL::append_global_func_args(const SPIRFunction &func, uint32_t in if (var_id) flush_variable_declaration(var_id); - arglist.push_back(to_func_call_arg(arg.id)); + arglist.push_back(to_func_call_arg(arg, arg.id)); } } string CompilerGLSL::to_member_name(const SPIRType &type, uint32_t index) { + if (type.type_alias != TypeID(0) && + !has_extended_decoration(type.type_alias, SPIRVCrossDecorationBufferBlockRepacked)) + { + return to_member_name(get(type.type_alias), index); + } + auto &memb = ir.meta[type.self].members; if (index < memb.size() && !memb[index].alias.empty()) return memb[index].alias; @@ -10341,12 +11140,6 @@ string CompilerGLSL::to_array_size(const SPIRType &type, uint32_t index) { assert(type.array.size() == type.array_size_literal.size()); - // Tessellation control and evaluation shaders must have either gl_MaxPatchVertices or unsized arrays for input arrays. - // Opt for unsized as it's the more "correct" variant to use. - if (type.storage == StorageClassInput && (get_entry_point().model == ExecutionModelTessellationControl || - get_entry_point().model == ExecutionModelTessellationEvaluation)) - return ""; - auto &size = type.array[index]; if (!type.array_size_literal[index]) return to_expression(size); @@ -10513,7 +11306,7 @@ string CompilerGLSL::image_type_glsl(const SPIRType &type, uint32_t id) string CompilerGLSL::type_to_glsl_constructor(const SPIRType &type) { - if (type.array.size() > 1) + if (backend.use_array_constructor && type.array.size() > 1) { if (options.flatten_multidimensional_arrays) SPIRV_CROSS_THROW("Cannot flatten constructors of multidimensional array constructors, e.g. float[][]()."); @@ -10524,8 +11317,11 @@ string CompilerGLSL::type_to_glsl_constructor(const SPIRType &type) } auto e = type_to_glsl(type); - for (uint32_t i = 0; i < type.array.size(); i++) - e += "[]"; + if (backend.use_array_constructor) + { + for (uint32_t i = 0; i < type.array.size(); i++) + e += "[]"; + } return e; } @@ -10745,7 +11541,7 @@ void CompilerGLSL::require_extension_internal(const string &ext) } } -void CompilerGLSL::flatten_buffer_block(uint32_t id) +void CompilerGLSL::flatten_buffer_block(VariableID id) { auto &var = get(id); auto &type = get(var.basetype); @@ -10764,6 +11560,11 @@ void CompilerGLSL::flatten_buffer_block(uint32_t id) flattened_buffer_blocks.insert(id); } +bool CompilerGLSL::builtin_translates_to_nonarray(spv::BuiltIn /*builtin*/) const +{ + return false; // GLSL itself does not need to translate array builtin types to non-array builtin types +} + bool CompilerGLSL::check_atomic_image(uint32_t id) { auto &type = expression_type(id); @@ -10861,7 +11662,13 @@ void CompilerGLSL::emit_function_prototype(SPIRFunction &func, const Bitset &ret if (func.self == ir.default_entry_point) { - decl += "main"; + // If we need complex fallback in GLSL, we just wrap main() in a function + // and interlock the entire shader ... + if (interlocked_is_complex) + decl += "spvMainInterlockedBody"; + else + decl += "main"; + processing_entry_point = true; } else @@ -11060,16 +11867,7 @@ void CompilerGLSL::emit_fixup() } } -bool CompilerGLSL::flush_phi_required(uint32_t from, uint32_t to) -{ - auto &child = get(to); - for (auto &phi : child.phi_variables) - if (phi.parent == from) - return true; - return false; -} - -void CompilerGLSL::flush_phi(uint32_t from, uint32_t to) +void CompilerGLSL::flush_phi(BlockID from, BlockID to) { auto &child = get(to); if (child.ignore_phi_from_block == from) @@ -11098,7 +11896,7 @@ void CompilerGLSL::flush_phi(uint32_t from, uint32_t to) // This is judged to be extremely rare, so deal with it here using a simple, but suboptimal algorithm. bool need_saved_temporary = find_if(itr + 1, end(child.phi_variables), [&](const SPIRBlock::Phi &future_phi) -> bool { - return future_phi.local_variable == phi.function_variable && future_phi.parent == from; + return future_phi.local_variable == ID(phi.function_variable) && future_phi.parent == from; }) != end(child.phi_variables); if (need_saved_temporary) @@ -11133,7 +11931,7 @@ void CompilerGLSL::flush_phi(uint32_t from, uint32_t to) } } -void CompilerGLSL::branch_to_continue(uint32_t from, uint32_t to) +void CompilerGLSL::branch_to_continue(BlockID from, BlockID to) { auto &to_block = get(to); if (from == to) @@ -11163,23 +11961,23 @@ void CompilerGLSL::branch_to_continue(uint32_t from, uint32_t to) // so just use "self" here. loop_dominator = from; } - else if (from_block.loop_dominator != SPIRBlock::NoDominator) + else if (from_block.loop_dominator != BlockID(SPIRBlock::NoDominator)) { loop_dominator = from_block.loop_dominator; } if (loop_dominator != 0) { - auto &dominator = get(loop_dominator); + auto &cfg = get_cfg_for_current_function(); // For non-complex continue blocks, we implicitly branch to the continue block // by having the continue block be part of the loop header in for (; ; continue-block). - outside_control_flow = block_is_outside_flow_control_from_block(dominator, from_block); + outside_control_flow = cfg.node_terminates_control_flow_in_sub_graph(loop_dominator, from); } // Some simplification for for-loops. We always end up with a useless continue; // statement since we branch to a loop block. - // Walk the CFG, if we uncoditionally execute the block calling continue assuming we're in the loop block, + // Walk the CFG, if we unconditionally execute the block calling continue assuming we're in the loop block, // we can avoid writing out an explicit continue statement. // Similar optimization to return statements if we know we're outside flow control. if (!outside_control_flow) @@ -11187,11 +11985,13 @@ void CompilerGLSL::branch_to_continue(uint32_t from, uint32_t to) } } -void CompilerGLSL::branch(uint32_t from, uint32_t to) +void CompilerGLSL::branch(BlockID from, BlockID to) { flush_phi(from, to); flush_control_dependent_expressions(from); + bool to_is_continue = is_continue(to); + // This is only a continue if we branch to our loop dominator. if ((ir.block_meta[to] & ParsedIR::BLOCK_META_LOOP_HEADER_BIT) != 0 && get(from).loop_dominator == to) { @@ -11207,7 +12007,8 @@ void CompilerGLSL::branch(uint32_t from, uint32_t to) // Only sensible solution is to make a ladder variable, which we declare at the top of the switch block, // write to the ladder here, and defer the break. // The loop we're breaking out of must dominate the switch block, or there is no ladder breaking case. - if (current_emitting_switch && is_loop_break(to) && current_emitting_switch->loop_dominator != ~0u && + if (current_emitting_switch && is_loop_break(to) && + current_emitting_switch->loop_dominator != BlockID(SPIRBlock::NoDominator) && get(current_emitting_switch->loop_dominator).merge_block == to) { if (!current_emitting_switch->need_ladder_break) @@ -11220,12 +12021,25 @@ void CompilerGLSL::branch(uint32_t from, uint32_t to) } statement("break;"); } - else if (is_continue(to) || (from == to)) + else if (to_is_continue || from == to) { // For from == to case can happen for a do-while loop which branches into itself. // We don't mark these cases as continue blocks, but the only possible way to branch into // ourselves is through means of continue blocks. - branch_to_continue(from, to); + + // If we are merging to a continue block, there is no need to emit the block chain for continue here. + // We can branch to the continue block after we merge execution. + + // Here we make use of structured control flow rules from spec: + // 2.11: - the merge block declared by a header block cannot be a merge block declared by any other header block + // - each header block must strictly dominate its merge block, unless the merge block is unreachable in the CFG + // If we are branching to a merge block, we must be inside a construct which dominates the merge block. + auto &block_meta = ir.block_meta[to]; + bool branching_to_merge = + (block_meta & (ParsedIR::BLOCK_META_SELECTION_MERGE_BIT | ParsedIR::BLOCK_META_MULTISELECT_MERGE_BIT | + ParsedIR::BLOCK_META_LOOP_MERGE_BIT)) != 0; + if (!to_is_continue || !branching_to_merge) + branch_to_continue(from, to); } else if (!is_conditional(to)) emit_block_chain(get(to)); @@ -11236,12 +12050,19 @@ void CompilerGLSL::branch(uint32_t from, uint32_t to) // Inner scope always takes precedence. } -void CompilerGLSL::branch(uint32_t from, uint32_t cond, uint32_t true_block, uint32_t false_block) +void CompilerGLSL::branch(BlockID from, uint32_t cond, BlockID true_block, BlockID false_block) { - // If we branch directly to a selection merge target, we don't really need a code path. + auto &from_block = get(from); + BlockID merge_block = from_block.merge == SPIRBlock::MergeSelection ? from_block.next_block : BlockID(0); + + // If we branch directly to a selection merge target, we don't need a code path. + // This covers both merge out of if () / else () as well as a break for switch blocks. bool true_sub = !is_conditional(true_block); bool false_sub = !is_conditional(false_block); + bool true_block_is_selection_merge = true_block == merge_block; + bool false_block_is_selection_merge = false_block == merge_block; + if (true_sub) { emit_block_hints(get(from)); @@ -11250,7 +12071,11 @@ void CompilerGLSL::branch(uint32_t from, uint32_t cond, uint32_t true_block, uin branch(from, true_block); end_scope(); - if (false_sub || is_continue(false_block) || is_break(false_block)) + // If we merge to continue, we handle that explicitly in emit_block_chain(), + // so there is no need to branch to it directly here. + // break; is required to handle ladder fallthrough cases, so keep that in for now, even + // if we could potentially handle it in emit_block_chain(). + if (false_sub || (!false_block_is_selection_merge && is_continue(false_block)) || is_break(false_block)) { statement("else"); begin_scope(); @@ -11265,7 +12090,7 @@ void CompilerGLSL::branch(uint32_t from, uint32_t cond, uint32_t true_block, uin end_scope(); } } - else if (false_sub && !true_sub) + else if (false_sub) { // Only need false path, use negative conditional. emit_block_hints(get(from)); @@ -11274,7 +12099,7 @@ void CompilerGLSL::branch(uint32_t from, uint32_t cond, uint32_t true_block, uin branch(from, false_block); end_scope(); - if (is_continue(true_block) || is_break(true_block)) + if ((!true_block_is_selection_merge && is_continue(true_block)) || is_break(true_block)) { statement("else"); begin_scope(); @@ -11627,12 +12452,12 @@ void CompilerGLSL::flush_undeclared_variables(SPIRBlock &block) flush_variable_declaration(v); } -void CompilerGLSL::emit_hoisted_temporaries(SmallVector> &temporaries) +void CompilerGLSL::emit_hoisted_temporaries(SmallVector> &temporaries) { // If we need to force temporaries for certain IDs due to continue blocks, do it before starting loop header. // Need to sort these to ensure that reference output is stable. sort(begin(temporaries), end(temporaries), - [](const pair &a, const pair &b) { return a.second < b.second; }); + [](const pair &a, const pair &b) { return a.second < b.second; }); for (auto &tmp : temporaries) { @@ -11661,7 +12486,12 @@ void CompilerGLSL::emit_block_chain(SPIRBlock &block) SPIRBlock::ContinueBlockType continue_type = SPIRBlock::ContinueNone; if (block.continue_block) + { continue_type = continue_block_type(get(block.continue_block)); + // If we know we cannot emit a loop, mark the block early as a complex loop so we don't force unnecessary recompiles. + if (continue_type == SPIRBlock::ComplexLoop) + block.complex_continue = true; + } // If we have loop variables, stop masking out access to the variable now. for (auto var_id : block.loop_variables) @@ -12063,12 +12893,15 @@ void CompilerGLSL::emit_block_chain(SPIRBlock &block) } case SPIRBlock::Return: + { for (auto &line : current_function->fixup_hooks_out) line(); if (processing_entry_point) emit_fixup(); + auto &cfg = get_cfg_for_current_function(); + if (block.return_value) { auto &type = expression_type(block.return_value); @@ -12077,10 +12910,13 @@ void CompilerGLSL::emit_block_chain(SPIRBlock &block) // If we cannot return arrays, we will have a special out argument we can write to instead. // The backend is responsible for setting this up, and redirection the return values as appropriate. if (ir.ids[block.return_value].get_type() != TypeUndef) - emit_array_copy("SPIRV_Cross_return_value", block.return_value); + { + emit_array_copy("SPIRV_Cross_return_value", block.return_value, StorageClassFunction, + get_backing_variable_storage(block.return_value)); + } - if (!block_is_outside_flow_control_from_block(get(current_function->entry_block), block) || - block.loop_dominator != SPIRBlock::NoDominator) + if (!cfg.node_terminates_control_flow_in_sub_graph(current_function->entry_block, block.self) || + block.loop_dominator != BlockID(SPIRBlock::NoDominator)) { statement("return;"); } @@ -12092,16 +12928,17 @@ void CompilerGLSL::emit_block_chain(SPIRBlock &block) statement("return ", to_expression(block.return_value), ";"); } } - // If this block is the very final block and not called from control flow, - // we do not need an explicit return which looks out of place. Just end the function here. - // In the very weird case of for(;;) { return; } executing return is unconditional, - // but we actually need a return here ... - else if (!block_is_outside_flow_control_from_block(get(current_function->entry_block), block) || - block.loop_dominator != SPIRBlock::NoDominator) + else if (!cfg.node_terminates_control_flow_in_sub_graph(current_function->entry_block, block.self) || + block.loop_dominator != BlockID(SPIRBlock::NoDominator)) { + // If this block is the very final block and not called from control flow, + // we do not need an explicit return which looks out of place. Just end the function here. + // In the very weird case of for(;;) { return; } executing return is unconditional, + // but we actually need a return here ... statement("return;"); } break; + } case SPIRBlock::Kill: statement(backend.discard_literal, ";"); @@ -12139,7 +12976,7 @@ void CompilerGLSL::emit_block_chain(SPIRBlock &block) assert(block.merge == SPIRBlock::MergeSelection); branch_to_continue(block.self, block.next_block); } - else if (block.self != block.next_block) + else if (BlockID(block.self) != block.next_block) emit_block_chain(get(block.next_block)); } } @@ -12215,6 +13052,14 @@ void CompilerGLSL::end_scope() statement("}"); } +void CompilerGLSL::end_scope(const string &trailer) +{ + if (!indent) + SPIRV_CROSS_THROW("Popping empty indent stack."); + indent--; + statement("}", trailer); +} + void CompilerGLSL::end_scope_decl() { if (!indent) @@ -12271,7 +13116,7 @@ uint32_t CompilerGLSL::mask_relevant_memory_semantics(uint32_t semantics) MemorySemanticsCrossWorkgroupMemoryMask | MemorySemanticsSubgroupMemoryMask); } -void CompilerGLSL::emit_array_copy(const string &lhs, uint32_t rhs_id) +void CompilerGLSL::emit_array_copy(const string &lhs, uint32_t rhs_id, StorageClass, StorageClass) { statement(lhs, " = ", to_expression(rhs_id), ";"); } @@ -12296,25 +13141,26 @@ void CompilerGLSL::unroll_array_from_complex_load(uint32_t target_id, uint32_t s auto builtin = BuiltIn(get_decoration(var->self, DecorationBuiltIn)); bool is_builtin = is_builtin_variable(*var) && (builtin == BuiltInPointSize || builtin == BuiltInPosition); bool is_tess = is_tessellation_shader(); + bool is_patch = has_decoration(var->self, DecorationPatch); // Tessellation input arrays are special in that they are unsized, so we cannot directly copy from it. // We must unroll the array load. // For builtins, we couldn't catch this case normally, // because this is resolved in the OpAccessChain in most cases. // If we load the entire array, we have no choice but to unroll here. - if (is_builtin || is_tess) + if (!is_patch && (is_builtin || is_tess)) { auto new_expr = join("_", target_id, "_unrolled"); statement(variable_decl(type, new_expr, target_id), ";"); string array_expr; - if (type.array_size_literal.front()) + if (type.array_size_literal.back()) { - array_expr = convert_to_string(type.array.front()); - if (type.array.front() == 0) + array_expr = convert_to_string(type.array.back()); + if (type.array.back() == 0) SPIRV_CROSS_THROW("Cannot unroll an array copy from unsized array."); } else - array_expr = to_expression(type.array.front()); + array_expr = to_expression(type.array.back()); // The array size might be a specialization constant, so use a for-loop instead. statement("for (int i = 0; i < int(", array_expr, "); i++)"); @@ -12492,6 +13338,14 @@ void CompilerGLSL::fixup_type_alias() // This is not allowed, drop the type_alias. type.type_alias = 0; } + else if (type.type_alias && !type_is_block_like(this->get(type.type_alias))) + { + // If the alias master is not a block-like type, there is no reason to use type aliasing. + // This case can happen if two structs are declared with the same name, but they are unrelated. + // Aliases are only used to deal with aliased types for structs which are used in different buffer types + // which all create a variant of the same struct with different DecorationOffset values. + type.type_alias = 0; + } }); } @@ -12506,10 +13360,11 @@ void CompilerGLSL::reorder_type_alias() for (auto alias_itr = begin(type_ids); alias_itr != end(type_ids); ++alias_itr) { auto &type = get(*alias_itr); - if (type.type_alias != 0 && !has_extended_decoration(type.type_alias, SPIRVCrossDecorationBufferBlockRepacked)) + if (type.type_alias != TypeID(0) && + !has_extended_decoration(type.type_alias, SPIRVCrossDecorationBufferBlockRepacked)) { // We will skip declaring this type, so make sure the type_alias type comes before. - auto master_itr = find(begin(type_ids), end(type_ids), type.type_alias); + auto master_itr = find(begin(type_ids), end(type_ids), ID(type.type_alias)); assert(master_itr != end(type_ids)); if (alias_itr < master_itr) @@ -12575,3 +13430,81 @@ void CompilerGLSL::propagate_nonuniform_qualifier(uint32_t id) propagate_nonuniform_qualifier(expr); } } + +void CompilerGLSL::emit_copy_logical_type(uint32_t lhs_id, uint32_t lhs_type_id, uint32_t rhs_id, uint32_t rhs_type_id, + SmallVector chain) +{ + // Fully unroll all member/array indices one by one. + + auto &lhs_type = get(lhs_type_id); + auto &rhs_type = get(rhs_type_id); + + if (!lhs_type.array.empty()) + { + // Could use a loop here to support specialization constants, but it gets rather complicated with nested array types, + // and this is a rather obscure opcode anyways, keep it simple unless we are forced to. + uint32_t array_size = to_array_size_literal(lhs_type); + chain.push_back(0); + + for (uint32_t i = 0; i < array_size; i++) + { + chain.back() = i; + emit_copy_logical_type(lhs_id, lhs_type.parent_type, rhs_id, rhs_type.parent_type, chain); + } + } + else if (lhs_type.basetype == SPIRType::Struct) + { + chain.push_back(0); + uint32_t member_count = uint32_t(lhs_type.member_types.size()); + for (uint32_t i = 0; i < member_count; i++) + { + chain.back() = i; + emit_copy_logical_type(lhs_id, lhs_type.member_types[i], rhs_id, rhs_type.member_types[i], chain); + } + } + else + { + // Need to handle unpack/packing fixups since this can differ wildly between the logical types, + // particularly in MSL. + // To deal with this, we emit access chains and go through emit_store_statement + // to deal with all the special cases we can encounter. + + AccessChainMeta lhs_meta, rhs_meta; + auto lhs = access_chain_internal(lhs_id, chain.data(), uint32_t(chain.size()), + ACCESS_CHAIN_INDEX_IS_LITERAL_BIT, &lhs_meta); + auto rhs = access_chain_internal(rhs_id, chain.data(), uint32_t(chain.size()), + ACCESS_CHAIN_INDEX_IS_LITERAL_BIT, &rhs_meta); + + uint32_t id = ir.increase_bound_by(2); + lhs_id = id; + rhs_id = id + 1; + + { + auto &lhs_expr = set(lhs_id, move(lhs), lhs_type_id, true); + lhs_expr.need_transpose = lhs_meta.need_transpose; + + if (lhs_meta.storage_is_packed) + set_extended_decoration(lhs_id, SPIRVCrossDecorationPhysicalTypePacked); + if (lhs_meta.storage_physical_type != 0) + set_extended_decoration(lhs_id, SPIRVCrossDecorationPhysicalTypeID, lhs_meta.storage_physical_type); + + forwarded_temporaries.insert(lhs_id); + suppressed_usage_tracking.insert(lhs_id); + } + + { + auto &rhs_expr = set(rhs_id, move(rhs), rhs_type_id, true); + rhs_expr.need_transpose = rhs_meta.need_transpose; + + if (rhs_meta.storage_is_packed) + set_extended_decoration(rhs_id, SPIRVCrossDecorationPhysicalTypePacked); + if (rhs_meta.storage_physical_type != 0) + set_extended_decoration(rhs_id, SPIRVCrossDecorationPhysicalTypeID, rhs_meta.storage_physical_type); + + forwarded_temporaries.insert(rhs_id); + suppressed_usage_tracking.insert(rhs_id); + } + + emit_store_statement(lhs_id, rhs_id); + } +} diff --git a/third_party/spirv-cross/spirv_glsl.hpp b/third_party/spirv-cross/spirv_glsl.hpp index 3a4f485930..da00c05dfb 100644 --- a/third_party/spirv-cross/spirv_glsl.hpp +++ b/third_party/spirv-cross/spirv_glsl.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2015-2019 Arm Limited + * Copyright 2015-2020 Arm Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -56,7 +56,8 @@ enum AccessChainFlagBits ACCESS_CHAIN_INDEX_IS_LITERAL_BIT = 1 << 0, ACCESS_CHAIN_CHAIN_ONLY_BIT = 1 << 1, ACCESS_CHAIN_PTR_CHAIN_BIT = 1 << 2, - ACCESS_CHAIN_SKIP_REGISTER_EXPRESSION_READ_BIT = 1 << 3 + ACCESS_CHAIN_SKIP_REGISTER_EXPRESSION_READ_BIT = 1 << 3, + ACCESS_CHAIN_LITERAL_MSB_FORCE_ID = 1 << 4 }; typedef uint32_t AccessChainFlags; @@ -107,6 +108,13 @@ public: // May not correspond exactly to original source, but should be a good approximation. bool emit_line_directives = false; + // In cases where readonly/writeonly decoration are not used at all, + // we try to deduce which qualifier(s) we should actually used, since actually emitting + // read-write decoration is very rare, and older glslang/HLSL compilers tend to just emit readwrite as a matter of fact. + // The default (true) is to enable automatic deduction for these cases, but if you trust the decorations set + // by the SPIR-V, it's recommended to set this to false. + bool enable_storage_image_qualifier_deduction = true; + enum Precision { DontCare, @@ -209,7 +217,7 @@ public: // For this to work, all types in the block must be the same basic type, e.g. mixing vec2 and vec4 is fine, but // mixing int and float is not. // The name of the uniform array will be the same as the interface block name. - void flatten_buffer_block(uint32_t id); + void flatten_buffer_block(VariableID id); protected: void reset(); @@ -244,6 +252,8 @@ protected: virtual void emit_sampled_image_op(uint32_t result_type, uint32_t result_id, uint32_t image_id, uint32_t samp_id); virtual void emit_texture_op(const Instruction &i); + virtual std::string to_texture_op(const Instruction &i, bool *forward, + SmallVector &inherited_expressions); virtual void emit_subgroup_op(const Instruction &i); virtual std::string type_to_glsl(const SPIRType &type, uint32_t id = 0); virtual std::string builtin_to_glsl(spv::BuiltIn builtin, spv::StorageClass storage); @@ -256,11 +266,11 @@ protected: virtual std::string constant_expression_vector(const SPIRConstant &c, uint32_t vector); virtual void emit_fixup(); virtual std::string variable_decl(const SPIRType &type, const std::string &name, uint32_t id = 0); - virtual std::string to_func_call_arg(uint32_t id); - virtual std::string to_function_name(uint32_t img, const SPIRType &imgtype, bool is_fetch, bool is_gather, + virtual std::string to_func_call_arg(const SPIRFunction::Parameter &arg, uint32_t id); + virtual std::string to_function_name(VariableID img, const SPIRType &imgtype, bool is_fetch, bool is_gather, bool is_proj, bool has_array_offsets, bool has_offset, bool has_grad, bool has_dref, uint32_t lod, uint32_t minlod); - virtual std::string to_function_args(uint32_t img, const SPIRType &imgtype, bool is_fetch, bool is_gather, + virtual std::string to_function_args(VariableID img, const SPIRType &imgtype, bool is_fetch, bool is_gather, bool is_proj, uint32_t coord, uint32_t coord_components, uint32_t dref, uint32_t grad_x, uint32_t grad_y, uint32_t lod, uint32_t coffset, uint32_t offset, uint32_t bias, uint32_t comp, uint32_t sample, @@ -271,6 +281,11 @@ protected: virtual std::string unpack_expression_type(std::string expr_str, const SPIRType &type, uint32_t physical_type_id, bool packed_type, bool row_major); + virtual bool builtin_translates_to_nonarray(spv::BuiltIn builtin) const; + + void emit_copy_logical_type(uint32_t lhs_id, uint32_t lhs_type_id, uint32_t rhs_id, uint32_t rhs_type_id, + SmallVector chain); + StringStream<> buffer; template @@ -330,16 +345,18 @@ protected: void begin_scope(); void end_scope(); + void end_scope(const std::string &trailer); void end_scope_decl(); void end_scope_decl(const std::string &decl); Options options; - std::string type_to_array_glsl(const SPIRType &type); + virtual std::string type_to_array_glsl( + const SPIRType &type); // Allow Metal to use the array template to make arrays a value type std::string to_array_size(const SPIRType &type, uint32_t index); uint32_t to_array_size_literal(const SPIRType &type, uint32_t index) const; uint32_t to_array_size_literal(const SPIRType &type) const; - std::string variable_decl(const SPIRVariable &variable); + virtual std::string variable_decl(const SPIRVariable &variable); // Threadgroup arrays can't have a wrapper type std::string variable_decl_function_local(SPIRVariable &variable); void add_local_variable_name(uint32_t id); @@ -411,6 +428,7 @@ protected: bool native_pointers = false; bool support_small_type_sampling_result = false; bool support_case_fallthrough = true; + bool use_array_constructor = false; } backend; void emit_struct(SPIRType &type); @@ -420,23 +438,23 @@ protected: void emit_buffer_block_legacy(const SPIRVariable &var); void emit_buffer_block_flattened(const SPIRVariable &type); void emit_declared_builtin_block(spv::StorageClass storage, spv::ExecutionModel model); + bool should_force_emit_builtin_block(spv::StorageClass storage); void emit_push_constant_block_vulkan(const SPIRVariable &var); void emit_push_constant_block_glsl(const SPIRVariable &var); void emit_interface_block(const SPIRVariable &type); void emit_flattened_io_block(const SPIRVariable &var, const char *qual); void emit_block_chain(SPIRBlock &block); - void emit_hoisted_temporaries(SmallVector> &temporaries); + void emit_hoisted_temporaries(SmallVector> &temporaries); std::string constant_value_macro_name(uint32_t id); void emit_constant(const SPIRConstant &constant); void emit_specialization_constant_op(const SPIRConstantOp &constant); std::string emit_continue_block(uint32_t continue_block, bool follow_true_block, bool follow_false_block); bool attempt_emit_loop_header(SPIRBlock &block, SPIRBlock::Method method); - void branch(uint32_t from, uint32_t to); - void branch_to_continue(uint32_t from, uint32_t to); - void branch(uint32_t from, uint32_t cond, uint32_t true_block, uint32_t false_block); - void flush_phi(uint32_t from, uint32_t to); - bool flush_phi_required(uint32_t from, uint32_t to); + void branch(BlockID from, BlockID to); + void branch_to_continue(BlockID from, BlockID to); + void branch(BlockID from, uint32_t cond, BlockID true_block, BlockID false_block); + void flush_phi(BlockID from, BlockID to); void flush_variable_declaration(uint32_t id); void flush_undeclared_variables(SPIRBlock &block); void emit_variable_temporary_copies(const SPIRVariable &var); @@ -457,13 +475,22 @@ protected: SPIRType::BaseType input_type, SPIRType::BaseType expected_result_type); void emit_binary_func_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, const char *op, SPIRType::BaseType input_type, bool skip_cast_if_equal_type); + void emit_binary_func_op_cast_clustered(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, + const char *op, SPIRType::BaseType input_type); void emit_trinary_func_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, uint32_t op2, const char *op, SPIRType::BaseType input_type); + void emit_trinary_func_op_bitextract(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, + uint32_t op2, const char *op, SPIRType::BaseType expected_result_type, + SPIRType::BaseType input_type0, SPIRType::BaseType input_type1, + SPIRType::BaseType input_type2); + void emit_bitfield_insert_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, uint32_t op2, + uint32_t op3, const char *op, SPIRType::BaseType offset_count_type); void emit_unary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, const char *op); void emit_unrolled_unary_op(uint32_t result_type, uint32_t result_id, uint32_t operand, const char *op); void emit_binary_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, const char *op); - void emit_unrolled_binary_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, const char *op); + void emit_unrolled_binary_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, const char *op, + bool negate, SPIRType::BaseType expected_type); void emit_binary_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, const char *op, SPIRType::BaseType input_type, bool skip_cast_if_equal_type); @@ -479,6 +506,9 @@ protected: SPIRExpression &emit_op(uint32_t result_type, uint32_t result_id, const std::string &rhs, bool forward_rhs, bool suppress_usage_tracking = false); + void access_chain_internal_append_index(std::string &expr, uint32_t base, const SPIRType *type, + AccessChainFlags flags, bool &access_chain_is_arrayed, uint32_t index); + std::string access_chain_internal(uint32_t base, const uint32_t *indices, uint32_t count, AccessChainFlags flags, AccessChainMeta *meta); @@ -487,7 +517,7 @@ protected: std::string flattened_access_chain(uint32_t base, const uint32_t *indices, uint32_t count, const SPIRType &target_type, uint32_t offset, uint32_t matrix_stride, - bool need_transpose); + uint32_t array_stride, bool need_transpose); std::string flattened_access_chain_struct(uint32_t base, const uint32_t *indices, uint32_t count, const SPIRType &target_type, uint32_t offset); std::string flattened_access_chain_matrix(uint32_t base, const uint32_t *indices, uint32_t count, @@ -500,6 +530,7 @@ protected: uint32_t count, uint32_t offset, uint32_t word_stride, bool *need_transpose = nullptr, uint32_t *matrix_stride = nullptr, + uint32_t *array_stride = nullptr, bool ptr_chain = false); const char *index_to_swizzle(uint32_t index); @@ -535,13 +566,15 @@ protected: virtual std::string layout_for_member(const SPIRType &type, uint32_t index); virtual std::string to_interpolation_qualifiers(const Bitset &flags); std::string layout_for_variable(const SPIRVariable &variable); - std::string to_combined_image_sampler(uint32_t image_id, uint32_t samp_id); + std::string to_combined_image_sampler(VariableID image_id, VariableID samp_id); virtual bool skip_argument(uint32_t id) const; - virtual void emit_array_copy(const std::string &lhs, uint32_t rhs_id); + virtual void emit_array_copy(const std::string &lhs, uint32_t rhs_id, spv::StorageClass lhs_storage, + spv::StorageClass rhs_storage); virtual void emit_block_hints(const SPIRBlock &block); virtual std::string to_initializer_expression(const SPIRVariable &var); - bool buffer_is_packing_standard(const SPIRType &type, BufferPackingStandard packing, uint32_t start_offset = 0, + bool buffer_is_packing_standard(const SPIRType &type, BufferPackingStandard packing, + uint32_t *failed_index = nullptr, uint32_t start_offset = 0, uint32_t end_offset = ~(0u)); std::string buffer_to_packing_standard(const SPIRType &type, bool support_std430_without_scalar_layout); @@ -565,6 +598,7 @@ protected: bool check_atomic_image(uint32_t id); virtual void replace_illegal_names(); + void replace_illegal_names(const std::unordered_set &keywords); virtual void emit_entry_point_declarations(); void replace_fragment_output(SPIRVariable &var); @@ -576,6 +610,9 @@ protected: std::unordered_set emitted_functions; + // Ensure that we declare phi-variable copies even if the original declaration isn't deferred + std::unordered_set flushed_phi_variables; + std::unordered_set flattened_buffer_blocks; std::unordered_set flattened_structs; @@ -684,6 +721,8 @@ protected: void propagate_nonuniform_qualifier(uint32_t id); + static const char *vector_swizzle(int vecsize, int index); + private: void init(); }; diff --git a/third_party/spirv-cross/spirv_hlsl.cpp b/third_party/spirv-cross/spirv_hlsl.cpp index 0f1fac661a..f3e63b068b 100644 --- a/third_party/spirv-cross/spirv_hlsl.cpp +++ b/third_party/spirv-cross/spirv_hlsl.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2016-2019 Robert Konrad + * Copyright 2016-2020 Robert Konrad * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -203,7 +203,7 @@ static string image_format_to_type(ImageFormat fmt, SPIRType::BaseType basetype) } } -string CompilerHLSL::image_type_hlsl_modern(const SPIRType &type, uint32_t) +string CompilerHLSL::image_type_hlsl_modern(const SPIRType &type, uint32_t id) { auto &imagetype = get(type.image.type); const char *dim = nullptr; @@ -235,7 +235,12 @@ string CompilerHLSL::image_type_hlsl_modern(const SPIRType &type, uint32_t) if (type.image.sampled == 1) return join("Buffer<", type_to_glsl(imagetype), components, ">"); else if (type.image.sampled == 2) + { + if (interlocked_resources.count(id)) + return join("RasterizerOrderedBuffer<", image_format_to_type(type.image.format, imagetype.basetype), + ">"); return join("RWBuffer<", image_format_to_type(type.image.format, imagetype.basetype), ">"); + } else SPIRV_CROSS_THROW("Sampler buffers must be either sampled or unsampled. Cannot deduce in runtime."); case DimSubpassData: @@ -248,6 +253,8 @@ string CompilerHLSL::image_type_hlsl_modern(const SPIRType &type, uint32_t) const char *arrayed = type.image.arrayed ? "Array" : ""; const char *ms = type.image.ms ? "MS" : ""; const char *rw = typed_load ? "RW" : ""; + if (typed_load && interlocked_resources.count(id)) + rw = "RasterizerOrdered"; return join(rw, "Texture", dim, ms, arrayed, "<", typed_load ? image_format_to_type(type.image.format, imagetype.basetype) : join(type_to_glsl(imagetype), components), @@ -1038,7 +1045,7 @@ void CompilerHLSL::emit_specialization_constants_and_structs() { bool emitted = false; SpecializationConstant wg_x, wg_y, wg_z; - uint32_t workgroup_size_id = get_work_group_size_specialization_constants(wg_x, wg_y, wg_z); + ID workgroup_size_id = get_work_group_size_specialization_constants(wg_x, wg_y, wg_z); auto loop_lock = ir.create_loop_hard_lock(); for (auto &id_ : ir.ids_for_constant_or_type) @@ -1106,16 +1113,20 @@ void CompilerHLSL::replace_illegal_names() "line", "linear", "matrix", "point", "row_major", "sampler", }; - ir.for_each_typed_id([&](uint32_t, SPIRVariable &var) { - if (!is_hidden_variable(var)) - { - auto &m = ir.meta[var.self].decoration; - if (keywords.find(m.alias) != end(keywords)) - m.alias = join("_", m.alias); - } + CompilerGLSL::replace_illegal_names(keywords); + CompilerGLSL::replace_illegal_names(); +} + +void CompilerHLSL::declare_undefined_values() +{ + bool emitted = false; + ir.for_each_typed_id([&](uint32_t, const SPIRUndef &undef) { + statement("static ", variable_decl(this->get(undef.basetype), to_name(undef.self), undef.self), ";"); + emitted = true; }); - CompilerGLSL::replace_illegal_names(); + if (emitted) + statement(""); } void CompilerHLSL::emit_resources() @@ -1846,21 +1857,20 @@ void CompilerHLSL::emit_buffer_block(const SPIRVariable &var) if (is_uav) { Bitset flags = ir.get_buffer_block_flags(var); - bool is_readonly = flags.get(DecorationNonWritable); - bool is_coherent = flags.get(DecorationCoherent); + bool is_readonly = flags.get(DecorationNonWritable) && !hlsl_options.force_storage_buffer_as_uav; + bool is_coherent = flags.get(DecorationCoherent) && !is_readonly; + bool is_interlocked = interlocked_resources.count(var.self) > 0; + const char *type_name = "ByteAddressBuffer "; + if (!is_readonly) + type_name = is_interlocked ? "RasterizerOrderedByteAddressBuffer " : "RWByteAddressBuffer "; add_resource_name(var.self); - statement(is_coherent ? "globallycoherent " : "", is_readonly ? "ByteAddressBuffer " : "RWByteAddressBuffer ", - to_name(var.self), type_to_array_glsl(type), to_resource_binding(var), ";"); + statement(is_coherent ? "globallycoherent " : "", type_name, to_name(var.self), type_to_array_glsl(type), + to_resource_binding(var), ";"); } else { if (type.array.empty()) { - if (buffer_is_packing_standard(type, BufferPackingHLSLCbufferPackOffset)) - set_extended_decoration(type.self, SPIRVCrossDecorationExplicitOffset); - else - SPIRV_CROSS_THROW("cbuffer cannot be expressed with either HLSL packing layout or packoffset."); - // Flatten the top-level struct so we can use packoffset, // this restriction is similar to GLSL where layout(offset) is not possible on sub-structs. flattened_structs.insert(var.self); @@ -1881,6 +1891,16 @@ void CompilerHLSL::emit_buffer_block(const SPIRVariable &var) if (buffer_name.empty()) buffer_name = join("_", get(var.basetype).self, "_", var.self); + uint32_t failed_index = 0; + if (buffer_is_packing_standard(type, BufferPackingHLSLCbufferPackOffset, &failed_index)) + set_extended_decoration(type.self, SPIRVCrossDecorationExplicitOffset); + else + { + SPIRV_CROSS_THROW(join("cbuffer ID ", var.self, " (name: ", buffer_name, "), member index ", + failed_index, " (name: ", to_member_name(type, failed_index), + ") cannot be expressed with either HLSL packing layout or packoffset.")); + } + block_names.insert(buffer_name); // Save for post-reflection later. @@ -1916,13 +1936,18 @@ void CompilerHLSL::emit_buffer_block(const SPIRVariable &var) SPIRV_CROSS_THROW( "Need ConstantBuffer to use arrays of UBOs, but this is only supported in SM 5.1."); - // ConstantBuffer does not support packoffset, so it is unuseable unless everything aligns as we expect. - if (!buffer_is_packing_standard(type, BufferPackingHLSLCbuffer)) - SPIRV_CROSS_THROW("HLSL ConstantBuffer cannot be expressed with normal HLSL packing rules."); - add_resource_name(type.self); add_resource_name(var.self); + // ConstantBuffer does not support packoffset, so it is unuseable unless everything aligns as we expect. + uint32_t failed_index = 0; + if (!buffer_is_packing_standard(type, BufferPackingHLSLCbuffer, &failed_index)) + { + SPIRV_CROSS_THROW(join("HLSL ConstantBuffer ID ", var.self, " (name: ", to_name(type.self), + "), member index ", failed_index, " (name: ", to_member_name(type, failed_index), + ") cannot be expressed with normal HLSL packing rules.")); + } + emit_struct(get(type.self)); statement("ConstantBuffer<", to_name(type.self), "> ", to_name(var.self), type_to_array_glsl(type), to_resource_binding(var), ";"); @@ -1942,11 +1967,16 @@ void CompilerHLSL::emit_push_constant_block(const SPIRVariable &var) { auto &type = get(var.basetype); - if (buffer_is_packing_standard(type, BufferPackingHLSLCbufferPackOffset, layout.start, layout.end)) + uint32_t failed_index = 0; + if (buffer_is_packing_standard(type, BufferPackingHLSLCbufferPackOffset, &failed_index, layout.start, + layout.end)) set_extended_decoration(type.self, SPIRVCrossDecorationExplicitOffset); else - SPIRV_CROSS_THROW( - "root constant cbuffer cannot be expressed with either HLSL packing layout or packoffset."); + { + SPIRV_CROSS_THROW(join("Root constant cbuffer ID ", var.self, " (name: ", to_name(type.self), ")", + ", member index ", failed_index, " (name: ", to_member_name(type, failed_index), + ") cannot be expressed with either HLSL packing layout or packoffset.")); + } flattened_structs.insert(var.self); type.member_name_cache.clear(); @@ -1954,7 +1984,7 @@ void CompilerHLSL::emit_push_constant_block(const SPIRVariable &var) auto &memb = ir.meta[type.self].members; statement("cbuffer SPIRV_CROSS_RootConstant_", to_name(var.self), - to_resource_register('b', layout.binding, layout.space)); + to_resource_register(HLSL_BINDING_AUTO_PUSH_CONSTANT_BIT, 'b', layout.binding, layout.space)); begin_scope(); // Index of the next field in the generated root constant constant buffer @@ -2014,9 +2044,9 @@ void CompilerHLSL::emit_sampled_image_op(uint32_t result_type, uint32_t result_i } } -string CompilerHLSL::to_func_call_arg(uint32_t id) +string CompilerHLSL::to_func_call_arg(const SPIRFunction::Parameter &arg, uint32_t id) { - string arg_str = CompilerGLSL::to_func_call_arg(id); + string arg_str = CompilerGLSL::to_func_call_arg(arg, id); if (hlsl_options.shader_model <= 30) return arg_str; @@ -2478,7 +2508,7 @@ void CompilerHLSL::emit_texture_op(const Instruction &i) uint32_t result_type = ops[0]; uint32_t id = ops[1]; - uint32_t img = ops[2]; + VariableID img = ops[2]; uint32_t coord = ops[3]; uint32_t dref = 0; uint32_t comp = 0; @@ -2908,30 +2938,39 @@ void CompilerHLSL::emit_texture_op(const Instruction &i) string CompilerHLSL::to_resource_binding(const SPIRVariable &var) { - // TODO: Basic implementation, might need special consideration for RW/RO structured buffers, - // RW/RO images, and so on. + const auto &type = get(var.basetype); - if (!has_decoration(var.self, DecorationBinding)) + // We can remap push constant blocks, even if they don't have any binding decoration. + if (type.storage != StorageClassPushConstant && !has_decoration(var.self, DecorationBinding)) return ""; - const auto &type = get(var.basetype); char space = '\0'; + HLSLBindingFlagBits resource_flags = HLSL_BINDING_AUTO_NONE_BIT; + switch (type.basetype) { case SPIRType::SampledImage: space = 't'; // SRV + resource_flags = HLSL_BINDING_AUTO_SRV_BIT; break; case SPIRType::Image: if (type.image.sampled == 2 && type.image.dim != DimSubpassData) + { space = 'u'; // UAV + resource_flags = HLSL_BINDING_AUTO_UAV_BIT; + } else + { space = 't'; // SRV + resource_flags = HLSL_BINDING_AUTO_SRV_BIT; + } break; case SPIRType::Sampler: space = 's'; + resource_flags = HLSL_BINDING_AUTO_SAMPLER_BIT; break; case SPIRType::Struct: @@ -2942,20 +2981,28 @@ string CompilerHLSL::to_resource_binding(const SPIRVariable &var) if (has_decoration(type.self, DecorationBufferBlock)) { Bitset flags = ir.get_buffer_block_flags(var); - bool is_readonly = flags.get(DecorationNonWritable); + bool is_readonly = flags.get(DecorationNonWritable) && !hlsl_options.force_storage_buffer_as_uav; space = is_readonly ? 't' : 'u'; // UAV + resource_flags = is_readonly ? HLSL_BINDING_AUTO_SRV_BIT : HLSL_BINDING_AUTO_UAV_BIT; } else if (has_decoration(type.self, DecorationBlock)) + { space = 'b'; // Constant buffers + resource_flags = HLSL_BINDING_AUTO_CBV_BIT; + } } else if (storage == StorageClassPushConstant) + { space = 'b'; // Constant buffers + resource_flags = HLSL_BINDING_AUTO_PUSH_CONSTANT_BIT; + } else if (storage == StorageClassStorageBuffer) { // UAV or SRV depending on readonly flag. Bitset flags = ir.get_buffer_block_flags(var); - bool is_readonly = flags.get(DecorationNonWritable); + bool is_readonly = flags.get(DecorationNonWritable) && !hlsl_options.force_storage_buffer_as_uav; space = is_readonly ? 't' : 'u'; + resource_flags = is_readonly ? HLSL_BINDING_AUTO_SRV_BIT : HLSL_BINDING_AUTO_UAV_BIT; } break; @@ -2967,8 +3014,16 @@ string CompilerHLSL::to_resource_binding(const SPIRVariable &var) if (!space) return ""; - return to_resource_register(space, get_decoration(var.self, DecorationBinding), - get_decoration(var.self, DecorationDescriptorSet)); + uint32_t desc_set = + resource_flags == HLSL_BINDING_AUTO_PUSH_CONSTANT_BIT ? ResourceBindingPushConstantDescriptorSet : 0u; + uint32_t binding = resource_flags == HLSL_BINDING_AUTO_PUSH_CONSTANT_BIT ? ResourceBindingPushConstantBinding : 0u; + + if (has_decoration(var.self, DecorationBinding)) + binding = get_decoration(var.self, DecorationBinding); + if (has_decoration(var.self, DecorationDescriptorSet)) + desc_set = get_decoration(var.self, DecorationDescriptorSet); + + return to_resource_register(resource_flags, space, binding, desc_set); } string CompilerHLSL::to_resource_binding_sampler(const SPIRVariable &var) @@ -2977,16 +3032,65 @@ string CompilerHLSL::to_resource_binding_sampler(const SPIRVariable &var) if (!has_decoration(var.self, DecorationBinding)) return ""; - return to_resource_register('s', get_decoration(var.self, DecorationBinding), + return to_resource_register(HLSL_BINDING_AUTO_SAMPLER_BIT, 's', get_decoration(var.self, DecorationBinding), get_decoration(var.self, DecorationDescriptorSet)); } -string CompilerHLSL::to_resource_register(char space, uint32_t binding, uint32_t space_set) +void CompilerHLSL::remap_hlsl_resource_binding(HLSLBindingFlagBits type, uint32_t &desc_set, uint32_t &binding) { - if (hlsl_options.shader_model >= 51) - return join(" : register(", space, binding, ", space", space_set, ")"); + auto itr = resource_bindings.find({ get_execution_model(), desc_set, binding }); + if (itr != end(resource_bindings)) + { + auto &remap = itr->second; + remap.second = true; + + switch (type) + { + case HLSL_BINDING_AUTO_PUSH_CONSTANT_BIT: + case HLSL_BINDING_AUTO_CBV_BIT: + desc_set = remap.first.cbv.register_space; + binding = remap.first.cbv.register_binding; + break; + + case HLSL_BINDING_AUTO_SRV_BIT: + desc_set = remap.first.srv.register_space; + binding = remap.first.srv.register_binding; + break; + + case HLSL_BINDING_AUTO_SAMPLER_BIT: + desc_set = remap.first.sampler.register_space; + binding = remap.first.sampler.register_binding; + break; + + case HLSL_BINDING_AUTO_UAV_BIT: + desc_set = remap.first.uav.register_space; + binding = remap.first.uav.register_binding; + break; + + default: + break; + } + } +} + +string CompilerHLSL::to_resource_register(HLSLBindingFlagBits flag, char space, uint32_t binding, uint32_t space_set) +{ + if ((flag & resource_binding_flags) == 0) + { + remap_hlsl_resource_binding(flag, space_set, binding); + + // The push constant block did not have a binding, and there were no remap for it, + // so, declare without register binding. + if (flag == HLSL_BINDING_AUTO_PUSH_CONSTANT_BIT && space_set == ResourceBindingPushConstantDescriptorSet) + return ""; + + if (hlsl_options.shader_model >= 51) + return join(" : register(", space, binding, ", space", space_set, ")"); + else + return join(" : register(", space, binding, ")"); + } else - return join(" : register(", space, binding, ")"); + return ""; } void CompilerHLSL::emit_modern_uniform(const SPIRVariable &var) @@ -3352,7 +3456,57 @@ void CompilerHLSL::emit_glsl_op(uint32_t result_type, uint32_t id, uint32_t eop, } } -string CompilerHLSL::read_access_chain(const SPIRAccessChain &chain) +void CompilerHLSL::read_access_chain_array(const string &lhs, const SPIRAccessChain &chain) +{ + auto &type = get(chain.basetype); + + // Need to use a reserved identifier here since it might shadow an identifier in the access chain input or other loops. + auto ident = get_unique_identifier(); + + statement("[unroll]"); + statement("for (int ", ident, " = 0; ", ident, " < ", to_array_size(type, uint32_t(type.array.size() - 1)), "; ", + ident, "++)"); + begin_scope(); + auto subchain = chain; + subchain.dynamic_index = join(ident, " * ", chain.array_stride, " + ", chain.dynamic_index); + subchain.basetype = type.parent_type; + if (!get(subchain.basetype).array.empty()) + subchain.array_stride = get_decoration(subchain.basetype, DecorationArrayStride); + read_access_chain(nullptr, join(lhs, "[", ident, "]"), subchain); + end_scope(); +} + +void CompilerHLSL::read_access_chain_struct(const string &lhs, const SPIRAccessChain &chain) +{ + auto &type = get(chain.basetype); + auto subchain = chain; + uint32_t member_count = uint32_t(type.member_types.size()); + + for (uint32_t i = 0; i < member_count; i++) + { + uint32_t offset = type_struct_member_offset(type, i); + subchain.static_index = chain.static_index + offset; + subchain.basetype = type.member_types[i]; + + subchain.matrix_stride = 0; + subchain.array_stride = 0; + subchain.row_major_matrix = false; + + auto &member_type = get(subchain.basetype); + if (member_type.columns > 1) + { + subchain.matrix_stride = type_struct_member_matrix_stride(type, i); + subchain.row_major_matrix = has_member_decoration(type.self, i, DecorationRowMajor); + } + + if (!member_type.array.empty()) + subchain.array_stride = type_struct_member_array_stride(type, i); + + read_access_chain(nullptr, join(lhs, ".", to_member_name(type, i)), subchain); + } +} + +void CompilerHLSL::read_access_chain(string *expr, const string &lhs, const SPIRAccessChain &chain) { auto &type = get(chain.basetype); @@ -3361,14 +3515,18 @@ string CompilerHLSL::read_access_chain(const SPIRAccessChain &chain) target_type.vecsize = type.vecsize; target_type.columns = type.columns; - if (type.basetype == SPIRType::Struct) - SPIRV_CROSS_THROW("Reading structs from ByteAddressBuffer not yet supported."); - - if (type.width != 32) - SPIRV_CROSS_THROW("Reading types other than 32-bit from ByteAddressBuffer not yet supported."); - if (!type.array.empty()) - SPIRV_CROSS_THROW("Reading arrays from ByteAddressBuffer not yet supported."); + { + read_access_chain_array(lhs, chain); + return; + } + else if (type.basetype == SPIRType::Struct) + { + read_access_chain_struct(lhs, chain); + return; + } + else if (type.width != 32) + SPIRV_CROSS_THROW("Reading types other than 32-bit from ByteAddressBuffer not yet supported."); string load_expr; @@ -3476,7 +3634,13 @@ string CompilerHLSL::read_access_chain(const SPIRAccessChain &chain) if (!bitcast_op.empty()) load_expr = join(bitcast_op, "(", load_expr, ")"); - return load_expr; + if (lhs.empty()) + { + assert(expr); + *expr = move(load_expr); + } + else + statement(lhs, " = ", load_expr, ";"); } void CompilerHLSL::emit_load(const Instruction &instruction) @@ -3493,33 +3657,138 @@ void CompilerHLSL::emit_load(const Instruction &instruction) if (has_decoration(ptr, DecorationNonUniformEXT)) propagate_nonuniform_qualifier(ptr); - auto load_expr = read_access_chain(*chain); - - bool forward = should_forward(ptr) && forced_temporaries.find(id) == end(forced_temporaries); - - // If we are forwarding this load, - // don't register the read to access chain here, defer that to when we actually use the expression, - // using the add_implied_read_expression mechanism. - if (!forward) - track_expression_read(chain->self); - - // Do not forward complex load sequences like matrices, structs and arrays. auto &type = get(result_type); - if (type.columns > 1 || !type.array.empty() || type.basetype == SPIRType::Struct) - forward = false; + bool composite_load = !type.array.empty() || type.basetype == SPIRType::Struct; - auto &e = emit_op(result_type, id, load_expr, forward, true); - e.need_transpose = false; - register_read(id, ptr, forward); - inherit_expression_dependencies(id, ptr); - if (forward) - add_implied_read_expression(e, chain->self); + if (composite_load) + { + // We cannot make this work in one single expression as we might have nested structures and arrays, + // so unroll the load to an uninitialized temporary. + emit_uninitialized_temporary_expression(result_type, id); + read_access_chain(nullptr, to_expression(id), *chain); + track_expression_read(chain->self); + } + else + { + string load_expr; + read_access_chain(&load_expr, "", *chain); + + bool forward = should_forward(ptr) && forced_temporaries.find(id) == end(forced_temporaries); + + // If we are forwarding this load, + // don't register the read to access chain here, defer that to when we actually use the expression, + // using the add_implied_read_expression mechanism. + if (!forward) + track_expression_read(chain->self); + + // Do not forward complex load sequences like matrices, structs and arrays. + if (type.columns > 1) + forward = false; + + auto &e = emit_op(result_type, id, load_expr, forward, true); + e.need_transpose = false; + register_read(id, ptr, forward); + inherit_expression_dependencies(id, ptr); + if (forward) + add_implied_read_expression(e, chain->self); + } } else CompilerGLSL::emit_instruction(instruction); } -void CompilerHLSL::write_access_chain(const SPIRAccessChain &chain, uint32_t value) +void CompilerHLSL::write_access_chain_array(const SPIRAccessChain &chain, uint32_t value, + const SmallVector &composite_chain) +{ + auto &type = get(chain.basetype); + + // Need to use a reserved identifier here since it might shadow an identifier in the access chain input or other loops. + auto ident = get_unique_identifier(); + + uint32_t id = ir.increase_bound_by(2); + uint32_t int_type_id = id + 1; + SPIRType int_type; + int_type.basetype = SPIRType::Int; + int_type.width = 32; + set(int_type_id, int_type); + set(id, ident, int_type_id, true); + set_name(id, ident); + suppressed_usage_tracking.insert(id); + + statement("[unroll]"); + statement("for (int ", ident, " = 0; ", ident, " < ", to_array_size(type, uint32_t(type.array.size() - 1)), "; ", + ident, "++)"); + begin_scope(); + auto subchain = chain; + subchain.dynamic_index = join(ident, " * ", chain.array_stride, " + ", chain.dynamic_index); + subchain.basetype = type.parent_type; + + // Forcefully allow us to use an ID here by setting MSB. + auto subcomposite_chain = composite_chain; + subcomposite_chain.push_back(0x80000000u | id); + + if (!get(subchain.basetype).array.empty()) + subchain.array_stride = get_decoration(subchain.basetype, DecorationArrayStride); + + write_access_chain(subchain, value, subcomposite_chain); + end_scope(); +} + +void CompilerHLSL::write_access_chain_struct(const SPIRAccessChain &chain, uint32_t value, + const SmallVector &composite_chain) +{ + auto &type = get(chain.basetype); + uint32_t member_count = uint32_t(type.member_types.size()); + auto subchain = chain; + + auto subcomposite_chain = composite_chain; + subcomposite_chain.push_back(0); + + for (uint32_t i = 0; i < member_count; i++) + { + uint32_t offset = type_struct_member_offset(type, i); + subchain.static_index = chain.static_index + offset; + subchain.basetype = type.member_types[i]; + + subchain.matrix_stride = 0; + subchain.array_stride = 0; + subchain.row_major_matrix = false; + + auto &member_type = get(subchain.basetype); + if (member_type.columns > 1) + { + subchain.matrix_stride = type_struct_member_matrix_stride(type, i); + subchain.row_major_matrix = has_member_decoration(type.self, i, DecorationRowMajor); + } + + if (!member_type.array.empty()) + subchain.array_stride = type_struct_member_array_stride(type, i); + + subcomposite_chain.back() = i; + write_access_chain(subchain, value, subcomposite_chain); + } +} + +string CompilerHLSL::write_access_chain_value(uint32_t value, const SmallVector &composite_chain, + bool enclose) +{ + string ret; + if (composite_chain.empty()) + ret = to_expression(value); + else + { + AccessChainMeta meta; + ret = access_chain_internal(value, composite_chain.data(), uint32_t(composite_chain.size()), + ACCESS_CHAIN_INDEX_IS_LITERAL_BIT | ACCESS_CHAIN_LITERAL_MSB_FORCE_ID, &meta); + } + + if (enclose) + ret = enclose_expression(ret); + return ret; +} + +void CompilerHLSL::write_access_chain(const SPIRAccessChain &chain, uint32_t value, + const SmallVector &composite_chain) { auto &type = get(chain.basetype); @@ -3534,12 +3803,20 @@ void CompilerHLSL::write_access_chain(const SPIRAccessChain &chain, uint32_t val target_type.vecsize = type.vecsize; target_type.columns = type.columns; - if (type.basetype == SPIRType::Struct) - SPIRV_CROSS_THROW("Writing structs to RWByteAddressBuffer not yet supported."); - if (type.width != 32) - SPIRV_CROSS_THROW("Writing types other than 32-bit to RWByteAddressBuffer not yet supported."); if (!type.array.empty()) - SPIRV_CROSS_THROW("Reading arrays from ByteAddressBuffer not yet supported."); + { + write_access_chain_array(chain, value, composite_chain); + register_write(chain.self); + return; + } + else if (type.basetype == SPIRType::Struct) + { + write_access_chain_struct(chain, value, composite_chain); + register_write(chain.self); + return; + } + else if (type.width != 32) + SPIRV_CROSS_THROW("Writing types other than 32-bit to RWByteAddressBuffer not yet supported."); if (type.columns == 1 && !chain.row_major_matrix) { @@ -3562,7 +3839,7 @@ void CompilerHLSL::write_access_chain(const SPIRAccessChain &chain, uint32_t val SPIRV_CROSS_THROW("Unknown vector size."); } - auto store_expr = to_expression(value); + auto store_expr = write_access_chain_value(value, composite_chain, false); auto bitcast_op = bitcast_glsl_op(target_type, type); if (!bitcast_op.empty()) store_expr = join(bitcast_op, "(", store_expr, ")"); @@ -3573,7 +3850,7 @@ void CompilerHLSL::write_access_chain(const SPIRAccessChain &chain, uint32_t val // Strided store. for (uint32_t r = 0; r < type.vecsize; r++) { - auto store_expr = to_enclosed_expression(value); + auto store_expr = write_access_chain_value(value, composite_chain, true); if (type.vecsize > 1) { store_expr += "."; @@ -3611,7 +3888,7 @@ void CompilerHLSL::write_access_chain(const SPIRAccessChain &chain, uint32_t val for (uint32_t c = 0; c < type.columns; c++) { - auto store_expr = join(to_enclosed_expression(value), "[", c, "]"); + auto store_expr = join(write_access_chain_value(value, composite_chain, true), "[", c, "]"); auto bitcast_op = bitcast_glsl_op(target_type, type); if (!bitcast_op.empty()) store_expr = join(bitcast_op, "(", store_expr, ")"); @@ -3625,7 +3902,8 @@ void CompilerHLSL::write_access_chain(const SPIRAccessChain &chain, uint32_t val { for (uint32_t c = 0; c < type.columns; c++) { - auto store_expr = join(to_enclosed_expression(value), "[", c, "].", index_to_swizzle(r)); + auto store_expr = + join(write_access_chain_value(value, composite_chain, true), "[", c, "].", index_to_swizzle(r)); remove_duplicate_swizzle(store_expr); auto bitcast_op = bitcast_glsl_op(target_type, type); if (!bitcast_op.empty()) @@ -3644,7 +3922,7 @@ void CompilerHLSL::emit_store(const Instruction &instruction) auto ops = stream(instruction); auto *chain = maybe_get(ops[0]); if (chain) - write_access_chain(*chain, ops[1]); + write_access_chain(*chain, ops[1], {}); else CompilerGLSL::emit_instruction(instruction); } @@ -3674,7 +3952,10 @@ void CompilerHLSL::emit_access_chain(const Instruction &instruction) if (need_byte_access_chain) { - uint32_t to_plain_buffer_length = static_cast(type.array.size()); + // If we have a chain variable, we are already inside the SSBO, and any array type will refer to arrays within a block, + // and not array of SSBO. + uint32_t to_plain_buffer_length = chain ? 0u : static_cast(type.array.size()); + auto *backing_variable = maybe_get_backing_variable(ops[2]); string base; @@ -3696,6 +3977,7 @@ void CompilerHLSL::emit_access_chain(const Instruction &instruction) } uint32_t matrix_stride = 0; + uint32_t array_stride = 0; bool row_major_matrix = false; // Inherit matrix information. @@ -3703,17 +3985,19 @@ void CompilerHLSL::emit_access_chain(const Instruction &instruction) { matrix_stride = chain->matrix_stride; row_major_matrix = chain->row_major_matrix; + array_stride = chain->array_stride; } - auto offsets = - flattened_access_chain_offset(*basetype, &ops[3 + to_plain_buffer_length], - length - 3 - to_plain_buffer_length, 0, 1, &row_major_matrix, &matrix_stride); + auto offsets = flattened_access_chain_offset(*basetype, &ops[3 + to_plain_buffer_length], + length - 3 - to_plain_buffer_length, 0, 1, &row_major_matrix, + &matrix_stride, &array_stride); auto &e = set(ops[1], ops[0], type.storage, base, offsets.first, offsets.second); e.row_major_matrix = row_major_matrix; e.matrix_stride = matrix_stride; + e.array_stride = array_stride; e.immutable = should_forward(ops[2]); - e.loaded_from = backing_variable ? backing_variable->self : 0; + e.loaded_from = backing_variable ? backing_variable->self : ID(0); if (chain) { @@ -3850,6 +4134,11 @@ void CompilerHLSL::emit_subgroup_op(const Instruction &i) return join(expr, " * ", to_expression(ops[4])); }; + // If we need to do implicit bitcasts, make sure we do it with the correct type. + uint32_t integer_width = get_integer_width_for_instruction(i); + auto int_type = to_signed_basetype(integer_width); + auto uint_type = to_unsigned_basetype(integer_width); + #define make_inclusive_BitAnd(expr) "" #define make_inclusive_BitOr(expr) "" #define make_inclusive_BitXor(expr) "" @@ -3958,20 +4247,34 @@ case OpGroupNonUniform##op: \ SPIRV_CROSS_THROW("Invalid group operation."); \ break; \ } + +#define HLSL_GROUP_OP_CAST(op, hlsl_op, type) \ +case OpGroupNonUniform##op: \ + { \ + auto operation = static_cast(ops[3]); \ + if (operation == GroupOperationReduce) \ + emit_unary_func_op_cast(result_type, id, ops[4], "WaveActive" #hlsl_op, type, type); \ + else \ + SPIRV_CROSS_THROW("Invalid group operation."); \ + break; \ + } + HLSL_GROUP_OP(FAdd, Sum, true) HLSL_GROUP_OP(FMul, Product, true) HLSL_GROUP_OP(FMin, Min, false) HLSL_GROUP_OP(FMax, Max, false) HLSL_GROUP_OP(IAdd, Sum, true) HLSL_GROUP_OP(IMul, Product, true) - HLSL_GROUP_OP(SMin, Min, false) - HLSL_GROUP_OP(SMax, Max, false) - HLSL_GROUP_OP(UMin, Min, false) - HLSL_GROUP_OP(UMax, Max, false) + HLSL_GROUP_OP_CAST(SMin, Min, int_type) + HLSL_GROUP_OP_CAST(SMax, Max, int_type) + HLSL_GROUP_OP_CAST(UMin, Min, uint_type) + HLSL_GROUP_OP_CAST(UMax, Max, uint_type) HLSL_GROUP_OP(BitwiseAnd, BitAnd, false) HLSL_GROUP_OP(BitwiseOr, BitOr, false) HLSL_GROUP_OP(BitwiseXor, BitXor, false) + #undef HLSL_GROUP_OP +#undef HLSL_GROUP_OP_CAST // clang-format on case OpGroupNonUniformQuadSwap: @@ -4021,6 +4324,7 @@ void CompilerHLSL::emit_instruction(const Instruction &instruction) // If we need to do implicit bitcasts, make sure we do it with the correct type. uint32_t integer_width = get_integer_width_for_instruction(instruction); auto int_type = to_signed_basetype(integer_width); + auto uint_type = to_unsigned_basetype(integer_width); switch (opcode) { @@ -4183,7 +4487,7 @@ void CompilerHLSL::emit_instruction(const Instruction &instruction) auto id = ops[1]; if (expression_type(ops[2]).vecsize > 1) - emit_unrolled_binary_op(result_type, id, ops[2], ops[3], "=="); + emit_unrolled_binary_op(result_type, id, ops[2], ops[3], "==", false, SPIRType::Unknown); else HLSL_BOP_CAST(==, int_type); break; @@ -4191,12 +4495,19 @@ void CompilerHLSL::emit_instruction(const Instruction &instruction) case OpLogicalEqual: case OpFOrdEqual: + case OpFUnordEqual: { + // HLSL != operator is unordered. + // https://docs.microsoft.com/en-us/windows/win32/direct3d10/d3d10-graphics-programming-guide-resources-float-rules. + // isnan() is apparently implemented as x != x as well. + // We cannot implement UnordEqual as !(OrdNotEqual), as HLSL cannot express OrdNotEqual. + // HACK: FUnordEqual will be implemented as FOrdEqual. + auto result_type = ops[0]; auto id = ops[1]; if (expression_type(ops[2]).vecsize > 1) - emit_unrolled_binary_op(result_type, id, ops[2], ops[3], "=="); + emit_unrolled_binary_op(result_type, id, ops[2], ops[3], "==", false, SPIRType::Unknown); else HLSL_BOP(==); break; @@ -4208,7 +4519,7 @@ void CompilerHLSL::emit_instruction(const Instruction &instruction) auto id = ops[1]; if (expression_type(ops[2]).vecsize > 1) - emit_unrolled_binary_op(result_type, id, ops[2], ops[3], "!="); + emit_unrolled_binary_op(result_type, id, ops[2], ops[3], "!=", false, SPIRType::Unknown); else HLSL_BOP_CAST(!=, int_type); break; @@ -4216,12 +4527,23 @@ void CompilerHLSL::emit_instruction(const Instruction &instruction) case OpLogicalNotEqual: case OpFOrdNotEqual: + case OpFUnordNotEqual: { + // HLSL != operator is unordered. + // https://docs.microsoft.com/en-us/windows/win32/direct3d10/d3d10-graphics-programming-guide-resources-float-rules. + // isnan() is apparently implemented as x != x as well. + + // FIXME: FOrdNotEqual cannot be implemented in a crisp and simple way here. + // We would need to do something like not(UnordEqual), but that cannot be expressed either. + // Adding a lot of NaN checks would be a breaking change from perspective of performance. + // SPIR-V will generally use isnan() checks when this even matters. + // HACK: FOrdNotEqual will be implemented as FUnordEqual. + auto result_type = ops[0]; auto id = ops[1]; if (expression_type(ops[2]).vecsize > 1) - emit_unrolled_binary_op(result_type, id, ops[2], ops[3], "!="); + emit_unrolled_binary_op(result_type, id, ops[2], ops[3], "!=", false, SPIRType::Unknown); else HLSL_BOP(!=); break; @@ -4232,10 +4554,10 @@ void CompilerHLSL::emit_instruction(const Instruction &instruction) { auto result_type = ops[0]; auto id = ops[1]; - auto type = opcode == OpUGreaterThan ? SPIRType::UInt : SPIRType::Int; + auto type = opcode == OpUGreaterThan ? uint_type : int_type; if (expression_type(ops[2]).vecsize > 1) - emit_unrolled_binary_op(result_type, id, ops[2], ops[3], ">"); + emit_unrolled_binary_op(result_type, id, ops[2], ops[3], ">", false, type); else HLSL_BOP_CAST(>, type); break; @@ -4247,21 +4569,33 @@ void CompilerHLSL::emit_instruction(const Instruction &instruction) auto id = ops[1]; if (expression_type(ops[2]).vecsize > 1) - emit_unrolled_binary_op(result_type, id, ops[2], ops[3], ">"); + emit_unrolled_binary_op(result_type, id, ops[2], ops[3], ">", false, SPIRType::Unknown); else HLSL_BOP(>); break; } + case OpFUnordGreaterThan: + { + auto result_type = ops[0]; + auto id = ops[1]; + + if (expression_type(ops[2]).vecsize > 1) + emit_unrolled_binary_op(result_type, id, ops[2], ops[3], "<=", true, SPIRType::Unknown); + else + CompilerGLSL::emit_instruction(instruction); + break; + } + case OpUGreaterThanEqual: case OpSGreaterThanEqual: { auto result_type = ops[0]; auto id = ops[1]; - auto type = opcode == OpUGreaterThanEqual ? SPIRType::UInt : SPIRType::Int; + auto type = opcode == OpUGreaterThanEqual ? uint_type : int_type; if (expression_type(ops[2]).vecsize > 1) - emit_unrolled_binary_op(result_type, id, ops[2], ops[3], ">="); + emit_unrolled_binary_op(result_type, id, ops[2], ops[3], ">=", false, type); else HLSL_BOP_CAST(>=, type); break; @@ -4273,21 +4607,33 @@ void CompilerHLSL::emit_instruction(const Instruction &instruction) auto id = ops[1]; if (expression_type(ops[2]).vecsize > 1) - emit_unrolled_binary_op(result_type, id, ops[2], ops[3], ">="); + emit_unrolled_binary_op(result_type, id, ops[2], ops[3], ">=", false, SPIRType::Unknown); else HLSL_BOP(>=); break; } + case OpFUnordGreaterThanEqual: + { + auto result_type = ops[0]; + auto id = ops[1]; + + if (expression_type(ops[2]).vecsize > 1) + emit_unrolled_binary_op(result_type, id, ops[2], ops[3], "<", true, SPIRType::Unknown); + else + CompilerGLSL::emit_instruction(instruction); + break; + } + case OpULessThan: case OpSLessThan: { auto result_type = ops[0]; auto id = ops[1]; - auto type = opcode == OpULessThan ? SPIRType::UInt : SPIRType::Int; + auto type = opcode == OpULessThan ? uint_type : int_type; if (expression_type(ops[2]).vecsize > 1) - emit_unrolled_binary_op(result_type, id, ops[2], ops[3], "<"); + emit_unrolled_binary_op(result_type, id, ops[2], ops[3], "<", false, type); else HLSL_BOP_CAST(<, type); break; @@ -4299,21 +4645,33 @@ void CompilerHLSL::emit_instruction(const Instruction &instruction) auto id = ops[1]; if (expression_type(ops[2]).vecsize > 1) - emit_unrolled_binary_op(result_type, id, ops[2], ops[3], "<"); + emit_unrolled_binary_op(result_type, id, ops[2], ops[3], "<", false, SPIRType::Unknown); else HLSL_BOP(<); break; } + case OpFUnordLessThan: + { + auto result_type = ops[0]; + auto id = ops[1]; + + if (expression_type(ops[2]).vecsize > 1) + emit_unrolled_binary_op(result_type, id, ops[2], ops[3], ">=", true, SPIRType::Unknown); + else + CompilerGLSL::emit_instruction(instruction); + break; + } + case OpULessThanEqual: case OpSLessThanEqual: { auto result_type = ops[0]; auto id = ops[1]; - auto type = opcode == OpULessThanEqual ? SPIRType::UInt : SPIRType::Int; + auto type = opcode == OpULessThanEqual ? uint_type : int_type; if (expression_type(ops[2]).vecsize > 1) - emit_unrolled_binary_op(result_type, id, ops[2], ops[3], "<="); + emit_unrolled_binary_op(result_type, id, ops[2], ops[3], "<=", false, type); else HLSL_BOP_CAST(<=, type); break; @@ -4325,12 +4683,24 @@ void CompilerHLSL::emit_instruction(const Instruction &instruction) auto id = ops[1]; if (expression_type(ops[2]).vecsize > 1) - emit_unrolled_binary_op(result_type, id, ops[2], ops[3], "<="); + emit_unrolled_binary_op(result_type, id, ops[2], ops[3], "<=", false, SPIRType::Unknown); else HLSL_BOP(<=); break; } + case OpFUnordLessThanEqual: + { + auto result_type = ops[0]; + auto id = ops[1]; + + if (expression_type(ops[2]).vecsize > 1) + emit_unrolled_binary_op(result_type, id, ops[2], ops[3], ">", true, SPIRType::Unknown); + else + CompilerGLSL::emit_instruction(instruction); + break; + } + case OpImageQueryLod: emit_texture_op(instruction); break; @@ -4483,7 +4853,8 @@ void CompilerHLSL::emit_instruction(const Instruction &instruction) // When using the pointer, we need to know which variable it is actually loaded from. auto *var = maybe_get_backing_variable(ops[2]); - e.loaded_from = var ? var->self : 0; + e.loaded_from = var ? var->self : ID(0); + inherit_expression_dependencies(id, ops[3]); break; } @@ -4641,8 +5012,11 @@ void CompilerHLSL::emit_instruction(const Instruction &instruction) } case OpBitCount: - HLSL_UFOP(countbits); + { + auto basetype = expression_type(ops[2]).basetype; + emit_unary_func_op_cast(ops[0], ops[1], ops[2], "countbits", basetype, basetype); break; + } case OpBitReverse: HLSL_UFOP(reversebits); @@ -4670,6 +5044,12 @@ void CompilerHLSL::emit_instruction(const Instruction &instruction) case OpIsHelperInvocationEXT: SPIRV_CROSS_THROW("helperInvocationEXT() is not supported in HLSL."); + case OpBeginInvocationInterlockEXT: + case OpEndInvocationInterlockEXT: + if (hlsl_options.shader_model < 51) + SPIRV_CROSS_THROW("Rasterizer order views require Shader Model 5.1."); + break; // Nothing to do in the body + default: CompilerGLSL::emit_instruction(instruction); break; @@ -4744,7 +5124,7 @@ void CompilerHLSL::add_vertex_attribute_remap(const HLSLVertexAttributeRemap &ve remap_vertex_attributes.push_back(vertex_attributes); } -uint32_t CompilerHLSL::remap_num_workgroups_builtin() +VariableID CompilerHLSL::remap_num_workgroups_builtin() { update_active_builtins(); @@ -4790,6 +5170,11 @@ uint32_t CompilerHLSL::remap_num_workgroups_builtin() return variable_id; } +void CompilerHLSL::set_resource_binding_flags(HLSLBindingFlags flags) +{ + resource_binding_flags = flags; +} + void CompilerHLSL::validate_shader_model() { // Check for nonuniform qualifier. @@ -4847,6 +5232,7 @@ string CompilerHLSL::compile() validate_shader_model(); update_active_builtins(); analyze_image_and_sampler_usage(); + analyze_interlocked_resource_usage(); // Subpass input needs SV_Position. if (need_subpass_input) @@ -4898,3 +5284,21 @@ void CompilerHLSL::emit_block_hints(const SPIRBlock &block) break; } } + +string CompilerHLSL::get_unique_identifier() +{ + return join("_", unique_identifier_count++, "ident"); +} + +void CompilerHLSL::add_hlsl_resource_binding(const HLSLResourceBinding &binding) +{ + StageSetBinding tuple = { binding.stage, binding.desc_set, binding.binding }; + resource_bindings[tuple] = { binding, false }; +} + +bool CompilerHLSL::is_hlsl_resource_binding_used(ExecutionModel model, uint32_t desc_set, uint32_t binding) const +{ + StageSetBinding tuple = { model, desc_set, binding }; + auto itr = resource_bindings.find(tuple); + return itr != end(resource_bindings) && itr->second.second; +} diff --git a/third_party/spirv-cross/spirv_hlsl.hpp b/third_party/spirv-cross/spirv_hlsl.hpp index 6f10141459..29b38e628f 100644 --- a/third_party/spirv-cross/spirv_hlsl.hpp +++ b/third_party/spirv-cross/spirv_hlsl.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2016-2019 Robert Konrad + * Copyright 2016-2020 Robert Konrad * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -41,6 +41,56 @@ struct RootConstants uint32_t space; }; +// For finer control, decorations may be removed from specific resources instead with unset_decoration(). +enum HLSLBindingFlagBits +{ + HLSL_BINDING_AUTO_NONE_BIT = 0, + + // Push constant (root constant) resources will be declared as CBVs (b-space) without a register() declaration. + // A register will be automatically assigned by the D3D compiler, but must therefore be reflected in D3D-land. + // Push constants do not normally have a DecorationBinding set, but if they do, this can be used to ignore it. + HLSL_BINDING_AUTO_PUSH_CONSTANT_BIT = 1 << 0, + + // cbuffer resources will be declared as CBVs (b-space) without a register() declaration. + // A register will be automatically assigned, but must be reflected in D3D-land. + HLSL_BINDING_AUTO_CBV_BIT = 1 << 1, + + // All SRVs (t-space) will be declared without a register() declaration. + HLSL_BINDING_AUTO_SRV_BIT = 1 << 2, + + // All UAVs (u-space) will be declared without a register() declaration. + HLSL_BINDING_AUTO_UAV_BIT = 1 << 3, + + // All samplers (s-space) will be declared without a register() declaration. + HLSL_BINDING_AUTO_SAMPLER_BIT = 1 << 4, + + // No resources will be declared with register(). + HLSL_BINDING_AUTO_ALL = 0x7fffffff +}; +using HLSLBindingFlags = uint32_t; + +// By matching stage, desc_set and binding for a SPIR-V resource, +// register bindings are set based on whether the HLSL resource is a +// CBV, UAV, SRV or Sampler. A single binding in SPIR-V might contain multiple +// resource types, e.g. COMBINED_IMAGE_SAMPLER, and SRV/Sampler bindings will be used respectively. +// On SM 5.0 and lower, register_space is ignored. +// +// To remap a push constant block which does not have any desc_set/binding associated with it, +// use ResourceBindingPushConstant{DescriptorSet,Binding} as values for desc_set/binding. +// For deeper control of push constants, set_root_constant_layouts() can be used instead. +struct HLSLResourceBinding +{ + spv::ExecutionModel stage = spv::ExecutionModelMax; + uint32_t desc_set = 0; + uint32_t binding = 0; + + struct Binding + { + uint32_t register_space = 0; + uint32_t register_binding = 0; + } cbv, uav, srv, sampler; +}; + class CompilerHLSL : public CompilerGLSL { public: @@ -59,6 +109,10 @@ public: // Set to false if you know you will never use base instance or base vertex // functionality as it might remove an internal cbuffer. bool support_nonzero_base_vertex_base_instance = false; + + // Forces a storage buffer to always be declared as UAV, even if the readonly decoration is used. + // By default, a readonly storage buffer will be declared as ByteAddressBuffer (SRV) instead. + bool force_storage_buffer_as_uav = false; }; explicit CompilerHLSL(std::vector spirv_) @@ -114,7 +168,18 @@ public: // If non-zero, this returns the variable ID of a cbuffer which corresponds to // the cbuffer declared above. By default, no binding or descriptor set decoration is set, // so the calling application should declare explicit bindings on this ID before calling compile(). - uint32_t remap_num_workgroups_builtin(); + VariableID remap_num_workgroups_builtin(); + + // Controls how resource bindings are declared in the output HLSL. + void set_resource_binding_flags(HLSLBindingFlags flags); + + // resource is a resource binding to indicate the HLSL CBV, SRV, UAV or sampler binding + // to use for a particular SPIR-V description set + // and binding. If resource bindings are provided, + // is_hlsl_resource_binding_used() will return true after calling ::compile() if + // the set/binding combination was used by the HLSL code. + void add_hlsl_resource_binding(const HLSLResourceBinding &resource); + bool is_hlsl_resource_binding_used(spv::ExecutionModel model, uint32_t set, uint32_t binding) const; private: std::string type_to_glsl(const SPIRType &type, uint32_t id = 0) override; @@ -125,6 +190,7 @@ private: void emit_hlsl_entry_point(); void emit_header() override; void emit_resources(); + void declare_undefined_values() override; void emit_interface_block_globally(const SPIRVariable &type); void emit_interface_block_in_struct(const SPIRVariable &type, std::unordered_set &active_locations); void emit_builtin_inputs_in_struct(); @@ -145,16 +211,23 @@ private: std::string layout_for_member(const SPIRType &type, uint32_t index) override; std::string to_interpolation_qualifiers(const Bitset &flags) override; std::string bitcast_glsl_op(const SPIRType &result_type, const SPIRType &argument_type) override; - std::string to_func_call_arg(uint32_t id) override; + std::string to_func_call_arg(const SPIRFunction::Parameter &arg, uint32_t id) override; std::string to_sampler_expression(uint32_t id); std::string to_resource_binding(const SPIRVariable &var); std::string to_resource_binding_sampler(const SPIRVariable &var); - std::string to_resource_register(char space, uint32_t binding, uint32_t set); + std::string to_resource_register(HLSLBindingFlagBits flag, char space, uint32_t binding, uint32_t set); void emit_sampled_image_op(uint32_t result_type, uint32_t result_id, uint32_t image_id, uint32_t samp_id) override; void emit_access_chain(const Instruction &instruction); void emit_load(const Instruction &instruction); - std::string read_access_chain(const SPIRAccessChain &chain); - void write_access_chain(const SPIRAccessChain &chain, uint32_t value); + void read_access_chain(std::string *expr, const std::string &lhs, const SPIRAccessChain &chain); + void read_access_chain_struct(const std::string &lhs, const SPIRAccessChain &chain); + void read_access_chain_array(const std::string &lhs, const SPIRAccessChain &chain); + void write_access_chain(const SPIRAccessChain &chain, uint32_t value, const SmallVector &composite_chain); + void write_access_chain_struct(const SPIRAccessChain &chain, uint32_t value, + const SmallVector &composite_chain); + void write_access_chain_array(const SPIRAccessChain &chain, uint32_t value, + const SmallVector &composite_chain); + std::string write_access_chain_value(uint32_t value, const SmallVector &composite_chain, bool enclose); void emit_store(const Instruction &instruction); void emit_atomic(const uint32_t *ops, uint32_t length, spv::Op op); void emit_subgroup_op(const Instruction &i) override; @@ -221,12 +294,19 @@ private: std::string to_semantic(uint32_t location, spv::ExecutionModel em, spv::StorageClass sc); uint32_t num_workgroups_builtin = 0; + HLSLBindingFlags resource_binding_flags = 0; // Custom root constant layout, which should be emitted // when translating push constant ranges. std::vector root_constants_layout; void validate_shader_model(); + + std::string get_unique_identifier(); + uint32_t unique_identifier_count = 0; + + std::unordered_map, InternalHasher> resource_bindings; + void remap_hlsl_resource_binding(HLSLBindingFlagBits type, uint32_t &desc_set, uint32_t &binding); }; } // namespace SPIRV_CROSS_NAMESPACE diff --git a/third_party/spirv-cross/spirv_msl.cpp b/third_party/spirv-cross/spirv_msl.cpp index 9f33034ff2..515cb06e4d 100644 --- a/third_party/spirv-cross/spirv_msl.cpp +++ b/third_party/spirv-cross/spirv_msl.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2016-2019 The Brenwill Workshop Ltd. + * Copyright 2016-2020 The Brenwill Workshop Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,6 +27,7 @@ using namespace std; static const uint32_t k_unknown_location = ~0u; static const uint32_t k_unknown_component = ~0u; +static const char *force_inline = "static inline __attribute__((always_inline))"; CompilerMSL::CompilerMSL(std::vector spirv_) : CompilerGLSL(move(spirv_)) @@ -61,18 +62,41 @@ void CompilerMSL::add_msl_resource_binding(const MSLResourceBinding &binding) resource_bindings[tuple] = { binding, false }; } +void CompilerMSL::add_dynamic_buffer(uint32_t desc_set, uint32_t binding, uint32_t index) +{ + SetBindingPair pair = { desc_set, binding }; + buffers_requiring_dynamic_offset[pair] = { index, 0 }; +} + +void CompilerMSL::add_inline_uniform_block(uint32_t desc_set, uint32_t binding) +{ + SetBindingPair pair = { desc_set, binding }; + inline_uniform_blocks.insert(pair); +} + void CompilerMSL::add_discrete_descriptor_set(uint32_t desc_set) { if (desc_set < kMaxArgumentBuffers) argument_buffer_discrete_mask |= 1u << desc_set; } +void CompilerMSL::set_argument_buffer_device_address_space(uint32_t desc_set, bool device_storage) +{ + if (desc_set < kMaxArgumentBuffers) + { + if (device_storage) + argument_buffer_device_storage_mask |= 1u << desc_set; + else + argument_buffer_device_storage_mask &= ~(1u << desc_set); + } +} + bool CompilerMSL::is_msl_vertex_attribute_used(uint32_t location) { return vtx_attrs_in_use.count(location) != 0; } -bool CompilerMSL::is_msl_resource_binding_used(ExecutionModel model, uint32_t desc_set, uint32_t binding) +bool CompilerMSL::is_msl_resource_binding_used(ExecutionModel model, uint32_t desc_set, uint32_t binding) const { StageSetBinding tuple = { model, desc_set, binding }; auto itr = resource_bindings.find(tuple); @@ -89,11 +113,26 @@ uint32_t CompilerMSL::get_automatic_msl_resource_binding_secondary(uint32_t id) return get_extended_decoration(id, SPIRVCrossDecorationResourceIndexSecondary); } +uint32_t CompilerMSL::get_automatic_msl_resource_binding_tertiary(uint32_t id) const +{ + return get_extended_decoration(id, SPIRVCrossDecorationResourceIndexTertiary); +} + +uint32_t CompilerMSL::get_automatic_msl_resource_binding_quaternary(uint32_t id) const +{ + return get_extended_decoration(id, SPIRVCrossDecorationResourceIndexQuaternary); +} + void CompilerMSL::set_fragment_output_components(uint32_t location, uint32_t components) { fragment_output_components[location] = components; } +bool CompilerMSL::builtin_translates_to_nonarray(spv::BuiltIn builtin) const +{ + return (builtin == BuiltInSampleMask); +} + void CompilerMSL::build_implicit_builtins() { bool need_sample_pos = active_input_builtins.get(BuiltInSamplePosition); @@ -107,8 +146,11 @@ void CompilerMSL::build_implicit_builtins() active_input_builtins.get(BuiltInSubgroupGtMask)); bool need_multiview = get_execution_model() == ExecutionModelVertex && !msl_options.view_index_from_device_index && (msl_options.multiview || active_input_builtins.get(BuiltInViewIndex)); + bool need_dispatch_base = + msl_options.dispatch_base && get_execution_model() == ExecutionModelGLCompute && + (active_input_builtins.get(BuiltInWorkgroupId) || active_input_builtins.get(BuiltInGlobalInvocationId)); if (need_subpass_input || need_sample_pos || need_subgroup_mask || need_vertex_params || need_tesc_params || - need_multiview || needs_subgroup_invocation_id) + need_multiview || need_dispatch_base || needs_subgroup_invocation_id) { bool has_frag_coord = false; bool has_sample_id = false; @@ -121,13 +163,16 @@ void CompilerMSL::build_implicit_builtins() bool has_subgroup_invocation_id = false; bool has_subgroup_size = false; bool has_view_idx = false; + uint32_t workgroup_id_type = 0; ir.for_each_typed_id([&](uint32_t, SPIRVariable &var) { if (var.storage != StorageClassInput || !ir.meta[var.self].decoration.builtin) return; + // Use Metal's native frame-buffer fetch API for subpass inputs. BuiltIn builtin = ir.meta[var.self].decoration.builtin_type; - if (need_subpass_input && builtin == BuiltInFragCoord) + if (need_subpass_input && (!msl_options.is_ios() || !msl_options.ios_use_framebuffer_fetch_subpasses) && + builtin == BuiltInFragCoord) { builtin_frag_coord_id = var.self; has_frag_coord = true; @@ -195,22 +240,33 @@ void CompilerMSL::build_implicit_builtins() if (need_multiview) { - if (builtin == BuiltInInstanceIndex) + switch (builtin) { + case BuiltInInstanceIndex: // The view index here is derived from the instance index. builtin_instance_idx_id = var.self; has_instance_idx = true; - } - - if (builtin == BuiltInViewIndex) - { + break; + case BuiltInViewIndex: builtin_view_idx_id = var.self; has_view_idx = true; + break; + default: + break; } } + + // The base workgroup needs to have the same type and vector size + // as the workgroup or invocation ID, so keep track of the type that + // was used. + if (need_dispatch_base && workgroup_id_type == 0 && + (builtin == BuiltInWorkgroupId || builtin == BuiltInGlobalInvocationId)) + workgroup_id_type = var.basetype; }); - if (!has_frag_coord && need_subpass_input) + // Use Metal's native frame-buffer fetch API for subpass inputs. + if (!has_frag_coord && (!msl_options.is_ios() || !msl_options.ios_use_framebuffer_fetch_subpasses) && + need_subpass_input) { uint32_t offset = ir.increase_bound_by(3); uint32_t type_id = offset; @@ -457,6 +513,42 @@ void CompilerMSL::build_implicit_builtins() builtin_subgroup_size_id = var_id; mark_implicit_builtin(StorageClassInput, BuiltInSubgroupSize, var_id); } + + if (need_dispatch_base) + { + uint32_t var_id; + if (msl_options.supports_msl_version(1, 2)) + { + // If we have MSL 1.2, we can (ab)use the [[grid_origin]] builtin + // to convey this information and save a buffer slot. + uint32_t offset = ir.increase_bound_by(1); + var_id = offset; + + set(var_id, workgroup_id_type, StorageClassInput); + set_extended_decoration(var_id, SPIRVCrossDecorationBuiltInDispatchBase); + get_entry_point().interface_variables.push_back(var_id); + } + else + { + // Otherwise, we need to fall back to a good ol' fashioned buffer. + uint32_t offset = ir.increase_bound_by(2); + var_id = offset; + uint32_t type_id = offset + 1; + + SPIRType var_type = get(workgroup_id_type); + var_type.storage = StorageClassUniform; + set(type_id, var_type); + + set(var_id, type_id, StorageClassUniform); + // This should never match anything. + set_decoration(var_id, DecorationDescriptorSet, ~(5u)); + set_decoration(var_id, DecorationBinding, msl_options.indirect_params_buffer_index); + set_extended_decoration(var_id, SPIRVCrossDecorationResourceIndexPrimary, + msl_options.indirect_params_buffer_index); + } + set_name(var_id, "spvDispatchBase"); + builtin_dispatch_base_id = var_id; + } } if (needs_swizzle_buffer_def) @@ -491,6 +583,47 @@ void CompilerMSL::build_implicit_builtins() set_extended_decoration(var_id, SPIRVCrossDecorationResourceIndexPrimary, msl_options.view_mask_buffer_index); view_mask_buffer_id = var_id; } + + if (!buffers_requiring_dynamic_offset.empty()) + { + uint32_t var_id = build_constant_uint_array_pointer(); + set_name(var_id, "spvDynamicOffsets"); + // This should never match anything. + set_decoration(var_id, DecorationDescriptorSet, ~(5u)); + set_decoration(var_id, DecorationBinding, msl_options.dynamic_offsets_buffer_index); + set_extended_decoration(var_id, SPIRVCrossDecorationResourceIndexPrimary, + msl_options.dynamic_offsets_buffer_index); + dynamic_offsets_buffer_id = var_id; + } +} + +// Checks if the specified builtin variable (e.g. gl_InstanceIndex) is marked as active. +// If not, it marks it as active and forces a recompilation. +// This might be used when the optimization of inactive builtins was too optimistic (e.g. when "spvOut" is emitted). +void CompilerMSL::ensure_builtin(spv::StorageClass storage, spv::BuiltIn builtin) +{ + Bitset *active_builtins = nullptr; + switch (storage) + { + case StorageClassInput: + active_builtins = &active_input_builtins; + break; + + case StorageClassOutput: + active_builtins = &active_output_builtins; + break; + + default: + break; + } + + // At this point, the specified builtin variable must have already been declared in the entry point. + // If not, mark as active and force recompile. + if (active_builtins != nullptr && !active_builtins->get(builtin)) + { + active_builtins->set(builtin); + force_recompile(); + } } void CompilerMSL::mark_implicit_builtin(StorageClass storage, BuiltIn builtin, uint32_t id) @@ -599,6 +732,8 @@ std::string CompilerMSL::get_tess_factor_struct_name() void CompilerMSL::emit_entry_point_declarations() { // FIXME: Get test coverage here ... + // Constant arrays of non-primitive types (i.e. matrices) won't link properly into Metal libraries + declare_complex_constant_arrays(); // Emit constexpr samplers here. for (auto &samp : constexpr_samplers_by_id) @@ -717,9 +852,85 @@ void CompilerMSL::emit_entry_point_declarations() convert_to_string(s.lod_clamp_max, current_locale_radix_character), ")")); } - statement("constexpr sampler ", - type.basetype == SPIRType::SampledImage ? to_sampler_expression(samp.first) : to_name(samp.first), - "(", merge(args), ");"); + // If we would emit no arguments, then omit the parentheses entirely. Otherwise, + // we'll wind up with a "most vexing parse" situation. + if (args.empty()) + statement("constexpr sampler ", + type.basetype == SPIRType::SampledImage ? to_sampler_expression(samp.first) : to_name(samp.first), + ";"); + else + statement("constexpr sampler ", + type.basetype == SPIRType::SampledImage ? to_sampler_expression(samp.first) : to_name(samp.first), + "(", merge(args), ");"); + } + + // Emit dynamic buffers here. + for (auto &dynamic_buffer : buffers_requiring_dynamic_offset) + { + if (!dynamic_buffer.second.second) + { + // Could happen if no buffer was used at requested binding point. + continue; + } + + const auto &var = get(dynamic_buffer.second.second); + uint32_t var_id = var.self; + const auto &type = get_variable_data_type(var); + string name = to_name(var.self); + uint32_t desc_set = get_decoration(var.self, DecorationDescriptorSet); + uint32_t arg_id = argument_buffer_ids[desc_set]; + uint32_t base_index = dynamic_buffer.second.first; + + if (!type.array.empty()) + { + // This is complicated, because we need to support arrays of arrays. + // And it's even worse if the outermost dimension is a runtime array, because now + // all this complicated goop has to go into the shader itself. (FIXME) + if (!type.array[type.array.size() - 1]) + SPIRV_CROSS_THROW("Runtime arrays with dynamic offsets are not supported yet."); + else + { + is_using_builtin_array = true; + statement(get_argument_address_space(var), " ", type_to_glsl(type), "* ", to_restrict(var_id), name, + type_to_array_glsl(type), " ="); + + uint32_t dim = uint32_t(type.array.size()); + uint32_t j = 0; + for (SmallVector indices(type.array.size()); + indices[type.array.size() - 1] < to_array_size_literal(type); j++) + { + while (dim > 0) + { + begin_scope(); + --dim; + } + + string arrays; + for (uint32_t i = uint32_t(type.array.size()); i; --i) + arrays += join("[", indices[i - 1], "]"); + statement("(", get_argument_address_space(var), " ", type_to_glsl(type), "* ", + to_restrict(var_id, false), ")((", get_argument_address_space(var), " char* ", + to_restrict(var_id, false), ")", to_name(arg_id), ".", ensure_valid_name(name, "m"), + arrays, " + ", to_name(dynamic_offsets_buffer_id), "[", base_index + j, "]),"); + + while (++indices[dim] >= to_array_size_literal(type, dim) && dim < type.array.size() - 1) + { + end_scope(","); + indices[dim++] = 0; + } + } + end_scope_decl(); + statement_no_indent(""); + is_using_builtin_array = false; + } + } + else + { + statement(get_argument_address_space(var), " auto& ", to_restrict(var_id), name, " = *(", + get_argument_address_space(var), " ", type_to_glsl(type), "* ", to_restrict(var_id, false), ")((", + get_argument_address_space(var), " char* ", to_restrict(var_id, false), ")", to_name(arg_id), ".", + ensure_valid_name(name, "m"), " + ", to_name(dynamic_offsets_buffer_id), "[", base_index, "]);"); + } } // Emit buffer arrays here. @@ -727,11 +938,13 @@ void CompilerMSL::emit_entry_point_declarations() { const auto &var = get(array_id); const auto &type = get_variable_data_type(var); + const auto &buffer_type = get_variable_element_type(var); string name = to_name(array_id); - statement(get_argument_address_space(var), " ", type_to_glsl(type), "* ", to_restrict(array_id), name, "[] ="); + statement(get_argument_address_space(var), " ", type_to_glsl(buffer_type), "* ", to_restrict(array_id), name, + "[] ="); begin_scope(); - for (uint32_t i = 0; i < type.array[0]; ++i) - statement(name + "_" + convert_to_string(i) + ","); + for (uint32_t i = 0; i < to_array_size_literal(type); ++i) + statement(name, "_", i, ","); end_scope_decl(); statement_no_indent(""); } @@ -749,7 +962,7 @@ string CompilerMSL::compile() backend.float_literal_suffix = false; backend.uint32_t_literal_suffix = true; backend.int16_t_literal_suffix = ""; - backend.uint16_t_literal_suffix = "u"; + backend.uint16_t_literal_suffix = ""; backend.basic_int_type = "int"; backend.basic_uint_type = "uint"; backend.basic_int8_type = "char"; @@ -766,13 +979,16 @@ string CompilerMSL::compile() backend.native_row_major_matrix = false; backend.unsized_array_supported = false; backend.can_declare_arrays_inline = false; - backend.can_return_array = false; backend.allow_truncated_access_chain = true; - backend.array_is_value_type = false; backend.comparison_image_samples_scalar = true; backend.native_pointers = true; backend.nonuniform_qualifier = ""; backend.support_small_type_sampling_result = true; + backend.supports_empty_struct = true; + + // Allow Metal to use the array template unless we force it off. + backend.can_return_array = !msl_options.force_native_arrays; + backend.array_is_value_type = !msl_options.force_native_arrays; capture_output_to_buffer = msl_options.capture_output_to_buffer; is_rasterization_disabled = msl_options.disable_rasterization || capture_output_to_buffer; @@ -788,20 +1004,28 @@ string CompilerMSL::compile() update_active_builtins(); analyze_image_and_sampler_usage(); analyze_sampled_image_usage(); + analyze_interlocked_resource_usage(); preprocess_op_codes(); build_implicit_builtins(); fixup_image_load_store_access(); set_enabled_interface_variables(get_active_interface_variables()); + if (msl_options.force_active_argument_buffer_resources) + activate_argument_buffer_resources(); + if (swizzle_buffer_id) active_interface_variables.insert(swizzle_buffer_id); if (buffer_size_buffer_id) active_interface_variables.insert(buffer_size_buffer_id); if (view_mask_buffer_id) active_interface_variables.insert(view_mask_buffer_id); + if (dynamic_offsets_buffer_id) + active_interface_variables.insert(dynamic_offsets_buffer_id); if (builtin_layer_id) active_interface_variables.insert(builtin_layer_id); + if (builtin_dispatch_base_id && !msl_options.supports_msl_version(1, 2)) + active_interface_variables.insert(builtin_dispatch_base_id); // Create structs to hold input, output and uniform variables. // Do output first to ensure out. is declared at top of entry function. @@ -861,6 +1085,7 @@ string CompilerMSL::compile() buffer.reset(); emit_header(); + emit_custom_templates(); emit_specialization_constants_and_structs(); emit_resources(); emit_custom_functions(); @@ -989,8 +1214,10 @@ void CompilerMSL::extract_global_variables_from_function(uint32_t func_id, std:: if (global_var_ids.find(base_id) != global_var_ids.end()) added_arg_ids.insert(base_id); + // Use Metal's native frame-buffer fetch API for subpass inputs. auto &type = get(ops[0]); - if (type.basetype == SPIRType::Image && type.image.dim == DimSubpassData) + if (type.basetype == SPIRType::Image && type.image.dim == DimSubpassData && + (!msl_options.is_ios() || !msl_options.ios_use_framebuffer_fetch_subpasses)) { // Implicitly reads gl_FragCoord. assert(builtin_frag_coord_id != 0); @@ -1038,6 +1265,20 @@ void CompilerMSL::extract_global_variables_from_function(uint32_t func_id, std:: break; } + // Emulate texture2D atomic operations + case OpImageTexelPointer: + { + // When using the pointer, we need to know which variable it is actually loaded from. + uint32_t base_id = ops[2]; + auto *var = maybe_get_backing_variable(base_id); + if (var && atomic_image_vars.count(var->self)) + { + if (global_var_ids.find(base_id) != global_var_ids.end()) + added_arg_ids.insert(base_id); + } + break; + } + default: break; } @@ -1221,7 +1462,7 @@ uint32_t CompilerMSL::build_extended_vector_type(uint32_t type_id, uint32_t comp } void CompilerMSL::add_plain_variable_to_interface_block(StorageClass storage, const string &ib_var_ref, - SPIRType &ib_type, SPIRVariable &var, bool strip_array) + SPIRType &ib_type, SPIRVariable &var, InterfaceBlockMeta &meta) { bool is_builtin = is_builtin_variable(var); BuiltIn builtin = BuiltIn(get_decoration(var.self, DecorationBuiltIn)); @@ -1236,16 +1477,77 @@ void CompilerMSL::add_plain_variable_to_interface_block(StorageClass storage, co var.basetype = type_id; type_id = get_pointee_type_id(var.basetype); - if (strip_array && is_array(get(type_id))) + if (meta.strip_array && is_array(get(type_id))) type_id = get(type_id).parent_type; auto &type = get(type_id); uint32_t target_components = 0; uint32_t type_components = type.vecsize; + bool padded_output = false; + bool padded_input = false; + uint32_t start_component = 0; + + auto &entry_func = get(ir.default_entry_point); + + // Deal with Component decorations. + InterfaceBlockMeta::LocationMeta *location_meta = nullptr; + if (has_decoration(var.self, DecorationLocation)) + { + auto location_meta_itr = meta.location_meta.find(get_decoration(var.self, DecorationLocation)); + if (location_meta_itr != end(meta.location_meta)) + location_meta = &location_meta_itr->second; + } + + bool pad_fragment_output = has_decoration(var.self, DecorationLocation) && + msl_options.pad_fragment_output_components && + get_entry_point().model == ExecutionModelFragment && storage == StorageClassOutput; // Check if we need to pad fragment output to match a certain number of components. - if (get_decoration_bitset(var.self).get(DecorationLocation) && msl_options.pad_fragment_output_components && - get_entry_point().model == ExecutionModelFragment && storage == StorageClassOutput) + if (location_meta) + { + start_component = get_decoration(var.self, DecorationComponent); + uint32_t num_components = location_meta->num_components; + if (pad_fragment_output) + { + uint32_t locn = get_decoration(var.self, DecorationLocation); + num_components = std::max(num_components, get_target_components_for_fragment_location(locn)); + } + + if (location_meta->ib_index != ~0u) + { + // We have already declared the variable. Just emit an early-declared variable and fixup as needed. + entry_func.add_local_variable(var.self); + vars_needing_early_declaration.push_back(var.self); + + if (var.storage == StorageClassInput) + { + uint32_t ib_index = location_meta->ib_index; + entry_func.fixup_hooks_in.push_back([=, &var]() { + statement(to_name(var.self), " = ", ib_var_ref, ".", to_member_name(ib_type, ib_index), + vector_swizzle(type_components, start_component), ";"); + }); + } + else + { + uint32_t ib_index = location_meta->ib_index; + entry_func.fixup_hooks_out.push_back([=, &var]() { + statement(ib_var_ref, ".", to_member_name(ib_type, ib_index), + vector_swizzle(type_components, start_component), " = ", to_name(var.self), ";"); + }); + } + return; + } + else + { + location_meta->ib_index = uint32_t(ib_type.member_types.size()); + type_id = build_extended_vector_type(type_id, num_components); + if (var.storage == StorageClassInput) + padded_input = true; + else + padded_output = true; + } + } + else if (pad_fragment_output) { uint32_t locn = get_decoration(var.self, DecorationLocation); target_components = get_target_components_for_fragment_location(locn); @@ -1265,25 +1567,42 @@ void CompilerMSL::add_plain_variable_to_interface_block(StorageClass storage, co // Update the original variable reference to include the structure reference string qual_var_name = ib_var_ref + "." + mbr_name; - auto &entry_func = get(ir.default_entry_point); - if (padded_output) + if (padded_output || padded_input) { entry_func.add_local_variable(var.self); vars_needing_early_declaration.push_back(var.self); - entry_func.fixup_hooks_out.push_back([=, &var]() { - SPIRType &padded_type = this->get(type_id); - statement(qual_var_name, " = ", remap_swizzle(padded_type, type_components, to_name(var.self)), ";"); - }); + if (padded_output) + { + entry_func.fixup_hooks_out.push_back([=, &var]() { + statement(qual_var_name, vector_swizzle(type_components, start_component), " = ", to_name(var.self), + ";"); + }); + } + else + { + entry_func.fixup_hooks_in.push_back([=, &var]() { + statement(to_name(var.self), " = ", qual_var_name, vector_swizzle(type_components, start_component), + ";"); + }); + } } - else if (!strip_array) + else if (!meta.strip_array) ir.meta[var.self].decoration.qualified_alias = qual_var_name; - if (var.storage == StorageClassOutput && var.initializer != 0) + if (var.storage == StorageClassOutput && var.initializer != ID(0)) { - entry_func.fixup_hooks_in.push_back( - [=, &var]() { statement(qual_var_name, " = ", to_expression(var.initializer), ";"); }); + if (padded_output || padded_input) + { + entry_func.fixup_hooks_in.push_back( + [=, &var]() { statement(to_name(var.self), " = ", to_expression(var.initializer), ";"); }); + } + else + { + entry_func.fixup_hooks_in.push_back( + [=, &var]() { statement(qual_var_name, " = ", to_expression(var.initializer), ";"); }); + } } // Copy the variable location from the original variable to the member @@ -1292,10 +1611,14 @@ void CompilerMSL::add_plain_variable_to_interface_block(StorageClass storage, co uint32_t locn = get_decoration(var.self, DecorationLocation); if (storage == StorageClassInput && (get_execution_model() == ExecutionModelVertex || is_tessellation_shader())) { - type_id = ensure_correct_attribute_type(var.basetype, locn); - var.basetype = type_id; + type_id = ensure_correct_attribute_type(var.basetype, locn, + location_meta ? location_meta->num_components : type.vecsize); + + if (!location_meta) + var.basetype = type_id; + type_id = get_pointee_type_id(type_id); - if (strip_array && is_array(get(type_id))) + if (meta.strip_array && is_array(get(type_id))) type_id = get(type_id).parent_type; ib_type.member_types[ib_mbr_idx] = type_id; } @@ -1309,10 +1632,13 @@ void CompilerMSL::add_plain_variable_to_interface_block(StorageClass storage, co mark_location_as_used_by_shader(locn, storage); } - if (get_decoration_bitset(var.self).get(DecorationComponent)) + if (!location_meta) { - uint32_t comp = get_decoration(var.self, DecorationComponent); - set_member_decoration(ib_type.self, ib_mbr_idx, DecorationComponent, comp); + if (get_decoration_bitset(var.self).get(DecorationComponent)) + { + uint32_t component = get_decoration(var.self, DecorationComponent); + set_member_decoration(ib_type.self, ib_mbr_idx, DecorationComponent, component); + } } if (get_decoration_bitset(var.self).get(DecorationIndex)) @@ -1339,14 +1665,18 @@ void CompilerMSL::add_plain_variable_to_interface_block(StorageClass storage, co if (is_sample) set_member_decoration(ib_type.self, ib_mbr_idx, DecorationSample); - set_extended_member_decoration(ib_type.self, ib_mbr_idx, SPIRVCrossDecorationInterfaceOrigID, var.self); + // If we have location meta, there is no unique OrigID. We won't need it, since we flatten/unflatten + // the variable to stack anyways here. + if (!location_meta) + set_extended_member_decoration(ib_type.self, ib_mbr_idx, SPIRVCrossDecorationInterfaceOrigID, var.self); } void CompilerMSL::add_composite_variable_to_interface_block(StorageClass storage, const string &ib_var_ref, - SPIRType &ib_type, SPIRVariable &var, bool strip_array) + SPIRType &ib_type, SPIRVariable &var, + InterfaceBlockMeta &meta) { auto &entry_func = get(ir.default_entry_point); - auto &var_type = strip_array ? get_variable_element_type(var) : get_variable_data_type(var); + auto &var_type = meta.strip_array ? get_variable_element_type(var) : get_variable_data_type(var); uint32_t elem_cnt = 0; if (is_matrix(var_type)) @@ -1381,10 +1711,30 @@ void CompilerMSL::add_composite_variable_to_interface_block(StorageClass storage if (is_builtin) set_name(var.self, builtin_to_glsl(builtin, StorageClassFunction)); - entry_func.add_local_variable(var.self); + bool flatten_from_ib_var = false; + string flatten_from_ib_mbr_name; - // We need to declare the variable early and at entry-point scope. - vars_needing_early_declaration.push_back(var.self); + if (storage == StorageClassOutput && is_builtin && builtin == BuiltInClipDistance) + { + // Also declare [[clip_distance]] attribute here. + uint32_t clip_array_mbr_idx = uint32_t(ib_type.member_types.size()); + ib_type.member_types.push_back(get_variable_data_type_id(var)); + set_member_decoration(ib_type.self, clip_array_mbr_idx, DecorationBuiltIn, BuiltInClipDistance); + + flatten_from_ib_mbr_name = builtin_to_glsl(BuiltInClipDistance, StorageClassOutput); + set_member_name(ib_type.self, clip_array_mbr_idx, flatten_from_ib_mbr_name); + + // When we flatten, we flatten directly from the "out" struct, + // not from a function variable. + flatten_from_ib_var = true; + } + else if (!meta.strip_array) + { + // Only flatten/unflatten IO composites for non-tessellation cases where arrays are not stripped. + entry_func.add_local_variable(var.self); + // We need to declare the variable early and at entry-point scope. + vars_needing_early_declaration.push_back(var.self); + } for (uint32_t i = 0; i < elem_cnt; i++) { @@ -1435,6 +1785,12 @@ void CompilerMSL::add_composite_variable_to_interface_block(StorageClass storage set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, locn); mark_location_as_used_by_shader(locn, storage); } + else if (is_builtin && builtin == BuiltInClipDistance) + { + // Declare the ClipDistance as [[user(clipN)]]. + set_member_decoration(ib_type.self, ib_mbr_idx, DecorationBuiltIn, BuiltInClipDistance); + set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, i); + } if (get_decoration_bitset(var.self).get(DecorationIndex)) { @@ -1454,7 +1810,8 @@ void CompilerMSL::add_composite_variable_to_interface_block(StorageClass storage set_extended_member_decoration(ib_type.self, ib_mbr_idx, SPIRVCrossDecorationInterfaceOrigID, var.self); - if (!strip_array) + // Only flatten/unflatten IO composites for non-tessellation cases where arrays are not stripped. + if (!meta.strip_array) { switch (storage) { @@ -1473,6 +1830,9 @@ void CompilerMSL::add_composite_variable_to_interface_block(StorageClass storage remap_swizzle(padded_type, usable_type->vecsize, join(to_name(var.self), "[", i, "]")), ";"); } + else if (flatten_from_ib_var) + statement(ib_var_ref, ".", mbr_name, " = ", ib_var_ref, ".", flatten_from_ib_mbr_name, "[", i, + "];"); else statement(ib_var_ref, ".", mbr_name, " = ", to_name(var.self), "[", i, "];"); }); @@ -1515,12 +1875,12 @@ uint32_t CompilerMSL::get_accumulated_member_location(const SPIRVariable &var, u void CompilerMSL::add_composite_member_variable_to_interface_block(StorageClass storage, const string &ib_var_ref, SPIRType &ib_type, SPIRVariable &var, - uint32_t mbr_idx, bool strip_array) + uint32_t mbr_idx, InterfaceBlockMeta &meta) { auto &entry_func = get(ir.default_entry_point); - auto &var_type = strip_array ? get_variable_element_type(var) : get_variable_data_type(var); + auto &var_type = meta.strip_array ? get_variable_element_type(var) : get_variable_data_type(var); - BuiltIn builtin; + BuiltIn builtin = BuiltInMax; bool is_builtin = is_member_builtin(var_type, mbr_idx, &builtin); bool is_flat = has_member_decoration(var_type.self, mbr_idx, DecorationFlat) || has_decoration(var.self, DecorationFlat); @@ -1556,6 +1916,24 @@ void CompilerMSL::add_composite_member_variable_to_interface_block(StorageClass while (is_array(*usable_type) || is_matrix(*usable_type)) usable_type = &get(usable_type->parent_type); + bool flatten_from_ib_var = false; + string flatten_from_ib_mbr_name; + + if (storage == StorageClassOutput && is_builtin && builtin == BuiltInClipDistance) + { + // Also declare [[clip_distance]] attribute here. + uint32_t clip_array_mbr_idx = uint32_t(ib_type.member_types.size()); + ib_type.member_types.push_back(mbr_type_id); + set_member_decoration(ib_type.self, clip_array_mbr_idx, DecorationBuiltIn, BuiltInClipDistance); + + flatten_from_ib_mbr_name = builtin_to_glsl(BuiltInClipDistance, StorageClassOutput); + set_member_name(ib_type.self, clip_array_mbr_idx, flatten_from_ib_mbr_name); + + // When we flatten, we flatten directly from the "out" struct, + // not from a function variable. + flatten_from_ib_var = true; + } + for (uint32_t i = 0; i < elem_cnt; i++) { // Add a reference to the variable type to the interface struct. @@ -1574,7 +1952,7 @@ void CompilerMSL::add_composite_member_variable_to_interface_block(StorageClass } else if (has_decoration(var.self, DecorationLocation)) { - uint32_t locn = get_accumulated_member_location(var, mbr_idx, strip_array) + i; + uint32_t locn = get_accumulated_member_location(var, mbr_idx, meta.strip_array) + i; set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, locn); mark_location_as_used_by_shader(locn, storage); } @@ -1584,6 +1962,12 @@ void CompilerMSL::add_composite_member_variable_to_interface_block(StorageClass set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, locn); mark_location_as_used_by_shader(locn, storage); } + else if (is_builtin && builtin == BuiltInClipDistance) + { + // Declare the ClipDistance as [[user(clipN)]]. + set_member_decoration(ib_type.self, ib_mbr_idx, DecorationBuiltIn, BuiltInClipDistance); + set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, i); + } if (has_member_decoration(var_type.self, mbr_idx, DecorationComponent)) SPIRV_CROSS_THROW("DecorationComponent on matrices and arrays make little sense."); @@ -1602,7 +1986,7 @@ void CompilerMSL::add_composite_member_variable_to_interface_block(StorageClass set_extended_member_decoration(ib_type.self, ib_mbr_idx, SPIRVCrossDecorationInterfaceMemberIndex, mbr_idx); // Unflatten or flatten from [[stage_in]] or [[stage_out]] as appropriate. - if (!strip_array) + if (!meta.strip_array) { switch (storage) { @@ -1615,8 +1999,16 @@ void CompilerMSL::add_composite_member_variable_to_interface_block(StorageClass case StorageClassOutput: entry_func.fixup_hooks_out.push_back([=, &var, &var_type]() { - statement(ib_var_ref, ".", mbr_name, " = ", to_name(var.self), ".", - to_member_name(var_type, mbr_idx), "[", i, "];"); + if (flatten_from_ib_var) + { + statement(ib_var_ref, ".", mbr_name, " = ", ib_var_ref, ".", flatten_from_ib_mbr_name, "[", i, + "];"); + } + else + { + statement(ib_var_ref, ".", mbr_name, " = ", to_name(var.self), ".", + to_member_name(var_type, mbr_idx), "[", i, "];"); + } }); break; @@ -1629,9 +2021,9 @@ void CompilerMSL::add_composite_member_variable_to_interface_block(StorageClass void CompilerMSL::add_plain_member_variable_to_interface_block(StorageClass storage, const string &ib_var_ref, SPIRType &ib_type, SPIRVariable &var, uint32_t mbr_idx, - bool strip_array) + InterfaceBlockMeta &meta) { - auto &var_type = strip_array ? get_variable_element_type(var) : get_variable_data_type(var); + auto &var_type = meta.strip_array ? get_variable_element_type(var) : get_variable_data_type(var); auto &entry_func = get(ir.default_entry_point); BuiltIn builtin = BuiltInMax; @@ -1659,13 +2051,13 @@ void CompilerMSL::add_plain_member_variable_to_interface_block(StorageClass stor // Update the original variable reference to include the structure reference string qual_var_name = ib_var_ref + "." + mbr_name; - if (is_builtin && !strip_array) + if (is_builtin && !meta.strip_array) { // For the builtin gl_PerVertex, we cannot treat it as a block anyways, // so redirect to qualified name. set_member_qualified_name(var_type.self, mbr_idx, qual_var_name); } - else if (!strip_array) + else if (!meta.strip_array) { // Unflatten or flatten from [[stage_in]] or [[stage_out]] as appropriate. switch (storage) @@ -1704,7 +2096,7 @@ void CompilerMSL::add_plain_member_variable_to_interface_block(StorageClass stor { // The block itself might have a location and in this case, all members of the block // receive incrementing locations. - uint32_t locn = get_accumulated_member_location(var, mbr_idx, strip_array); + uint32_t locn = get_accumulated_member_location(var, mbr_idx, meta.strip_array); if (storage == StorageClassInput && (get_execution_model() == ExecutionModelVertex || is_tessellation_shader())) { mbr_type_id = ensure_correct_attribute_type(mbr_type_id, locn); @@ -1870,19 +2262,20 @@ void CompilerMSL::add_tess_level_input_to_interface_block(const std::string &ib_ } void CompilerMSL::add_variable_to_interface_block(StorageClass storage, const string &ib_var_ref, SPIRType &ib_type, - SPIRVariable &var, bool strip_array) + SPIRVariable &var, InterfaceBlockMeta &meta) { auto &entry_func = get(ir.default_entry_point); // Tessellation control I/O variables and tessellation evaluation per-point inputs are // usually declared as arrays. In these cases, we want to add the element type to the // interface block, since in Metal it's the interface block itself which is arrayed. - auto &var_type = strip_array ? get_variable_element_type(var) : get_variable_data_type(var); + auto &var_type = meta.strip_array ? get_variable_element_type(var) : get_variable_data_type(var); bool is_builtin = is_builtin_variable(var); auto builtin = BuiltIn(get_decoration(var.self, DecorationBuiltIn)); if (var_type.basetype == SPIRType::Struct) { - if (!is_builtin_type(var_type) && (!capture_output_to_buffer || storage == StorageClassInput) && !strip_array) + if (!is_builtin_type(var_type) && (!capture_output_to_buffer || storage == StorageClassInput) && + !meta.strip_array) { // For I/O blocks or structs, we will need to pass the block itself around // to functions if they are used globally in leaf functions. @@ -1901,7 +2294,7 @@ void CompilerMSL::add_variable_to_interface_block(StorageClass storage, const st // Luckily, for stage-out when capturing output, we can avoid this and just add // composite members directly, because the stage-out structure is stored to a buffer, // not returned. - add_plain_variable_to_interface_block(storage, ib_var_ref, ib_type, var, strip_array); + add_plain_variable_to_interface_block(storage, ib_var_ref, ib_type, var, meta); } else { @@ -1914,25 +2307,30 @@ void CompilerMSL::add_variable_to_interface_block(StorageClass storage, const st if (!is_builtin || has_active_builtin(builtin, storage)) { - if ((!is_builtin || - (storage == StorageClassInput && get_execution_model() != ExecutionModelFragment)) && - (storage == StorageClassInput || storage == StorageClassOutput) && - (is_matrix(mbr_type) || is_array(mbr_type))) + bool is_composite_type = is_matrix(mbr_type) || is_array(mbr_type); + bool attribute_load_store = + storage == StorageClassInput && get_execution_model() != ExecutionModelFragment; + bool storage_is_stage_io = storage == StorageClassInput || storage == StorageClassOutput; + + // ClipDistance always needs to be declared as user attributes. + if (builtin == BuiltInClipDistance) + is_builtin = false; + + if ((!is_builtin || attribute_load_store) && storage_is_stage_io && is_composite_type) { add_composite_member_variable_to_interface_block(storage, ib_var_ref, ib_type, var, mbr_idx, - strip_array); + meta); } else { - add_plain_member_variable_to_interface_block(storage, ib_var_ref, ib_type, var, mbr_idx, - strip_array); + add_plain_member_variable_to_interface_block(storage, ib_var_ref, ib_type, var, mbr_idx, meta); } } } } } else if (get_execution_model() == ExecutionModelTessellationEvaluation && storage == StorageClassInput && - !strip_array && is_builtin && (builtin == BuiltInTessLevelOuter || builtin == BuiltInTessLevelInner)) + !meta.strip_array && is_builtin && (builtin == BuiltInTessLevelOuter || builtin == BuiltInTessLevelInner)) { add_tess_level_input_to_interface_block(ib_var_ref, ib_type, var); } @@ -1941,16 +2339,23 @@ void CompilerMSL::add_variable_to_interface_block(StorageClass storage, const st { if (!is_builtin || has_active_builtin(builtin, storage)) { + bool is_composite_type = is_matrix(var_type) || is_array(var_type); + bool storage_is_stage_io = + storage == StorageClassInput || (storage == StorageClassOutput && !capture_output_to_buffer); + bool attribute_load_store = storage == StorageClassInput && get_execution_model() != ExecutionModelFragment; + + // ClipDistance always needs to be declared as user attributes. + if (builtin == BuiltInClipDistance) + is_builtin = false; + // MSL does not allow matrices or arrays in input or output variables, so need to handle it specially. - if ((!is_builtin || (storage == StorageClassInput && get_execution_model() != ExecutionModelFragment)) && - (storage == StorageClassInput || (storage == StorageClassOutput && !capture_output_to_buffer)) && - (is_matrix(var_type) || is_array(var_type))) + if ((!is_builtin || attribute_load_store) && storage_is_stage_io && is_composite_type) { - add_composite_variable_to_interface_block(storage, ib_var_ref, ib_type, var, strip_array); + add_composite_variable_to_interface_block(storage, ib_var_ref, ib_type, var, meta); } else { - add_plain_variable_to_interface_block(storage, ib_var_ref, ib_type, var, strip_array); + add_plain_variable_to_interface_block(storage, ib_var_ref, ib_type, var, meta); } } } @@ -1961,60 +2366,37 @@ void CompilerMSL::add_variable_to_interface_block(StorageClass storage, const st void CompilerMSL::fix_up_interface_member_indices(StorageClass storage, uint32_t ib_type_id) { // Only needed for tessellation shaders. + // Need to redirect interface indices back to variables themselves. + // For structs, each member of the struct need a separate instance. if (get_execution_model() != ExecutionModelTessellationControl && !(get_execution_model() == ExecutionModelTessellationEvaluation && storage == StorageClassInput)) return; - bool in_array = false; - for (uint32_t i = 0; i < ir.meta[ib_type_id].members.size(); i++) + auto mbr_cnt = uint32_t(ir.meta[ib_type_id].members.size()); + for (uint32_t i = 0; i < mbr_cnt; i++) { uint32_t var_id = get_extended_member_decoration(ib_type_id, i, SPIRVCrossDecorationInterfaceOrigID); if (!var_id) continue; auto &var = get(var_id); - // Unfortunately, all this complexity is needed to handle flattened structs and/or - // arrays. - if (storage == StorageClassInput) + auto &type = get_variable_element_type(var); + if (storage == StorageClassInput && type.basetype == SPIRType::Struct) { - auto &type = get_variable_element_type(var); - if (is_array(type) || is_matrix(type)) - { - if (in_array) - continue; - in_array = true; - set_extended_decoration(var_id, SPIRVCrossDecorationInterfaceMemberIndex, i); - } - else - { - if (type.basetype == SPIRType::Struct) - { - uint32_t mbr_idx = - get_extended_member_decoration(ib_type_id, i, SPIRVCrossDecorationInterfaceMemberIndex); - auto &mbr_type = get(type.member_types[mbr_idx]); + uint32_t mbr_idx = get_extended_member_decoration(ib_type_id, i, SPIRVCrossDecorationInterfaceMemberIndex); - if (is_array(mbr_type) || is_matrix(mbr_type)) - { - if (in_array) - continue; - in_array = true; - set_extended_member_decoration(var_id, mbr_idx, SPIRVCrossDecorationInterfaceMemberIndex, i); - } - else - { - in_array = false; - set_extended_member_decoration(var_id, mbr_idx, SPIRVCrossDecorationInterfaceMemberIndex, i); - } - } - else - { - in_array = false; - set_extended_decoration(var_id, SPIRVCrossDecorationInterfaceMemberIndex, i); - } - } + // Only set the lowest InterfaceMemberIndex for each variable member. + // IB struct members will be emitted in-order w.r.t. interface member index. + if (!has_extended_member_decoration(var_id, mbr_idx, SPIRVCrossDecorationInterfaceMemberIndex)) + set_extended_member_decoration(var_id, mbr_idx, SPIRVCrossDecorationInterfaceMemberIndex, i); } else - set_extended_decoration(var_id, SPIRVCrossDecorationInterfaceMemberIndex, i); + { + // Only set the lowest InterfaceMemberIndex for each variable. + // IB struct members will be emitted in-order w.r.t. interface member index. + if (!has_extended_decoration(var_id, SPIRVCrossDecorationInterfaceMemberIndex)) + set_extended_decoration(var_id, SPIRVCrossDecorationInterfaceMemberIndex, i); + } } } @@ -2027,6 +2409,16 @@ uint32_t CompilerMSL::add_interface_block(StorageClass storage, bool patch) bool incl_builtins = storage == StorageClassOutput || is_tessellation_shader(); bool has_seen_barycentric = false; + InterfaceBlockMeta meta; + + // Varying interfaces between stages which use "user()" attribute can be dealt with + // without explicit packing and unpacking of components. For any variables which link against the runtime + // in some way (vertex attributes, fragment output, etc), we'll need to deal with it somehow. + bool pack_components = + (storage == StorageClassInput && get_execution_model() == ExecutionModelVertex) || + (storage == StorageClassOutput && get_execution_model() == ExecutionModelFragment) || + (storage == StorageClassOutput && get_execution_model() == ExecutionModelVertex && capture_output_to_buffer); + ir.for_each_typed_id([&](uint32_t var_id, SPIRVariable &var) { if (var.storage != storage) return; @@ -2055,6 +2447,11 @@ uint32_t CompilerMSL::add_interface_block(StorageClass storage, bool patch) bool filter_patch_decoration = (has_decoration(var_id, DecorationPatch) || is_patch_block(type)) == patch; bool hidden = is_hidden_variable(var, incl_builtins); + + // ClipDistance is never hidden, we need to emulate it when used as an input. + if (bi_type == BuiltInClipDistance) + hidden = false; + // Barycentric inputs must be emitted in stage-in, because they can have interpolation arguments. if (is_active && (bi_type == BuiltInBaryCoordNV || bi_type == BuiltInBaryCoordNoPerspNV)) { @@ -2068,6 +2465,28 @@ uint32_t CompilerMSL::add_interface_block(StorageClass storage, bool patch) (!is_builtin || is_interface_block_builtin)) { vars.push_back(&var); + + if (!is_builtin) + { + // Need to deal specially with DecorationComponent. + // Multiple variables can alias the same Location, and try to make sure each location is declared only once. + // We will swizzle data in and out to make this work. + // We only need to consider plain variables here, not composites. + // This is only relevant for vertex inputs and fragment outputs. + // Technically tessellation as well, but it is too complicated to support. + uint32_t component = get_decoration(var_id, DecorationComponent); + if (component != 0) + { + if (is_tessellation_shader()) + SPIRV_CROSS_THROW("Component decoration is not supported in tessellation shaders."); + else if (pack_components) + { + uint32_t location = get_decoration(var_id, DecorationLocation); + auto &location_meta = meta.location_meta[location]; + location_meta.num_components = std::max(location_meta.num_components, component + type.vecsize); + } + } + } } }); @@ -2150,11 +2569,21 @@ uint32_t CompilerMSL::add_interface_block(StorageClass storage, bool patch) { // The first member of the indirect buffer is always the number of vertices // to draw. - statement("device ", to_name(ir.default_entry_point), "_", ib_var_ref, "& ", ib_var_ref, " = ", - output_buffer_var_name, "[(", to_expression(builtin_instance_idx_id), " - ", - to_expression(builtin_base_instance_id), ") * spvIndirectParams[0] + ", - to_expression(builtin_vertex_idx_id), " - ", to_expression(builtin_base_vertex_id), - "];"); + // We zero-base the InstanceID & VertexID variables for HLSL emulation elsewhere, so don't do it twice + if (msl_options.enable_base_index_zero) + { + statement("device ", to_name(ir.default_entry_point), "_", ib_var_ref, "& ", ib_var_ref, + " = ", output_buffer_var_name, "[", to_expression(builtin_instance_idx_id), + " * spvIndirectParams[0] + ", to_expression(builtin_vertex_idx_id), "];"); + } + else + { + statement("device ", to_name(ir.default_entry_point), "_", ib_var_ref, "& ", ib_var_ref, + " = ", output_buffer_var_name, "[(", to_expression(builtin_instance_idx_id), + " - ", to_expression(builtin_base_instance_id), ") * spvIndirectParams[0] + ", + to_expression(builtin_vertex_idx_id), " - ", + to_expression(builtin_base_vertex_id), "];"); + } } }); break; @@ -2191,7 +2620,9 @@ uint32_t CompilerMSL::add_interface_block(StorageClass storage, bool patch) (get_execution_model() == ExecutionModelTessellationControl || (get_execution_model() == ExecutionModelTessellationEvaluation && storage == StorageClassInput)) && !patch; - add_variable_to_interface_block(storage, ib_var_ref, ib_type, *p_var, strip_array); + + meta.strip_array = strip_array; + add_variable_to_interface_block(storage, ib_var_ref, ib_type, *p_var, meta); } // Sort the members of the structure by their locations. @@ -2310,13 +2741,18 @@ uint32_t CompilerMSL::ensure_correct_builtin_type(uint32_t type_id, BuiltIn buil // Ensure that the type is compatible with the vertex attribute. // If it is, simply return the given type ID. // Otherwise, create a new type, and return its ID. -uint32_t CompilerMSL::ensure_correct_attribute_type(uint32_t type_id, uint32_t location) +uint32_t CompilerMSL::ensure_correct_attribute_type(uint32_t type_id, uint32_t location, uint32_t num_components) { auto &type = get(type_id); auto p_va = vtx_attrs_by_location.find(location); if (p_va == end(vtx_attrs_by_location)) - return type_id; + { + if (num_components != 0 && type.vecsize != num_components) + return build_extended_vector_type(type_id, num_components); + else + return type_id; + } switch (p_va->second.format) { @@ -2327,19 +2763,27 @@ uint32_t CompilerMSL::ensure_correct_attribute_type(uint32_t type_id, uint32_t l case SPIRType::UByte: case SPIRType::UShort: case SPIRType::UInt: - return type_id; + if (num_components != 0 && type.vecsize != num_components) + return build_extended_vector_type(type_id, num_components); + else + return type_id; + case SPIRType::Short: case SPIRType::Int: break; + default: SPIRV_CROSS_THROW("Vertex attribute type mismatch between host and shader"); } + uint32_t next_id = ir.increase_bound_by(type.pointer ? 2 : 1); uint32_t base_type_id = next_id++; auto &base_type = set(base_type_id); base_type = type; base_type.basetype = type.basetype == SPIRType::Short ? SPIRType::UShort : SPIRType::UInt; base_type.pointer = false; + if (num_components != 0) + base_type.vecsize = num_components; if (!type.pointer) return base_type_id; @@ -2359,18 +2803,26 @@ uint32_t CompilerMSL::ensure_correct_attribute_type(uint32_t type_id, uint32_t l { case SPIRType::UShort: case SPIRType::UInt: - return type_id; + if (num_components != 0 && type.vecsize != num_components) + return build_extended_vector_type(type_id, num_components); + else + return type_id; + case SPIRType::Int: break; + default: SPIRV_CROSS_THROW("Vertex attribute type mismatch between host and shader"); } + uint32_t next_id = ir.increase_bound_by(type.pointer ? 2 : 1); uint32_t base_type_id = next_id++; auto &base_type = set(base_type_id); base_type = type; base_type.basetype = SPIRType::UInt; base_type.pointer = false; + if (num_components != 0) + base_type.vecsize = num_components; if (!type.pointer) return base_type_id; @@ -2385,7 +2837,8 @@ uint32_t CompilerMSL::ensure_correct_attribute_type(uint32_t type_id, uint32_t l } default: - case MSL_VERTEX_FORMAT_OTHER: + if (num_components != 0 && type.vecsize != num_components) + type_id = build_extended_vector_type(type_id, num_components); break; } @@ -2500,7 +2953,7 @@ void CompilerMSL::mark_scalar_layout_structs(const SPIRType &type) void CompilerMSL::align_struct(SPIRType &ib_type, unordered_set &aligned_structs) { // We align structs recursively, so stop any redundant work. - uint32_t &ib_type_id = ib_type.self; + ID &ib_type_id = ib_type.self; if (aligned_structs.count(ib_type_id)) return; aligned_structs.insert(ib_type_id); @@ -2779,8 +3232,9 @@ void CompilerMSL::emit_store_statement(uint32_t lhs_expression, uint32_t rhs_exp // Special handling when storing to a remapped physical type. // This is mostly to deal with std140 padded matrices or vectors. - uint32_t physical_type_id = - lhs_remapped_type ? get_extended_decoration(lhs_expression, SPIRVCrossDecorationPhysicalTypeID) : type.self; + TypeID physical_type_id = lhs_remapped_type ? + ID(get_extended_decoration(lhs_expression, SPIRVCrossDecorationPhysicalTypeID)) : + type.self; auto &physical_type = get(physical_type_id); @@ -2943,6 +3397,14 @@ void CompilerMSL::emit_store_statement(uint32_t lhs_expression, uint32_t rhs_exp } } +static bool expression_ends_with(const string &expr_str, const std::string &ending) +{ + if (expr_str.length() >= ending.length()) + return (expr_str.compare(expr_str.length() - ending.length(), ending.length(), ending) == 0); + else + return false; +} + // Converts the format of the current expression from packed to unpacked, // by wrapping the expression in a constructor of the appropriate type. // Also, handle special physical ID remapping scenarios, similar to emit_store_statement(). @@ -2963,9 +3425,16 @@ string CompilerMSL::unpack_expression_type(string expr_str, const SPIRType &type ".xyz", }; - // std140 array cases for vectors. - if (physical_type && is_vector(*physical_type) && is_array(*physical_type) && physical_type->vecsize > type.vecsize) + if (physical_type && is_vector(*physical_type) && is_array(*physical_type) && + physical_type->vecsize > type.vecsize && !expression_ends_with(expr_str, swizzle_lut[type.vecsize - 1])) { + // std140 array cases for vectors. + assert(type.vecsize >= 1 && type.vecsize <= 3); + return enclose_expression(expr_str) + swizzle_lut[type.vecsize - 1]; + } + else if (physical_type && is_matrix(*physical_type) && is_vector(type) && physical_type->vecsize > type.vecsize) + { + // Extract column from padded matrix. assert(type.vecsize >= 1 && type.vecsize <= 3); return enclose_expression(expr_str) + swizzle_lut[type.vecsize - 1]; } @@ -3007,7 +3476,9 @@ string CompilerMSL::unpack_expression_type(string expr_str, const SPIRType &type return unpack_expr; } else + { return join(type_to_glsl(type), "(", expr_str, ")"); + } } // Emits the file header info @@ -3016,6 +3487,11 @@ void CompilerMSL::emit_header() // This particular line can be overridden during compilation, so make it a flag and not a pragma line. if (suppress_missing_prototypes) statement("#pragma clang diagnostic ignored \"-Wmissing-prototypes\""); + + // Disable warning about missing braces for array template to make arrays a value type + if (spv_function_implementations.count(SPVFuncImplUnsafeArray) != 0) + statement("#pragma clang diagnostic ignored \"-Wmissing-braces\""); + for (auto &pragma : pragma_lines) statement(pragma); @@ -3053,21 +3529,110 @@ void CompilerMSL::add_typedef_line(const string &line) force_recompile(); } +// Template struct like spvUnsafeArray<> need to be declared *before* any resources are declared +void CompilerMSL::emit_custom_templates() +{ + for (const auto &spv_func : spv_function_implementations) + { + switch (spv_func) + { + case SPVFuncImplUnsafeArray: + statement("template"); + statement("struct spvUnsafeArray"); + begin_scope(); + statement("T elements[Num ? Num : 1];"); + statement(""); + statement("thread T& operator [] (size_t pos) thread"); + begin_scope(); + statement("return elements[pos];"); + end_scope(); + statement("constexpr const thread T& operator [] (size_t pos) const thread"); + begin_scope(); + statement("return elements[pos];"); + end_scope(); + statement(""); + statement("device T& operator [] (size_t pos) device"); + begin_scope(); + statement("return elements[pos];"); + end_scope(); + statement("constexpr const device T& operator [] (size_t pos) const device"); + begin_scope(); + statement("return elements[pos];"); + end_scope(); + statement(""); + statement("constexpr const constant T& operator [] (size_t pos) const constant"); + begin_scope(); + statement("return elements[pos];"); + end_scope(); + statement(""); + statement("threadgroup T& operator [] (size_t pos) threadgroup"); + begin_scope(); + statement("return elements[pos];"); + end_scope(); + statement("constexpr const threadgroup T& operator [] (size_t pos) const threadgroup"); + begin_scope(); + statement("return elements[pos];"); + end_scope(); + end_scope_decl(); + statement(""); + break; + + default: + break; + } + } +} + // Emits any needed custom function bodies. +// Metal helper functions must be static force-inline, i.e. static inline __attribute__((always_inline)) +// otherwise they will cause problems when linked together in a single Metallib. void CompilerMSL::emit_custom_functions() { for (uint32_t i = SPVFuncImplArrayCopyMultidimMax; i >= 2; i--) if (spv_function_implementations.count(static_cast(SPVFuncImplArrayCopyMultidimBase + i))) spv_function_implementations.insert(static_cast(SPVFuncImplArrayCopyMultidimBase + i - 1)); - for (auto &spv_func : spv_function_implementations) + if (spv_function_implementations.count(SPVFuncImplDynamicImageSampler)) + { + // Unfortunately, this one needs a lot of the other functions to compile OK. + if (!msl_options.supports_msl_version(2)) + SPIRV_CROSS_THROW( + "spvDynamicImageSampler requires default-constructible texture objects, which require MSL 2.0."); + spv_function_implementations.insert(SPVFuncImplForwardArgs); + spv_function_implementations.insert(SPVFuncImplTextureSwizzle); + if (msl_options.swizzle_texture_samples) + spv_function_implementations.insert(SPVFuncImplGatherSwizzle); + for (uint32_t i = SPVFuncImplChromaReconstructNearest2Plane; + i <= SPVFuncImplChromaReconstructLinear420XMidpointYMidpoint3Plane; i++) + spv_function_implementations.insert(static_cast(i)); + spv_function_implementations.insert(SPVFuncImplExpandITUFullRange); + spv_function_implementations.insert(SPVFuncImplExpandITUNarrowRange); + spv_function_implementations.insert(SPVFuncImplConvertYCbCrBT709); + spv_function_implementations.insert(SPVFuncImplConvertYCbCrBT601); + spv_function_implementations.insert(SPVFuncImplConvertYCbCrBT2020); + } + + for (uint32_t i = SPVFuncImplChromaReconstructNearest2Plane; + i <= SPVFuncImplChromaReconstructLinear420XMidpointYMidpoint3Plane; i++) + if (spv_function_implementations.count(static_cast(i))) + spv_function_implementations.insert(SPVFuncImplForwardArgs); + + if (spv_function_implementations.count(SPVFuncImplTextureSwizzle) || + spv_function_implementations.count(SPVFuncImplGatherSwizzle) || + spv_function_implementations.count(SPVFuncImplGatherCompareSwizzle)) + { + spv_function_implementations.insert(SPVFuncImplForwardArgs); + spv_function_implementations.insert(SPVFuncImplGetSwizzle); + } + + for (const auto &spv_func : spv_function_implementations) { switch (spv_func) { case SPVFuncImplMod: statement("// Implementation of the GLSL mod() function, which is slightly different than Metal fmod()"); statement("template"); - statement("Tx mod(Tx x, Ty y)"); + statement("inline Tx mod(Tx x, Ty y)"); begin_scope(); statement("return x - y * floor(x / y);"); end_scope(); @@ -3077,7 +3642,7 @@ void CompilerMSL::emit_custom_functions() case SPVFuncImplRadians: statement("// Implementation of the GLSL radians() function"); statement("template"); - statement("T radians(T d)"); + statement("inline T radians(T d)"); begin_scope(); statement("return d * T(0.01745329251);"); end_scope(); @@ -3087,7 +3652,7 @@ void CompilerMSL::emit_custom_functions() case SPVFuncImplDegrees: statement("// Implementation of the GLSL degrees() function"); statement("template"); - statement("T degrees(T r)"); + statement("inline T degrees(T r)"); begin_scope(); statement("return r * T(57.2957795131);"); end_scope(); @@ -3097,7 +3662,7 @@ void CompilerMSL::emit_custom_functions() case SPVFuncImplFindILsb: statement("// Implementation of the GLSL findLSB() function"); statement("template"); - statement("T spvFindLSB(T x)"); + statement("inline T spvFindLSB(T x)"); begin_scope(); statement("return select(ctz(x), T(-1), x == T(0));"); end_scope(); @@ -3107,7 +3672,7 @@ void CompilerMSL::emit_custom_functions() case SPVFuncImplFindUMsb: statement("// Implementation of the unsigned GLSL findMSB() function"); statement("template"); - statement("T spvFindUMSB(T x)"); + statement("inline T spvFindUMSB(T x)"); begin_scope(); statement("return select(clz(T(0)) - (clz(x) + T(1)), T(-1), x == T(0));"); end_scope(); @@ -3117,7 +3682,7 @@ void CompilerMSL::emit_custom_functions() case SPVFuncImplFindSMsb: statement("// Implementation of the signed GLSL findMSB() function"); statement("template"); - statement("T spvFindSMSB(T x)"); + statement("inline T spvFindSMSB(T x)"); begin_scope(); statement("T v = select(x, T(-1) - x, x < T(0));"); statement("return select(clz(T(0)) - (clz(v) + T(1)), T(-1), v == T(0));"); @@ -3128,7 +3693,7 @@ void CompilerMSL::emit_custom_functions() case SPVFuncImplSSign: statement("// Implementation of the GLSL sign() function for integer types"); statement("template::value>::type>"); - statement("T sign(T x)"); + statement("inline T sign(T x)"); begin_scope(); statement("return select(select(select(x, T(0), x == T(0)), T(1), x > T(0)), T(-1), x < T(0));"); end_scope(); @@ -3136,40 +3701,27 @@ void CompilerMSL::emit_custom_functions() break; case SPVFuncImplArrayCopy: - statement("// Implementation of an array copy function to cover GLSL's ability to copy an array via " - "assignment."); - statement("template"); - statement("void spvArrayCopyFromStack1(thread T (&dst)[N], thread const T (&src)[N])"); - begin_scope(); - statement("for (uint i = 0; i < N; dst[i] = src[i], i++);"); - end_scope(); - statement(""); - - statement("template"); - statement("void spvArrayCopyFromConstant1(thread T (&dst)[N], constant T (&src)[N])"); - begin_scope(); - statement("for (uint i = 0; i < N; dst[i] = src[i], i++);"); - end_scope(); - statement(""); - break; - case SPVFuncImplArrayOfArrayCopy2Dim: case SPVFuncImplArrayOfArrayCopy3Dim: case SPVFuncImplArrayOfArrayCopy4Dim: case SPVFuncImplArrayOfArrayCopy5Dim: case SPVFuncImplArrayOfArrayCopy6Dim: { + // Unfortunately we cannot template on the address space, so combinatorial explosion it is. static const char *function_name_tags[] = { - "FromStack", - "FromConstant", + "FromConstantToStack", "FromConstantToThreadGroup", "FromStackToStack", + "FromStackToThreadGroup", "FromThreadGroupToStack", "FromThreadGroupToThreadGroup", }; static const char *src_address_space[] = { - "thread const", - "constant", + "constant", "constant", "thread const", "thread const", "threadgroup const", "threadgroup const", }; - for (uint32_t variant = 0; variant < 2; variant++) + static const char *dst_address_space[] = { + "thread", "threadgroup", "thread", "threadgroup", "thread", "threadgroup", + }; + + for (uint32_t variant = 0; variant < 6; variant++) { uint32_t dimensions = spv_func - SPVFuncImplArrayCopyMultidimBase; string tmp = "template 0) + { + string tex_width_str = convert_to_string(msl_options.texel_buffer_texture_width); + statement("// Returns 2D texture coords corresponding to 1D texel buffer coords"); + statement(force_inline); + statement("uint2 spvTexelBufferCoord(uint tc)"); + begin_scope(); + statement(join("return uint2(tc % ", tex_width_str, ", tc / ", tex_width_str, ");")); + end_scope(); + statement(""); + } + else + { + statement("// Returns 2D texture coords corresponding to 1D texel buffer coords"); + statement( + "#define spvTexelBufferCoord(tc, tex) uint2((tc) % (tex).get_width(), (tc) / (tex).get_width())"); + statement(""); + } + break; + } + + // Emulate texture2D atomic operations + case SPVFuncImplImage2DAtomicCoords: + { + statement("// Returns buffer coords corresponding to 2D texture coords for emulating 2D texture atomics"); + statement("#define spvImage2DAtomicCoord(tc, tex) (((tex).get_width() * (tc).x) + (tc).y)"); statement(""); break; } + // "fadd" intrinsic support + case SPVFuncImplFAdd: + statement("template"); + statement("T spvFAdd(T l, T r)"); + begin_scope(); + statement("return fma(T(1), l, r);"); + end_scope(); + statement(""); + break; + + // "fmul' intrinsic support + case SPVFuncImplFMul: + statement("template"); + statement("T spvFMul(T l, T r)"); + begin_scope(); + statement("return fma(l, r, T(0));"); + end_scope(); + statement(""); + + statement("template"); + statement("vec spvFMulVectorMatrix(vec v, matrix m)"); + begin_scope(); + statement("vec res = vec(0);"); + statement("for (uint i = Rows; i > 0; --i)"); + begin_scope(); + statement("vec tmp(0);"); + statement("for (uint j = 0; j < Cols; ++j)"); + begin_scope(); + statement("tmp[j] = m[j][i - 1];"); + end_scope(); + statement("res = fma(tmp, vec(v[i - 1]), res);"); + end_scope(); + statement("return res;"); + end_scope(); + statement(""); + + statement("template"); + statement("vec spvFMulMatrixVector(matrix m, vec v)"); + begin_scope(); + statement("vec res = vec(0);"); + statement("for (uint i = Cols; i > 0; --i)"); + begin_scope(); + statement("res = fma(m[i - 1], vec(v[i - 1]), res);"); + end_scope(); + statement("return res;"); + end_scope(); + statement(""); + + statement("template"); + statement( + "matrix spvFMulMatrixMatrix(matrix l, matrix r)"); + begin_scope(); + statement("matrix res;"); + statement("for (uint i = 0; i < RCols; i++)"); + begin_scope(); + statement("vec tmp(0);"); + statement("for (uint j = 0; j < LCols; j++)"); + begin_scope(); + statement("tmp = fma(vec(r[i][j]), l[j], tmp);"); + end_scope(); + statement("res[i] = tmp;"); + end_scope(); + statement("return res;"); + end_scope(); + statement(""); + break; + + // Emulate texturecube_array with texture2d_array for iOS where this type is not available + case SPVFuncImplCubemapTo2DArrayFace: + statement(force_inline); + statement("float3 spvCubemapTo2DArrayFace(float3 P)"); + begin_scope(); + statement("float3 Coords = abs(P.xyz);"); + statement("float CubeFace = 0;"); + statement("float ProjectionAxis = 0;"); + statement("float u = 0;"); + statement("float v = 0;"); + statement("if (Coords.x >= Coords.y && Coords.x >= Coords.z)"); + begin_scope(); + statement("CubeFace = P.x >= 0 ? 0 : 1;"); + statement("ProjectionAxis = Coords.x;"); + statement("u = P.x >= 0 ? -P.z : P.z;"); + statement("v = -P.y;"); + end_scope(); + statement("else if (Coords.y >= Coords.x && Coords.y >= Coords.z)"); + begin_scope(); + statement("CubeFace = P.y >= 0 ? 2 : 3;"); + statement("ProjectionAxis = Coords.y;"); + statement("u = P.x;"); + statement("v = P.y >= 0 ? P.z : -P.z;"); + end_scope(); + statement("else"); + begin_scope(); + statement("CubeFace = P.z >= 0 ? 4 : 5;"); + statement("ProjectionAxis = Coords.z;"); + statement("u = P.z >= 0 ? P.x : -P.x;"); + statement("v = -P.y;"); + end_scope(); + statement("u = 0.5 * (u/ProjectionAxis + 1);"); + statement("v = 0.5 * (v/ProjectionAxis + 1);"); + statement("return float3(u, v, CubeFace);"); + end_scope(); + statement(""); + break; + case SPVFuncImplInverse4x4: statement("// Returns the determinant of a 2x2 matrix."); - statement("inline float spvDet2x2(float a1, float a2, float b1, float b2)"); + statement(force_inline); + statement("float spvDet2x2(float a1, float a2, float b1, float b2)"); begin_scope(); statement("return a1 * b2 - b1 * a2;"); end_scope(); statement(""); statement("// Returns the determinant of a 3x3 matrix."); - statement("inline float spvDet3x3(float a1, float a2, float a3, float b1, float b2, float b3, float c1, " + statement(force_inline); + statement("float spvDet3x3(float a1, float a2, float a3, float b1, float b2, float b3, float c1, " "float c2, float c3)"); begin_scope(); statement("return a1 * spvDet2x2(b2, b3, c2, c3) - b1 * spvDet2x2(a2, a3, c2, c3) + c1 * spvDet2x2(a2, a3, " @@ -3233,6 +3918,7 @@ void CompilerMSL::emit_custom_functions() statement(""); statement("// Returns the inverse of a matrix, by using the algorithm of calculating the classical"); statement("// adjoint and dividing by the determinant. The contents of the matrix are changed."); + statement(force_inline); statement("float4x4 spvInverse4x4(float4x4 m)"); begin_scope(); statement("float4x4 adj; // The adjoint matrix (inverse after dividing by determinant)"); @@ -3289,7 +3975,8 @@ void CompilerMSL::emit_custom_functions() if (spv_function_implementations.count(SPVFuncImplInverse4x4) == 0) { statement("// Returns the determinant of a 2x2 matrix."); - statement("inline float spvDet2x2(float a1, float a2, float b1, float b2)"); + statement(force_inline); + statement("float spvDet2x2(float a1, float a2, float b1, float b2)"); begin_scope(); statement("return a1 * b2 - b1 * a2;"); end_scope(); @@ -3298,6 +3985,7 @@ void CompilerMSL::emit_custom_functions() statement("// Returns the inverse of a matrix, by using the algorithm of calculating the classical"); statement("// adjoint and dividing by the determinant. The contents of the matrix are changed."); + statement(force_inline); statement("float3x3 spvInverse3x3(float3x3 m)"); begin_scope(); statement("float3x3 adj; // The adjoint matrix (inverse after dividing by determinant)"); @@ -3328,6 +4016,7 @@ void CompilerMSL::emit_custom_functions() case SPVFuncImplInverse2x2: statement("// Returns the inverse of a matrix, by using the algorithm of calculating the classical"); statement("// adjoint and dividing by the determinant. The contents of the matrix are changed."); + statement(force_inline); statement("float2x2 spvInverse2x2(float2x2 m)"); begin_scope(); statement("float2x2 adj; // The adjoint matrix (inverse after dividing by determinant)"); @@ -3349,18 +4038,7 @@ void CompilerMSL::emit_custom_functions() statement(""); break; - case SPVFuncImplTextureSwizzle: - statement("enum class spvSwizzle : uint"); - begin_scope(); - statement("none = 0,"); - statement("zero,"); - statement("one,"); - statement("red,"); - statement("green,"); - statement("blue,"); - statement("alpha"); - end_scope_decl(); - statement(""); + case SPVFuncImplForwardArgs: statement("template struct spvRemoveReference { typedef T type; };"); statement("template struct spvRemoveReference { typedef T type; };"); statement("template struct spvRemoveReference { typedef T type; };"); @@ -3375,6 +4053,20 @@ void CompilerMSL::emit_custom_functions() statement("return static_cast(x);"); end_scope(); statement(""); + break; + + case SPVFuncImplGetSwizzle: + statement("enum class spvSwizzle : uint"); + begin_scope(); + statement("none = 0,"); + statement("zero,"); + statement("one,"); + statement("red,"); + statement("green,"); + statement("blue,"); + statement("alpha"); + end_scope_decl(); + statement(""); statement("template"); statement("inline T spvGetSwizzle(vec x, T c, spvSwizzle s)"); begin_scope(); @@ -3397,6 +4089,9 @@ void CompilerMSL::emit_custom_functions() end_scope(); end_scope(); statement(""); + break; + + case SPVFuncImplTextureSwizzle: statement("// Wrapper function that swizzles texture samples and fetches."); statement("template"); statement("inline vec spvTextureSwizzle(vec x, uint s)"); @@ -3415,11 +4110,14 @@ void CompilerMSL::emit_custom_functions() statement("return spvTextureSwizzle(vec(x, 0, 0, 1), s).x;"); end_scope(); statement(""); + break; + + case SPVFuncImplGatherSwizzle: statement("// Wrapper function that swizzles texture gathers."); - statement("template"); - statement( - "inline vec spvGatherSwizzle(sampler s, const thread Tex& t, Ts... params, component c, uint sw) " - "METAL_CONST_ARG(c)"); + statement("template class Tex, " + "typename... Ts>"); + statement("inline vec spvGatherSwizzle(const thread Tex& t, sampler s, " + "uint sw, component c, Ts... params) METAL_CONST_ARG(c)"); begin_scope(); statement("if (sw)"); begin_scope(); @@ -3456,10 +4154,14 @@ void CompilerMSL::emit_custom_functions() end_scope(); end_scope(); statement(""); + break; + + case SPVFuncImplGatherCompareSwizzle: statement("// Wrapper function that swizzles depth texture gathers."); - statement("template"); - statement( - "inline vec spvGatherCompareSwizzle(sampler s, const thread Tex& t, Ts... params, uint sw) "); + statement("template class Tex, " + "typename... Ts>"); + statement("inline vec spvGatherCompareSwizzle(const thread Tex& t, sampler " + "s, uint sw, Ts... params) "); begin_scope(); statement("if (sw)"); begin_scope(); @@ -3605,6 +4307,704 @@ void CompilerMSL::emit_custom_functions() statement(""); break; + case SPVFuncImplChromaReconstructNearest2Plane: + statement("template"); + statement("inline vec spvChromaReconstructNearest(texture2d plane0, texture2d plane1, sampler " + "samp, float2 coord, LodOptions... options)"); + begin_scope(); + statement("vec ycbcr = vec(0, 0, 0, 1);"); + statement("ycbcr.g = plane0.sample(samp, coord, spvForward(options)...).r;"); + statement("ycbcr.br = plane1.sample(samp, coord, spvForward(options)...).rg;"); + statement("return ycbcr;"); + end_scope(); + statement(""); + break; + + case SPVFuncImplChromaReconstructNearest3Plane: + statement("template"); + statement("inline vec spvChromaReconstructNearest(texture2d plane0, texture2d plane1, " + "texture2d plane2, sampler samp, float2 coord, LodOptions... options)"); + begin_scope(); + statement("vec ycbcr = vec(0, 0, 0, 1);"); + statement("ycbcr.g = plane0.sample(samp, coord, spvForward(options)...).r;"); + statement("ycbcr.b = plane1.sample(samp, coord, spvForward(options)...).r;"); + statement("ycbcr.r = plane2.sample(samp, coord, spvForward(options)...).r;"); + statement("return ycbcr;"); + end_scope(); + statement(""); + break; + + case SPVFuncImplChromaReconstructLinear422CositedEven2Plane: + statement("template"); + statement("inline vec spvChromaReconstructLinear422CositedEven(texture2d plane0, texture2d " + "plane1, sampler samp, float2 coord, LodOptions... options)"); + begin_scope(); + statement("vec ycbcr = vec(0, 0, 0, 1);"); + statement("ycbcr.g = plane0.sample(samp, coord, spvForward(options)...).r;"); + statement("if (fract(coord.x * plane1.get_width()) != 0.0)"); + begin_scope(); + statement("ycbcr.br = vec(mix(plane1.sample(samp, coord, spvForward(options)...), " + "plane1.sample(samp, coord, spvForward(options)..., int2(1, 0)), 0.5).rg);"); + end_scope(); + statement("else"); + begin_scope(); + statement("ycbcr.br = plane1.sample(samp, coord, spvForward(options)...).rg;"); + end_scope(); + statement("return ycbcr;"); + end_scope(); + statement(""); + break; + + case SPVFuncImplChromaReconstructLinear422CositedEven3Plane: + statement("template"); + statement("inline vec spvChromaReconstructLinear422CositedEven(texture2d plane0, texture2d " + "plane1, texture2d plane2, sampler samp, float2 coord, LodOptions... options)"); + begin_scope(); + statement("vec ycbcr = vec(0, 0, 0, 1);"); + statement("ycbcr.g = plane0.sample(samp, coord, spvForward(options)...).r;"); + statement("if (fract(coord.x * plane1.get_width()) != 0.0)"); + begin_scope(); + statement("ycbcr.b = T(mix(plane1.sample(samp, coord, spvForward(options)...), " + "plane1.sample(samp, coord, spvForward(options)..., int2(1, 0)), 0.5).r);"); + statement("ycbcr.r = T(mix(plane2.sample(samp, coord, spvForward(options)...), " + "plane2.sample(samp, coord, spvForward(options)..., int2(1, 0)), 0.5).r);"); + end_scope(); + statement("else"); + begin_scope(); + statement("ycbcr.b = plane1.sample(samp, coord, spvForward(options)...).r;"); + statement("ycbcr.r = plane2.sample(samp, coord, spvForward(options)...).r;"); + end_scope(); + statement("return ycbcr;"); + end_scope(); + statement(""); + break; + + case SPVFuncImplChromaReconstructLinear422Midpoint2Plane: + statement("template"); + statement("inline vec spvChromaReconstructLinear422Midpoint(texture2d plane0, texture2d " + "plane1, sampler samp, float2 coord, LodOptions... options)"); + begin_scope(); + statement("vec ycbcr = vec(0, 0, 0, 1);"); + statement("ycbcr.g = plane0.sample(samp, coord, spvForward(options)...).r;"); + statement("int2 offs = int2(fract(coord.x * plane1.get_width()) != 0.0 ? 1 : -1, 0);"); + statement("ycbcr.br = vec(mix(plane1.sample(samp, coord, spvForward(options)...), " + "plane1.sample(samp, coord, spvForward(options)..., offs), 0.25).rg);"); + statement("return ycbcr;"); + end_scope(); + statement(""); + break; + + case SPVFuncImplChromaReconstructLinear422Midpoint3Plane: + statement("template"); + statement("inline vec spvChromaReconstructLinear422Midpoint(texture2d plane0, texture2d " + "plane1, texture2d plane2, sampler samp, float2 coord, LodOptions... options)"); + begin_scope(); + statement("vec ycbcr = vec(0, 0, 0, 1);"); + statement("ycbcr.g = plane0.sample(samp, coord, spvForward(options)...).r;"); + statement("int2 offs = int2(fract(coord.x * plane1.get_width()) != 0.0 ? 1 : -1, 0);"); + statement("ycbcr.b = T(mix(plane1.sample(samp, coord, spvForward(options)...), " + "plane1.sample(samp, coord, spvForward(options)..., offs), 0.25).r);"); + statement("ycbcr.r = T(mix(plane2.sample(samp, coord, spvForward(options)...), " + "plane2.sample(samp, coord, spvForward(options)..., offs), 0.25).r);"); + statement("return ycbcr;"); + end_scope(); + statement(""); + break; + + case SPVFuncImplChromaReconstructLinear420XCositedEvenYCositedEven2Plane: + statement("template"); + statement("inline vec spvChromaReconstructLinear420XCositedEvenYCositedEven(texture2d plane0, " + "texture2d plane1, sampler samp, float2 coord, LodOptions... options)"); + begin_scope(); + statement("vec ycbcr = vec(0, 0, 0, 1);"); + statement("ycbcr.g = plane0.sample(samp, coord, spvForward(options)...).r;"); + statement("float2 ab = fract(round(coord * float2(plane0.get_width(), plane0.get_height())) * 0.5);"); + statement("ycbcr.br = vec(mix(mix(plane1.sample(samp, coord, spvForward(options)...), " + "plane1.sample(samp, coord, spvForward(options)..., int2(1, 0)), ab.x), " + "mix(plane1.sample(samp, coord, spvForward(options)..., int2(0, 1)), " + "plane1.sample(samp, coord, spvForward(options)..., int2(1, 1)), ab.x), ab.y).rg);"); + statement("return ycbcr;"); + end_scope(); + statement(""); + break; + + case SPVFuncImplChromaReconstructLinear420XCositedEvenYCositedEven3Plane: + statement("template"); + statement("inline vec spvChromaReconstructLinear420XCositedEvenYCositedEven(texture2d plane0, " + "texture2d plane1, texture2d plane2, sampler samp, float2 coord, LodOptions... options)"); + begin_scope(); + statement("vec ycbcr = vec(0, 0, 0, 1);"); + statement("ycbcr.g = plane0.sample(samp, coord, spvForward(options)...).r;"); + statement("float2 ab = fract(round(coord * float2(plane0.get_width(), plane0.get_height())) * 0.5);"); + statement("ycbcr.b = T(mix(mix(plane1.sample(samp, coord, spvForward(options)...), " + "plane1.sample(samp, coord, spvForward(options)..., int2(1, 0)), ab.x), " + "mix(plane1.sample(samp, coord, spvForward(options)..., int2(0, 1)), " + "plane1.sample(samp, coord, spvForward(options)..., int2(1, 1)), ab.x), ab.y).r);"); + statement("ycbcr.r = T(mix(mix(plane2.sample(samp, coord, spvForward(options)...), " + "plane2.sample(samp, coord, spvForward(options)..., int2(1, 0)), ab.x), " + "mix(plane2.sample(samp, coord, spvForward(options)..., int2(0, 1)), " + "plane2.sample(samp, coord, spvForward(options)..., int2(1, 1)), ab.x), ab.y).r);"); + statement("return ycbcr;"); + end_scope(); + statement(""); + break; + + case SPVFuncImplChromaReconstructLinear420XMidpointYCositedEven2Plane: + statement("template"); + statement("inline vec spvChromaReconstructLinear420XMidpointYCositedEven(texture2d plane0, " + "texture2d plane1, sampler samp, float2 coord, LodOptions... options)"); + begin_scope(); + statement("vec ycbcr = vec(0, 0, 0, 1);"); + statement("ycbcr.g = plane0.sample(samp, coord, spvForward(options)...).r;"); + statement("float2 ab = fract((round(coord * float2(plane0.get_width(), plane0.get_height())) - float2(0.5, " + "0)) * 0.5);"); + statement("ycbcr.br = vec(mix(mix(plane1.sample(samp, coord, spvForward(options)...), " + "plane1.sample(samp, coord, spvForward(options)..., int2(1, 0)), ab.x), " + "mix(plane1.sample(samp, coord, spvForward(options)..., int2(0, 1)), " + "plane1.sample(samp, coord, spvForward(options)..., int2(1, 1)), ab.x), ab.y).rg);"); + statement("return ycbcr;"); + end_scope(); + statement(""); + break; + + case SPVFuncImplChromaReconstructLinear420XMidpointYCositedEven3Plane: + statement("template"); + statement("inline vec spvChromaReconstructLinear420XMidpointYCositedEven(texture2d plane0, " + "texture2d plane1, texture2d plane2, sampler samp, float2 coord, LodOptions... options)"); + begin_scope(); + statement("vec ycbcr = vec(0, 0, 0, 1);"); + statement("ycbcr.g = plane0.sample(samp, coord, spvForward(options)...).r;"); + statement("float2 ab = fract((round(coord * float2(plane0.get_width(), plane0.get_height())) - float2(0.5, " + "0)) * 0.5);"); + statement("ycbcr.b = T(mix(mix(plane1.sample(samp, coord, spvForward(options)...), " + "plane1.sample(samp, coord, spvForward(options)..., int2(1, 0)), ab.x), " + "mix(plane1.sample(samp, coord, spvForward(options)..., int2(0, 1)), " + "plane1.sample(samp, coord, spvForward(options)..., int2(1, 1)), ab.x), ab.y).r);"); + statement("ycbcr.r = T(mix(mix(plane2.sample(samp, coord, spvForward(options)...), " + "plane2.sample(samp, coord, spvForward(options)..., int2(1, 0)), ab.x), " + "mix(plane2.sample(samp, coord, spvForward(options)..., int2(0, 1)), " + "plane2.sample(samp, coord, spvForward(options)..., int2(1, 1)), ab.x), ab.y).r);"); + statement("return ycbcr;"); + end_scope(); + statement(""); + break; + + case SPVFuncImplChromaReconstructLinear420XCositedEvenYMidpoint2Plane: + statement("template"); + statement("inline vec spvChromaReconstructLinear420XCositedEvenYMidpoint(texture2d plane0, " + "texture2d plane1, sampler samp, float2 coord, LodOptions... options)"); + begin_scope(); + statement("vec ycbcr = vec(0, 0, 0, 1);"); + statement("ycbcr.g = plane0.sample(samp, coord, spvForward(options)...).r;"); + statement("float2 ab = fract((round(coord * float2(plane0.get_width(), plane0.get_height())) - float2(0, " + "0.5)) * 0.5);"); + statement("ycbcr.br = vec(mix(mix(plane1.sample(samp, coord, spvForward(options)...), " + "plane1.sample(samp, coord, spvForward(options)..., int2(1, 0)), ab.x), " + "mix(plane1.sample(samp, coord, spvForward(options)..., int2(0, 1)), " + "plane1.sample(samp, coord, spvForward(options)..., int2(1, 1)), ab.x), ab.y).rg);"); + statement("return ycbcr;"); + end_scope(); + statement(""); + break; + + case SPVFuncImplChromaReconstructLinear420XCositedEvenYMidpoint3Plane: + statement("template"); + statement("inline vec spvChromaReconstructLinear420XCositedEvenYMidpoint(texture2d plane0, " + "texture2d plane1, texture2d plane2, sampler samp, float2 coord, LodOptions... options)"); + begin_scope(); + statement("vec ycbcr = vec(0, 0, 0, 1);"); + statement("ycbcr.g = plane0.sample(samp, coord, spvForward(options)...).r;"); + statement("float2 ab = fract((round(coord * float2(plane0.get_width(), plane0.get_height())) - float2(0, " + "0.5)) * 0.5);"); + statement("ycbcr.b = T(mix(mix(plane1.sample(samp, coord, spvForward(options)...), " + "plane1.sample(samp, coord, spvForward(options)..., int2(1, 0)), ab.x), " + "mix(plane1.sample(samp, coord, spvForward(options)..., int2(0, 1)), " + "plane1.sample(samp, coord, spvForward(options)..., int2(1, 1)), ab.x), ab.y).r);"); + statement("ycbcr.r = T(mix(mix(plane2.sample(samp, coord, spvForward(options)...), " + "plane2.sample(samp, coord, spvForward(options)..., int2(1, 0)), ab.x), " + "mix(plane2.sample(samp, coord, spvForward(options)..., int2(0, 1)), " + "plane2.sample(samp, coord, spvForward(options)..., int2(1, 1)), ab.x), ab.y).r);"); + statement("return ycbcr;"); + end_scope(); + statement(""); + break; + + case SPVFuncImplChromaReconstructLinear420XMidpointYMidpoint2Plane: + statement("template"); + statement("inline vec spvChromaReconstructLinear420XMidpointYMidpoint(texture2d plane0, " + "texture2d plane1, sampler samp, float2 coord, LodOptions... options)"); + begin_scope(); + statement("vec ycbcr = vec(0, 0, 0, 1);"); + statement("ycbcr.g = plane0.sample(samp, coord, spvForward(options)...).r;"); + statement("float2 ab = fract((round(coord * float2(plane0.get_width(), plane0.get_height())) - float2(0.5, " + "0.5)) * 0.5);"); + statement("ycbcr.br = vec(mix(mix(plane1.sample(samp, coord, spvForward(options)...), " + "plane1.sample(samp, coord, spvForward(options)..., int2(1, 0)), ab.x), " + "mix(plane1.sample(samp, coord, spvForward(options)..., int2(0, 1)), " + "plane1.sample(samp, coord, spvForward(options)..., int2(1, 1)), ab.x), ab.y).rg);"); + statement("return ycbcr;"); + end_scope(); + statement(""); + break; + + case SPVFuncImplChromaReconstructLinear420XMidpointYMidpoint3Plane: + statement("template"); + statement("inline vec spvChromaReconstructLinear420XMidpointYMidpoint(texture2d plane0, " + "texture2d plane1, texture2d plane2, sampler samp, float2 coord, LodOptions... options)"); + begin_scope(); + statement("vec ycbcr = vec(0, 0, 0, 1);"); + statement("ycbcr.g = plane0.sample(samp, coord, spvForward(options)...).r;"); + statement("float2 ab = fract((round(coord * float2(plane0.get_width(), plane0.get_height())) - float2(0.5, " + "0.5)) * 0.5);"); + statement("ycbcr.b = T(mix(mix(plane1.sample(samp, coord, spvForward(options)...), " + "plane1.sample(samp, coord, spvForward(options)..., int2(1, 0)), ab.x), " + "mix(plane1.sample(samp, coord, spvForward(options)..., int2(0, 1)), " + "plane1.sample(samp, coord, spvForward(options)..., int2(1, 1)), ab.x), ab.y).r);"); + statement("ycbcr.r = T(mix(mix(plane2.sample(samp, coord, spvForward(options)...), " + "plane2.sample(samp, coord, spvForward(options)..., int2(1, 0)), ab.x), " + "mix(plane2.sample(samp, coord, spvForward(options)..., int2(0, 1)), " + "plane2.sample(samp, coord, spvForward(options)..., int2(1, 1)), ab.x), ab.y).r);"); + statement("return ycbcr;"); + end_scope(); + statement(""); + break; + + case SPVFuncImplExpandITUFullRange: + statement("template"); + statement("inline vec spvExpandITUFullRange(vec ycbcr, int n)"); + begin_scope(); + statement("ycbcr.br -= exp2(T(n-1))/(exp2(T(n))-1);"); + statement("return ycbcr;"); + end_scope(); + statement(""); + break; + + case SPVFuncImplExpandITUNarrowRange: + statement("template"); + statement("inline vec spvExpandITUNarrowRange(vec ycbcr, int n)"); + begin_scope(); + statement("ycbcr.g = (ycbcr.g * (exp2(T(n)) - 1) - ldexp(T(16), n - 8))/ldexp(T(219), n - 8);"); + statement("ycbcr.br = (ycbcr.br * (exp2(T(n)) - 1) - ldexp(T(128), n - 8))/ldexp(T(224), n - 8);"); + statement("return ycbcr;"); + end_scope(); + statement(""); + break; + + case SPVFuncImplConvertYCbCrBT709: + statement("// cf. Khronos Data Format Specification, section 15.1.1"); + statement("constant float3x3 spvBT709Factors = {{1, 1, 1}, {0, -0.13397432/0.7152, 1.8556}, {1.5748, " + "-0.33480248/0.7152, 0}};"); + statement(""); + statement("template"); + statement("inline vec spvConvertYCbCrBT709(vec ycbcr)"); + begin_scope(); + statement("vec rgba;"); + statement("rgba.rgb = vec(spvBT709Factors * ycbcr.gbr);"); + statement("rgba.a = ycbcr.a;"); + statement("return rgba;"); + end_scope(); + statement(""); + break; + + case SPVFuncImplConvertYCbCrBT601: + statement("// cf. Khronos Data Format Specification, section 15.1.2"); + statement("constant float3x3 spvBT601Factors = {{1, 1, 1}, {0, -0.202008/0.587, 1.772}, {1.402, " + "-0.419198/0.587, 0}};"); + statement(""); + statement("template"); + statement("inline vec spvConvertYCbCrBT601(vec ycbcr)"); + begin_scope(); + statement("vec rgba;"); + statement("rgba.rgb = vec(spvBT601Factors * ycbcr.gbr);"); + statement("rgba.a = ycbcr.a;"); + statement("return rgba;"); + end_scope(); + statement(""); + break; + + case SPVFuncImplConvertYCbCrBT2020: + statement("// cf. Khronos Data Format Specification, section 15.1.3"); + statement("constant float3x3 spvBT2020Factors = {{1, 1, 1}, {0, -0.11156702/0.6780, 1.8814}, {1.4746, " + "-0.38737742/0.6780, 0}};"); + statement(""); + statement("template"); + statement("inline vec spvConvertYCbCrBT2020(vec ycbcr)"); + begin_scope(); + statement("vec rgba;"); + statement("rgba.rgb = vec(spvBT2020Factors * ycbcr.gbr);"); + statement("rgba.a = ycbcr.a;"); + statement("return rgba;"); + end_scope(); + statement(""); + break; + + case SPVFuncImplDynamicImageSampler: + statement("enum class spvFormatResolution"); + begin_scope(); + statement("_444 = 0,"); + statement("_422,"); + statement("_420"); + end_scope_decl(); + statement(""); + statement("enum class spvChromaFilter"); + begin_scope(); + statement("nearest = 0,"); + statement("linear"); + end_scope_decl(); + statement(""); + statement("enum class spvXChromaLocation"); + begin_scope(); + statement("cosited_even = 0,"); + statement("midpoint"); + end_scope_decl(); + statement(""); + statement("enum class spvYChromaLocation"); + begin_scope(); + statement("cosited_even = 0,"); + statement("midpoint"); + end_scope_decl(); + statement(""); + statement("enum class spvYCbCrModelConversion"); + begin_scope(); + statement("rgb_identity = 0,"); + statement("ycbcr_identity,"); + statement("ycbcr_bt_709,"); + statement("ycbcr_bt_601,"); + statement("ycbcr_bt_2020"); + end_scope_decl(); + statement(""); + statement("enum class spvYCbCrRange"); + begin_scope(); + statement("itu_full = 0,"); + statement("itu_narrow"); + end_scope_decl(); + statement(""); + statement("struct spvComponentBits"); + begin_scope(); + statement("constexpr explicit spvComponentBits(int v) thread : value(v) {}"); + statement("uchar value : 6;"); + end_scope_decl(); + statement("// A class corresponding to metal::sampler which holds sampler"); + statement("// Y'CbCr conversion info."); + statement("struct spvYCbCrSampler"); + begin_scope(); + statement("constexpr spvYCbCrSampler() thread : val(build()) {}"); + statement("template"); + statement("constexpr spvYCbCrSampler(Ts... t) thread : val(build(t...)) {}"); + statement("constexpr spvYCbCrSampler(const thread spvYCbCrSampler& s) thread = default;"); + statement(""); + statement("spvFormatResolution get_resolution() const thread"); + begin_scope(); + statement("return spvFormatResolution((val & resolution_mask) >> resolution_base);"); + end_scope(); + statement("spvChromaFilter get_chroma_filter() const thread"); + begin_scope(); + statement("return spvChromaFilter((val & chroma_filter_mask) >> chroma_filter_base);"); + end_scope(); + statement("spvXChromaLocation get_x_chroma_offset() const thread"); + begin_scope(); + statement("return spvXChromaLocation((val & x_chroma_off_mask) >> x_chroma_off_base);"); + end_scope(); + statement("spvYChromaLocation get_y_chroma_offset() const thread"); + begin_scope(); + statement("return spvYChromaLocation((val & y_chroma_off_mask) >> y_chroma_off_base);"); + end_scope(); + statement("spvYCbCrModelConversion get_ycbcr_model() const thread"); + begin_scope(); + statement("return spvYCbCrModelConversion((val & ycbcr_model_mask) >> ycbcr_model_base);"); + end_scope(); + statement("spvYCbCrRange get_ycbcr_range() const thread"); + begin_scope(); + statement("return spvYCbCrRange((val & ycbcr_range_mask) >> ycbcr_range_base);"); + end_scope(); + statement("int get_bpc() const thread { return (val & bpc_mask) >> bpc_base; }"); + statement(""); + statement("private:"); + statement("ushort val;"); + statement(""); + statement("constexpr static constant ushort resolution_bits = 2;"); + statement("constexpr static constant ushort chroma_filter_bits = 2;"); + statement("constexpr static constant ushort x_chroma_off_bit = 1;"); + statement("constexpr static constant ushort y_chroma_off_bit = 1;"); + statement("constexpr static constant ushort ycbcr_model_bits = 3;"); + statement("constexpr static constant ushort ycbcr_range_bit = 1;"); + statement("constexpr static constant ushort bpc_bits = 6;"); + statement(""); + statement("constexpr static constant ushort resolution_base = 0;"); + statement("constexpr static constant ushort chroma_filter_base = 2;"); + statement("constexpr static constant ushort x_chroma_off_base = 4;"); + statement("constexpr static constant ushort y_chroma_off_base = 5;"); + statement("constexpr static constant ushort ycbcr_model_base = 6;"); + statement("constexpr static constant ushort ycbcr_range_base = 9;"); + statement("constexpr static constant ushort bpc_base = 10;"); + statement(""); + statement( + "constexpr static constant ushort resolution_mask = ((1 << resolution_bits) - 1) << resolution_base;"); + statement("constexpr static constant ushort chroma_filter_mask = ((1 << chroma_filter_bits) - 1) << " + "chroma_filter_base;"); + statement("constexpr static constant ushort x_chroma_off_mask = ((1 << x_chroma_off_bit) - 1) << " + "x_chroma_off_base;"); + statement("constexpr static constant ushort y_chroma_off_mask = ((1 << y_chroma_off_bit) - 1) << " + "y_chroma_off_base;"); + statement("constexpr static constant ushort ycbcr_model_mask = ((1 << ycbcr_model_bits) - 1) << " + "ycbcr_model_base;"); + statement("constexpr static constant ushort ycbcr_range_mask = ((1 << ycbcr_range_bit) - 1) << " + "ycbcr_range_base;"); + statement("constexpr static constant ushort bpc_mask = ((1 << bpc_bits) - 1) << bpc_base;"); + statement(""); + statement("static constexpr ushort build()"); + begin_scope(); + statement("return 0;"); + end_scope(); + statement(""); + statement("template"); + statement("static constexpr ushort build(spvFormatResolution res, Ts... t)"); + begin_scope(); + statement("return (ushort(res) << resolution_base) | (build(t...) & ~resolution_mask);"); + end_scope(); + statement(""); + statement("template"); + statement("static constexpr ushort build(spvChromaFilter filt, Ts... t)"); + begin_scope(); + statement("return (ushort(filt) << chroma_filter_base) | (build(t...) & ~chroma_filter_mask);"); + end_scope(); + statement(""); + statement("template"); + statement("static constexpr ushort build(spvXChromaLocation loc, Ts... t)"); + begin_scope(); + statement("return (ushort(loc) << x_chroma_off_base) | (build(t...) & ~x_chroma_off_mask);"); + end_scope(); + statement(""); + statement("template"); + statement("static constexpr ushort build(spvYChromaLocation loc, Ts... t)"); + begin_scope(); + statement("return (ushort(loc) << y_chroma_off_base) | (build(t...) & ~y_chroma_off_mask);"); + end_scope(); + statement(""); + statement("template"); + statement("static constexpr ushort build(spvYCbCrModelConversion model, Ts... t)"); + begin_scope(); + statement("return (ushort(model) << ycbcr_model_base) | (build(t...) & ~ycbcr_model_mask);"); + end_scope(); + statement(""); + statement("template"); + statement("static constexpr ushort build(spvYCbCrRange range, Ts... t)"); + begin_scope(); + statement("return (ushort(range) << ycbcr_range_base) | (build(t...) & ~ycbcr_range_mask);"); + end_scope(); + statement(""); + statement("template"); + statement("static constexpr ushort build(spvComponentBits bpc, Ts... t)"); + begin_scope(); + statement("return (ushort(bpc.value) << bpc_base) | (build(t...) & ~bpc_mask);"); + end_scope(); + end_scope_decl(); + statement(""); + statement("// A class which can hold up to three textures and a sampler, including"); + statement("// Y'CbCr conversion info, used to pass combined image-samplers"); + statement("// dynamically to functions."); + statement("template"); + statement("struct spvDynamicImageSampler"); + begin_scope(); + statement("texture2d plane0;"); + statement("texture2d plane1;"); + statement("texture2d plane2;"); + statement("sampler samp;"); + statement("spvYCbCrSampler ycbcr_samp;"); + statement("uint swizzle = 0;"); + statement(""); + if (msl_options.swizzle_texture_samples) + { + statement("constexpr spvDynamicImageSampler(texture2d tex, sampler samp, uint sw) thread :"); + statement(" plane0(tex), samp(samp), swizzle(sw) {}"); + } + else + { + statement("constexpr spvDynamicImageSampler(texture2d tex, sampler samp) thread :"); + statement(" plane0(tex), samp(samp) {}"); + } + statement("constexpr spvDynamicImageSampler(texture2d tex, sampler samp, spvYCbCrSampler ycbcr_samp, " + "uint sw) thread :"); + statement(" plane0(tex), samp(samp), ycbcr_samp(ycbcr_samp), swizzle(sw) {}"); + statement("constexpr spvDynamicImageSampler(texture2d plane0, texture2d plane1,"); + statement(" sampler samp, spvYCbCrSampler ycbcr_samp, uint sw) thread :"); + statement(" plane0(plane0), plane1(plane1), samp(samp), ycbcr_samp(ycbcr_samp), swizzle(sw) {}"); + statement( + "constexpr spvDynamicImageSampler(texture2d plane0, texture2d plane1, texture2d plane2,"); + statement(" sampler samp, spvYCbCrSampler ycbcr_samp, uint sw) thread :"); + statement(" plane0(plane0), plane1(plane1), plane2(plane2), samp(samp), ycbcr_samp(ycbcr_samp), " + "swizzle(sw) {}"); + statement(""); + // XXX This is really hard to follow... I've left comments to make it a bit easier. + statement("template"); + statement("vec do_sample(float2 coord, LodOptions... options) const thread"); + begin_scope(); + statement("if (!is_null_texture(plane1))"); + begin_scope(); + statement("if (ycbcr_samp.get_resolution() == spvFormatResolution::_444 ||"); + statement(" ycbcr_samp.get_chroma_filter() == spvChromaFilter::nearest)"); + begin_scope(); + statement("if (!is_null_texture(plane2))"); + statement(" return spvChromaReconstructNearest(plane0, plane1, plane2, samp, coord,"); + statement(" spvForward(options)...);"); + statement( + "return spvChromaReconstructNearest(plane0, plane1, samp, coord, spvForward(options)...);"); + end_scope(); // if (resolution == 422 || chroma_filter == nearest) + statement("switch (ycbcr_samp.get_resolution())"); + begin_scope(); + statement("case spvFormatResolution::_444: break;"); + statement("case spvFormatResolution::_422:"); + begin_scope(); + statement("switch (ycbcr_samp.get_x_chroma_offset())"); + begin_scope(); + statement("case spvXChromaLocation::cosited_even:"); + statement(" if (!is_null_texture(plane2))"); + statement(" return spvChromaReconstructLinear422CositedEven("); + statement(" plane0, plane1, plane2, samp,"); + statement(" coord, spvForward(options)...);"); + statement(" return spvChromaReconstructLinear422CositedEven("); + statement(" plane0, plane1, samp, coord,"); + statement(" spvForward(options)...);"); + statement("case spvXChromaLocation::midpoint:"); + statement(" if (!is_null_texture(plane2))"); + statement(" return spvChromaReconstructLinear422Midpoint("); + statement(" plane0, plane1, plane2, samp,"); + statement(" coord, spvForward(options)...);"); + statement(" return spvChromaReconstructLinear422Midpoint("); + statement(" plane0, plane1, samp, coord,"); + statement(" spvForward(options)...);"); + end_scope(); // switch (x_chroma_offset) + end_scope(); // case 422: + statement("case spvFormatResolution::_420:"); + begin_scope(); + statement("switch (ycbcr_samp.get_x_chroma_offset())"); + begin_scope(); + statement("case spvXChromaLocation::cosited_even:"); + begin_scope(); + statement("switch (ycbcr_samp.get_y_chroma_offset())"); + begin_scope(); + statement("case spvYChromaLocation::cosited_even:"); + statement(" if (!is_null_texture(plane2))"); + statement(" return spvChromaReconstructLinear420XCositedEvenYCositedEven("); + statement(" plane0, plane1, plane2, samp,"); + statement(" coord, spvForward(options)...);"); + statement(" return spvChromaReconstructLinear420XCositedEvenYCositedEven("); + statement(" plane0, plane1, samp, coord,"); + statement(" spvForward(options)...);"); + statement("case spvYChromaLocation::midpoint:"); + statement(" if (!is_null_texture(plane2))"); + statement(" return spvChromaReconstructLinear420XCositedEvenYMidpoint("); + statement(" plane0, plane1, plane2, samp,"); + statement(" coord, spvForward(options)...);"); + statement(" return spvChromaReconstructLinear420XCositedEvenYMidpoint("); + statement(" plane0, plane1, samp, coord,"); + statement(" spvForward(options)...);"); + end_scope(); // switch (y_chroma_offset) + end_scope(); // case x::cosited_even: + statement("case spvXChromaLocation::midpoint:"); + begin_scope(); + statement("switch (ycbcr_samp.get_y_chroma_offset())"); + begin_scope(); + statement("case spvYChromaLocation::cosited_even:"); + statement(" if (!is_null_texture(plane2))"); + statement(" return spvChromaReconstructLinear420XMidpointYCositedEven("); + statement(" plane0, plane1, plane2, samp,"); + statement(" coord, spvForward(options)...);"); + statement(" return spvChromaReconstructLinear420XMidpointYCositedEven("); + statement(" plane0, plane1, samp, coord,"); + statement(" spvForward(options)...);"); + statement("case spvYChromaLocation::midpoint:"); + statement(" if (!is_null_texture(plane2))"); + statement(" return spvChromaReconstructLinear420XMidpointYMidpoint("); + statement(" plane0, plane1, plane2, samp,"); + statement(" coord, spvForward(options)...);"); + statement(" return spvChromaReconstructLinear420XMidpointYMidpoint("); + statement(" plane0, plane1, samp, coord,"); + statement(" spvForward(options)...);"); + end_scope(); // switch (y_chroma_offset) + end_scope(); // case x::midpoint + end_scope(); // switch (x_chroma_offset) + end_scope(); // case 420: + end_scope(); // switch (resolution) + end_scope(); // if (multiplanar) + statement("return plane0.sample(samp, coord, spvForward(options)...);"); + end_scope(); // do_sample() + statement("template "); + statement("vec sample(float2 coord, LodOptions... options) const thread"); + begin_scope(); + statement( + "vec s = spvTextureSwizzle(do_sample(coord, spvForward(options)...), swizzle);"); + statement("if (ycbcr_samp.get_ycbcr_model() == spvYCbCrModelConversion::rgb_identity)"); + statement(" return s;"); + statement(""); + statement("switch (ycbcr_samp.get_ycbcr_range())"); + begin_scope(); + statement("case spvYCbCrRange::itu_full:"); + statement(" s = spvExpandITUFullRange(s, ycbcr_samp.get_bpc());"); + statement(" break;"); + statement("case spvYCbCrRange::itu_narrow:"); + statement(" s = spvExpandITUNarrowRange(s, ycbcr_samp.get_bpc());"); + statement(" break;"); + end_scope(); + statement(""); + statement("switch (ycbcr_samp.get_ycbcr_model())"); + begin_scope(); + statement("case spvYCbCrModelConversion::rgb_identity:"); // Silence Clang warning + statement("case spvYCbCrModelConversion::ycbcr_identity:"); + statement(" return s;"); + statement("case spvYCbCrModelConversion::ycbcr_bt_709:"); + statement(" return spvConvertYCbCrBT709(s);"); + statement("case spvYCbCrModelConversion::ycbcr_bt_601:"); + statement(" return spvConvertYCbCrBT601(s);"); + statement("case spvYCbCrModelConversion::ycbcr_bt_2020:"); + statement(" return spvConvertYCbCrBT2020(s);"); + end_scope(); + end_scope(); + statement(""); + // Sampler Y'CbCr conversion forbids offsets. + statement("vec sample(float2 coord, int2 offset) const thread"); + begin_scope(); + if (msl_options.swizzle_texture_samples) + statement("return spvTextureSwizzle(plane0.sample(samp, coord, offset), swizzle);"); + else + statement("return plane0.sample(samp, coord, offset);"); + end_scope(); + statement("template"); + statement("vec sample(float2 coord, lod_options options, int2 offset) const thread"); + begin_scope(); + if (msl_options.swizzle_texture_samples) + statement("return spvTextureSwizzle(plane0.sample(samp, coord, options, offset), swizzle);"); + else + statement("return plane0.sample(samp, coord, options, offset);"); + end_scope(); + statement("#if __HAVE_MIN_LOD_CLAMP__"); + statement("vec sample(float2 coord, bias b, min_lod_clamp min_lod, int2 offset) const thread"); + begin_scope(); + statement("return plane0.sample(samp, coord, b, min_lod, offset);"); + end_scope(); + statement( + "vec sample(float2 coord, gradient2d grad, min_lod_clamp min_lod, int2 offset) const thread"); + begin_scope(); + statement("return plane0.sample(samp, coord, grad, min_lod, offset);"); + end_scope(); + statement("#endif"); + statement(""); + // Y'CbCr conversion forbids all operations but sampling. + statement("vec read(uint2 coord, uint lod = 0) const thread"); + begin_scope(); + statement("return plane0.read(coord, lod);"); + end_scope(); + statement(""); + statement("vec gather(float2 coord, int2 offset = int2(0), component c = component::x) const thread"); + begin_scope(); + if (msl_options.swizzle_texture_samples) + statement("return spvGatherSwizzle(plane0, samp, swizzle, c, coord, offset);"); + else + statement("return plane0.gather(samp, coord, offset, c);"); + end_scope(); + end_scope_decl(); + statement(""); + default: break; } @@ -3628,6 +5028,8 @@ void CompilerMSL::declare_undefined_values() void CompilerMSL::declare_constant_arrays() { + bool fully_inlined = ir.ids_for_type[TypeFunction].size() == 1; + // MSL cannot declare arrays inline (except when declaring a variable), so we must move them out to // global constants directly, so we are able to use constants as variable expressions. bool emitted = false; @@ -3637,7 +5039,11 @@ void CompilerMSL::declare_constant_arrays() return; auto &type = this->get(c.constant_type); - if (!type.array.empty()) + // Constant arrays of non-primitive types (i.e. matrices) won't link properly into Metal libraries. + // FIXME: However, hoisting constants to main() means we need to pass down constant arrays to leaf functions if they are used there. + // If there are multiple functions in the module, drop this case to avoid breaking use cases which do not need to + // link into Metal libraries. This is hacky. + if (!type.array.empty() && (!fully_inlined || is_scalar(type) || is_vector(type))) { auto name = to_name(c.self); statement("constant ", variable_decl(type, name), " = ", constant_expression(c), ";"); @@ -3649,6 +5055,36 @@ void CompilerMSL::declare_constant_arrays() statement(""); } +// Constant arrays of non-primitive types (i.e. matrices) won't link properly into Metal libraries +void CompilerMSL::declare_complex_constant_arrays() +{ + // If we do not have a fully inlined module, we did not opt in to + // declaring constant arrays of complex types. See CompilerMSL::declare_constant_arrays(). + bool fully_inlined = ir.ids_for_type[TypeFunction].size() == 1; + if (!fully_inlined) + return; + + // MSL cannot declare arrays inline (except when declaring a variable), so we must move them out to + // global constants directly, so we are able to use constants as variable expressions. + bool emitted = false; + + ir.for_each_typed_id([&](uint32_t, SPIRConstant &c) { + if (c.specialization) + return; + + auto &type = this->get(c.constant_type); + if (!type.array.empty() && !(is_scalar(type) || is_vector(type))) + { + auto name = to_name(c.self); + statement("", variable_decl(type, name), " = ", constant_expression(c), ";"); + emitted = true; + } + }); + + if (emitted) + statement(""); +} + void CompilerMSL::emit_resources() { declare_constant_arrays(); @@ -3665,7 +5101,7 @@ void CompilerMSL::emit_resources() void CompilerMSL::emit_specialization_constants_and_structs() { SpecializationConstant wg_x, wg_y, wg_z; - uint32_t workgroup_size_id = get_work_group_size_specialization_constants(wg_x, wg_y, wg_z); + ID workgroup_size_id = get_work_group_size_specialization_constants(wg_x, wg_y, wg_z); bool emitted = false; unordered_set declared_structs; @@ -3759,7 +5195,7 @@ void CompilerMSL::emit_specialization_constants_and_structs() // Output non-builtin interface structs. These include local function structs // and structs nested within uniform and read-write buffers. auto &type = id.get(); - uint32_t type_id = type.self; + TypeID type_id = type.self; bool is_struct = (type.basetype == SPIRType::Struct) && type.array.empty(); bool is_block = @@ -3814,15 +5250,301 @@ void CompilerMSL::emit_binary_unord_op(uint32_t result_type, uint32_t result_id, inherit_expression_dependencies(result_id, op1); } +bool CompilerMSL::emit_tessellation_io_load(uint32_t result_type_id, uint32_t id, uint32_t ptr) +{ + auto &ptr_type = expression_type(ptr); + auto &result_type = get(result_type_id); + if (ptr_type.storage != StorageClassInput && ptr_type.storage != StorageClassOutput) + return false; + if (ptr_type.storage == StorageClassOutput && get_execution_model() == ExecutionModelTessellationEvaluation) + return false; + + bool flat_data_type = is_matrix(result_type) || is_array(result_type) || result_type.basetype == SPIRType::Struct; + if (!flat_data_type) + return false; + + if (has_decoration(ptr, DecorationPatch)) + return false; + + // Now, we must unflatten a composite type and take care of interleaving array access with gl_in/gl_out. + // Lots of painful code duplication since we *really* should not unroll these kinds of loads in entry point fixup + // unless we're forced to do this when the code is emitting inoptimal OpLoads. + string expr; + + uint32_t interface_index = get_extended_decoration(ptr, SPIRVCrossDecorationInterfaceMemberIndex); + auto *var = maybe_get_backing_variable(ptr); + bool ptr_is_io_variable = ir.ids[ptr].get_type() == TypeVariable; + + const auto &iface_type = expression_type(stage_in_ptr_var_id); + + if (result_type.array.size() > 2) + { + SPIRV_CROSS_THROW("Cannot load tessellation IO variables with more than 2 dimensions."); + } + else if (result_type.array.size() == 2) + { + if (!ptr_is_io_variable) + SPIRV_CROSS_THROW("Loading an array-of-array must be loaded directly from an IO variable."); + if (interface_index == uint32_t(-1)) + SPIRV_CROSS_THROW("Interface index is unknown. Cannot continue."); + if (result_type.basetype == SPIRType::Struct || is_matrix(result_type)) + SPIRV_CROSS_THROW("Cannot load array-of-array of composite type in tessellation IO."); + + expr += type_to_glsl(result_type) + "({ "; + uint32_t num_control_points = to_array_size_literal(result_type, 1); + uint32_t base_interface_index = interface_index; + + auto &sub_type = get(result_type.parent_type); + + for (uint32_t i = 0; i < num_control_points; i++) + { + expr += type_to_glsl(sub_type) + "({ "; + interface_index = base_interface_index; + uint32_t array_size = to_array_size_literal(result_type, 0); + for (uint32_t j = 0; j < array_size; j++, interface_index++) + { + const uint32_t indices[2] = { i, interface_index }; + + AccessChainMeta meta; + expr += access_chain_internal(stage_in_ptr_var_id, indices, 2, + ACCESS_CHAIN_INDEX_IS_LITERAL_BIT | ACCESS_CHAIN_PTR_CHAIN_BIT, &meta); + + if (j + 1 < array_size) + expr += ", "; + } + expr += " })"; + if (i + 1 < num_control_points) + expr += ", "; + } + expr += " })"; + } + else if (result_type.basetype == SPIRType::Struct) + { + bool is_array_of_struct = is_array(result_type); + if (is_array_of_struct && !ptr_is_io_variable) + SPIRV_CROSS_THROW("Loading array of struct from IO variable must come directly from IO variable."); + + uint32_t num_control_points = 1; + if (is_array_of_struct) + { + num_control_points = to_array_size_literal(result_type, 0); + expr += type_to_glsl(result_type) + "({ "; + } + + auto &struct_type = is_array_of_struct ? get(result_type.parent_type) : result_type; + assert(struct_type.array.empty()); + + for (uint32_t i = 0; i < num_control_points; i++) + { + expr += type_to_glsl(struct_type) + "{ "; + for (uint32_t j = 0; j < uint32_t(struct_type.member_types.size()); j++) + { + // The base interface index is stored per variable for structs. + if (var) + { + interface_index = + get_extended_member_decoration(var->self, j, SPIRVCrossDecorationInterfaceMemberIndex); + } + + if (interface_index == uint32_t(-1)) + SPIRV_CROSS_THROW("Interface index is unknown. Cannot continue."); + + const auto &mbr_type = get(struct_type.member_types[j]); + if (is_matrix(mbr_type)) + { + expr += type_to_glsl(mbr_type) + "("; + for (uint32_t k = 0; k < mbr_type.columns; k++, interface_index++) + { + if (is_array_of_struct) + { + const uint32_t indices[2] = { i, interface_index }; + AccessChainMeta meta; + expr += access_chain_internal( + stage_in_ptr_var_id, indices, 2, + ACCESS_CHAIN_INDEX_IS_LITERAL_BIT | ACCESS_CHAIN_PTR_CHAIN_BIT, &meta); + } + else + expr += to_expression(ptr) + "." + to_member_name(iface_type, interface_index); + + if (k + 1 < mbr_type.columns) + expr += ", "; + } + expr += ")"; + } + else if (is_array(mbr_type)) + { + expr += type_to_glsl(mbr_type) + "({ "; + uint32_t array_size = to_array_size_literal(mbr_type, 0); + for (uint32_t k = 0; k < array_size; k++, interface_index++) + { + if (is_array_of_struct) + { + const uint32_t indices[2] = { i, interface_index }; + AccessChainMeta meta; + expr += access_chain_internal( + stage_in_ptr_var_id, indices, 2, + ACCESS_CHAIN_INDEX_IS_LITERAL_BIT | ACCESS_CHAIN_PTR_CHAIN_BIT, &meta); + } + else + expr += to_expression(ptr) + "." + to_member_name(iface_type, interface_index); + + if (k + 1 < array_size) + expr += ", "; + } + expr += " })"; + } + else + { + if (is_array_of_struct) + { + const uint32_t indices[2] = { i, interface_index }; + AccessChainMeta meta; + expr += access_chain_internal(stage_in_ptr_var_id, indices, 2, + ACCESS_CHAIN_INDEX_IS_LITERAL_BIT | ACCESS_CHAIN_PTR_CHAIN_BIT, + &meta); + } + else + expr += to_expression(ptr) + "." + to_member_name(iface_type, interface_index); + } + + if (j + 1 < struct_type.member_types.size()) + expr += ", "; + } + expr += " }"; + if (i + 1 < num_control_points) + expr += ", "; + } + if (is_array_of_struct) + expr += " })"; + } + else if (is_matrix(result_type)) + { + bool is_array_of_matrix = is_array(result_type); + if (is_array_of_matrix && !ptr_is_io_variable) + SPIRV_CROSS_THROW("Loading array of matrix from IO variable must come directly from IO variable."); + if (interface_index == uint32_t(-1)) + SPIRV_CROSS_THROW("Interface index is unknown. Cannot continue."); + + if (is_array_of_matrix) + { + // Loading a matrix from each control point. + uint32_t base_interface_index = interface_index; + uint32_t num_control_points = to_array_size_literal(result_type, 0); + expr += type_to_glsl(result_type) + "({ "; + + auto &matrix_type = get_variable_element_type(get(ptr)); + + for (uint32_t i = 0; i < num_control_points; i++) + { + interface_index = base_interface_index; + expr += type_to_glsl(matrix_type) + "("; + for (uint32_t j = 0; j < result_type.columns; j++, interface_index++) + { + const uint32_t indices[2] = { i, interface_index }; + + AccessChainMeta meta; + expr += + access_chain_internal(stage_in_ptr_var_id, indices, 2, + ACCESS_CHAIN_INDEX_IS_LITERAL_BIT | ACCESS_CHAIN_PTR_CHAIN_BIT, &meta); + if (j + 1 < result_type.columns) + expr += ", "; + } + expr += ")"; + if (i + 1 < num_control_points) + expr += ", "; + } + + expr += " })"; + } + else + { + expr += type_to_glsl(result_type) + "("; + for (uint32_t i = 0; i < result_type.columns; i++, interface_index++) + { + expr += to_expression(ptr) + "." + to_member_name(iface_type, interface_index); + if (i + 1 < result_type.columns) + expr += ", "; + } + expr += ")"; + } + } + else if (ptr_is_io_variable) + { + assert(is_array(result_type)); + assert(result_type.array.size() == 1); + if (interface_index == uint32_t(-1)) + SPIRV_CROSS_THROW("Interface index is unknown. Cannot continue."); + + // We're loading an array directly from a global variable. + // This means we're loading one member from each control point. + expr += type_to_glsl(result_type) + "({ "; + uint32_t num_control_points = to_array_size_literal(result_type, 0); + + for (uint32_t i = 0; i < num_control_points; i++) + { + const uint32_t indices[2] = { i, interface_index }; + + AccessChainMeta meta; + expr += access_chain_internal(stage_in_ptr_var_id, indices, 2, + ACCESS_CHAIN_INDEX_IS_LITERAL_BIT | ACCESS_CHAIN_PTR_CHAIN_BIT, &meta); + + if (i + 1 < num_control_points) + expr += ", "; + } + expr += " })"; + } + else + { + // We're loading an array from a concrete control point. + assert(is_array(result_type)); + assert(result_type.array.size() == 1); + if (interface_index == uint32_t(-1)) + SPIRV_CROSS_THROW("Interface index is unknown. Cannot continue."); + + expr += type_to_glsl(result_type) + "({ "; + uint32_t array_size = to_array_size_literal(result_type, 0); + for (uint32_t i = 0; i < array_size; i++, interface_index++) + { + expr += to_expression(ptr) + "." + to_member_name(iface_type, interface_index); + if (i + 1 < array_size) + expr += ", "; + } + expr += " })"; + } + + emit_op(result_type_id, id, expr, false); + register_read(id, ptr, false); + return true; +} + bool CompilerMSL::emit_tessellation_access_chain(const uint32_t *ops, uint32_t length) { // If this is a per-vertex output, remap it to the I/O array buffer. - auto *var = maybe_get(ops[2]); + + // Any object which did not go through IO flattening shenanigans will go there instead. + // We will unflatten on-demand instead as needed, but not all possible cases can be supported, especially with arrays. + + auto *var = maybe_get_backing_variable(ops[2]); + bool patch = false; + bool flat_data = false; + bool ptr_is_chain = false; + + if (var) + { + patch = has_decoration(ops[2], DecorationPatch) || is_patch_block(get_variable_data_type(*var)); + + // Should match strip_array in add_interface_block. + flat_data = var->storage == StorageClassInput || + (var->storage == StorageClassOutput && get_execution_model() == ExecutionModelTessellationControl); + + // We might have a chained access chain, where + // we first take the access chain to the control point, and then we chain into a member or something similar. + // In this case, we need to skip gl_in/gl_out remapping. + ptr_is_chain = var->self != ID(ops[2]); + } + BuiltIn bi_type = BuiltIn(get_decoration(ops[2], DecorationBuiltIn)); - if (var && - (var->storage == StorageClassInput || - (get_execution_model() == ExecutionModelTessellationControl && var->storage == StorageClassOutput)) && - !(has_decoration(ops[2], DecorationPatch) || is_patch_block(get_variable_data_type(*var))) && + if (var && flat_data && !patch && (!is_builtin_variable(*var) || bi_type == BuiltInPosition || bi_type == BuiltInPointSize || bi_type == BuiltInClipDistance || bi_type == BuiltInCullDistance || get_variable_data_type(*var).basetype == SPIRType::Struct)) @@ -3838,26 +5560,35 @@ bool CompilerMSL::emit_tessellation_access_chain(const uint32_t *ops, uint32_t l new_uint_type.width = 32; set(type_id, new_uint_type); - indices.push_back(ops[3]); + uint32_t first_non_array_index = ptr_is_chain ? 3 : 4; + VariableID stage_var_id = var->storage == StorageClassInput ? stage_in_ptr_var_id : stage_out_ptr_var_id; + VariableID ptr = ptr_is_chain ? VariableID(ops[2]) : stage_var_id; + if (!ptr_is_chain) + { + // Index into gl_in/gl_out with first array index. + indices.push_back(ops[3]); + } + + auto &result_ptr_type = get(ops[0]); uint32_t const_mbr_id = next_id++; - uint32_t index = get_extended_decoration(ops[2], SPIRVCrossDecorationInterfaceMemberIndex); - uint32_t ptr = var->storage == StorageClassInput ? stage_in_ptr_var_id : stage_out_ptr_var_id; + uint32_t index = get_extended_decoration(var->self, SPIRVCrossDecorationInterfaceMemberIndex); if (var->storage == StorageClassInput || has_decoration(get_variable_element_type(*var).self, DecorationBlock)) { - uint32_t i = 4; + uint32_t i = first_non_array_index; auto *type = &get_variable_element_type(*var); - if (index == uint32_t(-1) && length >= 5) + if (index == uint32_t(-1) && length >= (first_non_array_index + 1)) { // Maybe this is a struct type in the input class, in which case // we put it as a decoration on the corresponding member. - index = get_extended_member_decoration(ops[2], get_constant(ops[4]).scalar(), + index = get_extended_member_decoration(var->self, get_constant(ops[first_non_array_index]).scalar(), SPIRVCrossDecorationInterfaceMemberIndex); assert(index != uint32_t(-1)); i++; - type = &get(type->member_types[get_constant(ops[4]).scalar()]); + type = &get(type->member_types[get_constant(ops[first_non_array_index]).scalar()]); } - // In this case, we flattened structures and arrays, so now we have to + + // In this case, we're poking into flattened structures and arrays, so now we have to // combine the following indices. If we encounter a non-constant index, // we're hosed. for (; i < length; ++i) @@ -3865,92 +5596,35 @@ bool CompilerMSL::emit_tessellation_access_chain(const uint32_t *ops, uint32_t l if (!is_array(*type) && !is_matrix(*type) && type->basetype != SPIRType::Struct) break; - auto &c = get_constant(ops[i]); - index += c.scalar(); + auto *c = maybe_get(ops[i]); + if (!c || c->specialization) + SPIRV_CROSS_THROW("Trying to dynamically index into an array interface variable in tessellation. " + "This is currently unsupported."); + + // We're in flattened space, so just increment the member index into IO block. + // We can only do this once in the current implementation, so either: + // Struct, Matrix or 1-dimensional array for a control point. + index += c->scalar(); + if (type->parent_type) type = &get(type->parent_type); else if (type->basetype == SPIRType::Struct) - type = &get(type->member_types[c.scalar()]); + type = &get(type->member_types[c->scalar()]); } - // If the access chain terminates at a composite type, the composite - // itself might be copied. In that case, we must unflatten it. - if (is_matrix(*type) || is_array(*type) || type->basetype == SPIRType::Struct) - { - std::string temp_name = join(to_name(var->self), "_", ops[1]); - statement(variable_decl(*type, temp_name, var->self), ";"); - // Set up the initializer for this temporary variable. - indices.push_back(const_mbr_id); - if (type->basetype == SPIRType::Struct) - { - for (uint32_t j = 0; j < type->member_types.size(); j++) - { - index = get_extended_member_decoration(ops[2], j, SPIRVCrossDecorationInterfaceMemberIndex); - const auto &mbr_type = get(type->member_types[j]); - if (is_matrix(mbr_type)) - { - for (uint32_t k = 0; k < mbr_type.columns; k++, index++) - { - set(const_mbr_id, type_id, index, false); - auto e = access_chain(ptr, indices.data(), uint32_t(indices.size()), mbr_type, nullptr, - true); - statement(temp_name, ".", to_member_name(*type, j), "[", k, "] = ", e, ";"); - } - } - else if (is_array(mbr_type)) - { - for (uint32_t k = 0; k < mbr_type.array[0]; k++, index++) - { - set(const_mbr_id, type_id, index, false); - auto e = access_chain(ptr, indices.data(), uint32_t(indices.size()), mbr_type, nullptr, - true); - statement(temp_name, ".", to_member_name(*type, j), "[", k, "] = ", e, ";"); - } - } - else - { - set(const_mbr_id, type_id, index, false); - auto e = - access_chain(ptr, indices.data(), uint32_t(indices.size()), mbr_type, nullptr, true); - statement(temp_name, ".", to_member_name(*type, j), " = ", e, ";"); - } - } - } - else if (is_matrix(*type)) - { - for (uint32_t j = 0; j < type->columns; j++, index++) - { - set(const_mbr_id, type_id, index, false); - auto e = access_chain(ptr, indices.data(), uint32_t(indices.size()), *type, nullptr, true); - statement(temp_name, "[", j, "] = ", e, ";"); - } - } - else // Must be an array - { - assert(is_array(*type)); - for (uint32_t j = 0; j < type->array[0]; j++, index++) - { - set(const_mbr_id, type_id, index, false); - auto e = access_chain(ptr, indices.data(), uint32_t(indices.size()), *type, nullptr, true); - statement(temp_name, "[", j, "] = ", e, ";"); - } - } - // This needs to be a variable instead of an expression so we don't - // try to dereference this as a variable pointer. - set(ops[1], ops[0], var->storage); - ir.meta[ops[1]] = ir.meta[ops[2]]; - set_name(ops[1], temp_name); - if (has_decoration(var->self, DecorationInvariant)) - set_decoration(ops[1], DecorationInvariant); - for (uint32_t j = 2; j < length; j++) - inherit_expression_dependencies(ops[1], ops[j]); - return true; + if (is_matrix(result_ptr_type) || is_array(result_ptr_type) || result_ptr_type.basetype == SPIRType::Struct) + { + // We're not going to emit the actual member name, we let any further OpLoad take care of that. + // Tag the access chain with the member index we're referencing. + set_extended_decoration(ops[1], SPIRVCrossDecorationInterfaceMemberIndex, index); } else { + // Access the appropriate member of gl_in/gl_out. set(const_mbr_id, type_id, index, false); indices.push_back(const_mbr_id); + // Append any straggling access chain indices. if (i < length) indices.insert(indices.end(), ops + i, ops + length); } @@ -3966,7 +5640,39 @@ bool CompilerMSL::emit_tessellation_access_chain(const uint32_t *ops, uint32_t l // We use the pointer to the base of the input/output array here, // so this is always a pointer chain. - auto e = access_chain(ptr, indices.data(), uint32_t(indices.size()), get(ops[0]), &meta, true); + string e; + + if (!ptr_is_chain) + { + // This is the start of an access chain, use ptr_chain to index into control point array. + e = access_chain(ptr, indices.data(), uint32_t(indices.size()), result_ptr_type, &meta, true); + } + else + { + // If we're accessing a struct, we need to use member indices which are based on the IO block, + // not actual struct type, so we have to use a split access chain here where + // first path resolves the control point index, i.e. gl_in[index], and second half deals with + // looking up flattened member name. + + // However, it is possible that we partially accessed a struct, + // by taking pointer to member inside the control-point array. + // For this case, we fall back to a natural access chain since we have already dealt with remapping struct members. + // One way to check this here is if we have 2 implied read expressions. + // First one is the gl_in/gl_out struct itself, then an index into that array. + // If we have traversed further, we use a normal access chain formulation. + auto *ptr_expr = maybe_get(ptr); + if (ptr_expr && ptr_expr->implied_read_expressions.size() == 2) + { + e = join(to_expression(ptr), + access_chain_internal(stage_var_id, indices.data(), uint32_t(indices.size()), + ACCESS_CHAIN_CHAIN_ONLY_BIT, &meta)); + } + else + { + e = access_chain_internal(ptr, indices.data(), uint32_t(indices.size()), 0, &meta); + } + } + auto &expr = set(ops[1], move(e), ops[0], should_forward(ops[2])); expr.loaded_from = var->self; expr.need_transpose = meta.need_transpose; @@ -3980,12 +5686,24 @@ bool CompilerMSL::emit_tessellation_access_chain(const uint32_t *ops, uint32_t l if (meta.storage_is_invariant) set_decoration(ops[1], DecorationInvariant); + // If we have some expression dependencies in our access chain, this access chain is technically a forwarded + // temporary which could be subject to invalidation. + // Need to assume we're forwarded while calling inherit_expression_depdendencies. + forwarded_temporaries.insert(ops[1]); + // The access chain itself is never forced to a temporary, but its dependencies might. + suppressed_usage_tracking.insert(ops[1]); + for (uint32_t i = 2; i < length; i++) { inherit_expression_dependencies(ops[1], ops[i]); add_implied_read_expression(expr, ops[i]); } + // If we have no dependencies after all, i.e., all indices in the access chain are immutable temporaries, + // we're not forwarded after all. + if (expr.expression_dependencies.empty()) + forwarded_temporaries.erase(ops[1]); + return true; } @@ -3995,7 +5713,7 @@ bool CompilerMSL::emit_tessellation_access_chain(const uint32_t *ops, uint32_t l // expression so we don't try to dereference it as a variable pointer. // Don't do this if the index is a constant 1, though. We need to drop stores // to that one. - auto *m = ir.find_meta(var ? var->self : 0); + auto *m = ir.find_meta(var ? var->self : ID(0)); if (get_execution_model() == ExecutionModelTessellationControl && var && m && m->decoration.builtin_type == BuiltInTessLevelInner && get_entry_point().flags.get(ExecutionModeTriangles)) { @@ -4064,6 +5782,24 @@ void CompilerMSL::emit_instruction(const Instruction &instruction) switch (opcode) { + case OpLoad: + { + uint32_t id = ops[1]; + uint32_t ptr = ops[2]; + if (is_tessellation_shader()) + { + if (!emit_tessellation_io_load(ops[0], id, ptr)) + CompilerGLSL::emit_instruction(instruction); + } + else + { + // Sample mask input for Metal is not an array + if (BuiltIn(get_decoration(ptr, DecorationBuiltIn)) == BuiltInSampleMask) + set_decoration(id, DecorationBuiltIn, BuiltInSampleMask); + CompilerGLSL::emit_instruction(instruction); + } + break; + } // Comparisons case OpIEqual: @@ -4180,26 +5916,55 @@ void CompilerMSL::emit_instruction(const Instruction &instruction) // Bitfield case OpBitFieldInsert: - MSL_QFOP(insert_bits); + { + emit_bitfield_insert_op(ops[0], ops[1], ops[2], ops[3], ops[4], ops[5], "insert_bits", SPIRType::UInt); break; + } case OpBitFieldSExtract: - case OpBitFieldUExtract: - MSL_TFOP(extract_bits); + { + emit_trinary_func_op_bitextract(ops[0], ops[1], ops[2], ops[3], ops[4], "extract_bits", int_type, int_type, + SPIRType::UInt, SPIRType::UInt); break; + } + + case OpBitFieldUExtract: + { + emit_trinary_func_op_bitextract(ops[0], ops[1], ops[2], ops[3], ops[4], "extract_bits", uint_type, uint_type, + SPIRType::UInt, SPIRType::UInt); + break; + } case OpBitReverse: + // BitReverse does not have issues with sign since result type must match input type. MSL_UFOP(reverse_bits); break; case OpBitCount: - MSL_UFOP(popcount); + { + auto basetype = expression_type(ops[2]).basetype; + emit_unary_func_op_cast(ops[0], ops[1], ops[2], "popcount", basetype, basetype); break; + } case OpFRem: MSL_BFOP(fmod); break; + case OpFMul: + if (msl_options.invariant_float_math) + MSL_BFOP(spvFMul); + else + MSL_BOP(*); + break; + + case OpFAdd: + if (msl_options.invariant_float_math) + MSL_BFOP(spvFAdd); + else + MSL_BOP(+); + break; + // Atomics case OpAtomicExchange: { @@ -4325,6 +6090,41 @@ void CompilerMSL::emit_instruction(const Instruction &instruction) break; } + // Emulate texture2D atomic operations + case OpImageTexelPointer: + { + // When using the pointer, we need to know which variable it is actually loaded from. + auto *var = maybe_get_backing_variable(ops[2]); + if (var && atomic_image_vars.count(var->self)) + { + uint32_t result_type = ops[0]; + uint32_t id = ops[1]; + + std::string coord = to_expression(ops[3]); + auto &type = expression_type(ops[2]); + if (type.image.dim == Dim2D) + { + coord = join("spvImage2DAtomicCoord(", coord, ", ", to_expression(ops[2]), ")"); + } + + auto &e = set(id, join(to_expression(ops[2]), "_atomic[", coord, "]"), result_type, true); + e.loaded_from = var ? var->self : ID(0); + inherit_expression_dependencies(id, ops[3]); + } + else + { + uint32_t result_type = ops[0]; + uint32_t id = ops[1]; + auto &e = + set(id, join(to_expression(ops[2]), ", ", to_expression(ops[3])), result_type, true); + + // When using the pointer, we need to know which variable it is actually loaded from. + e.loaded_from = var ? var->self : ID(0); + inherit_expression_dependencies(id, ops[3]); + } + break; + } + case OpImageWrite: { uint32_t img_id = ops[0]; @@ -4420,7 +6220,11 @@ void CompilerMSL::emit_instruction(const Instruction &instruction) expr += ", " + img_exp + ".get_depth(" + lod + ")"; if (img_is_array) + { expr += ", " + img_exp + ".get_array_size()"; + if (img_dim == DimCube && msl_options.emulate_cube_array) + expr += " / 6"; + } expr += ")"; @@ -4490,17 +6294,18 @@ void CompilerMSL::emit_instruction(const Instruction &instruction) } else { - auto &e = emit_op(result_type, id, to_expression(ops[2]), true, true); auto *var = maybe_get_backing_variable(ops[2]); + SPIRExpression *e; + if (var && has_extended_decoration(var->self, SPIRVCrossDecorationDynamicImageSampler)) + e = &emit_op(result_type, id, join(to_expression(ops[2]), ".plane0"), true, true); + else + e = &emit_op(result_type, id, to_expression(ops[2]), true, true); if (var) - e.loaded_from = var->self; + e->loaded_from = var->self; } break; } - case OpImageTexelPointer: - SPIRV_CROSS_THROW("MSL does not support atomic operations on images or texel buffers."); - // Casting case OpQuantizeToF16: { @@ -4593,6 +6398,85 @@ void CompilerMSL::emit_instruction(const Instruction &instruction) break; } + case OpVectorTimesMatrix: + case OpMatrixTimesVector: + { + if (!msl_options.invariant_float_math) + { + CompilerGLSL::emit_instruction(instruction); + break; + } + + // If the matrix needs transpose, just flip the multiply order. + auto *e = maybe_get(ops[opcode == OpMatrixTimesVector ? 2 : 3]); + if (e && e->need_transpose) + { + e->need_transpose = false; + string expr; + + if (opcode == OpMatrixTimesVector) + { + expr = join("spvFMulVectorMatrix(", to_enclosed_unpacked_expression(ops[3]), ", ", + to_unpacked_row_major_matrix_expression(ops[2]), ")"); + } + else + { + expr = join("spvFMulMatrixVector(", to_unpacked_row_major_matrix_expression(ops[3]), ", ", + to_enclosed_unpacked_expression(ops[2]), ")"); + } + + bool forward = should_forward(ops[2]) && should_forward(ops[3]); + emit_op(ops[0], ops[1], expr, forward); + e->need_transpose = true; + inherit_expression_dependencies(ops[1], ops[2]); + inherit_expression_dependencies(ops[1], ops[3]); + } + else + { + if (opcode == OpMatrixTimesVector) + MSL_BFOP(spvFMulMatrixVector); + else + MSL_BFOP(spvFMulVectorMatrix); + } + break; + } + + case OpMatrixTimesMatrix: + { + if (!msl_options.invariant_float_math) + { + CompilerGLSL::emit_instruction(instruction); + break; + } + + auto *a = maybe_get(ops[2]); + auto *b = maybe_get(ops[3]); + + // If both matrices need transpose, we can multiply in flipped order and tag the expression as transposed. + // a^T * b^T = (b * a)^T. + if (a && b && a->need_transpose && b->need_transpose) + { + a->need_transpose = false; + b->need_transpose = false; + + auto expr = + join("spvFMulMatrixMatrix(", enclose_expression(to_unpacked_row_major_matrix_expression(ops[3])), ", ", + enclose_expression(to_unpacked_row_major_matrix_expression(ops[2])), ")"); + + bool forward = should_forward(ops[2]) && should_forward(ops[3]); + auto &e = emit_op(ops[0], ops[1], expr, forward); + e.need_transpose = true; + a->need_transpose = true; + b->need_transpose = true; + inherit_expression_dependencies(ops[1], ops[2]); + inherit_expression_dependencies(ops[1], ops[3]); + } + else + MSL_BFOP(spvFMulMatrixMatrix); + + break; + } + case OpIAddCarry: case OpISubBorrow: { @@ -4600,10 +6484,8 @@ void CompilerMSL::emit_instruction(const Instruction &instruction) uint32_t result_id = ops[1]; uint32_t op0 = ops[2]; uint32_t op1 = ops[3]; - forced_temporaries.insert(result_id); auto &type = get(result_type); - statement(variable_decl(type, to_name(result_id)), ";"); - set(result_id, to_name(result_id), result_type, true); + emit_uninitialized_temporary_expression(result_type, result_id); auto &res_type = get(type.member_types[1]); if (opcode == OpIAddCarry) @@ -4632,10 +6514,8 @@ void CompilerMSL::emit_instruction(const Instruction &instruction) uint32_t result_id = ops[1]; uint32_t op0 = ops[2]; uint32_t op1 = ops[3]; - forced_temporaries.insert(result_id); auto &type = get(result_type); - statement(variable_decl(type, to_name(result_id)), ";"); - set(result_id, to_name(result_id), result_type, true); + emit_uninitialized_temporary_expression(result_type, result_id); statement(to_expression(result_id), ".", to_member_name(type, 0), " = ", to_enclosed_expression(op0), " * ", to_enclosed_expression(op1), ";"); @@ -4723,6 +6603,12 @@ void CompilerMSL::emit_instruction(const Instruction &instruction) emit_op(ops[0], ops[1], "simd_is_helper_thread()", false); break; + case OpBeginInvocationInterlockEXT: + case OpEndInvocationInterlockEXT: + if (!msl_options.supports_msl_version(2, 0)) + SPIRV_CROSS_THROW("Raster order groups require MSL 2.0."); + break; // Nothing to do in the body + default: CompilerGLSL::emit_instruction(instruction); break; @@ -4731,6 +6617,34 @@ void CompilerMSL::emit_instruction(const Instruction &instruction) previous_instruction_opcode = opcode; } +void CompilerMSL::emit_texture_op(const Instruction &i) +{ + if (msl_options.is_ios() && msl_options.ios_use_framebuffer_fetch_subpasses) + { + auto *ops = stream(i); + + uint32_t result_type_id = ops[0]; + uint32_t id = ops[1]; + uint32_t img = ops[2]; + + auto &type = expression_type(img); + auto &imgtype = get(type.self); + + // Use Metal's native frame-buffer fetch API for subpass inputs. + if (imgtype.image.dim == DimSubpassData) + { + // Subpass inputs cannot be invalidated, + // so just forward the expression directly. + string expr = to_expression(img); + emit_op(result_type_id, id, expr, true); + return; + } + } + + // Fallback to default implementation + CompilerGLSL::emit_texture_op(i); +} + void CompilerMSL::emit_barrier(uint32_t id_exe_scope, uint32_t id_mem_scope, uint32_t id_mem_sem) { if (get_execution_model() != ExecutionModelGLCompute && get_execution_model() != ExecutionModelTessellationControl) @@ -4759,8 +6673,10 @@ void CompilerMSL::emit_barrier(uint32_t id_exe_scope, uint32_t id_mem_scope, uin if (get_execution_model() == ExecutionModelTessellationControl || (mem_sem & (MemorySemanticsUniformMemoryMask | MemorySemanticsCrossWorkgroupMemoryMask))) mem_flags += "mem_flags::mem_device"; - if (mem_sem & (MemorySemanticsSubgroupMemoryMask | MemorySemanticsWorkgroupMemoryMask | - MemorySemanticsAtomicCounterMemoryMask)) + + // Fix tessellation patch function processing + if (get_execution_model() == ExecutionModelTessellationControl || + (mem_sem & (MemorySemanticsSubgroupMemoryMask | MemorySemanticsWorkgroupMemoryMask))) { if (!mem_flags.empty()) mem_flags += " | "; @@ -4781,13 +6697,11 @@ void CompilerMSL::emit_barrier(uint32_t id_exe_scope, uint32_t id_mem_scope, uin else { if ((mem_sem & (MemorySemanticsUniformMemoryMask | MemorySemanticsCrossWorkgroupMemoryMask)) && - (mem_sem & (MemorySemanticsSubgroupMemoryMask | MemorySemanticsWorkgroupMemoryMask | - MemorySemanticsAtomicCounterMemoryMask))) + (mem_sem & (MemorySemanticsSubgroupMemoryMask | MemorySemanticsWorkgroupMemoryMask))) bar_stmt += "mem_flags::mem_device_and_threadgroup"; else if (mem_sem & (MemorySemanticsUniformMemoryMask | MemorySemanticsCrossWorkgroupMemoryMask)) bar_stmt += "mem_flags::mem_device"; - else if (mem_sem & (MemorySemanticsSubgroupMemoryMask | MemorySemanticsWorkgroupMemoryMask | - MemorySemanticsAtomicCounterMemoryMask)) + else if (mem_sem & (MemorySemanticsSubgroupMemoryMask | MemorySemanticsWorkgroupMemoryMask)) bar_stmt += "mem_flags::mem_threadgroup"; else if (mem_sem & MemorySemanticsImageMemoryMask) bar_stmt += "mem_flags::mem_texture"; @@ -4795,29 +6709,6 @@ void CompilerMSL::emit_barrier(uint32_t id_exe_scope, uint32_t id_mem_scope, uin bar_stmt += "mem_flags::mem_none"; } - if (msl_options.is_ios() && (msl_options.supports_msl_version(2) && !msl_options.supports_msl_version(2, 1))) - { - bar_stmt += ", "; - - switch (mem_scope) - { - case ScopeCrossDevice: - case ScopeDevice: - bar_stmt += "memory_scope_device"; - break; - - case ScopeSubgroup: - case ScopeInvocation: - bar_stmt += "memory_scope_simdgroup"; - break; - - case ScopeWorkgroup: - default: - bar_stmt += "memory_scope_threadgroup"; - break; - } - } - bar_stmt += ");"; statement(bar_stmt); @@ -4827,50 +6718,79 @@ void CompilerMSL::emit_barrier(uint32_t id_exe_scope, uint32_t id_mem_scope, uin flush_all_active_variables(); } -void CompilerMSL::emit_array_copy(const string &lhs, uint32_t rhs_id) +void CompilerMSL::emit_array_copy(const string &lhs, uint32_t rhs_id, StorageClass lhs_storage, + StorageClass rhs_storage) { - // Assignment from an array initializer is fine. - auto &type = expression_type(rhs_id); - auto *var = maybe_get_backing_variable(rhs_id); + // Allow Metal to use the array template to make arrays a value type. + // This, however, cannot be used for threadgroup address specifiers, so consider the custom array copy as fallback. + bool lhs_thread = (lhs_storage == StorageClassOutput || lhs_storage == StorageClassFunction || + lhs_storage == StorageClassGeneric || lhs_storage == StorageClassPrivate); + bool rhs_thread = (rhs_storage == StorageClassInput || rhs_storage == StorageClassFunction || + rhs_storage == StorageClassGeneric || rhs_storage == StorageClassPrivate); - // Unfortunately, we cannot template on address space in MSL, - // so explicit address space redirection it is ... - bool is_constant = false; - if (ir.ids[rhs_id].get_type() == TypeConstant) + // If threadgroup storage qualifiers are *not* used: + // Avoid spvCopy* wrapper functions; Otherwise, spvUnsafeArray<> template cannot be used with that storage qualifier. + if (lhs_thread && rhs_thread && !using_builtin_array()) { - is_constant = true; + statement(lhs, " = ", to_expression(rhs_id), ";"); } - else if (var && var->remapped_variable && var->statically_assigned && - ir.ids[var->static_expression].get_type() == TypeConstant) + else { - is_constant = true; - } + // Assignment from an array initializer is fine. + auto &type = expression_type(rhs_id); + auto *var = maybe_get_backing_variable(rhs_id); - // For the case where we have OpLoad triggering an array copy, - // we cannot easily detect this case ahead of time since it's - // context dependent. We might have to force a recompile here - // if this is the only use of array copies in our shader. - if (type.array.size() > 1) - { - if (type.array.size() > SPVFuncImplArrayCopyMultidimMax) - SPIRV_CROSS_THROW("Cannot support this many dimensions for arrays of arrays."); - auto func = static_cast(SPVFuncImplArrayCopyMultidimBase + type.array.size()); - if (spv_function_implementations.count(func) == 0) + // Unfortunately, we cannot template on address space in MSL, + // so explicit address space redirection it is ... + bool is_constant = false; + if (ir.ids[rhs_id].get_type() == TypeConstant) { - spv_function_implementations.insert(func); - suppress_missing_prototypes = true; - force_recompile(); + is_constant = true; + } + else if (var && var->remapped_variable && var->statically_assigned && + ir.ids[var->static_expression].get_type() == TypeConstant) + { + is_constant = true; } - } - else if (spv_function_implementations.count(SPVFuncImplArrayCopy) == 0) - { - spv_function_implementations.insert(SPVFuncImplArrayCopy); - suppress_missing_prototypes = true; - force_recompile(); - } - const char *tag = is_constant ? "FromConstant" : "FromStack"; - statement("spvArrayCopy", tag, type.array.size(), "(", lhs, ", ", to_expression(rhs_id), ");"); + // For the case where we have OpLoad triggering an array copy, + // we cannot easily detect this case ahead of time since it's + // context dependent. We might have to force a recompile here + // if this is the only use of array copies in our shader. + if (type.array.size() > 1) + { + if (type.array.size() > SPVFuncImplArrayCopyMultidimMax) + SPIRV_CROSS_THROW("Cannot support this many dimensions for arrays of arrays."); + auto func = static_cast(SPVFuncImplArrayCopyMultidimBase + type.array.size()); + add_spv_func_and_recompile(func); + } + else + add_spv_func_and_recompile(SPVFuncImplArrayCopy); + + const char *tag = nullptr; + if (lhs_thread && is_constant) + tag = "FromConstantToStack"; + else if (lhs_storage == StorageClassWorkgroup && is_constant) + tag = "FromConstantToThreadGroup"; + else if (lhs_thread && rhs_thread) + tag = "FromStackToStack"; + else if (lhs_storage == StorageClassWorkgroup && rhs_thread) + tag = "FromStackToThreadGroup"; + else if (lhs_thread && rhs_storage == StorageClassWorkgroup) + tag = "FromThreadGroupToStack"; + else if (lhs_storage == StorageClassWorkgroup && rhs_storage == StorageClassWorkgroup) + tag = "FromThreadGroupToThreadGroup"; + else + SPIRV_CROSS_THROW("Unknown storage class used for copying arrays."); + + // Pass internal array of spvUnsafeArray<> into wrapper functions + if (lhs_thread && !msl_options.force_native_arrays) + statement("spvArrayCopy", tag, type.array.size(), "(", lhs, ".elements, ", to_expression(rhs_id), ");"); + else if (rhs_thread && !msl_options.force_native_arrays) + statement("spvArrayCopy", tag, type.array.size(), "(", lhs, ", ", to_expression(rhs_id), ".elements);"); + else + statement("spvArrayCopy", tag, type.array.size(), "(", lhs, ", ", to_expression(rhs_id), ");"); + } } // Since MSL does not allow arrays to be copied via simple variable assignment, @@ -4906,7 +6826,8 @@ bool CompilerMSL::maybe_emit_array_assignment(uint32_t id_lhs, uint32_t id_rhs) if (p_v_lhs) flush_variable_declaration(p_v_lhs->self); - emit_array_copy(to_expression(id_lhs), id_rhs); + emit_array_copy(to_expression(id_lhs), id_rhs, get_backing_variable_storage(id_lhs), + get_backing_variable_storage(id_rhs)); register_write(id_lhs); return true; @@ -4917,8 +6838,6 @@ void CompilerMSL::emit_atomic_func_op(uint32_t result_type, uint32_t result_id, uint32_t mem_order_2, bool has_mem_order_2, uint32_t obj, uint32_t op1, bool op1_is_pointer, bool op1_is_literal, uint32_t op2) { - forced_temporaries.insert(result_id); - string exp = string(op) + "("; auto &type = get_pointee_type(expression_type(obj)); @@ -4926,7 +6845,18 @@ void CompilerMSL::emit_atomic_func_op(uint32_t result_type, uint32_t result_id, auto *var = maybe_get_backing_variable(obj); if (!var) SPIRV_CROSS_THROW("No backing variable for atomic operation."); - exp += get_argument_address_space(*var); + + // Emulate texture2D atomic operations + const auto &res_type = get(var->basetype); + if (res_type.storage == StorageClassUniformConstant && res_type.basetype == SPIRType::Image) + { + exp += "device"; + } + else + { + exp += get_argument_address_space(*var); + } + exp += " atomic_"; exp += type_to_glsl(type); exp += "*)"; @@ -4957,12 +6887,11 @@ void CompilerMSL::emit_atomic_func_op(uint32_t result_type, uint32_t result_id, // the CAS loop, otherwise it will loop infinitely, with the comparison test always failing. // The function updates the comparitor value from the memory value, so the additional // comparison test evaluates the memory value against the expected value. - statement(variable_decl(type, to_name(result_id)), ";"); + emit_uninitialized_temporary_expression(result_type, result_id); statement("do"); begin_scope(); statement(to_name(result_id), " = ", to_expression(op1), ";"); end_scope_decl(join("while (!", exp, " && ", to_name(result_id), " == ", to_enclosed_expression(op1), ")")); - set(result_id, to_name(result_id), result_type, true); } else { @@ -5211,6 +7140,32 @@ void CompilerMSL::emit_glsl_op(uint32_t result_type, uint32_t id, uint32_t eop, CompilerGLSL::emit_glsl_op(result_type, id, eop, args, count); break; + case GLSLstd450Modf: + case GLSLstd450Frexp: + { + // Special case. If the variable is a scalar access chain, we cannot use it directly. We have to emit a temporary. + auto *ptr = maybe_get(args[1]); + if (ptr && ptr->access_chain && is_scalar(expression_type(args[1]))) + { + register_call_out_argument(args[1]); + forced_temporaries.insert(id); + + // Need to create temporaries and copy over to access chain after. + // We cannot directly take the reference of a vector swizzle in MSL, even if it's scalar ... + uint32_t &tmp_id = extra_sub_expressions[id]; + if (!tmp_id) + tmp_id = ir.increase_bound_by(1); + + uint32_t tmp_type_id = get_pointee_type_id(ptr->expression_type); + emit_uninitialized_temporary_expression(tmp_type_id, tmp_id); + emit_binary_func_op(result_type, id, args[0], tmp_id, eop == GLSLstd450Modf ? "modf" : "frexp"); + statement(to_expression(args[1]), " = ", to_expression(tmp_id), ";"); + } + else + CompilerGLSL::emit_glsl_op(result_type, id, eop, args, count); + break; + } + default: CompilerGLSL::emit_glsl_op(result_type, id, eop, args, count); break; @@ -5273,25 +7228,29 @@ void CompilerMSL::emit_function_prototype(SPIRFunction &func, const Bitset &) local_variable_names = resource_names; string decl; - processing_entry_point = (func.self == ir.default_entry_point); + processing_entry_point = func.self == ir.default_entry_point; + + // Metal helper functions must be static force-inline otherwise they will cause problems when linked together in a single Metallib. + if (!processing_entry_point) + statement(force_inline); auto &type = get(func.return_type); - if (type.array.empty()) + if (!type.array.empty() && msl_options.force_native_arrays) { - decl += func_type_decl(type); + // We cannot return native arrays in MSL, so "return" through an out variable. + decl += "void"; } else { - // We cannot return arrays in MSL, so "return" through an out variable. - decl = "void"; + decl += func_type_decl(type); } decl += " "; decl += to_name(func.self); decl += "("; - if (!type.array.empty()) + if (!type.array.empty() && msl_options.force_native_arrays) { // Fake arrays returns by writing to an out array instead. decl += "thread "; @@ -5316,7 +7275,7 @@ void CompilerMSL::emit_function_prototype(SPIRFunction &func, const Bitset &) for (auto var_id : vars_needing_early_declaration) { auto &ed_var = get(var_id); - uint32_t &initializer = ed_var.initializer; + ID &initializer = ed_var.initializer; if (!initializer) initializer = ir.increase_bound_by(1); @@ -5345,13 +7304,27 @@ void CompilerMSL::emit_function_prototype(SPIRFunction &func, const Bitset &) decl += argument_decl(arg); - // Manufacture automatic sampler arg for SampledImage texture + bool is_dynamic_img_sampler = has_extended_decoration(arg.id, SPIRVCrossDecorationDynamicImageSampler); + auto &arg_type = get(arg.type); - if (arg_type.basetype == SPIRType::SampledImage && arg_type.image.dim != DimBuffer) - decl += join(", thread const ", sampler_type(arg_type), " ", to_sampler_expression(arg.id)); + if (arg_type.basetype == SPIRType::SampledImage && !is_dynamic_img_sampler) + { + // Manufacture automatic plane args for multiplanar texture + uint32_t planes = 1; + if (auto *constexpr_sampler = find_constexpr_sampler(name_id)) + if (constexpr_sampler->ycbcr_conversion_enable) + planes = constexpr_sampler->planes; + for (uint32_t i = 1; i < planes; i++) + decl += join(", ", argument_decl(arg), plane_name_suffix, i); + + // Manufacture automatic sampler arg for SampledImage texture + if (arg_type.image.dim != DimBuffer) + decl += join(", thread const ", sampler_type(arg_type), " ", to_sampler_expression(arg.id)); + } // Manufacture automatic swizzle arg. - if (msl_options.swizzle_texture_samples && has_sampled_images && is_sampled_image_type(arg_type)) + if (msl_options.swizzle_texture_samples && has_sampled_images && is_sampled_image_type(arg_type) && + !is_dynamic_img_sampler) { bool arg_is_array = !arg_type.array.empty(); decl += join(", constant uint", arg_is_array ? "* " : "& ", to_swizzle_expression(arg.id)); @@ -5371,60 +7344,157 @@ void CompilerMSL::emit_function_prototype(SPIRFunction &func, const Bitset &) statement(decl); } -// Returns the texture sampling function string for the specified image and sampling characteristics. -string CompilerMSL::to_function_name(uint32_t img, const SPIRType &imgtype, bool is_fetch, bool is_gather, bool, bool, - bool has_offset, bool, bool has_dref, uint32_t, uint32_t) +static bool needs_chroma_reconstruction(const MSLConstexprSampler *constexpr_sampler) { + // For now, only multiplanar images need explicit reconstruction. GBGR and BGRG images + // use implicit reconstruction. + return constexpr_sampler && constexpr_sampler->ycbcr_conversion_enable && constexpr_sampler->planes > 1; +} + +// Returns the texture sampling function string for the specified image and sampling characteristics. +string CompilerMSL::to_function_name(VariableID img, const SPIRType &imgtype, bool is_fetch, bool is_gather, bool, bool, + bool, bool, bool has_dref, uint32_t, uint32_t) +{ + const MSLConstexprSampler *constexpr_sampler = nullptr; + bool is_dynamic_img_sampler = false; + if (auto *var = maybe_get_backing_variable(img)) + { + constexpr_sampler = find_constexpr_sampler(var->basevariable ? var->basevariable : VariableID(var->self)); + is_dynamic_img_sampler = has_extended_decoration(var->self, SPIRVCrossDecorationDynamicImageSampler); + } + // Special-case gather. We have to alter the component being looked up // in the swizzle case. - if (msl_options.swizzle_texture_samples && is_gather) + if (msl_options.swizzle_texture_samples && is_gather && !is_dynamic_img_sampler && + (!constexpr_sampler || !constexpr_sampler->ycbcr_conversion_enable)) { - string fname = imgtype.image.depth ? "spvGatherCompareSwizzle" : "spvGatherSwizzle"; - fname += "<" + type_to_glsl(get(imgtype.image.type)) + ", metal::" + type_to_glsl(imgtype); - // Add the arg types ourselves. Yes, this sucks, but Clang can't - // deduce template pack parameters in the middle of an argument list. - switch (imgtype.image.dim) - { - case Dim2D: - fname += ", float2"; - if (imgtype.image.arrayed) - fname += ", uint"; - if (imgtype.image.depth) - fname += ", float"; - if (!imgtype.image.depth || has_offset) - fname += ", int2"; - break; - case DimCube: - fname += ", float3"; - if (imgtype.image.arrayed) - fname += ", uint"; - if (imgtype.image.depth) - fname += ", float"; - break; - default: - SPIRV_CROSS_THROW("Invalid texture dimension for gather op."); - } - fname += ">"; - return fname; + add_spv_func_and_recompile(imgtype.image.depth ? SPVFuncImplGatherCompareSwizzle : SPVFuncImplGatherSwizzle); + return imgtype.image.depth ? "spvGatherCompareSwizzle" : "spvGatherSwizzle"; } auto *combined = maybe_get(img); // Texture reference - string fname = to_expression(combined ? combined->image : img) + "."; - if (msl_options.swizzle_texture_samples && !is_gather && is_sampled_image_type(imgtype)) - fname = "spvTextureSwizzle(" + fname; - - // Texture function and sampler - if (is_fetch) - fname += "read"; - else if (is_gather) - fname += "gather"; + string fname; + if (needs_chroma_reconstruction(constexpr_sampler) && !is_dynamic_img_sampler) + { + if (constexpr_sampler->planes != 2 && constexpr_sampler->planes != 3) + SPIRV_CROSS_THROW("Unhandled number of color image planes!"); + // 444 images aren't downsampled, so we don't need to do linear filtering. + if (constexpr_sampler->resolution == MSL_FORMAT_RESOLUTION_444 || + constexpr_sampler->chroma_filter == MSL_SAMPLER_FILTER_NEAREST) + { + if (constexpr_sampler->planes == 2) + add_spv_func_and_recompile(SPVFuncImplChromaReconstructNearest2Plane); + else + add_spv_func_and_recompile(SPVFuncImplChromaReconstructNearest3Plane); + fname = "spvChromaReconstructNearest"; + } + else // Linear with a downsampled format + { + fname = "spvChromaReconstructLinear"; + switch (constexpr_sampler->resolution) + { + case MSL_FORMAT_RESOLUTION_444: + assert(false); + break; // not reached + case MSL_FORMAT_RESOLUTION_422: + switch (constexpr_sampler->x_chroma_offset) + { + case MSL_CHROMA_LOCATION_COSITED_EVEN: + if (constexpr_sampler->planes == 2) + add_spv_func_and_recompile(SPVFuncImplChromaReconstructLinear422CositedEven2Plane); + else + add_spv_func_and_recompile(SPVFuncImplChromaReconstructLinear422CositedEven3Plane); + fname += "422CositedEven"; + break; + case MSL_CHROMA_LOCATION_MIDPOINT: + if (constexpr_sampler->planes == 2) + add_spv_func_and_recompile(SPVFuncImplChromaReconstructLinear422Midpoint2Plane); + else + add_spv_func_and_recompile(SPVFuncImplChromaReconstructLinear422Midpoint3Plane); + fname += "422Midpoint"; + break; + default: + SPIRV_CROSS_THROW("Invalid chroma location."); + } + break; + case MSL_FORMAT_RESOLUTION_420: + fname += "420"; + switch (constexpr_sampler->x_chroma_offset) + { + case MSL_CHROMA_LOCATION_COSITED_EVEN: + switch (constexpr_sampler->y_chroma_offset) + { + case MSL_CHROMA_LOCATION_COSITED_EVEN: + if (constexpr_sampler->planes == 2) + add_spv_func_and_recompile( + SPVFuncImplChromaReconstructLinear420XCositedEvenYCositedEven2Plane); + else + add_spv_func_and_recompile( + SPVFuncImplChromaReconstructLinear420XCositedEvenYCositedEven3Plane); + fname += "XCositedEvenYCositedEven"; + break; + case MSL_CHROMA_LOCATION_MIDPOINT: + if (constexpr_sampler->planes == 2) + add_spv_func_and_recompile( + SPVFuncImplChromaReconstructLinear420XCositedEvenYMidpoint2Plane); + else + add_spv_func_and_recompile( + SPVFuncImplChromaReconstructLinear420XCositedEvenYMidpoint3Plane); + fname += "XCositedEvenYMidpoint"; + break; + default: + SPIRV_CROSS_THROW("Invalid Y chroma location."); + } + break; + case MSL_CHROMA_LOCATION_MIDPOINT: + switch (constexpr_sampler->y_chroma_offset) + { + case MSL_CHROMA_LOCATION_COSITED_EVEN: + if (constexpr_sampler->planes == 2) + add_spv_func_and_recompile( + SPVFuncImplChromaReconstructLinear420XMidpointYCositedEven2Plane); + else + add_spv_func_and_recompile( + SPVFuncImplChromaReconstructLinear420XMidpointYCositedEven3Plane); + fname += "XMidpointYCositedEven"; + break; + case MSL_CHROMA_LOCATION_MIDPOINT: + if (constexpr_sampler->planes == 2) + add_spv_func_and_recompile(SPVFuncImplChromaReconstructLinear420XMidpointYMidpoint2Plane); + else + add_spv_func_and_recompile(SPVFuncImplChromaReconstructLinear420XMidpointYMidpoint3Plane); + fname += "XMidpointYMidpoint"; + break; + default: + SPIRV_CROSS_THROW("Invalid Y chroma location."); + } + break; + default: + SPIRV_CROSS_THROW("Invalid X chroma location."); + } + break; + default: + SPIRV_CROSS_THROW("Invalid format resolution."); + } + } + } else - fname += "sample"; + { + fname = to_expression(combined ? combined->image : img) + "."; - if (has_dref) - fname += "_compare"; + // Texture function and sampler + if (is_fetch) + fname += "read"; + else if (is_gather) + fname += "gather"; + else + fname += "sample"; + + if (has_dref) + fname += "_compare"; + } return fname; } @@ -5445,26 +7515,66 @@ static inline bool sampling_type_needs_f32_conversion(const SPIRType &type) } // Returns the function args for a texture sampling function for the specified image and sampling characteristics. -string CompilerMSL::to_function_args(uint32_t img, const SPIRType &imgtype, bool is_fetch, bool is_gather, bool is_proj, - uint32_t coord, uint32_t, uint32_t dref, uint32_t grad_x, uint32_t grad_y, - uint32_t lod, uint32_t coffset, uint32_t offset, uint32_t bias, uint32_t comp, - uint32_t sample, uint32_t minlod, bool *p_forward) +string CompilerMSL::to_function_args(VariableID img, const SPIRType &imgtype, bool is_fetch, bool is_gather, + bool is_proj, uint32_t coord, uint32_t, uint32_t dref, uint32_t grad_x, + uint32_t grad_y, uint32_t lod, uint32_t coffset, uint32_t offset, uint32_t bias, + uint32_t comp, uint32_t sample, uint32_t minlod, bool *p_forward) { - string farg_str; - if (!is_fetch) - farg_str += to_sampler_expression(img); - - if (msl_options.swizzle_texture_samples && is_gather) + const MSLConstexprSampler *constexpr_sampler = nullptr; + bool is_dynamic_img_sampler = false; + if (auto *var = maybe_get_backing_variable(img)) { - if (!farg_str.empty()) - farg_str += ", "; + constexpr_sampler = find_constexpr_sampler(var->basevariable ? var->basevariable : VariableID(var->self)); + is_dynamic_img_sampler = has_extended_decoration(var->self, SPIRVCrossDecorationDynamicImageSampler); + } - auto *combined = maybe_get(img); - farg_str += to_expression(combined ? combined->image : img); + string farg_str; + bool forward = true; + + if (!is_dynamic_img_sampler) + { + // Texture reference (for some cases) + if (needs_chroma_reconstruction(constexpr_sampler)) + { + // Multiplanar images need two or three textures. + farg_str += to_expression(img); + for (uint32_t i = 1; i < constexpr_sampler->planes; i++) + farg_str += join(", ", to_expression(img), plane_name_suffix, i); + } + else if ((!constexpr_sampler || !constexpr_sampler->ycbcr_conversion_enable) && + msl_options.swizzle_texture_samples && is_gather) + { + auto *combined = maybe_get(img); + farg_str += to_expression(combined ? combined->image : img); + } + + // Sampler reference + if (!is_fetch) + { + if (!farg_str.empty()) + farg_str += ", "; + farg_str += to_sampler_expression(img); + } + + if ((!constexpr_sampler || !constexpr_sampler->ycbcr_conversion_enable) && + msl_options.swizzle_texture_samples && is_gather) + { + // Add the swizzle constant from the swizzle buffer. + farg_str += ", " + to_swizzle_expression(img); + used_swizzle_buffer = true; + } + + // Swizzled gather puts the component before the other args, to allow template + // deduction to work. + if (comp && msl_options.swizzle_texture_samples) + { + forward = should_forward(comp); + farg_str += ", " + to_component_argument(comp); + } } // Texture coordinates - bool forward = should_forward(coord); + forward = forward && should_forward(coord); auto coord_expr = to_enclosed_expression(coord); auto &coord_type = expression_type(coord); bool coord_is_fp = type_is_floating_point(coord_type); @@ -5485,6 +7595,14 @@ string CompilerMSL::to_function_args(uint32_t img, const SPIRType &imgtype, bool else if (sampling_type_needs_f32_conversion(coord_type)) tex_coords = convert_to_f32(tex_coords, 1); + if (msl_options.texture_1D_as_2D) + { + if (is_fetch) + tex_coords = "uint2(" + tex_coords + ", 0)"; + else + tex_coords = "float2(" + tex_coords + ", 0.5)"; + } + alt_coord_component = 1; break; @@ -5499,14 +7617,27 @@ string CompilerMSL::to_function_args(uint32_t img, const SPIRType &imgtype, bool else { // Metal texel buffer textures are 2D, so convert 1D coord to 2D. + // Support for Metal 2.1's new texture_buffer type. if (is_fetch) - tex_coords = "spvTexelBufferCoord(" + round_fp_tex_coords(tex_coords, coord_is_fp) + ")"; + { + if (msl_options.texel_buffer_texture_width > 0) + { + tex_coords = "spvTexelBufferCoord(" + round_fp_tex_coords(tex_coords, coord_is_fp) + ")"; + } + else + { + tex_coords = "spvTexelBufferCoord(" + round_fp_tex_coords(tex_coords, coord_is_fp) + ", " + + to_expression(img) + ")"; + } + } } alt_coord_component = 1; break; case DimSubpassData: + // If we're using Metal's native frame-buffer fetch API for subpass inputs, + // this path will not be hit. if (imgtype.image.ms) tex_coords = "uint2(gl_FragCoord.xy)"; else @@ -5592,28 +7723,46 @@ string CompilerMSL::to_function_args(uint32_t img, const SPIRType &imgtype, bool if (!farg_str.empty()) farg_str += ", "; - farg_str += tex_coords; - // If fetch from cube, add face explicitly - if (is_cube_fetch) + if (imgtype.image.dim == DimCube && imgtype.image.arrayed && msl_options.emulate_cube_array) { - // Special case for cube arrays, face and layer are packed in one dimension. - if (imgtype.image.arrayed) - farg_str += ", uint(" + to_extract_component_expression(coord, 2) + ") % 6u"; - else - farg_str += ", uint(" + round_fp_tex_coords(to_extract_component_expression(coord, 2), coord_is_fp) + ")"; - } + farg_str += "spvCubemapTo2DArrayFace(" + tex_coords + ").xy"; - // If array, use alt coord - if (imgtype.image.arrayed) - { - // Special case for cube arrays, face and layer are packed in one dimension. - if (imgtype.image.dim == DimCube && is_fetch) - farg_str += ", uint(" + to_extract_component_expression(coord, 2) + ") / 6u"; + if (is_cube_fetch) + farg_str += ", uint(" + to_extract_component_expression(coord, 2) + ")"; else - farg_str += ", uint(" + + farg_str += ", uint(spvCubemapTo2DArrayFace(" + tex_coords + ").z) + (uint(" + round_fp_tex_coords(to_extract_component_expression(coord, alt_coord_component), coord_is_fp) + - ")"; + ") * 6u)"; + + add_spv_func_and_recompile(SPVFuncImplCubemapTo2DArrayFace); + } + else + { + farg_str += tex_coords; + + // If fetch from cube, add face explicitly + if (is_cube_fetch) + { + // Special case for cube arrays, face and layer are packed in one dimension. + if (imgtype.image.arrayed) + farg_str += ", uint(" + to_extract_component_expression(coord, 2) + ") % 6u"; + else + farg_str += + ", uint(" + round_fp_tex_coords(to_extract_component_expression(coord, 2), coord_is_fp) + ")"; + } + + // If array, use alt coord + if (imgtype.image.arrayed) + { + // Special case for cube arrays, face and layer are packed in one dimension. + if (imgtype.image.dim == DimCube && is_fetch) + farg_str += ", uint(" + to_extract_component_expression(coord, 2) + ") / 6u"; + else + farg_str += + ", uint(" + + round_fp_tex_coords(to_extract_component_expression(coord, alt_coord_component), coord_is_fp) + ")"; + } } // Depth compare reference value @@ -5676,14 +7825,14 @@ string CompilerMSL::to_function_args(uint32_t img, const SPIRType &imgtype, bool // LOD Options // Metal does not support LOD for 1D textures. - if (bias && imgtype.image.dim != Dim1D) + if (bias && (imgtype.image.dim != Dim1D || msl_options.texture_1D_as_2D)) { forward = forward && should_forward(bias); farg_str += ", bias(" + to_expression(bias) + ")"; } // Metal does not support LOD for 1D textures. - if (lod && imgtype.image.dim != Dim1D) + if (lod && (imgtype.image.dim != Dim1D || msl_options.texture_1D_as_2D)) { forward = forward && should_forward(lod); if (is_fetch) @@ -5695,8 +7844,8 @@ string CompilerMSL::to_function_args(uint32_t img, const SPIRType &imgtype, bool farg_str += ", level(" + to_expression(lod) + ")"; } } - else if (is_fetch && !lod && imgtype.image.dim != Dim1D && imgtype.image.dim != DimBuffer && !imgtype.image.ms && - imgtype.image.sampled != 2) + else if (is_fetch && !lod && (imgtype.image.dim != Dim1D || msl_options.texture_1D_as_2D) && + imgtype.image.dim != DimBuffer && !imgtype.image.ms && imgtype.image.sampled != 2) { // Lod argument is optional in OpImageFetch, but we require a LOD value, pick 0 as the default. // Check for sampled type as well, because is_fetch is also used for OpImageRead in MSL. @@ -5704,7 +7853,7 @@ string CompilerMSL::to_function_args(uint32_t img, const SPIRType &imgtype, bool } // Metal does not support LOD for 1D textures. - if ((grad_x || grad_y) && imgtype.image.dim != Dim1D) + if ((grad_x || grad_y) && (imgtype.image.dim != Dim1D || msl_options.texture_1D_as_2D)) { forward = forward && should_forward(grad_x); forward = forward && should_forward(grad_y); @@ -5718,7 +7867,10 @@ string CompilerMSL::to_function_args(uint32_t img, const SPIRType &imgtype, bool grad_opt = "3d"; break; case DimCube: - grad_opt = "cube"; + if (imgtype.image.arrayed && msl_options.emulate_cube_array) + grad_opt = "2d"; + else + grad_opt = "cube"; break; default: grad_opt = "unsupported_gradient_dimension"; @@ -5783,8 +7935,11 @@ string CompilerMSL::to_function_args(uint32_t img, const SPIRType &imgtype, bool if (imgtype.image.dim == Dim2D && offset_expr.empty()) farg_str += ", int2(0)"; - forward = forward && should_forward(comp); - farg_str += ", " + to_component_argument(comp); + if (!msl_options.swizzle_texture_samples || is_dynamic_img_sampler) + { + forward = forward && should_forward(comp); + farg_str += ", " + to_component_argument(comp); + } } if (sample) @@ -5794,15 +7949,6 @@ string CompilerMSL::to_function_args(uint32_t img, const SPIRType &imgtype, bool farg_str += to_expression(sample); } - if (msl_options.swizzle_texture_samples && is_sampled_image_type(imgtype)) - { - // Add the swizzle constant from the swizzle buffer. - if (!is_gather) - farg_str += ")"; - farg_str += ", " + to_swizzle_expression(img); - used_swizzle_buffer = true; - } - *p_forward = forward; return farg_str; @@ -5849,14 +7995,218 @@ void CompilerMSL::emit_sampled_image_op(uint32_t result_type, uint32_t result_id set(result_id, result_type, image_id, samp_id); } +string CompilerMSL::to_texture_op(const Instruction &i, bool *forward, SmallVector &inherited_expressions) +{ + auto *ops = stream(i); + uint32_t result_type_id = ops[0]; + uint32_t img = ops[2]; + auto &result_type = get(result_type_id); + auto op = static_cast(i.op); + bool is_gather = (op == OpImageGather || op == OpImageDrefGather); + + // Bypass pointers because we need the real image struct + auto &type = expression_type(img); + auto &imgtype = get(type.self); + + const MSLConstexprSampler *constexpr_sampler = nullptr; + bool is_dynamic_img_sampler = false; + if (auto *var = maybe_get_backing_variable(img)) + { + constexpr_sampler = find_constexpr_sampler(var->basevariable ? var->basevariable : VariableID(var->self)); + is_dynamic_img_sampler = has_extended_decoration(var->self, SPIRVCrossDecorationDynamicImageSampler); + } + + string expr; + if (constexpr_sampler && constexpr_sampler->ycbcr_conversion_enable && !is_dynamic_img_sampler) + { + // If this needs sampler Y'CbCr conversion, we need to do some additional + // processing. + switch (constexpr_sampler->ycbcr_model) + { + case MSL_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_BT_709: + add_spv_func_and_recompile(SPVFuncImplConvertYCbCrBT709); + expr += "spvConvertYCbCrBT709("; + break; + case MSL_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_BT_601: + add_spv_func_and_recompile(SPVFuncImplConvertYCbCrBT601); + expr += "spvConvertYCbCrBT601("; + break; + case MSL_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_BT_2020: + add_spv_func_and_recompile(SPVFuncImplConvertYCbCrBT2020); + expr += "spvConvertYCbCrBT2020("; + break; + default: + SPIRV_CROSS_THROW("Invalid Y'CbCr model conversion."); + } + + if (constexpr_sampler->ycbcr_model != MSL_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY) + { + switch (constexpr_sampler->ycbcr_range) + { + case MSL_SAMPLER_YCBCR_RANGE_ITU_FULL: + add_spv_func_and_recompile(SPVFuncImplExpandITUFullRange); + expr += "spvExpandITUFullRange("; + break; + case MSL_SAMPLER_YCBCR_RANGE_ITU_NARROW: + add_spv_func_and_recompile(SPVFuncImplExpandITUNarrowRange); + expr += "spvExpandITUNarrowRange("; + break; + default: + SPIRV_CROSS_THROW("Invalid Y'CbCr range."); + } + } + } + else if (msl_options.swizzle_texture_samples && !is_gather && is_sampled_image_type(imgtype) && + !is_dynamic_img_sampler) + { + add_spv_func_and_recompile(SPVFuncImplTextureSwizzle); + expr += "spvTextureSwizzle("; + } + + string inner_expr = CompilerGLSL::to_texture_op(i, forward, inherited_expressions); + + if (constexpr_sampler && constexpr_sampler->ycbcr_conversion_enable && !is_dynamic_img_sampler) + { + if (!constexpr_sampler->swizzle_is_identity()) + { + static const char swizzle_names[] = "rgba"; + if (!constexpr_sampler->swizzle_has_one_or_zero()) + { + // If we can, do it inline. + expr += inner_expr + "."; + for (uint32_t c = 0; c < 4; c++) + { + switch (constexpr_sampler->swizzle[c]) + { + case MSL_COMPONENT_SWIZZLE_IDENTITY: + expr += swizzle_names[c]; + break; + case MSL_COMPONENT_SWIZZLE_R: + case MSL_COMPONENT_SWIZZLE_G: + case MSL_COMPONENT_SWIZZLE_B: + case MSL_COMPONENT_SWIZZLE_A: + expr += swizzle_names[constexpr_sampler->swizzle[c] - MSL_COMPONENT_SWIZZLE_R]; + break; + default: + SPIRV_CROSS_THROW("Invalid component swizzle."); + } + } + } + else + { + // Otherwise, we need to emit a temporary and swizzle that. + uint32_t temp_id = ir.increase_bound_by(1); + emit_op(result_type_id, temp_id, inner_expr, false); + for (auto &inherit : inherited_expressions) + inherit_expression_dependencies(temp_id, inherit); + inherited_expressions.clear(); + inherited_expressions.push_back(temp_id); + + switch (op) + { + case OpImageSampleDrefImplicitLod: + case OpImageSampleImplicitLod: + case OpImageSampleProjImplicitLod: + case OpImageSampleProjDrefImplicitLod: + register_control_dependent_expression(temp_id); + break; + + default: + break; + } + expr += type_to_glsl(result_type) + "("; + for (uint32_t c = 0; c < 4; c++) + { + switch (constexpr_sampler->swizzle[c]) + { + case MSL_COMPONENT_SWIZZLE_IDENTITY: + expr += to_expression(temp_id) + "." + swizzle_names[c]; + break; + case MSL_COMPONENT_SWIZZLE_ZERO: + expr += "0"; + break; + case MSL_COMPONENT_SWIZZLE_ONE: + expr += "1"; + break; + case MSL_COMPONENT_SWIZZLE_R: + case MSL_COMPONENT_SWIZZLE_G: + case MSL_COMPONENT_SWIZZLE_B: + case MSL_COMPONENT_SWIZZLE_A: + expr += to_expression(temp_id) + "." + + swizzle_names[constexpr_sampler->swizzle[c] - MSL_COMPONENT_SWIZZLE_R]; + break; + default: + SPIRV_CROSS_THROW("Invalid component swizzle."); + } + if (c < 3) + expr += ", "; + } + expr += ")"; + } + } + else + expr += inner_expr; + if (constexpr_sampler->ycbcr_model != MSL_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY) + { + expr += join(", ", constexpr_sampler->bpc, ")"); + if (constexpr_sampler->ycbcr_model != MSL_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY) + expr += ")"; + } + } + else + { + expr += inner_expr; + if (msl_options.swizzle_texture_samples && !is_gather && is_sampled_image_type(imgtype) && + !is_dynamic_img_sampler) + { + // Add the swizzle constant from the swizzle buffer. + expr += ", " + to_swizzle_expression(img) + ")"; + used_swizzle_buffer = true; + } + } + + return expr; +} + +static string create_swizzle(MSLComponentSwizzle swizzle) +{ + switch (swizzle) + { + case MSL_COMPONENT_SWIZZLE_IDENTITY: + return "spvSwizzle::none"; + case MSL_COMPONENT_SWIZZLE_ZERO: + return "spvSwizzle::zero"; + case MSL_COMPONENT_SWIZZLE_ONE: + return "spvSwizzle::one"; + case MSL_COMPONENT_SWIZZLE_R: + return "spvSwizzle::red"; + case MSL_COMPONENT_SWIZZLE_G: + return "spvSwizzle::green"; + case MSL_COMPONENT_SWIZZLE_B: + return "spvSwizzle::blue"; + case MSL_COMPONENT_SWIZZLE_A: + return "spvSwizzle::alpha"; + default: + SPIRV_CROSS_THROW("Invalid component swizzle."); + return ""; + } +} + // Returns a string representation of the ID, usable as a function arg. // Manufacture automatic sampler arg for SampledImage texture. -string CompilerMSL::to_func_call_arg(uint32_t id) +string CompilerMSL::to_func_call_arg(const SPIRFunction::Parameter &arg, uint32_t id) { string arg_str; + auto &type = expression_type(id); + bool is_dynamic_img_sampler = has_extended_decoration(arg.id, SPIRVCrossDecorationDynamicImageSampler); + // If the argument *itself* is a "dynamic" combined-image sampler, then we can just pass that around. + bool arg_is_dynamic_img_sampler = has_extended_decoration(id, SPIRVCrossDecorationDynamicImageSampler); + if (is_dynamic_img_sampler && !arg_is_dynamic_img_sampler) + arg_str = join("spvDynamicImageSampler<", type_to_glsl(get(type.image.type)), ">("); + auto *c = maybe_get(id); - if (c && !get(c->constant_type).array.empty()) + if (msl_options.force_native_arrays && c && !get(c->constant_type).array.empty()) { // If we are passing a constant array directly to a function for some reason, // the callee will expect an argument in thread const address space @@ -5869,7 +8219,7 @@ string CompilerMSL::to_func_call_arg(uint32_t id) // so just create a thread local copy in the current function. arg_str = join("_", id, "_array_copy"); auto &constants = current_function->constant_arrays_needed_on_stack; - auto itr = find(begin(constants), end(constants), id); + auto itr = find(begin(constants), end(constants), ID(id)); if (itr == end(constants)) { force_recompile(); @@ -5877,34 +8227,113 @@ string CompilerMSL::to_func_call_arg(uint32_t id) } } else - arg_str = CompilerGLSL::to_func_call_arg(id); - - // Manufacture automatic sampler arg if the arg is a SampledImage texture. - auto &type = expression_type(id); - if (type.basetype == SPIRType::SampledImage && type.image.dim != DimBuffer) - { - // Need to check the base variable in case we need to apply a qualified alias. - uint32_t var_id = 0; - auto *sampler_var = maybe_get(id); - if (sampler_var) - var_id = sampler_var->basevariable; - - arg_str += ", " + to_sampler_expression(var_id ? var_id : id); - } + arg_str += CompilerGLSL::to_func_call_arg(arg, id); + // Need to check the base variable in case we need to apply a qualified alias. uint32_t var_id = 0; auto *var = maybe_get(id); if (var) var_id = var->basevariable; - if (msl_options.swizzle_texture_samples && has_sampled_images && is_sampled_image_type(type)) + if (!arg_is_dynamic_img_sampler) { - // Need to check the base variable in case we need to apply a qualified alias. - arg_str += ", " + to_swizzle_expression(var_id ? var_id : id); + auto *constexpr_sampler = find_constexpr_sampler(var_id ? var_id : id); + if (type.basetype == SPIRType::SampledImage) + { + // Manufacture automatic plane args for multiplanar texture + uint32_t planes = 1; + if (constexpr_sampler && constexpr_sampler->ycbcr_conversion_enable) + { + planes = constexpr_sampler->planes; + // If this parameter isn't aliasing a global, then we need to use + // the special "dynamic image-sampler" class to pass it--and we need + // to use it for *every* non-alias parameter, in case a combined + // image-sampler with a Y'CbCr conversion is passed. Hopefully, this + // pathological case is so rare that it should never be hit in practice. + if (!arg.alias_global_variable) + add_spv_func_and_recompile(SPVFuncImplDynamicImageSampler); + } + for (uint32_t i = 1; i < planes; i++) + arg_str += join(", ", CompilerGLSL::to_func_call_arg(arg, id), plane_name_suffix, i); + // Manufacture automatic sampler arg if the arg is a SampledImage texture. + if (type.image.dim != DimBuffer) + arg_str += ", " + to_sampler_expression(var_id ? var_id : id); + + // Add sampler Y'CbCr conversion info if we have it + if (is_dynamic_img_sampler && constexpr_sampler && constexpr_sampler->ycbcr_conversion_enable) + { + SmallVector samp_args; + + switch (constexpr_sampler->resolution) + { + case MSL_FORMAT_RESOLUTION_444: + // Default + break; + case MSL_FORMAT_RESOLUTION_422: + samp_args.push_back("spvFormatResolution::_422"); + break; + case MSL_FORMAT_RESOLUTION_420: + samp_args.push_back("spvFormatResolution::_420"); + break; + default: + SPIRV_CROSS_THROW("Invalid format resolution."); + } + + if (constexpr_sampler->chroma_filter != MSL_SAMPLER_FILTER_NEAREST) + samp_args.push_back("spvChromaFilter::linear"); + + if (constexpr_sampler->x_chroma_offset != MSL_CHROMA_LOCATION_COSITED_EVEN) + samp_args.push_back("spvXChromaLocation::midpoint"); + if (constexpr_sampler->y_chroma_offset != MSL_CHROMA_LOCATION_COSITED_EVEN) + samp_args.push_back("spvYChromaLocation::midpoint"); + switch (constexpr_sampler->ycbcr_model) + { + case MSL_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY: + // Default + break; + case MSL_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY: + samp_args.push_back("spvYCbCrModelConversion::ycbcr_identity"); + break; + case MSL_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_BT_709: + samp_args.push_back("spvYCbCrModelConversion::ycbcr_bt_709"); + break; + case MSL_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_BT_601: + samp_args.push_back("spvYCbCrModelConversion::ycbcr_bt_601"); + break; + case MSL_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_BT_2020: + samp_args.push_back("spvYCbCrModelConversion::ycbcr_bt_2020"); + break; + default: + SPIRV_CROSS_THROW("Invalid Y'CbCr model conversion."); + } + if (constexpr_sampler->ycbcr_range != MSL_SAMPLER_YCBCR_RANGE_ITU_FULL) + samp_args.push_back("spvYCbCrRange::itu_narrow"); + samp_args.push_back(join("spvComponentBits(", constexpr_sampler->bpc, ")")); + arg_str += join(", spvYCbCrSampler(", merge(samp_args), ")"); + } + } + + if (is_dynamic_img_sampler && constexpr_sampler && constexpr_sampler->ycbcr_conversion_enable) + arg_str += join(", (uint(", create_swizzle(constexpr_sampler->swizzle[3]), ") << 24) | (uint(", + create_swizzle(constexpr_sampler->swizzle[2]), ") << 16) | (uint(", + create_swizzle(constexpr_sampler->swizzle[1]), ") << 8) | uint(", + create_swizzle(constexpr_sampler->swizzle[0]), ")"); + else if (msl_options.swizzle_texture_samples && has_sampled_images && is_sampled_image_type(type)) + arg_str += ", " + to_swizzle_expression(var_id ? var_id : id); + + if (buffers_requiring_array_length.count(var_id)) + arg_str += ", " + to_buffer_size_expression(var_id ? var_id : id); + + if (is_dynamic_img_sampler) + arg_str += ")"; } - if (buffers_requiring_array_length.count(var_id)) - arg_str += ", " + to_buffer_size_expression(var_id ? var_id : id); + // Emulate texture2D atomic operations + auto *backing_var = maybe_get_backing_variable(var_id); + if (backing_var && atomic_image_vars.count(backing_var->self)) + { + arg_str += ", " + to_expression(var_id) + "_atomic"; + } return arg_str; } @@ -5915,7 +8344,7 @@ string CompilerMSL::to_func_call_arg(uint32_t id) string CompilerMSL::to_sampler_expression(uint32_t id) { auto *combined = maybe_get(id); - auto expr = to_expression(combined ? combined->image : id); + auto expr = to_expression(combined ? combined->image : VariableID(id)); auto index = expr.find_first_of('['); uint32_t samp_id = 0; @@ -5936,7 +8365,7 @@ string CompilerMSL::to_swizzle_expression(uint32_t id) { auto *combined = maybe_get(id); - auto expr = to_expression(combined ? combined->image : id); + auto expr = to_expression(combined ? combined->image : VariableID(id)); auto index = expr.find_first_of('['); // If an image is part of an argument buffer translate this to a legal identifier. @@ -6054,6 +8483,7 @@ string CompilerMSL::to_struct_member(const SPIRType &type, uint32_t member_type_ // If this member is packed, mark it as so. string pack_pfx; + // Allow Metal to use the array template to make arrays a value type uint32_t orig_id = 0; if (has_extended_member_decoration(type.self, index, SPIRVCrossDecorationInterfaceOrigID)) orig_id = get_extended_member_decoration(type.self, index, SPIRVCrossDecorationInterfaceOrigID); @@ -6065,6 +8495,17 @@ string CompilerMSL::to_struct_member(const SPIRType &type, uint32_t member_type_ SPIRType row_major_physical_type; const SPIRType *declared_type = &physical_type; + // If a struct is being declared with physical layout, + // do not use array wrappers. + // This avoids a lot of complicated cases with packed vectors and matrices, + // and generally we cannot copy full arrays in and out of buffers into Function + // address space. + // Array of resources should also be declared as builtin arrays. + if (has_member_decoration(type.self, index, DecorationOffset)) + is_using_builtin_array = true; + else if (has_extended_member_decoration(type.self, index, SPIRVCrossDecorationResourceIndexPrimary)) + is_using_builtin_array = true; + if (member_is_packed_physical_type(type, index)) { // If we're packing a matrix, output an appropriate typedef @@ -6117,11 +8558,17 @@ string CompilerMSL::to_struct_member(const SPIRType &type, uint32_t member_type_ if (physical_type.basetype != SPIRType::Image && physical_type.basetype != SPIRType::Sampler && physical_type.basetype != SPIRType::SampledImage) { + BuiltIn builtin = BuiltInMax; + if (is_member_builtin(type, index, &builtin)) + is_using_builtin_array = true; array_type = type_to_array_glsl(physical_type); } - return join(pack_pfx, type_to_glsl(*declared_type, orig_id), " ", qualifier, to_member_name(type, index), - member_attribute_qualifier(type, index), array_type, ";"); + auto result = join(pack_pfx, type_to_glsl(*declared_type, orig_id), " ", qualifier, to_member_name(type, index), + member_attribute_qualifier(type, index), array_type, ";"); + + is_using_builtin_array = false; + return result; } // Emit a structure member, padding and packing to maintain the correct memeber alignments. @@ -6135,7 +8582,10 @@ void CompilerMSL::emit_struct_member(const SPIRType &type, uint32_t member_type_ statement("char _m", index, "_pad", "[", pad_len, "];"); } + // Handle HLSL-style 0-based vertex/instance index. + builtin_declaration = true; statement(to_struct_member(type, member_type_id, index, qualifier)); + builtin_declaration = false; } void CompilerMSL::emit_struct_padding_target(const SPIRType &type) @@ -6160,8 +8610,15 @@ string CompilerMSL::member_attribute_qualifier(const SPIRType &type, uint32_t in bool is_builtin = is_member_builtin(type, index, &builtin); if (has_extended_member_decoration(type.self, index, SPIRVCrossDecorationResourceIndexPrimary)) - return join(" [[id(", - get_extended_member_decoration(type.self, index, SPIRVCrossDecorationResourceIndexPrimary), ")]]"); + { + string quals = join( + " [[id(", get_extended_member_decoration(type.self, index, SPIRVCrossDecorationResourceIndexPrimary), ")"); + if (interlocked_resources.count( + get_extended_member_decoration(type.self, index, SPIRVCrossDecorationInterfaceOrigID))) + quals += ", raster_order_group(0)"; + quals += "]]"; + return quals; + } // Vertex function inputs if (execution.model == ExecutionModelVertex && type.storage == StorageClassInput) @@ -6211,9 +8668,14 @@ string CompilerMSL::member_attribute_qualifier(const SPIRType &type, uint32_t in /* fallthrough */ case BuiltInPosition: case BuiltInLayer: - case BuiltInClipDistance: return string(" [[") + builtin_qualifier(builtin) + "]]" + (mbr_type.array.empty() ? "" : " "); + case BuiltInClipDistance: + if (has_member_decoration(type.self, index, DecorationLocation)) + return join(" [[user(clip", get_member_decoration(type.self, index, DecorationLocation), ")]]"); + else + return string(" [[") + builtin_qualifier(builtin) + "]]" + (mbr_type.array.empty() ? "" : " "); + default: return ""; } @@ -6311,6 +8773,9 @@ string CompilerMSL::member_attribute_qualifier(const SPIRType &type, uint32_t in quals = builtin_qualifier(builtin); break; + case BuiltInClipDistance: + return join(" [[user(clip", get_member_decoration(type.self, index, DecorationLocation), ")]]"); + default: break; } @@ -6321,7 +8786,14 @@ string CompilerMSL::member_attribute_qualifier(const SPIRType &type, uint32_t in uint32_t locn = get_ordered_member_location(type.self, index, &comp); if (locn != k_unknown_location) { - if (comp != k_unknown_component) + // For user-defined attributes, this is fine. From Vulkan spec: + // A user-defined output variable is considered to match an input variable in the subsequent stage if + // the two variables are declared with the same Location and Component decoration and match in type + // and decoration, except that interpolation decorations are not required to match. For the purposes + // of interface matching, variables declared without a Component decoration are considered to have a + // Component decoration of zero. + + if (comp != k_unknown_component && comp != 0) quals = string("user(locn") + convert_to_string(locn) + "_" + convert_to_string(comp) + ")"; else quals = string("user(locn") + convert_to_string(locn) + ")"; @@ -6527,80 +8999,15 @@ string CompilerMSL::func_type_decl(SPIRType &type) string CompilerMSL::get_argument_address_space(const SPIRVariable &argument) { const auto &type = get(argument.basetype); - Bitset flags; - if (type.basetype == SPIRType::Struct && - (has_decoration(type.self, DecorationBlock) || has_decoration(type.self, DecorationBufferBlock))) - flags = ir.get_buffer_block_flags(argument); - else - flags = get_decoration_bitset(argument.self); - const char *addr_space = nullptr; - - switch (type.storage) - { - case StorageClassWorkgroup: - addr_space = "threadgroup"; - break; - - case StorageClassStorageBuffer: - { - // For arguments from variable pointers, we use the write count deduction, so - // we should not assume any constness here. Only for global SSBOs. - bool readonly = false; - if (has_decoration(type.self, DecorationBlock)) - readonly = flags.get(DecorationNonWritable); - - addr_space = readonly ? "const device" : "device"; - break; - } - - case StorageClassUniform: - case StorageClassUniformConstant: - case StorageClassPushConstant: - if (type.basetype == SPIRType::Struct) - { - bool ssbo = has_decoration(type.self, DecorationBufferBlock); - if (ssbo) - { - bool readonly = flags.get(DecorationNonWritable); - addr_space = readonly ? "const device" : "device"; - } - else - addr_space = "constant"; - break; - } - break; - - case StorageClassFunction: - case StorageClassGeneric: - // No address space for plain values. - addr_space = type.pointer ? "thread" : ""; - break; - - case StorageClassInput: - if (get_execution_model() == ExecutionModelTessellationControl && argument.basevariable == stage_in_ptr_var_id) - addr_space = "threadgroup"; - break; - - case StorageClassOutput: - if (capture_output_to_buffer) - addr_space = "device"; - break; - - default: - break; - } - - if (!addr_space) - addr_space = "thread"; - - return join(flags.get(DecorationVolatile) || flags.get(DecorationCoherent) ? "volatile " : "", addr_space); + return get_type_address_space(type, argument.self, true); } -string CompilerMSL::get_type_address_space(const SPIRType &type, uint32_t id) +string CompilerMSL::get_type_address_space(const SPIRType &type, uint32_t id, bool argument) { // This can be called for variable pointer contexts as well, so be very careful about which method we choose. Bitset flags; - if (ir.ids[id].get_type() == TypeVariable && type.basetype == SPIRType::Struct && + auto *var = maybe_get(id); + if (var && type.basetype == SPIRType::Struct && (has_decoration(type.self, DecorationBlock) || has_decoration(type.self, DecorationBufferBlock))) flags = get_buffer_block_flags(id); else @@ -6614,8 +9021,16 @@ string CompilerMSL::get_type_address_space(const SPIRType &type, uint32_t id) break; case StorageClassStorageBuffer: - addr_space = flags.get(DecorationNonWritable) ? "const device" : "device"; + { + // For arguments from variable pointers, we use the write count deduction, so + // we should not assume any constness here. Only for global SSBOs. + bool readonly = false; + if (!var || has_decoration(type.self, DecorationBlock)) + readonly = flags.get(DecorationNonWritable); + + addr_space = readonly ? "const device" : "device"; break; + } case StorageClassUniform: case StorageClassUniformConstant: @@ -6628,14 +9043,18 @@ string CompilerMSL::get_type_address_space(const SPIRType &type, uint32_t id) else addr_space = "constant"; } - else + else if (!argument) addr_space = "constant"; break; case StorageClassFunction: case StorageClassGeneric: - // No address space for plain values. - addr_space = type.pointer ? "thread" : ""; + break; + + case StorageClassInput: + if (get_execution_model() == ExecutionModelTessellationControl && var && + var->basevariable == stage_in_ptr_var_id) + addr_space = "threadgroup"; break; case StorageClassOutput: @@ -6648,7 +9067,8 @@ string CompilerMSL::get_type_address_space(const SPIRType &type, uint32_t id) } if (!addr_space) - addr_space = "thread"; + // No address space for plain values. + addr_space = type.pointer || (argument && type.basetype == SPIRType::ControlPointArray) ? "thread" : ""; return join(flags.get(DecorationVolatile) || flags.get(DecorationCoherent) ? "volatile " : "", addr_space); } @@ -6735,6 +9155,8 @@ void CompilerMSL::entry_point_args_builtin(string &ep_args) if (!ep_args.empty()) ep_args += ", "; + // Handle HLSL-style 0-based vertex/instance index. + builtin_declaration = true; ep_args += builtin_type_decl(bi_type, var_id) + " " + to_expression(var_id); ep_args += " [[" + builtin_qualifier(bi_type); if (bi_type == BuiltInSampleMask && get_entry_point().flags.get(ExecutionModePostDepthCoverage)) @@ -6746,8 +9168,22 @@ void CompilerMSL::entry_point_args_builtin(string &ep_args) ep_args += ", post_depth_coverage"; } ep_args += "]]"; + builtin_declaration = false; } } + + if (var.storage == StorageClassInput && + has_extended_decoration(var_id, SPIRVCrossDecorationBuiltInDispatchBase)) + { + // This is a special implicit builtin, not corresponding to any SPIR-V builtin, + // which holds the base that was passed to vkCmdDispatchBase(). If it's present, + // assume we emitted it for a good reason. + assert(msl_options.supports_msl_version(1, 2)); + if (!ep_args.empty()) + ep_args += ", "; + + ep_args += type_to_glsl(get_variable_data_type(var)) + " " + to_expression(var_id) + " [[grid_origin]]"; + } }); // Correct the types of all encountered active builtins. We couldn't do this before @@ -6756,12 +9192,12 @@ void CompilerMSL::entry_point_args_builtin(string &ep_args) for (auto &var : active_builtins) var.first->basetype = ensure_correct_builtin_type(var.first->basetype, var.second); - // Vertex and instance index built-ins - if (needs_vertex_idx_arg) - ep_args += built_in_func_arg(BuiltInVertexIndex, !ep_args.empty()); + // Handle HLSL-style 0-based vertex/instance index. + if (needs_base_vertex_arg == TriState::Yes) + ep_args += built_in_func_arg(BuiltInBaseVertex, !ep_args.empty()); - if (needs_instance_idx_arg) - ep_args += built_in_func_arg(BuiltInInstanceIndex, !ep_args.empty()); + if (needs_base_instance_arg == TriState::Yes) + ep_args += built_in_func_arg(BuiltInBaseInstance, !ep_args.empty()); if (capture_output_to_buffer) { @@ -6905,19 +9341,25 @@ void CompilerMSL::entry_point_args_discrete_descriptors(string &ep_args) string name; SPIRType::BaseType basetype; uint32_t index; + uint32_t plane; + uint32_t secondary_index; }; SmallVector resources; - ir.for_each_typed_id([&](uint32_t, SPIRVariable &var) { + ir.for_each_typed_id([&](uint32_t var_id, SPIRVariable &var) { if ((var.storage == StorageClassUniform || var.storage == StorageClassUniformConstant || var.storage == StorageClassPushConstant || var.storage == StorageClassStorageBuffer) && !is_hidden_variable(var)) { auto &type = get_variable_data_type(var); - uint32_t var_id = var.self; - if (var.storage != StorageClassPushConstant) + // Very specifically, image load-store in argument buffers are disallowed on MSL on iOS. + // But we won't know when the argument buffer is encoded whether this image will have + // a NonWritable decoration. So just use discrete arguments for all storage images + // on iOS. + if (!(msl_options.is_ios() && type.basetype == SPIRType::Image && type.image.sampled == 2) && + var.storage != StorageClassPushConstant) { uint32_t desc_set = get_decoration(var_id, DecorationDescriptorSet); if (descriptor_set_is_argument_buffer(desc_set)) @@ -6935,24 +9377,37 @@ void CompilerMSL::entry_point_args_discrete_descriptors(string &ep_args) } } + // Emulate texture2D atomic operations + uint32_t secondary_index = 0; + if (atomic_image_vars.count(var.self)) + { + secondary_index = get_metal_resource_index(var, SPIRType::AtomicCounter, 0); + } + if (type.basetype == SPIRType::SampledImage) { add_resource_name(var_id); - resources.push_back( - { &var, to_name(var_id), SPIRType::Image, get_metal_resource_index(var, SPIRType::Image) }); + + uint32_t plane_count = 1; + if (constexpr_sampler && constexpr_sampler->ycbcr_conversion_enable) + plane_count = constexpr_sampler->planes; + + for (uint32_t i = 0; i < plane_count; i++) + resources.push_back({ &var, to_name(var_id), SPIRType::Image, + get_metal_resource_index(var, SPIRType::Image, i), i, secondary_index }); if (type.image.dim != DimBuffer && !constexpr_sampler) { resources.push_back({ &var, to_sampler_expression(var_id), SPIRType::Sampler, - get_metal_resource_index(var, SPIRType::Sampler) }); + get_metal_resource_index(var, SPIRType::Sampler), 0, 0 }); } } else if (!constexpr_sampler) { // constexpr samplers are not declared as resources. add_resource_name(var_id); - resources.push_back( - { &var, to_name(var_id), type.basetype, get_metal_resource_index(var, type.basetype) }); + resources.push_back({ &var, to_name(var_id), type.basetype, + get_metal_resource_index(var, type.basetype), 0, secondary_index }); } } }); @@ -6988,6 +9443,8 @@ void CompilerMSL::entry_point_args_discrete_descriptors(string &ep_args) if (array_size == 0) SPIRV_CROSS_THROW("Unsized arrays of buffers are not supported in MSL."); + // Allow Metal to use the array template to make arrays a value type + is_using_builtin_array = true; buffer_arrays.push_back(var_id); for (uint32_t i = 0; i < array_size; ++i) { @@ -6995,8 +9452,12 @@ void CompilerMSL::entry_point_args_discrete_descriptors(string &ep_args) ep_args += ", "; ep_args += get_argument_address_space(var) + " " + type_to_glsl(type) + "* " + to_restrict(var_id) + r.name + "_" + convert_to_string(i); - ep_args += " [[buffer(" + convert_to_string(r.index + i) + ")]]"; + ep_args += " [[buffer(" + convert_to_string(r.index + i) + ")"; + if (interlocked_resources.count(var_id)) + ep_args += ", raster_order_group(0)"; + ep_args += "]]"; } + is_using_builtin_array = false; } else { @@ -7004,7 +9465,10 @@ void CompilerMSL::entry_point_args_discrete_descriptors(string &ep_args) ep_args += ", "; ep_args += get_argument_address_space(var) + " " + type_to_glsl(type) + "& " + to_restrict(var_id) + r.name; - ep_args += " [[buffer(" + convert_to_string(r.index) + ")]]"; + ep_args += " [[buffer(" + convert_to_string(r.index) + ")"; + if (interlocked_resources.count(var_id)) + ep_args += ", raster_order_group(0)"; + ep_args += "]]"; } break; } @@ -7015,16 +9479,50 @@ void CompilerMSL::entry_point_args_discrete_descriptors(string &ep_args) ep_args += " [[sampler(" + convert_to_string(r.index) + ")]]"; break; case SPIRType::Image: + { if (!ep_args.empty()) ep_args += ", "; - ep_args += image_type_glsl(type, var_id) + " " + r.name; - ep_args += " [[texture(" + convert_to_string(r.index) + ")]]"; + + // Use Metal's native frame-buffer fetch API for subpass inputs. + const auto &basetype = get(var.basetype); + if (basetype.image.dim != DimSubpassData || !msl_options.is_ios() || + !msl_options.ios_use_framebuffer_fetch_subpasses) + { + ep_args += image_type_glsl(type, var_id) + " " + r.name; + if (r.plane > 0) + ep_args += join(plane_name_suffix, r.plane); + ep_args += " [[texture(" + convert_to_string(r.index) + ")"; + if (interlocked_resources.count(var_id)) + ep_args += ", raster_order_group(0)"; + ep_args += "]]"; + } + else + { + ep_args += image_type_glsl(type, var_id) + "4 " + r.name; + ep_args += " [[color(" + convert_to_string(r.index) + ")]]"; + } + + // Emulate texture2D atomic operations + if (atomic_image_vars.count(var.self)) + { + ep_args += ", device atomic_" + type_to_glsl(get(basetype.image.type), 0); + ep_args += "* " + r.name + "_atomic"; + ep_args += " [[buffer(" + convert_to_string(r.secondary_index) + ")]]"; + } break; + } default: if (!ep_args.empty()) ep_args += ", "; - ep_args += type_to_glsl(type, var_id) + " " + r.name; - ep_args += " [[buffer(" + convert_to_string(r.index) + ")]]"; + if (!type.pointer) + ep_args += get_type_address_space(get(var.basetype), var_id) + " " + + type_to_glsl(type, var_id) + "& " + r.name; + else + ep_args += type_to_glsl(type, var_id) + " " + r.name; + ep_args += " [[buffer(" + convert_to_string(r.index) + ")"; + if (interlocked_resources.count(var_id)) + ep_args += ", raster_order_group(0)"; + ep_args += "]]"; break; } } @@ -7343,6 +9841,35 @@ void CompilerMSL::fix_up_shader_inputs_outputs() msl_options.device_index, ";"); }); break; + case BuiltInWorkgroupId: + if (!msl_options.dispatch_base || !active_input_builtins.get(BuiltInWorkgroupId)) + break; + + // The vkCmdDispatchBase() command lets the client set the base value + // of WorkgroupId. Metal has no direct equivalent; we must make this + // adjustment ourselves. + entry_func.fixup_hooks_in.push_back([=]() { + statement(to_expression(var_id), " += ", to_dereferenced_expression(builtin_dispatch_base_id), ";"); + }); + break; + case BuiltInGlobalInvocationId: + if (!msl_options.dispatch_base || !active_input_builtins.get(BuiltInGlobalInvocationId)) + break; + + // GlobalInvocationId is defined as LocalInvocationId + WorkgroupId * WorkgroupSize. + // This needs to be adjusted too. + entry_func.fixup_hooks_in.push_back([=]() { + auto &execution = this->get_entry_point(); + uint32_t workgroup_size_id = execution.workgroup_size.constant; + if (workgroup_size_id) + statement(to_expression(var_id), " += ", to_dereferenced_expression(builtin_dispatch_base_id), + " * ", to_expression(workgroup_size_id), ";"); + else + statement(to_expression(var_id), " += ", to_dereferenced_expression(builtin_dispatch_base_id), + " * uint3(", execution.workgroup_size.x, ", ", execution.workgroup_size.y, ", ", + execution.workgroup_size.z, ");"); + }); + break; default: break; } @@ -7351,7 +9878,7 @@ void CompilerMSL::fix_up_shader_inputs_outputs() } // Returns the Metal index of the resource of the specified type as used by the specified variable. -uint32_t CompilerMSL::get_metal_resource_index(SPIRVariable &var, SPIRType::BaseType basetype) +uint32_t CompilerMSL::get_metal_resource_index(SPIRVariable &var, SPIRType::BaseType basetype, uint32_t plane) { auto &execution = get_entry_point(); auto &var_dec = ir.meta[var.self].decoration; @@ -7362,9 +9889,17 @@ uint32_t CompilerMSL::get_metal_resource_index(SPIRVariable &var, SPIRType::Base // If a matching binding has been specified, find and use it. auto itr = resource_bindings.find({ execution.model, var_desc_set, var_binding }); - auto resource_decoration = var_type.basetype == SPIRType::SampledImage && basetype == SPIRType::Sampler ? - SPIRVCrossDecorationResourceIndexSecondary : - SPIRVCrossDecorationResourceIndexPrimary; + // Atomic helper buffers for image atomics need to use secondary bindings as well. + bool use_secondary_binding = (var_type.basetype == SPIRType::SampledImage && basetype == SPIRType::Sampler) || + basetype == SPIRType::AtomicCounter; + + auto resource_decoration = + use_secondary_binding ? SPIRVCrossDecorationResourceIndexSecondary : SPIRVCrossDecorationResourceIndexPrimary; + + if (plane == 1) + resource_decoration = SPIRVCrossDecorationResourceIndexTertiary; + if (plane == 2) + resource_decoration = SPIRVCrossDecorationResourceIndexQuaternary; if (itr != end(resource_bindings)) { @@ -7373,8 +9908,8 @@ uint32_t CompilerMSL::get_metal_resource_index(SPIRVariable &var, SPIRType::Base switch (basetype) { case SPIRType::Image: - set_extended_decoration(var.self, resource_decoration, remap.first.msl_texture); - return remap.first.msl_texture; + set_extended_decoration(var.self, resource_decoration, remap.first.msl_texture + plane); + return remap.first.msl_texture + plane; case SPIRType::Sampler: set_extended_decoration(var.self, resource_decoration, remap.first.msl_sampler); return remap.first.msl_sampler; @@ -7388,33 +9923,42 @@ uint32_t CompilerMSL::get_metal_resource_index(SPIRVariable &var, SPIRType::Base if (has_extended_decoration(var.self, resource_decoration)) return get_extended_decoration(var.self, resource_decoration); + // Allow user to enable decoration binding + if (msl_options.enable_decoration_binding) + { + // If there is no explicit mapping of bindings to MSL, use the declared binding. + if (has_decoration(var.self, DecorationBinding)) + { + var_binding = get_decoration(var.self, DecorationBinding); + // Avoid emitting sentinel bindings. + if (var_binding < 0x80000000u) + return var_binding; + } + } + // If we did not explicitly remap, allocate bindings on demand. // We cannot reliably use Binding decorations since SPIR-V and MSL's binding models are very different. + bool allocate_argument_buffer_ids = false; + + if (var.storage != StorageClassPushConstant) + allocate_argument_buffer_ids = descriptor_set_is_argument_buffer(var_desc_set); + uint32_t binding_stride = 1; auto &type = get(var.basetype); for (uint32_t i = 0; i < uint32_t(type.array.size()); i++) - binding_stride *= type.array_size_literal[i] ? type.array[i] : get(type.array[i]).scalar(); + binding_stride *= to_array_size_literal(type, i); assert(binding_stride != 0); // If a binding has not been specified, revert to incrementing resource indices. uint32_t resource_index; - bool allocate_argument_buffer_ids = false; - uint32_t desc_set = 0; - - if (var.storage != StorageClassPushConstant) - { - desc_set = get_decoration(var.self, DecorationDescriptorSet); - allocate_argument_buffer_ids = descriptor_set_is_argument_buffer(desc_set); - } - if (allocate_argument_buffer_ids) { // Allocate from a flat ID binding space. - resource_index = next_metal_resource_ids[desc_set]; - next_metal_resource_ids[desc_set] += binding_stride; + resource_index = next_metal_resource_ids[var_desc_set]; + next_metal_resource_ids[var_desc_set] += binding_stride; } else { @@ -7467,25 +10011,47 @@ string CompilerMSL::argument_decl(const SPIRFunction::Parameter &arg) if (constref) decl += "const "; + // If this is a combined image-sampler for a 2D image with floating-point type, + // we emitted the 'spvDynamicImageSampler' type, and this is *not* an alias parameter + // for a global, then we need to emit a "dynamic" combined image-sampler. + // Unfortunately, this is necessary to properly support passing around + // combined image-samplers with Y'CbCr conversions on them. + bool is_dynamic_img_sampler = !arg.alias_global_variable && type.basetype == SPIRType::SampledImage && + type.image.dim == Dim2D && type_is_floating_point(get(type.image.type)) && + spv_function_implementations.count(SPVFuncImplDynamicImageSampler); + + // Allow Metal to use the array template to make arrays a value type + string address_space = get_argument_address_space(var); bool builtin = is_builtin_variable(var); - if (var.basevariable == stage_in_ptr_var_id || var.basevariable == stage_out_ptr_var_id) + is_using_builtin_array = builtin; + if (address_space == "threadgroup") + is_using_builtin_array = true; + + if (var.basevariable && (var.basevariable == stage_in_ptr_var_id || var.basevariable == stage_out_ptr_var_id)) decl += type_to_glsl(type, arg.id); else if (builtin) decl += builtin_type_decl(static_cast(get_decoration(arg.id, DecorationBuiltIn)), arg.id); else if ((storage == StorageClassUniform || storage == StorageClassStorageBuffer) && is_array(type)) + { + is_using_builtin_array = true; decl += join(type_to_glsl(type, arg.id), "*"); + } + else if (is_dynamic_img_sampler) + { + decl += join("spvDynamicImageSampler<", type_to_glsl(get(type.image.type)), ">"); + // Mark the variable so that we can handle passing it to another function. + set_extended_decoration(arg.id, SPIRVCrossDecorationDynamicImageSampler); + } else decl += type_to_glsl(type, arg.id); bool opaque_handle = storage == StorageClassUniformConstant; - string address_space = get_argument_address_space(var); - if (!builtin && !opaque_handle && !is_pointer && (storage == StorageClassFunction || storage == StorageClassGeneric)) { // If the argument is a pure value and not an opaque type, we will pass by value. - if (is_array(type)) + if (msl_options.force_native_arrays && is_array(type)) { // We are receiving an array by value. This is problematic. // We cannot be sure of the target address space since we are supposed to receive a copy, @@ -7535,7 +10101,13 @@ string CompilerMSL::argument_decl(const SPIRFunction::Parameter &arg) // constant SSBO * constant (&array)[N]. // However, this only matters for argument buffers, since for MSL 1.0 style codegen, // we emit the buffer array on stack instead, and that seems to work just fine apparently. - decl += " constant"; + + // If the argument was marked as being in device address space, any pointer to member would + // be const device, not constant. + if (argument_buffer_device_storage_mask & (1u << desc_set)) + decl += " const device"; + else + decl += " constant"; } } @@ -7574,6 +10146,16 @@ string CompilerMSL::argument_decl(const SPIRFunction::Parameter &arg) decl += to_expression(name_id); } + // Emulate texture2D atomic operations + auto *backing_var = maybe_get_backing_variable(name_id); + if (backing_var && atomic_image_vars.count(backing_var->self)) + { + decl += ", device atomic_" + type_to_glsl(get(var_type.image.type), 0); + decl += "* " + to_expression(name_id) + "_atomic"; + } + + is_using_builtin_array = false; + return decl; } @@ -7870,19 +10452,31 @@ void CompilerMSL::replace_illegal_names() }; ir.for_each_typed_id([&](uint32_t self, SPIRVariable &) { - auto &dec = ir.meta[self].decoration; + auto *meta = ir.find_meta(self); + if (!meta) + return; + + auto &dec = meta->decoration; if (keywords.find(dec.alias) != end(keywords)) dec.alias += "0"; }); ir.for_each_typed_id([&](uint32_t self, SPIRFunction &) { - auto &dec = ir.meta[self].decoration; + auto *meta = ir.find_meta(self); + if (!meta) + return; + + auto &dec = meta->decoration; if (illegal_func_names.find(dec.alias) != end(illegal_func_names)) dec.alias += "0"; }); ir.for_each_typed_id([&](uint32_t self, SPIRType &) { - for (auto &mbr_dec : ir.meta[self].members) + auto *meta = ir.find_meta(self); + if (!meta) + return; + + for (auto &mbr_dec : meta->members) if (keywords.find(mbr_dec.alias) != end(keywords)) mbr_dec.alias += "0"; }); @@ -7944,6 +10538,7 @@ string CompilerMSL::type_to_glsl(const SPIRType &type, uint32_t id) { const char *restrict_kw; type_name = join(get_type_address_space(type, id), " ", type_to_glsl(get(type.parent_type), id)); + switch (type.basetype) { case SPIRType::Image: @@ -7969,7 +10564,9 @@ string CompilerMSL::type_to_glsl(const SPIRType &type, uint32_t id) { case SPIRType::Struct: // Need OpName lookup here to get a "sensible" name for a struct. - return to_name(type.self); + // Allow Metal to use the array template to make arrays a value type + type_name = to_name(type.self); + break; case SPIRType::Image: case SPIRType::SampledImage: @@ -8042,7 +10639,69 @@ string CompilerMSL::type_to_glsl(const SPIRType &type, uint32_t id) if (type.vecsize > 1) type_name += to_string(type.vecsize); - return type_name; + if (type.array.empty() || using_builtin_array()) + { + return type_name; + } + else + { + // Allow Metal to use the array template to make arrays a value type + add_spv_func_and_recompile(SPVFuncImplUnsafeArray); + string res; + string sizes; + + for (uint32_t i = 0; i < uint32_t(type.array.size()); i++) + { + res += "spvUnsafeArray<"; + sizes += ", "; + sizes += to_array_size(type, i); + sizes += ">"; + } + + res += type_name + sizes; + return res; + } +} + +string CompilerMSL::type_to_array_glsl(const SPIRType &type) +{ + // Allow Metal to use the array template to make arrays a value type + switch (type.basetype) + { + case SPIRType::AtomicCounter: + case SPIRType::ControlPointArray: + { + return CompilerGLSL::type_to_array_glsl(type); + } + default: + { + if (using_builtin_array()) + return CompilerGLSL::type_to_array_glsl(type); + else + return ""; + } + } +} + +// Threadgroup arrays can't have a wrapper type +std::string CompilerMSL::variable_decl(const SPIRVariable &variable) +{ + if (variable.storage == StorageClassWorkgroup) + { + is_using_builtin_array = true; + } + std::string expr = CompilerGLSL::variable_decl(variable); + if (variable.storage == StorageClassWorkgroup) + { + is_using_builtin_array = false; + } + return expr; +} + +// GCC workaround of lambdas calling protected funcs +std::string CompilerMSL::variable_decl(const SPIRType &type, const std::string &name, uint32_t id) +{ + return CompilerGLSL::variable_decl(type, name, id); } std::string CompilerMSL::sampler_type(const SPIRType &type) @@ -8115,9 +10774,14 @@ string CompilerMSL::image_type_glsl(const SPIRType &type, uint32_t id) switch (img_type.dim) { case Dim1D: - img_type_name += "depth1d_unsupported_by_metal"; - break; case Dim2D: + if (img_type.dim == Dim1D && !msl_options.texture_1D_as_2D) + { + // Use a native Metal 1D texture + img_type_name += "depth1d_unsupported_by_metal"; + break; + } + if (img_type.ms && img_type.arrayed) { if (!msl_options.supports_msl_version(2, 1)) @@ -8135,7 +10799,10 @@ string CompilerMSL::image_type_glsl(const SPIRType &type, uint32_t id) img_type_name += "depth3d_unsupported_by_metal"; break; case DimCube: - img_type_name += (img_type.arrayed ? "depthcube_array" : "depthcube"); + if (!msl_options.emulate_cube_array) + img_type_name += (img_type.arrayed ? "depthcube_array" : "depthcube"); + else + img_type_name += (img_type.arrayed ? "depth2d_array" : "depthcube"); break; default: img_type_name += "unknown_depth_texture_type"; @@ -8146,9 +10813,6 @@ string CompilerMSL::image_type_glsl(const SPIRType &type, uint32_t id) { switch (img_type.dim) { - case Dim1D: - img_type_name += (img_type.arrayed ? "texture1d_array" : "texture1d"); - break; case DimBuffer: if (img_type.ms || img_type.arrayed) SPIRV_CROSS_THROW("Cannot use texel buffers with multisampling or array layers."); @@ -8162,8 +10826,22 @@ string CompilerMSL::image_type_glsl(const SPIRType &type, uint32_t id) else img_type_name += "texture2d"; break; + case Dim1D: case Dim2D: case DimSubpassData: + if (img_type.dim == Dim1D && !msl_options.texture_1D_as_2D) + { + // Use a native Metal 1D texture + img_type_name += (img_type.arrayed ? "texture1d_array" : "texture1d"); + break; + } + + // Use Metal's native frame-buffer fetch API for subpass inputs. + if (img_type.dim == DimSubpassData && msl_options.is_ios() && + msl_options.ios_use_framebuffer_fetch_subpasses) + { + return type_to_glsl(get(img_type.type)); + } if (img_type.ms && img_type.arrayed) { if (!msl_options.supports_msl_version(2, 1)) @@ -8181,7 +10859,10 @@ string CompilerMSL::image_type_glsl(const SPIRType &type, uint32_t id) img_type_name += "texture3d"; break; case DimCube: - img_type_name += (img_type.arrayed ? "texturecube_array" : "texturecube"); + if (!msl_options.emulate_cube_array) + img_type_name += (img_type.arrayed ? "texturecube_array" : "texturecube"); + else + img_type_name += (img_type.arrayed ? "texture2d_array" : "texturecube"); break; default: img_type_name += "unknown_texture_type"; @@ -8248,6 +10929,11 @@ void CompilerMSL::emit_subgroup_op(const Instruction &i) if (!msl_options.supports_msl_version(2)) SPIRV_CROSS_THROW("Subgroups are only supported in Metal 2.0 and up."); + // If we need to do implicit bitcasts, make sure we do it with the correct type. + uint32_t integer_width = get_integer_width_for_instruction(i); + auto int_type = to_signed_basetype(integer_width); + auto uint_type = to_unsigned_basetype(integer_width); + if (msl_options.is_ios()) { switch (op) @@ -8270,7 +10956,7 @@ void CompilerMSL::emit_subgroup_op(const Instruction &i) switch (op) { default: - SPIRV_CROSS_THROW("Subgroup ops beyond broadcast and shuffle on macOS require Metal 2.0 and up."); + SPIRV_CROSS_THROW("Subgroup ops beyond broadcast and shuffle on macOS require Metal 2.1 and up."); case OpGroupNonUniformBroadcast: case OpGroupNonUniformShuffle: case OpGroupNonUniformShuffleXor: @@ -8398,6 +11084,7 @@ case OpGroupNonUniform##op: \ MSL_GROUP_OP(IMul, product) #undef MSL_GROUP_OP // The others, unfortunately, don't support InclusiveScan or ExclusiveScan. + #define MSL_GROUP_OP(op, msl_op) \ case OpGroupNonUniform##op: \ { \ @@ -8420,12 +11107,36 @@ case OpGroupNonUniform##op: \ SPIRV_CROSS_THROW("Invalid group operation."); \ break; \ } + +#define MSL_GROUP_OP_CAST(op, msl_op, type) \ +case OpGroupNonUniform##op: \ + { \ + auto operation = static_cast(ops[3]); \ + if (operation == GroupOperationReduce) \ + emit_unary_func_op_cast(result_type, id, ops[4], "simd_" #msl_op, type, type); \ + else if (operation == GroupOperationInclusiveScan) \ + SPIRV_CROSS_THROW("Metal doesn't support InclusiveScan for OpGroupNonUniform" #op "."); \ + else if (operation == GroupOperationExclusiveScan) \ + SPIRV_CROSS_THROW("Metal doesn't support ExclusiveScan for OpGroupNonUniform" #op "."); \ + else if (operation == GroupOperationClusteredReduce) \ + { \ + /* Only cluster sizes of 4 are supported. */ \ + uint32_t cluster_size = get(ops[5]).scalar(); \ + if (cluster_size != 4) \ + SPIRV_CROSS_THROW("Metal only supports quad ClusteredReduce."); \ + emit_unary_func_op_cast(result_type, id, ops[4], "quad_" #msl_op, type, type); \ + } \ + else \ + SPIRV_CROSS_THROW("Invalid group operation."); \ + break; \ + } + MSL_GROUP_OP(FMin, min) MSL_GROUP_OP(FMax, max) - MSL_GROUP_OP(SMin, min) - MSL_GROUP_OP(SMax, max) - MSL_GROUP_OP(UMin, min) - MSL_GROUP_OP(UMax, max) + MSL_GROUP_OP_CAST(SMin, min, int_type) + MSL_GROUP_OP_CAST(SMax, max, int_type) + MSL_GROUP_OP_CAST(UMin, min, uint_type) + MSL_GROUP_OP_CAST(UMax, max, uint_type) MSL_GROUP_OP(BitwiseAnd, and) MSL_GROUP_OP(BitwiseOr, or) MSL_GROUP_OP(BitwiseXor, xor) @@ -8433,6 +11144,8 @@ case OpGroupNonUniform##op: \ MSL_GROUP_OP(LogicalOr, or) MSL_GROUP_OP(LogicalXor, xor) // clang-format on +#undef MSL_GROUP_OP +#undef MSL_GROUP_OP_CAST case OpGroupNonUniformQuadSwap: { @@ -8494,19 +11207,114 @@ string CompilerMSL::builtin_to_glsl(BuiltIn builtin, StorageClass storage) switch (builtin) { + // Handle HLSL-style 0-based vertex/instance index. // Override GLSL compiler strictness case BuiltInVertexId: - return "gl_VertexID"; + ensure_builtin(StorageClassInput, BuiltInVertexId); + if (msl_options.enable_base_index_zero && msl_options.supports_msl_version(1, 1) && + (msl_options.ios_support_base_vertex_instance || msl_options.is_macos())) + { + if (builtin_declaration) + { + if (needs_base_vertex_arg != TriState::No) + needs_base_vertex_arg = TriState::Yes; + return "gl_VertexID"; + } + else + { + ensure_builtin(StorageClassInput, BuiltInBaseVertex); + return "(gl_VertexID - gl_BaseVertex)"; + } + } + else + { + return "gl_VertexID"; + } case BuiltInInstanceId: - return "gl_InstanceID"; + ensure_builtin(StorageClassInput, BuiltInInstanceId); + if (msl_options.enable_base_index_zero && msl_options.supports_msl_version(1, 1) && + (msl_options.ios_support_base_vertex_instance || msl_options.is_macos())) + { + if (builtin_declaration) + { + if (needs_base_instance_arg != TriState::No) + needs_base_instance_arg = TriState::Yes; + return "gl_InstanceID"; + } + else + { + ensure_builtin(StorageClassInput, BuiltInBaseInstance); + return "(gl_InstanceID - gl_BaseInstance)"; + } + } + else + { + return "gl_InstanceID"; + } case BuiltInVertexIndex: - return "gl_VertexIndex"; + ensure_builtin(StorageClassInput, BuiltInVertexIndex); + if (msl_options.enable_base_index_zero && msl_options.supports_msl_version(1, 1) && + (msl_options.ios_support_base_vertex_instance || msl_options.is_macos())) + { + if (builtin_declaration) + { + if (needs_base_vertex_arg != TriState::No) + needs_base_vertex_arg = TriState::Yes; + return "gl_VertexIndex"; + } + else + { + ensure_builtin(StorageClassInput, BuiltInBaseVertex); + return "(gl_VertexIndex - gl_BaseVertex)"; + } + } + else + { + return "gl_VertexIndex"; + } case BuiltInInstanceIndex: - return "gl_InstanceIndex"; + ensure_builtin(StorageClassInput, BuiltInInstanceIndex); + if (msl_options.enable_base_index_zero && msl_options.supports_msl_version(1, 1) && + (msl_options.ios_support_base_vertex_instance || msl_options.is_macos())) + { + if (builtin_declaration) + { + if (needs_base_instance_arg != TriState::No) + needs_base_instance_arg = TriState::Yes; + return "gl_InstanceIndex"; + } + else + { + ensure_builtin(StorageClassInput, BuiltInBaseInstance); + return "(gl_InstanceIndex - gl_BaseInstance)"; + } + } + else + { + return "gl_InstanceIndex"; + } case BuiltInBaseVertex: - return "gl_BaseVertex"; + if (msl_options.supports_msl_version(1, 1) && + (msl_options.ios_support_base_vertex_instance || msl_options.is_macos())) + { + needs_base_vertex_arg = TriState::No; + return "gl_BaseVertex"; + } + else + { + SPIRV_CROSS_THROW("BaseVertex requires Metal 1.1 and Mac or Apple A9+ hardware."); + } case BuiltInBaseInstance: - return "gl_BaseInstance"; + if (msl_options.supports_msl_version(1, 1) && + (msl_options.ios_support_base_vertex_instance || msl_options.is_macos())) + { + needs_base_instance_arg = TriState::No; + return "gl_BaseInstance"; + } + else + { + SPIRV_CROSS_THROW("BaseInstance requires Metal 1.1 and Mac or Apple A9+ hardware."); + } case BuiltInDrawIndex: SPIRV_CROSS_THROW("DrawIndex is not supported in MSL."); @@ -8889,9 +11697,12 @@ string CompilerMSL::built_in_func_arg(BuiltIn builtin, bool prefix_comma) if (prefix_comma) bi_arg += ", "; + // Handle HLSL-style 0-based vertex/instance index. + builtin_declaration = true; bi_arg += builtin_type_decl(builtin); bi_arg += " " + builtin_to_glsl(builtin, StorageClassInput); bi_arg += " [[" + builtin_qualifier(builtin) + "]]"; + builtin_declaration = false; return bi_arg; } @@ -9152,6 +11963,17 @@ bool CompilerMSL::SampledImageScanner::handle(spv::Op opcode, const uint32_t *ar return true; } +// If a needed custom function wasn't added before, add it and force a recompile. +void CompilerMSL::add_spv_func_and_recompile(SPVFuncImpl spv_func) +{ + if (spv_function_implementations.count(spv_func) == 0) + { + spv_function_implementations.insert(spv_func); + suppress_missing_prototypes = true; + force_recompile(); + } +} + bool CompilerMSL::OpCodePreprocessor::handle(Op opcode, const uint32_t *args, uint32_t length) { // Since MSL exists in a single execution scope, function prototype declarations are not @@ -9174,6 +11996,14 @@ bool CompilerMSL::OpCodePreprocessor::handle(Op opcode, const uint32_t *args, ui suppress_missing_prototypes = true; break; + // Emulate texture2D atomic operations + case OpImageTexelPointer: + { + auto *var = compiler.maybe_get_backing_variable(args[2]); + image_pointers[args[1]] = var ? var->self : ID(0); + break; + } + case OpImageWrite: uses_resource_write = true; break; @@ -9182,6 +12012,7 @@ bool CompilerMSL::OpCodePreprocessor::handle(Op opcode, const uint32_t *args, ui check_resource_write(args[0]); break; + // Emulate texture2D atomic operations case OpAtomicExchange: case OpAtomicCompareExchange: case OpAtomicCompareExchangeWeak: @@ -9196,13 +12027,39 @@ bool CompilerMSL::OpCodePreprocessor::handle(Op opcode, const uint32_t *args, ui case OpAtomicAnd: case OpAtomicOr: case OpAtomicXor: + { uses_atomics = true; + auto it = image_pointers.find(args[2]); + if (it != image_pointers.end()) + { + compiler.atomic_image_vars.insert(it->second); + } check_resource_write(args[2]); break; + } + + case OpAtomicStore: + { + uses_atomics = true; + auto it = image_pointers.find(args[0]); + if (it != image_pointers.end()) + { + compiler.atomic_image_vars.insert(it->second); + } + check_resource_write(args[0]); + break; + } case OpAtomicLoad: + { uses_atomics = true; + auto it = image_pointers.find(args[2]); + if (it != image_pointers.end()) + { + compiler.atomic_image_vars.insert(it->second); + } break; + } case OpGroupNonUniformInverseBallot: needs_subgroup_invocation_id = true; @@ -9229,6 +12086,7 @@ bool CompilerMSL::OpCodePreprocessor::handle(Op opcode, const uint32_t *args, ui uint32_t result_type = args[0]; uint32_t id = args[1]; uint32_t ptr = args[2]; + compiler.set(id, "", result_type, true); compiler.register_read(id, ptr, true); compiler.ir.ids[id].set_allow_type_rewrite(); @@ -9264,60 +12122,55 @@ CompilerMSL::SPVFuncImpl CompilerMSL::OpCodePreprocessor::get_spv_func_impl(Op o case OpFMod: return SPVFuncImplMod; - case OpFunctionCall: - { - auto &return_type = compiler.get(args[0]); - if (return_type.array.size() > 1) + case OpFAdd: + if (compiler.msl_options.invariant_float_math) { - if (return_type.array.size() > SPVFuncImplArrayCopyMultidimMax) - SPIRV_CROSS_THROW("Cannot support this many dimensions for arrays of arrays."); - return static_cast(SPVFuncImplArrayCopyMultidimBase + return_type.array.size()); + return SPVFuncImplFAdd; } - else if (return_type.array.size() > 0) - return SPVFuncImplArrayCopy; - break; + + case OpFMul: + case OpOuterProduct: + case OpMatrixTimesVector: + case OpVectorTimesMatrix: + case OpMatrixTimesMatrix: + if (compiler.msl_options.invariant_float_math) + { + return SPVFuncImplFMul; + } + break; + + case OpTypeArray: + { + // Allow Metal to use the array template to make arrays a value type + return SPVFuncImplUnsafeArray; } - case OpStore: + // Emulate texture2D atomic operations + case OpAtomicExchange: + case OpAtomicCompareExchange: + case OpAtomicCompareExchangeWeak: + case OpAtomicIIncrement: + case OpAtomicIDecrement: + case OpAtomicIAdd: + case OpAtomicISub: + case OpAtomicSMin: + case OpAtomicUMin: + case OpAtomicSMax: + case OpAtomicUMax: + case OpAtomicAnd: + case OpAtomicOr: + case OpAtomicXor: + case OpAtomicLoad: + case OpAtomicStore: { - // Get the result type of the RHS. Since this is run as a pre-processing stage, - // we must extract the result type directly from the Instruction, rather than the ID. - uint32_t id_lhs = args[0]; - uint32_t id_rhs = args[1]; - - const SPIRType *type = nullptr; - if (compiler.ir.ids[id_rhs].get_type() != TypeNone) + auto it = image_pointers.find(args[opcode == OpAtomicStore ? 0 : 2]); + if (it != image_pointers.end()) { - // Could be a constant, or similar. - type = &compiler.expression_type(id_rhs); + uint32_t tid = compiler.get(it->second).basetype; + if (tid && compiler.get(tid).image.dim == Dim2D) + return SPVFuncImplImage2DAtomicCoords; } - else - { - // Or ... an expression. - uint32_t tid = result_types[id_rhs]; - if (tid) - type = &compiler.get(tid); - } - - auto *var = compiler.maybe_get(id_lhs); - - // Are we simply assigning to a statically assigned variable which takes a constant? - // Don't bother emitting this function. - bool static_expression_lhs = - var && var->storage == StorageClassFunction && var->statically_assigned && var->remapped_variable; - if (type && compiler.is_array(*type) && !static_expression_lhs) - { - if (type->array.size() > 1) - { - if (type->array.size() > SPVFuncImplArrayCopyMultidimMax) - SPIRV_CROSS_THROW("Cannot support this many dimensions for arrays of arrays."); - return static_cast(SPVFuncImplArrayCopyMultidimBase + type->array.size()); - } - else - return SPVFuncImplArrayCopy; - } - break; } @@ -9329,27 +12182,9 @@ CompilerMSL::SPVFuncImpl CompilerMSL::OpCodePreprocessor::get_spv_func_impl(Op o uint32_t tid = result_types[args[opcode == OpImageWrite ? 0 : 2]]; if (tid && compiler.get(tid).image.dim == DimBuffer && !compiler.msl_options.texture_buffer_native) return SPVFuncImplTexelBufferCoords; - - if (opcode == OpImageFetch && compiler.msl_options.swizzle_texture_samples) - return SPVFuncImplTextureSwizzle; - break; } - case OpImageSampleExplicitLod: - case OpImageSampleProjExplicitLod: - case OpImageSampleDrefExplicitLod: - case OpImageSampleProjDrefExplicitLod: - case OpImageSampleImplicitLod: - case OpImageSampleProjImplicitLod: - case OpImageSampleDrefImplicitLod: - case OpImageSampleProjDrefImplicitLod: - case OpImageGather: - case OpImageDrefGather: - if (compiler.msl_options.swizzle_texture_samples) - return SPVFuncImplTextureSwizzle; - break; - case OpExtInst: { uint32_t extension_set = args[2]; @@ -9375,24 +12210,21 @@ CompilerMSL::SPVFuncImpl CompilerMSL::OpCodePreprocessor::get_spv_func_impl(Op o auto &type = compiler.get(args[0]); if (type.vecsize == 1) return SPVFuncImplReflectScalar; - else - return SPVFuncImplNone; + break; } case GLSLstd450Refract: { auto &type = compiler.get(args[0]); if (type.vecsize == 1) return SPVFuncImplRefractScalar; - else - return SPVFuncImplNone; + break; } case GLSLstd450FaceForward: { auto &type = compiler.get(args[0]); if (type.vecsize == 1) return SPVFuncImplFaceForwardScalar; - else - return SPVFuncImplNone; + break; } case GLSLstd450MatrixInverse: { @@ -9451,7 +12283,7 @@ void CompilerMSL::MemberSorter::sort() size_t mbr_cnt = type.member_types.size(); SmallVector mbr_idxs(mbr_cnt); iota(mbr_idxs.begin(), mbr_idxs.end(), 0); // Fill with consecutive indices - std::sort(mbr_idxs.begin(), mbr_idxs.end(), *this); // Sort member indices based on sorting aspect + std::stable_sort(mbr_idxs.begin(), mbr_idxs.end(), *this); // Sort member indices based on sorting aspect // Move type and meta member info to the order defined by the sorted member indices. // This is done by creating temporary copies of both member types and meta, and then @@ -9500,7 +12332,7 @@ CompilerMSL::MemberSorter::MemberSorter(SPIRType &t, Meta &m, SortAspect sa) meta.members.resize(max(type.member_types.size(), meta.members.size())); } -void CompilerMSL::remap_constexpr_sampler(uint32_t id, const MSLConstexprSampler &sampler) +void CompilerMSL::remap_constexpr_sampler(VariableID id, const MSLConstexprSampler &sampler) { auto &type = get(get(id).basetype); if (type.basetype != SPIRType::SampledImage && type.basetype != SPIRType::Sampler) @@ -9543,6 +12375,10 @@ void CompilerMSL::bitcast_from_builtin_load(uint32_t source_id, std::string &exp case BuiltInSubgroupSize: case BuiltInSubgroupLocalInvocationId: case BuiltInViewIndex: + case BuiltInVertexIndex: + case BuiltInInstanceIndex: + case BuiltInBaseInstance: + case BuiltInBaseVertex: expected_type = SPIRType::UInt; break; @@ -9656,8 +12492,10 @@ void CompilerMSL::analyze_argument_buffers() string name; SPIRType::BaseType basetype; uint32_t index; + uint32_t plane; }; SmallVector resources_in_set[kMaxArgumentBuffers]; + SmallVector inline_block_vars; bool set_needs_swizzle_buffer[kMaxArgumentBuffers] = {}; bool set_needs_buffer_sizes[kMaxArgumentBuffers] = {}; @@ -9690,27 +12528,43 @@ void CompilerMSL::analyze_argument_buffers() } } + uint32_t binding = get_decoration(var_id, DecorationBinding); if (type.basetype == SPIRType::SampledImage) { add_resource_name(var_id); - uint32_t image_resource_index = get_metal_resource_index(var, SPIRType::Image); - uint32_t sampler_resource_index = get_metal_resource_index(var, SPIRType::Sampler); + uint32_t plane_count = 1; + if (constexpr_sampler && constexpr_sampler->ycbcr_conversion_enable) + plane_count = constexpr_sampler->planes; - resources_in_set[desc_set].push_back({ &var, to_name(var_id), SPIRType::Image, image_resource_index }); + for (uint32_t i = 0; i < plane_count; i++) + { + uint32_t image_resource_index = get_metal_resource_index(var, SPIRType::Image, i); + resources_in_set[desc_set].push_back( + { &var, to_name(var_id), SPIRType::Image, image_resource_index, i }); + } if (type.image.dim != DimBuffer && !constexpr_sampler) { + uint32_t sampler_resource_index = get_metal_resource_index(var, SPIRType::Sampler); resources_in_set[desc_set].push_back( - { &var, to_sampler_expression(var_id), SPIRType::Sampler, sampler_resource_index }); + { &var, to_sampler_expression(var_id), SPIRType::Sampler, sampler_resource_index, 0 }); } } + else if (inline_uniform_blocks.count(SetBindingPair{ desc_set, binding })) + { + inline_block_vars.push_back(var_id); + } else if (!constexpr_sampler) { // constexpr samplers are not declared as resources. - add_resource_name(var_id); - resources_in_set[desc_set].push_back( - { &var, to_name(var_id), type.basetype, get_metal_resource_index(var, type.basetype) }); + // Inline uniform blocks are always emitted at the end. + if (!msl_options.is_ios() || type.basetype != SPIRType::Image || type.image.sampled != 2) + { + add_resource_name(var_id); + resources_in_set[desc_set].push_back( + { &var, to_name(var_id), type.basetype, get_metal_resource_index(var, type.basetype), 0 }); + } } // Check if this descriptor set needs a swizzle buffer. @@ -9763,7 +12617,7 @@ void CompilerMSL::analyze_argument_buffers() set_decoration(var_id, DecorationDescriptorSet, desc_set); set_decoration(var_id, DecorationBinding, kSwizzleBufferBinding); resources_in_set[desc_set].push_back( - { &var, to_name(var_id), SPIRType::UInt, get_metal_resource_index(var, SPIRType::UInt) }); + { &var, to_name(var_id), SPIRType::UInt, get_metal_resource_index(var, SPIRType::UInt), 0 }); } if (set_needs_buffer_sizes[desc_set]) @@ -9774,11 +12628,21 @@ void CompilerMSL::analyze_argument_buffers() set_decoration(var_id, DecorationDescriptorSet, desc_set); set_decoration(var_id, DecorationBinding, kBufferSizeBufferBinding); resources_in_set[desc_set].push_back( - { &var, to_name(var_id), SPIRType::UInt, get_metal_resource_index(var, SPIRType::UInt) }); + { &var, to_name(var_id), SPIRType::UInt, get_metal_resource_index(var, SPIRType::UInt), 0 }); } } } + // Now add inline uniform blocks. + for (uint32_t var_id : inline_block_vars) + { + auto &var = get(var_id); + uint32_t desc_set = get_decoration(var_id, DecorationDescriptorSet); + add_resource_name(var_id); + resources_in_set[desc_set].push_back( + { &var, to_name(var_id), SPIRType::Struct, get_metal_resource_index(var, SPIRType::Struct), 0 }); + } + for (uint32_t desc_set = 0; desc_set < kMaxArgumentBuffers; desc_set++) { auto &resources = resources_in_set[desc_set]; @@ -9793,8 +12657,20 @@ void CompilerMSL::analyze_argument_buffers() argument_buffer_ids[desc_set] = next_id; auto &buffer_type = set(type_id); - buffer_type.storage = StorageClassUniform; + buffer_type.basetype = SPIRType::Struct; + + if ((argument_buffer_device_storage_mask & (1u << desc_set)) != 0) + { + buffer_type.storage = StorageClassStorageBuffer; + // Make sure the argument buffer gets marked as const device. + set_decoration(next_id, DecorationNonWritable); + // Need to mark the type as a Block to enable this. + set_decoration(type_id, DecorationBlock); + } + else + buffer_type.storage = StorageClassUniform; + set_name(type_id, join("spvDescriptorSetBuffer", desc_set)); auto &ptr_type = set(ptr_type_id); @@ -9818,6 +12694,8 @@ void CompilerMSL::analyze_argument_buffers() auto &var = *resource.var; auto &type = get_variable_data_type(var); string mbr_name = ensure_valid_name(resource.name, "m"); + if (resource.plane > 0) + mbr_name += join(plane_name_suffix, resource.plane); set_member_name(buffer_type.self, member_index, mbr_name); if (resource.basetype == SPIRType::Sampler && type.basetype != SPIRType::Sampler) @@ -9845,11 +12723,27 @@ void CompilerMSL::analyze_argument_buffers() } else { + uint32_t binding = get_decoration(var.self, DecorationBinding); + SetBindingPair pair = { desc_set, binding }; + if (resource.basetype == SPIRType::Image || resource.basetype == SPIRType::Sampler || resource.basetype == SPIRType::SampledImage) { // Drop pointer information when we emit the resources into a struct. buffer_type.member_types.push_back(get_variable_data_type_id(var)); + if (resource.plane == 0) + set_qualified_name(var.self, join(to_name(buffer_variable_id), ".", mbr_name)); + } + else if (buffers_requiring_dynamic_offset.count(pair)) + { + // Don't set the qualified name here; we'll define a variable holding the corrected buffer address later. + buffer_type.member_types.push_back(var.basetype); + buffers_requiring_dynamic_offset[pair].second = var.self; + } + else if (inline_uniform_blocks.count(pair)) + { + // Put the buffer block itself into the argument buffer. + buffer_type.member_types.push_back(get_variable_data_type_id(var)); set_qualified_name(var.self, join(to_name(buffer_variable_id), ".", mbr_name)); } else @@ -9872,29 +12766,20 @@ void CompilerMSL::analyze_argument_buffers() } } -bool CompilerMSL::SetBindingPair::operator==(const SetBindingPair &other) const +void CompilerMSL::activate_argument_buffer_resources() { - return desc_set == other.desc_set && binding == other.binding; + // For ABI compatibility, force-enable all resources which are part of argument buffers. + ir.for_each_typed_id([&](uint32_t self, const SPIRVariable &) { + if (!has_decoration(self, DecorationDescriptorSet)) + return; + + uint32_t desc_set = get_decoration(self, DecorationDescriptorSet); + if (descriptor_set_is_argument_buffer(desc_set)) + active_interface_variables.insert(self); + }); } -bool CompilerMSL::StageSetBinding::operator==(const StageSetBinding &other) const +bool CompilerMSL::using_builtin_array() const { - return model == other.model && desc_set == other.desc_set && binding == other.binding; -} - -size_t CompilerMSL::InternalHasher::operator()(const SetBindingPair &value) const -{ - // Quality of hash doesn't really matter here. - auto hash_set = std::hash()(value.desc_set); - auto hash_binding = std::hash()(value.binding); - return (hash_set * 0x10001b31) ^ hash_binding; -} - -size_t CompilerMSL::InternalHasher::operator()(const StageSetBinding &value) const -{ - // Quality of hash doesn't really matter here. - auto hash_model = std::hash()(value.model); - auto hash_set = std::hash()(value.desc_set); - auto tmp_hash = (hash_model * 0x10001b31) ^ hash_set; - return (tmp_hash * 0x10001b31) ^ value.binding; + return msl_options.force_native_arrays || is_using_builtin_array; } diff --git a/third_party/spirv-cross/spirv_msl.hpp b/third_party/spirv-cross/spirv_msl.hpp index abd481b336..6b021c66b0 100644 --- a/third_party/spirv-cross/spirv_msl.hpp +++ b/third_party/spirv-cross/spirv_msl.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2016-2019 The Brenwill Workshop Ltd. + * Copyright 2016-2020 The Brenwill Workshop Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -54,9 +54,9 @@ struct MSLVertexAttr // Matches the binding index of a MSL resource for a binding within a descriptor set. // Taken together, the stage, desc_set and binding combine to form a reference to a resource // descriptor used in a particular shading stage. -// If using MSL 2.0 argument buffers, and the descriptor set is not marked as a discrete descriptor set, -// the binding reference we remap to will become an [[id(N)]] attribute within -// the "descriptor set" argument buffer structure. +// If using MSL 2.0 argument buffers, the descriptor set is not marked as a discrete descriptor set, +// and (for iOS only) the resource is not a storage image (sampled != 2), the binding reference we +// remap to will become an [[id(N)]] attribute within the "descriptor set" argument buffer structure. // For resources which are bound in the "classic" MSL 1.0 way or discrete descriptors, the remap will become a // [[buffer(N)]], [[texture(N)]] or [[sampler(N)]] depending on the resource types used. struct MSLResourceBinding @@ -122,6 +122,50 @@ enum MSLSamplerBorderColor MSL_SAMPLER_BORDER_COLOR_INT_MAX = 0x7fffffff }; +enum MSLFormatResolution +{ + MSL_FORMAT_RESOLUTION_444 = 0, + MSL_FORMAT_RESOLUTION_422, + MSL_FORMAT_RESOLUTION_420, + MSL_FORMAT_RESOLUTION_INT_MAX = 0x7fffffff +}; + +enum MSLChromaLocation +{ + MSL_CHROMA_LOCATION_COSITED_EVEN = 0, + MSL_CHROMA_LOCATION_MIDPOINT, + MSL_CHROMA_LOCATION_INT_MAX = 0x7fffffff +}; + +enum MSLComponentSwizzle +{ + MSL_COMPONENT_SWIZZLE_IDENTITY = 0, + MSL_COMPONENT_SWIZZLE_ZERO, + MSL_COMPONENT_SWIZZLE_ONE, + MSL_COMPONENT_SWIZZLE_R, + MSL_COMPONENT_SWIZZLE_G, + MSL_COMPONENT_SWIZZLE_B, + MSL_COMPONENT_SWIZZLE_A, + MSL_COMPONENT_SWIZZLE_INT_MAX = 0x7fffffff +}; + +enum MSLSamplerYCbCrModelConversion +{ + MSL_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY = 0, + MSL_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY, + MSL_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_BT_709, + MSL_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_BT_601, + MSL_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_BT_2020, + MSL_SAMPLER_YCBCR_MODEL_CONVERSION_INT_MAX = 0x7fffffff +}; + +enum MSLSamplerYCbCrRange +{ + MSL_SAMPLER_YCBCR_RANGE_ITU_FULL = 0, + MSL_SAMPLER_YCBCR_RANGE_ITU_NARROW, + MSL_SAMPLER_YCBCR_RANGE_INT_MAX = 0x7fffffff +}; + struct MSLConstexprSampler { MSLSamplerCoord coord = MSL_SAMPLER_COORD_NORMALIZED; @@ -137,18 +181,50 @@ struct MSLConstexprSampler float lod_clamp_max = 1000.0f; int max_anisotropy = 1; + // Sampler Y'CbCr conversion parameters + uint32_t planes = 0; + MSLFormatResolution resolution = MSL_FORMAT_RESOLUTION_444; + MSLSamplerFilter chroma_filter = MSL_SAMPLER_FILTER_NEAREST; + MSLChromaLocation x_chroma_offset = MSL_CHROMA_LOCATION_COSITED_EVEN; + MSLChromaLocation y_chroma_offset = MSL_CHROMA_LOCATION_COSITED_EVEN; + MSLComponentSwizzle swizzle[4]; // IDENTITY, IDENTITY, IDENTITY, IDENTITY + MSLSamplerYCbCrModelConversion ycbcr_model = MSL_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY; + MSLSamplerYCbCrRange ycbcr_range = MSL_SAMPLER_YCBCR_RANGE_ITU_FULL; + uint32_t bpc = 8; + bool compare_enable = false; bool lod_clamp_enable = false; bool anisotropy_enable = false; + bool ycbcr_conversion_enable = false; + + MSLConstexprSampler() + { + for (uint32_t i = 0; i < 4; i++) + swizzle[i] = MSL_COMPONENT_SWIZZLE_IDENTITY; + } + bool swizzle_is_identity() const + { + return (swizzle[0] == MSL_COMPONENT_SWIZZLE_IDENTITY && swizzle[1] == MSL_COMPONENT_SWIZZLE_IDENTITY && + swizzle[2] == MSL_COMPONENT_SWIZZLE_IDENTITY && swizzle[3] == MSL_COMPONENT_SWIZZLE_IDENTITY); + } + bool swizzle_has_one_or_zero() const + { + return (swizzle[0] == MSL_COMPONENT_SWIZZLE_ZERO || swizzle[0] == MSL_COMPONENT_SWIZZLE_ONE || + swizzle[1] == MSL_COMPONENT_SWIZZLE_ZERO || swizzle[1] == MSL_COMPONENT_SWIZZLE_ONE || + swizzle[2] == MSL_COMPONENT_SWIZZLE_ZERO || swizzle[2] == MSL_COMPONENT_SWIZZLE_ONE || + swizzle[3] == MSL_COMPONENT_SWIZZLE_ZERO || swizzle[3] == MSL_COMPONENT_SWIZZLE_ONE); + } }; // Special constant used in a MSLResourceBinding desc_set // element to indicate the bindings for the push constants. -static const uint32_t kPushConstDescSet = ~(0u); +// Kinda deprecated. Just use ResourceBindingPushConstant{DescriptorSet,Binding} directly. +static const uint32_t kPushConstDescSet = ResourceBindingPushConstantDescriptorSet; // Special constant used in a MSLResourceBinding binding // element to indicate the bindings for the push constants. -static const uint32_t kPushConstBinding = 0; +// Kinda deprecated. Just use ResourceBindingPushConstant{DescriptorSet,Binding} directly. +static const uint32_t kPushConstBinding = ResourceBindingPushConstantBinding; // Special constant used in a MSLResourceBinding binding // element to indicate the buffer binding for swizzle buffers. @@ -189,6 +265,7 @@ public: uint32_t shader_tess_factor_buffer_index = 26; uint32_t buffer_size_buffer_index = 25; uint32_t view_mask_buffer_index = 24; + uint32_t dynamic_offsets_buffer_index = 23; uint32_t shader_input_wg_index = 0; uint32_t device_index = 0; bool enable_point_size_builtin = true; @@ -198,18 +275,48 @@ public: bool tess_domain_origin_lower_left = false; bool multiview = false; bool view_index_from_device_index = false; + bool dispatch_base = false; + bool texture_1D_as_2D = false; // Enable use of MSL 2.0 indirect argument buffers. // MSL 2.0 must also be enabled. bool argument_buffers = false; + // Ensures vertex and instance indices start at zero. This reflects the behavior of HLSL with SV_VertexID and SV_InstanceID. + bool enable_base_index_zero = false; + // Fragment output in MSL must have at least as many components as the render pass. // Add support to explicit pad out components. bool pad_fragment_output_components = false; + // Specifies whether the iOS target version supports the [[base_vertex]] and [[base_instance]] attributes. + bool ios_support_base_vertex_instance = false; + + // Use Metal's native frame-buffer fetch API for subpass inputs. + bool ios_use_framebuffer_fetch_subpasses = false; + + // Enables use of "fma" intrinsic for invariant float math + bool invariant_float_math = false; + + // Emulate texturecube_array with texture2d_array for iOS where this type is not available + bool emulate_cube_array = false; + + // Allow user to enable decoration binding + bool enable_decoration_binding = false; + // Requires MSL 2.1, use the native support for texel buffers. bool texture_buffer_native = false; + // Forces all resources which are part of an argument buffer to be considered active. + // This ensures ABI compatibility between shaders where some resources might be unused, + // and would otherwise declare a different IAB. + bool force_active_argument_buffer_resources = false; + + // Forces the use of plain arrays, which works around certain driver bugs on certain versions + // of Intel Macbooks. See https://github.com/KhronosGroup/SPIRV-Cross/issues/1210. + // May reduce performance in scenarios where arrays are copied around as value-types. + bool force_native_arrays = false; + bool is_ios() { return platform == iOS; @@ -225,7 +332,7 @@ public: msl_version = make_msl_version(major, minor, patch); } - bool supports_msl_version(uint32_t major, uint32_t minor = 0, uint32_t patch = 0) + bool supports_msl_version(uint32_t major, uint32_t minor = 0, uint32_t patch = 0) const { return msl_version >= make_msl_version(major, minor, patch); } @@ -276,25 +383,32 @@ public: return msl_options.multiview && !msl_options.view_index_from_device_index; } + // Provide feedback to calling API to allow it to pass a buffer + // containing the dispatch base workgroup ID. + bool needs_dispatch_base_buffer() const + { + return msl_options.dispatch_base && !msl_options.supports_msl_version(1, 2); + } + // Provide feedback to calling API to allow it to pass an output // buffer if the shader needs it. bool needs_output_buffer() const { - return capture_output_to_buffer && stage_out_var_id != 0; + return capture_output_to_buffer && stage_out_var_id != ID(0); } // Provide feedback to calling API to allow it to pass a patch output // buffer if the shader needs it. bool needs_patch_output_buffer() const { - return capture_output_to_buffer && patch_stage_out_var_id != 0; + return capture_output_to_buffer && patch_stage_out_var_id != ID(0); } // Provide feedback to calling API to allow it to pass an input threadgroup // buffer if the shader needs it. bool needs_input_threadgroup_mem() const { - return capture_output_to_buffer && stage_in_var_id != 0; + return capture_output_to_buffer && stage_in_var_id != ID(0); } explicit CompilerMSL(std::vector spirv); @@ -315,10 +429,29 @@ public: // the set/binding combination was used by the MSL code. void add_msl_resource_binding(const MSLResourceBinding &resource); + // desc_set and binding are the SPIR-V descriptor set and binding of a buffer resource + // in this shader. index is the index within the dynamic offset buffer to use. This + // function marks that resource as using a dynamic offset (VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC + // or VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC). This function only has any effect if argument buffers + // are enabled. If so, the buffer will have its address adjusted at the beginning of the shader with + // an offset taken from the dynamic offset buffer. + void add_dynamic_buffer(uint32_t desc_set, uint32_t binding, uint32_t index); + + // desc_set and binding are the SPIR-V descriptor set and binding of a buffer resource + // in this shader. This function marks that resource as an inline uniform block + // (VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT). This function only has any effect if argument buffers + // are enabled. If so, the buffer block will be directly embedded into the argument + // buffer, instead of being referenced indirectly via pointer. + void add_inline_uniform_block(uint32_t desc_set, uint32_t binding); + // When using MSL argument buffers, we can force "classic" MSL 1.0 binding schemes for certain descriptor sets. // This corresponds to VK_KHR_push_descriptor in Vulkan. void add_discrete_descriptor_set(uint32_t desc_set); + // If an argument buffer is large enough, it may need to be in the device storage space rather than + // constant. Opt-in to this behavior here on a per set basis. + void set_argument_buffer_device_address_space(uint32_t desc_set, bool device_storage); + // Query after compilation is done. This allows you to check if a location or set/binding combination was used by the shader. bool is_msl_vertex_attribute_used(uint32_t location); @@ -326,7 +459,7 @@ public: // Constexpr samplers are always assumed to be emitted. // No specific MSLResourceBinding remapping is required for constexpr samplers as long as they are remapped // by remap_constexpr_sampler(_by_binding). - bool is_msl_resource_binding_used(spv::ExecutionModel model, uint32_t set, uint32_t binding); + bool is_msl_resource_binding_used(spv::ExecutionModel model, uint32_t set, uint32_t binding) const; // This must only be called after a successful call to CompilerMSL::compile(). // For a variable resource ID obtained through reflection API, report the automatically assigned resource index. @@ -341,6 +474,14 @@ public: // sampler's binding is returned instead. For any other resource type, -1 is returned. uint32_t get_automatic_msl_resource_binding_secondary(uint32_t id) const; + // Same as get_automatic_msl_resource_binding, but should only be used for combined image samplers for multiplanar images, + // in which case the second plane's binding is returned instead. For any other resource type, -1 is returned. + uint32_t get_automatic_msl_resource_binding_tertiary(uint32_t id) const; + + // Same as get_automatic_msl_resource_binding, but should only be used for combined image samplers for triplanar images, + // in which case the third plane's binding is returned instead. For any other resource type, -1 is returned. + uint32_t get_automatic_msl_resource_binding_quaternary(uint32_t id) const; + // Compiles the SPIR-V code into Metal Shading Language. std::string compile() override; @@ -351,7 +492,7 @@ public: // This can be used on both combined image/samplers (sampler2D) or standalone samplers. // The remapped sampler must not be an array of samplers. // Prefer remap_constexpr_sampler_by_binding unless you're also doing reflection anyways. - void remap_constexpr_sampler(uint32_t id, const MSLConstexprSampler &sampler); + void remap_constexpr_sampler(VariableID id, const MSLConstexprSampler &sampler); // Same as remap_constexpr_sampler, except you provide set/binding, rather than variable ID. // Remaps based on ID take priority over set/binding remaps. @@ -384,10 +525,22 @@ protected: SPVFuncImplArrayOfArrayCopy5Dim = SPVFuncImplArrayCopyMultidimBase + 5, SPVFuncImplArrayOfArrayCopy6Dim = SPVFuncImplArrayCopyMultidimBase + 6, SPVFuncImplTexelBufferCoords, + SPVFuncImplImage2DAtomicCoords, // Emulate texture2D atomic operations + SPVFuncImplFMul, + SPVFuncImplFAdd, + SPVFuncImplCubemapTo2DArrayFace, + SPVFuncImplUnsafeArray, // Allow Metal to use the array template to make arrays a value type SPVFuncImplInverse4x4, SPVFuncImplInverse3x3, SPVFuncImplInverse2x2, + // It is very important that this come before *Swizzle and ChromaReconstruct*, to ensure it's + // emitted before them. + SPVFuncImplForwardArgs, + // Likewise, this must come before *Swizzle. + SPVFuncImplGetSwizzle, SPVFuncImplTextureSwizzle, + SPVFuncImplGatherSwizzle, + SPVFuncImplGatherCompareSwizzle, SPVFuncImplSubgroupBallot, SPVFuncImplSubgroupBallotBitExtract, SPVFuncImplSubgroupBallotFindLSB, @@ -397,9 +550,33 @@ protected: SPVFuncImplReflectScalar, SPVFuncImplRefractScalar, SPVFuncImplFaceForwardScalar, + SPVFuncImplChromaReconstructNearest2Plane, + SPVFuncImplChromaReconstructNearest3Plane, + SPVFuncImplChromaReconstructLinear422CositedEven2Plane, + SPVFuncImplChromaReconstructLinear422CositedEven3Plane, + SPVFuncImplChromaReconstructLinear422Midpoint2Plane, + SPVFuncImplChromaReconstructLinear422Midpoint3Plane, + SPVFuncImplChromaReconstructLinear420XCositedEvenYCositedEven2Plane, + SPVFuncImplChromaReconstructLinear420XCositedEvenYCositedEven3Plane, + SPVFuncImplChromaReconstructLinear420XMidpointYCositedEven2Plane, + SPVFuncImplChromaReconstructLinear420XMidpointYCositedEven3Plane, + SPVFuncImplChromaReconstructLinear420XCositedEvenYMidpoint2Plane, + SPVFuncImplChromaReconstructLinear420XCositedEvenYMidpoint3Plane, + SPVFuncImplChromaReconstructLinear420XMidpointYMidpoint2Plane, + SPVFuncImplChromaReconstructLinear420XMidpointYMidpoint3Plane, + SPVFuncImplExpandITUFullRange, + SPVFuncImplExpandITUNarrowRange, + SPVFuncImplConvertYCbCrBT709, + SPVFuncImplConvertYCbCrBT601, + SPVFuncImplConvertYCbCrBT2020, + SPVFuncImplDynamicImageSampler, + SPVFuncImplArrayCopyMultidimMax = 6 }; + // If the underlying resource has been used for comparison then duplicate loads of that resource must be too + // Use Metal's native frame-buffer fetch API for subpass inputs. + void emit_texture_op(const Instruction &i) override; void emit_binary_unord_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, const char *op); void emit_instruction(const Instruction &instr) override; void emit_glsl_op(uint32_t result_type, uint32_t result_id, uint32_t op, const uint32_t *args, @@ -410,6 +587,8 @@ protected: void emit_function_prototype(SPIRFunction &func, const Bitset &return_flags) override; void emit_sampled_image_op(uint32_t result_type, uint32_t result_id, uint32_t image_id, uint32_t samp_id) override; void emit_subgroup_op(const Instruction &i) override; + std::string to_texture_op(const Instruction &i, bool *forward, + SmallVector &inherited_expressions) override; void emit_fixup() override; std::string to_struct_member(const SPIRType &type, uint32_t member_type_id, uint32_t index, const std::string &qualifier = ""); @@ -417,22 +596,36 @@ protected: const std::string &qualifier = "", uint32_t base_offset = 0) override; void emit_struct_padding_target(const SPIRType &type) override; std::string type_to_glsl(const SPIRType &type, uint32_t id = 0) override; + + // Allow Metal to use the array template to make arrays a value type + std::string type_to_array_glsl(const SPIRType &type) override; + + // Threadgroup arrays can't have a wrapper type + std::string variable_decl(const SPIRVariable &variable) override; + + // GCC workaround of lambdas calling protected functions (for older GCC versions) + std::string variable_decl(const SPIRType &type, const std::string &name, uint32_t id = 0) override; + std::string image_type_glsl(const SPIRType &type, uint32_t id = 0) override; std::string sampler_type(const SPIRType &type); std::string builtin_to_glsl(spv::BuiltIn builtin, spv::StorageClass storage) override; - std::string to_func_call_arg(uint32_t id) override; + std::string to_func_call_arg(const SPIRFunction::Parameter &arg, uint32_t id) override; std::string to_name(uint32_t id, bool allow_alias = true) const override; - std::string to_function_name(uint32_t img, const SPIRType &imgtype, bool is_fetch, bool is_gather, bool is_proj, + std::string to_function_name(VariableID img, const SPIRType &imgtype, bool is_fetch, bool is_gather, bool is_proj, bool has_array_offsets, bool has_offset, bool has_grad, bool has_dref, uint32_t lod, uint32_t minlod) override; - std::string to_function_args(uint32_t img, const SPIRType &imgtype, bool is_fetch, bool is_gather, bool is_proj, + std::string to_function_args(VariableID img, const SPIRType &imgtype, bool is_fetch, bool is_gather, bool is_proj, uint32_t coord, uint32_t coord_components, uint32_t dref, uint32_t grad_x, uint32_t grad_y, uint32_t lod, uint32_t coffset, uint32_t offset, uint32_t bias, uint32_t comp, uint32_t sample, uint32_t minlod, bool *p_forward) override; std::string to_initializer_expression(const SPIRVariable &var) override; + std::string unpack_expression_type(std::string expr_str, const SPIRType &type, uint32_t physical_type_id, bool is_packed, bool row_major) override; + // Returns true for BuiltInSampleMask because gl_SampleMask[] is an array in SPIR-V, but [[sample_mask]] is a scalar in Metal. + bool builtin_translates_to_nonarray(spv::BuiltIn builtin) const override; + std::string bitcast_glsl_op(const SPIRType &result_type, const SPIRType &argument_type) override; bool skip_argument(uint32_t id) const override; std::string to_member_reference(uint32_t base, const SPIRType &type, uint32_t index, bool ptr_chain) override; @@ -440,6 +633,10 @@ protected: void replace_illegal_names() override; void declare_undefined_values() override; void declare_constant_arrays(); + + // Constant arrays of non-primitive types (i.e. matrices) won't link properly into Metal libraries + void declare_complex_constant_arrays(); + bool is_patch_block(const SPIRType &type); bool is_non_native_row_major_matrix(uint32_t id) override; bool member_is_non_native_row_major_matrix(const SPIRType &type, uint32_t index) override; @@ -459,18 +656,29 @@ protected: uint32_t add_interface_block(spv::StorageClass storage, bool patch = false); uint32_t add_interface_block_pointer(uint32_t ib_var_id, spv::StorageClass storage); + struct InterfaceBlockMeta + { + struct LocationMeta + { + uint32_t num_components = 0; + uint32_t ib_index = ~0u; + }; + std::unordered_map location_meta; + bool strip_array = false; + }; + void add_variable_to_interface_block(spv::StorageClass storage, const std::string &ib_var_ref, SPIRType &ib_type, - SPIRVariable &var, bool strip_array); + SPIRVariable &var, InterfaceBlockMeta &meta); void add_composite_variable_to_interface_block(spv::StorageClass storage, const std::string &ib_var_ref, - SPIRType &ib_type, SPIRVariable &var, bool strip_array); + SPIRType &ib_type, SPIRVariable &var, InterfaceBlockMeta &meta); void add_plain_variable_to_interface_block(spv::StorageClass storage, const std::string &ib_var_ref, - SPIRType &ib_type, SPIRVariable &var, bool strip_array); + SPIRType &ib_type, SPIRVariable &var, InterfaceBlockMeta &meta); void add_plain_member_variable_to_interface_block(spv::StorageClass storage, const std::string &ib_var_ref, SPIRType &ib_type, SPIRVariable &var, uint32_t index, - bool strip_array); + InterfaceBlockMeta &meta); void add_composite_member_variable_to_interface_block(spv::StorageClass storage, const std::string &ib_var_ref, SPIRType &ib_type, SPIRVariable &var, uint32_t index, - bool strip_array); + InterfaceBlockMeta &meta); uint32_t get_accumulated_member_location(const SPIRVariable &var, uint32_t mbr_idx, bool strip_array); void add_tess_level_input_to_interface_block(const std::string &ib_var_ref, SPIRType &ib_type, SPIRVariable &var); @@ -478,8 +686,9 @@ protected: void mark_location_as_used_by_shader(uint32_t location, spv::StorageClass storage); uint32_t ensure_correct_builtin_type(uint32_t type_id, spv::BuiltIn builtin); - uint32_t ensure_correct_attribute_type(uint32_t type_id, uint32_t location); + uint32_t ensure_correct_attribute_type(uint32_t type_id, uint32_t location, uint32_t num_components = 0); + void emit_custom_templates(); void emit_custom_functions(); void emit_resources(); void emit_specialization_constants_and_structs(); @@ -505,7 +714,7 @@ protected: std::string member_attribute_qualifier(const SPIRType &type, uint32_t index); std::string argument_decl(const SPIRFunction::Parameter &arg); std::string round_fp_tex_coords(std::string tex_coords, bool coord_is_fp); - uint32_t get_metal_resource_index(SPIRVariable &var, SPIRType::BaseType basetype); + uint32_t get_metal_resource_index(SPIRVariable &var, SPIRType::BaseType basetype, uint32_t plane = 0); uint32_t get_ordered_member_location(uint32_t type_id, uint32_t index, uint32_t *comp = nullptr); // MSL packing rules. These compute the effective packing rules as observed by the MSL compiler in the MSL output. @@ -533,7 +742,7 @@ protected: void ensure_member_packing_rules_msl(SPIRType &ib_type, uint32_t index); bool validate_member_packing_rules_msl(const SPIRType &type, uint32_t index) const; std::string get_argument_address_space(const SPIRVariable &argument); - std::string get_type_address_space(const SPIRType &type, uint32_t id); + std::string get_type_address_space(const SPIRType &type, uint32_t id, bool argument = false); const char *to_restrict(uint32_t id, bool space = true); SPIRType &get_stage_in_struct_type(); SPIRType &get_stage_out_struct_type(); @@ -547,7 +756,8 @@ protected: void add_pragma_line(const std::string &line); void add_typedef_line(const std::string &line); void emit_barrier(uint32_t id_exe_scope, uint32_t id_mem_scope, uint32_t id_mem_sem); - void emit_array_copy(const std::string &lhs, uint32_t rhs_id) override; + void emit_array_copy(const std::string &lhs, uint32_t rhs_id, spv::StorageClass lhs_storage, + spv::StorageClass rhs_storage) override; void build_implicit_builtins(); uint32_t build_constant_uint_array_pointer(); void emit_entry_point_declarations() override; @@ -563,9 +773,11 @@ protected: uint32_t builtin_primitive_id_id = 0; uint32_t builtin_subgroup_invocation_id_id = 0; uint32_t builtin_subgroup_size_id = 0; + uint32_t builtin_dispatch_base_id = 0; uint32_t swizzle_buffer_id = 0; uint32_t buffer_size_buffer_id = 0; uint32_t view_mask_buffer_id = 0; + uint32_t dynamic_offsets_buffer_id = 0; void bitcast_to_builtin_store(uint32_t target_id, std::string &expr, const SPIRType &expr_type) override; void bitcast_from_builtin_load(uint32_t source_id, std::string &expr, const SPIRType &expr_type) override; @@ -574,8 +786,11 @@ protected: void analyze_sampled_image_usage(); bool emit_tessellation_access_chain(const uint32_t *ops, uint32_t length); + bool emit_tessellation_io_load(uint32_t result_type, uint32_t id, uint32_t ptr); bool is_out_of_bounds_tessellation_level(uint32_t id_lhs); + void ensure_builtin(spv::StorageClass storage, spv::BuiltIn builtin); + void mark_implicit_builtin(spv::StorageClass storage, spv::BuiltIn builtin, uint32_t id); std::string convert_to_f32(const std::string &expr, uint32_t components); @@ -590,27 +805,6 @@ protected: std::set typedef_lines; SmallVector vars_needing_early_declaration; - struct SetBindingPair - { - uint32_t desc_set; - uint32_t binding; - bool operator==(const SetBindingPair &other) const; - }; - - struct StageSetBinding - { - spv::ExecutionModel model; - uint32_t desc_set; - uint32_t binding; - bool operator==(const StageSetBinding &other) const; - }; - - struct InternalHasher - { - size_t operator()(const SetBindingPair &value) const; - size_t operator()(const StageSetBinding &value) const; - }; - std::unordered_map, InternalHasher> resource_bindings; uint32_t next_metal_resource_index_buffer = 0; @@ -619,15 +813,29 @@ protected: // Intentionally uninitialized, works around MSVC 2013 bug. uint32_t next_metal_resource_ids[kMaxArgumentBuffers]; - uint32_t stage_in_var_id = 0; - uint32_t stage_out_var_id = 0; - uint32_t patch_stage_in_var_id = 0; - uint32_t patch_stage_out_var_id = 0; - uint32_t stage_in_ptr_var_id = 0; - uint32_t stage_out_ptr_var_id = 0; + VariableID stage_in_var_id = 0; + VariableID stage_out_var_id = 0; + VariableID patch_stage_in_var_id = 0; + VariableID patch_stage_out_var_id = 0; + VariableID stage_in_ptr_var_id = 0; + VariableID stage_out_ptr_var_id = 0; + + // Handle HLSL-style 0-based vertex/instance index. + enum class TriState + { + Neutral, + No, + Yes + }; + TriState needs_base_vertex_arg = TriState::Neutral; + TriState needs_base_instance_arg = TriState::Neutral; + bool has_sampled_images = false; - bool needs_vertex_idx_arg = false; - bool needs_instance_idx_arg = false; + bool builtin_declaration = false; // Handle HLSL-style 0-based vertex/instance index. + + bool is_using_builtin_array = false; // Force the use of C style array declaration. + bool using_builtin_array() const; + bool is_rasterization_disabled = false; bool capture_output_to_buffer = false; bool needs_swizzle_buffer_def = false; @@ -642,6 +850,7 @@ protected: std::string sampler_name_suffix = "Smplr"; std::string swizzle_name_suffix = "Swzl"; std::string buffer_size_name_suffix = "BufferSize"; + std::string plane_name_suffix = "Plane"; std::string input_wg_var_name = "gl_in"; std::string output_buffer_var_name = "spvOut"; std::string patch_output_buffer_var_name = "spvPatchOut"; @@ -655,9 +864,17 @@ protected: std::unordered_set buffers_requiring_array_length; SmallVector buffer_arrays; + std::unordered_set atomic_image_vars; // Emulate texture2D atomic operations + + // Must be ordered since array is in a specific order. + std::map> buffers_requiring_dynamic_offset; + + std::unordered_set inline_uniform_blocks; uint32_t argument_buffer_ids[kMaxArgumentBuffers]; uint32_t argument_buffer_discrete_mask = 0; + uint32_t argument_buffer_device_storage_mask = 0; + void analyze_argument_buffers(); bool descriptor_set_is_argument_buffer(uint32_t desc_set) const; @@ -666,6 +883,10 @@ protected: bool suppress_missing_prototypes = false; + void add_spv_func_and_recompile(SPVFuncImpl spv_func); + + void activate_argument_buffer_resources(); + // OpcodeHandler that handles several MSL preprocessing operations. struct OpCodePreprocessor : OpcodeHandler { @@ -680,6 +901,7 @@ protected: CompilerMSL &compiler; std::unordered_map result_types; + std::unordered_map image_pointers; // Emulate texture2D atomic operations bool suppress_missing_prototypes = false; bool uses_atomics = false; bool uses_resource_write = false; diff --git a/third_party/spirv-cross/spirv_parser.cpp b/third_party/spirv-cross/spirv_parser.cpp index d5a16337d1..4479002641 100644 --- a/third_party/spirv-cross/spirv_parser.cpp +++ b/third_party/spirv-cross/spirv_parser.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2018-2019 Arm Limited + * Copyright 2018-2020 Arm Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -60,6 +60,7 @@ static bool is_valid_spirv_version(uint32_t version) case 0x10200: // SPIR-V 1.2 case 0x10300: // SPIR-V 1.3 case 0x10400: // SPIR-V 1.4 + case 0x10500: // SPIR-V 1.5 return true; default: @@ -85,6 +86,11 @@ void Parser::parse() SPIRV_CROSS_THROW("Invalid SPIRV format."); uint32_t bound = s[3]; + + const uint32_t MaximumNumberOfIDs = 0x3fffff; + if (bound > MaximumNumberOfIDs) + SPIRV_CROSS_THROW("ID bound exceeds limit of 0x3fffff.\n"); + ir.set_id_bounds(bound); uint32_t offset = 5; @@ -278,7 +284,9 @@ void Parser::parse(const Instruction &instruction) // Strings need nul-terminator and consume the whole word. uint32_t strlen_words = uint32_t((e.name.size() + 1 + 3) >> 2); - e.interface_variables.insert(end(e.interface_variables), ops + strlen_words + 2, ops + instruction.length); + + for (uint32_t i = strlen_words + 2; i < instruction.length; i++) + e.interface_variables.push_back(ops[i]); // Set the name of the entry point in case OpName is not provided later. ir.set_name(ops[1], e.name); @@ -658,7 +666,7 @@ void Parser::parse(const Instruction &instruction) } } - if (type.type_alias == 0) + if (type.type_alias == TypeID(0)) global_struct_cache.push_back(id); } break; @@ -700,15 +708,6 @@ void Parser::parse(const Instruction &instruction) } set(id, type, storage, initializer); - - // hlsl based shaders don't have those decorations. force them and then reset when reading/writing images - auto &ttype = get(type); - if (ttype.basetype == SPIRType::BaseType::Image) - { - ir.set_decoration(id, DecorationNonWritable); - ir.set_decoration(id, DecorationNonReadable); - } - break; } @@ -1008,12 +1007,12 @@ void Parser::parse(const Instruction &instruction) ir.block_meta[current_block->self] |= ParsedIR::BLOCK_META_LOOP_HEADER_BIT; ir.block_meta[current_block->merge_block] |= ParsedIR::BLOCK_META_LOOP_MERGE_BIT; - ir.continue_block_to_loop_header[current_block->continue_block] = current_block->self; + ir.continue_block_to_loop_header[current_block->continue_block] = BlockID(current_block->self); // Don't add loop headers to continue blocks, // which would make it impossible branch into the loop header since // they are treated as continues. - if (current_block->continue_block != current_block->self) + if (current_block->continue_block != BlockID(current_block->self)) ir.block_meta[current_block->continue_block] |= ParsedIR::BLOCK_META_CONTINUE_BIT; if (length >= 3) diff --git a/third_party/spirv-cross/spirv_parser.hpp b/third_party/spirv-cross/spirv_parser.hpp index ef2c1b9869..7d5b799734 100644 --- a/third_party/spirv-cross/spirv_parser.hpp +++ b/third_party/spirv-cross/spirv_parser.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2018-2019 Arm Limited + * Copyright 2018-2020 Arm Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/third_party/spirv-cross/spirv_reflect.cpp b/third_party/spirv-cross/spirv_reflect.cpp index b187a7fa61..f40c08a767 100644 --- a/third_party/spirv-cross/spirv_reflect.cpp +++ b/third_party/spirv-cross/spirv_reflect.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2018-2019 Bradley Austin Davis + * Copyright 2018-2020 Bradley Austin Davis * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -61,6 +61,7 @@ public: void end_json_array(); void emit_json_array_value(const std::string &value); void emit_json_array_value(uint32_t value); + void emit_json_array_value(bool value); std::string str() const { @@ -158,6 +159,16 @@ void Stream::emit_json_array_value(uint32_t value) stack.top().second = true; } +void Stream::emit_json_array_value(bool value) +{ + if (stack.empty() || stack.top().first != Type::Array) + SPIRV_CROSS_THROW("Invalid JSON state"); + if (stack.top().second) + statement_inner(",\n"); + statement_no_return(value ? "true" : "false"); + stack.top().second = true; +} + void Stream::begin_json_object() { if (!stack.empty() && stack.top().second) @@ -285,7 +296,7 @@ void CompilerReflection::emit_type(const SPIRType &type, bool &emitted_open_tag) { auto name = type_to_glsl(type); - if (type.type_alias != 0) + if (type.type_alias != TypeID(0)) return; if (!emitted_open_tag) @@ -347,15 +358,16 @@ void CompilerReflection::emit_type_array(const SPIRType &type) for (const auto &value : type.array) json_stream->emit_json_array_value(value); json_stream->end_json_array(); + + json_stream->emit_json_key_array("array_size_is_literal"); + for (const auto &value : type.array_size_literal) + json_stream->emit_json_array_value(value); + json_stream->end_json_array(); } } void CompilerReflection::emit_type_member_qualifiers(const SPIRType &type, uint32_t index) { - auto flags = combined_decoration_for_member(type, index); - if (flags.get(DecorationRowMajor)) - json_stream->emit_json_key_value("row_major", true); - auto &membertype = get(type.member_types[index]); emit_type_array(membertype); auto &memb = ir.meta[type.self].members; @@ -366,6 +378,16 @@ void CompilerReflection::emit_type_member_qualifiers(const SPIRType &type, uint3 json_stream->emit_json_key_value("location", dec.location); if (dec.decoration_flags.get(DecorationOffset)) json_stream->emit_json_key_value("offset", dec.offset); + + // Array stride is a property of the array type, not the struct. + if (has_decoration(type.member_types[index], DecorationArrayStride)) + json_stream->emit_json_key_value("array_stride", + get_decoration(type.member_types[index], DecorationArrayStride)); + + if (dec.decoration_flags.get(DecorationMatrixStride)) + json_stream->emit_json_key_value("matrix_stride", dec.matrix_stride); + if (dec.decoration_flags.get(DecorationRowMajor)) + json_stream->emit_json_key_value("row_major", true); } } @@ -424,6 +446,28 @@ void CompilerReflection::emit_entry_points() json_stream->begin_json_object(); json_stream->emit_json_key_value("name", e.name); json_stream->emit_json_key_value("mode", execution_model_to_str(e.execution_model)); + if (e.execution_model == ExecutionModelGLCompute) + { + const auto &spv_entry = get_entry_point(e.name, e.execution_model); + + SpecializationConstant spec_x, spec_y, spec_z; + get_work_group_size_specialization_constants(spec_x, spec_y, spec_z); + + json_stream->emit_json_key_array("workgroup_size"); + json_stream->emit_json_array_value(spec_x.id != ID(0) ? spec_x.constant_id : + spv_entry.workgroup_size.x); + json_stream->emit_json_array_value(spec_y.id != ID(0) ? spec_y.constant_id : + spv_entry.workgroup_size.y); + json_stream->emit_json_array_value(spec_z.id != ID(0) ? spec_z.constant_id : + spv_entry.workgroup_size.z); + json_stream->end_json_array(); + + json_stream->emit_json_key_array("workgroup_size_is_spec_constant_id"); + json_stream->emit_json_array_value(spec_x.id != ID(0)); + json_stream->emit_json_array_value(spec_y.id != ID(0)); + json_stream->emit_json_array_value(spec_z.id != ID(0)); + json_stream->end_json_array(); + } json_stream->end_json_object(); } json_stream->end_json_array(); @@ -468,7 +512,7 @@ void CompilerReflection::emit_resources(const char *tag, const SmallVectorbegin_json_object(); @@ -559,6 +603,7 @@ void CompilerReflection::emit_specialization_constants() json_stream->begin_json_object(); json_stream->emit_json_key_value("id", spec_const.constant_id); json_stream->emit_json_key_value("type", type_to_glsl(type)); + json_stream->emit_json_key_value("variable_id", spec_const.id); switch (type.basetype) { case SPIRType::UInt: diff --git a/third_party/spirv-cross/spirv_reflect.hpp b/third_party/spirv-cross/spirv_reflect.hpp index 5a228a6837..844d3f1e9d 100644 --- a/third_party/spirv-cross/spirv_reflect.hpp +++ b/third_party/spirv-cross/spirv_reflect.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2018-2019 Bradley Austin Davis + * Copyright 2018-2020 Bradley Austin Davis * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/third_party/spirv-cross/test_shaders.py b/third_party/spirv-cross/test_shaders.py index b3f6925337..c72c7665bc 100755 --- a/third_party/spirv-cross/test_shaders.py +++ b/third_party/spirv-cross/test_shaders.py @@ -1,5 +1,19 @@ #!/usr/bin/env python3 +# Copyright 2015-2020 Arm Limited +# +# 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. + import sys import os import os.path @@ -164,17 +178,22 @@ def cross_compile_msl(shader, spirv, opt, iterations, paths): spirv_path = create_temporary() msl_path = create_temporary(os.path.basename(shader)) - spirv_cmd = [paths.spirv_as, '--target-env', 'vulkan1.1', '-o', spirv_path, shader] + spirv_env = 'vulkan1.1spv1.4' if ('.spv14.' in shader) else 'vulkan1.1' + + spirv_cmd = [paths.spirv_as, '--target-env', spirv_env, '-o', spirv_path, shader] if '.preserve.' in shader: spirv_cmd.append('--preserve-numeric-ids') if spirv: subprocess.check_call(spirv_cmd) else: - subprocess.check_call([paths.glslang, '--target-env', 'vulkan1.1', '-V', '-o', spirv_path, shader]) + subprocess.check_call([paths.glslang, '--amb' ,'--target-env', 'vulkan1.1', '-V', '-o', spirv_path, shader]) - if opt: - subprocess.check_call([paths.spirv_opt, '--skip-validation', '-O', '-o', spirv_path, spirv_path]) + if opt and (not shader_is_invalid_spirv(shader)): + if '.graphics-robust-access.' in shader: + subprocess.check_call([paths.spirv_opt, '--skip-validation', '-O', '--graphics-robust-access', '-o', spirv_path, spirv_path]) + else: + subprocess.check_call([paths.spirv_opt, '--skip-validation', '-O', '-o', spirv_path, spirv_path]) spirv_cross_path = paths.spirv_cross @@ -195,23 +214,53 @@ def cross_compile_msl(shader, spirv, opt, iterations, paths): msl_args.append('--msl-argument-buffers') if '.texture-buffer-native.' in shader: msl_args.append('--msl-texture-buffer-native') + if '.framebuffer-fetch.' in shader: + msl_args.append('--msl-framebuffer-fetch') + if '.invariant-float-math.' in shader: + msl_args.append('--msl-invariant-float-math') + if '.emulate-cube-array.' in shader: + msl_args.append('--msl-emulate-cube-array') if '.discrete.' in shader: # Arbitrary for testing purposes. msl_args.append('--msl-discrete-descriptor-set') msl_args.append('2') msl_args.append('--msl-discrete-descriptor-set') msl_args.append('3') + if '.force-active.' in shader: + msl_args.append('--msl-force-active-argument-buffer-resources') if '.line.' in shader: msl_args.append('--emit-line-directives') if '.multiview.' in shader: msl_args.append('--msl-multiview') if '.viewfromdev.' in shader: msl_args.append('--msl-view-index-from-device-index') + if '.dispatchbase.' in shader: + msl_args.append('--msl-dispatch-base') + if '.dynamic-buffer.' in shader: + # Arbitrary for testing purposes. + msl_args.append('--msl-dynamic-buffer') + msl_args.append('0') + msl_args.append('0') + msl_args.append('--msl-dynamic-buffer') + msl_args.append('1') + msl_args.append('2') + if '.inline-block.' in shader: + # Arbitrary for testing purposes. + msl_args.append('--msl-inline-uniform-block') + msl_args.append('0') + msl_args.append('0') + if '.device-argument-buffer.' in shader: + msl_args.append('--msl-device-argument-buffer') + msl_args.append('0') + msl_args.append('--msl-device-argument-buffer') + msl_args.append('1') + if '.force-native-array.' in shader: + msl_args.append('--msl-force-native-arrays') subprocess.check_call(msl_args) if not shader_is_invalid_spirv(msl_path): - subprocess.check_call([paths.spirv_val, '--scalar-block-layout', '--target-env', 'vulkan1.1', spirv_path]) + subprocess.check_call([paths.spirv_val, '--scalar-block-layout', '--target-env', spirv_env, spirv_path]) return (spirv_path, msl_path) @@ -254,7 +303,7 @@ def validate_shader_hlsl(shader, force_no_external_validation, paths): test_glslang = False if test_glslang: - subprocess.check_call([paths.glslang, '-e', 'main', '-D', '--target-env', 'vulkan1.1', '-V', shader]) + subprocess.check_call([paths.glslang, '--amb', '-e', 'main', '-D', '--target-env', 'vulkan1.1', '-V', shader]) is_no_fxc = '.nofxc.' in shader global ignore_fxc if (not ignore_fxc) and (not force_no_external_validation) and (not is_no_fxc): @@ -297,9 +346,9 @@ def cross_compile_hlsl(shader, spirv, opt, force_no_external_validation, iterati if spirv: subprocess.check_call(spirv_cmd) else: - subprocess.check_call([paths.glslang, '--target-env', 'vulkan1.1', '-V', '-o', spirv_path, shader]) + subprocess.check_call([paths.glslang, '--amb', '--target-env', 'vulkan1.1', '-V', '-o', spirv_path, shader]) - if opt: + if opt and (not shader_is_invalid_spirv(hlsl_path)): subprocess.check_call([paths.spirv_opt, '--skip-validation', '-O', '-o', spirv_path, spirv_path]) spirv_cross_path = paths.spirv_cross @@ -309,13 +358,15 @@ def cross_compile_hlsl(shader, spirv, opt, force_no_external_validation, iterati hlsl_args = [spirv_cross_path, '--entry', 'main', '--output', hlsl_path, spirv_path, '--hlsl-enable-compat', '--hlsl', '--shader-model', sm, '--iterations', str(iterations)] if '.line.' in shader: hlsl_args.append('--emit-line-directives') + if '.force-uav.' in shader: + hlsl_args.append('--hlsl-force-storage-buffer-as-uav') subprocess.check_call(hlsl_args) if not shader_is_invalid_spirv(hlsl_path): subprocess.check_call([paths.spirv_val, '--scalar-block-layout', '--target-env', 'vulkan1.1', spirv_path]) validate_shader_hlsl(hlsl_path, force_no_external_validation, paths) - + return (spirv_path, hlsl_path) def cross_compile_reflect(shader, spirv, opt, iterations, paths): @@ -329,9 +380,9 @@ def cross_compile_reflect(shader, spirv, opt, iterations, paths): if spirv: subprocess.check_call(spirv_cmd) else: - subprocess.check_call([paths.glslang, '--target-env', 'vulkan1.1', '-V', '-o', spirv_path, shader]) + subprocess.check_call([paths.glslang, '--amb', '--target-env', 'vulkan1.1', '-V', '-o', spirv_path, shader]) - if opt: + if opt and (not shader_is_invalid_spirv(reflect_path)): subprocess.check_call([paths.spirv_opt, '--skip-validation', '-O', '-o', spirv_path, spirv_path]) spirv_cross_path = paths.spirv_cross @@ -342,7 +393,7 @@ def cross_compile_reflect(shader, spirv, opt, iterations, paths): def validate_shader(shader, vulkan, paths): if vulkan: - subprocess.check_call([paths.glslang, '--target-env', 'vulkan1.1', '-V', shader]) + subprocess.check_call([paths.glslang, '--amb', '--target-env', 'vulkan1.1', '-V', shader]) else: subprocess.check_call([paths.glslang, shader]) @@ -350,23 +401,25 @@ def cross_compile(shader, vulkan, spirv, invalid_spirv, eliminate, is_legacy, fl spirv_path = create_temporary() glsl_path = create_temporary(os.path.basename(shader)) + spirv_env = 'vulkan1.1spv1.4' if ('.spv14.' in shader) else 'vulkan1.1' + if vulkan or spirv: vulkan_glsl_path = create_temporary('vk' + os.path.basename(shader)) - spirv_cmd = [paths.spirv_as, '--target-env', 'vulkan1.1', '-o', spirv_path, shader] + spirv_cmd = [paths.spirv_as, '--target-env', spirv_env, '-o', spirv_path, shader] if '.preserve.' in shader: spirv_cmd.append('--preserve-numeric-ids') if spirv: subprocess.check_call(spirv_cmd) else: - subprocess.check_call([paths.glslang, '--target-env', 'vulkan1.1', '-V', '-o', spirv_path, shader]) + subprocess.check_call([paths.glslang, '--amb', '--target-env', 'vulkan1.1', '-V', '-o', spirv_path, shader]) if opt and (not invalid_spirv): subprocess.check_call([paths.spirv_opt, '--skip-validation', '-O', '-o', spirv_path, spirv_path]) if not invalid_spirv: - subprocess.check_call([paths.spirv_val, '--scalar-block-layout', '--target-env', 'vulkan1.1', spirv_path]) + subprocess.check_call([paths.spirv_val, '--scalar-block-layout', '--target-env', spirv_env, spirv_path]) extra_args = ['--iterations', str(iterations)] if eliminate: @@ -383,6 +436,10 @@ def cross_compile(shader, vulkan, spirv, invalid_spirv, eliminate, is_legacy, fl extra_args += ['--glsl-emit-push-constant-as-ubo'] if '.line.' in shader: extra_args += ['--emit-line-directives'] + if '.no-samplerless.' in shader: + extra_args += ['--vulkan-glsl-disable-ext-samplerless-texture-functions'] + if '.no-qualifier-deduction.' in shader: + extra_args += ['--disable-storage-image-qualifier-deduction'] spirv_cross_path = paths.spirv_cross @@ -426,30 +483,14 @@ def reference_path(directory, relpath, opt): reference_dir = os.path.join(reference_dir, split_paths[1]) return os.path.join(reference_dir, relpath) -def json_ordered(obj): - if isinstance(obj, dict): - return sorted((k, json_ordered(v)) for k, v in obj.items()) - if isinstance(obj, list): - return sorted(json_ordered(x) for x in obj) - else: - return obj - -def json_compare(json_a, json_b): - return json_ordered(json_a) == json_ordered(json_b) - def regression_check_reflect(shader, json_file, args): reference = reference_path(shader[0], shader[1], args.opt) + '.json' joined_path = os.path.join(shader[0], shader[1]) print('Reference shader reflection path:', reference) if os.path.exists(reference): - actual = '' - expected = '' - with open(json_file) as f: - actual_json = f.read(); - actual = json.loads(actual_json) - with open(reference) as f: - expected = json.load(f) - if (json_compare(actual, expected) != True): + actual = md5_for_file(json_file) + expected = md5_for_file(reference) + if actual != expected: if args.update: print('Generated reflection json has changed for {}!'.format(reference)) # If we expect changes, update the reference file. @@ -478,7 +519,7 @@ def regression_check_reflect(shader, json_file, args): print('Found new shader {}. Placing generated source code in {}'.format(joined_path, reference)) make_reference_dir(reference) shutil.move(json_file, reference) - + def regression_check(shader, glsl, args): reference = reference_path(shader[0], shader[1], args.opt) joined_path = os.path.join(shader[0], shader[1]) @@ -654,7 +695,7 @@ def test_shaders_helper(stats, backend, args): relpath = os.path.relpath(path, args.folder) all_files.append(relpath) - # The child processes in parallel execution mode don't have the proper state for the global args variable, so + # The child processes in parallel execution mode don't have the proper state for the global args variable, so # at this point we need to switch to explicit arguments if args.parallel: pool = multiprocessing.Pool(multiprocessing.cpu_count()) @@ -739,7 +780,7 @@ def main(): default = 1, type = int, help = 'Number of iterations to run SPIRV-Cross (benchmarking)') - + args = parser.parse_args() if not args.folder: sys.stderr.write('Need shader folder.\n') @@ -748,16 +789,16 @@ def main(): if (args.parallel and (args.malisc or args.force_no_external_validation or args.update)): sys.stderr.write('Parallel execution is disabled when using the flags --update, --malisc or --force-no-external-validation\n') args.parallel = False - + args.msl22 = False if args.msl: print_msl_compiler_version() args.msl22 = msl_compiler_supports_22() backend = 'glsl' - if (args.msl or args.metal): + if (args.msl or args.metal): backend = 'msl' - elif args.hlsl: + elif args.hlsl: backend = 'hlsl' elif args.reflect: backend = 'reflect' diff --git a/third_party/spirv-cross/test_shaders.sh b/third_party/spirv-cross/test_shaders.sh index 4498ac3f08..dccdf3420e 100755 --- a/third_party/spirv-cross/test_shaders.sh +++ b/third_party/spirv-cross/test_shaders.sh @@ -1,5 +1,7 @@ #!/bin/bash +OPTS=$@ + if [ -z "$SPIRV_CROSS_PATH" ]; then echo "Building spirv-cross" make -j$(nproc) @@ -11,14 +13,17 @@ echo "Using glslangValidation in: $(which glslangValidator)." echo "Using spirv-opt in: $(which spirv-opt)." echo "Using SPIRV-Cross in: \"$SPIRV_CROSS_PATH\"." -./test_shaders.py shaders --spirv-cross "$SPIRV_CROSS_PATH" || exit 1 -./test_shaders.py shaders --opt --spirv-cross "$SPIRV_CROSS_PATH" || exit 1 -./test_shaders.py shaders-no-opt --spirv-cross "$SPIRV_CROSS_PATH" || exit 1 -./test_shaders.py shaders-msl --msl --spirv-cross "$SPIRV_CROSS_PATH" || exit 1 -./test_shaders.py shaders-msl --msl --opt --spirv-cross "$SPIRV_CROSS_PATH" || exit 1 -./test_shaders.py shaders-msl-no-opt --msl --spirv-cross "$SPIRV_CROSS_PATH" || exit 1 -./test_shaders.py shaders-hlsl --hlsl --spirv-cross "$SPIRV_CROSS_PATH" || exit 1 -./test_shaders.py shaders-hlsl --hlsl --opt --spirv-cross "$SPIRV_CROSS_PATH" || exit 1 -./test_shaders.py shaders-hlsl-no-opt --hlsl --spirv-cross "$SPIRV_CROSS_PATH" || exit 1 -./test_shaders.py shaders-reflection --reflect --spirv-cross "$SPIRV_CROSS_PATH" || exit 1 +./test_shaders.py shaders ${OPTS} --spirv-cross "$SPIRV_CROSS_PATH" || exit 1 +./test_shaders.py shaders ${OPTS} --opt --spirv-cross "$SPIRV_CROSS_PATH" || exit 1 +./test_shaders.py shaders-no-opt ${OPTS} --spirv-cross "$SPIRV_CROSS_PATH" || exit 1 +./test_shaders.py shaders-msl ${OPTS} --msl --spirv-cross "$SPIRV_CROSS_PATH" || exit 1 +./test_shaders.py shaders-msl ${OPTS} --msl --opt --spirv-cross "$SPIRV_CROSS_PATH" || exit 1 +./test_shaders.py shaders-msl-no-opt ${OPTS} --msl --spirv-cross "$SPIRV_CROSS_PATH" || exit 1 +./test_shaders.py shaders-hlsl ${OPTS} --hlsl --spirv-cross "$SPIRV_CROSS_PATH" || exit 1 +./test_shaders.py shaders-hlsl ${OPTS} --hlsl --opt --spirv-cross "$SPIRV_CROSS_PATH" || exit 1 +./test_shaders.py shaders-hlsl-no-opt ${OPTS} --hlsl --spirv-cross "$SPIRV_CROSS_PATH" || exit 1 +./test_shaders.py shaders-reflection ${OPTS} --reflect --spirv-cross "$SPIRV_CROSS_PATH" || exit 1 +./test_shaders.py shaders-ue4 ${OPTS} --msl --spirv-cross "$SPIRV_CROSS_PATH" || exit 1 +./test_shaders.py shaders-ue4 ${OPTS} --msl --opt --spirv-cross "$SPIRV_CROSS_PATH" || exit 1 +./test_shaders.py shaders-ue4-no-opt ${OPTS} --msl --spirv-cross "$SPIRV_CROSS_PATH" || exit 1 diff --git a/third_party/spirv-cross/tests-other/hlsl_resource_binding.spv b/third_party/spirv-cross/tests-other/hlsl_resource_binding.spv new file mode 100644 index 0000000000000000000000000000000000000000..c48dc49ea00c0d7753a027d29dcbc8f66247a7d4 GIT binary patch literal 796 zcmYk2%}PRH5Qe`r&9c;f%*qPQWe_bYf+&a}TeM25wUmgU6-Vn1y0NaRP0;fkk8noD znR(AUGw*!aOlu*8xlrJ@7pArvG9V!oLq3k}`_BE*c=CF5a(XPI6tXc5wmvJ0q#w+x=F51Ywwxy?^1hO;947P z?)JuY{*BG}>M6EKo(F5-HRkyy*3NJ6Um*Ib;ulG+MzL+wE)nIcFKx5B4ztJydCpr- zNMg>j_D0S9Wuo)cDZfH=mbiRtZx-8UwzsKGZk4DuF}c>hu~?P5Mr`2r9wzk`xn}=1 zQLgjOcuO_-4x0D=g5-#opz1H-YPVM38m_iySk73-<%nN{Ie!ONlY8xxSI5P_lfGSY Pd&RHVtR}HPl%M1OI}s?= literal 0 HcmV?d00001 diff --git a/third_party/spirv-cross/tests-other/hlsl_resource_bindings.cpp b/third_party/spirv-cross/tests-other/hlsl_resource_bindings.cpp new file mode 100644 index 0000000000..1a938dac33 --- /dev/null +++ b/third_party/spirv-cross/tests-other/hlsl_resource_bindings.cpp @@ -0,0 +1,89 @@ +// Testbench for HLSL resource binding APIs. +// It does not validate output at the moment, but it's useful for ad-hoc testing. + +#include +#include +#include +#include + +#define SPVC_CHECKED_CALL(x) do { \ + if ((x) != SPVC_SUCCESS) { \ + fprintf(stderr, "Failed at line %d.\n", __LINE__); \ + exit(1); \ + } \ +} while(0) + +static std::vector read_file(const char *path) +{ + long len; + FILE *file = fopen(path, "rb"); + + if (!file) + return {}; + + fseek(file, 0, SEEK_END); + len = ftell(file); + rewind(file); + + std::vector buffer(len / sizeof(SpvId)); + if (fread(buffer.data(), 1, len, file) != (size_t)len) + { + fclose(file); + return {}; + } + + fclose(file); + return buffer; +} + +int main(int argc, char **argv) +{ + if (argc != 2) + return EXIT_FAILURE; + + auto buffer = read_file(argv[1]); + if (buffer.empty()) + return EXIT_FAILURE; + + spvc_context ctx; + spvc_parsed_ir parsed_ir; + spvc_compiler compiler; + + SPVC_CHECKED_CALL(spvc_context_create(&ctx)); + SPVC_CHECKED_CALL(spvc_context_parse_spirv(ctx, buffer.data(), buffer.size(), &parsed_ir)); + SPVC_CHECKED_CALL(spvc_context_create_compiler(ctx, SPVC_BACKEND_HLSL, parsed_ir, SPVC_CAPTURE_MODE_TAKE_OWNERSHIP, &compiler)); + + spvc_compiler_options opts; + SPVC_CHECKED_CALL(spvc_compiler_create_compiler_options(compiler, &opts)); + SPVC_CHECKED_CALL(spvc_compiler_options_set_uint(opts, SPVC_COMPILER_OPTION_HLSL_SHADER_MODEL, 51)); + SPVC_CHECKED_CALL(spvc_compiler_install_compiler_options(compiler, opts)); + + spvc_hlsl_resource_binding binding; + spvc_hlsl_resource_binding_init(&binding); + binding.stage = SpvExecutionModelFragment; + binding.desc_set = 1; + binding.binding = 4; + binding.srv.register_space = 2; + binding.srv.register_binding = 3; + binding.sampler.register_space = 4; + binding.sampler.register_binding = 5; + SPVC_CHECKED_CALL(spvc_compiler_hlsl_add_resource_binding(compiler, &binding)); + + binding.desc_set = SPVC_HLSL_PUSH_CONSTANT_DESC_SET; + binding.binding = SPVC_HLSL_PUSH_CONSTANT_BINDING; + binding.cbv.register_space = 0; + binding.cbv.register_binding = 4; + SPVC_CHECKED_CALL(spvc_compiler_hlsl_add_resource_binding(compiler, &binding)); + + const char *str; + SPVC_CHECKED_CALL(spvc_compiler_compile(compiler, &str)); + + fprintf(stderr, "Output:\n%s\n", str); + + if (!spvc_compiler_hlsl_is_resource_used(compiler, SpvExecutionModelFragment, 1, 4)) + return EXIT_FAILURE; + + if (!spvc_compiler_hlsl_is_resource_used(compiler, SpvExecutionModelFragment, SPVC_HLSL_PUSH_CONSTANT_DESC_SET, SPVC_HLSL_PUSH_CONSTANT_BINDING)) + return EXIT_FAILURE; +} + diff --git a/third_party/spirv-cross/tests-other/msl_ycbcr_conversion_test.cpp b/third_party/spirv-cross/tests-other/msl_ycbcr_conversion_test.cpp new file mode 100644 index 0000000000..deab27bec2 --- /dev/null +++ b/third_party/spirv-cross/tests-other/msl_ycbcr_conversion_test.cpp @@ -0,0 +1,103 @@ +// Testbench for MSL constexpr samplers, with Y'CbCr conversion. +// It does not validate output, but it's useful for ad-hoc testing. + +#ifdef _MSC_VER +#define _CRT_SECURE_NO_WARNINGS +#endif + +#include +#include +#include +#include + +#define SPVC_CHECKED_CALL(x) do { \ + if ((x) != SPVC_SUCCESS) { \ + fprintf(stderr, "Failed at line %d.\n", __LINE__); \ + exit(1); \ + } \ +} while(0) +#define SPVC_CHECKED_CALL_NEGATIVE(x) do { \ + g_fail_on_error = SPVC_FALSE; \ + if ((x) == SPVC_SUCCESS) { \ + fprintf(stderr, "Failed at line %d.\n", __LINE__); \ + exit(1); \ + } \ + g_fail_on_error = SPVC_TRUE; \ +} while(0) + +static std::vector read_file(const char *path) +{ + long len; + FILE *file = fopen(path, "rb"); + + if (!file) + return {}; + + fseek(file, 0, SEEK_END); + len = ftell(file); + rewind(file); + + std::vector buffer(len / sizeof(SpvId)); + if (fread(buffer.data(), 1, len, file) != (size_t)len) + { + fclose(file); + return {}; + } + + fclose(file); + return buffer; +} + +int main(int argc, char **argv) +{ + if (argc != 2) + return EXIT_FAILURE; + + auto buffer = read_file(argv[1]); + if (buffer.empty()) + return EXIT_FAILURE; + + spvc_context ctx; + spvc_parsed_ir parsed_ir; + spvc_compiler compiler; + spvc_compiler_options options; + + SPVC_CHECKED_CALL(spvc_context_create(&ctx)); + SPVC_CHECKED_CALL(spvc_context_parse_spirv(ctx, buffer.data(), buffer.size(), &parsed_ir)); + SPVC_CHECKED_CALL(spvc_context_create_compiler(ctx, SPVC_BACKEND_MSL, parsed_ir, SPVC_CAPTURE_MODE_TAKE_OWNERSHIP, &compiler)); + SPVC_CHECKED_CALL(spvc_compiler_create_compiler_options(compiler, &options)); + SPVC_CHECKED_CALL(spvc_compiler_options_set_uint(options, SPVC_COMPILER_OPTION_MSL_VERSION, SPVC_MAKE_MSL_VERSION(2, 0, 0))); + SPVC_CHECKED_CALL(spvc_compiler_install_compiler_options(compiler, options)); + + spvc_msl_resource_binding binding; + spvc_msl_resource_binding_init(&binding); + binding.desc_set = 1; + binding.binding = 2; + binding.stage = SpvExecutionModelFragment; + binding.msl_texture = 0; + binding.msl_sampler = 0; + SPVC_CHECKED_CALL(spvc_compiler_msl_add_resource_binding(compiler, &binding)); + + spvc_msl_constexpr_sampler samp; + spvc_msl_sampler_ycbcr_conversion conv; + spvc_msl_constexpr_sampler_init(&samp); + spvc_msl_sampler_ycbcr_conversion_init(&conv); + conv.planes = 3; + conv.resolution = SPVC_MSL_FORMAT_RESOLUTION_422; + conv.chroma_filter = SPVC_MSL_SAMPLER_FILTER_LINEAR; + conv.x_chroma_offset = SPVC_MSL_CHROMA_LOCATION_MIDPOINT; + conv.ycbcr_model = SPVC_MSL_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_BT_2020; + conv.ycbcr_range = SPVC_MSL_SAMPLER_YCBCR_RANGE_ITU_NARROW; + conv.bpc = 8; + SPVC_CHECKED_CALL(spvc_compiler_msl_remap_constexpr_sampler_by_binding_ycbcr(compiler, 1, 2, &samp, &conv)); + + const char *str; + SPVC_CHECKED_CALL(spvc_compiler_compile(compiler, &str)); + + // Should be marked, as a sanity check. + if (!spvc_compiler_msl_is_resource_used(compiler, SpvExecutionModelFragment, 1, 2)) + return EXIT_FAILURE; + + fprintf(stderr, "Output:\n%s\n", str); +} + diff --git a/third_party/spirv-cross/tests-other/msl_ycbcr_conversion_test.spv b/third_party/spirv-cross/tests-other/msl_ycbcr_conversion_test.spv new file mode 100644 index 0000000000000000000000000000000000000000..62372d5c652d451a87af8389c634f934b8acd3f0 GIT binary patch literal 728 zcmYk3%Syvw5QWF2Y1C>j)>_-Dq`DD=;zC6c-3WG55Gm?9c%#sZROLN^58?qCH{{Z2a4wN!GUt#7SrcL*+4&f+|J|oo7s3acbxBfem^|Acv0M97*9UN zuY|3yC^dTk378r3n3{blyAcO>rOZ;-mpQxYvMh_gC4WUWa$2xeS>AxVRDFiwT4GCS zjQ)Aaa9eMzDbP`uby@P8>Qk1bCw(H}iYztoyaQ$zIP$BqdCnm$L>2)c;s4_<92Y_O#hADApZaW literal 0 HcmV?d00001 diff --git a/third_party/spirv-cross/tests-other/msl_ycbcr_conversion_test_2.spv b/third_party/spirv-cross/tests-other/msl_ycbcr_conversion_test_2.spv new file mode 100644 index 0000000000000000000000000000000000000000..10fa7690d0dbc416e42af9b2e65ace610c182950 GIT binary patch literal 840 zcmZ9KNlyYn5QPhdVQ~df5OD#$a3X5l2+@m)T(}YSJjNv^;22O3{ycw`7Zcyt%$SiP z#p`;tcaN9e%bAz5oaL=yQz=>6Qaa9C)?u$d=(i_t_wA$OeIl03bAiMxD>EZRN5S(8 zjx}jbT2vf-PU`8G7Jezo7n_Xt#VpA87>2FM;XzkNF`oLHP2Aa6AG5n){LjDi=g(Nl z`9E6%<@#=ht8wsj84km-<2*Oh$Muc#Z;5*!1f$pC18(bSBIe%4kYKYz(k5qD%HH^~ zn^N{F>mO{oO{ZK%=d8Gfv}Of&57^`7C4W(Pu6%Z^L_9V#ZAh8tR$bVsE+q#3LUq^;Znhua3X<%{w?e<7 euoLaFsWY?To2|hfNWABY&T$^!1U nul - - set PATH=C:\ninja;%PATH% + - set PATH=C:\ninja;C:\Python36;%PATH% before_build: - git clone --depth=1 https://github.com/KhronosGroup/SPIRV-Headers.git external/spirv-headers @@ -59,11 +59,11 @@ build: build_script: - mkdir build && cd build - - cmake -GNinja -DSPIRV_BUILD_COMPRESSION=ON -DCMAKE_BUILD_TYPE=%CONFIGURATION% -DCMAKE_INSTALL_PREFIX=install -DRE2_BUILD_TESTING=OFF .. + - cmake -GNinja -DCMAKE_BUILD_TYPE=%CONFIGURATION% -DCMAKE_INSTALL_PREFIX=install -DRE2_BUILD_TESTING=OFF .. - ninja install test_script: - - ctest -C %CONFIGURATION% --output-on-failure --timeout 300 + - ctest -C %CONFIGURATION% --output-on-failure --timeout 310 after_test: # Zip build artifacts for uploading and deploying diff --git a/third_party/spirv-tools/.gitignore b/third_party/spirv-tools/.gitignore index 0bb282757b..196c63c922 100644 --- a/third_party/spirv-tools/.gitignore +++ b/third_party/spirv-tools/.gitignore @@ -5,15 +5,27 @@ compile_commands.json /build/ /buildtools/ /external/googletest +/external/SPIRV-Headers +/external/spirv-headers /external/effcee /external/re2 +/external/protobuf /out /TAGS /third_party/llvm-build/ /testing /tools/clang/ /utils/clang-format-diff.py +bazel-bin +bazel-genfiles +bazel-out +bazel-spirv-tools +bazel-testlogs # Vim [._]*.s[a-w][a-z] *~ + +# C-Lion +/.idea/ +/cmake-build-*/ diff --git a/third_party/spirv-tools/Android.mk b/third_party/spirv-tools/Android.mk index cc336a892a..4fab1ec73d 100644 --- a/third_party/spirv-tools/Android.mk +++ b/third_party/spirv-tools/Android.mk @@ -1,6 +1,9 @@ LOCAL_PATH := $(call my-dir) SPVTOOLS_OUT_PATH=$(if $(call host-path-is-absolute,$(TARGET_OUT)),$(TARGET_OUT),$(abspath $(TARGET_OUT))) -SPVHEADERS_LOCAL_PATH := $(LOCAL_PATH)/external/spirv-headers + +ifeq ($(SPVHEADERS_LOCAL_PATH),) + SPVHEADERS_LOCAL_PATH := $(LOCAL_PATH)/external/spirv-headers +endif SPVTOOLS_SRC_FILES := \ source/assembly_grammar.cpp \ @@ -10,7 +13,6 @@ SPVTOOLS_SRC_FILES := \ source/ext_inst.cpp \ source/enum_string_mapping.cpp \ source/extensions.cpp \ - source/id_descriptor.cpp \ source/libspirv.cpp \ source/name_mapper.cpp \ source/opcode.cpp \ @@ -19,6 +21,7 @@ SPVTOOLS_SRC_FILES := \ source/print.cpp \ source/software_version.cpp \ source/spirv_endian.cpp \ + source/spirv_optimizer_options.cpp \ source/spirv_target_env.cpp \ source/spirv_validator_options.cpp \ source/table.cpp \ @@ -46,11 +49,10 @@ SPVTOOLS_SRC_FILES := \ source/val/validate_composites.cpp \ source/val/validate_constants.cpp \ source/val/validate_conversion.cpp \ - source/val/validate_datarules.cpp \ source/val/validate_debug.cpp \ source/val/validate_decorations.cpp \ source/val/validate_derivatives.cpp \ - source/val/validate_ext_inst.cpp \ + source/val/validate_extensions.cpp \ source/val/validate_execution_limitations.cpp \ source/val/validate_function.cpp \ source/val/validate_id.cpp \ @@ -58,59 +60,76 @@ SPVTOOLS_SRC_FILES := \ source/val/validate_interfaces.cpp \ source/val/validate_instruction.cpp \ source/val/validate_memory.cpp \ + source/val/validate_memory_semantics.cpp \ + source/val/validate_misc.cpp \ source/val/validate_mode_setting.cpp \ source/val/validate_layout.cpp \ source/val/validate_literals.cpp \ source/val/validate_logicals.cpp \ source/val/validate_non_uniform.cpp \ source/val/validate_primitives.cpp \ + source/val/validate_scopes.cpp \ + source/val/validate_small_type_uses.cpp \ source/val/validate_type.cpp SPVTOOLS_OPT_SRC_FILES := \ source/opt/aggressive_dead_code_elim_pass.cpp \ + source/opt/amd_ext_to_khr.cpp \ source/opt/basic_block.cpp \ source/opt/block_merge_pass.cpp \ + source/opt/block_merge_util.cpp \ source/opt/build_module.cpp \ source/opt/cfg.cpp \ source/opt/cfg_cleanup_pass.cpp \ source/opt/ccp_pass.cpp \ + source/opt/code_sink.cpp \ source/opt/combine_access_chains.cpp \ - source/opt/common_uniform_elim_pass.cpp \ source/opt/compact_ids_pass.cpp \ source/opt/composite.cpp \ source/opt/const_folding_rules.cpp \ source/opt/constants.cpp \ + source/opt/convert_to_half_pass.cpp \ source/opt/copy_prop_arrays.cpp \ source/opt/dead_branch_elim_pass.cpp \ source/opt/dead_insert_elim_pass.cpp \ source/opt/dead_variable_elimination.cpp \ + source/opt/decompose_initialized_variables_pass.cpp \ source/opt/decoration_manager.cpp \ source/opt/def_use_manager.cpp \ + source/opt/desc_sroa.cpp \ source/opt/dominator_analysis.cpp \ source/opt/dominator_tree.cpp \ source/opt/eliminate_dead_constant_pass.cpp \ source/opt/eliminate_dead_functions_pass.cpp \ + source/opt/eliminate_dead_functions_util.cpp \ + source/opt/eliminate_dead_members_pass.cpp \ source/opt/feature_manager.cpp \ + source/opt/fix_storage_class.cpp \ source/opt/flatten_decoration_pass.cpp \ source/opt/fold.cpp \ source/opt/folding_rules.cpp \ source/opt/fold_spec_constant_op_and_composite_pass.cpp \ source/opt/freeze_spec_constant_value_pass.cpp \ source/opt/function.cpp \ + source/opt/generate_webgpu_initializers_pass.cpp \ + source/opt/graphics_robust_access_pass.cpp \ source/opt/if_conversion.cpp \ source/opt/inline_pass.cpp \ source/opt/inline_exhaustive_pass.cpp \ source/opt/inline_opaque_pass.cpp \ + source/opt/inst_bindless_check_pass.cpp \ + source/opt/inst_buff_addr_check_pass.cpp \ source/opt/instruction.cpp \ source/opt/instruction_list.cpp \ + source/opt/instrument_pass.cpp \ source/opt/ir_context.cpp \ source/opt/ir_loader.cpp \ + source/opt/legalize_vector_shuffle_pass.cpp \ source/opt/licm_pass.cpp \ source/opt/local_access_chain_convert_pass.cpp \ source/opt/local_redundancy_elimination.cpp \ source/opt/local_single_block_elim_pass.cpp \ source/opt/local_single_store_elim_pass.cpp \ - source/opt/local_ssa_elim_pass.cpp \ source/opt/loop_dependence.cpp \ source/opt/loop_dependence_helpers.cpp \ source/opt/loop_descriptor.cpp \ @@ -128,10 +147,12 @@ SPVTOOLS_OPT_SRC_FILES := \ source/opt/pass.cpp \ source/opt/pass_manager.cpp \ source/opt/private_to_local_pass.cpp \ + source/opt/process_lines_pass.cpp \ source/opt/propagator.cpp \ source/opt/reduce_load_size.cpp \ source/opt/redundancy_elimination.cpp \ source/opt/register_pressure.cpp \ + source/opt/relax_float_ops_pass.cpp \ source/opt/remove_duplicates_pass.cpp \ source/opt/replace_invalid_opc.cpp \ source/opt/scalar_analysis.cpp \ @@ -139,90 +160,67 @@ SPVTOOLS_OPT_SRC_FILES := \ source/opt/scalar_replacement_pass.cpp \ source/opt/set_spec_constant_default_value_pass.cpp \ source/opt/simplification_pass.cpp \ + source/opt/split_invalid_unreachable_pass.cpp \ source/opt/ssa_rewrite_pass.cpp \ source/opt/strength_reduction_pass.cpp \ + source/opt/strip_atomic_counter_memory_pass.cpp \ source/opt/strip_debug_info_pass.cpp \ source/opt/strip_reflect_info_pass.cpp \ + source/opt/struct_cfg_analysis.cpp \ source/opt/type_manager.cpp \ source/opt/types.cpp \ source/opt/unify_const_pass.cpp \ + source/opt/upgrade_memory_model.cpp \ source/opt/value_number_table.cpp \ source/opt/vector_dce.cpp \ - source/opt/workaround1209.cpp + source/opt/workaround1209.cpp \ + source/opt/wrap_opkill.cpp # Locations of grammar files. # -# TODO(dneto): Build a single set of tables that embeds versioning differences on -# a per-item basis. That must happen before SPIR-V 1.4, etc. -# https://github.com/KhronosGroup/SPIRV-Tools/issues/1195 -SPV_CORE10_GRAMMAR=$(SPVHEADERS_LOCAL_PATH)/include/spirv/1.0/spirv.core.grammar.json -SPV_CORE11_GRAMMAR=$(SPVHEADERS_LOCAL_PATH)/include/spirv/1.1/spirv.core.grammar.json -SPV_CORE12_GRAMMAR=$(SPVHEADERS_LOCAL_PATH)/include/spirv/1.2/spirv.core.grammar.json SPV_COREUNIFIED1_GRAMMAR=$(SPVHEADERS_LOCAL_PATH)/include/spirv/unified1/spirv.core.grammar.json -SPV_CORELATEST_GRAMMAR=$(SPV_COREUNIFIED1_GRAMMAR) SPV_GLSL_GRAMMAR=$(SPVHEADERS_LOCAL_PATH)/include/spirv/1.2/extinst.glsl.std.450.grammar.json SPV_OPENCL_GRAMMAR=$(SPVHEADERS_LOCAL_PATH)/include/spirv/1.2/extinst.opencl.std.100.grammar.json # TODO(dneto): I expect the DebugInfo grammar file to eventually migrate to SPIRV-Headers SPV_DEBUGINFO_GRAMMAR=$(LOCAL_PATH)/source/extinst.debuginfo.grammar.json +SPV_CLDEBUGINFO100_GRAMMAR=$(LOCAL_PATH)/source/extinst.opencl.debuginfo.100.grammar.json define gen_spvtools_grammar_tables -$(call generate-file-dir,$(1)/core.insts-1.0.inc) -$(1)/core.insts-1.0.inc $(1)/operand.kinds-1.0.inc $(1)/glsl.std.450.insts.inc $(1)/opencl.std.insts.inc: \ +$(call generate-file-dir,$(1)/core.insts-unified1.inc) +$(1)/core.insts-unified1.inc $(1)/operand.kinds-unified1.inc \ +$(1)/glsl.std.450.insts.inc \ +$(1)/opencl.std.insts.inc \ +: \ $(LOCAL_PATH)/utils/generate_grammar_tables.py \ - $(SPV_CORE10_GRAMMAR) \ + $(SPV_COREUNIFIED1_GRAMMAR) \ $(SPV_GLSL_GRAMMAR) \ - $(SPV_OPENCL_GRAMMAR) \ - $(SPV_DEBUGINFO_GRAMMAR) + $(SPV_OpenCL_GRAMMAR) \ + $(SPV_DEBUGINFO_GRAMMAR) \ + $(SPV_CLDEBUGINFO100_GRAMMAR) @$(HOST_PYTHON) $(LOCAL_PATH)/utils/generate_grammar_tables.py \ - --spirv-core-grammar=$(SPV_CORE10_GRAMMAR) \ + --spirv-core-grammar=$(SPV_COREUNIFIED1_GRAMMAR) \ --extinst-glsl-grammar=$(SPV_GLSL_GRAMMAR) \ --extinst-opencl-grammar=$(SPV_OPENCL_GRAMMAR) \ --extinst-debuginfo-grammar=$(SPV_DEBUGINFO_GRAMMAR) \ - --core-insts-output=$(1)/core.insts-1.0.inc \ + --extinst-cldebuginfo100-grammar=$(SPV_CLDEBUGINFO100_GRAMMAR) \ + --core-insts-output=$(1)/core.insts-unified1.inc \ --glsl-insts-output=$(1)/glsl.std.450.insts.inc \ --opencl-insts-output=$(1)/opencl.std.insts.inc \ - --operand-kinds-output=$(1)/operand.kinds-1.0.inc - @echo "[$(TARGET_ARCH_ABI)] Grammar v1.0 : instructions & operands <= grammar JSON files" -$(1)/core.insts-1.1.inc $(1)/operand.kinds-1.1.inc: \ - $(LOCAL_PATH)/utils/generate_grammar_tables.py \ - $(SPV_CORE11_GRAMMAR) \ - $(SPV_DEBUGINFO_GRAMMAR) - @$(HOST_PYTHON) $(LOCAL_PATH)/utils/generate_grammar_tables.py \ - --spirv-core-grammar=$(SPV_CORE11_GRAMMAR) \ - --extinst-debuginfo-grammar=$(SPV_DEBUGINFO_GRAMMAR) \ - --core-insts-output=$(1)/core.insts-1.1.inc \ - --operand-kinds-output=$(1)/operand.kinds-1.1.inc - @echo "[$(TARGET_ARCH_ABI)] Grammar v1.1 : instructions & operands <= grammar JSON files" -$(1)/core.insts-1.2.inc $(1)/operand.kinds-1.2.inc: \ - $(LOCAL_PATH)/utils/generate_grammar_tables.py \ - $(SPV_CORE12_GRAMMAR) \ - $(SPV_DEBUGINFO_GRAMMAR) - @$(HOST_PYTHON) $(LOCAL_PATH)/utils/generate_grammar_tables.py \ - --spirv-core-grammar=$(SPV_CORE12_GRAMMAR) \ - --extinst-debuginfo-grammar=$(SPV_DEBUGINFO_GRAMMAR) \ - --core-insts-output=$(1)/core.insts-1.2.inc \ - --operand-kinds-output=$(1)/operand.kinds-1.2.inc - @echo "[$(TARGET_ARCH_ABI)] Grammar v1.2 : instructions & operands <= grammar JSON files" -$(1)/core.insts-unified1.inc $(1)/operand.kinds-unified1.inc: \ - $(LOCAL_PATH)/utils/generate_grammar_tables.py \ - $(SPV_COREUNIFIED1_GRAMMAR) \ - $(SPV_DEBUGINFO_GRAMMAR) - @$(HOST_PYTHON) $(LOCAL_PATH)/utils/generate_grammar_tables.py \ - --spirv-core-grammar=$(SPV_COREUNIFIED1_GRAMMAR) \ - --extinst-debuginfo-grammar=$(SPV_DEBUGINFO_GRAMMAR) \ - --core-insts-output=$(1)/core.insts-unified1.inc \ --operand-kinds-output=$(1)/operand.kinds-unified1.inc - @echo "[$(TARGET_ARCH_ABI)] Grammar v1.3 (from unified1) : instructions & operands <= grammar JSON files" -$(LOCAL_PATH)/source/opcode.cpp: $(1)/core.insts-1.0.inc $(1)/core.insts-1.1.inc $(1)/core.insts-1.2.inc $(1)/core.insts-unified1.inc -$(LOCAL_PATH)/source/operand.cpp: $(1)/operand.kinds-1.0.inc $(1)/operand.kinds-1.1.inc $(1)/operand.kinds-1.2.inc $(1)/operand.kinds-unified1.inc + @echo "[$(TARGET_ARCH_ABI)] Grammar (from unified1) : instructions & operands <= grammar JSON files" +$(LOCAL_PATH)/source/opcode.cpp: $(1)/core.insts-unified1.inc +$(LOCAL_PATH)/source/operand.cpp: $(1)/operand.kinds-unified1.inc $(LOCAL_PATH)/source/ext_inst.cpp: \ $(1)/glsl.std.450.insts.inc \ $(1)/opencl.std.insts.inc \ $(1)/debuginfo.insts.inc \ + $(1)/opencl.debuginfo.100.insts.inc \ $(1)/spv-amd-gcn-shader.insts.inc \ $(1)/spv-amd-shader-ballot.insts.inc \ $(1)/spv-amd-shader-explicit-vertex-parameter.insts.inc \ $(1)/spv-amd-shader-trinary-minmax.insts.inc +$(LOCAL_PATH)/source/opt/amd_ext_to_khr.cpp: \ + $(1)/spv-amd-shader-ballot.insts.inc endef $(eval $(call gen_spvtools_grammar_tables,$(SPVTOOLS_OUT_PATH))) @@ -241,10 +239,12 @@ $(1)/$(2).h : \ --extinst-grammar=$(3) \ --extinst-output-base=$(1)/$(2) @echo "[$(TARGET_ARCH_ABI)] Generate language specific header for $(2): headers <= grammar" -$(LOCAL_PATH)/source/ext_inst.cpp: $(1)/$(2).h +$(foreach F,$(SPVTOOLS_SRC_FILES) $(SPVTOOLS_OPT_SRC_FILES),$(LOCAL_PATH)/$F ) \ + : $(1)/$(2).h endef -# We generate language-specific headers for DebugInfo +# We generate language-specific headers for DebugInfo and OpenCL.DebugInfo.100 $(eval $(call gen_spvtools_lang_headers,$(SPVTOOLS_OUT_PATH),DebugInfo,$(SPV_DEBUGINFO_GRAMMAR))) +$(eval $(call gen_spvtools_lang_headers,$(SPVTOOLS_OUT_PATH),OpenCLDebugInfo100,$(SPV_CLDEBUGINFO100_GRAMMAR))) define gen_spvtools_vendor_tables @@ -254,22 +254,28 @@ $(1)/$(2).insts.inc : \ $(LOCAL_PATH)/source/extinst.$(2).grammar.json @$(HOST_PYTHON) $(LOCAL_PATH)/utils/generate_grammar_tables.py \ --extinst-vendor-grammar=$(LOCAL_PATH)/source/extinst.$(2).grammar.json \ - --vendor-insts-output=$(1)/$(2).insts.inc + --vendor-insts-output=$(1)/$(2).insts.inc \ + --vendor-operand-kind-prefix=$(3) @echo "[$(TARGET_ARCH_ABI)] Vendor extended instruction set: $(2) tables <= grammar" $(LOCAL_PATH)/source/ext_inst.cpp: $(1)/$(2).insts.inc endef -# Vendor extended instruction sets, with grammars from SPIRV-Tools source tree. -SPV_NONSTANDARD_EXTINST_GRAMMARS=$(foreach F,$(wildcard $(LOCAL_PATH)/source/extinst.*.grammar.json),$(patsubst extinst.%.grammar.json,%,$(notdir $F))) -$(foreach E,$(SPV_NONSTANDARD_EXTINST_GRAMMARS),$(eval $(call gen_spvtools_vendor_tables,$(SPVTOOLS_OUT_PATH),$E))) +# Vendor and debug extended instruction sets, with grammars from SPIRV-Tools source tree. +$(eval $(call gen_spvtools_vendor_tables,$(SPVTOOLS_OUT_PATH),debuginfo,"")) +$(eval $(call gen_spvtools_vendor_tables,$(SPVTOOLS_OUT_PATH),opencl.debuginfo.100,"CLDEBUG100_")) +$(eval $(call gen_spvtools_vendor_tables,$(SPVTOOLS_OUT_PATH),spv-amd-gcn-shader,"")) +$(eval $(call gen_spvtools_vendor_tables,$(SPVTOOLS_OUT_PATH),spv-amd-shader-ballot,"")) +$(eval $(call gen_spvtools_vendor_tables,$(SPVTOOLS_OUT_PATH),spv-amd-shader-explicit-vertex-parameter,"")) +$(eval $(call gen_spvtools_vendor_tables,$(SPVTOOLS_OUT_PATH),spv-amd-shader-trinary-minmax,"")) define gen_spvtools_enum_string_mapping $(call generate-file-dir,$(1)/extension_enum.inc.inc) $(1)/extension_enum.inc $(1)/enum_string_mapping.inc: \ $(LOCAL_PATH)/utils/generate_grammar_tables.py \ - $(SPV_CORELATEST_GRAMMAR) + $(SPV_COREUNIFIED1_GRAMMAR) @$(HOST_PYTHON) $(LOCAL_PATH)/utils/generate_grammar_tables.py \ - --spirv-core-grammar=$(SPV_CORELATEST_GRAMMAR) \ + --spirv-core-grammar=$(SPV_COREUNIFIED1_GRAMMAR) \ --extinst-debuginfo-grammar=$(SPV_DEBUGINFO_GRAMMAR) \ + --extinst-cldebuginfo100-grammar=$(SPV_CLDEBUGINFO100_GRAMMAR) \ --extension-enum-output=$(1)/extension_enum.inc \ --enum-string-mapping-output=$(1)/enum_string_mapping.inc @echo "[$(TARGET_ARCH_ABI)] Generate enum<->string mapping <= grammar JSON files" @@ -310,7 +316,7 @@ include $(CLEAR_VARS) LOCAL_MODULE := SPIRV-Tools LOCAL_C_INCLUDES := \ $(LOCAL_PATH)/include \ - $(LOCAL_PATH)/external/spirv-headers/include \ + $(SPVHEADERS_LOCAL_PATH)/include \ $(SPVTOOLS_OUT_PATH) LOCAL_EXPORT_C_INCLUDES := \ $(LOCAL_PATH)/include @@ -323,7 +329,7 @@ LOCAL_MODULE := SPIRV-Tools-opt LOCAL_C_INCLUDES := \ $(LOCAL_PATH)/include \ $(LOCAL_PATH)/source \ - $(LOCAL_PATH)/external/spirv-headers/include \ + $(SPVHEADERS_LOCAL_PATH)/include \ $(SPVTOOLS_OUT_PATH) LOCAL_CXXFLAGS:=-std=c++11 -fno-exceptions -fno-rtti -Werror LOCAL_STATIC_LIBRARIES:=SPIRV-Tools diff --git a/third_party/spirv-tools/BUILD.bazel b/third_party/spirv-tools/BUILD.bazel new file mode 100644 index 0000000000..3046781fc2 --- /dev/null +++ b/third_party/spirv-tools/BUILD.bazel @@ -0,0 +1,511 @@ +load( + ":build_defs.bzl", + "COMMON_COPTS", + "DEBUGINFO_GRAMMAR_JSON_FILE", + "CLDEBUGINFO100_GRAMMAR_JSON_FILE", + "TEST_COPTS", + "base_test", + "generate_core_tables", + "generate_enum_string_mapping", + "generate_extinst_lang_headers", + "generate_glsl_tables", + "generate_opencl_tables", + "generate_vendor_tables", + "link_test", + "opt_test", + "reduce_test", + "util_test", + "val_test", +) + +package( + default_visibility = ["//visibility:private"], +) + +licenses(["notice"]) + +exports_files([ + "CHANGES", + "LICENSE", +]) + +py_binary( + name = "generate_grammar_tables", + srcs = ["utils/generate_grammar_tables.py"], +) + +py_binary( + name = "generate_language_headers", + srcs = ["utils/generate_language_headers.py"], +) + +generate_core_tables("unified1") + +generate_enum_string_mapping("unified1") + +generate_opencl_tables("unified1") + +generate_glsl_tables("unified1") + +generate_vendor_tables("spv-amd-shader-explicit-vertex-parameter") + +generate_vendor_tables("spv-amd-shader-trinary-minmax") + +generate_vendor_tables("spv-amd-gcn-shader") + +generate_vendor_tables("spv-amd-shader-ballot") + +generate_vendor_tables("debuginfo") + +generate_vendor_tables("opencl.debuginfo.100", "CLDEBUG100_") + +generate_extinst_lang_headers("DebugInfo", DEBUGINFO_GRAMMAR_JSON_FILE) + +generate_extinst_lang_headers("OpenCLDebugInfo100", CLDEBUGINFO100_GRAMMAR_JSON_FILE) + +py_binary( + name = "generate_registry_tables", + srcs = ["utils/generate_registry_tables.py"], +) + +genrule( + name = "gen_registry_tables", + srcs = ["@spirv_headers//:spirv_xml_registry"], + outs = ["generators.inc"], + cmd = "$(location generate_registry_tables) --xml=$(location @spirv_headers//:spirv_xml_registry) --generator-output=$(location generators.inc)", + tools = [":generate_registry_tables"], +) + +py_binary( + name = "update_build_version", + srcs = ["utils/update_build_version.py"], +) + +genrule( + name = "gen_build_version", + srcs = ["CHANGES"], + outs = ["build-version.inc"], + cmd = "SOURCE_DATE_EPOCH=0 $(location update_build_version) $$(dirname $(location CHANGES)) $(location build-version.inc)", + tools = [":update_build_version"], +) + +# Libraries + +cc_library( + name = "generated_headers", + hdrs = [ + ":gen_build_version", + ":gen_core_tables_unified1", + ":gen_enum_string_mapping", + ":gen_extinst_lang_headers_DebugInfo", + ":gen_extinst_lang_headers_OpenCLDebugInfo100", + ":gen_glsl_tables_unified1", + ":gen_opencl_tables_unified1", + ":gen_registry_tables", + ":gen_vendor_tables_debuginfo", + ":gen_vendor_tables_opencl_debuginfo_100", + ":gen_vendor_tables_spv_amd_gcn_shader", + ":gen_vendor_tables_spv_amd_shader_ballot", + ":gen_vendor_tables_spv_amd_shader_explicit_vertex_parameter", + ":gen_vendor_tables_spv_amd_shader_trinary_minmax", + ], + copts = COMMON_COPTS, +) + +cc_library( + name = "spirv_tools_headers", + hdrs = glob([ + "include/spirv-tools/libspirv.h", + "include/spirv-tools/libspirv.hpp", + "source/*.h", + "source/util/*.h", + "source/val/*.h", + ]), + copts = COMMON_COPTS, + includes = ["source"], + deps = [ + "@spirv_headers//:spirv_c_headers", + ], +) + +cc_library( + name = "spirv_tools", + srcs = glob([ + "source/*.cpp", + "source/util/*.cpp", + "source/val/*.cpp", + ]), + hdrs = [ + "include/spirv-tools/libspirv.h", + "include/spirv-tools/libspirv.hpp", + ], + copts = COMMON_COPTS + select({ + "@bazel_tools//src/conditions:windows": [""], + "//conditions:default": ["-Wno-implicit-fallthrough"], + }), + includes = ["include"], + linkstatic = 1, + visibility = ["//visibility:public"], + deps = [ + ":generated_headers", + ":spirv_tools_headers", + "@spirv_headers//:spirv_c_headers", + "@spirv_headers//:spirv_common_headers", + ], +) + +cc_library( + name = "spirv_tools_comp", + srcs = glob([ + "source/comp/*.cpp", + "source/comp/*.h", + ]), + copts = COMMON_COPTS, + linkstatic = 1, + visibility = ["//visibility:public"], + deps = [ + ":generated_headers", + ":spirv_tools", + ":spirv_tools_headers", + "@spirv_headers//:spirv_common_headers", + ], +) + +cc_library( + name = "spirv_tools_opt_headers", + hdrs = glob(["source/opt/*.h"]), + copts = COMMON_COPTS, +) + +cc_library( + name = "spirv_tools_opt", + srcs = glob(["source/opt/*.cpp"]), + hdrs = [ + "include/spirv-tools/instrument.hpp", + "include/spirv-tools/optimizer.hpp", + ], + copts = COMMON_COPTS, + includes = ["include"], + linkstatic = 1, + visibility = ["//visibility:public"], + deps = [ + ":spirv_tools", + ":spirv_tools_headers", + ":spirv_tools_opt_headers", + "@spirv_headers//:spirv_common_headers", + ], +) + +cc_library( + name = "spirv_tools_reduce", + srcs = glob(["source/reduce/*.cpp"]), + hdrs = glob(["source/reduce/*.h"]), + copts = COMMON_COPTS, + linkstatic = 1, + visibility = ["//visibility:public"], + deps = [ + ":spirv_tools", + ":spirv_tools_opt", + ], +) + +cc_library( + name = "spirv_tools_link", + srcs = glob(["source/link/*.cpp"]), + hdrs = ["include/spirv-tools/linker.hpp"], + copts = COMMON_COPTS, + linkstatic = 1, + visibility = ["//visibility:public"], + deps = [ + ":spirv_tools", + ":spirv_tools_opt", + ], +) + +cc_library( + name = "tools_util", + srcs = glob(["tools/util/*.cpp"]), + hdrs = glob(["tools/util/*.h"]), + copts = COMMON_COPTS, + linkstatic = 1, + visibility = ["//visibility:public"], + deps = [":spirv_tools"], +) + +# Tools + +cc_binary( + name = "spirv-as", + srcs = [ + "tools/as/as.cpp", + "tools/io.h", + ], + copts = COMMON_COPTS, + visibility = ["//visibility:public"], + deps = [ + ":spirv_tools", + ], +) + +cc_binary( + name = "spirv-dis", + srcs = [ + "tools/dis/dis.cpp", + "tools/io.h", + ], + copts = COMMON_COPTS, + visibility = ["//visibility:public"], + deps = [ + ":spirv_tools", + ], +) + +cc_binary( + name = "spirv-val", + srcs = [ + "tools/io.h", + "tools/val/val.cpp", + ], + copts = COMMON_COPTS, + visibility = ["//visibility:public"], + deps = [ + ":spirv_tools", + ":tools_util", + ], +) + +cc_binary( + name = "spirv-opt", + srcs = [ + "tools/io.h", + "tools/opt/opt.cpp", + ], + copts = COMMON_COPTS, + visibility = ["//visibility:public"], + deps = [ + ":spirv_tools", + ":spirv_tools_opt", + ":tools_util", + ], +) + +cc_binary( + name = "spirv-reduce", + srcs = [ + "tools/io.h", + "tools/reduce/reduce.cpp", + ], + copts = COMMON_COPTS, + visibility = ["//visibility:public"], + deps = [ + ":spirv_tools", + ":spirv_tools_opt", + ":spirv_tools_reduce", + ":tools_util", + ], +) + +cc_binary( + name = "spirv-link", + srcs = [ + "tools/io.h", + "tools/link/linker.cpp", + ], + copts = COMMON_COPTS, + visibility = ["//visibility:public"], + deps = [ + ":spirv_tools", + ":spirv_tools_link", + ], +) + +cc_binary( + name = "spirv-cfg", + srcs = [ + "tools/cfg/bin_to_dot.cpp", + "tools/cfg/bin_to_dot.h", + "tools/cfg/cfg.cpp", + "tools/io.h", + ], + copts = COMMON_COPTS, + visibility = ["//visibility:public"], + deps = [":spirv_tools"], +) + +# Unit tests + +cc_library( + name = "test_common", + testonly = 1, + srcs = [ + "test/test_fixture.h", + "test/unit_spirv.cpp", + "test/unit_spirv.h", + ], + compatible_with = [], + copts = TEST_COPTS, + includes = ["test"], + linkstatic = 1, + deps = [ + ":spirv_tools", + "@com_google_googletest//:gtest", + ], +) + +cc_library( + name = "link_test_common", + testonly = 1, + srcs = ["test/link/linker_fixture.h"], + compatible_with = [], + copts = TEST_COPTS, + linkstatic = 1, + deps = [ + ":spirv_tools_link", + ":test_common", + ], +) + +cc_library( + name = "opt_test_common", + testonly = 1, + srcs = ["test/opt/pass_utils.cpp"], + hdrs = [ + "test/opt/assembly_builder.h", + "test/opt/function_utils.h", + "test/opt/module_utils.h", + "test/opt/pass_fixture.h", + "test/opt/pass_utils.h", + ], + compatible_with = [], + copts = TEST_COPTS, + linkstatic = 1, + deps = [ + ":spirv_tools_opt", + ":test_common", + ], +) + +cc_library( + name = "reduce_test_common", + testonly = 1, + srcs = [ + "test/reduce/reduce_test_util.cpp", + "tools/io.h", + ], + hdrs = ["test/reduce/reduce_test_util.h"], + compatible_with = [], + copts = TEST_COPTS, + linkstatic = 1, + deps = [ + ":spirv_tools_reduce", + ":test_common", + ], +) + +cc_library( + name = "val_test_common", + testonly = 1, + srcs = [ + "test/val/val_code_generator.cpp", + "test/val/val_fixtures.h", + ], + hdrs = [ + "test/val/val_code_generator.h", + ], + compatible_with = [], + copts = TEST_COPTS, + linkstatic = 1, + deps = [":test_common"], +) + +# PCH (precompiled header) tests only work when using CMake and MSVC on Windows, +# so they will be skipped in the Bazel builds. + +[base_test( + name = f[5:-4], # strip test/, .cpp + srcs = [f], +) for f in glob( + ["test/*.cpp"], + exclude = [ + "test/cpp_interface_test.cpp", # has its own base_test below. + "test/log_test.cpp", # has its own base_test below. + "test/pch_test.cpp", # pch tests are skipped. + "test/timer_test.cpp", # has its own base_test below. + ], +)] + +# This test uses unistd.h and does not run on Windows. +base_test( + name = "timer_test", + srcs = select({ + "@bazel_tools//src/conditions:windows": [], + "//conditions:default": ["test/timer_test.cpp"], + }), +) + +base_test( + name = "cpp_interface_test", + srcs = ["test/cpp_interface_test.cpp"], + deps = [":spirv_tools_opt"], +) + +base_test( + name = "log_test", + srcs = ["test/log_test.cpp"], + deps = [":spirv_tools_opt"], +) + +[link_test( + name = f[10:-4], # strip test/link/, .cpp + srcs = [f], +) for f in glob( + ["test/link/*.cpp"], +)] + +[opt_test( + name = f[9:-4], # strip test/opt/, .cpp + srcs = [f], +) for f in glob( + ["test/opt/*.cpp"], + # pch tests are skipped. + exclude = ["test/opt/pch_test_opt.cpp"], +)] + +[opt_test( + name = "dom_tree_" + f[24:-4], # strip test/opt/dominator_tree/, .cpp + srcs = [f], +) for f in glob( + ["test/opt/dominator_tree/*.cpp"], + # pch tests are skipped. + exclude = ["test/opt/dominator_tree/pch_test_opt_dom.cpp"], +)] + +[opt_test( + name = "loop_" + f[28:-4], # strip test/opt/loop_optimizations/, .cpp + srcs = [f], +) for f in glob( + ["test/opt/loop_optimizations/*.cpp"], + # pch tests are skipped. + exclude = ["test/opt/loop_optimizations/pch_test_opt_loop.cpp"], +)] + +[reduce_test( + name = f[12:-4], # strip test/reduce/, .cpp + srcs = [f], +) for f in glob(["test/reduce/*.cpp"])] + +[util_test( + name = f[10:-4], # strip test/util/, .cpp + srcs = [f], +) for f in glob(["test/util/*.cpp"])] + +[val_test( + name = f[9:-4], # strip test/val/, .cpp + srcs = [f], +) for f in glob( + ["test/val/*.cpp"], + exclude = [ + "test/val/pch_test_val.cpp", # pch tests are skipped. + ], +)] + diff --git a/third_party/spirv-tools/BUILD.gn b/third_party/spirv-tools/BUILD.gn index 9fa9493df5..28dcc3d727 100644 --- a/third_party/spirv-tools/BUILD.gn +++ b/third_party/spirv-tools/BUILD.gn @@ -12,10 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -import("//build_overrides/spirv_tools.gni") - -import("//testing/test.gni") import("//build_overrides/build.gni") +import("//build_overrides/spirv_tools.gni") +if (build_with_chromium) { + import("//testing/test.gni") +} spirv_headers = spirv_tools_spirv_headers_dir @@ -31,7 +32,8 @@ template("spvtools_core_tables") { "${spirv_headers}/include/spirv/$version/spirv.core.grammar.json" core_insts_file = "${target_gen_dir}/core.insts-$version.inc" operand_kinds_file = "${target_gen_dir}/operand.kinds-$version.inc" - extinst_file = "source/extinst.debuginfo.grammar.json" + debuginfo_insts_file = "source/extinst.debuginfo.grammar.json" + cldebuginfo100_insts_file = "source/extinst.opencl.debuginfo.100.grammar.json" sources = [ core_json_file, @@ -46,7 +48,9 @@ template("spvtools_core_tables") { "--core-insts-output", rebase_path(core_insts_file, root_build_dir), "--extinst-debuginfo-grammar", - rebase_path(extinst_file, root_build_dir), + rebase_path(debuginfo_insts_file, root_build_dir), + "--extinst-cldebuginfo100-grammar", + rebase_path(cldebuginfo100_insts_file, root_build_dir), "--operand-kinds-output", rebase_path(operand_kinds_file, root_build_dir), ] @@ -63,7 +67,9 @@ template("spvtools_core_enums") { core_json_file = "${spirv_headers}/include/spirv/$version/spirv.core.grammar.json" - debug_insts_file = "source/extinst.debuginfo.grammar.json" + debuginfo_insts_file = "source/extinst.debuginfo.grammar.json" + cldebuginfo100_insts_file = "source/extinst.opencl.debuginfo.100.grammar.json" + extension_enum_file = "${target_gen_dir}/extension_enum.inc" extension_map_file = "${target_gen_dir}/enum_string_mapping.inc" @@ -71,7 +77,9 @@ template("spvtools_core_enums") { "--spirv-core-grammar", rebase_path(core_json_file, root_build_dir), "--extinst-debuginfo-grammar", - rebase_path(debug_insts_file, root_build_dir), + rebase_path(debuginfo_insts_file, root_build_dir), + "--extinst-cldebuginfo100-grammar", + rebase_path(cldebuginfo100_insts_file, root_build_dir), "--extension-enum-output", rebase_path(extension_enum_file, root_build_dir), "--enum-string-mapping-output", @@ -79,6 +87,8 @@ template("spvtools_core_enums") { ] inputs = [ core_json_file, + debuginfo_insts_file, + cldebuginfo100_insts_file, ] outputs = [ extension_enum_file, @@ -98,22 +108,28 @@ template("spvtools_glsl_tables") { core_json_file = "${spirv_headers}/include/spirv/$version/spirv.core.grammar.json" glsl_json_file = "${spirv_headers}/include/spirv/${version}/extinst.glsl.std.450.grammar.json" + debuginfo_insts_file = "source/extinst.debuginfo.grammar.json" + cldebuginfo100_insts_file = "source/extinst.opencl.debuginfo.100.grammar.json" + glsl_insts_file = "${target_gen_dir}/glsl.std.450.insts.inc" - debug_insts_file = "source/extinst.debuginfo.grammar.json" args = [ "--spirv-core-grammar", rebase_path(core_json_file, root_build_dir), + "--extinst-debuginfo-grammar", + rebase_path(debuginfo_insts_file, root_build_dir), + "--extinst-cldebuginfo100-grammar", + rebase_path(cldebuginfo100_insts_file, root_build_dir), "--extinst-glsl-grammar", rebase_path(glsl_json_file, root_build_dir), "--glsl-insts-output", rebase_path(glsl_insts_file, root_build_dir), - "--extinst-debuginfo-grammar", - rebase_path(debug_insts_file, root_build_dir), ] inputs = [ core_json_file, glsl_json_file, + debuginfo_insts_file, + cldebuginfo100_insts_file, ] outputs = [ glsl_insts_file, @@ -131,23 +147,29 @@ template("spvtools_opencl_tables") { core_json_file = "${spirv_headers}/include/spirv/$version/spirv.core.grammar.json" - opengl_json_file = "${spirv_headers}/include/spirv/${version}/extinst.opencl.std.100.grammar.json" + opencl_json_file = "${spirv_headers}/include/spirv/${version}/extinst.opencl.std.100.grammar.json" + debuginfo_insts_file = "source/extinst.debuginfo.grammar.json" + cldebuginfo100_insts_file = "source/extinst.opencl.debuginfo.100.grammar.json" + opencl_insts_file = "${target_gen_dir}/opencl.std.insts.inc" - debug_insts_file = "source/extinst.debuginfo.grammar.json" args = [ "--spirv-core-grammar", rebase_path(core_json_file, root_build_dir), + "--extinst-debuginfo-grammar", + rebase_path(debuginfo_insts_file, root_build_dir), + "--extinst-cldebuginfo100-grammar", + rebase_path(cldebuginfo100_insts_file, root_build_dir), "--extinst-opencl-grammar", - rebase_path(opengl_json_file, root_build_dir), + rebase_path(opencl_json_file, root_build_dir), "--opencl-insts-output", rebase_path(opencl_insts_file, root_build_dir), - "--extinst-debuginfo-grammar", - rebase_path(debug_insts_file, root_build_dir), ] inputs = [ core_json_file, - opengl_json_file, + opencl_json_file, + debuginfo_insts_file, + cldebuginfo100_insts_file, ] outputs = [ opencl_insts_file, @@ -163,18 +185,17 @@ template("spvtools_language_header") { name = invoker.name extinst_output_base = "${target_gen_dir}/${name}" - debug_insts_file = "source/extinst.debuginfo.grammar.json" args = [ "--extinst-name", "${name}", "--extinst-grammar", - rebase_path(debug_insts_file, root_build_dir), + rebase_path(invoker.grammar_file, root_build_dir), "--extinst-output-base", rebase_path(extinst_output_base, root_build_dir), ] inputs = [ - debug_insts_file, + invoker.grammar_file, ] outputs = [ "${extinst_output_base}.h", @@ -197,6 +218,8 @@ template("spvtools_vendor_table") { rebase_path(extinst_vendor_grammar, root_build_dir), "--vendor-insts-output", rebase_path(extinst_file, root_build_dir), + "--vendor-operand-kind-prefix", + invoker.operand_kind_prefix ] inputs = [ extinst_vendor_grammar, @@ -255,47 +278,75 @@ spvtools_glsl_tables("glsl1-0") { spvtools_opencl_tables("opencl1-0") { version = "1.0" } -spvtools_language_header("unified1") { +spvtools_language_header("debuginfo") { name = "DebugInfo" + grammar_file = "source/extinst.debuginfo.grammar.json" +} +spvtools_language_header("cldebuginfo100") { + name = "OpenCLDebugInfo100" + grammar_file = "source/extinst.opencl.debuginfo.100.grammar.json" } spvtools_vendor_tables = [ - "spv-amd-shader-explicit-vertex-parameter", - "spv-amd-shader-trinary-minmax", - "spv-amd-gcn-shader", - "spv-amd-shader-ballot", - "debuginfo", + ["spv-amd-shader-explicit-vertex-parameter", "...nil..."], + ["spv-amd-shader-trinary-minmax", "...nil..."], + ["spv-amd-gcn-shader", "...nil..."], + ["spv-amd-shader-ballot", "...nil..."], + ["debuginfo", "...nil..."], + ["opencl.debuginfo.100", "CLDEBUG100_"], ] -foreach(table, spvtools_vendor_tables) { - spvtools_vendor_table(table) { - name = table +foreach(table_def, spvtools_vendor_tables) { + spvtools_vendor_table(table_def[0]) { + name = table_def[0] + operand_kind_prefix = table_def[1] } } -config("spvtools_config") { +config("spvtools_public_config") { + include_dirs = [ "include" ] +} + +config("spvtools_internal_config") { include_dirs = [ ".", - "include", "$target_gen_dir", "${spirv_headers}/include", ] + configs = [ ":spvtools_public_config" ] + if (is_clang) { - cflags = [ "-Wno-implicit-fallthrough" ] + cflags = [ + "-Wno-implicit-fallthrough", + "-Wno-newline-eof", + ] } } +source_set("spvtools_headers") { + sources = [ + "include/spirv-tools/instrument.hpp", + "include/spirv-tools/libspirv.h", + "include/spirv-tools/libspirv.hpp", + "include/spirv-tools/linker.hpp", + "include/spirv-tools/optimizer.hpp", + ] + + public_configs = [ ":spvtools_public_config" ] +} + static_library("spvtools") { deps = [ - ":spvtools_core_enums_unified1", ":spvtools_core_tables_unified1", ":spvtools_generators_inc", ":spvtools_glsl_tables_glsl1-0", - ":spvtools_language_header_unified1", + ":spvtools_language_header_debuginfo", + ":spvtools_language_header_cldebuginfo100", ":spvtools_opencl_tables_opencl1-0", ] - foreach(target_name, spvtools_vendor_tables) { + foreach(table_def, spvtools_vendor_tables) { + target_name = table_def[0] deps += [ ":spvtools_vendor_tables_$target_name" ] } @@ -304,16 +355,22 @@ static_library("spvtools") { "source/assembly_grammar.h", "source/binary.cpp", "source/binary.h", + "source/cfa.h", "source/diagnostic.cpp", "source/diagnostic.h", "source/disassemble.cpp", + "source/disassemble.h", "source/enum_set.h", "source/enum_string_mapping.cpp", + "source/enum_string_mapping.h", "source/ext_inst.cpp", "source/ext_inst.h", "source/extensions.cpp", "source/extensions.h", "source/instruction.h", + "source/latest_version_glsl_std_450_header.h", + "source/latest_version_opencl_std_header.h", + "source/latest_version_spirv_header.h", "source/libspirv.cpp", "source/macro.h", "source/name_mapper.cpp", @@ -330,6 +387,8 @@ static_library("spvtools") { "source/spirv_definition.h", "source/spirv_endian.cpp", "source/spirv_endian.h", + "source/spirv_optimizer_options.cpp", + "source/spirv_optimizer_options.h", "source/spirv_target_env.cpp", "source/spirv_target_env.h", "source/spirv_validator_options.cpp", @@ -356,16 +415,28 @@ static_library("spvtools") { "source/util/timer.h", ] - public_configs = [ ":spvtools_config" ] - configs -= [ "//build/config/compiler:chromium_code" ] - configs += [ "//build/config/compiler:no_chromium_code" ] + public_deps = [ + ":spvtools_core_enums_unified1", + ":spvtools_headers", + "${spirv_headers}:spv_headers", + ] + + if (build_with_chromium) { + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + } + configs += [ ":spvtools_internal_config" ] } static_library("spvtools_val") { sources = [ "source/val/basic_block.cpp", + "source/val/basic_block.h", "source/val/construct.cpp", + "source/val/construct.h", + "source/val/decoration.h", "source/val/function.cpp", + "source/val/function.h", "source/val/instruction.cpp", "source/val/validate.cpp", "source/val/validate.h", @@ -381,12 +452,11 @@ static_library("spvtools_val") { "source/val/validate_composites.cpp", "source/val/validate_constants.cpp", "source/val/validate_conversion.cpp", - "source/val/validate_datarules.cpp", "source/val/validate_debug.cpp", "source/val/validate_decorations.cpp", "source/val/validate_derivatives.cpp", "source/val/validate_execution_limitations.cpp", - "source/val/validate_ext_inst.cpp", + "source/val/validate_extensions.cpp", "source/val/validate_function.cpp", "source/val/validate_id.cpp", "source/val/validate_image.cpp", @@ -396,30 +466,48 @@ static_library("spvtools_val") { "source/val/validate_literals.cpp", "source/val/validate_logicals.cpp", "source/val/validate_memory.cpp", + "source/val/validate_memory_semantics.cpp", + "source/val/validate_memory_semantics.h", + "source/val/validate_misc.cpp", "source/val/validate_mode_setting.cpp", "source/val/validate_non_uniform.cpp", "source/val/validate_primitives.cpp", + "source/val/validate_scopes.cpp", + "source/val/validate_scopes.h", + "source/val/validate_small_type_uses.cpp", "source/val/validate_type.cpp", "source/val/validation_state.cpp", + "source/val/validation_state.h", ] deps = [ ":spvtools", + ":spvtools_language_header_cldebuginfo100", + ":spvtools_language_header_debuginfo", + ] + public_deps = [ + ":spvtools_headers", ] - public_configs = [ ":spvtools_config" ] - configs -= [ "//build/config/compiler:chromium_code" ] - configs += [ "//build/config/compiler:no_chromium_code" ] + if (build_with_chromium) { + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + } + configs += [ ":spvtools_internal_config" ] } static_library("spvtools_opt") { sources = [ "source/opt/aggressive_dead_code_elim_pass.cpp", "source/opt/aggressive_dead_code_elim_pass.h", + "source/opt/amd_ext_to_khr.cpp", + "source/opt/amd_ext_to_khr.h", "source/opt/basic_block.cpp", "source/opt/basic_block.h", "source/opt/block_merge_pass.cpp", "source/opt/block_merge_pass.h", + "source/opt/block_merge_util.cpp", + "source/opt/block_merge_util.h", "source/opt/build_module.cpp", "source/opt/build_module.h", "source/opt/ccp_pass.cpp", @@ -428,10 +516,10 @@ static_library("spvtools_opt") { "source/opt/cfg.h", "source/opt/cfg_cleanup_pass.cpp", "source/opt/cfg_cleanup_pass.h", + "source/opt/code_sink.cpp", + "source/opt/code_sink.h", "source/opt/combine_access_chains.cpp", "source/opt/combine_access_chains.h", - "source/opt/common_uniform_elim_pass.cpp", - "source/opt/common_uniform_elim_pass.h", "source/opt/compact_ids_pass.cpp", "source/opt/compact_ids_pass.h", "source/opt/composite.cpp", @@ -440,6 +528,8 @@ static_library("spvtools_opt") { "source/opt/const_folding_rules.h", "source/opt/constants.cpp", "source/opt/constants.h", + "source/opt/convert_to_half_pass.cpp", + "source/opt/convert_to_half_pass.h", "source/opt/copy_prop_arrays.cpp", "source/opt/copy_prop_arrays.h", "source/opt/dead_branch_elim_pass.cpp", @@ -448,10 +538,14 @@ static_library("spvtools_opt") { "source/opt/dead_insert_elim_pass.h", "source/opt/dead_variable_elimination.cpp", "source/opt/dead_variable_elimination.h", + "source/opt/decompose_initialized_variables_pass.cpp", + "source/opt/decompose_initialized_variables_pass.h", "source/opt/decoration_manager.cpp", "source/opt/decoration_manager.h", "source/opt/def_use_manager.cpp", "source/opt/def_use_manager.h", + "source/opt/desc_sroa.cpp", + "source/opt/desc_sroa.h", "source/opt/dominator_analysis.cpp", "source/opt/dominator_analysis.h", "source/opt/dominator_tree.cpp", @@ -460,8 +554,14 @@ static_library("spvtools_opt") { "source/opt/eliminate_dead_constant_pass.h", "source/opt/eliminate_dead_functions_pass.cpp", "source/opt/eliminate_dead_functions_pass.h", + "source/opt/eliminate_dead_functions_util.cpp", + "source/opt/eliminate_dead_functions_util.h", + "source/opt/eliminate_dead_members_pass.cpp", + "source/opt/eliminate_dead_members_pass.h", "source/opt/feature_manager.cpp", "source/opt/feature_manager.h", + "source/opt/fix_storage_class.cpp", + "source/opt/fix_storage_class.h", "source/opt/flatten_decoration_pass.cpp", "source/opt/flatten_decoration_pass.h", "source/opt/fold.cpp", @@ -474,6 +574,10 @@ static_library("spvtools_opt") { "source/opt/freeze_spec_constant_value_pass.h", "source/opt/function.cpp", "source/opt/function.h", + "source/opt/generate_webgpu_initializers_pass.cpp", + "source/opt/generate_webgpu_initializers_pass.h", + "source/opt/graphics_robust_access_pass.cpp", + "source/opt/graphics_robust_access_pass.h", "source/opt/if_conversion.cpp", "source/opt/if_conversion.h", "source/opt/inline_exhaustive_pass.cpp", @@ -482,16 +586,24 @@ static_library("spvtools_opt") { "source/opt/inline_opaque_pass.h", "source/opt/inline_pass.cpp", "source/opt/inline_pass.h", + "source/opt/inst_bindless_check_pass.cpp", + "source/opt/inst_bindless_check_pass.h", + "source/opt/inst_buff_addr_check_pass.cpp", + "source/opt/inst_buff_addr_check_pass.h", "source/opt/instruction.cpp", "source/opt/instruction.h", "source/opt/instruction_list.cpp", "source/opt/instruction_list.h", + "source/opt/instrument_pass.cpp", + "source/opt/instrument_pass.h", "source/opt/ir_builder.h", "source/opt/ir_context.cpp", "source/opt/ir_context.h", "source/opt/ir_loader.cpp", "source/opt/ir_loader.h", "source/opt/iterator.h", + "source/opt/legalize_vector_shuffle_pass.cpp", + "source/opt/legalize_vector_shuffle_pass.h", "source/opt/licm_pass.cpp", "source/opt/licm_pass.h", "source/opt/local_access_chain_convert_pass.cpp", @@ -502,8 +614,6 @@ static_library("spvtools_opt") { "source/opt/local_single_block_elim_pass.h", "source/opt/local_single_store_elim_pass.cpp", "source/opt/local_single_store_elim_pass.h", - "source/opt/local_ssa_elim_pass.cpp", - "source/opt/local_ssa_elim_pass.h", "source/opt/log.h", "source/opt/loop_dependence.cpp", "source/opt/loop_dependence.h", @@ -539,6 +649,8 @@ static_library("spvtools_opt") { "source/opt/passes.h", "source/opt/private_to_local_pass.cpp", "source/opt/private_to_local_pass.h", + "source/opt/process_lines_pass.cpp", + "source/opt/process_lines_pass.h", "source/opt/propagator.cpp", "source/opt/propagator.h", "source/opt/reduce_load_size.cpp", @@ -548,6 +660,8 @@ static_library("spvtools_opt") { "source/opt/reflect.h", "source/opt/register_pressure.cpp", "source/opt/register_pressure.h", + "source/opt/relax_float_ops_pass.cpp", + "source/opt/relax_float_ops_pass.h", "source/opt/remove_duplicates_pass.cpp", "source/opt/remove_duplicates_pass.h", "source/opt/replace_invalid_opc.cpp", @@ -562,14 +676,20 @@ static_library("spvtools_opt") { "source/opt/set_spec_constant_default_value_pass.h", "source/opt/simplification_pass.cpp", "source/opt/simplification_pass.h", + "source/opt/split_invalid_unreachable_pass.cpp", + "source/opt/split_invalid_unreachable_pass.h", "source/opt/ssa_rewrite_pass.cpp", "source/opt/ssa_rewrite_pass.h", "source/opt/strength_reduction_pass.cpp", "source/opt/strength_reduction_pass.h", + "source/opt/strip_atomic_counter_memory_pass.cpp", + "source/opt/strip_atomic_counter_memory_pass.h", "source/opt/strip_debug_info_pass.cpp", "source/opt/strip_debug_info_pass.h", "source/opt/strip_reflect_info_pass.cpp", "source/opt/strip_reflect_info_pass.h", + "source/opt/struct_cfg_analysis.cpp", + "source/opt/struct_cfg_analysis.h", "source/opt/tree_iterator.h", "source/opt/type_manager.cpp", "source/opt/type_manager.h", @@ -577,161 +697,217 @@ static_library("spvtools_opt") { "source/opt/types.h", "source/opt/unify_const_pass.cpp", "source/opt/unify_const_pass.h", + "source/opt/upgrade_memory_model.cpp", + "source/opt/upgrade_memory_model.h", "source/opt/value_number_table.cpp", "source/opt/value_number_table.h", "source/opt/vector_dce.cpp", "source/opt/vector_dce.h", "source/opt/workaround1209.cpp", "source/opt/workaround1209.h", + "source/opt/wrap_opkill.cpp", + "source/opt/wrap_opkill.h", ] + deps = [ ":spvtools", + ":spvtools_language_header_cldebuginfo100", + ":spvtools_language_header_debuginfo", + ":spvtools_vendor_tables_spv-amd-shader-ballot", + ] + public_deps = [ + ":spvtools_headers", ] - public_configs = [ ":spvtools_config" ] - configs -= [ "//build/config/compiler:chromium_code" ] - configs += [ "//build/config/compiler:no_chromium_code" ] + if (build_with_chromium) { + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + } + configs += [ ":spvtools_internal_config" ] } -group("SPIRV-Tools") { +static_library("spvtools_link") { + sources = [ + "source/link/linker.cpp", + ] deps = [ ":spvtools", ":spvtools_opt", ":spvtools_val", ] -} - -if (!build_with_chromium) { - googletest_dir = spirv_tools_googletest_dir - - config("gtest_config") { - include_dirs = [ - "${googletest_dir}/googletest", - "${googletest_dir}/googletest/include", - ] - } - - static_library("gtest") { - testonly = true - sources = [ - "${googletest_dir}/googletest/src/gtest-all.cc", - ] - public_configs = [ ":gtest_config" ] - } - - config("gmock_config") { - include_dirs = [ - "${googletest_dir}/googlemock", - "${googletest_dir}/googlemock/include", - "${googletest_dir}/googletest/include", - ] - if (is_clang) { - # TODO: Can remove this if/when the issue is fixed. - # https://github.com/google/googletest/issues/533 - cflags = [ "-Wno-inconsistent-missing-override" ] - } - } - - static_library("gmock") { - testonly = true - sources = [ - "${googletest_dir}/googlemock/src/gmock-all.cc", - ] - public_configs = [ ":gmock_config" ] - } -} - -config("spvtools_test_config") { - if (is_clang) { - cflags = [ "-Wno-self-assign" ] - } -} - -test("spvtools_test") { - sources = [ - "test/assembly_context_test.cpp", - "test/assembly_format_test.cpp", - "test/binary_destroy_test.cpp", - "test/binary_endianness_test.cpp", - "test/binary_header_get_test.cpp", - "test/binary_parse_test.cpp", - "test/binary_strnlen_s_test.cpp", - "test/binary_to_text.literal_test.cpp", - "test/binary_to_text_test.cpp", - "test/comment_test.cpp", - "test/enum_set_test.cpp", - "test/enum_string_mapping_test.cpp", - "test/ext_inst.debuginfo_test.cpp", - "test/ext_inst.glsl_test.cpp", - "test/ext_inst.opencl_test.cpp", - "test/fix_word_test.cpp", - "test/generator_magic_number_test.cpp", - "test/hex_float_test.cpp", - "test/immediate_int_test.cpp", - "test/libspirv_macros_test.cpp", - "test/name_mapper_test.cpp", - "test/named_id_test.cpp", - "test/opcode_make_test.cpp", - "test/opcode_require_capabilities_test.cpp", - "test/opcode_split_test.cpp", - "test/opcode_table_get_test.cpp", - "test/operand_capabilities_test.cpp", - "test/operand_pattern_test.cpp", - "test/operand_test.cpp", - "test/target_env_test.cpp", - "test/test_fixture.h", - "test/text_advance_test.cpp", - "test/text_destroy_test.cpp", - "test/text_literal_test.cpp", - "test/text_start_new_inst_test.cpp", - "test/text_to_binary.annotation_test.cpp", - "test/text_to_binary.barrier_test.cpp", - "test/text_to_binary.constant_test.cpp", - "test/text_to_binary.control_flow_test.cpp", - "test/text_to_binary.debug_test.cpp", - "test/text_to_binary.device_side_enqueue_test.cpp", - "test/text_to_binary.extension_test.cpp", - "test/text_to_binary.function_test.cpp", - "test/text_to_binary.group_test.cpp", - "test/text_to_binary.image_test.cpp", - "test/text_to_binary.literal_test.cpp", - "test/text_to_binary.memory_test.cpp", - "test/text_to_binary.misc_test.cpp", - "test/text_to_binary.mode_setting_test.cpp", - "test/text_to_binary.pipe_storage_test.cpp", - "test/text_to_binary.reserved_sampling_test.cpp", - "test/text_to_binary.subgroup_dispatch_test.cpp", - "test/text_to_binary.type_declaration_test.cpp", - "test/text_to_binary_test.cpp", - "test/text_word_get_test.cpp", - "test/unit_spirv.cpp", - "test/unit_spirv.h", + public_deps = [ + ":spvtools_headers", ] + if (build_with_chromium) { + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + } + configs += [ ":spvtools_internal_config" ] +} +static_library("spvtools_reduce") { + sources = [ + "source/reduce/change_operand_reduction_opportunity.cpp", + "source/reduce/change_operand_reduction_opportunity.h", + "source/reduce/change_operand_to_undef_reduction_opportunity.cpp", + "source/reduce/change_operand_to_undef_reduction_opportunity.h", + "source/reduce/conditional_branch_to_simple_conditional_branch_opportunity_finder.cpp", + "source/reduce/conditional_branch_to_simple_conditional_branch_opportunity_finder.h", + "source/reduce/conditional_branch_to_simple_conditional_branch_reduction_opportunity.cpp", + "source/reduce/conditional_branch_to_simple_conditional_branch_reduction_opportunity.h", + "source/reduce/merge_blocks_reduction_opportunity.cpp", + "source/reduce/merge_blocks_reduction_opportunity.h", + "source/reduce/merge_blocks_reduction_opportunity_finder.cpp", + "source/reduce/merge_blocks_reduction_opportunity_finder.h", + "source/reduce/operand_to_const_reduction_opportunity_finder.cpp", + "source/reduce/operand_to_const_reduction_opportunity_finder.h", + "source/reduce/operand_to_dominating_id_reduction_opportunity_finder.cpp", + "source/reduce/operand_to_dominating_id_reduction_opportunity_finder.h", + "source/reduce/operand_to_undef_reduction_opportunity_finder.cpp", + "source/reduce/operand_to_undef_reduction_opportunity_finder.h", + "source/reduce/reducer.cpp", + "source/reduce/reducer.h", + "source/reduce/reduction_opportunity.cpp", + "source/reduce/reduction_opportunity.h", + "source/reduce/reduction_opportunity_finder.h", + "source/reduce/reduction_pass.cpp", + "source/reduce/reduction_pass.h", + "source/reduce/reduction_util.cpp", + "source/reduce/reduction_util.h", + "source/reduce/remove_block_reduction_opportunity.cpp", + "source/reduce/remove_block_reduction_opportunity.h", + "source/reduce/remove_block_reduction_opportunity_finder.cpp", + "source/reduce/remove_block_reduction_opportunity_finder.h", + "source/reduce/remove_function_reduction_opportunity.cpp", + "source/reduce/remove_function_reduction_opportunity.h", + "source/reduce/remove_function_reduction_opportunity_finder.cpp", + "source/reduce/remove_function_reduction_opportunity_finder.h", + "source/reduce/remove_instruction_reduction_opportunity.cpp", + "source/reduce/remove_instruction_reduction_opportunity.h", + "source/reduce/remove_selection_reduction_opportunity.cpp", + "source/reduce/remove_selection_reduction_opportunity.h", + "source/reduce/remove_selection_reduction_opportunity_finder.cpp", + "source/reduce/remove_selection_reduction_opportunity_finder.h", + "source/reduce/remove_unreferenced_instruction_reduction_opportunity_finder.cpp", + "source/reduce/remove_unreferenced_instruction_reduction_opportunity_finder.h", + "source/reduce/simple_conditional_branch_to_branch_opportunity_finder.cpp", + "source/reduce/simple_conditional_branch_to_branch_opportunity_finder.h", + "source/reduce/simple_conditional_branch_to_branch_reduction_opportunity.cpp", + "source/reduce/simple_conditional_branch_to_branch_reduction_opportunity.h", + "source/reduce/structured_loop_to_selection_reduction_opportunity.cpp", + "source/reduce/structured_loop_to_selection_reduction_opportunity.h", + "source/reduce/structured_loop_to_selection_reduction_opportunity_finder.cpp", + "source/reduce/structured_loop_to_selection_reduction_opportunity_finder.h", + "source/spirv_reducer_options.cpp", + "source/spirv_reducer_options.h", + ] deps = [ ":spvtools", - ":spvtools_language_header_unified1", + ":spvtools_opt", + ] + public_deps = [ + ":spvtools_headers", + ] + if (build_with_chromium) { + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ "//build/config/compiler:no_chromium_code" ] + } + configs += [ ":spvtools_internal_config" ] +} + +group("SPIRV-Tools") { + public_deps = [ + ":spvtools", + ":spvtools_link", + ":spvtools_opt", + ":spvtools_reduce", ":spvtools_val", ] +} - if (build_with_chromium) { - deps += [ +# The tests are scoped to Chromium to avoid needing to write gtest integration. +# See Chromium's third_party/googletest/BUILD.gn for a complete integration. +if (build_with_chromium) { + test("spvtools_test") { + sources = [ + "test/assembly_context_test.cpp", + "test/assembly_format_test.cpp", + "test/binary_destroy_test.cpp", + "test/binary_endianness_test.cpp", + "test/binary_header_get_test.cpp", + "test/binary_parse_test.cpp", + "test/binary_strnlen_s_test.cpp", + "test/binary_to_text.literal_test.cpp", + "test/binary_to_text_test.cpp", + "test/comment_test.cpp", + "test/enum_set_test.cpp", + "test/enum_string_mapping_test.cpp", + "test/ext_inst.debuginfo_test.cpp", + "test/ext_inst.glsl_test.cpp", + "test/ext_inst.opencl_test.cpp", + "test/ext_inst.cldebug100_test.cpp", + "test/fix_word_test.cpp", + "test/generator_magic_number_test.cpp", + "test/hex_float_test.cpp", + "test/immediate_int_test.cpp", + "test/libspirv_macros_test.cpp", + "test/name_mapper_test.cpp", + "test/named_id_test.cpp", + "test/opcode_make_test.cpp", + "test/opcode_require_capabilities_test.cpp", + "test/opcode_split_test.cpp", + "test/opcode_table_get_test.cpp", + "test/operand_capabilities_test.cpp", + "test/operand_pattern_test.cpp", + "test/operand_test.cpp", + "test/target_env_test.cpp", + "test/test_fixture.h", + "test/text_advance_test.cpp", + "test/text_destroy_test.cpp", + "test/text_literal_test.cpp", + "test/text_start_new_inst_test.cpp", + "test/text_to_binary.annotation_test.cpp", + "test/text_to_binary.barrier_test.cpp", + "test/text_to_binary.constant_test.cpp", + "test/text_to_binary.control_flow_test.cpp", + "test/text_to_binary.debug_test.cpp", + "test/text_to_binary.device_side_enqueue_test.cpp", + "test/text_to_binary.extension_test.cpp", + "test/text_to_binary.function_test.cpp", + "test/text_to_binary.group_test.cpp", + "test/text_to_binary.image_test.cpp", + "test/text_to_binary.literal_test.cpp", + "test/text_to_binary.memory_test.cpp", + "test/text_to_binary.misc_test.cpp", + "test/text_to_binary.mode_setting_test.cpp", + "test/text_to_binary.pipe_storage_test.cpp", + "test/text_to_binary.reserved_sampling_test.cpp", + "test/text_to_binary.subgroup_dispatch_test.cpp", + "test/text_to_binary.type_declaration_test.cpp", + "test/text_to_binary_test.cpp", + "test/text_word_get_test.cpp", + "test/unit_spirv.cpp", + "test/unit_spirv.h", + ] + + deps = [ + ":spvtools", + ":spvtools_language_header_debuginfo", + ":spvtools_language_header_cldebuginfo100", + ":spvtools_val", "//testing/gmock", "//testing/gtest", "//testing/gtest:gtest_main", + "//third_party/googletest:gmock", + "//third_party/googletest:gtest", ] - } else { - deps += [ - ":gmock", - ":gtest", - ] - sources += [ "${googletest_dir}/googletest/src/gtest_main.cc" ] - } - configs += [ - ":spvtools_config", - ":spvtools_test_config", - ] + if (is_clang) { + cflags_cc = [ "-Wno-self-assign" ] + } + + configs += [ ":spvtools_internal_config" ] + } } if (spirv_tools_standalone) { @@ -743,14 +919,132 @@ if (spirv_tools_standalone) { } } -executable("spirv-as") { +source_set("spvtools_util_cli_consumer") { + sources = [ + "tools/util/cli_consumer.cpp", + "tools/util/cli_consumer.h", + ] + deps = [ + ":spvtools_headers", + ] + configs += [ ":spvtools_internal_config" ] +} + +source_set("spvtools_software_version") { sources = [ "source/software_version.cpp", + ] + deps = [ + ":spvtools_build_version", + ":spvtools_headers", + ] + configs += [ ":spvtools_internal_config" ] +} + +executable("spirv-as") { + sources = [ "tools/as/as.cpp", ] deps = [ ":spvtools", - ":spvtools_build_version", + ":spvtools_software_version", ] - configs += [ ":spvtools_config" ] + configs += [ ":spvtools_internal_config" ] +} + +executable("spirv-dis") { + sources = [ + "tools/dis/dis.cpp", + ] + deps = [ + ":spvtools", + ":spvtools_software_version", + ] + configs += [ ":spvtools_internal_config" ] +} + +executable("spirv-val") { + sources = [ + "tools/val/val.cpp", + ] + deps = [ + ":spvtools", + ":spvtools_software_version", + ":spvtools_util_cli_consumer", + ":spvtools_val", + ] + configs += [ ":spvtools_internal_config" ] +} + +executable("spirv-cfg") { + sources = [ + "tools/cfg/bin_to_dot.cpp", + "tools/cfg/bin_to_dot.h", + "tools/cfg/cfg.cpp", + ] + deps = [ + ":spvtools", + ":spvtools_software_version", + ] + configs += [ ":spvtools_internal_config" ] +} + +executable("spirv-opt") { + sources = [ + "tools/opt/opt.cpp", + ] + deps = [ + ":spvtools", + ":spvtools_opt", + ":spvtools_software_version", + ":spvtools_util_cli_consumer", + ":spvtools_val", + ] + configs += [ ":spvtools_internal_config" ] +} + +executable("spirv-link") { + sources = [ + "tools/link/linker.cpp", + ] + deps = [ + ":spvtools", + ":spvtools_link", + ":spvtools_opt", + ":spvtools_software_version", + ":spvtools_val", + ] + configs += [ ":spvtools_internal_config" ] +} + +if (!is_ios) { + # iOS does not allow std::system calls which spirv-reduce requires + executable("spirv-reduce") { + sources = [ + "tools/reduce/reduce.cpp", + ] + deps = [ + ":spvtools", + ":spvtools_opt", + ":spvtools_reduce", + ":spvtools_software_version", + ":spvtools_util_cli_consumer", + ":spvtools_val", + ] + configs += [ ":spvtools_internal_config" ] + } +} + +group("all_spirv_tools") { + deps = [ + ":spirv-as", + ":spirv-cfg", + ":spirv-dis", + ":spirv-link", + ":spirv-opt", + ":spirv-val", + ] + if (!is_ios) { + deps += [ ":spirv-reduce" ] + } } diff --git a/third_party/spirv-tools/CHANGES b/third_party/spirv-tools/CHANGES index ef499027f7..4130e9652b 100644 --- a/third_party/spirv-tools/CHANGES +++ b/third_party/spirv-tools/CHANGES @@ -1,7 +1,386 @@ Revision history for SPIRV-Tools -v2018.5-dev 2018-07-08 +v2020.1 2020-02-03 - General: + - Add support for SPV_KHR_non_semantic_info (#3110) + - Support OpenCL.DebugInfo.100 extended instruction set (#3080) + - Added support for Vulkan 1.2 + - Add API function to better handle getting the necessary environment (#3142) + - Clarify mapping of target env to SPIR-V version (#3150) + - Implement constant folding for many transcendentals (#3166) + - Optimizer + - Change default version for CreatInstBindlessCheckPass to 2 (#3096, #3119) + - Better handling of OpLine on merge blocks (#3130) + - Use dummy switch instead of dummy loop in MergeReturn pass. (#3151) + - Handle TimeAMD in AmdExtensionToKhrPass. (#3168) + - Validator + - Fix structured exit validation (#3141) + - Reduce + - Fuzz + - Fuzzer pass to merge blocks (#3097) + - Transformation to add a new function to a module (#3114) + - Add fuzzer pass to perform module donation (#3117) + - Fuzzer passes to create and branch to new dead blocks (#3135) + - Fuzzer pass to add composite types (#3171) + - Linker: + - Remove names and decorations of imported symbols (#3081) + +v2019.5 2019-12-11 + - General: + - Export SPIRV-Tools targets on installation + - SPIRV-Tools support for SPIR-V 1.5 (#2865) + - Add WebGPU SPIR-V Assembler in JavaScript. (#2876) + - Add Bazel build configuration. (#2891) + - Add support for building with emscripten (#2948) + - Update SPIR-V binary header test for SPIR-V 1.5 (#2967) + - Add fuzzer for spirv-as call path (#2976) + - Improved CMake install step. (#2963) + - Add fuzzer for spirv-dis call path (#2977) + - Ensure timestamp does not vary with timezone. (#2982) + - Add a vscode extension for SPIR-V disassembly files (#2987) + - Add iOS as a supported platform (#3001) + - utils/vscode: Add SPIR-V language server support + - Respect CMAKE_INSTALL_LIBDIR in installed CMake files (#3054) + - Permit the debug instructions in WebGPU SPIR-V (#3063) + - Add support for Fuchsia. (#3062) + - Optimizer + - Add descriptor array scalar replacement (#2742) + - Add pass to wrap OpKill in a function call (#2790) + - Fold FMix during constant folding. (#2818) + - Add pass to replace AMD shader ballot extension (#2811) + - Add pass to make Float32 operation relax precision (#2808) + - Add pass to make relax precision operation Float16 (#2808) + - Add pass to replace uses of 3 AMD extensions (#2814) + - Fold Min, Max, and Clamp instructions. (#2836) + - Better handling of OpKill in continues (#2842,#2922,#2933) + - Enable OpTypeCooperativeMatrix specialization (#2927) + - Support constant-folding UConvert and SConvert (#2960) + - Update Offset to ConstOffset bitmask if operand is constant. (#3024) + - Improve RegisterSizePasses (#3059) + - Folding: perform add and sub on mismatched integer types (#3084) + - Graphics robust access: use signed clamp (#3073) + Fixes: + - Instrument: Fix version 2 output record write for tess eval shaders. (#2782) + - Instrument: Add support for Buffer Device Address extension (#2792) + - Fix check for changed binary in API call. (#2798) + - For WebGPU<->Vulkan optimization, set correct execution environment (#2834) + - Handle OpConstantNull in copy-prop-arrays. (#2870) + - Use OpReturn* in wrap-opkill (#2886) + - Validator + - Add generic builtin validation of target (#2843) + - Extra resource interface validation (#2864) + - Adding valilidation checks for OpEntryPoint duplicate names and execution mode (#2862) + - Relaxed bitcast with pointers (#2878) + - Validate physical storage buffer restrictions (#2930) + - Add SPV_KHR_shader_clock validation (#2879, #3013) + - Validate that selections are structured (#2962) + - Disallow use of OpCompositeExtract/OpCompositeInsert with no indices (#2980) + - Check that derivatives operate on 32-bit values (#2983) + - Validate array stride does not cause overlap (#3028) + - Validate nested constructs (#3068) + Fixes: + - Fix validation of constant matrices (#2794) + - Update "remquor" validation + - Only allow previously declared forward refs in structs (#2920) + - Reduce + - Remove relaxed precision decorations (#2797) + - Reduce/fuzz: improve command line args (#2932) + - Improve remove unref instr pass (#2945) + Fixes: + - Fuzz + - Fix add-dead-break and add-dead-continue passes to respect dominance (#2838) + - Add fuzzer pass to copy objects (#2853) + - Add fuzzer pass to replace ids with synonyms (#2857) + - Allow validation during spirv-fuzz replay (#2873) + - Employ the "swarm testing" idea in spirv-fuzz (#2890) + - reduce/fuzz: improve command line args (#2932) + - option to convert shader into a form that renders red (#2934) + - Add fuzzer pass to change selection controls (#2944) + - add transformation and pass to construct composites (#2941) + - Add fuzzer pass to change loop controls (#2949) + - Add fuzzer pass to change function controls (#2951) + - Add fuzzer pass to add NoContraction decorations (#2950) + - Add missing functionality for matrix composites (#2974) + - Fuzzer pass to adjust memory access operands (#2968) + - Transformation to extract from a composite object (#2991) + - Vector shuffle transformation (#3015) + - Improve debugging facilities (#3074) + - Function outlining fuzzer pass (#3078) + + +v2019.4 2019-08-08 + - General: + - Memory model support for SPIR-V 1.4 + - Add new spirv-fuzz tool + - Add option for base branch in check_code_format.sh + - Removed MarkV and Stats code. (#2576) + - Instrument: Add version 2 of record formats (#2630) + - Linker: Better type comparison for OpTypeArray and OpTypeForwardPointer (#2580) + - Optimizer + - Bindless Validation: Instrument descriptor-based loads and stores (#2583) + - Better folding for OpSpecConstantOp (#2585, #2614) + - Add in individual flags for Vulkan <-> WebGPU passes (#2615) + - Handle nested breaks from switches. (#2624) + - Optimizer: Handle array type with OpSpecConstantOp length (#2652) + - Perform merge return with single return in loop. (#2714) + - Add --preserve-bindings and --preserve-spec-constants (#2693) + - Remove Common Uniform Elimination Pass (#2731) + - Allow ray tracing shaders in inst bindle check pass. (#2733) + - Add pass to inject code for robust-buffer-access semantics (#2771) + - Treat access chain indexes as signed in SROA (#2776) + - Handle RelaxedPrecision in SROA (#2788) + - Add descriptor array scalar replacement (#2742) + Fixes: + - Handle decorations better in some optimizations (#2716) + - Change the order branches are simplified in dead branch elim (#2728) + - Fix bug in merge return (#2734) + - SSA rewriter: Don't use trivial phis (#2757) + - Record correct dominators in merge return (#2760) + - Process OpDecorateId in ADCE (#2761) + - Fix check for unreachable blocks in merge-return (#2762) + - Handle out-of-bounds scalar replacements. (#2767) + - Don't move debug or decorations when folding (#2772) + - Protect against out-of-bounds references when folding OpCompositeExtract (#2774) + - Validator + - Validate loop merge (#2579) + - Validate construct exits (#2459) + - Validate OpenCL memory and addressing model environment rules (#2589) + - Validate OpenCL environment rules for OpTypeImage (#2606) + - Allow breaks to switch merge from nested construct (#2604) + - Validate OpenCL environment rules for OpImageWrite (#2619) + - Allow arrays of out per-primitive builtins for mesh shaders (#2617) + - Validate OpenCL rules for ImageRead and OpImageSampleExplicitLod (#2643) + - Add validation for SPV_EXT_fragment_shader_interlock (#2650) + - Add builtin validation for SPV_NV_shader_sm_builtins (#2656) + - Add validation for Subgroup builtins (#2637) + - Validate variable initializer type (#2668) + - Disallow stores to UBOs (#2651)A + - Validate Volatile memory semantics bit (#2672) + - Basic validation for Component decorations (#2679) + - Validate that in OpenGL env block variables have Binding (#2685) + - Validate usage of 8- and 16-bit types with only storage capabilities (#2704) + - Add validation for SPV_EXT_demote_to_helper_invocation (#2707) + - Extra small storage validation (#2732) + - For Vulkan, disallow structures containing opaque types (#2546) + - Validate storage class OpenCL environment rules for atomics (#2750) + - Update OpControlBarriers rules for WebGPU (#2769) + - Update OpMemoryBarriers rules for WebGPU (#2775) + - Update WebGPU validation rules of OpAtomic*s (#2777) + Fixes: + - Disallow merge targeting block with OpLoopMerge (#2610) + - Update vloadn and vstoren validation to match the OpenCL Extended + Instruction Set Specification (#2599) + - Update memory scope rules for WebGPU (#2725) + - Allow LOD ops in compute shaders with derivative group execution modes (#2752) + - Reduce + Fixes: + +v2019.3 2019-05-14 + - General: + - Require Python 3 since Python 2 will out of service soon. + - Add a continuous test that does memory checks using the address sanitizer. + - Fix the build files so the SPIRV_USE_SANITIZER=address build works. + - Packaging top of tree build artifacts again. + - Added support for SPIR-V 1.4. (#2550) + - Optimizer + - Remove duplicates from list of interface IDs in OpEntryPoint instruction (#2449) + - Bindless Validation: Descriptor Initialization Check (#2419) + - Add option to validate after each pass (#2462) + - Add legalization pass to fix mismatched pointer (#2430, #2535) + - Add error messages when the input contains unknown instructions. (#2487) + - Add pass to convert from WebGPU Spir-V to Vulkan Spir-V and back. (#2495) + Fixes: + - #2412: Dead memeber elimination should not change input and output variables. + - #2405: Fix OpDot folding of half float vectors. + - #2391: Dead branch elim should not fold away back edges. + - #2441: Removing decorations when doing constant propagation. + - #2455: Maintain inst to block mapping in merge return. + - #2453: Fix merge return in the face of breaks. + - #2456: Handle dead infinite loops in DCE. + - #2458: Handle variable pointer in some optimizations. + - #2452: Fix dead branch elimination to handle unreachable blocks better. + - #2528: Fix undefined bit shift in sroa. + - #2539: Change implementation of post order CFG traversal. + - Validator + - Add validation of storage classes for WebGPU (#2446) + - Add validation for ExecutionMode in WebGPU (#2443) + - Implement WebGPU specific CFG validation (#2386) + - Allow NonWritable to target struct members. (#2420) + - Allow storage type mismatch for parameter in relaxed addressing mode. + - Allow non memory objects as parameter in relaxed addressing mode. + - Disallow nested Blocks and buffer blocks (#2410). + - Add validation for SPV_NV_cooperative_matrix (#2404) + - Add --strip-atomic-counter-memory (#2413) + - Check OpSampledImage is only passed into valid instructions (#2467) + - Handle function decls in Structured CFG analysis (#2474) + - Validate that OpUnreacahble is not statically reachable (#2473) + - Add pass to generate needed initializers for WebGPU (#2481) + - Allow images without format for OpenCL. (#2470) + - Remove unreachable block validation (#2525) + - Reduce runtime of array layout checks (#2534) + - Add validation specific to OpExecutionModeId (#2536) + - Validate sign of int types. (#2549) + - VK_KHR_uniform_buffer_standard_layout validation (#2562) + Fixes: + - #2439: Add missing DepthGreater case to Fragment only check. + - #2168: Disallow BufferBlock on StorageBuffer variables for Vulkan. + - #2408: Restrict and Aliased decorations cannot be applied to the same id. + - #2447: Improve function call parameter check. + - Reduce + - Add Pass to remove unreferenced blocks. (#2398) + - Allows passing options to the validator. (#2401) + - Improve reducer algorithm and other changes (#2472) + - Add Pass to remove selections (#2485) + - Add passes to simplify branches (#2507) + Fixes: + - #2478: fix loop to selection pass for loops with combined header/continue block + +v2019.2 2019-02-20 + - General: + - Support SPV_EXT_physical_storage_buffer + - A number of memory leak have been fixed. + - Removed use of deprecated Google test macro: + - Changed the BUILD.gn to only build tests in Chromium. + - Optimizer + - Upgrade memory model improvments for modf and frexp. + - Add a new pass to move loads closer to their uses: code sinking. + - Invalidating the type manager now invalidates the constnat manager. + - Expand instrumentation pass for bindless bounds checking to runtime-sized descriptor arrays. + - Add a new pass that removes members from structs that are not used: dead member elimination. + Fixes: + - #2292: Remove undefined behaviour when folding bit shifts. + - #2294: Fixes for instrumentation code. + - #2293: Fix overflow when folding -INT_MIN. + - #2374: Don't merge unreachable blocks when merging blocks. + - Validator + - Support SPV_KHR_no_integer_wrap and related decorations. + - Validate Vulkan rules for OpTypeRuntimeArray. + - Validate NonWritable decoration. + - Many WebGPU specific validation rules were added. + - Validate variable pointer related function call rules. + - Better error messages. + Fixes: + - #2307: Check forwards references in OpTypeArray. + - #2315, #2303: Fixed the layout check for relaxed layout. + - #1628: Emit an error when an OpSwitch target is not an OpLabel. + - Reduce + - Added more documentation for spirv-reduce. + - Add ability to remove OpPhi instructions. + - Add ability to merge two basic blocks. + - Add ability to remove unused functions and unused basic blocks. + Fixes: + +v2019.1 2019-01-07 + - General: + - Created a new tool called spirv-reduce. + - Add cmake option to turn off SPIRV_TIMER_ENABLED (#2103) + - New optimization pass to update the memory model from GLSL450 to VulkanKHR. + - Recognize OpTypeAccelerationStructureNV as a type instruction and ray tracing storage classes. + - Fix GCC8 build. + - Add --target-env flag to spirv-opt. + - Add --webgpu-mode flag to run optimizations for webgpu. + - The output disassembled line number stead of byte offset in validation errors. (#2091) + - Optimizer + - Added the instrumentation passes for bindless validation. + - Added passes to help preserve OpLine information (#2027) + - Add basic support for EXT_fragment_invocation_density (#2100) + - Fix invalid OpPhi generated by merge-return. (#2172) + - Constant and type manager have been turned into analysies. (#2251) + Fixes: + - #2018: Don't inline functions with a return in a structured CFG contstruct. + - #2047: Fix bug in folding when volatile stores are present. + - #2053: Fix check for when folding floating pointer values is allowed. + - #2130: Don't inline recursive functions. + - #2202: Handle multiple edges between two basic blocks in SSA-rewriter. + - #2205: Don't unswitch a latch condition during loop unswitch. + - #2245: Don't fold branch in loop unswitch. Run dead branch elimination to fold them. + - #2204: Fix eliminate common uniform to place OpPhi instructions correctly. + - #2247: Fix type mismatches caused by scalar replacement. + - #2248: Fix missing OpPhi after merge return. + - #2211: After merge return, fix invalid continue target. + - #2210: Fix loop invariant code motion to not place code between merge instruction and branch. + - #2258: Handle CompositeInsert with no indices in VDCE. + - #2261: Have replace load size handle extact with no index. + - Validator + - Changed the naming convention of outputing ids with names in diagnostic messages. + - Added validation rules for UniformConstant variables in Vulkan. + - #1949: Validate uniform variable type in Vulkan + - Ensure for OpVariable that result type and storage class operand agree (#2052) + - Validator: Support VK_EXT_scalar_block_layout + - Added Vulkan memory model semantics validation + - Added validation checkes spefic to WebGPU environment. + - Add support for VK_EXT_Transform_feedback capabilities (#2088) + - Add validation for OpArrayLength. (#2117) + - Ensure that function parameter's type is not void (#2118) + - Validate pointer variables (#2111) + - Add check for QueueFamilyKHMR memory scope (#2144) + - Validate PushConstants annotation and type (#2140) + - Allow Float16/Int8 for Vulkan 1.0 (#2153) + - Check binding annotations in resource variables (#2151, #2167) + - Validate OpForwardPointer (#2156) + - Validate operation for OpSpecConstantOp (#2260) + Fixes: + - #2049: Allow InstanceId for NV ray tracing + - Reduce + - Initial commit wit a few passes to reduce test cases. + - Validation is run after each reduction step. + Fixes: + + +v2018.6 2018-11-07 + - General: + - Added support for the Nvidia Turing and ray tracing extensions. + - Make C++11 the CXX standard in CMakeLists.txt. + - Enabled a parallel build for MSVC. + - Enable pre-compiled headers for MSVC. + - Added a code of conduct. + - EFFCEE and RE2 are now required when build the tests. + - Optimizer + - Unrolling loops marked for unrolling in the legalization passes. + - Improved the compile time of loop unrolling. + - Changee merge-return to create a dummy loop around the function. + - Small improvement to merge-blocks to allow it to merge more often. + - Enforce an upper bound for the ids, and add option to set it. + - #1966: Report error if there are unreachable block before running merge return + Fixes: + - #1917: Allow 0 (meaning unlimited) as a parameter to --scalar-replacement + - #1915: Improve handling of group decorations. + - #1942: Fix incorrect uses of the constant manager. Avoids type mismatches in generated code. + - #1997: Fix dead branch elimination when there is a loop in folded selection. + - #1991: Fixes legality check in if-conversion. + - #1987: Add nullptr check to array copy propagation. + - #1984: Better handling of OpUnreachable in ADCE. + - #1983: Run merge return on reachable functions only. + - #1956: Handled atomic operations in ADCE. + - #1963: Fold integer divisions by 0 to 0. + - #2019: Handle MemberDecorateStringGOOGLE in ADCE and strip reflect. + - Validator + - Added validation for OpGroupNonUniformBallotBitCount. + - Added validation for the Vulkan memory model. + - Added support for VK_KHR_shader_atddomic_int64. + - Added validation for execution modes. + - Added validation for runtime array layouts. + - Added validation for 8-bit storage. + - Added validation of OpPhi instructions with pointer result type. + - Added checks for the Vulkan memory model. + - Validate MakeTexelAvailableKHR and MakeTexelVisibleKHR + - Allow atomic function pointer for OpenCL. + - FPRounding mode checks were implemented. + - Added validation for the id bound with an option to set the max id bound. + Fixes: + - #1882: Improve the validation of decorations to reduce memory usage. + - #1891: Fix an potential infinite loop in dead-branch-elimination. + - #1405: Validate the storage class of boolean objects. + - #1880: Identify arrays of type void as invalid. + - #487: Validate OpImageTexelPointer. + - #1922: Validate OpPhi instructions are at the start of a block correctly. + - #1923: Validate function scope variable are at the start of the entry block. + +v2018.5 2018-09-07 + - General: + - Support SPV_KHR_vulkan_memory_model + - Update Dim capabilities, to match SPIR-V 1.3 Rev 4 + - Automated build bots no run tests for the VS2013 case - Support Chromium GN build - Use Kokoro bots: - Disable Travis-CI bots @@ -11,26 +390,48 @@ v2018.5-dev 2018-07-08 - Fixes for ClangTidy, and whitespace (passes 'git cl presumit --all -uf') - Fix unused param compile warnings/errors when Effcee not present - Avoid including time headers when timer functionality is disabled + - Avoid too-stringent warnings flags for Clang on Windows + - Internal refactoring + - Add hooks for automated fuzzing + - Add testing of command line executables - #1688: Use binary mode on stdin; fixes "spirv-dis ![Linux Build Status](https://storage.googleapis.com/spirv-tools/badges/build_status_linux_release.svg) -MacOS![MacOS Build Status](https://storage.googleapis.com/spirv-tools/badges/build_status_macos_release.svg) -Windows![Windows Build Status](https://storage.googleapis.com/spirv-tools/badges/build_status_windows_release.svg) - ## Overview The SPIR-V Tools project provides an API and commands for processing SPIR-V @@ -24,12 +19,21 @@ SPIR-V is defined by the Khronos Group Inc. See the [SPIR-V Registry][spirv-registry] for the SPIR-V specification, headers, and XML registry. +## Downloads + +[![Build status](https://ci.appveyor.com/api/projects/status/gpue87cesrx3pi0d/branch/master?svg=true)](https://ci.appveyor.com/project/Khronoswebmaster/spirv-tools/branch/master) +Linux[![Linux Build Status](https://storage.googleapis.com/spirv-tools/badges/build_status_linux_clang_release.svg)](https://storage.googleapis.com/spirv-tools/badges/build_link_linux_clang_release.html) +MacOS[![MacOS Build Status](https://storage.googleapis.com/spirv-tools/badges/build_status_macos_clang_release.svg)](https://storage.googleapis.com/spirv-tools/badges/build_link_macos_clang_release.html) +Windows[![Windows Build Status](https://storage.googleapis.com/spirv-tools/badges/build_status_windows_release.svg)](https://storage.googleapis.com/spirv-tools/badges/build_link_windows_vs2017_release.html) + +[More downloads](docs/downloads.md) + ## Versioning SPIRV-Tools See [`CHANGES`](CHANGES) for a high level summary of recent changes, by version. SPIRV-Tools project version numbers are of the form `v`*year*`.`*index* and with -an optional `-dev` suffix to indicate work in progress. For exampe, the +an optional `-dev` suffix to indicate work in progress. For example, the following versions are ordered from oldest to newest: * `v2016.0` @@ -45,9 +49,11 @@ version. An API call reports the software version as a C-style string. ### Assembler, binary parser, and disassembler -* Support for SPIR-V 1.0, 1.1, 1.2, and 1.3 +* Support for SPIR-V 1.0, through 1.5 * Based on SPIR-V syntax described by JSON grammar files in the - [SPIRV-Headers](spirv-headers) repository. + [SPIRV-Headers](https://github.com/KhronosGroup/SPIRV-Headers) repository. + * Usually, support for a new version of SPIR-V is ready within days after + publication. * Support for extended instruction sets: * GLSL std450 version 1.0 Rev 3 * OpenCL version 1.0 Rev 2 @@ -55,7 +61,7 @@ version. An API call reports the software version as a C-style string. IDs or types is performed, except to check literal arguments to `OpConstant`, `OpSpecConstant`, and `OpSwitch`. -See [`syntax.md`](syntax.md) for the assembly language syntax. +See [`docs/syntax.md`](docs/syntax.md) for the assembly language syntax. ### Validator @@ -84,14 +90,22 @@ limits accepted by a more than minimally capable SPIR-V consumer. ### Optimizer -*Note:* The optimizer is still under development. +The optimizer is a collection of code transforms, or "passes". +Transforms are written for a diverse set of reasons: -Currently supported optimizations: -* General +* To restructure, simplify, or normalize the code for further processing. +* To eliminate undesirable code. +* To improve code quality in some metric such as size or performance. + **Note**: These transforms are not guaranteed to actually improve any + given metric. Users should always measure results for their own situation. + +As of this writing, there are 67 transforms including examples such as: +* Simplification * Strip debug info + * Strip reflection info * Specialization Constants * Set spec constant default value - * Freeze spec constant + * Freeze spec constant to default value * Fold `OpSpecConstantOp` and `OpSpecConstantComposite` * Unify constants * Eliminate dead constant @@ -108,6 +122,29 @@ Currently supported optimizations: * Eliminate common uniform loads * Remove duplicates: Capabilities, extended instruction imports, types, and decorations. +* Normalization + * Compact IDs + * CFG cleanup + * Flatten decorations + * Merge returns + * Convert AMD-specific instructions to KHR instructions +* Code improvement + * Conditional constant propagation + * If-conversion + * Loop fission + * Loop fusion + * Loop-invariant code motion + * Loop unroll +* Other + * Generate WebGPU initializers + * Graphics robust access + * Upgrade memory model to VulkanKHR + +Additionally, certain sets of transformations have been packaged into +higher-level recipes. These include: + +* Optimization for size (`spirv-opt -Os`) +* Optimization for performance (`spirv-opt -O`) For the latest list with detailed documentation, please refer to [`include/spirv-tools/optimizer.hpp`](include/spirv-tools/optimizer.hpp). @@ -128,6 +165,41 @@ See the [CHANGES](CHANGES) file for reports on completed work, and the [General sub-project](https://github.com/KhronosGroup/SPIRV-Tools/projects/2) for planned and in-progress work. + +### Reducer + +*Note:* The reducer is still under development. + +The reducer simplifies and shrinks a SPIR-V module with respect to a +user-supplied *interestingness function*. For example, given a large +SPIR-V module that cause some SPIR-V compiler to fail with a given +fatal error message, the reducer could be used to look for a smaller +version of the module that causes the compiler to fail with the same +fatal error message. + +To suggest an additional capability for the reducer, [file an +issue](https://github.com/KhronosGroup/SPIRV-Tools/issues]) with +"Reducer:" as the start of its title. + + +### Fuzzer + +*Note:* The fuzzer is still under development. + +The fuzzer applies semantics-preserving transformations to a SPIR-V binary +module, to produce an equivalent module. The original and transformed modules +should produce essentially identical results when executed on identical inputs: +their results should differ only due to floating-point round-off, if at all. +Significant differences in results can pinpoint bugs in tools that process +SPIR-V binaries, such as miscompilations. This *metamorphic testing* approach +is similar to the method used by the [GraphicsFuzz +project](https://github.com/google/graphicsfuzz) for fuzzing of GLSL shaders. + +To suggest an additional capability for the fuzzer, [file an +issue](https://github.com/KhronosGroup/SPIRV-Tools/issues]) with +"Fuzzer:" as the start of its title. + + ### Extras * [Utility filters](#utility-filters) @@ -150,7 +222,7 @@ specific work is tracked via issues and sometimes in one of the (To provide feedback on the SPIR-V _specification_, file an issue on the [SPIRV-Headers][spirv-headers] GitHub repository.) -See [`projects.md`](projects.md) to see how we use the +See [`docs/projects.md`](docs/projects.md) to see how we use the [GitHub Project feature](https://help.github.com/articles/tracking-the-progress-of-your-work-with-projects/) to organize planned and in-progress work. @@ -163,7 +235,10 @@ Contributions via merge request are welcome. Changes should: other contribution to GitHub. * Include tests to cover updated functionality. * C++ code should follow the [Google C++ Style Guide][cpp-style-guide]. -* Code should be formatted with `clang-format`. Settings are defined by +* Code should be formatted with `clang-format`. + [kokoro/check-format/build.sh](kokoro/check-format/build.sh) + shows how to download it. Note that we currently use + `clang-format version 5.0.0` for SPIRV-Tools. Settings are defined by the included [.clang-format](.clang-format) file. We intend to maintain a linear history on the GitHub `master` branch. @@ -175,7 +250,7 @@ We intend to maintain a linear history on the GitHub `master` branch. [googletest][googletest] sources, not provided * `external/effcee`: Location of [Effcee][effcee] sources, if the `effcee` library is not already configured by an enclosing project. -* `external/re2`: Location of [RE2][re2] sources, if the `effcee` library is not already +* `external/re2`: Location of [RE2][re2] sources, if the `re2` library is not already configured by an enclosing project. (The Effcee project already requires RE2.) * `include/`: API clients should add this directory to the include search path @@ -212,7 +287,7 @@ tests: The fix is included on the googletest master branch any time after 2015-11-10. In particular, googletest must be newer than version 1.7.0. -### Optional dependency on Effcee +### Dependency on Effcee Some tests depend on the [Effcee][effcee] library for stateful matching. Effcee itself depends on [RE2][re2]. @@ -222,7 +297,6 @@ Effcee itself depends on [RE2][re2]. * Otherwise, SPIRV-Tools expects Effcee sources to appear in `external/effcee` and RE2 sources to appear in `external/re2`. -Currently Effcee is an optional dependency, but soon it will be required. ## Build @@ -232,15 +306,29 @@ Those binaries are automatically uploaded by the buildbots after successful testing and they always reflect the current top of the tree of the master branch. -The project uses [CMake][cmake] to generate platform-specific build -configurations. Assume that `` is the root directory of the checked -out code: +In order to build the code, you first need to sync the external repositories +that it depends on. Assume that `` is the root directory of the +checked out code: ```sh cd git clone https://github.com/KhronosGroup/SPIRV-Headers.git external/spirv-headers +git clone https://github.com/google/effcee.git external/effcee +git clone https://github.com/google/re2.git external/re2 git clone https://github.com/google/googletest.git external/googletest # optional +``` + +*Note*: +The script `utils/git-sync-deps` can be used to checkout and/or update the +contents of the repos under `external/` instead of manually maintaining them. + +### Build using CMake +You can build The project using [CMake][cmake] to generate platform-specific +build configurations. + +```sh +cd mkdir build && cd build cmake [-G ] ``` @@ -248,17 +336,51 @@ cmake [-G ] Once the build files have been generated, build using your preferred development environment. +### Build using Bazel +You can also use [Bazel](https://bazel.build/) to build the project. +```sh +cd +bazel build :all +``` + +### Tools you'll need + +For building and testing SPIRV-Tools, the following tools should be +installed regardless of your OS: + +- [CMake](http://www.cmake.org/): if using CMake for generating compilation +targets, you need to install CMake Version 2.8.12 or later. +- [Python 3](http://www.python.org/): for utility scripts and running the test +suite. +- [Bazel](https://bazel.build/) (optional): if building the source with Bazel, +you need to install Bazel Version 0.29.1 on your machine. Other versions may +also work, but are not verified. + +SPIRV-Tools is regularly tested with the following compilers: + +On Linux +- GCC version 4.8.5 +- Clang version 3.8 + +On MacOS +- AppleClang 10.0 + +On Windows +- Visual Studio 2015 +- Visual Studio 2017 + +Other compilers or later versions may work, but they are not tested. + ### CMake options The following CMake options are supported: +* `SPIRV_BUILD_FUZZER={ON|OFF}`, default `OFF` - Build the spirv-fuzz tool. * `SPIRV_COLOR_TERMINAL={ON|OFF}`, default `ON` - Enables color console output. * `SPIRV_SKIP_TESTS={ON|OFF}`, default `OFF`- Build only the library and the command line tools. This will prevent the tests from being built. * `SPIRV_SKIP_EXECUTABLES={ON|OFF}`, default `OFF`- Build only the library, not the command line tools and tests. -* `SPIRV_BUILD_COMPRESSION={ON|OFF}`, default `OFF`- Build SPIR-V compressing - codec. * `SPIRV_USE_SANITIZER=`, default is no sanitizing - On UNIX platforms with an appropriate version of `clang` this option enables the use of the sanitizers documented [here][clang-sanitizers]. @@ -269,7 +391,7 @@ The following CMake options are supported: See [`CMakeLists.txt`](CMakeLists.txt) for details. * `SPIRV_WERROR={ON|OFF}`, default `ON` - Forces a compilation error on any warnings encountered by enabling the compiler-specific compiler front-end - option. + option. No compiler front-end options are enabled when this option is OFF. Additionally, you can pass additional C preprocessor definitions to SPIRV-Tools via setting `SPIRV_TOOLS_EXTRA_DEFINITIONS`. For example, by setting it to @@ -296,6 +418,13 @@ $ANDROID_NDK/ndk-build -C ../android_test \ NDK_APP_OUT=`pwd`/app ``` +### Updating DEPS +Occasionally the entries in DEPS will need to be updated. This is done on demand +when there is a request to do this, often due to downstream breakages. There is +a script `utils/roll_deps.sh` provided, which will generate a patch with the +updated DEPS values. This will still need to be tested in your checkout to +confirm that there are no integration issues that need to be resolved. + ## Library ### Usage @@ -411,6 +540,31 @@ The validator operates on the binary form. * `spirv-val` - the standalone validator * `/tools/val` +### Reducer tool + +The reducer shrinks a SPIR-V binary module, guided by a user-supplied +*interestingness test*. + +This is a work in progress, with initially only shrinks a module in a few ways. + +* `spirv-reduce` - the standalone reducer + * `/tools/reduce` + +Run `spirv-reduce --help` to see how to specify interestingness. + +### Fuzzer tool + +The fuzzer transforms a SPIR-V binary module into a semantically-equivalent +SPIR-V binary module by applying transformations in a randomized fashion. + +This is a work in progress, with initially only a few semantics-preserving +transformations. + +* `spirv-fuzz` - the standalone fuzzer + * `/tools/fuzz` + +Run `spirv-fuzz --help` for a detailed list of options. + ### Control flow dumper tool The control flow dumper prints the control flow graph for a SPIR-V module as a diff --git a/third_party/spirv-tools/WORKSPACE b/third_party/spirv-tools/WORKSPACE new file mode 100644 index 0000000000..5abfc98bcc --- /dev/null +++ b/third_party/spirv-tools/WORKSPACE @@ -0,0 +1,19 @@ +local_repository( + name = "spirv_headers", + path = "external/spirv-headers", +) + +local_repository( + name = "com_google_googletest", + path = "external/googletest", +) + +local_repository( + name = "com_googlesource_code_re2", + path = "external/re2", +) + +local_repository( + name = "com_google_effcee", + path = "external/effcee", +) diff --git a/third_party/spirv-tools/build_defs.bzl b/third_party/spirv-tools/build_defs.bzl new file mode 100644 index 0000000000..5d913a14c8 --- /dev/null +++ b/third_party/spirv-tools/build_defs.bzl @@ -0,0 +1,291 @@ +COMMON_COPTS = [ + "-DSPIRV_CHECK_CONTEXT", + "-DSPIRV_COLOR_TERMINAL", + ] + select({ + "@bazel_tools//src/conditions:windows": [""], + "//conditions:default": [ + "-DSPIRV_LINUX", + "-DSPIRV_TIMER_ENABLED", + "-Wall", + "-Wextra", + "-Wnon-virtual-dtor", + "-Wno-missing-field-initializers", + "-Werror", + "-std=c++11", + "-fvisibility=hidden", + "-fno-exceptions", + "-fno-rtti", + "-Wno-long-long", + "-Wshadow", + "-Wundef", + "-Wconversion", + "-Wno-sign-conversion", + ], +}) + +TEST_COPTS = COMMON_COPTS + select({ + "@bazel_tools//src/conditions:windows": [ + # Disable C4503 "decorated name length exceeded" warning, + # triggered by some heavily templated types. + # We don't care much about that in test code. + # Important to do since we have warnings-as-errors. + "/wd4503" + ], + "//conditions:default": [ + "-Wno-undef", + "-Wno-self-assign", + "-Wno-shadow", + "-Wno-unused-parameter" + ], +}) + +DEBUGINFO_GRAMMAR_JSON_FILE = "source/extinst.debuginfo.grammar.json" +CLDEBUGINFO100_GRAMMAR_JSON_FILE = "source/extinst.opencl.debuginfo.100.grammar.json" + +def generate_core_tables(version = None): + if not version: + fail("Must specify version", "version") + grammars = [ + "@spirv_headers//:spirv_core_grammar_" + version, + DEBUGINFO_GRAMMAR_JSON_FILE, + CLDEBUGINFO100_GRAMMAR_JSON_FILE, + ] + outs = [ + "core.insts-{}.inc".format(version), + "operand.kinds-{}.inc".format(version), + ] + fmtargs = grammars + outs + native.genrule( + name = "gen_core_tables_" + version, + srcs = grammars, + outs = outs, + cmd = ( + "$(location :generate_grammar_tables) " + + "--spirv-core-grammar=$(location {0}) " + + "--extinst-debuginfo-grammar=$(location {1}) " + + "--extinst-cldebuginfo100-grammar=$(location {2}) " + + "--core-insts-output=$(location {3}) " + + "--operand-kinds-output=$(location {4})" + ).format(*fmtargs), + tools = [":generate_grammar_tables"], + visibility = ["//visibility:private"], + ) + +def generate_enum_string_mapping(version = None): + if not version: + fail("Must specify version", "version") + grammars = [ + "@spirv_headers//:spirv_core_grammar_" + version, + DEBUGINFO_GRAMMAR_JSON_FILE, + CLDEBUGINFO100_GRAMMAR_JSON_FILE, + ] + outs = [ + "extension_enum.inc", + "enum_string_mapping.inc", + ] + fmtargs = grammars + outs + native.genrule( + name = "gen_enum_string_mapping", + srcs = grammars, + outs = outs, + cmd = ( + "$(location :generate_grammar_tables) " + + "--spirv-core-grammar=$(location {0}) " + + "--extinst-debuginfo-grammar=$(location {1}) " + + "--extinst-cldebuginfo100-grammar=$(location {2}) " + + "--extension-enum-output=$(location {3}) " + + "--enum-string-mapping-output=$(location {4})" + ).format(*fmtargs), + tools = [":generate_grammar_tables"], + visibility = ["//visibility:private"], + ) + +def generate_opencl_tables(version = None): + if not version: + fail("Must specify version", "version") + grammars = [ + "@spirv_headers//:spirv_opencl_grammar_" + version, + ] + outs = ["opencl.std.insts.inc"] + fmtargs = grammars + outs + native.genrule( + name = "gen_opencl_tables_" + version, + srcs = grammars, + outs = outs, + cmd = ( + "$(location :generate_grammar_tables) " + + "--extinst-opencl-grammar=$(location {0}) " + + "--opencl-insts-output=$(location {1})" + ).format(*fmtargs), + tools = [":generate_grammar_tables"], + visibility = ["//visibility:private"], + ) + +def generate_glsl_tables(version = None): + if not version: + fail("Must specify version", "version") + grammars = [ + "@spirv_headers//:spirv_glsl_grammar_" + version, + ] + outs = ["glsl.std.450.insts.inc"] + fmtargs = grammars + outs + native.genrule( + name = "gen_glsl_tables_" + version, + srcs = grammars, + outs = outs, + cmd = ( + "$(location :generate_grammar_tables) " + + "--extinst-glsl-grammar=$(location {0}) " + + "--glsl-insts-output=$(location {1})" + ).format(*fmtargs), + tools = [":generate_grammar_tables"], + visibility = ["//visibility:private"], + ) + +def generate_vendor_tables(extension, operand_kind_prefix = ""): + if not extension: + fail("Must specify extension", "extension") + extension_rule = extension.replace("-", "_").replace(".", "_") + grammars = ["source/extinst.{}.grammar.json".format(extension)] + outs = ["{}.insts.inc".format(extension)] + prefices = [operand_kind_prefix] + fmtargs = grammars + outs + prefices + native.genrule( + name = "gen_vendor_tables_" + extension_rule, + srcs = grammars, + outs = outs, + cmd = ( + "$(location :generate_grammar_tables) " + + "--extinst-vendor-grammar=$(location {0}) " + + "--vendor-insts-output=$(location {1}) " + + "--vendor-operand-kind-prefix={2}" + ).format(*fmtargs), + tools = [":generate_grammar_tables"], + visibility = ["//visibility:private"], + ) + +def generate_extinst_lang_headers(name, grammar = None): + if not grammar: + fail("Must specify grammar", "grammar") + fmtargs = [name] + native.genrule( + name = "gen_extinst_lang_headers_" + name, + srcs = [grammar], + outs = [name + ".h"], + cmd = ( + "$(location :generate_language_headers) " + + "--extinst-name={0} " + + "--extinst-grammar=$< " + + "--extinst-output-base=$(@D)/{0}" + ).format(*fmtargs), + tools = [":generate_language_headers"], + visibility = ["//visibility:private"], + ) + +def base_test(name, srcs, deps = []): + if srcs == []: + return + if name[-5:] != "_test": + name = name + "_test" + native.cc_test( + name = "base_" + name, + srcs = srcs, + compatible_with = [], + copts = TEST_COPTS, + size = "large", + deps = [ + ":test_common", + "@com_google_googletest//:gtest_main", + "@com_google_googletest//:gtest", + "@com_google_effcee//:effcee", + ] + deps, + ) + +def link_test(name, srcs, deps = []): + if name[-5:] != "_test": + name = name + "_test" + native.cc_test( + name = "link_" + name, + srcs = srcs, + compatible_with = [], + copts = TEST_COPTS, + size = "large", + deps = [ + ":link_test_common", + "@com_google_googletest//:gtest_main", + "@com_google_googletest//:gtest", + "@com_google_effcee//:effcee", + ] + deps, + ) + +def opt_test(name, srcs, deps = []): + if name[-5:] != "_test": + name = name + "_test" + native.cc_test( + name = "opt_" + name, + srcs = srcs, + compatible_with = [], + copts = TEST_COPTS, + size = "large", + deps = [ + ":opt_test_common", + "@com_google_googletest//:gtest_main", + "@com_google_googletest//:gtest", + "@com_google_effcee//:effcee", + ] + deps, + ) + +def reduce_test(name, srcs, deps = []): + if name[-5:] != "_test": + name = name + "_test" + native.cc_test( + name = "reduce_" + name, + srcs = srcs, + compatible_with = [], + copts = TEST_COPTS, + size = "large", + deps = [ + ":reduce_test_common", + ":spirv_tools_reduce", + "@com_google_googletest//:gtest_main", + "@com_google_googletest//:gtest", + "@com_google_effcee//:effcee", + ] + deps, + ) + +def util_test(name, srcs, deps = []): + if name[-5:] != "_test": + name = name + "_test" + native.cc_test( + name = "util_" + name, + srcs = srcs, + compatible_with = [], + copts = TEST_COPTS, + size = "large", + deps = [ + ":opt_test_common", + "@com_google_googletest//:gtest_main", + "@com_google_googletest//:gtest", + "@com_google_effcee//:effcee", + ] + deps, + ) + +def val_test(name, srcs = [], copts = [], deps = [], **kwargs): + if name[-5:] != "_test": + name = name + "_test" + if name[:4] != "val_": + name = "val_" + name + native.cc_test( + name = name, + srcs = srcs, + compatible_with = [], + copts = TEST_COPTS + copts, + size = "large", + deps = [ + ":val_test_common", + "@com_google_googletest//:gtest_main", + "@com_google_googletest//:gtest", + "@com_google_effcee//:effcee", + ] + deps, + **kwargs + ) diff --git a/third_party/spirv-tools/cmake/setup_build.cmake b/third_party/spirv-tools/cmake/setup_build.cmake deleted file mode 100644 index 6ba4c53d73..0000000000 --- a/third_party/spirv-tools/cmake/setup_build.cmake +++ /dev/null @@ -1,20 +0,0 @@ -# Find nosetests; see spirv_add_nosetests() for opting in to nosetests in a -# specific directory. -find_program(NOSETESTS_EXE NAMES nosetests PATHS $ENV{PYTHON_PACKAGE_PATH}) -if (NOT NOSETESTS_EXE) - message(STATUS "SPIRV-Tools: nosetests was not found - python support code will not be tested") -else() - message(STATUS "SPIRV-Tools: nosetests found - python support code will be tested") -endif() - -# Run nosetests on file ${PREFIX}_nosetest.py. Nosetests will look for classes -# and functions whose names start with "nosetest". The test name will be -# ${PREFIX}_nosetests. -function(spirv_add_nosetests PREFIX) - if(NOT "${SPIRV_SKIP_TESTS}" AND NOSETESTS_EXE) - add_test( - NAME ${PREFIX}_nosetests - COMMAND ${NOSETESTS_EXE} -m "^[Nn]ose[Tt]est" -v - ${CMAKE_CURRENT_SOURCE_DIR}/${PREFIX}_nosetest.py) - endif() -endfunction() diff --git a/third_party/spirv-tools/docs/downloads.md b/third_party/spirv-tools/docs/downloads.md new file mode 100644 index 0000000000..9c7d85671d --- /dev/null +++ b/third_party/spirv-tools/docs/downloads.md @@ -0,0 +1,14 @@ +# Downloads +Download the latest builds. + +## Release +| Windows | Linux | MacOS | +| --- | --- | --- | +| [MSVC 2017](https://storage.googleapis.com/spirv-tools/badges/build_link_windows_vs2017_release.html) | [clang](https://storage.googleapis.com/spirv-tools/badges/build_link_linux_clang_release.html) | [clang](https://storage.googleapis.com/spirv-tools/badges/build_link_macos_clang_release.html) | +| | [gcc](https://storage.googleapis.com/spirv-tools/badges/build_link_linux_gcc_release.html) | | + +## Debug +| Windows | Linux | MacOS | +| --- | --- | --- | +| [MSVC 2017](https://storage.googleapis.com/spirv-tools/badges/build_link_windows_vs2017_debug.html) | [clang](https://storage.googleapis.com/spirv-tools/badges/build_link_linux_clang_debug.html) | [clang](https://storage.googleapis.com/spirv-tools/badges/build_link_macos_clang_debug.html) | +| | [gcc](https://storage.googleapis.com/spirv-tools/badges/build_link_linux_gcc_debug.html) | | diff --git a/third_party/spirv-tools/projects.md b/third_party/spirv-tools/docs/projects.md similarity index 100% rename from third_party/spirv-tools/projects.md rename to third_party/spirv-tools/docs/projects.md diff --git a/third_party/spirv-tools/syntax.md b/third_party/spirv-tools/docs/syntax.md similarity index 100% rename from third_party/spirv-tools/syntax.md rename to third_party/spirv-tools/docs/syntax.md diff --git a/third_party/spirv-tools/examples/cpp-interface/main.cpp b/third_party/spirv-tools/examples/cpp-interface/main.cpp index c5354b8bdb..a1e22c7365 100644 --- a/third_party/spirv-tools/examples/cpp-interface/main.cpp +++ b/third_party/spirv-tools/examples/cpp-interface/main.cpp @@ -28,6 +28,7 @@ int main() { const std::string source = + " OpCapability Linkage " " OpCapability Shader " " OpMemoryModel Logical GLSL450 " " OpSource GLSL 450 " @@ -36,8 +37,8 @@ int main() { " %spec = OpSpecConstant %int 0 " "%const = OpConstant %int 42"; - spvtools::SpirvTools core(SPV_ENV_VULKAN_1_0); - spvtools::Optimizer opt(SPV_ENV_VULKAN_1_0); + spvtools::SpirvTools core(SPV_ENV_UNIVERSAL_1_3); + spvtools::Optimizer opt(SPV_ENV_UNIVERSAL_1_3); auto print_msg_to_stderr = [](spv_message_level_t, const char*, const spv_position_t&, const char* m) { diff --git a/third_party/spirv-tools/external/CMakeLists.txt b/third_party/spirv-tools/external/CMakeLists.txt index da0b2e6497..8bde13ca15 100644 --- a/third_party/spirv-tools/external/CMakeLists.txt +++ b/third_party/spirv-tools/external/CMakeLists.txt @@ -66,57 +66,54 @@ if (NOT ${SPIRV_SKIP_TESTS}) endforeach() endif() - set(SPIRV_ENABLE_EFFCEE ON) - if (MSVC) - if (MSVC_VERSION LESS 1900) - message(STATUS "SPIRV-Tools: Need Visual Studio 2015 or later for Effcee and RE2") - set(SPIRV_ENABLE_EFFCEE OFF) - endif() - endif() + # Find Effcee and RE2, for testing. - if (SPIRV_ENABLE_EFFCEE) - # Find Effcee and RE2, for testing. - # Optional for now, but eventually we'll make this required. - - # First find RE2, since Effcee depends on it. - # If already configured, then use that. Otherwise, prefer to find it under 're2' - # in this directory. - if (NOT TARGET re2) - # If we are configuring RE2, then turn off its testing. It takes a long time and - # does not add much value for us. If an enclosing project configured RE2, then it - # has already chosen whether to enable RE2 tesitng. - set(RE2_BUILD_TESTING OFF CACHE STRING "Run RE2 Tests") - if (NOT RE2_SOURCE_DIR) - if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/re2) - set(RE2_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/re2" CACHE STRING "RE2 source dir" ) - endif() + # First find RE2, since Effcee depends on it. + # If already configured, then use that. Otherwise, prefer to find it under 're2' + # in this directory. + if (NOT TARGET re2) + # If we are configuring RE2, then turn off its testing. It takes a long time and + # does not add much value for us. If an enclosing project configured RE2, then it + # has already chosen whether to enable RE2 testing. + set(RE2_BUILD_TESTING OFF CACHE STRING "Run RE2 Tests") + if (NOT RE2_SOURCE_DIR) + if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/re2) + set(RE2_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/re2" CACHE STRING "RE2 source dir" ) endif() endif() + endif() - if (NOT TARGET effcee) - # Expect to find effcee in this directory. - if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/effcee) - # If we're configuring RE2 (via Effcee), then turn off RE2 testing. - if (NOT TARGET re2) - set(RE2_BUILD_TESTING OFF) - endif() - if (MSVC) - # SPIRV-Tools uses the shared CRT with MSVC. Tell Effcee to do the same. - set(EFFCEE_ENABLE_SHARED_CRT ON) - endif() - add_subdirectory(effcee) - set_property(TARGET effcee PROPERTY FOLDER Effcee) - # Turn off warnings for effcee and re2 - set_property(TARGET effcee APPEND PROPERTY COMPILE_OPTIONS -w) - set_property(TARGET re2 APPEND PROPERTY COMPILE_OPTIONS -w) + if (NOT TARGET effcee) + # Expect to find effcee in this directory. + if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/effcee) + # If we're configuring RE2 (via Effcee), then turn off RE2 testing. + if (NOT TARGET re2) + set(RE2_BUILD_TESTING OFF) endif() + if (MSVC) + # SPIRV-Tools uses the shared CRT with MSVC. Tell Effcee to do the same. + set(EFFCEE_ENABLE_SHARED_CRT ON) + endif() + add_subdirectory(effcee) + set_property(TARGET effcee PROPERTY FOLDER Effcee) + # Turn off warnings for effcee and re2 + set_property(TARGET effcee APPEND PROPERTY COMPILE_OPTIONS -w) + set_property(TARGET re2 APPEND PROPERTY COMPILE_OPTIONS -w) endif() - # TODO(dneto): Eventually, require this. endif() - if (TARGET effcee) - message(STATUS "SPIRV-Tools: Effcee is configured") - else() - message(STATUS "SPIRV-Tools: Effcee is not configured. Skipping Effcee-based tests.") - endif() - endif() + +if(SPIRV_BUILD_FUZZER) + set(PROTOBUF_DIR ${CMAKE_CURRENT_SOURCE_DIR}/protobuf/cmake) + set(protobuf_BUILD_TESTS OFF CACHE BOOL "Disable protobuf tests") + set(protobuf_MSVC_STATIC_RUNTIME OFF CACHE BOOL "Do not build protobuf static runtime") + if (IS_DIRECTORY ${PROTOBUF_DIR}) + if (${CMAKE_CXX_COMPILER_ID} MATCHES Clang) + add_definitions(-Wno-inconsistent-missing-override) + endif() + add_subdirectory(${PROTOBUF_DIR} EXCLUDE_FROM_ALL) + else() + message(FATAL_ERROR + "protobuf not found - please checkout a copy under external/.") + endif() +endif(SPIRV_BUILD_FUZZER) diff --git a/third_party/spirv-tools/external/spirv-headers/.gitignore b/third_party/spirv-tools/external/spirv-headers/.gitignore index 9bcdd5aba5..f33592c908 100644 --- a/third_party/spirv-tools/external/spirv-headers/.gitignore +++ b/third_party/spirv-tools/external/spirv-headers/.gitignore @@ -1,2 +1,3 @@ build out +.DS_Store diff --git a/third_party/spirv-tools/external/spirv-headers/CMakeLists.txt b/third_party/spirv-tools/external/spirv-headers/CMakeLists.txt index 2488baf0ad..c6f4c4cbed 100644 --- a/third_party/spirv-tools/external/spirv-headers/CMakeLists.txt +++ b/third_party/spirv-tools/external/spirv-headers/CMakeLists.txt @@ -28,8 +28,8 @@ # The SPIR-V headers from the SPIR-V Registry # https://www.khronos.org/registry/spir-v/ # -cmake_minimum_required(VERSION 2.8.11) -project(SPIRV-Headers) +cmake_minimum_required(VERSION 3.0) +project(SPIRV-Headers VERSION 1.4.1) # There are two ways to use this project. # @@ -44,17 +44,84 @@ project(SPIRV-Headers) # 2. cmake .. # 3. cmake --build . --target install -file(GLOB_RECURSE HEADER_FILES - RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} - include/spirv/*) -foreach(HEADER_FILE ${HEADER_FILES}) - get_filename_component(HEADER_INSTALL_DIR ${HEADER_FILE} PATH) - install(FILES ${HEADER_FILE} DESTINATION ${HEADER_INSTALL_DIR}) -endforeach() - # legacy add_custom_target(install-headers COMMAND cmake -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/include/spirv $ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/include/spirv) -add_subdirectory(example) +option(SPIRV_HEADERS_SKIP_EXAMPLES "Skip building examples" + ${SPIRV_HEADERS_SKIP_EXAMPLES}) + +option(SPIRV_HEADERS_SKIP_INSTALL "Skip install" + ${SPIRV_HEADERS_SKIP_INSTALL}) + +if(NOT ${SPIRV_HEADERS_SKIP_EXAMPLES}) + set(SPIRV_HEADERS_ENABLE_EXAMPLES ON) +endif() + +if(NOT ${SPIRV_HEADERS_SKIP_INSTALL}) + set(SPIRV_HEADERS_ENABLE_INSTALL ON) +endif() + +if (SPIRV_HEADERS_ENABLE_EXAMPLES) + message(STATUS "Building SPIRV-Header examples") + add_subdirectory(example) +endif() + +include(GNUInstallDirs) +add_library(${PROJECT_NAME} INTERFACE) +target_include_directories(${PROJECT_NAME} INTERFACE + $ +) + +# Installation + +if (SPIRV_HEADERS_ENABLE_INSTALL) + message(STATUS "Installing SPIRV-Header") + + set(config_install_dir "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}") + + set(generated_dir "${CMAKE_CURRENT_BINARY_DIR}/generated") + + set(version_config "${generated_dir}/${PROJECT_NAME}ConfigVersion.cmake") + set(project_config "${generated_dir}/${PROJECT_NAME}Config.cmake") + set(TARGETS_EXPORT_NAME "${PROJECT_NAME}Targets") + set(namespace "${PROJECT_NAME}::") + + include(CMakePackageConfigHelpers) + write_basic_package_version_file( + "${version_config}" + COMPATIBILITY SameMajorVersion + ) + + configure_package_config_file( + "cmake/Config.cmake.in" + "${project_config}" + INSTALL_DESTINATION "${config_install_dir}" + ) + + install( + TARGETS ${PROJECT_NAME} + EXPORT "${TARGETS_EXPORT_NAME}" + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + ) + + install( + DIRECTORY include/spirv + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + ) + + install( + FILES "${project_config}" "${version_config}" + DESTINATION "${config_install_dir}" + ) + + install( + EXPORT "${TARGETS_EXPORT_NAME}" + NAMESPACE "${namespace}" + DESTINATION "${config_install_dir}" + ) +endif() diff --git a/third_party/spirv-tools/external/spirv-headers/README.md b/third_party/spirv-tools/external/spirv-headers/README.md index 846b20d802..53c476f359 100644 --- a/third_party/spirv-tools/external/spirv-headers/README.md +++ b/third_party/spirv-tools/external/spirv-headers/README.md @@ -25,10 +25,18 @@ the files under [include](include). The SPIR-V XML registry file is updated by Khronos whenever a new enum range is allocated. -Pull requests can be made to +Pull requests can be made to - request allocation of new enum ranges in the XML registry file - reserve specific tokens in the JSON grammar +### Reserving tokens in the JSON grammar + +Care should be taken to follow existing precedent in populating the details of reserved tokens. This includes: +- pointing to what extension has more information, when possible +- keeping enumerants in numeric order +- when there are aliases, listing the preferred spelling first +- adding the statement `"version" : "None"` + ## How to install the headers ``` @@ -45,6 +53,7 @@ If you want to install them somewhere else, then use ## Using the headers without installing +### Using CMake A CMake-based project can use the headers without installing, as follows: 1. Add an `add_subdirectory` directive to include this source tree. @@ -61,6 +70,55 @@ A CMake-based project can use the headers without installing, as follows: See also the [example](example/) subdirectory. But since that example is *inside* this repostory, it doesn't use and `add_subdirectory` directive. +### Using Bazel +A Bazel-based project can use the headers without installing, as follows: + +1. Add SPIRV-Headers as a submodule of your project, and add a +`local_repository` to your `WORKSPACE` file. For example, if you place +SPIRV-Headers under `external/spirv-headers`, then add the following to your +`WORKSPACE` file: + +``` +local_repository( + name = "spirv_headers", + path = "external/spirv-headers", +) +``` + +2. Add one of the following to the `deps` attribute of your build target based +on your needs: +``` +@spirv_headers//:spirv_c_headers +@spirv_headers//:spirv_cpp_headers +@spirv_headers//:spirv_cpp11_headers +``` + +For example: + +``` +cc_library( + name = "project", + srcs = [ + # Path to project sources + ], + hdrs = [ + # Path to project headers + ], + deps = [ + "@spirv_tools//:spirv_c_headers", + # Other dependencies, + ], +) +``` + +3. In your C or C++ source code use `#include` directives that explicitly mention + the `spirv` path component. +``` +#include "spirv/unified1/GLSL.std.450.h" +#include "spirv/unified1/OpenCL.std.h" +#include "spirv/unified1/spirv.hpp" +``` + ## Generating the headers from the JSON grammar This will generally be done by Khronos, for a change to the JSON grammar. diff --git a/third_party/spirv-tools/external/spirv-headers/include/spirv/1.2/spirv.py b/third_party/spirv-tools/external/spirv-headers/include/spirv/1.2/spirv.py old mode 100755 new mode 100644 diff --git a/third_party/spirv-tools/external/spirv-headers/include/spirv/spir-v.xml b/third_party/spirv-tools/external/spirv-headers/include/spirv/spir-v.xml index b05bfa7c49..2fac9c5ff2 100644 --- a/third_party/spirv-tools/external/spirv-headers/include/spirv/spir-v.xml +++ b/third_party/spirv-tools/external/spirv-headers/include/spirv/spir-v.xml @@ -52,7 +52,7 @@ - + @@ -69,7 +69,10 @@ - + + + + @@ -98,7 +101,7 @@ - + @@ -106,6 +109,9 @@ + + + - + + + + + + + + + + + diff --git a/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/OpenCL.std.h b/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/OpenCL.std.h index fe759e1bcb..2745e30df3 100644 --- a/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/OpenCL.std.h +++ b/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/OpenCL.std.h @@ -1,5 +1,5 @@ /* -** Copyright (c) 2015-2017 The Khronos Group Inc. +** Copyright (c) 2015-2019 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"), @@ -27,6 +27,7 @@ #ifndef OPENCLstd_H #define OPENCLstd_H +#ifdef __cplusplus namespace OpenCLLIB { enum Entrypoints { @@ -212,4 +213,189 @@ enum Entrypoints { } // end namespace OpenCLLIB +#else + +enum OpenCLstd_Entrypoints { + + // Section 2.1: Math extended instructions + OpenCLstd_Acos = 0, + OpenCLstd_Acosh = 1, + OpenCLstd_Acospi = 2, + OpenCLstd_Asin = 3, + OpenCLstd_Asinh = 4, + OpenCLstd_Asinpi = 5, + OpenCLstd_Atan = 6, + OpenCLstd_Atan2 = 7, + OpenCLstd_Atanh = 8, + OpenCLstd_Atanpi = 9, + OpenCLstd_Atan2pi = 10, + OpenCLstd_Cbrt = 11, + OpenCLstd_Ceil = 12, + OpenCLstd_Copysign = 13, + OpenCLstd_Cos = 14, + OpenCLstd_Cosh = 15, + OpenCLstd_Cospi = 16, + OpenCLstd_Erfc = 17, + OpenCLstd_Erf = 18, + OpenCLstd_Exp = 19, + OpenCLstd_Exp2 = 20, + OpenCLstd_Exp10 = 21, + OpenCLstd_Expm1 = 22, + OpenCLstd_Fabs = 23, + OpenCLstd_Fdim = 24, + OpenCLstd_Floor = 25, + OpenCLstd_Fma = 26, + OpenCLstd_Fmax = 27, + OpenCLstd_Fmin = 28, + OpenCLstd_Fmod = 29, + OpenCLstd_Fract = 30, + OpenCLstd_Frexp = 31, + OpenCLstd_Hypot = 32, + OpenCLstd_Ilogb = 33, + OpenCLstd_Ldexp = 34, + OpenCLstd_Lgamma = 35, + OpenCLstd_Lgamma_r = 36, + OpenCLstd_Log = 37, + OpenCLstd_Log2 = 38, + OpenCLstd_Log10 = 39, + OpenCLstd_Log1p = 40, + OpenCLstd_Logb = 41, + OpenCLstd_Mad = 42, + OpenCLstd_Maxmag = 43, + OpenCLstd_Minmag = 44, + OpenCLstd_Modf = 45, + OpenCLstd_Nan = 46, + OpenCLstd_Nextafter = 47, + OpenCLstd_Pow = 48, + OpenCLstd_Pown = 49, + OpenCLstd_Powr = 50, + OpenCLstd_Remainder = 51, + OpenCLstd_Remquo = 52, + OpenCLstd_Rint = 53, + OpenCLstd_Rootn = 54, + OpenCLstd_Round = 55, + OpenCLstd_Rsqrt = 56, + OpenCLstd_Sin = 57, + OpenCLstd_Sincos = 58, + OpenCLstd_Sinh = 59, + OpenCLstd_Sinpi = 60, + OpenCLstd_Sqrt = 61, + OpenCLstd_Tan = 62, + OpenCLstd_Tanh = 63, + OpenCLstd_Tanpi = 64, + OpenCLstd_Tgamma = 65, + OpenCLstd_Trunc = 66, + OpenCLstd_Half_cos = 67, + OpenCLstd_Half_divide = 68, + OpenCLstd_Half_exp = 69, + OpenCLstd_Half_exp2 = 70, + OpenCLstd_Half_exp10 = 71, + OpenCLstd_Half_log = 72, + OpenCLstd_Half_log2 = 73, + OpenCLstd_Half_log10 = 74, + OpenCLstd_Half_powr = 75, + OpenCLstd_Half_recip = 76, + OpenCLstd_Half_rsqrt = 77, + OpenCLstd_Half_sin = 78, + OpenCLstd_Half_sqrt = 79, + OpenCLstd_Half_tan = 80, + OpenCLstd_Native_cos = 81, + OpenCLstd_Native_divide = 82, + OpenCLstd_Native_exp = 83, + OpenCLstd_Native_exp2 = 84, + OpenCLstd_Native_exp10 = 85, + OpenCLstd_Native_log = 86, + OpenCLstd_Native_log2 = 87, + OpenCLstd_Native_log10 = 88, + OpenCLstd_Native_powr = 89, + OpenCLstd_Native_recip = 90, + OpenCLstd_Native_rsqrt = 91, + OpenCLstd_Native_sin = 92, + OpenCLstd_Native_sqrt = 93, + OpenCLstd_Native_tan = 94, + + // Section 2.2: Integer instructions + OpenCLstd_SAbs = 141, + OpenCLstd_SAbs_diff = 142, + OpenCLstd_SAdd_sat = 143, + OpenCLstd_UAdd_sat = 144, + OpenCLstd_SHadd = 145, + OpenCLstd_UHadd = 146, + OpenCLstd_SRhadd = 147, + OpenCLstd_URhadd = 148, + OpenCLstd_SClamp = 149, + OpenCLstd_UClamp = 150, + OpenCLstd_Clz = 151, + OpenCLstd_Ctz = 152, + OpenCLstd_SMad_hi = 153, + OpenCLstd_UMad_sat = 154, + OpenCLstd_SMad_sat = 155, + OpenCLstd_SMax = 156, + OpenCLstd_UMax = 157, + OpenCLstd_SMin = 158, + OpenCLstd_UMin = 159, + OpenCLstd_SMul_hi = 160, + OpenCLstd_Rotate = 161, + OpenCLstd_SSub_sat = 162, + OpenCLstd_USub_sat = 163, + OpenCLstd_U_Upsample = 164, + OpenCLstd_S_Upsample = 165, + OpenCLstd_Popcount = 166, + OpenCLstd_SMad24 = 167, + OpenCLstd_UMad24 = 168, + OpenCLstd_SMul24 = 169, + OpenCLstd_UMul24 = 170, + OpenCLstd_UAbs = 201, + OpenCLstd_UAbs_diff = 202, + OpenCLstd_UMul_hi = 203, + OpenCLstd_UMad_hi = 204, + + // Section 2.3: Common instructions + OpenCLstd_FClamp = 95, + OpenCLstd_Degrees = 96, + OpenCLstd_FMax_common = 97, + OpenCLstd_FMin_common = 98, + OpenCLstd_Mix = 99, + OpenCLstd_Radians = 100, + OpenCLstd_Step = 101, + OpenCLstd_Smoothstep = 102, + OpenCLstd_Sign = 103, + + // Section 2.4: Geometric instructions + OpenCLstd_Cross = 104, + OpenCLstd_Distance = 105, + OpenCLstd_Length = 106, + OpenCLstd_Normalize = 107, + OpenCLstd_Fast_distance = 108, + OpenCLstd_Fast_length = 109, + OpenCLstd_Fast_normalize = 110, + + // Section 2.5: Relational instructions + OpenCLstd_Bitselect = 186, + OpenCLstd_Select = 187, + + // Section 2.6: Vector Data Load and Store instructions + OpenCLstd_Vloadn = 171, + OpenCLstd_Vstoren = 172, + OpenCLstd_Vload_half = 173, + OpenCLstd_Vload_halfn = 174, + OpenCLstd_Vstore_half = 175, + OpenCLstd_Vstore_half_r = 176, + OpenCLstd_Vstore_halfn = 177, + OpenCLstd_Vstore_halfn_r = 178, + OpenCLstd_Vloada_halfn = 179, + OpenCLstd_Vstorea_halfn = 180, + OpenCLstd_Vstorea_halfn_r = 181, + + // Section 2.7: Miscellaneous Vector instructions + OpenCLstd_Shuffle = 182, + OpenCLstd_Shuffle2 = 183, + + // Section 2.8: Misc instructions + OpenCLstd_Printf = 184, + OpenCLstd_Prefetch = 185, +}; + +#endif + #endif // #ifndef OPENCLstd_H diff --git a/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/spirv.core.grammar.json b/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/spirv.core.grammar.json old mode 100755 new mode 100644 index cb641420d0..45bac526d2 --- a/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/spirv.core.grammar.json +++ b/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/spirv.core.grammar.json @@ -26,15 +26,122 @@ ], "magic_number" : "0x07230203", "major_version" : 1, - "minor_version" : 3, + "minor_version" : 5, "revision" : 1, + "instruction_printing_class" : [ + { + "tag" : "@exclude" + }, + { + "tag" : "Miscellaneous", + "heading" : "Miscellaneous Instructions" + }, + { + "tag" : "Debug", + "heading" : "Debug Instructions" + }, + { + "tag" : "Annotation", + "heading" : "Annotation Instructions" + }, + { + "tag" : "Extension", + "heading" : "Extension Instructions" + }, + { + "tag" : "Mode-Setting", + "heading" : "Mode-Setting Instructions" + }, + { + "tag" : "Type-Declaration", + "heading" : "Type-Declaration Instructions" + }, + { + "tag" : "Constant-Creation", + "heading" : "Constant-Creation Instructions" + }, + { + "tag" : "Memory", + "heading" : "Memory Instructions" + }, + { + "tag" : "Function", + "heading" : "Function Instructions" + }, + { + "tag" : "Image", + "heading" : "Image Instructions" + }, + { + "tag" : "Conversion", + "heading" : "Conversion Instructions" + }, + { + "tag" : "Composite", + "heading" : "Composite Instructions" + }, + { + "tag" : "Arithmetic", + "heading" : "Arithmetic Instructions" + }, + { + "tag" : "Bit", + "heading" : "Bit Instructions" + }, + { + "tag" : "Relational_and_Logical", + "heading" : "Relational and Logical Instructions" + }, + { + "tag" : "Derivative", + "heading" : "Derivative Instructions" + }, + { + "tag" : "Control-Flow", + "heading" : "Control-Flow Instructions" + }, + { + "tag" : "Atomic", + "heading" : "Atomic Instructions" + }, + { + "tag" : "Primitive", + "heading" : "Primitive Instructions" + }, + { + "tag" : "Barrier", + "heading" : "Barrier Instructions" + }, + { + "tag" : "Group", + "heading" : "Group and Subgroup Instructions" + }, + { + "tag" : "Device-Side_Enqueue", + "heading" : "Device-Side Enqueue Instructions" + }, + { + "tag" : "Pipe", + "heading" : "Pipe Instructions" + }, + { + "tag" : "Non-Uniform", + "heading" : "Non-Uniform Instructions" + }, + { + "tag" : "Reserved", + "heading" : "Reserved Instructions" + } + ], "instructions" : [ { "opname" : "OpNop", + "class" : "Miscellaneous", "opcode" : 0 }, { "opname" : "OpUndef", + "class" : "Miscellaneous", "opcode" : 1, "operands" : [ { "kind" : "IdResultType" }, @@ -43,6 +150,7 @@ }, { "opname" : "OpSourceContinued", + "class" : "Debug", "opcode" : 2, "operands" : [ { "kind" : "LiteralString", "name" : "'Continued Source'" } @@ -50,6 +158,7 @@ }, { "opname" : "OpSource", + "class" : "Debug", "opcode" : 3, "operands" : [ { "kind" : "SourceLanguage" }, @@ -60,6 +169,7 @@ }, { "opname" : "OpSourceExtension", + "class" : "Debug", "opcode" : 4, "operands" : [ { "kind" : "LiteralString", "name" : "'Extension'" } @@ -67,6 +177,7 @@ }, { "opname" : "OpName", + "class" : "Debug", "opcode" : 5, "operands" : [ { "kind" : "IdRef", "name" : "'Target'" }, @@ -75,6 +186,7 @@ }, { "opname" : "OpMemberName", + "class" : "Debug", "opcode" : 6, "operands" : [ { "kind" : "IdRef", "name" : "'Type'" }, @@ -84,6 +196,7 @@ }, { "opname" : "OpString", + "class" : "Debug", "opcode" : 7, "operands" : [ { "kind" : "IdResult" }, @@ -92,6 +205,7 @@ }, { "opname" : "OpLine", + "class" : "Debug", "opcode" : 8, "operands" : [ { "kind" : "IdRef", "name" : "'File'" }, @@ -101,6 +215,7 @@ }, { "opname" : "OpExtension", + "class" : "Extension", "opcode" : 10, "operands" : [ { "kind" : "LiteralString", "name" : "'Name'" } @@ -108,6 +223,7 @@ }, { "opname" : "OpExtInstImport", + "class" : "Extension", "opcode" : 11, "operands" : [ { "kind" : "IdResult" }, @@ -116,6 +232,7 @@ }, { "opname" : "OpExtInst", + "class" : "Extension", "opcode" : 12, "operands" : [ { "kind" : "IdResultType" }, @@ -127,6 +244,7 @@ }, { "opname" : "OpMemoryModel", + "class" : "Mode-Setting", "opcode" : 14, "operands" : [ { "kind" : "AddressingModel" }, @@ -135,6 +253,7 @@ }, { "opname" : "OpEntryPoint", + "class" : "Mode-Setting", "opcode" : 15, "operands" : [ { "kind" : "ExecutionModel" }, @@ -145,6 +264,7 @@ }, { "opname" : "OpExecutionMode", + "class" : "Mode-Setting", "opcode" : 16, "operands" : [ { "kind" : "IdRef", "name" : "'Entry Point'" }, @@ -153,6 +273,7 @@ }, { "opname" : "OpCapability", + "class" : "Mode-Setting", "opcode" : 17, "operands" : [ { "kind" : "Capability", "name" : "'Capability'" } @@ -160,6 +281,7 @@ }, { "opname" : "OpTypeVoid", + "class" : "Type-Declaration", "opcode" : 19, "operands" : [ { "kind" : "IdResult" } @@ -167,6 +289,7 @@ }, { "opname" : "OpTypeBool", + "class" : "Type-Declaration", "opcode" : 20, "operands" : [ { "kind" : "IdResult" } @@ -174,6 +297,7 @@ }, { "opname" : "OpTypeInt", + "class" : "Type-Declaration", "opcode" : 21, "operands" : [ { "kind" : "IdResult" }, @@ -183,6 +307,7 @@ }, { "opname" : "OpTypeFloat", + "class" : "Type-Declaration", "opcode" : 22, "operands" : [ { "kind" : "IdResult" }, @@ -191,6 +316,7 @@ }, { "opname" : "OpTypeVector", + "class" : "Type-Declaration", "opcode" : 23, "operands" : [ { "kind" : "IdResult" }, @@ -200,6 +326,7 @@ }, { "opname" : "OpTypeMatrix", + "class" : "Type-Declaration", "opcode" : 24, "operands" : [ { "kind" : "IdResult" }, @@ -210,6 +337,7 @@ }, { "opname" : "OpTypeImage", + "class" : "Type-Declaration", "opcode" : 25, "operands" : [ { "kind" : "IdResult" }, @@ -225,6 +353,7 @@ }, { "opname" : "OpTypeSampler", + "class" : "Type-Declaration", "opcode" : 26, "operands" : [ { "kind" : "IdResult" } @@ -232,6 +361,7 @@ }, { "opname" : "OpTypeSampledImage", + "class" : "Type-Declaration", "opcode" : 27, "operands" : [ { "kind" : "IdResult" }, @@ -240,6 +370,7 @@ }, { "opname" : "OpTypeArray", + "class" : "Type-Declaration", "opcode" : 28, "operands" : [ { "kind" : "IdResult" }, @@ -249,6 +380,7 @@ }, { "opname" : "OpTypeRuntimeArray", + "class" : "Type-Declaration", "opcode" : 29, "operands" : [ { "kind" : "IdResult" }, @@ -258,6 +390,7 @@ }, { "opname" : "OpTypeStruct", + "class" : "Type-Declaration", "opcode" : 30, "operands" : [ { "kind" : "IdResult" }, @@ -266,6 +399,7 @@ }, { "opname" : "OpTypeOpaque", + "class" : "Type-Declaration", "opcode" : 31, "operands" : [ { "kind" : "IdResult" }, @@ -275,6 +409,7 @@ }, { "opname" : "OpTypePointer", + "class" : "Type-Declaration", "opcode" : 32, "operands" : [ { "kind" : "IdResult" }, @@ -284,6 +419,7 @@ }, { "opname" : "OpTypeFunction", + "class" : "Type-Declaration", "opcode" : 33, "operands" : [ { "kind" : "IdResult" }, @@ -293,6 +429,7 @@ }, { "opname" : "OpTypeEvent", + "class" : "Type-Declaration", "opcode" : 34, "operands" : [ { "kind" : "IdResult" } @@ -301,6 +438,7 @@ }, { "opname" : "OpTypeDeviceEvent", + "class" : "Type-Declaration", "opcode" : 35, "operands" : [ { "kind" : "IdResult" } @@ -309,6 +447,7 @@ }, { "opname" : "OpTypeReserveId", + "class" : "Type-Declaration", "opcode" : 36, "operands" : [ { "kind" : "IdResult" } @@ -317,6 +456,7 @@ }, { "opname" : "OpTypeQueue", + "class" : "Type-Declaration", "opcode" : 37, "operands" : [ { "kind" : "IdResult" } @@ -325,6 +465,7 @@ }, { "opname" : "OpTypePipe", + "class" : "Type-Declaration", "opcode" : 38, "operands" : [ { "kind" : "IdResult" }, @@ -334,15 +475,20 @@ }, { "opname" : "OpTypeForwardPointer", + "class" : "Type-Declaration", "opcode" : 39, "operands" : [ { "kind" : "IdRef", "name" : "'Pointer Type'" }, { "kind" : "StorageClass" } ], - "capabilities" : [ "Addresses" ] + "capabilities" : [ + "Addresses", + "PhysicalStorageBufferAddresses" + ] }, { "opname" : "OpConstantTrue", + "class" : "Constant-Creation", "opcode" : 41, "operands" : [ { "kind" : "IdResultType" }, @@ -351,6 +497,7 @@ }, { "opname" : "OpConstantFalse", + "class" : "Constant-Creation", "opcode" : 42, "operands" : [ { "kind" : "IdResultType" }, @@ -359,6 +506,7 @@ }, { "opname" : "OpConstant", + "class" : "Constant-Creation", "opcode" : 43, "operands" : [ { "kind" : "IdResultType" }, @@ -368,6 +516,7 @@ }, { "opname" : "OpConstantComposite", + "class" : "Constant-Creation", "opcode" : 44, "operands" : [ { "kind" : "IdResultType" }, @@ -377,6 +526,7 @@ }, { "opname" : "OpConstantSampler", + "class" : "Constant-Creation", "opcode" : 45, "operands" : [ { "kind" : "IdResultType" }, @@ -389,6 +539,7 @@ }, { "opname" : "OpConstantNull", + "class" : "Constant-Creation", "opcode" : 46, "operands" : [ { "kind" : "IdResultType" }, @@ -397,6 +548,7 @@ }, { "opname" : "OpSpecConstantTrue", + "class" : "Constant-Creation", "opcode" : 48, "operands" : [ { "kind" : "IdResultType" }, @@ -405,6 +557,7 @@ }, { "opname" : "OpSpecConstantFalse", + "class" : "Constant-Creation", "opcode" : 49, "operands" : [ { "kind" : "IdResultType" }, @@ -413,6 +566,7 @@ }, { "opname" : "OpSpecConstant", + "class" : "Constant-Creation", "opcode" : 50, "operands" : [ { "kind" : "IdResultType" }, @@ -422,6 +576,7 @@ }, { "opname" : "OpSpecConstantComposite", + "class" : "Constant-Creation", "opcode" : 51, "operands" : [ { "kind" : "IdResultType" }, @@ -431,6 +586,7 @@ }, { "opname" : "OpSpecConstantOp", + "class" : "Constant-Creation", "opcode" : 52, "operands" : [ { "kind" : "IdResultType" }, @@ -440,6 +596,7 @@ }, { "opname" : "OpFunction", + "class" : "Function", "opcode" : 54, "operands" : [ { "kind" : "IdResultType" }, @@ -450,6 +607,7 @@ }, { "opname" : "OpFunctionParameter", + "class" : "Function", "opcode" : 55, "operands" : [ { "kind" : "IdResultType" }, @@ -458,10 +616,12 @@ }, { "opname" : "OpFunctionEnd", + "class" : "Function", "opcode" : 56 }, { "opname" : "OpFunctionCall", + "class" : "Function", "opcode" : 57, "operands" : [ { "kind" : "IdResultType" }, @@ -472,6 +632,7 @@ }, { "opname" : "OpVariable", + "class" : "Memory", "opcode" : 59, "operands" : [ { "kind" : "IdResultType" }, @@ -482,6 +643,7 @@ }, { "opname" : "OpImageTexelPointer", + "class" : "Memory", "opcode" : 60, "operands" : [ { "kind" : "IdResultType" }, @@ -493,6 +655,7 @@ }, { "opname" : "OpLoad", + "class" : "Memory", "opcode" : 61, "operands" : [ { "kind" : "IdResultType" }, @@ -503,6 +666,7 @@ }, { "opname" : "OpStore", + "class" : "Memory", "opcode" : 62, "operands" : [ { "kind" : "IdRef", "name" : "'Pointer'" }, @@ -512,26 +676,31 @@ }, { "opname" : "OpCopyMemory", + "class" : "Memory", "opcode" : 63, "operands" : [ { "kind" : "IdRef", "name" : "'Target'" }, { "kind" : "IdRef", "name" : "'Source'" }, + { "kind" : "MemoryAccess", "quantifier" : "?" }, { "kind" : "MemoryAccess", "quantifier" : "?" } ] }, { "opname" : "OpCopyMemorySized", + "class" : "Memory", "opcode" : 64, "operands" : [ { "kind" : "IdRef", "name" : "'Target'" }, { "kind" : "IdRef", "name" : "'Source'" }, { "kind" : "IdRef", "name" : "'Size'" }, + { "kind" : "MemoryAccess", "quantifier" : "?" }, { "kind" : "MemoryAccess", "quantifier" : "?" } ], "capabilities" : [ "Addresses" ] }, { "opname" : "OpAccessChain", + "class" : "Memory", "opcode" : 65, "operands" : [ { "kind" : "IdResultType" }, @@ -542,6 +711,7 @@ }, { "opname" : "OpInBoundsAccessChain", + "class" : "Memory", "opcode" : 66, "operands" : [ { "kind" : "IdResultType" }, @@ -552,6 +722,7 @@ }, { "opname" : "OpPtrAccessChain", + "class" : "Memory", "opcode" : 67, "operands" : [ { "kind" : "IdResultType" }, @@ -563,11 +734,13 @@ "capabilities" : [ "Addresses", "VariablePointers", - "VariablePointersStorageBuffer" + "VariablePointersStorageBuffer", + "PhysicalStorageBufferAddresses" ] }, { "opname" : "OpArrayLength", + "class" : "Memory", "opcode" : 68, "operands" : [ { "kind" : "IdResultType" }, @@ -579,6 +752,7 @@ }, { "opname" : "OpGenericPtrMemSemantics", + "class" : "Memory", "opcode" : 69, "operands" : [ { "kind" : "IdResultType" }, @@ -589,6 +763,7 @@ }, { "opname" : "OpInBoundsPtrAccessChain", + "class" : "Memory", "opcode" : 70, "operands" : [ { "kind" : "IdResultType" }, @@ -601,6 +776,7 @@ }, { "opname" : "OpDecorate", + "class" : "Annotation", "opcode" : 71, "operands" : [ { "kind" : "IdRef", "name" : "'Target'" }, @@ -609,6 +785,7 @@ }, { "opname" : "OpMemberDecorate", + "class" : "Annotation", "opcode" : 72, "operands" : [ { "kind" : "IdRef", "name" : "'Structure Type'" }, @@ -618,6 +795,7 @@ }, { "opname" : "OpDecorationGroup", + "class" : "Annotation", "opcode" : 73, "operands" : [ { "kind" : "IdResult" } @@ -625,6 +803,7 @@ }, { "opname" : "OpGroupDecorate", + "class" : "Annotation", "opcode" : 74, "operands" : [ { "kind" : "IdRef", "name" : "'Decoration Group'" }, @@ -633,6 +812,7 @@ }, { "opname" : "OpGroupMemberDecorate", + "class" : "Annotation", "opcode" : 75, "operands" : [ { "kind" : "IdRef", "name" : "'Decoration Group'" }, @@ -641,6 +821,7 @@ }, { "opname" : "OpVectorExtractDynamic", + "class" : "Composite", "opcode" : 77, "operands" : [ { "kind" : "IdResultType" }, @@ -651,6 +832,7 @@ }, { "opname" : "OpVectorInsertDynamic", + "class" : "Composite", "opcode" : 78, "operands" : [ { "kind" : "IdResultType" }, @@ -662,6 +844,7 @@ }, { "opname" : "OpVectorShuffle", + "class" : "Composite", "opcode" : 79, "operands" : [ { "kind" : "IdResultType" }, @@ -673,6 +856,7 @@ }, { "opname" : "OpCompositeConstruct", + "class" : "Composite", "opcode" : 80, "operands" : [ { "kind" : "IdResultType" }, @@ -682,6 +866,7 @@ }, { "opname" : "OpCompositeExtract", + "class" : "Composite", "opcode" : 81, "operands" : [ { "kind" : "IdResultType" }, @@ -692,6 +877,7 @@ }, { "opname" : "OpCompositeInsert", + "class" : "Composite", "opcode" : 82, "operands" : [ { "kind" : "IdResultType" }, @@ -703,6 +889,7 @@ }, { "opname" : "OpCopyObject", + "class" : "Composite", "opcode" : 83, "operands" : [ { "kind" : "IdResultType" }, @@ -712,6 +899,7 @@ }, { "opname" : "OpTranspose", + "class" : "Composite", "opcode" : 84, "operands" : [ { "kind" : "IdResultType" }, @@ -722,6 +910,7 @@ }, { "opname" : "OpSampledImage", + "class" : "Image", "opcode" : 86, "operands" : [ { "kind" : "IdResultType" }, @@ -732,6 +921,7 @@ }, { "opname" : "OpImageSampleImplicitLod", + "class" : "Image", "opcode" : 87, "operands" : [ { "kind" : "IdResultType" }, @@ -744,6 +934,7 @@ }, { "opname" : "OpImageSampleExplicitLod", + "class" : "Image", "opcode" : 88, "operands" : [ { "kind" : "IdResultType" }, @@ -755,6 +946,7 @@ }, { "opname" : "OpImageSampleDrefImplicitLod", + "class" : "Image", "opcode" : 89, "operands" : [ { "kind" : "IdResultType" }, @@ -768,6 +960,7 @@ }, { "opname" : "OpImageSampleDrefExplicitLod", + "class" : "Image", "opcode" : 90, "operands" : [ { "kind" : "IdResultType" }, @@ -781,6 +974,7 @@ }, { "opname" : "OpImageSampleProjImplicitLod", + "class" : "Image", "opcode" : 91, "operands" : [ { "kind" : "IdResultType" }, @@ -793,6 +987,7 @@ }, { "opname" : "OpImageSampleProjExplicitLod", + "class" : "Image", "opcode" : 92, "operands" : [ { "kind" : "IdResultType" }, @@ -805,6 +1000,7 @@ }, { "opname" : "OpImageSampleProjDrefImplicitLod", + "class" : "Image", "opcode" : 93, "operands" : [ { "kind" : "IdResultType" }, @@ -818,6 +1014,7 @@ }, { "opname" : "OpImageSampleProjDrefExplicitLod", + "class" : "Image", "opcode" : 94, "operands" : [ { "kind" : "IdResultType" }, @@ -831,6 +1028,7 @@ }, { "opname" : "OpImageFetch", + "class" : "Image", "opcode" : 95, "operands" : [ { "kind" : "IdResultType" }, @@ -842,6 +1040,7 @@ }, { "opname" : "OpImageGather", + "class" : "Image", "opcode" : 96, "operands" : [ { "kind" : "IdResultType" }, @@ -855,6 +1054,7 @@ }, { "opname" : "OpImageDrefGather", + "class" : "Image", "opcode" : 97, "operands" : [ { "kind" : "IdResultType" }, @@ -868,6 +1068,7 @@ }, { "opname" : "OpImageRead", + "class" : "Image", "opcode" : 98, "operands" : [ { "kind" : "IdResultType" }, @@ -879,6 +1080,7 @@ }, { "opname" : "OpImageWrite", + "class" : "Image", "opcode" : 99, "operands" : [ { "kind" : "IdRef", "name" : "'Image'" }, @@ -889,6 +1091,7 @@ }, { "opname" : "OpImage", + "class" : "Image", "opcode" : 100, "operands" : [ { "kind" : "IdResultType" }, @@ -898,6 +1101,7 @@ }, { "opname" : "OpImageQueryFormat", + "class" : "Image", "opcode" : 101, "operands" : [ { "kind" : "IdResultType" }, @@ -908,6 +1112,7 @@ }, { "opname" : "OpImageQueryOrder", + "class" : "Image", "opcode" : 102, "operands" : [ { "kind" : "IdResultType" }, @@ -918,6 +1123,7 @@ }, { "opname" : "OpImageQuerySizeLod", + "class" : "Image", "opcode" : 103, "operands" : [ { "kind" : "IdResultType" }, @@ -929,6 +1135,7 @@ }, { "opname" : "OpImageQuerySize", + "class" : "Image", "opcode" : 104, "operands" : [ { "kind" : "IdResultType" }, @@ -939,6 +1146,7 @@ }, { "opname" : "OpImageQueryLod", + "class" : "Image", "opcode" : 105, "operands" : [ { "kind" : "IdResultType" }, @@ -950,6 +1158,7 @@ }, { "opname" : "OpImageQueryLevels", + "class" : "Image", "opcode" : 106, "operands" : [ { "kind" : "IdResultType" }, @@ -960,6 +1169,7 @@ }, { "opname" : "OpImageQuerySamples", + "class" : "Image", "opcode" : 107, "operands" : [ { "kind" : "IdResultType" }, @@ -970,6 +1180,7 @@ }, { "opname" : "OpConvertFToU", + "class" : "Conversion", "opcode" : 109, "operands" : [ { "kind" : "IdResultType" }, @@ -979,6 +1190,7 @@ }, { "opname" : "OpConvertFToS", + "class" : "Conversion", "opcode" : 110, "operands" : [ { "kind" : "IdResultType" }, @@ -988,6 +1200,7 @@ }, { "opname" : "OpConvertSToF", + "class" : "Conversion", "opcode" : 111, "operands" : [ { "kind" : "IdResultType" }, @@ -997,6 +1210,7 @@ }, { "opname" : "OpConvertUToF", + "class" : "Conversion", "opcode" : 112, "operands" : [ { "kind" : "IdResultType" }, @@ -1006,6 +1220,7 @@ }, { "opname" : "OpUConvert", + "class" : "Conversion", "opcode" : 113, "operands" : [ { "kind" : "IdResultType" }, @@ -1015,6 +1230,7 @@ }, { "opname" : "OpSConvert", + "class" : "Conversion", "opcode" : 114, "operands" : [ { "kind" : "IdResultType" }, @@ -1024,6 +1240,7 @@ }, { "opname" : "OpFConvert", + "class" : "Conversion", "opcode" : 115, "operands" : [ { "kind" : "IdResultType" }, @@ -1033,6 +1250,7 @@ }, { "opname" : "OpQuantizeToF16", + "class" : "Conversion", "opcode" : 116, "operands" : [ { "kind" : "IdResultType" }, @@ -1042,16 +1260,21 @@ }, { "opname" : "OpConvertPtrToU", + "class" : "Conversion", "opcode" : 117, "operands" : [ { "kind" : "IdResultType" }, { "kind" : "IdResult" }, { "kind" : "IdRef", "name" : "'Pointer'" } ], - "capabilities" : [ "Addresses" ] + "capabilities" : [ + "Addresses", + "PhysicalStorageBufferAddresses" + ] }, { "opname" : "OpSatConvertSToU", + "class" : "Conversion", "opcode" : 118, "operands" : [ { "kind" : "IdResultType" }, @@ -1062,6 +1285,7 @@ }, { "opname" : "OpSatConvertUToS", + "class" : "Conversion", "opcode" : 119, "operands" : [ { "kind" : "IdResultType" }, @@ -1072,16 +1296,21 @@ }, { "opname" : "OpConvertUToPtr", + "class" : "Conversion", "opcode" : 120, "operands" : [ { "kind" : "IdResultType" }, { "kind" : "IdResult" }, { "kind" : "IdRef", "name" : "'Integer Value'" } ], - "capabilities" : [ "Addresses" ] + "capabilities" : [ + "Addresses", + "PhysicalStorageBufferAddresses" + ] }, { "opname" : "OpPtrCastToGeneric", + "class" : "Conversion", "opcode" : 121, "operands" : [ { "kind" : "IdResultType" }, @@ -1092,6 +1321,7 @@ }, { "opname" : "OpGenericCastToPtr", + "class" : "Conversion", "opcode" : 122, "operands" : [ { "kind" : "IdResultType" }, @@ -1102,6 +1332,7 @@ }, { "opname" : "OpGenericCastToPtrExplicit", + "class" : "Conversion", "opcode" : 123, "operands" : [ { "kind" : "IdResultType" }, @@ -1113,6 +1344,7 @@ }, { "opname" : "OpBitcast", + "class" : "Conversion", "opcode" : 124, "operands" : [ { "kind" : "IdResultType" }, @@ -1122,6 +1354,7 @@ }, { "opname" : "OpSNegate", + "class" : "Arithmetic", "opcode" : 126, "operands" : [ { "kind" : "IdResultType" }, @@ -1131,6 +1364,7 @@ }, { "opname" : "OpFNegate", + "class" : "Arithmetic", "opcode" : 127, "operands" : [ { "kind" : "IdResultType" }, @@ -1140,6 +1374,7 @@ }, { "opname" : "OpIAdd", + "class" : "Arithmetic", "opcode" : 128, "operands" : [ { "kind" : "IdResultType" }, @@ -1150,6 +1385,7 @@ }, { "opname" : "OpFAdd", + "class" : "Arithmetic", "opcode" : 129, "operands" : [ { "kind" : "IdResultType" }, @@ -1160,6 +1396,7 @@ }, { "opname" : "OpISub", + "class" : "Arithmetic", "opcode" : 130, "operands" : [ { "kind" : "IdResultType" }, @@ -1170,6 +1407,7 @@ }, { "opname" : "OpFSub", + "class" : "Arithmetic", "opcode" : 131, "operands" : [ { "kind" : "IdResultType" }, @@ -1180,6 +1418,7 @@ }, { "opname" : "OpIMul", + "class" : "Arithmetic", "opcode" : 132, "operands" : [ { "kind" : "IdResultType" }, @@ -1190,6 +1429,7 @@ }, { "opname" : "OpFMul", + "class" : "Arithmetic", "opcode" : 133, "operands" : [ { "kind" : "IdResultType" }, @@ -1200,6 +1440,7 @@ }, { "opname" : "OpUDiv", + "class" : "Arithmetic", "opcode" : 134, "operands" : [ { "kind" : "IdResultType" }, @@ -1210,6 +1451,7 @@ }, { "opname" : "OpSDiv", + "class" : "Arithmetic", "opcode" : 135, "operands" : [ { "kind" : "IdResultType" }, @@ -1220,6 +1462,7 @@ }, { "opname" : "OpFDiv", + "class" : "Arithmetic", "opcode" : 136, "operands" : [ { "kind" : "IdResultType" }, @@ -1230,6 +1473,7 @@ }, { "opname" : "OpUMod", + "class" : "Arithmetic", "opcode" : 137, "operands" : [ { "kind" : "IdResultType" }, @@ -1240,6 +1484,7 @@ }, { "opname" : "OpSRem", + "class" : "Arithmetic", "opcode" : 138, "operands" : [ { "kind" : "IdResultType" }, @@ -1250,6 +1495,7 @@ }, { "opname" : "OpSMod", + "class" : "Arithmetic", "opcode" : 139, "operands" : [ { "kind" : "IdResultType" }, @@ -1260,6 +1506,7 @@ }, { "opname" : "OpFRem", + "class" : "Arithmetic", "opcode" : 140, "operands" : [ { "kind" : "IdResultType" }, @@ -1270,6 +1517,7 @@ }, { "opname" : "OpFMod", + "class" : "Arithmetic", "opcode" : 141, "operands" : [ { "kind" : "IdResultType" }, @@ -1280,6 +1528,7 @@ }, { "opname" : "OpVectorTimesScalar", + "class" : "Arithmetic", "opcode" : 142, "operands" : [ { "kind" : "IdResultType" }, @@ -1290,6 +1539,7 @@ }, { "opname" : "OpMatrixTimesScalar", + "class" : "Arithmetic", "opcode" : 143, "operands" : [ { "kind" : "IdResultType" }, @@ -1301,6 +1551,7 @@ }, { "opname" : "OpVectorTimesMatrix", + "class" : "Arithmetic", "opcode" : 144, "operands" : [ { "kind" : "IdResultType" }, @@ -1312,6 +1563,7 @@ }, { "opname" : "OpMatrixTimesVector", + "class" : "Arithmetic", "opcode" : 145, "operands" : [ { "kind" : "IdResultType" }, @@ -1323,6 +1575,7 @@ }, { "opname" : "OpMatrixTimesMatrix", + "class" : "Arithmetic", "opcode" : 146, "operands" : [ { "kind" : "IdResultType" }, @@ -1334,6 +1587,7 @@ }, { "opname" : "OpOuterProduct", + "class" : "Arithmetic", "opcode" : 147, "operands" : [ { "kind" : "IdResultType" }, @@ -1345,6 +1599,7 @@ }, { "opname" : "OpDot", + "class" : "Arithmetic", "opcode" : 148, "operands" : [ { "kind" : "IdResultType" }, @@ -1355,6 +1610,7 @@ }, { "opname" : "OpIAddCarry", + "class" : "Arithmetic", "opcode" : 149, "operands" : [ { "kind" : "IdResultType" }, @@ -1365,6 +1621,7 @@ }, { "opname" : "OpISubBorrow", + "class" : "Arithmetic", "opcode" : 150, "operands" : [ { "kind" : "IdResultType" }, @@ -1375,6 +1632,7 @@ }, { "opname" : "OpUMulExtended", + "class" : "Arithmetic", "opcode" : 151, "operands" : [ { "kind" : "IdResultType" }, @@ -1385,6 +1643,7 @@ }, { "opname" : "OpSMulExtended", + "class" : "Arithmetic", "opcode" : 152, "operands" : [ { "kind" : "IdResultType" }, @@ -1395,6 +1654,7 @@ }, { "opname" : "OpAny", + "class" : "Relational_and_Logical", "opcode" : 154, "operands" : [ { "kind" : "IdResultType" }, @@ -1404,6 +1664,7 @@ }, { "opname" : "OpAll", + "class" : "Relational_and_Logical", "opcode" : 155, "operands" : [ { "kind" : "IdResultType" }, @@ -1413,6 +1674,7 @@ }, { "opname" : "OpIsNan", + "class" : "Relational_and_Logical", "opcode" : 156, "operands" : [ { "kind" : "IdResultType" }, @@ -1422,6 +1684,7 @@ }, { "opname" : "OpIsInf", + "class" : "Relational_and_Logical", "opcode" : 157, "operands" : [ { "kind" : "IdResultType" }, @@ -1431,6 +1694,7 @@ }, { "opname" : "OpIsFinite", + "class" : "Relational_and_Logical", "opcode" : 158, "operands" : [ { "kind" : "IdResultType" }, @@ -1441,6 +1705,7 @@ }, { "opname" : "OpIsNormal", + "class" : "Relational_and_Logical", "opcode" : 159, "operands" : [ { "kind" : "IdResultType" }, @@ -1451,6 +1716,7 @@ }, { "opname" : "OpSignBitSet", + "class" : "Relational_and_Logical", "opcode" : 160, "operands" : [ { "kind" : "IdResultType" }, @@ -1461,6 +1727,7 @@ }, { "opname" : "OpLessOrGreater", + "class" : "Relational_and_Logical", "opcode" : 161, "operands" : [ { "kind" : "IdResultType" }, @@ -1472,6 +1739,7 @@ }, { "opname" : "OpOrdered", + "class" : "Relational_and_Logical", "opcode" : 162, "operands" : [ { "kind" : "IdResultType" }, @@ -1483,6 +1751,7 @@ }, { "opname" : "OpUnordered", + "class" : "Relational_and_Logical", "opcode" : 163, "operands" : [ { "kind" : "IdResultType" }, @@ -1494,6 +1763,7 @@ }, { "opname" : "OpLogicalEqual", + "class" : "Relational_and_Logical", "opcode" : 164, "operands" : [ { "kind" : "IdResultType" }, @@ -1504,6 +1774,7 @@ }, { "opname" : "OpLogicalNotEqual", + "class" : "Relational_and_Logical", "opcode" : 165, "operands" : [ { "kind" : "IdResultType" }, @@ -1514,6 +1785,7 @@ }, { "opname" : "OpLogicalOr", + "class" : "Relational_and_Logical", "opcode" : 166, "operands" : [ { "kind" : "IdResultType" }, @@ -1524,6 +1796,7 @@ }, { "opname" : "OpLogicalAnd", + "class" : "Relational_and_Logical", "opcode" : 167, "operands" : [ { "kind" : "IdResultType" }, @@ -1534,6 +1807,7 @@ }, { "opname" : "OpLogicalNot", + "class" : "Relational_and_Logical", "opcode" : 168, "operands" : [ { "kind" : "IdResultType" }, @@ -1543,6 +1817,7 @@ }, { "opname" : "OpSelect", + "class" : "Relational_and_Logical", "opcode" : 169, "operands" : [ { "kind" : "IdResultType" }, @@ -1554,6 +1829,7 @@ }, { "opname" : "OpIEqual", + "class" : "Relational_and_Logical", "opcode" : 170, "operands" : [ { "kind" : "IdResultType" }, @@ -1564,6 +1840,7 @@ }, { "opname" : "OpINotEqual", + "class" : "Relational_and_Logical", "opcode" : 171, "operands" : [ { "kind" : "IdResultType" }, @@ -1574,6 +1851,7 @@ }, { "opname" : "OpUGreaterThan", + "class" : "Relational_and_Logical", "opcode" : 172, "operands" : [ { "kind" : "IdResultType" }, @@ -1584,6 +1862,7 @@ }, { "opname" : "OpSGreaterThan", + "class" : "Relational_and_Logical", "opcode" : 173, "operands" : [ { "kind" : "IdResultType" }, @@ -1594,6 +1873,7 @@ }, { "opname" : "OpUGreaterThanEqual", + "class" : "Relational_and_Logical", "opcode" : 174, "operands" : [ { "kind" : "IdResultType" }, @@ -1604,6 +1884,7 @@ }, { "opname" : "OpSGreaterThanEqual", + "class" : "Relational_and_Logical", "opcode" : 175, "operands" : [ { "kind" : "IdResultType" }, @@ -1614,6 +1895,7 @@ }, { "opname" : "OpULessThan", + "class" : "Relational_and_Logical", "opcode" : 176, "operands" : [ { "kind" : "IdResultType" }, @@ -1624,6 +1906,7 @@ }, { "opname" : "OpSLessThan", + "class" : "Relational_and_Logical", "opcode" : 177, "operands" : [ { "kind" : "IdResultType" }, @@ -1634,6 +1917,7 @@ }, { "opname" : "OpULessThanEqual", + "class" : "Relational_and_Logical", "opcode" : 178, "operands" : [ { "kind" : "IdResultType" }, @@ -1644,6 +1928,7 @@ }, { "opname" : "OpSLessThanEqual", + "class" : "Relational_and_Logical", "opcode" : 179, "operands" : [ { "kind" : "IdResultType" }, @@ -1654,6 +1939,7 @@ }, { "opname" : "OpFOrdEqual", + "class" : "Relational_and_Logical", "opcode" : 180, "operands" : [ { "kind" : "IdResultType" }, @@ -1664,6 +1950,7 @@ }, { "opname" : "OpFUnordEqual", + "class" : "Relational_and_Logical", "opcode" : 181, "operands" : [ { "kind" : "IdResultType" }, @@ -1674,6 +1961,7 @@ }, { "opname" : "OpFOrdNotEqual", + "class" : "Relational_and_Logical", "opcode" : 182, "operands" : [ { "kind" : "IdResultType" }, @@ -1684,6 +1972,7 @@ }, { "opname" : "OpFUnordNotEqual", + "class" : "Relational_and_Logical", "opcode" : 183, "operands" : [ { "kind" : "IdResultType" }, @@ -1694,6 +1983,7 @@ }, { "opname" : "OpFOrdLessThan", + "class" : "Relational_and_Logical", "opcode" : 184, "operands" : [ { "kind" : "IdResultType" }, @@ -1704,6 +1994,7 @@ }, { "opname" : "OpFUnordLessThan", + "class" : "Relational_and_Logical", "opcode" : 185, "operands" : [ { "kind" : "IdResultType" }, @@ -1714,6 +2005,7 @@ }, { "opname" : "OpFOrdGreaterThan", + "class" : "Relational_and_Logical", "opcode" : 186, "operands" : [ { "kind" : "IdResultType" }, @@ -1724,6 +2016,7 @@ }, { "opname" : "OpFUnordGreaterThan", + "class" : "Relational_and_Logical", "opcode" : 187, "operands" : [ { "kind" : "IdResultType" }, @@ -1734,6 +2027,7 @@ }, { "opname" : "OpFOrdLessThanEqual", + "class" : "Relational_and_Logical", "opcode" : 188, "operands" : [ { "kind" : "IdResultType" }, @@ -1744,6 +2038,7 @@ }, { "opname" : "OpFUnordLessThanEqual", + "class" : "Relational_and_Logical", "opcode" : 189, "operands" : [ { "kind" : "IdResultType" }, @@ -1754,6 +2049,7 @@ }, { "opname" : "OpFOrdGreaterThanEqual", + "class" : "Relational_and_Logical", "opcode" : 190, "operands" : [ { "kind" : "IdResultType" }, @@ -1764,6 +2060,7 @@ }, { "opname" : "OpFUnordGreaterThanEqual", + "class" : "Relational_and_Logical", "opcode" : 191, "operands" : [ { "kind" : "IdResultType" }, @@ -1774,6 +2071,7 @@ }, { "opname" : "OpShiftRightLogical", + "class" : "Bit", "opcode" : 194, "operands" : [ { "kind" : "IdResultType" }, @@ -1784,6 +2082,7 @@ }, { "opname" : "OpShiftRightArithmetic", + "class" : "Bit", "opcode" : 195, "operands" : [ { "kind" : "IdResultType" }, @@ -1794,6 +2093,7 @@ }, { "opname" : "OpShiftLeftLogical", + "class" : "Bit", "opcode" : 196, "operands" : [ { "kind" : "IdResultType" }, @@ -1804,6 +2104,7 @@ }, { "opname" : "OpBitwiseOr", + "class" : "Bit", "opcode" : 197, "operands" : [ { "kind" : "IdResultType" }, @@ -1814,6 +2115,7 @@ }, { "opname" : "OpBitwiseXor", + "class" : "Bit", "opcode" : 198, "operands" : [ { "kind" : "IdResultType" }, @@ -1824,6 +2126,7 @@ }, { "opname" : "OpBitwiseAnd", + "class" : "Bit", "opcode" : 199, "operands" : [ { "kind" : "IdResultType" }, @@ -1834,6 +2137,7 @@ }, { "opname" : "OpNot", + "class" : "Bit", "opcode" : 200, "operands" : [ { "kind" : "IdResultType" }, @@ -1843,6 +2147,7 @@ }, { "opname" : "OpBitFieldInsert", + "class" : "Bit", "opcode" : 201, "operands" : [ { "kind" : "IdResultType" }, @@ -1856,6 +2161,7 @@ }, { "opname" : "OpBitFieldSExtract", + "class" : "Bit", "opcode" : 202, "operands" : [ { "kind" : "IdResultType" }, @@ -1868,6 +2174,7 @@ }, { "opname" : "OpBitFieldUExtract", + "class" : "Bit", "opcode" : 203, "operands" : [ { "kind" : "IdResultType" }, @@ -1880,6 +2187,7 @@ }, { "opname" : "OpBitReverse", + "class" : "Bit", "opcode" : 204, "operands" : [ { "kind" : "IdResultType" }, @@ -1890,6 +2198,7 @@ }, { "opname" : "OpBitCount", + "class" : "Bit", "opcode" : 205, "operands" : [ { "kind" : "IdResultType" }, @@ -1899,6 +2208,7 @@ }, { "opname" : "OpDPdx", + "class" : "Derivative", "opcode" : 207, "operands" : [ { "kind" : "IdResultType" }, @@ -1909,6 +2219,7 @@ }, { "opname" : "OpDPdy", + "class" : "Derivative", "opcode" : 208, "operands" : [ { "kind" : "IdResultType" }, @@ -1919,6 +2230,7 @@ }, { "opname" : "OpFwidth", + "class" : "Derivative", "opcode" : 209, "operands" : [ { "kind" : "IdResultType" }, @@ -1929,6 +2241,7 @@ }, { "opname" : "OpDPdxFine", + "class" : "Derivative", "opcode" : 210, "operands" : [ { "kind" : "IdResultType" }, @@ -1939,6 +2252,7 @@ }, { "opname" : "OpDPdyFine", + "class" : "Derivative", "opcode" : 211, "operands" : [ { "kind" : "IdResultType" }, @@ -1949,6 +2263,7 @@ }, { "opname" : "OpFwidthFine", + "class" : "Derivative", "opcode" : 212, "operands" : [ { "kind" : "IdResultType" }, @@ -1959,6 +2274,7 @@ }, { "opname" : "OpDPdxCoarse", + "class" : "Derivative", "opcode" : 213, "operands" : [ { "kind" : "IdResultType" }, @@ -1969,6 +2285,7 @@ }, { "opname" : "OpDPdyCoarse", + "class" : "Derivative", "opcode" : 214, "operands" : [ { "kind" : "IdResultType" }, @@ -1979,6 +2296,7 @@ }, { "opname" : "OpFwidthCoarse", + "class" : "Derivative", "opcode" : 215, "operands" : [ { "kind" : "IdResultType" }, @@ -1989,16 +2307,19 @@ }, { "opname" : "OpEmitVertex", + "class" : "Primitive", "opcode" : 218, "capabilities" : [ "Geometry" ] }, { "opname" : "OpEndPrimitive", + "class" : "Primitive", "opcode" : 219, "capabilities" : [ "Geometry" ] }, { "opname" : "OpEmitStreamVertex", + "class" : "Primitive", "opcode" : 220, "operands" : [ { "kind" : "IdRef", "name" : "'Stream'" } @@ -2007,6 +2328,7 @@ }, { "opname" : "OpEndStreamPrimitive", + "class" : "Primitive", "opcode" : 221, "operands" : [ { "kind" : "IdRef", "name" : "'Stream'" } @@ -2015,6 +2337,7 @@ }, { "opname" : "OpControlBarrier", + "class" : "Barrier", "opcode" : 224, "operands" : [ { "kind" : "IdScope", "name" : "'Execution'" }, @@ -2024,6 +2347,7 @@ }, { "opname" : "OpMemoryBarrier", + "class" : "Barrier", "opcode" : 225, "operands" : [ { "kind" : "IdScope", "name" : "'Memory'" }, @@ -2032,45 +2356,49 @@ }, { "opname" : "OpAtomicLoad", + "class" : "Atomic", "opcode" : 227, "operands" : [ { "kind" : "IdResultType" }, { "kind" : "IdResult" }, { "kind" : "IdRef", "name" : "'Pointer'" }, - { "kind" : "IdScope", "name" : "'Scope'" }, + { "kind" : "IdScope", "name" : "'Memory'" }, { "kind" : "IdMemorySemantics", "name" : "'Semantics'" } ] }, { "opname" : "OpAtomicStore", + "class" : "Atomic", "opcode" : 228, "operands" : [ { "kind" : "IdRef", "name" : "'Pointer'" }, - { "kind" : "IdScope", "name" : "'Scope'" }, + { "kind" : "IdScope", "name" : "'Memory'" }, { "kind" : "IdMemorySemantics", "name" : "'Semantics'" }, { "kind" : "IdRef", "name" : "'Value'" } ] }, { "opname" : "OpAtomicExchange", + "class" : "Atomic", "opcode" : 229, "operands" : [ { "kind" : "IdResultType" }, { "kind" : "IdResult" }, { "kind" : "IdRef", "name" : "'Pointer'" }, - { "kind" : "IdScope", "name" : "'Scope'" }, + { "kind" : "IdScope", "name" : "'Memory'" }, { "kind" : "IdMemorySemantics", "name" : "'Semantics'" }, { "kind" : "IdRef", "name" : "'Value'" } ] }, { "opname" : "OpAtomicCompareExchange", + "class" : "Atomic", "opcode" : 230, "operands" : [ { "kind" : "IdResultType" }, { "kind" : "IdResult" }, { "kind" : "IdRef", "name" : "'Pointer'" }, - { "kind" : "IdScope", "name" : "'Scope'" }, + { "kind" : "IdScope", "name" : "'Memory'" }, { "kind" : "IdMemorySemantics", "name" : "'Equal'" }, { "kind" : "IdMemorySemantics", "name" : "'Unequal'" }, { "kind" : "IdRef", "name" : "'Value'" }, @@ -2079,151 +2407,165 @@ }, { "opname" : "OpAtomicCompareExchangeWeak", + "class" : "Atomic", "opcode" : 231, "operands" : [ { "kind" : "IdResultType" }, { "kind" : "IdResult" }, { "kind" : "IdRef", "name" : "'Pointer'" }, - { "kind" : "IdScope", "name" : "'Scope'" }, + { "kind" : "IdScope", "name" : "'Memory'" }, { "kind" : "IdMemorySemantics", "name" : "'Equal'" }, { "kind" : "IdMemorySemantics", "name" : "'Unequal'" }, { "kind" : "IdRef", "name" : "'Value'" }, { "kind" : "IdRef", "name" : "'Comparator'" } ], - "capabilities" : [ "Kernel" ] + "capabilities" : [ "Kernel" ], + "lastVersion" : "1.3" }, { "opname" : "OpAtomicIIncrement", + "class" : "Atomic", "opcode" : 232, "operands" : [ { "kind" : "IdResultType" }, { "kind" : "IdResult" }, { "kind" : "IdRef", "name" : "'Pointer'" }, - { "kind" : "IdScope", "name" : "'Scope'" }, + { "kind" : "IdScope", "name" : "'Memory'" }, { "kind" : "IdMemorySemantics", "name" : "'Semantics'" } ] }, { "opname" : "OpAtomicIDecrement", + "class" : "Atomic", "opcode" : 233, "operands" : [ { "kind" : "IdResultType" }, { "kind" : "IdResult" }, { "kind" : "IdRef", "name" : "'Pointer'" }, - { "kind" : "IdScope", "name" : "'Scope'" }, + { "kind" : "IdScope", "name" : "'Memory'" }, { "kind" : "IdMemorySemantics", "name" : "'Semantics'" } ] }, { "opname" : "OpAtomicIAdd", + "class" : "Atomic", "opcode" : 234, "operands" : [ { "kind" : "IdResultType" }, { "kind" : "IdResult" }, { "kind" : "IdRef", "name" : "'Pointer'" }, - { "kind" : "IdScope", "name" : "'Scope'" }, + { "kind" : "IdScope", "name" : "'Memory'" }, { "kind" : "IdMemorySemantics", "name" : "'Semantics'" }, { "kind" : "IdRef", "name" : "'Value'" } ] }, { "opname" : "OpAtomicISub", + "class" : "Atomic", "opcode" : 235, "operands" : [ { "kind" : "IdResultType" }, { "kind" : "IdResult" }, { "kind" : "IdRef", "name" : "'Pointer'" }, - { "kind" : "IdScope", "name" : "'Scope'" }, + { "kind" : "IdScope", "name" : "'Memory'" }, { "kind" : "IdMemorySemantics", "name" : "'Semantics'" }, { "kind" : "IdRef", "name" : "'Value'" } ] }, { "opname" : "OpAtomicSMin", + "class" : "Atomic", "opcode" : 236, "operands" : [ { "kind" : "IdResultType" }, { "kind" : "IdResult" }, { "kind" : "IdRef", "name" : "'Pointer'" }, - { "kind" : "IdScope", "name" : "'Scope'" }, + { "kind" : "IdScope", "name" : "'Memory'" }, { "kind" : "IdMemorySemantics", "name" : "'Semantics'" }, { "kind" : "IdRef", "name" : "'Value'" } ] }, { "opname" : "OpAtomicUMin", + "class" : "Atomic", "opcode" : 237, "operands" : [ { "kind" : "IdResultType" }, { "kind" : "IdResult" }, { "kind" : "IdRef", "name" : "'Pointer'" }, - { "kind" : "IdScope", "name" : "'Scope'" }, + { "kind" : "IdScope", "name" : "'Memory'" }, { "kind" : "IdMemorySemantics", "name" : "'Semantics'" }, { "kind" : "IdRef", "name" : "'Value'" } ] }, { "opname" : "OpAtomicSMax", + "class" : "Atomic", "opcode" : 238, "operands" : [ { "kind" : "IdResultType" }, { "kind" : "IdResult" }, { "kind" : "IdRef", "name" : "'Pointer'" }, - { "kind" : "IdScope", "name" : "'Scope'" }, + { "kind" : "IdScope", "name" : "'Memory'" }, { "kind" : "IdMemorySemantics", "name" : "'Semantics'" }, { "kind" : "IdRef", "name" : "'Value'" } ] }, { "opname" : "OpAtomicUMax", + "class" : "Atomic", "opcode" : 239, "operands" : [ { "kind" : "IdResultType" }, { "kind" : "IdResult" }, { "kind" : "IdRef", "name" : "'Pointer'" }, - { "kind" : "IdScope", "name" : "'Scope'" }, + { "kind" : "IdScope", "name" : "'Memory'" }, { "kind" : "IdMemorySemantics", "name" : "'Semantics'" }, { "kind" : "IdRef", "name" : "'Value'" } ] }, { "opname" : "OpAtomicAnd", + "class" : "Atomic", "opcode" : 240, "operands" : [ { "kind" : "IdResultType" }, { "kind" : "IdResult" }, { "kind" : "IdRef", "name" : "'Pointer'" }, - { "kind" : "IdScope", "name" : "'Scope'" }, + { "kind" : "IdScope", "name" : "'Memory'" }, { "kind" : "IdMemorySemantics", "name" : "'Semantics'" }, { "kind" : "IdRef", "name" : "'Value'" } ] }, { "opname" : "OpAtomicOr", + "class" : "Atomic", "opcode" : 241, "operands" : [ { "kind" : "IdResultType" }, { "kind" : "IdResult" }, { "kind" : "IdRef", "name" : "'Pointer'" }, - { "kind" : "IdScope", "name" : "'Scope'" }, + { "kind" : "IdScope", "name" : "'Memory'" }, { "kind" : "IdMemorySemantics", "name" : "'Semantics'" }, { "kind" : "IdRef", "name" : "'Value'" } ] }, { "opname" : "OpAtomicXor", + "class" : "Atomic", "opcode" : 242, "operands" : [ { "kind" : "IdResultType" }, { "kind" : "IdResult" }, { "kind" : "IdRef", "name" : "'Pointer'" }, - { "kind" : "IdScope", "name" : "'Scope'" }, + { "kind" : "IdScope", "name" : "'Memory'" }, { "kind" : "IdMemorySemantics", "name" : "'Semantics'" }, { "kind" : "IdRef", "name" : "'Value'" } ] }, { "opname" : "OpPhi", + "class" : "Control-Flow", "opcode" : 245, "operands" : [ { "kind" : "IdResultType" }, @@ -2233,6 +2575,7 @@ }, { "opname" : "OpLoopMerge", + "class" : "Control-Flow", "opcode" : 246, "operands" : [ { "kind" : "IdRef", "name" : "'Merge Block'" }, @@ -2242,6 +2585,7 @@ }, { "opname" : "OpSelectionMerge", + "class" : "Control-Flow", "opcode" : 247, "operands" : [ { "kind" : "IdRef", "name" : "'Merge Block'" }, @@ -2250,6 +2594,7 @@ }, { "opname" : "OpLabel", + "class" : "Control-Flow", "opcode" : 248, "operands" : [ { "kind" : "IdResult" } @@ -2257,6 +2602,7 @@ }, { "opname" : "OpBranch", + "class" : "Control-Flow", "opcode" : 249, "operands" : [ { "kind" : "IdRef", "name" : "'Target Label'" } @@ -2264,6 +2610,7 @@ }, { "opname" : "OpBranchConditional", + "class" : "Control-Flow", "opcode" : 250, "operands" : [ { "kind" : "IdRef", "name" : "'Condition'" }, @@ -2274,6 +2621,7 @@ }, { "opname" : "OpSwitch", + "class" : "Control-Flow", "opcode" : 251, "operands" : [ { "kind" : "IdRef", "name" : "'Selector'" }, @@ -2283,15 +2631,18 @@ }, { "opname" : "OpKill", + "class" : "Control-Flow", "opcode" : 252, "capabilities" : [ "Shader" ] }, { "opname" : "OpReturn", + "class" : "Control-Flow", "opcode" : 253 }, { "opname" : "OpReturnValue", + "class" : "Control-Flow", "opcode" : 254, "operands" : [ { "kind" : "IdRef", "name" : "'Value'" } @@ -2299,10 +2650,12 @@ }, { "opname" : "OpUnreachable", + "class" : "Control-Flow", "opcode" : 255 }, { "opname" : "OpLifetimeStart", + "class" : "Control-Flow", "opcode" : 256, "operands" : [ { "kind" : "IdRef", "name" : "'Pointer'" }, @@ -2312,6 +2665,7 @@ }, { "opname" : "OpLifetimeStop", + "class" : "Control-Flow", "opcode" : 257, "operands" : [ { "kind" : "IdRef", "name" : "'Pointer'" }, @@ -2321,6 +2675,7 @@ }, { "opname" : "OpGroupAsyncCopy", + "class" : "Group", "opcode" : 259, "operands" : [ { "kind" : "IdResultType" }, @@ -2336,6 +2691,7 @@ }, { "opname" : "OpGroupWaitEvents", + "class" : "Group", "opcode" : 260, "operands" : [ { "kind" : "IdScope", "name" : "'Execution'" }, @@ -2346,6 +2702,7 @@ }, { "opname" : "OpGroupAll", + "class" : "Group", "opcode" : 261, "operands" : [ { "kind" : "IdResultType" }, @@ -2357,6 +2714,7 @@ }, { "opname" : "OpGroupAny", + "class" : "Group", "opcode" : 262, "operands" : [ { "kind" : "IdResultType" }, @@ -2368,6 +2726,7 @@ }, { "opname" : "OpGroupBroadcast", + "class" : "Group", "opcode" : 263, "operands" : [ { "kind" : "IdResultType" }, @@ -2380,6 +2739,7 @@ }, { "opname" : "OpGroupIAdd", + "class" : "Group", "opcode" : 264, "operands" : [ { "kind" : "IdResultType" }, @@ -2392,6 +2752,7 @@ }, { "opname" : "OpGroupFAdd", + "class" : "Group", "opcode" : 265, "operands" : [ { "kind" : "IdResultType" }, @@ -2404,6 +2765,7 @@ }, { "opname" : "OpGroupFMin", + "class" : "Group", "opcode" : 266, "operands" : [ { "kind" : "IdResultType" }, @@ -2416,6 +2778,7 @@ }, { "opname" : "OpGroupUMin", + "class" : "Group", "opcode" : 267, "operands" : [ { "kind" : "IdResultType" }, @@ -2428,6 +2791,7 @@ }, { "opname" : "OpGroupSMin", + "class" : "Group", "opcode" : 268, "operands" : [ { "kind" : "IdResultType" }, @@ -2440,6 +2804,7 @@ }, { "opname" : "OpGroupFMax", + "class" : "Group", "opcode" : 269, "operands" : [ { "kind" : "IdResultType" }, @@ -2452,6 +2817,7 @@ }, { "opname" : "OpGroupUMax", + "class" : "Group", "opcode" : 270, "operands" : [ { "kind" : "IdResultType" }, @@ -2464,6 +2830,7 @@ }, { "opname" : "OpGroupSMax", + "class" : "Group", "opcode" : 271, "operands" : [ { "kind" : "IdResultType" }, @@ -2476,6 +2843,7 @@ }, { "opname" : "OpReadPipe", + "class" : "Pipe", "opcode" : 274, "operands" : [ { "kind" : "IdResultType" }, @@ -2489,6 +2857,7 @@ }, { "opname" : "OpWritePipe", + "class" : "Pipe", "opcode" : 275, "operands" : [ { "kind" : "IdResultType" }, @@ -2502,6 +2871,7 @@ }, { "opname" : "OpReservedReadPipe", + "class" : "Pipe", "opcode" : 276, "operands" : [ { "kind" : "IdResultType" }, @@ -2517,6 +2887,7 @@ }, { "opname" : "OpReservedWritePipe", + "class" : "Pipe", "opcode" : 277, "operands" : [ { "kind" : "IdResultType" }, @@ -2532,6 +2903,7 @@ }, { "opname" : "OpReserveReadPipePackets", + "class" : "Pipe", "opcode" : 278, "operands" : [ { "kind" : "IdResultType" }, @@ -2545,6 +2917,7 @@ }, { "opname" : "OpReserveWritePipePackets", + "class" : "Pipe", "opcode" : 279, "operands" : [ { "kind" : "IdResultType" }, @@ -2558,6 +2931,7 @@ }, { "opname" : "OpCommitReadPipe", + "class" : "Pipe", "opcode" : 280, "operands" : [ { "kind" : "IdRef", "name" : "'Pipe'" }, @@ -2569,6 +2943,7 @@ }, { "opname" : "OpCommitWritePipe", + "class" : "Pipe", "opcode" : 281, "operands" : [ { "kind" : "IdRef", "name" : "'Pipe'" }, @@ -2580,6 +2955,7 @@ }, { "opname" : "OpIsValidReserveId", + "class" : "Pipe", "opcode" : 282, "operands" : [ { "kind" : "IdResultType" }, @@ -2590,6 +2966,7 @@ }, { "opname" : "OpGetNumPipePackets", + "class" : "Pipe", "opcode" : 283, "operands" : [ { "kind" : "IdResultType" }, @@ -2602,6 +2979,7 @@ }, { "opname" : "OpGetMaxPipePackets", + "class" : "Pipe", "opcode" : 284, "operands" : [ { "kind" : "IdResultType" }, @@ -2614,6 +2992,7 @@ }, { "opname" : "OpGroupReserveReadPipePackets", + "class" : "Pipe", "opcode" : 285, "operands" : [ { "kind" : "IdResultType" }, @@ -2628,6 +3007,7 @@ }, { "opname" : "OpGroupReserveWritePipePackets", + "class" : "Pipe", "opcode" : 286, "operands" : [ { "kind" : "IdResultType" }, @@ -2642,6 +3022,7 @@ }, { "opname" : "OpGroupCommitReadPipe", + "class" : "Pipe", "opcode" : 287, "operands" : [ { "kind" : "IdScope", "name" : "'Execution'" }, @@ -2654,6 +3035,7 @@ }, { "opname" : "OpGroupCommitWritePipe", + "class" : "Pipe", "opcode" : 288, "operands" : [ { "kind" : "IdScope", "name" : "'Execution'" }, @@ -2666,6 +3048,7 @@ }, { "opname" : "OpEnqueueMarker", + "class" : "Device-Side_Enqueue", "opcode" : 291, "operands" : [ { "kind" : "IdResultType" }, @@ -2679,6 +3062,7 @@ }, { "opname" : "OpEnqueueKernel", + "class" : "Device-Side_Enqueue", "opcode" : 292, "operands" : [ { "kind" : "IdResultType" }, @@ -2699,6 +3083,7 @@ }, { "opname" : "OpGetKernelNDrangeSubGroupCount", + "class" : "Device-Side_Enqueue", "opcode" : 293, "operands" : [ { "kind" : "IdResultType" }, @@ -2713,6 +3098,7 @@ }, { "opname" : "OpGetKernelNDrangeMaxSubGroupSize", + "class" : "Device-Side_Enqueue", "opcode" : 294, "operands" : [ { "kind" : "IdResultType" }, @@ -2727,6 +3113,7 @@ }, { "opname" : "OpGetKernelWorkGroupSize", + "class" : "Device-Side_Enqueue", "opcode" : 295, "operands" : [ { "kind" : "IdResultType" }, @@ -2740,6 +3127,7 @@ }, { "opname" : "OpGetKernelPreferredWorkGroupSizeMultiple", + "class" : "Device-Side_Enqueue", "opcode" : 296, "operands" : [ { "kind" : "IdResultType" }, @@ -2753,6 +3141,7 @@ }, { "opname" : "OpRetainEvent", + "class" : "Device-Side_Enqueue", "opcode" : 297, "operands" : [ { "kind" : "IdRef", "name" : "'Event'" } @@ -2761,6 +3150,7 @@ }, { "opname" : "OpReleaseEvent", + "class" : "Device-Side_Enqueue", "opcode" : 298, "operands" : [ { "kind" : "IdRef", "name" : "'Event'" } @@ -2769,6 +3159,7 @@ }, { "opname" : "OpCreateUserEvent", + "class" : "Device-Side_Enqueue", "opcode" : 299, "operands" : [ { "kind" : "IdResultType" }, @@ -2778,6 +3169,7 @@ }, { "opname" : "OpIsValidEvent", + "class" : "Device-Side_Enqueue", "opcode" : 300, "operands" : [ { "kind" : "IdResultType" }, @@ -2788,6 +3180,7 @@ }, { "opname" : "OpSetUserEventStatus", + "class" : "Device-Side_Enqueue", "opcode" : 301, "operands" : [ { "kind" : "IdRef", "name" : "'Event'" }, @@ -2797,6 +3190,7 @@ }, { "opname" : "OpCaptureEventProfilingInfo", + "class" : "Device-Side_Enqueue", "opcode" : 302, "operands" : [ { "kind" : "IdRef", "name" : "'Event'" }, @@ -2807,6 +3201,7 @@ }, { "opname" : "OpGetDefaultQueue", + "class" : "Device-Side_Enqueue", "opcode" : 303, "operands" : [ { "kind" : "IdResultType" }, @@ -2816,6 +3211,7 @@ }, { "opname" : "OpBuildNDRange", + "class" : "Device-Side_Enqueue", "opcode" : 304, "operands" : [ { "kind" : "IdResultType" }, @@ -2828,6 +3224,7 @@ }, { "opname" : "OpImageSparseSampleImplicitLod", + "class" : "Image", "opcode" : 305, "operands" : [ { "kind" : "IdResultType" }, @@ -2840,6 +3237,7 @@ }, { "opname" : "OpImageSparseSampleExplicitLod", + "class" : "Image", "opcode" : 306, "operands" : [ { "kind" : "IdResultType" }, @@ -2852,6 +3250,7 @@ }, { "opname" : "OpImageSparseSampleDrefImplicitLod", + "class" : "Image", "opcode" : 307, "operands" : [ { "kind" : "IdResultType" }, @@ -2865,6 +3264,7 @@ }, { "opname" : "OpImageSparseSampleDrefExplicitLod", + "class" : "Image", "opcode" : 308, "operands" : [ { "kind" : "IdResultType" }, @@ -2878,6 +3278,7 @@ }, { "opname" : "OpImageSparseSampleProjImplicitLod", + "class" : "Image", "opcode" : 309, "operands" : [ { "kind" : "IdResultType" }, @@ -2891,6 +3292,7 @@ }, { "opname" : "OpImageSparseSampleProjExplicitLod", + "class" : "Image", "opcode" : 310, "operands" : [ { "kind" : "IdResultType" }, @@ -2904,6 +3306,7 @@ }, { "opname" : "OpImageSparseSampleProjDrefImplicitLod", + "class" : "Image", "opcode" : 311, "operands" : [ { "kind" : "IdResultType" }, @@ -2918,6 +3321,7 @@ }, { "opname" : "OpImageSparseSampleProjDrefExplicitLod", + "class" : "Image", "opcode" : 312, "operands" : [ { "kind" : "IdResultType" }, @@ -2932,6 +3336,7 @@ }, { "opname" : "OpImageSparseFetch", + "class" : "Image", "opcode" : 313, "operands" : [ { "kind" : "IdResultType" }, @@ -2944,6 +3349,7 @@ }, { "opname" : "OpImageSparseGather", + "class" : "Image", "opcode" : 314, "operands" : [ { "kind" : "IdResultType" }, @@ -2957,6 +3363,7 @@ }, { "opname" : "OpImageSparseDrefGather", + "class" : "Image", "opcode" : 315, "operands" : [ { "kind" : "IdResultType" }, @@ -2970,6 +3377,7 @@ }, { "opname" : "OpImageSparseTexelsResident", + "class" : "Image", "opcode" : 316, "operands" : [ { "kind" : "IdResultType" }, @@ -2980,32 +3388,36 @@ }, { "opname" : "OpNoLine", + "class" : "Debug", "opcode" : 317 }, { "opname" : "OpAtomicFlagTestAndSet", + "class" : "Atomic", "opcode" : 318, "operands" : [ { "kind" : "IdResultType" }, { "kind" : "IdResult" }, { "kind" : "IdRef", "name" : "'Pointer'" }, - { "kind" : "IdScope", "name" : "'Scope'" }, + { "kind" : "IdScope", "name" : "'Memory'" }, { "kind" : "IdMemorySemantics", "name" : "'Semantics'" } ], "capabilities" : [ "Kernel" ] }, { "opname" : "OpAtomicFlagClear", + "class" : "Atomic", "opcode" : 319, "operands" : [ { "kind" : "IdRef", "name" : "'Pointer'" }, - { "kind" : "IdScope", "name" : "'Scope'" }, + { "kind" : "IdScope", "name" : "'Memory'" }, { "kind" : "IdMemorySemantics", "name" : "'Semantics'" } ], "capabilities" : [ "Kernel" ] }, { "opname" : "OpImageSparseRead", + "class" : "Image", "opcode" : 320, "operands" : [ { "kind" : "IdResultType" }, @@ -3018,6 +3430,7 @@ }, { "opname" : "OpSizeOf", + "class" : "Miscellaneous", "opcode" : 321, "operands" : [ { "kind" : "IdResultType" }, @@ -3029,6 +3442,7 @@ }, { "opname" : "OpTypePipeStorage", + "class" : "Type-Declaration", "opcode" : 322, "operands" : [ { "kind" : "IdResult" } @@ -3038,6 +3452,7 @@ }, { "opname" : "OpConstantPipeStorage", + "class" : "Pipe", "opcode" : 323, "operands" : [ { "kind" : "IdResultType" }, @@ -3051,6 +3466,7 @@ }, { "opname" : "OpCreatePipeFromPipeStorage", + "class" : "Pipe", "opcode" : 324, "operands" : [ { "kind" : "IdResultType" }, @@ -3062,6 +3478,7 @@ }, { "opname" : "OpGetKernelLocalSizeForSubgroupCount", + "class" : "Device-Side_Enqueue", "opcode" : 325, "operands" : [ { "kind" : "IdResultType" }, @@ -3077,6 +3494,7 @@ }, { "opname" : "OpGetKernelMaxNumSubgroups", + "class" : "Device-Side_Enqueue", "opcode" : 326, "operands" : [ { "kind" : "IdResultType" }, @@ -3091,6 +3509,7 @@ }, { "opname" : "OpTypeNamedBarrier", + "class" : "Type-Declaration", "opcode" : 327, "operands" : [ { "kind" : "IdResult" } @@ -3100,6 +3519,7 @@ }, { "opname" : "OpNamedBarrierInitialize", + "class" : "Barrier", "opcode" : 328, "operands" : [ { "kind" : "IdResultType" }, @@ -3111,6 +3531,7 @@ }, { "opname" : "OpMemoryNamedBarrier", + "class" : "Barrier", "opcode" : 329, "operands" : [ { "kind" : "IdRef", "name" : "'Named Barrier'" }, @@ -3122,6 +3543,7 @@ }, { "opname" : "OpModuleProcessed", + "class" : "Debug", "opcode" : 330, "operands" : [ { "kind" : "LiteralString", "name" : "'Process'" } @@ -3130,6 +3552,7 @@ }, { "opname" : "OpExecutionModeId", + "class" : "Mode-Setting", "opcode" : 331, "operands" : [ { "kind" : "IdRef", "name" : "'Entry Point'" }, @@ -3139,6 +3562,7 @@ }, { "opname" : "OpDecorateId", + "class" : "Annotation", "opcode" : 332, "operands" : [ { "kind" : "IdRef", "name" : "'Target'" }, @@ -3149,6 +3573,7 @@ }, { "opname" : "OpGroupNonUniformElect", + "class" : "Non-Uniform", "opcode" : 333, "operands" : [ { "kind" : "IdResultType" }, @@ -3160,6 +3585,7 @@ }, { "opname" : "OpGroupNonUniformAll", + "class" : "Non-Uniform", "opcode" : 334, "operands" : [ { "kind" : "IdResultType" }, @@ -3172,6 +3598,7 @@ }, { "opname" : "OpGroupNonUniformAny", + "class" : "Non-Uniform", "opcode" : 335, "operands" : [ { "kind" : "IdResultType" }, @@ -3184,6 +3611,7 @@ }, { "opname" : "OpGroupNonUniformAllEqual", + "class" : "Non-Uniform", "opcode" : 336, "operands" : [ { "kind" : "IdResultType" }, @@ -3196,6 +3624,7 @@ }, { "opname" : "OpGroupNonUniformBroadcast", + "class" : "Non-Uniform", "opcode" : 337, "operands" : [ { "kind" : "IdResultType" }, @@ -3209,6 +3638,7 @@ }, { "opname" : "OpGroupNonUniformBroadcastFirst", + "class" : "Non-Uniform", "opcode" : 338, "operands" : [ { "kind" : "IdResultType" }, @@ -3221,6 +3651,7 @@ }, { "opname" : "OpGroupNonUniformBallot", + "class" : "Non-Uniform", "opcode" : 339, "operands" : [ { "kind" : "IdResultType" }, @@ -3233,6 +3664,7 @@ }, { "opname" : "OpGroupNonUniformInverseBallot", + "class" : "Non-Uniform", "opcode" : 340, "operands" : [ { "kind" : "IdResultType" }, @@ -3245,6 +3677,7 @@ }, { "opname" : "OpGroupNonUniformBallotBitExtract", + "class" : "Non-Uniform", "opcode" : 341, "operands" : [ { "kind" : "IdResultType" }, @@ -3258,6 +3691,7 @@ }, { "opname" : "OpGroupNonUniformBallotBitCount", + "class" : "Non-Uniform", "opcode" : 342, "operands" : [ { "kind" : "IdResultType" }, @@ -3271,6 +3705,7 @@ }, { "opname" : "OpGroupNonUniformBallotFindLSB", + "class" : "Non-Uniform", "opcode" : 343, "operands" : [ { "kind" : "IdResultType" }, @@ -3283,6 +3718,7 @@ }, { "opname" : "OpGroupNonUniformBallotFindMSB", + "class" : "Non-Uniform", "opcode" : 344, "operands" : [ { "kind" : "IdResultType" }, @@ -3295,6 +3731,7 @@ }, { "opname" : "OpGroupNonUniformShuffle", + "class" : "Non-Uniform", "opcode" : 345, "operands" : [ { "kind" : "IdResultType" }, @@ -3308,6 +3745,7 @@ }, { "opname" : "OpGroupNonUniformShuffleXor", + "class" : "Non-Uniform", "opcode" : 346, "operands" : [ { "kind" : "IdResultType" }, @@ -3321,6 +3759,7 @@ }, { "opname" : "OpGroupNonUniformShuffleUp", + "class" : "Non-Uniform", "opcode" : 347, "operands" : [ { "kind" : "IdResultType" }, @@ -3334,6 +3773,7 @@ }, { "opname" : "OpGroupNonUniformShuffleDown", + "class" : "Non-Uniform", "opcode" : 348, "operands" : [ { "kind" : "IdResultType" }, @@ -3347,6 +3787,7 @@ }, { "opname" : "OpGroupNonUniformIAdd", + "class" : "Non-Uniform", "opcode" : 349, "operands" : [ { "kind" : "IdResultType" }, @@ -3356,11 +3797,12 @@ { "kind" : "IdRef", "name" : "'Value'" }, { "kind" : "IdRef", "name" : "'ClusterSize'", "quantifier" : "?" } ], - "capabilities" : [ "GroupNonUniformArithmetic", "GroupNonUniformClustered" ], + "capabilities" : [ "GroupNonUniformArithmetic", "GroupNonUniformClustered", "GroupNonUniformPartitionedNV" ], "version" : "1.3" }, { "opname" : "OpGroupNonUniformFAdd", + "class" : "Non-Uniform", "opcode" : 350, "operands" : [ { "kind" : "IdResultType" }, @@ -3370,11 +3812,12 @@ { "kind" : "IdRef", "name" : "'Value'" }, { "kind" : "IdRef", "name" : "'ClusterSize'", "quantifier" : "?" } ], - "capabilities" : [ "GroupNonUniformArithmetic", "GroupNonUniformClustered" ], + "capabilities" : [ "GroupNonUniformArithmetic", "GroupNonUniformClustered", "GroupNonUniformPartitionedNV" ], "version" : "1.3" }, { "opname" : "OpGroupNonUniformIMul", + "class" : "Non-Uniform", "opcode" : 351, "operands" : [ { "kind" : "IdResultType" }, @@ -3384,11 +3827,12 @@ { "kind" : "IdRef", "name" : "'Value'" }, { "kind" : "IdRef", "name" : "'ClusterSize'", "quantifier" : "?" } ], - "capabilities" : [ "GroupNonUniformArithmetic", "GroupNonUniformClustered" ], + "capabilities" : [ "GroupNonUniformArithmetic", "GroupNonUniformClustered", "GroupNonUniformPartitionedNV" ], "version" : "1.3" }, { "opname" : "OpGroupNonUniformFMul", + "class" : "Non-Uniform", "opcode" : 352, "operands" : [ { "kind" : "IdResultType" }, @@ -3398,11 +3842,12 @@ { "kind" : "IdRef", "name" : "'Value'" }, { "kind" : "IdRef", "name" : "'ClusterSize'", "quantifier" : "?" } ], - "capabilities" : [ "GroupNonUniformArithmetic", "GroupNonUniformClustered" ], + "capabilities" : [ "GroupNonUniformArithmetic", "GroupNonUniformClustered", "GroupNonUniformPartitionedNV" ], "version" : "1.3" }, { "opname" : "OpGroupNonUniformSMin", + "class" : "Non-Uniform", "opcode" : 353, "operands" : [ { "kind" : "IdResultType" }, @@ -3412,11 +3857,12 @@ { "kind" : "IdRef", "name" : "'Value'" }, { "kind" : "IdRef", "name" : "'ClusterSize'", "quantifier" : "?" } ], - "capabilities" : [ "GroupNonUniformArithmetic", "GroupNonUniformClustered" ], + "capabilities" : [ "GroupNonUniformArithmetic", "GroupNonUniformClustered", "GroupNonUniformPartitionedNV" ], "version" : "1.3" }, { "opname" : "OpGroupNonUniformUMin", + "class" : "Non-Uniform", "opcode" : 354, "operands" : [ { "kind" : "IdResultType" }, @@ -3426,11 +3872,12 @@ { "kind" : "IdRef", "name" : "'Value'" }, { "kind" : "IdRef", "name" : "'ClusterSize'", "quantifier" : "?" } ], - "capabilities" : [ "GroupNonUniformArithmetic", "GroupNonUniformClustered" ], + "capabilities" : [ "GroupNonUniformArithmetic", "GroupNonUniformClustered", "GroupNonUniformPartitionedNV" ], "version" : "1.3" }, { "opname" : "OpGroupNonUniformFMin", + "class" : "Non-Uniform", "opcode" : 355, "operands" : [ { "kind" : "IdResultType" }, @@ -3440,11 +3887,12 @@ { "kind" : "IdRef", "name" : "'Value'" }, { "kind" : "IdRef", "name" : "'ClusterSize'", "quantifier" : "?" } ], - "capabilities" : [ "GroupNonUniformArithmetic", "GroupNonUniformClustered" ], + "capabilities" : [ "GroupNonUniformArithmetic", "GroupNonUniformClustered", "GroupNonUniformPartitionedNV" ], "version" : "1.3" }, { "opname" : "OpGroupNonUniformSMax", + "class" : "Non-Uniform", "opcode" : 356, "operands" : [ { "kind" : "IdResultType" }, @@ -3454,11 +3902,12 @@ { "kind" : "IdRef", "name" : "'Value'" }, { "kind" : "IdRef", "name" : "'ClusterSize'", "quantifier" : "?" } ], - "capabilities" : [ "GroupNonUniformArithmetic", "GroupNonUniformClustered" ], + "capabilities" : [ "GroupNonUniformArithmetic", "GroupNonUniformClustered", "GroupNonUniformPartitionedNV" ], "version" : "1.3" }, { "opname" : "OpGroupNonUniformUMax", + "class" : "Non-Uniform", "opcode" : 357, "operands" : [ { "kind" : "IdResultType" }, @@ -3468,11 +3917,12 @@ { "kind" : "IdRef", "name" : "'Value'" }, { "kind" : "IdRef", "name" : "'ClusterSize'", "quantifier" : "?" } ], - "capabilities" : [ "GroupNonUniformArithmetic", "GroupNonUniformClustered" ], + "capabilities" : [ "GroupNonUniformArithmetic", "GroupNonUniformClustered", "GroupNonUniformPartitionedNV" ], "version" : "1.3" }, { "opname" : "OpGroupNonUniformFMax", + "class" : "Non-Uniform", "opcode" : 358, "operands" : [ { "kind" : "IdResultType" }, @@ -3482,11 +3932,12 @@ { "kind" : "IdRef", "name" : "'Value'" }, { "kind" : "IdRef", "name" : "'ClusterSize'", "quantifier" : "?" } ], - "capabilities" : [ "GroupNonUniformArithmetic", "GroupNonUniformClustered" ], + "capabilities" : [ "GroupNonUniformArithmetic", "GroupNonUniformClustered", "GroupNonUniformPartitionedNV" ], "version" : "1.3" }, { "opname" : "OpGroupNonUniformBitwiseAnd", + "class" : "Non-Uniform", "opcode" : 359, "operands" : [ { "kind" : "IdResultType" }, @@ -3496,11 +3947,12 @@ { "kind" : "IdRef", "name" : "'Value'" }, { "kind" : "IdRef", "name" : "'ClusterSize'", "quantifier" : "?" } ], - "capabilities" : [ "GroupNonUniformArithmetic", "GroupNonUniformClustered" ], + "capabilities" : [ "GroupNonUniformArithmetic", "GroupNonUniformClustered", "GroupNonUniformPartitionedNV" ], "version" : "1.3" }, { "opname" : "OpGroupNonUniformBitwiseOr", + "class" : "Non-Uniform", "opcode" : 360, "operands" : [ { "kind" : "IdResultType" }, @@ -3510,11 +3962,12 @@ { "kind" : "IdRef", "name" : "'Value'" }, { "kind" : "IdRef", "name" : "'ClusterSize'", "quantifier" : "?" } ], - "capabilities" : [ "GroupNonUniformArithmetic", "GroupNonUniformClustered" ], + "capabilities" : [ "GroupNonUniformArithmetic", "GroupNonUniformClustered", "GroupNonUniformPartitionedNV" ], "version" : "1.3" }, { "opname" : "OpGroupNonUniformBitwiseXor", + "class" : "Non-Uniform", "opcode" : 361, "operands" : [ { "kind" : "IdResultType" }, @@ -3524,11 +3977,12 @@ { "kind" : "IdRef", "name" : "'Value'" }, { "kind" : "IdRef", "name" : "'ClusterSize'", "quantifier" : "?" } ], - "capabilities" : [ "GroupNonUniformArithmetic", "GroupNonUniformClustered" ], + "capabilities" : [ "GroupNonUniformArithmetic", "GroupNonUniformClustered", "GroupNonUniformPartitionedNV" ], "version" : "1.3" }, { "opname" : "OpGroupNonUniformLogicalAnd", + "class" : "Non-Uniform", "opcode" : 362, "operands" : [ { "kind" : "IdResultType" }, @@ -3538,11 +3992,12 @@ { "kind" : "IdRef", "name" : "'Value'" }, { "kind" : "IdRef", "name" : "'ClusterSize'", "quantifier" : "?" } ], - "capabilities" : [ "GroupNonUniformArithmetic", "GroupNonUniformClustered" ], + "capabilities" : [ "GroupNonUniformArithmetic", "GroupNonUniformClustered", "GroupNonUniformPartitionedNV" ], "version" : "1.3" }, { "opname" : "OpGroupNonUniformLogicalOr", + "class" : "Non-Uniform", "opcode" : 363, "operands" : [ { "kind" : "IdResultType" }, @@ -3552,11 +4007,12 @@ { "kind" : "IdRef", "name" : "'Value'" }, { "kind" : "IdRef", "name" : "'ClusterSize'", "quantifier" : "?" } ], - "capabilities" : [ "GroupNonUniformArithmetic", "GroupNonUniformClustered" ], + "capabilities" : [ "GroupNonUniformArithmetic", "GroupNonUniformClustered", "GroupNonUniformPartitionedNV" ], "version" : "1.3" }, { "opname" : "OpGroupNonUniformLogicalXor", + "class" : "Non-Uniform", "opcode" : 364, "operands" : [ { "kind" : "IdResultType" }, @@ -3566,11 +4022,12 @@ { "kind" : "IdRef", "name" : "'Value'" }, { "kind" : "IdRef", "name" : "'ClusterSize'", "quantifier" : "?" } ], - "capabilities" : [ "GroupNonUniformArithmetic", "GroupNonUniformClustered" ], + "capabilities" : [ "GroupNonUniformArithmetic", "GroupNonUniformClustered", "GroupNonUniformPartitionedNV" ], "version" : "1.3" }, { "opname" : "OpGroupNonUniformQuadBroadcast", + "class" : "Non-Uniform", "opcode" : 365, "operands" : [ { "kind" : "IdResultType" }, @@ -3584,6 +4041,7 @@ }, { "opname" : "OpGroupNonUniformQuadSwap", + "class" : "Non-Uniform", "opcode" : 366, "operands" : [ { "kind" : "IdResultType" }, @@ -3595,8 +4053,57 @@ "capabilities" : [ "GroupNonUniformQuad" ], "version" : "1.3" }, + { + "opname" : "OpCopyLogical", + "class" : "Composite", + "opcode" : 400, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Operand'" } + ], + "version" : "1.4" + }, + { + "opname" : "OpPtrEqual", + "class" : "Memory", + "opcode" : 401, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Operand 1'" }, + { "kind" : "IdRef", "name" : "'Operand 2'" } + ], + "version" : "1.4" + }, + { + "opname" : "OpPtrNotEqual", + "class" : "Memory", + "opcode" : 402, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Operand 1'" }, + { "kind" : "IdRef", "name" : "'Operand 2'" } + ], + "version" : "1.4" + }, + { + "opname" : "OpPtrDiff", + "class" : "Memory", + "opcode" : 403, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Operand 1'" }, + { "kind" : "IdRef", "name" : "'Operand 2'" } + ], + "capabilities" : [ "Addresses", "VariablePointers", "VariablePointersStorageBuffer" ], + "version" : "1.4" + }, { "opname" : "OpSubgroupBallotKHR", + "class" : "Group", "opcode" : 4421, "operands" : [ { "kind" : "IdResultType" }, @@ -3609,6 +4116,7 @@ }, { "opname" : "OpSubgroupFirstInvocationKHR", + "class" : "Group", "opcode" : 4422, "operands" : [ { "kind" : "IdResultType" }, @@ -3621,6 +4129,7 @@ }, { "opname" : "OpSubgroupAllKHR", + "class" : "Group", "opcode" : 4428, "operands" : [ { "kind" : "IdResultType" }, @@ -3635,6 +4144,7 @@ }, { "opname" : "OpSubgroupAnyKHR", + "class" : "Group", "opcode" : 4429, "operands" : [ { "kind" : "IdResultType" }, @@ -3649,6 +4159,7 @@ }, { "opname" : "OpSubgroupAllEqualKHR", + "class" : "Group", "opcode" : 4430, "operands" : [ { "kind" : "IdResultType" }, @@ -3663,6 +4174,7 @@ }, { "opname" : "OpSubgroupReadInvocationKHR", + "class" : "Group", "opcode" : 4432, "operands" : [ { "kind" : "IdResultType" }, @@ -3676,6 +4188,7 @@ }, { "opname" : "OpGroupIAddNonUniformAMD", + "class" : "Group", "opcode" : 5000, "operands" : [ { "kind" : "IdResultType" }, @@ -3690,6 +4203,7 @@ }, { "opname" : "OpGroupFAddNonUniformAMD", + "class" : "Group", "opcode" : 5001, "operands" : [ { "kind" : "IdResultType" }, @@ -3704,6 +4218,7 @@ }, { "opname" : "OpGroupFMinNonUniformAMD", + "class" : "Group", "opcode" : 5002, "operands" : [ { "kind" : "IdResultType" }, @@ -3718,6 +4233,7 @@ }, { "opname" : "OpGroupUMinNonUniformAMD", + "class" : "Group", "opcode" : 5003, "operands" : [ { "kind" : "IdResultType" }, @@ -3732,6 +4248,7 @@ }, { "opname" : "OpGroupSMinNonUniformAMD", + "class" : "Group", "opcode" : 5004, "operands" : [ { "kind" : "IdResultType" }, @@ -3746,6 +4263,7 @@ }, { "opname" : "OpGroupFMaxNonUniformAMD", + "class" : "Group", "opcode" : 5005, "operands" : [ { "kind" : "IdResultType" }, @@ -3760,6 +4278,7 @@ }, { "opname" : "OpGroupUMaxNonUniformAMD", + "class" : "Group", "opcode" : 5006, "operands" : [ { "kind" : "IdResultType" }, @@ -3774,6 +4293,7 @@ }, { "opname" : "OpGroupSMaxNonUniformAMD", + "class" : "Group", "opcode" : 5007, "operands" : [ { "kind" : "IdResultType" }, @@ -3788,6 +4308,7 @@ }, { "opname" : "OpFragmentMaskFetchAMD", + "class" : "Reserved", "opcode" : 5011, "operands" : [ { "kind" : "IdResultType" }, @@ -3801,6 +4322,7 @@ }, { "opname" : "OpFragmentFetchAMD", + "class" : "Reserved", "opcode" : 5012, "operands" : [ { "kind" : "IdResultType" }, @@ -3813,8 +4335,252 @@ "extensions" : [ "SPV_AMD_shader_fragment_mask" ], "version" : "None" }, + { + "opname" : "OpReadClockKHR", + "class" : "Reserved", + "opcode" : 5056, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdScope", "name" : "'Execution'" } + ], + "capabilities" : [ "ShaderClockKHR" ], + "extensions" : [ "SPV_KHR_shader_clock" ], + "version" : "None" + }, + { + "opname" : "OpImageSampleFootprintNV", + "class" : "Image", + "opcode" : 5283, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Sampled Image'" }, + { "kind" : "IdRef", "name" : "'Coordinate'" }, + { "kind" : "IdRef", "name" : "'Granularity'" }, + { "kind" : "IdRef", "name" : "'Coarse'" }, + { "kind" : "ImageOperands", "quantifier" : "?" } + ], + "capabilities" : [ "ImageFootprintNV" ], + "extensions" : [ "SPV_NV_shader_image_footprint" ], + "version" : "None" + }, + { + "opname" : "OpGroupNonUniformPartitionNV", + "class" : "Non-Uniform", + "opcode" : 5296, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Value'" } + ], + "capabilities" : [ "GroupNonUniformPartitionedNV" ], + "extensions" : [ "SPV_NV_shader_subgroup_partitioned" ], + "version" : "None" + }, + { + "opname" : "OpWritePackedPrimitiveIndices4x8NV", + "class" : "Reserved", + "opcode" : 5299, + "operands" : [ + { "kind" : "IdRef", "name" : "'Index Offset'" }, + { "kind" : "IdRef", "name" : "'Packed Indices'" } + ], + "capabilities" : [ "MeshShadingNV" ], + "extensions" : [ "SPV_NV_mesh_shader" ], + "version" : "None" + }, + { + "opname" : "OpReportIntersectionNV", + "class" : "Reserved", + "opcode" : 5334, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Hit'" }, + { "kind" : "IdRef", "name" : "'HitKind'" } + ], + "capabilities" : [ "RayTracingNV" ], + "extensions" : [ "SPV_NV_ray_tracing" ], + "version" : "None" + }, + { + "opname" : "OpIgnoreIntersectionNV", + "class" : "Reserved", + "opcode" : 5335, + + "capabilities" : [ "RayTracingNV" ], + "extensions" : [ "SPV_NV_ray_tracing" ], + "version" : "None" + }, + { + "opname" : "OpTerminateRayNV", + "class" : "Reserved", + "opcode" : 5336, + + "capabilities" : [ "RayTracingNV" ], + "extensions" : [ "SPV_NV_ray_tracing" ], + "version" : "None" + }, + { + "opname" : "OpTraceNV", + "class" : "Reserved", + "opcode" : 5337, + "operands" : [ + + { "kind" : "IdRef", "name" : "'Accel'" }, + { "kind" : "IdRef", "name" : "'Ray Flags'" }, + { "kind" : "IdRef", "name" : "'Cull Mask'" }, + { "kind" : "IdRef", "name" : "'SBT Offset'" }, + { "kind" : "IdRef", "name" : "'SBT Stride'" }, + { "kind" : "IdRef", "name" : "'Miss Index'" }, + { "kind" : "IdRef", "name" : "'Ray Origin'" }, + { "kind" : "IdRef", "name" : "'Ray Tmin'" }, + { "kind" : "IdRef", "name" : "'Ray Direction'" }, + { "kind" : "IdRef", "name" : "'Ray Tmax'" }, + { "kind" : "IdRef", "name" : "'PayloadId'" } + ], + "capabilities" : [ "RayTracingNV" ], + "extensions" : [ "SPV_NV_ray_tracing" ], + "version" : "None" + }, + { + "opname" : "OpTypeAccelerationStructureNV", + "class" : "Reserved", + "opcode" : 5341, + "operands" : [ + { "kind" : "IdResult" } + ], + "capabilities" : [ "RayTracingNV" ], + "extensions" : [ "SPV_NV_ray_tracing" ], + "version" : "None" + }, + { + "opname" : "OpExecuteCallableNV", + "class" : "Reserved", + "opcode" : 5344, + "operands" : [ + + { "kind" : "IdRef", "name" : "'SBT Index'" }, + { "kind" : "IdRef", "name" : "'Callable DataId'" } + ], + "capabilities" : [ "RayTracingNV" ], + "extensions" : [ "SPV_NV_ray_tracing" ], + "version" : "None" + }, + { + "opname" : "OpTypeCooperativeMatrixNV", + "class" : "Reserved", + "opcode" : 5358, + "operands" : [ + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Component Type'" }, + { "kind" : "IdScope", "name" : "'Execution'" }, + { "kind" : "IdRef", "name" : "'Rows'" }, + { "kind" : "IdRef", "name" : "'Columns'" } + ], + "capabilities" : [ "CooperativeMatrixNV" ], + "extensions" : [ "SPV_NV_cooperative_matrix" ], + "version" : "None" + }, + { + "opname" : "OpCooperativeMatrixLoadNV", + "class" : "Reserved", + "opcode" : 5359, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Pointer'" }, + { "kind" : "IdRef", "name" : "'Stride'" }, + { "kind" : "IdRef", "name" : "'Column Major'" }, + { "kind" : "MemoryAccess", "quantifier" : "?" } + ], + "capabilities" : [ "CooperativeMatrixNV" ], + "extensions" : [ "SPV_NV_cooperative_matrix" ], + "version" : "None" + }, + { + "opname" : "OpCooperativeMatrixStoreNV", + "class" : "Reserved", + "opcode" : 5360, + "operands" : [ + { "kind" : "IdRef", "name" : "'Pointer'" }, + { "kind" : "IdRef", "name" : "'Object'" }, + { "kind" : "IdRef", "name" : "'Stride'" }, + { "kind" : "IdRef", "name" : "'Column Major'" }, + { "kind" : "MemoryAccess", "quantifier" : "?" } + ], + "capabilities" : [ "CooperativeMatrixNV" ], + "extensions" : [ "SPV_NV_cooperative_matrix" ], + "version" : "None" + }, + { + "opname" : "OpCooperativeMatrixMulAddNV", + "class" : "Reserved", + "opcode" : 5361, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'A'" }, + { "kind" : "IdRef", "name" : "'B'" }, + { "kind" : "IdRef", "name" : "'C'" } + ], + "capabilities" : [ "CooperativeMatrixNV" ], + "extensions" : [ "SPV_NV_cooperative_matrix" ], + "version" : "None" + }, + { + "opname" : "OpCooperativeMatrixLengthNV", + "class" : "Reserved", + "opcode" : 5362, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Type'" } + ], + "capabilities" : [ "CooperativeMatrixNV" ], + "extensions" : [ "SPV_NV_cooperative_matrix" ], + "version" : "None" + }, + { + "opname" : "OpBeginInvocationInterlockEXT", + "class" : "Reserved", + "opcode" : 5364, + "capabilities" : [ "FragmentShaderSampleInterlockEXT", "FragmentShaderPixelInterlockEXT", "FragmentShaderShadingRateInterlockEXT" ], + "extensions" : [ "SPV_EXT_fragment_shader_interlock" ], + "version" : "None" + }, + { + "opname" : "OpEndInvocationInterlockEXT", + "class" : "Reserved", + "opcode" : 5365, + "capabilities" : [ "FragmentShaderSampleInterlockEXT", "FragmentShaderPixelInterlockEXT", "FragmentShaderShadingRateInterlockEXT" ], + "extensions" : [ "SPV_EXT_fragment_shader_interlock" ], + "version" : "None" + }, + { + "opname" : "OpDemoteToHelperInvocationEXT", + "class" : "Reserved", + "opcode" : 5380, + "capabilities" : [ "DemoteToHelperInvocationEXT" ], + "extensions" : [ "SPV_EXT_demote_to_helper_invocation" ], + "version" : "None" + }, + { + "opname" : "OpIsHelperInvocationEXT", + "class" : "Reserved", + "opcode" : 5381, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" } + ], + "capabilities" : [ "DemoteToHelperInvocationEXT" ], + "extensions" : [ "SPV_EXT_demote_to_helper_invocation" ], + "version" : "None" + }, { "opname" : "OpSubgroupShuffleINTEL", + "class" : "Group", "opcode" : 5571, "operands" : [ { "kind" : "IdResultType" }, @@ -3827,6 +4593,7 @@ }, { "opname" : "OpSubgroupShuffleDownINTEL", + "class" : "Group", "opcode" : 5572, "operands" : [ { "kind" : "IdResultType" }, @@ -3840,6 +4607,7 @@ }, { "opname" : "OpSubgroupShuffleUpINTEL", + "class" : "Group", "opcode" : 5573, "operands" : [ { "kind" : "IdResultType" }, @@ -3853,6 +4621,7 @@ }, { "opname" : "OpSubgroupShuffleXorINTEL", + "class" : "Group", "opcode" : 5574, "operands" : [ { "kind" : "IdResultType" }, @@ -3865,6 +4634,7 @@ }, { "opname" : "OpSubgroupBlockReadINTEL", + "class" : "Group", "opcode" : 5575, "operands" : [ { "kind" : "IdResultType" }, @@ -3876,6 +4646,7 @@ }, { "opname" : "OpSubgroupBlockWriteINTEL", + "class" : "Group", "opcode" : 5576, "operands" : [ { "kind" : "IdRef", "name" : "'Ptr'" }, @@ -3886,6 +4657,7 @@ }, { "opname" : "OpSubgroupImageBlockReadINTEL", + "class" : "Group", "opcode" : 5577, "operands" : [ { "kind" : "IdResultType" }, @@ -3898,6 +4670,7 @@ }, { "opname" : "OpSubgroupImageBlockWriteINTEL", + "class" : "Group", "opcode" : 5578, "operands" : [ { "kind" : "IdRef", "name" : "'Image'" }, @@ -3908,17 +4681,239 @@ "version" : "None" }, { - "opname" : "OpDecorateStringGOOGLE", + "opname" : "OpSubgroupImageMediaBlockReadINTEL", + "class" : "Group", + "opcode" : 5580, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Image'" }, + { "kind" : "IdRef", "name" : "'Coordinate'" }, + { "kind" : "IdRef", "name" : "'Width'" }, + { "kind" : "IdRef", "name" : "'Height'" } + ], + "capabilities" : [ "SubgroupImageMediaBlockIOINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupImageMediaBlockWriteINTEL", + "class" : "Group", + "opcode" : 5581, + "operands" : [ + { "kind" : "IdRef", "name" : "'Image'" }, + { "kind" : "IdRef", "name" : "'Coordinate'" }, + { "kind" : "IdRef", "name" : "'Width'" }, + { "kind" : "IdRef", "name" : "'Height'" }, + { "kind" : "IdRef", "name" : "'Data'" } + ], + "capabilities" : [ "SubgroupImageMediaBlockIOINTEL" ], + "version" : "None" + }, + { + "opname" : "OpUCountLeadingZerosINTEL", + "class" : "Reserved", + "opcode" : 5585, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Operand'" } + ], + "capabilities" : [ "IntegerFunctions2INTEL" ], + "version" : "None" + }, + { + "opname" : "OpUCountTrailingZerosINTEL", + "class" : "Reserved", + "opcode" : 5586, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Operand'" } + ], + "capabilities" : [ "IntegerFunctions2INTEL" ], + "version" : "None" + }, + { + "opname" : "OpAbsISubINTEL", + "class" : "Reserved", + "opcode" : 5587, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Operand 1'" }, + { "kind" : "IdRef", "name" : "'Operand 2'" } + ], + "capabilities" : [ "IntegerFunctions2INTEL" ], + "version" : "None" + }, + { + "opname" : "OpAbsUSubINTEL", + "class" : "Reserved", + "opcode" : 5588, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Operand 1'" }, + { "kind" : "IdRef", "name" : "'Operand 2'" } + ], + "capabilities" : [ "IntegerFunctions2INTEL" ], + "version" : "None" + }, + { + "opname" : "OpIAddSatINTEL", + "class" : "Reserved", + "opcode" : 5589, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Operand 1'" }, + { "kind" : "IdRef", "name" : "'Operand 2'" } + ], + "capabilities" : [ "IntegerFunctions2INTEL" ], + "version" : "None" + }, + { + "opname" : "OpUAddSatINTEL", + "class" : "Reserved", + "opcode" : 5590, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Operand 1'" }, + { "kind" : "IdRef", "name" : "'Operand 2'" } + ], + "capabilities" : [ "IntegerFunctions2INTEL" ], + "version" : "None" + }, + { + "opname" : "OpIAverageINTEL", + "class" : "Reserved", + "opcode" : 5591, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Operand 1'" }, + { "kind" : "IdRef", "name" : "'Operand 2'" } + ], + "capabilities" : [ "IntegerFunctions2INTEL" ], + "version" : "None" + }, + { + "opname" : "OpUAverageINTEL", + "class" : "Reserved", + "opcode" : 5592, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Operand 1'" }, + { "kind" : "IdRef", "name" : "'Operand 2'" } + ], + "capabilities" : [ "IntegerFunctions2INTEL" ], + "version" : "None" + }, + { + "opname" : "OpIAverageRoundedINTEL", + "class" : "Reserved", + "opcode" : 5593, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Operand 1'" }, + { "kind" : "IdRef", "name" : "'Operand 2'" } + ], + "capabilities" : [ "IntegerFunctions2INTEL" ], + "version" : "None" + }, + { + "opname" : "OpUAverageRoundedINTEL", + "class" : "Reserved", + "opcode" : 5594, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Operand 1'" }, + { "kind" : "IdRef", "name" : "'Operand 2'" } + ], + "capabilities" : [ "IntegerFunctions2INTEL" ], + "version" : "None" + }, + { + "opname" : "OpISubSatINTEL", + "class" : "Reserved", + "opcode" : 5595, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Operand 1'" }, + { "kind" : "IdRef", "name" : "'Operand 2'" } + ], + "capabilities" : [ "IntegerFunctions2INTEL" ], + "version" : "None" + }, + { + "opname" : "OpUSubSatINTEL", + "class" : "Reserved", + "opcode" : 5596, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Operand 1'" }, + { "kind" : "IdRef", "name" : "'Operand 2'" } + ], + "capabilities" : [ "IntegerFunctions2INTEL" ], + "version" : "None" + }, + { + "opname" : "OpIMul32x16INTEL", + "class" : "Reserved", + "opcode" : 5597, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Operand 1'" }, + { "kind" : "IdRef", "name" : "'Operand 2'" } + ], + "capabilities" : [ "IntegerFunctions2INTEL" ], + "version" : "None" + }, + { + "opname" : "OpUMul32x16INTEL", + "class" : "Reserved", + "opcode" : 5598, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Operand 1'" }, + { "kind" : "IdRef", "name" : "'Operand 2'" } + ], + "capabilities" : [ "IntegerFunctions2INTEL" ], + "version" : "None" + }, + { + "opname" : "OpDecorateString", + "class" : "Annotation", "opcode" : 5632, "operands" : [ { "kind" : "IdRef", "name" : "'Target'" }, { "kind" : "Decoration" } ], "extensions" : [ "SPV_GOOGLE_decorate_string", "SPV_GOOGLE_hlsl_functionality1" ], - "version" : "None" + "version" : "1.4" }, { - "opname" : "OpMemberDecorateStringGOOGLE", + "opname" : "OpDecorateStringGOOGLE", + "class" : "Annotation", + "opcode" : 5632, + "operands" : [ + { "kind" : "IdRef", "name" : "'Target'" }, + { "kind" : "Decoration" } + ], + "extensions" : [ "SPV_GOOGLE_decorate_string", "SPV_GOOGLE_hlsl_functionality1" ], + "version" : "1.4" + }, + { + "opname" : "OpMemberDecorateString", + "class" : "Annotation", "opcode" : 5633, "operands" : [ { "kind" : "IdRef", "name" : "'Struct Type'" }, @@ -3926,18 +4921,1535 @@ { "kind" : "Decoration" } ], "extensions" : [ "SPV_GOOGLE_decorate_string", "SPV_GOOGLE_hlsl_functionality1" ], - "version" : "None" + "version" : "1.4" }, { - "opname" : "OpGroupNonUniformPartitionNV", - "opcode" : 5296, + "opname" : "OpMemberDecorateStringGOOGLE", + "class" : "Annotation", + "opcode" : 5633, + "operands" : [ + { "kind" : "IdRef", "name" : "'Struct Type'" }, + { "kind" : "LiteralInteger", "name" : "'Member'" }, + { "kind" : "Decoration" } + ], + "extensions" : [ "SPV_GOOGLE_decorate_string", "SPV_GOOGLE_hlsl_functionality1" ], + "version" : "1.4" + }, + { + "opname" : "OpVmeImageINTEL", + "class" : "@exclude", + "opcode" : 5699, "operands" : [ { "kind" : "IdResultType" }, { "kind" : "IdResult" }, - { "kind" : "IdRef", "name" : "'Value'" } + { "kind" : "IdRef", "name" : "'Image Type'" }, + { "kind" : "IdRef", "name" : "'Sampler'" } ], - "capabilities" : [ "GroupNonUniformPartitionedNV" ], - "extensions" : [ "SPV_NV_shader_subgroup_partitioned" ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpTypeVmeImageINTEL", + "class" : "@exclude", + "opcode" : 5700, + "operands" : [ + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Image Type'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpTypeAvcImePayloadINTEL", + "class" : "@exclude", + "opcode" : 5701, + "operands" : [ + { "kind" : "IdResult" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpTypeAvcRefPayloadINTEL", + "class" : "@exclude", + "opcode" : 5702, + "operands" : [ + { "kind" : "IdResult" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpTypeAvcSicPayloadINTEL", + "class" : "@exclude", + "opcode" : 5703, + "operands" : [ + { "kind" : "IdResult" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpTypeAvcMcePayloadINTEL", + "class" : "@exclude", + "opcode" : 5704, + "operands" : [ + { "kind" : "IdResult" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpTypeAvcMceResultINTEL", + "class" : "@exclude", + "opcode" : 5705, + "operands" : [ + { "kind" : "IdResult" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpTypeAvcImeResultINTEL", + "class" : "@exclude", + "opcode" : 5706, + "operands" : [ + { "kind" : "IdResult" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpTypeAvcImeResultSingleReferenceStreamoutINTEL", + "class" : "@exclude", + "opcode" : 5707, + "operands" : [ + { "kind" : "IdResult" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpTypeAvcImeResultDualReferenceStreamoutINTEL", + "class" : "@exclude", + "opcode" : 5708, + "operands" : [ + { "kind" : "IdResult" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpTypeAvcImeSingleReferenceStreaminINTEL", + "class" : "@exclude", + "opcode" : 5709, + "operands" : [ + { "kind" : "IdResult" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpTypeAvcImeDualReferenceStreaminINTEL", + "class" : "@exclude", + "opcode" : 5710, + "operands" : [ + { "kind" : "IdResult" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpTypeAvcRefResultINTEL", + "class" : "@exclude", + "opcode" : 5711, + "operands" : [ + { "kind" : "IdResult" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpTypeAvcSicResultINTEL", + "class" : "@exclude", + "opcode" : 5712, + "operands" : [ + { "kind" : "IdResult" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcMceGetDefaultInterBaseMultiReferencePenaltyINTEL", + "class" : "@exclude", + "opcode" : 5713, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Slice Type'" }, + { "kind" : "IdRef", "name" : "'Qp'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcMceSetInterBaseMultiReferencePenaltyINTEL", + "class" : "@exclude", + "opcode" : 5714, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Reference Base Penalty'" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcMceGetDefaultInterShapePenaltyINTEL", + "class" : "@exclude", + "opcode" : 5715, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Slice Type'" }, + { "kind" : "IdRef", "name" : "'Qp'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcMceSetInterShapePenaltyINTEL", + "class" : "@exclude", + "opcode" : 5716, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Packed Shape Penalty'" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcMceGetDefaultInterDirectionPenaltyINTEL", + "class" : "@exclude", + "opcode" : 5717, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Slice Type'" }, + { "kind" : "IdRef", "name" : "'Qp'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcMceSetInterDirectionPenaltyINTEL", + "class" : "@exclude", + "opcode" : 5718, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Direction Cost'" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcMceGetDefaultIntraLumaShapePenaltyINTEL", + "class" : "@exclude", + "opcode" : 5719, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Slice Type'" }, + { "kind" : "IdRef", "name" : "'Qp'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL", "SubgroupAvcMotionEstimationIntraINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcMceGetDefaultInterMotionVectorCostTableINTEL", + "class" : "@exclude", + "opcode" : 5720, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Slice Type'" }, + { "kind" : "IdRef", "name" : "'Qp'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcMceGetDefaultHighPenaltyCostTableINTEL", + "class" : "@exclude", + "opcode" : 5721, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcMceGetDefaultMediumPenaltyCostTableINTEL", + "class" : "@exclude", + "opcode" : 5722, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcMceGetDefaultLowPenaltyCostTableINTEL", + "class" : "@exclude", + "opcode" : 5723, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcMceSetMotionVectorCostFunctionINTEL", + "class" : "@exclude", + "opcode" : 5724, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Packed Cost Center Delta'" }, + { "kind" : "IdRef", "name" : "'Packed Cost Table'" }, + { "kind" : "IdRef", "name" : "'Cost Precision'" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcMceGetDefaultIntraLumaModePenaltyINTEL", + "class" : "@exclude", + "opcode" : 5725, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Slice Type'" }, + { "kind" : "IdRef", "name" : "'Qp'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL", "SubgroupAvcMotionEstimationIntraINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcMceGetDefaultNonDcLumaIntraPenaltyINTEL", + "class" : "@exclude", + "opcode" : 5726, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL", "SubgroupAvcMotionEstimationIntraINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcMceGetDefaultIntraChromaModeBasePenaltyINTEL", + "class" : "@exclude", + "opcode" : 5727, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL", "SubgroupAvcMotionEstimationChromaINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcMceSetAcOnlyHaarINTEL", + "class" : "@exclude", + "opcode" : 5728, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcMceSetSourceInterlacedFieldPolarityINTEL", + "class" : "@exclude", + "opcode" : 5729, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Source Field Polarity'" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcMceSetSingleReferenceInterlacedFieldPolarityINTEL", + "class" : "@exclude", + "opcode" : 5730, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Reference Field Polarity'" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcMceSetDualReferenceInterlacedFieldPolaritiesINTEL", + "class" : "@exclude", + "opcode" : 5731, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Forward Reference Field Polarity'" }, + { "kind" : "IdRef", "name" : "'Backward Reference Field Polarity'" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcMceConvertToImePayloadINTEL", + "class" : "@exclude", + "opcode" : 5732, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcMceConvertToImeResultINTEL", + "class" : "@exclude", + "opcode" : 5733, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcMceConvertToRefPayloadINTEL", + "class" : "@exclude", + "opcode" : 5734, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcMceConvertToRefResultINTEL", + "class" : "@exclude", + "opcode" : 5735, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcMceConvertToSicPayloadINTEL", + "class" : "@exclude", + "opcode" : 5736, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcMceConvertToSicResultINTEL", + "class" : "@exclude", + "opcode" : 5737, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcMceGetMotionVectorsINTEL", + "class" : "@exclude", + "opcode" : 5738, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcMceGetInterDistortionsINTEL", + "class" : "@exclude", + "opcode" : 5739, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcMceGetBestInterDistortionsINTEL", + "class" : "@exclude", + "opcode" : 5740, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcMceGetInterMajorShapeINTEL", + "class" : "@exclude", + "opcode" : 5741, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcMceGetInterMinorShapeINTEL", + "class" : "@exclude", + "opcode" : 5742, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcMceGetInterDirectionsINTEL", + "class" : "@exclude", + "opcode" : 5743, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcMceGetInterMotionVectorCountINTEL", + "class" : "@exclude", + "opcode" : 5744, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcMceGetInterReferenceIdsINTEL", + "class" : "@exclude", + "opcode" : 5745, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcMceGetInterReferenceInterlacedFieldPolaritiesINTEL", + "class" : "@exclude", + "opcode" : 5746, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Packed Reference Ids'" }, + { "kind" : "IdRef", "name" : "'Packed Reference Parameter Field Polarities'" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcImeInitializeINTEL", + "class" : "@exclude", + "opcode" : 5747, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Src Coord'" }, + { "kind" : "IdRef", "name" : "'Partition Mask'" }, + { "kind" : "IdRef", "name" : "'SAD Adjustment'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcImeSetSingleReferenceINTEL", + "class" : "@exclude", + "opcode" : 5748, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Ref Offset'" }, + { "kind" : "IdRef", "name" : "'Search Window Config'" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcImeSetDualReferenceINTEL", + "class" : "@exclude", + "opcode" : 5749, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Fwd Ref Offset'" }, + { "kind" : "IdRef", "name" : "'Bwd Ref Offset'" }, + { "kind" : "IdRef", "name" : "'id> Search Window Config'" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcImeRefWindowSizeINTEL", + "class" : "@exclude", + "opcode" : 5750, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Search Window Config'" }, + { "kind" : "IdRef", "name" : "'Dual Ref'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcImeAdjustRefOffsetINTEL", + "class" : "@exclude", + "opcode" : 5751, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Ref Offset'" }, + { "kind" : "IdRef", "name" : "'Src Coord'" }, + { "kind" : "IdRef", "name" : "'Ref Window Size'" }, + { "kind" : "IdRef", "name" : "'Image Size'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcImeConvertToMcePayloadINTEL", + "class" : "@exclude", + "opcode" : 5752, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcImeSetMaxMotionVectorCountINTEL", + "class" : "@exclude", + "opcode" : 5753, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Max Motion Vector Count'" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcImeSetUnidirectionalMixDisableINTEL", + "class" : "@exclude", + "opcode" : 5754, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcImeSetEarlySearchTerminationThresholdINTEL", + "class" : "@exclude", + "opcode" : 5755, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Threshold'" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcImeSetWeightedSadINTEL", + "class" : "@exclude", + "opcode" : 5756, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Packed Sad Weights'" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcImeEvaluateWithSingleReferenceINTEL", + "class" : "@exclude", + "opcode" : 5757, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Src Image'" }, + { "kind" : "IdRef", "name" : "'Ref Image'" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcImeEvaluateWithDualReferenceINTEL", + "class" : "@exclude", + "opcode" : 5758, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Src Image'" }, + { "kind" : "IdRef", "name" : "'Fwd Ref Image'" }, + { "kind" : "IdRef", "name" : "'Bwd Ref Image'" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcImeEvaluateWithSingleReferenceStreaminINTEL", + "class" : "@exclude", + "opcode" : 5759, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Src Image'" }, + { "kind" : "IdRef", "name" : "'Ref Image'" }, + { "kind" : "IdRef", "name" : "'Payload'" }, + { "kind" : "IdRef", "name" : "'Streamin Components'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcImeEvaluateWithDualReferenceStreaminINTEL", + "class" : "@exclude", + "opcode" : 5760, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Src Image'" }, + { "kind" : "IdRef", "name" : "'Fwd Ref Image'" }, + { "kind" : "IdRef", "name" : "'Bwd Ref Image'" }, + { "kind" : "IdRef", "name" : "'Payload'" }, + { "kind" : "IdRef", "name" : "'Streamin Components'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcImeEvaluateWithSingleReferenceStreamoutINTEL", + "class" : "@exclude", + "opcode" : 5761, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Src Image'" }, + { "kind" : "IdRef", "name" : "'Ref Image'" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcImeEvaluateWithDualReferenceStreamoutINTEL", + "class" : "@exclude", + "opcode" : 5762, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Src Image'" }, + { "kind" : "IdRef", "name" : "'Fwd Ref Image'" }, + { "kind" : "IdRef", "name" : "'Bwd Ref Image'" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcImeEvaluateWithSingleReferenceStreaminoutINTEL", + "class" : "@exclude", + "opcode" : 5763, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Src Image'" }, + { "kind" : "IdRef", "name" : "'Ref Image'" }, + { "kind" : "IdRef", "name" : "'Payload'" }, + { "kind" : "IdRef", "name" : "'Streamin Components'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcImeEvaluateWithDualReferenceStreaminoutINTEL", + "class" : "@exclude", + "opcode" : 5764, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Src Image'" }, + { "kind" : "IdRef", "name" : "'Fwd Ref Image'" }, + { "kind" : "IdRef", "name" : "'Bwd Ref Image'" }, + { "kind" : "IdRef", "name" : "'Payload'" }, + { "kind" : "IdRef", "name" : "'Streamin Components'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcImeConvertToMceResultINTEL", + "class" : "@exclude", + "opcode" : 5765, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcImeGetSingleReferenceStreaminINTEL", + "class" : "@exclude", + "opcode" : 5766, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcImeGetDualReferenceStreaminINTEL", + "class" : "@exclude", + "opcode" : 5767, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcImeStripSingleReferenceStreamoutINTEL", + "class" : "@exclude", + "opcode" : 5768, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcImeStripDualReferenceStreamoutINTEL", + "class" : "@exclude", + "opcode" : 5769, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeMotionVectorsINTEL", + "class" : "@exclude", + "opcode" : 5770, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Payload'" }, + { "kind" : "IdRef", "name" : "'Major Shape'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeDistortionsINTEL", + "class" : "@exclude", + "opcode" : 5771, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Payload'" }, + { "kind" : "IdRef", "name" : "'Major Shape'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeReferenceIdsINTEL", + "class" : "@exclude", + "opcode" : 5772, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Payload'" }, + { "kind" : "IdRef", "name" : "'Major Shape'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeMotionVectorsINTEL", + "class" : "@exclude", + "opcode" : 5773, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Payload'" }, + { "kind" : "IdRef", "name" : "'Major Shape'" }, + { "kind" : "IdRef", "name" : "'Direction'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeDistortionsINTEL", + "class" : "@exclude", + "opcode" : 5774, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Payload'" }, + { "kind" : "IdRef", "name" : "'Major Shape'" }, + { "kind" : "IdRef", "name" : "'Direction'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeReferenceIdsINTEL", + "class" : "@exclude", + "opcode" : 5775, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Payload'" }, + { "kind" : "IdRef", "name" : "'Major Shape'" }, + { "kind" : "IdRef", "name" : "'Direction'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcImeGetBorderReachedINTEL", + "class" : "@exclude", + "opcode" : 5776, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Image Select'" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcImeGetTruncatedSearchIndicationINTEL", + "class" : "@exclude", + "opcode" : 5777, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcImeGetUnidirectionalEarlySearchTerminationINTEL", + "class" : "@exclude", + "opcode" : 5778, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcImeGetWeightingPatternMinimumMotionVectorINTEL", + "class" : "@exclude", + "opcode" : 5779, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcImeGetWeightingPatternMinimumDistortionINTEL", + "class" : "@exclude", + "opcode" : 5780, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcFmeInitializeINTEL", + "class" : "@exclude", + "opcode" : 5781, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Src Coord'" }, + { "kind" : "IdRef", "name" : "'Motion Vectors'" }, + { "kind" : "IdRef", "name" : "'Major Shapes'" }, + { "kind" : "IdRef", "name" : "'Minor Shapes'" }, + { "kind" : "IdRef", "name" : "'Direction'" }, + { "kind" : "IdRef", "name" : "'Pixel Resolution'" }, + { "kind" : "IdRef", "name" : "'Sad Adjustment'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcBmeInitializeINTEL", + "class" : "@exclude", + "opcode" : 5782, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Src Coord'" }, + { "kind" : "IdRef", "name" : "'Motion Vectors'" }, + { "kind" : "IdRef", "name" : "'Major Shapes'" }, + { "kind" : "IdRef", "name" : "'Minor Shapes'" }, + { "kind" : "IdRef", "name" : "'Direction'" }, + { "kind" : "IdRef", "name" : "'Pixel Resolution'" }, + { "kind" : "IdRef", "name" : "'Bidirectional Weight'" }, + { "kind" : "IdRef", "name" : "'Sad Adjustment'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcRefConvertToMcePayloadINTEL", + "class" : "@exclude", + "opcode" : 5783, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcRefSetBidirectionalMixDisableINTEL", + "class" : "@exclude", + "opcode" : 5784, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcRefSetBilinearFilterEnableINTEL", + "class" : "@exclude", + "opcode" : 5785, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcRefEvaluateWithSingleReferenceINTEL", + "class" : "@exclude", + "opcode" : 5786, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Src Image'" }, + { "kind" : "IdRef", "name" : "'Ref Image'" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcRefEvaluateWithDualReferenceINTEL", + "class" : "@exclude", + "opcode" : 5787, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Src Image'" }, + { "kind" : "IdRef", "name" : "'Fwd Ref Image'" }, + { "kind" : "IdRef", "name" : "'Bwd Ref Image'" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcRefEvaluateWithMultiReferenceINTEL", + "class" : "@exclude", + "opcode" : 5788, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Src Image'" }, + { "kind" : "IdRef", "name" : "'Packed Reference Ids'" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcRefEvaluateWithMultiReferenceInterlacedINTEL", + "class" : "@exclude", + "opcode" : 5789, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Src Image'" }, + { "kind" : "IdRef", "name" : "'Packed Reference Ids'" }, + { "kind" : "IdRef", "name" : "'Packed Reference Field Polarities'" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcRefConvertToMceResultINTEL", + "class" : "@exclude", + "opcode" : 5790, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcSicInitializeINTEL", + "class" : "@exclude", + "opcode" : 5791, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Src Coord'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcSicConfigureSkcINTEL", + "class" : "@exclude", + "opcode" : 5792, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Skip Block Partition Type'" }, + { "kind" : "IdRef", "name" : "'Skip Motion Vector Mask'" }, + { "kind" : "IdRef", "name" : "'Motion Vectors'" }, + { "kind" : "IdRef", "name" : "'Bidirectional Weight'" }, + { "kind" : "IdRef", "name" : "'Sad Adjustment'" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcSicConfigureIpeLumaINTEL", + "class" : "@exclude", + "opcode" : 5793, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Luma Intra Partition Mask'" }, + { "kind" : "IdRef", "name" : "'Intra Neighbour Availabilty'" }, + { "kind" : "IdRef", "name" : "'Left Edge Luma Pixels'" }, + { "kind" : "IdRef", "name" : "'Upper Left Corner Luma Pixel'" }, + { "kind" : "IdRef", "name" : "'Upper Edge Luma Pixels'" }, + { "kind" : "IdRef", "name" : "'Upper Right Edge Luma Pixels'" }, + { "kind" : "IdRef", "name" : "'Sad Adjustment'" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL", "SubgroupAvcMotionEstimationIntraINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcSicConfigureIpeLumaChromaINTEL", + "class" : "@exclude", + "opcode" : 5794, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Luma Intra Partition Mask'" }, + { "kind" : "IdRef", "name" : "'Intra Neighbour Availabilty'" }, + { "kind" : "IdRef", "name" : "'Left Edge Luma Pixels'" }, + { "kind" : "IdRef", "name" : "'Upper Left Corner Luma Pixel'" }, + { "kind" : "IdRef", "name" : "'Upper Edge Luma Pixels'" }, + { "kind" : "IdRef", "name" : "'Upper Right Edge Luma Pixels'" }, + { "kind" : "IdRef", "name" : "'Left Edge Chroma Pixels'" }, + { "kind" : "IdRef", "name" : "'Upper Left Corner Chroma Pixel'" }, + { "kind" : "IdRef", "name" : "'Upper Edge Chroma Pixels'" }, + { "kind" : "IdRef", "name" : "'Sad Adjustment'" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL", "SubgroupAvcMotionEstimationChromaINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcSicGetMotionVectorMaskINTEL", + "class" : "@exclude", + "opcode" : 5795, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Skip Block Partition Type'" }, + { "kind" : "IdRef", "name" : "'Direction'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcSicConvertToMcePayloadINTEL", + "class" : "@exclude", + "opcode" : 5796, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcSicSetIntraLumaShapePenaltyINTEL", + "class" : "@exclude", + "opcode" : 5797, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Packed Shape Penalty'" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcSicSetIntraLumaModeCostFunctionINTEL", + "class" : "@exclude", + "opcode" : 5798, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Luma Mode Penalty'" }, + { "kind" : "IdRef", "name" : "'Luma Packed Neighbor Modes'" }, + { "kind" : "IdRef", "name" : "'Luma Packed Non Dc Penalty'" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL", "SubgroupAvcMotionEstimationIntraINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcSicSetIntraChromaModeCostFunctionINTEL", + "class" : "@exclude", + "opcode" : 5799, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Chroma Mode Base Penalty'" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL", "SubgroupAvcMotionEstimationChromaINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcSicSetBilinearFilterEnableINTEL", + "class" : "@exclude", + "opcode" : 5800, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcSicSetSkcForwardTransformEnableINTEL", + "class" : "@exclude", + "opcode" : 5801, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Packed Sad Coefficients'" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcSicSetBlockBasedRawSkipSadINTEL", + "class" : "@exclude", + "opcode" : 5802, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Block Based Skip Type'" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcSicEvaluateIpeINTEL", + "class" : "@exclude", + "opcode" : 5803, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Src Image'" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL", "SubgroupAvcMotionEstimationIntraINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcSicEvaluateWithSingleReferenceINTEL", + "class" : "@exclude", + "opcode" : 5804, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Src Image'" }, + { "kind" : "IdRef", "name" : "'Ref Image'" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcSicEvaluateWithDualReferenceINTEL", + "class" : "@exclude", + "opcode" : 5805, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Src Image'" }, + { "kind" : "IdRef", "name" : "'Fwd Ref Image'" }, + { "kind" : "IdRef", "name" : "'Bwd Ref Image'" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcSicEvaluateWithMultiReferenceINTEL", + "class" : "@exclude", + "opcode" : 5806, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Src Image'" }, + { "kind" : "IdRef", "name" : "'Packed Reference Ids'" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcSicEvaluateWithMultiReferenceInterlacedINTEL", + "class" : "@exclude", + "opcode" : 5807, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Src Image'" }, + { "kind" : "IdRef", "name" : "'Packed Reference Ids'" }, + { "kind" : "IdRef", "name" : "'Packed Reference Field Polarities'" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcSicConvertToMceResultINTEL", + "class" : "@exclude", + "opcode" : 5808, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcSicGetIpeLumaShapeINTEL", + "class" : "@exclude", + "opcode" : 5809, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL", "SubgroupAvcMotionEstimationIntraINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcSicGetBestIpeLumaDistortionINTEL", + "class" : "@exclude", + "opcode" : 5810, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL", "SubgroupAvcMotionEstimationIntraINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcSicGetBestIpeChromaDistortionINTEL", + "class" : "@exclude", + "opcode" : 5811, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcSicGetPackedIpeLumaModesINTEL", + "class" : "@exclude", + "opcode" : 5812, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL", "SubgroupAvcMotionEstimationIntraINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcSicGetIpeChromaModeINTEL", + "class" : "@exclude", + "opcode" : 5813, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL", "SubgroupAvcMotionEstimationChromaINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcSicGetPackedSkcLumaCountThresholdINTEL", + "class" : "@exclude", + "opcode" : 5814, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL", "SubgroupAvcMotionEstimationIntraINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcSicGetPackedSkcLumaSumThresholdINTEL", + "class" : "@exclude", + "opcode" : 5815, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL", "SubgroupAvcMotionEstimationIntraINTEL" ], + "version" : "None" + }, + { + "opname" : "OpSubgroupAvcSicGetInterRawSadsINTEL", + "class" : "@exclude", + "opcode" : 5816, + "operands" : [ + { "kind" : "IdResultType" }, + { "kind" : "IdResult" }, + { "kind" : "IdRef", "name" : "'Payload'" } + ], + "capabilities" : [ "SubgroupAvcMotionEstimationINTEL" ], "version" : "None" } ], @@ -4010,6 +6522,80 @@ "parameters" : [ { "kind" : "IdRef" } ] + }, + { + "enumerant" : "MakeTexelAvailable", + "value" : "0x0100", + "capabilities" : [ "VulkanMemoryModel" ], + "parameters" : [ + { "kind" : "IdScope" } + ], + "version" : "1.5" + }, + { + "enumerant" : "MakeTexelAvailableKHR", + "value" : "0x0100", + "capabilities" : [ "VulkanMemoryModel" ], + "parameters" : [ + { "kind" : "IdScope" } + ], + "extensions" : [ "SPV_KHR_vulkan_memory_model" ], + "version" : "1.5" + }, + { + "enumerant" : "MakeTexelVisible", + "value" : "0x0200", + "capabilities" : [ "VulkanMemoryModel" ], + "parameters" : [ + { "kind" : "IdScope" } + ], + "version" : "1.5" + }, + { + "enumerant" : "MakeTexelVisibleKHR", + "value" : "0x0200", + "capabilities" : [ "VulkanMemoryModel" ], + "parameters" : [ + { "kind" : "IdScope" } + ], + "extensions" : [ "SPV_KHR_vulkan_memory_model" ], + "version" : "1.5" + }, + { + "enumerant" : "NonPrivateTexel", + "value" : "0x0400", + "capabilities" : [ "VulkanMemoryModel" ], + "version" : "1.5" + }, + { + "enumerant" : "NonPrivateTexelKHR", + "value" : "0x0400", + "capabilities" : [ "VulkanMemoryModel" ], + "extensions" : [ "SPV_KHR_vulkan_memory_model" ], + "version" : "1.5" + }, + { + "enumerant" : "VolatileTexel", + "value" : "0x0800", + "capabilities" : [ "VulkanMemoryModel" ], + "version" : "1.5" + }, + { + "enumerant" : "VolatileTexelKHR", + "value" : "0x0800", + "capabilities" : [ "VulkanMemoryModel" ], + "extensions" : [ "SPV_KHR_vulkan_memory_model" ], + "version" : "1.5" + }, + { + "enumerant" : "SignExtend", + "value" : "0x1000", + "version" : "1.4" + }, + { + "enumerant" : "ZeroExtend", + "value" : "0x2000", + "version" : "1.4" } ] }, @@ -4094,6 +6680,46 @@ { "kind" : "LiteralInteger" } ], "version" : "1.1" + }, + { + "enumerant" : "MinIterations", + "value" : "0x0010", + "parameters" : [ + { "kind" : "LiteralInteger" } + ], + "version" : "1.4" + }, + { + "enumerant" : "MaxIterations", + "value" : "0x0020", + "parameters" : [ + { "kind" : "LiteralInteger" } + ], + "version" : "1.4" + }, + { + "enumerant" : "IterationMultiple", + "value" : "0x0040", + "parameters" : [ + { "kind" : "LiteralInteger" } + ], + "version" : "1.4" + }, + { + "enumerant" : "PeelCount", + "value" : "0x0080", + "parameters" : [ + { "kind" : "LiteralInteger" } + ], + "version" : "1.4" + }, + { + "enumerant" : "PartialCount", + "value" : "0x0100", + "parameters" : [ + { "kind" : "LiteralInteger" } + ], + "version" : "1.4" } ] }, @@ -4176,6 +6802,52 @@ { "enumerant" : "ImageMemory", "value" : "0x0800" + }, + { + "enumerant" : "OutputMemory", + "value" : "0x1000", + "capabilities" : [ "VulkanMemoryModel" ], + "version" : "1.5" + }, + { + "enumerant" : "OutputMemoryKHR", + "value" : "0x1000", + "capabilities" : [ "VulkanMemoryModel" ], + "extensions" : [ "SPV_KHR_vulkan_memory_model" ], + "version" : "1.5" + }, + { + "enumerant" : "MakeAvailable", + "value" : "0x2000", + "capabilities" : [ "VulkanMemoryModel" ], + "version" : "1.5" + }, + { + "enumerant" : "MakeAvailableKHR", + "value" : "0x2000", + "capabilities" : [ "VulkanMemoryModel" ], + "extensions" : [ "SPV_KHR_vulkan_memory_model" ], + "version" : "1.5" + }, + { + "enumerant" : "MakeVisible", + "value" : "0x4000", + "capabilities" : [ "VulkanMemoryModel" ], + "version" : "1.5" + }, + { + "enumerant" : "MakeVisibleKHR", + "value" : "0x4000", + "capabilities" : [ "VulkanMemoryModel" ], + "extensions" : [ "SPV_KHR_vulkan_memory_model" ], + "version" : "1.5" + }, + { + "enumerant" : "Volatile", + "value" : "0x8000", + "capabilities" : [ "VulkanMemoryModel" ], + "extensions" : [ "SPV_KHR_vulkan_memory_model" ], + "version" : "1.5" } ] }, @@ -4201,6 +6873,57 @@ { "enumerant" : "Nontemporal", "value" : "0x0004" + }, + { + "enumerant" : "MakePointerAvailable", + "value" : "0x0008", + "parameters" : [ + { "kind" : "IdScope" } + ], + "capabilities" : [ "VulkanMemoryModel" ], + "version" : "1.5" + }, + { + "enumerant" : "MakePointerAvailableKHR", + "value" : "0x0008", + "parameters" : [ + { "kind" : "IdScope" } + ], + "capabilities" : [ "VulkanMemoryModel" ], + "extensions" : [ "SPV_KHR_vulkan_memory_model" ], + "version" : "1.5" + }, + { + "enumerant" : "MakePointerVisible", + "value" : "0x0010", + "parameters" : [ + { "kind" : "IdScope" } + ], + "capabilities" : [ "VulkanMemoryModel" ], + "version" : "1.5" + }, + { + "enumerant" : "MakePointerVisibleKHR", + "value" : "0x0010", + "parameters" : [ + { "kind" : "IdScope" } + ], + "capabilities" : [ "VulkanMemoryModel" ], + "extensions" : [ "SPV_KHR_vulkan_memory_model" ], + "version" : "1.5" + }, + { + "enumerant" : "NonPrivatePointer", + "value" : "0x0020", + "capabilities" : [ "VulkanMemoryModel" ], + "version" : "1.5" + }, + { + "enumerant" : "NonPrivatePointerKHR", + "value" : "0x0020", + "capabilities" : [ "VulkanMemoryModel" ], + "extensions" : [ "SPV_KHR_vulkan_memory_model" ], + "version" : "1.5" } ] }, @@ -4287,6 +7010,54 @@ "enumerant" : "Kernel", "value" : 6, "capabilities" : [ "Kernel" ] + }, + { + "enumerant" : "TaskNV", + "value" : 5267, + "capabilities" : [ "MeshShadingNV" ], + "version" : "None" + }, + { + "enumerant" : "MeshNV", + "value" : 5268, + "capabilities" : [ "MeshShadingNV" ], + "version" : "None" + }, + { + "enumerant" : "RayGenerationNV", + "value" : 5313, + "capabilities" : [ "RayTracingNV" ], + "version" : "None" + }, + { + "enumerant" : "IntersectionNV", + "value" : 5314, + "capabilities" : [ "RayTracingNV" ], + "version" : "None" + }, + { + "enumerant" : "AnyHitNV", + "value" : 5315, + "capabilities" : [ "RayTracingNV" ], + "version" : "None" + }, + { + "enumerant" : "ClosestHitNV", + "value" : 5316, + "capabilities" : [ "RayTracingNV" ], + "version" : "None" + }, + { + "enumerant" : "MissNV", + "value" : 5317, + "capabilities" : [ "RayTracingNV" ], + "version" : "None" + }, + { + "enumerant" : "CallableNV", + "value" : 5318, + "capabilities" : [ "RayTracingNV" ], + "version" : "None" } ] }, @@ -4307,6 +7078,20 @@ "enumerant" : "Physical64", "value" : 2, "capabilities" : [ "Addresses" ] + }, + { + "enumerant" : "PhysicalStorageBuffer64", + "value" : 5348, + "extensions" : [ "SPV_EXT_physical_storage_buffer", "SPV_KHR_physical_storage_buffer" ], + "capabilities" : [ "PhysicalStorageBufferAddresses" ], + "version" : "1.5" + }, + { + "enumerant" : "PhysicalStorageBuffer64EXT", + "value" : 5348, + "extensions" : [ "SPV_EXT_physical_storage_buffer" ], + "capabilities" : [ "PhysicalStorageBufferAddresses" ], + "version" : "1.5" } ] }, @@ -4328,6 +7113,19 @@ "enumerant" : "OpenCL", "value" : 2, "capabilities" : [ "Kernel" ] + }, + { + "enumerant" : "Vulkan", + "value" : 3, + "capabilities" : [ "VulkanMemoryModel" ], + "version" : "1.5" + }, + { + "enumerant" : "VulkanKHR", + "value" : 3, + "capabilities" : [ "VulkanMemoryModel" ], + "extensions" : [ "SPV_KHR_vulkan_memory_model" ], + "version" : "1.5" } ] }, @@ -4475,7 +7273,7 @@ { "enumerant" : "OutputVertices", "value" : 26, - "capabilities" : [ "Geometry", "Tessellation" ], + "capabilities" : [ "Geometry", "Tessellation", "MeshShadingNV" ], "parameters" : [ { "kind" : "LiteralInteger", "name" : "'Vertex count'" } ] @@ -4483,7 +7281,7 @@ { "enumerant" : "OutputPoints", "value" : 27, - "capabilities" : [ "Geometry" ] + "capabilities" : [ "Geometry", "MeshShadingNV" ] }, { "enumerant" : "OutputLineStrip", @@ -4573,12 +7371,142 @@ "extensions" : [ "SPV_KHR_post_depth_coverage" ], "version" : "None" }, + { + "enumerant" : "DenormPreserve", + "value" : 4459, + "capabilities" : [ "DenormPreserve" ], + "extensions" : [ "SPV_KHR_float_controls" ], + "parameters" : [ + { "kind" : "LiteralInteger", "name" : "'Target Width'" } + ], + "version" : "1.4" + }, + { + "enumerant" : "DenormFlushToZero", + "value" : 4460, + "capabilities" : [ "DenormFlushToZero" ], + "extensions" : [ "SPV_KHR_float_controls" ], + "parameters" : [ + { "kind" : "LiteralInteger", "name" : "'Target Width'" } + ], + "version" : "1.4" + }, + { + "enumerant" : "SignedZeroInfNanPreserve", + "value" : 4461, + "capabilities" : [ "SignedZeroInfNanPreserve" ], + "extensions" : [ "SPV_KHR_float_controls" ], + "parameters" : [ + { "kind" : "LiteralInteger", "name" : "'Target Width'" } + ], + "version" : "1.4" + }, + { + "enumerant" : "RoundingModeRTE", + "value" : 4462, + "capabilities" : [ "RoundingModeRTE" ], + "extensions" : [ "SPV_KHR_float_controls" ], + "parameters" : [ + { "kind" : "LiteralInteger", "name" : "'Target Width'" } + ], + "version" : "1.4" + }, + { + "enumerant" : "RoundingModeRTZ", + "value" : 4463, + "capabilities" : [ "RoundingModeRTZ" ], + "extensions" : [ "SPV_KHR_float_controls" ], + "parameters" : [ + { "kind" : "LiteralInteger", "name" : "'Target Width'" } + ], + "version" : "1.4" + }, { "enumerant" : "StencilRefReplacingEXT", "value" : 5027, "capabilities" : [ "StencilExportEXT" ], "extensions" : [ "SPV_EXT_shader_stencil_export" ], "version" : "None" + }, + { + "enumerant" : "OutputLinesNV", + "value" : 5269, + "capabilities" : [ "MeshShadingNV" ], + "extensions" : [ "SPV_NV_mesh_shader" ], + "version" : "None" + }, + { + "enumerant" : "OutputPrimitivesNV", + "value" : 5270, + "capabilities" : [ "MeshShadingNV" ], + "parameters" : [ + { "kind" : "LiteralInteger", "name" : "'Primitive count'" } + ], + "extensions" : [ "SPV_NV_mesh_shader" ], + "version" : "None" + }, + { + "enumerant" : "DerivativeGroupQuadsNV", + "value" : 5289, + "capabilities" : [ "ComputeDerivativeGroupQuadsNV" ], + "extensions" : [ "SPV_NV_compute_shader_derivatives" ], + "version" : "None" + }, + { + "enumerant" : "DerivativeGroupLinearNV", + "value" : 5290, + "capabilities" : [ "ComputeDerivativeGroupLinearNV" ], + "extensions" : [ "SPV_NV_compute_shader_derivatives" ], + "version" : "None" + }, + { + "enumerant" : "OutputTrianglesNV", + "value" : 5298, + "capabilities" : [ "MeshShadingNV" ], + "extensions" : [ "SPV_NV_mesh_shader" ], + "version" : "None" + }, + { + "enumerant" : "PixelInterlockOrderedEXT", + "value" : 5366, + "capabilities" : [ "FragmentShaderPixelInterlockEXT" ], + "extensions" : [ "SPV_EXT_fragment_shader_interlock" ], + "version" : "None" + }, + { + "enumerant" : "PixelInterlockUnorderedEXT", + "value" : 5367, + "capabilities" : [ "FragmentShaderPixelInterlockEXT" ], + "extensions" : [ "SPV_EXT_fragment_shader_interlock" ], + "version" : "None" + }, + { + "enumerant" : "SampleInterlockOrderedEXT", + "value" : 5368, + "capabilities" : [ "FragmentShaderSampleInterlockEXT" ], + "extensions" : [ "SPV_EXT_fragment_shader_interlock" ], + "version" : "None" + }, + { + "enumerant" : "SampleInterlockUnorderedEXT", + "value" : 5369, + "capabilities" : [ "FragmentShaderSampleInterlockEXT" ], + "extensions" : [ "SPV_EXT_fragment_shader_interlock" ], + "version" : "None" + }, + { + "enumerant" : "ShadingRateInterlockOrderedEXT", + "value" : 5370, + "capabilities" : [ "FragmentShaderShadingRateInterlockEXT" ], + "extensions" : [ "SPV_EXT_fragment_shader_interlock" ], + "version" : "None" + }, + { + "enumerant" : "ShadingRateInterlockUnorderedEXT", + "value" : 5371, + "capabilities" : [ "FragmentShaderShadingRateInterlockEXT" ], + "extensions" : [ "SPV_EXT_fragment_shader_interlock" ], + "version" : "None" } ] }, @@ -4649,6 +7577,62 @@ ], "capabilities" : [ "Shader" ], "version" : "1.3" + }, + { + "enumerant" : "CallableDataNV", + "value" : 5328, + "extensions" : [ "SPV_NV_ray_tracing" ], + "capabilities" : [ "RayTracingNV" ], + "version" : "None" + }, + { + "enumerant" : "IncomingCallableDataNV", + "value" : 5329, + "extensions" : [ "SPV_NV_ray_tracing" ], + "capabilities" : [ "RayTracingNV" ], + "version" : "None" + }, + { + "enumerant" : "RayPayloadNV", + "value" : 5338, + "extensions" : [ "SPV_NV_ray_tracing" ], + "capabilities" : [ "RayTracingNV" ], + "version" : "None" + }, + { + "enumerant" : "HitAttributeNV", + "value" : 5339, + "extensions" : [ "SPV_NV_ray_tracing" ], + "capabilities" : [ "RayTracingNV" ], + "version" : "None" + }, + { + "enumerant" : "IncomingRayPayloadNV", + "value" : 5342, + "extensions" : [ "SPV_NV_ray_tracing" ], + "capabilities" : [ "RayTracingNV" ], + "version" : "None" + }, + { + "enumerant" : "ShaderRecordBufferNV", + "value" : 5343, + "extensions" : [ "SPV_NV_ray_tracing" ], + "capabilities" : [ "RayTracingNV" ], + "version" : "None" + }, + { + "enumerant" : "PhysicalStorageBuffer", + "value" : 5349, + "extensions" : [ "SPV_EXT_physical_storage_buffer", "SPV_KHR_physical_storage_buffer" ], + "capabilities" : [ "PhysicalStorageBufferAddresses" ], + "version" : "1.5" + }, + { + "enumerant" : "PhysicalStorageBufferEXT", + "value" : 5349, + "extensions" : [ "SPV_EXT_physical_storage_buffer" ], + "capabilities" : [ "PhysicalStorageBufferAddresses" ], + "version" : "1.5" } ] }, @@ -4659,11 +7643,12 @@ { "enumerant" : "1D", "value" : 0, - "capabilities" : [ "Sampled1D" ] + "capabilities" : [ "Sampled1D", "Image1D" ] }, { "enumerant" : "2D", - "value" : 1 + "value" : 1, + "capabilities" : [ "Shader", "Kernel", "ImageMSArray" ] }, { "enumerant" : "3D", @@ -4672,17 +7657,17 @@ { "enumerant" : "Cube", "value" : 3, - "capabilities" : [ "Shader" ] + "capabilities" : [ "Shader", "ImageCubeArray" ] }, { "enumerant" : "Rect", "value" : 4, - "capabilities" : [ "SampledRect" ] + "capabilities" : [ "SampledRect", "ImageRect" ] }, { "enumerant" : "Buffer", "value" : 5, - "capabilities" : [ "SampledBuffer" ] + "capabilities" : [ "SampledBuffer", "ImageBuffer" ] }, { "enumerant" : "SubpassData", @@ -5270,7 +8255,8 @@ { "enumerant" : "BufferBlock", "value" : 3, - "capabilities" : [ "Shader" ] + "capabilities" : [ "Shader" ], + "lastVersion" : "1.3" }, { "enumerant" : "RowMajor", @@ -5384,6 +8370,15 @@ "value" : 26, "capabilities" : [ "Shader" ] }, + { + "enumerant" : "UniformId", + "value" : 27, + "capabilities" : [ "Shader" ], + "parameters" : [ + { "kind" : "IdScope", "name" : "'Execution'" } + ], + "version" : "1.4" + }, { "enumerant" : "SaturatedConversion", "value" : 28, @@ -5541,6 +8536,18 @@ ], "version" : "1.2" }, + { + "enumerant" : "NoSignedWrap", + "value" : 4469, + "extensions" : [ "SPV_KHR_no_integer_wrap_decoration" ], + "version" : "1.4" + }, + { + "enumerant" : "NoUnsignedWrap", + "value" : 4470, + "extensions" : [ "SPV_KHR_no_integer_wrap_decoration" ], + "version" : "1.4" + }, { "enumerant" : "ExplicitInterpAMD", "value" : 4999, @@ -5577,10 +8584,82 @@ { "kind" : "LiteralInteger", "name" : "'Offset'" } ] }, + { + "enumerant" : "PerPrimitiveNV", + "value" : 5271, + "capabilities" : [ "MeshShadingNV" ], + "extensions" : [ "SPV_NV_mesh_shader" ], + "version" : "None" + }, + { + "enumerant" : "PerViewNV", + "value" : 5272, + "capabilities" : [ "MeshShadingNV" ], + "extensions" : [ "SPV_NV_mesh_shader" ], + "version" : "None" + }, + { + "enumerant" : "PerTaskNV", + "value" : 5273, + "capabilities" : [ "MeshShadingNV" ], + "extensions" : [ "SPV_NV_mesh_shader" ], + "version" : "None" + }, + { + "enumerant" : "PerVertexNV", + "value" : 5285, + "capabilities" : [ "FragmentBarycentricNV" ], + "extensions" : [ "SPV_NV_fragment_shader_barycentric" ], + "version" : "None" + }, + { + "enumerant" : "NonUniform", + "value" : 5300, + "capabilities" : [ "ShaderNonUniform" ], + "version" : "1.5" + }, { "enumerant" : "NonUniformEXT", "value" : 5300, - "capabilities" : [ "ShaderNonUniformEXT" ] + "capabilities" : [ "ShaderNonUniform" ], + "extensions" : [ "SPV_EXT_descriptor_indexing" ], + "version" : "1.5" + }, + { + "enumerant" : "RestrictPointer", + "value" : 5355, + "capabilities" : [ "PhysicalStorageBufferAddresses" ], + "extensions" : [ "SPV_EXT_physical_storage_buffer", "SPV_KHR_physical_storage_buffer" ], + "version" : "1.5" + }, + { + "enumerant" : "RestrictPointerEXT", + "value" : 5355, + "capabilities" : [ "PhysicalStorageBufferAddresses" ], + "extensions" : [ "SPV_EXT_physical_storage_buffer" ], + "version" : "1.5" + }, + { + "enumerant" : "AliasedPointer", + "value" : 5356, + "capabilities" : [ "PhysicalStorageBufferAddresses" ], + "extensions" : [ "SPV_EXT_physical_storage_buffer", "SPV_KHR_physical_storage_buffer" ], + "version" : "1.5" + }, + { + "enumerant" : "AliasedPointerEXT", + "value" : 5356, + "capabilities" : [ "PhysicalStorageBufferAddresses" ], + "extensions" : [ "SPV_EXT_physical_storage_buffer" ], + "version" : "1.5" + }, + { + "enumerant" : "CounterBuffer", + "value" : 5634, + "parameters" : [ + { "kind" : "IdRef", "name" : "'Counter Buffer'" } + ], + "version" : "1.4" }, { "enumerant" : "HlslCounterBufferGOOGLE", @@ -5591,6 +8670,14 @@ "extensions" : [ "SPV_GOOGLE_hlsl_functionality1" ], "version" : "None" }, + { + "enumerant" : "UserSemantic", + "value" : 5635, + "parameters" : [ + { "kind" : "LiteralString", "name" : "'Semantic'" } + ], + "version" : "1.4" + }, { "enumerant" : "HlslSemanticGOOGLE", "value" : 5635, @@ -5599,6 +8686,15 @@ ], "extensions" : [ "SPV_GOOGLE_hlsl_functionality1" ], "version" : "None" + }, + { + "enumerant" : "UserTypeGOOGLE", + "value" : 5636, + "parameters" : [ + { "kind" : "LiteralString", "name" : "'User Type'" } + ], + "extensions" : [ "SPV_GOOGLE_user_type" ], + "version" : "None" } ] }, @@ -5639,7 +8735,7 @@ { "enumerant" : "PrimitiveId", "value" : 7, - "capabilities" : [ "Geometry", "Tessellation" ] + "capabilities" : [ "Geometry", "Tessellation", "RayTracingNV" ] }, { "enumerant" : "InvocationId", @@ -5649,12 +8745,12 @@ { "enumerant" : "Layer", "value" : 9, - "capabilities" : [ "Geometry" ] + "capabilities" : [ "Geometry", "ShaderLayer", "ShaderViewportIndexLayerEXT" ] }, { "enumerant" : "ViewportIndex", "value" : 10, - "capabilities" : [ "MultiViewport" ] + "capabilities" : [ "MultiViewport", "ShaderViewportIndex", "ShaderViewportIndexLayerEXT" ] }, { "enumerant" : "TessLevelOuter", @@ -5887,8 +8983,8 @@ { "enumerant" : "DrawIndex", "value" : 4426, - "capabilities" : [ "DrawParameters" ], - "extensions" : [ "SPV_KHR_shader_draw_parameters" ], + "capabilities" : [ "DrawParameters", "MeshShadingNV" ], + "extensions" : [ "SPV_KHR_shader_draw_parameters", "SPV_NV_mesh_shader" ], "version" : "1.3" }, { @@ -5957,7 +9053,8 @@ { "enumerant" : "ViewportMaskNV", "value" : 5253, - "capabilities" : [ "ShaderViewportMaskNV" ], + "capabilities" : [ "ShaderViewportMaskNV", "MeshShadingNV" ], + "extensions" : [ "SPV_NV_viewport_array2", "SPV_NV_mesh_shader" ], "version" : "None" }, { @@ -5977,13 +9074,15 @@ { "enumerant" : "PositionPerViewNV", "value" : 5261, - "capabilities" : [ "PerViewAttributesNV" ], + "capabilities" : [ "PerViewAttributesNV", "MeshShadingNV" ], + "extensions" : [ "SPV_NVX_multiview_per_view_attributes", "SPV_NV_mesh_shader" ], "version" : "None" }, { "enumerant" : "ViewportMaskPerViewNV", "value" : 5262, - "capabilities" : [ "PerViewAttributesNV" ], + "capabilities" : [ "PerViewAttributesNV", "MeshShadingNV" ], + "extensions" : [ "SPV_NVX_multiview_per_view_attributes", "SPV_NV_mesh_shader" ], "version" : "None" }, { @@ -5992,6 +9091,230 @@ "capabilities" : [ "FragmentFullyCoveredEXT" ], "extensions" : [ "SPV_EXT_fragment_fully_covered" ], "version" : "None" + }, + { + "enumerant" : "TaskCountNV", + "value" : 5274, + "capabilities" : [ "MeshShadingNV" ], + "extensions" : [ "SPV_NV_mesh_shader" ], + "version" : "None" + }, + { + "enumerant" : "PrimitiveCountNV", + "value" : 5275, + "capabilities" : [ "MeshShadingNV" ], + "extensions" : [ "SPV_NV_mesh_shader" ], + "version" : "None" + }, + { + "enumerant" : "PrimitiveIndicesNV", + "value" : 5276, + "capabilities" : [ "MeshShadingNV" ], + "extensions" : [ "SPV_NV_mesh_shader" ], + "version" : "None" + }, + { + "enumerant" : "ClipDistancePerViewNV", + "value" : 5277, + "capabilities" : [ "MeshShadingNV" ], + "extensions" : [ "SPV_NV_mesh_shader" ], + "version" : "None" + }, + { + "enumerant" : "CullDistancePerViewNV", + "value" : 5278, + "capabilities" : [ "MeshShadingNV" ], + "extensions" : [ "SPV_NV_mesh_shader" ], + "version" : "None" + }, + { + "enumerant" : "LayerPerViewNV", + "value" : 5279, + "capabilities" : [ "MeshShadingNV" ], + "extensions" : [ "SPV_NV_mesh_shader" ], + "version" : "None" + }, + { + "enumerant" : "MeshViewCountNV", + "value" : 5280, + "capabilities" : [ "MeshShadingNV" ], + "extensions" : [ "SPV_NV_mesh_shader" ], + "version" : "None" + }, + { + "enumerant" : "MeshViewIndicesNV", + "value" : 5281, + "capabilities" : [ "MeshShadingNV" ], + "extensions" : [ "SPV_NV_mesh_shader" ], + "version" : "None" + }, + { + "enumerant" : "BaryCoordNV", + "value" : 5286, + "capabilities" : [ "FragmentBarycentricNV" ], + "extensions" : [ "SPV_NV_fragment_shader_barycentric" ], + "version" : "None" + }, + { + "enumerant" : "BaryCoordNoPerspNV", + "value" : 5287, + "capabilities" : [ "FragmentBarycentricNV" ], + "extensions" : [ "SPV_NV_fragment_shader_barycentric" ], + "version" : "None" + }, + { + "enumerant" : "FragSizeEXT", + "value" : 5292 , + "capabilities" : [ "FragmentDensityEXT", "ShadingRateNV" ], + "extensions" : [ "SPV_EXT_fragment_invocation_density", "SPV_NV_shading_rate" ], + "version" : "None" + }, + { + "enumerant" : "FragmentSizeNV", + "value" : 5292 , + "capabilities" : [ "ShadingRateNV", "FragmentDensityEXT" ], + "extensions" : [ "SPV_NV_shading_rate", "SPV_EXT_fragment_invocation_density" ], + "version" : "None" + }, + { + "enumerant" : "FragInvocationCountEXT", + "value" : 5293, + "capabilities" : [ "FragmentDensityEXT", "ShadingRateNV" ], + "extensions" : [ "SPV_EXT_fragment_invocation_density", "SPV_NV_shading_rate" ], + "version" : "None" + }, + { + "enumerant" : "InvocationsPerPixelNV", + "value" : 5293, + "capabilities" : [ "ShadingRateNV", "FragmentDensityEXT" ], + "extensions" : [ "SPV_NV_shading_rate", "SPV_EXT_fragment_invocation_density" ], + "version" : "None" + }, + { + "enumerant" : "LaunchIdNV", + "value" : 5319, + "capabilities" : [ "RayTracingNV" ], + "extensions" : [ "SPV_NV_ray_tracing" ], + "version" : "None" + }, + { + "enumerant" : "LaunchSizeNV", + "value" : 5320, + "capabilities" : [ "RayTracingNV" ], + "extensions" : [ "SPV_NV_ray_tracing" ], + "version" : "None" + }, + { + "enumerant" : "WorldRayOriginNV", + "value" : 5321, + "capabilities" : [ "RayTracingNV" ], + "extensions" : [ "SPV_NV_ray_tracing" ], + "version" : "None" + }, + { + "enumerant" : "WorldRayDirectionNV", + "value" : 5322, + "capabilities" : [ "RayTracingNV" ], + "extensions" : [ "SPV_NV_ray_tracing" ], + "version" : "None" + }, + { + "enumerant" : "ObjectRayOriginNV", + "value" : 5323, + "capabilities" : [ "RayTracingNV" ], + "extensions" : [ "SPV_NV_ray_tracing" ], + "version" : "None" + }, + { + "enumerant" : "ObjectRayDirectionNV", + "value" : 5324, + "capabilities" : [ "RayTracingNV" ], + "extensions" : [ "SPV_NV_ray_tracing" ], + "version" : "None" + }, + { + "enumerant" : "RayTminNV", + "value" : 5325, + "capabilities" : [ "RayTracingNV" ], + "extensions" : [ "SPV_NV_ray_tracing" ], + "version" : "None" + }, + { + "enumerant" : "RayTmaxNV", + "value" : 5326, + "capabilities" : [ "RayTracingNV" ], + "extensions" : [ "SPV_NV_ray_tracing" ], + "version" : "None" + }, + { + "enumerant" : "InstanceCustomIndexNV", + "value" : 5327, + "capabilities" : [ "RayTracingNV" ], + "extensions" : [ "SPV_NV_ray_tracing" ], + "version" : "None" + }, + { + "enumerant" : "ObjectToWorldNV", + "value" : 5330, + "capabilities" : [ "RayTracingNV" ], + "extensions" : [ "SPV_NV_ray_tracing" ], + "version" : "None" + }, + { + "enumerant" : "WorldToObjectNV", + "value" : 5331, + "capabilities" : [ "RayTracingNV" ], + "extensions" : [ "SPV_NV_ray_tracing" ], + "version" : "None" + }, + { + "enumerant" : "HitTNV", + "value" : 5332, + "capabilities" : [ "RayTracingNV" ], + "extensions" : [ "SPV_NV_ray_tracing" ], + "version" : "None" + }, + { + "enumerant" : "HitKindNV", + "value" : 5333, + "capabilities" : [ "RayTracingNV" ], + "extensions" : [ "SPV_NV_ray_tracing" ], + "version" : "None" + }, + { + "enumerant" : "IncomingRayFlagsNV", + "value" : 5351, + "capabilities" : [ "RayTracingNV" ], + "extensions" : [ "SPV_NV_ray_tracing" ], + "version" : "None" + }, + { + "enumerant" : "WarpsPerSMNV", + "value" : 5374, + "capabilities" : [ "ShaderSMBuiltinsNV" ], + "extensions" : [ "SPV_NV_shader_sm_builtins" ], + "version" : "None" + }, + { + "enumerant" : "SMCountNV", + "value" : 5375, + "capabilities" : [ "ShaderSMBuiltinsNV" ], + "extensions" : [ "SPV_NV_shader_sm_builtins" ], + "version" : "None" + }, + { + "enumerant" : "WarpIDNV", + "value" : 5376, + "capabilities" : [ "ShaderSMBuiltinsNV" ], + "extensions" : [ "SPV_NV_shader_sm_builtins" ], + "version" : "None" + }, + { + "enumerant" : "SMIDNV", + "value" : 5377, + "capabilities" : [ "ShaderSMBuiltinsNV" ], + "extensions" : [ "SPV_NV_shader_sm_builtins" ], + "version" : "None" } ] }, @@ -6018,6 +9341,18 @@ { "enumerant" : "Invocation", "value" : 4 + }, + { + "enumerant" : "QueueFamily", + "value" : 5, + "capabilities" : [ "VulkanMemoryModel" ], + "version" : "1.5" + }, + { + "enumerant" : "QueueFamilyKHR", + "value" : 5, + "capabilities" : [ "VulkanMemoryModel" ], + "version" : "1.5" } ] }, @@ -6174,7 +9509,8 @@ }, { "enumerant" : "Groups", - "value" : 18 + "value" : 18, + "extensions" : [ "SPV_AMD_shader_ballot" ] }, { "enumerant" : "DeviceEnqueue", @@ -6427,6 +9763,16 @@ "capabilities" : [ "GroupNonUniform" ], "version" : "1.3" }, + { + "enumerant" : "ShaderLayer", + "value" : 69, + "version" : "1.5" + }, + { + "enumerant" : "ShaderViewportIndex", + "value" : 70, + "version" : "1.5" + }, { "enumerant" : "SubgroupBallotKHR", "value" : 4423, @@ -6533,20 +9879,50 @@ "enumerant" : "StorageBuffer8BitAccess", "value" : 4448, "extensions" : [ "SPV_KHR_8bit_storage" ], - "version" : "None" + "version" : "1.5" }, { "enumerant" : "UniformAndStorageBuffer8BitAccess", "value" : 4449, "capabilities" : [ "StorageBuffer8BitAccess" ], "extensions" : [ "SPV_KHR_8bit_storage" ], - "version" : "None" + "version" : "1.5" }, { "enumerant" : "StoragePushConstant8", "value" : 4450, "extensions" : [ "SPV_KHR_8bit_storage" ], - "version" : "None" + "version" : "1.5" + }, + { + "enumerant" : "DenormPreserve", + "value" : 4464, + "extensions" : [ "SPV_KHR_float_controls" ], + "version" : "1.4" + }, + { + "enumerant" : "DenormFlushToZero", + "value" : 4465, + "extensions" : [ "SPV_KHR_float_controls" ], + "version" : "1.4" + }, + { + "enumerant" : "SignedZeroInfNanPreserve", + "value" : 4466, + "extensions" : [ "SPV_KHR_float_controls" ], + "version" : "1.4" + }, + { + "enumerant" : "RoundingModeRTE", + "value" : 4467, + "extensions" : [ "SPV_KHR_float_controls" ], + "version" : "1.4" + }, + { + "enumerant" : "RoundingModeRTZ", + "value" : 4468, + "extensions" : [ "SPV_KHR_float_controls" ], + "version" : "1.4" }, { "enumerant" : "Float16ImageAMD", @@ -6583,6 +9959,13 @@ "extensions" : [ "SPV_AMD_shader_image_load_store_lod" ], "version" : "None" }, + { + "enumerant" : "ShaderClockKHR", + "value" : 5055, + "capabilities" : [ "Shader" ], + "extensions" : [ "SPV_KHR_shader_clock" ], + "version" : "None" + }, { "enumerant" : "SampleMaskOverrideCoverageNV", "value" : 5249, @@ -6639,88 +10022,296 @@ "extensions" : [ "SPV_EXT_fragment_fully_covered" ], "version" : "None" }, + { + "enumerant" : "MeshShadingNV", + "value" : 5266, + "capabilities" : [ "Shader" ], + "extensions" : [ "SPV_NV_mesh_shader" ], + "version" : "None" + }, + { + "enumerant" : "ImageFootprintNV", + "value" : 5282, + "extensions" : [ "SPV_NV_shader_image_footprint" ], + "version" : "None" + }, + { + "enumerant" : "FragmentBarycentricNV", + "value" : 5284, + "extensions" : [ "SPV_NV_fragment_shader_barycentric" ], + "version" : "None" + }, + { + "enumerant" : "ComputeDerivativeGroupQuadsNV", + "value" : 5288, + "extensions" : [ "SPV_NV_compute_shader_derivatives" ], + "version" : "None" + }, + { + "enumerant" : "FragmentDensityEXT", + "value" : 5291, + "capabilities" : [ "Shader" ], + "extensions" : [ "SPV_EXT_fragment_invocation_density", "SPV_NV_shading_rate" ], + "version" : "None" + }, + { + "enumerant" : "ShadingRateNV", + "value" : 5291, + "capabilities" : [ "Shader" ], + "extensions" : [ "SPV_NV_shading_rate", "SPV_EXT_fragment_invocation_density" ], + "version" : "None" + }, + { + "enumerant" : "GroupNonUniformPartitionedNV", + "value" : 5297, + "extensions" : [ "SPV_NV_shader_subgroup_partitioned" ], + "version" : "None" + }, + { + "enumerant" : "ShaderNonUniform", + "value" : 5301, + "capabilities" : [ "Shader" ], + "version" : "1.5" + }, { "enumerant" : "ShaderNonUniformEXT", "value" : 5301, "capabilities" : [ "Shader" ], "extensions" : [ "SPV_EXT_descriptor_indexing" ], - "version" : "None" + "version" : "1.5" + }, + { + "enumerant" : "RuntimeDescriptorArray", + "value" : 5302, + "capabilities" : [ "Shader" ], + "version" : "1.5" }, { "enumerant" : "RuntimeDescriptorArrayEXT", "value" : 5302, "capabilities" : [ "Shader" ], "extensions" : [ "SPV_EXT_descriptor_indexing" ], - "version" : "None" + "version" : "1.5" + }, + { + "enumerant" : "InputAttachmentArrayDynamicIndexing", + "value" : 5303, + "capabilities" : [ "InputAttachment" ], + "version" : "1.5" }, { "enumerant" : "InputAttachmentArrayDynamicIndexingEXT", "value" : 5303, "capabilities" : [ "InputAttachment" ], "extensions" : [ "SPV_EXT_descriptor_indexing" ], - "version" : "None" + "version" : "1.5" + }, + { + "enumerant" : "UniformTexelBufferArrayDynamicIndexing", + "value" : 5304, + "capabilities" : [ "SampledBuffer" ], + "version" : "1.5" }, { "enumerant" : "UniformTexelBufferArrayDynamicIndexingEXT", "value" : 5304, "capabilities" : [ "SampledBuffer" ], "extensions" : [ "SPV_EXT_descriptor_indexing" ], - "version" : "None" + "version" : "1.5" + }, + { + "enumerant" : "StorageTexelBufferArrayDynamicIndexing", + "value" : 5305, + "capabilities" : [ "ImageBuffer" ], + "version" : "1.5" }, { "enumerant" : "StorageTexelBufferArrayDynamicIndexingEXT", "value" : 5305, "capabilities" : [ "ImageBuffer" ], "extensions" : [ "SPV_EXT_descriptor_indexing" ], - "version" : "None" + "version" : "1.5" + }, + { + "enumerant" : "UniformBufferArrayNonUniformIndexing", + "value" : 5306, + "capabilities" : [ "ShaderNonUniform" ], + "version" : "1.5" }, { "enumerant" : "UniformBufferArrayNonUniformIndexingEXT", "value" : 5306, - "capabilities" : [ "ShaderNonUniformEXT" ], + "capabilities" : [ "ShaderNonUniform" ], "extensions" : [ "SPV_EXT_descriptor_indexing" ], - "version" : "None" + "version" : "1.5" + }, + { + "enumerant" : "SampledImageArrayNonUniformIndexing", + "value" : 5307, + "capabilities" : [ "ShaderNonUniform" ], + "version" : "1.5" }, { "enumerant" : "SampledImageArrayNonUniformIndexingEXT", "value" : 5307, - "capabilities" : [ "ShaderNonUniformEXT" ], + "capabilities" : [ "ShaderNonUniform" ], "extensions" : [ "SPV_EXT_descriptor_indexing" ], - "version" : "None" + "version" : "1.5" + }, + { + "enumerant" : "StorageBufferArrayNonUniformIndexing", + "value" : 5308, + "capabilities" : [ "ShaderNonUniform" ], + "version" : "1.5" }, { "enumerant" : "StorageBufferArrayNonUniformIndexingEXT", "value" : 5308, - "capabilities" : [ "ShaderNonUniformEXT" ], + "capabilities" : [ "ShaderNonUniform" ], "extensions" : [ "SPV_EXT_descriptor_indexing" ], - "version" : "None" + "version" : "1.5" + }, + { + "enumerant" : "StorageImageArrayNonUniformIndexing", + "value" : 5309, + "capabilities" : [ "ShaderNonUniform" ], + "version" : "1.5" }, { "enumerant" : "StorageImageArrayNonUniformIndexingEXT", "value" : 5309, - "capabilities" : [ "ShaderNonUniformEXT" ], + "capabilities" : [ "ShaderNonUniform" ], "extensions" : [ "SPV_EXT_descriptor_indexing" ], - "version" : "None" + "version" : "1.5" + }, + { + "enumerant" : "InputAttachmentArrayNonUniformIndexing", + "value" : 5310, + "capabilities" : [ "InputAttachment", "ShaderNonUniform" ], + "version" : "1.5" }, { "enumerant" : "InputAttachmentArrayNonUniformIndexingEXT", "value" : 5310, - "capabilities" : [ "InputAttachment", "ShaderNonUniformEXT" ], + "capabilities" : [ "InputAttachment", "ShaderNonUniform" ], "extensions" : [ "SPV_EXT_descriptor_indexing" ], - "version" : "None" + "version" : "1.5" + }, + { + "enumerant" : "UniformTexelBufferArrayNonUniformIndexing", + "value" : 5311, + "capabilities" : [ "SampledBuffer", "ShaderNonUniform" ], + "version" : "1.5" }, { "enumerant" : "UniformTexelBufferArrayNonUniformIndexingEXT", "value" : 5311, - "capabilities" : [ "SampledBuffer", "ShaderNonUniformEXT" ], + "capabilities" : [ "SampledBuffer", "ShaderNonUniform" ], "extensions" : [ "SPV_EXT_descriptor_indexing" ], - "version" : "None" + "version" : "1.5" + }, + { + "enumerant" : "StorageTexelBufferArrayNonUniformIndexing", + "value" : 5312, + "capabilities" : [ "ImageBuffer", "ShaderNonUniform" ], + "version" : "1.5" }, { "enumerant" : "StorageTexelBufferArrayNonUniformIndexingEXT", "value" : 5312, - "capabilities" : [ "ImageBuffer", "ShaderNonUniformEXT" ], + "capabilities" : [ "ImageBuffer", "ShaderNonUniform" ], "extensions" : [ "SPV_EXT_descriptor_indexing" ], + "version" : "1.5" + }, + { + "enumerant" : "RayTracingNV", + "value" : 5340, + "capabilities" : [ "Shader" ], + "extensions" : [ "SPV_NV_ray_tracing" ], + "version" : "None" + }, + { + "enumerant" : "VulkanMemoryModel", + "value" : 5345, + "version" : "1.5" + }, + { + "enumerant" : "VulkanMemoryModelKHR", + "value" : 5345, + "extensions" : [ "SPV_KHR_vulkan_memory_model" ], + "version" : "1.5" + }, + { + "enumerant" : "VulkanMemoryModelDeviceScope", + "value" : 5346, + "version" : "1.5" + }, + { + "enumerant" : "VulkanMemoryModelDeviceScopeKHR", + "value" : 5346, + "extensions" : [ "SPV_KHR_vulkan_memory_model" ], + "version" : "1.5" + }, + { + "enumerant" : "PhysicalStorageBufferAddresses", + "value" : 5347, + "capabilities" : [ "Shader" ], + "extensions" : [ "SPV_EXT_physical_storage_buffer", "SPV_KHR_physical_storage_buffer" ], + "version" : "1.5" + }, + { + "enumerant" : "PhysicalStorageBufferAddressesEXT", + "value" : 5347, + "capabilities" : [ "Shader" ], + "extensions" : [ "SPV_EXT_physical_storage_buffer" ], + "version" : "1.5" + }, + { + "enumerant" : "ComputeDerivativeGroupLinearNV", + "value" : 5350, + "extensions" : [ "SPV_NV_compute_shader_derivatives" ], + "version" : "None" + }, + { + "enumerant" : "CooperativeMatrixNV", + "value" : 5357, + "capabilities" : [ "Shader" ], + "extensions" : [ "SPV_NV_cooperative_matrix" ], + "version" : "None" + }, + { + "enumerant" : "FragmentShaderSampleInterlockEXT", + "value" : 5363, + "capabilities" : [ "Shader" ], + "extensions" : [ "SPV_EXT_fragment_shader_interlock" ], + "version" : "None" + }, + { + "enumerant" : "FragmentShaderShadingRateInterlockEXT", + "value" : 5372, + "capabilities" : [ "Shader" ], + "extensions" : [ "SPV_EXT_fragment_shader_interlock" ], + "version" : "None" + }, + { + "enumerant" : "ShaderSMBuiltinsNV", + "value" : 5373, + "capabilities" : [ "Shader" ], + "extensions" : [ "SPV_NV_shader_sm_builtins" ], + "version" : "None" + }, + { + "enumerant" : "FragmentShaderPixelInterlockEXT", + "value" : 5378, + "capabilities" : [ "Shader" ], + "extensions" : [ "SPV_EXT_fragment_shader_interlock" ], + "version" : "None" + }, + { + "enumerant" : "DemoteToHelperInvocationEXT", + "value" : 5379, + "capabilities" : [ "Shader" ], + "extensions" : [ "SPV_EXT_demote_to_helper_invocation" ], "version" : "None" }, { @@ -6742,9 +10333,34 @@ "version" : "None" }, { - "enumerant" : "GroupNonUniformPartitionedNV", - "value" : 5297, - "extensions" : [ "SPV_NV_shader_subgroup_partitioned" ], + "enumerant" : "SubgroupImageMediaBlockIOINTEL", + "value" : 5579, + "extensions" : [ "SPV_INTEL_media_block_io" ], + "version" : "None" + }, + { + "enumerant" : "IntegerFunctions2INTEL", + "value" : 5584, + "capabilities" : [ "Shader" ], + "extensions" : [ "SPV_INTEL_shader_integer_functions2" ], + "version" : "None" + }, + { + "enumerant" : "SubgroupAvcMotionEstimationINTEL", + "value" : 5696, + "extensions" : [ "SPV_INTEL_device_side_avc_motion_estimation" ], + "version" : "None" + }, + { + "enumerant" : "SubgroupAvcMotionEstimationIntraINTEL", + "value" : 5697, + "extensions" : [ "SPV_INTEL_device_side_avc_motion_estimation" ], + "version" : "None" + }, + { + "enumerant" : "SubgroupAvcMotionEstimationChromaINTEL", + "value" : 5698, + "extensions" : [ "SPV_INTEL_device_side_avc_motion_estimation" ], "version" : "None" } ] diff --git a/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/spirv.h b/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/spirv.h index 4c90c936ce..53928a4a9e 100644 --- a/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/spirv.h +++ b/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/spirv.h @@ -1,5 +1,5 @@ /* -** Copyright (c) 2014-2018 The Khronos Group Inc. +** Copyright (c) 2014-2019 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"), @@ -31,13 +31,16 @@ /* ** Enumeration tokens for SPIR-V, in various styles: -** C, C++, C++11, JSON, Lua, Python +** C, C++, C++11, JSON, Lua, Python, C#, D ** ** - C will have tokens with a "Spv" prefix, e.g.: SpvSourceLanguageGLSL ** - C++ will have tokens in the "spv" name space, e.g.: spv::SourceLanguageGLSL ** - C++11 will use enum classes in the spv namespace, e.g.: spv::SourceLanguage::GLSL ** - Lua will use tables, e.g.: spv.SourceLanguage.GLSL ** - Python will use dictionaries, e.g.: spv['SourceLanguage']['GLSL'] +** - C# will use enum classes in the Specification class located in the "Spv" namespace, +** e.g.: Spv.Specification.SourceLanguage.GLSL +** - D will have tokens under the "spv" module, e.g: spv.SourceLanguage.GLSL ** ** Some tokens act like mask values, which can be OR'd together, ** while others are mutually exclusive. The mask-like ones have @@ -50,11 +53,11 @@ typedef unsigned int SpvId; -#define SPV_VERSION 0x10300 +#define SPV_VERSION 0x10500 #define SPV_REVISION 1 static const unsigned int SpvMagicNumber = 0x07230203; -static const unsigned int SpvVersion = 0x00010300; +static const unsigned int SpvVersion = 0x00010500; static const unsigned int SpvRevision = 1; static const unsigned int SpvOpCodeMask = 0xffff; static const unsigned int SpvWordCountShift = 16; @@ -77,6 +80,14 @@ typedef enum SpvExecutionModel_ { SpvExecutionModelFragment = 4, SpvExecutionModelGLCompute = 5, SpvExecutionModelKernel = 6, + SpvExecutionModelTaskNV = 5267, + SpvExecutionModelMeshNV = 5268, + SpvExecutionModelRayGenerationNV = 5313, + SpvExecutionModelIntersectionNV = 5314, + SpvExecutionModelAnyHitNV = 5315, + SpvExecutionModelClosestHitNV = 5316, + SpvExecutionModelMissNV = 5317, + SpvExecutionModelCallableNV = 5318, SpvExecutionModelMax = 0x7fffffff, } SpvExecutionModel; @@ -84,6 +95,8 @@ typedef enum SpvAddressingModel_ { SpvAddressingModelLogical = 0, SpvAddressingModelPhysical32 = 1, SpvAddressingModelPhysical64 = 2, + SpvAddressingModelPhysicalStorageBuffer64 = 5348, + SpvAddressingModelPhysicalStorageBuffer64EXT = 5348, SpvAddressingModelMax = 0x7fffffff, } SpvAddressingModel; @@ -91,6 +104,8 @@ typedef enum SpvMemoryModel_ { SpvMemoryModelSimple = 0, SpvMemoryModelGLSL450 = 1, SpvMemoryModelOpenCL = 2, + SpvMemoryModelVulkan = 3, + SpvMemoryModelVulkanKHR = 3, SpvMemoryModelMax = 0x7fffffff, } SpvMemoryModel; @@ -134,7 +149,23 @@ typedef enum SpvExecutionMode_ { SpvExecutionModeLocalSizeId = 38, SpvExecutionModeLocalSizeHintId = 39, SpvExecutionModePostDepthCoverage = 4446, + SpvExecutionModeDenormPreserve = 4459, + SpvExecutionModeDenormFlushToZero = 4460, + SpvExecutionModeSignedZeroInfNanPreserve = 4461, + SpvExecutionModeRoundingModeRTE = 4462, + SpvExecutionModeRoundingModeRTZ = 4463, SpvExecutionModeStencilRefReplacingEXT = 5027, + SpvExecutionModeOutputLinesNV = 5269, + SpvExecutionModeOutputPrimitivesNV = 5270, + SpvExecutionModeDerivativeGroupQuadsNV = 5289, + SpvExecutionModeDerivativeGroupLinearNV = 5290, + SpvExecutionModeOutputTrianglesNV = 5298, + SpvExecutionModePixelInterlockOrderedEXT = 5366, + SpvExecutionModePixelInterlockUnorderedEXT = 5367, + SpvExecutionModeSampleInterlockOrderedEXT = 5368, + SpvExecutionModeSampleInterlockUnorderedEXT = 5369, + SpvExecutionModeShadingRateInterlockOrderedEXT = 5370, + SpvExecutionModeShadingRateInterlockUnorderedEXT = 5371, SpvExecutionModeMax = 0x7fffffff, } SpvExecutionMode; @@ -152,6 +183,14 @@ typedef enum SpvStorageClass_ { SpvStorageClassAtomicCounter = 10, SpvStorageClassImage = 11, SpvStorageClassStorageBuffer = 12, + SpvStorageClassCallableDataNV = 5328, + SpvStorageClassIncomingCallableDataNV = 5329, + SpvStorageClassRayPayloadNV = 5338, + SpvStorageClassHitAttributeNV = 5339, + SpvStorageClassIncomingRayPayloadNV = 5342, + SpvStorageClassShaderRecordBufferNV = 5343, + SpvStorageClassPhysicalStorageBuffer = 5349, + SpvStorageClassPhysicalStorageBufferEXT = 5349, SpvStorageClassMax = 0x7fffffff, } SpvStorageClass; @@ -279,6 +318,16 @@ typedef enum SpvImageOperandsShift_ { SpvImageOperandsConstOffsetsShift = 5, SpvImageOperandsSampleShift = 6, SpvImageOperandsMinLodShift = 7, + SpvImageOperandsMakeTexelAvailableShift = 8, + SpvImageOperandsMakeTexelAvailableKHRShift = 8, + SpvImageOperandsMakeTexelVisibleShift = 9, + SpvImageOperandsMakeTexelVisibleKHRShift = 9, + SpvImageOperandsNonPrivateTexelShift = 10, + SpvImageOperandsNonPrivateTexelKHRShift = 10, + SpvImageOperandsVolatileTexelShift = 11, + SpvImageOperandsVolatileTexelKHRShift = 11, + SpvImageOperandsSignExtendShift = 12, + SpvImageOperandsZeroExtendShift = 13, SpvImageOperandsMax = 0x7fffffff, } SpvImageOperandsShift; @@ -292,6 +341,16 @@ typedef enum SpvImageOperandsMask_ { SpvImageOperandsConstOffsetsMask = 0x00000020, SpvImageOperandsSampleMask = 0x00000040, SpvImageOperandsMinLodMask = 0x00000080, + SpvImageOperandsMakeTexelAvailableMask = 0x00000100, + SpvImageOperandsMakeTexelAvailableKHRMask = 0x00000100, + SpvImageOperandsMakeTexelVisibleMask = 0x00000200, + SpvImageOperandsMakeTexelVisibleKHRMask = 0x00000200, + SpvImageOperandsNonPrivateTexelMask = 0x00000400, + SpvImageOperandsNonPrivateTexelKHRMask = 0x00000400, + SpvImageOperandsVolatileTexelMask = 0x00000800, + SpvImageOperandsVolatileTexelKHRMask = 0x00000800, + SpvImageOperandsSignExtendMask = 0x00001000, + SpvImageOperandsZeroExtendMask = 0x00002000, } SpvImageOperandsMask; typedef enum SpvFPFastMathModeShift_ { @@ -372,6 +431,7 @@ typedef enum SpvDecoration_ { SpvDecorationNonWritable = 24, SpvDecorationNonReadable = 25, SpvDecorationUniform = 26, + SpvDecorationUniformId = 27, SpvDecorationSaturatedConversion = 28, SpvDecorationStream = 29, SpvDecorationLocation = 30, @@ -392,14 +452,28 @@ typedef enum SpvDecoration_ { SpvDecorationMaxByteOffset = 45, SpvDecorationAlignmentId = 46, SpvDecorationMaxByteOffsetId = 47, + SpvDecorationNoSignedWrap = 4469, + SpvDecorationNoUnsignedWrap = 4470, SpvDecorationExplicitInterpAMD = 4999, SpvDecorationOverrideCoverageNV = 5248, SpvDecorationPassthroughNV = 5250, SpvDecorationViewportRelativeNV = 5252, SpvDecorationSecondaryViewportRelativeNV = 5256, + SpvDecorationPerPrimitiveNV = 5271, + SpvDecorationPerViewNV = 5272, + SpvDecorationPerTaskNV = 5273, + SpvDecorationPerVertexNV = 5285, + SpvDecorationNonUniform = 5300, SpvDecorationNonUniformEXT = 5300, + SpvDecorationRestrictPointer = 5355, + SpvDecorationRestrictPointerEXT = 5355, + SpvDecorationAliasedPointer = 5356, + SpvDecorationAliasedPointerEXT = 5356, + SpvDecorationCounterBuffer = 5634, SpvDecorationHlslCounterBufferGOOGLE = 5634, SpvDecorationHlslSemanticGOOGLE = 5635, + SpvDecorationUserSemantic = 5635, + SpvDecorationUserTypeGOOGLE = 5636, SpvDecorationMax = 0x7fffffff, } SpvDecoration; @@ -474,6 +548,38 @@ typedef enum SpvBuiltIn_ { SpvBuiltInPositionPerViewNV = 5261, SpvBuiltInViewportMaskPerViewNV = 5262, SpvBuiltInFullyCoveredEXT = 5264, + SpvBuiltInTaskCountNV = 5274, + SpvBuiltInPrimitiveCountNV = 5275, + SpvBuiltInPrimitiveIndicesNV = 5276, + SpvBuiltInClipDistancePerViewNV = 5277, + SpvBuiltInCullDistancePerViewNV = 5278, + SpvBuiltInLayerPerViewNV = 5279, + SpvBuiltInMeshViewCountNV = 5280, + SpvBuiltInMeshViewIndicesNV = 5281, + SpvBuiltInBaryCoordNV = 5286, + SpvBuiltInBaryCoordNoPerspNV = 5287, + SpvBuiltInFragSizeEXT = 5292, + SpvBuiltInFragmentSizeNV = 5292, + SpvBuiltInFragInvocationCountEXT = 5293, + SpvBuiltInInvocationsPerPixelNV = 5293, + SpvBuiltInLaunchIdNV = 5319, + SpvBuiltInLaunchSizeNV = 5320, + SpvBuiltInWorldRayOriginNV = 5321, + SpvBuiltInWorldRayDirectionNV = 5322, + SpvBuiltInObjectRayOriginNV = 5323, + SpvBuiltInObjectRayDirectionNV = 5324, + SpvBuiltInRayTminNV = 5325, + SpvBuiltInRayTmaxNV = 5326, + SpvBuiltInInstanceCustomIndexNV = 5327, + SpvBuiltInObjectToWorldNV = 5330, + SpvBuiltInWorldToObjectNV = 5331, + SpvBuiltInHitTNV = 5332, + SpvBuiltInHitKindNV = 5333, + SpvBuiltInIncomingRayFlagsNV = 5351, + SpvBuiltInWarpsPerSMNV = 5374, + SpvBuiltInSMCountNV = 5375, + SpvBuiltInWarpIDNV = 5376, + SpvBuiltInSMIDNV = 5377, SpvBuiltInMax = 0x7fffffff, } SpvBuiltIn; @@ -494,6 +600,11 @@ typedef enum SpvLoopControlShift_ { SpvLoopControlDontUnrollShift = 1, SpvLoopControlDependencyInfiniteShift = 2, SpvLoopControlDependencyLengthShift = 3, + SpvLoopControlMinIterationsShift = 4, + SpvLoopControlMaxIterationsShift = 5, + SpvLoopControlIterationMultipleShift = 6, + SpvLoopControlPeelCountShift = 7, + SpvLoopControlPartialCountShift = 8, SpvLoopControlMax = 0x7fffffff, } SpvLoopControlShift; @@ -503,6 +614,11 @@ typedef enum SpvLoopControlMask_ { SpvLoopControlDontUnrollMask = 0x00000002, SpvLoopControlDependencyInfiniteMask = 0x00000004, SpvLoopControlDependencyLengthMask = 0x00000008, + SpvLoopControlMinIterationsMask = 0x00000010, + SpvLoopControlMaxIterationsMask = 0x00000020, + SpvLoopControlIterationMultipleMask = 0x00000040, + SpvLoopControlPeelCountMask = 0x00000080, + SpvLoopControlPartialCountMask = 0x00000100, } SpvLoopControlMask; typedef enum SpvFunctionControlShift_ { @@ -532,6 +648,13 @@ typedef enum SpvMemorySemanticsShift_ { SpvMemorySemanticsCrossWorkgroupMemoryShift = 9, SpvMemorySemanticsAtomicCounterMemoryShift = 10, SpvMemorySemanticsImageMemoryShift = 11, + SpvMemorySemanticsOutputMemoryShift = 12, + SpvMemorySemanticsOutputMemoryKHRShift = 12, + SpvMemorySemanticsMakeAvailableShift = 13, + SpvMemorySemanticsMakeAvailableKHRShift = 13, + SpvMemorySemanticsMakeVisibleShift = 14, + SpvMemorySemanticsMakeVisibleKHRShift = 14, + SpvMemorySemanticsVolatileShift = 15, SpvMemorySemanticsMax = 0x7fffffff, } SpvMemorySemanticsShift; @@ -547,12 +670,25 @@ typedef enum SpvMemorySemanticsMask_ { SpvMemorySemanticsCrossWorkgroupMemoryMask = 0x00000200, SpvMemorySemanticsAtomicCounterMemoryMask = 0x00000400, SpvMemorySemanticsImageMemoryMask = 0x00000800, + SpvMemorySemanticsOutputMemoryMask = 0x00001000, + SpvMemorySemanticsOutputMemoryKHRMask = 0x00001000, + SpvMemorySemanticsMakeAvailableMask = 0x00002000, + SpvMemorySemanticsMakeAvailableKHRMask = 0x00002000, + SpvMemorySemanticsMakeVisibleMask = 0x00004000, + SpvMemorySemanticsMakeVisibleKHRMask = 0x00004000, + SpvMemorySemanticsVolatileMask = 0x00008000, } SpvMemorySemanticsMask; typedef enum SpvMemoryAccessShift_ { SpvMemoryAccessVolatileShift = 0, SpvMemoryAccessAlignedShift = 1, SpvMemoryAccessNontemporalShift = 2, + SpvMemoryAccessMakePointerAvailableShift = 3, + SpvMemoryAccessMakePointerAvailableKHRShift = 3, + SpvMemoryAccessMakePointerVisibleShift = 4, + SpvMemoryAccessMakePointerVisibleKHRShift = 4, + SpvMemoryAccessNonPrivatePointerShift = 5, + SpvMemoryAccessNonPrivatePointerKHRShift = 5, SpvMemoryAccessMax = 0x7fffffff, } SpvMemoryAccessShift; @@ -561,6 +697,12 @@ typedef enum SpvMemoryAccessMask_ { SpvMemoryAccessVolatileMask = 0x00000001, SpvMemoryAccessAlignedMask = 0x00000002, SpvMemoryAccessNontemporalMask = 0x00000004, + SpvMemoryAccessMakePointerAvailableMask = 0x00000008, + SpvMemoryAccessMakePointerAvailableKHRMask = 0x00000008, + SpvMemoryAccessMakePointerVisibleMask = 0x00000010, + SpvMemoryAccessMakePointerVisibleKHRMask = 0x00000010, + SpvMemoryAccessNonPrivatePointerMask = 0x00000020, + SpvMemoryAccessNonPrivatePointerKHRMask = 0x00000020, } SpvMemoryAccessMask; typedef enum SpvScope_ { @@ -569,6 +711,8 @@ typedef enum SpvScope_ { SpvScopeWorkgroup = 2, SpvScopeSubgroup = 3, SpvScopeInvocation = 4, + SpvScopeQueueFamily = 5, + SpvScopeQueueFamilyKHR = 5, SpvScopeMax = 0x7fffffff, } SpvScope; @@ -668,6 +812,8 @@ typedef enum SpvCapability_ { SpvCapabilityGroupNonUniformShuffleRelative = 66, SpvCapabilityGroupNonUniformClustered = 67, SpvCapabilityGroupNonUniformQuad = 68, + SpvCapabilityShaderLayer = 69, + SpvCapabilityShaderViewportIndex = 70, SpvCapabilitySubgroupBallotKHR = 4423, SpvCapabilityDrawParameters = 4427, SpvCapabilitySubgroupVoteKHR = 4431, @@ -686,11 +832,17 @@ typedef enum SpvCapability_ { SpvCapabilityStorageBuffer8BitAccess = 4448, SpvCapabilityUniformAndStorageBuffer8BitAccess = 4449, SpvCapabilityStoragePushConstant8 = 4450, + SpvCapabilityDenormPreserve = 4464, + SpvCapabilityDenormFlushToZero = 4465, + SpvCapabilitySignedZeroInfNanPreserve = 4466, + SpvCapabilityRoundingModeRTE = 4467, + SpvCapabilityRoundingModeRTZ = 4468, SpvCapabilityFloat16ImageAMD = 5008, SpvCapabilityImageGatherBiasLodAMD = 5009, SpvCapabilityFragmentMaskAMD = 5010, SpvCapabilityStencilExportEXT = 5013, SpvCapabilityImageReadWriteLodAMD = 5015, + SpvCapabilityShaderClockKHR = 5055, SpvCapabilitySampleMaskOverrideCoverageNV = 5249, SpvCapabilityGeometryShaderPassthroughNV = 5251, SpvCapabilityShaderViewportIndexLayerEXT = 5254, @@ -699,22 +851,59 @@ typedef enum SpvCapability_ { SpvCapabilityShaderStereoViewNV = 5259, SpvCapabilityPerViewAttributesNV = 5260, SpvCapabilityFragmentFullyCoveredEXT = 5265, + SpvCapabilityMeshShadingNV = 5266, + SpvCapabilityImageFootprintNV = 5282, + SpvCapabilityFragmentBarycentricNV = 5284, + SpvCapabilityComputeDerivativeGroupQuadsNV = 5288, + SpvCapabilityFragmentDensityEXT = 5291, + SpvCapabilityShadingRateNV = 5291, SpvCapabilityGroupNonUniformPartitionedNV = 5297, + SpvCapabilityShaderNonUniform = 5301, SpvCapabilityShaderNonUniformEXT = 5301, + SpvCapabilityRuntimeDescriptorArray = 5302, SpvCapabilityRuntimeDescriptorArrayEXT = 5302, + SpvCapabilityInputAttachmentArrayDynamicIndexing = 5303, SpvCapabilityInputAttachmentArrayDynamicIndexingEXT = 5303, + SpvCapabilityUniformTexelBufferArrayDynamicIndexing = 5304, SpvCapabilityUniformTexelBufferArrayDynamicIndexingEXT = 5304, + SpvCapabilityStorageTexelBufferArrayDynamicIndexing = 5305, SpvCapabilityStorageTexelBufferArrayDynamicIndexingEXT = 5305, + SpvCapabilityUniformBufferArrayNonUniformIndexing = 5306, SpvCapabilityUniformBufferArrayNonUniformIndexingEXT = 5306, + SpvCapabilitySampledImageArrayNonUniformIndexing = 5307, SpvCapabilitySampledImageArrayNonUniformIndexingEXT = 5307, + SpvCapabilityStorageBufferArrayNonUniformIndexing = 5308, SpvCapabilityStorageBufferArrayNonUniformIndexingEXT = 5308, + SpvCapabilityStorageImageArrayNonUniformIndexing = 5309, SpvCapabilityStorageImageArrayNonUniformIndexingEXT = 5309, + SpvCapabilityInputAttachmentArrayNonUniformIndexing = 5310, SpvCapabilityInputAttachmentArrayNonUniformIndexingEXT = 5310, + SpvCapabilityUniformTexelBufferArrayNonUniformIndexing = 5311, SpvCapabilityUniformTexelBufferArrayNonUniformIndexingEXT = 5311, + SpvCapabilityStorageTexelBufferArrayNonUniformIndexing = 5312, SpvCapabilityStorageTexelBufferArrayNonUniformIndexingEXT = 5312, + SpvCapabilityRayTracingNV = 5340, + SpvCapabilityVulkanMemoryModel = 5345, + SpvCapabilityVulkanMemoryModelKHR = 5345, + SpvCapabilityVulkanMemoryModelDeviceScope = 5346, + SpvCapabilityVulkanMemoryModelDeviceScopeKHR = 5346, + SpvCapabilityPhysicalStorageBufferAddresses = 5347, + SpvCapabilityPhysicalStorageBufferAddressesEXT = 5347, + SpvCapabilityComputeDerivativeGroupLinearNV = 5350, + SpvCapabilityCooperativeMatrixNV = 5357, + SpvCapabilityFragmentShaderSampleInterlockEXT = 5363, + SpvCapabilityFragmentShaderShadingRateInterlockEXT = 5372, + SpvCapabilityShaderSMBuiltinsNV = 5373, + SpvCapabilityFragmentShaderPixelInterlockEXT = 5378, + SpvCapabilityDemoteToHelperInvocationEXT = 5379, SpvCapabilitySubgroupShuffleINTEL = 5568, SpvCapabilitySubgroupBufferBlockIOINTEL = 5569, SpvCapabilitySubgroupImageBlockIOINTEL = 5570, + SpvCapabilitySubgroupImageMediaBlockIOINTEL = 5579, + SpvCapabilityIntegerFunctions2INTEL = 5584, + SpvCapabilitySubgroupAvcMotionEstimationINTEL = 5696, + SpvCapabilitySubgroupAvcMotionEstimationIntraINTEL = 5697, + SpvCapabilitySubgroupAvcMotionEstimationChromaINTEL = 5698, SpvCapabilityMax = 0x7fffffff, } SpvCapability; @@ -1059,6 +1248,10 @@ typedef enum SpvOp_ { SpvOpGroupNonUniformLogicalXor = 364, SpvOpGroupNonUniformQuadBroadcast = 365, SpvOpGroupNonUniformQuadSwap = 366, + SpvOpCopyLogical = 400, + SpvOpPtrEqual = 401, + SpvOpPtrNotEqual = 402, + SpvOpPtrDiff = 403, SpvOpSubgroupBallotKHR = 4421, SpvOpSubgroupFirstInvocationKHR = 4422, SpvOpSubgroupAllKHR = 4428, @@ -1075,7 +1268,25 @@ typedef enum SpvOp_ { SpvOpGroupSMaxNonUniformAMD = 5007, SpvOpFragmentMaskFetchAMD = 5011, SpvOpFragmentFetchAMD = 5012, + SpvOpReadClockKHR = 5056, + SpvOpImageSampleFootprintNV = 5283, SpvOpGroupNonUniformPartitionNV = 5296, + SpvOpWritePackedPrimitiveIndices4x8NV = 5299, + SpvOpReportIntersectionNV = 5334, + SpvOpIgnoreIntersectionNV = 5335, + SpvOpTerminateRayNV = 5336, + SpvOpTraceNV = 5337, + SpvOpTypeAccelerationStructureNV = 5341, + SpvOpExecuteCallableNV = 5344, + SpvOpTypeCooperativeMatrixNV = 5358, + SpvOpCooperativeMatrixLoadNV = 5359, + SpvOpCooperativeMatrixStoreNV = 5360, + SpvOpCooperativeMatrixMulAddNV = 5361, + SpvOpCooperativeMatrixLengthNV = 5362, + SpvOpBeginInvocationInterlockEXT = 5364, + SpvOpEndInvocationInterlockEXT = 5365, + SpvOpDemoteToHelperInvocationEXT = 5380, + SpvOpIsHelperInvocationEXT = 5381, SpvOpSubgroupShuffleINTEL = 5571, SpvOpSubgroupShuffleDownINTEL = 5572, SpvOpSubgroupShuffleUpINTEL = 5573, @@ -1084,10 +1295,678 @@ typedef enum SpvOp_ { SpvOpSubgroupBlockWriteINTEL = 5576, SpvOpSubgroupImageBlockReadINTEL = 5577, SpvOpSubgroupImageBlockWriteINTEL = 5578, + SpvOpSubgroupImageMediaBlockReadINTEL = 5580, + SpvOpSubgroupImageMediaBlockWriteINTEL = 5581, + SpvOpUCountLeadingZerosINTEL = 5585, + SpvOpUCountTrailingZerosINTEL = 5586, + SpvOpAbsISubINTEL = 5587, + SpvOpAbsUSubINTEL = 5588, + SpvOpIAddSatINTEL = 5589, + SpvOpUAddSatINTEL = 5590, + SpvOpIAverageINTEL = 5591, + SpvOpUAverageINTEL = 5592, + SpvOpIAverageRoundedINTEL = 5593, + SpvOpUAverageRoundedINTEL = 5594, + SpvOpISubSatINTEL = 5595, + SpvOpUSubSatINTEL = 5596, + SpvOpIMul32x16INTEL = 5597, + SpvOpUMul32x16INTEL = 5598, + SpvOpDecorateString = 5632, SpvOpDecorateStringGOOGLE = 5632, + SpvOpMemberDecorateString = 5633, SpvOpMemberDecorateStringGOOGLE = 5633, + SpvOpVmeImageINTEL = 5699, + SpvOpTypeVmeImageINTEL = 5700, + SpvOpTypeAvcImePayloadINTEL = 5701, + SpvOpTypeAvcRefPayloadINTEL = 5702, + SpvOpTypeAvcSicPayloadINTEL = 5703, + SpvOpTypeAvcMcePayloadINTEL = 5704, + SpvOpTypeAvcMceResultINTEL = 5705, + SpvOpTypeAvcImeResultINTEL = 5706, + SpvOpTypeAvcImeResultSingleReferenceStreamoutINTEL = 5707, + SpvOpTypeAvcImeResultDualReferenceStreamoutINTEL = 5708, + SpvOpTypeAvcImeSingleReferenceStreaminINTEL = 5709, + SpvOpTypeAvcImeDualReferenceStreaminINTEL = 5710, + SpvOpTypeAvcRefResultINTEL = 5711, + SpvOpTypeAvcSicResultINTEL = 5712, + SpvOpSubgroupAvcMceGetDefaultInterBaseMultiReferencePenaltyINTEL = 5713, + SpvOpSubgroupAvcMceSetInterBaseMultiReferencePenaltyINTEL = 5714, + SpvOpSubgroupAvcMceGetDefaultInterShapePenaltyINTEL = 5715, + SpvOpSubgroupAvcMceSetInterShapePenaltyINTEL = 5716, + SpvOpSubgroupAvcMceGetDefaultInterDirectionPenaltyINTEL = 5717, + SpvOpSubgroupAvcMceSetInterDirectionPenaltyINTEL = 5718, + SpvOpSubgroupAvcMceGetDefaultIntraLumaShapePenaltyINTEL = 5719, + SpvOpSubgroupAvcMceGetDefaultInterMotionVectorCostTableINTEL = 5720, + SpvOpSubgroupAvcMceGetDefaultHighPenaltyCostTableINTEL = 5721, + SpvOpSubgroupAvcMceGetDefaultMediumPenaltyCostTableINTEL = 5722, + SpvOpSubgroupAvcMceGetDefaultLowPenaltyCostTableINTEL = 5723, + SpvOpSubgroupAvcMceSetMotionVectorCostFunctionINTEL = 5724, + SpvOpSubgroupAvcMceGetDefaultIntraLumaModePenaltyINTEL = 5725, + SpvOpSubgroupAvcMceGetDefaultNonDcLumaIntraPenaltyINTEL = 5726, + SpvOpSubgroupAvcMceGetDefaultIntraChromaModeBasePenaltyINTEL = 5727, + SpvOpSubgroupAvcMceSetAcOnlyHaarINTEL = 5728, + SpvOpSubgroupAvcMceSetSourceInterlacedFieldPolarityINTEL = 5729, + SpvOpSubgroupAvcMceSetSingleReferenceInterlacedFieldPolarityINTEL = 5730, + SpvOpSubgroupAvcMceSetDualReferenceInterlacedFieldPolaritiesINTEL = 5731, + SpvOpSubgroupAvcMceConvertToImePayloadINTEL = 5732, + SpvOpSubgroupAvcMceConvertToImeResultINTEL = 5733, + SpvOpSubgroupAvcMceConvertToRefPayloadINTEL = 5734, + SpvOpSubgroupAvcMceConvertToRefResultINTEL = 5735, + SpvOpSubgroupAvcMceConvertToSicPayloadINTEL = 5736, + SpvOpSubgroupAvcMceConvertToSicResultINTEL = 5737, + SpvOpSubgroupAvcMceGetMotionVectorsINTEL = 5738, + SpvOpSubgroupAvcMceGetInterDistortionsINTEL = 5739, + SpvOpSubgroupAvcMceGetBestInterDistortionsINTEL = 5740, + SpvOpSubgroupAvcMceGetInterMajorShapeINTEL = 5741, + SpvOpSubgroupAvcMceGetInterMinorShapeINTEL = 5742, + SpvOpSubgroupAvcMceGetInterDirectionsINTEL = 5743, + SpvOpSubgroupAvcMceGetInterMotionVectorCountINTEL = 5744, + SpvOpSubgroupAvcMceGetInterReferenceIdsINTEL = 5745, + SpvOpSubgroupAvcMceGetInterReferenceInterlacedFieldPolaritiesINTEL = 5746, + SpvOpSubgroupAvcImeInitializeINTEL = 5747, + SpvOpSubgroupAvcImeSetSingleReferenceINTEL = 5748, + SpvOpSubgroupAvcImeSetDualReferenceINTEL = 5749, + SpvOpSubgroupAvcImeRefWindowSizeINTEL = 5750, + SpvOpSubgroupAvcImeAdjustRefOffsetINTEL = 5751, + SpvOpSubgroupAvcImeConvertToMcePayloadINTEL = 5752, + SpvOpSubgroupAvcImeSetMaxMotionVectorCountINTEL = 5753, + SpvOpSubgroupAvcImeSetUnidirectionalMixDisableINTEL = 5754, + SpvOpSubgroupAvcImeSetEarlySearchTerminationThresholdINTEL = 5755, + SpvOpSubgroupAvcImeSetWeightedSadINTEL = 5756, + SpvOpSubgroupAvcImeEvaluateWithSingleReferenceINTEL = 5757, + SpvOpSubgroupAvcImeEvaluateWithDualReferenceINTEL = 5758, + SpvOpSubgroupAvcImeEvaluateWithSingleReferenceStreaminINTEL = 5759, + SpvOpSubgroupAvcImeEvaluateWithDualReferenceStreaminINTEL = 5760, + SpvOpSubgroupAvcImeEvaluateWithSingleReferenceStreamoutINTEL = 5761, + SpvOpSubgroupAvcImeEvaluateWithDualReferenceStreamoutINTEL = 5762, + SpvOpSubgroupAvcImeEvaluateWithSingleReferenceStreaminoutINTEL = 5763, + SpvOpSubgroupAvcImeEvaluateWithDualReferenceStreaminoutINTEL = 5764, + SpvOpSubgroupAvcImeConvertToMceResultINTEL = 5765, + SpvOpSubgroupAvcImeGetSingleReferenceStreaminINTEL = 5766, + SpvOpSubgroupAvcImeGetDualReferenceStreaminINTEL = 5767, + SpvOpSubgroupAvcImeStripSingleReferenceStreamoutINTEL = 5768, + SpvOpSubgroupAvcImeStripDualReferenceStreamoutINTEL = 5769, + SpvOpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeMotionVectorsINTEL = 5770, + SpvOpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeDistortionsINTEL = 5771, + SpvOpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeReferenceIdsINTEL = 5772, + SpvOpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeMotionVectorsINTEL = 5773, + SpvOpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeDistortionsINTEL = 5774, + SpvOpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeReferenceIdsINTEL = 5775, + SpvOpSubgroupAvcImeGetBorderReachedINTEL = 5776, + SpvOpSubgroupAvcImeGetTruncatedSearchIndicationINTEL = 5777, + SpvOpSubgroupAvcImeGetUnidirectionalEarlySearchTerminationINTEL = 5778, + SpvOpSubgroupAvcImeGetWeightingPatternMinimumMotionVectorINTEL = 5779, + SpvOpSubgroupAvcImeGetWeightingPatternMinimumDistortionINTEL = 5780, + SpvOpSubgroupAvcFmeInitializeINTEL = 5781, + SpvOpSubgroupAvcBmeInitializeINTEL = 5782, + SpvOpSubgroupAvcRefConvertToMcePayloadINTEL = 5783, + SpvOpSubgroupAvcRefSetBidirectionalMixDisableINTEL = 5784, + SpvOpSubgroupAvcRefSetBilinearFilterEnableINTEL = 5785, + SpvOpSubgroupAvcRefEvaluateWithSingleReferenceINTEL = 5786, + SpvOpSubgroupAvcRefEvaluateWithDualReferenceINTEL = 5787, + SpvOpSubgroupAvcRefEvaluateWithMultiReferenceINTEL = 5788, + SpvOpSubgroupAvcRefEvaluateWithMultiReferenceInterlacedINTEL = 5789, + SpvOpSubgroupAvcRefConvertToMceResultINTEL = 5790, + SpvOpSubgroupAvcSicInitializeINTEL = 5791, + SpvOpSubgroupAvcSicConfigureSkcINTEL = 5792, + SpvOpSubgroupAvcSicConfigureIpeLumaINTEL = 5793, + SpvOpSubgroupAvcSicConfigureIpeLumaChromaINTEL = 5794, + SpvOpSubgroupAvcSicGetMotionVectorMaskINTEL = 5795, + SpvOpSubgroupAvcSicConvertToMcePayloadINTEL = 5796, + SpvOpSubgroupAvcSicSetIntraLumaShapePenaltyINTEL = 5797, + SpvOpSubgroupAvcSicSetIntraLumaModeCostFunctionINTEL = 5798, + SpvOpSubgroupAvcSicSetIntraChromaModeCostFunctionINTEL = 5799, + SpvOpSubgroupAvcSicSetBilinearFilterEnableINTEL = 5800, + SpvOpSubgroupAvcSicSetSkcForwardTransformEnableINTEL = 5801, + SpvOpSubgroupAvcSicSetBlockBasedRawSkipSadINTEL = 5802, + SpvOpSubgroupAvcSicEvaluateIpeINTEL = 5803, + SpvOpSubgroupAvcSicEvaluateWithSingleReferenceINTEL = 5804, + SpvOpSubgroupAvcSicEvaluateWithDualReferenceINTEL = 5805, + SpvOpSubgroupAvcSicEvaluateWithMultiReferenceINTEL = 5806, + SpvOpSubgroupAvcSicEvaluateWithMultiReferenceInterlacedINTEL = 5807, + SpvOpSubgroupAvcSicConvertToMceResultINTEL = 5808, + SpvOpSubgroupAvcSicGetIpeLumaShapeINTEL = 5809, + SpvOpSubgroupAvcSicGetBestIpeLumaDistortionINTEL = 5810, + SpvOpSubgroupAvcSicGetBestIpeChromaDistortionINTEL = 5811, + SpvOpSubgroupAvcSicGetPackedIpeLumaModesINTEL = 5812, + SpvOpSubgroupAvcSicGetIpeChromaModeINTEL = 5813, + SpvOpSubgroupAvcSicGetPackedSkcLumaCountThresholdINTEL = 5814, + SpvOpSubgroupAvcSicGetPackedSkcLumaSumThresholdINTEL = 5815, + SpvOpSubgroupAvcSicGetInterRawSadsINTEL = 5816, SpvOpMax = 0x7fffffff, } SpvOp; -#endif // #ifndef spirv_H +#ifdef SPV_ENABLE_UTILITY_CODE +inline void SpvHasResultAndType(SpvOp opcode, bool *hasResult, bool *hasResultType) { + *hasResult = *hasResultType = false; + switch (opcode) { + default: /* unknown opcode */ break; + case SpvOpNop: *hasResult = false; *hasResultType = false; break; + case SpvOpUndef: *hasResult = true; *hasResultType = true; break; + case SpvOpSourceContinued: *hasResult = false; *hasResultType = false; break; + case SpvOpSource: *hasResult = false; *hasResultType = false; break; + case SpvOpSourceExtension: *hasResult = false; *hasResultType = false; break; + case SpvOpName: *hasResult = false; *hasResultType = false; break; + case SpvOpMemberName: *hasResult = false; *hasResultType = false; break; + case SpvOpString: *hasResult = true; *hasResultType = false; break; + case SpvOpLine: *hasResult = false; *hasResultType = false; break; + case SpvOpExtension: *hasResult = false; *hasResultType = false; break; + case SpvOpExtInstImport: *hasResult = true; *hasResultType = false; break; + case SpvOpExtInst: *hasResult = true; *hasResultType = true; break; + case SpvOpMemoryModel: *hasResult = false; *hasResultType = false; break; + case SpvOpEntryPoint: *hasResult = false; *hasResultType = false; break; + case SpvOpExecutionMode: *hasResult = false; *hasResultType = false; break; + case SpvOpCapability: *hasResult = false; *hasResultType = false; break; + case SpvOpTypeVoid: *hasResult = true; *hasResultType = false; break; + case SpvOpTypeBool: *hasResult = true; *hasResultType = false; break; + case SpvOpTypeInt: *hasResult = true; *hasResultType = false; break; + case SpvOpTypeFloat: *hasResult = true; *hasResultType = false; break; + case SpvOpTypeVector: *hasResult = true; *hasResultType = false; break; + case SpvOpTypeMatrix: *hasResult = true; *hasResultType = false; break; + case SpvOpTypeImage: *hasResult = true; *hasResultType = false; break; + case SpvOpTypeSampler: *hasResult = true; *hasResultType = false; break; + case SpvOpTypeSampledImage: *hasResult = true; *hasResultType = false; break; + case SpvOpTypeArray: *hasResult = true; *hasResultType = false; break; + case SpvOpTypeRuntimeArray: *hasResult = true; *hasResultType = false; break; + case SpvOpTypeStruct: *hasResult = true; *hasResultType = false; break; + case SpvOpTypeOpaque: *hasResult = true; *hasResultType = false; break; + case SpvOpTypePointer: *hasResult = true; *hasResultType = false; break; + case SpvOpTypeFunction: *hasResult = true; *hasResultType = false; break; + case SpvOpTypeEvent: *hasResult = true; *hasResultType = false; break; + case SpvOpTypeDeviceEvent: *hasResult = true; *hasResultType = false; break; + case SpvOpTypeReserveId: *hasResult = true; *hasResultType = false; break; + case SpvOpTypeQueue: *hasResult = true; *hasResultType = false; break; + case SpvOpTypePipe: *hasResult = true; *hasResultType = false; break; + case SpvOpTypeForwardPointer: *hasResult = false; *hasResultType = false; break; + case SpvOpConstantTrue: *hasResult = true; *hasResultType = true; break; + case SpvOpConstantFalse: *hasResult = true; *hasResultType = true; break; + case SpvOpConstant: *hasResult = true; *hasResultType = true; break; + case SpvOpConstantComposite: *hasResult = true; *hasResultType = true; break; + case SpvOpConstantSampler: *hasResult = true; *hasResultType = true; break; + case SpvOpConstantNull: *hasResult = true; *hasResultType = true; break; + case SpvOpSpecConstantTrue: *hasResult = true; *hasResultType = true; break; + case SpvOpSpecConstantFalse: *hasResult = true; *hasResultType = true; break; + case SpvOpSpecConstant: *hasResult = true; *hasResultType = true; break; + case SpvOpSpecConstantComposite: *hasResult = true; *hasResultType = true; break; + case SpvOpSpecConstantOp: *hasResult = true; *hasResultType = true; break; + case SpvOpFunction: *hasResult = true; *hasResultType = true; break; + case SpvOpFunctionParameter: *hasResult = true; *hasResultType = true; break; + case SpvOpFunctionEnd: *hasResult = false; *hasResultType = false; break; + case SpvOpFunctionCall: *hasResult = true; *hasResultType = true; break; + case SpvOpVariable: *hasResult = true; *hasResultType = true; break; + case SpvOpImageTexelPointer: *hasResult = true; *hasResultType = true; break; + case SpvOpLoad: *hasResult = true; *hasResultType = true; break; + case SpvOpStore: *hasResult = false; *hasResultType = false; break; + case SpvOpCopyMemory: *hasResult = false; *hasResultType = false; break; + case SpvOpCopyMemorySized: *hasResult = false; *hasResultType = false; break; + case SpvOpAccessChain: *hasResult = true; *hasResultType = true; break; + case SpvOpInBoundsAccessChain: *hasResult = true; *hasResultType = true; break; + case SpvOpPtrAccessChain: *hasResult = true; *hasResultType = true; break; + case SpvOpArrayLength: *hasResult = true; *hasResultType = true; break; + case SpvOpGenericPtrMemSemantics: *hasResult = true; *hasResultType = true; break; + case SpvOpInBoundsPtrAccessChain: *hasResult = true; *hasResultType = true; break; + case SpvOpDecorate: *hasResult = false; *hasResultType = false; break; + case SpvOpMemberDecorate: *hasResult = false; *hasResultType = false; break; + case SpvOpDecorationGroup: *hasResult = true; *hasResultType = false; break; + case SpvOpGroupDecorate: *hasResult = false; *hasResultType = false; break; + case SpvOpGroupMemberDecorate: *hasResult = false; *hasResultType = false; break; + case SpvOpVectorExtractDynamic: *hasResult = true; *hasResultType = true; break; + case SpvOpVectorInsertDynamic: *hasResult = true; *hasResultType = true; break; + case SpvOpVectorShuffle: *hasResult = true; *hasResultType = true; break; + case SpvOpCompositeConstruct: *hasResult = true; *hasResultType = true; break; + case SpvOpCompositeExtract: *hasResult = true; *hasResultType = true; break; + case SpvOpCompositeInsert: *hasResult = true; *hasResultType = true; break; + case SpvOpCopyObject: *hasResult = true; *hasResultType = true; break; + case SpvOpTranspose: *hasResult = true; *hasResultType = true; break; + case SpvOpSampledImage: *hasResult = true; *hasResultType = true; break; + case SpvOpImageSampleImplicitLod: *hasResult = true; *hasResultType = true; break; + case SpvOpImageSampleExplicitLod: *hasResult = true; *hasResultType = true; break; + case SpvOpImageSampleDrefImplicitLod: *hasResult = true; *hasResultType = true; break; + case SpvOpImageSampleDrefExplicitLod: *hasResult = true; *hasResultType = true; break; + case SpvOpImageSampleProjImplicitLod: *hasResult = true; *hasResultType = true; break; + case SpvOpImageSampleProjExplicitLod: *hasResult = true; *hasResultType = true; break; + case SpvOpImageSampleProjDrefImplicitLod: *hasResult = true; *hasResultType = true; break; + case SpvOpImageSampleProjDrefExplicitLod: *hasResult = true; *hasResultType = true; break; + case SpvOpImageFetch: *hasResult = true; *hasResultType = true; break; + case SpvOpImageGather: *hasResult = true; *hasResultType = true; break; + case SpvOpImageDrefGather: *hasResult = true; *hasResultType = true; break; + case SpvOpImageRead: *hasResult = true; *hasResultType = true; break; + case SpvOpImageWrite: *hasResult = false; *hasResultType = false; break; + case SpvOpImage: *hasResult = true; *hasResultType = true; break; + case SpvOpImageQueryFormat: *hasResult = true; *hasResultType = true; break; + case SpvOpImageQueryOrder: *hasResult = true; *hasResultType = true; break; + case SpvOpImageQuerySizeLod: *hasResult = true; *hasResultType = true; break; + case SpvOpImageQuerySize: *hasResult = true; *hasResultType = true; break; + case SpvOpImageQueryLod: *hasResult = true; *hasResultType = true; break; + case SpvOpImageQueryLevels: *hasResult = true; *hasResultType = true; break; + case SpvOpImageQuerySamples: *hasResult = true; *hasResultType = true; break; + case SpvOpConvertFToU: *hasResult = true; *hasResultType = true; break; + case SpvOpConvertFToS: *hasResult = true; *hasResultType = true; break; + case SpvOpConvertSToF: *hasResult = true; *hasResultType = true; break; + case SpvOpConvertUToF: *hasResult = true; *hasResultType = true; break; + case SpvOpUConvert: *hasResult = true; *hasResultType = true; break; + case SpvOpSConvert: *hasResult = true; *hasResultType = true; break; + case SpvOpFConvert: *hasResult = true; *hasResultType = true; break; + case SpvOpQuantizeToF16: *hasResult = true; *hasResultType = true; break; + case SpvOpConvertPtrToU: *hasResult = true; *hasResultType = true; break; + case SpvOpSatConvertSToU: *hasResult = true; *hasResultType = true; break; + case SpvOpSatConvertUToS: *hasResult = true; *hasResultType = true; break; + case SpvOpConvertUToPtr: *hasResult = true; *hasResultType = true; break; + case SpvOpPtrCastToGeneric: *hasResult = true; *hasResultType = true; break; + case SpvOpGenericCastToPtr: *hasResult = true; *hasResultType = true; break; + case SpvOpGenericCastToPtrExplicit: *hasResult = true; *hasResultType = true; break; + case SpvOpBitcast: *hasResult = true; *hasResultType = true; break; + case SpvOpSNegate: *hasResult = true; *hasResultType = true; break; + case SpvOpFNegate: *hasResult = true; *hasResultType = true; break; + case SpvOpIAdd: *hasResult = true; *hasResultType = true; break; + case SpvOpFAdd: *hasResult = true; *hasResultType = true; break; + case SpvOpISub: *hasResult = true; *hasResultType = true; break; + case SpvOpFSub: *hasResult = true; *hasResultType = true; break; + case SpvOpIMul: *hasResult = true; *hasResultType = true; break; + case SpvOpFMul: *hasResult = true; *hasResultType = true; break; + case SpvOpUDiv: *hasResult = true; *hasResultType = true; break; + case SpvOpSDiv: *hasResult = true; *hasResultType = true; break; + case SpvOpFDiv: *hasResult = true; *hasResultType = true; break; + case SpvOpUMod: *hasResult = true; *hasResultType = true; break; + case SpvOpSRem: *hasResult = true; *hasResultType = true; break; + case SpvOpSMod: *hasResult = true; *hasResultType = true; break; + case SpvOpFRem: *hasResult = true; *hasResultType = true; break; + case SpvOpFMod: *hasResult = true; *hasResultType = true; break; + case SpvOpVectorTimesScalar: *hasResult = true; *hasResultType = true; break; + case SpvOpMatrixTimesScalar: *hasResult = true; *hasResultType = true; break; + case SpvOpVectorTimesMatrix: *hasResult = true; *hasResultType = true; break; + case SpvOpMatrixTimesVector: *hasResult = true; *hasResultType = true; break; + case SpvOpMatrixTimesMatrix: *hasResult = true; *hasResultType = true; break; + case SpvOpOuterProduct: *hasResult = true; *hasResultType = true; break; + case SpvOpDot: *hasResult = true; *hasResultType = true; break; + case SpvOpIAddCarry: *hasResult = true; *hasResultType = true; break; + case SpvOpISubBorrow: *hasResult = true; *hasResultType = true; break; + case SpvOpUMulExtended: *hasResult = true; *hasResultType = true; break; + case SpvOpSMulExtended: *hasResult = true; *hasResultType = true; break; + case SpvOpAny: *hasResult = true; *hasResultType = true; break; + case SpvOpAll: *hasResult = true; *hasResultType = true; break; + case SpvOpIsNan: *hasResult = true; *hasResultType = true; break; + case SpvOpIsInf: *hasResult = true; *hasResultType = true; break; + case SpvOpIsFinite: *hasResult = true; *hasResultType = true; break; + case SpvOpIsNormal: *hasResult = true; *hasResultType = true; break; + case SpvOpSignBitSet: *hasResult = true; *hasResultType = true; break; + case SpvOpLessOrGreater: *hasResult = true; *hasResultType = true; break; + case SpvOpOrdered: *hasResult = true; *hasResultType = true; break; + case SpvOpUnordered: *hasResult = true; *hasResultType = true; break; + case SpvOpLogicalEqual: *hasResult = true; *hasResultType = true; break; + case SpvOpLogicalNotEqual: *hasResult = true; *hasResultType = true; break; + case SpvOpLogicalOr: *hasResult = true; *hasResultType = true; break; + case SpvOpLogicalAnd: *hasResult = true; *hasResultType = true; break; + case SpvOpLogicalNot: *hasResult = true; *hasResultType = true; break; + case SpvOpSelect: *hasResult = true; *hasResultType = true; break; + case SpvOpIEqual: *hasResult = true; *hasResultType = true; break; + case SpvOpINotEqual: *hasResult = true; *hasResultType = true; break; + case SpvOpUGreaterThan: *hasResult = true; *hasResultType = true; break; + case SpvOpSGreaterThan: *hasResult = true; *hasResultType = true; break; + case SpvOpUGreaterThanEqual: *hasResult = true; *hasResultType = true; break; + case SpvOpSGreaterThanEqual: *hasResult = true; *hasResultType = true; break; + case SpvOpULessThan: *hasResult = true; *hasResultType = true; break; + case SpvOpSLessThan: *hasResult = true; *hasResultType = true; break; + case SpvOpULessThanEqual: *hasResult = true; *hasResultType = true; break; + case SpvOpSLessThanEqual: *hasResult = true; *hasResultType = true; break; + case SpvOpFOrdEqual: *hasResult = true; *hasResultType = true; break; + case SpvOpFUnordEqual: *hasResult = true; *hasResultType = true; break; + case SpvOpFOrdNotEqual: *hasResult = true; *hasResultType = true; break; + case SpvOpFUnordNotEqual: *hasResult = true; *hasResultType = true; break; + case SpvOpFOrdLessThan: *hasResult = true; *hasResultType = true; break; + case SpvOpFUnordLessThan: *hasResult = true; *hasResultType = true; break; + case SpvOpFOrdGreaterThan: *hasResult = true; *hasResultType = true; break; + case SpvOpFUnordGreaterThan: *hasResult = true; *hasResultType = true; break; + case SpvOpFOrdLessThanEqual: *hasResult = true; *hasResultType = true; break; + case SpvOpFUnordLessThanEqual: *hasResult = true; *hasResultType = true; break; + case SpvOpFOrdGreaterThanEqual: *hasResult = true; *hasResultType = true; break; + case SpvOpFUnordGreaterThanEqual: *hasResult = true; *hasResultType = true; break; + case SpvOpShiftRightLogical: *hasResult = true; *hasResultType = true; break; + case SpvOpShiftRightArithmetic: *hasResult = true; *hasResultType = true; break; + case SpvOpShiftLeftLogical: *hasResult = true; *hasResultType = true; break; + case SpvOpBitwiseOr: *hasResult = true; *hasResultType = true; break; + case SpvOpBitwiseXor: *hasResult = true; *hasResultType = true; break; + case SpvOpBitwiseAnd: *hasResult = true; *hasResultType = true; break; + case SpvOpNot: *hasResult = true; *hasResultType = true; break; + case SpvOpBitFieldInsert: *hasResult = true; *hasResultType = true; break; + case SpvOpBitFieldSExtract: *hasResult = true; *hasResultType = true; break; + case SpvOpBitFieldUExtract: *hasResult = true; *hasResultType = true; break; + case SpvOpBitReverse: *hasResult = true; *hasResultType = true; break; + case SpvOpBitCount: *hasResult = true; *hasResultType = true; break; + case SpvOpDPdx: *hasResult = true; *hasResultType = true; break; + case SpvOpDPdy: *hasResult = true; *hasResultType = true; break; + case SpvOpFwidth: *hasResult = true; *hasResultType = true; break; + case SpvOpDPdxFine: *hasResult = true; *hasResultType = true; break; + case SpvOpDPdyFine: *hasResult = true; *hasResultType = true; break; + case SpvOpFwidthFine: *hasResult = true; *hasResultType = true; break; + case SpvOpDPdxCoarse: *hasResult = true; *hasResultType = true; break; + case SpvOpDPdyCoarse: *hasResult = true; *hasResultType = true; break; + case SpvOpFwidthCoarse: *hasResult = true; *hasResultType = true; break; + case SpvOpEmitVertex: *hasResult = false; *hasResultType = false; break; + case SpvOpEndPrimitive: *hasResult = false; *hasResultType = false; break; + case SpvOpEmitStreamVertex: *hasResult = false; *hasResultType = false; break; + case SpvOpEndStreamPrimitive: *hasResult = false; *hasResultType = false; break; + case SpvOpControlBarrier: *hasResult = false; *hasResultType = false; break; + case SpvOpMemoryBarrier: *hasResult = false; *hasResultType = false; break; + case SpvOpAtomicLoad: *hasResult = true; *hasResultType = true; break; + case SpvOpAtomicStore: *hasResult = false; *hasResultType = false; break; + case SpvOpAtomicExchange: *hasResult = true; *hasResultType = true; break; + case SpvOpAtomicCompareExchange: *hasResult = true; *hasResultType = true; break; + case SpvOpAtomicCompareExchangeWeak: *hasResult = true; *hasResultType = true; break; + case SpvOpAtomicIIncrement: *hasResult = true; *hasResultType = true; break; + case SpvOpAtomicIDecrement: *hasResult = true; *hasResultType = true; break; + case SpvOpAtomicIAdd: *hasResult = true; *hasResultType = true; break; + case SpvOpAtomicISub: *hasResult = true; *hasResultType = true; break; + case SpvOpAtomicSMin: *hasResult = true; *hasResultType = true; break; + case SpvOpAtomicUMin: *hasResult = true; *hasResultType = true; break; + case SpvOpAtomicSMax: *hasResult = true; *hasResultType = true; break; + case SpvOpAtomicUMax: *hasResult = true; *hasResultType = true; break; + case SpvOpAtomicAnd: *hasResult = true; *hasResultType = true; break; + case SpvOpAtomicOr: *hasResult = true; *hasResultType = true; break; + case SpvOpAtomicXor: *hasResult = true; *hasResultType = true; break; + case SpvOpPhi: *hasResult = true; *hasResultType = true; break; + case SpvOpLoopMerge: *hasResult = false; *hasResultType = false; break; + case SpvOpSelectionMerge: *hasResult = false; *hasResultType = false; break; + case SpvOpLabel: *hasResult = true; *hasResultType = false; break; + case SpvOpBranch: *hasResult = false; *hasResultType = false; break; + case SpvOpBranchConditional: *hasResult = false; *hasResultType = false; break; + case SpvOpSwitch: *hasResult = false; *hasResultType = false; break; + case SpvOpKill: *hasResult = false; *hasResultType = false; break; + case SpvOpReturn: *hasResult = false; *hasResultType = false; break; + case SpvOpReturnValue: *hasResult = false; *hasResultType = false; break; + case SpvOpUnreachable: *hasResult = false; *hasResultType = false; break; + case SpvOpLifetimeStart: *hasResult = false; *hasResultType = false; break; + case SpvOpLifetimeStop: *hasResult = false; *hasResultType = false; break; + case SpvOpGroupAsyncCopy: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupWaitEvents: *hasResult = false; *hasResultType = false; break; + case SpvOpGroupAll: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupAny: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupBroadcast: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupIAdd: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupFAdd: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupFMin: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupUMin: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupSMin: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupFMax: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupUMax: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupSMax: *hasResult = true; *hasResultType = true; break; + case SpvOpReadPipe: *hasResult = true; *hasResultType = true; break; + case SpvOpWritePipe: *hasResult = true; *hasResultType = true; break; + case SpvOpReservedReadPipe: *hasResult = true; *hasResultType = true; break; + case SpvOpReservedWritePipe: *hasResult = true; *hasResultType = true; break; + case SpvOpReserveReadPipePackets: *hasResult = true; *hasResultType = true; break; + case SpvOpReserveWritePipePackets: *hasResult = true; *hasResultType = true; break; + case SpvOpCommitReadPipe: *hasResult = false; *hasResultType = false; break; + case SpvOpCommitWritePipe: *hasResult = false; *hasResultType = false; break; + case SpvOpIsValidReserveId: *hasResult = true; *hasResultType = true; break; + case SpvOpGetNumPipePackets: *hasResult = true; *hasResultType = true; break; + case SpvOpGetMaxPipePackets: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupReserveReadPipePackets: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupReserveWritePipePackets: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupCommitReadPipe: *hasResult = false; *hasResultType = false; break; + case SpvOpGroupCommitWritePipe: *hasResult = false; *hasResultType = false; break; + case SpvOpEnqueueMarker: *hasResult = true; *hasResultType = true; break; + case SpvOpEnqueueKernel: *hasResult = true; *hasResultType = true; break; + case SpvOpGetKernelNDrangeSubGroupCount: *hasResult = true; *hasResultType = true; break; + case SpvOpGetKernelNDrangeMaxSubGroupSize: *hasResult = true; *hasResultType = true; break; + case SpvOpGetKernelWorkGroupSize: *hasResult = true; *hasResultType = true; break; + case SpvOpGetKernelPreferredWorkGroupSizeMultiple: *hasResult = true; *hasResultType = true; break; + case SpvOpRetainEvent: *hasResult = false; *hasResultType = false; break; + case SpvOpReleaseEvent: *hasResult = false; *hasResultType = false; break; + case SpvOpCreateUserEvent: *hasResult = true; *hasResultType = true; break; + case SpvOpIsValidEvent: *hasResult = true; *hasResultType = true; break; + case SpvOpSetUserEventStatus: *hasResult = false; *hasResultType = false; break; + case SpvOpCaptureEventProfilingInfo: *hasResult = false; *hasResultType = false; break; + case SpvOpGetDefaultQueue: *hasResult = true; *hasResultType = true; break; + case SpvOpBuildNDRange: *hasResult = true; *hasResultType = true; break; + case SpvOpImageSparseSampleImplicitLod: *hasResult = true; *hasResultType = true; break; + case SpvOpImageSparseSampleExplicitLod: *hasResult = true; *hasResultType = true; break; + case SpvOpImageSparseSampleDrefImplicitLod: *hasResult = true; *hasResultType = true; break; + case SpvOpImageSparseSampleDrefExplicitLod: *hasResult = true; *hasResultType = true; break; + case SpvOpImageSparseSampleProjImplicitLod: *hasResult = true; *hasResultType = true; break; + case SpvOpImageSparseSampleProjExplicitLod: *hasResult = true; *hasResultType = true; break; + case SpvOpImageSparseSampleProjDrefImplicitLod: *hasResult = true; *hasResultType = true; break; + case SpvOpImageSparseSampleProjDrefExplicitLod: *hasResult = true; *hasResultType = true; break; + case SpvOpImageSparseFetch: *hasResult = true; *hasResultType = true; break; + case SpvOpImageSparseGather: *hasResult = true; *hasResultType = true; break; + case SpvOpImageSparseDrefGather: *hasResult = true; *hasResultType = true; break; + case SpvOpImageSparseTexelsResident: *hasResult = true; *hasResultType = true; break; + case SpvOpNoLine: *hasResult = false; *hasResultType = false; break; + case SpvOpAtomicFlagTestAndSet: *hasResult = true; *hasResultType = true; break; + case SpvOpAtomicFlagClear: *hasResult = false; *hasResultType = false; break; + case SpvOpImageSparseRead: *hasResult = true; *hasResultType = true; break; + case SpvOpSizeOf: *hasResult = true; *hasResultType = true; break; + case SpvOpTypePipeStorage: *hasResult = true; *hasResultType = false; break; + case SpvOpConstantPipeStorage: *hasResult = true; *hasResultType = true; break; + case SpvOpCreatePipeFromPipeStorage: *hasResult = true; *hasResultType = true; break; + case SpvOpGetKernelLocalSizeForSubgroupCount: *hasResult = true; *hasResultType = true; break; + case SpvOpGetKernelMaxNumSubgroups: *hasResult = true; *hasResultType = true; break; + case SpvOpTypeNamedBarrier: *hasResult = true; *hasResultType = false; break; + case SpvOpNamedBarrierInitialize: *hasResult = true; *hasResultType = true; break; + case SpvOpMemoryNamedBarrier: *hasResult = false; *hasResultType = false; break; + case SpvOpModuleProcessed: *hasResult = false; *hasResultType = false; break; + case SpvOpExecutionModeId: *hasResult = false; *hasResultType = false; break; + case SpvOpDecorateId: *hasResult = false; *hasResultType = false; break; + case SpvOpGroupNonUniformElect: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformAll: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformAny: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformAllEqual: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformBroadcast: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformBroadcastFirst: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformBallot: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformInverseBallot: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformBallotBitExtract: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformBallotBitCount: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformBallotFindLSB: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformBallotFindMSB: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformShuffle: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformShuffleXor: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformShuffleUp: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformShuffleDown: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformIAdd: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformFAdd: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformIMul: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformFMul: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformSMin: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformUMin: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformFMin: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformSMax: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformUMax: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformFMax: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformBitwiseAnd: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformBitwiseOr: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformBitwiseXor: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformLogicalAnd: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformLogicalOr: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformLogicalXor: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformQuadBroadcast: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformQuadSwap: *hasResult = true; *hasResultType = true; break; + case SpvOpCopyLogical: *hasResult = true; *hasResultType = true; break; + case SpvOpPtrEqual: *hasResult = true; *hasResultType = true; break; + case SpvOpPtrNotEqual: *hasResult = true; *hasResultType = true; break; + case SpvOpPtrDiff: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupBallotKHR: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupFirstInvocationKHR: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAllKHR: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAnyKHR: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAllEqualKHR: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupReadInvocationKHR: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupIAddNonUniformAMD: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupFAddNonUniformAMD: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupFMinNonUniformAMD: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupUMinNonUniformAMD: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupSMinNonUniformAMD: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupFMaxNonUniformAMD: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupUMaxNonUniformAMD: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupSMaxNonUniformAMD: *hasResult = true; *hasResultType = true; break; + case SpvOpFragmentMaskFetchAMD: *hasResult = true; *hasResultType = true; break; + case SpvOpFragmentFetchAMD: *hasResult = true; *hasResultType = true; break; + case SpvOpReadClockKHR: *hasResult = true; *hasResultType = true; break; + case SpvOpImageSampleFootprintNV: *hasResult = true; *hasResultType = true; break; + case SpvOpGroupNonUniformPartitionNV: *hasResult = true; *hasResultType = true; break; + case SpvOpWritePackedPrimitiveIndices4x8NV: *hasResult = false; *hasResultType = false; break; + case SpvOpReportIntersectionNV: *hasResult = true; *hasResultType = true; break; + case SpvOpIgnoreIntersectionNV: *hasResult = false; *hasResultType = false; break; + case SpvOpTerminateRayNV: *hasResult = false; *hasResultType = false; break; + case SpvOpTraceNV: *hasResult = false; *hasResultType = false; break; + case SpvOpTypeAccelerationStructureNV: *hasResult = true; *hasResultType = false; break; + case SpvOpExecuteCallableNV: *hasResult = false; *hasResultType = false; break; + case SpvOpTypeCooperativeMatrixNV: *hasResult = true; *hasResultType = false; break; + case SpvOpCooperativeMatrixLoadNV: *hasResult = true; *hasResultType = true; break; + case SpvOpCooperativeMatrixStoreNV: *hasResult = false; *hasResultType = false; break; + case SpvOpCooperativeMatrixMulAddNV: *hasResult = true; *hasResultType = true; break; + case SpvOpCooperativeMatrixLengthNV: *hasResult = true; *hasResultType = true; break; + case SpvOpBeginInvocationInterlockEXT: *hasResult = false; *hasResultType = false; break; + case SpvOpEndInvocationInterlockEXT: *hasResult = false; *hasResultType = false; break; + case SpvOpDemoteToHelperInvocationEXT: *hasResult = false; *hasResultType = false; break; + case SpvOpIsHelperInvocationEXT: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupShuffleINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupShuffleDownINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupShuffleUpINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupShuffleXorINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupBlockReadINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupBlockWriteINTEL: *hasResult = false; *hasResultType = false; break; + case SpvOpSubgroupImageBlockReadINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupImageBlockWriteINTEL: *hasResult = false; *hasResultType = false; break; + case SpvOpSubgroupImageMediaBlockReadINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupImageMediaBlockWriteINTEL: *hasResult = false; *hasResultType = false; break; + case SpvOpUCountLeadingZerosINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpUCountTrailingZerosINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpAbsISubINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpAbsUSubINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpIAddSatINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpUAddSatINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpIAverageINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpUAverageINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpIAverageRoundedINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpUAverageRoundedINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpISubSatINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpUSubSatINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpIMul32x16INTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpUMul32x16INTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpDecorateString: *hasResult = false; *hasResultType = false; break; + case SpvOpMemberDecorateString: *hasResult = false; *hasResultType = false; break; + case SpvOpVmeImageINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpTypeVmeImageINTEL: *hasResult = true; *hasResultType = false; break; + case SpvOpTypeAvcImePayloadINTEL: *hasResult = true; *hasResultType = false; break; + case SpvOpTypeAvcRefPayloadINTEL: *hasResult = true; *hasResultType = false; break; + case SpvOpTypeAvcSicPayloadINTEL: *hasResult = true; *hasResultType = false; break; + case SpvOpTypeAvcMcePayloadINTEL: *hasResult = true; *hasResultType = false; break; + case SpvOpTypeAvcMceResultINTEL: *hasResult = true; *hasResultType = false; break; + case SpvOpTypeAvcImeResultINTEL: *hasResult = true; *hasResultType = false; break; + case SpvOpTypeAvcImeResultSingleReferenceStreamoutINTEL: *hasResult = true; *hasResultType = false; break; + case SpvOpTypeAvcImeResultDualReferenceStreamoutINTEL: *hasResult = true; *hasResultType = false; break; + case SpvOpTypeAvcImeSingleReferenceStreaminINTEL: *hasResult = true; *hasResultType = false; break; + case SpvOpTypeAvcImeDualReferenceStreaminINTEL: *hasResult = true; *hasResultType = false; break; + case SpvOpTypeAvcRefResultINTEL: *hasResult = true; *hasResultType = false; break; + case SpvOpTypeAvcSicResultINTEL: *hasResult = true; *hasResultType = false; break; + case SpvOpSubgroupAvcMceGetDefaultInterBaseMultiReferencePenaltyINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcMceSetInterBaseMultiReferencePenaltyINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcMceGetDefaultInterShapePenaltyINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcMceSetInterShapePenaltyINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcMceGetDefaultInterDirectionPenaltyINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcMceSetInterDirectionPenaltyINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcMceGetDefaultIntraLumaShapePenaltyINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcMceGetDefaultInterMotionVectorCostTableINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcMceGetDefaultHighPenaltyCostTableINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcMceGetDefaultMediumPenaltyCostTableINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcMceGetDefaultLowPenaltyCostTableINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcMceSetMotionVectorCostFunctionINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcMceGetDefaultIntraLumaModePenaltyINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcMceGetDefaultNonDcLumaIntraPenaltyINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcMceGetDefaultIntraChromaModeBasePenaltyINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcMceSetAcOnlyHaarINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcMceSetSourceInterlacedFieldPolarityINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcMceSetSingleReferenceInterlacedFieldPolarityINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcMceSetDualReferenceInterlacedFieldPolaritiesINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcMceConvertToImePayloadINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcMceConvertToImeResultINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcMceConvertToRefPayloadINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcMceConvertToRefResultINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcMceConvertToSicPayloadINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcMceConvertToSicResultINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcMceGetMotionVectorsINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcMceGetInterDistortionsINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcMceGetBestInterDistortionsINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcMceGetInterMajorShapeINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcMceGetInterMinorShapeINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcMceGetInterDirectionsINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcMceGetInterMotionVectorCountINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcMceGetInterReferenceIdsINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcMceGetInterReferenceInterlacedFieldPolaritiesINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeInitializeINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeSetSingleReferenceINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeSetDualReferenceINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeRefWindowSizeINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeAdjustRefOffsetINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeConvertToMcePayloadINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeSetMaxMotionVectorCountINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeSetUnidirectionalMixDisableINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeSetEarlySearchTerminationThresholdINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeSetWeightedSadINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeEvaluateWithSingleReferenceINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeEvaluateWithDualReferenceINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeEvaluateWithSingleReferenceStreaminINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeEvaluateWithDualReferenceStreaminINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeEvaluateWithSingleReferenceStreamoutINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeEvaluateWithDualReferenceStreamoutINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeEvaluateWithSingleReferenceStreaminoutINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeEvaluateWithDualReferenceStreaminoutINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeConvertToMceResultINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeGetSingleReferenceStreaminINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeGetDualReferenceStreaminINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeStripSingleReferenceStreamoutINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeStripDualReferenceStreamoutINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeMotionVectorsINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeDistortionsINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeReferenceIdsINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeMotionVectorsINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeDistortionsINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeReferenceIdsINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeGetBorderReachedINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeGetTruncatedSearchIndicationINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeGetUnidirectionalEarlySearchTerminationINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeGetWeightingPatternMinimumMotionVectorINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcImeGetWeightingPatternMinimumDistortionINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcFmeInitializeINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcBmeInitializeINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcRefConvertToMcePayloadINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcRefSetBidirectionalMixDisableINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcRefSetBilinearFilterEnableINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcRefEvaluateWithSingleReferenceINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcRefEvaluateWithDualReferenceINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcRefEvaluateWithMultiReferenceINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcRefEvaluateWithMultiReferenceInterlacedINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcRefConvertToMceResultINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcSicInitializeINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcSicConfigureSkcINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcSicConfigureIpeLumaINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcSicConfigureIpeLumaChromaINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcSicGetMotionVectorMaskINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcSicConvertToMcePayloadINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcSicSetIntraLumaShapePenaltyINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcSicSetIntraLumaModeCostFunctionINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcSicSetIntraChromaModeCostFunctionINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcSicSetBilinearFilterEnableINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcSicSetSkcForwardTransformEnableINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcSicSetBlockBasedRawSkipSadINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcSicEvaluateIpeINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcSicEvaluateWithSingleReferenceINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcSicEvaluateWithDualReferenceINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcSicEvaluateWithMultiReferenceINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcSicEvaluateWithMultiReferenceInterlacedINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcSicConvertToMceResultINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcSicGetIpeLumaShapeINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcSicGetBestIpeLumaDistortionINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcSicGetBestIpeChromaDistortionINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcSicGetPackedIpeLumaModesINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcSicGetIpeChromaModeINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcSicGetPackedSkcLumaCountThresholdINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcSicGetPackedSkcLumaSumThresholdINTEL: *hasResult = true; *hasResultType = true; break; + case SpvOpSubgroupAvcSicGetInterRawSadsINTEL: *hasResult = true; *hasResultType = true; break; + } +} +#endif /* SPV_ENABLE_UTILITY_CODE */ + +#endif diff --git a/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/spirv.hpp b/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/spirv.hpp index f16c2963eb..ae999578f2 100644 --- a/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/spirv.hpp +++ b/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/spirv.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2018 The Khronos Group Inc. +// Copyright (c) 2014-2019 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"), @@ -26,13 +26,16 @@ // the Binary Section of the SPIR-V specification. // Enumeration tokens for SPIR-V, in various styles: -// C, C++, C++11, JSON, Lua, Python +// C, C++, C++11, JSON, Lua, Python, C#, D // // - C will have tokens with a "Spv" prefix, e.g.: SpvSourceLanguageGLSL // - C++ will have tokens in the "spv" name space, e.g.: spv::SourceLanguageGLSL // - C++11 will use enum classes in the spv namespace, e.g.: spv::SourceLanguage::GLSL // - Lua will use tables, e.g.: spv.SourceLanguage.GLSL // - Python will use dictionaries, e.g.: spv['SourceLanguage']['GLSL'] +// - C# will use enum classes in the Specification class located in the "Spv" namespace, +// e.g.: Spv.Specification.SourceLanguage.GLSL +// - D will have tokens under the "spv" module, e.g: spv.SourceLanguage.GLSL // // Some tokens act like mask values, which can be OR'd together, // while others are mutually exclusive. The mask-like ones have @@ -46,11 +49,11 @@ namespace spv { typedef unsigned int Id; -#define SPV_VERSION 0x10300 +#define SPV_VERSION 0x10500 #define SPV_REVISION 1 static const unsigned int MagicNumber = 0x07230203; -static const unsigned int Version = 0x00010300; +static const unsigned int Version = 0x00010500; static const unsigned int Revision = 1; static const unsigned int OpCodeMask = 0xffff; static const unsigned int WordCountShift = 16; @@ -73,6 +76,14 @@ enum ExecutionModel { ExecutionModelFragment = 4, ExecutionModelGLCompute = 5, ExecutionModelKernel = 6, + ExecutionModelTaskNV = 5267, + ExecutionModelMeshNV = 5268, + ExecutionModelRayGenerationNV = 5313, + ExecutionModelIntersectionNV = 5314, + ExecutionModelAnyHitNV = 5315, + ExecutionModelClosestHitNV = 5316, + ExecutionModelMissNV = 5317, + ExecutionModelCallableNV = 5318, ExecutionModelMax = 0x7fffffff, }; @@ -80,6 +91,8 @@ enum AddressingModel { AddressingModelLogical = 0, AddressingModelPhysical32 = 1, AddressingModelPhysical64 = 2, + AddressingModelPhysicalStorageBuffer64 = 5348, + AddressingModelPhysicalStorageBuffer64EXT = 5348, AddressingModelMax = 0x7fffffff, }; @@ -87,6 +100,8 @@ enum MemoryModel { MemoryModelSimple = 0, MemoryModelGLSL450 = 1, MemoryModelOpenCL = 2, + MemoryModelVulkan = 3, + MemoryModelVulkanKHR = 3, MemoryModelMax = 0x7fffffff, }; @@ -130,7 +145,23 @@ enum ExecutionMode { ExecutionModeLocalSizeId = 38, ExecutionModeLocalSizeHintId = 39, ExecutionModePostDepthCoverage = 4446, + ExecutionModeDenormPreserve = 4459, + ExecutionModeDenormFlushToZero = 4460, + ExecutionModeSignedZeroInfNanPreserve = 4461, + ExecutionModeRoundingModeRTE = 4462, + ExecutionModeRoundingModeRTZ = 4463, ExecutionModeStencilRefReplacingEXT = 5027, + ExecutionModeOutputLinesNV = 5269, + ExecutionModeOutputPrimitivesNV = 5270, + ExecutionModeDerivativeGroupQuadsNV = 5289, + ExecutionModeDerivativeGroupLinearNV = 5290, + ExecutionModeOutputTrianglesNV = 5298, + ExecutionModePixelInterlockOrderedEXT = 5366, + ExecutionModePixelInterlockUnorderedEXT = 5367, + ExecutionModeSampleInterlockOrderedEXT = 5368, + ExecutionModeSampleInterlockUnorderedEXT = 5369, + ExecutionModeShadingRateInterlockOrderedEXT = 5370, + ExecutionModeShadingRateInterlockUnorderedEXT = 5371, ExecutionModeMax = 0x7fffffff, }; @@ -148,6 +179,14 @@ enum StorageClass { StorageClassAtomicCounter = 10, StorageClassImage = 11, StorageClassStorageBuffer = 12, + StorageClassCallableDataNV = 5328, + StorageClassIncomingCallableDataNV = 5329, + StorageClassRayPayloadNV = 5338, + StorageClassHitAttributeNV = 5339, + StorageClassIncomingRayPayloadNV = 5342, + StorageClassShaderRecordBufferNV = 5343, + StorageClassPhysicalStorageBuffer = 5349, + StorageClassPhysicalStorageBufferEXT = 5349, StorageClassMax = 0x7fffffff, }; @@ -275,6 +314,16 @@ enum ImageOperandsShift { ImageOperandsConstOffsetsShift = 5, ImageOperandsSampleShift = 6, ImageOperandsMinLodShift = 7, + ImageOperandsMakeTexelAvailableShift = 8, + ImageOperandsMakeTexelAvailableKHRShift = 8, + ImageOperandsMakeTexelVisibleShift = 9, + ImageOperandsMakeTexelVisibleKHRShift = 9, + ImageOperandsNonPrivateTexelShift = 10, + ImageOperandsNonPrivateTexelKHRShift = 10, + ImageOperandsVolatileTexelShift = 11, + ImageOperandsVolatileTexelKHRShift = 11, + ImageOperandsSignExtendShift = 12, + ImageOperandsZeroExtendShift = 13, ImageOperandsMax = 0x7fffffff, }; @@ -288,6 +337,16 @@ enum ImageOperandsMask { ImageOperandsConstOffsetsMask = 0x00000020, ImageOperandsSampleMask = 0x00000040, ImageOperandsMinLodMask = 0x00000080, + ImageOperandsMakeTexelAvailableMask = 0x00000100, + ImageOperandsMakeTexelAvailableKHRMask = 0x00000100, + ImageOperandsMakeTexelVisibleMask = 0x00000200, + ImageOperandsMakeTexelVisibleKHRMask = 0x00000200, + ImageOperandsNonPrivateTexelMask = 0x00000400, + ImageOperandsNonPrivateTexelKHRMask = 0x00000400, + ImageOperandsVolatileTexelMask = 0x00000800, + ImageOperandsVolatileTexelKHRMask = 0x00000800, + ImageOperandsSignExtendMask = 0x00001000, + ImageOperandsZeroExtendMask = 0x00002000, }; enum FPFastMathModeShift { @@ -368,6 +427,7 @@ enum Decoration { DecorationNonWritable = 24, DecorationNonReadable = 25, DecorationUniform = 26, + DecorationUniformId = 27, DecorationSaturatedConversion = 28, DecorationStream = 29, DecorationLocation = 30, @@ -388,14 +448,28 @@ enum Decoration { DecorationMaxByteOffset = 45, DecorationAlignmentId = 46, DecorationMaxByteOffsetId = 47, + DecorationNoSignedWrap = 4469, + DecorationNoUnsignedWrap = 4470, DecorationExplicitInterpAMD = 4999, DecorationOverrideCoverageNV = 5248, DecorationPassthroughNV = 5250, DecorationViewportRelativeNV = 5252, DecorationSecondaryViewportRelativeNV = 5256, + DecorationPerPrimitiveNV = 5271, + DecorationPerViewNV = 5272, + DecorationPerTaskNV = 5273, + DecorationPerVertexNV = 5285, + DecorationNonUniform = 5300, DecorationNonUniformEXT = 5300, + DecorationRestrictPointer = 5355, + DecorationRestrictPointerEXT = 5355, + DecorationAliasedPointer = 5356, + DecorationAliasedPointerEXT = 5356, + DecorationCounterBuffer = 5634, DecorationHlslCounterBufferGOOGLE = 5634, DecorationHlslSemanticGOOGLE = 5635, + DecorationUserSemantic = 5635, + DecorationUserTypeGOOGLE = 5636, DecorationMax = 0x7fffffff, }; @@ -470,6 +544,38 @@ enum BuiltIn { BuiltInPositionPerViewNV = 5261, BuiltInViewportMaskPerViewNV = 5262, BuiltInFullyCoveredEXT = 5264, + BuiltInTaskCountNV = 5274, + BuiltInPrimitiveCountNV = 5275, + BuiltInPrimitiveIndicesNV = 5276, + BuiltInClipDistancePerViewNV = 5277, + BuiltInCullDistancePerViewNV = 5278, + BuiltInLayerPerViewNV = 5279, + BuiltInMeshViewCountNV = 5280, + BuiltInMeshViewIndicesNV = 5281, + BuiltInBaryCoordNV = 5286, + BuiltInBaryCoordNoPerspNV = 5287, + BuiltInFragSizeEXT = 5292, + BuiltInFragmentSizeNV = 5292, + BuiltInFragInvocationCountEXT = 5293, + BuiltInInvocationsPerPixelNV = 5293, + BuiltInLaunchIdNV = 5319, + BuiltInLaunchSizeNV = 5320, + BuiltInWorldRayOriginNV = 5321, + BuiltInWorldRayDirectionNV = 5322, + BuiltInObjectRayOriginNV = 5323, + BuiltInObjectRayDirectionNV = 5324, + BuiltInRayTminNV = 5325, + BuiltInRayTmaxNV = 5326, + BuiltInInstanceCustomIndexNV = 5327, + BuiltInObjectToWorldNV = 5330, + BuiltInWorldToObjectNV = 5331, + BuiltInHitTNV = 5332, + BuiltInHitKindNV = 5333, + BuiltInIncomingRayFlagsNV = 5351, + BuiltInWarpsPerSMNV = 5374, + BuiltInSMCountNV = 5375, + BuiltInWarpIDNV = 5376, + BuiltInSMIDNV = 5377, BuiltInMax = 0x7fffffff, }; @@ -490,6 +596,11 @@ enum LoopControlShift { LoopControlDontUnrollShift = 1, LoopControlDependencyInfiniteShift = 2, LoopControlDependencyLengthShift = 3, + LoopControlMinIterationsShift = 4, + LoopControlMaxIterationsShift = 5, + LoopControlIterationMultipleShift = 6, + LoopControlPeelCountShift = 7, + LoopControlPartialCountShift = 8, LoopControlMax = 0x7fffffff, }; @@ -499,6 +610,11 @@ enum LoopControlMask { LoopControlDontUnrollMask = 0x00000002, LoopControlDependencyInfiniteMask = 0x00000004, LoopControlDependencyLengthMask = 0x00000008, + LoopControlMinIterationsMask = 0x00000010, + LoopControlMaxIterationsMask = 0x00000020, + LoopControlIterationMultipleMask = 0x00000040, + LoopControlPeelCountMask = 0x00000080, + LoopControlPartialCountMask = 0x00000100, }; enum FunctionControlShift { @@ -528,6 +644,13 @@ enum MemorySemanticsShift { MemorySemanticsCrossWorkgroupMemoryShift = 9, MemorySemanticsAtomicCounterMemoryShift = 10, MemorySemanticsImageMemoryShift = 11, + MemorySemanticsOutputMemoryShift = 12, + MemorySemanticsOutputMemoryKHRShift = 12, + MemorySemanticsMakeAvailableShift = 13, + MemorySemanticsMakeAvailableKHRShift = 13, + MemorySemanticsMakeVisibleShift = 14, + MemorySemanticsMakeVisibleKHRShift = 14, + MemorySemanticsVolatileShift = 15, MemorySemanticsMax = 0x7fffffff, }; @@ -543,12 +666,25 @@ enum MemorySemanticsMask { MemorySemanticsCrossWorkgroupMemoryMask = 0x00000200, MemorySemanticsAtomicCounterMemoryMask = 0x00000400, MemorySemanticsImageMemoryMask = 0x00000800, + MemorySemanticsOutputMemoryMask = 0x00001000, + MemorySemanticsOutputMemoryKHRMask = 0x00001000, + MemorySemanticsMakeAvailableMask = 0x00002000, + MemorySemanticsMakeAvailableKHRMask = 0x00002000, + MemorySemanticsMakeVisibleMask = 0x00004000, + MemorySemanticsMakeVisibleKHRMask = 0x00004000, + MemorySemanticsVolatileMask = 0x00008000, }; enum MemoryAccessShift { MemoryAccessVolatileShift = 0, MemoryAccessAlignedShift = 1, MemoryAccessNontemporalShift = 2, + MemoryAccessMakePointerAvailableShift = 3, + MemoryAccessMakePointerAvailableKHRShift = 3, + MemoryAccessMakePointerVisibleShift = 4, + MemoryAccessMakePointerVisibleKHRShift = 4, + MemoryAccessNonPrivatePointerShift = 5, + MemoryAccessNonPrivatePointerKHRShift = 5, MemoryAccessMax = 0x7fffffff, }; @@ -557,6 +693,12 @@ enum MemoryAccessMask { MemoryAccessVolatileMask = 0x00000001, MemoryAccessAlignedMask = 0x00000002, MemoryAccessNontemporalMask = 0x00000004, + MemoryAccessMakePointerAvailableMask = 0x00000008, + MemoryAccessMakePointerAvailableKHRMask = 0x00000008, + MemoryAccessMakePointerVisibleMask = 0x00000010, + MemoryAccessMakePointerVisibleKHRMask = 0x00000010, + MemoryAccessNonPrivatePointerMask = 0x00000020, + MemoryAccessNonPrivatePointerKHRMask = 0x00000020, }; enum Scope { @@ -565,6 +707,8 @@ enum Scope { ScopeWorkgroup = 2, ScopeSubgroup = 3, ScopeInvocation = 4, + ScopeQueueFamily = 5, + ScopeQueueFamilyKHR = 5, ScopeMax = 0x7fffffff, }; @@ -664,6 +808,8 @@ enum Capability { CapabilityGroupNonUniformShuffleRelative = 66, CapabilityGroupNonUniformClustered = 67, CapabilityGroupNonUniformQuad = 68, + CapabilityShaderLayer = 69, + CapabilityShaderViewportIndex = 70, CapabilitySubgroupBallotKHR = 4423, CapabilityDrawParameters = 4427, CapabilitySubgroupVoteKHR = 4431, @@ -682,11 +828,17 @@ enum Capability { CapabilityStorageBuffer8BitAccess = 4448, CapabilityUniformAndStorageBuffer8BitAccess = 4449, CapabilityStoragePushConstant8 = 4450, + CapabilityDenormPreserve = 4464, + CapabilityDenormFlushToZero = 4465, + CapabilitySignedZeroInfNanPreserve = 4466, + CapabilityRoundingModeRTE = 4467, + CapabilityRoundingModeRTZ = 4468, CapabilityFloat16ImageAMD = 5008, CapabilityImageGatherBiasLodAMD = 5009, CapabilityFragmentMaskAMD = 5010, CapabilityStencilExportEXT = 5013, CapabilityImageReadWriteLodAMD = 5015, + CapabilityShaderClockKHR = 5055, CapabilitySampleMaskOverrideCoverageNV = 5249, CapabilityGeometryShaderPassthroughNV = 5251, CapabilityShaderViewportIndexLayerEXT = 5254, @@ -695,22 +847,59 @@ enum Capability { CapabilityShaderStereoViewNV = 5259, CapabilityPerViewAttributesNV = 5260, CapabilityFragmentFullyCoveredEXT = 5265, + CapabilityMeshShadingNV = 5266, + CapabilityImageFootprintNV = 5282, + CapabilityFragmentBarycentricNV = 5284, + CapabilityComputeDerivativeGroupQuadsNV = 5288, + CapabilityFragmentDensityEXT = 5291, + CapabilityShadingRateNV = 5291, CapabilityGroupNonUniformPartitionedNV = 5297, + CapabilityShaderNonUniform = 5301, CapabilityShaderNonUniformEXT = 5301, + CapabilityRuntimeDescriptorArray = 5302, CapabilityRuntimeDescriptorArrayEXT = 5302, + CapabilityInputAttachmentArrayDynamicIndexing = 5303, CapabilityInputAttachmentArrayDynamicIndexingEXT = 5303, + CapabilityUniformTexelBufferArrayDynamicIndexing = 5304, CapabilityUniformTexelBufferArrayDynamicIndexingEXT = 5304, + CapabilityStorageTexelBufferArrayDynamicIndexing = 5305, CapabilityStorageTexelBufferArrayDynamicIndexingEXT = 5305, + CapabilityUniformBufferArrayNonUniformIndexing = 5306, CapabilityUniformBufferArrayNonUniformIndexingEXT = 5306, + CapabilitySampledImageArrayNonUniformIndexing = 5307, CapabilitySampledImageArrayNonUniformIndexingEXT = 5307, + CapabilityStorageBufferArrayNonUniformIndexing = 5308, CapabilityStorageBufferArrayNonUniformIndexingEXT = 5308, + CapabilityStorageImageArrayNonUniformIndexing = 5309, CapabilityStorageImageArrayNonUniformIndexingEXT = 5309, + CapabilityInputAttachmentArrayNonUniformIndexing = 5310, CapabilityInputAttachmentArrayNonUniformIndexingEXT = 5310, + CapabilityUniformTexelBufferArrayNonUniformIndexing = 5311, CapabilityUniformTexelBufferArrayNonUniformIndexingEXT = 5311, + CapabilityStorageTexelBufferArrayNonUniformIndexing = 5312, CapabilityStorageTexelBufferArrayNonUniformIndexingEXT = 5312, + CapabilityRayTracingNV = 5340, + CapabilityVulkanMemoryModel = 5345, + CapabilityVulkanMemoryModelKHR = 5345, + CapabilityVulkanMemoryModelDeviceScope = 5346, + CapabilityVulkanMemoryModelDeviceScopeKHR = 5346, + CapabilityPhysicalStorageBufferAddresses = 5347, + CapabilityPhysicalStorageBufferAddressesEXT = 5347, + CapabilityComputeDerivativeGroupLinearNV = 5350, + CapabilityCooperativeMatrixNV = 5357, + CapabilityFragmentShaderSampleInterlockEXT = 5363, + CapabilityFragmentShaderShadingRateInterlockEXT = 5372, + CapabilityShaderSMBuiltinsNV = 5373, + CapabilityFragmentShaderPixelInterlockEXT = 5378, + CapabilityDemoteToHelperInvocationEXT = 5379, CapabilitySubgroupShuffleINTEL = 5568, CapabilitySubgroupBufferBlockIOINTEL = 5569, CapabilitySubgroupImageBlockIOINTEL = 5570, + CapabilitySubgroupImageMediaBlockIOINTEL = 5579, + CapabilityIntegerFunctions2INTEL = 5584, + CapabilitySubgroupAvcMotionEstimationINTEL = 5696, + CapabilitySubgroupAvcMotionEstimationIntraINTEL = 5697, + CapabilitySubgroupAvcMotionEstimationChromaINTEL = 5698, CapabilityMax = 0x7fffffff, }; @@ -1055,6 +1244,10 @@ enum Op { OpGroupNonUniformLogicalXor = 364, OpGroupNonUniformQuadBroadcast = 365, OpGroupNonUniformQuadSwap = 366, + OpCopyLogical = 400, + OpPtrEqual = 401, + OpPtrNotEqual = 402, + OpPtrDiff = 403, OpSubgroupBallotKHR = 4421, OpSubgroupFirstInvocationKHR = 4422, OpSubgroupAllKHR = 4428, @@ -1071,7 +1264,25 @@ enum Op { OpGroupSMaxNonUniformAMD = 5007, OpFragmentMaskFetchAMD = 5011, OpFragmentFetchAMD = 5012, + OpReadClockKHR = 5056, + OpImageSampleFootprintNV = 5283, OpGroupNonUniformPartitionNV = 5296, + OpWritePackedPrimitiveIndices4x8NV = 5299, + OpReportIntersectionNV = 5334, + OpIgnoreIntersectionNV = 5335, + OpTerminateRayNV = 5336, + OpTraceNV = 5337, + OpTypeAccelerationStructureNV = 5341, + OpExecuteCallableNV = 5344, + OpTypeCooperativeMatrixNV = 5358, + OpCooperativeMatrixLoadNV = 5359, + OpCooperativeMatrixStoreNV = 5360, + OpCooperativeMatrixMulAddNV = 5361, + OpCooperativeMatrixLengthNV = 5362, + OpBeginInvocationInterlockEXT = 5364, + OpEndInvocationInterlockEXT = 5365, + OpDemoteToHelperInvocationEXT = 5380, + OpIsHelperInvocationEXT = 5381, OpSubgroupShuffleINTEL = 5571, OpSubgroupShuffleDownINTEL = 5572, OpSubgroupShuffleUpINTEL = 5573, @@ -1080,11 +1291,679 @@ enum Op { OpSubgroupBlockWriteINTEL = 5576, OpSubgroupImageBlockReadINTEL = 5577, OpSubgroupImageBlockWriteINTEL = 5578, + OpSubgroupImageMediaBlockReadINTEL = 5580, + OpSubgroupImageMediaBlockWriteINTEL = 5581, + OpUCountLeadingZerosINTEL = 5585, + OpUCountTrailingZerosINTEL = 5586, + OpAbsISubINTEL = 5587, + OpAbsUSubINTEL = 5588, + OpIAddSatINTEL = 5589, + OpUAddSatINTEL = 5590, + OpIAverageINTEL = 5591, + OpUAverageINTEL = 5592, + OpIAverageRoundedINTEL = 5593, + OpUAverageRoundedINTEL = 5594, + OpISubSatINTEL = 5595, + OpUSubSatINTEL = 5596, + OpIMul32x16INTEL = 5597, + OpUMul32x16INTEL = 5598, + OpDecorateString = 5632, OpDecorateStringGOOGLE = 5632, + OpMemberDecorateString = 5633, OpMemberDecorateStringGOOGLE = 5633, + OpVmeImageINTEL = 5699, + OpTypeVmeImageINTEL = 5700, + OpTypeAvcImePayloadINTEL = 5701, + OpTypeAvcRefPayloadINTEL = 5702, + OpTypeAvcSicPayloadINTEL = 5703, + OpTypeAvcMcePayloadINTEL = 5704, + OpTypeAvcMceResultINTEL = 5705, + OpTypeAvcImeResultINTEL = 5706, + OpTypeAvcImeResultSingleReferenceStreamoutINTEL = 5707, + OpTypeAvcImeResultDualReferenceStreamoutINTEL = 5708, + OpTypeAvcImeSingleReferenceStreaminINTEL = 5709, + OpTypeAvcImeDualReferenceStreaminINTEL = 5710, + OpTypeAvcRefResultINTEL = 5711, + OpTypeAvcSicResultINTEL = 5712, + OpSubgroupAvcMceGetDefaultInterBaseMultiReferencePenaltyINTEL = 5713, + OpSubgroupAvcMceSetInterBaseMultiReferencePenaltyINTEL = 5714, + OpSubgroupAvcMceGetDefaultInterShapePenaltyINTEL = 5715, + OpSubgroupAvcMceSetInterShapePenaltyINTEL = 5716, + OpSubgroupAvcMceGetDefaultInterDirectionPenaltyINTEL = 5717, + OpSubgroupAvcMceSetInterDirectionPenaltyINTEL = 5718, + OpSubgroupAvcMceGetDefaultIntraLumaShapePenaltyINTEL = 5719, + OpSubgroupAvcMceGetDefaultInterMotionVectorCostTableINTEL = 5720, + OpSubgroupAvcMceGetDefaultHighPenaltyCostTableINTEL = 5721, + OpSubgroupAvcMceGetDefaultMediumPenaltyCostTableINTEL = 5722, + OpSubgroupAvcMceGetDefaultLowPenaltyCostTableINTEL = 5723, + OpSubgroupAvcMceSetMotionVectorCostFunctionINTEL = 5724, + OpSubgroupAvcMceGetDefaultIntraLumaModePenaltyINTEL = 5725, + OpSubgroupAvcMceGetDefaultNonDcLumaIntraPenaltyINTEL = 5726, + OpSubgroupAvcMceGetDefaultIntraChromaModeBasePenaltyINTEL = 5727, + OpSubgroupAvcMceSetAcOnlyHaarINTEL = 5728, + OpSubgroupAvcMceSetSourceInterlacedFieldPolarityINTEL = 5729, + OpSubgroupAvcMceSetSingleReferenceInterlacedFieldPolarityINTEL = 5730, + OpSubgroupAvcMceSetDualReferenceInterlacedFieldPolaritiesINTEL = 5731, + OpSubgroupAvcMceConvertToImePayloadINTEL = 5732, + OpSubgroupAvcMceConvertToImeResultINTEL = 5733, + OpSubgroupAvcMceConvertToRefPayloadINTEL = 5734, + OpSubgroupAvcMceConvertToRefResultINTEL = 5735, + OpSubgroupAvcMceConvertToSicPayloadINTEL = 5736, + OpSubgroupAvcMceConvertToSicResultINTEL = 5737, + OpSubgroupAvcMceGetMotionVectorsINTEL = 5738, + OpSubgroupAvcMceGetInterDistortionsINTEL = 5739, + OpSubgroupAvcMceGetBestInterDistortionsINTEL = 5740, + OpSubgroupAvcMceGetInterMajorShapeINTEL = 5741, + OpSubgroupAvcMceGetInterMinorShapeINTEL = 5742, + OpSubgroupAvcMceGetInterDirectionsINTEL = 5743, + OpSubgroupAvcMceGetInterMotionVectorCountINTEL = 5744, + OpSubgroupAvcMceGetInterReferenceIdsINTEL = 5745, + OpSubgroupAvcMceGetInterReferenceInterlacedFieldPolaritiesINTEL = 5746, + OpSubgroupAvcImeInitializeINTEL = 5747, + OpSubgroupAvcImeSetSingleReferenceINTEL = 5748, + OpSubgroupAvcImeSetDualReferenceINTEL = 5749, + OpSubgroupAvcImeRefWindowSizeINTEL = 5750, + OpSubgroupAvcImeAdjustRefOffsetINTEL = 5751, + OpSubgroupAvcImeConvertToMcePayloadINTEL = 5752, + OpSubgroupAvcImeSetMaxMotionVectorCountINTEL = 5753, + OpSubgroupAvcImeSetUnidirectionalMixDisableINTEL = 5754, + OpSubgroupAvcImeSetEarlySearchTerminationThresholdINTEL = 5755, + OpSubgroupAvcImeSetWeightedSadINTEL = 5756, + OpSubgroupAvcImeEvaluateWithSingleReferenceINTEL = 5757, + OpSubgroupAvcImeEvaluateWithDualReferenceINTEL = 5758, + OpSubgroupAvcImeEvaluateWithSingleReferenceStreaminINTEL = 5759, + OpSubgroupAvcImeEvaluateWithDualReferenceStreaminINTEL = 5760, + OpSubgroupAvcImeEvaluateWithSingleReferenceStreamoutINTEL = 5761, + OpSubgroupAvcImeEvaluateWithDualReferenceStreamoutINTEL = 5762, + OpSubgroupAvcImeEvaluateWithSingleReferenceStreaminoutINTEL = 5763, + OpSubgroupAvcImeEvaluateWithDualReferenceStreaminoutINTEL = 5764, + OpSubgroupAvcImeConvertToMceResultINTEL = 5765, + OpSubgroupAvcImeGetSingleReferenceStreaminINTEL = 5766, + OpSubgroupAvcImeGetDualReferenceStreaminINTEL = 5767, + OpSubgroupAvcImeStripSingleReferenceStreamoutINTEL = 5768, + OpSubgroupAvcImeStripDualReferenceStreamoutINTEL = 5769, + OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeMotionVectorsINTEL = 5770, + OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeDistortionsINTEL = 5771, + OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeReferenceIdsINTEL = 5772, + OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeMotionVectorsINTEL = 5773, + OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeDistortionsINTEL = 5774, + OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeReferenceIdsINTEL = 5775, + OpSubgroupAvcImeGetBorderReachedINTEL = 5776, + OpSubgroupAvcImeGetTruncatedSearchIndicationINTEL = 5777, + OpSubgroupAvcImeGetUnidirectionalEarlySearchTerminationINTEL = 5778, + OpSubgroupAvcImeGetWeightingPatternMinimumMotionVectorINTEL = 5779, + OpSubgroupAvcImeGetWeightingPatternMinimumDistortionINTEL = 5780, + OpSubgroupAvcFmeInitializeINTEL = 5781, + OpSubgroupAvcBmeInitializeINTEL = 5782, + OpSubgroupAvcRefConvertToMcePayloadINTEL = 5783, + OpSubgroupAvcRefSetBidirectionalMixDisableINTEL = 5784, + OpSubgroupAvcRefSetBilinearFilterEnableINTEL = 5785, + OpSubgroupAvcRefEvaluateWithSingleReferenceINTEL = 5786, + OpSubgroupAvcRefEvaluateWithDualReferenceINTEL = 5787, + OpSubgroupAvcRefEvaluateWithMultiReferenceINTEL = 5788, + OpSubgroupAvcRefEvaluateWithMultiReferenceInterlacedINTEL = 5789, + OpSubgroupAvcRefConvertToMceResultINTEL = 5790, + OpSubgroupAvcSicInitializeINTEL = 5791, + OpSubgroupAvcSicConfigureSkcINTEL = 5792, + OpSubgroupAvcSicConfigureIpeLumaINTEL = 5793, + OpSubgroupAvcSicConfigureIpeLumaChromaINTEL = 5794, + OpSubgroupAvcSicGetMotionVectorMaskINTEL = 5795, + OpSubgroupAvcSicConvertToMcePayloadINTEL = 5796, + OpSubgroupAvcSicSetIntraLumaShapePenaltyINTEL = 5797, + OpSubgroupAvcSicSetIntraLumaModeCostFunctionINTEL = 5798, + OpSubgroupAvcSicSetIntraChromaModeCostFunctionINTEL = 5799, + OpSubgroupAvcSicSetBilinearFilterEnableINTEL = 5800, + OpSubgroupAvcSicSetSkcForwardTransformEnableINTEL = 5801, + OpSubgroupAvcSicSetBlockBasedRawSkipSadINTEL = 5802, + OpSubgroupAvcSicEvaluateIpeINTEL = 5803, + OpSubgroupAvcSicEvaluateWithSingleReferenceINTEL = 5804, + OpSubgroupAvcSicEvaluateWithDualReferenceINTEL = 5805, + OpSubgroupAvcSicEvaluateWithMultiReferenceINTEL = 5806, + OpSubgroupAvcSicEvaluateWithMultiReferenceInterlacedINTEL = 5807, + OpSubgroupAvcSicConvertToMceResultINTEL = 5808, + OpSubgroupAvcSicGetIpeLumaShapeINTEL = 5809, + OpSubgroupAvcSicGetBestIpeLumaDistortionINTEL = 5810, + OpSubgroupAvcSicGetBestIpeChromaDistortionINTEL = 5811, + OpSubgroupAvcSicGetPackedIpeLumaModesINTEL = 5812, + OpSubgroupAvcSicGetIpeChromaModeINTEL = 5813, + OpSubgroupAvcSicGetPackedSkcLumaCountThresholdINTEL = 5814, + OpSubgroupAvcSicGetPackedSkcLumaSumThresholdINTEL = 5815, + OpSubgroupAvcSicGetInterRawSadsINTEL = 5816, OpMax = 0x7fffffff, }; +#ifdef SPV_ENABLE_UTILITY_CODE +inline void HasResultAndType(Op opcode, bool *hasResult, bool *hasResultType) { + *hasResult = *hasResultType = false; + switch (opcode) { + default: /* unknown opcode */ break; + case OpNop: *hasResult = false; *hasResultType = false; break; + case OpUndef: *hasResult = true; *hasResultType = true; break; + case OpSourceContinued: *hasResult = false; *hasResultType = false; break; + case OpSource: *hasResult = false; *hasResultType = false; break; + case OpSourceExtension: *hasResult = false; *hasResultType = false; break; + case OpName: *hasResult = false; *hasResultType = false; break; + case OpMemberName: *hasResult = false; *hasResultType = false; break; + case OpString: *hasResult = true; *hasResultType = false; break; + case OpLine: *hasResult = false; *hasResultType = false; break; + case OpExtension: *hasResult = false; *hasResultType = false; break; + case OpExtInstImport: *hasResult = true; *hasResultType = false; break; + case OpExtInst: *hasResult = true; *hasResultType = true; break; + case OpMemoryModel: *hasResult = false; *hasResultType = false; break; + case OpEntryPoint: *hasResult = false; *hasResultType = false; break; + case OpExecutionMode: *hasResult = false; *hasResultType = false; break; + case OpCapability: *hasResult = false; *hasResultType = false; break; + case OpTypeVoid: *hasResult = true; *hasResultType = false; break; + case OpTypeBool: *hasResult = true; *hasResultType = false; break; + case OpTypeInt: *hasResult = true; *hasResultType = false; break; + case OpTypeFloat: *hasResult = true; *hasResultType = false; break; + case OpTypeVector: *hasResult = true; *hasResultType = false; break; + case OpTypeMatrix: *hasResult = true; *hasResultType = false; break; + case OpTypeImage: *hasResult = true; *hasResultType = false; break; + case OpTypeSampler: *hasResult = true; *hasResultType = false; break; + case OpTypeSampledImage: *hasResult = true; *hasResultType = false; break; + case OpTypeArray: *hasResult = true; *hasResultType = false; break; + case OpTypeRuntimeArray: *hasResult = true; *hasResultType = false; break; + case OpTypeStruct: *hasResult = true; *hasResultType = false; break; + case OpTypeOpaque: *hasResult = true; *hasResultType = false; break; + case OpTypePointer: *hasResult = true; *hasResultType = false; break; + case OpTypeFunction: *hasResult = true; *hasResultType = false; break; + case OpTypeEvent: *hasResult = true; *hasResultType = false; break; + case OpTypeDeviceEvent: *hasResult = true; *hasResultType = false; break; + case OpTypeReserveId: *hasResult = true; *hasResultType = false; break; + case OpTypeQueue: *hasResult = true; *hasResultType = false; break; + case OpTypePipe: *hasResult = true; *hasResultType = false; break; + case OpTypeForwardPointer: *hasResult = false; *hasResultType = false; break; + case OpConstantTrue: *hasResult = true; *hasResultType = true; break; + case OpConstantFalse: *hasResult = true; *hasResultType = true; break; + case OpConstant: *hasResult = true; *hasResultType = true; break; + case OpConstantComposite: *hasResult = true; *hasResultType = true; break; + case OpConstantSampler: *hasResult = true; *hasResultType = true; break; + case OpConstantNull: *hasResult = true; *hasResultType = true; break; + case OpSpecConstantTrue: *hasResult = true; *hasResultType = true; break; + case OpSpecConstantFalse: *hasResult = true; *hasResultType = true; break; + case OpSpecConstant: *hasResult = true; *hasResultType = true; break; + case OpSpecConstantComposite: *hasResult = true; *hasResultType = true; break; + case OpSpecConstantOp: *hasResult = true; *hasResultType = true; break; + case OpFunction: *hasResult = true; *hasResultType = true; break; + case OpFunctionParameter: *hasResult = true; *hasResultType = true; break; + case OpFunctionEnd: *hasResult = false; *hasResultType = false; break; + case OpFunctionCall: *hasResult = true; *hasResultType = true; break; + case OpVariable: *hasResult = true; *hasResultType = true; break; + case OpImageTexelPointer: *hasResult = true; *hasResultType = true; break; + case OpLoad: *hasResult = true; *hasResultType = true; break; + case OpStore: *hasResult = false; *hasResultType = false; break; + case OpCopyMemory: *hasResult = false; *hasResultType = false; break; + case OpCopyMemorySized: *hasResult = false; *hasResultType = false; break; + case OpAccessChain: *hasResult = true; *hasResultType = true; break; + case OpInBoundsAccessChain: *hasResult = true; *hasResultType = true; break; + case OpPtrAccessChain: *hasResult = true; *hasResultType = true; break; + case OpArrayLength: *hasResult = true; *hasResultType = true; break; + case OpGenericPtrMemSemantics: *hasResult = true; *hasResultType = true; break; + case OpInBoundsPtrAccessChain: *hasResult = true; *hasResultType = true; break; + case OpDecorate: *hasResult = false; *hasResultType = false; break; + case OpMemberDecorate: *hasResult = false; *hasResultType = false; break; + case OpDecorationGroup: *hasResult = true; *hasResultType = false; break; + case OpGroupDecorate: *hasResult = false; *hasResultType = false; break; + case OpGroupMemberDecorate: *hasResult = false; *hasResultType = false; break; + case OpVectorExtractDynamic: *hasResult = true; *hasResultType = true; break; + case OpVectorInsertDynamic: *hasResult = true; *hasResultType = true; break; + case OpVectorShuffle: *hasResult = true; *hasResultType = true; break; + case OpCompositeConstruct: *hasResult = true; *hasResultType = true; break; + case OpCompositeExtract: *hasResult = true; *hasResultType = true; break; + case OpCompositeInsert: *hasResult = true; *hasResultType = true; break; + case OpCopyObject: *hasResult = true; *hasResultType = true; break; + case OpTranspose: *hasResult = true; *hasResultType = true; break; + case OpSampledImage: *hasResult = true; *hasResultType = true; break; + case OpImageSampleImplicitLod: *hasResult = true; *hasResultType = true; break; + case OpImageSampleExplicitLod: *hasResult = true; *hasResultType = true; break; + case OpImageSampleDrefImplicitLod: *hasResult = true; *hasResultType = true; break; + case OpImageSampleDrefExplicitLod: *hasResult = true; *hasResultType = true; break; + case OpImageSampleProjImplicitLod: *hasResult = true; *hasResultType = true; break; + case OpImageSampleProjExplicitLod: *hasResult = true; *hasResultType = true; break; + case OpImageSampleProjDrefImplicitLod: *hasResult = true; *hasResultType = true; break; + case OpImageSampleProjDrefExplicitLod: *hasResult = true; *hasResultType = true; break; + case OpImageFetch: *hasResult = true; *hasResultType = true; break; + case OpImageGather: *hasResult = true; *hasResultType = true; break; + case OpImageDrefGather: *hasResult = true; *hasResultType = true; break; + case OpImageRead: *hasResult = true; *hasResultType = true; break; + case OpImageWrite: *hasResult = false; *hasResultType = false; break; + case OpImage: *hasResult = true; *hasResultType = true; break; + case OpImageQueryFormat: *hasResult = true; *hasResultType = true; break; + case OpImageQueryOrder: *hasResult = true; *hasResultType = true; break; + case OpImageQuerySizeLod: *hasResult = true; *hasResultType = true; break; + case OpImageQuerySize: *hasResult = true; *hasResultType = true; break; + case OpImageQueryLod: *hasResult = true; *hasResultType = true; break; + case OpImageQueryLevels: *hasResult = true; *hasResultType = true; break; + case OpImageQuerySamples: *hasResult = true; *hasResultType = true; break; + case OpConvertFToU: *hasResult = true; *hasResultType = true; break; + case OpConvertFToS: *hasResult = true; *hasResultType = true; break; + case OpConvertSToF: *hasResult = true; *hasResultType = true; break; + case OpConvertUToF: *hasResult = true; *hasResultType = true; break; + case OpUConvert: *hasResult = true; *hasResultType = true; break; + case OpSConvert: *hasResult = true; *hasResultType = true; break; + case OpFConvert: *hasResult = true; *hasResultType = true; break; + case OpQuantizeToF16: *hasResult = true; *hasResultType = true; break; + case OpConvertPtrToU: *hasResult = true; *hasResultType = true; break; + case OpSatConvertSToU: *hasResult = true; *hasResultType = true; break; + case OpSatConvertUToS: *hasResult = true; *hasResultType = true; break; + case OpConvertUToPtr: *hasResult = true; *hasResultType = true; break; + case OpPtrCastToGeneric: *hasResult = true; *hasResultType = true; break; + case OpGenericCastToPtr: *hasResult = true; *hasResultType = true; break; + case OpGenericCastToPtrExplicit: *hasResult = true; *hasResultType = true; break; + case OpBitcast: *hasResult = true; *hasResultType = true; break; + case OpSNegate: *hasResult = true; *hasResultType = true; break; + case OpFNegate: *hasResult = true; *hasResultType = true; break; + case OpIAdd: *hasResult = true; *hasResultType = true; break; + case OpFAdd: *hasResult = true; *hasResultType = true; break; + case OpISub: *hasResult = true; *hasResultType = true; break; + case OpFSub: *hasResult = true; *hasResultType = true; break; + case OpIMul: *hasResult = true; *hasResultType = true; break; + case OpFMul: *hasResult = true; *hasResultType = true; break; + case OpUDiv: *hasResult = true; *hasResultType = true; break; + case OpSDiv: *hasResult = true; *hasResultType = true; break; + case OpFDiv: *hasResult = true; *hasResultType = true; break; + case OpUMod: *hasResult = true; *hasResultType = true; break; + case OpSRem: *hasResult = true; *hasResultType = true; break; + case OpSMod: *hasResult = true; *hasResultType = true; break; + case OpFRem: *hasResult = true; *hasResultType = true; break; + case OpFMod: *hasResult = true; *hasResultType = true; break; + case OpVectorTimesScalar: *hasResult = true; *hasResultType = true; break; + case OpMatrixTimesScalar: *hasResult = true; *hasResultType = true; break; + case OpVectorTimesMatrix: *hasResult = true; *hasResultType = true; break; + case OpMatrixTimesVector: *hasResult = true; *hasResultType = true; break; + case OpMatrixTimesMatrix: *hasResult = true; *hasResultType = true; break; + case OpOuterProduct: *hasResult = true; *hasResultType = true; break; + case OpDot: *hasResult = true; *hasResultType = true; break; + case OpIAddCarry: *hasResult = true; *hasResultType = true; break; + case OpISubBorrow: *hasResult = true; *hasResultType = true; break; + case OpUMulExtended: *hasResult = true; *hasResultType = true; break; + case OpSMulExtended: *hasResult = true; *hasResultType = true; break; + case OpAny: *hasResult = true; *hasResultType = true; break; + case OpAll: *hasResult = true; *hasResultType = true; break; + case OpIsNan: *hasResult = true; *hasResultType = true; break; + case OpIsInf: *hasResult = true; *hasResultType = true; break; + case OpIsFinite: *hasResult = true; *hasResultType = true; break; + case OpIsNormal: *hasResult = true; *hasResultType = true; break; + case OpSignBitSet: *hasResult = true; *hasResultType = true; break; + case OpLessOrGreater: *hasResult = true; *hasResultType = true; break; + case OpOrdered: *hasResult = true; *hasResultType = true; break; + case OpUnordered: *hasResult = true; *hasResultType = true; break; + case OpLogicalEqual: *hasResult = true; *hasResultType = true; break; + case OpLogicalNotEqual: *hasResult = true; *hasResultType = true; break; + case OpLogicalOr: *hasResult = true; *hasResultType = true; break; + case OpLogicalAnd: *hasResult = true; *hasResultType = true; break; + case OpLogicalNot: *hasResult = true; *hasResultType = true; break; + case OpSelect: *hasResult = true; *hasResultType = true; break; + case OpIEqual: *hasResult = true; *hasResultType = true; break; + case OpINotEqual: *hasResult = true; *hasResultType = true; break; + case OpUGreaterThan: *hasResult = true; *hasResultType = true; break; + case OpSGreaterThan: *hasResult = true; *hasResultType = true; break; + case OpUGreaterThanEqual: *hasResult = true; *hasResultType = true; break; + case OpSGreaterThanEqual: *hasResult = true; *hasResultType = true; break; + case OpULessThan: *hasResult = true; *hasResultType = true; break; + case OpSLessThan: *hasResult = true; *hasResultType = true; break; + case OpULessThanEqual: *hasResult = true; *hasResultType = true; break; + case OpSLessThanEqual: *hasResult = true; *hasResultType = true; break; + case OpFOrdEqual: *hasResult = true; *hasResultType = true; break; + case OpFUnordEqual: *hasResult = true; *hasResultType = true; break; + case OpFOrdNotEqual: *hasResult = true; *hasResultType = true; break; + case OpFUnordNotEqual: *hasResult = true; *hasResultType = true; break; + case OpFOrdLessThan: *hasResult = true; *hasResultType = true; break; + case OpFUnordLessThan: *hasResult = true; *hasResultType = true; break; + case OpFOrdGreaterThan: *hasResult = true; *hasResultType = true; break; + case OpFUnordGreaterThan: *hasResult = true; *hasResultType = true; break; + case OpFOrdLessThanEqual: *hasResult = true; *hasResultType = true; break; + case OpFUnordLessThanEqual: *hasResult = true; *hasResultType = true; break; + case OpFOrdGreaterThanEqual: *hasResult = true; *hasResultType = true; break; + case OpFUnordGreaterThanEqual: *hasResult = true; *hasResultType = true; break; + case OpShiftRightLogical: *hasResult = true; *hasResultType = true; break; + case OpShiftRightArithmetic: *hasResult = true; *hasResultType = true; break; + case OpShiftLeftLogical: *hasResult = true; *hasResultType = true; break; + case OpBitwiseOr: *hasResult = true; *hasResultType = true; break; + case OpBitwiseXor: *hasResult = true; *hasResultType = true; break; + case OpBitwiseAnd: *hasResult = true; *hasResultType = true; break; + case OpNot: *hasResult = true; *hasResultType = true; break; + case OpBitFieldInsert: *hasResult = true; *hasResultType = true; break; + case OpBitFieldSExtract: *hasResult = true; *hasResultType = true; break; + case OpBitFieldUExtract: *hasResult = true; *hasResultType = true; break; + case OpBitReverse: *hasResult = true; *hasResultType = true; break; + case OpBitCount: *hasResult = true; *hasResultType = true; break; + case OpDPdx: *hasResult = true; *hasResultType = true; break; + case OpDPdy: *hasResult = true; *hasResultType = true; break; + case OpFwidth: *hasResult = true; *hasResultType = true; break; + case OpDPdxFine: *hasResult = true; *hasResultType = true; break; + case OpDPdyFine: *hasResult = true; *hasResultType = true; break; + case OpFwidthFine: *hasResult = true; *hasResultType = true; break; + case OpDPdxCoarse: *hasResult = true; *hasResultType = true; break; + case OpDPdyCoarse: *hasResult = true; *hasResultType = true; break; + case OpFwidthCoarse: *hasResult = true; *hasResultType = true; break; + case OpEmitVertex: *hasResult = false; *hasResultType = false; break; + case OpEndPrimitive: *hasResult = false; *hasResultType = false; break; + case OpEmitStreamVertex: *hasResult = false; *hasResultType = false; break; + case OpEndStreamPrimitive: *hasResult = false; *hasResultType = false; break; + case OpControlBarrier: *hasResult = false; *hasResultType = false; break; + case OpMemoryBarrier: *hasResult = false; *hasResultType = false; break; + case OpAtomicLoad: *hasResult = true; *hasResultType = true; break; + case OpAtomicStore: *hasResult = false; *hasResultType = false; break; + case OpAtomicExchange: *hasResult = true; *hasResultType = true; break; + case OpAtomicCompareExchange: *hasResult = true; *hasResultType = true; break; + case OpAtomicCompareExchangeWeak: *hasResult = true; *hasResultType = true; break; + case OpAtomicIIncrement: *hasResult = true; *hasResultType = true; break; + case OpAtomicIDecrement: *hasResult = true; *hasResultType = true; break; + case OpAtomicIAdd: *hasResult = true; *hasResultType = true; break; + case OpAtomicISub: *hasResult = true; *hasResultType = true; break; + case OpAtomicSMin: *hasResult = true; *hasResultType = true; break; + case OpAtomicUMin: *hasResult = true; *hasResultType = true; break; + case OpAtomicSMax: *hasResult = true; *hasResultType = true; break; + case OpAtomicUMax: *hasResult = true; *hasResultType = true; break; + case OpAtomicAnd: *hasResult = true; *hasResultType = true; break; + case OpAtomicOr: *hasResult = true; *hasResultType = true; break; + case OpAtomicXor: *hasResult = true; *hasResultType = true; break; + case OpPhi: *hasResult = true; *hasResultType = true; break; + case OpLoopMerge: *hasResult = false; *hasResultType = false; break; + case OpSelectionMerge: *hasResult = false; *hasResultType = false; break; + case OpLabel: *hasResult = true; *hasResultType = false; break; + case OpBranch: *hasResult = false; *hasResultType = false; break; + case OpBranchConditional: *hasResult = false; *hasResultType = false; break; + case OpSwitch: *hasResult = false; *hasResultType = false; break; + case OpKill: *hasResult = false; *hasResultType = false; break; + case OpReturn: *hasResult = false; *hasResultType = false; break; + case OpReturnValue: *hasResult = false; *hasResultType = false; break; + case OpUnreachable: *hasResult = false; *hasResultType = false; break; + case OpLifetimeStart: *hasResult = false; *hasResultType = false; break; + case OpLifetimeStop: *hasResult = false; *hasResultType = false; break; + case OpGroupAsyncCopy: *hasResult = true; *hasResultType = true; break; + case OpGroupWaitEvents: *hasResult = false; *hasResultType = false; break; + case OpGroupAll: *hasResult = true; *hasResultType = true; break; + case OpGroupAny: *hasResult = true; *hasResultType = true; break; + case OpGroupBroadcast: *hasResult = true; *hasResultType = true; break; + case OpGroupIAdd: *hasResult = true; *hasResultType = true; break; + case OpGroupFAdd: *hasResult = true; *hasResultType = true; break; + case OpGroupFMin: *hasResult = true; *hasResultType = true; break; + case OpGroupUMin: *hasResult = true; *hasResultType = true; break; + case OpGroupSMin: *hasResult = true; *hasResultType = true; break; + case OpGroupFMax: *hasResult = true; *hasResultType = true; break; + case OpGroupUMax: *hasResult = true; *hasResultType = true; break; + case OpGroupSMax: *hasResult = true; *hasResultType = true; break; + case OpReadPipe: *hasResult = true; *hasResultType = true; break; + case OpWritePipe: *hasResult = true; *hasResultType = true; break; + case OpReservedReadPipe: *hasResult = true; *hasResultType = true; break; + case OpReservedWritePipe: *hasResult = true; *hasResultType = true; break; + case OpReserveReadPipePackets: *hasResult = true; *hasResultType = true; break; + case OpReserveWritePipePackets: *hasResult = true; *hasResultType = true; break; + case OpCommitReadPipe: *hasResult = false; *hasResultType = false; break; + case OpCommitWritePipe: *hasResult = false; *hasResultType = false; break; + case OpIsValidReserveId: *hasResult = true; *hasResultType = true; break; + case OpGetNumPipePackets: *hasResult = true; *hasResultType = true; break; + case OpGetMaxPipePackets: *hasResult = true; *hasResultType = true; break; + case OpGroupReserveReadPipePackets: *hasResult = true; *hasResultType = true; break; + case OpGroupReserveWritePipePackets: *hasResult = true; *hasResultType = true; break; + case OpGroupCommitReadPipe: *hasResult = false; *hasResultType = false; break; + case OpGroupCommitWritePipe: *hasResult = false; *hasResultType = false; break; + case OpEnqueueMarker: *hasResult = true; *hasResultType = true; break; + case OpEnqueueKernel: *hasResult = true; *hasResultType = true; break; + case OpGetKernelNDrangeSubGroupCount: *hasResult = true; *hasResultType = true; break; + case OpGetKernelNDrangeMaxSubGroupSize: *hasResult = true; *hasResultType = true; break; + case OpGetKernelWorkGroupSize: *hasResult = true; *hasResultType = true; break; + case OpGetKernelPreferredWorkGroupSizeMultiple: *hasResult = true; *hasResultType = true; break; + case OpRetainEvent: *hasResult = false; *hasResultType = false; break; + case OpReleaseEvent: *hasResult = false; *hasResultType = false; break; + case OpCreateUserEvent: *hasResult = true; *hasResultType = true; break; + case OpIsValidEvent: *hasResult = true; *hasResultType = true; break; + case OpSetUserEventStatus: *hasResult = false; *hasResultType = false; break; + case OpCaptureEventProfilingInfo: *hasResult = false; *hasResultType = false; break; + case OpGetDefaultQueue: *hasResult = true; *hasResultType = true; break; + case OpBuildNDRange: *hasResult = true; *hasResultType = true; break; + case OpImageSparseSampleImplicitLod: *hasResult = true; *hasResultType = true; break; + case OpImageSparseSampleExplicitLod: *hasResult = true; *hasResultType = true; break; + case OpImageSparseSampleDrefImplicitLod: *hasResult = true; *hasResultType = true; break; + case OpImageSparseSampleDrefExplicitLod: *hasResult = true; *hasResultType = true; break; + case OpImageSparseSampleProjImplicitLod: *hasResult = true; *hasResultType = true; break; + case OpImageSparseSampleProjExplicitLod: *hasResult = true; *hasResultType = true; break; + case OpImageSparseSampleProjDrefImplicitLod: *hasResult = true; *hasResultType = true; break; + case OpImageSparseSampleProjDrefExplicitLod: *hasResult = true; *hasResultType = true; break; + case OpImageSparseFetch: *hasResult = true; *hasResultType = true; break; + case OpImageSparseGather: *hasResult = true; *hasResultType = true; break; + case OpImageSparseDrefGather: *hasResult = true; *hasResultType = true; break; + case OpImageSparseTexelsResident: *hasResult = true; *hasResultType = true; break; + case OpNoLine: *hasResult = false; *hasResultType = false; break; + case OpAtomicFlagTestAndSet: *hasResult = true; *hasResultType = true; break; + case OpAtomicFlagClear: *hasResult = false; *hasResultType = false; break; + case OpImageSparseRead: *hasResult = true; *hasResultType = true; break; + case OpSizeOf: *hasResult = true; *hasResultType = true; break; + case OpTypePipeStorage: *hasResult = true; *hasResultType = false; break; + case OpConstantPipeStorage: *hasResult = true; *hasResultType = true; break; + case OpCreatePipeFromPipeStorage: *hasResult = true; *hasResultType = true; break; + case OpGetKernelLocalSizeForSubgroupCount: *hasResult = true; *hasResultType = true; break; + case OpGetKernelMaxNumSubgroups: *hasResult = true; *hasResultType = true; break; + case OpTypeNamedBarrier: *hasResult = true; *hasResultType = false; break; + case OpNamedBarrierInitialize: *hasResult = true; *hasResultType = true; break; + case OpMemoryNamedBarrier: *hasResult = false; *hasResultType = false; break; + case OpModuleProcessed: *hasResult = false; *hasResultType = false; break; + case OpExecutionModeId: *hasResult = false; *hasResultType = false; break; + case OpDecorateId: *hasResult = false; *hasResultType = false; break; + case OpGroupNonUniformElect: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformAll: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformAny: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformAllEqual: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformBroadcast: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformBroadcastFirst: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformBallot: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformInverseBallot: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformBallotBitExtract: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformBallotBitCount: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformBallotFindLSB: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformBallotFindMSB: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformShuffle: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformShuffleXor: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformShuffleUp: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformShuffleDown: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformIAdd: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformFAdd: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformIMul: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformFMul: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformSMin: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformUMin: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformFMin: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformSMax: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformUMax: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformFMax: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformBitwiseAnd: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformBitwiseOr: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformBitwiseXor: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformLogicalAnd: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformLogicalOr: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformLogicalXor: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformQuadBroadcast: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformQuadSwap: *hasResult = true; *hasResultType = true; break; + case OpCopyLogical: *hasResult = true; *hasResultType = true; break; + case OpPtrEqual: *hasResult = true; *hasResultType = true; break; + case OpPtrNotEqual: *hasResult = true; *hasResultType = true; break; + case OpPtrDiff: *hasResult = true; *hasResultType = true; break; + case OpSubgroupBallotKHR: *hasResult = true; *hasResultType = true; break; + case OpSubgroupFirstInvocationKHR: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAllKHR: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAnyKHR: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAllEqualKHR: *hasResult = true; *hasResultType = true; break; + case OpSubgroupReadInvocationKHR: *hasResult = true; *hasResultType = true; break; + case OpGroupIAddNonUniformAMD: *hasResult = true; *hasResultType = true; break; + case OpGroupFAddNonUniformAMD: *hasResult = true; *hasResultType = true; break; + case OpGroupFMinNonUniformAMD: *hasResult = true; *hasResultType = true; break; + case OpGroupUMinNonUniformAMD: *hasResult = true; *hasResultType = true; break; + case OpGroupSMinNonUniformAMD: *hasResult = true; *hasResultType = true; break; + case OpGroupFMaxNonUniformAMD: *hasResult = true; *hasResultType = true; break; + case OpGroupUMaxNonUniformAMD: *hasResult = true; *hasResultType = true; break; + case OpGroupSMaxNonUniformAMD: *hasResult = true; *hasResultType = true; break; + case OpFragmentMaskFetchAMD: *hasResult = true; *hasResultType = true; break; + case OpFragmentFetchAMD: *hasResult = true; *hasResultType = true; break; + case OpReadClockKHR: *hasResult = true; *hasResultType = true; break; + case OpImageSampleFootprintNV: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformPartitionNV: *hasResult = true; *hasResultType = true; break; + case OpWritePackedPrimitiveIndices4x8NV: *hasResult = false; *hasResultType = false; break; + case OpReportIntersectionNV: *hasResult = true; *hasResultType = true; break; + case OpIgnoreIntersectionNV: *hasResult = false; *hasResultType = false; break; + case OpTerminateRayNV: *hasResult = false; *hasResultType = false; break; + case OpTraceNV: *hasResult = false; *hasResultType = false; break; + case OpTypeAccelerationStructureNV: *hasResult = true; *hasResultType = false; break; + case OpExecuteCallableNV: *hasResult = false; *hasResultType = false; break; + case OpTypeCooperativeMatrixNV: *hasResult = true; *hasResultType = false; break; + case OpCooperativeMatrixLoadNV: *hasResult = true; *hasResultType = true; break; + case OpCooperativeMatrixStoreNV: *hasResult = false; *hasResultType = false; break; + case OpCooperativeMatrixMulAddNV: *hasResult = true; *hasResultType = true; break; + case OpCooperativeMatrixLengthNV: *hasResult = true; *hasResultType = true; break; + case OpBeginInvocationInterlockEXT: *hasResult = false; *hasResultType = false; break; + case OpEndInvocationInterlockEXT: *hasResult = false; *hasResultType = false; break; + case OpDemoteToHelperInvocationEXT: *hasResult = false; *hasResultType = false; break; + case OpIsHelperInvocationEXT: *hasResult = true; *hasResultType = true; break; + case OpSubgroupShuffleINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupShuffleDownINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupShuffleUpINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupShuffleXorINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupBlockReadINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupBlockWriteINTEL: *hasResult = false; *hasResultType = false; break; + case OpSubgroupImageBlockReadINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupImageBlockWriteINTEL: *hasResult = false; *hasResultType = false; break; + case OpSubgroupImageMediaBlockReadINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupImageMediaBlockWriteINTEL: *hasResult = false; *hasResultType = false; break; + case OpUCountLeadingZerosINTEL: *hasResult = true; *hasResultType = true; break; + case OpUCountTrailingZerosINTEL: *hasResult = true; *hasResultType = true; break; + case OpAbsISubINTEL: *hasResult = true; *hasResultType = true; break; + case OpAbsUSubINTEL: *hasResult = true; *hasResultType = true; break; + case OpIAddSatINTEL: *hasResult = true; *hasResultType = true; break; + case OpUAddSatINTEL: *hasResult = true; *hasResultType = true; break; + case OpIAverageINTEL: *hasResult = true; *hasResultType = true; break; + case OpUAverageINTEL: *hasResult = true; *hasResultType = true; break; + case OpIAverageRoundedINTEL: *hasResult = true; *hasResultType = true; break; + case OpUAverageRoundedINTEL: *hasResult = true; *hasResultType = true; break; + case OpISubSatINTEL: *hasResult = true; *hasResultType = true; break; + case OpUSubSatINTEL: *hasResult = true; *hasResultType = true; break; + case OpIMul32x16INTEL: *hasResult = true; *hasResultType = true; break; + case OpUMul32x16INTEL: *hasResult = true; *hasResultType = true; break; + case OpDecorateString: *hasResult = false; *hasResultType = false; break; + case OpMemberDecorateString: *hasResult = false; *hasResultType = false; break; + case OpVmeImageINTEL: *hasResult = true; *hasResultType = true; break; + case OpTypeVmeImageINTEL: *hasResult = true; *hasResultType = false; break; + case OpTypeAvcImePayloadINTEL: *hasResult = true; *hasResultType = false; break; + case OpTypeAvcRefPayloadINTEL: *hasResult = true; *hasResultType = false; break; + case OpTypeAvcSicPayloadINTEL: *hasResult = true; *hasResultType = false; break; + case OpTypeAvcMcePayloadINTEL: *hasResult = true; *hasResultType = false; break; + case OpTypeAvcMceResultINTEL: *hasResult = true; *hasResultType = false; break; + case OpTypeAvcImeResultINTEL: *hasResult = true; *hasResultType = false; break; + case OpTypeAvcImeResultSingleReferenceStreamoutINTEL: *hasResult = true; *hasResultType = false; break; + case OpTypeAvcImeResultDualReferenceStreamoutINTEL: *hasResult = true; *hasResultType = false; break; + case OpTypeAvcImeSingleReferenceStreaminINTEL: *hasResult = true; *hasResultType = false; break; + case OpTypeAvcImeDualReferenceStreaminINTEL: *hasResult = true; *hasResultType = false; break; + case OpTypeAvcRefResultINTEL: *hasResult = true; *hasResultType = false; break; + case OpTypeAvcSicResultINTEL: *hasResult = true; *hasResultType = false; break; + case OpSubgroupAvcMceGetDefaultInterBaseMultiReferencePenaltyINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcMceSetInterBaseMultiReferencePenaltyINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcMceGetDefaultInterShapePenaltyINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcMceSetInterShapePenaltyINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcMceGetDefaultInterDirectionPenaltyINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcMceSetInterDirectionPenaltyINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcMceGetDefaultIntraLumaShapePenaltyINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcMceGetDefaultInterMotionVectorCostTableINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcMceGetDefaultHighPenaltyCostTableINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcMceGetDefaultMediumPenaltyCostTableINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcMceGetDefaultLowPenaltyCostTableINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcMceSetMotionVectorCostFunctionINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcMceGetDefaultIntraLumaModePenaltyINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcMceGetDefaultNonDcLumaIntraPenaltyINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcMceGetDefaultIntraChromaModeBasePenaltyINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcMceSetAcOnlyHaarINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcMceSetSourceInterlacedFieldPolarityINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcMceSetSingleReferenceInterlacedFieldPolarityINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcMceSetDualReferenceInterlacedFieldPolaritiesINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcMceConvertToImePayloadINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcMceConvertToImeResultINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcMceConvertToRefPayloadINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcMceConvertToRefResultINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcMceConvertToSicPayloadINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcMceConvertToSicResultINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcMceGetMotionVectorsINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcMceGetInterDistortionsINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcMceGetBestInterDistortionsINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcMceGetInterMajorShapeINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcMceGetInterMinorShapeINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcMceGetInterDirectionsINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcMceGetInterMotionVectorCountINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcMceGetInterReferenceIdsINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcMceGetInterReferenceInterlacedFieldPolaritiesINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeInitializeINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeSetSingleReferenceINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeSetDualReferenceINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeRefWindowSizeINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeAdjustRefOffsetINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeConvertToMcePayloadINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeSetMaxMotionVectorCountINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeSetUnidirectionalMixDisableINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeSetEarlySearchTerminationThresholdINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeSetWeightedSadINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeEvaluateWithSingleReferenceINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeEvaluateWithDualReferenceINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeEvaluateWithSingleReferenceStreaminINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeEvaluateWithDualReferenceStreaminINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeEvaluateWithSingleReferenceStreamoutINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeEvaluateWithDualReferenceStreamoutINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeEvaluateWithSingleReferenceStreaminoutINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeEvaluateWithDualReferenceStreaminoutINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeConvertToMceResultINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeGetSingleReferenceStreaminINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeGetDualReferenceStreaminINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeStripSingleReferenceStreamoutINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeStripDualReferenceStreamoutINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeMotionVectorsINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeDistortionsINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeReferenceIdsINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeMotionVectorsINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeDistortionsINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeReferenceIdsINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeGetBorderReachedINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeGetTruncatedSearchIndicationINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeGetUnidirectionalEarlySearchTerminationINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeGetWeightingPatternMinimumMotionVectorINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeGetWeightingPatternMinimumDistortionINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcFmeInitializeINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcBmeInitializeINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcRefConvertToMcePayloadINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcRefSetBidirectionalMixDisableINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcRefSetBilinearFilterEnableINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcRefEvaluateWithSingleReferenceINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcRefEvaluateWithDualReferenceINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcRefEvaluateWithMultiReferenceINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcRefEvaluateWithMultiReferenceInterlacedINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcRefConvertToMceResultINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcSicInitializeINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcSicConfigureSkcINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcSicConfigureIpeLumaINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcSicConfigureIpeLumaChromaINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcSicGetMotionVectorMaskINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcSicConvertToMcePayloadINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcSicSetIntraLumaShapePenaltyINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcSicSetIntraLumaModeCostFunctionINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcSicSetIntraChromaModeCostFunctionINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcSicSetBilinearFilterEnableINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcSicSetSkcForwardTransformEnableINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcSicSetBlockBasedRawSkipSadINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcSicEvaluateIpeINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcSicEvaluateWithSingleReferenceINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcSicEvaluateWithDualReferenceINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcSicEvaluateWithMultiReferenceINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcSicEvaluateWithMultiReferenceInterlacedINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcSicConvertToMceResultINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcSicGetIpeLumaShapeINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcSicGetBestIpeLumaDistortionINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcSicGetBestIpeChromaDistortionINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcSicGetPackedIpeLumaModesINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcSicGetIpeChromaModeINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcSicGetPackedSkcLumaCountThresholdINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcSicGetPackedSkcLumaSumThresholdINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcSicGetInterRawSadsINTEL: *hasResult = true; *hasResultType = true; break; + } +} +#endif /* SPV_ENABLE_UTILITY_CODE */ + // Overload operator| for mask bit combining inline ImageOperandsMask operator|(ImageOperandsMask a, ImageOperandsMask b) { return ImageOperandsMask(unsigned(a) | unsigned(b)); } diff --git a/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/spirv.hpp11 b/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/spirv.hpp11 index 3bd5b8a0df..34ee3b498f 100644 --- a/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/spirv.hpp11 +++ b/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/spirv.hpp11 @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2018 The Khronos Group Inc. +// Copyright (c) 2014-2019 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"), @@ -26,13 +26,16 @@ // the Binary Section of the SPIR-V specification. // Enumeration tokens for SPIR-V, in various styles: -// C, C++, C++11, JSON, Lua, Python +// C, C++, C++11, JSON, Lua, Python, C#, D // // - C will have tokens with a "Spv" prefix, e.g.: SpvSourceLanguageGLSL // - C++ will have tokens in the "spv" name space, e.g.: spv::SourceLanguageGLSL // - C++11 will use enum classes in the spv namespace, e.g.: spv::SourceLanguage::GLSL // - Lua will use tables, e.g.: spv.SourceLanguage.GLSL // - Python will use dictionaries, e.g.: spv['SourceLanguage']['GLSL'] +// - C# will use enum classes in the Specification class located in the "Spv" namespace, +// e.g.: Spv.Specification.SourceLanguage.GLSL +// - D will have tokens under the "spv" module, e.g: spv.SourceLanguage.GLSL // // Some tokens act like mask values, which can be OR'd together, // while others are mutually exclusive. The mask-like ones have @@ -46,11 +49,11 @@ namespace spv { typedef unsigned int Id; -#define SPV_VERSION 0x10300 +#define SPV_VERSION 0x10500 #define SPV_REVISION 1 static const unsigned int MagicNumber = 0x07230203; -static const unsigned int Version = 0x00010300; +static const unsigned int Version = 0x00010500; static const unsigned int Revision = 1; static const unsigned int OpCodeMask = 0xffff; static const unsigned int WordCountShift = 16; @@ -73,6 +76,14 @@ enum class ExecutionModel : unsigned { Fragment = 4, GLCompute = 5, Kernel = 6, + TaskNV = 5267, + MeshNV = 5268, + RayGenerationNV = 5313, + IntersectionNV = 5314, + AnyHitNV = 5315, + ClosestHitNV = 5316, + MissNV = 5317, + CallableNV = 5318, Max = 0x7fffffff, }; @@ -80,6 +91,8 @@ enum class AddressingModel : unsigned { Logical = 0, Physical32 = 1, Physical64 = 2, + PhysicalStorageBuffer64 = 5348, + PhysicalStorageBuffer64EXT = 5348, Max = 0x7fffffff, }; @@ -87,6 +100,8 @@ enum class MemoryModel : unsigned { Simple = 0, GLSL450 = 1, OpenCL = 2, + Vulkan = 3, + VulkanKHR = 3, Max = 0x7fffffff, }; @@ -130,7 +145,23 @@ enum class ExecutionMode : unsigned { LocalSizeId = 38, LocalSizeHintId = 39, PostDepthCoverage = 4446, + DenormPreserve = 4459, + DenormFlushToZero = 4460, + SignedZeroInfNanPreserve = 4461, + RoundingModeRTE = 4462, + RoundingModeRTZ = 4463, StencilRefReplacingEXT = 5027, + OutputLinesNV = 5269, + OutputPrimitivesNV = 5270, + DerivativeGroupQuadsNV = 5289, + DerivativeGroupLinearNV = 5290, + OutputTrianglesNV = 5298, + PixelInterlockOrderedEXT = 5366, + PixelInterlockUnorderedEXT = 5367, + SampleInterlockOrderedEXT = 5368, + SampleInterlockUnorderedEXT = 5369, + ShadingRateInterlockOrderedEXT = 5370, + ShadingRateInterlockUnorderedEXT = 5371, Max = 0x7fffffff, }; @@ -148,6 +179,14 @@ enum class StorageClass : unsigned { AtomicCounter = 10, Image = 11, StorageBuffer = 12, + CallableDataNV = 5328, + IncomingCallableDataNV = 5329, + RayPayloadNV = 5338, + HitAttributeNV = 5339, + IncomingRayPayloadNV = 5342, + ShaderRecordBufferNV = 5343, + PhysicalStorageBuffer = 5349, + PhysicalStorageBufferEXT = 5349, Max = 0x7fffffff, }; @@ -275,6 +314,16 @@ enum class ImageOperandsShift : unsigned { ConstOffsets = 5, Sample = 6, MinLod = 7, + MakeTexelAvailable = 8, + MakeTexelAvailableKHR = 8, + MakeTexelVisible = 9, + MakeTexelVisibleKHR = 9, + NonPrivateTexel = 10, + NonPrivateTexelKHR = 10, + VolatileTexel = 11, + VolatileTexelKHR = 11, + SignExtend = 12, + ZeroExtend = 13, Max = 0x7fffffff, }; @@ -288,6 +337,16 @@ enum class ImageOperandsMask : unsigned { ConstOffsets = 0x00000020, Sample = 0x00000040, MinLod = 0x00000080, + MakeTexelAvailable = 0x00000100, + MakeTexelAvailableKHR = 0x00000100, + MakeTexelVisible = 0x00000200, + MakeTexelVisibleKHR = 0x00000200, + NonPrivateTexel = 0x00000400, + NonPrivateTexelKHR = 0x00000400, + VolatileTexel = 0x00000800, + VolatileTexelKHR = 0x00000800, + SignExtend = 0x00001000, + ZeroExtend = 0x00002000, }; enum class FPFastMathModeShift : unsigned { @@ -368,6 +427,7 @@ enum class Decoration : unsigned { NonWritable = 24, NonReadable = 25, Uniform = 26, + UniformId = 27, SaturatedConversion = 28, Stream = 29, Location = 30, @@ -388,14 +448,28 @@ enum class Decoration : unsigned { MaxByteOffset = 45, AlignmentId = 46, MaxByteOffsetId = 47, + NoSignedWrap = 4469, + NoUnsignedWrap = 4470, ExplicitInterpAMD = 4999, OverrideCoverageNV = 5248, PassthroughNV = 5250, ViewportRelativeNV = 5252, SecondaryViewportRelativeNV = 5256, + PerPrimitiveNV = 5271, + PerViewNV = 5272, + PerTaskNV = 5273, + PerVertexNV = 5285, + NonUniform = 5300, NonUniformEXT = 5300, + RestrictPointer = 5355, + RestrictPointerEXT = 5355, + AliasedPointer = 5356, + AliasedPointerEXT = 5356, + CounterBuffer = 5634, HlslCounterBufferGOOGLE = 5634, HlslSemanticGOOGLE = 5635, + UserSemantic = 5635, + UserTypeGOOGLE = 5636, Max = 0x7fffffff, }; @@ -470,6 +544,38 @@ enum class BuiltIn : unsigned { PositionPerViewNV = 5261, ViewportMaskPerViewNV = 5262, FullyCoveredEXT = 5264, + TaskCountNV = 5274, + PrimitiveCountNV = 5275, + PrimitiveIndicesNV = 5276, + ClipDistancePerViewNV = 5277, + CullDistancePerViewNV = 5278, + LayerPerViewNV = 5279, + MeshViewCountNV = 5280, + MeshViewIndicesNV = 5281, + BaryCoordNV = 5286, + BaryCoordNoPerspNV = 5287, + FragSizeEXT = 5292, + FragmentSizeNV = 5292, + FragInvocationCountEXT = 5293, + InvocationsPerPixelNV = 5293, + LaunchIdNV = 5319, + LaunchSizeNV = 5320, + WorldRayOriginNV = 5321, + WorldRayDirectionNV = 5322, + ObjectRayOriginNV = 5323, + ObjectRayDirectionNV = 5324, + RayTminNV = 5325, + RayTmaxNV = 5326, + InstanceCustomIndexNV = 5327, + ObjectToWorldNV = 5330, + WorldToObjectNV = 5331, + HitTNV = 5332, + HitKindNV = 5333, + IncomingRayFlagsNV = 5351, + WarpsPerSMNV = 5374, + SMCountNV = 5375, + WarpIDNV = 5376, + SMIDNV = 5377, Max = 0x7fffffff, }; @@ -490,6 +596,11 @@ enum class LoopControlShift : unsigned { DontUnroll = 1, DependencyInfinite = 2, DependencyLength = 3, + MinIterations = 4, + MaxIterations = 5, + IterationMultiple = 6, + PeelCount = 7, + PartialCount = 8, Max = 0x7fffffff, }; @@ -499,6 +610,11 @@ enum class LoopControlMask : unsigned { DontUnroll = 0x00000002, DependencyInfinite = 0x00000004, DependencyLength = 0x00000008, + MinIterations = 0x00000010, + MaxIterations = 0x00000020, + IterationMultiple = 0x00000040, + PeelCount = 0x00000080, + PartialCount = 0x00000100, }; enum class FunctionControlShift : unsigned { @@ -528,6 +644,13 @@ enum class MemorySemanticsShift : unsigned { CrossWorkgroupMemory = 9, AtomicCounterMemory = 10, ImageMemory = 11, + OutputMemory = 12, + OutputMemoryKHR = 12, + MakeAvailable = 13, + MakeAvailableKHR = 13, + MakeVisible = 14, + MakeVisibleKHR = 14, + Volatile = 15, Max = 0x7fffffff, }; @@ -543,12 +666,25 @@ enum class MemorySemanticsMask : unsigned { CrossWorkgroupMemory = 0x00000200, AtomicCounterMemory = 0x00000400, ImageMemory = 0x00000800, + OutputMemory = 0x00001000, + OutputMemoryKHR = 0x00001000, + MakeAvailable = 0x00002000, + MakeAvailableKHR = 0x00002000, + MakeVisible = 0x00004000, + MakeVisibleKHR = 0x00004000, + Volatile = 0x00008000, }; enum class MemoryAccessShift : unsigned { Volatile = 0, Aligned = 1, Nontemporal = 2, + MakePointerAvailable = 3, + MakePointerAvailableKHR = 3, + MakePointerVisible = 4, + MakePointerVisibleKHR = 4, + NonPrivatePointer = 5, + NonPrivatePointerKHR = 5, Max = 0x7fffffff, }; @@ -557,6 +693,12 @@ enum class MemoryAccessMask : unsigned { Volatile = 0x00000001, Aligned = 0x00000002, Nontemporal = 0x00000004, + MakePointerAvailable = 0x00000008, + MakePointerAvailableKHR = 0x00000008, + MakePointerVisible = 0x00000010, + MakePointerVisibleKHR = 0x00000010, + NonPrivatePointer = 0x00000020, + NonPrivatePointerKHR = 0x00000020, }; enum class Scope : unsigned { @@ -565,6 +707,8 @@ enum class Scope : unsigned { Workgroup = 2, Subgroup = 3, Invocation = 4, + QueueFamily = 5, + QueueFamilyKHR = 5, Max = 0x7fffffff, }; @@ -664,6 +808,8 @@ enum class Capability : unsigned { GroupNonUniformShuffleRelative = 66, GroupNonUniformClustered = 67, GroupNonUniformQuad = 68, + ShaderLayer = 69, + ShaderViewportIndex = 70, SubgroupBallotKHR = 4423, DrawParameters = 4427, SubgroupVoteKHR = 4431, @@ -682,11 +828,17 @@ enum class Capability : unsigned { StorageBuffer8BitAccess = 4448, UniformAndStorageBuffer8BitAccess = 4449, StoragePushConstant8 = 4450, + DenormPreserve = 4464, + DenormFlushToZero = 4465, + SignedZeroInfNanPreserve = 4466, + RoundingModeRTE = 4467, + RoundingModeRTZ = 4468, Float16ImageAMD = 5008, ImageGatherBiasLodAMD = 5009, FragmentMaskAMD = 5010, StencilExportEXT = 5013, ImageReadWriteLodAMD = 5015, + ShaderClockKHR = 5055, SampleMaskOverrideCoverageNV = 5249, GeometryShaderPassthroughNV = 5251, ShaderViewportIndexLayerEXT = 5254, @@ -695,22 +847,59 @@ enum class Capability : unsigned { ShaderStereoViewNV = 5259, PerViewAttributesNV = 5260, FragmentFullyCoveredEXT = 5265, + MeshShadingNV = 5266, + ImageFootprintNV = 5282, + FragmentBarycentricNV = 5284, + ComputeDerivativeGroupQuadsNV = 5288, + FragmentDensityEXT = 5291, + ShadingRateNV = 5291, GroupNonUniformPartitionedNV = 5297, + ShaderNonUniform = 5301, ShaderNonUniformEXT = 5301, + RuntimeDescriptorArray = 5302, RuntimeDescriptorArrayEXT = 5302, + InputAttachmentArrayDynamicIndexing = 5303, InputAttachmentArrayDynamicIndexingEXT = 5303, + UniformTexelBufferArrayDynamicIndexing = 5304, UniformTexelBufferArrayDynamicIndexingEXT = 5304, + StorageTexelBufferArrayDynamicIndexing = 5305, StorageTexelBufferArrayDynamicIndexingEXT = 5305, + UniformBufferArrayNonUniformIndexing = 5306, UniformBufferArrayNonUniformIndexingEXT = 5306, + SampledImageArrayNonUniformIndexing = 5307, SampledImageArrayNonUniformIndexingEXT = 5307, + StorageBufferArrayNonUniformIndexing = 5308, StorageBufferArrayNonUniformIndexingEXT = 5308, + StorageImageArrayNonUniformIndexing = 5309, StorageImageArrayNonUniformIndexingEXT = 5309, + InputAttachmentArrayNonUniformIndexing = 5310, InputAttachmentArrayNonUniformIndexingEXT = 5310, + UniformTexelBufferArrayNonUniformIndexing = 5311, UniformTexelBufferArrayNonUniformIndexingEXT = 5311, + StorageTexelBufferArrayNonUniformIndexing = 5312, StorageTexelBufferArrayNonUniformIndexingEXT = 5312, + RayTracingNV = 5340, + VulkanMemoryModel = 5345, + VulkanMemoryModelKHR = 5345, + VulkanMemoryModelDeviceScope = 5346, + VulkanMemoryModelDeviceScopeKHR = 5346, + PhysicalStorageBufferAddresses = 5347, + PhysicalStorageBufferAddressesEXT = 5347, + ComputeDerivativeGroupLinearNV = 5350, + CooperativeMatrixNV = 5357, + FragmentShaderSampleInterlockEXT = 5363, + FragmentShaderShadingRateInterlockEXT = 5372, + ShaderSMBuiltinsNV = 5373, + FragmentShaderPixelInterlockEXT = 5378, + DemoteToHelperInvocationEXT = 5379, SubgroupShuffleINTEL = 5568, SubgroupBufferBlockIOINTEL = 5569, SubgroupImageBlockIOINTEL = 5570, + SubgroupImageMediaBlockIOINTEL = 5579, + IntegerFunctions2INTEL = 5584, + SubgroupAvcMotionEstimationINTEL = 5696, + SubgroupAvcMotionEstimationIntraINTEL = 5697, + SubgroupAvcMotionEstimationChromaINTEL = 5698, Max = 0x7fffffff, }; @@ -1055,6 +1244,10 @@ enum class Op : unsigned { OpGroupNonUniformLogicalXor = 364, OpGroupNonUniformQuadBroadcast = 365, OpGroupNonUniformQuadSwap = 366, + OpCopyLogical = 400, + OpPtrEqual = 401, + OpPtrNotEqual = 402, + OpPtrDiff = 403, OpSubgroupBallotKHR = 4421, OpSubgroupFirstInvocationKHR = 4422, OpSubgroupAllKHR = 4428, @@ -1071,7 +1264,25 @@ enum class Op : unsigned { OpGroupSMaxNonUniformAMD = 5007, OpFragmentMaskFetchAMD = 5011, OpFragmentFetchAMD = 5012, + OpReadClockKHR = 5056, + OpImageSampleFootprintNV = 5283, OpGroupNonUniformPartitionNV = 5296, + OpWritePackedPrimitiveIndices4x8NV = 5299, + OpReportIntersectionNV = 5334, + OpIgnoreIntersectionNV = 5335, + OpTerminateRayNV = 5336, + OpTraceNV = 5337, + OpTypeAccelerationStructureNV = 5341, + OpExecuteCallableNV = 5344, + OpTypeCooperativeMatrixNV = 5358, + OpCooperativeMatrixLoadNV = 5359, + OpCooperativeMatrixStoreNV = 5360, + OpCooperativeMatrixMulAddNV = 5361, + OpCooperativeMatrixLengthNV = 5362, + OpBeginInvocationInterlockEXT = 5364, + OpEndInvocationInterlockEXT = 5365, + OpDemoteToHelperInvocationEXT = 5380, + OpIsHelperInvocationEXT = 5381, OpSubgroupShuffleINTEL = 5571, OpSubgroupShuffleDownINTEL = 5572, OpSubgroupShuffleUpINTEL = 5573, @@ -1080,11 +1291,679 @@ enum class Op : unsigned { OpSubgroupBlockWriteINTEL = 5576, OpSubgroupImageBlockReadINTEL = 5577, OpSubgroupImageBlockWriteINTEL = 5578, + OpSubgroupImageMediaBlockReadINTEL = 5580, + OpSubgroupImageMediaBlockWriteINTEL = 5581, + OpUCountLeadingZerosINTEL = 5585, + OpUCountTrailingZerosINTEL = 5586, + OpAbsISubINTEL = 5587, + OpAbsUSubINTEL = 5588, + OpIAddSatINTEL = 5589, + OpUAddSatINTEL = 5590, + OpIAverageINTEL = 5591, + OpUAverageINTEL = 5592, + OpIAverageRoundedINTEL = 5593, + OpUAverageRoundedINTEL = 5594, + OpISubSatINTEL = 5595, + OpUSubSatINTEL = 5596, + OpIMul32x16INTEL = 5597, + OpUMul32x16INTEL = 5598, + OpDecorateString = 5632, OpDecorateStringGOOGLE = 5632, + OpMemberDecorateString = 5633, OpMemberDecorateStringGOOGLE = 5633, + OpVmeImageINTEL = 5699, + OpTypeVmeImageINTEL = 5700, + OpTypeAvcImePayloadINTEL = 5701, + OpTypeAvcRefPayloadINTEL = 5702, + OpTypeAvcSicPayloadINTEL = 5703, + OpTypeAvcMcePayloadINTEL = 5704, + OpTypeAvcMceResultINTEL = 5705, + OpTypeAvcImeResultINTEL = 5706, + OpTypeAvcImeResultSingleReferenceStreamoutINTEL = 5707, + OpTypeAvcImeResultDualReferenceStreamoutINTEL = 5708, + OpTypeAvcImeSingleReferenceStreaminINTEL = 5709, + OpTypeAvcImeDualReferenceStreaminINTEL = 5710, + OpTypeAvcRefResultINTEL = 5711, + OpTypeAvcSicResultINTEL = 5712, + OpSubgroupAvcMceGetDefaultInterBaseMultiReferencePenaltyINTEL = 5713, + OpSubgroupAvcMceSetInterBaseMultiReferencePenaltyINTEL = 5714, + OpSubgroupAvcMceGetDefaultInterShapePenaltyINTEL = 5715, + OpSubgroupAvcMceSetInterShapePenaltyINTEL = 5716, + OpSubgroupAvcMceGetDefaultInterDirectionPenaltyINTEL = 5717, + OpSubgroupAvcMceSetInterDirectionPenaltyINTEL = 5718, + OpSubgroupAvcMceGetDefaultIntraLumaShapePenaltyINTEL = 5719, + OpSubgroupAvcMceGetDefaultInterMotionVectorCostTableINTEL = 5720, + OpSubgroupAvcMceGetDefaultHighPenaltyCostTableINTEL = 5721, + OpSubgroupAvcMceGetDefaultMediumPenaltyCostTableINTEL = 5722, + OpSubgroupAvcMceGetDefaultLowPenaltyCostTableINTEL = 5723, + OpSubgroupAvcMceSetMotionVectorCostFunctionINTEL = 5724, + OpSubgroupAvcMceGetDefaultIntraLumaModePenaltyINTEL = 5725, + OpSubgroupAvcMceGetDefaultNonDcLumaIntraPenaltyINTEL = 5726, + OpSubgroupAvcMceGetDefaultIntraChromaModeBasePenaltyINTEL = 5727, + OpSubgroupAvcMceSetAcOnlyHaarINTEL = 5728, + OpSubgroupAvcMceSetSourceInterlacedFieldPolarityINTEL = 5729, + OpSubgroupAvcMceSetSingleReferenceInterlacedFieldPolarityINTEL = 5730, + OpSubgroupAvcMceSetDualReferenceInterlacedFieldPolaritiesINTEL = 5731, + OpSubgroupAvcMceConvertToImePayloadINTEL = 5732, + OpSubgroupAvcMceConvertToImeResultINTEL = 5733, + OpSubgroupAvcMceConvertToRefPayloadINTEL = 5734, + OpSubgroupAvcMceConvertToRefResultINTEL = 5735, + OpSubgroupAvcMceConvertToSicPayloadINTEL = 5736, + OpSubgroupAvcMceConvertToSicResultINTEL = 5737, + OpSubgroupAvcMceGetMotionVectorsINTEL = 5738, + OpSubgroupAvcMceGetInterDistortionsINTEL = 5739, + OpSubgroupAvcMceGetBestInterDistortionsINTEL = 5740, + OpSubgroupAvcMceGetInterMajorShapeINTEL = 5741, + OpSubgroupAvcMceGetInterMinorShapeINTEL = 5742, + OpSubgroupAvcMceGetInterDirectionsINTEL = 5743, + OpSubgroupAvcMceGetInterMotionVectorCountINTEL = 5744, + OpSubgroupAvcMceGetInterReferenceIdsINTEL = 5745, + OpSubgroupAvcMceGetInterReferenceInterlacedFieldPolaritiesINTEL = 5746, + OpSubgroupAvcImeInitializeINTEL = 5747, + OpSubgroupAvcImeSetSingleReferenceINTEL = 5748, + OpSubgroupAvcImeSetDualReferenceINTEL = 5749, + OpSubgroupAvcImeRefWindowSizeINTEL = 5750, + OpSubgroupAvcImeAdjustRefOffsetINTEL = 5751, + OpSubgroupAvcImeConvertToMcePayloadINTEL = 5752, + OpSubgroupAvcImeSetMaxMotionVectorCountINTEL = 5753, + OpSubgroupAvcImeSetUnidirectionalMixDisableINTEL = 5754, + OpSubgroupAvcImeSetEarlySearchTerminationThresholdINTEL = 5755, + OpSubgroupAvcImeSetWeightedSadINTEL = 5756, + OpSubgroupAvcImeEvaluateWithSingleReferenceINTEL = 5757, + OpSubgroupAvcImeEvaluateWithDualReferenceINTEL = 5758, + OpSubgroupAvcImeEvaluateWithSingleReferenceStreaminINTEL = 5759, + OpSubgroupAvcImeEvaluateWithDualReferenceStreaminINTEL = 5760, + OpSubgroupAvcImeEvaluateWithSingleReferenceStreamoutINTEL = 5761, + OpSubgroupAvcImeEvaluateWithDualReferenceStreamoutINTEL = 5762, + OpSubgroupAvcImeEvaluateWithSingleReferenceStreaminoutINTEL = 5763, + OpSubgroupAvcImeEvaluateWithDualReferenceStreaminoutINTEL = 5764, + OpSubgroupAvcImeConvertToMceResultINTEL = 5765, + OpSubgroupAvcImeGetSingleReferenceStreaminINTEL = 5766, + OpSubgroupAvcImeGetDualReferenceStreaminINTEL = 5767, + OpSubgroupAvcImeStripSingleReferenceStreamoutINTEL = 5768, + OpSubgroupAvcImeStripDualReferenceStreamoutINTEL = 5769, + OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeMotionVectorsINTEL = 5770, + OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeDistortionsINTEL = 5771, + OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeReferenceIdsINTEL = 5772, + OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeMotionVectorsINTEL = 5773, + OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeDistortionsINTEL = 5774, + OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeReferenceIdsINTEL = 5775, + OpSubgroupAvcImeGetBorderReachedINTEL = 5776, + OpSubgroupAvcImeGetTruncatedSearchIndicationINTEL = 5777, + OpSubgroupAvcImeGetUnidirectionalEarlySearchTerminationINTEL = 5778, + OpSubgroupAvcImeGetWeightingPatternMinimumMotionVectorINTEL = 5779, + OpSubgroupAvcImeGetWeightingPatternMinimumDistortionINTEL = 5780, + OpSubgroupAvcFmeInitializeINTEL = 5781, + OpSubgroupAvcBmeInitializeINTEL = 5782, + OpSubgroupAvcRefConvertToMcePayloadINTEL = 5783, + OpSubgroupAvcRefSetBidirectionalMixDisableINTEL = 5784, + OpSubgroupAvcRefSetBilinearFilterEnableINTEL = 5785, + OpSubgroupAvcRefEvaluateWithSingleReferenceINTEL = 5786, + OpSubgroupAvcRefEvaluateWithDualReferenceINTEL = 5787, + OpSubgroupAvcRefEvaluateWithMultiReferenceINTEL = 5788, + OpSubgroupAvcRefEvaluateWithMultiReferenceInterlacedINTEL = 5789, + OpSubgroupAvcRefConvertToMceResultINTEL = 5790, + OpSubgroupAvcSicInitializeINTEL = 5791, + OpSubgroupAvcSicConfigureSkcINTEL = 5792, + OpSubgroupAvcSicConfigureIpeLumaINTEL = 5793, + OpSubgroupAvcSicConfigureIpeLumaChromaINTEL = 5794, + OpSubgroupAvcSicGetMotionVectorMaskINTEL = 5795, + OpSubgroupAvcSicConvertToMcePayloadINTEL = 5796, + OpSubgroupAvcSicSetIntraLumaShapePenaltyINTEL = 5797, + OpSubgroupAvcSicSetIntraLumaModeCostFunctionINTEL = 5798, + OpSubgroupAvcSicSetIntraChromaModeCostFunctionINTEL = 5799, + OpSubgroupAvcSicSetBilinearFilterEnableINTEL = 5800, + OpSubgroupAvcSicSetSkcForwardTransformEnableINTEL = 5801, + OpSubgroupAvcSicSetBlockBasedRawSkipSadINTEL = 5802, + OpSubgroupAvcSicEvaluateIpeINTEL = 5803, + OpSubgroupAvcSicEvaluateWithSingleReferenceINTEL = 5804, + OpSubgroupAvcSicEvaluateWithDualReferenceINTEL = 5805, + OpSubgroupAvcSicEvaluateWithMultiReferenceINTEL = 5806, + OpSubgroupAvcSicEvaluateWithMultiReferenceInterlacedINTEL = 5807, + OpSubgroupAvcSicConvertToMceResultINTEL = 5808, + OpSubgroupAvcSicGetIpeLumaShapeINTEL = 5809, + OpSubgroupAvcSicGetBestIpeLumaDistortionINTEL = 5810, + OpSubgroupAvcSicGetBestIpeChromaDistortionINTEL = 5811, + OpSubgroupAvcSicGetPackedIpeLumaModesINTEL = 5812, + OpSubgroupAvcSicGetIpeChromaModeINTEL = 5813, + OpSubgroupAvcSicGetPackedSkcLumaCountThresholdINTEL = 5814, + OpSubgroupAvcSicGetPackedSkcLumaSumThresholdINTEL = 5815, + OpSubgroupAvcSicGetInterRawSadsINTEL = 5816, Max = 0x7fffffff, }; +#ifdef SPV_ENABLE_UTILITY_CODE +inline void HasResultAndType(Op opcode, bool *hasResult, bool *hasResultType) { + *hasResult = *hasResultType = false; + switch (opcode) { + default: /* unknown opcode */ break; + case Op::OpNop: *hasResult = false; *hasResultType = false; break; + case Op::OpUndef: *hasResult = true; *hasResultType = true; break; + case Op::OpSourceContinued: *hasResult = false; *hasResultType = false; break; + case Op::OpSource: *hasResult = false; *hasResultType = false; break; + case Op::OpSourceExtension: *hasResult = false; *hasResultType = false; break; + case Op::OpName: *hasResult = false; *hasResultType = false; break; + case Op::OpMemberName: *hasResult = false; *hasResultType = false; break; + case Op::OpString: *hasResult = true; *hasResultType = false; break; + case Op::OpLine: *hasResult = false; *hasResultType = false; break; + case Op::OpExtension: *hasResult = false; *hasResultType = false; break; + case Op::OpExtInstImport: *hasResult = true; *hasResultType = false; break; + case Op::OpExtInst: *hasResult = true; *hasResultType = true; break; + case Op::OpMemoryModel: *hasResult = false; *hasResultType = false; break; + case Op::OpEntryPoint: *hasResult = false; *hasResultType = false; break; + case Op::OpExecutionMode: *hasResult = false; *hasResultType = false; break; + case Op::OpCapability: *hasResult = false; *hasResultType = false; break; + case Op::OpTypeVoid: *hasResult = true; *hasResultType = false; break; + case Op::OpTypeBool: *hasResult = true; *hasResultType = false; break; + case Op::OpTypeInt: *hasResult = true; *hasResultType = false; break; + case Op::OpTypeFloat: *hasResult = true; *hasResultType = false; break; + case Op::OpTypeVector: *hasResult = true; *hasResultType = false; break; + case Op::OpTypeMatrix: *hasResult = true; *hasResultType = false; break; + case Op::OpTypeImage: *hasResult = true; *hasResultType = false; break; + case Op::OpTypeSampler: *hasResult = true; *hasResultType = false; break; + case Op::OpTypeSampledImage: *hasResult = true; *hasResultType = false; break; + case Op::OpTypeArray: *hasResult = true; *hasResultType = false; break; + case Op::OpTypeRuntimeArray: *hasResult = true; *hasResultType = false; break; + case Op::OpTypeStruct: *hasResult = true; *hasResultType = false; break; + case Op::OpTypeOpaque: *hasResult = true; *hasResultType = false; break; + case Op::OpTypePointer: *hasResult = true; *hasResultType = false; break; + case Op::OpTypeFunction: *hasResult = true; *hasResultType = false; break; + case Op::OpTypeEvent: *hasResult = true; *hasResultType = false; break; + case Op::OpTypeDeviceEvent: *hasResult = true; *hasResultType = false; break; + case Op::OpTypeReserveId: *hasResult = true; *hasResultType = false; break; + case Op::OpTypeQueue: *hasResult = true; *hasResultType = false; break; + case Op::OpTypePipe: *hasResult = true; *hasResultType = false; break; + case Op::OpTypeForwardPointer: *hasResult = false; *hasResultType = false; break; + case Op::OpConstantTrue: *hasResult = true; *hasResultType = true; break; + case Op::OpConstantFalse: *hasResult = true; *hasResultType = true; break; + case Op::OpConstant: *hasResult = true; *hasResultType = true; break; + case Op::OpConstantComposite: *hasResult = true; *hasResultType = true; break; + case Op::OpConstantSampler: *hasResult = true; *hasResultType = true; break; + case Op::OpConstantNull: *hasResult = true; *hasResultType = true; break; + case Op::OpSpecConstantTrue: *hasResult = true; *hasResultType = true; break; + case Op::OpSpecConstantFalse: *hasResult = true; *hasResultType = true; break; + case Op::OpSpecConstant: *hasResult = true; *hasResultType = true; break; + case Op::OpSpecConstantComposite: *hasResult = true; *hasResultType = true; break; + case Op::OpSpecConstantOp: *hasResult = true; *hasResultType = true; break; + case Op::OpFunction: *hasResult = true; *hasResultType = true; break; + case Op::OpFunctionParameter: *hasResult = true; *hasResultType = true; break; + case Op::OpFunctionEnd: *hasResult = false; *hasResultType = false; break; + case Op::OpFunctionCall: *hasResult = true; *hasResultType = true; break; + case Op::OpVariable: *hasResult = true; *hasResultType = true; break; + case Op::OpImageTexelPointer: *hasResult = true; *hasResultType = true; break; + case Op::OpLoad: *hasResult = true; *hasResultType = true; break; + case Op::OpStore: *hasResult = false; *hasResultType = false; break; + case Op::OpCopyMemory: *hasResult = false; *hasResultType = false; break; + case Op::OpCopyMemorySized: *hasResult = false; *hasResultType = false; break; + case Op::OpAccessChain: *hasResult = true; *hasResultType = true; break; + case Op::OpInBoundsAccessChain: *hasResult = true; *hasResultType = true; break; + case Op::OpPtrAccessChain: *hasResult = true; *hasResultType = true; break; + case Op::OpArrayLength: *hasResult = true; *hasResultType = true; break; + case Op::OpGenericPtrMemSemantics: *hasResult = true; *hasResultType = true; break; + case Op::OpInBoundsPtrAccessChain: *hasResult = true; *hasResultType = true; break; + case Op::OpDecorate: *hasResult = false; *hasResultType = false; break; + case Op::OpMemberDecorate: *hasResult = false; *hasResultType = false; break; + case Op::OpDecorationGroup: *hasResult = true; *hasResultType = false; break; + case Op::OpGroupDecorate: *hasResult = false; *hasResultType = false; break; + case Op::OpGroupMemberDecorate: *hasResult = false; *hasResultType = false; break; + case Op::OpVectorExtractDynamic: *hasResult = true; *hasResultType = true; break; + case Op::OpVectorInsertDynamic: *hasResult = true; *hasResultType = true; break; + case Op::OpVectorShuffle: *hasResult = true; *hasResultType = true; break; + case Op::OpCompositeConstruct: *hasResult = true; *hasResultType = true; break; + case Op::OpCompositeExtract: *hasResult = true; *hasResultType = true; break; + case Op::OpCompositeInsert: *hasResult = true; *hasResultType = true; break; + case Op::OpCopyObject: *hasResult = true; *hasResultType = true; break; + case Op::OpTranspose: *hasResult = true; *hasResultType = true; break; + case Op::OpSampledImage: *hasResult = true; *hasResultType = true; break; + case Op::OpImageSampleImplicitLod: *hasResult = true; *hasResultType = true; break; + case Op::OpImageSampleExplicitLod: *hasResult = true; *hasResultType = true; break; + case Op::OpImageSampleDrefImplicitLod: *hasResult = true; *hasResultType = true; break; + case Op::OpImageSampleDrefExplicitLod: *hasResult = true; *hasResultType = true; break; + case Op::OpImageSampleProjImplicitLod: *hasResult = true; *hasResultType = true; break; + case Op::OpImageSampleProjExplicitLod: *hasResult = true; *hasResultType = true; break; + case Op::OpImageSampleProjDrefImplicitLod: *hasResult = true; *hasResultType = true; break; + case Op::OpImageSampleProjDrefExplicitLod: *hasResult = true; *hasResultType = true; break; + case Op::OpImageFetch: *hasResult = true; *hasResultType = true; break; + case Op::OpImageGather: *hasResult = true; *hasResultType = true; break; + case Op::OpImageDrefGather: *hasResult = true; *hasResultType = true; break; + case Op::OpImageRead: *hasResult = true; *hasResultType = true; break; + case Op::OpImageWrite: *hasResult = false; *hasResultType = false; break; + case Op::OpImage: *hasResult = true; *hasResultType = true; break; + case Op::OpImageQueryFormat: *hasResult = true; *hasResultType = true; break; + case Op::OpImageQueryOrder: *hasResult = true; *hasResultType = true; break; + case Op::OpImageQuerySizeLod: *hasResult = true; *hasResultType = true; break; + case Op::OpImageQuerySize: *hasResult = true; *hasResultType = true; break; + case Op::OpImageQueryLod: *hasResult = true; *hasResultType = true; break; + case Op::OpImageQueryLevels: *hasResult = true; *hasResultType = true; break; + case Op::OpImageQuerySamples: *hasResult = true; *hasResultType = true; break; + case Op::OpConvertFToU: *hasResult = true; *hasResultType = true; break; + case Op::OpConvertFToS: *hasResult = true; *hasResultType = true; break; + case Op::OpConvertSToF: *hasResult = true; *hasResultType = true; break; + case Op::OpConvertUToF: *hasResult = true; *hasResultType = true; break; + case Op::OpUConvert: *hasResult = true; *hasResultType = true; break; + case Op::OpSConvert: *hasResult = true; *hasResultType = true; break; + case Op::OpFConvert: *hasResult = true; *hasResultType = true; break; + case Op::OpQuantizeToF16: *hasResult = true; *hasResultType = true; break; + case Op::OpConvertPtrToU: *hasResult = true; *hasResultType = true; break; + case Op::OpSatConvertSToU: *hasResult = true; *hasResultType = true; break; + case Op::OpSatConvertUToS: *hasResult = true; *hasResultType = true; break; + case Op::OpConvertUToPtr: *hasResult = true; *hasResultType = true; break; + case Op::OpPtrCastToGeneric: *hasResult = true; *hasResultType = true; break; + case Op::OpGenericCastToPtr: *hasResult = true; *hasResultType = true; break; + case Op::OpGenericCastToPtrExplicit: *hasResult = true; *hasResultType = true; break; + case Op::OpBitcast: *hasResult = true; *hasResultType = true; break; + case Op::OpSNegate: *hasResult = true; *hasResultType = true; break; + case Op::OpFNegate: *hasResult = true; *hasResultType = true; break; + case Op::OpIAdd: *hasResult = true; *hasResultType = true; break; + case Op::OpFAdd: *hasResult = true; *hasResultType = true; break; + case Op::OpISub: *hasResult = true; *hasResultType = true; break; + case Op::OpFSub: *hasResult = true; *hasResultType = true; break; + case Op::OpIMul: *hasResult = true; *hasResultType = true; break; + case Op::OpFMul: *hasResult = true; *hasResultType = true; break; + case Op::OpUDiv: *hasResult = true; *hasResultType = true; break; + case Op::OpSDiv: *hasResult = true; *hasResultType = true; break; + case Op::OpFDiv: *hasResult = true; *hasResultType = true; break; + case Op::OpUMod: *hasResult = true; *hasResultType = true; break; + case Op::OpSRem: *hasResult = true; *hasResultType = true; break; + case Op::OpSMod: *hasResult = true; *hasResultType = true; break; + case Op::OpFRem: *hasResult = true; *hasResultType = true; break; + case Op::OpFMod: *hasResult = true; *hasResultType = true; break; + case Op::OpVectorTimesScalar: *hasResult = true; *hasResultType = true; break; + case Op::OpMatrixTimesScalar: *hasResult = true; *hasResultType = true; break; + case Op::OpVectorTimesMatrix: *hasResult = true; *hasResultType = true; break; + case Op::OpMatrixTimesVector: *hasResult = true; *hasResultType = true; break; + case Op::OpMatrixTimesMatrix: *hasResult = true; *hasResultType = true; break; + case Op::OpOuterProduct: *hasResult = true; *hasResultType = true; break; + case Op::OpDot: *hasResult = true; *hasResultType = true; break; + case Op::OpIAddCarry: *hasResult = true; *hasResultType = true; break; + case Op::OpISubBorrow: *hasResult = true; *hasResultType = true; break; + case Op::OpUMulExtended: *hasResult = true; *hasResultType = true; break; + case Op::OpSMulExtended: *hasResult = true; *hasResultType = true; break; + case Op::OpAny: *hasResult = true; *hasResultType = true; break; + case Op::OpAll: *hasResult = true; *hasResultType = true; break; + case Op::OpIsNan: *hasResult = true; *hasResultType = true; break; + case Op::OpIsInf: *hasResult = true; *hasResultType = true; break; + case Op::OpIsFinite: *hasResult = true; *hasResultType = true; break; + case Op::OpIsNormal: *hasResult = true; *hasResultType = true; break; + case Op::OpSignBitSet: *hasResult = true; *hasResultType = true; break; + case Op::OpLessOrGreater: *hasResult = true; *hasResultType = true; break; + case Op::OpOrdered: *hasResult = true; *hasResultType = true; break; + case Op::OpUnordered: *hasResult = true; *hasResultType = true; break; + case Op::OpLogicalEqual: *hasResult = true; *hasResultType = true; break; + case Op::OpLogicalNotEqual: *hasResult = true; *hasResultType = true; break; + case Op::OpLogicalOr: *hasResult = true; *hasResultType = true; break; + case Op::OpLogicalAnd: *hasResult = true; *hasResultType = true; break; + case Op::OpLogicalNot: *hasResult = true; *hasResultType = true; break; + case Op::OpSelect: *hasResult = true; *hasResultType = true; break; + case Op::OpIEqual: *hasResult = true; *hasResultType = true; break; + case Op::OpINotEqual: *hasResult = true; *hasResultType = true; break; + case Op::OpUGreaterThan: *hasResult = true; *hasResultType = true; break; + case Op::OpSGreaterThan: *hasResult = true; *hasResultType = true; break; + case Op::OpUGreaterThanEqual: *hasResult = true; *hasResultType = true; break; + case Op::OpSGreaterThanEqual: *hasResult = true; *hasResultType = true; break; + case Op::OpULessThan: *hasResult = true; *hasResultType = true; break; + case Op::OpSLessThan: *hasResult = true; *hasResultType = true; break; + case Op::OpULessThanEqual: *hasResult = true; *hasResultType = true; break; + case Op::OpSLessThanEqual: *hasResult = true; *hasResultType = true; break; + case Op::OpFOrdEqual: *hasResult = true; *hasResultType = true; break; + case Op::OpFUnordEqual: *hasResult = true; *hasResultType = true; break; + case Op::OpFOrdNotEqual: *hasResult = true; *hasResultType = true; break; + case Op::OpFUnordNotEqual: *hasResult = true; *hasResultType = true; break; + case Op::OpFOrdLessThan: *hasResult = true; *hasResultType = true; break; + case Op::OpFUnordLessThan: *hasResult = true; *hasResultType = true; break; + case Op::OpFOrdGreaterThan: *hasResult = true; *hasResultType = true; break; + case Op::OpFUnordGreaterThan: *hasResult = true; *hasResultType = true; break; + case Op::OpFOrdLessThanEqual: *hasResult = true; *hasResultType = true; break; + case Op::OpFUnordLessThanEqual: *hasResult = true; *hasResultType = true; break; + case Op::OpFOrdGreaterThanEqual: *hasResult = true; *hasResultType = true; break; + case Op::OpFUnordGreaterThanEqual: *hasResult = true; *hasResultType = true; break; + case Op::OpShiftRightLogical: *hasResult = true; *hasResultType = true; break; + case Op::OpShiftRightArithmetic: *hasResult = true; *hasResultType = true; break; + case Op::OpShiftLeftLogical: *hasResult = true; *hasResultType = true; break; + case Op::OpBitwiseOr: *hasResult = true; *hasResultType = true; break; + case Op::OpBitwiseXor: *hasResult = true; *hasResultType = true; break; + case Op::OpBitwiseAnd: *hasResult = true; *hasResultType = true; break; + case Op::OpNot: *hasResult = true; *hasResultType = true; break; + case Op::OpBitFieldInsert: *hasResult = true; *hasResultType = true; break; + case Op::OpBitFieldSExtract: *hasResult = true; *hasResultType = true; break; + case Op::OpBitFieldUExtract: *hasResult = true; *hasResultType = true; break; + case Op::OpBitReverse: *hasResult = true; *hasResultType = true; break; + case Op::OpBitCount: *hasResult = true; *hasResultType = true; break; + case Op::OpDPdx: *hasResult = true; *hasResultType = true; break; + case Op::OpDPdy: *hasResult = true; *hasResultType = true; break; + case Op::OpFwidth: *hasResult = true; *hasResultType = true; break; + case Op::OpDPdxFine: *hasResult = true; *hasResultType = true; break; + case Op::OpDPdyFine: *hasResult = true; *hasResultType = true; break; + case Op::OpFwidthFine: *hasResult = true; *hasResultType = true; break; + case Op::OpDPdxCoarse: *hasResult = true; *hasResultType = true; break; + case Op::OpDPdyCoarse: *hasResult = true; *hasResultType = true; break; + case Op::OpFwidthCoarse: *hasResult = true; *hasResultType = true; break; + case Op::OpEmitVertex: *hasResult = false; *hasResultType = false; break; + case Op::OpEndPrimitive: *hasResult = false; *hasResultType = false; break; + case Op::OpEmitStreamVertex: *hasResult = false; *hasResultType = false; break; + case Op::OpEndStreamPrimitive: *hasResult = false; *hasResultType = false; break; + case Op::OpControlBarrier: *hasResult = false; *hasResultType = false; break; + case Op::OpMemoryBarrier: *hasResult = false; *hasResultType = false; break; + case Op::OpAtomicLoad: *hasResult = true; *hasResultType = true; break; + case Op::OpAtomicStore: *hasResult = false; *hasResultType = false; break; + case Op::OpAtomicExchange: *hasResult = true; *hasResultType = true; break; + case Op::OpAtomicCompareExchange: *hasResult = true; *hasResultType = true; break; + case Op::OpAtomicCompareExchangeWeak: *hasResult = true; *hasResultType = true; break; + case Op::OpAtomicIIncrement: *hasResult = true; *hasResultType = true; break; + case Op::OpAtomicIDecrement: *hasResult = true; *hasResultType = true; break; + case Op::OpAtomicIAdd: *hasResult = true; *hasResultType = true; break; + case Op::OpAtomicISub: *hasResult = true; *hasResultType = true; break; + case Op::OpAtomicSMin: *hasResult = true; *hasResultType = true; break; + case Op::OpAtomicUMin: *hasResult = true; *hasResultType = true; break; + case Op::OpAtomicSMax: *hasResult = true; *hasResultType = true; break; + case Op::OpAtomicUMax: *hasResult = true; *hasResultType = true; break; + case Op::OpAtomicAnd: *hasResult = true; *hasResultType = true; break; + case Op::OpAtomicOr: *hasResult = true; *hasResultType = true; break; + case Op::OpAtomicXor: *hasResult = true; *hasResultType = true; break; + case Op::OpPhi: *hasResult = true; *hasResultType = true; break; + case Op::OpLoopMerge: *hasResult = false; *hasResultType = false; break; + case Op::OpSelectionMerge: *hasResult = false; *hasResultType = false; break; + case Op::OpLabel: *hasResult = true; *hasResultType = false; break; + case Op::OpBranch: *hasResult = false; *hasResultType = false; break; + case Op::OpBranchConditional: *hasResult = false; *hasResultType = false; break; + case Op::OpSwitch: *hasResult = false; *hasResultType = false; break; + case Op::OpKill: *hasResult = false; *hasResultType = false; break; + case Op::OpReturn: *hasResult = false; *hasResultType = false; break; + case Op::OpReturnValue: *hasResult = false; *hasResultType = false; break; + case Op::OpUnreachable: *hasResult = false; *hasResultType = false; break; + case Op::OpLifetimeStart: *hasResult = false; *hasResultType = false; break; + case Op::OpLifetimeStop: *hasResult = false; *hasResultType = false; break; + case Op::OpGroupAsyncCopy: *hasResult = true; *hasResultType = true; break; + case Op::OpGroupWaitEvents: *hasResult = false; *hasResultType = false; break; + case Op::OpGroupAll: *hasResult = true; *hasResultType = true; break; + case Op::OpGroupAny: *hasResult = true; *hasResultType = true; break; + case Op::OpGroupBroadcast: *hasResult = true; *hasResultType = true; break; + case Op::OpGroupIAdd: *hasResult = true; *hasResultType = true; break; + case Op::OpGroupFAdd: *hasResult = true; *hasResultType = true; break; + case Op::OpGroupFMin: *hasResult = true; *hasResultType = true; break; + case Op::OpGroupUMin: *hasResult = true; *hasResultType = true; break; + case Op::OpGroupSMin: *hasResult = true; *hasResultType = true; break; + case Op::OpGroupFMax: *hasResult = true; *hasResultType = true; break; + case Op::OpGroupUMax: *hasResult = true; *hasResultType = true; break; + case Op::OpGroupSMax: *hasResult = true; *hasResultType = true; break; + case Op::OpReadPipe: *hasResult = true; *hasResultType = true; break; + case Op::OpWritePipe: *hasResult = true; *hasResultType = true; break; + case Op::OpReservedReadPipe: *hasResult = true; *hasResultType = true; break; + case Op::OpReservedWritePipe: *hasResult = true; *hasResultType = true; break; + case Op::OpReserveReadPipePackets: *hasResult = true; *hasResultType = true; break; + case Op::OpReserveWritePipePackets: *hasResult = true; *hasResultType = true; break; + case Op::OpCommitReadPipe: *hasResult = false; *hasResultType = false; break; + case Op::OpCommitWritePipe: *hasResult = false; *hasResultType = false; break; + case Op::OpIsValidReserveId: *hasResult = true; *hasResultType = true; break; + case Op::OpGetNumPipePackets: *hasResult = true; *hasResultType = true; break; + case Op::OpGetMaxPipePackets: *hasResult = true; *hasResultType = true; break; + case Op::OpGroupReserveReadPipePackets: *hasResult = true; *hasResultType = true; break; + case Op::OpGroupReserveWritePipePackets: *hasResult = true; *hasResultType = true; break; + case Op::OpGroupCommitReadPipe: *hasResult = false; *hasResultType = false; break; + case Op::OpGroupCommitWritePipe: *hasResult = false; *hasResultType = false; break; + case Op::OpEnqueueMarker: *hasResult = true; *hasResultType = true; break; + case Op::OpEnqueueKernel: *hasResult = true; *hasResultType = true; break; + case Op::OpGetKernelNDrangeSubGroupCount: *hasResult = true; *hasResultType = true; break; + case Op::OpGetKernelNDrangeMaxSubGroupSize: *hasResult = true; *hasResultType = true; break; + case Op::OpGetKernelWorkGroupSize: *hasResult = true; *hasResultType = true; break; + case Op::OpGetKernelPreferredWorkGroupSizeMultiple: *hasResult = true; *hasResultType = true; break; + case Op::OpRetainEvent: *hasResult = false; *hasResultType = false; break; + case Op::OpReleaseEvent: *hasResult = false; *hasResultType = false; break; + case Op::OpCreateUserEvent: *hasResult = true; *hasResultType = true; break; + case Op::OpIsValidEvent: *hasResult = true; *hasResultType = true; break; + case Op::OpSetUserEventStatus: *hasResult = false; *hasResultType = false; break; + case Op::OpCaptureEventProfilingInfo: *hasResult = false; *hasResultType = false; break; + case Op::OpGetDefaultQueue: *hasResult = true; *hasResultType = true; break; + case Op::OpBuildNDRange: *hasResult = true; *hasResultType = true; break; + case Op::OpImageSparseSampleImplicitLod: *hasResult = true; *hasResultType = true; break; + case Op::OpImageSparseSampleExplicitLod: *hasResult = true; *hasResultType = true; break; + case Op::OpImageSparseSampleDrefImplicitLod: *hasResult = true; *hasResultType = true; break; + case Op::OpImageSparseSampleDrefExplicitLod: *hasResult = true; *hasResultType = true; break; + case Op::OpImageSparseSampleProjImplicitLod: *hasResult = true; *hasResultType = true; break; + case Op::OpImageSparseSampleProjExplicitLod: *hasResult = true; *hasResultType = true; break; + case Op::OpImageSparseSampleProjDrefImplicitLod: *hasResult = true; *hasResultType = true; break; + case Op::OpImageSparseSampleProjDrefExplicitLod: *hasResult = true; *hasResultType = true; break; + case Op::OpImageSparseFetch: *hasResult = true; *hasResultType = true; break; + case Op::OpImageSparseGather: *hasResult = true; *hasResultType = true; break; + case Op::OpImageSparseDrefGather: *hasResult = true; *hasResultType = true; break; + case Op::OpImageSparseTexelsResident: *hasResult = true; *hasResultType = true; break; + case Op::OpNoLine: *hasResult = false; *hasResultType = false; break; + case Op::OpAtomicFlagTestAndSet: *hasResult = true; *hasResultType = true; break; + case Op::OpAtomicFlagClear: *hasResult = false; *hasResultType = false; break; + case Op::OpImageSparseRead: *hasResult = true; *hasResultType = true; break; + case Op::OpSizeOf: *hasResult = true; *hasResultType = true; break; + case Op::OpTypePipeStorage: *hasResult = true; *hasResultType = false; break; + case Op::OpConstantPipeStorage: *hasResult = true; *hasResultType = true; break; + case Op::OpCreatePipeFromPipeStorage: *hasResult = true; *hasResultType = true; break; + case Op::OpGetKernelLocalSizeForSubgroupCount: *hasResult = true; *hasResultType = true; break; + case Op::OpGetKernelMaxNumSubgroups: *hasResult = true; *hasResultType = true; break; + case Op::OpTypeNamedBarrier: *hasResult = true; *hasResultType = false; break; + case Op::OpNamedBarrierInitialize: *hasResult = true; *hasResultType = true; break; + case Op::OpMemoryNamedBarrier: *hasResult = false; *hasResultType = false; break; + case Op::OpModuleProcessed: *hasResult = false; *hasResultType = false; break; + case Op::OpExecutionModeId: *hasResult = false; *hasResultType = false; break; + case Op::OpDecorateId: *hasResult = false; *hasResultType = false; break; + case Op::OpGroupNonUniformElect: *hasResult = true; *hasResultType = true; break; + case Op::OpGroupNonUniformAll: *hasResult = true; *hasResultType = true; break; + case Op::OpGroupNonUniformAny: *hasResult = true; *hasResultType = true; break; + case Op::OpGroupNonUniformAllEqual: *hasResult = true; *hasResultType = true; break; + case Op::OpGroupNonUniformBroadcast: *hasResult = true; *hasResultType = true; break; + case Op::OpGroupNonUniformBroadcastFirst: *hasResult = true; *hasResultType = true; break; + case Op::OpGroupNonUniformBallot: *hasResult = true; *hasResultType = true; break; + case Op::OpGroupNonUniformInverseBallot: *hasResult = true; *hasResultType = true; break; + case Op::OpGroupNonUniformBallotBitExtract: *hasResult = true; *hasResultType = true; break; + case Op::OpGroupNonUniformBallotBitCount: *hasResult = true; *hasResultType = true; break; + case Op::OpGroupNonUniformBallotFindLSB: *hasResult = true; *hasResultType = true; break; + case Op::OpGroupNonUniformBallotFindMSB: *hasResult = true; *hasResultType = true; break; + case Op::OpGroupNonUniformShuffle: *hasResult = true; *hasResultType = true; break; + case Op::OpGroupNonUniformShuffleXor: *hasResult = true; *hasResultType = true; break; + case Op::OpGroupNonUniformShuffleUp: *hasResult = true; *hasResultType = true; break; + case Op::OpGroupNonUniformShuffleDown: *hasResult = true; *hasResultType = true; break; + case Op::OpGroupNonUniformIAdd: *hasResult = true; *hasResultType = true; break; + case Op::OpGroupNonUniformFAdd: *hasResult = true; *hasResultType = true; break; + case Op::OpGroupNonUniformIMul: *hasResult = true; *hasResultType = true; break; + case Op::OpGroupNonUniformFMul: *hasResult = true; *hasResultType = true; break; + case Op::OpGroupNonUniformSMin: *hasResult = true; *hasResultType = true; break; + case Op::OpGroupNonUniformUMin: *hasResult = true; *hasResultType = true; break; + case Op::OpGroupNonUniformFMin: *hasResult = true; *hasResultType = true; break; + case Op::OpGroupNonUniformSMax: *hasResult = true; *hasResultType = true; break; + case Op::OpGroupNonUniformUMax: *hasResult = true; *hasResultType = true; break; + case Op::OpGroupNonUniformFMax: *hasResult = true; *hasResultType = true; break; + case Op::OpGroupNonUniformBitwiseAnd: *hasResult = true; *hasResultType = true; break; + case Op::OpGroupNonUniformBitwiseOr: *hasResult = true; *hasResultType = true; break; + case Op::OpGroupNonUniformBitwiseXor: *hasResult = true; *hasResultType = true; break; + case Op::OpGroupNonUniformLogicalAnd: *hasResult = true; *hasResultType = true; break; + case Op::OpGroupNonUniformLogicalOr: *hasResult = true; *hasResultType = true; break; + case Op::OpGroupNonUniformLogicalXor: *hasResult = true; *hasResultType = true; break; + case Op::OpGroupNonUniformQuadBroadcast: *hasResult = true; *hasResultType = true; break; + case Op::OpGroupNonUniformQuadSwap: *hasResult = true; *hasResultType = true; break; + case Op::OpCopyLogical: *hasResult = true; *hasResultType = true; break; + case Op::OpPtrEqual: *hasResult = true; *hasResultType = true; break; + case Op::OpPtrNotEqual: *hasResult = true; *hasResultType = true; break; + case Op::OpPtrDiff: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupBallotKHR: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupFirstInvocationKHR: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAllKHR: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAnyKHR: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAllEqualKHR: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupReadInvocationKHR: *hasResult = true; *hasResultType = true; break; + case Op::OpGroupIAddNonUniformAMD: *hasResult = true; *hasResultType = true; break; + case Op::OpGroupFAddNonUniformAMD: *hasResult = true; *hasResultType = true; break; + case Op::OpGroupFMinNonUniformAMD: *hasResult = true; *hasResultType = true; break; + case Op::OpGroupUMinNonUniformAMD: *hasResult = true; *hasResultType = true; break; + case Op::OpGroupSMinNonUniformAMD: *hasResult = true; *hasResultType = true; break; + case Op::OpGroupFMaxNonUniformAMD: *hasResult = true; *hasResultType = true; break; + case Op::OpGroupUMaxNonUniformAMD: *hasResult = true; *hasResultType = true; break; + case Op::OpGroupSMaxNonUniformAMD: *hasResult = true; *hasResultType = true; break; + case Op::OpFragmentMaskFetchAMD: *hasResult = true; *hasResultType = true; break; + case Op::OpFragmentFetchAMD: *hasResult = true; *hasResultType = true; break; + case Op::OpReadClockKHR: *hasResult = true; *hasResultType = true; break; + case Op::OpImageSampleFootprintNV: *hasResult = true; *hasResultType = true; break; + case Op::OpGroupNonUniformPartitionNV: *hasResult = true; *hasResultType = true; break; + case Op::OpWritePackedPrimitiveIndices4x8NV: *hasResult = false; *hasResultType = false; break; + case Op::OpReportIntersectionNV: *hasResult = true; *hasResultType = true; break; + case Op::OpIgnoreIntersectionNV: *hasResult = false; *hasResultType = false; break; + case Op::OpTerminateRayNV: *hasResult = false; *hasResultType = false; break; + case Op::OpTraceNV: *hasResult = false; *hasResultType = false; break; + case Op::OpTypeAccelerationStructureNV: *hasResult = true; *hasResultType = false; break; + case Op::OpExecuteCallableNV: *hasResult = false; *hasResultType = false; break; + case Op::OpTypeCooperativeMatrixNV: *hasResult = true; *hasResultType = false; break; + case Op::OpCooperativeMatrixLoadNV: *hasResult = true; *hasResultType = true; break; + case Op::OpCooperativeMatrixStoreNV: *hasResult = false; *hasResultType = false; break; + case Op::OpCooperativeMatrixMulAddNV: *hasResult = true; *hasResultType = true; break; + case Op::OpCooperativeMatrixLengthNV: *hasResult = true; *hasResultType = true; break; + case Op::OpBeginInvocationInterlockEXT: *hasResult = false; *hasResultType = false; break; + case Op::OpEndInvocationInterlockEXT: *hasResult = false; *hasResultType = false; break; + case Op::OpDemoteToHelperInvocationEXT: *hasResult = false; *hasResultType = false; break; + case Op::OpIsHelperInvocationEXT: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupShuffleINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupShuffleDownINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupShuffleUpINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupShuffleXorINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupBlockReadINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupBlockWriteINTEL: *hasResult = false; *hasResultType = false; break; + case Op::OpSubgroupImageBlockReadINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupImageBlockWriteINTEL: *hasResult = false; *hasResultType = false; break; + case Op::OpSubgroupImageMediaBlockReadINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupImageMediaBlockWriteINTEL: *hasResult = false; *hasResultType = false; break; + case Op::OpUCountLeadingZerosINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpUCountTrailingZerosINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpAbsISubINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpAbsUSubINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpIAddSatINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpUAddSatINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpIAverageINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpUAverageINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpIAverageRoundedINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpUAverageRoundedINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpISubSatINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpUSubSatINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpIMul32x16INTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpUMul32x16INTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpDecorateString: *hasResult = false; *hasResultType = false; break; + case Op::OpMemberDecorateString: *hasResult = false; *hasResultType = false; break; + case Op::OpVmeImageINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpTypeVmeImageINTEL: *hasResult = true; *hasResultType = false; break; + case Op::OpTypeAvcImePayloadINTEL: *hasResult = true; *hasResultType = false; break; + case Op::OpTypeAvcRefPayloadINTEL: *hasResult = true; *hasResultType = false; break; + case Op::OpTypeAvcSicPayloadINTEL: *hasResult = true; *hasResultType = false; break; + case Op::OpTypeAvcMcePayloadINTEL: *hasResult = true; *hasResultType = false; break; + case Op::OpTypeAvcMceResultINTEL: *hasResult = true; *hasResultType = false; break; + case Op::OpTypeAvcImeResultINTEL: *hasResult = true; *hasResultType = false; break; + case Op::OpTypeAvcImeResultSingleReferenceStreamoutINTEL: *hasResult = true; *hasResultType = false; break; + case Op::OpTypeAvcImeResultDualReferenceStreamoutINTEL: *hasResult = true; *hasResultType = false; break; + case Op::OpTypeAvcImeSingleReferenceStreaminINTEL: *hasResult = true; *hasResultType = false; break; + case Op::OpTypeAvcImeDualReferenceStreaminINTEL: *hasResult = true; *hasResultType = false; break; + case Op::OpTypeAvcRefResultINTEL: *hasResult = true; *hasResultType = false; break; + case Op::OpTypeAvcSicResultINTEL: *hasResult = true; *hasResultType = false; break; + case Op::OpSubgroupAvcMceGetDefaultInterBaseMultiReferencePenaltyINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcMceSetInterBaseMultiReferencePenaltyINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcMceGetDefaultInterShapePenaltyINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcMceSetInterShapePenaltyINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcMceGetDefaultInterDirectionPenaltyINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcMceSetInterDirectionPenaltyINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcMceGetDefaultIntraLumaShapePenaltyINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcMceGetDefaultInterMotionVectorCostTableINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcMceGetDefaultHighPenaltyCostTableINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcMceGetDefaultMediumPenaltyCostTableINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcMceGetDefaultLowPenaltyCostTableINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcMceSetMotionVectorCostFunctionINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcMceGetDefaultIntraLumaModePenaltyINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcMceGetDefaultNonDcLumaIntraPenaltyINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcMceGetDefaultIntraChromaModeBasePenaltyINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcMceSetAcOnlyHaarINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcMceSetSourceInterlacedFieldPolarityINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcMceSetSingleReferenceInterlacedFieldPolarityINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcMceSetDualReferenceInterlacedFieldPolaritiesINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcMceConvertToImePayloadINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcMceConvertToImeResultINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcMceConvertToRefPayloadINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcMceConvertToRefResultINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcMceConvertToSicPayloadINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcMceConvertToSicResultINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcMceGetMotionVectorsINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcMceGetInterDistortionsINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcMceGetBestInterDistortionsINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcMceGetInterMajorShapeINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcMceGetInterMinorShapeINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcMceGetInterDirectionsINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcMceGetInterMotionVectorCountINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcMceGetInterReferenceIdsINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcMceGetInterReferenceInterlacedFieldPolaritiesINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcImeInitializeINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcImeSetSingleReferenceINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcImeSetDualReferenceINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcImeRefWindowSizeINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcImeAdjustRefOffsetINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcImeConvertToMcePayloadINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcImeSetMaxMotionVectorCountINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcImeSetUnidirectionalMixDisableINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcImeSetEarlySearchTerminationThresholdINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcImeSetWeightedSadINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcImeEvaluateWithSingleReferenceINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcImeEvaluateWithDualReferenceINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcImeEvaluateWithSingleReferenceStreaminINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcImeEvaluateWithDualReferenceStreaminINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcImeEvaluateWithSingleReferenceStreamoutINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcImeEvaluateWithDualReferenceStreamoutINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcImeEvaluateWithSingleReferenceStreaminoutINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcImeEvaluateWithDualReferenceStreaminoutINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcImeConvertToMceResultINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcImeGetSingleReferenceStreaminINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcImeGetDualReferenceStreaminINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcImeStripSingleReferenceStreamoutINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcImeStripDualReferenceStreamoutINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeMotionVectorsINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeDistortionsINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeReferenceIdsINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeMotionVectorsINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeDistortionsINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeReferenceIdsINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcImeGetBorderReachedINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcImeGetTruncatedSearchIndicationINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcImeGetUnidirectionalEarlySearchTerminationINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcImeGetWeightingPatternMinimumMotionVectorINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcImeGetWeightingPatternMinimumDistortionINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcFmeInitializeINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcBmeInitializeINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcRefConvertToMcePayloadINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcRefSetBidirectionalMixDisableINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcRefSetBilinearFilterEnableINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcRefEvaluateWithSingleReferenceINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcRefEvaluateWithDualReferenceINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcRefEvaluateWithMultiReferenceINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcRefEvaluateWithMultiReferenceInterlacedINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcRefConvertToMceResultINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcSicInitializeINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcSicConfigureSkcINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcSicConfigureIpeLumaINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcSicConfigureIpeLumaChromaINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcSicGetMotionVectorMaskINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcSicConvertToMcePayloadINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcSicSetIntraLumaShapePenaltyINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcSicSetIntraLumaModeCostFunctionINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcSicSetIntraChromaModeCostFunctionINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcSicSetBilinearFilterEnableINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcSicSetSkcForwardTransformEnableINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcSicSetBlockBasedRawSkipSadINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcSicEvaluateIpeINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcSicEvaluateWithSingleReferenceINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcSicEvaluateWithDualReferenceINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcSicEvaluateWithMultiReferenceINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcSicEvaluateWithMultiReferenceInterlacedINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcSicConvertToMceResultINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcSicGetIpeLumaShapeINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcSicGetBestIpeLumaDistortionINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcSicGetBestIpeChromaDistortionINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcSicGetPackedIpeLumaModesINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcSicGetIpeChromaModeINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcSicGetPackedSkcLumaCountThresholdINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcSicGetPackedSkcLumaSumThresholdINTEL: *hasResult = true; *hasResultType = true; break; + case Op::OpSubgroupAvcSicGetInterRawSadsINTEL: *hasResult = true; *hasResultType = true; break; + } +} +#endif /* SPV_ENABLE_UTILITY_CODE */ + // Overload operator| for mask bit combining inline ImageOperandsMask operator|(ImageOperandsMask a, ImageOperandsMask b) { return ImageOperandsMask(unsigned(a) | unsigned(b)); } diff --git a/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/spirv.json b/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/spirv.json index a592dfa231..b08a1a5d21 100644 --- a/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/spirv.json +++ b/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/spirv.json @@ -6,7 +6,7 @@ "Comment": [ [ - "Copyright (c) 2014-2018 The Khronos Group Inc.", + "Copyright (c) 2014-2019 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\"),", @@ -36,13 +36,16 @@ ], [ "Enumeration tokens for SPIR-V, in various styles:", - " C, C++, C++11, JSON, Lua, Python", + " C, C++, C++11, JSON, Lua, Python, C#, D", "", "- C will have tokens with a \"Spv\" prefix, e.g.: SpvSourceLanguageGLSL", "- C++ will have tokens in the \"spv\" name space, e.g.: spv::SourceLanguageGLSL", "- C++11 will use enum classes in the spv namespace, e.g.: spv::SourceLanguage::GLSL", "- Lua will use tables, e.g.: spv.SourceLanguage.GLSL", "- Python will use dictionaries, e.g.: spv['SourceLanguage']['GLSL']", + "- C# will use enum classes in the Specification class located in the \"Spv\" namespace,", + " e.g.: Spv.Specification.SourceLanguage.GLSL", + "- D will have tokens under the \"spv\" module, e.g: spv.SourceLanguage.GLSL", "", "Some tokens act like mask values, which can be OR'd together,", "while others are mutually exclusive. The mask-like ones have", @@ -51,7 +54,7 @@ ] ], "MagicNumber": 119734787, - "Version": 66304, + "Version": 66816, "Revision": 1, "OpCodeMask": 65535, "WordCountShift": 16 @@ -82,7 +85,15 @@ "Geometry": 3, "Fragment": 4, "GLCompute": 5, - "Kernel": 6 + "Kernel": 6, + "TaskNV": 5267, + "MeshNV": 5268, + "RayGenerationNV": 5313, + "IntersectionNV": 5314, + "AnyHitNV": 5315, + "ClosestHitNV": 5316, + "MissNV": 5317, + "CallableNV": 5318 } }, { @@ -92,7 +103,9 @@ { "Logical": 0, "Physical32": 1, - "Physical64": 2 + "Physical64": 2, + "PhysicalStorageBuffer64": 5348, + "PhysicalStorageBuffer64EXT": 5348 } }, { @@ -102,7 +115,9 @@ { "Simple": 0, "GLSL450": 1, - "OpenCL": 2 + "OpenCL": 2, + "Vulkan": 3, + "VulkanKHR": 3 } }, { @@ -149,7 +164,23 @@ "LocalSizeId": 38, "LocalSizeHintId": 39, "PostDepthCoverage": 4446, - "StencilRefReplacingEXT": 5027 + "DenormPreserve": 4459, + "DenormFlushToZero": 4460, + "SignedZeroInfNanPreserve": 4461, + "RoundingModeRTE": 4462, + "RoundingModeRTZ": 4463, + "StencilRefReplacingEXT": 5027, + "OutputLinesNV": 5269, + "OutputPrimitivesNV": 5270, + "DerivativeGroupQuadsNV": 5289, + "DerivativeGroupLinearNV": 5290, + "OutputTrianglesNV": 5298, + "PixelInterlockOrderedEXT": 5366, + "PixelInterlockUnorderedEXT": 5367, + "SampleInterlockOrderedEXT": 5368, + "SampleInterlockUnorderedEXT": 5369, + "ShadingRateInterlockOrderedEXT": 5370, + "ShadingRateInterlockUnorderedEXT": 5371 } }, { @@ -169,7 +200,15 @@ "PushConstant": 9, "AtomicCounter": 10, "Image": 11, - "StorageBuffer": 12 + "StorageBuffer": 12, + "CallableDataNV": 5328, + "IncomingCallableDataNV": 5329, + "RayPayloadNV": 5338, + "HitAttributeNV": 5339, + "IncomingRayPayloadNV": 5342, + "ShaderRecordBufferNV": 5343, + "PhysicalStorageBuffer": 5349, + "PhysicalStorageBufferEXT": 5349 } }, { @@ -317,7 +356,17 @@ "Offset": 4, "ConstOffsets": 5, "Sample": 6, - "MinLod": 7 + "MinLod": 7, + "MakeTexelAvailable": 8, + "MakeTexelAvailableKHR": 8, + "MakeTexelVisible": 9, + "MakeTexelVisibleKHR": 9, + "NonPrivateTexel": 10, + "NonPrivateTexelKHR": 10, + "VolatileTexel": 11, + "VolatileTexelKHR": 11, + "SignExtend": 12, + "ZeroExtend": 13 } }, { @@ -408,6 +457,7 @@ "NonWritable": 24, "NonReadable": 25, "Uniform": 26, + "UniformId": 27, "SaturatedConversion": 28, "Stream": 29, "Location": 30, @@ -428,14 +478,28 @@ "MaxByteOffset": 45, "AlignmentId": 46, "MaxByteOffsetId": 47, + "NoSignedWrap": 4469, + "NoUnsignedWrap": 4470, "ExplicitInterpAMD": 4999, "OverrideCoverageNV": 5248, "PassthroughNV": 5250, "ViewportRelativeNV": 5252, "SecondaryViewportRelativeNV": 5256, + "PerPrimitiveNV": 5271, + "PerViewNV": 5272, + "PerTaskNV": 5273, + "PerVertexNV": 5285, + "NonUniform": 5300, "NonUniformEXT": 5300, + "RestrictPointer": 5355, + "RestrictPointerEXT": 5355, + "AliasedPointer": 5356, + "AliasedPointerEXT": 5356, + "CounterBuffer": 5634, "HlslCounterBufferGOOGLE": 5634, - "HlslSemanticGOOGLE": 5635 + "HlslSemanticGOOGLE": 5635, + "UserSemantic": 5635, + "UserTypeGOOGLE": 5636 } }, { @@ -512,7 +576,39 @@ "SecondaryViewportMaskNV": 5258, "PositionPerViewNV": 5261, "ViewportMaskPerViewNV": 5262, - "FullyCoveredEXT": 5264 + "FullyCoveredEXT": 5264, + "TaskCountNV": 5274, + "PrimitiveCountNV": 5275, + "PrimitiveIndicesNV": 5276, + "ClipDistancePerViewNV": 5277, + "CullDistancePerViewNV": 5278, + "LayerPerViewNV": 5279, + "MeshViewCountNV": 5280, + "MeshViewIndicesNV": 5281, + "BaryCoordNV": 5286, + "BaryCoordNoPerspNV": 5287, + "FragSizeEXT": 5292, + "FragmentSizeNV": 5292, + "FragInvocationCountEXT": 5293, + "InvocationsPerPixelNV": 5293, + "LaunchIdNV": 5319, + "LaunchSizeNV": 5320, + "WorldRayOriginNV": 5321, + "WorldRayDirectionNV": 5322, + "ObjectRayOriginNV": 5323, + "ObjectRayDirectionNV": 5324, + "RayTminNV": 5325, + "RayTmaxNV": 5326, + "InstanceCustomIndexNV": 5327, + "ObjectToWorldNV": 5330, + "WorldToObjectNV": 5331, + "HitTNV": 5332, + "HitKindNV": 5333, + "IncomingRayFlagsNV": 5351, + "WarpsPerSMNV": 5374, + "SMCountNV": 5375, + "WarpIDNV": 5376, + "SMIDNV": 5377 } }, { @@ -532,7 +628,12 @@ "Unroll": 0, "DontUnroll": 1, "DependencyInfinite": 2, - "DependencyLength": 3 + "DependencyLength": 3, + "MinIterations": 4, + "MaxIterations": 5, + "IterationMultiple": 6, + "PeelCount": 7, + "PartialCount": 8 } }, { @@ -560,7 +661,14 @@ "WorkgroupMemory": 8, "CrossWorkgroupMemory": 9, "AtomicCounterMemory": 10, - "ImageMemory": 11 + "ImageMemory": 11, + "OutputMemory": 12, + "OutputMemoryKHR": 12, + "MakeAvailable": 13, + "MakeAvailableKHR": 13, + "MakeVisible": 14, + "MakeVisibleKHR": 14, + "Volatile": 15 } }, { @@ -570,7 +678,13 @@ { "Volatile": 0, "Aligned": 1, - "Nontemporal": 2 + "Nontemporal": 2, + "MakePointerAvailable": 3, + "MakePointerAvailableKHR": 3, + "MakePointerVisible": 4, + "MakePointerVisibleKHR": 4, + "NonPrivatePointer": 5, + "NonPrivatePointerKHR": 5 } }, { @@ -582,7 +696,9 @@ "Device": 1, "Workgroup": 2, "Subgroup": 3, - "Invocation": 4 + "Invocation": 4, + "QueueFamily": 5, + "QueueFamilyKHR": 5 } }, { @@ -689,6 +805,8 @@ "GroupNonUniformShuffleRelative": 66, "GroupNonUniformClustered": 67, "GroupNonUniformQuad": 68, + "ShaderLayer": 69, + "ShaderViewportIndex": 70, "SubgroupBallotKHR": 4423, "DrawParameters": 4427, "SubgroupVoteKHR": 4431, @@ -707,11 +825,17 @@ "StorageBuffer8BitAccess": 4448, "UniformAndStorageBuffer8BitAccess": 4449, "StoragePushConstant8": 4450, + "DenormPreserve": 4464, + "DenormFlushToZero": 4465, + "SignedZeroInfNanPreserve": 4466, + "RoundingModeRTE": 4467, + "RoundingModeRTZ": 4468, "Float16ImageAMD": 5008, "ImageGatherBiasLodAMD": 5009, "FragmentMaskAMD": 5010, "StencilExportEXT": 5013, "ImageReadWriteLodAMD": 5015, + "ShaderClockKHR": 5055, "SampleMaskOverrideCoverageNV": 5249, "GeometryShaderPassthroughNV": 5251, "ShaderViewportIndexLayerEXT": 5254, @@ -720,22 +844,59 @@ "ShaderStereoViewNV": 5259, "PerViewAttributesNV": 5260, "FragmentFullyCoveredEXT": 5265, + "MeshShadingNV": 5266, + "ImageFootprintNV": 5282, + "FragmentBarycentricNV": 5284, + "ComputeDerivativeGroupQuadsNV": 5288, + "FragmentDensityEXT": 5291, + "ShadingRateNV": 5291, "GroupNonUniformPartitionedNV": 5297, + "ShaderNonUniform": 5301, "ShaderNonUniformEXT": 5301, + "RuntimeDescriptorArray": 5302, "RuntimeDescriptorArrayEXT": 5302, + "InputAttachmentArrayDynamicIndexing": 5303, "InputAttachmentArrayDynamicIndexingEXT": 5303, + "UniformTexelBufferArrayDynamicIndexing": 5304, "UniformTexelBufferArrayDynamicIndexingEXT": 5304, + "StorageTexelBufferArrayDynamicIndexing": 5305, "StorageTexelBufferArrayDynamicIndexingEXT": 5305, + "UniformBufferArrayNonUniformIndexing": 5306, "UniformBufferArrayNonUniformIndexingEXT": 5306, + "SampledImageArrayNonUniformIndexing": 5307, "SampledImageArrayNonUniformIndexingEXT": 5307, + "StorageBufferArrayNonUniformIndexing": 5308, "StorageBufferArrayNonUniformIndexingEXT": 5308, + "StorageImageArrayNonUniformIndexing": 5309, "StorageImageArrayNonUniformIndexingEXT": 5309, + "InputAttachmentArrayNonUniformIndexing": 5310, "InputAttachmentArrayNonUniformIndexingEXT": 5310, + "UniformTexelBufferArrayNonUniformIndexing": 5311, "UniformTexelBufferArrayNonUniformIndexingEXT": 5311, + "StorageTexelBufferArrayNonUniformIndexing": 5312, "StorageTexelBufferArrayNonUniformIndexingEXT": 5312, + "RayTracingNV": 5340, + "VulkanMemoryModel": 5345, + "VulkanMemoryModelKHR": 5345, + "VulkanMemoryModelDeviceScope": 5346, + "VulkanMemoryModelDeviceScopeKHR": 5346, + "PhysicalStorageBufferAddresses": 5347, + "PhysicalStorageBufferAddressesEXT": 5347, + "ComputeDerivativeGroupLinearNV": 5350, + "CooperativeMatrixNV": 5357, + "FragmentShaderSampleInterlockEXT": 5363, + "FragmentShaderShadingRateInterlockEXT": 5372, + "ShaderSMBuiltinsNV": 5373, + "FragmentShaderPixelInterlockEXT": 5378, + "DemoteToHelperInvocationEXT": 5379, "SubgroupShuffleINTEL": 5568, "SubgroupBufferBlockIOINTEL": 5569, - "SubgroupImageBlockIOINTEL": 5570 + "SubgroupImageBlockIOINTEL": 5570, + "SubgroupImageMediaBlockIOINTEL": 5579, + "IntegerFunctions2INTEL": 5584, + "SubgroupAvcMotionEstimationINTEL": 5696, + "SubgroupAvcMotionEstimationIntraINTEL": 5697, + "SubgroupAvcMotionEstimationChromaINTEL": 5698 } }, { @@ -1083,6 +1244,10 @@ "OpGroupNonUniformLogicalXor": 364, "OpGroupNonUniformQuadBroadcast": 365, "OpGroupNonUniformQuadSwap": 366, + "OpCopyLogical": 400, + "OpPtrEqual": 401, + "OpPtrNotEqual": 402, + "OpPtrDiff": 403, "OpSubgroupBallotKHR": 4421, "OpSubgroupFirstInvocationKHR": 4422, "OpSubgroupAllKHR": 4428, @@ -1099,7 +1264,25 @@ "OpGroupSMaxNonUniformAMD": 5007, "OpFragmentMaskFetchAMD": 5011, "OpFragmentFetchAMD": 5012, + "OpReadClockKHR": 5056, + "OpImageSampleFootprintNV": 5283, "OpGroupNonUniformPartitionNV": 5296, + "OpWritePackedPrimitiveIndices4x8NV": 5299, + "OpReportIntersectionNV": 5334, + "OpIgnoreIntersectionNV": 5335, + "OpTerminateRayNV": 5336, + "OpTraceNV": 5337, + "OpTypeAccelerationStructureNV": 5341, + "OpExecuteCallableNV": 5344, + "OpTypeCooperativeMatrixNV": 5358, + "OpCooperativeMatrixLoadNV": 5359, + "OpCooperativeMatrixStoreNV": 5360, + "OpCooperativeMatrixMulAddNV": 5361, + "OpCooperativeMatrixLengthNV": 5362, + "OpBeginInvocationInterlockEXT": 5364, + "OpEndInvocationInterlockEXT": 5365, + "OpDemoteToHelperInvocationEXT": 5380, + "OpIsHelperInvocationEXT": 5381, "OpSubgroupShuffleINTEL": 5571, "OpSubgroupShuffleDownINTEL": 5572, "OpSubgroupShuffleUpINTEL": 5573, @@ -1108,8 +1291,144 @@ "OpSubgroupBlockWriteINTEL": 5576, "OpSubgroupImageBlockReadINTEL": 5577, "OpSubgroupImageBlockWriteINTEL": 5578, + "OpSubgroupImageMediaBlockReadINTEL": 5580, + "OpSubgroupImageMediaBlockWriteINTEL": 5581, + "OpUCountLeadingZerosINTEL": 5585, + "OpUCountTrailingZerosINTEL": 5586, + "OpAbsISubINTEL": 5587, + "OpAbsUSubINTEL": 5588, + "OpIAddSatINTEL": 5589, + "OpUAddSatINTEL": 5590, + "OpIAverageINTEL": 5591, + "OpUAverageINTEL": 5592, + "OpIAverageRoundedINTEL": 5593, + "OpUAverageRoundedINTEL": 5594, + "OpISubSatINTEL": 5595, + "OpUSubSatINTEL": 5596, + "OpIMul32x16INTEL": 5597, + "OpUMul32x16INTEL": 5598, + "OpDecorateString": 5632, "OpDecorateStringGOOGLE": 5632, - "OpMemberDecorateStringGOOGLE": 5633 + "OpMemberDecorateString": 5633, + "OpMemberDecorateStringGOOGLE": 5633, + "OpVmeImageINTEL": 5699, + "OpTypeVmeImageINTEL": 5700, + "OpTypeAvcImePayloadINTEL": 5701, + "OpTypeAvcRefPayloadINTEL": 5702, + "OpTypeAvcSicPayloadINTEL": 5703, + "OpTypeAvcMcePayloadINTEL": 5704, + "OpTypeAvcMceResultINTEL": 5705, + "OpTypeAvcImeResultINTEL": 5706, + "OpTypeAvcImeResultSingleReferenceStreamoutINTEL": 5707, + "OpTypeAvcImeResultDualReferenceStreamoutINTEL": 5708, + "OpTypeAvcImeSingleReferenceStreaminINTEL": 5709, + "OpTypeAvcImeDualReferenceStreaminINTEL": 5710, + "OpTypeAvcRefResultINTEL": 5711, + "OpTypeAvcSicResultINTEL": 5712, + "OpSubgroupAvcMceGetDefaultInterBaseMultiReferencePenaltyINTEL": 5713, + "OpSubgroupAvcMceSetInterBaseMultiReferencePenaltyINTEL": 5714, + "OpSubgroupAvcMceGetDefaultInterShapePenaltyINTEL": 5715, + "OpSubgroupAvcMceSetInterShapePenaltyINTEL": 5716, + "OpSubgroupAvcMceGetDefaultInterDirectionPenaltyINTEL": 5717, + "OpSubgroupAvcMceSetInterDirectionPenaltyINTEL": 5718, + "OpSubgroupAvcMceGetDefaultIntraLumaShapePenaltyINTEL": 5719, + "OpSubgroupAvcMceGetDefaultInterMotionVectorCostTableINTEL": 5720, + "OpSubgroupAvcMceGetDefaultHighPenaltyCostTableINTEL": 5721, + "OpSubgroupAvcMceGetDefaultMediumPenaltyCostTableINTEL": 5722, + "OpSubgroupAvcMceGetDefaultLowPenaltyCostTableINTEL": 5723, + "OpSubgroupAvcMceSetMotionVectorCostFunctionINTEL": 5724, + "OpSubgroupAvcMceGetDefaultIntraLumaModePenaltyINTEL": 5725, + "OpSubgroupAvcMceGetDefaultNonDcLumaIntraPenaltyINTEL": 5726, + "OpSubgroupAvcMceGetDefaultIntraChromaModeBasePenaltyINTEL": 5727, + "OpSubgroupAvcMceSetAcOnlyHaarINTEL": 5728, + "OpSubgroupAvcMceSetSourceInterlacedFieldPolarityINTEL": 5729, + "OpSubgroupAvcMceSetSingleReferenceInterlacedFieldPolarityINTEL": 5730, + "OpSubgroupAvcMceSetDualReferenceInterlacedFieldPolaritiesINTEL": 5731, + "OpSubgroupAvcMceConvertToImePayloadINTEL": 5732, + "OpSubgroupAvcMceConvertToImeResultINTEL": 5733, + "OpSubgroupAvcMceConvertToRefPayloadINTEL": 5734, + "OpSubgroupAvcMceConvertToRefResultINTEL": 5735, + "OpSubgroupAvcMceConvertToSicPayloadINTEL": 5736, + "OpSubgroupAvcMceConvertToSicResultINTEL": 5737, + "OpSubgroupAvcMceGetMotionVectorsINTEL": 5738, + "OpSubgroupAvcMceGetInterDistortionsINTEL": 5739, + "OpSubgroupAvcMceGetBestInterDistortionsINTEL": 5740, + "OpSubgroupAvcMceGetInterMajorShapeINTEL": 5741, + "OpSubgroupAvcMceGetInterMinorShapeINTEL": 5742, + "OpSubgroupAvcMceGetInterDirectionsINTEL": 5743, + "OpSubgroupAvcMceGetInterMotionVectorCountINTEL": 5744, + "OpSubgroupAvcMceGetInterReferenceIdsINTEL": 5745, + "OpSubgroupAvcMceGetInterReferenceInterlacedFieldPolaritiesINTEL": 5746, + "OpSubgroupAvcImeInitializeINTEL": 5747, + "OpSubgroupAvcImeSetSingleReferenceINTEL": 5748, + "OpSubgroupAvcImeSetDualReferenceINTEL": 5749, + "OpSubgroupAvcImeRefWindowSizeINTEL": 5750, + "OpSubgroupAvcImeAdjustRefOffsetINTEL": 5751, + "OpSubgroupAvcImeConvertToMcePayloadINTEL": 5752, + "OpSubgroupAvcImeSetMaxMotionVectorCountINTEL": 5753, + "OpSubgroupAvcImeSetUnidirectionalMixDisableINTEL": 5754, + "OpSubgroupAvcImeSetEarlySearchTerminationThresholdINTEL": 5755, + "OpSubgroupAvcImeSetWeightedSadINTEL": 5756, + "OpSubgroupAvcImeEvaluateWithSingleReferenceINTEL": 5757, + "OpSubgroupAvcImeEvaluateWithDualReferenceINTEL": 5758, + "OpSubgroupAvcImeEvaluateWithSingleReferenceStreaminINTEL": 5759, + "OpSubgroupAvcImeEvaluateWithDualReferenceStreaminINTEL": 5760, + "OpSubgroupAvcImeEvaluateWithSingleReferenceStreamoutINTEL": 5761, + "OpSubgroupAvcImeEvaluateWithDualReferenceStreamoutINTEL": 5762, + "OpSubgroupAvcImeEvaluateWithSingleReferenceStreaminoutINTEL": 5763, + "OpSubgroupAvcImeEvaluateWithDualReferenceStreaminoutINTEL": 5764, + "OpSubgroupAvcImeConvertToMceResultINTEL": 5765, + "OpSubgroupAvcImeGetSingleReferenceStreaminINTEL": 5766, + "OpSubgroupAvcImeGetDualReferenceStreaminINTEL": 5767, + "OpSubgroupAvcImeStripSingleReferenceStreamoutINTEL": 5768, + "OpSubgroupAvcImeStripDualReferenceStreamoutINTEL": 5769, + "OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeMotionVectorsINTEL": 5770, + "OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeDistortionsINTEL": 5771, + "OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeReferenceIdsINTEL": 5772, + "OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeMotionVectorsINTEL": 5773, + "OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeDistortionsINTEL": 5774, + "OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeReferenceIdsINTEL": 5775, + "OpSubgroupAvcImeGetBorderReachedINTEL": 5776, + "OpSubgroupAvcImeGetTruncatedSearchIndicationINTEL": 5777, + "OpSubgroupAvcImeGetUnidirectionalEarlySearchTerminationINTEL": 5778, + "OpSubgroupAvcImeGetWeightingPatternMinimumMotionVectorINTEL": 5779, + "OpSubgroupAvcImeGetWeightingPatternMinimumDistortionINTEL": 5780, + "OpSubgroupAvcFmeInitializeINTEL": 5781, + "OpSubgroupAvcBmeInitializeINTEL": 5782, + "OpSubgroupAvcRefConvertToMcePayloadINTEL": 5783, + "OpSubgroupAvcRefSetBidirectionalMixDisableINTEL": 5784, + "OpSubgroupAvcRefSetBilinearFilterEnableINTEL": 5785, + "OpSubgroupAvcRefEvaluateWithSingleReferenceINTEL": 5786, + "OpSubgroupAvcRefEvaluateWithDualReferenceINTEL": 5787, + "OpSubgroupAvcRefEvaluateWithMultiReferenceINTEL": 5788, + "OpSubgroupAvcRefEvaluateWithMultiReferenceInterlacedINTEL": 5789, + "OpSubgroupAvcRefConvertToMceResultINTEL": 5790, + "OpSubgroupAvcSicInitializeINTEL": 5791, + "OpSubgroupAvcSicConfigureSkcINTEL": 5792, + "OpSubgroupAvcSicConfigureIpeLumaINTEL": 5793, + "OpSubgroupAvcSicConfigureIpeLumaChromaINTEL": 5794, + "OpSubgroupAvcSicGetMotionVectorMaskINTEL": 5795, + "OpSubgroupAvcSicConvertToMcePayloadINTEL": 5796, + "OpSubgroupAvcSicSetIntraLumaShapePenaltyINTEL": 5797, + "OpSubgroupAvcSicSetIntraLumaModeCostFunctionINTEL": 5798, + "OpSubgroupAvcSicSetIntraChromaModeCostFunctionINTEL": 5799, + "OpSubgroupAvcSicSetBilinearFilterEnableINTEL": 5800, + "OpSubgroupAvcSicSetSkcForwardTransformEnableINTEL": 5801, + "OpSubgroupAvcSicSetBlockBasedRawSkipSadINTEL": 5802, + "OpSubgroupAvcSicEvaluateIpeINTEL": 5803, + "OpSubgroupAvcSicEvaluateWithSingleReferenceINTEL": 5804, + "OpSubgroupAvcSicEvaluateWithDualReferenceINTEL": 5805, + "OpSubgroupAvcSicEvaluateWithMultiReferenceINTEL": 5806, + "OpSubgroupAvcSicEvaluateWithMultiReferenceInterlacedINTEL": 5807, + "OpSubgroupAvcSicConvertToMceResultINTEL": 5808, + "OpSubgroupAvcSicGetIpeLumaShapeINTEL": 5809, + "OpSubgroupAvcSicGetBestIpeLumaDistortionINTEL": 5810, + "OpSubgroupAvcSicGetBestIpeChromaDistortionINTEL": 5811, + "OpSubgroupAvcSicGetPackedIpeLumaModesINTEL": 5812, + "OpSubgroupAvcSicGetIpeChromaModeINTEL": 5813, + "OpSubgroupAvcSicGetPackedSkcLumaCountThresholdINTEL": 5814, + "OpSubgroupAvcSicGetPackedSkcLumaSumThresholdINTEL": 5815, + "OpSubgroupAvcSicGetInterRawSadsINTEL": 5816 } } ] diff --git a/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/spirv.lua b/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/spirv.lua index 43e9ba5be4..27385dbb41 100644 --- a/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/spirv.lua +++ b/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/spirv.lua @@ -1,4 +1,4 @@ --- Copyright (c) 2014-2018 The Khronos Group Inc. +-- Copyright (c) 2014-2019 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"), @@ -26,13 +26,16 @@ -- the Binary Section of the SPIR-V specification. -- Enumeration tokens for SPIR-V, in various styles: --- C, C++, C++11, JSON, Lua, Python +-- C, C++, C++11, JSON, Lua, Python, C#, D -- -- - C will have tokens with a "Spv" prefix, e.g.: SpvSourceLanguageGLSL -- - C++ will have tokens in the "spv" name space, e.g.: spv::SourceLanguageGLSL -- - C++11 will use enum classes in the spv namespace, e.g.: spv::SourceLanguage::GLSL -- - Lua will use tables, e.g.: spv.SourceLanguage.GLSL -- - Python will use dictionaries, e.g.: spv['SourceLanguage']['GLSL'] +-- - C# will use enum classes in the Specification class located in the "Spv" namespace, +-- e.g.: Spv.Specification.SourceLanguage.GLSL +-- - D will have tokens under the "spv" module, e.g: spv.SourceLanguage.GLSL -- -- Some tokens act like mask values, which can be OR'd together, -- while others are mutually exclusive. The mask-like ones have @@ -41,7 +44,7 @@ spv = { MagicNumber = 0x07230203, - Version = 0x00010300, + Version = 0x00010500, Revision = 1, OpCodeMask = 0xffff, WordCountShift = 16, @@ -63,18 +66,30 @@ spv = { Fragment = 4, GLCompute = 5, Kernel = 6, + TaskNV = 5267, + MeshNV = 5268, + RayGenerationNV = 5313, + IntersectionNV = 5314, + AnyHitNV = 5315, + ClosestHitNV = 5316, + MissNV = 5317, + CallableNV = 5318, }, AddressingModel = { Logical = 0, Physical32 = 1, Physical64 = 2, + PhysicalStorageBuffer64 = 5348, + PhysicalStorageBuffer64EXT = 5348, }, MemoryModel = { Simple = 0, GLSL450 = 1, OpenCL = 2, + Vulkan = 3, + VulkanKHR = 3, }, ExecutionMode = { @@ -117,7 +132,23 @@ spv = { LocalSizeId = 38, LocalSizeHintId = 39, PostDepthCoverage = 4446, + DenormPreserve = 4459, + DenormFlushToZero = 4460, + SignedZeroInfNanPreserve = 4461, + RoundingModeRTE = 4462, + RoundingModeRTZ = 4463, StencilRefReplacingEXT = 5027, + OutputLinesNV = 5269, + OutputPrimitivesNV = 5270, + DerivativeGroupQuadsNV = 5289, + DerivativeGroupLinearNV = 5290, + OutputTrianglesNV = 5298, + PixelInterlockOrderedEXT = 5366, + PixelInterlockUnorderedEXT = 5367, + SampleInterlockOrderedEXT = 5368, + SampleInterlockUnorderedEXT = 5369, + ShadingRateInterlockOrderedEXT = 5370, + ShadingRateInterlockUnorderedEXT = 5371, }, StorageClass = { @@ -134,6 +165,14 @@ spv = { AtomicCounter = 10, Image = 11, StorageBuffer = 12, + CallableDataNV = 5328, + IncomingCallableDataNV = 5329, + RayPayloadNV = 5338, + HitAttributeNV = 5339, + IncomingRayPayloadNV = 5342, + ShaderRecordBufferNV = 5343, + PhysicalStorageBuffer = 5349, + PhysicalStorageBufferEXT = 5349, }, Dim = { @@ -254,6 +293,16 @@ spv = { ConstOffsets = 5, Sample = 6, MinLod = 7, + MakeTexelAvailable = 8, + MakeTexelAvailableKHR = 8, + MakeTexelVisible = 9, + MakeTexelVisibleKHR = 9, + NonPrivateTexel = 10, + NonPrivateTexelKHR = 10, + VolatileTexel = 11, + VolatileTexelKHR = 11, + SignExtend = 12, + ZeroExtend = 13, }, ImageOperandsMask = { @@ -266,6 +315,16 @@ spv = { ConstOffsets = 0x00000020, Sample = 0x00000040, MinLod = 0x00000080, + MakeTexelAvailable = 0x00000100, + MakeTexelAvailableKHR = 0x00000100, + MakeTexelVisible = 0x00000200, + MakeTexelVisibleKHR = 0x00000200, + NonPrivateTexel = 0x00000400, + NonPrivateTexelKHR = 0x00000400, + VolatileTexel = 0x00000800, + VolatileTexelKHR = 0x00000800, + SignExtend = 0x00001000, + ZeroExtend = 0x00002000, }, FPFastMathModeShift = { @@ -341,6 +400,7 @@ spv = { NonWritable = 24, NonReadable = 25, Uniform = 26, + UniformId = 27, SaturatedConversion = 28, Stream = 29, Location = 30, @@ -361,14 +421,28 @@ spv = { MaxByteOffset = 45, AlignmentId = 46, MaxByteOffsetId = 47, + NoSignedWrap = 4469, + NoUnsignedWrap = 4470, ExplicitInterpAMD = 4999, OverrideCoverageNV = 5248, PassthroughNV = 5250, ViewportRelativeNV = 5252, SecondaryViewportRelativeNV = 5256, + PerPrimitiveNV = 5271, + PerViewNV = 5272, + PerTaskNV = 5273, + PerVertexNV = 5285, + NonUniform = 5300, NonUniformEXT = 5300, + RestrictPointer = 5355, + RestrictPointerEXT = 5355, + AliasedPointer = 5356, + AliasedPointerEXT = 5356, + CounterBuffer = 5634, HlslCounterBufferGOOGLE = 5634, HlslSemanticGOOGLE = 5635, + UserSemantic = 5635, + UserTypeGOOGLE = 5636, }, BuiltIn = { @@ -442,6 +516,38 @@ spv = { PositionPerViewNV = 5261, ViewportMaskPerViewNV = 5262, FullyCoveredEXT = 5264, + TaskCountNV = 5274, + PrimitiveCountNV = 5275, + PrimitiveIndicesNV = 5276, + ClipDistancePerViewNV = 5277, + CullDistancePerViewNV = 5278, + LayerPerViewNV = 5279, + MeshViewCountNV = 5280, + MeshViewIndicesNV = 5281, + BaryCoordNV = 5286, + BaryCoordNoPerspNV = 5287, + FragSizeEXT = 5292, + FragmentSizeNV = 5292, + FragInvocationCountEXT = 5293, + InvocationsPerPixelNV = 5293, + LaunchIdNV = 5319, + LaunchSizeNV = 5320, + WorldRayOriginNV = 5321, + WorldRayDirectionNV = 5322, + ObjectRayOriginNV = 5323, + ObjectRayDirectionNV = 5324, + RayTminNV = 5325, + RayTmaxNV = 5326, + InstanceCustomIndexNV = 5327, + ObjectToWorldNV = 5330, + WorldToObjectNV = 5331, + HitTNV = 5332, + HitKindNV = 5333, + IncomingRayFlagsNV = 5351, + WarpsPerSMNV = 5374, + SMCountNV = 5375, + WarpIDNV = 5376, + SMIDNV = 5377, }, SelectionControlShift = { @@ -460,6 +566,11 @@ spv = { DontUnroll = 1, DependencyInfinite = 2, DependencyLength = 3, + MinIterations = 4, + MaxIterations = 5, + IterationMultiple = 6, + PeelCount = 7, + PartialCount = 8, }, LoopControlMask = { @@ -468,6 +579,11 @@ spv = { DontUnroll = 0x00000002, DependencyInfinite = 0x00000004, DependencyLength = 0x00000008, + MinIterations = 0x00000010, + MaxIterations = 0x00000020, + IterationMultiple = 0x00000040, + PeelCount = 0x00000080, + PartialCount = 0x00000100, }, FunctionControlShift = { @@ -496,6 +612,13 @@ spv = { CrossWorkgroupMemory = 9, AtomicCounterMemory = 10, ImageMemory = 11, + OutputMemory = 12, + OutputMemoryKHR = 12, + MakeAvailable = 13, + MakeAvailableKHR = 13, + MakeVisible = 14, + MakeVisibleKHR = 14, + Volatile = 15, }, MemorySemanticsMask = { @@ -510,12 +633,25 @@ spv = { CrossWorkgroupMemory = 0x00000200, AtomicCounterMemory = 0x00000400, ImageMemory = 0x00000800, + OutputMemory = 0x00001000, + OutputMemoryKHR = 0x00001000, + MakeAvailable = 0x00002000, + MakeAvailableKHR = 0x00002000, + MakeVisible = 0x00004000, + MakeVisibleKHR = 0x00004000, + Volatile = 0x00008000, }, MemoryAccessShift = { Volatile = 0, Aligned = 1, Nontemporal = 2, + MakePointerAvailable = 3, + MakePointerAvailableKHR = 3, + MakePointerVisible = 4, + MakePointerVisibleKHR = 4, + NonPrivatePointer = 5, + NonPrivatePointerKHR = 5, }, MemoryAccessMask = { @@ -523,6 +659,12 @@ spv = { Volatile = 0x00000001, Aligned = 0x00000002, Nontemporal = 0x00000004, + MakePointerAvailable = 0x00000008, + MakePointerAvailableKHR = 0x00000008, + MakePointerVisible = 0x00000010, + MakePointerVisibleKHR = 0x00000010, + NonPrivatePointer = 0x00000020, + NonPrivatePointerKHR = 0x00000020, }, Scope = { @@ -531,6 +673,8 @@ spv = { Workgroup = 2, Subgroup = 3, Invocation = 4, + QueueFamily = 5, + QueueFamilyKHR = 5, }, GroupOperation = { @@ -626,6 +770,8 @@ spv = { GroupNonUniformShuffleRelative = 66, GroupNonUniformClustered = 67, GroupNonUniformQuad = 68, + ShaderLayer = 69, + ShaderViewportIndex = 70, SubgroupBallotKHR = 4423, DrawParameters = 4427, SubgroupVoteKHR = 4431, @@ -644,11 +790,17 @@ spv = { StorageBuffer8BitAccess = 4448, UniformAndStorageBuffer8BitAccess = 4449, StoragePushConstant8 = 4450, + DenormPreserve = 4464, + DenormFlushToZero = 4465, + SignedZeroInfNanPreserve = 4466, + RoundingModeRTE = 4467, + RoundingModeRTZ = 4468, Float16ImageAMD = 5008, ImageGatherBiasLodAMD = 5009, FragmentMaskAMD = 5010, StencilExportEXT = 5013, ImageReadWriteLodAMD = 5015, + ShaderClockKHR = 5055, SampleMaskOverrideCoverageNV = 5249, GeometryShaderPassthroughNV = 5251, ShaderViewportIndexLayerEXT = 5254, @@ -657,22 +809,59 @@ spv = { ShaderStereoViewNV = 5259, PerViewAttributesNV = 5260, FragmentFullyCoveredEXT = 5265, + MeshShadingNV = 5266, + ImageFootprintNV = 5282, + FragmentBarycentricNV = 5284, + ComputeDerivativeGroupQuadsNV = 5288, + FragmentDensityEXT = 5291, + ShadingRateNV = 5291, GroupNonUniformPartitionedNV = 5297, + ShaderNonUniform = 5301, ShaderNonUniformEXT = 5301, + RuntimeDescriptorArray = 5302, RuntimeDescriptorArrayEXT = 5302, + InputAttachmentArrayDynamicIndexing = 5303, InputAttachmentArrayDynamicIndexingEXT = 5303, + UniformTexelBufferArrayDynamicIndexing = 5304, UniformTexelBufferArrayDynamicIndexingEXT = 5304, + StorageTexelBufferArrayDynamicIndexing = 5305, StorageTexelBufferArrayDynamicIndexingEXT = 5305, + UniformBufferArrayNonUniformIndexing = 5306, UniformBufferArrayNonUniformIndexingEXT = 5306, + SampledImageArrayNonUniformIndexing = 5307, SampledImageArrayNonUniformIndexingEXT = 5307, + StorageBufferArrayNonUniformIndexing = 5308, StorageBufferArrayNonUniformIndexingEXT = 5308, + StorageImageArrayNonUniformIndexing = 5309, StorageImageArrayNonUniformIndexingEXT = 5309, + InputAttachmentArrayNonUniformIndexing = 5310, InputAttachmentArrayNonUniformIndexingEXT = 5310, + UniformTexelBufferArrayNonUniformIndexing = 5311, UniformTexelBufferArrayNonUniformIndexingEXT = 5311, + StorageTexelBufferArrayNonUniformIndexing = 5312, StorageTexelBufferArrayNonUniformIndexingEXT = 5312, + RayTracingNV = 5340, + VulkanMemoryModel = 5345, + VulkanMemoryModelKHR = 5345, + VulkanMemoryModelDeviceScope = 5346, + VulkanMemoryModelDeviceScopeKHR = 5346, + PhysicalStorageBufferAddresses = 5347, + PhysicalStorageBufferAddressesEXT = 5347, + ComputeDerivativeGroupLinearNV = 5350, + CooperativeMatrixNV = 5357, + FragmentShaderSampleInterlockEXT = 5363, + FragmentShaderShadingRateInterlockEXT = 5372, + ShaderSMBuiltinsNV = 5373, + FragmentShaderPixelInterlockEXT = 5378, + DemoteToHelperInvocationEXT = 5379, SubgroupShuffleINTEL = 5568, SubgroupBufferBlockIOINTEL = 5569, SubgroupImageBlockIOINTEL = 5570, + SubgroupImageMediaBlockIOINTEL = 5579, + IntegerFunctions2INTEL = 5584, + SubgroupAvcMotionEstimationINTEL = 5696, + SubgroupAvcMotionEstimationIntraINTEL = 5697, + SubgroupAvcMotionEstimationChromaINTEL = 5698, }, Op = { @@ -1016,6 +1205,10 @@ spv = { OpGroupNonUniformLogicalXor = 364, OpGroupNonUniformQuadBroadcast = 365, OpGroupNonUniformQuadSwap = 366, + OpCopyLogical = 400, + OpPtrEqual = 401, + OpPtrNotEqual = 402, + OpPtrDiff = 403, OpSubgroupBallotKHR = 4421, OpSubgroupFirstInvocationKHR = 4422, OpSubgroupAllKHR = 4428, @@ -1032,7 +1225,25 @@ spv = { OpGroupSMaxNonUniformAMD = 5007, OpFragmentMaskFetchAMD = 5011, OpFragmentFetchAMD = 5012, + OpReadClockKHR = 5056, + OpImageSampleFootprintNV = 5283, OpGroupNonUniformPartitionNV = 5296, + OpWritePackedPrimitiveIndices4x8NV = 5299, + OpReportIntersectionNV = 5334, + OpIgnoreIntersectionNV = 5335, + OpTerminateRayNV = 5336, + OpTraceNV = 5337, + OpTypeAccelerationStructureNV = 5341, + OpExecuteCallableNV = 5344, + OpTypeCooperativeMatrixNV = 5358, + OpCooperativeMatrixLoadNV = 5359, + OpCooperativeMatrixStoreNV = 5360, + OpCooperativeMatrixMulAddNV = 5361, + OpCooperativeMatrixLengthNV = 5362, + OpBeginInvocationInterlockEXT = 5364, + OpEndInvocationInterlockEXT = 5365, + OpDemoteToHelperInvocationEXT = 5380, + OpIsHelperInvocationEXT = 5381, OpSubgroupShuffleINTEL = 5571, OpSubgroupShuffleDownINTEL = 5572, OpSubgroupShuffleUpINTEL = 5573, @@ -1041,8 +1252,144 @@ spv = { OpSubgroupBlockWriteINTEL = 5576, OpSubgroupImageBlockReadINTEL = 5577, OpSubgroupImageBlockWriteINTEL = 5578, + OpSubgroupImageMediaBlockReadINTEL = 5580, + OpSubgroupImageMediaBlockWriteINTEL = 5581, + OpUCountLeadingZerosINTEL = 5585, + OpUCountTrailingZerosINTEL = 5586, + OpAbsISubINTEL = 5587, + OpAbsUSubINTEL = 5588, + OpIAddSatINTEL = 5589, + OpUAddSatINTEL = 5590, + OpIAverageINTEL = 5591, + OpUAverageINTEL = 5592, + OpIAverageRoundedINTEL = 5593, + OpUAverageRoundedINTEL = 5594, + OpISubSatINTEL = 5595, + OpUSubSatINTEL = 5596, + OpIMul32x16INTEL = 5597, + OpUMul32x16INTEL = 5598, + OpDecorateString = 5632, OpDecorateStringGOOGLE = 5632, + OpMemberDecorateString = 5633, OpMemberDecorateStringGOOGLE = 5633, + OpVmeImageINTEL = 5699, + OpTypeVmeImageINTEL = 5700, + OpTypeAvcImePayloadINTEL = 5701, + OpTypeAvcRefPayloadINTEL = 5702, + OpTypeAvcSicPayloadINTEL = 5703, + OpTypeAvcMcePayloadINTEL = 5704, + OpTypeAvcMceResultINTEL = 5705, + OpTypeAvcImeResultINTEL = 5706, + OpTypeAvcImeResultSingleReferenceStreamoutINTEL = 5707, + OpTypeAvcImeResultDualReferenceStreamoutINTEL = 5708, + OpTypeAvcImeSingleReferenceStreaminINTEL = 5709, + OpTypeAvcImeDualReferenceStreaminINTEL = 5710, + OpTypeAvcRefResultINTEL = 5711, + OpTypeAvcSicResultINTEL = 5712, + OpSubgroupAvcMceGetDefaultInterBaseMultiReferencePenaltyINTEL = 5713, + OpSubgroupAvcMceSetInterBaseMultiReferencePenaltyINTEL = 5714, + OpSubgroupAvcMceGetDefaultInterShapePenaltyINTEL = 5715, + OpSubgroupAvcMceSetInterShapePenaltyINTEL = 5716, + OpSubgroupAvcMceGetDefaultInterDirectionPenaltyINTEL = 5717, + OpSubgroupAvcMceSetInterDirectionPenaltyINTEL = 5718, + OpSubgroupAvcMceGetDefaultIntraLumaShapePenaltyINTEL = 5719, + OpSubgroupAvcMceGetDefaultInterMotionVectorCostTableINTEL = 5720, + OpSubgroupAvcMceGetDefaultHighPenaltyCostTableINTEL = 5721, + OpSubgroupAvcMceGetDefaultMediumPenaltyCostTableINTEL = 5722, + OpSubgroupAvcMceGetDefaultLowPenaltyCostTableINTEL = 5723, + OpSubgroupAvcMceSetMotionVectorCostFunctionINTEL = 5724, + OpSubgroupAvcMceGetDefaultIntraLumaModePenaltyINTEL = 5725, + OpSubgroupAvcMceGetDefaultNonDcLumaIntraPenaltyINTEL = 5726, + OpSubgroupAvcMceGetDefaultIntraChromaModeBasePenaltyINTEL = 5727, + OpSubgroupAvcMceSetAcOnlyHaarINTEL = 5728, + OpSubgroupAvcMceSetSourceInterlacedFieldPolarityINTEL = 5729, + OpSubgroupAvcMceSetSingleReferenceInterlacedFieldPolarityINTEL = 5730, + OpSubgroupAvcMceSetDualReferenceInterlacedFieldPolaritiesINTEL = 5731, + OpSubgroupAvcMceConvertToImePayloadINTEL = 5732, + OpSubgroupAvcMceConvertToImeResultINTEL = 5733, + OpSubgroupAvcMceConvertToRefPayloadINTEL = 5734, + OpSubgroupAvcMceConvertToRefResultINTEL = 5735, + OpSubgroupAvcMceConvertToSicPayloadINTEL = 5736, + OpSubgroupAvcMceConvertToSicResultINTEL = 5737, + OpSubgroupAvcMceGetMotionVectorsINTEL = 5738, + OpSubgroupAvcMceGetInterDistortionsINTEL = 5739, + OpSubgroupAvcMceGetBestInterDistortionsINTEL = 5740, + OpSubgroupAvcMceGetInterMajorShapeINTEL = 5741, + OpSubgroupAvcMceGetInterMinorShapeINTEL = 5742, + OpSubgroupAvcMceGetInterDirectionsINTEL = 5743, + OpSubgroupAvcMceGetInterMotionVectorCountINTEL = 5744, + OpSubgroupAvcMceGetInterReferenceIdsINTEL = 5745, + OpSubgroupAvcMceGetInterReferenceInterlacedFieldPolaritiesINTEL = 5746, + OpSubgroupAvcImeInitializeINTEL = 5747, + OpSubgroupAvcImeSetSingleReferenceINTEL = 5748, + OpSubgroupAvcImeSetDualReferenceINTEL = 5749, + OpSubgroupAvcImeRefWindowSizeINTEL = 5750, + OpSubgroupAvcImeAdjustRefOffsetINTEL = 5751, + OpSubgroupAvcImeConvertToMcePayloadINTEL = 5752, + OpSubgroupAvcImeSetMaxMotionVectorCountINTEL = 5753, + OpSubgroupAvcImeSetUnidirectionalMixDisableINTEL = 5754, + OpSubgroupAvcImeSetEarlySearchTerminationThresholdINTEL = 5755, + OpSubgroupAvcImeSetWeightedSadINTEL = 5756, + OpSubgroupAvcImeEvaluateWithSingleReferenceINTEL = 5757, + OpSubgroupAvcImeEvaluateWithDualReferenceINTEL = 5758, + OpSubgroupAvcImeEvaluateWithSingleReferenceStreaminINTEL = 5759, + OpSubgroupAvcImeEvaluateWithDualReferenceStreaminINTEL = 5760, + OpSubgroupAvcImeEvaluateWithSingleReferenceStreamoutINTEL = 5761, + OpSubgroupAvcImeEvaluateWithDualReferenceStreamoutINTEL = 5762, + OpSubgroupAvcImeEvaluateWithSingleReferenceStreaminoutINTEL = 5763, + OpSubgroupAvcImeEvaluateWithDualReferenceStreaminoutINTEL = 5764, + OpSubgroupAvcImeConvertToMceResultINTEL = 5765, + OpSubgroupAvcImeGetSingleReferenceStreaminINTEL = 5766, + OpSubgroupAvcImeGetDualReferenceStreaminINTEL = 5767, + OpSubgroupAvcImeStripSingleReferenceStreamoutINTEL = 5768, + OpSubgroupAvcImeStripDualReferenceStreamoutINTEL = 5769, + OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeMotionVectorsINTEL = 5770, + OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeDistortionsINTEL = 5771, + OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeReferenceIdsINTEL = 5772, + OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeMotionVectorsINTEL = 5773, + OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeDistortionsINTEL = 5774, + OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeReferenceIdsINTEL = 5775, + OpSubgroupAvcImeGetBorderReachedINTEL = 5776, + OpSubgroupAvcImeGetTruncatedSearchIndicationINTEL = 5777, + OpSubgroupAvcImeGetUnidirectionalEarlySearchTerminationINTEL = 5778, + OpSubgroupAvcImeGetWeightingPatternMinimumMotionVectorINTEL = 5779, + OpSubgroupAvcImeGetWeightingPatternMinimumDistortionINTEL = 5780, + OpSubgroupAvcFmeInitializeINTEL = 5781, + OpSubgroupAvcBmeInitializeINTEL = 5782, + OpSubgroupAvcRefConvertToMcePayloadINTEL = 5783, + OpSubgroupAvcRefSetBidirectionalMixDisableINTEL = 5784, + OpSubgroupAvcRefSetBilinearFilterEnableINTEL = 5785, + OpSubgroupAvcRefEvaluateWithSingleReferenceINTEL = 5786, + OpSubgroupAvcRefEvaluateWithDualReferenceINTEL = 5787, + OpSubgroupAvcRefEvaluateWithMultiReferenceINTEL = 5788, + OpSubgroupAvcRefEvaluateWithMultiReferenceInterlacedINTEL = 5789, + OpSubgroupAvcRefConvertToMceResultINTEL = 5790, + OpSubgroupAvcSicInitializeINTEL = 5791, + OpSubgroupAvcSicConfigureSkcINTEL = 5792, + OpSubgroupAvcSicConfigureIpeLumaINTEL = 5793, + OpSubgroupAvcSicConfigureIpeLumaChromaINTEL = 5794, + OpSubgroupAvcSicGetMotionVectorMaskINTEL = 5795, + OpSubgroupAvcSicConvertToMcePayloadINTEL = 5796, + OpSubgroupAvcSicSetIntraLumaShapePenaltyINTEL = 5797, + OpSubgroupAvcSicSetIntraLumaModeCostFunctionINTEL = 5798, + OpSubgroupAvcSicSetIntraChromaModeCostFunctionINTEL = 5799, + OpSubgroupAvcSicSetBilinearFilterEnableINTEL = 5800, + OpSubgroupAvcSicSetSkcForwardTransformEnableINTEL = 5801, + OpSubgroupAvcSicSetBlockBasedRawSkipSadINTEL = 5802, + OpSubgroupAvcSicEvaluateIpeINTEL = 5803, + OpSubgroupAvcSicEvaluateWithSingleReferenceINTEL = 5804, + OpSubgroupAvcSicEvaluateWithDualReferenceINTEL = 5805, + OpSubgroupAvcSicEvaluateWithMultiReferenceINTEL = 5806, + OpSubgroupAvcSicEvaluateWithMultiReferenceInterlacedINTEL = 5807, + OpSubgroupAvcSicConvertToMceResultINTEL = 5808, + OpSubgroupAvcSicGetIpeLumaShapeINTEL = 5809, + OpSubgroupAvcSicGetBestIpeLumaDistortionINTEL = 5810, + OpSubgroupAvcSicGetBestIpeChromaDistortionINTEL = 5811, + OpSubgroupAvcSicGetPackedIpeLumaModesINTEL = 5812, + OpSubgroupAvcSicGetIpeChromaModeINTEL = 5813, + OpSubgroupAvcSicGetPackedSkcLumaCountThresholdINTEL = 5814, + OpSubgroupAvcSicGetPackedSkcLumaSumThresholdINTEL = 5815, + OpSubgroupAvcSicGetInterRawSadsINTEL = 5816, }, } diff --git a/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/spirv.py b/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/spirv.py old mode 100755 new mode 100644 index cb3775ff9a..6968e7b362 --- a/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/spirv.py +++ b/third_party/spirv-tools/external/spirv-headers/include/spirv/unified1/spirv.py @@ -1,4 +1,4 @@ -# Copyright (c) 2014-2018 The Khronos Group Inc. +# Copyright (c) 2014-2019 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"), @@ -26,13 +26,16 @@ # the Binary Section of the SPIR-V specification. # Enumeration tokens for SPIR-V, in various styles: -# C, C++, C++11, JSON, Lua, Python +# C, C++, C++11, JSON, Lua, Python, C#, D # # - C will have tokens with a "Spv" prefix, e.g.: SpvSourceLanguageGLSL # - C++ will have tokens in the "spv" name space, e.g.: spv::SourceLanguageGLSL # - C++11 will use enum classes in the spv namespace, e.g.: spv::SourceLanguage::GLSL # - Lua will use tables, e.g.: spv.SourceLanguage.GLSL # - Python will use dictionaries, e.g.: spv['SourceLanguage']['GLSL'] +# - C# will use enum classes in the Specification class located in the "Spv" namespace, +# e.g.: Spv.Specification.SourceLanguage.GLSL +# - D will have tokens under the "spv" module, e.g: spv.SourceLanguage.GLSL # # Some tokens act like mask values, which can be OR'd together, # while others are mutually exclusive. The mask-like ones have @@ -41,7 +44,7 @@ spv = { 'MagicNumber' : 0x07230203, - 'Version' : 0x00010300, + 'Version' : 0x00010500, 'Revision' : 1, 'OpCodeMask' : 0xffff, 'WordCountShift' : 16, @@ -63,18 +66,30 @@ spv = { 'Fragment' : 4, 'GLCompute' : 5, 'Kernel' : 6, + 'TaskNV' : 5267, + 'MeshNV' : 5268, + 'RayGenerationNV' : 5313, + 'IntersectionNV' : 5314, + 'AnyHitNV' : 5315, + 'ClosestHitNV' : 5316, + 'MissNV' : 5317, + 'CallableNV' : 5318, }, 'AddressingModel' : { 'Logical' : 0, 'Physical32' : 1, 'Physical64' : 2, + 'PhysicalStorageBuffer64' : 5348, + 'PhysicalStorageBuffer64EXT' : 5348, }, 'MemoryModel' : { 'Simple' : 0, 'GLSL450' : 1, 'OpenCL' : 2, + 'Vulkan' : 3, + 'VulkanKHR' : 3, }, 'ExecutionMode' : { @@ -117,7 +132,23 @@ spv = { 'LocalSizeId' : 38, 'LocalSizeHintId' : 39, 'PostDepthCoverage' : 4446, + 'DenormPreserve' : 4459, + 'DenormFlushToZero' : 4460, + 'SignedZeroInfNanPreserve' : 4461, + 'RoundingModeRTE' : 4462, + 'RoundingModeRTZ' : 4463, 'StencilRefReplacingEXT' : 5027, + 'OutputLinesNV' : 5269, + 'OutputPrimitivesNV' : 5270, + 'DerivativeGroupQuadsNV' : 5289, + 'DerivativeGroupLinearNV' : 5290, + 'OutputTrianglesNV' : 5298, + 'PixelInterlockOrderedEXT' : 5366, + 'PixelInterlockUnorderedEXT' : 5367, + 'SampleInterlockOrderedEXT' : 5368, + 'SampleInterlockUnorderedEXT' : 5369, + 'ShadingRateInterlockOrderedEXT' : 5370, + 'ShadingRateInterlockUnorderedEXT' : 5371, }, 'StorageClass' : { @@ -134,6 +165,14 @@ spv = { 'AtomicCounter' : 10, 'Image' : 11, 'StorageBuffer' : 12, + 'CallableDataNV' : 5328, + 'IncomingCallableDataNV' : 5329, + 'RayPayloadNV' : 5338, + 'HitAttributeNV' : 5339, + 'IncomingRayPayloadNV' : 5342, + 'ShaderRecordBufferNV' : 5343, + 'PhysicalStorageBuffer' : 5349, + 'PhysicalStorageBufferEXT' : 5349, }, 'Dim' : { @@ -254,6 +293,16 @@ spv = { 'ConstOffsets' : 5, 'Sample' : 6, 'MinLod' : 7, + 'MakeTexelAvailable' : 8, + 'MakeTexelAvailableKHR' : 8, + 'MakeTexelVisible' : 9, + 'MakeTexelVisibleKHR' : 9, + 'NonPrivateTexel' : 10, + 'NonPrivateTexelKHR' : 10, + 'VolatileTexel' : 11, + 'VolatileTexelKHR' : 11, + 'SignExtend' : 12, + 'ZeroExtend' : 13, }, 'ImageOperandsMask' : { @@ -266,6 +315,16 @@ spv = { 'ConstOffsets' : 0x00000020, 'Sample' : 0x00000040, 'MinLod' : 0x00000080, + 'MakeTexelAvailable' : 0x00000100, + 'MakeTexelAvailableKHR' : 0x00000100, + 'MakeTexelVisible' : 0x00000200, + 'MakeTexelVisibleKHR' : 0x00000200, + 'NonPrivateTexel' : 0x00000400, + 'NonPrivateTexelKHR' : 0x00000400, + 'VolatileTexel' : 0x00000800, + 'VolatileTexelKHR' : 0x00000800, + 'SignExtend' : 0x00001000, + 'ZeroExtend' : 0x00002000, }, 'FPFastMathModeShift' : { @@ -341,6 +400,7 @@ spv = { 'NonWritable' : 24, 'NonReadable' : 25, 'Uniform' : 26, + 'UniformId' : 27, 'SaturatedConversion' : 28, 'Stream' : 29, 'Location' : 30, @@ -361,14 +421,28 @@ spv = { 'MaxByteOffset' : 45, 'AlignmentId' : 46, 'MaxByteOffsetId' : 47, + 'NoSignedWrap' : 4469, + 'NoUnsignedWrap' : 4470, 'ExplicitInterpAMD' : 4999, 'OverrideCoverageNV' : 5248, 'PassthroughNV' : 5250, 'ViewportRelativeNV' : 5252, 'SecondaryViewportRelativeNV' : 5256, + 'PerPrimitiveNV' : 5271, + 'PerViewNV' : 5272, + 'PerTaskNV' : 5273, + 'PerVertexNV' : 5285, + 'NonUniform' : 5300, 'NonUniformEXT' : 5300, + 'RestrictPointer' : 5355, + 'RestrictPointerEXT' : 5355, + 'AliasedPointer' : 5356, + 'AliasedPointerEXT' : 5356, + 'CounterBuffer' : 5634, 'HlslCounterBufferGOOGLE' : 5634, 'HlslSemanticGOOGLE' : 5635, + 'UserSemantic' : 5635, + 'UserTypeGOOGLE' : 5636, }, 'BuiltIn' : { @@ -442,6 +516,38 @@ spv = { 'PositionPerViewNV' : 5261, 'ViewportMaskPerViewNV' : 5262, 'FullyCoveredEXT' : 5264, + 'TaskCountNV' : 5274, + 'PrimitiveCountNV' : 5275, + 'PrimitiveIndicesNV' : 5276, + 'ClipDistancePerViewNV' : 5277, + 'CullDistancePerViewNV' : 5278, + 'LayerPerViewNV' : 5279, + 'MeshViewCountNV' : 5280, + 'MeshViewIndicesNV' : 5281, + 'BaryCoordNV' : 5286, + 'BaryCoordNoPerspNV' : 5287, + 'FragSizeEXT' : 5292, + 'FragmentSizeNV' : 5292, + 'FragInvocationCountEXT' : 5293, + 'InvocationsPerPixelNV' : 5293, + 'LaunchIdNV' : 5319, + 'LaunchSizeNV' : 5320, + 'WorldRayOriginNV' : 5321, + 'WorldRayDirectionNV' : 5322, + 'ObjectRayOriginNV' : 5323, + 'ObjectRayDirectionNV' : 5324, + 'RayTminNV' : 5325, + 'RayTmaxNV' : 5326, + 'InstanceCustomIndexNV' : 5327, + 'ObjectToWorldNV' : 5330, + 'WorldToObjectNV' : 5331, + 'HitTNV' : 5332, + 'HitKindNV' : 5333, + 'IncomingRayFlagsNV' : 5351, + 'WarpsPerSMNV' : 5374, + 'SMCountNV' : 5375, + 'WarpIDNV' : 5376, + 'SMIDNV' : 5377, }, 'SelectionControlShift' : { @@ -460,6 +566,11 @@ spv = { 'DontUnroll' : 1, 'DependencyInfinite' : 2, 'DependencyLength' : 3, + 'MinIterations' : 4, + 'MaxIterations' : 5, + 'IterationMultiple' : 6, + 'PeelCount' : 7, + 'PartialCount' : 8, }, 'LoopControlMask' : { @@ -468,6 +579,11 @@ spv = { 'DontUnroll' : 0x00000002, 'DependencyInfinite' : 0x00000004, 'DependencyLength' : 0x00000008, + 'MinIterations' : 0x00000010, + 'MaxIterations' : 0x00000020, + 'IterationMultiple' : 0x00000040, + 'PeelCount' : 0x00000080, + 'PartialCount' : 0x00000100, }, 'FunctionControlShift' : { @@ -496,6 +612,13 @@ spv = { 'CrossWorkgroupMemory' : 9, 'AtomicCounterMemory' : 10, 'ImageMemory' : 11, + 'OutputMemory' : 12, + 'OutputMemoryKHR' : 12, + 'MakeAvailable' : 13, + 'MakeAvailableKHR' : 13, + 'MakeVisible' : 14, + 'MakeVisibleKHR' : 14, + 'Volatile' : 15, }, 'MemorySemanticsMask' : { @@ -510,12 +633,25 @@ spv = { 'CrossWorkgroupMemory' : 0x00000200, 'AtomicCounterMemory' : 0x00000400, 'ImageMemory' : 0x00000800, + 'OutputMemory' : 0x00001000, + 'OutputMemoryKHR' : 0x00001000, + 'MakeAvailable' : 0x00002000, + 'MakeAvailableKHR' : 0x00002000, + 'MakeVisible' : 0x00004000, + 'MakeVisibleKHR' : 0x00004000, + 'Volatile' : 0x00008000, }, 'MemoryAccessShift' : { 'Volatile' : 0, 'Aligned' : 1, 'Nontemporal' : 2, + 'MakePointerAvailable' : 3, + 'MakePointerAvailableKHR' : 3, + 'MakePointerVisible' : 4, + 'MakePointerVisibleKHR' : 4, + 'NonPrivatePointer' : 5, + 'NonPrivatePointerKHR' : 5, }, 'MemoryAccessMask' : { @@ -523,6 +659,12 @@ spv = { 'Volatile' : 0x00000001, 'Aligned' : 0x00000002, 'Nontemporal' : 0x00000004, + 'MakePointerAvailable' : 0x00000008, + 'MakePointerAvailableKHR' : 0x00000008, + 'MakePointerVisible' : 0x00000010, + 'MakePointerVisibleKHR' : 0x00000010, + 'NonPrivatePointer' : 0x00000020, + 'NonPrivatePointerKHR' : 0x00000020, }, 'Scope' : { @@ -531,6 +673,8 @@ spv = { 'Workgroup' : 2, 'Subgroup' : 3, 'Invocation' : 4, + 'QueueFamily' : 5, + 'QueueFamilyKHR' : 5, }, 'GroupOperation' : { @@ -626,6 +770,8 @@ spv = { 'GroupNonUniformShuffleRelative' : 66, 'GroupNonUniformClustered' : 67, 'GroupNonUniformQuad' : 68, + 'ShaderLayer' : 69, + 'ShaderViewportIndex' : 70, 'SubgroupBallotKHR' : 4423, 'DrawParameters' : 4427, 'SubgroupVoteKHR' : 4431, @@ -644,11 +790,17 @@ spv = { 'StorageBuffer8BitAccess' : 4448, 'UniformAndStorageBuffer8BitAccess' : 4449, 'StoragePushConstant8' : 4450, + 'DenormPreserve' : 4464, + 'DenormFlushToZero' : 4465, + 'SignedZeroInfNanPreserve' : 4466, + 'RoundingModeRTE' : 4467, + 'RoundingModeRTZ' : 4468, 'Float16ImageAMD' : 5008, 'ImageGatherBiasLodAMD' : 5009, 'FragmentMaskAMD' : 5010, 'StencilExportEXT' : 5013, 'ImageReadWriteLodAMD' : 5015, + 'ShaderClockKHR' : 5055, 'SampleMaskOverrideCoverageNV' : 5249, 'GeometryShaderPassthroughNV' : 5251, 'ShaderViewportIndexLayerEXT' : 5254, @@ -657,22 +809,59 @@ spv = { 'ShaderStereoViewNV' : 5259, 'PerViewAttributesNV' : 5260, 'FragmentFullyCoveredEXT' : 5265, + 'MeshShadingNV' : 5266, + 'ImageFootprintNV' : 5282, + 'FragmentBarycentricNV' : 5284, + 'ComputeDerivativeGroupQuadsNV' : 5288, + 'FragmentDensityEXT' : 5291, + 'ShadingRateNV' : 5291, 'GroupNonUniformPartitionedNV' : 5297, + 'ShaderNonUniform' : 5301, 'ShaderNonUniformEXT' : 5301, + 'RuntimeDescriptorArray' : 5302, 'RuntimeDescriptorArrayEXT' : 5302, + 'InputAttachmentArrayDynamicIndexing' : 5303, 'InputAttachmentArrayDynamicIndexingEXT' : 5303, + 'UniformTexelBufferArrayDynamicIndexing' : 5304, 'UniformTexelBufferArrayDynamicIndexingEXT' : 5304, + 'StorageTexelBufferArrayDynamicIndexing' : 5305, 'StorageTexelBufferArrayDynamicIndexingEXT' : 5305, + 'UniformBufferArrayNonUniformIndexing' : 5306, 'UniformBufferArrayNonUniformIndexingEXT' : 5306, + 'SampledImageArrayNonUniformIndexing' : 5307, 'SampledImageArrayNonUniformIndexingEXT' : 5307, + 'StorageBufferArrayNonUniformIndexing' : 5308, 'StorageBufferArrayNonUniformIndexingEXT' : 5308, + 'StorageImageArrayNonUniformIndexing' : 5309, 'StorageImageArrayNonUniformIndexingEXT' : 5309, + 'InputAttachmentArrayNonUniformIndexing' : 5310, 'InputAttachmentArrayNonUniformIndexingEXT' : 5310, + 'UniformTexelBufferArrayNonUniformIndexing' : 5311, 'UniformTexelBufferArrayNonUniformIndexingEXT' : 5311, + 'StorageTexelBufferArrayNonUniformIndexing' : 5312, 'StorageTexelBufferArrayNonUniformIndexingEXT' : 5312, + 'RayTracingNV' : 5340, + 'VulkanMemoryModel' : 5345, + 'VulkanMemoryModelKHR' : 5345, + 'VulkanMemoryModelDeviceScope' : 5346, + 'VulkanMemoryModelDeviceScopeKHR' : 5346, + 'PhysicalStorageBufferAddresses' : 5347, + 'PhysicalStorageBufferAddressesEXT' : 5347, + 'ComputeDerivativeGroupLinearNV' : 5350, + 'CooperativeMatrixNV' : 5357, + 'FragmentShaderSampleInterlockEXT' : 5363, + 'FragmentShaderShadingRateInterlockEXT' : 5372, + 'ShaderSMBuiltinsNV' : 5373, + 'FragmentShaderPixelInterlockEXT' : 5378, + 'DemoteToHelperInvocationEXT' : 5379, 'SubgroupShuffleINTEL' : 5568, 'SubgroupBufferBlockIOINTEL' : 5569, 'SubgroupImageBlockIOINTEL' : 5570, + 'SubgroupImageMediaBlockIOINTEL' : 5579, + 'IntegerFunctions2INTEL' : 5584, + 'SubgroupAvcMotionEstimationINTEL' : 5696, + 'SubgroupAvcMotionEstimationIntraINTEL' : 5697, + 'SubgroupAvcMotionEstimationChromaINTEL' : 5698, }, 'Op' : { @@ -1016,6 +1205,10 @@ spv = { 'OpGroupNonUniformLogicalXor' : 364, 'OpGroupNonUniformQuadBroadcast' : 365, 'OpGroupNonUniformQuadSwap' : 366, + 'OpCopyLogical' : 400, + 'OpPtrEqual' : 401, + 'OpPtrNotEqual' : 402, + 'OpPtrDiff' : 403, 'OpSubgroupBallotKHR' : 4421, 'OpSubgroupFirstInvocationKHR' : 4422, 'OpSubgroupAllKHR' : 4428, @@ -1032,7 +1225,25 @@ spv = { 'OpGroupSMaxNonUniformAMD' : 5007, 'OpFragmentMaskFetchAMD' : 5011, 'OpFragmentFetchAMD' : 5012, + 'OpReadClockKHR' : 5056, + 'OpImageSampleFootprintNV' : 5283, 'OpGroupNonUniformPartitionNV' : 5296, + 'OpWritePackedPrimitiveIndices4x8NV' : 5299, + 'OpReportIntersectionNV' : 5334, + 'OpIgnoreIntersectionNV' : 5335, + 'OpTerminateRayNV' : 5336, + 'OpTraceNV' : 5337, + 'OpTypeAccelerationStructureNV' : 5341, + 'OpExecuteCallableNV' : 5344, + 'OpTypeCooperativeMatrixNV' : 5358, + 'OpCooperativeMatrixLoadNV' : 5359, + 'OpCooperativeMatrixStoreNV' : 5360, + 'OpCooperativeMatrixMulAddNV' : 5361, + 'OpCooperativeMatrixLengthNV' : 5362, + 'OpBeginInvocationInterlockEXT' : 5364, + 'OpEndInvocationInterlockEXT' : 5365, + 'OpDemoteToHelperInvocationEXT' : 5380, + 'OpIsHelperInvocationEXT' : 5381, 'OpSubgroupShuffleINTEL' : 5571, 'OpSubgroupShuffleDownINTEL' : 5572, 'OpSubgroupShuffleUpINTEL' : 5573, @@ -1041,8 +1252,144 @@ spv = { 'OpSubgroupBlockWriteINTEL' : 5576, 'OpSubgroupImageBlockReadINTEL' : 5577, 'OpSubgroupImageBlockWriteINTEL' : 5578, + 'OpSubgroupImageMediaBlockReadINTEL' : 5580, + 'OpSubgroupImageMediaBlockWriteINTEL' : 5581, + 'OpUCountLeadingZerosINTEL' : 5585, + 'OpUCountTrailingZerosINTEL' : 5586, + 'OpAbsISubINTEL' : 5587, + 'OpAbsUSubINTEL' : 5588, + 'OpIAddSatINTEL' : 5589, + 'OpUAddSatINTEL' : 5590, + 'OpIAverageINTEL' : 5591, + 'OpUAverageINTEL' : 5592, + 'OpIAverageRoundedINTEL' : 5593, + 'OpUAverageRoundedINTEL' : 5594, + 'OpISubSatINTEL' : 5595, + 'OpUSubSatINTEL' : 5596, + 'OpIMul32x16INTEL' : 5597, + 'OpUMul32x16INTEL' : 5598, + 'OpDecorateString' : 5632, 'OpDecorateStringGOOGLE' : 5632, + 'OpMemberDecorateString' : 5633, 'OpMemberDecorateStringGOOGLE' : 5633, + 'OpVmeImageINTEL' : 5699, + 'OpTypeVmeImageINTEL' : 5700, + 'OpTypeAvcImePayloadINTEL' : 5701, + 'OpTypeAvcRefPayloadINTEL' : 5702, + 'OpTypeAvcSicPayloadINTEL' : 5703, + 'OpTypeAvcMcePayloadINTEL' : 5704, + 'OpTypeAvcMceResultINTEL' : 5705, + 'OpTypeAvcImeResultINTEL' : 5706, + 'OpTypeAvcImeResultSingleReferenceStreamoutINTEL' : 5707, + 'OpTypeAvcImeResultDualReferenceStreamoutINTEL' : 5708, + 'OpTypeAvcImeSingleReferenceStreaminINTEL' : 5709, + 'OpTypeAvcImeDualReferenceStreaminINTEL' : 5710, + 'OpTypeAvcRefResultINTEL' : 5711, + 'OpTypeAvcSicResultINTEL' : 5712, + 'OpSubgroupAvcMceGetDefaultInterBaseMultiReferencePenaltyINTEL' : 5713, + 'OpSubgroupAvcMceSetInterBaseMultiReferencePenaltyINTEL' : 5714, + 'OpSubgroupAvcMceGetDefaultInterShapePenaltyINTEL' : 5715, + 'OpSubgroupAvcMceSetInterShapePenaltyINTEL' : 5716, + 'OpSubgroupAvcMceGetDefaultInterDirectionPenaltyINTEL' : 5717, + 'OpSubgroupAvcMceSetInterDirectionPenaltyINTEL' : 5718, + 'OpSubgroupAvcMceGetDefaultIntraLumaShapePenaltyINTEL' : 5719, + 'OpSubgroupAvcMceGetDefaultInterMotionVectorCostTableINTEL' : 5720, + 'OpSubgroupAvcMceGetDefaultHighPenaltyCostTableINTEL' : 5721, + 'OpSubgroupAvcMceGetDefaultMediumPenaltyCostTableINTEL' : 5722, + 'OpSubgroupAvcMceGetDefaultLowPenaltyCostTableINTEL' : 5723, + 'OpSubgroupAvcMceSetMotionVectorCostFunctionINTEL' : 5724, + 'OpSubgroupAvcMceGetDefaultIntraLumaModePenaltyINTEL' : 5725, + 'OpSubgroupAvcMceGetDefaultNonDcLumaIntraPenaltyINTEL' : 5726, + 'OpSubgroupAvcMceGetDefaultIntraChromaModeBasePenaltyINTEL' : 5727, + 'OpSubgroupAvcMceSetAcOnlyHaarINTEL' : 5728, + 'OpSubgroupAvcMceSetSourceInterlacedFieldPolarityINTEL' : 5729, + 'OpSubgroupAvcMceSetSingleReferenceInterlacedFieldPolarityINTEL' : 5730, + 'OpSubgroupAvcMceSetDualReferenceInterlacedFieldPolaritiesINTEL' : 5731, + 'OpSubgroupAvcMceConvertToImePayloadINTEL' : 5732, + 'OpSubgroupAvcMceConvertToImeResultINTEL' : 5733, + 'OpSubgroupAvcMceConvertToRefPayloadINTEL' : 5734, + 'OpSubgroupAvcMceConvertToRefResultINTEL' : 5735, + 'OpSubgroupAvcMceConvertToSicPayloadINTEL' : 5736, + 'OpSubgroupAvcMceConvertToSicResultINTEL' : 5737, + 'OpSubgroupAvcMceGetMotionVectorsINTEL' : 5738, + 'OpSubgroupAvcMceGetInterDistortionsINTEL' : 5739, + 'OpSubgroupAvcMceGetBestInterDistortionsINTEL' : 5740, + 'OpSubgroupAvcMceGetInterMajorShapeINTEL' : 5741, + 'OpSubgroupAvcMceGetInterMinorShapeINTEL' : 5742, + 'OpSubgroupAvcMceGetInterDirectionsINTEL' : 5743, + 'OpSubgroupAvcMceGetInterMotionVectorCountINTEL' : 5744, + 'OpSubgroupAvcMceGetInterReferenceIdsINTEL' : 5745, + 'OpSubgroupAvcMceGetInterReferenceInterlacedFieldPolaritiesINTEL' : 5746, + 'OpSubgroupAvcImeInitializeINTEL' : 5747, + 'OpSubgroupAvcImeSetSingleReferenceINTEL' : 5748, + 'OpSubgroupAvcImeSetDualReferenceINTEL' : 5749, + 'OpSubgroupAvcImeRefWindowSizeINTEL' : 5750, + 'OpSubgroupAvcImeAdjustRefOffsetINTEL' : 5751, + 'OpSubgroupAvcImeConvertToMcePayloadINTEL' : 5752, + 'OpSubgroupAvcImeSetMaxMotionVectorCountINTEL' : 5753, + 'OpSubgroupAvcImeSetUnidirectionalMixDisableINTEL' : 5754, + 'OpSubgroupAvcImeSetEarlySearchTerminationThresholdINTEL' : 5755, + 'OpSubgroupAvcImeSetWeightedSadINTEL' : 5756, + 'OpSubgroupAvcImeEvaluateWithSingleReferenceINTEL' : 5757, + 'OpSubgroupAvcImeEvaluateWithDualReferenceINTEL' : 5758, + 'OpSubgroupAvcImeEvaluateWithSingleReferenceStreaminINTEL' : 5759, + 'OpSubgroupAvcImeEvaluateWithDualReferenceStreaminINTEL' : 5760, + 'OpSubgroupAvcImeEvaluateWithSingleReferenceStreamoutINTEL' : 5761, + 'OpSubgroupAvcImeEvaluateWithDualReferenceStreamoutINTEL' : 5762, + 'OpSubgroupAvcImeEvaluateWithSingleReferenceStreaminoutINTEL' : 5763, + 'OpSubgroupAvcImeEvaluateWithDualReferenceStreaminoutINTEL' : 5764, + 'OpSubgroupAvcImeConvertToMceResultINTEL' : 5765, + 'OpSubgroupAvcImeGetSingleReferenceStreaminINTEL' : 5766, + 'OpSubgroupAvcImeGetDualReferenceStreaminINTEL' : 5767, + 'OpSubgroupAvcImeStripSingleReferenceStreamoutINTEL' : 5768, + 'OpSubgroupAvcImeStripDualReferenceStreamoutINTEL' : 5769, + 'OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeMotionVectorsINTEL' : 5770, + 'OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeDistortionsINTEL' : 5771, + 'OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeReferenceIdsINTEL' : 5772, + 'OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeMotionVectorsINTEL' : 5773, + 'OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeDistortionsINTEL' : 5774, + 'OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeReferenceIdsINTEL' : 5775, + 'OpSubgroupAvcImeGetBorderReachedINTEL' : 5776, + 'OpSubgroupAvcImeGetTruncatedSearchIndicationINTEL' : 5777, + 'OpSubgroupAvcImeGetUnidirectionalEarlySearchTerminationINTEL' : 5778, + 'OpSubgroupAvcImeGetWeightingPatternMinimumMotionVectorINTEL' : 5779, + 'OpSubgroupAvcImeGetWeightingPatternMinimumDistortionINTEL' : 5780, + 'OpSubgroupAvcFmeInitializeINTEL' : 5781, + 'OpSubgroupAvcBmeInitializeINTEL' : 5782, + 'OpSubgroupAvcRefConvertToMcePayloadINTEL' : 5783, + 'OpSubgroupAvcRefSetBidirectionalMixDisableINTEL' : 5784, + 'OpSubgroupAvcRefSetBilinearFilterEnableINTEL' : 5785, + 'OpSubgroupAvcRefEvaluateWithSingleReferenceINTEL' : 5786, + 'OpSubgroupAvcRefEvaluateWithDualReferenceINTEL' : 5787, + 'OpSubgroupAvcRefEvaluateWithMultiReferenceINTEL' : 5788, + 'OpSubgroupAvcRefEvaluateWithMultiReferenceInterlacedINTEL' : 5789, + 'OpSubgroupAvcRefConvertToMceResultINTEL' : 5790, + 'OpSubgroupAvcSicInitializeINTEL' : 5791, + 'OpSubgroupAvcSicConfigureSkcINTEL' : 5792, + 'OpSubgroupAvcSicConfigureIpeLumaINTEL' : 5793, + 'OpSubgroupAvcSicConfigureIpeLumaChromaINTEL' : 5794, + 'OpSubgroupAvcSicGetMotionVectorMaskINTEL' : 5795, + 'OpSubgroupAvcSicConvertToMcePayloadINTEL' : 5796, + 'OpSubgroupAvcSicSetIntraLumaShapePenaltyINTEL' : 5797, + 'OpSubgroupAvcSicSetIntraLumaModeCostFunctionINTEL' : 5798, + 'OpSubgroupAvcSicSetIntraChromaModeCostFunctionINTEL' : 5799, + 'OpSubgroupAvcSicSetBilinearFilterEnableINTEL' : 5800, + 'OpSubgroupAvcSicSetSkcForwardTransformEnableINTEL' : 5801, + 'OpSubgroupAvcSicSetBlockBasedRawSkipSadINTEL' : 5802, + 'OpSubgroupAvcSicEvaluateIpeINTEL' : 5803, + 'OpSubgroupAvcSicEvaluateWithSingleReferenceINTEL' : 5804, + 'OpSubgroupAvcSicEvaluateWithDualReferenceINTEL' : 5805, + 'OpSubgroupAvcSicEvaluateWithMultiReferenceINTEL' : 5806, + 'OpSubgroupAvcSicEvaluateWithMultiReferenceInterlacedINTEL' : 5807, + 'OpSubgroupAvcSicConvertToMceResultINTEL' : 5808, + 'OpSubgroupAvcSicGetIpeLumaShapeINTEL' : 5809, + 'OpSubgroupAvcSicGetBestIpeLumaDistortionINTEL' : 5810, + 'OpSubgroupAvcSicGetBestIpeChromaDistortionINTEL' : 5811, + 'OpSubgroupAvcSicGetPackedIpeLumaModesINTEL' : 5812, + 'OpSubgroupAvcSicGetIpeChromaModeINTEL' : 5813, + 'OpSubgroupAvcSicGetPackedSkcLumaCountThresholdINTEL' : 5814, + 'OpSubgroupAvcSicGetPackedSkcLumaSumThresholdINTEL' : 5815, + 'OpSubgroupAvcSicGetInterRawSadsINTEL' : 5816, }, } diff --git a/third_party/spirv-tools/external/spirv-headers/tools/buildHeaders/CMakeLists.txt b/third_party/spirv-tools/external/spirv-headers/tools/buildHeaders/CMakeLists.txt old mode 100755 new mode 100644 diff --git a/third_party/spirv-tools/external/spirv-headers/tools/buildHeaders/bin/makeHeaders b/third_party/spirv-tools/external/spirv-headers/tools/buildHeaders/bin/makeHeaders index bf2c61515f..47d2218649 100755 --- a/third_party/spirv-tools/external/spirv-headers/tools/buildHeaders/bin/makeHeaders +++ b/third_party/spirv-tools/external/spirv-headers/tools/buildHeaders/bin/makeHeaders @@ -2,4 +2,4 @@ cd ../../include/spirv/unified1 ../../../tools/buildHeaders/build/install/bin/buildSpvHeaders -H spirv.core.grammar.json -dos2unix spirv.* +dos2unix spirv.* SpirV.* spv.* diff --git a/third_party/spirv-tools/external/spirv-headers/tools/buildHeaders/header.cpp b/third_party/spirv-tools/external/spirv-headers/tools/buildHeaders/header.cpp old mode 100755 new mode 100644 index b8b227f3bc..0f65291b52 --- a/third_party/spirv-tools/external/spirv-headers/tools/buildHeaders/header.cpp +++ b/third_party/spirv-tools/external/spirv-headers/tools/buildHeaders/header.cpp @@ -1,19 +1,19 @@ -// Copyright (c) 2014-2018 The Khronos Group Inc. -// +// Copyright (c) 2014-2019 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"), // to deal in the Materials without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Materials, and to permit persons to whom the // Materials are furnished to do so, subject to the following conditions: -// +// // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Materials. -// +// // MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS // STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND -// HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/ -// +// HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/ +// // THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL @@ -42,6 +42,7 @@ #include #include #include +#include #include "jsoncpp/dist/json/json.h" @@ -68,7 +69,7 @@ namespace { TPrinter(); static const int DocMagicNumber = 0x07230203; - static const int DocVersion = 0x00010300; + static const int DocVersion = 0x00010500; static const int DocRevision = 1; #define DocRevisionString "1" static const std::string DocCopyright; @@ -97,7 +98,8 @@ namespace { virtual void printEpilogue(std::ostream&) const { } virtual void printMeta(std::ostream&) const; virtual void printTypes(std::ostream&) const { } - + virtual void printHasResultType(std::ostream&) const { }; + virtual std::string escapeComment(const std::string& s) const; // Default printComments() uses these comment strings @@ -107,7 +109,7 @@ namespace { virtual std::string commentEOL(bool isLast) const { return ""; } typedef std::pair valpair_t; - + // for printing enum values virtual std::string enumBeg(const std::string&, enumStyle_t) const { return ""; } virtual std::string enumEnd(const std::string&, enumStyle_t, bool isLast = false) const { @@ -126,7 +128,7 @@ namespace { const char* fmt, bool isLast = false) const { return ""; } - + std::vector getSortedVals(const Json::Value&) const; virtual std::string indent(int count = 1) const { @@ -149,7 +151,7 @@ namespace { } void addComment(Json::Value& node, const std::string& str); - + Json::Value spvRoot; // JSON SPIR-V data }; @@ -167,7 +169,7 @@ namespace { } const std::string TPrinter::DocCopyright = - "Copyright (c) 2014-2018 The Khronos Group Inc.\n" + "Copyright (c) 2014-2019 The Khronos Group Inc.\n" "\n" "Permission is hereby granted, free of charge, to any person obtaining a copy\n" "of this software and/or associated documentation files (the \"Materials\"),\n" @@ -197,13 +199,16 @@ namespace { const std::string TPrinter::DocComment2 = "Enumeration tokens for SPIR-V, in various styles:\n" - " C, C++, C++11, JSON, Lua, Python\n" + " C, C++, C++11, JSON, Lua, Python, C#, D\n" "\n" "- C will have tokens with a \"Spv\" prefix, e.g.: SpvSourceLanguageGLSL\n" "- C++ will have tokens in the \"spv\" name space, e.g.: spv::SourceLanguageGLSL\n" "- C++11 will use enum classes in the spv namespace, e.g.: spv::SourceLanguage::GLSL\n" "- Lua will use tables, e.g.: spv.SourceLanguage.GLSL\n" "- Python will use dictionaries, e.g.: spv['SourceLanguage']['GLSL']\n" + "- C# will use enum classes in the Specification class located in the \"Spv\" namespace,\n" + " e.g.: Spv.Specification.SourceLanguage.GLSL\n" + "- D will have tokens under the \"spv\" module, e.g: spv.SourceLanguage.GLSL\n" "\n" "Some tokens act like mask values, which can be OR'd together,\n" "while others are mutually exclusive. The mask-like ones have\n" @@ -290,7 +295,7 @@ namespace { { const int commentCount = spvRoot["spv"]["meta"]["Comment"].size(); int commentNum = 0; - + for (const auto& comment : spvRoot["spv"]["meta"]["Comment"]) { out << commentBeg(); @@ -322,7 +327,7 @@ namespace { void TPrinter::printDefs(std::ostream& out) const { const Json::Value& enums = spvRoot["spv"]["enum"]; - + for (auto opClass = enums.begin(); opClass != enums.end(); ++opClass) { const bool isMask = (*opClass)["Type"].asString() == "Bit"; const auto opName = (*opClass)["Name"].asString(); @@ -337,13 +342,13 @@ namespace { out << enumFmt(opPrefix, valpair_t(0, "MaskNone"), enumNoMask); const auto sorted = getSortedVals((*opClass)["Values"]); - - std::string maxEnum = maxEnumFmt(opName, valpair_t(0x7FFFFFFF, "Max"), enumHex); + + std::string maxEnum = maxEnumFmt(opName, valpair_t(0x7FFFFFFF, "Max"), enumHex); bool printMax = (style != enumMask && maxEnum.size() > 0); for (const auto& v : sorted) - out << enumFmt(opPrefix, v, style, !printMax && v.first == sorted.back().first); + out << enumFmt(opPrefix, v, style, !printMax && v.second == sorted.back().second); if (printMax) out << maxEnum; @@ -361,6 +366,7 @@ namespace { printTypes(out); printMeta(out); printDefs(out); + printHasResultType(out); printEpilogue(out); } @@ -390,7 +396,7 @@ namespace { } return newStr; } - + std::string fmtConstInt(unsigned val, const std::string& name, const char* fmt, bool isLast) const override { return indent(3) + '"' + name + "\": " + fmtNum("%d", val) + (isLast ? "\n" : ",\n"); @@ -475,7 +481,7 @@ namespace { } virtual void printEpilogue(std::ostream& out) const override { - out << "#endif // #ifndef spirv_" << headerGuardSuffix() << std::endl; + out << "#endif" << std::endl; } virtual void printTypes(std::ostream& out) const override { @@ -488,9 +494,48 @@ namespace { return std::string("static const unsigned int ") + pre() + name + " = " + fmtNum(fmt, val) + (isLast ? ";\n\n" : ";\n"); } - + virtual std::string pre() const { return ""; } // C name prefix virtual std::string headerGuardSuffix() const = 0; + + virtual std::string fmtEnumUse(const std::string& opPrefix, const std::string& name) const { return pre() + name; } + + virtual void printHasResultType(std::ostream& out) const + { + const Json::Value& enums = spvRoot["spv"]["enum"]; + + std::set seenValues; + + for (auto opClass = enums.begin(); opClass != enums.end(); ++opClass) { + const auto opName = (*opClass)["Name"].asString(); + if (opName != "Op") { + continue; + } + + out << "#ifdef SPV_ENABLE_UTILITY_CODE" << std::endl; + out << "inline void " << pre() << "HasResultAndType(" << pre() << opName << " opcode, bool *hasResult, bool *hasResultType) {" << std::endl; + out << " *hasResult = *hasResultType = false;" << std::endl; + out << " switch (opcode) {" << std::endl; + out << " default: /* unknown opcode */ break;" << std::endl; + + for (auto& inst : spv::InstructionDesc) { + + // Filter out duplicate enum values, which would break the switch statement. + // These are probably just extension enums promoted to core. + if (seenValues.find(inst.value) != seenValues.end()) { + continue; + } + seenValues.insert(inst.value); + + std::string name = inst.name; + out << " case " << fmtEnumUse("Op", name) << ": *hasResult = " << (inst.hasResult() ? "true" : "false") << "; *hasResultType = " << (inst.hasType() ? "true" : "false") << "; break;" << std::endl; + } + + out << " }" << std::endl; + out << "}" << std::endl; + out << "#endif /* SPV_ENABLE_UTILITY_CODE */" << std::endl << std::endl; + } + } }; // C printer @@ -542,19 +587,19 @@ namespace { if (isMask) { const auto typeName = opName + styleStr(enumMask); - + out << "inline " + typeName + " operator|(" + typeName + " a, " + typeName + " b) { return " + typeName + "(unsigned(a) | unsigned(b)); }\n"; } } out << "\n} // end namespace spv\n\n"; - TPrinterCBase::printEpilogue(out); + out << "#endif // #ifndef spirv_" << headerGuardSuffix() << std::endl; } std::string commentBOL() const override { return "// "; } - + virtual std::string enumBeg(const std::string& s, enumStyle_t style) const override { return std::string("enum ") + s + styleStr(style) + " {\n"; } @@ -597,6 +642,9 @@ namespace { return enumFmt(s, v, style, true); } + // Add type prefix for scoped enum + virtual std::string fmtEnumUse(const std::string& opPrefix, const std::string& name) const { return opPrefix + "::" + name; } + std::string headerGuardSuffix() const override { return "HPP"; } }; @@ -658,6 +706,76 @@ namespace { } }; + // C# printer + class TPrinterCSharp final : public TPrinter { + private: + std::string commentBOL() const override { return "// "; } + + void printPrologue(std::ostream& out) const override { + out << "namespace Spv\n{\n\n"; + out << indent() << "public static class Specification\n"; + out << indent() << "{\n"; + } + + void printEpilogue(std::ostream& out) const override { + out << indent() << "}\n"; + out << "}\n"; + } + + std::string enumBeg(const std::string& s, enumStyle_t style) const override { + return indent(2) + "public enum " + s + styleStr(style) + "\n" + indent(2) + "{\n"; + } + + std::string enumEnd(const std::string& s, enumStyle_t style, bool isLast) const override { + return indent(2) + "}" + + (isLast ? "\n" : "\n\n"); + } + + std::string enumFmt(const std::string& s, const valpair_t& v, + enumStyle_t style, bool isLast) const override { + return indent(3) + prependIfDigit(s, v.second) + " = " + fmtStyleVal(v.first, style) + ",\n"; + } + + std::string fmtConstInt(unsigned val, const std::string& name, + const char* fmt, bool isLast) const override { + return indent(2) + std::string("public const uint ") + name + + " = " + fmtNum(fmt, val) + (isLast ? ";\n\n" : ";\n"); + } + }; + + // D printer + class TPrinterD final : public TPrinter { + private: + std::string commentBeg() const override { return "/+\n"; } + std::string commentBOL() const override { return " + "; } + std::string commentEnd(bool isLast) const override { return " +/\n"; } + + void printPrologue(std::ostream& out) const override { + out << "module spv;\n\n"; + } + + void printEpilogue(std::ostream& out) const override { + } + + std::string enumBeg(const std::string& s, enumStyle_t style) const override { + return "enum " + s + styleStr(style) + " : uint\n{\n"; + } + + std::string enumEnd(const std::string& s, enumStyle_t style, bool isLast) const override { + return std::string("}\n\n"); + } + + std::string enumFmt(const std::string& s, const valpair_t& v, + enumStyle_t style, bool isLast) const override { + return indent() + prependIfDigit("_", v.second) + " = " + fmtStyleVal(v.first, style) + ",\n"; + } + + std::string fmtConstInt(unsigned val, const std::string& name, + const char* fmt, bool isLast) const override { + return std::string("enum uint ") + name + + " = " + fmtNum(fmt, val) + (isLast ? ";\n\n" : ";\n"); + } + }; + } // namespace namespace spv { @@ -672,6 +790,8 @@ namespace spv { langInfo.push_back(std::make_pair(ELangJSON, "spirv.json")); langInfo.push_back(std::make_pair(ELangLua, "spirv.lua")); langInfo.push_back(std::make_pair(ELangPython, "spirv.py")); + langInfo.push_back(std::make_pair(ELangCSharp, "spirv.cs")); + langInfo.push_back(std::make_pair(ELangD, "spv.d")); for (const auto& lang : langInfo) { std::ofstream out(lang.second, std::ios::out); @@ -697,6 +817,8 @@ namespace spv { case ELangJSON: p = TPrinterPtr(new TPrinterJSON); break; case ELangLua: p = TPrinterPtr(new TPrinterLua); break; case ELangPython: p = TPrinterPtr(new TPrinterPython); break; + case ELangCSharp: p = TPrinterPtr(new TPrinterCSharp); break; + case ELangD: p = TPrinterPtr(new TPrinterD); break; case ELangAll: PrintAllHeaders(); break; default: std::cerr << "Unknown language." << std::endl; diff --git a/third_party/spirv-tools/external/spirv-headers/tools/buildHeaders/header.h b/third_party/spirv-tools/external/spirv-headers/tools/buildHeaders/header.h old mode 100755 new mode 100644 index 5a0952db2d..9c34b21128 --- a/third_party/spirv-tools/external/spirv-headers/tools/buildHeaders/header.h +++ b/third_party/spirv-tools/external/spirv-headers/tools/buildHeaders/header.h @@ -1,19 +1,19 @@ -// Copyright (c) 2014-2018 The Khronos Group Inc. -// +// Copyright (c) 2014-2019 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"), // to deal in the Materials without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Materials, and to permit persons to whom the // Materials are furnished to do so, subject to the following conditions: -// +// // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Materials. -// +// // MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS // STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND -// HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/ -// +// HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/ +// // THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL @@ -41,6 +41,8 @@ namespace spv { ELangJSON, // JSON ELangLua, // Lua ELangPython, // Python + ELangCSharp, // CSharp + ELangD, // D ELangAll, // print headers in all languages to files }; diff --git a/third_party/spirv-tools/external/spirv-headers/tools/buildHeaders/jsonToSpirv.cpp b/third_party/spirv-tools/external/spirv-headers/tools/buildHeaders/jsonToSpirv.cpp old mode 100755 new mode 100644 index bb325661ef..2190bd3d48 --- a/third_party/spirv-tools/external/spirv-headers/tools/buildHeaders/jsonToSpirv.cpp +++ b/third_party/spirv-tools/external/spirv-headers/tools/buildHeaders/jsonToSpirv.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2018 The Khronos Group Inc. +// Copyright (c) 2014-2019 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"), @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -40,6 +41,10 @@ namespace spv { // parameterization information. InstructionValues InstructionDesc; +// The ordered list (in printing order) of printing classes +// (specification subsections). +PrintingClasses InstructionPrintingClasses; + // Note: There is no entry for OperandOpcode. Use InstructionDesc instead. EnumDefinition OperandClassParams[OperandOpcode]; EnumValues SourceLanguageParams; @@ -119,8 +124,7 @@ ClassOptionality ToOperandClassAndOptionality(const std::string& operandKind, co else if (quantifier == "?") return {OperandLiteralString, true}; else { - assert(0 && "this case should not exist"); - return {OperandNone, false}; + return {OperandOptionalLiteralStrings, false}; } } else if (operandKind == "PairLiteralIntegerIdRef") { // Used by OpSwitch in the grammar @@ -198,7 +202,7 @@ ClassOptionality ToOperandClassAndOptionality(const std::string& operandKind, co } else if (operandKind == "FunctionControl") { type = OperandFunction; } else if (operandKind == "MemoryAccess") { - type = OperandMemoryAccess; + type = OperandMemoryOperands; } if (type == OperandNone) { @@ -230,7 +234,7 @@ unsigned int NumberStringToBit(const std::string& str) return bit; } -void jsonToSpirv(const std::string& jsonPath) +void jsonToSpirv(const std::string& jsonPath, bool buildingHeaders) { // only do this once. static bool initialized = false; @@ -285,12 +289,40 @@ void jsonToSpirv(const std::string& jsonPath) return result; }; + // set up the printing classes + std::unordered_set tags; // short-lived local for error checking below + const Json::Value printingClasses = root["instruction_printing_class"]; + for (const auto& printingClass : printingClasses) { + if (printingClass["tag"].asString().size() > 0) + tags.insert(printingClass["tag"].asString()); // just for error checking + else + std::cerr << "Error: each instruction_printing_class requires a non-empty \"tag\"" << std::endl; + if (buildingHeaders || printingClass["tag"].asString() != "@exclude") { + InstructionPrintingClasses.push_back({printingClass["tag"].asString(), + printingClass["heading"].asString()}); + } + } + + // process the instructions const Json::Value insts = root["instructions"]; for (const auto& inst : insts) { - const unsigned int opcode = inst["opcode"].asUInt(); + const auto printingClass = inst["class"].asString(); + if (printingClass.size() == 0) { + std::cerr << "Error: " << inst["opname"].asString() + << " requires a non-empty printing \"class\" tag" << std::endl; + } + if (!buildingHeaders && printingClass == "@exclude") + continue; + if (tags.find(printingClass) == tags.end()) { + std::cerr << "Error: " << inst["opname"].asString() + << " requires a \"class\" declared as a \"tag\" in \"instruction printing_class\"" + << std::endl; + } + const auto opcode = inst["opcode"].asUInt(); const std::string name = inst["opname"].asString(); EnumCaps caps = getCaps(inst); std::string version = inst["version"].asString(); + std::string lastVersion = inst["lastVersion"].asString(); Extensions exts = getExts(inst); OperandParameters operands; bool defResultId = false; @@ -306,9 +338,9 @@ void jsonToSpirv(const std::string& jsonPath) } InstructionDesc.emplace_back( std::move(EnumValue(opcode, name, - std::move(caps), std::move(version), std::move(exts), + std::move(caps), std::move(version), std::move(lastVersion), std::move(exts), std::move(operands))), - defTypeId, defResultId); + printingClass, defTypeId, defResultId); } // Specific additional context-dependent operands @@ -339,6 +371,7 @@ void jsonToSpirv(const std::string& jsonPath) continue; EnumCaps caps(getCaps(enumerant)); std::string version = enumerant["version"].asString(); + std::string lastVersion = enumerant["lastVersion"].asString(); Extensions exts(getExts(enumerant)); OperandParameters params; const Json::Value& paramsJson = enumerant["parameters"]; @@ -353,7 +386,7 @@ void jsonToSpirv(const std::string& jsonPath) } dest->emplace_back( value, enumerant["enumerant"].asString(), - std::move(caps), std::move(version), std::move(exts), std::move(params)); + std::move(caps), std::move(version), std::move(lastVersion), std::move(exts), std::move(params)); } }; @@ -421,7 +454,7 @@ void jsonToSpirv(const std::string& jsonPath) } else if (enumName == "Dim") { establishOperandClass(enumName, OperandDimensionality, &DimensionalityParams, operandEnum, category); } else if (enumName == "MemoryAccess") { - establishOperandClass(enumName, OperandMemoryAccess, &MemoryAccessParams, operandEnum, category); + establishOperandClass(enumName, OperandMemoryOperands, &MemoryAccessParams, operandEnum, category); } else if (enumName == "Scope") { establishOperandClass(enumName, OperandScope, &ScopeParams, operandEnum, category); } else if (enumName == "GroupOperation") { diff --git a/third_party/spirv-tools/external/spirv-headers/tools/buildHeaders/jsonToSpirv.h b/third_party/spirv-tools/external/spirv-headers/tools/buildHeaders/jsonToSpirv.h old mode 100755 new mode 100644 index 00a2f70d9a..0764de36cd --- a/third_party/spirv-tools/external/spirv-headers/tools/buildHeaders/jsonToSpirv.h +++ b/third_party/spirv-tools/external/spirv-headers/tools/buildHeaders/jsonToSpirv.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2018 The Khronos Group Inc. +// Copyright (c) 2014-2019 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"), @@ -38,7 +38,7 @@ namespace spv { std::pair ReadFile(const std::string& path); // Fill in all the parameters -void jsonToSpirv(const std::string& jsonPath); +void jsonToSpirv(const std::string& jsonPath, bool buildingHeaders); // For parameterizing operands. enum OperandClass { @@ -47,6 +47,7 @@ enum OperandClass { OperandVariableIds, OperandOptionalLiteral, OperandOptionalLiteralString, + OperandOptionalLiteralStrings, OperandVariableLiterals, OperandVariableIdLiteral, OperandVariableLiteralId, @@ -76,7 +77,7 @@ enum OperandClass { OperandLoop, OperandFunction, OperandMemorySemantics, - OperandMemoryAccess, + OperandMemoryOperands, OperandScope, OperandGroupOperation, OperandKernelEnqueueFlags, @@ -88,6 +89,13 @@ enum OperandClass { OperandCount }; +// For direct representation of the JSON grammar "instruction_printing_class". +struct PrintingClass { + std::string tag; + std::string heading; +}; +using PrintingClasses = std::vector; + // Any specific enum can have a set of capabilities that allow it: typedef std::vector EnumCaps; @@ -145,6 +153,12 @@ public: assert((where != end()) && "Could not find enum in the enum list"); return *where; } + // gets *all* entries for the value, including the first one + void gatherAliases(unsigned value, std::vector& aliases) { + std::for_each(begin(), end(), [&](EValue& e) { + if (value == e.value) + aliases.push_back(&e);}); + } // Returns the EValue with the given name. We assume uniqueness // by name. EValue& at(std::string name) { @@ -167,9 +181,11 @@ private: class EnumValue { public: EnumValue() : value(0), desc(nullptr) {} - EnumValue(unsigned int the_value, const std::string& the_name, EnumCaps&& the_caps, const std::string& the_version, - Extensions&& the_extensions, OperandParameters&& the_operands) : - value(the_value), name(the_name), capabilities(std::move(the_caps)), version(std::move(the_version)), + EnumValue(unsigned int the_value, const std::string& the_name, EnumCaps&& the_caps, + const std::string& the_firstVersion, const std::string& the_lastVersion, + Extensions&& the_extensions, OperandParameters&& the_operands) : + value(the_value), name(the_name), capabilities(std::move(the_caps)), + firstVersion(std::move(the_firstVersion)), lastVersion(std::move(the_lastVersion)), extensions(std::move(the_extensions)), operands(std::move(the_operands)), desc(nullptr) { } // For ValueEnum, the value from the JSON file. @@ -178,7 +194,8 @@ public: unsigned value; std::string name; EnumCaps capabilities; - std::string version; + std::string firstVersion; + std::string lastVersion; // A feature only be enabled by certain extensions. // An empty list means the feature does not require an extension. // Normally, only Capability enums are enabled by extension. In turn, @@ -228,28 +245,39 @@ public: // per OperandParameters above. class InstructionValue : public EnumValue { public: - InstructionValue(EnumValue&& e, bool has_type, bool has_result) + InstructionValue(EnumValue&& e, const std::string& printClass, bool has_type, bool has_result) : EnumValue(std::move(e)), + printingClass(printClass), opDesc("TBD"), - opClass(0), typePresent(has_type), - resultPresent(has_result) {} + resultPresent(has_result), + alias(this) { } + InstructionValue(const InstructionValue& v) + { + *this = v; + alias = this; + } bool hasResult() const { return resultPresent != 0; } bool hasType() const { return typePresent != 0; } + void setAlias(const InstructionValue& a) { alias = &a; } + const InstructionValue& getAlias() const { return *alias; } + bool isAlias() const { return alias != this; } + std::string printingClass; const char* opDesc; - int opClass; protected: int typePresent : 1; int resultPresent : 1; + const InstructionValue* alias; // correct only after discovering the aliases; otherwise points to this }; using InstructionValues = EnumValuesContainer; // Parameterization info for all instructions. extern InstructionValues InstructionDesc; +extern PrintingClasses InstructionPrintingClasses; // These hold definitions of the enumerants used for operands. // This is indexed by OperandClass, but not including OperandOpcode. diff --git a/third_party/spirv-tools/external/spirv-headers/tools/buildHeaders/main.cpp b/third_party/spirv-tools/external/spirv-headers/tools/buildHeaders/main.cpp old mode 100755 new mode 100644 index e146b39b4b..7e5f7f808f --- a/third_party/spirv-tools/external/spirv-headers/tools/buildHeaders/main.cpp +++ b/third_party/spirv-tools/external/spirv-headers/tools/buildHeaders/main.cpp @@ -1,19 +1,19 @@ -// Copyright (c) 2014-2018 The Khronos Group Inc. -// +// Copyright (c) 2014-2019 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"), // to deal in the Materials without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Materials, and to permit persons to whom the // Materials are furnished to do so, subject to the following conditions: -// +// // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Materials. -// +// // MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS // STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND -// HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/ -// +// HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/ +// // THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL @@ -50,6 +50,8 @@ void Usage() " JSON - JSON format data\n" " Lua - Lua module\n" " Python - Python module (also accepts Py)\n" + " C# - C# module (also accepts CSharp)\n" + " D - D module\n" " -H print header in all supported languages to files in current directory\n" ); } @@ -90,6 +92,10 @@ bool ProcessArguments(int argc, char* argv[]) Language = spv::ELangLua; } else if (language == "python" || language == "py") { Language = spv::ELangPython; + } else if (language == "c#" || language == "csharp") { + Language = spv::ELangCSharp; + } else if (language == "d") { + Language = spv::ELangD; } else return false; @@ -113,7 +119,7 @@ int main(int argc, char* argv[]) return 1; } - spv::jsonToSpirv(jsonPath); + spv::jsonToSpirv(jsonPath, (Options & EOptionPrintHeader) != 0); if (Options & EOptionPrintHeader) spv::PrintHeader(Language, std::cout); diff --git a/third_party/spirv-tools/filament-specific-changes.patch b/third_party/spirv-tools/filament-specific-changes.patch new file mode 100644 index 0000000000..f375abfaea --- /dev/null +++ b/third_party/spirv-tools/filament-specific-changes.patch @@ -0,0 +1,118 @@ +diff --git a/third_party/spirv-tools/CMakeLists.txt b/third_party/spirv-tools/CMakeLists.txt +index 6ed56a81..2392dfd8 100755 +--- a/third_party/spirv-tools/CMakeLists.txt ++++ b/third_party/spirv-tools/CMakeLists.txt +@@ -24,8 +24,19 @@ if (POLICY CMP0054) + endif() + set_property(GLOBAL PROPERTY USE_FOLDERS ON) + ++# Filament specific changes ++if (APPLE) ++ set(CMAKE_MACOSX_RPATH ON) ++endif (APPLE) ++set(SPIRV_SKIP_EXECUTABLES_OPTION ON) ++set(SPIRV_SKIP_TESTS_OPTION ON) ++set(SKIP_SPIRV_TOOLS_INSTALL ON) ++# End Filament specific changes ++ + project(spirv-tools) +-enable_testing() ++# Filament specific changes ++# enable_testing() ++# End Filament specific changes + set(SPIRV_TOOLS "SPIRV-Tools") + + include(GNUInstallDirs) +@@ -68,7 +79,9 @@ if ("${CMAKE_BUILD_TYPE}" STREQUAL "") + set(CMAKE_BUILD_TYPE "Debug") + endif() + +-option(SKIP_SPIRV_TOOLS_INSTALL "Skip installation" ${SKIP_SPIRV_TOOLS_INSTALL}) ++# Filament specific changes ++# option(SKIP_SPIRV_TOOLS_INSTALL "Skip installation" ${SKIP_SPIRV_TOOLS_INSTALL}) ++# End Filament specific changes + if(NOT ${SKIP_SPIRV_TOOLS_INSTALL}) + set(ENABLE_SPIRV_TOOLS_INSTALL ON) + endif() +@@ -231,11 +244,13 @@ if(ENABLE_SPIRV_TOOLS_INSTALL) + endif() + + # Defaults to OFF if the user didn't set it. ++# Filament specific changes + option(SPIRV_SKIP_EXECUTABLES + "Skip building the executable and tests along with the library" +- ${SPIRV_SKIP_EXECUTABLES}) ++ ${SPIRV_SKIP_EXECUTABLES_OPTION}) + option(SPIRV_SKIP_TESTS +- "Skip building tests along with the library" ${SPIRV_SKIP_TESTS}) ++ "Skip building tests along with the library" ${SPIRV_SKIP_TESTS_OPTION}) ++# End Filament specific changes + if ("${SPIRV_SKIP_EXECUTABLES}") + set(SPIRV_SKIP_TESTS ON) + endif() +@@ -279,8 +294,10 @@ endif() + add_subdirectory(source) + add_subdirectory(tools) + +-add_subdirectory(test) +-add_subdirectory(examples) ++# Filament specific changes ++#add_subdirectory(test) ++#add_subdirectory(examples) ++# End Filament specific changes + + if(ENABLE_SPIRV_TOOLS_INSTALL) + install( +@@ -305,28 +322,30 @@ set(SPIRV_SHARED_LIBRARIES "-lSPIRV-Tools-shared") + + # Build pkg-config file + # Use a first-class target so it's regenerated when relevant files are updated. +-add_custom_target(spirv-tools-pkg-config ALL +- COMMAND ${CMAKE_COMMAND} +- -DCHANGES_FILE=${CMAKE_CURRENT_SOURCE_DIR}/CHANGES +- -DTEMPLATE_FILE=${CMAKE_CURRENT_SOURCE_DIR}/cmake/SPIRV-Tools.pc.in +- -DOUT_FILE=${CMAKE_CURRENT_BINARY_DIR}/SPIRV-Tools.pc +- -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX} +- -DCMAKE_INSTALL_LIBDIR=${CMAKE_INSTALL_LIBDIR} +- -DCMAKE_INSTALL_INCLUDEDIR=${CMAKE_INSTALL_INCLUDEDIR} +- -DSPIRV_LIBRARIES=${SPIRV_LIBRARIES} +- -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/write_pkg_config.cmake +- DEPENDS "CHANGES" "cmake/SPIRV-Tools.pc.in" "cmake/write_pkg_config.cmake") +-add_custom_target(spirv-tools-shared-pkg-config ALL +- COMMAND ${CMAKE_COMMAND} +- -DCHANGES_FILE=${CMAKE_CURRENT_SOURCE_DIR}/CHANGES +- -DTEMPLATE_FILE=${CMAKE_CURRENT_SOURCE_DIR}/cmake/SPIRV-Tools-shared.pc.in +- -DOUT_FILE=${CMAKE_CURRENT_BINARY_DIR}/SPIRV-Tools-shared.pc +- -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX} +- -DCMAKE_INSTALL_LIBDIR=${CMAKE_INSTALL_LIBDIR} +- -DCMAKE_INSTALL_INCLUDEDIR=${CMAKE_INSTALL_INCLUDEDIR} +- -DSPIRV_SHARED_LIBRARIES=${SPIRV_SHARED_LIBRARIES} +- -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/write_pkg_config.cmake +- DEPENDS "CHANGES" "cmake/SPIRV-Tools-shared.pc.in" "cmake/write_pkg_config.cmake") ++# Filament specific changes ++# add_custom_target(spirv-tools-pkg-config ALL ++# COMMAND ${CMAKE_COMMAND} ++# -DCHANGES_FILE=${CMAKE_CURRENT_SOURCE_DIR}/CHANGES ++# -DTEMPLATE_FILE=${CMAKE_CURRENT_SOURCE_DIR}/cmake/SPIRV-Tools.pc.in ++# -DOUT_FILE=${CMAKE_CURRENT_BINARY_DIR}/SPIRV-Tools.pc ++# -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX} ++# -DCMAKE_INSTALL_LIBDIR=${CMAKE_INSTALL_LIBDIR} ++# -DCMAKE_INSTALL_INCLUDEDIR=${CMAKE_INSTALL_INCLUDEDIR} ++# -DSPIRV_LIBRARIES=${SPIRV_LIBRARIES} ++# -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/write_pkg_config.cmake ++# DEPENDS "CHANGES" "cmake/SPIRV-Tools.pc.in" "cmake/write_pkg_config.cmake") ++# add_custom_target(spirv-tools-shared-pkg-config ALL ++# COMMAND ${CMAKE_COMMAND} ++# -DCHANGES_FILE=${CMAKE_CURRENT_SOURCE_DIR}/CHANGES ++# -DTEMPLATE_FILE=${CMAKE_CURRENT_SOURCE_DIR}/cmake/SPIRV-Tools-shared.pc.in ++# -DOUT_FILE=${CMAKE_CURRENT_BINARY_DIR}/SPIRV-Tools-shared.pc ++# -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX} ++# -DCMAKE_INSTALL_LIBDIR=${CMAKE_INSTALL_LIBDIR} ++# -DCMAKE_INSTALL_INCLUDEDIR=${CMAKE_INSTALL_INCLUDEDIR} ++# -DSPIRV_SHARED_LIBRARIES=${SPIRV_SHARED_LIBRARIES} ++# -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/write_pkg_config.cmake ++# DEPENDS "CHANGES" "cmake/SPIRV-Tools-shared.pc.in" "cmake/write_pkg_config.cmake") ++# End Filament specific changes + + # Install pkg-config file + if (ENABLE_SPIRV_TOOLS_INSTALL) diff --git a/third_party/spirv-tools/include/spirv-tools/instrument.hpp b/third_party/spirv-tools/include/spirv-tools/instrument.hpp new file mode 100644 index 0000000000..2dcb333160 --- /dev/null +++ b/third_party/spirv-tools/include/spirv-tools/instrument.hpp @@ -0,0 +1,259 @@ +// Copyright (c) 2018 The Khronos Group Inc. +// Copyright (c) 2018 Valve Corporation +// Copyright (c) 2018 LunarG Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef INCLUDE_SPIRV_TOOLS_INSTRUMENT_HPP_ +#define INCLUDE_SPIRV_TOOLS_INSTRUMENT_HPP_ + +// Shader Instrumentation Interface +// +// This file provides an external interface for applications that wish to +// communicate with shaders instrumented by passes created by: +// +// CreateInstBindlessCheckPass +// CreateInstBuffAddrCheckPass +// +// More detailed documentation of these routines can be found in optimizer.hpp + +namespace spvtools { + +// Stream Output Buffer Offsets +// +// The following values provide offsets into the output buffer struct +// generated by InstrumentPass::GenDebugStreamWrite. This method is utilized +// by InstBindlessCheckPass. +// +// kInst2* values support version 2 of the output record format and were used +// for the transition to this format. These values have now been transferred +// to the original kInst* values. The kInst2* values are therefore DEPRECATED. +// +// The first member of the debug output buffer contains the next available word +// in the data stream to be written. Shaders will atomically read and update +// this value so as not to overwrite each others records. This value must be +// initialized to zero +static const int kDebugOutputSizeOffset = 0; + +// The second member of the output buffer is the start of the stream of records +// written by the instrumented shaders. Each record represents a validation +// error. The format of the records is documented below. +static const int kDebugOutputDataOffset = 1; + +// Common Stream Record Offsets +// +// The following are offsets to fields which are common to all records written +// to the output stream. +// +// Each record first contains the size of the record in 32-bit words, including +// the size word. +static const int kInstCommonOutSize = 0; + +// This is the shader id passed by the layer when the instrumentation pass is +// created. +static const int kInstCommonOutShaderId = 1; + +// This is the ordinal position of the instruction within the SPIR-V shader +// which generated the validation error. +static const int kInstCommonOutInstructionIdx = 2; + +// This is the stage which generated the validation error. This word is used +// to determine the contents of the next two words in the record. +// 0:Vert, 1:TessCtrl, 2:TessEval, 3:Geom, 4:Frag, 5:Compute +static const int kInstCommonOutStageIdx = 3; +static const int kInstCommonOutCnt = 4; + +// Stage-specific Stream Record Offsets +// +// Each stage will contain different values in the next set of words of the +// record used to identify which instantiation of the shader generated the +// validation error. +// +// Vertex Shader Output Record Offsets +static const int kInstVertOutVertexIndex = kInstCommonOutCnt; +static const int kInstVertOutInstanceIndex = kInstCommonOutCnt + 1; +static const int kInstVertOutUnused = kInstCommonOutCnt + 2; + +// Frag Shader Output Record Offsets +static const int kInstFragOutFragCoordX = kInstCommonOutCnt; +static const int kInstFragOutFragCoordY = kInstCommonOutCnt + 1; +static const int kInstFragOutUnused = kInstCommonOutCnt + 2; + +// Compute Shader Output Record Offsets +static const int kInstCompOutGlobalInvocationIdX = kInstCommonOutCnt; +static const int kInstCompOutGlobalInvocationIdY = kInstCommonOutCnt + 1; +static const int kInstCompOutGlobalInvocationIdZ = kInstCommonOutCnt + 2; + +// Compute Shader Output Record Offsets - Version 1 (DEPRECATED) +static const int kInstCompOutGlobalInvocationId = kInstCommonOutCnt; +static const int kInstCompOutUnused = kInstCommonOutCnt + 1; + +// Tessellation Control Shader Output Record Offsets +static const int kInstTessCtlOutInvocationId = kInstCommonOutCnt; +static const int kInstTessCtlOutPrimitiveId = kInstCommonOutCnt + 1; +static const int kInstTessCtlOutUnused = kInstCommonOutCnt + 2; + +// Tessellation Eval Shader Output Record Offsets +static const int kInstTessEvalOutPrimitiveId = kInstCommonOutCnt; +static const int kInstTessEvalOutTessCoordU = kInstCommonOutCnt + 1; +static const int kInstTessEvalOutTessCoordV = kInstCommonOutCnt + 2; + +// Tessellation Shader Output Record Offsets - Version 1 (DEPRECATED) +static const int kInstTessOutInvocationId = kInstCommonOutCnt; +static const int kInstTessOutUnused = kInstCommonOutCnt + 1; + +// Geometry Shader Output Record Offsets +static const int kInstGeomOutPrimitiveId = kInstCommonOutCnt; +static const int kInstGeomOutInvocationId = kInstCommonOutCnt + 1; +static const int kInstGeomOutUnused = kInstCommonOutCnt + 2; + +// Ray Tracing Shader Output Record Offsets +static const int kInstRayTracingOutLaunchIdX = kInstCommonOutCnt; +static const int kInstRayTracingOutLaunchIdY = kInstCommonOutCnt + 1; +static const int kInstRayTracingOutLaunchIdZ = kInstCommonOutCnt + 2; + +// Size of Common and Stage-specific Members +static const int kInstStageOutCnt = kInstCommonOutCnt + 3; +static const int kInst2StageOutCnt = kInstCommonOutCnt + 3; + +// Validation Error Code Offset +// +// This identifies the validation error. It also helps to identify +// how many words follow in the record and their meaning. +static const int kInstValidationOutError = kInstStageOutCnt; +static const int kInst2ValidationOutError = kInst2StageOutCnt; + +// Validation-specific Output Record Offsets +// +// Each different validation will generate a potentially different +// number of words at the end of the record giving more specifics +// about the validation error. +// +// A bindless bounds error will output the index and the bound. +static const int kInstBindlessBoundsOutDescIndex = kInstStageOutCnt + 1; +static const int kInstBindlessBoundsOutDescBound = kInstStageOutCnt + 2; +static const int kInstBindlessBoundsOutCnt = kInstStageOutCnt + 3; + +static const int kInst2BindlessBoundsOutDescIndex = kInst2StageOutCnt + 1; +static const int kInst2BindlessBoundsOutDescBound = kInst2StageOutCnt + 2; +static const int kInst2BindlessBoundsOutCnt = kInst2StageOutCnt + 3; + +// A bindless uninitialized error will output the index. +static const int kInstBindlessUninitOutDescIndex = kInstStageOutCnt + 1; +static const int kInstBindlessUninitOutUnused = kInstStageOutCnt + 2; +static const int kInstBindlessUninitOutCnt = kInstStageOutCnt + 3; + +static const int kInst2BindlessUninitOutDescIndex = kInst2StageOutCnt + 1; +static const int kInst2BindlessUninitOutUnused = kInst2StageOutCnt + 2; +static const int kInst2BindlessUninitOutCnt = kInst2StageOutCnt + 3; + +// A buffer address unalloc error will output the 64-bit pointer in +// two 32-bit pieces, lower bits first. +static const int kInstBuffAddrUnallocOutDescPtrLo = kInstStageOutCnt + 1; +static const int kInstBuffAddrUnallocOutDescPtrHi = kInstStageOutCnt + 2; +static const int kInstBuffAddrUnallocOutCnt = kInstStageOutCnt + 3; + +static const int kInst2BuffAddrUnallocOutDescPtrLo = kInst2StageOutCnt + 1; +static const int kInst2BuffAddrUnallocOutDescPtrHi = kInst2StageOutCnt + 2; +static const int kInst2BuffAddrUnallocOutCnt = kInst2StageOutCnt + 3; + +// DEPRECATED +static const int kInstBindlessOutDescIndex = kInstStageOutCnt + 1; +static const int kInstBindlessOutDescBound = kInstStageOutCnt + 2; +static const int kInstBindlessOutCnt = kInstStageOutCnt + 3; + +// Maximum Output Record Member Count +static const int kInstMaxOutCnt = kInstStageOutCnt + 3; +static const int kInst2MaxOutCnt = kInst2StageOutCnt + 3; + +// Validation Error Codes +// +// These are the possible validation error codes. +static const int kInstErrorBindlessBounds = 0; +static const int kInstErrorBindlessUninit = 1; +static const int kInstErrorBuffAddrUnallocRef = 2; + +// Direct Input Buffer Offsets +// +// The following values provide member offsets into the input buffers +// consumed by InstrumentPass::GenDebugDirectRead(). This method is utilized +// by InstBindlessCheckPass. +// +// The only object in an input buffer is a runtime array of unsigned +// integers. Each validation will have its own formatting of this array. +static const int kDebugInputDataOffset = 0; + +// Debug Buffer Bindings +// +// These are the bindings for the different buffers which are +// read or written by the instrumentation passes. +// +// This is the output buffer written by InstBindlessCheckPass, +// InstBuffAddrCheckPass, and possibly other future validations. +static const int kDebugOutputBindingStream = 0; + +// The binding for the input buffer read by InstBindlessCheckPass. +static const int kDebugInputBindingBindless = 1; + +// The binding for the input buffer read by InstBuffAddrCheckPass. +static const int kDebugInputBindingBuffAddr = 2; + +// Bindless Validation Input Buffer Format +// +// An input buffer for bindless validation consists of a single array of +// unsigned integers we will call Data[]. This array is formatted as follows. +// +// At offset kDebugInputBindlessInitOffset in Data[] is a single uint which +// gives an offset to the start of the bindless initialization data. More +// specifically, if the following value is zero, we know that the descriptor at +// (set = s, binding = b, index = i) is not initialized: +// Data[ i + Data[ b + Data[ s + Data[ kDebugInputBindlessInitOffset ] ] ] ] +static const int kDebugInputBindlessInitOffset = 0; + +// DEPRECATED +static const int kDebugInputBindlessOffsetReserved = 0; + +// At offset kDebugInputBindlessOffsetLengths is some number of uints which +// provide the bindless length data. More specifically, the number of +// descriptors at (set=s, binding=b) is: +// Data[ Data[ s + kDebugInputBindlessOffsetLengths ] + b ] +static const int kDebugInputBindlessOffsetLengths = 1; + +// Buffer Device Address Input Buffer Format +// +// An input buffer for buffer device address validation consists of a single +// array of unsigned 64-bit integers we will call Data[]. This array is +// formatted as follows: +// +// At offset kDebugInputBuffAddrPtrOffset is a list of sorted valid buffer +// addresses. The list is terminated with the address 0xffffffffffffffff. +// If 0x0 is not a valid buffer address, this address is inserted at the +// start of the list. +// +static const int kDebugInputBuffAddrPtrOffset = 1; +// +// At offset kDebugInputBuffAddrLengthOffset in Data[] is a single uint64 which +// gives an offset to the start of the buffer length data. More +// specifically, for a buffer whose pointer is located at input buffer offset +// i, the length is located at: +// +// Data[ i - kDebugInputBuffAddrPtrOffset +// + Data[ kDebugInputBuffAddrLengthOffset ] ] +// +// The length associated with the 0xffffffffffffffff address is zero. If +// not a valid buffer, the length associated with the 0x0 address is zero. +static const int kDebugInputBuffAddrLengthOffset = 0; + +} // namespace spvtools + +#endif // INCLUDE_SPIRV_TOOLS_INSTRUMENT_HPP_ diff --git a/third_party/spirv-tools/include/spirv-tools/libspirv.h b/third_party/spirv-tools/include/spirv-tools/libspirv.h index a7e1b30079..d63f3634d0 100644 --- a/third_party/spirv-tools/include/spirv-tools/libspirv.h +++ b/third_party/spirv-tools/include/spirv-tools/libspirv.h @@ -225,13 +225,23 @@ typedef enum spv_operand_type_t { // A sequence of zero or more pairs of (Id, Literal integer) LAST_VARIABLE(SPV_OPERAND_TYPE_VARIABLE_ID_LITERAL_INTEGER), - // The following are concrete enum types. + // The following are concrete enum types from the DebugInfo extended + // instruction set. SPV_OPERAND_TYPE_DEBUG_INFO_FLAGS, // DebugInfo Sec 3.2. A mask. SPV_OPERAND_TYPE_DEBUG_BASE_TYPE_ATTRIBUTE_ENCODING, // DebugInfo Sec 3.3 SPV_OPERAND_TYPE_DEBUG_COMPOSITE_TYPE, // DebugInfo Sec 3.4 SPV_OPERAND_TYPE_DEBUG_TYPE_QUALIFIER, // DebugInfo Sec 3.5 SPV_OPERAND_TYPE_DEBUG_OPERATION, // DebugInfo Sec 3.6 + // The following are concrete enum types from the OpenCL.DebugInfo.100 + // extended instruction set. + SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_INFO_FLAGS, // Sec 3.2. A Mask + SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_BASE_TYPE_ATTRIBUTE_ENCODING, // Sec 3.3 + SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_COMPOSITE_TYPE, // Sec 3.4 + SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_TYPE_QUALIFIER, // Sec 3.5 + SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_OPERATION, // Sec 3.6 + SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_IMPORTED_ENTITY, // Sec 3.7 + // This is a sentinel value, and does not represent an operand type. // It should come last. SPV_OPERAND_TYPE_NUM_OPERAND_TYPES, @@ -248,6 +258,12 @@ typedef enum spv_ext_inst_type_t { SPV_EXT_INST_TYPE_SPV_AMD_GCN_SHADER, SPV_EXT_INST_TYPE_SPV_AMD_SHADER_BALLOT, SPV_EXT_INST_TYPE_DEBUGINFO, + SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100, + + // Multiple distinct extended instruction set types could return this + // value, if they are prefixed with NonSemantic. and are otherwise + // unrecognised + SPV_EXT_INST_TYPE_NONSEMANTIC_UNKNOWN, SPV_FORCE_32_BIT_ENUM(spv_ext_inst_type_t) } spv_ext_inst_type_t; @@ -288,6 +304,12 @@ typedef enum spv_binary_to_text_options_t { SPV_FORCE_32_BIT_ENUM(spv_binary_to_text_options_t) } spv_binary_to_text_options_t; +// Constants + +// The default id bound is to the minimum value for the id limit +// in the spir-v specification under the section "Universal Limits". +const uint32_t kDefaultMaxIdBound = 0x3FFFFF; + // Structures // Information about an operand parsed from a binary SPIR-V module. @@ -360,6 +382,12 @@ typedef struct spv_context_t spv_context_t; typedef struct spv_validator_options_t spv_validator_options_t; +typedef struct spv_optimizer_options_t spv_optimizer_options_t; + +typedef struct spv_reducer_options_t spv_reducer_options_t; + +typedef struct spv_fuzzer_options_t spv_fuzzer_options_t; + // Type Definitions typedef spv_const_binary_t* spv_const_binary; @@ -371,6 +399,12 @@ typedef const spv_context_t* spv_const_context; typedef spv_context_t* spv_context; typedef spv_validator_options_t* spv_validator_options; typedef const spv_validator_options_t* spv_const_validator_options; +typedef spv_optimizer_options_t* spv_optimizer_options; +typedef const spv_optimizer_options_t* spv_const_optimizer_options; +typedef spv_reducer_options_t* spv_reducer_options; +typedef const spv_reducer_options_t* spv_const_reducer_options; +typedef spv_fuzzer_options_t* spv_fuzzer_options; +typedef const spv_fuzzer_options_t* spv_const_fuzzer_options; // Platform API @@ -385,8 +419,17 @@ SPIRV_TOOLS_EXPORT const char* spvSoftwareVersionString(void); SPIRV_TOOLS_EXPORT const char* spvSoftwareVersionDetailsString(void); // Certain target environments impose additional restrictions on SPIR-V, so it's -// often necessary to specify which one applies. SPV_ENV_UNIVERSAL means +// often necessary to specify which one applies. SPV_ENV_UNIVERSAL_* implies an // environment-agnostic SPIR-V. +// +// When an API method needs to derive a SPIR-V version from a target environment +// (from the spv_context object), the method will choose the highest version of +// SPIR-V supported by the target environment. Examples: +// SPV_ENV_VULKAN_1_0 -> SPIR-V 1.0 +// SPV_ENV_VULKAN_1_1 -> SPIR-V 1.3 +// SPV_ENV_VULKAN_1_1_SPIRV_1_4 -> SPIR-V 1.4 +// SPV_ENV_VULKAN_1_2 -> SPIR-V 1.5 +// Consult the description of API entry points for specific rules. typedef enum { SPV_ENV_UNIVERSAL_1_0, // SPIR-V 1.0 latest revision, no other restrictions. SPV_ENV_VULKAN_1_0, // Vulkan 1.0 latest revision. @@ -413,6 +456,13 @@ typedef enum { SPV_ENV_UNIVERSAL_1_3, // SPIR-V 1.3 latest revision, no other restrictions. SPV_ENV_VULKAN_1_1, // Vulkan 1.1 latest revision. SPV_ENV_WEBGPU_0, // Work in progress WebGPU 1.0. + SPV_ENV_UNIVERSAL_1_4, // SPIR-V 1.4 latest revision, no other restrictions. + + // Vulkan 1.1 with VK_KHR_spirv_1_4, i.e. SPIR-V 1.4 binary. + SPV_ENV_VULKAN_1_1_SPIRV_1_4, + + SPV_ENV_UNIVERSAL_1_5, // SPIR-V 1.5 latest revision, no other restrictions. + SPV_ENV_VULKAN_1_2, // Vulkan 1.2 latest revision. } spv_target_env; // SPIR-V Validator can be parameterized with the following Universal Limits. @@ -425,12 +475,34 @@ typedef enum { spv_validator_limit_max_function_args, spv_validator_limit_max_control_flow_nesting_depth, spv_validator_limit_max_access_chain_indexes, + spv_validator_limit_max_id_bound, } spv_validator_limit; // Returns a string describing the given SPIR-V target environment. SPIRV_TOOLS_EXPORT const char* spvTargetEnvDescription(spv_target_env env); -// Creates a context object. Returns null if env is invalid. +// Parses s into *env and returns true if successful. If unparsable, returns +// false and sets *env to SPV_ENV_UNIVERSAL_1_0. +SPIRV_TOOLS_EXPORT bool spvParseTargetEnv(const char* s, spv_target_env* env); + +// Determines the target env value with the least features but which enables +// the given Vulkan and SPIR-V versions. If such a target is supported, returns +// true and writes the value to |env|, otherwise returns false. +// +// The Vulkan version is given as an unsigned 32-bit number as specified in +// Vulkan section "29.2.1 Version Numbers": the major version number appears +// in bits 22 to 21, and the minor version is in bits 12 to 21. The SPIR-V +// version is given in the SPIR-V version header word: major version in bits +// 16 to 23, and minor version in bits 8 to 15. +SPIRV_TOOLS_EXPORT bool spvParseVulkanEnv(uint32_t vulkan_ver, + uint32_t spirv_ver, + spv_target_env* env); + +// Creates a context object for most of the SPIRV-Tools API. +// Returns null if env is invalid. +// +// See specific API calls for how the target environment is interpeted +// (particularly assembly and validation). SPIRV_TOOLS_EXPORT spv_context spvContextCreate(spv_target_env env); // Destroys the given context object. @@ -473,23 +545,146 @@ SPIRV_TOOLS_EXPORT void spvValidatorOptionsSetRelaxStoreStruct( SPIRV_TOOLS_EXPORT void spvValidatorOptionsSetRelaxLogicalPointer( spv_validator_options options, bool val); -// Records whether or not the validator should relax the rules on block layout. +// Records whether or not the validator should relax the rules because it is +// expected that the optimizations will make the code legal. // -// When relaxed, it will enable VK_KHR_relaxed_block_layout when validating -// standard uniform/storage block layout. +// When relaxed, it will allow the following: +// 1) It will allow relaxed logical pointers. Setting this option will also +// set that option. +// 2) Pointers that are pass as parameters to function calls do not have to +// match the storage class of the formal parameter. +// 3) Pointers that are actaul parameters on function calls do not have to point +// to the same type pointed as the formal parameter. The types just need to +// logically match. +SPIRV_TOOLS_EXPORT void spvValidatorOptionsSetBeforeHlslLegalization( + spv_validator_options options, bool val); + +// Records whether the validator should use "relaxed" block layout rules. +// Relaxed layout rules are described by Vulkan extension +// VK_KHR_relaxed_block_layout, and they affect uniform blocks, storage blocks, +// and push constants. +// +// This is enabled by default when targeting Vulkan 1.1 or later. +// Relaxed layout is more permissive than the default rules in Vulkan 1.0. SPIRV_TOOLS_EXPORT void spvValidatorOptionsSetRelaxBlockLayout( spv_validator_options options, bool val); +// Records whether the validator should use standard block layout rules for +// uniform blocks. +SPIRV_TOOLS_EXPORT void spvValidatorOptionsSetUniformBufferStandardLayout( + spv_validator_options options, bool val); + +// Records whether the validator should use "scalar" block layout rules. +// Scalar layout rules are more permissive than relaxed block layout. +// +// See Vulkan extnesion VK_EXT_scalar_block_layout. The scalar alignment is +// defined as follows: +// - scalar alignment of a scalar is the scalar size +// - scalar alignment of a vector is the scalar alignment of its component +// - scalar alignment of a matrix is the scalar alignment of its component +// - scalar alignment of an array is the scalar alignment of its element +// - scalar alignment of a struct is the max scalar alignment among its +// members +// +// For a struct in Uniform, StorageClass, or PushConstant: +// - a member Offset must be a multiple of the member's scalar alignment +// - ArrayStride or MatrixStride must be a multiple of the array or matrix +// scalar alignment +SPIRV_TOOLS_EXPORT void spvValidatorOptionsSetScalarBlockLayout( + spv_validator_options options, bool val); + // Records whether or not the validator should skip validating standard // uniform/storage block layout. SPIRV_TOOLS_EXPORT void spvValidatorOptionsSetSkipBlockLayout( spv_validator_options options, bool val); +// Creates an optimizer options object with default options. Returns a valid +// options object. The object remains valid until it is passed into +// |spvOptimizerOptionsDestroy|. +SPIRV_TOOLS_EXPORT spv_optimizer_options spvOptimizerOptionsCreate(void); + +// Destroys the given optimizer options object. +SPIRV_TOOLS_EXPORT void spvOptimizerOptionsDestroy( + spv_optimizer_options options); + +// Records whether or not the optimizer should run the validator before +// optimizing. If |val| is true, the validator will be run. +SPIRV_TOOLS_EXPORT void spvOptimizerOptionsSetRunValidator( + spv_optimizer_options options, bool val); + +// Records the validator options that should be passed to the validator if it is +// run. +SPIRV_TOOLS_EXPORT void spvOptimizerOptionsSetValidatorOptions( + spv_optimizer_options options, spv_validator_options val); + +// Records the maximum possible value for the id bound. +SPIRV_TOOLS_EXPORT void spvOptimizerOptionsSetMaxIdBound( + spv_optimizer_options options, uint32_t val); + +// Records whether all bindings within the module should be preserved. +SPIRV_TOOLS_EXPORT void spvOptimizerOptionsSetPreserveBindings( + spv_optimizer_options options, bool val); + +// Records whether all specialization constants within the module +// should be preserved. +SPIRV_TOOLS_EXPORT void spvOptimizerOptionsSetPreserveSpecConstants( + spv_optimizer_options options, bool val); + +// Creates a reducer options object with default options. Returns a valid +// options object. The object remains valid until it is passed into +// |spvReducerOptionsDestroy|. +SPIRV_TOOLS_EXPORT spv_reducer_options spvReducerOptionsCreate(); + +// Destroys the given reducer options object. +SPIRV_TOOLS_EXPORT void spvReducerOptionsDestroy(spv_reducer_options options); + +// Sets the maximum number of reduction steps that should run before the reducer +// gives up. +SPIRV_TOOLS_EXPORT void spvReducerOptionsSetStepLimit( + spv_reducer_options options, uint32_t step_limit); + +// Sets the fail-on-validation-error option; if true, the reducer will return +// kStateInvalid if a reduction step yields a state that fails SPIR-V +// validation. Otherwise, an invalid state is treated as uninteresting and the +// reduction backtracks and continues. +SPIRV_TOOLS_EXPORT void spvReducerOptionsSetFailOnValidationError( + spv_reducer_options options, bool fail_on_validation_error); + +// Creates a fuzzer options object with default options. Returns a valid +// options object. The object remains valid until it is passed into +// |spvFuzzerOptionsDestroy|. +SPIRV_TOOLS_EXPORT spv_fuzzer_options spvFuzzerOptionsCreate(); + +// Destroys the given fuzzer options object. +SPIRV_TOOLS_EXPORT void spvFuzzerOptionsDestroy(spv_fuzzer_options options); + +// Enables running the validator after every transformation is applied during +// a replay. +SPIRV_TOOLS_EXPORT void spvFuzzerOptionsEnableReplayValidation( + spv_fuzzer_options options); + +// Sets the seed with which the random number generator used by the fuzzer +// should be initialized. +SPIRV_TOOLS_EXPORT void spvFuzzerOptionsSetRandomSeed( + spv_fuzzer_options options, uint32_t seed); + +// Sets the maximum number of steps that the shrinker should take before giving +// up. +SPIRV_TOOLS_EXPORT void spvFuzzerOptionsSetShrinkerStepLimit( + spv_fuzzer_options options, uint32_t shrinker_step_limit); + +// Enables running the validator after every pass is applied during a fuzzing +// run. +SPIRV_TOOLS_EXPORT void spvFuzzerOptionsEnableFuzzerPassValidation( + spv_fuzzer_options options); + // Encodes the given SPIR-V assembly text to its binary representation. The // length parameter specifies the number of bytes for text. Encoded binary will // be stored into *binary. Any error will be written into *diagnostic if -// diagnostic is non-null. The generated binary is independent of the context -// and may outlive it. +// diagnostic is non-null, otherwise the context's message consumer will be +// used. The generated binary is independent of the context and may outlive it. +// The SPIR-V binary version is set to the highest version of SPIR-V supported +// by the context's target environment. SPIRV_TOOLS_EXPORT spv_result_t spvTextToBinary(const spv_const_context context, const char* text, const size_t length, @@ -511,7 +706,8 @@ SPIRV_TOOLS_EXPORT void spvTextDestroy(spv_text text); // word_count parameter specifies the number of words for binary. The options // parameter is a bit field of spv_binary_to_text_options_t. Decoded text will // be stored into *text. Any error will be written into *diagnostic if -// diagnostic is non-null. +// diagnostic is non-null, otherwise the context's message consumer will be +// used. SPIRV_TOOLS_EXPORT spv_result_t spvBinaryToText(const spv_const_context context, const uint32_t* binary, const size_t word_count, @@ -524,20 +720,34 @@ SPIRV_TOOLS_EXPORT spv_result_t spvBinaryToText(const spv_const_context context, SPIRV_TOOLS_EXPORT void spvBinaryDestroy(spv_binary binary); // Validates a SPIR-V binary for correctness. Any errors will be written into -// *diagnostic if diagnostic is non-null. +// *diagnostic if diagnostic is non-null, otherwise the context's message +// consumer will be used. +// +// Validate for SPIR-V spec rules for the SPIR-V version named in the +// binary's header (at word offset 1). Additionally, if the context target +// environment is a client API (such as Vulkan 1.1), then validate for that +// client API version, to the extent that it is verifiable from data in the +// binary itself. SPIRV_TOOLS_EXPORT spv_result_t spvValidate(const spv_const_context context, const spv_const_binary binary, spv_diagnostic* diagnostic); // Validates a SPIR-V binary for correctness. Uses the provided Validator // options. Any errors will be written into *diagnostic if diagnostic is -// non-null. +// non-null, otherwise the context's message consumer will be used. +// +// Validate for SPIR-V spec rules for the SPIR-V version named in the +// binary's header (at word offset 1). Additionally, if the context target +// environment is a client API (such as Vulkan 1.1), then validate for that +// client API version, to the extent that it is verifiable from data in the +// binary itself, or in the validator options. SPIRV_TOOLS_EXPORT spv_result_t spvValidateWithOptions( const spv_const_context context, const spv_const_validator_options options, const spv_const_binary binary, spv_diagnostic* diagnostic); // Validates a raw SPIR-V binary for correctness. Any errors will be written -// into *diagnostic if diagnostic is non-null. +// into *diagnostic if diagnostic is non-null, otherwise the context's message +// consumer will be used. SPIRV_TOOLS_EXPORT spv_result_t spvValidateBinary(const spv_const_context context, const uint32_t* words, const size_t num_words, spv_diagnostic* diagnostic); @@ -584,7 +794,8 @@ typedef spv_result_t (*spv_parsed_instruction_fn_t)( // is supplied as context to the callbacks. Returns SPV_SUCCESS on successful // parse where the callbacks always return SPV_SUCCESS. For an invalid parse, // returns a status code other than SPV_SUCCESS, and if diagnostic is non-null -// also emits a diagnostic. If a callback returns anything other than +// also emits a diagnostic. If diagnostic is null the context's message consumer +// will be used to emit any errors. If a callback returns anything other than // SPV_SUCCESS, then that status code is returned, no further callbacks are // issued, and no additional diagnostics are emitted. SPIRV_TOOLS_EXPORT spv_result_t spvBinaryParse( diff --git a/third_party/spirv-tools/include/spirv-tools/libspirv.hpp b/third_party/spirv-tools/include/spirv-tools/libspirv.hpp index b6ae38c10b..5e1819ee6f 100644 --- a/third_party/spirv-tools/include/spirv-tools/libspirv.hpp +++ b/third_party/spirv-tools/include/spirv-tools/libspirv.hpp @@ -36,6 +36,9 @@ class Context { public: // Constructs a context targeting the given environment |env|. // + // See specific API calls for how the target environment is interpeted + // (particularly assembly and validation). + // // The constructed instance will have an empty message consumer, which just // ignores all messages from the library. Use SetMessageConsumer() to supply // one if messages are of concern. @@ -82,12 +85,26 @@ class ValidatorOptions { } // Enables VK_KHR_relaxed_block_layout when validating standard - // uniform/storage buffer layout. + // uniform/storage buffer/push-constant layout. If true, disables + // scalar block layout rules. void SetRelaxBlockLayout(bool val) { spvValidatorOptionsSetRelaxBlockLayout(options_, val); } - // Skips validating standard uniform/storage buffer layout. + // Enables VK_KHR_uniform_buffer_standard_layout when validating standard + // uniform layout. If true, disables scalar block layout rules. + void SetUniformBufferStandardLayout(bool val) { + spvValidatorOptionsSetUniformBufferStandardLayout(options_, val); + } + + // Enables VK_EXT_scalar_block_layout when validating standard + // uniform/storage buffer/push-constant layout. If true, disables + // relaxed block layout rules. + void SetScalarBlockLayout(bool val) { + spvValidatorOptionsSetScalarBlockLayout(options_, val); + } + + // Skips validating standard uniform/storage buffer/push-constant layout. void SetSkipBlockLayout(bool val) { spvValidatorOptionsSetSkipBlockLayout(options_, val); } @@ -102,10 +119,128 @@ class ValidatorOptions { spvValidatorOptionsSetRelaxLogicalPointer(options_, val); } + // Records whether or not the validator should relax the rules because it is + // expected that the optimizations will make the code legal. + // + // When relaxed, it will allow the following: + // 1) It will allow relaxed logical pointers. Setting this option will also + // set that option. + // 2) Pointers that are pass as parameters to function calls do not have to + // match the storage class of the formal parameter. + // 3) Pointers that are actaul parameters on function calls do not have to + // point to the same type pointed as the formal parameter. The types just + // need to logically match. + void SetBeforeHlslLegalization(bool val) { + spvValidatorOptionsSetBeforeHlslLegalization(options_, val); + } + private: spv_validator_options options_; }; +// A C++ wrapper around an optimization options object. +class OptimizerOptions { + public: + OptimizerOptions() : options_(spvOptimizerOptionsCreate()) {} + ~OptimizerOptions() { spvOptimizerOptionsDestroy(options_); } + + // Allow implicit conversion to the underlying object. + operator spv_optimizer_options() const { return options_; } + + // Records whether or not the optimizer should run the validator before + // optimizing. If |run| is true, the validator will be run. + void set_run_validator(bool run) { + spvOptimizerOptionsSetRunValidator(options_, run); + } + + // Records the validator options that should be passed to the validator if it + // is run. + void set_validator_options(const ValidatorOptions& val_options) { + spvOptimizerOptionsSetValidatorOptions(options_, val_options); + } + + // Records the maximum possible value for the id bound. + void set_max_id_bound(uint32_t new_bound) { + spvOptimizerOptionsSetMaxIdBound(options_, new_bound); + } + + // Records whether all bindings within the module should be preserved. + void set_preserve_bindings(bool preserve_bindings) { + spvOptimizerOptionsSetPreserveBindings(options_, preserve_bindings); + } + + // Records whether all specialization constants within the module + // should be preserved. + void set_preserve_spec_constants(bool preserve_spec_constants) { + spvOptimizerOptionsSetPreserveSpecConstants(options_, + preserve_spec_constants); + } + + private: + spv_optimizer_options options_; +}; + +// A C++ wrapper around a reducer options object. +class ReducerOptions { + public: + ReducerOptions() : options_(spvReducerOptionsCreate()) {} + ~ReducerOptions() { spvReducerOptionsDestroy(options_); } + + // Allow implicit conversion to the underlying object. + operator spv_reducer_options() const { // NOLINT(google-explicit-constructor) + return options_; + } + + // See spvReducerOptionsSetStepLimit. + void set_step_limit(uint32_t step_limit) { + spvReducerOptionsSetStepLimit(options_, step_limit); + } + + // See spvReducerOptionsSetFailOnValidationError. + void set_fail_on_validation_error(bool fail_on_validation_error) { + spvReducerOptionsSetFailOnValidationError(options_, + fail_on_validation_error); + } + + private: + spv_reducer_options options_; +}; + +// A C++ wrapper around a fuzzer options object. +class FuzzerOptions { + public: + FuzzerOptions() : options_(spvFuzzerOptionsCreate()) {} + ~FuzzerOptions() { spvFuzzerOptionsDestroy(options_); } + + // Allow implicit conversion to the underlying object. + operator spv_fuzzer_options() const { // NOLINT(google-explicit-constructor) + return options_; + } + + // See spvFuzzerOptionsEnableReplayValidation. + void enable_replay_validation() { + spvFuzzerOptionsEnableReplayValidation(options_); + } + + // See spvFuzzerOptionsSetRandomSeed. + void set_random_seed(uint32_t seed) { + spvFuzzerOptionsSetRandomSeed(options_, seed); + } + + // See spvFuzzerOptionsSetShrinkerStepLimit. + void set_shrinker_step_limit(uint32_t shrinker_step_limit) { + spvFuzzerOptionsSetShrinkerStepLimit(options_, shrinker_step_limit); + } + + // See spvFuzzerOptionsEnableFuzzerPassValidation. + void enable_fuzzer_pass_validation() { + spvFuzzerOptionsEnableFuzzerPassValidation(options_); + } + + private: + spv_fuzzer_options options_; +}; + // C++ interface for SPIRV-Tools functionalities. It wraps the context // (including target environment and the corresponding SPIR-V grammar) and // provides methods for assembling, disassembling, and validating. @@ -147,16 +282,20 @@ class SpirvTools { // Assembles the given assembly |text| and writes the result to |binary|. // Returns true on successful assembling. |binary| will be kept untouched if // assembling is unsuccessful. + // The SPIR-V binary version is set to the highest version of SPIR-V supported + // by the target environment with which this SpirvTools object was created. bool Assemble(const std::string& text, std::vector* binary, uint32_t options = kDefaultAssembleOption) const; // |text_size| specifies the number of bytes in |text|. A terminating null // character is not required to present in |text| as long as |text| is valid. + // The SPIR-V binary version is set to the highest version of SPIR-V supported + // by the target environment with which this SpirvTools object was created. bool Assemble(const char* text, size_t text_size, std::vector* binary, uint32_t options = kDefaultAssembleOption) const; // Disassembles the given SPIR-V |binary| with the given |options| and writes - // the assembly to |text|. Returns ture on successful disassembling. |text| + // the assembly to |text|. Returns true on successful disassembling. |text| // will be kept untouched if diassembling is unsuccessful. bool Disassemble(const std::vector& binary, std::string* text, uint32_t options = kDefaultDisassembleOption) const; @@ -168,12 +307,31 @@ class SpirvTools { // Validates the given SPIR-V |binary|. Returns true if no issues are found. // Otherwise, returns false and communicates issues via the message consumer // registered. + // Validates for SPIR-V spec rules for the SPIR-V version named in the + // binary's header (at word offset 1). Additionally, if the target + // environment is a client API (such as Vulkan 1.1), then validate for that + // client API version, to the extent that it is verifiable from data in the + // binary itself. bool Validate(const std::vector& binary) const; + // Like the previous overload, but provides the binary as a pointer and size: // |binary_size| specifies the number of words in |binary|. + // Validates for SPIR-V spec rules for the SPIR-V version named in the + // binary's header (at word offset 1). Additionally, if the target + // environment is a client API (such as Vulkan 1.1), then validate for that + // client API version, to the extent that it is verifiable from data in the + // binary itself. bool Validate(const uint32_t* binary, size_t binary_size) const; // Like the previous overload, but takes an options object. + // Validates for SPIR-V spec rules for the SPIR-V version named in the + // binary's header (at word offset 1). Additionally, if the target + // environment is a client API (such as Vulkan 1.1), then validate for that + // client API version, to the extent that it is verifiable from data in the + // binary itself, or in the validator options. bool Validate(const uint32_t* binary, size_t binary_size, - const ValidatorOptions& options) const; + spv_validator_options options) const; + + // Was this object successfully constructed. + bool IsValid() const; private: struct Impl; // Opaque struct for holding the data fields used by this class. diff --git a/third_party/spirv-tools/include/spirv-tools/optimizer.hpp b/third_party/spirv-tools/include/spirv-tools/optimizer.hpp index 4364d9ff50..c31ccef8c3 100644 --- a/third_party/spirv-tools/include/spirv-tools/optimizer.hpp +++ b/third_party/spirv-tools/include/spirv-tools/optimizer.hpp @@ -65,9 +65,14 @@ class Optimizer { // Constructs an instance with the given target |env|, which is used to decode // the binaries to be optimized later. // - // The constructed instance will have an empty message consumer, which just - // ignores all messages from the library. Use SetMessageConsumer() to supply - // one if messages are of concern. + // The instance will have an empty message consumer, which ignores all + // messages from the library. Use SetMessageConsumer() to supply a consumer + // if messages are of concern. + // + // For collections of passes that are meant to transform the input into + // another execution environment, then the source environment should be + // supplied. e.g. for VulkanToWebGPUPasses the environment should be + // SPV_ENV_VULKAN_1_1 not SPV_ENV_WEBGPU_0. explicit Optimizer(spv_target_env env); // Disables copy/move constructor/assignment operations. @@ -101,6 +106,16 @@ class Optimizer { // from time to time. Optimizer& RegisterSizePasses(); + // Registers passes that have been prescribed for converting from Vulkan to + // WebGPU. This sequence of passes is subject to constant review and will + // change from time to time. + Optimizer& RegisterVulkanToWebGPUPasses(); + + // Registers passes that have been prescribed for converting from WebGPU to + // Vulkan. This sequence of passes is subject to constant review and will + // change from time to time. + Optimizer& RegisterWebGPUToVulkanPasses(); + // Registers passes that attempt to legalize the generated code. // // Note: this recipe is specially designed for legalizing SPIR-V. It should be @@ -148,25 +163,53 @@ class Optimizer { // returns false. bool FlagHasValidForm(const std::string& flag) const; + // Allows changing, after creation time, the target environment to be + // optimized for and validated. Should be called before calling Run(). + void SetTargetEnv(const spv_target_env env); + // Optimizes the given SPIR-V module |original_binary| and writes the - // optimized binary into |optimized_binary|. + // optimized binary into |optimized_binary|. The optimized binary uses + // the same SPIR-V version as the original binary. + // // Returns true on successful optimization, whether or not the module is // modified. Returns false if |original_binary| fails to validate or if errors // occur when processing |original_binary| using any of the registered passes. // In that case, no further passes are executed and the contents in // |optimized_binary| may be invalid. // + // By default, the binary is validated before any transforms are performed, + // and optionally after each transform. Validation uses SPIR-V spec rules + // for the SPIR-V version named in the binary's header (at word offset 1). + // Additionally, if the target environment is a client API (such as + // Vulkan 1.1), then validate for that client API version, to the extent + // that it is verifiable from data in the binary itself. + // // It's allowed to alias |original_binary| to the start of |optimized_binary|. bool Run(const uint32_t* original_binary, size_t original_binary_size, std::vector* optimized_binary) const; - // Same as above, except passes |options| to the validator when trying to - // validate the binary. If |skip_validation| is true, then the caller is - // guaranteeing that |original_binary| is valid, and the validator will not - // be run. + // DEPRECATED: Same as above, except passes |options| to the validator when + // trying to validate the binary. If |skip_validation| is true, then the + // caller is guaranteeing that |original_binary| is valid, and the validator + // will not be run. The |max_id_bound| is the limit on the max id in the + // module. bool Run(const uint32_t* original_binary, const size_t original_binary_size, std::vector* optimized_binary, - const ValidatorOptions& options, bool skip_validation = false) const; + const ValidatorOptions& options, bool skip_validation) const; + + // Same as above, except it takes an options object. See the documentation + // for |OptimizerOptions| to see which options can be set. + // + // By default, the binary is validated before any transforms are performed, + // and optionally after each transform. Validation uses SPIR-V spec rules + // for the SPIR-V version named in the binary's header (at word offset 1). + // Additionally, if the target environment is a client API (such as + // Vulkan 1.1), then validate for that client API version, to the extent + // that it is verifiable from data in the binary itself, or from the + // validator options set on the optimizer options. + bool Run(const uint32_t* original_binary, const size_t original_binary_size, + std::vector* optimized_binary, + const spv_optimizer_options opt_options) const; // Returns a vector of strings with all the pass names added to this // optimizer's pass manager. These strings are valid until the associated @@ -183,6 +226,9 @@ class Optimizer { // |out| output stream. Optimizer& SetTimeReport(std::ostream* out); + // Sets the option to validate the module after each pass. + Optimizer& SetValidateAfterAll(bool validate); + private: struct Impl; // Opaque struct for holding internal data. std::unique_ptr impl_; // Unique pointer to internal data. @@ -192,6 +238,13 @@ class Optimizer { // A null pass does nothing to the SPIR-V module to be optimized. Optimizer::PassToken CreateNullPass(); +// Creates a strip-atomic-counter-memory pass. +// A strip-atomic-counter-memory pass removes all usages of the +// AtomicCounterMemory bit in Memory Semantics bitmasks. This bit is a no-op in +// Vulkan, so isn't needed in that env. And the related capability is not +// allowed in WebGPU, so it is not allowed in that env. +Optimizer::PassToken CreateStripAtomicCounterMemoryPass(); + // Creates a strip-debug-info pass. // A strip-debug-info pass removes all debug instructions (as documented in // Section 3.32.2 of the SPIR-V spec) of the SPIR-V module to be optimized. @@ -210,6 +263,11 @@ Optimizer::PassToken CreateStripReflectInfoPass(); // functions are not needed because they will never be called. Optimizer::PassToken CreateEliminateDeadFunctionsPass(); +// Creates an eliminate-dead-members pass. +// An eliminate-dead-members pass will remove all unused members of structures. +// This will not affect the data layout of the remaining members. +Optimizer::PassToken CreateEliminateDeadMembersPass(); + // Creates a set-spec-constant-default-value pass from a mapping from spec-ids // to the default values in the form of string. // A set-spec-constant-default-value pass sets the default values for the @@ -456,20 +514,6 @@ Optimizer::PassToken CreateInsertExtractElimPass(); // inserts created by that pass. Optimizer::PassToken CreateDeadInsertElimPass(); -// Creates a pass to consolidate uniform references. -// For each entry point function in the module, first change all constant index -// access chain loads into equivalent composite extracts. Then consolidate -// identical uniform loads into one uniform load. Finally, consolidate -// identical uniform extracts into one uniform extract. This may require -// moving a load or extract to a point which dominates all uses. -// -// This pass requires a module to have structured control flow ie shader -// capability. It also requires logical addressing ie Addresses capability -// is not enabled. It also currently does not support any extensions. -// -// This pass currently only optimizes loads with a single index. -Optimizer::PassToken CreateCommonUniformElimPass(); - // Create aggressive dead code elimination pass // This pass eliminates unused code from the module. In addition, // it detects and eliminates code which may have spurious uses but which do @@ -492,6 +536,30 @@ Optimizer::PassToken CreateCommonUniformElimPass(); // eliminated with standard dead code elimination. Optimizer::PassToken CreateAggressiveDCEPass(); +// Create line propagation pass +// This pass propagates line information based on the rules for OpLine and +// OpNoline and clones an appropriate line instruction into every instruction +// which does not already have debug line instructions. +// +// This pass is intended to maximize preservation of source line information +// through passes which delete, move and clone instructions. Ideally it should +// be run before any such pass. It is a bookend pass with EliminateDeadLines +// which can be used to remove redundant line instructions at the end of a +// run of such passes and reduce final output file size. +Optimizer::PassToken CreatePropagateLineInfoPass(); + +// Create dead line elimination pass +// This pass eliminates redundant line instructions based on the rules for +// OpLine and OpNoline. Its main purpose is to reduce the size of the file +// need to store the SPIR-V without losing line information. +// +// This is a bookend pass with PropagateLines which attaches line instructions +// to every instruction to preserve line information during passes which +// delete, move and clone instructions. DeadLineElim should be run after +// PropagateLines and all such subsequent passes. Normally it would be one +// of the last passes to be run. +Optimizer::PassToken CreateRedundantLineInfoElimPass(); + // Creates a compact ids pass. // The pass remaps result ids to a compact and gapless range starting from %1. Optimizer::PassToken CreateCompactIdsPass(); @@ -628,6 +696,22 @@ Optimizer::PassToken CreateLoopUnrollPass(bool fully_unroll, int factor = 0); // processed (see IsSSATargetVar for details). Optimizer::PassToken CreateSSARewritePass(); +// Create pass to convert relaxed precision instructions to half precision. +// This pass converts as many relaxed float32 arithmetic operations to half as +// possible. It converts any float32 operands to half if needed. It converts +// any resulting half precision values back to float32 as needed. No variables +// are changed. No image operations are changed. +// +// Best if run after function scope store/load and composite operation +// eliminations are run. Also best if followed by instruction simplification, +// redundancy elimination and DCE. +Optimizer::PassToken CreateConvertRelaxedToHalfPass(); + +// Create relax float ops pass. +// This pass decorates all float32 result instructions with RelaxedPrecision +// if not already so decorated. +Optimizer::PassToken CreateRelaxFloatOpsPass(); + // Create copy propagate arrays pass. // This pass looks to copy propagate memory references for arrays. It looks // for specific code patterns to recognize array copies. @@ -650,6 +734,148 @@ Optimizer::PassToken CreateReduceLoadSizePass(); // them into a single instruction where possible. Optimizer::PassToken CreateCombineAccessChainsPass(); +// Create a pass to instrument bindless descriptor checking +// This pass instruments all bindless references to check that descriptor +// array indices are inbounds, and if the descriptor indexing extension is +// enabled, that the descriptor has been initialized. If the reference is +// invalid, a record is written to the debug output buffer (if space allows) +// and a null value is returned. This pass is designed to support bindless +// validation in the Vulkan validation layers. +// +// TODO(greg-lunarg): Add support for buffer references. Currently only does +// checking for image references. +// +// Dead code elimination should be run after this pass as the original, +// potentially invalid code is not removed and could cause undefined behavior, +// including crashes. It may also be beneficial to run Simplification +// (ie Constant Propagation), DeadBranchElim and BlockMerge after this pass to +// optimize instrument code involving the testing of compile-time constants. +// It is also generally recommended that this pass (and all +// instrumentation passes) be run after any legalization and optimization +// passes. This will give better analysis for the instrumentation and avoid +// potentially de-optimizing the instrument code, for example, inlining +// the debug record output function throughout the module. +// +// The instrumentation will read and write buffers in debug +// descriptor set |desc_set|. It will write |shader_id| in each output record +// to identify the shader module which generated the record. +// |input_length_enable| controls instrumentation of runtime descriptor array +// references, and |input_init_enable| controls instrumentation of descriptor +// initialization checking, both of which require input buffer support. +// |version| specifies the buffer record format. +Optimizer::PassToken CreateInstBindlessCheckPass( + uint32_t desc_set, uint32_t shader_id, bool input_length_enable = false, + bool input_init_enable = false, uint32_t version = 2); + +// Create a pass to instrument physical buffer address checking +// This pass instruments all physical buffer address references to check that +// all referenced bytes fall in a valid buffer. If the reference is +// invalid, a record is written to the debug output buffer (if space allows) +// and a null value is returned. This pass is designed to support buffer +// address validation in the Vulkan validation layers. +// +// Dead code elimination should be run after this pass as the original, +// potentially invalid code is not removed and could cause undefined behavior, +// including crashes. Instruction simplification would likely also be +// beneficial. It is also generally recommended that this pass (and all +// instrumentation passes) be run after any legalization and optimization +// passes. This will give better analysis for the instrumentation and avoid +// potentially de-optimizing the instrument code, for example, inlining +// the debug record output function throughout the module. +// +// The instrumentation will read and write buffers in debug +// descriptor set |desc_set|. It will write |shader_id| in each output record +// to identify the shader module which generated the record. +// |version| specifies the output buffer record format. +Optimizer::PassToken CreateInstBuffAddrCheckPass(uint32_t desc_set, + uint32_t shader_id, + uint32_t version = 2); + +// Create a pass to upgrade to the VulkanKHR memory model. +// This pass upgrades the Logical GLSL450 memory model to Logical VulkanKHR. +// Additionally, it modifies memory, image, atomic and barrier operations to +// conform to that model's requirements. +Optimizer::PassToken CreateUpgradeMemoryModelPass(); + +// Create a pass to do code sinking. Code sinking is a transformation +// where an instruction is moved into a more deeply nested construct. +Optimizer::PassToken CreateCodeSinkingPass(); + +// Create a pass to adds initializers for OpVariable calls that require them +// in WebGPU. Currently this pass naively initializes variables that are +// missing an initializer with a null value. In the future it may initialize +// variables to the first value stored in them, if that is a constant. +Optimizer::PassToken CreateGenerateWebGPUInitializersPass(); + +// Create a pass to fix incorrect storage classes. In order to make code +// generation simpler, DXC may generate code where the storage classes do not +// match up correctly. This pass will fix the errors that it can. +Optimizer::PassToken CreateFixStorageClassPass(); + +// Create a pass to legalize OpVectorShuffle operands going into WebGPU. WebGPU +// forbids using 0xFFFFFFFF, which indicates an undefined result, so this pass +// converts those literals to 0. +Optimizer::PassToken CreateLegalizeVectorShufflePass(); + +// Create a pass to decompose initialized variables into a seperate variable +// declaration and an initial store. +Optimizer::PassToken CreateDecomposeInitializedVariablesPass(); + +// Create a pass to attempt to split up invalid unreachable merge-blocks and +// continue-targets to legalize for WebGPU. +Optimizer::PassToken CreateSplitInvalidUnreachablePass(); + +// Creates a graphics robust access pass. +// +// This pass injects code to clamp indexed accesses to buffers and internal +// arrays, providing guarantees satisfying Vulkan's robustBufferAccess rules. +// +// TODO(dneto): Clamps coordinates and sample index for pointer calculations +// into storage images (OpImageTexelPointer). For an cube array image, it +// assumes the maximum layer count times 6 is at most 0xffffffff. +// +// NOTE: This pass will fail with a message if: +// - The module is not a Shader module. +// - The module declares VariablePointers, VariablePointersStorageBuffer, or +// RuntimeDescriptorArrayEXT capabilities. +// - The module uses an addressing model other than Logical +// - Access chain indices are wider than 64 bits. +// - Access chain index for a struct is not an OpConstant integer or is out +// of range. (The module is already invalid if that is the case.) +// - TODO(dneto): The OpImageTexelPointer coordinate component is not 32-bits +// wide. +// +// NOTE: Access chain indices are always treated as signed integers. So +// if an array has a fixed size of more than 2^31 elements, then elements +// from 2^31 and above are never accessible with a 32-bit index, +// signed or unsigned. For this case, this pass will clamp the index +// between 0 and at 2^31-1, inclusive. +// Similarly, if an array has more then 2^15 element and is accessed with +// a 16-bit index, then elements from 2^15 and above are not accessible. +// In this case, the pass will clamp the index between 0 and 2^15-1 +// inclusive. +Optimizer::PassToken CreateGraphicsRobustAccessPass(); + +// Create descriptor scalar replacement pass. +// This pass replaces every array variable |desc| that has a DescriptorSet and +// Binding decorations with a new variable for each element of the array. +// Suppose |desc| was bound at binding |b|. Then the variable corresponding to +// |desc[i]| will have binding |b+i|. The descriptor set will be the same. It +// is assumed that no other variable already has a binding that will used by one +// of the new variables. If not, the pass will generate invalid Spir-V. All +// accesses to |desc| must be OpAccessChain instructions with a literal index +// for the first index. +Optimizer::PassToken CreateDescriptorScalarReplacementPass(); + +// Create a pass to replace all OpKill instruction with a function call to a +// function that has a single OpKill. This allows more code to be inlined. +Optimizer::PassToken CreateWrapOpKillPass(); + +// Replaces the extensions VK_AMD_shader_ballot,VK_AMD_gcn_shader, and +// VK_AMD_shader_trinary_minmax with equivalent code using core instructions and +// capabilities. +Optimizer::PassToken CreateAmdExtToKhrPass(); + } // namespace spvtools #endif // INCLUDE_SPIRV_TOOLS_OPTIMIZER_HPP_ diff --git a/third_party/spirv-tools/kokoro/android/build.sh b/third_party/spirv-tools/kokoro/android/build.sh index e31744fd15..c5a0a87593 100644 --- a/third_party/spirv-tools/kokoro/android/build.sh +++ b/third_party/spirv-tools/kokoro/android/build.sh @@ -44,7 +44,7 @@ mkdir build && cd $SRC/build # Invoke the build. BUILD_SHA=${KOKORO_GITHUB_COMMIT:-$KOKORO_GITHUB_PULL_REQUEST_COMMIT} echo $(date): Starting build... -cmake -DCMAKE_BUILD_TYPE=Release -DANDROID_NATIVE_API_LEVEL=android-14 -DANDROID_ABI="armeabi-v7a with NEON" -DSPIRV_BUILD_COMPRESSION=ON -DSPIRV_SKIP_TESTS=ON -DCMAKE_TOOLCHAIN_FILE=$TOOLCHAIN_PATH -GNinja -DANDROID_NDK=$ANDROID_NDK .. +cmake -DPYTHON_EXECUTABLE:FILEPATH=/usr/bin/python3 -DCMAKE_BUILD_TYPE=Release -DANDROID_NATIVE_API_LEVEL=android-14 -DANDROID_ABI="armeabi-v7a with NEON" -DSPIRV_SKIP_TESTS=ON -DCMAKE_TOOLCHAIN_FILE=$TOOLCHAIN_PATH -GNinja -DANDROID_NDK=$ANDROID_NDK .. echo $(date): Build everything... ninja diff --git a/third_party/spirv-tools/test/comp/CMakeLists.txt b/third_party/spirv-tools/kokoro/linux-clang-asan/build.sh similarity index 51% rename from third_party/spirv-tools/test/comp/CMakeLists.txt rename to third_party/spirv-tools/kokoro/linux-clang-asan/build.sh index c947fde0c6..8f86e6ec71 100644 --- a/third_party/spirv-tools/test/comp/CMakeLists.txt +++ b/third_party/spirv-tools/kokoro/linux-clang-asan/build.sh @@ -1,4 +1,5 @@ -# Copyright (c) 2017 Google Inc. +#!/bin/bash +# Copyright (c) 2019 Google LLC. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -11,19 +12,13 @@ # 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. +# +# Linux Build Script. -set(VAL_TEST_COMMON_SRCS - ${CMAKE_CURRENT_SOURCE_DIR}/../test_fixture.h - ${CMAKE_CURRENT_SOURCE_DIR}/../unit_spirv.h -) +# Fail on any error. +set -e +# Display commands being run. +set -x -if(SPIRV_BUILD_COMPRESSION) - add_spvtools_unittest(TARGET markv_codec - SRCS - markv_codec_test.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/../../tools/comp/markv_model_factory.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/../../tools/comp/markv_model_shader.cpp - ${VAL_TEST_COMMON_SRCS} - LIBS SPIRV-Tools-comp ${SPIRV_TOOLS} - ) -endif(SPIRV_BUILD_COMPRESSION) +SCRIPT_DIR=`dirname "$BASH_SOURCE"` +source $SCRIPT_DIR/../scripts/linux/build.sh ASAN clang diff --git a/third_party/spirv-tools/kokoro/linux-clang-asan/continuous.cfg b/third_party/spirv-tools/kokoro/linux-clang-asan/continuous.cfg new file mode 100644 index 0000000000..3a98fc7e16 --- /dev/null +++ b/third_party/spirv-tools/kokoro/linux-clang-asan/continuous.cfg @@ -0,0 +1,16 @@ +# Copyright (c) 2019 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. + +# Continuous build configuration. +build_file: "SPIRV-Tools/kokoro/linux-clang-asan/build.sh" diff --git a/third_party/spirv-tools/kokoro/linux-clang-asan/presubmit.cfg b/third_party/spirv-tools/kokoro/linux-clang-asan/presubmit.cfg new file mode 100644 index 0000000000..ceac44ba38 --- /dev/null +++ b/third_party/spirv-tools/kokoro/linux-clang-asan/presubmit.cfg @@ -0,0 +1,16 @@ +# Copyright (c) 2019 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. + +# Presubmit build configuration. +build_file: "SPIRV-Tools/kokoro/linux-clang-asan/build.sh" diff --git a/third_party/spirv-tools/kokoro/linux-clang-debug/continuous.cfg b/third_party/spirv-tools/kokoro/linux-clang-debug/continuous.cfg index e92f059ed5..3350f3bb12 100644 --- a/third_party/spirv-tools/kokoro/linux-clang-debug/continuous.cfg +++ b/third_party/spirv-tools/kokoro/linux-clang-debug/continuous.cfg @@ -14,3 +14,9 @@ # Continuous build configuration. build_file: "SPIRV-Tools/kokoro/linux-clang-debug/build.sh" + +action { + define_artifacts { + regex: "install.tgz" + } +} diff --git a/third_party/spirv-tools/kokoro/linux-clang-release-bazel/build.sh b/third_party/spirv-tools/kokoro/linux-clang-release-bazel/build.sh new file mode 100644 index 0000000000..cc38bd4ace --- /dev/null +++ b/third_party/spirv-tools/kokoro/linux-clang-release-bazel/build.sh @@ -0,0 +1,42 @@ +#!/bin/bash +# Copyright (c) 2019 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. +# +# Linux Build Script. + +# Fail on any error. +set -e +# Display commands being run. +set -x + +CC=clang +CXX=clang++ +SRC=$PWD/github/SPIRV-Tools + +cd $SRC +git clone --depth=1 https://github.com/KhronosGroup/SPIRV-Headers external/spirv-headers +git clone --depth=1 https://github.com/google/googletest external/googletest +git clone --depth=1 https://github.com/google/effcee external/effcee +git clone --depth=1 https://github.com/google/re2 external/re2 + +gsutil cp gs://bazel/0.29.1/release/bazel-0.29.1-linux-x86_64 . +chmod +x bazel-0.29.1-linux-x86_64 + +echo $(date): Build everything... +./bazel-0.29.1-linux-x86_64 build :all +echo $(date): Build completed. + +echo $(date): Starting bazel test... +./bazel-0.29.1-linux-x86_64 test :all +echo $(date): Bazel test completed. diff --git a/third_party/spirv-tools/kokoro/linux-clang-release-bazel/continuous.cfg b/third_party/spirv-tools/kokoro/linux-clang-release-bazel/continuous.cfg new file mode 100644 index 0000000000..8b33a24c53 --- /dev/null +++ b/third_party/spirv-tools/kokoro/linux-clang-release-bazel/continuous.cfg @@ -0,0 +1,16 @@ +# Copyright (c) 2019 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. + +# Continuous build configuration. +build_file: "SPIRV-Tools/kokoro/linux-clang-release-bazel/build.sh" diff --git a/third_party/spirv-tools/kokoro/linux-clang-release-bazel/presubmit.cfg b/third_party/spirv-tools/kokoro/linux-clang-release-bazel/presubmit.cfg new file mode 100644 index 0000000000..c7a2e6f952 --- /dev/null +++ b/third_party/spirv-tools/kokoro/linux-clang-release-bazel/presubmit.cfg @@ -0,0 +1,16 @@ +# Copyright (c) 2019 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. + +# Presubmit build configuration. +build_file: "SPIRV-Tools/kokoro/linux-clang-release-bazel/build.sh" diff --git a/third_party/spirv-tools/kokoro/linux-clang-release/continuous.cfg b/third_party/spirv-tools/kokoro/linux-clang-release/continuous.cfg index 687434accd..8b075c6eb0 100644 --- a/third_party/spirv-tools/kokoro/linux-clang-release/continuous.cfg +++ b/third_party/spirv-tools/kokoro/linux-clang-release/continuous.cfg @@ -14,3 +14,9 @@ # Continuous build configuration. build_file: "SPIRV-Tools/kokoro/linux-clang-release/build.sh" + +action { + define_artifacts { + regex: "install.tgz" + } +} diff --git a/third_party/spirv-tools/kokoro/linux-gcc-debug/continuous.cfg b/third_party/spirv-tools/kokoro/linux-gcc-debug/continuous.cfg index 4f8418d84c..d9579d5a03 100644 --- a/third_party/spirv-tools/kokoro/linux-gcc-debug/continuous.cfg +++ b/third_party/spirv-tools/kokoro/linux-gcc-debug/continuous.cfg @@ -14,3 +14,9 @@ # Continuous build configuration. build_file: "SPIRV-Tools/kokoro/linux-gcc-debug/build.sh" + +action { + define_artifacts { + regex: "install.tgz" + } +} diff --git a/third_party/spirv-tools/kokoro/linux-gcc-release/continuous.cfg b/third_party/spirv-tools/kokoro/linux-gcc-release/continuous.cfg index 41a0024e78..ead07bf404 100644 --- a/third_party/spirv-tools/kokoro/linux-gcc-release/continuous.cfg +++ b/third_party/spirv-tools/kokoro/linux-gcc-release/continuous.cfg @@ -14,3 +14,9 @@ # Continuous build configuration. build_file: "SPIRV-Tools/kokoro/linux-gcc-release/build.sh" + +action { + define_artifacts { + regex: "install.tgz" + } +} diff --git a/third_party/spirv-tools/kokoro/macos-clang-debug/continuous.cfg b/third_party/spirv-tools/kokoro/macos-clang-debug/continuous.cfg index 84aaa5c258..f5f274a0e6 100644 --- a/third_party/spirv-tools/kokoro/macos-clang-debug/continuous.cfg +++ b/third_party/spirv-tools/kokoro/macos-clang-debug/continuous.cfg @@ -14,3 +14,9 @@ # Continuous build configuration. build_file: "SPIRV-Tools/kokoro/macos-clang-debug/build.sh" + +action { + define_artifacts { + regex: "install.tgz" + } +} diff --git a/third_party/spirv-tools/kokoro/macos-clang-release-bazel/build.sh b/third_party/spirv-tools/kokoro/macos-clang-release-bazel/build.sh new file mode 100644 index 0000000000..e92fa74ef6 --- /dev/null +++ b/third_party/spirv-tools/kokoro/macos-clang-release-bazel/build.sh @@ -0,0 +1,43 @@ +#!/bin/bash +# Copyright (c) 2019 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. +# +# Linux Build Script. + +# Fail on any error. +set -e +# Display commands being run. +set -x + +CC=clang +CXX=clang++ +SRC=$PWD/github/SPIRV-Tools + +cd $SRC +git clone --depth=1 https://github.com/KhronosGroup/SPIRV-Headers external/spirv-headers +git clone --depth=1 https://github.com/google/googletest external/googletest +git clone --depth=1 https://github.com/google/effcee external/effcee +git clone --depth=1 https://github.com/google/re2 external/re2 + +# Get bazel 0.29.1. +gsutil cp gs://bazel/0.29.1/release/bazel-0.29.1-darwin-x86_64 . +chmod +x bazel-0.29.1-darwin-x86_64 + +echo $(date): Build everything... +./bazel-0.29.1-darwin-x86_64 build :all +echo $(date): Build completed. + +echo $(date): Starting bazel test... +./bazel-0.29.1-darwin-x86_64 test :all +echo $(date): Bazel test completed. diff --git a/third_party/spirv-tools/kokoro/macos-clang-release-bazel/continuous.cfg b/third_party/spirv-tools/kokoro/macos-clang-release-bazel/continuous.cfg new file mode 100644 index 0000000000..97654892bb --- /dev/null +++ b/third_party/spirv-tools/kokoro/macos-clang-release-bazel/continuous.cfg @@ -0,0 +1,16 @@ +# Copyright (c) 2019 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. + +# Continuous build configuration. +build_file: "SPIRV-Tools/kokoro/macos-clang-release-bazel/build.sh" diff --git a/third_party/spirv-tools/kokoro/macos-clang-release-bazel/presubmit.cfg b/third_party/spirv-tools/kokoro/macos-clang-release-bazel/presubmit.cfg new file mode 100644 index 0000000000..3b13602716 --- /dev/null +++ b/third_party/spirv-tools/kokoro/macos-clang-release-bazel/presubmit.cfg @@ -0,0 +1,16 @@ +# Copyright (c) 2019 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. + +# Presubmit build configuration. +build_file: "SPIRV-Tools/kokoro/macos-clang-release-bazel/build.sh" diff --git a/third_party/spirv-tools/kokoro/macos-clang-release/continuous.cfg b/third_party/spirv-tools/kokoro/macos-clang-release/continuous.cfg index a8e23a71aa..710185e463 100644 --- a/third_party/spirv-tools/kokoro/macos-clang-release/continuous.cfg +++ b/third_party/spirv-tools/kokoro/macos-clang-release/continuous.cfg @@ -14,3 +14,9 @@ # Continuous build configuration. build_file: "SPIRV-Tools/kokoro/macos-clang-release/build.sh" + +action { + define_artifacts { + regex: "install.tgz" + } +} diff --git a/third_party/spirv-tools/kokoro/scripts/linux/build.sh b/third_party/spirv-tools/kokoro/scripts/linux/build.sh index d457539d40..f7b0fe1497 100644 --- a/third_party/spirv-tools/kokoro/scripts/linux/build.sh +++ b/third_party/spirv-tools/kokoro/scripts/linux/build.sh @@ -31,8 +31,7 @@ BUILD_TYPE="Debug" CMAKE_C_CXX_COMPILER="" if [ $COMPILER = "clang" ] then - sudo ln -s /usr/bin/clang-3.8 /usr/bin/clang - sudo ln -s /usr/bin/clang++-3.8 /usr/bin/clang++ + PATH=/usr/lib/llvm-3.8/bin:$PATH CMAKE_C_CXX_COMPILER="-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++" fi @@ -47,8 +46,8 @@ fi ADDITIONAL_CMAKE_FLAGS="" if [ $CONFIG = "ASAN" ] then - ADDITIONAL_CMAKE_FLAGS="-DCMAKE_CXX_FLAGS=-fsanitize=address -DCMAKE_C_FLAGS=-fsanitize=address" - export ASAN_SYMBOLIZER_PATH=/usr/bin/llvm-symbolizer-3.4 + ADDITIONAL_CMAKE_FLAGS="SPIRV_USE_SANITIZER=address" + [ $COMPILER = "clang" ] || { echo "$CONFIG requires clang"; exit 1; } elif [ $CONFIG = "COVERAGE" ] then ADDITIONAL_CMAKE_FLAGS="-DENABLE_CODE_COVERAGE=ON" @@ -72,13 +71,18 @@ git clone --depth=1 https://github.com/KhronosGroup/SPIRV-Headers external/spirv git clone --depth=1 https://github.com/google/googletest external/googletest git clone --depth=1 https://github.com/google/effcee external/effcee git clone --depth=1 https://github.com/google/re2 external/re2 +git clone --depth=1 https://github.com/protocolbuffers/protobuf external/protobuf +pushd external/protobuf +git fetch --all --tags --prune +git checkout v3.7.1 +popd mkdir build && cd $SRC/build # Invoke the build. BUILD_SHA=${KOKORO_GITHUB_COMMIT:-$KOKORO_GITHUB_PULL_REQUEST_COMMIT} echo $(date): Starting build... -cmake -GNinja -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_INSTALL_PREFIX=install -DRE2_BUILD_TESTING=OFF $ADDITIONAL_CMAKE_FLAGS $CMAKE_C_CXX_COMPILER .. +cmake -DPYTHON_EXECUTABLE:FILEPATH=/usr/bin/python3 -GNinja -DCMAKE_INSTALL_PREFIX=$KOKORO_ARTIFACTS_DIR/install -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DRE2_BUILD_TESTING=OFF -DSPIRV_BUILD_FUZZER=ON $ADDITIONAL_CMAKE_FLAGS $CMAKE_C_CXX_COMPILER .. echo $(date): Build everything... ninja @@ -98,3 +102,7 @@ then fi echo $(date): ctest completed. +# Package the build. +ninja install +cd $KOKORO_ARTIFACTS_DIR +tar czf install.tgz install diff --git a/third_party/spirv-tools/kokoro/scripts/macos/build.sh b/third_party/spirv-tools/kokoro/scripts/macos/build.sh index a7f0453fe0..5a3af43bb8 100644 --- a/third_party/spirv-tools/kokoro/scripts/macos/build.sh +++ b/third_party/spirv-tools/kokoro/scripts/macos/build.sh @@ -35,13 +35,27 @@ git clone --depth=1 https://github.com/KhronosGroup/SPIRV-Headers external/spirv git clone --depth=1 https://github.com/google/googletest external/googletest git clone --depth=1 https://github.com/google/effcee external/effcee git clone --depth=1 https://github.com/google/re2 external/re2 +git clone --depth=1 https://github.com/protocolbuffers/protobuf external/protobuf +pushd external/protobuf +git fetch --all --tags --prune +git checkout v3.7.1 +popd mkdir build && cd $SRC/build # Invoke the build. BUILD_SHA=${KOKORO_GITHUB_COMMIT:-$KOKORO_GITHUB_PULL_REQUEST_COMMIT} echo $(date): Starting build... -cmake -GNinja -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_BUILD_TYPE=$BUILD_TYPE .. +# We need Python 3. At the moment python3.7 is the newest Python on Kokoro. +cmake \ + -GNinja \ + -DCMAKE_INSTALL_PREFIX=$KOKORO_ARTIFACTS_DIR/install \ + -DPYTHON_EXECUTABLE:FILEPATH=/usr/local/bin/python3.7 \ + -DCMAKE_C_COMPILER=clang \ + -DCMAKE_CXX_COMPILER=clang++ \ + -DCMAKE_BUILD_TYPE=$BUILD_TYPE \ + -DSPIRV_BUILD_FUZZER=ON \ + .. echo $(date): Build everything... ninja @@ -51,3 +65,8 @@ echo $(date): Starting ctest... ctest -j4 --output-on-failure --timeout 300 echo $(date): ctest completed. +# Package the build. +ninja install +cd $KOKORO_ARTIFACTS_DIR +tar czf install.tgz install + diff --git a/third_party/spirv-tools/kokoro/scripts/windows/build.bat b/third_party/spirv-tools/kokoro/scripts/windows/build.bat index a2472fb4fd..a4f2bf0077 100644 --- a/third_party/spirv-tools/kokoro/scripts/windows/build.bat +++ b/third_party/spirv-tools/kokoro/scripts/windows/build.bat @@ -21,14 +21,19 @@ set SRC=%cd%\github\SPIRV-Tools set BUILD_TYPE=%1 set VS_VERSION=%2 -:: Force usage of python 2.7 rather than 3.6 -set PATH=C:\python27;%PATH% +:: Force usage of python 3.6 +set PATH=C:\python36;%PATH% cd %SRC% git clone --depth=1 https://github.com/KhronosGroup/SPIRV-Headers external/spirv-headers git clone --depth=1 https://github.com/google/googletest external/googletest git clone --depth=1 https://github.com/google/effcee external/effcee git clone --depth=1 https://github.com/google/re2 external/re2 +git clone --depth=1 https://github.com/protocolbuffers/protobuf external/protobuf +pushd external\protobuf +git fetch --all --tags --prune +git checkout v3.7.1 +popd :: ######################################### :: set up msvc build env @@ -58,33 +63,50 @@ if "%KOKORO_GITHUB_COMMIT%." == "." ( set BUILD_SHA=%KOKORO_GITHUB_COMMIT% ) +set CMAKE_FLAGS=-DCMAKE_INSTALL_PREFIX=%KOKORO_ARTIFACTS_DIR%\install -GNinja -DCMAKE_BUILD_TYPE=%BUILD_TYPE% -DRE2_BUILD_TESTING=OFF -DCMAKE_C_COMPILER=cl.exe -DCMAKE_CXX_COMPILER=cl.exe + :: Skip building tests for VS2013 if %VS_VERSION% == 2013 ( - cmake -GNinja -DSPIRV_SKIP_TESTS=ON -DSPIRV_BUILD_COMPRESSION=ON -DCMAKE_BUILD_TYPE=%BUILD_TYPE% -DCMAKE_INSTALL_PREFIX=install -DRE2_BUILD_TESTING=OFF -DCMAKE_C_COMPILER=cl.exe -DCMAKE_CXX_COMPILER=cl.exe .. -) else ( - cmake -GNinja -DSPIRV_BUILD_COMPRESSION=ON -DCMAKE_BUILD_TYPE=%BUILD_TYPE% -DCMAKE_INSTALL_PREFIX=install -DRE2_BUILD_TESTING=OFF -DCMAKE_C_COMPILER=cl.exe -DCMAKE_CXX_COMPILER=cl.exe .. + set CMAKE_FLAGS=%CMAKE_FLAGS% -DSPIRV_SKIP_TESTS=ON ) -if %ERRORLEVEL% GEQ 1 exit /b %ERRORLEVEL% +:: Skip building spirv-fuzz for VS2013; it relies on protobufs which VS2013 cannot handle. +if %VS_VERSION% NEQ 2013 ( + set CMAKE_FLAGS=%CMAKE_FLAGS% -DSPIRV_BUILD_FUZZER=ON +) + +cmake %CMAKE_FLAGS% .. + +if %ERRORLEVEL% NEQ 0 exit /b %ERRORLEVEL% echo "Build everything... %DATE% %TIME%" ninja -if %ERRORLEVEL% GEQ 1 exit /b %ERRORLEVEL% +if %ERRORLEVEL% NEQ 0 exit /b %ERRORLEVEL% echo "Build Completed %DATE% %TIME%" +:: This lets us use !ERRORLEVEL! inside an IF ... () and get the actual error at that point. +setlocal ENABLEDELAYEDEXPANSION + :: ################################################ :: Run the tests (We no longer run tests on VS2013) :: ################################################ -if NOT %VS_VERSION% == 2013 ( - echo "Running Tests... %DATE% %TIME%" +echo "Running Tests... %DATE% %TIME%" +if %VS_VERSION% NEQ 2013 ( ctest -C %BUILD_TYPE% --output-on-failure --timeout 300 - if %ERRORLEVEL% GEQ 1 exit /b %ERRORLEVEL% - echo "Tests Completed %DATE% %TIME%" + if !ERRORLEVEL! NEQ 0 exit /b !ERRORLEVEL! ) +echo "Tests Completed %DATE% %TIME%" + +:: ################################################ +:: Install and package. +:: ################################################ +ninja install +cd %KOKORO_ARTIFACTS_DIR% +zip -r install.zip install :: Clean up some directories. rm -rf %SRC%\build rm -rf %SRC%\external -exit /b %ERRORLEVEL% +exit /b 0 diff --git a/third_party/spirv-tools/kokoro/shaderc-smoketest/build.sh b/third_party/spirv-tools/kokoro/shaderc-smoketest/build.sh new file mode 100644 index 0000000000..0856c9b25f --- /dev/null +++ b/third_party/spirv-tools/kokoro/shaderc-smoketest/build.sh @@ -0,0 +1,71 @@ +#!/bin/bash +# Copyright (c) 2018 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. + +# Fail on any error. +set -e +# Display commands being run. +set -x + +BUILD_ROOT=$PWD +GITHUB_DIR=$BUILD_ROOT/github + +SKIP_TESTS="False" +BUILD_TYPE="Release" + +# Get NINJA. +wget -q https://github.com/ninja-build/ninja/releases/download/v1.8.2/ninja-linux.zip +unzip -q ninja-linux.zip +export PATH="$PWD:$PATH" + +# Get shaderc. +cd $GITHUB_DIR +git clone https://github.com/google/shaderc.git +SHADERC_DIR=$GITHUB_DIR/shaderc +cd $SHADERC_DIR/third_party + +# Get shaderc dependencies. Link the appropriate SPIRV-Tools. +git clone https://github.com/google/googletest.git +git clone https://github.com/KhronosGroup/glslang.git +ln -s $GITHUB_DIR/SPIRV-Tools spirv-tools +git clone https://github.com/KhronosGroup/SPIRV-Headers.git spirv-headers +git clone https://github.com/google/re2 +git clone https://github.com/google/effcee + +cd $SHADERC_DIR +mkdir build +cd $SHADERC_DIR/build + +# Invoke the build. +BUILD_SHA=${KOKORO_GITHUB_COMMIT:-$KOKORO_GITHUB_PULL_REQUEST_COMMIT} +echo $(date): Starting build... +cmake -GNinja -DRE2_BUILD_TESTING=OFF -DCMAKE_BUILD_TYPE=$BUILD_TYPE .. + +echo $(date): Build glslang... +ninja glslangValidator + +echo $(date): Build everything... +ninja +echo $(date): Build completed. + +echo $(date): Check Shaderc for copyright notices... +ninja check-copyright + +echo $(date): Starting ctest... +if [ $SKIP_TESTS = "False" ] +then + ctest --output-on-failure -j4 +fi +echo $(date): ctest completed. + diff --git a/third_party/spirv-tools/kokoro/shaderc-smoketest/continuous.cfg b/third_party/spirv-tools/kokoro/shaderc-smoketest/continuous.cfg new file mode 100644 index 0000000000..ee151ae1af --- /dev/null +++ b/third_party/spirv-tools/kokoro/shaderc-smoketest/continuous.cfg @@ -0,0 +1,17 @@ +# Copyright (c) 2018 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. + +# Continuous build configuration. +build_file: "SPIRV-Tools/kokoro/shaderc-smoketest/build.sh" + diff --git a/third_party/spirv-tools/kokoro/shaderc-smoketest/presubmit.cfg b/third_party/spirv-tools/kokoro/shaderc-smoketest/presubmit.cfg new file mode 100644 index 0000000000..4f2ed21b77 --- /dev/null +++ b/third_party/spirv-tools/kokoro/shaderc-smoketest/presubmit.cfg @@ -0,0 +1,17 @@ +# Copyright (c) 2018 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. + +# Presubmit build configuration. +build_file: "SPIRV-Tools/kokoro/shaderc-smoketest/build.sh" + diff --git a/third_party/spirv-tools/kokoro/windows-msvc-2015-release-bazel/build.bat b/third_party/spirv-tools/kokoro/windows-msvc-2015-release-bazel/build.bat new file mode 100644 index 0000000000..ddb4f540d7 --- /dev/null +++ b/third_party/spirv-tools/kokoro/windows-msvc-2015-release-bazel/build.bat @@ -0,0 +1,59 @@ +:: Copyright (c) 2019 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. +:: +:: Windows Build Script. + +@echo on + +set SRC=%cd%\github\SPIRV-Tools + +:: Force usage of python 3.6 +set PATH=C:\python36;%PATH% + +:: Get dependencies +cd %SRC% +git clone --depth=1 https://github.com/KhronosGroup/SPIRV-Headers external/spirv-headers +git clone --depth=1 https://github.com/google/googletest external/googletest +git clone --depth=1 https://github.com/google/effcee external/effcee +git clone --depth=1 https://github.com/google/re2 external/re2 + +:: REM Install Bazel. +wget -q https://github.com/bazelbuild/bazel/releases/download/0.29.1/bazel-0.29.1-windows-x86_64.zip +unzip -q bazel-0.29.1-windows-x86_64.zip + +:: Set up MSVC +call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x64 +set BAZEL_VS=C:\Program Files (x86)\Microsoft Visual Studio 14.0 +set BAZEL_VC=C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC +set BAZEL_SH=c:\tools\msys64\usr\bin\bash.exe +set BAZEL_PYTHON=c:\tools\python2\python.exe + +:: ######################################### +:: Start building. +:: ######################################### +echo "Build everything... %DATE% %TIME%" +bazel.exe build :all +if %ERRORLEVEL% NEQ 0 exit /b %ERRORLEVEL% +echo "Build Completed %DATE% %TIME%" + +:: ############## +:: Run the tests +:: ############## +echo "Running Tests... %DATE% %TIME%" +bazel.exe test :all +if %ERRORLEVEL% NEQ 0 exit /b %ERRORLEVEL% +echo "Tests Completed %DATE% %TIME%" + +exit /b 0 + diff --git a/third_party/spirv-tools/kokoro/windows-msvc-2015-release-bazel/continuous.cfg b/third_party/spirv-tools/kokoro/windows-msvc-2015-release-bazel/continuous.cfg new file mode 100644 index 0000000000..f72cf0593d --- /dev/null +++ b/third_party/spirv-tools/kokoro/windows-msvc-2015-release-bazel/continuous.cfg @@ -0,0 +1,16 @@ +# Copyright (c) 2019 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. + +# Continuous build configuration. +build_file: "SPIRV-Tools/kokoro/windows-msvc-2015-release-bazel/build.bat" diff --git a/third_party/spirv-tools/kokoro/windows-msvc-2015-release-bazel/presubmit.cfg b/third_party/spirv-tools/kokoro/windows-msvc-2015-release-bazel/presubmit.cfg new file mode 100644 index 0000000000..148972ce8c --- /dev/null +++ b/third_party/spirv-tools/kokoro/windows-msvc-2015-release-bazel/presubmit.cfg @@ -0,0 +1,16 @@ +# Copyright (c) 2019 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. + +# Presubmit build configuration. +build_file: "SPIRV-Tools/kokoro/windows-msvc-2015-release-bazel/build.bat" diff --git a/third_party/spirv-tools/kokoro/windows-msvc-2017-debug/continuous.cfg b/third_party/spirv-tools/kokoro/windows-msvc-2017-debug/continuous.cfg index b842c30f19..25c5e113de 100644 --- a/third_party/spirv-tools/kokoro/windows-msvc-2017-debug/continuous.cfg +++ b/third_party/spirv-tools/kokoro/windows-msvc-2017-debug/continuous.cfg @@ -14,3 +14,9 @@ # Continuous build configuration. build_file: "SPIRV-Tools/kokoro/windows-msvc-2017-debug/build.bat" + +action { + define_artifacts { + regex: "install.zip" + } +} diff --git a/third_party/spirv-tools/kokoro/windows-msvc-2017-release/continuous.cfg b/third_party/spirv-tools/kokoro/windows-msvc-2017-release/continuous.cfg index 7b8c2ff2b8..a9ac6eca91 100644 --- a/third_party/spirv-tools/kokoro/windows-msvc-2017-release/continuous.cfg +++ b/third_party/spirv-tools/kokoro/windows-msvc-2017-release/continuous.cfg @@ -14,3 +14,9 @@ # Continuous build configuration. build_file: "SPIRV-Tools/kokoro/windows-msvc-2017-release/build.bat" + +action { + define_artifacts { + regex: "install.zip" + } +} diff --git a/third_party/spirv-tools/source/CMakeLists.txt b/third_party/spirv-tools/source/CMakeLists.txt index 4df5de3ad4..4e7e10cb6b 100644 --- a/third_party/spirv-tools/source/CMakeLists.txt +++ b/third_party/spirv-tools/source/CMakeLists.txt @@ -20,29 +20,34 @@ set(LANG_HEADER_PROCESSING_SCRIPT "${spirv-tools_SOURCE_DIR}/utils/generate_lang # For now, assume the DebugInfo grammar file is in the current directory. # It might migrate to SPIRV-Headers. set(DEBUGINFO_GRAMMAR_JSON_FILE "${CMAKE_CURRENT_SOURCE_DIR}/extinst.debuginfo.grammar.json") +set(CLDEBUGINFO100_GRAMMAR_JSON_FILE "${CMAKE_CURRENT_SOURCE_DIR}/extinst.opencl.debuginfo.100.grammar.json") # macro() definitions are used in the following because we need to append .inc # file paths into some global lists (*_CPP_DEPENDS). And those global lists are # later used by set_source_files_properties() calls. # function() definitions are not suitable because they create new scopes. -macro(spvtools_core_tables VERSION) - set(GRAMMAR_JSON_FILE "${SPIRV_HEADER_INCLUDE_DIR}/spirv/${VERSION}/spirv.core.grammar.json") - set(GRAMMAR_INSTS_INC_FILE "${spirv-tools_BINARY_DIR}/core.insts-${VERSION}.inc") - set(GRAMMAR_KINDS_INC_FILE "${spirv-tools_BINARY_DIR}/operand.kinds-${VERSION}.inc") +macro(spvtools_core_tables CONFIG_VERSION) + set(GRAMMAR_JSON_FILE "${SPIRV_HEADER_INCLUDE_DIR}/spirv/${CONFIG_VERSION}/spirv.core.grammar.json") + set(GRAMMAR_INSTS_INC_FILE "${spirv-tools_BINARY_DIR}/core.insts-${CONFIG_VERSION}.inc") + set(GRAMMAR_KINDS_INC_FILE "${spirv-tools_BINARY_DIR}/operand.kinds-${CONFIG_VERSION}.inc") add_custom_command(OUTPUT ${GRAMMAR_INSTS_INC_FILE} ${GRAMMAR_KINDS_INC_FILE} COMMAND ${PYTHON_EXECUTABLE} ${GRAMMAR_PROCESSING_SCRIPT} --spirv-core-grammar=${GRAMMAR_JSON_FILE} --extinst-debuginfo-grammar=${DEBUGINFO_GRAMMAR_JSON_FILE} + --extinst-cldebuginfo100-grammar=${CLDEBUGINFO100_GRAMMAR_JSON_FILE} --core-insts-output=${GRAMMAR_INSTS_INC_FILE} --operand-kinds-output=${GRAMMAR_KINDS_INC_FILE} - DEPENDS ${GRAMMAR_PROCESSING_SCRIPT} ${GRAMMAR_JSON_FILE} ${DEBUGINFO_GRAMMAR_JSON_FILE} - COMMENT "Generate info tables for SPIR-V v${VERSION} core instructions and operands.") + DEPENDS ${GRAMMAR_PROCESSING_SCRIPT} + ${GRAMMAR_JSON_FILE} + ${DEBUGINFO_GRAMMAR_JSON_FILE} + ${CLDEBUGINFO100_GRAMMAR_JSON_FILE} + COMMENT "Generate info tables for SPIR-V v${CONFIG_VERSION} core instructions and operands.") list(APPEND OPCODE_CPP_DEPENDS ${GRAMMAR_INSTS_INC_FILE}) list(APPEND OPERAND_CPP_DEPENDS ${GRAMMAR_KINDS_INC_FILE}) endmacro(spvtools_core_tables) -macro(spvtools_enum_string_mapping VERSION) - set(GRAMMAR_JSON_FILE "${SPIRV_HEADER_INCLUDE_DIR}/spirv/${VERSION}/spirv.core.grammar.json") +macro(spvtools_enum_string_mapping CONFIG_VERSION) + set(GRAMMAR_JSON_FILE "${SPIRV_HEADER_INCLUDE_DIR}/spirv/${CONFIG_VERSION}/spirv.core.grammar.json") set(GRAMMAR_EXTENSION_ENUM_INC_FILE "${spirv-tools_BINARY_DIR}/extension_enum.inc") set(GRAMMAR_ENUM_STRING_MAPPING_INC_FILE "${spirv-tools_BINARY_DIR}/enum_string_mapping.inc") add_custom_command(OUTPUT ${GRAMMAR_EXTENSION_ENUM_INC_FILE} @@ -50,18 +55,22 @@ macro(spvtools_enum_string_mapping VERSION) COMMAND ${PYTHON_EXECUTABLE} ${GRAMMAR_PROCESSING_SCRIPT} --spirv-core-grammar=${GRAMMAR_JSON_FILE} --extinst-debuginfo-grammar=${DEBUGINFO_GRAMMAR_JSON_FILE} + --extinst-cldebuginfo100-grammar=${CLDEBUGINFO100_GRAMMAR_JSON_FILE} --extension-enum-output=${GRAMMAR_EXTENSION_ENUM_INC_FILE} --enum-string-mapping-output=${GRAMMAR_ENUM_STRING_MAPPING_INC_FILE} - DEPENDS ${GRAMMAR_PROCESSING_SCRIPT} ${GRAMMAR_JSON_FILE} ${DEBUGINFO_GRAMMAR_JSON_FILE} - COMMENT "Generate enum-string mapping for SPIR-V v${VERSION}.") + DEPENDS ${GRAMMAR_PROCESSING_SCRIPT} + ${GRAMMAR_JSON_FILE} + ${DEBUGINFO_GRAMMAR_JSON_FILE} + ${CLDEBUGINFO100_GRAMMAR_JSON_FILE} + COMMENT "Generate enum-string mapping for SPIR-V v${CONFIG_VERSION}.") list(APPEND EXTENSION_H_DEPENDS ${GRAMMAR_EXTENSION_ENUM_INC_FILE}) list(APPEND ENUM_STRING_MAPPING_CPP_DEPENDS ${GRAMMAR_ENUM_STRING_MAPPING_INC_FILE}) endmacro(spvtools_enum_string_mapping) -macro(spvtools_vimsyntax VERSION CLVERSION) - set(GRAMMAR_JSON_FILE "${SPIRV_HEADER_INCLUDE_DIR}/spirv/${VERSION}/spirv.core.grammar.json") - set(GLSL_GRAMMAR_JSON_FILE "${SPIRV_HEADER_INCLUDE_DIR}/spirv/${VERSION}/extinst.glsl.std.450.grammar.json") - set(OPENCL_GRAMMAR_JSON_FILE "${SPIRV_HEADER_INCLUDE_DIR}/spirv/${VERSION}/extinst.opencl.std.100.grammar.json") +macro(spvtools_vimsyntax CONFIG_VERSION CLVERSION) + set(GRAMMAR_JSON_FILE "${SPIRV_HEADER_INCLUDE_DIR}/spirv/${CONFIG_VERSION}/spirv.core.grammar.json") + set(GLSL_GRAMMAR_JSON_FILE "${SPIRV_HEADER_INCLUDE_DIR}/spirv/${CONFIG_VERSION}/extinst.glsl.std.450.grammar.json") + set(OPENCL_GRAMMAR_JSON_FILE "${SPIRV_HEADER_INCLUDE_DIR}/spirv/${CONFIG_VERSION}/extinst.opencl.std.100.grammar.json") set(VIMSYNTAX_FILE "${spirv-tools_BINARY_DIR}/spvasm.vim") add_custom_command(OUTPUT ${VIMSYNTAX_FILE} COMMAND ${PYTHON_EXECUTABLE} ${VIMSYNTAX_PROCESSING_SCRIPT} @@ -75,44 +84,45 @@ macro(spvtools_vimsyntax VERSION CLVERSION) COMMENT "Generate spvasm.vim: Vim syntax file for SPIR-V assembly.") endmacro(spvtools_vimsyntax) -macro(spvtools_glsl_tables VERSION) - set(CORE_GRAMMAR_JSON_FILE "${SPIRV_HEADER_INCLUDE_DIR}/spirv/${VERSION}/spirv.core.grammar.json") - set(GLSL_GRAMMAR_JSON_FILE "${SPIRV_HEADER_INCLUDE_DIR}/spirv/${VERSION}/extinst.glsl.std.450.grammar.json") +macro(spvtools_glsl_tables CONFIG_VERSION) + set(CORE_GRAMMAR_JSON_FILE "${SPIRV_HEADER_INCLUDE_DIR}/spirv/${CONFIG_VERSION}/spirv.core.grammar.json") + set(GLSL_GRAMMAR_JSON_FILE "${SPIRV_HEADER_INCLUDE_DIR}/spirv/${CONFIG_VERSION}/extinst.glsl.std.450.grammar.json") set(GRAMMAR_INC_FILE "${spirv-tools_BINARY_DIR}/glsl.std.450.insts.inc") add_custom_command(OUTPUT ${GRAMMAR_INC_FILE} COMMAND ${PYTHON_EXECUTABLE} ${GRAMMAR_PROCESSING_SCRIPT} --extinst-glsl-grammar=${GLSL_GRAMMAR_JSON_FILE} --glsl-insts-output=${GRAMMAR_INC_FILE} DEPENDS ${GRAMMAR_PROCESSING_SCRIPT} ${CORE_GRAMMAR_JSON_FILE} ${GLSL_GRAMMAR_JSON_FILE} - COMMENT "Generate info tables for GLSL extended instructions and operands v${VERSION}.") + COMMENT "Generate info tables for GLSL extended instructions and operands v${CONFIG_VERSION}.") list(APPEND EXTINST_CPP_DEPENDS ${GRAMMAR_INC_FILE}) endmacro(spvtools_glsl_tables) -macro(spvtools_opencl_tables VERSION) - set(CORE_GRAMMAR_JSON_FILE "${SPIRV_HEADER_INCLUDE_DIR}/spirv/${VERSION}/spirv.core.grammar.json") - set(OPENCL_GRAMMAR_JSON_FILE "${SPIRV_HEADER_INCLUDE_DIR}/spirv/${VERSION}/extinst.opencl.std.100.grammar.json") +macro(spvtools_opencl_tables CONFIG_VERSION) + set(CORE_GRAMMAR_JSON_FILE "${SPIRV_HEADER_INCLUDE_DIR}/spirv/${CONFIG_VERSION}/spirv.core.grammar.json") + set(OPENCL_GRAMMAR_JSON_FILE "${SPIRV_HEADER_INCLUDE_DIR}/spirv/${CONFIG_VERSION}/extinst.opencl.std.100.grammar.json") set(GRAMMAR_INC_FILE "${spirv-tools_BINARY_DIR}/opencl.std.insts.inc") add_custom_command(OUTPUT ${GRAMMAR_INC_FILE} COMMAND ${PYTHON_EXECUTABLE} ${GRAMMAR_PROCESSING_SCRIPT} --extinst-opencl-grammar=${OPENCL_GRAMMAR_JSON_FILE} --opencl-insts-output=${GRAMMAR_INC_FILE} DEPENDS ${GRAMMAR_PROCESSING_SCRIPT} ${CORE_GRAMMAR_JSON_FILE} ${OPENCL_GRAMMAR_JSON_FILE} - COMMENT "Generate info tables for OpenCL extended instructions and operands v${VERSION}.") + COMMENT "Generate info tables for OpenCL extended instructions and operands v${CONFIG_VERSION}.") list(APPEND EXTINST_CPP_DEPENDS ${GRAMMAR_INC_FILE}) endmacro(spvtools_opencl_tables) -macro(spvtools_vendor_tables VENDOR_TABLE) +macro(spvtools_vendor_tables VENDOR_TABLE SHORT_NAME OPERAND_KIND_PREFIX) set(INSTS_FILE "${spirv-tools_BINARY_DIR}/${VENDOR_TABLE}.insts.inc") set(GRAMMAR_FILE "${spirv-tools_SOURCE_DIR}/source/extinst.${VENDOR_TABLE}.grammar.json") add_custom_command(OUTPUT ${INSTS_FILE} COMMAND ${PYTHON_EXECUTABLE} ${GRAMMAR_PROCESSING_SCRIPT} --extinst-vendor-grammar=${GRAMMAR_FILE} --vendor-insts-output=${INSTS_FILE} + --vendor-operand-kind-prefix=${OPERAND_KIND_PREFIX} DEPENDS ${GRAMMAR_PROCESSING_SCRIPT} ${GRAMMAR_FILE} COMMENT "Generate extended instruction tables for ${VENDOR_TABLE}.") - list(APPEND EXTINST_CPP_DEPENDS ${INSTS_FILE}) - add_custom_target(spirv-tools-${VENDOR_TABLE} DEPENDS ${INSTS_FILE}) - set_property(TARGET spirv-tools-${VENDOR_TABLE} PROPERTY FOLDER "SPIRV-Tools build") + add_custom_target(spv-tools-${SHORT_NAME} DEPENDS ${INSTS_FILE}) + set_property(TARGET spv-tools-${SHORT_NAME} PROPERTY FOLDER "SPIRV-Tools build") + list(APPEND EXTINST_CPP_DEPENDS spv-tools-${SHORT_NAME}) endmacro(spvtools_vendor_tables) macro(spvtools_extinst_lang_headers NAME GRAMMAR_FILE) @@ -125,21 +135,23 @@ macro(spvtools_extinst_lang_headers NAME GRAMMAR_FILE) --extinst-output-base=${OUTBASE} DEPENDS ${LANG_HEADER_PROCESSING_SCRIPT} ${GRAMMAR_FILE} COMMENT "Generate language specific header for ${NAME}.") - list(APPEND EXTINST_CPP_DEPENDS ${OUT_H}) add_custom_target(spirv-tools-header-${NAME} DEPENDS ${OUT_H}) set_property(TARGET spirv-tools-header-${NAME} PROPERTY FOLDER "SPIRV-Tools build") + list(APPEND EXTINST_CPP_DEPENDS spirv-tools-header-${NAME}) endmacro(spvtools_extinst_lang_headers) spvtools_core_tables("unified1") spvtools_enum_string_mapping("unified1") spvtools_opencl_tables("unified1") spvtools_glsl_tables("unified1") -spvtools_vendor_tables("spv-amd-shader-explicit-vertex-parameter") -spvtools_vendor_tables("spv-amd-shader-trinary-minmax") -spvtools_vendor_tables("spv-amd-gcn-shader") -spvtools_vendor_tables("spv-amd-shader-ballot") -spvtools_vendor_tables("debuginfo") +spvtools_vendor_tables("spv-amd-shader-explicit-vertex-parameter" "spv-amd-sevp" "") +spvtools_vendor_tables("spv-amd-shader-trinary-minmax" "spv-amd-stm" "") +spvtools_vendor_tables("spv-amd-gcn-shader" "spv-amd-gs" "") +spvtools_vendor_tables("spv-amd-shader-ballot" "spv-amd-sb" "") +spvtools_vendor_tables("debuginfo" "debuginfo" "") +spvtools_vendor_tables("opencl.debuginfo.100" "cldi100" "CLDEBUG100_") spvtools_extinst_lang_headers("DebugInfo" ${DEBUGINFO_GRAMMAR_JSON_FILE}) +spvtools_extinst_lang_headers("OpenCLDebugInfo100" ${CLDEBUGINFO100_GRAMMAR_JSON_FILE}) spvtools_vimsyntax("unified1" "1.0") add_custom_target(spirv-tools-vimsyntax DEPENDS ${VIMSYNTAX_FILE}) @@ -159,36 +171,18 @@ list(APPEND OPCODE_CPP_DEPENDS ${GENERATOR_INC_FILE}) # The following .cpp files include the above generated .inc files. # Add those .inc files as their dependencies. # -# Why using such an awkward way? -# * If we use add_custom_target() to define a target to generate all .inc files -# and let ${SPIRV_TOOLS} depend on it, then we need to run ninja twice every -# time the grammar is updated: the first time is for generating those .inc -# files, and the second time is for rebuilding .cpp files, when ninja finds -# out that .inc files are updated. -# * If we use add_custom_command() with PRE_BUILD, then the grammar processing -# script will always run no matter whether the grammar is updated. -# * add_dependencies() is used to add *target* dependencies to a target. -# * The following solution only generates .inc files when the script or the -# grammar files is updated, and in a single ninja run. -set_source_files_properties( - ${CMAKE_CURRENT_SOURCE_DIR}/opcode.cpp - PROPERTIES OBJECT_DEPENDS "${OPCODE_CPP_DEPENDS}") -set_source_files_properties( - ${CMAKE_CURRENT_SOURCE_DIR}/operand.cpp - PROPERTIES OBJECT_DEPENDS "${OPERAND_CPP_DEPENDS}") -set_source_files_properties( - ${CMAKE_CURRENT_SOURCE_DIR}/ext_inst.cpp - PROPERTIES OBJECT_DEPENDS "${EXTINST_CPP_DEPENDS}") -set_source_files_properties( - ${CMAKE_CURRENT_SOURCE_DIR}/enum_string_mapping.cpp - PROPERTIES OBJECT_DEPENDS "${ENUM_STRING_MAPPING_CPP_DEPENDS}") +# We need to wrap the .inc files with a custom target to avoid problems when +# multiple targets depend on the same custom command. +add_custom_target(core_tables + DEPENDS ${OPCODE_CPP_DEPENDS} ${OPERAND_CPP_DEPENDS}) +add_custom_target(enum_string_mapping + DEPENDS ${EXTENSION_H_DEPENDS} ${ENUM_STRING_MAPPING_CPP_DEPENDS}) +add_custom_target(extinst_tables + DEPENDS ${EXTINST_CPP_DEPENDS}) set_source_files_properties( - ${CMAKE_CURRENT_SOURCE_DIR}/extension.h + ${CMAKE_CURRENT_SOURCE_DIR}/extensions.h PROPERTIES HEADER_FILE_ONLY TRUE) -set_source_files_properties( - ${CMAKE_CURRENT_SOURCE_DIR}/extension.h - PROPERTIES OBJECT_DEPENDS "${EXTENSION_H_DEPENDS}") set(SPIRV_TOOLS_BUILD_VERSION_INC ${spirv-tools_BINARY_DIR}/build-version.inc) @@ -209,8 +203,14 @@ add_custom_target(spirv-tools-build-version DEPENDS ${SPIRV_TOOLS_BUILD_VERSION_INC}) set_property(TARGET spirv-tools-build-version PROPERTY FOLDER "SPIRV-Tools build") -add_subdirectory(comp) +list(APPEND PCH_DEPENDS ${ENUM_STRING_MAPPING_CPP_DEPENDS} ${OPCODE_CPP_DEPENDS} ${OPERAND_CPP_DEPENDS} ${EXTENSION_H_DEPENDS} ${EXTINST_CPP_DEPENDS} ${SPIRV_TOOLS_BUILD_VERSION_INC}) +set_source_files_properties( + ${CMAKE_CURRENT_SOURCE_DIR}/pch_source.cpp + PROPERTIES OBJECT_DEPENDS "${PCH_DEPENDS}") + add_subdirectory(opt) +add_subdirectory(reduce) +add_subdirectory(fuzz) add_subdirectory(link) set(SPIRV_SOURCES @@ -233,7 +233,6 @@ set(SPIRV_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/enum_string_mapping.h ${CMAKE_CURRENT_SOURCE_DIR}/ext_inst.h ${CMAKE_CURRENT_SOURCE_DIR}/extensions.h - ${CMAKE_CURRENT_SOURCE_DIR}/id_descriptor.h ${CMAKE_CURRENT_SOURCE_DIR}/instruction.h ${CMAKE_CURRENT_SOURCE_DIR}/latest_version_glsl_std_450_header.h ${CMAKE_CURRENT_SOURCE_DIR}/latest_version_opencl_std_header.h @@ -247,6 +246,9 @@ set(SPIRV_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/spirv_constant.h ${CMAKE_CURRENT_SOURCE_DIR}/spirv_definition.h ${CMAKE_CURRENT_SOURCE_DIR}/spirv_endian.h + ${CMAKE_CURRENT_SOURCE_DIR}/spirv_fuzzer_options.h + ${CMAKE_CURRENT_SOURCE_DIR}/spirv_optimizer_options.h + ${CMAKE_CURRENT_SOURCE_DIR}/spirv_reducer_options.h ${CMAKE_CURRENT_SOURCE_DIR}/spirv_target_env.h ${CMAKE_CURRENT_SOURCE_DIR}/spirv_validator_options.h ${CMAKE_CURRENT_SOURCE_DIR}/table.h @@ -264,7 +266,6 @@ set(SPIRV_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/enum_string_mapping.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ext_inst.cpp ${CMAKE_CURRENT_SOURCE_DIR}/extensions.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/id_descriptor.cpp ${CMAKE_CURRENT_SOURCE_DIR}/libspirv.cpp ${CMAKE_CURRENT_SOURCE_DIR}/name_mapper.cpp ${CMAKE_CURRENT_SOURCE_DIR}/opcode.cpp @@ -273,6 +274,9 @@ set(SPIRV_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/print.cpp ${CMAKE_CURRENT_SOURCE_DIR}/software_version.cpp ${CMAKE_CURRENT_SOURCE_DIR}/spirv_endian.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/spirv_fuzzer_options.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/spirv_optimizer_options.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/spirv_reducer_options.cpp ${CMAKE_CURRENT_SOURCE_DIR}/spirv_target_env.cpp ${CMAKE_CURRENT_SOURCE_DIR}/spirv_validator_options.cpp ${CMAKE_CURRENT_SOURCE_DIR}/table.cpp @@ -291,11 +295,10 @@ set(SPIRV_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/val/validate_composites.cpp ${CMAKE_CURRENT_SOURCE_DIR}/val/validate_constants.cpp ${CMAKE_CURRENT_SOURCE_DIR}/val/validate_conversion.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/val/validate_datarules.cpp ${CMAKE_CURRENT_SOURCE_DIR}/val/validate_debug.cpp ${CMAKE_CURRENT_SOURCE_DIR}/val/validate_decorations.cpp ${CMAKE_CURRENT_SOURCE_DIR}/val/validate_derivatives.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/val/validate_ext_inst.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/val/validate_extensions.cpp ${CMAKE_CURRENT_SOURCE_DIR}/val/validate_execution_limitations.cpp ${CMAKE_CURRENT_SOURCE_DIR}/val/validate_function.cpp ${CMAKE_CURRENT_SOURCE_DIR}/val/validate_id.cpp @@ -306,9 +309,13 @@ set(SPIRV_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/val/validate_literals.cpp ${CMAKE_CURRENT_SOURCE_DIR}/val/validate_logicals.cpp ${CMAKE_CURRENT_SOURCE_DIR}/val/validate_memory.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/val/validate_memory_semantics.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/val/validate_misc.cpp ${CMAKE_CURRENT_SOURCE_DIR}/val/validate_mode_setting.cpp ${CMAKE_CURRENT_SOURCE_DIR}/val/validate_non_uniform.cpp ${CMAKE_CURRENT_SOURCE_DIR}/val/validate_primitives.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/val/validate_scopes.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/val/validate_small_type_uses.cpp ${CMAKE_CURRENT_SOURCE_DIR}/val/validate_type.cpp ${CMAKE_CURRENT_SOURCE_DIR}/val/decoration.h ${CMAKE_CURRENT_SOURCE_DIR}/val/basic_block.cpp @@ -338,20 +345,27 @@ set_source_files_properties( ${CMAKE_CURRENT_SOURCE_DIR}/software_version.cpp PROPERTIES OBJECT_DEPENDS "${SPIRV_TOOLS_BUILD_VERSION_INC}") +spvtools_pch(SPIRV_SOURCES pch_source) + add_library(${SPIRV_TOOLS} ${SPIRV_SOURCES}) spvtools_default_compile_options(${SPIRV_TOOLS}) target_include_directories(${SPIRV_TOOLS} - PUBLIC ${spirv-tools_SOURCE_DIR}/include + PUBLIC + $ + $ PRIVATE ${spirv-tools_BINARY_DIR} PRIVATE ${SPIRV_HEADER_INCLUDE_DIR} ) set_property(TARGET ${SPIRV_TOOLS} PROPERTY FOLDER "SPIRV-Tools libraries") spvtools_check_symbol_exports(${SPIRV_TOOLS}) +add_dependencies( ${SPIRV_TOOLS} core_tables enum_string_mapping extinst_tables ) add_library(${SPIRV_TOOLS}-shared SHARED ${SPIRV_SOURCES}) spvtools_default_compile_options(${SPIRV_TOOLS}-shared) target_include_directories(${SPIRV_TOOLS}-shared - PUBLIC ${spirv-tools_SOURCE_DIR}/include + PUBLIC + $ + $ PRIVATE ${spirv-tools_BINARY_DIR} PRIVATE ${SPIRV_HEADER_INCLUDE_DIR} ) @@ -362,10 +376,35 @@ target_compile_definitions(${SPIRV_TOOLS}-shared PRIVATE SPIRV_TOOLS_IMPLEMENTATION PUBLIC SPIRV_TOOLS_SHAREDLIB ) +add_dependencies( ${SPIRV_TOOLS}-shared core_tables enum_string_mapping extinst_tables ) + +if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") + find_library(LIBRT rt) + if(LIBRT) + target_link_libraries(${SPIRV_TOOLS} ${LIBRT}) + target_link_libraries(${SPIRV_TOOLS}-shared ${LIBRT}) + endif() +endif() if(ENABLE_SPIRV_TOOLS_INSTALL) - install(TARGETS ${SPIRV_TOOLS} ${SPIRV_TOOLS}-shared + install(TARGETS ${SPIRV_TOOLS} ${SPIRV_TOOLS}-shared EXPORT ${SPIRV_TOOLS}Targets RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) + export(EXPORT ${SPIRV_TOOLS}Targets FILE ${SPIRV_TOOLS}Target.cmake) + + spvtools_config_package_dir(${SPIRV_TOOLS} PACKAGE_DIR) + install(EXPORT ${SPIRV_TOOLS}Targets FILE ${SPIRV_TOOLS}Target.cmake DESTINATION ${PACKAGE_DIR}) + + # Special config file for root library compared to other libs. + file(WRITE ${CMAKE_BINARY_DIR}/${SPIRV_TOOLS}Config.cmake + "include(\${CMAKE_CURRENT_LIST_DIR}/${SPIRV_TOOLS}Target.cmake)\n" + "set(${SPIRV_TOOLS}_LIBRARIES ${SPIRV_TOOLS})\n" + "get_target_property(${SPIRV_TOOLS}_INCLUDE_DIRS ${SPIRV_TOOLS} INTERFACE_INCLUDE_DIRECTORIES)\n") + install(FILES ${CMAKE_BINARY_DIR}/${SPIRV_TOOLS}Config.cmake DESTINATION ${PACKAGE_DIR}) endif(ENABLE_SPIRV_TOOLS_INSTALL) + +if(MSVC) + # Enable parallel builds across four cores for this lib + add_definitions(/MP4) +endif() diff --git a/third_party/spirv-tools/source/assembly_grammar.cpp b/third_party/spirv-tools/source/assembly_grammar.cpp index 4d98e3dab8..79f18eee39 100644 --- a/third_party/spirv-tools/source/assembly_grammar.cpp +++ b/third_party/spirv-tools/source/assembly_grammar.cpp @@ -154,10 +154,11 @@ const SpecConstantOpcodeEntry kOpSpecConstantOpcodes[] = { CASE(InBoundsAccessChain), CASE(PtrAccessChain), CASE(InBoundsPtrAccessChain), + CASE(CooperativeMatrixLengthNV) }; -// The 59 is determined by counting the opcodes listed in the spec. -static_assert(59 == sizeof(kOpSpecConstantOpcodes)/sizeof(kOpSpecConstantOpcodes[0]), +// The 60 is determined by counting the opcodes listed in the spec. +static_assert(60 == sizeof(kOpSpecConstantOpcodes)/sizeof(kOpSpecConstantOpcodes[0]), "OpSpecConstantOp opcode table is incomplete"); #undef CASE // clang-format on diff --git a/third_party/spirv-tools/source/binary.cpp b/third_party/spirv-tools/source/binary.cpp index 6604d80945..0463061850 100644 --- a/third_party/spirv-tools/source/binary.cpp +++ b/third_party/spirv-tools/source/binary.cpp @@ -123,8 +123,8 @@ class Parser { // returned object will be propagated to the current parse's diagnostic // object. spvtools::DiagnosticStream diagnostic(spv_result_t error) { - return spvtools::DiagnosticStream({0, 0, _.word_index}, consumer_, "", - error); + return spvtools::DiagnosticStream({0, 0, _.instruction_count}, consumer_, + "", error); } // Returns a diagnostic stream object with the default parse error code. @@ -179,6 +179,7 @@ class Parser { num_words(num_words_arg), diagnostic(diagnostic_arg), word_index(0), + instruction_count(0), endian(), requires_endian_conversion(false) { // Temporary storage for parser state within a single instruction. @@ -192,6 +193,7 @@ class Parser { size_t num_words; // Number of words in the module. spv_diagnostic* diagnostic; // Where diagnostics go. size_t word_index; // The current position in words. + size_t instruction_count; // The count of processed instructions spv_endianness_t endian; // The endianness of the binary. // Is the SPIR-V binary in a different endiannes from the host native // endianness? @@ -269,6 +271,8 @@ spv_result_t Parser::parseModule() { } spv_result_t Parser::parseInstruction() { + _.instruction_count++; + // The zero values for all members except for opcode are the // correct initial values. spv_parsed_instruction_t inst = {}; @@ -473,9 +477,22 @@ spv_result_t Parser::parseOperand(size_t inst_offset, assert(SpvOpExtInst == opcode); assert(inst->ext_inst_type != SPV_EXT_INST_TYPE_NONE); spv_ext_inst_desc ext_inst; - if (grammar_.lookupExtInst(inst->ext_inst_type, word, &ext_inst)) - return diagnostic() << "Invalid extended instruction number: " << word; - spvPushOperandTypes(ext_inst->operandTypes, expected_operands); + if (grammar_.lookupExtInst(inst->ext_inst_type, word, &ext_inst) == + SPV_SUCCESS) { + // if we know about this ext inst, push the expected operands + spvPushOperandTypes(ext_inst->operandTypes, expected_operands); + } else { + // if we don't know this extended instruction and the set isn't + // non-semantic, we cannot process further + if (!spvExtInstIsNonSemantic(inst->ext_inst_type)) { + return diagnostic() + << "Invalid extended instruction number: " << word; + } else { + // for non-semantic instruction sets, we know the form of all such + // extended instructions contains a series of IDs as parameters + expected_operands->push_back(SPV_OPERAND_TYPE_VARIABLE_ID); + } + } } break; case SPV_OPERAND_TYPE_SPEC_CONSTANT_OP_NUMBER: { @@ -619,7 +636,12 @@ spv_result_t Parser::parseOperand(size_t inst_offset, case SPV_OPERAND_TYPE_DEBUG_BASE_TYPE_ATTRIBUTE_ENCODING: case SPV_OPERAND_TYPE_DEBUG_COMPOSITE_TYPE: case SPV_OPERAND_TYPE_DEBUG_TYPE_QUALIFIER: - case SPV_OPERAND_TYPE_DEBUG_OPERATION: { + case SPV_OPERAND_TYPE_DEBUG_OPERATION: + case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_BASE_TYPE_ATTRIBUTE_ENCODING: + case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_COMPOSITE_TYPE: + case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_TYPE_QUALIFIER: + case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_OPERATION: + case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_IMPORTED_ENTITY: { // A single word that is a plain enum value. // Map an optional operand type to its corresponding concrete type. @@ -643,6 +665,7 @@ spv_result_t Parser::parseOperand(size_t inst_offset, case SPV_OPERAND_TYPE_OPTIONAL_IMAGE: case SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS: case SPV_OPERAND_TYPE_SELECTION_CONTROL: + case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_INFO_FLAGS: case SPV_OPERAND_TYPE_DEBUG_INFO_FLAGS: { // This operand is a mask. @@ -777,9 +800,10 @@ spv_result_t spvBinaryParse(const spv_const_context context, void* user_data, // TODO(dneto): This probably belongs in text.cpp since that's the only place // that a spv_binary_t value is created. void spvBinaryDestroy(spv_binary binary) { - if (!binary) return; - delete[] binary->code; - delete binary; + if (binary) { + if (binary->code) delete[] binary->code; + delete binary; + } } size_t spv_strnlen_s(const char* str, size_t strsz) { diff --git a/third_party/spirv-tools/source/comp/CMakeLists.txt b/third_party/spirv-tools/source/comp/CMakeLists.txt deleted file mode 100644 index f65f9f670d..0000000000 --- a/third_party/spirv-tools/source/comp/CMakeLists.txt +++ /dev/null @@ -1,52 +0,0 @@ -# Copyright (c) 2017 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -if(SPIRV_BUILD_COMPRESSION) - add_library(SPIRV-Tools-comp - bit_stream.cpp - bit_stream.h - huffman_codec.h - markv_codec.cpp - markv_codec.h - markv.cpp - markv.h - markv_decoder.cpp - markv_decoder.h - markv_encoder.cpp - markv_encoder.h - markv_logger.h - move_to_front.h - move_to_front.cpp) - - spvtools_default_compile_options(SPIRV-Tools-comp) - target_include_directories(SPIRV-Tools-comp - PUBLIC ${spirv-tools_SOURCE_DIR}/include - PUBLIC ${SPIRV_HEADER_INCLUDE_DIR} - PRIVATE ${spirv-tools_BINARY_DIR} - ) - - target_link_libraries(SPIRV-Tools-comp - PUBLIC ${SPIRV_TOOLS}) - - set_property(TARGET SPIRV-Tools-comp PROPERTY FOLDER "SPIRV-Tools libraries") - spvtools_check_symbol_exports(SPIRV-Tools-comp) - - if(ENABLE_SPIRV_TOOLS_INSTALL) - install(TARGETS SPIRV-Tools-comp - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) - endif(ENABLE_SPIRV_TOOLS_INSTALL) - -endif(SPIRV_BUILD_COMPRESSION) diff --git a/third_party/spirv-tools/source/comp/bit_stream.cpp b/third_party/spirv-tools/source/comp/bit_stream.cpp deleted file mode 100644 index a5769e03e4..0000000000 --- a/third_party/spirv-tools/source/comp/bit_stream.cpp +++ /dev/null @@ -1,348 +0,0 @@ -// Copyright (c) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include -#include -#include -#include - -#include "source/comp/bit_stream.h" - -namespace spvtools { -namespace comp { -namespace { - -// Returns if the system is little-endian. Unfortunately only works during -// runtime. -bool IsLittleEndian() { - // This constant value allows the detection of the host machine's endianness. - // Accessing it as an array of bytes is valid due to C++11 section 3.10 - // paragraph 10. - static const uint16_t kFF00 = 0xff00; - return reinterpret_cast(&kFF00)[0] == 0; -} - -// Copies bytes from the given buffer to a uint64_t buffer. -// Motivation: casting uint64_t* to uint8_t* is ok. Casting in the other -// direction is only advisable if uint8_t* is aligned to 64-bit word boundary. -std::vector ToBuffer64(const void* buffer, size_t num_bytes) { - std::vector out; - out.resize((num_bytes + 7) / 8, 0); - memcpy(out.data(), buffer, num_bytes); - return out; -} - -// Copies uint8_t buffer to a uint64_t buffer. -std::vector ToBuffer64(const std::vector& in) { - return ToBuffer64(in.data(), in.size()); -} - -// Returns uint64_t containing the same bits as |val|. -// Type size must be less than 8 bytes. -template -uint64_t ToU64(T val) { - static_assert(sizeof(T) <= 8, "Type size too big"); - uint64_t val64 = 0; - std::memcpy(&val64, &val, sizeof(T)); - return val64; -} - -// Returns value of type T containing the same bits as |val64|. -// Type size must be less than 8 bytes. Upper (unused) bits of |val64| must be -// zero (irrelevant, but is checked with assertion). -template -T FromU64(uint64_t val64) { - assert(sizeof(T) == 8 || (val64 >> (sizeof(T) * 8)) == 0); - static_assert(sizeof(T) <= 8, "Type size too big"); - T val = 0; - std::memcpy(&val, &val64, sizeof(T)); - return val; -} - -// Writes bits from |val| to |writer| in chunks of size |chunk_length|. -// Signal bit is used to signal if the reader should expect another chunk: -// 0 - no more chunks to follow -// 1 - more chunks to follow -// If number of written bits reaches |max_payload| last chunk is truncated. -void WriteVariableWidthInternal(BitWriterInterface* writer, uint64_t val, - size_t chunk_length, size_t max_payload) { - assert(chunk_length > 0); - assert(chunk_length < max_payload); - assert(max_payload == 64 || (val >> max_payload) == 0); - - if (val == 0) { - // Split in two writes for more readable logging. - writer->WriteBits(0, chunk_length); - writer->WriteBits(0, 1); - return; - } - - size_t payload_written = 0; - - while (val) { - if (payload_written + chunk_length >= max_payload) { - // This has to be the last chunk. - // There is no need for the signal bit and the chunk can be truncated. - const size_t left_to_write = max_payload - payload_written; - assert((val >> left_to_write) == 0); - writer->WriteBits(val, left_to_write); - break; - } - - writer->WriteBits(val, chunk_length); - payload_written += chunk_length; - val = val >> chunk_length; - - // Write a single bit to signal if there is more to come. - writer->WriteBits(val ? 1 : 0, 1); - } -} - -// Reads data written with WriteVariableWidthInternal. |chunk_length| and -// |max_payload| should be identical to those used to write the data. -// Returns false if the stream ends prematurely. -bool ReadVariableWidthInternal(BitReaderInterface* reader, uint64_t* val, - size_t chunk_length, size_t max_payload) { - assert(chunk_length > 0); - assert(chunk_length <= max_payload); - size_t payload_read = 0; - - while (payload_read + chunk_length < max_payload) { - uint64_t bits = 0; - if (reader->ReadBits(&bits, chunk_length) != chunk_length) return false; - - *val |= bits << payload_read; - payload_read += chunk_length; - - uint64_t more_to_come = 0; - if (reader->ReadBits(&more_to_come, 1) != 1) return false; - - if (!more_to_come) { - return true; - } - } - - // Need to read the last chunk which may be truncated. No signal bit follows. - uint64_t bits = 0; - const size_t left_to_read = max_payload - payload_read; - if (reader->ReadBits(&bits, left_to_read) != left_to_read) return false; - - *val |= bits << payload_read; - return true; -} - -// Calls WriteVariableWidthInternal with the right max_payload argument. -template -void WriteVariableWidthUnsigned(BitWriterInterface* writer, T val, - size_t chunk_length) { - static_assert(std::is_unsigned::value, "Type must be unsigned"); - static_assert(std::is_integral::value, "Type must be integral"); - WriteVariableWidthInternal(writer, val, chunk_length, sizeof(T) * 8); -} - -// Calls ReadVariableWidthInternal with the right max_payload argument. -template -bool ReadVariableWidthUnsigned(BitReaderInterface* reader, T* val, - size_t chunk_length) { - static_assert(std::is_unsigned::value, "Type must be unsigned"); - static_assert(std::is_integral::value, "Type must be integral"); - uint64_t val64 = 0; - if (!ReadVariableWidthInternal(reader, &val64, chunk_length, sizeof(T) * 8)) - return false; - *val = static_cast(val64); - assert(*val == val64); - return true; -} - -// Encodes signed |val| to an unsigned value and calls -// WriteVariableWidthInternal with the right max_payload argument. -template -void WriteVariableWidthSigned(BitWriterInterface* writer, T val, - size_t chunk_length, size_t zigzag_exponent) { - static_assert(std::is_signed::value, "Type must be signed"); - static_assert(std::is_integral::value, "Type must be integral"); - WriteVariableWidthInternal(writer, EncodeZigZag(val, zigzag_exponent), - chunk_length, sizeof(T) * 8); -} - -// Calls ReadVariableWidthInternal with the right max_payload argument -// and decodes the value. -template -bool ReadVariableWidthSigned(BitReaderInterface* reader, T* val, - size_t chunk_length, size_t zigzag_exponent) { - static_assert(std::is_signed::value, "Type must be signed"); - static_assert(std::is_integral::value, "Type must be integral"); - uint64_t encoded = 0; - if (!ReadVariableWidthInternal(reader, &encoded, chunk_length, sizeof(T) * 8)) - return false; - - const int64_t decoded = DecodeZigZag(encoded, zigzag_exponent); - - *val = static_cast(decoded); - assert(*val == decoded); - return true; -} - -} // namespace - -void BitWriterInterface::WriteVariableWidthU64(uint64_t val, - size_t chunk_length) { - WriteVariableWidthUnsigned(this, val, chunk_length); -} - -void BitWriterInterface::WriteVariableWidthU32(uint32_t val, - size_t chunk_length) { - WriteVariableWidthUnsigned(this, val, chunk_length); -} - -void BitWriterInterface::WriteVariableWidthU16(uint16_t val, - size_t chunk_length) { - WriteVariableWidthUnsigned(this, val, chunk_length); -} - -void BitWriterInterface::WriteVariableWidthS64(int64_t val, size_t chunk_length, - size_t zigzag_exponent) { - WriteVariableWidthSigned(this, val, chunk_length, zigzag_exponent); -} - -BitWriterWord64::BitWriterWord64(size_t reserve_bits) : end_(0) { - buffer_.reserve(NumBitsToNumWords<64>(reserve_bits)); -} - -void BitWriterWord64::WriteBits(uint64_t bits, size_t num_bits) { - // Check that |bits| and |num_bits| are valid and consistent. - assert(num_bits <= 64); - const bool is_little_endian = IsLittleEndian(); - assert(is_little_endian && "Big-endian architecture support not implemented"); - if (!is_little_endian) return; - - if (num_bits == 0) return; - - bits = GetLowerBits(bits, num_bits); - - EmitSequence(bits, num_bits); - - // Offset from the start of the current word. - const size_t offset = end_ % 64; - - if (offset == 0) { - // If no offset, simply add |bits| as a new word to the buffer_. - buffer_.push_back(bits); - } else { - // Shift bits and add them to the current word after offset. - const uint64_t first_word = bits << offset; - buffer_.back() |= first_word; - - // If we don't overflow to the next word, there is nothing more to do. - - if (offset + num_bits > 64) { - // We overflow to the next word. - const uint64_t second_word = bits >> (64 - offset); - // Add remaining bits as a new word to buffer_. - buffer_.push_back(second_word); - } - } - - // Move end_ into position for next write. - end_ += num_bits; - assert(buffer_.size() * 64 >= end_); -} - -bool BitReaderInterface::ReadVariableWidthU64(uint64_t* val, - size_t chunk_length) { - return ReadVariableWidthUnsigned(this, val, chunk_length); -} - -bool BitReaderInterface::ReadVariableWidthU32(uint32_t* val, - size_t chunk_length) { - return ReadVariableWidthUnsigned(this, val, chunk_length); -} - -bool BitReaderInterface::ReadVariableWidthU16(uint16_t* val, - size_t chunk_length) { - return ReadVariableWidthUnsigned(this, val, chunk_length); -} - -bool BitReaderInterface::ReadVariableWidthS64(int64_t* val, size_t chunk_length, - size_t zigzag_exponent) { - return ReadVariableWidthSigned(this, val, chunk_length, zigzag_exponent); -} - -BitReaderWord64::BitReaderWord64(std::vector&& buffer) - : buffer_(std::move(buffer)), pos_(0) {} - -BitReaderWord64::BitReaderWord64(const std::vector& buffer) - : buffer_(ToBuffer64(buffer)), pos_(0) {} - -BitReaderWord64::BitReaderWord64(const void* buffer, size_t num_bytes) - : buffer_(ToBuffer64(buffer, num_bytes)), pos_(0) {} - -size_t BitReaderWord64::ReadBits(uint64_t* bits, size_t num_bits) { - assert(num_bits <= 64); - const bool is_little_endian = IsLittleEndian(); - assert(is_little_endian && "Big-endian architecture support not implemented"); - if (!is_little_endian) return 0; - - if (ReachedEnd()) return 0; - - // Index of the current word. - const size_t index = pos_ / 64; - - // Bit position in the current word where we start reading. - const size_t offset = pos_ % 64; - - // Read all bits from the current word (it might be too much, but - // excessive bits will be removed later). - *bits = buffer_[index] >> offset; - - const size_t num_read_from_first_word = std::min(64 - offset, num_bits); - pos_ += num_read_from_first_word; - - if (pos_ >= buffer_.size() * 64) { - // Reached end of buffer_. - EmitSequence(*bits, num_read_from_first_word); - return num_read_from_first_word; - } - - if (offset + num_bits > 64) { - // Requested |num_bits| overflows to next word. - // Write all bits from the beginning of next word to *bits after offset. - *bits |= buffer_[index + 1] << (64 - offset); - pos_ += offset + num_bits - 64; - } - - // We likely have written more bits than requested. Clear excessive bits. - *bits = GetLowerBits(*bits, num_bits); - EmitSequence(*bits, num_bits); - return num_bits; -} - -bool BitReaderWord64::ReachedEnd() const { return pos_ >= buffer_.size() * 64; } - -bool BitReaderWord64::OnlyZeroesLeft() const { - if (ReachedEnd()) return true; - - const size_t index = pos_ / 64; - if (index < buffer_.size() - 1) return false; - - assert(index == buffer_.size() - 1); - - const size_t offset = pos_ % 64; - const uint64_t remaining_bits = buffer_[index] >> offset; - return !remaining_bits; -} - -} // namespace comp -} // namespace spvtools diff --git a/third_party/spirv-tools/source/comp/bit_stream.h b/third_party/spirv-tools/source/comp/bit_stream.h deleted file mode 100644 index 5f82344d6a..0000000000 --- a/third_party/spirv-tools/source/comp/bit_stream.h +++ /dev/null @@ -1,280 +0,0 @@ -// Copyright (c) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Contains utils for reading, writing and debug printing bit streams. - -#ifndef SOURCE_COMP_BIT_STREAM_H_ -#define SOURCE_COMP_BIT_STREAM_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace spvtools { -namespace comp { - -// Terminology: -// Bits - usually used for a uint64 word, first bit is the lowest. -// Stream - std::string of '0' and '1', read left-to-right, -// i.e. first bit is at the front and not at the end as in -// std::bitset::to_string(). -// Bitset - std::bitset corresponding to uint64 bits and to reverse(stream). - -// Converts number of bits to a respective number of chunks of size N. -// For example NumBitsToNumWords<8> returns how many bytes are needed to store -// |num_bits|. -template -inline size_t NumBitsToNumWords(size_t num_bits) { - return (num_bits + (N - 1)) / N; -} - -// Returns value of the same type as |in|, where all but the first |num_bits| -// are set to zero. -template -inline T GetLowerBits(T in, size_t num_bits) { - return sizeof(T) * 8 == num_bits ? in : in & T((T(1) << num_bits) - T(1)); -} - -// Encodes signed integer as unsigned. This is a generalized version of -// EncodeZigZag, designed to favor small positive numbers. -// Values are transformed in blocks of 2^|block_exponent|. -// If |block_exponent| is zero, then this degenerates into normal EncodeZigZag. -// Example when |block_exponent| is 1 (return value is the index): -// 0, 1, -1, -2, 2, 3, -3, -4, 4, 5, -5, -6, 6, 7, -7, -8 -// Example when |block_exponent| is 2: -// 0, 1, 2, 3, -1, -2, -3, -4, 4, 5, 6, 7, -5, -6, -7, -8 -inline uint64_t EncodeZigZag(int64_t val, size_t block_exponent) { - assert(block_exponent < 64); - const uint64_t uval = static_cast(val >= 0 ? val : -val - 1); - const uint64_t block_num = - ((uval >> block_exponent) << 1) + (val >= 0 ? 0 : 1); - const uint64_t pos = GetLowerBits(uval, block_exponent); - return (block_num << block_exponent) + pos; -} - -// Decodes signed integer encoded with EncodeZigZag. |block_exponent| must be -// the same. -inline int64_t DecodeZigZag(uint64_t val, size_t block_exponent) { - assert(block_exponent < 64); - const uint64_t block_num = val >> block_exponent; - const uint64_t pos = GetLowerBits(val, block_exponent); - if (block_num & 1) { - // Negative. - return -1LL - ((block_num >> 1) << block_exponent) - pos; - } else { - // Positive. - return ((block_num >> 1) << block_exponent) + pos; - } -} - -// Converts first |num_bits| stored in uint64 to a left-to-right stream of bits. -inline std::string BitsToStream(uint64_t bits, size_t num_bits = 64) { - std::bitset<64> bitset(bits); - std::string str = bitset.to_string().substr(64 - num_bits); - std::reverse(str.begin(), str.end()); - return str; -} - -// Base class for writing sequences of bits. -class BitWriterInterface { - public: - BitWriterInterface() = default; - virtual ~BitWriterInterface() = default; - - // Writes lower |num_bits| in |bits| to the stream. - // |num_bits| must be no greater than 64. - virtual void WriteBits(uint64_t bits, size_t num_bits) = 0; - - // Writes bits from value of type |T| to the stream. No encoding is done. - // Always writes 8 * sizeof(T) bits. - template - void WriteUnencoded(T val) { - static_assert(sizeof(T) <= 64, "Type size too large"); - uint64_t bits = 0; - memcpy(&bits, &val, sizeof(T)); - WriteBits(bits, sizeof(T) * 8); - } - - // Writes |val| in chunks of size |chunk_length| followed by a signal bit: - // 0 - no more chunks to follow - // 1 - more chunks to follow - // for example 255 is encoded into 1111 1 1111 0 for chunk length 4. - // The last chunk can be truncated and signal bit omitted, if the entire - // payload (for example 16 bit for uint16_t has already been written). - void WriteVariableWidthU64(uint64_t val, size_t chunk_length); - void WriteVariableWidthU32(uint32_t val, size_t chunk_length); - void WriteVariableWidthU16(uint16_t val, size_t chunk_length); - void WriteVariableWidthS64(int64_t val, size_t chunk_length, - size_t zigzag_exponent); - - // Returns number of bits written. - virtual size_t GetNumBits() const = 0; - - // Provides direct access to the buffer data if implemented. - virtual const uint8_t* GetData() const { return nullptr; } - - // Returns buffer size in bytes. - size_t GetDataSizeBytes() const { return NumBitsToNumWords<8>(GetNumBits()); } - - // Generates and returns byte array containing written bits. - virtual std::vector GetDataCopy() const = 0; - - BitWriterInterface(const BitWriterInterface&) = delete; - BitWriterInterface& operator=(const BitWriterInterface&) = delete; -}; - -// This class is an implementation of BitWriterInterface, using -// std::vector to store written bits. -class BitWriterWord64 : public BitWriterInterface { - public: - explicit BitWriterWord64(size_t reserve_bits = 64); - - void WriteBits(uint64_t bits, size_t num_bits) override; - - size_t GetNumBits() const override { return end_; } - - const uint8_t* GetData() const override { - return reinterpret_cast(buffer_.data()); - } - - std::vector GetDataCopy() const override { - return std::vector(GetData(), GetData() + GetDataSizeBytes()); - } - - // Sets callback to emit bit sequences after every write. - void SetCallback(std::function callback) { - callback_ = callback; - } - - protected: - // Sends string generated from arguments to callback_ if defined. - void EmitSequence(uint64_t bits, size_t num_bits) const { - if (callback_) callback_(BitsToStream(bits, num_bits)); - } - - private: - std::vector buffer_; - // Total number of bits written so far. Named 'end' as analogy to std::end(). - size_t end_; - - // If not null, the writer will use the callback to emit the written bit - // sequence as a string of '0' and '1'. - std::function callback_; -}; - -// Base class for reading sequences of bits. -class BitReaderInterface { - public: - BitReaderInterface() {} - virtual ~BitReaderInterface() {} - - // Reads |num_bits| from the stream, stores them in |bits|. - // Returns number of read bits. |num_bits| must be no greater than 64. - virtual size_t ReadBits(uint64_t* bits, size_t num_bits) = 0; - - // Reads 8 * sizeof(T) bits and stores them in |val|. - template - bool ReadUnencoded(T* val) { - static_assert(sizeof(T) <= 64, "Type size too large"); - uint64_t bits = 0; - const size_t num_read = ReadBits(&bits, sizeof(T) * 8); - if (num_read != sizeof(T) * 8) return false; - memcpy(val, &bits, sizeof(T)); - return true; - } - - // Returns number of bits already read. - virtual size_t GetNumReadBits() const = 0; - - // These two functions define 'hard' and 'soft' EOF. - // - // Returns true if the end of the buffer was reached. - virtual bool ReachedEnd() const = 0; - // Returns true if we reached the end of the buffer or are nearing it and only - // zero bits are left to read. Implementations of this function are allowed to - // commit a "false negative" error if the end of the buffer was not reached, - // i.e. it can return false even if indeed only zeroes are left. - // It is assumed that the consumer expects that - // the buffer stream ends with padding zeroes, and would accept this as a - // 'soft' EOF. Implementations of this class do not necessarily need to - // implement this, default behavior can simply delegate to ReachedEnd(). - virtual bool OnlyZeroesLeft() const { return ReachedEnd(); } - - // Reads value encoded with WriteVariableWidthXXX (see BitWriterInterface). - // Reader and writer must use the same |chunk_length| and variable type. - // Returns true on success, false if the bit stream ends prematurely. - bool ReadVariableWidthU64(uint64_t* val, size_t chunk_length); - bool ReadVariableWidthU32(uint32_t* val, size_t chunk_length); - bool ReadVariableWidthU16(uint16_t* val, size_t chunk_length); - bool ReadVariableWidthS64(int64_t* val, size_t chunk_length, - size_t zigzag_exponent); - - BitReaderInterface(const BitReaderInterface&) = delete; - BitReaderInterface& operator=(const BitReaderInterface&) = delete; -}; - -// This class is an implementation of BitReaderInterface which accepts both -// uint8_t and uint64_t buffers as input. uint64_t buffers are consumed and -// owned. uint8_t buffers are copied. -class BitReaderWord64 : public BitReaderInterface { - public: - // Consumes and owns the buffer. - explicit BitReaderWord64(std::vector&& buffer); - - // Copies the buffer and casts it to uint64. - // Consuming the original buffer and casting it to uint64 is difficult, - // as it would potentially cause data misalignment and poor performance. - explicit BitReaderWord64(const std::vector& buffer); - BitReaderWord64(const void* buffer, size_t num_bytes); - - size_t ReadBits(uint64_t* bits, size_t num_bits) override; - - size_t GetNumReadBits() const override { return pos_; } - - bool ReachedEnd() const override; - bool OnlyZeroesLeft() const override; - - BitReaderWord64() = delete; - - // Sets callback to emit bit sequences after every read. - void SetCallback(std::function callback) { - callback_ = callback; - } - - protected: - // Sends string generated from arguments to callback_ if defined. - void EmitSequence(uint64_t bits, size_t num_bits) const { - if (callback_) callback_(BitsToStream(bits, num_bits)); - } - - private: - const std::vector buffer_; - size_t pos_; - - // If not null, the reader will use the callback to emit the read bit - // sequence as a string of '0' and '1'. - std::function callback_; -}; - -} // namespace comp -} // namespace spvtools - -#endif // SOURCE_COMP_BIT_STREAM_H_ diff --git a/third_party/spirv-tools/source/comp/huffman_codec.h b/third_party/spirv-tools/source/comp/huffman_codec.h deleted file mode 100644 index 1660216144..0000000000 --- a/third_party/spirv-tools/source/comp/huffman_codec.h +++ /dev/null @@ -1,389 +0,0 @@ -// Copyright (c) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Contains utils for reading, writing and debug printing bit streams. - -#ifndef SOURCE_COMP_HUFFMAN_CODEC_H_ -#define SOURCE_COMP_HUFFMAN_CODEC_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace spvtools { -namespace comp { - -// Used to generate and apply a Huffman coding scheme. -// |Val| is the type of variable being encoded (for example a string or a -// literal). -template -class HuffmanCodec { - public: - // Huffman tree node. - struct Node { - Node() {} - - // Creates Node from serialization leaving weight and id undefined. - Node(const Val& in_value, uint32_t in_left, uint32_t in_right) - : value(in_value), left(in_left), right(in_right) {} - - Val value = Val(); - uint32_t weight = 0; - // Ids are issued sequentially starting from 1. Ids are used as an ordering - // tie-breaker, to make sure that the ordering (and resulting coding scheme) - // are consistent accross multiple platforms. - uint32_t id = 0; - // Handles of children. - uint32_t left = 0; - uint32_t right = 0; - }; - - // Creates Huffman codec from a histogramm. - // Histogramm counts must not be zero. - explicit HuffmanCodec(const std::map& hist) { - if (hist.empty()) return; - - // Heuristic estimate. - nodes_.reserve(3 * hist.size()); - - // Create NIL. - CreateNode(); - - // The queue is sorted in ascending order by weight (or by node id if - // weights are equal). - std::vector queue_vector; - queue_vector.reserve(hist.size()); - std::priority_queue, - std::function> - queue(std::bind(&HuffmanCodec::LeftIsBigger, this, - std::placeholders::_1, std::placeholders::_2), - std::move(queue_vector)); - - // Put all leaves in the queue. - for (const auto& pair : hist) { - const uint32_t node = CreateNode(); - MutableValueOf(node) = pair.first; - MutableWeightOf(node) = pair.second; - assert(WeightOf(node)); - queue.push(node); - } - - // Form the tree by combining two subtrees with the least weight, - // and pushing the root of the new tree in the queue. - while (true) { - // We push a node at the end of each iteration, so the queue is never - // supposed to be empty at this point, unless there are no leaves, but - // that case was already handled. - assert(!queue.empty()); - const uint32_t right = queue.top(); - queue.pop(); - - // If the queue is empty at this point, then the last node is - // the root of the complete Huffman tree. - if (queue.empty()) { - root_ = right; - break; - } - - const uint32_t left = queue.top(); - queue.pop(); - - // Combine left and right into a new tree and push it into the queue. - const uint32_t parent = CreateNode(); - MutableWeightOf(parent) = WeightOf(right) + WeightOf(left); - MutableLeftOf(parent) = left; - MutableRightOf(parent) = right; - queue.push(parent); - } - - // Traverse the tree and form encoding table. - CreateEncodingTable(); - } - - // Creates Huffman codec from saved tree structure. - // |nodes| is the list of nodes of the tree, nodes[0] being NIL. - // |root_handle| is the index of the root node. - HuffmanCodec(uint32_t root_handle, std::vector&& nodes) { - nodes_ = std::move(nodes); - assert(!nodes_.empty()); - assert(root_handle > 0 && root_handle < nodes_.size()); - assert(!LeftOf(0) && !RightOf(0)); - - root_ = root_handle; - - // Traverse the tree and form encoding table. - CreateEncodingTable(); - } - - // Serializes the codec in the following text format: - // (, { - // {0, 0, 0}, - // {val1, left1, right1}, - // {val2, left2, right2}, - // ... - // }) - std::string SerializeToText(int indent_num_whitespaces) const { - const bool value_is_text = std::is_same::value; - - const std::string indent1 = std::string(indent_num_whitespaces, ' '); - const std::string indent2 = std::string(indent_num_whitespaces + 2, ' '); - - std::stringstream code; - code << "(" << root_ << ", {\n"; - - for (const Node& node : nodes_) { - code << indent2 << "{"; - if (value_is_text) code << "\""; - code << node.value; - if (value_is_text) code << "\""; - code << ", " << node.left << ", " << node.right << "},\n"; - } - - code << indent1 << "})"; - - return code.str(); - } - - // Prints the Huffman tree in the following format: - // w------w------'x' - // w------'y' - // Where w stands for the weight of the node. - // Right tree branches appear above left branches. Taking the right path - // adds 1 to the code, taking the left adds 0. - void PrintTree(std::ostream& out) const { PrintTreeInternal(out, root_, 0); } - - // Traverses the tree and prints the Huffman table: value, code - // and optionally node weight for every leaf. - void PrintTable(std::ostream& out, bool print_weights = true) { - std::queue> queue; - queue.emplace(root_, ""); - - while (!queue.empty()) { - const uint32_t node = queue.front().first; - const std::string code = queue.front().second; - queue.pop(); - if (!RightOf(node) && !LeftOf(node)) { - out << ValueOf(node); - if (print_weights) out << " " << WeightOf(node); - out << " " << code << std::endl; - } else { - if (LeftOf(node)) queue.emplace(LeftOf(node), code + "0"); - - if (RightOf(node)) queue.emplace(RightOf(node), code + "1"); - } - } - } - - // Returns the Huffman table. The table was built at at construction time, - // this function just returns a const reference. - const std::unordered_map>& GetEncodingTable() - const { - return encoding_table_; - } - - // Encodes |val| and stores its Huffman code in the lower |num_bits| of - // |bits|. Returns false of |val| is not in the Huffman table. - bool Encode(const Val& val, uint64_t* bits, size_t* num_bits) const { - auto it = encoding_table_.find(val); - if (it == encoding_table_.end()) return false; - *bits = it->second.first; - *num_bits = it->second.second; - return true; - } - - // Reads bits one-by-one using callback |read_bit| until a match is found. - // Matching value is stored in |val|. Returns false if |read_bit| terminates - // before a code was mathced. - // |read_bit| has type bool func(bool* bit). When called, the next bit is - // stored in |bit|. |read_bit| returns false if the stream terminates - // prematurely. - bool DecodeFromStream(const std::function& read_bit, - Val* val) const { - uint32_t node = root_; - while (true) { - assert(node); - - if (!RightOf(node) && !LeftOf(node)) { - *val = ValueOf(node); - return true; - } - - bool go_right; - if (!read_bit(&go_right)) return false; - - if (go_right) - node = RightOf(node); - else - node = LeftOf(node); - } - - assert(0); - return false; - } - - private: - // Returns value of the node referenced by |handle|. - Val ValueOf(uint32_t node) const { return nodes_.at(node).value; } - - // Returns left child of |node|. - uint32_t LeftOf(uint32_t node) const { return nodes_.at(node).left; } - - // Returns right child of |node|. - uint32_t RightOf(uint32_t node) const { return nodes_.at(node).right; } - - // Returns weight of |node|. - uint32_t WeightOf(uint32_t node) const { return nodes_.at(node).weight; } - - // Returns id of |node|. - uint32_t IdOf(uint32_t node) const { return nodes_.at(node).id; } - - // Returns mutable reference to value of |node|. - Val& MutableValueOf(uint32_t node) { - assert(node); - return nodes_.at(node).value; - } - - // Returns mutable reference to handle of left child of |node|. - uint32_t& MutableLeftOf(uint32_t node) { - assert(node); - return nodes_.at(node).left; - } - - // Returns mutable reference to handle of right child of |node|. - uint32_t& MutableRightOf(uint32_t node) { - assert(node); - return nodes_.at(node).right; - } - - // Returns mutable reference to weight of |node|. - uint32_t& MutableWeightOf(uint32_t node) { return nodes_.at(node).weight; } - - // Returns mutable reference to id of |node|. - uint32_t& MutableIdOf(uint32_t node) { return nodes_.at(node).id; } - - // Returns true if |left| has bigger weight than |right|. Node ids are - // used as tie-breaker. - bool LeftIsBigger(uint32_t left, uint32_t right) const { - if (WeightOf(left) == WeightOf(right)) { - assert(IdOf(left) != IdOf(right)); - return IdOf(left) > IdOf(right); - } - return WeightOf(left) > WeightOf(right); - } - - // Prints subtree (helper function used by PrintTree). - void PrintTreeInternal(std::ostream& out, uint32_t node, size_t depth) const { - if (!node) return; - - const size_t kTextFieldWidth = 7; - - if (!RightOf(node) && !LeftOf(node)) { - out << ValueOf(node) << std::endl; - } else { - if (RightOf(node)) { - std::stringstream label; - label << std::setfill('-') << std::left << std::setw(kTextFieldWidth) - << WeightOf(RightOf(node)); - out << label.str(); - PrintTreeInternal(out, RightOf(node), depth + 1); - } - - if (LeftOf(node)) { - out << std::string(depth * kTextFieldWidth, ' '); - std::stringstream label; - label << std::setfill('-') << std::left << std::setw(kTextFieldWidth) - << WeightOf(LeftOf(node)); - out << label.str(); - PrintTreeInternal(out, LeftOf(node), depth + 1); - } - } - } - - // Traverses the Huffman tree and saves paths to the leaves as bit - // sequences to encoding_table_. - void CreateEncodingTable() { - struct Context { - Context(uint32_t in_node, uint64_t in_bits, size_t in_depth) - : node(in_node), bits(in_bits), depth(in_depth) {} - uint32_t node; - // Huffman tree depth cannot exceed 64 as histogramm counts are expected - // to be positive and limited by numeric_limits::max(). - // For practical applications tree depth would be much smaller than 64. - uint64_t bits; - size_t depth; - }; - - std::queue queue; - queue.emplace(root_, 0, 0); - - while (!queue.empty()) { - const Context& context = queue.front(); - const uint32_t node = context.node; - const uint64_t bits = context.bits; - const size_t depth = context.depth; - queue.pop(); - - if (!RightOf(node) && !LeftOf(node)) { - auto insertion_result = encoding_table_.emplace( - ValueOf(node), std::pair(bits, depth)); - assert(insertion_result.second); - (void)insertion_result; - } else { - if (LeftOf(node)) queue.emplace(LeftOf(node), bits, depth + 1); - - if (RightOf(node)) - queue.emplace(RightOf(node), bits | (1ULL << depth), depth + 1); - } - } - } - - // Creates new Huffman tree node and stores it in the deleter array. - uint32_t CreateNode() { - const uint32_t handle = static_cast(nodes_.size()); - nodes_.emplace_back(Node()); - nodes_.back().id = next_node_id_++; - return handle; - } - - // Huffman tree root handle. - uint32_t root_ = 0; - - // Huffman tree deleter. - std::vector nodes_; - - // Encoding table value -> {bits, num_bits}. - // Huffman codes are expected to never exceed 64 bit length (this is in fact - // impossible if frequencies are stored as uint32_t). - std::unordered_map> encoding_table_; - - // Next node id issued by CreateNode(); - uint32_t next_node_id_ = 1; -}; - -} // namespace comp -} // namespace spvtools - -#endif // SOURCE_COMP_HUFFMAN_CODEC_H_ diff --git a/third_party/spirv-tools/source/comp/markv.cpp b/third_party/spirv-tools/source/comp/markv.cpp deleted file mode 100644 index 736bc51ba2..0000000000 --- a/third_party/spirv-tools/source/comp/markv.cpp +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright (c) 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/comp/markv.h" - -#include "source/comp/markv_decoder.h" -#include "source/comp/markv_encoder.h" - -namespace spvtools { -namespace comp { -namespace { - -spv_result_t EncodeHeader(void* user_data, spv_endianness_t endian, - uint32_t magic, uint32_t version, uint32_t generator, - uint32_t id_bound, uint32_t schema) { - MarkvEncoder* encoder = reinterpret_cast(user_data); - return encoder->EncodeHeader(endian, magic, version, generator, id_bound, - schema); -} - -spv_result_t EncodeInstruction(void* user_data, - const spv_parsed_instruction_t* inst) { - MarkvEncoder* encoder = reinterpret_cast(user_data); - return encoder->EncodeInstruction(*inst); -} - -} // namespace - -spv_result_t SpirvToMarkv( - spv_const_context context, const std::vector& spirv, - const MarkvCodecOptions& options, const MarkvModel& markv_model, - MessageConsumer message_consumer, MarkvLogConsumer log_consumer, - MarkvDebugConsumer debug_consumer, std::vector* markv) { - spv_context_t hijack_context = *context; - SetContextMessageConsumer(&hijack_context, message_consumer); - - spv_validator_options validator_options = - MarkvDecoder::GetValidatorOptions(options); - if (validator_options) { - spv_const_binary_t spirv_binary = {spirv.data(), spirv.size()}; - const spv_result_t result = spvValidateWithOptions( - &hijack_context, validator_options, &spirv_binary, nullptr); - if (result != SPV_SUCCESS) return result; - } - - MarkvEncoder encoder(&hijack_context, options, &markv_model); - - spv_position_t position = {}; - if (log_consumer || debug_consumer) { - encoder.CreateLogger(log_consumer, debug_consumer); - - spv_text text = nullptr; - if (spvBinaryToText(&hijack_context, spirv.data(), spirv.size(), - SPV_BINARY_TO_TEXT_OPTION_NO_HEADER, &text, - nullptr) != SPV_SUCCESS) { - return DiagnosticStream(position, hijack_context.consumer, "", - SPV_ERROR_INVALID_BINARY) - << "Failed to disassemble SPIR-V binary."; - } - assert(text); - encoder.SetDisassembly(std::string(text->str, text->length)); - spvTextDestroy(text); - } - - if (spvBinaryParse(&hijack_context, &encoder, spirv.data(), spirv.size(), - EncodeHeader, EncodeInstruction, nullptr) != SPV_SUCCESS) { - return DiagnosticStream(position, hijack_context.consumer, "", - SPV_ERROR_INVALID_BINARY) - << "Unable to encode to MARK-V."; - } - - *markv = encoder.GetMarkvBinary(); - return SPV_SUCCESS; -} - -spv_result_t MarkvToSpirv( - spv_const_context context, const std::vector& markv, - const MarkvCodecOptions& options, const MarkvModel& markv_model, - MessageConsumer message_consumer, MarkvLogConsumer log_consumer, - MarkvDebugConsumer debug_consumer, std::vector* spirv) { - spv_position_t position = {}; - spv_context_t hijack_context = *context; - SetContextMessageConsumer(&hijack_context, message_consumer); - - MarkvDecoder decoder(&hijack_context, markv, options, &markv_model); - - if (log_consumer || debug_consumer) - decoder.CreateLogger(log_consumer, debug_consumer); - - if (decoder.DecodeModule(spirv) != SPV_SUCCESS) { - return DiagnosticStream(position, hijack_context.consumer, "", - SPV_ERROR_INVALID_BINARY) - << "Unable to decode MARK-V."; - } - - assert(!spirv->empty()); - return SPV_SUCCESS; -} - -} // namespace comp -} // namespace spvtools diff --git a/third_party/spirv-tools/source/comp/markv.h b/third_party/spirv-tools/source/comp/markv.h deleted file mode 100644 index 587086f912..0000000000 --- a/third_party/spirv-tools/source/comp/markv.h +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright (c) 2018 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. - -// MARK-V is a compression format for SPIR-V binaries. It strips away -// non-essential information (such as result ids which can be regenerated) and -// uses various bit reduction techiniques to reduce the size of the binary and -// make it more similar to other compressed SPIR-V files to further improve -// compression of the dataset. - -#ifndef SOURCE_COMP_MARKV_H_ -#define SOURCE_COMP_MARKV_H_ - -#include "spirv-tools/libspirv.hpp" - -namespace spvtools { -namespace comp { - -class MarkvModel; - -struct MarkvCodecOptions { - bool validate_spirv_binary = false; -}; - -// Debug callback. Called once per instruction. -// |words| is instruction SPIR-V words. -// |bits| is a textual representation of the MARK-V bit sequence used to encode -// the instruction (char '0' for 0, char '1' for 1). -// |comment| contains all logs generated while processing the instruction. -using MarkvDebugConsumer = - std::function& words, - const std::string& bits, const std::string& comment)>; - -// Logging callback. Called often (if decoder reads a single bit, the log -// consumer will receive 1 character string with that bit). -// This callback is more suitable for continous output than MarkvDebugConsumer, -// for example if the codec crashes it would allow to pinpoint on which operand -// or bit the crash happened. -// |snippet| could be any atomic fragment of text logged by the codec. It can -// contain a paragraph of text with newlines, or can be just one character. -using MarkvLogConsumer = std::function; - -// Encodes the given SPIR-V binary to MARK-V binary. -// |log_consumer| is optional (pass MarkvLogConsumer() to disable). -// |debug_consumer| is optional (pass MarkvDebugConsumer() to disable). -spv_result_t SpirvToMarkv( - spv_const_context context, const std::vector& spirv, - const MarkvCodecOptions& options, const MarkvModel& markv_model, - MessageConsumer message_consumer, MarkvLogConsumer log_consumer, - MarkvDebugConsumer debug_consumer, std::vector* markv); - -// Decodes a SPIR-V binary from the given MARK-V binary. -// |log_consumer| is optional (pass MarkvLogConsumer() to disable). -// |debug_consumer| is optional (pass MarkvDebugConsumer() to disable). -spv_result_t MarkvToSpirv( - spv_const_context context, const std::vector& markv, - const MarkvCodecOptions& options, const MarkvModel& markv_model, - MessageConsumer message_consumer, MarkvLogConsumer log_consumer, - MarkvDebugConsumer debug_consumer, std::vector* spirv); - -} // namespace comp -} // namespace spvtools - -#endif // SOURCE_COMP_MARKV_H_ diff --git a/third_party/spirv-tools/source/comp/markv_codec.cpp b/third_party/spirv-tools/source/comp/markv_codec.cpp deleted file mode 100644 index ae3ce79f2b..0000000000 --- a/third_party/spirv-tools/source/comp/markv_codec.cpp +++ /dev/null @@ -1,793 +0,0 @@ -// Copyright (c) 2018 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. - -// MARK-V is a compression format for SPIR-V binaries. It strips away -// non-essential information (such as result IDs which can be regenerated) and -// uses various bit reduction techniques to reduce the size of the binary. - -#include "source/comp/markv_codec.h" - -#include "source/comp/markv_logger.h" -#include "source/latest_version_glsl_std_450_header.h" -#include "source/latest_version_opencl_std_header.h" -#include "source/opcode.h" -#include "source/util/make_unique.h" - -namespace spvtools { -namespace comp { -namespace { - -// Custom hash function used to produce short descriptors. -uint32_t ShortHashU32Array(const std::vector& words) { - // The hash function is a sum of hashes of each word seeded by word index. - // Knuth's multiplicative hash is used to hash the words. - const uint32_t kKnuthMulHash = 2654435761; - uint32_t val = 0; - for (uint32_t i = 0; i < words.size(); ++i) { - val += (words[i] + i + 123) * kKnuthMulHash; - } - return 1 + val % ((1 << MarkvCodec::kShortDescriptorNumBits) - 1); -} - -// Returns a set of mtf rank codecs based on a plausible hand-coded -// distribution. -std::map>> -GetMtfHuffmanCodecs() { - std::map>> codecs; - - std::unique_ptr> codec; - - codec = MakeUnique>(std::map({ - {0, 5}, - {1, 40}, - {2, 10}, - {3, 5}, - {4, 5}, - {5, 5}, - {6, 3}, - {7, 3}, - {8, 3}, - {9, 3}, - {MarkvCodec::kMtfRankEncodedByValueSignal, 10}, - })); - codecs.emplace(kMtfAll, std::move(codec)); - - codec = MakeUnique>(std::map({ - {1, 50}, - {2, 20}, - {3, 5}, - {4, 5}, - {5, 2}, - {6, 1}, - {7, 1}, - {8, 1}, - {9, 1}, - {MarkvCodec::kMtfRankEncodedByValueSignal, 10}, - })); - codecs.emplace(kMtfGenericNonZeroRank, std::move(codec)); - - return codecs; -} - -} // namespace - -const uint32_t MarkvCodec::kMarkvMagicNumber = 0x07230303; - -const uint32_t MarkvCodec::kMtfSmallestRankEncodedByValue = 10; - -const uint32_t MarkvCodec::kMtfRankEncodedByValueSignal = - std::numeric_limits::max(); - -const uint32_t MarkvCodec::kShortDescriptorNumBits = 8; - -const size_t MarkvCodec::kByteBreakAfterInstIfLessThanUntilNextByte = 8; - -MarkvCodec::MarkvCodec(spv_const_context context, - spv_validator_options validator_options, - const MarkvModel* model) - : validator_options_(validator_options), - grammar_(context), - model_(model), - short_id_descriptors_(ShortHashU32Array), - mtf_huffman_codecs_(GetMtfHuffmanCodecs()), - context_(context) {} - -MarkvCodec::~MarkvCodec() { spvValidatorOptionsDestroy(validator_options_); } - -MarkvCodec::MarkvHeader::MarkvHeader() - : magic_number(MarkvCodec::kMarkvMagicNumber), - markv_version(MarkvCodec::GetMarkvVersion()) {} - -// Defines and returns current MARK-V version. -// static -uint32_t MarkvCodec::GetMarkvVersion() { - const uint32_t kVersionMajor = 1; - const uint32_t kVersionMinor = 4; - return kVersionMinor | (kVersionMajor << 16); -} - -size_t MarkvCodec::GetNumBitsToNextByte(size_t bit_pos) const { - return (8 - (bit_pos % 8)) % 8; -} - -// Returns true if the opcode has a fixed number of operands. May return a -// false negative. -bool MarkvCodec::OpcodeHasFixedNumberOfOperands(SpvOp opcode) const { - switch (opcode) { - // TODO(atgoo@github.com) This is not a complete list. - case SpvOpNop: - case SpvOpName: - case SpvOpUndef: - case SpvOpSizeOf: - case SpvOpLine: - case SpvOpNoLine: - case SpvOpDecorationGroup: - case SpvOpExtension: - case SpvOpExtInstImport: - case SpvOpMemoryModel: - case SpvOpCapability: - case SpvOpTypeVoid: - case SpvOpTypeBool: - case SpvOpTypeInt: - case SpvOpTypeFloat: - case SpvOpTypeVector: - case SpvOpTypeMatrix: - case SpvOpTypeSampler: - case SpvOpTypeSampledImage: - case SpvOpTypeArray: - case SpvOpTypePointer: - case SpvOpConstantTrue: - case SpvOpConstantFalse: - case SpvOpLabel: - case SpvOpBranch: - case SpvOpFunction: - case SpvOpFunctionParameter: - case SpvOpFunctionEnd: - case SpvOpBitcast: - case SpvOpCopyObject: - case SpvOpTranspose: - case SpvOpSNegate: - case SpvOpFNegate: - case SpvOpIAdd: - case SpvOpFAdd: - case SpvOpISub: - case SpvOpFSub: - case SpvOpIMul: - case SpvOpFMul: - case SpvOpUDiv: - case SpvOpSDiv: - case SpvOpFDiv: - case SpvOpUMod: - case SpvOpSRem: - case SpvOpSMod: - case SpvOpFRem: - case SpvOpFMod: - case SpvOpVectorTimesScalar: - case SpvOpMatrixTimesScalar: - case SpvOpVectorTimesMatrix: - case SpvOpMatrixTimesVector: - case SpvOpMatrixTimesMatrix: - case SpvOpOuterProduct: - case SpvOpDot: - return true; - default: - break; - } - return false; -} - -void MarkvCodec::ProcessCurInstruction() { - instructions_.emplace_back(new val::Instruction(&inst_)); - - const SpvOp opcode = SpvOp(inst_.opcode); - - if (inst_.result_id) { - id_to_def_instruction_.emplace(inst_.result_id, instructions_.back().get()); - - // Collect ids local to the current function. - if (cur_function_id_) { - ids_local_to_cur_function_.push_back(inst_.result_id); - } - - // Starting new function. - if (opcode == SpvOpFunction) { - cur_function_id_ = inst_.result_id; - cur_function_return_type_ = inst_.type_id; - if (model_->id_fallback_strategy() == - MarkvModel::IdFallbackStrategy::kRuleBased) { - multi_mtf_.Insert(GetMtfFunctionWithReturnType(inst_.type_id), - inst_.result_id); - } - - // Store function parameter types in a queue, so that we know which types - // to expect in the following OpFunctionParameter instructions. - const val::Instruction* def_inst = FindDef(inst_.words[4]); - assert(def_inst); - assert(def_inst->opcode() == SpvOpTypeFunction); - for (uint32_t i = 3; i < def_inst->words().size(); ++i) { - remaining_function_parameter_types_.push_back(def_inst->word(i)); - } - } - } - - // Remove local ids from MTFs if function end. - if (opcode == SpvOpFunctionEnd) { - cur_function_id_ = 0; - for (uint32_t id : ids_local_to_cur_function_) multi_mtf_.RemoveFromAll(id); - ids_local_to_cur_function_.clear(); - assert(remaining_function_parameter_types_.empty()); - } - - if (!inst_.result_id) return; - - { - // Save the result ID to type ID mapping. - // In the grammar, type ID always appears before result ID. - // A regular value maps to its type. Some instructions (e.g. OpLabel) - // have no type Id, and will map to 0. The result Id for a - // type-generating instruction (e.g. OpTypeInt) maps to itself. - auto insertion_result = id_to_type_id_.emplace( - inst_.result_id, spvOpcodeGeneratesType(SpvOp(inst_.opcode)) - ? inst_.result_id - : inst_.type_id); - (void)insertion_result; - assert(insertion_result.second); - } - - // Add result_id to MTFs. - if (model_->id_fallback_strategy() == - MarkvModel::IdFallbackStrategy::kRuleBased) { - switch (opcode) { - case SpvOpTypeFloat: - case SpvOpTypeInt: - case SpvOpTypeBool: - case SpvOpTypeVector: - case SpvOpTypePointer: - case SpvOpExtInstImport: - case SpvOpTypeSampledImage: - case SpvOpTypeImage: - case SpvOpTypeSampler: - multi_mtf_.Insert(GetMtfIdGeneratedByOpcode(opcode), inst_.result_id); - break; - default: - break; - } - - if (spvOpcodeIsComposite(opcode)) { - multi_mtf_.Insert(kMtfTypeComposite, inst_.result_id); - } - - if (opcode == SpvOpLabel) { - multi_mtf_.InsertOrPromote(kMtfLabel, inst_.result_id); - } - - if (opcode == SpvOpTypeInt) { - multi_mtf_.Insert(kMtfTypeScalar, inst_.result_id); - multi_mtf_.Insert(kMtfTypeIntScalarOrVector, inst_.result_id); - } - - if (opcode == SpvOpTypeFloat) { - multi_mtf_.Insert(kMtfTypeScalar, inst_.result_id); - multi_mtf_.Insert(kMtfTypeFloatScalarOrVector, inst_.result_id); - } - - if (opcode == SpvOpTypeBool) { - multi_mtf_.Insert(kMtfTypeScalar, inst_.result_id); - multi_mtf_.Insert(kMtfTypeBoolScalarOrVector, inst_.result_id); - } - - if (opcode == SpvOpTypeVector) { - const uint32_t component_type_id = inst_.words[2]; - const uint32_t size = inst_.words[3]; - if (multi_mtf_.HasValue(GetMtfIdGeneratedByOpcode(SpvOpTypeFloat), - component_type_id)) { - multi_mtf_.Insert(kMtfTypeFloatScalarOrVector, inst_.result_id); - } else if (multi_mtf_.HasValue(GetMtfIdGeneratedByOpcode(SpvOpTypeInt), - component_type_id)) { - multi_mtf_.Insert(kMtfTypeIntScalarOrVector, inst_.result_id); - } else if (multi_mtf_.HasValue(GetMtfIdGeneratedByOpcode(SpvOpTypeBool), - component_type_id)) { - multi_mtf_.Insert(kMtfTypeBoolScalarOrVector, inst_.result_id); - } - multi_mtf_.Insert(GetMtfTypeVectorOfSize(size), inst_.result_id); - } - - if (inst_.opcode == SpvOpTypeFunction) { - const uint32_t return_type = inst_.words[2]; - multi_mtf_.Insert(kMtfTypeReturnedByFunction, return_type); - multi_mtf_.Insert(GetMtfFunctionTypeWithReturnType(return_type), - inst_.result_id); - } - - if (inst_.type_id) { - const val::Instruction* type_inst = FindDef(inst_.type_id); - assert(type_inst); - - multi_mtf_.Insert(kMtfObject, inst_.result_id); - - multi_mtf_.Insert(GetMtfIdOfType(inst_.type_id), inst_.result_id); - - if (multi_mtf_.HasValue(kMtfTypeFloatScalarOrVector, inst_.type_id)) { - multi_mtf_.Insert(kMtfFloatScalarOrVector, inst_.result_id); - } - - if (multi_mtf_.HasValue(kMtfTypeIntScalarOrVector, inst_.type_id)) - multi_mtf_.Insert(kMtfIntScalarOrVector, inst_.result_id); - - if (multi_mtf_.HasValue(kMtfTypeBoolScalarOrVector, inst_.type_id)) - multi_mtf_.Insert(kMtfBoolScalarOrVector, inst_.result_id); - - if (multi_mtf_.HasValue(kMtfTypeComposite, inst_.type_id)) - multi_mtf_.Insert(kMtfComposite, inst_.result_id); - - switch (type_inst->opcode()) { - case SpvOpTypeInt: - case SpvOpTypeBool: - case SpvOpTypePointer: - case SpvOpTypeVector: - case SpvOpTypeImage: - case SpvOpTypeSampledImage: - case SpvOpTypeSampler: - multi_mtf_.Insert( - GetMtfIdWithTypeGeneratedByOpcode(type_inst->opcode()), - inst_.result_id); - break; - default: - break; - } - - if (type_inst->opcode() == SpvOpTypeVector) { - const uint32_t component_type = type_inst->word(2); - multi_mtf_.Insert(GetMtfVectorOfComponentType(component_type), - inst_.result_id); - } - - if (type_inst->opcode() == SpvOpTypePointer) { - assert(type_inst->operands().size() > 2); - assert(type_inst->words().size() > type_inst->operands()[2].offset); - const uint32_t data_type = - type_inst->word(type_inst->operands()[2].offset); - multi_mtf_.Insert(GetMtfPointerToType(data_type), inst_.result_id); - - if (multi_mtf_.HasValue(kMtfTypeComposite, data_type)) - multi_mtf_.Insert(kMtfTypePointerToComposite, inst_.result_id); - } - } - - if (spvOpcodeGeneratesType(opcode)) { - if (opcode != SpvOpTypeFunction) { - multi_mtf_.Insert(kMtfTypeNonFunction, inst_.result_id); - } - } - } - - if (model_->AnyDescriptorHasCodingScheme()) { - const uint32_t long_descriptor = - long_id_descriptors_.ProcessInstruction(inst_); - if (model_->DescriptorHasCodingScheme(long_descriptor)) - multi_mtf_.Insert(GetMtfLongIdDescriptor(long_descriptor), - inst_.result_id); - } - - if (model_->id_fallback_strategy() == - MarkvModel::IdFallbackStrategy::kShortDescriptor) { - const uint32_t short_descriptor = - short_id_descriptors_.ProcessInstruction(inst_); - multi_mtf_.Insert(GetMtfShortIdDescriptor(short_descriptor), - inst_.result_id); - } -} - -uint64_t MarkvCodec::GetRuleBasedMtf() { - // This function is only called for id operands (but not result ids). - assert(spvIsIdType(operand_.type) || - operand_.type == SPV_OPERAND_TYPE_OPTIONAL_ID); - assert(operand_.type != SPV_OPERAND_TYPE_RESULT_ID); - - const SpvOp opcode = static_cast(inst_.opcode); - - // All operand slots which expect label id. - if ((inst_.opcode == SpvOpLoopMerge && operand_index_ <= 1) || - (inst_.opcode == SpvOpSelectionMerge && operand_index_ == 0) || - (inst_.opcode == SpvOpBranch && operand_index_ == 0) || - (inst_.opcode == SpvOpBranchConditional && - (operand_index_ == 1 || operand_index_ == 2)) || - (inst_.opcode == SpvOpPhi && operand_index_ >= 3 && - operand_index_ % 2 == 1) || - (inst_.opcode == SpvOpSwitch && operand_index_ > 0)) { - return kMtfLabel; - } - - switch (opcode) { - case SpvOpFAdd: - case SpvOpFSub: - case SpvOpFMul: - case SpvOpFDiv: - case SpvOpFRem: - case SpvOpFMod: - case SpvOpFNegate: { - if (operand_index_ == 0) return kMtfTypeFloatScalarOrVector; - return GetMtfIdOfType(inst_.type_id); - } - - case SpvOpISub: - case SpvOpIAdd: - case SpvOpIMul: - case SpvOpSDiv: - case SpvOpUDiv: - case SpvOpSMod: - case SpvOpUMod: - case SpvOpSRem: - case SpvOpSNegate: { - if (operand_index_ == 0) return kMtfTypeIntScalarOrVector; - - return kMtfIntScalarOrVector; - } - - // TODO(atgoo@github.com) Add OpConvertFToU and other opcodes. - - case SpvOpFOrdEqual: - case SpvOpFUnordEqual: - case SpvOpFOrdNotEqual: - case SpvOpFUnordNotEqual: - case SpvOpFOrdLessThan: - case SpvOpFUnordLessThan: - case SpvOpFOrdGreaterThan: - case SpvOpFUnordGreaterThan: - case SpvOpFOrdLessThanEqual: - case SpvOpFUnordLessThanEqual: - case SpvOpFOrdGreaterThanEqual: - case SpvOpFUnordGreaterThanEqual: { - if (operand_index_ == 0) return kMtfTypeBoolScalarOrVector; - if (operand_index_ == 2) return kMtfFloatScalarOrVector; - if (operand_index_ == 3) { - const uint32_t first_operand_id = GetInstWords()[3]; - const uint32_t first_operand_type = id_to_type_id_.at(first_operand_id); - return GetMtfIdOfType(first_operand_type); - } - break; - } - - case SpvOpVectorShuffle: { - if (operand_index_ == 0) { - assert(inst_.num_operands > 4); - return GetMtfTypeVectorOfSize(inst_.num_operands - 4); - } - - assert(inst_.type_id); - if (operand_index_ == 2 || operand_index_ == 3) - return GetMtfVectorOfComponentType( - GetVectorComponentType(inst_.type_id)); - break; - } - - case SpvOpVectorTimesScalar: { - if (operand_index_ == 0) { - // TODO(atgoo@github.com) Could be narrowed to vector of floats. - return GetMtfIdGeneratedByOpcode(SpvOpTypeVector); - } - - assert(inst_.type_id); - if (operand_index_ == 2) return GetMtfIdOfType(inst_.type_id); - if (operand_index_ == 3) - return GetMtfIdOfType(GetVectorComponentType(inst_.type_id)); - break; - } - - case SpvOpDot: { - if (operand_index_ == 0) return GetMtfIdGeneratedByOpcode(SpvOpTypeFloat); - - assert(inst_.type_id); - if (operand_index_ == 2) - return GetMtfVectorOfComponentType(inst_.type_id); - if (operand_index_ == 3) { - const uint32_t vector_id = GetInstWords()[3]; - const uint32_t vector_type = id_to_type_id_.at(vector_id); - return GetMtfIdOfType(vector_type); - } - break; - } - - case SpvOpTypeVector: { - if (operand_index_ == 1) { - return kMtfTypeScalar; - } - break; - } - - case SpvOpTypeMatrix: { - if (operand_index_ == 1) { - return GetMtfIdGeneratedByOpcode(SpvOpTypeVector); - } - break; - } - - case SpvOpTypePointer: { - if (operand_index_ == 2) { - return kMtfTypeNonFunction; - } - break; - } - - case SpvOpTypeStruct: { - if (operand_index_ >= 1) { - return kMtfTypeNonFunction; - } - break; - } - - case SpvOpTypeFunction: { - if (operand_index_ == 1) { - return kMtfTypeNonFunction; - } - - if (operand_index_ >= 2) { - return kMtfTypeNonFunction; - } - break; - } - - case SpvOpLoad: { - if (operand_index_ == 0) return kMtfTypeNonFunction; - - if (operand_index_ == 2) { - assert(inst_.type_id); - return GetMtfPointerToType(inst_.type_id); - } - break; - } - - case SpvOpStore: { - if (operand_index_ == 0) - return GetMtfIdWithTypeGeneratedByOpcode(SpvOpTypePointer); - if (operand_index_ == 1) { - const uint32_t pointer_id = GetInstWords()[1]; - const uint32_t pointer_type = id_to_type_id_.at(pointer_id); - const val::Instruction* pointer_inst = FindDef(pointer_type); - assert(pointer_inst); - assert(pointer_inst->opcode() == SpvOpTypePointer); - const uint32_t data_type = - pointer_inst->word(pointer_inst->operands()[2].offset); - return GetMtfIdOfType(data_type); - } - break; - } - - case SpvOpVariable: { - if (operand_index_ == 0) - return GetMtfIdGeneratedByOpcode(SpvOpTypePointer); - break; - } - - case SpvOpAccessChain: { - if (operand_index_ == 0) - return GetMtfIdGeneratedByOpcode(SpvOpTypePointer); - if (operand_index_ == 2) return kMtfTypePointerToComposite; - if (operand_index_ >= 3) - return GetMtfIdWithTypeGeneratedByOpcode(SpvOpTypeInt); - break; - } - - case SpvOpCompositeConstruct: { - if (operand_index_ == 0) return kMtfTypeComposite; - if (operand_index_ >= 2) { - const uint32_t composite_type = GetInstWords()[1]; - if (multi_mtf_.HasValue(kMtfTypeFloatScalarOrVector, composite_type)) - return kMtfFloatScalarOrVector; - if (multi_mtf_.HasValue(kMtfTypeIntScalarOrVector, composite_type)) - return kMtfIntScalarOrVector; - if (multi_mtf_.HasValue(kMtfTypeBoolScalarOrVector, composite_type)) - return kMtfBoolScalarOrVector; - } - break; - } - - case SpvOpCompositeExtract: { - if (operand_index_ == 2) return kMtfComposite; - break; - } - - case SpvOpConstantComposite: { - if (operand_index_ == 0) return kMtfTypeComposite; - if (operand_index_ >= 2) { - const val::Instruction* composite_type_inst = FindDef(inst_.type_id); - assert(composite_type_inst); - if (composite_type_inst->opcode() == SpvOpTypeVector) { - return GetMtfIdOfType(composite_type_inst->word(2)); - } - } - break; - } - - case SpvOpExtInst: { - if (operand_index_ == 2) - return GetMtfIdGeneratedByOpcode(SpvOpExtInstImport); - if (operand_index_ >= 4) { - const uint32_t return_type = GetInstWords()[1]; - const uint32_t ext_inst_type = inst_.ext_inst_type; - const uint32_t ext_inst_index = GetInstWords()[4]; - // TODO(atgoo@github.com) The list of extended instructions is - // incomplete. Only common instructions and low-hanging fruits listed. - if (ext_inst_type == SPV_EXT_INST_TYPE_GLSL_STD_450) { - switch (ext_inst_index) { - case GLSLstd450FAbs: - case GLSLstd450FClamp: - case GLSLstd450FMax: - case GLSLstd450FMin: - case GLSLstd450FMix: - case GLSLstd450Step: - case GLSLstd450SmoothStep: - case GLSLstd450Fma: - case GLSLstd450Pow: - case GLSLstd450Exp: - case GLSLstd450Exp2: - case GLSLstd450Log: - case GLSLstd450Log2: - case GLSLstd450Sqrt: - case GLSLstd450InverseSqrt: - case GLSLstd450Fract: - case GLSLstd450Floor: - case GLSLstd450Ceil: - case GLSLstd450Radians: - case GLSLstd450Degrees: - case GLSLstd450Sin: - case GLSLstd450Cos: - case GLSLstd450Tan: - case GLSLstd450Sinh: - case GLSLstd450Cosh: - case GLSLstd450Tanh: - case GLSLstd450Asin: - case GLSLstd450Acos: - case GLSLstd450Atan: - case GLSLstd450Atan2: - case GLSLstd450Asinh: - case GLSLstd450Acosh: - case GLSLstd450Atanh: - case GLSLstd450MatrixInverse: - case GLSLstd450Cross: - case GLSLstd450Normalize: - case GLSLstd450Reflect: - case GLSLstd450FaceForward: - return GetMtfIdOfType(return_type); - case GLSLstd450Length: - case GLSLstd450Distance: - case GLSLstd450Refract: - return kMtfFloatScalarOrVector; - default: - break; - } - } else if (ext_inst_type == SPV_EXT_INST_TYPE_OPENCL_STD) { - switch (ext_inst_index) { - case OpenCLLIB::Fabs: - case OpenCLLIB::FClamp: - case OpenCLLIB::Fmax: - case OpenCLLIB::Fmin: - case OpenCLLIB::Step: - case OpenCLLIB::Smoothstep: - case OpenCLLIB::Fma: - case OpenCLLIB::Pow: - case OpenCLLIB::Exp: - case OpenCLLIB::Exp2: - case OpenCLLIB::Log: - case OpenCLLIB::Log2: - case OpenCLLIB::Sqrt: - case OpenCLLIB::Rsqrt: - case OpenCLLIB::Fract: - case OpenCLLIB::Floor: - case OpenCLLIB::Ceil: - case OpenCLLIB::Radians: - case OpenCLLIB::Degrees: - case OpenCLLIB::Sin: - case OpenCLLIB::Cos: - case OpenCLLIB::Tan: - case OpenCLLIB::Sinh: - case OpenCLLIB::Cosh: - case OpenCLLIB::Tanh: - case OpenCLLIB::Asin: - case OpenCLLIB::Acos: - case OpenCLLIB::Atan: - case OpenCLLIB::Atan2: - case OpenCLLIB::Asinh: - case OpenCLLIB::Acosh: - case OpenCLLIB::Atanh: - case OpenCLLIB::Cross: - case OpenCLLIB::Normalize: - return GetMtfIdOfType(return_type); - case OpenCLLIB::Length: - case OpenCLLIB::Distance: - return kMtfFloatScalarOrVector; - default: - break; - } - } - } - break; - } - - case SpvOpFunction: { - if (operand_index_ == 0) return kMtfTypeReturnedByFunction; - - if (operand_index_ == 3) { - const uint32_t return_type = GetInstWords()[1]; - return GetMtfFunctionTypeWithReturnType(return_type); - } - break; - } - - case SpvOpFunctionCall: { - if (operand_index_ == 0) return kMtfTypeReturnedByFunction; - - if (operand_index_ == 2) { - const uint32_t return_type = GetInstWords()[1]; - return GetMtfFunctionWithReturnType(return_type); - } - - if (operand_index_ >= 3) { - const uint32_t function_id = GetInstWords()[3]; - const val::Instruction* function_inst = FindDef(function_id); - if (!function_inst) return kMtfObject; - - assert(function_inst->opcode() == SpvOpFunction); - - const uint32_t function_type_id = function_inst->word(4); - const val::Instruction* function_type_inst = FindDef(function_type_id); - assert(function_type_inst); - assert(function_type_inst->opcode() == SpvOpTypeFunction); - - const uint32_t argument_type = function_type_inst->word(operand_index_); - return GetMtfIdOfType(argument_type); - } - break; - } - - case SpvOpReturnValue: { - if (operand_index_ == 0) return GetMtfIdOfType(cur_function_return_type_); - break; - } - - case SpvOpBranchConditional: { - if (operand_index_ == 0) - return GetMtfIdWithTypeGeneratedByOpcode(SpvOpTypeBool); - break; - } - - case SpvOpSampledImage: { - if (operand_index_ == 0) - return GetMtfIdGeneratedByOpcode(SpvOpTypeSampledImage); - if (operand_index_ == 2) - return GetMtfIdWithTypeGeneratedByOpcode(SpvOpTypeImage); - if (operand_index_ == 3) - return GetMtfIdWithTypeGeneratedByOpcode(SpvOpTypeSampler); - break; - } - - case SpvOpImageSampleImplicitLod: { - if (operand_index_ == 0) - return GetMtfIdGeneratedByOpcode(SpvOpTypeVector); - if (operand_index_ == 2) - return GetMtfIdWithTypeGeneratedByOpcode(SpvOpTypeSampledImage); - if (operand_index_ == 3) - return GetMtfIdWithTypeGeneratedByOpcode(SpvOpTypeVector); - break; - } - - default: - break; - } - - return kMtfNone; -} - -} // namespace comp -} // namespace spvtools diff --git a/third_party/spirv-tools/source/comp/markv_codec.h b/third_party/spirv-tools/source/comp/markv_codec.h deleted file mode 100644 index f313d61788..0000000000 --- a/third_party/spirv-tools/source/comp/markv_codec.h +++ /dev/null @@ -1,337 +0,0 @@ -// Copyright (c) 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_COMP_MARKV_CODEC_H_ -#define SOURCE_COMP_MARKV_CODEC_H_ - -#include -#include -#include -#include - -#include "source/assembly_grammar.h" -#include "source/comp/huffman_codec.h" -#include "source/comp/markv_model.h" -#include "source/comp/move_to_front.h" -#include "source/diagnostic.h" -#include "source/id_descriptor.h" - -#include "source/val/instruction.h" - -// Base class for MARK-V encoder and decoder. Contains common functionality -// such as: -// - Validator connection and validation state. -// - SPIR-V grammar and helper functions. - -namespace spvtools { -namespace comp { - -class MarkvLogger; - -// Handles for move-to-front sequences. Enums which end with "Begin" define -// handle spaces which start at that value and span 16 or 32 bit wide. -enum : uint64_t { - kMtfNone = 0, - // All ids. - kMtfAll, - // All forward declared ids. - kMtfForwardDeclared, - // All type ids except for generated by OpTypeFunction. - kMtfTypeNonFunction, - // All labels. - kMtfLabel, - // All ids created by instructions which had type_id. - kMtfObject, - // All types generated by OpTypeFloat, OpTypeInt, OpTypeBool. - kMtfTypeScalar, - // All composite types. - kMtfTypeComposite, - // Boolean type or any vector type of it. - kMtfTypeBoolScalarOrVector, - // All float types or any vector floats type. - kMtfTypeFloatScalarOrVector, - // All int types or any vector int type. - kMtfTypeIntScalarOrVector, - // All types declared as return types in OpTypeFunction. - kMtfTypeReturnedByFunction, - // All composite objects. - kMtfComposite, - // All bool objects or vectors of bools. - kMtfBoolScalarOrVector, - // All float objects or vectors of float. - kMtfFloatScalarOrVector, - // All int objects or vectors of int. - kMtfIntScalarOrVector, - // All pointer types which point to composited. - kMtfTypePointerToComposite, - // Used by EncodeMtfRankHuffman. - kMtfGenericNonZeroRank, - // Handle space for ids of specific type. - kMtfIdOfTypeBegin = 0x10000, - // Handle space for ids generated by specific opcode. - kMtfIdGeneratedByOpcode = 0x20000, - // Handle space for ids of objects with type generated by specific opcode. - kMtfIdWithTypeGeneratedByOpcodeBegin = 0x30000, - // All vectors of specific component type. - kMtfVectorOfComponentTypeBegin = 0x40000, - // All vector types of specific size. - kMtfTypeVectorOfSizeBegin = 0x50000, - // All pointer types to specific type. - kMtfPointerToTypeBegin = 0x60000, - // All function types which return specific type. - kMtfFunctionTypeWithReturnTypeBegin = 0x70000, - // All function objects which return specific type. - kMtfFunctionWithReturnTypeBegin = 0x80000, - // Short id descriptor space (max 16-bit). - kMtfShortIdDescriptorSpaceBegin = 0x90000, - // Long id descriptor space (32-bit). - kMtfLongIdDescriptorSpaceBegin = 0x100000000, -}; - -class MarkvCodec { - public: - static const uint32_t kMarkvMagicNumber; - - // Mtf ranks smaller than this are encoded with Huffman coding. - static const uint32_t kMtfSmallestRankEncodedByValue; - - // Signals that the mtf rank is too large to be encoded with Huffman. - static const uint32_t kMtfRankEncodedByValueSignal; - - static const uint32_t kShortDescriptorNumBits; - - static const size_t kByteBreakAfterInstIfLessThanUntilNextByte; - - static uint32_t GetMarkvVersion(); - - virtual ~MarkvCodec(); - - protected: - struct MarkvHeader { - MarkvHeader(); - - uint32_t magic_number; - uint32_t markv_version; - // Magic number to identify or verify MarkvModel used for encoding. - uint32_t markv_model = 0; - uint32_t markv_length_in_bits = 0; - uint32_t spirv_version = 0; - uint32_t spirv_generator = 0; - }; - - // |model| is owned by the caller, must be not null and valid during the - // lifetime of the codec. - MarkvCodec(spv_const_context context, spv_validator_options validator_options, - const MarkvModel* model); - - // Returns instruction which created |id| or nullptr if such instruction was - // not registered. - const val::Instruction* FindDef(uint32_t id) const { - const auto it = id_to_def_instruction_.find(id); - if (it == id_to_def_instruction_.end()) return nullptr; - return it->second; - } - - size_t GetNumBitsToNextByte(size_t bit_pos) const; - bool OpcodeHasFixedNumberOfOperands(SpvOp opcode) const; - - // Returns type id of vector type component. - uint32_t GetVectorComponentType(uint32_t vector_type_id) const { - const val::Instruction* type_inst = FindDef(vector_type_id); - assert(type_inst); - assert(type_inst->opcode() == SpvOpTypeVector); - - const uint32_t component_type = - type_inst->word(type_inst->operands()[1].offset); - return component_type; - } - - // Returns mtf handle for ids of given type. - uint64_t GetMtfIdOfType(uint32_t type_id) const { - return kMtfIdOfTypeBegin + type_id; - } - - // Returns mtf handle for ids generated by given opcode. - uint64_t GetMtfIdGeneratedByOpcode(SpvOp opcode) const { - return kMtfIdGeneratedByOpcode + opcode; - } - - // Returns mtf handle for ids of type generated by given opcode. - uint64_t GetMtfIdWithTypeGeneratedByOpcode(SpvOp opcode) const { - return kMtfIdWithTypeGeneratedByOpcodeBegin + opcode; - } - - // Returns mtf handle for vectors of specific component type. - uint64_t GetMtfVectorOfComponentType(uint32_t type_id) const { - return kMtfVectorOfComponentTypeBegin + type_id; - } - - // Returns mtf handle for vector type of specific size. - uint64_t GetMtfTypeVectorOfSize(uint32_t size) const { - return kMtfTypeVectorOfSizeBegin + size; - } - - // Returns mtf handle for pointers to specific size. - uint64_t GetMtfPointerToType(uint32_t type_id) const { - return kMtfPointerToTypeBegin + type_id; - } - - // Returns mtf handle for function types with given return type. - uint64_t GetMtfFunctionTypeWithReturnType(uint32_t type_id) const { - return kMtfFunctionTypeWithReturnTypeBegin + type_id; - } - - // Returns mtf handle for functions with given return type. - uint64_t GetMtfFunctionWithReturnType(uint32_t type_id) const { - return kMtfFunctionWithReturnTypeBegin + type_id; - } - - // Returns mtf handle for the given long id descriptor. - uint64_t GetMtfLongIdDescriptor(uint32_t descriptor) const { - return kMtfLongIdDescriptorSpaceBegin + descriptor; - } - - // Returns mtf handle for the given short id descriptor. - uint64_t GetMtfShortIdDescriptor(uint32_t descriptor) const { - return kMtfShortIdDescriptorSpaceBegin + descriptor; - } - - // Process data from the current instruction. This would update MTFs and - // other data containers. - void ProcessCurInstruction(); - - // Returns move-to-front handle to be used for the current operand slot. - // Mtf handle is chosen based on a set of rules defined by SPIR-V grammar. - uint64_t GetRuleBasedMtf(); - - // Returns words of the current instruction. Decoder has a different - // implementation and the array is valid only until the previously decoded - // word. - virtual const uint32_t* GetInstWords() const { return inst_.words; } - - // Returns the opcode of the previous instruction. - SpvOp GetPrevOpcode() const { - if (instructions_.empty()) return SpvOpNop; - - return instructions_.back()->opcode(); - } - - // Returns diagnostic stream, position index is set to instruction number. - DiagnosticStream Diag(spv_result_t error_code) const { - return DiagnosticStream({0, 0, instructions_.size()}, context_->consumer, - "", error_code); - } - - // Returns current id bound. - uint32_t GetIdBound() const { return id_bound_; } - - // Sets current id bound, expected to be no lower than the previous one. - void SetIdBound(uint32_t id_bound) { - assert(id_bound >= id_bound_); - id_bound_ = id_bound; - } - - // Returns Huffman codec for ranks of the mtf with given |handle|. - // Different mtfs can use different rank distributions. - // May return nullptr if the codec doesn't exist. - const HuffmanCodec* GetMtfHuffmanCodec(uint64_t handle) const { - const auto it = mtf_huffman_codecs_.find(handle); - if (it == mtf_huffman_codecs_.end()) return nullptr; - return it->second.get(); - } - - // Promotes id in all move-to-front sequences if ids can be shared by multiple - // sequences. - void PromoteIfNeeded(uint32_t id) { - if (!model_->AnyDescriptorHasCodingScheme() && - model_->id_fallback_strategy() == - MarkvModel::IdFallbackStrategy::kShortDescriptor) { - // Move-to-front sequences do not share ids. Nothing to do. - return; - } - multi_mtf_.Promote(id); - } - - spv_validator_options validator_options_ = nullptr; - const AssemblyGrammar grammar_; - MarkvHeader header_; - - // MARK-V model, not owned. - const MarkvModel* model_ = nullptr; - - // Current instruction, current operand and current operand index. - spv_parsed_instruction_t inst_; - spv_parsed_operand_t operand_; - uint32_t operand_index_; - - // Maps a result ID to its type ID. By convention: - // - a result ID that is a type definition maps to itself. - // - a result ID without a type maps to 0. (E.g. for OpLabel) - std::unordered_map id_to_type_id_; - - // Container for all move-to-front sequences. - MultiMoveToFront multi_mtf_; - - // Id of the current function or zero if outside of function. - uint32_t cur_function_id_ = 0; - - // Return type of the current function. - uint32_t cur_function_return_type_ = 0; - - // Remaining function parameter types. This container is filled on OpFunction, - // and drained on OpFunctionParameter. - std::list remaining_function_parameter_types_; - - // List of ids local to the current function. - std::vector ids_local_to_cur_function_; - - // List of instructions in the order they are given in the module. - std::vector> instructions_; - - // Container/computer for long (32-bit) id descriptors. - IdDescriptorCollection long_id_descriptors_; - - // Container/computer for short id descriptors. - // Short descriptors are stored in uint32_t, but their actual bit width is - // defined with kShortDescriptorNumBits. - // It doesn't seem logical to have a different computer for short id - // descriptors, since one could actually map/truncate long descriptors. - // But as short descriptors have collisions, the efficiency of - // compression depends on the collision pattern, and short descriptors - // produced by function ShortHashU32Array have been empirically proven to - // produce better results. - IdDescriptorCollection short_id_descriptors_; - - // Huffman codecs for move-to-front ranks. The map key is mtf handle. Doesn't - // need to contain a different codec for every handle as most use one and the - // same. - std::map>> - mtf_huffman_codecs_; - - // If not nullptr, codec will log comments on the compression process. - std::unique_ptr logger_; - - spv_const_context context_ = nullptr; - - private: - // Maps result id to the instruction which defined it. - std::unordered_map id_to_def_instruction_; - - uint32_t id_bound_ = 1; -}; - -} // namespace comp -} // namespace spvtools - -#endif // SOURCE_COMP_MARKV_CODEC_H_ diff --git a/third_party/spirv-tools/source/comp/markv_decoder.cpp b/third_party/spirv-tools/source/comp/markv_decoder.cpp deleted file mode 100644 index 22115831dc..0000000000 --- a/third_party/spirv-tools/source/comp/markv_decoder.cpp +++ /dev/null @@ -1,925 +0,0 @@ -// Copyright (c) 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/comp/markv_decoder.h" - -#include -#include -#include - -#include "source/ext_inst.h" -#include "source/opcode.h" -#include "spirv-tools/libspirv.hpp" - -namespace spvtools { -namespace comp { - -spv_result_t MarkvDecoder::DecodeNonIdWord(uint32_t* word) { - auto* codec = model_->GetNonIdWordHuffmanCodec(inst_.opcode, operand_index_); - - if (codec) { - uint64_t decoded_value = 0; - if (!codec->DecodeFromStream(GetReadBitCallback(), &decoded_value)) - return Diag(SPV_ERROR_INVALID_BINARY) - << "Failed to decode non-id word with Huffman"; - - if (decoded_value != MarkvModel::GetMarkvNoneOfTheAbove()) { - // The word decoded successfully. - *word = uint32_t(decoded_value); - assert(*word == decoded_value); - return SPV_SUCCESS; - } - - // Received kMarkvNoneOfTheAbove signal, use fallback decoding. - } - - const size_t chunk_length = - model_->GetOperandVariableWidthChunkLength(operand_.type); - if (chunk_length) { - if (!reader_.ReadVariableWidthU32(word, chunk_length)) - return Diag(SPV_ERROR_INVALID_BINARY) - << "Failed to decode non-id word with varint"; - } else { - if (!reader_.ReadUnencoded(word)) - return Diag(SPV_ERROR_INVALID_BINARY) - << "Failed to read unencoded non-id word"; - } - return SPV_SUCCESS; -} - -spv_result_t MarkvDecoder::DecodeOpcodeAndNumberOfOperands( - uint32_t* opcode, uint32_t* num_operands) { - // First try to use the Markov chain codec. - auto* codec = - model_->GetOpcodeAndNumOperandsMarkovHuffmanCodec(GetPrevOpcode()); - if (codec) { - uint64_t decoded_value = 0; - if (!codec->DecodeFromStream(GetReadBitCallback(), &decoded_value)) - return Diag(SPV_ERROR_INTERNAL) - << "Failed to decode opcode_and_num_operands, previous opcode is " - << spvOpcodeString(GetPrevOpcode()); - - if (decoded_value != MarkvModel::GetMarkvNoneOfTheAbove()) { - // The word was successfully decoded. - *opcode = uint32_t(decoded_value & 0xFFFF); - *num_operands = uint32_t(decoded_value >> 16); - return SPV_SUCCESS; - } - - // Received kMarkvNoneOfTheAbove signal, use fallback decoding. - } - - // Fallback to base-rate codec. - codec = model_->GetOpcodeAndNumOperandsMarkovHuffmanCodec(SpvOpNop); - assert(codec); - uint64_t decoded_value = 0; - if (!codec->DecodeFromStream(GetReadBitCallback(), &decoded_value)) - return Diag(SPV_ERROR_INTERNAL) - << "Failed to decode opcode_and_num_operands with global codec"; - - if (decoded_value == MarkvModel::GetMarkvNoneOfTheAbove()) { - // Received kMarkvNoneOfTheAbove signal, fallback further. - return SPV_UNSUPPORTED; - } - - *opcode = uint32_t(decoded_value & 0xFFFF); - *num_operands = uint32_t(decoded_value >> 16); - return SPV_SUCCESS; -} - -spv_result_t MarkvDecoder::DecodeMtfRankHuffman(uint64_t mtf, - uint32_t fallback_method, - uint32_t* rank) { - const auto* codec = GetMtfHuffmanCodec(mtf); - if (!codec) { - assert(fallback_method != kMtfNone); - codec = GetMtfHuffmanCodec(fallback_method); - } - - if (!codec) return Diag(SPV_ERROR_INTERNAL) << "No codec to decode MTF rank"; - - uint32_t decoded_value = 0; - if (!codec->DecodeFromStream(GetReadBitCallback(), &decoded_value)) - return Diag(SPV_ERROR_INTERNAL) << "Failed to decode MTF rank with Huffman"; - - if (decoded_value == kMtfRankEncodedByValueSignal) { - // Decode by value. - if (!reader_.ReadVariableWidthU32(rank, model_->mtf_rank_chunk_length())) - return Diag(SPV_ERROR_INTERNAL) - << "Failed to decode MTF rank with varint"; - *rank += MarkvCodec::kMtfSmallestRankEncodedByValue; - } else { - // Decode using Huffman coding. - assert(decoded_value < MarkvCodec::kMtfSmallestRankEncodedByValue); - *rank = decoded_value; - } - return SPV_SUCCESS; -} - -spv_result_t MarkvDecoder::DecodeIdWithDescriptor(uint32_t* id) { - auto* codec = - model_->GetIdDescriptorHuffmanCodec(inst_.opcode, operand_index_); - - uint64_t mtf = kMtfNone; - if (codec) { - uint64_t decoded_value = 0; - if (!codec->DecodeFromStream(GetReadBitCallback(), &decoded_value)) - return Diag(SPV_ERROR_INTERNAL) - << "Failed to decode descriptor with Huffman"; - - if (decoded_value != MarkvModel::GetMarkvNoneOfTheAbove()) { - const uint32_t long_descriptor = uint32_t(decoded_value); - mtf = GetMtfLongIdDescriptor(long_descriptor); - } - } - - if (mtf == kMtfNone) { - if (model_->id_fallback_strategy() != - MarkvModel::IdFallbackStrategy::kShortDescriptor) { - return SPV_UNSUPPORTED; - } - - uint64_t decoded_value = 0; - if (!reader_.ReadBits(&decoded_value, MarkvCodec::kShortDescriptorNumBits)) - return Diag(SPV_ERROR_INTERNAL) << "Failed to read short descriptor"; - const uint32_t short_descriptor = uint32_t(decoded_value); - if (short_descriptor == 0) { - // Forward declared id. - return SPV_UNSUPPORTED; - } - mtf = GetMtfShortIdDescriptor(short_descriptor); - } - - return DecodeExistingId(mtf, id); -} - -spv_result_t MarkvDecoder::DecodeExistingId(uint64_t mtf, uint32_t* id) { - assert(multi_mtf_.GetSize(mtf) > 0); - *id = 0; - - uint32_t rank = 0; - - if (multi_mtf_.GetSize(mtf) == 1) { - rank = 1; - } else { - const spv_result_t result = - DecodeMtfRankHuffman(mtf, kMtfGenericNonZeroRank, &rank); - if (result != SPV_SUCCESS) return result; - } - - assert(rank); - if (!multi_mtf_.ValueFromRank(mtf, rank, id)) - return Diag(SPV_ERROR_INTERNAL) << "MTF rank is out of bounds"; - - return SPV_SUCCESS; -} - -spv_result_t MarkvDecoder::DecodeRefId(uint32_t* id) { - { - const spv_result_t result = DecodeIdWithDescriptor(id); - if (result != SPV_UNSUPPORTED) return result; - } - - const bool can_forward_declare = spvOperandCanBeForwardDeclaredFunction( - SpvOp(inst_.opcode))(operand_index_); - uint32_t rank = 0; - *id = 0; - - if (model_->id_fallback_strategy() == - MarkvModel::IdFallbackStrategy::kRuleBased) { - uint64_t mtf = GetRuleBasedMtf(); - if (mtf != kMtfNone && !can_forward_declare) { - return DecodeExistingId(mtf, id); - } - - if (mtf == kMtfNone) mtf = kMtfAll; - { - const spv_result_t result = DecodeMtfRankHuffman(mtf, kMtfAll, &rank); - if (result != SPV_SUCCESS) return result; - } - - if (rank == 0) { - // This is the first occurrence of a forward declared id. - *id = GetIdBound(); - SetIdBound(*id + 1); - multi_mtf_.Insert(kMtfAll, *id); - multi_mtf_.Insert(kMtfForwardDeclared, *id); - if (mtf != kMtfAll) multi_mtf_.Insert(mtf, *id); - } else { - if (!multi_mtf_.ValueFromRank(mtf, rank, id)) - return Diag(SPV_ERROR_INTERNAL) << "MTF rank out of bounds"; - } - } else { - assert(can_forward_declare); - - if (!reader_.ReadVariableWidthU32(&rank, model_->mtf_rank_chunk_length())) - return Diag(SPV_ERROR_INTERNAL) - << "Failed to decode MTF rank with varint"; - - if (rank == 0) { - // This is the first occurrence of a forward declared id. - *id = GetIdBound(); - SetIdBound(*id + 1); - multi_mtf_.Insert(kMtfForwardDeclared, *id); - } else { - if (!multi_mtf_.ValueFromRank(kMtfForwardDeclared, rank, id)) - return Diag(SPV_ERROR_INTERNAL) << "MTF rank out of bounds"; - } - } - assert(*id); - return SPV_SUCCESS; -} - -spv_result_t MarkvDecoder::DecodeTypeId() { - if (inst_.opcode == SpvOpFunctionParameter) { - assert(!remaining_function_parameter_types_.empty()); - inst_.type_id = remaining_function_parameter_types_.front(); - remaining_function_parameter_types_.pop_front(); - return SPV_SUCCESS; - } - - { - const spv_result_t result = DecodeIdWithDescriptor(&inst_.type_id); - if (result != SPV_UNSUPPORTED) return result; - } - - assert(model_->id_fallback_strategy() == - MarkvModel::IdFallbackStrategy::kRuleBased); - - uint64_t mtf = GetRuleBasedMtf(); - assert(!spvOperandCanBeForwardDeclaredFunction(SpvOp(inst_.opcode))( - operand_index_)); - - if (mtf == kMtfNone) { - mtf = kMtfTypeNonFunction; - // Function types should have been handled by GetRuleBasedMtf. - assert(inst_.opcode != SpvOpFunction); - } - - return DecodeExistingId(mtf, &inst_.type_id); -} - -spv_result_t MarkvDecoder::DecodeResultId() { - uint32_t rank = 0; - - const uint64_t num_still_forward_declared = - multi_mtf_.GetSize(kMtfForwardDeclared); - - if (num_still_forward_declared) { - // Some ids were forward declared. Check if this id is one of them. - uint64_t id_was_forward_declared; - if (!reader_.ReadBits(&id_was_forward_declared, 1)) - return Diag(SPV_ERROR_INVALID_BINARY) - << "Failed to read id_was_forward_declared flag"; - - if (id_was_forward_declared) { - if (!reader_.ReadVariableWidthU32(&rank, model_->mtf_rank_chunk_length())) - return Diag(SPV_ERROR_INVALID_BINARY) - << "Failed to read MTF rank of forward declared id"; - - if (rank) { - // The id was forward declared, recover it from kMtfForwardDeclared. - if (!multi_mtf_.ValueFromRank(kMtfForwardDeclared, rank, - &inst_.result_id)) - return Diag(SPV_ERROR_INTERNAL) - << "Forward declared MTF rank is out of bounds"; - - // We can now remove the id from kMtfForwardDeclared. - if (!multi_mtf_.Remove(kMtfForwardDeclared, inst_.result_id)) - return Diag(SPV_ERROR_INTERNAL) - << "Failed to remove id from kMtfForwardDeclared"; - } - } - } - - if (inst_.result_id == 0) { - // The id was not forward declared, issue a new id. - inst_.result_id = GetIdBound(); - SetIdBound(inst_.result_id + 1); - } - - if (model_->id_fallback_strategy() == - MarkvModel::IdFallbackStrategy::kRuleBased) { - if (!rank) { - multi_mtf_.Insert(kMtfAll, inst_.result_id); - } - } - - return SPV_SUCCESS; -} - -spv_result_t MarkvDecoder::DecodeLiteralNumber( - const spv_parsed_operand_t& operand) { - if (operand.number_bit_width <= 32) { - uint32_t word = 0; - const spv_result_t result = DecodeNonIdWord(&word); - if (result != SPV_SUCCESS) return result; - inst_words_.push_back(word); - } else { - assert(operand.number_bit_width <= 64); - uint64_t word = 0; - if (operand.number_kind == SPV_NUMBER_UNSIGNED_INT) { - if (!reader_.ReadVariableWidthU64(&word, model_->u64_chunk_length())) - return Diag(SPV_ERROR_INVALID_BINARY) << "Failed to read literal U64"; - } else if (operand.number_kind == SPV_NUMBER_SIGNED_INT) { - int64_t val = 0; - if (!reader_.ReadVariableWidthS64(&val, model_->s64_chunk_length(), - model_->s64_block_exponent())) - return Diag(SPV_ERROR_INVALID_BINARY) << "Failed to read literal S64"; - std::memcpy(&word, &val, 8); - } else if (operand.number_kind == SPV_NUMBER_FLOATING) { - if (!reader_.ReadUnencoded(&word)) - return Diag(SPV_ERROR_INVALID_BINARY) << "Failed to read literal F64"; - } else { - return Diag(SPV_ERROR_INTERNAL) << "Unsupported bit length"; - } - inst_words_.push_back(static_cast(word)); - inst_words_.push_back(static_cast(word >> 32)); - } - return SPV_SUCCESS; -} - -bool MarkvDecoder::ReadToByteBreak(size_t byte_break_if_less_than) { - const size_t num_bits_to_next_byte = - GetNumBitsToNextByte(reader_.GetNumReadBits()); - if (num_bits_to_next_byte == 0 || - num_bits_to_next_byte > byte_break_if_less_than) - return true; - - uint64_t bits = 0; - if (!reader_.ReadBits(&bits, num_bits_to_next_byte)) return false; - - assert(bits == 0); - if (bits != 0) return false; - - return true; -} - -spv_result_t MarkvDecoder::DecodeModule(std::vector* spirv_binary) { - const bool header_read_success = - reader_.ReadUnencoded(&header_.magic_number) && - reader_.ReadUnencoded(&header_.markv_version) && - reader_.ReadUnencoded(&header_.markv_model) && - reader_.ReadUnencoded(&header_.markv_length_in_bits) && - reader_.ReadUnencoded(&header_.spirv_version) && - reader_.ReadUnencoded(&header_.spirv_generator); - - if (!header_read_success) - return Diag(SPV_ERROR_INVALID_BINARY) << "Unable to read MARK-V header"; - - if (header_.markv_length_in_bits == 0) - return Diag(SPV_ERROR_INVALID_BINARY) - << "Header markv_length_in_bits field is zero"; - - if (header_.magic_number != MarkvCodec::kMarkvMagicNumber) - return Diag(SPV_ERROR_INVALID_BINARY) - << "MARK-V binary has incorrect magic number"; - - // TODO(atgoo@github.com): Print version strings. - if (header_.markv_version != MarkvCodec::GetMarkvVersion()) - return Diag(SPV_ERROR_INVALID_BINARY) - << "MARK-V binary and the codec have different versions"; - - const uint32_t model_type = header_.markv_model >> 16; - const uint32_t model_version = header_.markv_model & 0xFFFF; - if (model_type != model_->model_type()) - return Diag(SPV_ERROR_INVALID_BINARY) - << "MARK-V binary and the codec use different MARK-V models"; - - if (model_version != model_->model_version()) - return Diag(SPV_ERROR_INVALID_BINARY) - << "MARK-V binary and the codec use different versions if the same " - << "MARK-V model"; - - spirv_.reserve(header_.markv_length_in_bits / 2); // Heuristic. - spirv_.resize(5, 0); - spirv_[0] = SpvMagicNumber; - spirv_[1] = header_.spirv_version; - spirv_[2] = header_.spirv_generator; - - if (logger_) { - reader_.SetCallback( - [this](const std::string& str) { logger_->AppendBitSequence(str); }); - } - - while (reader_.GetNumReadBits() < header_.markv_length_in_bits) { - inst_ = {}; - const spv_result_t decode_result = DecodeInstruction(); - if (decode_result != SPV_SUCCESS) return decode_result; - } - - if (validator_options_) { - spv_const_binary_t validation_binary = {spirv_.data(), spirv_.size()}; - const spv_result_t result = spvValidateWithOptions( - context_, validator_options_, &validation_binary, nullptr); - if (result != SPV_SUCCESS) return result; - } - - // Validate the decode binary - if (reader_.GetNumReadBits() != header_.markv_length_in_bits || - !reader_.OnlyZeroesLeft()) { - return Diag(SPV_ERROR_INVALID_BINARY) - << "MARK-V binary has wrong stated bit length " - << reader_.GetNumReadBits() << " " << header_.markv_length_in_bits; - } - - // Decoding of the module is finished, validation state should have correct - // id bound. - spirv_[3] = GetIdBound(); - - *spirv_binary = std::move(spirv_); - return SPV_SUCCESS; -} - -// TODO(atgoo@github.com): The implementation borrows heavily from -// Parser::parseOperand. -// Consider coupling them together in some way once MARK-V codec is more mature. -// For now it's better to keep the code independent for experimentation -// purposes. -spv_result_t MarkvDecoder::DecodeOperand( - size_t operand_offset, const spv_operand_type_t type, - spv_operand_pattern_t* expected_operands) { - const SpvOp opcode = static_cast(inst_.opcode); - - memset(&operand_, 0, sizeof(operand_)); - - assert((operand_offset >> 16) == 0); - operand_.offset = static_cast(operand_offset); - operand_.type = type; - - // Set default values, may be updated later. - operand_.number_kind = SPV_NUMBER_NONE; - operand_.number_bit_width = 0; - - const size_t first_word_index = inst_words_.size(); - - switch (type) { - case SPV_OPERAND_TYPE_RESULT_ID: { - const spv_result_t result = DecodeResultId(); - if (result != SPV_SUCCESS) return result; - - inst_words_.push_back(inst_.result_id); - SetIdBound(std::max(GetIdBound(), inst_.result_id + 1)); - PromoteIfNeeded(inst_.result_id); - break; - } - - case SPV_OPERAND_TYPE_TYPE_ID: { - const spv_result_t result = DecodeTypeId(); - if (result != SPV_SUCCESS) return result; - - inst_words_.push_back(inst_.type_id); - SetIdBound(std::max(GetIdBound(), inst_.type_id + 1)); - PromoteIfNeeded(inst_.type_id); - break; - } - - case SPV_OPERAND_TYPE_ID: - case SPV_OPERAND_TYPE_OPTIONAL_ID: - case SPV_OPERAND_TYPE_SCOPE_ID: - case SPV_OPERAND_TYPE_MEMORY_SEMANTICS_ID: { - uint32_t id = 0; - const spv_result_t result = DecodeRefId(&id); - if (result != SPV_SUCCESS) return result; - - if (id == 0) return Diag(SPV_ERROR_INVALID_BINARY) << "Decoded id is 0"; - - if (type == SPV_OPERAND_TYPE_ID || type == SPV_OPERAND_TYPE_OPTIONAL_ID) { - operand_.type = SPV_OPERAND_TYPE_ID; - - if (opcode == SpvOpExtInst && operand_.offset == 3) { - // The current word is the extended instruction set id. - // Set the extended instruction set type for the current - // instruction. - auto ext_inst_type_iter = import_id_to_ext_inst_type_.find(id); - if (ext_inst_type_iter == import_id_to_ext_inst_type_.end()) { - return Diag(SPV_ERROR_INVALID_ID) - << "OpExtInst set id " << id - << " does not reference an OpExtInstImport result Id"; - } - inst_.ext_inst_type = ext_inst_type_iter->second; - } - } - - inst_words_.push_back(id); - SetIdBound(std::max(GetIdBound(), id + 1)); - PromoteIfNeeded(id); - break; - } - - case SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER: { - uint32_t word = 0; - const spv_result_t result = DecodeNonIdWord(&word); - if (result != SPV_SUCCESS) return result; - - inst_words_.push_back(word); - - assert(SpvOpExtInst == opcode); - assert(inst_.ext_inst_type != SPV_EXT_INST_TYPE_NONE); - spv_ext_inst_desc ext_inst; - if (grammar_.lookupExtInst(inst_.ext_inst_type, word, &ext_inst)) - return Diag(SPV_ERROR_INVALID_BINARY) - << "Invalid extended instruction number: " << word; - spvPushOperandTypes(ext_inst->operandTypes, expected_operands); - break; - } - - case SPV_OPERAND_TYPE_LITERAL_INTEGER: - case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_INTEGER: { - // These are regular single-word literal integer operands. - // Post-parsing validation should check the range of the parsed value. - operand_.type = SPV_OPERAND_TYPE_LITERAL_INTEGER; - // It turns out they are always unsigned integers! - operand_.number_kind = SPV_NUMBER_UNSIGNED_INT; - operand_.number_bit_width = 32; - - uint32_t word = 0; - const spv_result_t result = DecodeNonIdWord(&word); - if (result != SPV_SUCCESS) return result; - - inst_words_.push_back(word); - break; - } - - case SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER: - case SPV_OPERAND_TYPE_OPTIONAL_TYPED_LITERAL_INTEGER: { - operand_.type = SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER; - if (opcode == SpvOpSwitch) { - // The literal operands have the same type as the value - // referenced by the selector Id. - const uint32_t selector_id = inst_words_.at(1); - const auto type_id_iter = id_to_type_id_.find(selector_id); - if (type_id_iter == id_to_type_id_.end() || type_id_iter->second == 0) { - return Diag(SPV_ERROR_INVALID_BINARY) - << "Invalid OpSwitch: selector id " << selector_id - << " has no type"; - } - uint32_t type_id = type_id_iter->second; - - if (selector_id == type_id) { - // Recall that by convention, a result ID that is a type definition - // maps to itself. - return Diag(SPV_ERROR_INVALID_BINARY) - << "Invalid OpSwitch: selector id " << selector_id - << " is a type, not a value"; - } - if (auto error = SetNumericTypeInfoForType(&operand_, type_id)) - return error; - if (operand_.number_kind != SPV_NUMBER_UNSIGNED_INT && - operand_.number_kind != SPV_NUMBER_SIGNED_INT) { - return Diag(SPV_ERROR_INVALID_BINARY) - << "Invalid OpSwitch: selector id " << selector_id - << " is not a scalar integer"; - } - } else { - assert(opcode == SpvOpConstant || opcode == SpvOpSpecConstant); - // The literal number type is determined by the type Id for the - // constant. - assert(inst_.type_id); - if (auto error = SetNumericTypeInfoForType(&operand_, inst_.type_id)) - return error; - } - - if (auto error = DecodeLiteralNumber(operand_)) return error; - - break; - } - - case SPV_OPERAND_TYPE_LITERAL_STRING: - case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_STRING: { - operand_.type = SPV_OPERAND_TYPE_LITERAL_STRING; - std::vector str; - auto* codec = model_->GetLiteralStringHuffmanCodec(inst_.opcode); - - if (codec) { - std::string decoded_string; - const bool huffman_result = - codec->DecodeFromStream(GetReadBitCallback(), &decoded_string); - assert(huffman_result); - if (!huffman_result) - return Diag(SPV_ERROR_INVALID_BINARY) - << "Failed to read literal string"; - - if (decoded_string != "kMarkvNoneOfTheAbove") { - std::copy(decoded_string.begin(), decoded_string.end(), - std::back_inserter(str)); - str.push_back('\0'); - } - } - - // The loop is expected to terminate once we encounter '\0' or exhaust - // the bit stream. - if (str.empty()) { - while (true) { - char ch = 0; - if (!reader_.ReadUnencoded(&ch)) - return Diag(SPV_ERROR_INVALID_BINARY) - << "Failed to read literal string"; - - str.push_back(ch); - - if (ch == '\0') break; - } - } - - while (str.size() % 4 != 0) str.push_back('\0'); - - inst_words_.resize(inst_words_.size() + str.size() / 4); - std::memcpy(&inst_words_[first_word_index], str.data(), str.size()); - - if (SpvOpExtInstImport == opcode) { - // Record the extended instruction type for the ID for this import. - // There is only one string literal argument to OpExtInstImport, - // so it's sufficient to guard this just on the opcode. - const spv_ext_inst_type_t ext_inst_type = - spvExtInstImportTypeGet(str.data()); - if (SPV_EXT_INST_TYPE_NONE == ext_inst_type) { - return Diag(SPV_ERROR_INVALID_BINARY) - << "Invalid extended instruction import '" << str.data() - << "'"; - } - // We must have parsed a valid result ID. It's a condition - // of the grammar, and we only accept non-zero result Ids. - assert(inst_.result_id); - const bool inserted = - import_id_to_ext_inst_type_.emplace(inst_.result_id, ext_inst_type) - .second; - (void)inserted; - assert(inserted); - } - break; - } - - case SPV_OPERAND_TYPE_CAPABILITY: - case SPV_OPERAND_TYPE_SOURCE_LANGUAGE: - case SPV_OPERAND_TYPE_EXECUTION_MODEL: - case SPV_OPERAND_TYPE_ADDRESSING_MODEL: - case SPV_OPERAND_TYPE_MEMORY_MODEL: - case SPV_OPERAND_TYPE_EXECUTION_MODE: - case SPV_OPERAND_TYPE_STORAGE_CLASS: - case SPV_OPERAND_TYPE_DIMENSIONALITY: - case SPV_OPERAND_TYPE_SAMPLER_ADDRESSING_MODE: - case SPV_OPERAND_TYPE_SAMPLER_FILTER_MODE: - case SPV_OPERAND_TYPE_SAMPLER_IMAGE_FORMAT: - case SPV_OPERAND_TYPE_FP_ROUNDING_MODE: - case SPV_OPERAND_TYPE_LINKAGE_TYPE: - case SPV_OPERAND_TYPE_ACCESS_QUALIFIER: - case SPV_OPERAND_TYPE_OPTIONAL_ACCESS_QUALIFIER: - case SPV_OPERAND_TYPE_FUNCTION_PARAMETER_ATTRIBUTE: - case SPV_OPERAND_TYPE_DECORATION: - case SPV_OPERAND_TYPE_BUILT_IN: - case SPV_OPERAND_TYPE_GROUP_OPERATION: - case SPV_OPERAND_TYPE_KERNEL_ENQ_FLAGS: - case SPV_OPERAND_TYPE_KERNEL_PROFILING_INFO: { - // A single word that is a plain enum value. - uint32_t word = 0; - const spv_result_t result = DecodeNonIdWord(&word); - if (result != SPV_SUCCESS) return result; - - inst_words_.push_back(word); - - // Map an optional operand type to its corresponding concrete type. - if (type == SPV_OPERAND_TYPE_OPTIONAL_ACCESS_QUALIFIER) - operand_.type = SPV_OPERAND_TYPE_ACCESS_QUALIFIER; - - spv_operand_desc entry; - if (grammar_.lookupOperand(type, word, &entry)) { - return Diag(SPV_ERROR_INVALID_BINARY) - << "Invalid " << spvOperandTypeStr(operand_.type) - << " operand: " << word; - } - - // Prepare to accept operands to this operand, if needed. - spvPushOperandTypes(entry->operandTypes, expected_operands); - break; - } - - case SPV_OPERAND_TYPE_FP_FAST_MATH_MODE: - case SPV_OPERAND_TYPE_FUNCTION_CONTROL: - case SPV_OPERAND_TYPE_LOOP_CONTROL: - case SPV_OPERAND_TYPE_IMAGE: - case SPV_OPERAND_TYPE_OPTIONAL_IMAGE: - case SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS: - case SPV_OPERAND_TYPE_SELECTION_CONTROL: { - // This operand is a mask. - uint32_t word = 0; - const spv_result_t result = DecodeNonIdWord(&word); - if (result != SPV_SUCCESS) return result; - - inst_words_.push_back(word); - - // Map an optional operand type to its corresponding concrete type. - if (type == SPV_OPERAND_TYPE_OPTIONAL_IMAGE) - operand_.type = SPV_OPERAND_TYPE_IMAGE; - else if (type == SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS) - operand_.type = SPV_OPERAND_TYPE_MEMORY_ACCESS; - - // Check validity of set mask bits. Also prepare for operands for those - // masks if they have any. To get operand order correct, scan from - // MSB to LSB since we can only prepend operands to a pattern. - // The only case in the grammar where you have more than one mask bit - // having an operand is for image operands. See SPIR-V 3.14 Image - // Operands. - uint32_t remaining_word = word; - for (uint32_t mask = (1u << 31); remaining_word; mask >>= 1) { - if (remaining_word & mask) { - spv_operand_desc entry; - if (grammar_.lookupOperand(type, mask, &entry)) { - return Diag(SPV_ERROR_INVALID_BINARY) - << "Invalid " << spvOperandTypeStr(operand_.type) - << " operand: " << word << " has invalid mask component " - << mask; - } - remaining_word ^= mask; - spvPushOperandTypes(entry->operandTypes, expected_operands); - } - } - if (word == 0) { - // An all-zeroes mask *might* also be valid. - spv_operand_desc entry; - if (SPV_SUCCESS == grammar_.lookupOperand(type, 0, &entry)) { - // Prepare for its operands, if any. - spvPushOperandTypes(entry->operandTypes, expected_operands); - } - } - break; - } - default: - return Diag(SPV_ERROR_INVALID_BINARY) - << "Internal error: Unhandled operand type: " << type; - } - - operand_.num_words = uint16_t(inst_words_.size() - first_word_index); - - assert(spvOperandIsConcrete(operand_.type)); - - parsed_operands_.push_back(operand_); - - return SPV_SUCCESS; -} - -spv_result_t MarkvDecoder::DecodeInstruction() { - parsed_operands_.clear(); - inst_words_.clear(); - - // Opcode/num_words placeholder, the word will be filled in later. - inst_words_.push_back(0); - - bool num_operands_still_unknown = true; - { - uint32_t opcode = 0; - uint32_t num_operands = 0; - - const spv_result_t opcode_decoding_result = - DecodeOpcodeAndNumberOfOperands(&opcode, &num_operands); - if (opcode_decoding_result < 0) return opcode_decoding_result; - - if (opcode_decoding_result == SPV_SUCCESS) { - inst_.num_operands = static_cast(num_operands); - num_operands_still_unknown = false; - } else { - if (!reader_.ReadVariableWidthU32(&opcode, - model_->opcode_chunk_length())) { - return Diag(SPV_ERROR_INVALID_BINARY) - << "Failed to read opcode of instruction"; - } - } - - inst_.opcode = static_cast(opcode); - } - - const SpvOp opcode = static_cast(inst_.opcode); - - spv_opcode_desc opcode_desc; - if (grammar_.lookupOpcode(opcode, &opcode_desc) != SPV_SUCCESS) { - return Diag(SPV_ERROR_INVALID_BINARY) << "Invalid opcode"; - } - - spv_operand_pattern_t expected_operands; - expected_operands.reserve(opcode_desc->numTypes); - for (auto i = 0; i < opcode_desc->numTypes; i++) { - expected_operands.push_back( - opcode_desc->operandTypes[opcode_desc->numTypes - i - 1]); - } - - if (num_operands_still_unknown) { - if (!OpcodeHasFixedNumberOfOperands(opcode)) { - if (!reader_.ReadVariableWidthU16(&inst_.num_operands, - model_->num_operands_chunk_length())) - return Diag(SPV_ERROR_INVALID_BINARY) - << "Failed to read num_operands of instruction"; - } else { - inst_.num_operands = static_cast(expected_operands.size()); - } - } - - for (operand_index_ = 0; - operand_index_ < static_cast(inst_.num_operands); - ++operand_index_) { - assert(!expected_operands.empty()); - const spv_operand_type_t type = - spvTakeFirstMatchableOperand(&expected_operands); - - const size_t operand_offset = inst_words_.size(); - - const spv_result_t decode_result = - DecodeOperand(operand_offset, type, &expected_operands); - - if (decode_result != SPV_SUCCESS) return decode_result; - } - - assert(inst_.num_operands == parsed_operands_.size()); - - // Only valid while inst_words_ and parsed_operands_ remain unchanged (until - // next DecodeInstruction call). - inst_.words = inst_words_.data(); - inst_.operands = parsed_operands_.empty() ? nullptr : parsed_operands_.data(); - inst_.num_words = static_cast(inst_words_.size()); - inst_words_[0] = spvOpcodeMake(inst_.num_words, SpvOp(inst_.opcode)); - - std::copy(inst_words_.begin(), inst_words_.end(), std::back_inserter(spirv_)); - - assert(inst_.num_words == - std::accumulate( - parsed_operands_.begin(), parsed_operands_.end(), 1, - [](int num_words, const spv_parsed_operand_t& operand) { - return num_words += operand.num_words; - }) && - "num_words in instruction doesn't correspond to the sum of num_words" - "in the operands"); - - RecordNumberType(); - ProcessCurInstruction(); - - if (!ReadToByteBreak(MarkvCodec::kByteBreakAfterInstIfLessThanUntilNextByte)) - return Diag(SPV_ERROR_INVALID_BINARY) << "Failed to read to byte break"; - - if (logger_) { - logger_->NewLine(); - std::stringstream ss; - ss << spvOpcodeString(opcode) << " "; - for (size_t index = 1; index < inst_words_.size(); ++index) - ss << inst_words_[index] << " "; - logger_->AppendText(ss.str()); - logger_->NewLine(); - logger_->NewLine(); - if (!logger_->DebugInstruction(inst_)) return SPV_REQUESTED_TERMINATION; - } - - return SPV_SUCCESS; -} - -spv_result_t MarkvDecoder::SetNumericTypeInfoForType( - spv_parsed_operand_t* parsed_operand, uint32_t type_id) { - assert(type_id != 0); - auto type_info_iter = type_id_to_number_type_info_.find(type_id); - if (type_info_iter == type_id_to_number_type_info_.end()) { - return Diag(SPV_ERROR_INVALID_BINARY) - << "Type Id " << type_id << " is not a type"; - } - - const NumberType& info = type_info_iter->second; - if (info.type == SPV_NUMBER_NONE) { - // This is a valid type, but for something other than a scalar number. - return Diag(SPV_ERROR_INVALID_BINARY) - << "Type Id " << type_id << " is not a scalar numeric type"; - } - - parsed_operand->number_kind = info.type; - parsed_operand->number_bit_width = info.bit_width; - // Round up the word count. - parsed_operand->num_words = static_cast((info.bit_width + 31) / 32); - return SPV_SUCCESS; -} - -void MarkvDecoder::RecordNumberType() { - const SpvOp opcode = static_cast(inst_.opcode); - if (spvOpcodeGeneratesType(opcode)) { - NumberType info = {SPV_NUMBER_NONE, 0}; - if (SpvOpTypeInt == opcode) { - info.bit_width = inst_.words[inst_.operands[1].offset]; - info.type = inst_.words[inst_.operands[2].offset] - ? SPV_NUMBER_SIGNED_INT - : SPV_NUMBER_UNSIGNED_INT; - } else if (SpvOpTypeFloat == opcode) { - info.bit_width = inst_.words[inst_.operands[1].offset]; - info.type = SPV_NUMBER_FLOATING; - } - // The *result* Id of a type generating instruction is the type Id. - type_id_to_number_type_info_[inst_.result_id] = info; - } -} - -} // namespace comp -} // namespace spvtools diff --git a/third_party/spirv-tools/source/comp/markv_decoder.h b/third_party/spirv-tools/source/comp/markv_decoder.h deleted file mode 100644 index 4d8402b442..0000000000 --- a/third_party/spirv-tools/source/comp/markv_decoder.h +++ /dev/null @@ -1,175 +0,0 @@ -// Copyright (c) 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/comp/bit_stream.h" -#include "source/comp/markv.h" -#include "source/comp/markv_codec.h" -#include "source/comp/markv_logger.h" -#include "source/util/make_unique.h" - -#ifndef SOURCE_COMP_MARKV_DECODER_H_ -#define SOURCE_COMP_MARKV_DECODER_H_ - -namespace spvtools { -namespace comp { - -class MarkvLogger; - -// Decodes MARK-V buffers written by MarkvEncoder. -class MarkvDecoder : public MarkvCodec { - public: - // |model| is owned by the caller, must be not null and valid during the - // lifetime of MarkvEncoder. - MarkvDecoder(spv_const_context context, const std::vector& markv, - const MarkvCodecOptions& options, const MarkvModel* model) - : MarkvCodec(context, GetValidatorOptions(options), model), - options_(options), - reader_(markv) { - SetIdBound(1); - parsed_operands_.reserve(25); - inst_words_.reserve(25); - } - ~MarkvDecoder() = default; - - // Creates an internal logger which writes comments on the decoding process. - void CreateLogger(MarkvLogConsumer log_consumer, - MarkvDebugConsumer debug_consumer) { - logger_ = MakeUnique(log_consumer, debug_consumer); - } - - // Decodes SPIR-V from MARK-V and stores the words in |spirv_binary|. - // Can be called only once. Fails if data of wrong format or ends prematurely, - // of if validation fails. - spv_result_t DecodeModule(std::vector* spirv_binary); - - // Creates and returns validator options. Returned value owned by the caller. - static spv_validator_options GetValidatorOptions( - const MarkvCodecOptions& options) { - return options.validate_spirv_binary ? spvValidatorOptionsCreate() - : nullptr; - } - - private: - // Describes the format of a typed literal number. - struct NumberType { - spv_number_kind_t type; - uint32_t bit_width; - }; - - // Reads a single bit from reader_. The read bit is stored in |bit|. - // Returns false iff reader_ fails. - bool ReadBit(bool* bit) { - uint64_t bits = 0; - const bool result = reader_.ReadBits(&bits, 1); - if (result) *bit = bits ? true : false; - return result; - }; - - // Returns ReadBit bound to the class object. - std::function GetReadBitCallback() { - return std::bind(&MarkvDecoder::ReadBit, this, std::placeholders::_1); - } - - // Reads a single non-id word from bit stream. operand_.type determines if - // the word needs to be decoded and how. - spv_result_t DecodeNonIdWord(uint32_t* word); - - // Reads and decodes both opcode and num_operands as a single code. - // Returns SPV_UNSUPPORTED iff no suitable codec was found. - spv_result_t DecodeOpcodeAndNumberOfOperands(uint32_t* opcode, - uint32_t* num_operands); - - // Reads mtf rank from bit stream. |mtf| is used to determine the codec - // scheme. |fallback_method| is used if no codec defined for |mtf|. - spv_result_t DecodeMtfRankHuffman(uint64_t mtf, uint32_t fallback_method, - uint32_t* rank); - - // Reads id using coding based on mtf associated with the id descriptor. - // Returns SPV_UNSUPPORTED iff fallback method needs to be used. - spv_result_t DecodeIdWithDescriptor(uint32_t* id); - - // Reads id using coding based on the given |mtf|, which is expected to - // contain the needed |id|. - spv_result_t DecodeExistingId(uint64_t mtf, uint32_t* id); - - // Reads type id of the current instruction if can't be inferred. - spv_result_t DecodeTypeId(); - - // Reads result id of the current instruction if can't be inferred. - spv_result_t DecodeResultId(); - - // Reads id which is neither type nor result id. - spv_result_t DecodeRefId(uint32_t* id); - - // Reads and discards bits until the beginning of the next byte if the - // number of bits until the next byte is less than |byte_break_if_less_than|. - bool ReadToByteBreak(size_t byte_break_if_less_than); - - // Returns instruction words decoded up to this point. - const uint32_t* GetInstWords() const override { return inst_words_.data(); } - - // Reads a literal number as it is described in |operand| from the bit stream, - // decodes and writes it to spirv_. - spv_result_t DecodeLiteralNumber(const spv_parsed_operand_t& operand); - - // Reads instruction from bit stream, decodes and validates it. - // Decoded instruction is valid until the next call of DecodeInstruction(). - spv_result_t DecodeInstruction(); - - // Read operand from the stream decodes and validates it. - spv_result_t DecodeOperand(size_t operand_offset, - const spv_operand_type_t type, - spv_operand_pattern_t* expected_operands); - - // Records the numeric type for an operand according to the type information - // associated with the given non-zero type Id. This can fail if the type Id - // is not a type Id, or if the type Id does not reference a scalar numeric - // type. On success, return SPV_SUCCESS and populates the num_words, - // number_kind, and number_bit_width fields of parsed_operand. - spv_result_t SetNumericTypeInfoForType(spv_parsed_operand_t* parsed_operand, - uint32_t type_id); - - // Records the number type for the current instruction, if it generates a - // type. For types that aren't scalar numbers, record something with number - // kind SPV_NUMBER_NONE. - void RecordNumberType(); - - MarkvCodecOptions options_; - - // Temporary sink where decoded SPIR-V words are written. Once it contains the - // entire module, the container is moved and returned. - std::vector spirv_; - - // Bit stream containing encoded data. - BitReaderWord64 reader_; - - // Temporary storage for operands of the currently parsed instruction. - // Valid until next DecodeInstruction call. - std::vector parsed_operands_; - - // Temporary storage for current instruction words. - // Valid until next DecodeInstruction call. - std::vector inst_words_; - - // Maps a type ID to its number type description. - std::unordered_map type_id_to_number_type_info_; - - // Maps an ExtInstImport id to the extended instruction type. - std::unordered_map import_id_to_ext_inst_type_; -}; - -} // namespace comp -} // namespace spvtools - -#endif // SOURCE_COMP_MARKV_DECODER_H_ diff --git a/third_party/spirv-tools/source/comp/markv_encoder.cpp b/third_party/spirv-tools/source/comp/markv_encoder.cpp deleted file mode 100644 index 1abd586460..0000000000 --- a/third_party/spirv-tools/source/comp/markv_encoder.cpp +++ /dev/null @@ -1,486 +0,0 @@ -// Copyright (c) 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/comp/markv_encoder.h" - -#include "source/binary.h" -#include "source/opcode.h" -#include "spirv-tools/libspirv.hpp" - -namespace spvtools { -namespace comp { -namespace { - -const size_t kCommentNumWhitespaces = 2; - -} // namespace - -spv_result_t MarkvEncoder::EncodeNonIdWord(uint32_t word) { - auto* codec = model_->GetNonIdWordHuffmanCodec(inst_.opcode, operand_index_); - - if (codec) { - uint64_t bits = 0; - size_t num_bits = 0; - if (codec->Encode(word, &bits, &num_bits)) { - // Encoding successful. - writer_.WriteBits(bits, num_bits); - return SPV_SUCCESS; - } else { - // Encoding failed, write kMarkvNoneOfTheAbove flag. - if (!codec->Encode(MarkvModel::GetMarkvNoneOfTheAbove(), &bits, - &num_bits)) - return Diag(SPV_ERROR_INTERNAL) - << "Non-id word Huffman table for " - << spvOpcodeString(SpvOp(inst_.opcode)) << " operand index " - << operand_index_ << " is missing kMarkvNoneOfTheAbove"; - writer_.WriteBits(bits, num_bits); - } - } - - // Fallback encoding. - const size_t chunk_length = - model_->GetOperandVariableWidthChunkLength(operand_.type); - if (chunk_length) { - writer_.WriteVariableWidthU32(word, chunk_length); - } else { - writer_.WriteUnencoded(word); - } - return SPV_SUCCESS; -} - -spv_result_t MarkvEncoder::EncodeOpcodeAndNumOperands(uint32_t opcode, - uint32_t num_operands) { - uint64_t bits = 0; - size_t num_bits = 0; - - const uint32_t word = opcode | (num_operands << 16); - - // First try to use the Markov chain codec. - auto* codec = - model_->GetOpcodeAndNumOperandsMarkovHuffmanCodec(GetPrevOpcode()); - if (codec) { - if (codec->Encode(word, &bits, &num_bits)) { - // The word was successfully encoded into bits/num_bits. - writer_.WriteBits(bits, num_bits); - return SPV_SUCCESS; - } else { - // The word is not in the Huffman table. Write kMarkvNoneOfTheAbove - // and use fallback encoding. - if (!codec->Encode(MarkvModel::GetMarkvNoneOfTheAbove(), &bits, - &num_bits)) - return Diag(SPV_ERROR_INTERNAL) - << "opcode_and_num_operands Huffman table for " - << spvOpcodeString(GetPrevOpcode()) - << "is missing kMarkvNoneOfTheAbove"; - writer_.WriteBits(bits, num_bits); - } - } - - // Fallback to base-rate codec. - codec = model_->GetOpcodeAndNumOperandsMarkovHuffmanCodec(SpvOpNop); - assert(codec); - if (codec->Encode(word, &bits, &num_bits)) { - // The word was successfully encoded into bits/num_bits. - writer_.WriteBits(bits, num_bits); - return SPV_SUCCESS; - } else { - // The word is not in the Huffman table. Write kMarkvNoneOfTheAbove - // and return false. - if (!codec->Encode(MarkvModel::GetMarkvNoneOfTheAbove(), &bits, &num_bits)) - return Diag(SPV_ERROR_INTERNAL) - << "Global opcode_and_num_operands Huffman table is missing " - << "kMarkvNoneOfTheAbove"; - writer_.WriteBits(bits, num_bits); - return SPV_UNSUPPORTED; - } -} - -spv_result_t MarkvEncoder::EncodeMtfRankHuffman(uint32_t rank, uint64_t mtf, - uint64_t fallback_method) { - const auto* codec = GetMtfHuffmanCodec(mtf); - if (!codec) { - assert(fallback_method != kMtfNone); - codec = GetMtfHuffmanCodec(fallback_method); - } - - if (!codec) return Diag(SPV_ERROR_INTERNAL) << "No codec to encode MTF rank"; - - uint64_t bits = 0; - size_t num_bits = 0; - if (rank < MarkvCodec::kMtfSmallestRankEncodedByValue) { - // Encode using Huffman coding. - if (!codec->Encode(rank, &bits, &num_bits)) - return Diag(SPV_ERROR_INTERNAL) - << "Failed to encode MTF rank with Huffman"; - - writer_.WriteBits(bits, num_bits); - } else { - // Encode by value. - if (!codec->Encode(MarkvCodec::kMtfRankEncodedByValueSignal, &bits, - &num_bits)) - return Diag(SPV_ERROR_INTERNAL) - << "Failed to encode kMtfRankEncodedByValueSignal"; - - writer_.WriteBits(bits, num_bits); - writer_.WriteVariableWidthU32( - rank - MarkvCodec::kMtfSmallestRankEncodedByValue, - model_->mtf_rank_chunk_length()); - } - return SPV_SUCCESS; -} - -spv_result_t MarkvEncoder::EncodeIdWithDescriptor(uint32_t id) { - // Get the descriptor for id. - const uint32_t long_descriptor = long_id_descriptors_.GetDescriptor(id); - auto* codec = - model_->GetIdDescriptorHuffmanCodec(inst_.opcode, operand_index_); - uint64_t bits = 0; - size_t num_bits = 0; - uint64_t mtf = kMtfNone; - if (long_descriptor && codec && - codec->Encode(long_descriptor, &bits, &num_bits)) { - // If the descriptor exists and is in the table, write the descriptor and - // proceed to encoding the rank. - writer_.WriteBits(bits, num_bits); - mtf = GetMtfLongIdDescriptor(long_descriptor); - } else { - if (codec) { - // The descriptor doesn't exist or we have no coding for it. Write - // kMarkvNoneOfTheAbove and go to fallback method. - if (!codec->Encode(MarkvModel::GetMarkvNoneOfTheAbove(), &bits, - &num_bits)) - return Diag(SPV_ERROR_INTERNAL) - << "Descriptor Huffman table for " - << spvOpcodeString(SpvOp(inst_.opcode)) << " operand index " - << operand_index_ << " is missing kMarkvNoneOfTheAbove"; - - writer_.WriteBits(bits, num_bits); - } - - if (model_->id_fallback_strategy() != - MarkvModel::IdFallbackStrategy::kShortDescriptor) { - return SPV_UNSUPPORTED; - } - - const uint32_t short_descriptor = short_id_descriptors_.GetDescriptor(id); - writer_.WriteBits(short_descriptor, MarkvCodec::kShortDescriptorNumBits); - - if (short_descriptor == 0) { - // Forward declared id. - return SPV_UNSUPPORTED; - } - - mtf = GetMtfShortIdDescriptor(short_descriptor); - } - - // Descriptor has been encoded. Now encode the rank of the id in the - // associated mtf sequence. - return EncodeExistingId(mtf, id); -} - -spv_result_t MarkvEncoder::EncodeExistingId(uint64_t mtf, uint32_t id) { - assert(multi_mtf_.GetSize(mtf) > 0); - if (multi_mtf_.GetSize(mtf) == 1) { - // If the sequence has only one element no need to write rank, the decoder - // would make the same decision. - return SPV_SUCCESS; - } - - uint32_t rank = 0; - if (!multi_mtf_.RankFromValue(mtf, id, &rank)) - return Diag(SPV_ERROR_INTERNAL) << "Id is not in the MTF sequence"; - - return EncodeMtfRankHuffman(rank, mtf, kMtfGenericNonZeroRank); -} - -spv_result_t MarkvEncoder::EncodeRefId(uint32_t id) { - { - // Try to encode using id descriptor mtfs. - const spv_result_t result = EncodeIdWithDescriptor(id); - if (result != SPV_UNSUPPORTED) return result; - // If can't be done continue with other methods. - } - - const bool can_forward_declare = spvOperandCanBeForwardDeclaredFunction( - SpvOp(inst_.opcode))(operand_index_); - uint32_t rank = 0; - - if (model_->id_fallback_strategy() == - MarkvModel::IdFallbackStrategy::kRuleBased) { - // Encode using rule-based mtf. - uint64_t mtf = GetRuleBasedMtf(); - - if (mtf != kMtfNone && !can_forward_declare) { - assert(multi_mtf_.HasValue(kMtfAll, id)); - return EncodeExistingId(mtf, id); - } - - if (mtf == kMtfNone) mtf = kMtfAll; - - if (!multi_mtf_.RankFromValue(mtf, id, &rank)) { - // This is the first occurrence of a forward declared id. - multi_mtf_.Insert(kMtfAll, id); - multi_mtf_.Insert(kMtfForwardDeclared, id); - if (mtf != kMtfAll) multi_mtf_.Insert(mtf, id); - rank = 0; - } - - return EncodeMtfRankHuffman(rank, mtf, kMtfAll); - } else { - assert(can_forward_declare); - - if (!multi_mtf_.RankFromValue(kMtfForwardDeclared, id, &rank)) { - // This is the first occurrence of a forward declared id. - multi_mtf_.Insert(kMtfForwardDeclared, id); - rank = 0; - } - - writer_.WriteVariableWidthU32(rank, model_->mtf_rank_chunk_length()); - return SPV_SUCCESS; - } -} - -spv_result_t MarkvEncoder::EncodeTypeId() { - if (inst_.opcode == SpvOpFunctionParameter) { - assert(!remaining_function_parameter_types_.empty()); - assert(inst_.type_id == remaining_function_parameter_types_.front()); - remaining_function_parameter_types_.pop_front(); - return SPV_SUCCESS; - } - - { - // Try to encode using id descriptor mtfs. - const spv_result_t result = EncodeIdWithDescriptor(inst_.type_id); - if (result != SPV_UNSUPPORTED) return result; - // If can't be done continue with other methods. - } - - assert(model_->id_fallback_strategy() == - MarkvModel::IdFallbackStrategy::kRuleBased); - - uint64_t mtf = GetRuleBasedMtf(); - assert(!spvOperandCanBeForwardDeclaredFunction(SpvOp(inst_.opcode))( - operand_index_)); - - if (mtf == kMtfNone) { - mtf = kMtfTypeNonFunction; - // Function types should have been handled by GetRuleBasedMtf. - assert(inst_.opcode != SpvOpFunction); - } - - return EncodeExistingId(mtf, inst_.type_id); -} - -spv_result_t MarkvEncoder::EncodeResultId() { - uint32_t rank = 0; - - const uint64_t num_still_forward_declared = - multi_mtf_.GetSize(kMtfForwardDeclared); - - if (num_still_forward_declared) { - // We write the rank only if kMtfForwardDeclared is not empty. If it is - // empty the decoder knows that there are no forward declared ids to expect. - if (multi_mtf_.RankFromValue(kMtfForwardDeclared, inst_.result_id, &rank)) { - // This is a definition of a forward declared id. We can remove the id - // from kMtfForwardDeclared. - if (!multi_mtf_.Remove(kMtfForwardDeclared, inst_.result_id)) - return Diag(SPV_ERROR_INTERNAL) - << "Failed to remove id from kMtfForwardDeclared"; - writer_.WriteBits(1, 1); - writer_.WriteVariableWidthU32(rank, model_->mtf_rank_chunk_length()); - } else { - rank = 0; - writer_.WriteBits(0, 1); - } - } - - if (model_->id_fallback_strategy() == - MarkvModel::IdFallbackStrategy::kRuleBased) { - if (!rank) { - multi_mtf_.Insert(kMtfAll, inst_.result_id); - } - } - - return SPV_SUCCESS; -} - -spv_result_t MarkvEncoder::EncodeLiteralNumber( - const spv_parsed_operand_t& operand) { - if (operand.number_bit_width <= 32) { - const uint32_t word = inst_.words[operand.offset]; - return EncodeNonIdWord(word); - } else { - assert(operand.number_bit_width <= 64); - const uint64_t word = uint64_t(inst_.words[operand.offset]) | - (uint64_t(inst_.words[operand.offset + 1]) << 32); - if (operand.number_kind == SPV_NUMBER_UNSIGNED_INT) { - writer_.WriteVariableWidthU64(word, model_->u64_chunk_length()); - } else if (operand.number_kind == SPV_NUMBER_SIGNED_INT) { - int64_t val = 0; - std::memcpy(&val, &word, 8); - writer_.WriteVariableWidthS64(val, model_->s64_chunk_length(), - model_->s64_block_exponent()); - } else if (operand.number_kind == SPV_NUMBER_FLOATING) { - writer_.WriteUnencoded(word); - } else { - return Diag(SPV_ERROR_INTERNAL) << "Unsupported bit length"; - } - } - return SPV_SUCCESS; -} - -void MarkvEncoder::AddByteBreak(size_t byte_break_if_less_than) { - const size_t num_bits_to_next_byte = - GetNumBitsToNextByte(writer_.GetNumBits()); - if (num_bits_to_next_byte == 0 || - num_bits_to_next_byte > byte_break_if_less_than) - return; - - if (logger_) { - logger_->AppendWhitespaces(kCommentNumWhitespaces); - logger_->AppendText(""); - } - - writer_.WriteBits(0, num_bits_to_next_byte); -} - -spv_result_t MarkvEncoder::EncodeInstruction( - const spv_parsed_instruction_t& inst) { - SpvOp opcode = SpvOp(inst.opcode); - inst_ = inst; - - LogDisassemblyInstruction(); - - const spv_result_t opcode_encodig_result = - EncodeOpcodeAndNumOperands(opcode, inst.num_operands); - if (opcode_encodig_result < 0) return opcode_encodig_result; - - if (opcode_encodig_result != SPV_SUCCESS) { - // Fallback encoding for opcode and num_operands. - writer_.WriteVariableWidthU32(opcode, model_->opcode_chunk_length()); - - if (!OpcodeHasFixedNumberOfOperands(opcode)) { - // If the opcode has a variable number of operands, encode the number of - // operands with the instruction. - - if (logger_) logger_->AppendWhitespaces(kCommentNumWhitespaces); - - writer_.WriteVariableWidthU16(inst.num_operands, - model_->num_operands_chunk_length()); - } - } - - // Write operands. - const uint32_t num_operands = inst_.num_operands; - for (operand_index_ = 0; operand_index_ < num_operands; ++operand_index_) { - operand_ = inst_.operands[operand_index_]; - - if (logger_) { - logger_->AppendWhitespaces(kCommentNumWhitespaces); - logger_->AppendText("<"); - logger_->AppendText(spvOperandTypeStr(operand_.type)); - logger_->AppendText(">"); - } - - switch (operand_.type) { - case SPV_OPERAND_TYPE_RESULT_ID: - case SPV_OPERAND_TYPE_TYPE_ID: - case SPV_OPERAND_TYPE_ID: - case SPV_OPERAND_TYPE_OPTIONAL_ID: - case SPV_OPERAND_TYPE_SCOPE_ID: - case SPV_OPERAND_TYPE_MEMORY_SEMANTICS_ID: { - const uint32_t id = inst_.words[operand_.offset]; - if (operand_.type == SPV_OPERAND_TYPE_TYPE_ID) { - const spv_result_t result = EncodeTypeId(); - if (result != SPV_SUCCESS) return result; - } else if (operand_.type == SPV_OPERAND_TYPE_RESULT_ID) { - const spv_result_t result = EncodeResultId(); - if (result != SPV_SUCCESS) return result; - } else { - const spv_result_t result = EncodeRefId(id); - if (result != SPV_SUCCESS) return result; - } - - PromoteIfNeeded(id); - break; - } - - case SPV_OPERAND_TYPE_LITERAL_INTEGER: { - const spv_result_t result = - EncodeNonIdWord(inst_.words[operand_.offset]); - if (result != SPV_SUCCESS) return result; - break; - } - - case SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER: { - const spv_result_t result = EncodeLiteralNumber(operand_); - if (result != SPV_SUCCESS) return result; - break; - } - - case SPV_OPERAND_TYPE_LITERAL_STRING: { - const char* src = - reinterpret_cast(&inst_.words[operand_.offset]); - - auto* codec = model_->GetLiteralStringHuffmanCodec(opcode); - if (codec) { - uint64_t bits = 0; - size_t num_bits = 0; - const std::string str = src; - if (codec->Encode(str, &bits, &num_bits)) { - writer_.WriteBits(bits, num_bits); - break; - } else { - bool result = - codec->Encode("kMarkvNoneOfTheAbove", &bits, &num_bits); - (void)result; - assert(result); - writer_.WriteBits(bits, num_bits); - } - } - - const size_t length = spv_strnlen_s(src, operand_.num_words * 4); - if (length == operand_.num_words * 4) - return Diag(SPV_ERROR_INVALID_BINARY) - << "Failed to find terminal character of literal string"; - for (size_t i = 0; i < length + 1; ++i) writer_.WriteUnencoded(src[i]); - break; - } - - default: { - for (int i = 0; i < operand_.num_words; ++i) { - const uint32_t word = inst_.words[operand_.offset + i]; - const spv_result_t result = EncodeNonIdWord(word); - if (result != SPV_SUCCESS) return result; - } - break; - } - } - } - - AddByteBreak(MarkvCodec::kByteBreakAfterInstIfLessThanUntilNextByte); - - if (logger_) { - logger_->NewLine(); - logger_->NewLine(); - if (!logger_->DebugInstruction(inst_)) return SPV_REQUESTED_TERMINATION; - } - - ProcessCurInstruction(); - - return SPV_SUCCESS; -} - -} // namespace comp -} // namespace spvtools diff --git a/third_party/spirv-tools/source/comp/markv_encoder.h b/third_party/spirv-tools/source/comp/markv_encoder.h deleted file mode 100644 index 21843123f0..0000000000 --- a/third_party/spirv-tools/source/comp/markv_encoder.h +++ /dev/null @@ -1,167 +0,0 @@ -// Copyright (c) 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/comp/bit_stream.h" -#include "source/comp/markv.h" -#include "source/comp/markv_codec.h" -#include "source/comp/markv_logger.h" -#include "source/util/make_unique.h" - -#ifndef SOURCE_COMP_MARKV_ENCODER_H_ -#define SOURCE_COMP_MARKV_ENCODER_H_ - -#include - -namespace spvtools { -namespace comp { - -// SPIR-V to MARK-V encoder. Exposes functions EncodeHeader and -// EncodeInstruction which can be used as callback by spvBinaryParse. -// Encoded binary is written to an internally maintained bitstream. -// After the last instruction is encoded, the resulting MARK-V binary can be -// acquired by calling GetMarkvBinary(). -// -// The encoder uses SPIR-V validator to keep internal state, therefore -// SPIR-V binary needs to be able to pass validator checks. -// CreateCommentsLogger() can be used to enable the encoder to write comments -// on how encoding was done, which can later be accessed with GetComments(). -class MarkvEncoder : public MarkvCodec { - public: - // |model| is owned by the caller, must be not null and valid during the - // lifetime of MarkvEncoder. - MarkvEncoder(spv_const_context context, const MarkvCodecOptions& options, - const MarkvModel* model) - : MarkvCodec(context, GetValidatorOptions(options), model), - options_(options) {} - ~MarkvEncoder() override = default; - - // Writes data from SPIR-V header to MARK-V header. - spv_result_t EncodeHeader(spv_endianness_t /* endian */, uint32_t /* magic */, - uint32_t version, uint32_t generator, - uint32_t id_bound, uint32_t /* schema */) { - SetIdBound(id_bound); - header_.spirv_version = version; - header_.spirv_generator = generator; - return SPV_SUCCESS; - } - - // Creates an internal logger which writes comments on the encoding process. - void CreateLogger(MarkvLogConsumer log_consumer, - MarkvDebugConsumer debug_consumer) { - logger_ = MakeUnique(log_consumer, debug_consumer); - writer_.SetCallback( - [this](const std::string& str) { logger_->AppendBitSequence(str); }); - } - - // Encodes SPIR-V instruction to MARK-V and writes to bit stream. - // Operation can fail if the instruction fails to pass the validator or if - // the encoder stubmles on something unexpected. - spv_result_t EncodeInstruction(const spv_parsed_instruction_t& inst); - - // Concatenates MARK-V header and the bit stream with encoded instructions - // into a single buffer and returns it as spv_markv_binary. The returned - // value is owned by the caller and needs to be destroyed with - // spvMarkvBinaryDestroy(). - std::vector GetMarkvBinary() { - header_.markv_length_in_bits = - static_cast(sizeof(header_) * 8 + writer_.GetNumBits()); - header_.markv_model = - (model_->model_type() << 16) | model_->model_version(); - - const size_t num_bytes = sizeof(header_) + writer_.GetDataSizeBytes(); - std::vector markv(num_bytes); - - assert(writer_.GetData()); - std::memcpy(markv.data(), &header_, sizeof(header_)); - std::memcpy(markv.data() + sizeof(header_), writer_.GetData(), - writer_.GetDataSizeBytes()); - return markv; - } - - // Optionally adds disassembly to the comments. - // Disassembly should contain all instructions in the module separated by - // \n, and no header. - void SetDisassembly(std::string&& disassembly) { - disassembly_ = MakeUnique(std::move(disassembly)); - } - - // Extracts the next instruction line from the disassembly and logs it. - void LogDisassemblyInstruction() { - if (logger_ && disassembly_) { - std::string line; - std::getline(*disassembly_, line, '\n'); - logger_->AppendTextNewLine(line); - } - } - - private: - // Creates and returns validator options. Returned value owned by the caller. - static spv_validator_options GetValidatorOptions( - const MarkvCodecOptions& options) { - return options.validate_spirv_binary ? spvValidatorOptionsCreate() - : nullptr; - } - - // Writes a single word to bit stream. operand_.type determines if the word is - // encoded and how. - spv_result_t EncodeNonIdWord(uint32_t word); - - // Writes both opcode and num_operands as a single code. - // Returns SPV_UNSUPPORTED iff no suitable codec was found. - spv_result_t EncodeOpcodeAndNumOperands(uint32_t opcode, - uint32_t num_operands); - - // Writes mtf rank to bit stream. |mtf| is used to determine the codec - // scheme. |fallback_method| is used if no codec defined for |mtf|. - spv_result_t EncodeMtfRankHuffman(uint32_t rank, uint64_t mtf, - uint64_t fallback_method); - - // Writes id using coding based on mtf associated with the id descriptor. - // Returns SPV_UNSUPPORTED iff fallback method needs to be used. - spv_result_t EncodeIdWithDescriptor(uint32_t id); - - // Writes id using coding based on the given |mtf|, which is expected to - // contain the given |id|. - spv_result_t EncodeExistingId(uint64_t mtf, uint32_t id); - - // Writes type id of the current instruction if can't be inferred. - spv_result_t EncodeTypeId(); - - // Writes result id of the current instruction if can't be inferred. - spv_result_t EncodeResultId(); - - // Writes ids which are neither type nor result ids. - spv_result_t EncodeRefId(uint32_t id); - - // Writes bits to the stream until the beginning of the next byte if the - // number of bits until the next byte is less than |byte_break_if_less_than|. - void AddByteBreak(size_t byte_break_if_less_than); - - // Encodes a literal number operand and writes it to the bit stream. - spv_result_t EncodeLiteralNumber(const spv_parsed_operand_t& operand); - - MarkvCodecOptions options_; - - // Bit stream where encoded instructions are written. - BitWriterWord64 writer_; - - // If not nullptr, disassembled instruction lines will be written to comments. - // Format: \n separated instruction lines, no header. - std::unique_ptr disassembly_; -}; - -} // namespace comp -} // namespace spvtools - -#endif // SOURCE_COMP_MARKV_ENCODER_H_ diff --git a/third_party/spirv-tools/source/comp/markv_logger.h b/third_party/spirv-tools/source/comp/markv_logger.h deleted file mode 100644 index c07fe97b7a..0000000000 --- a/third_party/spirv-tools/source/comp/markv_logger.h +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright (c) 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_COMP_MARKV_LOGGER_H_ -#define SOURCE_COMP_MARKV_LOGGER_H_ - -#include "source/comp/markv.h" - -namespace spvtools { -namespace comp { - -class MarkvLogger { - public: - MarkvLogger(MarkvLogConsumer log_consumer, MarkvDebugConsumer debug_consumer) - : log_consumer_(log_consumer), debug_consumer_(debug_consumer) {} - - void AppendText(const std::string& str) { - Append(str); - use_delimiter_ = false; - } - - void AppendTextNewLine(const std::string& str) { - Append(str); - Append("\n"); - use_delimiter_ = false; - } - - void AppendBitSequence(const std::string& str) { - if (debug_consumer_) instruction_bits_ << str; - if (use_delimiter_) Append("-"); - Append(str); - use_delimiter_ = true; - } - - void AppendWhitespaces(size_t num) { - Append(std::string(num, ' ')); - use_delimiter_ = false; - } - - void NewLine() { - Append("\n"); - use_delimiter_ = false; - } - - bool DebugInstruction(const spv_parsed_instruction_t& inst) { - bool result = true; - if (debug_consumer_) { - result = debug_consumer_( - std::vector(inst.words, inst.words + inst.num_words), - instruction_bits_.str(), instruction_comment_.str()); - instruction_bits_.str(std::string()); - instruction_comment_.str(std::string()); - } - return result; - } - - private: - MarkvLogger(const MarkvLogger&) = delete; - MarkvLogger(MarkvLogger&&) = delete; - MarkvLogger& operator=(const MarkvLogger&) = delete; - MarkvLogger& operator=(MarkvLogger&&) = delete; - - void Append(const std::string& str) { - if (log_consumer_) log_consumer_(str); - if (debug_consumer_) instruction_comment_ << str; - } - - MarkvLogConsumer log_consumer_; - MarkvDebugConsumer debug_consumer_; - - std::stringstream instruction_bits_; - std::stringstream instruction_comment_; - - // If true a delimiter will be appended before the next bit sequence. - // Used to generate outputs like: 1100-0 1110-1-1100-1-1111-0 110-0. - bool use_delimiter_ = false; -}; - -} // namespace comp -} // namespace spvtools - -#endif // SOURCE_COMP_MARKV_LOGGER_H_ diff --git a/third_party/spirv-tools/source/comp/markv_model.h b/third_party/spirv-tools/source/comp/markv_model.h deleted file mode 100644 index d03df02df9..0000000000 --- a/third_party/spirv-tools/source/comp/markv_model.h +++ /dev/null @@ -1,232 +0,0 @@ -// Copyright (c) 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_COMP_MARKV_MODEL_H_ -#define SOURCE_COMP_MARKV_MODEL_H_ - -#include - -#include "source/comp/huffman_codec.h" -#include "source/latest_version_spirv_header.h" -#include "spirv-tools/libspirv.hpp" - -namespace spvtools { -namespace comp { - -// Base class for MARK-V models. -// The class contains encoding/decoding model with various constants and -// codecs used by the compression algorithm. -class MarkvModel { - public: - MarkvModel() - : operand_chunk_lengths_( - static_cast(SPV_OPERAND_TYPE_NUM_OPERAND_TYPES), 0) { - // Set default values. - operand_chunk_lengths_[SPV_OPERAND_TYPE_TYPE_ID] = 4; - operand_chunk_lengths_[SPV_OPERAND_TYPE_RESULT_ID] = 8; - operand_chunk_lengths_[SPV_OPERAND_TYPE_ID] = 8; - operand_chunk_lengths_[SPV_OPERAND_TYPE_SCOPE_ID] = 8; - operand_chunk_lengths_[SPV_OPERAND_TYPE_MEMORY_SEMANTICS_ID] = 8; - operand_chunk_lengths_[SPV_OPERAND_TYPE_LITERAL_INTEGER] = 6; - operand_chunk_lengths_[SPV_OPERAND_TYPE_OPTIONAL_LITERAL_INTEGER] = 6; - operand_chunk_lengths_[SPV_OPERAND_TYPE_CAPABILITY] = 6; - operand_chunk_lengths_[SPV_OPERAND_TYPE_SOURCE_LANGUAGE] = 3; - operand_chunk_lengths_[SPV_OPERAND_TYPE_EXECUTION_MODEL] = 3; - operand_chunk_lengths_[SPV_OPERAND_TYPE_ADDRESSING_MODEL] = 2; - operand_chunk_lengths_[SPV_OPERAND_TYPE_MEMORY_MODEL] = 2; - operand_chunk_lengths_[SPV_OPERAND_TYPE_EXECUTION_MODE] = 6; - operand_chunk_lengths_[SPV_OPERAND_TYPE_STORAGE_CLASS] = 4; - operand_chunk_lengths_[SPV_OPERAND_TYPE_DIMENSIONALITY] = 3; - operand_chunk_lengths_[SPV_OPERAND_TYPE_SAMPLER_ADDRESSING_MODE] = 3; - operand_chunk_lengths_[SPV_OPERAND_TYPE_SAMPLER_FILTER_MODE] = 2; - operand_chunk_lengths_[SPV_OPERAND_TYPE_SAMPLER_IMAGE_FORMAT] = 6; - operand_chunk_lengths_[SPV_OPERAND_TYPE_FP_ROUNDING_MODE] = 2; - operand_chunk_lengths_[SPV_OPERAND_TYPE_LINKAGE_TYPE] = 2; - operand_chunk_lengths_[SPV_OPERAND_TYPE_ACCESS_QUALIFIER] = 2; - operand_chunk_lengths_[SPV_OPERAND_TYPE_OPTIONAL_ACCESS_QUALIFIER] = 2; - operand_chunk_lengths_[SPV_OPERAND_TYPE_FUNCTION_PARAMETER_ATTRIBUTE] = 3; - operand_chunk_lengths_[SPV_OPERAND_TYPE_DECORATION] = 6; - operand_chunk_lengths_[SPV_OPERAND_TYPE_BUILT_IN] = 6; - operand_chunk_lengths_[SPV_OPERAND_TYPE_GROUP_OPERATION] = 2; - operand_chunk_lengths_[SPV_OPERAND_TYPE_KERNEL_ENQ_FLAGS] = 2; - operand_chunk_lengths_[SPV_OPERAND_TYPE_KERNEL_PROFILING_INFO] = 2; - operand_chunk_lengths_[SPV_OPERAND_TYPE_FP_FAST_MATH_MODE] = 4; - operand_chunk_lengths_[SPV_OPERAND_TYPE_FUNCTION_CONTROL] = 4; - operand_chunk_lengths_[SPV_OPERAND_TYPE_LOOP_CONTROL] = 4; - operand_chunk_lengths_[SPV_OPERAND_TYPE_IMAGE] = 4; - operand_chunk_lengths_[SPV_OPERAND_TYPE_OPTIONAL_IMAGE] = 4; - operand_chunk_lengths_[SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS] = 4; - operand_chunk_lengths_[SPV_OPERAND_TYPE_SELECTION_CONTROL] = 4; - operand_chunk_lengths_[SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER] = 6; - operand_chunk_lengths_[SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER] = 6; - } - - uint32_t model_type() const { return model_type_; } - uint32_t model_version() const { return model_version_; } - - uint32_t opcode_chunk_length() const { return opcode_chunk_length_; } - uint32_t num_operands_chunk_length() const { - return num_operands_chunk_length_; - } - uint32_t mtf_rank_chunk_length() const { return mtf_rank_chunk_length_; } - - uint32_t u64_chunk_length() const { return u64_chunk_length_; } - uint32_t s64_chunk_length() const { return s64_chunk_length_; } - uint32_t s64_block_exponent() const { return s64_block_exponent_; } - - enum class IdFallbackStrategy { - kRuleBased = 0, - kShortDescriptor, - }; - - IdFallbackStrategy id_fallback_strategy() const { - return id_fallback_strategy_; - } - - // Returns a codec for common opcode_and_num_operands words for the given - // previous opcode. May return nullptr if the codec doesn't exist. - const HuffmanCodec* GetOpcodeAndNumOperandsMarkovHuffmanCodec( - uint32_t prev_opcode) const { - if (prev_opcode == SpvOpNop) - return opcode_and_num_operands_huffman_codec_.get(); - - const auto it = - opcode_and_num_operands_markov_huffman_codecs_.find(prev_opcode); - if (it == opcode_and_num_operands_markov_huffman_codecs_.end()) - return nullptr; - return it->second.get(); - } - - // Returns a codec for common non-id words used for given operand slot. - // Operand slot is defined by the opcode and the operand index. - // May return nullptr if the codec doesn't exist. - const HuffmanCodec* GetNonIdWordHuffmanCodec( - uint32_t opcode, uint32_t operand_index) const { - const auto it = non_id_word_huffman_codecs_.find( - std::pair(opcode, operand_index)); - if (it == non_id_word_huffman_codecs_.end()) return nullptr; - return it->second.get(); - } - - // Returns a codec for common id descriptos used for given operand slot. - // Operand slot is defined by the opcode and the operand index. - // May return nullptr if the codec doesn't exist. - const HuffmanCodec* GetIdDescriptorHuffmanCodec( - uint32_t opcode, uint32_t operand_index) const { - const auto it = id_descriptor_huffman_codecs_.find( - std::pair(opcode, operand_index)); - if (it == id_descriptor_huffman_codecs_.end()) return nullptr; - return it->second.get(); - } - - // Returns a codec for common strings used by the given opcode. - // Operand slot is defined by the opcode and the operand index. - // May return nullptr if the codec doesn't exist. - const HuffmanCodec* GetLiteralStringHuffmanCodec( - uint32_t opcode) const { - const auto it = literal_string_huffman_codecs_.find(opcode); - if (it == literal_string_huffman_codecs_.end()) return nullptr; - return it->second.get(); - } - - // Checks if |descriptor| has a coding scheme in any of - // id_descriptor_huffman_codecs_. - bool DescriptorHasCodingScheme(uint32_t descriptor) const { - return descriptors_with_coding_scheme_.count(descriptor); - } - - // Checks if any descriptor has a coding scheme. - bool AnyDescriptorHasCodingScheme() const { - return !descriptors_with_coding_scheme_.empty(); - } - - // Returns chunk length used for variable length encoding of spirv operand - // words. - uint32_t GetOperandVariableWidthChunkLength(spv_operand_type_t type) const { - return operand_chunk_lengths_.at(static_cast(type)); - } - - // Sets model type. - void SetModelType(uint32_t in_model_type) { model_type_ = in_model_type; } - - // Sets model version. - void SetModelVersion(uint32_t in_model_version) { - model_version_ = in_model_version; - } - - // Returns value used by Huffman codecs as a signal that a value is not in the - // coding table. - static uint64_t GetMarkvNoneOfTheAbove() { - // Magic number. - return 1111111111111111111; - } - - MarkvModel(const MarkvModel&) = delete; - const MarkvModel& operator=(const MarkvModel&) = delete; - - protected: - // Huffman codec for base-rate of opcode_and_num_operands. - std::unique_ptr> - opcode_and_num_operands_huffman_codec_; - - // Huffman codecs for opcode_and_num_operands. The map key is previous opcode. - std::map>> - opcode_and_num_operands_markov_huffman_codecs_; - - // Huffman codecs for non-id single-word operand values. - // The map key is pair . - std::map, - std::unique_ptr>> - non_id_word_huffman_codecs_; - - // Huffman codecs for id descriptors. The map key is pair - // . - std::map, - std::unique_ptr>> - id_descriptor_huffman_codecs_; - - // Set of all descriptors which have a coding scheme in any of - // id_descriptor_huffman_codecs_. - std::unordered_set descriptors_with_coding_scheme_; - - // Huffman codecs for literal strings. The map key is the opcode of the - // current instruction. This assumes, that there is no more than one literal - // string operand per instruction, but would still work even if this is not - // the case. Names and debug information strings are not collected. - std::map>> - literal_string_huffman_codecs_; - - // Chunk lengths used for variable width encoding of operands (index is - // spv_operand_type of the operand). - std::vector operand_chunk_lengths_; - - uint32_t opcode_chunk_length_ = 7; - uint32_t num_operands_chunk_length_ = 3; - uint32_t mtf_rank_chunk_length_ = 5; - - uint32_t u64_chunk_length_ = 8; - uint32_t s64_chunk_length_ = 8; - uint32_t s64_block_exponent_ = 10; - - IdFallbackStrategy id_fallback_strategy_ = - IdFallbackStrategy::kShortDescriptor; - - uint32_t model_type_ = 0; - uint32_t model_version_ = 0; -}; - -} // namespace comp -} // namespace spvtools - -#endif // SOURCE_COMP_MARKV_MODEL_H_ diff --git a/third_party/spirv-tools/source/comp/move_to_front.cpp b/third_party/spirv-tools/source/comp/move_to_front.cpp deleted file mode 100644 index 9d35a3f5b6..0000000000 --- a/third_party/spirv-tools/source/comp/move_to_front.cpp +++ /dev/null @@ -1,456 +0,0 @@ -// Copyright (c) 2018 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/comp/move_to_front.h" - -#include -#include -#include -#include -#include -#include -#include - -namespace spvtools { -namespace comp { - -bool MoveToFront::Insert(uint32_t value) { - auto it = value_to_node_.find(value); - if (it != value_to_node_.end() && IsInTree(it->second)) return false; - - const uint32_t old_size = GetSize(); - (void)old_size; - - InsertNode(CreateNode(next_timestamp_++, value)); - - last_accessed_value_ = value; - last_accessed_value_valid_ = true; - - assert(value_to_node_.count(value)); - assert(old_size + 1 == GetSize()); - return true; -} - -bool MoveToFront::Remove(uint32_t value) { - auto it = value_to_node_.find(value); - if (it == value_to_node_.end()) return false; - - if (!IsInTree(it->second)) return false; - - if (last_accessed_value_ == value) last_accessed_value_valid_ = false; - - const uint32_t orphan = RemoveNode(it->second); - (void)orphan; - // The node of |value| is still alive but it's orphaned now. Can still be - // reused later. - assert(!IsInTree(orphan)); - assert(ValueOf(orphan) == value); - return true; -} - -bool MoveToFront::RankFromValue(uint32_t value, uint32_t* rank) { - if (last_accessed_value_valid_ && last_accessed_value_ == value) { - *rank = 1; - return true; - } - - const uint32_t old_size = GetSize(); - if (old_size == 1) { - if (ValueOf(root_) == value) { - *rank = 1; - return true; - } else { - return false; - } - } - - const auto it = value_to_node_.find(value); - if (it == value_to_node_.end()) { - return false; - } - - uint32_t target = it->second; - - if (!IsInTree(target)) { - return false; - } - - uint32_t node = target; - *rank = 1 + SizeOf(LeftOf(node)); - while (node) { - if (IsRightChild(node)) *rank += 1 + SizeOf(LeftOf(ParentOf(node))); - node = ParentOf(node); - } - - // Don't update timestamp if the node has rank 1. - if (*rank != 1) { - // Update timestamp and reposition the node. - target = RemoveNode(target); - assert(ValueOf(target) == value); - assert(old_size == GetSize() + 1); - MutableTimestampOf(target) = next_timestamp_++; - InsertNode(target); - assert(old_size == GetSize()); - } - - last_accessed_value_ = value; - last_accessed_value_valid_ = true; - return true; -} - -bool MoveToFront::HasValue(uint32_t value) const { - const auto it = value_to_node_.find(value); - if (it == value_to_node_.end()) { - return false; - } - - return IsInTree(it->second); -} - -bool MoveToFront::Promote(uint32_t value) { - if (last_accessed_value_valid_ && last_accessed_value_ == value) { - return true; - } - - const uint32_t old_size = GetSize(); - if (old_size == 1) return ValueOf(root_) == value; - - const auto it = value_to_node_.find(value); - if (it == value_to_node_.end()) { - return false; - } - - uint32_t target = it->second; - - if (!IsInTree(target)) { - return false; - } - - // Update timestamp and reposition the node. - target = RemoveNode(target); - assert(ValueOf(target) == value); - assert(old_size == GetSize() + 1); - - MutableTimestampOf(target) = next_timestamp_++; - InsertNode(target); - assert(old_size == GetSize()); - - last_accessed_value_ = value; - last_accessed_value_valid_ = true; - return true; -} - -bool MoveToFront::ValueFromRank(uint32_t rank, uint32_t* value) { - if (last_accessed_value_valid_ && rank == 1) { - *value = last_accessed_value_; - return true; - } - - const uint32_t old_size = GetSize(); - if (rank <= 0 || rank > old_size) { - return false; - } - - if (old_size == 1) { - *value = ValueOf(root_); - return true; - } - - const bool update_timestamp = (rank != 1); - - uint32_t node = root_; - while (node) { - const uint32_t left_subtree_num_nodes = SizeOf(LeftOf(node)); - if (rank == left_subtree_num_nodes + 1) { - // This is the node we are looking for. - // Don't update timestamp if the node has rank 1. - if (update_timestamp) { - node = RemoveNode(node); - assert(old_size == GetSize() + 1); - MutableTimestampOf(node) = next_timestamp_++; - InsertNode(node); - assert(old_size == GetSize()); - } - *value = ValueOf(node); - last_accessed_value_ = *value; - last_accessed_value_valid_ = true; - return true; - } - - if (rank < left_subtree_num_nodes + 1) { - // Descend into the left subtree. The rank is still valid. - node = LeftOf(node); - } else { - // Descend into the right subtree. We leave behind the left subtree and - // the current node, adjust the |rank| accordingly. - rank -= left_subtree_num_nodes + 1; - node = RightOf(node); - } - } - - assert(0); - return false; -} - -uint32_t MoveToFront::CreateNode(uint32_t timestamp, uint32_t value) { - uint32_t handle = static_cast(nodes_.size()); - const auto result = value_to_node_.emplace(value, handle); - if (result.second) { - // Create new node. - nodes_.emplace_back(Node()); - Node& node = nodes_.back(); - node.timestamp = timestamp; - node.value = value; - node.size = 1; - // Non-NIL nodes start with height 1 because their NIL children are - // leaves. - node.height = 1; - } else { - // Reuse old node. - handle = result.first->second; - assert(!IsInTree(handle)); - assert(ValueOf(handle) == value); - assert(SizeOf(handle) == 1); - assert(HeightOf(handle) == 1); - MutableTimestampOf(handle) = timestamp; - } - - return handle; -} - -void MoveToFront::InsertNode(uint32_t node) { - assert(!IsInTree(node)); - assert(SizeOf(node) == 1); - assert(HeightOf(node) == 1); - assert(TimestampOf(node)); - - if (!root_) { - root_ = node; - return; - } - - uint32_t iter = root_; - uint32_t parent = 0; - - // Will determine if |node| will become the right or left child after - // insertion (but before balancing). - bool right_child = true; - - // Find the node which will become |node|'s parent after insertion - // (but before balancing). - while (iter) { - parent = iter; - assert(TimestampOf(iter) != TimestampOf(node)); - right_child = TimestampOf(iter) > TimestampOf(node); - iter = right_child ? RightOf(iter) : LeftOf(iter); - } - - assert(parent); - - // Connect node and parent. - MutableParentOf(node) = parent; - if (right_child) - MutableRightOf(parent) = node; - else - MutableLeftOf(parent) = node; - - // Insertion is finished. Start the balancing process. - bool needs_rebalancing = true; - parent = ParentOf(node); - - while (parent) { - UpdateNode(parent); - - if (needs_rebalancing) { - const int parent_balance = BalanceOf(parent); - - if (RightOf(parent) == node) { - // Added node to the right subtree. - if (parent_balance > 1) { - // Parent is right heavy, rotate left. - if (BalanceOf(node) < 0) RotateRight(node); - parent = RotateLeft(parent); - } else if (parent_balance == 0 || parent_balance == -1) { - // Parent is balanced or left heavy, no need to balance further. - needs_rebalancing = false; - } - } else { - // Added node to the left subtree. - if (parent_balance < -1) { - // Parent is left heavy, rotate right. - if (BalanceOf(node) > 0) RotateLeft(node); - parent = RotateRight(parent); - } else if (parent_balance == 0 || parent_balance == 1) { - // Parent is balanced or right heavy, no need to balance further. - needs_rebalancing = false; - } - } - } - - assert(BalanceOf(parent) >= -1 && (BalanceOf(parent) <= 1)); - - node = parent; - parent = ParentOf(parent); - } -} - -uint32_t MoveToFront::RemoveNode(uint32_t node) { - if (LeftOf(node) && RightOf(node)) { - // If |node| has two children, then use another node as scapegoat and swap - // their contents. We pick the scapegoat on the side of the tree which has - // more nodes. - const uint32_t scapegoat = SizeOf(LeftOf(node)) >= SizeOf(RightOf(node)) - ? RightestDescendantOf(LeftOf(node)) - : LeftestDescendantOf(RightOf(node)); - assert(scapegoat); - std::swap(MutableValueOf(node), MutableValueOf(scapegoat)); - std::swap(MutableTimestampOf(node), MutableTimestampOf(scapegoat)); - value_to_node_[ValueOf(node)] = node; - value_to_node_[ValueOf(scapegoat)] = scapegoat; - node = scapegoat; - } - - // |node| may have only one child at this point. - assert(!RightOf(node) || !LeftOf(node)); - - uint32_t parent = ParentOf(node); - uint32_t child = RightOf(node) ? RightOf(node) : LeftOf(node); - - // Orphan |node| and reconnect parent and child. - if (child) MutableParentOf(child) = parent; - - if (parent) { - if (LeftOf(parent) == node) - MutableLeftOf(parent) = child; - else - MutableRightOf(parent) = child; - } - - MutableParentOf(node) = 0; - MutableLeftOf(node) = 0; - MutableRightOf(node) = 0; - UpdateNode(node); - const uint32_t orphan = node; - - if (root_ == node) root_ = child; - - // Removal is finished. Start the balancing process. - bool needs_rebalancing = true; - node = child; - - while (parent) { - UpdateNode(parent); - - if (needs_rebalancing) { - const int parent_balance = BalanceOf(parent); - - if (parent_balance == 1 || parent_balance == -1) { - // The height of the subtree was not changed. - needs_rebalancing = false; - } else { - if (RightOf(parent) == node) { - // Removed node from the right subtree. - if (parent_balance < -1) { - // Parent is left heavy, rotate right. - const uint32_t sibling = LeftOf(parent); - if (BalanceOf(sibling) > 0) RotateLeft(sibling); - parent = RotateRight(parent); - } - } else { - // Removed node from the left subtree. - if (parent_balance > 1) { - // Parent is right heavy, rotate left. - const uint32_t sibling = RightOf(parent); - if (BalanceOf(sibling) < 0) RotateRight(sibling); - parent = RotateLeft(parent); - } - } - } - } - - assert(BalanceOf(parent) >= -1 && (BalanceOf(parent) <= 1)); - - node = parent; - parent = ParentOf(parent); - } - - return orphan; -} - -uint32_t MoveToFront::RotateLeft(const uint32_t node) { - const uint32_t pivot = RightOf(node); - assert(pivot); - - // LeftOf(pivot) gets attached to node in place of pivot. - MutableRightOf(node) = LeftOf(pivot); - if (RightOf(node)) MutableParentOf(RightOf(node)) = node; - - // Pivot gets attached to ParentOf(node) in place of node. - MutableParentOf(pivot) = ParentOf(node); - if (!ParentOf(node)) - root_ = pivot; - else if (IsLeftChild(node)) - MutableLeftOf(ParentOf(node)) = pivot; - else - MutableRightOf(ParentOf(node)) = pivot; - - // Node is child of pivot. - MutableLeftOf(pivot) = node; - MutableParentOf(node) = pivot; - - // Update both node and pivot. Pivot is the new parent of node, so node should - // be updated first. - UpdateNode(node); - UpdateNode(pivot); - - return pivot; -} - -uint32_t MoveToFront::RotateRight(const uint32_t node) { - const uint32_t pivot = LeftOf(node); - assert(pivot); - - // RightOf(pivot) gets attached to node in place of pivot. - MutableLeftOf(node) = RightOf(pivot); - if (LeftOf(node)) MutableParentOf(LeftOf(node)) = node; - - // Pivot gets attached to ParentOf(node) in place of node. - MutableParentOf(pivot) = ParentOf(node); - if (!ParentOf(node)) - root_ = pivot; - else if (IsLeftChild(node)) - MutableLeftOf(ParentOf(node)) = pivot; - else - MutableRightOf(ParentOf(node)) = pivot; - - // Node is child of pivot. - MutableRightOf(pivot) = node; - MutableParentOf(node) = pivot; - - // Update both node and pivot. Pivot is the new parent of node, so node should - // be updated first. - UpdateNode(node); - UpdateNode(pivot); - - return pivot; -} - -void MoveToFront::UpdateNode(uint32_t node) { - MutableSizeOf(node) = 1 + SizeOf(LeftOf(node)) + SizeOf(RightOf(node)); - MutableHeightOf(node) = - 1 + std::max(HeightOf(LeftOf(node)), HeightOf(RightOf(node))); -} - -} // namespace comp -} // namespace spvtools diff --git a/third_party/spirv-tools/source/comp/move_to_front.h b/third_party/spirv-tools/source/comp/move_to_front.h deleted file mode 100644 index 8752194ece..0000000000 --- a/third_party/spirv-tools/source/comp/move_to_front.h +++ /dev/null @@ -1,384 +0,0 @@ -// Copyright (c) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_COMP_MOVE_TO_FRONT_H_ -#define SOURCE_COMP_MOVE_TO_FRONT_H_ - -#include -#include -#include -#include -#include -#include - -namespace spvtools { -namespace comp { - -// Log(n) move-to-front implementation. Implements the following functions: -// Insert - pushes value to the front of the mtf sequence -// (only unique values allowed). -// Remove - remove value from the sequence. -// ValueFromRank - access value by its 1-indexed rank in the sequence. -// RankFromValue - get the rank of the given value in the sequence. -// Accessing a value with ValueFromRank or RankFromValue moves the value to the -// front of the sequence (rank of 1). -// -// The implementation is based on an AVL-based order statistic tree. The tree -// is ordered by timestamps issued when values are inserted or accessed (recent -// values go to the left side of the tree, old values are gradually rotated to -// the right side). -// -// Terminology -// rank: 1-indexed rank showing how recently the value was inserted or accessed. -// node: handle used internally to access node data. -// size: size of the subtree of a node (including the node). -// height: distance from a node to the farthest leaf. -class MoveToFront { - public: - explicit MoveToFront(size_t reserve_capacity = 4) { - nodes_.reserve(reserve_capacity); - - // Create NIL node. - nodes_.emplace_back(Node()); - } - - virtual ~MoveToFront() = default; - - // Inserts value in the move-to-front sequence. Does nothing if the value is - // already in the sequence. Returns true if insertion was successful. - // The inserted value is placed at the front of the sequence (rank 1). - bool Insert(uint32_t value); - - // Removes value from move-to-front sequence. Returns false iff the value - // was not found. - bool Remove(uint32_t value); - - // Computes 1-indexed rank of value in the move-to-front sequence and moves - // the value to the front. Example: - // Before the call: 4 8 2 1 7 - // RankFromValue(8) returns 2 - // After the call: 8 4 2 1 7 - // Returns true iff the value was found in the sequence. - bool RankFromValue(uint32_t value, uint32_t* rank); - - // Returns value corresponding to a 1-indexed rank in the move-to-front - // sequence and moves the value to the front. Example: - // Before the call: 4 8 2 1 7 - // ValueFromRank(2) returns 8 - // After the call: 8 4 2 1 7 - // Returns true iff the rank is within bounds [1, GetSize()]. - bool ValueFromRank(uint32_t rank, uint32_t* value); - - // Moves the value to the front of the sequence. - // Returns false iff value is not in the sequence. - bool Promote(uint32_t value); - - // Returns true iff the move-to-front sequence contains the value. - bool HasValue(uint32_t value) const; - - // Returns the number of elements in the move-to-front sequence. - uint32_t GetSize() const { return SizeOf(root_); } - - protected: - // Internal tree data structure uses handles instead of pointers. Leaves and - // root parent reference a singleton under handle 0. Although dereferencing - // a null pointer is not possible, inappropriate access to handle 0 would - // cause an assertion. Handles are not garbage collected if value was - // deprecated - // with DeprecateValue(). But handles are recycled when a node is - // repositioned. - - // Internal tree data structure node. - struct Node { - // Timestamp from a logical clock which updates every time the element is - // accessed through ValueFromRank or RankFromValue. - uint32_t timestamp = 0; - // The size of the node's subtree, including the node. - // SizeOf(LeftOf(node)) + SizeOf(RightOf(node)) + 1. - uint32_t size = 0; - // Handles to connected nodes. - uint32_t left = 0; - uint32_t right = 0; - uint32_t parent = 0; - // Distance to the farthest leaf. - // Leaves have height 0, real nodes at least 1. - uint32_t height = 0; - // Stored value. - uint32_t value = 0; - }; - - // Creates node and sets correct values. Non-NIL nodes should be created only - // through this function. If the node with this value has been created - // previously - // and since orphaned, reuses the old node instead of creating a new one. - uint32_t CreateNode(uint32_t timestamp, uint32_t value); - - // Node accessor methods. Naming is designed to be similar to natural - // language as these functions tend to be used in sequences, for example: - // ParentOf(LeftestDescendentOf(RightOf(node))) - - // Returns value of the node referenced by |handle|. - uint32_t ValueOf(uint32_t node) const { return nodes_.at(node).value; } - - // Returns left child of |node|. - uint32_t LeftOf(uint32_t node) const { return nodes_.at(node).left; } - - // Returns right child of |node|. - uint32_t RightOf(uint32_t node) const { return nodes_.at(node).right; } - - // Returns parent of |node|. - uint32_t ParentOf(uint32_t node) const { return nodes_.at(node).parent; } - - // Returns timestamp of |node|. - uint32_t TimestampOf(uint32_t node) const { - assert(node); - return nodes_.at(node).timestamp; - } - - // Returns size of |node|. - uint32_t SizeOf(uint32_t node) const { return nodes_.at(node).size; } - - // Returns height of |node|. - uint32_t HeightOf(uint32_t node) const { return nodes_.at(node).height; } - - // Returns mutable reference to value of |node|. - uint32_t& MutableValueOf(uint32_t node) { - assert(node); - return nodes_.at(node).value; - } - - // Returns mutable reference to handle of left child of |node|. - uint32_t& MutableLeftOf(uint32_t node) { - assert(node); - return nodes_.at(node).left; - } - - // Returns mutable reference to handle of right child of |node|. - uint32_t& MutableRightOf(uint32_t node) { - assert(node); - return nodes_.at(node).right; - } - - // Returns mutable reference to handle of parent of |node|. - uint32_t& MutableParentOf(uint32_t node) { - assert(node); - return nodes_.at(node).parent; - } - - // Returns mutable reference to timestamp of |node|. - uint32_t& MutableTimestampOf(uint32_t node) { - assert(node); - return nodes_.at(node).timestamp; - } - - // Returns mutable reference to size of |node|. - uint32_t& MutableSizeOf(uint32_t node) { - assert(node); - return nodes_.at(node).size; - } - - // Returns mutable reference to height of |node|. - uint32_t& MutableHeightOf(uint32_t node) { - assert(node); - return nodes_.at(node).height; - } - - // Returns true iff |node| is left child of its parent. - bool IsLeftChild(uint32_t node) const { - assert(node); - return LeftOf(ParentOf(node)) == node; - } - - // Returns true iff |node| is right child of its parent. - bool IsRightChild(uint32_t node) const { - assert(node); - return RightOf(ParentOf(node)) == node; - } - - // Returns true iff |node| has no relatives. - bool IsOrphan(uint32_t node) const { - assert(node); - return !ParentOf(node) && !LeftOf(node) && !RightOf(node); - } - - // Returns true iff |node| is in the tree. - bool IsInTree(uint32_t node) const { - assert(node); - return node == root_ || !IsOrphan(node); - } - - // Returns the height difference between right and left subtrees. - int BalanceOf(uint32_t node) const { - return int(HeightOf(RightOf(node))) - int(HeightOf(LeftOf(node))); - } - - // Updates size and height of the node, assuming that the children have - // correct values. - void UpdateNode(uint32_t node); - - // Returns the most LeftOf(LeftOf(... descendent which is not leaf. - uint32_t LeftestDescendantOf(uint32_t node) const { - uint32_t parent = 0; - while (node) { - parent = node; - node = LeftOf(node); - } - return parent; - } - - // Returns the most RightOf(RightOf(... descendent which is not leaf. - uint32_t RightestDescendantOf(uint32_t node) const { - uint32_t parent = 0; - while (node) { - parent = node; - node = RightOf(node); - } - return parent; - } - - // Inserts node in the tree. The node must be an orphan. - void InsertNode(uint32_t node); - - // Removes node from the tree. May change value_to_node_ if removal uses a - // scapegoat. Returns the removed (orphaned) handle for recycling. The - // returned handle may not be equal to |node| if scapegoat was used. - uint32_t RemoveNode(uint32_t node); - - // Rotates |node| left, reassigns all connections and returns the node - // which takes place of the |node|. - uint32_t RotateLeft(const uint32_t node); - - // Rotates |node| right, reassigns all connections and returns the node - // which takes place of the |node|. - uint32_t RotateRight(const uint32_t node); - - // Root node handle. The tree is empty if root_ is 0. - uint32_t root_ = 0; - - // Incremented counters for next timestamp and value. - uint32_t next_timestamp_ = 1; - - // Holds all tree nodes. Indices of this vector are node handles. - std::vector nodes_; - - // Maps ids to node handles. - std::unordered_map value_to_node_; - - // Cache for the last accessed value in the sequence. - uint32_t last_accessed_value_ = 0; - bool last_accessed_value_valid_ = false; -}; - -class MultiMoveToFront { - public: - // Inserts |value| to sequence with handle |mtf|. - // Returns false if |mtf| already has |value|. - bool Insert(uint64_t mtf, uint32_t value) { - if (GetMtf(mtf).Insert(value)) { - val_to_mtfs_[value].insert(mtf); - return true; - } - return false; - } - - // Removes |value| from sequence with handle |mtf|. - // Returns false if |mtf| doesn't have |value|. - bool Remove(uint64_t mtf, uint32_t value) { - if (GetMtf(mtf).Remove(value)) { - val_to_mtfs_[value].erase(mtf); - return true; - } - assert(val_to_mtfs_[value].count(mtf) == 0); - return false; - } - - // Removes |value| from all sequences which have it. - void RemoveFromAll(uint32_t value) { - auto it = val_to_mtfs_.find(value); - if (it == val_to_mtfs_.end()) return; - - auto& mtfs_containing_value = it->second; - for (uint64_t mtf : mtfs_containing_value) { - GetMtf(mtf).Remove(value); - } - - val_to_mtfs_.erase(value); - } - - // Computes rank of |value| in sequence |mtf|. - // Returns false if |mtf| doesn't have |value|. - bool RankFromValue(uint64_t mtf, uint32_t value, uint32_t* rank) { - return GetMtf(mtf).RankFromValue(value, rank); - } - - // Finds |value| with |rank| in sequence |mtf|. - // Returns false if |rank| is out of bounds. - bool ValueFromRank(uint64_t mtf, uint32_t rank, uint32_t* value) { - return GetMtf(mtf).ValueFromRank(rank, value); - } - - // Returns size of |mtf| sequence. - uint32_t GetSize(uint64_t mtf) { return GetMtf(mtf).GetSize(); } - - // Promotes |value| in all sequences which have it. - void Promote(uint32_t value) { - const auto it = val_to_mtfs_.find(value); - if (it == val_to_mtfs_.end()) return; - - const auto& mtfs_containing_value = it->second; - for (uint64_t mtf : mtfs_containing_value) { - GetMtf(mtf).Promote(value); - } - } - - // Inserts |value| in sequence |mtf| or promotes if it's already there. - void InsertOrPromote(uint64_t mtf, uint32_t value) { - if (!Insert(mtf, value)) { - GetMtf(mtf).Promote(value); - } - } - - // Returns if |mtf| sequence has |value|. - bool HasValue(uint64_t mtf, uint32_t value) { - return GetMtf(mtf).HasValue(value); - } - - private: - // Returns actual MoveToFront object corresponding to |handle|. - // As multiple operations are often performed consecutively for the same - // sequence, the last returned value is cached. - MoveToFront& GetMtf(uint64_t handle) { - if (!cached_mtf_ || cached_handle_ != handle) { - cached_handle_ = handle; - cached_mtf_ = &mtfs_[handle]; - } - - return *cached_mtf_; - } - - // Container holding MoveToFront objects. Map key is sequence handle. - std::map mtfs_; - - // Container mapping value to sequences which contain that value. - std::unordered_map> val_to_mtfs_; - - // Cache for the last accessed sequence. - uint64_t cached_handle_ = 0; - MoveToFront* cached_mtf_ = nullptr; -}; - -} // namespace comp -} // namespace spvtools - -#endif // SOURCE_COMP_MOVE_TO_FRONT_H_ diff --git a/third_party/spirv-tools/source/disassemble.cpp b/third_party/spirv-tools/source/disassemble.cpp index c116f50722..4b3972b51d 100644 --- a/third_party/spirv-tools/source/disassemble.cpp +++ b/third_party/spirv-tools/source/disassemble.cpp @@ -217,10 +217,18 @@ void Disassembler::EmitOperand(const spv_parsed_instruction_t& inst, break; case SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER: { spv_ext_inst_desc ext_inst; - if (grammar_.lookupExtInst(inst.ext_inst_type, word, &ext_inst)) - assert(false && "should have caught this earlier"); SetRed(); - stream_ << ext_inst->name; + if (grammar_.lookupExtInst(inst.ext_inst_type, word, &ext_inst) == + SPV_SUCCESS) { + stream_ << ext_inst->name; + } else { + if (!spvExtInstIsNonSemantic(inst.ext_inst_type)) { + assert(false && "should have caught this earlier"); + } else { + // for non-semantic instruction sets we can just print the number + stream_ << word; + } + } } break; case SPV_OPERAND_TYPE_SPEC_CONSTANT_OP_NUMBER: { spv_opcode_desc opcode_desc; @@ -272,7 +280,12 @@ void Disassembler::EmitOperand(const spv_parsed_instruction_t& inst, case SPV_OPERAND_TYPE_DEBUG_BASE_TYPE_ATTRIBUTE_ENCODING: case SPV_OPERAND_TYPE_DEBUG_COMPOSITE_TYPE: case SPV_OPERAND_TYPE_DEBUG_TYPE_QUALIFIER: - case SPV_OPERAND_TYPE_DEBUG_OPERATION: { + case SPV_OPERAND_TYPE_DEBUG_OPERATION: + case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_BASE_TYPE_ATTRIBUTE_ENCODING: + case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_COMPOSITE_TYPE: + case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_TYPE_QUALIFIER: + case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_OPERATION: + case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_IMPORTED_ENTITY: { spv_operand_desc entry; if (grammar_.lookupOperand(operand.type, word, &entry)) assert(false && "should have caught this earlier"); @@ -285,6 +298,7 @@ void Disassembler::EmitOperand(const spv_parsed_instruction_t& inst, case SPV_OPERAND_TYPE_MEMORY_ACCESS: case SPV_OPERAND_TYPE_SELECTION_CONTROL: case SPV_OPERAND_TYPE_DEBUG_INFO_FLAGS: + case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_INFO_FLAGS: EmitMaskOperand(operand.type, word); break; default: diff --git a/third_party/spirv-tools/source/enum_set.h b/third_party/spirv-tools/source/enum_set.h index e4ef297cd7..2e7046d4ec 100644 --- a/third_party/spirv-tools/source/enum_set.h +++ b/third_party/spirv-tools/source/enum_set.h @@ -69,6 +69,26 @@ class EnumSet { return *this; } + friend bool operator==(const EnumSet& a, const EnumSet& b) { + if (a.mask_ != b.mask_) { + return false; + } + + if (a.overflow_ == nullptr && b.overflow_ == nullptr) { + return true; + } + + if (a.overflow_ == nullptr || b.overflow_ == nullptr) { + return false; + } + + return *a.overflow_ == *b.overflow_; + } + + friend bool operator!=(const EnumSet& a, const EnumSet& b) { + return !(a == b); + } + // Adds the given enum value to the set. This has no effect if the // enum value is already in the set. void Add(EnumType c) { AddWord(ToWord(c)); } diff --git a/third_party/spirv-tools/source/ext_inst.cpp b/third_party/spirv-tools/source/ext_inst.cpp index a4c00c2fff..e69c3c9b79 100644 --- a/third_party/spirv-tools/source/ext_inst.cpp +++ b/third_party/spirv-tools/source/ext_inst.cpp @@ -14,7 +14,6 @@ #include "source/ext_inst.h" -#include #include // DebugInfo extended instruction set. @@ -29,8 +28,10 @@ #include "debuginfo.insts.inc" #include "glsl.std.450.insts.inc" +#include "opencl.debuginfo.100.insts.inc" #include "opencl.std.insts.inc" +#include "spirv-tools/libspirv.h" #include "spv-amd-gcn-shader.insts.inc" #include "spv-amd-shader-ballot.insts.inc" #include "spv-amd-shader-explicit-vertex-parameter.insts.inc" @@ -51,6 +52,8 @@ static const spv_ext_inst_group_t kGroups_1_0[] = { ARRAY_SIZE(spv_amd_shader_ballot_entries), spv_amd_shader_ballot_entries}, {SPV_EXT_INST_TYPE_DEBUGINFO, ARRAY_SIZE(debuginfo_entries), debuginfo_entries}, + {SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100, + ARRAY_SIZE(opencl_debuginfo_100_entries), opencl_debuginfo_100_entries}, }; static const spv_ext_inst_table_t kTable_1_0 = {ARRAY_SIZE(kGroups_1_0), @@ -81,11 +84,14 @@ spv_result_t spvExtInstTableGet(spv_ext_inst_table* pExtInstTable, case SPV_ENV_OPENGL_4_5: case SPV_ENV_UNIVERSAL_1_3: case SPV_ENV_VULKAN_1_1: + case SPV_ENV_VULKAN_1_1_SPIRV_1_4: case SPV_ENV_WEBGPU_0: + case SPV_ENV_UNIVERSAL_1_4: + case SPV_ENV_UNIVERSAL_1_5: + case SPV_ENV_VULKAN_1_2: *pExtInstTable = &kTable_1_0; return SPV_SUCCESS; default: - assert(0 && "Unknown spv_target_env in spvExtInstTableGet()"); return SPV_ERROR_INVALID_TABLE; } } @@ -114,9 +120,32 @@ spv_ext_inst_type_t spvExtInstImportTypeGet(const char* name) { if (!strcmp("DebugInfo", name)) { return SPV_EXT_INST_TYPE_DEBUGINFO; } + if (!strcmp("OpenCL.DebugInfo.100", name)) { + return SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100; + } + // ensure to add any known non-semantic extended instruction sets + // above this point, and update spvExtInstIsNonSemantic() + if (!strncmp("NonSemantic.", name, 12)) { + return SPV_EXT_INST_TYPE_NONSEMANTIC_UNKNOWN; + } return SPV_EXT_INST_TYPE_NONE; } +bool spvExtInstIsNonSemantic(const spv_ext_inst_type_t type) { + if (type == SPV_EXT_INST_TYPE_NONSEMANTIC_UNKNOWN) { + return true; + } + return false; +} + +bool spvExtInstIsDebugInfo(const spv_ext_inst_type_t type) { + if (type == SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100 || + type == SPV_EXT_INST_TYPE_DEBUGINFO) { + return true; + } + return false; +} + spv_result_t spvExtInstTableNameLookup(const spv_ext_inst_table table, const spv_ext_inst_type_t type, const char* name, diff --git a/third_party/spirv-tools/source/ext_inst.h b/third_party/spirv-tools/source/ext_inst.h index a821cc2bc7..aff6e308c7 100644 --- a/third_party/spirv-tools/source/ext_inst.h +++ b/third_party/spirv-tools/source/ext_inst.h @@ -21,6 +21,12 @@ // Gets the type of the extended instruction set with the specified name. spv_ext_inst_type_t spvExtInstImportTypeGet(const char* name); +// Returns true if the extended instruction set is non-semantic +bool spvExtInstIsNonSemantic(const spv_ext_inst_type_t type); + +// Returns true if the extended instruction set is debug info +bool spvExtInstIsDebugInfo(const spv_ext_inst_type_t type); + // Finds the named extented instruction of the given type in the given extended // instruction table. On success, returns SPV_SUCCESS and writes a handle of // the instruction entry into *entry. diff --git a/third_party/spirv-tools/source/extinst.opencl.debuginfo.100.grammar.json b/third_party/spirv-tools/source/extinst.opencl.debuginfo.100.grammar.json new file mode 100644 index 0000000000..08062be4f6 --- /dev/null +++ b/third_party/spirv-tools/source/extinst.opencl.debuginfo.100.grammar.json @@ -0,0 +1,632 @@ +{ + "copyright" : [ + "Copyright (c) 2018 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\"),", + "to deal in the Materials without restriction, including without limitation", + "the rights to use, copy, modify, merge, publish, distribute, sublicense,", + "and/or sell copies of the Materials, and to permit persons to whom the", + "Materials are furnished to do so, subject to the following conditions:", + "", + "The above copyright notice and this permission notice shall be included in", + "all copies or substantial portions of the Materials.", + "", + "MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS", + "STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND", + "HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/ ", + "", + "THE MATERIALS ARE PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS", + "OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,", + "FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL", + "THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER", + "LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING", + "FROM,OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS", + "IN THE MATERIALS." + ], + "version" : 200, + "revision" : 2, + "instructions" : [ + { + "opname" : "DebugInfoNone", + "opcode" : 0 + }, + { + "opname" : "DebugCompilationUnit", + "opcode" : 1, + "operands" : [ + { "kind" : "LiteralInteger", "name" : "'Version'" }, + { "kind" : "LiteralInteger", "name" : "'DWARF Version'" }, + { "kind" : "IdRef", "name" : "'Source'" }, + { "kind" : "SourceLanguage", "name" : "'Language'" } + ] + }, + { + "opname" : "DebugTypeBasic", + "opcode" : 2, + "operands" : [ + { "kind" : "IdRef", "name" : "'Name'" }, + { "kind" : "IdRef", "name" : "'Size'" }, + { "kind" : "DebugBaseTypeAttributeEncoding", "name" : "'Encoding'" } + ] + }, + { + "opname" : "DebugTypePointer", + "opcode" : 3, + "operands" : [ + { "kind" : "IdRef", "name" : "'Base Type'" }, + { "kind" : "StorageClass", "name" : "'Storage Class'" }, + { "kind" : "DebugInfoFlags", "name" : "'Flags'" } + ] + }, + { + "opname" : "DebugTypeQualifier", + "opcode" : 4, + "operands" : [ + { "kind" : "IdRef", "name" : "'Base Type'" }, + { "kind" : "DebugTypeQualifier", "name" : "'Type Qualifier'" } + ] + }, + { + "opname" : "DebugTypeArray", + "opcode" : 5, + "operands" : [ + { "kind" : "IdRef", "name" : "'Base Type'" }, + { "kind" : "IdRef", "name" : "'Component Counts'", "quantifier" : "*" } + ] + }, + { + "opname" : "DebugTypeVector", + "opcode" : 6, + "operands" : [ + { "kind" : "IdRef", "name" : "'Base Type'" }, + { "kind" : "LiteralInteger", "name" : "'Component Count'" } + ] + }, + { + "opname" : "DebugTypedef", + "opcode" : 7, + "operands" : [ + { "kind" : "IdRef", "name" : "'Name'" }, + { "kind" : "IdRef", "name" : "'Base Type'" }, + { "kind" : "IdRef", "name" : "'Source'" }, + { "kind" : "LiteralInteger", "name" : "'Line'" }, + { "kind" : "LiteralInteger", "name" : "'Column'" }, + { "kind" : "IdRef", "name" : "'Parent'" } + ] + }, + { + "opname" : "DebugTypeFunction", + "opcode" : 8, + "operands" : [ + { "kind" : "DebugInfoFlags", "name" : "'Flags'" }, + { "kind" : "IdRef", "name" : "'Return Type'" }, + { "kind" : "IdRef", "name" : "'Parameter Types'", "quantifier" : "*" } + ] + }, + { + "opname" : "DebugTypeEnum", + "opcode" : 9, + "operands" : [ + { "kind" : "IdRef", "name" : "'Name'" }, + { "kind" : "IdRef", "name" : "'Underlying Type'" }, + { "kind" : "IdRef", "name" : "'Source'" }, + { "kind" : "LiteralInteger", "name" : "'Line'" }, + { "kind" : "LiteralInteger", "name" : "'Column'" }, + { "kind" : "IdRef", "name" : "'Parent'" }, + { "kind" : "IdRef", "name" : "'Size'" }, + { "kind" : "DebugInfoFlags", "name" : "'Flags'" }, + { "kind" : "PairIdRefIdRef", "name" : "'Value, Name, Value, Name, ...'", "quantifier" : "*" } + ] + }, + { + "opname" : "DebugTypeComposite", + "opcode" : 10, + "operands" : [ + { "kind" : "IdRef", "name" : "'Name'" }, + { "kind" : "DebugCompositeType", "name" : "'Tag'" }, + { "kind" : "IdRef", "name" : "'Source'" }, + { "kind" : "LiteralInteger", "name" : "'Line'" }, + { "kind" : "LiteralInteger", "name" : "'Column'" }, + { "kind" : "IdRef", "name" : "'Parent'" }, + { "kind" : "IdRef", "name" : "'Linkage Name'" }, + { "kind" : "IdRef", "name" : "'Size'" }, + { "kind" : "DebugInfoFlags", "name" : "'Flags'" }, + { "kind" : "IdRef", "name" : "'Members'", "quantifier" : "*" } + ] + }, + { + "opname" : "DebugTypeMember", + "opcode" : 11, + "operands" : [ + { "kind" : "IdRef", "name" : "'Name'" }, + { "kind" : "IdRef", "name" : "'Type'" }, + { "kind" : "IdRef", "name" : "'Source'" }, + { "kind" : "LiteralInteger", "name" : "'Line'" }, + { "kind" : "LiteralInteger", "name" : "'Column'" }, + { "kind" : "IdRef", "name" : "'Parent'" }, + { "kind" : "IdRef", "name" : "'Offset'" }, + { "kind" : "IdRef", "name" : "'Size'" }, + { "kind" : "DebugInfoFlags", "name" : "'Flags'" }, + { "kind" : "IdRef", "name" : "'Value'", "quantifier" : "?" } + ] + }, + { + "opname" : "DebugTypeInheritance", + "opcode" : 12, + "operands" : [ + { "kind" : "IdRef", "name" : "'Child'" }, + { "kind" : "IdRef", "name" : "'Parent'" }, + { "kind" : "IdRef", "name" : "'Offset'" }, + { "kind" : "IdRef", "name" : "'Size'" }, + { "kind" : "DebugInfoFlags", "name" : "'Flags'" } + ] + }, + { + "opname" : "DebugTypePtrToMember", + "opcode" : 13, + "operands" : [ + { "kind" : "IdRef", "name" : "'Member Type'" }, + { "kind" : "IdRef", "name" : "'Parent'" } + ] + }, + { + "opname" : "DebugTypeTemplate", + "opcode" : 14, + "operands" : [ + { "kind" : "IdRef", "name" : "'Target'" }, + { "kind" : "IdRef", "name" : "'Parameters'", "quantifier" : "*" } + ] + }, + { + "opname" : "DebugTypeTemplateParameter", + "opcode" : 15, + "operands" : [ + { "kind" : "IdRef", "name" : "'Name'" }, + { "kind" : "IdRef", "name" : "'Actual Type'" }, + { "kind" : "IdRef", "name" : "'Value'" }, + { "kind" : "IdRef", "name" : "'Source'" }, + { "kind" : "LiteralInteger", "name" : "'Line'" }, + { "kind" : "LiteralInteger", "name" : "'Column'" } + ] + }, + { + "opname" : "DebugTypeTemplateTemplateParameter", + "opcode" : 16, + "operands" : [ + { "kind" : "IdRef", "name" : "'Name'" }, + { "kind" : "IdRef", "name" : "'Template Name'" }, + { "kind" : "IdRef", "name" : "'Source'" }, + { "kind" : "LiteralInteger", "name" : "'Line'" }, + { "kind" : "LiteralInteger", "name" : "'Column'" } + ] + }, + { + "opname" : "DebugTypeTemplateParameterPack", + "opcode" : 17, + "operands" : [ + { "kind" : "IdRef", "name" : "'Name'" }, + { "kind" : "IdRef", "name" : "'Source'" }, + { "kind" : "LiteralInteger", "name" : "'Line'" }, + { "kind" : "LiteralInteger", "name" : "'Column'" }, + { "kind" : "IdRef", "name" : "'Template Parameters'", "quantifier" : "*" } + ] + }, + { + "opname" : "DebugGlobalVariable", + "opcode" : 18, + "operands" : [ + { "kind" : "IdRef", "name" : "'Name'" }, + { "kind" : "IdRef", "name" : "'Type'" }, + { "kind" : "IdRef", "name" : "'Source'" }, + { "kind" : "LiteralInteger", "name" : "'Line'" }, + { "kind" : "LiteralInteger", "name" : "'Column'" }, + { "kind" : "IdRef", "name" : "'Parent'" }, + { "kind" : "IdRef", "name" : "'Linkage Name'" }, + { "kind" : "IdRef", "name" : "'Variable'" }, + { "kind" : "DebugInfoFlags", "name" : "'Flags'" }, + { "kind" : "IdRef", "name" : "'Static Member Declaration'", "quantifier" : "?" } + ] + }, + { + "opname" : "DebugFunctionDeclaration", + "opcode" : 19, + "operands" : [ + { "kind" : "IdRef", "name" : "'Name'" }, + { "kind" : "IdRef", "name" : "'Type'" }, + { "kind" : "IdRef", "name" : "'Source'" }, + { "kind" : "LiteralInteger", "name" : "'Line'" }, + { "kind" : "LiteralInteger", "name" : "'Column'" }, + { "kind" : "IdRef", "name" : "'Parent'" }, + { "kind" : "IdRef", "name" : "'Linkage Name'" }, + { "kind" : "DebugInfoFlags", "name" : "'Flags'" } + ] + }, + { + "opname" : "DebugFunction", + "opcode" : 20, + "operands" : [ + { "kind" : "IdRef", "name" : "'Name'" }, + { "kind" : "IdRef", "name" : "'Type'" }, + { "kind" : "IdRef", "name" : "'Source'" }, + { "kind" : "LiteralInteger", "name" : "'Line'" }, + { "kind" : "LiteralInteger", "name" : "'Column'" }, + { "kind" : "IdRef", "name" : "'Parent'" }, + { "kind" : "IdRef", "name" : "'Linkage Name'" }, + { "kind" : "DebugInfoFlags", "name" : "'Flags'" }, + { "kind" : "LiteralInteger", "name" : "'Scope Line'" }, + { "kind" : "IdRef", "name" : "'Function'" }, + { "kind" : "IdRef", "name" : "'Declaration'", "quantifier" : "?" } + ] + }, + { + "opname" : "DebugLexicalBlock", + "opcode" : 21, + "operands" : [ + { "kind" : "IdRef", "name" : "'Source'" }, + { "kind" : "LiteralInteger", "name" : "'Line'" }, + { "kind" : "LiteralInteger", "name" : "'Column'" }, + { "kind" : "IdRef", "name" : "'Parent'" }, + { "kind" : "IdRef", "name" : "'Name'", "quantifier" : "?" } + ] + }, + { + "opname" : "DebugLexicalBlockDiscriminator", + "opcode" : 22, + "operands" : [ + { "kind" : "IdRef", "name" : "'Source'" }, + { "kind" : "LiteralInteger", "name" : "'Discriminator'" }, + { "kind" : "IdRef", "name" : "'Parent'" } + ] + }, + { + "opname" : "DebugScope", + "opcode" : 23, + "operands" : [ + { "kind" : "IdRef", "name" : "'Scope'" }, + { "kind" : "IdRef", "name" : "'Inlined At'", "quantifier" : "?" } + ] + }, + { + "opname" : "DebugNoScope", + "opcode" : 24 + }, + { + "opname" : "DebugInlinedAt", + "opcode" : 25, + "operands" : [ + { "kind" : "LiteralInteger", "name" : "'Line'" }, + { "kind" : "IdRef", "name" : "'Scope'" }, + { "kind" : "IdRef", "name" : "'Inlined'", "quantifier" : "?" } + ] + }, + { + "opname" : "DebugLocalVariable", + "opcode" : 26, + "operands" : [ + { "kind" : "IdRef", "name" : "'Name'" }, + { "kind" : "IdRef", "name" : "'Type'" }, + { "kind" : "IdRef", "name" : "'Source'" }, + { "kind" : "LiteralInteger", "name" : "'Line'" }, + { "kind" : "LiteralInteger", "name" : "'Column'" }, + { "kind" : "IdRef", "name" : "'Parent'" }, + { "kind" : "DebugInfoFlags", "name" : "'Flags'" }, + { "kind" : "LiteralInteger", "name" : "'Arg Number'", "quantifier" : "?" } + ] + }, + { + "opname" : "DebugInlinedVariable", + "opcode" : 27, + "operands" : [ + { "kind" : "IdRef", "name" : "'Variable'" }, + { "kind" : "IdRef", "name" : "'Inlined'" } + ] + }, + { + "opname" : "DebugDeclare", + "opcode" : 28, + "operands" : [ + { "kind" : "IdRef", "name" : "'Local Variable'" }, + { "kind" : "IdRef", "name" : "'Variable'" }, + { "kind" : "IdRef", "name" : "'Expression'" } + ] + }, + { + "opname" : "DebugValue", + "opcode" : 29, + "operands" : [ + { "kind" : "IdRef", "name" : "'Local Variable'" }, + { "kind" : "IdRef", "name" : "'Value'" }, + { "kind" : "IdRef", "name" : "'Expression'" }, + { "kind" : "IdRef", "name" : "'Indexes'", "quantifier" : "*" } + ] + }, + { + "opname" : "DebugOperation", + "opcode" : 30, + "operands" : [ + { "kind" : "DebugOperation", "name" : "'OpCode'" }, + { "kind" : "LiteralInteger", "name" : "'Operands ...'", "quantifier" : "*" } + ] + }, + { + "opname" : "DebugExpression", + "opcode" : 31, + "operands" : [ + { "kind" : "IdRef", "name" : "'Operands ...'", "quantifier" : "*" } + ] + }, + { + "opname" : "DebugMacroDef", + "opcode" : 32, + "operands" : [ + { "kind" : "IdRef", "name" : "'Source'" }, + { "kind" : "LiteralInteger", "name" : "'Line'" }, + { "kind" : "IdRef", "name" : "'Name'" }, + { "kind" : "IdRef", "name" : "'Value'", "quantifier" : "?" } + ] + }, + { + "opname" : "DebugMacroUndef", + "opcode" : 33, + "operands" : [ + { "kind" : "IdRef", "name" : "'Source'" }, + { "kind" : "LiteralInteger", "name" : "'Line'" }, + { "kind" : "IdRef", "name" : "'Macro'" } + ] + }, + { + "opname" : "DebugImportedEntity", + "opcode" : 34, + "operands" : [ + { "kind" : "IdRef", "name" : "'Name'" }, + { "kind" : "DebugImportedEntity", "name" : "'Tag'" }, + { "kind" : "IdRef", "name" : "'Source'" }, + { "kind" : "IdRef", "name" : "'Entity'" }, + { "kind" : "LiteralInteger", "name" : "'Line'" }, + { "kind" : "LiteralInteger", "name" : "'Column'" }, + { "kind" : "IdRef", "name" : "'Parent'" } + ] + }, + { + "opname" : "DebugSource", + "opcode" : 35, + "operands" : [ + { "kind" : "IdRef", "name" : "'File'" }, + { "kind" : "IdRef", "name" : "'Text'", "quantifier" : "?" } + ] + } + ], + "operand_kinds" : [ + { + "category" : "BitEnum", + "kind" : "DebugInfoFlags", + "enumerants" : [ + { + "enumerant" : "FlagIsProtected", + "value" : "0x01" + }, + { + "enumerant" : "FlagIsPrivate", + "value" : "0x02" + }, + { + "enumerant" : "FlagIsPublic", + "value" : "0x03" + }, + { + "enumerant" : "FlagIsLocal", + "value" : "0x04" + }, + { + "enumerant" : "FlagIsDefinition", + "value" : "0x08" + }, + { + "enumerant" : "FlagFwdDecl", + "value" : "0x10" + }, + { + "enumerant" : "FlagArtificial", + "value" : "0x20" + }, + { + "enumerant" : "FlagExplicit", + "value" : "0x40" + }, + { + "enumerant" : "FlagPrototyped", + "value" : "0x80" + }, + { + "enumerant" : "FlagObjectPointer", + "value" : "0x100" + }, + { + "enumerant" : "FlagStaticMember", + "value" : "0x200" + }, + { + "enumerant" : "FlagIndirectVariable", + "value" : "0x400" + }, + { + "enumerant" : "FlagLValueReference", + "value" : "0x800" + }, + { + "enumerant" : "FlagRValueReference", + "value" : "0x1000" + }, + { + "enumerant" : "FlagIsOptimized", + "value" : "0x2000" + }, + { + "enumerant" : "FlagIsEnumClass", + "value" : "0x4000" + }, + { + "enumerant" : "FlagTypePassByValue", + "value" : "0x8000" + }, + { + "enumerant" : "FlagTypePassByReference", + "value" : "0x10000" + } + ] + }, + { + "category" : "ValueEnum", + "kind" : "DebugBaseTypeAttributeEncoding", + "enumerants" : [ + { + "enumerant" : "Unspecified", + "value" : "0" + }, + { + "enumerant" : "Address", + "value" : "1" + }, + { + "enumerant" : "Boolean", + "value" : "2" + }, + { + "enumerant" : "Float", + "value" : "3" + }, + { + "enumerant" : "Signed", + "value" : "4" + }, + { + "enumerant" : "SignedChar", + "value" : "5" + }, + { + "enumerant" : "Unsigned", + "value" : "6" + }, + { + "enumerant" : "UnsignedChar", + "value" : "7" + } + ] + }, + { + "category" : "ValueEnum", + "kind" : "DebugCompositeType", + "enumerants" : [ + { + "enumerant" : "Class", + "value" : "0" + }, + { + "enumerant" : "Structure", + "value" : "1" + }, + { + "enumerant" : "Union", + "value" : "2" + } + ] + }, + { + "category" : "ValueEnum", + "kind" : "DebugTypeQualifier", + "enumerants" : [ + { + "enumerant" : "ConstType", + "value" : "0" + }, + { + "enumerant" : "VolatileType", + "value" : "1" + }, + { + "enumerant" : "RestrictType", + "value" : "2" + }, + { + "enumerant" : "AtomicType", + "value" : "3" + } + ] + }, + { + "category" : "ValueEnum", + "kind" : "DebugOperation", + "enumerants" : [ + { + "enumerant" : "Deref", + "value" : "0" + }, + { + "enumerant" : "Plus", + "value" : "1" + }, + { + "enumerant" : "Minus", + "value" : "2" + }, + { + "enumerant" : "PlusUconst", + "value" : "3", + "parameters" : [ + { "kind" : "LiteralInteger" } + ] + }, + { + "enumerant" : "BitPiece", + "value" : "4", + "parameters" : [ + { "kind" : "LiteralInteger" }, + { "kind" : "LiteralInteger" } + ] + }, + { + "enumerant" : "Swap", + "value" : "5" + }, + { + "enumerant" : "Xderef", + "value" : "6" + }, + { + "enumerant" : "StackValue", + "value" : "7" + }, + { + "enumerant" : "Constu", + "value" : "8", + "parameters" : [ + { "kind" : "LiteralInteger" } + ] + }, + { + "enumerant" : "Fragment", + "value" : "9", + "parameters" : [ + { "kind" : "LiteralInteger" }, + { "kind" : "LiteralInteger" } + ] + } + ] + }, + { + "category" : "ValueEnum", + "kind" : "DebugImportedEntity", + "enumerants" : [ + { + "enumerant" : "ImportedModule", + "value" : "0" + }, + { + "enumerant" : "ImportedDeclaration", + "value" : "1" + } + ] + } + ] +} diff --git a/third_party/spirv-tools/source/fuzz/CMakeLists.txt b/third_party/spirv-tools/source/fuzz/CMakeLists.txt new file mode 100644 index 0000000000..c816f87576 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/CMakeLists.txt @@ -0,0 +1,230 @@ +# Copyright (c) 2019 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. + +if(SPIRV_BUILD_FUZZER) + + file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/protobufs) + + set(PROTOBUF_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/protobufs/spvtoolsfuzz.proto) + + add_custom_command( + OUTPUT protobufs/spvtoolsfuzz.pb.cc protobufs/spvtoolsfuzz.pb.h + COMMAND protobuf::protoc + -I=${CMAKE_CURRENT_SOURCE_DIR}/protobufs + --cpp_out=protobufs + ${PROTOBUF_SOURCE} + DEPENDS ${PROTOBUF_SOURCE} + COMMENT "Generate protobuf sources from proto definition file." + ) + + set(SPIRV_TOOLS_FUZZ_SOURCES + data_descriptor.h + equivalence_relation.h + fact_manager.h + force_render_red.h + fuzzer.h + fuzzer_context.h + fuzzer_pass.h + fuzzer_pass_add_composite_types.h + fuzzer_pass_add_dead_blocks.h + fuzzer_pass_add_dead_breaks.h + fuzzer_pass_add_dead_continues.h + fuzzer_pass_add_no_contraction_decorations.h + fuzzer_pass_add_useful_constructs.h + fuzzer_pass_adjust_function_controls.h + fuzzer_pass_adjust_loop_controls.h + fuzzer_pass_adjust_memory_operands_masks.h + fuzzer_pass_adjust_selection_controls.h + fuzzer_pass_apply_id_synonyms.h + fuzzer_pass_construct_composites.h + fuzzer_pass_copy_objects.h + fuzzer_pass_donate_modules.h + fuzzer_pass_merge_blocks.h + fuzzer_pass_obfuscate_constants.h + fuzzer_pass_outline_functions.h + fuzzer_pass_permute_blocks.h + fuzzer_pass_split_blocks.h + fuzzer_util.h + id_use_descriptor.h + instruction_descriptor.h + instruction_message.h + protobufs/spirvfuzz_protobufs.h + pseudo_random_generator.h + random_generator.h + replayer.h + shrinker.h + transformation.h + transformation_add_constant_boolean.h + transformation_add_constant_composite.h + transformation_add_constant_scalar.h + transformation_add_dead_block.h + transformation_add_dead_break.h + transformation_add_dead_continue.h + transformation_add_function.h + transformation_add_global_undef.h + transformation_add_global_variable.h + transformation_add_no_contraction_decoration.h + transformation_add_type_array.h + transformation_add_type_boolean.h + transformation_add_type_float.h + transformation_add_type_function.h + transformation_add_type_int.h + transformation_add_type_matrix.h + transformation_add_type_pointer.h + transformation_add_type_struct.h + transformation_add_type_vector.h + transformation_composite_construct.h + transformation_composite_extract.h + transformation_copy_object.h + transformation_merge_blocks.h + transformation_move_block_down.h + transformation_outline_function.h + transformation_replace_boolean_constant_with_constant_binary.h + transformation_replace_constant_with_uniform.h + transformation_replace_id_with_synonym.h + transformation_set_function_control.h + transformation_set_loop_control.h + transformation_set_memory_operands_mask.h + transformation_set_selection_control.h + transformation_split_block.h + transformation_vector_shuffle.h + uniform_buffer_element_descriptor.h + ${CMAKE_CURRENT_BINARY_DIR}/protobufs/spvtoolsfuzz.pb.h + + data_descriptor.cpp + fact_manager.cpp + force_render_red.cpp + fuzzer.cpp + fuzzer_context.cpp + fuzzer_pass.cpp + fuzzer_pass_add_composite_types.cpp + fuzzer_pass_add_dead_blocks.cpp + fuzzer_pass_add_dead_breaks.cpp + fuzzer_pass_add_dead_continues.cpp + fuzzer_pass_add_no_contraction_decorations.cpp + fuzzer_pass_add_useful_constructs.cpp + fuzzer_pass_adjust_function_controls.cpp + fuzzer_pass_adjust_loop_controls.cpp + fuzzer_pass_adjust_memory_operands_masks.cpp + fuzzer_pass_adjust_selection_controls.cpp + fuzzer_pass_apply_id_synonyms.cpp + fuzzer_pass_construct_composites.cpp + fuzzer_pass_copy_objects.cpp + fuzzer_pass_donate_modules.cpp + fuzzer_pass_merge_blocks.cpp + fuzzer_pass_obfuscate_constants.cpp + fuzzer_pass_outline_functions.cpp + fuzzer_pass_permute_blocks.cpp + fuzzer_pass_split_blocks.cpp + fuzzer_util.cpp + id_use_descriptor.cpp + instruction_descriptor.cpp + instruction_message.cpp + pseudo_random_generator.cpp + random_generator.cpp + replayer.cpp + shrinker.cpp + transformation.cpp + transformation_add_constant_boolean.cpp + transformation_add_constant_composite.cpp + transformation_add_constant_scalar.cpp + transformation_add_dead_block.cpp + transformation_add_dead_break.cpp + transformation_add_dead_continue.cpp + transformation_add_function.cpp + transformation_add_global_undef.cpp + transformation_add_global_variable.cpp + transformation_add_no_contraction_decoration.cpp + transformation_add_type_array.cpp + transformation_add_type_boolean.cpp + transformation_add_type_float.cpp + transformation_add_type_function.cpp + transformation_add_type_int.cpp + transformation_add_type_matrix.cpp + transformation_add_type_pointer.cpp + transformation_add_type_struct.cpp + transformation_add_type_vector.cpp + transformation_composite_construct.cpp + transformation_composite_extract.cpp + transformation_copy_object.cpp + transformation_merge_blocks.cpp + transformation_move_block_down.cpp + transformation_outline_function.cpp + transformation_replace_boolean_constant_with_constant_binary.cpp + transformation_replace_constant_with_uniform.cpp + transformation_replace_id_with_synonym.cpp + transformation_set_function_control.cpp + transformation_set_loop_control.cpp + transformation_set_memory_operands_mask.cpp + transformation_set_selection_control.cpp + transformation_split_block.cpp + transformation_vector_shuffle.cpp + uniform_buffer_element_descriptor.cpp + ${CMAKE_CURRENT_BINARY_DIR}/protobufs/spvtoolsfuzz.pb.cc + ) + + if(MSVC) + # Enable parallel builds across four cores for this lib + add_definitions(/MP4) + endif() + + spvtools_pch(SPIRV_TOOLS_FUZZ_SOURCES pch_source_fuzz) + + add_library(SPIRV-Tools-fuzz ${SPIRV_TOOLS_FUZZ_SOURCES}) + + spvtools_default_compile_options(SPIRV-Tools-fuzz) + target_compile_definitions(SPIRV-Tools-fuzz PUBLIC -DGOOGLE_PROTOBUF_NO_RTTI -DGOOGLE_PROTOBUF_USE_UNALIGNED=0) + + # Compilation of the auto-generated protobuf source file will yield warnings, + # which we have no control over and thus wish to ignore. + if(${COMPILER_IS_LIKE_GNU}) + set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/protobufs/spvtoolsfuzz.pb.cc PROPERTIES COMPILE_FLAGS -w) + endif() + if(MSVC) + set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/protobufs/spvtoolsfuzz.pb.cc PROPERTIES COMPILE_FLAGS /w) + endif() + + target_include_directories(SPIRV-Tools-fuzz + PUBLIC + $ + $ + $ + PRIVATE ${spirv-tools_BINARY_DIR} + PRIVATE ${CMAKE_BINARY_DIR}) + + # The fuzzer reuses a lot of functionality from the SPIRV-Tools library. + target_link_libraries(SPIRV-Tools-fuzz + PUBLIC ${SPIRV_TOOLS} + PUBLIC SPIRV-Tools-opt + PUBLIC protobuf::libprotobuf) + + set_property(TARGET SPIRV-Tools-fuzz PROPERTY FOLDER "SPIRV-Tools libraries") + spvtools_check_symbol_exports(SPIRV-Tools-fuzz) + + if(ENABLE_SPIRV_TOOLS_INSTALL) + install(TARGETS SPIRV-Tools-fuzz EXPORT SPIRV-Tools-fuzzTargets + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) + export(EXPORT SPIRV-Tools-fuzzTargets FILE SPIRV-Tools-fuzzTarget.cmake) + + spvtools_config_package_dir(SPIRV-Tools-fuzz PACKAGE_DIR) + install(EXPORT SPIRV-Tools-fuzzTargets FILE SPIRV-Tools-fuzzTarget.cmake + DESTINATION ${PACKAGE_DIR}) + + spvtools_generate_config_file(SPIRV-Tools-fuzz) + install(FILES ${CMAKE_BINARY_DIR}/SPIRV-Tools-fuzzConfig.cmake DESTINATION ${PACKAGE_DIR}) + endif(ENABLE_SPIRV_TOOLS_INSTALL) + +endif(SPIRV_BUILD_FUZZER) diff --git a/third_party/spirv-tools/source/fuzz/data_descriptor.cpp b/third_party/spirv-tools/source/fuzz/data_descriptor.cpp new file mode 100644 index 0000000000..86e5325f14 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/data_descriptor.cpp @@ -0,0 +1,69 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/data_descriptor.h" + +#include + +namespace spvtools { +namespace fuzz { + +protobufs::DataDescriptor MakeDataDescriptor(uint32_t object, + std::vector&& indices) { + protobufs::DataDescriptor result; + result.set_object(object); + for (auto index : indices) { + result.add_index(index); + } + return result; +} + +size_t DataDescriptorHash::operator()( + const protobufs::DataDescriptor* data_descriptor) const { + std::u32string hash; + hash.push_back(data_descriptor->object()); + for (auto an_index : data_descriptor->index()) { + hash.push_back(an_index); + } + return std::hash()(hash); +} + +bool DataDescriptorEquals::operator()( + const protobufs::DataDescriptor* first, + const protobufs::DataDescriptor* second) const { + return first->object() == second->object() && + first->index().size() == second->index().size() && + std::equal(first->index().begin(), first->index().end(), + second->index().begin()); +} + +std::ostream& operator<<(std::ostream& out, + const protobufs::DataDescriptor& data_descriptor) { + out << data_descriptor.object(); + out << "["; + bool first = true; + for (auto index : data_descriptor.index()) { + if (first) { + first = false; + } else { + out << ", "; + } + out << index; + } + out << "]"; + return out; +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/data_descriptor.h b/third_party/spirv-tools/source/fuzz/data_descriptor.h new file mode 100644 index 0000000000..c569ac80a4 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/data_descriptor.h @@ -0,0 +1,48 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_DATA_DESCRIPTOR_H_ +#define SOURCE_FUZZ_DATA_DESCRIPTOR_H_ + +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" + +#include +#include + +namespace spvtools { +namespace fuzz { + +// Factory method to create a data descriptor message from an object id and a +// list of indices. +protobufs::DataDescriptor MakeDataDescriptor(uint32_t object, + std::vector&& indices); + +// Hash function for data descriptors. +struct DataDescriptorHash { + size_t operator()(const protobufs::DataDescriptor* data_descriptor) const; +}; + +// Equality function for data descriptors. +struct DataDescriptorEquals { + bool operator()(const protobufs::DataDescriptor* first, + const protobufs::DataDescriptor* second) const; +}; + +std::ostream& operator<<(std::ostream& out, + const protobufs::DataDescriptor& data_descriptor); + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_DATA_DESCRIPTOR_H_ diff --git a/third_party/spirv-tools/source/fuzz/equivalence_relation.h b/third_party/spirv-tools/source/fuzz/equivalence_relation.h new file mode 100644 index 0000000000..046536f80e --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/equivalence_relation.h @@ -0,0 +1,237 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_EQUIVALENCE_RELATION_H_ +#define SOURCE_FUZZ_EQUIVALENCE_RELATION_H_ + +#include +#include +#include +#include + +#include "source/util/make_unique.h" + +namespace spvtools { +namespace fuzz { + +// A class for representing an equivalence relation on objects of type |T|, +// which should be a value type. The type |T| is required to have a copy +// constructor, and |PointerHashT| and |PointerEqualsT| must be functors +// providing hashing and equality testing functionality for pointers to objects +// of type |T|. +// +// A disjoint-set (a.k.a. union-find or merge-find) data structure is used to +// represent the equivalence relation. Path compression is used. Union by +// rank/size is not used. +// +// Each disjoint set is represented as a tree, rooted at the representative +// of the set. +// +// Getting the representative of a value simply requires chasing parent pointers +// from the value until you reach the root. +// +// Checking equivalence of two elements requires checking that the +// representatives are equal. +// +// Traversing the tree rooted at a value's representative visits the value's +// equivalence class. +// +// |PointerHashT| and |PointerEqualsT| are used to define *equality* between +// values, and otherwise are *not* used to define the equivalence relation +// (except that equal values are equivalent). The equivalence relation is +// constructed by repeatedly adding pairs of (typically non-equal) values that +// are deemed to be equivalent. +// +// For example in an equivalence relation on integers, 1 and 5 might be added +// as equivalent, so that IsEquivalent(1, 5) holds, because they represent +// IDs in a SPIR-V binary that are known to contain the same value at run time, +// but clearly 1 != 5. Since 1 and 1 are equal, IsEquivalent(1, 1) will also +// hold. +// +// Each unique (up to equality) value added to the relation is copied into +// |owned_values_|, so there is one canonical memory address per unique value. +// Uniqueness is ensured by storing (and checking) a set of pointers to these +// values in |value_set_|, which uses |PointerHashT| and |PointerEqualsT|. +// +// |parent_| and |children_| encode the equivalence relation, i.e., the trees. +template +class EquivalenceRelation { + public: + // Merges the equivalence classes associated with |value1| and |value2|. + // If any of these values was not previously in the equivalence relation, it + // is added to the pool of values known to be in the relation. + void MakeEquivalent(const T& value1, const T& value2) { + // Register each value if necessary. + for (auto value : {value1, value2}) { + if (!Exists(value)) { + // Register the value in the equivalence relation. This relies on + // T having a copy constructor. + auto unique_pointer_to_value = MakeUnique(value); + auto pointer_to_value = unique_pointer_to_value.get(); + owned_values_.push_back(std::move(unique_pointer_to_value)); + value_set_.insert(pointer_to_value); + + // Initially say that the value is its own parent and that it has no + // children. + assert(pointer_to_value && "Representatives should never be null."); + parent_[pointer_to_value] = pointer_to_value; + children_[pointer_to_value] = std::vector(); + } + } + + // Look up canonical pointers to each of the values in the value pool. + const T* value1_ptr = *value_set_.find(&value1); + const T* value2_ptr = *value_set_.find(&value2); + + // If the values turn out to be identical, they are already in the same + // equivalence class so there is nothing to do. + if (value1_ptr == value2_ptr) { + return; + } + + // Find the representative for each value's equivalence class, and if they + // are not already in the same class, make one the parent of the other. + const T* representative1 = Find(value1_ptr); + const T* representative2 = Find(value2_ptr); + assert(representative1 && "Representatives should never be null."); + assert(representative2 && "Representatives should never be null."); + if (representative1 != representative2) { + parent_[representative1] = representative2; + children_[representative2].push_back(representative1); + } + } + + // Returns exactly one representative per equivalence class. + std::vector GetEquivalenceClassRepresentatives() const { + std::vector result; + for (auto& value : owned_values_) { + if (parent_[value.get()] == value.get()) { + result.push_back(value.get()); + } + } + return result; + } + + // Returns pointers to all values in the equivalence class of |value|, which + // must already be part of the equivalence relation. + std::vector GetEquivalenceClass(const T& value) const { + assert(Exists(value)); + + std::vector result; + + // Traverse the tree of values rooted at the representative of the + // equivalence class to which |value| belongs, and collect up all the values + // that are encountered. This constitutes the whole equivalence class. + std::vector stack; + stack.push_back(Find(*value_set_.find(&value))); + while (!stack.empty()) { + const T* item = stack.back(); + result.push_back(item); + stack.pop_back(); + for (auto child : children_[item]) { + stack.push_back(child); + } + } + return result; + } + + // Returns true if and only if |value1| and |value2| are in the same + // equivalence class. Both values must already be known to the equivalence + // relation. + bool IsEquivalent(const T& value1, const T& value2) const { + return Find(&value1) == Find(&value2); + } + + // Returns all values known to be part of the equivalence relation. + std::vector GetAllKnownValues() const { + std::vector result; + for (auto& value : owned_values_) { + result.push_back(value.get()); + } + return result; + } + + // Returns true if and only if |value| is known to be part of the equivalence + // relation. + bool Exists(const T& value) const { + return value_set_.find(&value) != value_set_.end(); + } + + private: + // Returns the representative of the equivalence class of |value|, which must + // already be known to the equivalence relation. This is the 'Find' operation + // in a classic union-find data structure. + const T* Find(const T* value) const { + assert(Exists(*value)); + + // Get the canonical pointer to the value from the value pool. + const T* known_value = *value_set_.find(value); + assert(parent_[known_value] && "Every known value should have a parent."); + + // Compute the result by chasing parents until we find a value that is its + // own parent. + const T* result = known_value; + while (parent_[result] != result) { + result = parent_[result]; + } + assert(result && "Representatives should never be null."); + + // At this point, |result| is the representative of the equivalence class. + // Now perform the 'path compression' optimization by doing another pass up + // the parent chain, setting the parent of each node to be the + // representative, and rewriting children correspondingly. + const T* current = known_value; + while (parent_[current] != result) { + const T* next = parent_[current]; + parent_[current] = result; + children_[result].push_back(current); + auto child_iterator = + std::find(children_[next].begin(), children_[next].end(), current); + assert(child_iterator != children_[next].end() && + "'next' is the parent of 'current', so 'current' should be a " + "child of 'next'"); + children_[next].erase(child_iterator); + current = next; + } + return result; + } + + // Maps every value to a parent. The representative of an equivalence class + // is its own parent. A value's representative can be found by walking its + // chain of ancestors. + // + // Mutable because the intuitively const method, 'Find', performs path + // compression. + mutable std::unordered_map parent_; + + // Stores the children of each value. This allows the equivalence class of + // a value to be calculated by traversing all descendents of the class's + // representative. + // + // Mutable because the intuitively const method, 'Find', performs path + // compression. + mutable std::unordered_map> children_; + + // The values known to the equivalence relation are allocated in + // |owned_values_|, and |value_pool_| provides (via |PointerHashT| and + // |PointerEqualsT|) a means for mapping a value of interest to a pointer + // into an equivalent value in |owned_values_|. + std::unordered_set value_set_; + std::vector> owned_values_; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_EQUIVALENCE_RELATION_H_ diff --git a/third_party/spirv-tools/source/fuzz/fact_manager.cpp b/third_party/spirv-tools/source/fuzz/fact_manager.cpp new file mode 100644 index 0000000000..a7b431120a --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/fact_manager.cpp @@ -0,0 +1,1032 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/fact_manager.h" + +#include +#include +#include + +#include "source/fuzz/equivalence_relation.h" +#include "source/fuzz/fuzzer_util.h" +#include "source/fuzz/uniform_buffer_element_descriptor.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace fuzz { + +namespace { + +std::string ToString(const protobufs::Fact& fact) { + assert(fact.fact_case() == protobufs::Fact::kConstantUniformFact && + "Right now this is the only fact we know how to stringify."); + std::stringstream stream; + stream << "(" + << fact.constant_uniform_fact() + .uniform_buffer_element_descriptor() + .descriptor_set() + << ", " + << fact.constant_uniform_fact() + .uniform_buffer_element_descriptor() + .binding() + << ")["; + + bool first = true; + for (auto index : fact.constant_uniform_fact() + .uniform_buffer_element_descriptor() + .index()) { + if (first) { + first = false; + } else { + stream << ", "; + } + stream << index; + } + + stream << "] == ["; + + first = true; + for (auto constant_word : fact.constant_uniform_fact().constant_word()) { + if (first) { + first = false; + } else { + stream << ", "; + } + stream << constant_word; + } + + stream << "]"; + return stream.str(); +} + +} // namespace + +//======================= +// Constant uniform facts + +// The purpose of this class is to group the fields and data used to represent +// facts about uniform constants. +class FactManager::ConstantUniformFacts { + public: + // See method in FactManager which delegates to this method. + bool AddFact(const protobufs::FactConstantUniform& fact, + opt::IRContext* context); + + // See method in FactManager which delegates to this method. + std::vector GetConstantsAvailableFromUniformsForType( + opt::IRContext* ir_context, uint32_t type_id) const; + + // See method in FactManager which delegates to this method. + const std::vector + GetUniformDescriptorsForConstant(opt::IRContext* ir_context, + uint32_t constant_id) const; + + // See method in FactManager which delegates to this method. + uint32_t GetConstantFromUniformDescriptor( + opt::IRContext* context, + const protobufs::UniformBufferElementDescriptor& uniform_descriptor) + const; + + // See method in FactManager which delegates to this method. + std::vector GetTypesForWhichUniformValuesAreKnown() const; + + // See method in FactManager which delegates to this method. + const std::vector>& + GetConstantUniformFactsAndTypes() const; + + private: + // Returns true if and only if the words associated with + // |constant_instruction| exactly match the words for the constant associated + // with |constant_uniform_fact|. + bool DataMatches( + const opt::Instruction& constant_instruction, + const protobufs::FactConstantUniform& constant_uniform_fact) const; + + // Yields the constant words associated with |constant_uniform_fact|. + std::vector GetConstantWords( + const protobufs::FactConstantUniform& constant_uniform_fact) const; + + // Yields the id of a constant of type |type_id| whose data matches the + // constant data in |constant_uniform_fact|, or 0 if no such constant is + // declared. + uint32_t GetConstantId( + opt::IRContext* context, + const protobufs::FactConstantUniform& constant_uniform_fact, + uint32_t type_id) const; + + // Checks that the width of a floating-point constant is supported, and that + // the constant is finite. + bool FloatingPointValueIsSuitable(const protobufs::FactConstantUniform& fact, + uint32_t width) const; + + std::vector> + facts_and_type_ids_; +}; + +uint32_t FactManager::ConstantUniformFacts::GetConstantId( + opt::IRContext* context, + const protobufs::FactConstantUniform& constant_uniform_fact, + uint32_t type_id) const { + auto type = context->get_type_mgr()->GetType(type_id); + assert(type != nullptr && "Unknown type id."); + auto constant = context->get_constant_mgr()->GetConstant( + type, GetConstantWords(constant_uniform_fact)); + return context->get_constant_mgr()->FindDeclaredConstant(constant, type_id); +} + +std::vector FactManager::ConstantUniformFacts::GetConstantWords( + const protobufs::FactConstantUniform& constant_uniform_fact) const { + std::vector result; + for (auto constant_word : constant_uniform_fact.constant_word()) { + result.push_back(constant_word); + } + return result; +} + +bool FactManager::ConstantUniformFacts::DataMatches( + const opt::Instruction& constant_instruction, + const protobufs::FactConstantUniform& constant_uniform_fact) const { + assert(constant_instruction.opcode() == SpvOpConstant); + std::vector data_in_constant; + for (uint32_t i = 0; i < constant_instruction.NumInOperands(); i++) { + data_in_constant.push_back(constant_instruction.GetSingleWordInOperand(i)); + } + return data_in_constant == GetConstantWords(constant_uniform_fact); +} + +std::vector +FactManager::ConstantUniformFacts::GetConstantsAvailableFromUniformsForType( + opt::IRContext* ir_context, uint32_t type_id) const { + std::vector result; + std::set already_seen; + for (auto& fact_and_type_id : facts_and_type_ids_) { + if (fact_and_type_id.second != type_id) { + continue; + } + if (auto constant_id = + GetConstantId(ir_context, fact_and_type_id.first, type_id)) { + if (already_seen.find(constant_id) == already_seen.end()) { + result.push_back(constant_id); + already_seen.insert(constant_id); + } + } + } + return result; +} + +const std::vector +FactManager::ConstantUniformFacts::GetUniformDescriptorsForConstant( + opt::IRContext* ir_context, uint32_t constant_id) const { + std::vector result; + auto constant_inst = ir_context->get_def_use_mgr()->GetDef(constant_id); + assert(constant_inst->opcode() == SpvOpConstant && + "The given id must be that of a constant"); + auto type_id = constant_inst->type_id(); + for (auto& fact_and_type_id : facts_and_type_ids_) { + if (fact_and_type_id.second != type_id) { + continue; + } + if (DataMatches(*constant_inst, fact_and_type_id.first)) { + result.emplace_back( + fact_and_type_id.first.uniform_buffer_element_descriptor()); + } + } + return result; +} + +uint32_t FactManager::ConstantUniformFacts::GetConstantFromUniformDescriptor( + opt::IRContext* context, + const protobufs::UniformBufferElementDescriptor& uniform_descriptor) const { + // Consider each fact. + for (auto& fact_and_type : facts_and_type_ids_) { + // Check whether the uniform descriptor associated with the fact matches + // |uniform_descriptor|. + if (UniformBufferElementDescriptorEquals()( + &uniform_descriptor, + &fact_and_type.first.uniform_buffer_element_descriptor())) { + return GetConstantId(context, fact_and_type.first, fact_and_type.second); + } + } + // No fact associated with the given uniform descriptor was found. + return 0; +} + +std::vector +FactManager::ConstantUniformFacts::GetTypesForWhichUniformValuesAreKnown() + const { + std::vector result; + for (auto& fact_and_type : facts_and_type_ids_) { + if (std::find(result.begin(), result.end(), fact_and_type.second) == + result.end()) { + result.push_back(fact_and_type.second); + } + } + return result; +} + +bool FactManager::ConstantUniformFacts::FloatingPointValueIsSuitable( + const protobufs::FactConstantUniform& fact, uint32_t width) const { + const uint32_t kFloatWidth = 32; + const uint32_t kDoubleWidth = 64; + if (width != kFloatWidth && width != kDoubleWidth) { + // Only 32- and 64-bit floating-point types are handled. + return false; + } + std::vector words = GetConstantWords(fact); + if (width == 32) { + float value; + memcpy(&value, words.data(), sizeof(float)); + if (!std::isfinite(value)) { + return false; + } + } else { + double value; + memcpy(&value, words.data(), sizeof(double)); + if (!std::isfinite(value)) { + return false; + } + } + return true; +} + +bool FactManager::ConstantUniformFacts::AddFact( + const protobufs::FactConstantUniform& fact, opt::IRContext* context) { + // Try to find a unique instruction that declares a variable such that the + // variable is decorated with the descriptor set and binding associated with + // the constant uniform fact. + opt::Instruction* uniform_variable = FindUniformVariable( + fact.uniform_buffer_element_descriptor(), context, true); + + if (!uniform_variable) { + return false; + } + + assert(SpvOpVariable == uniform_variable->opcode()); + assert(SpvStorageClassUniform == uniform_variable->GetSingleWordInOperand(0)); + + auto should_be_uniform_pointer_type = + context->get_type_mgr()->GetType(uniform_variable->type_id()); + if (!should_be_uniform_pointer_type->AsPointer()) { + return false; + } + if (should_be_uniform_pointer_type->AsPointer()->storage_class() != + SpvStorageClassUniform) { + return false; + } + auto should_be_uniform_pointer_instruction = + context->get_def_use_mgr()->GetDef(uniform_variable->type_id()); + auto composite_type = + should_be_uniform_pointer_instruction->GetSingleWordInOperand(1); + + auto final_element_type_id = fuzzerutil::WalkCompositeTypeIndices( + context, composite_type, + fact.uniform_buffer_element_descriptor().index()); + if (!final_element_type_id) { + return false; + } + auto final_element_type = + context->get_type_mgr()->GetType(final_element_type_id); + assert(final_element_type && + "There should be a type corresponding to this id."); + + if (!(final_element_type->AsFloat() || final_element_type->AsInteger())) { + return false; + } + auto width = final_element_type->AsFloat() + ? final_element_type->AsFloat()->width() + : final_element_type->AsInteger()->width(); + + if (final_element_type->AsFloat() && + !FloatingPointValueIsSuitable(fact, width)) { + return false; + } + + auto required_words = (width + 32 - 1) / 32; + if (static_cast(fact.constant_word().size()) != required_words) { + return false; + } + facts_and_type_ids_.emplace_back( + std::pair( + fact, final_element_type_id)); + return true; +} + +const std::vector>& +FactManager::ConstantUniformFacts::GetConstantUniformFactsAndTypes() const { + return facts_and_type_ids_; +} + +// End of uniform constant facts +//============================== + +//============================== +// Data synonym facts + +// The purpose of this class is to group the fields and data used to represent +// facts about data synonyms. +class FactManager::DataSynonymFacts { + public: + // See method in FactManager which delegates to this method. + void AddFact(const protobufs::FactDataSynonym& fact, opt::IRContext* context); + + // See method in FactManager which delegates to this method. + std::vector GetSynonymsForDataDescriptor( + const protobufs::DataDescriptor& data_descriptor, + opt::IRContext* context) const; + + // See method in FactManager which delegates to this method. + std::vector GetIdsForWhichSynonymsAreKnown( + opt::IRContext* context) const; + + // See method in FactManager which delegates to this method. + bool IsSynonymous(const protobufs::DataDescriptor& data_descriptor1, + const protobufs::DataDescriptor& data_descriptor2, + opt::IRContext* context) const; + + private: + // Adds |fact| to the set of managed facts, and recurses into sub-components + // of the data descriptors referenced in |fact|, if they are composites, to + // record that their components are pairwise-synonymous. + void AddFactRecursive(const protobufs::FactDataSynonym& fact, + opt::IRContext* context); + + // Inspects all known facts and adds corollary facts; e.g. if we know that + // a.x == b.x and a.y == b.y, where a and b have vec2 type, we can record + // that a == b holds. + // + // This method is expensive, and is thus called on demand: rather than + // computing the closure of facts each time a data synonym fact is added, we + // compute the closure only when a data synonym fact is *queried*. + void ComputeClosureOfFacts(opt::IRContext* context) const; + + // Returns true if and only if |dd1| and |dd2| are valid data descriptors + // whose associated data have the same type. + bool DataDescriptorsAreWellFormedAndComparable( + opt::IRContext* context, const protobufs::DataDescriptor& dd1, + const protobufs::DataDescriptor& dd2) const; + + // The data descriptors that are known to be synonymous with one another are + // captured by this equivalence relation. + // + // This member is mutable in order to allow the closure of facts captured by + // the relation to be computed lazily when a question about data synonym + // facts is asked. + mutable EquivalenceRelation + synonymous_; + + // When a new synonym fact is added, it may be possible to deduce further + // synonym facts by computing a closure of all known facts. However, there is + // no point computing this closure until a question regarding synonym facts is + // actually asked: if several facts are added in succession with no questions + // asked in between, we can avoid computing fact closures multiple times. + // + // This boolean tracks whether a closure computation is required - i.e., + // whether a new fact has been added since the last time such a computation + // was performed. + // + // It is mutable so faciliate having const methods, that provide answers to + // questions about data synonym facts, triggering closure computation on + // demand. + mutable bool closure_computation_required = false; +}; + +void FactManager::DataSynonymFacts::AddFact( + const protobufs::FactDataSynonym& fact, opt::IRContext* context) { + // Add the fact, including all facts relating sub-components of the data + // descriptors that are involved. + AddFactRecursive(fact, context); +} + +void FactManager::DataSynonymFacts::AddFactRecursive( + const protobufs::FactDataSynonym& fact, opt::IRContext* context) { + assert(DataDescriptorsAreWellFormedAndComparable(context, fact.data1(), + fact.data2())); + + // Record that the data descriptors provided in the fact are equivalent. + synonymous_.MakeEquivalent(fact.data1(), fact.data2()); + // As we have updated the equivalence relation, we might be able to deduce + // more facts by performing a closure computation, so we record that such a + // computation is required; it will be performed next time a method answering + // a data synonym fact-related question is invoked. + closure_computation_required = true; + + // We now check whether this is a synonym about composite objects. If it is, + // we can recursively add synonym facts about their associated sub-components. + + // Get the type of the object referred to by the first data descriptor in the + // synonym fact. + uint32_t type_id = fuzzerutil::WalkCompositeTypeIndices( + context, + context->get_def_use_mgr()->GetDef(fact.data1().object())->type_id(), + fact.data1().index()); + auto type = context->get_type_mgr()->GetType(type_id); + auto type_instruction = context->get_def_use_mgr()->GetDef(type_id); + assert(type != nullptr && + "Invalid data synonym fact: one side has an unknown type."); + + // Check whether the type is composite, recording the number of elements + // associated with the composite if so. + uint32_t num_composite_elements; + if (type->AsArray()) { + num_composite_elements = + fuzzerutil::GetArraySize(*type_instruction, context); + } else if (type->AsMatrix()) { + num_composite_elements = type->AsMatrix()->element_count(); + } else if (type->AsStruct()) { + num_composite_elements = + fuzzerutil::GetNumberOfStructMembers(*type_instruction); + } else if (type->AsVector()) { + num_composite_elements = type->AsVector()->element_count(); + } else { + // The type is not a composite, so return. + return; + } + + // If the fact has the form: + // obj_1[a_1, ..., a_m] == obj_2[b_1, ..., b_n] + // then for each composite index i, we add a fact of the form: + // obj_1[a_1, ..., a_m, i] == obj_2[b_1, ..., b_n, i] + for (uint32_t i = 0; i < num_composite_elements; i++) { + std::vector extended_indices1 = + fuzzerutil::RepeatedFieldToVector(fact.data1().index()); + extended_indices1.push_back(i); + std::vector extended_indices2 = + fuzzerutil::RepeatedFieldToVector(fact.data2().index()); + extended_indices2.push_back(i); + protobufs::FactDataSynonym extended_data_synonym_fact; + *extended_data_synonym_fact.mutable_data1() = + MakeDataDescriptor(fact.data1().object(), std::move(extended_indices1)); + *extended_data_synonym_fact.mutable_data2() = + MakeDataDescriptor(fact.data2().object(), std::move(extended_indices2)); + AddFactRecursive(extended_data_synonym_fact, context); + } +} + +void FactManager::DataSynonymFacts::ComputeClosureOfFacts( + opt::IRContext* context) const { + // Suppose that obj_1[a_1, ..., a_m] and obj_2[b_1, ..., b_n] are distinct + // data descriptors that describe objects of the same composite type, and that + // the composite type is comprised of k components. + // + // For example, if m is a mat4x4 and v a vec4, we might consider: + // m[2]: describes the 2nd column of m, a vec4 + // v[]: describes all of v, a vec4 + // + // Suppose that we know, for every 0 <= i < k, that the fact: + // obj_1[a_1, ..., a_m, i] == obj_2[b_1, ..., b_n, i] + // holds - i.e. that the children of the two data descriptors are synonymous. + // + // Then we can conclude that: + // obj_1[a_1, ..., a_m] == obj_2[b_1, ..., b_n] + // holds. + // + // For instance, if we have the facts: + // m[2, 0] == v[0] + // m[2, 1] == v[1] + // m[2, 2] == v[2] + // m[2, 3] == v[3] + // then we can conclude that: + // m[2] == v. + // + // This method repeatedly searches the equivalence relation of data + // descriptors, deducing and adding such facts, until a pass over the + // relation leads to no further facts being deduced. + + // The method relies on working with pairs of data descriptors, and in + // particular being able to hash and compare such pairs. + + using DataDescriptorPair = + std::pair; + + struct DataDescriptorPairHash { + std::size_t operator()(const DataDescriptorPair& pair) const { + return DataDescriptorHash()(&pair.first) ^ + DataDescriptorHash()(&pair.second); + } + }; + + struct DataDescriptorPairEquals { + bool operator()(const DataDescriptorPair& first, + const DataDescriptorPair& second) const { + return DataDescriptorEquals()(&first.first, &second.first) && + DataDescriptorEquals()(&first.second, &second.second); + } + }; + + // This map records, for a given pair of composite data descriptors of the + // same type, all the indices at which the data descriptors are known to be + // synonymous. A pair is a key to this map only if we have observed that + // the pair are synonymous at *some* index, but not at *all* indices. + // Once we find that a pair of data descriptors are equivalent at all indices + // we record the fact that they are synonymous and remove them from the map. + // + // Using the m and v example from above, initially the pair (m[2], v) would + // not be a key to the map. If we find that m[2, 2] == v[2] holds, we would + // add an entry: + // (m[2], v) -> [false, false, true, false] + // to record that they are synonymous at index 2. If we then find that + // m[2, 0] == v[0] holds, we would update this entry to: + // (m[2], v) -> [true, false, true, false] + // If we then find that m[2, 3] == v[3] holds, we would update this entry to: + // (m[2], v) -> [true, false, true, true] + // Finally, if we then find that m[2, 1] == v[1] holds, which would make the + // boolean vector true at every index, we would add the fact: + // m[2] == v + // to the equivalence relation and remove (m[2], v) from the map. + std::unordered_map, + DataDescriptorPairHash, DataDescriptorPairEquals> + candidate_composite_synonyms; + + // We keep looking for new facts until we perform a complete pass over the + // equivalence relation without finding any new facts. + while (closure_computation_required) { + // We have not found any new facts yet during this pass; we set this to + // 'true' if we do find a new fact. + closure_computation_required = false; + + // Consider each class in the equivalence relation. + for (auto representative : + synonymous_.GetEquivalenceClassRepresentatives()) { + auto equivalence_class = synonymous_.GetEquivalenceClass(*representative); + + // Consider every data descriptor in the equivalence class. + for (auto dd1_it = equivalence_class.begin(); + dd1_it != equivalence_class.end(); ++dd1_it) { + // If this data descriptor has no indices then it does not have the form + // obj_1[a_1, ..., a_m, i], so move on. + auto dd1 = *dd1_it; + if (dd1->index_size() == 0) { + continue; + } + + // Consider every other data descriptor later in the equivalence class + // (due to symmetry, there is no need to compare with previous data + // descriptors). + auto dd2_it = dd1_it; + for (++dd2_it; dd2_it != equivalence_class.end(); ++dd2_it) { + auto dd2 = *dd2_it; + // If this data descriptor has no indices then it does not have the + // form obj_2[b_1, ..., b_n, i], so move on. + if (dd2->index_size() == 0) { + continue; + } + + // At this point we know that: + // - |dd1| has the form obj_1[a_1, ..., a_m, i] + // - |dd2| has the form obj_2[b_1, ..., b_n, j] + assert(dd1->index_size() > 0 && dd2->index_size() > 0 && + "Control should not reach here if either data descriptor has " + "no indices."); + + // We are only interested if i == j. + if (dd1->index(dd1->index_size() - 1) != + dd2->index(dd2->index_size() - 1)) { + continue; + } + + const uint32_t common_final_index = dd1->index(dd1->index_size() - 1); + + // Make data descriptors |dd1_prefix| and |dd2_prefix| for + // obj_1[a_1, ..., a_m] + // and + // obj_2[b_1, ..., b_n] + // These are the two data descriptors we might be getting closer to + // deducing as being synonymous, due to knowing that they are + // synonymous when extended by a particular index. + protobufs::DataDescriptor dd1_prefix; + dd1_prefix.set_object(dd1->object()); + for (uint32_t i = 0; i < static_cast(dd1->index_size() - 1); + i++) { + dd1_prefix.add_index(dd1->index(i)); + } + protobufs::DataDescriptor dd2_prefix; + dd2_prefix.set_object(dd2->object()); + for (uint32_t i = 0; i < static_cast(dd2->index_size() - 1); + i++) { + dd2_prefix.add_index(dd2->index(i)); + } + assert(!DataDescriptorEquals()(&dd1_prefix, &dd2_prefix) && + "By construction these prefixes should be different."); + + // If we already know that these prefixes are synonymous, move on. + if (synonymous_.Exists(dd1_prefix) && + synonymous_.Exists(dd2_prefix) && + synonymous_.IsEquivalent(dd1_prefix, dd2_prefix)) { + continue; + } + + // Get the type of obj_1 + auto dd1_root_type_id = + context->get_def_use_mgr()->GetDef(dd1->object())->type_id(); + // Use this type, together with a_1, ..., a_m, to get the type of + // obj_1[a_1, ..., a_m]. + auto dd1_prefix_type = fuzzerutil::WalkCompositeTypeIndices( + context, dd1_root_type_id, dd1_prefix.index()); + + // Similarly, get the type of obj_2 and use it to get the type of + // obj_2[b_1, ..., b_n]. + auto dd2_root_type_id = + context->get_def_use_mgr()->GetDef(dd2->object())->type_id(); + auto dd2_prefix_type = fuzzerutil::WalkCompositeTypeIndices( + context, dd2_root_type_id, dd2_prefix.index()); + + // If the types of dd1_prefix and dd2_prefix are not the same, they + // cannot be synonymous. + if (dd1_prefix_type != dd2_prefix_type) { + continue; + } + + // At this point, we know we have synonymous data descriptors of the + // form: + // obj_1[a_1, ..., a_m, i] + // obj_2[b_1, ..., b_n, i] + // with the same last_index i, such that: + // obj_1[a_1, ..., a_m] + // and + // obj_2[b_1, ..., b_n] + // have the same type. + + // Work out how many components there are in the (common) commposite + // type associated with obj_1[a_1, ..., a_m] and obj_2[b_1, ..., b_n]. + // This depends on whether the composite type is array, matrix, struct + // or vector. + uint32_t num_components_in_composite; + auto composite_type = + context->get_type_mgr()->GetType(dd1_prefix_type); + auto composite_type_instruction = + context->get_def_use_mgr()->GetDef(dd1_prefix_type); + if (composite_type->AsArray()) { + num_components_in_composite = + fuzzerutil::GetArraySize(*composite_type_instruction, context); + if (num_components_in_composite == 0) { + // This indicates that the array has an unknown size, in which + // case we cannot be sure we have matched all of its elements with + // synonymous elements of another array. + continue; + } + } else if (composite_type->AsMatrix()) { + num_components_in_composite = + composite_type->AsMatrix()->element_count(); + } else if (composite_type->AsStruct()) { + num_components_in_composite = fuzzerutil::GetNumberOfStructMembers( + *composite_type_instruction); + } else { + assert(composite_type->AsVector()); + num_components_in_composite = + composite_type->AsVector()->element_count(); + } + + // We are one step closer to being able to say that |dd1_prefix| and + // |dd2_prefix| are synonymous. + DataDescriptorPair candidate_composite_synonym(dd1_prefix, + dd2_prefix); + + // We look up what we already know about this pair. + auto existing_entry = + candidate_composite_synonyms.find(candidate_composite_synonym); + + if (existing_entry == candidate_composite_synonyms.end()) { + // If this is the first time we have seen the pair, we make a vector + // of size |num_components_in_composite| that is 'true' at the + // common final index associated with |dd1| and |dd2|, and 'false' + // everywhere else, and register this vector as being associated + // with the pair. + std::vector entry; + for (uint32_t i = 0; i < num_components_in_composite; i++) { + entry.push_back(i == common_final_index); + } + candidate_composite_synonyms[candidate_composite_synonym] = entry; + existing_entry = + candidate_composite_synonyms.find(candidate_composite_synonym); + } else { + // We have seen this pair of data descriptors before, and we now + // know that they are synonymous at one further index, so we + // update the entry to record that. + existing_entry->second[common_final_index] = true; + } + assert(existing_entry != candidate_composite_synonyms.end()); + + // Check whether |dd1_prefix| and |dd2_prefix| are now known to match + // at every sub-component. + bool all_components_match = true; + for (uint32_t i = 0; i < num_components_in_composite; i++) { + if (!existing_entry->second[i]) { + all_components_match = false; + break; + } + } + if (all_components_match) { + // The two prefixes match on all sub-components, so we know that + // they are synonymous. We add this fact *non-recursively*, as we + // have deduced that |dd1_prefix| and |dd2_prefix| are synonymous + // by observing that all their sub-components are already + // synonymous. + assert(DataDescriptorsAreWellFormedAndComparable( + context, dd1_prefix, dd2_prefix)); + synonymous_.MakeEquivalent(dd1_prefix, dd2_prefix); + // As we have added a new synonym fact, we might benefit from doing + // another pass over the equivalence relation. + closure_computation_required = true; + // Now that we know this pair of data descriptors are synonymous, + // there is no point recording how close they are to being + // synonymous. + candidate_composite_synonyms.erase(candidate_composite_synonym); + } + } + } + } + } +} + +bool FactManager::DataSynonymFacts::DataDescriptorsAreWellFormedAndComparable( + opt::IRContext* context, const protobufs::DataDescriptor& dd1, + const protobufs::DataDescriptor& dd2) const { + auto end_type_1 = fuzzerutil::WalkCompositeTypeIndices( + context, context->get_def_use_mgr()->GetDef(dd1.object())->type_id(), + dd1.index()); + auto end_type_2 = fuzzerutil::WalkCompositeTypeIndices( + context, context->get_def_use_mgr()->GetDef(dd2.object())->type_id(), + dd2.index()); + return end_type_1 && end_type_1 == end_type_2; +} + +std::vector +FactManager::DataSynonymFacts::GetSynonymsForDataDescriptor( + const protobufs::DataDescriptor& data_descriptor, + opt::IRContext* context) const { + ComputeClosureOfFacts(context); + if (synonymous_.Exists(data_descriptor)) { + return synonymous_.GetEquivalenceClass(data_descriptor); + } + return std::vector(); +} + +std::vector +FactManager::DataSynonymFacts ::GetIdsForWhichSynonymsAreKnown( + opt::IRContext* context) const { + ComputeClosureOfFacts(context); + std::vector result; + for (auto& data_descriptor : synonymous_.GetAllKnownValues()) { + if (data_descriptor->index().empty()) { + result.push_back(data_descriptor->object()); + } + } + return result; +} + +bool FactManager::DataSynonymFacts::IsSynonymous( + const protobufs::DataDescriptor& data_descriptor1, + const protobufs::DataDescriptor& data_descriptor2, + opt::IRContext* context) const { + const_cast(this)->ComputeClosureOfFacts( + context); + return synonymous_.Exists(data_descriptor1) && + synonymous_.Exists(data_descriptor2) && + synonymous_.IsEquivalent(data_descriptor1, data_descriptor2); +} + +// End of data synonym facts +//============================== + +//============================== +// Dead block facts + +// The purpose of this class is to group the fields and data used to represent +// facts about data blocks. +class FactManager::DeadBlockFacts { + public: + // See method in FactManager which delegates to this method. + void AddFact(const protobufs::FactBlockIsDead& fact); + + // See method in FactManager which delegates to this method. + bool BlockIsDead(uint32_t block_id) const; + + private: + std::set dead_block_ids_; +}; + +void FactManager::DeadBlockFacts::AddFact( + const protobufs::FactBlockIsDead& fact) { + dead_block_ids_.insert(fact.block_id()); +} + +bool FactManager::DeadBlockFacts::BlockIsDead(uint32_t block_id) const { + return dead_block_ids_.count(block_id) != 0; +} + +// End of dead block facts +//============================== + +//============================== +// Livesafe function facts + +// The purpose of this class is to group the fields and data used to represent +// facts about livesafe functions. +class FactManager::LivesafeFunctionFacts { + public: + // See method in FactManager which delegates to this method. + void AddFact(const protobufs::FactFunctionIsLivesafe& fact); + + // See method in FactManager which delegates to this method. + bool FunctionIsLivesafe(uint32_t function_id) const; + + private: + std::set livesafe_function_ids_; +}; + +void FactManager::LivesafeFunctionFacts::AddFact( + const protobufs::FactFunctionIsLivesafe& fact) { + livesafe_function_ids_.insert(fact.function_id()); +} + +bool FactManager::LivesafeFunctionFacts::FunctionIsLivesafe( + uint32_t function_id) const { + return livesafe_function_ids_.count(function_id) != 0; +} + +// End of livesafe function facts +//============================== + +//============================== +// Arbitrarily-valued variable facts + +// The purpose of this class is to group the fields and data used to represent +// facts about livesafe functions. +class FactManager::ArbitrarilyValuedVaribleFacts { + public: + // See method in FactManager which delegates to this method. + void AddFact(const protobufs::FactValueOfVariableIsArbitrary& fact); + + // See method in FactManager which delegates to this method. + bool VariableValueIsArbitrary(uint32_t variable_id) const; + + private: + std::set arbitrary_valued_varible_ids_; +}; + +void FactManager::ArbitrarilyValuedVaribleFacts::AddFact( + const protobufs::FactValueOfVariableIsArbitrary& fact) { + arbitrary_valued_varible_ids_.insert(fact.variable_id()); +} + +bool FactManager::ArbitrarilyValuedVaribleFacts::VariableValueIsArbitrary( + uint32_t variable_id) const { + return arbitrary_valued_varible_ids_.count(variable_id) != 0; +} + +// End of arbitrarily-valued variable facts +//============================== + +FactManager::FactManager() + : uniform_constant_facts_(MakeUnique()), + data_synonym_facts_(MakeUnique()), + dead_block_facts_(MakeUnique()), + livesafe_function_facts_(MakeUnique()), + arbitrarily_valued_variable_facts_( + MakeUnique()) {} + +FactManager::~FactManager() = default; + +void FactManager::AddFacts(const MessageConsumer& message_consumer, + const protobufs::FactSequence& initial_facts, + opt::IRContext* context) { + for (auto& fact : initial_facts.fact()) { + if (!AddFact(fact, context)) { + message_consumer( + SPV_MSG_WARNING, nullptr, {}, + ("Invalid fact " + ToString(fact) + " ignored.").c_str()); + } + } +} + +bool FactManager::AddFact(const fuzz::protobufs::Fact& fact, + opt::IRContext* context) { + switch (fact.fact_case()) { + case protobufs::Fact::kConstantUniformFact: + return uniform_constant_facts_->AddFact(fact.constant_uniform_fact(), + context); + case protobufs::Fact::kDataSynonymFact: + data_synonym_facts_->AddFact(fact.data_synonym_fact(), context); + return true; + case protobufs::Fact::kBlockIsDeadFact: + dead_block_facts_->AddFact(fact.block_is_dead_fact()); + return true; + case protobufs::Fact::kFunctionIsLivesafeFact: + livesafe_function_facts_->AddFact(fact.function_is_livesafe_fact()); + return true; + default: + assert(false && "Unknown fact type."); + return false; + } +} + +void FactManager::AddFactDataSynonym(const protobufs::DataDescriptor& data1, + const protobufs::DataDescriptor& data2, + opt::IRContext* context) { + protobufs::FactDataSynonym fact; + *fact.mutable_data1() = data1; + *fact.mutable_data2() = data2; + data_synonym_facts_->AddFact(fact, context); +} + +std::vector FactManager::GetConstantsAvailableFromUniformsForType( + opt::IRContext* ir_context, uint32_t type_id) const { + return uniform_constant_facts_->GetConstantsAvailableFromUniformsForType( + ir_context, type_id); +} + +const std::vector +FactManager::GetUniformDescriptorsForConstant(opt::IRContext* ir_context, + uint32_t constant_id) const { + return uniform_constant_facts_->GetUniformDescriptorsForConstant(ir_context, + constant_id); +} + +uint32_t FactManager::GetConstantFromUniformDescriptor( + opt::IRContext* context, + const protobufs::UniformBufferElementDescriptor& uniform_descriptor) const { + return uniform_constant_facts_->GetConstantFromUniformDescriptor( + context, uniform_descriptor); +} + +std::vector FactManager::GetTypesForWhichUniformValuesAreKnown() + const { + return uniform_constant_facts_->GetTypesForWhichUniformValuesAreKnown(); +} + +const std::vector>& +FactManager::GetConstantUniformFactsAndTypes() const { + return uniform_constant_facts_->GetConstantUniformFactsAndTypes(); +} + +std::vector FactManager::GetIdsForWhichSynonymsAreKnown( + opt::IRContext* context) const { + return data_synonym_facts_->GetIdsForWhichSynonymsAreKnown(context); +} + +std::vector +FactManager::GetSynonymsForDataDescriptor( + const protobufs::DataDescriptor& data_descriptor, + opt::IRContext* context) const { + return data_synonym_facts_->GetSynonymsForDataDescriptor(data_descriptor, + context); +} + +std::vector FactManager::GetSynonymsForId( + uint32_t id, opt::IRContext* context) const { + return GetSynonymsForDataDescriptor(MakeDataDescriptor(id, {}), context); +} + +bool FactManager::IsSynonymous( + const protobufs::DataDescriptor& data_descriptor1, + const protobufs::DataDescriptor& data_descriptor2, + opt::IRContext* context) const { + return data_synonym_facts_->IsSynonymous(data_descriptor1, data_descriptor2, + context); +} + +bool FactManager::BlockIsDead(uint32_t block_id) const { + return dead_block_facts_->BlockIsDead(block_id); +} + +void FactManager::AddFactBlockIsDead(uint32_t block_id) { + protobufs::FactBlockIsDead fact; + fact.set_block_id(block_id); + dead_block_facts_->AddFact(fact); +} + +bool FactManager::FunctionIsLivesafe(uint32_t function_id) const { + return livesafe_function_facts_->FunctionIsLivesafe(function_id); +} + +void FactManager::AddFactFunctionIsLivesafe(uint32_t function_id) { + protobufs::FactFunctionIsLivesafe fact; + fact.set_function_id(function_id); + livesafe_function_facts_->AddFact(fact); +} + +bool FactManager::VariableValueIsArbitrary(uint32_t variable_id) const { + return arbitrarily_valued_variable_facts_->VariableValueIsArbitrary( + variable_id); +} + +void FactManager::AddFactValueOfVariableIsArbitrary(uint32_t variable_id) { + protobufs::FactValueOfVariableIsArbitrary fact; + fact.set_variable_id(variable_id); + arbitrarily_valued_variable_facts_->AddFact(fact); +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/fact_manager.h b/third_party/spirv-tools/source/fuzz/fact_manager.h new file mode 100644 index 0000000000..117ed1c617 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/fact_manager.h @@ -0,0 +1,203 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_FACT_MANAGER_H_ +#define SOURCE_FUZZ_FACT_MANAGER_H_ + +#include +#include +#include +#include + +#include "source/fuzz/data_descriptor.h" +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "source/opt/constants.h" + +namespace spvtools { +namespace fuzz { + +// Keeps track of facts about the module being transformed on which the fuzzing +// process can depend. Some initial facts can be provided, for example about +// guarantees on the values of inputs to SPIR-V entry points. Transformations +// may then rely on these facts, can add further facts that they establish. +// Facts are intended to be simple properties that either cannot be deduced from +// the module (such as properties that are guaranteed to hold for entry point +// inputs), or that are established by transformations, likely to be useful for +// future transformations, and not completely trivial to deduce straight from +// the module. +class FactManager { + public: + FactManager(); + + ~FactManager(); + + // Adds all the facts from |facts|, checking them for validity with respect to + // |context|. Warnings about invalid facts are communicated via + // |message_consumer|; such facts are otherwise ignored. + void AddFacts(const MessageConsumer& message_consumer, + const protobufs::FactSequence& facts, opt::IRContext* context); + + // Checks the fact for validity with respect to |context|. Returns false, + // with no side effects, if the fact is invalid. Otherwise adds |fact| to the + // fact manager. + bool AddFact(const protobufs::Fact& fact, opt::IRContext* context); + + // Record the fact that |data1| and |data2| are synonymous. + void AddFactDataSynonym(const protobufs::DataDescriptor& data1, + const protobufs::DataDescriptor& data2, + opt::IRContext* context); + + // Records the fact that |block_id| is dead. + void AddFactBlockIsDead(uint32_t block_id); + + // Records the fact that |function_id| is livesafe. + void AddFactFunctionIsLivesafe(uint32_t function_id); + + // Records the fact that |variable_id| has an arbitrary value and can thus be + // stored to without affecting the module's behaviour. + void AddFactValueOfVariableIsArbitrary(uint32_t variable_id); + + // The fact manager is responsible for managing a few distinct categories of + // facts. In principle there could be different fact managers for each kind + // of fact, but in practice providing one 'go to' place for facts is + // convenient. To keep some separation, the public methods of the fact + // manager should be grouped according to the kind of fact to which they + // relate. + + //============================== + // Querying facts about uniform constants + + // Provides the distinct type ids for which at least one "constant == + // uniform element" fact is known. + std::vector GetTypesForWhichUniformValuesAreKnown() const; + + // Provides distinct constant ids with type |type_id| for which at least one + // "constant == uniform element" fact is known. If multiple identically- + // valued constants are relevant, only one will appear in the sequence. + std::vector GetConstantsAvailableFromUniformsForType( + opt::IRContext* ir_context, uint32_t type_id) const; + + // Provides details of all uniform elements that are known to be equal to the + // constant associated with |constant_id| in |ir_context|. + const std::vector + GetUniformDescriptorsForConstant(opt::IRContext* ir_context, + uint32_t constant_id) const; + + // Returns the id of a constant whose value is known to match that of + // |uniform_descriptor|, and whose type matches the type of the uniform + // element. If multiple such constant is exist, the one that is returned + // is arbitrary. Returns 0 if no such constant id exists. + uint32_t GetConstantFromUniformDescriptor( + opt::IRContext* context, + const protobufs::UniformBufferElementDescriptor& uniform_descriptor) + const; + + // Returns all "constant == uniform element" facts known to the fact + // manager, pairing each fact with id of the type that is associated with + // both the constant and the uniform element. + const std::vector>& + GetConstantUniformFactsAndTypes() const; + + // End of uniform constant facts + //============================== + + //============================== + // Querying facts about id synonyms + + // Returns every id for which a fact of the form "this id is synonymous with + // this piece of data" is known. + std::vector GetIdsForWhichSynonymsAreKnown( + opt::IRContext* context) const; + + // Returns the equivalence class of all known synonyms of |id|, or an empty + // set if no synonyms are known. + std::vector GetSynonymsForId( + uint32_t id, opt::IRContext* context) const; + + // Returns the equivalence class of all known synonyms of |data_descriptor|, + // or empty if no synonyms are known. + std::vector GetSynonymsForDataDescriptor( + const protobufs::DataDescriptor& data_descriptor, + opt::IRContext* context) const; + + // Returns true if and ony if |data_descriptor1| and |data_descriptor2| are + // known to be synonymous. + bool IsSynonymous(const protobufs::DataDescriptor& data_descriptor1, + const protobufs::DataDescriptor& data_descriptor2, + opt::IRContext* context) const; + + // End of id synonym facts + //============================== + + //============================== + // Querying facts about dead blocks + + // Returns true if and ony if |block_id| is the id of a block known to be + // dynamically unreachable. + bool BlockIsDead(uint32_t block_id) const; + + // End of dead block facts + //============================== + + //============================== + // Querying facts about livesafe function + + // Returns true if and ony if |function_id| is the id of a function known + // to be livesafe. + bool FunctionIsLivesafe(uint32_t function_id) const; + + // End of dead livesafe function facts + //============================== + + //============================== + // Querying facts about arbitrarily-valued variables + + // Returns true if and ony if |variable_id| is arbitrarily-valued. + bool VariableValueIsArbitrary(uint32_t variable_id) const; + + // End of arbitrarily-valued variable facts + //============================== + + private: + // For each distinct kind of fact to be managed, we use a separate opaque + // class type. + + class ConstantUniformFacts; // Opaque class for management of + // constant uniform facts. + std::unique_ptr + uniform_constant_facts_; // Unique pointer to internal data. + + class DataSynonymFacts; // Opaque class for management of data synonym facts. + std::unique_ptr + data_synonym_facts_; // Unique pointer to internal data. + + class DeadBlockFacts; // Opaque class for management of dead block facts. + std::unique_ptr + dead_block_facts_; // Unique pointer to internal data. + + class LivesafeFunctionFacts; // Opaque class for management of livesafe + // function facts. + std::unique_ptr + livesafe_function_facts_; // Unique pointer to internal data. + + class ArbitrarilyValuedVaribleFacts; // Opaque class for management of + // facts about variables whose values should be expected to be arbitrary. + std::unique_ptr + arbitrarily_valued_variable_facts_; // Unique pointer to internal data. +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_FACT_MANAGER_H_ diff --git a/third_party/spirv-tools/source/fuzz/force_render_red.cpp b/third_party/spirv-tools/source/fuzz/force_render_red.cpp new file mode 100644 index 0000000000..46e23e80e6 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/force_render_red.cpp @@ -0,0 +1,370 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/force_render_red.h" + +#include "source/fuzz/fact_manager.h" +#include "source/fuzz/instruction_descriptor.h" +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "source/fuzz/transformation_replace_constant_with_uniform.h" +#include "source/fuzz/uniform_buffer_element_descriptor.h" +#include "source/opt/build_module.h" +#include "source/opt/ir_context.h" +#include "source/opt/types.h" +#include "source/util/make_unique.h" +#include "tools/util/cli_consumer.h" + +#include +#include + +namespace spvtools { +namespace fuzz { + +namespace { + +// Helper method to find the fragment shader entry point, complaining if there +// is no shader or if there is no fragment entry point. +opt::Function* FindFragmentShaderEntryPoint(opt::IRContext* ir_context, + MessageConsumer message_consumer) { + // Check that this is a fragment shader + bool found_capability_shader = false; + for (auto& capability : ir_context->capabilities()) { + assert(capability.opcode() == SpvOpCapability); + if (capability.GetSingleWordInOperand(0) == SpvCapabilityShader) { + found_capability_shader = true; + break; + } + } + if (!found_capability_shader) { + message_consumer( + SPV_MSG_ERROR, nullptr, {}, + "Forcing of red rendering requires the Shader capability."); + return nullptr; + } + + opt::Instruction* fragment_entry_point = nullptr; + for (auto& entry_point : ir_context->module()->entry_points()) { + if (entry_point.GetSingleWordInOperand(0) == SpvExecutionModelFragment) { + fragment_entry_point = &entry_point; + break; + } + } + if (fragment_entry_point == nullptr) { + message_consumer(SPV_MSG_ERROR, nullptr, {}, + "Forcing of red rendering requires an entry point with " + "the Fragment execution model."); + return nullptr; + } + + for (auto& function : *ir_context->module()) { + if (function.result_id() == + fragment_entry_point->GetSingleWordInOperand(1)) { + return &function; + } + } + assert( + false && + "A valid module must have a function associate with each entry point."); + return nullptr; +} + +// Helper method to check that there is a single vec4 output variable and get a +// pointer to it. +opt::Instruction* FindVec4OutputVariable(opt::IRContext* ir_context, + MessageConsumer message_consumer) { + opt::Instruction* output_variable = nullptr; + for (auto& inst : ir_context->types_values()) { + if (inst.opcode() == SpvOpVariable && + inst.GetSingleWordInOperand(0) == SpvStorageClassOutput) { + if (output_variable != nullptr) { + message_consumer(SPV_MSG_ERROR, nullptr, {}, + "Only one output variable can be handled at present; " + "found multiple."); + return nullptr; + } + output_variable = &inst; + // Do not break, as we want to check for multiple output variables. + } + } + if (output_variable == nullptr) { + message_consumer(SPV_MSG_ERROR, nullptr, {}, + "No output variable to which to write red was found."); + return nullptr; + } + + auto output_variable_base_type = ir_context->get_type_mgr() + ->GetType(output_variable->type_id()) + ->AsPointer() + ->pointee_type() + ->AsVector(); + if (!output_variable_base_type || + output_variable_base_type->element_count() != 4 || + !output_variable_base_type->element_type()->AsFloat()) { + message_consumer(SPV_MSG_ERROR, nullptr, {}, + "The output variable must have type vec4."); + return nullptr; + } + + return output_variable; +} + +// Helper to get the ids of float constants 0.0 and 1.0, creating them if +// necessary. +std::pair FindOrCreateFloatZeroAndOne( + opt::IRContext* ir_context, opt::analysis::Float* float_type) { + float one = 1.0; + uint32_t one_as_uint; + memcpy(&one_as_uint, &one, sizeof(float)); + std::vector zero_bytes = {0}; + std::vector one_bytes = {one_as_uint}; + auto constant_zero = ir_context->get_constant_mgr()->RegisterConstant( + MakeUnique(float_type, zero_bytes)); + auto constant_one = ir_context->get_constant_mgr()->RegisterConstant( + MakeUnique(float_type, one_bytes)); + auto constant_zero_id = ir_context->get_constant_mgr() + ->GetDefiningInstruction(constant_zero) + ->result_id(); + auto constant_one_id = ir_context->get_constant_mgr() + ->GetDefiningInstruction(constant_one) + ->result_id(); + return std::pair(constant_zero_id, constant_one_id); +} + +std::unique_ptr +MakeConstantUniformReplacement(opt::IRContext* ir_context, + const FactManager& fact_manager, + uint32_t constant_id, + uint32_t greater_than_instruction, + uint32_t in_operand_index) { + return MakeUnique( + MakeIdUseDescriptor(constant_id, + MakeInstructionDescriptor(greater_than_instruction, + SpvOpFOrdGreaterThan, 0), + in_operand_index), + fact_manager.GetUniformDescriptorsForConstant(ir_context, constant_id)[0], + ir_context->TakeNextId(), ir_context->TakeNextId()); +} + +} // namespace + +bool ForceRenderRed( + const spv_target_env& target_env, const std::vector& binary_in, + const spvtools::fuzz::protobufs::FactSequence& initial_facts, + std::vector* binary_out) { + auto message_consumer = spvtools::utils::CLIMessageConsumer; + spvtools::SpirvTools tools(target_env); + if (!tools.IsValid()) { + message_consumer(SPV_MSG_ERROR, nullptr, {}, + "Failed to create SPIRV-Tools interface; stopping."); + return false; + } + + // Initial binary should be valid. + if (!tools.Validate(&binary_in[0], binary_in.size())) { + message_consumer(SPV_MSG_ERROR, nullptr, {}, + "Initial binary is invalid; stopping."); + return false; + } + + // Build the module from the input binary. + std::unique_ptr ir_context = BuildModule( + target_env, message_consumer, binary_in.data(), binary_in.size()); + assert(ir_context); + + // Set up a fact manager with any given initial facts. + FactManager fact_manager; + for (auto& fact : initial_facts.fact()) { + fact_manager.AddFact(fact, ir_context.get()); + } + + auto entry_point_function = + FindFragmentShaderEntryPoint(ir_context.get(), message_consumer); + auto output_variable = + FindVec4OutputVariable(ir_context.get(), message_consumer); + if (entry_point_function == nullptr || output_variable == nullptr) { + return false; + } + + opt::analysis::Float temp_float_type(32); + opt::analysis::Float* float_type = ir_context->get_type_mgr() + ->GetRegisteredType(&temp_float_type) + ->AsFloat(); + std::pair zero_one_float_ids = + FindOrCreateFloatZeroAndOne(ir_context.get(), float_type); + + // Make the new exit block + auto new_exit_block_id = ir_context->TakeNextId(); + { + auto label = MakeUnique(ir_context.get(), SpvOpLabel, 0, + new_exit_block_id, + opt::Instruction::OperandList()); + auto new_exit_block = MakeUnique(std::move(label)); + new_exit_block->AddInstruction(MakeUnique( + ir_context.get(), SpvOpReturn, 0, 0, opt::Instruction::OperandList())); + entry_point_function->AddBasicBlock(std::move(new_exit_block)); + } + + // Make the new entry block + { + auto label = MakeUnique(ir_context.get(), SpvOpLabel, 0, + ir_context->TakeNextId(), + opt::Instruction::OperandList()); + auto new_entry_block = MakeUnique(std::move(label)); + + // Make an instruction to construct vec4(1.0, 0.0, 0.0, 1.0), representing + // the colour red. + opt::Operand zero_float = {SPV_OPERAND_TYPE_ID, {zero_one_float_ids.first}}; + opt::Operand one_float = {SPV_OPERAND_TYPE_ID, {zero_one_float_ids.second}}; + opt::Instruction::OperandList op_composite_construct_operands = { + one_float, zero_float, zero_float, one_float}; + auto temp_vec4 = opt::analysis::Vector(float_type, 4); + auto vec4_id = ir_context->get_type_mgr()->GetId(&temp_vec4); + auto red = MakeUnique( + ir_context.get(), SpvOpCompositeConstruct, vec4_id, + ir_context->TakeNextId(), op_composite_construct_operands); + auto red_id = red->result_id(); + new_entry_block->AddInstruction(std::move(red)); + + // Make an instruction to store red into the output color. + opt::Operand variable_to_store_into = {SPV_OPERAND_TYPE_ID, + {output_variable->result_id()}}; + opt::Operand value_to_be_stored = {SPV_OPERAND_TYPE_ID, {red_id}}; + opt::Instruction::OperandList op_store_operands = {variable_to_store_into, + value_to_be_stored}; + new_entry_block->AddInstruction(MakeUnique( + ir_context.get(), SpvOpStore, 0, 0, op_store_operands)); + + // We are going to attempt to construct 'false' as an expression of the form + // 'literal1 > literal2'. If we succeed, we will later replace each literal + // with a uniform of the same value - we can only do that replacement once + // we have added the entry block to the module. + std::unique_ptr + first_greater_then_operand_replacement = nullptr; + std::unique_ptr + second_greater_then_operand_replacement = nullptr; + uint32_t id_guaranteed_to_be_false = 0; + + opt::analysis::Bool temp_bool_type; + opt::analysis::Bool* registered_bool_type = + ir_context->get_type_mgr() + ->GetRegisteredType(&temp_bool_type) + ->AsBool(); + + auto float_type_id = ir_context->get_type_mgr()->GetId(float_type); + auto types_for_which_uniforms_are_known = + fact_manager.GetTypesForWhichUniformValuesAreKnown(); + + // Check whether we have any float uniforms. + if (std::find(types_for_which_uniforms_are_known.begin(), + types_for_which_uniforms_are_known.end(), + float_type_id) != types_for_which_uniforms_are_known.end()) { + // We have at least one float uniform; let's see whether we have at least + // two. + auto available_constants = + fact_manager.GetConstantsAvailableFromUniformsForType( + ir_context.get(), float_type_id); + if (available_constants.size() > 1) { + // Grab the float constants associated with the first two known float + // uniforms. + auto first_constant = + ir_context->get_constant_mgr() + ->GetConstantFromInst(ir_context->get_def_use_mgr()->GetDef( + available_constants[0])) + ->AsFloatConstant(); + auto second_constant = + ir_context->get_constant_mgr() + ->GetConstantFromInst(ir_context->get_def_use_mgr()->GetDef( + available_constants[1])) + ->AsFloatConstant(); + + // Now work out which of the two constants is larger than the other. + uint32_t larger_constant_index = 0; + uint32_t smaller_constant_index = 0; + if (first_constant->GetFloat() > second_constant->GetFloat()) { + larger_constant_index = 0; + smaller_constant_index = 1; + } else if (first_constant->GetFloat() < second_constant->GetFloat()) { + larger_constant_index = 1; + smaller_constant_index = 0; + } + + // Only proceed with these constants if they have turned out to be + // distinct. + if (larger_constant_index != smaller_constant_index) { + // We are in a position to create 'false' as 'literal1 > literal2', so + // reserve an id for this computation; this id will end up being + // guaranteed to be 'false'. + id_guaranteed_to_be_false = ir_context->TakeNextId(); + + auto smaller_constant = available_constants[smaller_constant_index]; + auto larger_constant = available_constants[larger_constant_index]; + + opt::Instruction::OperandList greater_than_operands = { + {SPV_OPERAND_TYPE_ID, {smaller_constant}}, + {SPV_OPERAND_TYPE_ID, {larger_constant}}}; + new_entry_block->AddInstruction(MakeUnique( + ir_context.get(), SpvOpFOrdGreaterThan, + ir_context->get_type_mgr()->GetId(registered_bool_type), + id_guaranteed_to_be_false, greater_than_operands)); + + first_greater_then_operand_replacement = + MakeConstantUniformReplacement(ir_context.get(), fact_manager, + smaller_constant, + id_guaranteed_to_be_false, 0); + second_greater_then_operand_replacement = + MakeConstantUniformReplacement(ir_context.get(), fact_manager, + larger_constant, + id_guaranteed_to_be_false, 1); + } + } + } + + if (id_guaranteed_to_be_false == 0) { + auto constant_false = ir_context->get_constant_mgr()->RegisterConstant( + MakeUnique(registered_bool_type, false)); + id_guaranteed_to_be_false = ir_context->get_constant_mgr() + ->GetDefiningInstruction(constant_false) + ->result_id(); + } + + opt::Operand false_condition = {SPV_OPERAND_TYPE_ID, + {id_guaranteed_to_be_false}}; + opt::Operand then_block = {SPV_OPERAND_TYPE_ID, + {entry_point_function->entry()->id()}}; + opt::Operand else_block = {SPV_OPERAND_TYPE_ID, {new_exit_block_id}}; + opt::Instruction::OperandList op_branch_conditional_operands = { + false_condition, then_block, else_block}; + new_entry_block->AddInstruction( + MakeUnique(ir_context.get(), SpvOpBranchConditional, + 0, 0, op_branch_conditional_operands)); + + entry_point_function->InsertBasicBlockBefore( + std::move(new_entry_block), entry_point_function->entry().get()); + + for (auto& replacement : {first_greater_then_operand_replacement.get(), + second_greater_then_operand_replacement.get()}) { + if (replacement) { + assert(replacement->IsApplicable(ir_context.get(), fact_manager)); + replacement->Apply(ir_context.get(), &fact_manager); + } + } + } + + // Write out the module as a binary. + ir_context->module()->ToBinary(binary_out, false); + return true; +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/force_render_red.h b/third_party/spirv-tools/source/fuzz/force_render_red.h new file mode 100644 index 0000000000..2484d27883 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/force_render_red.h @@ -0,0 +1,48 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FORCE_RENDER_RED_H_ +#define SOURCE_FORCE_RENDER_RED_H_ + +#include + +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "spirv-tools/libspirv.hpp" + +namespace spvtools { +namespace fuzz { + +// Requires |binary_in| to be a valid SPIR-V module with Shader capability, +// containing an entry point with the Fragment execution model, and a single +// output variable of type vec4. +// +// Turns the body of this entry point into effectively: +// +// output_variable = vec4(1.0, 0.0, 0.0, 1.0); +// if (false) { +// original_body +// } +// +// If suitable facts about values of uniforms are available, the 'false' will +// instead become: 'u > v', where 'u' and 'v' are pieces of uniform data for +// which it is known that 'u < v' holds. +bool ForceRenderRed( + const spv_target_env& target_env, const std::vector& binary_in, + const spvtools::fuzz::protobufs::FactSequence& initial_facts, + std::vector* binary_out); + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FORCE_RENDER_RED_H_ diff --git a/third_party/spirv-tools/source/fuzz/fuzzer.cpp b/third_party/spirv-tools/source/fuzz/fuzzer.cpp new file mode 100644 index 0000000000..27b697c947 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/fuzzer.cpp @@ -0,0 +1,268 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/fuzzer.h" + +#include +#include +#include + +#include "fuzzer_pass_adjust_memory_operands_masks.h" +#include "source/fuzz/fact_manager.h" +#include "source/fuzz/fuzzer_context.h" +#include "source/fuzz/fuzzer_pass_add_composite_types.h" +#include "source/fuzz/fuzzer_pass_add_dead_blocks.h" +#include "source/fuzz/fuzzer_pass_add_dead_breaks.h" +#include "source/fuzz/fuzzer_pass_add_dead_continues.h" +#include "source/fuzz/fuzzer_pass_add_no_contraction_decorations.h" +#include "source/fuzz/fuzzer_pass_add_useful_constructs.h" +#include "source/fuzz/fuzzer_pass_adjust_function_controls.h" +#include "source/fuzz/fuzzer_pass_adjust_loop_controls.h" +#include "source/fuzz/fuzzer_pass_adjust_selection_controls.h" +#include "source/fuzz/fuzzer_pass_apply_id_synonyms.h" +#include "source/fuzz/fuzzer_pass_construct_composites.h" +#include "source/fuzz/fuzzer_pass_copy_objects.h" +#include "source/fuzz/fuzzer_pass_donate_modules.h" +#include "source/fuzz/fuzzer_pass_merge_blocks.h" +#include "source/fuzz/fuzzer_pass_obfuscate_constants.h" +#include "source/fuzz/fuzzer_pass_outline_functions.h" +#include "source/fuzz/fuzzer_pass_permute_blocks.h" +#include "source/fuzz/fuzzer_pass_split_blocks.h" +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "source/fuzz/pseudo_random_generator.h" +#include "source/opt/build_module.h" +#include "source/spirv_fuzzer_options.h" +#include "source/util/make_unique.h" + +namespace spvtools { +namespace fuzz { + +namespace { +const uint32_t kIdBoundGap = 100; + +const uint32_t kTransformationLimit = 500; + +const uint32_t kChanceOfApplyingAnotherPass = 85; + +// A convenience method to add a fuzzer pass to |passes| with probability 0.5. +// All fuzzer passes take |ir_context|, |fact_manager|, |fuzzer_context| and +// |transformation_sequence_out| as parameters. Extra arguments can be provided +// via |extra_args|. +template +void MaybeAddPass( + std::vector>* passes, + opt::IRContext* ir_context, FactManager* fact_manager, + FuzzerContext* fuzzer_context, + protobufs::TransformationSequence* transformation_sequence_out, + Args&&... extra_args) { + if (fuzzer_context->ChooseEven()) { + passes->push_back(MakeUnique(ir_context, fact_manager, fuzzer_context, + transformation_sequence_out, + std::forward(extra_args)...)); + } +} + +} // namespace + +struct Fuzzer::Impl { + explicit Impl(spv_target_env env, uint32_t random_seed, + bool validate_after_each_pass) + : target_env(env), + seed(random_seed), + validate_after_each_fuzzer_pass(validate_after_each_pass) {} + + bool ApplyPassAndCheckValidity(FuzzerPass* pass, + const opt::IRContext& ir_context, + const spvtools::SpirvTools& tools) const; + + const spv_target_env target_env; // Target environment. + const uint32_t seed; // Seed for random number generator. + bool validate_after_each_fuzzer_pass; // Determines whether the validator + // should be invoked after every fuzzer pass. + MessageConsumer consumer; // Message consumer. +}; + +Fuzzer::Fuzzer(spv_target_env env, uint32_t seed, + bool validate_after_each_fuzzer_pass) + : impl_(MakeUnique(env, seed, validate_after_each_fuzzer_pass)) {} + +Fuzzer::~Fuzzer() = default; + +void Fuzzer::SetMessageConsumer(MessageConsumer c) { + impl_->consumer = std::move(c); +} + +bool Fuzzer::Impl::ApplyPassAndCheckValidity( + FuzzerPass* pass, const opt::IRContext& ir_context, + const spvtools::SpirvTools& tools) const { + pass->Apply(); + if (validate_after_each_fuzzer_pass) { + std::vector binary_to_validate; + ir_context.module()->ToBinary(&binary_to_validate, false); + if (!tools.Validate(&binary_to_validate[0], binary_to_validate.size())) { + consumer(SPV_MSG_INFO, nullptr, {}, + "Binary became invalid during fuzzing (set a breakpoint to " + "inspect); stopping."); + return false; + } + } + return true; +} + +Fuzzer::FuzzerResultStatus Fuzzer::Run( + const std::vector& binary_in, + const protobufs::FactSequence& initial_facts, + const std::vector& donor_suppliers, + std::vector* binary_out, + protobufs::TransformationSequence* transformation_sequence_out) const { + // Check compatibility between the library version being linked with and the + // header files being used. + GOOGLE_PROTOBUF_VERIFY_VERSION; + + spvtools::SpirvTools tools(impl_->target_env); + tools.SetMessageConsumer(impl_->consumer); + if (!tools.IsValid()) { + impl_->consumer(SPV_MSG_ERROR, nullptr, {}, + "Failed to create SPIRV-Tools interface; stopping."); + return Fuzzer::FuzzerResultStatus::kFailedToCreateSpirvToolsInterface; + } + + // Initial binary should be valid. + if (!tools.Validate(&binary_in[0], binary_in.size())) { + impl_->consumer(SPV_MSG_ERROR, nullptr, {}, + "Initial binary is invalid; stopping."); + return Fuzzer::FuzzerResultStatus::kInitialBinaryInvalid; + } + + // Build the module from the input binary. + std::unique_ptr ir_context = BuildModule( + impl_->target_env, impl_->consumer, binary_in.data(), binary_in.size()); + assert(ir_context); + + // Make a PRNG from the seed passed to the fuzzer on creation. + PseudoRandomGenerator random_generator(impl_->seed); + + // The fuzzer will introduce new ids into the module. The module's id bound + // gives the smallest id that can be used for this purpose. We add an offset + // to this so that there is a sizeable gap between the ids used in the + // original module and the ids used for fuzzing, as a readability aid. + // + // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/2541) consider the + // case where the maximum id bound is reached. + auto minimum_fresh_id = ir_context->module()->id_bound() + kIdBoundGap; + FuzzerContext fuzzer_context(&random_generator, minimum_fresh_id); + + FactManager fact_manager; + fact_manager.AddFacts(impl_->consumer, initial_facts, ir_context.get()); + + // Add some essential ingredients to the module if they are not already + // present, such as boolean constants. + FuzzerPassAddUsefulConstructs add_useful_constructs( + ir_context.get(), &fact_manager, &fuzzer_context, + transformation_sequence_out); + if (!impl_->ApplyPassAndCheckValidity(&add_useful_constructs, *ir_context, + tools)) { + return Fuzzer::FuzzerResultStatus::kFuzzerPassLedToInvalidModule; + } + + // Apply some semantics-preserving passes. + std::vector> passes; + while (passes.empty()) { + MaybeAddPass(&passes, ir_context.get(), + &fact_manager, &fuzzer_context, + transformation_sequence_out); + MaybeAddPass(&passes, ir_context.get(), + &fact_manager, &fuzzer_context, + transformation_sequence_out); + MaybeAddPass(&passes, ir_context.get(), + &fact_manager, &fuzzer_context, + transformation_sequence_out); + MaybeAddPass(&passes, ir_context.get(), + &fact_manager, &fuzzer_context, + transformation_sequence_out); + MaybeAddPass(&passes, ir_context.get(), + &fact_manager, &fuzzer_context, + transformation_sequence_out); + MaybeAddPass(&passes, ir_context.get(), + &fact_manager, &fuzzer_context, + transformation_sequence_out); + MaybeAddPass(&passes, ir_context.get(), + &fact_manager, &fuzzer_context, + transformation_sequence_out); + MaybeAddPass( + &passes, ir_context.get(), &fact_manager, &fuzzer_context, + transformation_sequence_out, donor_suppliers); + MaybeAddPass(&passes, ir_context.get(), + &fact_manager, &fuzzer_context, + transformation_sequence_out); + MaybeAddPass(&passes, ir_context.get(), + &fact_manager, &fuzzer_context, + transformation_sequence_out); + MaybeAddPass(&passes, ir_context.get(), + &fact_manager, &fuzzer_context, + transformation_sequence_out); + MaybeAddPass(&passes, ir_context.get(), + &fact_manager, &fuzzer_context, + transformation_sequence_out); + MaybeAddPass(&passes, ir_context.get(), + &fact_manager, &fuzzer_context, + transformation_sequence_out); + } + + bool is_first = true; + while (static_cast( + transformation_sequence_out->transformation_size()) < + kTransformationLimit && + (is_first || + fuzzer_context.ChoosePercentage(kChanceOfApplyingAnotherPass))) { + is_first = false; + if (!impl_->ApplyPassAndCheckValidity( + passes[fuzzer_context.RandomIndex(passes)].get(), *ir_context, + tools)) { + return Fuzzer::FuzzerResultStatus::kFuzzerPassLedToInvalidModule; + } + } + + // Now apply some passes that it does not make sense to apply repeatedly, + // as they do not unlock other passes. + std::vector> final_passes; + MaybeAddPass( + &final_passes, ir_context.get(), &fact_manager, &fuzzer_context, + transformation_sequence_out); + MaybeAddPass(&final_passes, ir_context.get(), + &fact_manager, &fuzzer_context, + transformation_sequence_out); + MaybeAddPass( + &final_passes, ir_context.get(), &fact_manager, &fuzzer_context, + transformation_sequence_out); + MaybeAddPass( + &final_passes, ir_context.get(), &fact_manager, &fuzzer_context, + transformation_sequence_out); + MaybeAddPass( + &final_passes, ir_context.get(), &fact_manager, &fuzzer_context, + transformation_sequence_out); + for (auto& pass : final_passes) { + if (!impl_->ApplyPassAndCheckValidity(pass.get(), *ir_context, tools)) { + return Fuzzer::FuzzerResultStatus::kFuzzerPassLedToInvalidModule; + } + } + + // Encode the module as a binary. + ir_context->module()->ToBinary(binary_out, false); + + return Fuzzer::FuzzerResultStatus::kComplete; +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/fuzzer.h b/third_party/spirv-tools/source/fuzz/fuzzer.h new file mode 100644 index 0000000000..3ac73a1a6f --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/fuzzer.h @@ -0,0 +1,80 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_FUZZER_H_ +#define SOURCE_FUZZ_FUZZER_H_ + +#include +#include + +#include "source/fuzz/fuzzer_util.h" +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "spirv-tools/libspirv.hpp" + +namespace spvtools { +namespace fuzz { + +// Transforms a SPIR-V module into a semantically equivalent SPIR-V module by +// running a number of randomized fuzzer passes. +class Fuzzer { + public: + // Possible statuses that can result from running the fuzzer. + enum class FuzzerResultStatus { + kComplete, + kFailedToCreateSpirvToolsInterface, + kFuzzerPassLedToInvalidModule, + kInitialBinaryInvalid, + }; + + // Constructs a fuzzer from the given target environment |env|. |seed| is a + // seed for pseudo-random number generation. + // |validate_after_each_fuzzer_pass| controls whether the validator will be + // invoked after every fuzzer pass is applied. + explicit Fuzzer(spv_target_env env, uint32_t seed, + bool validate_after_each_fuzzer_pass); + + // Disables copy/move constructor/assignment operations. + Fuzzer(const Fuzzer&) = delete; + Fuzzer(Fuzzer&&) = delete; + Fuzzer& operator=(const Fuzzer&) = delete; + Fuzzer& operator=(Fuzzer&&) = delete; + + ~Fuzzer(); + + // Sets the message consumer to the given |consumer|. The |consumer| will be + // invoked once for each message communicated from the library. + void SetMessageConsumer(MessageConsumer consumer); + + // Transforms |binary_in| to |binary_out| by running a number of randomized + // fuzzer passes. Initial facts about the input binary and the context in + // which it will execute are provided via |initial_facts|. A source of donor + // modules to be used by transformations is provided via |donor_suppliers|. + // The transformation sequence that was applied is returned via + // |transformation_sequence_out|. + FuzzerResultStatus Run( + const std::vector& binary_in, + const protobufs::FactSequence& initial_facts, + const std::vector& donor_suppliers, + std::vector* binary_out, + protobufs::TransformationSequence* transformation_sequence_out) const; + + private: + struct Impl; // Opaque struct for holding internal data. + std::unique_ptr impl_; // Unique pointer to internal data. +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_FUZZER_H_ diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_context.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_context.cpp new file mode 100644 index 0000000000..916803a7bb --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/fuzzer_context.cpp @@ -0,0 +1,149 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/fuzzer_context.h" + +#include + +namespace spvtools { +namespace fuzz { + +namespace { +// Default pairs of probabilities for applying various +// transformations. All values are percentages. Keep them in alphabetical order. + +const std::pair kChanceOfAddingAnotherStructField = {20, + 90}; +const std::pair kChanceOfAddingArrayOrStructType = {20, 90}; +const std::pair kChanceOfAddingDeadBlock = {20, 90}; +const std::pair kChanceOfAddingDeadBreak = {5, 80}; +const std::pair kChanceOfAddingDeadContinue = {5, 80}; +const std::pair kChanceOfAddingMatrixType = {20, 70}; +const std::pair kChanceOfAddingNoContractionDecoration = { + 5, 70}; +const std::pair kChanceOfAddingVectorType = {20, 70}; +const std::pair kChanceOfAdjustingFunctionControl = {20, + 70}; +const std::pair kChanceOfAdjustingLoopControl = {20, 90}; +const std::pair kChanceOfAdjustingMemoryOperandsMask = {20, + 90}; +const std::pair kChanceOfAdjustingSelectionControl = {20, + 90}; +const std::pair kChanceOfChoosingStructTypeVsArrayType = { + 20, 80}; +const std::pair kChanceOfConstructingComposite = {20, 50}; +const std::pair kChanceOfCopyingObject = {20, 50}; +const std::pair kChanceOfDonatingAdditionalModule = {5, 50}; +const std::pair kChanceOfMakingDonorLivesafe = {40, 60}; +const std::pair kChanceOfMergingBlocks = {20, 95}; +const std::pair kChanceOfMovingBlockDown = {20, 50}; +const std::pair kChanceOfObfuscatingConstant = {10, 90}; +const std::pair kChanceOfOutliningFunction = {10, 90}; +const std::pair kChanceOfReplacingIdWithSynonym = {10, 90}; +const std::pair kChanceOfSplittingBlock = {40, 95}; + +// Default limits for various quantities that are chosen during fuzzing. +// Keep them in alphabetical order. +const uint32_t kDefaultMaxLoopControlPartialCount = 100; +const uint32_t kDefaultMaxLoopControlPeelCount = 100; +const uint32_t kDefaultMaxLoopLimit = 20; +const uint32_t kDefaultMaxNewArraySizeLimit = 100; + +// Default functions for controlling how deep to go during recursive +// generation/transformation. Keep them in alphabetical order. + +const std::function + kDefaultGoDeeperInConstantObfuscation = + [](uint32_t current_depth, RandomGenerator* random_generator) -> bool { + double chance = 1.0 / std::pow(3.0, static_cast(current_depth + 1)); + return random_generator->RandomDouble() < chance; +}; + +} // namespace + +FuzzerContext::FuzzerContext(RandomGenerator* random_generator, + uint32_t min_fresh_id) + : random_generator_(random_generator), + next_fresh_id_(min_fresh_id), + go_deeper_in_constant_obfuscation_( + kDefaultGoDeeperInConstantObfuscation) { + chance_of_adding_another_struct_field_ = + ChooseBetweenMinAndMax(kChanceOfAddingAnotherStructField); + chance_of_adding_array_or_struct_type_ = + ChooseBetweenMinAndMax(kChanceOfAddingArrayOrStructType); + chance_of_adding_dead_block_ = + ChooseBetweenMinAndMax(kChanceOfAddingDeadBlock); + chance_of_adding_dead_break_ = + ChooseBetweenMinAndMax(kChanceOfAddingDeadBreak); + chance_of_adding_dead_continue_ = + ChooseBetweenMinAndMax(kChanceOfAddingDeadContinue); + chance_of_adding_matrix_type_ = + ChooseBetweenMinAndMax(kChanceOfAddingMatrixType); + chance_of_adding_no_contraction_decoration_ = + ChooseBetweenMinAndMax(kChanceOfAddingNoContractionDecoration); + chance_of_adding_vector_type_ = + ChooseBetweenMinAndMax(kChanceOfAddingVectorType); + chance_of_adjusting_function_control_ = + ChooseBetweenMinAndMax(kChanceOfAdjustingFunctionControl); + chance_of_adjusting_loop_control_ = + ChooseBetweenMinAndMax(kChanceOfAdjustingLoopControl); + chance_of_adjusting_memory_operands_mask_ = + ChooseBetweenMinAndMax(kChanceOfAdjustingMemoryOperandsMask); + chance_of_adjusting_selection_control_ = + ChooseBetweenMinAndMax(kChanceOfAdjustingSelectionControl); + chance_of_choosing_struct_type_vs_array_type_ = + ChooseBetweenMinAndMax(kChanceOfChoosingStructTypeVsArrayType); + chance_of_constructing_composite_ = + ChooseBetweenMinAndMax(kChanceOfConstructingComposite); + chance_of_copying_object_ = ChooseBetweenMinAndMax(kChanceOfCopyingObject); + chance_of_donating_additional_module_ = + ChooseBetweenMinAndMax(kChanceOfDonatingAdditionalModule); + chance_of_making_donor_livesafe_ = + ChooseBetweenMinAndMax(kChanceOfMakingDonorLivesafe); + chance_of_merging_blocks_ = ChooseBetweenMinAndMax(kChanceOfMergingBlocks); + chance_of_moving_block_down_ = + ChooseBetweenMinAndMax(kChanceOfMovingBlockDown); + chance_of_obfuscating_constant_ = + ChooseBetweenMinAndMax(kChanceOfObfuscatingConstant); + chance_of_outlining_function_ = + ChooseBetweenMinAndMax(kChanceOfOutliningFunction); + chance_of_replacing_id_with_synonym_ = + ChooseBetweenMinAndMax(kChanceOfReplacingIdWithSynonym); + chance_of_splitting_block_ = ChooseBetweenMinAndMax(kChanceOfSplittingBlock); + max_loop_control_partial_count_ = kDefaultMaxLoopControlPartialCount; + max_loop_control_peel_count_ = kDefaultMaxLoopControlPeelCount; + max_loop_limit_ = kDefaultMaxLoopLimit; + max_new_array_size_limit_ = kDefaultMaxNewArraySizeLimit; +} + +FuzzerContext::~FuzzerContext() = default; + +uint32_t FuzzerContext::GetFreshId() { return next_fresh_id_++; } + +bool FuzzerContext::ChooseEven() { return random_generator_->RandomBool(); } + +bool FuzzerContext::ChoosePercentage(uint32_t percentage_chance) { + assert(percentage_chance <= 100); + return random_generator_->RandomPercentage() < percentage_chance; +} + +uint32_t FuzzerContext::ChooseBetweenMinAndMax( + const std::pair& min_max) { + assert(min_max.first <= min_max.second); + return min_max.first + + random_generator_->RandomUint32(min_max.second - min_max.first + 1); +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_context.h b/third_party/spirv-tools/source/fuzz/fuzzer_context.h new file mode 100644 index 0000000000..d4d6d58fbb --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/fuzzer_context.h @@ -0,0 +1,191 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_FUZZER_CONTEXT_H_ +#define SOURCE_FUZZ_FUZZER_CONTEXT_H_ + +#include +#include + +#include "source/fuzz/random_generator.h" +#include "source/opt/function.h" + +namespace spvtools { +namespace fuzz { + +// Encapsulates all parameters that control the fuzzing process, such as the +// source of randomness and the probabilities with which transformations are +// applied. +class FuzzerContext { + public: + // Constructs a fuzzer context with a given random generator and the minimum + // value that can be used for fresh ids. + FuzzerContext(RandomGenerator* random_generator, uint32_t min_fresh_id); + + ~FuzzerContext(); + + // Returns a random boolean. + bool ChooseEven(); + + // Returns true if and only if a randomly-chosen integer in the range [0, 100] + // is less than |percentage_chance|. + bool ChoosePercentage(uint32_t percentage_chance); + + // Returns a random index into |sequence|, which is expected to have a 'size' + // method, and which must be non-empty. Typically 'HasSizeMethod' will be an + // std::vector. + template + uint32_t RandomIndex(const HasSizeMethod& sequence) { + assert(sequence.size() > 0); + return random_generator_->RandomUint32( + static_cast(sequence.size())); + } + + // Yields an id that is guaranteed not to be used in the module being fuzzed, + // or to have been issued before. + uint32_t GetFreshId(); + + // Probabilities associated with applying various transformations. + // Keep them in alphabetical order. + uint32_t GetChanceOfAddingAnotherStructField() { + return chance_of_adding_another_struct_field_; + } + uint32_t GetChanceOfAddingArrayOrStructType() { + return chance_of_adding_array_or_struct_type_; + } + uint32_t GetChanceOfAddingDeadBlock() { return chance_of_adding_dead_block_; } + uint32_t GetChanceOfAddingDeadBreak() { return chance_of_adding_dead_break_; } + uint32_t GetChanceOfAddingDeadContinue() { + return chance_of_adding_dead_continue_; + } + uint32_t GetChanceOfAddingMatrixType() { + return chance_of_adding_matrix_type_; + } + uint32_t GetChanceOfAddingNoContractionDecoration() { + return chance_of_adding_no_contraction_decoration_; + } + uint32_t GetChanceOfAddingVectorType() { + return chance_of_adding_vector_type_; + } + uint32_t GetChanceOfAdjustingFunctionControl() { + return chance_of_adjusting_function_control_; + } + uint32_t GetChanceOfAdjustingLoopControl() { + return chance_of_adjusting_loop_control_; + } + uint32_t GetChanceOfAdjustingMemoryOperandsMask() { + return chance_of_adjusting_memory_operands_mask_; + } + uint32_t GetChanceOfAdjustingSelectionControl() { + return chance_of_adjusting_selection_control_; + } + uint32_t GetChanceOfChoosingStructTypeVsArrayType() { + return chance_of_choosing_struct_type_vs_array_type_; + } + uint32_t GetChanceOfConstructingComposite() { + return chance_of_constructing_composite_; + } + uint32_t GetChanceOfCopyingObject() { return chance_of_copying_object_; } + uint32_t GetChanceOfDonatingAdditionalModule() { + return chance_of_donating_additional_module_; + } + uint32_t ChanceOfMakingDonorLivesafe() { + return chance_of_making_donor_livesafe_; + } + uint32_t GetChanceOfMergingBlocks() { return chance_of_merging_blocks_; } + uint32_t GetChanceOfMovingBlockDown() { return chance_of_moving_block_down_; } + uint32_t GetChanceOfObfuscatingConstant() { + return chance_of_obfuscating_constant_; + } + uint32_t GetChanceOfOutliningFunction() { + return chance_of_outlining_function_; + } + uint32_t GetChanceOfReplacingIdWithSynonym() { + return chance_of_replacing_id_with_synonym_; + } + uint32_t GetChanceOfSplittingBlock() { return chance_of_splitting_block_; } + uint32_t GetRandomLoopControlPeelCount() { + return random_generator_->RandomUint32(max_loop_control_peel_count_); + } + uint32_t GetRandomLoopControlPartialCount() { + return random_generator_->RandomUint32(max_loop_control_partial_count_); + } + uint32_t GetRandomLoopLimit() { + return random_generator_->RandomUint32(max_loop_limit_); + } + uint32_t GetRandomSizeForNewArray() { + // Ensure that the array size is non-zero. + return random_generator_->RandomUint32(max_new_array_size_limit_ - 1) + 1; + } + + // Functions to control how deeply to recurse. + // Keep them in alphabetical order. + bool GoDeeperInConstantObfuscation(uint32_t depth) { + return go_deeper_in_constant_obfuscation_(depth, random_generator_); + } + + private: + // The source of randomness. + RandomGenerator* random_generator_; + // The next fresh id to be issued. + uint32_t next_fresh_id_; + + // Probabilities associated with applying various transformations. + // Keep them in alphabetical order. + uint32_t chance_of_adding_another_struct_field_; + uint32_t chance_of_adding_array_or_struct_type_; + uint32_t chance_of_adding_dead_block_; + uint32_t chance_of_adding_dead_break_; + uint32_t chance_of_adding_dead_continue_; + uint32_t chance_of_adding_matrix_type_; + uint32_t chance_of_adding_no_contraction_decoration_; + uint32_t chance_of_adding_vector_type_; + uint32_t chance_of_adjusting_function_control_; + uint32_t chance_of_adjusting_loop_control_; + uint32_t chance_of_adjusting_memory_operands_mask_; + uint32_t chance_of_adjusting_selection_control_; + uint32_t chance_of_choosing_struct_type_vs_array_type_; + uint32_t chance_of_constructing_composite_; + uint32_t chance_of_copying_object_; + uint32_t chance_of_donating_additional_module_; + uint32_t chance_of_making_donor_livesafe_; + uint32_t chance_of_merging_blocks_; + uint32_t chance_of_moving_block_down_; + uint32_t chance_of_obfuscating_constant_; + uint32_t chance_of_outlining_function_; + uint32_t chance_of_replacing_id_with_synonym_; + uint32_t chance_of_splitting_block_; + + // Limits associated with various quantities for which random values are + // chosen during fuzzing. + // Keep them in alphabetical order. + uint32_t max_loop_control_partial_count_; + uint32_t max_loop_control_peel_count_; + uint32_t max_loop_limit_; + uint32_t max_new_array_size_limit_; + + // Functions to determine with what probability to go deeper when generating + // or mutating constructs recursively. + const std::function& + go_deeper_in_constant_obfuscation_; + + // Requires |min_max.first| <= |min_max.second|, and returns a value in the + // range [ |min_max.first|, |min_max.second| ] + uint32_t ChooseBetweenMinAndMax(const std::pair& min_max); +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_FUZZER_CONTEXT_H_ diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass.cpp new file mode 100644 index 0000000000..9964a6c3f5 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass.cpp @@ -0,0 +1,258 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/fuzzer_pass.h" + +#include "source/fuzz/instruction_descriptor.h" +#include "source/fuzz/transformation_add_constant_scalar.h" +#include "source/fuzz/transformation_add_global_undef.h" +#include "source/fuzz/transformation_add_type_boolean.h" +#include "source/fuzz/transformation_add_type_float.h" +#include "source/fuzz/transformation_add_type_int.h" +#include "source/fuzz/transformation_add_type_matrix.h" +#include "source/fuzz/transformation_add_type_pointer.h" +#include "source/fuzz/transformation_add_type_vector.h" + +namespace spvtools { +namespace fuzz { + +FuzzerPass::FuzzerPass(opt::IRContext* ir_context, FactManager* fact_manager, + FuzzerContext* fuzzer_context, + protobufs::TransformationSequence* transformations) + : ir_context_(ir_context), + fact_manager_(fact_manager), + fuzzer_context_(fuzzer_context), + transformations_(transformations) {} + +FuzzerPass::~FuzzerPass() = default; + +std::vector FuzzerPass::FindAvailableInstructions( + const opt::Function& function, opt::BasicBlock* block, + opt::BasicBlock::iterator inst_it, + std::function + instruction_is_relevant) { + // TODO(afd) The following is (relatively) simple, but may end up being + // prohibitively inefficient, as it walks the whole dominator tree for + // every instruction that is considered. + + std::vector result; + // Consider all global declarations + for (auto& global : GetIRContext()->module()->types_values()) { + if (instruction_is_relevant(GetIRContext(), &global)) { + result.push_back(&global); + } + } + + // Consider all previous instructions in this block + for (auto prev_inst_it = block->begin(); prev_inst_it != inst_it; + ++prev_inst_it) { + if (instruction_is_relevant(GetIRContext(), &*prev_inst_it)) { + result.push_back(&*prev_inst_it); + } + } + + // Walk the dominator tree to consider all instructions from dominating + // blocks + auto dominator_analysis = GetIRContext()->GetDominatorAnalysis(&function); + for (auto next_dominator = dominator_analysis->ImmediateDominator(block); + next_dominator != nullptr; + next_dominator = + dominator_analysis->ImmediateDominator(next_dominator)) { + for (auto& dominating_inst : *next_dominator) { + if (instruction_is_relevant(GetIRContext(), &dominating_inst)) { + result.push_back(&dominating_inst); + } + } + } + return result; +} + +void FuzzerPass::MaybeAddTransformationBeforeEachInstruction( + std::function< + void(const opt::Function& function, opt::BasicBlock* block, + opt::BasicBlock::iterator inst_it, + const protobufs::InstructionDescriptor& instruction_descriptor)> + maybe_apply_transformation) { + // Consider every block in every function. + for (auto& function : *GetIRContext()->module()) { + for (auto& block : function) { + // We now consider every instruction in the block, randomly deciding + // whether to apply a transformation before it. + + // In order for transformations to insert new instructions, they need to + // be able to identify the instruction to insert before. We describe an + // instruction via its opcode, 'opc', a base instruction 'base' that has a + // result id, and the number of instructions with opcode 'opc' that we + // should skip when searching from 'base' for the desired instruction. + // (An instruction that has a result id is represented by its own opcode, + // itself as 'base', and a skip-count of 0.) + std::vector> + base_opcode_skip_triples; + + // The initial base instruction is the block label. + uint32_t base = block.id(); + + // Counts the number of times we have seen each opcode since we reset the + // base instruction. + std::map skip_count; + + // Consider every instruction in the block. The label is excluded: it is + // only necessary to consider it as a base in case the first instruction + // in the block does not have a result id. + for (auto inst_it = block.begin(); inst_it != block.end(); ++inst_it) { + if (inst_it->HasResultId()) { + // In the case that the instruction has a result id, we use the + // instruction as its own base, and clear the skip counts we have + // collected. + base = inst_it->result_id(); + skip_count.clear(); + } + const SpvOp opcode = inst_it->opcode(); + + // Invoke the provided function, which might apply a transformation. + maybe_apply_transformation( + function, &block, inst_it, + MakeInstructionDescriptor( + base, opcode, + skip_count.count(opcode) ? skip_count.at(opcode) : 0)); + + if (!inst_it->HasResultId()) { + skip_count[opcode] = + skip_count.count(opcode) ? skip_count.at(opcode) + 1 : 1; + } + } + } + } +} + +uint32_t FuzzerPass::FindOrCreateBoolType() { + opt::analysis::Bool bool_type; + auto existing_id = GetIRContext()->get_type_mgr()->GetId(&bool_type); + if (existing_id) { + return existing_id; + } + auto result = GetFuzzerContext()->GetFreshId(); + ApplyTransformation(TransformationAddTypeBoolean(result)); + return result; +} + +uint32_t FuzzerPass::FindOrCreate32BitIntegerType(bool is_signed) { + opt::analysis::Integer int_type(32, is_signed); + auto existing_id = GetIRContext()->get_type_mgr()->GetId(&int_type); + if (existing_id) { + return existing_id; + } + auto result = GetFuzzerContext()->GetFreshId(); + ApplyTransformation(TransformationAddTypeInt(result, 32, is_signed)); + return result; +} + +uint32_t FuzzerPass::FindOrCreate32BitFloatType() { + opt::analysis::Float float_type(32); + auto existing_id = GetIRContext()->get_type_mgr()->GetId(&float_type); + if (existing_id) { + return existing_id; + } + auto result = GetFuzzerContext()->GetFreshId(); + ApplyTransformation(TransformationAddTypeFloat(result, 32)); + return result; +} + +uint32_t FuzzerPass::FindOrCreateVectorType(uint32_t component_type_id, + uint32_t component_count) { + assert(component_count >= 2 && component_count <= 4 && + "Precondition: component count must be in range [2, 4]."); + opt::analysis::Type* component_type = + GetIRContext()->get_type_mgr()->GetType(component_type_id); + assert(component_type && "Precondition: the component type must exist."); + opt::analysis::Vector vector_type(component_type, component_count); + auto existing_id = GetIRContext()->get_type_mgr()->GetId(&vector_type); + if (existing_id) { + return existing_id; + } + auto result = GetFuzzerContext()->GetFreshId(); + ApplyTransformation( + TransformationAddTypeVector(result, component_type_id, component_count)); + return result; +} + +uint32_t FuzzerPass::FindOrCreateMatrixType(uint32_t column_count, + uint32_t row_count) { + assert(column_count >= 2 && column_count <= 4 && + "Precondition: column count must be in range [2, 4]."); + assert(row_count >= 2 && row_count <= 4 && + "Precondition: row count must be in range [2, 4]."); + uint32_t column_type_id = + FindOrCreateVectorType(FindOrCreate32BitFloatType(), row_count); + opt::analysis::Type* column_type = + GetIRContext()->get_type_mgr()->GetType(column_type_id); + opt::analysis::Matrix matrix_type(column_type, column_count); + auto existing_id = GetIRContext()->get_type_mgr()->GetId(&matrix_type); + if (existing_id) { + return existing_id; + } + auto result = GetFuzzerContext()->GetFreshId(); + ApplyTransformation( + TransformationAddTypeMatrix(result, column_type_id, column_count)); + return result; +} + +uint32_t FuzzerPass::FindOrCreatePointerTo32BitIntegerType( + bool is_signed, SpvStorageClass storage_class) { + auto uint32_type_id = FindOrCreate32BitIntegerType(is_signed); + opt::analysis::Pointer pointer_type( + GetIRContext()->get_type_mgr()->GetType(uint32_type_id), storage_class); + auto existing_id = GetIRContext()->get_type_mgr()->GetId(&pointer_type); + if (existing_id) { + return existing_id; + } + auto result = GetFuzzerContext()->GetFreshId(); + ApplyTransformation( + TransformationAddTypePointer(result, storage_class, uint32_type_id)); + return result; +} + +uint32_t FuzzerPass::FindOrCreate32BitIntegerConstant(uint32_t word, + bool is_signed) { + auto uint32_type_id = FindOrCreate32BitIntegerType(is_signed); + opt::analysis::IntConstant int_constant( + GetIRContext()->get_type_mgr()->GetType(uint32_type_id)->AsInteger(), + {word}); + auto existing_constant = + GetIRContext()->get_constant_mgr()->FindConstant(&int_constant); + if (existing_constant) { + return GetIRContext() + ->get_constant_mgr() + ->GetDefiningInstruction(existing_constant) + ->result_id(); + } + auto result = GetFuzzerContext()->GetFreshId(); + ApplyTransformation( + TransformationAddConstantScalar(result, uint32_type_id, {word})); + return result; +} + +uint32_t FuzzerPass::FindOrCreateGlobalUndef(uint32_t type_id) { + for (auto& inst : GetIRContext()->types_values()) { + if (inst.opcode() == SpvOpUndef && inst.type_id() == type_id) { + return inst.result_id(); + } + } + auto result = GetFuzzerContext()->GetFreshId(); + ApplyTransformation(TransformationAddGlobalUndef(result, type_id)); + return result; +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass.h new file mode 100644 index 0000000000..e1e8aec25c --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass.h @@ -0,0 +1,156 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_FUZZER_PASS_H_ +#define SOURCE_FUZZ_FUZZER_PASS_H_ + +#include +#include + +#include "source/fuzz/fact_manager.h" +#include "source/fuzz/fuzzer_context.h" +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace fuzz { + +// Interface for applying a pass of transformations to a module. +class FuzzerPass { + public: + FuzzerPass(opt::IRContext* ir_context, FactManager* fact_manager, + FuzzerContext* fuzzer_context, + protobufs::TransformationSequence* transformations); + + virtual ~FuzzerPass(); + + // Applies the pass to the module |ir_context_|, assuming and updating + // facts from |fact_manager_|, and using |fuzzer_context_| to guide the + // process. Appends to |transformations_| all transformations that were + // applied during the pass. + virtual void Apply() = 0; + + protected: + opt::IRContext* GetIRContext() const { return ir_context_; } + + FactManager* GetFactManager() const { return fact_manager_; } + + FuzzerContext* GetFuzzerContext() const { return fuzzer_context_; } + + protobufs::TransformationSequence* GetTransformations() const { + return transformations_; + } + + // Returns all instructions that are *available* at |inst_it|, which is + // required to be inside block |block| of function |function| - that is, all + // instructions at global scope and all instructions that strictly dominate + // |inst_it|. + // + // Filters said instructions to return only those that satisfy the + // |instruction_is_relevant| predicate. This, for instance, could ignore all + // instructions that have a particular decoration. + std::vector FindAvailableInstructions( + const opt::Function& function, opt::BasicBlock* block, + opt::BasicBlock::iterator inst_it, + std::function + instruction_is_relevant); + + // A helper method that iterates through each instruction in each block, at + // all times tracking an instruction descriptor that allows the latest + // instruction to be located even if it has no result id. + // + // The code to manipulate the instruction descriptor is a bit fiddly, and the + // point of this method is to avoiding having to duplicate it in multiple + // transformation passes. + // + // The function |maybe_apply_transformation| is invoked for each instruction + // |inst_it| in block |block| of function |function| that is encountered. The + // |instruction_descriptor| parameter to the function object allows |inst_it| + // to be identified. + // + // The job of |maybe_apply_transformation| is to randomly decide whether to + // try to apply some transformation, and then - if selected - to attempt to + // apply it. + void MaybeAddTransformationBeforeEachInstruction( + std::function< + void(const opt::Function& function, opt::BasicBlock* block, + opt::BasicBlock::iterator inst_it, + const protobufs::InstructionDescriptor& instruction_descriptor)> + maybe_apply_transformation); + + // A generic helper for applying a transformation that should be applicable + // by construction, and adding it to the sequence of applied transformations. + template + void ApplyTransformation(const TransformationType& transformation) { + assert(transformation.IsApplicable(GetIRContext(), *GetFactManager()) && + "Transformation should be applicable by construction."); + transformation.Apply(GetIRContext(), GetFactManager()); + *GetTransformations()->add_transformation() = transformation.ToMessage(); + } + + // Returns the id of an OpTypeBool instruction. If such an instruction does + // not exist, a transformation is applied to add it. + uint32_t FindOrCreateBoolType(); + + // Returns the id of an OpTypeInt instruction, with width 32 and signedness + // specified by |is_signed|. If such an instruction does not exist, a + // transformation is applied to add it. + uint32_t FindOrCreate32BitIntegerType(bool is_signed); + + // Returns the id of an OpTypeFloat instruction, with width 32. If such an + // instruction does not exist, a transformation is applied to add it. + uint32_t FindOrCreate32BitFloatType(); + + // Returns the id of an OpTypeVector instruction, with |component_type_id| + // (which must already exist) as its base type, and |component_count| + // elements (which must be in the range [2, 4]). If such an instruction does + // not exist, a transformation is applied to add it. + uint32_t FindOrCreateVectorType(uint32_t component_type_id, + uint32_t component_count); + + // Returns the id of an OpTypeMatrix instruction, with |column_count| columns + // and |row_count| rows (each of which must be in the range [2, 4]). If the + // float and vector types required to build this matrix type or the matrix + // type itself do not exist, transformations are applied to add them. + uint32_t FindOrCreateMatrixType(uint32_t column_count, uint32_t row_count); + + // Returns the id of an OpTypePointer instruction, with a 32-bit integer base + // type of signedness specified by |is_signed|. If the pointer type or + // required integer base type do not exist, transformations are applied to add + // them. + uint32_t FindOrCreatePointerTo32BitIntegerType(bool is_signed, + SpvStorageClass storage_class); + + // Returns the id of an OpConstant instruction, with 32-bit integer type of + // signedness specified by |is_signed|, with |word| as its value. If either + // the required integer type or the constant do not exist, transformations are + // applied to add them. + uint32_t FindOrCreate32BitIntegerConstant(uint32_t word, bool is_signed); + + // Returns the result id of an instruction of the form: + // %id = OpUndef %|type_id| + // If no such instruction exists, a transformation is applied to add it. + uint32_t FindOrCreateGlobalUndef(uint32_t type_id); + + private: + opt::IRContext* ir_context_; + FactManager* fact_manager_; + FuzzerContext* fuzzer_context_; + protobufs::TransformationSequence* transformations_; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_FUZZER_PASS_H_ diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_composite_types.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_composite_types.cpp new file mode 100644 index 0000000000..32c720e16f --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_composite_types.cpp @@ -0,0 +1,138 @@ +// Copyright (c) 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/fuzzer_pass_add_composite_types.h" + +#include "source/fuzz/fuzzer_util.h" +#include "source/fuzz/transformation_add_type_array.h" +#include "source/fuzz/transformation_add_type_struct.h" + +namespace spvtools { +namespace fuzz { + +FuzzerPassAddCompositeTypes::FuzzerPassAddCompositeTypes( + opt::IRContext* ir_context, FactManager* fact_manager, + FuzzerContext* fuzzer_context, + protobufs::TransformationSequence* transformations) + : FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {} + +FuzzerPassAddCompositeTypes::~FuzzerPassAddCompositeTypes() = default; + +void FuzzerPassAddCompositeTypes::Apply() { + MaybeAddMissingVectorTypes(); + MaybeAddMissingMatrixTypes(); + + // Randomly interleave between adding struct and array composite types + while (GetFuzzerContext()->ChoosePercentage( + GetFuzzerContext()->GetChanceOfAddingArrayOrStructType())) { + if (GetFuzzerContext()->ChoosePercentage( + GetFuzzerContext()->GetChanceOfChoosingStructTypeVsArrayType())) { + AddNewStructType(); + } else { + AddNewArrayType(); + } + } +} + +void FuzzerPassAddCompositeTypes::MaybeAddMissingVectorTypes() { + // Functions to lazily supply scalar base types on demand if we decide to + // create vectors with the relevant base types. + std::function bool_type_supplier = [this]() -> uint32_t { + return FindOrCreateBoolType(); + }; + std::function float_type_supplier = [this]() -> uint32_t { + return FindOrCreate32BitFloatType(); + }; + std::function int_type_supplier = [this]() -> uint32_t { + return FindOrCreate32BitIntegerType(true); + }; + std::function uint_type_supplier = [this]() -> uint32_t { + return FindOrCreate32BitIntegerType(false); + }; + + // Consider each of the base types with which we can make vectors. + for (auto& base_type_supplier : {bool_type_supplier, float_type_supplier, + int_type_supplier, uint_type_supplier}) { + // Consider each valid vector size. + for (uint32_t size = 2; size <= 4; size++) { + // Randomly decide whether to create (if it does not already exist) a + // vector with this size and base type. + if (GetFuzzerContext()->ChoosePercentage( + GetFuzzerContext()->GetChanceOfAddingVectorType())) { + FindOrCreateVectorType(base_type_supplier(), size); + } + } + } +} + +void FuzzerPassAddCompositeTypes::MaybeAddMissingMatrixTypes() { + // Consider every valid matrix dimension. + for (uint32_t columns = 2; columns <= 4; columns++) { + for (uint32_t rows = 2; rows <= 4; rows++) { + // Randomly decide whether to create (if it does not already exist) a + // matrix with these dimensions. As matrices can only have floating-point + // base type, we do not need to consider multiple base types as in the + // case for vectors. + if (GetFuzzerContext()->ChoosePercentage( + GetFuzzerContext()->GetChanceOfAddingMatrixType())) { + FindOrCreateMatrixType(columns, rows); + } + } + } +} + +void FuzzerPassAddCompositeTypes::AddNewArrayType() { + ApplyTransformation(TransformationAddTypeArray( + GetFuzzerContext()->GetFreshId(), ChooseScalarOrCompositeType(), + FindOrCreate32BitIntegerConstant( + GetFuzzerContext()->GetRandomSizeForNewArray(), false))); +} + +void FuzzerPassAddCompositeTypes::AddNewStructType() { + std::vector field_type_ids; + do { + field_type_ids.push_back(ChooseScalarOrCompositeType()); + } while (GetFuzzerContext()->ChoosePercentage( + GetFuzzerContext()->GetChanceOfAddingAnotherStructField())); + ApplyTransformation(TransformationAddTypeStruct( + GetFuzzerContext()->GetFreshId(), field_type_ids)); +} + +uint32_t FuzzerPassAddCompositeTypes::ChooseScalarOrCompositeType() { + // Gather up all the possibly-relevant types. + std::vector candidates; + for (auto& inst : GetIRContext()->types_values()) { + switch (inst.opcode()) { + case SpvOpTypeArray: + case SpvOpTypeBool: + case SpvOpTypeFloat: + case SpvOpTypeInt: + case SpvOpTypeMatrix: + case SpvOpTypeStruct: + case SpvOpTypeVector: + candidates.push_back(inst.result_id()); + break; + default: + break; + } + } + assert(!candidates.empty() && + "This function should only be called if there is at least one scalar " + "or composite type available."); + // Return one of these types at random. + return candidates[GetFuzzerContext()->RandomIndex(candidates)]; +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_composite_types.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_composite_types.h new file mode 100644 index 0000000000..29d4bb896f --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_composite_types.h @@ -0,0 +1,61 @@ +// Copyright (c) 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_FUZZER_PASS_ADD_COMPOSITE_TYPES_H_ +#define SOURCE_FUZZ_FUZZER_PASS_ADD_COMPOSITE_TYPES_H_ + +#include "source/fuzz/fuzzer_pass.h" + +namespace spvtools { +namespace fuzz { + +// Fuzzer pass that randomly adds missing vector and matrix types, and new +// array and struct types, to the module. +class FuzzerPassAddCompositeTypes : public FuzzerPass { + public: + FuzzerPassAddCompositeTypes( + opt::IRContext* ir_context, FactManager* fact_manager, + FuzzerContext* fuzzer_context, + protobufs::TransformationSequence* transformations); + + ~FuzzerPassAddCompositeTypes(); + + void Apply() override; + + private: + // Creates an array of a random size with a random existing base type and adds + // it to the module. + void AddNewArrayType(); + + // Creates a struct with fields of random existing types and adds it to the + // module. + void AddNewStructType(); + + // For each vector type not already present in the module, randomly decides + // whether to add it to the module. + void MaybeAddMissingVectorTypes(); + + // For each matrix type not already present in the module, randomly decides + // whether to add it to the module. + void MaybeAddMissingMatrixTypes(); + + // Returns the id of a scalar or composite type declared in the module, + // chosen randomly. + uint32_t ChooseScalarOrCompositeType(); +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_FUZZER_PASS_ADD_COMPOSITE_TYPES_H_ diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_dead_blocks.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_dead_blocks.cpp new file mode 100644 index 0000000000..c9bc9c4859 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_dead_blocks.cpp @@ -0,0 +1,64 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/fuzzer_pass_add_dead_blocks.h" + +#include "source/fuzz/fuzzer_util.h" +#include "source/fuzz/transformation_add_dead_block.h" + +namespace spvtools { +namespace fuzz { + +FuzzerPassAddDeadBlocks::FuzzerPassAddDeadBlocks( + opt::IRContext* ir_context, FactManager* fact_manager, + FuzzerContext* fuzzer_context, + protobufs::TransformationSequence* transformations) + : FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {} + +FuzzerPassAddDeadBlocks::~FuzzerPassAddDeadBlocks() = default; + +void FuzzerPassAddDeadBlocks::Apply() { + // We iterate over all blocks in the module collecting up those at which we + // might add a branch to a new dead block. We then loop over all such + // candidates and actually apply transformations. This separation is to + // avoid modifying the module as we traverse it. + std::vector candidate_transformations; + for (auto& function : *GetIRContext()->module()) { + for (auto& block : function) { + if (!GetFuzzerContext()->ChoosePercentage( + GetFuzzerContext()->GetChanceOfAddingDeadBlock())) { + continue; + } + // We speculatively create a transformation, and then apply it (below) if + // it turns out to be applicable. This avoids duplicating the logic for + // applicability checking. + // + // It means that fresh ids for transformations that turn out not to be + // applicable end up being unused. + candidate_transformations.emplace_back(TransformationAddDeadBlock( + GetFuzzerContext()->GetFreshId(), block.id(), + GetFuzzerContext()->ChooseEven())); + } + } + // Apply all those transformations that are in fact applicable. + for (auto& transformation : candidate_transformations) { + if (transformation.IsApplicable(GetIRContext(), *GetFactManager())) { + transformation.Apply(GetIRContext(), GetFactManager()); + *GetTransformations()->add_transformation() = transformation.ToMessage(); + } + } +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_dead_blocks.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_dead_blocks.h new file mode 100644 index 0000000000..01e3843db6 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_dead_blocks.h @@ -0,0 +1,39 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_FUZZER_PASS_ADD_DEAD_BLOCKS_H_ +#define SOURCE_FUZZ_FUZZER_PASS_ADD_DEAD_BLOCKS_H_ + +#include "source/fuzz/fuzzer_pass.h" + +namespace spvtools { +namespace fuzz { + +// Fuzzer pass to add dynamically unreachable blocks to the module. Future +// passes can then manipulate such blocks. +class FuzzerPassAddDeadBlocks : public FuzzerPass { + public: + FuzzerPassAddDeadBlocks(opt::IRContext* ir_context, FactManager* fact_manager, + FuzzerContext* fuzzer_context, + protobufs::TransformationSequence* transformations); + + ~FuzzerPassAddDeadBlocks(); + + void Apply() override; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_FUZZER_PASS_ADD_DEAD_BLOCKS_H_ diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_dead_breaks.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_dead_breaks.cpp new file mode 100644 index 0000000000..fa6b098844 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_dead_breaks.cpp @@ -0,0 +1,95 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/fuzzer_pass_add_dead_breaks.h" + +#include "source/fuzz/transformation_add_dead_break.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace fuzz { + +FuzzerPassAddDeadBreaks::FuzzerPassAddDeadBreaks( + opt::IRContext* ir_context, FactManager* fact_manager, + FuzzerContext* fuzzer_context, + protobufs::TransformationSequence* transformations) + : FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {} + +FuzzerPassAddDeadBreaks::~FuzzerPassAddDeadBreaks() = default; + +void FuzzerPassAddDeadBreaks::Apply() { + // We first collect up lots of possibly-applicable transformations. + std::vector candidate_transformations; + // We consider each function separately. + for (auto& function : *GetIRContext()->module()) { + // For a given function, we find all the merge blocks in that function. + std::vector merge_block_ids; + for (auto& block : function) { + auto maybe_merge_id = block.MergeBlockIdIfAny(); + if (maybe_merge_id) { + merge_block_ids.push_back(maybe_merge_id); + } + } + // We rather aggressively consider the possibility of adding a break from + // every block in the function to every merge block. Many of these will be + // inapplicable as they would be illegal. That's OK - we later discard the + // ones that turn out to be no good. + for (auto& block : function) { + for (auto merge_block_id : merge_block_ids) { + // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/2856): right + // now we completely ignore OpPhi instructions at merge blocks. This + // will lead to interesting opportunities being missed. + auto candidate_transformation = TransformationAddDeadBreak( + block.id(), merge_block_id, GetFuzzerContext()->ChooseEven(), {}); + if (candidate_transformation.IsApplicable(GetIRContext(), + *GetFactManager())) { + // Only consider a transformation as a candidate if it is applicable. + candidate_transformations.push_back( + std::move(candidate_transformation)); + } + } + } + } + + // Go through the candidate transformations that were accumulated, + // probabilistically deciding whether to consider each one further and + // applying the still-applicable ones that are considered further. + // + // We iterate through the candidate transformations in a random order by + // repeatedly removing a random candidate transformation from the sequence + // until no candidate transformations remain. This is done because + // transformations can potentially disable one another, so that iterating + // through them in order would lead to a higher probability of + // transformations appearing early in the sequence being applied compared + // with later transformations. + while (!candidate_transformations.empty()) { + // Choose a random index into the sequence of remaining candidate + // transformations. + auto index = GetFuzzerContext()->RandomIndex(candidate_transformations); + // Remove the transformation at the chosen index from the sequence. + auto transformation = std::move(candidate_transformations[index]); + candidate_transformations.erase(candidate_transformations.begin() + index); + // Probabilistically decide whether to try to apply it vs. ignore it, in the + // case that it is applicable. + if (transformation.IsApplicable(GetIRContext(), *GetFactManager()) && + GetFuzzerContext()->ChoosePercentage( + GetFuzzerContext()->GetChanceOfAddingDeadBreak())) { + transformation.Apply(GetIRContext(), GetFactManager()); + *GetTransformations()->add_transformation() = transformation.ToMessage(); + } + } +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_dead_breaks.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_dead_breaks.h new file mode 100644 index 0000000000..12a5095f0e --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_dead_breaks.h @@ -0,0 +1,38 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_FUZZER_PASS_ADD_DEAD_BREAKS_H_ +#define SOURCE_FUZZ_FUZZER_PASS_ADD_DEAD_BREAKS_H_ + +#include "source/fuzz/fuzzer_pass.h" + +namespace spvtools { +namespace fuzz { + +// A fuzzer pass for adding dead break edges to the module. +class FuzzerPassAddDeadBreaks : public FuzzerPass { + public: + FuzzerPassAddDeadBreaks(opt::IRContext* ir_context, FactManager* fact_manager, + FuzzerContext* fuzzer_context, + protobufs::TransformationSequence* transformations); + + ~FuzzerPassAddDeadBreaks(); + + void Apply() override; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_FUZZER_PASS_ADD_DEAD_BREAKS_H_ diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_dead_continues.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_dead_continues.cpp new file mode 100644 index 0000000000..51bcb91ebe --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_dead_continues.cpp @@ -0,0 +1,59 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/fuzzer_pass_add_dead_continues.h" + +#include "source/fuzz/transformation_add_dead_continue.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace fuzz { + +FuzzerPassAddDeadContinues::FuzzerPassAddDeadContinues( + opt::IRContext* ir_context, FactManager* fact_manager, + FuzzerContext* fuzzer_context, + protobufs::TransformationSequence* transformations) + : FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {} + +FuzzerPassAddDeadContinues::~FuzzerPassAddDeadContinues() = default; + +void FuzzerPassAddDeadContinues::Apply() { + // Consider every block in every function. + for (auto& function : *GetIRContext()->module()) { + for (auto& block : function) { + // Make a transformation to add a dead continue from this node; if the + // node turns out to be inappropriate (e.g. by not being in a loop) the + // precondition for the transformation will fail and it will be ignored. + // + // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/2856): right + // now we completely ignore OpPhi instructions at continue targets. + // This will lead to interesting opportunities being missed. + auto candidate_transformation = TransformationAddDeadContinue( + block.id(), GetFuzzerContext()->ChooseEven(), {}); + // Probabilistically decide whether to apply the transformation in the + // case that it is applicable. + if (candidate_transformation.IsApplicable(GetIRContext(), + *GetFactManager()) && + GetFuzzerContext()->ChoosePercentage( + GetFuzzerContext()->GetChanceOfAddingDeadContinue())) { + candidate_transformation.Apply(GetIRContext(), GetFactManager()); + *GetTransformations()->add_transformation() = + candidate_transformation.ToMessage(); + } + } + } +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_dead_continues.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_dead_continues.h new file mode 100644 index 0000000000..d067f1c4d8 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_dead_continues.h @@ -0,0 +1,39 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_FUZZER_PASS_ADD_DEAD_CONTINUES_H_ +#define SOURCE_FUZZ_FUZZER_PASS_ADD_DEAD_CONTINUES_H_ + +#include "source/fuzz/fuzzer_pass.h" + +namespace spvtools { +namespace fuzz { + +// A fuzzer pass for adding dead continue edges to the module. +class FuzzerPassAddDeadContinues : public FuzzerPass { + public: + FuzzerPassAddDeadContinues( + opt::IRContext* ir_context, FactManager* fact_manager, + FuzzerContext* fuzzer_context, + protobufs::TransformationSequence* transformations); + + ~FuzzerPassAddDeadContinues(); + + void Apply() override; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_FUZZER_PASS_ADD_DEAD_CONTINUES_H_ diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_no_contraction_decorations.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_no_contraction_decorations.cpp new file mode 100644 index 0000000000..ead8c5cd55 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_no_contraction_decorations.cpp @@ -0,0 +1,61 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/fuzzer_pass_add_no_contraction_decorations.h" + +#include "source/fuzz/transformation_add_no_contraction_decoration.h" + +namespace spvtools { +namespace fuzz { + +FuzzerPassAddNoContractionDecorations::FuzzerPassAddNoContractionDecorations( + opt::IRContext* ir_context, FactManager* fact_manager, + FuzzerContext* fuzzer_context, + protobufs::TransformationSequence* transformations) + : FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {} + +FuzzerPassAddNoContractionDecorations:: + ~FuzzerPassAddNoContractionDecorations() = default; + +void FuzzerPassAddNoContractionDecorations::Apply() { + // Consider every instruction in every block in every function. + for (auto& function : *GetIRContext()->module()) { + for (auto& block : function) { + for (auto& inst : block) { + // Restrict attention to arithmetic instructions (as defined in the + // SPIR-V specification). + if (TransformationAddNoContractionDecoration::IsArithmetic( + inst.opcode())) { + // Randomly choose whether to apply the NoContraction decoration to + // this arithmetic instruction. + if (GetFuzzerContext()->ChoosePercentage( + GetFuzzerContext() + ->GetChanceOfAddingNoContractionDecoration())) { + TransformationAddNoContractionDecoration transformation( + inst.result_id()); + assert(transformation.IsApplicable(GetIRContext(), + *GetFactManager()) && + "Transformation should be applicable by construction."); + transformation.Apply(GetIRContext(), GetFactManager()); + *GetTransformations()->add_transformation() = + transformation.ToMessage(); + } + } + } + } + } +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_no_contraction_decorations.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_no_contraction_decorations.h new file mode 100644 index 0000000000..abe5bd7ad9 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_no_contraction_decorations.h @@ -0,0 +1,39 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_FUZZER_PASS_ADD_NO_CONTRACTION_DECORATIONS_ +#define SOURCE_FUZZ_FUZZER_PASS_ADD_NO_CONTRACTION_DECORATIONS_ + +#include "source/fuzz/fuzzer_pass.h" + +namespace spvtools { +namespace fuzz { + +// A pass that applies the NoContraction decoration to arithmetic instructions. +class FuzzerPassAddNoContractionDecorations : public FuzzerPass { + public: + FuzzerPassAddNoContractionDecorations( + opt::IRContext* ir_context, FactManager* fact_manager, + FuzzerContext* fuzzer_context, + protobufs::TransformationSequence* transformations); + + ~FuzzerPassAddNoContractionDecorations() override; + + void Apply() override; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_FUZZER_PASS_ADD_NO_CONTRACTION_DECORATIONS_ diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_useful_constructs.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_useful_constructs.cpp new file mode 100644 index 0000000000..8552dfd299 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_useful_constructs.cpp @@ -0,0 +1,214 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/fuzzer_pass_add_useful_constructs.h" + +#include "source/fuzz/transformation_add_constant_boolean.h" +#include "source/fuzz/transformation_add_constant_scalar.h" +#include "source/fuzz/transformation_add_type_boolean.h" +#include "source/fuzz/transformation_add_type_float.h" +#include "source/fuzz/transformation_add_type_int.h" +#include "source/fuzz/transformation_add_type_pointer.h" + +namespace spvtools { +namespace fuzz { + +FuzzerPassAddUsefulConstructs::FuzzerPassAddUsefulConstructs( + opt::IRContext* ir_context, FactManager* fact_manager, + FuzzerContext* fuzzer_context, + protobufs::TransformationSequence* transformations) + : FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {} + +FuzzerPassAddUsefulConstructs::~FuzzerPassAddUsefulConstructs() = default; + +void FuzzerPassAddUsefulConstructs::MaybeAddIntConstant( + uint32_t width, bool is_signed, std::vector data) const { + opt::analysis::Integer temp_int_type(width, is_signed); + assert(GetIRContext()->get_type_mgr()->GetId(&temp_int_type) && + "int type should already be registered."); + auto registered_int_type = GetIRContext() + ->get_type_mgr() + ->GetRegisteredType(&temp_int_type) + ->AsInteger(); + auto int_type_id = GetIRContext()->get_type_mgr()->GetId(registered_int_type); + assert(int_type_id && + "The relevant int type should have been added to the module already."); + opt::analysis::IntConstant int_constant(registered_int_type, data); + if (!GetIRContext()->get_constant_mgr()->FindConstant(&int_constant)) { + TransformationAddConstantScalar add_constant_int = + TransformationAddConstantScalar(GetFuzzerContext()->GetFreshId(), + int_type_id, data); + assert(add_constant_int.IsApplicable(GetIRContext(), *GetFactManager()) && + "Should be applicable by construction."); + add_constant_int.Apply(GetIRContext(), GetFactManager()); + *GetTransformations()->add_transformation() = add_constant_int.ToMessage(); + } +} + +void FuzzerPassAddUsefulConstructs::MaybeAddFloatConstant( + uint32_t width, std::vector data) const { + opt::analysis::Float temp_float_type(width); + assert(GetIRContext()->get_type_mgr()->GetId(&temp_float_type) && + "float type should already be registered."); + auto registered_float_type = GetIRContext() + ->get_type_mgr() + ->GetRegisteredType(&temp_float_type) + ->AsFloat(); + auto float_type_id = + GetIRContext()->get_type_mgr()->GetId(registered_float_type); + assert( + float_type_id && + "The relevant float type should have been added to the module already."); + opt::analysis::FloatConstant float_constant(registered_float_type, data); + if (!GetIRContext()->get_constant_mgr()->FindConstant(&float_constant)) { + TransformationAddConstantScalar add_constant_float = + TransformationAddConstantScalar(GetFuzzerContext()->GetFreshId(), + float_type_id, data); + assert(add_constant_float.IsApplicable(GetIRContext(), *GetFactManager()) && + "Should be applicable by construction."); + add_constant_float.Apply(GetIRContext(), GetFactManager()); + *GetTransformations()->add_transformation() = + add_constant_float.ToMessage(); + } +} + +void FuzzerPassAddUsefulConstructs::Apply() { + { + // Add boolean type if not present. + opt::analysis::Bool temp_bool_type; + if (!GetIRContext()->get_type_mgr()->GetId(&temp_bool_type)) { + auto add_type_boolean = + TransformationAddTypeBoolean(GetFuzzerContext()->GetFreshId()); + assert(add_type_boolean.IsApplicable(GetIRContext(), *GetFactManager()) && + "Should be applicable by construction."); + add_type_boolean.Apply(GetIRContext(), GetFactManager()); + *GetTransformations()->add_transformation() = + add_type_boolean.ToMessage(); + } + } + + { + // Add signed and unsigned 32-bit integer types if not present. + for (auto is_signed : {true, false}) { + opt::analysis::Integer temp_int_type(32, is_signed); + if (!GetIRContext()->get_type_mgr()->GetId(&temp_int_type)) { + TransformationAddTypeInt add_type_int = TransformationAddTypeInt( + GetFuzzerContext()->GetFreshId(), 32, is_signed); + assert(add_type_int.IsApplicable(GetIRContext(), *GetFactManager()) && + "Should be applicable by construction."); + add_type_int.Apply(GetIRContext(), GetFactManager()); + *GetTransformations()->add_transformation() = add_type_int.ToMessage(); + } + } + } + + { + // Add 32-bit float type if not present. + opt::analysis::Float temp_float_type(32); + if (!GetIRContext()->get_type_mgr()->GetId(&temp_float_type)) { + TransformationAddTypeFloat add_type_float = + TransformationAddTypeFloat(GetFuzzerContext()->GetFreshId(), 32); + assert(add_type_float.IsApplicable(GetIRContext(), *GetFactManager()) && + "Should be applicable by construction."); + add_type_float.Apply(GetIRContext(), GetFactManager()); + *GetTransformations()->add_transformation() = add_type_float.ToMessage(); + } + } + + // Add boolean constants true and false if not present. + opt::analysis::Bool temp_bool_type; + auto bool_type = GetIRContext() + ->get_type_mgr() + ->GetRegisteredType(&temp_bool_type) + ->AsBool(); + for (auto boolean_value : {true, false}) { + // Add OpConstantTrue/False if not already there. + opt::analysis::BoolConstant bool_constant(bool_type, boolean_value); + if (!GetIRContext()->get_constant_mgr()->FindConstant(&bool_constant)) { + TransformationAddConstantBoolean add_constant_boolean( + GetFuzzerContext()->GetFreshId(), boolean_value); + assert(add_constant_boolean.IsApplicable(GetIRContext(), + *GetFactManager()) && + "Should be applicable by construction."); + add_constant_boolean.Apply(GetIRContext(), GetFactManager()); + *GetTransformations()->add_transformation() = + add_constant_boolean.ToMessage(); + } + } + + // Add signed and unsigned 32-bit integer constants 0 and 1 if not present. + for (auto is_signed : {true, false}) { + for (auto value : {0u, 1u}) { + MaybeAddIntConstant(32, is_signed, {value}); + } + } + + // Add 32-bit float constants 0.0 and 1.0 if not present. + uint32_t uint_data[2]; + float float_data[2] = {0.0, 1.0}; + memcpy(uint_data, float_data, sizeof(float_data)); + for (unsigned int& datum : uint_data) { + MaybeAddFloatConstant(32, {datum}); + } + + // For every known-to-be-constant uniform, make sure we have instructions + // declaring: + // - a pointer type with uniform storage class, whose pointee type is the type + // of the element + // - a signed integer constant for each index required to access the element + // - a constant for the constant value itself + for (auto& fact_and_type_id : + GetFactManager()->GetConstantUniformFactsAndTypes()) { + uint32_t element_type_id = fact_and_type_id.second; + assert(element_type_id); + auto element_type = + GetIRContext()->get_type_mgr()->GetType(element_type_id); + assert(element_type && + "If the constant uniform fact is well-formed, the module must " + "already have a declaration of the type for the uniform element."); + opt::analysis::Pointer uniform_pointer(element_type, + SpvStorageClassUniform); + if (!GetIRContext()->get_type_mgr()->GetId(&uniform_pointer)) { + auto add_pointer = + TransformationAddTypePointer(GetFuzzerContext()->GetFreshId(), + SpvStorageClassUniform, element_type_id); + assert(add_pointer.IsApplicable(GetIRContext(), *GetFactManager()) && + "Should be applicable by construction."); + add_pointer.Apply(GetIRContext(), GetFactManager()); + *GetTransformations()->add_transformation() = add_pointer.ToMessage(); + } + std::vector words; + for (auto word : fact_and_type_id.first.constant_word()) { + words.push_back(word); + } + // We get the element type again as the type manager may have been + // invalidated since we last retrieved it. + element_type = GetIRContext()->get_type_mgr()->GetType(element_type_id); + if (element_type->AsInteger()) { + MaybeAddIntConstant(element_type->AsInteger()->width(), + element_type->AsInteger()->IsSigned(), words); + } else { + assert(element_type->AsFloat() && + "Known uniform values must be integer or floating-point."); + MaybeAddFloatConstant(element_type->AsFloat()->width(), words); + } + for (auto index : + fact_and_type_id.first.uniform_buffer_element_descriptor().index()) { + MaybeAddIntConstant(32, true, {index}); + } + } +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_useful_constructs.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_useful_constructs.h new file mode 100644 index 0000000000..7dc00f13ef --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_add_useful_constructs.h @@ -0,0 +1,46 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_FUZZER_PASS_ADD_USEFUL_CONSTRUCTS_ +#define SOURCE_FUZZ_FUZZER_PASS_ADD_USEFUL_CONSTRUCTS_ + +#include "source/fuzz/fuzzer_pass.h" + +namespace spvtools { +namespace fuzz { + +// An initial pass for adding useful ingredients to the module, such as boolean +// constants, if they are not present. +class FuzzerPassAddUsefulConstructs : public FuzzerPass { + public: + FuzzerPassAddUsefulConstructs( + opt::IRContext* ir_context, FactManager* fact_manager, + FuzzerContext* fuzzer_context, + protobufs::TransformationSequence* transformations); + + ~FuzzerPassAddUsefulConstructs() override; + + void Apply() override; + + private: + void MaybeAddIntConstant(uint32_t width, bool is_signed, + std::vector data) const; + + void MaybeAddFloatConstant(uint32_t width, std::vector data) const; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_FUZZER_PASS_ADD_USEFUL_CONSTRUCTS_ diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_function_controls.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_function_controls.cpp new file mode 100644 index 0000000000..2a11988f47 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_function_controls.cpp @@ -0,0 +1,73 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/fuzzer_pass_adjust_function_controls.h" + +#include "source/fuzz/transformation_set_function_control.h" + +namespace spvtools { +namespace fuzz { + +FuzzerPassAdjustFunctionControls::FuzzerPassAdjustFunctionControls( + opt::IRContext* ir_context, FactManager* fact_manager, + FuzzerContext* fuzzer_context, + protobufs::TransformationSequence* transformations) + : FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {} + +FuzzerPassAdjustFunctionControls::~FuzzerPassAdjustFunctionControls() = default; + +void FuzzerPassAdjustFunctionControls::Apply() { + // Consider every function in the module. + for (auto& function : *GetIRContext()->module()) { + // Randomly decide whether to adjust this function's controls. + if (GetFuzzerContext()->ChoosePercentage( + GetFuzzerContext()->GetChanceOfAdjustingFunctionControl())) { + // Grab the function control mask for the function in its present form. + uint32_t existing_function_control_mask = + function.DefInst().GetSingleWordInOperand(0); + + // For the new mask, we first randomly select one of three basic masks: + // None, Inline or DontInline. These are always valid (and are mutually + // exclusive). + std::vector basic_function_control_masks = { + SpvFunctionControlMaskNone, SpvFunctionControlInlineMask, + SpvFunctionControlDontInlineMask}; + uint32_t new_function_control_mask = + basic_function_control_masks[GetFuzzerContext()->RandomIndex( + basic_function_control_masks)]; + + // We now consider the Pure and Const mask bits. If these are already + // set on the function then it's OK to keep them, but also interesting + // to consider dropping them, so we decide randomly in each case. + for (auto mask_bit : + {SpvFunctionControlPureMask, SpvFunctionControlConstMask}) { + if ((existing_function_control_mask & mask_bit) && + GetFuzzerContext()->ChooseEven()) { + new_function_control_mask |= mask_bit; + } + } + + // Create and add a transformation. + TransformationSetFunctionControl transformation( + function.DefInst().result_id(), new_function_control_mask); + assert(transformation.IsApplicable(GetIRContext(), *GetFactManager()) && + "Transformation should be applicable by construction."); + transformation.Apply(GetIRContext(), GetFactManager()); + *GetTransformations()->add_transformation() = transformation.ToMessage(); + } + } +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_function_controls.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_function_controls.h new file mode 100644 index 0000000000..02d36004ee --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_function_controls.h @@ -0,0 +1,39 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_FUZZER_PASS_ADJUST_FUNCTION_CONTROLS_ +#define SOURCE_FUZZ_FUZZER_PASS_ADJUST_FUNCTION_CONTROLS_ + +#include "source/fuzz/fuzzer_pass.h" + +namespace spvtools { +namespace fuzz { + +// A pass that adjusts the function controls on OpFunction instructions. +class FuzzerPassAdjustFunctionControls : public FuzzerPass { + public: + FuzzerPassAdjustFunctionControls( + opt::IRContext* ir_context, FactManager* fact_manager, + FuzzerContext* fuzzer_context, + protobufs::TransformationSequence* transformations); + + ~FuzzerPassAdjustFunctionControls() override; + + void Apply() override; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_FUZZER_PASS_ADJUST_FUNCTION_CONTROLS_ diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_loop_controls.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_loop_controls.cpp new file mode 100644 index 0000000000..ac2408aef9 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_loop_controls.cpp @@ -0,0 +1,121 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/fuzzer_pass_adjust_loop_controls.h" + +#include "source/fuzz/transformation_set_loop_control.h" + +namespace spvtools { +namespace fuzz { + +FuzzerPassAdjustLoopControls::FuzzerPassAdjustLoopControls( + opt::IRContext* ir_context, FactManager* fact_manager, + FuzzerContext* fuzzer_context, + protobufs::TransformationSequence* transformations) + : FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {} + +FuzzerPassAdjustLoopControls::~FuzzerPassAdjustLoopControls() = default; + +void FuzzerPassAdjustLoopControls::Apply() { + // Consider every merge instruction in the module (via looking through all + // functions and blocks). + for (auto& function : *GetIRContext()->module()) { + for (auto& block : function) { + if (auto merge_inst = block.GetMergeInst()) { + // Ignore the instruction if it is not a loop merge. + if (merge_inst->opcode() != SpvOpLoopMerge) { + continue; + } + + // Decide randomly whether to adjust this loop merge. + if (!GetFuzzerContext()->ChoosePercentage( + GetFuzzerContext()->GetChanceOfAdjustingLoopControl())) { + continue; + } + + uint32_t existing_mask = merge_inst->GetSingleWordOperand( + TransformationSetLoopControl::kLoopControlMaskInOperandIndex); + + // First, set the new mask to one of None, Unroll or DontUnroll. + std::vector basic_masks = {SpvLoopControlMaskNone, + SpvLoopControlUnrollMask, + SpvLoopControlDontUnrollMask}; + uint32_t new_mask = + basic_masks[GetFuzzerContext()->RandomIndex(basic_masks)]; + + // For the loop controls that depend on guarantees about what the loop + // does, check which of these were present in the existing mask and + // randomly decide whether to keep them. They are just hints, so + // removing them should not change the semantics of the module. + for (auto mask_bit : + {SpvLoopControlDependencyInfiniteMask, + SpvLoopControlDependencyLengthMask, + SpvLoopControlMinIterationsMask, SpvLoopControlMaxIterationsMask, + SpvLoopControlIterationMultipleMask}) { + if ((existing_mask & mask_bit) && GetFuzzerContext()->ChooseEven()) { + // The mask bits we are considering are not available in all SPIR-V + // versions. However, we only include a mask bit if it was present + // in the original loop control mask, and we work under the + // assumption that we are transforming a valid module, thus we don't + // need to actually check whether the SPIR-V version being used + // supports these loop control mask bits. + new_mask |= mask_bit; + } + } + + // We use 0 for peel count and partial count in the case that we choose + // not to set these controls. + uint32_t peel_count = 0; + uint32_t partial_count = 0; + + // PeelCount and PartialCount are not compatible with DontUnroll, so + // we check whether DontUnroll is set. + if (!(new_mask & SpvLoopControlDontUnrollMask)) { + // If PeelCount is supported by this SPIR-V version, randomly choose + // whether to set it. If it was set in the original mask and is not + // selected for setting here, that amounts to dropping it. + if (TransformationSetLoopControl::PeelCountIsSupported( + GetIRContext()) && + GetFuzzerContext()->ChooseEven()) { + new_mask |= SpvLoopControlPeelCountMask; + // The peel count is chosen randomly - if PeelCount was already set + // this will overwrite whatever peel count was previously used. + peel_count = GetFuzzerContext()->GetRandomLoopControlPeelCount(); + } + // Similar, but for PartialCount. + if (TransformationSetLoopControl::PartialCountIsSupported( + GetIRContext()) && + GetFuzzerContext()->ChooseEven()) { + new_mask |= SpvLoopControlPartialCountMask; + partial_count = + GetFuzzerContext()->GetRandomLoopControlPartialCount(); + } + } + + // Apply the transformation and add it to the output transformation + // sequence. + TransformationSetLoopControl transformation(block.id(), new_mask, + peel_count, partial_count); + assert(transformation.IsApplicable(GetIRContext(), *GetFactManager()) && + "Transformation should be applicable by construction."); + transformation.Apply(GetIRContext(), GetFactManager()); + *GetTransformations()->add_transformation() = + transformation.ToMessage(); + } + } + } +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_loop_controls.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_loop_controls.h new file mode 100644 index 0000000000..e94560673e --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_loop_controls.h @@ -0,0 +1,39 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_FUZZER_PASS_ADJUST_LOOP_CONTROLS_ +#define SOURCE_FUZZ_FUZZER_PASS_ADJUST_LOOP_CONTROLS_ + +#include "source/fuzz/fuzzer_pass.h" + +namespace spvtools { +namespace fuzz { + +// A pass that adjusts the loop controls on OpLoopMerge instructions. +class FuzzerPassAdjustLoopControls : public FuzzerPass { + public: + FuzzerPassAdjustLoopControls( + opt::IRContext* ir_context, FactManager* fact_manager, + FuzzerContext* fuzzer_context, + protobufs::TransformationSequence* transformations); + + ~FuzzerPassAdjustLoopControls() override; + + void Apply() override; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_FUZZER_PASS_ADJUST_LOOP_CONTROLS_ diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_memory_operands_masks.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_memory_operands_masks.cpp new file mode 100644 index 0000000000..a9d4b3243b --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_memory_operands_masks.cpp @@ -0,0 +1,113 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/fuzzer_pass_adjust_memory_operands_masks.h" + +#include "source/fuzz/instruction_descriptor.h" +#include "source/fuzz/transformation_set_memory_operands_mask.h" + +namespace spvtools { +namespace fuzz { + +FuzzerPassAdjustMemoryOperandsMasks::FuzzerPassAdjustMemoryOperandsMasks( + opt::IRContext* ir_context, FactManager* fact_manager, + FuzzerContext* fuzzer_context, + protobufs::TransformationSequence* transformations) + : FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {} + +FuzzerPassAdjustMemoryOperandsMasks::~FuzzerPassAdjustMemoryOperandsMasks() = + default; + +void FuzzerPassAdjustMemoryOperandsMasks::Apply() { + // Consider every block in every function. + for (auto& function : *GetIRContext()->module()) { + for (auto& block : function) { + // Consider every instruction in this block, using an explicit iterator so + // that when we find an instruction of interest we can search backwards to + // create an id descriptor for it. + for (auto inst_it = block.cbegin(); inst_it != block.cend(); ++inst_it) { + if (!TransformationSetMemoryOperandsMask::IsMemoryAccess(*inst_it)) { + // We are only interested in memory access instructions. + continue; + } + + std::vector indices_of_available_masks_to_adjust; + // All memory instructions have at least one memory operands mask. + indices_of_available_masks_to_adjust.push_back(0); + // From SPIR-V 1.4 onwards, OpCopyMemory and OpCopyMemorySized have a + // second mask. + switch (inst_it->opcode()) { + case SpvOpCopyMemory: + case SpvOpCopyMemorySized: + if (TransformationSetMemoryOperandsMask:: + MultipleMemoryOperandMasksAreSupported(GetIRContext())) { + indices_of_available_masks_to_adjust.push_back(1); + } + break; + default: + break; + } + + // Consider the available masks + for (auto mask_index : indices_of_available_masks_to_adjust) { + // Randomly decide whether to adjust this mask. + if (!GetFuzzerContext()->ChoosePercentage( + GetFuzzerContext() + ->GetChanceOfAdjustingMemoryOperandsMask())) { + continue; + } + // Get the existing mask, using None if there was no mask present at + // all. + auto existing_mask_in_operand_index = + TransformationSetMemoryOperandsMask::GetInOperandIndexForMask( + *inst_it, mask_index); + auto existing_mask = + existing_mask_in_operand_index < inst_it->NumInOperands() + ? inst_it->GetSingleWordOperand( + existing_mask_in_operand_index) + : static_cast(SpvMemoryAccessMaskNone); + + // There are two things we can do to a mask: + // - add Volatile if not already present + // - toggle Nontemporal + // The following ensures that we do at least one of these + bool add_volatile = !(existing_mask & SpvMemoryAccessVolatileMask) && + GetFuzzerContext()->ChooseEven(); + bool toggle_nontemporal = + !add_volatile || GetFuzzerContext()->ChooseEven(); + + // These bitwise operations use '|' to add Volatile if desired, and + // '^' to toggle Nontemporal if desired. + uint32_t new_mask = + (existing_mask | (add_volatile ? SpvMemoryAccessVolatileMask + : SpvMemoryAccessMaskNone)) ^ + (toggle_nontemporal ? SpvMemoryAccessNontemporalMask + : SpvMemoryAccessMaskNone); + + TransformationSetMemoryOperandsMask transformation( + MakeInstructionDescriptor(block, inst_it), new_mask, mask_index); + assert( + transformation.IsApplicable(GetIRContext(), *GetFactManager()) && + "Transformation should be applicable by construction."); + transformation.Apply(GetIRContext(), GetFactManager()); + *GetTransformations()->add_transformation() = + transformation.ToMessage(); + } + } + } + } +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_memory_operands_masks.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_memory_operands_masks.h new file mode 100644 index 0000000000..c3d71185ea --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_memory_operands_masks.h @@ -0,0 +1,40 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_FUZZER_PASS_ADJUST_MEMORY_OPERANDS_MASKS_H_ +#define SOURCE_FUZZ_FUZZER_PASS_ADJUST_MEMORY_OPERANDS_MASKS_H_ + +#include "source/fuzz/fuzzer_pass.h" + +namespace spvtools { +namespace fuzz { + +// A fuzzer pass to adjust the memory operand masks in memory access +// instructions. +class FuzzerPassAdjustMemoryOperandsMasks : public FuzzerPass { + public: + FuzzerPassAdjustMemoryOperandsMasks( + opt::IRContext* ir_context, FactManager* fact_manager, + FuzzerContext* fuzzer_context, + protobufs::TransformationSequence* transformations); + + ~FuzzerPassAdjustMemoryOperandsMasks(); + + void Apply() override; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_FUZZER_PASS_ADJUST_MEMORY_OPERANDS_MASKS_H_ diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_selection_controls.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_selection_controls.cpp new file mode 100644 index 0000000000..22654f242f --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_selection_controls.cpp @@ -0,0 +1,76 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/fuzzer_pass_adjust_selection_controls.h" + +#include "source/fuzz/transformation_set_selection_control.h" + +namespace spvtools { +namespace fuzz { + +FuzzerPassAdjustSelectionControls::FuzzerPassAdjustSelectionControls( + opt::IRContext* ir_context, FactManager* fact_manager, + FuzzerContext* fuzzer_context, + protobufs::TransformationSequence* transformations) + : FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {} + +FuzzerPassAdjustSelectionControls::~FuzzerPassAdjustSelectionControls() = + default; + +void FuzzerPassAdjustSelectionControls::Apply() { + // Consider every merge instruction in the module (via looking through all + // functions and blocks). + for (auto& function : *GetIRContext()->module()) { + for (auto& block : function) { + if (auto merge_inst = block.GetMergeInst()) { + // Ignore the instruction if it is not a selection merge. + if (merge_inst->opcode() != SpvOpSelectionMerge) { + continue; + } + + // Choose randomly whether to change the selection control for this + // instruction. + if (!GetFuzzerContext()->ChoosePercentage( + GetFuzzerContext()->GetChanceOfAdjustingSelectionControl())) { + continue; + } + + // The choices to change the selection control to are the set of valid + // controls, minus the current control. + std::vector choices; + for (auto control : + {SpvSelectionControlMaskNone, SpvSelectionControlFlattenMask, + SpvSelectionControlDontFlattenMask}) { + if (control == merge_inst->GetSingleWordOperand(1)) { + continue; + } + choices.push_back(control); + } + + // Apply the transformation and add it to the output transformation + // sequence. + TransformationSetSelectionControl transformation( + block.id(), choices[GetFuzzerContext()->RandomIndex(choices)]); + assert(transformation.IsApplicable(GetIRContext(), *GetFactManager()) && + "Transformation should be applicable by construction."); + transformation.Apply(GetIRContext(), GetFactManager()); + *GetTransformations()->add_transformation() = + transformation.ToMessage(); + } + } + } +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_selection_controls.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_selection_controls.h new file mode 100644 index 0000000000..b5b255ce3e --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_adjust_selection_controls.h @@ -0,0 +1,39 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_FUZZER_PASS_ADJUST_SELECTION_CONTROLS_ +#define SOURCE_FUZZ_FUZZER_PASS_ADJUST_SELECTION_CONTROLS_ + +#include "source/fuzz/fuzzer_pass.h" + +namespace spvtools { +namespace fuzz { + +// A pass that adjusts the selection controls on OpSelectionMerge instructions. +class FuzzerPassAdjustSelectionControls : public FuzzerPass { + public: + FuzzerPassAdjustSelectionControls( + opt::IRContext* ir_context, FactManager* fact_manager, + FuzzerContext* fuzzer_context, + protobufs::TransformationSequence* transformations); + + ~FuzzerPassAdjustSelectionControls() override; + + void Apply() override; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_FUZZER_PASS_ADJUST_SELECTION_CONTROLS_ diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_apply_id_synonyms.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_apply_id_synonyms.cpp new file mode 100644 index 0000000000..6ff42ca79b --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_apply_id_synonyms.cpp @@ -0,0 +1,147 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/fuzzer_pass_apply_id_synonyms.h" + +#include "source/fuzz/data_descriptor.h" +#include "source/fuzz/fuzzer_util.h" +#include "source/fuzz/id_use_descriptor.h" +#include "source/fuzz/instruction_descriptor.h" +#include "source/fuzz/transformation_composite_extract.h" +#include "source/fuzz/transformation_replace_id_with_synonym.h" + +namespace spvtools { +namespace fuzz { + +FuzzerPassApplyIdSynonyms::FuzzerPassApplyIdSynonyms( + opt::IRContext* ir_context, FactManager* fact_manager, + FuzzerContext* fuzzer_context, + protobufs::TransformationSequence* transformations) + : FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {} + +FuzzerPassApplyIdSynonyms::~FuzzerPassApplyIdSynonyms() = default; + +void FuzzerPassApplyIdSynonyms::Apply() { + for (auto id_with_known_synonyms : + GetFactManager()->GetIdsForWhichSynonymsAreKnown(GetIRContext())) { + // Gather up all uses of |id_with_known_synonym|, and then subsequently + // iterate over these uses. We use this separation because, when + // considering a given use, we might apply a transformation that will + // invalidate the def-use manager. + std::vector> uses; + GetIRContext()->get_def_use_mgr()->ForEachUse( + id_with_known_synonyms, + [&uses](opt::Instruction* use_inst, uint32_t use_index) -> void { + uses.emplace_back( + std::pair(use_inst, use_index)); + }); + + for (auto& use : uses) { + auto use_inst = use.first; + auto use_index = use.second; + auto block_containing_use = GetIRContext()->get_instr_block(use_inst); + // The use might not be in a block; e.g. it could be a decoration. + if (!block_containing_use) { + continue; + } + if (!GetFuzzerContext()->ChoosePercentage( + GetFuzzerContext()->GetChanceOfReplacingIdWithSynonym())) { + continue; + } + // |use_index| is the absolute index of the operand. We require + // the index of the operand restricted to input operands only, so + // we subtract the number of non-input operands from |use_index|. + uint32_t use_in_operand_index = + use_index - use_inst->NumOperands() + use_inst->NumInOperands(); + if (!TransformationReplaceIdWithSynonym::UseCanBeReplacedWithSynonym( + GetIRContext(), use_inst, use_in_operand_index)) { + continue; + } + + std::vector synonyms_to_try; + for (auto& data_descriptor : GetFactManager()->GetSynonymsForId( + id_with_known_synonyms, GetIRContext())) { + protobufs::DataDescriptor descriptor_for_this_id = + MakeDataDescriptor(id_with_known_synonyms, {}); + if (DataDescriptorEquals()(data_descriptor, &descriptor_for_this_id)) { + // Exclude the fact that the id is synonymous with itself. + continue; + } + synonyms_to_try.push_back(data_descriptor); + } + while (!synonyms_to_try.empty()) { + auto synonym_index = GetFuzzerContext()->RandomIndex(synonyms_to_try); + auto synonym_to_try = synonyms_to_try[synonym_index]; + synonyms_to_try.erase(synonyms_to_try.begin() + synonym_index); + + if (synonym_to_try->index_size() > 0 && + use_inst->opcode() == SpvOpPhi) { + // We are trying to replace an operand to an OpPhi. This means + // we cannot use a composite synonym, because that requires + // extracting a component from a composite and we cannot insert + // an extract instruction before an OpPhi. + // + // TODO(afd): We could consider inserting the extract instruction + // into the relevant parent block of the OpPhi. + continue; + } + + if (!TransformationReplaceIdWithSynonym::IdsIsAvailableAtUse( + GetIRContext(), use_inst, use_in_operand_index, + synonym_to_try->object())) { + continue; + } + + // We either replace the use with an id known to be synonymous, or + // an id that will hold the result of extracting a synonym from a + // composite. + uint32_t id_with_which_to_replace_use; + if (synonym_to_try->index_size() == 0) { + id_with_which_to_replace_use = synonym_to_try->object(); + } else { + id_with_which_to_replace_use = GetFuzzerContext()->GetFreshId(); + protobufs::InstructionDescriptor instruction_to_insert_before = + MakeInstructionDescriptor(GetIRContext(), use_inst); + TransformationCompositeExtract composite_extract_transformation( + instruction_to_insert_before, id_with_which_to_replace_use, + synonym_to_try->object(), + fuzzerutil::RepeatedFieldToVector(synonym_to_try->index())); + assert(composite_extract_transformation.IsApplicable( + GetIRContext(), *GetFactManager()) && + "Transformation should be applicable by construction."); + composite_extract_transformation.Apply(GetIRContext(), + GetFactManager()); + *GetTransformations()->add_transformation() = + composite_extract_transformation.ToMessage(); + } + + TransformationReplaceIdWithSynonym replace_id_transformation( + MakeIdUseDescriptorFromUse(GetIRContext(), use_inst, + use_in_operand_index), + id_with_which_to_replace_use); + + // The transformation should be applicable by construction. + assert(replace_id_transformation.IsApplicable(GetIRContext(), + *GetFactManager())); + replace_id_transformation.Apply(GetIRContext(), GetFactManager()); + *GetTransformations()->add_transformation() = + replace_id_transformation.ToMessage(); + break; + } + } + } +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_apply_id_synonyms.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_apply_id_synonyms.h new file mode 100644 index 0000000000..1a0748eb4f --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_apply_id_synonyms.h @@ -0,0 +1,42 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_FUZZER_PASS_APPLY_ID_SYNONYMS_ +#define SOURCE_FUZZ_FUZZER_PASS_APPLY_ID_SYNONYMS_ + +#include "source/fuzz/fuzzer_pass.h" + +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace fuzz { + +// A pass that replaces ids with other ids, or accesses into structures, that +// are known to hold the same values. +class FuzzerPassApplyIdSynonyms : public FuzzerPass { + public: + FuzzerPassApplyIdSynonyms(opt::IRContext* ir_context, + FactManager* fact_manager, + FuzzerContext* fuzzer_context, + protobufs::TransformationSequence* transformations); + + ~FuzzerPassApplyIdSynonyms() override; + + void Apply() override; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_FUZZER_PASS_APPLY_ID_SYNONYMS_ diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_construct_composites.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_construct_composites.cpp new file mode 100644 index 0000000000..ff0adabcc3 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_construct_composites.cpp @@ -0,0 +1,362 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/fuzzer_pass_construct_composites.h" + +#include +#include + +#include "source/fuzz/fuzzer_util.h" +#include "source/fuzz/transformation_composite_construct.h" +#include "source/util/make_unique.h" + +namespace spvtools { +namespace fuzz { + +FuzzerPassConstructComposites::FuzzerPassConstructComposites( + opt::IRContext* ir_context, FactManager* fact_manager, + FuzzerContext* fuzzer_context, + protobufs::TransformationSequence* transformations) + : FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {} + +FuzzerPassConstructComposites::~FuzzerPassConstructComposites() = default; + +void FuzzerPassConstructComposites::Apply() { + // Gather up the ids of all composite types. + std::vector composite_type_ids; + for (auto& inst : GetIRContext()->types_values()) { + if (fuzzerutil::IsCompositeType( + GetIRContext()->get_type_mgr()->GetType(inst.result_id()))) { + composite_type_ids.push_back(inst.result_id()); + } + } + + MaybeAddTransformationBeforeEachInstruction( + [this, &composite_type_ids]( + const opt::Function& function, opt::BasicBlock* block, + opt::BasicBlock::iterator inst_it, + const protobufs::InstructionDescriptor& instruction_descriptor) + -> void { + // Check whether it is legitimate to insert a composite construction + // before the instruction. + if (!fuzzerutil::CanInsertOpcodeBeforeInstruction( + SpvOpCompositeConstruct, inst_it)) { + return; + } + + // Randomly decide whether to try inserting an object copy here. + if (!GetFuzzerContext()->ChoosePercentage( + GetFuzzerContext()->GetChanceOfConstructingComposite())) { + return; + } + + // For each instruction that is available at this program point (i.e. an + // instruction that is global or whose definition strictly dominates the + // program point) and suitable for making a synonym of, associate it + // with the id of its result type. + TypeIdToInstructions type_id_to_available_instructions; + for (auto instruction : FindAvailableInstructions( + function, block, inst_it, fuzzerutil::CanMakeSynonymOf)) { + RecordAvailableInstruction(instruction, + &type_id_to_available_instructions); + } + + // At this point, |composite_type_ids| captures all the composite types + // we could try to create, while |type_id_to_available_instructions| + // captures all the available result ids we might use, organized by + // type. + + // Now we try to find a composite that we can construct. We might not + // manage, if there is a paucity of available ingredients in the module + // (e.g. if our only available composite was a boolean vector and we had + // no instructions generating boolean result types available). + // + // If we succeed, |chosen_composite_type| will end up being non-zero, + // and |constructor_arguments| will end up giving us result ids suitable + // for constructing a composite of that type. Otherwise these variables + // will remain 0 and null respectively. + uint32_t chosen_composite_type = 0; + std::unique_ptr> constructor_arguments = nullptr; + + // Initially, all composite type ids are available for us to try. Keep + // trying until we run out of options. + auto composites_to_try_constructing = composite_type_ids; + while (!composites_to_try_constructing.empty()) { + // Remove a composite type from the composite types left for us to + // try. + auto index = + GetFuzzerContext()->RandomIndex(composites_to_try_constructing); + auto next_composite_to_try_constructing = + composites_to_try_constructing[index]; + composites_to_try_constructing.erase( + composites_to_try_constructing.begin() + index); + + // Now try to construct a composite of this type, using an appropriate + // helper method depending on the kind of composite type. + auto composite_type = GetIRContext()->get_type_mgr()->GetType( + next_composite_to_try_constructing); + if (auto array_type = composite_type->AsArray()) { + constructor_arguments = TryConstructingArrayComposite( + *array_type, type_id_to_available_instructions); + } else if (auto matrix_type = composite_type->AsMatrix()) { + constructor_arguments = TryConstructingMatrixComposite( + *matrix_type, type_id_to_available_instructions); + } else if (auto struct_type = composite_type->AsStruct()) { + constructor_arguments = TryConstructingStructComposite( + *struct_type, type_id_to_available_instructions); + } else { + auto vector_type = composite_type->AsVector(); + assert(vector_type && + "The space of possible composite types should be covered by " + "the above cases."); + constructor_arguments = TryConstructingVectorComposite( + *vector_type, type_id_to_available_instructions); + } + if (constructor_arguments != nullptr) { + // We succeeded! Note the composite type we finally settled on, and + // exit from the loop. + chosen_composite_type = next_composite_to_try_constructing; + break; + } + } + + if (!chosen_composite_type) { + // We did not manage to make a composite; return 0 to indicate that no + // instructions were added. + assert(constructor_arguments == nullptr); + return; + } + assert(constructor_arguments != nullptr); + + // Make and apply a transformation. + TransformationCompositeConstruct transformation( + chosen_composite_type, *constructor_arguments, + instruction_descriptor, GetFuzzerContext()->GetFreshId()); + assert(transformation.IsApplicable(GetIRContext(), *GetFactManager()) && + "This transformation should be applicable by construction."); + transformation.Apply(GetIRContext(), GetFactManager()); + *GetTransformations()->add_transformation() = + transformation.ToMessage(); + }); +} + +void FuzzerPassConstructComposites::RecordAvailableInstruction( + opt::Instruction* inst, + TypeIdToInstructions* type_id_to_available_instructions) { + if (type_id_to_available_instructions->count(inst->type_id()) == 0) { + (*type_id_to_available_instructions)[inst->type_id()] = {}; + } + type_id_to_available_instructions->at(inst->type_id()).push_back(inst); +} + +std::unique_ptr> +FuzzerPassConstructComposites::TryConstructingArrayComposite( + const opt::analysis::Array& array_type, + const TypeIdToInstructions& type_id_to_available_instructions) { + // At present we assume arrays have a constant size. + assert(array_type.length_info().words.size() == 2); + assert(array_type.length_info().words[0] == + opt::analysis::Array::LengthInfo::kConstant); + + auto result = MakeUnique>(); + + // Get the element type for the array. + auto element_type_id = + GetIRContext()->get_type_mgr()->GetId(array_type.element_type()); + + // Get all instructions at our disposal that compute something of this element + // type. + auto available_instructions = + type_id_to_available_instructions.find(element_type_id); + + if (available_instructions == type_id_to_available_instructions.cend()) { + // If there are not any instructions available that compute the element type + // of the array then we are not in a position to construct a composite with + // this array type. + return nullptr; + } + for (uint32_t index = 0; index < array_type.length_info().words[1]; index++) { + result->push_back(available_instructions + ->second[GetFuzzerContext()->RandomIndex( + available_instructions->second)] + ->result_id()); + } + return result; +} + +std::unique_ptr> +FuzzerPassConstructComposites::TryConstructingMatrixComposite( + const opt::analysis::Matrix& matrix_type, + const TypeIdToInstructions& type_id_to_available_instructions) { + auto result = MakeUnique>(); + + // Get the element type for the matrix. + auto element_type_id = + GetIRContext()->get_type_mgr()->GetId(matrix_type.element_type()); + + // Get all instructions at our disposal that compute something of this element + // type. + auto available_instructions = + type_id_to_available_instructions.find(element_type_id); + + if (available_instructions == type_id_to_available_instructions.cend()) { + // If there are not any instructions available that compute the element type + // of the matrix then we are not in a position to construct a composite with + // this matrix type. + return nullptr; + } + for (uint32_t index = 0; index < matrix_type.element_count(); index++) { + result->push_back(available_instructions + ->second[GetFuzzerContext()->RandomIndex( + available_instructions->second)] + ->result_id()); + } + return result; +} + +std::unique_ptr> +FuzzerPassConstructComposites::TryConstructingStructComposite( + const opt::analysis::Struct& struct_type, + const TypeIdToInstructions& type_id_to_available_instructions) { + auto result = MakeUnique>(); + // Consider the type of each field of the struct. + for (auto element_type : struct_type.element_types()) { + auto element_type_id = GetIRContext()->get_type_mgr()->GetId(element_type); + // Find the instructions at our disposal that compute something of the field + // type. + auto available_instructions = + type_id_to_available_instructions.find(element_type_id); + if (available_instructions == type_id_to_available_instructions.cend()) { + // If there are no such instructions, we cannot construct a composite of + // this struct type. + return nullptr; + } + result->push_back(available_instructions + ->second[GetFuzzerContext()->RandomIndex( + available_instructions->second)] + ->result_id()); + } + return result; +} + +std::unique_ptr> +FuzzerPassConstructComposites::TryConstructingVectorComposite( + const opt::analysis::Vector& vector_type, + const TypeIdToInstructions& type_id_to_available_instructions) { + // Get details of the type underlying the vector, and the width of the vector, + // for convenience. + auto element_type = vector_type.element_type(); + auto element_count = vector_type.element_count(); + + // Collect a mapping, from type id to width, for scalar/vector types that are + // smaller in width than |vector_type|, but that have the same underlying + // type. For example, if |vector_type| is vec4, the mapping will be: + // { float -> 1, vec2 -> 2, vec3 -> 3 } + // The mapping will have missing entries if some of these types do not exist. + + std::map smaller_vector_type_id_to_width; + // Add the underlying type. This id must exist, in order for |vector_type| to + // exist. + auto scalar_type_id = GetIRContext()->get_type_mgr()->GetId(element_type); + smaller_vector_type_id_to_width[scalar_type_id] = 1; + + // Now add every vector type with width at least 2, and less than the width of + // |vector_type|. + for (uint32_t width = 2; width < element_count; width++) { + opt::analysis::Vector smaller_vector_type(vector_type.element_type(), + width); + auto smaller_vector_type_id = + GetIRContext()->get_type_mgr()->GetId(&smaller_vector_type); + // We might find that there is no declared type of this smaller width. + // For example, a module can declare vec4 without having declared vec2 or + // vec3. + if (smaller_vector_type_id) { + smaller_vector_type_id_to_width[smaller_vector_type_id] = width; + } + } + + // Now we know the types that are available to us, we set about populating a + // vector of the right length. We do this by deciding, with no order in mind, + // which instructions we will use to populate the vector, and subsequently + // randomly choosing an order. This is to avoid biasing construction of + // vectors with smaller vectors to the left and scalars to the right. That is + // a concern because, e.g. in the case of populating a vec4, if we populate + // the constructor instructions left-to-right, we can always choose a vec3 to + // construct the first three elements, but can only choose a vec3 to construct + // the last three elements if we chose a float to construct the first element + // (otherwise there will not be space left for a vec3). + + uint32_t vector_slots_used = 0; + // The instructions we will use to construct the vector, in no particular + // order at this stage. + std::vector instructions_to_use; + + while (vector_slots_used < vector_type.element_count()) { + std::vector instructions_to_choose_from; + for (auto& entry : smaller_vector_type_id_to_width) { + if (entry.second > + std::min(vector_type.element_count() - 1, + vector_type.element_count() - vector_slots_used)) { + continue; + } + auto available_instructions = + type_id_to_available_instructions.find(entry.first); + if (available_instructions == type_id_to_available_instructions.cend()) { + continue; + } + instructions_to_choose_from.insert(instructions_to_choose_from.end(), + available_instructions->second.begin(), + available_instructions->second.end()); + } + if (instructions_to_choose_from.empty()) { + // We may get unlucky and find that there are not any instructions to + // choose from. In this case we give up constructing a composite of this + // vector type. It might be that we could construct the composite in + // another manner, so we could opt to retry a few times here, but it is + // simpler to just give up on the basis that this will not happen + // frequently. + return nullptr; + } + auto instruction_to_use = + instructions_to_choose_from[GetFuzzerContext()->RandomIndex( + instructions_to_choose_from)]; + instructions_to_use.push_back(instruction_to_use); + auto chosen_type = + GetIRContext()->get_type_mgr()->GetType(instruction_to_use->type_id()); + if (chosen_type->AsVector()) { + assert(chosen_type->AsVector()->element_type() == element_type); + assert(chosen_type->AsVector()->element_count() < element_count); + assert(chosen_type->AsVector()->element_count() <= + element_count - vector_slots_used); + vector_slots_used += chosen_type->AsVector()->element_count(); + } else { + assert(chosen_type == element_type); + vector_slots_used += 1; + } + } + assert(vector_slots_used == vector_type.element_count()); + + auto result = MakeUnique>(); + std::vector operands; + while (!instructions_to_use.empty()) { + auto index = GetFuzzerContext()->RandomIndex(instructions_to_use); + result->push_back(instructions_to_use[index]->result_id()); + instructions_to_use.erase(instructions_to_use.begin() + index); + } + assert(result->size() > 1); + return result; +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_construct_composites.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_construct_composites.h new file mode 100644 index 0000000000..99ef31ff96 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_construct_composites.h @@ -0,0 +1,79 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_FUZZER_PASS_CONSTRUCT_COMPOSITES_H_ +#define SOURCE_FUZZ_FUZZER_PASS_CONSTRUCT_COMPOSITES_H_ + +#include "source/fuzz/fuzzer_pass.h" + +#include +#include + +namespace spvtools { +namespace fuzz { + +// A fuzzer pass for constructing composite objects from smaller objects. +class FuzzerPassConstructComposites : public FuzzerPass { + public: + FuzzerPassConstructComposites( + opt::IRContext* ir_context, FactManager* fact_manager, + FuzzerContext* fuzzer_context, + protobufs::TransformationSequence* transformations); + + ~FuzzerPassConstructComposites(); + + void Apply() override; + + private: + // Used to map a type id to relevant instructions whose result type matches + // the type id. + typedef std::map> + TypeIdToInstructions; + + // Considers all instructions that are available at |inst| - instructions + // whose results could be packed into a composite - and updates + // |type_id_to_available_instructions| so that each such instruction is + // associated with its the id of its result type. + void RecordAvailableInstruction( + opt::Instruction* inst, + TypeIdToInstructions* type_id_to_available_instructions); + + // Attempts to find suitable instruction result ids from the values of + // |type_id_to_available_instructions| that would allow a composite of type + // |array_type| to be constructed. Returns said ids if they can be found. + // Returns |nullptr| otherwise. + std::unique_ptr> TryConstructingArrayComposite( + const opt::analysis::Array& array_type, + const TypeIdToInstructions& type_id_to_available_instructions); + + // Similar to TryConstructingArrayComposite, but for matrices. + std::unique_ptr> TryConstructingMatrixComposite( + const opt::analysis::Matrix& matrix_type, + const TypeIdToInstructions& type_id_to_available_instructions); + + // Similar to TryConstructingArrayComposite, but for structs. + std::unique_ptr> TryConstructingStructComposite( + const opt::analysis::Struct& struct_type, + const TypeIdToInstructions& type_id_to_available_instructions); + + // Similar to TryConstructingArrayComposite, but for vectors. + std::unique_ptr> TryConstructingVectorComposite( + const opt::analysis::Vector& vector_type, + const TypeIdToInstructions& type_id_to_available_instructions); +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_FUZZER_PASS_CONSTRUCT_COMPOSITES_H_ diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_copy_objects.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_copy_objects.cpp new file mode 100644 index 0000000000..35b15a38a3 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_copy_objects.cpp @@ -0,0 +1,80 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/fuzzer_pass_copy_objects.h" + +#include "source/fuzz/fuzzer_util.h" +#include "source/fuzz/transformation_copy_object.h" + +namespace spvtools { +namespace fuzz { + +FuzzerPassCopyObjects::FuzzerPassCopyObjects( + opt::IRContext* ir_context, FactManager* fact_manager, + FuzzerContext* fuzzer_context, + protobufs::TransformationSequence* transformations) + : FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {} + +FuzzerPassCopyObjects::~FuzzerPassCopyObjects() = default; + +void FuzzerPassCopyObjects::Apply() { + MaybeAddTransformationBeforeEachInstruction( + [this](const opt::Function& function, opt::BasicBlock* block, + opt::BasicBlock::iterator inst_it, + const protobufs::InstructionDescriptor& instruction_descriptor) + -> void { + assert(inst_it->opcode() == + instruction_descriptor.target_instruction_opcode() && + "The opcode of the instruction we might insert before must be " + "the same as the opcode in the descriptor for the instruction"); + + // Check whether it is legitimate to insert a copy before this + // instruction. + if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpCopyObject, + inst_it)) { + return; + } + + // Randomly decide whether to try inserting an object copy here. + if (!GetFuzzerContext()->ChoosePercentage( + GetFuzzerContext()->GetChanceOfCopyingObject())) { + return; + } + + std::vector relevant_instructions = + FindAvailableInstructions(function, block, inst_it, + fuzzerutil::CanMakeSynonymOf); + + // At this point, |relevant_instructions| contains all the instructions + // we might think of copying. + if (relevant_instructions.empty()) { + return; + } + + // Choose a copyable instruction at random, and create and apply an + // object copying transformation based on it. + uint32_t index = GetFuzzerContext()->RandomIndex(relevant_instructions); + TransformationCopyObject transformation( + relevant_instructions[index]->result_id(), instruction_descriptor, + GetFuzzerContext()->GetFreshId()); + assert(transformation.IsApplicable(GetIRContext(), *GetFactManager()) && + "This transformation should be applicable by construction."); + transformation.Apply(GetIRContext(), GetFactManager()); + *GetTransformations()->add_transformation() = + transformation.ToMessage(); + }); +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_copy_objects.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_copy_objects.h new file mode 100644 index 0000000000..5419459e9f --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_copy_objects.h @@ -0,0 +1,38 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_FUZZER_PASS_COPY_OBJECTS_H_ +#define SOURCE_FUZZ_FUZZER_PASS_COPY_OBJECTS_H_ + +#include "source/fuzz/fuzzer_pass.h" + +namespace spvtools { +namespace fuzz { + +// A fuzzer pass for adding adding copies of objects to the module. +class FuzzerPassCopyObjects : public FuzzerPass { + public: + FuzzerPassCopyObjects(opt::IRContext* ir_context, FactManager* fact_manager, + FuzzerContext* fuzzer_context, + protobufs::TransformationSequence* transformations); + + ~FuzzerPassCopyObjects(); + + void Apply() override; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_FUZZER_PASS_COPY_OBJECTS_H_ diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_donate_modules.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_donate_modules.cpp new file mode 100644 index 0000000000..75530b10e3 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_donate_modules.cpp @@ -0,0 +1,748 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/fuzzer_pass_donate_modules.h" + +#include +#include +#include + +#include "source/fuzz/instruction_message.h" +#include "source/fuzz/transformation_add_constant_boolean.h" +#include "source/fuzz/transformation_add_constant_composite.h" +#include "source/fuzz/transformation_add_constant_scalar.h" +#include "source/fuzz/transformation_add_function.h" +#include "source/fuzz/transformation_add_global_undef.h" +#include "source/fuzz/transformation_add_global_variable.h" +#include "source/fuzz/transformation_add_type_array.h" +#include "source/fuzz/transformation_add_type_boolean.h" +#include "source/fuzz/transformation_add_type_float.h" +#include "source/fuzz/transformation_add_type_function.h" +#include "source/fuzz/transformation_add_type_int.h" +#include "source/fuzz/transformation_add_type_matrix.h" +#include "source/fuzz/transformation_add_type_pointer.h" +#include "source/fuzz/transformation_add_type_struct.h" +#include "source/fuzz/transformation_add_type_vector.h" + +namespace spvtools { +namespace fuzz { + +FuzzerPassDonateModules::FuzzerPassDonateModules( + opt::IRContext* ir_context, FactManager* fact_manager, + FuzzerContext* fuzzer_context, + protobufs::TransformationSequence* transformations, + const std::vector& donor_suppliers) + : FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations), + donor_suppliers_(donor_suppliers) {} + +FuzzerPassDonateModules::~FuzzerPassDonateModules() = default; + +void FuzzerPassDonateModules::Apply() { + // If there are no donor suppliers, this fuzzer pass is a no-op. + if (donor_suppliers_.empty()) { + return; + } + + // Donate at least one module, and probabilistically decide when to stop + // donating modules. + do { + // Choose a donor supplier at random, and get the module that it provides. + std::unique_ptr donor_ir_context = donor_suppliers_.at( + GetFuzzerContext()->RandomIndex(donor_suppliers_))(); + assert(donor_ir_context != nullptr && "Supplying of donor failed"); + // Donate the supplied module. + // + // Randomly decide whether to make the module livesafe (see + // FactFunctionIsLivesafe); doing so allows it to be used for live code + // injection but restricts its behaviour to allow this, and means that its + // functions cannot be transformed as if they were arbitrary dead code. + bool make_livesafe = GetFuzzerContext()->ChoosePercentage( + GetFuzzerContext()->ChanceOfMakingDonorLivesafe()); + DonateSingleModule(donor_ir_context.get(), make_livesafe); + } while (GetFuzzerContext()->ChoosePercentage( + GetFuzzerContext()->GetChanceOfDonatingAdditionalModule())); +} + +void FuzzerPassDonateModules::DonateSingleModule( + opt::IRContext* donor_ir_context, bool make_livesafe) { + // The ids used by the donor module may very well clash with ids defined in + // the recipient module. Furthermore, some instructions defined in the donor + // module will be equivalent to instructions defined in the recipient module, + // and it is not always legal to re-declare equivalent instructions. For + // example, OpTypeVoid cannot be declared twice. + // + // To handle this, we maintain a mapping from an id used in the donor module + // to the corresponding id that will be used by the donated code when it + // appears in the recipient module. + // + // This mapping is populated in two ways: + // (1) by mapping a donor instruction's result id to the id of some equivalent + // existing instruction in the recipient (e.g. this has to be done for + // OpTypeVoid) + // (2) by mapping a donor instruction's result id to a freshly chosen id that + // is guaranteed to be different from any id already used by the recipient + // (or from any id already chosen to handle a previous donor id) + std::map original_id_to_donated_id; + + HandleExternalInstructionImports(donor_ir_context, + &original_id_to_donated_id); + HandleTypesAndValues(donor_ir_context, &original_id_to_donated_id); + HandleFunctions(donor_ir_context, &original_id_to_donated_id, make_livesafe); + + // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3115) Handle some + // kinds of decoration. +} + +SpvStorageClass FuzzerPassDonateModules::AdaptStorageClass( + SpvStorageClass donor_storage_class) { + switch (donor_storage_class) { + case SpvStorageClassFunction: + case SpvStorageClassPrivate: + // We leave these alone + return donor_storage_class; + case SpvStorageClassInput: + case SpvStorageClassOutput: + case SpvStorageClassUniform: + case SpvStorageClassUniformConstant: + case SpvStorageClassPushConstant: + // We change these to Private + return SpvStorageClassPrivate; + default: + // Handle other cases on demand. + assert(false && "Currently unsupported storage class."); + return SpvStorageClassMax; + } +} + +void FuzzerPassDonateModules::HandleExternalInstructionImports( + opt::IRContext* donor_ir_context, + std::map* original_id_to_donated_id) { + // Consider every external instruction set import in the donor module. + for (auto& donor_import : donor_ir_context->module()->ext_inst_imports()) { + const auto& donor_import_name_words = donor_import.GetInOperand(0).words; + // Look for an identical import in the recipient module. + for (auto& existing_import : GetIRContext()->module()->ext_inst_imports()) { + const auto& existing_import_name_words = + existing_import.GetInOperand(0).words; + if (donor_import_name_words == existing_import_name_words) { + // A matching import has found. Map the result id for the donor import + // to the id of the existing import, so that when donor instructions + // rely on the import they will be rewritten to use the existing import. + original_id_to_donated_id->insert( + {donor_import.result_id(), existing_import.result_id()}); + break; + } + } + // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3116): At present + // we do not handle donation of instruction imports, i.e. we do not allow + // the donor to import instruction sets that the recipient did not already + // import. It might be a good idea to allow this, but it requires some + // thought. + assert(original_id_to_donated_id->count(donor_import.result_id()) && + "Donation of imports is not yet supported."); + } +} + +void FuzzerPassDonateModules::HandleTypesAndValues( + opt::IRContext* donor_ir_context, + std::map* original_id_to_donated_id) { + // Consider every type/global/constant/undef in the module. + for (auto& type_or_value : donor_ir_context->module()->types_values()) { + // Each such instruction generates a result id, and as part of donation we + // need to associate the donor's result id with a new result id. That new + // result id will either be the id of some existing instruction, or a fresh + // id. This variable captures it. + uint32_t new_result_id; + + // Decide how to handle each kind of instruction on a case-by-case basis. + // + // Because the donor module is required to be valid, when we encounter a + // type comprised of component types (e.g. an aggregate or pointer), we know + // that its component types will have been considered previously, and that + // |original_id_to_donated_id| will already contain an entry for them. + switch (type_or_value.opcode()) { + case SpvOpTypeVoid: { + // Void has to exist already in order for us to have an entry point. + // Get the existing id of void. + opt::analysis::Void void_type; + new_result_id = GetIRContext()->get_type_mgr()->GetId(&void_type); + assert(new_result_id && + "The module being transformed will always have 'void' type " + "declared."); + } break; + case SpvOpTypeBool: { + // Bool cannot be declared multiple times, so use its existing id if + // present, or add a declaration of Bool with a fresh id if not. + opt::analysis::Bool bool_type; + auto bool_type_id = GetIRContext()->get_type_mgr()->GetId(&bool_type); + if (bool_type_id) { + new_result_id = bool_type_id; + } else { + new_result_id = GetFuzzerContext()->GetFreshId(); + ApplyTransformation(TransformationAddTypeBoolean(new_result_id)); + } + } break; + case SpvOpTypeInt: { + // Int cannot be declared multiple times with the same width and + // signedness, so check whether an existing identical Int type is + // present and use its id if so. Otherwise add a declaration of the + // Int type used by the donor, with a fresh id. + const uint32_t width = type_or_value.GetSingleWordInOperand(0); + const bool is_signed = + static_cast(type_or_value.GetSingleWordInOperand(1)); + opt::analysis::Integer int_type(width, is_signed); + auto int_type_id = GetIRContext()->get_type_mgr()->GetId(&int_type); + if (int_type_id) { + new_result_id = int_type_id; + } else { + new_result_id = GetFuzzerContext()->GetFreshId(); + ApplyTransformation( + TransformationAddTypeInt(new_result_id, width, is_signed)); + } + } break; + case SpvOpTypeFloat: { + // Similar to SpvOpTypeInt. + const uint32_t width = type_or_value.GetSingleWordInOperand(0); + opt::analysis::Float float_type(width); + auto float_type_id = GetIRContext()->get_type_mgr()->GetId(&float_type); + if (float_type_id) { + new_result_id = float_type_id; + } else { + new_result_id = GetFuzzerContext()->GetFreshId(); + ApplyTransformation(TransformationAddTypeFloat(new_result_id, width)); + } + } break; + case SpvOpTypeVector: { + // It is not legal to have two Vector type declarations with identical + // element types and element counts, so check whether an existing + // identical Vector type is present and use its id if so. Otherwise add + // a declaration of the Vector type used by the donor, with a fresh id. + + // When considering the vector's component type id, we look up the id + // use in the donor to find the id to which this has been remapped. + uint32_t component_type_id = original_id_to_donated_id->at( + type_or_value.GetSingleWordInOperand(0)); + auto component_type = + GetIRContext()->get_type_mgr()->GetType(component_type_id); + assert(component_type && "The base type should be registered."); + auto component_count = type_or_value.GetSingleWordInOperand(1); + opt::analysis::Vector vector_type(component_type, component_count); + auto vector_type_id = + GetIRContext()->get_type_mgr()->GetId(&vector_type); + if (vector_type_id) { + new_result_id = vector_type_id; + } else { + new_result_id = GetFuzzerContext()->GetFreshId(); + ApplyTransformation(TransformationAddTypeVector( + new_result_id, component_type_id, component_count)); + } + } break; + case SpvOpTypeMatrix: { + // Similar to SpvOpTypeVector. + uint32_t column_type_id = original_id_to_donated_id->at( + type_or_value.GetSingleWordInOperand(0)); + auto column_type = + GetIRContext()->get_type_mgr()->GetType(column_type_id); + assert(column_type && column_type->AsVector() && + "The column type should be a registered vector type."); + auto column_count = type_or_value.GetSingleWordInOperand(1); + opt::analysis::Matrix matrix_type(column_type, column_count); + auto matrix_type_id = + GetIRContext()->get_type_mgr()->GetId(&matrix_type); + if (matrix_type_id) { + new_result_id = matrix_type_id; + } else { + new_result_id = GetFuzzerContext()->GetFreshId(); + ApplyTransformation(TransformationAddTypeMatrix( + new_result_id, column_type_id, column_count)); + } + + } break; + case SpvOpTypeArray: { + // It is OK to have multiple structurally identical array types, so + // we go ahead and add a remapped version of the type declared by the + // donor. + new_result_id = GetFuzzerContext()->GetFreshId(); + ApplyTransformation(TransformationAddTypeArray( + new_result_id, + original_id_to_donated_id->at( + type_or_value.GetSingleWordInOperand(0)), + original_id_to_donated_id->at( + type_or_value.GetSingleWordInOperand(1)))); + } break; + case SpvOpTypeStruct: { + // Similar to SpvOpTypeArray. + new_result_id = GetFuzzerContext()->GetFreshId(); + std::vector member_type_ids; + type_or_value.ForEachInId( + [&member_type_ids, + &original_id_to_donated_id](const uint32_t* component_type_id) { + member_type_ids.push_back( + original_id_to_donated_id->at(*component_type_id)); + }); + ApplyTransformation( + TransformationAddTypeStruct(new_result_id, member_type_ids)); + } break; + case SpvOpTypePointer: { + // Similar to SpvOpTypeArray. + new_result_id = GetFuzzerContext()->GetFreshId(); + ApplyTransformation(TransformationAddTypePointer( + new_result_id, + AdaptStorageClass(static_cast( + type_or_value.GetSingleWordInOperand(0))), + original_id_to_donated_id->at( + type_or_value.GetSingleWordInOperand(1)))); + } break; + case SpvOpTypeFunction: { + // It is not OK to have multiple function types that use identical ids + // for their return and parameter types. We thus go through all + // existing function types to look for a match. We do not use the + // type manager here because we want to regard two function types that + // are structurally identical but that differ with respect to the + // actual ids used for pointer types as different. + // + // Example: + // + // %1 = OpTypeVoid + // %2 = OpTypeInt 32 0 + // %3 = OpTypePointer Function %2 + // %4 = OpTypePointer Function %2 + // %5 = OpTypeFunction %1 %3 + // %6 = OpTypeFunction %1 %4 + // + // We regard %5 and %6 as distinct function types here, even though + // they both have the form "uint32* -> void" + + std::vector return_and_parameter_types; + for (uint32_t i = 0; i < type_or_value.NumInOperands(); i++) { + return_and_parameter_types.push_back(original_id_to_donated_id->at( + type_or_value.GetSingleWordInOperand(i))); + } + uint32_t existing_function_id = fuzzerutil::FindFunctionType( + GetIRContext(), return_and_parameter_types); + if (existing_function_id) { + new_result_id = existing_function_id; + } else { + // No match was found, so add a remapped version of the function type + // to the module, with a fresh id. + new_result_id = GetFuzzerContext()->GetFreshId(); + std::vector argument_type_ids; + for (uint32_t i = 1; i < type_or_value.NumInOperands(); i++) { + argument_type_ids.push_back(original_id_to_donated_id->at( + type_or_value.GetSingleWordInOperand(i))); + } + ApplyTransformation(TransformationAddTypeFunction( + new_result_id, + original_id_to_donated_id->at( + type_or_value.GetSingleWordInOperand(0)), + argument_type_ids)); + } + } break; + case SpvOpConstantTrue: + case SpvOpConstantFalse: { + // It is OK to have duplicate definitions of True and False, so add + // these to the module, using a remapped Bool type. + new_result_id = GetFuzzerContext()->GetFreshId(); + ApplyTransformation(TransformationAddConstantBoolean( + new_result_id, type_or_value.opcode() == SpvOpConstantTrue)); + } break; + case SpvOpConstant: { + // It is OK to have duplicate constant definitions, so add this to the + // module using a remapped result type. + new_result_id = GetFuzzerContext()->GetFreshId(); + std::vector data_words; + type_or_value.ForEachInOperand( + [&data_words](const uint32_t* in_operand) { + data_words.push_back(*in_operand); + }); + ApplyTransformation(TransformationAddConstantScalar( + new_result_id, + original_id_to_donated_id->at(type_or_value.type_id()), + data_words)); + } break; + case SpvOpConstantComposite: { + // It is OK to have duplicate constant composite definitions, so add + // this to the module using remapped versions of all consituent ids and + // the result type. + new_result_id = GetFuzzerContext()->GetFreshId(); + std::vector constituent_ids; + type_or_value.ForEachInId( + [&constituent_ids, + &original_id_to_donated_id](const uint32_t* constituent_id) { + constituent_ids.push_back( + original_id_to_donated_id->at(*constituent_id)); + }); + ApplyTransformation(TransformationAddConstantComposite( + new_result_id, + original_id_to_donated_id->at(type_or_value.type_id()), + constituent_ids)); + } break; + case SpvOpVariable: { + // This is a global variable that could have one of various storage + // classes. However, we change all global variable pointer storage + // classes (such as Uniform, Input and Output) to private when donating + // pointer types. Thus this variable's pointer type is guaranteed to + // have storage class private. As a result, we simply add a Private + // storage class global variable, using remapped versions of the result + // type and initializer ids for the global variable in the donor. + // + // We regard the added variable as having an arbitrary value. This + // means that future passes can add stores to the variable in any + // way they wish, and pass them as pointer parameters to functions + // without worrying about whether their data might get modified. + new_result_id = GetFuzzerContext()->GetFreshId(); + ApplyTransformation(TransformationAddGlobalVariable( + new_result_id, + original_id_to_donated_id->at(type_or_value.type_id()), + type_or_value.NumInOperands() == 1 + ? 0 + : original_id_to_donated_id->at( + type_or_value.GetSingleWordInOperand(1)), + true)); + } break; + case SpvOpUndef: { + // It is fine to have multiple Undef instructions of the same type, so + // we just add this to the recipient module. + new_result_id = GetFuzzerContext()->GetFreshId(); + ApplyTransformation(TransformationAddGlobalUndef( + new_result_id, + original_id_to_donated_id->at(type_or_value.type_id()))); + } break; + default: { + assert(0 && "Unknown type/value."); + new_result_id = 0; + } break; + } + // Update the id mapping to associate the instruction's result id with its + // corresponding id in the recipient. + original_id_to_donated_id->insert( + {type_or_value.result_id(), new_result_id}); + } +} + +void FuzzerPassDonateModules::HandleFunctions( + opt::IRContext* donor_ir_context, + std::map* original_id_to_donated_id, + bool make_livesafe) { + // Get the ids of functions in the donor module, topologically sorted + // according to the donor's call graph. + auto topological_order = + GetFunctionsInCallGraphTopologicalOrder(donor_ir_context); + + // Donate the functions in reverse topological order. This ensures that a + // function gets donated before any function that depends on it. This allows + // donation of the functions to be separated into a number of transformations, + // each adding one function, such that every prefix of transformations leaves + // the module valid. + for (auto function_id = topological_order.rbegin(); + function_id != topological_order.rend(); ++function_id) { + // Find the function to be donated. + opt::Function* function_to_donate = nullptr; + for (auto& function : *donor_ir_context->module()) { + if (function.result_id() == *function_id) { + function_to_donate = &function; + break; + } + } + assert(function_to_donate && "Function to be donated was not found."); + + // We will collect up protobuf messages representing the donor function's + // instructions here, and use them to create an AddFunction transformation. + std::vector donated_instructions; + + // Scan through the function, remapping each result id that it generates to + // a fresh id. This is necessary because functions include forward + // references, e.g. to labels. + function_to_donate->ForEachInst([this, &original_id_to_donated_id]( + const opt::Instruction* instruction) { + if (instruction->result_id()) { + original_id_to_donated_id->insert( + {instruction->result_id(), GetFuzzerContext()->GetFreshId()}); + } + }); + + // Consider every instruction of the donor function. + function_to_donate->ForEachInst( + [&donated_instructions, + &original_id_to_donated_id](const opt::Instruction* instruction) { + // Get the instruction's input operands into donation-ready form, + // remapping any id uses in the process. + opt::Instruction::OperandList input_operands; + + // Consider each input operand in turn. + for (uint32_t in_operand_index = 0; + in_operand_index < instruction->NumInOperands(); + in_operand_index++) { + std::vector operand_data; + const opt::Operand& in_operand = + instruction->GetInOperand(in_operand_index); + switch (in_operand.type) { + case SPV_OPERAND_TYPE_ID: + case SPV_OPERAND_TYPE_TYPE_ID: + case SPV_OPERAND_TYPE_RESULT_ID: + case SPV_OPERAND_TYPE_MEMORY_SEMANTICS_ID: + case SPV_OPERAND_TYPE_SCOPE_ID: + // This is an id operand - it consists of a single word of data, + // which needs to be remapped so that it is replaced with the + // donated form of the id. + operand_data.push_back( + original_id_to_donated_id->at(in_operand.words[0])); + break; + default: + // For non-id operands, we just add each of the data words. + for (auto word : in_operand.words) { + operand_data.push_back(word); + } + break; + } + input_operands.push_back({in_operand.type, operand_data}); + } + // Remap the result type and result id (if present) of the + // instruction, and turn it into a protobuf message. + donated_instructions.push_back(MakeInstructionMessage( + instruction->opcode(), + instruction->type_id() + ? original_id_to_donated_id->at(instruction->type_id()) + : 0, + instruction->result_id() + ? original_id_to_donated_id->at(instruction->result_id()) + : 0, + input_operands)); + }); + + if (make_livesafe) { + // Various types and constants must be in place for a function to be made + // live-safe. Add them if not already present. + FindOrCreateBoolType(); // Needed for comparisons + FindOrCreatePointerTo32BitIntegerType( + false, SpvStorageClassFunction); // Needed for adding loop limiters + FindOrCreate32BitIntegerConstant( + 0, false); // Needed for initializing loop limiters + FindOrCreate32BitIntegerConstant( + 1, false); // Needed for incrementing loop limiters + + // Get a fresh id for the variable that will be used as a loop limiter. + const uint32_t loop_limiter_variable_id = + GetFuzzerContext()->GetFreshId(); + // Choose a random loop limit, and add the required constant to the + // module if not already there. + const uint32_t loop_limit = FindOrCreate32BitIntegerConstant( + GetFuzzerContext()->GetRandomLoopLimit(), false); + + // Consider every loop header in the function to donate, and create a + // structure capturing the ids to be used for manipulating the loop + // limiter each time the loop is iterated. + std::vector loop_limiters; + for (auto& block : *function_to_donate) { + if (block.IsLoopHeader()) { + protobufs::LoopLimiterInfo loop_limiter; + // Grab the loop header's id, mapped to its donated value. + loop_limiter.set_loop_header_id( + original_id_to_donated_id->at(block.id())); + // Get fresh ids that will be used to load the loop limiter, increment + // it, compare it with the loop limit, and an id for a new block that + // will contain the loop's original terminator. + loop_limiter.set_load_id(GetFuzzerContext()->GetFreshId()); + loop_limiter.set_increment_id(GetFuzzerContext()->GetFreshId()); + loop_limiter.set_compare_id(GetFuzzerContext()->GetFreshId()); + loop_limiter.set_logical_op_id(GetFuzzerContext()->GetFreshId()); + loop_limiters.emplace_back(loop_limiter); + } + } + + // Consider every access chain in the function to donate, and create a + // structure containing the ids necessary to clamp the access chain + // indices to be in-bounds. + std::vector + access_chain_clamping_info; + for (auto& block : *function_to_donate) { + for (auto& inst : block) { + switch (inst.opcode()) { + case SpvOpAccessChain: + case SpvOpInBoundsAccessChain: { + protobufs::AccessChainClampingInfo clamping_info; + clamping_info.set_access_chain_id( + original_id_to_donated_id->at(inst.result_id())); + + auto base_object = donor_ir_context->get_def_use_mgr()->GetDef( + inst.GetSingleWordInOperand(0)); + assert(base_object && "The base object must exist."); + auto pointer_type = donor_ir_context->get_def_use_mgr()->GetDef( + base_object->type_id()); + assert(pointer_type && + pointer_type->opcode() == SpvOpTypePointer && + "The base object must have pointer type."); + + auto should_be_composite_type = + donor_ir_context->get_def_use_mgr()->GetDef( + pointer_type->GetSingleWordInOperand(1)); + + // Walk the access chain, creating fresh ids to facilitate + // clamping each index. For simplicity we do this for every + // index, even though constant indices will not end up being + // clamped. + for (uint32_t index = 1; index < inst.NumInOperands(); index++) { + auto compare_and_select_ids = + clamping_info.add_compare_and_select_ids(); + compare_and_select_ids->set_first( + GetFuzzerContext()->GetFreshId()); + compare_and_select_ids->set_second( + GetFuzzerContext()->GetFreshId()); + + // Get the bound for the component being indexed into. + uint32_t bound = + TransformationAddFunction::GetBoundForCompositeIndex( + donor_ir_context, *should_be_composite_type); + const uint32_t index_id = inst.GetSingleWordInOperand(index); + auto index_inst = + donor_ir_context->get_def_use_mgr()->GetDef(index_id); + auto index_type_inst = + donor_ir_context->get_def_use_mgr()->GetDef( + index_inst->type_id()); + assert(index_type_inst->opcode() == SpvOpTypeInt); + assert(index_type_inst->GetSingleWordInOperand(0) == 32); + opt::analysis::Integer* index_int_type = + donor_ir_context->get_type_mgr() + ->GetType(index_type_inst->result_id()) + ->AsInteger(); + if (index_inst->opcode() != SpvOpConstant) { + // We will have to clamp this index, so we need a constant + // whose value is one less than the bound, to compare + // against and to use as the clamped value. + FindOrCreate32BitIntegerConstant(bound - 1, + index_int_type->IsSigned()); + } + should_be_composite_type = + TransformationAddFunction::FollowCompositeIndex( + donor_ir_context, *should_be_composite_type, index_id); + } + access_chain_clamping_info.push_back(clamping_info); + break; + } + default: + break; + } + } + } + + // If the function contains OpKill or OpUnreachable instructions, and has + // non-void return type, then we need a value %v to use in order to turn + // these into instructions of the form OpReturn %v. + uint32_t kill_unreachable_return_value_id; + auto function_return_type_inst = + donor_ir_context->get_def_use_mgr()->GetDef( + function_to_donate->type_id()); + if (function_return_type_inst->opcode() == SpvOpTypeVoid) { + // The return type is void, so we don't need a return value. + kill_unreachable_return_value_id = 0; + } else { + // We do need a return value; we use OpUndef. + kill_unreachable_return_value_id = + FindOrCreateGlobalUndef(function_return_type_inst->type_id()); + } + // Add the function in a livesafe manner. + ApplyTransformation(TransformationAddFunction( + donated_instructions, loop_limiter_variable_id, loop_limit, + loop_limiters, kill_unreachable_return_value_id, + access_chain_clamping_info)); + } else { + // Add the function in a non-livesafe manner. + ApplyTransformation(TransformationAddFunction(donated_instructions)); + } + } +} + +std::vector +FuzzerPassDonateModules::GetFunctionsInCallGraphTopologicalOrder( + opt::IRContext* context) { + // This is an implementation of Kahn’s algorithm for topological sorting. + + // For each function id, stores the number of distinct functions that call + // the function. + std::map function_in_degree; + + // We first build a call graph for the module, and compute the in-degree for + // each function in the process. + // TODO(afd): If there is functionality elsewhere in the SPIR-V tools + // framework to construct call graphs it could be nice to re-use it here. + std::map> call_graph_edges; + + // Initialize function in-degree and call graph edges to 0 and empty. + for (auto& function : *context->module()) { + function_in_degree[function.result_id()] = 0; + call_graph_edges[function.result_id()] = std::set(); + } + + // Consider every function. + for (auto& function : *context->module()) { + // Avoid considering the same callee of this function multiple times by + // recording known callees. + std::set known_callees; + // Consider every function call instruction in every block. + for (auto& block : function) { + for (auto& instruction : block) { + if (instruction.opcode() != SpvOpFunctionCall) { + continue; + } + // Get the id of the function being called. + uint32_t callee = instruction.GetSingleWordInOperand(0); + if (known_callees.count(callee)) { + // We have already considered a call to this function - ignore it. + continue; + } + // Increase the callee's in-degree and add an edge to the call graph. + function_in_degree[callee]++; + call_graph_edges[function.result_id()].insert(callee); + // Mark the callee as 'known'. + known_callees.insert(callee); + } + } + } + + // This is the sorted order of function ids that we will eventually return. + std::vector result; + + // Populate a queue with all those function ids with in-degree zero. + std::queue queue; + for (auto& entry : function_in_degree) { + if (entry.second == 0) { + queue.push(entry.first); + } + } + + // Pop ids from the queue, adding them to the sorted order and decreasing the + // in-degrees of their successors. A successor who's in-degree becomes zero + // gets added to the queue. + while (!queue.empty()) { + auto next = queue.front(); + queue.pop(); + result.push_back(next); + for (auto successor : call_graph_edges.at(next)) { + assert(function_in_degree.at(successor) > 0 && + "The in-degree cannot be zero if the function is a successor."); + function_in_degree[successor] = function_in_degree.at(successor) - 1; + if (function_in_degree.at(successor) == 0) { + queue.push(successor); + } + } + } + + assert(result.size() == function_in_degree.size() && + "Every function should appear in the sort."); + + return result; +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_donate_modules.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_donate_modules.h new file mode 100644 index 0000000000..ef529db707 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_donate_modules.h @@ -0,0 +1,93 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_FUZZER_PASS_DONATE_MODULES_H_ +#define SOURCE_FUZZ_FUZZER_PASS_DONATE_MODULES_H_ + +#include + +#include "source/fuzz/fuzzer_pass.h" +#include "source/fuzz/fuzzer_util.h" + +namespace spvtools { +namespace fuzz { + +// A fuzzer pass that randomly adds code from other SPIR-V modules to the module +// being transformed. +class FuzzerPassDonateModules : public FuzzerPass { + public: + FuzzerPassDonateModules( + opt::IRContext* ir_context, FactManager* fact_manager, + FuzzerContext* fuzzer_context, + protobufs::TransformationSequence* transformations, + const std::vector& donor_suppliers); + + ~FuzzerPassDonateModules(); + + void Apply() override; + + // Donates the global declarations and functions of |donor_ir_context| into + // the fuzzer pass's IR context. |make_livesafe| dictates whether the + // functions of the donated module will be made livesafe (see + // FactFunctionIsLivesafe). + void DonateSingleModule(opt::IRContext* donor_ir_context, bool make_livesafe); + + private: + // Adapts a storage class coming from a donor module so that it will work + // in a recipient module, e.g. by changing Uniform to Private. + static SpvStorageClass AdaptStorageClass(SpvStorageClass donor_storage_class); + + // Identifies all external instruction set imports in |donor_ir_context| and + // populates |original_id_to_donated_id| with a mapping from the donor's id + // for such an import to a corresponding import in the recipient. Aborts if + // no such corresponding import is available. + void HandleExternalInstructionImports( + opt::IRContext* donor_ir_context, + std::map* original_id_to_donated_id); + + // Considers all types, globals, constants and undefs in |donor_ir_context|. + // For each instruction, uses |original_to_donated_id| to map its result id to + // either (1) the id of an existing identical instruction in the recipient, or + // (2) to a fresh id, in which case the instruction is also added to the + // recipient (with any operand ids that it uses being remapped via + // |original_id_to_donated_id|). + void HandleTypesAndValues( + opt::IRContext* donor_ir_context, + std::map* original_id_to_donated_id); + + // Assumes that |donor_ir_context| does not exhibit recursion. Considers the + // functions in |donor_ir_context|'s call graph in a reverse-topologically- + // sorted order (leaves-to-root), adding each function to the recipient + // module, rewritten to use fresh ids and using |original_id_to_donated_id| to + // remap ids. The |make_livesafe| argument captures whether the functions in + // the module are required to be made livesafe before being added to the + // recipient. + void HandleFunctions(opt::IRContext* donor_ir_context, + std::map* original_id_to_donated_id, + bool make_livesafe); + + // Returns the ids of all functions in |context| in a topological order in + // relation to the call graph of |context|, which is assumed to be recursion- + // free. + static std::vector GetFunctionsInCallGraphTopologicalOrder( + opt::IRContext* context); + + // Functions that supply SPIR-V modules + std::vector donor_suppliers_; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_FUZZER_PASS_DONATE_MODULES_H_ diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_merge_blocks.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_merge_blocks.cpp new file mode 100644 index 0000000000..ca1bfb33f5 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_merge_blocks.cpp @@ -0,0 +1,65 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/fuzzer_pass_merge_blocks.h" + +#include + +#include "source/fuzz/transformation_merge_blocks.h" + +namespace spvtools { +namespace fuzz { + +FuzzerPassMergeBlocks::FuzzerPassMergeBlocks( + opt::IRContext* ir_context, FactManager* fact_manager, + FuzzerContext* fuzzer_context, + protobufs::TransformationSequence* transformations) + : FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {} + +FuzzerPassMergeBlocks::~FuzzerPassMergeBlocks() = default; + +void FuzzerPassMergeBlocks::Apply() { + // First we populate a sequence of transformations that we might consider + // applying. + std::vector potential_transformations; + // We do this by considering every block of every function. + for (auto& function : *GetIRContext()->module()) { + for (auto& block : function) { + // We probabilistically decide to ignore some blocks. + if (!GetFuzzerContext()->ChoosePercentage( + GetFuzzerContext()->GetChanceOfMergingBlocks())) { + continue; + } + // For other blocks, we add a transformation to merge the block into its + // predecessor if that transformation would be applicable. + TransformationMergeBlocks transformation(block.id()); + if (transformation.IsApplicable(GetIRContext(), *GetFactManager())) { + potential_transformations.push_back(transformation); + } + } + } + + while (!potential_transformations.empty()) { + uint32_t index = GetFuzzerContext()->RandomIndex(potential_transformations); + auto transformation = potential_transformations.at(index); + potential_transformations.erase(potential_transformations.begin() + index); + if (transformation.IsApplicable(GetIRContext(), *GetFactManager())) { + transformation.Apply(GetIRContext(), GetFactManager()); + *GetTransformations()->add_transformation() = transformation.ToMessage(); + } + } +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_merge_blocks.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_merge_blocks.h new file mode 100644 index 0000000000..457e591376 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_merge_blocks.h @@ -0,0 +1,38 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_FUZZER_PASS_MERGE_BLOCKS_H_ +#define SOURCE_FUZZ_FUZZER_PASS_MERGE_BLOCKS_H_ + +#include "source/fuzz/fuzzer_pass.h" + +namespace spvtools { +namespace fuzz { + +// A fuzzer pass for merging blocks in the module. +class FuzzerPassMergeBlocks : public FuzzerPass { + public: + FuzzerPassMergeBlocks(opt::IRContext* ir_context, FactManager* fact_manager, + FuzzerContext* fuzzer_context, + protobufs::TransformationSequence* transformations); + + ~FuzzerPassMergeBlocks(); + + void Apply() override; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_FUZZER_PASS_MERGE_BLOCKS_H_ diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_obfuscate_constants.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_obfuscate_constants.cpp new file mode 100644 index 0000000000..3df11aeecd --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_obfuscate_constants.cpp @@ -0,0 +1,458 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/fuzzer_pass_obfuscate_constants.h" + +#include + +#include "source/fuzz/instruction_descriptor.h" +#include "source/fuzz/transformation_replace_boolean_constant_with_constant_binary.h" +#include "source/fuzz/transformation_replace_constant_with_uniform.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace fuzz { + +FuzzerPassObfuscateConstants::FuzzerPassObfuscateConstants( + opt::IRContext* ir_context, FactManager* fact_manager, + FuzzerContext* fuzzer_context, + protobufs::TransformationSequence* transformations) + : FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {} + +FuzzerPassObfuscateConstants::~FuzzerPassObfuscateConstants() = default; + +void FuzzerPassObfuscateConstants::ObfuscateBoolConstantViaConstantPair( + uint32_t depth, const protobufs::IdUseDescriptor& bool_constant_use, + const std::vector& greater_than_opcodes, + const std::vector& less_than_opcodes, uint32_t constant_id_1, + uint32_t constant_id_2, bool first_constant_is_larger) { + auto bool_constant_opcode = GetIRContext() + ->get_def_use_mgr() + ->GetDef(bool_constant_use.id_of_interest()) + ->opcode(); + assert((bool_constant_opcode == SpvOpConstantFalse || + bool_constant_opcode == SpvOpConstantTrue) && + "Precondition: this must be a usage of a boolean constant."); + + // Pick an opcode at random. First randomly decide whether to generate + // a 'greater than' or 'less than' kind of opcode, and then select a + // random opcode from the resulting subset. + SpvOp comparison_opcode; + if (GetFuzzerContext()->ChooseEven()) { + comparison_opcode = greater_than_opcodes[GetFuzzerContext()->RandomIndex( + greater_than_opcodes)]; + } else { + comparison_opcode = + less_than_opcodes[GetFuzzerContext()->RandomIndex(less_than_opcodes)]; + } + + // We now need to decide how to order constant_id_1 and constant_id_2 such + // that 'constant_id_1 comparison_opcode constant_id_2' evaluates to the + // boolean constant. + const bool is_greater_than_opcode = + std::find(greater_than_opcodes.begin(), greater_than_opcodes.end(), + comparison_opcode) != greater_than_opcodes.end(); + uint32_t lhs_id; + uint32_t rhs_id; + if ((bool_constant_opcode == SpvOpConstantTrue && + first_constant_is_larger == is_greater_than_opcode) || + (bool_constant_opcode == SpvOpConstantFalse && + first_constant_is_larger != is_greater_than_opcode)) { + lhs_id = constant_id_1; + rhs_id = constant_id_2; + } else { + lhs_id = constant_id_2; + rhs_id = constant_id_1; + } + + // We can now make a transformation that will replace |bool_constant_use| + // with an expression of the form (written using infix notation): + // |lhs_id| |comparison_opcode| |rhs_id| + auto transformation = TransformationReplaceBooleanConstantWithConstantBinary( + bool_constant_use, lhs_id, rhs_id, comparison_opcode, + GetFuzzerContext()->GetFreshId()); + // The transformation should be applicable by construction. + assert(transformation.IsApplicable(GetIRContext(), *GetFactManager())); + + // Applying this transformation yields a pointer to the new instruction that + // computes the result of the binary expression. + auto binary_operator_instruction = + transformation.ApplyWithResult(GetIRContext(), GetFactManager()); + + // Add this transformation to the sequence of transformations that have been + // applied. + *GetTransformations()->add_transformation() = transformation.ToMessage(); + + // Having made a binary expression, there may now be opportunities to further + // obfuscate the constants used as the LHS and RHS of the expression (e.g. by + // replacing them with loads from known uniforms). + // + // We thus consider operands 0 and 1 (LHS and RHS in turn). + for (uint32_t index : {0u, 1u}) { + // We randomly decide, based on the current depth of obfuscation, whether + // to further obfuscate this operand. + if (GetFuzzerContext()->GoDeeperInConstantObfuscation(depth)) { + auto in_operand_use = MakeIdUseDescriptor( + binary_operator_instruction->GetSingleWordInOperand(index), + MakeInstructionDescriptor(binary_operator_instruction->result_id(), + binary_operator_instruction->opcode(), 0), + index); + ObfuscateConstant(depth + 1, in_operand_use); + } + } +} + +void FuzzerPassObfuscateConstants::ObfuscateBoolConstantViaFloatConstantPair( + uint32_t depth, const protobufs::IdUseDescriptor& bool_constant_use, + uint32_t float_constant_id_1, uint32_t float_constant_id_2) { + auto float_constant_1 = GetIRContext() + ->get_constant_mgr() + ->FindDeclaredConstant(float_constant_id_1) + ->AsFloatConstant(); + auto float_constant_2 = GetIRContext() + ->get_constant_mgr() + ->FindDeclaredConstant(float_constant_id_2) + ->AsFloatConstant(); + assert(float_constant_1->words() != float_constant_2->words() && + "The constants should not be identical."); + assert(std::isfinite(float_constant_1->GetValueAsDouble()) && + "The constants must be finite numbers."); + assert(std::isfinite(float_constant_2->GetValueAsDouble()) && + "The constants must be finite numbers."); + bool first_constant_is_larger; + assert(float_constant_1->type()->AsFloat()->width() == + float_constant_2->type()->AsFloat()->width() && + "First and second floating-point constants must have the same width."); + if (float_constant_1->type()->AsFloat()->width() == 32) { + first_constant_is_larger = + float_constant_1->GetFloat() > float_constant_2->GetFloat(); + } else { + assert(float_constant_1->type()->AsFloat()->width() == 64 && + "Supported floating-point widths are 32 and 64."); + first_constant_is_larger = + float_constant_1->GetDouble() > float_constant_2->GetDouble(); + } + std::vector greater_than_opcodes{ + SpvOpFOrdGreaterThan, SpvOpFOrdGreaterThanEqual, SpvOpFUnordGreaterThan, + SpvOpFUnordGreaterThanEqual}; + std::vector less_than_opcodes{ + SpvOpFOrdGreaterThan, SpvOpFOrdGreaterThanEqual, SpvOpFUnordGreaterThan, + SpvOpFUnordGreaterThanEqual}; + + ObfuscateBoolConstantViaConstantPair( + depth, bool_constant_use, greater_than_opcodes, less_than_opcodes, + float_constant_id_1, float_constant_id_2, first_constant_is_larger); +} + +void FuzzerPassObfuscateConstants:: + ObfuscateBoolConstantViaSignedIntConstantPair( + uint32_t depth, const protobufs::IdUseDescriptor& bool_constant_use, + uint32_t signed_int_constant_id_1, uint32_t signed_int_constant_id_2) { + auto signed_int_constant_1 = + GetIRContext() + ->get_constant_mgr() + ->FindDeclaredConstant(signed_int_constant_id_1) + ->AsIntConstant(); + auto signed_int_constant_2 = + GetIRContext() + ->get_constant_mgr() + ->FindDeclaredConstant(signed_int_constant_id_2) + ->AsIntConstant(); + assert(signed_int_constant_1->words() != signed_int_constant_2->words() && + "The constants should not be identical."); + bool first_constant_is_larger; + assert(signed_int_constant_1->type()->AsInteger()->width() == + signed_int_constant_2->type()->AsInteger()->width() && + "First and second floating-point constants must have the same width."); + assert(signed_int_constant_1->type()->AsInteger()->IsSigned()); + assert(signed_int_constant_2->type()->AsInteger()->IsSigned()); + if (signed_int_constant_1->type()->AsFloat()->width() == 32) { + first_constant_is_larger = + signed_int_constant_1->GetS32() > signed_int_constant_2->GetS32(); + } else { + assert(signed_int_constant_1->type()->AsFloat()->width() == 64 && + "Supported integer widths are 32 and 64."); + first_constant_is_larger = + signed_int_constant_1->GetS64() > signed_int_constant_2->GetS64(); + } + std::vector greater_than_opcodes{SpvOpSGreaterThan, + SpvOpSGreaterThanEqual}; + std::vector less_than_opcodes{SpvOpSLessThan, SpvOpSLessThanEqual}; + + ObfuscateBoolConstantViaConstantPair( + depth, bool_constant_use, greater_than_opcodes, less_than_opcodes, + signed_int_constant_id_1, signed_int_constant_id_2, + first_constant_is_larger); +} + +void FuzzerPassObfuscateConstants:: + ObfuscateBoolConstantViaUnsignedIntConstantPair( + uint32_t depth, const protobufs::IdUseDescriptor& bool_constant_use, + uint32_t unsigned_int_constant_id_1, + uint32_t unsigned_int_constant_id_2) { + auto unsigned_int_constant_1 = + GetIRContext() + ->get_constant_mgr() + ->FindDeclaredConstant(unsigned_int_constant_id_1) + ->AsIntConstant(); + auto unsigned_int_constant_2 = + GetIRContext() + ->get_constant_mgr() + ->FindDeclaredConstant(unsigned_int_constant_id_2) + ->AsIntConstant(); + assert(unsigned_int_constant_1->words() != unsigned_int_constant_2->words() && + "The constants should not be identical."); + bool first_constant_is_larger; + assert(unsigned_int_constant_1->type()->AsInteger()->width() == + unsigned_int_constant_2->type()->AsInteger()->width() && + "First and second floating-point constants must have the same width."); + assert(!unsigned_int_constant_1->type()->AsInteger()->IsSigned()); + assert(!unsigned_int_constant_2->type()->AsInteger()->IsSigned()); + if (unsigned_int_constant_1->type()->AsFloat()->width() == 32) { + first_constant_is_larger = + unsigned_int_constant_1->GetU32() > unsigned_int_constant_2->GetU32(); + } else { + assert(unsigned_int_constant_1->type()->AsFloat()->width() == 64 && + "Supported integer widths are 32 and 64."); + first_constant_is_larger = + unsigned_int_constant_1->GetU64() > unsigned_int_constant_2->GetU64(); + } + std::vector greater_than_opcodes{SpvOpUGreaterThan, + SpvOpUGreaterThanEqual}; + std::vector less_than_opcodes{SpvOpULessThan, SpvOpULessThanEqual}; + + ObfuscateBoolConstantViaConstantPair( + depth, bool_constant_use, greater_than_opcodes, less_than_opcodes, + unsigned_int_constant_id_1, unsigned_int_constant_id_2, + first_constant_is_larger); +} + +void FuzzerPassObfuscateConstants::ObfuscateBoolConstant( + uint32_t depth, const protobufs::IdUseDescriptor& constant_use) { + // We want to replace the boolean constant use with a binary expression over + // scalar constants, but only if we can then potentially replace the constants + // with uniforms of the same value. + + auto available_types_with_uniforms = + GetFactManager()->GetTypesForWhichUniformValuesAreKnown(); + if (available_types_with_uniforms.empty()) { + // Do not try to obfuscate if we do not have access to any uniform + // elements with known values. + return; + } + auto chosen_type_id = + available_types_with_uniforms[GetFuzzerContext()->RandomIndex( + available_types_with_uniforms)]; + auto available_constants = + GetFactManager()->GetConstantsAvailableFromUniformsForType( + GetIRContext(), chosen_type_id); + if (available_constants.size() == 1) { + // TODO(afd): for now we only obfuscate a boolean if there are at least + // two constants available from uniforms, so that we can do a + // comparison between them. It would be good to be able to do the + // obfuscation even if there is only one such constant, if there is + // also another regular constant available. + return; + } + + // We know we have at least two known-to-be-constant uniforms of the chosen + // type. Pick one of them at random. + auto constant_index_1 = GetFuzzerContext()->RandomIndex(available_constants); + uint32_t constant_index_2; + + // Now choose another one distinct from the first one. + do { + constant_index_2 = GetFuzzerContext()->RandomIndex(available_constants); + } while (constant_index_1 == constant_index_2); + + auto constant_id_1 = available_constants[constant_index_1]; + auto constant_id_2 = available_constants[constant_index_2]; + + assert(constant_id_1 != 0 && constant_id_2 != 0 && + "We should not find an available constant with an id of 0."); + + // Now perform the obfuscation, according to whether the type of the constants + // is float, signed int, or unsigned int. + auto chosen_type = GetIRContext()->get_type_mgr()->GetType(chosen_type_id); + if (chosen_type->AsFloat()) { + ObfuscateBoolConstantViaFloatConstantPair(depth, constant_use, + constant_id_1, constant_id_2); + } else { + assert(chosen_type->AsInteger() && + "We should only have uniform facts about ints and floats."); + if (chosen_type->AsInteger()->IsSigned()) { + ObfuscateBoolConstantViaSignedIntConstantPair( + depth, constant_use, constant_id_1, constant_id_2); + } else { + ObfuscateBoolConstantViaUnsignedIntConstantPair( + depth, constant_use, constant_id_1, constant_id_2); + } + } +} + +void FuzzerPassObfuscateConstants::ObfuscateScalarConstant( + uint32_t /*depth*/, const protobufs::IdUseDescriptor& constant_use) { + // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/2670): consider + // additional ways to obfuscate scalar constants. + + // Check whether we know that any uniforms are guaranteed to be equal to the + // scalar constant associated with |constant_use|. + auto uniform_descriptors = GetFactManager()->GetUniformDescriptorsForConstant( + GetIRContext(), constant_use.id_of_interest()); + if (uniform_descriptors.empty()) { + // No relevant uniforms, so do not obfuscate. + return; + } + + // Choose a random available uniform known to be equal to the constant. + protobufs::UniformBufferElementDescriptor uniform_descriptor = + uniform_descriptors[GetFuzzerContext()->RandomIndex(uniform_descriptors)]; + // Create, apply and record a transformation to replace the constant use with + // the result of a load from the chosen uniform. + auto transformation = TransformationReplaceConstantWithUniform( + constant_use, uniform_descriptor, GetFuzzerContext()->GetFreshId(), + GetFuzzerContext()->GetFreshId()); + // Transformation should be applicable by construction. + assert(transformation.IsApplicable(GetIRContext(), *GetFactManager())); + transformation.Apply(GetIRContext(), GetFactManager()); + *GetTransformations()->add_transformation() = transformation.ToMessage(); +} + +void FuzzerPassObfuscateConstants::ObfuscateConstant( + uint32_t depth, const protobufs::IdUseDescriptor& constant_use) { + switch (GetIRContext() + ->get_def_use_mgr() + ->GetDef(constant_use.id_of_interest()) + ->opcode()) { + case SpvOpConstantTrue: + case SpvOpConstantFalse: + ObfuscateBoolConstant(depth, constant_use); + break; + case SpvOpConstant: + ObfuscateScalarConstant(depth, constant_use); + break; + default: + assert(false && "The opcode should be one of the above."); + break; + } +} + +void FuzzerPassObfuscateConstants::MaybeAddConstantIdUse( + const opt::Instruction& inst, uint32_t in_operand_index, + uint32_t base_instruction_result_id, + const std::map& skipped_opcode_count, + std::vector* constant_uses) { + if (inst.GetInOperand(in_operand_index).type != SPV_OPERAND_TYPE_ID) { + // The operand is not an id, so it cannot be a constant id. + return; + } + auto operand_id = inst.GetSingleWordInOperand(in_operand_index); + auto operand_definition = + GetIRContext()->get_def_use_mgr()->GetDef(operand_id); + switch (operand_definition->opcode()) { + case SpvOpConstantFalse: + case SpvOpConstantTrue: + case SpvOpConstant: { + // The operand is a constant id, so make an id use descriptor and record + // it. + protobufs::IdUseDescriptor id_use_descriptor; + id_use_descriptor.set_id_of_interest(operand_id); + id_use_descriptor.mutable_enclosing_instruction() + ->set_target_instruction_opcode(inst.opcode()); + id_use_descriptor.mutable_enclosing_instruction() + ->set_base_instruction_result_id(base_instruction_result_id); + id_use_descriptor.mutable_enclosing_instruction() + ->set_num_opcodes_to_ignore( + skipped_opcode_count.find(inst.opcode()) == + skipped_opcode_count.end() + ? 0 + : skipped_opcode_count.at(inst.opcode())); + id_use_descriptor.set_in_operand_index(in_operand_index); + constant_uses->push_back(id_use_descriptor); + } break; + default: + break; + } +} + +void FuzzerPassObfuscateConstants::Apply() { + // First, gather up all the constant uses available in the module, by going + // through each block in each function. + std::vector constant_uses; + for (auto& function : *GetIRContext()->module()) { + for (auto& block : function) { + // For each constant use we encounter we are going to make an id use + // descriptor. An id use is described with respect to a base instruction; + // if there are instructions at the start of the block without result ids, + // the base instruction will have to be the block's label. + uint32_t base_instruction_result_id = block.id(); + + // An id use descriptor also records how many instructions of a particular + // opcode need to be skipped in order to find the instruction of interest + // from the base instruction. We maintain a mapping that records a skip + // count for each relevant opcode. + std::map skipped_opcode_count; + + // Go through each instruction in the block. + for (auto& inst : block) { + if (inst.HasResultId()) { + // The instruction has a result id, so can be used as the base + // instruction from now on, until another instruction with a result id + // is encountered. + base_instruction_result_id = inst.result_id(); + // Opcode skip counts were with respect to the previous base + // instruction and are now irrelevant. + skipped_opcode_count.clear(); + } + + // Consider each operand of the instruction, and add a constant id use + // for the operand if relevant. + for (uint32_t in_operand_index = 0; + in_operand_index < inst.NumInOperands(); in_operand_index++) { + MaybeAddConstantIdUse(inst, in_operand_index, + base_instruction_result_id, + skipped_opcode_count, &constant_uses); + } + + if (!inst.HasResultId()) { + // The instruction has no result id, so in order to identify future id + // uses for instructions with this opcode from the existing base + // instruction, we need to increase the skip count for this opcode. + skipped_opcode_count[inst.opcode()] = + skipped_opcode_count.find(inst.opcode()) == + skipped_opcode_count.end() + ? 1 + : skipped_opcode_count[inst.opcode()] + 1; + } + } + } + } + + // Go through the constant uses in a random order by repeatedly pulling out a + // constant use at a random index. + while (!constant_uses.empty()) { + auto index = GetFuzzerContext()->RandomIndex(constant_uses); + auto constant_use = std::move(constant_uses[index]); + constant_uses.erase(constant_uses.begin() + index); + // Decide probabilistically whether to skip or obfuscate this constant use. + if (!GetFuzzerContext()->ChoosePercentage( + GetFuzzerContext()->GetChanceOfObfuscatingConstant())) { + continue; + } + ObfuscateConstant(0, constant_use); + } +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_obfuscate_constants.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_obfuscate_constants.h new file mode 100644 index 0000000000..f34717b2e3 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_obfuscate_constants.h @@ -0,0 +1,107 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_FUZZER_PASS_OBFUSCATE_CONSTANTS_ +#define SOURCE_FUZZ_FUZZER_PASS_OBFUSCATE_CONSTANTS_ + +#include + +#include "source/fuzz/fuzzer_pass.h" + +namespace spvtools { +namespace fuzz { + +// A fuzzer pass for turning uses of constants into more complex forms. +// Examples include replacing 'true' with '42 < 52', and replacing '42' with +// 'a.b.c' if 'a.b.c' is known to hold the value '42'. +class FuzzerPassObfuscateConstants : public FuzzerPass { + public: + FuzzerPassObfuscateConstants( + opt::IRContext* ir_context, FactManager* fact_manager, + FuzzerContext* fuzzer_context, + protobufs::TransformationSequence* transformations); + + ~FuzzerPassObfuscateConstants() override; + + void Apply() override; + + private: + // Applies 0 or more transformations to potentially obfuscate the constant + // use represented by |constant_use|. The |depth| parameter controls how + // deeply obfuscation can recurse. + void ObfuscateConstant(uint32_t depth, + const protobufs::IdUseDescriptor& constant_use); + + // This method will try to turn |constant_use|, required to be a use of a + // boolean constant, into a binary expression on scalar constants, which may + // themselves be recursively obfuscated. + void ObfuscateBoolConstant(uint32_t depth, + const protobufs::IdUseDescriptor& constant_use); + + // This method will try to turn |constant_use|, required to be a use of a + // scalar constant, into the value loaded from a uniform known to have the + // same value as the constant (if one exists). + void ObfuscateScalarConstant(uint32_t depth, + const protobufs::IdUseDescriptor& constant_use); + + // Applies a transformation to replace the boolean constant usage represented + // by |bool_constant_use| with a binary expression involving + // |float_constant_id_1| and |float_constant_id_2|, which must not be equal + // to one another. Possibly further obfuscates the uses of these float + // constants. The |depth| parameter controls how deeply obfuscation can + // recurse. + void ObfuscateBoolConstantViaFloatConstantPair( + uint32_t depth, const protobufs::IdUseDescriptor& bool_constant_use, + uint32_t float_constant_id_1, uint32_t float_constant_id_2); + + // Similar to the above, but for signed int constants. + void ObfuscateBoolConstantViaSignedIntConstantPair( + uint32_t depth, const protobufs::IdUseDescriptor& bool_constant_use, + uint32_t signed_int_constant_id_1, uint32_t signed_int_constant_id_2); + + // Similar to the above, but for unsigned int constants. + void ObfuscateBoolConstantViaUnsignedIntConstantPair( + uint32_t depth, const protobufs::IdUseDescriptor& bool_constant_use, + uint32_t unsigned_int_constant_id_1, uint32_t unsigned_int_constant_id_2); + + // A helper method to capture the common parts of the above methods. + // The method is used to obfuscate the boolean constant usage represented by + // |bool_constant_use| by replacing it with '|constant_id_1| OP + // |constant_id_2|', where 'OP' is chosen from either |greater_than_opcodes| + // or |less_than_opcodes|. + // + // The two constant ids must not represent the same value, and thus + // |greater_than_opcodes| may include 'greater than or equal' opcodes + // (similar for |less_than_opcodes|). + void ObfuscateBoolConstantViaConstantPair( + uint32_t depth, const protobufs::IdUseDescriptor& bool_constant_use, + const std::vector& greater_than_opcodes, + const std::vector& less_than_opcodes, uint32_t constant_id_1, + uint32_t constant_id_2, bool first_constant_is_larger); + + // A helper method to determine whether input operand |in_operand_index| of + // |inst| is the id of a constant, and add an id use descriptor to + // |candidate_constant_uses| if so. The other parameters are used for id use + // descriptor construction. + void MaybeAddConstantIdUse( + const opt::Instruction& inst, uint32_t in_operand_index, + uint32_t base_instruction_result_id, + const std::map& skipped_opcode_count, + std::vector* constant_uses); +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_FUZZER_PASS_OBFUSCATE_CONSTANTS_ diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_outline_functions.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_outline_functions.cpp new file mode 100644 index 0000000000..d59c195d7c --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_outline_functions.cpp @@ -0,0 +1,99 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/fuzzer_pass_outline_functions.h" + +#include + +#include "source/fuzz/fuzzer_util.h" +#include "source/fuzz/transformation_outline_function.h" + +namespace spvtools { +namespace fuzz { + +FuzzerPassOutlineFunctions::FuzzerPassOutlineFunctions( + opt::IRContext* ir_context, FactManager* fact_manager, + FuzzerContext* fuzzer_context, + protobufs::TransformationSequence* transformations) + : FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {} + +FuzzerPassOutlineFunctions::~FuzzerPassOutlineFunctions() = default; + +void FuzzerPassOutlineFunctions::Apply() { + std::vector original_functions; + for (auto& function : *GetIRContext()->module()) { + original_functions.push_back(&function); + } + for (auto& function : original_functions) { + if (!GetFuzzerContext()->ChoosePercentage( + GetFuzzerContext()->GetChanceOfOutliningFunction())) { + continue; + } + std::vector blocks; + for (auto& block : *function) { + blocks.push_back(&block); + } + auto entry_block = blocks[GetFuzzerContext()->RandomIndex(blocks)]; + auto dominator_analysis = GetIRContext()->GetDominatorAnalysis(function); + auto postdominator_analysis = + GetIRContext()->GetPostDominatorAnalysis(function); + std::vector candidate_exit_blocks; + for (auto postdominates_entry_block = entry_block; + postdominates_entry_block != nullptr; + postdominates_entry_block = postdominator_analysis->ImmediateDominator( + postdominates_entry_block)) { + if (dominator_analysis->Dominates(entry_block, + postdominates_entry_block)) { + candidate_exit_blocks.push_back(postdominates_entry_block); + } + } + if (candidate_exit_blocks.empty()) { + continue; + } + auto exit_block = candidate_exit_blocks[GetFuzzerContext()->RandomIndex( + candidate_exit_blocks)]; + + auto region_blocks = TransformationOutlineFunction::GetRegionBlocks( + GetIRContext(), entry_block, exit_block); + std::map input_id_to_fresh_id; + for (auto id : TransformationOutlineFunction::GetRegionInputIds( + GetIRContext(), region_blocks, exit_block)) { + input_id_to_fresh_id[id] = GetFuzzerContext()->GetFreshId(); + } + std::map output_id_to_fresh_id; + for (auto id : TransformationOutlineFunction::GetRegionOutputIds( + GetIRContext(), region_blocks, exit_block)) { + output_id_to_fresh_id[id] = GetFuzzerContext()->GetFreshId(); + } + TransformationOutlineFunction transformation( + entry_block->id(), exit_block->id(), + /*new_function_struct_return_type_id*/ + GetFuzzerContext()->GetFreshId(), + /*new_function_type_id*/ GetFuzzerContext()->GetFreshId(), + /*new_function_id*/ GetFuzzerContext()->GetFreshId(), + /*new_function_region_entry_block*/ + GetFuzzerContext()->GetFreshId(), + /*new_caller_result_id*/ GetFuzzerContext()->GetFreshId(), + /*new_callee_result_id*/ GetFuzzerContext()->GetFreshId(), + /*input_id_to_fresh_id*/ std::move(input_id_to_fresh_id), + /*output_id_to_fresh_id*/ std::move(output_id_to_fresh_id)); + if (transformation.IsApplicable(GetIRContext(), *GetFactManager())) { + transformation.Apply(GetIRContext(), GetFactManager()); + *GetTransformations()->add_transformation() = transformation.ToMessage(); + } + } +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_outline_functions.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_outline_functions.h new file mode 100644 index 0000000000..5448e7df75 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_outline_functions.h @@ -0,0 +1,40 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_FUZZER_PASS_OUTLINE_FUNCTIONS_H_ +#define SOURCE_FUZZ_FUZZER_PASS_OUTLINE_FUNCTIONS_H_ + +#include "source/fuzz/fuzzer_pass.h" + +namespace spvtools { +namespace fuzz { + +// A fuzzer pass for outlining single-entry single-exit regions of a control +// flow graph into their own functions. +class FuzzerPassOutlineFunctions : public FuzzerPass { + public: + FuzzerPassOutlineFunctions( + opt::IRContext* ir_context, FactManager* fact_manager, + FuzzerContext* fuzzer_context, + protobufs::TransformationSequence* transformations); + + ~FuzzerPassOutlineFunctions(); + + void Apply() override; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_FUZZER_PASS_OUTLINE_FUNCTIONS_H_ diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_permute_blocks.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_permute_blocks.cpp new file mode 100644 index 0000000000..af6d2a5dbf --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_permute_blocks.cpp @@ -0,0 +1,82 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/fuzzer_pass_permute_blocks.h" + +#include "source/fuzz/transformation_move_block_down.h" + +namespace spvtools { +namespace fuzz { + +FuzzerPassPermuteBlocks::FuzzerPassPermuteBlocks( + opt::IRContext* ir_context, FactManager* fact_manager, + FuzzerContext* fuzzer_context, + protobufs::TransformationSequence* transformations) + : FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {} + +FuzzerPassPermuteBlocks::~FuzzerPassPermuteBlocks() = default; + +void FuzzerPassPermuteBlocks::Apply() { + // For now we do something very simple: we randomly decide whether to move a + // block, and for each block that we do move, we push it down as far as we + // legally can. + // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/2635): it would be + // nice to randomly sample from the set of legal block permutations and then + // encode the chosen permutation via a series of move-block-down + // transformations. This should be possible but will require some thought. + + for (auto& function : *GetIRContext()->module()) { + std::vector block_ids; + // Collect all block ids for the function before messing with block + // ordering. + for (auto& block : function) { + block_ids.push_back(block.id()); + } + // Now consider each block id. We consider block ids in reverse, because + // e.g. in code generated from the following: + // + // if (...) { + // A + // B + // } else { + // C + // } + // + // block A cannot be moved down, but B has freedom to move and that movement + // would provide more freedom for A to move. + for (auto id = block_ids.rbegin(); id != block_ids.rend(); ++id) { + // Randomly decide whether to ignore the block id. + if (!GetFuzzerContext()->ChoosePercentage( + GetFuzzerContext()->GetChanceOfMovingBlockDown())) { + continue; + } + // Keep pushing the block down, until pushing down fails. + // The loop is guaranteed to terminate because a block cannot be pushed + // down indefinitely. + while (true) { + TransformationMoveBlockDown transformation(*id); + if (transformation.IsApplicable(GetIRContext(), *GetFactManager())) { + transformation.Apply(GetIRContext(), GetFactManager()); + *GetTransformations()->add_transformation() = + transformation.ToMessage(); + } else { + break; + } + } + } + } +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_permute_blocks.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_permute_blocks.h new file mode 100644 index 0000000000..6735e952bf --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_permute_blocks.h @@ -0,0 +1,39 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_FUZZER_PASS_PERMUTE_BLOCKS_ +#define SOURCE_FUZZ_FUZZER_PASS_PERMUTE_BLOCKS_ + +#include "source/fuzz/fuzzer_pass.h" + +namespace spvtools { +namespace fuzz { + +// A fuzzer pass for shuffling the blocks of the module in a validity-preserving +// manner. +class FuzzerPassPermuteBlocks : public FuzzerPass { + public: + FuzzerPassPermuteBlocks(opt::IRContext* ir_context, FactManager* fact_manager, + FuzzerContext* fuzzer_context, + protobufs::TransformationSequence* transformations); + + ~FuzzerPassPermuteBlocks() override; + + void Apply() override; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_FUZZER_PASS_PERMUTE_BLOCKS_ diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_split_blocks.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_pass_split_blocks.cpp new file mode 100644 index 0000000000..6a2ea4dcc8 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_split_blocks.cpp @@ -0,0 +1,106 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/fuzzer_pass_split_blocks.h" + +#include + +#include "source/fuzz/instruction_descriptor.h" +#include "source/fuzz/transformation_split_block.h" + +namespace spvtools { +namespace fuzz { + +FuzzerPassSplitBlocks::FuzzerPassSplitBlocks( + opt::IRContext* ir_context, FactManager* fact_manager, + FuzzerContext* fuzzer_context, + protobufs::TransformationSequence* transformations) + : FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations) {} + +FuzzerPassSplitBlocks::~FuzzerPassSplitBlocks() = default; + +void FuzzerPassSplitBlocks::Apply() { + // Gather up pointers to all the blocks in the module. We are then able to + // iterate over these pointers and split the blocks to which they point; + // we cannot safely split blocks while we iterate through the module. + std::vector blocks; + for (auto& function : *GetIRContext()->module()) { + for (auto& block : function) { + blocks.push_back(&block); + } + } + + // Now go through all the block pointers that were gathered. + for (auto& block : blocks) { + // Probabilistically decide whether to try to split this block. + if (!GetFuzzerContext()->ChoosePercentage( + GetFuzzerContext()->GetChanceOfSplittingBlock())) { + // We are not going to try to split this block. + continue; + } + + // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/2964): consider + // taking a simpler approach to identifying the instruction before which + // to split a block. + + // We are going to try to split this block. We now need to choose where + // to split it. We describe the instruction before which we would like to + // split a block via an InstructionDescriptor, details of which are + // commented in the protobufs definition file. + std::vector instruction_descriptors; + + // The initial base instruction is the block label. + uint32_t base = block->id(); + + // Counts the number of times we have seen each opcode since we reset the + // base instruction. + std::map skip_count; + + // Consider every instruction in the block. The label is excluded: it is + // only necessary to consider it as a base in case the first instruction + // in the block does not have a result id. + for (auto& inst : *block) { + if (inst.HasResultId()) { + // In the case that the instruction has a result id, we use the + // instruction as its own base, and clear the skip counts we have + // collected. + base = inst.result_id(); + skip_count.clear(); + } + const SpvOp opcode = inst.opcode(); + instruction_descriptors.emplace_back(MakeInstructionDescriptor( + base, opcode, skip_count.count(opcode) ? skip_count.at(opcode) : 0)); + if (!inst.HasResultId()) { + skip_count[opcode] = + skip_count.count(opcode) ? skip_count.at(opcode) + 1 : 1; + } + } + // Having identified all the places we might be able to split the block, + // we choose one of them. + auto transformation = TransformationSplitBlock( + instruction_descriptors[GetFuzzerContext()->RandomIndex( + instruction_descriptors)], + GetFuzzerContext()->GetFreshId()); + // If the position we have chosen turns out to be a valid place to split + // the block, we apply the split. Otherwise the block just doesn't get + // split. + if (transformation.IsApplicable(GetIRContext(), *GetFactManager())) { + transformation.Apply(GetIRContext(), GetFactManager()); + *GetTransformations()->add_transformation() = transformation.ToMessage(); + } + } +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_pass_split_blocks.h b/third_party/spirv-tools/source/fuzz/fuzzer_pass_split_blocks.h new file mode 100644 index 0000000000..6e56dde955 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/fuzzer_pass_split_blocks.h @@ -0,0 +1,39 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_FUZZER_PASS_SPLIT_BLOCKS_ +#define SOURCE_FUZZ_FUZZER_PASS_SPLIT_BLOCKS_ + +#include "source/fuzz/fuzzer_pass.h" + +namespace spvtools { +namespace fuzz { + +// A fuzzer pass for splitting blocks in the module, to create more blocks; this +// can be very useful for giving other passes a chance to apply. +class FuzzerPassSplitBlocks : public FuzzerPass { + public: + FuzzerPassSplitBlocks(opt::IRContext* ir_context, FactManager* fact_manager, + FuzzerContext* fuzzer_context, + protobufs::TransformationSequence* transformations); + + ~FuzzerPassSplitBlocks() override; + + void Apply() override; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_FUZZER_PASS_SPLIT_BLOCKS_ diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_util.cpp b/third_party/spirv-tools/source/fuzz/fuzzer_util.cpp new file mode 100644 index 0000000000..f9f9969cdd --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/fuzzer_util.cpp @@ -0,0 +1,397 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/fuzzer_util.h" + +#include "source/opt/build_module.h" + +namespace spvtools { +namespace fuzz { + +namespace fuzzerutil { + +bool IsFreshId(opt::IRContext* context, uint32_t id) { + return !context->get_def_use_mgr()->GetDef(id); +} + +void UpdateModuleIdBound(opt::IRContext* context, uint32_t id) { + // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/2541) consider the + // case where the maximum id bound is reached. + context->module()->SetIdBound( + std::max(context->module()->id_bound(), id + 1)); +} + +opt::BasicBlock* MaybeFindBlock(opt::IRContext* context, + uint32_t maybe_block_id) { + auto inst = context->get_def_use_mgr()->GetDef(maybe_block_id); + if (inst == nullptr) { + // No instruction defining this id was found. + return nullptr; + } + if (inst->opcode() != SpvOpLabel) { + // The instruction defining the id is not a label, so it cannot be a block + // id. + return nullptr; + } + return context->cfg()->block(maybe_block_id); +} + +bool PhiIdsOkForNewEdge( + opt::IRContext* context, opt::BasicBlock* bb_from, opt::BasicBlock* bb_to, + const google::protobuf::RepeatedField& phi_ids) { + if (bb_from->IsSuccessor(bb_to)) { + // There is already an edge from |from_block| to |to_block|, so there is + // no need to extend OpPhi instructions. Do not allow phi ids to be + // present. This might turn out to be too strict; perhaps it would be OK + // just to ignore the ids in this case. + return phi_ids.empty(); + } + // The edge would add a previously non-existent edge from |from_block| to + // |to_block|, so we go through the given phi ids and check that they exactly + // match the OpPhi instructions in |to_block|. + uint32_t phi_index = 0; + // An explicit loop, rather than applying a lambda to each OpPhi in |bb_to|, + // makes sense here because we need to increment |phi_index| for each OpPhi + // instruction. + for (auto& inst : *bb_to) { + if (inst.opcode() != SpvOpPhi) { + // The OpPhi instructions all occur at the start of the block; if we find + // a non-OpPhi then we have seen them all. + break; + } + if (phi_index == static_cast(phi_ids.size())) { + // Not enough phi ids have been provided to account for the OpPhi + // instructions. + return false; + } + // Look for an instruction defining the next phi id. + opt::Instruction* phi_extension = + context->get_def_use_mgr()->GetDef(phi_ids[phi_index]); + if (!phi_extension) { + // The id given to extend this OpPhi does not exist. + return false; + } + if (phi_extension->type_id() != inst.type_id()) { + // The instruction given to extend this OpPhi either does not have a type + // or its type does not match that of the OpPhi. + return false; + } + + if (context->get_instr_block(phi_extension)) { + // The instruction defining the phi id has an associated block (i.e., it + // is not a global value). Check whether its definition dominates the + // exit of |from_block|. + auto dominator_analysis = + context->GetDominatorAnalysis(bb_from->GetParent()); + if (!dominator_analysis->Dominates(phi_extension, + bb_from->terminator())) { + // The given id is no good as its definition does not dominate the exit + // of |from_block| + return false; + } + } + phi_index++; + } + // We allow some of the ids provided for extending OpPhi instructions to be + // unused. Their presence does no harm, and requiring a perfect match may + // make transformations less likely to cleanly apply. + return true; +} + +uint32_t MaybeGetBoolConstantId(opt::IRContext* context, bool value) { + opt::analysis::Bool bool_type; + auto registered_bool_type = + context->get_type_mgr()->GetRegisteredType(&bool_type); + if (!registered_bool_type) { + return 0; + } + opt::analysis::BoolConstant bool_constant(registered_bool_type->AsBool(), + value); + return context->get_constant_mgr()->FindDeclaredConstant( + &bool_constant, context->get_type_mgr()->GetId(&bool_type)); +} + +void AddUnreachableEdgeAndUpdateOpPhis( + opt::IRContext* context, opt::BasicBlock* bb_from, opt::BasicBlock* bb_to, + bool condition_value, + const google::protobuf::RepeatedField& phi_ids) { + assert(PhiIdsOkForNewEdge(context, bb_from, bb_to, phi_ids) && + "Precondition on phi_ids is not satisfied"); + assert(bb_from->terminator()->opcode() == SpvOpBranch && + "Precondition on terminator of bb_from is not satisfied"); + + // Get the id of the boolean constant to be used as the condition. + uint32_t bool_id = MaybeGetBoolConstantId(context, condition_value); + assert( + bool_id && + "Precondition that condition value must be available is not satisfied"); + + const bool from_to_edge_already_exists = bb_from->IsSuccessor(bb_to); + auto successor = bb_from->terminator()->GetSingleWordInOperand(0); + + // Add the dead branch, by turning OpBranch into OpBranchConditional, and + // ordering the targets depending on whether the given boolean corresponds to + // true or false. + bb_from->terminator()->SetOpcode(SpvOpBranchConditional); + bb_from->terminator()->SetInOperands( + {{SPV_OPERAND_TYPE_ID, {bool_id}}, + {SPV_OPERAND_TYPE_ID, {condition_value ? successor : bb_to->id()}}, + {SPV_OPERAND_TYPE_ID, {condition_value ? bb_to->id() : successor}}}); + + // Update OpPhi instructions in the target block if this branch adds a + // previously non-existent edge from source to target. + if (!from_to_edge_already_exists) { + uint32_t phi_index = 0; + for (auto& inst : *bb_to) { + if (inst.opcode() != SpvOpPhi) { + break; + } + assert(phi_index < static_cast(phi_ids.size()) && + "There should be at least one phi id per OpPhi instruction."); + inst.AddOperand({SPV_OPERAND_TYPE_ID, {phi_ids[phi_index]}}); + inst.AddOperand({SPV_OPERAND_TYPE_ID, {bb_from->id()}}); + phi_index++; + } + } +} + +bool BlockIsInLoopContinueConstruct(opt::IRContext* context, uint32_t block_id, + uint32_t maybe_loop_header_id) { + // We deem a block to be part of a loop's continue construct if the loop's + // continue target dominates the block. + auto containing_construct_block = context->cfg()->block(maybe_loop_header_id); + if (containing_construct_block->IsLoopHeader()) { + auto continue_target = containing_construct_block->ContinueBlockId(); + if (context->GetDominatorAnalysis(containing_construct_block->GetParent()) + ->Dominates(continue_target, block_id)) { + return true; + } + } + return false; +} + +opt::BasicBlock::iterator GetIteratorForInstruction( + opt::BasicBlock* block, const opt::Instruction* inst) { + for (auto inst_it = block->begin(); inst_it != block->end(); ++inst_it) { + if (inst == &*inst_it) { + return inst_it; + } + } + return block->end(); +} + +bool BlockIsReachableInItsFunction(opt::IRContext* context, + opt::BasicBlock* bb) { + auto enclosing_function = bb->GetParent(); + return context->GetDominatorAnalysis(enclosing_function) + ->Dominates(enclosing_function->entry().get(), bb); +} + +bool CanInsertOpcodeBeforeInstruction( + SpvOp opcode, const opt::BasicBlock::iterator& instruction_in_block) { + if (instruction_in_block->PreviousNode() && + (instruction_in_block->PreviousNode()->opcode() == SpvOpLoopMerge || + instruction_in_block->PreviousNode()->opcode() == SpvOpSelectionMerge)) { + // We cannot insert directly after a merge instruction. + return false; + } + if (opcode != SpvOpVariable && + instruction_in_block->opcode() == SpvOpVariable) { + // We cannot insert a non-OpVariable instruction directly before a + // variable; variables in a function must be contiguous in the entry block. + return false; + } + // We cannot insert a non-OpPhi instruction directly before an OpPhi, because + // OpPhi instructions need to be contiguous at the start of a block. + return opcode == SpvOpPhi || instruction_in_block->opcode() != SpvOpPhi; +} + +bool CanMakeSynonymOf(opt::IRContext* ir_context, opt::Instruction* inst) { + if (!inst->HasResultId()) { + // We can only make a synonym of an instruction that generates an id. + return false; + } + if (!inst->type_id()) { + // We can only make a synonym of an instruction that has a type. + return false; + } + auto type_inst = ir_context->get_def_use_mgr()->GetDef(inst->type_id()); + if (type_inst->opcode() == SpvOpTypePointer) { + switch (inst->opcode()) { + case SpvOpConstantNull: + case SpvOpUndef: + // We disallow making synonyms of null or undefined pointers. This is + // to provide the property that if the original shader exhibited no bad + // pointer accesses, the transformed shader will not either. + return false; + default: + break; + } + } + + // We do not make synonyms of objects that have decorations: if the synonym is + // not decorated analogously, using the original object vs. its synonymous + // form may not be equivalent. + return ir_context->get_decoration_mgr() + ->GetDecorationsFor(inst->result_id(), true) + .empty(); +} + +bool IsCompositeType(const opt::analysis::Type* type) { + return type && (type->AsArray() || type->AsMatrix() || type->AsStruct() || + type->AsVector()); +} + +std::vector RepeatedFieldToVector( + const google::protobuf::RepeatedField& repeated_field) { + std::vector result; + for (auto i : repeated_field) { + result.push_back(i); + } + return result; +} + +uint32_t WalkCompositeTypeIndices( + opt::IRContext* context, uint32_t base_object_type_id, + const google::protobuf::RepeatedField& indices) { + uint32_t sub_object_type_id = base_object_type_id; + for (auto index : indices) { + auto should_be_composite_type = + context->get_def_use_mgr()->GetDef(sub_object_type_id); + assert(should_be_composite_type && "The type should exist."); + switch (should_be_composite_type->opcode()) { + case SpvOpTypeArray: { + auto array_length = GetArraySize(*should_be_composite_type, context); + if (array_length == 0 || index >= array_length) { + return 0; + } + sub_object_type_id = + should_be_composite_type->GetSingleWordInOperand(0); + break; + } + case SpvOpTypeMatrix: + case SpvOpTypeVector: { + auto count = should_be_composite_type->GetSingleWordInOperand(1); + if (index >= count) { + return 0; + } + sub_object_type_id = + should_be_composite_type->GetSingleWordInOperand(0); + break; + } + case SpvOpTypeStruct: { + if (index >= GetNumberOfStructMembers(*should_be_composite_type)) { + return 0; + } + sub_object_type_id = + should_be_composite_type->GetSingleWordInOperand(index); + break; + } + default: + return 0; + } + } + return sub_object_type_id; +} + +uint32_t GetNumberOfStructMembers( + const opt::Instruction& struct_type_instruction) { + assert(struct_type_instruction.opcode() == SpvOpTypeStruct && + "An OpTypeStruct instruction is required here."); + return struct_type_instruction.NumInOperands(); +} + +uint32_t GetArraySize(const opt::Instruction& array_type_instruction, + opt::IRContext* context) { + auto array_length_constant = + context->get_constant_mgr() + ->GetConstantFromInst(context->get_def_use_mgr()->GetDef( + array_type_instruction.GetSingleWordInOperand(1))) + ->AsIntConstant(); + if (array_length_constant->words().size() != 1) { + return 0; + } + return array_length_constant->GetU32(); +} + +bool IsValid(opt::IRContext* context) { + std::vector binary; + context->module()->ToBinary(&binary, false); + SpirvTools tools(context->grammar().target_env()); + return tools.Validate(binary); +} + +std::unique_ptr CloneIRContext(opt::IRContext* context) { + std::vector binary; + context->module()->ToBinary(&binary, false); + return BuildModule(context->grammar().target_env(), nullptr, binary.data(), + binary.size()); +} + +bool IsNonFunctionTypeId(opt::IRContext* ir_context, uint32_t id) { + auto type = ir_context->get_type_mgr()->GetType(id); + return type && !type->AsFunction(); +} + +bool IsMergeOrContinue(opt::IRContext* ir_context, uint32_t block_id) { + bool result = false; + ir_context->get_def_use_mgr()->WhileEachUse( + block_id, + [&result](const opt::Instruction* use_instruction, + uint32_t /*unused*/) -> bool { + switch (use_instruction->opcode()) { + case SpvOpLoopMerge: + case SpvOpSelectionMerge: + result = true; + return false; + default: + return true; + } + }); + return result; +} + +uint32_t FindFunctionType(opt::IRContext* ir_context, + const std::vector& type_ids) { + // Look through the existing types for a match. + for (auto& type_or_value : ir_context->types_values()) { + if (type_or_value.opcode() != SpvOpTypeFunction) { + // We are only interested in function types. + continue; + } + if (type_or_value.NumInOperands() != type_ids.size()) { + // Not a match: different numbers of arguments. + continue; + } + // Check whether the return type and argument types match. + bool input_operands_match = true; + for (uint32_t i = 0; i < type_or_value.NumInOperands(); i++) { + if (type_ids[i] != type_or_value.GetSingleWordInOperand(i)) { + input_operands_match = false; + break; + } + } + if (input_operands_match) { + // Everything matches. + return type_or_value.result_id(); + } + } + // No match was found. + return 0; +} + +} // namespace fuzzerutil + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/fuzzer_util.h b/third_party/spirv-tools/source/fuzz/fuzzer_util.h new file mode 100644 index 0000000000..f0a2953fd2 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/fuzzer_util.h @@ -0,0 +1,145 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_FUZZER_UTIL_H_ +#define SOURCE_FUZZ_FUZZER_UTIL_H_ + +#include + +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "source/opt/basic_block.h" +#include "source/opt/instruction.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace fuzz { + +// Provides types and global utility methods for use by the fuzzer +namespace fuzzerutil { + +// Function type that produces a SPIR-V module. +using ModuleSupplier = std::function()>; + +// Returns true if and only if the module does not define the given id. +bool IsFreshId(opt::IRContext* context, uint32_t id); + +// Updates the module's id bound if needed so that it is large enough to +// account for the given id. +void UpdateModuleIdBound(opt::IRContext* context, uint32_t id); + +// Return the block with id |maybe_block_id| if it exists, and nullptr +// otherwise. +opt::BasicBlock* MaybeFindBlock(opt::IRContext* context, + uint32_t maybe_block_id); + +// When adding an edge from |bb_from| to |bb_to| (which are assumed to be blocks +// in the same function), it is important to supply |bb_to| with ids that can be +// used to augment OpPhi instructions in the case that there is not already such +// an edge. This function returns true if and only if the ids provided in +// |phi_ids| suffice for this purpose, +bool PhiIdsOkForNewEdge( + opt::IRContext* context, opt::BasicBlock* bb_from, opt::BasicBlock* bb_to, + const google::protobuf::RepeatedField& phi_ids); + +// Returns the id of a boolean constant with value |value| if it exists in the +// module, or 0 otherwise. +uint32_t MaybeGetBoolConstantId(opt::IRContext* context, bool value); + +// Requires that a boolean constant with value |condition_value| is available, +// that PhiIdsOkForNewEdge(context, bb_from, bb_to, phi_ids) holds, and that +// bb_from ends with "OpBranch %some_block". Turns OpBranch into +// "OpBranchConditional |condition_value| ...", such that control will branch +// to %some_block, with |bb_to| being the unreachable alternative. Updates +// OpPhi instructions in |bb_to| using |phi_ids| so that the new edge is valid. +void AddUnreachableEdgeAndUpdateOpPhis( + opt::IRContext* context, opt::BasicBlock* bb_from, opt::BasicBlock* bb_to, + bool condition_value, + const google::protobuf::RepeatedField& phi_ids); + +// Returns true if and only if |maybe_loop_header_id| is a loop header and +// |block_id| is in the continue construct of the associated loop. +bool BlockIsInLoopContinueConstruct(opt::IRContext* context, uint32_t block_id, + uint32_t maybe_loop_header_id); + +// If |block| contains |inst|, an iterator for |inst| is returned. +// Otherwise |block|->end() is returned. +opt::BasicBlock::iterator GetIteratorForInstruction( + opt::BasicBlock* block, const opt::Instruction* inst); + +// Returns true if and only if there is a path to |bb| from the entry block of +// the function that contains |bb|. +bool BlockIsReachableInItsFunction(opt::IRContext* context, + opt::BasicBlock* bb); + +// Determines whether it is OK to insert an instruction with opcode |opcode| +// before |instruction_in_block|. +bool CanInsertOpcodeBeforeInstruction( + SpvOp opcode, const opt::BasicBlock::iterator& instruction_in_block); + +// Determines whether it is OK to make a synonym of |inst|. +bool CanMakeSynonymOf(opt::IRContext* ir_context, opt::Instruction* inst); + +// Determines whether the given type is a composite; that is: an array, matrix, +// struct or vector. +bool IsCompositeType(const opt::analysis::Type* type); + +// Returns a vector containing the same elements as |repeated_field|. +std::vector RepeatedFieldToVector( + const google::protobuf::RepeatedField& repeated_field); + +// Given a type id, |base_object_type_id|, checks that the given sequence of +// |indices| is suitable for indexing into this type. Returns the id of the +// type of the final sub-object reached via the indices if they are valid, and +// 0 otherwise. +uint32_t WalkCompositeTypeIndices( + opt::IRContext* context, uint32_t base_object_type_id, + const google::protobuf::RepeatedField& indices); + +// Returns the number of members associated with |struct_type_instruction|, +// which must be an OpStructType instruction. +uint32_t GetNumberOfStructMembers( + const opt::Instruction& struct_type_instruction); + +// Returns the constant size of the array associated with +// |array_type_instruction|, which must be an OpArrayType instruction. Returns +// 0 if there is not a static size. +uint32_t GetArraySize(const opt::Instruction& array_type_instruction, + opt::IRContext* context); + +// Returns true if and only if |context| is valid, according to the validator. +bool IsValid(opt::IRContext* context); + +// Returns a clone of |context|, by writing |context| to a binary and then +// parsing it again. +std::unique_ptr CloneIRContext(opt::IRContext* context); + +// Returns true if and only if |id| is the id of a type that is not a function +// type. +bool IsNonFunctionTypeId(opt::IRContext* ir_context, uint32_t id); + +// Returns true if and only if |block_id| is a merge block or continue target +bool IsMergeOrContinue(opt::IRContext* ir_context, uint32_t block_id); + +// Returns the result id of an instruction of the form: +// %id = OpTypeFunction |type_ids| +// or 0 if no such instruction exists. +uint32_t FindFunctionType(opt::IRContext* ir_context, + const std::vector& type_ids); + +} // namespace fuzzerutil + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_FUZZER_UTIL_H_ diff --git a/third_party/spirv-tools/source/fuzz/id_use_descriptor.cpp b/third_party/spirv-tools/source/fuzz/id_use_descriptor.cpp new file mode 100644 index 0000000000..eb8589df55 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/id_use_descriptor.cpp @@ -0,0 +1,62 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/id_use_descriptor.h" + +#include "source/fuzz/instruction_descriptor.h" + +namespace spvtools { +namespace fuzz { + +opt::Instruction* FindInstructionContainingUse( + const protobufs::IdUseDescriptor& id_use_descriptor, + opt::IRContext* context) { + auto result = + FindInstruction(id_use_descriptor.enclosing_instruction(), context); + if (!result) { + return nullptr; + } + if (id_use_descriptor.in_operand_index() >= result->NumInOperands()) { + return nullptr; + } + if (result->GetSingleWordInOperand(id_use_descriptor.in_operand_index()) != + id_use_descriptor.id_of_interest()) { + return nullptr; + } + return result; +} + +protobufs::IdUseDescriptor MakeIdUseDescriptor( + uint32_t id_of_interest, + const protobufs::InstructionDescriptor& enclosing_instruction, + uint32_t in_operand_index) { + protobufs::IdUseDescriptor result; + result.set_id_of_interest(id_of_interest); + *result.mutable_enclosing_instruction() = enclosing_instruction; + result.set_in_operand_index(in_operand_index); + return result; +} + +protobufs::IdUseDescriptor MakeIdUseDescriptorFromUse( + opt::IRContext* context, opt::Instruction* inst, + uint32_t in_operand_index) { + const auto& in_operand = inst->GetInOperand(in_operand_index); + assert(in_operand.type == SPV_OPERAND_TYPE_ID); + return MakeIdUseDescriptor(in_operand.words[0], + MakeInstructionDescriptor(context, inst), + in_operand_index); +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/id_use_descriptor.h b/third_party/spirv-tools/source/fuzz/id_use_descriptor.h new file mode 100644 index 0000000000..d18bb668da --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/id_use_descriptor.h @@ -0,0 +1,47 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_ID_USE_DESCRIPTOR_H_ +#define SOURCE_FUZZ_ID_USE_DESCRIPTOR_H_ + +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace fuzz { + +// Looks for an instruction in |context| that contains a use +// identified by |id_use_descriptor|. +// Returns |nullptr| if no such instruction can be found. +opt::Instruction* FindInstructionContainingUse( + const protobufs::IdUseDescriptor& id_use_descriptor, + opt::IRContext* context); + +// Creates an IdUseDescriptor protobuf message from the given components. +// See the protobuf definition for details of what these components mean. +protobufs::IdUseDescriptor MakeIdUseDescriptor( + uint32_t id_of_interest, + const protobufs::InstructionDescriptor& enclosing_instruction, + uint32_t in_operand_index); + +// Given an id use, represented by the instruction |inst| that uses the id, and +// the input operand index |in_operand_index| associated with the usage, returns +// an IdUseDescriptor that represents the use. +protobufs::IdUseDescriptor MakeIdUseDescriptorFromUse( + opt::IRContext* context, opt::Instruction* inst, uint32_t in_operand_index); + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_ID_USE_DESCRIPTOR_H_ diff --git a/third_party/spirv-tools/source/fuzz/instruction_descriptor.cpp b/third_party/spirv-tools/source/fuzz/instruction_descriptor.cpp new file mode 100644 index 0000000000..c0cc5e52cd --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/instruction_descriptor.cpp @@ -0,0 +1,127 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/instruction_descriptor.h" + +namespace spvtools { +namespace fuzz { + +opt::Instruction* FindInstruction( + const protobufs::InstructionDescriptor& instruction_descriptor, + spvtools::opt::IRContext* context) { + for (auto& function : *context->module()) { + for (auto& block : function) { + bool found_base = + block.id() == instruction_descriptor.base_instruction_result_id(); + uint32_t num_ignored = 0; + for (auto& instruction : block) { + if (instruction.HasResultId() && + instruction.result_id() == + instruction_descriptor.base_instruction_result_id()) { + assert(!found_base && + "It should not be possible to find the base instruction " + "multiple times."); + found_base = true; + assert(num_ignored == 0 && + "The skipped instruction count should only be incremented " + "after the instruction base has been found."); + } + if (found_base && + instruction.opcode() == + instruction_descriptor.target_instruction_opcode()) { + if (num_ignored == instruction_descriptor.num_opcodes_to_ignore()) { + return &instruction; + } + num_ignored++; + } + } + if (found_base) { + // We found the base instruction, but did not find the target + // instruction in the same block. + return nullptr; + } + } + } + return nullptr; +} + +protobufs::InstructionDescriptor MakeInstructionDescriptor( + uint32_t base_instruction_result_id, SpvOp target_instruction_opcode, + uint32_t num_opcodes_to_ignore) { + protobufs::InstructionDescriptor result; + result.set_base_instruction_result_id(base_instruction_result_id); + result.set_target_instruction_opcode(target_instruction_opcode); + result.set_num_opcodes_to_ignore(num_opcodes_to_ignore); + return result; +} + +protobufs::InstructionDescriptor MakeInstructionDescriptor( + const opt::BasicBlock& block, + const opt::BasicBlock::const_iterator& inst_it) { + const SpvOp opcode = + inst_it->opcode(); // The opcode of the instruction being described. + uint32_t skip_count = 0; // The number of these opcodes we have skipped when + // searching backwards. + + // Consider instructions in the block in reverse order, starting from + // |inst_it|. + for (opt::BasicBlock::const_iterator backwards_iterator = inst_it;; + --backwards_iterator) { + if (backwards_iterator->HasResultId()) { + // As soon as we find an instruction with a result id, we can return a + // descriptor for |inst_it|. + return MakeInstructionDescriptor(backwards_iterator->result_id(), opcode, + skip_count); + } + if (backwards_iterator != inst_it && + backwards_iterator->opcode() == opcode) { + // We are skipping over an instruction with the same opcode as |inst_it|; + // we increase our skip count to reflect this. + skip_count++; + } + if (backwards_iterator == block.begin()) { + // We exit the loop when we reach the start of the block, but only after + // we have processed the first instruction in the block. + break; + } + } + // We did not find an instruction inside the block with a result id, so we use + // the block's label's id. + return MakeInstructionDescriptor(block.id(), opcode, skip_count); +} + +protobufs::InstructionDescriptor MakeInstructionDescriptor( + opt::IRContext* context, opt::Instruction* inst) { + auto block = context->get_instr_block(inst); + uint32_t base_instruction_result_id = block->id(); + uint32_t num_opcodes_to_ignore = 0; + for (auto& inst_in_block : *block) { + if (inst_in_block.HasResultId()) { + base_instruction_result_id = inst_in_block.result_id(); + num_opcodes_to_ignore = 0; + } + if (&inst_in_block == inst) { + return MakeInstructionDescriptor(base_instruction_result_id, + inst->opcode(), num_opcodes_to_ignore); + } + if (inst_in_block.opcode() == inst->opcode()) { + num_opcodes_to_ignore++; + } + } + assert(false && "No matching instruction was found."); + return protobufs::InstructionDescriptor(); +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/instruction_descriptor.h b/third_party/spirv-tools/source/fuzz/instruction_descriptor.h new file mode 100644 index 0000000000..2ccd15a232 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/instruction_descriptor.h @@ -0,0 +1,53 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_INSTRUCTION_DESCRIPTOR_H_ +#define SOURCE_FUZZ_INSTRUCTION_DESCRIPTOR_H_ + +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "source/opt/basic_block.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace fuzz { + +// Looks for an instruction in |context| corresponding to |descriptor|. +// Returns |nullptr| if no such instruction can be found. +opt::Instruction* FindInstruction( + const protobufs::InstructionDescriptor& instruction_descriptor, + opt::IRContext* context); + +// Creates an InstructionDescriptor protobuf message from the given +// components. See the protobuf definition for details of what these +// components mean. +protobufs::InstructionDescriptor MakeInstructionDescriptor( + uint32_t base_instruction_result_id, SpvOp target_instruction_opcode, + uint32_t num_opcodes_to_ignore); + +// Returns an instruction descriptor that describing the instruction at +// |inst_it|, which must be inside |block|. The descriptor will be with +// respect to the first instruction at or before |inst_it| that has a result +// id. +protobufs::InstructionDescriptor MakeInstructionDescriptor( + const opt::BasicBlock& block, + const opt::BasicBlock::const_iterator& inst_it); + +// Returns an InstructionDescriptor that describes the given instruction |inst|. +protobufs::InstructionDescriptor MakeInstructionDescriptor( + opt::IRContext* context, opt::Instruction* inst); + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_INSTRUCTION_DESCRIPTOR_H_ diff --git a/third_party/spirv-tools/source/fuzz/instruction_message.cpp b/third_party/spirv-tools/source/fuzz/instruction_message.cpp new file mode 100644 index 0000000000..44777aede3 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/instruction_message.cpp @@ -0,0 +1,68 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/instruction_message.h" + +#include "source/fuzz/fuzzer_util.h" + +namespace spvtools { +namespace fuzz { + +protobufs::Instruction MakeInstructionMessage( + SpvOp opcode, uint32_t result_type_id, uint32_t result_id, + const opt::Instruction::OperandList& input_operands) { + protobufs::Instruction result; + result.set_opcode(opcode); + result.set_result_type_id(result_type_id); + result.set_result_id(result_id); + for (auto& operand : input_operands) { + auto operand_message = result.add_input_operand(); + operand_message->set_operand_type(static_cast(operand.type)); + for (auto operand_word : operand.words) { + operand_message->add_operand_data(operand_word); + } + } + return result; +} + +std::unique_ptr InstructionFromMessage( + opt::IRContext* ir_context, + const protobufs::Instruction& instruction_message) { + // First, update the module's id bound with respect to the new instruction, + // if it has a result id. + if (instruction_message.result_id()) { + fuzzerutil::UpdateModuleIdBound(ir_context, + instruction_message.result_id()); + } + // Now create a sequence of input operands from the input operand data in the + // protobuf message. + opt::Instruction::OperandList in_operands; + for (auto& operand_message : instruction_message.input_operand()) { + opt::Operand::OperandData operand_data; + for (auto& word : operand_message.operand_data()) { + operand_data.push_back(word); + } + in_operands.push_back( + {static_cast(operand_message.operand_type()), + operand_data}); + } + // Create and return the instruction. + return MakeUnique( + ir_context, static_cast(instruction_message.opcode()), + instruction_message.result_type_id(), instruction_message.result_id(), + in_operands); +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/instruction_message.h b/third_party/spirv-tools/source/fuzz/instruction_message.h new file mode 100644 index 0000000000..c010c2f6ac --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/instruction_message.h @@ -0,0 +1,43 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_INSTRUCTION_MESSAGE_H_ +#define SOURCE_FUZZ_INSTRUCTION_MESSAGE_H_ + +#include + +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "source/opt/instruction.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace fuzz { + +// Creates an Instruction protobuf message from its component parts. +protobufs::Instruction MakeInstructionMessage( + SpvOp opcode, uint32_t result_type_id, uint32_t result_id, + const opt::Instruction::OperandList& input_operands); + +// Creates and returns an opt::Instruction from protobuf message +// |instruction_message|, relative to |ir_context|. In the process, the module +// id bound associated with |ir_context| is updated to be at least as large as +// the result id (if any) associated with the new instruction. +std::unique_ptr InstructionFromMessage( + opt::IRContext* ir_context, + const protobufs::Instruction& instruction_message); + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_INSTRUCTION_MESSAGE_H_ diff --git a/third_party/spirv-tools/source/fuzz/protobufs/spirvfuzz_protobufs.h b/third_party/spirv-tools/source/fuzz/protobufs/spirvfuzz_protobufs.h new file mode 100644 index 0000000000..b801626bbc --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/protobufs/spirvfuzz_protobufs.h @@ -0,0 +1,52 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_SPIRVFUZZ_PROTOBUFS_H_ +#define SOURCE_FUZZ_SPIRVFUZZ_PROTOBUFS_H_ + +// This header file serves to act as a barrier between the protobuf header +// files and files that include them. It uses compiler pragmas to disable +// diagnostics, in order to ignore warnings generated during the processing +// of these header files without having to compromise on freedom from warnings +// in the rest of the project. + +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-parameter" +#elif defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#pragma GCC diagnostic ignored "-Wshadow" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#elif defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable : 4244) +#endif + +// The following should be the only place in the project where protobuf files +// are directly included. This is so that they can be compiled in a manner +// where warnings are ignored. + +#include "google/protobuf/util/json_util.h" +#include "source/fuzz/protobufs/spvtoolsfuzz.pb.h" + +#if defined(__clang__) +#pragma clang diagnostic pop +#elif defined(__GNUC__) +#pragma GCC diagnostic pop +#elif defined(_MSC_VER) +#pragma warning(pop) +#endif + +#endif // SOURCE_FUZZ_SPIRVFUZZ_PROTOBUFS_H_ diff --git a/third_party/spirv-tools/source/fuzz/protobufs/spvtoolsfuzz.proto b/third_party/spirv-tools/source/fuzz/protobufs/spvtoolsfuzz.proto new file mode 100644 index 0000000000..52a3a788ca --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/protobufs/spvtoolsfuzz.proto @@ -0,0 +1,942 @@ +// Copyright (c) 2019 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. + +// This file is specifically named spvtools_fuzz.proto so that the string +// 'spvtools_fuzz' appears in the names of global-scope symbols that protoc +// generates when targeting C++. This is to reduce the potential for name +// clashes with other globally-scoped symbols. + +syntax = "proto3"; + +package spvtools.fuzz.protobufs; + +message UInt32Pair { + + // A pair of uint32s; useful for defining mappings. + + uint32 first = 1; + + uint32 second = 2; + +} + +message InstructionDescriptor { + + // Describes an instruction in some block of a function with respect to a + // base instruction. + + // The id of an instruction after which the instruction being described is + // believed to be located. It might be the using instruction itself. + uint32 base_instruction_result_id = 1; + + // The opcode for the instruction being described. + uint32 target_instruction_opcode = 2; + + // The number of matching opcodes to skip over when searching from the base + // instruction to the instruction being described. + uint32 num_opcodes_to_ignore = 3; + +} + +message IdUseDescriptor { + + // Describes a use of an id as an input operand to an instruction in some + // block of a function. + + // Example: + // - id_of_interest = 42 + // - enclosing_instruction = ( + // base_instruction_result_id = 50, + // target_instruction_opcode = OpStore + // num_opcodes_to_ignore = 7 + // ) + // - in_operand_index = 1 + // represents a use of id 42 as input operand 1 to an OpStore instruction, + // such that the OpStore instruction can be found in the same basic block as + // the instruction with result id 50, and in particular is the 8th OpStore + // instruction found from instruction 50 onwards (i.e. 7 OpStore + // instructions are skipped). + + // An id that we would like to be able to find a use of. + uint32 id_of_interest = 1; + + // The input operand index at which the use is expected. + InstructionDescriptor enclosing_instruction = 2; + + uint32 in_operand_index = 3; + +} + +message DataDescriptor { + + // Represents a data element that can be accessed from an id, by walking the + // type hierarchy via a sequence of 0 or more indices. + // + // Very similar to a UniformBufferElementDescriptor, except that a + // DataDescriptor is rooted at the id of a scalar or composite. + + // The object being accessed - a scalar or composite + uint32 object = 1; + + // 0 or more indices, used to index into a composite object + repeated uint32 index = 2; + +} + +message UniformBufferElementDescriptor { + + // Represents a data element inside a uniform buffer. The element is + // specified via (a) the result id of a uniform variable in which the element + // is contained, and (b) a series of indices that need to be followed to get + // to the element (via fields and array/vector indices). + // + // Example: suppose there is a uniform variable with descriptor set 7 and + // binding 9, and that the uniform variable has the following type (using + // GLSL-like syntax): + // + // struct S { + // float f; + // vec3 g; + // int4 h[10]; + // }; + // + // Then: + // - (7, 9, [0]) describes the 'f' field. + // - (7, 9, [1,1]) describes the y component of the 'g' field. + // - (7, 9, [2,7,3]) describes the w component of element 7 of the 'h' field + + // The descriptor set and binding associated with a uniform variable. + uint32 descriptor_set = 1; + uint32 binding = 2; + + // An ordered sequence of indices through composite structures in the + // uniform buffer. + repeated uint32 index = 3; + +} + +message InstructionOperand { + + // Represents an operand to a SPIR-V instruction. + + // The type of the operand. + uint32 operand_type = 1; + + // The data associated with the operand. For most operands (e.g. ids, + // storage classes and literals) this will be a single word. + repeated uint32 operand_data = 2; + +} + +message Instruction { + + // Represents a SPIR-V instruction. + + // The instruction's opcode (e.g. OpLabel). + uint32 opcode = 1; + + // The id of the instruction's result type; 0 if there is no result type. + uint32 result_type_id = 2; + + // The id of the instruction's result; 0 if there is no result. + uint32 result_id = 3; + + // Zero or more input operands. + repeated InstructionOperand input_operand = 4; + +} + +message FactSequence { + repeated Fact fact = 1; +} + +message Fact { + oneof fact { + // Order the fact options by numeric id (rather than alphabetically). + FactConstantUniform constant_uniform_fact = 1; + FactDataSynonym data_synonym_fact = 2; + FactBlockIsDead block_is_dead_fact = 3; + FactFunctionIsLivesafe function_is_livesafe_fact = 4; + FactValueOfVariableIsArbitrary value_of_variable_is_arbitrary = 5; + } +} + +// Keep fact message types in alphabetical order: + +message FactConstantUniform { + + // Records the fact that a uniform buffer element is guaranteed to be equal + // to a particular constant value. spirv-fuzz can use such guarantees to + // obfuscate code, e.g. to manufacture an expression that will (due to the + // guarantee) evaluate to a particular value at runtime but in a manner that + // cannot be predicted at compile-time. + + // An element of a uniform buffer + UniformBufferElementDescriptor uniform_buffer_element_descriptor = 1; + + // The words of the associated constant + repeated uint32 constant_word = 2; + +} + +message FactDataSynonym { + + // Records the fact that the data held in two data descriptors are guaranteed + // to be equal. spirv-fuzz can use this to replace uses of one piece of data + // with a known-to-be-equal piece of data. + + // Data descriptors guaranteed to hold identical data. + DataDescriptor data1 = 1; + + DataDescriptor data2 = 2; + +} + +message FactBlockIsDead { + + // Records the fact that a block is guaranteed to be dynamically unreachable. + // This is useful because it informs the fuzzer that rather arbitrary changes + // can be made to this block. + + uint32 block_id = 1; +} + +message FactFunctionIsLivesafe { + + // Records the fact that a function is guaranteed to be "livesafe", meaning + // that it will not make out-of-bounds accesses, does not contain reachable + // OpKill or OpUnreachable instructions, does not contain loops that will + // execute for large numbers of iterations, and only invokes other livesafe + // functions. + + uint32 function_id = 1; +} + +message FactValueOfVariableIsArbitrary { + + // Records the fact that the value stored in the variable or function + // parameter with the given id can be arbitrary: the module's observable + // behaviour does not depend on it. This means that arbitrary stores can be + // made to the variable, and that nothing can be guaranteed about values + // loaded from the variable. + + // The result id of an OpVariable instruction, or an OpFunctionParameter + // instruction with pointer type + uint32 variable_id = 1; +} + +message AccessChainClampingInfo { + + // When making a function livesafe it is necessary to clamp the indices that + // occur as operands to access chain instructions so that they are guaranteed + // to be in bounds. This message type allows an access chain instruction to + // have an associated sequence of ids that are reserved for comparing an + // access chain index with a bound (e.g. an array size), and selecting + // between the access chain index (if it is within bounds) and the bound (if + // it is not). + // + // This allows turning an instruction of the form: + // + // %result = OpAccessChain %type %object ... %index ... + // + // into: + // + // %t1 = OpULessThanEqual %bool %index %bound_minus_one + // %t2 = OpSelect %int_type %t1 %index %bound_minus_one + // %result = OpAccessChain %type %object ... %t2 ... + + // The result id of an OpAccessChain or OpInBoundsAccessChain instruction. + uint32 access_chain_id = 1; + + // A series of pairs of fresh ids, one per access chain index, for the results + // of a compare instruction and a select instruction, serving the roles of %t1 + // and %t2 in the above example. + repeated UInt32Pair compare_and_select_ids = 2; + +} + +message LoopLimiterInfo { + + // Structure capturing the information required to manipulate a loop limiter + // at a loop header. + + // The header for the loop. + uint32 loop_header_id = 1; + + // A fresh id into which the loop limiter's current value can be loaded. + uint32 load_id = 2; + + // A fresh id that can be used to increment the loaded value by 1. + uint32 increment_id = 3; + + // A fresh id that can be used to compare the loaded value with the loop + // limit. + uint32 compare_id = 4; + + // A fresh id that can be used to compute the conjunction or disjunction of + // an original loop exit condition with |compare_id|, if the loop's back edge + // block can conditionally exit the loop. + uint32 logical_op_id = 5; + + // A sequence of ids suitable for extending OpPhi instructions of the loop + // merge block if it did not previously have an incoming edge from the loop + // back edge block. + repeated uint32 phi_id = 6; + +} + +message TransformationSequence { + repeated Transformation transformation = 1; +} + +message Transformation { + oneof transformation { + // Order the transformation options by numeric id (rather than + // alphabetically). + TransformationMoveBlockDown move_block_down = 1; + TransformationSplitBlock split_block = 2; + TransformationAddConstantBoolean add_constant_boolean = 3; + TransformationAddConstantScalar add_constant_scalar = 4; + TransformationAddTypeBoolean add_type_boolean = 5; + TransformationAddTypeFloat add_type_float = 6; + TransformationAddTypeInt add_type_int = 7; + TransformationAddDeadBreak add_dead_break = 8; + TransformationReplaceBooleanConstantWithConstantBinary + replace_boolean_constant_with_constant_binary = 9; + TransformationAddTypePointer add_type_pointer = 10; + TransformationReplaceConstantWithUniform replace_constant_with_uniform = 11; + TransformationAddDeadContinue add_dead_continue = 12; + TransformationCopyObject copy_object = 13; + TransformationReplaceIdWithSynonym replace_id_with_synonym = 14; + TransformationSetSelectionControl set_selection_control = 15; + TransformationCompositeConstruct composite_construct = 16; + TransformationSetLoopControl set_loop_control = 17; + TransformationSetFunctionControl set_function_control = 18; + TransformationAddNoContractionDecoration add_no_contraction_decoration = 19; + TransformationSetMemoryOperandsMask set_memory_operands_mask = 20; + TransformationCompositeExtract composite_extract = 21; + TransformationVectorShuffle vector_shuffle = 22; + TransformationOutlineFunction outline_function = 23; + TransformationMergeBlocks merge_blocks = 24; + TransformationAddTypeVector add_type_vector = 25; + TransformationAddTypeArray add_type_array = 26; + TransformationAddTypeMatrix add_type_matrix = 27; + TransformationAddTypeStruct add_type_struct = 28; + TransformationAddTypeFunction add_type_function = 29; + TransformationAddConstantComposite add_constant_composite = 30; + TransformationAddGlobalVariable add_global_variable = 31; + TransformationAddGlobalUndef add_global_undef = 32; + TransformationAddFunction add_function = 33; + TransformationAddDeadBlock add_dead_block = 34; + // Add additional option using the next available number. + } +} + +// Keep transformation message types in alphabetical order: + +message TransformationAddConstantBoolean { + + // Supports adding the constants true and false to a module, which may be + // necessary in order to enable other transformations if they are not present. + + uint32 fresh_id = 1; + bool is_true = 2; + +} + +message TransformationAddConstantComposite { + + // Adds a constant of the given composite type to the module. + + // Fresh id for the composite + uint32 fresh_id = 1; + + // A composite type id + uint32 type_id = 2; + + // Constituent ids for the composite + repeated uint32 constituent_id = 3; + +} + +message TransformationAddConstantScalar { + + // Adds a constant of the given scalar type. + + // Id for the constant + uint32 fresh_id = 1; + + // Id for the scalar type of the constant + uint32 type_id = 2; + + // Value of the constant + repeated uint32 word = 3; + +} + +message TransformationAddDeadBlock { + + // Adds a new block to the module that is statically reachable from an + // existing block, but dynamically unreachable. + + // Fresh id for the dead block + uint32 fresh_id = 1; + + // Id of an existing block terminated with OpBranch, such that this OpBranch + // can be replaced with an OpBranchConditional to its exiting successor or + // the dead block + uint32 existing_block = 2; + + // Determines whether the condition associated with the OpBranchConditional + // is true or false + bool condition_value = 3; + +} + +message TransformationAddDeadBreak { + + // A transformation that turns a basic block that unconditionally branches to + // its successor into a block that potentially breaks out of a structured + // control flow construct, but in such a manner that the break cannot actually + // be taken. + + // The block to break from + uint32 from_block = 1; + + // The merge block to break to + uint32 to_block = 2; + + // Determines whether the break condition is true or false + bool break_condition_value = 3; + + // A sequence of ids suitable for extending OpPhi instructions as a result of + // the new break edge + repeated uint32 phi_id = 4; + +} + +message TransformationAddDeadContinue { + + // A transformation that turns a basic block appearing in a loop and that + // unconditionally branches to its successor into a block that potentially + // branches to the continue target of the loop, but in such a manner that the + // continue branch cannot actually be taken. + + // The block to continue from + uint32 from_block = 1; + + // Determines whether the continue condition is true or false + bool continue_condition_value = 2; + + // A sequence of ids suitable for extending OpPhi instructions as a result of + // the new break edge + repeated uint32 phi_id = 3; + +} + +message TransformationAddFunction { + + // Adds a SPIR-V function to the module. + + // The series of instructions that comprise the function. + repeated Instruction instruction = 1; + + // True if and only if the given function should be made livesafe (see + // FactFunctionIsLivesafe for definition). + bool is_livesafe = 2; + + // Fresh id for a new variable that will serve as a "loop limiter" for the + // function; only relevant if |is_livesafe| holds. + uint32 loop_limiter_variable_id = 3; + + // Id of an existing unsigned integer constant providing the maximum value + // that the loop limiter can reach before the loop is broken from; only + // relevant if |is_livesafe| holds. + uint32 loop_limit_constant_id = 4; + + // Fresh ids for each loop in the function that allow the loop limiter to be + // manipulated; only relevant if |is_livesafe| holds. + repeated LoopLimiterInfo loop_limiter_info = 5; + + // Id of an existing global value with the same return type as the function + // that can be used to replace OpKill and OpReachable instructions with + // ReturnValue instructions. Ignored if the function has void return type. + uint32 kill_unreachable_return_value_id = 6; + + // A mapping (represented as a sequence) from every access chain result id in + // the function to the ids required to clamp its indices to ensure they are in + // bounds. + repeated AccessChainClampingInfo access_chain_clamping_info = 7; + +} + +message TransformationAddGlobalUndef { + + // Adds an undefined value of a given type to the module at global scope. + + // Fresh id for the undefined value + uint32 fresh_id = 1; + + // The type of the undefined value + uint32 type_id = 2; + +} + +message TransformationAddGlobalVariable { + + // Adds a global variable of the given type to the module, with Private + // storage class and optionally with an initializer. + + // Fresh id for the global variable + uint32 fresh_id = 1; + + // The type of the global variable + uint32 type_id = 2; + + // Optional initializer; 0 if there is no initializer + uint32 initializer_id = 3; + + // True if and only if the value of the variable should be regarded, in + // general, as totally unknown and subject to change (even if, due to an + // initializer, the original value is known). This is the case for variables + // added when a module is donated, for example, and means that stores to such + // variables can be performed in an arbitrary fashion. + bool value_is_arbitrary = 4; + +} + +message TransformationAddNoContractionDecoration { + + // Applies OpDecorate NoContraction to the given result id + + // Result id to be decorated + uint32 result_id = 1; + +} + +message TransformationAddTypeArray { + + // Adds an array type of the given element type and size to the module + + // Fresh id for the array type + uint32 fresh_id = 1; + + // The array's element type + uint32 element_type_id = 2; + + // The array's size + uint32 size_id = 3; + +} + +message TransformationAddTypeBoolean { + + // Adds OpTypeBool to the module + + // Id to be used for the type + uint32 fresh_id = 1; + +} + +message TransformationAddTypeFloat { + + // Adds OpTypeFloat to the module with the given width + + // Id to be used for the type + uint32 fresh_id = 1; + + // Floating-point width + uint32 width = 2; + +} + +message TransformationAddTypeFunction { + + // Adds a function type to the module + + // Fresh id for the function type + uint32 fresh_id = 1; + + // The function's return type + uint32 return_type_id = 2; + + // The function's argument types + repeated uint32 argument_type_id = 3; + +} + +message TransformationAddTypeInt { + + // Adds OpTypeInt to the module with the given width and signedness + + // Id to be used for the type + uint32 fresh_id = 1; + + // Integer width + uint32 width = 2; + + // True if and only if this is a signed type + bool is_signed = 3; + +} + +message TransformationAddTypeMatrix { + + // Adds a matrix type to the module + + // Fresh id for the matrix type + uint32 fresh_id = 1; + + // The matrix's column type, which must be a floating-point vector (as per + // the "data rules" in the SPIR-V specification). + uint32 column_type_id = 2; + + // The matrix's column count + uint32 column_count = 3; + +} + +message TransformationAddTypePointer { + + // Adds OpTypePointer to the module, with the given storage class and base + // type + + // Id to be used for the type + uint32 fresh_id = 1; + + // Pointer storage class + uint32 storage_class = 2; + + // Id of the base type for the pointer + uint32 base_type_id = 3; + +} + +message TransformationAddTypeStruct { + + // Adds a struct type to the module + + // Fresh id for the struct type + uint32 fresh_id = 1; + + // The struct's member types + repeated uint32 member_type_id = 3; + +} + +message TransformationAddTypeVector { + + // Adds a vector type to the module + + // Fresh id for the vector type + uint32 fresh_id = 1; + + // The vector's component type + uint32 component_type_id = 2; + + // The vector's component count + uint32 component_count = 3; + +} + +message TransformationCompositeConstruct { + + // A transformation that introduces an OpCompositeConstruct instruction to + // make a composite object. + + // Id of the type of the composite that is to be constructed + uint32 composite_type_id = 1; + + // Ids of the objects that will form the components of the composite + repeated uint32 component = 2; + + // A descriptor for an instruction in a block before which the new + // OpCompositeConstruct instruction should be inserted + InstructionDescriptor instruction_to_insert_before = 3; + + // A fresh id for the composite object + uint32 fresh_id = 4; + +} + +message TransformationCompositeExtract { + + // A transformation that adds an instruction to extract an element from a + // composite. + + // A descriptor for an instruction in a block before which the new + // OpCompositeExtract instruction should be inserted + InstructionDescriptor instruction_to_insert_before = 1; + + // Result id for the extract operation. + uint32 fresh_id = 2; + + // Id of the composite from which data is to be extracted. + uint32 composite_id = 3; + + // Indices that indicate which part of the composite should be extracted. + repeated uint32 index = 4; + +} + +message TransformationCopyObject { + + // A transformation that introduces an OpCopyObject instruction to make a + // copy of an object. + + // Id of the object to be copied + uint32 object = 1; + + // A descriptor for an instruction in a block before which the new + // OpCopyObject instruction should be inserted + InstructionDescriptor instruction_to_insert_before = 2; + + // A fresh id for the copied object + uint32 fresh_id = 3; + +} + +message TransformationMergeBlocks { + + // A transformation that merges a block with its predecessor. + + // The id of the block that is to be merged with its predecessor; the merged + // block will have the *predecessor's* id. + uint32 block_id = 1; + +} + +message TransformationMoveBlockDown { + + // A transformation that moves a basic block to be one position lower in + // program order. + + // The id of the block to move down. + uint32 block_id = 1; +} + +message TransformationOutlineFunction { + + // A transformation that outlines a single-entry single-exit region of a + // control flow graph into a separate function, and replaces the region with + // a call to that function. + + // Id of the entry block of the single-entry single-exit region to be outlined + uint32 entry_block = 1; + + // Id of the exit block of the single-entry single-exit region to be outlined + uint32 exit_block = 2; + + // Id of a struct that will store the return values of the new function + uint32 new_function_struct_return_type_id = 3; + + // A fresh id for the type of the outlined function + uint32 new_function_type_id = 4; + + // A fresh id for the outlined function itself + uint32 new_function_id = 5; + + // A fresh id to represent the block in the outlined function that represents + // the first block of the outlined region. + uint32 new_function_region_entry_block = 6; + + // A fresh id for the result of the OpFunctionCall instruction that will call + // the outlined function + uint32 new_caller_result_id = 7; + + // A fresh id to capture the return value of the outlined function - the + // argument to OpReturn + uint32 new_callee_result_id = 8; + + // Ids defined outside the region and used inside the region will become + // parameters to the outlined function. This is a mapping from used ids to + // fresh parameter ids. + repeated UInt32Pair input_id_to_fresh_id = 9; + + // Ids defined inside the region and used outside the region will become + // fresh ids defined by the outlined function, which get copied into the + // function's struct return value and then copied into their destination ids + // by the caller. This is a mapping from original ids to corresponding fresh + // ids. + repeated UInt32Pair output_id_to_fresh_id = 10; + +} + +message TransformationReplaceBooleanConstantWithConstantBinary { + + // A transformation to capture replacing a use of a boolean constant with + // binary operation on two constant values + + // A descriptor for the boolean constant id we would like to replace + IdUseDescriptor id_use_descriptor = 1; + + // Id for the constant to be used on the LHS of the comparision + uint32 lhs_id = 2; + + // Id for the constant to be used on the RHS of the comparision + uint32 rhs_id = 3; + + // Opcode for binary operator + uint32 opcode = 4; + + // Id that will store the result of the binary operation instruction + uint32 fresh_id_for_binary_operation = 5; + +} + +message TransformationReplaceConstantWithUniform { + + // Replaces a use of a constant id with the result of a load from an + // element of uniform buffer known to hold the same value as the constant + + // A descriptor for the id we would like to replace + IdUseDescriptor id_use_descriptor = 1; + + // Uniform descriptor to identify which uniform value to choose + UniformBufferElementDescriptor uniform_descriptor = 2; + + // Id that will store the result of an access chain + uint32 fresh_id_for_access_chain = 3; + + // Id that will store the result of a load + uint32 fresh_id_for_load = 4; + +} + +message TransformationReplaceIdWithSynonym { + + // Replaces a use of an id with an id that is known to be synonymous, e.g. + // because it was obtained via applying OpCopyObject + + // The id use that is to be replaced + IdUseDescriptor id_use_descriptor = 1; + + // The synonymous id + uint32 synonymous_id = 2; + +} + +message TransformationSetFunctionControl { + + // A transformation that sets the function control operand of an OpFunction + // instruction. + + // The result id of an OpFunction instruction + uint32 function_id = 1; + + // The value to which the 'function control' operand should be set. + uint32 function_control = 2; + +} + +message TransformationSetLoopControl { + + // A transformation that sets the loop control operand of an OpLoopMerge + // instruction. + + // The id of a basic block that should contain OpLoopMerge + uint32 block_id = 1; + + // The value to which the 'loop control' operand should be set. + // This must be a legal loop control mask. + uint32 loop_control = 2; + + // Provides a peel count value for the loop. Used if and only if the + // PeelCount bit is set. Must be zero if the PeelCount bit is not set (can + // still be zero if this bit is set). + uint32 peel_count = 3; + + // Provides a partial count value for the loop. Used if and only if the + // PartialCount bit is set. Must be zero if the PartialCount bit is not set + // (can still be zero if this bit is set). + uint32 partial_count = 4; + +} + +message TransformationSetMemoryOperandsMask { + + // A transformation that sets the memory operands mask of a memory access + // instruction. + + // A descriptor for a memory access instruction, e.g. an OpLoad + InstructionDescriptor memory_access_instruction = 1; + + // A mask of memory operands to be applied to the instruction. It must be the + // same as the original mask, except that Volatile can be added, and + // Nontemporal can be added or removed. + uint32 memory_operands_mask = 2; + + // Some memory access instructions allow more than one mask to be specified; + // this field indicates which mask should be set + uint32 memory_operands_mask_index = 3; + +} + +message TransformationSetSelectionControl { + + // A transformation that sets the selection control operand of an + // OpSelectionMerge instruction. + + // The id of a basic block that should contain OpSelectionMerge + uint32 block_id = 1; + + // The value to which the 'selection control' operand should be set. + // Although technically 'selection control' is a literal mask that can be + // some combination of 'None', 'Flatten' and 'DontFlatten', the combination + // 'Flatten | DontFlatten' does not make sense and is not allowed here. + uint32 selection_control = 2; + +} + +message TransformationSplitBlock { + + // A transformation that splits a basic block into two basic blocks + + // A descriptor for an instruction such that the block containing the + // described instruction should be split right before the instruction. + InstructionDescriptor instruction_to_split_before = 1; + + // An id that must not yet be used by the module to which this transformation + // is applied. Rather than having the transformation choose a suitable id on + // application, we require the id to be given upfront in order to facilitate + // reducing fuzzed shaders by removing transformations. The reason is that + // future transformations may refer to the fresh id introduced by this + // transformation, and if we end up changing what that id is, due to removing + // earlier transformations, it may inhibit later transformations from + // applying. + uint32 fresh_id = 2; + +} + +message TransformationVectorShuffle { + + // A transformation that adds a vector shuffle instruction. + + // A descriptor for an instruction in a block before which the new + // OpVectorShuffle instruction should be inserted + InstructionDescriptor instruction_to_insert_before = 1; + + // Result id for the shuffle operation. + uint32 fresh_id = 2; + + // Id of the first vector operand. + uint32 vector1 = 3; + + // Id of the second vector operand. + uint32 vector2 = 4; + + // Indices that indicate which components of the input vectors should be used. + repeated uint32 component = 5; + +} diff --git a/third_party/spirv-tools/source/fuzz/pseudo_random_generator.cpp b/third_party/spirv-tools/source/fuzz/pseudo_random_generator.cpp new file mode 100644 index 0000000000..9643264a2a --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/pseudo_random_generator.cpp @@ -0,0 +1,47 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/pseudo_random_generator.h" + +#include + +namespace spvtools { +namespace fuzz { + +PseudoRandomGenerator::PseudoRandomGenerator(uint32_t seed) : mt_(seed) {} + +PseudoRandomGenerator::~PseudoRandomGenerator() = default; + +uint32_t PseudoRandomGenerator::RandomUint32(uint32_t bound) { + assert(bound > 0 && "Bound must be positive"); + return static_cast( + std::uniform_int_distribution<>(0, bound - 1)(mt_)); +} + +bool PseudoRandomGenerator::RandomBool() { + return static_cast(std::uniform_int_distribution<>(0, 1)(mt_)); +} + +uint32_t PseudoRandomGenerator::RandomPercentage() { + // We use 101 because we want a result in the closed interval [0, 100], and + // RandomUint32 is not inclusive of its bound. + return RandomUint32(101); +} + +double PseudoRandomGenerator::RandomDouble() { + return std::uniform_real_distribution(0.0, 1.0)(mt_); +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/pseudo_random_generator.h b/third_party/spirv-tools/source/fuzz/pseudo_random_generator.h new file mode 100644 index 0000000000..d2f529205f --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/pseudo_random_generator.h @@ -0,0 +1,47 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_PSEUDO_RANDOM_GENERATOR_H_ +#define SOURCE_FUZZ_PSEUDO_RANDOM_GENERATOR_H_ + +#include + +#include "source/fuzz/random_generator.h" + +namespace spvtools { +namespace fuzz { + +// Generates random data from a pseudo-random number generator. +class PseudoRandomGenerator : public RandomGenerator { + public: + explicit PseudoRandomGenerator(uint32_t seed); + + ~PseudoRandomGenerator() override; + + uint32_t RandomUint32(uint32_t bound) override; + + uint32_t RandomPercentage() override; + + bool RandomBool() override; + + double RandomDouble() override; + + private: + std::mt19937 mt_; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_PSEUDO_RANDOM_GENERATOR_H_ diff --git a/third_party/spirv-tools/source/fuzz/random_generator.cpp b/third_party/spirv-tools/source/fuzz/random_generator.cpp new file mode 100644 index 0000000000..9ec4845dfd --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/random_generator.cpp @@ -0,0 +1,25 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/random_generator.h" + +namespace spvtools { +namespace fuzz { + +RandomGenerator::RandomGenerator() = default; + +RandomGenerator::~RandomGenerator() = default; + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/random_generator.h b/third_party/spirv-tools/source/fuzz/random_generator.h new file mode 100644 index 0000000000..9c467983d6 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/random_generator.h @@ -0,0 +1,45 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_RANDOM_GENERATOR_H_ +#define SOURCE_FUZZ_RANDOM_GENERATOR_H_ + +#include + +namespace spvtools { +namespace fuzz { + +class RandomGenerator { + public: + RandomGenerator(); + + virtual ~RandomGenerator(); + + // Returns a value in the half-open interval [0, bound). + virtual uint32_t RandomUint32(uint32_t bound) = 0; + + // Returns a value in the closed interval [0, 100]. + virtual uint32_t RandomPercentage() = 0; + + // Returns a boolean. + virtual bool RandomBool() = 0; + + // Returns a double in the closed interval [0, 1] + virtual double RandomDouble() = 0; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_RANDOM_GENERATOR_H_ diff --git a/third_party/spirv-tools/source/fuzz/replayer.cpp b/third_party/spirv-tools/source/fuzz/replayer.cpp new file mode 100644 index 0000000000..398ce59501 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/replayer.cpp @@ -0,0 +1,134 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/replayer.h" + +#include + +#include "source/fuzz/fact_manager.h" +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "source/fuzz/transformation.h" +#include "source/fuzz/transformation_add_constant_boolean.h" +#include "source/fuzz/transformation_add_constant_scalar.h" +#include "source/fuzz/transformation_add_dead_break.h" +#include "source/fuzz/transformation_add_type_boolean.h" +#include "source/fuzz/transformation_add_type_float.h" +#include "source/fuzz/transformation_add_type_int.h" +#include "source/fuzz/transformation_add_type_pointer.h" +#include "source/fuzz/transformation_move_block_down.h" +#include "source/fuzz/transformation_replace_boolean_constant_with_constant_binary.h" +#include "source/fuzz/transformation_replace_constant_with_uniform.h" +#include "source/fuzz/transformation_split_block.h" +#include "source/opt/build_module.h" +#include "source/util/make_unique.h" + +namespace spvtools { +namespace fuzz { + +struct Replayer::Impl { + explicit Impl(spv_target_env env, bool validate) + : target_env(env), validate_during_replay(validate) {} + + const spv_target_env target_env; // Target environment. + MessageConsumer consumer; // Message consumer. + + const bool validate_during_replay; // Controls whether the validator should + // be run after every replay step. +}; + +Replayer::Replayer(spv_target_env env, bool validate_during_replay) + : impl_(MakeUnique(env, validate_during_replay)) {} + +Replayer::~Replayer() = default; + +void Replayer::SetMessageConsumer(MessageConsumer c) { + impl_->consumer = std::move(c); +} + +Replayer::ReplayerResultStatus Replayer::Run( + const std::vector& binary_in, + const protobufs::FactSequence& initial_facts, + const protobufs::TransformationSequence& transformation_sequence_in, + std::vector* binary_out, + protobufs::TransformationSequence* transformation_sequence_out) const { + // Check compatibility between the library version being linked with and the + // header files being used. + GOOGLE_PROTOBUF_VERIFY_VERSION; + + spvtools::SpirvTools tools(impl_->target_env); + if (!tools.IsValid()) { + impl_->consumer(SPV_MSG_ERROR, nullptr, {}, + "Failed to create SPIRV-Tools interface; stopping."); + return Replayer::ReplayerResultStatus::kFailedToCreateSpirvToolsInterface; + } + + // Initial binary should be valid. + if (!tools.Validate(&binary_in[0], binary_in.size())) { + impl_->consumer(SPV_MSG_INFO, nullptr, {}, + "Initial binary is invalid; stopping."); + return Replayer::ReplayerResultStatus::kInitialBinaryInvalid; + } + + // Build the module from the input binary. + std::unique_ptr ir_context = BuildModule( + impl_->target_env, impl_->consumer, binary_in.data(), binary_in.size()); + assert(ir_context); + + // For replay validation, we track the last valid SPIR-V binary that was + // observed. Initially this is the input binary. + std::vector last_valid_binary; + if (impl_->validate_during_replay) { + last_valid_binary = binary_in; + } + + FactManager fact_manager; + fact_manager.AddFacts(impl_->consumer, initial_facts, ir_context.get()); + + // Consider the transformation proto messages in turn. + for (auto& message : transformation_sequence_in.transformation()) { + auto transformation = Transformation::FromMessage(message); + + // Check whether the transformation can be applied. + if (transformation->IsApplicable(ir_context.get(), fact_manager)) { + // The transformation is applicable, so apply it, and copy it to the + // sequence of transformations that were applied. + transformation->Apply(ir_context.get(), &fact_manager); + *transformation_sequence_out->add_transformation() = message; + + if (impl_->validate_during_replay) { + std::vector binary_to_validate; + ir_context->module()->ToBinary(&binary_to_validate, false); + + // Check whether the latest transformation led to a valid binary. + if (!tools.Validate(&binary_to_validate[0], + binary_to_validate.size())) { + impl_->consumer(SPV_MSG_INFO, nullptr, {}, + "Binary became invalid during replay (set a " + "breakpoint to inspect); stopping."); + return Replayer::ReplayerResultStatus::kReplayValidationFailure; + } + + // The binary was valid, so it becomes the latest valid binary. + last_valid_binary = std::move(binary_to_validate); + } + } + } + + // Write out the module as a binary. + ir_context->module()->ToBinary(binary_out, false); + return Replayer::ReplayerResultStatus::kComplete; +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/replayer.h b/third_party/spirv-tools/source/fuzz/replayer.h new file mode 100644 index 0000000000..1d58baeb7d --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/replayer.h @@ -0,0 +1,74 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_REPLAYER_H_ +#define SOURCE_FUZZ_REPLAYER_H_ + +#include +#include + +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "spirv-tools/libspirv.hpp" + +namespace spvtools { +namespace fuzz { + +// Transforms a SPIR-V module into a semantically equivalent SPIR-V module by +// applying a series of pre-defined transformations. +class Replayer { + public: + // Possible statuses that can result from running the replayer. + enum ReplayerResultStatus { + kComplete, + kFailedToCreateSpirvToolsInterface, + kInitialBinaryInvalid, + kReplayValidationFailure, + }; + + // Constructs a replayer from the given target environment. + explicit Replayer(spv_target_env env, bool validate_during_replay); + + // Disables copy/move constructor/assignment operations. + Replayer(const Replayer&) = delete; + Replayer(Replayer&&) = delete; + Replayer& operator=(const Replayer&) = delete; + Replayer& operator=(Replayer&&) = delete; + + ~Replayer(); + + // Sets the message consumer to the given |consumer|. The |consumer| will be + // invoked once for each message communicated from the library. + void SetMessageConsumer(MessageConsumer consumer); + + // Transforms |binary_in| to |binary_out| by attempting to apply the + // transformations from |transformation_sequence_in|. Initial facts about the + // input binary and the context in which it will execute are provided via + // |initial_facts|. The transformations that were successfully applied are + // returned via |transformation_sequence_out|. + ReplayerResultStatus Run( + const std::vector& binary_in, + const protobufs::FactSequence& initial_facts, + const protobufs::TransformationSequence& transformation_sequence_in, + std::vector* binary_out, + protobufs::TransformationSequence* transformation_sequence_out) const; + + private: + struct Impl; // Opaque struct for holding internal data. + std::unique_ptr impl_; // Unique pointer to internal data. +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_REPLAYER_H_ diff --git a/third_party/spirv-tools/source/fuzz/shrinker.cpp b/third_party/spirv-tools/source/fuzz/shrinker.cpp new file mode 100644 index 0000000000..1bb92f1007 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/shrinker.cpp @@ -0,0 +1,244 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/shrinker.h" + +#include + +#include "source/fuzz/pseudo_random_generator.h" +#include "source/fuzz/replayer.h" +#include "source/spirv_fuzzer_options.h" +#include "source/util/make_unique.h" + +namespace spvtools { +namespace fuzz { + +namespace { + +// A helper to get the size of a protobuf transformation sequence in a less +// verbose manner. +uint32_t NumRemainingTransformations( + const protobufs::TransformationSequence& transformation_sequence) { + return static_cast(transformation_sequence.transformation_size()); +} + +// A helper to return a transformation sequence identical to |transformations|, +// except that a chunk of size |chunk_size| starting from |chunk_index| x +// |chunk_size| is removed (or as many transformations as available if the whole +// chunk is not). +protobufs::TransformationSequence RemoveChunk( + const protobufs::TransformationSequence& transformations, + uint32_t chunk_index, uint32_t chunk_size) { + uint32_t lower = chunk_index * chunk_size; + uint32_t upper = std::min((chunk_index + 1) * chunk_size, + NumRemainingTransformations(transformations)); + assert(lower < upper); + assert(upper <= NumRemainingTransformations(transformations)); + protobufs::TransformationSequence result; + for (uint32_t j = 0; j < NumRemainingTransformations(transformations); j++) { + if (j >= lower && j < upper) { + continue; + } + protobufs::Transformation transformation = + transformations.transformation()[j]; + *result.mutable_transformation()->Add() = transformation; + } + return result; +} + +} // namespace + +struct Shrinker::Impl { + explicit Impl(spv_target_env env, uint32_t limit, bool validate) + : target_env(env), step_limit(limit), validate_during_replay(validate) {} + + const spv_target_env target_env; // Target environment. + MessageConsumer consumer; // Message consumer. + const uint32_t step_limit; // Step limit for reductions. + const bool validate_during_replay; // Determines whether to check for + // validity during the replaying of + // transformations. +}; + +Shrinker::Shrinker(spv_target_env env, uint32_t step_limit, + bool validate_during_replay) + : impl_(MakeUnique(env, step_limit, validate_during_replay)) {} + +Shrinker::~Shrinker() = default; + +void Shrinker::SetMessageConsumer(MessageConsumer c) { + impl_->consumer = std::move(c); +} + +Shrinker::ShrinkerResultStatus Shrinker::Run( + const std::vector& binary_in, + const protobufs::FactSequence& initial_facts, + const protobufs::TransformationSequence& transformation_sequence_in, + const Shrinker::InterestingnessFunction& interestingness_function, + std::vector* binary_out, + protobufs::TransformationSequence* transformation_sequence_out) const { + // Check compatibility between the library version being linked with and the + // header files being used. + GOOGLE_PROTOBUF_VERIFY_VERSION; + + spvtools::SpirvTools tools(impl_->target_env); + if (!tools.IsValid()) { + impl_->consumer(SPV_MSG_ERROR, nullptr, {}, + "Failed to create SPIRV-Tools interface; stopping."); + return Shrinker::ShrinkerResultStatus::kFailedToCreateSpirvToolsInterface; + } + + // Initial binary should be valid. + if (!tools.Validate(&binary_in[0], binary_in.size())) { + impl_->consumer(SPV_MSG_INFO, nullptr, {}, + "Initial binary is invalid; stopping."); + return Shrinker::ShrinkerResultStatus::kInitialBinaryInvalid; + } + + std::vector current_best_binary; + protobufs::TransformationSequence current_best_transformations; + + // Run a replay of the initial transformation sequence to (a) check that it + // succeeds, (b) get the binary that results from running these + // transformations, and (c) get the subsequence of the initial transformations + // that actually apply (in principle this could be a strict subsequence). + if (Replayer(impl_->target_env, impl_->validate_during_replay) + .Run(binary_in, initial_facts, transformation_sequence_in, + ¤t_best_binary, ¤t_best_transformations) != + Replayer::ReplayerResultStatus::kComplete) { + return ShrinkerResultStatus::kReplayFailed; + } + + // Check that the binary produced by applying the initial transformations is + // indeed interesting. + if (!interestingness_function(current_best_binary, 0)) { + impl_->consumer(SPV_MSG_INFO, nullptr, {}, + "Initial binary is not interesting; stopping."); + return ShrinkerResultStatus::kInitialBinaryNotInteresting; + } + + uint32_t attempt = 0; // Keeps track of the number of shrink attempts that + // have been tried, whether successful or not. + + uint32_t chunk_size = + std::max(1u, NumRemainingTransformations(current_best_transformations) / + 2); // The number of contiguous transformations that the + // shrinker will try to remove in one go; starts + // high and decreases during the shrinking process. + + // Keep shrinking until we: + // - reach the step limit, + // - run out of transformations to remove, or + // - cannot make the chunk size any smaller. + while (attempt < impl_->step_limit && + !current_best_transformations.transformation().empty() && + chunk_size > 0) { + bool progress_this_round = + false; // Used to decide whether to make the chunk size with which we + // remove transformations smaller. If we managed to remove at + // least one chunk of transformations at a particular chunk + // size, we set this flag so that we do not yet decrease the + // chunk size. + + assert(chunk_size <= + NumRemainingTransformations(current_best_transformations) && + "Chunk size should never exceed the number of transformations that " + "remain."); + + // The number of chunks is the ceiling of (#remaining_transformations / + // chunk_size). + const uint32_t num_chunks = + (NumRemainingTransformations(current_best_transformations) + + chunk_size - 1) / + chunk_size; + assert(num_chunks >= 1 && "There should be at least one chunk."); + assert(num_chunks * chunk_size >= + NumRemainingTransformations(current_best_transformations) && + "All transformations should be in some chunk."); + + // We go through the transformations in reverse, in chunks of size + // |chunk_size|, using |chunk_index| to track which chunk to try removing + // next. The loop exits early if we reach the shrinking step limit. + for (int chunk_index = num_chunks - 1; + attempt < impl_->step_limit && chunk_index >= 0; chunk_index--) { + // Remove a chunk of transformations according to the current index and + // chunk size. + auto transformations_with_chunk_removed = + RemoveChunk(current_best_transformations, chunk_index, chunk_size); + + // Replay the smaller sequence of transformations to get a next binary and + // transformation sequence. Note that the transformations arising from + // replay might be even smaller than the transformations with the chunk + // removed, because removing those transformations might make further + // transformations inapplicable. + std::vector next_binary; + protobufs::TransformationSequence next_transformation_sequence; + if (Replayer(impl_->target_env, false) + .Run(binary_in, initial_facts, transformations_with_chunk_removed, + &next_binary, &next_transformation_sequence) != + Replayer::ReplayerResultStatus::kComplete) { + // Replay should not fail; if it does, we need to abort shrinking. + return ShrinkerResultStatus::kReplayFailed; + } + + assert(NumRemainingTransformations(next_transformation_sequence) >= + chunk_index * chunk_size && + "Removing this chunk of transformations should not have an effect " + "on earlier chunks."); + + if (interestingness_function(next_binary, attempt)) { + // If the binary arising from the smaller transformation sequence is + // interesting, this becomes our current best binary and transformation + // sequence. + current_best_binary = next_binary; + current_best_transformations = next_transformation_sequence; + progress_this_round = true; + } + // Either way, this was a shrink attempt, so increment our count of shrink + // attempts. + attempt++; + } + if (!progress_this_round) { + // If we didn't manage to remove any chunks at this chunk size, try a + // smaller chunk size. + chunk_size /= 2; + } + // Decrease the chunk size until it becomes no larger than the number of + // remaining transformations. + while (chunk_size > + NumRemainingTransformations(current_best_transformations)) { + chunk_size /= 2; + } + } + + // The output from the shrinker is the best binary we saw, and the + // transformations that led to it. + *binary_out = current_best_binary; + *transformation_sequence_out = current_best_transformations; + + // Indicate whether shrinking completed or was truncated due to reaching the + // step limit. + assert(attempt <= impl_->step_limit); + if (attempt == impl_->step_limit) { + std::stringstream strstream; + strstream << "Shrinking did not complete; step limit " << impl_->step_limit + << " was reached."; + impl_->consumer(SPV_MSG_WARNING, nullptr, {}, strstream.str().c_str()); + return Shrinker::ShrinkerResultStatus::kStepLimitReached; + } + return Shrinker::ShrinkerResultStatus::kComplete; +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/shrinker.h b/third_party/spirv-tools/source/fuzz/shrinker.h new file mode 100644 index 0000000000..0163a53abd --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/shrinker.h @@ -0,0 +1,92 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_SHRINKER_H_ +#define SOURCE_FUZZ_SHRINKER_H_ + +#include +#include + +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "spirv-tools/libspirv.hpp" + +namespace spvtools { +namespace fuzz { + +// Shrinks a sequence of transformations that lead to an interesting SPIR-V +// binary to yield a smaller sequence of transformations that still produce an +// interesting binary. +class Shrinker { + public: + // Possible statuses that can result from running the shrinker. + enum ShrinkerResultStatus { + kComplete, + kFailedToCreateSpirvToolsInterface, + kInitialBinaryInvalid, + kInitialBinaryNotInteresting, + kReplayFailed, + kStepLimitReached, + }; + + // The type for a function that will take a binary, |binary|, and return true + // if and only if the binary is deemed interesting. (The function also takes + // an integer argument, |counter|, that will be incremented each time the + // function is called; this is for debugging purposes). + // + // The notion of "interesting" depends on what properties of the binary or + // tools that process the binary we are trying to maintain during shrinking. + using InterestingnessFunction = std::function& binary, uint32_t counter)>; + + // Constructs a shrinker from the given target environment. + Shrinker(spv_target_env env, uint32_t step_limit, + bool validate_during_replay); + + // Disables copy/move constructor/assignment operations. + Shrinker(const Shrinker&) = delete; + Shrinker(Shrinker&&) = delete; + Shrinker& operator=(const Shrinker&) = delete; + Shrinker& operator=(Shrinker&&) = delete; + + ~Shrinker(); + + // Sets the message consumer to the given |consumer|. The |consumer| will be + // invoked once for each message communicated from the library. + void SetMessageConsumer(MessageConsumer consumer); + + // Requires that when |transformation_sequence_in| is applied to |binary_in| + // with initial facts |initial_facts|, the resulting binary is interesting + // according to |interestingness_function|. + // + // Produces, via |transformation_sequence_out|, a subsequence of + // |transformation_sequence_in| that, when applied with initial facts + // |initial_facts|, produces a binary (captured via |binary_out|) that is + // also interesting according to |interestingness_function|. + ShrinkerResultStatus Run( + const std::vector& binary_in, + const protobufs::FactSequence& initial_facts, + const protobufs::TransformationSequence& transformation_sequence_in, + const InterestingnessFunction& interestingness_function, + std::vector* binary_out, + protobufs::TransformationSequence* transformation_sequence_out) const; + + private: + struct Impl; // Opaque struct for holding internal data. + std::unique_ptr impl_; // Unique pointer to internal data. +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_SHRINKER_H_ diff --git a/third_party/spirv-tools/source/fuzz/transformation.cpp b/third_party/spirv-tools/source/fuzz/transformation.cpp new file mode 100644 index 0000000000..8037af15e4 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation.cpp @@ -0,0 +1,177 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation.h" + +#include + +#include "source/fuzz/fuzzer_util.h" +#include "source/fuzz/transformation_add_constant_boolean.h" +#include "source/fuzz/transformation_add_constant_composite.h" +#include "source/fuzz/transformation_add_constant_scalar.h" +#include "source/fuzz/transformation_add_dead_block.h" +#include "source/fuzz/transformation_add_dead_break.h" +#include "source/fuzz/transformation_add_dead_continue.h" +#include "source/fuzz/transformation_add_function.h" +#include "source/fuzz/transformation_add_global_undef.h" +#include "source/fuzz/transformation_add_global_variable.h" +#include "source/fuzz/transformation_add_no_contraction_decoration.h" +#include "source/fuzz/transformation_add_type_array.h" +#include "source/fuzz/transformation_add_type_boolean.h" +#include "source/fuzz/transformation_add_type_float.h" +#include "source/fuzz/transformation_add_type_function.h" +#include "source/fuzz/transformation_add_type_int.h" +#include "source/fuzz/transformation_add_type_matrix.h" +#include "source/fuzz/transformation_add_type_pointer.h" +#include "source/fuzz/transformation_add_type_struct.h" +#include "source/fuzz/transformation_add_type_vector.h" +#include "source/fuzz/transformation_composite_construct.h" +#include "source/fuzz/transformation_composite_extract.h" +#include "source/fuzz/transformation_copy_object.h" +#include "source/fuzz/transformation_merge_blocks.h" +#include "source/fuzz/transformation_move_block_down.h" +#include "source/fuzz/transformation_outline_function.h" +#include "source/fuzz/transformation_replace_boolean_constant_with_constant_binary.h" +#include "source/fuzz/transformation_replace_constant_with_uniform.h" +#include "source/fuzz/transformation_replace_id_with_synonym.h" +#include "source/fuzz/transformation_set_function_control.h" +#include "source/fuzz/transformation_set_loop_control.h" +#include "source/fuzz/transformation_set_memory_operands_mask.h" +#include "source/fuzz/transformation_set_selection_control.h" +#include "source/fuzz/transformation_split_block.h" +#include "source/fuzz/transformation_vector_shuffle.h" +#include "source/util/make_unique.h" + +namespace spvtools { +namespace fuzz { + +Transformation::~Transformation() = default; + +std::unique_ptr Transformation::FromMessage( + const protobufs::Transformation& message) { + switch (message.transformation_case()) { + case protobufs::Transformation::TransformationCase::kAddConstantBoolean: + return MakeUnique( + message.add_constant_boolean()); + case protobufs::Transformation::TransformationCase::kAddConstantComposite: + return MakeUnique( + message.add_constant_composite()); + case protobufs::Transformation::TransformationCase::kAddConstantScalar: + return MakeUnique( + message.add_constant_scalar()); + case protobufs::Transformation::TransformationCase::kAddDeadBlock: + return MakeUnique(message.add_dead_block()); + case protobufs::Transformation::TransformationCase::kAddDeadBreak: + return MakeUnique(message.add_dead_break()); + case protobufs::Transformation::TransformationCase::kAddDeadContinue: + return MakeUnique( + message.add_dead_continue()); + case protobufs::Transformation::TransformationCase::kAddFunction: + return MakeUnique(message.add_function()); + case protobufs::Transformation::TransformationCase::kAddGlobalUndef: + return MakeUnique( + message.add_global_undef()); + case protobufs::Transformation::TransformationCase::kAddGlobalVariable: + return MakeUnique( + message.add_global_variable()); + case protobufs::Transformation::TransformationCase:: + kAddNoContractionDecoration: + return MakeUnique( + message.add_no_contraction_decoration()); + case protobufs::Transformation::TransformationCase::kAddTypeArray: + return MakeUnique(message.add_type_array()); + case protobufs::Transformation::TransformationCase::kAddTypeBoolean: + return MakeUnique( + message.add_type_boolean()); + case protobufs::Transformation::TransformationCase::kAddTypeFloat: + return MakeUnique(message.add_type_float()); + case protobufs::Transformation::TransformationCase::kAddTypeFunction: + return MakeUnique( + message.add_type_function()); + case protobufs::Transformation::TransformationCase::kAddTypeInt: + return MakeUnique(message.add_type_int()); + case protobufs::Transformation::TransformationCase::kAddTypeMatrix: + return MakeUnique(message.add_type_matrix()); + case protobufs::Transformation::TransformationCase::kAddTypePointer: + return MakeUnique( + message.add_type_pointer()); + case protobufs::Transformation::TransformationCase::kAddTypeStruct: + return MakeUnique(message.add_type_struct()); + case protobufs::Transformation::TransformationCase::kAddTypeVector: + return MakeUnique(message.add_type_vector()); + case protobufs::Transformation::TransformationCase::kCompositeConstruct: + return MakeUnique( + message.composite_construct()); + case protobufs::Transformation::TransformationCase::kCompositeExtract: + return MakeUnique( + message.composite_extract()); + case protobufs::Transformation::TransformationCase::kCopyObject: + return MakeUnique(message.copy_object()); + case protobufs::Transformation::TransformationCase::kMergeBlocks: + return MakeUnique(message.merge_blocks()); + case protobufs::Transformation::TransformationCase::kMoveBlockDown: + return MakeUnique(message.move_block_down()); + case protobufs::Transformation::TransformationCase::kOutlineFunction: + return MakeUnique( + message.outline_function()); + case protobufs::Transformation::TransformationCase:: + kReplaceBooleanConstantWithConstantBinary: + return MakeUnique( + message.replace_boolean_constant_with_constant_binary()); + case protobufs::Transformation::TransformationCase:: + kReplaceConstantWithUniform: + return MakeUnique( + message.replace_constant_with_uniform()); + case protobufs::Transformation::TransformationCase::kReplaceIdWithSynonym: + return MakeUnique( + message.replace_id_with_synonym()); + case protobufs::Transformation::TransformationCase::kSetFunctionControl: + return MakeUnique( + message.set_function_control()); + case protobufs::Transformation::TransformationCase::kSetLoopControl: + return MakeUnique( + message.set_loop_control()); + case protobufs::Transformation::TransformationCase::kSetMemoryOperandsMask: + return MakeUnique( + message.set_memory_operands_mask()); + case protobufs::Transformation::TransformationCase::kSetSelectionControl: + return MakeUnique( + message.set_selection_control()); + case protobufs::Transformation::TransformationCase::kSplitBlock: + return MakeUnique(message.split_block()); + case protobufs::Transformation::TransformationCase::kVectorShuffle: + return MakeUnique(message.vector_shuffle()); + case protobufs::Transformation::TRANSFORMATION_NOT_SET: + assert(false && "An unset transformation was encountered."); + return nullptr; + } + assert(false && "Should be unreachable as all cases must be handled above."); + return nullptr; +} + +bool Transformation::CheckIdIsFreshAndNotUsedByThisTransformation( + uint32_t id, opt::IRContext* context, + std::set* ids_used_by_this_transformation) { + if (!fuzzerutil::IsFreshId(context, id)) { + return false; + } + if (ids_used_by_this_transformation->count(id) != 0) { + return false; + } + ids_used_by_this_transformation->insert(id); + return true; +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/transformation.h b/third_party/spirv-tools/source/fuzz/transformation.h new file mode 100644 index 0000000000..dbe803f35c --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation.h @@ -0,0 +1,100 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_TRANSFORMATION_H_ +#define SOURCE_FUZZ_TRANSFORMATION_H_ + +#include + +#include "source/fuzz/fact_manager.h" +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace fuzz { + +// Rules for transformations +// ------------------------- +// +// - Immutability: a transformation must be immutable. +// - Ability to copy and serialize: to ensure that a copy of a transformation, +// possibly saved out to disk and read back again, is indistinguishable +// from the original transformation, thus a transformation must depend +// only on well-defined pieces of state, such as instruction ids. It must +// not rely on state such as pointers to instructions and blocks. +// - Determinism: the effect of a transformation on a module be a deterministic +// function of the module and the transformation. Any randomization should +// be applied before creating the transformation, not during its +// application. +// - Well-defined and precondition: the 'IsApplicable' method should only +// return true if the transformation can be cleanly applied to the given +// module, to mutate it into a valid and semantically-equivalent module, as +// long as the module is initially valid. +// - Ability to test precondition on any valid module: 'IsApplicable' should be +// designed so that it is safe to ask whether a transformation is +// applicable to an arbitrary valid module. For example, if a +// transformation involves a block id, 'IsApplicable' should check whether +// the module indeed has a block with that id, and return false if not. It +// must not assume that there is such a block. +// - Documented precondition: while the implementation of 'IsApplicable' should +// should codify the precondition, the method should be commented in the +// header file for a transformation with a precise English description of +// the precondition. +// - Documented effect: while the implementation of 'Apply' should codify the +// effect of the transformation, the method should be commented in the +// header file for a transformation with a precise English description of +// the effect. + +class Transformation { + public: + // A precondition that determines whether the transformation can be cleanly + // applied in a semantics-preserving manner to the SPIR-V module given by + // |context|, in the presence of facts captured by |fact_manager|. + // Preconditions for individual transformations must be documented in the + // associated header file using precise English. The fact manager is used to + // provide access to facts about the module that are known to be true, on + // which the precondition may depend. + virtual bool IsApplicable(opt::IRContext* context, + const FactManager& fact_manager) const = 0; + + // Requires that IsApplicable(context, fact_manager) holds. Applies the + // transformation, mutating |context| and possibly updating |fact_manager| + // with new facts established by the transformation. + virtual void Apply(opt::IRContext* context, + FactManager* fact_manager) const = 0; + + // Turns the transformation into a protobuf message for serialization. + virtual protobufs::Transformation ToMessage() const = 0; + + virtual ~Transformation(); + + // Factory method to obtain a transformation object from the protobuf + // representation of a transformation given by |message|. + static std::unique_ptr FromMessage( + const protobufs::Transformation& message); + + // Helper that returns true if and only if (a) |id| is a fresh id for the + // module, and (b) |id| is not in |ids_used_by_this_transformation|, a set of + // ids already known to be in use by a transformation. This is useful when + // checking id freshness for a transformation that uses many ids, all of which + // must be distinct. + static bool CheckIdIsFreshAndNotUsedByThisTransformation( + uint32_t id, opt::IRContext* context, + std::set* ids_used_by_this_transformation); +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_TRANSFORMATION_H_ diff --git a/third_party/spirv-tools/source/fuzz/transformation_add_constant_boolean.cpp b/third_party/spirv-tools/source/fuzz/transformation_add_constant_boolean.cpp new file mode 100644 index 0000000000..21c8ed3fcf --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_add_constant_boolean.cpp @@ -0,0 +1,64 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_add_constant_boolean.h" + +#include "source/fuzz/fuzzer_util.h" +#include "source/opt/types.h" + +namespace spvtools { +namespace fuzz { + +TransformationAddConstantBoolean::TransformationAddConstantBoolean( + const protobufs::TransformationAddConstantBoolean& message) + : message_(message) {} + +TransformationAddConstantBoolean::TransformationAddConstantBoolean( + uint32_t fresh_id, bool is_true) { + message_.set_fresh_id(fresh_id); + message_.set_is_true(is_true); +} + +bool TransformationAddConstantBoolean::IsApplicable( + opt::IRContext* context, const FactManager& /*unused*/) const { + opt::analysis::Bool bool_type; + if (!context->get_type_mgr()->GetId(&bool_type)) { + // No OpTypeBool is present. + return false; + } + return fuzzerutil::IsFreshId(context, message_.fresh_id()); +} + +void TransformationAddConstantBoolean::Apply(opt::IRContext* context, + FactManager* /*unused*/) const { + opt::analysis::Bool bool_type; + // Add the boolean constant to the module, ensuring the module's id bound is + // high enough. + fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id()); + context->module()->AddGlobalValue( + message_.is_true() ? SpvOpConstantTrue : SpvOpConstantFalse, + message_.fresh_id(), context->get_type_mgr()->GetId(&bool_type)); + // We have added an instruction to the module, so need to be careful about the + // validity of existing analyses. + context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone); +} + +protobufs::Transformation TransformationAddConstantBoolean::ToMessage() const { + protobufs::Transformation result; + *result.mutable_add_constant_boolean() = message_; + return result; +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/transformation_add_constant_boolean.h b/third_party/spirv-tools/source/fuzz/transformation_add_constant_boolean.h new file mode 100644 index 0000000000..79df1cdaf7 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_add_constant_boolean.h @@ -0,0 +1,51 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_BOOLEAN_CONSTANT_H_ +#define SOURCE_FUZZ_TRANSFORMATION_ADD_BOOLEAN_CONSTANT_H_ + +#include "source/fuzz/fact_manager.h" +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "source/fuzz/transformation.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace fuzz { + +class TransformationAddConstantBoolean : public Transformation { + public: + explicit TransformationAddConstantBoolean( + const protobufs::TransformationAddConstantBoolean& message); + + TransformationAddConstantBoolean(uint32_t fresh_id, bool is_true); + + // - |message_.fresh_id| must not be used by the module. + // - The module must already contain OpTypeBool. + bool IsApplicable(opt::IRContext* context, + const FactManager& fact_manager) const override; + + // - Adds OpConstantTrue (OpConstantFalse) to the module with id + // |message_.fresh_id| if |message_.is_true| holds (does not hold). + void Apply(opt::IRContext* context, FactManager* fact_manager) const override; + + protobufs::Transformation ToMessage() const override; + + private: + protobufs::TransformationAddConstantBoolean message_; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_TRANSFORMATION_ADD_BOOLEAN_CONSTANT_H_ diff --git a/third_party/spirv-tools/source/fuzz/transformation_add_constant_composite.cpp b/third_party/spirv-tools/source/fuzz/transformation_add_constant_composite.cpp new file mode 100644 index 0000000000..7ba1ea4d7f --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_add_constant_composite.cpp @@ -0,0 +1,130 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_add_constant_composite.h" + +#include + +#include "source/fuzz/fuzzer_util.h" + +namespace spvtools { +namespace fuzz { + +TransformationAddConstantComposite::TransformationAddConstantComposite( + const spvtools::fuzz::protobufs::TransformationAddConstantComposite& + message) + : message_(message) {} + +TransformationAddConstantComposite::TransformationAddConstantComposite( + uint32_t fresh_id, uint32_t type_id, + const std::vector& constituent_ids) { + message_.set_fresh_id(fresh_id); + message_.set_type_id(type_id); + for (auto constituent_id : constituent_ids) { + message_.add_constituent_id(constituent_id); + } +} + +bool TransformationAddConstantComposite::IsApplicable( + opt::IRContext* context, + const spvtools::fuzz::FactManager& /*unused*/) const { + // Check that the given id is fresh. + if (!fuzzerutil::IsFreshId(context, message_.fresh_id())) { + return false; + } + // Check that the composite type id is an instruction id. + auto composite_type_instruction = + context->get_def_use_mgr()->GetDef(message_.type_id()); + if (!composite_type_instruction) { + return false; + } + // Gather up the operands for the composite constant, in the process checking + // whether the given type really defines a composite. + std::vector constituent_type_ids; + switch (composite_type_instruction->opcode()) { + case SpvOpTypeArray: + for (uint32_t index = 0; + index < + fuzzerutil::GetArraySize(*composite_type_instruction, context); + index++) { + constituent_type_ids.push_back( + composite_type_instruction->GetSingleWordInOperand(0)); + } + break; + case SpvOpTypeMatrix: + case SpvOpTypeVector: + for (uint32_t index = 0; + index < composite_type_instruction->GetSingleWordInOperand(1); + index++) { + constituent_type_ids.push_back( + composite_type_instruction->GetSingleWordInOperand(0)); + } + break; + case SpvOpTypeStruct: + composite_type_instruction->ForEachInOperand( + [&constituent_type_ids](const uint32_t* member_type_id) { + constituent_type_ids.push_back(*member_type_id); + }); + break; + default: + // Not a composite type. + return false; + } + + // Check that the number of provided operands matches the number of + // constituents required by the type. + if (constituent_type_ids.size() != + static_cast(message_.constituent_id().size())) { + return false; + } + + // Check that every provided operand refers to an instruction of the + // corresponding constituent type. + for (uint32_t index = 0; index < constituent_type_ids.size(); index++) { + auto constituent_instruction = + context->get_def_use_mgr()->GetDef(message_.constituent_id(index)); + if (!constituent_instruction) { + return false; + } + if (constituent_instruction->type_id() != constituent_type_ids.at(index)) { + return false; + } + } + return true; +} + +void TransformationAddConstantComposite::Apply( + opt::IRContext* context, spvtools::fuzz::FactManager* /*unused*/) const { + opt::Instruction::OperandList in_operands; + for (auto constituent_id : message_.constituent_id()) { + in_operands.push_back({SPV_OPERAND_TYPE_ID, {constituent_id}}); + } + context->module()->AddGlobalValue(MakeUnique( + context, SpvOpConstantComposite, message_.type_id(), message_.fresh_id(), + in_operands)); + fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id()); + // We have added an instruction to the module, so need to be careful about the + // validity of existing analyses. + context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone); +} + +protobufs::Transformation TransformationAddConstantComposite::ToMessage() + const { + protobufs::Transformation result; + *result.mutable_add_constant_composite() = message_; + return result; +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/transformation_add_constant_composite.h b/third_party/spirv-tools/source/fuzz/transformation_add_constant_composite.h new file mode 100644 index 0000000000..9a824a047a --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_add_constant_composite.h @@ -0,0 +1,58 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_CONSTANT_COMPOSITE_H_ +#define SOURCE_FUZZ_TRANSFORMATION_ADD_CONSTANT_COMPOSITE_H_ + +#include + +#include "source/fuzz/fact_manager.h" +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "source/fuzz/transformation.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace fuzz { + +class TransformationAddConstantComposite : public Transformation { + public: + explicit TransformationAddConstantComposite( + const protobufs::TransformationAddConstantComposite& message); + + TransformationAddConstantComposite( + uint32_t fresh_id, uint32_t type_id, + const std::vector& constituent_ids); + + // - |message_.fresh_id| must be a fresh id + // - |message_.type_id| must be the id of a composite type + // - |message_.constituent_id| must refer to ids that match the constituent + // types of this composite type + bool IsApplicable(opt::IRContext* context, + const FactManager& fact_manager) const override; + + // Adds an OpConstantComposite instruction defining a constant of type + // |message_.type_id|, using |message_.constituent_id| as constituents, with + // result id |message_.fresh_id|. + void Apply(opt::IRContext* context, FactManager* fact_manager) const override; + + protobufs::Transformation ToMessage() const override; + + private: + protobufs::TransformationAddConstantComposite message_; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_TRANSFORMATION_ADD_CONSTANT_COMPOSITE_H_ diff --git a/third_party/spirv-tools/source/fuzz/transformation_add_constant_scalar.cpp b/third_party/spirv-tools/source/fuzz/transformation_add_constant_scalar.cpp new file mode 100644 index 0000000000..36af5e01cc --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_add_constant_scalar.cpp @@ -0,0 +1,87 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_add_constant_scalar.h" + +#include "source/fuzz/fuzzer_util.h" + +namespace spvtools { +namespace fuzz { + +TransformationAddConstantScalar::TransformationAddConstantScalar( + const spvtools::fuzz::protobufs::TransformationAddConstantScalar& message) + : message_(message) {} + +TransformationAddConstantScalar::TransformationAddConstantScalar( + uint32_t fresh_id, uint32_t type_id, std::vector words) { + message_.set_fresh_id(fresh_id); + message_.set_type_id(type_id); + for (auto word : words) { + message_.add_word(word); + } +} + +bool TransformationAddConstantScalar::IsApplicable( + opt::IRContext* context, + const spvtools::fuzz::FactManager& /*unused*/) const { + // The id needs to be fresh. + if (!fuzzerutil::IsFreshId(context, message_.fresh_id())) { + return false; + } + // The type id for the scalar must exist and be a type. + auto type = context->get_type_mgr()->GetType(message_.type_id()); + if (!type) { + return false; + } + uint32_t width; + if (type->AsFloat()) { + width = type->AsFloat()->width(); + } else if (type->AsInteger()) { + width = type->AsInteger()->width(); + } else { + return false; + } + // The number of words is the integer floor of the width. + auto words = (width + 32 - 1) / 32; + + // The number of words provided by the transformation needs to match the + // width of the type. + return static_cast(message_.word().size()) == words; +} + +void TransformationAddConstantScalar::Apply( + opt::IRContext* context, spvtools::fuzz::FactManager* /*unused*/) const { + opt::Instruction::OperandList operand_list; + for (auto word : message_.word()) { + operand_list.push_back({SPV_OPERAND_TYPE_LITERAL_INTEGER, {word}}); + } + context->module()->AddGlobalValue( + MakeUnique(context, SpvOpConstant, message_.type_id(), + message_.fresh_id(), operand_list)); + + fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id()); + + // We have added an instruction to the module, so need to be careful about the + // validity of existing analyses. + context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone); +} + +protobufs::Transformation TransformationAddConstantScalar::ToMessage() const { + protobufs::Transformation result; + *result.mutable_add_constant_scalar() = message_; + return result; +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/transformation_add_constant_scalar.h b/third_party/spirv-tools/source/fuzz/transformation_add_constant_scalar.h new file mode 100644 index 0000000000..914cfe62af --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_add_constant_scalar.h @@ -0,0 +1,55 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_CONSTANT_SCALAR_H_ +#define SOURCE_FUZZ_TRANSFORMATION_ADD_CONSTANT_SCALAR_H_ + +#include + +#include "source/fuzz/fact_manager.h" +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "source/fuzz/transformation.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace fuzz { + +class TransformationAddConstantScalar : public Transformation { + public: + explicit TransformationAddConstantScalar( + const protobufs::TransformationAddConstantScalar& message); + + TransformationAddConstantScalar(uint32_t fresh_id, uint32_t type_id, + std::vector words); + + // - |message_.fresh_id| must not be used by the module + // - |message_.type_id| must be the id of a floating-point or integer type + // - The size of |message_.word| must be compatible with the width of this + // type + bool IsApplicable(opt::IRContext* context, + const FactManager& fact_manager) const override; + + // Adds a new OpConstant instruction with the given type and words. + void Apply(opt::IRContext* context, FactManager* fact_manager) const override; + + protobufs::Transformation ToMessage() const override; + + private: + protobufs::TransformationAddConstantScalar message_; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_TRANSFORMATION_ADD_CONSTANT_SCALAR_H_ diff --git a/third_party/spirv-tools/source/fuzz/transformation_add_dead_block.cpp b/third_party/spirv-tools/source/fuzz/transformation_add_dead_block.cpp new file mode 100644 index 0000000000..b58f75e520 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_add_dead_block.cpp @@ -0,0 +1,169 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_add_dead_block.h" + +#include "source/fuzz/fuzzer_util.h" + +namespace spvtools { +namespace fuzz { + +TransformationAddDeadBlock::TransformationAddDeadBlock( + const spvtools::fuzz::protobufs::TransformationAddDeadBlock& message) + : message_(message) {} + +TransformationAddDeadBlock::TransformationAddDeadBlock(uint32_t fresh_id, + uint32_t existing_block, + bool condition_value) { + message_.set_fresh_id(fresh_id); + message_.set_existing_block(existing_block); + message_.set_condition_value(condition_value); +} + +bool TransformationAddDeadBlock::IsApplicable( + opt::IRContext* context, + const spvtools::fuzz::FactManager& /*unused*/) const { + // The new block's id must be fresh. + if (!fuzzerutil::IsFreshId(context, message_.fresh_id())) { + return false; + } + + // First, we check that a constant with the same value as + // |message_.condition_value| is present. + if (!fuzzerutil::MaybeGetBoolConstantId(context, + message_.condition_value())) { + // The required constant is not present, so the transformation cannot be + // applied. + return false; + } + + // The existing block must indeed exist. + auto existing_block = + fuzzerutil::MaybeFindBlock(context, message_.existing_block()); + if (!existing_block) { + return false; + } + + // It must not head a loop. + if (existing_block->IsLoopHeader()) { + return false; + } + + // It must end with OpBranch. + if (existing_block->terminator()->opcode() != SpvOpBranch) { + return false; + } + + // Its successor must not be a merge block nor continue target. + auto successor_block_id = + existing_block->terminator()->GetSingleWordInOperand(0); + if (fuzzerutil::IsMergeOrContinue(context, successor_block_id)) { + return false; + } + + // The successor must not be a loop header (i.e., |message_.existing_block| + // must not be a back-edge block. + if (context->cfg()->block(successor_block_id)->IsLoopHeader()) { + return false; + } + + return true; +} + +void TransformationAddDeadBlock::Apply( + opt::IRContext* context, spvtools::fuzz::FactManager* fact_manager) const { + // Update the module id bound so that it is at least the id of the new block. + fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id()); + + // Get the existing block and its successor. + auto existing_block = context->cfg()->block(message_.existing_block()); + auto successor_block_id = + existing_block->terminator()->GetSingleWordInOperand(0); + + // Get the id of the boolean value that will be used as the branch condition. + auto bool_id = + fuzzerutil::MaybeGetBoolConstantId(context, message_.condition_value()); + + // Make a new block that unconditionally branches to the original successor + // block. + auto enclosing_function = existing_block->GetParent(); + std::unique_ptr new_block = MakeUnique( + MakeUnique(context, SpvOpLabel, 0, message_.fresh_id(), + opt::Instruction::OperandList())); + new_block->AddInstruction(MakeUnique( + context, SpvOpBranch, 0, 0, + opt::Instruction::OperandList( + {{SPV_OPERAND_TYPE_ID, {successor_block_id}}}))); + + // Turn the original block into a selection merge, with its original successor + // as the merge block. + existing_block->terminator()->InsertBefore(MakeUnique( + context, SpvOpSelectionMerge, 0, 0, + opt::Instruction::OperandList( + {{SPV_OPERAND_TYPE_ID, {successor_block_id}}, + {SPV_OPERAND_TYPE_SELECTION_CONTROL, + {SpvSelectionControlMaskNone}}}))); + + // Change the original block's terminator to be a conditional branch on the + // given boolean, with the original successor and the new successor as branch + // targets, and such that at runtime control will always transfer to the + // original successor. + existing_block->terminator()->SetOpcode(SpvOpBranchConditional); + existing_block->terminator()->SetInOperands( + {{SPV_OPERAND_TYPE_ID, {bool_id}}, + {SPV_OPERAND_TYPE_ID, + {message_.condition_value() ? successor_block_id + : message_.fresh_id()}}, + {SPV_OPERAND_TYPE_ID, + {message_.condition_value() ? message_.fresh_id() + : successor_block_id}}}); + + // Add the new block to the enclosing function. + new_block->SetParent(enclosing_function); + enclosing_function->InsertBasicBlockAfter(std::move(new_block), + existing_block); + + // Record the fact that the new block is dead. + fact_manager->AddFactBlockIsDead(message_.fresh_id()); + + // Fix up OpPhi instructions in the successor block, so that the values they + // yield when control has transferred from the new block are the same as if + // control had transferred from |message_.existing_block|. This is guaranteed + // to be valid since |message_.existing_block| dominates the new block by + // construction. Other transformations can change these phi operands to more + // interesting values. + context->cfg() + ->block(successor_block_id) + ->ForEachPhiInst([this](opt::Instruction* phi_inst) { + // Copy the operand that provides the phi value for the first of any + // existing predecessors. + opt::Operand copy_of_existing_operand = phi_inst->GetInOperand(0); + // Use this as the value associated with the new predecessor. + phi_inst->AddOperand(std::move(copy_of_existing_operand)); + phi_inst->AddOperand({SPV_OPERAND_TYPE_ID, {message_.fresh_id()}}); + }); + + // Do not rely on any existing analysis results since the control flow graph + // of the module has changed. + context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone); +} + +protobufs::Transformation TransformationAddDeadBlock::ToMessage() const { + protobufs::Transformation result; + *result.mutable_add_dead_block() = message_; + return result; +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/transformation_add_dead_block.h b/third_party/spirv-tools/source/fuzz/transformation_add_dead_block.h new file mode 100644 index 0000000000..059daca9b1 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_add_dead_block.h @@ -0,0 +1,63 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_DEAD_BLOCK_H_ +#define SOURCE_FUZZ_TRANSFORMATION_ADD_DEAD_BLOCK_H_ + +#include "source/fuzz/fact_manager.h" +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "source/fuzz/transformation.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace fuzz { + +class TransformationAddDeadBlock : public Transformation { + public: + explicit TransformationAddDeadBlock( + const protobufs::TransformationAddDeadBlock& message); + + TransformationAddDeadBlock(uint32_t fresh_id, uint32_t existing_block, + bool condition_value); + + // - |message_.fresh_id| must be a fresh id + // - A constant with the same value as |message_.condition_value| must be + // available + // - |message_.existing_block| must be a block that is not a loop header, + // and that ends with OpBranch to a block that is not a merge block nor + // continue target - this is because the successor will become the merge + // block of a selection construct headed at |message_.existing_block| + // - |message_.existing_block| must not be a back-edge block, since in this + // case the newly-added block would lead to another back-edge to the + // associated loop header + bool IsApplicable(opt::IRContext* context, + const FactManager& fact_manager) const override; + + // Changes the OpBranch from |message_.existing_block| to its successor 's' + // to an OpBranchConditional to either 's' or a new block, + // |message_.fresh_id|, which itself unconditionally branches to 's'. The + // conditional branch uses |message.condition_value| as its condition, and is + // arranged so that control will pass to 's' at runtime. + void Apply(opt::IRContext* context, FactManager* fact_manager) const override; + + protobufs::Transformation ToMessage() const override; + + private: + protobufs::TransformationAddDeadBlock message_; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_TRANSFORMATION_ADD_DEAD_BLOCK_H_ diff --git a/third_party/spirv-tools/source/fuzz/transformation_add_dead_break.cpp b/third_party/spirv-tools/source/fuzz/transformation_add_dead_break.cpp new file mode 100644 index 0000000000..43847fada5 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_add_dead_break.cpp @@ -0,0 +1,207 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_add_dead_break.h" + +#include "source/fuzz/fact_manager.h" +#include "source/fuzz/fuzzer_util.h" +#include "source/opt/basic_block.h" +#include "source/opt/ir_context.h" +#include "source/opt/struct_cfg_analysis.h" + +namespace spvtools { +namespace fuzz { + +TransformationAddDeadBreak::TransformationAddDeadBreak( + const spvtools::fuzz::protobufs::TransformationAddDeadBreak& message) + : message_(message) {} + +TransformationAddDeadBreak::TransformationAddDeadBreak( + uint32_t from_block, uint32_t to_block, bool break_condition_value, + std::vector phi_id) { + message_.set_from_block(from_block); + message_.set_to_block(to_block); + message_.set_break_condition_value(break_condition_value); + for (auto id : phi_id) { + message_.add_phi_id(id); + } +} + +bool TransformationAddDeadBreak::AddingBreakRespectsStructuredControlFlow( + opt::IRContext* context, opt::BasicBlock* bb_from) const { + // Look at the structured control flow associated with |from_block| and + // check whether it is contained in an appropriate construct with merge id + // |to_block| such that a break from |from_block| to |to_block| is legal. + + // There are three legal cases to consider: + // (1) |from_block| is a loop header and |to_block| is its merge + // (2) |from_block| is a non-header node of a construct, and |to_block| + // is the merge for that construct + // (3) |from_block| is a non-header node of a selection construct, and + // |to_block| is the merge for the innermost loop containing + // |from_block| + // + // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/2653) It may be + // possible to be more aggressive in breaking from switch constructs. + // + // The reason we need to distinguish between cases (1) and (2) is that the + // structured CFG analysis does not deem a header to be part of the construct + // that it heads. + + // Consider case (1) + if (bb_from->IsLoopHeader()) { + // Case (1) holds if |to_block| is the merge block for the loop; + // otherwise no case holds + return bb_from->MergeBlockId() == message_.to_block(); + } + + // Both cases (2) and (3) require that |from_block| is inside some + // structured control flow construct. + + auto containing_construct = + context->GetStructuredCFGAnalysis()->ContainingConstruct( + message_.from_block()); + if (!containing_construct) { + // |from_block| is not in a construct from which we can break. + return false; + } + + // Consider case (2) + if (message_.to_block() == + context->cfg()->block(containing_construct)->MergeBlockId()) { + // This looks like an instance of case (2). + // However, the structured CFG analysis regards the continue construct of a + // loop as part of the loop, but it is not legal to jump from a loop's + // continue construct to the loop's merge (except from the back-edge block), + // so we need to check for this case. + // + // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/2577): We do not + // currently allow a dead break from a back edge block, but we could and + // ultimately should. + return !fuzzerutil::BlockIsInLoopContinueConstruct( + context, message_.from_block(), containing_construct); + } + + // Case (3) holds if and only if |to_block| is the merge block for this + // innermost loop that contains |from_block| + auto containing_loop_header = + context->GetStructuredCFGAnalysis()->ContainingLoop( + message_.from_block()); + if (containing_loop_header && + message_.to_block() == + context->cfg()->block(containing_loop_header)->MergeBlockId()) { + return !fuzzerutil::BlockIsInLoopContinueConstruct( + context, message_.from_block(), containing_loop_header); + } + return false; +} + +bool TransformationAddDeadBreak::IsApplicable( + opt::IRContext* context, const FactManager& /*unused*/) const { + // First, we check that a constant with the same value as + // |message_.break_condition_value| is present. + if (!fuzzerutil::MaybeGetBoolConstantId(context, + message_.break_condition_value())) { + // The required constant is not present, so the transformation cannot be + // applied. + return false; + } + + // Check that |message_.from_block| and |message_.to_block| really are block + // ids + opt::BasicBlock* bb_from = + fuzzerutil::MaybeFindBlock(context, message_.from_block()); + if (bb_from == nullptr) { + return false; + } + opt::BasicBlock* bb_to = + fuzzerutil::MaybeFindBlock(context, message_.to_block()); + if (bb_to == nullptr) { + return false; + } + + if (!fuzzerutil::BlockIsReachableInItsFunction(context, bb_to)) { + // If the target of the break is unreachable, we conservatively do not + // allow adding a dead break, to avoid the compilations that arise due to + // the lack of sensible dominance information for unreachable blocks. + return false; + } + + // Check that |message_.from_block| ends with an unconditional branch. + if (bb_from->terminator()->opcode() != SpvOpBranch) { + // The block associated with the id does not end with an unconditional + // branch. + return false; + } + + assert(bb_from != nullptr && + "We should have found a block if this line of code is reached."); + assert( + bb_from->id() == message_.from_block() && + "The id of the block we found should match the source id for the break."); + assert(bb_to != nullptr && + "We should have found a block if this line of code is reached."); + assert( + bb_to->id() == message_.to_block() && + "The id of the block we found should match the target id for the break."); + + // Check whether the data passed to extend OpPhi instructions is appropriate. + if (!fuzzerutil::PhiIdsOkForNewEdge(context, bb_from, bb_to, + message_.phi_id())) { + return false; + } + + // Check that adding the break would respect the rules of structured + // control flow. + if (!AddingBreakRespectsStructuredControlFlow(context, bb_from)) { + return false; + } + + // Adding the dead break is only valid if SPIR-V rules related to dominance + // hold. Rather than checking these rules explicitly, we defer to the + // validator. We make a clone of the module, apply the transformation to the + // clone, and check whether the transformed clone is valid. + // + // In principle some of the above checks could be removed, with more reliance + // being places on the validator. This should be revisited if we are sure + // the validator is complete with respect to checking structured control flow + // rules. + auto cloned_context = fuzzerutil::CloneIRContext(context); + ApplyImpl(cloned_context.get()); + return fuzzerutil::IsValid(cloned_context.get()); +} + +void TransformationAddDeadBreak::Apply(opt::IRContext* context, + FactManager* /*unused*/) const { + ApplyImpl(context); + // Invalidate all analyses + context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone); +} + +protobufs::Transformation TransformationAddDeadBreak::ToMessage() const { + protobufs::Transformation result; + *result.mutable_add_dead_break() = message_; + return result; +} + +void TransformationAddDeadBreak::ApplyImpl( + spvtools::opt::IRContext* context) const { + fuzzerutil::AddUnreachableEdgeAndUpdateOpPhis( + context, context->cfg()->block(message_.from_block()), + context->cfg()->block(message_.to_block()), + message_.break_condition_value(), message_.phi_id()); +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/transformation_add_dead_break.h b/third_party/spirv-tools/source/fuzz/transformation_add_dead_break.h new file mode 100644 index 0000000000..81a2c991b5 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_add_dead_break.h @@ -0,0 +1,84 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_DEAD_BREAK_H_ +#define SOURCE_FUZZ_TRANSFORMATION_ADD_DEAD_BREAK_H_ + +#include + +#include "source/fuzz/fact_manager.h" +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "source/fuzz/transformation.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace fuzz { + +class TransformationAddDeadBreak : public Transformation { + public: + explicit TransformationAddDeadBreak( + const protobufs::TransformationAddDeadBreak& message); + + TransformationAddDeadBreak(uint32_t from_block, uint32_t to_block, + bool break_condition_value, + std::vector phi_id); + + // - |message_.from_block| must be the id of a block a in the given module. + // - |message_.to_block| must be the id of a block b in the given module. + // - if |message_.break_condition_value| holds (does not hold) then + // OpConstantTrue (OpConstantFalse) must be present in the module + // - |message_.phi_ids| must be a list of ids that are all available at + // |message_.from_block| + // - a and b must be in the same function. + // - b must be a merge block. + // - a must end with an unconditional branch to some block c. + // - replacing this branch with a conditional branch to b or c, with + // the boolean constant associated with |message_.break_condition_value| as + // the condition, and the ids in |message_.phi_ids| used to extend + // any OpPhi instructions at b as a result of the edge from a, must + // maintain validity of the module. + // In particular, the new branch must not lead to violations of the rule + // that a use must be dominated by its definition. + bool IsApplicable(opt::IRContext* context, + const FactManager& fact_manager) const override; + + // Replaces the terminator of a with a conditional branch to b or c. + // The boolean constant associated with |message_.break_condition_value| is + // used as the condition, and the order of b and c is arranged such that + // control is guaranteed to jump to c. + void Apply(opt::IRContext* context, FactManager* fact_manager) const override; + + protobufs::Transformation ToMessage() const override; + + private: + // Returns true if and only if adding an edge from |bb_from| to + // |message_.to_block| respects structured control flow. + bool AddingBreakRespectsStructuredControlFlow(opt::IRContext* context, + opt::BasicBlock* bb_from) const; + + // Used by 'Apply' to actually apply the transformation to the module of + // interest, and by 'IsApplicable' to do a dry-run of the transformation on a + // cloned module, in order to check that the transformation leads to a valid + // module. This is only invoked by 'IsApplicable' after certain basic + // applicability checks have been made, ensuring that the invocation of this + // method is legal. + void ApplyImpl(opt::IRContext* context) const; + + protobufs::TransformationAddDeadBreak message_; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_TRANSFORMATION_ADD_DEAD_BREAK_H_ diff --git a/third_party/spirv-tools/source/fuzz/transformation_add_dead_continue.cpp b/third_party/spirv-tools/source/fuzz/transformation_add_dead_continue.cpp new file mode 100644 index 0000000000..ffa182e930 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_add_dead_continue.cpp @@ -0,0 +1,151 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_add_dead_continue.h" + +#include "source/fuzz/fuzzer_util.h" + +namespace spvtools { +namespace fuzz { + +TransformationAddDeadContinue::TransformationAddDeadContinue( + const spvtools::fuzz::protobufs::TransformationAddDeadContinue& message) + : message_(message) {} + +TransformationAddDeadContinue::TransformationAddDeadContinue( + uint32_t from_block, bool continue_condition_value, + std::vector phi_id) { + message_.set_from_block(from_block); + message_.set_continue_condition_value(continue_condition_value); + for (auto id : phi_id) { + message_.add_phi_id(id); + } +} + +bool TransformationAddDeadContinue::IsApplicable( + opt::IRContext* context, const FactManager& /*unused*/) const { + // First, we check that a constant with the same value as + // |message_.continue_condition_value| is present. + if (!fuzzerutil::MaybeGetBoolConstantId( + context, message_.continue_condition_value())) { + // The required constant is not present, so the transformation cannot be + // applied. + return false; + } + + // Check that |message_.from_block| really is a block id. + opt::BasicBlock* bb_from = + fuzzerutil::MaybeFindBlock(context, message_.from_block()); + if (bb_from == nullptr) { + return false; + } + + // Check that |message_.from_block| ends with an unconditional branch. + if (bb_from->terminator()->opcode() != SpvOpBranch) { + // The block associated with the id does not end with an unconditional + // branch. + return false; + } + + assert(bb_from != nullptr && + "We should have found a block if this line of code is reached."); + assert( + bb_from->id() == message_.from_block() && + "The id of the block we found should match the source id for the break."); + + // Get the header for the innermost loop containing |message_.from_block|. + // Because the structured CFG analysis does not regard a loop header as part + // of the loop it heads, we check first whether bb_from is a loop header + // before using the structured CFG analysis. + auto loop_header = bb_from->IsLoopHeader() + ? message_.from_block() + : context->GetStructuredCFGAnalysis()->ContainingLoop( + message_.from_block()); + if (!loop_header) { + return false; + } + + auto continue_block = context->cfg()->block(loop_header)->ContinueBlockId(); + + if (!fuzzerutil::BlockIsReachableInItsFunction( + context, context->cfg()->block(continue_block))) { + // If the loop's continue block is unreachable, we conservatively do not + // allow adding a dead continue, to avoid the compilations that arise due to + // the lack of sensible dominance information for unreachable blocks. + return false; + } + + if (fuzzerutil::BlockIsInLoopContinueConstruct(context, message_.from_block(), + loop_header)) { + // We cannot jump to the continue target from the continue construct. + return false; + } + + if (context->GetStructuredCFGAnalysis()->IsMergeBlock(continue_block)) { + // A branch straight to the continue target that is also a merge block might + // break the property that a construct header must dominate its merge block + // (if the merge block is reachable). + return false; + } + + // Check whether the data passed to extend OpPhi instructions is appropriate. + if (!fuzzerutil::PhiIdsOkForNewEdge(context, bb_from, + context->cfg()->block(continue_block), + message_.phi_id())) { + return false; + } + + // Adding the dead break is only valid if SPIR-V rules related to dominance + // hold. Rather than checking these rules explicitly, we defer to the + // validator. We make a clone of the module, apply the transformation to the + // clone, and check whether the transformed clone is valid. + // + // In principle some of the above checks could be removed, with more reliance + // being places on the validator. This should be revisited if we are sure + // the validator is complete with respect to checking structured control flow + // rules. + auto cloned_context = fuzzerutil::CloneIRContext(context); + ApplyImpl(cloned_context.get()); + return fuzzerutil::IsValid(cloned_context.get()); +} + +void TransformationAddDeadContinue::Apply(opt::IRContext* context, + FactManager* /*unused*/) const { + ApplyImpl(context); + // Invalidate all analyses + context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone); +} + +protobufs::Transformation TransformationAddDeadContinue::ToMessage() const { + protobufs::Transformation result; + *result.mutable_add_dead_continue() = message_; + return result; +} + +void TransformationAddDeadContinue::ApplyImpl( + spvtools::opt::IRContext* context) const { + auto bb_from = context->cfg()->block(message_.from_block()); + auto continue_block = + bb_from->IsLoopHeader() + ? bb_from->ContinueBlockId() + : context->GetStructuredCFGAnalysis()->LoopContinueBlock( + message_.from_block()); + assert(continue_block && "message_.from_block must be in a loop."); + fuzzerutil::AddUnreachableEdgeAndUpdateOpPhis( + context, bb_from, context->cfg()->block(continue_block), + message_.continue_condition_value(), message_.phi_id()); +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/transformation_add_dead_continue.h b/third_party/spirv-tools/source/fuzz/transformation_add_dead_continue.h new file mode 100644 index 0000000000..86b4c93bd0 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_add_dead_continue.h @@ -0,0 +1,81 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_DEAD_CONTINUE_H_ +#define SOURCE_FUZZ_TRANSFORMATION_ADD_DEAD_CONTINUE_H_ + +#include + +#include "source/fuzz/fact_manager.h" +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "source/fuzz/transformation.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace fuzz { + +class TransformationAddDeadContinue : public Transformation { + public: + explicit TransformationAddDeadContinue( + const protobufs::TransformationAddDeadContinue& message); + + TransformationAddDeadContinue(uint32_t from_block, + bool continue_condition_value, + std::vector phi_id); + + // - |message_.from_block| must be the id of a block a in the given module. + // - a must be contained in a loop with continue target b + // - The continue target b must be dominated by the head of the loop in which + // it is contained + // - b must not be the merge block of a selection construct + // - if |message_.continue_condition_value| holds (does not hold) then + // OpConstantTrue (OpConstantFalse) must be present in the module + // - |message_.phi_ids| must be a list of ids that are all available at + // |message_.from_block| + // - a must end with an unconditional branch to some block c. + // - replacing this branch with a conditional branch to b or c, with + // the boolean constant associated with |message_.continue_condition_value| + // as the condition, and the ids in |message_.phi_ids| used to extend any + // OpPhi instructions at b as a result of the edge from a, must maintain + // validity of the module. + // In particular, adding an edge from somewhere in the loop to the continue + // target must not prevent uses of ids in the continue target from being + // dominated by the definitions of those ids. + bool IsApplicable(opt::IRContext* context, + const FactManager& fact_manager) const override; + + // Replaces the terminator of a with a conditional branch to b or c. + // The boolean constant associated with |message_.continue_condition_value| is + // used as the condition, and the order of b and c is arranged such that + // control is guaranteed to jump to c. + void Apply(opt::IRContext* context, FactManager* fact_manager) const override; + + protobufs::Transformation ToMessage() const override; + + private: + // Used by 'Apply' to actually apply the transformation to the module of + // interest, and by 'IsApplicable' to do a dry-run of the transformation on a + // cloned module, in order to check that the transformation leads to a valid + // module. This is only invoked by 'IsApplicable' after certain basic + // applicability checks have been made, ensuring that the invocation of this + // method is legal. + void ApplyImpl(opt::IRContext* context) const; + + protobufs::TransformationAddDeadContinue message_; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_TRANSFORMATION_ADD_DEAD_CONTINUE_H_ diff --git a/third_party/spirv-tools/source/fuzz/transformation_add_function.cpp b/third_party/spirv-tools/source/fuzz/transformation_add_function.cpp new file mode 100644 index 0000000000..b013d9441c --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_add_function.cpp @@ -0,0 +1,921 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_add_function.h" + +#include "source/fuzz/fuzzer_util.h" +#include "source/fuzz/instruction_message.h" + +namespace spvtools { +namespace fuzz { + +TransformationAddFunction::TransformationAddFunction( + const spvtools::fuzz::protobufs::TransformationAddFunction& message) + : message_(message) {} + +TransformationAddFunction::TransformationAddFunction( + const std::vector& instructions) { + for (auto& instruction : instructions) { + *message_.add_instruction() = instruction; + } + message_.set_is_livesafe(false); +} + +TransformationAddFunction::TransformationAddFunction( + const std::vector& instructions, + uint32_t loop_limiter_variable_id, uint32_t loop_limit_constant_id, + const std::vector& loop_limiters, + uint32_t kill_unreachable_return_value_id, + const std::vector& + access_chain_clampers) { + for (auto& instruction : instructions) { + *message_.add_instruction() = instruction; + } + message_.set_is_livesafe(true); + message_.set_loop_limiter_variable_id(loop_limiter_variable_id); + message_.set_loop_limit_constant_id(loop_limit_constant_id); + for (auto& loop_limiter : loop_limiters) { + *message_.add_loop_limiter_info() = loop_limiter; + } + message_.set_kill_unreachable_return_value_id( + kill_unreachable_return_value_id); + for (auto& access_clamper : access_chain_clampers) { + *message_.add_access_chain_clamping_info() = access_clamper; + } +} + +bool TransformationAddFunction::IsApplicable( + opt::IRContext* context, + const spvtools::fuzz::FactManager& fact_manager) const { + // This transformation may use a lot of ids, all of which need to be fresh + // and distinct. This set tracks them. + std::set ids_used_by_this_transformation; + + // Ensure that all result ids in the new function are fresh and distinct. + for (auto& instruction : message_.instruction()) { + if (instruction.result_id()) { + if (!CheckIdIsFreshAndNotUsedByThisTransformation( + instruction.result_id(), context, + &ids_used_by_this_transformation)) { + return false; + } + } + } + + if (message_.is_livesafe()) { + // Ensure that all ids provided for making the function livesafe are fresh + // and distinct. + if (!CheckIdIsFreshAndNotUsedByThisTransformation( + message_.loop_limiter_variable_id(), context, + &ids_used_by_this_transformation)) { + return false; + } + for (auto& loop_limiter_info : message_.loop_limiter_info()) { + if (!CheckIdIsFreshAndNotUsedByThisTransformation( + loop_limiter_info.load_id(), context, + &ids_used_by_this_transformation)) { + return false; + } + if (!CheckIdIsFreshAndNotUsedByThisTransformation( + loop_limiter_info.increment_id(), context, + &ids_used_by_this_transformation)) { + return false; + } + if (!CheckIdIsFreshAndNotUsedByThisTransformation( + loop_limiter_info.compare_id(), context, + &ids_used_by_this_transformation)) { + return false; + } + if (!CheckIdIsFreshAndNotUsedByThisTransformation( + loop_limiter_info.logical_op_id(), context, + &ids_used_by_this_transformation)) { + return false; + } + } + for (auto& access_chain_clamping_info : + message_.access_chain_clamping_info()) { + for (auto& pair : access_chain_clamping_info.compare_and_select_ids()) { + if (!CheckIdIsFreshAndNotUsedByThisTransformation( + pair.first(), context, &ids_used_by_this_transformation)) { + return false; + } + if (!CheckIdIsFreshAndNotUsedByThisTransformation( + pair.second(), context, &ids_used_by_this_transformation)) { + return false; + } + } + } + } + + // Because checking all the conditions for a function to be valid is a big + // job that the SPIR-V validator can already do, a "try it and see" approach + // is taken here. + + // We first clone the current module, so that we can try adding the new + // function without risking wrecking |context|. + auto cloned_module = fuzzerutil::CloneIRContext(context); + + // We try to add a function to the cloned module, which may fail if + // |message_.instruction| is not sufficiently well-formed. + if (!TryToAddFunction(cloned_module.get())) { + return false; + } + + if (message_.is_livesafe()) { + // We make the cloned module livesafe. + if (!TryToMakeFunctionLivesafe(cloned_module.get(), fact_manager)) { + return false; + } + } + + // Having managed to add the new function to the cloned module, and + // potentially also made it livesafe, we ascertain whether the cloned module + // is still valid. If it is, the transformation is applicable. + return fuzzerutil::IsValid(cloned_module.get()); +} + +void TransformationAddFunction::Apply( + opt::IRContext* context, spvtools::fuzz::FactManager* fact_manager) const { + // Add the function to the module. As the transformation is applicable, this + // should succeed. + bool success = TryToAddFunction(context); + assert(success && "The function should be successfully added."); + (void)(success); // Keep release builds happy (otherwise they may complain + // that |success| is not used). + + // Record the fact that all pointer parameters and variables declared in the + // function should be regarded as having arbitrary values. This allows other + // passes to store arbitrarily to such variables, and to pass them freely as + // parameters to other functions knowing that it is OK if they get + // over-written. + for (auto& instruction : message_.instruction()) { + switch (instruction.opcode()) { + case SpvOpFunctionParameter: + if (context->get_def_use_mgr() + ->GetDef(instruction.result_type_id()) + ->opcode() == SpvOpTypePointer) { + fact_manager->AddFactValueOfVariableIsArbitrary( + instruction.result_id()); + } + break; + case SpvOpVariable: + fact_manager->AddFactValueOfVariableIsArbitrary( + instruction.result_id()); + break; + default: + break; + } + } + + if (message_.is_livesafe()) { + // Make the function livesafe, which also should succeed. + success = TryToMakeFunctionLivesafe(context, *fact_manager); + assert(success && "It should be possible to make the function livesafe."); + (void)(success); // Keep release builds happy. + + // Inform the fact manager that the function is livesafe. + assert(message_.instruction(0).opcode() == SpvOpFunction && + "The first instruction of an 'add function' transformation must be " + "OpFunction."); + fact_manager->AddFactFunctionIsLivesafe( + message_.instruction(0).result_id()); + } else { + // Inform the fact manager that all blocks in the function are dead. + for (auto& inst : message_.instruction()) { + if (inst.opcode() == SpvOpLabel) { + fact_manager->AddFactBlockIsDead(inst.result_id()); + } + } + } + context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone); +} + +protobufs::Transformation TransformationAddFunction::ToMessage() const { + protobufs::Transformation result; + *result.mutable_add_function() = message_; + return result; +} + +bool TransformationAddFunction::TryToAddFunction( + opt::IRContext* context) const { + // This function returns false if |message_.instruction| was not well-formed + // enough to actually create a function and add it to |context|. + + // A function must have at least some instructions. + if (message_.instruction().empty()) { + return false; + } + + // A function must start with OpFunction. + auto function_begin = message_.instruction(0); + if (function_begin.opcode() != SpvOpFunction) { + return false; + } + + // Make a function, headed by the OpFunction instruction. + std::unique_ptr new_function = MakeUnique( + InstructionFromMessage(context, function_begin)); + + // Keeps track of which instruction protobuf message we are currently + // considering. + uint32_t instruction_index = 1; + const auto num_instructions = + static_cast(message_.instruction().size()); + + // Iterate through all function parameter instructions, adding parameters to + // the new function. + while (instruction_index < num_instructions && + message_.instruction(instruction_index).opcode() == + SpvOpFunctionParameter) { + new_function->AddParameter(InstructionFromMessage( + context, message_.instruction(instruction_index))); + instruction_index++; + } + + // After the parameters, there needs to be a label. + if (instruction_index == num_instructions || + message_.instruction(instruction_index).opcode() != SpvOpLabel) { + return false; + } + + // Iterate through the instructions block by block until the end of the + // function is reached. + while (instruction_index < num_instructions && + message_.instruction(instruction_index).opcode() != SpvOpFunctionEnd) { + // Invariant: we should always be at a label instruction at this point. + assert(message_.instruction(instruction_index).opcode() == SpvOpLabel); + + // Make a basic block using the label instruction, with the new function + // as its parent. + std::unique_ptr block = + MakeUnique(InstructionFromMessage( + context, message_.instruction(instruction_index))); + block->SetParent(new_function.get()); + + // Consider successive instructions until we hit another label or the end + // of the function, adding each such instruction to the block. + instruction_index++; + while (instruction_index < num_instructions && + message_.instruction(instruction_index).opcode() != + SpvOpFunctionEnd && + message_.instruction(instruction_index).opcode() != SpvOpLabel) { + block->AddInstruction(InstructionFromMessage( + context, message_.instruction(instruction_index))); + instruction_index++; + } + // Add the block to the new function. + new_function->AddBasicBlock(std::move(block)); + } + // Having considered all the blocks, we should be at the last instruction and + // it needs to be OpFunctionEnd. + if (instruction_index != num_instructions - 1 || + message_.instruction(instruction_index).opcode() != SpvOpFunctionEnd) { + return false; + } + // Set the function's final instruction, add the function to the module and + // report success. + new_function->SetFunctionEnd( + InstructionFromMessage(context, message_.instruction(instruction_index))); + context->AddFunction(std::move(new_function)); + + context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone); + + return true; +} + +bool TransformationAddFunction::TryToMakeFunctionLivesafe( + opt::IRContext* context, const FactManager& fact_manager) const { + assert(message_.is_livesafe() && "Precondition: is_livesafe must hold."); + + // Get a pointer to the added function. + opt::Function* added_function = nullptr; + for (auto& function : *context->module()) { + if (function.result_id() == message_.instruction(0).result_id()) { + added_function = &function; + break; + } + } + assert(added_function && "The added function should have been found."); + + if (!TryToAddLoopLimiters(context, added_function)) { + // Adding loop limiters did not work; bail out. + return false; + } + + // Consider all the instructions in the function, and: + // - attempt to replace OpKill and OpUnreachable with return instructions + // - attempt to clamp access chains to be within bounds + // - check that OpFunctionCall instructions are only to livesafe functions + for (auto& block : *added_function) { + for (auto& inst : block) { + switch (inst.opcode()) { + case SpvOpKill: + case SpvOpUnreachable: + if (!TryToTurnKillOrUnreachableIntoReturn(context, added_function, + &inst)) { + return false; + } + break; + case SpvOpAccessChain: + case SpvOpInBoundsAccessChain: + if (!TryToClampAccessChainIndices(context, &inst)) { + return false; + } + break; + case SpvOpFunctionCall: + // A livesafe function my only call other livesafe functions. + if (!fact_manager.FunctionIsLivesafe( + inst.GetSingleWordInOperand(0))) { + return false; + } + default: + break; + } + } + } + return true; +} + +bool TransformationAddFunction::TryToAddLoopLimiters( + opt::IRContext* context, opt::Function* added_function) const { + // Collect up all the loop headers so that we can subsequently add loop + // limiting logic. + std::vector loop_headers; + for (auto& block : *added_function) { + if (block.IsLoopHeader()) { + loop_headers.push_back(&block); + } + } + + if (loop_headers.empty()) { + // There are no loops, so no need to add any loop limiters. + return true; + } + + // Check that the module contains appropriate ingredients for declaring and + // manipulating a loop limiter. + + auto loop_limit_constant_id_instr = + context->get_def_use_mgr()->GetDef(message_.loop_limit_constant_id()); + if (!loop_limit_constant_id_instr || + loop_limit_constant_id_instr->opcode() != SpvOpConstant) { + // The loop limit constant id instruction must exist and have an + // appropriate opcode. + return false; + } + + auto loop_limit_type = context->get_def_use_mgr()->GetDef( + loop_limit_constant_id_instr->type_id()); + if (loop_limit_type->opcode() != SpvOpTypeInt || + loop_limit_type->GetSingleWordInOperand(0) != 32) { + // The type of the loop limit constant must be 32-bit integer. It + // doesn't actually matter whether the integer is signed or not. + return false; + } + + // Find the id of the "unsigned int" type. + opt::analysis::Integer unsigned_int_type(32, false); + uint32_t unsigned_int_type_id = + context->get_type_mgr()->GetId(&unsigned_int_type); + if (!unsigned_int_type_id) { + // Unsigned int is not available; we need this type in order to add loop + // limiters. + return false; + } + auto registered_unsigned_int_type = + context->get_type_mgr()->GetRegisteredType(&unsigned_int_type); + + // Look for 0 of type unsigned int. + opt::analysis::IntConstant zero(registered_unsigned_int_type->AsInteger(), + {0}); + auto registered_zero = context->get_constant_mgr()->FindConstant(&zero); + if (!registered_zero) { + // We need 0 in order to be able to initialize loop limiters. + return false; + } + uint32_t zero_id = context->get_constant_mgr() + ->GetDefiningInstruction(registered_zero) + ->result_id(); + + // Look for 1 of type unsigned int. + opt::analysis::IntConstant one(registered_unsigned_int_type->AsInteger(), + {1}); + auto registered_one = context->get_constant_mgr()->FindConstant(&one); + if (!registered_one) { + // We need 1 in order to be able to increment loop limiters. + return false; + } + uint32_t one_id = context->get_constant_mgr() + ->GetDefiningInstruction(registered_one) + ->result_id(); + + // Look for pointer-to-unsigned int type. + opt::analysis::Pointer pointer_to_unsigned_int_type( + registered_unsigned_int_type, SpvStorageClassFunction); + uint32_t pointer_to_unsigned_int_type_id = + context->get_type_mgr()->GetId(&pointer_to_unsigned_int_type); + if (!pointer_to_unsigned_int_type_id) { + // We need pointer-to-unsigned int in order to declare the loop limiter + // variable. + return false; + } + + // Look for bool type. + opt::analysis::Bool bool_type; + uint32_t bool_type_id = context->get_type_mgr()->GetId(&bool_type); + if (!bool_type_id) { + // We need bool in order to compare the loop limiter's value with the loop + // limit constant. + return false; + } + + // Declare the loop limiter variable at the start of the function's entry + // block, via an instruction of the form: + // %loop_limiter_var = SpvOpVariable %ptr_to_uint Function %zero + added_function->begin()->begin()->InsertBefore(MakeUnique( + context, SpvOpVariable, pointer_to_unsigned_int_type_id, + message_.loop_limiter_variable_id(), + opt::Instruction::OperandList( + {{SPV_OPERAND_TYPE_STORAGE_CLASS, {SpvStorageClassFunction}}, + {SPV_OPERAND_TYPE_ID, {zero_id}}}))); + // Update the module's id bound since we have added the loop limiter + // variable id. + fuzzerutil::UpdateModuleIdBound(context, message_.loop_limiter_variable_id()); + + // Consider each loop in turn. + for (auto loop_header : loop_headers) { + // Look for the loop's back-edge block. This is a predecessor of the loop + // header that is dominated by the loop header. + uint32_t back_edge_block_id = 0; + for (auto pred : context->cfg()->preds(loop_header->id())) { + if (context->GetDominatorAnalysis(added_function) + ->Dominates(loop_header->id(), pred)) { + back_edge_block_id = pred; + break; + } + } + if (!back_edge_block_id) { + // The loop's back-edge block must be unreachable. This means that the + // loop cannot iterate, so there is no need to make it lifesafe; we can + // move on from this loop. + continue; + } + auto back_edge_block = context->cfg()->block(back_edge_block_id); + + // Go through the sequence of loop limiter infos and find the one + // corresponding to this loop. + bool found = false; + protobufs::LoopLimiterInfo loop_limiter_info; + for (auto& info : message_.loop_limiter_info()) { + if (info.loop_header_id() == loop_header->id()) { + loop_limiter_info = info; + found = true; + break; + } + } + if (!found) { + // We don't have loop limiter info for this loop header. + return false; + } + + // The back-edge block either has the form: + // + // (1) + // + // %l = OpLabel + // ... instructions ... + // OpBranch %loop_header + // + // (2) + // + // %l = OpLabel + // ... instructions ... + // OpBranchConditional %c %loop_header %loop_merge + // + // (3) + // + // %l = OpLabel + // ... instructions ... + // OpBranchConditional %c %loop_merge %loop_header + // + // We turn these into the following: + // + // (1) + // + // %l = OpLabel + // ... instructions ... + // %t1 = OpLoad %uint32 %loop_limiter + // %t2 = OpIAdd %uint32 %t1 %one + // OpStore %loop_limiter %t2 + // %t3 = OpUGreaterThanEqual %bool %t1 %loop_limit + // OpBranchConditional %t3 %loop_merge %loop_header + // + // (2) + // + // %l = OpLabel + // ... instructions ... + // %t1 = OpLoad %uint32 %loop_limiter + // %t2 = OpIAdd %uint32 %t1 %one + // OpStore %loop_limiter %t2 + // %t3 = OpULessThan %bool %t1 %loop_limit + // %t4 = OpLogicalAnd %bool %c %t3 + // OpBranchConditional %t4 %loop_header %loop_merge + // + // (3) + // + // %l = OpLabel + // ... instructions ... + // %t1 = OpLoad %uint32 %loop_limiter + // %t2 = OpIAdd %uint32 %t1 %one + // OpStore %loop_limiter %t2 + // %t3 = OpUGreaterThanEqual %bool %t1 %loop_limit + // %t4 = OpLogicalOr %bool %c %t3 + // OpBranchConditional %t4 %loop_merge %loop_header + + auto back_edge_block_terminator = back_edge_block->terminator(); + bool compare_using_greater_than_equal; + if (back_edge_block_terminator->opcode() == SpvOpBranch) { + compare_using_greater_than_equal = true; + } else { + assert(back_edge_block_terminator->opcode() == SpvOpBranchConditional); + assert(((back_edge_block_terminator->GetSingleWordInOperand(1) == + loop_header->id() && + back_edge_block_terminator->GetSingleWordInOperand(2) == + loop_header->MergeBlockId()) || + (back_edge_block_terminator->GetSingleWordInOperand(2) == + loop_header->id() && + back_edge_block_terminator->GetSingleWordInOperand(1) == + loop_header->MergeBlockId())) && + "A back edge edge block must branch to" + " either the loop header or merge"); + compare_using_greater_than_equal = + back_edge_block_terminator->GetSingleWordInOperand(1) == + loop_header->MergeBlockId(); + } + + std::vector> new_instructions; + + // Add a load from the loop limiter variable, of the form: + // %t1 = OpLoad %uint32 %loop_limiter + new_instructions.push_back(MakeUnique( + context, SpvOpLoad, unsigned_int_type_id, loop_limiter_info.load_id(), + opt::Instruction::OperandList( + {{SPV_OPERAND_TYPE_ID, {message_.loop_limiter_variable_id()}}}))); + + // Increment the loaded value: + // %t2 = OpIAdd %uint32 %t1 %one + new_instructions.push_back(MakeUnique( + context, SpvOpIAdd, unsigned_int_type_id, + loop_limiter_info.increment_id(), + opt::Instruction::OperandList( + {{SPV_OPERAND_TYPE_ID, {loop_limiter_info.load_id()}}, + {SPV_OPERAND_TYPE_ID, {one_id}}}))); + + // Store the incremented value back to the loop limiter variable: + // OpStore %loop_limiter %t2 + new_instructions.push_back(MakeUnique( + context, SpvOpStore, 0, 0, + opt::Instruction::OperandList( + {{SPV_OPERAND_TYPE_ID, {message_.loop_limiter_variable_id()}}, + {SPV_OPERAND_TYPE_ID, {loop_limiter_info.increment_id()}}}))); + + // Compare the loaded value with the loop limit; either: + // %t3 = OpUGreaterThanEqual %bool %t1 %loop_limit + // or + // %t3 = OpULessThan %bool %t1 %loop_limit + new_instructions.push_back(MakeUnique( + context, + compare_using_greater_than_equal ? SpvOpUGreaterThanEqual + : SpvOpULessThan, + bool_type_id, loop_limiter_info.compare_id(), + opt::Instruction::OperandList( + {{SPV_OPERAND_TYPE_ID, {loop_limiter_info.load_id()}}, + {SPV_OPERAND_TYPE_ID, {message_.loop_limit_constant_id()}}}))); + + if (back_edge_block_terminator->opcode() == SpvOpBranchConditional) { + new_instructions.push_back(MakeUnique( + context, + compare_using_greater_than_equal ? SpvOpLogicalOr : SpvOpLogicalAnd, + bool_type_id, loop_limiter_info.logical_op_id(), + opt::Instruction::OperandList( + {{SPV_OPERAND_TYPE_ID, + {back_edge_block_terminator->GetSingleWordInOperand(0)}}, + {SPV_OPERAND_TYPE_ID, {loop_limiter_info.compare_id()}}}))); + } + + // Add the new instructions at the end of the back edge block, before the + // terminator and any loop merge instruction (as the back edge block can + // be the loop header). + if (back_edge_block->GetLoopMergeInst()) { + back_edge_block->GetLoopMergeInst()->InsertBefore( + std::move(new_instructions)); + } else { + back_edge_block_terminator->InsertBefore(std::move(new_instructions)); + } + + if (back_edge_block_terminator->opcode() == SpvOpBranchConditional) { + back_edge_block_terminator->SetInOperand( + 0, {loop_limiter_info.logical_op_id()}); + } else { + assert(back_edge_block_terminator->opcode() == SpvOpBranch && + "Back-edge terminator must be OpBranch or OpBranchConditional"); + + // Check that, if the merge block starts with OpPhi instructions, suitable + // ids have been provided to give these instructions a value corresponding + // to the new incoming edge from the back edge block. + auto merge_block = context->cfg()->block(loop_header->MergeBlockId()); + if (!fuzzerutil::PhiIdsOkForNewEdge(context, back_edge_block, merge_block, + loop_limiter_info.phi_id())) { + return false; + } + + // Augment OpPhi instructions at the loop merge with the given ids. + uint32_t phi_index = 0; + for (auto& inst : *merge_block) { + if (inst.opcode() != SpvOpPhi) { + break; + } + assert(phi_index < + static_cast(loop_limiter_info.phi_id().size()) && + "There should be at least one phi id per OpPhi instruction."); + inst.AddOperand( + {SPV_OPERAND_TYPE_ID, {loop_limiter_info.phi_id(phi_index)}}); + inst.AddOperand({SPV_OPERAND_TYPE_ID, {back_edge_block_id}}); + phi_index++; + } + + // Add the new edge, by changing OpBranch to OpBranchConditional. + // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3162): This + // could be a problem if the merge block was originally unreachable: it + // might now be dominated by other blocks that it appears earlier than in + // the module. + back_edge_block_terminator->SetOpcode(SpvOpBranchConditional); + back_edge_block_terminator->SetInOperands(opt::Instruction::OperandList( + {{SPV_OPERAND_TYPE_ID, {loop_limiter_info.compare_id()}}, + {SPV_OPERAND_TYPE_ID, {loop_header->MergeBlockId()} + + }, + {SPV_OPERAND_TYPE_ID, {loop_header->id()}}})); + } + + // Update the module's id bound with respect to the various ids that + // have been used for loop limiter manipulation. + fuzzerutil::UpdateModuleIdBound(context, loop_limiter_info.load_id()); + fuzzerutil::UpdateModuleIdBound(context, loop_limiter_info.increment_id()); + fuzzerutil::UpdateModuleIdBound(context, loop_limiter_info.compare_id()); + fuzzerutil::UpdateModuleIdBound(context, loop_limiter_info.logical_op_id()); + } + return true; +} + +bool TransformationAddFunction::TryToTurnKillOrUnreachableIntoReturn( + opt::IRContext* context, opt::Function* added_function, + opt::Instruction* kill_or_unreachable_inst) const { + assert((kill_or_unreachable_inst->opcode() == SpvOpKill || + kill_or_unreachable_inst->opcode() == SpvOpUnreachable) && + "Precondition: instruction must be OpKill or OpUnreachable."); + + // Get the function's return type. + auto function_return_type_inst = + context->get_def_use_mgr()->GetDef(added_function->type_id()); + + if (function_return_type_inst->opcode() == SpvOpTypeVoid) { + // The function has void return type, so change this instruction to + // OpReturn. + kill_or_unreachable_inst->SetOpcode(SpvOpReturn); + } else { + // The function has non-void return type, so change this instruction + // to OpReturnValue, using the value id provided with the + // transformation. + + // We first check that the id, %id, provided with the transformation + // specifically to turn OpKill and OpUnreachable instructions into + // OpReturnValue %id has the same type as the function's return type. + if (context->get_def_use_mgr() + ->GetDef(message_.kill_unreachable_return_value_id()) + ->type_id() != function_return_type_inst->result_id()) { + return false; + } + kill_or_unreachable_inst->SetOpcode(SpvOpReturnValue); + kill_or_unreachable_inst->SetInOperands( + {{SPV_OPERAND_TYPE_ID, {message_.kill_unreachable_return_value_id()}}}); + } + return true; +} + +bool TransformationAddFunction::TryToClampAccessChainIndices( + opt::IRContext* context, opt::Instruction* access_chain_inst) const { + assert((access_chain_inst->opcode() == SpvOpAccessChain || + access_chain_inst->opcode() == SpvOpInBoundsAccessChain) && + "Precondition: instruction must be OpAccessChain or " + "OpInBoundsAccessChain."); + + // Find the AccessChainClampingInfo associated with this access chain. + const protobufs::AccessChainClampingInfo* access_chain_clamping_info = + nullptr; + for (auto& clamping_info : message_.access_chain_clamping_info()) { + if (clamping_info.access_chain_id() == access_chain_inst->result_id()) { + access_chain_clamping_info = &clamping_info; + break; + } + } + if (!access_chain_clamping_info) { + // No access chain clamping information was found; the function cannot be + // made livesafe. + return false; + } + + // Check that there is a (compare_id, select_id) pair for every + // index associated with the instruction. + if (static_cast( + access_chain_clamping_info->compare_and_select_ids().size()) != + access_chain_inst->NumInOperands() - 1) { + return false; + } + + // Walk the access chain, clamping each index to be within bounds if it is + // not a constant. + auto base_object = context->get_def_use_mgr()->GetDef( + access_chain_inst->GetSingleWordInOperand(0)); + assert(base_object && "The base object must exist."); + auto pointer_type = + context->get_def_use_mgr()->GetDef(base_object->type_id()); + assert(pointer_type && pointer_type->opcode() == SpvOpTypePointer && + "The base object must have pointer type."); + auto should_be_composite_type = context->get_def_use_mgr()->GetDef( + pointer_type->GetSingleWordInOperand(1)); + + // Consider each index input operand in turn (operand 0 is the base object). + for (uint32_t index = 1; index < access_chain_inst->NumInOperands(); + index++) { + // We are going to turn: + // + // %result = OpAccessChain %type %object ... %index ... + // + // into: + // + // %t1 = OpULessThanEqual %bool %index %bound_minus_one + // %t2 = OpSelect %int_type %t1 %index %bound_minus_one + // %result = OpAccessChain %type %object ... %t2 ... + // + // ... unless %index is already a constant. + + // Get the bound for the composite being indexed into; e.g. the number of + // columns of matrix or the size of an array. + uint32_t bound = + GetBoundForCompositeIndex(context, *should_be_composite_type); + + // Get the instruction associated with the index and figure out its integer + // type. + const uint32_t index_id = access_chain_inst->GetSingleWordInOperand(index); + auto index_inst = context->get_def_use_mgr()->GetDef(index_id); + auto index_type_inst = + context->get_def_use_mgr()->GetDef(index_inst->type_id()); + assert(index_type_inst->opcode() == SpvOpTypeInt); + assert(index_type_inst->GetSingleWordInOperand(0) == 32); + opt::analysis::Integer* index_int_type = + context->get_type_mgr() + ->GetType(index_type_inst->result_id()) + ->AsInteger(); + + if (index_inst->opcode() != SpvOpConstant) { + // The index is non-constant so we need to clamp it. + assert(should_be_composite_type->opcode() != SpvOpTypeStruct && + "Access chain indices into structures are required to be " + "constants."); + opt::analysis::IntConstant bound_minus_one(index_int_type, {bound - 1}); + if (!context->get_constant_mgr()->FindConstant(&bound_minus_one)) { + // We do not have an integer constant whose value is |bound| -1. + return false; + } + + opt::analysis::Bool bool_type; + uint32_t bool_type_id = context->get_type_mgr()->GetId(&bool_type); + if (!bool_type_id) { + // Bool type is not declared; we cannot do a comparison. + return false; + } + + uint32_t bound_minus_one_id = + context->get_constant_mgr() + ->GetDefiningInstruction(&bound_minus_one) + ->result_id(); + + uint32_t compare_id = + access_chain_clamping_info->compare_and_select_ids(index - 1).first(); + uint32_t select_id = + access_chain_clamping_info->compare_and_select_ids(index - 1) + .second(); + std::vector> new_instructions; + + // Compare the index with the bound via an instruction of the form: + // %t1 = OpULessThanEqual %bool %index %bound_minus_one + new_instructions.push_back(MakeUnique( + context, SpvOpULessThanEqual, bool_type_id, compare_id, + opt::Instruction::OperandList( + {{SPV_OPERAND_TYPE_ID, {index_inst->result_id()}}, + {SPV_OPERAND_TYPE_ID, {bound_minus_one_id}}}))); + + // Select the index if in-bounds, otherwise one less than the bound: + // %t2 = OpSelect %int_type %t1 %index %bound_minus_one + new_instructions.push_back(MakeUnique( + context, SpvOpSelect, index_type_inst->result_id(), select_id, + opt::Instruction::OperandList( + {{SPV_OPERAND_TYPE_ID, {compare_id}}, + {SPV_OPERAND_TYPE_ID, {index_inst->result_id()}}, + {SPV_OPERAND_TYPE_ID, {bound_minus_one_id}}}))); + + // Add the new instructions before the access chain + access_chain_inst->InsertBefore(std::move(new_instructions)); + + // Replace %index with %t2. + access_chain_inst->SetInOperand(index, {select_id}); + fuzzerutil::UpdateModuleIdBound(context, compare_id); + fuzzerutil::UpdateModuleIdBound(context, select_id); + } else { + // TODO(afd): At present the SPIR-V spec is not clear on whether + // statically out-of-bounds indices mean that a module is invalid (so + // that it should be rejected by the validator), or that such accesses + // yield undefined results. Via the following assertion, we assume that + // functions added to the module do not feature statically out-of-bounds + // accesses. + // Assert that the index is smaller (unsigned) than this value. + // Return false if it is not (to keep compilers happy). + if (index_inst->GetSingleWordInOperand(0) >= bound) { + assert(false && + "The function has a statically out-of-bounds access; " + "this should not occur."); + return false; + } + } + should_be_composite_type = + FollowCompositeIndex(context, *should_be_composite_type, index_id); + } + return true; +} + +uint32_t TransformationAddFunction::GetBoundForCompositeIndex( + opt::IRContext* context, const opt::Instruction& composite_type_inst) { + switch (composite_type_inst.opcode()) { + case SpvOpTypeArray: + return fuzzerutil::GetArraySize(composite_type_inst, context); + case SpvOpTypeMatrix: + case SpvOpTypeVector: + return composite_type_inst.GetSingleWordInOperand(1); + case SpvOpTypeStruct: { + return fuzzerutil::GetNumberOfStructMembers(composite_type_inst); + } + default: + assert(false && "Unknown composite type."); + return 0; + } +} + +opt::Instruction* TransformationAddFunction::FollowCompositeIndex( + opt::IRContext* context, const opt::Instruction& composite_type_inst, + uint32_t index_id) { + uint32_t sub_object_type_id; + switch (composite_type_inst.opcode()) { + case SpvOpTypeArray: + sub_object_type_id = composite_type_inst.GetSingleWordInOperand(0); + break; + case SpvOpTypeMatrix: + case SpvOpTypeVector: + sub_object_type_id = composite_type_inst.GetSingleWordInOperand(0); + break; + case SpvOpTypeStruct: { + auto index_inst = context->get_def_use_mgr()->GetDef(index_id); + assert(index_inst->opcode() == SpvOpConstant); + assert( + context->get_def_use_mgr()->GetDef(index_inst->type_id())->opcode() == + SpvOpTypeInt); + assert(context->get_def_use_mgr() + ->GetDef(index_inst->type_id()) + ->GetSingleWordInOperand(0) == 32); + uint32_t index_value = index_inst->GetSingleWordInOperand(0); + sub_object_type_id = + composite_type_inst.GetSingleWordInOperand(index_value); + break; + } + default: + assert(false && "Unknown composite type."); + sub_object_type_id = 0; + break; + } + assert(sub_object_type_id && "No sub-object found."); + return context->get_def_use_mgr()->GetDef(sub_object_type_id); +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/transformation_add_function.h b/third_party/spirv-tools/source/fuzz/transformation_add_function.h new file mode 100644 index 0000000000..848b799fca --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_add_function.h @@ -0,0 +1,124 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_FUNCTION_H_ +#define SOURCE_FUZZ_TRANSFORMATION_ADD_FUNCTION_H_ + +#include "source/fuzz/fact_manager.h" +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "source/fuzz/transformation.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace fuzz { + +class TransformationAddFunction : public Transformation { + public: + explicit TransformationAddFunction( + const protobufs::TransformationAddFunction& message); + + // Creates a transformation to add a non live-safe function. + explicit TransformationAddFunction( + const std::vector& instructions); + + // Creates a transformation to add a live-safe function. + TransformationAddFunction( + const std::vector& instructions, + uint32_t loop_limiter_variable_id, uint32_t loop_limit_constant_id, + const std::vector& loop_limiters, + uint32_t kill_unreachable_return_value_id, + const std::vector& + access_chain_clampers); + + // - |message_.instruction| must correspond to a sufficiently well-formed + // sequence of instructions that a function can be created from them + // - If |message_.is_livesafe| holds then |message_| must contain suitable + // ingredients to make the function livesafe, and the function must only + // invoke other livesafe functions + // - Adding the created function to the module must lead to a valid module. + bool IsApplicable(opt::IRContext* context, + const FactManager& fact_manager) const override; + + // Adds the function defined by |message_.instruction| to the module, making + // it livesafe if |message_.is_livesafe| holds. + void Apply(opt::IRContext* context, FactManager* fact_manager) const override; + + protobufs::Transformation ToMessage() const override; + + // Helper method that returns the bound for indexing into a composite of type + // |composite_type_inst|, i.e. the number of fields of a struct, the size of + // an array, the number of components of a vector, or the number of columns of + // a matrix. + static uint32_t GetBoundForCompositeIndex( + opt::IRContext* context, const opt::Instruction& composite_type_inst); + + // Helper method that, given composite type |composite_type_inst|, returns the + // type of the sub-object at index |index_id|, which is required to be in- + // bounds. + static opt::Instruction* FollowCompositeIndex( + opt::IRContext* context, const opt::Instruction& composite_type_inst, + uint32_t index_id); + + private: + // Attempts to create a function from the series of instructions in + // |message_.instruction| and add it to |context|. + // + // Returns false if adding the function is not possible due to the messages + // not respecting the basic structure of a function, e.g. if there is no + // OpFunction instruction or no blocks; in this case |context| is left in an + // indeterminate state. + // + // Otherwise returns true. Whether |context| is valid after addition of the + // function depends on the contents of |message_.instruction|. + // + // Intended usage: + // - Perform a dry run of this method on a clone of a module, and use + // the validator to check whether the resulting module is valid. Working + // on a clone means it does not matter if the function fails to be cleanly + // added, or leads to an invalid module. + // - If the dry run succeeds, run the method on the real module of interest, + // to add the function. + bool TryToAddFunction(opt::IRContext* context) const; + + // Should only be called if |message_.is_livesafe| holds. Attempts to make + // the function livesafe (see FactFunctionIsLivesafe for a definition). + // Returns false if this is not possible, due to |message_| or |context| not + // containing sufficient ingredients (such as types and fresh ids) to add + // the instrumentation necessary to make the function livesafe. + bool TryToMakeFunctionLivesafe(opt::IRContext* context, + const FactManager& fact_manager) const; + + // A helper for TryToMakeFunctionLivesafe that tries to add loop-limiting + // logic. + bool TryToAddLoopLimiters(opt::IRContext* context, + opt::Function* added_function) const; + + // A helper for TryToMakeFunctionLivesafe that tries to replace OpKill and + // OpUnreachable instructions into return instructions. + bool TryToTurnKillOrUnreachableIntoReturn( + opt::IRContext* context, opt::Function* added_function, + opt::Instruction* kill_or_unreachable_inst) const; + + // A helper for TryToMakeFunctionLivesafe that tries to clamp access chain + // indices so that they are guaranteed to be in-bounds. + bool TryToClampAccessChainIndices(opt::IRContext* context, + opt::Instruction* access_chain_inst) const; + + protobufs::TransformationAddFunction message_; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_TRANSFORMATION_ADD_FUNCTION_H_ diff --git a/third_party/spirv-tools/source/fuzz/transformation_add_global_undef.cpp b/third_party/spirv-tools/source/fuzz/transformation_add_global_undef.cpp new file mode 100644 index 0000000000..f9585b3bc6 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_add_global_undef.cpp @@ -0,0 +1,62 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_add_global_undef.h" + +#include "source/fuzz/fuzzer_util.h" + +namespace spvtools { +namespace fuzz { + +TransformationAddGlobalUndef::TransformationAddGlobalUndef( + const spvtools::fuzz::protobufs::TransformationAddGlobalUndef& message) + : message_(message) {} + +TransformationAddGlobalUndef::TransformationAddGlobalUndef(uint32_t fresh_id, + uint32_t type_id) { + message_.set_fresh_id(fresh_id); + message_.set_type_id(type_id); +} + +bool TransformationAddGlobalUndef::IsApplicable( + opt::IRContext* context, + const spvtools::fuzz::FactManager& /*unused*/) const { + // A fresh id is required. + if (!fuzzerutil::IsFreshId(context, message_.fresh_id())) { + return false; + } + auto type = context->get_type_mgr()->GetType(message_.type_id()); + // The type must exist, and must not be a function type. + return type && !type->AsFunction(); +} + +void TransformationAddGlobalUndef::Apply( + opt::IRContext* context, spvtools::fuzz::FactManager* /*unused*/) const { + context->module()->AddGlobalValue(MakeUnique( + context, SpvOpUndef, message_.type_id(), message_.fresh_id(), + opt::Instruction::OperandList())); + fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id()); + // We have added an instruction to the module, so need to be careful about the + // validity of existing analyses. + context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone); +} + +protobufs::Transformation TransformationAddGlobalUndef::ToMessage() const { + protobufs::Transformation result; + *result.mutable_add_global_undef() = message_; + return result; +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/transformation_add_global_undef.h b/third_party/spirv-tools/source/fuzz/transformation_add_global_undef.h new file mode 100644 index 0000000000..550d9f68fa --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_add_global_undef.h @@ -0,0 +1,51 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_GLOBAL_UNDEF_H_ +#define SOURCE_FUZZ_TRANSFORMATION_ADD_GLOBAL_UNDEF_H_ + +#include "source/fuzz/fact_manager.h" +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "source/fuzz/transformation.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace fuzz { + +class TransformationAddGlobalUndef : public Transformation { + public: + explicit TransformationAddGlobalUndef( + const protobufs::TransformationAddGlobalUndef& message); + + TransformationAddGlobalUndef(uint32_t fresh_id, uint32_t type_id); + + // - |message_.fresh_id| must be fresh + // - |message_.type_id| must be the id of a non-function type + bool IsApplicable(opt::IRContext* context, + const FactManager& fact_manager) const override; + + // Adds an OpUndef instruction to the module, with |message_.type_id| as its + // type. The instruction has result id |message_.fresh_id|. + void Apply(opt::IRContext* context, FactManager* fact_manager) const override; + + protobufs::Transformation ToMessage() const override; + + private: + protobufs::TransformationAddGlobalUndef message_; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_TRANSFORMATION_ADD_GLOBAL_UNDEF_H_ diff --git a/third_party/spirv-tools/source/fuzz/transformation_add_global_variable.cpp b/third_party/spirv-tools/source/fuzz/transformation_add_global_variable.cpp new file mode 100644 index 0000000000..c08517f9a5 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_add_global_variable.cpp @@ -0,0 +1,137 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_add_global_variable.h" + +#include "source/fuzz/fuzzer_util.h" + +namespace spvtools { +namespace fuzz { + +TransformationAddGlobalVariable::TransformationAddGlobalVariable( + const spvtools::fuzz::protobufs::TransformationAddGlobalVariable& message) + : message_(message) {} + +TransformationAddGlobalVariable::TransformationAddGlobalVariable( + uint32_t fresh_id, uint32_t type_id, uint32_t initializer_id, + bool value_is_arbitrary) { + message_.set_fresh_id(fresh_id); + message_.set_type_id(type_id); + message_.set_initializer_id(initializer_id); + message_.set_value_is_arbitrary(value_is_arbitrary); +} + +bool TransformationAddGlobalVariable::IsApplicable( + opt::IRContext* context, + const spvtools::fuzz::FactManager& /*unused*/) const { + // The result id must be fresh. + if (!fuzzerutil::IsFreshId(context, message_.fresh_id())) { + return false; + } + // The type id must correspond to a type. + auto type = context->get_type_mgr()->GetType(message_.type_id()); + if (!type) { + return false; + } + // That type must be a pointer type ... + auto pointer_type = type->AsPointer(); + if (!pointer_type) { + return false; + } + // ... with Private storage class. + if (pointer_type->storage_class() != SpvStorageClassPrivate) { + return false; + } + if (message_.initializer_id()) { + // The initializer id must be the id of a constant. Check this with the + // constant manager. + auto constant_id = context->get_constant_mgr()->GetConstantsFromIds( + {message_.initializer_id()}); + if (constant_id.empty()) { + return false; + } + assert(constant_id.size() == 1 && + "We asked for the constant associated with a single id; we should " + "get a single constant."); + // The type of the constant must match the pointee type of the pointer. + if (pointer_type->pointee_type() != constant_id[0]->type()) { + return false; + } + } + return true; +} + +void TransformationAddGlobalVariable::Apply( + opt::IRContext* context, spvtools::fuzz::FactManager* fact_manager) const { + opt::Instruction::OperandList input_operands; + input_operands.push_back( + {SPV_OPERAND_TYPE_STORAGE_CLASS, {SpvStorageClassPrivate}}); + if (message_.initializer_id()) { + input_operands.push_back( + {SPV_OPERAND_TYPE_ID, {message_.initializer_id()}}); + } + context->module()->AddGlobalValue( + MakeUnique(context, SpvOpVariable, message_.type_id(), + message_.fresh_id(), input_operands)); + fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id()); + + if (PrivateGlobalsMustBeDeclaredInEntryPointInterfaces(context)) { + // Conservatively add this global to the interface of every entry point in + // the module. This means that the global is available for other + // transformations to use. + // + // A downside of this is that the global will be in the interface even if it + // ends up never being used. + // + // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3111) revisit + // this if a more thorough approach to entry point interfaces is taken. + for (auto& entry_point : context->module()->entry_points()) { + entry_point.AddOperand({SPV_OPERAND_TYPE_ID, {message_.fresh_id()}}); + } + } + + if (message_.value_is_arbitrary()) { + fact_manager->AddFactValueOfVariableIsArbitrary(message_.fresh_id()); + } + + // We have added an instruction to the module, so need to be careful about the + // validity of existing analyses. + context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone); +} + +protobufs::Transformation TransformationAddGlobalVariable::ToMessage() const { + protobufs::Transformation result; + *result.mutable_add_global_variable() = message_; + return result; +} + +bool TransformationAddGlobalVariable:: + PrivateGlobalsMustBeDeclaredInEntryPointInterfaces( + opt::IRContext* context) { + // TODO(afd): We capture the universal environments for which this requirement + // holds. The check should be refined on demand for other target + // environments. + switch (context->grammar().target_env()) { + case SPV_ENV_UNIVERSAL_1_0: + case SPV_ENV_UNIVERSAL_1_1: + case SPV_ENV_UNIVERSAL_1_2: + case SPV_ENV_UNIVERSAL_1_3: + return false; + default: + return true; + } +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/transformation_add_global_variable.h b/third_party/spirv-tools/source/fuzz/transformation_add_global_variable.h new file mode 100644 index 0000000000..406c915715 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_add_global_variable.h @@ -0,0 +1,61 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_GLOBAL_VARIABLE_H_ +#define SOURCE_FUZZ_TRANSFORMATION_ADD_GLOBAL_VARIABLE_H_ + +#include "source/fuzz/fact_manager.h" +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "source/fuzz/transformation.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace fuzz { + +class TransformationAddGlobalVariable : public Transformation { + public: + explicit TransformationAddGlobalVariable( + const protobufs::TransformationAddGlobalVariable& message); + + TransformationAddGlobalVariable(uint32_t fresh_id, uint32_t type_id, + uint32_t initializer_id, + bool value_is_arbitrary); + + // - |message_.fresh_id| must be fresh + // - |message_.type_id| must be the id of a pointer type with Private storage + // class + // - |message_.initializer_id| must either be 0 or the id of a constant whose + // type is the pointee type of |message_.type_id| + bool IsApplicable(opt::IRContext* context, + const FactManager& fact_manager) const override; + + // Adds a global variable with Private storage class to the module, with type + // |message_.type_id| and either no initializer or |message_.initializer_id| + // as an initializer, depending on whether |message_.initializer_id| is 0. + // The global variable has result id |message_.fresh_id|. + void Apply(opt::IRContext* context, FactManager* fact_manager) const override; + + protobufs::Transformation ToMessage() const override; + + private: + static bool PrivateGlobalsMustBeDeclaredInEntryPointInterfaces( + opt::IRContext* context); + + protobufs::TransformationAddGlobalVariable message_; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_TRANSFORMATION_ADD_GLOBAL_VARIABLE_H_ diff --git a/third_party/spirv-tools/source/fuzz/transformation_add_no_contraction_decoration.cpp b/third_party/spirv-tools/source/fuzz/transformation_add_no_contraction_decoration.cpp new file mode 100644 index 0000000000..7f22cc22c7 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_add_no_contraction_decoration.cpp @@ -0,0 +1,110 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_add_no_contraction_decoration.h" + +#include "source/fuzz/fuzzer_util.h" + +namespace spvtools { +namespace fuzz { + +TransformationAddNoContractionDecoration:: + TransformationAddNoContractionDecoration( + const spvtools::fuzz::protobufs:: + TransformationAddNoContractionDecoration& message) + : message_(message) {} + +TransformationAddNoContractionDecoration:: + TransformationAddNoContractionDecoration(uint32_t result_id) { + message_.set_result_id(result_id); +} + +bool TransformationAddNoContractionDecoration::IsApplicable( + opt::IRContext* context, + const spvtools::fuzz::FactManager& /*unused*/) const { + // |message_.result_id| must be the id of an instruction. + auto instr = context->get_def_use_mgr()->GetDef(message_.result_id()); + if (!instr) { + return false; + } + // The instruction must be arithmetic. + return IsArithmetic(instr->opcode()); +} + +void TransformationAddNoContractionDecoration::Apply( + opt::IRContext* context, spvtools::fuzz::FactManager* /*unused*/) const { + // Add a NoContraction decoration targeting |message_.result_id|. + context->get_decoration_mgr()->AddDecoration(message_.result_id(), + SpvDecorationNoContraction); +} + +protobufs::Transformation TransformationAddNoContractionDecoration::ToMessage() + const { + protobufs::Transformation result; + *result.mutable_add_no_contraction_decoration() = message_; + return result; +} + +bool TransformationAddNoContractionDecoration::IsArithmetic(uint32_t opcode) { + switch (opcode) { + case SpvOpSNegate: + case SpvOpFNegate: + case SpvOpIAdd: + case SpvOpFAdd: + case SpvOpISub: + case SpvOpFSub: + case SpvOpIMul: + case SpvOpFMul: + case SpvOpUDiv: + case SpvOpSDiv: + case SpvOpFDiv: + case SpvOpUMod: + case SpvOpSRem: + case SpvOpSMod: + case SpvOpFRem: + case SpvOpFMod: + case SpvOpVectorTimesScalar: + case SpvOpMatrixTimesScalar: + case SpvOpVectorTimesMatrix: + case SpvOpMatrixTimesVector: + case SpvOpMatrixTimesMatrix: + case SpvOpOuterProduct: + case SpvOpDot: + case SpvOpIAddCarry: + case SpvOpISubBorrow: + case SpvOpUMulExtended: + case SpvOpSMulExtended: + case SpvOpAny: + case SpvOpAll: + case SpvOpIsNan: + case SpvOpIsInf: + case SpvOpIsFinite: + case SpvOpIsNormal: + case SpvOpSignBitSet: + case SpvOpLessOrGreater: + case SpvOpOrdered: + case SpvOpUnordered: + case SpvOpLogicalEqual: + case SpvOpLogicalNotEqual: + case SpvOpLogicalOr: + case SpvOpLogicalAnd: + case SpvOpLogicalNot: + return true; + default: + return false; + } +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/transformation_add_no_contraction_decoration.h b/third_party/spirv-tools/source/fuzz/transformation_add_no_contraction_decoration.h new file mode 100644 index 0000000000..cec1b2cded --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_add_no_contraction_decoration.h @@ -0,0 +1,58 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_NO_CONTRACTION_DECORATION_H_ +#define SOURCE_FUZZ_TRANSFORMATION_ADD_NO_CONTRACTION_DECORATION_H_ + +#include "source/fuzz/fact_manager.h" +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "source/fuzz/transformation.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace fuzz { + +class TransformationAddNoContractionDecoration : public Transformation { + public: + explicit TransformationAddNoContractionDecoration( + const protobufs::TransformationAddNoContractionDecoration& message); + + explicit TransformationAddNoContractionDecoration(uint32_t fresh_id); + + // - |message_.result_id| must be the result id of an arithmetic instruction, + // as defined by the SPIR-V specification. + // - It does not matter whether this instruction is already annotated with the + // NoContraction decoration. + bool IsApplicable(opt::IRContext* context, + const FactManager& fact_manager) const override; + + // Adds a decoration of the form: + // 'OpDecoration |message_.result_id| NoContraction' + // to the module. + void Apply(opt::IRContext* context, FactManager* fact_manager) const override; + + protobufs::Transformation ToMessage() const override; + + // Returns true if and only if |opcode| is the opcode of an arithmetic + // instruction, as defined by the SPIR-V specification. + static bool IsArithmetic(uint32_t opcode); + + private: + protobufs::TransformationAddNoContractionDecoration message_; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_TRANSFORMATION_ADD_NO_CONTRACTION_DECORATION_H_ diff --git a/third_party/spirv-tools/source/fuzz/transformation_add_type_array.cpp b/third_party/spirv-tools/source/fuzz/transformation_add_type_array.cpp new file mode 100644 index 0000000000..2074e98a1e --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_add_type_array.cpp @@ -0,0 +1,88 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_add_type_array.h" + +#include "source/fuzz/fuzzer_util.h" + +namespace spvtools { +namespace fuzz { + +TransformationAddTypeArray::TransformationAddTypeArray( + const spvtools::fuzz::protobufs::TransformationAddTypeArray& message) + : message_(message) {} + +TransformationAddTypeArray::TransformationAddTypeArray(uint32_t fresh_id, + uint32_t element_type_id, + uint32_t size_id) { + message_.set_fresh_id(fresh_id); + message_.set_element_type_id(element_type_id); + message_.set_size_id(size_id); +} + +bool TransformationAddTypeArray::IsApplicable( + opt::IRContext* context, + const spvtools::fuzz::FactManager& /*unused*/) const { + // A fresh id is required. + if (!fuzzerutil::IsFreshId(context, message_.fresh_id())) { + return false; + } + auto element_type = + context->get_type_mgr()->GetType(message_.element_type_id()); + if (!element_type || element_type->AsFunction()) { + // The element type id either does not refer to a type, or refers to a + // function type; both are illegal. + return false; + } + auto constant = + context->get_constant_mgr()->GetConstantsFromIds({message_.size_id()}); + if (constant.empty()) { + // The size id does not refer to a constant. + return false; + } + assert(constant.size() == 1 && + "Only one constant id was provided, so only one constant should have " + "been returned"); + + auto int_constant = constant[0]->AsIntConstant(); + if (!int_constant) { + // The size constant is not an integer. + return false; + } + // We require that the size constant be a 32-bit value that is positive when + // interpreted as being signed. + return int_constant->words().size() == 1 && int_constant->GetS32() >= 1; +} + +void TransformationAddTypeArray::Apply( + opt::IRContext* context, spvtools::fuzz::FactManager* /*unused*/) const { + opt::Instruction::OperandList in_operands; + in_operands.push_back({SPV_OPERAND_TYPE_ID, {message_.element_type_id()}}); + in_operands.push_back({SPV_OPERAND_TYPE_ID, {message_.size_id()}}); + context->module()->AddType(MakeUnique( + context, SpvOpTypeArray, 0, message_.fresh_id(), in_operands)); + fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id()); + // We have added an instruction to the module, so need to be careful about the + // validity of existing analyses. + context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone); +} + +protobufs::Transformation TransformationAddTypeArray::ToMessage() const { + protobufs::Transformation result; + *result.mutable_add_type_array() = message_; + return result; +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/transformation_add_type_array.h b/third_party/spirv-tools/source/fuzz/transformation_add_type_array.h new file mode 100644 index 0000000000..b6e071827d --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_add_type_array.h @@ -0,0 +1,55 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_ARRAY_H_ +#define SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_ARRAY_H_ + +#include "source/fuzz/fact_manager.h" +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "source/fuzz/transformation.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace fuzz { + +class TransformationAddTypeArray : public Transformation { + public: + explicit TransformationAddTypeArray( + const protobufs::TransformationAddTypeArray& message); + + TransformationAddTypeArray(uint32_t fresh_id, uint32_t element_type_id, + uint32_t size_id); + + // - |message_.fresh_id| must be fresh + // - |message_.element_type_id| must be the id of a non-function type + // - |message_.size_id| must be the id of a 32-bit integer constant that is + // positive when interpreted as signed. + bool IsApplicable(opt::IRContext* context, + const FactManager& fact_manager) const override; + + // Adds an OpTypeArray instruction to the module, with element type given by + // |message_.element_type_id| and size given by |message_.size_id|. The + // result id of the instruction is |message_.fresh_id|. + void Apply(opt::IRContext* context, FactManager* fact_manager) const override; + + protobufs::Transformation ToMessage() const override; + + private: + protobufs::TransformationAddTypeArray message_; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_ARRAY_H_ diff --git a/third_party/spirv-tools/source/fuzz/transformation_add_type_boolean.cpp b/third_party/spirv-tools/source/fuzz/transformation_add_type_boolean.cpp new file mode 100644 index 0000000000..b55028a6be --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_add_type_boolean.cpp @@ -0,0 +1,61 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_add_type_boolean.h" + +#include "source/fuzz/fuzzer_util.h" + +namespace spvtools { +namespace fuzz { + +TransformationAddTypeBoolean::TransformationAddTypeBoolean( + const spvtools::fuzz::protobufs::TransformationAddTypeBoolean& message) + : message_(message) {} + +TransformationAddTypeBoolean::TransformationAddTypeBoolean(uint32_t fresh_id) { + message_.set_fresh_id(fresh_id); +} + +bool TransformationAddTypeBoolean::IsApplicable( + opt::IRContext* context, + const spvtools::fuzz::FactManager& /*unused*/) const { + // The id must be fresh. + if (!fuzzerutil::IsFreshId(context, message_.fresh_id())) { + return false; + } + + // Applicable if there is no bool type already declared in the module. + opt::analysis::Bool bool_type; + return context->get_type_mgr()->GetId(&bool_type) == 0; +} + +void TransformationAddTypeBoolean::Apply( + opt::IRContext* context, spvtools::fuzz::FactManager* /*unused*/) const { + opt::Instruction::OperandList empty_operands; + context->module()->AddType(MakeUnique( + context, SpvOpTypeBool, 0, message_.fresh_id(), empty_operands)); + fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id()); + // We have added an instruction to the module, so need to be careful about the + // validity of existing analyses. + context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone); +} + +protobufs::Transformation TransformationAddTypeBoolean::ToMessage() const { + protobufs::Transformation result; + *result.mutable_add_type_boolean() = message_; + return result; +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/transformation_add_type_boolean.h b/third_party/spirv-tools/source/fuzz/transformation_add_type_boolean.h new file mode 100644 index 0000000000..98c1e639c7 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_add_type_boolean.h @@ -0,0 +1,50 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_BOOLEAN_H_ +#define SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_BOOLEAN_H_ + +#include "source/fuzz/fact_manager.h" +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "source/fuzz/transformation.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace fuzz { + +class TransformationAddTypeBoolean : public Transformation { + public: + explicit TransformationAddTypeBoolean( + const protobufs::TransformationAddTypeBoolean& message); + + explicit TransformationAddTypeBoolean(uint32_t fresh_id); + + // - |message_.fresh_id| must not be used by the module. + // - The module must not yet declare OpTypeBoolean + bool IsApplicable(opt::IRContext* context, + const FactManager& fact_manager) const override; + + // Adds OpTypeBoolean with |message_.fresh_id| as result id. + void Apply(opt::IRContext* context, FactManager* fact_manager) const override; + + protobufs::Transformation ToMessage() const override; + + private: + protobufs::TransformationAddTypeBoolean message_; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_BOOLEAN_H_ diff --git a/third_party/spirv-tools/source/fuzz/transformation_add_type_float.cpp b/third_party/spirv-tools/source/fuzz/transformation_add_type_float.cpp new file mode 100644 index 0000000000..d2af5f885b --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_add_type_float.cpp @@ -0,0 +1,65 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_add_type_float.h" + +#include "source/fuzz/fuzzer_util.h" + +namespace spvtools { +namespace fuzz { + +TransformationAddTypeFloat::TransformationAddTypeFloat(uint32_t fresh_id, + uint32_t width) { + message_.set_fresh_id(fresh_id); + message_.set_width(width); +} + +TransformationAddTypeFloat::TransformationAddTypeFloat( + const spvtools::fuzz::protobufs::TransformationAddTypeFloat& message) + : message_(message) {} + +bool TransformationAddTypeFloat::IsApplicable( + opt::IRContext* context, + const spvtools::fuzz::FactManager& /*unused*/) const { + // The id must be fresh. + if (!fuzzerutil::IsFreshId(context, message_.fresh_id())) { + return false; + } + + // Applicable if there is no float type with this width already declared in + // the module. + opt::analysis::Float float_type(message_.width()); + return context->get_type_mgr()->GetId(&float_type) == 0; +} + +void TransformationAddTypeFloat::Apply( + opt::IRContext* context, spvtools::fuzz::FactManager* /*unused*/) const { + opt::Instruction::OperandList width = { + {SPV_OPERAND_TYPE_LITERAL_INTEGER, {message_.width()}}}; + context->module()->AddType(MakeUnique( + context, SpvOpTypeFloat, 0, message_.fresh_id(), width)); + fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id()); + // We have added an instruction to the module, so need to be careful about the + // validity of existing analyses. + context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone); +} + +protobufs::Transformation TransformationAddTypeFloat::ToMessage() const { + protobufs::Transformation result; + *result.mutable_add_type_float() = message_; + return result; +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/transformation_add_type_float.h b/third_party/spirv-tools/source/fuzz/transformation_add_type_float.h new file mode 100644 index 0000000000..0fdc8314ef --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_add_type_float.h @@ -0,0 +1,51 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_FLOAT_H_ +#define SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_FLOAT_H_ + +#include "source/fuzz/fact_manager.h" +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "source/fuzz/transformation.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace fuzz { + +class TransformationAddTypeFloat : public Transformation { + public: + explicit TransformationAddTypeFloat( + const protobufs::TransformationAddTypeFloat& message); + + TransformationAddTypeFloat(uint32_t fresh_id, uint32_t width); + + // - |message_.fresh_id| must not be used by the module + // - The module must not contain an OpTypeFloat instruction with width + // |message_.width| + bool IsApplicable(opt::IRContext* context, + const FactManager& fact_manager) const override; + + // Adds an OpTypeFloat instruction to the module with the given width + void Apply(opt::IRContext* context, FactManager* fact_manager) const override; + + protobufs::Transformation ToMessage() const override; + + private: + protobufs::TransformationAddTypeFloat message_; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_FLOAT_H_ diff --git a/third_party/spirv-tools/source/fuzz/transformation_add_type_function.cpp b/third_party/spirv-tools/source/fuzz/transformation_add_type_function.cpp new file mode 100644 index 0000000000..4b6717b868 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_add_type_function.cpp @@ -0,0 +1,113 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_add_type_function.h" + +#include + +#include "source/fuzz/fuzzer_util.h" + +namespace spvtools { +namespace fuzz { + +TransformationAddTypeFunction::TransformationAddTypeFunction( + const spvtools::fuzz::protobufs::TransformationAddTypeFunction& message) + : message_(message) {} + +TransformationAddTypeFunction::TransformationAddTypeFunction( + uint32_t fresh_id, uint32_t return_type_id, + const std::vector& argument_type_ids) { + message_.set_fresh_id(fresh_id); + message_.set_return_type_id(return_type_id); + for (auto id : argument_type_ids) { + message_.add_argument_type_id(id); + } +} + +bool TransformationAddTypeFunction::IsApplicable( + opt::IRContext* context, + const spvtools::fuzz::FactManager& /*unused*/) const { + // The result id must be fresh. + if (!fuzzerutil::IsFreshId(context, message_.fresh_id())) { + return false; + } + // The return and argument types must be type ids but not not be function + // type ids. + if (!fuzzerutil::IsNonFunctionTypeId(context, message_.return_type_id())) { + return false; + } + for (auto argument_type_id : message_.argument_type_id()) { + if (!fuzzerutil::IsNonFunctionTypeId(context, argument_type_id)) { + return false; + } + } + // Check whether there is already an OpTypeFunction definition that uses + // exactly the same return and argument type ids. (Note that the type manager + // does not allow us to check this, as it does not distinguish between + // function types with different but isomorphic pointer argument types.) + for (auto& inst : context->module()->types_values()) { + if (inst.opcode() != SpvOpTypeFunction) { + // Consider only OpTypeFunction instructions. + continue; + } + if (inst.GetSingleWordInOperand(0) != message_.return_type_id()) { + // Different return types - cannot be the same. + continue; + } + if (inst.NumInOperands() != + 1 + static_cast(message_.argument_type_id().size())) { + // Different numbers of arguments - cannot be the same. + continue; + } + bool found_argument_mismatch = false; + for (uint32_t index = 1; index < inst.NumInOperands(); index++) { + if (message_.argument_type_id(index - 1) != + inst.GetSingleWordInOperand(index)) { + // Argument mismatch - cannot be the same. + found_argument_mismatch = true; + break; + } + } + if (found_argument_mismatch) { + continue; + } + // Everything matches - the type is already declared. + return false; + } + return true; +} + +void TransformationAddTypeFunction::Apply( + opt::IRContext* context, spvtools::fuzz::FactManager* /*unused*/) const { + opt::Instruction::OperandList in_operands; + in_operands.push_back({SPV_OPERAND_TYPE_ID, {message_.return_type_id()}}); + for (auto argument_type_id : message_.argument_type_id()) { + in_operands.push_back({SPV_OPERAND_TYPE_ID, {argument_type_id}}); + } + context->module()->AddType(MakeUnique( + context, SpvOpTypeFunction, 0, message_.fresh_id(), in_operands)); + fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id()); + // We have added an instruction to the module, so need to be careful about the + // validity of existing analyses. + context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone); +} + +protobufs::Transformation TransformationAddTypeFunction::ToMessage() const { + protobufs::Transformation result; + *result.mutable_add_type_function() = message_; + return result; +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/transformation_add_type_function.h b/third_party/spirv-tools/source/fuzz/transformation_add_type_function.h new file mode 100644 index 0000000000..2b596613ae --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_add_type_function.h @@ -0,0 +1,59 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_FUNCTION_H_ +#define SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_FUNCTION_H_ + +#include + +#include "source/fuzz/fact_manager.h" +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "source/fuzz/transformation.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace fuzz { + +class TransformationAddTypeFunction : public Transformation { + public: + explicit TransformationAddTypeFunction( + const protobufs::TransformationAddTypeFunction& message); + + TransformationAddTypeFunction(uint32_t fresh_id, uint32_t return_type_id, + const std::vector& argument_type_ids); + + // - |message_.fresh_id| must not be used by the module + // - |message_.return_type_id| and each element of |message_.argument_type_id| + // must be the ids of non-function types + // - The module must not contain an OpTypeFunction instruction defining a + // function type with the signature provided by teh given return and + // argument types + bool IsApplicable(opt::IRContext* context, + const FactManager& fact_manager) const override; + + // Adds an OpTypeFunction instruction to the module, with signature given by + // |message_.return_type_id| and |message_.argument_type_id|. The result id + // for the instruction is |message_.fresh_id|. + void Apply(opt::IRContext* context, FactManager* fact_manager) const override; + + protobufs::Transformation ToMessage() const override; + + private: + protobufs::TransformationAddTypeFunction message_; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_FUNCTION_H_ diff --git a/third_party/spirv-tools/source/fuzz/transformation_add_type_int.cpp b/third_party/spirv-tools/source/fuzz/transformation_add_type_int.cpp new file mode 100644 index 0000000000..6f592709a8 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_add_type_int.cpp @@ -0,0 +1,68 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_add_type_int.h" + +#include "source/fuzz/fuzzer_util.h" + +namespace spvtools { +namespace fuzz { + +TransformationAddTypeInt::TransformationAddTypeInt( + const spvtools::fuzz::protobufs::TransformationAddTypeInt& message) + : message_(message) {} + +TransformationAddTypeInt::TransformationAddTypeInt(uint32_t fresh_id, + uint32_t width, + bool is_signed) { + message_.set_fresh_id(fresh_id); + message_.set_width(width); + message_.set_is_signed(is_signed); +} + +bool TransformationAddTypeInt::IsApplicable( + opt::IRContext* context, + const spvtools::fuzz::FactManager& /*unused*/) const { + // The id must be fresh. + if (!fuzzerutil::IsFreshId(context, message_.fresh_id())) { + return false; + } + + // Applicable if there is no int type with this width and signedness already + // declared in the module. + opt::analysis::Integer int_type(message_.width(), message_.is_signed()); + return context->get_type_mgr()->GetId(&int_type) == 0; +} + +void TransformationAddTypeInt::Apply( + opt::IRContext* context, spvtools::fuzz::FactManager* /*unused*/) const { + opt::Instruction::OperandList in_operands = { + {SPV_OPERAND_TYPE_LITERAL_INTEGER, {message_.width()}}, + {SPV_OPERAND_TYPE_LITERAL_INTEGER, {message_.is_signed() ? 1u : 0u}}}; + context->module()->AddType(MakeUnique( + context, SpvOpTypeInt, 0, message_.fresh_id(), in_operands)); + fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id()); + // We have added an instruction to the module, so need to be careful about the + // validity of existing analyses. + context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone); +} + +protobufs::Transformation TransformationAddTypeInt::ToMessage() const { + protobufs::Transformation result; + *result.mutable_add_type_int() = message_; + return result; +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/transformation_add_type_int.h b/third_party/spirv-tools/source/fuzz/transformation_add_type_int.h new file mode 100644 index 0000000000..86342d06dd --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_add_type_int.h @@ -0,0 +1,52 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_INT_H_ +#define SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_INT_H_ + +#include "source/fuzz/fact_manager.h" +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "source/fuzz/transformation.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace fuzz { + +class TransformationAddTypeInt : public Transformation { + public: + explicit TransformationAddTypeInt( + const protobufs::TransformationAddTypeInt& message); + + TransformationAddTypeInt(uint32_t fresh_id, uint32_t width, bool is_signed); + + // - |message_.fresh_id| must not be used by the module + // - The module must not contain an OpTypeInt instruction with width + // |message_.width| and signedness |message.is_signed| + bool IsApplicable(opt::IRContext* context, + const FactManager& fact_manager) const override; + + // Adds an OpTypeInt instruction to the module with the given width and + // signedness. + void Apply(opt::IRContext* context, FactManager* fact_manager) const override; + + protobufs::Transformation ToMessage() const override; + + private: + protobufs::TransformationAddTypeInt message_; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_INT_H_ diff --git a/third_party/spirv-tools/source/fuzz/transformation_add_type_matrix.cpp b/third_party/spirv-tools/source/fuzz/transformation_add_type_matrix.cpp new file mode 100644 index 0000000000..07ab7054a0 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_add_type_matrix.cpp @@ -0,0 +1,71 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_add_type_matrix.h" + +#include "fuzzer_util.h" + +namespace spvtools { +namespace fuzz { + +TransformationAddTypeMatrix::TransformationAddTypeMatrix( + const spvtools::fuzz::protobufs::TransformationAddTypeMatrix& message) + : message_(message) {} + +TransformationAddTypeMatrix::TransformationAddTypeMatrix( + uint32_t fresh_id, uint32_t column_type_id, uint32_t column_count) { + message_.set_fresh_id(fresh_id); + message_.set_column_type_id(column_type_id); + message_.set_column_count(column_count); +} + +bool TransformationAddTypeMatrix::IsApplicable( + opt::IRContext* context, + const spvtools::fuzz::FactManager& /*unused*/) const { + // The result id must be fresh. + if (!fuzzerutil::IsFreshId(context, message_.fresh_id())) { + return false; + } + // The column type must be a floating-point vector. + auto column_type = + context->get_type_mgr()->GetType(message_.column_type_id()); + if (!column_type) { + return false; + } + return column_type->AsVector() && + column_type->AsVector()->element_type()->AsFloat(); +} + +void TransformationAddTypeMatrix::Apply( + opt::IRContext* context, spvtools::fuzz::FactManager* /*unused*/) const { + opt::Instruction::OperandList in_operands; + in_operands.push_back({SPV_OPERAND_TYPE_ID, {message_.column_type_id()}}); + in_operands.push_back( + {SPV_OPERAND_TYPE_LITERAL_INTEGER, {message_.column_count()}}); + context->module()->AddType(MakeUnique( + context, SpvOpTypeMatrix, 0, message_.fresh_id(), in_operands)); + fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id()); + // We have added an instruction to the module, so need to be careful about the + // validity of existing analyses. + context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone); +} + +protobufs::Transformation TransformationAddTypeMatrix::ToMessage() const { + protobufs::Transformation result; + *result.mutable_add_type_matrix() = message_; + return result; +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/transformation_add_type_matrix.h b/third_party/spirv-tools/source/fuzz/transformation_add_type_matrix.h new file mode 100644 index 0000000000..69d638906c --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_add_type_matrix.h @@ -0,0 +1,53 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_MATRIX_H_ +#define SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_MATRIX_H_ + +#include "source/fuzz/fact_manager.h" +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "source/fuzz/transformation.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace fuzz { + +class TransformationAddTypeMatrix : public Transformation { + public: + explicit TransformationAddTypeMatrix( + const protobufs::TransformationAddTypeMatrix& message); + + TransformationAddTypeMatrix(uint32_t fresh_id, uint32_t column_type_id, + uint32_t column_count); + + // - |message_.fresh_id| must be a fresh id + // - |message_.column_type_id| must be the id of a floating-point vector type + bool IsApplicable(opt::IRContext* context, + const FactManager& fact_manager) const override; + + // Adds an OpTypeMatrix instruction to the module, with column type + // |message_.column_type_id| and |message_.column_count| columns, with result + // id |message_.fresh_id|. + void Apply(opt::IRContext* context, FactManager* fact_manager) const override; + + protobufs::Transformation ToMessage() const override; + + private: + protobufs::TransformationAddTypeMatrix message_; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_MATRIX_H_ diff --git a/third_party/spirv-tools/source/fuzz/transformation_add_type_pointer.cpp b/third_party/spirv-tools/source/fuzz/transformation_add_type_pointer.cpp new file mode 100644 index 0000000000..426985a37e --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_add_type_pointer.cpp @@ -0,0 +1,65 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_add_type_pointer.h" + +#include "source/fuzz/fuzzer_util.h" + +namespace spvtools { +namespace fuzz { + +TransformationAddTypePointer::TransformationAddTypePointer( + const spvtools::fuzz::protobufs::TransformationAddTypePointer& message) + : message_(message) {} + +TransformationAddTypePointer::TransformationAddTypePointer( + uint32_t fresh_id, SpvStorageClass storage_class, uint32_t base_type_id) { + message_.set_fresh_id(fresh_id); + message_.set_storage_class(storage_class); + message_.set_base_type_id(base_type_id); +} + +bool TransformationAddTypePointer::IsApplicable( + opt::IRContext* context, + const spvtools::fuzz::FactManager& /*unused*/) const { + // The id must be fresh. + if (!fuzzerutil::IsFreshId(context, message_.fresh_id())) { + return false; + } + // The base type must be known. + return context->get_type_mgr()->GetType(message_.base_type_id()) != nullptr; +} + +void TransformationAddTypePointer::Apply( + opt::IRContext* context, spvtools::fuzz::FactManager* /*unused*/) const { + // Add the pointer type. + opt::Instruction::OperandList in_operands = { + {SPV_OPERAND_TYPE_STORAGE_CLASS, {message_.storage_class()}}, + {SPV_OPERAND_TYPE_ID, {message_.base_type_id()}}}; + context->module()->AddType(MakeUnique( + context, SpvOpTypePointer, 0, message_.fresh_id(), in_operands)); + fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id()); + // We have added an instruction to the module, so need to be careful about the + // validity of existing analyses. + context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone); +} + +protobufs::Transformation TransformationAddTypePointer::ToMessage() const { + protobufs::Transformation result; + *result.mutable_add_type_pointer() = message_; + return result; +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/transformation_add_type_pointer.h b/third_party/spirv-tools/source/fuzz/transformation_add_type_pointer.h new file mode 100644 index 0000000000..2b9ff77fdb --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_add_type_pointer.h @@ -0,0 +1,53 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_POINTER_H_ +#define SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_POINTER_H_ + +#include "source/fuzz/fact_manager.h" +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "source/fuzz/transformation.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace fuzz { + +class TransformationAddTypePointer : public Transformation { + public: + explicit TransformationAddTypePointer( + const protobufs::TransformationAddTypePointer& message); + + TransformationAddTypePointer(uint32_t fresh_id, SpvStorageClass storage_class, + uint32_t base_type_id); + + // - |message_.fresh_id| must not be used by the module + // - |message_.base_type_id| must be the result id of an OpType[...] + // instruction + bool IsApplicable(opt::IRContext* context, + const FactManager& fact_manager) const override; + + // Adds an OpTypePointer instruction with the given storage class and base + // type to the module. + void Apply(opt::IRContext* context, FactManager* fact_manager) const override; + + protobufs::Transformation ToMessage() const override; + + private: + protobufs::TransformationAddTypePointer message_; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_POINTER_H_ diff --git a/third_party/spirv-tools/source/fuzz/transformation_add_type_struct.cpp b/third_party/spirv-tools/source/fuzz/transformation_add_type_struct.cpp new file mode 100644 index 0000000000..1ae83723dc --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_add_type_struct.cpp @@ -0,0 +1,73 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_add_type_struct.h" + +#include "source/fuzz/fuzzer_util.h" + +namespace spvtools { +namespace fuzz { + +TransformationAddTypeStruct::TransformationAddTypeStruct( + const spvtools::fuzz::protobufs::TransformationAddTypeStruct& message) + : message_(message) {} + +TransformationAddTypeStruct::TransformationAddTypeStruct( + uint32_t fresh_id, const std::vector& member_type_ids) { + message_.set_fresh_id(fresh_id); + for (auto member_type_id : member_type_ids) { + message_.add_member_type_id(member_type_id); + } +} + +bool TransformationAddTypeStruct::IsApplicable( + opt::IRContext* context, + const spvtools::fuzz::FactManager& /*unused*/) const { + // A fresh id is required. + if (!fuzzerutil::IsFreshId(context, message_.fresh_id())) { + return false; + } + for (auto member_type : message_.member_type_id()) { + auto type = context->get_type_mgr()->GetType(member_type); + if (!type || type->AsFunction()) { + // The member type id either does not refer to a type, or refers to a + // function type; both are illegal. + return false; + } + } + return true; +} + +void TransformationAddTypeStruct::Apply( + opt::IRContext* context, spvtools::fuzz::FactManager* /*unused*/) const { + opt::Instruction::OperandList in_operands; + for (auto member_type : message_.member_type_id()) { + in_operands.push_back({SPV_OPERAND_TYPE_ID, {member_type}}); + } + context->module()->AddType(MakeUnique( + context, SpvOpTypeStruct, 0, message_.fresh_id(), in_operands)); + fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id()); + // We have added an instruction to the module, so need to be careful about the + // validity of existing analyses. + context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone); +} + +protobufs::Transformation TransformationAddTypeStruct::ToMessage() const { + protobufs::Transformation result; + *result.mutable_add_type_struct() = message_; + return result; +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/transformation_add_type_struct.h b/third_party/spirv-tools/source/fuzz/transformation_add_type_struct.h new file mode 100644 index 0000000000..edf3ec6eef --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_add_type_struct.h @@ -0,0 +1,54 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_STRUCT_H_ +#define SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_STRUCT_H_ + +#include + +#include "source/fuzz/fact_manager.h" +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "source/fuzz/transformation.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace fuzz { + +class TransformationAddTypeStruct : public Transformation { + public: + explicit TransformationAddTypeStruct( + const protobufs::TransformationAddTypeStruct& message); + + TransformationAddTypeStruct(uint32_t fresh_id, + const std::vector& component_type_ids); + + // - |message_.fresh_id| must be a fresh id + // - |message_.member_type_id| must be a sequence of non-function type ids + bool IsApplicable(opt::IRContext* context, + const FactManager& fact_manager) const override; + + // Adds an OpTypeStruct instruction whose field types are given by + // |message_.member_type_id|, with result id |message_.fresh_id|. + void Apply(opt::IRContext* context, FactManager* fact_manager) const override; + + protobufs::Transformation ToMessage() const override; + + private: + protobufs::TransformationAddTypeStruct message_; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_STRUCT_H_ diff --git a/third_party/spirv-tools/source/fuzz/transformation_add_type_vector.cpp b/third_party/spirv-tools/source/fuzz/transformation_add_type_vector.cpp new file mode 100644 index 0000000000..3fdf50b1c8 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_add_type_vector.cpp @@ -0,0 +1,69 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_add_type_vector.h" + +#include "fuzzer_util.h" + +namespace spvtools { +namespace fuzz { + +TransformationAddTypeVector::TransformationAddTypeVector( + const spvtools::fuzz::protobufs::TransformationAddTypeVector& message) + : message_(message) {} + +TransformationAddTypeVector::TransformationAddTypeVector( + uint32_t fresh_id, uint32_t component_type_id, uint32_t component_count) { + message_.set_fresh_id(fresh_id); + message_.set_component_type_id(component_type_id); + message_.set_component_count(component_count); +} + +bool TransformationAddTypeVector::IsApplicable( + opt::IRContext* context, + const spvtools::fuzz::FactManager& /*unused*/) const { + if (!fuzzerutil::IsFreshId(context, message_.fresh_id())) { + return false; + } + auto component_type = + context->get_type_mgr()->GetType(message_.component_type_id()); + if (!component_type) { + return false; + } + return component_type->AsBool() || component_type->AsFloat() || + component_type->AsInteger(); +} + +void TransformationAddTypeVector::Apply( + opt::IRContext* context, spvtools::fuzz::FactManager* /*unused*/) const { + opt::Instruction::OperandList in_operands; + in_operands.push_back({SPV_OPERAND_TYPE_ID, {message_.component_type_id()}}); + in_operands.push_back( + {SPV_OPERAND_TYPE_LITERAL_INTEGER, {message_.component_count()}}); + context->module()->AddType(MakeUnique( + context, SpvOpTypeVector, 0, message_.fresh_id(), in_operands)); + fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id()); + // We have added an instruction to the module, so need to be careful about the + // validity of existing analyses. + context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone); +} + +protobufs::Transformation TransformationAddTypeVector::ToMessage() const { + protobufs::Transformation result; + *result.mutable_add_type_vector() = message_; + return result; +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/transformation_add_type_vector.h b/third_party/spirv-tools/source/fuzz/transformation_add_type_vector.h new file mode 100644 index 0000000000..af840f5ebe --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_add_type_vector.h @@ -0,0 +1,53 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_VECTOR_H_ +#define SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_VECTOR_H_ + +#include "source/fuzz/fact_manager.h" +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "source/fuzz/transformation.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace fuzz { + +class TransformationAddTypeVector : public Transformation { + public: + explicit TransformationAddTypeVector( + const protobufs::TransformationAddTypeVector& message); + + TransformationAddTypeVector(uint32_t fresh_id, uint32_t component_type_id, + uint32_t component_count); + + // - |message_.fresh_id| must be a fresh id + // - |message_.component_type_id| must be the id of a scalar type + bool IsApplicable(opt::IRContext* context, + const FactManager& fact_manager) const override; + + // Adds an OpTypeVector instruction to the module, with component type + // |message_.component_type_id| and |message_.component_count| components, + // with result id |message_.fresh_id|. + void Apply(opt::IRContext* context, FactManager* fact_manager) const override; + + protobufs::Transformation ToMessage() const override; + + private: + protobufs::TransformationAddTypeVector message_; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_TRANSFORMATION_ADD_TYPE_VECTOR_H_ diff --git a/third_party/spirv-tools/source/fuzz/transformation_composite_construct.cpp b/third_party/spirv-tools/source/fuzz/transformation_composite_construct.cpp new file mode 100644 index 0000000000..7a3aff1458 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_composite_construct.cpp @@ -0,0 +1,305 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_composite_construct.h" + +#include "source/fuzz/data_descriptor.h" +#include "source/fuzz/fuzzer_util.h" +#include "source/fuzz/instruction_descriptor.h" +#include "source/opt/instruction.h" + +namespace spvtools { +namespace fuzz { + +TransformationCompositeConstruct::TransformationCompositeConstruct( + const protobufs::TransformationCompositeConstruct& message) + : message_(message) {} + +TransformationCompositeConstruct::TransformationCompositeConstruct( + uint32_t composite_type_id, std::vector component, + const protobufs::InstructionDescriptor& instruction_to_insert_before, + uint32_t fresh_id) { + message_.set_composite_type_id(composite_type_id); + for (auto a_component : component) { + message_.add_component(a_component); + } + *message_.mutable_instruction_to_insert_before() = + instruction_to_insert_before; + message_.set_fresh_id(fresh_id); +} + +bool TransformationCompositeConstruct::IsApplicable( + opt::IRContext* context, const FactManager& /*fact_manager*/) const { + if (!fuzzerutil::IsFreshId(context, message_.fresh_id())) { + // We require the id for the composite constructor to be unused. + return false; + } + + auto insert_before = + FindInstruction(message_.instruction_to_insert_before(), context); + if (!insert_before) { + // The instruction before which the composite should be inserted was not + // found. + return false; + } + + auto composite_type = + context->get_type_mgr()->GetType(message_.composite_type_id()); + + if (!fuzzerutil::IsCompositeType(composite_type)) { + // The type must actually be a composite. + return false; + } + + // If the type is an array, matrix, struct or vector, the components need to + // be suitable for constructing something of that type. + if (composite_type->AsArray() && !ComponentsForArrayConstructionAreOK( + context, *composite_type->AsArray())) { + return false; + } + if (composite_type->AsMatrix() && !ComponentsForMatrixConstructionAreOK( + context, *composite_type->AsMatrix())) { + return false; + } + if (composite_type->AsStruct() && !ComponentsForStructConstructionAreOK( + context, *composite_type->AsStruct())) { + return false; + } + if (composite_type->AsVector() && !ComponentsForVectorConstructionAreOK( + context, *composite_type->AsVector())) { + return false; + } + + // Now check whether every component being used to initialize the composite is + // available at the desired program point. + for (auto& component : message_.component()) { + auto component_inst = context->get_def_use_mgr()->GetDef(component); + if (!context->get_instr_block(component)) { + // The component does not have a block; that means it is in global scope, + // which is OK. (Whether the component actually corresponds to an + // instruction is checked above when determining whether types are + // suitable.) + continue; + } + // Check whether the component is available. + if (insert_before->HasResultId() && + insert_before->result_id() == component) { + // This constitutes trying to use an id right before it is defined. The + // special case is needed due to an instruction always dominating itself. + return false; + } + if (!context + ->GetDominatorAnalysis( + context->get_instr_block(&*insert_before)->GetParent()) + ->Dominates(component_inst, &*insert_before)) { + // The instruction defining the component must dominate the instruction we + // wish to insert the composite before. + return false; + } + } + + return true; +} + +void TransformationCompositeConstruct::Apply(opt::IRContext* context, + FactManager* fact_manager) const { + // Use the base and offset information from the transformation to determine + // where in the module a new instruction should be inserted. + auto insert_before_inst = + FindInstruction(message_.instruction_to_insert_before(), context); + auto destination_block = context->get_instr_block(insert_before_inst); + auto insert_before = fuzzerutil::GetIteratorForInstruction( + destination_block, insert_before_inst); + + // Prepare the input operands for an OpCompositeConstruct instruction. + opt::Instruction::OperandList in_operands; + for (auto& component_id : message_.component()) { + in_operands.push_back({SPV_OPERAND_TYPE_ID, {component_id}}); + } + + // Insert an OpCompositeConstruct instruction. + insert_before.InsertBefore(MakeUnique( + context, SpvOpCompositeConstruct, message_.composite_type_id(), + message_.fresh_id(), in_operands)); + + fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id()); + context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone); + + // Inform the fact manager that we now have new synonyms: every component of + // the composite is synonymous with the id used to construct that component, + // except in the case of a vector where a single vector id can span multiple + // components. + auto composite_type = + context->get_type_mgr()->GetType(message_.composite_type_id()); + uint32_t index = 0; + for (auto component : message_.component()) { + auto component_type = context->get_type_mgr()->GetType( + context->get_def_use_mgr()->GetDef(component)->type_id()); + if (composite_type->AsVector() && component_type->AsVector()) { + // The case where the composite being constructed is a vector and the + // component provided for construction is also a vector is special. It + // requires adding a synonym fact relating each element of the sub-vector + // to the corresponding element of the composite being constructed. + assert(component_type->AsVector()->element_type() == + composite_type->AsVector()->element_type()); + assert(component_type->AsVector()->element_count() < + composite_type->AsVector()->element_count()); + for (uint32_t subvector_index = 0; + subvector_index < component_type->AsVector()->element_count(); + subvector_index++) { + fact_manager->AddFactDataSynonym( + MakeDataDescriptor(component, {subvector_index}), + MakeDataDescriptor(message_.fresh_id(), {index}), context); + index++; + } + } else { + // The other cases are simple: the component is made directly synonymous + // with the element of the composite being constructed. + fact_manager->AddFactDataSynonym( + MakeDataDescriptor(component, {}), + MakeDataDescriptor(message_.fresh_id(), {index}), context); + index++; + } + } +} + +bool TransformationCompositeConstruct::ComponentsForArrayConstructionAreOK( + opt::IRContext* context, const opt::analysis::Array& array_type) const { + if (array_type.length_info().words[0] != + opt::analysis::Array::LengthInfo::kConstant) { + // We only handle constant-sized arrays. + return false; + } + if (array_type.length_info().words.size() != 2) { + // We only handle the case where the array size can be captured in a single + // word. + return false; + } + // Get the array size. + auto array_size = array_type.length_info().words[1]; + if (static_cast(message_.component().size()) != array_size) { + // The number of components must match the array size. + return false; + } + // Check that each component is the result id of an instruction whose type is + // the array's element type. + for (auto component_id : message_.component()) { + auto inst = context->get_def_use_mgr()->GetDef(component_id); + if (inst == nullptr || !inst->type_id()) { + // The component does not correspond to an instruction with a result + // type. + return false; + } + auto component_type = context->get_type_mgr()->GetType(inst->type_id()); + assert(component_type); + if (component_type != array_type.element_type()) { + // The component's type does not match the array's element type. + return false; + } + } + return true; +} + +bool TransformationCompositeConstruct::ComponentsForMatrixConstructionAreOK( + opt::IRContext* context, const opt::analysis::Matrix& matrix_type) const { + if (static_cast(message_.component().size()) != + matrix_type.element_count()) { + // The number of components must match the number of columns of the matrix. + return false; + } + // Check that each component is the result id of an instruction whose type is + // the matrix's column type. + for (auto component_id : message_.component()) { + auto inst = context->get_def_use_mgr()->GetDef(component_id); + if (inst == nullptr || !inst->type_id()) { + // The component does not correspond to an instruction with a result + // type. + return false; + } + auto component_type = context->get_type_mgr()->GetType(inst->type_id()); + assert(component_type); + if (component_type != matrix_type.element_type()) { + // The component's type does not match the matrix's column type. + return false; + } + } + return true; +} + +bool TransformationCompositeConstruct::ComponentsForStructConstructionAreOK( + opt::IRContext* context, const opt::analysis::Struct& struct_type) const { + if (static_cast(message_.component().size()) != + struct_type.element_types().size()) { + // The number of components must match the number of fields of the struct. + return false; + } + // Check that each component is the result id of an instruction those type + // matches the associated field type. + for (uint32_t field_index = 0; + field_index < struct_type.element_types().size(); field_index++) { + auto inst = + context->get_def_use_mgr()->GetDef(message_.component()[field_index]); + if (inst == nullptr || !inst->type_id()) { + // The component does not correspond to an instruction with a result + // type. + return false; + } + auto component_type = context->get_type_mgr()->GetType(inst->type_id()); + assert(component_type); + if (component_type != struct_type.element_types()[field_index]) { + // The component's type does not match the corresponding field type. + return false; + } + } + return true; +} + +bool TransformationCompositeConstruct::ComponentsForVectorConstructionAreOK( + opt::IRContext* context, const opt::analysis::Vector& vector_type) const { + uint32_t base_element_count = 0; + auto element_type = vector_type.element_type(); + for (auto& component_id : message_.component()) { + auto inst = context->get_def_use_mgr()->GetDef(component_id); + if (inst == nullptr || !inst->type_id()) { + // The component does not correspond to an instruction with a result + // type. + return false; + } + auto component_type = context->get_type_mgr()->GetType(inst->type_id()); + assert(component_type); + if (component_type == element_type) { + base_element_count++; + } else if (component_type->AsVector() && + component_type->AsVector()->element_type() == element_type) { + base_element_count += component_type->AsVector()->element_count(); + } else { + // The component was not appropriate; e.g. no type corresponding to the + // given id was found, or the type that was found was not compatible + // with the vector being constructed. + return false; + } + } + // The number of components provided (when vector components are flattened + // out) needs to match the length of the vector being constructed. + return base_element_count == vector_type.element_count(); +} + +protobufs::Transformation TransformationCompositeConstruct::ToMessage() const { + protobufs::Transformation result; + *result.mutable_composite_construct() = message_; + return result; +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/transformation_composite_construct.h b/third_party/spirv-tools/source/fuzz/transformation_composite_construct.h new file mode 100644 index 0000000000..5369c4c899 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_composite_construct.h @@ -0,0 +1,88 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_TRANSFORMATION_COMPOSITE_CONSTRUCT_H_ +#define SOURCE_FUZZ_TRANSFORMATION_COMPOSITE_CONSTRUCT_H_ + +#include "source/fuzz/fact_manager.h" +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "source/fuzz/transformation.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace fuzz { + +class TransformationCompositeConstruct : public Transformation { + public: + explicit TransformationCompositeConstruct( + const protobufs::TransformationCompositeConstruct& message); + + TransformationCompositeConstruct( + uint32_t composite_type_id, std::vector component, + const protobufs::InstructionDescriptor& instruction_to_insert_before, + uint32_t fresh_id); + + // - |message_.fresh_id| must not be used by the module. + // - |message_.composite_type_id| must be the id of a composite type + // - The elements of |message_.component| must be result ids that are + // suitable for constructing an element of the given composite type, in + // order + // - The elements of |message_.component| must not be the target of any + // decorations. + // - |message_.base_instruction_id| must be the result id of an instruction + // 'base' in some block 'blk'. + // - 'blk' must contain an instruction 'inst' located |message_.offset| + // instructions after 'base' (if |message_.offset| = 0 then 'inst' = + // 'base'). + // - It must be legal to insert an OpCompositeConstruct instruction directly + // before 'inst'. + // - Each element of |message_.component| must be available directly before + // 'inst'. + bool IsApplicable(opt::IRContext* context, + const FactManager& fact_manager) const override; + + // Inserts a new OpCompositeConstruct instruction, with id + // |message_.fresh_id|, directly before the instruction identified by + // |message_.base_instruction_id| and |message_.offset|. The instruction + // creates a composite of type |message_.composite_type_id| using the ids of + // |message_.component|. + void Apply(opt::IRContext* context, FactManager* fact_manager) const override; + + protobufs::Transformation ToMessage() const override; + + private: + // Helper to decide whether the components of the transformation are suitable + // for constructing an array of the given type. + bool ComponentsForArrayConstructionAreOK( + opt::IRContext* context, const opt::analysis::Array& array_type) const; + + // Similar, but for matrices. + bool ComponentsForMatrixConstructionAreOK( + opt::IRContext* context, const opt::analysis::Matrix& matrix_type) const; + + // Similar, but for structs. + bool ComponentsForStructConstructionAreOK( + opt::IRContext* context, const opt::analysis::Struct& struct_type) const; + + // Similar, but for vectors. + bool ComponentsForVectorConstructionAreOK( + opt::IRContext* context, const opt::analysis::Vector& vector_type) const; + + protobufs::TransformationCompositeConstruct message_; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_TRANSFORMATION_COMPOSITE_CONSTRUCT_H_ diff --git a/third_party/spirv-tools/source/fuzz/transformation_composite_extract.cpp b/third_party/spirv-tools/source/fuzz/transformation_composite_extract.cpp new file mode 100644 index 0000000000..5d3a386e28 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_composite_extract.cpp @@ -0,0 +1,125 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_composite_extract.h" + +#include + +#include "source/fuzz/data_descriptor.h" +#include "source/fuzz/fuzzer_util.h" +#include "source/fuzz/instruction_descriptor.h" + +namespace spvtools { +namespace fuzz { + +TransformationCompositeExtract::TransformationCompositeExtract( + const spvtools::fuzz::protobufs::TransformationCompositeExtract& message) + : message_(message) {} + +TransformationCompositeExtract::TransformationCompositeExtract( + const protobufs::InstructionDescriptor& instruction_to_insert_before, + uint32_t fresh_id, uint32_t composite_id, std::vector&& index) { + *message_.mutable_instruction_to_insert_before() = + instruction_to_insert_before; + message_.set_fresh_id(fresh_id); + message_.set_composite_id(composite_id); + for (auto an_index : index) { + message_.add_index(an_index); + } +} + +bool TransformationCompositeExtract::IsApplicable( + opt::IRContext* context, + const spvtools::fuzz::FactManager& /*unused*/) const { + if (!fuzzerutil::IsFreshId(context, message_.fresh_id())) { + return false; + } + auto instruction_to_insert_before = + FindInstruction(message_.instruction_to_insert_before(), context); + if (!instruction_to_insert_before) { + return false; + } + auto composite_instruction = + context->get_def_use_mgr()->GetDef(message_.composite_id()); + if (!composite_instruction) { + return false; + } + if (auto block = context->get_instr_block(composite_instruction)) { + if (composite_instruction == instruction_to_insert_before || + !context->GetDominatorAnalysis(block->GetParent()) + ->Dominates(composite_instruction, instruction_to_insert_before)) { + return false; + } + } + assert(composite_instruction->type_id() && + "An instruction in a block cannot have a result id but no type id."); + + auto composite_type = + context->get_type_mgr()->GetType(composite_instruction->type_id()); + if (!composite_type) { + return false; + } + + if (!fuzzerutil::CanInsertOpcodeBeforeInstruction( + SpvOpCompositeExtract, instruction_to_insert_before)) { + return false; + } + + return fuzzerutil::WalkCompositeTypeIndices( + context, composite_instruction->type_id(), message_.index()) != 0; +} + +void TransformationCompositeExtract::Apply( + opt::IRContext* context, spvtools::fuzz::FactManager* fact_manager) const { + opt::Instruction::OperandList extract_operands; + extract_operands.push_back({SPV_OPERAND_TYPE_ID, {message_.composite_id()}}); + for (auto an_index : message_.index()) { + extract_operands.push_back({SPV_OPERAND_TYPE_LITERAL_INTEGER, {an_index}}); + } + auto composite_instruction = + context->get_def_use_mgr()->GetDef(message_.composite_id()); + auto extracted_type = fuzzerutil::WalkCompositeTypeIndices( + context, composite_instruction->type_id(), message_.index()); + + FindInstruction(message_.instruction_to_insert_before(), context) + ->InsertBefore(MakeUnique( + context, SpvOpCompositeExtract, extracted_type, message_.fresh_id(), + extract_operands)); + + fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id()); + + context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone); + + // Add the fact that the id storing the extracted element is synonymous with + // the index into the structure. + std::vector indices; + for (auto an_index : message_.index()) { + indices.push_back(an_index); + } + protobufs::DataDescriptor data_descriptor_for_extracted_element = + MakeDataDescriptor(message_.composite_id(), std::move(indices)); + protobufs::DataDescriptor data_descriptor_for_result_id = + MakeDataDescriptor(message_.fresh_id(), {}); + fact_manager->AddFactDataSynonym(data_descriptor_for_extracted_element, + data_descriptor_for_result_id, context); +} + +protobufs::Transformation TransformationCompositeExtract::ToMessage() const { + protobufs::Transformation result; + *result.mutable_composite_extract() = message_; + return result; +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/transformation_composite_extract.h b/third_party/spirv-tools/source/fuzz/transformation_composite_extract.h new file mode 100644 index 0000000000..c4c9278ccd --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_composite_extract.h @@ -0,0 +1,63 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_TRANSFORMATION_COMPOSITE_EXTRACT_H_ +#define SOURCE_FUZZ_TRANSFORMATION_COMPOSITE_EXTRACT_H_ + +#include "source/fuzz/fact_manager.h" +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "source/fuzz/transformation.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace fuzz { + +class TransformationCompositeExtract : public Transformation { + public: + explicit TransformationCompositeExtract( + const protobufs::TransformationCompositeExtract& message); + + TransformationCompositeExtract( + const protobufs::InstructionDescriptor& instruction_to_insert_before, + uint32_t fresh_id, uint32_t composite_id, std::vector&& index); + + // - |message_.fresh_id| must be available + // - |message_.instruction_to_insert_before| must identify an instruction + // before which it is valid to place an OpCompositeExtract + // - |message_.composite_id| must be the id of an instruction that defines + // a composite object, and this id must be available at the instruction + // identified by |message_.instruction_to_insert_before| + // - |message_.index| must be a suitable set of indices for + // |message_.composite_id|, i.e. it must be possible to follow this chain + // of indices to reach a sub-object of |message_.composite_id| + bool IsApplicable(opt::IRContext* context, + const FactManager& fact_manager) const override; + + // Adds an OpCompositeConstruct instruction before the instruction identified + // by |message_.instruction_to_insert_before|, that extracts from + // |message_.composite_id| via indices |message_.index| into + // |message_.fresh_id|. Generates a data synonym fact relating + // |message_.fresh_id| to the extracted element. + void Apply(opt::IRContext* context, FactManager* fact_manager) const override; + + protobufs::Transformation ToMessage() const override; + + private: + protobufs::TransformationCompositeExtract message_; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_TRANSFORMATION_COMPOSITE_EXTRACT_H_ diff --git a/third_party/spirv-tools/source/fuzz/transformation_copy_object.cpp b/third_party/spirv-tools/source/fuzz/transformation_copy_object.cpp new file mode 100644 index 0000000000..af1e81c37e --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_copy_object.cpp @@ -0,0 +1,117 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_copy_object.h" + +#include "source/fuzz/data_descriptor.h" +#include "source/fuzz/fuzzer_util.h" +#include "source/fuzz/instruction_descriptor.h" +#include "source/opt/instruction.h" +#include "source/util/make_unique.h" + +namespace spvtools { +namespace fuzz { + +TransformationCopyObject::TransformationCopyObject( + const protobufs::TransformationCopyObject& message) + : message_(message) {} + +TransformationCopyObject::TransformationCopyObject( + uint32_t object, + const protobufs::InstructionDescriptor& instruction_to_insert_before, + uint32_t fresh_id) { + message_.set_object(object); + *message_.mutable_instruction_to_insert_before() = + instruction_to_insert_before; + message_.set_fresh_id(fresh_id); +} + +bool TransformationCopyObject::IsApplicable( + opt::IRContext* context, const FactManager& /*fact_manager*/) const { + if (!fuzzerutil::IsFreshId(context, message_.fresh_id())) { + // We require the id for the object copy to be unused. + return false; + } + // The id of the object to be copied must exist + auto object_inst = context->get_def_use_mgr()->GetDef(message_.object()); + if (!object_inst) { + return false; + } + if (!fuzzerutil::CanMakeSynonymOf(context, object_inst)) { + return false; + } + + auto insert_before = + FindInstruction(message_.instruction_to_insert_before(), context); + if (!insert_before) { + // The instruction before which the copy should be inserted was not found. + return false; + } + + if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpCopyObject, + insert_before)) { + return false; + } + + // |message_object| must be available at the point where we want to add the + // copy. It is available if it is at global scope (in which case it has no + // block), or if it dominates the point of insertion but is different from the + // point of insertion. + // + // The reason why the object needs to be different from the insertion point is + // that the copy will be added *before* this point, and we do not want to + // insert it before the object's defining instruction. + return !context->get_instr_block(object_inst) || + (object_inst != &*insert_before && + context + ->GetDominatorAnalysis( + context->get_instr_block(insert_before)->GetParent()) + ->Dominates(object_inst, &*insert_before)); +} + +void TransformationCopyObject::Apply(opt::IRContext* context, + FactManager* fact_manager) const { + auto object_inst = context->get_def_use_mgr()->GetDef(message_.object()); + assert(object_inst && "The object to be copied must exist."); + auto insert_before_inst = + FindInstruction(message_.instruction_to_insert_before(), context); + auto destination_block = context->get_instr_block(insert_before_inst); + assert(destination_block && "The base instruction must be in a block."); + auto insert_before = fuzzerutil::GetIteratorForInstruction( + destination_block, insert_before_inst); + assert(insert_before != destination_block->end() && + "There must be an instruction before which the copy can be inserted."); + + opt::Instruction::OperandList operands = { + {SPV_OPERAND_TYPE_ID, {message_.object()}}}; + insert_before->InsertBefore(MakeUnique( + context, SpvOp::SpvOpCopyObject, object_inst->type_id(), + message_.fresh_id(), operands)); + + fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id()); + context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone); + + fact_manager->AddFactDataSynonym(MakeDataDescriptor(message_.object(), {}), + MakeDataDescriptor(message_.fresh_id(), {}), + context); +} + +protobufs::Transformation TransformationCopyObject::ToMessage() const { + protobufs::Transformation result; + *result.mutable_copy_object() = message_; + return result; +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/transformation_copy_object.h b/third_party/spirv-tools/source/fuzz/transformation_copy_object.h new file mode 100644 index 0000000000..ac5e978df6 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_copy_object.h @@ -0,0 +1,72 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_TRANSFORMATION_COPY_OBJECT_H_ +#define SOURCE_FUZZ_TRANSFORMATION_COPY_OBJECT_H_ + +#include "source/fuzz/fact_manager.h" +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "source/fuzz/transformation.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace fuzz { + +class TransformationCopyObject : public Transformation { + public: + explicit TransformationCopyObject( + const protobufs::TransformationCopyObject& message); + + TransformationCopyObject( + uint32_t object, + const protobufs::InstructionDescriptor& instruction_to_insert_before, + uint32_t fresh_id); + + // - |message_.fresh_id| must not be used by the module. + // - |message_.object| must be a result id that is a legitimate operand for + // OpCopyObject. In particular, it must be the id of an instruction that + // has a result type + // - |message_.object| must not be the target of any decoration. + // TODO(afd): consider copying decorations along with objects. + // - |message_.base_instruction_id| must be the result id of an instruction + // 'base' in some block 'blk'. + // - 'blk' must contain an instruction 'inst' located |message_.offset| + // instructions after 'base' (if |message_.offset| = 0 then 'inst' = + // 'base'). + // - It must be legal to insert an OpCopyObject instruction directly + // before 'inst'. + // - |message_.object| must be available directly before 'inst'. + // - |message_.object| must not be a null pointer or undefined pointer (so as + // to make it legal to load from copied pointers). + bool IsApplicable(opt::IRContext* context, + const FactManager& fact_manager) const override; + + // - A new instruction, + // %|message_.fresh_id| = OpCopyObject %ty %|message_.object| + // is added directly before the instruction at |message_.insert_after_id| + + // |message_|.offset, where %ty is the type of |message_.object|. + // - The fact that |message_.fresh_id| and |message_.object| are synonyms + // is added to the fact manager. + void Apply(opt::IRContext* context, FactManager* fact_manager) const override; + + protobufs::Transformation ToMessage() const override; + + private: + protobufs::TransformationCopyObject message_; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_TRANSFORMATION_COPY_OBJECT_H_ diff --git a/third_party/spirv-tools/source/fuzz/transformation_merge_blocks.cpp b/third_party/spirv-tools/source/fuzz/transformation_merge_blocks.cpp new file mode 100644 index 0000000000..316e80df3f --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_merge_blocks.cpp @@ -0,0 +1,81 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_merge_blocks.h" + +#include "source/fuzz/fuzzer_util.h" +#include "source/opt/block_merge_util.h" + +namespace spvtools { +namespace fuzz { + +TransformationMergeBlocks::TransformationMergeBlocks( + const spvtools::fuzz::protobufs::TransformationMergeBlocks& message) + : message_(message) {} + +TransformationMergeBlocks::TransformationMergeBlocks(uint32_t block_id) { + message_.set_block_id(block_id); +} + +bool TransformationMergeBlocks::IsApplicable( + opt::IRContext* context, + const spvtools::fuzz::FactManager& /*unused*/) const { + auto second_block = fuzzerutil::MaybeFindBlock(context, message_.block_id()); + // The given block must exist. + if (!second_block) { + return false; + } + // The block must have just one predecessor. + auto predecessors = context->cfg()->preds(second_block->id()); + if (predecessors.size() != 1) { + return false; + } + auto first_block = context->cfg()->block(predecessors.at(0)); + + return opt::blockmergeutil::CanMergeWithSuccessor(context, first_block); +} + +void TransformationMergeBlocks::Apply( + opt::IRContext* context, spvtools::fuzz::FactManager* /*unused*/) const { + auto second_block = fuzzerutil::MaybeFindBlock(context, message_.block_id()); + auto first_block = + context->cfg()->block(context->cfg()->preds(second_block->id()).at(0)); + + auto function = first_block->GetParent(); + // We need an iterator pointing to the predecessor, hence the loop. + for (auto bi = function->begin(); bi != function->end(); ++bi) { + if (bi->id() == first_block->id()) { + assert(opt::blockmergeutil::CanMergeWithSuccessor(context, &*bi) && + "Because 'Apply' should only be invoked if 'IsApplicable' holds, " + "it must be possible to merge |bi| with its successor."); + opt::blockmergeutil::MergeWithSuccessor(context, function, bi); + // Invalidate all analyses, since we have changed the module + // significantly. + context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone); + return; + } + } + assert(false && + "Control should not reach here - we should always find the desired " + "block"); +} + +protobufs::Transformation TransformationMergeBlocks::ToMessage() const { + protobufs::Transformation result; + *result.mutable_merge_blocks() = message_; + return result; +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/transformation_merge_blocks.h b/third_party/spirv-tools/source/fuzz/transformation_merge_blocks.h new file mode 100644 index 0000000000..86216db3ba --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_merge_blocks.h @@ -0,0 +1,54 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_TRANSFORMATION_MERGE_BLOCKS_H_ +#define SOURCE_FUZZ_TRANSFORMATION_MERGE_BLOCKS_H_ + +#include "source/fuzz/fact_manager.h" +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "source/fuzz/transformation.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace fuzz { + +class TransformationMergeBlocks : public Transformation { + public: + explicit TransformationMergeBlocks( + const protobufs::TransformationMergeBlocks& message); + + TransformationMergeBlocks(uint32_t block_id); + + // - |message_.block_id| must be the id of a block, b + // - b must have a single predecessor, a + // - b must be the sole successor of a + // - Replacing a with the merge of a and b (and removing b) must lead to a + // valid module + bool IsApplicable(opt::IRContext* context, + const FactManager& fact_manager) const override; + + // The contents of b are merged into a, and a's terminator is replaced with + // the terminator of b. Block b is removed from the module. + void Apply(opt::IRContext* context, FactManager* fact_manager) const override; + + protobufs::Transformation ToMessage() const override; + + private: + protobufs::TransformationMergeBlocks message_; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_TRANSFORMATION_MERGE_BLOCKS_H_ diff --git a/third_party/spirv-tools/source/fuzz/transformation_move_block_down.cpp b/third_party/spirv-tools/source/fuzz/transformation_move_block_down.cpp new file mode 100644 index 0000000000..f181855fda --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_move_block_down.cpp @@ -0,0 +1,109 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_move_block_down.h" + +#include "source/opt/basic_block.h" + +namespace spvtools { +namespace fuzz { + +TransformationMoveBlockDown::TransformationMoveBlockDown( + const spvtools::fuzz::protobufs::TransformationMoveBlockDown& message) + : message_(message) {} + +TransformationMoveBlockDown::TransformationMoveBlockDown(uint32_t id) { + message_.set_block_id(id); +} + +bool TransformationMoveBlockDown::IsApplicable( + opt::IRContext* context, const FactManager& /*unused*/) const { + // Go through every block in every function, looking for a block whose id + // matches that of the block we want to consider moving down. + for (auto& function : *context->module()) { + for (auto block_it = function.begin(); block_it != function.end(); + ++block_it) { + if (block_it->id() == message_.block_id()) { + // We have found a match. + if (block_it == function.begin()) { + // The block is the first one appearing in the function. We are not + // allowed to move this block down. + return false; + } + // Record the block we would like to consider moving down. + opt::BasicBlock* block_matching_id = &*block_it; + if (!context->GetDominatorAnalysis(&function)->IsReachable( + block_matching_id)) { + // The block is not reachable. We are not allowed to move it down. + return false; + } + // Now see whether there is some block following that block in program + // order. + ++block_it; + if (block_it == function.end()) { + // There is no such block; i.e., the block we are considering moving + // is the last one in the function. The transformation thus does not + // apply. + return false; + } + opt::BasicBlock* next_block_in_program_order = &*block_it; + // We can move the block of interest down if and only if it does not + // dominate the block that comes next. + return !context->GetDominatorAnalysis(&function)->Dominates( + block_matching_id, next_block_in_program_order); + } + } + } + + // We did not find a matching block, so the transformation is not applicable: + // there is no relevant block to move. + return false; +} + +void TransformationMoveBlockDown::Apply(opt::IRContext* context, + FactManager* /*unused*/) const { + // Go through every block in every function, looking for a block whose id + // matches that of the block we want to move down. + for (auto& function : *context->module()) { + for (auto block_it = function.begin(); block_it != function.end(); + ++block_it) { + if (block_it->id() == message_.block_id()) { + ++block_it; + assert(block_it != function.end() && + "To be able to move a block down, it needs to have a " + "program-order successor."); + function.MoveBasicBlockToAfter(message_.block_id(), &*block_it); + // For performance, it is vital to keep the dominator analysis valid + // (which due to https://github.com/KhronosGroup/SPIRV-Tools/issues/2889 + // requires keeping the CFG analysis valid). + context->InvalidateAnalysesExceptFor( + opt::IRContext::Analysis::kAnalysisDefUse | + opt::IRContext::Analysis::kAnalysisCFG | + opt::IRContext::Analysis::kAnalysisDominatorAnalysis); + + return; + } + } + } + assert(false && "No block was found to move down."); +} + +protobufs::Transformation TransformationMoveBlockDown::ToMessage() const { + protobufs::Transformation result; + *result.mutable_move_block_down() = message_; + return result; +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/transformation_move_block_down.h b/third_party/spirv-tools/source/fuzz/transformation_move_block_down.h new file mode 100644 index 0000000000..fd1584a357 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_move_block_down.h @@ -0,0 +1,54 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_TRANSFORMATION_MOVE_BLOCK_DOWN_H_ +#define SOURCE_FUZZ_TRANSFORMATION_MOVE_BLOCK_DOWN_H_ + +#include "source/fuzz/fact_manager.h" +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "source/fuzz/transformation.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace fuzz { + +class TransformationMoveBlockDown : public Transformation { + public: + explicit TransformationMoveBlockDown( + const protobufs::TransformationMoveBlockDown& message); + + explicit TransformationMoveBlockDown(uint32_t id); + + // - |message_.block_id| must be the id of a block b in the given module. + // - b must not be the first nor last block appearing, in program order, + // in a function. + // - b must not dominate the block that follows it in program order. + // - b must be reachable. + bool IsApplicable(opt::IRContext* context, + const FactManager& fact_manager) const override; + + // The block with id |message_.block_id| is moved down; i.e. the program order + // between it and the block that follows it is swapped. + void Apply(opt::IRContext* context, FactManager* fact_manager) const override; + + protobufs::Transformation ToMessage() const override; + + private: + protobufs::TransformationMoveBlockDown message_; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_TRANSFORMATION_MOVE_BLOCK_DOWN_H_ diff --git a/third_party/spirv-tools/source/fuzz/transformation_outline_function.cpp b/third_party/spirv-tools/source/fuzz/transformation_outline_function.cpp new file mode 100644 index 0000000000..7bbac54839 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_outline_function.cpp @@ -0,0 +1,943 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_outline_function.h" + +#include + +#include "source/fuzz/fuzzer_util.h" + +namespace spvtools { +namespace fuzz { + +namespace { + +std::map PairSequenceToMap( + const google::protobuf::RepeatedPtrField& + pair_sequence) { + std::map result; + for (auto& pair : pair_sequence) { + result[pair.first()] = pair.second(); + } + return result; +} + +} // namespace + +TransformationOutlineFunction::TransformationOutlineFunction( + const spvtools::fuzz::protobufs::TransformationOutlineFunction& message) + : message_(message) {} + +TransformationOutlineFunction::TransformationOutlineFunction( + uint32_t entry_block, uint32_t exit_block, + uint32_t new_function_struct_return_type_id, uint32_t new_function_type_id, + uint32_t new_function_id, uint32_t new_function_region_entry_block, + uint32_t new_caller_result_id, uint32_t new_callee_result_id, + std::map&& input_id_to_fresh_id, + std::map&& output_id_to_fresh_id) { + message_.set_entry_block(entry_block); + message_.set_exit_block(exit_block); + message_.set_new_function_struct_return_type_id( + new_function_struct_return_type_id); + message_.set_new_function_type_id(new_function_type_id); + message_.set_new_function_id(new_function_id); + message_.set_new_function_region_entry_block(new_function_region_entry_block); + message_.set_new_caller_result_id(new_caller_result_id); + message_.set_new_callee_result_id(new_callee_result_id); + for (auto& entry : input_id_to_fresh_id) { + protobufs::UInt32Pair pair; + pair.set_first(entry.first); + pair.set_second(entry.second); + *message_.add_input_id_to_fresh_id() = pair; + } + for (auto& entry : output_id_to_fresh_id) { + protobufs::UInt32Pair pair; + pair.set_first(entry.first); + pair.set_second(entry.second); + *message_.add_output_id_to_fresh_id() = pair; + } +} + +bool TransformationOutlineFunction::IsApplicable( + opt::IRContext* context, + const spvtools::fuzz::FactManager& /*unused*/) const { + std::set ids_used_by_this_transformation; + + // The various new ids used by the transformation must be fresh and distinct. + + if (!CheckIdIsFreshAndNotUsedByThisTransformation( + message_.new_function_struct_return_type_id(), context, + &ids_used_by_this_transformation)) { + return false; + } + + if (!CheckIdIsFreshAndNotUsedByThisTransformation( + message_.new_function_type_id(), context, + &ids_used_by_this_transformation)) { + return false; + } + + if (!CheckIdIsFreshAndNotUsedByThisTransformation( + message_.new_function_id(), context, + &ids_used_by_this_transformation)) { + return false; + } + + if (!CheckIdIsFreshAndNotUsedByThisTransformation( + message_.new_function_region_entry_block(), context, + &ids_used_by_this_transformation)) { + return false; + } + + if (!CheckIdIsFreshAndNotUsedByThisTransformation( + message_.new_caller_result_id(), context, + &ids_used_by_this_transformation)) { + return false; + } + + if (!CheckIdIsFreshAndNotUsedByThisTransformation( + message_.new_callee_result_id(), context, + &ids_used_by_this_transformation)) { + return false; + } + + for (auto& pair : message_.input_id_to_fresh_id()) { + if (!CheckIdIsFreshAndNotUsedByThisTransformation( + pair.second(), context, &ids_used_by_this_transformation)) { + return false; + } + } + + for (auto& pair : message_.output_id_to_fresh_id()) { + if (!CheckIdIsFreshAndNotUsedByThisTransformation( + pair.second(), context, &ids_used_by_this_transformation)) { + return false; + } + } + + // The entry and exit block ids must indeed refer to blocks. + for (auto block_id : {message_.entry_block(), message_.exit_block()}) { + auto block_label = context->get_def_use_mgr()->GetDef(block_id); + if (!block_label || block_label->opcode() != SpvOpLabel) { + return false; + } + } + + auto entry_block = context->cfg()->block(message_.entry_block()); + auto exit_block = context->cfg()->block(message_.exit_block()); + + // The entry block cannot start with OpVariable - this would mean that + // outlining would remove a variable from the function containing the region + // being outlined. + if (entry_block->begin()->opcode() == SpvOpVariable) { + return false; + } + + // For simplicity, we do not allow the entry block to be a loop header. + if (entry_block->GetLoopMergeInst()) { + return false; + } + + // For simplicity, we do not allow the exit block to be a merge block or + // continue target. + if (fuzzerutil::IsMergeOrContinue(context, exit_block->id())) { + return false; + } + + // The entry block cannot start with OpPhi. This is to keep the + // transformation logic simple. (Another transformation to split the OpPhis + // from a block could be applied to avoid this scenario.) + if (entry_block->begin()->opcode() == SpvOpPhi) { + return false; + } + + // The block must be in the same function. + if (entry_block->GetParent() != exit_block->GetParent()) { + return false; + } + + // The entry block must dominate the exit block. + auto dominator_analysis = + context->GetDominatorAnalysis(entry_block->GetParent()); + if (!dominator_analysis->Dominates(entry_block, exit_block)) { + return false; + } + + // The exit block must post-dominate the entry block. + auto postdominator_analysis = + context->GetPostDominatorAnalysis(entry_block->GetParent()); + if (!postdominator_analysis->Dominates(exit_block, entry_block)) { + return false; + } + + // Find all the blocks dominated by |message_.entry_block| and post-dominated + // by |message_.exit_block|. + auto region_set = GetRegionBlocks( + context, entry_block = context->cfg()->block(message_.entry_block()), + exit_block = context->cfg()->block(message_.exit_block())); + + // Check whether |region_set| really is a single-entry single-exit region, and + // also check whether structured control flow constructs and their merge + // and continue constructs are either wholly in or wholly out of the region - + // e.g. avoid the situation where the region contains the head of a loop but + // not the loop's continue construct. + // + // This is achieved by going through every block in the function that contains + // the region. + for (auto& block : *entry_block->GetParent()) { + if (&block == exit_block) { + // It is OK (and typically expected) for the exit block of the region to + // have successors outside the region. It is also OK for the exit block + // to head a structured control flow construct - the block containing the + // call to the outlined function will end up heading this construct if + // outlining takes place. + continue; + } + + if (region_set.count(&block) != 0) { + // The block is in the region and is not the region's exit block. Let's + // see whether all of the block's successors are in the region. If they + // are not, the region is not single-entry single-exit. + bool all_successors_in_region = true; + block.WhileEachSuccessorLabel([&all_successors_in_region, context, + ®ion_set](uint32_t successor) -> bool { + if (region_set.count(context->cfg()->block(successor)) == 0) { + all_successors_in_region = false; + return false; + } + return true; + }); + if (!all_successors_in_region) { + return false; + } + } + + if (auto merge = block.GetMergeInst()) { + // The block is a loop or selection header -- the header and its + // associated merge block had better both be in the region or both be + // outside the region. + auto merge_block = context->cfg()->block(merge->GetSingleWordOperand(0)); + if (region_set.count(&block) != region_set.count(merge_block)) { + return false; + } + } + + if (auto loop_merge = block.GetLoopMergeInst()) { + // Similar to the above, but for the continue target of a loop. + auto continue_target = + context->cfg()->block(loop_merge->GetSingleWordOperand(1)); + if (continue_target != exit_block && + region_set.count(&block) != region_set.count(continue_target)) { + return false; + } + } + } + + // For each region input id, i.e. every id defined outside the region but + // used inside the region, ... + std::map input_id_to_fresh_id_map = + PairSequenceToMap(message_.input_id_to_fresh_id()); + for (auto id : GetRegionInputIds(context, region_set, exit_block)) { + // There needs to be a corresponding fresh id to be used as a function + // parameter. + if (input_id_to_fresh_id_map.count(id) == 0) { + return false; + } + // Furthermore, if the input id has pointer type it must be an OpVariable + // or OpFunctionParameter. + auto input_id_inst = context->get_def_use_mgr()->GetDef(id); + if (context->get_def_use_mgr() + ->GetDef(input_id_inst->type_id()) + ->opcode() == SpvOpTypePointer) { + switch (input_id_inst->opcode()) { + case SpvOpFunctionParameter: + case SpvOpVariable: + // These are OK. + break; + default: + // Anything else is not OK. + return false; + } + } + } + + // For each region output id -- i.e. every id defined inside the region but + // used outside the region -- there needs to be a corresponding fresh id that + // can hold the value for this id computed in the outlined function. + std::map output_id_to_fresh_id_map = + PairSequenceToMap(message_.output_id_to_fresh_id()); + for (auto id : GetRegionOutputIds(context, region_set, exit_block)) { + if (output_id_to_fresh_id_map.count(id) == 0) { + return false; + } + } + + return true; +} + +void TransformationOutlineFunction::Apply( + opt::IRContext* context, spvtools::fuzz::FactManager* fact_manager) const { + // The entry block for the region before outlining. + auto original_region_entry_block = + context->cfg()->block(message_.entry_block()); + + // The exit block for the region before outlining. + auto original_region_exit_block = + context->cfg()->block(message_.exit_block()); + + // The single-entry single-exit region defined by |message_.entry_block| and + // |message_.exit_block|. + std::set region_blocks = GetRegionBlocks( + context, original_region_entry_block, original_region_exit_block); + + // Input and output ids for the region being outlined. + std::vector region_input_ids = + GetRegionInputIds(context, region_blocks, original_region_exit_block); + std::vector region_output_ids = + GetRegionOutputIds(context, region_blocks, original_region_exit_block); + + // Maps from input and output ids to fresh ids. + std::map input_id_to_fresh_id_map = + PairSequenceToMap(message_.input_id_to_fresh_id()); + std::map output_id_to_fresh_id_map = + PairSequenceToMap(message_.output_id_to_fresh_id()); + + UpdateModuleIdBoundForFreshIds(context, input_id_to_fresh_id_map, + output_id_to_fresh_id_map); + + // Construct a map that associates each output id with its type id. + std::map output_id_to_type_id; + for (uint32_t output_id : region_output_ids) { + output_id_to_type_id[output_id] = + context->get_def_use_mgr()->GetDef(output_id)->type_id(); + } + + // The region will be collapsed to a single block that calls a function + // containing the outlined region. This block needs to end with whatever + // the exit block of the region ended with before outlining. We thus clone + // the terminator of the region's exit block, and the merge instruction for + // the block if there is one, so that we can append them to the end of the + // collapsed block later. + std::unique_ptr cloned_exit_block_terminator = + std::unique_ptr( + original_region_exit_block->terminator()->Clone(context)); + std::unique_ptr cloned_exit_block_merge = + original_region_exit_block->GetMergeInst() + ? std::unique_ptr( + original_region_exit_block->GetMergeInst()->Clone(context)) + : nullptr; + + // Make a function prototype for the outlined function, which involves + // figuring out its required type. + std::unique_ptr outlined_function = + PrepareFunctionPrototype(region_input_ids, region_output_ids, + input_id_to_fresh_id_map, context, fact_manager); + + // If the original function was livesafe, the new function should also be + // livesafe. + if (fact_manager->FunctionIsLivesafe( + original_region_entry_block->GetParent()->result_id())) { + fact_manager->AddFactFunctionIsLivesafe(message_.new_function_id()); + } + + // Adapt the region to be outlined so that its input ids are replaced with the + // ids of the outlined function's input parameters, and so that output ids + // are similarly remapped. + RemapInputAndOutputIdsInRegion( + context, *original_region_exit_block, region_blocks, region_input_ids, + region_output_ids, input_id_to_fresh_id_map, output_id_to_fresh_id_map); + + // Fill out the body of the outlined function according to the region that is + // being outlined. + PopulateOutlinedFunction(*original_region_entry_block, + *original_region_exit_block, region_blocks, + region_output_ids, output_id_to_fresh_id_map, + context, outlined_function.get(), fact_manager); + + // Collapse the region that has been outlined into a function down to a single + // block that calls said function. + ShrinkOriginalRegion( + context, region_blocks, region_input_ids, region_output_ids, + output_id_to_type_id, outlined_function->type_id(), + std::move(cloned_exit_block_merge), + std::move(cloned_exit_block_terminator), original_region_entry_block); + + // Add the outlined function to the module. + context->module()->AddFunction(std::move(outlined_function)); + + // Major surgery has been conducted on the module, so invalidate all analyses. + context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone); +} + +protobufs::Transformation TransformationOutlineFunction::ToMessage() const { + protobufs::Transformation result; + *result.mutable_outline_function() = message_; + return result; +} + +std::vector TransformationOutlineFunction::GetRegionInputIds( + opt::IRContext* context, const std::set& region_set, + opt::BasicBlock* region_exit_block) { + std::vector result; + + auto enclosing_function = region_exit_block->GetParent(); + + // Consider each parameter of the function containing the region. + enclosing_function->ForEachParam([context, ®ion_set, &result]( + opt::Instruction* function_parameter) { + // Consider every use of the parameter. + context->get_def_use_mgr()->WhileEachUse( + function_parameter, [context, function_parameter, ®ion_set, &result]( + opt::Instruction* use, uint32_t /*unused*/) { + // Get the block, if any, in which the parameter is used. + auto use_block = context->get_instr_block(use); + // If the use is in a block that lies within the region, the + // parameter is an input id for the region. + if (use_block && region_set.count(use_block) != 0) { + result.push_back(function_parameter->result_id()); + return false; + } + return true; + }); + }); + + // Consider all definitions in the function that might turn out to be input + // ids. + for (auto& block : *enclosing_function) { + std::vector candidate_input_ids_for_block; + if (region_set.count(&block) == 0) { + // All instructions in blocks outside the region are candidate's for + // generating input ids. + for (auto& inst : block) { + candidate_input_ids_for_block.push_back(&inst); + } + } else { + // Blocks in the region cannot generate input ids. + continue; + } + + // Consider each candidate input id to check whether it is used in the + // region. + for (auto& inst : candidate_input_ids_for_block) { + context->get_def_use_mgr()->WhileEachUse( + inst, + [context, &inst, region_exit_block, ®ion_set, &result]( + opt::Instruction* use, uint32_t /*unused*/) -> bool { + + // Find the block in which this id use occurs, recording the id as + // an input id if the block is outside the region, with some + // exceptions detailed below. + auto use_block = context->get_instr_block(use); + + if (!use_block) { + // There might be no containing block, e.g. if the use is in a + // decoration. + return true; + } + + if (region_set.count(use_block) == 0) { + // The use is not in the region: this does not make it an input + // id. + return true; + } + + if (use_block == region_exit_block && use->IsBlockTerminator()) { + // We do not regard uses in the exit block terminator as input + // ids, as this terminator does not get outlined. + return true; + } + + result.push_back(inst->result_id()); + return false; + }); + } + } + return result; +} + +std::vector TransformationOutlineFunction::GetRegionOutputIds( + opt::IRContext* context, const std::set& region_set, + opt::BasicBlock* region_exit_block) { + std::vector result; + + // Consider each block in the function containing the region. + for (auto& block : *region_exit_block->GetParent()) { + if (region_set.count(&block) == 0) { + // Skip blocks that are not in the region. + continue; + } + // Consider each use of each instruction defined in the block. + for (auto& inst : block) { + context->get_def_use_mgr()->WhileEachUse( + &inst, + [®ion_set, context, &inst, region_exit_block, &result]( + opt::Instruction* use, uint32_t /*unused*/) -> bool { + + // Find the block in which this id use occurs, recording the id as + // an output id if the block is outside the region, with some + // exceptions detailed below. + auto use_block = context->get_instr_block(use); + + if (!use_block) { + // There might be no containing block, e.g. if the use is in a + // decoration. + return true; + } + + if (region_set.count(use_block) != 0) { + // The use is in the region. + if (use_block != region_exit_block || !use->IsBlockTerminator()) { + // Furthermore, the use is not in the terminator of the region's + // exit block. + return true; + } + } + + result.push_back(inst.result_id()); + return false; + }); + } + } + return result; +} + +std::set TransformationOutlineFunction::GetRegionBlocks( + opt::IRContext* context, opt::BasicBlock* entry_block, + opt::BasicBlock* exit_block) { + auto enclosing_function = entry_block->GetParent(); + auto dominator_analysis = context->GetDominatorAnalysis(enclosing_function); + auto postdominator_analysis = + context->GetPostDominatorAnalysis(enclosing_function); + + std::set result; + for (auto& block : *enclosing_function) { + if (dominator_analysis->Dominates(entry_block, &block) && + postdominator_analysis->Dominates(exit_block, &block)) { + result.insert(&block); + } + } + return result; +} + +std::unique_ptr +TransformationOutlineFunction::PrepareFunctionPrototype( + const std::vector& region_input_ids, + const std::vector& region_output_ids, + const std::map& input_id_to_fresh_id_map, + opt::IRContext* context, FactManager* fact_manager) const { + uint32_t return_type_id = 0; + uint32_t function_type_id = 0; + + // First, try to find an existing function type that is suitable. This is + // only possible if the region generates no output ids; if it generates output + // ids we are going to make a new struct for those, and since that struct does + // not exist there cannot already be a function type with this struct as its + // return type. + if (region_output_ids.empty()) { + std::vector return_and_parameter_types; + opt::analysis::Void void_type; + return_type_id = context->get_type_mgr()->GetId(&void_type); + return_and_parameter_types.push_back(return_type_id); + for (auto id : region_input_ids) { + return_and_parameter_types.push_back( + context->get_def_use_mgr()->GetDef(id)->type_id()); + } + function_type_id = + fuzzerutil::FindFunctionType(context, return_and_parameter_types); + } + + // If no existing function type was found, we need to create one. + if (function_type_id == 0) { + assert( + ((return_type_id == 0) == !region_output_ids.empty()) && + "We should only have set the return type if there are no output ids."); + // If the region generates output ids, we need to make a struct with one + // field per output id. + if (!region_output_ids.empty()) { + opt::Instruction::OperandList struct_member_types; + for (uint32_t output_id : region_output_ids) { + auto output_id_type = + context->get_def_use_mgr()->GetDef(output_id)->type_id(); + struct_member_types.push_back({SPV_OPERAND_TYPE_ID, {output_id_type}}); + } + // Add a new struct type to the module. + context->module()->AddType(MakeUnique( + context, SpvOpTypeStruct, 0, + message_.new_function_struct_return_type_id(), + std::move(struct_member_types))); + // The return type for the function is the newly-created struct. + return_type_id = message_.new_function_struct_return_type_id(); + } + assert( + return_type_id != 0 && + "We should either have a void return type, or have created a struct."); + + // The region's input ids dictate the parameter types to the function. + opt::Instruction::OperandList function_type_operands; + function_type_operands.push_back({SPV_OPERAND_TYPE_ID, {return_type_id}}); + for (auto id : region_input_ids) { + function_type_operands.push_back( + {SPV_OPERAND_TYPE_ID, + {context->get_def_use_mgr()->GetDef(id)->type_id()}}); + } + // Add a new function type to the module, and record that this is the type + // id for the new function. + context->module()->AddType(MakeUnique( + context, SpvOpTypeFunction, 0, message_.new_function_type_id(), + function_type_operands)); + function_type_id = message_.new_function_type_id(); + } + + // Create a new function with |message_.new_function_id| as the function id, + // and the return type and function type prepared above. + std::unique_ptr outlined_function = + MakeUnique(MakeUnique( + context, SpvOpFunction, return_type_id, message_.new_function_id(), + opt::Instruction::OperandList( + {{spv_operand_type_t ::SPV_OPERAND_TYPE_LITERAL_INTEGER, + {SpvFunctionControlMaskNone}}, + {spv_operand_type_t::SPV_OPERAND_TYPE_ID, + {function_type_id}}}))); + + // Add one parameter to the function for each input id, using the fresh ids + // provided in |input_id_to_fresh_id_map|. + for (auto id : region_input_ids) { + outlined_function->AddParameter(MakeUnique( + context, SpvOpFunctionParameter, + context->get_def_use_mgr()->GetDef(id)->type_id(), + input_id_to_fresh_id_map.at(id), opt::Instruction::OperandList())); + // If the input id is an arbitrary-valued variable, the same should be true + // of the corresponding parameter. + if (fact_manager->VariableValueIsArbitrary(id)) { + fact_manager->AddFactValueOfVariableIsArbitrary( + input_id_to_fresh_id_map.at(id)); + } + } + + return outlined_function; +} + +void TransformationOutlineFunction::UpdateModuleIdBoundForFreshIds( + opt::IRContext* context, + const std::map& input_id_to_fresh_id_map, + const std::map& output_id_to_fresh_id_map) const { + // Enlarge the module's id bound as needed to accommodate the various fresh + // ids associated with the transformation. + fuzzerutil::UpdateModuleIdBound( + context, message_.new_function_struct_return_type_id()); + fuzzerutil::UpdateModuleIdBound(context, message_.new_function_type_id()); + fuzzerutil::UpdateModuleIdBound(context, message_.new_function_id()); + fuzzerutil::UpdateModuleIdBound(context, + message_.new_function_region_entry_block()); + fuzzerutil::UpdateModuleIdBound(context, message_.new_caller_result_id()); + fuzzerutil::UpdateModuleIdBound(context, message_.new_callee_result_id()); + + for (auto& entry : input_id_to_fresh_id_map) { + fuzzerutil::UpdateModuleIdBound(context, entry.second); + } + + for (auto& entry : output_id_to_fresh_id_map) { + fuzzerutil::UpdateModuleIdBound(context, entry.second); + } +} + +void TransformationOutlineFunction::RemapInputAndOutputIdsInRegion( + opt::IRContext* context, const opt::BasicBlock& original_region_exit_block, + const std::set& region_blocks, + const std::vector& region_input_ids, + const std::vector& region_output_ids, + const std::map& input_id_to_fresh_id_map, + const std::map& output_id_to_fresh_id_map) const { + // Change all uses of input ids inside the region to the corresponding fresh + // ids that will ultimately be parameters of the outlined function. + // This is done by considering each region input id in turn. + for (uint32_t id : region_input_ids) { + // We then consider each use of the input id. + context->get_def_use_mgr()->ForEachUse( + id, [context, id, &input_id_to_fresh_id_map, region_blocks]( + opt::Instruction* use, uint32_t operand_index) { + // Find the block in which this use of the input id occurs. + opt::BasicBlock* use_block = context->get_instr_block(use); + // We want to rewrite the use id if its block occurs in the outlined + // region. + if (region_blocks.count(use_block) != 0) { + // Rewrite this use of the input id. + use->SetOperand(operand_index, {input_id_to_fresh_id_map.at(id)}); + } + }); + } + + // Change each definition of a region output id to define the corresponding + // fresh ids that will store intermediate value for the output ids. Also + // change all uses of the output id located in the outlined region. + // This is done by considering each region output id in turn. + for (uint32_t id : region_output_ids) { + // First consider each use of the output id and update the relevant uses. + context->get_def_use_mgr()->ForEachUse( + id, + [context, &original_region_exit_block, id, &output_id_to_fresh_id_map, + region_blocks](opt::Instruction* use, uint32_t operand_index) { + // Find the block in which this use of the output id occurs. + auto use_block = context->get_instr_block(use); + // We want to rewrite the use id if its block occurs in the outlined + // region, with one exception: the terminator of the exit block of + // the region is going to remain in the original function, so if the + // use appears in such a terminator instruction we leave it alone. + if ( + // The block is in the region ... + region_blocks.count(use_block) != 0 && + // ... and the use is not in the terminator instruction of the + // region's exit block. + !(use_block == &original_region_exit_block && + use->IsBlockTerminator())) { + // Rewrite this use of the output id. + use->SetOperand(operand_index, {output_id_to_fresh_id_map.at(id)}); + } + }); + + // Now change the instruction that defines the output id so that it instead + // defines the corresponding fresh id. We do this after changing all the + // uses so that the definition of the original id is still registered when + // we analyse its uses. + context->get_def_use_mgr()->GetDef(id)->SetResultId( + output_id_to_fresh_id_map.at(id)); + } +} + +void TransformationOutlineFunction::PopulateOutlinedFunction( + const opt::BasicBlock& original_region_entry_block, + const opt::BasicBlock& original_region_exit_block, + const std::set& region_blocks, + const std::vector& region_output_ids, + const std::map& output_id_to_fresh_id_map, + opt::IRContext* context, opt::Function* outlined_function, + FactManager* fact_manager) const { + // When we create the exit block for the outlined region, we use this pointer + // to track of it so that we can manipulate it later. + opt::BasicBlock* outlined_region_exit_block = nullptr; + + // The region entry block in the new function is identical to the entry block + // of the region being outlined, except that it has + // |message_.new_function_region_entry_block| as its id. + std::unique_ptr outlined_region_entry_block = + MakeUnique(MakeUnique( + context, SpvOpLabel, 0, message_.new_function_region_entry_block(), + opt::Instruction::OperandList())); + outlined_region_entry_block->SetParent(outlined_function); + + // If the original region's entry block was dead, the outlined region's entry + // block is also dead. + if (fact_manager->BlockIsDead(original_region_entry_block.id())) { + fact_manager->AddFactBlockIsDead(outlined_region_entry_block->id()); + } + + if (&original_region_entry_block == &original_region_exit_block) { + outlined_region_exit_block = outlined_region_entry_block.get(); + } + + for (auto& inst : original_region_entry_block) { + outlined_region_entry_block->AddInstruction( + std::unique_ptr(inst.Clone(context))); + } + outlined_function->AddBasicBlock(std::move(outlined_region_entry_block)); + + // We now go through the single-entry single-exit region defined by the entry + // and exit blocks, adding clones of all blocks to the new function. + + // Consider every block in the enclosing function. + auto enclosing_function = original_region_entry_block.GetParent(); + for (auto block_it = enclosing_function->begin(); + block_it != enclosing_function->end();) { + // Skip the region's entry block - we already dealt with it above. + if (region_blocks.count(&*block_it) == 0 || + &*block_it == &original_region_entry_block) { + ++block_it; + continue; + } + // Clone the block so that it can be added to the new function. + auto cloned_block = + std::unique_ptr(block_it->Clone(context)); + + // If this is the region's exit block, then the cloned block is the outlined + // region's exit block. + if (&*block_it == &original_region_exit_block) { + assert(outlined_region_exit_block == nullptr && + "We should not yet have encountered the exit block."); + outlined_region_exit_block = cloned_block.get(); + } + + cloned_block->SetParent(outlined_function); + + // Redirect any OpPhi operands whose predecessors are the original region + // entry block to become the new function entry block. + cloned_block->ForEachPhiInst([this](opt::Instruction* phi_inst) { + for (uint32_t predecessor_index = 1; + predecessor_index < phi_inst->NumInOperands(); + predecessor_index += 2) { + if (phi_inst->GetSingleWordInOperand(predecessor_index) == + message_.entry_block()) { + phi_inst->SetInOperand(predecessor_index, + {message_.new_function_region_entry_block()}); + } + } + }); + + outlined_function->AddBasicBlock(std::move(cloned_block)); + block_it = block_it.Erase(); + } + assert(outlined_region_exit_block != nullptr && + "We should have encountered the region's exit block when iterating " + "through the function"); + + // We now need to adapt the exit block for the region - in the new function - + // so that it ends with a return. + + // We first eliminate the merge instruction (if any) and the terminator for + // the cloned exit block. + for (auto inst_it = outlined_region_exit_block->begin(); + inst_it != outlined_region_exit_block->end();) { + if (inst_it->opcode() == SpvOpLoopMerge || + inst_it->opcode() == SpvOpSelectionMerge) { + inst_it = inst_it.Erase(); + } else if (inst_it->IsBlockTerminator()) { + inst_it = inst_it.Erase(); + } else { + ++inst_it; + } + } + + // We now add either OpReturn or OpReturnValue as the cloned exit block's + // terminator. + if (region_output_ids.empty()) { + // The case where there are no region output ids is simple: we just add + // OpReturn. + outlined_region_exit_block->AddInstruction(MakeUnique( + context, SpvOpReturn, 0, 0, opt::Instruction::OperandList())); + } else { + // In the case where there are output ids, we add an OpCompositeConstruct + // instruction to pack all the output values into a struct, and then an + // OpReturnValue instruction to return this struct. + opt::Instruction::OperandList struct_member_operands; + for (uint32_t id : region_output_ids) { + struct_member_operands.push_back( + {SPV_OPERAND_TYPE_ID, {output_id_to_fresh_id_map.at(id)}}); + } + outlined_region_exit_block->AddInstruction(MakeUnique( + context, SpvOpCompositeConstruct, + message_.new_function_struct_return_type_id(), + message_.new_callee_result_id(), struct_member_operands)); + outlined_region_exit_block->AddInstruction(MakeUnique( + context, SpvOpReturnValue, 0, 0, + opt::Instruction::OperandList( + {{SPV_OPERAND_TYPE_ID, {message_.new_callee_result_id()}}}))); + } + + outlined_function->SetFunctionEnd(MakeUnique( + context, SpvOpFunctionEnd, 0, 0, opt::Instruction::OperandList())); +} + +void TransformationOutlineFunction::ShrinkOriginalRegion( + opt::IRContext* context, std::set& region_blocks, + const std::vector& region_input_ids, + const std::vector& region_output_ids, + const std::map& output_id_to_type_id, + uint32_t return_type_id, + std::unique_ptr cloned_exit_block_merge, + std::unique_ptr cloned_exit_block_terminator, + opt::BasicBlock* original_region_entry_block) const { + // Erase all blocks from the original function that are in the outlined + // region, except for the region's entry block. + // + // In the process, identify all references to the exit block of the region, + // as merge blocks, continue targets, or OpPhi predecessors, and rewrite them + // to refer to the region entry block (the single block to which we are + // shrinking the region). + auto enclosing_function = original_region_entry_block->GetParent(); + for (auto block_it = enclosing_function->begin(); + block_it != enclosing_function->end();) { + if (&*block_it == original_region_entry_block) { + ++block_it; + } else if (region_blocks.count(&*block_it) == 0) { + // The block is not in the region. Check whether it has the last block + // of the region as an OpPhi predecessor, and if so change the + // predecessor to be the first block of the region (i.e. the block + // containing the call to what was outlined). + assert(block_it->MergeBlockIdIfAny() != message_.exit_block() && + "Outlined region must not end with a merge block"); + assert(block_it->ContinueBlockIdIfAny() != message_.exit_block() && + "Outlined region must not end with a continue target"); + block_it->ForEachPhiInst([this](opt::Instruction* phi_inst) { + for (uint32_t predecessor_index = 1; + predecessor_index < phi_inst->NumInOperands(); + predecessor_index += 2) { + if (phi_inst->GetSingleWordInOperand(predecessor_index) == + message_.exit_block()) { + phi_inst->SetInOperand(predecessor_index, {message_.entry_block()}); + } + } + }); + ++block_it; + } else { + // The block is in the region and is not the region's entry block: kill + // it. + block_it = block_it.Erase(); + } + } + + // Now erase all instructions from the region's entry block, as they have + // been outlined. + for (auto inst_it = original_region_entry_block->begin(); + inst_it != original_region_entry_block->end();) { + inst_it = inst_it.Erase(); + } + + // Now we add a call to the outlined function to the region's entry block. + opt::Instruction::OperandList function_call_operands; + function_call_operands.push_back( + {SPV_OPERAND_TYPE_ID, {message_.new_function_id()}}); + // The function parameters are the region input ids. + for (auto input_id : region_input_ids) { + function_call_operands.push_back({SPV_OPERAND_TYPE_ID, {input_id}}); + } + + original_region_entry_block->AddInstruction(MakeUnique( + context, SpvOpFunctionCall, return_type_id, + message_.new_caller_result_id(), function_call_operands)); + + // If there are output ids, the function call will return a struct. For each + // output id, we add an extract operation to pull the appropriate struct + // member out into an output id. + for (uint32_t index = 0; index < region_output_ids.size(); ++index) { + uint32_t output_id = region_output_ids[index]; + original_region_entry_block->AddInstruction(MakeUnique( + context, SpvOpCompositeExtract, output_id_to_type_id.at(output_id), + output_id, + opt::Instruction::OperandList( + {{SPV_OPERAND_TYPE_ID, {message_.new_caller_result_id()}}, + {SPV_OPERAND_TYPE_LITERAL_INTEGER, {index}}}))); + } + + // Finally, we terminate the block with the merge instruction (if any) that + // used to belong to the region's exit block, and the terminator that used + // to belong to the region's exit block. + if (cloned_exit_block_merge != nullptr) { + original_region_entry_block->AddInstruction( + std::move(cloned_exit_block_merge)); + } + original_region_entry_block->AddInstruction( + std::move(cloned_exit_block_terminator)); +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/transformation_outline_function.h b/third_party/spirv-tools/source/fuzz/transformation_outline_function.h new file mode 100644 index 0000000000..5711790620 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_outline_function.h @@ -0,0 +1,221 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_TRANSFORMATION_OUTLINE_FUNCTION_H_ +#define SOURCE_FUZZ_TRANSFORMATION_OUTLINE_FUNCTION_H_ + +#include +#include +#include + +#include "source/fuzz/fact_manager.h" +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "source/fuzz/transformation.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace fuzz { + +class TransformationOutlineFunction : public Transformation { + public: + explicit TransformationOutlineFunction( + const protobufs::TransformationOutlineFunction& message); + + TransformationOutlineFunction( + uint32_t entry_block, uint32_t exit_block, + uint32_t new_function_struct_return_type_id, + uint32_t new_function_type_id, uint32_t new_function_id, + uint32_t new_function_region_entry_block, uint32_t new_caller_result_id, + uint32_t new_callee_result_id, + std::map&& input_id_to_fresh_id, + std::map&& output_id_to_fresh_id); + + // - All the fresh ids occurring in the transformation must be distinct and + // fresh + // - |message_.entry_block| and |message_.exit_block| must form a single-entry + // single-exit control flow graph region + // - |message_.entry_block| must not start with OpVariable + // - |message_.entry_block| must not be a loop header + // - |message_.exit_block| must not be a merge block or the continue target + // of a loop + // - A structured control flow construct must lie either completely within the + // region or completely outside it + // - |message.entry_block| must not start with OpPhi; this is to keep the + // transformation simple - another transformation should be used to split + // a desired entry block that starts with OpPhi if needed + // - |message_.input_id_to_fresh_id| must contain an entry for every id + // defined outside the region but used in the region + // - |message_.output_id_to_fresh_id| must contain an entry for every id + // defined in the region but used outside the region + bool IsApplicable(opt::IRContext* context, + const FactManager& fact_manager) const override; + + // - A new function with id |message_.new_function_id| is added to the module. + // - If the region generates output ids, the return type of this function is + // a new struct type with one field per output id, and with type id + // |message_.new_function_struct_return_type|, otherwise the function return + // types is void and |message_.new_function_struct_return_type| is not used. + // - If the region generates input ids, the new function has one parameter per + // input id. Fresh ids for these parameters are provided by + // |message_.input_id_to_fresh_id|. + // - Unless the type required for the new function is already known, + // |message_.new_function_type_id| is used as the type id for a new function + // type, and the new function uses this type. + // - The new function starts with a dummy block with id + // |message_.new_function_first_block|, which jumps straight to a successor + // block, to avoid violating rules on what the first block in a function may + // look like. + // - The outlined region is replaced with a single block, with the same id + // as |message_.entry_block|, and which calls the new function, passing the + // region's input ids as parameters. The result is stored in + // |message_.new_caller_result_id|, which has type + // |message_.new_function_struct_return_type| (unless there are + // no output ids, in which case the return type is void). The components + // of this returned struct are then copied out into the region's output ids. + // The block ends with the merge instruction (if any) and terminator of + // |message_.exit_block|. + // - The body of the new function is identical to the outlined region, except + // that (a) the region's entry block has id + // |message_.new_function_region_entry_block|, (b) input id uses are + // replaced with parameter accesses, (c) and definitions of output ids are + // replaced with definitions of corresponding fresh ids provided by + // |message_.output_id_to_fresh_id|, and (d) the block of the function + // ends by returning a composite of type + // |message_.new_function_struct_return_type| comprised of all the fresh + // output ids (unless the return type is void, in which case no value is + // returned. + void Apply(opt::IRContext* context, FactManager* fact_manager) const override; + + protobufs::Transformation ToMessage() const override; + + // Returns the set of blocks dominated by |entry_block| and post-dominated + // by |exit_block|. + static std::set GetRegionBlocks( + opt::IRContext* context, opt::BasicBlock* entry_block, + opt::BasicBlock* exit_block); + + // Yields ids that are used in |region_set| and that are either parameters + // to the function containing |region_set|, or are defined by blocks of this + // function that are outside |region_set|. + // + // Special cases: OpPhi instructions in |region_entry_block| and the + // terminator of |region_exit_block| do not get outlined, therefore + // - id uses in OpPhi instructions in |region_entry_block| are ignored + // - id uses in the terminator instruction of |region_exit_block| are ignored + static std::vector GetRegionInputIds( + opt::IRContext* context, const std::set& region_set, + opt::BasicBlock* region_exit_block); + + // Yields all ids that are defined in |region_set| and used outside + // |region_set|. + // + // Special cases: for similar reasons as for |GetRegionInputIds|, + // - ids defined in the region and used in the terminator of + // |region_exit_block| count as output ids + static std::vector GetRegionOutputIds( + opt::IRContext* context, const std::set& region_set, + opt::BasicBlock* region_exit_block); + + private: + // Ensures that the module's id bound is at least the maximum of any fresh id + // associated with the transformation. + void UpdateModuleIdBoundForFreshIds( + opt::IRContext* context, + const std::map& input_id_to_fresh_id_map, + const std::map& output_id_to_fresh_id_map) const; + + // Uses |input_id_to_fresh_id_map| and |output_id_to_fresh_id_map| to convert, + // in the region to be outlined, all the input ids in |region_input_ids| and + // the output ids in |region_output_ids| to their fresh counterparts. + // Parameters |region_blocks| provides access to the blocks that must be + // modified, and |original_region_exit_block| allows for some special cases + // where ids should not be remapped. + void RemapInputAndOutputIdsInRegion( + opt::IRContext* context, + const opt::BasicBlock& original_region_exit_block, + const std::set& region_blocks, + const std::vector& region_input_ids, + const std::vector& region_output_ids, + const std::map& input_id_to_fresh_id_map, + const std::map& output_id_to_fresh_id_map) const; + + // Produce a Function object that has the right function type and parameter + // declarations. The function argument types and parameter ids are dictated + // by |region_input_ids| and |input_id_to_fresh_id_map|. The function return + // type is dictated by |region_output_ids|. + // + // A new struct type to represent the function return type, and a new function + // type for the function, will be added to the module (unless suitable types + // are already present). + // + // Facts about the function containing the outlined region that are relevant + // to the new function are propagated via |fact_manager|. + std::unique_ptr PrepareFunctionPrototype( + const std::vector& region_input_ids, + const std::vector& region_output_ids, + const std::map& input_id_to_fresh_id_map, + opt::IRContext* context, FactManager* fact_manager) const; + + // Creates the body of the outlined function by cloning blocks from the + // original region, given by |region_blocks|, adapting the cloned version + // of |original_region_exit_block| so that it returns something appropriate, + // and patching up branches to |original_region_entry_block| to refer to its + // clone. Parameters |region_output_ids| and |output_id_to_fresh_id_map| are + // used to determine what the function should return. + // + // The |fact_manager| argument allow facts about blocks being outlined, e.g. + // whether they are dead blocks, to be asserted about blocks that get created + // during outlining. + void PopulateOutlinedFunction( + const opt::BasicBlock& original_region_entry_block, + const opt::BasicBlock& original_region_exit_block, + const std::set& region_blocks, + const std::vector& region_output_ids, + const std::map& output_id_to_fresh_id_map, + opt::IRContext* context, opt::Function* outlined_function, + FactManager* fact_manager) const; + + // Shrinks the outlined region, given by |region_blocks|, down to the single + // block |original_region_entry_block|. This block is itself shrunk to just + // contain: + // - any OpPhi instructions that were originally present + // - a call to the outlined function, with parameters provided by + // |region_input_ids| + // - instructions to route components of the call's return value into + // |region_output_ids| + // - The merge instruction (if any) and terminator of the original region's + // exit block, given by |cloned_exit_block_merge| and + // |cloned_exit_block_terminator| + // Parameters |output_id_to_type_id| and |return_type_id| provide the + // provide types for the region's output ids, and the return type of the + // outlined function: as the module is in an inconsistent state when this + // function is called, this information cannot be gotten from the def-use + // manager. + void ShrinkOriginalRegion( + opt::IRContext* context, std::set& region_blocks, + const std::vector& region_input_ids, + const std::vector& region_output_ids, + const std::map& output_id_to_type_id, + uint32_t return_type_id, + std::unique_ptr cloned_exit_block_merge, + std::unique_ptr cloned_exit_block_terminator, + opt::BasicBlock* original_region_entry_block) const; + + protobufs::TransformationOutlineFunction message_; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_TRANSFORMATION_OUTLINE_FUNCTION_H_ diff --git a/third_party/spirv-tools/source/fuzz/transformation_replace_boolean_constant_with_constant_binary.cpp b/third_party/spirv-tools/source/fuzz/transformation_replace_boolean_constant_with_constant_binary.cpp new file mode 100644 index 0000000000..b097767fba --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_replace_boolean_constant_with_constant_binary.cpp @@ -0,0 +1,304 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_replace_boolean_constant_with_constant_binary.h" + +#include + +#include "source/fuzz/fuzzer_util.h" +#include "source/fuzz/id_use_descriptor.h" + +namespace spvtools { +namespace fuzz { + +namespace { + +// Given floating-point values |lhs| and |rhs|, and a floating-point binary +// operator |binop|, returns true if it is certain that 'lhs binop rhs' +// evaluates to |required_value|. +template +bool float_binop_evaluates_to(T lhs, T rhs, SpvOp binop, bool required_value) { + // Infinity and NaN values are conservatively treated as out of scope. + if (!std::isfinite(lhs) || !std::isfinite(rhs)) { + return false; + } + bool binop_result; + // The following captures the binary operators that spirv-fuzz can actually + // generate when turning a boolean constant into a binary expression. + switch (binop) { + case SpvOpFOrdGreaterThanEqual: + case SpvOpFUnordGreaterThanEqual: + binop_result = (lhs >= rhs); + break; + case SpvOpFOrdGreaterThan: + case SpvOpFUnordGreaterThan: + binop_result = (lhs > rhs); + break; + case SpvOpFOrdLessThanEqual: + case SpvOpFUnordLessThanEqual: + binop_result = (lhs <= rhs); + break; + case SpvOpFOrdLessThan: + case SpvOpFUnordLessThan: + binop_result = (lhs < rhs); + break; + default: + return false; + } + return binop_result == required_value; +} + +// Analogous to 'float_binop_evaluates_to', but for signed int values. +template +bool signed_int_binop_evaluates_to(T lhs, T rhs, SpvOp binop, + bool required_value) { + bool binop_result; + switch (binop) { + case SpvOpSGreaterThanEqual: + binop_result = (lhs >= rhs); + break; + case SpvOpSGreaterThan: + binop_result = (lhs > rhs); + break; + case SpvOpSLessThanEqual: + binop_result = (lhs <= rhs); + break; + case SpvOpSLessThan: + binop_result = (lhs < rhs); + break; + default: + return false; + } + return binop_result == required_value; +} + +// Analogous to 'float_binop_evaluates_to', but for unsigned int values. +template +bool unsigned_int_binop_evaluates_to(T lhs, T rhs, SpvOp binop, + bool required_value) { + bool binop_result; + switch (binop) { + case SpvOpUGreaterThanEqual: + binop_result = (lhs >= rhs); + break; + case SpvOpUGreaterThan: + binop_result = (lhs > rhs); + break; + case SpvOpULessThanEqual: + binop_result = (lhs <= rhs); + break; + case SpvOpULessThan: + binop_result = (lhs < rhs); + break; + default: + return false; + } + return binop_result == required_value; +} + +} // namespace + +TransformationReplaceBooleanConstantWithConstantBinary:: + TransformationReplaceBooleanConstantWithConstantBinary( + const spvtools::fuzz::protobufs:: + TransformationReplaceBooleanConstantWithConstantBinary& message) + : message_(message) {} + +TransformationReplaceBooleanConstantWithConstantBinary:: + TransformationReplaceBooleanConstantWithConstantBinary( + const protobufs::IdUseDescriptor& id_use_descriptor, uint32_t lhs_id, + uint32_t rhs_id, SpvOp comparison_opcode, + uint32_t fresh_id_for_binary_operation) { + *message_.mutable_id_use_descriptor() = id_use_descriptor; + message_.set_lhs_id(lhs_id); + message_.set_rhs_id(rhs_id); + message_.set_opcode(comparison_opcode); + message_.set_fresh_id_for_binary_operation(fresh_id_for_binary_operation); +} + +bool TransformationReplaceBooleanConstantWithConstantBinary::IsApplicable( + opt::IRContext* context, const FactManager& /*unused*/) const { + // The id for the binary result must be fresh + if (!fuzzerutil::IsFreshId(context, + message_.fresh_id_for_binary_operation())) { + return false; + } + + // The used id must be for a boolean constant + auto boolean_constant = context->get_def_use_mgr()->GetDef( + message_.id_use_descriptor().id_of_interest()); + if (!boolean_constant) { + return false; + } + if (!(boolean_constant->opcode() == SpvOpConstantFalse || + boolean_constant->opcode() == SpvOpConstantTrue)) { + return false; + } + + // The left-hand-side id must correspond to a constant instruction. + auto lhs_constant_inst = + context->get_def_use_mgr()->GetDef(message_.lhs_id()); + if (!lhs_constant_inst) { + return false; + } + if (lhs_constant_inst->opcode() != SpvOpConstant) { + return false; + } + + // The right-hand-side id must correspond to a constant instruction. + auto rhs_constant_inst = + context->get_def_use_mgr()->GetDef(message_.rhs_id()); + if (!rhs_constant_inst) { + return false; + } + if (rhs_constant_inst->opcode() != SpvOpConstant) { + return false; + } + + // The left- and right-hand side instructions must have the same type. + if (lhs_constant_inst->type_id() != rhs_constant_inst->type_id()) { + return false; + } + + // The expression 'LHS opcode RHS' must evaluate to the boolean constant. + auto lhs_constant = + context->get_constant_mgr()->FindDeclaredConstant(message_.lhs_id()); + auto rhs_constant = + context->get_constant_mgr()->FindDeclaredConstant(message_.rhs_id()); + bool expected_result = (boolean_constant->opcode() == SpvOpConstantTrue); + + const auto binary_opcode = static_cast(message_.opcode()); + + // We consider the floating point, signed and unsigned integer cases + // separately. In each case the logic is very similar. + if (lhs_constant->AsFloatConstant()) { + assert(rhs_constant->AsFloatConstant() && + "Both constants should be of the same type."); + if (lhs_constant->type()->AsFloat()->width() == 32) { + if (!float_binop_evaluates_to(lhs_constant->GetFloat(), + rhs_constant->GetFloat(), binary_opcode, + expected_result)) { + return false; + } + } else { + assert(lhs_constant->type()->AsFloat()->width() == 64); + if (!float_binop_evaluates_to(lhs_constant->GetDouble(), + rhs_constant->GetDouble(), binary_opcode, + expected_result)) { + return false; + } + } + } else { + assert(lhs_constant->AsIntConstant() && "Constants should be in or float."); + assert(rhs_constant->AsIntConstant() && + "Both constants should be of the same type."); + if (lhs_constant->type()->AsInteger()->IsSigned()) { + if (lhs_constant->type()->AsInteger()->width() == 32) { + if (!signed_int_binop_evaluates_to(lhs_constant->GetS32(), + rhs_constant->GetS32(), + binary_opcode, expected_result)) { + return false; + } + } else { + assert(lhs_constant->type()->AsInteger()->width() == 64); + if (!signed_int_binop_evaluates_to(lhs_constant->GetS64(), + rhs_constant->GetS64(), + binary_opcode, expected_result)) { + return false; + } + } + } else { + if (lhs_constant->type()->AsInteger()->width() == 32) { + if (!unsigned_int_binop_evaluates_to(lhs_constant->GetU32(), + rhs_constant->GetU32(), + binary_opcode, expected_result)) { + return false; + } + } else { + assert(lhs_constant->type()->AsInteger()->width() == 64); + if (!unsigned_int_binop_evaluates_to(lhs_constant->GetU64(), + rhs_constant->GetU64(), + binary_opcode, expected_result)) { + return false; + } + } + } + } + + // The id use descriptor must identify some instruction + auto instruction = + FindInstructionContainingUse(message_.id_use_descriptor(), context); + if (instruction == nullptr) { + return false; + } + + // The instruction must not be an OpPhi, as we cannot insert a binary + // operator instruction before an OpPhi. + // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/2902): there is + // scope for being less conservative. + return instruction->opcode() != SpvOpPhi; +} + +void TransformationReplaceBooleanConstantWithConstantBinary::Apply( + opt::IRContext* context, FactManager* fact_manager) const { + ApplyWithResult(context, fact_manager); +} + +opt::Instruction* +TransformationReplaceBooleanConstantWithConstantBinary::ApplyWithResult( + opt::IRContext* context, FactManager* /*unused*/) const { + opt::analysis::Bool bool_type; + opt::Instruction::OperandList operands = { + {SPV_OPERAND_TYPE_ID, {message_.lhs_id()}}, + {SPV_OPERAND_TYPE_ID, {message_.rhs_id()}}}; + auto binary_instruction = MakeUnique( + context, static_cast(message_.opcode()), + context->get_type_mgr()->GetId(&bool_type), + message_.fresh_id_for_binary_operation(), operands); + opt::Instruction* result = binary_instruction.get(); + auto instruction_containing_constant_use = + FindInstructionContainingUse(message_.id_use_descriptor(), context); + + // We want to insert the new instruction before the instruction that contains + // the use of the boolean, but we need to go backwards one more instruction if + // the using instruction is preceded by a merge instruction. + auto instruction_before_which_to_insert = instruction_containing_constant_use; + { + opt::Instruction* previous_node = + instruction_before_which_to_insert->PreviousNode(); + if (previous_node && (previous_node->opcode() == SpvOpLoopMerge || + previous_node->opcode() == SpvOpSelectionMerge)) { + instruction_before_which_to_insert = previous_node; + } + } + instruction_before_which_to_insert->InsertBefore( + std::move(binary_instruction)); + instruction_containing_constant_use->SetInOperand( + message_.id_use_descriptor().in_operand_index(), + {message_.fresh_id_for_binary_operation()}); + fuzzerutil::UpdateModuleIdBound(context, + message_.fresh_id_for_binary_operation()); + context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone); + return result; +} + +protobufs::Transformation +TransformationReplaceBooleanConstantWithConstantBinary::ToMessage() const { + protobufs::Transformation result; + *result.mutable_replace_boolean_constant_with_constant_binary() = message_; + return result; +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/transformation_replace_boolean_constant_with_constant_binary.h b/third_party/spirv-tools/source/fuzz/transformation_replace_boolean_constant_with_constant_binary.h new file mode 100644 index 0000000000..f74cd8d178 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_replace_boolean_constant_with_constant_binary.h @@ -0,0 +1,76 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_TRANSFORMATION_REPLACE_BOOLEAN_CONSTANT_WITH_CONSTANT_BINARY_H_ +#define SOURCE_FUZZ_TRANSFORMATION_REPLACE_BOOLEAN_CONSTANT_WITH_CONSTANT_BINARY_H_ + +#include "source/fuzz/fact_manager.h" +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "source/fuzz/transformation.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace fuzz { + +class TransformationReplaceBooleanConstantWithConstantBinary + : public Transformation { + public: + explicit TransformationReplaceBooleanConstantWithConstantBinary( + const protobufs::TransformationReplaceBooleanConstantWithConstantBinary& + message); + + TransformationReplaceBooleanConstantWithConstantBinary( + const protobufs::IdUseDescriptor& id_use_descriptor, uint32_t lhs_id, + uint32_t rhs_id, SpvOp comparison_opcode, + uint32_t fresh_id_for_binary_operation); + + // - |message_.fresh_id_for_binary_operation| must not already be used by the + // module. + // - |message_.id_use_descriptor| must identify a use of a boolean constant c. + // - |message_.lhs_id| and |message.rhs_id| must be the ids of constant + // instructions with the same type + // - |message_.opcode| must be suitable for applying to |message.lhs_id| and + // |message_.rhs_id|, and the result must evaluate to the boolean constant + // c. + // - The boolean constant usage must not be an argument to OpPhi, because in + // this case it is not legal to insert a binary operator instruction right + // before the OpPhi. + // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/2902): consider + // replacing a boolean in an OpPhi by adding a binary operator instruction + // to the parent block for the OpPhi. + bool IsApplicable(opt::IRContext* context, + const FactManager& fact_manager) const override; + + // A new instruction is added before the boolean constant usage that computes + // the result of applying |message_.opcode| to |message_.lhs_id| and + // |message_.rhs_id| is added, with result id + // |message_.fresh_id_for_binary_operation|. The boolean constant usage is + // replaced with this result id. + void Apply(opt::IRContext* context, FactManager* fact_manager) const override; + + // The same as Apply, except that the newly-added binary instruction is + // returned. + opt::Instruction* ApplyWithResult(opt::IRContext* context, + FactManager* fact_manager) const; + + protobufs::Transformation ToMessage() const override; + + private: + protobufs::TransformationReplaceBooleanConstantWithConstantBinary message_; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_TRANSFORMATION_REPLACE_BOOLEAN_CONSTANT_WITH_CONSTANT_BINARY_H_ diff --git a/third_party/spirv-tools/source/fuzz/transformation_replace_constant_with_uniform.cpp b/third_party/spirv-tools/source/fuzz/transformation_replace_constant_with_uniform.cpp new file mode 100644 index 0000000000..405776ec03 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_replace_constant_with_uniform.cpp @@ -0,0 +1,235 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_replace_constant_with_uniform.h" + +#include "source/fuzz/fuzzer_util.h" +#include "source/fuzz/uniform_buffer_element_descriptor.h" + +namespace spvtools { +namespace fuzz { + +TransformationReplaceConstantWithUniform:: + TransformationReplaceConstantWithUniform( + const spvtools::fuzz::protobufs:: + TransformationReplaceConstantWithUniform& message) + : message_(message) {} + +TransformationReplaceConstantWithUniform:: + TransformationReplaceConstantWithUniform( + protobufs::IdUseDescriptor id_use, + protobufs::UniformBufferElementDescriptor uniform_descriptor, + uint32_t fresh_id_for_access_chain, uint32_t fresh_id_for_load) { + *message_.mutable_id_use_descriptor() = std::move(id_use); + *message_.mutable_uniform_descriptor() = std::move(uniform_descriptor); + message_.set_fresh_id_for_access_chain(fresh_id_for_access_chain); + message_.set_fresh_id_for_load(fresh_id_for_load); +} + +std::unique_ptr +TransformationReplaceConstantWithUniform::MakeAccessChainInstruction( + spvtools::opt::IRContext* context, uint32_t constant_type_id) const { + // The input operands for the access chain. + opt::Instruction::OperandList operands_for_access_chain; + + opt::Instruction* uniform_variable = + FindUniformVariable(message_.uniform_descriptor(), context, false); + + // The first input operand is the id of the uniform variable. + operands_for_access_chain.push_back( + {SPV_OPERAND_TYPE_ID, {uniform_variable->result_id()}}); + + // The other input operands are the ids of the constants used to index into + // the uniform. The uniform buffer descriptor specifies a series of literals; + // for each we find the id of the instruction that defines it, and add these + // instruction ids as operands. + opt::analysis::Integer int_type(32, true); + auto registered_int_type = + context->get_type_mgr()->GetRegisteredType(&int_type)->AsInteger(); + auto int_type_id = context->get_type_mgr()->GetId(&int_type); + for (auto index : message_.uniform_descriptor().index()) { + opt::analysis::IntConstant int_constant(registered_int_type, {index}); + auto constant_id = context->get_constant_mgr()->FindDeclaredConstant( + &int_constant, int_type_id); + operands_for_access_chain.push_back({SPV_OPERAND_TYPE_ID, {constant_id}}); + } + + // The type id for the access chain is a uniform pointer with base type + // matching the given constant id type. + auto type_and_pointer_type = context->get_type_mgr()->GetTypeAndPointerType( + constant_type_id, SpvStorageClassUniform); + assert(type_and_pointer_type.first != nullptr); + assert(type_and_pointer_type.second != nullptr); + auto pointer_to_uniform_constant_type_id = + context->get_type_mgr()->GetId(type_and_pointer_type.second.get()); + + return MakeUnique( + context, SpvOpAccessChain, pointer_to_uniform_constant_type_id, + message_.fresh_id_for_access_chain(), operands_for_access_chain); +} + +std::unique_ptr +TransformationReplaceConstantWithUniform::MakeLoadInstruction( + spvtools::opt::IRContext* context, uint32_t constant_type_id) const { + opt::Instruction::OperandList operands_for_load = { + {SPV_OPERAND_TYPE_ID, {message_.fresh_id_for_access_chain()}}}; + return MakeUnique(context, SpvOpLoad, constant_type_id, + message_.fresh_id_for_load(), + operands_for_load); +} + +bool TransformationReplaceConstantWithUniform::IsApplicable( + spvtools::opt::IRContext* context, + const spvtools::fuzz::FactManager& fact_manager) const { + // The following is really an invariant of the transformation rather than + // merely a requirement of the precondition. We check it here since we cannot + // check it in the message_ constructor. + assert(message_.fresh_id_for_access_chain() != message_.fresh_id_for_load() && + "Fresh ids for access chain and load result cannot be the same."); + + // The ids for the access chain and load instructions must both be fresh. + if (!fuzzerutil::IsFreshId(context, message_.fresh_id_for_access_chain())) { + return false; + } + if (!fuzzerutil::IsFreshId(context, message_.fresh_id_for_load())) { + return false; + } + + // The id specified in the id use descriptor must be that of a declared scalar + // constant. + auto declared_constant = context->get_constant_mgr()->FindDeclaredConstant( + message_.id_use_descriptor().id_of_interest()); + if (!declared_constant) { + return false; + } + if (!declared_constant->AsScalarConstant()) { + return false; + } + + // The fact manager needs to believe that the uniform data element described + // by the uniform buffer element descriptor will hold a scalar value. + auto constant_id_associated_with_uniform = + fact_manager.GetConstantFromUniformDescriptor( + context, message_.uniform_descriptor()); + if (!constant_id_associated_with_uniform) { + return false; + } + auto constant_associated_with_uniform = + context->get_constant_mgr()->FindDeclaredConstant( + constant_id_associated_with_uniform); + assert(constant_associated_with_uniform && + "The constant should be present in the module."); + if (!constant_associated_with_uniform->AsScalarConstant()) { + return false; + } + + // The types and values of the scalar value held in the id specified by the id + // use descriptor and in the uniform data element specified by the uniform + // buffer element descriptor need to match on both type and value. + if (!declared_constant->type()->IsSame( + constant_associated_with_uniform->type())) { + return false; + } + if (declared_constant->AsScalarConstant()->words() != + constant_associated_with_uniform->AsScalarConstant()->words()) { + return false; + } + + // The id use descriptor must identify some instruction with respect to the + // module. + auto instruction_using_constant = + FindInstructionContainingUse(message_.id_use_descriptor(), context); + if (!instruction_using_constant) { + return false; + } + + // The module needs to have a uniform pointer type suitable for indexing into + // the uniform variable, i.e. matching the type of the constant we wish to + // replace with a uniform. + opt::analysis::Pointer pointer_to_type_of_constant(declared_constant->type(), + SpvStorageClassUniform); + if (!context->get_type_mgr()->GetId(&pointer_to_type_of_constant)) { + return false; + } + + // In order to index into the uniform, the module has got to contain the int32 + // type, plus an OpConstant for each of the indices of interest. + opt::analysis::Integer int_type(32, true); + if (!context->get_type_mgr()->GetId(&int_type)) { + return false; + } + auto registered_int_type = + context->get_type_mgr()->GetRegisteredType(&int_type)->AsInteger(); + auto int_type_id = context->get_type_mgr()->GetId(&int_type); + for (auto index : message_.uniform_descriptor().index()) { + opt::analysis::IntConstant int_constant(registered_int_type, {index}); + if (!context->get_constant_mgr()->FindDeclaredConstant(&int_constant, + int_type_id)) { + return false; + } + } + + return true; +} + +void TransformationReplaceConstantWithUniform::Apply( + spvtools::opt::IRContext* context, + spvtools::fuzz::FactManager* /*unused*/) const { + // Get the instruction that contains the id use we wish to replace. + auto instruction_containing_constant_use = + FindInstructionContainingUse(message_.id_use_descriptor(), context); + assert(instruction_containing_constant_use && + "Precondition requires that the id use can be found."); + assert(instruction_containing_constant_use->GetSingleWordInOperand( + message_.id_use_descriptor().in_operand_index()) == + message_.id_use_descriptor().id_of_interest() && + "Does not appear to be a usage of the desired id."); + + // The id of the type for the constant whose use we wish to replace. + auto constant_type_id = + context->get_def_use_mgr() + ->GetDef(message_.id_use_descriptor().id_of_interest()) + ->type_id(); + + // Add an access chain instruction to target the uniform element. + instruction_containing_constant_use->InsertBefore( + MakeAccessChainInstruction(context, constant_type_id)); + + // Add a load from this access chain. + instruction_containing_constant_use->InsertBefore( + MakeLoadInstruction(context, constant_type_id)); + + // Adjust the instruction containing the usage of the constant so that this + // usage refers instead to the result of the load. + instruction_containing_constant_use->SetInOperand( + message_.id_use_descriptor().in_operand_index(), + {message_.fresh_id_for_load()}); + + // Update the module id bound to reflect the new instructions. + fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id_for_load()); + fuzzerutil::UpdateModuleIdBound(context, + message_.fresh_id_for_access_chain()); + + context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone); +} + +protobufs::Transformation TransformationReplaceConstantWithUniform::ToMessage() + const { + protobufs::Transformation result; + *result.mutable_replace_constant_with_uniform() = message_; + return result; +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/transformation_replace_constant_with_uniform.h b/third_party/spirv-tools/source/fuzz/transformation_replace_constant_with_uniform.h new file mode 100644 index 0000000000..ed354b1dbc --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_replace_constant_with_uniform.h @@ -0,0 +1,91 @@ +#include + +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_TRANSFORMATION_REPLACE_CONSTANT_WITH_UNIFORM_H_ +#define SOURCE_FUZZ_TRANSFORMATION_REPLACE_CONSTANT_WITH_UNIFORM_H_ + +#include "source/fuzz/fact_manager.h" +#include "source/fuzz/id_use_descriptor.h" +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "source/fuzz/transformation.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace fuzz { + +class TransformationReplaceConstantWithUniform : public Transformation { + public: + explicit TransformationReplaceConstantWithUniform( + const protobufs::TransformationReplaceConstantWithUniform& message); + + TransformationReplaceConstantWithUniform( + protobufs::IdUseDescriptor id_use, + protobufs::UniformBufferElementDescriptor uniform_descriptor, + uint32_t fresh_id_for_access_chain, uint32_t fresh_id_for_load); + + // - |message_.fresh_id_for_access_chain| and |message_.fresh_id_for_load| + // must be distinct fresh ids. + // - |message_.uniform_descriptor| specifies a result id and a list of integer + // literal indices. + // As an example, suppose |message_.uniform_descriptor| is (18, [0, 1, 0]) + // It is required that: + // - the result id (18 in our example) is the id of some uniform variable + // - the module contains an integer constant instruction corresponding to + // each of the literal indices; in our example there must thus be + // OpConstant instructions %A and %B say for each of 0 and 1 + // - it is legitimate to index into the uniform variable using the + // sequence of indices; in our example this means indexing into %18 + // using the sequence %A %B %A + // - the module contains a uniform pointer type corresponding to the type + // of the uniform data element obtained by following these indices + // - |message_.id_use_descriptor| identifies the use of some id %C. It is + // required that: + // - this use does indeed exist in the module + // - %C is an OpConstant + // - According to the fact manager, the uniform data element specified by + // |message_.uniform_descriptor| holds a value with the same type and + // value as %C + bool IsApplicable(opt::IRContext* context, + const FactManager& fact_manager) const override; + + // - Introduces two new instructions: + // - An access chain targeting the uniform data element specified by + // |message_.uniform_descriptor|, with result id + // |message_.fresh_id_for_access_chain| + // - A load from this access chain, with id |message_.fresh_id_for_load| + // - Replaces the id use specified by |message_.id_use_descriptor| with + // |message_.fresh_id_for_load| + void Apply(opt::IRContext* context, FactManager* fact_manager) const override; + + protobufs::Transformation ToMessage() const override; + + private: + // Helper method to create an access chain for the uniform element associated + // with the transformation. + std::unique_ptr MakeAccessChainInstruction( + spvtools::opt::IRContext* context, uint32_t constant_type_id) const; + + // Helper to create a load instruction. + std::unique_ptr MakeLoadInstruction( + spvtools::opt::IRContext* context, uint32_t constant_type_id) const; + + protobufs::TransformationReplaceConstantWithUniform message_; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_TRANSFORMATION_REPLACE_CONSTANT_WITH_UNIFORM_H_ diff --git a/third_party/spirv-tools/source/fuzz/transformation_replace_id_with_synonym.cpp b/third_party/spirv-tools/source/fuzz/transformation_replace_id_with_synonym.cpp new file mode 100644 index 0000000000..79ba012829 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_replace_id_with_synonym.cpp @@ -0,0 +1,195 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_replace_id_with_synonym.h" + +#include + +#include "source/fuzz/data_descriptor.h" +#include "source/fuzz/fuzzer_util.h" +#include "source/fuzz/id_use_descriptor.h" +#include "source/opt/types.h" +#include "source/util/make_unique.h" + +namespace spvtools { +namespace fuzz { + +TransformationReplaceIdWithSynonym::TransformationReplaceIdWithSynonym( + const spvtools::fuzz::protobufs::TransformationReplaceIdWithSynonym& + message) + : message_(message) {} + +TransformationReplaceIdWithSynonym::TransformationReplaceIdWithSynonym( + protobufs::IdUseDescriptor id_use_descriptor, uint32_t synonymous_id) { + *message_.mutable_id_use_descriptor() = std::move(id_use_descriptor); + message_.set_synonymous_id(synonymous_id); +} + +bool TransformationReplaceIdWithSynonym::IsApplicable( + spvtools::opt::IRContext* context, + const spvtools::fuzz::FactManager& fact_manager) const { + auto id_of_interest = message_.id_use_descriptor().id_of_interest(); + + // Does the fact manager know about the synonym? + auto data_descriptor_for_synonymous_id = + MakeDataDescriptor(message_.synonymous_id(), {}); + if (!fact_manager.IsSynonymous(MakeDataDescriptor(id_of_interest, {}), + data_descriptor_for_synonymous_id, context)) { + return false; + } + + // Does the id use descriptor in the transformation identify an instruction? + auto use_instruction = + FindInstructionContainingUse(message_.id_use_descriptor(), context); + if (!use_instruction) { + return false; + } + + // Is the use suitable for being replaced in principle? + if (!UseCanBeReplacedWithSynonym( + context, use_instruction, + message_.id_use_descriptor().in_operand_index())) { + return false; + } + + // The transformation is applicable if the synonymous id is available at the + // use point. + return IdsIsAvailableAtUse(context, use_instruction, + message_.id_use_descriptor().in_operand_index(), + message_.synonymous_id()); +} + +void TransformationReplaceIdWithSynonym::Apply( + spvtools::opt::IRContext* context, + spvtools::fuzz::FactManager* /*unused*/) const { + auto instruction_to_change = + FindInstructionContainingUse(message_.id_use_descriptor(), context); + instruction_to_change->SetInOperand( + message_.id_use_descriptor().in_operand_index(), + {message_.synonymous_id()}); + context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone); +} + +protobufs::Transformation TransformationReplaceIdWithSynonym::ToMessage() + const { + protobufs::Transformation result; + *result.mutable_replace_id_with_synonym() = message_; + return result; +} + +bool TransformationReplaceIdWithSynonym::IdsIsAvailableAtUse( + opt::IRContext* context, opt::Instruction* use_instruction, + uint32_t use_input_operand_index, uint32_t id) { + if (!context->get_instr_block(id)) { + return true; + } + auto defining_instruction = context->get_def_use_mgr()->GetDef(id); + if (defining_instruction == use_instruction) { + return false; + } + auto dominator_analysis = context->GetDominatorAnalysis( + context->get_instr_block(use_instruction)->GetParent()); + if (use_instruction->opcode() == SpvOpPhi) { + // In the case where the use is an operand to OpPhi, it is actually the + // *parent* block associated with the operand that must be dominated by + // the synonym. + auto parent_block = + use_instruction->GetSingleWordInOperand(use_input_operand_index + 1); + return dominator_analysis->Dominates( + context->get_instr_block(defining_instruction)->id(), parent_block); + } + return dominator_analysis->Dominates(defining_instruction, use_instruction); +} + +bool TransformationReplaceIdWithSynonym::UseCanBeReplacedWithSynonym( + opt::IRContext* context, opt::Instruction* use_instruction, + uint32_t use_in_operand_index) { + if (use_instruction->opcode() == SpvOpAccessChain && + use_in_operand_index > 0) { + // This is an access chain index. If the (sub-)object being accessed by the + // given index has struct type then we cannot replace the use with a + // synonym, as the use needs to be an OpConstant. + + // Get the top-level composite type that is being accessed. + auto object_being_accessed = context->get_def_use_mgr()->GetDef( + use_instruction->GetSingleWordInOperand(0)); + auto pointer_type = + context->get_type_mgr()->GetType(object_being_accessed->type_id()); + assert(pointer_type->AsPointer()); + auto composite_type_being_accessed = + pointer_type->AsPointer()->pointee_type(); + + // Now walk the access chain, tracking the type of each sub-object of the + // composite that is traversed, until the index of interest is reached. + for (uint32_t index_in_operand = 1; index_in_operand < use_in_operand_index; + index_in_operand++) { + // For vectors, matrices and arrays, getting the type of the sub-object is + // trivial. For the struct case, the sub-object type is field-sensitive, + // and depends on the constant index that is used. + if (composite_type_being_accessed->AsVector()) { + composite_type_being_accessed = + composite_type_being_accessed->AsVector()->element_type(); + } else if (composite_type_being_accessed->AsMatrix()) { + composite_type_being_accessed = + composite_type_being_accessed->AsMatrix()->element_type(); + } else if (composite_type_being_accessed->AsArray()) { + composite_type_being_accessed = + composite_type_being_accessed->AsArray()->element_type(); + } else { + assert(composite_type_being_accessed->AsStruct()); + auto constant_index_instruction = context->get_def_use_mgr()->GetDef( + use_instruction->GetSingleWordInOperand(index_in_operand)); + assert(constant_index_instruction->opcode() == SpvOpConstant); + uint32_t member_index = + constant_index_instruction->GetSingleWordInOperand(0); + composite_type_being_accessed = + composite_type_being_accessed->AsStruct() + ->element_types()[member_index]; + } + } + + // We have found the composite type being accessed by the index we are + // considering replacing. If it is a struct, then we cannot do the + // replacement as struct indices must be constants. + if (composite_type_being_accessed->AsStruct()) { + return false; + } + } + + if (use_instruction->opcode() == SpvOpFunctionCall && + use_in_operand_index > 0) { + // This is a function call argument. It is not allowed to have pointer + // type. + + // Get the definition of the function being called. + auto function = context->get_def_use_mgr()->GetDef( + use_instruction->GetSingleWordInOperand(0)); + // From the function definition, get the function type. + auto function_type = + context->get_def_use_mgr()->GetDef(function->GetSingleWordInOperand(1)); + // OpTypeFunction's 0-th input operand is the function return type, and the + // function argument types follow. Because the arguments to OpFunctionCall + // start from input operand 1, we can use |use_in_operand_index| to get the + // type associated with this function argument. + auto parameter_type = context->get_type_mgr()->GetType( + function_type->GetSingleWordInOperand(use_in_operand_index)); + if (parameter_type->AsPointer()) { + return false; + } + } + return true; +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/transformation_replace_id_with_synonym.h b/third_party/spirv-tools/source/fuzz/transformation_replace_id_with_synonym.h new file mode 100644 index 0000000000..c21673dcdd --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_replace_id_with_synonym.h @@ -0,0 +1,80 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_TRANSFORMATION_REPLACE_ID_WITH_SYNONYM_H_ +#define SOURCE_FUZZ_TRANSFORMATION_REPLACE_ID_WITH_SYNONYM_H_ + +#include "source/fuzz/fact_manager.h" +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "source/fuzz/transformation.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace fuzz { + +class TransformationReplaceIdWithSynonym : public Transformation { + public: + explicit TransformationReplaceIdWithSynonym( + const protobufs::TransformationReplaceIdWithSynonym& message); + + TransformationReplaceIdWithSynonym( + protobufs::IdUseDescriptor id_use_descriptor, uint32_t synonymous_id); + + // - The fact manager must know that the id identified by + // |message_.id_use_descriptor| is synonomous with + // |message_.synonymous_id|. + // - Replacing the id in |message_.id_use_descriptor| by + // |message_.synonymous_id| must respect SPIR-V's rules about uses being + // dominated by their definitions. + // - The id must not be an index into an access chain whose base object has + // struct type, as such indices must be constants. + // - The id must not be a pointer argument to a function call (because the + // synonym might not be a memory object declaration). + // - |fresh_id_for_temporary| must be 0. + bool IsApplicable(opt::IRContext* context, + const FactManager& fact_manager) const override; + + // Replaces the use identified by |message_.id_use_descriptor| with the + // synonymous id identified by |message_.synonymous_id|. + void Apply(opt::IRContext* context, FactManager* fact_manager) const override; + + protobufs::Transformation ToMessage() const override; + + // Checks whether the |id| is available (according to dominance rules) at the + // use point defined by input operand |use_input_operand_index| of + // |use_instruction|. + static bool IdsIsAvailableAtUse(opt::IRContext* context, + opt::Instruction* use_instruction, + uint32_t use_input_operand_index, + uint32_t id); + + // Checks whether various conditions hold related to the acceptability of + // replacing the id use at |use_in_operand_index| of |use_instruction| with + // a synonym. In particular, this checks that: + // - the id use is not an index into a struct field in an OpAccessChain - such + // indices must be constants, so it is dangerous to replace them. + // - the id use is not a pointer function call argument, on which there are + // restrictions that make replacement problematic. + static bool UseCanBeReplacedWithSynonym(opt::IRContext* context, + opt::Instruction* use_instruction, + uint32_t use_in_operand_index); + + private: + protobufs::TransformationReplaceIdWithSynonym message_; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_TRANSFORMATION_REPLACE_ID_WITH_SYNONYM_H_ diff --git a/third_party/spirv-tools/source/fuzz/transformation_set_function_control.cpp b/third_party/spirv-tools/source/fuzz/transformation_set_function_control.cpp new file mode 100644 index 0000000000..d2b61f198a --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_set_function_control.cpp @@ -0,0 +1,100 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_set_function_control.h" + +namespace spvtools { +namespace fuzz { + +TransformationSetFunctionControl::TransformationSetFunctionControl( + const spvtools::fuzz::protobufs::TransformationSetFunctionControl& message) + : message_(message) {} + +TransformationSetFunctionControl::TransformationSetFunctionControl( + uint32_t function_id, uint32_t function_control) { + message_.set_function_id(function_id); + message_.set_function_control(function_control); +} + +bool TransformationSetFunctionControl::IsApplicable( + opt::IRContext* context, const FactManager& /*unused*/) const { + opt::Instruction* function_def_instruction = + FindFunctionDefInstruction(context); + if (!function_def_instruction) { + // The given function id does not correspond to any function. + return false; + } + uint32_t existing_function_control_mask = + function_def_instruction->GetSingleWordInOperand(0); + + // Check (via an assertion) that function control mask doesn't have any bad + // bits set. + uint32_t acceptable_function_control_bits = + SpvFunctionControlInlineMask | SpvFunctionControlDontInlineMask | + SpvFunctionControlPureMask | SpvFunctionControlConstMask; + // The following is to keep release-mode compilers happy as this variable is + // only used in an assertion. + (void)(acceptable_function_control_bits); + assert(!(message_.function_control() & ~acceptable_function_control_bits) && + "Nonsensical loop control bits were found."); + + // Check (via an assertion) that function control mask does not have both + // Inline and DontInline bits set. + assert(!((message_.function_control() & SpvFunctionControlInlineMask) && + (message_.function_control() & SpvFunctionControlDontInlineMask)) && + "It is not OK to set both the 'Inline' and 'DontInline' bits of a " + "function control mask"); + + // Check that Const and Pure are only present if they were present on the + // original function + for (auto mask_bit : + {SpvFunctionControlPureMask, SpvFunctionControlConstMask}) { + if ((message_.function_control() & mask_bit) && + !(existing_function_control_mask & mask_bit)) { + return false; + } + } + + return true; +} + +void TransformationSetFunctionControl::Apply(opt::IRContext* context, + FactManager* /*unused*/) const { + opt::Instruction* function_def_instruction = + FindFunctionDefInstruction(context); + function_def_instruction->SetInOperand(0, {message_.function_control()}); +} + +protobufs::Transformation TransformationSetFunctionControl::ToMessage() const { + protobufs::Transformation result; + *result.mutable_set_function_control() = message_; + return result; +} + +opt::Instruction* TransformationSetFunctionControl ::FindFunctionDefInstruction( + opt::IRContext* context) const { + // Look through all functions for a function whose defining instruction's + // result id matches |message_.function_id|, returning the defining + // instruction if found. + for (auto& function : *context->module()) { + if (function.DefInst().result_id() == message_.function_id()) { + return &function.DefInst(); + } + } + // A nullptr result indicates that no match was found. + return nullptr; +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/transformation_set_function_control.h b/third_party/spirv-tools/source/fuzz/transformation_set_function_control.h new file mode 100644 index 0000000000..0526bb9c52 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_set_function_control.h @@ -0,0 +1,58 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_TRANSFORMATION_SET_FUNCTION_CONTROL_H_ +#define SOURCE_FUZZ_TRANSFORMATION_SET_FUNCTION_CONTROL_H_ + +#include "source/fuzz/fact_manager.h" +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "source/fuzz/transformation.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace fuzz { + +class TransformationSetFunctionControl : public Transformation { + public: + explicit TransformationSetFunctionControl( + const protobufs::TransformationSetFunctionControl& message); + + TransformationSetFunctionControl(uint32_t function_id, + uint32_t function_control); + + // - |message_.function_id| must be the result id of an OpFunction + // instruction. + // - |message_.function_control| must be a function control mask that sets + // at most one of 'Inline' or 'DontInline', and that may not contain 'Pure' + // (respectively 'Const') unless the existing function control mask contains + // 'Pure' (respectively 'Const'). + bool IsApplicable(opt::IRContext* context, + const FactManager& fact_manager) const override; + + // The function control operand of instruction |message_.function_id| is + // over-written with |message_.function_control|. + void Apply(opt::IRContext* context, FactManager* fact_manager) const override; + + protobufs::Transformation ToMessage() const override; + + private: + opt::Instruction* FindFunctionDefInstruction(opt::IRContext* context) const; + + protobufs::TransformationSetFunctionControl message_; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_TRANSFORMATION_SET_FUNCTION_CONTROL_H_ diff --git a/third_party/spirv-tools/source/fuzz/transformation_set_loop_control.cpp b/third_party/spirv-tools/source/fuzz/transformation_set_loop_control.cpp new file mode 100644 index 0000000000..9062f174a2 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_set_loop_control.cpp @@ -0,0 +1,216 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_set_loop_control.h" + +namespace spvtools { +namespace fuzz { + +TransformationSetLoopControl::TransformationSetLoopControl( + const spvtools::fuzz::protobufs::TransformationSetLoopControl& message) + : message_(message) {} + +TransformationSetLoopControl::TransformationSetLoopControl( + uint32_t block_id, uint32_t loop_control, uint32_t peel_count, + uint32_t partial_count) { + message_.set_block_id(block_id); + message_.set_loop_control(loop_control); + message_.set_peel_count(peel_count); + message_.set_partial_count(partial_count); +} + +bool TransformationSetLoopControl::IsApplicable( + opt::IRContext* context, const FactManager& /*unused*/) const { + // |message_.block_id| must identify a block that ends with OpLoopMerge. + auto block = context->get_instr_block(message_.block_id()); + if (!block) { + return false; + } + auto merge_inst = block->GetMergeInst(); + if (!merge_inst || merge_inst->opcode() != SpvOpLoopMerge) { + return false; + } + + // We sanity-check that the transformation does not try to set any meaningless + // bits of the loop control mask. + uint32_t all_loop_control_mask_bits_set = + SpvLoopControlUnrollMask | SpvLoopControlDontUnrollMask | + SpvLoopControlDependencyInfiniteMask | + SpvLoopControlDependencyLengthMask | SpvLoopControlMinIterationsMask | + SpvLoopControlMaxIterationsMask | SpvLoopControlIterationMultipleMask | + SpvLoopControlPeelCountMask | SpvLoopControlPartialCountMask; + + // The variable is only used in an assertion; the following keeps release-mode + // compilers happy. + (void)(all_loop_control_mask_bits_set); + + // No additional bits should be set. + assert(!(message_.loop_control() & ~all_loop_control_mask_bits_set)); + + // Grab the loop control mask currently associated with the OpLoopMerge + // instruction. + auto existing_loop_control_mask = + merge_inst->GetSingleWordInOperand(kLoopControlMaskInOperandIndex); + + // Check that there is no attempt to set one of the loop controls that + // requires guarantees to hold. + for (SpvLoopControlMask mask : + {SpvLoopControlDependencyInfiniteMask, + SpvLoopControlDependencyLengthMask, SpvLoopControlMinIterationsMask, + SpvLoopControlMaxIterationsMask, SpvLoopControlIterationMultipleMask}) { + // We have a problem if this loop control bit was not set in the original + // loop control mask but is set by the transformation. + if (LoopControlBitIsAddedByTransformation(mask, + existing_loop_control_mask)) { + return false; + } + } + + if ((message_.loop_control() & + (SpvLoopControlPeelCountMask | SpvLoopControlPartialCountMask)) && + !(PeelCountIsSupported(context) && PartialCountIsSupported(context))) { + // At least one of PeelCount or PartialCount is used, but the SPIR-V version + // in question does not support these loop controls. + return false; + } + + if (message_.peel_count() > 0 && + !(message_.loop_control() & SpvLoopControlPeelCountMask)) { + // Peel count provided, but peel count mask bit not set. + return false; + } + + if (message_.partial_count() > 0 && + !(message_.loop_control() & SpvLoopControlPartialCountMask)) { + // Partial count provided, but partial count mask bit not set. + return false; + } + + // We must not set both 'don't unroll' and one of 'peel count' or 'partial + // count'. + return !((message_.loop_control() & SpvLoopControlDontUnrollMask) && + (message_.loop_control() & + (SpvLoopControlPeelCountMask | SpvLoopControlPartialCountMask))); +} + +void TransformationSetLoopControl::Apply(opt::IRContext* context, + FactManager* /*unused*/) const { + // Grab the loop merge instruction and its associated loop control mask. + auto merge_inst = + context->get_instr_block(message_.block_id())->GetMergeInst(); + auto existing_loop_control_mask = + merge_inst->GetSingleWordInOperand(kLoopControlMaskInOperandIndex); + + // We are going to replace the OpLoopMerge's operands with this list. + opt::Instruction::OperandList new_operands; + // We add the existing merge block and continue target ids. + new_operands.push_back(merge_inst->GetInOperand(0)); + new_operands.push_back(merge_inst->GetInOperand(1)); + // We use the loop control mask from the transformation. + new_operands.push_back( + {SPV_OPERAND_TYPE_LOOP_CONTROL, {message_.loop_control()}}); + + // It remains to determine what literals to provide, in association with + // the new loop control mask. + // + // For the loop controls that require guarantees to hold about the number + // of loop iterations, we need to keep, from the original OpLoopMerge, any + // literals associated with loop control bits that are still set. + + uint32_t literal_index = 0; // Indexes into the literals from the original + // instruction. + for (SpvLoopControlMask mask : + {SpvLoopControlDependencyLengthMask, SpvLoopControlMinIterationsMask, + SpvLoopControlMaxIterationsMask, SpvLoopControlIterationMultipleMask}) { + // Check whether the bit was set in the original loop control mask. + if (existing_loop_control_mask & mask) { + // Check whether the bit is set in the new loop control mask. + if (message_.loop_control() & mask) { + // Add the associated literal to our sequence of replacement operands. + new_operands.push_back( + {SPV_OPERAND_TYPE_LITERAL_INTEGER, + {merge_inst->GetSingleWordInOperand( + kLoopControlFirstLiteralInOperandIndex + literal_index)}}); + } + // Increment our index into the original loop control mask's literals, + // whether or not the bit was set in the new mask. + literal_index++; + } + } + + // If PeelCount is set in the new mask, |message_.peel_count| provides the + // associated peel count. + if (message_.loop_control() & SpvLoopControlPeelCountMask) { + new_operands.push_back( + {SPV_OPERAND_TYPE_LITERAL_INTEGER, {message_.peel_count()}}); + } + + // Similar, but for PartialCount. + if (message_.loop_control() & SpvLoopControlPartialCountMask) { + new_operands.push_back( + {SPV_OPERAND_TYPE_LITERAL_INTEGER, {message_.partial_count()}}); + } + + // Replace the input operands of the OpLoopMerge with the new operands we have + // accumulated. + merge_inst->SetInOperands(std::move(new_operands)); +} + +protobufs::Transformation TransformationSetLoopControl::ToMessage() const { + protobufs::Transformation result; + *result.mutable_set_loop_control() = message_; + return result; +} + +bool TransformationSetLoopControl::LoopControlBitIsAddedByTransformation( + SpvLoopControlMask loop_control_single_bit_mask, + uint32_t existing_loop_control_mask) const { + return !(loop_control_single_bit_mask & existing_loop_control_mask) && + (loop_control_single_bit_mask & message_.loop_control()); +} + +bool TransformationSetLoopControl::PartialCountIsSupported( + opt::IRContext* context) { + // TODO(afd): We capture the universal environments for which this loop + // control is definitely not supported. The check should be refined on + // demand for other target environments. + switch (context->grammar().target_env()) { + case SPV_ENV_UNIVERSAL_1_0: + case SPV_ENV_UNIVERSAL_1_1: + case SPV_ENV_UNIVERSAL_1_2: + case SPV_ENV_UNIVERSAL_1_3: + return false; + default: + return true; + } +} + +bool TransformationSetLoopControl::PeelCountIsSupported( + opt::IRContext* context) { + // TODO(afd): We capture the universal environments for which this loop + // control is definitely not supported. The check should be refined on + // demand for other target environments. + switch (context->grammar().target_env()) { + case SPV_ENV_UNIVERSAL_1_0: + case SPV_ENV_UNIVERSAL_1_1: + case SPV_ENV_UNIVERSAL_1_2: + case SPV_ENV_UNIVERSAL_1_3: + return false; + default: + return true; + } +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/transformation_set_loop_control.h b/third_party/spirv-tools/source/fuzz/transformation_set_loop_control.h new file mode 100644 index 0000000000..28b148cad2 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_set_loop_control.h @@ -0,0 +1,79 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_TRANSFORMATION_SET_LOOP_CONTROL_H_ +#define SOURCE_FUZZ_TRANSFORMATION_SET_LOOP_CONTROL_H_ + +#include "source/fuzz/fact_manager.h" +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "source/fuzz/transformation.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace fuzz { + +class TransformationSetLoopControl : public Transformation { + public: + const static uint32_t kLoopControlMaskInOperandIndex = 2; + const static uint32_t kLoopControlFirstLiteralInOperandIndex = 3; + + explicit TransformationSetLoopControl( + const protobufs::TransformationSetLoopControl& message); + + TransformationSetLoopControl(uint32_t block_id, uint32_t loop_control, + uint32_t peel_count, uint32_t partial_count); + + // - |message_.block_id| must be a block containing an OpLoopMerge + // instruction. + // - |message_.loop_control| must be a legal loop control mask that + // only uses controls available in the SPIR-V version associated with + // |context|, and must not add loop controls that are only valid in the + // presence of guarantees about what the loop does (e.g. MinIterations). + // - |message_.peel_count| (respectively |message_.partial_count|) must be + // zero PeelCount (respectively PartialCount) is set in + // |message_.loop_control|. + bool IsApplicable(opt::IRContext* context, + const FactManager& fact_manager) const override; + + // - The loop control operand of the OpLoopMergeInstruction in + // |message_.block_id| is overwritten with |message_.loop_control|. + // - The literals associated with the loop control are updated to reflect any + // controls with associated literals that have been removed (e.g. + // MinIterations), and any that have been added (PeelCount and/or + // PartialCount). + void Apply(opt::IRContext* context, FactManager* fact_manager) const override; + + protobufs::Transformation ToMessage() const override; + + // Does the version of SPIR-V being used support the PartialCount loop + // control? + static bool PartialCountIsSupported(opt::IRContext* context); + + // Does the version of SPIR-V being used support the PeelCount loop control? + static bool PeelCountIsSupported(opt::IRContext* context); + + private: + // Returns true if and only if |loop_single_bit_mask| is *not* set in + // |existing_loop_control| but *is* set in |message_.loop_control|. + bool LoopControlBitIsAddedByTransformation( + SpvLoopControlMask loop_control_single_bit_mask, + uint32_t existing_loop_control_mask) const; + + protobufs::TransformationSetLoopControl message_; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_TRANSFORMATION_SET_LOOP_CONTROL_H_ diff --git a/third_party/spirv-tools/source/fuzz/transformation_set_memory_operands_mask.cpp b/third_party/spirv-tools/source/fuzz/transformation_set_memory_operands_mask.cpp new file mode 100644 index 0000000000..a14e1a6098 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_set_memory_operands_mask.cpp @@ -0,0 +1,201 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_set_memory_operands_mask.h" + +#include "source/fuzz/instruction_descriptor.h" + +namespace spvtools { +namespace fuzz { + +namespace { + +const uint32_t kOpLoadMemoryOperandsMaskIndex = 1; +const uint32_t kOpStoreMemoryOperandsMaskIndex = 2; +const uint32_t kOpCopyMemoryFirstMemoryOperandsMaskIndex = 2; +const uint32_t kOpCopyMemorySizedFirstMemoryOperandsMaskIndex = 3; + +} // namespace + +TransformationSetMemoryOperandsMask::TransformationSetMemoryOperandsMask( + const spvtools::fuzz::protobufs::TransformationSetMemoryOperandsMask& + message) + : message_(message) {} + +TransformationSetMemoryOperandsMask::TransformationSetMemoryOperandsMask( + const protobufs::InstructionDescriptor& memory_access_instruction, + uint32_t memory_operands_mask, uint32_t memory_operands_mask_index) { + *message_.mutable_memory_access_instruction() = memory_access_instruction; + message_.set_memory_operands_mask(memory_operands_mask); + message_.set_memory_operands_mask_index(memory_operands_mask_index); +} + +bool TransformationSetMemoryOperandsMask::IsApplicable( + opt::IRContext* context, + const spvtools::fuzz::FactManager& /*unused*/) const { + if (message_.memory_operands_mask_index() != 0) { + // The following conditions should never be violated, even if + // transformations end up being replayed in a different way to the manner in + // which they were applied during fuzzing, hence why these are assertions + // rather than applicability checks. + assert(message_.memory_operands_mask_index() == 1); + assert(message_.memory_access_instruction().target_instruction_opcode() == + SpvOpCopyMemory || + message_.memory_access_instruction().target_instruction_opcode() == + SpvOpCopyMemorySized); + assert(MultipleMemoryOperandMasksAreSupported(context)); + } + + auto instruction = + FindInstruction(message_.memory_access_instruction(), context); + if (!instruction) { + return false; + } + if (!IsMemoryAccess(*instruction)) { + return false; + } + + auto original_mask_in_operand_index = GetInOperandIndexForMask( + *instruction, message_.memory_operands_mask_index()); + assert(original_mask_in_operand_index != 0 && + "The given mask index is not valid."); + uint32_t original_mask = + original_mask_in_operand_index < instruction->NumInOperands() + ? instruction->GetSingleWordInOperand(original_mask_in_operand_index) + : static_cast(SpvMemoryAccessMaskNone); + uint32_t new_mask = message_.memory_operands_mask(); + + // Volatile must not be removed + if ((original_mask & SpvMemoryAccessVolatileMask) && + !(new_mask & SpvMemoryAccessVolatileMask)) { + return false; + } + + // Nontemporal can be added or removed, and no other flag is allowed to + // change. We do this by checking that the masks are equal once we set + // their Volatile and Nontemporal flags to the same value (this works + // because valid manipulation of Volatile is checked above, and the manner + // in which Nontemporal is manipulated does not matter). + return (original_mask | SpvMemoryAccessVolatileMask | + SpvMemoryAccessNontemporalMask) == + (new_mask | SpvMemoryAccessVolatileMask | + SpvMemoryAccessNontemporalMask); +} + +void TransformationSetMemoryOperandsMask::Apply( + opt::IRContext* context, spvtools::fuzz::FactManager* /*unused*/) const { + auto instruction = + FindInstruction(message_.memory_access_instruction(), context); + auto original_mask_in_operand_index = GetInOperandIndexForMask( + *instruction, message_.memory_operands_mask_index()); + // Either add a new operand, if no mask operand was already present, or + // replace an existing mask operand. + if (original_mask_in_operand_index >= instruction->NumInOperands()) { + instruction->AddOperand( + {SPV_OPERAND_TYPE_MEMORY_ACCESS, {message_.memory_operands_mask()}}); + + } else { + instruction->SetInOperand(original_mask_in_operand_index, + {message_.memory_operands_mask()}); + } +} + +protobufs::Transformation TransformationSetMemoryOperandsMask::ToMessage() + const { + protobufs::Transformation result; + *result.mutable_set_memory_operands_mask() = message_; + return result; +} + +bool TransformationSetMemoryOperandsMask::IsMemoryAccess( + const opt::Instruction& instruction) { + switch (instruction.opcode()) { + case SpvOpLoad: + case SpvOpStore: + case SpvOpCopyMemory: + case SpvOpCopyMemorySized: + return true; + default: + return false; + } +} + +uint32_t TransformationSetMemoryOperandsMask::GetInOperandIndexForMask( + const opt::Instruction& instruction, uint32_t mask_index) { + // Get the input operand index associated with the first memory operands mask + // for the instruction. + uint32_t first_mask_in_operand_index = 0; + switch (instruction.opcode()) { + case SpvOpLoad: + first_mask_in_operand_index = kOpLoadMemoryOperandsMaskIndex; + break; + case SpvOpStore: + first_mask_in_operand_index = kOpStoreMemoryOperandsMaskIndex; + break; + case SpvOpCopyMemory: + first_mask_in_operand_index = kOpCopyMemoryFirstMemoryOperandsMaskIndex; + break; + case SpvOpCopyMemorySized: + first_mask_in_operand_index = + kOpCopyMemorySizedFirstMemoryOperandsMaskIndex; + break; + default: + assert(false && "Unknown memory instruction."); + break; + } + // If we are looking for the input operand index of the first mask, return it. + if (mask_index == 0) { + return first_mask_in_operand_index; + } + assert(mask_index == 1 && "Memory operands mask index must be 0 or 1."); + + // We are looking for the input operand index of the second mask. This is a + // little complicated because, depending on the contents of the first mask, + // there may be some input operands separating the two masks. + uint32_t first_mask = + instruction.GetSingleWordInOperand(first_mask_in_operand_index); + + // Consider each bit that might have an associated extra input operand, and + // count how many there are expected to be. + uint32_t first_mask_extra_operand_count = 0; + for (auto mask_bit : + {SpvMemoryAccessAlignedMask, SpvMemoryAccessMakePointerAvailableMask, + SpvMemoryAccessMakePointerAvailableKHRMask, + SpvMemoryAccessMakePointerVisibleMask, + SpvMemoryAccessMakePointerVisibleKHRMask}) { + if (first_mask & mask_bit) { + first_mask_extra_operand_count++; + } + } + return first_mask_in_operand_index + first_mask_extra_operand_count + 1; +} + +bool TransformationSetMemoryOperandsMask:: + MultipleMemoryOperandMasksAreSupported(opt::IRContext* context) { + // TODO(afd): We capture the universal environments for which this loop + // control is definitely not supported. The check should be refined on + // demand for other target environments. + switch (context->grammar().target_env()) { + case SPV_ENV_UNIVERSAL_1_0: + case SPV_ENV_UNIVERSAL_1_1: + case SPV_ENV_UNIVERSAL_1_2: + case SPV_ENV_UNIVERSAL_1_3: + return false; + default: + return true; + } +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/transformation_set_memory_operands_mask.h b/third_party/spirv-tools/source/fuzz/transformation_set_memory_operands_mask.h new file mode 100644 index 0000000000..20ae145787 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_set_memory_operands_mask.h @@ -0,0 +1,76 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_TRANSFORMATION_SET_MEMORY_OPERANDS_MASK_H_ +#define SOURCE_FUZZ_TRANSFORMATION_SET_MEMORY_OPERANDS_MASK_H_ + +#include "source/fuzz/fact_manager.h" +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "source/fuzz/transformation.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace fuzz { + +class TransformationSetMemoryOperandsMask : public Transformation { + public: + explicit TransformationSetMemoryOperandsMask( + const protobufs::TransformationSetMemoryOperandsMask& message); + + TransformationSetMemoryOperandsMask( + const protobufs::InstructionDescriptor& memory_access_instruction, + uint32_t memory_operands_mask, uint32_t memory_operands_mask_index); + + // - |message_.memory_access_instruction| must describe a memory access + // instruction. + // - |message_.memory_operands_mask_index| must be suitable for this memory + // access instruction, e.g. it must be 0 in the case of OpLoad, and may be + // 1 in the case of OpCopyMemory if the SPIR-V version is 1.4 or higher. + // - |message_.memory_operands_mask| must be identical to the original memory + // operands mask, except that Volatile may be added, and Nontemporal may be + // toggled. + bool IsApplicable(opt::IRContext* context, + const FactManager& fact_manager) const override; + + // Replaces the operands mask identified by + // |message_.memory_operands_mask_index| in the instruction described by + // |message_.memory_access_instruction| with |message_.memory_operands_mask|, + // creating an input operand for the mask if no such operand was present. + void Apply(opt::IRContext* context, FactManager* fact_manager) const override; + + protobufs::Transformation ToMessage() const override; + + // Helper function that determines whether |instruction| is a memory + // instruction (e.g. OpLoad). + static bool IsMemoryAccess(const opt::Instruction& instruction); + + // Does the version of SPIR-V being used support multiple memory operand + // masks on relevant memory access instructions? + static bool MultipleMemoryOperandMasksAreSupported(opt::IRContext* context); + + // Helper function to get the input operand index associated with mask number + // |mask_index|. This is a bit tricky if there are multiple masks, because the + // index associated with the second mask depends on whether the first mask + // includes any flags such as Aligned that have corresponding operands. + static uint32_t GetInOperandIndexForMask(const opt::Instruction& instruction, + uint32_t mask_index); + + private: + protobufs::TransformationSetMemoryOperandsMask message_; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_TRANSFORMATION_SET_MEMORY_OPERANDS_MASK_H_ diff --git a/third_party/spirv-tools/source/fuzz/transformation_set_selection_control.cpp b/third_party/spirv-tools/source/fuzz/transformation_set_selection_control.cpp new file mode 100644 index 0000000000..ebabdef209 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_set_selection_control.cpp @@ -0,0 +1,60 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_set_selection_control.h" + +namespace spvtools { +namespace fuzz { + +TransformationSetSelectionControl::TransformationSetSelectionControl( + const spvtools::fuzz::protobufs::TransformationSetSelectionControl& message) + : message_(message) {} + +TransformationSetSelectionControl::TransformationSetSelectionControl( + uint32_t block_id, uint32_t selection_control) { + message_.set_block_id(block_id); + message_.set_selection_control(selection_control); +} + +bool TransformationSetSelectionControl::IsApplicable( + opt::IRContext* context, const FactManager& /*unused*/) const { + assert((message_.selection_control() == SpvSelectionControlMaskNone || + message_.selection_control() == SpvSelectionControlFlattenMask || + message_.selection_control() == SpvSelectionControlDontFlattenMask) && + "Selection control should never be set to something other than " + "'None', 'Flatten' or 'DontFlatten'"); + if (auto block = context->get_instr_block(message_.block_id())) { + if (auto merge_inst = block->GetMergeInst()) { + return merge_inst->opcode() == SpvOpSelectionMerge; + } + } + // Either the block did not exit, or did not end with OpSelectionMerge. + return false; +} + +void TransformationSetSelectionControl::Apply(opt::IRContext* context, + FactManager* /*unused*/) const { + context->get_instr_block(message_.block_id()) + ->GetMergeInst() + ->SetInOperand(1, {message_.selection_control()}); +} + +protobufs::Transformation TransformationSetSelectionControl::ToMessage() const { + protobufs::Transformation result; + *result.mutable_set_selection_control() = message_; + return result; +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/transformation_set_selection_control.h b/third_party/spirv-tools/source/fuzz/transformation_set_selection_control.h new file mode 100644 index 0000000000..19e0c3cfd8 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_set_selection_control.h @@ -0,0 +1,54 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_TRANSFORMATION_SET_SELECTION_CONTROL_H_ +#define SOURCE_FUZZ_TRANSFORMATION_SET_SELECTION_CONTROL_H_ + +#include "source/fuzz/fact_manager.h" +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "source/fuzz/transformation.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace fuzz { + +class TransformationSetSelectionControl : public Transformation { + public: + explicit TransformationSetSelectionControl( + const protobufs::TransformationSetSelectionControl& message); + + TransformationSetSelectionControl(uint32_t block_id, + uint32_t selection_control); + + // - |message_.block_id| must be a block containing an OpSelectionMerge + // instruction. + // - |message_.selection_control| must be one of None, Flatten or + // DontFlatten. + bool IsApplicable(opt::IRContext* context, + const FactManager& fact_manager) const override; + + // - The selection control operand of the OpSelectionMergeInstruction in + // |message_.block_id| is overwritten with |message_.selection_control|. + void Apply(opt::IRContext* context, FactManager* fact_manager) const override; + + protobufs::Transformation ToMessage() const override; + + private: + protobufs::TransformationSetSelectionControl message_; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_TRANSFORMATION_SET_SELECTION_CONTROL_H_ diff --git a/third_party/spirv-tools/source/fuzz/transformation_split_block.cpp b/third_party/spirv-tools/source/fuzz/transformation_split_block.cpp new file mode 100644 index 0000000000..fc5229edc9 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_split_block.cpp @@ -0,0 +1,135 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_split_block.h" + +#include + +#include "source/fuzz/fuzzer_util.h" +#include "source/fuzz/instruction_descriptor.h" +#include "source/util/make_unique.h" + +namespace spvtools { +namespace fuzz { + +TransformationSplitBlock::TransformationSplitBlock( + const spvtools::fuzz::protobufs::TransformationSplitBlock& message) + : message_(message) {} + +TransformationSplitBlock::TransformationSplitBlock( + const protobufs::InstructionDescriptor& instruction_to_split_before, + uint32_t fresh_id) { + *message_.mutable_instruction_to_split_before() = instruction_to_split_before; + message_.set_fresh_id(fresh_id); +} + +bool TransformationSplitBlock::IsApplicable( + opt::IRContext* context, const FactManager& /*unused*/) const { + if (!fuzzerutil::IsFreshId(context, message_.fresh_id())) { + // We require the id for the new block to be unused. + return false; + } + auto instruction_to_split_before = + FindInstruction(message_.instruction_to_split_before(), context); + if (!instruction_to_split_before) { + // The instruction describing the block we should split does not exist. + return false; + } + auto block_to_split = context->get_instr_block(instruction_to_split_before); + assert(block_to_split && + "We should not have managed to find the " + "instruction if it was not contained in a block."); + + if (block_to_split->IsLoopHeader()) { + // We cannot split a loop header block: back-edges would become invalid. + return false; + } + + auto split_before = fuzzerutil::GetIteratorForInstruction( + block_to_split, instruction_to_split_before); + assert(split_before != block_to_split->end() && + "At this point we know the" + " block split point exists."); + + if (split_before->PreviousNode() && + split_before->PreviousNode()->opcode() == SpvOpSelectionMerge) { + // We cannot split directly after a selection merge: this would separate + // the merge from its associated branch or switch operation. + return false; + } + if (split_before->opcode() == SpvOpVariable) { + // We cannot split directly after a variable; variables in a function + // must be contiguous in the entry block. + return false; + } + // We cannot split before an OpPhi unless the OpPhi has exactly one + // associated incoming edge. + return !(split_before->opcode() == SpvOpPhi && + split_before->NumInOperands() != 2); +} + +void TransformationSplitBlock::Apply(opt::IRContext* context, + FactManager* fact_manager) const { + opt::Instruction* instruction_to_split_before = + FindInstruction(message_.instruction_to_split_before(), context); + opt::BasicBlock* block_to_split = + context->get_instr_block(instruction_to_split_before); + auto split_before = fuzzerutil::GetIteratorForInstruction( + block_to_split, instruction_to_split_before); + assert(split_before != block_to_split->end() && + "If the transformation is applicable, we should have an " + "instruction to split on."); + + // We need to make sure the module's id bound is large enough to add the + // fresh id. + fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id()); + // Split the block. + auto new_bb = block_to_split->SplitBasicBlock(context, message_.fresh_id(), + split_before); + // The split does not automatically add a branch between the two parts of + // the original block, so we add one. + block_to_split->AddInstruction(MakeUnique( + context, SpvOpBranch, 0, 0, + std::initializer_list{opt::Operand( + spv_operand_type_t::SPV_OPERAND_TYPE_ID, {message_.fresh_id()})})); + // If we split before OpPhi instructions, we need to update their + // predecessor operand so that the block they used to be inside is now the + // predecessor. + new_bb->ForEachPhiInst([block_to_split](opt::Instruction* phi_inst) { + // The following assertion is a sanity check. It is guaranteed to hold + // if IsApplicable holds. + assert(phi_inst->NumInOperands() == 2 && + "We can only split a block before an OpPhi if block has exactly " + "one predecessor."); + phi_inst->SetInOperand(1, {block_to_split->id()}); + }); + + // If the block being split was dead, the new block arising from the split is + // also dead. + if (fact_manager->BlockIsDead(block_to_split->id())) { + fact_manager->AddFactBlockIsDead(message_.fresh_id()); + } + + // Invalidate all analyses + context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone); +} + +protobufs::Transformation TransformationSplitBlock::ToMessage() const { + protobufs::Transformation result; + *result.mutable_split_block() = message_; + return result; +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/transformation_split_block.h b/third_party/spirv-tools/source/fuzz/transformation_split_block.h new file mode 100644 index 0000000000..a193fc7b8f --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_split_block.h @@ -0,0 +1,63 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_TRANSFORMATION_SPLIT_BLOCK_H_ +#define SOURCE_FUZZ_TRANSFORMATION_SPLIT_BLOCK_H_ + +#include "source/fuzz/fact_manager.h" +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "source/fuzz/transformation.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace fuzz { + +class TransformationSplitBlock : public Transformation { + public: + explicit TransformationSplitBlock( + const protobufs::TransformationSplitBlock& message); + + TransformationSplitBlock( + const protobufs::InstructionDescriptor& instruction_to_split_before, + uint32_t fresh_id); + + // - |message_.base_instruction_id| must be the result id of an instruction + // 'base' in some block 'blk'. + // - 'blk' must contain an instruction 'inst' located |message_.offset| + // instructions after 'base' (if |message_.offset| = 0 then 'inst' = + // 'base'). + // - Splitting 'blk' at 'inst', so that all instructions from 'inst' onwards + // appear in a new block that 'blk' directly jumps to must be valid. + // - |message_.fresh_id| must not be used by the module. + bool IsApplicable(opt::IRContext* context, + const FactManager& fact_manager) const override; + + // - A new block with label |message_.fresh_id| is inserted right after 'blk' + // in program order. + // - All instructions of 'blk' from 'inst' onwards are moved into the new + // block. + // - 'blk' is made to jump unconditionally to the new block. + // - If 'blk' was dead, the new block is also dead. + void Apply(opt::IRContext* context, FactManager* fact_manager) const override; + + protobufs::Transformation ToMessage() const override; + + private: + protobufs::TransformationSplitBlock message_; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_TRANSFORMATION_SPLIT_BLOCK_H_ diff --git a/third_party/spirv-tools/source/fuzz/transformation_vector_shuffle.cpp b/third_party/spirv-tools/source/fuzz/transformation_vector_shuffle.cpp new file mode 100644 index 0000000000..e2d889d580 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_vector_shuffle.cpp @@ -0,0 +1,203 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_vector_shuffle.h" + +#include "source/fuzz/fuzzer_util.h" +#include "source/fuzz/instruction_descriptor.h" + +namespace spvtools { +namespace fuzz { + +TransformationVectorShuffle::TransformationVectorShuffle( + const spvtools::fuzz::protobufs::TransformationVectorShuffle& message) + : message_(message) {} + +TransformationVectorShuffle::TransformationVectorShuffle( + const protobufs::InstructionDescriptor& instruction_to_insert_before, + uint32_t fresh_id, uint32_t vector1, uint32_t vector2, + const std::vector& component) { + *message_.mutable_instruction_to_insert_before() = + instruction_to_insert_before; + message_.set_fresh_id(fresh_id); + message_.set_vector1(vector1); + message_.set_vector2(vector2); + for (auto a_component : component) { + message_.add_component(a_component); + } +} + +bool TransformationVectorShuffle::IsApplicable( + opt::IRContext* context, + const spvtools::fuzz::FactManager& /*unused*/) const { + // The fresh id must not already be in use. + if (!fuzzerutil::IsFreshId(context, message_.fresh_id())) { + return false; + } + // The instruction before which the shuffle will be inserted must exist. + auto instruction_to_insert_before = + FindInstruction(message_.instruction_to_insert_before(), context); + if (!instruction_to_insert_before) { + return false; + } + // The first vector must be an instruction with a type id + auto vector1_instruction = + context->get_def_use_mgr()->GetDef(message_.vector1()); + if (!vector1_instruction || !vector1_instruction->type_id()) { + return false; + } + // The second vector must be an instruction with a type id + auto vector2_instruction = + context->get_def_use_mgr()->GetDef(message_.vector2()); + if (!vector2_instruction || !vector2_instruction->type_id()) { + return false; + } + auto vector1_type = + context->get_type_mgr()->GetType(vector1_instruction->type_id()); + // The first vector instruction's type must actually be a vector type. + if (!vector1_type->AsVector()) { + return false; + } + auto vector2_type = + context->get_type_mgr()->GetType(vector2_instruction->type_id()); + // The second vector instruction's type must actually be a vector type. + if (!vector2_type->AsVector()) { + return false; + } + // The element types of the vectors must be the same. + if (vector1_type->AsVector()->element_type() != + vector2_type->AsVector()->element_type()) { + return false; + } + uint32_t combined_size = vector1_type->AsVector()->element_count() + + vector2_type->AsVector()->element_count(); + for (auto a_compoment : message_.component()) { + // 0xFFFFFFFF is used to represent an undefined component. Unless + // undefined, a component must be less than the combined size of the + // vectors. + if (a_compoment != 0xFFFFFFFF && a_compoment >= combined_size) { + return false; + } + } + // The module must already declare an appropriate type in which to store the + // result of the shuffle. + if (!GetResultTypeId(context, *vector1_type->AsVector()->element_type())) { + return false; + } + // Each of the vectors used in the shuffle must be available at the insertion + // point. + for (auto used_instruction : {vector1_instruction, vector2_instruction}) { + if (auto block = context->get_instr_block(used_instruction)) { + if (!context->GetDominatorAnalysis(block->GetParent()) + ->Dominates(used_instruction, instruction_to_insert_before)) { + return false; + } + } + } + + // It must be legitimate to insert an OpVectorShuffle before the identified + // instruction. + return fuzzerutil::CanInsertOpcodeBeforeInstruction( + SpvOpVectorShuffle, instruction_to_insert_before); +} + +void TransformationVectorShuffle::Apply( + opt::IRContext* context, spvtools::fuzz::FactManager* fact_manager) const { + // Make input operands for a shuffle instruction - these comprise the two + // vectors being shuffled, followed by the integer literal components. + opt::Instruction::OperandList shuffle_operands = { + {SPV_OPERAND_TYPE_ID, {message_.vector1()}}, + {SPV_OPERAND_TYPE_ID, {message_.vector2()}}}; + for (auto a_component : message_.component()) { + shuffle_operands.push_back( + {SPV_OPERAND_TYPE_LITERAL_INTEGER, {a_component}}); + } + + uint32_t result_type_id = GetResultTypeId( + context, *GetVectorType(context, message_.vector1())->element_type()); + + // Add a shuffle instruction right before the instruction identified by + // |message_.instruction_to_insert_before|. + FindInstruction(message_.instruction_to_insert_before(), context) + ->InsertBefore(MakeUnique( + context, SpvOpVectorShuffle, result_type_id, message_.fresh_id(), + shuffle_operands)); + fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id()); + context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone); + + // Add synonym facts relating the defined elements of the shuffle result to + // the vector components that they come from. + for (uint32_t component_index = 0; + component_index < static_cast(message_.component_size()); + component_index++) { + uint32_t component = message_.component(component_index); + if (component == 0xFFFFFFFF) { + // This component is undefined, so move on - but first note that the + // overall shuffle result cannot be synonymous with any vector. + continue; + } + + // This describes the element of the result vector associated with + // |component_index|. + protobufs::DataDescriptor descriptor_for_result_component = + MakeDataDescriptor(message_.fresh_id(), {component_index}); + + protobufs::DataDescriptor descriptor_for_source_component; + + // Get a data descriptor for the component of the input vector to which + // |component| refers. + if (component < + GetVectorType(context, message_.vector1())->element_count()) { + descriptor_for_source_component = + MakeDataDescriptor(message_.vector1(), {component}); + } else { + auto index_into_vector_2 = + component - + GetVectorType(context, message_.vector1())->element_count(); + assert(index_into_vector_2 < + GetVectorType(context, message_.vector2())->element_count() && + "Vector shuffle index is out of bounds."); + descriptor_for_source_component = + MakeDataDescriptor(message_.vector2(), {index_into_vector_2}); + } + + // Add a fact relating this input vector component with the associated + // result component. + fact_manager->AddFactDataSynonym(descriptor_for_result_component, + descriptor_for_source_component, context); + } +} + +protobufs::Transformation TransformationVectorShuffle::ToMessage() const { + protobufs::Transformation result; + *result.mutable_vector_shuffle() = message_; + return result; +} + +uint32_t TransformationVectorShuffle::GetResultTypeId( + opt::IRContext* context, const opt::analysis::Type& element_type) const { + opt::analysis::Vector result_type( + &element_type, static_cast(message_.component_size())); + return context->get_type_mgr()->GetId(&result_type); +} + +opt::analysis::Vector* TransformationVectorShuffle::GetVectorType( + opt::IRContext* context, uint32_t id_of_vector) { + return context->get_type_mgr() + ->GetType(context->get_def_use_mgr()->GetDef(id_of_vector)->type_id()) + ->AsVector(); +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/transformation_vector_shuffle.h b/third_party/spirv-tools/source/fuzz/transformation_vector_shuffle.h new file mode 100644 index 0000000000..81ed227039 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/transformation_vector_shuffle.h @@ -0,0 +1,82 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_TRANSFORMATION_VECTOR_SHUFFLE_H_ +#define SOURCE_FUZZ_TRANSFORMATION_VECTOR_SHUFFLE_H_ + +#include "source/fuzz/fact_manager.h" +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "source/fuzz/transformation.h" +#include "source/opt/ir_context.h" +#include "source/opt/types.h" + +namespace spvtools { +namespace fuzz { + +class TransformationVectorShuffle : public Transformation { + public: + explicit TransformationVectorShuffle( + const protobufs::TransformationVectorShuffle& message); + + TransformationVectorShuffle( + const protobufs::InstructionDescriptor& instruction_to_insert_before, + uint32_t fresh_id, uint32_t vector1, uint32_t vector2, + const std::vector& component); + + // - |message_.fresh_id| must not be in use + // - |message_.instruction_to_insert_before| must identify an instruction + // before which it is legitimate to insert an OpVectorShuffle + // - |message_.vector1| and |message_.vector2| must be instructions of vector + // type, and the element types of these vectors must be the same + // - Each element of |message_.component| must either be 0xFFFFFFFF + // (representing an undefined component), or must be less than the combined + // sizes of the input vectors + // - The module must already contain a vector type with the same element type + // as |message_.vector1| and |message_.vector2|, and with the size of + // |message_component| as its element count + bool IsApplicable(opt::IRContext* context, + const FactManager& fact_manager) const override; + + // Inserts an OpVectorShuffle instruction before + // |message_.instruction_to_insert_before|, shuffles vectors + // |message_.vector1| and |message_.vector2| using the indices provided by + // |message_.component|, into |message_.fresh_id|. Adds a fact to the fact + // manager recording the fact each element of |message_.fresh_id| is + // synonymous with the element of |message_.vector1| or |message_.vector2| + // from which it came (with undefined components being ignored). If the + // result vector is a contiguous sub-range of one of the input vectors, a + // fact is added to record that |message_.fresh_id| is synonymous with this + // sub-range. + void Apply(opt::IRContext* context, FactManager* fact_manager) const override; + + protobufs::Transformation ToMessage() const override; + + private: + // Returns a type id that already exists in |context| suitable for + // representing the result of the shuffle, where |element_type| is known to + // be the common element type of the vectors to which the shuffle is being + // applied. Returns 0 if no such id exists. + uint32_t GetResultTypeId(opt::IRContext* context, + const opt::analysis::Type& element_type) const; + + static opt::analysis::Vector* GetVectorType(opt::IRContext* context, + uint32_t id_of_vector); + + protobufs::TransformationVectorShuffle message_; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_TRANSFORMATION_VECTOR_SHUFFLE_H_ diff --git a/third_party/spirv-tools/source/fuzz/uniform_buffer_element_descriptor.cpp b/third_party/spirv-tools/source/fuzz/uniform_buffer_element_descriptor.cpp new file mode 100644 index 0000000000..90fd85e96f --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/uniform_buffer_element_descriptor.cpp @@ -0,0 +1,118 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/uniform_buffer_element_descriptor.h" + +#include + +namespace spvtools { +namespace fuzz { + +protobufs::UniformBufferElementDescriptor MakeUniformBufferElementDescriptor( + uint32_t descriptor_set, uint32_t binding, + std::vector&& indices) { + protobufs::UniformBufferElementDescriptor result; + result.set_descriptor_set(descriptor_set); + result.set_binding(binding); + for (auto index : indices) { + result.add_index(index); + } + return result; +} + +bool UniformBufferElementDescriptorEquals::operator()( + const protobufs::UniformBufferElementDescriptor* first, + const protobufs::UniformBufferElementDescriptor* second) const { + return first->descriptor_set() == second->descriptor_set() && + first->binding() == second->binding() && + first->index().size() == second->index().size() && + std::equal(first->index().begin(), first->index().end(), + second->index().begin()); +} + +opt::Instruction* FindUniformVariable( + const protobufs::UniformBufferElementDescriptor& + uniform_buffer_element_descriptor, + opt::IRContext* context, bool check_unique) { + opt::Instruction* result = nullptr; + + for (auto& inst : context->types_values()) { + // Consider all global variables with uniform storage class. + if (inst.opcode() != SpvOpVariable) { + continue; + } + if (inst.GetSingleWordInOperand(0) != SpvStorageClassUniform) { + continue; + } + + // Determine whether the variable is decorated with a descriptor set + // matching that in |uniform_buffer_element|. + bool descriptor_set_matches = false; + context->get_decoration_mgr()->ForEachDecoration( + inst.result_id(), SpvDecorationDescriptorSet, + [&descriptor_set_matches, &uniform_buffer_element_descriptor]( + const opt::Instruction& decoration_inst) { + const uint32_t kDescriptorSetOperandIndex = 2; + if (decoration_inst.GetSingleWordInOperand( + kDescriptorSetOperandIndex) == + uniform_buffer_element_descriptor.descriptor_set()) { + descriptor_set_matches = true; + } + }); + if (!descriptor_set_matches) { + // Descriptor set does not match. + continue; + } + + // Determine whether the variable is decorated with a binding matching that + // in |uniform_buffer_element|. + bool binding_matches = false; + context->get_decoration_mgr()->ForEachDecoration( + inst.result_id(), SpvDecorationBinding, + [&binding_matches, &uniform_buffer_element_descriptor]( + const opt::Instruction& decoration_inst) { + const uint32_t kBindingOperandIndex = 2; + if (decoration_inst.GetSingleWordInOperand(kBindingOperandIndex) == + uniform_buffer_element_descriptor.binding()) { + binding_matches = true; + } + }); + if (!binding_matches) { + // Binding does not match. + continue; + } + + // This instruction is a uniform variable with the right descriptor set and + // binding. + if (!check_unique) { + // If we aren't checking uniqueness, return it. + return &inst; + } + + if (result) { + // More than one uniform variable is decorated with the given descriptor + // set and binding. This means the fact is ambiguous. + return nullptr; + } + result = &inst; + } + + // We get here either if no match was found, or if |check_unique| holds and + // exactly one match was found. + assert(result == nullptr || check_unique); + return result; +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/source/fuzz/uniform_buffer_element_descriptor.h b/third_party/spirv-tools/source/fuzz/uniform_buffer_element_descriptor.h new file mode 100644 index 0000000000..f5d7320a26 --- /dev/null +++ b/third_party/spirv-tools/source/fuzz/uniform_buffer_element_descriptor.h @@ -0,0 +1,52 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_FUZZ_UNIFORM_BUFFER_ELEMENT_DESCRIPTOR_H_ +#define SOURCE_FUZZ_UNIFORM_BUFFER_ELEMENT_DESCRIPTOR_H_ + +#include + +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "source/opt/instruction.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace fuzz { + +// Factory method to create a uniform buffer element descriptor message from +// descriptor set and binding ids and a list of indices. +protobufs::UniformBufferElementDescriptor MakeUniformBufferElementDescriptor( + uint32_t descriptor_set, uint32_t binding, std::vector&& indices); + +// Equality function for uniform buffer element descriptors. +struct UniformBufferElementDescriptorEquals { + bool operator()( + const protobufs::UniformBufferElementDescriptor* first, + const protobufs::UniformBufferElementDescriptor* second) const; +}; + +// Returns a pointer to an OpVariable in |context| that is decorated with the +// descriptor set and binding associated with |uniform_buffer_element|. Returns +// nullptr if no such variable exists. If multiple such variables exist, a +// pointer to an arbitrary one of the associated instructions is returned if +// |check_unique| is false, and nullptr is returned if |check_unique| is true. +opt::Instruction* FindUniformVariable( + const protobufs::UniformBufferElementDescriptor& + uniform_buffer_element_descriptor, + opt::IRContext* context, bool check_unique); + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_UNIFORM_BUFFER_ELEMENT_DESCRIPTOR_H_ diff --git a/third_party/spirv-tools/source/id_descriptor.cpp b/third_party/spirv-tools/source/id_descriptor.cpp deleted file mode 100644 index d44ed672c2..0000000000 --- a/third_party/spirv-tools/source/id_descriptor.cpp +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright (c) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/id_descriptor.h" - -#include -#include - -#include "source/opcode.h" -#include "source/operand.h" - -namespace spvtools { -namespace { - -// Hashes an array of words. Order of words is important. -uint32_t HashU32Array(const std::vector& words) { - // The hash function is a sum of hashes of each word seeded by word index. - // Knuth's multiplicative hash is used to hash the words. - const uint32_t kKnuthMulHash = 2654435761; - uint32_t val = 0; - for (uint32_t i = 0; i < words.size(); ++i) { - val += (words[i] + i + 123) * kKnuthMulHash; - } - return val; -} - -} // namespace - -uint32_t IdDescriptorCollection::ProcessInstruction( - const spv_parsed_instruction_t& inst) { - if (!inst.result_id) return 0; - - assert(words_.empty()); - words_.push_back(inst.words[0]); - - for (size_t operand_index = 0; operand_index < inst.num_operands; - ++operand_index) { - const auto& operand = inst.operands[operand_index]; - if (spvIsIdType(operand.type)) { - const uint32_t id = inst.words[operand.offset]; - const auto it = id_to_descriptor_.find(id); - // Forward declared ids are not hashed. - if (it != id_to_descriptor_.end()) { - words_.push_back(it->second); - } - } else { - for (size_t operand_word_index = 0; - operand_word_index < operand.num_words; ++operand_word_index) { - words_.push_back(inst.words[operand.offset + operand_word_index]); - } - } - } - - uint32_t descriptor = - custom_hash_func_ ? custom_hash_func_(words_) : HashU32Array(words_); - if (descriptor == 0) descriptor = 1; - assert(descriptor); - - words_.clear(); - - const auto result = id_to_descriptor_.emplace(inst.result_id, descriptor); - assert(result.second); - (void)result; - return descriptor; -} - -} // namespace spvtools diff --git a/third_party/spirv-tools/source/id_descriptor.h b/third_party/spirv-tools/source/id_descriptor.h deleted file mode 100644 index add23343a1..0000000000 --- a/third_party/spirv-tools/source/id_descriptor.h +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (c) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_ID_DESCRIPTOR_H_ -#define SOURCE_ID_DESCRIPTOR_H_ - -#include -#include - -#include "spirv-tools/libspirv.hpp" - -namespace spvtools { - -using CustomHashFunc = std::function&)>; - -// Computes and stores id descriptors. -// -// Descriptors are computed as hash of all words in the instruction where ids -// were substituted with previously computed descriptors. -class IdDescriptorCollection { - public: - explicit IdDescriptorCollection( - CustomHashFunc custom_hash_func = CustomHashFunc()) - : custom_hash_func_(custom_hash_func) { - words_.reserve(16); - } - - // Computes descriptor for the result id of the given instruction and - // registers it in id_to_descriptor_. Returns the computed descriptor. - // This function needs to be sequentially called for every instruction in the - // module. - uint32_t ProcessInstruction(const spv_parsed_instruction_t& inst); - - // Returns a previously computed descriptor id. - uint32_t GetDescriptor(uint32_t id) const { - const auto it = id_to_descriptor_.find(id); - if (it == id_to_descriptor_.end()) return 0; - return it->second; - } - - private: - std::unordered_map id_to_descriptor_; - - std::function&)> custom_hash_func_; - - // Scratch buffer used for hashing. Class member to optimize on allocation. - std::vector words_; -}; - -} // namespace spvtools - -#endif // SOURCE_ID_DESCRIPTOR_H_ diff --git a/third_party/spirv-tools/source/libspirv.cpp b/third_party/spirv-tools/source/libspirv.cpp index cbbc4c9089..a1ed11d3fb 100644 --- a/third_party/spirv-tools/source/libspirv.cpp +++ b/third_party/spirv-tools/source/libspirv.cpp @@ -115,7 +115,7 @@ bool SpirvTools::Validate(const uint32_t* binary, } bool SpirvTools::Validate(const uint32_t* binary, const size_t binary_size, - const ValidatorOptions& options) const { + spv_validator_options options) const { spv_const_binary_t the_binary{binary, binary_size}; spv_diagnostic diagnostic = nullptr; bool valid = spvValidateWithOptions(impl_->context, options, &the_binary, @@ -128,4 +128,6 @@ bool SpirvTools::Validate(const uint32_t* binary, const size_t binary_size, return valid; } +bool SpirvTools::IsValid() const { return impl_->context != nullptr; } + } // namespace spvtools diff --git a/third_party/spirv-tools/source/link/CMakeLists.txt b/third_party/spirv-tools/source/link/CMakeLists.txt index 8ca4df39f7..d3083192c5 100644 --- a/third_party/spirv-tools/source/link/CMakeLists.txt +++ b/third_party/spirv-tools/source/link/CMakeLists.txt @@ -17,8 +17,10 @@ add_library(SPIRV-Tools-link spvtools_default_compile_options(SPIRV-Tools-link) target_include_directories(SPIRV-Tools-link - PUBLIC ${spirv-tools_SOURCE_DIR}/include - PUBLIC ${SPIRV_HEADER_INCLUDE_DIR} + PUBLIC + $ + $ + $ PRIVATE ${spirv-tools_BINARY_DIR} ) # We need the IR functionnalities from the optimizer @@ -29,8 +31,16 @@ set_property(TARGET SPIRV-Tools-link PROPERTY FOLDER "SPIRV-Tools libraries") spvtools_check_symbol_exports(SPIRV-Tools-link) if(ENABLE_SPIRV_TOOLS_INSTALL) - install(TARGETS SPIRV-Tools-link + install(TARGETS SPIRV-Tools-link EXPORT SPIRV-Tools-linkTargets RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) + export(EXPORT SPIRV-Tools-linkTargets FILE SPIRV-Tools-linkTargets.cmake) + + spvtools_config_package_dir(SPIRV-Tools-link PACKAGE_DIR) + install(EXPORT SPIRV-Tools-linkTargets FILE SPIRV-Tools-linkTargets.cmake + DESTINATION ${PACKAGE_DIR}) + + spvtools_generate_config_file(SPIRV-Tools-link) + install(FILES ${CMAKE_BINARY_DIR}/SPIRV-Tools-linkConfig.cmake DESTINATION ${PACKAGE_DIR}) endif(ENABLE_SPIRV_TOOLS_INSTALL) diff --git a/third_party/spirv-tools/source/link/linker.cpp b/third_party/spirv-tools/source/link/linker.cpp index f28b7595aa..da6f0a78c7 100644 --- a/third_party/spirv-tools/source/link/linker.cpp +++ b/third_party/spirv-tools/source/link/linker.cpp @@ -33,6 +33,7 @@ #include "source/opt/ir_loader.h" #include "source/opt/pass_manager.h" #include "source/opt/remove_duplicates_pass.h" +#include "source/opt/type_manager.h" #include "source/spirv_target_env.h" #include "source/util/make_unique.h" #include "spirv-tools/libspirv.hpp" @@ -40,14 +41,15 @@ namespace spvtools { namespace { -using opt::IRContext; using opt::Instruction; +using opt::IRContext; using opt::Module; -using opt::Operand; using opt::PassManager; using opt::RemoveDuplicatesPass; using opt::analysis::DecorationManager; using opt::analysis::DefUseManager; +using opt::analysis::Type; +using opt::analysis::TypeManager; // Stores various information about an imported or exported symbol. struct LinkageSymbolInfo { @@ -135,8 +137,6 @@ spv_result_t CheckImportExportCompatibility(const MessageConsumer& consumer, // TODO(pierremoreau): Linkage attributes applied by a group decoration are // currently not handled. (You could have a group being // applied to a single ID.) -// TODO(pierremoreau): Run a pass for removing dead instructions, for example -// OpName for prototypes of imported funcions. spv_result_t RemoveLinkageSpecificInstructions( const MessageConsumer& consumer, const LinkerOptions& options, const LinkageTable& linkings_to_do, DecorationManager* decoration_manager, @@ -324,6 +324,11 @@ spv_result_t MergeModules(const MessageConsumer& consumer, linked_module->AddDebug3Inst( std::unique_ptr(inst.Clone(linked_context))); + for (const auto& module : input_modules) + for (const auto& inst : module->ext_inst_debuginfo()) + linked_module->AddExtInstDebugInfo( + std::unique_ptr(inst.Clone(linked_context))); + // If the generated module uses SPIR-V 1.1 or higher, add an // OpModuleProcessed instruction about the linking step. if (linked_module->version() >= 0x10100) { @@ -472,14 +477,15 @@ spv_result_t CheckImportExportCompatibility(const MessageConsumer& consumer, opt::IRContext* context) { spv_position_t position = {}; - // Ensure th import and export types are the same. - const DefUseManager& def_use_manager = *context->get_def_use_mgr(); + // Ensure the import and export types are the same. const DecorationManager& decoration_manager = *context->get_decoration_mgr(); + const TypeManager& type_manager = *context->get_type_mgr(); for (const auto& linking_entry : linkings_to_do) { - if (!RemoveDuplicatesPass::AreTypesEqual( - *def_use_manager.GetDef(linking_entry.imported_symbol.type_id), - *def_use_manager.GetDef(linking_entry.exported_symbol.type_id), - context)) + Type* imported_symbol_type = + type_manager.GetType(linking_entry.imported_symbol.type_id); + Type* exported_symbol_type = + type_manager.GetType(linking_entry.exported_symbol.type_id); + if (!(*imported_symbol_type == *exported_symbol_type)) return DiagnosticStream(position, consumer, "", SPV_ERROR_INVALID_BINARY) << "Type mismatch on symbol \"" << linking_entry.imported_symbol.name @@ -528,24 +534,6 @@ spv_result_t RemoveLinkageSpecificInstructions( // TODO(pierremoreau): Remove FuncParamAttr decorations of imported // functions' return type. - // Remove FuncParamAttr decorations of imported functions' parameters. - // From the SPIR-V specification, Sec. 2.13: - // When resolving imported functions, the Function Control and all Function - // Parameter Attributes are taken from the function definition, and not - // from the function declaration. - for (const auto& linking_entry : linkings_to_do) { - for (const auto parameter_id : - linking_entry.imported_symbol.parameter_ids) { - decoration_manager->RemoveDecorationsFrom( - parameter_id, [](const Instruction& inst) { - return (inst.opcode() == SpvOpDecorate || - inst.opcode() == SpvOpMemberDecorate) && - inst.GetSingleWordInOperand(1u) == - SpvDecorationFuncParamAttr; - }); - } - } - // Remove prototypes of imported functions for (const auto& linking_entry : linkings_to_do) { for (auto func_iter = linked_context->module()->begin(); @@ -743,24 +731,34 @@ spv_result_t Link(const Context& context, const uint32_t* const* binaries, opt::Pass::Status pass_res = manager.Run(&linked_context); if (pass_res == opt::Pass::Status::Failure) return SPV_ERROR_INVALID_DATA; - // Phase 7: Rematch import variables/functions to export variables/functions - for (const auto& linking_entry : linkings_to_do) + // Phase 7: Remove all names and decorations of import variables/functions + for (const auto& linking_entry : linkings_to_do) { + linked_context.KillNamesAndDecorates(linking_entry.imported_symbol.id); + for (const auto parameter_id : + linking_entry.imported_symbol.parameter_ids) { + linked_context.KillNamesAndDecorates(parameter_id); + } + } + + // Phase 8: Rematch import variables/functions to export variables/functions + for (const auto& linking_entry : linkings_to_do) { linked_context.ReplaceAllUsesWith(linking_entry.imported_symbol.id, linking_entry.exported_symbol.id); + } - // Phase 8: Remove linkage specific instructions, such as import/export + // Phase 9: Remove linkage specific instructions, such as import/export // attributes, linkage capability, etc. if applicable res = RemoveLinkageSpecificInstructions(consumer, options, linkings_to_do, linked_context.get_decoration_mgr(), &linked_context); if (res != SPV_SUCCESS) return res; - // Phase 9: Compact the IDs used in the module + // Phase 10: Compact the IDs used in the module manager.AddPass(); pass_res = manager.Run(&linked_context); if (pass_res == opt::Pass::Status::Failure) return SPV_ERROR_INVALID_DATA; - // Phase 10: Output the module + // Phase 11: Output the module linked_context.module()->ToBinary(linked_binary, true); return SPV_SUCCESS; diff --git a/third_party/spirv-tools/source/opcode.cpp b/third_party/spirv-tools/source/opcode.cpp index af34b64605..7f91a0ffd4 100644 --- a/third_party/spirv-tools/source/opcode.cpp +++ b/third_party/spirv-tools/source/opcode.cpp @@ -97,6 +97,7 @@ spv_result_t spvOpcodeTableNameLookup(spv_target_env env, // preferable but the table requires sorting on the Opcode name, but it's // static const initialized and matches the order of the spec. const size_t nameLength = strlen(name); + const auto version = spvVersionForTargetEnv(env); for (uint64_t opcodeIndex = 0; opcodeIndex < table->count; ++opcodeIndex) { const spv_opcode_desc_t& entry = table->entries[opcodeIndex]; // We considers the current opcode as available as long as @@ -107,7 +108,7 @@ spv_result_t spvOpcodeTableNameLookup(spv_target_env env, // Note that the second rule assumes the extension enabling this instruction // is indeed requested in the SPIR-V code; checking that should be // validator's work. - if ((spvVersionForTargetEnv(env) >= entry.minVersion || + if (((version >= entry.minVersion && version <= entry.lastVersion) || entry.numExtensions > 0u || entry.numCapabilities > 0u) && nameLength == strlen(entry.name) && !strncmp(name, entry.name, nameLength)) { @@ -130,8 +131,8 @@ spv_result_t spvOpcodeTableValueLookup(spv_target_env env, const auto beg = table->entries; const auto end = table->entries + table->count; - spv_opcode_desc_t needle = {"", opcode, 0, nullptr, 0, {}, - false, false, 0, nullptr, ~0u}; + spv_opcode_desc_t needle = {"", opcode, 0, nullptr, 0, {}, + false, false, 0, nullptr, ~0u, ~0u}; auto comp = [](const spv_opcode_desc_t& lhs, const spv_opcode_desc_t& rhs) { return lhs.opcode < rhs.opcode; @@ -142,6 +143,7 @@ spv_result_t spvOpcodeTableValueLookup(spv_target_env env, // which means they can have different minimal version requirements. // Assumes the underlying table is already sorted ascendingly according to // opcode value. + const auto version = spvVersionForTargetEnv(env); for (auto it = std::lower_bound(beg, end, needle, comp); it != end && it->opcode == opcode; ++it) { // We considers the current opcode as available as long as @@ -152,7 +154,7 @@ spv_result_t spvOpcodeTableValueLookup(spv_target_env env, // Note that the second rule assumes the extension enabling this instruction // is indeed requested in the SPIR-V code; checking that should be // validator's work. - if (spvVersionForTargetEnv(env) >= it->minVersion || + if ((version >= it->minVersion && version <= it->lastVersion) || it->numExtensions > 0u || it->numCapabilities > 0u) { *pEntry = it; return SPV_SUCCESS; @@ -182,8 +184,8 @@ void spvInstructionCopy(const uint32_t* words, const SpvOp opcode, const char* spvOpcodeString(const SpvOp opcode) { const auto beg = kOpcodeTableEntries; const auto end = kOpcodeTableEntries + ARRAY_SIZE(kOpcodeTableEntries); - spv_opcode_desc_t needle = {"", opcode, 0, nullptr, 0, {}, - false, false, 0, nullptr, ~0u}; + spv_opcode_desc_t needle = {"", opcode, 0, nullptr, 0, {}, + false, false, 0, nullptr, ~0u, ~0u}; auto comp = [](const spv_opcode_desc_t& lhs, const spv_opcode_desc_t& rhs) { return lhs.opcode < rhs.opcode; }; @@ -260,6 +262,7 @@ int32_t spvOpcodeIsComposite(const SpvOp opcode) { case SpvOpTypeMatrix: case SpvOpTypeArray: case SpvOpTypeStruct: + case SpvOpTypeCooperativeMatrixNV: return true; default: return false; @@ -324,6 +327,8 @@ int32_t spvOpcodeGeneratesType(SpvOp op) { case SpvOpTypePipe: case SpvOpTypePipeStorage: case SpvOpTypeNamedBarrier: + case SpvOpTypeAccelerationStructureNV: + case SpvOpTypeCooperativeMatrixNV: return true; default: // In particular, OpTypeForwardPointer does not generate a type, @@ -390,10 +395,9 @@ bool spvOpcodeIsBranch(SpvOp opcode) { } } -bool spvOpcodeIsAtomicOp(const SpvOp opcode) { +bool spvOpcodeIsAtomicWithLoad(const SpvOp opcode) { switch (opcode) { case SpvOpAtomicLoad: - case SpvOpAtomicStore: case SpvOpAtomicExchange: case SpvOpAtomicCompareExchange: case SpvOpAtomicCompareExchangeWeak: @@ -409,13 +413,17 @@ bool spvOpcodeIsAtomicOp(const SpvOp opcode) { case SpvOpAtomicOr: case SpvOpAtomicXor: case SpvOpAtomicFlagTestAndSet: - case SpvOpAtomicFlagClear: return true; default: return false; } } +bool spvOpcodeIsAtomicOp(const SpvOp opcode) { + return (spvOpcodeIsAtomicWithLoad(opcode) || opcode == SpvOpAtomicStore || + opcode == SpvOpAtomicFlagClear); +} + bool spvOpcodeIsReturn(SpvOp opcode) { switch (opcode) { case SpvOpReturn: @@ -583,3 +591,51 @@ bool spvOpcodeIsScalarizable(SpvOp opcode) { return false; } } + +bool spvOpcodeIsDebug(SpvOp opcode) { + switch (opcode) { + case SpvOpName: + case SpvOpMemberName: + case SpvOpSource: + case SpvOpSourceContinued: + case SpvOpSourceExtension: + case SpvOpString: + case SpvOpLine: + case SpvOpNoLine: + return true; + default: + return false; + } +} + +std::vector spvOpcodeMemorySemanticsOperandIndices(SpvOp opcode) { + switch (opcode) { + case SpvOpMemoryBarrier: + return {1}; + case SpvOpAtomicStore: + case SpvOpControlBarrier: + case SpvOpAtomicFlagClear: + case SpvOpMemoryNamedBarrier: + return {2}; + case SpvOpAtomicLoad: + case SpvOpAtomicExchange: + case SpvOpAtomicIIncrement: + case SpvOpAtomicIDecrement: + case SpvOpAtomicIAdd: + case SpvOpAtomicISub: + case SpvOpAtomicSMin: + case SpvOpAtomicUMin: + case SpvOpAtomicSMax: + case SpvOpAtomicUMax: + case SpvOpAtomicAnd: + case SpvOpAtomicOr: + case SpvOpAtomicXor: + case SpvOpAtomicFlagTestAndSet: + return {4}; + case SpvOpAtomicCompareExchange: + case SpvOpAtomicCompareExchangeWeak: + return {4, 5}; + default: + return {}; + } +} diff --git a/third_party/spirv-tools/source/opcode.h b/third_party/spirv-tools/source/opcode.h index 5643a64c8b..ed64f1b5ab 100644 --- a/third_party/spirv-tools/source/opcode.h +++ b/third_party/spirv-tools/source/opcode.h @@ -100,6 +100,10 @@ bool spvOpcodeIsDecoration(const SpvOp opcode); // function only considers core instructions. bool spvOpcodeIsLoad(const SpvOp opcode); +// Returns true if the opcode is an atomic operation that uses the original +// value. +bool spvOpcodeIsAtomicWithLoad(const SpvOp opcode); + // Returns true if the opcode is an atomic operation. bool spvOpcodeIsAtomicOp(const SpvOp opcode); @@ -125,4 +129,12 @@ bool spvOpcodeIsNonUniformGroupOperation(SpvOp opcode); // Returns true if the opcode with vector inputs could be divided into a series // of independent scalar operations that would give the same result. bool spvOpcodeIsScalarizable(SpvOp opcode); + +// Returns true if the given opcode is a debug instruction. +bool spvOpcodeIsDebug(SpvOp opcode); + +// Returns a vector containing the indices of the memory semantics +// operands for |opcode|. +std::vector spvOpcodeMemorySemanticsOperandIndices(SpvOp opcode); + #endif // SOURCE_OPCODE_H_ diff --git a/third_party/spirv-tools/source/operand.cpp b/third_party/spirv-tools/source/operand.cpp index c97b13fc65..304260668d 100644 --- a/third_party/spirv-tools/source/operand.cpp +++ b/third_party/spirv-tools/source/operand.cpp @@ -16,8 +16,11 @@ #include #include + #include +#include "DebugInfo.h" +#include "OpenCLDebugInfo100.h" #include "source/macro.h" #include "source/spirv_constant.h" #include "source/spirv_target_env.h" @@ -28,6 +31,7 @@ // per-item basis. https://github.com/KhronosGroup/SPIRV-Tools/issues/1195 #include "operand.kinds-unified1.inc" +#include "spirv-tools/libspirv.h" static const spv_operand_table_t kOperandTable = { ARRAY_SIZE(pygen_variable_OperandInfoTable), @@ -50,6 +54,7 @@ spv_result_t spvOperandTableNameLookup(spv_target_env env, if (!table) return SPV_ERROR_INVALID_TABLE; if (!name || !pEntry) return SPV_ERROR_INVALID_POINTER; + const auto version = spvVersionForTargetEnv(env); for (uint64_t typeIndex = 0; typeIndex < table->count; ++typeIndex) { const auto& group = table->types[typeIndex]; if (type != group.type) continue; @@ -64,7 +69,7 @@ spv_result_t spvOperandTableNameLookup(spv_target_env env, // Note that the second rule assumes the extension enabling this operand // is indeed requested in the SPIR-V code; checking that should be // validator's work. - if ((spvVersionForTargetEnv(env) >= entry.minVersion || + if (((version >= entry.minVersion && version <= entry.lastVersion) || entry.numExtensions > 0u || entry.numCapabilities > 0u) && nameLength == strlen(entry.name) && !strncmp(entry.name, name, nameLength)) { @@ -85,7 +90,7 @@ spv_result_t spvOperandTableValueLookup(spv_target_env env, if (!table) return SPV_ERROR_INVALID_TABLE; if (!pEntry) return SPV_ERROR_INVALID_POINTER; - spv_operand_desc_t needle = {"", value, 0, nullptr, 0, nullptr, {}, ~0u}; + spv_operand_desc_t needle = {"", value, 0, nullptr, 0, nullptr, {}, ~0u, ~0u}; auto comp = [](const spv_operand_desc_t& lhs, const spv_operand_desc_t& rhs) { return lhs.value < rhs.value; @@ -108,6 +113,7 @@ spv_result_t spvOperandTableValueLookup(spv_target_env env, // requirements. // Assumes the underlying table is already sorted ascendingly according to // opcode value. + const auto version = spvVersionForTargetEnv(env); for (auto it = std::lower_bound(beg, end, needle, comp); it != end && it->value == value; ++it) { // We consider the current operand as available as long as @@ -119,7 +125,7 @@ spv_result_t spvOperandTableValueLookup(spv_target_env env, // Note that the second rule assumes the extension enabling this operand // is indeed requested in the SPIR-V code; checking that should be // validator's work. - if (spvVersionForTargetEnv(env) >= it->minVersion || + if ((version >= it->minVersion && version <= it->lastVersion) || it->numExtensions > 0u || it->numCapabilities > 0u) { *pEntry = it; return SPV_SUCCESS; @@ -225,6 +231,18 @@ const char* spvOperandTypeStr(spv_operand_type_t type) { return "debug type qualifier"; case SPV_OPERAND_TYPE_DEBUG_OPERATION: return "debug operation"; + case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_INFO_FLAGS: + return "OpenCL.DebugInfo.100 debug info flags"; + case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_BASE_TYPE_ATTRIBUTE_ENCODING: + return "OpenCL.DebugInfo.100 debug base type encoding"; + case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_COMPOSITE_TYPE: + return "OpenCL.DebugInfo.100 debug composite type"; + case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_TYPE_QUALIFIER: + return "OpenCL.DebugInfo.100 debug type qualifier"; + case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_OPERATION: + return "OpenCL.DebugInfo.100 debug operation"; + case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_IMPORTED_ENTITY: + return "OpenCL.DebugInfo.100 debug imported entity"; // The next values are for values returned from an instruction, not actually // an operand. So the specific strings don't matter. But let's add them @@ -309,6 +327,11 @@ bool spvOperandIsConcrete(spv_operand_type_t type) { case SPV_OPERAND_TYPE_DEBUG_COMPOSITE_TYPE: case SPV_OPERAND_TYPE_DEBUG_TYPE_QUALIFIER: case SPV_OPERAND_TYPE_DEBUG_OPERATION: + case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_BASE_TYPE_ATTRIBUTE_ENCODING: + case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_COMPOSITE_TYPE: + case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_TYPE_QUALIFIER: + case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_OPERATION: + case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_IMPORTED_ENTITY: return true; default: break; @@ -325,6 +348,7 @@ bool spvOperandIsConcreteMask(spv_operand_type_t type) { case SPV_OPERAND_TYPE_FUNCTION_CONTROL: case SPV_OPERAND_TYPE_MEMORY_ACCESS: case SPV_OPERAND_TYPE_DEBUG_INFO_FLAGS: + case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_INFO_FLAGS: return true; default: break; @@ -411,6 +435,21 @@ bool spvIsIdType(spv_operand_type_t type) { } } +bool spvIsInIdType(spv_operand_type_t type) { + if (!spvIsIdType(type)) { + // If it is not an ID it cannot be an input ID. + return false; + } + switch (type) { + // Blacklist non-input IDs. + case SPV_OPERAND_TYPE_TYPE_ID: + case SPV_OPERAND_TYPE_RESULT_ID: + return false; + default: + return true; + } +} + std::function spvOperandCanBeForwardDeclaredFunction( SpvOp opcode) { std::function out; @@ -466,9 +505,46 @@ std::function spvOperandCanBeForwardDeclaredFunction( case SpvOpTypeForwardPointer: out = [](unsigned index) { return index == 0; }; break; + case SpvOpTypeArray: + out = [](unsigned index) { return index == 1; }; + break; default: out = [](unsigned) { return false; }; break; } return out; } + +std::function spvDbgInfoExtOperandCanBeForwardDeclaredFunction( + spv_ext_inst_type_t ext_type, uint32_t key) { + // TODO(https://gitlab.khronos.org/spirv/SPIR-V/issues/532): Forward + // references for debug info instructions are still in discussion. We must + // update the following lines of code when we conclude the spec. + std::function out; + if (ext_type == SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100) { + switch (OpenCLDebugInfo100Instructions(key)) { + case OpenCLDebugInfo100DebugFunction: + out = [](unsigned index) { return index == 13; }; + break; + case OpenCLDebugInfo100DebugTypeComposite: + out = [](unsigned index) { return index >= 13; }; + break; + default: + out = [](unsigned) { return false; }; + break; + } + } else { + switch (DebugInfoInstructions(key)) { + case DebugInfoDebugFunction: + out = [](unsigned index) { return index == 13; }; + break; + case DebugInfoDebugTypeComposite: + out = [](unsigned index) { return index >= 12; }; + break; + default: + out = [](unsigned) { return false; }; + break; + } + } + return out; +} diff --git a/third_party/spirv-tools/source/operand.h b/third_party/spirv-tools/source/operand.h index 76f16f7ae5..7c73c6f560 100644 --- a/third_party/spirv-tools/source/operand.h +++ b/third_party/spirv-tools/source/operand.h @@ -131,6 +131,9 @@ spv_operand_pattern_t spvAlternatePatternFollowingImmediate( // Is the operand an ID? bool spvIsIdType(spv_operand_type_t type); +// Is the operand an input ID? +bool spvIsInIdType(spv_operand_type_t type); + // Takes the opcode of an instruction and returns // a function object that will return true if the index // of the operand can be forward declared. This function will @@ -138,4 +141,11 @@ bool spvIsIdType(spv_operand_type_t type); std::function spvOperandCanBeForwardDeclaredFunction( SpvOp opcode); +// Takes the instruction key of a debug info extension instruction +// and returns a function object that will return true if the index +// of the operand can be forward declared. This function will +// used in the SSA validation stage of the pipeline +std::function spvDbgInfoExtOperandCanBeForwardDeclaredFunction( + spv_ext_inst_type_t ext_type, uint32_t key); + #endif // SOURCE_OPERAND_H_ diff --git a/third_party/spirv-tools/source/opt/CMakeLists.txt b/third_party/spirv-tools/source/opt/CMakeLists.txt index 83f92fe886..0f719cb908 100644 --- a/third_party/spirv-tools/source/opt/CMakeLists.txt +++ b/third_party/spirv-tools/source/opt/CMakeLists.txt @@ -11,43 +11,56 @@ # 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. -add_library(SPIRV-Tools-opt +set(SPIRV_TOOLS_OPT_SOURCES aggressive_dead_code_elim_pass.h + amd_ext_to_khr.h basic_block.h block_merge_pass.h + block_merge_util.h build_module.h ccp_pass.h cfg_cleanup_pass.h cfg.h + code_sink.h combine_access_chains.h - common_uniform_elim_pass.h compact_ids_pass.h composite.h const_folding_rules.h constants.h + convert_to_half_pass.h copy_prop_arrays.h dead_branch_elim_pass.h dead_insert_elim_pass.h dead_variable_elimination.h + decompose_initialized_variables_pass.h decoration_manager.h def_use_manager.h + desc_sroa.h dominator_analysis.h dominator_tree.h eliminate_dead_constant_pass.h eliminate_dead_functions_pass.h + eliminate_dead_functions_util.h + eliminate_dead_members_pass.h feature_manager.h + fix_storage_class.h flatten_decoration_pass.h fold.h folding_rules.h fold_spec_constant_op_and_composite_pass.h freeze_spec_constant_value_pass.h function.h + generate_webgpu_initializers_pass.h + graphics_robust_access_pass.h if_conversion.h inline_exhaustive_pass.h inline_opaque_pass.h inline_pass.h + inst_bindless_check_pass.h + inst_buff_addr_check_pass.h instruction.h instruction_list.h + instrument_pass.h ir_builder.h ir_context.h ir_loader.h @@ -56,7 +69,6 @@ add_library(SPIRV-Tools-opt local_redundancy_elimination.h local_single_block_elim_pass.h local_single_store_elim_pass.h - local_ssa_elim_pass.h log.h loop_dependence.h loop_descriptor.h @@ -75,11 +87,13 @@ add_library(SPIRV-Tools-opt pass.h pass_manager.h private_to_local_pass.h + process_lines_pass.h propagator.h reduce_load_size.h redundancy_elimination.h reflect.h register_pressure.h + relax_float_ops_pass.h remove_duplicates_pass.h replace_invalid_opc.h scalar_analysis.h @@ -87,62 +101,80 @@ add_library(SPIRV-Tools-opt scalar_replacement_pass.h set_spec_constant_default_value_pass.h simplification_pass.h + split_invalid_unreachable_pass.h ssa_rewrite_pass.h strength_reduction_pass.h + strip_atomic_counter_memory_pass.h strip_debug_info_pass.h strip_reflect_info_pass.h + struct_cfg_analysis.h tree_iterator.h type_manager.h types.h unify_const_pass.h + upgrade_memory_model.h value_number_table.h vector_dce.h workaround1209.h + wrap_opkill.h aggressive_dead_code_elim_pass.cpp + amd_ext_to_khr.cpp basic_block.cpp block_merge_pass.cpp + block_merge_util.cpp build_module.cpp ccp_pass.cpp cfg_cleanup_pass.cpp cfg.cpp + code_sink.cpp combine_access_chains.cpp - common_uniform_elim_pass.cpp compact_ids_pass.cpp composite.cpp const_folding_rules.cpp constants.cpp + convert_to_half_pass.cpp copy_prop_arrays.cpp dead_branch_elim_pass.cpp dead_insert_elim_pass.cpp dead_variable_elimination.cpp + decompose_initialized_variables_pass.cpp decoration_manager.cpp def_use_manager.cpp + desc_sroa.cpp dominator_analysis.cpp dominator_tree.cpp eliminate_dead_constant_pass.cpp eliminate_dead_functions_pass.cpp + eliminate_dead_functions_util.cpp + eliminate_dead_members_pass.cpp feature_manager.cpp + fix_storage_class.cpp flatten_decoration_pass.cpp fold.cpp folding_rules.cpp fold_spec_constant_op_and_composite_pass.cpp freeze_spec_constant_value_pass.cpp function.cpp + graphics_robust_access_pass.cpp + generate_webgpu_initializers_pass.cpp if_conversion.cpp inline_exhaustive_pass.cpp inline_opaque_pass.cpp inline_pass.cpp + inst_bindless_check_pass.cpp + inst_buff_addr_check_pass.cpp instruction.cpp instruction_list.cpp + instrument_pass.cpp ir_context.cpp ir_loader.cpp + legalize_vector_shuffle_pass.cpp licm_pass.cpp local_access_chain_convert_pass.cpp local_redundancy_elimination.cpp local_single_block_elim_pass.cpp local_single_store_elim_pass.cpp - local_ssa_elim_pass.cpp loop_dependence.cpp loop_dependence_helpers.cpp loop_descriptor.cpp @@ -160,10 +192,12 @@ add_library(SPIRV-Tools-opt pass.cpp pass_manager.cpp private_to_local_pass.cpp + process_lines_pass.cpp propagator.cpp reduce_load_size.cpp redundancy_elimination.cpp register_pressure.cpp + relax_float_ops_pass.cpp remove_duplicates_pass.cpp replace_invalid_opc.cpp scalar_analysis.cpp @@ -171,22 +205,38 @@ add_library(SPIRV-Tools-opt scalar_replacement_pass.cpp set_spec_constant_default_value_pass.cpp simplification_pass.cpp + split_invalid_unreachable_pass.cpp ssa_rewrite_pass.cpp strength_reduction_pass.cpp + strip_atomic_counter_memory_pass.cpp strip_debug_info_pass.cpp strip_reflect_info_pass.cpp + struct_cfg_analysis.cpp type_manager.cpp types.cpp unify_const_pass.cpp + upgrade_memory_model.cpp value_number_table.cpp vector_dce.cpp workaround1209.cpp + wrap_opkill.cpp ) +if(MSVC) + # Enable parallel builds across four cores for this lib + add_definitions(/MP4) +endif() + +spvtools_pch(SPIRV_TOOLS_OPT_SOURCES pch_source_opt) + +add_library(SPIRV-Tools-opt ${SPIRV_TOOLS_OPT_SOURCES}) + spvtools_default_compile_options(SPIRV-Tools-opt) target_include_directories(SPIRV-Tools-opt - PUBLIC ${spirv-tools_SOURCE_DIR}/include - PUBLIC ${SPIRV_HEADER_INCLUDE_DIR} + PUBLIC + $ + $ + $ PRIVATE ${spirv-tools_BINARY_DIR} ) # We need the assembling and disassembling functionalities in the main library. @@ -197,9 +247,16 @@ set_property(TARGET SPIRV-Tools-opt PROPERTY FOLDER "SPIRV-Tools libraries") spvtools_check_symbol_exports(SPIRV-Tools-opt) if(ENABLE_SPIRV_TOOLS_INSTALL) - install(TARGETS SPIRV-Tools-opt + install(TARGETS SPIRV-Tools-opt EXPORT SPIRV-Tools-optTargets RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) + export(EXPORT SPIRV-Tools-optTargets FILE SPIRV-Tools-optTargets.cmake) + + spvtools_config_package_dir(SPIRV-Tools-opt PACKAGE_DIR) + install(EXPORT SPIRV-Tools-optTargets FILE SPIRV-Tools-optTargets.cmake + DESTINATION ${PACKAGE_DIR}) + + spvtools_generate_config_file(SPIRV-Tools-opt) + install(FILES ${CMAKE_BINARY_DIR}/SPIRV-Tools-optConfig.cmake DESTINATION ${PACKAGE_DIR}) endif(ENABLE_SPIRV_TOOLS_INSTALL) - diff --git a/third_party/spirv-tools/source/opt/aggressive_dead_code_elim_pass.cpp b/third_party/spirv-tools/source/opt/aggressive_dead_code_elim_pass.cpp index faf278aa62..761ff7c336 100644 --- a/third_party/spirv-tools/source/opt/aggressive_dead_code_elim_pass.cpp +++ b/third_party/spirv-tools/source/opt/aggressive_dead_code_elim_pass.cpp @@ -24,6 +24,7 @@ #include "source/latest_version_glsl_std_450_header.h" #include "source/opt/iterator.h" #include "source/opt/reflect.h" +#include "source/spirv_constant.h" namespace spvtools { namespace opt { @@ -142,8 +143,9 @@ bool AggressiveDCEPass::AllExtensionsSupported() const { bool AggressiveDCEPass::IsDead(Instruction* inst) { if (IsLive(inst)) return false; - if (inst->IsBranch() && !IsStructuredHeader(context()->get_instr_block(inst), - nullptr, nullptr, nullptr)) + if ((inst->IsBranch() || inst->opcode() == SpvOpUnreachable) && + !IsStructuredHeader(context()->get_instr_block(inst), nullptr, nullptr, + nullptr)) return false; return true; } @@ -195,6 +197,7 @@ bool AggressiveDCEPass::IsStructuredHeader(BasicBlock* bp, void AggressiveDCEPass::ComputeBlock2HeaderMaps( std::list& structuredOrder) { block2headerBranch_.clear(); + header2nextHeaderBranch_.clear(); branch2merge_.clear(); structured_order_index_.clear(); std::stack currentHeaderBranch; @@ -217,8 +220,10 @@ void AggressiveDCEPass::ComputeBlock2HeaderMaps( uint32_t mergeBlockId; bool is_header = IsStructuredHeader(*bi, &mergeInst, &branchInst, &mergeBlockId); + // Map header block to next enclosing header. + if (is_header) header2nextHeaderBranch_[*bi] = currentHeaderBranch.top(); // If this is a loop header, update state first so the block will map to - // the loop. + // itself. if (is_header && mergeInst->opcode() == SpvOpLoopMerge) { currentHeaderBranch.push(branchInst); branch2merge_[branchInst] = mergeInst; @@ -380,7 +385,8 @@ bool AggressiveDCEPass::AggressiveDCE(Function* func) { } break; case SpvOpSwitch: case SpvOpBranch: - case SpvOpBranchConditional: { + case SpvOpBranchConditional: + case SpvOpUnreachable: { if (assume_branches_live.top()) { AddToWorklist(&*ii); } @@ -427,24 +433,30 @@ bool AggressiveDCEPass::AggressiveDCE(Function* func) { AddToWorklist(get_def_use_mgr()->GetDef(liveInst->type_id())); } // If in a structured if or loop construct, add the controlling - // conditional branch and its merge. Any containing control construct - // is marked live when the merge and branch are processed out of the - // worklist. + // conditional branch and its merge. BasicBlock* blk = context()->get_instr_block(liveInst); Instruction* branchInst = block2headerBranch_[blk]; if (branchInst != nullptr) { AddToWorklist(branchInst); Instruction* mergeInst = branch2merge_[branchInst]; AddToWorklist(mergeInst); - AddBreaksAndContinuesToWorklist(mergeInst); + } + // If the block is a header, add the next outermost controlling + // conditional branch and its merge. + Instruction* nextBranchInst = header2nextHeaderBranch_[blk]; + if (nextBranchInst != nullptr) { + AddToWorklist(nextBranchInst); + Instruction* mergeInst = branch2merge_[nextBranchInst]; + AddToWorklist(mergeInst); } // If local load, add all variable's stores if variable not already live - if (liveInst->opcode() == SpvOpLoad) { + if (liveInst->opcode() == SpvOpLoad || liveInst->IsAtomicWithLoad()) { uint32_t varId; (void)GetPtr(liveInst, &varId); if (varId != 0) { ProcessLoad(varId); } + // Process memory copies like loads } else if (liveInst->opcode() == SpvOpCopyMemory || liveInst->opcode() == SpvOpCopyMemorySized) { uint32_t varId; @@ -453,6 +465,10 @@ bool AggressiveDCEPass::AggressiveDCE(Function* func) { if (varId != 0) { ProcessLoad(varId); } + // If merge, add other branches that are part of its control structure + } else if (liveInst->opcode() == SpvOpLoopMerge || + liveInst->opcode() == SpvOpSelectionMerge) { + AddBreaksAndContinuesToWorklist(liveInst); // If function call, treat as if it loads from all pointer arguments } else if (liveInst->opcode() == SpvOpFunctionCall) { liveInst->ForEachInId([this](const uint32_t* iid) { @@ -474,6 +490,28 @@ bool AggressiveDCEPass::AggressiveDCE(Function* func) { ProcessLoad(varId); } } + + // Add OpDecorateId instructions that apply to this instruction to the work + // list. We use the decoration manager to look through the group + // decorations to get to the OpDecorate* instructions themselves. + auto decorations = + get_decoration_mgr()->GetDecorationsFor(liveInst->result_id(), false); + for (Instruction* dec : decorations) { + // We only care about OpDecorateId instructions because the are the only + // decorations that will reference an id that will have to be kept live + // because of that use. + if (dec->opcode() != SpvOpDecorateId) { + continue; + } + if (dec->GetSingleWordInOperand(1) == + SpvDecorationHlslCounterBufferGOOGLE) { + // These decorations should not force the use id to be live. It will be + // removed if either the target or the in operand are dead. + continue; + } + AddToWorklist(dec); + } + worklist_.pop(); } @@ -498,6 +536,26 @@ bool AggressiveDCEPass::AggressiveDCE(Function* func) { AddBranch(mergeBlockId, *bi); for (++bi; (*bi)->id() != mergeBlockId; ++bi) { } + + auto merge_terminator = (*bi)->terminator(); + if (merge_terminator->opcode() == SpvOpUnreachable) { + // The merge was unreachable. This is undefined behaviour so just + // return (or return an undef). Then mark the new return as live. + auto func_ret_type_inst = get_def_use_mgr()->GetDef(func->type_id()); + if (func_ret_type_inst->opcode() == SpvOpTypeVoid) { + merge_terminator->SetOpcode(SpvOpReturn); + } else { + // Find an undef for the return value and make sure it gets kept by + // the pass. + auto undef_id = Type2Undef(func->type_id()); + auto undef = get_def_use_mgr()->GetDef(undef_id); + live_insts_.Set(undef->unique_id()); + merge_terminator->SetOpcode(SpvOpReturnValue); + merge_terminator->SetInOperands({{SPV_OPERAND_TYPE_ID, {undef_id}}}); + get_def_use_mgr()->AnalyzeInstUse(merge_terminator); + } + live_insts_.Set(merge_terminator->unique_id()); + } } else { ++bi; } @@ -513,15 +571,49 @@ void AggressiveDCEPass::InitializeModuleScopeLiveInstructions() { } // Keep all entry points. for (auto& entry : get_module()->entry_points()) { - AddToWorklist(&entry); + if (get_module()->version() >= SPV_SPIRV_VERSION_WORD(1, 4)) { + // In SPIR-V 1.4 and later, entry points must list all global variables + // used. DCE can still remove non-input/output variables and update the + // interface list. Mark the entry point as live and inputs and outputs as + // live, but defer decisions all other interfaces. + live_insts_.Set(entry.unique_id()); + // The actual function is live always. + AddToWorklist( + get_def_use_mgr()->GetDef(entry.GetSingleWordInOperand(1u))); + for (uint32_t i = 3; i < entry.NumInOperands(); ++i) { + auto* var = get_def_use_mgr()->GetDef(entry.GetSingleWordInOperand(i)); + auto storage_class = var->GetSingleWordInOperand(0u); + if (storage_class == SpvStorageClassInput || + storage_class == SpvStorageClassOutput) { + AddToWorklist(var); + } + } + } else { + AddToWorklist(&entry); + } } - // Keep workgroup size. for (auto& anno : get_module()->annotations()) { if (anno.opcode() == SpvOpDecorate) { + // Keep workgroup size. if (anno.GetSingleWordInOperand(1u) == SpvDecorationBuiltIn && anno.GetSingleWordInOperand(2u) == SpvBuiltInWorkgroupSize) { AddToWorklist(&anno); } + + if (context()->preserve_bindings()) { + // Keep all bindings. + if ((anno.GetSingleWordInOperand(1u) == SpvDecorationDescriptorSet) || + (anno.GetSingleWordInOperand(1u) == SpvDecorationBinding)) { + AddToWorklist(&anno); + } + } + + if (context()->preserve_spec_constants()) { + // Keep all specialization constant instructions + if (anno.GetSingleWordInOperand(1u) == SpvDecorationSpecId) { + AddToWorklist(&anno); + } + } } } } @@ -531,11 +623,19 @@ Pass::Status AggressiveDCEPass::ProcessImpl() { // TODO(greg-lunarg): Handle additional capabilities if (!context()->get_feature_mgr()->HasCapability(SpvCapabilityShader)) return Status::SuccessWithoutChange; + // Current functionality assumes relaxed logical addressing (see // instruction.h) // TODO(greg-lunarg): Handle non-logical addressing if (context()->get_feature_mgr()->HasCapability(SpvCapabilityAddresses)) return Status::SuccessWithoutChange; + + // The variable pointer extension is no longer needed to use the capability, + // so we have to look for the capability. + if (context()->get_feature_mgr()->HasCapability( + SpvCapabilityVariablePointersStorageBuffer)) + return Status::SuccessWithoutChange; + // If any extensions in the module are not explicitly supported, // return unmodified. if (!AllExtensionsSupported()) return Status::SuccessWithoutChange; @@ -547,12 +647,26 @@ Pass::Status AggressiveDCEPass::ProcessImpl() { // Process all entry point functions. ProcessFunction pfn = [this](Function* fp) { return AggressiveDCE(fp); }; - modified |= ProcessEntryPointCallTree(pfn, get_module()); + modified |= context()->ProcessEntryPointCallTree(pfn); + + // If the decoration manager is kept live then the context will try to keep it + // up to date. ADCE deals with group decorations by changing the operands in + // |OpGroupDecorate| instruction directly without informing the decoration + // manager. This can put it in an invalid state which will cause an error + // when the context tries to update it. To avoid this problem invalidate + // the decoration manager upfront. + // + // We kill it at now because it is used when processing the entry point + // functions. + context()->InvalidateAnalyses(IRContext::Analysis::kAnalysisDecorations); // Process module-level instructions. Now that all live instructions have // been marked, it is safe to remove dead global values. modified |= ProcessGlobalValues(); + // Sanity check. + assert(to_kill_.size() == 0 || modified); + // Kill all dead instructions. for (auto inst : to_kill_) { context()->KillInst(inst); @@ -560,7 +674,7 @@ Pass::Status AggressiveDCEPass::ProcessImpl() { // Cleanup all CFG including all unreachable blocks. ProcessFunction cleanup = [this](Function* f) { return CFGCleanup(f); }; - modified |= ProcessEntryPointCallTree(cleanup, get_module()); + modified |= context()->ProcessEntryPointCallTree(cleanup); return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange; } @@ -574,7 +688,7 @@ bool AggressiveDCEPass::EliminateDeadFunctions() { live_function_set.insert(fp); return false; }; - ProcessEntryPointCallTree(mark_live, get_module()); + context()->ProcessEntryPointCallTree(mark_live); bool modified = false; for (auto funcIter = get_module()->begin(); @@ -627,17 +741,37 @@ bool AggressiveDCEPass::ProcessGlobalValues() { switch (annotation->opcode()) { case SpvOpDecorate: case SpvOpMemberDecorate: - case SpvOpDecorateId: case SpvOpDecorateStringGOOGLE: + case SpvOpMemberDecorateStringGOOGLE: if (IsTargetDead(annotation)) { context()->KillInst(annotation); modified = true; } break; + case SpvOpDecorateId: + if (IsTargetDead(annotation)) { + context()->KillInst(annotation); + modified = true; + } else { + if (annotation->GetSingleWordInOperand(1) == + SpvDecorationHlslCounterBufferGOOGLE) { + // HlslCounterBuffer will reference an id other than the target. + // If that id is dead, then the decoration can be removed as well. + uint32_t counter_buffer_id = annotation->GetSingleWordInOperand(2); + Instruction* counter_buffer_inst = + get_def_use_mgr()->GetDef(counter_buffer_id); + if (IsDead(counter_buffer_inst)) { + context()->KillInst(annotation); + modified = true; + } + } + } + break; case SpvOpGroupDecorate: { // Go through the targets of this group decorate. Remove each dead // target. If all targets are dead, remove this decoration. bool dead = true; + bool removed_operand = false; for (uint32_t i = 1; i < annotation->NumOperands();) { Instruction* opInst = get_def_use_mgr()->GetDef(annotation->GetSingleWordOperand(i)); @@ -645,6 +779,7 @@ bool AggressiveDCEPass::ProcessGlobalValues() { // Don't increment |i|. annotation->RemoveOperand(i); modified = true; + removed_operand = true; } else { i++; dead = false; @@ -653,6 +788,8 @@ bool AggressiveDCEPass::ProcessGlobalValues() { if (dead) { context()->KillInst(annotation); modified = true; + } else if (removed_operand) { + context()->UpdateDefUse(annotation); } break; } @@ -661,6 +798,7 @@ bool AggressiveDCEPass::ProcessGlobalValues() { // dead target (and member index). If all targets are dead, remove this // decoration. bool dead = true; + bool removed_operand = false; for (uint32_t i = 1; i < annotation->NumOperands();) { Instruction* opInst = get_def_use_mgr()->GetDef(annotation->GetSingleWordOperand(i)); @@ -669,6 +807,7 @@ bool AggressiveDCEPass::ProcessGlobalValues() { annotation->RemoveOperand(i + 1); annotation->RemoveOperand(i); modified = true; + removed_operand = true; } else { i += 2; dead = false; @@ -677,6 +816,8 @@ bool AggressiveDCEPass::ProcessGlobalValues() { if (dead) { context()->KillInst(annotation); modified = true; + } else if (removed_operand) { + context()->UpdateDefUse(annotation); } break; } @@ -698,7 +839,40 @@ bool AggressiveDCEPass::ProcessGlobalValues() { // attributes here. for (auto& val : get_module()->types_values()) { if (IsDead(&val)) { + // Save forwarded pointer if pointer is live since closure does not mark + // this live as it does not have a result id. This is a little too + // conservative since it is not known if the structure type that needed + // it is still live. TODO(greg-lunarg): Only save if needed. + if (val.opcode() == SpvOpTypeForwardPointer) { + uint32_t ptr_ty_id = val.GetSingleWordInOperand(0); + Instruction* ptr_ty_inst = get_def_use_mgr()->GetDef(ptr_ty_id); + if (!IsDead(ptr_ty_inst)) continue; + } to_kill_.push_back(&val); + modified = true; + } + } + + if (get_module()->version() >= SPV_SPIRV_VERSION_WORD(1, 4)) { + // Remove the dead interface variables from the entry point interface list. + for (auto& entry : get_module()->entry_points()) { + std::vector new_operands; + for (uint32_t i = 0; i < entry.NumInOperands(); ++i) { + if (i < 3) { + // Execution model, function id and name are always valid. + new_operands.push_back(entry.GetInOperand(i)); + } else { + auto* var = + get_def_use_mgr()->GetDef(entry.GetSingleWordInOperand(i)); + if (!IsDead(var)) { + new_operands.push_back(entry.GetInOperand(i)); + } + } + } + if (new_operands.size() != entry.NumInOperands()) { + entry.SetInOperands(std::move(new_operands)); + get_def_use_mgr()->UpdateDefUse(&entry); + } } } @@ -747,8 +921,17 @@ void AggressiveDCEPass::InitExtensions() { "SPV_AMD_gpu_shader_half_float_fetch", "SPV_GOOGLE_decorate_string", "SPV_GOOGLE_hlsl_functionality1", + "SPV_GOOGLE_user_type", "SPV_NV_shader_subgroup_partitioned", "SPV_EXT_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_EXT_fragment_invocation_density", + "SPV_EXT_physical_storage_buffer", }); } diff --git a/third_party/spirv-tools/source/opt/aggressive_dead_code_elim_pass.h b/third_party/spirv-tools/source/opt/aggressive_dead_code_elim_pass.h index 3c03cc66b9..c043a96f40 100644 --- a/third_party/spirv-tools/source/opt/aggressive_dead_code_elim_pass.h +++ b/third_party/spirv-tools/source/opt/aggressive_dead_code_elim_pass.h @@ -49,7 +49,9 @@ class AggressiveDCEPass : public MemPass { Status Process() override; IRContext::Analysis GetPreservedAnalyses() override { - return IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping; + return IRContext::kAnalysisDefUse | + IRContext::kAnalysisInstrToBlockMapping | + IRContext::kAnalysisConstants | IRContext::kAnalysisTypes; } private: @@ -107,8 +109,8 @@ class AggressiveDCEPass : public MemPass { bool IsStructuredHeader(BasicBlock* bp, Instruction** mergeInst, Instruction** branchInst, uint32_t* mergeBlockId); - // Initialize block2headerBranch_ and branch2merge_ using |structuredOrder| - // to order blocks. + // Initialize block2headerBranch_, header2nextHeaderBranch_, and + // branch2merge_ using |structuredOrder| to order blocks. void ComputeBlock2HeaderMaps(std::list& structuredOrder); // Add branch to |labelId| to end of block |bp|. @@ -163,6 +165,12 @@ class AggressiveDCEPass : public MemPass { // of an enclosing construct's header, if one exists. std::unordered_map block2headerBranch_; + // Map from header block to the branch instruction in the header of the + // structured construct enclosing it. + // The liveness algorithm is designed to iteratively mark as live all + // structured constructs enclosing a live instruction. + std::unordered_map header2nextHeaderBranch_; + // Maps basic block to their index in the structured order traversal. std::unordered_map structured_order_index_; diff --git a/third_party/spirv-tools/source/opt/amd_ext_to_khr.cpp b/third_party/spirv-tools/source/opt/amd_ext_to_khr.cpp new file mode 100644 index 0000000000..ccedc0bc5c --- /dev/null +++ b/third_party/spirv-tools/source/opt/amd_ext_to_khr.cpp @@ -0,0 +1,972 @@ +// Copyright (c) 2019 Google LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/opt/amd_ext_to_khr.h" + +#include +#include + +#include "ir_builder.h" +#include "source/opt/ir_context.h" +#include "spv-amd-shader-ballot.insts.inc" +#include "type_manager.h" + +namespace spvtools { +namespace opt { + +namespace { + +enum AmdShaderBallotExtOpcodes { + AmdShaderBallotSwizzleInvocationsAMD = 1, + AmdShaderBallotSwizzleInvocationsMaskedAMD = 2, + AmdShaderBallotWriteInvocationAMD = 3, + AmdShaderBallotMbcntAMD = 4 +}; + +enum AmdShaderTrinaryMinMaxExtOpCodes { + FMin3AMD = 1, + UMin3AMD = 2, + SMin3AMD = 3, + FMax3AMD = 4, + UMax3AMD = 5, + SMax3AMD = 6, + FMid3AMD = 7, + UMid3AMD = 8, + SMid3AMD = 9 +}; + +enum AmdGcnShader { CubeFaceCoordAMD = 2, CubeFaceIndexAMD = 1, TimeAMD = 3 }; + +analysis::Type* GetUIntType(IRContext* ctx) { + analysis::Integer int_type(32, false); + return ctx->get_type_mgr()->GetRegisteredType(&int_type); +} + +// Returns a folding rule that replaces |op(a,b,c)| by |op(op(a,b),c)|, where +// |op| is either min or max. |opcode| is the binary opcode in the GLSLstd450 +// extended instruction set that corresponds to the trinary instruction being +// replaced. +template +bool ReplaceTrinaryMinMax(IRContext* ctx, Instruction* inst, + const std::vector&) { + uint32_t glsl405_ext_inst_id = + ctx->get_feature_mgr()->GetExtInstImportId_GLSLstd450(); + if (glsl405_ext_inst_id == 0) { + ctx->AddExtInstImport("GLSL.std.450"); + glsl405_ext_inst_id = + ctx->get_feature_mgr()->GetExtInstImportId_GLSLstd450(); + } + + InstructionBuilder ir_builder( + ctx, inst, + IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping); + + uint32_t op1 = inst->GetSingleWordInOperand(2); + uint32_t op2 = inst->GetSingleWordInOperand(3); + uint32_t op3 = inst->GetSingleWordInOperand(4); + + Instruction* temp = ir_builder.AddNaryExtendedInstruction( + inst->type_id(), glsl405_ext_inst_id, opcode, {op1, op2}); + + Instruction::OperandList new_operands; + new_operands.push_back({SPV_OPERAND_TYPE_ID, {glsl405_ext_inst_id}}); + new_operands.push_back({SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER, + {static_cast(opcode)}}); + new_operands.push_back({SPV_OPERAND_TYPE_ID, {temp->result_id()}}); + new_operands.push_back({SPV_OPERAND_TYPE_ID, {op3}}); + + inst->SetInOperands(std::move(new_operands)); + ctx->UpdateDefUse(inst); + return true; +} + +// Returns a folding rule that replaces |mid(a,b,c)| by |clamp(a, min(b,c), +// max(b,c)|. The three parameters are the opcode that correspond to the min, +// max, and clamp operations for the type of the instruction being replaced. +template +bool ReplaceTrinaryMid(IRContext* ctx, Instruction* inst, + const std::vector&) { + uint32_t glsl405_ext_inst_id = + ctx->get_feature_mgr()->GetExtInstImportId_GLSLstd450(); + if (glsl405_ext_inst_id == 0) { + ctx->AddExtInstImport("GLSL.std.450"); + glsl405_ext_inst_id = + ctx->get_feature_mgr()->GetExtInstImportId_GLSLstd450(); + } + + InstructionBuilder ir_builder( + ctx, inst, + IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping); + + uint32_t op1 = inst->GetSingleWordInOperand(2); + uint32_t op2 = inst->GetSingleWordInOperand(3); + uint32_t op3 = inst->GetSingleWordInOperand(4); + + Instruction* min = ir_builder.AddNaryExtendedInstruction( + inst->type_id(), glsl405_ext_inst_id, static_cast(min_opcode), + {op2, op3}); + Instruction* max = ir_builder.AddNaryExtendedInstruction( + inst->type_id(), glsl405_ext_inst_id, static_cast(max_opcode), + {op2, op3}); + + Instruction::OperandList new_operands; + new_operands.push_back({SPV_OPERAND_TYPE_ID, {glsl405_ext_inst_id}}); + new_operands.push_back({SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER, + {static_cast(clamp_opcode)}}); + new_operands.push_back({SPV_OPERAND_TYPE_ID, {op1}}); + new_operands.push_back({SPV_OPERAND_TYPE_ID, {min->result_id()}}); + new_operands.push_back({SPV_OPERAND_TYPE_ID, {max->result_id()}}); + + inst->SetInOperands(std::move(new_operands)); + ctx->UpdateDefUse(inst); + return true; +} + +// Returns a folding rule that will replace the opcode with |opcode| and add +// the capabilities required. The folding rule assumes it is folding an +// OpGroup*NonUniformAMD instruction from the SPV_AMD_shader_ballot extension. +template +bool ReplaceGroupNonuniformOperationOpCode( + IRContext* ctx, Instruction* inst, + const std::vector&) { + switch (new_opcode) { + case SpvOpGroupNonUniformIAdd: + case SpvOpGroupNonUniformFAdd: + case SpvOpGroupNonUniformUMin: + case SpvOpGroupNonUniformSMin: + case SpvOpGroupNonUniformFMin: + case SpvOpGroupNonUniformUMax: + case SpvOpGroupNonUniformSMax: + case SpvOpGroupNonUniformFMax: + break; + default: + assert( + false && + "Should be replacing with a group non uniform arithmetic operation."); + } + + switch (inst->opcode()) { + case SpvOpGroupIAddNonUniformAMD: + case SpvOpGroupFAddNonUniformAMD: + case SpvOpGroupUMinNonUniformAMD: + case SpvOpGroupSMinNonUniformAMD: + case SpvOpGroupFMinNonUniformAMD: + case SpvOpGroupUMaxNonUniformAMD: + case SpvOpGroupSMaxNonUniformAMD: + case SpvOpGroupFMaxNonUniformAMD: + break; + default: + assert(false && + "Should be replacing a group non uniform arithmetic operation."); + } + + ctx->AddCapability(SpvCapabilityGroupNonUniformArithmetic); + inst->SetOpcode(new_opcode); + return true; +} + +// Returns a folding rule that will replace the SwizzleInvocationsAMD extended +// instruction in the SPV_AMD_shader_ballot extension. +// +// The instruction +// +// %offset = OpConstantComposite %v3uint %x %y %z %w +// %result = OpExtInst %type %1 SwizzleInvocationsAMD %data %offset +// +// is replaced with +// +// potentially new constants and types +// +// clang-format off +// %uint_max = OpConstant %uint 0xFFFFFFFF +// %v4uint = OpTypeVector %uint 4 +// %ballot_value = OpConstantComposite %v4uint %uint_max %uint_max %uint_max %uint_max +// %null = OpConstantNull %type +// clang-format on +// +// and the following code in the function body +// +// clang-format off +// %id = OpLoad %uint %SubgroupLocalInvocationId +// %quad_idx = OpBitwiseAnd %uint %id %uint_3 +// %quad_ldr = OpBitwiseXor %uint %id %quad_idx +// %my_offset = OpVectorExtractDynamic %uint %offset %quad_idx +// %target_inv = OpIAdd %uint %quad_ldr %my_offset +// %is_active = OpGroupNonUniformBallotBitExtract %bool %uint_3 %ballot_value %target_inv +// %shuffle = OpGroupNonUniformShuffle %type %uint_3 %data %target_inv +// %result = OpSelect %type %is_active %shuffle %null +// clang-format on +// +// Also adding the capabilities and builtins that are needed. +bool ReplaceSwizzleInvocations(IRContext* ctx, Instruction* inst, + const std::vector&) { + analysis::TypeManager* type_mgr = ctx->get_type_mgr(); + analysis::ConstantManager* const_mgr = ctx->get_constant_mgr(); + + ctx->AddExtension("SPV_KHR_shader_ballot"); + ctx->AddCapability(SpvCapabilityGroupNonUniformBallot); + ctx->AddCapability(SpvCapabilityGroupNonUniformShuffle); + + InstructionBuilder ir_builder( + ctx, inst, + IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping); + + uint32_t data_id = inst->GetSingleWordInOperand(2); + uint32_t offset_id = inst->GetSingleWordInOperand(3); + + // Get the subgroup invocation id. + uint32_t var_id = + ctx->GetBuiltinInputVarId(SpvBuiltInSubgroupLocalInvocationId); + assert(var_id != 0 && "Could not get SubgroupLocalInvocationId variable."); + Instruction* var_inst = ctx->get_def_use_mgr()->GetDef(var_id); + Instruction* var_ptr_type = + ctx->get_def_use_mgr()->GetDef(var_inst->type_id()); + uint32_t uint_type_id = var_ptr_type->GetSingleWordInOperand(1); + + Instruction* id = ir_builder.AddLoad(uint_type_id, var_id); + + uint32_t quad_mask = ir_builder.GetUintConstantId(3); + + // This gives the offset in the group of 4 of this invocation. + Instruction* quad_idx = ir_builder.AddBinaryOp(uint_type_id, SpvOpBitwiseAnd, + id->result_id(), quad_mask); + + // Get the invocation id of the first invocation in the group of 4. + Instruction* quad_ldr = ir_builder.AddBinaryOp( + uint_type_id, SpvOpBitwiseXor, id->result_id(), quad_idx->result_id()); + + // Get the offset of the target invocation from the offset vector. + Instruction* my_offset = + ir_builder.AddBinaryOp(uint_type_id, SpvOpVectorExtractDynamic, offset_id, + quad_idx->result_id()); + + // Determine the index of the invocation to read from. + Instruction* target_inv = ir_builder.AddBinaryOp( + uint_type_id, SpvOpIAdd, quad_ldr->result_id(), my_offset->result_id()); + + // Do the group operations + uint32_t uint_max_id = ir_builder.GetUintConstantId(0xFFFFFFFF); + uint32_t subgroup_scope = ir_builder.GetUintConstantId(SpvScopeSubgroup); + const auto* ballot_value_const = const_mgr->GetConstant( + type_mgr->GetUIntVectorType(4), + {uint_max_id, uint_max_id, uint_max_id, uint_max_id}); + Instruction* ballot_value = + const_mgr->GetDefiningInstruction(ballot_value_const); + Instruction* is_active = ir_builder.AddNaryOp( + type_mgr->GetBoolTypeId(), SpvOpGroupNonUniformBallotBitExtract, + {subgroup_scope, ballot_value->result_id(), target_inv->result_id()}); + Instruction* shuffle = + ir_builder.AddNaryOp(inst->type_id(), SpvOpGroupNonUniformShuffle, + {subgroup_scope, data_id, target_inv->result_id()}); + + // Create the null constant to use in the select. + const auto* null = const_mgr->GetConstant(type_mgr->GetType(inst->type_id()), + std::vector()); + Instruction* null_inst = const_mgr->GetDefiningInstruction(null); + + // Build the select. + inst->SetOpcode(SpvOpSelect); + Instruction::OperandList new_operands; + new_operands.push_back({SPV_OPERAND_TYPE_ID, {is_active->result_id()}}); + new_operands.push_back({SPV_OPERAND_TYPE_ID, {shuffle->result_id()}}); + new_operands.push_back({SPV_OPERAND_TYPE_ID, {null_inst->result_id()}}); + + inst->SetInOperands(std::move(new_operands)); + ctx->UpdateDefUse(inst); + return true; +} + +// Returns a folding rule that will replace the SwizzleInvocationsMaskedAMD +// extended instruction in the SPV_AMD_shader_ballot extension. +// +// The instruction +// +// %mask = OpConstantComposite %v3uint %uint_x %uint_y %uint_z +// %result = OpExtInst %uint %1 SwizzleInvocationsMaskedAMD %data %mask +// +// is replaced with +// +// potentially new constants and types +// +// clang-format off +// %uint_mask_extend = OpConstant %uint 0xFFFFFFE0 +// %uint_max = OpConstant %uint 0xFFFFFFFF +// %v4uint = OpTypeVector %uint 4 +// %ballot_value = OpConstantComposite %v4uint %uint_max %uint_max %uint_max %uint_max +// clang-format on +// +// and the following code in the function body +// +// clang-format off +// %id = OpLoad %uint %SubgroupLocalInvocationId +// %and_mask = OpBitwiseOr %uint %uint_x %uint_mask_extend +// %and = OpBitwiseAnd %uint %id %and_mask +// %or = OpBitwiseOr %uint %and %uint_y +// %target_inv = OpBitwiseXor %uint %or %uint_z +// %is_active = OpGroupNonUniformBallotBitExtract %bool %uint_3 %ballot_value %target_inv +// %shuffle = OpGroupNonUniformShuffle %type %uint_3 %data %target_inv +// %result = OpSelect %type %is_active %shuffle %uint_0 +// clang-format on +// +// Also adding the capabilities and builtins that are needed. +bool ReplaceSwizzleInvocationsMasked( + IRContext* ctx, Instruction* inst, + const std::vector&) { + analysis::TypeManager* type_mgr = ctx->get_type_mgr(); + analysis::DefUseManager* def_use_mgr = ctx->get_def_use_mgr(); + analysis::ConstantManager* const_mgr = ctx->get_constant_mgr(); + + ctx->AddCapability(SpvCapabilityGroupNonUniformBallot); + ctx->AddCapability(SpvCapabilityGroupNonUniformShuffle); + + InstructionBuilder ir_builder( + ctx, inst, + IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping); + + // Get the operands to inst, and the components of the mask + uint32_t data_id = inst->GetSingleWordInOperand(2); + + Instruction* mask_inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(3)); + assert(mask_inst->opcode() == SpvOpConstantComposite && + "The mask is suppose to be a vector constant."); + assert(mask_inst->NumInOperands() == 3 && + "The mask is suppose to have 3 components."); + + uint32_t uint_x = mask_inst->GetSingleWordInOperand(0); + uint32_t uint_y = mask_inst->GetSingleWordInOperand(1); + uint32_t uint_z = mask_inst->GetSingleWordInOperand(2); + + // Get the subgroup invocation id. + uint32_t var_id = + ctx->GetBuiltinInputVarId(SpvBuiltInSubgroupLocalInvocationId); + ctx->AddExtension("SPV_KHR_shader_ballot"); + assert(var_id != 0 && "Could not get SubgroupLocalInvocationId variable."); + Instruction* var_inst = ctx->get_def_use_mgr()->GetDef(var_id); + Instruction* var_ptr_type = + ctx->get_def_use_mgr()->GetDef(var_inst->type_id()); + uint32_t uint_type_id = var_ptr_type->GetSingleWordInOperand(1); + + Instruction* id = ir_builder.AddLoad(uint_type_id, var_id); + + // Do the bitwise operations. + uint32_t mask_extended = ir_builder.GetUintConstantId(0xFFFFFFE0); + Instruction* and_mask = ir_builder.AddBinaryOp(uint_type_id, SpvOpBitwiseOr, + uint_x, mask_extended); + Instruction* and_result = ir_builder.AddBinaryOp( + uint_type_id, SpvOpBitwiseAnd, id->result_id(), and_mask->result_id()); + Instruction* or_result = ir_builder.AddBinaryOp( + uint_type_id, SpvOpBitwiseOr, and_result->result_id(), uint_y); + Instruction* target_inv = ir_builder.AddBinaryOp( + uint_type_id, SpvOpBitwiseXor, or_result->result_id(), uint_z); + + // Do the group operations + uint32_t uint_max_id = ir_builder.GetUintConstantId(0xFFFFFFFF); + uint32_t subgroup_scope = ir_builder.GetUintConstantId(SpvScopeSubgroup); + const auto* ballot_value_const = const_mgr->GetConstant( + type_mgr->GetUIntVectorType(4), + {uint_max_id, uint_max_id, uint_max_id, uint_max_id}); + Instruction* ballot_value = + const_mgr->GetDefiningInstruction(ballot_value_const); + Instruction* is_active = ir_builder.AddNaryOp( + type_mgr->GetBoolTypeId(), SpvOpGroupNonUniformBallotBitExtract, + {subgroup_scope, ballot_value->result_id(), target_inv->result_id()}); + Instruction* shuffle = + ir_builder.AddNaryOp(inst->type_id(), SpvOpGroupNonUniformShuffle, + {subgroup_scope, data_id, target_inv->result_id()}); + + // Create the null constant to use in the select. + const auto* null = const_mgr->GetConstant(type_mgr->GetType(inst->type_id()), + std::vector()); + Instruction* null_inst = const_mgr->GetDefiningInstruction(null); + + // Build the select. + inst->SetOpcode(SpvOpSelect); + Instruction::OperandList new_operands; + new_operands.push_back({SPV_OPERAND_TYPE_ID, {is_active->result_id()}}); + new_operands.push_back({SPV_OPERAND_TYPE_ID, {shuffle->result_id()}}); + new_operands.push_back({SPV_OPERAND_TYPE_ID, {null_inst->result_id()}}); + + inst->SetInOperands(std::move(new_operands)); + ctx->UpdateDefUse(inst); + return true; +} + +// Returns a folding rule that will replace the WriteInvocationAMD extended +// instruction in the SPV_AMD_shader_ballot extension. +// +// The instruction +// +// clang-format off +// %result = OpExtInst %type %1 WriteInvocationAMD %input_value %write_value %invocation_index +// clang-format on +// +// with +// +// %id = OpLoad %uint %SubgroupLocalInvocationId +// %cmp = OpIEqual %bool %id %invocation_index +// %result = OpSelect %type %cmp %write_value %input_value +// +// Also adding the capabilities and builtins that are needed. +bool ReplaceWriteInvocation(IRContext* ctx, Instruction* inst, + const std::vector&) { + uint32_t var_id = + ctx->GetBuiltinInputVarId(SpvBuiltInSubgroupLocalInvocationId); + ctx->AddCapability(SpvCapabilitySubgroupBallotKHR); + ctx->AddExtension("SPV_KHR_shader_ballot"); + assert(var_id != 0 && "Could not get SubgroupLocalInvocationId variable."); + Instruction* var_inst = ctx->get_def_use_mgr()->GetDef(var_id); + Instruction* var_ptr_type = + ctx->get_def_use_mgr()->GetDef(var_inst->type_id()); + + InstructionBuilder ir_builder( + ctx, inst, + IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping); + Instruction* t = + ir_builder.AddLoad(var_ptr_type->GetSingleWordInOperand(1), var_id); + analysis::Bool bool_type; + uint32_t bool_type_id = ctx->get_type_mgr()->GetTypeInstruction(&bool_type); + Instruction* cmp = + ir_builder.AddBinaryOp(bool_type_id, SpvOpIEqual, t->result_id(), + inst->GetSingleWordInOperand(4)); + + // Build a select. + inst->SetOpcode(SpvOpSelect); + Instruction::OperandList new_operands; + new_operands.push_back({SPV_OPERAND_TYPE_ID, {cmp->result_id()}}); + new_operands.push_back(inst->GetInOperand(3)); + new_operands.push_back(inst->GetInOperand(2)); + + inst->SetInOperands(std::move(new_operands)); + ctx->UpdateDefUse(inst); + return true; +} + +// Returns a folding rule that will replace the MbcntAMD extended instruction in +// the SPV_AMD_shader_ballot extension. +// +// The instruction +// +// %result = OpExtInst %uint %1 MbcntAMD %mask +// +// with +// +// Get SubgroupLtMask and convert the first 64-bits into a uint64_t because +// AMD's shader compiler expects a 64-bit integer mask. +// +// %var = OpLoad %v4uint %SubgroupLtMaskKHR +// %shuffle = OpVectorShuffle %v2uint %var %var 0 1 +// %cast = OpBitcast %ulong %shuffle +// +// Perform the mask and count the bits. +// +// %and = OpBitwiseAnd %ulong %cast %mask +// %result = OpBitCount %uint %and +// +// Also adding the capabilities and builtins that are needed. +bool ReplaceMbcnt(IRContext* context, Instruction* inst, + const std::vector&) { + analysis::TypeManager* type_mgr = context->get_type_mgr(); + analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr(); + + uint32_t var_id = context->GetBuiltinInputVarId(SpvBuiltInSubgroupLtMask); + assert(var_id != 0 && "Could not get SubgroupLtMask variable."); + context->AddCapability(SpvCapabilityGroupNonUniformBallot); + Instruction* var_inst = def_use_mgr->GetDef(var_id); + Instruction* var_ptr_type = def_use_mgr->GetDef(var_inst->type_id()); + Instruction* var_type = + def_use_mgr->GetDef(var_ptr_type->GetSingleWordInOperand(1)); + assert(var_type->opcode() == SpvOpTypeVector && + "Variable is suppose to be a vector of 4 ints"); + + // Get the type for the shuffle. + analysis::Vector temp_type(GetUIntType(context), 2); + const analysis::Type* shuffle_type = + context->get_type_mgr()->GetRegisteredType(&temp_type); + uint32_t shuffle_type_id = type_mgr->GetTypeInstruction(shuffle_type); + + uint32_t mask_id = inst->GetSingleWordInOperand(2); + Instruction* mask_inst = def_use_mgr->GetDef(mask_id); + + // Testing with amd's shader compiler shows that a 64-bit mask is expected. + assert(type_mgr->GetType(mask_inst->type_id())->AsInteger() != nullptr); + assert(type_mgr->GetType(mask_inst->type_id())->AsInteger()->width() == 64); + + InstructionBuilder ir_builder( + context, inst, + IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping); + Instruction* load = ir_builder.AddLoad(var_type->result_id(), var_id); + Instruction* shuffle = ir_builder.AddVectorShuffle( + shuffle_type_id, load->result_id(), load->result_id(), {0, 1}); + Instruction* bitcast = ir_builder.AddUnaryOp( + mask_inst->type_id(), SpvOpBitcast, shuffle->result_id()); + Instruction* t = ir_builder.AddBinaryOp(mask_inst->type_id(), SpvOpBitwiseAnd, + bitcast->result_id(), mask_id); + + inst->SetOpcode(SpvOpBitCount); + inst->SetInOperands({{SPV_OPERAND_TYPE_ID, {t->result_id()}}}); + context->UpdateDefUse(inst); + return true; +} + +// A folding rule that will replace the CubeFaceCoordAMD extended +// instruction in the SPV_AMD_gcn_shader_ballot. Returns true if the folding is +// successful. +// +// The instruction +// +// %result = OpExtInst %v2float %1 CubeFaceCoordAMD %input +// +// with +// +// %x = OpCompositeExtract %float %input 0 +// %y = OpCompositeExtract %float %input 1 +// %z = OpCompositeExtract %float %input 2 +// %nx = OpFNegate %float %x +// %ny = OpFNegate %float %y +// %nz = OpFNegate %float %z +// %ax = OpExtInst %float %n_1 FAbs %x +// %ay = OpExtInst %float %n_1 FAbs %y +// %az = OpExtInst %float %n_1 FAbs %z +// %amax_x_y = OpExtInst %float %n_1 FMax %ay %ax +// %amax = OpExtInst %float %n_1 FMax %az %amax_x_y +// %cubema = OpFMul %float %float_2 %amax +// %is_z_max = OpFOrdGreaterThanEqual %bool %az %amax_x_y +// %not_is_z_max = OpLogicalNot %bool %is_z_max +// %y_gt_x = OpFOrdGreaterThanEqual %bool %ay %ax +// %is_y_max = OpLogicalAnd %bool %not_is_z_max %y_gt_x +// %is_z_neg = OpFOrdLessThan %bool %z %float_0 +// %cubesc_case_1 = OpSelect %float %is_z_neg %nx %x +// %is_x_neg = OpFOrdLessThan %bool %x %float_0 +// %cubesc_case_2 = OpSelect %float %is_x_neg %z %nz +// %sel = OpSelect %float %is_y_max %x %cubesc_case_2 +// %cubesc = OpSelect %float %is_z_max %cubesc_case_1 %sel +// %is_y_neg = OpFOrdLessThan %bool %y %float_0 +// %cubetc_case_1 = OpSelect %float %is_y_neg %nz %z +// %cubetc = OpSelect %float %is_y_max %cubetc_case_1 %ny +// %cube = OpCompositeConstruct %v2float %cubesc %cubetc +// %denom = OpCompositeConstruct %v2float %cubema %cubema +// %div = OpFDiv %v2float %cube %denom +// %result = OpFAdd %v2float %div %const +// +// Also adding the capabilities and builtins that are needed. +bool ReplaceCubeFaceCoord(IRContext* ctx, Instruction* inst, + const std::vector&) { + analysis::TypeManager* type_mgr = ctx->get_type_mgr(); + analysis::ConstantManager* const_mgr = ctx->get_constant_mgr(); + + uint32_t float_type_id = type_mgr->GetFloatTypeId(); + const analysis::Type* v2_float_type = type_mgr->GetFloatVectorType(2); + uint32_t v2_float_type_id = type_mgr->GetId(v2_float_type); + uint32_t bool_id = type_mgr->GetBoolTypeId(); + + InstructionBuilder ir_builder( + ctx, inst, + IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping); + + uint32_t input_id = inst->GetSingleWordInOperand(2); + uint32_t glsl405_ext_inst_id = + ctx->get_feature_mgr()->GetExtInstImportId_GLSLstd450(); + if (glsl405_ext_inst_id == 0) { + ctx->AddExtInstImport("GLSL.std.450"); + glsl405_ext_inst_id = + ctx->get_feature_mgr()->GetExtInstImportId_GLSLstd450(); + } + + // Get the constants that will be used. + uint32_t f0_const_id = const_mgr->GetFloatConst(0.0); + uint32_t f2_const_id = const_mgr->GetFloatConst(2.0); + uint32_t f0_5_const_id = const_mgr->GetFloatConst(0.5); + const analysis::Constant* vec_const = + const_mgr->GetConstant(v2_float_type, {f0_5_const_id, f0_5_const_id}); + uint32_t vec_const_id = + const_mgr->GetDefiningInstruction(vec_const)->result_id(); + + // Extract the input values. + Instruction* x = ir_builder.AddCompositeExtract(float_type_id, input_id, {0}); + Instruction* y = ir_builder.AddCompositeExtract(float_type_id, input_id, {1}); + Instruction* z = ir_builder.AddCompositeExtract(float_type_id, input_id, {2}); + + // Negate the input values. + Instruction* nx = + ir_builder.AddUnaryOp(float_type_id, SpvOpFNegate, x->result_id()); + Instruction* ny = + ir_builder.AddUnaryOp(float_type_id, SpvOpFNegate, y->result_id()); + Instruction* nz = + ir_builder.AddUnaryOp(float_type_id, SpvOpFNegate, z->result_id()); + + // Get the abolsute values of the inputs. + Instruction* ax = ir_builder.AddNaryExtendedInstruction( + float_type_id, glsl405_ext_inst_id, GLSLstd450FAbs, {x->result_id()}); + Instruction* ay = ir_builder.AddNaryExtendedInstruction( + float_type_id, glsl405_ext_inst_id, GLSLstd450FAbs, {y->result_id()}); + Instruction* az = ir_builder.AddNaryExtendedInstruction( + float_type_id, glsl405_ext_inst_id, GLSLstd450FAbs, {z->result_id()}); + + // Find which values are negative. Used in later computations. + Instruction* is_z_neg = ir_builder.AddBinaryOp(bool_id, SpvOpFOrdLessThan, + z->result_id(), f0_const_id); + Instruction* is_y_neg = ir_builder.AddBinaryOp(bool_id, SpvOpFOrdLessThan, + y->result_id(), f0_const_id); + Instruction* is_x_neg = ir_builder.AddBinaryOp(bool_id, SpvOpFOrdLessThan, + x->result_id(), f0_const_id); + + // Compute cubema + Instruction* amax_x_y = ir_builder.AddNaryExtendedInstruction( + float_type_id, glsl405_ext_inst_id, GLSLstd450FMax, + {ax->result_id(), ay->result_id()}); + Instruction* amax = ir_builder.AddNaryExtendedInstruction( + float_type_id, glsl405_ext_inst_id, GLSLstd450FMax, + {az->result_id(), amax_x_y->result_id()}); + Instruction* cubema = ir_builder.AddBinaryOp(float_type_id, SpvOpFMul, + f2_const_id, amax->result_id()); + + // Do the comparisons needed for computing cubesc and cubetc. + Instruction* is_z_max = + ir_builder.AddBinaryOp(bool_id, SpvOpFOrdGreaterThanEqual, + az->result_id(), amax_x_y->result_id()); + Instruction* not_is_z_max = + ir_builder.AddUnaryOp(bool_id, SpvOpLogicalNot, is_z_max->result_id()); + Instruction* y_gr_x = ir_builder.AddBinaryOp( + bool_id, SpvOpFOrdGreaterThanEqual, ay->result_id(), ax->result_id()); + Instruction* is_y_max = ir_builder.AddBinaryOp( + bool_id, SpvOpLogicalAnd, not_is_z_max->result_id(), y_gr_x->result_id()); + + // Select the correct value for cubesc. + Instruction* cubesc_case_1 = ir_builder.AddSelect( + float_type_id, is_z_neg->result_id(), nx->result_id(), x->result_id()); + Instruction* cubesc_case_2 = ir_builder.AddSelect( + float_type_id, is_x_neg->result_id(), z->result_id(), nz->result_id()); + Instruction* sel = + ir_builder.AddSelect(float_type_id, is_y_max->result_id(), x->result_id(), + cubesc_case_2->result_id()); + Instruction* cubesc = + ir_builder.AddSelect(float_type_id, is_z_max->result_id(), + cubesc_case_1->result_id(), sel->result_id()); + + // Select the correct value for cubetc. + Instruction* cubetc_case_1 = ir_builder.AddSelect( + float_type_id, is_y_neg->result_id(), nz->result_id(), z->result_id()); + Instruction* cubetc = + ir_builder.AddSelect(float_type_id, is_y_max->result_id(), + cubetc_case_1->result_id(), ny->result_id()); + + // Do the division + Instruction* cube = ir_builder.AddCompositeConstruct( + v2_float_type_id, {cubesc->result_id(), cubetc->result_id()}); + Instruction* denom = ir_builder.AddCompositeConstruct( + v2_float_type_id, {cubema->result_id(), cubema->result_id()}); + Instruction* div = ir_builder.AddBinaryOp( + v2_float_type_id, SpvOpFDiv, cube->result_id(), denom->result_id()); + + // Get the final result by adding 0.5 to |div|. + inst->SetOpcode(SpvOpFAdd); + Instruction::OperandList new_operands; + new_operands.push_back({SPV_OPERAND_TYPE_ID, {div->result_id()}}); + new_operands.push_back({SPV_OPERAND_TYPE_ID, {vec_const_id}}); + + inst->SetInOperands(std::move(new_operands)); + ctx->UpdateDefUse(inst); + return true; +} + +// A folding rule that will replace the CubeFaceIndexAMD extended +// instruction in the SPV_AMD_gcn_shader_ballot. Returns true if the folding +// is successful. +// +// The instruction +// +// %result = OpExtInst %float %1 CubeFaceIndexAMD %input +// +// with +// +// %x = OpCompositeExtract %float %input 0 +// %y = OpCompositeExtract %float %input 1 +// %z = OpCompositeExtract %float %input 2 +// %ax = OpExtInst %float %n_1 FAbs %x +// %ay = OpExtInst %float %n_1 FAbs %y +// %az = OpExtInst %float %n_1 FAbs %z +// %is_z_neg = OpFOrdLessThan %bool %z %float_0 +// %is_y_neg = OpFOrdLessThan %bool %y %float_0 +// %is_x_neg = OpFOrdLessThan %bool %x %float_0 +// %amax_x_y = OpExtInst %float %n_1 FMax %ax %ay +// %is_z_max = OpFOrdGreaterThanEqual %bool %az %amax_x_y +// %y_gt_x = OpFOrdGreaterThanEqual %bool %ay %ax +// %case_z = OpSelect %float %is_z_neg %float_5 %float4 +// %case_y = OpSelect %float %is_y_neg %float_3 %float2 +// %case_x = OpSelect %float %is_x_neg %float_1 %float0 +// %sel = OpSelect %float %y_gt_x %case_y %case_x +// %result = OpSelect %float %is_z_max %case_z %sel +// +// Also adding the capabilities and builtins that are needed. +bool ReplaceCubeFaceIndex(IRContext* ctx, Instruction* inst, + const std::vector&) { + analysis::TypeManager* type_mgr = ctx->get_type_mgr(); + analysis::ConstantManager* const_mgr = ctx->get_constant_mgr(); + + uint32_t float_type_id = type_mgr->GetFloatTypeId(); + uint32_t bool_id = type_mgr->GetBoolTypeId(); + + InstructionBuilder ir_builder( + ctx, inst, + IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping); + + uint32_t input_id = inst->GetSingleWordInOperand(2); + uint32_t glsl405_ext_inst_id = + ctx->get_feature_mgr()->GetExtInstImportId_GLSLstd450(); + if (glsl405_ext_inst_id == 0) { + ctx->AddExtInstImport("GLSL.std.450"); + glsl405_ext_inst_id = + ctx->get_feature_mgr()->GetExtInstImportId_GLSLstd450(); + } + + // Get the constants that will be used. + uint32_t f0_const_id = const_mgr->GetFloatConst(0.0); + uint32_t f1_const_id = const_mgr->GetFloatConst(1.0); + uint32_t f2_const_id = const_mgr->GetFloatConst(2.0); + uint32_t f3_const_id = const_mgr->GetFloatConst(3.0); + uint32_t f4_const_id = const_mgr->GetFloatConst(4.0); + uint32_t f5_const_id = const_mgr->GetFloatConst(5.0); + + // Extract the input values. + Instruction* x = ir_builder.AddCompositeExtract(float_type_id, input_id, {0}); + Instruction* y = ir_builder.AddCompositeExtract(float_type_id, input_id, {1}); + Instruction* z = ir_builder.AddCompositeExtract(float_type_id, input_id, {2}); + + // Get the absolute values of the inputs. + Instruction* ax = ir_builder.AddNaryExtendedInstruction( + float_type_id, glsl405_ext_inst_id, GLSLstd450FAbs, {x->result_id()}); + Instruction* ay = ir_builder.AddNaryExtendedInstruction( + float_type_id, glsl405_ext_inst_id, GLSLstd450FAbs, {y->result_id()}); + Instruction* az = ir_builder.AddNaryExtendedInstruction( + float_type_id, glsl405_ext_inst_id, GLSLstd450FAbs, {z->result_id()}); + + // Find which values are negative. Used in later computations. + Instruction* is_z_neg = ir_builder.AddBinaryOp(bool_id, SpvOpFOrdLessThan, + z->result_id(), f0_const_id); + Instruction* is_y_neg = ir_builder.AddBinaryOp(bool_id, SpvOpFOrdLessThan, + y->result_id(), f0_const_id); + Instruction* is_x_neg = ir_builder.AddBinaryOp(bool_id, SpvOpFOrdLessThan, + x->result_id(), f0_const_id); + + // Find the max value. + Instruction* amax_x_y = ir_builder.AddNaryExtendedInstruction( + float_type_id, glsl405_ext_inst_id, GLSLstd450FMax, + {ax->result_id(), ay->result_id()}); + Instruction* is_z_max = + ir_builder.AddBinaryOp(bool_id, SpvOpFOrdGreaterThanEqual, + az->result_id(), amax_x_y->result_id()); + Instruction* y_gr_x = ir_builder.AddBinaryOp( + bool_id, SpvOpFOrdGreaterThanEqual, ay->result_id(), ax->result_id()); + + // Get the value for each case. + Instruction* case_z = ir_builder.AddSelect( + float_type_id, is_z_neg->result_id(), f5_const_id, f4_const_id); + Instruction* case_y = ir_builder.AddSelect( + float_type_id, is_y_neg->result_id(), f3_const_id, f2_const_id); + Instruction* case_x = ir_builder.AddSelect( + float_type_id, is_x_neg->result_id(), f1_const_id, f0_const_id); + + // Select the correct case. + Instruction* sel = + ir_builder.AddSelect(float_type_id, y_gr_x->result_id(), + case_y->result_id(), case_x->result_id()); + + // Get the final result by adding 0.5 to |div|. + inst->SetOpcode(SpvOpSelect); + Instruction::OperandList new_operands; + new_operands.push_back({SPV_OPERAND_TYPE_ID, {is_z_max->result_id()}}); + new_operands.push_back({SPV_OPERAND_TYPE_ID, {case_z->result_id()}}); + new_operands.push_back({SPV_OPERAND_TYPE_ID, {sel->result_id()}}); + + inst->SetInOperands(std::move(new_operands)); + ctx->UpdateDefUse(inst); + return true; +} + +// A folding rule that will replace the TimeAMD extended instruction in the +// SPV_AMD_gcn_shader_ballot. It returns true if the folding is successful. +// It returns False, otherwise. +// +// The instruction +// +// %result = OpExtInst %uint64 %1 TimeAMD +// +// with +// +// %result = OpReadClockKHR %uint64 %uint_3 +// +// NOTE: TimeAMD uses subgroup scope (it is not a real time clock). +bool ReplaceTimeAMD(IRContext* ctx, Instruction* inst, + const std::vector&) { + InstructionBuilder ir_builder( + ctx, inst, + IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping); + ctx->AddExtension("SPV_KHR_shader_clock"); + ctx->AddCapability(SpvCapabilityShaderClockKHR); + + inst->SetOpcode(SpvOpReadClockKHR); + Instruction::OperandList args; + uint32_t subgroup_scope_id = ir_builder.GetUintConstantId(SpvScopeSubgroup); + args.push_back({SPV_OPERAND_TYPE_ID, {subgroup_scope_id}}); + inst->SetInOperands(std::move(args)); + ctx->UpdateDefUse(inst); + + return true; +} + +class AmdExtFoldingRules : public FoldingRules { + public: + explicit AmdExtFoldingRules(IRContext* ctx) : FoldingRules(ctx) {} + + protected: + virtual void AddFoldingRules() override { + rules_[SpvOpGroupIAddNonUniformAMD].push_back( + ReplaceGroupNonuniformOperationOpCode); + rules_[SpvOpGroupFAddNonUniformAMD].push_back( + ReplaceGroupNonuniformOperationOpCode); + rules_[SpvOpGroupUMinNonUniformAMD].push_back( + ReplaceGroupNonuniformOperationOpCode); + rules_[SpvOpGroupSMinNonUniformAMD].push_back( + ReplaceGroupNonuniformOperationOpCode); + rules_[SpvOpGroupFMinNonUniformAMD].push_back( + ReplaceGroupNonuniformOperationOpCode); + rules_[SpvOpGroupUMaxNonUniformAMD].push_back( + ReplaceGroupNonuniformOperationOpCode); + rules_[SpvOpGroupSMaxNonUniformAMD].push_back( + ReplaceGroupNonuniformOperationOpCode); + rules_[SpvOpGroupFMaxNonUniformAMD].push_back( + ReplaceGroupNonuniformOperationOpCode); + + uint32_t extension_id = + context()->module()->GetExtInstImportId("SPV_AMD_shader_ballot"); + + if (extension_id != 0) { + ext_rules_[{extension_id, AmdShaderBallotSwizzleInvocationsAMD}] + .push_back(ReplaceSwizzleInvocations); + ext_rules_[{extension_id, AmdShaderBallotSwizzleInvocationsMaskedAMD}] + .push_back(ReplaceSwizzleInvocationsMasked); + ext_rules_[{extension_id, AmdShaderBallotWriteInvocationAMD}].push_back( + ReplaceWriteInvocation); + ext_rules_[{extension_id, AmdShaderBallotMbcntAMD}].push_back( + ReplaceMbcnt); + } + + extension_id = context()->module()->GetExtInstImportId( + "SPV_AMD_shader_trinary_minmax"); + + if (extension_id != 0) { + ext_rules_[{extension_id, FMin3AMD}].push_back( + ReplaceTrinaryMinMax); + ext_rules_[{extension_id, UMin3AMD}].push_back( + ReplaceTrinaryMinMax); + ext_rules_[{extension_id, SMin3AMD}].push_back( + ReplaceTrinaryMinMax); + ext_rules_[{extension_id, FMax3AMD}].push_back( + ReplaceTrinaryMinMax); + ext_rules_[{extension_id, UMax3AMD}].push_back( + ReplaceTrinaryMinMax); + ext_rules_[{extension_id, SMax3AMD}].push_back( + ReplaceTrinaryMinMax); + ext_rules_[{extension_id, FMid3AMD}].push_back( + ReplaceTrinaryMid); + ext_rules_[{extension_id, UMid3AMD}].push_back( + ReplaceTrinaryMid); + ext_rules_[{extension_id, SMid3AMD}].push_back( + ReplaceTrinaryMid); + } + + extension_id = + context()->module()->GetExtInstImportId("SPV_AMD_gcn_shader"); + + if (extension_id != 0) { + ext_rules_[{extension_id, CubeFaceCoordAMD}].push_back( + ReplaceCubeFaceCoord); + ext_rules_[{extension_id, CubeFaceIndexAMD}].push_back( + ReplaceCubeFaceIndex); + ext_rules_[{extension_id, TimeAMD}].push_back(ReplaceTimeAMD); + } + } +}; + +class AmdExtConstFoldingRules : public ConstantFoldingRules { + public: + AmdExtConstFoldingRules(IRContext* ctx) : ConstantFoldingRules(ctx) {} + + protected: + virtual void AddFoldingRules() override {} +}; + +} // namespace + +Pass::Status AmdExtensionToKhrPass::Process() { + bool changed = false; + + // Traverse the body of the functions to replace instructions that require + // the extensions. + InstructionFolder folder( + context(), + std::unique_ptr(new AmdExtFoldingRules(context())), + MakeUnique(context())); + for (Function& func : *get_module()) { + func.ForEachInst([&changed, &folder](Instruction* inst) { + if (folder.FoldInstruction(inst)) { + changed = true; + } + }); + } + + // Now that instruction that require the extensions have been removed, we can + // remove the extension instructions. + std::set ext_to_remove = {"SPV_AMD_shader_ballot", + "SPV_AMD_shader_trinary_minmax", + "SPV_AMD_gcn_shader"}; + + std::vector to_be_killed; + for (Instruction& inst : context()->module()->extensions()) { + if (inst.opcode() == SpvOpExtension) { + if (ext_to_remove.count(reinterpret_cast( + &(inst.GetInOperand(0).words[0]))) != 0) { + to_be_killed.push_back(&inst); + } + } + } + + for (Instruction& inst : context()->ext_inst_imports()) { + if (inst.opcode() == SpvOpExtInstImport) { + if (ext_to_remove.count(reinterpret_cast( + &(inst.GetInOperand(0).words[0]))) != 0) { + to_be_killed.push_back(&inst); + } + } + } + + for (Instruction* inst : to_be_killed) { + context()->KillInst(inst); + changed = true; + } + + // The replacements that take place use instructions that are missing before + // SPIR-V 1.3. If we changed something, we will have to make sure the version + // is at least SPIR-V 1.3 to make sure those instruction can be used. + if (changed) { + uint32_t version = get_module()->version(); + if (version < 0x00010300 /*1.3*/) { + get_module()->set_version(0x00010300); + } + } + return changed ? Status::SuccessWithChange : Status::SuccessWithoutChange; +} + +} // namespace opt +} // namespace spvtools diff --git a/third_party/spirv-tools/source/opt/amd_ext_to_khr.h b/third_party/spirv-tools/source/opt/amd_ext_to_khr.h new file mode 100644 index 0000000000..fd3dab4e7d --- /dev/null +++ b/third_party/spirv-tools/source/opt/amd_ext_to_khr.h @@ -0,0 +1,51 @@ +// Copyright (c) 2019 Google LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_OPT_AMD_EXT_TO_KHR_H_ +#define SOURCE_OPT_AMD_EXT_TO_KHR_H_ + +#include "source/opt/ir_context.h" +#include "source/opt/module.h" +#include "source/opt/pass.h" + +namespace spvtools { +namespace opt { + +// Replaces the extensions VK_AMD_shader_ballot, VK_AMD_gcn_shader, and +// VK_AMD_shader_trinary_minmax with equivalant code using core instructions and +// capabilities. +class AmdExtensionToKhrPass : public Pass { + public: + const char* name() const override { return "amd-ext-to-khr"; } + Status Process() override; + + IRContext::Analysis GetPreservedAnalyses() override { + return IRContext::kAnalysisInstrToBlockMapping | + IRContext::kAnalysisDecorations | IRContext::kAnalysisCombinators | + IRContext::kAnalysisCFG | IRContext::kAnalysisDominatorAnalysis | + IRContext::kAnalysisLoopAnalysis | IRContext::kAnalysisNameMap | + IRContext::kAnalysisScalarEvolution | + IRContext::kAnalysisRegisterPressure | + IRContext::kAnalysisValueNumberTable | + IRContext::kAnalysisStructuredCFG | + IRContext::kAnalysisBuiltinVarId | + IRContext::kAnalysisIdToFuncMapping | IRContext::kAnalysisTypes | + IRContext::kAnalysisDefUse | IRContext::kAnalysisConstants; + } +}; + +} // namespace opt +} // namespace spvtools + +#endif // SOURCE_OPT_AMD_EXT_TO_KHR_H_ diff --git a/third_party/spirv-tools/source/opt/basic_block.cpp b/third_party/spirv-tools/source/opt/basic_block.cpp index b18b114a5d..3608448ba8 100644 --- a/third_party/spirv-tools/source/opt/basic_block.cpp +++ b/third_party/spirv-tools/source/opt/basic_block.cpp @@ -35,9 +35,18 @@ const uint32_t kSelectionMergeMergeBlockIdInIdx = 0; BasicBlock* BasicBlock::Clone(IRContext* context) const { BasicBlock* clone = new BasicBlock( std::unique_ptr(GetLabelInst()->Clone(context))); - for (const auto& inst : insts_) + for (const auto& inst : insts_) { // Use the incoming context clone->AddInstruction(std::unique_ptr(inst.Clone(context))); + } + + if (context->AreAnalysesValid( + IRContext::Analysis::kAnalysisInstrToBlockMapping)) { + for (auto& inst : *clone) { + context->set_instr_block(&inst, clone); + } + } + return clone; } @@ -99,21 +108,29 @@ void BasicBlock::KillAllInsts(bool killLabel) { void BasicBlock::ForEachSuccessorLabel( const std::function& f) const { + WhileEachSuccessorLabel([f](const uint32_t l) { + f(l); + return true; + }); +} + +bool BasicBlock::WhileEachSuccessorLabel( + const std::function& f) const { const auto br = &insts_.back(); switch (br->opcode()) { - case SpvOpBranch: { - f(br->GetOperand(0).words[0]); - } break; + case SpvOpBranch: + return f(br->GetOperand(0).words[0]); case SpvOpBranchConditional: case SpvOpSwitch: { bool is_first = true; - br->ForEachInId([&is_first, &f](const uint32_t* idp) { - if (!is_first) f(*idp); + return br->WhileEachInId([&is_first, &f](const uint32_t* idp) { + if (!is_first) return f(*idp); is_first = false; + return true; }); - } break; + } default: - break; + return true; } } @@ -175,6 +192,12 @@ uint32_t BasicBlock::MergeBlockIdIfAny() const { return mbid; } +uint32_t BasicBlock::MergeBlockId() const { + uint32_t mbid = MergeBlockIdIfAny(); + assert(mbid && "Expected block to have a corresponding merge block"); + return mbid; +} + uint32_t BasicBlock::ContinueBlockIdIfAny() const { auto merge_ii = cend(); --merge_ii; @@ -188,11 +211,21 @@ uint32_t BasicBlock::ContinueBlockIdIfAny() const { return cbid; } +uint32_t BasicBlock::ContinueBlockId() const { + uint32_t cbid = ContinueBlockIdIfAny(); + assert(cbid && "Expected block to have a corresponding continue target"); + return cbid; +} + std::ostream& operator<<(std::ostream& str, const BasicBlock& block) { str << block.PrettyPrint(); return str; } +void BasicBlock::Dump() const { + std::cerr << "Basic block #" << id() << "\n" << *this << "\n "; +} + std::string BasicBlock::PrettyPrint(uint32_t options) const { std::ostringstream str; ForEachInst([&str, options](const Instruction* inst) { @@ -208,8 +241,11 @@ BasicBlock* BasicBlock::SplitBasicBlock(IRContext* context, uint32_t label_id, iterator iter) { assert(!insts_.empty()); - BasicBlock* new_block = new BasicBlock(MakeUnique( - context, SpvOpLabel, 0, label_id, std::initializer_list{})); + std::unique_ptr new_block_temp = + MakeUnique(MakeUnique( + context, SpvOpLabel, 0, label_id, std::initializer_list{})); + BasicBlock* new_block = new_block_temp.get(); + function_->InsertBasicBlockAfter(std::move(new_block_temp), this); new_block->insts_.Splice(new_block->end(), &insts_, iter, end()); new_block->SetParent(GetParent()); diff --git a/third_party/spirv-tools/source/opt/basic_block.h b/third_party/spirv-tools/source/opt/basic_block.h index 9e1706e14f..6741a50f26 100644 --- a/third_party/spirv-tools/source/opt/basic_block.h +++ b/third_party/spirv-tools/source/opt/basic_block.h @@ -54,6 +54,9 @@ class BasicBlock { // // The parent function will default to null and needs to be explicitly set by // the user. + // + // If the inst-to-block map in |context| is valid, then the new instructions + // will be inserted into the map. BasicBlock* Clone(IRContext*) const; // Sets the enclosing function for this basic block. @@ -68,6 +71,9 @@ class BasicBlock { // Appends all of block's instructions (except label) to this block inline void AddInstructions(BasicBlock* bp); + // The pointer to the label starting this basic block. + std::unique_ptr& GetLabel() { return label_; } + // The label starting this basic block. Instruction* GetLabelInst() { return label_.get(); } const Instruction* GetLabelInst() const { return label_.get(); } @@ -154,6 +160,11 @@ class BasicBlock { void ForEachSuccessorLabel( const std::function& f) const; + // Runs the given function |f| on each label id of each successor block. If + // |f| returns false, iteration is terminated and this function returns false. + bool WhileEachSuccessorLabel( + const std::function& f) const; + // Runs the given function |f| on each label id of each successor block. // Modifying the pointed value will change the branch taken by the basic // block. It is the caller responsibility to update or invalidate the CFG. @@ -177,10 +188,16 @@ class BasicBlock { // block, if any. If none, returns zero. uint32_t MergeBlockIdIfAny() const; + // Returns MergeBlockIdIfAny() and asserts that it is non-zero. + uint32_t MergeBlockId() const; + // Returns the ID of the continue block declared by a merge instruction in // this block, if any. If none, returns zero. uint32_t ContinueBlockIdIfAny() const; + // Returns ContinueBlockIdIfAny() and asserts that it is non-zero. + uint32_t ContinueBlockId() const; + // Returns the terminator instruction. Assumes the terminator exists. Instruction* terminator() { return &*tail(); } const Instruction* terminator() const { return &*ctail(); } @@ -197,8 +214,9 @@ class BasicBlock { void KillAllInsts(bool killLabel); // Splits this basic block into two. Returns a new basic block with label - // |labelId| containing the instructions from |iter| onwards. Instructions - // prior to |iter| remain in this basic block. + // |label_id| containing the instructions from |iter| onwards. Instructions + // prior to |iter| remain in this basic block. The new block will be added + // to the function immediately after the original block. BasicBlock* SplitBasicBlock(IRContext* context, uint32_t label_id, iterator iter); @@ -209,6 +227,10 @@ class BasicBlock { // is always added to |options|. std::string PrettyPrint(uint32_t options = 0u) const; + // Dump this basic block on stderr. Useful when running interactive + // debuggers. + void Dump() const; + private: // The enclosing function. Function* function_; diff --git a/third_party/spirv-tools/source/opt/block_merge_pass.cpp b/third_party/spirv-tools/source/opt/block_merge_pass.cpp index aa4c1bd924..c7315baf26 100644 --- a/third_party/spirv-tools/source/opt/block_merge_pass.cpp +++ b/third_party/spirv-tools/source/opt/block_merge_pass.cpp @@ -18,137 +18,31 @@ #include +#include "source/opt/block_merge_util.h" #include "source/opt/ir_context.h" #include "source/opt/iterator.h" namespace spvtools { namespace opt { -void BlockMergePass::KillInstAndName(Instruction* inst) { - std::vector to_kill; - get_def_use_mgr()->ForEachUser(inst, [&to_kill](Instruction* user) { - if (user->opcode() == SpvOpName) { - to_kill.push_back(user); - } - }); - for (auto i : to_kill) { - context()->KillInst(i); - } - context()->KillInst(inst); -} - bool BlockMergePass::MergeBlocks(Function* func) { bool modified = false; for (auto bi = func->begin(); bi != func->end();) { - // Find block with single successor which has no other predecessors. - auto ii = bi->end(); - --ii; - Instruction* br = &*ii; - if (br->opcode() != SpvOpBranch) { + if (blockmergeutil::CanMergeWithSuccessor(context(), &*bi)) { + blockmergeutil::MergeWithSuccessor(context(), func, bi); + // Reprocess block. + modified = true; + } else { ++bi; - continue; } - - const uint32_t lab_id = br->GetSingleWordInOperand(0); - if (cfg()->preds(lab_id).size() != 1) { - ++bi; - continue; - } - - bool pred_is_header = IsHeader(&*bi); - bool succ_is_header = IsHeader(lab_id); - if (pred_is_header && succ_is_header) { - // Cannot merge two headers together. - ++bi; - continue; - } - - bool pred_is_merge = IsMerge(&*bi); - bool succ_is_merge = IsMerge(lab_id); - if (pred_is_merge && succ_is_merge) { - // Cannot merge two merges together. - ++bi; - continue; - } - - Instruction* merge_inst = bi->GetMergeInst(); - if (pred_is_header && lab_id != merge_inst->GetSingleWordInOperand(0u)) { - // If this is a header block and the successor is not its merge, we must - // be careful about which blocks we are willing to merge together. - // OpLoopMerge must be followed by a conditional or unconditional branch. - // The merge must be a loop merge because a selection merge cannot be - // followed by an unconditional branch. - BasicBlock* succ_block = context()->get_instr_block(lab_id); - SpvOp succ_term_op = succ_block->terminator()->opcode(); - assert(merge_inst->opcode() == SpvOpLoopMerge); - if (succ_term_op != SpvOpBranch && - succ_term_op != SpvOpBranchConditional) { - ++bi; - continue; - } - } - - // Merge blocks. - context()->KillInst(br); - auto sbi = bi; - for (; sbi != func->end(); ++sbi) - if (sbi->id() == lab_id) break; - // If bi is sbi's only predecessor, it dominates sbi and thus - // sbi must follow bi in func's ordering. - assert(sbi != func->end()); - - // Update the inst-to-block mapping for the instructions in sbi. - for (auto& inst : *sbi) { - context()->set_instr_block(&inst, &*bi); - } - - // Now actually move the instructions. - bi->AddInstructions(&*sbi); - - if (merge_inst) { - if (pred_is_header && lab_id == merge_inst->GetSingleWordInOperand(0u)) { - // Merging the header and merge blocks, so remove the structured control - // flow declaration. - context()->KillInst(merge_inst); - } else { - // Move the merge instruction to just before the terminator. - merge_inst->InsertBefore(bi->terminator()); - } - } - context()->ReplaceAllUsesWith(lab_id, bi->id()); - KillInstAndName(sbi->GetLabelInst()); - (void)sbi.Erase(); - // Reprocess block. - modified = true; } return modified; } -bool BlockMergePass::IsHeader(BasicBlock* block) { - return block->GetMergeInst() != nullptr; -} - -bool BlockMergePass::IsHeader(uint32_t id) { - return IsHeader(context()->get_instr_block(get_def_use_mgr()->GetDef(id))); -} - -bool BlockMergePass::IsMerge(uint32_t id) { - return !get_def_use_mgr()->WhileEachUse(id, [](Instruction* user, - uint32_t index) { - SpvOp op = user->opcode(); - if ((op == SpvOpLoopMerge || op == SpvOpSelectionMerge) && index == 0u) { - return false; - } - return true; - }); -} - -bool BlockMergePass::IsMerge(BasicBlock* block) { return IsMerge(block->id()); } - Pass::Status BlockMergePass::Process() { // Process all entry point functions. ProcessFunction pfn = [this](Function* fp) { return MergeBlocks(fp); }; - bool modified = ProcessEntryPointCallTree(pfn, get_module()); + bool modified = context()->ProcessEntryPointCallTree(pfn); return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange; } diff --git a/third_party/spirv-tools/source/opt/block_merge_pass.h b/third_party/spirv-tools/source/opt/block_merge_pass.h index 0ecde48846..aabf789fda 100644 --- a/third_party/spirv-tools/source/opt/block_merge_pass.h +++ b/third_party/spirv-tools/source/opt/block_merge_pass.h @@ -44,25 +44,16 @@ class BlockMergePass : public Pass { return IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping | IRContext::kAnalysisDecorations | IRContext::kAnalysisCombinators | - IRContext::kAnalysisNameMap; + IRContext::kAnalysisNameMap | IRContext::kAnalysisConstants | + IRContext::kAnalysisTypes; } private: - // Kill any OpName instruction referencing |inst|, then kill |inst|. - void KillInstAndName(Instruction* inst); // Search |func| for blocks which have a single Branch to a block // with no other predecessors. Merge these blocks into a single block. bool MergeBlocks(Function* func); - // Returns true if |block| (or |id|) contains a merge instruction. - bool IsHeader(BasicBlock* block); - bool IsHeader(uint32_t id); - - // Returns true if |block| (or |id|) is the merge target of a merge - // instruction. - bool IsMerge(BasicBlock* block); - bool IsMerge(uint32_t id); }; } // namespace opt diff --git a/third_party/spirv-tools/source/opt/block_merge_util.cpp b/third_party/spirv-tools/source/opt/block_merge_util.cpp new file mode 100644 index 0000000000..14b5d36425 --- /dev/null +++ b/third_party/spirv-tools/source/opt/block_merge_util.cpp @@ -0,0 +1,194 @@ +// Copyright (c) 2017 The Khronos Group Inc. +// Copyright (c) 2017 Valve Corporation +// Copyright (c) 2017 LunarG Inc. +// Copyright (c) 2019 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 "block_merge_util.h" + +namespace spvtools { +namespace opt { +namespace blockmergeutil { + +namespace { + +// Returns true if |block| contains a merge instruction. +bool IsHeader(BasicBlock* block) { return block->GetMergeInst() != nullptr; } + +// Returns true if |id| contains a merge instruction. +bool IsHeader(IRContext* context, uint32_t id) { + return IsHeader( + context->get_instr_block(context->get_def_use_mgr()->GetDef(id))); +} + +// Returns true if |id| is the merge target of a merge instruction. +bool IsMerge(IRContext* context, uint32_t id) { + return !context->get_def_use_mgr()->WhileEachUse(id, [](Instruction* user, + uint32_t index) { + SpvOp op = user->opcode(); + if ((op == SpvOpLoopMerge || op == SpvOpSelectionMerge) && index == 0u) { + return false; + } + return true; + }); +} + +// Returns true if |block| is the merge target of a merge instruction. +bool IsMerge(IRContext* context, BasicBlock* block) { + return IsMerge(context, block->id()); +} + +// Returns true if |id| is the continue target of a merge instruction. +bool IsContinue(IRContext* context, uint32_t id) { + return !context->get_def_use_mgr()->WhileEachUse( + id, [](Instruction* user, uint32_t index) { + SpvOp op = user->opcode(); + if (op == SpvOpLoopMerge && index == 1u) { + return false; + } + return true; + }); +} + +// Removes any OpPhi instructions in |block|, which should have exactly one +// predecessor, replacing uses of OpPhi ids with the ids associated with the +// predecessor. +void EliminateOpPhiInstructions(IRContext* context, BasicBlock* block) { + block->ForEachPhiInst([context](Instruction* phi) { + assert(2 == phi->NumInOperands() && + "A block can only have one predecessor for block merging to make " + "sense."); + context->ReplaceAllUsesWith(phi->result_id(), + phi->GetSingleWordInOperand(0)); + context->KillInst(phi); + }); +} + +} // Anonymous namespace + +bool CanMergeWithSuccessor(IRContext* context, BasicBlock* block) { + // Find block with single successor which has no other predecessors. + auto ii = block->end(); + --ii; + Instruction* br = &*ii; + if (br->opcode() != SpvOpBranch) { + return false; + } + + const uint32_t lab_id = br->GetSingleWordInOperand(0); + if (context->cfg()->preds(lab_id).size() != 1) { + return false; + } + + bool pred_is_merge = IsMerge(context, block); + bool succ_is_merge = IsMerge(context, lab_id); + if (pred_is_merge && succ_is_merge) { + // Cannot merge two merges together. + return false; + } + + if (pred_is_merge && IsContinue(context, lab_id)) { + // Cannot merge a continue target with a merge block. + return false; + } + + // Don't bother trying to merge unreachable blocks. + if (auto dominators = context->GetDominatorAnalysis(block->GetParent())) { + if (!dominators->IsReachable(block)) return false; + } + + Instruction* merge_inst = block->GetMergeInst(); + const bool pred_is_header = IsHeader(block); + if (pred_is_header && lab_id != merge_inst->GetSingleWordInOperand(0u)) { + bool succ_is_header = IsHeader(context, lab_id); + if (pred_is_header && succ_is_header) { + // Cannot merge two headers together when the successor is not the merge + // block of the predecessor. + return false; + } + + // If this is a header block and the successor is not its merge, we must + // be careful about which blocks we are willing to merge together. + // OpLoopMerge must be followed by a conditional or unconditional branch. + // The merge must be a loop merge because a selection merge cannot be + // followed by an unconditional branch. + BasicBlock* succ_block = context->get_instr_block(lab_id); + SpvOp succ_term_op = succ_block->terminator()->opcode(); + assert(merge_inst->opcode() == SpvOpLoopMerge); + if (succ_term_op != SpvOpBranch && succ_term_op != SpvOpBranchConditional) { + return false; + } + } + return true; +} + +void MergeWithSuccessor(IRContext* context, Function* func, + Function::iterator bi) { + assert(CanMergeWithSuccessor(context, &*bi) && + "Precondition failure for MergeWithSuccessor: it must be legal to " + "merge the block and its successor."); + + auto ii = bi->end(); + --ii; + Instruction* br = &*ii; + const uint32_t lab_id = br->GetSingleWordInOperand(0); + Instruction* merge_inst = bi->GetMergeInst(); + bool pred_is_header = IsHeader(&*bi); + + // Merge blocks. + context->KillInst(br); + auto sbi = bi; + for (; sbi != func->end(); ++sbi) + if (sbi->id() == lab_id) break; + // If bi is sbi's only predecessor, it dominates sbi and thus + // sbi must follow bi in func's ordering. + assert(sbi != func->end()); + + // Update the inst-to-block mapping for the instructions in sbi. + for (auto& inst : *sbi) { + context->set_instr_block(&inst, &*bi); + } + + EliminateOpPhiInstructions(context, &*sbi); + + // Now actually move the instructions. + bi->AddInstructions(&*sbi); + + if (merge_inst) { + if (pred_is_header && lab_id == merge_inst->GetSingleWordInOperand(0u)) { + // Merging the header and merge blocks, so remove the structured control + // flow declaration. + context->KillInst(merge_inst); + } else { + // Move OpLine/OpNoLine information to merge_inst. This solves + // the validation error that OpLine is placed between OpLoopMerge + // and OpBranchConditional. + auto terminator = bi->terminator(); + auto& vec = terminator->dbg_line_insts(); + auto& new_vec = merge_inst->dbg_line_insts(); + new_vec.insert(new_vec.end(), vec.begin(), vec.end()); + terminator->clear_dbg_line_insts(); + + // Move the merge instruction to just before the terminator. + merge_inst->InsertBefore(terminator); + } + } + context->ReplaceAllUsesWith(lab_id, bi->id()); + context->KillInst(sbi->GetLabelInst()); + (void)sbi.Erase(); +} + +} // namespace blockmergeutil +} // namespace opt +} // namespace spvtools diff --git a/third_party/spirv-tools/source/opt/block_merge_util.h b/third_party/spirv-tools/source/opt/block_merge_util.h new file mode 100644 index 0000000000..e71e3d6ad2 --- /dev/null +++ b/third_party/spirv-tools/source/opt/block_merge_util.h @@ -0,0 +1,44 @@ +// Copyright (c) 2017 The Khronos Group Inc. +// Copyright (c) 2017 Valve Corporation +// Copyright (c) 2017 LunarG Inc. +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_OPT_BLOCK_MERGE_UTIL_H_ +#define SOURCE_OPT_BLOCK_MERGE_UTIL_H_ + +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace opt { + +// Provides functions for determining when it is safe to merge blocks, and for +// actually merging blocks, for use by various analyses and passes. +namespace blockmergeutil { + +// Returns true if and only if |block| has exactly one successor and merging +// this successor into |block| has no impact on the semantics or validity of the +// SPIR-V module. +bool CanMergeWithSuccessor(IRContext* context, BasicBlock* block); + +// Requires that |bi| has a successor that can be safely merged into |bi|, and +// performs the merge. +void MergeWithSuccessor(IRContext* context, Function* func, + Function::iterator bi); + +} // namespace blockmergeutil +} // namespace opt +} // namespace spvtools + +#endif // SOURCE_OPT_BLOCK_MERGE_UTIL_H_ diff --git a/third_party/spirv-tools/source/opt/ccp_pass.cpp b/third_party/spirv-tools/source/opt/ccp_pass.cpp index a8411d9fe1..2de925020d 100644 --- a/third_party/spirv-tools/source/opt/ccp_pass.cpp +++ b/third_party/spirv-tools/source/opt/ccp_pass.cpp @@ -271,6 +271,7 @@ bool CCPPass::ReplaceValues() { uint32_t id = it.first; uint32_t cst_id = it.second; if (!IsVaryingValue(cst_id) && id != cst_id) { + context()->KillNamesAndDecorates(id); retval |= context()->ReplaceAllUsesWith(id, cst_id); } } @@ -319,7 +320,7 @@ Pass::Status CCPPass::Process() { // Process all entry point functions. ProcessFunction pfn = [this](Function* fp) { return PropagateConstants(fp); }; - bool modified = ProcessReachableCallTree(pfn, context()); + bool modified = context()->ProcessReachableCallTree(pfn); return modified ? Pass::Status::SuccessWithChange : Pass::Status::SuccessWithoutChange; } diff --git a/third_party/spirv-tools/source/opt/ccp_pass.h b/third_party/spirv-tools/source/opt/ccp_pass.h index 178fd1281d..527f459c50 100644 --- a/third_party/spirv-tools/source/opt/ccp_pass.h +++ b/third_party/spirv-tools/source/opt/ccp_pass.h @@ -40,7 +40,8 @@ class CCPPass : public MemPass { IRContext::kAnalysisInstrToBlockMapping | IRContext::kAnalysisDecorations | IRContext::kAnalysisCombinators | IRContext::kAnalysisCFG | IRContext::kAnalysisDominatorAnalysis | - IRContext::kAnalysisNameMap; + IRContext::kAnalysisNameMap | IRContext::kAnalysisConstants | + IRContext::kAnalysisTypes; } private: diff --git a/third_party/spirv-tools/source/opt/cfg.cpp b/third_party/spirv-tools/source/opt/cfg.cpp index dcf2b573ff..ac0fcc3685 100644 --- a/third_party/spirv-tools/source/opt/cfg.cpp +++ b/third_party/spirv-tools/source/opt/cfg.cpp @@ -110,15 +110,26 @@ void CFG::ForEachBlockInPostOrder(BasicBlock* bb, void CFG::ForEachBlockInReversePostOrder( BasicBlock* bb, const std::function& f) { + WhileEachBlockInReversePostOrder(bb, [f](BasicBlock* b) { + f(b); + return true; + }); +} + +bool CFG::WhileEachBlockInReversePostOrder( + BasicBlock* bb, const std::function& f) { std::vector po; std::unordered_set seen; ComputePostOrderTraversal(bb, &po, &seen); for (auto current_bb = po.rbegin(); current_bb != po.rend(); ++current_bb) { if (!IsPseudoExitBlock(*current_bb) && !IsPseudoEntryBlock(*current_bb)) { - f(*current_bb); + if (!f(*current_bb)) { + return false; + } } } + return true; } void CFG::ComputeStructuredSuccessors(Function* func) { @@ -150,15 +161,25 @@ void CFG::ComputeStructuredSuccessors(Function* func) { void CFG::ComputePostOrderTraversal(BasicBlock* bb, std::vector* order, std::unordered_set* seen) { - seen->insert(bb); - static_cast(bb)->ForEachSuccessorLabel( - [&order, &seen, this](const uint32_t sbid) { - BasicBlock* succ_bb = id2block_[sbid]; - if (!seen->count(succ_bb)) { - ComputePostOrderTraversal(succ_bb, order, seen); - } - }); - order->push_back(bb); + std::vector stack; + stack.push_back(bb); + while (!stack.empty()) { + bb = stack.back(); + seen->insert(bb); + static_cast(bb)->WhileEachSuccessorLabel( + [&seen, &stack, this](const uint32_t sbid) { + BasicBlock* succ_bb = id2block_[sbid]; + if (!seen->count(succ_bb)) { + stack.push_back(succ_bb); + return false; + } + return true; + }); + if (stack.back() == bb) { + order->push_back(bb); + stack.pop_back(); + } + } } BasicBlock* CFG::SplitLoopHeader(BasicBlock* bb) { @@ -167,6 +188,13 @@ BasicBlock* CFG::SplitLoopHeader(BasicBlock* bb) { Function* fn = bb->GetParent(); IRContext* context = module_->context(); + // Get the new header id up front. If we are out of ids, then we cannot split + // the loop. + uint32_t new_header_id = context->TakeNextId(); + if (new_header_id == 0) { + return nullptr; + } + // Find the insertion point for the new bb. Function::iterator header_it = std::find_if( fn->begin(), fn->end(), @@ -197,15 +225,7 @@ BasicBlock* CFG::SplitLoopHeader(BasicBlock* bb) { ++iter; } - std::unique_ptr newBlock( - bb->SplitBasicBlock(context, context->TakeNextId(), iter)); - - // Insert the new bb in the correct position - auto insert_pos = header_it; - ++insert_pos; - BasicBlock* new_header = &*insert_pos.InsertBefore(std::move(newBlock)); - new_header->SetParent(fn); - uint32_t new_header_id = new_header->id(); + BasicBlock* new_header = bb->SplitBasicBlock(context, new_header_id, iter); context->AnalyzeDefUse(new_header->GetLabelInst()); // Update cfg diff --git a/third_party/spirv-tools/source/opt/cfg.h b/third_party/spirv-tools/source/opt/cfg.h index 375d09c5c7..f280682295 100644 --- a/third_party/spirv-tools/source/opt/cfg.h +++ b/third_party/spirv-tools/source/opt/cfg.h @@ -60,26 +60,35 @@ class CFG { // Compute structured block order into |order| for |func| starting at |root|. // This order has the property that dominators come before all blocks they - // dominate and merge blocks come after all blocks that are in the control - // constructs of their header. + // dominate, merge blocks come after all blocks that are in the control + // constructs of their header, and continue blocks come after all of the + // blocks in the body of their loop. void ComputeStructuredOrder(Function* func, BasicBlock* root, std::list* order); - // Applies |f| to the basic block in post order starting with |bb|. - // Note that basic blocks that cannot be reached from |bb| node will not be - // processed. + // Applies |f| to all blocks that can be reach from |bb| in post order. void ForEachBlockInPostOrder(BasicBlock* bb, const std::function& f); - // Applies |f| to the basic block in reverse post order starting with |bb|. - // Note that basic blocks that cannot be reached from |bb| node will not be - // processed. + // Applies |f| to all blocks that can be reach from |bb| in reverse post + // order. void ForEachBlockInReversePostOrder( BasicBlock* bb, const std::function& f); + // Applies |f| to all blocks that can be reach from |bb| in reverse post + // order. Return false if |f| return false on any basic block, and stops + // processing. + bool WhileEachBlockInReversePostOrder( + BasicBlock* bb, const std::function& f); + // Registers |blk| as a basic block in the cfg, this also updates the - // predecessor lists of each successor of |blk|. + // predecessor lists of each successor of |blk|. |blk| must have a terminator + // instruction at the end of the block. void RegisterBlock(BasicBlock* blk) { + assert(blk->begin() != blk->end() && + "Basic blocks must have a terminator before registering."); + assert(blk->tail()->IsBlockTerminator() && + "Basic blocks must have a terminator before registering."); uint32_t blk_id = blk->id(); id2block_[blk_id] = blk; AddEdges(blk); @@ -123,7 +132,8 @@ class CFG { // id as |block| and will become a preheader for the loop. The other block // is a new block that will be the new loop header. // - // Returns a pointer to the new loop header. + // Returns a pointer to the new loop header. Returns |nullptr| if the new + // loop pointer could not be created. BasicBlock* SplitLoopHeader(BasicBlock* bb); private: diff --git a/third_party/spirv-tools/source/opt/cfg_cleanup_pass.cpp b/third_party/spirv-tools/source/opt/cfg_cleanup_pass.cpp index 2d548462b4..6d48637a45 100644 --- a/third_party/spirv-tools/source/opt/cfg_cleanup_pass.cpp +++ b/third_party/spirv-tools/source/opt/cfg_cleanup_pass.cpp @@ -30,7 +30,7 @@ namespace opt { Pass::Status CFGCleanupPass::Process() { // Process all entry point functions. ProcessFunction pfn = [this](Function* fp) { return CFGCleanup(fp); }; - bool modified = ProcessReachableCallTree(pfn, context()); + bool modified = context()->ProcessReachableCallTree(pfn); return modified ? Pass::Status::SuccessWithChange : Pass::Status::SuccessWithoutChange; } diff --git a/third_party/spirv-tools/source/opt/cfg_cleanup_pass.h b/third_party/spirv-tools/source/opt/cfg_cleanup_pass.h index afbc67c09f..5095428904 100644 --- a/third_party/spirv-tools/source/opt/cfg_cleanup_pass.h +++ b/third_party/spirv-tools/source/opt/cfg_cleanup_pass.h @@ -30,7 +30,8 @@ class CFGCleanupPass : public MemPass { Status Process() override; IRContext::Analysis GetPreservedAnalyses() override { - return IRContext::kAnalysisDefUse; + return IRContext::kAnalysisDefUse | IRContext::kAnalysisConstants | + IRContext::kAnalysisTypes; } }; diff --git a/third_party/spirv-tools/source/opt/code_sink.cpp b/third_party/spirv-tools/source/opt/code_sink.cpp new file mode 100644 index 0000000000..9d54ee5172 --- /dev/null +++ b/third_party/spirv-tools/source/opt/code_sink.cpp @@ -0,0 +1,319 @@ +// Copyright (c) 2019 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 "code_sink.h" + +#include +#include + +#include "source/opt/instruction.h" +#include "source/opt/ir_builder.h" +#include "source/opt/ir_context.h" +#include "source/util/bit_vector.h" + +namespace spvtools { +namespace opt { + +Pass::Status CodeSinkingPass::Process() { + bool modified = false; + for (Function& function : *get_module()) { + cfg()->ForEachBlockInPostOrder(function.entry().get(), + [&modified, this](BasicBlock* bb) { + if (SinkInstructionsInBB(bb)) { + modified = true; + } + }); + } + return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange; +} + +bool CodeSinkingPass::SinkInstructionsInBB(BasicBlock* bb) { + bool modified = false; + for (auto inst = bb->rbegin(); inst != bb->rend(); ++inst) { + if (SinkInstruction(&*inst)) { + inst = bb->rbegin(); + modified = true; + } + } + return modified; +} + +bool CodeSinkingPass::SinkInstruction(Instruction* inst) { + if (inst->opcode() != SpvOpLoad && inst->opcode() != SpvOpAccessChain) { + return false; + } + + if (ReferencesMutableMemory(inst)) { + return false; + } + + if (BasicBlock* target_bb = FindNewBasicBlockFor(inst)) { + Instruction* pos = &*target_bb->begin(); + while (pos->opcode() == SpvOpPhi) { + pos = pos->NextNode(); + } + + inst->InsertBefore(pos); + context()->set_instr_block(inst, target_bb); + return true; + } + return false; +} + +BasicBlock* CodeSinkingPass::FindNewBasicBlockFor(Instruction* inst) { + assert(inst->result_id() != 0 && "Instruction should have a result."); + BasicBlock* original_bb = context()->get_instr_block(inst); + BasicBlock* bb = original_bb; + + std::unordered_set bbs_with_uses; + get_def_use_mgr()->ForEachUse( + inst, [&bbs_with_uses, this](Instruction* use, uint32_t idx) { + if (use->opcode() != SpvOpPhi) { + BasicBlock* use_bb = context()->get_instr_block(use); + if (use_bb) { + bbs_with_uses.insert(use_bb->id()); + } + } else { + bbs_with_uses.insert(use->GetSingleWordOperand(idx + 1)); + } + }); + + while (true) { + // If |inst| is used in |bb|, then |inst| cannot be moved any further. + if (bbs_with_uses.count(bb->id())) { + break; + } + + // If |bb| has one successor (succ_bb), and |bb| is the only predecessor + // of succ_bb, then |inst| can be moved to succ_bb. If succ_bb, has move + // then one predecessor, then moving |inst| into succ_bb could cause it to + // be executed more often, so the search has to stop. + if (bb->terminator()->opcode() == SpvOpBranch) { + uint32_t succ_bb_id = bb->terminator()->GetSingleWordInOperand(0); + if (cfg()->preds(succ_bb_id).size() == 1) { + bb = context()->get_instr_block(succ_bb_id); + continue; + } else { + break; + } + } + + // The remaining checks need to know the merge node. If there is no merge + // instruction or an OpLoopMerge, then it is a break or continue. We could + // figure it out, but not worth doing it now. + Instruction* merge_inst = bb->GetMergeInst(); + if (merge_inst == nullptr || merge_inst->opcode() != SpvOpSelectionMerge) { + break; + } + + // Check all of the successors of |bb| it see which lead to a use of |inst| + // before reaching the merge node. + bool used_in_multiple_blocks = false; + uint32_t bb_used_in = 0; + bb->ForEachSuccessorLabel([this, bb, &bb_used_in, &used_in_multiple_blocks, + &bbs_with_uses](uint32_t* succ_bb_id) { + if (IntersectsPath(*succ_bb_id, bb->MergeBlockIdIfAny(), bbs_with_uses)) { + if (bb_used_in == 0) { + bb_used_in = *succ_bb_id; + } else { + used_in_multiple_blocks = true; + } + } + }); + + // If more than one successor, which is not the merge block, uses |inst| + // then we have to leave |inst| in bb because there is none of the + // successors dominate all uses of |inst|. + if (used_in_multiple_blocks) { + break; + } + + if (bb_used_in == 0) { + // If |inst| is not used before reaching the merge node, then we can move + // |inst| to the merge node. + bb = context()->get_instr_block(bb->MergeBlockIdIfAny()); + } else { + // If the only successor that leads to a used of |inst| has more than 1 + // predecessor, then moving |inst| could cause it to be executed more + // often, so we cannot move it. + if (cfg()->preds(bb_used_in).size() != 1) { + break; + } + + // If |inst| is used after the merge block, then |bb_used_in| does not + // dominate all of the uses. So we cannot move |inst| any further. + if (IntersectsPath(bb->MergeBlockIdIfAny(), original_bb->id(), + bbs_with_uses)) { + break; + } + + // Otherwise, |bb_used_in| dominates all uses, so move |inst| into that + // block. + bb = context()->get_instr_block(bb_used_in); + } + continue; + } + return (bb != original_bb ? bb : nullptr); +} + +bool CodeSinkingPass::ReferencesMutableMemory(Instruction* inst) { + if (!inst->IsLoad()) { + return false; + } + + Instruction* base_ptr = inst->GetBaseAddress(); + if (base_ptr->opcode() != SpvOpVariable) { + return true; + } + + if (base_ptr->IsReadOnlyVariable()) { + return false; + } + + if (HasUniformMemorySync()) { + return true; + } + + if (base_ptr->GetSingleWordInOperand(0) != SpvStorageClassUniform) { + return true; + } + + return HasPossibleStore(base_ptr); +} + +bool CodeSinkingPass::HasUniformMemorySync() { + if (checked_for_uniform_sync_) { + return has_uniform_sync_; + } + + bool has_sync = false; + get_module()->ForEachInst([this, &has_sync](Instruction* inst) { + switch (inst->opcode()) { + case SpvOpMemoryBarrier: { + uint32_t mem_semantics_id = inst->GetSingleWordInOperand(1); + if (IsSyncOnUniform(mem_semantics_id)) { + has_sync = true; + } + break; + } + case SpvOpControlBarrier: + case SpvOpAtomicLoad: + case SpvOpAtomicStore: + case SpvOpAtomicExchange: + case SpvOpAtomicIIncrement: + case SpvOpAtomicIDecrement: + case SpvOpAtomicIAdd: + case SpvOpAtomicISub: + case SpvOpAtomicSMin: + case SpvOpAtomicUMin: + case SpvOpAtomicSMax: + case SpvOpAtomicUMax: + case SpvOpAtomicAnd: + case SpvOpAtomicOr: + case SpvOpAtomicXor: + case SpvOpAtomicFlagTestAndSet: + case SpvOpAtomicFlagClear: { + uint32_t mem_semantics_id = inst->GetSingleWordInOperand(2); + if (IsSyncOnUniform(mem_semantics_id)) { + has_sync = true; + } + break; + } + case SpvOpAtomicCompareExchange: + case SpvOpAtomicCompareExchangeWeak: + if (IsSyncOnUniform(inst->GetSingleWordInOperand(2)) || + IsSyncOnUniform(inst->GetSingleWordInOperand(3))) { + has_sync = true; + } + break; + default: + break; + } + }); + has_uniform_sync_ = has_sync; + return has_sync; +} + +bool CodeSinkingPass::IsSyncOnUniform(uint32_t mem_semantics_id) const { + const analysis::Constant* mem_semantics_const = + context()->get_constant_mgr()->FindDeclaredConstant(mem_semantics_id); + assert(mem_semantics_const != nullptr && + "Expecting memory semantics id to be a constant."); + assert(mem_semantics_const->AsIntConstant() && + "Memory semantics should be an integer."); + uint32_t mem_semantics_int = mem_semantics_const->GetU32(); + + // If it does not affect uniform memory, then it is does not apply to uniform + // memory. + if ((mem_semantics_int & SpvMemorySemanticsUniformMemoryMask) == 0) { + return false; + } + + // Check if there is an acquire or release. If so not, this it does not add + // any memory constraints. + return (mem_semantics_int & (SpvMemorySemanticsAcquireMask | + SpvMemorySemanticsAcquireReleaseMask | + SpvMemorySemanticsReleaseMask)) != 0; +} + +bool CodeSinkingPass::HasPossibleStore(Instruction* var_inst) { + assert(var_inst->opcode() == SpvOpVariable || + var_inst->opcode() == SpvOpAccessChain || + var_inst->opcode() == SpvOpPtrAccessChain); + + return get_def_use_mgr()->WhileEachUser(var_inst, [this](Instruction* use) { + switch (use->opcode()) { + case SpvOpStore: + return true; + case SpvOpAccessChain: + case SpvOpPtrAccessChain: + return HasPossibleStore(use); + default: + return false; + } + }); +} + +bool CodeSinkingPass::IntersectsPath(uint32_t start, uint32_t end, + const std::unordered_set& set) { + std::vector worklist; + worklist.push_back(start); + std::unordered_set already_done; + already_done.insert(start); + + while (!worklist.empty()) { + BasicBlock* bb = context()->get_instr_block(worklist.back()); + worklist.pop_back(); + + if (bb->id() == end) { + continue; + } + + if (set.count(bb->id())) { + return true; + } + + bb->ForEachSuccessorLabel([&already_done, &worklist](uint32_t* succ_bb_id) { + if (already_done.insert(*succ_bb_id).second) { + worklist.push_back(*succ_bb_id); + } + }); + } + return false; +} + +// namespace opt + +} // namespace opt +} // namespace spvtools diff --git a/third_party/spirv-tools/source/opt/code_sink.h b/third_party/spirv-tools/source/opt/code_sink.h new file mode 100644 index 0000000000..d24df030df --- /dev/null +++ b/third_party/spirv-tools/source/opt/code_sink.h @@ -0,0 +1,107 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_OPT_CODE_SINK_H_ +#define SOURCE_OPT_CODE_SINK_H_ + +#include + +#include "source/opt/ir_context.h" +#include "source/opt/module.h" +#include "source/opt/pass.h" + +namespace spvtools { +namespace opt { + +// This pass does code sinking for OpAccessChain and OpLoad on variables in +// uniform storage or in read only memory. Code sinking is a transformation +// where an instruction is moved into a more deeply nested construct. +// +// The goal is to move these instructions as close as possible to their uses +// without having to execute them more often or to replicate the instruction. +// Moving the instruction in this way can lead to shorter live ranges, which can +// lead to less register pressure. It can also cause instructions to be +// executed less often because they could be moved into one path of a selection +// construct. +// +// This optimization can cause register pressure to rise if the operands of the +// instructions go dead after the instructions being moved. That is why we only +// move certain OpLoad and OpAccessChain instructions. They generally have +// constants, loop induction variables, and global pointers as operands. The +// operands are live for a longer time in most cases. +class CodeSinkingPass : public Pass { + public: + const char* name() const override { return "code-sink"; } + Status Process() override; + + // Return the mask of preserved Analyses. + IRContext::Analysis GetPreservedAnalyses() override { + return IRContext::kAnalysisDefUse | + IRContext::kAnalysisInstrToBlockMapping | + IRContext::kAnalysisCombinators | IRContext::kAnalysisCFG | + IRContext::kAnalysisDominatorAnalysis | + IRContext::kAnalysisLoopAnalysis | IRContext::kAnalysisNameMap | + IRContext::kAnalysisConstants | IRContext::kAnalysisTypes; + } + + private: + // Sinks the instructions in |bb| as much as possible. Returns true if + // something changes. + bool SinkInstructionsInBB(BasicBlock* bb); + + // Tries the sink |inst| as much as possible. Returns true if the instruction + // is moved. + bool SinkInstruction(Instruction* inst); + + // Returns the basic block in which to move |inst| to move is as close as + // possible to the uses of |inst| without increasing the number of times + // |inst| will be executed. Return |nullptr| if there is no need to move + // |inst|. + BasicBlock* FindNewBasicBlockFor(Instruction* inst); + + // Return true if |inst| reference memory and it is possible that the data in + // the memory changes at some point. + bool ReferencesMutableMemory(Instruction* inst); + + // Returns true if the module contains an instruction that has a memory + // semantics id as an operand, and the memory semantics enforces a + // synchronization of uniform memory. See section 3.25 of the SPIR-V + // specification. + bool HasUniformMemorySync(); + + // Returns true if there may be a store to the variable |var_inst|. + bool HasPossibleStore(Instruction* var_inst); + + // Returns true if one of the basic blocks in |set| exists on a path from the + // basic block |start| to |end|. + bool IntersectsPath(uint32_t start, uint32_t end, + const std::unordered_set& set); + + // Returns true if |mem_semantics_id| is the id of a constant that, when + // interpreted as a memory semantics mask enforces synchronization of uniform + // memory. See section 3.25 of the SPIR-V specification. + bool IsSyncOnUniform(uint32_t mem_semantics_id) const; + + // True if a check has for uniform storage has taken place. + bool checked_for_uniform_sync_; + + // Cache of whether or not the module has a memory sync on uniform storage. + // only valid if |check_for_uniform_sync_| is true. + bool has_uniform_sync_; +}; + +} // namespace opt +} // namespace spvtools + +#endif // SOURCE_OPT_CODE_SINK_H_ diff --git a/third_party/spirv-tools/source/opt/combine_access_chains.h b/third_party/spirv-tools/source/opt/combine_access_chains.h index 75885dadaf..531209ec10 100644 --- a/third_party/spirv-tools/source/opt/combine_access_chains.h +++ b/third_party/spirv-tools/source/opt/combine_access_chains.h @@ -33,7 +33,8 @@ class CombineAccessChains : public Pass { IRContext::kAnalysisInstrToBlockMapping | IRContext::kAnalysisDecorations | IRContext::kAnalysisCombinators | IRContext::kAnalysisCFG | IRContext::kAnalysisDominatorAnalysis | - IRContext::kAnalysisNameMap; + IRContext::kAnalysisNameMap | IRContext::kAnalysisConstants | + IRContext::kAnalysisTypes; } private: diff --git a/third_party/spirv-tools/source/opt/common_uniform_elim_pass.cpp b/third_party/spirv-tools/source/opt/common_uniform_elim_pass.cpp deleted file mode 100644 index e6426a555d..0000000000 --- a/third_party/spirv-tools/source/opt/common_uniform_elim_pass.cpp +++ /dev/null @@ -1,580 +0,0 @@ -// Copyright (c) 2017 The Khronos Group Inc. -// Copyright (c) 2017 Valve Corporation -// Copyright (c) 2017 LunarG Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/opt/common_uniform_elim_pass.h" -#include "source/cfa.h" -#include "source/opt/ir_context.h" - -namespace spvtools { -namespace opt { - -namespace { - -const uint32_t kAccessChainPtrIdInIdx = 0; -const uint32_t kTypePointerStorageClassInIdx = 0; -const uint32_t kTypePointerTypeIdInIdx = 1; -const uint32_t kConstantValueInIdx = 0; -const uint32_t kExtractCompositeIdInIdx = 0; -const uint32_t kExtractIdx0InIdx = 1; -const uint32_t kStorePtrIdInIdx = 0; -const uint32_t kLoadPtrIdInIdx = 0; -const uint32_t kCopyObjectOperandInIdx = 0; -const uint32_t kTypeIntWidthInIdx = 0; - -} // anonymous namespace - -bool CommonUniformElimPass::IsNonPtrAccessChain(const SpvOp opcode) const { - return opcode == SpvOpAccessChain || opcode == SpvOpInBoundsAccessChain; -} - -bool CommonUniformElimPass::IsSamplerOrImageType( - const Instruction* typeInst) const { - switch (typeInst->opcode()) { - case SpvOpTypeSampler: - case SpvOpTypeImage: - case SpvOpTypeSampledImage: - return true; - default: - break; - } - if (typeInst->opcode() != SpvOpTypeStruct) return false; - // Return true if any member is a sampler or image - return !typeInst->WhileEachInId([this](const uint32_t* tid) { - const Instruction* compTypeInst = get_def_use_mgr()->GetDef(*tid); - if (IsSamplerOrImageType(compTypeInst)) { - return false; - } - return true; - }); -} - -bool CommonUniformElimPass::IsSamplerOrImageVar(uint32_t varId) const { - const Instruction* varInst = get_def_use_mgr()->GetDef(varId); - assert(varInst->opcode() == SpvOpVariable); - const uint32_t varTypeId = varInst->type_id(); - const Instruction* varTypeInst = get_def_use_mgr()->GetDef(varTypeId); - const uint32_t varPteTypeId = - varTypeInst->GetSingleWordInOperand(kTypePointerTypeIdInIdx); - Instruction* varPteTypeInst = get_def_use_mgr()->GetDef(varPteTypeId); - return IsSamplerOrImageType(varPteTypeInst); -} - -Instruction* CommonUniformElimPass::GetPtr(Instruction* ip, uint32_t* objId) { - const SpvOp op = ip->opcode(); - assert(op == SpvOpStore || op == SpvOpLoad); - *objId = ip->GetSingleWordInOperand(op == SpvOpStore ? kStorePtrIdInIdx - : kLoadPtrIdInIdx); - Instruction* ptrInst = get_def_use_mgr()->GetDef(*objId); - while (ptrInst->opcode() == SpvOpCopyObject) { - *objId = ptrInst->GetSingleWordInOperand(kCopyObjectOperandInIdx); - ptrInst = get_def_use_mgr()->GetDef(*objId); - } - Instruction* objInst = ptrInst; - while (objInst->opcode() != SpvOpVariable && - objInst->opcode() != SpvOpFunctionParameter) { - if (IsNonPtrAccessChain(objInst->opcode())) { - *objId = objInst->GetSingleWordInOperand(kAccessChainPtrIdInIdx); - } else { - assert(objInst->opcode() == SpvOpCopyObject); - *objId = objInst->GetSingleWordInOperand(kCopyObjectOperandInIdx); - } - objInst = get_def_use_mgr()->GetDef(*objId); - } - return ptrInst; -} - -bool CommonUniformElimPass::IsVolatileStruct(uint32_t type_id) { - assert(get_def_use_mgr()->GetDef(type_id)->opcode() == SpvOpTypeStruct); - return !get_decoration_mgr()->WhileEachDecoration( - type_id, SpvDecorationVolatile, [](const Instruction&) { return false; }); -} - -bool CommonUniformElimPass::IsAccessChainToVolatileStructType( - const Instruction& AccessChainInst) { - assert(AccessChainInst.opcode() == SpvOpAccessChain); - - uint32_t ptr_id = AccessChainInst.GetSingleWordInOperand(0); - const Instruction* ptr_inst = get_def_use_mgr()->GetDef(ptr_id); - uint32_t pointee_type_id = GetPointeeTypeId(ptr_inst); - const uint32_t num_operands = AccessChainInst.NumOperands(); - - // walk the type tree: - for (uint32_t idx = 3; idx < num_operands; ++idx) { - Instruction* pointee_type = get_def_use_mgr()->GetDef(pointee_type_id); - - switch (pointee_type->opcode()) { - case SpvOpTypeMatrix: - case SpvOpTypeVector: - case SpvOpTypeArray: - case SpvOpTypeRuntimeArray: - pointee_type_id = pointee_type->GetSingleWordOperand(1); - break; - case SpvOpTypeStruct: - // check for volatile decorations: - if (IsVolatileStruct(pointee_type_id)) return true; - - if (idx < num_operands - 1) { - const uint32_t index_id = AccessChainInst.GetSingleWordOperand(idx); - const Instruction* index_inst = get_def_use_mgr()->GetDef(index_id); - uint32_t index_value = index_inst->GetSingleWordOperand( - 2); // TODO: replace with GetUintValueFromConstant() - pointee_type_id = pointee_type->GetSingleWordInOperand(index_value); - } - break; - default: - assert(false && "Unhandled pointee type."); - } - } - return false; -} - -bool CommonUniformElimPass::IsVolatileLoad(const Instruction& loadInst) { - assert(loadInst.opcode() == SpvOpLoad); - // Check if this Load instruction has Volatile Memory Access flag - if (loadInst.NumOperands() == 4) { - uint32_t memory_access_mask = loadInst.GetSingleWordOperand(3); - if (memory_access_mask & SpvMemoryAccessVolatileMask) return true; - } - // If we load a struct directly (result type is struct), - // check if the struct is decorated volatile - uint32_t type_id = loadInst.type_id(); - if (get_def_use_mgr()->GetDef(type_id)->opcode() == SpvOpTypeStruct) - return IsVolatileStruct(type_id); - else - return false; -} - -bool CommonUniformElimPass::IsUniformVar(uint32_t varId) { - const Instruction* varInst = - get_def_use_mgr()->id_to_defs().find(varId)->second; - if (varInst->opcode() != SpvOpVariable) return false; - const uint32_t varTypeId = varInst->type_id(); - const Instruction* varTypeInst = - get_def_use_mgr()->id_to_defs().find(varTypeId)->second; - return varTypeInst->GetSingleWordInOperand(kTypePointerStorageClassInIdx) == - SpvStorageClassUniform || - varTypeInst->GetSingleWordInOperand(kTypePointerStorageClassInIdx) == - SpvStorageClassUniformConstant; -} - -bool CommonUniformElimPass::HasUnsupportedDecorates(uint32_t id) const { - return !get_def_use_mgr()->WhileEachUser(id, [this](Instruction* user) { - if (IsNonTypeDecorate(user->opcode())) return false; - return true; - }); -} - -bool CommonUniformElimPass::HasOnlyNamesAndDecorates(uint32_t id) const { - return get_def_use_mgr()->WhileEachUser(id, [this](Instruction* user) { - SpvOp op = user->opcode(); - if (op != SpvOpName && !IsNonTypeDecorate(op)) return false; - return true; - }); -} - -void CommonUniformElimPass::DeleteIfUseless(Instruction* inst) { - const uint32_t resId = inst->result_id(); - assert(resId != 0); - if (HasOnlyNamesAndDecorates(resId)) { - context()->KillInst(inst); - } -} - -Instruction* CommonUniformElimPass::ReplaceAndDeleteLoad(Instruction* loadInst, - uint32_t replId, - Instruction* ptrInst) { - const uint32_t loadId = loadInst->result_id(); - context()->KillNamesAndDecorates(loadId); - (void)context()->ReplaceAllUsesWith(loadId, replId); - // remove load instruction - Instruction* next_instruction = context()->KillInst(loadInst); - // if access chain, see if it can be removed as well - if (IsNonPtrAccessChain(ptrInst->opcode())) DeleteIfUseless(ptrInst); - return next_instruction; -} - -void CommonUniformElimPass::GenACLoadRepl( - const Instruction* ptrInst, - std::vector>* newInsts, uint32_t* resultId) { - // Build and append Load - const uint32_t ldResultId = TakeNextId(); - const uint32_t varId = - ptrInst->GetSingleWordInOperand(kAccessChainPtrIdInIdx); - const Instruction* varInst = get_def_use_mgr()->GetDef(varId); - assert(varInst->opcode() == SpvOpVariable); - const uint32_t varPteTypeId = GetPointeeTypeId(varInst); - std::vector load_in_operands; - load_in_operands.push_back(Operand(spv_operand_type_t::SPV_OPERAND_TYPE_ID, - std::initializer_list{varId})); - std::unique_ptr newLoad(new Instruction( - context(), SpvOpLoad, varPteTypeId, ldResultId, load_in_operands)); - get_def_use_mgr()->AnalyzeInstDefUse(&*newLoad); - newInsts->emplace_back(std::move(newLoad)); - - // Build and append Extract - const uint32_t extResultId = TakeNextId(); - const uint32_t ptrPteTypeId = GetPointeeTypeId(ptrInst); - std::vector ext_in_opnds; - ext_in_opnds.push_back(Operand(spv_operand_type_t::SPV_OPERAND_TYPE_ID, - std::initializer_list{ldResultId})); - uint32_t iidIdx = 0; - ptrInst->ForEachInId([&iidIdx, &ext_in_opnds, this](const uint32_t* iid) { - if (iidIdx > 0) { - const Instruction* cInst = get_def_use_mgr()->GetDef(*iid); - uint32_t val = cInst->GetSingleWordInOperand(kConstantValueInIdx); - ext_in_opnds.push_back( - Operand(spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, - std::initializer_list{val})); - } - ++iidIdx; - }); - std::unique_ptr newExt( - new Instruction(context(), SpvOpCompositeExtract, ptrPteTypeId, - extResultId, ext_in_opnds)); - get_def_use_mgr()->AnalyzeInstDefUse(&*newExt); - newInsts->emplace_back(std::move(newExt)); - *resultId = extResultId; -} - -bool CommonUniformElimPass::IsConstantIndexAccessChain(Instruction* acp) { - uint32_t inIdx = 0; - return acp->WhileEachInId([&inIdx, this](uint32_t* tid) { - if (inIdx > 0) { - Instruction* opInst = get_def_use_mgr()->GetDef(*tid); - if (opInst->opcode() != SpvOpConstant) return false; - } - ++inIdx; - return true; - }); -} - -bool CommonUniformElimPass::UniformAccessChainConvert(Function* func) { - bool modified = false; - for (auto bi = func->begin(); bi != func->end(); ++bi) { - for (Instruction* inst = &*bi->begin(); inst; inst = inst->NextNode()) { - if (inst->opcode() != SpvOpLoad) continue; - uint32_t varId; - Instruction* ptrInst = GetPtr(inst, &varId); - if (!IsNonPtrAccessChain(ptrInst->opcode())) continue; - // Do not convert nested access chains - if (ptrInst->GetSingleWordInOperand(kAccessChainPtrIdInIdx) != varId) - continue; - if (!IsUniformVar(varId)) continue; - if (!IsConstantIndexAccessChain(ptrInst)) continue; - if (HasUnsupportedDecorates(inst->result_id())) continue; - if (HasUnsupportedDecorates(ptrInst->result_id())) continue; - if (IsVolatileLoad(*inst)) continue; - if (IsAccessChainToVolatileStructType(*ptrInst)) continue; - std::vector> newInsts; - uint32_t replId; - GenACLoadRepl(ptrInst, &newInsts, &replId); - inst = ReplaceAndDeleteLoad(inst, replId, ptrInst); - inst = inst->InsertBefore(std::move(newInsts)); - modified = true; - } - } - return modified; -} - -void CommonUniformElimPass::ComputeStructuredSuccessors(Function* func) { - block2structured_succs_.clear(); - for (auto& blk : *func) { - // If header, make merge block first successor. - uint32_t mbid = blk.MergeBlockIdIfAny(); - if (mbid != 0) { - block2structured_succs_[&blk].push_back(cfg()->block(mbid)); - uint32_t cbid = blk.ContinueBlockIdIfAny(); - if (cbid != 0) { - block2structured_succs_[&blk].push_back(cfg()->block(mbid)); - } - } - // add true successors - const auto& const_blk = blk; - const_blk.ForEachSuccessorLabel([&blk, this](const uint32_t sbid) { - block2structured_succs_[&blk].push_back(cfg()->block(sbid)); - }); - } -} - -void CommonUniformElimPass::ComputeStructuredOrder( - Function* func, std::list* order) { - // Compute structured successors and do DFS - ComputeStructuredSuccessors(func); - auto ignore_block = [](cbb_ptr) {}; - auto ignore_edge = [](cbb_ptr, cbb_ptr) {}; - auto get_structured_successors = [this](const BasicBlock* block) { - return &(block2structured_succs_[block]); - }; - // TODO(greg-lunarg): Get rid of const_cast by making moving const - // out of the cfa.h prototypes and into the invoking code. - auto post_order = [&](cbb_ptr b) { - order->push_front(const_cast(b)); - }; - - order->clear(); - CFA::DepthFirstTraversal(&*func->begin(), - get_structured_successors, ignore_block, - post_order, ignore_edge); -} - -bool CommonUniformElimPass::CommonUniformLoadElimination(Function* func) { - // Process all blocks in structured order. This is just one way (the - // simplest?) to keep track of the most recent block outside of control - // flow, used to copy common instructions, guaranteed to dominate all - // following load sites. - std::list structuredOrder; - ComputeStructuredOrder(func, &structuredOrder); - uniform2load_id_.clear(); - bool modified = false; - // Find insertion point in first block to copy non-dominating loads. - auto insertItr = func->begin()->begin(); - while (insertItr->opcode() == SpvOpVariable || - insertItr->opcode() == SpvOpNop) - ++insertItr; - // Update insertItr until it will not be removed. Without this code, - // ReplaceAndDeleteLoad() can set |insertItr| as a dangling pointer. - while (IsUniformLoadToBeRemoved(&*insertItr)) ++insertItr; - uint32_t mergeBlockId = 0; - for (auto bi = structuredOrder.begin(); bi != structuredOrder.end(); ++bi) { - BasicBlock* bp = *bi; - // Check if we are exiting outermost control construct. If so, remember - // new load insertion point. Trying to keep register pressure down. - if (mergeBlockId == bp->id()) { - mergeBlockId = 0; - insertItr = bp->begin(); - // Update insertItr until it will not be removed. Without this code, - // ReplaceAndDeleteLoad() can set |insertItr| as a dangling pointer. - while (IsUniformLoadToBeRemoved(&*insertItr)) ++insertItr; - } - for (Instruction* inst = &*bp->begin(); inst; inst = inst->NextNode()) { - if (inst->opcode() != SpvOpLoad) continue; - uint32_t varId; - Instruction* ptrInst = GetPtr(inst, &varId); - if (ptrInst->opcode() != SpvOpVariable) continue; - if (!IsUniformVar(varId)) continue; - if (IsSamplerOrImageVar(varId)) continue; - if (HasUnsupportedDecorates(inst->result_id())) continue; - if (IsVolatileLoad(*inst)) continue; - uint32_t replId; - const auto uItr = uniform2load_id_.find(varId); - if (uItr != uniform2load_id_.end()) { - replId = uItr->second; - } else { - if (mergeBlockId == 0) { - // Load is in dominating block; just remember it - uniform2load_id_[varId] = inst->result_id(); - continue; - } else { - // Copy load into most recent dominating block and remember it - replId = TakeNextId(); - std::unique_ptr newLoad(new Instruction( - context(), SpvOpLoad, inst->type_id(), replId, - {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {varId}}})); - get_def_use_mgr()->AnalyzeInstDefUse(&*newLoad); - insertItr = insertItr.InsertBefore(std::move(newLoad)); - ++insertItr; - uniform2load_id_[varId] = replId; - } - } - inst = ReplaceAndDeleteLoad(inst, replId, ptrInst); - modified = true; - } - // If we are outside of any control construct and entering one, remember - // the id of the merge block - if (mergeBlockId == 0) { - mergeBlockId = bp->MergeBlockIdIfAny(); - } - } - return modified; -} - -bool CommonUniformElimPass::CommonUniformLoadElimBlock(Function* func) { - bool modified = false; - for (auto& blk : *func) { - uniform2load_id_.clear(); - for (Instruction* inst = &*blk.begin(); inst; inst = inst->NextNode()) { - if (inst->opcode() != SpvOpLoad) continue; - uint32_t varId; - Instruction* ptrInst = GetPtr(inst, &varId); - if (ptrInst->opcode() != SpvOpVariable) continue; - if (!IsUniformVar(varId)) continue; - if (!IsSamplerOrImageVar(varId)) continue; - if (HasUnsupportedDecorates(inst->result_id())) continue; - if (IsVolatileLoad(*inst)) continue; - uint32_t replId; - const auto uItr = uniform2load_id_.find(varId); - if (uItr != uniform2load_id_.end()) { - replId = uItr->second; - } else { - uniform2load_id_[varId] = inst->result_id(); - continue; - } - inst = ReplaceAndDeleteLoad(inst, replId, ptrInst); - modified = true; - } - } - return modified; -} - -bool CommonUniformElimPass::CommonExtractElimination(Function* func) { - // Find all composite ids with duplicate extracts. - for (auto bi = func->begin(); bi != func->end(); ++bi) { - for (auto ii = bi->begin(); ii != bi->end(); ++ii) { - if (ii->opcode() != SpvOpCompositeExtract) continue; - // TODO(greg-lunarg): Support multiple indices - if (ii->NumInOperands() > 2) continue; - if (HasUnsupportedDecorates(ii->result_id())) continue; - uint32_t compId = ii->GetSingleWordInOperand(kExtractCompositeIdInIdx); - uint32_t idx = ii->GetSingleWordInOperand(kExtractIdx0InIdx); - comp2idx2inst_[compId][idx].push_back(&*ii); - } - } - // For all defs of ids with duplicate extracts, insert new extracts - // after def, and replace and delete old extracts - bool modified = false; - for (auto bi = func->begin(); bi != func->end(); ++bi) { - for (auto ii = bi->begin(); ii != bi->end(); ++ii) { - const auto cItr = comp2idx2inst_.find(ii->result_id()); - if (cItr == comp2idx2inst_.end()) continue; - for (auto idxItr : cItr->second) { - if (idxItr.second.size() < 2) continue; - uint32_t replId = TakeNextId(); - std::unique_ptr newExtract( - idxItr.second.front()->Clone(context())); - newExtract->SetResultId(replId); - get_def_use_mgr()->AnalyzeInstDefUse(&*newExtract); - ++ii; - ii = ii.InsertBefore(std::move(newExtract)); - for (auto instItr : idxItr.second) { - uint32_t resId = instItr->result_id(); - context()->KillNamesAndDecorates(resId); - (void)context()->ReplaceAllUsesWith(resId, replId); - context()->KillInst(instItr); - } - modified = true; - } - } - } - return modified; -} - -bool CommonUniformElimPass::EliminateCommonUniform(Function* func) { - bool modified = false; - modified |= UniformAccessChainConvert(func); - modified |= CommonUniformLoadElimination(func); - modified |= CommonExtractElimination(func); - - modified |= CommonUniformLoadElimBlock(func); - return modified; -} - -void CommonUniformElimPass::Initialize() { - // Clear collections. - comp2idx2inst_.clear(); - - // Initialize extension whitelist - InitExtensions(); -} - -bool CommonUniformElimPass::AllExtensionsSupported() const { - // If any extension not in whitelist, return false - for (auto& ei : get_module()->extensions()) { - const char* extName = - reinterpret_cast(&ei.GetInOperand(0).words[0]); - if (extensions_whitelist_.find(extName) == extensions_whitelist_.end()) - return false; - } - return true; -} - -Pass::Status CommonUniformElimPass::ProcessImpl() { - // Assumes all control flow structured. - // TODO(greg-lunarg): Do SSA rewrite for non-structured control flow - if (!context()->get_feature_mgr()->HasCapability(SpvCapabilityShader)) - return Status::SuccessWithoutChange; - // Assumes logical addressing only - // TODO(greg-lunarg): Add support for physical addressing - if (context()->get_feature_mgr()->HasCapability(SpvCapabilityAddresses)) - return Status::SuccessWithoutChange; - // Do not process if any disallowed extensions are enabled - if (!AllExtensionsSupported()) return Status::SuccessWithoutChange; - // Do not process if module contains OpGroupDecorate. Additional - // support required in KillNamesAndDecorates(). - // TODO(greg-lunarg): Add support for OpGroupDecorate - for (auto& ai : get_module()->annotations()) - if (ai.opcode() == SpvOpGroupDecorate) return Status::SuccessWithoutChange; - // If non-32-bit integer type in module, terminate processing - // TODO(): Handle non-32-bit integer constants in access chains - for (const Instruction& inst : get_module()->types_values()) - if (inst.opcode() == SpvOpTypeInt && - inst.GetSingleWordInOperand(kTypeIntWidthInIdx) != 32) - return Status::SuccessWithoutChange; - // Process entry point functions - ProcessFunction pfn = [this](Function* fp) { - return EliminateCommonUniform(fp); - }; - bool modified = ProcessEntryPointCallTree(pfn, get_module()); - return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange; -} - -CommonUniformElimPass::CommonUniformElimPass() = default; - -Pass::Status CommonUniformElimPass::Process() { - Initialize(); - return ProcessImpl(); -} - -void CommonUniformElimPass::InitExtensions() { - extensions_whitelist_.clear(); - extensions_whitelist_.insert({ - "SPV_AMD_shader_explicit_vertex_parameter", - "SPV_AMD_shader_trinary_minmax", - "SPV_AMD_gcn_shader", - "SPV_KHR_shader_ballot", - "SPV_AMD_shader_ballot", - "SPV_AMD_gpu_shader_half_float", - "SPV_KHR_shader_draw_parameters", - "SPV_KHR_subgroup_vote", - "SPV_KHR_16bit_storage", - "SPV_KHR_device_group", - "SPV_KHR_multiview", - "SPV_NVX_multiview_per_view_attributes", - "SPV_NV_viewport_array2", - "SPV_NV_stereo_view_rendering", - "SPV_NV_sample_mask_override_coverage", - "SPV_NV_geometry_shader_passthrough", - "SPV_AMD_texture_gather_bias_lod", - "SPV_KHR_storage_buffer_storage_class", - // SPV_KHR_variable_pointers - // Currently do not support extended pointer expressions - "SPV_AMD_gpu_shader_int16", - "SPV_KHR_post_depth_coverage", - "SPV_KHR_shader_atomic_counter_ops", - "SPV_EXT_shader_stencil_export", - "SPV_EXT_shader_viewport_index_layer", - "SPV_AMD_shader_image_load_store_lod", - "SPV_AMD_shader_fragment_mask", - "SPV_EXT_fragment_fully_covered", - "SPV_AMD_gpu_shader_half_float_fetch", - "SPV_GOOGLE_decorate_string", - "SPV_GOOGLE_hlsl_functionality1", - "SPV_NV_shader_subgroup_partitioned", - "SPV_EXT_descriptor_indexing", - }); -} - -} // namespace opt -} // namespace spvtools diff --git a/third_party/spirv-tools/source/opt/common_uniform_elim_pass.h b/third_party/spirv-tools/source/opt/common_uniform_elim_pass.h deleted file mode 100644 index e6ef69c5dc..0000000000 --- a/third_party/spirv-tools/source/opt/common_uniform_elim_pass.h +++ /dev/null @@ -1,213 +0,0 @@ -// Copyright (c) 2016 The Khronos Group Inc. -// Copyright (c) 2016 Valve Corporation -// Copyright (c) 2016 LunarG Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_OPT_COMMON_UNIFORM_ELIM_PASS_H_ -#define SOURCE_OPT_COMMON_UNIFORM_ELIM_PASS_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "source/opt/basic_block.h" -#include "source/opt/decoration_manager.h" -#include "source/opt/def_use_manager.h" -#include "source/opt/ir_context.h" -#include "source/opt/module.h" -#include "source/opt/pass.h" - -namespace spvtools { -namespace opt { - -// See optimizer.hpp for documentation. -class CommonUniformElimPass : public Pass { - using cbb_ptr = const BasicBlock*; - - public: - using GetBlocksFunction = - std::function*(const BasicBlock*)>; - - CommonUniformElimPass(); - - const char* name() const override { return "eliminate-common-uniform"; } - Status Process() override; - - private: - // Returns true if |opcode| is a non-ptr access chain op - bool IsNonPtrAccessChain(const SpvOp opcode) const; - - // Returns true if |typeInst| is a sampler or image type or a struct - // containing one, recursively. - bool IsSamplerOrImageType(const Instruction* typeInst) const; - - // Returns true if |varId| is a variable containing a sampler or image. - bool IsSamplerOrImageVar(uint32_t varId) const; - - // Given a load or store pointed at by |ip|, return the top-most - // non-CopyObj in its pointer operand. Also return the base pointer - // in |objId|. - Instruction* GetPtr(Instruction* ip, uint32_t* objId); - - // Return true if variable is uniform - bool IsUniformVar(uint32_t varId); - - // Given the type id for a struct type, checks if the struct type - // or any struct member is volatile decorated - bool IsVolatileStruct(uint32_t type_id); - - // Given an OpAccessChain instruction, return true - // if the accessed variable belongs to a volatile - // decorated object or member of a struct type - bool IsAccessChainToVolatileStructType(const Instruction& AccessChainInst); - - // Given an OpLoad instruction, return true if - // OpLoad has a Volatile Memory Access flag or if - // the resulting type is a volatile decorated struct - bool IsVolatileLoad(const Instruction& loadInst); - - // Return true if any uses of |id| are decorate ops. - bool HasUnsupportedDecorates(uint32_t id) const; - - // Return true if all uses of |id| are only name or decorate ops. - bool HasOnlyNamesAndDecorates(uint32_t id) const; - - // Delete inst if it has no uses. Assumes inst has a resultId. - void DeleteIfUseless(Instruction* inst); - - // Replace all instances of load's id with replId and delete load - // and its access chain, if any - Instruction* ReplaceAndDeleteLoad(Instruction* loadInst, uint32_t replId, - Instruction* ptrInst); - - // For the (constant index) access chain ptrInst, create an - // equivalent load and extract - void GenACLoadRepl(const Instruction* ptrInst, - std::vector>* newInsts, - uint32_t* resultId); - - // Return true if all indices are constant - bool IsConstantIndexAccessChain(Instruction* acp); - - // Convert all uniform access chain loads into load/extract. - bool UniformAccessChainConvert(Function* func); - - // Compute structured successors for function |func|. - // A block's structured successors are the blocks it branches to - // together with its declared merge block if it has one. - // When order matters, the merge block always appears first. - // This assures correct depth first search in the presence of early - // returns and kills. If the successor vector contain duplicates - // if the merge block, they are safely ignored by DFS. - // - // TODO(dnovillo): This pass computes structured successors slightly different - // than the implementation in class Pass. Can this be re-factored? - void ComputeStructuredSuccessors(Function* func); - - // Compute structured block order for |func| into |structuredOrder|. This - // order has the property that dominators come before all blocks they - // dominate and merge blocks come after all blocks that are in the control - // constructs of their header. - // - // TODO(dnovillo): This pass computes structured order slightly different - // than the implementation in class Pass. Can this be re-factored? - void ComputeStructuredOrder(Function* func, std::list* order); - - // Eliminate loads of uniform variables which have previously been loaded. - // If first load is in control flow, move it to first block of function. - // Most effective if preceded by UniformAccessChainRemoval(). - bool CommonUniformLoadElimination(Function* func); - - // Eliminate loads of uniform sampler and image variables which have - // previously - // been loaded in the same block for types whose loads cannot cross blocks. - bool CommonUniformLoadElimBlock(Function* func); - - // Eliminate duplicated extracts of same id. Extract may be moved to same - // block as the id definition. This is primarily intended for extracts - // from uniform loads. Most effective if preceded by - // CommonUniformLoadElimination(). - bool CommonExtractElimination(Function* func); - - // For function |func|, first change all uniform constant index - // access chain loads into equivalent composite extracts. Then consolidate - // identical uniform loads into one uniform load. Finally, consolidate - // identical uniform extracts into one uniform extract. This may require - // moving a load or extract to a point which dominates all uses. - // Return true if func is modified. - // - // This pass requires the function to have structured control flow ie shader - // capability. It also requires logical addressing ie Addresses capability - // is not enabled. It also currently does not support any extensions. - // - // This function currently only optimizes loads with a single index. - bool EliminateCommonUniform(Function* func); - - // Initialize extensions whitelist - void InitExtensions(); - - // Return true if all extensions in this module are allowed by this pass. - bool AllExtensionsSupported() const; - - // Return true if |op| is a decorate for non-type instruction - inline bool IsNonTypeDecorate(uint32_t op) const { - return (op == SpvOpDecorate || op == SpvOpDecorateId); - } - - // Return true if |inst| is an instruction that loads uniform variable and - // can be replaced with other uniform load instruction. - bool IsUniformLoadToBeRemoved(Instruction* inst) { - if (inst->opcode() == SpvOpLoad) { - uint32_t varId; - Instruction* ptrInst = GetPtr(inst, &varId); - if (ptrInst->opcode() == SpvOpVariable && IsUniformVar(varId) && - !IsSamplerOrImageVar(varId) && - !HasUnsupportedDecorates(inst->result_id()) && !IsVolatileLoad(*inst)) - return true; - } - return false; - } - - void Initialize(); - Pass::Status ProcessImpl(); - - // Map from uniform variable id to its common load id - std::unordered_map uniform2load_id_; - - // Map of extract composite ids to map of indices to insts - // TODO(greg-lunarg): Consider std::vector. - std::unordered_map>> - comp2idx2inst_; - - // Extensions supported by this pass. - std::unordered_set extensions_whitelist_; - - // Map from block to its structured successor blocks. See - // ComputeStructuredSuccessors() for definition. - std::unordered_map> - block2structured_succs_; -}; - -} // namespace opt -} // namespace spvtools - -#endif // SOURCE_OPT_COMMON_UNIFORM_ELIM_PASS_H_ diff --git a/third_party/spirv-tools/source/opt/const_folding_rules.cpp b/third_party/spirv-tools/source/opt/const_folding_rules.cpp index f6013a3d71..d262a7ecab 100644 --- a/third_party/spirv-tools/source/opt/const_folding_rules.cpp +++ b/third_party/spirv-tools/source/opt/const_folding_rules.cpp @@ -55,6 +55,9 @@ ConstantFoldingRule FoldExtractWithConstants() { auto cc = c->AsCompositeConstant(); assert(cc != nullptr); auto components = cc->GetComponents(); + // Protect against invalid IR. Refuse to fold if the index is out + // of bounds. + if (element_index >= components.size()) return nullptr; c = components[element_index]; } return c; @@ -262,7 +265,10 @@ ConstantFoldingRule FoldFPUnaryOp(UnaryScalarFoldingRule scalar_rule) { return nullptr; } - if (constants[0] == nullptr) { + const analysis::Constant* arg = + (inst->opcode() == SpvOpExtInst) ? constants[1] : constants[0]; + + if (arg == nullptr) { return nullptr; } @@ -270,7 +276,7 @@ ConstantFoldingRule FoldFPUnaryOp(UnaryScalarFoldingRule scalar_rule) { std::vector a_components; std::vector results_components; - a_components = constants[0]->GetVectorComponents(const_mgr); + a_components = arg->GetVectorComponents(const_mgr); // Fold each component of the vector. for (uint32_t i = 0; i < a_components.size(); ++i) { @@ -288,11 +294,56 @@ ConstantFoldingRule FoldFPUnaryOp(UnaryScalarFoldingRule scalar_rule) { } return const_mgr->GetConstant(vector_type, ids); } else { - return scalar_rule(result_type, constants[0], const_mgr); + return scalar_rule(result_type, arg, const_mgr); } }; } +// Returns the result of folding the constants in |constants| according the +// |scalar_rule|. If |result_type| is a vector, then |scalar_rule| is applied +// per component. +const analysis::Constant* FoldFPBinaryOp( + BinaryScalarFoldingRule scalar_rule, uint32_t result_type_id, + const std::vector& constants, + IRContext* context) { + analysis::ConstantManager* const_mgr = context->get_constant_mgr(); + analysis::TypeManager* type_mgr = context->get_type_mgr(); + const analysis::Type* result_type = type_mgr->GetType(result_type_id); + const analysis::Vector* vector_type = result_type->AsVector(); + + if (constants[0] == nullptr || constants[1] == nullptr) { + return nullptr; + } + + if (vector_type != nullptr) { + std::vector a_components; + std::vector b_components; + std::vector results_components; + + a_components = constants[0]->GetVectorComponents(const_mgr); + b_components = constants[1]->GetVectorComponents(const_mgr); + + // 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 ids; + for (const analysis::Constant* member : results_components) { + ids.push_back(const_mgr->GetDefiningInstruction(member)->result_id()); + } + return const_mgr->GetConstant(vector_type, ids); + } else { + return scalar_rule(result_type, constants[0], constants[1], const_mgr); + } +} + // Returns a |ConstantFoldingRule| that folds floating point scalars using // |scalar_rule| and vectors of floating point by applying |scalar_rule| to the // elements of the vector. The |ConstantFoldingRule| that is returned assumes @@ -302,46 +353,14 @@ ConstantFoldingRule FoldFPBinaryOp(BinaryScalarFoldingRule scalar_rule) { return [scalar_rule](IRContext* context, Instruction* inst, const std::vector& 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()); - const analysis::Vector* vector_type = result_type->AsVector(); - if (!inst->IsFloatingPointFoldingAllowed()) { return nullptr; } - - if (constants[0] == nullptr || constants[1] == nullptr) { - return nullptr; - } - - if (vector_type != nullptr) { - std::vector a_components; - std::vector b_components; - std::vector results_components; - - a_components = constants[0]->GetVectorComponents(const_mgr); - b_components = constants[1]->GetVectorComponents(const_mgr); - - // 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 ids; - for (const analysis::Constant* member : results_components) { - ids.push_back(const_mgr->GetDefiningInstruction(member)->result_id()); - } - return const_mgr->GetConstant(vector_type, ids); - } else { - return scalar_rule(result_type, constants[0], constants[1], const_mgr); + if (inst->opcode() == SpvOpExtInst) { + return FoldFPBinaryOp(scalar_rule, inst->type_id(), + {constants[1], constants[2]}, context); } + return FoldFPBinaryOp(scalar_rule, inst->type_id(), constants, context); }; } @@ -408,36 +427,65 @@ UnaryScalarFoldingRule FoldIToFOp() { }; } +// This defines a |UnaryScalarFoldingRule| that performs |OpQuantizeToF16|. +UnaryScalarFoldingRule FoldQuantizeToF16Scalar() { + return [](const analysis::Type* result_type, const analysis::Constant* a, + analysis::ConstantManager* const_mgr) -> const analysis::Constant* { + assert(result_type != nullptr && a != nullptr); + const analysis::Float* float_type = a->type()->AsFloat(); + assert(float_type != nullptr); + if (float_type->width() != 32) { + return nullptr; + } + + float fa = a->GetFloat(); + utils::HexFloat> orignal(fa); + utils::HexFloat> quantized(0); + utils::HexFloat> result(0.0f); + orignal.castTo(quantized, utils::round_direction::kToZero); + quantized.castTo(result, utils::round_direction::kToZero); + std::vector words = {result.getBits()}; + return const_mgr->GetConstant(result_type, words); + }; +} + // This macro defines a |BinaryScalarFoldingRule| that applies |op|. The // operator |op| must work for both float and double, and use syntax "f1 op f2". -#define FOLD_FPARITH_OP(op) \ - [](const analysis::Type* result_type, const analysis::Constant* a, \ - const analysis::Constant* b, \ - analysis::ConstantManager* const_mgr_in_macro) \ - -> const analysis::Constant* { \ - assert(result_type != nullptr && a != nullptr && b != nullptr); \ - assert(result_type == a->type() && result_type == b->type()); \ - const analysis::Float* float_type_in_macro = result_type->AsFloat(); \ - assert(float_type_in_macro != nullptr); \ - if (float_type_in_macro->width() == 32) { \ - float fa = a->GetFloat(); \ - float fb = b->GetFloat(); \ - utils::FloatProxy result_in_macro(fa op fb); \ - std::vector words_in_macro = result_in_macro.GetWords(); \ - return const_mgr_in_macro->GetConstant(result_type, words_in_macro); \ - } else if (float_type_in_macro->width() == 64) { \ - double fa = a->GetDouble(); \ - double fb = b->GetDouble(); \ - utils::FloatProxy result_in_macro(fa op fb); \ - std::vector words_in_macro = result_in_macro.GetWords(); \ - return const_mgr_in_macro->GetConstant(result_type, words_in_macro); \ - } \ - return nullptr; \ +#define FOLD_FPARITH_OP(op) \ + [](const analysis::Type* result_type_in_macro, const analysis::Constant* a, \ + const analysis::Constant* b, \ + analysis::ConstantManager* const_mgr_in_macro) \ + -> const analysis::Constant* { \ + assert(result_type_in_macro != nullptr && a != nullptr && b != nullptr); \ + assert(result_type_in_macro == a->type() && \ + result_type_in_macro == b->type()); \ + const analysis::Float* float_type_in_macro = \ + result_type_in_macro->AsFloat(); \ + assert(float_type_in_macro != nullptr); \ + if (float_type_in_macro->width() == 32) { \ + float fa = a->GetFloat(); \ + float fb = b->GetFloat(); \ + utils::FloatProxy result_in_macro(fa op fb); \ + std::vector words_in_macro = result_in_macro.GetWords(); \ + return const_mgr_in_macro->GetConstant(result_type_in_macro, \ + words_in_macro); \ + } else if (float_type_in_macro->width() == 64) { \ + double fa = a->GetDouble(); \ + double fb = b->GetDouble(); \ + utils::FloatProxy result_in_macro(fa op fb); \ + std::vector words_in_macro = result_in_macro.GetWords(); \ + return const_mgr_in_macro->GetConstant(result_type_in_macro, \ + words_in_macro); \ + } \ + return nullptr; \ } // Define the folding rule for conversion between floating point and integer ConstantFoldingRule FoldFToI() { return FoldFPUnaryOp(FoldFToIOp()); } ConstantFoldingRule FoldIToF() { return FoldFPUnaryOp(FoldIToFOp()); } +ConstantFoldingRule FoldQuantizeToF16() { + return FoldFPUnaryOp(FoldQuantizeToF16Scalar()); +} // Define the folding rules for subtraction, addition, multiplication, and // division for floating point values. @@ -582,13 +630,17 @@ ConstantFoldingRule FoldOpDotWithConstants() { std::vector words = result.GetWords(); const analysis::Constant* result_const = const_mgr->GetConstant(float_type, words); - for (uint32_t i = 0; i < a_components.size(); ++i) { + for (uint32_t i = 0; i < a_components.size() && result_const != nullptr; + ++i) { if (a_components[i] == nullptr || b_components[i] == nullptr) { return nullptr; } const analysis::Constant* component = FOLD_FPARITH_OP(*)( new_type, a_components[i], b_components[i], const_mgr); + if (component == nullptr) { + return nullptr; + } result_const = FOLD_FPARITH_OP(+)(new_type, result_const, component, const_mgr); } @@ -777,9 +829,307 @@ ConstantFoldingRule FoldFClampFeedingCompare(uint32_t cmp_opcode) { }; } +ConstantFoldingRule FoldFMix() { + return [](IRContext* context, Instruction* inst, + const std::vector& constants) + -> const analysis::Constant* { + analysis::ConstantManager* const_mgr = context->get_constant_mgr(); + assert(inst->opcode() == SpvOpExtInst && + "Expecting an extended instruction."); + assert(inst->GetSingleWordInOperand(0) == + context->get_feature_mgr()->GetExtInstImportId_GLSLstd450() && + "Expecting a GLSLstd450 extended instruction."); + assert(inst->GetSingleWordInOperand(1) == GLSLstd450FMix && + "Expecting and FMix instruction."); + + if (!inst->IsFloatingPointFoldingAllowed()) { + return nullptr; + } + + // Make sure all FMix operands are constants. + for (uint32_t i = 1; i < 4; i++) { + if (constants[i] == nullptr) { + return nullptr; + } + } + + const analysis::Constant* one; + bool is_vector = false; + const analysis::Type* result_type = constants[1]->type(); + const analysis::Type* base_type = result_type; + if (base_type->AsVector()) { + is_vector = true; + base_type = base_type->AsVector()->element_type(); + } + assert(base_type->AsFloat() != nullptr && + "FMix is suppose to act on floats or vectors of floats."); + + if (base_type->AsFloat()->width() == 32) { + one = const_mgr->GetConstant(base_type, + utils::FloatProxy(1.0f).GetWords()); + } else { + one = const_mgr->GetConstant(base_type, + utils::FloatProxy(1.0).GetWords()); + } + + if (is_vector) { + uint32_t one_id = const_mgr->GetDefiningInstruction(one)->result_id(); + one = + const_mgr->GetConstant(result_type, std::vector(4, one_id)); + } + + const analysis::Constant* temp1 = FoldFPBinaryOp( + FOLD_FPARITH_OP(-), inst->type_id(), {one, constants[3]}, context); + if (temp1 == nullptr) { + return nullptr; + } + + const analysis::Constant* temp2 = FoldFPBinaryOp( + FOLD_FPARITH_OP(*), inst->type_id(), {constants[1], temp1}, context); + if (temp2 == nullptr) { + return nullptr; + } + const analysis::Constant* temp3 = + FoldFPBinaryOp(FOLD_FPARITH_OP(*), inst->type_id(), + {constants[2], constants[3]}, context); + if (temp3 == nullptr) { + return nullptr; + } + return FoldFPBinaryOp(FOLD_FPARITH_OP(+), inst->type_id(), {temp2, temp3}, + context); + }; +} + +template +IntType FoldIClamp(IntType x, IntType min_val, IntType max_val) { + if (x < min_val) { + x = min_val; + } + if (x > max_val) { + x = max_val; + } + return x; +} + +const analysis::Constant* FoldMin(const analysis::Type* result_type, + const analysis::Constant* a, + const analysis::Constant* b, + analysis::ConstantManager*) { + if (const analysis::Integer* int_type = result_type->AsInteger()) { + if (int_type->width() == 32) { + if (int_type->IsSigned()) { + int32_t va = a->GetS32(); + int32_t vb = b->GetS32(); + return (va < vb ? a : b); + } else { + uint32_t va = a->GetU32(); + uint32_t vb = b->GetU32(); + return (va < vb ? a : b); + } + } else if (int_type->width() == 64) { + if (int_type->IsSigned()) { + int64_t va = a->GetS64(); + int64_t vb = b->GetS64(); + return (va < vb ? a : b); + } else { + uint64_t va = a->GetU64(); + uint64_t vb = b->GetU64(); + return (va < vb ? a : b); + } + } + } else if (const analysis::Float* float_type = result_type->AsFloat()) { + if (float_type->width() == 32) { + float va = a->GetFloat(); + float vb = b->GetFloat(); + return (va < vb ? a : b); + } else if (float_type->width() == 64) { + double va = a->GetDouble(); + double vb = b->GetDouble(); + return (va < vb ? a : b); + } + } + return nullptr; +} + +const analysis::Constant* FoldMax(const analysis::Type* result_type, + const analysis::Constant* a, + const analysis::Constant* b, + analysis::ConstantManager*) { + if (const analysis::Integer* int_type = result_type->AsInteger()) { + if (int_type->width() == 32) { + if (int_type->IsSigned()) { + int32_t va = a->GetS32(); + int32_t vb = b->GetS32(); + return (va > vb ? a : b); + } else { + uint32_t va = a->GetU32(); + uint32_t vb = b->GetU32(); + return (va > vb ? a : b); + } + } else if (int_type->width() == 64) { + if (int_type->IsSigned()) { + int64_t va = a->GetS64(); + int64_t vb = b->GetS64(); + return (va > vb ? a : b); + } else { + uint64_t va = a->GetU64(); + uint64_t vb = b->GetU64(); + return (va > vb ? a : b); + } + } + } else if (const analysis::Float* float_type = result_type->AsFloat()) { + if (float_type->width() == 32) { + float va = a->GetFloat(); + float vb = b->GetFloat(); + return (va > vb ? a : b); + } else if (float_type->width() == 64) { + double va = a->GetDouble(); + double vb = b->GetDouble(); + return (va > vb ? a : b); + } + } + return nullptr; +} + +// Fold an clamp instruction when all three operands are constant. +const analysis::Constant* FoldClamp1( + IRContext* context, Instruction* inst, + const std::vector& constants) { + assert(inst->opcode() == SpvOpExtInst && + "Expecting an extended instruction."); + assert(inst->GetSingleWordInOperand(0) == + context->get_feature_mgr()->GetExtInstImportId_GLSLstd450() && + "Expecting a GLSLstd450 extended instruction."); + + // Make sure all Clamp operands are constants. + for (uint32_t i = 1; i < 3; i++) { + if (constants[i] == nullptr) { + return nullptr; + } + } + + const analysis::Constant* temp = FoldFPBinaryOp( + FoldMax, inst->type_id(), {constants[1], constants[2]}, context); + if (temp == nullptr) { + return nullptr; + } + return FoldFPBinaryOp(FoldMin, inst->type_id(), {temp, constants[3]}, + context); +} + +// Fold a clamp instruction when |x >= min_val|. +const analysis::Constant* FoldClamp2( + IRContext* context, Instruction* inst, + const std::vector& constants) { + assert(inst->opcode() == SpvOpExtInst && + "Expecting an extended instruction."); + assert(inst->GetSingleWordInOperand(0) == + context->get_feature_mgr()->GetExtInstImportId_GLSLstd450() && + "Expecting a GLSLstd450 extended instruction."); + + const analysis::Constant* x = constants[1]; + const analysis::Constant* min_val = constants[2]; + + if (x == nullptr || min_val == nullptr) { + return nullptr; + } + + const analysis::Constant* temp = + FoldFPBinaryOp(FoldMax, inst->type_id(), {x, min_val}, context); + if (temp == min_val) { + // We can assume that |min_val| is less than |max_val|. Therefore, if the + // result of the max operation is |min_val|, we know the result of the min + // operation, even if |max_val| is not a constant. + return min_val; + } + return nullptr; +} + +// Fold a clamp instruction when |x >= max_val|. +const analysis::Constant* FoldClamp3( + IRContext* context, Instruction* inst, + const std::vector& constants) { + assert(inst->opcode() == SpvOpExtInst && + "Expecting an extended instruction."); + assert(inst->GetSingleWordInOperand(0) == + context->get_feature_mgr()->GetExtInstImportId_GLSLstd450() && + "Expecting a GLSLstd450 extended instruction."); + + const analysis::Constant* x = constants[1]; + const analysis::Constant* max_val = constants[3]; + + if (x == nullptr || max_val == nullptr) { + return nullptr; + } + + const analysis::Constant* temp = + FoldFPBinaryOp(FoldMin, inst->type_id(), {x, max_val}, context); + if (temp == max_val) { + // We can assume that |min_val| is less than |max_val|. Therefore, if the + // result of the max operation is |min_val|, we know the result of the min + // operation, even if |max_val| is not a constant. + return max_val; + } + return nullptr; +} + +UnaryScalarFoldingRule FoldFTranscendentalUnary(double (*fp)(double)) { + return + [fp](const analysis::Type* result_type, const analysis::Constant* a, + analysis::ConstantManager* const_mgr) -> const analysis::Constant* { + assert(result_type != nullptr && a != nullptr); + const analysis::Float* float_type = a->type()->AsFloat(); + assert(float_type != nullptr); + assert(float_type == result_type->AsFloat()); + if (float_type->width() == 32) { + float fa = a->GetFloat(); + float res = static_cast(fp(fa)); + utils::FloatProxy result(res); + std::vector words = result.GetWords(); + return const_mgr->GetConstant(result_type, words); + } else if (float_type->width() == 64) { + double fa = a->GetDouble(); + double res = fp(fa); + utils::FloatProxy result(res); + std::vector words = result.GetWords(); + return const_mgr->GetConstant(result_type, words); + } + return nullptr; + }; +} + +BinaryScalarFoldingRule FoldFTranscendentalBinary(double (*fp)(double, + double)) { + return + [fp](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); + const analysis::Float* float_type = a->type()->AsFloat(); + assert(float_type != nullptr); + assert(float_type == result_type->AsFloat()); + assert(float_type == b->type()->AsFloat()); + if (float_type->width() == 32) { + float fa = a->GetFloat(); + float fb = b->GetFloat(); + float res = static_cast(fp(fa, fb)); + utils::FloatProxy result(res); + std::vector words = result.GetWords(); + return const_mgr->GetConstant(result_type, words); + } else if (float_type->width() == 64) { + double fa = a->GetDouble(); + double fb = b->GetDouble(); + double res = fp(fa, fb); + utils::FloatProxy result(res); + std::vector words = result.GetWords(); + return const_mgr->GetConstant(result_type, words); + } + return nullptr; + }; +} } // namespace -ConstantFoldingRules::ConstantFoldingRules() { +void ConstantFoldingRules::AddFoldingRules() { // Add all folding rules to the list for the opcodes to which they apply. // Note that the order in which rules are added to the list matters. If a rule // applies to the instruction, the rest of the rules will not be attempted. @@ -844,6 +1194,84 @@ ConstantFoldingRules::ConstantFoldingRules() { rules_[SpvOpVectorTimesScalar].push_back(FoldVectorTimesScalar()); rules_[SpvOpFNegate].push_back(FoldFNegate()); + rules_[SpvOpQuantizeToF16].push_back(FoldQuantizeToF16()); + + // Add rules for GLSLstd450 + FeatureManager* feature_manager = context_->get_feature_mgr(); + uint32_t ext_inst_glslstd450_id = + feature_manager->GetExtInstImportId_GLSLstd450(); + if (ext_inst_glslstd450_id != 0) { + ext_rules_[{ext_inst_glslstd450_id, GLSLstd450FMix}].push_back(FoldFMix()); + ext_rules_[{ext_inst_glslstd450_id, GLSLstd450SMin}].push_back( + FoldFPBinaryOp(FoldMin)); + ext_rules_[{ext_inst_glslstd450_id, GLSLstd450UMin}].push_back( + FoldFPBinaryOp(FoldMin)); + ext_rules_[{ext_inst_glslstd450_id, GLSLstd450FMin}].push_back( + FoldFPBinaryOp(FoldMin)); + ext_rules_[{ext_inst_glslstd450_id, GLSLstd450SMax}].push_back( + FoldFPBinaryOp(FoldMax)); + ext_rules_[{ext_inst_glslstd450_id, GLSLstd450UMax}].push_back( + FoldFPBinaryOp(FoldMax)); + ext_rules_[{ext_inst_glslstd450_id, GLSLstd450FMax}].push_back( + FoldFPBinaryOp(FoldMax)); + ext_rules_[{ext_inst_glslstd450_id, GLSLstd450UClamp}].push_back( + FoldClamp1); + ext_rules_[{ext_inst_glslstd450_id, GLSLstd450UClamp}].push_back( + FoldClamp2); + ext_rules_[{ext_inst_glslstd450_id, GLSLstd450UClamp}].push_back( + FoldClamp3); + ext_rules_[{ext_inst_glslstd450_id, GLSLstd450SClamp}].push_back( + FoldClamp1); + ext_rules_[{ext_inst_glslstd450_id, GLSLstd450SClamp}].push_back( + FoldClamp2); + ext_rules_[{ext_inst_glslstd450_id, GLSLstd450SClamp}].push_back( + FoldClamp3); + ext_rules_[{ext_inst_glslstd450_id, GLSLstd450FClamp}].push_back( + FoldClamp1); + ext_rules_[{ext_inst_glslstd450_id, GLSLstd450FClamp}].push_back( + FoldClamp2); + ext_rules_[{ext_inst_glslstd450_id, GLSLstd450FClamp}].push_back( + FoldClamp3); + ext_rules_[{ext_inst_glslstd450_id, GLSLstd450Sin}].push_back( + FoldFPUnaryOp(FoldFTranscendentalUnary(std::sin))); + ext_rules_[{ext_inst_glslstd450_id, GLSLstd450Cos}].push_back( + FoldFPUnaryOp(FoldFTranscendentalUnary(std::cos))); + ext_rules_[{ext_inst_glslstd450_id, GLSLstd450Tan}].push_back( + FoldFPUnaryOp(FoldFTranscendentalUnary(std::tan))); + ext_rules_[{ext_inst_glslstd450_id, GLSLstd450Asin}].push_back( + FoldFPUnaryOp(FoldFTranscendentalUnary(std::asin))); + ext_rules_[{ext_inst_glslstd450_id, GLSLstd450Acos}].push_back( + FoldFPUnaryOp(FoldFTranscendentalUnary(std::acos))); + ext_rules_[{ext_inst_glslstd450_id, GLSLstd450Atan}].push_back( + FoldFPUnaryOp(FoldFTranscendentalUnary(std::atan))); + ext_rules_[{ext_inst_glslstd450_id, GLSLstd450Exp}].push_back( + FoldFPUnaryOp(FoldFTranscendentalUnary(std::exp))); + ext_rules_[{ext_inst_glslstd450_id, GLSLstd450Log}].push_back( + FoldFPUnaryOp(FoldFTranscendentalUnary(std::log))); + +#ifdef __ANDROID__ + // Android NDK r15c tageting ABI 15 doesn't have full support for C++11 + // (no std::exp2/log2). ::exp2 is available from C99 but ::log2 isn't + // available up until ABI 18 so we use a shim + auto log2_shim = [](double v) -> double { return log(v) / log(2.0); }; + ext_rules_[{ext_inst_glslstd450_id, GLSLstd450Exp2}].push_back( + FoldFPUnaryOp(FoldFTranscendentalUnary(::exp2))); + ext_rules_[{ext_inst_glslstd450_id, GLSLstd450Log2}].push_back( + FoldFPUnaryOp(FoldFTranscendentalUnary(log2_shim))); +#else + ext_rules_[{ext_inst_glslstd450_id, GLSLstd450Exp2}].push_back( + FoldFPUnaryOp(FoldFTranscendentalUnary(std::exp2))); + ext_rules_[{ext_inst_glslstd450_id, GLSLstd450Log2}].push_back( + FoldFPUnaryOp(FoldFTranscendentalUnary(std::log2))); +#endif + + ext_rules_[{ext_inst_glslstd450_id, GLSLstd450Sqrt}].push_back( + FoldFPUnaryOp(FoldFTranscendentalUnary(std::sqrt))); + ext_rules_[{ext_inst_glslstd450_id, GLSLstd450Atan2}].push_back( + FoldFPBinaryOp(FoldFTranscendentalBinary(std::atan2))); + ext_rules_[{ext_inst_glslstd450_id, GLSLstd450Pow}].push_back( + FoldFPBinaryOp(FoldFTranscendentalBinary(std::pow))); + } } } // namespace opt } // namespace spvtools diff --git a/third_party/spirv-tools/source/opt/const_folding_rules.h b/third_party/spirv-tools/source/opt/const_folding_rules.h index c1865792bc..41ee2aa226 100644 --- a/third_party/spirv-tools/source/opt/const_folding_rules.h +++ b/third_party/spirv-tools/source/opt/const_folding_rules.h @@ -53,24 +53,74 @@ using ConstantFoldingRule = std::function& constants)>; class ConstantFoldingRules { + protected: + // The |Key| and |Value| structs are used to by-pass a "decorated name length + // exceeded, name was truncated" warning on VS2013 and VS2015. + struct Key { + uint32_t instruction_set; + uint32_t opcode; + }; + + friend bool operator<(const Key& a, const Key& b) { + if (a.instruction_set < b.instruction_set) { + return true; + } + if (a.instruction_set > b.instruction_set) { + return false; + } + return a.opcode < b.opcode; + } + + struct Value { + std::vector value; + void push_back(ConstantFoldingRule rule) { value.push_back(rule); } + }; + public: - ConstantFoldingRules(); + ConstantFoldingRules(IRContext* ctx) : context_(ctx) {} + virtual ~ConstantFoldingRules() = default; // Returns true if there is at least 1 folding rule for |opcode|. - bool HasFoldingRule(SpvOp opcode) const { return rules_.count(opcode); } + bool HasFoldingRule(const Instruction* inst) const { + return !GetRulesForInstruction(inst).empty(); + } - // Returns an vector of constant folding rules for |opcode|. - const std::vector& GetRulesForOpcode( - SpvOp opcode) const { - auto it = rules_.find(opcode); - if (it != rules_.end()) { - return it->second; + // Returns true if there is at least 1 folding rule for |inst|. + const std::vector& GetRulesForInstruction( + const Instruction* inst) const { + if (inst->opcode() != SpvOpExtInst) { + auto it = rules_.find(inst->opcode()); + if (it != rules_.end()) { + return it->second.value; + } + } else { + uint32_t ext_inst_id = inst->GetSingleWordInOperand(0); + uint32_t ext_opcode = inst->GetSingleWordInOperand(1); + auto it = ext_rules_.find({ext_inst_id, ext_opcode}); + if (it != ext_rules_.end()) { + return it->second.value; + } } return empty_vector_; } + // Add the folding rules. + virtual void AddFoldingRules(); + + protected: + // |rules[opcode]| is the set of rules that can be applied to instructions + // with |opcode| as the opcode. + std::unordered_map rules_; + + // The folding rules for extended instructions. + std::map ext_rules_; + private: - std::unordered_map> rules_; + // The context that the instruction to be folded will be a part of. + IRContext* context_; + + // The empty set of rules to be used as the default return value in + // |GetRulesForInstruction|. std::vector empty_vector_; }; diff --git a/third_party/spirv-tools/source/opt/constants.cpp b/third_party/spirv-tools/source/opt/constants.cpp index b1e4bee40e..6057356cb8 100644 --- a/third_party/spirv-tools/source/opt/constants.cpp +++ b/third_party/spirv-tools/source/opt/constants.cpp @@ -103,6 +103,45 @@ int64_t Constant::GetS64() const { } } +uint64_t Constant::GetZeroExtendedValue() const { + const auto* int_type = type()->AsInteger(); + assert(int_type != nullptr); + const auto width = int_type->width(); + assert(width <= 64); + + uint64_t value = 0; + if (const IntConstant* ic = AsIntConstant()) { + if (width <= 32) { + value = ic->GetU32BitValue(); + } else { + value = ic->GetU64BitValue(); + } + } else { + assert(AsNullConstant() && "Must be an integer constant."); + } + return value; +} + +int64_t Constant::GetSignExtendedValue() const { + const auto* int_type = type()->AsInteger(); + assert(int_type != nullptr); + const auto width = int_type->width(); + assert(width <= 64); + + int64_t value = 0; + if (const IntConstant* ic = AsIntConstant()) { + if (width <= 32) { + // Let the C++ compiler do the sign extension. + value = int64_t(ic->GetS32BitValue()); + } else { + value = ic->GetS64BitValue(); + } + } else { + assert(AsNullConstant() && "Must be an integer constant."); + } + return value; +} + ConstantManager::ConstantManager(IRContext* ctx) : ctx_(ctx) { // Populate the constant table with values from constant declarations in the // module. The values of each OpConstant declaration is the identity @@ -117,7 +156,7 @@ Type* ConstantManager::GetType(const Instruction* inst) const { } std::vector ConstantManager::GetOperandConstants( - Instruction* inst) const { + const Instruction* inst) const { std::vector constants; for (uint32_t i = 0; i < inst->NumInOperands(); i++) { const Operand* operand = &inst->GetInOperand(i); @@ -165,7 +204,12 @@ std::vector ConstantManager::GetConstantsFromIds( Instruction* ConstantManager::BuildInstructionAndAddToModule( const Constant* new_const, Module::inst_iterator* pos, uint32_t type_id) { + // TODO(1841): Handle id overflow. uint32_t new_id = context()->TakeNextId(); + if (new_id == 0) { + return nullptr; + } + auto new_inst = CreateInstruction(new_id, new_const, type_id); if (!new_inst) { return nullptr; @@ -180,8 +224,6 @@ Instruction* ConstantManager::BuildInstructionAndAddToModule( Instruction* ConstantManager::GetDefiningInstruction( const Constant* c, uint32_t type_id, Module::inst_iterator* pos) { - assert(type_id == 0 || - context()->get_type_mgr()->GetType(type_id) == c->type()); uint32_t decl_id = FindDeclaredConstant(c, type_id); if (decl_id == 0) { auto iter = context()->types_values_end(); @@ -196,19 +238,19 @@ Instruction* ConstantManager::GetDefiningInstruction( } } -const Constant* ConstantManager::CreateConstant( +std::unique_ptr ConstantManager::CreateConstant( const Type* type, const std::vector& literal_words_or_ids) const { if (literal_words_or_ids.size() == 0) { // Constant declared with OpConstantNull - return new NullConstant(type); + return MakeUnique(type); } else if (auto* bt = type->AsBool()) { assert(literal_words_or_ids.size() == 1 && "Bool constant should be declared with one operand"); - return new BoolConstant(bt, literal_words_or_ids.front()); + return MakeUnique(bt, literal_words_or_ids.front()); } else if (auto* it = type->AsInteger()) { - return new IntConstant(it, literal_words_or_ids); + return MakeUnique(it, literal_words_or_ids); } else if (auto* ft = type->AsFloat()) { - return new FloatConstant(ft, literal_words_or_ids); + return MakeUnique(ft, literal_words_or_ids); } else if (auto* vt = type->AsVector()) { auto components = GetConstantsFromIds(literal_words_or_ids); if (components.empty()) return nullptr; @@ -231,25 +273,25 @@ const Constant* ConstantManager::CreateConstant( return false; })) return nullptr; - return new VectorConstant(vt, components); + return MakeUnique(vt, components); } else if (auto* mt = type->AsMatrix()) { auto components = GetConstantsFromIds(literal_words_or_ids); if (components.empty()) return nullptr; - return new MatrixConstant(mt, components); + return MakeUnique(mt, components); } else if (auto* st = type->AsStruct()) { auto components = GetConstantsFromIds(literal_words_or_ids); if (components.empty()) return nullptr; - return new StructConstant(st, components); + return MakeUnique(st, components); } else if (auto* at = type->AsArray()) { auto components = GetConstantsFromIds(literal_words_or_ids); if (components.empty()) return nullptr; - return new ArrayConstant(at, components); + return MakeUnique(at, components); } else { return nullptr; } } -const Constant* ConstantManager::GetConstantFromInst(Instruction* inst) { +const Constant* ConstantManager::GetConstantFromInst(const Instruction* inst) { std::vector literal_words_or_ids; // Collect the constant defining literals or component ids. @@ -344,7 +386,14 @@ std::unique_ptr ConstantManager::CreateCompositeInstruction( const Constant* ConstantManager::GetConstant( const Type* type, const std::vector& literal_words_or_ids) { auto cst = CreateConstant(type, literal_words_or_ids); - return cst ? RegisterConstant(cst) : nullptr; + return cst ? RegisterConstant(std::move(cst)) : nullptr; +} + +uint32_t ConstantManager::GetFloatConst(float val) { + Type* float_type = context()->get_type_mgr()->GetFloatType(); + utils::FloatProxy v(val); + const Constant* c = GetConstant(float_type, v.GetWords()); + return GetDefiningInstruction(c)->result_id(); } std::vector Constant::GetVectorComponents( diff --git a/third_party/spirv-tools/source/opt/constants.h b/third_party/spirv-tools/source/opt/constants.h index 2833b845b1..9518b5b6e6 100644 --- a/third_party/spirv-tools/source/opt/constants.h +++ b/third_party/spirv-tools/source/opt/constants.h @@ -116,6 +116,14 @@ class Constant { // Integer type. int64_t GetS64() const; + // Returns the zero-extended representation of an integer constant. Must + // be an integral constant of at most 64 bits. + uint64_t GetZeroExtendedValue() const; + + // Returns the sign-extended representation of an integer constant. Must + // be an integral constant of at most 64 bits. + int64_t GetSignExtendedValue() const; + // Returns true if the constant is a zero or a composite containing 0s. virtual bool IsZero() const { return false; } @@ -432,7 +440,7 @@ class NullConstant : public Constant { std::unique_ptr Copy() const override { return std::unique_ptr(CopyNullConstant().release()); } - bool IsZero() const override { return true; }; + bool IsZero() const override { return true; } }; // Hash function for Constant instances. Use the structure of the constant as @@ -514,7 +522,7 @@ class ConstantManager { // Gets or creates a Constant instance to hold the constant value of the given // instruction. It returns a pointer to a Constant instance or nullptr if it // could not create the constant. - const Constant* GetConstantFromInst(Instruction* inst); + const Constant* GetConstantFromInst(const Instruction* inst); // Gets or creates a constant defining instruction for the given Constant |c|. // If |c| had already been defined, it returns a pointer to the existing @@ -524,12 +532,7 @@ class ConstantManager { // instruction at the end of the current module's types section. // // |type_id| is an optional argument for disambiguating equivalent types. If - // |type_id| is specified, it is used as the type of the constant when a new - // instruction is created. Otherwise the type of the constant is derived by - // getting an id from the type manager for |c|. - // - // When |type_id| is not zero, the type of |c| must be the type returned by - // type manager when given |type_id|. + // |type_id| is specified, the contant returned will have that type id. Instruction* GetDefiningInstruction(const Constant* c, uint32_t type_id = 0, Module::inst_iterator* pos = nullptr); @@ -578,8 +581,11 @@ class ConstantManager { // Registers a new constant |cst| in the constant pool. If the constant // existed already, it returns a pointer to the previously existing Constant // in the pool. Otherwise, it returns |cst|. - const Constant* RegisterConstant(const Constant* cst) { - auto ret = const_pool_.insert(cst); + const Constant* RegisterConstant(std::unique_ptr cst) { + auto ret = const_pool_.insert(cst.get()); + if (ret.second) { + owned_constants_.emplace_back(std::move(cst)); + } return *ret.first; } @@ -591,7 +597,8 @@ class ConstantManager { // Returns a vector of constants representing each in operand. If an operand // is not constant its entry is nullptr. - std::vector GetOperandConstants(Instruction* inst) const; + std::vector GetOperandConstants( + const Instruction* inst) const; // Records a mapping between |inst| and the constant value generated by it. // It returns true if a new Constant was successfully mapped, false if |inst| @@ -620,6 +627,9 @@ class ConstantManager { } } + // Returns the id of a 32-bit floating point constant with value |val|. + uint32_t GetFloatConst(float val); + private: // Creates a Constant instance with the given type and a vector of constant // defining words. Returns a unique pointer to the created Constant instance @@ -633,7 +643,7 @@ class ConstantManager { // type, either Bool, Integer or Float. If any of the rules above failed, the // creation will fail and nullptr will be returned. If the vector is empty, // a NullConstant instance will be created with the given type. - const Constant* CreateConstant( + std::unique_ptr CreateConstant( const Type* type, const std::vector& literal_words_or_ids) const; @@ -680,6 +690,10 @@ class ConstantManager { // The constant pool. All created constants are registered here. std::unordered_set const_pool_; + + // The constant that are owned by the constant manager. Every constant in + // |const_pool_| should be in |owned_constants_| as well. + std::vector> owned_constants_; }; } // namespace analysis diff --git a/third_party/spirv-tools/source/opt/convert_to_half_pass.cpp b/third_party/spirv-tools/source/opt/convert_to_half_pass.cpp new file mode 100644 index 0000000000..5022e1b686 --- /dev/null +++ b/third_party/spirv-tools/source/opt/convert_to_half_pass.cpp @@ -0,0 +1,471 @@ +// Copyright (c) 2019 The Khronos Group Inc. +// Copyright (c) 2019 Valve Corporation +// Copyright (c) 2019 LunarG Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "convert_to_half_pass.h" + +#include "source/opt/ir_builder.h" + +namespace { + +// Indices of operands in SPIR-V instructions +static const int kImageSampleDrefIdInIdx = 2; + +} // anonymous namespace + +namespace spvtools { +namespace opt { + +bool ConvertToHalfPass::IsArithmetic(Instruction* inst) { + return target_ops_core_.count(inst->opcode()) != 0 || + (inst->opcode() == SpvOpExtInst && + inst->GetSingleWordInOperand(0) == + context()->get_feature_mgr()->GetExtInstImportId_GLSLstd450() && + target_ops_450_.count(inst->GetSingleWordInOperand(1)) != 0); +} + +bool ConvertToHalfPass::IsFloat(Instruction* inst, uint32_t width) { + uint32_t ty_id = inst->type_id(); + if (ty_id == 0) return false; + return Pass::IsFloat(ty_id, width); +} + +bool ConvertToHalfPass::IsDecoratedRelaxed(Instruction* inst) { + uint32_t r_id = inst->result_id(); + for (auto r_inst : get_decoration_mgr()->GetDecorationsFor(r_id, false)) + if (r_inst->opcode() == SpvOpDecorate && + r_inst->GetSingleWordInOperand(1) == SpvDecorationRelaxedPrecision) + return true; + return false; +} + +bool ConvertToHalfPass::IsRelaxed(uint32_t id) { + return relaxed_ids_set_.count(id) > 0; +} + +void ConvertToHalfPass::AddRelaxed(uint32_t id) { relaxed_ids_set_.insert(id); } + +analysis::Type* ConvertToHalfPass::FloatScalarType(uint32_t width) { + analysis::Float float_ty(width); + return context()->get_type_mgr()->GetRegisteredType(&float_ty); +} + +analysis::Type* ConvertToHalfPass::FloatVectorType(uint32_t v_len, + uint32_t width) { + analysis::Type* reg_float_ty = FloatScalarType(width); + analysis::Vector vec_ty(reg_float_ty, v_len); + return context()->get_type_mgr()->GetRegisteredType(&vec_ty); +} + +analysis::Type* ConvertToHalfPass::FloatMatrixType(uint32_t v_cnt, + uint32_t vty_id, + uint32_t width) { + Instruction* vty_inst = get_def_use_mgr()->GetDef(vty_id); + uint32_t v_len = vty_inst->GetSingleWordInOperand(1); + analysis::Type* reg_vec_ty = FloatVectorType(v_len, width); + analysis::Matrix mat_ty(reg_vec_ty, v_cnt); + return context()->get_type_mgr()->GetRegisteredType(&mat_ty); +} + +uint32_t ConvertToHalfPass::EquivFloatTypeId(uint32_t ty_id, uint32_t width) { + analysis::Type* reg_equiv_ty; + Instruction* ty_inst = get_def_use_mgr()->GetDef(ty_id); + if (ty_inst->opcode() == SpvOpTypeMatrix) + reg_equiv_ty = FloatMatrixType(ty_inst->GetSingleWordInOperand(1), + ty_inst->GetSingleWordInOperand(0), width); + else if (ty_inst->opcode() == SpvOpTypeVector) + reg_equiv_ty = FloatVectorType(ty_inst->GetSingleWordInOperand(1), width); + else // SpvOpTypeFloat + reg_equiv_ty = FloatScalarType(width); + return context()->get_type_mgr()->GetTypeInstruction(reg_equiv_ty); +} + +void ConvertToHalfPass::GenConvert(uint32_t* val_idp, uint32_t width, + Instruction* inst) { + Instruction* val_inst = get_def_use_mgr()->GetDef(*val_idp); + uint32_t ty_id = val_inst->type_id(); + uint32_t nty_id = EquivFloatTypeId(ty_id, width); + if (nty_id == ty_id) return; + Instruction* cvt_inst; + InstructionBuilder builder( + context(), inst, + IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping); + if (val_inst->opcode() == SpvOpUndef) + cvt_inst = builder.AddNullaryOp(nty_id, SpvOpUndef); + else + cvt_inst = builder.AddUnaryOp(nty_id, SpvOpFConvert, *val_idp); + *val_idp = cvt_inst->result_id(); +} + +bool ConvertToHalfPass::MatConvertCleanup(Instruction* inst) { + if (inst->opcode() != SpvOpFConvert) return false; + uint32_t mty_id = inst->type_id(); + Instruction* mty_inst = get_def_use_mgr()->GetDef(mty_id); + if (mty_inst->opcode() != SpvOpTypeMatrix) return false; + uint32_t vty_id = mty_inst->GetSingleWordInOperand(0); + uint32_t v_cnt = mty_inst->GetSingleWordInOperand(1); + Instruction* vty_inst = get_def_use_mgr()->GetDef(vty_id); + uint32_t cty_id = vty_inst->GetSingleWordInOperand(0); + Instruction* cty_inst = get_def_use_mgr()->GetDef(cty_id); + InstructionBuilder builder( + context(), inst, + IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping); + // Convert each component vector, combine them with OpCompositeConstruct + // and replace original instruction. + uint32_t orig_width = (cty_inst->GetSingleWordInOperand(0) == 16) ? 32 : 16; + uint32_t orig_mat_id = inst->GetSingleWordInOperand(0); + uint32_t orig_vty_id = EquivFloatTypeId(vty_id, orig_width); + std::vector opnds = {}; + for (uint32_t vidx = 0; vidx < v_cnt; ++vidx) { + Instruction* ext_inst = builder.AddIdLiteralOp( + orig_vty_id, SpvOpCompositeExtract, orig_mat_id, vidx); + Instruction* cvt_inst = + builder.AddUnaryOp(vty_id, SpvOpFConvert, ext_inst->result_id()); + opnds.push_back({SPV_OPERAND_TYPE_ID, {cvt_inst->result_id()}}); + } + uint32_t mat_id = TakeNextId(); + std::unique_ptr mat_inst(new Instruction( + context(), SpvOpCompositeConstruct, mty_id, mat_id, opnds)); + (void)builder.AddInstruction(std::move(mat_inst)); + context()->ReplaceAllUsesWith(inst->result_id(), mat_id); + // Turn original instruction into copy so it is valid. + inst->SetOpcode(SpvOpCopyObject); + inst->SetResultType(EquivFloatTypeId(mty_id, orig_width)); + get_def_use_mgr()->AnalyzeInstUse(inst); + return true; +} + +void ConvertToHalfPass::RemoveRelaxedDecoration(uint32_t id) { + context()->get_decoration_mgr()->RemoveDecorationsFrom( + id, [](const Instruction& dec) { + if (dec.opcode() == SpvOpDecorate && + dec.GetSingleWordInOperand(1u) == SpvDecorationRelaxedPrecision) + return true; + else + return false; + }); +} + +bool ConvertToHalfPass::GenHalfArith(Instruction* inst) { + bool modified = false; + // Convert all float32 based operands to float16 equivalent and change + // instruction type to float16 equivalent. + inst->ForEachInId([&inst, &modified, this](uint32_t* idp) { + Instruction* op_inst = get_def_use_mgr()->GetDef(*idp); + if (!IsFloat(op_inst, 32)) return; + GenConvert(idp, 16, inst); + modified = true; + }); + if (IsFloat(inst, 32)) { + inst->SetResultType(EquivFloatTypeId(inst->type_id(), 16)); + converted_ids_.insert(inst->result_id()); + modified = true; + } + if (modified) get_def_use_mgr()->AnalyzeInstUse(inst); + return modified; +} + +bool ConvertToHalfPass::ProcessPhi(Instruction* inst) { + // Add float16 converts of any float32 operands and change type + // of phi to float16 equivalent. Operand converts need to be added to + // preceeding blocks. + uint32_t ocnt = 0; + uint32_t* prev_idp; + inst->ForEachInId([&ocnt, &prev_idp, this](uint32_t* idp) { + if (ocnt % 2 == 0) { + prev_idp = idp; + } else { + Instruction* val_inst = get_def_use_mgr()->GetDef(*prev_idp); + if (IsFloat(val_inst, 32)) { + BasicBlock* bp = context()->get_instr_block(*idp); + auto insert_before = bp->tail(); + if (insert_before != bp->begin()) { + --insert_before; + if (insert_before->opcode() != SpvOpSelectionMerge && + insert_before->opcode() != SpvOpLoopMerge) + ++insert_before; + } + GenConvert(prev_idp, 16, &*insert_before); + } + } + ++ocnt; + }); + inst->SetResultType(EquivFloatTypeId(inst->type_id(), 16)); + get_def_use_mgr()->AnalyzeInstUse(inst); + converted_ids_.insert(inst->result_id()); + return true; +} + +bool ConvertToHalfPass::ProcessConvert(Instruction* inst) { + // If float32 and relaxed, change to float16 convert + if (IsFloat(inst, 32) && IsRelaxed(inst->result_id())) { + inst->SetResultType(EquivFloatTypeId(inst->type_id(), 16)); + get_def_use_mgr()->AnalyzeInstUse(inst); + converted_ids_.insert(inst->result_id()); + } + // If operand and result types are the same, change FConvert to CopyObject to + // keep validator happy; simplification and DCE will clean it up + // One way this can happen is if an FConvert generated during this pass + // (likely by ProcessPhi) is later encountered here and its operand has been + // changed to half. + uint32_t val_id = inst->GetSingleWordInOperand(0); + Instruction* val_inst = get_def_use_mgr()->GetDef(val_id); + if (inst->type_id() == val_inst->type_id()) inst->SetOpcode(SpvOpCopyObject); + return true; // modified +} + +bool ConvertToHalfPass::ProcessImageRef(Instruction* inst) { + bool modified = false; + // If image reference, only need to convert dref args back to float32 + if (dref_image_ops_.count(inst->opcode()) != 0) { + uint32_t dref_id = inst->GetSingleWordInOperand(kImageSampleDrefIdInIdx); + if (converted_ids_.count(dref_id) > 0) { + GenConvert(&dref_id, 32, inst); + inst->SetInOperand(kImageSampleDrefIdInIdx, {dref_id}); + get_def_use_mgr()->AnalyzeInstUse(inst); + modified = true; + } + } + return modified; +} + +bool ConvertToHalfPass::ProcessDefault(Instruction* inst) { + bool modified = false; + // If non-relaxed instruction has changed operands, need to convert + // them back to float32 + inst->ForEachInId([&inst, &modified, this](uint32_t* idp) { + if (converted_ids_.count(*idp) == 0) return; + uint32_t old_id = *idp; + GenConvert(idp, 32, inst); + if (*idp != old_id) modified = true; + }); + if (modified) get_def_use_mgr()->AnalyzeInstUse(inst); + return modified; +} + +bool ConvertToHalfPass::GenHalfInst(Instruction* inst) { + bool modified = false; + // Remember id for later deletion of RelaxedPrecision decoration + bool inst_relaxed = IsRelaxed(inst->result_id()); + if (IsArithmetic(inst) && inst_relaxed) + modified = GenHalfArith(inst); + else if (inst->opcode() == SpvOpPhi && inst_relaxed) + modified = ProcessPhi(inst); + else if (inst->opcode() == SpvOpFConvert) + modified = ProcessConvert(inst); + else if (image_ops_.count(inst->opcode()) != 0) + modified = ProcessImageRef(inst); + else + modified = ProcessDefault(inst); + return modified; +} + +bool ConvertToHalfPass::CloseRelaxInst(Instruction* inst) { + if (inst->result_id() == 0) return false; + if (IsRelaxed(inst->result_id())) return false; + if (!IsFloat(inst, 32)) return false; + if (IsDecoratedRelaxed(inst)) { + AddRelaxed(inst->result_id()); + return true; + } + 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) { + Instruction* op_inst = get_def_use_mgr()->GetDef(*idp); + if (!IsFloat(op_inst, 32)) return; + if (!IsRelaxed(*idp)) relax = false; + }); + if (relax) { + AddRelaxed(inst->result_id()); + return true; + } + // Can relax if all uses are relaxed + relax = true; + get_def_use_mgr()->ForEachUser(inst, [&relax, this](Instruction* uinst) { + if (uinst->result_id() == 0 || !IsFloat(uinst, 32) || + (!IsDecoratedRelaxed(uinst) && !IsRelaxed(uinst->result_id()))) { + relax = false; + return; + } + }); + if (relax) { + AddRelaxed(inst->result_id()); + return true; + } + return false; +} + +bool ConvertToHalfPass::ProcessFunction(Function* func) { + // Do a closure of Relaxed on composite and phi instructions + bool changed = true; + while (changed) { + changed = false; + cfg()->ForEachBlockInReversePostOrder( + func->entry().get(), [&changed, this](BasicBlock* bb) { + for (auto ii = bb->begin(); ii != bb->end(); ++ii) + changed |= CloseRelaxInst(&*ii); + }); + } + // Do convert of relaxed instructions to half precision + bool modified = false; + cfg()->ForEachBlockInReversePostOrder( + func->entry().get(), [&modified, this](BasicBlock* bb) { + for (auto ii = bb->begin(); ii != bb->end(); ++ii) + modified |= GenHalfInst(&*ii); + }); + // Replace invalid converts of matrix into equivalent vector extracts, + // converts and finally a composite construct + cfg()->ForEachBlockInReversePostOrder( + func->entry().get(), [&modified, this](BasicBlock* bb) { + for (auto ii = bb->begin(); ii != bb->end(); ++ii) + modified |= MatConvertCleanup(&*ii); + }); + return modified; +} + +Pass::Status ConvertToHalfPass::ProcessImpl() { + Pass::ProcessFunction pfn = [this](Function* fp) { + return ProcessFunction(fp); + }; + bool modified = context()->ProcessEntryPointCallTree(pfn); + // If modified, make sure module has Float16 capability + if (modified) context()->AddCapability(SpvCapabilityFloat16); + // Remove all RelaxedPrecision decorations from instructions and globals + for (auto c_id : relaxed_ids_set_) RemoveRelaxedDecoration(c_id); + for (auto& val : get_module()->types_values()) { + uint32_t v_id = val.result_id(); + if (v_id != 0) RemoveRelaxedDecoration(v_id); + } + return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange; +} + +Pass::Status ConvertToHalfPass::Process() { + Initialize(); + return ProcessImpl(); +} + +void ConvertToHalfPass::Initialize() { + target_ops_core_ = { + SpvOpVectorExtractDynamic, + SpvOpVectorInsertDynamic, + SpvOpVectorShuffle, + SpvOpCompositeConstruct, + SpvOpCompositeInsert, + SpvOpCompositeExtract, + SpvOpCopyObject, + SpvOpTranspose, + SpvOpConvertSToF, + SpvOpConvertUToF, + // SpvOpFConvert, + // SpvOpQuantizeToF16, + SpvOpFNegate, + SpvOpFAdd, + SpvOpFSub, + SpvOpFMul, + SpvOpFDiv, + SpvOpFMod, + SpvOpVectorTimesScalar, + SpvOpMatrixTimesScalar, + SpvOpVectorTimesMatrix, + SpvOpMatrixTimesVector, + SpvOpMatrixTimesMatrix, + SpvOpOuterProduct, + SpvOpDot, + SpvOpSelect, + SpvOpFOrdEqual, + SpvOpFUnordEqual, + SpvOpFOrdNotEqual, + SpvOpFUnordNotEqual, + SpvOpFOrdLessThan, + SpvOpFUnordLessThan, + SpvOpFOrdGreaterThan, + SpvOpFUnordGreaterThan, + SpvOpFOrdLessThanEqual, + SpvOpFUnordLessThanEqual, + SpvOpFOrdGreaterThanEqual, + SpvOpFUnordGreaterThanEqual, + }; + target_ops_450_ = { + GLSLstd450Round, GLSLstd450RoundEven, GLSLstd450Trunc, GLSLstd450FAbs, + GLSLstd450FSign, GLSLstd450Floor, GLSLstd450Ceil, GLSLstd450Fract, + GLSLstd450Radians, GLSLstd450Degrees, GLSLstd450Sin, GLSLstd450Cos, + GLSLstd450Tan, GLSLstd450Asin, GLSLstd450Acos, GLSLstd450Atan, + GLSLstd450Sinh, GLSLstd450Cosh, GLSLstd450Tanh, GLSLstd450Asinh, + GLSLstd450Acosh, GLSLstd450Atanh, GLSLstd450Atan2, GLSLstd450Pow, + GLSLstd450Exp, GLSLstd450Log, GLSLstd450Exp2, GLSLstd450Log2, + GLSLstd450Sqrt, GLSLstd450InverseSqrt, GLSLstd450Determinant, + GLSLstd450MatrixInverse, + // TODO(greg-lunarg): GLSLstd450ModfStruct, + GLSLstd450FMin, GLSLstd450FMax, GLSLstd450FClamp, GLSLstd450FMix, + GLSLstd450Step, GLSLstd450SmoothStep, GLSLstd450Fma, + // TODO(greg-lunarg): GLSLstd450FrexpStruct, + GLSLstd450Ldexp, GLSLstd450Length, GLSLstd450Distance, GLSLstd450Cross, + GLSLstd450Normalize, GLSLstd450FaceForward, GLSLstd450Reflect, + GLSLstd450Refract, GLSLstd450NMin, GLSLstd450NMax, GLSLstd450NClamp}; + image_ops_ = {SpvOpImageSampleImplicitLod, + SpvOpImageSampleExplicitLod, + SpvOpImageSampleDrefImplicitLod, + SpvOpImageSampleDrefExplicitLod, + SpvOpImageSampleProjImplicitLod, + SpvOpImageSampleProjExplicitLod, + SpvOpImageSampleProjDrefImplicitLod, + SpvOpImageSampleProjDrefExplicitLod, + SpvOpImageFetch, + SpvOpImageGather, + SpvOpImageDrefGather, + SpvOpImageRead, + SpvOpImageSparseSampleImplicitLod, + SpvOpImageSparseSampleExplicitLod, + SpvOpImageSparseSampleDrefImplicitLod, + SpvOpImageSparseSampleDrefExplicitLod, + SpvOpImageSparseSampleProjImplicitLod, + SpvOpImageSparseSampleProjExplicitLod, + SpvOpImageSparseSampleProjDrefImplicitLod, + SpvOpImageSparseSampleProjDrefExplicitLod, + SpvOpImageSparseFetch, + SpvOpImageSparseGather, + SpvOpImageSparseDrefGather, + SpvOpImageSparseTexelsResident, + SpvOpImageSparseRead}; + dref_image_ops_ = { + SpvOpImageSampleDrefImplicitLod, + SpvOpImageSampleDrefExplicitLod, + SpvOpImageSampleProjDrefImplicitLod, + SpvOpImageSampleProjDrefExplicitLod, + SpvOpImageDrefGather, + SpvOpImageSparseSampleDrefImplicitLod, + SpvOpImageSparseSampleDrefExplicitLod, + SpvOpImageSparseSampleProjDrefImplicitLod, + SpvOpImageSparseSampleProjDrefExplicitLod, + SpvOpImageSparseDrefGather, + }; + closure_ops_ = { + SpvOpVectorExtractDynamic, + SpvOpVectorInsertDynamic, + SpvOpVectorShuffle, + SpvOpCompositeConstruct, + SpvOpCompositeInsert, + SpvOpCompositeExtract, + SpvOpCopyObject, + SpvOpTranspose, + SpvOpPhi, + }; + relaxed_ids_set_.clear(); + converted_ids_.clear(); +} + +} // namespace opt +} // namespace spvtools diff --git a/third_party/spirv-tools/source/opt/convert_to_half_pass.h b/third_party/spirv-tools/source/opt/convert_to_half_pass.h new file mode 100644 index 0000000000..143aebfa28 --- /dev/null +++ b/third_party/spirv-tools/source/opt/convert_to_half_pass.h @@ -0,0 +1,148 @@ +// Copyright (c) 2019 Valve Corporation +// Copyright (c) 2019 LunarG Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef LIBSPIRV_OPT_CONVERT_TO_HALF_PASS_H_ +#define LIBSPIRV_OPT_CONVERT_TO_HALF_PASS_H_ + +#include "source/opt/ir_builder.h" +#include "source/opt/pass.h" + +namespace spvtools { +namespace opt { + +class ConvertToHalfPass : public Pass { + public: + ConvertToHalfPass() : Pass() {} + + ~ConvertToHalfPass() override = default; + + IRContext::Analysis GetPreservedAnalyses() override { + return IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping; + } + + // See optimizer.hpp for pass user documentation. + Status Process() override; + + const char* name() const override { return "convert-to-half-pass"; } + + private: + // Return true if |inst| is an arithmetic, composite or phi op that can be + // of type float16 + bool IsArithmetic(Instruction* inst); + + // Return true if |inst| returns scalar, vector or matrix type with base + // float and |width| + bool IsFloat(Instruction* inst, uint32_t width); + + // Return true if |inst| is decorated with RelaxedPrecision + bool IsDecoratedRelaxed(Instruction* inst); + + // Return true if |id| has been added to the relaxed id set + bool IsRelaxed(uint32_t id); + + // Add |id| to the relaxed id set + void AddRelaxed(uint32_t id); + + // Return type id for float with |width| + analysis::Type* FloatScalarType(uint32_t width); + + // Return type id for vector of length |vlen| of float of |width| + analysis::Type* FloatVectorType(uint32_t v_len, uint32_t width); + + // Return type id for matrix of |v_cnt| vectors of length identical to + // |vty_id| of float of |width| + analysis::Type* FloatMatrixType(uint32_t v_cnt, uint32_t vty_id, + uint32_t width); + + // Return equivalent to float type |ty_id| with |width| + uint32_t EquivFloatTypeId(uint32_t ty_id, uint32_t width); + + // Append instructions to builder to convert value |*val_idp| to type + // |ty_id| but with |width|. Set |*val_idp| to the new id. + void GenConvert(uint32_t* val_idp, uint32_t width, Instruction* inst); + + // Remove RelaxedPrecision decoration of |id|. + void RemoveRelaxedDecoration(uint32_t id); + + // Add |inst| to relaxed instruction set if warranted. Specifically, if + // it is float32 and either decorated relaxed or a composite or phi + // instruction where all operands are relaxed or all uses are relaxed. + bool CloseRelaxInst(Instruction* inst); + + // If |inst| is an arithmetic, phi, extract or convert instruction of float32 + // base type and decorated with RelaxedPrecision, change it to the equivalent + // float16 based type instruction. Specifically, insert instructions to + // convert all operands to float16 (if needed) and change its type to the + // equivalent float16 type. Otherwise, insert instructions to convert its + // operands back to their original types, if needed. + bool GenHalfInst(Instruction* inst); + + // Gen code for relaxed arithmetic |inst| + bool GenHalfArith(Instruction* inst); + + // Gen code for relaxed phi |inst| + bool ProcessPhi(Instruction* inst); + + // Gen code for relaxed convert |inst| + bool ProcessConvert(Instruction* inst); + + // Gen code for image reference |inst| + bool ProcessImageRef(Instruction* inst); + + // Process default non-relaxed |inst| + bool ProcessDefault(Instruction* inst); + + // If |inst| is an FConvert of a matrix type, decompose it to a series + // of vector extracts, converts and inserts into an Undef. These are + // generated by GenHalfInst because they are easier to manipulate, but are + // invalid so we need to clean them up. + bool MatConvertCleanup(Instruction* inst); + + // Call GenHalfInst on every instruction in |func|. + // If code is generated for an instruction, replace the instruction + // with the new instructions that are generated. + bool ProcessFunction(Function* func); + + Pass::Status ProcessImpl(); + + // Initialize state for converting to half + void Initialize(); + + // Set of core operations to be processed + std::unordered_set target_ops_core_; + + // Set of 450 extension operations to be processed + std::unordered_set target_ops_450_; + + // Set of sample operations + std::unordered_set image_ops_; + + // Set of dref sample operations + std::unordered_set dref_image_ops_; + + // Set of dref sample operations + std::unordered_set closure_ops_; + + // Set of ids of all relaxed instructions + std::unordered_set relaxed_ids_set_; + + // Ids of all converted instructions + std::unordered_set converted_ids_; +}; + +} // namespace opt +} // namespace spvtools + +#endif // LIBSPIRV_OPT_CONVERT_TO_HALF_PASS_H_ diff --git a/third_party/spirv-tools/source/opt/copy_prop_arrays.cpp b/third_party/spirv-tools/source/opt/copy_prop_arrays.cpp index 028b237d73..b3b90da533 100644 --- a/third_party/spirv-tools/source/opt/copy_prop_arrays.cpp +++ b/third_party/spirv-tools/source/opt/copy_prop_arrays.cpp @@ -26,6 +26,8 @@ const uint32_t kLoadPointerInOperand = 0; const uint32_t kStorePointerInOperand = 0; const uint32_t kStoreObjectInOperand = 1; const uint32_t kCompositeExtractObjectInOperand = 0; +const uint32_t kTypePointerStorageClassInIdx = 0; +const uint32_t kTypePointerPointeeInIdx = 1; } // namespace @@ -51,7 +53,7 @@ Pass::Status CopyPropagateArrays::Process() { FindSourceObjectIfPossible(&*var_inst, store_inst); if (source_object != nullptr) { - if (CanUpdateUses(&*var_inst, source_object->GetPointerTypeId())) { + if (CanUpdateUses(&*var_inst, source_object->GetPointerTypeId(this))) { modified = true; PropagateObject(&*var_inst, source_object.get(), store_inst); } @@ -139,7 +141,7 @@ Instruction* CopyPropagateArrays::BuildNewAccessChain( return source->GetVariable(); } - return builder.AddAccessChain(source->GetPointerTypeId(), + return builder.AddAccessChain(source->GetPointerTypeId(this), source->GetVariable()->result_id(), source->AccessChain()); } @@ -304,8 +306,7 @@ CopyPropagateArrays::BuildMemoryObjectFromCompositeConstruct( analysis::ConstantManager* const_mgr = context()->get_constant_mgr(); const analysis::Constant* last_access = const_mgr->FindDeclaredConstant(memory_object->AccessChain().back()); - if (!last_access || - (!last_access->AsIntConstant() && !last_access->AsNullConstant())) { + if (!last_access || !last_access->type()->AsInteger()) { return nullptr; } @@ -324,6 +325,10 @@ CopyPropagateArrays::BuildMemoryObjectFromCompositeConstruct( std::unique_ptr member_object = GetSourceObjectIfAny(conststruct_inst->GetSingleWordInOperand(i)); + if (!member_object) { + return nullptr; + } + if (!member_object->IsMember()) { return nullptr; } @@ -334,7 +339,7 @@ CopyPropagateArrays::BuildMemoryObjectFromCompositeConstruct( last_access = const_mgr->FindDeclaredConstant(member_object->AccessChain().back()); - if (!last_access || !last_access->AsIntConstant()) { + if (!last_access || !last_access->type()->AsInteger()) { return nullptr; } @@ -362,8 +367,7 @@ CopyPropagateArrays::BuildMemoryObjectFromInsert(Instruction* insert_inst) { } else if (const analysis::Array* array_type = result_type->AsArray()) { const analysis::Constant* length_const = const_mgr->FindDeclaredConstant(array_type->LengthId()); - assert(length_const->AsIntConstant()); - number_of_elements = length_const->AsIntConstant()->GetU32(); + number_of_elements = length_const->GetU32(); } else if (const analysis::Vector* vector_type = result_type->AsVector()) { number_of_elements = vector_type->element_count(); } else if (const analysis::Matrix* matrix_type = result_type->AsMatrix()) { @@ -395,7 +399,7 @@ CopyPropagateArrays::BuildMemoryObjectFromInsert(Instruction* insert_inst) { const analysis::Constant* last_access = const_mgr->FindDeclaredConstant(memory_object->AccessChain().back()); - if (!last_access || !last_access->AsIntConstant()) { + if (!last_access || !last_access->type()->AsInteger()) { return nullptr; } @@ -443,7 +447,7 @@ CopyPropagateArrays::BuildMemoryObjectFromInsert(Instruction* insert_inst) { const analysis::Constant* current_last_access = const_mgr->FindDeclaredConstant( current_memory_object->AccessChain().back()); - if (!current_last_access || !current_last_access->AsIntConstant()) { + if (!current_last_access || !current_last_access->type()->AsInteger()) { return nullptr; } @@ -484,88 +488,85 @@ bool CopyPropagateArrays::CanUpdateUses(Instruction* original_ptr_inst, return true; } - return def_use_mgr->WhileEachUse( - original_ptr_inst, - [this, type_mgr, const_mgr, type](Instruction* use, uint32_t) { - switch (use->opcode()) { - case SpvOpLoad: { - analysis::Pointer* pointer_type = type->AsPointer(); - uint32_t new_type_id = - type_mgr->GetId(pointer_type->pointee_type()); + return def_use_mgr->WhileEachUse(original_ptr_inst, [this, type_mgr, + const_mgr, + type](Instruction* use, + uint32_t) { + switch (use->opcode()) { + case SpvOpLoad: { + analysis::Pointer* pointer_type = type->AsPointer(); + uint32_t new_type_id = type_mgr->GetId(pointer_type->pointee_type()); - if (new_type_id != use->type_id()) { - return CanUpdateUses(use, new_type_id); - } - return true; - } - case SpvOpAccessChain: { - analysis::Pointer* pointer_type = type->AsPointer(); - const analysis::Type* pointee_type = pointer_type->pointee_type(); - - std::vector access_chain; - for (uint32_t i = 1; i < use->NumInOperands(); ++i) { - const analysis::Constant* index_const = - const_mgr->FindDeclaredConstant( - use->GetSingleWordInOperand(i)); - if (index_const) { - access_chain.push_back(index_const->AsIntConstant()->GetU32()); - } else { - // Variable index means the type is a type where every element - // is the same type. Use element 0 to get the type. - access_chain.push_back(0); - } - } - - const analysis::Type* new_pointee_type = - type_mgr->GetMemberType(pointee_type, access_chain); - analysis::Pointer pointerTy(new_pointee_type, - pointer_type->storage_class()); - uint32_t new_pointer_type_id = - context()->get_type_mgr()->GetTypeInstruction(&pointerTy); - - if (new_pointer_type_id != use->type_id()) { - return CanUpdateUses(use, new_pointer_type_id); - } - return true; - } - case SpvOpCompositeExtract: { - std::vector access_chain; - for (uint32_t i = 1; i < use->NumInOperands(); ++i) { - access_chain.push_back(use->GetSingleWordInOperand(i)); - } - - const analysis::Type* new_type = - type_mgr->GetMemberType(type, access_chain); - uint32_t new_type_id = type_mgr->GetTypeInstruction(new_type); - - if (new_type_id != use->type_id()) { - return CanUpdateUses(use, new_type_id); - } - return true; - } - case SpvOpStore: - // Can't handle changing the type of a store. There are too many - // other things that might need to change as well. Not worth the - // effort. Punting for now. - - // TODO (s-perron): This can be handled by expanding the store into - // a series of extracts, composite constructs, and a store. - return true; - case SpvOpImageTexelPointer: - case SpvOpName: - return true; - default: - return use->IsDecoration(); + if (new_type_id != use->type_id()) { + return CanUpdateUses(use, new_type_id); } - }); + return true; + } + case SpvOpAccessChain: { + analysis::Pointer* pointer_type = type->AsPointer(); + const analysis::Type* pointee_type = pointer_type->pointee_type(); + + std::vector access_chain; + for (uint32_t i = 1; i < use->NumInOperands(); ++i) { + const analysis::Constant* index_const = + const_mgr->FindDeclaredConstant(use->GetSingleWordInOperand(i)); + if (index_const) { + access_chain.push_back(index_const->GetU32()); + } else { + // Variable index means the type is a type where every element + // is the same type. Use element 0 to get the type. + access_chain.push_back(0); + } + } + + const analysis::Type* new_pointee_type = + type_mgr->GetMemberType(pointee_type, access_chain); + analysis::Pointer pointerTy(new_pointee_type, + pointer_type->storage_class()); + uint32_t new_pointer_type_id = + context()->get_type_mgr()->GetTypeInstruction(&pointerTy); + if (new_pointer_type_id == 0) { + return false; + } + + if (new_pointer_type_id != use->type_id()) { + return CanUpdateUses(use, new_pointer_type_id); + } + return true; + } + case SpvOpCompositeExtract: { + std::vector access_chain; + for (uint32_t i = 1; i < use->NumInOperands(); ++i) { + access_chain.push_back(use->GetSingleWordInOperand(i)); + } + + const analysis::Type* new_type = + type_mgr->GetMemberType(type, access_chain); + uint32_t new_type_id = type_mgr->GetTypeInstruction(new_type); + if (new_type_id == 0) { + return false; + } + + if (new_type_id != use->type_id()) { + return CanUpdateUses(use, new_type_id); + } + return true; + } + case SpvOpStore: + // If needed, we can create an element-by-element copy to change the + // type of the value being stored. This way we can always handled + // stores. + return true; + case SpvOpImageTexelPointer: + case SpvOpName: + return true; + default: + return use->IsDecoration(); + } + }); } void CopyPropagateArrays::UpdateUses(Instruction* original_ptr_inst, Instruction* new_ptr_inst) { - // TODO (s-perron): Keep the def-use manager up to date. Not done now because - // it can cause problems for the |ForEachUse| traversals. Can be use by - // keeping a list of instructions that need updating, and then updating them - // in |PropagateObject|. - analysis::TypeManager* type_mgr = context()->get_type_mgr(); analysis::ConstantManager* const_mgr = context()->get_constant_mgr(); analysis::DefUseManager* def_use_mgr = context()->get_def_use_mgr(); @@ -579,7 +580,6 @@ void CopyPropagateArrays::UpdateUses(Instruction* original_ptr_inst, for (auto pair : uses) { Instruction* use = pair.first; uint32_t index = pair.second; - analysis::Pointer* pointer_type = nullptr; switch (use->opcode()) { case SpvOpLoad: { // Replace the actual use. @@ -587,8 +587,10 @@ void CopyPropagateArrays::UpdateUses(Instruction* original_ptr_inst, use->SetOperand(index, {new_ptr_inst->result_id()}); // Update the type. - pointer_type = type_mgr->GetType(new_ptr_inst->type_id())->AsPointer(); - uint32_t new_type_id = type_mgr->GetId(pointer_type->pointee_type()); + Instruction* pointer_type_inst = + def_use_mgr->GetDef(new_ptr_inst->type_id()); + uint32_t new_type_id = + pointer_type_inst->GetSingleWordInOperand(kTypePointerPointeeInIdx); if (new_type_id != use->type_id()) { use->SetResultType(new_type_id); context()->AnalyzeUses(use); @@ -602,10 +604,6 @@ void CopyPropagateArrays::UpdateUses(Instruction* original_ptr_inst, context()->ForgetUses(use); use->SetOperand(index, {new_ptr_inst->result_id()}); - // Update the result type. - pointer_type = type_mgr->GetType(new_ptr_inst->type_id())->AsPointer(); - const analysis::Type* pointee_type = pointer_type->pointee_type(); - // Convert the ids on the OpAccessChain to indices that can be used to // get the specific member. std::vector access_chain; @@ -613,21 +611,27 @@ void CopyPropagateArrays::UpdateUses(Instruction* original_ptr_inst, const analysis::Constant* index_const = const_mgr->FindDeclaredConstant(use->GetSingleWordInOperand(i)); if (index_const) { - access_chain.push_back(index_const->AsIntConstant()->GetU32()); + access_chain.push_back(index_const->GetU32()); } else { // Variable index means the type is an type where every element // is the same type. Use element 0 to get the type. access_chain.push_back(0); } } - const analysis::Type* new_pointee_type = - type_mgr->GetMemberType(pointee_type, access_chain); - // Now build a pointer to the type of the member. - analysis::Pointer new_pointer_type(new_pointee_type, - pointer_type->storage_class()); + Instruction* pointer_type_inst = + get_def_use_mgr()->GetDef(new_ptr_inst->type_id()); + + uint32_t new_pointee_type_id = GetMemberTypeId( + pointer_type_inst->GetSingleWordInOperand(kTypePointerPointeeInIdx), + access_chain); + + SpvStorageClass storage_class = static_cast( + pointer_type_inst->GetSingleWordInOperand( + kTypePointerStorageClassInIdx)); + uint32_t new_pointer_type_id = - context()->get_type_mgr()->GetTypeInstruction(&new_pointer_type); + type_mgr->FindPointerToType(new_pointee_type_id, storage_class); if (new_pointer_type_id != use->type_id()) { use->SetResultType(new_pointer_type_id); @@ -642,15 +646,13 @@ void CopyPropagateArrays::UpdateUses(Instruction* original_ptr_inst, context()->ForgetUses(use); use->SetOperand(index, {new_ptr_inst->result_id()}); + uint32_t new_type_id = new_ptr_inst->type_id(); std::vector access_chain; for (uint32_t i = 1; i < use->NumInOperands(); ++i) { access_chain.push_back(use->GetSingleWordInOperand(i)); } - const analysis::Type* type = type_mgr->GetType(new_ptr_inst->type_id()); - const analysis::Type* new_type = - type_mgr->GetMemberType(type, access_chain); - uint32_t new_type_id = type_mgr->GetTypeInstruction(new_type); + new_type_id = GetMemberTypeId(new_type_id, access_chain); if (new_type_id != use->type_id()) { use->SetResultType(new_type_id); @@ -672,11 +674,11 @@ void CopyPropagateArrays::UpdateUses(Instruction* original_ptr_inst, if (index == 1) { Instruction* target_pointer = def_use_mgr->GetDef( use->GetSingleWordInOperand(kStorePointerInOperand)); - pointer_type = - type_mgr->GetType(target_pointer->type_id())->AsPointer(); - uint32_t copy = - GenerateCopy(original_ptr_inst, - type_mgr->GetId(pointer_type->pointee_type()), use); + Instruction* pointer_type = + def_use_mgr->GetDef(target_pointer->type_id()); + uint32_t pointee_type_id = + pointer_type->GetSingleWordInOperand(kTypePointerPointeeInIdx); + uint32_t copy = GenerateCopy(original_ptr_inst, pointee_type_id, use); context()->ForgetUses(use); use->SetInOperand(index, {copy}); @@ -700,72 +702,27 @@ void CopyPropagateArrays::UpdateUses(Instruction* original_ptr_inst, } } -uint32_t CopyPropagateArrays::GenerateCopy(Instruction* object_inst, - uint32_t new_type_id, - Instruction* insertion_position) { - analysis::TypeManager* type_mgr = context()->get_type_mgr(); - analysis::ConstantManager* const_mgr = context()->get_constant_mgr(); - - uint32_t original_type_id = object_inst->type_id(); - if (original_type_id == new_type_id) { - return object_inst->result_id(); - } - - InstructionBuilder ir_builder( - context(), insertion_position, - IRContext::kAnalysisInstrToBlockMapping | IRContext::kAnalysisDefUse); - - analysis::Type* original_type = type_mgr->GetType(original_type_id); - analysis::Type* new_type = type_mgr->GetType(new_type_id); - - if (const analysis::Array* original_array_type = original_type->AsArray()) { - uint32_t original_element_type_id = - type_mgr->GetId(original_array_type->element_type()); - - analysis::Array* new_array_type = new_type->AsArray(); - assert(new_array_type != nullptr && "Can't copy an array to a non-array."); - uint32_t new_element_type_id = - type_mgr->GetId(new_array_type->element_type()); - - std::vector element_ids; - const analysis::Constant* length_const = - const_mgr->FindDeclaredConstant(original_array_type->LengthId()); - assert(length_const->AsIntConstant()); - uint32_t array_length = length_const->AsIntConstant()->GetU32(); - for (uint32_t i = 0; i < array_length; i++) { - Instruction* extract = ir_builder.AddCompositeExtract( - original_element_type_id, object_inst->result_id(), {i}); - element_ids.push_back( - GenerateCopy(extract, new_element_type_id, insertion_position)); +uint32_t CopyPropagateArrays::GetMemberTypeId( + uint32_t id, const std::vector& access_chain) const { + for (uint32_t element_index : access_chain) { + Instruction* type_inst = get_def_use_mgr()->GetDef(id); + switch (type_inst->opcode()) { + case SpvOpTypeArray: + case SpvOpTypeRuntimeArray: + case SpvOpTypeMatrix: + case SpvOpTypeVector: + id = type_inst->GetSingleWordInOperand(0); + break; + case SpvOpTypeStruct: + id = type_inst->GetSingleWordInOperand(element_index); + break; + default: + break; } - - return ir_builder.AddCompositeConstruct(new_type_id, element_ids) - ->result_id(); - } else if (const analysis::Struct* original_struct_type = - original_type->AsStruct()) { - analysis::Struct* new_struct_type = new_type->AsStruct(); - - const std::vector& original_types = - original_struct_type->element_types(); - const std::vector& new_types = - new_struct_type->element_types(); - std::vector element_ids; - for (uint32_t i = 0; i < original_types.size(); i++) { - Instruction* extract = ir_builder.AddCompositeExtract( - type_mgr->GetId(original_types[i]), object_inst->result_id(), {i}); - element_ids.push_back(GenerateCopy(extract, type_mgr->GetId(new_types[i]), - insertion_position)); - } - return ir_builder.AddCompositeConstruct(new_type_id, element_ids) - ->result_id(); - } else { - // If we do not have an aggregate type, then we have a problem. Either we - // found multiple instances of the same type, or we are copying to an - // incompatible type. Either way the code is illegal. - assert(false && - "Don't know how to copy this type. Code is likely illegal."); + assert(id != 0 && + "Tried to extract from an object where it cannot be done."); } - return 0; + return id; } void CopyPropagateArrays::MemoryObject::GetMember( @@ -790,8 +747,8 @@ uint32_t CopyPropagateArrays::MemoryObject::GetNumberOfMembers() { const analysis::Constant* length_const = context->get_constant_mgr()->FindDeclaredConstant( array_type->LengthId()); - assert(length_const->AsIntConstant()); - return length_const->AsIntConstant()->GetU32(); + assert(length_const->type()->AsInteger()); + return length_const->GetU32(); } else if (const analysis::Vector* vector_type = type->AsVector()) { return vector_type->element_count(); } else if (const analysis::Matrix* matrix_type = type->AsMatrix()) { @@ -817,8 +774,7 @@ std::vector CopyPropagateArrays::MemoryObject::GetAccessIds() const { if (!element_index_const) { access_indices.push_back(0); } else { - assert(element_index_const->AsIntConstant()); - access_indices.push_back(element_index_const->AsIntConstant()->GetU32()); + access_indices.push_back(element_index_const->GetU32()); } } return access_indices; diff --git a/third_party/spirv-tools/source/opt/copy_prop_arrays.h b/third_party/spirv-tools/source/opt/copy_prop_arrays.h index abc07165f4..f4314a74b7 100644 --- a/third_party/spirv-tools/source/opt/copy_prop_arrays.h +++ b/third_party/spirv-tools/source/opt/copy_prop_arrays.h @@ -47,7 +47,8 @@ class CopyPropagateArrays : public MemPass { return IRContext::kAnalysisDefUse | IRContext::kAnalysisCFG | IRContext::kAnalysisInstrToBlockMapping | IRContext::kAnalysisLoopAnalysis | IRContext::kAnalysisDecorations | - IRContext::kAnalysisDominatorAnalysis | IRContext::kAnalysisNameMap; + IRContext::kAnalysisDominatorAnalysis | IRContext::kAnalysisNameMap | + IRContext::kAnalysisConstants | IRContext::kAnalysisTypes; } private: @@ -98,18 +99,21 @@ class CopyPropagateArrays : public MemPass { // Returns the type id of the pointer type that can be used to point to this // memory object. - uint32_t GetPointerTypeId() const { + uint32_t GetPointerTypeId(const CopyPropagateArrays* pass) const { + analysis::DefUseManager* def_use_mgr = + GetVariable()->context()->get_def_use_mgr(); analysis::TypeManager* type_mgr = GetVariable()->context()->get_type_mgr(); - const analysis::Pointer* pointer_type = - type_mgr->GetType(GetVariable()->type_id())->AsPointer(); - const analysis::Type* var_type = pointer_type->pointee_type(); - const analysis::Type* member_type = - type_mgr->GetMemberType(var_type, GetAccessIds()); - uint32_t member_type_id = type_mgr->GetId(member_type); - assert(member_type != 0); + + Instruction* var_pointer_inst = + def_use_mgr->GetDef(GetVariable()->type_id()); + + uint32_t member_type_id = pass->GetMemberTypeId( + var_pointer_inst->GetSingleWordInOperand(1), GetAccessIds()); + uint32_t member_pointer_type_id = type_mgr->FindPointerToType( - member_type_id, pointer_type->storage_class()); + member_type_id, static_cast( + var_pointer_inst->GetSingleWordInOperand(0))); return member_pointer_type_id; } @@ -213,16 +217,16 @@ class CopyPropagateArrays : public MemPass { // |original_ptr_inst| to |type_id| and still have valid code. bool CanUpdateUses(Instruction* original_ptr_inst, uint32_t type_id); - // Returns the id whose value is the same as |object_to_copy| except its type - // is |new_type_id|. Any instructions need to generate this value will be - // inserted before |insertion_position|. - uint32_t GenerateCopy(Instruction* object_to_copy, uint32_t new_type_id, - Instruction* insertion_position); - // Returns a store to |var_inst| that writes to the entire variable, and is // the only store that does so. Note it does not look through OpAccessChain // instruction, so partial stores are not considered. Instruction* FindStoreInstruction(const Instruction* var_inst) const; + + // Return the type id of the member of the type |id| access using + // |access_chain|. The elements of |access_chain| are to be interpreted the + // same way the indexes are used in an |OpCompositeExtract| instruction. + uint32_t GetMemberTypeId(uint32_t id, + const std::vector& access_chain) const; }; } // namespace opt diff --git a/third_party/spirv-tools/source/opt/dead_branch_elim_pass.cpp b/third_party/spirv-tools/source/opt/dead_branch_elim_pass.cpp index b147ef74ca..16d9fd5636 100644 --- a/third_party/spirv-tools/source/opt/dead_branch_elim_pass.cpp +++ b/third_party/spirv-tools/source/opt/dead_branch_elim_pass.cpp @@ -24,6 +24,7 @@ #include "source/cfa.h" #include "source/opt/ir_context.h" #include "source/opt/iterator.h" +#include "source/opt/struct_cfg_analysis.h" #include "source/util/make_unique.h" namespace spvtools { @@ -92,7 +93,8 @@ BasicBlock* DeadBranchElimPass::GetParentBlock(uint32_t id) { bool DeadBranchElimPass::MarkLiveBlocks( Function* func, std::unordered_set* live_blocks) { - std::unordered_set continues; + std::vector> conditions_to_simplify; + std::unordered_set blocks_with_backedge; std::vector stack; stack.push_back(&*func->begin()); bool modified = false; @@ -104,7 +106,10 @@ bool DeadBranchElimPass::MarkLiveBlocks( if (!live_blocks->insert(block).second) continue; uint32_t cont_id = block->ContinueBlockIdIfAny(); - if (cont_id != 0) continues.insert(GetParentBlock(cont_id)); + if (cont_id != 0) { + AddBlocksWithBackEdge(cont_id, block->id(), block->MergeBlockIdIfAny(), + &blocks_with_backedge); + } Instruction* terminator = block->terminator(); uint32_t live_lab_id = 0; @@ -143,33 +148,26 @@ bool DeadBranchElimPass::MarkLiveBlocks( } } - // Don't simplify branches of continue blocks. A path from the continue to - // the header is required. - // TODO(alan-baker): They can be simplified iff there remains a path to the - // backedge. Structured control flow should guarantee one path hits the - // backedge, but I've removed the requirement for structured control flow - // from this pass. - bool simplify = live_lab_id != 0 && !continues.count(block); - - if (simplify) { - modified = true; - // Replace with unconditional branch. - // Remove the merge instruction if it is a selection merge. - AddBranch(live_lab_id, block); - context()->KillInst(terminator); - Instruction* mergeInst = block->GetMergeInst(); - if (mergeInst && mergeInst->opcode() == SpvOpSelectionMerge) { - Instruction* first_break = FindFirstExitFromSelectionMerge( - live_lab_id, mergeInst->GetSingleWordInOperand(0)); - if (first_break == nullptr) { - context()->KillInst(mergeInst); - } else { - mergeInst->RemoveFromList(); - first_break->InsertBefore(std::unique_ptr(mergeInst)); - context()->set_instr_block(mergeInst, - context()->get_instr_block(first_break)); + // Don't simplify back edges unless it becomes a branch to the header. Every + // loop must have exactly one back edge to the loop header, so we cannot + // remove it. + bool simplify = false; + if (live_lab_id != 0) { + if (!blocks_with_backedge.count(block)) { + // This is not a back edge. + simplify = true; + } else { + const auto& struct_cfg_analysis = context()->GetStructuredCFGAnalysis(); + uint32_t header_id = struct_cfg_analysis->ContainingLoop(block->id()); + if (live_lab_id == header_id) { + // The new branch will be a branch to the header. + simplify = true; } } + } + + if (simplify) { + conditions_to_simplify.push_back({block, live_lab_id}); stack.push_back(GetParentBlock(live_lab_id)); } else { // All successors are live. @@ -180,9 +178,66 @@ bool DeadBranchElimPass::MarkLiveBlocks( } } + // Traverse |conditions_to_simplify| in reverse order. This is done so that + // we simplify nested constructs before simplifying the constructs that + // contain them. + for (auto b = conditions_to_simplify.rbegin(); + b != conditions_to_simplify.rend(); ++b) { + modified |= SimplifyBranch(b->first, b->second); + } + return modified; } +bool DeadBranchElimPass::SimplifyBranch(BasicBlock* block, + uint32_t live_lab_id) { + Instruction* merge_inst = block->GetMergeInst(); + Instruction* terminator = block->terminator(); + if (merge_inst && merge_inst->opcode() == SpvOpSelectionMerge) { + if (merge_inst->NextNode()->opcode() == SpvOpSwitch && + SwitchHasNestedBreak(block->id())) { + if (terminator->NumInOperands() == 2) { + // We cannot remove the branch, and it already has a single case, so no + // work to do. + return false; + } + // We have to keep the switch because it has a nest break, so we + // remove all cases except for the live one. + Instruction::OperandList new_operands; + new_operands.push_back(terminator->GetInOperand(0)); + new_operands.push_back({SPV_OPERAND_TYPE_ID, {live_lab_id}}); + terminator->SetInOperands(move(new_operands)); + context()->UpdateDefUse(terminator); + } else { + // Check if the merge instruction is still needed because of a + // non-nested break from the construct. Move the merge instruction if + // it is still needed. + StructuredCFGAnalysis* cfg_analysis = + context()->GetStructuredCFGAnalysis(); + Instruction* first_break = FindFirstExitFromSelectionMerge( + live_lab_id, merge_inst->GetSingleWordInOperand(0), + cfg_analysis->LoopMergeBlock(live_lab_id), + cfg_analysis->LoopContinueBlock(live_lab_id), + cfg_analysis->SwitchMergeBlock(live_lab_id)); + + AddBranch(live_lab_id, block); + context()->KillInst(terminator); + if (first_break == nullptr) { + context()->KillInst(merge_inst); + } else { + merge_inst->RemoveFromList(); + first_break->InsertBefore(std::unique_ptr(merge_inst)); + context()->set_instr_block(merge_inst, + context()->get_instr_block(first_break)); + } + } + } else { + AddBranch(live_lab_id, block); + context()->KillInst(terminator); + } + return true; +} + void DeadBranchElimPass::MarkUnreachableStructuredTargets( const std::unordered_set& live_blocks, std::unordered_set* unreachable_merges, @@ -318,20 +373,7 @@ bool DeadBranchElimPass::EraseDeadBlocks( const std::unordered_map& unreachable_continues) { bool modified = false; for (auto ebi = func->begin(); ebi != func->end();) { - if (unreachable_merges.count(&*ebi)) { - if (ebi->begin() != ebi->tail() || - ebi->terminator()->opcode() != SpvOpUnreachable) { - // Make unreachable, but leave the label. - KillAllInsts(&*ebi, false); - // Add unreachable terminator. - ebi->AddInstruction( - MakeUnique(context(), SpvOpUnreachable, 0, 0, - std::initializer_list{})); - context()->set_instr_block(&*ebi->tail(), &*ebi); - modified = true; - } - ++ebi; - } else if (unreachable_continues.count(&*ebi)) { + if (unreachable_continues.count(&*ebi)) { uint32_t cont_id = unreachable_continues.find(&*ebi)->second->id(); if (ebi->begin() != ebi->tail() || ebi->terminator()->opcode() != SpvOpBranch || @@ -348,6 +390,20 @@ bool DeadBranchElimPass::EraseDeadBlocks( modified = true; } ++ebi; + } else if (unreachable_merges.count(&*ebi)) { + if (ebi->begin() != ebi->tail() || + ebi->terminator()->opcode() != SpvOpUnreachable) { + // Make unreachable, but leave the label. + KillAllInsts(&*ebi, false); + // Add unreachable terminator. + ebi->AddInstruction( + MakeUnique(context(), SpvOpUnreachable, 0, 0, + std::initializer_list{})); + context()->AnalyzeUses(ebi->terminator()); + context()->set_instr_block(ebi->terminator(), &*ebi); + modified = true; + } + ++ebi; } else if (!live_blocks.count(&*ebi)) { // Kill this block. KillAllInsts(&*ebi); @@ -413,9 +469,9 @@ void DeadBranchElimPass::FixBlockOrder() { // Structured order is more intuitive so use it where possible. if (context()->get_feature_mgr()->HasCapability(SpvCapabilityShader)) { - ProcessReachableCallTree(reorder_structured, context()); + context()->ProcessReachableCallTree(reorder_structured); } else { - ProcessReachableCallTree(reorder_dominators, context()); + context()->ProcessReachableCallTree(reorder_dominators); } } @@ -429,31 +485,109 @@ Pass::Status DeadBranchElimPass::Process() { ProcessFunction pfn = [this](Function* fp) { return EliminateDeadBranches(fp); }; - bool modified = ProcessReachableCallTree(pfn, context()); + bool modified = context()->ProcessReachableCallTree(pfn); if (modified) FixBlockOrder(); return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange; } Instruction* DeadBranchElimPass::FindFirstExitFromSelectionMerge( - uint32_t start_block_id, uint32_t merge_block_id) { + uint32_t start_block_id, uint32_t merge_block_id, uint32_t loop_merge_id, + uint32_t loop_continue_id, uint32_t switch_merge_id) { // To find the "first" exit, we follow branches looking for a conditional // branch that is not in a nested construct and is not the header of a new // construct. We follow the control flow from |start_block_id| to find the // first one. - while (start_block_id != merge_block_id) { + + while (start_block_id != merge_block_id && start_block_id != loop_merge_id && + start_block_id != loop_continue_id) { BasicBlock* start_block = context()->get_instr_block(start_block_id); Instruction* branch = start_block->terminator(); uint32_t next_block_id = 0; switch (branch->opcode()) { case SpvOpBranchConditional: + next_block_id = start_block->MergeBlockIdIfAny(); + if (next_block_id == 0) { + // If a possible target is the |loop_merge_id| or |loop_continue_id|, + // which are not the current merge node, then we continue the search + // with the other target. + for (uint32_t i = 1; i < 3; i++) { + if (branch->GetSingleWordInOperand(i) == loop_merge_id && + loop_merge_id != merge_block_id) { + next_block_id = branch->GetSingleWordInOperand(3 - i); + break; + } + if (branch->GetSingleWordInOperand(i) == loop_continue_id && + loop_continue_id != merge_block_id) { + next_block_id = branch->GetSingleWordInOperand(3 - i); + break; + } + if (branch->GetSingleWordInOperand(i) == switch_merge_id && + switch_merge_id != merge_block_id) { + next_block_id = branch->GetSingleWordInOperand(3 - i); + break; + } + } + + if (next_block_id == 0) { + return branch; + } + } + break; case SpvOpSwitch: next_block_id = start_block->MergeBlockIdIfAny(); if (next_block_id == 0) { - return branch; + // A switch with no merge instructions can have at most 5 targets: + // a. |merge_block_id| + // b. |loop_merge_id| + // c. |loop_continue_id| + // d. |switch_merge_id| + // e. 1 block inside the current region. + // + // Note that because this is a switch, |merge_block_id| must equal + // |switch_merge_id|. + // + // This leads to a number of cases of what to do. + // + // 1. Does not jump to a block inside of the current construct. In + // this case, there is not conditional break, so we should return + // |nullptr|. + // + // 2. Jumps to |merge_block_id| and a block inside the current + // construct. In this case, this branch conditionally break to the + // end of the current construct, so return the current branch. + // + // 3. Otherwise, this branch may break, but not to the current merge + // block. So we continue with the block that is inside the loop. + bool found_break = false; + for (uint32_t i = 1; i < branch->NumInOperands(); i += 2) { + uint32_t target = branch->GetSingleWordInOperand(i); + if (target == merge_block_id) { + found_break = true; + } else if (target != loop_merge_id && target != loop_continue_id) { + next_block_id = branch->GetSingleWordInOperand(i); + } + } + + if (next_block_id == 0) { + // Case 1. + return nullptr; + } + + if (found_break) { + // Case 2. + return branch; + } + + // The fall through is case 3. } break; case SpvOpBranch: - next_block_id = branch->GetSingleWordInOperand(0); + // Need to check if this is the header of a loop nested in the + // selection construct. + next_block_id = start_block->MergeBlockIdIfAny(); + if (next_block_id == 0) { + next_block_id = branch->GetSingleWordInOperand(0); + } break; default: return nullptr; @@ -463,5 +597,61 @@ Instruction* DeadBranchElimPass::FindFirstExitFromSelectionMerge( return nullptr; } +void DeadBranchElimPass::AddBlocksWithBackEdge( + uint32_t cont_id, uint32_t header_id, uint32_t merge_id, + std::unordered_set* blocks_with_back_edges) { + std::unordered_set visited; + visited.insert(cont_id); + visited.insert(header_id); + visited.insert(merge_id); + + std::vector work_list; + work_list.push_back(cont_id); + + while (!work_list.empty()) { + uint32_t bb_id = work_list.back(); + work_list.pop_back(); + + BasicBlock* bb = context()->get_instr_block(bb_id); + + bool has_back_edge = false; + bb->ForEachSuccessorLabel([header_id, &visited, &work_list, + &has_back_edge](uint32_t* succ_label_id) { + if (visited.insert(*succ_label_id).second) { + work_list.push_back(*succ_label_id); + } + if (*succ_label_id == header_id) { + has_back_edge = true; + } + }); + + if (has_back_edge) { + blocks_with_back_edges->insert(bb); + } + } +} + +bool DeadBranchElimPass::SwitchHasNestedBreak(uint32_t switch_header_id) { + std::vector block_in_construct; + BasicBlock* start_block = context()->get_instr_block(switch_header_id); + uint32_t merge_block_id = start_block->MergeBlockIdIfAny(); + + StructuredCFGAnalysis* cfg_analysis = context()->GetStructuredCFGAnalysis(); + return !get_def_use_mgr()->WhileEachUser( + merge_block_id, + [this, cfg_analysis, switch_header_id](Instruction* inst) { + if (!inst->IsBranch()) { + return true; + } + + BasicBlock* bb = context()->get_instr_block(inst); + if (bb->id() == switch_header_id) { + return true; + } + return (cfg_analysis->ContainingConstruct(inst) == switch_header_id && + bb->GetMergeInst() == nullptr); + }); +} + } // namespace opt } // namespace spvtools diff --git a/third_party/spirv-tools/source/opt/dead_branch_elim_pass.h b/third_party/spirv-tools/source/opt/dead_branch_elim_pass.h index f8b4412077..7841bc4705 100644 --- a/third_party/spirv-tools/source/opt/dead_branch_elim_pass.h +++ b/third_party/spirv-tools/source/opt/dead_branch_elim_pass.h @@ -44,7 +44,9 @@ class DeadBranchElimPass : public MemPass { Status Process() override; IRContext::Analysis GetPreservedAnalyses() override { - return IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping; + return IRContext::kAnalysisDefUse | + IRContext::kAnalysisInstrToBlockMapping | + IRContext::kAnalysisConstants | IRContext::kAnalysisTypes; } private: @@ -132,15 +134,40 @@ class DeadBranchElimPass : public MemPass { void FixBlockOrder(); // Return the first branch instruction that is a conditional branch to - // |merge_block_id|. Returns |nullptr| if not such branch exists. If there are + // |merge_block_id|. Returns |nullptr| if no such branch exists. If there are // multiple such branches, the first one is the one that would be executed // first when running the code. That is, the one that dominates all of the // others. // // |start_block_id| must be a block whose innermost containing merge construct // has |merge_block_id| as the merge block. + // + // |loop_merge_id| and |loop_continue_id| are the merge and continue block ids + // of the innermost loop containing |start_block_id|. Instruction* FindFirstExitFromSelectionMerge(uint32_t start_block_id, - uint32_t merge_block_id); + uint32_t merge_block_id, + uint32_t loop_merge_id, + uint32_t loop_continue_id, + uint32_t switch_merge_id); + + // Adds to |blocks_with_back_edges| all of the blocks on the path from the + // basic block |cont_id| to |header_id| and |merge_id|. The intention is that + // |cond_id| is a the continue target of a loop, |header_id| is the header of + // the loop, and |merge_id| is the merge block of the loop. + void AddBlocksWithBackEdge( + uint32_t cont_id, uint32_t header_id, uint32_t merge_id, + std::unordered_set* blocks_with_back_edges); + + // Returns true if there is a brach to the merge node of the selection + // construct |switch_header_id| that is inside a nested selection construct or + // in the header of the nested selection construct. + bool SwitchHasNestedBreak(uint32_t switch_header_id); + + // Return true of the terminator of |block| is successfully replaced with a + // branch to |live_lab_id|. The merge instruction is deleted or moved as + // needed to maintain structured control flow. Assumes that the + // StructuredCFGAnalysis is valid for the constructs containing |block|. + bool SimplifyBranch(BasicBlock* block, uint32_t live_lab_id); }; } // namespace opt diff --git a/third_party/spirv-tools/source/opt/dead_insert_elim_pass.cpp b/third_party/spirv-tools/source/opt/dead_insert_elim_pass.cpp index b42588ff73..7d5634383a 100644 --- a/third_party/spirv-tools/source/opt/dead_insert_elim_pass.cpp +++ b/third_party/spirv-tools/source/opt/dead_insert_elim_pass.cpp @@ -255,7 +255,7 @@ Pass::Status DeadInsertElimPass::Process() { ProcessFunction pfn = [this](Function* fp) { return EliminateDeadInserts(fp); }; - bool modified = ProcessEntryPointCallTree(pfn, get_module()); + bool modified = context()->ProcessEntryPointCallTree(pfn); return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange; } diff --git a/third_party/spirv-tools/source/opt/dead_insert_elim_pass.h b/third_party/spirv-tools/source/opt/dead_insert_elim_pass.h index 0b111d02c0..01f12bb048 100644 --- a/third_party/spirv-tools/source/opt/dead_insert_elim_pass.h +++ b/third_party/spirv-tools/source/opt/dead_insert_elim_pass.h @@ -45,7 +45,8 @@ class DeadInsertElimPass : public MemPass { IRContext::kAnalysisInstrToBlockMapping | IRContext::kAnalysisDecorations | IRContext::kAnalysisCombinators | IRContext::kAnalysisCFG | IRContext::kAnalysisDominatorAnalysis | - IRContext::kAnalysisNameMap; + IRContext::kAnalysisNameMap | IRContext::kAnalysisConstants | + IRContext::kAnalysisTypes; } private: diff --git a/third_party/spirv-tools/source/opt/dead_variable_elimination.h b/third_party/spirv-tools/source/opt/dead_variable_elimination.h index 40a7bc0256..5dde71ba79 100644 --- a/third_party/spirv-tools/source/opt/dead_variable_elimination.h +++ b/third_party/spirv-tools/source/opt/dead_variable_elimination.h @@ -30,7 +30,8 @@ class DeadVariableElimination : public MemPass { Status Process() override; IRContext::Analysis GetPreservedAnalyses() override { - return IRContext::kAnalysisDefUse; + return IRContext::kAnalysisDefUse | IRContext::kAnalysisConstants | + IRContext::kAnalysisTypes; } private: diff --git a/third_party/spirv-tools/source/opt/decompose_initialized_variables_pass.cpp b/third_party/spirv-tools/source/opt/decompose_initialized_variables_pass.cpp new file mode 100644 index 0000000000..875bf7e85c --- /dev/null +++ b/third_party/spirv-tools/source/opt/decompose_initialized_variables_pass.cpp @@ -0,0 +1,112 @@ +// Copyright (c) 2019 Google LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/opt/decompose_initialized_variables_pass.h" + +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace opt { + +using inst_iterator = InstructionList::iterator; + +namespace { + +bool HasInitializer(Instruction* inst) { + if (inst->opcode() != SpvOpVariable) return false; + if (inst->NumOperands() < 4) return false; + + return true; +} + +} // namespace + +Pass::Status DecomposeInitializedVariablesPass::Process() { + auto* module = context()->module(); + std::unordered_set changed; + + std::vector> global_stores; + for (auto iter = module->types_values_begin(); + iter != module->types_values_end(); ++iter) { + Instruction* inst = &(*iter); + if (!HasInitializer(inst)) continue; + + auto var_id = inst->result_id(); + auto val_id = inst->GetOperand(3).words[0]; + global_stores.push_back(std::make_tuple(var_id, val_id)); + iter->RemoveOperand(3); + changed.insert(&*iter); + } + + std::unordered_set entry_ids; + for (auto entry = module->entry_points().begin(); + entry != module->entry_points().end(); ++entry) { + entry_ids.insert(entry->GetSingleWordInOperand(1)); + } + + for (auto func = module->begin(); func != module->end(); ++func) { + std::vector function_stores; + auto first_block = func->entry().get(); + inst_iterator insert_point = first_block->begin(); + for (auto iter = first_block->begin(); + iter != first_block->end() && iter->opcode() == SpvOpVariable; + ++iter) { + // For valid SPIRV-V, there is guaranteed to be at least one instruction + // after the OpVariable instructions. + insert_point = (*iter).NextNode(); + Instruction* inst = &(*iter); + if (!HasInitializer(inst)) continue; + + auto var_id = inst->result_id(); + auto val_id = inst->GetOperand(3).words[0]; + Instruction* store_inst = new Instruction( + context(), SpvOpStore, 0, 0, + {{SPV_OPERAND_TYPE_ID, {var_id}}, {SPV_OPERAND_TYPE_ID, {val_id}}}); + function_stores.push_back(store_inst); + iter->RemoveOperand(3); + changed.insert(&*iter); + } + + if (entry_ids.find(func->result_id()) != entry_ids.end()) { + for (auto store_ids : global_stores) { + uint32_t var_id; + uint32_t val_id; + std::tie(var_id, val_id) = store_ids; + auto* store_inst = new Instruction( + context(), SpvOpStore, 0, 0, + {{SPV_OPERAND_TYPE_ID, {var_id}}, {SPV_OPERAND_TYPE_ID, {val_id}}}); + context()->set_instr_block(store_inst, &*first_block); + first_block->AddInstruction(std::unique_ptr(store_inst)); + store_inst->InsertBefore(&*insert_point); + changed.insert(store_inst); + } + } + + for (auto store = function_stores.begin(); store != function_stores.end(); + ++store) { + context()->set_instr_block(*store, first_block); + (*store)->InsertBefore(&*insert_point); + changed.insert(*store); + } + } + + auto* def_use_mgr = get_def_use_mgr(); + for (auto* inst : changed) def_use_mgr->UpdateDefUse(inst); + + return !changed.empty() ? Pass::Status::SuccessWithChange + : Pass::Status::SuccessWithoutChange; +} + +} // namespace opt +} // namespace spvtools diff --git a/third_party/spirv-tools/source/opt/decompose_initialized_variables_pass.h b/third_party/spirv-tools/source/opt/decompose_initialized_variables_pass.h new file mode 100644 index 0000000000..c0bd35e760 --- /dev/null +++ b/third_party/spirv-tools/source/opt/decompose_initialized_variables_pass.h @@ -0,0 +1,57 @@ +// Copyright (c) 2019 Google LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_OPT_DECOMPOSE_INITALIZED_VAIRABLES_PASS_H_ +#define SOURCE_OPT_DECOMPOSE_INITALIZED_VAIRABLES_PASS_H_ + +#include "source/opt/ir_context.h" +#include "source/opt/module.h" +#include "source/opt/pass.h" + +namespace spvtools { +namespace opt { + +// Converts variable declartions with initializers into seperate declaration and +// assignment statements. This is done due to known issues with some Vulkan +// implementations' handling of initialized variables. +// +// Only decomposes variables with storage classes that are valid in Vulkan +// execution environments; Output, Private, and Function. +// Currently only Function is implemented. +class DecomposeInitializedVariablesPass : public Pass { + public: + const char* name() const override { + return "decompose-initialized-variables"; + } + Status Process() override; + + IRContext::Analysis GetPreservedAnalyses() override { + return IRContext::kAnalysisInstrToBlockMapping | + IRContext::kAnalysisDecorations | IRContext::kAnalysisCombinators | + IRContext::kAnalysisCFG | IRContext::kAnalysisDominatorAnalysis | + IRContext::kAnalysisLoopAnalysis | IRContext::kAnalysisNameMap | + IRContext::kAnalysisScalarEvolution | + IRContext::kAnalysisRegisterPressure | + IRContext::kAnalysisValueNumberTable | + IRContext::kAnalysisStructuredCFG | + IRContext::kAnalysisBuiltinVarId | + IRContext::kAnalysisIdToFuncMapping | IRContext::kAnalysisTypes | + IRContext::kAnalysisDefUse | IRContext::kAnalysisConstants; + } +}; + +} // namespace opt +} // namespace spvtools + +#endif // SOURCE_OPT_DECOMPOSE_INITALIZED_VAIRABLES_PASS_H_ diff --git a/third_party/spirv-tools/source/opt/decoration_manager.cpp b/third_party/spirv-tools/source/opt/decoration_manager.cpp index 82aa495c9e..a10c992e16 100644 --- a/third_party/spirv-tools/source/opt/decoration_manager.cpp +++ b/third_party/spirv-tools/source/opt/decoration_manager.cpp @@ -22,6 +22,33 @@ #include "source/opt/ir_context.h" +namespace { +using InstructionVector = std::vector; +using DecorationSet = std::set; + +// Returns true if |a| is a subet of |b|. +bool IsSubset(const DecorationSet& a, const DecorationSet& b) { + auto it1 = a.begin(); + auto it2 = b.begin(); + + while (it1 != a.end()) { + if (it2 == b.end() || *it1 < *it2) { + // |*it1| is in |a|, but not in |b|. + return false; + } + if (*it1 == *it2) { + // Found the element move to the next one. + it1++; + it2++; + } else /* *it1 > *it2 */ { + // Did not find |*it1| yet, check the next element in |b|. + it2++; + } + } + return true; +} +} // namespace + namespace spvtools { namespace opt { namespace analysis { @@ -29,7 +56,9 @@ namespace analysis { void DecorationManager::RemoveDecorationsFrom( uint32_t id, std::function pred) { const auto ids_iter = id_to_decoration_insts_.find(id); - if (ids_iter == id_to_decoration_insts_.end()) return; + if (ids_iter == id_to_decoration_insts_.end()) { + return; + } TargetData& decorations_info = ids_iter->second; auto context = module_->context(); @@ -59,8 +88,14 @@ void DecorationManager::RemoveDecorationsFrom( if (!pred(*decoration)) group_decorations_to_keep.push_back(decoration); } - // If all decorations should be kept, move to the next group - if (group_decorations_to_keep.size() == group_decorations.size()) continue; + // If all decorations should be kept, then we can keep |id| part of the + // group. However, if the group itself has no decorations, we should remove + // the id from the group. This is needed to make |KillNameAndDecorate| work + // correctly when a decoration group has no decorations. + if (group_decorations_to_keep.size() == group_decorations.size() && + group_decorations.size() != 0) { + continue; + } // Otherwise, remove |id| from the targets of |group_id| const uint32_t stride = inst->opcode() == SpvOpGroupDecorate ? 1u : 2u; @@ -136,9 +171,6 @@ void DecorationManager::RemoveDecorationsFrom( decorations_info.indirect_decorations.empty() && decorations_info.decorate_insts.empty()) { id_to_decoration_insts_.erase(ids_iter); - - // Remove the OpDecorationGroup defining this group. - if (is_group) context->KillInst(context->get_def_use_mgr()->GetDef(id)); } } @@ -155,18 +187,15 @@ std::vector DecorationManager::GetDecorationsFor( bool DecorationManager::HaveTheSameDecorations(uint32_t id1, uint32_t id2) const { - using InstructionList = std::vector; - using DecorationSet = std::set; - - const InstructionList decorations_for1 = GetDecorationsFor(id1, false); - const InstructionList decorations_for2 = GetDecorationsFor(id2, false); + const InstructionVector decorations_for1 = GetDecorationsFor(id1, false); + const InstructionVector decorations_for2 = GetDecorationsFor(id2, false); // This function splits the decoration instructions into different sets, // based on their opcode; only OpDecorate, OpDecorateId, // OpDecorateStringGOOGLE, and OpMemberDecorate are considered, the other // opcodes are ignored. const auto fillDecorationSets = - [](const InstructionList& decoration_list, DecorationSet* decorate_set, + [](const InstructionVector& decoration_list, DecorationSet* decorate_set, DecorationSet* decorate_id_set, DecorationSet* decorate_string_set, DecorationSet* member_decorate_set) { for (const Instruction* inst : decoration_list) { @@ -222,6 +251,73 @@ bool DecorationManager::HaveTheSameDecorations(uint32_t id1, return result; } +bool DecorationManager::HaveSubsetOfDecorations(uint32_t id1, + uint32_t id2) const { + const InstructionVector decorations_for1 = GetDecorationsFor(id1, false); + const InstructionVector decorations_for2 = GetDecorationsFor(id2, false); + + // This function splits the decoration instructions into different sets, + // based on their opcode; only OpDecorate, OpDecorateId, + // OpDecorateStringGOOGLE, and OpMemberDecorate are considered, the other + // opcodes are ignored. + const auto fillDecorationSets = + [](const InstructionVector& decoration_list, DecorationSet* decorate_set, + DecorationSet* decorate_id_set, DecorationSet* decorate_string_set, + DecorationSet* member_decorate_set) { + for (const Instruction* inst : decoration_list) { + std::u32string decoration_payload; + // Ignore the opcode and the target as we do not want them to be + // compared. + for (uint32_t i = 1u; i < inst->NumInOperands(); ++i) { + for (uint32_t word : inst->GetInOperand(i).words) { + decoration_payload.push_back(word); + } + } + + switch (inst->opcode()) { + case SpvOpDecorate: + decorate_set->emplace(std::move(decoration_payload)); + break; + case SpvOpMemberDecorate: + member_decorate_set->emplace(std::move(decoration_payload)); + break; + case SpvOpDecorateId: + decorate_id_set->emplace(std::move(decoration_payload)); + break; + case SpvOpDecorateStringGOOGLE: + decorate_string_set->emplace(std::move(decoration_payload)); + break; + default: + break; + } + } + }; + + DecorationSet decorate_set_for1; + DecorationSet decorate_id_set_for1; + DecorationSet decorate_string_set_for1; + DecorationSet member_decorate_set_for1; + fillDecorationSets(decorations_for1, &decorate_set_for1, + &decorate_id_set_for1, &decorate_string_set_for1, + &member_decorate_set_for1); + + DecorationSet decorate_set_for2; + DecorationSet decorate_id_set_for2; + DecorationSet decorate_string_set_for2; + DecorationSet member_decorate_set_for2; + fillDecorationSets(decorations_for2, &decorate_set_for2, + &decorate_id_set_for2, &decorate_string_set_for2, + &member_decorate_set_for2); + + const bool result = + IsSubset(decorate_set_for1, decorate_set_for2) && + IsSubset(decorate_id_set_for1, decorate_id_set_for2) && + IsSubset(member_decorate_set_for1, member_decorate_set_for2) && + // Compare string sets last in case the strings are long. + IsSubset(decorate_string_set_for1, decorate_string_set_for2); + return result; +} + // TODO(pierremoreau): If OpDecorateId is referencing an OpConstant, one could // check that the constants are the same rather than just // looking at the constant ID. @@ -256,6 +352,7 @@ void DecorationManager::AnalyzeDecorations() { AddDecoration(&inst); } } + void DecorationManager::AddDecoration(Instruction* inst) { switch (inst->opcode()) { case SpvOpDecorate: @@ -284,6 +381,43 @@ void DecorationManager::AddDecoration(Instruction* inst) { } } +void DecorationManager::AddDecoration(SpvOp opcode, + std::vector opnds) { + IRContext* ctx = module_->context(); + std::unique_ptr newDecoOp( + new Instruction(ctx, opcode, 0, 0, opnds)); + ctx->AddAnnotationInst(std::move(newDecoOp)); +} + +void DecorationManager::AddDecoration(uint32_t inst_id, uint32_t decoration) { + AddDecoration( + SpvOpDecorate, + {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {inst_id}}, + {spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, {decoration}}}); +} + +void DecorationManager::AddDecorationVal(uint32_t inst_id, uint32_t decoration, + uint32_t decoration_value) { + AddDecoration( + SpvOpDecorate, + {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {inst_id}}, + {spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, {decoration}}, + {spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, + {decoration_value}}}); +} + +void DecorationManager::AddMemberDecoration(uint32_t inst_id, uint32_t member, + uint32_t decoration, + uint32_t decoration_value) { + AddDecoration( + SpvOpMemberDecorate, + {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {inst_id}}, + {spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, {member}}, + {spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, {decoration}}, + {spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, + {decoration_value}}}); +} + template std::vector DecorationManager::InternalGetDecorationsFor( uint32_t id, bool include_linkage) { @@ -474,6 +608,11 @@ void DecorationManager::RemoveDecoration(Instruction* inst) { break; } } + +bool operator==(const DecorationManager& lhs, const DecorationManager& rhs) { + return lhs.id_to_decoration_insts_ == rhs.id_to_decoration_insts_; +} + } // namespace analysis } // namespace opt } // namespace spvtools diff --git a/third_party/spirv-tools/source/opt/decoration_manager.h b/third_party/spirv-tools/source/opt/decoration_manager.h index a517ba2d8c..01244f293d 100644 --- a/third_party/spirv-tools/source/opt/decoration_manager.h +++ b/third_party/spirv-tools/source/opt/decoration_manager.h @@ -36,11 +36,22 @@ class DecorationManager { } DecorationManager() = delete; - // Removes all decorations from |id| (either directly or indirectly) for - // which |pred| returns true. - // If |id| is a group ID, OpGroupDecorate and OpGroupMemberDecorate will be - // removed if they have no targets left, and OpDecorationGroup will be - // removed if the group is not applied to anyone and contains no decorations. + // Changes all of the decorations (direct and through groups) where |pred| is + // true and that apply to |id| so that they no longer apply to |id|. + // + // If |id| is part of a group, it will be removed from the group if it + // does not use all of the group's decorations, or, if there are no + // decorations that apply to the group. + // + // If decoration groups become empty, the |OpGroupDecorate| and + // |OpGroupMemberDecorate| instructions will be killed. + // + // Decoration instructions that apply directly to |id| will be killed. + // + // If |id| is a decoration group and all of the group's decorations are + // removed, then the |OpGroupDecorate| and + // |OpGroupMemberDecorate| for the group will be killed, but not the defining + // |OpDecorationGroup| instruction. void RemoveDecorationsFrom(uint32_t id, std::function pred = [](const Instruction&) { return true; }); @@ -63,6 +74,12 @@ class DecorationManager { // instructions that apply the same decorations but to different IDs, still // count as being the same. bool HaveTheSameDecorations(uint32_t id1, uint32_t id2) const; + + // Returns whether two IDs have the same decorations. Two SpvOpGroupDecorate + // instructions that apply the same decorations but to different IDs, still + // count as being the same. + bool HaveSubsetOfDecorations(uint32_t id1, uint32_t id2) const; + // Returns whether the two decorations instructions are the same and are // applying the same decorations; unless |ignore_target| is false, the targets // to which they are applied to does not matter, except for the member part. @@ -100,6 +117,26 @@ class DecorationManager { // Informs the decoration manager of a new decoration that it needs to track. void AddDecoration(Instruction* inst); + // Add decoration with |opcode| and operands |opnds|. + void AddDecoration(SpvOp opcode, const std::vector opnds); + + // Add |decoration| of |inst_id| to module. + void AddDecoration(uint32_t inst_id, uint32_t decoration); + + // Add |decoration, decoration_value| of |inst_id| to module. + void AddDecorationVal(uint32_t inst_id, uint32_t decoration, + uint32_t decoration_value); + + // Add |decoration, decoration_value| of |inst_id, member| to module. + void AddMemberDecoration(uint32_t member, uint32_t inst_id, + uint32_t decoration, uint32_t decoration_value); + + friend bool operator==(const DecorationManager&, const DecorationManager&); + friend bool operator!=(const DecorationManager& lhs, + const DecorationManager& rhs) { + return !(lhs == rhs); + } + private: // Analyzes the defs and uses in the given |module| and populates data // structures in this class. Does nothing if |module| is nullptr. @@ -125,6 +162,25 @@ class DecorationManager { // group. }; + friend bool operator==(const TargetData& lhs, const TargetData& rhs) { + if (!std::is_permutation(lhs.direct_decorations.begin(), + lhs.direct_decorations.end(), + rhs.direct_decorations.begin())) { + return false; + } + if (!std::is_permutation(lhs.indirect_decorations.begin(), + lhs.indirect_decorations.end(), + rhs.indirect_decorations.begin())) { + return false; + } + if (!std::is_permutation(lhs.decorate_insts.begin(), + lhs.decorate_insts.end(), + rhs.decorate_insts.begin())) { + return false; + } + return true; + } + // Mapping from ids to the instructions applying a decoration to those ids. // In other words, for each id you get all decoration instructions // referencing that id, be it directly (SpvOpDecorate, SpvOpMemberDecorate diff --git a/third_party/spirv-tools/source/opt/def_use_manager.cpp b/third_party/spirv-tools/source/opt/def_use_manager.cpp index 4e36493825..0ec98cae10 100644 --- a/third_party/spirv-tools/source/opt/def_use_manager.cpp +++ b/third_party/spirv-tools/source/opt/def_use_manager.cpp @@ -278,7 +278,17 @@ bool operator==(const DefUseManager& lhs, const DefUseManager& rhs) { return false; } - if (lhs.inst_to_used_ids_ != lhs.inst_to_used_ids_) { + if (lhs.inst_to_used_ids_ != rhs.inst_to_used_ids_) { + for (auto p : lhs.inst_to_used_ids_) { + if (rhs.inst_to_used_ids_.count(p.first) == 0) { + return false; + } + } + for (auto p : rhs.inst_to_used_ids_) { + if (lhs.inst_to_used_ids_.count(p.first) == 0) { + return false; + } + } return false; } return true; diff --git a/third_party/spirv-tools/source/opt/desc_sroa.cpp b/third_party/spirv-tools/source/opt/desc_sroa.cpp new file mode 100644 index 0000000000..1f25b33b82 --- /dev/null +++ b/third_party/spirv-tools/source/opt/desc_sroa.cpp @@ -0,0 +1,273 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/opt/desc_sroa.h" + +#include "source/util/string_utils.h" + +namespace spvtools { +namespace opt { + +Pass::Status DescriptorScalarReplacement::Process() { + bool modified = false; + + std::vector vars_to_kill; + + for (Instruction& var : context()->types_values()) { + if (IsCandidate(&var)) { + modified = true; + if (!ReplaceCandidate(&var)) { + return Status::Failure; + } + vars_to_kill.push_back(&var); + } + } + + for (Instruction* var : vars_to_kill) { + context()->KillInst(var); + } + + return (modified ? Status::SuccessWithChange : Status::SuccessWithoutChange); +} + +bool DescriptorScalarReplacement::IsCandidate(Instruction* var) { + if (var->opcode() != SpvOpVariable) { + return false; + } + + uint32_t ptr_type_id = var->type_id(); + Instruction* ptr_type_inst = + context()->get_def_use_mgr()->GetDef(ptr_type_id); + if (ptr_type_inst->opcode() != SpvOpTypePointer) { + return false; + } + + uint32_t var_type_id = ptr_type_inst->GetSingleWordInOperand(1); + Instruction* var_type_inst = + context()->get_def_use_mgr()->GetDef(var_type_id); + if (var_type_inst->opcode() != SpvOpTypeArray) { + return false; + } + + bool has_desc_set_decoration = false; + context()->get_decoration_mgr()->ForEachDecoration( + var->result_id(), SpvDecorationDescriptorSet, + [&has_desc_set_decoration](const Instruction&) { + has_desc_set_decoration = true; + }); + if (!has_desc_set_decoration) { + return false; + } + + bool has_binding_decoration = false; + context()->get_decoration_mgr()->ForEachDecoration( + var->result_id(), SpvDecorationBinding, + [&has_binding_decoration](const Instruction&) { + has_binding_decoration = true; + }); + if (!has_binding_decoration) { + return false; + } + + return true; +} + +bool DescriptorScalarReplacement::ReplaceCandidate(Instruction* var) { + std::vector work_list; + bool failed = !get_def_use_mgr()->WhileEachUser( + var->result_id(), [this, &work_list](Instruction* use) { + if (use->opcode() == SpvOpName) { + return true; + } + + if (use->IsDecoration()) { + return true; + } + + switch (use->opcode()) { + case SpvOpAccessChain: + case SpvOpInBoundsAccessChain: + work_list.push_back(use); + return true; + default: + context()->EmitErrorMessage( + "Variable cannot be replaced: invalid instruction", use); + return false; + } + return true; + }); + + if (failed) { + return false; + } + + for (Instruction* use : work_list) { + if (!ReplaceAccessChain(var, use)) { + return false; + } + } + return true; +} + +bool DescriptorScalarReplacement::ReplaceAccessChain(Instruction* var, + Instruction* use) { + if (use->NumInOperands() <= 1) { + context()->EmitErrorMessage( + "Variable cannot be replaced: invalid instruction", use); + return false; + } + + uint32_t idx_id = use->GetSingleWordInOperand(1); + const analysis::Constant* idx_const = + context()->get_constant_mgr()->FindDeclaredConstant(idx_id); + if (idx_const == nullptr) { + context()->EmitErrorMessage("Variable cannot be replaced: invalid index", + use); + return false; + } + + uint32_t idx = idx_const->GetU32(); + uint32_t replacement_var = GetReplacementVariable(var, idx); + + if (use->NumInOperands() == 2) { + // We are not indexing into the replacement variable. We can replaces the + // access chain with the replacement varibale itself. + context()->ReplaceAllUsesWith(use->result_id(), replacement_var); + context()->KillInst(use); + return true; + } + + // We need to build a new access chain with the replacement variable as the + // base address. + Instruction::OperandList new_operands; + + // Same result id and result type. + new_operands.emplace_back(use->GetOperand(0)); + new_operands.emplace_back(use->GetOperand(1)); + + // Use the replacement variable as the base address. + new_operands.push_back({SPV_OPERAND_TYPE_ID, {replacement_var}}); + + // Drop the first index because it is consumed by the replacment, and copy the + // rest. + for (uint32_t i = 4; i < use->NumOperands(); i++) { + new_operands.emplace_back(use->GetOperand(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); + if (replacement_vars == replacement_variables_.end()) { + uint32_t ptr_type_id = var->type_id(); + Instruction* ptr_type_inst = get_def_use_mgr()->GetDef(ptr_type_id); + assert(ptr_type_inst->opcode() == SpvOpTypePointer && + "Variable should be a pointer to an array."); + uint32_t arr_type_id = ptr_type_inst->GetSingleWordInOperand(1); + Instruction* arr_type_inst = get_def_use_mgr()->GetDef(arr_type_id); + assert(arr_type_inst->opcode() == SpvOpTypeArray && + "Variable should be a pointer to an array."); + + uint32_t array_len_id = arr_type_inst->GetSingleWordInOperand(1); + const analysis::Constant* array_len_const = + context()->get_constant_mgr()->FindDeclaredConstant(array_len_id); + assert(array_len_const != nullptr && "Array length must be a constant."); + uint32_t array_len = array_len_const->GetU32(); + + replacement_vars = replacement_variables_ + .insert({var, std::vector(array_len, 0)}) + .first; + } + + if (replacement_vars->second[idx] == 0) { + replacement_vars->second[idx] = CreateReplacementVariable(var, idx); + } + + return replacement_vars->second[idx]; +} + +uint32_t DescriptorScalarReplacement::CreateReplacementVariable( + Instruction* var, uint32_t idx) { + // The storage class for the new variable is the same as the original. + SpvStorageClass storage_class = + static_cast(var->GetSingleWordInOperand(0)); + + // The type for the new variable will be a pointer to type of the elements of + // the array. + uint32_t ptr_type_id = var->type_id(); + Instruction* ptr_type_inst = get_def_use_mgr()->GetDef(ptr_type_id); + assert(ptr_type_inst->opcode() == SpvOpTypePointer && + "Variable should be a pointer to an array."); + uint32_t arr_type_id = ptr_type_inst->GetSingleWordInOperand(1); + Instruction* arr_type_inst = get_def_use_mgr()->GetDef(arr_type_id); + assert(arr_type_inst->opcode() == SpvOpTypeArray && + "Variable should be a pointer to an array."); + uint32_t element_type_id = arr_type_inst->GetSingleWordInOperand(0); + + uint32_t ptr_element_type_id = context()->get_type_mgr()->FindPointerToType( + element_type_id, storage_class); + + // Create the variable. + uint32_t id = TakeNextId(); + std::unique_ptr variable( + new Instruction(context(), SpvOpVariable, ptr_element_type_id, id, + std::initializer_list{ + {SPV_OPERAND_TYPE_STORAGE_CLASS, + {static_cast(storage_class)}}})); + context()->AddGlobalValue(std::move(variable)); + + // Copy all of the decorations to the new variable. The only difference is + // the Binding decoration needs to be adjusted. + for (auto old_decoration : + get_decoration_mgr()->GetDecorationsFor(var->result_id(), true)) { + assert(old_decoration->opcode() == SpvOpDecorate); + std::unique_ptr new_decoration( + old_decoration->Clone(context())); + new_decoration->SetInOperand(0, {id}); + + uint32_t decoration = new_decoration->GetSingleWordInOperand(1u); + if (decoration == SpvDecorationBinding) { + uint32_t new_binding = new_decoration->GetSingleWordInOperand(2) + idx; + new_decoration->SetInOperand(2, {new_binding}); + } + context()->AddAnnotationInst(std::move(new_decoration)); + } + + // Create a new OpName for the replacement variable. + for (auto p : context()->GetNames(var->result_id())) { + Instruction* name_inst = p.second; + std::string name_str = utils::MakeString(name_inst->GetOperand(1).words); + name_str += "["; + name_str += utils::ToString(idx); + name_str += "]"; + + std::unique_ptr new_name(new Instruction( + context(), SpvOpName, 0, 0, + std::initializer_list{ + {SPV_OPERAND_TYPE_ID, {id}}, + {SPV_OPERAND_TYPE_LITERAL_STRING, utils::MakeVector(name_str)}})); + Instruction* new_name_inst = new_name.get(); + context()->AddDebug2Inst(std::move(new_name)); + get_def_use_mgr()->AnalyzeInstDefUse(new_name_inst); + } + + return id; +} + +} // namespace opt +} // namespace spvtools diff --git a/third_party/spirv-tools/source/opt/desc_sroa.h b/third_party/spirv-tools/source/opt/desc_sroa.h new file mode 100644 index 0000000000..a95c6b582c --- /dev/null +++ b/third_party/spirv-tools/source/opt/desc_sroa.h @@ -0,0 +1,84 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_OPT_DESC_SROA_H_ +#define SOURCE_OPT_DESC_SROA_H_ + +#include +#include +#include +#include +#include +#include + +#include "source/opt/function.h" +#include "source/opt/pass.h" +#include "source/opt/type_manager.h" + +namespace spvtools { +namespace opt { + +// Documented in optimizer.hpp +class DescriptorScalarReplacement : public Pass { + public: + DescriptorScalarReplacement() {} + + const char* name() const override { return "descriptor-scalar-replacement"; } + + Status Process() override; + + IRContext::Analysis GetPreservedAnalyses() override { + return IRContext::kAnalysisDefUse | + IRContext::kAnalysisInstrToBlockMapping | + IRContext::kAnalysisCombinators | IRContext::kAnalysisCFG | + IRContext::kAnalysisConstants | IRContext::kAnalysisTypes; + } + + private: + // Returns true if |var| is an OpVariable instruction that represents a + // descriptor array. These are the variables that we want to replace. + bool IsCandidate(Instruction* var); + + // Replaces all references to |var| by new variables, one for each element of + // the array |var|. The binding for the new variables corresponding to + // element i will be the binding of |var| plus i. Returns true if successful. + bool ReplaceCandidate(Instruction* var); + + // Replaces the base address |var| in the OpAccessChain or + // OpInBoundsAccessChain instruction |use| by the variable that the access + // chain accesses. The first index in |use| must be an |OpConstant|. Returns + // |true| if successful. + bool ReplaceAccessChain(Instruction* var, Instruction* use); + + // Returns the id of the variable that will be used to replace the |idx|th + // element of |var|. The variable is created if it has not already been + // created. + uint32_t GetReplacementVariable(Instruction* var, uint32_t idx); + + // Returns the id of a new variable that can be used to replace the |idx|th + // element of |var|. + uint32_t CreateReplacementVariable(Instruction* var, uint32_t idx); + + // A map from an OpVariable instruction to the set of variables that will be + // used to replace it. The entry |replacement_variables_[var][i]| is the id of + // a variable that will be used in the place of the the ith element of the + // array |var|. If the entry is |0|, then the variable has not been + // created yet. + std::map> replacement_variables_; +}; + +} // namespace opt +} // namespace spvtools + +#endif // SOURCE_OPT_DESC_SROA_H_ diff --git a/third_party/spirv-tools/source/opt/eliminate_dead_functions_pass.cpp b/third_party/spirv-tools/source/opt/eliminate_dead_functions_pass.cpp index 5be983a58f..a465521937 100644 --- a/third_party/spirv-tools/source/opt/eliminate_dead_functions_pass.cpp +++ b/third_party/spirv-tools/source/opt/eliminate_dead_functions_pass.cpp @@ -13,6 +13,7 @@ // limitations under the License. #include "source/opt/eliminate_dead_functions_pass.h" +#include "source/opt/eliminate_dead_functions_util.h" #include @@ -29,15 +30,15 @@ Pass::Status EliminateDeadFunctionsPass::Process() { live_function_set.insert(fp); return false; }; - ProcessReachableCallTree(mark_live, context()); + context()->ProcessReachableCallTree(mark_live); bool modified = false; for (auto funcIter = get_module()->begin(); funcIter != get_module()->end();) { if (live_function_set.count(&*funcIter) == 0) { modified = true; - EliminateFunction(&*funcIter); - funcIter = funcIter.Erase(); + funcIter = + eliminatedeadfunctionsutil::EliminateFunction(context(), &funcIter); } else { ++funcIter; } @@ -47,10 +48,5 @@ Pass::Status EliminateDeadFunctionsPass::Process() { : Pass::Status::SuccessWithoutChange; } -void EliminateDeadFunctionsPass::EliminateFunction(Function* func) { - // Remove all of the instruction in the function body - func->ForEachInst([this](Instruction* inst) { context()->KillInst(inst); }, - true); -} } // namespace opt } // namespace spvtools diff --git a/third_party/spirv-tools/source/opt/eliminate_dead_functions_pass.h b/third_party/spirv-tools/source/opt/eliminate_dead_functions_pass.h index 165e9a6b5d..6ed5c42b0e 100644 --- a/third_party/spirv-tools/source/opt/eliminate_dead_functions_pass.h +++ b/third_party/spirv-tools/source/opt/eliminate_dead_functions_pass.h @@ -30,7 +30,8 @@ class EliminateDeadFunctionsPass : public MemPass { Status Process() override; IRContext::Analysis GetPreservedAnalyses() override { - return IRContext::kAnalysisDefUse; + return IRContext::kAnalysisDefUse | IRContext::kAnalysisConstants | + IRContext::kAnalysisTypes; } private: diff --git a/third_party/spirv-tools/source/opt/eliminate_dead_functions_util.cpp b/third_party/spirv-tools/source/opt/eliminate_dead_functions_util.cpp new file mode 100644 index 0000000000..8a38959313 --- /dev/null +++ b/third_party/spirv-tools/source/opt/eliminate_dead_functions_util.cpp @@ -0,0 +1,32 @@ +// Copyright (c) 2019 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 "eliminate_dead_functions_util.h" + +namespace spvtools { +namespace opt { + +namespace eliminatedeadfunctionsutil { + +Module::iterator EliminateFunction(IRContext* context, + Module::iterator* func_iter) { + (*func_iter) + ->ForEachInst([context](Instruction* inst) { context->KillInst(inst); }, + true); + return func_iter->Erase(); +} + +} // namespace eliminatedeadfunctionsutil +} // namespace opt +} // namespace spvtools diff --git a/third_party/spirv-tools/source/opt/eliminate_dead_functions_util.h b/third_party/spirv-tools/source/opt/eliminate_dead_functions_util.h new file mode 100644 index 0000000000..9fcce956fc --- /dev/null +++ b/third_party/spirv-tools/source/opt/eliminate_dead_functions_util.h @@ -0,0 +1,36 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_OPT_ELIMINATE_DEAD_FUNCTIONS_UTIL_H_ +#define SOURCE_OPT_ELIMINATE_DEAD_FUNCTIONS_UTIL_H_ + +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace opt { + +// Provides functionality for eliminating functions that are not needed, for use +// by various analyses and passes. +namespace eliminatedeadfunctionsutil { + +// Removes all of the function's instructions, removes the function from the +// module, and returns the next iterator. +Module::iterator EliminateFunction(IRContext* context, + Module::iterator* func_iter); + +} // namespace eliminatedeadfunctionsutil +} // namespace opt +} // namespace spvtools + +#endif // SOURCE_OPT_ELIMINATE_DEAD_FUNCTIONS_UTIL_H_ diff --git a/third_party/spirv-tools/source/opt/eliminate_dead_members_pass.cpp b/third_party/spirv-tools/source/opt/eliminate_dead_members_pass.cpp new file mode 100644 index 0000000000..0b73b2dbcb --- /dev/null +++ b/third_party/spirv-tools/source/opt/eliminate_dead_members_pass.cpp @@ -0,0 +1,637 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/opt/eliminate_dead_members_pass.h" + +#include "ir_builder.h" +#include "source/opt/ir_context.h" + +namespace { +const uint32_t kRemovedMember = 0xFFFFFFFF; +} + +namespace spvtools { +namespace opt { + +Pass::Status EliminateDeadMembersPass::Process() { + if (!context()->get_feature_mgr()->HasCapability(SpvCapabilityShader)) + return Status::SuccessWithoutChange; + + FindLiveMembers(); + if (RemoveDeadMembers()) { + return Status::SuccessWithChange; + } + return Status::SuccessWithoutChange; +} + +void EliminateDeadMembersPass::FindLiveMembers() { + // Until we have implemented the rewritting of OpSpecConsantOp instructions, + // we have to mark them as fully used just to be safe. + for (auto& inst : get_module()->types_values()) { + if (inst.opcode() == SpvOpSpecConstantOp) { + MarkTypeAsFullyUsed(inst.type_id()); + } else if (inst.opcode() == SpvOpVariable) { + switch (inst.GetSingleWordInOperand(0)) { + case SpvStorageClassInput: + case SpvStorageClassOutput: + MarkPointeeTypeAsFullUsed(inst.type_id()); + break; + default: + break; + } + } + } + + for (const Function& func : *get_module()) { + FindLiveMembers(func); + } +} + +void EliminateDeadMembersPass::FindLiveMembers(const Function& function) { + function.ForEachInst( + [this](const Instruction* inst) { FindLiveMembers(inst); }); +} + +void EliminateDeadMembersPass::FindLiveMembers(const Instruction* inst) { + switch (inst->opcode()) { + case SpvOpStore: + MarkMembersAsLiveForStore(inst); + break; + case SpvOpCopyMemory: + case SpvOpCopyMemorySized: + MarkMembersAsLiveForCopyMemory(inst); + break; + case SpvOpCompositeExtract: + MarkMembersAsLiveForExtract(inst); + break; + case SpvOpAccessChain: + case SpvOpInBoundsAccessChain: + case SpvOpPtrAccessChain: + case SpvOpInBoundsPtrAccessChain: + MarkMembersAsLiveForAccessChain(inst); + break; + case SpvOpReturnValue: + // This should be an issue only if we are returning from the entry point. + // However, for now I will keep it more conservative because functions are + // often inlined leaving only the entry points. + MarkOperandTypeAsFullyUsed(inst, 0); + break; + case SpvOpArrayLength: + MarkMembersAsLiveForArrayLength(inst); + break; + case SpvOpLoad: + case SpvOpCompositeInsert: + case SpvOpCompositeConstruct: + break; + default: + // This path is here for safety. All instructions that can reference + // structs in a function body should be handled above. However, this will + // keep the pass valid, but not optimal, as new instructions get added + // or if something was missed. + MarkStructOperandsAsFullyUsed(inst); + break; + } +} + +void EliminateDeadMembersPass::MarkMembersAsLiveForStore( + const Instruction* inst) { + // We should only have to mark the members as live if the store is to + // memory that is read outside of the shader. Other passes can remove all + // store to memory that is not visible outside of the shader, so we do not + // complicate the code for now. + assert(inst->opcode() == SpvOpStore); + uint32_t object_id = inst->GetSingleWordInOperand(1); + Instruction* object_inst = context()->get_def_use_mgr()->GetDef(object_id); + uint32_t object_type_id = object_inst->type_id(); + MarkTypeAsFullyUsed(object_type_id); +} + +void EliminateDeadMembersPass::MarkTypeAsFullyUsed(uint32_t type_id) { + Instruction* type_inst = get_def_use_mgr()->GetDef(type_id); + assert(type_inst != nullptr); + if (type_inst->opcode() != SpvOpTypeStruct) { + return; + } + + // Mark every member of the current struct as used. + for (uint32_t i = 0; i < type_inst->NumInOperands(); ++i) { + used_members_[type_id].insert(i); + } + + // Mark any sub struct as fully used. + for (uint32_t i = 0; i < type_inst->NumInOperands(); ++i) { + MarkTypeAsFullyUsed(type_inst->GetSingleWordInOperand(i)); + } +} + +void EliminateDeadMembersPass::MarkPointeeTypeAsFullUsed(uint32_t ptr_type_id) { + Instruction* ptr_type_inst = get_def_use_mgr()->GetDef(ptr_type_id); + assert(ptr_type_inst->opcode() == SpvOpTypePointer); + MarkTypeAsFullyUsed(ptr_type_inst->GetSingleWordInOperand(1)); +} + +void EliminateDeadMembersPass::MarkMembersAsLiveForCopyMemory( + const Instruction* inst) { + uint32_t target_id = inst->GetSingleWordInOperand(0); + Instruction* target_inst = get_def_use_mgr()->GetDef(target_id); + uint32_t pointer_type_id = target_inst->type_id(); + Instruction* pointer_type_inst = get_def_use_mgr()->GetDef(pointer_type_id); + uint32_t type_id = pointer_type_inst->GetSingleWordInOperand(1); + MarkTypeAsFullyUsed(type_id); +} + +void EliminateDeadMembersPass::MarkMembersAsLiveForExtract( + const Instruction* inst) { + assert(inst->opcode() == SpvOpCompositeExtract); + + uint32_t composite_id = inst->GetSingleWordInOperand(0); + Instruction* composite_inst = get_def_use_mgr()->GetDef(composite_id); + uint32_t type_id = composite_inst->type_id(); + + for (uint32_t i = 1; i < inst->NumInOperands(); ++i) { + Instruction* type_inst = get_def_use_mgr()->GetDef(type_id); + uint32_t member_idx = inst->GetSingleWordInOperand(i); + switch (type_inst->opcode()) { + case SpvOpTypeStruct: + used_members_[type_id].insert(member_idx); + type_id = type_inst->GetSingleWordInOperand(member_idx); + break; + case SpvOpTypeArray: + case SpvOpTypeRuntimeArray: + case SpvOpTypeVector: + case SpvOpTypeMatrix: + type_id = type_inst->GetSingleWordInOperand(0); + break; + default: + assert(false); + } + } +} + +void EliminateDeadMembersPass::MarkMembersAsLiveForAccessChain( + const Instruction* inst) { + assert(inst->opcode() == SpvOpAccessChain || + inst->opcode() == SpvOpInBoundsAccessChain || + inst->opcode() == SpvOpPtrAccessChain || + inst->opcode() == SpvOpInBoundsPtrAccessChain); + + uint32_t pointer_id = inst->GetSingleWordInOperand(0); + Instruction* pointer_inst = get_def_use_mgr()->GetDef(pointer_id); + uint32_t pointer_type_id = pointer_inst->type_id(); + Instruction* pointer_type_inst = get_def_use_mgr()->GetDef(pointer_type_id); + uint32_t type_id = pointer_type_inst->GetSingleWordInOperand(1); + + analysis::ConstantManager* const_mgr = context()->get_constant_mgr(); + + // For a pointer access chain, we need to skip the |element| index. It is not + // a reference to the member of a struct, and it does not change the type. + uint32_t i = (inst->opcode() == SpvOpAccessChain || + inst->opcode() == SpvOpInBoundsAccessChain + ? 1 + : 2); + for (; i < inst->NumInOperands(); ++i) { + Instruction* type_inst = get_def_use_mgr()->GetDef(type_id); + switch (type_inst->opcode()) { + case SpvOpTypeStruct: { + const analysis::IntConstant* member_idx = + const_mgr->FindDeclaredConstant(inst->GetSingleWordInOperand(i)) + ->AsIntConstant(); + assert(member_idx); + if (member_idx->type()->AsInteger()->width() == 32) { + used_members_[type_id].insert(member_idx->GetU32()); + type_id = type_inst->GetSingleWordInOperand(member_idx->GetU32()); + } else { + used_members_[type_id].insert( + static_cast(member_idx->GetU64())); + type_id = type_inst->GetSingleWordInOperand( + static_cast(member_idx->GetU64())); + } + } break; + case SpvOpTypeArray: + case SpvOpTypeRuntimeArray: + case SpvOpTypeVector: + case SpvOpTypeMatrix: + type_id = type_inst->GetSingleWordInOperand(0); + break; + default: + assert(false); + } + } +} + +void EliminateDeadMembersPass::MarkOperandTypeAsFullyUsed( + const Instruction* inst, uint32_t in_idx) { + uint32_t op_id = inst->GetSingleWordInOperand(in_idx); + Instruction* op_inst = get_def_use_mgr()->GetDef(op_id); + MarkTypeAsFullyUsed(op_inst->type_id()); +} + +void EliminateDeadMembersPass::MarkMembersAsLiveForArrayLength( + const Instruction* inst) { + assert(inst->opcode() == SpvOpArrayLength); + uint32_t object_id = inst->GetSingleWordInOperand(0); + Instruction* object_inst = get_def_use_mgr()->GetDef(object_id); + uint32_t pointer_type_id = object_inst->type_id(); + Instruction* pointer_type_inst = get_def_use_mgr()->GetDef(pointer_type_id); + uint32_t type_id = pointer_type_inst->GetSingleWordInOperand(1); + used_members_[type_id].insert(inst->GetSingleWordInOperand(1)); +} + +bool EliminateDeadMembersPass::RemoveDeadMembers() { + bool modified = false; + + // First update all of the OpTypeStruct instructions. + get_module()->ForEachInst([&modified, this](Instruction* inst) { + switch (inst->opcode()) { + case SpvOpTypeStruct: + modified |= UpdateOpTypeStruct(inst); + break; + default: + break; + } + }); + + // Now update all of the instructions that reference the OpTypeStructs. + get_module()->ForEachInst([&modified, this](Instruction* inst) { + switch (inst->opcode()) { + case SpvOpMemberName: + modified |= UpdateOpMemberNameOrDecorate(inst); + break; + case SpvOpMemberDecorate: + modified |= UpdateOpMemberNameOrDecorate(inst); + break; + case SpvOpGroupMemberDecorate: + modified |= UpdateOpGroupMemberDecorate(inst); + break; + case SpvOpSpecConstantComposite: + case SpvOpConstantComposite: + case SpvOpCompositeConstruct: + modified |= UpdateConstantComposite(inst); + break; + case SpvOpAccessChain: + case SpvOpInBoundsAccessChain: + case SpvOpPtrAccessChain: + case SpvOpInBoundsPtrAccessChain: + modified |= UpdateAccessChain(inst); + break; + case SpvOpCompositeExtract: + modified |= UpdateCompsiteExtract(inst); + break; + case SpvOpCompositeInsert: + modified |= UpdateCompositeInsert(inst); + break; + case SpvOpArrayLength: + modified |= UpdateOpArrayLength(inst); + break; + case SpvOpSpecConstantOp: + assert(false && "Not yet implemented."); + // with OpCompositeExtract, OpCompositeInsert + // For kernels: OpAccessChain, OpInBoundsAccessChain, OpPtrAccessChain, + // OpInBoundsPtrAccessChain + break; + default: + break; + } + }); + return modified; +} + +bool EliminateDeadMembersPass::UpdateOpTypeStruct(Instruction* inst) { + assert(inst->opcode() == SpvOpTypeStruct); + + const auto& live_members = used_members_[inst->result_id()]; + if (live_members.size() == inst->NumInOperands()) { + return false; + } + + Instruction::OperandList new_operands; + for (uint32_t idx : live_members) { + new_operands.emplace_back(inst->GetInOperand(idx)); + } + + inst->SetInOperands(std::move(new_operands)); + context()->UpdateDefUse(inst); + return true; +} + +bool EliminateDeadMembersPass::UpdateOpMemberNameOrDecorate(Instruction* inst) { + assert(inst->opcode() == SpvOpMemberName || + inst->opcode() == SpvOpMemberDecorate); + + uint32_t type_id = inst->GetSingleWordInOperand(0); + auto live_members = used_members_.find(type_id); + if (live_members == used_members_.end()) { + return false; + } + + uint32_t orig_member_idx = inst->GetSingleWordInOperand(1); + uint32_t new_member_idx = GetNewMemberIndex(type_id, orig_member_idx); + + if (new_member_idx == kRemovedMember) { + context()->KillInst(inst); + return true; + } + + if (new_member_idx == orig_member_idx) { + return false; + } + + inst->SetInOperand(1, {new_member_idx}); + return true; +} + +bool EliminateDeadMembersPass::UpdateOpGroupMemberDecorate(Instruction* inst) { + assert(inst->opcode() == SpvOpGroupMemberDecorate); + + bool modified = false; + + Instruction::OperandList new_operands; + new_operands.emplace_back(inst->GetInOperand(0)); + for (uint32_t i = 1; i < inst->NumInOperands(); i += 2) { + uint32_t type_id = inst->GetSingleWordInOperand(i); + uint32_t member_idx = inst->GetSingleWordInOperand(i + 1); + uint32_t new_member_idx = GetNewMemberIndex(type_id, member_idx); + + if (new_member_idx == kRemovedMember) { + modified = true; + continue; + } + + new_operands.emplace_back(inst->GetOperand(i)); + if (new_member_idx != member_idx) { + new_operands.emplace_back( + Operand({SPV_OPERAND_TYPE_LITERAL_INTEGER, {new_member_idx}})); + modified = true; + } else { + new_operands.emplace_back(inst->GetOperand(i + 1)); + } + } + + if (!modified) { + return false; + } + + if (new_operands.size() == 1) { + context()->KillInst(inst); + return true; + } + + inst->SetInOperands(std::move(new_operands)); + context()->UpdateDefUse(inst); + return true; +} + +bool EliminateDeadMembersPass::UpdateConstantComposite(Instruction* inst) { + assert(inst->opcode() == SpvOpConstantComposite || + inst->opcode() == SpvOpCompositeConstruct); + uint32_t type_id = inst->type_id(); + + bool modified = false; + Instruction::OperandList new_operands; + for (uint32_t i = 0; i < inst->NumInOperands(); ++i) { + uint32_t new_idx = GetNewMemberIndex(type_id, i); + if (new_idx == kRemovedMember) { + modified = true; + } else { + new_operands.emplace_back(inst->GetInOperand(i)); + } + } + inst->SetInOperands(std::move(new_operands)); + context()->UpdateDefUse(inst); + return modified; +} + +bool EliminateDeadMembersPass::UpdateAccessChain(Instruction* inst) { + assert(inst->opcode() == SpvOpAccessChain || + inst->opcode() == SpvOpInBoundsAccessChain || + inst->opcode() == SpvOpPtrAccessChain || + inst->opcode() == SpvOpInBoundsPtrAccessChain); + + uint32_t pointer_id = inst->GetSingleWordInOperand(0); + Instruction* pointer_inst = get_def_use_mgr()->GetDef(pointer_id); + uint32_t pointer_type_id = pointer_inst->type_id(); + Instruction* pointer_type_inst = get_def_use_mgr()->GetDef(pointer_type_id); + uint32_t type_id = pointer_type_inst->GetSingleWordInOperand(1); + + analysis::ConstantManager* const_mgr = context()->get_constant_mgr(); + Instruction::OperandList new_operands; + bool modified = false; + new_operands.emplace_back(inst->GetInOperand(0)); + + // For pointer access chains we want to copy the element operand. + if (inst->opcode() == SpvOpPtrAccessChain || + inst->opcode() == SpvOpInBoundsPtrAccessChain) { + new_operands.emplace_back(inst->GetInOperand(1)); + } + + for (uint32_t i = static_cast(new_operands.size()); + i < inst->NumInOperands(); ++i) { + Instruction* type_inst = get_def_use_mgr()->GetDef(type_id); + switch (type_inst->opcode()) { + case SpvOpTypeStruct: { + const analysis::IntConstant* member_idx = + const_mgr->FindDeclaredConstant(inst->GetSingleWordInOperand(i)) + ->AsIntConstant(); + assert(member_idx); + uint32_t orig_member_idx; + if (member_idx->type()->AsInteger()->width() == 32) { + orig_member_idx = member_idx->GetU32(); + } else { + orig_member_idx = static_cast(member_idx->GetU64()); + } + uint32_t new_member_idx = GetNewMemberIndex(type_id, orig_member_idx); + assert(new_member_idx != kRemovedMember); + if (orig_member_idx != new_member_idx) { + InstructionBuilder ir_builder( + context(), inst, + IRContext::kAnalysisDefUse | + IRContext::kAnalysisInstrToBlockMapping); + uint32_t const_id = + ir_builder.GetUintConstant(new_member_idx)->result_id(); + new_operands.emplace_back(Operand({SPV_OPERAND_TYPE_ID, {const_id}})); + modified = true; + } else { + new_operands.emplace_back(inst->GetInOperand(i)); + } + // The type will have already been rewritten, so use the new member + // index. + type_id = type_inst->GetSingleWordInOperand(new_member_idx); + } break; + case SpvOpTypeArray: + case SpvOpTypeRuntimeArray: + case SpvOpTypeVector: + case SpvOpTypeMatrix: + new_operands.emplace_back(inst->GetInOperand(i)); + type_id = type_inst->GetSingleWordInOperand(0); + break; + default: + assert(false); + break; + } + } + + if (!modified) { + return false; + } + inst->SetInOperands(std::move(new_operands)); + context()->UpdateDefUse(inst); + return true; +} + +uint32_t EliminateDeadMembersPass::GetNewMemberIndex(uint32_t type_id, + uint32_t member_idx) { + auto live_members = used_members_.find(type_id); + if (live_members == used_members_.end()) { + return member_idx; + } + + auto current_member = live_members->second.find(member_idx); + if (current_member == live_members->second.end()) { + return kRemovedMember; + } + + return static_cast( + std::distance(live_members->second.begin(), current_member)); +} + +bool EliminateDeadMembersPass::UpdateCompsiteExtract(Instruction* inst) { + uint32_t object_id = inst->GetSingleWordInOperand(0); + Instruction* object_inst = get_def_use_mgr()->GetDef(object_id); + uint32_t type_id = object_inst->type_id(); + + Instruction::OperandList new_operands; + bool modified = false; + new_operands.emplace_back(inst->GetInOperand(0)); + for (uint32_t i = 1; i < inst->NumInOperands(); ++i) { + uint32_t member_idx = inst->GetSingleWordInOperand(i); + uint32_t new_member_idx = GetNewMemberIndex(type_id, member_idx); + assert(new_member_idx != kRemovedMember); + if (member_idx != new_member_idx) { + modified = true; + } + new_operands.emplace_back( + Operand({SPV_OPERAND_TYPE_LITERAL_INTEGER, {new_member_idx}})); + + Instruction* type_inst = get_def_use_mgr()->GetDef(type_id); + switch (type_inst->opcode()) { + case SpvOpTypeStruct: + assert(i != 1 || (inst->opcode() != SpvOpPtrAccessChain && + inst->opcode() != SpvOpInBoundsPtrAccessChain)); + // The type will have already been rewriten, so use the new member + // index. + type_id = type_inst->GetSingleWordInOperand(new_member_idx); + break; + case SpvOpTypeArray: + case SpvOpTypeRuntimeArray: + case SpvOpTypeVector: + case SpvOpTypeMatrix: + type_id = type_inst->GetSingleWordInOperand(0); + break; + default: + assert(false); + } + } + + if (!modified) { + return false; + } + inst->SetInOperands(std::move(new_operands)); + context()->UpdateDefUse(inst); + return true; +} + +bool EliminateDeadMembersPass::UpdateCompositeInsert(Instruction* inst) { + uint32_t composite_id = inst->GetSingleWordInOperand(1); + Instruction* composite_inst = get_def_use_mgr()->GetDef(composite_id); + uint32_t type_id = composite_inst->type_id(); + + Instruction::OperandList new_operands; + bool modified = false; + new_operands.emplace_back(inst->GetInOperand(0)); + new_operands.emplace_back(inst->GetInOperand(1)); + for (uint32_t i = 2; i < inst->NumInOperands(); ++i) { + uint32_t member_idx = inst->GetSingleWordInOperand(i); + uint32_t new_member_idx = GetNewMemberIndex(type_id, member_idx); + if (new_member_idx == kRemovedMember) { + context()->KillInst(inst); + return true; + } + + if (member_idx != new_member_idx) { + modified = true; + } + new_operands.emplace_back( + Operand({SPV_OPERAND_TYPE_LITERAL_INTEGER, {new_member_idx}})); + + Instruction* type_inst = get_def_use_mgr()->GetDef(type_id); + switch (type_inst->opcode()) { + case SpvOpTypeStruct: + // The type will have already been rewritten, so use the new member + // index. + type_id = type_inst->GetSingleWordInOperand(new_member_idx); + break; + case SpvOpTypeArray: + case SpvOpTypeRuntimeArray: + case SpvOpTypeVector: + case SpvOpTypeMatrix: + type_id = type_inst->GetSingleWordInOperand(0); + break; + default: + assert(false); + } + } + + if (!modified) { + return false; + } + inst->SetInOperands(std::move(new_operands)); + context()->UpdateDefUse(inst); + return true; +} + +bool EliminateDeadMembersPass::UpdateOpArrayLength(Instruction* inst) { + uint32_t struct_id = inst->GetSingleWordInOperand(0); + Instruction* struct_inst = get_def_use_mgr()->GetDef(struct_id); + uint32_t pointer_type_id = struct_inst->type_id(); + Instruction* pointer_type_inst = get_def_use_mgr()->GetDef(pointer_type_id); + uint32_t type_id = pointer_type_inst->GetSingleWordInOperand(1); + + uint32_t member_idx = inst->GetSingleWordInOperand(1); + uint32_t new_member_idx = GetNewMemberIndex(type_id, member_idx); + assert(new_member_idx != kRemovedMember); + + if (member_idx == new_member_idx) { + return false; + } + + inst->SetInOperand(1, {new_member_idx}); + context()->UpdateDefUse(inst); + return true; +} + +void EliminateDeadMembersPass::MarkStructOperandsAsFullyUsed( + const Instruction* inst) { + if (inst->type_id() != 0) { + MarkTypeAsFullyUsed(inst->type_id()); + } + + inst->ForEachInId([this](const uint32_t* id) { + Instruction* instruction = get_def_use_mgr()->GetDef(*id); + if (instruction->type_id() != 0) { + MarkTypeAsFullyUsed(instruction->type_id()); + } + }); +} +} // namespace opt +} // namespace spvtools diff --git a/third_party/spirv-tools/source/opt/eliminate_dead_members_pass.h b/third_party/spirv-tools/source/opt/eliminate_dead_members_pass.h new file mode 100644 index 0000000000..4feaa55f4f --- /dev/null +++ b/third_party/spirv-tools/source/opt/eliminate_dead_members_pass.h @@ -0,0 +1,146 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_OPT_ELIMINATE_DEAD_MEMBERS_PASS_H_ +#define SOURCE_OPT_ELIMINATE_DEAD_MEMBERS_PASS_H_ + +#include "source/opt/def_use_manager.h" +#include "source/opt/function.h" +#include "source/opt/mem_pass.h" +#include "source/opt/module.h" + +namespace spvtools { +namespace opt { + +// Remove unused members from structures. The remaining members will remain at +// the same offset. +class EliminateDeadMembersPass : public MemPass { + public: + const char* name() const override { return "eliminate-dead-members"; } + Status Process() override; + + IRContext::Analysis GetPreservedAnalyses() override { + return IRContext::kAnalysisDefUse | + IRContext::kAnalysisInstrToBlockMapping | + IRContext::kAnalysisCombinators | IRContext::kAnalysisCFG | + IRContext::kAnalysisDominatorAnalysis | + IRContext::kAnalysisLoopAnalysis | + IRContext::kAnalysisScalarEvolution | + IRContext::kAnalysisRegisterPressure | + IRContext::kAnalysisValueNumberTable | + IRContext::kAnalysisStructuredCFG | + IRContext::kAnalysisBuiltinVarId | + IRContext::kAnalysisIdToFuncMapping; + } + + private: + // Populate |used_members_| with the member of structures that are live in the + // current context. + void FindLiveMembers(); + + // Add to |used_members_| the member of structures that are live in + // |function|. + void FindLiveMembers(const Function& function); + // Add to |used_members_| the member of structures that are live in |inst|. + void FindLiveMembers(const Instruction* inst); + + // Add to |used_members_| the members that are live in the |OpStore| + // instruction |inst|. + void MarkMembersAsLiveForStore(const Instruction* inst); + + // Add to |used_members_| the members that are live in the |OpCopyMemory*| + // instruction |inst|. + void MarkMembersAsLiveForCopyMemory(const Instruction* inst); + + // Add to |used_members_| the members that are live in the + // |OpCompositeExtract| instruction |inst|. + void MarkMembersAsLiveForExtract(const Instruction* inst); + + // Add to |used_members_| the members that are live in the |Op*AccessChain| + // instruction |inst|. + void MarkMembersAsLiveForAccessChain(const Instruction* inst); + + // Add the member referenced by the OpArrayLength instruction |inst| to + // |uses_members_|. + void MarkMembersAsLiveForArrayLength(const Instruction* inst); + + // Remove dead members from structs and updates any instructions that need to + // be updated as a consequence. Return true if something changed. + bool RemoveDeadMembers(); + + // Update |inst|, which must be an |OpMemberName| or |OpMemberDecorate| + // instruction, so it references the correct member after the struct is + // updated. Return true if something changed. + bool UpdateOpMemberNameOrDecorate(Instruction* inst); + + // Update |inst|, which must be an |OpGroupMemberDecorate| instruction, so it + // references the correct member after the struct is updated. Return true if + // something changed. + bool UpdateOpGroupMemberDecorate(Instruction* inst); + + // Update the |OpTypeStruct| instruction |inst| my removing the members that + // are not live. Return true if something changed. + bool UpdateOpTypeStruct(Instruction* inst); + + // Update the |OpConstantComposite| instruction |inst| to match the change + // made to the type that was being generated. Return true if something + // changed. + bool UpdateConstantComposite(Instruction* inst); + + // Update the |Op*AccessChain| instruction |inst| to reference the correct + // members. All members referenced in the access chain must be live. This + // function must be called after the |OpTypeStruct| instruction for the type + // has been updated. Return true if something changed. + bool UpdateAccessChain(Instruction* inst); + + // Update the |OpCompositeExtract| instruction |inst| to reference the correct + // members. All members referenced in the instruction must be live. This + // function must be called after the |OpTypeStruct| instruction for the type + // has been updated. Return true if something changed. + bool UpdateCompsiteExtract(Instruction* inst); + + // Update the |OpCompositeInsert| instruction |inst| to reference the correct + // members. If the member being inserted is not live, then |inst| is killed. + // This function must be called after the |OpTypeStruct| instruction for the + // type has been updated. Return true if something changed. + bool UpdateCompositeInsert(Instruction* inst); + + // Update the |OpArrayLength| instruction |inst| to reference the correct + // member. The member referenced in the instruction must be live. Return true + // if something changed. + bool UpdateOpArrayLength(Instruction* inst); + + // Add all of the members of type |type_id| and members of any subtypes to + // |used_members_|. + void MarkTypeAsFullyUsed(uint32_t type_id); + + // Add all of the members of the type of the operand |in_idx| in |inst| and + // members of any subtypes to |uses_members_|. + void MarkOperandTypeAsFullyUsed(const Instruction* inst, uint32_t in_idx); + + // Return the index of the member that use to be the |member_idx|th member of + // |type_id|. If the member has been removed, |kRemovedMember| is returned. + uint32_t GetNewMemberIndex(uint32_t type_id, uint32_t member_idx); + + // A map from a type id to a set of indices representing the members of the + // type that are used, and must be kept. + std::unordered_map> used_members_; + void MarkStructOperandsAsFullyUsed(const Instruction* inst); + void MarkPointeeTypeAsFullUsed(uint32_t ptr_type_id); +}; + +} // namespace opt +} // namespace spvtools + +#endif // SOURCE_OPT_ELIMINATE_DEAD_MEMBERS_PASS_H_ diff --git a/third_party/spirv-tools/source/opt/feature_manager.cpp b/third_party/spirv-tools/source/opt/feature_manager.cpp index b7fc16a50d..63d50b6d74 100644 --- a/third_party/spirv-tools/source/opt/feature_manager.cpp +++ b/third_party/spirv-tools/source/opt/feature_manager.cpp @@ -31,12 +31,19 @@ void FeatureManager::Analyze(Module* module) { void FeatureManager::AddExtensions(Module* module) { for (auto ext : module->extensions()) { - const std::string name = - reinterpret_cast(ext.GetInOperand(0u).words.data()); - Extension extension; - if (GetExtensionFromString(name.c_str(), &extension)) { - extensions_.Add(extension); - } + AddExtension(&ext); + } +} + +void FeatureManager::AddExtension(Instruction* ext) { + assert(ext->opcode() == SpvOpExtension && + "Expecting an extension instruction."); + + const std::string name = + reinterpret_cast(ext->GetInOperand(0u).words.data()); + Extension extension; + if (GetExtensionFromString(name.c_str(), &extension)) { + extensions_.Add(extension); } } @@ -63,5 +70,27 @@ void FeatureManager::AddExtInstImportIds(Module* module) { extinst_importid_GLSLstd450_ = module->GetExtInstImportId("GLSL.std.450"); } +bool operator==(const FeatureManager& a, const FeatureManager& b) { + // We check that the addresses of the grammars are the same because they + // are large objects, and this is faster. It can be changed if needed as a + // later time. + if (&a.grammar_ != &b.grammar_) { + return false; + } + + if (a.capabilities_ != b.capabilities_) { + return false; + } + + if (a.extensions_ != b.extensions_) { + return false; + } + + if (a.extinst_importid_GLSLstd450_ != b.extinst_importid_GLSLstd450_) { + return false; + } + + return true; +} } // namespace opt } // namespace spvtools diff --git a/third_party/spirv-tools/source/opt/feature_manager.h b/third_party/spirv-tools/source/opt/feature_manager.h index 80b2cccf63..2fe3291088 100644 --- a/third_party/spirv-tools/source/opt/feature_manager.h +++ b/third_party/spirv-tools/source/opt/feature_manager.h @@ -45,20 +45,28 @@ class FeatureManager { return extinst_importid_GLSLstd450_; } - private: - // Analyzes |module| and records enabled extensions. - void AddExtensions(Module* module); + friend bool operator==(const FeatureManager& a, const FeatureManager& b); + friend bool operator!=(const FeatureManager& a, const FeatureManager& b) { + return !(a == b); + } // Adds the given |capability| and all implied capabilities into the current // FeatureManager. void AddCapability(SpvCapability capability); - // Analyzes |module| and records enabled capabilities. - void AddCapabilities(Module* module); + // Add the extension |ext| to the feature manager. + void AddExtension(Instruction* ext); // Analyzes |module| and records imported external instruction sets. void AddExtInstImportIds(Module* module); + private: + // Analyzes |module| and records enabled extensions. + void AddExtensions(Module* module); + + // Analyzes |module| and records enabled capabilities. + void AddCapabilities(Module* module); + // Auxiliary object for querying SPIR-V grammar facts. const AssemblyGrammar& grammar_; diff --git a/third_party/spirv-tools/source/opt/fix_storage_class.cpp b/third_party/spirv-tools/source/opt/fix_storage_class.cpp new file mode 100644 index 0000000000..03da0d0d1b --- /dev/null +++ b/third_party/spirv-tools/source/opt/fix_storage_class.cpp @@ -0,0 +1,330 @@ +// Copyright (c) 2019 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 "fix_storage_class.h" + +#include + +#include "source/opt/instruction.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace opt { + +Pass::Status FixStorageClass::Process() { + bool modified = false; + + get_module()->ForEachInst([this, &modified](Instruction* inst) { + if (inst->opcode() == SpvOpVariable) { + std::set seen; + std::vector> uses; + get_def_use_mgr()->ForEachUse(inst, + [&uses](Instruction* use, uint32_t op_idx) { + uses.push_back({use, op_idx}); + }); + + for (auto& use : uses) { + modified |= PropagateStorageClass( + use.first, + static_cast(inst->GetSingleWordInOperand(0)), + &seen); + assert(seen.empty() && "Seen was not properly reset."); + modified |= + PropagateType(use.first, inst->type_id(), use.second, &seen); + assert(seen.empty() && "Seen was not properly reset."); + } + } + }); + return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange; +} + +bool FixStorageClass::PropagateStorageClass(Instruction* inst, + SpvStorageClass storage_class, + std::set* seen) { + if (!IsPointerResultType(inst)) { + return false; + } + + if (IsPointerToStorageClass(inst, storage_class)) { + if (inst->opcode() == SpvOpPhi) { + if (!seen->insert(inst->result_id()).second) { + return false; + } + } + + bool modified = false; + std::vector uses; + get_def_use_mgr()->ForEachUser( + inst, [&uses](Instruction* use) { uses.push_back(use); }); + for (Instruction* use : uses) { + modified |= PropagateStorageClass(use, storage_class, seen); + } + + if (inst->opcode() == SpvOpPhi) { + seen->erase(inst->result_id()); + } + return modified; + } + + switch (inst->opcode()) { + case SpvOpAccessChain: + case SpvOpPtrAccessChain: + case SpvOpInBoundsAccessChain: + case SpvOpCopyObject: + case SpvOpPhi: + case SpvOpSelect: + FixInstructionStorageClass(inst, storage_class, seen); + return true; + case SpvOpFunctionCall: + // We cannot be sure of the actual connection between the storage class + // of the parameter and the storage class of the result, so we should not + // do anything. If the result type needs to be fixed, the function call + // should be inlined. + return false; + case SpvOpImageTexelPointer: + case SpvOpLoad: + case SpvOpStore: + case SpvOpCopyMemory: + case SpvOpCopyMemorySized: + case SpvOpVariable: + case SpvOpBitcast: + // Nothing to change for these opcode. The result type is the same + // regardless of the storage class of the operand. + return false; + default: + assert(false && + "Not expecting instruction to have a pointer result type."); + return false; + } +} + +void FixStorageClass::FixInstructionStorageClass(Instruction* inst, + SpvStorageClass storage_class, + std::set* seen) { + assert(IsPointerResultType(inst) && + "The result type of the instruction must be a pointer."); + + ChangeResultStorageClass(inst, storage_class); + + std::vector uses; + get_def_use_mgr()->ForEachUser( + inst, [&uses](Instruction* use) { uses.push_back(use); }); + for (Instruction* use : uses) { + PropagateStorageClass(use, storage_class, seen); + } +} + +void FixStorageClass::ChangeResultStorageClass( + Instruction* inst, SpvStorageClass storage_class) const { + analysis::TypeManager* type_mgr = context()->get_type_mgr(); + Instruction* result_type_inst = get_def_use_mgr()->GetDef(inst->type_id()); + assert(result_type_inst->opcode() == SpvOpTypePointer); + uint32_t pointee_type_id = result_type_inst->GetSingleWordInOperand(1); + uint32_t new_result_type_id = + type_mgr->FindPointerToType(pointee_type_id, storage_class); + inst->SetResultType(new_result_type_id); + context()->UpdateDefUse(inst); +} + +bool FixStorageClass::IsPointerResultType(Instruction* inst) { + if (inst->type_id() == 0) { + return false; + } + const analysis::Type* ret_type = + context()->get_type_mgr()->GetType(inst->type_id()); + return ret_type->AsPointer() != nullptr; +} + +bool FixStorageClass::IsPointerToStorageClass(Instruction* inst, + SpvStorageClass storage_class) { + analysis::TypeManager* type_mgr = context()->get_type_mgr(); + analysis::Type* pType = type_mgr->GetType(inst->type_id()); + const analysis::Pointer* result_type = pType->AsPointer(); + + if (result_type == nullptr) { + return false; + } + + return (result_type->storage_class() == storage_class); +} + +bool FixStorageClass::ChangeResultType(Instruction* inst, + uint32_t new_type_id) { + if (inst->type_id() == new_type_id) { + return false; + } + + context()->ForgetUses(inst); + inst->SetResultType(new_type_id); + context()->AnalyzeUses(inst); + return true; +} + +bool FixStorageClass::PropagateType(Instruction* inst, uint32_t type_id, + uint32_t op_idx, std::set* seen) { + assert(type_id != 0 && "Not given a valid type in PropagateType"); + bool modified = false; + + // If the type of operand |op_idx| forces the result type of |inst| to a + // particular type, then we want find that type. + uint32_t new_type_id = 0; + switch (inst->opcode()) { + case SpvOpAccessChain: + case SpvOpPtrAccessChain: + case SpvOpInBoundsAccessChain: + case SpvOpInBoundsPtrAccessChain: + if (op_idx == 2) { + new_type_id = WalkAccessChainType(inst, type_id); + } + break; + case SpvOpCopyObject: + new_type_id = type_id; + break; + case SpvOpPhi: + if (seen->insert(inst->result_id()).second) { + new_type_id = type_id; + } + break; + case SpvOpSelect: + if (op_idx > 2) { + new_type_id = type_id; + } + break; + case SpvOpFunctionCall: + // We cannot be sure of the actual connection between the type + // of the parameter and the type of the result, so we should not + // do anything. If the result type needs to be fixed, the function call + // should be inlined. + return false; + case SpvOpLoad: { + Instruction* type_inst = get_def_use_mgr()->GetDef(type_id); + new_type_id = type_inst->GetSingleWordInOperand(1); + break; + } + case SpvOpStore: { + uint32_t obj_id = inst->GetSingleWordInOperand(1); + Instruction* obj_inst = get_def_use_mgr()->GetDef(obj_id); + uint32_t obj_type_id = obj_inst->type_id(); + + uint32_t ptr_id = inst->GetSingleWordInOperand(0); + Instruction* ptr_inst = get_def_use_mgr()->GetDef(ptr_id); + uint32_t pointee_type_id = GetPointeeTypeId(ptr_inst); + + if (obj_type_id != pointee_type_id) { + uint32_t copy_id = GenerateCopy(obj_inst, pointee_type_id, inst); + inst->SetInOperand(1, {copy_id}); + context()->UpdateDefUse(inst); + } + } break; + case SpvOpCopyMemory: + case SpvOpCopyMemorySized: + // TODO: May need to expand the copy as we do with the stores. + break; + case SpvOpCompositeConstruct: + case SpvOpCompositeExtract: + case SpvOpCompositeInsert: + // TODO: DXC does not seem to generate code that will require changes to + // these opcode. The can be implemented when they come up. + break; + case SpvOpImageTexelPointer: + case SpvOpBitcast: + // Nothing to change for these opcode. The result type is the same + // regardless of the type of the operand. + return false; + default: + // I expect the remaining instructions to act on types that are guaranteed + // to be unique, so no change will be necessary. + break; + } + + // If the operand forces the result type, then make sure the result type + // matches, and update the uses of |inst|. We do not have to check the uses + // of |inst| in the result type is not forced because we are only looking for + // issue that come from mismatches between function formal and actual + // parameters after the function has been inlined. These parameters are + // pointers. Once the type no longer depends on the type of the parameter, + // then the types should have be correct. + if (new_type_id != 0) { + modified = ChangeResultType(inst, new_type_id); + + std::vector> uses; + get_def_use_mgr()->ForEachUse(inst, + [&uses](Instruction* use, uint32_t idx) { + uses.push_back({use, idx}); + }); + + for (auto& use : uses) { + PropagateType(use.first, new_type_id, use.second, seen); + } + + if (inst->opcode() == SpvOpPhi) { + seen->erase(inst->result_id()); + } + } + return modified; +} + +uint32_t FixStorageClass::WalkAccessChainType(Instruction* inst, uint32_t id) { + uint32_t start_idx = 0; + switch (inst->opcode()) { + case SpvOpAccessChain: + case SpvOpInBoundsAccessChain: + start_idx = 1; + break; + case SpvOpPtrAccessChain: + case SpvOpInBoundsPtrAccessChain: + start_idx = 2; + break; + default: + assert(false); + break; + } + + Instruction* orig_type_inst = get_def_use_mgr()->GetDef(id); + assert(orig_type_inst->opcode() == SpvOpTypePointer); + id = orig_type_inst->GetSingleWordInOperand(1); + + for (uint32_t i = start_idx; i < inst->NumInOperands(); ++i) { + Instruction* type_inst = get_def_use_mgr()->GetDef(id); + switch (type_inst->opcode()) { + case SpvOpTypeArray: + case SpvOpTypeRuntimeArray: + case SpvOpTypeMatrix: + case SpvOpTypeVector: + id = type_inst->GetSingleWordInOperand(0); + break; + case SpvOpTypeStruct: { + const analysis::Constant* index_const = + context()->get_constant_mgr()->FindDeclaredConstant( + inst->GetSingleWordInOperand(i)); + uint32_t index = index_const->GetU32(); + id = type_inst->GetSingleWordInOperand(index); + break; + } + default: + break; + } + assert(id != 0 && + "Tried to extract from an object where it cannot be done."); + } + + return context()->get_type_mgr()->FindPointerToType( + id, + static_cast(orig_type_inst->GetSingleWordInOperand(0))); +} + +// namespace opt + +} // namespace opt +} // namespace spvtools diff --git a/third_party/spirv-tools/source/opt/fix_storage_class.h b/third_party/spirv-tools/source/opt/fix_storage_class.h new file mode 100644 index 0000000000..e72e864a6e --- /dev/null +++ b/third_party/spirv-tools/source/opt/fix_storage_class.h @@ -0,0 +1,93 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_OPT_FIX_STORAGE_CLASS_H_ +#define SOURCE_OPT_FIX_STORAGE_CLASS_H_ + +#include + +#include "source/opt/ir_context.h" +#include "source/opt/module.h" +#include "source/opt/pass.h" + +namespace spvtools { +namespace opt { + +// This pass tries to fix validation error due to a mismatch of storage classes +// in instructions. There is no guarantee that all such error will be fixed, +// and it is possible that in fixing these errors, it could lead to other +// errors. +class FixStorageClass : public Pass { + public: + const char* name() const override { return "fix-storage-class"; } + Status Process() override; + + // Return the mask of preserved Analyses. + IRContext::Analysis GetPreservedAnalyses() override { + return IRContext::kAnalysisDefUse | + IRContext::kAnalysisInstrToBlockMapping | + IRContext::kAnalysisCombinators | IRContext::kAnalysisCFG | + IRContext::kAnalysisDominatorAnalysis | + IRContext::kAnalysisLoopAnalysis | IRContext::kAnalysisNameMap | + IRContext::kAnalysisConstants | IRContext::kAnalysisTypes; + } + + private: + // Changes the storage class of the result of |inst| to |storage_class| in + // appropriate, and propagates the change to the users of |inst| as well. + // Returns true of any changes were made. + // |seen| is used to track OpPhi instructions that should not be processed. + bool PropagateStorageClass(Instruction* inst, SpvStorageClass storage_class, + std::set* seen); + + // Changes the storage class of the result of |inst| to |storage_class|. + // Is it assumed that the result type of |inst| is a pointer type. + // Propagates the change to the users of |inst| as well. + // Returns true of any changes were made. + // |seen| is used to track OpPhi instructions that should not be processed by + // |PropagateStorageClass| + void FixInstructionStorageClass(Instruction* inst, + SpvStorageClass storage_class, + std::set* seen); + + // Changes the storage class of the result of |inst| to |storage_class|. The + // result type of |inst| must be a pointer. + void ChangeResultStorageClass(Instruction* inst, + SpvStorageClass storage_class) const; + + // Returns true if the result type of |inst| is a pointer. + bool IsPointerResultType(Instruction* inst); + + // Returns true if the result of |inst| is a pointer to storage class + // |storage_class|. + bool IsPointerToStorageClass(Instruction* inst, + SpvStorageClass storage_class); + + // Change |inst| to match that operand |op_idx| now has type |type_id|, and + // adjust any uses of |inst| accordingly. Returns true if the code changed. + bool PropagateType(Instruction* inst, uint32_t type_id, uint32_t op_idx, + std::set* seen); + + // Changes the result type of |inst| to |new_type_id|. + bool ChangeResultType(Instruction* inst, uint32_t new_type_id); + + // Returns the type id of the member of the type |id| that would be returned + // by following the indices of the access chain instruction |inst|. + uint32_t WalkAccessChainType(Instruction* inst, uint32_t id); +}; + +} // namespace opt +} // namespace spvtools + +#endif // SOURCE_OPT_FIX_STORAGE_CLASS_H_ diff --git a/third_party/spirv-tools/source/opt/fold.cpp b/third_party/spirv-tools/source/opt/fold.cpp index 09d7e51224..6550fb4fdb 100644 --- a/third_party/spirv-tools/source/opt/fold.cpp +++ b/third_party/spirv-tools/source/opt/fold.cpp @@ -45,12 +45,21 @@ namespace { uint32_t InstructionFolder::UnaryOperate(SpvOp opcode, uint32_t operand) const { switch (opcode) { // Arthimetics - case SpvOp::SpvOpSNegate: - return -static_cast(operand); + case SpvOp::SpvOpSNegate: { + int32_t s_operand = static_cast(operand); + if (s_operand == std::numeric_limits::min()) { + return s_operand; + } + return -s_operand; + } case SpvOp::SpvOpNot: return ~operand; case SpvOp::SpvOpLogicalNot: return !static_cast(operand); + case SpvOp::SpvOpUConvert: + return operand; + case SpvOp::SpvOpSConvert: + return operand; default: assert(false && "Unsupported unary operation for OpSpecConstantOp instruction"); @@ -69,37 +78,81 @@ uint32_t InstructionFolder::BinaryOperate(SpvOp opcode, uint32_t a, case SpvOp::SpvOpIMul: return a * b; case SpvOp::SpvOpUDiv: - assert(b != 0); - return a / b; + if (b != 0) { + return a / b; + } else { + // Dividing by 0 is undefined, so we will just pick 0. + return 0; + } case SpvOp::SpvOpSDiv: - assert(b != 0u); - return (static_cast(a)) / (static_cast(b)); + if (b != 0u) { + return (static_cast(a)) / (static_cast(b)); + } else { + // Dividing by 0 is undefined, so we will just pick 0. + return 0; + } case SpvOp::SpvOpSRem: { // The sign of non-zero result comes from the first operand: a. This is // guaranteed by C++11 rules for integer division operator. The division // result is rounded toward zero, so the result of '%' has the sign of // the first operand. - assert(b != 0u); - return static_cast(a) % static_cast(b); + if (b != 0u) { + return static_cast(a) % static_cast(b); + } else { + // Remainder when dividing with 0 is undefined, so we will just pick 0. + return 0; + } } case SpvOp::SpvOpSMod: { // The sign of non-zero result comes from the second operand: b - assert(b != 0u); - int32_t rem = BinaryOperate(SpvOp::SpvOpSRem, a, b); - int32_t b_prim = static_cast(b); - return (rem + b_prim) % b_prim; + if (b != 0u) { + int32_t rem = BinaryOperate(SpvOp::SpvOpSRem, a, b); + int32_t b_prim = static_cast(b); + return (rem + b_prim) % b_prim; + } else { + // Mod with 0 is undefined, so we will just pick 0. + return 0; + } } case SpvOp::SpvOpUMod: - assert(b != 0u); - return (a % b); + if (b != 0u) { + return (a % b); + } else { + // Mod with 0 is undefined, so we will just pick 0. + return 0; + } // Shifting - case SpvOp::SpvOpShiftRightLogical: { + case SpvOp::SpvOpShiftRightLogical: + if (b >= 32) { + // This is undefined behaviour when |b| > 32. Choose 0 for consistency. + // When |b| == 32, doing the shift in C++ in undefined, but the result + // will be 0, so just return that value. + return 0; + } return a >> b; - } case SpvOp::SpvOpShiftRightArithmetic: + if (b > 32) { + // This is undefined behaviour. Choose 0 for consistency. + return 0; + } + if (b == 32) { + // Doing the shift in C++ is undefined, but the result is defined in the + // spir-v spec. Find that value another way. + if (static_cast(a) >= 0) { + return 0; + } else { + return static_cast(-1); + } + } return (static_cast(a)) >> b; case SpvOp::SpvOpShiftLeftLogical: + if (b >= 32) { + // This is undefined behaviour when |b| > 32. Choose 0 for consistency. + // When |b| == 32, doing the shift in C++ in undefined, but the result + // will be 0, so just return that value. + return 0; + } return a << b; // Bitwise operations @@ -185,13 +238,12 @@ bool InstructionFolder::FoldInstructionInternal(Instruction* inst) const { return true; } - SpvOp opcode = inst->opcode(); analysis::ConstantManager* const_manager = context_->get_constant_mgr(); - std::vector constants = const_manager->GetOperandConstants(inst); - for (const FoldingRule& rule : GetFoldingRules().GetRulesForOpcode(opcode)) { + for (const FoldingRule& rule : + GetFoldingRules().GetRulesForInstruction(inst)) { if (rule(context_, inst, constants)) { return true; } @@ -276,7 +328,8 @@ bool InstructionFolder::FoldBinaryIntegerOpToConstant( if (constants[1] != nullptr) { // When shifting by a value larger than the size of the result, the // result is undefined. We are setting the undefined behaviour to a - // result of 0. + // result of 0. If the shift amount is the same as the size of the + // result, then the result is defined, and it 0. uint32_t shift_amount = constants[1]->GetU32BitValue(); if (shift_amount >= 32) { *result = 0; @@ -547,6 +600,8 @@ bool InstructionFolder::IsFoldableOpcode(SpvOp opcode) const { case SpvOp::SpvOpSMod: case SpvOp::SpvOpSNegate: case SpvOp::SpvOpSRem: + case SpvOp::SpvOpSConvert: + case SpvOp::SpvOpUConvert: case SpvOp::SpvOpUDiv: case SpvOp::SpvOpUGreaterThan: case SpvOp::SpvOpUGreaterThanEqual: @@ -573,7 +628,7 @@ Instruction* InstructionFolder::FoldInstructionToConstant( analysis::ConstantManager* const_mgr = context_->get_constant_mgr(); if (!inst->IsFoldableByFoldScalar() && - !GetConstantFoldingRules().HasFoldingRule(inst->opcode())) { + !GetConstantFoldingRules().HasFoldingRule(inst)) { return nullptr; } // Collect the values of the constant parameters. @@ -591,19 +646,19 @@ Instruction* InstructionFolder::FoldInstructionToConstant( } }); - if (GetConstantFoldingRules().HasFoldingRule(inst->opcode())) { - const analysis::Constant* folded_const = nullptr; - for (auto rule : - GetConstantFoldingRules().GetRulesForOpcode(inst->opcode())) { - folded_const = rule(context_, inst, constants); - if (folded_const != nullptr) { - Instruction* const_inst = - const_mgr->GetDefiningInstruction(folded_const, inst->type_id()); - assert(const_inst->type_id() == inst->type_id()); - // May be a new instruction that needs to be analysed. - context_->UpdateDefUse(const_inst); - return const_inst; + const analysis::Constant* folded_const = nullptr; + for (auto rule : GetConstantFoldingRules().GetRulesForInstruction(inst)) { + folded_const = rule(context_, inst, constants); + if (folded_const != nullptr) { + Instruction* const_inst = + const_mgr->GetDefiningInstruction(folded_const, inst->type_id()); + if (const_inst == nullptr) { + return nullptr; } + assert(const_inst->type_id() == inst->type_id()); + // May be a new instruction that needs to be analysed. + context_->UpdateDefUse(const_inst); + return const_inst; } } diff --git a/third_party/spirv-tools/source/opt/fold.h b/third_party/spirv-tools/source/opt/fold.h index 0dc7c0ebbe..9e7c4705e3 100644 --- a/third_party/spirv-tools/source/opt/fold.h +++ b/third_party/spirv-tools/source/opt/fold.h @@ -28,7 +28,23 @@ namespace opt { class InstructionFolder { public: - explicit InstructionFolder(IRContext* context) : context_(context) {} + explicit InstructionFolder(IRContext* context) + : context_(context), + const_folding_rules_(new ConstantFoldingRules(context)), + folding_rules_(new FoldingRules(context)) { + folding_rules_->AddFoldingRules(); + const_folding_rules_->AddFoldingRules(); + } + + explicit InstructionFolder( + IRContext* context, std::unique_ptr&& folding_rules, + std::unique_ptr&& constant_folding_rules) + : context_(context), + const_folding_rules_(std::move(constant_folding_rules)), + folding_rules_(std::move(folding_rules)) { + folding_rules_->AddFoldingRules(); + const_folding_rules_->AddFoldingRules(); + } // Returns the result of folding a scalar instruction with the given |opcode| // and |operands|. Each entry in |operands| is a pointer to an @@ -95,18 +111,18 @@ class InstructionFolder { bool FoldInstruction(Instruction* inst) const; // Return true if this opcode has a const folding rule associtated with it. - bool HasConstFoldingRule(SpvOp opcode) const { - return GetConstantFoldingRules().HasFoldingRule(opcode); + bool HasConstFoldingRule(const Instruction* inst) const { + return GetConstantFoldingRules().HasFoldingRule(inst); } private: // Returns a reference to the ConstnatFoldingRules instance. const ConstantFoldingRules& GetConstantFoldingRules() const { - return const_folding_rules; + return *const_folding_rules_; } // Returns a reference to the FoldingRules instance. - const FoldingRules& GetFoldingRules() const { return folding_rules; } + const FoldingRules& GetFoldingRules() const { return *folding_rules_; } // Returns the single-word result from performing the given unary operation on // the operand value which is passed in as a 32-bit word. @@ -159,10 +175,10 @@ class InstructionFolder { IRContext* context_; // Folding rules used by |FoldInstructionToConstant| and |FoldInstruction|. - ConstantFoldingRules const_folding_rules; + std::unique_ptr const_folding_rules_; // Folding rules used by |FoldInstruction|. - FoldingRules folding_rules; + std::unique_ptr folding_rules_; }; } // namespace opt diff --git a/third_party/spirv-tools/source/opt/fold_spec_constant_op_and_composite_pass.cpp b/third_party/spirv-tools/source/opt/fold_spec_constant_op_and_composite_pass.cpp index d43053e771..8ab717ea8a 100644 --- a/third_party/spirv-tools/source/opt/fold_spec_constant_op_and_composite_pass.cpp +++ b/third_party/spirv-tools/source/opt/fold_spec_constant_op_and_composite_pass.cpp @@ -120,19 +120,15 @@ bool FoldSpecConstantOpAndCompositePass::ProcessOpSpecConstantOp( switch (static_cast(inst->GetSingleWordInOperand(0))) { case SpvOp::SpvOpCompositeExtract: - folded_inst = DoCompositeExtract(pos); - break; case SpvOp::SpvOpVectorShuffle: - folded_inst = DoVectorShuffle(pos); - break; - case SpvOp::SpvOpCompositeInsert: - // Current Glslang does not generate code with OpSpecConstantOp - // CompositeInsert instruction, so this is not implmented so far. - // TODO(qining): Implement CompositeInsert case. - return false; - + case SpvOp::SpvOpQuantizeToF16: + folded_inst = FoldWithInstructionFolder(pos); + break; default: + // TODO: This should use the instruction folder as well, but some folding + // rules are missing. + // Component-wise operations. folded_inst = DoComponentWiseOperation(pos); break; @@ -157,54 +153,65 @@ uint32_t FoldSpecConstantOpAndCompositePass::GetTypeComponent( return subtype; } -Instruction* FoldSpecConstantOpAndCompositePass::DoCompositeExtract( - Module::inst_iterator* pos) { - Instruction* inst = &**pos; - assert(inst->NumInOperands() - 1 >= 2 && - "OpSpecConstantOp CompositeExtract requires at least two non-type " - "non-opcode operands."); - assert(inst->GetInOperand(1).type == SPV_OPERAND_TYPE_ID && - "The composite operand must have a SPV_OPERAND_TYPE_ID type"); - assert( - inst->GetInOperand(2).type == SPV_OPERAND_TYPE_LITERAL_INTEGER && - "The literal operand must have a SPV_OPERAND_TYPE_LITERAL_INTEGER type"); - - // Note that for OpSpecConstantOp, the second in-operand is the first id - // operand. The first in-operand is the spec opcode. - uint32_t source = inst->GetSingleWordInOperand(1); - uint32_t type = context()->get_def_use_mgr()->GetDef(source)->type_id(); - const analysis::Constant* first_operand_const = - context()->get_constant_mgr()->FindDeclaredConstant(source); - if (!first_operand_const) return nullptr; - - const analysis::Constant* current_const = first_operand_const; - for (uint32_t i = 2; i < inst->NumInOperands(); i++) { - uint32_t literal = inst->GetSingleWordInOperand(i); - type = GetTypeComponent(type, literal); - } - for (uint32_t i = 2; i < inst->NumInOperands(); i++) { - uint32_t literal = inst->GetSingleWordInOperand(i); - if (const analysis::CompositeConstant* composite_const = - current_const->AsCompositeConstant()) { - // Case 1: current constant is a non-null composite type constant. - assert(literal < composite_const->GetComponents().size() && - "Literal index out of bound of the composite constant"); - current_const = composite_const->GetComponents().at(literal); - } else if (current_const->AsNullConstant()) { - // Case 2: current constant is a constant created with OpConstantNull. - // Because components of a NullConstant are always NullConstants, we can - // return early with a NullConstant in the result type. - return context()->get_constant_mgr()->BuildInstructionAndAddToModule( - context()->get_constant_mgr()->GetConstant( - context()->get_constant_mgr()->GetType(inst), {}), - pos, type); - } else { - // Dereferencing a non-composite constant. Invalid case. +Instruction* FoldSpecConstantOpAndCompositePass::FoldWithInstructionFolder( + Module::inst_iterator* inst_iter_ptr) { + // If one of operands to the instruction is not a + // constant, then we cannot fold this spec constant. + for (uint32_t i = 1; i < (*inst_iter_ptr)->NumInOperands(); i++) { + const Operand& operand = (*inst_iter_ptr)->GetInOperand(i); + if (operand.type != SPV_OPERAND_TYPE_ID && + operand.type != SPV_OPERAND_TYPE_OPTIONAL_ID) { + continue; + } + uint32_t id = operand.words[0]; + if (context()->get_constant_mgr()->FindDeclaredConstant(id) == nullptr) { return nullptr; } } - return context()->get_constant_mgr()->BuildInstructionAndAddToModule( - current_const, pos); + + // All of the operands are constant. Construct a regular version of the + // instruction and pass it to the instruction folder. + std::unique_ptr inst((*inst_iter_ptr)->Clone(context())); + inst->SetOpcode( + static_cast((*inst_iter_ptr)->GetSingleWordInOperand(0))); + inst->RemoveOperand(2); + + // We want the current instruction to be replaced by an |OpConstant*| + // instruction in the same position. We need to keep track of which constants + // the instruction folder creates, so we can move them into the correct place. + auto last_type_value_iter = (context()->types_values_end()); + --last_type_value_iter; + Instruction* last_type_value = &*last_type_value_iter; + + auto identity_map = [](uint32_t id) { return id; }; + Instruction* new_const_inst = + context()->get_instruction_folder().FoldInstructionToConstant( + inst.get(), identity_map); + assert(new_const_inst != nullptr && + "Failed to fold instruction that must be folded."); + + // Get the instruction before |pos| to insert after. |pos| cannot be the + // first instruction in the list because its type has to come first. + Instruction* insert_pos = (*inst_iter_ptr)->PreviousNode(); + assert(insert_pos != nullptr && + "pos is the first instruction in the types and values."); + bool need_to_clone = true; + for (Instruction* i = last_type_value->NextNode(); i != nullptr; + i = last_type_value->NextNode()) { + if (i == new_const_inst) { + need_to_clone = false; + } + i->InsertAfter(insert_pos); + insert_pos = insert_pos->NextNode(); + } + + if (need_to_clone) { + new_const_inst = new_const_inst->Clone(context()); + new_const_inst->SetResultId(TakeNextId()); + new_const_inst->InsertAfter(insert_pos); + get_def_use_mgr()->AnalyzeInstDefUse(new_const_inst); + } + return new_const_inst; } Instruction* FoldSpecConstantOpAndCompositePass::DoVectorShuffle( @@ -279,11 +286,10 @@ Instruction* FoldSpecConstantOpAndCompositePass::DoVectorShuffle( "Literal index out of bound of the concatenated vector"); selected_components.push_back(concatenated_components[literal]); } - auto new_vec_const = - new analysis::VectorConstant(result_vec_type, selected_components); + auto new_vec_const = MakeUnique( + result_vec_type, selected_components); auto reg_vec_const = - context()->get_constant_mgr()->RegisterConstant(new_vec_const); - if (reg_vec_const != new_vec_const) delete new_vec_const; + context()->get_constant_mgr()->RegisterConstant(std::move(new_vec_const)); return context()->get_constant_mgr()->BuildInstructionAndAddToModule( reg_vec_const, pos); } @@ -310,6 +316,59 @@ bool IsValidTypeForComponentWiseOperation(const analysis::Type* type) { } return false; } + +// Encodes the integer |value| of in a word vector format appropriate for +// representing this value as a operands for a constant definition. Performs +// zero-extension/sign-extension/truncation when needed, based on the signess of +// the given target type. +// +// Note: type |type| argument must be either Integer or Bool. +utils::SmallVector EncodeIntegerAsWords(const analysis::Type& type, + uint32_t value) { + const uint32_t all_ones = ~0; + uint32_t bit_width = 0; + uint32_t pad_value = 0; + bool result_type_signed = false; + if (auto* int_ty = type.AsInteger()) { + bit_width = int_ty->width(); + result_type_signed = int_ty->IsSigned(); + if (result_type_signed && static_cast(value) < 0) { + pad_value = all_ones; + } + } else if (type.AsBool()) { + bit_width = 1; + } else { + assert(false && "type must be Integer or Bool"); + } + + assert(bit_width > 0); + uint32_t first_word = value; + const uint32_t bits_per_word = 32; + + // Truncate first_word if the |type| has width less than uint32. + if (bit_width < bits_per_word) { + const uint32_t num_high_bits_to_mask = bits_per_word - bit_width; + const bool is_negative_after_truncation = + result_type_signed && + utils::IsBitAtPositionSet(first_word, bit_width - 1); + + if (is_negative_after_truncation) { + // Truncate and sign-extend |first_word|. No padding words will be + // added and |pad_value| can be left as-is. + first_word = utils::SetHighBits(first_word, num_high_bits_to_mask); + } else { + first_word = utils::ClearHighBits(first_word, num_high_bits_to_mask); + } + } + + utils::SmallVector words = {first_word}; + for (uint32_t current_bit = bits_per_word; current_bit < bit_width; + current_bit += bits_per_word) { + words.push_back(pad_value); + } + + return words; +} } // namespace Instruction* FoldSpecConstantOpAndCompositePass::DoComponentWiseOperation( @@ -339,10 +398,10 @@ Instruction* FoldSpecConstantOpAndCompositePass::DoComponentWiseOperation( if (result_type->AsInteger() || result_type->AsBool()) { // Scalar operation - uint32_t result_val = + const uint32_t result_val = context()->get_instruction_folder().FoldScalars(spec_opcode, operands); - auto result_const = - context()->get_constant_mgr()->GetConstant(result_type, {result_val}); + auto result_const = context()->get_constant_mgr()->GetConstant( + result_type, EncodeIntegerAsWords(*result_type, result_val)); return context()->get_constant_mgr()->BuildInstructionAndAddToModule( result_const, pos); } else if (result_type->AsVector()) { @@ -354,9 +413,9 @@ Instruction* FoldSpecConstantOpAndCompositePass::DoComponentWiseOperation( context()->get_instruction_folder().FoldVectors(spec_opcode, num_dims, operands); std::vector result_vector_components; - for (uint32_t r : result_vec) { - if (auto rc = - context()->get_constant_mgr()->GetConstant(element_type, {r})) { + for (const uint32_t r : result_vec) { + if (auto rc = context()->get_constant_mgr()->GetConstant( + element_type, EncodeIntegerAsWords(*element_type, r))) { result_vector_components.push_back(rc); if (!context()->get_constant_mgr()->BuildInstructionAndAddToModule( rc, pos)) { @@ -368,11 +427,10 @@ Instruction* FoldSpecConstantOpAndCompositePass::DoComponentWiseOperation( assert(false && "Failed to create constants with 32-bit word"); } } - auto new_vec_const = new analysis::VectorConstant(result_type->AsVector(), - result_vector_components); - auto reg_vec_const = - context()->get_constant_mgr()->RegisterConstant(new_vec_const); - if (reg_vec_const != new_vec_const) delete new_vec_const; + auto new_vec_const = MakeUnique( + result_type->AsVector(), result_vector_components); + auto reg_vec_const = context()->get_constant_mgr()->RegisterConstant( + std::move(new_vec_const)); return context()->get_constant_mgr()->BuildInstructionAndAddToModule( reg_vec_const, pos); } else { diff --git a/third_party/spirv-tools/source/opt/fold_spec_constant_op_and_composite_pass.h b/third_party/spirv-tools/source/opt/fold_spec_constant_op_and_composite_pass.h index 16271251f4..361d3cacb4 100644 --- a/third_party/spirv-tools/source/opt/fold_spec_constant_op_and_composite_pass.h +++ b/third_party/spirv-tools/source/opt/fold_spec_constant_op_and_composite_pass.h @@ -54,11 +54,9 @@ class FoldSpecConstantOpAndCompositePass : public Pass { // it. bool ProcessOpSpecConstantOp(Module::inst_iterator* pos); - // Try to fold the OpSpecConstantOp CompositeExtract instruction pointed by - // the given instruction iterator to a normal constant defining instruction. - // Returns the pointer to the new constant defining instruction if succeeded. - // Otherwise returns nullptr. - Instruction* DoCompositeExtract(Module::inst_iterator* inst_iter_ptr); + // Returns the result of folding the OpSpecConstantOp instruction + // |inst_iter_ptr| using the instruction folder. + Instruction* FoldWithInstructionFolder(Module::inst_iterator* inst_iter_ptr); // Try to fold the OpSpecConstantOp VectorShuffle instruction pointed by the // given instruction iterator to a normal constant defining instruction. diff --git a/third_party/spirv-tools/source/opt/folding_rules.cpp b/third_party/spirv-tools/source/opt/folding_rules.cpp index c64cedfb19..1c8cdc893f 100644 --- a/third_party/spirv-tools/source/opt/folding_rules.cpp +++ b/third_party/spirv-tools/source/opt/folding_rules.cpp @@ -18,6 +18,7 @@ #include #include +#include "ir_builder.h" #include "source/latest_version_glsl_std_450_header.h" #include "source/opt/ir_context.h" @@ -35,6 +36,45 @@ const uint32_t kFMixYIdInIdx = 3; const uint32_t kFMixAIdInIdx = 4; const uint32_t kStoreObjectInIdx = 1; +// Some image instructions may contain an "image operands" argument. +// Returns the operand index for the "image operands". +// Returns -1 if the instruction does not have image operands. +int32_t ImageOperandsMaskInOperandIndex(Instruction* inst) { + const auto opcode = inst->opcode(); + switch (opcode) { + case SpvOpImageSampleImplicitLod: + case SpvOpImageSampleExplicitLod: + case SpvOpImageSampleProjImplicitLod: + case SpvOpImageSampleProjExplicitLod: + case SpvOpImageFetch: + case SpvOpImageRead: + case SpvOpImageSparseSampleImplicitLod: + case SpvOpImageSparseSampleExplicitLod: + case SpvOpImageSparseSampleProjImplicitLod: + case SpvOpImageSparseSampleProjExplicitLod: + case SpvOpImageSparseFetch: + case SpvOpImageSparseRead: + return inst->NumOperands() > 4 ? 2 : -1; + case SpvOpImageSampleDrefImplicitLod: + case SpvOpImageSampleDrefExplicitLod: + case SpvOpImageSampleProjDrefImplicitLod: + case SpvOpImageSampleProjDrefExplicitLod: + case SpvOpImageGather: + case SpvOpImageDrefGather: + case SpvOpImageSparseSampleDrefImplicitLod: + case SpvOpImageSparseSampleDrefExplicitLod: + case SpvOpImageSparseSampleProjDrefImplicitLod: + case SpvOpImageSparseSampleProjDrefExplicitLod: + case SpvOpImageSparseGather: + case SpvOpImageSparseDrefGather: + return inst->NumOperands() > 5 ? 3 : -1; + case SpvOpImageWrite: + return inst->NumOperands() > 3 ? 3 : -1; + default: + return -1; + } +} + // Returns the element width of |type|. uint32_t ElementWidth(const analysis::Type* type) { if (const analysis::Vector* vec_type = type->AsVector()) { @@ -513,7 +553,6 @@ uint32_t PerformOperation(analysis::ConstantManager* const_mgr, SpvOp opcode, const analysis::Constant* input1, const analysis::Constant* input2) { assert(input1 && input2); - assert(input1->type() == input2->type()); const analysis::Type* type = input1->type(); std::vector words; if (const analysis::Vector* vector_type = type->AsVector()) { @@ -1239,6 +1278,117 @@ FoldingRule MergeSubSubArithmetic() { }; } +// Helper function for MergeGenericAddSubArithmetic. If |addend| and +// subtrahend of |sub| is the same, merge to copy of minuend of |sub|. +bool MergeGenericAddendSub(uint32_t addend, uint32_t sub, Instruction* inst) { + IRContext* context = inst->context(); + analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr(); + Instruction* sub_inst = def_use_mgr->GetDef(sub); + if (sub_inst->opcode() != SpvOpFSub && sub_inst->opcode() != SpvOpISub) + return false; + if (sub_inst->opcode() == SpvOpFSub && + !sub_inst->IsFloatingPointFoldingAllowed()) + return false; + if (addend != sub_inst->GetSingleWordInOperand(1)) return false; + inst->SetOpcode(SpvOpCopyObject); + inst->SetInOperands( + {{SPV_OPERAND_TYPE_ID, {sub_inst->GetSingleWordInOperand(0)}}}); + context->UpdateDefUse(inst); + return true; +} + +// Folds addition of a subtraction where the subtrahend is equal to the +// other addend. Return a copy of the minuend. Accepts generic (const and +// non-const) operands. +// Cases: +// (a - b) + b = a +// b + (a - b) = a +FoldingRule MergeGenericAddSubArithmetic() { + return [](IRContext* context, Instruction* inst, + const std::vector&) { + assert(inst->opcode() == SpvOpFAdd || inst->opcode() == SpvOpIAdd); + const analysis::Type* type = + context->get_type_mgr()->GetType(inst->type_id()); + bool uses_float = HasFloatingPoint(type); + if (uses_float && !inst->IsFloatingPointFoldingAllowed()) return false; + + uint32_t width = ElementWidth(type); + if (width != 32 && width != 64) return false; + + uint32_t add_op0 = inst->GetSingleWordInOperand(0); + uint32_t add_op1 = inst->GetSingleWordInOperand(1); + if (MergeGenericAddendSub(add_op0, add_op1, inst)) return true; + return MergeGenericAddendSub(add_op1, add_op0, inst); + }; +} + +// Helper function for FactorAddMuls. If |factor0_0| is the same as |factor1_0|, +// generate |factor0_0| * (|factor0_1| + |factor1_1|). +bool FactorAddMulsOpnds(uint32_t factor0_0, uint32_t factor0_1, + uint32_t factor1_0, uint32_t factor1_1, + Instruction* inst) { + IRContext* context = inst->context(); + if (factor0_0 != factor1_0) return false; + InstructionBuilder ir_builder( + context, inst, + IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping); + Instruction* new_add_inst = ir_builder.AddBinaryOp( + inst->type_id(), inst->opcode(), factor0_1, factor1_1); + inst->SetOpcode(inst->opcode() == SpvOpFAdd ? SpvOpFMul : SpvOpIMul); + inst->SetInOperands({{SPV_OPERAND_TYPE_ID, {factor0_0}}, + {SPV_OPERAND_TYPE_ID, {new_add_inst->result_id()}}}); + context->UpdateDefUse(inst); + return true; +} + +// Perform the following factoring identity, handling all operand order +// combinations: (a * b) + (a * c) = a * (b + c) +FoldingRule FactorAddMuls() { + return [](IRContext* context, Instruction* inst, + const std::vector&) { + assert(inst->opcode() == SpvOpFAdd || inst->opcode() == SpvOpIAdd); + const analysis::Type* type = + context->get_type_mgr()->GetType(inst->type_id()); + bool uses_float = HasFloatingPoint(type); + if (uses_float && !inst->IsFloatingPointFoldingAllowed()) return false; + + analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr(); + uint32_t add_op0 = inst->GetSingleWordInOperand(0); + Instruction* add_op0_inst = def_use_mgr->GetDef(add_op0); + if (add_op0_inst->opcode() != SpvOpFMul && + add_op0_inst->opcode() != SpvOpIMul) + return false; + uint32_t add_op1 = inst->GetSingleWordInOperand(1); + Instruction* add_op1_inst = def_use_mgr->GetDef(add_op1); + if (add_op1_inst->opcode() != SpvOpFMul && + add_op1_inst->opcode() != SpvOpIMul) + return false; + + // Only perform this optimization if both of the muls only have one use. + // Otherwise this is a deoptimization in size and performance. + if (def_use_mgr->NumUses(add_op0_inst) > 1) return false; + if (def_use_mgr->NumUses(add_op1_inst) > 1) return false; + + if (add_op0_inst->opcode() == SpvOpFMul && + (!add_op0_inst->IsFloatingPointFoldingAllowed() || + !add_op1_inst->IsFloatingPointFoldingAllowed())) + return false; + + for (int i = 0; i < 2; i++) { + for (int j = 0; j < 2; j++) { + // Check if operand i in add_op0_inst matches operand j in add_op1_inst. + if (FactorAddMulsOpnds(add_op0_inst->GetSingleWordInOperand(i), + add_op0_inst->GetSingleWordInOperand(1 - i), + add_op1_inst->GetSingleWordInOperand(j), + add_op1_inst->GetSingleWordInOperand(1 - j), + inst)) + return true; + } + } + return false; + }; +} + FoldingRule IntMultipleBy1() { return [](IRContext*, Instruction* inst, const std::vector& constants) { @@ -1274,6 +1424,12 @@ FoldingRule CompositeConstructFeedingExtract() { "Wrong opcode. Should be OpCompositeExtract."); analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr(); analysis::TypeManager* type_mgr = context->get_type_mgr(); + + // If there are no index operands, then this rule cannot do anything. + if (inst->NumInOperands() <= 1) { + return false; + } + uint32_t cid = inst->GetSingleWordInOperand(kExtractCompositeIdInIdx); Instruction* cinst = def_use_mgr->GetDef(cid); @@ -1345,60 +1501,64 @@ FoldingRule CompositeConstructFeedingExtract() { }; } -FoldingRule CompositeExtractFeedingConstruct() { - // If the OpCompositeConstruct is simply putting back together elements that - // where extracted from the same souce, we can simlpy reuse the source. - // - // This is a common code pattern because of the way that scalar replacement - // works. - return [](IRContext* context, Instruction* inst, - const std::vector&) { - assert(inst->opcode() == SpvOpCompositeConstruct && - "Wrong opcode. Should be OpCompositeConstruct."); - analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr(); - uint32_t original_id = 0; +// If the OpCompositeConstruct is simply putting back together elements that +// where extracted from the same source, we can simply reuse the source. +// +// This is a common code pattern because of the way that scalar replacement +// works. +bool CompositeExtractFeedingConstruct( + IRContext* context, Instruction* inst, + const std::vector&) { + assert(inst->opcode() == SpvOpCompositeConstruct && + "Wrong opcode. Should be OpCompositeConstruct."); + analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr(); + uint32_t original_id = 0; - // Check each element to make sure they are: - // - extractions - // - extracting the same position they are inserting - // - all extract from the same id. - for (uint32_t i = 0; i < inst->NumInOperands(); ++i) { - uint32_t element_id = inst->GetSingleWordInOperand(i); - Instruction* element_inst = def_use_mgr->GetDef(element_id); + if (inst->NumInOperands() == 0) { + // The struct being constructed has no members. + return false; + } - if (element_inst->opcode() != SpvOpCompositeExtract) { - return false; - } + // Check each element to make sure they are: + // - extractions + // - extracting the same position they are inserting + // - all extract from the same id. + for (uint32_t i = 0; i < inst->NumInOperands(); ++i) { + const uint32_t element_id = inst->GetSingleWordInOperand(i); + Instruction* element_inst = def_use_mgr->GetDef(element_id); - if (element_inst->NumInOperands() != 2) { - return false; - } - - if (element_inst->GetSingleWordInOperand(1) != i) { - return false; - } - - if (i == 0) { - original_id = - element_inst->GetSingleWordInOperand(kExtractCompositeIdInIdx); - } else if (original_id != element_inst->GetSingleWordInOperand( - kExtractCompositeIdInIdx)) { - return false; - } - } - - // The last check it to see that the object being extracted from is the - // correct type. - Instruction* original_inst = def_use_mgr->GetDef(original_id); - if (original_inst->type_id() != inst->type_id()) { + if (element_inst->opcode() != SpvOpCompositeExtract) { return false; } - // Simplify by using the original object. - inst->SetOpcode(SpvOpCopyObject); - inst->SetInOperands({{SPV_OPERAND_TYPE_ID, {original_id}}}); - return true; - }; + if (element_inst->NumInOperands() != 2) { + return false; + } + + if (element_inst->GetSingleWordInOperand(1) != i) { + return false; + } + + if (i == 0) { + original_id = + element_inst->GetSingleWordInOperand(kExtractCompositeIdInIdx); + } else if (original_id != + element_inst->GetSingleWordInOperand(kExtractCompositeIdInIdx)) { + return false; + } + } + + // The last check it to see that the object being extracted from is the + // correct type. + Instruction* original_inst = def_use_mgr->GetDef(original_id); + if (original_inst->type_id() != inst->type_id()) { + return false; + } + + // Simplify by using the original object. + inst->SetOpcode(SpvOpCopyObject); + inst->SetInOperands({{SPV_OPERAND_TYPE_ID, {original_id}}}); + return true; } FoldingRule InsertFeedingExtract() { @@ -2025,7 +2185,7 @@ FoldingRule StoringUndef() { // If this is a volatile store, the store cannot be removed. if (inst->NumInOperands() == 3) { - if (inst->GetSingleWordInOperand(3) & SpvMemoryAccessVolatileMask) { + if (inst->GetSingleWordInOperand(2) & SpvMemoryAccessVolatileMask) { return false; } } @@ -2167,14 +2327,103 @@ FoldingRule VectorShuffleFeedingShuffle() { }; } +// Removes duplicate ids from the interface list of an OpEntryPoint +// instruction. +FoldingRule RemoveRedundantOperands() { + return [](IRContext*, Instruction* inst, + const std::vector&) { + assert(inst->opcode() == SpvOpEntryPoint && + "Wrong opcode. Should be OpEntryPoint."); + bool has_redundant_operand = false; + std::unordered_set seen_operands; + std::vector new_operands; + + new_operands.emplace_back(inst->GetOperand(0)); + new_operands.emplace_back(inst->GetOperand(1)); + new_operands.emplace_back(inst->GetOperand(2)); + for (uint32_t i = 3; i < inst->NumOperands(); ++i) { + if (seen_operands.insert(inst->GetSingleWordOperand(i)).second) { + new_operands.emplace_back(inst->GetOperand(i)); + } else { + has_redundant_operand = true; + } + } + + if (!has_redundant_operand) { + return false; + } + + inst->SetInOperands(std::move(new_operands)); + return true; + }; +} + +// If an image instruction's operand is a constant, updates the image operand +// flag from Offset to ConstOffset. +FoldingRule UpdateImageOperands() { + return [](IRContext*, Instruction* inst, + const std::vector& constants) { + const auto opcode = inst->opcode(); + (void)opcode; + assert((opcode == SpvOpImageSampleImplicitLod || + opcode == SpvOpImageSampleExplicitLod || + opcode == SpvOpImageSampleDrefImplicitLod || + opcode == SpvOpImageSampleDrefExplicitLod || + opcode == SpvOpImageSampleProjImplicitLod || + opcode == SpvOpImageSampleProjExplicitLod || + opcode == SpvOpImageSampleProjDrefImplicitLod || + opcode == SpvOpImageSampleProjDrefExplicitLod || + opcode == SpvOpImageFetch || opcode == SpvOpImageGather || + opcode == SpvOpImageDrefGather || opcode == SpvOpImageRead || + opcode == SpvOpImageWrite || + opcode == SpvOpImageSparseSampleImplicitLod || + opcode == SpvOpImageSparseSampleExplicitLod || + opcode == SpvOpImageSparseSampleDrefImplicitLod || + opcode == SpvOpImageSparseSampleDrefExplicitLod || + opcode == SpvOpImageSparseSampleProjImplicitLod || + opcode == SpvOpImageSparseSampleProjExplicitLod || + opcode == SpvOpImageSparseSampleProjDrefImplicitLod || + opcode == SpvOpImageSparseSampleProjDrefExplicitLod || + opcode == SpvOpImageSparseFetch || + opcode == SpvOpImageSparseGather || + opcode == SpvOpImageSparseDrefGather || + opcode == SpvOpImageSparseRead) && + "Wrong opcode. Should be an image instruction."); + + int32_t operand_index = ImageOperandsMaskInOperandIndex(inst); + if (operand_index >= 0) { + auto image_operands = inst->GetSingleWordInOperand(operand_index); + if (image_operands & SpvImageOperandsOffsetMask) { + uint32_t offset_operand_index = operand_index + 1; + if (image_operands & SpvImageOperandsBiasMask) offset_operand_index++; + if (image_operands & SpvImageOperandsLodMask) offset_operand_index++; + if (image_operands & SpvImageOperandsGradMask) + offset_operand_index += 2; + assert(((image_operands & SpvImageOperandsConstOffsetMask) == 0) && + "Offset and ConstOffset may not be used together"); + if (offset_operand_index < inst->NumOperands()) { + if (constants[offset_operand_index]) { + image_operands = image_operands | SpvImageOperandsConstOffsetMask; + image_operands = image_operands & ~SpvImageOperandsOffsetMask; + inst->SetInOperand(operand_index, {image_operands}); + return true; + } + } + } + } + + return false; + }; +} + } // namespace -FoldingRules::FoldingRules() { +void FoldingRules::AddFoldingRules() { // Add all folding rules to the list for the opcodes to which they apply. // Note that the order in which rules are added to the list matters. If a rule // applies to the instruction, the rest of the rules will not be attempted. // Take that into consideration. - rules_[SpvOpCompositeConstruct].push_back(CompositeExtractFeedingConstruct()); + rules_[SpvOpCompositeConstruct].push_back(CompositeExtractFeedingConstruct); rules_[SpvOpCompositeExtract].push_back(InsertFeedingExtract()); rules_[SpvOpCompositeExtract].push_back(CompositeConstructFeedingExtract()); @@ -2183,12 +2432,14 @@ FoldingRules::FoldingRules() { rules_[SpvOpDot].push_back(DotProductDoingExtract()); - rules_[SpvOpExtInst].push_back(RedundantFMix()); + rules_[SpvOpEntryPoint].push_back(RemoveRedundantOperands()); rules_[SpvOpFAdd].push_back(RedundantFAdd()); rules_[SpvOpFAdd].push_back(MergeAddNegateArithmetic()); rules_[SpvOpFAdd].push_back(MergeAddAddArithmetic()); rules_[SpvOpFAdd].push_back(MergeAddSubArithmetic()); + rules_[SpvOpFAdd].push_back(MergeGenericAddSubArithmetic()); + rules_[SpvOpFAdd].push_back(FactorAddMuls()); rules_[SpvOpFDiv].push_back(RedundantFDiv()); rules_[SpvOpFDiv].push_back(ReciprocalFDiv()); @@ -2214,6 +2465,8 @@ FoldingRules::FoldingRules() { rules_[SpvOpIAdd].push_back(MergeAddNegateArithmetic()); rules_[SpvOpIAdd].push_back(MergeAddAddArithmetic()); rules_[SpvOpIAdd].push_back(MergeAddSubArithmetic()); + rules_[SpvOpIAdd].push_back(MergeGenericAddSubArithmetic()); + rules_[SpvOpIAdd].push_back(FactorAddMuls()); rules_[SpvOpIMul].push_back(IntMultipleBy1()); rules_[SpvOpIMul].push_back(MergeMulMulArithmetic()); @@ -2238,6 +2491,47 @@ FoldingRules::FoldingRules() { rules_[SpvOpUDiv].push_back(MergeDivNegateArithmetic()); rules_[SpvOpVectorShuffle].push_back(VectorShuffleFeedingShuffle()); + + rules_[SpvOpImageSampleImplicitLod].push_back(UpdateImageOperands()); + rules_[SpvOpImageSampleExplicitLod].push_back(UpdateImageOperands()); + rules_[SpvOpImageSampleDrefImplicitLod].push_back(UpdateImageOperands()); + rules_[SpvOpImageSampleDrefExplicitLod].push_back(UpdateImageOperands()); + rules_[SpvOpImageSampleProjImplicitLod].push_back(UpdateImageOperands()); + rules_[SpvOpImageSampleProjExplicitLod].push_back(UpdateImageOperands()); + rules_[SpvOpImageSampleProjDrefImplicitLod].push_back(UpdateImageOperands()); + rules_[SpvOpImageSampleProjDrefExplicitLod].push_back(UpdateImageOperands()); + rules_[SpvOpImageFetch].push_back(UpdateImageOperands()); + rules_[SpvOpImageGather].push_back(UpdateImageOperands()); + rules_[SpvOpImageDrefGather].push_back(UpdateImageOperands()); + rules_[SpvOpImageRead].push_back(UpdateImageOperands()); + rules_[SpvOpImageWrite].push_back(UpdateImageOperands()); + rules_[SpvOpImageSparseSampleImplicitLod].push_back(UpdateImageOperands()); + rules_[SpvOpImageSparseSampleExplicitLod].push_back(UpdateImageOperands()); + rules_[SpvOpImageSparseSampleDrefImplicitLod].push_back( + UpdateImageOperands()); + rules_[SpvOpImageSparseSampleDrefExplicitLod].push_back( + UpdateImageOperands()); + rules_[SpvOpImageSparseSampleProjImplicitLod].push_back( + UpdateImageOperands()); + rules_[SpvOpImageSparseSampleProjExplicitLod].push_back( + UpdateImageOperands()); + rules_[SpvOpImageSparseSampleProjDrefImplicitLod].push_back( + UpdateImageOperands()); + rules_[SpvOpImageSparseSampleProjDrefExplicitLod].push_back( + UpdateImageOperands()); + rules_[SpvOpImageSparseFetch].push_back(UpdateImageOperands()); + rules_[SpvOpImageSparseGather].push_back(UpdateImageOperands()); + rules_[SpvOpImageSparseDrefGather].push_back(UpdateImageOperands()); + rules_[SpvOpImageSparseRead].push_back(UpdateImageOperands()); + + FeatureManager* feature_manager = context_->get_feature_mgr(); + // Add rules for GLSLstd450 + uint32_t ext_inst_glslstd450_id = + feature_manager->GetExtInstImportId_GLSLstd450(); + if (ext_inst_glslstd450_id != 0) { + ext_rules_[{ext_inst_glslstd450_id, GLSLstd450FMix}].push_back( + RedundantFMix()); + } } } // namespace opt } // namespace spvtools diff --git a/third_party/spirv-tools/source/opt/folding_rules.h b/third_party/spirv-tools/source/opt/folding_rules.h index 33fdbffe94..f1a86395ca 100644 --- a/third_party/spirv-tools/source/opt/folding_rules.h +++ b/third_party/spirv-tools/source/opt/folding_rules.h @@ -58,19 +58,58 @@ using FoldingRule = std::function; - const std::vector& GetRulesForOpcode(SpvOp opcode) const { - auto it = rules_.find(opcode); - if (it != rules_.end()) { - return it->second; + explicit FoldingRules(IRContext* ctx) : context_(ctx) {} + virtual ~FoldingRules() = default; + + const FoldingRuleSet& GetRulesForInstruction(Instruction* inst) const { + if (inst->opcode() != SpvOpExtInst) { + auto it = rules_.find(inst->opcode()); + if (it != rules_.end()) { + return it->second; + } + } else { + uint32_t ext_inst_id = inst->GetSingleWordInOperand(0); + uint32_t ext_opcode = inst->GetSingleWordInOperand(1); + auto it = ext_rules_.find({ext_inst_id, ext_opcode}); + if (it != ext_rules_.end()) { + return it->second; + } } return empty_vector_; } + IRContext* context() { return context_; } + + // Adds the folding rules for the object. + virtual void AddFoldingRules(); + + protected: + // The folding rules for core instructions. + std::unordered_map rules_; + + // The folding rules for extended instructions. + struct Key { + uint32_t instruction_set; + uint32_t opcode; + }; + + friend bool operator<(const Key& a, const Key& b) { + if (a.instruction_set < b.instruction_set) { + return true; + } + if (a.instruction_set > b.instruction_set) { + return false; + } + return a.opcode < b.opcode; + } + + std::map ext_rules_; + private: - std::unordered_map> rules_; - std::vector empty_vector_; + IRContext* context_; + FoldingRuleSet empty_vector_; }; } // namespace opt diff --git a/third_party/spirv-tools/source/opt/function.cpp b/third_party/spirv-tools/source/opt/function.cpp index c6894c6810..efda68b78a 100644 --- a/third_party/spirv-tools/source/opt/function.cpp +++ b/third_party/spirv-tools/source/opt/function.cpp @@ -17,6 +17,10 @@ #include #include +#include "function.h" +#include "ir_context.h" +#include "source/util/bit_vector.h" + namespace spvtools { namespace opt { @@ -43,28 +47,83 @@ Function* Function::Clone(IRContext* ctx) const { void Function::ForEachInst(const std::function& f, bool run_on_debug_line_insts) { - if (def_inst_) def_inst_->ForEachInst(f, run_on_debug_line_insts); - for (auto& param : params_) param->ForEachInst(f, run_on_debug_line_insts); - for (auto& bb : blocks_) bb->ForEachInst(f, run_on_debug_line_insts); - if (end_inst_) end_inst_->ForEachInst(f, run_on_debug_line_insts); + WhileEachInst( + [&f](Instruction* inst) { + f(inst); + return true; + }, + run_on_debug_line_insts); } void Function::ForEachInst(const std::function& f, bool run_on_debug_line_insts) const { - if (def_inst_) - static_cast(def_inst_.get()) - ->ForEachInst(f, run_on_debug_line_insts); + WhileEachInst( + [&f](const Instruction* inst) { + f(inst); + return true; + }, + run_on_debug_line_insts); +} - for (const auto& param : params_) - static_cast(param.get()) - ->ForEachInst(f, run_on_debug_line_insts); +bool Function::WhileEachInst(const std::function& f, + bool run_on_debug_line_insts) { + if (def_inst_) { + if (!def_inst_->WhileEachInst(f, run_on_debug_line_insts)) { + return false; + } + } - for (const auto& bb : blocks_) - static_cast(bb.get())->ForEachInst( - f, run_on_debug_line_insts); + for (auto& param : params_) { + if (!param->WhileEachInst(f, run_on_debug_line_insts)) { + return false; + } + } + + for (auto& bb : blocks_) { + if (!bb->WhileEachInst(f, run_on_debug_line_insts)) { + return false; + } + } + + if (end_inst_) return end_inst_->WhileEachInst(f, run_on_debug_line_insts); + + return true; +} + +bool Function::WhileEachInst(const std::function& f, + bool run_on_debug_line_insts) const { + if (def_inst_) { + if (!static_cast(def_inst_.get()) + ->WhileEachInst(f, run_on_debug_line_insts)) { + return false; + } + } + + for (const auto& param : params_) { + if (!static_cast(param.get()) + ->WhileEachInst(f, run_on_debug_line_insts)) { + return false; + } + } + + for (const auto& bb : blocks_) { + if (!static_cast(bb.get())->WhileEachInst( + f, run_on_debug_line_insts)) { + return false; + } + } if (end_inst_) - static_cast(end_inst_.get()) + return static_cast(end_inst_.get()) + ->WhileEachInst(f, run_on_debug_line_insts); + + return true; +} + +void Function::ForEachParam(const std::function& f, + bool run_on_debug_line_insts) { + for (auto& param : params_) + static_cast(param.get()) ->ForEachInst(f, run_on_debug_line_insts); } @@ -89,11 +148,41 @@ BasicBlock* Function::InsertBasicBlockAfter( return nullptr; } +BasicBlock* Function::InsertBasicBlockBefore( + std::unique_ptr&& new_block, BasicBlock* position) { + for (auto bb_iter = begin(); bb_iter != end(); ++bb_iter) { + if (&*bb_iter == position) { + new_block->SetParent(this); + bb_iter = bb_iter.InsertBefore(std::move(new_block)); + return &*bb_iter; + } + } + assert(false && "Could not find insertion point."); + return nullptr; +} + +bool Function::IsRecursive() const { + IRContext* ctx = blocks_.front()->GetLabel()->context(); + IRContext::ProcessFunction mark_visited = [this](Function* fp) { + return fp == this; + }; + + // Process the call tree from all of the function called by |this|. If it get + // back to |this|, then we have a recursive function. + std::queue roots; + ctx->AddCalls(this, &roots); + return ctx->ProcessCallTreeFromRoots(mark_visited, &roots); +} + std::ostream& operator<<(std::ostream& str, const Function& func) { str << func.PrettyPrint(); return str; } +void Function::Dump() const { + std::cerr << "Function #" << result_id() << "\n" << *this << "\n"; +} + std::string Function::PrettyPrint(uint32_t options) const { std::ostringstream str; ForEachInst([&str, options](const Instruction* inst) { @@ -104,6 +193,5 @@ std::string Function::PrettyPrint(uint32_t options) const { }); return str.str(); } - } // namespace opt } // namespace spvtools diff --git a/third_party/spirv-tools/source/opt/function.h b/third_party/spirv-tools/source/opt/function.h index 4dc5d25a69..3908568239 100644 --- a/third_party/spirv-tools/source/opt/function.h +++ b/third_party/spirv-tools/source/opt/function.h @@ -104,27 +104,48 @@ class Function { }); } - // Runs the given function |f| on each instruction in this function, and - // optionally on debug line instructions that might precede them. + // Runs the given function |f| on instructions in this function, in order, + // and optionally on debug line instructions that might precede them. void ForEachInst(const std::function& f, bool run_on_debug_line_insts = false); void ForEachInst(const std::function& f, bool run_on_debug_line_insts = false) const; + // Runs the given function |f| on instructions in this function, in order, + // and optionally on debug line instructions that might precede them. + // If |f| returns false, iteration is terminated and this function returns + // false. + bool WhileEachInst(const std::function& f, + bool run_on_debug_line_insts = false); + bool WhileEachInst(const std::function& f, + bool run_on_debug_line_insts = false) const; // Runs the given function |f| on each parameter instruction in this function, - // and optionally on debug line instructions that might precede them. + // in order, and optionally on debug line instructions that might precede + // them. void ForEachParam(const std::function& f, bool run_on_debug_line_insts = false) const; + void ForEachParam(const std::function& f, + bool run_on_debug_line_insts = false); BasicBlock* InsertBasicBlockAfter(std::unique_ptr&& new_block, BasicBlock* position); + BasicBlock* InsertBasicBlockBefore(std::unique_ptr&& new_block, + BasicBlock* position); + + // Return true if the function calls itself either directly or indirectly. + bool IsRecursive() const; + // Pretty-prints all the basic blocks in this function into a std::string. // // |options| are the disassembly options. SPV_BINARY_TO_TEXT_OPTION_NO_HEADER // is always added to |options|. std::string PrettyPrint(uint32_t options = 0u) const; + // Dump this function on stderr. Useful when running interactive + // debuggers. + void Dump() const; + private: // The OpFunction instruction that begins the definition of this function. std::unique_ptr def_inst_; diff --git a/third_party/spirv-tools/source/opt/generate_webgpu_initializers_pass.cpp b/third_party/spirv-tools/source/opt/generate_webgpu_initializers_pass.cpp new file mode 100644 index 0000000000..eaed3c28e2 --- /dev/null +++ b/third_party/spirv-tools/source/opt/generate_webgpu_initializers_pass.cpp @@ -0,0 +1,116 @@ +// Copyright (c) 2019 Google LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/opt/generate_webgpu_initializers_pass.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace opt { + +using inst_iterator = InstructionList::iterator; + +namespace { + +bool NeedsWebGPUInitializer(Instruction* inst) { + if (inst->opcode() != SpvOpVariable) return false; + + auto storage_class = inst->GetSingleWordOperand(2); + if (storage_class != SpvStorageClassOutput && + storage_class != SpvStorageClassPrivate && + storage_class != SpvStorageClassFunction) { + return false; + } + + if (inst->NumOperands() > 3) return false; + + return true; +} + +} // namespace + +Pass::Status GenerateWebGPUInitializersPass::Process() { + auto* module = context()->module(); + bool changed = false; + + // Handle global/module scoped variables + for (auto iter = module->types_values_begin(); + iter != module->types_values_end(); ++iter) { + Instruction* inst = &(*iter); + + if (inst->opcode() == SpvOpConstantNull) { + null_constant_type_map_[inst->type_id()] = inst; + seen_null_constants_.insert(inst); + continue; + } + + if (!NeedsWebGPUInitializer(inst)) continue; + + changed = true; + + auto* constant_inst = GetNullConstantForVariable(inst); + if (!constant_inst) return Status::Failure; + + if (seen_null_constants_.find(constant_inst) == + seen_null_constants_.end()) { + constant_inst->InsertBefore(inst); + null_constant_type_map_[inst->type_id()] = inst; + seen_null_constants_.insert(inst); + } + AddNullInitializerToVariable(constant_inst, inst); + } + + // Handle local/function scoped variables + for (auto func = module->begin(); func != module->end(); ++func) { + auto block = func->entry().get(); + for (auto iter = block->begin(); + iter != block->end() && iter->opcode() == SpvOpVariable; ++iter) { + Instruction* inst = &(*iter); + if (!NeedsWebGPUInitializer(inst)) continue; + + changed = true; + auto* constant_inst = GetNullConstantForVariable(inst); + if (!constant_inst) return Status::Failure; + + AddNullInitializerToVariable(constant_inst, inst); + } + } + + return changed ? Status::SuccessWithChange : Status::SuccessWithoutChange; +} + +Instruction* GenerateWebGPUInitializersPass::GetNullConstantForVariable( + Instruction* variable_inst) { + auto constant_mgr = context()->get_constant_mgr(); + auto* def_use_mgr = get_def_use_mgr(); + + auto* ptr_inst = def_use_mgr->GetDef(variable_inst->type_id()); + auto type_id = ptr_inst->GetInOperand(1).words[0]; + if (null_constant_type_map_.find(type_id) == null_constant_type_map_.end()) { + auto* constant_type = context()->get_type_mgr()->GetType(type_id); + auto* constant = constant_mgr->GetConstant(constant_type, {}); + return constant_mgr->GetDefiningInstruction(constant, type_id); + } else { + return null_constant_type_map_[type_id]; + } +} + +void GenerateWebGPUInitializersPass::AddNullInitializerToVariable( + Instruction* constant_inst, Instruction* variable_inst) { + auto constant_id = constant_inst->result_id(); + variable_inst->AddOperand(Operand(SPV_OPERAND_TYPE_ID, {constant_id})); + get_def_use_mgr()->AnalyzeInstUse(variable_inst); +} + +} // namespace opt +} // namespace spvtools diff --git a/third_party/spirv-tools/source/opt/generate_webgpu_initializers_pass.h b/third_party/spirv-tools/source/opt/generate_webgpu_initializers_pass.h new file mode 100644 index 0000000000..f95e84c5b0 --- /dev/null +++ b/third_party/spirv-tools/source/opt/generate_webgpu_initializers_pass.h @@ -0,0 +1,62 @@ +// Copyright (c) 2019 Google LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_OPT_GENERATE_WEBGPU_INITIALIZERS_PASS_H_ +#define SOURCE_OPT_GENERATE_WEBGPU_INITIALIZERS_PASS_H_ + +#include "source/opt/ir_context.h" +#include "source/opt/module.h" +#include "source/opt/pass.h" + +namespace spvtools { +namespace opt { + +// Adds initializers to variables with storage classes Output, Private, and +// Function if they are missing. In the WebGPU environment these storage classes +// require that the variables are initialized. Currently they are initialized to +// NULL, though in the future some of them may be initialized to the first value +// that is stored in them, if that was a constant. +class GenerateWebGPUInitializersPass : public Pass { + public: + const char* name() const override { return "generate-webgpu-initializers"; } + Status Process() override; + + IRContext::Analysis GetPreservedAnalyses() override { + return IRContext::kAnalysisInstrToBlockMapping | + IRContext::kAnalysisDecorations | IRContext::kAnalysisCombinators | + IRContext::kAnalysisCFG | IRContext::kAnalysisDominatorAnalysis | + IRContext::kAnalysisLoopAnalysis | IRContext::kAnalysisNameMap | + IRContext::kAnalysisScalarEvolution | + IRContext::kAnalysisRegisterPressure | + IRContext::kAnalysisValueNumberTable | + IRContext::kAnalysisStructuredCFG | + IRContext::kAnalysisBuiltinVarId | + IRContext::kAnalysisIdToFuncMapping | IRContext::kAnalysisTypes | + IRContext::kAnalysisDefUse | IRContext::kAnalysisConstants; + } + + private: + using NullConstantTypeMap = std::unordered_map; + NullConstantTypeMap null_constant_type_map_; + std::unordered_set seen_null_constants_; + + Instruction* GetNullConstantForVariable(Instruction* variable_inst); + void AddNullInitializerToVariable(Instruction* constant_inst, + Instruction* variable_inst); +}; + +} // namespace opt +} // namespace spvtools + +#endif // SOURCE_OPT_GENERATE_WEBGPU_INITIALIZERS_PASS_H_ diff --git a/third_party/spirv-tools/source/opt/graphics_robust_access_pass.cpp b/third_party/spirv-tools/source/opt/graphics_robust_access_pass.cpp new file mode 100644 index 0000000000..22c979cf3a --- /dev/null +++ b/third_party/spirv-tools/source/opt/graphics_robust_access_pass.cpp @@ -0,0 +1,1053 @@ +// Copyright (c) 2019 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. + +// This pass injects code in a graphics shader to implement guarantees +// satisfying Vulkan's robustBufferAcces rules. Robust access rules permit +// an out-of-bounds access to be redirected to an access of the same type +// (load, store, etc.) but within the same root object. +// +// We assume baseline functionality in Vulkan, i.e. the module uses +// logical addressing mode, without VK_KHR_variable_pointers. +// +// - Logical addressing mode implies: +// - Each root pointer (a pointer that exists other than by the +// execution of a shader instruction) is the result of an OpVariable. +// +// - Instructions that result in pointers are: +// OpVariable +// OpAccessChain +// OpInBoundsAccessChain +// OpFunctionParameter +// OpImageTexelPointer +// OpCopyObject +// +// - Instructions that use a pointer are: +// OpLoad +// OpStore +// OpAccessChain +// OpInBoundsAccessChain +// OpFunctionCall +// OpImageTexelPointer +// OpCopyMemory +// OpCopyObject +// all OpAtomic* instructions +// +// We classify pointer-users into: +// - Accesses: +// - OpLoad +// - OpStore +// - OpAtomic* +// - OpCopyMemory +// +// - Address calculations: +// - OpAccessChain +// - OpInBoundsAccessChain +// +// - Pass-through: +// - OpFunctionCall +// - OpFunctionParameter +// - OpCopyObject +// +// The strategy is: +// +// - Handle only logical addressing mode. In particular, don't handle a module +// if it uses one of the variable-pointers capabilities. +// +// - Don't handle modules using capability RuntimeDescriptorArrayEXT. So the +// only runtime arrays are those that are the last member in a +// Block-decorated struct. This allows us to feasibly/easily compute the +// length of the runtime array. See below. +// +// - The memory locations accessed by OpLoad, OpStore, OpCopyMemory, and +// OpAtomic* are determined by their pointer parameter or parameters. +// Pointers are always (correctly) typed and so the address and number of +// consecutive locations are fully determined by the pointer. +// +// - A pointer value orginates as one of few cases: +// +// - OpVariable for an interface object or an array of them: image, +// buffer (UBO or SSBO), sampler, sampled-image, push-constant, input +// variable, output variable. The execution environment is responsible for +// allocating the correct amount of storage for these, and for ensuring +// each resource bound to such a variable is big enough to contain the +// SPIR-V pointee type of the variable. +// +// - OpVariable for a non-interface object. These are variables in +// Workgroup, Private, and Function storage classes. The compiler ensures +// the underlying allocation is big enough to store the entire SPIR-V +// pointee type of the variable. +// +// - An OpFunctionParameter. This always maps to a pointer parameter to an +// OpFunctionCall. +// +// - In logical addressing mode, these are severely limited: +// "Any pointer operand to an OpFunctionCall must be: +// - a memory object declaration, or +// - a pointer to an element in an array that is a memory object +// declaration, where the element type is OpTypeSampler or OpTypeImage" +// +// - This has an important simplifying consequence: +// +// - When looking for a pointer to the structure containing a runtime +// array, you begin with a pointer to the runtime array and trace +// backward in the function. You never have to trace back beyond +// your function call boundary. So you can't take a partial access +// chain into an SSBO, then pass that pointer into a function. So +// we don't resort to using fat pointers to compute array length. +// We can trace back to a pointer to the containing structure, +// and use that in an OpArrayLength instruction. (The structure type +// gives us the member index of the runtime array.) +// +// - Otherwise, the pointer type fully encodes the range of valid +// addresses. In particular, the type of a pointer to an aggregate +// value fully encodes the range of indices when indexing into +// that aggregate. +// +// - The pointer is the result of an access chain instruction. We clamp +// indices contributing to address calculations. As noted above, the +// valid ranges are either bound by the length of a runtime array, or +// by the type of the base pointer. The length of a runtime array is +// the result of an OpArrayLength instruction acting on the pointer of +// the containing structure as noted above. +// +// - Access chain indices are always treated as signed, so: +// - Clamp the upper bound at the signed integer maximum. +// - Use SClamp for all clamping. +// +// - TODO(dneto): OpImageTexelPointer: +// - Clamp coordinate to the image size returned by OpImageQuerySize +// - If multi-sampled, clamp the sample index to the count returned by +// OpImageQuerySamples. +// - If not multi-sampled, set the sample index to 0. +// +// - Rely on the external validator to check that pointers are only +// used by the instructions as above. +// +// - Handles OpTypeRuntimeArray +// Track pointer back to original resource (pointer to struct), so we can +// query the runtime array size. +// + +#include "graphics_robust_access_pass.h" + +#include +#include +#include +#include +#include +#include + +#include "constants.h" +#include "def_use_manager.h" +#include "function.h" +#include "ir_context.h" +#include "module.h" +#include "pass.h" +#include "source/diagnostic.h" +#include "source/util/make_unique.h" +#include "spirv-tools/libspirv.h" +#include "spirv/unified1/GLSL.std.450.h" +#include "spirv/unified1/spirv.h" +#include "type_manager.h" +#include "types.h" + +namespace spvtools { +namespace opt { + +using opt::Instruction; +using opt::Operand; +using spvtools::MakeUnique; + +GraphicsRobustAccessPass::GraphicsRobustAccessPass() : module_status_() {} + +Pass::Status GraphicsRobustAccessPass::Process() { + module_status_ = PerModuleState(); + + ProcessCurrentModule(); + + auto result = module_status_.failed + ? Status::Failure + : (module_status_.modified ? Status::SuccessWithChange + : Status::SuccessWithoutChange); + + return result; +} + +spvtools::DiagnosticStream GraphicsRobustAccessPass::Fail() { + module_status_.failed = true; + // We don't really have a position, and we'll ignore the result. + return std::move( + spvtools::DiagnosticStream({}, consumer(), "", SPV_ERROR_INVALID_BINARY) + << name() << ": "); +} + +spv_result_t GraphicsRobustAccessPass::IsCompatibleModule() { + auto* feature_mgr = context()->get_feature_mgr(); + if (!feature_mgr->HasCapability(SpvCapabilityShader)) + return Fail() << "Can only process Shader modules"; + if (feature_mgr->HasCapability(SpvCapabilityVariablePointers)) + return Fail() << "Can't process modules with VariablePointers capability"; + if (feature_mgr->HasCapability(SpvCapabilityVariablePointersStorageBuffer)) + return Fail() << "Can't process modules with VariablePointersStorageBuffer " + "capability"; + if (feature_mgr->HasCapability(SpvCapabilityRuntimeDescriptorArrayEXT)) { + // These have a RuntimeArray outside of Block-decorated struct. There + // is no way to compute the array length from within SPIR-V. + return Fail() << "Can't process modules with RuntimeDescriptorArrayEXT " + "capability"; + } + + { + auto* inst = context()->module()->GetMemoryModel(); + const auto addressing_model = inst->GetSingleWordOperand(0); + if (addressing_model != SpvAddressingModelLogical) + return Fail() << "Addressing model must be Logical. Found " + << inst->PrettyPrint(); + } + return SPV_SUCCESS; +} + +spv_result_t GraphicsRobustAccessPass::ProcessCurrentModule() { + auto err = IsCompatibleModule(); + if (err != SPV_SUCCESS) return err; + + ProcessFunction fn = [this](opt::Function* f) { return ProcessAFunction(f); }; + module_status_.modified |= context()->ProcessReachableCallTree(fn); + + // Need something here. It's the price we pay for easier failure paths. + return SPV_SUCCESS; +} + +bool GraphicsRobustAccessPass::ProcessAFunction(opt::Function* function) { + // Ensure that all pointers computed inside a function are within bounds. + // Find the access chains in this block before trying to modify them. + std::vector access_chains; + std::vector image_texel_pointers; + for (auto& block : *function) { + for (auto& inst : block) { + switch (inst.opcode()) { + case SpvOpAccessChain: + case SpvOpInBoundsAccessChain: + access_chains.push_back(&inst); + break; + case SpvOpImageTexelPointer: + image_texel_pointers.push_back(&inst); + break; + default: + break; + } + } + } + for (auto* inst : access_chains) { + ClampIndicesForAccessChain(inst); + if (module_status_.failed) return module_status_.modified; + } + + for (auto* inst : image_texel_pointers) { + if (SPV_SUCCESS != ClampCoordinateForImageTexelPointer(inst)) break; + } + return module_status_.modified; +} + +void GraphicsRobustAccessPass::ClampIndicesForAccessChain( + Instruction* access_chain) { + Instruction& inst = *access_chain; + + auto* constant_mgr = context()->get_constant_mgr(); + auto* def_use_mgr = context()->get_def_use_mgr(); + auto* type_mgr = context()->get_type_mgr(); + const bool have_int64_cap = + context()->get_feature_mgr()->HasCapability(SpvCapabilityInt64); + + // Replaces one of the OpAccessChain index operands with a new value. + // Updates def-use analysis. + auto replace_index = [&inst, def_use_mgr](uint32_t operand_index, + Instruction* new_value) { + inst.SetOperand(operand_index, {new_value->result_id()}); + def_use_mgr->AnalyzeInstUse(&inst); + return SPV_SUCCESS; + }; + + // Replaces one of the OpAccesssChain index operands with a clamped value. + // Replace the operand at |operand_index| with the value computed from + // signed_clamp(%old_value, %min_value, %max_value). It also analyzes + // the new instruction and records that them module is modified. + // Assumes %min_value is signed-less-or-equal than %max_value. (All callees + // use 0 for %min_value). + auto clamp_index = [&inst, type_mgr, this, &replace_index]( + uint32_t operand_index, Instruction* old_value, + Instruction* min_value, Instruction* max_value) { + auto* clamp_inst = + MakeSClampInst(*type_mgr, old_value, min_value, max_value, &inst); + return replace_index(operand_index, clamp_inst); + }; + + // Ensures the specified index of access chain |inst| has a value that is + // at most |count| - 1. If the index is already a constant value less than + // |count| then no change is made. + auto clamp_to_literal_count = + [&inst, this, &constant_mgr, &type_mgr, have_int64_cap, &replace_index, + &clamp_index](uint32_t operand_index, uint64_t count) -> spv_result_t { + Instruction* index_inst = + this->GetDef(inst.GetSingleWordOperand(operand_index)); + const auto* index_type = + type_mgr->GetType(index_inst->type_id())->AsInteger(); + assert(index_type); + const auto index_width = index_type->width(); + + if (count <= 1) { + // Replace the index with 0. + return replace_index(operand_index, GetValueForType(0, index_type)); + } + + uint64_t maxval = count - 1; + + // Compute the bit width of a viable type to hold |maxval|. + // Look for a bit width, up to 64 bits wide, to fit maxval. + uint32_t maxval_width = index_width; + while ((maxval_width < 64) && (0 != (maxval >> maxval_width))) { + maxval_width *= 2; + } + // Determine the type for |maxval|. + analysis::Integer signed_type_for_query(maxval_width, true); + auto* maxval_type = + type_mgr->GetRegisteredType(&signed_type_for_query)->AsInteger(); + // Access chain indices are treated as signed, so limit the maximum value + // of the index so it will always be positive for a signed clamp operation. + maxval = std::min(maxval, ((uint64_t(1) << (maxval_width - 1)) - 1)); + + if (index_width > 64) { + return this->Fail() << "Can't handle indices wider than 64 bits, found " + "constant index with " + << index_width << " bits as index number " + << operand_index << " of access chain " + << inst.PrettyPrint(); + } + + // Split into two cases: the current index is a constant, or not. + + // If the index is a constant then |index_constant| will not be a null + // pointer. (If index is an |OpConstantNull| then it |index_constant| will + // not be a null pointer.) Since access chain indices must be scalar + // integers, this can't be a spec constant. + if (auto* index_constant = constant_mgr->GetConstantFromInst(index_inst)) { + auto* int_index_constant = index_constant->AsIntConstant(); + int64_t value = 0; + // OpAccessChain indices are treated as signed. So get the signed + // constant value here. + if (index_width <= 32) { + value = int64_t(int_index_constant->GetS32BitValue()); + } else if (index_width <= 64) { + value = int_index_constant->GetS64BitValue(); + } + if (value < 0) { + return replace_index(operand_index, GetValueForType(0, index_type)); + } else if (uint64_t(value) <= maxval) { + // Nothing to do. + return SPV_SUCCESS; + } else { + // Replace with maxval. + assert(count > 0); // Already took care of this case above. + return replace_index(operand_index, + GetValueForType(maxval, maxval_type)); + } + } else { + // Generate a clamp instruction. + assert(maxval >= 1); + assert(index_width <= 64); // Otherwise, already returned above. + if (index_width >= 64 && !have_int64_cap) { + // An inconsistent module. + return Fail() << "Access chain index is wider than 64 bits, but Int64 " + "is not declared: " + << index_inst->PrettyPrint(); + } + // Widen the index value if necessary + if (maxval_width > index_width) { + // Find the wider type. We only need this case if a constant array + // bound is too big. + + // From how we calculated maxval_width, widening won't require adding + // the Int64 capability. + assert(have_int64_cap || maxval_width <= 32); + if (!have_int64_cap && maxval_width >= 64) { + // Be defensive, but this shouldn't happen. + return this->Fail() + << "Clamping index would require adding Int64 capability. " + << "Can't clamp 32-bit index " << operand_index + << " of access chain " << inst.PrettyPrint(); + } + index_inst = WidenInteger(index_type->IsSigned(), maxval_width, + index_inst, &inst); + } + + // Finally, clamp the index. + return clamp_index(operand_index, index_inst, + GetValueForType(0, maxval_type), + GetValueForType(maxval, maxval_type)); + } + return SPV_SUCCESS; + }; + + // Ensures the specified index of access chain |inst| has a value that is at + // most the value of |count_inst| minus 1, where |count_inst| is treated as an + // unsigned integer. This can log a failure. + auto clamp_to_count = [&inst, this, &constant_mgr, &clamp_to_literal_count, + &clamp_index, + &type_mgr](uint32_t operand_index, + Instruction* count_inst) -> spv_result_t { + Instruction* index_inst = + this->GetDef(inst.GetSingleWordOperand(operand_index)); + const auto* index_type = + type_mgr->GetType(index_inst->type_id())->AsInteger(); + const auto* count_type = + type_mgr->GetType(count_inst->type_id())->AsInteger(); + assert(index_type); + if (const auto* count_constant = + constant_mgr->GetConstantFromInst(count_inst)) { + uint64_t value = 0; + const auto width = count_constant->type()->AsInteger()->width(); + if (width <= 32) { + value = count_constant->AsIntConstant()->GetU32BitValue(); + } else if (width <= 64) { + value = count_constant->AsIntConstant()->GetU64BitValue(); + } else { + return this->Fail() << "Can't handle indices wider than 64 bits, found " + "constant index with " + << index_type->width() << "bits"; + } + return clamp_to_literal_count(operand_index, value); + } else { + // Widen them to the same width. + const auto index_width = index_type->width(); + const auto count_width = count_type->width(); + const auto target_width = std::max(index_width, count_width); + // UConvert requires the result type to have 0 signedness. So enforce + // that here. + auto* wider_type = index_width < count_width ? count_type : index_type; + if (index_type->width() < target_width) { + // Access chain indices are treated as signed integers. + index_inst = WidenInteger(true, target_width, index_inst, &inst); + } else if (count_type->width() < target_width) { + // Assume type sizes are treated as unsigned. + count_inst = WidenInteger(false, target_width, count_inst, &inst); + } + // Compute count - 1. + // It doesn't matter if 1 is signed or unsigned. + auto* one = GetValueForType(1, wider_type); + auto* count_minus_1 = InsertInst( + &inst, SpvOpISub, type_mgr->GetId(wider_type), TakeNextId(), + {{SPV_OPERAND_TYPE_ID, {count_inst->result_id()}}, + {SPV_OPERAND_TYPE_ID, {one->result_id()}}}); + auto* zero = GetValueForType(0, wider_type); + // Make sure we clamp to an upper bound that is at most the signed max + // for the target type. + const uint64_t max_signed_value = + ((uint64_t(1) << (target_width - 1)) - 1); + // Use unsigned-min to ensure that the result is always non-negative. + // That ensures we satisfy the invariant for SClamp, where the "min" + // argument we give it (zero), is no larger than the third argument. + auto* upper_bound = + MakeUMinInst(*type_mgr, count_minus_1, + GetValueForType(max_signed_value, wider_type), &inst); + // Now clamp the index to this upper bound. + return clamp_index(operand_index, index_inst, zero, upper_bound); + } + return SPV_SUCCESS; + }; + + const Instruction* base_inst = GetDef(inst.GetSingleWordInOperand(0)); + const Instruction* base_type = GetDef(base_inst->type_id()); + Instruction* pointee_type = GetDef(base_type->GetSingleWordInOperand(1)); + + // Walk the indices from earliest to latest, replacing indices with a + // clamped value, and updating the pointee_type. The order matters for + // the case when we have to compute the length of a runtime array. In + // that the algorithm relies on the fact that that the earlier indices + // have already been clamped. + const uint32_t num_operands = inst.NumOperands(); + for (uint32_t idx = 3; !module_status_.failed && idx < num_operands; ++idx) { + const uint32_t index_id = inst.GetSingleWordOperand(idx); + Instruction* index_inst = GetDef(index_id); + + switch (pointee_type->opcode()) { + case SpvOpTypeMatrix: // Use column count + case SpvOpTypeVector: // Use component count + { + const uint32_t count = pointee_type->GetSingleWordOperand(2); + clamp_to_literal_count(idx, count); + pointee_type = GetDef(pointee_type->GetSingleWordOperand(1)); + } break; + + case SpvOpTypeArray: { + // The array length can be a spec constant, so go through the general + // case. + Instruction* array_len = GetDef(pointee_type->GetSingleWordOperand(2)); + clamp_to_count(idx, array_len); + pointee_type = GetDef(pointee_type->GetSingleWordOperand(1)); + } break; + + case SpvOpTypeStruct: { + // SPIR-V requires the index to be an OpConstant. + // We need to know the index literal value so we can compute the next + // pointee type. + if (index_inst->opcode() != SpvOpConstant || + !constant_mgr->GetConstantFromInst(index_inst) + ->type() + ->AsInteger()) { + Fail() << "Member index into struct is not a constant integer: " + << index_inst->PrettyPrint( + SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES) + << "\nin access chain: " + << inst.PrettyPrint(SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES); + return; + } + const auto num_members = pointee_type->NumInOperands(); + const auto* index_constant = + constant_mgr->GetConstantFromInst(index_inst); + // Get the sign-extended value, since access index is always treated as + // signed. + const auto index_value = index_constant->GetSignExtendedValue(); + if (index_value < 0 || index_value >= num_members) { + Fail() << "Member index " << index_value + << " is out of bounds for struct type: " + << pointee_type->PrettyPrint( + SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES) + << "\nin access chain: " + << inst.PrettyPrint(SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES); + return; + } + pointee_type = GetDef(pointee_type->GetSingleWordInOperand( + static_cast(index_value))); + // No need to clamp this index. We just checked that it's valid. + } break; + + case SpvOpTypeRuntimeArray: { + auto* array_len = MakeRuntimeArrayLengthInst(&inst, idx); + if (!array_len) { // We've already signaled an error. + return; + } + clamp_to_count(idx, array_len); + if (module_status_.failed) return; + pointee_type = GetDef(pointee_type->GetSingleWordOperand(1)); + } break; + + default: + Fail() << " Unhandled pointee type for access chain " + << pointee_type->PrettyPrint( + SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES); + } + } +} + +uint32_t GraphicsRobustAccessPass::GetGlslInsts() { + if (module_status_.glsl_insts_id == 0) { + // This string serves double-duty as raw data for a string and for a vector + // of 32-bit words + const char glsl[] = "GLSL.std.450\0\0\0\0"; + const size_t glsl_str_byte_len = 16; + // Use an existing import if we can. + for (auto& inst : context()->module()->ext_inst_imports()) { + const auto& name_words = inst.GetInOperand(0).words; + if (0 == std::strncmp(reinterpret_cast(name_words.data()), + glsl, glsl_str_byte_len)) { + module_status_.glsl_insts_id = inst.result_id(); + } + } + if (module_status_.glsl_insts_id == 0) { + // Make a new import instruction. + module_status_.glsl_insts_id = TakeNextId(); + std::vector words(glsl_str_byte_len / sizeof(uint32_t)); + std::memcpy(words.data(), glsl, glsl_str_byte_len); + auto import_inst = MakeUnique( + context(), SpvOpExtInstImport, 0, module_status_.glsl_insts_id, + std::initializer_list{ + Operand{SPV_OPERAND_TYPE_LITERAL_STRING, std::move(words)}}); + Instruction* inst = import_inst.get(); + context()->module()->AddExtInstImport(std::move(import_inst)); + module_status_.modified = true; + context()->AnalyzeDefUse(inst); + // Reanalyze the feature list, since we added an extended instruction + // set improt. + context()->get_feature_mgr()->Analyze(context()->module()); + } + } + return module_status_.glsl_insts_id; +} + +opt::Instruction* opt::GraphicsRobustAccessPass::GetValueForType( + uint64_t value, const analysis::Integer* type) { + auto* mgr = context()->get_constant_mgr(); + assert(type->width() <= 64); + std::vector words; + words.push_back(uint32_t(value)); + if (type->width() > 32) { + words.push_back(uint32_t(value >> 32u)); + } + const auto* constant = mgr->GetConstant(type, words); + return mgr->GetDefiningInstruction( + constant, context()->get_type_mgr()->GetTypeInstruction(type)); +} + +opt::Instruction* opt::GraphicsRobustAccessPass::WidenInteger( + bool sign_extend, uint32_t bit_width, Instruction* value, + Instruction* before_inst) { + analysis::Integer unsigned_type_for_query(bit_width, false); + auto* type_mgr = context()->get_type_mgr(); + auto* unsigned_type = type_mgr->GetRegisteredType(&unsigned_type_for_query); + auto type_id = context()->get_type_mgr()->GetId(unsigned_type); + auto conversion_id = TakeNextId(); + auto* conversion = InsertInst( + before_inst, (sign_extend ? SpvOpSConvert : SpvOpUConvert), type_id, + conversion_id, {{SPV_OPERAND_TYPE_ID, {value->result_id()}}}); + return conversion; +} + +Instruction* GraphicsRobustAccessPass::MakeUMinInst( + const analysis::TypeManager& tm, Instruction* x, Instruction* y, + Instruction* where) { + // Get IDs of instructions we'll be referencing. Evaluate them before calling + // the function so we force a deterministic ordering in case both of them need + // to take a new ID. + const uint32_t glsl_insts_id = GetGlslInsts(); + uint32_t smin_id = TakeNextId(); + const auto xwidth = tm.GetType(x->type_id())->AsInteger()->width(); + const auto ywidth = tm.GetType(y->type_id())->AsInteger()->width(); + assert(xwidth == ywidth); + (void)xwidth; + (void)ywidth; + auto* smin_inst = InsertInst( + where, SpvOpExtInst, x->type_id(), smin_id, + { + {SPV_OPERAND_TYPE_ID, {glsl_insts_id}}, + {SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER, {GLSLstd450UMin}}, + {SPV_OPERAND_TYPE_ID, {x->result_id()}}, + {SPV_OPERAND_TYPE_ID, {y->result_id()}}, + }); + return smin_inst; +} + +Instruction* GraphicsRobustAccessPass::MakeSClampInst( + const analysis::TypeManager& tm, Instruction* x, Instruction* min, + Instruction* max, Instruction* where) { + // Get IDs of instructions we'll be referencing. Evaluate them before calling + // the function so we force a deterministic ordering in case both of them need + // to take a new ID. + const uint32_t glsl_insts_id = GetGlslInsts(); + uint32_t clamp_id = TakeNextId(); + const auto xwidth = tm.GetType(x->type_id())->AsInteger()->width(); + const auto minwidth = tm.GetType(min->type_id())->AsInteger()->width(); + const auto maxwidth = tm.GetType(max->type_id())->AsInteger()->width(); + assert(xwidth == minwidth); + assert(xwidth == maxwidth); + (void)xwidth; + (void)minwidth; + (void)maxwidth; + auto* clamp_inst = InsertInst( + where, SpvOpExtInst, x->type_id(), clamp_id, + { + {SPV_OPERAND_TYPE_ID, {glsl_insts_id}}, + {SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER, {GLSLstd450SClamp}}, + {SPV_OPERAND_TYPE_ID, {x->result_id()}}, + {SPV_OPERAND_TYPE_ID, {min->result_id()}}, + {SPV_OPERAND_TYPE_ID, {max->result_id()}}, + }); + return clamp_inst; +} + +Instruction* GraphicsRobustAccessPass::MakeRuntimeArrayLengthInst( + Instruction* access_chain, uint32_t operand_index) { + // The Index parameter to the access chain at |operand_index| is indexing + // *into* the runtime-array. To get the number of elements in the runtime + // array we need a pointer to the Block-decorated struct that contains the + // runtime array. So conceptually we have to go 2 steps backward in the + // access chain. The two steps backward might forces us to traverse backward + // across multiple dominating instructions. + auto* type_mgr = context()->get_type_mgr(); + + // How many access chain indices do we have to unwind to find the pointer + // to the struct containing the runtime array? + uint32_t steps_remaining = 2; + // Find or create an instruction computing the pointer to the structure + // containing the runtime array. + // Walk backward through pointer address calculations until we either get + // to exactly the right base pointer, or to an access chain instruction + // that we can replicate but truncate to compute the address of the right + // struct. + Instruction* current_access_chain = access_chain; + Instruction* pointer_to_containing_struct = nullptr; + while (steps_remaining > 0) { + switch (current_access_chain->opcode()) { + case SpvOpCopyObject: + // Whoops. Walk right through this one. + current_access_chain = + GetDef(current_access_chain->GetSingleWordInOperand(0)); + break; + case SpvOpAccessChain: + case SpvOpInBoundsAccessChain: { + const int first_index_operand = 3; + // How many indices in this access chain contribute to getting us + // to an element in the runtime array? + const auto num_contributing_indices = + current_access_chain == access_chain + ? operand_index - (first_index_operand - 1) + : current_access_chain->NumInOperands() - 1 /* skip the base */; + Instruction* base = + GetDef(current_access_chain->GetSingleWordInOperand(0)); + if (num_contributing_indices == steps_remaining) { + // The base pointer points to the structure. + pointer_to_containing_struct = base; + steps_remaining = 0; + break; + } else if (num_contributing_indices < steps_remaining) { + // Peel off the index and keep going backward. + steps_remaining -= num_contributing_indices; + current_access_chain = base; + } else { + // This access chain has more indices than needed. Generate a new + // access chain instruction, but truncating the list of indices. + const int base_operand = 2; + // We'll use the base pointer and the indices up to but not including + // the one indexing into the runtime array. + Instruction::OperandList ops; + // Use the base pointer + ops.push_back(current_access_chain->GetOperand(base_operand)); + const uint32_t num_indices_to_keep = + num_contributing_indices - steps_remaining - 1; + for (uint32_t i = 0; i <= num_indices_to_keep; i++) { + ops.push_back( + current_access_chain->GetOperand(first_index_operand + i)); + } + // Compute the type of the result of the new access chain. Start at + // the base and walk the indices in a forward direction. + auto* constant_mgr = context()->get_constant_mgr(); + std::vector indices_for_type; + for (uint32_t i = 0; i < ops.size() - 1; i++) { + uint32_t index_for_type_calculation = 0; + Instruction* index = + GetDef(current_access_chain->GetSingleWordOperand( + first_index_operand + i)); + if (auto* index_constant = + constant_mgr->GetConstantFromInst(index)) { + // We only need 32 bits. For the type calculation, it's sufficient + // to take the zero-extended value. It only matters for the struct + // case, and struct member indices are unsigned. + index_for_type_calculation = + uint32_t(index_constant->GetZeroExtendedValue()); + } else { + // Indexing into a variably-sized thing like an array. Use 0. + index_for_type_calculation = 0; + } + indices_for_type.push_back(index_for_type_calculation); + } + auto* base_ptr_type = type_mgr->GetType(base->type_id())->AsPointer(); + auto* base_pointee_type = base_ptr_type->pointee_type(); + auto* new_access_chain_result_pointee_type = + type_mgr->GetMemberType(base_pointee_type, indices_for_type); + const uint32_t new_access_chain_type_id = type_mgr->FindPointerToType( + type_mgr->GetId(new_access_chain_result_pointee_type), + base_ptr_type->storage_class()); + + // Create the instruction and insert it. + const auto new_access_chain_id = TakeNextId(); + auto* new_access_chain = + InsertInst(current_access_chain, current_access_chain->opcode(), + new_access_chain_type_id, new_access_chain_id, ops); + pointer_to_containing_struct = new_access_chain; + steps_remaining = 0; + break; + } + } break; + default: + Fail() << "Unhandled access chain in logical addressing mode passes " + "through " + << current_access_chain->PrettyPrint( + SPV_BINARY_TO_TEXT_OPTION_SHOW_BYTE_OFFSET | + SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES); + return nullptr; + } + } + assert(pointer_to_containing_struct); + auto* pointee_type = + type_mgr->GetType(pointer_to_containing_struct->type_id()) + ->AsPointer() + ->pointee_type(); + + auto* struct_type = pointee_type->AsStruct(); + const uint32_t member_index_of_runtime_array = + uint32_t(struct_type->element_types().size() - 1); + // Create the length-of-array instruction before the original access chain, + // but after the generation of the pointer to the struct. + const auto array_len_id = TakeNextId(); + analysis::Integer uint_type_for_query(32, false); + auto* uint_type = type_mgr->GetRegisteredType(&uint_type_for_query); + auto* array_len = InsertInst( + access_chain, SpvOpArrayLength, type_mgr->GetId(uint_type), array_len_id, + {{SPV_OPERAND_TYPE_ID, {pointer_to_containing_struct->result_id()}}, + {SPV_OPERAND_TYPE_LITERAL_INTEGER, {member_index_of_runtime_array}}}); + return array_len; +} + +spv_result_t GraphicsRobustAccessPass::ClampCoordinateForImageTexelPointer( + opt::Instruction* image_texel_pointer) { + // TODO(dneto): Write tests for this code. + // TODO(dneto): Use signed-clamp + return SPV_SUCCESS; + + // Example: + // %texel_ptr = OpImageTexelPointer %texel_ptr_type %image_ptr %coord + // %sample + // + // We want to clamp %coord components between vector-0 and the result + // of OpImageQuerySize acting on the underlying image. So insert: + // %image = OpLoad %image_type %image_ptr + // %query_size = OpImageQuerySize %query_size_type %image + // + // For a multi-sampled image, %sample is the sample index, and we need + // to clamp it between zero and the number of samples in the image. + // %sample_count = OpImageQuerySamples %uint %image + // %max_sample_index = OpISub %uint %sample_count %uint_1 + // For non-multi-sampled images, the sample index must be constant zero. + + auto* def_use_mgr = context()->get_def_use_mgr(); + auto* type_mgr = context()->get_type_mgr(); + auto* constant_mgr = context()->get_constant_mgr(); + + auto* image_ptr = GetDef(image_texel_pointer->GetSingleWordInOperand(0)); + auto* image_ptr_type = GetDef(image_ptr->type_id()); + auto image_type_id = image_ptr_type->GetSingleWordInOperand(1); + auto* image_type = GetDef(image_type_id); + auto* coord = GetDef(image_texel_pointer->GetSingleWordInOperand(1)); + auto* samples = GetDef(image_texel_pointer->GetSingleWordInOperand(2)); + + // We will modify the module, at least by adding image query instructions. + module_status_.modified = true; + + // Declare the ImageQuery capability if the module doesn't already have it. + auto* feature_mgr = context()->get_feature_mgr(); + if (!feature_mgr->HasCapability(SpvCapabilityImageQuery)) { + auto cap = MakeUnique( + context(), SpvOpCapability, 0, 0, + std::initializer_list{ + {SPV_OPERAND_TYPE_CAPABILITY, {SpvCapabilityImageQuery}}}); + def_use_mgr->AnalyzeInstDefUse(cap.get()); + context()->AddCapability(std::move(cap)); + feature_mgr->Analyze(context()->module()); + } + + // OpImageTexelPointer is used to translate a coordinate and sample index + // into an address for use with an atomic operation. That is, it may only + // used with what Vulkan calls a "storage image" + // (OpTypeImage parameter Sampled=2). + // Note: A storage image never has a level-of-detail associated with it. + + // Constraints on the sample id: + // - Only 2D images can be multi-sampled: OpTypeImage parameter MS=1 + // only if Dim=2D. + // - Non-multi-sampled images (OpTypeImage parameter MS=0) must use + // sample ID to a constant 0. + + // The coordinate is treated as unsigned, and should be clamped against the + // image "size", returned by OpImageQuerySize. (Note: OpImageQuerySizeLod + // is only usable with a sampled image, i.e. its image type has Sampled=1). + + // Determine the result type for the OpImageQuerySize. + // For non-arrayed images: + // non-Cube: + // - Always the same as the coordinate type + // Cube: + // - Use all but the last component of the coordinate (which is the face + // index from 0 to 5). + // For arrayed images (in Vulkan the Dim is 1D, 2D, or Cube): + // non-Cube: + // - A vector with the components in the coordinate, and one more for + // the layer index. + // Cube: + // - The same as the coordinate type: 3-element integer vector. + // - The third component from the size query is the layer count. + // - The third component in the texel pointer calculation is + // 6 * layer + face, where 0 <= face < 6. + // Cube: Use all but the last component of the coordinate (which is the face + // index from 0 to 5). + const auto dim = SpvDim(image_type->GetSingleWordInOperand(1)); + const bool arrayed = image_type->GetSingleWordInOperand(3) == 1; + const bool multisampled = image_type->GetSingleWordInOperand(4) != 0; + const auto query_num_components = [dim, arrayed, this]() -> int { + const int arrayness_bonus = arrayed ? 1 : 0; + int num_coords = 0; + switch (dim) { + case SpvDimBuffer: + case SpvDim1D: + num_coords = 1; + break; + case SpvDimCube: + // For cube, we need bounds for x, y, but not face. + case SpvDimRect: + case SpvDim2D: + num_coords = 2; + break; + case SpvDim3D: + num_coords = 3; + break; + case SpvDimSubpassData: + case SpvDimMax: + return Fail() << "Invalid image dimension for OpImageTexelPointer: " + << int(dim); + break; + } + return num_coords + arrayness_bonus; + }(); + const auto* coord_component_type = [type_mgr, coord]() { + const analysis::Type* coord_type = type_mgr->GetType(coord->type_id()); + if (auto* vector_type = coord_type->AsVector()) { + return vector_type->element_type()->AsInteger(); + } + return coord_type->AsInteger(); + }(); + // For now, only handle 32-bit case for coordinates. + if (!coord_component_type) { + return Fail() << " Coordinates for OpImageTexelPointer are not integral: " + << image_texel_pointer->PrettyPrint( + SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES); + } + if (coord_component_type->width() != 32) { + return Fail() << " Expected OpImageTexelPointer coordinate components to " + "be 32-bits wide. They are " + << coord_component_type->width() << " bits. " + << image_texel_pointer->PrettyPrint( + SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES); + } + const auto* query_size_type = + [type_mgr, coord_component_type, + query_num_components]() -> const analysis::Type* { + if (query_num_components == 1) return coord_component_type; + analysis::Vector proposed(coord_component_type, query_num_components); + return type_mgr->GetRegisteredType(&proposed); + }(); + + const uint32_t image_id = TakeNextId(); + auto* image = + InsertInst(image_texel_pointer, SpvOpLoad, image_type_id, image_id, + {{SPV_OPERAND_TYPE_ID, {image_ptr->result_id()}}}); + + const uint32_t query_size_id = TakeNextId(); + auto* query_size = + InsertInst(image_texel_pointer, SpvOpImageQuerySize, + type_mgr->GetTypeInstruction(query_size_type), query_size_id, + {{SPV_OPERAND_TYPE_ID, {image->result_id()}}}); + + auto* component_1 = constant_mgr->GetConstant(coord_component_type, {1}); + const uint32_t component_1_id = + constant_mgr->GetDefiningInstruction(component_1)->result_id(); + auto* component_0 = constant_mgr->GetConstant(coord_component_type, {0}); + const uint32_t component_0_id = + constant_mgr->GetDefiningInstruction(component_0)->result_id(); + + // If the image is a cube array, then the last component of the queried + // size is the layer count. In the query, we have to accomodate folding + // in the face index ranging from 0 through 5. The inclusive upper bound + // on the third coordinate therefore is multiplied by 6. + auto* query_size_including_faces = query_size; + if (arrayed && (dim == SpvDimCube)) { + // Multiply the last coordinate by 6. + auto* component_6 = constant_mgr->GetConstant(coord_component_type, {6}); + const uint32_t component_6_id = + constant_mgr->GetDefiningInstruction(component_6)->result_id(); + assert(query_num_components == 3); + auto* multiplicand = constant_mgr->GetConstant( + query_size_type, {component_1_id, component_1_id, component_6_id}); + auto* multiplicand_inst = + constant_mgr->GetDefiningInstruction(multiplicand); + const auto query_size_including_faces_id = TakeNextId(); + query_size_including_faces = InsertInst( + image_texel_pointer, SpvOpIMul, + type_mgr->GetTypeInstruction(query_size_type), + query_size_including_faces_id, + {{SPV_OPERAND_TYPE_ID, {query_size_including_faces->result_id()}}, + {SPV_OPERAND_TYPE_ID, {multiplicand_inst->result_id()}}}); + } + + // Make a coordinate-type with all 1 components. + auto* coordinate_1 = + query_num_components == 1 + ? component_1 + : constant_mgr->GetConstant( + query_size_type, + std::vector(query_num_components, component_1_id)); + // Make a coordinate-type with all 1 components. + auto* coordinate_0 = + query_num_components == 0 + ? component_0 + : constant_mgr->GetConstant( + query_size_type, + std::vector(query_num_components, component_0_id)); + + const uint32_t query_max_including_faces_id = TakeNextId(); + auto* query_max_including_faces = InsertInst( + image_texel_pointer, SpvOpISub, + type_mgr->GetTypeInstruction(query_size_type), + query_max_including_faces_id, + {{SPV_OPERAND_TYPE_ID, {query_size_including_faces->result_id()}}, + {SPV_OPERAND_TYPE_ID, + {constant_mgr->GetDefiningInstruction(coordinate_1)->result_id()}}}); + + // Clamp the coordinate + auto* clamp_coord = MakeSClampInst( + *type_mgr, coord, constant_mgr->GetDefiningInstruction(coordinate_0), + query_max_including_faces, image_texel_pointer); + image_texel_pointer->SetInOperand(1, {clamp_coord->result_id()}); + + // Clamp the sample index + if (multisampled) { + // Get the sample count via OpImageQuerySamples + const auto query_samples_id = TakeNextId(); + auto* query_samples = InsertInst( + image_texel_pointer, SpvOpImageQuerySamples, + constant_mgr->GetDefiningInstruction(component_0)->type_id(), + query_samples_id, {{SPV_OPERAND_TYPE_ID, {image->result_id()}}}); + + const auto max_samples_id = TakeNextId(); + auto* max_samples = InsertInst(image_texel_pointer, SpvOpImageQuerySamples, + query_samples->type_id(), max_samples_id, + {{SPV_OPERAND_TYPE_ID, {query_samples_id}}, + {SPV_OPERAND_TYPE_ID, {component_1_id}}}); + + auto* clamp_samples = MakeSClampInst( + *type_mgr, samples, constant_mgr->GetDefiningInstruction(coordinate_0), + max_samples, image_texel_pointer); + image_texel_pointer->SetInOperand(2, {clamp_samples->result_id()}); + + } else { + // Just replace it with 0. Don't even check what was there before. + image_texel_pointer->SetInOperand(2, {component_0_id}); + } + + def_use_mgr->AnalyzeInstUse(image_texel_pointer); + + return SPV_SUCCESS; +} + +opt::Instruction* GraphicsRobustAccessPass::InsertInst( + opt::Instruction* where_inst, SpvOp opcode, uint32_t type_id, + uint32_t result_id, const Instruction::OperandList& operands) { + module_status_.modified = true; + auto* result = where_inst->InsertBefore( + MakeUnique(context(), opcode, type_id, result_id, operands)); + context()->get_def_use_mgr()->AnalyzeInstDefUse(result); + auto* basic_block = context()->get_instr_block(where_inst); + context()->set_instr_block(result, basic_block); + return result; +} + +} // namespace opt +} // namespace spvtools diff --git a/third_party/spirv-tools/source/opt/graphics_robust_access_pass.h b/third_party/spirv-tools/source/opt/graphics_robust_access_pass.h new file mode 100644 index 0000000000..6fc692c133 --- /dev/null +++ b/third_party/spirv-tools/source/opt/graphics_robust_access_pass.h @@ -0,0 +1,156 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_OPT_GRAPHICS_ROBUST_ACCESS_PASS_H_ +#define SOURCE_OPT_GRAPHICS_ROBUST_ACCESS_PASS_H_ + +#include +#include + +#include "constants.h" +#include "def_use_manager.h" +#include "instruction.h" +#include "module.h" +#include "pass.h" +#include "source/diagnostic.h" +#include "type_manager.h" + +namespace spvtools { +namespace opt { + +// See optimizer.hpp for documentation. +class GraphicsRobustAccessPass : public Pass { + public: + GraphicsRobustAccessPass(); + const char* name() const override { return "graphics-robust-access"; } + Status Process() override; + + IRContext::Analysis GetPreservedAnalyses() override { + return IRContext::kAnalysisDefUse | + IRContext::kAnalysisInstrToBlockMapping | + IRContext::kAnalysisConstants | IRContext::kAnalysisTypes | + IRContext::kAnalysisIdToFuncMapping; + } + + private: + // Records failure for the current module, and returns a stream + // that can be used to provide user error information to the message + // consumer. + spvtools::DiagnosticStream Fail(); + + // Returns SPV_SUCCESS if this pass can correctly process the module, + // as far as we can tell from capabilities and the memory model. + // Otherwise logs a message and returns a failure code. + spv_result_t IsCompatibleModule(); + + // Transform the current module, if possible. Failure and modification + // status is recorded in the |_| member. On failure, error information is + // posted to the message consumer. The return value has no significance. + spv_result_t ProcessCurrentModule(); + + // Process the given function. Updates the state value |_|. Returns true + // if the module was modified. This can log a failure. + bool ProcessAFunction(opt::Function*); + + // Clamps indices in the OpAccessChain or OpInBoundsAccessChain instruction + // |access_chain|. Inserts instructions before the given instruction. Updates + // analyses and records that the module is modified. This can log a failure. + void ClampIndicesForAccessChain(Instruction* access_chain); + + // Returns the id of the instruction importing the "GLSL.std.450" extended + // instruction set. If it does not yet exist, the import instruction is + // created and inserted into the module, and updates |_.modified| and + // |_.glsl_insts_id|. + uint32_t GetGlslInsts(); + + // Returns an instruction which is constant with the given value of the given + // type. Ignores any value bits beyond the width of the type. + Instruction* GetValueForType(uint64_t value, const analysis::Integer* type); + + // Converts an integer value to an unsigned wider integer type, using either + // sign extension or zero extension. The new instruction is inserted + // immediately before |before_inst|, and is analyzed for definitions and uses. + // Returns the newly inserted instruction. Assumes the |value| is an integer + // scalar of a narrower type than |bit_width| bits. + Instruction* WidenInteger(bool sign_extend, uint32_t bit_width, + Instruction* value, Instruction* before_inst); + + // Returns a new instruction that invokes the UMin GLSL.std.450 extended + // instruction with the two given operands. That is, the result of the + // instruction is: + // - |x| if |x| is unsigned-less than |y| + // - |y| otherwise + // We assume that |x| and |y| are scalar integer types with the same + // width. The instruction is inserted before |where|. + opt::Instruction* MakeUMinInst(const analysis::TypeManager& tm, + Instruction* x, Instruction* y, + Instruction* where); + + // Returns a new instruction that invokes the SClamp GLSL.std.450 extended + // instruction with the three given operands. That is, the result of the + // instruction is: + // - |min| if |x| is signed-less than |min| + // - |max| if |x| is signed-more than |max| + // - |x| otherwise. + // We assume that |min| is signed-less-or-equal to |max|, and that the + // operands all have the same scalar integer type. The instruction is + // inserted before |where|. + opt::Instruction* MakeSClampInst(const analysis::TypeManager& tm, + Instruction* x, Instruction* min, + Instruction* max, Instruction* where); + + // Returns a new instruction which evaluates to the length the runtime array + // referenced by the access chain at the specfied index. The instruction is + // inserted before the access chain instruction. Returns a null pointer in + // some cases if assumptions are violated (rather than asserting out). + opt::Instruction* MakeRuntimeArrayLengthInst(Instruction* access_chain, + uint32_t operand_index); + + // Clamps the coordinate for an OpImageTexelPointer so it stays within + // the bounds of the size of the image. Updates analyses and records that + // the module is modified. Returns a status code to indicate success + // or failure. If assumptions are not met, returns an error status code + // and emits a diagnostic. + spv_result_t ClampCoordinateForImageTexelPointer( + opt::Instruction* image_texel_pointer); + + // Gets the instruction that defines the given id. + opt::Instruction* GetDef(uint32_t id) { + return context()->get_def_use_mgr()->GetDef(id); + } + + // Returns a new instruction inserted before |where_inst|, and created from + // the remaining arguments. Registers the definitions and uses of the new + // instruction and also records its block. + opt::Instruction* InsertInst(opt::Instruction* where_inst, SpvOp opcode, + uint32_t type_id, uint32_t result_id, + const Instruction::OperandList& operands); + + // State required for the current module. + struct PerModuleState { + // This pass modified the module. + bool modified = false; + // True if there is an error processing the current module, e.g. if + // preconditions are not met. + bool failed = false; + // The id of the GLSL.std.450 extended instruction set. Zero if it does + // not exist. + uint32_t glsl_insts_id = 0; + } module_status_; +}; + +} // namespace opt +} // namespace spvtools + +#endif // SOURCE_OPT_GRAPHICS_ROBUST_ACCESS_PASS_H_ diff --git a/third_party/spirv-tools/source/opt/if_conversion.cpp b/third_party/spirv-tools/source/opt/if_conversion.cpp index 7a3717f985..104182bc3d 100644 --- a/third_party/spirv-tools/source/opt/if_conversion.cpp +++ b/third_party/spirv-tools/source/opt/if_conversion.cpp @@ -23,6 +23,10 @@ namespace spvtools { namespace opt { Pass::Status IfConversion::Process() { + if (!context()->get_feature_mgr()->HasCapability(SpvCapabilityShader)) { + return Status::SuccessWithoutChange; + } + const ValueNumberTable& vn_table = *context()->GetValueNumberTable(); bool modified = false; std::vector to_kill; @@ -161,6 +165,9 @@ bool IfConversion::CheckBlock(BasicBlock* block, DominatorAnalysis* dominators, if (!*common || cfg()->IsPseudoEntryBlock(*common)) return false; Instruction* branch = (*common)->terminator(); if (branch->opcode() != SpvOpBranchConditional) return false; + auto merge = (*common)->GetMergeInst(); + if (!merge || merge->opcode() != SpvOpSelectionMerge) return false; + if ((*common)->MergeBlockIdIfAny() != block->id()) return false; return true; } diff --git a/third_party/spirv-tools/source/opt/if_conversion.h b/third_party/spirv-tools/source/opt/if_conversion.h index 609bdf3926..db84e703bd 100644 --- a/third_party/spirv-tools/source/opt/if_conversion.h +++ b/third_party/spirv-tools/source/opt/if_conversion.h @@ -32,7 +32,8 @@ class IfConversion : public Pass { IRContext::Analysis GetPreservedAnalyses() override { return IRContext::kAnalysisDefUse | IRContext::kAnalysisDominatorAnalysis | IRContext::kAnalysisInstrToBlockMapping | IRContext::kAnalysisCFG | - IRContext::kAnalysisNameMap; + IRContext::kAnalysisNameMap | IRContext::kAnalysisConstants | + IRContext::kAnalysisTypes; } private: diff --git a/third_party/spirv-tools/source/opt/inline_exhaustive_pass.cpp b/third_party/spirv-tools/source/opt/inline_exhaustive_pass.cpp index 5714cd867d..24f4e73640 100644 --- a/third_party/spirv-tools/source/opt/inline_exhaustive_pass.cpp +++ b/third_party/spirv-tools/source/opt/inline_exhaustive_pass.cpp @@ -21,7 +21,7 @@ namespace spvtools { namespace opt { -bool InlineExhaustivePass::InlineExhaustive(Function* func) { +Pass::Status InlineExhaustivePass::InlineExhaustive(Function* func) { bool modified = false; // Using block iterators here because of block erasures and insertions. for (auto bi = func->begin(); bi != func->end(); ++bi) { @@ -30,7 +30,9 @@ bool InlineExhaustivePass::InlineExhaustive(Function* func) { // Inline call. std::vector> newBlocks; std::vector> newVars; - GenInlineCode(&newBlocks, &newVars, ii, bi); + if (!GenInlineCode(&newBlocks, &newVars, ii, bi)) { + return Status::Failure; + } // If call block is replaced with more than one block, point // succeeding phis at new last block. if (newBlocks.size() > 1) UpdateSucceedingPhis(newBlocks); @@ -58,14 +60,18 @@ bool InlineExhaustivePass::InlineExhaustive(Function* func) { } } } - return modified; + return (modified ? Status::SuccessWithChange : Status::SuccessWithoutChange); } Pass::Status InlineExhaustivePass::ProcessImpl() { + Status status = Status::SuccessWithoutChange; // Attempt exhaustive inlining on each entry point function in module - ProcessFunction pfn = [this](Function* fp) { return InlineExhaustive(fp); }; - bool modified = ProcessEntryPointCallTree(pfn, get_module()); - return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange; + ProcessFunction pfn = [&status, this](Function* fp) { + status = CombineStatus(status, InlineExhaustive(fp)); + return false; + }; + context()->ProcessEntryPointCallTree(pfn); + return status; } InlineExhaustivePass::InlineExhaustivePass() = default; diff --git a/third_party/spirv-tools/source/opt/inline_exhaustive_pass.h b/third_party/spirv-tools/source/opt/inline_exhaustive_pass.h index 103e091e00..c2e854731e 100644 --- a/third_party/spirv-tools/source/opt/inline_exhaustive_pass.h +++ b/third_party/spirv-tools/source/opt/inline_exhaustive_pass.h @@ -40,8 +40,8 @@ class InlineExhaustivePass : public InlinePass { private: // Exhaustively inline all function calls in func as well as in - // all code that is inlined into func. Return true if func is modified. - bool InlineExhaustive(Function* func); + // all code that is inlined into func. Returns the status. + Status InlineExhaustive(Function* func); void Initialize(); Pass::Status ProcessImpl(); diff --git a/third_party/spirv-tools/source/opt/inline_opaque_pass.cpp b/third_party/spirv-tools/source/opt/inline_opaque_pass.cpp index c2c3719fe0..6ccaf90870 100644 --- a/third_party/spirv-tools/source/opt/inline_opaque_pass.cpp +++ b/third_party/spirv-tools/source/opt/inline_opaque_pass.cpp @@ -63,7 +63,7 @@ bool InlineOpaquePass::HasOpaqueArgsOrReturn(const Instruction* callInst) { }); } -bool InlineOpaquePass::InlineOpaque(Function* func) { +Pass::Status InlineOpaquePass::InlineOpaque(Function* func) { bool modified = false; // Using block iterators here because of block erasures and insertions. for (auto bi = func->begin(); bi != func->end(); ++bi) { @@ -72,7 +72,10 @@ bool InlineOpaquePass::InlineOpaque(Function* func) { // Inline call. std::vector> newBlocks; std::vector> newVars; - GenInlineCode(&newBlocks, &newVars, ii, bi); + if (!GenInlineCode(&newBlocks, &newVars, ii, bi)) { + return Status::Failure; + } + // If call block is replaced with more than one block, point // succeeding phis at new last block. if (newBlocks.size() > 1) UpdateSucceedingPhis(newBlocks); @@ -90,16 +93,20 @@ bool InlineOpaquePass::InlineOpaque(Function* func) { } } } - return modified; + return (modified ? Status::SuccessWithChange : Status::SuccessWithoutChange); } void InlineOpaquePass::Initialize() { InitializeInline(); } Pass::Status InlineOpaquePass::ProcessImpl() { + Status status = Status::SuccessWithoutChange; // Do opaque inlining on each function in entry point call tree - ProcessFunction pfn = [this](Function* fp) { return InlineOpaque(fp); }; - bool modified = ProcessEntryPointCallTree(pfn, get_module()); - return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange; + ProcessFunction pfn = [&status, this](Function* fp) { + status = CombineStatus(status, InlineOpaque(fp)); + return false; + }; + context()->ProcessEntryPointCallTree(pfn); + return status; } InlineOpaquePass::InlineOpaquePass() = default; diff --git a/third_party/spirv-tools/source/opt/inline_opaque_pass.h b/third_party/spirv-tools/source/opt/inline_opaque_pass.h index aad43fd6a3..1e3081d22c 100644 --- a/third_party/spirv-tools/source/opt/inline_opaque_pass.h +++ b/third_party/spirv-tools/source/opt/inline_opaque_pass.h @@ -48,7 +48,7 @@ class InlineOpaquePass : public InlinePass { // Inline all function calls in |func| that have opaque params or return // type. Inline similarly all code that is inlined into func. Return true // if func is modified. - bool InlineOpaque(Function* func); + Status InlineOpaque(Function* func); void Initialize(); Pass::Status ProcessImpl(); diff --git a/third_party/spirv-tools/source/opt/inline_pass.cpp b/third_party/spirv-tools/source/opt/inline_pass.cpp index 5a88ef5d3f..3c874a7ef0 100644 --- a/third_party/spirv-tools/source/opt/inline_pass.cpp +++ b/third_party/spirv-tools/source/opt/inline_pass.cpp @@ -27,15 +27,17 @@ static const int kSpvFunctionCallFunctionId = 2; static const int kSpvFunctionCallArgumentId = 3; static const int kSpvReturnValueId = 0; -static const int kSpvLoopMergeMergeBlockId = 0; -static const int kSpvLoopMergeContinueTargetIdInIdx = 1; namespace spvtools { namespace opt { uint32_t InlinePass::AddPointerToType(uint32_t type_id, SpvStorageClass storage_class) { - uint32_t resultId = TakeNextId(); + uint32_t resultId = context()->TakeNextId(); + if (resultId == 0) { + return resultId; + } + std::unique_ptr type_inst( new Instruction(context(), SpvOpTypePointer, 0, resultId, {{spv_operand_type_t::SPV_OPERAND_TYPE_STORAGE_CLASS, @@ -109,10 +111,16 @@ uint32_t InlinePass::GetFalseId() { if (false_id_ != 0) return false_id_; uint32_t boolId = get_module()->GetGlobalValue(SpvOpTypeBool); if (boolId == 0) { - boolId = TakeNextId(); + boolId = context()->TakeNextId(); + if (boolId == 0) { + return 0; + } get_module()->AddGlobalValue(SpvOpTypeBool, boolId, 0); } - false_id_ = TakeNextId(); + false_id_ = context()->TakeNextId(); + if (false_id_ == 0) { + return 0; + } get_module()->AddGlobalValue(SpvOpConstantFalse, false_id_, boolId); return false_id_; } @@ -121,50 +129,64 @@ void InlinePass::MapParams( Function* calleeFn, BasicBlock::iterator call_inst_itr, std::unordered_map* callee2caller) { int param_idx = 0; - calleeFn->ForEachParam([&call_inst_itr, ¶m_idx, - &callee2caller](const Instruction* cpi) { - const uint32_t pid = cpi->result_id(); - (*callee2caller)[pid] = call_inst_itr->GetSingleWordOperand( - kSpvFunctionCallArgumentId + param_idx); - ++param_idx; - }); + calleeFn->ForEachParam( + [&call_inst_itr, ¶m_idx, &callee2caller](const Instruction* cpi) { + const uint32_t pid = cpi->result_id(); + (*callee2caller)[pid] = call_inst_itr->GetSingleWordOperand( + kSpvFunctionCallArgumentId + param_idx); + ++param_idx; + }); } -void InlinePass::CloneAndMapLocals( +bool InlinePass::CloneAndMapLocals( Function* calleeFn, std::vector>* new_vars, std::unordered_map* callee2caller) { auto callee_block_itr = calleeFn->begin(); auto callee_var_itr = callee_block_itr->begin(); while (callee_var_itr->opcode() == SpvOp::SpvOpVariable) { std::unique_ptr var_inst(callee_var_itr->Clone(context())); - uint32_t newId = TakeNextId(); + uint32_t newId = context()->TakeNextId(); + if (newId == 0) { + return false; + } get_decoration_mgr()->CloneDecorations(callee_var_itr->result_id(), newId); var_inst->SetResultId(newId); (*callee2caller)[callee_var_itr->result_id()] = newId; new_vars->push_back(std::move(var_inst)); ++callee_var_itr; } + return true; } uint32_t InlinePass::CreateReturnVar( Function* calleeFn, std::vector>* new_vars) { uint32_t returnVarId = 0; const uint32_t calleeTypeId = calleeFn->type_id(); - analysis::Type* calleeType = context()->get_type_mgr()->GetType(calleeTypeId); - if (calleeType->AsVoid() == nullptr) { - // Find or create ptr to callee return type. - uint32_t returnVarTypeId = context()->get_type_mgr()->FindPointerToType( - calleeTypeId, SpvStorageClassFunction); - if (returnVarTypeId == 0) - returnVarTypeId = AddPointerToType(calleeTypeId, SpvStorageClassFunction); - // Add return var to new function scope variables. - returnVarId = TakeNextId(); - std::unique_ptr var_inst( - new Instruction(context(), SpvOpVariable, returnVarTypeId, returnVarId, - {{spv_operand_type_t::SPV_OPERAND_TYPE_STORAGE_CLASS, - {SpvStorageClassFunction}}})); - new_vars->push_back(std::move(var_inst)); + analysis::TypeManager* type_mgr = context()->get_type_mgr(); + assert(type_mgr->GetType(calleeTypeId)->AsVoid() == nullptr && + "Cannot create a return variable of type void."); + // Find or create ptr to callee return type. + uint32_t returnVarTypeId = + type_mgr->FindPointerToType(calleeTypeId, SpvStorageClassFunction); + + if (returnVarTypeId == 0) { + returnVarTypeId = AddPointerToType(calleeTypeId, SpvStorageClassFunction); + if (returnVarTypeId == 0) { + return 0; + } } + + // Add return var to new function scope variables. + returnVarId = context()->TakeNextId(); + if (returnVarId == 0) { + return 0; + } + + std::unique_ptr var_inst( + new Instruction(context(), SpvOpVariable, returnVarTypeId, returnVarId, + {{spv_operand_type_t::SPV_OPERAND_TYPE_STORAGE_CLASS, + {SpvStorageClassFunction}}})); + new_vars->push_back(std::move(var_inst)); get_decoration_mgr()->CloneDecorations(calleeFn->result_id(), returnVarId); return returnVarId; } @@ -173,37 +195,44 @@ bool InlinePass::IsSameBlockOp(const Instruction* inst) const { return inst->opcode() == SpvOpSampledImage || inst->opcode() == SpvOpImage; } -void InlinePass::CloneSameBlockOps( +bool InlinePass::CloneSameBlockOps( std::unique_ptr* inst, std::unordered_map* postCallSB, std::unordered_map* preCallSB, std::unique_ptr* block_ptr) { - (*inst)->ForEachInId( - [&postCallSB, &preCallSB, &block_ptr, this](uint32_t* iid) { - const auto mapItr = (*postCallSB).find(*iid); - if (mapItr == (*postCallSB).end()) { - const auto mapItr2 = (*preCallSB).find(*iid); - if (mapItr2 != (*preCallSB).end()) { - // Clone pre-call same-block ops, map result id. - const Instruction* inInst = mapItr2->second; - std::unique_ptr sb_inst(inInst->Clone(context())); - CloneSameBlockOps(&sb_inst, postCallSB, preCallSB, block_ptr); - const uint32_t rid = sb_inst->result_id(); - const uint32_t nid = this->TakeNextId(); - get_decoration_mgr()->CloneDecorations(rid, nid); - sb_inst->SetResultId(nid); - (*postCallSB)[rid] = nid; - *iid = nid; - (*block_ptr)->AddInstruction(std::move(sb_inst)); - } - } else { - // Reset same-block op operand. - *iid = mapItr->second; + return (*inst)->WhileEachInId([&postCallSB, &preCallSB, &block_ptr, + this](uint32_t* iid) { + const auto mapItr = (*postCallSB).find(*iid); + if (mapItr == (*postCallSB).end()) { + const auto mapItr2 = (*preCallSB).find(*iid); + if (mapItr2 != (*preCallSB).end()) { + // Clone pre-call same-block ops, map result id. + const Instruction* inInst = mapItr2->second; + std::unique_ptr sb_inst(inInst->Clone(context())); + if (!CloneSameBlockOps(&sb_inst, postCallSB, preCallSB, block_ptr)) { + return false; } - }); + + const uint32_t rid = sb_inst->result_id(); + const uint32_t nid = context()->TakeNextId(); + if (nid == 0) { + return false; + } + get_decoration_mgr()->CloneDecorations(rid, nid); + sb_inst->SetResultId(nid); + (*postCallSB)[rid] = nid; + *iid = nid; + (*block_ptr)->AddInstruction(std::move(sb_inst)); + } + } else { + // Reset same-block op operand. + *iid = mapItr->second; + } + return true; + }); } -void InlinePass::GenInlineCode( +bool InlinePass::GenInlineCode( std::vector>* new_blocks, std::vector>* new_vars, BasicBlock::iterator call_inst_itr, @@ -225,18 +254,28 @@ void InlinePass::GenInlineCode( kSpvFunctionCallFunctionId)]; // Check for multiple returns in the callee. - auto fi = multi_return_funcs_.find(calleeFn->result_id()); - const bool multiReturn = fi != multi_return_funcs_.end(); + auto fi = early_return_funcs_.find(calleeFn->result_id()); + const bool earlyReturn = fi != early_return_funcs_.end(); // Map parameters to actual arguments. MapParams(calleeFn, call_inst_itr, &callee2caller); // Define caller local variables for all callee variables and create map to // them. - CloneAndMapLocals(calleeFn, new_vars, &callee2caller); + if (!CloneAndMapLocals(calleeFn, new_vars, &callee2caller)) { + return false; + } // Create return var if needed. - uint32_t returnVarId = CreateReturnVar(calleeFn, new_vars); + const uint32_t calleeTypeId = calleeFn->type_id(); + uint32_t returnVarId = 0; + analysis::Type* calleeType = context()->get_type_mgr()->GetType(calleeTypeId); + if (calleeType->AsVoid() == nullptr) { + returnVarId = CreateReturnVar(calleeFn, new_vars); + if (returnVarId == 0) { + return false; + } + } // Create set of callee result ids. Used to detect forward references std::unordered_set callee_result_ids; @@ -245,19 +284,14 @@ void InlinePass::GenInlineCode( if (rid != 0) callee_result_ids.insert(rid); }); - // If the caller is in a single-block loop, and the callee has multiple - // blocks, then the normal inlining logic will place the OpLoopMerge in - // the last of several blocks in the loop. Instead, it should be placed - // at the end of the first block. First determine if the caller is in a - // single block loop. We'll wait to move the OpLoopMerge until the end - // of the regular inlining logic, and only if necessary. - bool caller_is_single_block_loop = false; + // If the caller is a loop header and the callee has multiple blocks, then the + // normal inlining logic will place the OpLoopMerge in the last of several + // blocks in the loop. Instead, it should be placed at the end of the first + // block. We'll wait to move the OpLoopMerge until the end of the regular + // inlining logic, and only if necessary. bool caller_is_loop_header = false; - if (auto* loop_merge = call_block_itr->GetLoopMergeInst()) { + if (call_block_itr->GetLoopMergeInst()) { caller_is_loop_header = true; - caller_is_single_block_loop = - call_block_itr->id() == - loop_merge->GetSingleWordInOperand(kSpvLoopMergeContinueTargetIdInIdx); } bool callee_begins_with_structured_header = @@ -270,241 +304,294 @@ void InlinePass::GenInlineCode( uint32_t singleTripLoopContinueId = 0; uint32_t returnLabelId = 0; bool multiBlocks = false; - const uint32_t calleeTypeId = calleeFn->type_id(); // new_blk_ptr is a new basic block in the caller. New instructions are // written to it. It is created when we encounter the OpLabel // of the first callee block. It is appended to new_blocks only when // it is complete. std::unique_ptr new_blk_ptr; - calleeFn->ForEachInst([&new_blocks, &callee2caller, &call_block_itr, - &call_inst_itr, &new_blk_ptr, &prevInstWasReturn, - &returnLabelId, &returnVarId, caller_is_loop_header, - callee_begins_with_structured_header, &calleeTypeId, - &multiBlocks, &postCallSB, &preCallSB, multiReturn, - &singleTripLoopHeaderId, &singleTripLoopContinueId, - &callee_result_ids, this](const Instruction* cpi) { - switch (cpi->opcode()) { - case SpvOpFunction: - case SpvOpFunctionParameter: - // Already processed - break; - case SpvOpVariable: - if (cpi->NumInOperands() == 2) { - assert(callee2caller.count(cpi->result_id()) && - "Expected the variable to have already been mapped."); - uint32_t new_var_id = callee2caller.at(cpi->result_id()); + bool successful = calleeFn->WhileEachInst( + [&new_blocks, &callee2caller, &call_block_itr, &call_inst_itr, + &new_blk_ptr, &prevInstWasReturn, &returnLabelId, &returnVarId, + caller_is_loop_header, callee_begins_with_structured_header, + &calleeTypeId, &multiBlocks, &postCallSB, &preCallSB, earlyReturn, + &singleTripLoopHeaderId, &singleTripLoopContinueId, &callee_result_ids, + this](const Instruction* cpi) { + switch (cpi->opcode()) { + case SpvOpFunction: + case SpvOpFunctionParameter: + // Already processed + break; + case SpvOpVariable: + if (cpi->NumInOperands() == 2) { + assert(callee2caller.count(cpi->result_id()) && + "Expected the variable to have already been mapped."); + uint32_t new_var_id = callee2caller.at(cpi->result_id()); - // The initializer must be a constant or global value. No mapped - // should be used. - uint32_t val_id = cpi->GetSingleWordInOperand(1); - AddStore(new_var_id, val_id, &new_blk_ptr); - } - break; - case SpvOpUnreachable: - case SpvOpKill: { - // Generate a return label so that we split the block with the function - // call. Copy the terminator into the new block. - if (returnLabelId == 0) returnLabelId = this->TakeNextId(); - std::unique_ptr terminator( - new Instruction(context(), cpi->opcode(), 0, 0, {})); - new_blk_ptr->AddInstruction(std::move(terminator)); - break; - } - case SpvOpLabel: { - // If previous instruction was early return, insert branch - // instruction to return block. - if (prevInstWasReturn) { - if (returnLabelId == 0) returnLabelId = this->TakeNextId(); - AddBranch(returnLabelId, &new_blk_ptr); - prevInstWasReturn = false; - } - // Finish current block (if it exists) and get label for next block. - uint32_t labelId; - bool firstBlock = false; - if (new_blk_ptr != nullptr) { - new_blocks->push_back(std::move(new_blk_ptr)); - // If result id is already mapped, use it, otherwise get a new - // one. - const uint32_t rid = cpi->result_id(); - const auto mapItr = callee2caller.find(rid); - labelId = (mapItr != callee2caller.end()) ? mapItr->second - : this->TakeNextId(); - } else { - // First block needs to use label of original block - // but map callee label in case of phi reference. - labelId = call_block_itr->id(); - callee2caller[cpi->result_id()] = labelId; - firstBlock = true; - } - // Create first/next block. - new_blk_ptr = MakeUnique(NewLabel(labelId)); - if (firstBlock) { - // Copy contents of original caller block up to call instruction. - for (auto cii = call_block_itr->begin(); cii != call_inst_itr; - cii = call_block_itr->begin()) { - Instruction* inst = &*cii; - inst->RemoveFromList(); - std::unique_ptr cp_inst(inst); - // Remember same-block ops for possible regeneration. - if (IsSameBlockOp(&*cp_inst)) { - auto* sb_inst_ptr = cp_inst.get(); - preCallSB[cp_inst->result_id()] = sb_inst_ptr; + // The initializer must be a constant or global value. No mapped + // should be used. + uint32_t val_id = cpi->GetSingleWordInOperand(1); + AddStore(new_var_id, val_id, &new_blk_ptr); + } + break; + case SpvOpUnreachable: + case SpvOpKill: { + // Generate a return label so that we split the block with the + // function call. Copy the terminator into the new block. + if (returnLabelId == 0) { + returnLabelId = context()->TakeNextId(); + if (returnLabelId == 0) { + return false; + } + } + std::unique_ptr terminator( + new Instruction(context(), cpi->opcode(), 0, 0, {})); + new_blk_ptr->AddInstruction(std::move(terminator)); + break; + } + case SpvOpLabel: { + // If previous instruction was early return, insert branch + // instruction to return block. + if (prevInstWasReturn) { + if (returnLabelId == 0) { + returnLabelId = context()->TakeNextId(); + if (returnLabelId == 0) { + return false; + } + } + AddBranch(returnLabelId, &new_blk_ptr); + prevInstWasReturn = false; + } + // Finish current block (if it exists) and get label for next block. + uint32_t labelId; + bool firstBlock = false; + if (new_blk_ptr != nullptr) { + new_blocks->push_back(std::move(new_blk_ptr)); + // If result id is already mapped, use it, otherwise get a new + // one. + const uint32_t rid = cpi->result_id(); + const auto mapItr = callee2caller.find(rid); + labelId = (mapItr != callee2caller.end()) + ? mapItr->second + : context()->TakeNextId(); + if (labelId == 0) { + return false; + } + } else { + // First block needs to use label of original block + // but map callee label in case of phi reference. + labelId = call_block_itr->id(); + callee2caller[cpi->result_id()] = labelId; + firstBlock = true; + } + // Create first/next block. + new_blk_ptr = MakeUnique(NewLabel(labelId)); + if (firstBlock) { + // Copy contents of original caller block up to call instruction. + for (auto cii = call_block_itr->begin(); cii != call_inst_itr; + cii = call_block_itr->begin()) { + Instruction* inst = &*cii; + inst->RemoveFromList(); + std::unique_ptr cp_inst(inst); + // Remember same-block ops for possible regeneration. + if (IsSameBlockOp(&*cp_inst)) { + auto* sb_inst_ptr = cp_inst.get(); + preCallSB[cp_inst->result_id()] = sb_inst_ptr; + } + new_blk_ptr->AddInstruction(std::move(cp_inst)); + } + if (caller_is_loop_header && + callee_begins_with_structured_header) { + // We can't place both the caller's merge instruction and + // another merge instruction in the same block. So split the + // calling block. Insert an unconditional branch to a new guard + // block. Later, once we know the ID of the last block, we + // will move the caller's OpLoopMerge from the last generated + // block into the first block. We also wait to avoid + // invalidating various iterators. + const auto guard_block_id = context()->TakeNextId(); + if (guard_block_id == 0) { + return false; + } + AddBranch(guard_block_id, &new_blk_ptr); + new_blocks->push_back(std::move(new_blk_ptr)); + // Start the next block. + new_blk_ptr = MakeUnique(NewLabel(guard_block_id)); + // Reset the mapping of the callee's entry block to point to + // the guard block. Do this so we can fix up phis later on to + // satisfy dominance. + callee2caller[cpi->result_id()] = guard_block_id; + } + // If callee has early return, insert a header block for + // single-trip loop that will encompass callee code. Start + // postheader block. + // + // Note: Consider the following combination: + // - the caller is a single block loop + // - the callee does not begin with a structure header + // - the callee has multiple returns. + // We still need to split the caller block and insert a guard + // block. But we only need to do it once. We haven't done it yet, + // but the single-trip loop header will serve the same purpose. + if (earlyReturn) { + singleTripLoopHeaderId = context()->TakeNextId(); + if (singleTripLoopHeaderId == 0) { + return false; + } + AddBranch(singleTripLoopHeaderId, &new_blk_ptr); + new_blocks->push_back(std::move(new_blk_ptr)); + new_blk_ptr = + MakeUnique(NewLabel(singleTripLoopHeaderId)); + returnLabelId = context()->TakeNextId(); + singleTripLoopContinueId = context()->TakeNextId(); + if (returnLabelId == 0 || singleTripLoopContinueId == 0) { + return false; + } + AddLoopMerge(returnLabelId, singleTripLoopContinueId, + &new_blk_ptr); + uint32_t postHeaderId = context()->TakeNextId(); + if (postHeaderId == 0) { + return false; + } + AddBranch(postHeaderId, &new_blk_ptr); + new_blocks->push_back(std::move(new_blk_ptr)); + new_blk_ptr = MakeUnique(NewLabel(postHeaderId)); + multiBlocks = true; + // Reset the mapping of the callee's entry block to point to + // the post-header block. Do this so we can fix up phis later + // on to satisfy dominance. + callee2caller[cpi->result_id()] = postHeaderId; + } + } else { + multiBlocks = true; + } + } break; + case SpvOpReturnValue: { + // Store return value to return variable. + assert(returnVarId != 0); + uint32_t valId = cpi->GetInOperand(kSpvReturnValueId).words[0]; + const auto mapItr = callee2caller.find(valId); + if (mapItr != callee2caller.end()) { + valId = mapItr->second; + } + AddStore(returnVarId, valId, &new_blk_ptr); + + // Remember we saw a return; if followed by a label, will need to + // insert branch. + prevInstWasReturn = true; + } break; + case SpvOpReturn: { + // Remember we saw a return; if followed by a label, will need to + // insert branch. + prevInstWasReturn = true; + } break; + case SpvOpFunctionEnd: { + // If there was an early return, we generated a return label id + // for it. Now we have to generate the return block with that Id. + if (returnLabelId != 0) { + // If previous instruction was return, insert branch instruction + // to return block. + if (prevInstWasReturn) AddBranch(returnLabelId, &new_blk_ptr); + if (earlyReturn) { + // If we generated a loop header for the single-trip loop + // to accommodate early returns, insert the continue + // target block now, with a false branch back to the loop + // header. + new_blocks->push_back(std::move(new_blk_ptr)); + new_blk_ptr = + MakeUnique(NewLabel(singleTripLoopContinueId)); + uint32_t false_id = GetFalseId(); + if (false_id == 0) { + return false; + } + AddBranchCond(false_id, singleTripLoopHeaderId, returnLabelId, + &new_blk_ptr); + } + // Generate the return block. + new_blocks->push_back(std::move(new_blk_ptr)); + new_blk_ptr = MakeUnique(NewLabel(returnLabelId)); + multiBlocks = true; + } + // Load return value into result id of call, if it exists. + if (returnVarId != 0) { + const uint32_t resId = call_inst_itr->result_id(); + assert(resId != 0); + AddLoad(calleeTypeId, resId, returnVarId, &new_blk_ptr); + } + // Copy remaining instructions from caller block. + for (Instruction* inst = call_inst_itr->NextNode(); inst; + inst = call_inst_itr->NextNode()) { + inst->RemoveFromList(); + std::unique_ptr cp_inst(inst); + // If multiple blocks generated, regenerate any same-block + // instruction that has not been seen in this last block. + if (multiBlocks) { + if (!CloneSameBlockOps(&cp_inst, &postCallSB, &preCallSB, + &new_blk_ptr)) { + return false; + } + + // Remember same-block ops in this block. + if (IsSameBlockOp(&*cp_inst)) { + const uint32_t rid = cp_inst->result_id(); + postCallSB[rid] = rid; + } + } + new_blk_ptr->AddInstruction(std::move(cp_inst)); + } + // Finalize inline code. + new_blocks->push_back(std::move(new_blk_ptr)); + } break; + default: { + // Copy callee instruction and remap all input Ids. + std::unique_ptr cp_inst(cpi->Clone(context())); + bool succeeded = cp_inst->WhileEachInId( + [&callee2caller, &callee_result_ids, this](uint32_t* iid) { + const auto mapItr = callee2caller.find(*iid); + if (mapItr != callee2caller.end()) { + *iid = mapItr->second; + } else if (callee_result_ids.find(*iid) != + callee_result_ids.end()) { + // Forward reference. Allocate a new id, map it, + // use it and check for it when remapping result ids + const uint32_t nid = context()->TakeNextId(); + if (nid == 0) { + return false; + } + callee2caller[*iid] = nid; + *iid = nid; + } + return true; + }); + if (!succeeded) { + return false; + } + // If result id is non-zero, remap it. If already mapped, use mapped + // value, else use next id. + const uint32_t rid = cp_inst->result_id(); + if (rid != 0) { + const auto mapItr = callee2caller.find(rid); + uint32_t nid; + if (mapItr != callee2caller.end()) { + nid = mapItr->second; + } else { + nid = context()->TakeNextId(); + if (nid == 0) { + return false; + } + callee2caller[rid] = nid; + } + cp_inst->SetResultId(nid); + get_decoration_mgr()->CloneDecorations(rid, nid); } new_blk_ptr->AddInstruction(std::move(cp_inst)); - } - if (caller_is_loop_header && callee_begins_with_structured_header) { - // We can't place both the caller's merge instruction and another - // merge instruction in the same block. So split the calling block. - // Insert an unconditional branch to a new guard block. Later, - // once we know the ID of the last block, we will move the caller's - // OpLoopMerge from the last generated block into the first block. - // We also wait to avoid invalidating various iterators. - const auto guard_block_id = this->TakeNextId(); - AddBranch(guard_block_id, &new_blk_ptr); - new_blocks->push_back(std::move(new_blk_ptr)); - // Start the next block. - new_blk_ptr = MakeUnique(NewLabel(guard_block_id)); - // Reset the mapping of the callee's entry block to point to - // the guard block. Do this so we can fix up phis later on to - // satisfy dominance. - callee2caller[cpi->result_id()] = guard_block_id; - } - // If callee has multiple returns, insert a header block for - // single-trip loop that will encompass callee code. Start postheader - // block. - // - // Note: Consider the following combination: - // - the caller is a single block loop - // - the callee does not begin with a structure header - // - the callee has multiple returns. - // We still need to split the caller block and insert a guard block. - // But we only need to do it once. We haven't done it yet, but the - // single-trip loop header will serve the same purpose. - if (multiReturn) { - singleTripLoopHeaderId = this->TakeNextId(); - AddBranch(singleTripLoopHeaderId, &new_blk_ptr); - new_blocks->push_back(std::move(new_blk_ptr)); - new_blk_ptr = - MakeUnique(NewLabel(singleTripLoopHeaderId)); - returnLabelId = this->TakeNextId(); - singleTripLoopContinueId = this->TakeNextId(); - AddLoopMerge(returnLabelId, singleTripLoopContinueId, &new_blk_ptr); - uint32_t postHeaderId = this->TakeNextId(); - AddBranch(postHeaderId, &new_blk_ptr); - new_blocks->push_back(std::move(new_blk_ptr)); - new_blk_ptr = MakeUnique(NewLabel(postHeaderId)); - multiBlocks = true; - // Reset the mapping of the callee's entry block to point to - // the post-header block. Do this so we can fix up phis later - // on to satisfy dominance. - callee2caller[cpi->result_id()] = postHeaderId; - } - } else { - multiBlocks = true; + } break; } - } break; - case SpvOpReturnValue: { - // Store return value to return variable. - assert(returnVarId != 0); - uint32_t valId = cpi->GetInOperand(kSpvReturnValueId).words[0]; - const auto mapItr = callee2caller.find(valId); - if (mapItr != callee2caller.end()) { - valId = mapItr->second; - } - AddStore(returnVarId, valId, &new_blk_ptr); + return true; + }); - // Remember we saw a return; if followed by a label, will need to - // insert branch. - prevInstWasReturn = true; - } break; - case SpvOpReturn: { - // Remember we saw a return; if followed by a label, will need to - // insert branch. - prevInstWasReturn = true; - } break; - case SpvOpFunctionEnd: { - // If there was an early return, we generated a return label id - // for it. Now we have to generate the return block with that Id. - if (returnLabelId != 0) { - // If previous instruction was return, insert branch instruction - // to return block. - if (prevInstWasReturn) AddBranch(returnLabelId, &new_blk_ptr); - if (multiReturn) { - // If we generated a loop header to for the single-trip loop - // to accommodate multiple returns, insert the continue - // target block now, with a false branch back to the loop header. - new_blocks->push_back(std::move(new_blk_ptr)); - new_blk_ptr = - MakeUnique(NewLabel(singleTripLoopContinueId)); - AddBranchCond(GetFalseId(), singleTripLoopHeaderId, returnLabelId, - &new_blk_ptr); - } - // Generate the return block. - new_blocks->push_back(std::move(new_blk_ptr)); - new_blk_ptr = MakeUnique(NewLabel(returnLabelId)); - multiBlocks = true; - } - // Load return value into result id of call, if it exists. - if (returnVarId != 0) { - const uint32_t resId = call_inst_itr->result_id(); - assert(resId != 0); - AddLoad(calleeTypeId, resId, returnVarId, &new_blk_ptr); - } - // Copy remaining instructions from caller block. - for (Instruction* inst = call_inst_itr->NextNode(); inst; - inst = call_inst_itr->NextNode()) { - inst->RemoveFromList(); - std::unique_ptr cp_inst(inst); - // If multiple blocks generated, regenerate any same-block - // instruction that has not been seen in this last block. - if (multiBlocks) { - CloneSameBlockOps(&cp_inst, &postCallSB, &preCallSB, &new_blk_ptr); - // Remember same-block ops in this block. - if (IsSameBlockOp(&*cp_inst)) { - const uint32_t rid = cp_inst->result_id(); - postCallSB[rid] = rid; - } - } - new_blk_ptr->AddInstruction(std::move(cp_inst)); - } - // Finalize inline code. - new_blocks->push_back(std::move(new_blk_ptr)); - } break; - default: { - // Copy callee instruction and remap all input Ids. - std::unique_ptr cp_inst(cpi->Clone(context())); - cp_inst->ForEachInId([&callee2caller, &callee_result_ids, - this](uint32_t* iid) { - const auto mapItr = callee2caller.find(*iid); - if (mapItr != callee2caller.end()) { - *iid = mapItr->second; - } else if (callee_result_ids.find(*iid) != callee_result_ids.end()) { - // Forward reference. Allocate a new id, map it, - // use it and check for it when remapping result ids - const uint32_t nid = this->TakeNextId(); - callee2caller[*iid] = nid; - *iid = nid; - } - }); - // If result id is non-zero, remap it. If already mapped, use mapped - // value, else use next id. - const uint32_t rid = cp_inst->result_id(); - if (rid != 0) { - const auto mapItr = callee2caller.find(rid); - uint32_t nid; - if (mapItr != callee2caller.end()) { - nid = mapItr->second; - } else { - nid = this->TakeNextId(); - callee2caller[rid] = nid; - } - cp_inst->SetResultId(nid); - get_decoration_mgr()->CloneDecorations(rid, nid); - } - new_blk_ptr->AddInstruction(std::move(cp_inst)); - } break; - } - }); + if (!successful) { + return false; + } if (caller_is_loop_header && (new_blocks->size() > 1)) { // Move the OpLoopMerge from the last block back to the first, where @@ -518,10 +605,6 @@ void InlinePass::GenInlineCode( --loop_merge_itr; assert(loop_merge_itr->opcode() == SpvOpLoopMerge); std::unique_ptr cp_inst(loop_merge_itr->Clone(context())); - if (caller_is_single_block_loop) { - // Also, update its continue target to point to the last block. - cp_inst->SetInOperand(kSpvLoopMergeContinueTargetIdInIdx, {last->id()}); - } first->tail().InsertBefore(std::move(cp_inst)); // Remove the loop merge from the last block. @@ -533,6 +616,7 @@ void InlinePass::GenInlineCode( for (auto& blk : *new_blocks) { id2block_[blk->id()] = &*blk; } + return true; } bool InlinePass::IsInlinableFunctionCall(const Instruction* inst) { @@ -561,44 +645,24 @@ void InlinePass::UpdateSucceedingPhis( }); } -bool InlinePass::HasMultipleReturns(Function* func) { - bool seenReturn = false; - bool multipleReturns = false; +bool InlinePass::HasNoReturnInStructuredConstruct(Function* func) { + // If control not structured, do not do loop/return analysis + // TODO: Analyze returns in non-structured control flow + if (!context()->get_feature_mgr()->HasCapability(SpvCapabilityShader)) + return false; + const auto structured_analysis = context()->GetStructuredCFGAnalysis(); + // Search for returns in structured construct. + bool return_in_construct = false; for (auto& blk : *func) { auto terminal_ii = blk.cend(); --terminal_ii; - if (terminal_ii->opcode() == SpvOpReturn || - terminal_ii->opcode() == SpvOpReturnValue) { - if (seenReturn) { - multipleReturns = true; - break; - } - seenReturn = true; + if (spvOpcodeIsReturn(terminal_ii->opcode()) && + structured_analysis->ContainingConstruct(blk.id()) != 0) { + return_in_construct = true; + break; } } - return multipleReturns; -} - -void InlinePass::ComputeStructuredSuccessors(Function* func) { - // If header, make merge block first successor. - for (auto& blk : *func) { - uint32_t mbid = blk.MergeBlockIdIfAny(); - if (mbid != 0) { - block2structured_succs_[&blk].push_back(id2block_[mbid]); - } - - // Add true successors. - const auto& const_blk = blk; - const_blk.ForEachSuccessorLabel([&blk, this](const uint32_t sbid) { - block2structured_succs_[&blk].push_back(id2block_[sbid]); - }); - } -} - -InlinePass::GetBlocksFunction InlinePass::StructuredSuccessorsFunction() { - return [this](const BasicBlock* block) { - return &(block2structured_succs_[block]); - }; + return !return_in_construct; } bool InlinePass::HasNoReturnInLoop(Function* func) { @@ -606,52 +670,27 @@ bool InlinePass::HasNoReturnInLoop(Function* func) { // TODO: Analyze returns in non-structured control flow if (!context()->get_feature_mgr()->HasCapability(SpvCapabilityShader)) return false; - // Compute structured block order. This order has the property - // that dominators are before all blocks they dominate and merge blocks - // are after all blocks that are in the control constructs of their header. - ComputeStructuredSuccessors(func); - auto ignore_block = [](cbb_ptr) {}; - auto ignore_edge = [](cbb_ptr, cbb_ptr) {}; - std::list structuredOrder; - CFA::DepthFirstTraversal( - &*func->begin(), StructuredSuccessorsFunction(), ignore_block, - [&](cbb_ptr b) { structuredOrder.push_front(b); }, ignore_edge); - // Search for returns in loops. Only need to track outermost loop + const auto structured_analysis = context()->GetStructuredCFGAnalysis(); + // Search for returns in structured construct. bool return_in_loop = false; - uint32_t outerLoopMergeId = 0; - for (auto& blk : structuredOrder) { - // Exiting current outer loop - if (blk->id() == outerLoopMergeId) outerLoopMergeId = 0; - // Return block - auto terminal_ii = blk->cend(); + for (auto& blk : *func) { + auto terminal_ii = blk.cend(); --terminal_ii; - if (terminal_ii->opcode() == SpvOpReturn || - terminal_ii->opcode() == SpvOpReturnValue) { - if (outerLoopMergeId != 0) { - return_in_loop = true; - break; - } - } else if (terminal_ii != blk->cbegin()) { - auto merge_ii = terminal_ii; - --merge_ii; - // Entering outermost loop - if (merge_ii->opcode() == SpvOpLoopMerge && outerLoopMergeId == 0) - outerLoopMergeId = - merge_ii->GetSingleWordOperand(kSpvLoopMergeMergeBlockId); + if (spvOpcodeIsReturn(terminal_ii->opcode()) && + structured_analysis->ContainingLoop(blk.id()) != 0) { + return_in_loop = true; + break; } } return !return_in_loop; } void InlinePass::AnalyzeReturns(Function* func) { - // Look for multiple returns - if (!HasMultipleReturns(func)) { + if (HasNoReturnInLoop(func)) { no_return_in_loop_.insert(func->result_id()); - return; + if (!HasNoReturnInStructuredConstruct(func)) + early_return_funcs_.insert(func->result_id()); } - multi_return_funcs_.insert(func->result_id()); - // If multiple returns, see if any are in a loop - if (HasNoReturnInLoop(func)) no_return_in_loop_.insert(func->result_id()); } bool InlinePass::IsInlinableFunction(Function* func) { @@ -663,8 +702,30 @@ bool InlinePass::IsInlinableFunction(Function* func) { // done validly if the return was not in a loop in the original function. // Also remember functions with multiple (early) returns. AnalyzeReturns(func); - return no_return_in_loop_.find(func->result_id()) != - no_return_in_loop_.cend(); + if (no_return_in_loop_.find(func->result_id()) == no_return_in_loop_.cend()) { + return false; + } + + if (func->IsRecursive()) { + return false; + } + + // Do not inline functions with an OpKill if they are called from a continue + // construct. If it is inlined into a continue construct it will generate + // invalid code. + bool func_is_called_from_continue = + funcs_called_from_continue_.count(func->result_id()) != 0; + + if (func_is_called_from_continue && ContainsKill(func)) { + return false; + } + + return true; +} + +bool InlinePass::ContainsKill(Function* func) const { + return !func->WhileEachInst( + [](Instruction* inst) { return inst->opcode() != SpvOpKill; }); } void InlinePass::InitializeInline() { @@ -673,10 +734,11 @@ void InlinePass::InitializeInline() { // clear collections id2function_.clear(); id2block_.clear(); - block2structured_succs_.clear(); inlinable_.clear(); no_return_in_loop_.clear(); - multi_return_funcs_.clear(); + early_return_funcs_.clear(); + funcs_called_from_continue_ = + context()->GetStructuredCFGAnalysis()->FindFuncsCalledFromContinue(); for (auto& fn : *get_module()) { // Initialize function and block maps. diff --git a/third_party/spirv-tools/source/opt/inline_pass.h b/third_party/spirv-tools/source/opt/inline_pass.h index 55369c98cb..bc5f78127d 100644 --- a/third_party/spirv-tools/source/opt/inline_pass.h +++ b/third_party/spirv-tools/source/opt/inline_pass.h @@ -36,15 +36,13 @@ class InlinePass : public Pass { using cbb_ptr = const BasicBlock*; public: - using GetBlocksFunction = - std::function*(const BasicBlock*)>; - virtual ~InlinePass() = default; protected: InlinePass(); - // Add pointer to type to module and return resultId. + // Add pointer to type to module and return resultId. Returns 0 if the type + // could not be created. uint32_t AddPointerToType(uint32_t type_id, SpvStorageClass storage_class); // Add unconditional branch to labelId to end of block block_ptr. @@ -70,20 +68,22 @@ class InlinePass : public Pass { std::unique_ptr NewLabel(uint32_t label_id); // Returns the id for the boolean false value. Looks in the module first - // and creates it if not found. Remembers it for future calls. + // and creates it if not found. Remembers it for future calls. Returns 0 if + // the value could not be created. uint32_t GetFalseId(); // Map callee params to caller args void MapParams(Function* calleeFn, BasicBlock::iterator call_inst_itr, std::unordered_map* callee2caller); - // Clone and map callee locals - void CloneAndMapLocals(Function* calleeFn, + // Clone and map callee locals. Return true if successful. + bool CloneAndMapLocals(Function* calleeFn, std::vector>* new_vars, std::unordered_map* callee2caller); - // Create return variable for callee clone code if needed. Return id - // if created, otherwise 0. + // Create return variable for callee clone code. The return type of + // |calleeFn| must not be void. Returns the id of the return variable if + // created. Returns 0 if the return variable could not be created. uint32_t CreateReturnVar(Function* calleeFn, std::vector>* new_vars); @@ -95,7 +95,7 @@ class InlinePass : public Pass { // Look in preCallSB for instructions that need cloning. Look in // postCallSB for instructions already cloned. Add cloned instruction // to postCallSB. - void CloneSameBlockOps(std::unique_ptr* inst, + bool CloneSameBlockOps(std::unique_ptr* inst, std::unordered_map* postCallSB, std::unordered_map* preCallSB, std::unique_ptr* block_ptr); @@ -114,7 +114,9 @@ class InlinePass : public Pass { // Also return in new_vars additional OpVariable instructions required by // and to be inserted into the caller function after the block at // call_block_itr is replaced with new_blocks. - void GenInlineCode(std::vector>* new_blocks, + // + // Returns true if successful. + bool GenInlineCode(std::vector>* new_blocks, std::vector>* new_vars, BasicBlock::iterator call_inst_itr, UptrVectorIterator call_block_itr); @@ -122,21 +124,9 @@ class InlinePass : public Pass { // Return true if |inst| is a function call that can be inlined. bool IsInlinableFunctionCall(const Instruction* inst); - // Compute structured successors for function |func|. - // A block's structured successors are the blocks it branches to - // together with its declared merge block if it has one. - // When order matters, the merge block always appears first. - // This assures correct depth first search in the presence of early - // returns and kills. If the successor vector contain duplicates - // if the merge block, they are safely ignored by DFS. - void ComputeStructuredSuccessors(Function* func); - - // Return function to return ordered structure successors for a given block - // Assumes ComputeStructuredSuccessors() has been called. - GetBlocksFunction StructuredSuccessorsFunction(); - - // Return true if |func| has multiple returns - bool HasMultipleReturns(Function* func); + // Return true if |func| does not have a return that is + // nested in a structured if, switch or loop. + bool HasNoReturnInStructuredConstruct(Function* func); // Return true if |func| has no return in a loop. The current analysis // requires structured control flow, so return false if control flow not @@ -149,6 +139,9 @@ class InlinePass : public Pass { // Return true if |func| is a function that can be inlined. bool IsInlinableFunction(Function* func); + // Returns true if |func| contains an OpKill instruction. + bool ContainsKill(Function* func) const; + // Update phis in succeeding blocks to point to new last block void UpdateSucceedingPhis( std::vector>& new_blocks); @@ -163,8 +156,8 @@ class InlinePass : public Pass { // CFG. It has functionality not present in CFG. Consolidate. std::unordered_map id2block_; - // Set of ids of functions with multiple returns. - std::set multi_return_funcs_; + // Set of ids of functions with early return. + std::set early_return_funcs_; // Set of ids of functions with no returns in loop std::set no_return_in_loop_; @@ -175,12 +168,9 @@ class InlinePass : public Pass { // result id for OpConstantFalse uint32_t false_id_; - // Map from block to its structured successor blocks. See - // ComputeStructuredSuccessors() for definition. TODO(dnovillo): This is - // superfluous wrt CFG, but it seems to be computed in a slightly - // different way in the inliner. Can these be consolidated? - std::unordered_map> - block2structured_succs_; + // Set of functions that are originally called directly or indirectly from a + // continue construct. + std::unordered_set funcs_called_from_continue_; }; } // namespace opt diff --git a/third_party/spirv-tools/source/opt/inst_bindless_check_pass.cpp b/third_party/spirv-tools/source/opt/inst_bindless_check_pass.cpp new file mode 100644 index 0000000000..4587343fd3 --- /dev/null +++ b/third_party/spirv-tools/source/opt/inst_bindless_check_pass.cpp @@ -0,0 +1,446 @@ +// Copyright (c) 2018 The Khronos Group Inc. +// Copyright (c) 2018 Valve Corporation +// Copyright (c) 2018 LunarG Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "inst_bindless_check_pass.h" + +namespace { + +// Input Operand Indices +static const int kSpvImageSampleImageIdInIdx = 0; +static const int kSpvSampledImageImageIdInIdx = 0; +static const int kSpvSampledImageSamplerIdInIdx = 1; +static const int kSpvImageSampledImageIdInIdx = 0; +static const int kSpvLoadPtrIdInIdx = 0; +static const int kSpvAccessChainBaseIdInIdx = 0; +static const int kSpvAccessChainIndex0IdInIdx = 1; +static const int kSpvTypePointerTypeIdInIdx = 1; +static const int kSpvTypeArrayLengthIdInIdx = 1; +static const int kSpvConstantValueInIdx = 0; +static const int kSpvVariableStorageClassInIdx = 0; + +} // anonymous namespace + +namespace spvtools { +namespace opt { + +uint32_t InstBindlessCheckPass::GenDebugReadLength( + uint32_t var_id, InstructionBuilder* builder) { + uint32_t desc_set_idx = + var2desc_set_[var_id] + kDebugInputBindlessOffsetLengths; + uint32_t desc_set_idx_id = builder->GetUintConstantId(desc_set_idx); + uint32_t binding_idx_id = builder->GetUintConstantId(var2binding_[var_id]); + return GenDebugDirectRead({desc_set_idx_id, binding_idx_id}, builder); +} + +uint32_t InstBindlessCheckPass::GenDebugReadInit(uint32_t var_id, + uint32_t desc_idx_id, + InstructionBuilder* builder) { + uint32_t desc_set_base_id = + builder->GetUintConstantId(kDebugInputBindlessInitOffset); + uint32_t desc_set_idx_id = builder->GetUintConstantId(var2desc_set_[var_id]); + uint32_t binding_idx_id = builder->GetUintConstantId(var2binding_[var_id]); + uint32_t u_desc_idx_id = GenUintCastCode(desc_idx_id, builder); + return GenDebugDirectRead( + {desc_set_base_id, desc_set_idx_id, binding_idx_id, u_desc_idx_id}, + builder); +} + +uint32_t InstBindlessCheckPass::CloneOriginalReference( + ref_analysis* ref, InstructionBuilder* builder) { + // If original is image based, start by cloning descriptor load + uint32_t new_image_id = 0; + if (ref->desc_load_id != 0) { + Instruction* desc_load_inst = get_def_use_mgr()->GetDef(ref->desc_load_id); + Instruction* new_load_inst = builder->AddLoad( + desc_load_inst->type_id(), + desc_load_inst->GetSingleWordInOperand(kSpvLoadPtrIdInIdx)); + uid2offset_[new_load_inst->unique_id()] = + uid2offset_[desc_load_inst->unique_id()]; + uint32_t new_load_id = new_load_inst->result_id(); + get_decoration_mgr()->CloneDecorations(desc_load_inst->result_id(), + new_load_id); + new_image_id = new_load_id; + // Clone Image/SampledImage with new load, if needed + if (ref->image_id != 0) { + Instruction* image_inst = get_def_use_mgr()->GetDef(ref->image_id); + if (image_inst->opcode() == SpvOp::SpvOpSampledImage) { + Instruction* new_image_inst = builder->AddBinaryOp( + image_inst->type_id(), SpvOpSampledImage, new_load_id, + image_inst->GetSingleWordInOperand(kSpvSampledImageSamplerIdInIdx)); + uid2offset_[new_image_inst->unique_id()] = + uid2offset_[image_inst->unique_id()]; + new_image_id = new_image_inst->result_id(); + } else { + assert(image_inst->opcode() == SpvOp::SpvOpImage && + "expecting OpImage"); + Instruction* new_image_inst = + builder->AddUnaryOp(image_inst->type_id(), SpvOpImage, new_load_id); + uid2offset_[new_image_inst->unique_id()] = + uid2offset_[image_inst->unique_id()]; + new_image_id = new_image_inst->result_id(); + } + get_decoration_mgr()->CloneDecorations(ref->image_id, new_image_id); + } + } + // Clone original reference + std::unique_ptr new_ref_inst(ref->ref_inst->Clone(context())); + uint32_t ref_result_id = ref->ref_inst->result_id(); + uint32_t new_ref_id = 0; + if (ref_result_id != 0) { + new_ref_id = TakeNextId(); + new_ref_inst->SetResultId(new_ref_id); + } + // Update new ref with new image if created + if (new_image_id != 0) + new_ref_inst->SetInOperand(kSpvImageSampleImageIdInIdx, {new_image_id}); + // Register new reference and add to new block + Instruction* added_inst = builder->AddInstruction(std::move(new_ref_inst)); + uid2offset_[added_inst->unique_id()] = + uid2offset_[ref->ref_inst->unique_id()]; + if (new_ref_id != 0) + get_decoration_mgr()->CloneDecorations(ref_result_id, new_ref_id); + return new_ref_id; +} + +uint32_t InstBindlessCheckPass::GetImageId(Instruction* inst) { + switch (inst->opcode()) { + case SpvOp::SpvOpImageSampleImplicitLod: + case SpvOp::SpvOpImageSampleExplicitLod: + case SpvOp::SpvOpImageSampleDrefImplicitLod: + case SpvOp::SpvOpImageSampleDrefExplicitLod: + case SpvOp::SpvOpImageSampleProjImplicitLod: + case SpvOp::SpvOpImageSampleProjExplicitLod: + case SpvOp::SpvOpImageSampleProjDrefImplicitLod: + case SpvOp::SpvOpImageSampleProjDrefExplicitLod: + case SpvOp::SpvOpImageGather: + case SpvOp::SpvOpImageDrefGather: + case SpvOp::SpvOpImageQueryLod: + case SpvOp::SpvOpImageSparseSampleImplicitLod: + case SpvOp::SpvOpImageSparseSampleExplicitLod: + case SpvOp::SpvOpImageSparseSampleDrefImplicitLod: + case SpvOp::SpvOpImageSparseSampleDrefExplicitLod: + case SpvOp::SpvOpImageSparseSampleProjImplicitLod: + case SpvOp::SpvOpImageSparseSampleProjExplicitLod: + case SpvOp::SpvOpImageSparseSampleProjDrefImplicitLod: + case SpvOp::SpvOpImageSparseSampleProjDrefExplicitLod: + case SpvOp::SpvOpImageSparseGather: + case SpvOp::SpvOpImageSparseDrefGather: + case SpvOp::SpvOpImageFetch: + case SpvOp::SpvOpImageRead: + case SpvOp::SpvOpImageQueryFormat: + case SpvOp::SpvOpImageQueryOrder: + case SpvOp::SpvOpImageQuerySizeLod: + case SpvOp::SpvOpImageQuerySize: + case SpvOp::SpvOpImageQueryLevels: + case SpvOp::SpvOpImageQuerySamples: + case SpvOp::SpvOpImageSparseFetch: + case SpvOp::SpvOpImageSparseRead: + case SpvOp::SpvOpImageWrite: + return inst->GetSingleWordInOperand(kSpvImageSampleImageIdInIdx); + default: + break; + } + return 0; +} + +Instruction* InstBindlessCheckPass::GetDescriptorTypeInst( + Instruction* var_inst) { + uint32_t var_type_id = var_inst->type_id(); + Instruction* var_type_inst = get_def_use_mgr()->GetDef(var_type_id); + uint32_t desc_type_id = + var_type_inst->GetSingleWordInOperand(kSpvTypePointerTypeIdInIdx); + return get_def_use_mgr()->GetDef(desc_type_id); +} + +bool InstBindlessCheckPass::AnalyzeDescriptorReference(Instruction* ref_inst, + ref_analysis* ref) { + ref->ref_inst = ref_inst; + if (ref_inst->opcode() == SpvOpLoad || ref_inst->opcode() == SpvOpStore) { + ref->desc_load_id = 0; + ref->ptr_id = ref_inst->GetSingleWordInOperand(kSpvLoadPtrIdInIdx); + Instruction* ptr_inst = get_def_use_mgr()->GetDef(ref->ptr_id); + if (ptr_inst->opcode() != SpvOp::SpvOpAccessChain) return false; + ref->var_id = ptr_inst->GetSingleWordInOperand(kSpvAccessChainBaseIdInIdx); + Instruction* var_inst = get_def_use_mgr()->GetDef(ref->var_id); + if (var_inst->opcode() != SpvOp::SpvOpVariable) return false; + uint32_t storage_class = + var_inst->GetSingleWordInOperand(kSpvVariableStorageClassInIdx); + switch (storage_class) { + case SpvStorageClassUniform: + case SpvStorageClassUniformConstant: + case SpvStorageClassStorageBuffer: + break; + default: + return false; + break; + } + Instruction* desc_type_inst = GetDescriptorTypeInst(var_inst); + switch (desc_type_inst->opcode()) { + case SpvOpTypeArray: + case SpvOpTypeRuntimeArray: + // A load through a descriptor array will have at least 3 operands. We + // do not want to instrument loads of descriptors here which are part of + // an image-based reference. + if (ptr_inst->NumInOperands() < 3) return false; + ref->index_id = + ptr_inst->GetSingleWordInOperand(kSpvAccessChainIndex0IdInIdx); + break; + default: + ref->index_id = 0; + break; + } + return true; + } + // Reference is not load or store. If not an image-based reference, return. + ref->image_id = GetImageId(ref_inst); + if (ref->image_id == 0) return false; + Instruction* image_inst = get_def_use_mgr()->GetDef(ref->image_id); + Instruction* desc_load_inst = nullptr; + if (image_inst->opcode() == SpvOp::SpvOpSampledImage) { + ref->desc_load_id = + image_inst->GetSingleWordInOperand(kSpvSampledImageImageIdInIdx); + desc_load_inst = get_def_use_mgr()->GetDef(ref->desc_load_id); + } else if (image_inst->opcode() == SpvOp::SpvOpImage) { + ref->desc_load_id = + image_inst->GetSingleWordInOperand(kSpvImageSampledImageIdInIdx); + desc_load_inst = get_def_use_mgr()->GetDef(ref->desc_load_id); + } else { + ref->desc_load_id = ref->image_id; + desc_load_inst = image_inst; + ref->image_id = 0; + } + if (desc_load_inst->opcode() != SpvOp::SpvOpLoad) { + // TODO(greg-lunarg): Handle additional possibilities? + return false; + } + ref->ptr_id = desc_load_inst->GetSingleWordInOperand(kSpvLoadPtrIdInIdx); + Instruction* ptr_inst = get_def_use_mgr()->GetDef(ref->ptr_id); + if (ptr_inst->opcode() == SpvOp::SpvOpVariable) { + ref->index_id = 0; + ref->var_id = ref->ptr_id; + } else if (ptr_inst->opcode() == SpvOp::SpvOpAccessChain) { + if (ptr_inst->NumInOperands() != 2) { + assert(false && "unexpected bindless index number"); + return false; + } + ref->index_id = + ptr_inst->GetSingleWordInOperand(kSpvAccessChainIndex0IdInIdx); + ref->var_id = ptr_inst->GetSingleWordInOperand(kSpvAccessChainBaseIdInIdx); + Instruction* var_inst = get_def_use_mgr()->GetDef(ref->var_id); + if (var_inst->opcode() != SpvOpVariable) { + assert(false && "unexpected bindless base"); + return false; + } + } else { + // TODO(greg-lunarg): Handle additional possibilities? + return false; + } + return true; +} + +void InstBindlessCheckPass::GenCheckCode( + uint32_t check_id, uint32_t error_id, uint32_t length_id, + uint32_t stage_idx, ref_analysis* ref, + std::vector>* new_blocks) { + BasicBlock* back_blk_ptr = &*new_blocks->back(); + InstructionBuilder builder( + context(), back_blk_ptr, + IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping); + // Gen conditional branch on check_id. Valid branch generates original + // reference. Invalid generates debug output and zero result (if needed). + uint32_t merge_blk_id = TakeNextId(); + uint32_t valid_blk_id = TakeNextId(); + uint32_t invalid_blk_id = TakeNextId(); + std::unique_ptr merge_label(NewLabel(merge_blk_id)); + std::unique_ptr valid_label(NewLabel(valid_blk_id)); + std::unique_ptr invalid_label(NewLabel(invalid_blk_id)); + (void)builder.AddConditionalBranch(check_id, valid_blk_id, invalid_blk_id, + merge_blk_id, SpvSelectionControlMaskNone); + // Gen valid bounds branch + std::unique_ptr new_blk_ptr( + new BasicBlock(std::move(valid_label))); + builder.SetInsertPoint(&*new_blk_ptr); + uint32_t new_ref_id = CloneOriginalReference(ref, &builder); + (void)builder.AddBranch(merge_blk_id); + new_blocks->push_back(std::move(new_blk_ptr)); + // Gen invalid block + new_blk_ptr.reset(new BasicBlock(std::move(invalid_label))); + builder.SetInsertPoint(&*new_blk_ptr); + uint32_t u_index_id = GenUintCastCode(ref->index_id, &builder); + GenDebugStreamWrite(uid2offset_[ref->ref_inst->unique_id()], stage_idx, + {error_id, u_index_id, length_id}, &builder); + // Remember last invalid block id + uint32_t last_invalid_blk_id = new_blk_ptr->GetLabelInst()->result_id(); + // Gen zero for invalid reference + uint32_t ref_type_id = ref->ref_inst->type_id(); + (void)builder.AddBranch(merge_blk_id); + new_blocks->push_back(std::move(new_blk_ptr)); + // Gen merge block + new_blk_ptr.reset(new BasicBlock(std::move(merge_label))); + builder.SetInsertPoint(&*new_blk_ptr); + // Gen phi of new reference and zero, if necessary, and replace the + // result id of the original reference with that of the Phi. Kill original + // reference. + if (new_ref_id != 0) { + Instruction* phi_inst = builder.AddPhi( + ref_type_id, {new_ref_id, valid_blk_id, GetNullId(ref_type_id), + last_invalid_blk_id}); + context()->ReplaceAllUsesWith(ref->ref_inst->result_id(), + phi_inst->result_id()); + } + new_blocks->push_back(std::move(new_blk_ptr)); + context()->KillInst(ref->ref_inst); +} + +void InstBindlessCheckPass::GenBoundsCheckCode( + BasicBlock::iterator ref_inst_itr, + UptrVectorIterator ref_block_itr, uint32_t stage_idx, + std::vector>* new_blocks) { + // Look for reference through indexed descriptor. If found, analyze and + // save components. If not, return. + ref_analysis ref; + if (!AnalyzeDescriptorReference(&*ref_inst_itr, &ref)) return; + Instruction* ptr_inst = get_def_use_mgr()->GetDef(ref.ptr_id); + if (ptr_inst->opcode() != SpvOp::SpvOpAccessChain) return; + // If index and bound both compile-time constants and index < bound, + // return without changing + Instruction* var_inst = get_def_use_mgr()->GetDef(ref.var_id); + Instruction* desc_type_inst = GetDescriptorTypeInst(var_inst); + uint32_t length_id = 0; + if (desc_type_inst->opcode() == SpvOpTypeArray) { + length_id = + desc_type_inst->GetSingleWordInOperand(kSpvTypeArrayLengthIdInIdx); + Instruction* index_inst = get_def_use_mgr()->GetDef(ref.index_id); + Instruction* length_inst = get_def_use_mgr()->GetDef(length_id); + if (index_inst->opcode() == SpvOpConstant && + length_inst->opcode() == SpvOpConstant && + index_inst->GetSingleWordInOperand(kSpvConstantValueInIdx) < + length_inst->GetSingleWordInOperand(kSpvConstantValueInIdx)) + return; + } else if (!input_length_enabled_ || + desc_type_inst->opcode() != SpvOpTypeRuntimeArray) { + return; + } + // Move original block's preceding instructions into first new block + std::unique_ptr new_blk_ptr; + MovePreludeCode(ref_inst_itr, ref_block_itr, &new_blk_ptr); + InstructionBuilder builder( + context(), &*new_blk_ptr, + IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping); + new_blocks->push_back(std::move(new_blk_ptr)); + uint32_t error_id = builder.GetUintConstantId(kInstErrorBindlessBounds); + // If length id not yet set, descriptor array is runtime size so + // generate load of length from stage's debug input buffer. + if (length_id == 0) { + assert(desc_type_inst->opcode() == SpvOpTypeRuntimeArray && + "unexpected bindless type"); + length_id = GenDebugReadLength(ref.var_id, &builder); + } + // Generate full runtime bounds test code with true branch + // being full reference and false branch being debug output and zero + // for the referenced value. + Instruction* ult_inst = + builder.AddBinaryOp(GetBoolId(), SpvOpULessThan, ref.index_id, length_id); + GenCheckCode(ult_inst->result_id(), error_id, length_id, stage_idx, &ref, + new_blocks); + // Move original block's remaining code into remainder/merge block and add + // to new blocks + BasicBlock* back_blk_ptr = &*new_blocks->back(); + MovePostludeCode(ref_block_itr, back_blk_ptr); +} + +void InstBindlessCheckPass::GenInitCheckCode( + BasicBlock::iterator ref_inst_itr, + UptrVectorIterator ref_block_itr, uint32_t stage_idx, + std::vector>* new_blocks) { + // Look for reference through descriptor. If not, return. + ref_analysis ref; + if (!AnalyzeDescriptorReference(&*ref_inst_itr, &ref)) return; + // Move original block's preceding instructions into first new block + std::unique_ptr new_blk_ptr; + MovePreludeCode(ref_inst_itr, ref_block_itr, &new_blk_ptr); + InstructionBuilder builder( + context(), &*new_blk_ptr, + IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping); + new_blocks->push_back(std::move(new_blk_ptr)); + // Read initialization status from debug input buffer. If index id not yet + // set, binding is single descriptor, so set index to constant 0. + uint32_t zero_id = builder.GetUintConstantId(0u); + if (ref.index_id == 0) ref.index_id = zero_id; + uint32_t init_id = GenDebugReadInit(ref.var_id, ref.index_id, &builder); + // Generate full runtime non-zero init test code with true branch + // being full reference and false branch being debug output and zero + // for the referenced value. + Instruction* uneq_inst = + builder.AddBinaryOp(GetBoolId(), SpvOpINotEqual, init_id, zero_id); + uint32_t error_id = builder.GetUintConstantId(kInstErrorBindlessUninit); + GenCheckCode(uneq_inst->result_id(), error_id, zero_id, stage_idx, &ref, + new_blocks); + // Move original block's remaining code into remainder/merge block and add + // to new blocks + BasicBlock* back_blk_ptr = &*new_blocks->back(); + MovePostludeCode(ref_block_itr, back_blk_ptr); +} + +void InstBindlessCheckPass::InitializeInstBindlessCheck() { + // Initialize base class + InitializeInstrument(); + // If runtime array length support enabled, create variable mappings. Length + // support is always enabled if descriptor init check is enabled. + if (input_length_enabled_) + for (auto& anno : get_module()->annotations()) + if (anno.opcode() == SpvOpDecorate) { + if (anno.GetSingleWordInOperand(1u) == SpvDecorationDescriptorSet) + var2desc_set_[anno.GetSingleWordInOperand(0u)] = + anno.GetSingleWordInOperand(2u); + else if (anno.GetSingleWordInOperand(1u) == SpvDecorationBinding) + var2binding_[anno.GetSingleWordInOperand(0u)] = + anno.GetSingleWordInOperand(2u); + } +} + +Pass::Status InstBindlessCheckPass::ProcessImpl() { + // Perform bindless bounds check on each entry point function in module + InstProcessFunction pfn = + [this](BasicBlock::iterator ref_inst_itr, + UptrVectorIterator ref_block_itr, uint32_t stage_idx, + std::vector>* new_blocks) { + return GenBoundsCheckCode(ref_inst_itr, ref_block_itr, stage_idx, + new_blocks); + }; + bool modified = InstProcessEntryPointCallTree(pfn); + if (input_init_enabled_) { + // Perform descriptor initialization check on each entry point function in + // module + pfn = [this](BasicBlock::iterator ref_inst_itr, + UptrVectorIterator ref_block_itr, + uint32_t stage_idx, + std::vector>* new_blocks) { + return GenInitCheckCode(ref_inst_itr, ref_block_itr, stage_idx, + new_blocks); + }; + modified |= InstProcessEntryPointCallTree(pfn); + } + return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange; +} + +Pass::Status InstBindlessCheckPass::Process() { + InitializeInstBindlessCheck(); + return ProcessImpl(); +} + +} // namespace opt +} // namespace spvtools diff --git a/third_party/spirv-tools/source/opt/inst_bindless_check_pass.h b/third_party/spirv-tools/source/opt/inst_bindless_check_pass.h new file mode 100644 index 0000000000..447871bfc9 --- /dev/null +++ b/third_party/spirv-tools/source/opt/inst_bindless_check_pass.h @@ -0,0 +1,182 @@ +// Copyright (c) 2018 The Khronos Group Inc. +// Copyright (c) 2018 Valve Corporation +// Copyright (c) 2018 LunarG Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef LIBSPIRV_OPT_INST_BINDLESS_CHECK_PASS_H_ +#define LIBSPIRV_OPT_INST_BINDLESS_CHECK_PASS_H_ + +#include "instrument_pass.h" + +namespace spvtools { +namespace opt { + +// This class/pass is designed to support the bindless (descriptor indexing) +// GPU-assisted validation layer of +// https://github.com/KhronosGroup/Vulkan-ValidationLayers. Its internal and +// external design may change as the layer evolves. +class InstBindlessCheckPass : public InstrumentPass { + public: + // Deprecated interface + InstBindlessCheckPass(uint32_t desc_set, uint32_t shader_id, + bool input_length_enable, bool input_init_enable, + uint32_t version) + : InstrumentPass(desc_set, shader_id, kInstValidationIdBindless, version), + input_length_enabled_(input_length_enable), + input_init_enabled_(input_init_enable) {} + // Preferred Interface + InstBindlessCheckPass(uint32_t desc_set, uint32_t shader_id, + bool input_length_enable, bool input_init_enable) + : InstrumentPass(desc_set, shader_id, kInstValidationIdBindless), + input_length_enabled_(input_length_enable), + input_init_enabled_(input_init_enable) {} + + ~InstBindlessCheckPass() override = default; + + // See optimizer.hpp for pass user documentation. + Status Process() override; + + const char* name() const override { return "inst-bindless-check-pass"; } + + private: + // These functions do bindless checking instrumentation on a single + // instruction which references through a descriptor (ie references into an + // image or buffer). Refer to Vulkan API for further information on + // descriptors. GenBoundsCheckCode checks that an index into a descriptor + // array (array of images or buffers) is in-bounds. GenInitCheckCode + // checks that the referenced descriptor has been initialized, if the + // SPV_EXT_descriptor_indexing extension is enabled. + // + // TODO(greg-lunarg): Add support for buffers. Currently only does + // checking of references of images. + // + // The functions are designed to be passed to + // InstrumentPass::InstProcessEntryPointCallTree(), which applies the + // function to each instruction in a module and replaces the instruction + // if warranted. + // + // If |ref_inst_itr| is a bindless reference, return in |new_blocks| the + // result of instrumenting it with validation code within its block at + // |ref_block_itr|. The validation code first executes a check for the + // specific condition called for. If the check passes, it executes + // the remainder of the reference, otherwise writes a record to the debug + // output buffer stream including |function_idx, instruction_idx, stage_idx| + // and replaces the reference with the null value of the original type. The + // block at |ref_block_itr| can just be replaced with the blocks in + // |new_blocks|, which will contain at least two blocks. The last block will + // comprise all instructions following |ref_inst_itr|, + // preceded by a phi instruction. + // + // These instrumentation functions utilize GenDebugDirectRead() to read data + // from the debug input buffer, specifically the lengths of variable length + // descriptor arrays, and the initialization status of each descriptor. + // The format of the debug input buffer is documented in instrument.hpp. + // + // These instrumentation functions utilize GenDebugStreamWrite() to write its + // error records. The validation-specific part of the error record will + // have the format: + // + // Validation Error Code (=kInstErrorBindlessBounds) + // Descriptor Index + // Descriptor Array Size + // + // The Descriptor Index is the index which has been determined to be + // out-of-bounds. + // + // The Descriptor Array Size is the size of the descriptor array which was + // indexed. + void GenBoundsCheckCode(BasicBlock::iterator ref_inst_itr, + UptrVectorIterator ref_block_itr, + uint32_t stage_idx, + std::vector>* new_blocks); + + void GenInitCheckCode(BasicBlock::iterator ref_inst_itr, + UptrVectorIterator ref_block_itr, + uint32_t stage_idx, + std::vector>* new_blocks); + + // Generate instructions into |builder| to read length of runtime descriptor + // array |var_id| from debug input buffer and return id of value. + uint32_t GenDebugReadLength(uint32_t var_id, InstructionBuilder* builder); + + // Generate instructions into |builder| to read initialization status of + // descriptor array |image_id| at |index_id| from debug input buffer and + // return id of value. + uint32_t GenDebugReadInit(uint32_t image_id, uint32_t index_id, + InstructionBuilder* builder); + + // Analysis data for descriptor reference components, generated by + // AnalyzeDescriptorReference. It is necessary and sufficient for further + // analysis and regeneration of the reference. + typedef struct ref_analysis { + uint32_t desc_load_id; + uint32_t image_id; + uint32_t load_id; + uint32_t ptr_id; + uint32_t var_id; + uint32_t index_id; + Instruction* ref_inst; + } ref_analysis; + + // Clone original original reference encapsulated by |ref| into |builder|. + // This may generate more than one instruction if neccessary. + uint32_t CloneOriginalReference(ref_analysis* ref, + InstructionBuilder* builder); + + // If |inst| references through an image, return the id of the image it + // references through. Else return 0. + uint32_t GetImageId(Instruction* inst); + + // Get descriptor type inst of variable |var_inst|. + Instruction* GetDescriptorTypeInst(Instruction* var_inst); + + // Analyze descriptor reference |ref_inst| and save components into |ref|. + // Return true if |ref_inst| is a descriptor reference, false otherwise. + bool AnalyzeDescriptorReference(Instruction* ref_inst, ref_analysis* ref); + + // Generate instrumentation code for generic test result |check_id|, starting + // with |builder| of block |new_blk_ptr|, adding new blocks to |new_blocks|. + // Generate conditional branch to a valid or invalid branch. Generate valid + // block which does original reference |ref|. Generate invalid block which + // writes debug error output utilizing |ref|, |error_id|, |length_id| and + // |stage_idx|. Generate merge block for valid and invalid branches. Kill + // original reference. + void GenCheckCode(uint32_t check_id, uint32_t error_id, uint32_t length_id, + uint32_t stage_idx, ref_analysis* ref, + std::vector>* new_blocks); + + // Initialize state for instrumenting bindless checking + void InitializeInstBindlessCheck(); + + // Apply GenBoundsCheckCode to every instruction in module. Then apply + // GenInitCheckCode to every instruction in module. + Pass::Status ProcessImpl(); + + // Enable instrumentation of runtime array length checking + bool input_length_enabled_; + + // Enable instrumentation of descriptor initialization checking + bool input_init_enabled_; + + // Mapping from variable to descriptor set + std::unordered_map var2desc_set_; + + // Mapping from variable to binding + std::unordered_map var2binding_; +}; + +} // namespace opt +} // namespace spvtools + +#endif // LIBSPIRV_OPT_INST_BINDLESS_CHECK_PASS_H_ diff --git a/third_party/spirv-tools/source/opt/inst_buff_addr_check_pass.cpp b/third_party/spirv-tools/source/opt/inst_buff_addr_check_pass.cpp new file mode 100644 index 0000000000..fa6c2c6a03 --- /dev/null +++ b/third_party/spirv-tools/source/opt/inst_buff_addr_check_pass.cpp @@ -0,0 +1,441 @@ +// Copyright (c) 2019 The Khronos Group Inc. +// Copyright (c) 2019 Valve Corporation +// Copyright (c) 2019 LunarG Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "inst_buff_addr_check_pass.h" + +namespace spvtools { +namespace opt { + +uint32_t InstBuffAddrCheckPass::CloneOriginalReference( + Instruction* ref_inst, InstructionBuilder* builder) { + // Clone original ref with new result id (if load) + assert( + (ref_inst->opcode() == SpvOpLoad || ref_inst->opcode() == SpvOpStore) && + "unexpected ref"); + std::unique_ptr new_ref_inst(ref_inst->Clone(context())); + uint32_t ref_result_id = ref_inst->result_id(); + uint32_t new_ref_id = 0; + if (ref_result_id != 0) { + new_ref_id = TakeNextId(); + new_ref_inst->SetResultId(new_ref_id); + } + // Register new reference and add to new block + Instruction* added_inst = builder->AddInstruction(std::move(new_ref_inst)); + uid2offset_[added_inst->unique_id()] = uid2offset_[ref_inst->unique_id()]; + if (new_ref_id != 0) + get_decoration_mgr()->CloneDecorations(ref_result_id, new_ref_id); + return new_ref_id; +} + +bool InstBuffAddrCheckPass::IsPhysicalBuffAddrReference(Instruction* ref_inst) { + if (ref_inst->opcode() != SpvOpLoad && ref_inst->opcode() != SpvOpStore) + return false; + uint32_t ptr_id = ref_inst->GetSingleWordInOperand(0); + analysis::DefUseManager* du_mgr = get_def_use_mgr(); + Instruction* ptr_inst = du_mgr->GetDef(ptr_id); + if (ptr_inst->opcode() != SpvOpAccessChain) return false; + uint32_t ptr_ty_id = ptr_inst->type_id(); + Instruction* ptr_ty_inst = du_mgr->GetDef(ptr_ty_id); + if (ptr_ty_inst->GetSingleWordInOperand(0) != + SpvStorageClassPhysicalStorageBufferEXT) + return false; + return true; +} + +// TODO(greg-lunarg): Refactor with InstBindlessCheckPass::GenCheckCode() ?? +void InstBuffAddrCheckPass::GenCheckCode( + uint32_t check_id, uint32_t error_id, uint32_t ref_uptr_id, + uint32_t stage_idx, Instruction* ref_inst, + std::vector>* new_blocks) { + BasicBlock* back_blk_ptr = &*new_blocks->back(); + InstructionBuilder builder( + context(), back_blk_ptr, + IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping); + // Gen conditional branch on check_id. Valid branch generates original + // reference. Invalid generates debug output and zero result (if needed). + uint32_t merge_blk_id = TakeNextId(); + uint32_t valid_blk_id = TakeNextId(); + uint32_t invalid_blk_id = TakeNextId(); + std::unique_ptr merge_label(NewLabel(merge_blk_id)); + std::unique_ptr valid_label(NewLabel(valid_blk_id)); + std::unique_ptr invalid_label(NewLabel(invalid_blk_id)); + (void)builder.AddConditionalBranch(check_id, valid_blk_id, invalid_blk_id, + merge_blk_id, SpvSelectionControlMaskNone); + // Gen valid branch + std::unique_ptr new_blk_ptr( + new BasicBlock(std::move(valid_label))); + builder.SetInsertPoint(&*new_blk_ptr); + uint32_t new_ref_id = CloneOriginalReference(ref_inst, &builder); + (void)builder.AddBranch(merge_blk_id); + new_blocks->push_back(std::move(new_blk_ptr)); + // Gen invalid block + new_blk_ptr.reset(new BasicBlock(std::move(invalid_label))); + builder.SetInsertPoint(&*new_blk_ptr); + // Convert uptr from uint64 to 2 uint32 + Instruction* lo_uptr_inst = + builder.AddUnaryOp(GetUintId(), SpvOpUConvert, ref_uptr_id); + Instruction* rshift_uptr_inst = + builder.AddBinaryOp(GetUint64Id(), SpvOpShiftRightLogical, ref_uptr_id, + builder.GetUintConstantId(32)); + Instruction* hi_uptr_inst = builder.AddUnaryOp(GetUintId(), SpvOpUConvert, + rshift_uptr_inst->result_id()); + GenDebugStreamWrite( + uid2offset_[ref_inst->unique_id()], stage_idx, + {error_id, lo_uptr_inst->result_id(), hi_uptr_inst->result_id()}, + &builder); + // Gen zero for invalid load. If pointer type, need to convert uint64 + // zero to pointer; cannot create ConstantNull of pointer type. + uint32_t null_id = 0; + if (new_ref_id != 0) { + uint32_t ref_type_id = ref_inst->type_id(); + analysis::TypeManager* type_mgr = context()->get_type_mgr(); + analysis::Type* ref_type = type_mgr->GetType(ref_type_id); + if (ref_type->AsPointer() != nullptr) { + uint32_t null_u64_id = GetNullId(GetUint64Id()); + Instruction* null_ptr_inst = + builder.AddUnaryOp(ref_type_id, SpvOpConvertUToPtr, null_u64_id); + null_id = null_ptr_inst->result_id(); + } else { + null_id = GetNullId(ref_type_id); + } + } + (void)builder.AddBranch(merge_blk_id); + new_blocks->push_back(std::move(new_blk_ptr)); + // Gen merge block + new_blk_ptr.reset(new BasicBlock(std::move(merge_label))); + builder.SetInsertPoint(&*new_blk_ptr); + // Gen phi of new reference and zero, if necessary, and replace the + // result id of the original reference with that of the Phi. Kill original + // reference. + if (new_ref_id != 0) { + Instruction* phi_inst = + builder.AddPhi(ref_inst->type_id(), + {new_ref_id, valid_blk_id, null_id, invalid_blk_id}); + context()->ReplaceAllUsesWith(ref_inst->result_id(), phi_inst->result_id()); + } + new_blocks->push_back(std::move(new_blk_ptr)); + context()->KillInst(ref_inst); +} + +uint32_t InstBuffAddrCheckPass::GetTypeLength(uint32_t type_id) { + Instruction* type_inst = get_def_use_mgr()->GetDef(type_id); + switch (type_inst->opcode()) { + case SpvOpTypeFloat: + case SpvOpTypeInt: + return type_inst->GetSingleWordInOperand(0) / 8u; + case SpvOpTypeVector: + case SpvOpTypeMatrix: + return type_inst->GetSingleWordInOperand(1) * + GetTypeLength(type_inst->GetSingleWordInOperand(0)); + case SpvOpTypePointer: + assert(type_inst->GetSingleWordInOperand(0) == + SpvStorageClassPhysicalStorageBufferEXT && + "unexpected pointer type"); + return 8u; + default: + assert(false && "unexpected buffer reference type"); + return 0; + } +} + +void InstBuffAddrCheckPass::AddParam(uint32_t type_id, + std::vector* param_vec, + std::unique_ptr* input_func) { + uint32_t pid = TakeNextId(); + param_vec->push_back(pid); + std::unique_ptr param_inst(new Instruction( + get_module()->context(), SpvOpFunctionParameter, type_id, pid, {})); + get_def_use_mgr()->AnalyzeInstDefUse(&*param_inst); + (*input_func)->AddParameter(std::move(param_inst)); +} + +uint32_t InstBuffAddrCheckPass::GetSearchAndTestFuncId() { + if (search_test_func_id_ == 0) { + // Generate function "bool search_and_test(uint64_t ref_ptr, uint32_t len)" + // which searches input buffer for buffer which most likely contains the + // pointer value |ref_ptr| and verifies that the entire reference of + // length |len| bytes is contained in the buffer. + search_test_func_id_ = TakeNextId(); + analysis::TypeManager* type_mgr = context()->get_type_mgr(); + std::vector param_types = { + type_mgr->GetType(GetUint64Id()), type_mgr->GetType(GetUintId())}; + analysis::Function func_ty(type_mgr->GetType(GetBoolId()), param_types); + analysis::Type* reg_func_ty = type_mgr->GetRegisteredType(&func_ty); + std::unique_ptr func_inst( + new Instruction(get_module()->context(), SpvOpFunction, GetBoolId(), + search_test_func_id_, + {{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, + {SpvFunctionControlMaskNone}}, + {spv_operand_type_t::SPV_OPERAND_TYPE_ID, + {type_mgr->GetTypeInstruction(reg_func_ty)}}})); + get_def_use_mgr()->AnalyzeInstDefUse(&*func_inst); + std::unique_ptr input_func = + MakeUnique(std::move(func_inst)); + std::vector param_vec; + // Add ref_ptr and length parameters + AddParam(GetUint64Id(), ¶m_vec, &input_func); + AddParam(GetUintId(), ¶m_vec, &input_func); + // Empty first block. + uint32_t first_blk_id = TakeNextId(); + std::unique_ptr first_blk_label(NewLabel(first_blk_id)); + std::unique_ptr first_blk_ptr = + MakeUnique(std::move(first_blk_label)); + InstructionBuilder builder( + context(), &*first_blk_ptr, + IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping); + uint32_t hdr_blk_id = TakeNextId(); + // Branch to search loop header + std::unique_ptr hdr_blk_label(NewLabel(hdr_blk_id)); + (void)builder.AddInstruction(MakeUnique( + context(), SpvOpBranch, 0, 0, + std::initializer_list{{SPV_OPERAND_TYPE_ID, {hdr_blk_id}}})); + first_blk_ptr->SetParent(&*input_func); + input_func->AddBasicBlock(std::move(first_blk_ptr)); + // Linear search loop header block + // TODO(greg-lunarg): Implement binary search + std::unique_ptr hdr_blk_ptr = + MakeUnique(std::move(hdr_blk_label)); + builder.SetInsertPoint(&*hdr_blk_ptr); + // Phi for search index. Starts with 1. + uint32_t cont_blk_id = TakeNextId(); + std::unique_ptr cont_blk_label(NewLabel(cont_blk_id)); + // Deal with def-use cycle caused by search loop index computation. + // Create Add and Phi instructions first, then do Def analysis on Add. + // Add Phi and Add instructions and do Use analysis later. + uint32_t idx_phi_id = TakeNextId(); + uint32_t idx_inc_id = TakeNextId(); + std::unique_ptr idx_inc_inst(new Instruction( + context(), SpvOpIAdd, GetUintId(), idx_inc_id, + {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {idx_phi_id}}, + {spv_operand_type_t::SPV_OPERAND_TYPE_ID, + {builder.GetUintConstantId(1u)}}})); + std::unique_ptr idx_phi_inst(new Instruction( + context(), SpvOpPhi, GetUintId(), idx_phi_id, + {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, + {builder.GetUintConstantId(1u)}}, + {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {first_blk_id}}, + {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {idx_inc_id}}, + {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {cont_blk_id}}})); + get_def_use_mgr()->AnalyzeInstDef(&*idx_inc_inst); + // Add (previously created) search index phi + (void)builder.AddInstruction(std::move(idx_phi_inst)); + // LoopMerge + uint32_t bound_test_blk_id = TakeNextId(); + std::unique_ptr bound_test_blk_label( + NewLabel(bound_test_blk_id)); + (void)builder.AddInstruction(MakeUnique( + context(), SpvOpLoopMerge, 0, 0, + std::initializer_list{ + {SPV_OPERAND_TYPE_ID, {bound_test_blk_id}}, + {SPV_OPERAND_TYPE_ID, {cont_blk_id}}, + {SPV_OPERAND_TYPE_LITERAL_INTEGER, {SpvLoopControlMaskNone}}})); + // Branch to continue/work block + (void)builder.AddInstruction(MakeUnique( + context(), SpvOpBranch, 0, 0, + std::initializer_list{{SPV_OPERAND_TYPE_ID, {cont_blk_id}}})); + hdr_blk_ptr->SetParent(&*input_func); + input_func->AddBasicBlock(std::move(hdr_blk_ptr)); + // Continue/Work Block. Read next buffer pointer and break if greater + // than ref_ptr arg. + std::unique_ptr cont_blk_ptr = + MakeUnique(std::move(cont_blk_label)); + builder.SetInsertPoint(&*cont_blk_ptr); + // Add (previously created) search index increment now. + (void)builder.AddInstruction(std::move(idx_inc_inst)); + // Load next buffer address from debug input buffer + uint32_t ibuf_id = GetInputBufferId(); + uint32_t ibuf_ptr_id = GetInputBufferPtrId(); + Instruction* uptr_ac_inst = builder.AddTernaryOp( + ibuf_ptr_id, SpvOpAccessChain, ibuf_id, + builder.GetUintConstantId(kDebugInputDataOffset), idx_inc_id); + uint32_t ibuf_type_id = GetInputBufferTypeId(); + Instruction* uptr_load_inst = + builder.AddUnaryOp(ibuf_type_id, SpvOpLoad, uptr_ac_inst->result_id()); + // If loaded address greater than ref_ptr arg, break, else branch back to + // loop header + Instruction* uptr_test_inst = + builder.AddBinaryOp(GetBoolId(), SpvOpUGreaterThan, + uptr_load_inst->result_id(), param_vec[0]); + (void)builder.AddConditionalBranch(uptr_test_inst->result_id(), + bound_test_blk_id, hdr_blk_id, + kInvalidId, SpvSelectionControlMaskNone); + cont_blk_ptr->SetParent(&*input_func); + input_func->AddBasicBlock(std::move(cont_blk_ptr)); + // Bounds test block. Read length of selected buffer and test that + // all len arg bytes are in buffer. + std::unique_ptr bound_test_blk_ptr = + MakeUnique(std::move(bound_test_blk_label)); + builder.SetInsertPoint(&*bound_test_blk_ptr); + // Decrement index to point to previous/candidate buffer address + Instruction* cand_idx_inst = builder.AddBinaryOp( + GetUintId(), SpvOpISub, idx_inc_id, builder.GetUintConstantId(1u)); + // Load candidate buffer address + Instruction* cand_ac_inst = + builder.AddTernaryOp(ibuf_ptr_id, SpvOpAccessChain, ibuf_id, + builder.GetUintConstantId(kDebugInputDataOffset), + cand_idx_inst->result_id()); + Instruction* cand_load_inst = + builder.AddUnaryOp(ibuf_type_id, SpvOpLoad, cand_ac_inst->result_id()); + // Compute offset of ref_ptr from candidate buffer address + Instruction* offset_inst = builder.AddBinaryOp( + ibuf_type_id, SpvOpISub, param_vec[0], cand_load_inst->result_id()); + // Convert ref length to uint64 + Instruction* ref_len_64_inst = + builder.AddUnaryOp(ibuf_type_id, SpvOpUConvert, param_vec[1]); + // Add ref length to ref offset to compute end of reference + Instruction* ref_end_inst = + builder.AddBinaryOp(ibuf_type_id, SpvOpIAdd, offset_inst->result_id(), + ref_len_64_inst->result_id()); + // Load starting index of lengths in input buffer and convert to uint32 + Instruction* len_start_ac_inst = + builder.AddTernaryOp(ibuf_ptr_id, SpvOpAccessChain, ibuf_id, + builder.GetUintConstantId(kDebugInputDataOffset), + builder.GetUintConstantId(0u)); + Instruction* len_start_load_inst = builder.AddUnaryOp( + ibuf_type_id, SpvOpLoad, len_start_ac_inst->result_id()); + Instruction* len_start_32_inst = builder.AddUnaryOp( + GetUintId(), SpvOpUConvert, len_start_load_inst->result_id()); + // Decrement search index to get candidate buffer length index + Instruction* cand_len_idx_inst = + builder.AddBinaryOp(GetUintId(), SpvOpISub, cand_idx_inst->result_id(), + builder.GetUintConstantId(1u)); + // Add candidate length index to start index + Instruction* len_idx_inst = builder.AddBinaryOp( + GetUintId(), SpvOpIAdd, cand_len_idx_inst->result_id(), + len_start_32_inst->result_id()); + // Load candidate buffer length + Instruction* len_ac_inst = + builder.AddTernaryOp(ibuf_ptr_id, SpvOpAccessChain, ibuf_id, + builder.GetUintConstantId(kDebugInputDataOffset), + len_idx_inst->result_id()); + Instruction* len_load_inst = + builder.AddUnaryOp(ibuf_type_id, SpvOpLoad, len_ac_inst->result_id()); + // Test if reference end within candidate buffer length + Instruction* len_test_inst = builder.AddBinaryOp( + GetBoolId(), SpvOpULessThanEqual, ref_end_inst->result_id(), + len_load_inst->result_id()); + // Return test result + (void)builder.AddInstruction(MakeUnique( + context(), SpvOpReturnValue, 0, 0, + std::initializer_list{ + {SPV_OPERAND_TYPE_ID, {len_test_inst->result_id()}}})); + // Close block + bound_test_blk_ptr->SetParent(&*input_func); + input_func->AddBasicBlock(std::move(bound_test_blk_ptr)); + // Close function and add function to module + std::unique_ptr func_end_inst( + new Instruction(get_module()->context(), SpvOpFunctionEnd, 0, 0, {})); + get_def_use_mgr()->AnalyzeInstDefUse(&*func_end_inst); + input_func->SetFunctionEnd(std::move(func_end_inst)); + context()->AddFunction(std::move(input_func)); + } + return search_test_func_id_; +} + +uint32_t InstBuffAddrCheckPass::GenSearchAndTest(Instruction* ref_inst, + InstructionBuilder* builder, + uint32_t* ref_uptr_id) { + // Enable Int64 if necessary + if (!get_feature_mgr()->HasCapability(SpvCapabilityInt64)) { + std::unique_ptr cap_int64_inst(new Instruction( + context(), SpvOpCapability, 0, 0, + std::initializer_list{ + {SPV_OPERAND_TYPE_CAPABILITY, {SpvCapabilityInt64}}})); + get_def_use_mgr()->AnalyzeInstDefUse(&*cap_int64_inst); + context()->AddCapability(std::move(cap_int64_inst)); + } + // Convert reference pointer to uint64 + uint32_t ref_ptr_id = ref_inst->GetSingleWordInOperand(0); + Instruction* ref_uptr_inst = + builder->AddUnaryOp(GetUint64Id(), SpvOpConvertPtrToU, ref_ptr_id); + *ref_uptr_id = ref_uptr_inst->result_id(); + // Compute reference length in bytes + analysis::DefUseManager* du_mgr = get_def_use_mgr(); + Instruction* ref_ptr_inst = du_mgr->GetDef(ref_ptr_id); + uint32_t ref_ptr_ty_id = ref_ptr_inst->type_id(); + Instruction* ref_ptr_ty_inst = du_mgr->GetDef(ref_ptr_ty_id); + uint32_t ref_len = GetTypeLength(ref_ptr_ty_inst->GetSingleWordInOperand(1)); + uint32_t ref_len_id = builder->GetUintConstantId(ref_len); + // Gen call to search and test function + const std::vector args = {GetSearchAndTestFuncId(), *ref_uptr_id, + ref_len_id}; + Instruction* call_inst = + builder->AddNaryOp(GetBoolId(), SpvOpFunctionCall, args); + uint32_t retval = call_inst->result_id(); + return retval; +} + +void InstBuffAddrCheckPass::GenBuffAddrCheckCode( + BasicBlock::iterator ref_inst_itr, + UptrVectorIterator ref_block_itr, uint32_t stage_idx, + std::vector>* new_blocks) { + // Look for reference through indexed descriptor. If found, analyze and + // save components. If not, return. + Instruction* ref_inst = &*ref_inst_itr; + if (!IsPhysicalBuffAddrReference(ref_inst)) return; + // Move original block's preceding instructions into first new block + std::unique_ptr new_blk_ptr; + MovePreludeCode(ref_inst_itr, ref_block_itr, &new_blk_ptr); + InstructionBuilder builder( + context(), &*new_blk_ptr, + IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping); + new_blocks->push_back(std::move(new_blk_ptr)); + uint32_t error_id = builder.GetUintConstantId(kInstErrorBuffAddrUnallocRef); + // Generate code to do search and test if all bytes of reference + // are within a listed buffer. Return reference pointer converted to uint64. + uint32_t ref_uptr_id; + uint32_t valid_id = GenSearchAndTest(ref_inst, &builder, &ref_uptr_id); + // Generate test of search results with true branch + // being full reference and false branch being debug output and zero + // for the referenced value. + GenCheckCode(valid_id, error_id, ref_uptr_id, stage_idx, ref_inst, + new_blocks); + // Move original block's remaining code into remainder/merge block and add + // to new blocks + BasicBlock* back_blk_ptr = &*new_blocks->back(); + MovePostludeCode(ref_block_itr, back_blk_ptr); +} + +void InstBuffAddrCheckPass::InitInstBuffAddrCheck() { + // Initialize base class + InitializeInstrument(); + // Initialize class + search_test_func_id_ = 0; +} + +Pass::Status InstBuffAddrCheckPass::ProcessImpl() { + // Perform bindless bounds check on each entry point function in module + InstProcessFunction pfn = + [this](BasicBlock::iterator ref_inst_itr, + UptrVectorIterator ref_block_itr, uint32_t stage_idx, + std::vector>* new_blocks) { + return GenBuffAddrCheckCode(ref_inst_itr, ref_block_itr, stage_idx, + new_blocks); + }; + bool modified = InstProcessEntryPointCallTree(pfn); + return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange; +} + +Pass::Status InstBuffAddrCheckPass::Process() { + if (!get_feature_mgr()->HasCapability( + SpvCapabilityPhysicalStorageBufferAddressesEXT)) + return Status::SuccessWithoutChange; + InitInstBuffAddrCheck(); + return ProcessImpl(); +} + +} // namespace opt +} // namespace spvtools diff --git a/third_party/spirv-tools/source/opt/inst_buff_addr_check_pass.h b/third_party/spirv-tools/source/opt/inst_buff_addr_check_pass.h new file mode 100644 index 0000000000..67ffcc3924 --- /dev/null +++ b/third_party/spirv-tools/source/opt/inst_buff_addr_check_pass.h @@ -0,0 +1,133 @@ +// Copyright (c) 2019 The Khronos Group Inc. +// Copyright (c) 2019 Valve Corporation +// Copyright (c) 2019 LunarG Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef LIBSPIRV_OPT_INST_BUFFER_ADDRESS_PASS_H_ +#define LIBSPIRV_OPT_INST_BUFFER_ADDRESS_PASS_H_ + +#include "instrument_pass.h" + +namespace spvtools { +namespace opt { + +// This class/pass is designed to support the GPU-assisted validation layer of +// the Buffer Device Address (BDA) extension in +// https://github.com/KhronosGroup/Vulkan-ValidationLayers. The internal and +// external design of this class may change as the layer evolves. +class InstBuffAddrCheckPass : public InstrumentPass { + public: + // Deprecated interface + InstBuffAddrCheckPass(uint32_t desc_set, uint32_t shader_id, uint32_t version) + : InstrumentPass(desc_set, shader_id, kInstValidationIdBuffAddr, + version) {} + // Preferred interface + InstBuffAddrCheckPass(uint32_t desc_set, uint32_t shader_id) + : InstrumentPass(desc_set, shader_id, kInstValidationIdBuffAddr) {} + + ~InstBuffAddrCheckPass() override = default; + + // See optimizer.hpp for pass user documentation. + Status Process() override; + + const char* name() const override { return "inst-bindless-check-pass"; } + + private: + // Return byte length of type |type_id|. Must be int, float, vector, matrix + // or physical pointer. + uint32_t GetTypeLength(uint32_t type_id); + + // Add |type_id| param to |input_func| and add id to |param_vec|. + void AddParam(uint32_t type_id, std::vector* param_vec, + std::unique_ptr* input_func); + + // Return id for search and test function. Generate it if not already gen'd. + uint32_t GetSearchAndTestFuncId(); + + // Generate code into |builder| to do search of the BDA debug input buffer + // for the buffer used by |ref_inst| and test that all bytes of reference + // are within the buffer. Returns id of boolean value which is true if + // search and test is successful, false otherwise. + uint32_t GenSearchAndTest(Instruction* ref_inst, InstructionBuilder* builder, + uint32_t* ref_uptr_id); + + // This function does checking instrumentation on a single + // instruction which references through a physical storage buffer address. + // GenBuffAddrCheckCode generates code that checks that all bytes that + // are referenced fall within a buffer that was queried via + // the Vulkan API call vkGetBufferDeviceAddressEXT(). + // + // The function is designed to be passed to + // InstrumentPass::InstProcessEntryPointCallTree(), which applies the + // function to each instruction in a module and replaces the instruction + // with instrumented code if warranted. + // + // If |ref_inst_itr| is a physical storage buffer reference, return in + // |new_blocks| the result of instrumenting it with validation code within + // its block at |ref_block_itr|. The validation code first executes a check + // for the specific condition called for. If the check passes, it executes + // the remainder of the reference, otherwise writes a record to the debug + // output buffer stream including |function_idx, instruction_idx, stage_idx| + // and replaces the reference with the null value of the original type. The + // block at |ref_block_itr| can just be replaced with the blocks in + // |new_blocks|, which will contain at least two blocks. The last block will + // comprise all instructions following |ref_inst_itr|, + // preceded by a phi instruction if needed. + // + // This instrumentation function utilizes GenDebugStreamWrite() to write its + // error records. The validation-specific part of the error record will + // have the format: + // + // Validation Error Code (=kInstErrorBuffAddr) + // Buffer Address (lowest 32 bits) + // Buffer Address (highest 32 bits) + // + void GenBuffAddrCheckCode( + BasicBlock::iterator ref_inst_itr, + UptrVectorIterator ref_block_itr, uint32_t stage_idx, + std::vector>* new_blocks); + + // Return true if |ref_inst| is a physical buffer address reference, false + // otherwise. + bool IsPhysicalBuffAddrReference(Instruction* ref_inst); + + // Clone original reference |ref_inst| into |builder| and return id of result + uint32_t CloneOriginalReference(Instruction* ref_inst, + InstructionBuilder* builder); + + // Generate instrumentation code for boolean test result |check_id|, + // adding new blocks to |new_blocks|. Generate conditional branch to valid + // or invalid reference blocks. Generate valid reference block which does + // original reference |ref_inst|. Then generate invalid reference block which + // writes debug error output utilizing |ref_inst|, |error_id| and + // |stage_idx|. Generate merge block for valid and invalid reference blocks. + // Kill original reference. + void GenCheckCode(uint32_t check_id, uint32_t error_id, uint32_t length_id, + uint32_t stage_idx, Instruction* ref_inst, + std::vector>* new_blocks); + + // Initialize state for instrumenting physical buffer address checking + void InitInstBuffAddrCheck(); + + // Apply GenBuffAddrCheckCode to every instruction in module. + Pass::Status ProcessImpl(); + + // Id of search and test function, if already gen'd, else zero. + uint32_t search_test_func_id_; +}; + +} // namespace opt +} // namespace spvtools + +#endif // LIBSPIRV_OPT_INST_BUFFER_ADDRESS_PASS_H_ diff --git a/third_party/spirv-tools/source/opt/instruction.cpp b/third_party/spirv-tools/source/opt/instruction.cpp index 4cfa41d8e4..49f91426da 100644 --- a/third_party/spirv-tools/source/opt/instruction.cpp +++ b/third_party/spirv-tools/source/opt/instruction.cpp @@ -155,11 +155,6 @@ bool Instruction::IsReadOnlyLoad() const { } Instruction* Instruction::GetBaseAddress() const { - assert((IsLoad() || opcode() == SpvOpStore || opcode() == SpvOpAccessChain || - opcode() == SpvOpInBoundsAccessChain || opcode() == SpvOpCopyObject || - opcode() == SpvOpImageTexelPointer) && - "GetBaseAddress should only be called on instructions that take a " - "pointer or image."); uint32_t base = GetSingleWordInOperand(kLoadBaseIndex); Instruction* base_inst = context()->get_def_use_mgr()->GetDef(base); bool done = false; @@ -181,22 +176,6 @@ Instruction* Instruction::GetBaseAddress() const { break; } } - - switch (opcode()) { - case SpvOpLoad: - case SpvOpStore: - case SpvOpAccessChain: - case SpvOpInBoundsAccessChain: - case SpvOpCopyObject: - // A load or store through a pointer. - assert(base_inst->IsValidBasePointer() && - "We cannot have a base pointer come from this load"); - break; - default: - // A load or store of an image. - assert(base_inst->IsValidBaseImage() && "We are expecting an image."); - break; - } return base_inst; } @@ -393,6 +372,11 @@ uint32_t Instruction::GetTypeComponent(uint32_t element) const { return subtype; } +Instruction* Instruction::InsertBefore(std::unique_ptr&& i) { + i.get()->InsertBefore(this); + return i.release(); +} + Instruction* Instruction::InsertBefore( std::vector>&& list) { Instruction* first_node = list.front().get(); @@ -403,11 +387,6 @@ Instruction* Instruction::InsertBefore( return first_node; } -Instruction* Instruction::InsertBefore(std::unique_ptr&& i) { - i.get()->InsertBefore(this); - return i.release(); -} - bool Instruction::IsValidBasePointer() const { uint32_t tid = type_id(); if (tid == 0) { @@ -490,7 +469,7 @@ bool Instruction::IsOpaqueType() const { bool Instruction::IsFoldable() const { return IsFoldableByFoldScalar() || - context()->get_instruction_folder().HasConstFoldingRule(opcode()); + context()->get_instruction_folder().HasConstFoldingRule(this); } bool Instruction::IsFoldableByFoldScalar() const { @@ -504,13 +483,23 @@ bool Instruction::IsFoldableByFoldScalar() const { bool Instruction::IsFloatingPointFoldingAllowed() const { // TODO: Add the rules for kernels. For now it will be pessimistic. - if (!context_->get_feature_mgr()->HasCapability(SpvCapabilityShader)) { + // For now, do not support capabilities introduced by SPV_KHR_float_controls. + if (!context_->get_feature_mgr()->HasCapability(SpvCapabilityShader) || + context_->get_feature_mgr()->HasCapability(SpvCapabilityDenormPreserve) || + context_->get_feature_mgr()->HasCapability( + SpvCapabilityDenormFlushToZero) || + context_->get_feature_mgr()->HasCapability( + SpvCapabilitySignedZeroInfNanPreserve) || + context_->get_feature_mgr()->HasCapability( + SpvCapabilityRoundingModeRTZ) || + context_->get_feature_mgr()->HasCapability( + SpvCapabilityRoundingModeRTE)) { return false; } bool is_nocontract = false; context_->get_decoration_mgr()->WhileEachDecoration( - opcode_, SpvDecorationNoContraction, + result_id(), SpvDecorationNoContraction, [&is_nocontract](const Instruction&) { is_nocontract = true; return false; @@ -540,6 +529,10 @@ std::ostream& operator<<(std::ostream& str, const Instruction& inst) { return str; } +void Instruction::Dump() const { + std::cerr << "Instruction #" << unique_id() << "\n" << *this << "\n"; +} + bool Instruction::IsOpcodeCodeMotionSafe() const { switch (opcode_) { case SpvOpNop: diff --git a/third_party/spirv-tools/source/opt/instruction.h b/third_party/spirv-tools/source/opt/instruction.h index 2533ba2723..322e0aac0c 100644 --- a/third_party/spirv-tools/source/opt/instruction.h +++ b/third_party/spirv-tools/source/opt/instruction.h @@ -172,6 +172,9 @@ class Instruction : public utils::IntrusiveNodeBase { return dbg_line_insts_; } + // Clear line-related debug instructions attached to this instruction. + void clear_dbg_line_insts() { dbg_line_insts_.clear(); } + // Same semantics as in the base class except the list the InstructionList // containing |pos| will now assume ownership of |this|. // inline void MoveBefore(Instruction* pos); @@ -349,6 +352,10 @@ class Instruction : public utils::IntrusiveNodeBase { // uniform buffer. bool IsVulkanUniformBuffer() const; + // Returns true if the instruction is an atom operation that uses original + // value. + inline bool IsAtomicWithLoad() const; + // Returns true if the instruction is an atom operation. inline bool IsAtomicOp() const; @@ -394,8 +401,13 @@ class Instruction : public utils::IntrusiveNodeBase { inline bool operator!=(const Instruction&) const; inline bool operator<(const Instruction&) const; - Instruction* InsertBefore(std::vector>&& list); + // Takes ownership of the instruction owned by |i| and inserts it immediately + // before |this|. Returns the inserted instruction. Instruction* InsertBefore(std::unique_ptr&& i); + // Takes ownership of the instructions in |list| and inserts them in order + // immediately before |this|. Returns the first inserted instruction. + // Assumes the list is non-empty. + Instruction* InsertBefore(std::vector>&& list); using utils::IntrusiveNodeBase::InsertBefore; // Returns true if |this| is an instruction defining a constant, but not a @@ -427,6 +439,10 @@ class Instruction : public utils::IntrusiveNodeBase { // rules for physical addressing. bool IsValidBasePointer() const; + // Dump this instruction on stderr. Useful when running interactive + // debuggers. + void Dump() const; + private: // Returns the total count of result type id and result id. uint32_t TypeResultIdCount() const { @@ -610,15 +626,8 @@ inline void Instruction::ForEachId( inline bool Instruction::WhileEachInId( const std::function& f) { for (auto& opnd : operands_) { - switch (opnd.type) { - case SPV_OPERAND_TYPE_RESULT_ID: - case SPV_OPERAND_TYPE_TYPE_ID: - break; - default: - if (spvIsIdType(opnd.type)) { - if (!f(&opnd.words[0])) return false; - } - break; + if (spvIsInIdType(opnd.type)) { + if (!f(&opnd.words[0])) return false; } } return true; @@ -627,15 +636,8 @@ inline bool Instruction::WhileEachInId( inline bool Instruction::WhileEachInId( const std::function& f) const { for (const auto& opnd : operands_) { - switch (opnd.type) { - case SPV_OPERAND_TYPE_RESULT_ID: - case SPV_OPERAND_TYPE_TYPE_ID: - break; - default: - if (spvIsIdType(opnd.type)) { - if (!f(&opnd.words[0])) return false; - } - break; + if (spvIsInIdType(opnd.type)) { + if (!f(&opnd.words[0])) return false; } } return true; @@ -724,6 +726,10 @@ bool Instruction::IsDecoration() const { bool Instruction::IsLoad() const { return spvOpcodeIsLoad(opcode()); } +bool Instruction::IsAtomicWithLoad() const { + return spvOpcodeIsAtomicWithLoad(opcode()); +} + bool Instruction::IsAtomicOp() const { return spvOpcodeIsAtomicOp(opcode()); } bool Instruction::IsConstant() const { diff --git a/third_party/spirv-tools/source/opt/instrument_pass.cpp b/third_party/spirv-tools/source/opt/instrument_pass.cpp new file mode 100644 index 0000000000..b1a6edb9de --- /dev/null +++ b/third_party/spirv-tools/source/opt/instrument_pass.cpp @@ -0,0 +1,1025 @@ +// Copyright (c) 2018 The Khronos Group Inc. +// Copyright (c) 2018 Valve Corporation +// Copyright (c) 2018 LunarG Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "instrument_pass.h" + +#include "source/cfa.h" +#include "source/spirv_constant.h" + +namespace { + +// Common Parameter Positions +static const int kInstCommonParamInstIdx = 0; +static const int kInstCommonParamCnt = 1; + +// Indices of operands in SPIR-V instructions +static const int kEntryPointExecutionModelInIdx = 0; +static const int kEntryPointFunctionIdInIdx = 1; + +} // anonymous namespace + +namespace spvtools { +namespace opt { + +void InstrumentPass::MovePreludeCode( + BasicBlock::iterator ref_inst_itr, + UptrVectorIterator ref_block_itr, + std::unique_ptr* new_blk_ptr) { + same_block_pre_.clear(); + same_block_post_.clear(); + // Initialize new block. Reuse label from original block. + new_blk_ptr->reset(new BasicBlock(std::move(ref_block_itr->GetLabel()))); + // Move contents of original ref block up to ref instruction. + for (auto cii = ref_block_itr->begin(); cii != ref_inst_itr; + cii = ref_block_itr->begin()) { + Instruction* inst = &*cii; + inst->RemoveFromList(); + std::unique_ptr mv_ptr(inst); + // Remember same-block ops for possible regeneration. + if (IsSameBlockOp(&*mv_ptr)) { + auto* sb_inst_ptr = mv_ptr.get(); + same_block_pre_[mv_ptr->result_id()] = sb_inst_ptr; + } + (*new_blk_ptr)->AddInstruction(std::move(mv_ptr)); + } +} + +void InstrumentPass::MovePostludeCode( + UptrVectorIterator ref_block_itr, BasicBlock* new_blk_ptr) { + // new_blk_ptr->reset(new BasicBlock(NewLabel(ref_block_itr->id()))); + // Move contents of original ref block. + for (auto cii = ref_block_itr->begin(); cii != ref_block_itr->end(); + cii = ref_block_itr->begin()) { + Instruction* inst = &*cii; + inst->RemoveFromList(); + std::unique_ptr mv_inst(inst); + // Regenerate any same-block instruction that has not been seen in the + // current block. + if (same_block_pre_.size() > 0) { + CloneSameBlockOps(&mv_inst, &same_block_post_, &same_block_pre_, + new_blk_ptr); + // Remember same-block ops in this block. + if (IsSameBlockOp(&*mv_inst)) { + const uint32_t rid = mv_inst->result_id(); + same_block_post_[rid] = rid; + } + } + new_blk_ptr->AddInstruction(std::move(mv_inst)); + } +} + +std::unique_ptr InstrumentPass::NewLabel(uint32_t label_id) { + std::unique_ptr newLabel( + new Instruction(context(), SpvOpLabel, 0, label_id, {})); + get_def_use_mgr()->AnalyzeInstDefUse(&*newLabel); + return newLabel; +} + +uint32_t InstrumentPass::GenUintCastCode(uint32_t val_id, + InstructionBuilder* builder) { + // Cast value to 32-bit unsigned if necessary + if (get_def_use_mgr()->GetDef(val_id)->type_id() == GetUintId()) + return val_id; + return builder->AddUnaryOp(GetUintId(), SpvOpBitcast, val_id)->result_id(); +} + +void InstrumentPass::GenDebugOutputFieldCode(uint32_t base_offset_id, + uint32_t field_offset, + uint32_t field_value_id, + InstructionBuilder* builder) { + // Cast value to 32-bit unsigned if necessary + uint32_t val_id = GenUintCastCode(field_value_id, builder); + // Store value + Instruction* data_idx_inst = + builder->AddBinaryOp(GetUintId(), SpvOpIAdd, base_offset_id, + builder->GetUintConstantId(field_offset)); + uint32_t buf_id = GetOutputBufferId(); + uint32_t buf_uint_ptr_id = GetOutputBufferPtrId(); + Instruction* achain_inst = + builder->AddTernaryOp(buf_uint_ptr_id, SpvOpAccessChain, buf_id, + builder->GetUintConstantId(kDebugOutputDataOffset), + data_idx_inst->result_id()); + (void)builder->AddBinaryOp(0, SpvOpStore, achain_inst->result_id(), val_id); +} + +void InstrumentPass::GenCommonStreamWriteCode(uint32_t record_sz, + uint32_t inst_id, + uint32_t stage_idx, + uint32_t base_offset_id, + InstructionBuilder* builder) { + // Store record size + GenDebugOutputFieldCode(base_offset_id, kInstCommonOutSize, + builder->GetUintConstantId(record_sz), builder); + // Store Shader Id + GenDebugOutputFieldCode(base_offset_id, kInstCommonOutShaderId, + builder->GetUintConstantId(shader_id_), builder); + // Store Instruction Idx + GenDebugOutputFieldCode(base_offset_id, kInstCommonOutInstructionIdx, inst_id, + builder); + // Store Stage Idx + GenDebugOutputFieldCode(base_offset_id, kInstCommonOutStageIdx, + builder->GetUintConstantId(stage_idx), builder); +} + +void InstrumentPass::GenFragCoordEltDebugOutputCode( + uint32_t base_offset_id, uint32_t uint_frag_coord_id, uint32_t element, + InstructionBuilder* builder) { + Instruction* element_val_inst = builder->AddIdLiteralOp( + GetUintId(), SpvOpCompositeExtract, uint_frag_coord_id, element); + GenDebugOutputFieldCode(base_offset_id, kInstFragOutFragCoordX + element, + element_val_inst->result_id(), builder); +} + +uint32_t InstrumentPass::GenVarLoad(uint32_t var_id, + InstructionBuilder* builder) { + Instruction* var_inst = get_def_use_mgr()->GetDef(var_id); + uint32_t type_id = GetPointeeTypeId(var_inst); + Instruction* load_inst = builder->AddUnaryOp(type_id, SpvOpLoad, var_id); + return load_inst->result_id(); +} + +void InstrumentPass::GenBuiltinOutputCode(uint32_t builtin_id, + uint32_t builtin_off, + uint32_t base_offset_id, + InstructionBuilder* builder) { + // Load and store builtin + uint32_t load_id = GenVarLoad(builtin_id, builder); + GenDebugOutputFieldCode(base_offset_id, builtin_off, load_id, builder); +} + +void InstrumentPass::GenStageStreamWriteCode(uint32_t stage_idx, + uint32_t base_offset_id, + InstructionBuilder* builder) { + // TODO(greg-lunarg): Add support for all stages + switch (stage_idx) { + case SpvExecutionModelVertex: { + // Load and store VertexId and InstanceId + GenBuiltinOutputCode( + context()->GetBuiltinInputVarId(SpvBuiltInVertexIndex), + kInstVertOutVertexIndex, base_offset_id, builder); + GenBuiltinOutputCode( + context()->GetBuiltinInputVarId(SpvBuiltInInstanceIndex), + kInstVertOutInstanceIndex, base_offset_id, builder); + } break; + case SpvExecutionModelGLCompute: { + // Load and store GlobalInvocationId. + uint32_t load_id = GenVarLoad( + context()->GetBuiltinInputVarId(SpvBuiltInGlobalInvocationId), + builder); + Instruction* x_inst = builder->AddIdLiteralOp( + GetUintId(), SpvOpCompositeExtract, load_id, 0); + Instruction* y_inst = builder->AddIdLiteralOp( + GetUintId(), SpvOpCompositeExtract, load_id, 1); + Instruction* z_inst = builder->AddIdLiteralOp( + GetUintId(), SpvOpCompositeExtract, load_id, 2); + GenDebugOutputFieldCode(base_offset_id, kInstCompOutGlobalInvocationIdX, + x_inst->result_id(), builder); + GenDebugOutputFieldCode(base_offset_id, kInstCompOutGlobalInvocationIdY, + y_inst->result_id(), builder); + GenDebugOutputFieldCode(base_offset_id, kInstCompOutGlobalInvocationIdZ, + z_inst->result_id(), builder); + } break; + case SpvExecutionModelGeometry: { + // Load and store PrimitiveId and InvocationId. + GenBuiltinOutputCode( + context()->GetBuiltinInputVarId(SpvBuiltInPrimitiveId), + kInstGeomOutPrimitiveId, base_offset_id, builder); + GenBuiltinOutputCode( + context()->GetBuiltinInputVarId(SpvBuiltInInvocationId), + kInstGeomOutInvocationId, base_offset_id, builder); + } break; + case SpvExecutionModelTessellationControl: { + // Load and store InvocationId and PrimitiveId + GenBuiltinOutputCode( + context()->GetBuiltinInputVarId(SpvBuiltInInvocationId), + kInstTessCtlOutInvocationId, base_offset_id, builder); + GenBuiltinOutputCode( + context()->GetBuiltinInputVarId(SpvBuiltInPrimitiveId), + kInstTessCtlOutPrimitiveId, base_offset_id, builder); + } break; + case SpvExecutionModelTessellationEvaluation: { + // Load and store PrimitiveId and TessCoord.uv + GenBuiltinOutputCode( + context()->GetBuiltinInputVarId(SpvBuiltInPrimitiveId), + kInstTessEvalOutPrimitiveId, base_offset_id, builder); + uint32_t load_id = GenVarLoad( + context()->GetBuiltinInputVarId(SpvBuiltInTessCoord), builder); + Instruction* uvec3_cast_inst = + builder->AddUnaryOp(GetVec3UintId(), SpvOpBitcast, load_id); + uint32_t uvec3_cast_id = uvec3_cast_inst->result_id(); + Instruction* u_inst = builder->AddIdLiteralOp( + GetUintId(), SpvOpCompositeExtract, uvec3_cast_id, 0); + Instruction* v_inst = builder->AddIdLiteralOp( + GetUintId(), SpvOpCompositeExtract, uvec3_cast_id, 1); + GenDebugOutputFieldCode(base_offset_id, kInstTessEvalOutTessCoordU, + u_inst->result_id(), builder); + GenDebugOutputFieldCode(base_offset_id, kInstTessEvalOutTessCoordV, + v_inst->result_id(), builder); + } break; + case SpvExecutionModelFragment: { + // Load FragCoord and convert to Uint + Instruction* frag_coord_inst = builder->AddUnaryOp( + GetVec4FloatId(), SpvOpLoad, + context()->GetBuiltinInputVarId(SpvBuiltInFragCoord)); + Instruction* uint_frag_coord_inst = builder->AddUnaryOp( + GetVec4UintId(), SpvOpBitcast, frag_coord_inst->result_id()); + for (uint32_t u = 0; u < 2u; ++u) + GenFragCoordEltDebugOutputCode( + base_offset_id, uint_frag_coord_inst->result_id(), u, builder); + } break; + case SpvExecutionModelRayGenerationNV: + case SpvExecutionModelIntersectionNV: + case SpvExecutionModelAnyHitNV: + case SpvExecutionModelClosestHitNV: + case SpvExecutionModelMissNV: + case SpvExecutionModelCallableNV: { + // Load and store LaunchIdNV. + uint32_t launch_id = GenVarLoad( + context()->GetBuiltinInputVarId(SpvBuiltInLaunchIdNV), builder); + Instruction* x_launch_inst = builder->AddIdLiteralOp( + GetUintId(), SpvOpCompositeExtract, launch_id, 0); + Instruction* y_launch_inst = builder->AddIdLiteralOp( + GetUintId(), SpvOpCompositeExtract, launch_id, 1); + Instruction* z_launch_inst = builder->AddIdLiteralOp( + GetUintId(), SpvOpCompositeExtract, launch_id, 2); + GenDebugOutputFieldCode(base_offset_id, kInstRayTracingOutLaunchIdX, + x_launch_inst->result_id(), builder); + GenDebugOutputFieldCode(base_offset_id, kInstRayTracingOutLaunchIdY, + y_launch_inst->result_id(), builder); + GenDebugOutputFieldCode(base_offset_id, kInstRayTracingOutLaunchIdZ, + z_launch_inst->result_id(), builder); + } break; + default: { assert(false && "unsupported stage"); } break; + } +} + +void InstrumentPass::GenDebugStreamWrite( + uint32_t instruction_idx, uint32_t stage_idx, + const std::vector& validation_ids, InstructionBuilder* builder) { + // Call debug output function. Pass func_idx, instruction_idx and + // validation ids as args. + uint32_t val_id_cnt = static_cast(validation_ids.size()); + uint32_t output_func_id = GetStreamWriteFunctionId(stage_idx, val_id_cnt); + std::vector args = {output_func_id, + builder->GetUintConstantId(instruction_idx)}; + (void)args.insert(args.end(), validation_ids.begin(), validation_ids.end()); + (void)builder->AddNaryOp(GetVoidId(), SpvOpFunctionCall, args); +} + +uint32_t InstrumentPass::GenDebugDirectRead( + const std::vector& offset_ids, InstructionBuilder* builder) { + // Call debug input function. Pass func_idx and offset ids as args. + uint32_t off_id_cnt = static_cast(offset_ids.size()); + uint32_t input_func_id = GetDirectReadFunctionId(off_id_cnt); + std::vector args = {input_func_id}; + (void)args.insert(args.end(), offset_ids.begin(), offset_ids.end()); + return builder->AddNaryOp(GetUintId(), SpvOpFunctionCall, args)->result_id(); +} + +bool InstrumentPass::IsSameBlockOp(const Instruction* inst) const { + return inst->opcode() == SpvOpSampledImage || inst->opcode() == SpvOpImage; +} + +void InstrumentPass::CloneSameBlockOps( + std::unique_ptr* inst, + std::unordered_map* same_blk_post, + std::unordered_map* same_blk_pre, + BasicBlock* block_ptr) { + bool changed = false; + (*inst)->ForEachInId([&same_blk_post, &same_blk_pre, &block_ptr, &changed, + this](uint32_t* iid) { + const auto map_itr = (*same_blk_post).find(*iid); + if (map_itr == (*same_blk_post).end()) { + const auto map_itr2 = (*same_blk_pre).find(*iid); + if (map_itr2 != (*same_blk_pre).end()) { + // Clone pre-call same-block ops, map result id. + const Instruction* in_inst = map_itr2->second; + std::unique_ptr sb_inst(in_inst->Clone(context())); + const uint32_t rid = sb_inst->result_id(); + const uint32_t nid = this->TakeNextId(); + get_decoration_mgr()->CloneDecorations(rid, nid); + sb_inst->SetResultId(nid); + get_def_use_mgr()->AnalyzeInstDefUse(&*sb_inst); + (*same_blk_post)[rid] = nid; + *iid = nid; + changed = true; + CloneSameBlockOps(&sb_inst, same_blk_post, same_blk_pre, block_ptr); + block_ptr->AddInstruction(std::move(sb_inst)); + } + } else { + // Reset same-block op operand if necessary + if (*iid != map_itr->second) { + *iid = map_itr->second; + changed = true; + } + } + }); + if (changed) get_def_use_mgr()->AnalyzeInstUse(&**inst); +} + +void InstrumentPass::UpdateSucceedingPhis( + std::vector>& new_blocks) { + const auto first_blk = new_blocks.begin(); + const auto last_blk = new_blocks.end() - 1; + const uint32_t first_id = (*first_blk)->id(); + const uint32_t last_id = (*last_blk)->id(); + const BasicBlock& const_last_block = *last_blk->get(); + const_last_block.ForEachSuccessorLabel( + [&first_id, &last_id, this](const uint32_t succ) { + BasicBlock* sbp = this->id2block_[succ]; + sbp->ForEachPhiInst([&first_id, &last_id, this](Instruction* phi) { + bool changed = false; + phi->ForEachInId([&first_id, &last_id, &changed](uint32_t* id) { + if (*id == first_id) { + *id = last_id; + changed = true; + } + }); + if (changed) get_def_use_mgr()->AnalyzeInstUse(phi); + }); + }); +} + +uint32_t InstrumentPass::GetOutputBufferPtrId() { + if (output_buffer_ptr_id_ == 0) { + output_buffer_ptr_id_ = context()->get_type_mgr()->FindPointerToType( + GetUintId(), SpvStorageClassStorageBuffer); + } + return output_buffer_ptr_id_; +} + +uint32_t InstrumentPass::GetInputBufferTypeId() { + return (validation_id_ == kInstValidationIdBuffAddr) ? GetUint64Id() + : GetUintId(); +} + +uint32_t InstrumentPass::GetInputBufferPtrId() { + if (input_buffer_ptr_id_ == 0) { + input_buffer_ptr_id_ = context()->get_type_mgr()->FindPointerToType( + GetInputBufferTypeId(), SpvStorageClassStorageBuffer); + } + return input_buffer_ptr_id_; +} + +uint32_t InstrumentPass::GetOutputBufferBinding() { + switch (validation_id_) { + case kInstValidationIdBindless: + return kDebugOutputBindingStream; + case kInstValidationIdBuffAddr: + return kDebugOutputBindingStream; + default: + assert(false && "unexpected validation id"); + } + return 0; +} + +uint32_t InstrumentPass::GetInputBufferBinding() { + switch (validation_id_) { + case kInstValidationIdBindless: + return kDebugInputBindingBindless; + case kInstValidationIdBuffAddr: + return kDebugInputBindingBuffAddr; + default: + assert(false && "unexpected validation id"); + } + return 0; +} + +analysis::Type* InstrumentPass::GetUintXRuntimeArrayType( + uint32_t width, analysis::Type** rarr_ty) { + if (*rarr_ty == nullptr) { + analysis::DecorationManager* deco_mgr = get_decoration_mgr(); + analysis::TypeManager* type_mgr = context()->get_type_mgr(); + analysis::Integer uint_ty(width, false); + analysis::Type* reg_uint_ty = type_mgr->GetRegisteredType(&uint_ty); + analysis::RuntimeArray uint_rarr_ty_tmp(reg_uint_ty); + *rarr_ty = type_mgr->GetRegisteredType(&uint_rarr_ty_tmp); + uint32_t uint_arr_ty_id = type_mgr->GetTypeInstruction(*rarr_ty); + // By the Vulkan spec, a pre-existing RuntimeArray of uint must be part of + // a block, and will therefore be decorated with an ArrayStride. Therefore + // the undecorated type returned here will not be pre-existing and can + // safely be decorated. Since this type is now decorated, it is out of + // sync with the TypeManager and therefore the TypeManager must be + // invalidated after this pass. + assert(context()->get_def_use_mgr()->NumUses(uint_arr_ty_id) == 0 && + "used RuntimeArray type returned"); + deco_mgr->AddDecorationVal(uint_arr_ty_id, SpvDecorationArrayStride, + width / 8u); + } + return *rarr_ty; +} + +analysis::Type* InstrumentPass::GetUintRuntimeArrayType(uint32_t width) { + analysis::Type** rarr_ty = + (width == 64) ? &uint64_rarr_ty_ : &uint32_rarr_ty_; + return GetUintXRuntimeArrayType(width, rarr_ty); +} + +void InstrumentPass::AddStorageBufferExt() { + if (storage_buffer_ext_defined_) return; + if (!get_feature_mgr()->HasExtension(kSPV_KHR_storage_buffer_storage_class)) { + context()->AddExtension("SPV_KHR_storage_buffer_storage_class"); + } + storage_buffer_ext_defined_ = true; +} + +// Return id for output buffer +uint32_t InstrumentPass::GetOutputBufferId() { + if (output_buffer_id_ == 0) { + // If not created yet, create one + analysis::DecorationManager* deco_mgr = get_decoration_mgr(); + analysis::TypeManager* type_mgr = context()->get_type_mgr(); + analysis::Type* reg_uint_rarr_ty = GetUintRuntimeArrayType(32); + analysis::Integer uint_ty(32, false); + analysis::Type* reg_uint_ty = type_mgr->GetRegisteredType(&uint_ty); + analysis::Struct buf_ty({reg_uint_ty, reg_uint_rarr_ty}); + analysis::Type* reg_buf_ty = type_mgr->GetRegisteredType(&buf_ty); + uint32_t obufTyId = type_mgr->GetTypeInstruction(reg_buf_ty); + // By the Vulkan spec, a pre-existing struct containing a RuntimeArray + // must be a block, and will therefore be decorated with Block. Therefore + // the undecorated type returned here will not be pre-existing and can + // safely be decorated. Since this type is now decorated, it is out of + // sync with the TypeManager and therefore the TypeManager must be + // invalidated after this pass. + assert(context()->get_def_use_mgr()->NumUses(obufTyId) == 0 && + "used struct type returned"); + deco_mgr->AddDecoration(obufTyId, SpvDecorationBlock); + deco_mgr->AddMemberDecoration(obufTyId, kDebugOutputSizeOffset, + SpvDecorationOffset, 0); + deco_mgr->AddMemberDecoration(obufTyId, kDebugOutputDataOffset, + SpvDecorationOffset, 4); + uint32_t obufTyPtrId_ = + type_mgr->FindPointerToType(obufTyId, SpvStorageClassStorageBuffer); + output_buffer_id_ = TakeNextId(); + std::unique_ptr newVarOp(new Instruction( + context(), SpvOpVariable, obufTyPtrId_, output_buffer_id_, + {{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, + {SpvStorageClassStorageBuffer}}})); + context()->AddGlobalValue(std::move(newVarOp)); + deco_mgr->AddDecorationVal(output_buffer_id_, SpvDecorationDescriptorSet, + desc_set_); + deco_mgr->AddDecorationVal(output_buffer_id_, SpvDecorationBinding, + GetOutputBufferBinding()); + AddStorageBufferExt(); + if (get_module()->version() >= SPV_SPIRV_VERSION_WORD(1, 4)) { + // Add the new buffer to all entry points. + for (auto& entry : get_module()->entry_points()) { + entry.AddOperand({SPV_OPERAND_TYPE_ID, {output_buffer_id_}}); + context()->AnalyzeUses(&entry); + } + } + } + return output_buffer_id_; +} + +uint32_t InstrumentPass::GetInputBufferId() { + if (input_buffer_id_ == 0) { + // If not created yet, create one + analysis::DecorationManager* deco_mgr = get_decoration_mgr(); + analysis::TypeManager* type_mgr = context()->get_type_mgr(); + uint32_t width = (validation_id_ == kInstValidationIdBuffAddr) ? 64u : 32u; + analysis::Type* reg_uint_rarr_ty = GetUintRuntimeArrayType(width); + analysis::Struct buf_ty({reg_uint_rarr_ty}); + analysis::Type* reg_buf_ty = type_mgr->GetRegisteredType(&buf_ty); + uint32_t ibufTyId = type_mgr->GetTypeInstruction(reg_buf_ty); + // By the Vulkan spec, a pre-existing struct containing a RuntimeArray + // must be a block, and will therefore be decorated with Block. Therefore + // the undecorated type returned here will not be pre-existing and can + // safely be decorated. Since this type is now decorated, it is out of + // sync with the TypeManager and therefore the TypeManager must be + // invalidated after this pass. + assert(context()->get_def_use_mgr()->NumUses(ibufTyId) == 0 && + "used struct type returned"); + deco_mgr->AddDecoration(ibufTyId, SpvDecorationBlock); + deco_mgr->AddMemberDecoration(ibufTyId, 0, SpvDecorationOffset, 0); + uint32_t ibufTyPtrId_ = + type_mgr->FindPointerToType(ibufTyId, SpvStorageClassStorageBuffer); + input_buffer_id_ = TakeNextId(); + std::unique_ptr newVarOp(new Instruction( + context(), SpvOpVariable, ibufTyPtrId_, input_buffer_id_, + {{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, + {SpvStorageClassStorageBuffer}}})); + context()->AddGlobalValue(std::move(newVarOp)); + deco_mgr->AddDecorationVal(input_buffer_id_, SpvDecorationDescriptorSet, + desc_set_); + deco_mgr->AddDecorationVal(input_buffer_id_, SpvDecorationBinding, + GetInputBufferBinding()); + AddStorageBufferExt(); + if (get_module()->version() >= SPV_SPIRV_VERSION_WORD(1, 4)) { + // Add the new buffer to all entry points. + for (auto& entry : get_module()->entry_points()) { + entry.AddOperand({SPV_OPERAND_TYPE_ID, {input_buffer_id_}}); + context()->AnalyzeUses(&entry); + } + } + } + return input_buffer_id_; +} + +uint32_t InstrumentPass::GetVec4FloatId() { + if (v4float_id_ == 0) { + analysis::TypeManager* type_mgr = context()->get_type_mgr(); + analysis::Float float_ty(32); + analysis::Type* reg_float_ty = type_mgr->GetRegisteredType(&float_ty); + analysis::Vector v4float_ty(reg_float_ty, 4); + analysis::Type* reg_v4float_ty = type_mgr->GetRegisteredType(&v4float_ty); + v4float_id_ = type_mgr->GetTypeInstruction(reg_v4float_ty); + } + return v4float_id_; +} + +uint32_t InstrumentPass::GetUintId() { + if (uint_id_ == 0) { + analysis::TypeManager* type_mgr = context()->get_type_mgr(); + analysis::Integer uint_ty(32, false); + analysis::Type* reg_uint_ty = type_mgr->GetRegisteredType(&uint_ty); + uint_id_ = type_mgr->GetTypeInstruction(reg_uint_ty); + } + return uint_id_; +} + +uint32_t InstrumentPass::GetUint64Id() { + if (uint64_id_ == 0) { + analysis::TypeManager* type_mgr = context()->get_type_mgr(); + analysis::Integer uint64_ty(64, false); + analysis::Type* reg_uint64_ty = type_mgr->GetRegisteredType(&uint64_ty); + uint64_id_ = type_mgr->GetTypeInstruction(reg_uint64_ty); + } + return uint64_id_; +} + +uint32_t InstrumentPass::GetVecUintId(uint32_t len) { + analysis::TypeManager* type_mgr = context()->get_type_mgr(); + analysis::Integer uint_ty(32, false); + analysis::Type* reg_uint_ty = type_mgr->GetRegisteredType(&uint_ty); + analysis::Vector v_uint_ty(reg_uint_ty, len); + analysis::Type* reg_v_uint_ty = type_mgr->GetRegisteredType(&v_uint_ty); + uint32_t v_uint_id = type_mgr->GetTypeInstruction(reg_v_uint_ty); + return v_uint_id; +} + +uint32_t InstrumentPass::GetVec4UintId() { + if (v4uint_id_ == 0) v4uint_id_ = GetVecUintId(4u); + return v4uint_id_; +} + +uint32_t InstrumentPass::GetVec3UintId() { + if (v3uint_id_ == 0) v3uint_id_ = GetVecUintId(3u); + return v3uint_id_; +} + +uint32_t InstrumentPass::GetBoolId() { + if (bool_id_ == 0) { + analysis::TypeManager* type_mgr = context()->get_type_mgr(); + analysis::Bool bool_ty; + analysis::Type* reg_bool_ty = type_mgr->GetRegisteredType(&bool_ty); + bool_id_ = type_mgr->GetTypeInstruction(reg_bool_ty); + } + return bool_id_; +} + +uint32_t InstrumentPass::GetVoidId() { + if (void_id_ == 0) { + analysis::TypeManager* type_mgr = context()->get_type_mgr(); + analysis::Void void_ty; + analysis::Type* reg_void_ty = type_mgr->GetRegisteredType(&void_ty); + void_id_ = type_mgr->GetTypeInstruction(reg_void_ty); + } + return void_id_; +} + +uint32_t InstrumentPass::GetStreamWriteFunctionId(uint32_t stage_idx, + uint32_t val_spec_param_cnt) { + // Total param count is common params plus validation-specific + // params + uint32_t param_cnt = kInstCommonParamCnt + val_spec_param_cnt; + if (output_func_id_ == 0) { + // Create function + output_func_id_ = TakeNextId(); + analysis::TypeManager* type_mgr = context()->get_type_mgr(); + std::vector param_types; + for (uint32_t c = 0; c < param_cnt; ++c) + param_types.push_back(type_mgr->GetType(GetUintId())); + analysis::Function func_ty(type_mgr->GetType(GetVoidId()), param_types); + analysis::Type* reg_func_ty = type_mgr->GetRegisteredType(&func_ty); + std::unique_ptr func_inst(new Instruction( + get_module()->context(), SpvOpFunction, GetVoidId(), output_func_id_, + {{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, + {SpvFunctionControlMaskNone}}, + {spv_operand_type_t::SPV_OPERAND_TYPE_ID, + {type_mgr->GetTypeInstruction(reg_func_ty)}}})); + get_def_use_mgr()->AnalyzeInstDefUse(&*func_inst); + std::unique_ptr output_func = + MakeUnique(std::move(func_inst)); + // Add parameters + std::vector param_vec; + for (uint32_t c = 0; c < param_cnt; ++c) { + uint32_t pid = TakeNextId(); + param_vec.push_back(pid); + std::unique_ptr param_inst( + new Instruction(get_module()->context(), SpvOpFunctionParameter, + GetUintId(), pid, {})); + get_def_use_mgr()->AnalyzeInstDefUse(&*param_inst); + output_func->AddParameter(std::move(param_inst)); + } + // Create first block + uint32_t test_blk_id = TakeNextId(); + std::unique_ptr test_label(NewLabel(test_blk_id)); + std::unique_ptr new_blk_ptr = + MakeUnique(std::move(test_label)); + InstructionBuilder builder( + context(), &*new_blk_ptr, + IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping); + // Gen test if debug output buffer size will not be exceeded. + uint32_t val_spec_offset = kInstStageOutCnt; + uint32_t obuf_record_sz = val_spec_offset + val_spec_param_cnt; + uint32_t buf_id = GetOutputBufferId(); + uint32_t buf_uint_ptr_id = GetOutputBufferPtrId(); + Instruction* obuf_curr_sz_ac_inst = + builder.AddBinaryOp(buf_uint_ptr_id, SpvOpAccessChain, buf_id, + builder.GetUintConstantId(kDebugOutputSizeOffset)); + // Fetch the current debug buffer written size atomically, adding the + // size of the record to be written. + uint32_t obuf_record_sz_id = builder.GetUintConstantId(obuf_record_sz); + uint32_t mask_none_id = builder.GetUintConstantId(SpvMemoryAccessMaskNone); + uint32_t scope_invok_id = builder.GetUintConstantId(SpvScopeInvocation); + Instruction* obuf_curr_sz_inst = builder.AddQuadOp( + GetUintId(), SpvOpAtomicIAdd, obuf_curr_sz_ac_inst->result_id(), + scope_invok_id, mask_none_id, obuf_record_sz_id); + uint32_t obuf_curr_sz_id = obuf_curr_sz_inst->result_id(); + // Compute new written size + Instruction* obuf_new_sz_inst = + builder.AddBinaryOp(GetUintId(), SpvOpIAdd, obuf_curr_sz_id, + builder.GetUintConstantId(obuf_record_sz)); + // Fetch the data bound + Instruction* obuf_bnd_inst = + builder.AddIdLiteralOp(GetUintId(), SpvOpArrayLength, + GetOutputBufferId(), kDebugOutputDataOffset); + // Test that new written size is less than or equal to debug output + // data bound + Instruction* obuf_safe_inst = builder.AddBinaryOp( + GetBoolId(), SpvOpULessThanEqual, obuf_new_sz_inst->result_id(), + obuf_bnd_inst->result_id()); + uint32_t merge_blk_id = TakeNextId(); + uint32_t write_blk_id = TakeNextId(); + std::unique_ptr merge_label(NewLabel(merge_blk_id)); + std::unique_ptr write_label(NewLabel(write_blk_id)); + (void)builder.AddConditionalBranch(obuf_safe_inst->result_id(), + write_blk_id, merge_blk_id, merge_blk_id, + SpvSelectionControlMaskNone); + // Close safety test block and gen write block + new_blk_ptr->SetParent(&*output_func); + output_func->AddBasicBlock(std::move(new_blk_ptr)); + new_blk_ptr = MakeUnique(std::move(write_label)); + builder.SetInsertPoint(&*new_blk_ptr); + // Generate common and stage-specific debug record members + GenCommonStreamWriteCode(obuf_record_sz, param_vec[kInstCommonParamInstIdx], + stage_idx, obuf_curr_sz_id, &builder); + GenStageStreamWriteCode(stage_idx, obuf_curr_sz_id, &builder); + // Gen writes of validation specific data + for (uint32_t i = 0; i < val_spec_param_cnt; ++i) { + GenDebugOutputFieldCode(obuf_curr_sz_id, val_spec_offset + i, + param_vec[kInstCommonParamCnt + i], &builder); + } + // Close write block and gen merge block + (void)builder.AddBranch(merge_blk_id); + new_blk_ptr->SetParent(&*output_func); + output_func->AddBasicBlock(std::move(new_blk_ptr)); + new_blk_ptr = MakeUnique(std::move(merge_label)); + builder.SetInsertPoint(&*new_blk_ptr); + // Close merge block and function and add function to module + (void)builder.AddNullaryOp(0, SpvOpReturn); + new_blk_ptr->SetParent(&*output_func); + output_func->AddBasicBlock(std::move(new_blk_ptr)); + std::unique_ptr func_end_inst( + new Instruction(get_module()->context(), SpvOpFunctionEnd, 0, 0, {})); + get_def_use_mgr()->AnalyzeInstDefUse(&*func_end_inst); + output_func->SetFunctionEnd(std::move(func_end_inst)); + context()->AddFunction(std::move(output_func)); + output_func_param_cnt_ = param_cnt; + } + assert(param_cnt == output_func_param_cnt_ && "bad arg count"); + return output_func_id_; +} + +uint32_t InstrumentPass::GetDirectReadFunctionId(uint32_t param_cnt) { + uint32_t func_id = param2input_func_id_[param_cnt]; + if (func_id != 0) return func_id; + // Create input function for param_cnt. + func_id = TakeNextId(); + analysis::TypeManager* type_mgr = context()->get_type_mgr(); + std::vector param_types; + for (uint32_t c = 0; c < param_cnt; ++c) + param_types.push_back(type_mgr->GetType(GetUintId())); + uint32_t ibuf_type_id = GetInputBufferTypeId(); + analysis::Function func_ty(type_mgr->GetType(ibuf_type_id), param_types); + analysis::Type* reg_func_ty = type_mgr->GetRegisteredType(&func_ty); + std::unique_ptr func_inst(new Instruction( + get_module()->context(), SpvOpFunction, ibuf_type_id, func_id, + {{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, + {SpvFunctionControlMaskNone}}, + {spv_operand_type_t::SPV_OPERAND_TYPE_ID, + {type_mgr->GetTypeInstruction(reg_func_ty)}}})); + get_def_use_mgr()->AnalyzeInstDefUse(&*func_inst); + std::unique_ptr input_func = + MakeUnique(std::move(func_inst)); + // Add parameters + std::vector param_vec; + for (uint32_t c = 0; c < param_cnt; ++c) { + uint32_t pid = TakeNextId(); + param_vec.push_back(pid); + std::unique_ptr param_inst(new Instruction( + get_module()->context(), SpvOpFunctionParameter, GetUintId(), pid, {})); + get_def_use_mgr()->AnalyzeInstDefUse(&*param_inst); + input_func->AddParameter(std::move(param_inst)); + } + // Create block + uint32_t blk_id = TakeNextId(); + std::unique_ptr blk_label(NewLabel(blk_id)); + std::unique_ptr new_blk_ptr = + MakeUnique(std::move(blk_label)); + InstructionBuilder builder( + context(), &*new_blk_ptr, + IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping); + // For each offset parameter, generate new offset with parameter, adding last + // loaded value if it exists, and load value from input buffer at new offset. + // Return last loaded value. + uint32_t buf_id = GetInputBufferId(); + uint32_t buf_ptr_id = GetInputBufferPtrId(); + uint32_t last_value_id = 0; + for (uint32_t p = 0; p < param_cnt; ++p) { + uint32_t offset_id; + if (p == 0) { + offset_id = param_vec[0]; + } else { + if (ibuf_type_id != GetUintId()) { + Instruction* ucvt_inst = + builder.AddUnaryOp(GetUintId(), SpvOpUConvert, last_value_id); + last_value_id = ucvt_inst->result_id(); + } + Instruction* offset_inst = builder.AddBinaryOp( + GetUintId(), SpvOpIAdd, last_value_id, param_vec[p]); + offset_id = offset_inst->result_id(); + } + Instruction* ac_inst = builder.AddTernaryOp( + buf_ptr_id, SpvOpAccessChain, buf_id, + builder.GetUintConstantId(kDebugInputDataOffset), offset_id); + Instruction* load_inst = + builder.AddUnaryOp(ibuf_type_id, SpvOpLoad, ac_inst->result_id()); + last_value_id = load_inst->result_id(); + } + (void)builder.AddInstruction(MakeUnique( + context(), SpvOpReturnValue, 0, 0, + std::initializer_list{{SPV_OPERAND_TYPE_ID, {last_value_id}}})); + // Close block and function and add function to module + new_blk_ptr->SetParent(&*input_func); + input_func->AddBasicBlock(std::move(new_blk_ptr)); + std::unique_ptr func_end_inst( + new Instruction(get_module()->context(), SpvOpFunctionEnd, 0, 0, {})); + get_def_use_mgr()->AnalyzeInstDefUse(&*func_end_inst); + input_func->SetFunctionEnd(std::move(func_end_inst)); + context()->AddFunction(std::move(input_func)); + param2input_func_id_[param_cnt] = func_id; + return func_id; +} + +bool InstrumentPass::InstrumentFunction(Function* func, uint32_t stage_idx, + InstProcessFunction& pfn) { + bool modified = false; + // Compute function index + uint32_t function_idx = 0; + for (auto fii = get_module()->begin(); fii != get_module()->end(); ++fii) { + if (&*fii == func) break; + ++function_idx; + } + std::vector> new_blks; + // Using block iterators here because of block erasures and insertions. + for (auto bi = func->begin(); bi != func->end(); ++bi) { + for (auto ii = bi->begin(); ii != bi->end();) { + // Generate instrumentation if warranted + pfn(ii, bi, stage_idx, &new_blks); + if (new_blks.size() == 0) { + ++ii; + continue; + } + // Add new blocks to label id map + for (auto& blk : new_blks) id2block_[blk->id()] = &*blk; + // If there are new blocks we know there will always be two or + // more, so update succeeding phis with label of new last block. + size_t newBlocksSize = new_blks.size(); + assert(newBlocksSize > 1); + UpdateSucceedingPhis(new_blks); + // Replace original block with new block(s) + bi = bi.Erase(); + for (auto& bb : new_blks) { + bb->SetParent(func); + } + bi = bi.InsertBefore(&new_blks); + // Reset block iterator to last new block + for (size_t i = 0; i < newBlocksSize - 1; i++) ++bi; + modified = true; + // Restart instrumenting at beginning of last new block, + // but skip over any new phi or copy instruction. + ii = bi->begin(); + if (ii->opcode() == SpvOpPhi || ii->opcode() == SpvOpCopyObject) ++ii; + new_blks.clear(); + } + } + return modified; +} + +bool InstrumentPass::InstProcessCallTreeFromRoots(InstProcessFunction& pfn, + std::queue* roots, + uint32_t stage_idx) { + bool modified = false; + std::unordered_set done; + // Don't process input and output functions + for (auto& ifn : param2input_func_id_) done.insert(ifn.second); + if (output_func_id_ != 0) done.insert(output_func_id_); + // Process all functions from roots + while (!roots->empty()) { + const uint32_t fi = roots->front(); + roots->pop(); + if (done.insert(fi).second) { + Function* fn = id2function_.at(fi); + // Add calls first so we don't add new output function + context()->AddCalls(fn, roots); + modified = InstrumentFunction(fn, stage_idx, pfn) || modified; + } + } + return modified; +} + +bool InstrumentPass::InstProcessEntryPointCallTree(InstProcessFunction& pfn) { + // Check that format version 2 requested + if (version_ != 2u) { + if (consumer()) { + std::string message = "Unsupported instrumentation format requested"; + consumer()(SPV_MSG_ERROR, 0, {0, 0, 0}, message.c_str()); + } + return false; + } + // Make sure all entry points have the same execution model. Do not + // instrument if they do not. + // TODO(greg-lunarg): Handle mixed stages. Technically, a shader module + // can contain entry points with different execution models, although + // such modules will likely be rare as GLSL and HLSL are geared toward + // one model per module. In such cases we will need + // to clone any functions which are in the call trees of entrypoints + // with differing execution models. + uint32_t ecnt = 0; + uint32_t stage = SpvExecutionModelMax; + for (auto& e : get_module()->entry_points()) { + if (ecnt == 0) + stage = e.GetSingleWordInOperand(kEntryPointExecutionModelInIdx); + else if (e.GetSingleWordInOperand(kEntryPointExecutionModelInIdx) != + stage) { + if (consumer()) { + std::string message = "Mixed stage shader module not supported"; + consumer()(SPV_MSG_ERROR, 0, {0, 0, 0}, message.c_str()); + } + return false; + } + ++ecnt; + } + // Check for supported stages + if (stage != SpvExecutionModelVertex && stage != SpvExecutionModelFragment && + stage != SpvExecutionModelGeometry && + stage != SpvExecutionModelGLCompute && + stage != SpvExecutionModelTessellationControl && + stage != SpvExecutionModelTessellationEvaluation && + stage != SpvExecutionModelRayGenerationNV && + stage != SpvExecutionModelIntersectionNV && + stage != SpvExecutionModelAnyHitNV && + stage != SpvExecutionModelClosestHitNV && + stage != SpvExecutionModelMissNV && + stage != SpvExecutionModelCallableNV) { + if (consumer()) { + std::string message = "Stage not supported by instrumentation"; + consumer()(SPV_MSG_ERROR, 0, {0, 0, 0}, message.c_str()); + } + return false; + } + // Add together the roots of all entry points + std::queue roots; + for (auto& e : get_module()->entry_points()) { + roots.push(e.GetSingleWordInOperand(kEntryPointFunctionIdInIdx)); + } + bool modified = InstProcessCallTreeFromRoots(pfn, &roots, stage); + return modified; +} + +void InstrumentPass::InitializeInstrument() { + output_buffer_id_ = 0; + output_buffer_ptr_id_ = 0; + input_buffer_ptr_id_ = 0; + output_func_id_ = 0; + output_func_param_cnt_ = 0; + input_buffer_id_ = 0; + v4float_id_ = 0; + uint_id_ = 0; + uint64_id_ = 0; + v4uint_id_ = 0; + v3uint_id_ = 0; + bool_id_ = 0; + void_id_ = 0; + storage_buffer_ext_defined_ = false; + uint32_rarr_ty_ = nullptr; + uint64_rarr_ty_ = nullptr; + + // clear collections + id2function_.clear(); + id2block_.clear(); + + // Initialize function and block maps. + for (auto& fn : *get_module()) { + id2function_[fn.result_id()] = &fn; + for (auto& blk : fn) { + id2block_[blk.id()] = &blk; + } + } + + // Remember original instruction offsets + uint32_t module_offset = 0; + Module* module = get_module(); + for (auto& i : context()->capabilities()) { + (void)i; + ++module_offset; + } + for (auto& i : module->extensions()) { + (void)i; + ++module_offset; + } + for (auto& i : module->ext_inst_imports()) { + (void)i; + ++module_offset; + } + ++module_offset; // memory_model + for (auto& i : module->entry_points()) { + (void)i; + ++module_offset; + } + for (auto& i : module->execution_modes()) { + (void)i; + ++module_offset; + } + for (auto& i : module->debugs1()) { + (void)i; + ++module_offset; + } + for (auto& i : module->debugs2()) { + (void)i; + ++module_offset; + } + for (auto& i : module->debugs3()) { + (void)i; + ++module_offset; + } + for (auto& i : module->ext_inst_debuginfo()) { + (void)i; + ++module_offset; + } + for (auto& i : module->annotations()) { + (void)i; + ++module_offset; + } + for (auto& i : module->types_values()) { + module_offset += 1; + module_offset += static_cast(i.dbg_line_insts().size()); + } + + auto curr_fn = get_module()->begin(); + for (; curr_fn != get_module()->end(); ++curr_fn) { + // Count function instruction + module_offset += 1; + curr_fn->ForEachParam( + [&module_offset](const Instruction*) { module_offset += 1; }, true); + for (auto& blk : *curr_fn) { + // Count label + module_offset += 1; + for (auto& inst : blk) { + module_offset += static_cast(inst.dbg_line_insts().size()); + uid2offset_[inst.unique_id()] = module_offset; + module_offset += 1; + } + } + // Count function end instruction + module_offset += 1; + } +} + +} // namespace opt +} // namespace spvtools diff --git a/third_party/spirv-tools/source/opt/instrument_pass.h b/third_party/spirv-tools/source/opt/instrument_pass.h new file mode 100644 index 0000000000..02568fb7ad --- /dev/null +++ b/third_party/spirv-tools/source/opt/instrument_pass.h @@ -0,0 +1,440 @@ +// Copyright (c) 2018 The Khronos Group Inc. +// Copyright (c) 2018 Valve Corporation +// Copyright (c) 2018 LunarG Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef LIBSPIRV_OPT_INSTRUMENT_PASS_H_ +#define LIBSPIRV_OPT_INSTRUMENT_PASS_H_ + +#include +#include +#include + +#include "source/opt/ir_builder.h" +#include "source/opt/pass.h" +#include "spirv-tools/instrument.hpp" + +// This is a base class to assist in the creation of passes which instrument +// shader modules. More specifically, passes which replace instructions with a +// larger and more capable set of instructions. Commonly, these new +// instructions will add testing of operands and execute different +// instructions depending on the outcome, including outputting of debug +// information into a buffer created especially for that purpose. +// +// This class contains helper functions to create an InstProcessFunction, +// which is the heart of any derived class implementing a specific +// instrumentation pass. It takes an instruction as an argument, decides +// if it should be instrumented, and generates code to replace it. This class +// also supplies function InstProcessEntryPointCallTree which applies the +// InstProcessFunction to every reachable instruction in a module and replaces +// the instruction with new instructions if generated. +// +// Chief among the helper functions are output code generation functions, +// used to generate code in the shader which writes data to output buffers +// associated with that validation. Currently one such function, +// GenDebugStreamWrite, exists. Other such functions may be added in the +// future. Each is accompanied by documentation describing the format of +// its output buffer. +// +// A validation pass may read or write multiple buffers. All such buffers +// are located in a single debug descriptor set whose index is passed at the +// creation of the instrumentation pass. The bindings of the buffers used by +// a validation pass are permanantly assigned and fixed and documented by +// the kDebugOutput* static consts. + +namespace spvtools { +namespace opt { + +// Validation Ids +// These are used to identify the general validation being done and map to +// its output buffers. +static const uint32_t kInstValidationIdBindless = 0; +static const uint32_t kInstValidationIdBuffAddr = 1; + +class InstrumentPass : public Pass { + using cbb_ptr = const BasicBlock*; + + public: + using InstProcessFunction = + std::function, + uint32_t, std::vector>*)>; + + ~InstrumentPass() override = default; + + IRContext::Analysis GetPreservedAnalyses() override { + return IRContext::kAnalysisDefUse | IRContext::kAnalysisDecorations | + IRContext::kAnalysisCombinators | IRContext::kAnalysisNameMap | + IRContext::kAnalysisBuiltinVarId | IRContext::kAnalysisConstants; + } + + protected: + // Create instrumentation pass for |validation_id| which utilizes descriptor + // set |desc_set| for debug input and output buffers and writes |shader_id| + // into debug output records. + InstrumentPass(uint32_t desc_set, uint32_t shader_id, uint32_t validation_id) + : Pass(), + desc_set_(desc_set), + shader_id_(shader_id), + validation_id_(validation_id), + version_(2u) {} + // Create instrumentation pass for |validation_id| which utilizes descriptor + // set |desc_set| for debug input and output buffers and writes |shader_id| + // into debug output records with format |version|. Deprecated. + InstrumentPass(uint32_t desc_set, uint32_t shader_id, uint32_t validation_id, + uint32_t version) + : Pass(), + desc_set_(desc_set), + shader_id_(shader_id), + validation_id_(validation_id), + version_(version) {} + + // Initialize state for instrumentation of module. + void InitializeInstrument(); + + // Call |pfn| on all instructions in all functions in the call tree of the + // entry points in |module|. If code is generated for an instruction, replace + // the instruction's block with the new blocks that are generated. Continue + // processing at the top of the last new block. + bool InstProcessEntryPointCallTree(InstProcessFunction& pfn); + + // Move all code in |ref_block_itr| preceding the instruction |ref_inst_itr| + // to be instrumented into block |new_blk_ptr|. + void MovePreludeCode(BasicBlock::iterator ref_inst_itr, + UptrVectorIterator ref_block_itr, + std::unique_ptr* new_blk_ptr); + + // Move all code in |ref_block_itr| succeeding the instruction |ref_inst_itr| + // to be instrumented into block |new_blk_ptr|. + void MovePostludeCode(UptrVectorIterator ref_block_itr, + BasicBlock* new_blk_ptr); + + // Generate instructions in |builder| which will atomically fetch and + // increment the size of the debug output buffer stream of the current + // validation and write a record to the end of the stream, if enough space + // in the buffer remains. The record will contain the index of the function + // and instruction within that function |func_idx, instruction_idx| which + // generated the record. It will also contain additional information to + // identify the instance of the shader, depending on the stage |stage_idx| + // of the shader. Finally, the record will contain validation-specific + // data contained in |validation_ids| which will identify the validation + // error as well as the values involved in the error. + // + // The output buffer binding written to by the code generated by the function + // is determined by the validation id specified when each specific + // instrumentation pass is created. + // + // The output buffer is a sequence of 32-bit values with the following + // format (where all elements are unsigned 32-bit unless otherwise noted): + // + // Size + // Record0 + // Record1 + // Record2 + // ... + // + // Size is the number of 32-bit values that have been written or + // attempted to be written to the output buffer, excluding the Size. It is + // initialized to 0. If the size of attempts to write the buffer exceeds + // the actual size of the buffer, it is possible that this field can exceed + // the actual size of the buffer. + // + // Each Record* is a variable-length sequence of 32-bit values with the + // following format defined using static const offsets in the .cpp file: + // + // Record Size + // Shader ID + // Instruction Index + // Stage + // Stage-specific Word 0 + // Stage-specific Word 1 + // ... + // Validation Error Code + // Validation-specific Word 0 + // Validation-specific Word 1 + // Validation-specific Word 2 + // ... + // + // Each record consists of three subsections: members common across all + // validation, members specific to the stage, and members specific to a + // validation. + // + // The Record Size is the number of 32-bit words in the record, including + // the Record Size word. + // + // Shader ID is a value that identifies which shader has generated the + // validation error. It is passed when the instrumentation pass is created. + // + // The Instruction Index is the position of the instruction within the + // SPIR-V file which is in error. + // + // The Stage is the pipeline stage which has generated the error as defined + // by the SpvExecutionModel_ enumeration. This is used to interpret the + // following Stage-specific words. + // + // The Stage-specific Words identify which invocation of the shader generated + // the error. Every stage will write a fixed number of words. Vertex shaders + // will write the Vertex and Instance ID. Fragment shaders will write + // FragCoord.xy. Compute shaders will write the GlobalInvocation ID. + // The tesselation eval shader will write the Primitive ID and TessCoords.uv. + // The tesselation control shader and geometry shader will write the + // Primitive ID and Invocation ID. + // + // The Validation Error Code specifies the exact error which has occurred. + // These are enumerated with the kInstError* static consts. This allows + // multiple validation layers to use the same, single output buffer. + // + // The Validation-specific Words are a validation-specific number of 32-bit + // words which give further information on the validation error that + // occurred. These are documented further in each file containing the + // validation-specific class which derives from this base class. + // + // Because the code that is generated checks against the size of the buffer + // before writing, the size of the debug out buffer can be used by the + // validation layer to control the number of error records that are written. + void GenDebugStreamWrite(uint32_t instruction_idx, uint32_t stage_idx, + const std::vector& validation_ids, + InstructionBuilder* builder); + + // Generate in |builder| instructions to read the unsigned integer from the + // input buffer specified by the offsets in |offset_ids|. Given offsets + // o0, o1, ... oN, and input buffer ibuf, return the id for the value: + // + // ibuf[...ibuf[ibuf[o0]+o1]...+oN] + // + // The binding and the format of the input buffer is determined by each + // specific validation, which is specified at the creation of the pass. + uint32_t GenDebugDirectRead(const std::vector& offset_ids, + InstructionBuilder* builder); + + // Generate code to cast |value_id| to unsigned, if needed. Return + // an id to the unsigned equivalent. + uint32_t GenUintCastCode(uint32_t value_id, InstructionBuilder* builder); + + // Return new label. + std::unique_ptr NewLabel(uint32_t label_id); + + // Return id for 32-bit unsigned type + uint32_t GetUintId(); + + // Return id for 32-bit unsigned type + uint32_t GetUint64Id(); + + // Return id for 32-bit unsigned type + uint32_t GetBoolId(); + + // Return id for void type + uint32_t GetVoidId(); + + // Return pointer to type for runtime array of uint + analysis::Type* GetUintXRuntimeArrayType(uint32_t width, + analysis::Type** rarr_ty); + + // Return pointer to type for runtime array of uint + analysis::Type* GetUintRuntimeArrayType(uint32_t width); + + // Return id for buffer uint type + uint32_t GetOutputBufferPtrId(); + + // Return id for buffer uint type + uint32_t GetInputBufferTypeId(); + + // Return id for buffer uint type + uint32_t GetInputBufferPtrId(); + + // Return binding for output buffer for current validation. + uint32_t GetOutputBufferBinding(); + + // Return binding for input buffer for current validation. + uint32_t GetInputBufferBinding(); + + // Add storage buffer extension if needed + void AddStorageBufferExt(); + + // Return id for debug output buffer + uint32_t GetOutputBufferId(); + + // Return id for debug input buffer + uint32_t GetInputBufferId(); + + // Return id for v4float type + uint32_t GetVec4FloatId(); + + // Return id for uint vector type of |length| + uint32_t GetVecUintId(uint32_t length); + + // Return id for v4uint type + uint32_t GetVec4UintId(); + + // Return id for v3uint type + uint32_t GetVec3UintId(); + + // Return id for output function. Define if it doesn't exist with + // |val_spec_param_cnt| validation-specific uint32 parameters. + uint32_t GetStreamWriteFunctionId(uint32_t stage_idx, + uint32_t val_spec_param_cnt); + + // Return id for input function taking |param_cnt| uint32 parameters. Define + // if it doesn't exist. + uint32_t GetDirectReadFunctionId(uint32_t param_cnt); + + // Apply instrumentation function |pfn| to every instruction in |func|. + // If code is generated for an instruction, replace the instruction's + // block with the new blocks that are generated. Continue processing at the + // top of the last new block. + bool InstrumentFunction(Function* func, uint32_t stage_idx, + InstProcessFunction& pfn); + + // Call |pfn| on all functions in the call tree of the function + // ids in |roots|. + bool InstProcessCallTreeFromRoots(InstProcessFunction& pfn, + std::queue* roots, + uint32_t stage_idx); + + // Gen code into |builder| to write |field_value_id| into debug output + // buffer at |base_offset_id| + |field_offset|. + void GenDebugOutputFieldCode(uint32_t base_offset_id, uint32_t field_offset, + uint32_t field_value_id, + InstructionBuilder* builder); + + // Generate instructions into |builder| which will write the members + // of the debug output record common for all stages and validations at + // |base_off|. + void GenCommonStreamWriteCode(uint32_t record_sz, uint32_t instruction_idx, + uint32_t stage_idx, uint32_t base_off, + InstructionBuilder* builder); + + // Generate instructions into |builder| which will write + // |uint_frag_coord_id| at |component| of the record at |base_offset_id| of + // the debug output buffer . + void GenFragCoordEltDebugOutputCode(uint32_t base_offset_id, + uint32_t uint_frag_coord_id, + uint32_t component, + InstructionBuilder* builder); + + // Generate instructions into |builder| which will load |var_id| and return + // its result id. + uint32_t GenVarLoad(uint32_t var_id, InstructionBuilder* builder); + + // Generate instructions into |builder| which will load the uint |builtin_id| + // and write it into the debug output buffer at |base_off| + |builtin_off|. + void GenBuiltinOutputCode(uint32_t builtin_id, uint32_t builtin_off, + uint32_t base_off, InstructionBuilder* builder); + + // Generate instructions into |builder| which will write the |stage_idx|- + // specific members of the debug output stream at |base_off|. + void GenStageStreamWriteCode(uint32_t stage_idx, uint32_t base_off, + InstructionBuilder* builder); + + // Return true if instruction must be in the same block that its result + // is used. + bool IsSameBlockOp(const Instruction* inst) const; + + // Clone operands which must be in same block as consumer instructions. + // Look in same_blk_pre for instructions that need cloning. Look in + // same_blk_post for instructions already cloned. Add cloned instruction + // to same_blk_post. + void CloneSameBlockOps( + std::unique_ptr* inst, + std::unordered_map* same_blk_post, + std::unordered_map* same_blk_pre, + BasicBlock* block_ptr); + + // Update phis in succeeding blocks to point to new last block + void UpdateSucceedingPhis( + std::vector>& new_blocks); + + // Debug descriptor set index + uint32_t desc_set_; + + // Shader module ID written into output record + uint32_t shader_id_; + + // Map from function id to function pointer. + std::unordered_map id2function_; + + // Map from block's label id to block. TODO(dnovillo): This is superfluous wrt + // CFG. It has functionality not present in CFG. Consolidate. + std::unordered_map id2block_; + + // Map from instruction's unique id to offset in original file. + std::unordered_map uid2offset_; + + // result id for OpConstantFalse + uint32_t validation_id_; + + // id for output buffer variable + uint32_t output_buffer_id_; + + // ptr type id for output buffer element + uint32_t output_buffer_ptr_id_; + + // ptr type id for input buffer element + uint32_t input_buffer_ptr_id_; + + // id for debug output function + uint32_t output_func_id_; + + // ids for debug input functions + std::unordered_map param2input_func_id_; + + // param count for output function + uint32_t output_func_param_cnt_; + + // id for input buffer variable + uint32_t input_buffer_id_; + + // id for v4float type + uint32_t v4float_id_; + + // id for v4uint type + uint32_t v4uint_id_; + + // id for v3uint type + uint32_t v3uint_id_; + + // id for 32-bit unsigned type + uint32_t uint_id_; + + // id for 32-bit unsigned type + uint32_t uint64_id_; + + // id for bool type + uint32_t bool_id_; + + // id for void type + uint32_t void_id_; + + // Record format version + uint32_t version_; + + // boolean to remember storage buffer extension + bool storage_buffer_ext_defined_; + + // runtime array of uint type + analysis::Type* uint64_rarr_ty_; + + // runtime array of uint type + analysis::Type* uint32_rarr_ty_; + + // Pre-instrumentation same-block insts + std::unordered_map same_block_pre_; + + // Post-instrumentation same-block op ids + std::unordered_map same_block_post_; +}; + +} // namespace opt +} // namespace spvtools + +#endif // LIBSPIRV_OPT_INSTRUMENT_PASS_H_ diff --git a/third_party/spirv-tools/source/opt/ir_builder.h b/third_party/spirv-tools/source/opt/ir_builder.h index 2dab76e52a..b0c1d2ec9f 100644 --- a/third_party/spirv-tools/source/opt/ir_builder.h +++ b/third_party/spirv-tools/source/opt/ir_builder.h @@ -58,6 +58,119 @@ class InstructionBuilder { : InstructionBuilder(context, parent_block, parent_block->end(), preserved_analyses) {} + Instruction* AddNullaryOp(uint32_t type_id, SpvOp opcode) { + uint32_t result_id = 0; + if (type_id != 0) { + result_id = GetContext()->TakeNextId(); + if (result_id == 0) { + return nullptr; + } + } + std::unique_ptr new_inst( + new Instruction(GetContext(), opcode, type_id, result_id, {})); + return AddInstruction(std::move(new_inst)); + } + + Instruction* AddUnaryOp(uint32_t type_id, SpvOp opcode, uint32_t operand1) { + uint32_t result_id = 0; + if (type_id != 0) { + result_id = GetContext()->TakeNextId(); + if (result_id == 0) { + return nullptr; + } + } + std::unique_ptr newUnOp(new Instruction( + GetContext(), opcode, type_id, result_id, + {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand1}}})); + return AddInstruction(std::move(newUnOp)); + } + + Instruction* AddBinaryOp(uint32_t type_id, SpvOp opcode, uint32_t operand1, + uint32_t operand2) { + uint32_t result_id = 0; + if (type_id != 0) { + result_id = GetContext()->TakeNextId(); + if (result_id == 0) { + return nullptr; + } + } + std::unique_ptr newBinOp(new Instruction( + GetContext(), opcode, type_id, opcode == SpvOpStore ? 0 : result_id, + {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand1}}, + {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand2}}})); + return AddInstruction(std::move(newBinOp)); + } + + Instruction* AddTernaryOp(uint32_t type_id, SpvOp opcode, uint32_t operand1, + uint32_t operand2, uint32_t operand3) { + uint32_t result_id = 0; + if (type_id != 0) { + result_id = GetContext()->TakeNextId(); + if (result_id == 0) { + return nullptr; + } + } + std::unique_ptr newTernOp(new Instruction( + GetContext(), opcode, type_id, result_id, + {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand1}}, + {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand2}}, + {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand3}}})); + return AddInstruction(std::move(newTernOp)); + } + + Instruction* AddQuadOp(uint32_t type_id, SpvOp opcode, uint32_t operand1, + uint32_t operand2, uint32_t operand3, + uint32_t operand4) { + uint32_t result_id = 0; + if (type_id != 0) { + result_id = GetContext()->TakeNextId(); + if (result_id == 0) { + return nullptr; + } + } + std::unique_ptr newQuadOp(new Instruction( + GetContext(), opcode, type_id, result_id, + {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand1}}, + {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand2}}, + {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand3}}, + {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {operand4}}})); + return AddInstruction(std::move(newQuadOp)); + } + + Instruction* AddIdLiteralOp(uint32_t type_id, SpvOp opcode, uint32_t id, + uint32_t uliteral) { + uint32_t result_id = 0; + if (type_id != 0) { + result_id = GetContext()->TakeNextId(); + if (result_id == 0) { + return nullptr; + } + } + std::unique_ptr newBinOp(new Instruction( + GetContext(), opcode, type_id, result_id, + {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {id}}, + {spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, {uliteral}}})); + return AddInstruction(std::move(newBinOp)); + } + + // Creates an N-ary instruction of |opcode|. + // |typid| must be the id of the instruction's type. + // |operands| must be a sequence of operand ids. + // Use |result| for the result id if non-zero. + Instruction* AddNaryOp(uint32_t type_id, SpvOp opcode, + const std::vector& operands, + uint32_t result = 0) { + std::vector ops; + for (size_t i = 0; i < operands.size(); i++) { + ops.push_back({SPV_OPERAND_TYPE_ID, {operands[i]}}); + } + // TODO(1841): Handle id overflow. + std::unique_ptr new_inst(new Instruction( + GetContext(), opcode, type_id, + result != 0 ? result : GetContext()->TakeNextId(), ops)); + return AddInstruction(std::move(new_inst)); + } + // Creates a new selection merge instruction. // The id |merge_id| is the merge basic block id. Instruction* AddSelectionMerge( @@ -71,6 +184,20 @@ class InstructionBuilder { return AddInstruction(std::move(new_branch_merge)); } + // Creates a new loop merge instruction. + // The id |merge_id| is the basic block id of the merge block. + // |continue_id| is the id of the continue block. + // |loop_control| are the loop control flags to be added to the instruction. + Instruction* AddLoopMerge(uint32_t merge_id, uint32_t continue_id, + uint32_t loop_control = SpvLoopControlMaskNone) { + std::unique_ptr new_branch_merge(new Instruction( + GetContext(), SpvOpLoopMerge, 0, 0, + {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {merge_id}}, + {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {continue_id}}, + {spv_operand_type_t::SPV_OPERAND_TYPE_LOOP_CONTROL, {loop_control}}})); + return AddInstruction(std::move(new_branch_merge)); + } + // Creates a new branch instruction to |label_id|. // Note that the user must make sure the final basic block is // well formed. @@ -153,15 +280,10 @@ class InstructionBuilder { // The id |type| must be the id of the phi instruction's type. // The vector |incomings| must be a sequence of pairs of . - Instruction* AddPhi(uint32_t type, const std::vector& incomings) { + Instruction* AddPhi(uint32_t type, const std::vector& incomings, + uint32_t result = 0) { assert(incomings.size() % 2 == 0 && "A sequence of pairs is expected"); - std::vector phi_ops; - for (size_t i = 0; i < incomings.size(); i++) { - phi_ops.push_back({SPV_OPERAND_TYPE_ID, {incomings[i]}}); - } - std::unique_ptr phi_inst(new Instruction( - GetContext(), SpvOpPhi, type, GetContext()->TakeNextId(), phi_ops)); - return AddInstruction(std::move(phi_inst)); + return AddNaryOp(type, SpvOpPhi, incomings, result); } // Creates an addition instruction. @@ -170,6 +292,7 @@ class InstructionBuilder { // The id |op1| is the left hand side of the operation. // The id |op2| is the right hand side of the operation. Instruction* AddIAdd(uint32_t type, uint32_t op1, uint32_t op2) { + // TODO(1841): Handle id overflow. std::unique_ptr inst(new Instruction( GetContext(), SpvOpIAdd, type, GetContext()->TakeNextId(), {{SPV_OPERAND_TYPE_ID, {op1}}, {SPV_OPERAND_TYPE_ID, {op2}}})); @@ -183,6 +306,7 @@ class InstructionBuilder { Instruction* AddULessThan(uint32_t op1, uint32_t op2) { analysis::Bool bool_type; uint32_t type = GetContext()->get_type_mgr()->GetId(&bool_type); + // TODO(1841): Handle id overflow. std::unique_ptr inst(new Instruction( GetContext(), SpvOpULessThan, type, GetContext()->TakeNextId(), {{SPV_OPERAND_TYPE_ID, {op1}}, {SPV_OPERAND_TYPE_ID, {op2}}})); @@ -196,6 +320,7 @@ class InstructionBuilder { Instruction* AddSLessThan(uint32_t op1, uint32_t op2) { analysis::Bool bool_type; uint32_t type = GetContext()->get_type_mgr()->GetId(&bool_type); + // TODO(1841): Handle id overflow. std::unique_ptr inst(new Instruction( GetContext(), SpvOpSLessThan, type, GetContext()->TakeNextId(), {{SPV_OPERAND_TYPE_ID, {op1}}, {SPV_OPERAND_TYPE_ID, {op2}}})); @@ -225,6 +350,7 @@ class InstructionBuilder { // bool) for |type|. Instruction* AddSelect(uint32_t type, uint32_t cond, uint32_t true_value, uint32_t false_value) { + // TODO(1841): Handle id overflow. std::unique_ptr select(new Instruction( GetContext(), SpvOpSelect, type, GetContext()->TakeNextId(), std::initializer_list{{SPV_OPERAND_TYPE_ID, {cond}}, @@ -235,8 +361,8 @@ class InstructionBuilder { // Adds a signed int32 constant to the binary. // The |value| parameter is the constant value to be added. - Instruction* Add32BitSignedIntegerConstant(int32_t value) { - return Add32BitConstantInteger(value, true); + Instruction* GetSintConstant(int32_t value) { + return GetIntConstant(value, true); } // Create a composite construct. @@ -249,6 +375,7 @@ class InstructionBuilder { ops.emplace_back(SPV_OPERAND_TYPE_ID, std::initializer_list{id}); } + // TODO(1841): Handle id overflow. std::unique_ptr construct( new Instruction(GetContext(), SpvOpCompositeConstruct, type, GetContext()->TakeNextId(), ops)); @@ -256,8 +383,13 @@ class InstructionBuilder { } // Adds an unsigned int32 constant to the binary. // The |value| parameter is the constant value to be added. - Instruction* Add32BitUnsignedIntegerConstant(uint32_t value) { - return Add32BitConstantInteger(value, false); + Instruction* GetUintConstant(uint32_t value) { + return GetIntConstant(value, false); + } + + uint32_t GetUintConstantId(uint32_t value) { + Instruction* uint_inst = GetUintConstant(value); + return uint_inst->result_id(); } // Adds either a signed or unsigned 32 bit integer constant to the binary @@ -265,7 +397,7 @@ class InstructionBuilder { // signed constant otherwise as an unsigned constant. If |sign| is false the // value must not be a negative number. template - Instruction* Add32BitConstantInteger(T value, bool sign) { + Instruction* GetIntConstant(T value, bool sign) { // Assert that we are not trying to store a negative number in an unsigned // type. if (!sign) @@ -305,6 +437,7 @@ class InstructionBuilder { operands.push_back({SPV_OPERAND_TYPE_LITERAL_INTEGER, {index}}); } + // TODO(1841): Handle id overflow. std::unique_ptr new_inst( new Instruction(GetContext(), SpvOpCompositeExtract, type, GetContext()->TakeNextId(), operands)); @@ -328,6 +461,7 @@ class InstructionBuilder { operands.push_back({SPV_OPERAND_TYPE_ID, {index_id}}); } + // TODO(1841): Handle id overflow. std::unique_ptr new_inst( new Instruction(GetContext(), SpvOpAccessChain, type_id, GetContext()->TakeNextId(), operands)); @@ -338,12 +472,81 @@ class InstructionBuilder { std::vector operands; operands.push_back({SPV_OPERAND_TYPE_ID, {base_ptr_id}}); + // TODO(1841): Handle id overflow. std::unique_ptr new_inst( new Instruction(GetContext(), SpvOpLoad, type_id, GetContext()->TakeNextId(), operands)); return AddInstruction(std::move(new_inst)); } + Instruction* AddStore(uint32_t ptr_id, uint32_t obj_id) { + std::vector operands; + operands.push_back({SPV_OPERAND_TYPE_ID, {ptr_id}}); + operands.push_back({SPV_OPERAND_TYPE_ID, {obj_id}}); + + std::unique_ptr new_inst( + new Instruction(GetContext(), SpvOpStore, 0, 0, operands)); + return AddInstruction(std::move(new_inst)); + } + + Instruction* AddFunctionCall(uint32_t result_type, uint32_t function, + const std::vector& parameters) { + std::vector operands; + operands.push_back({SPV_OPERAND_TYPE_ID, {function}}); + for (uint32_t id : parameters) { + operands.push_back({SPV_OPERAND_TYPE_ID, {id}}); + } + + uint32_t result_id = GetContext()->TakeNextId(); + if (result_id == 0) { + return nullptr; + } + std::unique_ptr new_inst(new Instruction( + GetContext(), SpvOpFunctionCall, result_type, result_id, operands)); + return AddInstruction(std::move(new_inst)); + } + + Instruction* AddVectorShuffle(uint32_t result_type, uint32_t vec1, + uint32_t vec2, + const std::vector& components) { + std::vector operands; + operands.push_back({SPV_OPERAND_TYPE_ID, {vec1}}); + operands.push_back({SPV_OPERAND_TYPE_ID, {vec2}}); + for (uint32_t id : components) { + operands.push_back({SPV_OPERAND_TYPE_LITERAL_INTEGER, {id}}); + } + + uint32_t result_id = GetContext()->TakeNextId(); + if (result_id == 0) { + return nullptr; + } + + std::unique_ptr new_inst(new Instruction( + GetContext(), SpvOpVectorShuffle, result_type, result_id, operands)); + return AddInstruction(std::move(new_inst)); + } + + Instruction* AddNaryExtendedInstruction( + uint32_t result_type, uint32_t set, uint32_t instruction, + const std::vector& ext_operands) { + std::vector operands; + operands.push_back({SPV_OPERAND_TYPE_ID, {set}}); + operands.push_back( + {SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER, {instruction}}); + for (uint32_t id : ext_operands) { + operands.push_back({SPV_OPERAND_TYPE_ID, {id}}); + } + + uint32_t result_id = GetContext()->TakeNextId(); + if (result_id == 0) { + return nullptr; + } + + std::unique_ptr new_inst(new Instruction( + GetContext(), SpvOpExtInst, result_type, result_id, operands)); + return AddInstruction(std::move(new_inst)); + } + // Inserts the new instruction before the insertion point. Instruction* AddInstruction(std::unique_ptr&& insn) { Instruction* insn_ptr = &*insert_before_.InsertBefore(std::move(insn)); @@ -391,6 +594,10 @@ class InstructionBuilder { // Returns true if the users requested to update |analysis|. inline bool IsAnalysisUpdateRequested(IRContext::Analysis analysis) const { + if (!GetContext()->AreAnalysesValid(analysis)) { + // Do not try to update something that is not built. + return false; + } return preserved_analyses_ & analysis; } diff --git a/third_party/spirv-tools/source/opt/ir_context.cpp b/third_party/spirv-tools/source/opt/ir_context.cpp index 742ac1f626..7bca29b201 100644 --- a/third_party/spirv-tools/source/opt/ir_context.cpp +++ b/third_party/spirv-tools/source/opt/ir_context.cpp @@ -21,6 +21,16 @@ #include "source/opt/mem_pass.h" #include "source/opt/reflect.h" +namespace { + +static const int kSpvDecorateTargetIdInIdx = 0; +static const int kSpvDecorateDecorationInIdx = 1; +static const int kSpvDecorateBuiltinInIdx = 2; +static const int kEntryPointInterfaceInIdx = 3; +static const int kEntryPointFunctionIdInIdx = 1; + +} // anonymous namespace + namespace spvtools { namespace opt { @@ -43,6 +53,9 @@ void IRContext::BuildInvalidAnalyses(IRContext::Analysis set) { if (set & kAnalysisLoopAnalysis) { ResetLoopAnalysis(); } + if (set & kAnalysisBuiltinVarId) { + ResetBuiltinAnalysis(); + } if (set & kAnalysisNameMap) { BuildIdToNameMap(); } @@ -55,6 +68,18 @@ void IRContext::BuildInvalidAnalyses(IRContext::Analysis set) { if (set & kAnalysisValueNumberTable) { BuildValueNumberTable(); } + if (set & kAnalysisStructuredCFG) { + BuildStructuredCFGAnalysis(); + } + if (set & kAnalysisIdToFuncMapping) { + BuildIdToFuncMapping(); + } + if (set & kAnalysisConstants) { + BuildConstantManager(); + } + if (set & kAnalysisTypes) { + BuildTypeManager(); + } } void IRContext::InvalidateAnalysesExceptFor( @@ -64,6 +89,19 @@ void IRContext::InvalidateAnalysesExceptFor( } void IRContext::InvalidateAnalyses(IRContext::Analysis analyses_to_invalidate) { + // The ConstantManager contains Type pointers. If the TypeManager goes + // away, the ConstantManager has to go away. + if (analyses_to_invalidate & kAnalysisTypes) { + analyses_to_invalidate |= kAnalysisConstants; + } + + // The dominator analysis hold the psuedo entry and exit nodes from the CFG. + // Also if the CFG change the dominators many changed as well, so the + // dominator analysis should be invalidated as well. + if (analyses_to_invalidate & kAnalysisCFG) { + analyses_to_invalidate |= kAnalysisDominatorAnalysis; + } + if (analyses_to_invalidate & kAnalysisDefUse) { def_use_mgr_.reset(nullptr); } @@ -76,6 +114,9 @@ void IRContext::InvalidateAnalyses(IRContext::Analysis analyses_to_invalidate) { if (analyses_to_invalidate & kAnalysisCombinators) { combinator_ops_.clear(); } + if (analyses_to_invalidate & kAnalysisBuiltinVarId) { + builtin_var_id_map_.clear(); + } if (analyses_to_invalidate & kAnalysisCFG) { cfg_.reset(nullptr); } @@ -89,6 +130,18 @@ void IRContext::InvalidateAnalyses(IRContext::Analysis analyses_to_invalidate) { if (analyses_to_invalidate & kAnalysisValueNumberTable) { vn_table_.reset(nullptr); } + if (analyses_to_invalidate & kAnalysisStructuredCFG) { + struct_cfg_analysis_.reset(nullptr); + } + if (analyses_to_invalidate & kAnalysisIdToFuncMapping) { + id_to_func_.clear(); + } + if (analyses_to_invalidate & kAnalysisConstants) { + constant_mgr_.reset(nullptr); + } + if (analyses_to_invalidate & kAnalysisTypes) { + type_mgr_.reset(nullptr); + } valid_analyses_ = Analysis(valid_analyses_ & ~analyses_to_invalidate); } @@ -107,21 +160,24 @@ Instruction* IRContext::KillInst(Instruction* inst) { instr_to_block_.erase(inst); } if (AreAnalysesValid(kAnalysisDecorations)) { - if (inst->result_id() != 0) { - decoration_mgr_->RemoveDecorationsFrom(inst->result_id()); - } if (inst->IsDecoration()) { decoration_mgr_->RemoveDecoration(inst); } } - if (type_mgr_ && IsTypeInst(inst->opcode())) { type_mgr_->RemoveId(inst->result_id()); } - if (constant_mgr_ && IsConstantInst(inst->opcode())) { constant_mgr_->RemoveId(inst->result_id()); } + if (inst->opcode() == SpvOpCapability || inst->opcode() == SpvOpExtension) { + // We reset the feature manager, instead of updating it, because it is just + // as much work. We would have to remove all capabilities implied by this + // capability that are not also implied by the remaining OpCapability + // instructions. We could update extensions, but we will see if it is + // needed. + ResetFeatureManager(); + } RemoveFromIdToName(inst); @@ -148,6 +204,13 @@ bool IRContext::KillDef(uint32_t id) { } bool IRContext::ReplaceAllUsesWith(uint32_t before, uint32_t after) { + return ReplaceAllUsesWithPredicate( + before, after, [](Instruction*, uint32_t) { return true; }); +} + +bool IRContext::ReplaceAllUsesWithPredicate( + uint32_t before, uint32_t after, + const std::function& predicate) { if (before == after) return false; // Ensure that |after| has been registered as def. @@ -156,8 +219,10 @@ bool IRContext::ReplaceAllUsesWith(uint32_t before, uint32_t after) { std::vector> uses_to_update; get_def_use_mgr()->ForEachUse( - before, [&uses_to_update](Instruction* user, uint32_t index) { - uses_to_update.emplace_back(user, index); + before, [&predicate, &uses_to_update](Instruction* user, uint32_t index) { + if (predicate(user, index)) { + uses_to_update.emplace_back(user, index); + } }); Instruction* prev = nullptr; @@ -201,7 +266,6 @@ bool IRContext::IsConsistent() { #ifndef SPIRV_CHECK_CONTEXT return true; #endif - if (AreAnalysesValid(kAnalysisDefUse)) { analysis::DefUseManager new_def_use(module()); if (*get_def_use_mgr() != new_def_use) { @@ -209,6 +273,14 @@ bool IRContext::IsConsistent() { } } + if (AreAnalysesValid(kAnalysisIdToFuncMapping)) { + for (auto& fn : *module_) { + if (id_to_func_[fn.result_id()] != &fn) { + return false; + } + } + } + if (AreAnalysesValid(kAnalysisInstrToBlockMapping)) { for (auto& func : *module()) { for (auto& block : func) { @@ -227,6 +299,23 @@ bool IRContext::IsConsistent() { return false; } + if (AreAnalysesValid(kAnalysisDecorations)) { + analysis::DecorationManager* dec_mgr = get_decoration_mgr(); + analysis::DecorationManager current(module()); + + if (*dec_mgr != current) { + return false; + } + } + + if (feature_mgr_ != nullptr) { + FeatureManager current(grammar_); + current.Analyze(module()); + + if (current != *feature_mgr_) { + return false; + } + } return true; } @@ -258,12 +347,8 @@ void IRContext::AnalyzeUses(Instruction* inst) { } void IRContext::KillNamesAndDecorates(uint32_t id) { - std::vector decorations = - get_decoration_mgr()->GetDecorationsFor(id, true); - - for (Instruction* inst : decorations) { - KillInst(inst); - } + analysis::DecorationManager* dec_mgr = get_decoration_mgr(); + dec_mgr->RemoveDecorationsFrom(id); std::vector name_to_kill; for (auto name : GetNames(id)) { @@ -299,6 +384,7 @@ void IRContext::AddCombinatorsForCapability(uint32_t capability) { SpvOpTypeImage, SpvOpTypeSampler, SpvOpTypeSampledImage, + SpvOpTypeAccelerationStructureNV, SpvOpTypeArray, SpvOpTypeRuntimeArray, SpvOpTypeStruct, @@ -574,6 +660,216 @@ LoopDescriptor* IRContext::GetLoopDescriptor(const Function* f) { return &it->second; } +uint32_t IRContext::FindBuiltinInputVar(uint32_t builtin) { + for (auto& a : module_->annotations()) { + if (a.opcode() != SpvOpDecorate) continue; + if (a.GetSingleWordInOperand(kSpvDecorateDecorationInIdx) != + SpvDecorationBuiltIn) + continue; + if (a.GetSingleWordInOperand(kSpvDecorateBuiltinInIdx) != builtin) continue; + uint32_t target_id = a.GetSingleWordInOperand(kSpvDecorateTargetIdInIdx); + Instruction* b_var = get_def_use_mgr()->GetDef(target_id); + if (b_var->opcode() != SpvOpVariable) continue; + if (b_var->GetSingleWordInOperand(0) != SpvStorageClassInput) continue; + return target_id; + } + return 0; +} + +void IRContext::AddVarToEntryPoints(uint32_t var_id) { + uint32_t ocnt = 0; + for (auto& e : module()->entry_points()) { + bool found = false; + e.ForEachInOperand([&ocnt, &found, &var_id](const uint32_t* idp) { + if (ocnt >= kEntryPointInterfaceInIdx) { + if (*idp == var_id) found = true; + } + ++ocnt; + }); + if (!found) { + e.AddOperand({SPV_OPERAND_TYPE_ID, {var_id}}); + get_def_use_mgr()->AnalyzeInstDefUse(&e); + } + } +} + +uint32_t IRContext::GetBuiltinInputVarId(uint32_t builtin) { + if (!AreAnalysesValid(kAnalysisBuiltinVarId)) ResetBuiltinAnalysis(); + // If cached, return it. + std::unordered_map::iterator it = + builtin_var_id_map_.find(builtin); + if (it != builtin_var_id_map_.end()) return it->second; + // Look for one in shader + uint32_t var_id = FindBuiltinInputVar(builtin); + if (var_id == 0) { + // If not found, create it + // TODO(greg-lunarg): Add support for all builtins + analysis::TypeManager* type_mgr = get_type_mgr(); + analysis::Type* reg_type; + switch (builtin) { + case SpvBuiltInFragCoord: { + analysis::Float float_ty(32); + analysis::Type* reg_float_ty = type_mgr->GetRegisteredType(&float_ty); + analysis::Vector v4float_ty(reg_float_ty, 4); + reg_type = type_mgr->GetRegisteredType(&v4float_ty); + break; + } + case SpvBuiltInVertexIndex: + case SpvBuiltInInstanceIndex: + case SpvBuiltInPrimitiveId: + case SpvBuiltInInvocationId: + case SpvBuiltInSubgroupLocalInvocationId: { + analysis::Integer uint_ty(32, false); + reg_type = type_mgr->GetRegisteredType(&uint_ty); + break; + } + case SpvBuiltInGlobalInvocationId: + case SpvBuiltInLaunchIdNV: { + analysis::Integer uint_ty(32, false); + analysis::Type* reg_uint_ty = type_mgr->GetRegisteredType(&uint_ty); + analysis::Vector v3uint_ty(reg_uint_ty, 3); + reg_type = type_mgr->GetRegisteredType(&v3uint_ty); + break; + } + case SpvBuiltInTessCoord: { + analysis::Float float_ty(32); + analysis::Type* reg_float_ty = type_mgr->GetRegisteredType(&float_ty); + analysis::Vector v3float_ty(reg_float_ty, 3); + reg_type = type_mgr->GetRegisteredType(&v3float_ty); + break; + } + case SpvBuiltInSubgroupLtMask: { + analysis::Integer uint_ty(32, false); + analysis::Type* reg_uint_ty = type_mgr->GetRegisteredType(&uint_ty); + analysis::Vector v4uint_ty(reg_uint_ty, 4); + reg_type = type_mgr->GetRegisteredType(&v4uint_ty); + break; + } + default: { + assert(false && "unhandled builtin"); + return 0; + } + } + uint32_t type_id = type_mgr->GetTypeInstruction(reg_type); + uint32_t varTyPtrId = + type_mgr->FindPointerToType(type_id, SpvStorageClassInput); + // TODO(1841): Handle id overflow. + var_id = TakeNextId(); + std::unique_ptr newVarOp( + new Instruction(this, SpvOpVariable, varTyPtrId, var_id, + {{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, + {SpvStorageClassInput}}})); + get_def_use_mgr()->AnalyzeInstDefUse(&*newVarOp); + module()->AddGlobalValue(std::move(newVarOp)); + get_decoration_mgr()->AddDecorationVal(var_id, SpvDecorationBuiltIn, + builtin); + AddVarToEntryPoints(var_id); + } + builtin_var_id_map_[builtin] = var_id; + return var_id; +} + +void IRContext::AddCalls(const Function* func, std::queue* todo) { + for (auto bi = func->begin(); bi != func->end(); ++bi) + for (auto ii = bi->begin(); ii != bi->end(); ++ii) + if (ii->opcode() == SpvOpFunctionCall) + todo->push(ii->GetSingleWordInOperand(0)); +} + +bool IRContext::ProcessEntryPointCallTree(ProcessFunction& pfn) { + // Collect all of the entry points as the roots. + std::queue roots; + for (auto& e : module()->entry_points()) { + roots.push(e.GetSingleWordInOperand(kEntryPointFunctionIdInIdx)); + } + return ProcessCallTreeFromRoots(pfn, &roots); +} + +bool IRContext::ProcessReachableCallTree(ProcessFunction& pfn) { + std::queue roots; + + // Add all entry points since they can be reached from outside the module. + for (auto& e : module()->entry_points()) + roots.push(e.GetSingleWordInOperand(kEntryPointFunctionIdInIdx)); + + // Add all exported functions since they can be reached from outside the + // module. + for (auto& a : annotations()) { + // TODO: Handle group decorations as well. Currently not generate by any + // front-end, but could be coming. + if (a.opcode() == SpvOp::SpvOpDecorate) { + if (a.GetSingleWordOperand(1) == + SpvDecoration::SpvDecorationLinkageAttributes) { + uint32_t lastOperand = a.NumOperands() - 1; + if (a.GetSingleWordOperand(lastOperand) == + SpvLinkageType::SpvLinkageTypeExport) { + uint32_t id = a.GetSingleWordOperand(0); + if (GetFunction(id)) { + roots.push(id); + } + } + } + } + } + + return ProcessCallTreeFromRoots(pfn, &roots); +} + +bool IRContext::ProcessCallTreeFromRoots(ProcessFunction& pfn, + std::queue* roots) { + // Process call tree + bool modified = false; + std::unordered_set done; + + while (!roots->empty()) { + const uint32_t fi = roots->front(); + roots->pop(); + if (done.insert(fi).second) { + Function* fn = GetFunction(fi); + assert(fn && "Trying to process a function that does not exist."); + modified = pfn(fn) || modified; + AddCalls(fn, roots); + } + } + return modified; +} + +void IRContext::EmitErrorMessage(std::string message, Instruction* inst) { + if (!consumer()) { + return; + } + + Instruction* line_inst = inst; + while (line_inst != nullptr) { // Stop at the beginning of the basic block. + if (!line_inst->dbg_line_insts().empty()) { + line_inst = &line_inst->dbg_line_insts().back(); + if (line_inst->opcode() == SpvOpNoLine) { + line_inst = nullptr; + } + break; + } + line_inst = line_inst->PreviousNode(); + } + + uint32_t line_number = 0; + uint32_t col_number = 0; + char* source = nullptr; + if (line_inst != nullptr) { + Instruction* file_name = + get_def_use_mgr()->GetDef(line_inst->GetSingleWordInOperand(0)); + source = reinterpret_cast(&file_name->GetInOperand(0).words[0]); + + // Get the line number and column number. + line_number = line_inst->GetSingleWordInOperand(1); + col_number = line_inst->GetSingleWordInOperand(2); + } + + message += + "\n " + inst->PrettyPrint(SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES); + consumer()(SPV_MSG_ERROR, source, {line_number, col_number, 0}, + message.c_str()); +} + // Gets the dominator analysis for function |f|. DominatorAnalysis* IRContext::GetDominatorAnalysis(const Function* f) { if (!AreAnalysesValid(kAnalysisDominatorAnalysis)) { diff --git a/third_party/spirv-tools/source/opt/ir_context.h b/third_party/spirv-tools/source/opt/ir_context.h index a9d892fa2f..723a2bbb62 100644 --- a/third_party/spirv-tools/source/opt/ir_context.h +++ b/third_party/spirv-tools/source/opt/ir_context.h @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -37,6 +38,7 @@ #include "source/opt/module.h" #include "source/opt/register_pressure.h" #include "source/opt/scalar_analysis.h" +#include "source/opt/struct_cfg_analysis.h" #include "source/opt/type_manager.h" #include "source/opt/value_number_table.h" #include "source/util/make_unique.h" @@ -71,9 +73,16 @@ class IRContext { kAnalysisScalarEvolution = 1 << 8, kAnalysisRegisterPressure = 1 << 9, kAnalysisValueNumberTable = 1 << 10, - kAnalysisEnd = 1 << 11 + kAnalysisStructuredCFG = 1 << 11, + kAnalysisBuiltinVarId = 1 << 12, + kAnalysisIdToFuncMapping = 1 << 13, + kAnalysisConstants = 1 << 14, + kAnalysisTypes = 1 << 15, + kAnalysisEnd = 1 << 16 }; + using ProcessFunction = std::function; + friend inline Analysis operator|(Analysis lhs, Analysis rhs); friend inline Analysis& operator|=(Analysis& lhs, Analysis rhs); friend inline Analysis operator<<(Analysis a, int shift); @@ -90,7 +99,10 @@ class IRContext { valid_analyses_(kAnalysisNone), constant_mgr_(nullptr), type_mgr_(nullptr), - id_to_name_(nullptr) { + id_to_name_(nullptr), + max_id_bound_(kDefaultMaxIdBound), + preserve_bindings_(false), + preserve_spec_constants_(false) { SetContextMessageConsumer(syntax_context_, consumer_); module_->SetContext(this); } @@ -104,7 +116,10 @@ class IRContext { def_use_mgr_(nullptr), valid_analyses_(kAnalysisNone), type_mgr_(nullptr), - id_to_name_(nullptr) { + id_to_name_(nullptr), + max_id_bound_(kDefaultMaxIdBound), + preserve_bindings_(false), + preserve_spec_constants_(false) { SetContextMessageConsumer(syntax_context_, consumer_); module_->SetContext(this); InitializeCombinators(); @@ -172,14 +187,24 @@ class IRContext { inline IteratorRange debugs3(); inline IteratorRange debugs3() const; - // Clears all debug instructions (excluding OpLine & OpNoLine). - inline void debug_clear(); + // Iterators for debug info instructions (excluding OpLine & OpNoLine) + // contained in this module. These are OpExtInst for OpenCL.DebugInfo.100 + // or DebugInfo extension placed between section 9 and 10. + inline Module::inst_iterator ext_inst_debuginfo_begin(); + inline Module::inst_iterator ext_inst_debuginfo_end(); + inline IteratorRange ext_inst_debuginfo(); + inline IteratorRange ext_inst_debuginfo() const; + + // Add |capability| to the module, if it is not already enabled. + inline void AddCapability(SpvCapability capability); // Appends a capability instruction to this module. inline void AddCapability(std::unique_ptr&& c); // Appends an extension instruction to this module. + inline void AddExtension(const std::string& ext_name); inline void AddExtension(std::unique_ptr&& e); // Appends an extended instruction set instruction to this module. + inline void AddExtInstImport(const std::string& name); inline void AddExtInstImport(std::unique_ptr&& e); // Set the memory model for this module. inline void SetMemoryModel(std::unique_ptr&& m); @@ -198,6 +223,8 @@ class IRContext { // Appends a debug 3 instruction (OpModuleProcessed) to this module. // This is due to decision by the SPIR Working Group, pending publication. inline void AddDebug3Inst(std::unique_ptr&& d); + // Appends a OpExtInst for DebugInfo to this module. + inline void AddExtInstDebugInfo(std::unique_ptr&& d); // Appends an annotation instruction to this module. inline void AddAnnotationInst(std::unique_ptr&& a); // Appends a type-declaration instruction to this module. @@ -225,6 +252,15 @@ class IRContext { return vn_table_.get(); } + // Returns a pointer to a StructuredCFGAnalysis. If the analysis is invalid, + // it is rebuilt first. + StructuredCFGAnalysis* GetStructuredCFGAnalysis() { + if (!AreAnalysesValid(kAnalysisStructuredCFG)) { + BuildStructuredCFGAnalysis(); + } + return struct_cfg_analysis_.get(); + } + // Returns a pointer to a liveness analysis. If the liveness analysis is // invalid, it is rebuilt first. LivenessAnalysis* GetLivenessAnalysis() { @@ -274,8 +310,9 @@ class IRContext { // created yet, it creates one. NOTE: Once created, the constant manager // remains active and it is never re-built. analysis::ConstantManager* get_constant_mgr() { - if (!constant_mgr_) - constant_mgr_ = MakeUnique(this); + if (!AreAnalysesValid(kAnalysisConstants)) { + BuildConstantManager(); + } return constant_mgr_.get(); } @@ -283,8 +320,9 @@ class IRContext { // yet, it creates one. NOTE: Once created, the type manager remains active it // is never re-built. analysis::TypeManager* get_type_mgr() { - if (!type_mgr_) - type_mgr_ = MakeUnique(consumer(), this); + if (!AreAnalysesValid(kAnalysisTypes)) { + BuildTypeManager(); + } return type_mgr_.get(); } @@ -356,6 +394,15 @@ class IRContext { // |before| and |after| must be registered definitions in the DefUseManager. bool ReplaceAllUsesWith(uint32_t before, uint32_t after); + // Replace all uses of |before| id with |after| id if those uses + // (instruction, operand pair) return true for |predicate|. Returns true if + // any replacement happens. This method does not kill the definition of the + // |before| id. If |after| is the same as |before|, does nothing and return + // false. + bool ReplaceAllUsesWithPredicate( + uint32_t before, uint32_t after, + const std::function& predicate); + // Returns true if all of the analyses that are suppose to be valid are // actually valid. bool IsConsistent(); @@ -432,8 +479,18 @@ class IRContext { post_dominator_trees_.erase(f); } - // Return the next available SSA id and increment it. - inline uint32_t TakeNextId() { return module()->TakeNextIdBound(); } + // Return the next available SSA id and increment it. Returns 0 if the + // maximum SSA id has been reached. + inline uint32_t TakeNextId() { + uint32_t next_id = module()->TakeNextIdBound(); + if (next_id == 0) { + if (consumer()) { + std::string message = "ID overflow. Try running compact-ids."; + consumer()(SPV_MSG_ERROR, "", {0, 0, 0}, message.c_str()); + } + } + return next_id; + } FeatureManager* get_feature_mgr() { if (!feature_mgr_.get()) { @@ -442,6 +499,8 @@ class IRContext { return feature_mgr_.get(); } + void ResetFeatureManager() { feature_mgr_.reset(nullptr); } + // Returns the grammar for this context. const AssemblyGrammar& grammar() const { return grammar_; } @@ -456,6 +515,65 @@ class IRContext { return *inst_folder_; } + uint32_t max_id_bound() const { return max_id_bound_; } + void set_max_id_bound(uint32_t new_bound) { max_id_bound_ = new_bound; } + + bool preserve_bindings() const { return preserve_bindings_; } + void set_preserve_bindings(bool should_preserve_bindings) { + preserve_bindings_ = should_preserve_bindings; + } + + bool preserve_spec_constants() const { return preserve_spec_constants_; } + void set_preserve_spec_constants(bool should_preserve_spec_constants) { + preserve_spec_constants_ = should_preserve_spec_constants; + } + + // Return id of input variable only decorated with |builtin|, if in module. + // Create variable and return its id otherwise. If builtin not currently + // supported, return 0. + uint32_t GetBuiltinInputVarId(uint32_t builtin); + + // Returns the function whose id is |id|, if one exists. Returns |nullptr| + // otherwise. + Function* GetFunction(uint32_t id) { + if (!AreAnalysesValid(kAnalysisIdToFuncMapping)) { + BuildIdToFuncMapping(); + } + auto entry = id_to_func_.find(id); + return (entry != id_to_func_.end()) ? entry->second : nullptr; + } + + Function* GetFunction(Instruction* inst) { + if (inst->opcode() != SpvOpFunction) { + return nullptr; + } + return GetFunction(inst->result_id()); + } + + // Add to |todo| all ids of functions called directly from |func|. + void AddCalls(const Function* func, std::queue* todo); + + // Applies |pfn| to every function in the call trees that are rooted at the + // entry points. Returns true if any call |pfn| returns true. By convention + // |pfn| should return true if it modified the module. + bool ProcessEntryPointCallTree(ProcessFunction& pfn); + + // Applies |pfn| to every function in the call trees rooted at the entry + // points and exported functions. Returns true if any call |pfn| returns + // true. By convention |pfn| should return true if it modified the module. + bool ProcessReachableCallTree(ProcessFunction& pfn); + + // Applies |pfn| to every function in the call trees rooted at the elements of + // |roots|. Returns true if any call to |pfn| returns true. By convention + // |pfn| should return true if it modified the module. After returning + // |roots| will be empty. + bool ProcessCallTreeFromRoots(ProcessFunction& pfn, + std::queue* roots); + + // Emmits a error message to the message consumer indicating the error + // described by |message| occurred in |inst|. + void EmitErrorMessage(std::string message, Instruction* inst); + private: // Builds the def-use manager from scratch, even if it was already valid. void BuildDefUseManager() { @@ -476,6 +594,15 @@ class IRContext { valid_analyses_ = valid_analyses_ | kAnalysisInstrToBlockMapping; } + // Builds the instruction-function map for the whole module. + void BuildIdToFuncMapping() { + id_to_func_.clear(); + for (auto& fn : *module_) { + id_to_func_[fn.result_id()] = &fn; + } + valid_analyses_ = valid_analyses_ | kAnalysisIdToFuncMapping; + } + void BuildDecorationManager() { decoration_mgr_ = MakeUnique(module()); valid_analyses_ = valid_analyses_ | kAnalysisDecorations; @@ -504,6 +631,27 @@ class IRContext { valid_analyses_ = valid_analyses_ | kAnalysisValueNumberTable; } + // Builds the structured CFG analysis from scratch, even if it was already + // valid. + void BuildStructuredCFGAnalysis() { + struct_cfg_analysis_ = MakeUnique(this); + valid_analyses_ = valid_analyses_ | kAnalysisStructuredCFG; + } + + // Builds the constant manager from scratch, even if it was already + // valid. + void BuildConstantManager() { + constant_mgr_ = MakeUnique(this); + valid_analyses_ = valid_analyses_ | kAnalysisConstants; + } + + // Builds the type manager from scratch, even if it was already + // valid. + void BuildTypeManager() { + type_mgr_ = MakeUnique(consumer(), this); + valid_analyses_ = valid_analyses_ | kAnalysisTypes; + } + // Removes all computed dominator and post-dominator trees. This will force // the context to rebuild the trees on demand. void ResetDominatorAnalysis() { @@ -520,6 +668,13 @@ class IRContext { valid_analyses_ = valid_analyses_ | kAnalysisLoopAnalysis; } + // Removes all computed loop descriptors. + void ResetBuiltinAnalysis() { + // Clear the cache. + builtin_var_id_map_.clear(); + valid_analyses_ = valid_analyses_ | kAnalysisBuiltinVarId; + } + // Analyzes the features in the owned module. Builds the manager if required. void AnalyzeFeatures() { feature_mgr_ = MakeUnique(grammar_); @@ -543,6 +698,13 @@ class IRContext { // true if the cfg is invalidated. bool CheckCFG(); + // Return id of input variable only decorated with |builtin|, if in module. + // Return 0 otherwise. + uint32_t FindBuiltinInputVar(uint32_t builtin); + + // Add |var_id| to all entry points in module. + void AddVarToEntryPoints(uint32_t var_id); + // The SPIR-V syntax context containing grammar tables for opcodes and // operands. spv_context syntax_context_; @@ -570,13 +732,20 @@ class IRContext { std::unique_ptr decoration_mgr_; std::unique_ptr feature_mgr_; - // A map from instructions the the basic block they belong to. This mapping is + // A map from instructions to the basic block they belong to. This mapping is // built on-demand when get_instr_block() is called. // // NOTE: Do not traverse this map. Ever. Use the function and basic block // iterators to traverse instructions. std::unordered_map instr_to_block_; + // A map from ids to the function they define. This mapping is + // built on-demand when GetFunction() is called. + // + // NOTE: Do not traverse this map. Ever. Use the function and basic block + // iterators to traverse instructions. + std::unordered_map id_to_func_; + // A bitset indicating which analyes are currently valid. Analysis valid_analyses_; @@ -584,6 +753,10 @@ class IRContext { // without side-effect. std::unordered_map> combinator_ops_; + // Opcodes of shader capability core executable instructions + // without side-effect. + std::unordered_map builtin_var_id_map_; + // The CFG for all the functions in |module_|. std::unique_ptr cfg_; @@ -613,6 +786,18 @@ class IRContext { std::unique_ptr vn_table_; std::unique_ptr inst_folder_; + + std::unique_ptr struct_cfg_analysis_; + + // The maximum legal value for the id bound. + uint32_t max_id_bound_; + + // Whether all bindings within |module_| should be preserved. + bool preserve_bindings_; + + // Whether all specialization constants within |module_| + // should be preserved. + bool preserve_spec_constants_; }; inline IRContext::Analysis operator|(IRContext::Analysis lhs, @@ -750,20 +935,85 @@ IteratorRange IRContext::debugs3() const { return ((const Module*)module_.get())->debugs3(); } -void IRContext::debug_clear() { module_->debug_clear(); } +Module::inst_iterator IRContext::ext_inst_debuginfo_begin() { + return module()->ext_inst_debuginfo_begin(); +} + +Module::inst_iterator IRContext::ext_inst_debuginfo_end() { + return module()->ext_inst_debuginfo_end(); +} + +IteratorRange IRContext::ext_inst_debuginfo() { + return module()->ext_inst_debuginfo(); +} + +IteratorRange IRContext::ext_inst_debuginfo() + const { + return ((const Module*)module_.get())->ext_inst_debuginfo(); +} + +void IRContext::AddCapability(SpvCapability capability) { + if (!get_feature_mgr()->HasCapability(capability)) { + std::unique_ptr capability_inst(new Instruction( + this, SpvOpCapability, 0, 0, + {{SPV_OPERAND_TYPE_CAPABILITY, {static_cast(capability)}}})); + AddCapability(std::move(capability_inst)); + } +} void IRContext::AddCapability(std::unique_ptr&& c) { AddCombinatorsForCapability(c->GetSingleWordInOperand(0)); + if (feature_mgr_ != nullptr) { + feature_mgr_->AddCapability( + static_cast(c->GetSingleWordInOperand(0))); + } + if (AreAnalysesValid(kAnalysisDefUse)) { + get_def_use_mgr()->AnalyzeInstDefUse(c.get()); + } module()->AddCapability(std::move(c)); } +void IRContext::AddExtension(const std::string& ext_name) { + const auto num_chars = ext_name.size(); + // Compute num words, accommodate the terminating null character. + const auto num_words = (num_chars + 1 + 3) / 4; + std::vector ext_words(num_words, 0u); + std::memcpy(ext_words.data(), ext_name.data(), num_chars); + AddExtension(std::unique_ptr( + new Instruction(this, SpvOpExtension, 0u, 0u, + {{SPV_OPERAND_TYPE_LITERAL_STRING, ext_words}}))); +} + void IRContext::AddExtension(std::unique_ptr&& e) { + if (AreAnalysesValid(kAnalysisDefUse)) { + get_def_use_mgr()->AnalyzeInstDefUse(e.get()); + } + if (feature_mgr_ != nullptr) { + feature_mgr_->AddExtension(&*e); + } module()->AddExtension(std::move(e)); } +void IRContext::AddExtInstImport(const std::string& name) { + const auto num_chars = name.size(); + // Compute num words, accommodate the terminating null character. + const auto num_words = (num_chars + 1 + 3) / 4; + std::vector ext_words(num_words, 0u); + std::memcpy(ext_words.data(), name.data(), num_chars); + AddExtInstImport(std::unique_ptr( + new Instruction(this, SpvOpExtInstImport, 0u, TakeNextId(), + {{SPV_OPERAND_TYPE_LITERAL_STRING, ext_words}}))); +} + void IRContext::AddExtInstImport(std::unique_ptr&& e) { AddCombinatorsForExtension(e.get()); + if (AreAnalysesValid(kAnalysisDefUse)) { + get_def_use_mgr()->AnalyzeInstDefUse(e.get()); + } module()->AddExtInstImport(std::move(e)); + if (feature_mgr_ != nullptr) { + feature_mgr_->AddExtInstImportIds(module()); + } } void IRContext::SetMemoryModel(std::unique_ptr&& m) { @@ -795,10 +1045,17 @@ void IRContext::AddDebug3Inst(std::unique_ptr&& d) { module()->AddDebug3Inst(std::move(d)); } +void IRContext::AddExtInstDebugInfo(std::unique_ptr&& d) { + module()->AddExtInstDebugInfo(std::move(d)); +} + void IRContext::AddAnnotationInst(std::unique_ptr&& a) { if (AreAnalysesValid(kAnalysisDecorations)) { get_decoration_mgr()->AddDecoration(a.get()); } + if (AreAnalysesValid(kAnalysisDefUse)) { + get_def_use_mgr()->AnalyzeInstDefUse(a.get()); + } module()->AddAnnotationInst(std::move(a)); } @@ -810,10 +1067,10 @@ void IRContext::AddType(std::unique_ptr&& t) { } void IRContext::AddGlobalValue(std::unique_ptr&& v) { - module()->AddGlobalValue(std::move(v)); if (AreAnalysesValid(kAnalysisDefUse)) { - get_def_use_mgr()->AnalyzeInstDef(&*(--types_values_end())); + get_def_use_mgr()->AnalyzeInstDefUse(&*v); } + module()->AddGlobalValue(std::move(v)); } void IRContext::AddFunction(std::unique_ptr&& f) { diff --git a/third_party/spirv-tools/source/opt/ir_loader.cpp b/third_party/spirv-tools/source/opt/ir_loader.cpp index 46e2bee427..836012f171 100644 --- a/third_party/spirv-tools/source/opt/ir_loader.cpp +++ b/third_party/spirv-tools/source/opt/ir_loader.cpp @@ -16,6 +16,9 @@ #include +#include "DebugInfo.h" +#include "OpenCLDebugInfo100.h" +#include "source/ext_inst.h" #include "source/opt/log.h" #include "source/opt/reflect.h" #include "source/util/make_unique.h" @@ -113,11 +116,19 @@ bool IrLoader::AddInstruction(const spv_parsed_instruction_t* inst) { } else if (IsTypeInst(opcode)) { module_->AddType(std::move(spv_inst)); } else if (IsConstantInst(opcode) || opcode == SpvOpVariable || - opcode == SpvOpUndef) { + opcode == SpvOpUndef || + (opcode == SpvOpExtInst && + spvExtInstIsNonSemantic(inst->ext_inst_type))) { module_->AddGlobalValue(std::move(spv_inst)); + } else if (opcode == SpvOpExtInst && + spvExtInstIsDebugInfo(inst->ext_inst_type)) { + module_->AddExtInstDebugInfo(std::move(spv_inst)); } else { - SPIRV_UNIMPLEMENTED(consumer_, - "unhandled inst type outside function definition"); + Errorf(consumer_, src, loc, + "Unhandled inst type (opcode: %d) found outside function " + "definition.", + opcode); + return false; } } else { if (block_ == nullptr) { // Inside function but outside blocks @@ -130,6 +141,39 @@ bool IrLoader::AddInstruction(const spv_parsed_instruction_t* inst) { } function_->AddParameter(std::move(spv_inst)); } else { + if (opcode == SpvOpExtInst && + spvExtInstIsDebugInfo(inst->ext_inst_type)) { + const uint32_t ext_inst_index = inst->words[4]; + if (inst->ext_inst_type == SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100) { + const OpenCLDebugInfo100Instructions ext_inst_key = + OpenCLDebugInfo100Instructions(ext_inst_index); + if (ext_inst_key != OpenCLDebugInfo100DebugScope && + ext_inst_key != OpenCLDebugInfo100DebugNoScope && + ext_inst_key != OpenCLDebugInfo100DebugDeclare && + ext_inst_key != OpenCLDebugInfo100DebugValue) { + Errorf(consumer_, src, loc, + "Debug info extension instruction other than DebugScope, " + "DebugNoScope, DebugDeclare, and DebugValue found inside " + "function", + opcode); + return false; + } + } else { + const DebugInfoInstructions ext_inst_key = + DebugInfoInstructions(ext_inst_index); + if (ext_inst_key != DebugInfoDebugScope && + ext_inst_key != DebugInfoDebugNoScope && + ext_inst_key != DebugInfoDebugDeclare && + ext_inst_key != DebugInfoDebugValue) { + Errorf(consumer_, src, loc, + "Debug info extension instruction other than DebugScope, " + "DebugNoScope, DebugDeclare, and DebugValue found inside " + "function", + opcode); + return false; + } + } + } block_->AddInstruction(std::move(spv_inst)); } } @@ -157,6 +201,9 @@ void IrLoader::EndModule() { for (auto& function : *module_) { for (auto& bb : function) bb.SetParent(&function); } + + // Copy any trailing Op*Line instruction into the module + module_->SetTrailingDbgLineInfo(std::move(dbg_line_info_)); } } // namespace opt diff --git a/third_party/spirv-tools/source/opt/legalize_vector_shuffle_pass.cpp b/third_party/spirv-tools/source/opt/legalize_vector_shuffle_pass.cpp new file mode 100644 index 0000000000..b5d5d5993c --- /dev/null +++ b/third_party/spirv-tools/source/opt/legalize_vector_shuffle_pass.cpp @@ -0,0 +1,39 @@ +// Copyright (c) 2019 Google LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/opt/legalize_vector_shuffle_pass.h" + +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace opt { + +Pass::Status LegalizeVectorShufflePass::Process() { + bool changed = false; + context()->module()->ForEachInst([&changed](Instruction* inst) { + if (inst->opcode() != SpvOpVectorShuffle) return; + + for (uint32_t idx = 2; idx < inst->NumInOperands(); ++idx) { + auto literal = inst->GetSingleWordInOperand(idx); + if (literal != 0xFFFFFFFF) continue; + changed = true; + inst->SetInOperand(idx, {0}); + } + }); + + return changed ? Status::SuccessWithChange : Status::SuccessWithoutChange; +} + +} // namespace opt +} // namespace spvtools diff --git a/third_party/spirv-tools/source/opt/legalize_vector_shuffle_pass.h b/third_party/spirv-tools/source/opt/legalize_vector_shuffle_pass.h new file mode 100644 index 0000000000..ca6e1dfbe2 --- /dev/null +++ b/third_party/spirv-tools/source/opt/legalize_vector_shuffle_pass.h @@ -0,0 +1,53 @@ +// Copyright (c) 2019 Google LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_OPT_LEGALIZE_VECTOR_SHUFFLE_PASS_H_ +#define SOURCE_OPT_LEGALIZE_VECTOR_SHUFFLE_PASS_H_ + +#include "source/opt/ir_context.h" +#include "source/opt/module.h" +#include "source/opt/pass.h" + +namespace spvtools { +namespace opt { + +// Converts any usages of 0xFFFFFFFF for the literals in OpVectorShuffle to a +// literal 0. This is needed because using OxFFFFFFFF is forbidden by the WebGPU +// spec. 0xFFFFFFFF in the main spec indicates that the result for this +// component has no source, thus is undefined. Since this is undefined +// behaviour we are free to use 0. +class LegalizeVectorShufflePass : public Pass { + public: + const char* name() const override { return "legalize-vector-shuffle"; } + Status Process() override; + + IRContext::Analysis GetPreservedAnalyses() override { + return IRContext::kAnalysisInstrToBlockMapping | + IRContext::kAnalysisDecorations | IRContext::kAnalysisCombinators | + IRContext::kAnalysisCFG | IRContext::kAnalysisDominatorAnalysis | + IRContext::kAnalysisLoopAnalysis | IRContext::kAnalysisNameMap | + IRContext::kAnalysisScalarEvolution | + IRContext::kAnalysisRegisterPressure | + IRContext::kAnalysisValueNumberTable | + IRContext::kAnalysisStructuredCFG | + IRContext::kAnalysisBuiltinVarId | + IRContext::kAnalysisIdToFuncMapping | IRContext::kAnalysisTypes | + IRContext::kAnalysisDefUse | IRContext::kAnalysisConstants; + } +}; + +} // namespace opt +} // namespace spvtools + +#endif // SOURCE_OPT_LEGALIZE_VECTOR_SHUFFLE_PASS_H_ diff --git a/third_party/spirv-tools/source/opt/licm_pass.cpp b/third_party/spirv-tools/source/opt/licm_pass.cpp index d8256679e3..82851fd276 100644 --- a/third_party/spirv-tools/source/opt/licm_pass.cpp +++ b/third_party/spirv-tools/source/opt/licm_pass.cpp @@ -23,70 +23,81 @@ namespace spvtools { namespace opt { -Pass::Status LICMPass::Process() { - return ProcessIRContext() ? Status::SuccessWithChange - : Status::SuccessWithoutChange; -} +Pass::Status LICMPass::Process() { return ProcessIRContext(); } -bool LICMPass::ProcessIRContext() { - bool modified = false; +Pass::Status LICMPass::ProcessIRContext() { + Status status = Status::SuccessWithoutChange; Module* module = get_module(); // Process each function in the module - for (Function& f : *module) { - modified |= ProcessFunction(&f); + for (auto func = module->begin(); + func != module->end() && status != Status::Failure; ++func) { + status = CombineStatus(status, ProcessFunction(&*func)); } - return modified; + return status; } -bool LICMPass::ProcessFunction(Function* f) { - bool modified = false; +Pass::Status LICMPass::ProcessFunction(Function* f) { + Status status = Status::SuccessWithoutChange; LoopDescriptor* loop_descriptor = context()->GetLoopDescriptor(f); // Process each loop in the function - for (Loop& loop : *loop_descriptor) { + for (auto it = loop_descriptor->begin(); + it != loop_descriptor->end() && status != Status::Failure; ++it) { + Loop& loop = *it; // Ignore nested loops, as we will process them in order in ProcessLoop if (loop.IsNested()) { continue; } - modified |= ProcessLoop(&loop, f); + status = CombineStatus(status, ProcessLoop(&loop, f)); } - return modified; + return status; } -bool LICMPass::ProcessLoop(Loop* loop, Function* f) { - bool modified = false; +Pass::Status LICMPass::ProcessLoop(Loop* loop, Function* f) { + Status status = Status::SuccessWithoutChange; // Process all nested loops first - for (Loop* nested_loop : *loop) { - modified |= ProcessLoop(nested_loop, f); + for (auto nl = loop->begin(); nl != loop->end() && status != Status::Failure; + ++nl) { + Loop* nested_loop = *nl; + status = CombineStatus(status, ProcessLoop(nested_loop, f)); } std::vector loop_bbs{}; - modified |= AnalyseAndHoistFromBB(loop, f, loop->GetHeaderBlock(), &loop_bbs); + status = CombineStatus( + status, + AnalyseAndHoistFromBB(loop, f, loop->GetHeaderBlock(), &loop_bbs)); - for (size_t i = 0; i < loop_bbs.size(); ++i) { + for (size_t i = 0; i < loop_bbs.size() && status != Status::Failure; ++i) { BasicBlock* bb = loop_bbs[i]; // do not delete the element - modified |= AnalyseAndHoistFromBB(loop, f, bb, &loop_bbs); + status = + CombineStatus(status, AnalyseAndHoistFromBB(loop, f, bb, &loop_bbs)); } - return modified; + return status; } -bool LICMPass::AnalyseAndHoistFromBB(Loop* loop, Function* f, BasicBlock* bb, - std::vector* loop_bbs) { +Pass::Status LICMPass::AnalyseAndHoistFromBB( + Loop* loop, Function* f, BasicBlock* bb, + std::vector* loop_bbs) { bool modified = false; - std::function hoist_inst = + std::function hoist_inst = [this, &loop, &modified](Instruction* inst) { if (loop->ShouldHoistInstruction(this->context(), inst)) { - HoistInstruction(loop, inst); + if (!HoistInstruction(loop, inst)) { + return false; + } modified = true; } + return true; }; if (IsImmediatelyContainedInLoop(loop, f, bb)) { - bb->ForEachInst(hoist_inst, false); + if (!bb->WhileEachInst(hoist_inst, false)) { + return Status::Failure; + } } DominatorAnalysis* dom_analysis = context()->GetDominatorAnalysis(f); @@ -98,7 +109,7 @@ bool LICMPass::AnalyseAndHoistFromBB(Loop* loop, Function* f, BasicBlock* bb, } } - return modified; + return (modified ? Status::SuccessWithChange : Status::SuccessWithoutChange); } bool LICMPass::IsImmediatelyContainedInLoop(Loop* loop, Function* f, @@ -107,10 +118,22 @@ bool LICMPass::IsImmediatelyContainedInLoop(Loop* loop, Function* f, return loop == (*loop_descriptor)[bb->id()]; } -void LICMPass::HoistInstruction(Loop* loop, Instruction* inst) { +bool LICMPass::HoistInstruction(Loop* loop, Instruction* inst) { + // TODO(1841): Handle failure to create pre-header. BasicBlock* pre_header_bb = loop->GetOrCreatePreHeaderBlock(); - inst->InsertBefore(std::move(&(*pre_header_bb->tail()))); + if (!pre_header_bb) { + return false; + } + Instruction* insertion_point = &*pre_header_bb->tail(); + Instruction* previous_node = insertion_point->PreviousNode(); + if (previous_node && (previous_node->opcode() == SpvOpLoopMerge || + previous_node->opcode() == SpvOpSelectionMerge)) { + insertion_point = previous_node; + } + + inst->InsertBefore(insertion_point); context()->set_instr_block(inst, pre_header_bb); + return true; } } // namespace opt diff --git a/third_party/spirv-tools/source/opt/licm_pass.h b/third_party/spirv-tools/source/opt/licm_pass.h index a17450043a..597fe920a4 100644 --- a/third_party/spirv-tools/source/opt/licm_pass.h +++ b/third_party/spirv-tools/source/opt/licm_pass.h @@ -35,30 +35,35 @@ class LICMPass : public Pass { private: // Searches the IRContext for functions and processes each, moving invariants - // outside loops within the function where possible - // Returns true if a change was made to a function within the IRContext - bool ProcessIRContext(); + // outside loops within the function where possible. + // Returns the status depending on whether or not there was a failure or + // change. + Pass::Status ProcessIRContext(); // Checks the function for loops, calling ProcessLoop on each one found. - // Returns true if a change was made to the function, false otherwise. - bool ProcessFunction(Function* f); + // Returns the status depending on whether or not there was a failure or + // change. + Pass::Status ProcessFunction(Function* f); // Checks for invariants in the loop and attempts to move them to the loops // preheader. Works from inner loop to outer when nested loops are found. - // Returns true if a change was made to the loop, false otherwise. - bool ProcessLoop(Loop* loop, Function* f); + // Returns the status depending on whether or not there was a failure or + // change. + Pass::Status ProcessLoop(Loop* loop, Function* f); // Analyses each instruction in |bb|, hoisting invariants to |pre_header_bb|. // Each child of |bb| wrt to |dom_tree| is pushed to |loop_bbs| - bool AnalyseAndHoistFromBB(Loop* loop, Function* f, BasicBlock* bb, - std::vector* loop_bbs); + // Returns the status depending on whether or not there was a failure or + // change. + Pass::Status AnalyseAndHoistFromBB(Loop* loop, Function* f, BasicBlock* bb, + std::vector* loop_bbs); // Returns true if |bb| is immediately contained in |loop| bool IsImmediatelyContainedInLoop(Loop* loop, Function* f, BasicBlock* bb); - // Move the instruction to the given BasicBlock + // Move the instruction to the preheader of |loop|. // This method will update the instruction to block mapping for the context - void HoistInstruction(Loop* loop, Instruction* inst); + bool HoistInstruction(Loop* loop, Instruction* inst); }; } // namespace opt diff --git a/third_party/spirv-tools/source/opt/local_access_chain_convert_pass.cpp b/third_party/spirv-tools/source/opt/local_access_chain_convert_pass.cpp index 5d00e98f78..19215967ae 100644 --- a/third_party/spirv-tools/source/opt/local_access_chain_convert_pass.cpp +++ b/third_party/spirv-tools/source/opt/local_access_chain_convert_pass.cpp @@ -46,6 +46,10 @@ uint32_t LocalAccessChainConvertPass::BuildAndAppendVarLoad( const Instruction* ptrInst, uint32_t* varId, uint32_t* varPteTypeId, std::vector>* newInsts) { const uint32_t ldResultId = TakeNextId(); + if (ldResultId == 0) { + return 0; + } + *varId = ptrInst->GetSingleWordInOperand(kAccessChainPtrIdInIdx); const Instruction* varInst = get_def_use_mgr()->GetDef(*varId); assert(varInst->opcode() == SpvOpVariable); @@ -70,7 +74,7 @@ void LocalAccessChainConvertPass::AppendConstantOperands( }); } -void LocalAccessChainConvertPass::ReplaceAccessChainLoad( +bool LocalAccessChainConvertPass::ReplaceAccessChainLoad( const Instruction* address_inst, Instruction* original_load) { // Build and append load of variable in ptrInst std::vector> new_inst; @@ -78,6 +82,10 @@ void LocalAccessChainConvertPass::ReplaceAccessChainLoad( uint32_t varPteTypeId; const uint32_t ldResultId = BuildAndAppendVarLoad(address_inst, &varId, &varPteTypeId, &new_inst); + if (ldResultId == 0) { + return false; + } + context()->get_decoration_mgr()->CloneDecorations( original_load->result_id(), ldResultId, {SpvDecorationRelaxedPrecision}); original_load->InsertBefore(std::move(new_inst)); @@ -95,9 +103,10 @@ void LocalAccessChainConvertPass::ReplaceAccessChainLoad( original_load->SetOpcode(SpvOpCompositeExtract); original_load->ReplaceOperands(new_operands); context()->UpdateDefUse(original_load); + return true; } -void LocalAccessChainConvertPass::GenAccessChainStoreReplacement( +bool LocalAccessChainConvertPass::GenAccessChainStoreReplacement( const Instruction* ptrInst, uint32_t valId, std::vector>* newInsts) { // Build and append load of variable in ptrInst @@ -105,11 +114,18 @@ void LocalAccessChainConvertPass::GenAccessChainStoreReplacement( uint32_t varPteTypeId; const uint32_t ldResultId = BuildAndAppendVarLoad(ptrInst, &varId, &varPteTypeId, newInsts); + if (ldResultId == 0) { + return false; + } + context()->get_decoration_mgr()->CloneDecorations( varId, ldResultId, {SpvDecorationRelaxedPrecision}); // Build and append Insert const uint32_t insResultId = TakeNextId(); + if (insResultId == 0) { + return false; + } std::vector ins_in_opnds = { {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {valId}}, {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {ldResultId}}}; @@ -125,6 +141,7 @@ void LocalAccessChainConvertPass::GenAccessChainStoreReplacement( {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {varId}}, {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {insResultId}}}, newInsts); + return true; } bool LocalAccessChainConvertPass::IsConstantIndexAccessChain( @@ -198,7 +215,8 @@ void LocalAccessChainConvertPass::FindTargetVars(Function* func) { } } -bool LocalAccessChainConvertPass::ConvertLocalAccessChains(Function* func) { +Pass::Status LocalAccessChainConvertPass::ConvertLocalAccessChains( + Function* func) { FindTargetVars(func); // Replace access chains of all targeted variables with equivalent // extract and insert sequences @@ -213,7 +231,9 @@ bool LocalAccessChainConvertPass::ConvertLocalAccessChains(Function* func) { if (!IsNonPtrAccessChain(ptrInst->opcode())) break; if (!IsTargetVar(varId)) break; std::vector> newInsts; - ReplaceAccessChainLoad(ptrInst, &*ii); + if (!ReplaceAccessChainLoad(ptrInst, &*ii)) { + return Status::Failure; + } modified = true; } break; case SpvOpStore: { @@ -223,7 +243,9 @@ bool LocalAccessChainConvertPass::ConvertLocalAccessChains(Function* func) { if (!IsTargetVar(varId)) break; std::vector> newInsts; uint32_t valId = ii->GetSingleWordInOperand(kStoreValIdInIdx); - GenAccessChainStoreReplacement(ptrInst, valId, &newInsts); + if (!GenAccessChainStoreReplacement(ptrInst, valId, &newInsts)) { + return Status::Failure; + } dead_instructions.push_back(&*ii); ++ii; ii = ii.InsertBefore(std::move(newInsts)); @@ -248,7 +270,7 @@ bool LocalAccessChainConvertPass::ConvertLocalAccessChains(Function* func) { }); } } - return modified; + return (modified ? Status::SuccessWithChange : Status::SuccessWithoutChange); } void LocalAccessChainConvertPass::Initialize() { @@ -264,6 +286,12 @@ void LocalAccessChainConvertPass::Initialize() { } bool LocalAccessChainConvertPass::AllExtensionsSupported() const { + // This capability can now exist without the extension, so we have to check + // for the capability. This pass is only looking at function scope symbols, + // so we do not care if there are variable pointers on storage buffers. + if (context()->get_feature_mgr()->HasCapability( + SpvCapabilityVariablePointers)) + return false; // If any extension not in whitelist, return false for (auto& ei : get_module()->extensions()) { const char* extName = @@ -288,12 +316,16 @@ Pass::Status LocalAccessChainConvertPass::ProcessImpl() { if (ai.opcode() == SpvOpGroupDecorate) return Status::SuccessWithoutChange; // Do not process if any disallowed extensions are enabled if (!AllExtensionsSupported()) return Status::SuccessWithoutChange; - // Process all entry point functions. - ProcessFunction pfn = [this](Function* fp) { - return ConvertLocalAccessChains(fp); - }; - bool modified = ProcessEntryPointCallTree(pfn, get_module()); - return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange; + + // Process all functions in the module. + Status status = Status::SuccessWithoutChange; + for (Function& func : *get_module()) { + status = CombineStatus(status, ConvertLocalAccessChains(&func)); + if (status == Status::Failure) { + break; + } + } + return status; } LocalAccessChainConvertPass::LocalAccessChainConvertPass() {} @@ -337,8 +369,16 @@ void LocalAccessChainConvertPass::InitExtensions() { "SPV_AMD_gpu_shader_half_float_fetch", "SPV_GOOGLE_decorate_string", "SPV_GOOGLE_hlsl_functionality1", + "SPV_GOOGLE_user_type", "SPV_NV_shader_subgroup_partitioned", "SPV_EXT_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_EXT_fragment_invocation_density", }); } diff --git a/third_party/spirv-tools/source/opt/local_access_chain_convert_pass.h b/third_party/spirv-tools/source/opt/local_access_chain_convert_pass.h index 9d06890bfd..e3592bf0ce 100644 --- a/third_party/spirv-tools/source/opt/local_access_chain_convert_pass.h +++ b/third_party/spirv-tools/source/opt/local_access_chain_convert_pass.h @@ -44,7 +44,8 @@ class LocalAccessChainConvertPass : public MemPass { Status Process() override; IRContext::Analysis GetPreservedAnalyses() override { - return IRContext::kAnalysisDefUse; + return IRContext::kAnalysisDefUse | IRContext::kAnalysisConstants | + IRContext::kAnalysisTypes; } using ProcessFunction = std::function; @@ -81,16 +82,16 @@ class LocalAccessChainConvertPass : public MemPass { // Create a load/insert/store equivalent to a store of // |valId| through (constant index) access chaing |ptrInst|. - // Append to |newInsts|. - void GenAccessChainStoreReplacement( + // Append to |newInsts|. Returns true if successful. + bool GenAccessChainStoreReplacement( const Instruction* ptrInst, uint32_t valId, std::vector>* newInsts); // For the (constant index) access chain |address_inst|, create an // equivalent load and extract that replaces |original_load|. The result id // of the extract will be the same as the original result id of - // |original_load|. - void ReplaceAccessChainLoad(const Instruction* address_inst, + // |original_load|. Returns true if successful. + bool ReplaceAccessChainLoad(const Instruction* address_inst, Instruction* original_load); // Return true if all indices of access chain |acp| are OpConstant integers @@ -105,7 +106,9 @@ class LocalAccessChainConvertPass : public MemPass { // // Nested access chains and pointer access chains are not currently // converted. - bool ConvertLocalAccessChains(Function* func); + // + // Returns a status to indicate success or failure, and change or no change. + Status ConvertLocalAccessChains(Function* func); // Initialize extensions whitelist void InitExtensions(); diff --git a/third_party/spirv-tools/source/opt/local_redundancy_elimination.h b/third_party/spirv-tools/source/opt/local_redundancy_elimination.h index 9f55c8bfea..770457a32f 100644 --- a/third_party/spirv-tools/source/opt/local_redundancy_elimination.h +++ b/third_party/spirv-tools/source/opt/local_redundancy_elimination.h @@ -41,7 +41,8 @@ class LocalRedundancyEliminationPass : public Pass { IRContext::kAnalysisInstrToBlockMapping | IRContext::kAnalysisDecorations | IRContext::kAnalysisCombinators | IRContext::kAnalysisCFG | IRContext::kAnalysisDominatorAnalysis | - IRContext::kAnalysisNameMap; + IRContext::kAnalysisNameMap | IRContext::kAnalysisConstants | + IRContext::kAnalysisTypes; } protected: diff --git a/third_party/spirv-tools/source/opt/local_single_block_elim_pass.cpp b/third_party/spirv-tools/source/opt/local_single_block_elim_pass.cpp index bb909f4aa9..aebbd000fc 100644 --- a/third_party/spirv-tools/source/opt/local_single_block_elim_pass.cpp +++ b/third_party/spirv-tools/source/opt/local_single_block_elim_pass.cpp @@ -187,6 +187,7 @@ Pass::Status LocalSingleBlockLoadStoreElimPass::ProcessImpl() { // Assumes relaxed logical addressing only (see instruction.h). if (context()->get_feature_mgr()->HasCapability(SpvCapabilityAddresses)) return Status::SuccessWithoutChange; + // Do not process if module contains OpGroupDecorate. Additional // support required in KillNamesAndDecorates(). // TODO(greg-lunarg): Add support for OpGroupDecorate @@ -200,7 +201,7 @@ Pass::Status LocalSingleBlockLoadStoreElimPass::ProcessImpl() { return LocalSingleBlockLoadStoreElim(fp); }; - bool modified = ProcessEntryPointCallTree(pfn, get_module()); + bool modified = context()->ProcessEntryPointCallTree(pfn); return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange; } @@ -233,8 +234,7 @@ void LocalSingleBlockLoadStoreElimPass::InitExtensions() { "SPV_NV_geometry_shader_passthrough", "SPV_AMD_texture_gather_bias_lod", "SPV_KHR_storage_buffer_storage_class", - // SPV_KHR_variable_pointers - // Currently do not support extended pointer expressions + "SPV_KHR_variable_pointers", "SPV_AMD_gpu_shader_int16", "SPV_KHR_post_depth_coverage", "SPV_KHR_shader_atomic_counter_ops", @@ -246,8 +246,17 @@ void LocalSingleBlockLoadStoreElimPass::InitExtensions() { "SPV_AMD_gpu_shader_half_float_fetch", "SPV_GOOGLE_decorate_string", "SPV_GOOGLE_hlsl_functionality1", + "SPV_GOOGLE_user_type", "SPV_NV_shader_subgroup_partitioned", "SPV_EXT_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_EXT_fragment_invocation_density", + "SPV_EXT_physical_storage_buffer", }); } diff --git a/third_party/spirv-tools/source/opt/local_single_block_elim_pass.h b/third_party/spirv-tools/source/opt/local_single_block_elim_pass.h index 3dead98347..0fe7732a82 100644 --- a/third_party/spirv-tools/source/opt/local_single_block_elim_pass.h +++ b/third_party/spirv-tools/source/opt/local_single_block_elim_pass.h @@ -42,7 +42,9 @@ class LocalSingleBlockLoadStoreElimPass : public MemPass { Status Process() override; IRContext::Analysis GetPreservedAnalyses() override { - return IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping; + return IRContext::kAnalysisDefUse | + IRContext::kAnalysisInstrToBlockMapping | + IRContext::kAnalysisConstants | IRContext::kAnalysisTypes; } private: diff --git a/third_party/spirv-tools/source/opt/local_single_store_elim_pass.cpp b/third_party/spirv-tools/source/opt/local_single_store_elim_pass.cpp index 4c837fc73f..d6beeab296 100644 --- a/third_party/spirv-tools/source/opt/local_single_store_elim_pass.cpp +++ b/third_party/spirv-tools/source/opt/local_single_store_elim_pass.cpp @@ -67,7 +67,7 @@ Pass::Status LocalSingleStoreElimPass::ProcessImpl() { ProcessFunction pfn = [this](Function* fp) { return LocalSingleStoreElim(fp); }; - bool modified = ProcessEntryPointCallTree(pfn, get_module()); + bool modified = context()->ProcessEntryPointCallTree(pfn); return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange; } @@ -98,8 +98,7 @@ void LocalSingleStoreElimPass::InitExtensionWhiteList() { "SPV_NV_geometry_shader_passthrough", "SPV_AMD_texture_gather_bias_lod", "SPV_KHR_storage_buffer_storage_class", - // SPV_KHR_variable_pointers - // Currently do not support extended pointer expressions + "SPV_KHR_variable_pointers", "SPV_AMD_gpu_shader_int16", "SPV_KHR_post_depth_coverage", "SPV_KHR_shader_atomic_counter_ops", @@ -113,6 +112,14 @@ void LocalSingleStoreElimPass::InitExtensionWhiteList() { "SPV_GOOGLE_hlsl_functionality1", "SPV_NV_shader_subgroup_partitioned", "SPV_EXT_descriptor_indexing", + "SPV_NV_fragment_shader_barycentric", + "SPV_NV_compute_shader_derivatives", + "SPV_NV_shader_image_footprint", + "SPV_NV_shading_rate", + "SPV_NV_mesh_shader", + "SPV_NV_ray_tracing", + "SPV_EXT_fragment_invocation_density", + "SPV_EXT_physical_storage_buffer", }); } bool LocalSingleStoreElimPass::ProcessVariable(Instruction* var_inst) { diff --git a/third_party/spirv-tools/source/opt/local_single_store_elim_pass.h b/third_party/spirv-tools/source/opt/local_single_store_elim_pass.h index d3d64b829a..4cf8bbb86a 100644 --- a/third_party/spirv-tools/source/opt/local_single_store_elim_pass.h +++ b/third_party/spirv-tools/source/opt/local_single_store_elim_pass.h @@ -45,7 +45,9 @@ class LocalSingleStoreElimPass : public Pass { Status Process() override; IRContext::Analysis GetPreservedAnalyses() override { - return IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping; + return IRContext::kAnalysisDefUse | + IRContext::kAnalysisInstrToBlockMapping | + IRContext::kAnalysisConstants | IRContext::kAnalysisTypes; } private: diff --git a/third_party/spirv-tools/source/opt/local_ssa_elim_pass.cpp b/third_party/spirv-tools/source/opt/local_ssa_elim_pass.cpp deleted file mode 100644 index ec7326ed0e..0000000000 --- a/third_party/spirv-tools/source/opt/local_ssa_elim_pass.cpp +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright (c) 2017 The Khronos Group Inc. -// Copyright (c) 2017 Valve Corporation -// Copyright (c) 2017 LunarG Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "source/opt/local_ssa_elim_pass.h" - -#include "source/cfa.h" -#include "source/opt/iterator.h" -#include "source/opt/ssa_rewrite_pass.h" - -namespace spvtools { -namespace opt { - -bool LocalMultiStoreElimPass::AllExtensionsSupported() const { - // If any extension not in whitelist, return false - for (auto& ei : get_module()->extensions()) { - const char* extName = - reinterpret_cast(&ei.GetInOperand(0).words[0]); - if (extensions_whitelist_.find(extName) == extensions_whitelist_.end()) - return false; - } - return true; -} - -Pass::Status LocalMultiStoreElimPass::ProcessImpl() { - // Assumes relaxed logical addressing only (see instruction.h) - // TODO(greg-lunarg): Add support for physical addressing - if (context()->get_feature_mgr()->HasCapability(SpvCapabilityAddresses)) - return Status::SuccessWithoutChange; - // Do not process if module contains OpGroupDecorate. Additional - // support required in KillNamesAndDecorates(). - // TODO(greg-lunarg): Add support for OpGroupDecorate - for (auto& ai : get_module()->annotations()) - if (ai.opcode() == SpvOpGroupDecorate) return Status::SuccessWithoutChange; - // Do not process if any disallowed extensions are enabled - if (!AllExtensionsSupported()) return Status::SuccessWithoutChange; - // Process functions - ProcessFunction pfn = [this](Function* fp) { - return SSARewriter(this).RewriteFunctionIntoSSA(fp); - }; - bool modified = ProcessEntryPointCallTree(pfn, get_module()); - return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange; -} - -LocalMultiStoreElimPass::LocalMultiStoreElimPass() = default; - -Pass::Status LocalMultiStoreElimPass::Process() { - // Initialize extension whitelist - InitExtensions(); - return ProcessImpl(); -} - -void LocalMultiStoreElimPass::InitExtensions() { - extensions_whitelist_.clear(); - extensions_whitelist_.insert({ - "SPV_AMD_shader_explicit_vertex_parameter", - "SPV_AMD_shader_trinary_minmax", - "SPV_AMD_gcn_shader", - "SPV_KHR_shader_ballot", - "SPV_AMD_shader_ballot", - "SPV_AMD_gpu_shader_half_float", - "SPV_KHR_shader_draw_parameters", - "SPV_KHR_subgroup_vote", - "SPV_KHR_16bit_storage", - "SPV_KHR_device_group", - "SPV_KHR_multiview", - "SPV_NVX_multiview_per_view_attributes", - "SPV_NV_viewport_array2", - "SPV_NV_stereo_view_rendering", - "SPV_NV_sample_mask_override_coverage", - "SPV_NV_geometry_shader_passthrough", - "SPV_AMD_texture_gather_bias_lod", - "SPV_KHR_storage_buffer_storage_class", - // SPV_KHR_variable_pointers - // Currently do not support extended pointer expressions - "SPV_AMD_gpu_shader_int16", - "SPV_KHR_post_depth_coverage", - "SPV_KHR_shader_atomic_counter_ops", - "SPV_EXT_shader_stencil_export", - "SPV_EXT_shader_viewport_index_layer", - "SPV_AMD_shader_image_load_store_lod", - "SPV_AMD_shader_fragment_mask", - "SPV_EXT_fragment_fully_covered", - "SPV_AMD_gpu_shader_half_float_fetch", - "SPV_GOOGLE_decorate_string", - "SPV_GOOGLE_hlsl_functionality1", - "SPV_NV_shader_subgroup_partitioned", - "SPV_EXT_descriptor_indexing", - }); -} - -} // namespace opt -} // namespace spvtools diff --git a/third_party/spirv-tools/source/opt/local_ssa_elim_pass.h b/third_party/spirv-tools/source/opt/local_ssa_elim_pass.h deleted file mode 100644 index 63d3c33bac..0000000000 --- a/third_party/spirv-tools/source/opt/local_ssa_elim_pass.h +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright (c) 2017 The Khronos Group Inc. -// Copyright (c) 2017 Valve Corporation -// Copyright (c) 2017 LunarG Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef SOURCE_OPT_LOCAL_SSA_ELIM_PASS_H_ -#define SOURCE_OPT_LOCAL_SSA_ELIM_PASS_H_ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "source/opt/basic_block.h" -#include "source/opt/def_use_manager.h" -#include "source/opt/mem_pass.h" -#include "source/opt/module.h" - -namespace spvtools { -namespace opt { - -// See optimizer.hpp for documentation. -class LocalMultiStoreElimPass : public MemPass { - using cbb_ptr = const BasicBlock*; - - public: - using GetBlocksFunction = - std::function*(const BasicBlock*)>; - - LocalMultiStoreElimPass(); - - const char* name() const override { return "eliminate-local-multi-store"; } - Status Process() override; - - IRContext::Analysis GetPreservedAnalyses() override { - return IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping; - } - - private: - // Initialize extensions whitelist - void InitExtensions(); - - // Return true if all extensions in this module are allowed by this pass. - bool AllExtensionsSupported() const; - - Pass::Status ProcessImpl(); - - // Extensions supported by this pass. - std::unordered_set extensions_whitelist_; -}; - -} // namespace opt -} // namespace spvtools - -#endif // SOURCE_OPT_LOCAL_SSA_ELIM_PASS_H_ diff --git a/third_party/spirv-tools/source/opt/log.h b/third_party/spirv-tools/source/opt/log.h index f87cbf3817..68051002e2 100644 --- a/third_party/spirv-tools/source/opt/log.h +++ b/third_party/spirv-tools/source/opt/log.h @@ -54,18 +54,19 @@ // Logs an error message to the consumer saying the given feature is // unimplemented. -#define SPIRV_UNIMPLEMENTED(consumer, feature) \ - do { \ - spvtools::Log(consumer, SPV_MSG_INTERNAL_ERROR, __FILE__, \ - {__LINE__, 0, 0}, "unimplemented: " feature); \ +#define SPIRV_UNIMPLEMENTED(consumer, feature) \ + do { \ + spvtools::Log(consumer, SPV_MSG_INTERNAL_ERROR, __FILE__, \ + {static_cast(__LINE__), 0, 0}, \ + "unimplemented: " feature); \ } while (0) // Logs an error message to the consumer saying the code location // should be unreachable. -#define SPIRV_UNREACHABLE(consumer) \ - do { \ - spvtools::Log(consumer, SPV_MSG_INTERNAL_ERROR, __FILE__, \ - {__LINE__, 0, 0}, "unreachable"); \ +#define SPIRV_UNREACHABLE(consumer) \ + do { \ + spvtools::Log(consumer, SPV_MSG_INTERNAL_ERROR, __FILE__, \ + {static_cast(__LINE__), 0, 0}, "unreachable"); \ } while (0) // Helper macros for concatenating arguments. @@ -154,32 +155,34 @@ inline void Errorf(const MessageConsumer& consumer, const char* source, PP_EXPAND(SPIRV_CONCATENATE(SPIRV_DEBUG_, PP_NARGS(__VA_ARGS__))( \ consumer, __VA_ARGS__)) -#define SPIRV_ASSERT_1(consumer, condition) \ - do { \ - if (!(condition)) { \ - spvtools::Log(consumer, SPV_MSG_INTERNAL_ERROR, __FILE__, \ - {__LINE__, 0, 0}, "assertion failed: " #condition); \ - std::exit(EXIT_FAILURE); \ - } \ +#define SPIRV_ASSERT_1(consumer, condition) \ + do { \ + if (!(condition)) { \ + spvtools::Log(consumer, SPV_MSG_INTERNAL_ERROR, __FILE__, \ + {static_cast(__LINE__), 0, 0}, \ + "assertion failed: " #condition); \ + std::exit(EXIT_FAILURE); \ + } \ } while (0) -#define SPIRV_ASSERT_2(consumer, condition, message) \ - do { \ - if (!(condition)) { \ - spvtools::Log(consumer, SPV_MSG_INTERNAL_ERROR, __FILE__, \ - {__LINE__, 0, 0}, "assertion failed: " message); \ - std::exit(EXIT_FAILURE); \ - } \ +#define SPIRV_ASSERT_2(consumer, condition, message) \ + do { \ + if (!(condition)) { \ + spvtools::Log(consumer, SPV_MSG_INTERNAL_ERROR, __FILE__, \ + {static_cast(__LINE__), 0, 0}, \ + "assertion failed: " message); \ + std::exit(EXIT_FAILURE); \ + } \ } while (0) -#define SPIRV_ASSERT_more(consumer, condition, format, ...) \ - do { \ - if (!(condition)) { \ - spvtools::Logf(consumer, SPV_MSG_INTERNAL_ERROR, __FILE__, \ - {__LINE__, 0, 0}, "assertion failed: " format, \ - __VA_ARGS__); \ - std::exit(EXIT_FAILURE); \ - } \ +#define SPIRV_ASSERT_more(consumer, condition, format, ...) \ + do { \ + if (!(condition)) { \ + spvtools::Logf(consumer, SPV_MSG_INTERNAL_ERROR, __FILE__, \ + {static_cast(__LINE__), 0, 0}, \ + "assertion failed: " format, __VA_ARGS__); \ + std::exit(EXIT_FAILURE); \ + } \ } while (0) #define SPIRV_ASSERT_3(consumer, condition, format, ...) \ @@ -191,16 +194,17 @@ inline void Errorf(const MessageConsumer& consumer, const char* source, #define SPIRV_ASSERT_5(consumer, condition, format, ...) \ SPIRV_ASSERT_more(consumer, condition, format, __VA_ARGS__) -#define SPIRV_DEBUG_1(consumer, message) \ - do { \ - spvtools::Log(consumer, SPV_MSG_DEBUG, __FILE__, {__LINE__, 0, 0}, \ - message); \ +#define SPIRV_DEBUG_1(consumer, message) \ + do { \ + spvtools::Log(consumer, SPV_MSG_DEBUG, __FILE__, \ + {static_cast(__LINE__), 0, 0}, message); \ } while (0) -#define SPIRV_DEBUG_more(consumer, format, ...) \ - do { \ - spvtools::Logf(consumer, SPV_MSG_DEBUG, __FILE__, {__LINE__, 0, 0}, \ - format, __VA_ARGS__); \ +#define SPIRV_DEBUG_more(consumer, format, ...) \ + do { \ + spvtools::Logf(consumer, SPV_MSG_DEBUG, __FILE__, \ + {static_cast(__LINE__), 0, 0}, format, \ + __VA_ARGS__); \ } while (0) #define SPIRV_DEBUG_2(consumer, format, ...) \ diff --git a/third_party/spirv-tools/source/opt/loop_dependence.h b/third_party/spirv-tools/source/opt/loop_dependence.h index 582c8d0acb..03a9075fe0 100644 --- a/third_party/spirv-tools/source/opt/loop_dependence.h +++ b/third_party/spirv-tools/source/opt/loop_dependence.h @@ -181,19 +181,21 @@ class Constraint { bool operator!=(const Constraint& other) const; +// clang-format off #define DeclareCastMethod(target) \ virtual target* As##target() { return nullptr; } \ virtual const target* As##target() const { return nullptr; } - DeclareCastMethod(DependenceLine); - DeclareCastMethod(DependenceDistance); - DeclareCastMethod(DependencePoint); - DeclareCastMethod(DependenceNone); - DeclareCastMethod(DependenceEmpty); + DeclareCastMethod(DependenceLine) + DeclareCastMethod(DependenceDistance) + DeclareCastMethod(DependencePoint) + DeclareCastMethod(DependenceNone) + DeclareCastMethod(DependenceEmpty) #undef DeclareCastMethod protected: const Loop* loop_; }; +// clang-format on class DependenceLine : public Constraint { public: diff --git a/third_party/spirv-tools/source/opt/loop_descriptor.cpp b/third_party/spirv-tools/source/opt/loop_descriptor.cpp index efc56bdba6..11f7e9cfac 100644 --- a/third_party/spirv-tools/source/opt/loop_descriptor.cpp +++ b/third_party/spirv-tools/source/opt/loop_descriptor.cpp @@ -914,6 +914,7 @@ bool LoopDescriptor::CreatePreHeaderBlocksIfMissing() { for (auto& loop : *this) { if (!loop.GetPreHeaderBlock()) { modified = true; + // TODO(1841): Handle failure to create pre-header. loop.GetOrCreatePreHeaderBlock(); } } @@ -936,22 +937,23 @@ void LoopDescriptor::PostModificationCleanup() { for (Loop* loop : loops_to_remove_) { loops_.erase(std::find(loops_.begin(), loops_.end(), loop)); + delete loop; } for (auto& pair : loops_to_add_) { Loop* parent = pair.first; - Loop* loop = pair.second; + std::unique_ptr loop = std::move(pair.second); if (parent) { loop->SetParent(nullptr); - parent->AddNestedLoop(loop); + parent->AddNestedLoop(loop.get()); for (uint32_t block_id : loop->GetBlocks()) { parent->AddBasicBlock(block_id); } } - loops_.emplace_back(loop); + loops_.emplace_back(loop.release()); } loops_to_add_.clear(); diff --git a/third_party/spirv-tools/source/opt/loop_descriptor.h b/third_party/spirv-tools/source/opt/loop_descriptor.h index 45a175a0ca..6e2b82896e 100644 --- a/third_party/spirv-tools/source/opt/loop_descriptor.h +++ b/third_party/spirv-tools/source/opt/loop_descriptor.h @@ -132,7 +132,7 @@ class Loop { void SetPreHeaderBlock(BasicBlock* preheader); // Returns the loop pre-header, if there is no suitable preheader it will be - // created. + // created. Returns |nullptr| if it fails to create the preheader. BasicBlock* GetOrCreatePreHeaderBlock(); // Returns true if this loop contains any nested loops. @@ -499,8 +499,8 @@ class LoopDescriptor { // Mark the loop |loop_to_add| as needing to be added when the user calls // PostModificationCleanup. |parent| may be null. - inline void AddLoop(Loop* loop_to_add, Loop* parent) { - loops_to_add_.emplace_back(std::make_pair(parent, loop_to_add)); + inline void AddLoop(std::unique_ptr&& loop_to_add, Loop* parent) { + loops_to_add_.emplace_back(std::make_pair(parent, std::move(loop_to_add))); } // Checks all loops in |this| and will create pre-headers for all loops @@ -537,7 +537,9 @@ class LoopDescriptor { // TODO(dneto): This should be a vector of unique_ptr. But VisualStudio 2013 // is unable to compile it. using LoopContainerType = std::vector; - using LoopsToAddContainerType = std::vector>; + + using LoopsToAddContainerType = + std::vector>>; // Creates loop descriptors for the function |f|. void PopulateList(IRContext* context, const Function* f); diff --git a/third_party/spirv-tools/source/opt/loop_fission.cpp b/third_party/spirv-tools/source/opt/loop_fission.cpp index 0052406dd7..0678113c47 100644 --- a/third_party/spirv-tools/source/opt/loop_fission.cpp +++ b/third_party/spirv-tools/source/opt/loop_fission.cpp @@ -367,6 +367,7 @@ Loop* LoopFissionImpl::SplitLoop() { cloned_loop->UpdateLoopMergeInst(); // Add the loop_ to the module. + // TODO(1841): Handle failure to create pre-header. Function::iterator it = util.GetFunction()->FindBlock(loop_->GetOrCreatePreHeaderBlock()->id()); util.GetFunction()->AddBasicBlocks(clone_results.cloned_bb_.begin(), diff --git a/third_party/spirv-tools/source/opt/loop_peeling.cpp b/third_party/spirv-tools/source/opt/loop_peeling.cpp index 7d27480ae2..b640542d37 100644 --- a/third_party/spirv-tools/source/opt/loop_peeling.cpp +++ b/third_party/spirv-tools/source/opt/loop_peeling.cpp @@ -39,6 +39,7 @@ void LoopPeeling::DuplicateAndConnectLoop( assert(CanPeelLoop() && "Cannot peel loop!"); std::vector ordered_loop_blocks; + // TODO(1841): Handle failure to create pre-header. BasicBlock* pre_header = loop_->GetOrCreatePreHeaderBlock(); loop_->ComputeLoopStructuredOrder(&ordered_loop_blocks); @@ -131,6 +132,7 @@ void LoopPeeling::DuplicateAndConnectLoop( // Force the creation of a new preheader for the original loop and set it as // the merge block for the cloned loop. + // TODO(1841): Handle failure to create pre-header. cloned_loop_->SetMergeBlock(loop_->GetOrCreatePreHeaderBlock()); } @@ -151,7 +153,7 @@ void LoopPeeling::InsertCanonicalInductionVariable( context_, &*insert_point, IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping); Instruction* uint_1_cst = - builder.Add32BitConstantInteger(1, int_type_->IsSigned()); + builder.GetIntConstant(1, int_type_->IsSigned()); // Create the increment. // Note that we do "1 + 1" here, one of the operand should the phi // value but we don't have it yet. The operand will be set latter. @@ -162,8 +164,7 @@ void LoopPeeling::InsertCanonicalInductionVariable( canonical_induction_variable_ = builder.AddPhi( uint_1_cst->type_id(), - {builder.Add32BitConstantInteger(0, int_type_->IsSigned()) - ->result_id(), + {builder.GetIntConstant(0, int_type_->IsSigned())->result_id(), GetClonedLoop()->GetPreHeaderBlock()->id(), iv_inc->result_id(), GetClonedLoop()->GetLatchBlock()->id()}); // Connect everything. @@ -346,6 +347,7 @@ BasicBlock* LoopPeeling::CreateBlockBefore(BasicBlock* bb) { CFG& cfg = *context_->cfg(); assert(cfg.preds(bb->id()).size() == 1 && "More than one predecessor"); + // TODO(1841): Handle id overflow. std::unique_ptr new_bb = MakeUnique(std::unique_ptr(new Instruction( context_, SpvOpLabel, 0, context_->TakeNextId(), {}))); @@ -392,6 +394,7 @@ BasicBlock* LoopPeeling::CreateBlockBefore(BasicBlock* bb) { BasicBlock* LoopPeeling::ProtectLoop(Loop* loop, Instruction* condition, BasicBlock* if_merge) { + // TODO(1841): Handle failure to create pre-header. BasicBlock* if_block = loop->GetOrCreatePreHeaderBlock(); // Will no longer be a pre-header because of the if. loop->SetPreHeaderBlock(nullptr); @@ -422,7 +425,7 @@ void LoopPeeling::PeelBefore(uint32_t peel_factor) { context_, &*cloned_loop_->GetPreHeaderBlock()->tail(), IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping); Instruction* factor = - builder.Add32BitConstantInteger(peel_factor, int_type_->IsSigned()); + builder.GetIntConstant(peel_factor, int_type_->IsSigned()); Instruction* has_remaining_iteration = builder.AddLessThan( factor->result_id(), loop_iteration_count_->result_id()); @@ -484,7 +487,7 @@ void LoopPeeling::PeelAfter(uint32_t peel_factor) { context_, &*cloned_loop_->GetPreHeaderBlock()->tail(), IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping); Instruction* factor = - builder.Add32BitConstantInteger(peel_factor, int_type_->IsSigned()); + builder.GetIntConstant(peel_factor, int_type_->IsSigned()); Instruction* has_remaining_iteration = builder.AddLessThan( factor->result_id(), loop_iteration_count_->result_id()); @@ -677,8 +680,8 @@ std::pair LoopPeelingPass::ProcessLoop(Loop* loop, InstructionBuilder( context(), loop->GetHeaderBlock(), IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping) - .Add32BitConstantInteger(static_cast(iterations), - is_signed), + .GetIntConstant(static_cast(iterations), + is_signed), canonical_induction_variable); if (!peeler.CanPeelLoop()) { diff --git a/third_party/spirv-tools/source/opt/loop_unroller.cpp b/third_party/spirv-tools/source/opt/loop_unroller.cpp index 587615edf3..10fac0433f 100644 --- a/third_party/spirv-tools/source/opt/loop_unroller.cpp +++ b/third_party/spirv-tools/source/opt/loop_unroller.cpp @@ -244,6 +244,10 @@ class LoopUnrollerUtilsImpl { // ect). void AssignNewResultIds(BasicBlock* basic_block); + // Using the map built by AssignNewResultIds, replace the uses in |inst| + // by the id that the use maps to. + void RemapOperands(Instruction* inst); + // Using the map built by AssignNewResultIds, for each instruction in // |basic_block| use // that map to substitute the IDs used by instructions (in the operands) with @@ -373,6 +377,7 @@ void LoopUnrollerUtilsImpl::Init(Loop* loop) { // number of bodies. void LoopUnrollerUtilsImpl::PartiallyUnrollResidualFactor(Loop* loop, size_t factor) { + // TODO(1841): Handle id overflow. std::unique_ptr new_label{new Instruction( context_, SpvOp::SpvOpLabel, 0, context_->TakeNextId(), {})}; std::unique_ptr new_exit_bb{new BasicBlock(std::move(new_label))}; @@ -389,12 +394,12 @@ void LoopUnrollerUtilsImpl::PartiallyUnrollResidualFactor(Loop* loop, // This is a naked new due to the VS2013 requirement of not having unique // pointers in vectors, as it will be inserted into a vector with // loop_descriptor.AddLoop. - Loop* new_loop = new Loop(*loop); + std::unique_ptr new_loop = MakeUnique(*loop); // Clear the basic blocks of the new loop. new_loop->ClearBlocks(); - DuplicateLoop(loop, new_loop); + DuplicateLoop(loop, new_loop.get()); // Add the blocks to the function. AddBlocksToFunction(loop->GetMergeBlock()); @@ -409,10 +414,10 @@ void LoopUnrollerUtilsImpl::PartiallyUnrollResidualFactor(Loop* loop, loop_induction_variable_ = state_.new_phi; // Unroll the new loop by the factor with the usual -1 to account for the // existing block iteration. - Unroll(new_loop, factor); + Unroll(new_loop.get(), factor); - LinkLastPhisToStart(new_loop); - AddBlocksToLoop(new_loop); + LinkLastPhisToStart(new_loop.get()); + AddBlocksToLoop(new_loop.get()); // Add the new merge block to the back of the list of blocks to be added. It // needs to be the last block added to maintain dominator order in the binary. @@ -448,11 +453,9 @@ void LoopUnrollerUtilsImpl::PartiallyUnrollResidualFactor(Loop* loop, // If the remainder is negative then we add a signed constant, otherwise just // add an unsigned constant. if (remainder < 0) { - new_constant = - builder.Add32BitSignedIntegerConstant(static_cast(remainder)); + new_constant = builder.GetSintConstant(static_cast(remainder)); } else { - new_constant = builder.Add32BitUnsignedIntegerConstant( - static_cast(remainder)); + new_constant = builder.GetUintConstant(static_cast(remainder)); } uint32_t constant_id = new_constant->result_id(); @@ -504,7 +507,7 @@ void LoopUnrollerUtilsImpl::PartiallyUnrollResidualFactor(Loop* loop, LoopDescriptor& loop_descriptor = *context_->GetLoopDescriptor(&function_); - loop_descriptor.AddLoop(new_loop, loop->GetParent()); + loop_descriptor.AddLoop(std::move(new_loop), loop->GetParent()); RemoveDeadInstructions(); } @@ -547,7 +550,10 @@ void LoopUnrollerUtilsImpl::RemoveDeadInstructions() { void LoopUnrollerUtilsImpl::ReplaceInductionUseWithFinalValue(Loop* loop) { context_->InvalidateAnalysesExceptFor( - IRContext::Analysis::kAnalysisLoopAnalysis); + IRContext::Analysis::kAnalysisLoopAnalysis | + IRContext::Analysis::kAnalysisDefUse | + IRContext::Analysis::kAnalysisInstrToBlockMapping); + std::vector inductions; loop->GetInductionVariables(inductions); @@ -588,7 +594,8 @@ void LoopUnrollerUtilsImpl::FullyUnroll(Loop* loop) { RemoveDeadInstructions(); // Invalidate all analyses. context_->InvalidateAnalysesExceptFor( - IRContext::Analysis::kAnalysisLoopAnalysis); + IRContext::Analysis::kAnalysisLoopAnalysis | + IRContext::Analysis::kAnalysisDefUse); } // Copy a given basic block, give it a new result_id, and store the new block @@ -611,6 +618,7 @@ void LoopUnrollerUtilsImpl::CopyBasicBlock(Loop* loop, const BasicBlock* itr, if (!preserve_instructions) { Instruction* merge_inst = loop->GetHeaderBlock()->GetLoopMergeInst(); merge_inst->SetInOperand(1, {basic_block->id()}); + context_->UpdateDefUse(merge_inst); } state_.new_continue_block = basic_block; @@ -651,15 +659,17 @@ void LoopUnrollerUtilsImpl::CopyBody(Loop* loop, bool eliminate_conditions) { } // Set the previous latch block to point to the new header. - Instruction& latch_branch = *state_.previous_latch_block_->tail(); - latch_branch.SetInOperand(0, {state_.new_header_block->id()}); + Instruction* latch_branch = state_.previous_latch_block_->terminator(); + latch_branch->SetInOperand(0, {state_.new_header_block->id()}); + context_->UpdateDefUse(latch_branch); // As the algorithm copies the original loop blocks exactly, the tail of the // latch block on iterations after the first one will be a branch to the new // header and not the actual loop header. The last continue block in the loop // should always be a backedge to the global header. - Instruction& new_latch_branch = *state_.new_latch_block->tail(); - new_latch_branch.SetInOperand(0, {loop->GetHeaderBlock()->id()}); + Instruction* new_latch_branch = state_.new_latch_block->terminator(); + new_latch_branch->SetInOperand(0, {loop->GetHeaderBlock()->id()}); + context_->AnalyzeUses(new_latch_branch); std::vector inductions; loop->GetInductionVariables(inductions); @@ -721,7 +731,10 @@ void LoopUnrollerUtilsImpl::FoldConditionBlock(BasicBlock* condition_block, context_->KillInst(&old_branch); // Add the new unconditional branch to the merge block. - InstructionBuilder builder{context_, condition_block}; + InstructionBuilder builder( + context_, condition_block, + IRContext::Analysis::kAnalysisDefUse | + IRContext::Analysis::kAnalysisInstrToBlockMapping); builder.AddBranch(new_target); } @@ -732,8 +745,9 @@ void LoopUnrollerUtilsImpl::CloseUnrolledLoop(Loop* loop) { // Remove the final backedge to the header and make it point instead to the // merge block. - state_.previous_latch_block_->tail()->SetInOperand( - 0, {loop->GetMergeBlock()->id()}); + Instruction* latch_instruction = state_.previous_latch_block_->terminator(); + latch_instruction->SetInOperand(0, {loop->GetMergeBlock()->id()}); + context_->UpdateDefUse(latch_instruction); // Remove all induction variables as the phis will now be invalid. Replace all // uses with the constant initializer value (all uses of phis will be in @@ -757,6 +771,11 @@ void LoopUnrollerUtilsImpl::CloseUnrolledLoop(Loop* loop) { for (BasicBlock* block : loop_blocks_inorder_) { RemapOperands(block); } + + // Rewrite the last phis, since they may still reference the original phi. + for (Instruction* last_phi : state_.previous_phis_) { + RemapOperands(last_phi); + } } // Uses the first loop to create a copy of the loop with new IDs. @@ -812,13 +831,17 @@ void LoopUnrollerUtilsImpl::AddBlocksToFunction( // Assign all result_ids in |basic_block| instructions to new IDs and preserve // the mapping of new ids to old ones. void LoopUnrollerUtilsImpl::AssignNewResultIds(BasicBlock* basic_block) { + analysis::DefUseManager* def_use_mgr = context_->get_def_use_mgr(); + // Label instructions aren't covered by normal traversal of the // instructions. + // TODO(1841): Handle id overflow. uint32_t new_label_id = context_->TakeNextId(); // Assign a new id to the label. state_.new_inst[basic_block->GetLabelInst()->result_id()] = new_label_id; basic_block->GetLabelInst()->SetResultId(new_label_id); + def_use_mgr->AnalyzeInstDefUse(basic_block->GetLabelInst()); for (Instruction& inst : *basic_block) { uint32_t old_id = inst.result_id(); @@ -829,7 +852,9 @@ void LoopUnrollerUtilsImpl::AssignNewResultIds(BasicBlock* basic_block) { } // Give the instruction a new id. + // TODO(1841): Handle id overflow. inst.SetResultId(context_->TakeNextId()); + def_use_mgr->AnalyzeInstDef(&inst); // Save the mapping of old_id -> new_id. state_.new_inst[old_id] = inst.result_id(); @@ -842,19 +867,22 @@ void LoopUnrollerUtilsImpl::AssignNewResultIds(BasicBlock* basic_block) { } } -// For all instructions in |basic_block| check if the operands used are from a -// copied instruction and if so swap out the operand for the copy of it. +void LoopUnrollerUtilsImpl::RemapOperands(Instruction* inst) { + auto remap_operands_to_new_ids = [this](uint32_t* id) { + auto itr = state_.new_inst.find(*id); + + if (itr != state_.new_inst.end()) { + *id = itr->second; + } + }; + + inst->ForEachInId(remap_operands_to_new_ids); + context_->AnalyzeUses(inst); +} + void LoopUnrollerUtilsImpl::RemapOperands(BasicBlock* basic_block) { for (Instruction& inst : *basic_block) { - auto remap_operands_to_new_ids = [this](uint32_t* id) { - auto itr = state_.new_inst.find(*id); - - if (itr != state_.new_inst.end()) { - *id = itr->second; - } - }; - - inst.ForEachInId(remap_operands_to_new_ids); + RemapOperands(&inst); } } diff --git a/third_party/spirv-tools/source/opt/loop_unroller.h b/third_party/spirv-tools/source/opt/loop_unroller.h index eb358ae242..71e7cca316 100644 --- a/third_party/spirv-tools/source/opt/loop_unroller.h +++ b/third_party/spirv-tools/source/opt/loop_unroller.h @@ -30,6 +30,14 @@ class LoopUnroller : public Pass { Status Process() override; + IRContext::Analysis GetPreservedAnalyses() override { + return IRContext::kAnalysisDefUse | + IRContext::kAnalysisInstrToBlockMapping | + IRContext::kAnalysisDecorations | IRContext::kAnalysisCombinators | + IRContext::kAnalysisNameMap | IRContext::kAnalysisConstants | + IRContext::kAnalysisTypes; + } + private: bool fully_unroll_; int unroll_factor_; diff --git a/third_party/spirv-tools/source/opt/loop_unswitch_pass.cpp b/third_party/spirv-tools/source/opt/loop_unswitch_pass.cpp index 59a0cbcd37..502fc6b680 100644 --- a/third_party/spirv-tools/source/opt/loop_unswitch_pass.cpp +++ b/third_party/spirv-tools/source/opt/loop_unswitch_pass.cpp @@ -39,8 +39,6 @@ namespace opt { namespace { static const uint32_t kTypePointerStorageClassInIdx = 0; -static const uint32_t kBranchCondTrueLabIdInIdx = 1; -static const uint32_t kBranchCondFalseLabIdInIdx = 2; } // anonymous namespace @@ -74,9 +72,13 @@ class LoopUnswitch { for (uint32_t bb_id : loop_->GetBlocks()) { BasicBlock* bb = cfg.block(bb_id); + if (loop_->GetLatchBlock() == bb) { + continue; + } + if (bb->terminator()->IsBranch() && bb->terminator()->opcode() != SpvOpBranch) { - if (IsConditionLoopInvariant(bb->terminator())) { + if (IsConditionNonConstantLoopInvariant(bb->terminator())) { switch_block_ = bb; break; } @@ -99,6 +101,7 @@ class LoopUnswitch { BasicBlock* CreateBasicBlock(Function::iterator ip) { analysis::DefUseManager* def_use_mgr = context_->get_def_use_mgr(); + // TODO(1841): Handle id overflow. BasicBlock* bb = &*ip.InsertBefore(std::unique_ptr( new BasicBlock(std::unique_ptr(new Instruction( context_, SpvOpLabel, 0, context_->TakeNextId(), {}))))); @@ -109,6 +112,35 @@ class LoopUnswitch { return bb; } + Instruction* GetValueForDefaultPathForSwitch(Instruction* switch_inst) { + assert(switch_inst->opcode() == SpvOpSwitch && + "The given instructoin must be an OpSwitch."); + + // Find a value that can be used to select the default path. + // If none are possible, then it will just use 0. The value does not matter + // because this path will never be taken becaues the new switch outside of + // the loop cannot select this path either. + std::vector existing_values; + for (uint32_t i = 2; i < switch_inst->NumInOperands(); i += 2) { + existing_values.push_back(switch_inst->GetSingleWordInOperand(i)); + } + std::sort(existing_values.begin(), existing_values.end()); + uint32_t value_for_default_path = 0; + if (existing_values.size() < std::numeric_limits::max()) { + for (value_for_default_path = 0; + value_for_default_path < existing_values.size(); + value_for_default_path++) { + if (existing_values[value_for_default_path] != value_for_default_path) { + break; + } + } + } + InstructionBuilder builder( + context_, static_cast(nullptr), + IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping); + return builder.GetUintConstant(value_for_default_path); + } + // Unswitches |loop_|. void PerformUnswitch() { assert(CanUnswitchLoop() && @@ -153,6 +185,7 @@ class LoopUnswitch { if_merge_block->ForEachPhiInst( [loop_merge_block, &builder, this](Instruction* phi) { Instruction* cloned = phi->Clone(context_); + cloned->SetResultId(TakeNextId()); builder.AddInstruction(std::unique_ptr(cloned)); phi->SetInOperand(0, {cloned->result_id()}); phi->SetInOperand(1, {loop_merge_block->id()}); @@ -176,7 +209,6 @@ class LoopUnswitch { ploop->AddBasicBlock(loop_merge_block); loop_desc_.SetBasicBlockToLoop(loop_merge_block->id(), ploop); } - // Update the dominator tree. DominatorTreeNode* loop_merge_dtn = dom_tree->GetOrInsertNode(loop_merge_block); @@ -194,7 +226,7 @@ class LoopUnswitch { //////////////////////////////////////////////////////////////////////////// // Step 2: Build a new preheader for |loop_|, use the old one - // for the constant branch. + // for the invariant branch. //////////////////////////////////////////////////////////////////////////// BasicBlock* if_block = loop_->GetPreHeaderBlock(); @@ -272,7 +304,6 @@ class LoopUnswitch { std::vector> constant_branch; // Special case for the original loop Instruction* original_loop_constant_value; - BasicBlock* original_loop_target; if (iv_opcode == SpvOpBranchConditional) { constant_branch.emplace_back( cst_mgr->GetDefiningInstruction(cst_mgr->GetConstant(cond_type, {0})), @@ -282,7 +313,9 @@ class LoopUnswitch { } else { // We are looking to take the default branch, so we can't provide a // specific value. - original_loop_constant_value = nullptr; + original_loop_constant_value = + GetValueForDefaultPathForSwitch(iv_condition); + for (uint32_t i = 2; i < iv_condition->NumInOperands(); i += 2) { constant_branch.emplace_back( cst_mgr->GetDefiningInstruction(cst_mgr->GetConstant( @@ -322,24 +355,7 @@ class LoopUnswitch { //////////////////////////////////// { - std::unordered_set dead_blocks; - std::unordered_set unreachable_merges; - SimplifyLoop( - make_range( - UptrVectorIterator(&clone_result.cloned_bb_, - clone_result.cloned_bb_.begin()), - UptrVectorIterator(&clone_result.cloned_bb_, - clone_result.cloned_bb_.end())), - cloned_loop, condition, specialisation_value, &dead_blocks); - - // We tagged dead blocks, create the loop before we invalidate any basic - // block. - cloned_loop = - CleanLoopNest(cloned_loop, dead_blocks, &unreachable_merges); - CleanUpCFG( - UptrVectorIterator(&clone_result.cloned_bb_, - clone_result.cloned_bb_.begin()), - dead_blocks, unreachable_merges); + SpecializeLoop(cloned_loop, condition, specialisation_value); /////////////////////////////////////////////////////////// // Step 5: Connect convergent edges to the landing pads. // @@ -348,27 +364,25 @@ class LoopUnswitch { for (uint32_t merge_bb_id : if_merging_blocks) { BasicBlock* merge = context_->cfg()->block(merge_bb_id); // We are in LCSSA so we only care about phi instructions. - merge->ForEachPhiInst([is_from_original_loop, &dead_blocks, - &clone_result](Instruction* phi) { - uint32_t num_in_operands = phi->NumInOperands(); - for (uint32_t i = 0; i < num_in_operands; i += 2) { - uint32_t pred = phi->GetSingleWordInOperand(i + 1); - if (is_from_original_loop(pred)) { - pred = clone_result.value_map_.at(pred); - if (!dead_blocks.count(pred)) { - uint32_t incoming_value_id = phi->GetSingleWordInOperand(i); - // Not all the incoming value are coming from the loop. - ValueMapTy::iterator new_value = - clone_result.value_map_.find(incoming_value_id); - if (new_value != clone_result.value_map_.end()) { - incoming_value_id = new_value->second; + merge->ForEachPhiInst( + [is_from_original_loop, &clone_result](Instruction* phi) { + uint32_t num_in_operands = phi->NumInOperands(); + for (uint32_t i = 0; i < num_in_operands; i += 2) { + uint32_t pred = phi->GetSingleWordInOperand(i + 1); + if (is_from_original_loop(pred)) { + pred = clone_result.value_map_.at(pred); + uint32_t incoming_value_id = phi->GetSingleWordInOperand(i); + // Not all the incoming values are coming from the loop. + ValueMapTy::iterator new_value = + clone_result.value_map_.find(incoming_value_id); + if (new_value != clone_result.value_map_.end()) { + incoming_value_id = new_value->second; + } + phi->AddOperand({SPV_OPERAND_TYPE_ID, {incoming_value_id}}); + phi->AddOperand({SPV_OPERAND_TYPE_ID, {pred}}); } - phi->AddOperand({SPV_OPERAND_TYPE_ID, {incoming_value_id}}); - phi->AddOperand({SPV_OPERAND_TYPE_ID, {pred}}); } - } - } - }); + }); } } function_->AddBasicBlocks(clone_result.cloned_bb_.begin(), @@ -376,38 +390,9 @@ class LoopUnswitch { ++FindBasicBlockPosition(if_block)); } - // Same as above but specialize the existing loop - { - std::unordered_set dead_blocks; - std::unordered_set unreachable_merges; - SimplifyLoop(make_range(function_->begin(), function_->end()), loop_, - condition, original_loop_constant_value, &dead_blocks); - - for (uint32_t merge_bb_id : if_merging_blocks) { - BasicBlock* merge = context_->cfg()->block(merge_bb_id); - // LCSSA, so we only care about phi instructions. - // If we the phi is reduced to a single incoming branch, do not - // propagate it to preserve LCSSA. - PatchPhis(merge, dead_blocks, true); - } - if (if_merge_block) { - bool has_live_pred = false; - for (uint32_t pid : cfg.preds(if_merge_block->id())) { - if (!dead_blocks.count(pid)) { - has_live_pred = true; - break; - } - } - if (!has_live_pred) unreachable_merges.insert(if_merge_block->id()); - } - original_loop_target = loop_->GetPreHeaderBlock(); - // We tagged dead blocks, prune the loop descriptor from any dead loops. - // After this call, |loop_| can be nullptr (i.e. the unswitch killed this - // loop). - loop_ = CleanLoopNest(loop_, dead_blocks, &unreachable_merges); - - CleanUpCFG(function_->begin(), dead_blocks, unreachable_merges); - } + // Specialize the existing loop. + SpecializeLoop(loop_, condition, original_loop_constant_value); + BasicBlock* original_loop_target = loop_->GetPreHeaderBlock(); ///////////////////////////////////// // Finally: connect the new loops. // @@ -440,9 +425,6 @@ class LoopUnswitch { IRContext::Analysis::kAnalysisLoopAnalysis); } - // Returns true if the unswitch killed the original |loop_|. - bool WasLoopKilled() const { return loop_ == nullptr; } - private: using ValueMapTy = std::unordered_map; using BlockMapTy = std::unordered_map; @@ -459,96 +441,9 @@ class LoopUnswitch { std::vector ordered_loop_blocks_; // Returns the next usable id for the context. - uint32_t TakeNextId() { return context_->TakeNextId(); } - - // Patches |bb|'s phi instruction by removing incoming value from unexisting - // or tagged as dead branches. - void PatchPhis(BasicBlock* bb, - const std::unordered_set& dead_blocks, - bool preserve_phi) { - CFG& cfg = *context_->cfg(); - - std::vector phi_to_kill; - const std::vector& bb_preds = cfg.preds(bb->id()); - auto is_branch_dead = [&bb_preds, &dead_blocks](uint32_t id) { - return dead_blocks.count(id) || - std::find(bb_preds.begin(), bb_preds.end(), id) == bb_preds.end(); - }; - bb->ForEachPhiInst([&phi_to_kill, &is_branch_dead, preserve_phi, - this](Instruction* insn) { - uint32_t i = 0; - while (i < insn->NumInOperands()) { - uint32_t incoming_id = insn->GetSingleWordInOperand(i + 1); - if (is_branch_dead(incoming_id)) { - // Remove the incoming block id operand. - insn->RemoveInOperand(i + 1); - // Remove the definition id operand. - insn->RemoveInOperand(i); - continue; - } - i += 2; - } - // If there is only 1 remaining edge, propagate the value and - // kill the instruction. - if (insn->NumInOperands() == 2 && !preserve_phi) { - phi_to_kill.push_back(insn); - context_->ReplaceAllUsesWith(insn->result_id(), - insn->GetSingleWordInOperand(0)); - } - }); - for (Instruction* insn : phi_to_kill) { - context_->KillInst(insn); - } - } - - // Removes any block that is tagged as dead, if the block is in - // |unreachable_merges| then all block's instructions are replaced by a - // OpUnreachable. - void CleanUpCFG(UptrVectorIterator bb_it, - const std::unordered_set& dead_blocks, - const std::unordered_set& unreachable_merges) { - CFG& cfg = *context_->cfg(); - - while (bb_it != bb_it.End()) { - BasicBlock& bb = *bb_it; - - if (unreachable_merges.count(bb.id())) { - if (bb.begin() != bb.tail() || - bb.terminator()->opcode() != SpvOpUnreachable) { - // Make unreachable, but leave the label. - bb.KillAllInsts(false); - InstructionBuilder(context_, &bb).AddUnreachable(); - cfg.RemoveNonExistingEdges(bb.id()); - } - ++bb_it; - } else if (dead_blocks.count(bb.id())) { - cfg.ForgetBlock(&bb); - // Kill this block. - bb.KillAllInsts(true); - bb_it = bb_it.Erase(); - } else { - cfg.RemoveNonExistingEdges(bb.id()); - ++bb_it; - } - } - } - - // Return true if |c_inst| is a Boolean constant and set |cond_val| with the - // value that |c_inst| - bool GetConstCondition(const Instruction* c_inst, bool* cond_val) { - bool cond_is_const; - switch (c_inst->opcode()) { - case SpvOpConstantFalse: { - *cond_val = false; - cond_is_const = true; - } break; - case SpvOpConstantTrue: { - *cond_val = true; - cond_is_const = true; - } break; - default: { cond_is_const = false; } break; - } - return cond_is_const; + uint32_t TakeNextId() { + // TODO(1841): Handle id overflow. + return context_->TakeNextId(); } // Simplifies |loop| assuming the instruction |to_version_insn| takes the @@ -560,13 +455,9 @@ class LoopUnswitch { // // Requirements: // - |loop| must be in the LCSSA form; - // - |cst_value| must be constant or null (to represent the default target - // of an OpSwitch). - void SimplifyLoop(IteratorRange> block_range, - Loop* loop, Instruction* to_version_insn, - Instruction* cst_value, - std::unordered_set* dead_blocks) { - CFG& cfg = *context_->cfg(); + // - |cst_value| must be constant. + void SpecializeLoop(Loop* loop, Instruction* to_version_insn, + Instruction* cst_value) { analysis::DefUseManager* def_use_mgr = context_->get_def_use_mgr(); std::function ignore_node; @@ -591,192 +482,15 @@ class LoopUnswitch { for (auto use : use_list) { Instruction* inst = use.first; uint32_t operand_index = use.second; - BasicBlock* bb = context_->get_instr_block(inst); - // If it is not a branch, simply inject the value. - if (!inst->IsBranch()) { - // To also handle switch, cst_value can be nullptr: this case - // means that we are looking to branch to the default target of - // the switch. We don't actually know its value so we don't touch - // it if it not a switch. - if (cst_value) { - inst->SetOperand(operand_index, {cst_value->result_id()}); - def_use_mgr->AnalyzeInstUse(inst); - } - } - - // The user is a branch, kill dead branches. - uint32_t live_target = 0; - std::unordered_set dead_branches; - switch (inst->opcode()) { - case SpvOpBranchConditional: { - assert(cst_value && "No constant value to specialize !"); - bool branch_cond = false; - if (GetConstCondition(cst_value, &branch_cond)) { - uint32_t true_label = - inst->GetSingleWordInOperand(kBranchCondTrueLabIdInIdx); - uint32_t false_label = - inst->GetSingleWordInOperand(kBranchCondFalseLabIdInIdx); - live_target = branch_cond ? true_label : false_label; - uint32_t dead_target = !branch_cond ? true_label : false_label; - cfg.RemoveEdge(bb->id(), dead_target); - } - break; - } - case SpvOpSwitch: { - live_target = inst->GetSingleWordInOperand(1); - if (cst_value) { - if (!cst_value->IsConstant()) break; - const Operand& cst = cst_value->GetInOperand(0); - for (uint32_t i = 2; i < inst->NumInOperands(); i += 2) { - const Operand& literal = inst->GetInOperand(i); - if (literal == cst) { - live_target = inst->GetSingleWordInOperand(i + 1); - break; - } - } - } - for (uint32_t i = 1; i < inst->NumInOperands(); i += 2) { - uint32_t id = inst->GetSingleWordInOperand(i); - if (id != live_target) { - cfg.RemoveEdge(bb->id(), id); - } - } - } - default: - break; - } - if (live_target != 0) { - // Check for the presence of the merge block. - if (Instruction* merge = bb->GetMergeInst()) context_->KillInst(merge); - context_->KillInst(&*bb->tail()); - InstructionBuilder builder(context_, bb, - IRContext::kAnalysisDefUse | - IRContext::kAnalysisInstrToBlockMapping); - builder.AddBranch(live_target); - } + // To also handle switch, cst_value can be nullptr: this case + // means that we are looking to branch to the default target of + // the switch. We don't actually know its value so we don't touch + // it if it not a switch. + assert(cst_value && "We do not have a value to use."); + inst->SetOperand(operand_index, {cst_value->result_id()}); + def_use_mgr->AnalyzeInstUse(inst); } - - // Go through the loop basic block and tag all blocks that are obviously - // dead. - std::unordered_set visited; - for (BasicBlock& bb : block_range) { - if (ignore_node(bb.id())) continue; - visited.insert(bb.id()); - - // Check if this block is dead, if so tag it as dead otherwise patch phi - // instructions. - bool has_live_pred = false; - for (uint32_t pid : cfg.preds(bb.id())) { - if (!dead_blocks->count(pid)) { - has_live_pred = true; - break; - } - } - if (!has_live_pred) { - dead_blocks->insert(bb.id()); - const BasicBlock& cbb = bb; - // Patch the phis for any back-edge. - cbb.ForEachSuccessorLabel( - [dead_blocks, &visited, &cfg, this](uint32_t id) { - if (!visited.count(id) || dead_blocks->count(id)) return; - BasicBlock* succ = cfg.block(id); - PatchPhis(succ, *dead_blocks, false); - }); - continue; - } - // Update the phi instructions, some incoming branch have/will disappear. - PatchPhis(&bb, *dead_blocks, /* preserve_phi = */ false); - } - } - - // Returns true if the header is not reachable or tagged as dead or if we - // never loop back. - bool IsLoopDead(BasicBlock* header, BasicBlock* latch, - const std::unordered_set& dead_blocks) { - if (!header || dead_blocks.count(header->id())) return true; - if (!latch || dead_blocks.count(latch->id())) return true; - for (uint32_t pid : context_->cfg()->preds(header->id())) { - if (!dead_blocks.count(pid)) { - // Seems reachable. - return false; - } - } - return true; - } - - // Cleans the loop nest under |loop| and reflect changes to the loop - // descriptor. This will kill all descriptors that represent dead loops. - // If |loop_| is killed, it will be set to nullptr. - // Any merge blocks that become unreachable will be added to - // |unreachable_merges|. - // The function returns the pointer to |loop| or nullptr if the loop was - // killed. - Loop* CleanLoopNest(Loop* loop, - const std::unordered_set& dead_blocks, - std::unordered_set* unreachable_merges) { - // This represent the pair of dead loop and nearest alive parent (nullptr if - // no parent). - std::unordered_map dead_loops; - auto get_parent = [&dead_loops](Loop* l) -> Loop* { - std::unordered_map::iterator it = dead_loops.find(l); - if (it != dead_loops.end()) return it->second; - return nullptr; - }; - - bool is_main_loop_dead = - IsLoopDead(loop->GetHeaderBlock(), loop->GetLatchBlock(), dead_blocks); - if (is_main_loop_dead) { - if (Instruction* merge = loop->GetHeaderBlock()->GetLoopMergeInst()) { - context_->KillInst(merge); - } - dead_loops[loop] = loop->GetParent(); - } else { - dead_loops[loop] = loop; - } - - // For each loop, check if we killed it. If we did, find a suitable parent - // for its children. - for (Loop& sub_loop : - make_range(++TreeDFIterator(loop), TreeDFIterator())) { - if (IsLoopDead(sub_loop.GetHeaderBlock(), sub_loop.GetLatchBlock(), - dead_blocks)) { - if (Instruction* merge = - sub_loop.GetHeaderBlock()->GetLoopMergeInst()) { - context_->KillInst(merge); - } - dead_loops[&sub_loop] = get_parent(&sub_loop); - } else { - // The loop is alive, check if its merge block is dead, if it is, tag it - // as required. - if (sub_loop.GetMergeBlock()) { - uint32_t merge_id = sub_loop.GetMergeBlock()->id(); - if (dead_blocks.count(merge_id)) { - unreachable_merges->insert(sub_loop.GetMergeBlock()->id()); - } - } - } - } - if (!is_main_loop_dead) dead_loops.erase(loop); - - // Remove dead blocks from live loops. - for (uint32_t bb_id : dead_blocks) { - Loop* l = loop_desc_[bb_id]; - if (l) { - l->RemoveBasicBlock(bb_id); - loop_desc_.ForgetBasicBlock(bb_id); - } - } - - std::for_each( - dead_loops.begin(), dead_loops.end(), - [&loop, - this](std::unordered_map::iterator::reference it) { - if (it.first == loop) loop = nullptr; - loop_desc_.RemoveLoop(it.first); - }); - - return loop; } // Returns true if |var| is dynamically uniform. @@ -835,17 +549,25 @@ class LoopUnswitch { }); } - // Returns true if |insn| is constant and dynamically uniform within the loop. - bool IsConditionLoopInvariant(Instruction* insn) { + // Returns true if |insn| is not a constant, but is loop invariant and + // dynamically uniform. + bool IsConditionNonConstantLoopInvariant(Instruction* insn) { assert(insn->IsBranch()); assert(insn->opcode() != SpvOpBranch); analysis::DefUseManager* def_use_mgr = context_->get_def_use_mgr(); Instruction* condition = def_use_mgr->GetDef(insn->GetOperand(0).words[0]); - return !loop_->IsInsideLoop(condition) && - IsDynamicallyUniform( - condition, function_->entry().get(), - context_->GetPostDominatorAnalysis(function_)->GetDomTree()); + if (condition->IsConstant()) { + return false; + } + + if (loop_->IsInsideLoop(condition)) { + return false; + } + + return IsDynamicallyUniform( + condition, function_->entry().get(), + context_->GetPostDominatorAnalysis(function_)->GetDomTree()); } }; @@ -879,7 +601,7 @@ bool LoopUnswitchPass::ProcessFunction(Function* f) { processed_loop.insert(&loop); LoopUnswitch unswitcher(context(), f, &loop, &loop_descriptor); - while (!unswitcher.WasLoopKilled() && unswitcher.CanUnswitchLoop()) { + while (unswitcher.CanUnswitchLoop()) { if (!loop.IsLCSSA()) { LoopUtils(context(), &loop).MakeLoopClosedSSA(); } diff --git a/third_party/spirv-tools/source/opt/loop_utils.cpp b/third_party/spirv-tools/source/opt/loop_utils.cpp index 482335f3bf..8c6d355d66 100644 --- a/third_party/spirv-tools/source/opt/loop_utils.cpp +++ b/third_party/spirv-tools/source/opt/loop_utils.cpp @@ -352,6 +352,7 @@ void LoopUtils::CreateLoopDedicatedExits() { assert(insert_pt != function->end() && "Basic Block not found"); // Create the dedicate exit basic block. + // TODO(1841): Handle id overflow. BasicBlock& exit = *insert_pt.InsertBefore(std::unique_ptr( new BasicBlock(std::unique_ptr(new Instruction( context_, SpvOpLabel, 0, context_->TakeNextId(), {}))))); @@ -491,6 +492,7 @@ Loop* LoopUtils::CloneAndAttachLoopToHeader(LoopCloningResult* cloning_result) { Loop* new_loop = CloneLoop(cloning_result); // Create a new exit block/label for the new loop. + // TODO(1841): Handle id overflow. std::unique_ptr new_label{new Instruction( context_, SpvOp::SpvOpLabel, 0, context_->TakeNextId(), {})}; std::unique_ptr new_exit_bb{new BasicBlock(std::move(new_label))}; @@ -528,6 +530,7 @@ Loop* LoopUtils::CloneAndAttachLoopToHeader(LoopCloningResult* cloning_result) { inst->SetOperand(operand, {new_header}); }); + // TODO(1841): Handle failure to create pre-header. def_use->ForEachUse( loop_->GetOrCreatePreHeaderBlock()->id(), [new_merge_block, this](Instruction* inst, uint32_t operand) { @@ -560,6 +563,7 @@ Loop* LoopUtils::CloneLoop( // between old and new ids. BasicBlock* new_bb = old_bb->Clone(context_); new_bb->SetParent(&function_); + // TODO(1841): Handle id overflow. new_bb->GetLabelInst()->SetResultId(context_->TakeNextId()); def_use_mgr->AnalyzeInstDef(new_bb->GetLabelInst()); context_->set_instr_block(new_bb->GetLabelInst(), new_bb); @@ -575,6 +579,7 @@ Loop* LoopUtils::CloneLoop( new_inst != new_bb->end(); ++new_inst, ++old_inst) { cloning_result->ptr_map_[&*new_inst] = &*old_inst; if (new_inst->HasResultId()) { + // TODO(1841): Handle id overflow. new_inst->SetResultId(context_->TakeNextId()); cloning_result->value_map_[old_inst->result_id()] = new_inst->result_id(); diff --git a/third_party/spirv-tools/source/opt/mem_pass.cpp b/third_party/spirv-tools/source/opt/mem_pass.cpp index c65e04938a..04e2e8aea9 100644 --- a/third_party/spirv-tools/source/opt/mem_pass.cpp +++ b/third_party/spirv-tools/source/opt/mem_pass.cpp @@ -119,7 +119,7 @@ Instruction* MemPass::GetPtr(uint32_t ptrId, uint32_t* varId) { Instruction* MemPass::GetPtr(Instruction* ip, uint32_t* varId) { assert(ip->opcode() == SpvOpStore || ip->opcode() == SpvOpLoad || - ip->opcode() == SpvOpImageTexelPointer); + ip->opcode() == SpvOpImageTexelPointer || ip->IsAtomicWithLoad()); // All of these opcode place the pointer in position 0. const uint32_t ptrId = ip->GetSingleWordInOperand(0); @@ -233,6 +233,10 @@ uint32_t MemPass::Type2Undef(uint32_t type_id) { const auto uitr = type2undefs_.find(type_id); if (uitr != type2undefs_.end()) return uitr->second; const uint32_t undefId = TakeNextId(); + if (undefId == 0) { + return 0; + } + std::unique_ptr undef_inst( new Instruction(context(), SpvOpUndef, type_id, undefId, {})); get_def_use_mgr()->AnalyzeInstDefUse(&*undef_inst); diff --git a/third_party/spirv-tools/source/opt/mem_pass.h b/third_party/spirv-tools/source/opt/mem_pass.h index 67ce26b139..dcc16b6574 100644 --- a/third_party/spirv-tools/source/opt/mem_pass.h +++ b/third_party/spirv-tools/source/opt/mem_pass.h @@ -121,9 +121,10 @@ class MemPass : public Pass { return (op == SpvOpDecorate || op == SpvOpDecorateId); } - // Return undef in function for type. Create and insert an undef after the - // first non-variable in the function if it doesn't already exist. Add - // undef to function undef map. + // Return the id of an undef value with type |type_id|. Create and insert an + // undef after the first non-variable in the function if it doesn't already + // exist. Add undef to function undef map. Returns 0 of the value does not + // exist, and cannot be created. uint32_t Type2Undef(uint32_t type_id); // Cache of verified target vars diff --git a/third_party/spirv-tools/source/opt/merge_return_pass.cpp b/third_party/spirv-tools/source/opt/merge_return_pass.cpp index 4068d4a18f..bbac4bb6c8 100644 --- a/third_party/spirv-tools/source/opt/merge_return_pass.cpp +++ b/third_party/spirv-tools/source/opt/merge_return_pass.cpp @@ -22,52 +22,102 @@ #include "source/opt/ir_builder.h" #include "source/opt/ir_context.h" #include "source/opt/reflect.h" +#include "source/util/bit_vector.h" #include "source/util/make_unique.h" namespace spvtools { namespace opt { Pass::Status MergeReturnPass::Process() { - bool modified = false; bool is_shader = context()->get_feature_mgr()->HasCapability(SpvCapabilityShader); - for (auto& function : *get_module()) { - std::vector return_blocks = CollectReturnBlocks(&function); - if (return_blocks.size() <= 1) continue; - function_ = &function; + bool failed = false; + ProcessFunction pfn = [&failed, is_shader, this](Function* function) { + std::vector return_blocks = CollectReturnBlocks(function); + if (return_blocks.size() <= 1) { + if (!is_shader || return_blocks.size() == 0) { + return false; + } + if (context()->GetStructuredCFGAnalysis()->ContainingConstruct( + return_blocks[0]->id()) == 0) { + return false; + } + } + + function_ = function; return_flag_ = nullptr; return_value_ = nullptr; final_return_block_ = nullptr; - modified = true; if (is_shader) { - ProcessStructured(&function, return_blocks); + if (!ProcessStructured(function, return_blocks)) { + failed = true; + } } else { - MergeReturnBlocks(&function, return_blocks); + MergeReturnBlocks(function, return_blocks); } + return true; + }; + + bool modified = context()->ProcessReachableCallTree(pfn); + + if (failed) { + return Status::Failure; } return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange; } -void MergeReturnPass::ProcessStructured( +void MergeReturnPass::GenerateState(BasicBlock* block) { + if (Instruction* mergeInst = block->GetMergeInst()) { + if (mergeInst->opcode() == SpvOpLoopMerge) { + // If new loop, break to this loop merge block + state_.emplace_back(mergeInst, mergeInst); + } else { + auto branchInst = mergeInst->NextNode(); + if (branchInst->opcode() == SpvOpSwitch) { + // If switch inside of loop, break to innermost loop merge block. + // Otherwise need to break to this switch merge block. + auto lastMergeInst = state_.back().BreakMergeInst(); + if (lastMergeInst && lastMergeInst->opcode() == SpvOpLoopMerge) + state_.emplace_back(lastMergeInst, mergeInst); + else + state_.emplace_back(mergeInst, mergeInst); + } else { + // If branch conditional inside loop, always break to innermost + // loop merge block. If branch conditional inside switch, break to + // innermost switch merge block. + auto lastMergeInst = state_.back().BreakMergeInst(); + state_.emplace_back(lastMergeInst, mergeInst); + } + } + } +} + +bool MergeReturnPass::ProcessStructured( Function* function, const std::vector& return_blocks) { + if (HasNontrivialUnreachableBlocks(function)) { + if (consumer()) { + std::string message = + "Module contains unreachable blocks during merge return. Run dead " + "branch elimination before merge return."; + consumer()(SPV_MSG_ERROR, 0, {0, 0, 0}, message.c_str()); + } + return false; + } + + RecordImmediateDominators(function); + AddDummySwitchAroundFunction(); + std::list order; cfg()->ComputeStructuredOrder(function, &*function->begin(), &order); - // Create the new return block - CreateReturnBlock(); - - // Create the return - CreateReturn(final_return_block_); - - cfg()->RegisterBlock(final_return_block_); - state_.clear(); state_.emplace_back(nullptr, nullptr); for (auto block : order) { - if (cfg()->IsPseudoEntryBlock(block) || cfg()->IsPseudoExitBlock(block)) { + if (cfg()->IsPseudoEntryBlock(block) || cfg()->IsPseudoExitBlock(block) || + block == final_return_block_) { continue; } @@ -79,12 +129,8 @@ void MergeReturnPass::ProcessStructured( ProcessStructuredBlock(block); - // Generate state for next block - if (Instruction* mergeInst = block->GetMergeInst()) { - Instruction* loopMergeInst = block->GetLoopMergeInst(); - if (!loopMergeInst) loopMergeInst = state_.back().LoopMergeInst(); - state_.emplace_back(loopMergeInst, mergeInst); - } + // Generate state for next block if warranted + GenerateState(block); } state_.clear(); @@ -104,21 +150,20 @@ void MergeReturnPass::ProcessStructured( // Predicate successors of the original return blocks as necessary. if (std::find(return_blocks.begin(), return_blocks.end(), block) != return_blocks.end()) { - PredicateBlocks(block, &predicated, &order); + if (!PredicateBlocks(block, &predicated, &order)) { + return false; + } } - // Generate state for next block - if (Instruction* mergeInst = block->GetMergeInst()) { - Instruction* loopMergeInst = block->GetLoopMergeInst(); - if (!loopMergeInst) loopMergeInst = state_.back().LoopMergeInst(); - state_.emplace_back(loopMergeInst, mergeInst); - } + // Generate state for next block if warranted + GenerateState(block); } // We have not kept the dominator tree up-to-date. // Invalidate it at this point to make sure it will be rebuilt. context()->RemoveDominatorAnalysis(function); AddNewPhiNodes(); + return true; } void MergeReturnPass::CreateReturnBlock() { @@ -175,14 +220,9 @@ void MergeReturnPass::ProcessStructuredBlock(BasicBlock* block) { if (tail_opcode == SpvOpReturn || tail_opcode == SpvOpReturnValue || tail_opcode == SpvOpUnreachable) { - if (CurrentState().InLoop()) { - // Can always break out of innermost loop - BranchToBlock(block, CurrentState().LoopMergeId()); - } else if (CurrentState().InStructuredFlow()) { - BranchToBlock(block, CurrentState().CurrentMergeId()); - } else { - BranchToBlock(block, final_return_block_->id()); - } + assert(CurrentState().InBreakable() && "Should be in the dummy construct."); + BranchToBlock(block, CurrentState().BreakMergeId()); + return_blocks_.insert(block->id()); } } @@ -192,13 +232,18 @@ void MergeReturnPass::BranchToBlock(BasicBlock* block, uint32_t target) { RecordReturned(block); RecordReturnValue(block); } + BasicBlock* target_block = context()->get_instr_block(target); + if (target_block->GetLoopMergeInst()) { + cfg()->SplitLoopHeader(target_block); + } UpdatePhiNodes(block, target_block); Instruction* return_inst = block->terminator(); return_inst->SetOpcode(SpvOpBranch); return_inst->ReplaceOperands({{SPV_OPERAND_TYPE_ID, {target}}}); context()->get_def_use_mgr()->AnalyzeInstDefUse(return_inst); + new_edges_[target_block].insert(block->id()); cfg()->AddEdge(block->id(), target); } @@ -210,25 +255,33 @@ void MergeReturnPass::UpdatePhiNodes(BasicBlock* new_source, inst->AddOperand({SPV_OPERAND_TYPE_ID, {new_source->id()}}); context()->UpdateDefUse(inst); }); - - const auto& target_pred = cfg()->preds(target->id()); - if (target_pred.size() == 1) { - MarkForNewPhiNodes(target, context()->get_instr_block(target_pred[0])); - } } void MergeReturnPass::CreatePhiNodesForInst(BasicBlock* merge_block, - uint32_t predecessor, Instruction& inst) { DominatorAnalysis* dom_tree = context()->GetDominatorAnalysis(merge_block->GetParent()); - BasicBlock* inst_bb = context()->get_instr_block(&inst); if (inst.result_id() != 0) { + BasicBlock* inst_bb = context()->get_instr_block(&inst); std::vector users_to_update; context()->get_def_use_mgr()->ForEachUser( - &inst, [&users_to_update, &dom_tree, inst_bb, this](Instruction* user) { - BasicBlock* user_bb = context()->get_instr_block(user); + &inst, + [&users_to_update, &dom_tree, &inst, inst_bb, this](Instruction* user) { + BasicBlock* user_bb = nullptr; + if (user->opcode() != SpvOpPhi) { + user_bb = context()->get_instr_block(user); + } else { + // For OpPhi, the use should be considered to be in the predecessor. + for (uint32_t i = 0; i < user->NumInOperands(); i += 2) { + if (user->GetSingleWordInOperand(i) == inst.result_id()) { + uint32_t user_bb_id = user->GetSingleWordInOperand(i + 1); + user_bb = context()->get_instr_block(user_bb_id); + break; + } + } + } + // If |user_bb| is nullptr, then |user| is not in the function. It is // something like an OpName or decoration, which should not be // replaced with the result of the OpPhi. @@ -243,22 +296,23 @@ void MergeReturnPass::CreatePhiNodesForInst(BasicBlock* merge_block, // There is at least one values that needs to be replaced. // First create the OpPhi instruction. - InstructionBuilder builder(context(), &*merge_block->begin(), - IRContext::kAnalysisDefUse); + InstructionBuilder builder( + context(), &*merge_block->begin(), + IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping); uint32_t undef_id = Type2Undef(inst.type_id()); std::vector phi_operands; + const std::set& new_edges = new_edges_[merge_block]; - // Add the operands for the defining instructions. - phi_operands.push_back(inst.result_id()); - phi_operands.push_back(predecessor); - - // Add undef from all other blocks. + // Add the OpPhi operands. If the predecessor is a return block use undef, + // otherwise use |inst|'s id. std::vector preds = cfg()->preds(merge_block->id()); for (uint32_t pred_id : preds) { - if (pred_id != predecessor) { + if (new_edges.count(pred_id)) { phi_operands.push_back(undef_id); - phi_operands.push_back(pred_id); + } else { + phi_operands.push_back(inst.result_id()); } + phi_operands.push_back(pred_id); } Instruction* new_phi = builder.AddPhi(inst.type_id(), phi_operands); @@ -276,14 +330,14 @@ void MergeReturnPass::CreatePhiNodesForInst(BasicBlock* merge_block, } } -void MergeReturnPass::PredicateBlocks( +bool MergeReturnPass::PredicateBlocks( BasicBlock* return_block, std::unordered_set* predicated, std::list* order) { // The CFG is being modified as the function proceeds so avoid caching // successors. if (predicated->count(return_block)) { - return; + return true; } BasicBlock* block = nullptr; @@ -301,8 +355,8 @@ void MergeReturnPass::PredicateBlocks( std::unordered_set seen; if (block->id() == state->CurrentMergeId()) { state++; - } else if (block->id() == state->LoopMergeId()) { - while (state->LoopMergeId() == block->id()) { + } else if (block->id() == state->BreakMergeId()) { + while (state->BreakMergeId() == block->id()) { state++; } } @@ -310,71 +364,25 @@ void MergeReturnPass::PredicateBlocks( while (block != nullptr && block != final_return_block_) { if (!predicated->insert(block).second) break; // Skip structured subgraphs. - BasicBlock* next = nullptr; - if (state->InLoop()) { - next = context()->get_instr_block(state->LoopMergeId()); - while (state->LoopMergeId() == next->id()) { - state++; - } - BreakFromConstruct(block, next, predicated, order); - } else if (false && state->InStructuredFlow()) { - // TODO(#1861): This is disabled until drivers are fixed to accept - // conditional exits from a selection construct. Reenable tests when - // this code is turned back on. - - next = context()->get_instr_block(state->CurrentMergeId()); + assert(state->InBreakable() && + "Should be in the dummy construct at the very least."); + Instruction* break_merge_inst = state->BreakMergeInst(); + uint32_t merge_block_id = break_merge_inst->GetSingleWordInOperand(0); + while (state->BreakMergeId() == merge_block_id) { state++; - BreakFromConstruct(block, next, predicated, order); - } else { - BasicBlock* tail = block; - while (tail->GetMergeInst()) { - tail = context()->get_instr_block(tail->MergeBlockIdIfAny()); - } - - // Must find |next| (the successor of |tail|) before predicating the - // block because, if |block| == |tail|, then |tail| will have multiple - // successors. - next = nullptr; - const_cast(tail)->ForEachSuccessorLabel( - [this, &next](const uint32_t idx) { - BasicBlock* succ_block = context()->get_instr_block(idx); - assert(next == nullptr && - "Found block with multiple successors and no merge " - "instruction."); - next = succ_block; - }); - - PredicateBlock(block, tail, predicated, order); } - block = next; + if (!BreakFromConstruct(block, predicated, order, break_merge_inst)) { + return false; + } + block = context()->get_instr_block(merge_block_id); } + return true; } -bool MergeReturnPass::RequiresPredication(const BasicBlock* block, - const BasicBlock* tail_block) const { - // This is intentionally conservative. - // TODO(alanbaker): re-visit this when more performance data is available. - if (block != tail_block) return true; - - bool requires_predicate = false; - block->ForEachInst([&requires_predicate](const Instruction* inst) { - if (inst->opcode() != SpvOpPhi && inst->opcode() != SpvOpLabel && - !IsTerminatorInst(inst->opcode())) { - requires_predicate = true; - } - }); - return requires_predicate; -} - -void MergeReturnPass::PredicateBlock( - BasicBlock* block, BasicBlock* tail_block, - std::unordered_set* predicated, - std::list* order) { - if (!RequiresPredication(block, tail_block)) { - return; - } - - // Make sure the cfg is build here. If we don't then it becomes very hard +bool MergeReturnPass::BreakFromConstruct( + BasicBlock* block, std::unordered_set* predicated, + std::list* order, Instruction* break_merge_inst) { + // Make sure the CFG is build here. If we don't then it becomes very hard // to know which new blocks need to be updated. context()->BuildInvalidAnalyses(IRContext::kAnalysisCFG); @@ -390,7 +398,15 @@ void MergeReturnPass::PredicateBlock( // If |block| is a loop header, then the back edge must jump to the original // code, not the new header. if (block->GetLoopMergeInst()) { - cfg()->SplitLoopHeader(block); + if (cfg()->SplitLoopHeader(block) == nullptr) { + return false; + } + } + + uint32_t merge_block_id = break_merge_inst->GetSingleWordInOperand(0); + BasicBlock* merge_block = context()->get_instr_block(merge_block_id); + if (merge_block->GetLoopMergeInst()) { + cfg()->SplitLoopHeader(merge_block); } // Leave the phi instructions behind. @@ -402,152 +418,24 @@ void MergeReturnPass::PredicateBlock( // Forget about the edges leaving block. They will be removed. cfg()->RemoveSuccessorEdges(block); - std::unique_ptr new_block( - block->SplitBasicBlock(context(), TakeNextId(), iter)); - BasicBlock* old_body = - function_->InsertBasicBlockAfter(std::move(new_block), block); + auto old_body_id = TakeNextId(); + BasicBlock* old_body = block->SplitBasicBlock(context(), old_body_id, iter); predicated->insert(old_body); + cfg()->AddEdges(old_body); - // Update |order| so old_block will be traversed. - InsertAfterElement(block, old_body, order); - - if (tail_block == block) { - tail_block = old_body; + // If a return block is being split, mark the new body block also as a return + // block. + if (return_blocks_.count(block->id())) { + return_blocks_.insert(old_body_id); } - const BasicBlock* const_old_body = static_cast(old_body); - const_old_body->ForEachSuccessorLabel( - [old_body, block, this](const uint32_t label) { - BasicBlock* target_bb = context()->get_instr_block(label); - if (MarkedSinglePred(target_bb) == block) { - MarkForNewPhiNodes(target_bb, old_body); - } - }); - - std::unique_ptr new_merge_block(new BasicBlock( - MakeUnique(context(), SpvOpLabel, 0, TakeNextId(), - std::initializer_list{}))); - - BasicBlock* new_merge = - function_->InsertBasicBlockAfter(std::move(new_merge_block), tail_block); - predicated->insert(new_merge); - new_merge->SetParent(function_); - - // Update |order| so old_block will be traversed. - InsertAfterElement(tail_block, new_merge, order); - - // Register the new label. - get_def_use_mgr()->AnalyzeInstDef(new_merge->GetLabelInst()); - context()->set_instr_block(new_merge->GetLabelInst(), new_merge); - - // Move the tail branch into the new merge and fix the mapping. If a single - // block is being predicated then its branch was moved to the old body - // previously. - std::unique_ptr inst; - Instruction* i = tail_block->terminator(); - cfg()->RemoveSuccessorEdges(tail_block); - get_def_use_mgr()->ClearInst(i); - inst.reset(std::move(i)); - inst->RemoveFromList(); - new_merge->end().InsertBefore(std::move(inst)); - get_def_use_mgr()->AnalyzeInstUse(new_merge->terminator()); - context()->set_instr_block(new_merge->terminator(), new_merge); - - // Add a branch to the new merge. If we jumped multiple blocks, the branch - // is added to tail_block, otherwise the branch belongs in old_body. - tail_block->AddInstruction( - MakeUnique(context(), SpvOpBranch, 0, 0, - std::initializer_list{ - {SPV_OPERAND_TYPE_ID, {new_merge->id()}}})); - get_def_use_mgr()->AnalyzeInstUse(tail_block->terminator()); - context()->set_instr_block(tail_block->terminator(), tail_block); - - // Within the new header we need the following: - // 1. Load of the return status flag - // 2. Declare the merge block - // 3. Branch to new merge (true) or old body (false) - - // 1. Load of the return status flag - analysis::Bool bool_type; - uint32_t bool_id = context()->get_type_mgr()->GetId(&bool_type); - assert(bool_id != 0); - uint32_t load_id = TakeNextId(); - block->AddInstruction(MakeUnique( - context(), SpvOpLoad, bool_id, load_id, - std::initializer_list{ - {SPV_OPERAND_TYPE_ID, {return_flag_->result_id()}}})); - get_def_use_mgr()->AnalyzeInstDefUse(block->terminator()); - context()->set_instr_block(block->terminator(), block); - - // 2. Declare the merge block - block->AddInstruction(MakeUnique( - context(), SpvOpSelectionMerge, 0, 0, - std::initializer_list{{SPV_OPERAND_TYPE_ID, {new_merge->id()}}, - {SPV_OPERAND_TYPE_SELECTION_CONTROL, - {SpvSelectionControlMaskNone}}})); - get_def_use_mgr()->AnalyzeInstUse(block->terminator()); - context()->set_instr_block(block->terminator(), block); - - // 3. Branch to new merge (true) or old body (false) - block->AddInstruction(MakeUnique( - context(), SpvOpBranchConditional, 0, 0, - std::initializer_list{{SPV_OPERAND_TYPE_ID, {load_id}}, - {SPV_OPERAND_TYPE_ID, {new_merge->id()}}, - {SPV_OPERAND_TYPE_ID, {old_body->id()}}})); - get_def_use_mgr()->AnalyzeInstUse(block->terminator()); - context()->set_instr_block(block->terminator(), block); - - assert(old_body->begin() != old_body->end()); - assert(block->begin() != block->end()); - assert(new_merge->begin() != new_merge->end()); - - // Update the cfg - cfg()->AddEdges(block); - cfg()->RegisterBlock(old_body); - if (old_body != tail_block) { - cfg()->AddEdges(tail_block); + // If |block| was a continue target for a loop |old_body| is now the correct + // continue target. + if (break_merge_inst->opcode() == SpvOpLoopMerge && + break_merge_inst->GetSingleWordInOperand(1) == block->id()) { + break_merge_inst->SetInOperand(1, {old_body->id()}); + context()->UpdateDefUse(break_merge_inst); } - cfg()->RegisterBlock(new_merge); - MarkForNewPhiNodes(new_merge, tail_block); -} - -void MergeReturnPass::BreakFromConstruct( - BasicBlock* block, BasicBlock* merge_block, - std::unordered_set* predicated, - std::list* order) { - // Make sure the cfg is build here. If we don't then it becomes very hard - // to know which new blocks need to be updated. - context()->BuildInvalidAnalyses(IRContext::kAnalysisCFG); - - // When predicating, be aware of whether this block is a header block, a - // merge block or both. - // - // If this block is a merge block, ensure the appropriate header stays - // up-to-date with any changes (i.e. points to the pre-header). - // - // If this block is a header block, predicate the entire structured - // subgraph. This can act recursively. - - // If |block| is a loop header, then the back edge must jump to the original - // code, not the new header. - if (block->GetLoopMergeInst()) { - cfg()->SplitLoopHeader(block); - } - - // Leave the phi instructions behind. - auto iter = block->begin(); - while (iter->opcode() == SpvOpPhi) { - ++iter; - } - - // Forget about the edges leaving block. They will be removed. - cfg()->RemoveSuccessorEdges(block); - - std::unique_ptr new_block( - block->SplitBasicBlock(context(), TakeNextId(), iter)); - BasicBlock* old_body = - function_->InsertBasicBlockAfter(std::move(new_block), block); - predicated->insert(old_body); // Update |order| so old_block will be traversed. InsertAfterElement(block, old_body, order); @@ -556,45 +444,43 @@ void MergeReturnPass::BreakFromConstruct( // 1. Load of the return status flag // 2. Branch to |merge_block| (true) or old body (false) // 3. Update OpPhi instructions in |merge_block|. + // 4. Update the CFG. // - // Sine we are branching to the merge block of the current construct, there is - // no need for an OpSelectionMerge. + // Since we are branching to the merge block of the current construct, there + // is no need for an OpSelectionMerge. + InstructionBuilder builder( + context(), block, + IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping); // 1. Load of the return status flag analysis::Bool bool_type; uint32_t bool_id = context()->get_type_mgr()->GetId(&bool_type); assert(bool_id != 0); - uint32_t load_id = TakeNextId(); - block->AddInstruction(MakeUnique( - context(), SpvOpLoad, bool_id, load_id, - std::initializer_list{ - {SPV_OPERAND_TYPE_ID, {return_flag_->result_id()}}})); - get_def_use_mgr()->AnalyzeInstDefUse(block->terminator()); - context()->set_instr_block(block->terminator(), block); + uint32_t load_id = + builder.AddLoad(bool_id, return_flag_->result_id())->result_id(); // 2. Branch to |merge_block| (true) or |old_body| (false) - block->AddInstruction(MakeUnique( - context(), SpvOpBranchConditional, 0, 0, - std::initializer_list{{SPV_OPERAND_TYPE_ID, {load_id}}, - {SPV_OPERAND_TYPE_ID, {merge_block->id()}}, - {SPV_OPERAND_TYPE_ID, {old_body->id()}}})); - get_def_use_mgr()->AnalyzeInstUse(block->terminator()); - context()->set_instr_block(block->terminator(), block); + builder.AddConditionalBranch(load_id, merge_block->id(), old_body->id(), + old_body->id()); - // Update the cfg + if (!new_edges_[merge_block].insert(block->id()).second) { + // It is possible that we already inserted a new edge to the merge block. + // If so, that edge now goes from |old_body| to |merge_block|. + new_edges_[merge_block].insert(old_body->id()); + } + + // 3. Update OpPhi instructions in |merge_block|. + UpdatePhiNodes(block, merge_block); + + // 4. Update the CFG. We do this after updating the OpPhi instructions + // because |UpdatePhiNodes| assumes the edge from |block| has not been added + // to the CFG yet. cfg()->AddEdges(block); cfg()->RegisterBlock(old_body); - // 3. Update OpPhi instructions in |merge_block|. - BasicBlock* merge_original_pred = MarkedSinglePred(merge_block); - if (merge_original_pred == nullptr) { - UpdatePhiNodes(block, merge_block); - } else if (merge_original_pred == block) { - MarkForNewPhiNodes(merge_block, old_body); - } - assert(old_body->begin() != old_body->end()); assert(block->begin() != block->end()); + return true; } void MergeReturnPass::RecordReturned(BasicBlock* block) { @@ -781,34 +667,54 @@ void MergeReturnPass::MergeReturnBlocks( } void MergeReturnPass::AddNewPhiNodes() { - DominatorAnalysis* dom_tree = context()->GetDominatorAnalysis(function_); std::list order; cfg()->ComputeStructuredOrder(function_, &*function_->begin(), &order); for (BasicBlock* bb : order) { - AddNewPhiNodes(bb, new_merge_nodes_[bb], - dom_tree->ImmediateDominator(bb)->id()); + AddNewPhiNodes(bb); } } -void MergeReturnPass::AddNewPhiNodes(BasicBlock* bb, BasicBlock* pred, - uint32_t header_id) { - DominatorAnalysis* dom_tree = context()->GetDominatorAnalysis(function_); - // Insert as a stopping point. We do not have to add anything in the block - // or above because the header dominates |bb|. +void MergeReturnPass::AddNewPhiNodes(BasicBlock* bb) { + // New phi nodes are needed for any id whose definition used to dominate |bb|, + // but no longer dominates |bb|. These are found by walking the dominator + // tree starting at the original immediate dominator of |bb| and ending at its + // current dominator. - BasicBlock* current_bb = pred; - while (current_bb != nullptr && current_bb->id() != header_id) { + // Because we are walking the updated dominator tree it is important that the + // new phi nodes for the original dominators of |bb| have already been added. + // Otherwise some ids might be missed. Consider the case where bb1 dominates + // bb2, and bb2 dominates bb3. Suppose there are changes such that bb1 no + // longer dominates bb2 and the same for bb2 and bb3. This algorithm will not + // look at the ids defined in bb1. However, calling |AddNewPhiNodes(bb2)| + // first will add a phi node in bb2 for that value. Then a call to + // |AddNewPhiNodes(bb3)| will process that value by processing the phi in bb2. + DominatorAnalysis* dom_tree = context()->GetDominatorAnalysis(function_); + + BasicBlock* dominator = dom_tree->ImmediateDominator(bb); + if (dominator == nullptr) { + return; + } + + BasicBlock* current_bb = context()->get_instr_block(original_dominator_[bb]); + while (current_bb != nullptr && current_bb != dominator) { for (Instruction& inst : *current_bb) { - CreatePhiNodesForInst(bb, pred->id(), inst); + CreatePhiNodesForInst(bb, inst); } current_bb = dom_tree->ImmediateDominator(current_bb); } } -void MergeReturnPass::MarkForNewPhiNodes(BasicBlock* block, - BasicBlock* single_original_pred) { - new_merge_nodes_[block] = single_original_pred; +void MergeReturnPass::RecordImmediateDominators(Function* function) { + DominatorAnalysis* dom_tree = context()->GetDominatorAnalysis(function); + for (BasicBlock& bb : *function) { + BasicBlock* dominator_bb = dom_tree->ImmediateDominator(&bb); + if (dominator_bb && dominator_bb != cfg()->pseudo_entry_block()) { + original_dominator_[&bb] = dominator_bb->terminator(); + } else { + original_dominator_[&bb] = nullptr; + } + } } void MergeReturnPass::InsertAfterElement(BasicBlock* element, @@ -820,5 +726,110 @@ void MergeReturnPass::InsertAfterElement(BasicBlock* element, list->insert(pos, new_element); } +void MergeReturnPass::AddDummySwitchAroundFunction() { + CreateReturnBlock(); + CreateReturn(final_return_block_); + + if (context()->AreAnalysesValid(IRContext::kAnalysisCFG)) { + cfg()->RegisterBlock(final_return_block_); + } + + CreateDummySwitch(final_return_block_); +} + +BasicBlock* MergeReturnPass::CreateContinueTarget(uint32_t header_label_id) { + std::unique_ptr label( + new Instruction(context(), SpvOpLabel, 0u, TakeNextId(), {})); + + // Create the new basic block + std::unique_ptr block(new BasicBlock(std::move(label))); + + // Insert the new block just before the return block + auto pos = function_->end(); + assert(pos != function_->begin()); + pos--; + assert(pos != function_->begin()); + assert(&*pos == final_return_block_); + auto new_block = &*pos.InsertBefore(std::move(block)); + new_block->SetParent(function_); + + context()->AnalyzeDefUse(new_block->GetLabelInst()); + context()->set_instr_block(new_block->GetLabelInst(), new_block); + + InstructionBuilder builder( + context(), new_block, + IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping); + + builder.AddBranch(header_label_id); + + if (context()->AreAnalysesValid(IRContext::kAnalysisCFG)) { + cfg()->RegisterBlock(new_block); + } + + return new_block; +} + +void MergeReturnPass::CreateDummySwitch(BasicBlock* merge_target) { + // Insert the switch before any code is run. We have to split the entry + // block to make sure the OpVariable instructions remain in the entry block. + BasicBlock* start_block = &*function_->begin(); + auto split_pos = start_block->begin(); + while (split_pos->opcode() == SpvOpVariable) { + ++split_pos; + } + + BasicBlock* old_block = + start_block->SplitBasicBlock(context(), TakeNextId(), split_pos); + + // Add the switch to the end of the entry block. + InstructionBuilder builder( + context(), start_block, + IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping); + + builder.AddSwitch(builder.GetUintConstantId(0u), old_block->id(), {}, + merge_target->id()); + + if (context()->AreAnalysesValid(IRContext::kAnalysisCFG)) { + cfg()->RegisterBlock(old_block); + cfg()->AddEdges(start_block); + } +} + +bool MergeReturnPass::HasNontrivialUnreachableBlocks(Function* function) { + utils::BitVector reachable_blocks; + cfg()->ForEachBlockInPostOrder( + function->entry().get(), + [&reachable_blocks](BasicBlock* bb) { reachable_blocks.Set(bb->id()); }); + + for (auto& bb : *function) { + if (reachable_blocks.Get(bb.id())) { + continue; + } + + StructuredCFGAnalysis* struct_cfg_analysis = + context()->GetStructuredCFGAnalysis(); + if (struct_cfg_analysis->IsContinueBlock(bb.id())) { + // |bb| must be an empty block ending with a branch to the header. + Instruction* inst = &*bb.begin(); + if (inst->opcode() != SpvOpBranch) { + return true; + } + + if (inst->GetSingleWordInOperand(0) != + struct_cfg_analysis->ContainingLoop(bb.id())) { + return true; + } + } else if (struct_cfg_analysis->IsMergeBlock(bb.id())) { + // |bb| must be an empty block ending with OpUnreachable. + if (bb.begin()->opcode() != SpvOpUnreachable) { + return true; + } + } else { + return true; + } + } + return false; +} + } // namespace opt } // namespace spvtools diff --git a/third_party/spirv-tools/source/opt/merge_return_pass.h b/third_party/spirv-tools/source/opt/merge_return_pass.h index 472d059fe5..fe85557afa 100644 --- a/third_party/spirv-tools/source/opt/merge_return_pass.h +++ b/third_party/spirv-tools/source/opt/merge_return_pass.h @@ -30,13 +30,14 @@ namespace opt { * * Handling Structured Control Flow: * - * Structured control flow guarantees that the CFG will reconverge at a given + * Structured control flow guarantees that the CFG will converge at a given * point (the merge block). Within structured control flow, all blocks must be * post-dominated by the merge block, except return blocks and break blocks. - * A break block is a block that branches to the innermost loop's merge block. + * A break block is a block that branches to a containing construct's merge + * block. * * Beyond this, we further assume that all unreachable blocks have been - * cleanedup. This means that the only unreachable blocks are those necessary + * cleaned up. This means that the only unreachable blocks are those necessary * for valid structured control flow. * * Algorithm: @@ -46,14 +47,14 @@ namespace opt { * with a branch. If current block is not within structured control flow, this * is the final return. This block should branch to the new return block (its * direct successor). If the current block is within structured control flow, - * the branch destination should be the innermost loop's merge (if it exists) - * or the merge block of the immediate structured control flow. If the merge - * block produces any live values it will need to be predicated. While the merge - * is nested in structured control flow, the predication path should branch to - * the next best merge block available. Once structured control flow has been - * exited, remaining blocks must be predicated with new structured control flow - * (OpSelectionMerge). These should be nested correctly in case of straight line - * branching to reach the final return block. + * the branch destination should be the innermost construct's merge. This + * merge will always exist because a dummy switch is added around the + * entire function. If the merge block produces any live values it will need to + * be predicated. While the merge is nested in structured control flow, the + * predication path should branch to the merge block of the inner-most loop + * (or switch if no loop) it is contained in. Once structured control flow has + * been exited, it will be at the merge of the dummy switch, which will simply + * return. * * In the final return block, the return value should be loaded and returned. * Memory promotion passes should be able to promote the newly introduced @@ -65,31 +66,29 @@ namespace opt { * that block produces value live beyond it). This needs to be done carefully. * The merge block should be split into multiple blocks. * - * 1 (header) + * 1 (loop header) * / \ * (ret) 2 3 (merge) * * || * \/ * - * 1 (header) - * / \ - * 2 | - * \ / - * 3 (merge for 1, new header) - * / \ - * | 3 (old body) - * \ / - * (ret) 4 (new merge) + * 0 (dummy switch header) + * | + * 1 (loop header) + * / \ + * 2 | (merge) + * \ / + * 3' (merge) + * / \ + * | 3 (original code in 3) + * \ / + * (ret) 4 (dummy switch merge) * * In the above (simple) example, the return originally in |2| is passed through - * the merge. That merge is predicated such that the old body of the block is - * the else branch. The branch condition is based on the value of the "has - * returned" variable. In more complicated examples (blocks between |1| and - * |3|), the SSA would need to fixed up due the newly reconvergent path at the - * merge for |1|. Assuming |3| originally was also a return block, the old body - * of |3| should also store the return value for that case. The return value in - * |4| just requires loading the return value variable. + * the loop merge. That merge is predicated such that the old body of the block + * is the else branch. The branch condition is based on the value of the "has + * returned" variable. * ******************************************************************************/ @@ -107,22 +106,21 @@ class MergeReturnPass : public MemPass { Status Process() override; IRContext::Analysis GetPreservedAnalyses() override { - // return IRContext::kAnalysisDefUse; - return IRContext::kAnalysisNone; + return IRContext::kAnalysisConstants | IRContext::kAnalysisTypes; } private: - // This class is used to store the a loop merge instruction and a selection - // merge instruction. The intended use is that is represent the inner most - // contain selection construct and the inner most loop construct. + // This class is used to store the a break merge instruction and a current + // merge instruction. The intended use is to keep track of the block to + // break to and the current innermost control flow construct merge block. class StructuredControlState { public: - StructuredControlState(Instruction* loop, Instruction* merge) - : loop_merge_(loop), current_merge_(merge) {} + StructuredControlState(Instruction* break_merge, Instruction* merge) + : break_merge_(break_merge), current_merge_(merge) {} StructuredControlState(const StructuredControlState&) = default; - bool InLoop() const { return loop_merge_; } + bool InBreakable() const { return break_merge_; } bool InStructuredFlow() const { return CurrentMergeId() != 0; } uint32_t CurrentMergeId() const { @@ -136,20 +134,14 @@ class MergeReturnPass : public MemPass { : 0; } - uint32_t LoopMergeId() const { - return loop_merge_ ? loop_merge_->GetSingleWordInOperand(0u) : 0u; + uint32_t BreakMergeId() const { + return break_merge_ ? break_merge_->GetSingleWordInOperand(0u) : 0u; } - uint32_t CurrentLoopHeader() const { - return loop_merge_ - ? loop_merge_->context()->get_instr_block(loop_merge_)->id() - : 0; - } - - Instruction* LoopMergeInst() const { return loop_merge_; } + Instruction* BreakMergeInst() const { return break_merge_; } private: - Instruction* loop_merge_; + Instruction* break_merge_; Instruction* current_merge_; }; @@ -163,11 +155,14 @@ class MergeReturnPass : public MemPass { void MergeReturnBlocks(Function* function, const std::vector& returnBlocks); + // Generate and push new control flow state if |block| contains a merge. + void GenerateState(BasicBlock* block); + // Merges the return instruction in |function| so that it has a single return // statement. It is assumed that |function| has structured control flow, and // that |return_blocks| is a list of all of the basic blocks in |function| // that have a return. - void ProcessStructured(Function* function, + bool ProcessStructured(Function* function, const std::vector& return_blocks); // Changes an OpReturn* or OpUnreachable instruction at the end of |block| @@ -209,12 +204,6 @@ class MergeReturnPass : public MemPass { // |AddReturnFlag| and |AddReturnValue| must have already been called. void BranchToBlock(BasicBlock* block, uint32_t target); - // Returns true if we need to predicate |block| where |tail_block| is the - // merge point. (See |PredicateBlocks|). There is no need to predicate if - // there is no code that could be executed. - bool RequiresPredication(const BasicBlock* block, - const BasicBlock* tail_block) const; - // For every basic block that is reachable from |return_block|, extra code is // added to jump around any code that should not be executed because the // original code would have already returned. This involves adding new @@ -222,29 +211,25 @@ class MergeReturnPass : public MemPass { // // If new blocks that are created will be added to |order|. This way a call // can traverse these new block in structured order. - void PredicateBlocks(BasicBlock* return_block, + // + // Returns true if successful. + bool PredicateBlocks(BasicBlock* return_block, std::unordered_set* pSet, std::list* order); // Add a conditional branch at the start of |block| that either jumps to - // |merge_block| or the original code in |block| depending on the value in - // |return_flag_|. + // the merge block of |break_merge_inst| or the original code in |block| + // depending on the value in |return_flag_|. The continue target in + // |break_merge_inst| will be updated if needed. // // If new blocks that are created will be added to |order|. This way a call // can traverse these new block in structured order. - void BreakFromConstruct(BasicBlock* block, BasicBlock* merge_block, + // + // Returns true if successful. + bool BreakFromConstruct(BasicBlock* block, std::unordered_set* predicated, - std::list* order); - - // Add the predication code (see |PredicateBlocks|) to |tail_block| if it - // requires predication. |tail_block| and any new blocks that are known to - // not require predication will be added to |predicated|. - // - // If new blocks that are created will be added to |order|. This way a call - // can traverse these new block in structured order. - void PredicateBlock(BasicBlock* block, BasicBlock* tail_block, - std::unordered_set* predicated, - std::list* order); + std::list* order, + Instruction* break_merge_inst); // Add an |OpReturn| or |OpReturnValue| to the end of |block|. If an // |OpReturnValue| is needed, the return value is loaded from |return_value_|. @@ -254,43 +239,31 @@ class MergeReturnPass : public MemPass { // return block at the end of the pass. void CreateReturnBlock(); - // Creates a Phi node in |merge_block| for the result of |inst| coming from - // |predecessor|. Any uses of the result of |inst| that are no longer + // Creates a Phi node in |merge_block| for the result of |inst|. + // Any uses of the result of |inst| that are no longer // dominated by |inst|, are replaced with the result of the new |OpPhi| // instruction. - void CreatePhiNodesForInst(BasicBlock* merge_block, uint32_t predecessor, - Instruction& inst); + void CreatePhiNodesForInst(BasicBlock* merge_block, Instruction& inst); - // Traverse the nodes in |new_merge_nodes_|, and adds the OpPhi instructions - // that are needed to make the code correct. It is assumed that at this point - // there are no unreachable blocks in the control flow graph. + // Add new phi nodes for any id that no longer dominate all of it uses. A phi + // node is added to a block |bb| for an id if the id is defined between the + // original immediate dominator of |bb| and its new immidiate dominator. It + // is assumed that at this point there are no unreachable blocks in the + // control flow graph. void AddNewPhiNodes(); - // Creates any new phi nodes that are needed in |bb| now that |pred| is no - // longer the only block that preceedes |bb|. |header_id| is the id of the - // basic block for the loop or selection construct that merges at |bb|. - void AddNewPhiNodes(BasicBlock* bb, BasicBlock* pred, uint32_t header_id); + // Creates any new phi nodes that are needed in |bb|. |AddNewPhiNodes| must + // have already been called on the original dominators of |bb|. + void AddNewPhiNodes(BasicBlock* bb); - // Saves |block| to a list of basic block that will require OpPhi nodes to be - // added by calling |AddNewPhiNodes|. It is assumed that |block| used to have - // a single predecessor, |single_original_pred|, but now has more. - void MarkForNewPhiNodes(BasicBlock* block, BasicBlock* single_original_pred); - - // Return the original single predcessor of |block| if it was flagged as - // having a single predecessor. |nullptr| is returned otherwise. - BasicBlock* MarkedSinglePred(BasicBlock* block) { - auto it = new_merge_nodes_.find(block); - if (it != new_merge_nodes_.end()) { - return it->second; - } else { - return nullptr; - } - } + // Records the terminator of immediate dominator for every basic block in + // |function|. + void RecordImmediateDominators(Function* function); // Modifies existing OpPhi instruction in |target| block to account for the - // new edge from |new_source|. The value for that edge will be an Undef. If - // |target| only had a single predecessor, then it is marked as needing new - // phi nodes. See |MarkForNewPhiNodes|. + // new edge from |new_source|. The value for that edge will be an Undef. + // + // The CFG must not include the edge from |new_source| to |target| yet. void UpdatePhiNodes(BasicBlock* new_source, BasicBlock* target); StructuredControlState& CurrentState() { return state_.back(); } @@ -300,8 +273,28 @@ class MergeReturnPass : public MemPass { void InsertAfterElement(BasicBlock* element, BasicBlock* new_element, std::list* list); - // A stack used to keep track of the innermost contain loop and selection - // constructs. + // Creates a single case switch around all of the exectuable code of the + // current function where the switch and case value are both zero and the + // default is the merge block. Returns after the switch is executed. Sets + // |final_return_block_|. + void AddDummySwitchAroundFunction(); + + // Creates a new basic block that branches to |header_label_id|. Returns the + // new basic block. The block will be the second last basic block in the + // function. + BasicBlock* CreateContinueTarget(uint32_t header_label_id); + + // Creates a one case switch around the executable code of the function with + // |merge_target| as the merge node. + void CreateDummySwitch(BasicBlock* merge_target); + + // Returns true if |function| has an unreachable block that is not a continue + // target that simply branches back to the header, or a merge block containing + // 1 instruction which is OpUnreachable. + bool HasNontrivialUnreachableBlocks(Function* function); + + // A stack used to keep track of the break and current control flow construct + // merge blocks. std::vector state_; // The current function being transformed. @@ -323,11 +316,19 @@ class MergeReturnPass : public MemPass { // after processing the current function. BasicBlock* final_return_block_; - // This map contains the set of nodes that use to have a single predcessor, - // but now have more. They will need new OpPhi nodes. For each of the nodes, - // it is mapped to it original single predcessor. It is assumed there are no - // values that will need a phi on the new edges. - std::unordered_map new_merge_nodes_; + // This is a map from a node to its original immediate dominator identified by + // the terminator if that block. We use the terminator because the block we + // want may change if the block is split. + std::unordered_map original_dominator_; + + // A map from a basic block, bb, to the set of basic blocks which represent + // the new edges that reach |bb|. + std::unordered_map> new_edges_; + + // Contains all return blocks that are merged. This is set is populated while + // processing structured blocks and used to properly construct OpPhi + // instructions. + std::unordered_set return_blocks_; }; } // namespace opt diff --git a/third_party/spirv-tools/source/opt/module.cpp b/third_party/spirv-tools/source/opt/module.cpp index 6d024b5bcb..4403894d83 100644 --- a/third_party/spirv-tools/source/opt/module.cpp +++ b/third_party/spirv-tools/source/opt/module.cpp @@ -19,11 +19,24 @@ #include #include "source/operand.h" +#include "source/opt/ir_context.h" #include "source/opt/reflect.h" namespace spvtools { namespace opt { +uint32_t Module::TakeNextIdBound() { + if (context()) { + if (id_bound() >= context()->max_id_bound()) { + return 0; + } + } else if (id_bound() >= kDefaultMaxIdBound) { + return 0; + } + + return header_.bound++; +} + std::vector Module::GetTypes() { std::vector type_insts; for (auto& inst : types_values_) { @@ -82,6 +95,7 @@ void Module::ForEachInst(const std::function& f, DELEGATE(debugs1_); DELEGATE(debugs2_); DELEGATE(debugs3_); + DELEGATE(ext_inst_debuginfo_); DELEGATE(annotations_); DELEGATE(types_values_); for (auto& i : functions_) i->ForEachInst(f, run_on_debug_line_insts); @@ -104,10 +118,14 @@ void Module::ForEachInst(const std::function& f, for (auto& i : debugs3_) DELEGATE(i); for (auto& i : annotations_) DELEGATE(i); for (auto& i : types_values_) DELEGATE(i); + for (auto& i : ext_inst_debuginfo_) DELEGATE(i); for (auto& i : functions_) { static_cast(i.get())->ForEachInst(f, run_on_debug_line_insts); } + if (run_on_debug_line_insts) { + for (auto& i : trailing_dbg_line_info_) DELEGATE(i); + } #undef DELEGATE } diff --git a/third_party/spirv-tools/source/opt/module.h b/third_party/spirv-tools/source/opt/module.h index eca8cc7798..fc53d35a1a 100644 --- a/third_party/spirv-tools/source/opt/module.h +++ b/third_party/spirv-tools/source/opt/module.h @@ -53,14 +53,22 @@ class Module { // Sets the header to the given |header|. void SetHeader(const ModuleHeader& header) { header_ = header; } - // Sets the Id bound. - void SetIdBound(uint32_t bound) { header_.bound = bound; } + // Sets the Id bound. The Id bound cannot be set to 0. + void SetIdBound(uint32_t bound) { + assert(bound != 0); + header_.bound = bound; + } // Returns the Id bound. uint32_t IdBound() { return header_.bound; } // Returns the current Id bound and increases it to the next available value. - uint32_t TakeNextIdBound() { return header_.bound++; } + // If the id bound has already reached its maximum value, then 0 is returned. + // The maximum value for the id bound is obtained from the context. If there + // is none, then the minimum that limit can be according to the spir-v + // specification. + // TODO(1841): Update the uses to check for a 0 return value. + uint32_t TakeNextIdBound(); // Appends a capability instruction to this module. inline void AddCapability(std::unique_ptr c); @@ -94,6 +102,10 @@ class Module { // This is due to decision by the SPIR Working Group, pending publication. inline void AddDebug3Inst(std::unique_ptr d); + // Appends a debug info extension (OpenCL.DebugInfo.100 or DebugInfo) + // instruction to this module. + inline void AddExtInstDebugInfo(std::unique_ptr d); + // Appends an annotation instruction to this module. inline void AddAnnotationInst(std::unique_ptr a); @@ -125,6 +137,8 @@ class Module { inline uint32_t version() const { return header_.version; } + inline void set_version(uint32_t v) { header_.version = v; } + // Iterators for capabilities instructions contained in this module. inline inst_iterator capability_begin(); inline inst_iterator capability_end(); @@ -172,6 +186,14 @@ class Module { inline IteratorRange debugs3(); inline IteratorRange debugs3() const; + // Iterators for debug info instructions (excluding OpLine & OpNoLine) + // contained in this module. These are OpExtInst for OpenCL.DebugInfo.100 + // or DebugInfo extension placed between section 9 and 10. + inline inst_iterator ext_inst_debuginfo_begin(); + inline inst_iterator ext_inst_debuginfo_end(); + inline IteratorRange ext_inst_debuginfo(); + inline IteratorRange ext_inst_debuginfo() const; + // Iterators for entry point instructions contained in this module inline IteratorRange entry_points(); inline IteratorRange entry_points() const; @@ -182,22 +204,6 @@ class Module { inline IteratorRange execution_modes(); inline IteratorRange execution_modes() const; - // Clears all debug instructions (excluding OpLine & OpNoLine). - void debug_clear() { - debug1_clear(); - debug2_clear(); - debug3_clear(); - } - - // Clears all debug 1 instructions (excluding OpLine & OpNoLine). - void debug1_clear() { debugs1_.clear(); } - - // Clears all debug 2 instructions (excluding OpLine & OpNoLine). - void debug2_clear() { debugs2_.clear(); } - - // Clears all debug 3 instructions (excluding OpLine & OpNoLine). - void debug3_clear() { debugs3_.clear(); } - // Iterators for annotation instructions contained in this module. inline inst_iterator annotation_begin(); inline inst_iterator annotation_end(); @@ -251,6 +257,19 @@ class Module { // Gets the associated context for this module IRContext* context() const { return context_; } + // Sets the trailing debug line info to |dbg_line_info|. + void SetTrailingDbgLineInfo(std::vector&& dbg_line_info) { + trailing_dbg_line_info_ = std::move(dbg_line_info); + } + + std::vector& trailing_dbg_line_info() { + return trailing_dbg_line_info_; + } + + const std::vector& trailing_dbg_line_info() const { + return trailing_dbg_line_info_; + } + private: ModuleHeader header_; // Module header @@ -267,10 +286,15 @@ class Module { InstructionList debugs1_; InstructionList debugs2_; InstructionList debugs3_; + InstructionList ext_inst_debuginfo_; InstructionList annotations_; // Type declarations, constants, and global variable declarations. InstructionList types_values_; std::vector> functions_; + + // If the module ends with Op*Line instruction, they will not be attached to + // any instruction. We record them here, so they will not be lost. + std::vector trailing_dbg_line_info_; }; // Pretty-prints |module| to |str|. Returns |str|. @@ -312,6 +336,10 @@ inline void Module::AddDebug3Inst(std::unique_ptr d) { debugs3_.push_back(std::move(d)); } +inline void Module::AddExtInstDebugInfo(std::unique_ptr d) { + ext_inst_debuginfo_.push_back(std::move(d)); +} + inline void Module::AddAnnotationInst(std::unique_ptr a) { annotations_.push_back(std::move(a)); } @@ -392,6 +420,22 @@ inline IteratorRange Module::debugs3() const { return make_range(debugs3_.begin(), debugs3_.end()); } +inline Module::inst_iterator Module::ext_inst_debuginfo_begin() { + return ext_inst_debuginfo_.begin(); +} +inline Module::inst_iterator Module::ext_inst_debuginfo_end() { + return ext_inst_debuginfo_.end(); +} + +inline IteratorRange Module::ext_inst_debuginfo() { + return make_range(ext_inst_debuginfo_.begin(), ext_inst_debuginfo_.end()); +} + +inline IteratorRange Module::ext_inst_debuginfo() + const { + return make_range(ext_inst_debuginfo_.begin(), ext_inst_debuginfo_.end()); +} + inline IteratorRange Module::entry_points() { return make_range(entry_points_.begin(), entry_points_.end()); } diff --git a/third_party/spirv-tools/source/opt/optimizer.cpp b/third_party/spirv-tools/source/opt/optimizer.cpp index 30654869c5..241aa75bef 100644 --- a/third_party/spirv-tools/source/opt/optimizer.cpp +++ b/third_party/spirv-tools/source/opt/optimizer.cpp @@ -14,6 +14,7 @@ #include "spirv-tools/optimizer.hpp" +#include #include #include #include @@ -21,12 +22,13 @@ #include #include "source/opt/build_module.h" +#include "source/opt/graphics_robust_access_pass.h" #include "source/opt/log.h" #include "source/opt/pass_manager.h" #include "source/opt/passes.h" -#include "source/opt/reduce_load_size.h" -#include "source/opt/simplification_pass.h" +#include "source/spirv_optimizer_options.h" #include "source/util/make_unique.h" +#include "source/util/string_utils.h" namespace spvtools { @@ -56,8 +58,8 @@ Optimizer::PassToken::~PassToken() {} struct Optimizer::Impl { explicit Impl(spv_target_env env) : target_env(env), pass_manager() {} - const spv_target_env target_env; // Target environment. - opt::PassManager pass_manager; // Internal implementation pass manager. + spv_target_env target_env; // Target environment. + opt::PassManager pass_manager; // Internal implementation pass manager. }; Optimizer::Optimizer(spv_target_env env) : impl_(new Impl(env)) {} @@ -106,8 +108,10 @@ Optimizer& Optimizer::RegisterPass(PassToken&& p) { // or enable more copy propagation. Optimizer& Optimizer::RegisterLegalizationPasses() { return - // Remove unreachable block so that merge return works. - RegisterPass(CreateDeadBranchElimPass()) + // Wrap OpKill instructions so all other code can be inlined. + RegisterPass(CreateWrapOpKillPass()) + // Remove unreachable block so that merge return works. + .RegisterPass(CreateDeadBranchElimPass()) // Merge the returns so we can inline. .RegisterPass(CreateMergeReturnPass()) // Make sure uses and definitions are in the same function. @@ -115,6 +119,10 @@ Optimizer& Optimizer::RegisterLegalizationPasses() { // Make private variable function scope .RegisterPass(CreateEliminateDeadFunctionsPass()) .RegisterPass(CreatePrivateToLocalPass()) + // Fix up the storage classes that DXC may have purposely generated + // incorrectly. All functions are inlined, and a lot of dead code has + // been removed. + .RegisterPass(CreateFixStorageClassPass()) // Propagate the value stored to the loads in very simple cases. .RegisterPass(CreateLocalSingleBlockLoadStoreElimPass()) .RegisterPass(CreateLocalSingleStoreElimPass()) @@ -131,6 +139,7 @@ Optimizer& Optimizer::RegisterLegalizationPasses() { // Propagate constants to get as many constant conditions on branches // as possible. .RegisterPass(CreateCCPPass()) + .RegisterPass(CreateLoopUnrollPass(true)) .RegisterPass(CreateDeadBranchElimPass()) // Copy propagate members. Cleans up code sequences generated by // scalar replacement. Also important for removing OpPhi nodes. @@ -148,7 +157,9 @@ Optimizer& Optimizer::RegisterLegalizationPasses() { } Optimizer& Optimizer::RegisterPerformancePasses() { - return RegisterPass(CreateMergeReturnPass()) + return RegisterPass(CreateWrapOpKillPass()) + .RegisterPass(CreateDeadBranchElimPass()) + .RegisterPass(CreateMergeReturnPass()) .RegisterPass(CreateInlineExhaustivePass()) .RegisterPass(CreateAggressiveDCEPass()) .RegisterPass(CreatePrivateToLocalPass()) @@ -180,37 +191,59 @@ Optimizer& Optimizer::RegisterPerformancePasses() { .RegisterPass(CreateDeadBranchElimPass()) .RegisterPass(CreateBlockMergePass()) .RegisterPass(CreateSimplificationPass()); - // Currently exposing driver bugs resulting in crashes (#946) - // .RegisterPass(CreateCommonUniformElimPass()) } Optimizer& Optimizer::RegisterSizePasses() { - return RegisterPass(CreateMergeReturnPass()) + return RegisterPass(CreateWrapOpKillPass()) + .RegisterPass(CreateDeadBranchElimPass()) + .RegisterPass(CreateMergeReturnPass()) .RegisterPass(CreateInlineExhaustivePass()) - .RegisterPass(CreateAggressiveDCEPass()) + .RegisterPass(CreateEliminateDeadFunctionsPass()) .RegisterPass(CreatePrivateToLocalPass()) - .RegisterPass(CreateScalarReplacementPass()) - .RegisterPass(CreateLocalAccessChainConvertPass()) - .RegisterPass(CreateLocalSingleBlockLoadStoreElimPass()) - .RegisterPass(CreateLocalSingleStoreElimPass()) - .RegisterPass(CreateAggressiveDCEPass()) - .RegisterPass(CreateSimplificationPass()) - .RegisterPass(CreateDeadInsertElimPass()) + .RegisterPass(CreateScalarReplacementPass(0)) .RegisterPass(CreateLocalMultiStoreElimPass()) - .RegisterPass(CreateAggressiveDCEPass()) .RegisterPass(CreateCCPPass()) + .RegisterPass(CreateLoopUnrollPass(true)) + .RegisterPass(CreateDeadBranchElimPass()) + .RegisterPass(CreateSimplificationPass()) + .RegisterPass(CreateScalarReplacementPass(0)) + .RegisterPass(CreateLocalSingleStoreElimPass()) + .RegisterPass(CreateIfConversionPass()) + .RegisterPass(CreateSimplificationPass()) .RegisterPass(CreateAggressiveDCEPass()) .RegisterPass(CreateDeadBranchElimPass()) - .RegisterPass(CreateIfConversionPass()) - .RegisterPass(CreateAggressiveDCEPass()) .RegisterPass(CreateBlockMergePass()) - .RegisterPass(CreateSimplificationPass()) + .RegisterPass(CreateLocalAccessChainConvertPass()) + .RegisterPass(CreateLocalSingleBlockLoadStoreElimPass()) + .RegisterPass(CreateAggressiveDCEPass()) + .RegisterPass(CreateCopyPropagateArraysPass()) + .RegisterPass(CreateVectorDCEPass()) .RegisterPass(CreateDeadInsertElimPass()) + .RegisterPass(CreateEliminateDeadMembersPass()) + .RegisterPass(CreateLocalSingleStoreElimPass()) + .RegisterPass(CreateBlockMergePass()) + .RegisterPass(CreateLocalMultiStoreElimPass()) .RegisterPass(CreateRedundancyEliminationPass()) - .RegisterPass(CreateCFGCleanupPass()) - // Currently exposing driver bugs resulting in crashes (#946) - // .RegisterPass(CreateCommonUniformElimPass()) - .RegisterPass(CreateAggressiveDCEPass()); + .RegisterPass(CreateSimplificationPass()) + .RegisterPass(CreateAggressiveDCEPass()) + .RegisterPass(CreateCFGCleanupPass()); +} + +Optimizer& Optimizer::RegisterVulkanToWebGPUPasses() { + return RegisterPass(CreateStripAtomicCounterMemoryPass()) + .RegisterPass(CreateGenerateWebGPUInitializersPass()) + .RegisterPass(CreateLegalizeVectorShufflePass()) + .RegisterPass(CreateSplitInvalidUnreachablePass()) + .RegisterPass(CreateEliminateDeadConstantPass()) + .RegisterPass(CreateFlattenDecorationPass()) + .RegisterPass(CreateAggressiveDCEPass()) + .RegisterPass(CreateDeadBranchElimPass()) + .RegisterPass(CreateCompactIdsPass()); +} + +Optimizer& Optimizer::RegisterWebGPUToVulkanPasses() { + return RegisterPass(CreateDecomposeInitializedVariablesPass()) + .RegisterPass(CreateCompactIdsPass()); } bool Optimizer::RegisterPassesFromFlags(const std::vector& flags) { @@ -223,29 +256,6 @@ bool Optimizer::RegisterPassesFromFlags(const std::vector& flags) { return true; } -namespace { - -// Splits the string |flag|, of the form '--pass_name[=pass_args]' into two -// strings "pass_name" and "pass_args". If |flag| has no arguments, the second -// string will be empty. -std::pair SplitFlagArgs(const std::string& flag) { - if (flag.size() < 2) return make_pair(flag, std::string()); - - // Detect the last dash before the pass name. Since we have to - // handle single dash options (-O and -Os), count up to two dashes. - size_t dash_ix = 0; - if (flag[0] == '-' && flag[1] == '-') - dash_ix = 2; - else if (flag[0] == '-') - dash_ix = 1; - - size_t ix = flag.find('='); - return (ix != std::string::npos) - ? make_pair(flag.substr(dash_ix, ix - 2), flag.substr(ix + 1)) - : make_pair(flag.substr(dash_ix), std::string()); -} -} // namespace - bool Optimizer::FlagHasValidForm(const std::string& flag) const { if (flag == "-O" || flag == "-Os") { return true; @@ -267,7 +277,7 @@ bool Optimizer::RegisterPassFromFlag(const std::string& flag) { } // Split flags of the form --pass_name=pass_args. - auto p = SplitFlagArgs(flag); + auto p = utils::SplitFlagArgs(flag); std::string pass_name = p.first; std::string pass_args = p.second; @@ -278,7 +288,9 @@ bool Optimizer::RegisterPassFromFlag(const std::string& flag) { // // Both Pass::name() and Pass::desc() should be static class members so they // can be invoked without creating a pass instance. - if (pass_name == "strip-debug") { + if (pass_name == "strip-atomic-counter-memory") { + RegisterPass(CreateStripAtomicCounterMemoryPass()); + } else if (pass_name == "strip-debug") { RegisterPass(CreateStripDebugInfoPass()); } else if (pass_name == "strip-reflect") { RegisterPass(CreateStripReflectInfoPass()); @@ -314,8 +326,14 @@ bool Optimizer::RegisterPassFromFlag(const std::string& flag) { RegisterPass(CreateCombineAccessChainsPass()); } else if (pass_name == "convert-local-access-chains") { RegisterPass(CreateLocalAccessChainConvertPass()); + } else if (pass_name == "descriptor-scalar-replacement") { + RegisterPass(CreateDescriptorScalarReplacementPass()); } else if (pass_name == "eliminate-dead-code-aggressive") { RegisterPass(CreateAggressiveDCEPass()); + } else if (pass_name == "propagate-line-info") { + RegisterPass(CreatePropagateLineInfoPass()); + } else if (pass_name == "eliminate-redundant-line-info") { + RegisterPass(CreateRedundantLineInfoElimPass()); } else if (pass_name == "eliminate-insert-extract") { RegisterPass(CreateInsertExtractElimPass()); } else if (pass_name == "eliminate-local-single-block") { @@ -332,14 +350,14 @@ bool Optimizer::RegisterPassFromFlag(const std::string& flag) { RegisterPass(CreateEliminateDeadFunctionsPass()); } else if (pass_name == "eliminate-local-multi-store") { RegisterPass(CreateLocalMultiStoreElimPass()); - } else if (pass_name == "eliminate-common-uniform") { - RegisterPass(CreateCommonUniformElimPass()); } else if (pass_name == "eliminate-dead-const") { RegisterPass(CreateEliminateDeadConstantPass()); } else if (pass_name == "eliminate-dead-inserts") { RegisterPass(CreateDeadInsertElimPass()); } else if (pass_name == "eliminate-dead-variables") { RegisterPass(CreateDeadVariableEliminationPass()); + } else if (pass_name == "eliminate-dead-members") { + RegisterPass(CreateEliminateDeadMembersPass()); } else if (pass_name == "fold-spec-const-op-composite") { RegisterPass(CreateFoldSpecConstantOpAndCompositePass()); } else if (pass_name == "loop-unswitch") { @@ -348,12 +366,16 @@ bool Optimizer::RegisterPassFromFlag(const std::string& flag) { if (pass_args.size() == 0) { RegisterPass(CreateScalarReplacementPass()); } else { - int limit = atoi(pass_args.c_str()); - if (limit > 0) { + int limit = -1; + if (pass_args.find_first_not_of("0123456789") == std::string::npos) { + limit = atoi(pass_args.c_str()); + } + + if (limit >= 0) { RegisterPass(CreateScalarReplacementPass(limit)); } else { Error(consumer(), nullptr, {}, - "--scalar-replacement must have no arguments or a positive " + "--scalar-replacement must have no arguments or a non-negative " "integer argument"); return false; } @@ -384,6 +406,25 @@ bool Optimizer::RegisterPassFromFlag(const std::string& flag) { RegisterPass(CreateWorkaround1209Pass()); } else if (pass_name == "replace-invalid-opcode") { RegisterPass(CreateReplaceInvalidOpcodePass()); + } else if (pass_name == "inst-bindless-check") { + RegisterPass(CreateInstBindlessCheckPass(7, 23, false, false, 2)); + RegisterPass(CreateSimplificationPass()); + RegisterPass(CreateDeadBranchElimPass()); + RegisterPass(CreateBlockMergePass()); + RegisterPass(CreateAggressiveDCEPass()); + } else if (pass_name == "inst-desc-idx-check") { + RegisterPass(CreateInstBindlessCheckPass(7, 23, true, true, 2)); + RegisterPass(CreateSimplificationPass()); + RegisterPass(CreateDeadBranchElimPass()); + RegisterPass(CreateBlockMergePass()); + RegisterPass(CreateAggressiveDCEPass()); + } else if (pass_name == "inst-buff-addr-check") { + RegisterPass(CreateInstBuffAddrCheckPass(7, 23, 2)); + RegisterPass(CreateAggressiveDCEPass()); + } else if (pass_name == "convert-relaxed-to-half") { + RegisterPass(CreateConvertRelaxedToHalfPass()); + } else if (pass_name == "relax-float-ops") { + RegisterPass(CreateRelaxFloatOpsPass()); } else if (pass_name == "simplify-instructions") { RegisterPass(CreateSimplificationPass()); } else if (pass_name == "ssa-rewrite") { @@ -414,6 +455,8 @@ bool Optimizer::RegisterPassFromFlag(const std::string& flag) { } } else if (pass_name == "loop-unroll") { RegisterPass(CreateLoopUnrollPass(true)); + } else if (pass_name == "upgrade-memory-model") { + RegisterPass(CreateUpgradeMemoryModelPass()); } else if (pass_name == "vector-dce") { RegisterPass(CreateVectorDCEPass()); } else if (pass_name == "loop-unroll-partial") { @@ -438,12 +481,30 @@ bool Optimizer::RegisterPassFromFlag(const std::string& flag) { } } else if (pass_name == "ccp") { RegisterPass(CreateCCPPass()); + } else if (pass_name == "code-sink") { + RegisterPass(CreateCodeSinkingPass()); + } else if (pass_name == "fix-storage-class") { + RegisterPass(CreateFixStorageClassPass()); } else if (pass_name == "O") { RegisterPerformancePasses(); } else if (pass_name == "Os") { RegisterSizePasses(); } else if (pass_name == "legalize-hlsl") { RegisterLegalizationPasses(); + } else if (pass_name == "generate-webgpu-initializers") { + RegisterPass(CreateGenerateWebGPUInitializersPass()); + } else if (pass_name == "legalize-vector-shuffle") { + RegisterPass(CreateLegalizeVectorShufflePass()); + } else if (pass_name == "split-invalid-unreachable") { + RegisterPass(CreateLegalizeVectorShufflePass()); + } else if (pass_name == "decompose-initialized-variables") { + RegisterPass(CreateDecomposeInitializedVariablesPass()); + } else if (pass_name == "graphics-robust-access") { + RegisterPass(CreateGraphicsRobustAccessPass()); + } else if (pass_name == "wrap-opkill") { + RegisterPass(CreateWrapOpKillPass()); + } else if (pass_name == "amd-ext-to-khr") { + RegisterPass(CreateAmdExtToKhrPass()); } else { Errorf(consumer(), nullptr, {}, "Unknown flag '--%s'. Use --help for a list of valid flags", @@ -454,22 +515,38 @@ bool Optimizer::RegisterPassFromFlag(const std::string& flag) { return true; } +void Optimizer::SetTargetEnv(const spv_target_env env) { + impl_->target_env = env; +} + bool Optimizer::Run(const uint32_t* original_binary, const size_t original_binary_size, std::vector* optimized_binary) const { return Run(original_binary, original_binary_size, optimized_binary, - ValidatorOptions()); + OptimizerOptions()); } bool Optimizer::Run(const uint32_t* original_binary, const size_t original_binary_size, std::vector* optimized_binary, - const ValidatorOptions& options, + const ValidatorOptions& validator_options, bool skip_validation) const { + OptimizerOptions opt_options; + opt_options.set_run_validator(!skip_validation); + opt_options.set_validator_options(validator_options); + return Run(original_binary, original_binary_size, optimized_binary, + opt_options); +} + +bool Optimizer::Run(const uint32_t* original_binary, + const size_t original_binary_size, + std::vector* optimized_binary, + const spv_optimizer_options opt_options) const { spvtools::SpirvTools tools(impl_->target_env); tools.SetMessageConsumer(impl_->pass_manager.consumer()); - if (!skip_validation && - !tools.Validate(original_binary, original_binary_size, options)) { + if (opt_options->run_validator_ && + !tools.Validate(original_binary, original_binary_size, + &opt_options->val_options_)) { return false; } @@ -477,16 +554,39 @@ bool Optimizer::Run(const uint32_t* original_binary, impl_->target_env, consumer(), original_binary, original_binary_size); if (context == nullptr) return false; + context->set_max_id_bound(opt_options->max_id_bound_); + context->set_preserve_bindings(opt_options->preserve_bindings_); + context->set_preserve_spec_constants(opt_options->preserve_spec_constants_); + + impl_->pass_manager.SetValidatorOptions(&opt_options->val_options_); + impl_->pass_manager.SetTargetEnv(impl_->target_env); auto status = impl_->pass_manager.Run(context.get()); - if (status == opt::Pass::Status::SuccessWithChange || - (status == opt::Pass::Status::SuccessWithoutChange && - (optimized_binary->data() != original_binary || - optimized_binary->size() != original_binary_size))) { - optimized_binary->clear(); - context->module()->ToBinary(optimized_binary, /* skip_nop = */ true); + + if (status == opt::Pass::Status::Failure) { + return false; } - return status != opt::Pass::Status::Failure; +#ifndef NDEBUG + if (status == opt::Pass::Status::SuccessWithoutChange) { + std::vector optimized_binary_with_nop; + context->module()->ToBinary(&optimized_binary_with_nop, + /* skip_nop = */ false); + assert(optimized_binary_with_nop.size() == original_binary_size && + "Binary size unexpectedly changed despite the optimizer saying " + "there was no change"); + assert(memcmp(optimized_binary_with_nop.data(), original_binary, + original_binary_size) == 0 && + "Binary content unexpectedly changed despite the optimizer saying " + "there was no change"); + } +#endif // !NDEBUG + + // Note that |original_binary| and |optimized_binary| may share the same + // buffer and the below will invalidate |original_binary|. + optimized_binary->clear(); + context->module()->ToBinary(optimized_binary, /* skip_nop = */ true); + + return true; } Optimizer& Optimizer::SetPrintAll(std::ostream* out) { @@ -499,10 +599,20 @@ Optimizer& Optimizer::SetTimeReport(std::ostream* out) { return *this; } +Optimizer& Optimizer::SetValidateAfterAll(bool validate) { + impl_->pass_manager.SetValidateAfterAll(validate); + return *this; +} + Optimizer::PassToken CreateNullPass() { return MakeUnique(MakeUnique()); } +Optimizer::PassToken CreateStripAtomicCounterMemoryPass() { + return MakeUnique( + MakeUnique()); +} + Optimizer::PassToken CreateStripDebugInfoPass() { return MakeUnique( MakeUnique()); @@ -518,6 +628,11 @@ Optimizer::PassToken CreateEliminateDeadFunctionsPass() { MakeUnique()); } +Optimizer::PassToken CreateEliminateDeadMembersPass() { + return MakeUnique( + MakeUnique()); +} + Optimizer::PassToken CreateSetSpecConstantDefaultValuePass( const std::unordered_map& id_value_map) { return MakeUnique( @@ -612,7 +727,7 @@ Optimizer::PassToken CreateDeadBranchElimPass() { Optimizer::PassToken CreateLocalMultiStoreElimPass() { return MakeUnique( - MakeUnique()); + MakeUnique()); } Optimizer::PassToken CreateAggressiveDCEPass() { @@ -620,9 +735,14 @@ Optimizer::PassToken CreateAggressiveDCEPass() { MakeUnique()); } -Optimizer::PassToken CreateCommonUniformElimPass() { +Optimizer::PassToken CreatePropagateLineInfoPass() { return MakeUnique( - MakeUnique()); + MakeUnique(opt::kLinesPropagateLines)); +} + +Optimizer::PassToken CreateRedundantLineInfoElimPass() { + return MakeUnique( + MakeUnique(opt::kLinesEliminateDeadLines)); } Optimizer::PassToken CreateCompactIdsPass() { @@ -749,4 +869,87 @@ Optimizer::PassToken CreateCombineAccessChainsPass() { return MakeUnique( MakeUnique()); } + +Optimizer::PassToken CreateUpgradeMemoryModelPass() { + return MakeUnique( + MakeUnique()); +} + +Optimizer::PassToken CreateInstBindlessCheckPass(uint32_t desc_set, + uint32_t shader_id, + bool input_length_enable, + bool input_init_enable, + uint32_t version) { + return MakeUnique( + MakeUnique(desc_set, shader_id, + input_length_enable, + input_init_enable, version)); +} + +Optimizer::PassToken CreateInstBuffAddrCheckPass(uint32_t desc_set, + uint32_t shader_id, + uint32_t version) { + return MakeUnique( + MakeUnique(desc_set, shader_id, version)); +} + +Optimizer::PassToken CreateConvertRelaxedToHalfPass() { + return MakeUnique( + MakeUnique()); +} + +Optimizer::PassToken CreateRelaxFloatOpsPass() { + return MakeUnique( + MakeUnique()); +} + +Optimizer::PassToken CreateCodeSinkingPass() { + return MakeUnique( + MakeUnique()); +} + +Optimizer::PassToken CreateGenerateWebGPUInitializersPass() { + return MakeUnique( + MakeUnique()); +} + +Optimizer::PassToken CreateFixStorageClassPass() { + return MakeUnique( + MakeUnique()); +} + +Optimizer::PassToken CreateLegalizeVectorShufflePass() { + return MakeUnique( + MakeUnique()); +} + +Optimizer::PassToken CreateDecomposeInitializedVariablesPass() { + return MakeUnique( + MakeUnique()); +} + +Optimizer::PassToken CreateSplitInvalidUnreachablePass() { + return MakeUnique( + MakeUnique()); +} + +Optimizer::PassToken CreateGraphicsRobustAccessPass() { + return MakeUnique( + MakeUnique()); +} + +Optimizer::PassToken CreateDescriptorScalarReplacementPass() { + return MakeUnique( + MakeUnique()); +} + +Optimizer::PassToken CreateWrapOpKillPass() { + return MakeUnique(MakeUnique()); +} + +Optimizer::PassToken CreateAmdExtToKhrPass() { + return MakeUnique( + MakeUnique()); +} + } // namespace spvtools diff --git a/third_party/spirv-tools/source/opt/pass.cpp b/third_party/spirv-tools/source/opt/pass.cpp index 4c4a232c6c..09b78af933 100644 --- a/third_party/spirv-tools/source/opt/pass.cpp +++ b/third_party/spirv-tools/source/opt/pass.cpp @@ -16,6 +16,7 @@ #include "source/opt/pass.h" +#include "source/opt/ir_builder.h" #include "source/opt/iterator.h" namespace spvtools { @@ -23,85 +24,12 @@ namespace opt { namespace { -const uint32_t kEntryPointFunctionIdInIdx = 1; const uint32_t kTypePointerTypeIdInIdx = 1; } // namespace Pass::Pass() : consumer_(nullptr), context_(nullptr), already_run_(false) {} -void Pass::AddCalls(Function* func, std::queue* todo) { - for (auto bi = func->begin(); bi != func->end(); ++bi) - for (auto ii = bi->begin(); ii != bi->end(); ++ii) - if (ii->opcode() == SpvOpFunctionCall) - todo->push(ii->GetSingleWordInOperand(0)); -} - -bool Pass::ProcessEntryPointCallTree(ProcessFunction& pfn, Module* module) { - // Map from function's result id to function - std::unordered_map id2function; - for (auto& fn : *module) id2function[fn.result_id()] = &fn; - - // Collect all of the entry points as the roots. - std::queue roots; - for (auto& e : module->entry_points()) - roots.push(e.GetSingleWordInOperand(kEntryPointFunctionIdInIdx)); - return ProcessCallTreeFromRoots(pfn, id2function, &roots); -} - -bool Pass::ProcessReachableCallTree(ProcessFunction& pfn, - IRContext* irContext) { - // Map from function's result id to function - std::unordered_map id2function; - for (auto& fn : *irContext->module()) id2function[fn.result_id()] = &fn; - - std::queue roots; - - // Add all entry points since they can be reached from outside the module. - for (auto& e : irContext->module()->entry_points()) - roots.push(e.GetSingleWordInOperand(kEntryPointFunctionIdInIdx)); - - // Add all exported functions since they can be reached from outside the - // module. - for (auto& a : irContext->annotations()) { - // TODO: Handle group decorations as well. Currently not generate by any - // front-end, but could be coming. - if (a.opcode() == SpvOp::SpvOpDecorate) { - if (a.GetSingleWordOperand(1) == - SpvDecoration::SpvDecorationLinkageAttributes) { - uint32_t lastOperand = a.NumOperands() - 1; - if (a.GetSingleWordOperand(lastOperand) == - SpvLinkageType::SpvLinkageTypeExport) { - uint32_t id = a.GetSingleWordOperand(0); - if (id2function.count(id) != 0) roots.push(id); - } - } - } - } - - return ProcessCallTreeFromRoots(pfn, id2function, &roots); -} - -bool Pass::ProcessCallTreeFromRoots( - ProcessFunction& pfn, - const std::unordered_map& id2function, - std::queue* roots) { - // Process call tree - bool modified = false; - std::unordered_set done; - - while (!roots->empty()) { - const uint32_t fi = roots->front(); - roots->pop(); - if (done.insert(fi).second) { - Function* fn = id2function.at(fi); - modified = pfn(fn) || modified; - AddCalls(fn, roots); - } - } - return modified; -} - Pass::Status Pass::Run(IRContext* ctx) { if (already_run_) { return Status::Failure; @@ -115,7 +43,8 @@ Pass::Status Pass::Run(IRContext* ctx) { if (status == Status::SuccessWithChange) { ctx->InvalidateAnalysesExceptFor(GetPreservedAnalyses()); } - assert(ctx->IsConsistent()); + assert((status == Status::Failure || ctx->IsConsistent()) && + "An analysis in the context is out of date."); return status; } @@ -125,5 +54,102 @@ uint32_t Pass::GetPointeeTypeId(const Instruction* ptrInst) const { return ptrTypeInst->GetSingleWordInOperand(kTypePointerTypeIdInIdx); } +Instruction* Pass::GetBaseType(uint32_t ty_id) { + Instruction* ty_inst = get_def_use_mgr()->GetDef(ty_id); + if (ty_inst->opcode() == SpvOpTypeMatrix) { + uint32_t vty_id = ty_inst->GetSingleWordInOperand(0); + ty_inst = get_def_use_mgr()->GetDef(vty_id); + } + if (ty_inst->opcode() == SpvOpTypeVector) { + uint32_t cty_id = ty_inst->GetSingleWordInOperand(0); + ty_inst = get_def_use_mgr()->GetDef(cty_id); + } + return ty_inst; +} + +bool Pass::IsFloat(uint32_t ty_id, uint32_t width) { + Instruction* ty_inst = GetBaseType(ty_id); + if (ty_inst->opcode() != SpvOpTypeFloat) return false; + return ty_inst->GetSingleWordInOperand(0) == width; +} + +uint32_t Pass::GetNullId(uint32_t type_id) { + if (IsFloat(type_id, 16)) context()->AddCapability(SpvCapabilityFloat16); + analysis::TypeManager* type_mgr = context()->get_type_mgr(); + analysis::ConstantManager* const_mgr = context()->get_constant_mgr(); + const analysis::Type* type = type_mgr->GetType(type_id); + const analysis::Constant* null_const = const_mgr->GetConstant(type, {}); + Instruction* null_inst = + const_mgr->GetDefiningInstruction(null_const, type_id); + return null_inst->result_id(); +} + +uint32_t Pass::GenerateCopy(Instruction* object_to_copy, uint32_t new_type_id, + Instruction* insertion_position) { + analysis::TypeManager* type_mgr = context()->get_type_mgr(); + analysis::ConstantManager* const_mgr = context()->get_constant_mgr(); + + uint32_t original_type_id = object_to_copy->type_id(); + if (original_type_id == new_type_id) { + return object_to_copy->result_id(); + } + + InstructionBuilder ir_builder( + context(), insertion_position, + IRContext::kAnalysisInstrToBlockMapping | IRContext::kAnalysisDefUse); + + analysis::Type* original_type = type_mgr->GetType(original_type_id); + analysis::Type* new_type = type_mgr->GetType(new_type_id); + + if (const analysis::Array* original_array_type = original_type->AsArray()) { + uint32_t original_element_type_id = + type_mgr->GetId(original_array_type->element_type()); + + analysis::Array* new_array_type = new_type->AsArray(); + assert(new_array_type != nullptr && "Can't copy an array to a non-array."); + uint32_t new_element_type_id = + type_mgr->GetId(new_array_type->element_type()); + + std::vector element_ids; + const analysis::Constant* length_const = + const_mgr->FindDeclaredConstant(original_array_type->LengthId()); + assert(length_const->AsIntConstant()); + uint32_t array_length = length_const->AsIntConstant()->GetU32(); + for (uint32_t i = 0; i < array_length; i++) { + Instruction* extract = ir_builder.AddCompositeExtract( + original_element_type_id, object_to_copy->result_id(), {i}); + element_ids.push_back( + GenerateCopy(extract, new_element_type_id, insertion_position)); + } + + return ir_builder.AddCompositeConstruct(new_type_id, element_ids) + ->result_id(); + } else if (const analysis::Struct* original_struct_type = + original_type->AsStruct()) { + analysis::Struct* new_struct_type = new_type->AsStruct(); + + const std::vector& original_types = + original_struct_type->element_types(); + const std::vector& new_types = + new_struct_type->element_types(); + std::vector element_ids; + for (uint32_t i = 0; i < original_types.size(); i++) { + Instruction* extract = ir_builder.AddCompositeExtract( + type_mgr->GetId(original_types[i]), object_to_copy->result_id(), {i}); + element_ids.push_back(GenerateCopy(extract, type_mgr->GetId(new_types[i]), + insertion_position)); + } + return ir_builder.AddCompositeConstruct(new_type_id, element_ids) + ->result_id(); + } else { + // If we do not have an aggregate type, then we have a problem. Either we + // found multiple instances of the same type, or we are copying to an + // incompatible type. Either way the code is illegal. + assert(false && + "Don't know how to copy this type. Code is likely illegal."); + } + return 0; +} + } // namespace opt } // namespace spvtools diff --git a/third_party/spirv-tools/source/opt/pass.h b/third_party/spirv-tools/source/opt/pass.h index df1745099d..a8c9c4b43c 100644 --- a/third_party/spirv-tools/source/opt/pass.h +++ b/third_party/spirv-tools/source/opt/pass.h @@ -17,7 +17,6 @@ #include #include -#include #include #include #include @@ -27,6 +26,7 @@ #include "source/opt/ir_context.h" #include "source/opt/module.h" #include "spirv-tools/libspirv.hpp" +#include "types.h" namespace spvtools { namespace opt { @@ -91,28 +91,6 @@ class Pass { // Returns a pointer to the CFG for current module. CFG* cfg() const { return context()->cfg(); } - // Add to |todo| all ids of functions called in |func|. - void AddCalls(Function* func, std::queue* todo); - - // Applies |pfn| to every function in the call trees that are rooted at the - // entry points. Returns true if any call |pfn| returns true. By convention - // |pfn| should return true if it modified the module. - bool ProcessEntryPointCallTree(ProcessFunction& pfn, Module* module); - - // Applies |pfn| to every function in the call trees rooted at the entry - // points and exported functions. Returns true if any call |pfn| returns - // true. By convention |pfn| should return true if it modified the module. - bool ProcessReachableCallTree(ProcessFunction& pfn, IRContext* irContext); - - // Applies |pfn| to every function in the call trees rooted at the elements of - // |roots|. Returns true if any call to |pfn| returns true. By convention - // |pfn| should return true if it modified the module. After returning - // |roots| will be empty. - bool ProcessCallTreeFromRoots( - ProcessFunction& pfn, - const std::unordered_map& id2function, - std::queue* roots); - // Run the pass on the given |module|. Returns Status::Failure if errors occur // when processing. Returns the corresponding Status::Success if processing is // successful to indicate whether changes are made to the module. If there @@ -131,6 +109,16 @@ class Pass { // Return type id for |ptrInst|'s pointee uint32_t GetPointeeTypeId(const Instruction* ptrInst) const; + // Return base type of |ty_id| type + Instruction* GetBaseType(uint32_t ty_id); + + // Return true if |inst| returns scalar, vector or matrix type with base + // float and |width| + bool IsFloat(uint32_t ty_id, uint32_t width); + + // Return the id of OpConstantNull of type |type_id|. Create if necessary. + uint32_t GetNullId(uint32_t type_id); + protected: // Constructs a new pass. // @@ -145,8 +133,15 @@ class Pass { virtual Status Process() = 0; // Return the next available SSA id and increment it. + // TODO(1841): Handle id overflow. uint32_t TakeNextId() { return context_->TakeNextId(); } + // Returns the id whose value is the same as |object_to_copy| except its type + // is |new_type_id|. Any instructions needed to generate this value will be + // inserted before |insertion_position|. + uint32_t GenerateCopy(Instruction* object_to_copy, uint32_t new_type_id, + Instruction* insertion_position); + private: MessageConsumer consumer_; // Message consumer. @@ -159,6 +154,10 @@ class Pass { bool already_run_; }; +inline Pass::Status CombineStatus(Pass::Status a, Pass::Status b) { + return std::min(a, b); +} + } // namespace opt } // namespace spvtools diff --git a/third_party/spirv-tools/source/opt/pass_manager.cpp b/third_party/spirv-tools/source/opt/pass_manager.cpp index fa1e1d8a81..be53d3440e 100644 --- a/third_party/spirv-tools/source/opt/pass_manager.cpp +++ b/third_party/spirv-tools/source/opt/pass_manager.cpp @@ -51,6 +51,20 @@ Pass::Status PassManager::Run(IRContext* context) { if (one_status == Pass::Status::Failure) return one_status; if (one_status == Pass::Status::SuccessWithChange) status = one_status; + if (validate_after_all_) { + spvtools::SpirvTools tools(target_env_); + tools.SetMessageConsumer(consumer()); + std::vector binary; + context->module()->ToBinary(&binary, true); + if (!tools.Validate(binary.data(), binary.size(), val_options_)) { + std::string msg = "Validation failed after pass "; + msg += pass->name(); + spv_position_t null_pos{0, 0, 0}; + consumer()(SPV_MSG_INTERNAL_ERROR, "", null_pos, msg.c_str()); + return Pass::Status::Failure; + } + } + // Reset the pass to free any memory used by the pass. pass.reset(nullptr); } diff --git a/third_party/spirv-tools/source/opt/pass_manager.h b/third_party/spirv-tools/source/opt/pass_manager.h index ed88aa17c8..9686dddc26 100644 --- a/third_party/spirv-tools/source/opt/pass_manager.h +++ b/third_party/spirv-tools/source/opt/pass_manager.h @@ -43,7 +43,10 @@ class PassManager { PassManager() : consumer_(nullptr), print_all_stream_(nullptr), - time_report_stream_(nullptr) {} + time_report_stream_(nullptr), + target_env_(SPV_ENV_UNIVERSAL_1_2), + val_options_(nullptr), + validate_after_all_(false) {} // Sets the message consumer to the given |consumer|. void SetMessageConsumer(MessageConsumer c) { consumer_ = std::move(c); } @@ -89,6 +92,24 @@ class PassManager { return *this; } + // Sets the target environment for validation. + PassManager& SetTargetEnv(spv_target_env env) { + target_env_ = env; + return *this; + } + + // Sets the validation options. + PassManager& SetValidatorOptions(spv_validator_options options) { + val_options_ = options; + return *this; + } + + // Sets the option to validate after each pass. + PassManager& SetValidateAfterAll(bool validate) { + validate_after_all_ = validate; + return *this; + } + private: // Consumer for messages. MessageConsumer consumer_; @@ -100,6 +121,12 @@ class PassManager { // The output stream to write the resource utilization of each pass. If this // is null, no output is generated. std::ostream* time_report_stream_; + // The target environment. + spv_target_env target_env_; + // The validator options (used when validating each pass). + spv_validator_options val_options_; + // Controls whether validation occurs after every pass. + bool validate_after_all_; }; inline void PassManager::AddPass(std::unique_ptr pass) { diff --git a/third_party/spirv-tools/source/opt/passes.h b/third_party/spirv-tools/source/opt/passes.h index 42106c8f7b..1a3675c776 100644 --- a/third_party/spirv-tools/source/opt/passes.h +++ b/third_party/spirv-tools/source/opt/passes.h @@ -18,30 +18,40 @@ // A single header to include all passes. #include "source/opt/aggressive_dead_code_elim_pass.h" +#include "source/opt/amd_ext_to_khr.h" #include "source/opt/block_merge_pass.h" #include "source/opt/ccp_pass.h" #include "source/opt/cfg_cleanup_pass.h" +#include "source/opt/code_sink.h" #include "source/opt/combine_access_chains.h" -#include "source/opt/common_uniform_elim_pass.h" #include "source/opt/compact_ids_pass.h" +#include "source/opt/convert_to_half_pass.h" #include "source/opt/copy_prop_arrays.h" #include "source/opt/dead_branch_elim_pass.h" #include "source/opt/dead_insert_elim_pass.h" #include "source/opt/dead_variable_elimination.h" +#include "source/opt/decompose_initialized_variables_pass.h" +#include "source/opt/desc_sroa.h" #include "source/opt/eliminate_dead_constant_pass.h" #include "source/opt/eliminate_dead_functions_pass.h" +#include "source/opt/eliminate_dead_members_pass.h" +#include "source/opt/fix_storage_class.h" #include "source/opt/flatten_decoration_pass.h" #include "source/opt/fold_spec_constant_op_and_composite_pass.h" #include "source/opt/freeze_spec_constant_value_pass.h" +#include "source/opt/generate_webgpu_initializers_pass.h" +#include "source/opt/graphics_robust_access_pass.h" #include "source/opt/if_conversion.h" #include "source/opt/inline_exhaustive_pass.h" #include "source/opt/inline_opaque_pass.h" +#include "source/opt/inst_bindless_check_pass.h" +#include "source/opt/inst_buff_addr_check_pass.h" +#include "source/opt/legalize_vector_shuffle_pass.h" #include "source/opt/licm_pass.h" #include "source/opt/local_access_chain_convert_pass.h" #include "source/opt/local_redundancy_elimination.h" #include "source/opt/local_single_block_elim_pass.h" #include "source/opt/local_single_store_elim_pass.h" -#include "source/opt/local_ssa_elim_pass.h" #include "source/opt/loop_fission.h" #include "source/opt/loop_fusion_pass.h" #include "source/opt/loop_peeling.h" @@ -50,18 +60,25 @@ #include "source/opt/merge_return_pass.h" #include "source/opt/null_pass.h" #include "source/opt/private_to_local_pass.h" +#include "source/opt/process_lines_pass.h" #include "source/opt/reduce_load_size.h" #include "source/opt/redundancy_elimination.h" +#include "source/opt/relax_float_ops_pass.h" #include "source/opt/remove_duplicates_pass.h" #include "source/opt/replace_invalid_opc.h" #include "source/opt/scalar_replacement_pass.h" #include "source/opt/set_spec_constant_default_value_pass.h" +#include "source/opt/simplification_pass.h" +#include "source/opt/split_invalid_unreachable_pass.h" #include "source/opt/ssa_rewrite_pass.h" #include "source/opt/strength_reduction_pass.h" +#include "source/opt/strip_atomic_counter_memory_pass.h" #include "source/opt/strip_debug_info_pass.h" #include "source/opt/strip_reflect_info_pass.h" #include "source/opt/unify_const_pass.h" +#include "source/opt/upgrade_memory_model.h" #include "source/opt/vector_dce.h" #include "source/opt/workaround1209.h" +#include "source/opt/wrap_opkill.h" #endif // SOURCE_OPT_PASSES_H_ diff --git a/third_party/spirv-tools/source/opt/pch_source_opt.cpp b/third_party/spirv-tools/source/opt/pch_source_opt.cpp new file mode 100644 index 0000000000..f45448dc56 --- /dev/null +++ b/third_party/spirv-tools/source/opt/pch_source_opt.cpp @@ -0,0 +1,15 @@ +// Copyright (c) 2018 The Khronos Group Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "pch_source_opt.h" diff --git a/third_party/spirv-tools/source/opt/pch_source_opt.h b/third_party/spirv-tools/source/opt/pch_source_opt.h new file mode 100644 index 0000000000..73566510e6 --- /dev/null +++ b/third_party/spirv-tools/source/opt/pch_source_opt.h @@ -0,0 +1,32 @@ +// Copyright (c) 2018 The Khronos Group Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "source/opt/basic_block.h" +#include "source/opt/decoration_manager.h" +#include "source/opt/def_use_manager.h" +#include "source/opt/ir_context.h" +#include "source/opt/mem_pass.h" +#include "source/opt/module.h" +#include "source/opt/pass.h" +#include "source/util/hex_float.h" +#include "source/util/make_unique.h" diff --git a/third_party/spirv-tools/source/opt/private_to_local_pass.cpp b/third_party/spirv-tools/source/opt/private_to_local_pass.cpp index 02909a72b5..6df690dc07 100644 --- a/third_party/spirv-tools/source/opt/private_to_local_pass.cpp +++ b/third_party/spirv-tools/source/opt/private_to_local_pass.cpp @@ -19,6 +19,7 @@ #include #include "source/opt/ir_context.h" +#include "source/spirv_constant.h" namespace spvtools { namespace opt { @@ -38,6 +39,7 @@ Pass::Status PrivateToLocalPass::Process() { return Status::SuccessWithoutChange; std::vector> variables_to_move; + std::unordered_set localized_variables; for (auto& inst : context()->types_values()) { if (inst.opcode() != SpvOpVariable) { continue; @@ -56,7 +58,30 @@ Pass::Status PrivateToLocalPass::Process() { modified = !variables_to_move.empty(); for (auto p : variables_to_move) { - MoveVariable(p.first, p.second); + if (!MoveVariable(p.first, p.second)) { + return Status::Failure; + } + localized_variables.insert(p.first->result_id()); + } + + if (get_module()->version() >= SPV_SPIRV_VERSION_WORD(1, 4)) { + // In SPIR-V 1.4 and later entry points must list private storage class + // variables that are statically used by the entry point. Go through the + // entry points and remove any references to variables that were localized. + for (auto& entry : get_module()->entry_points()) { + std::vector new_operands; + for (uint32_t i = 0; i < entry.NumInOperands(); ++i) { + // Execution model, function id and name are always kept. + if (i < 3 || + !localized_variables.count(entry.GetSingleWordInOperand(i))) { + new_operands.push_back(entry.GetInOperand(i)); + } + } + if (new_operands.size() != entry.NumInOperands()) { + entry.SetInOperands(std::move(new_operands)); + context()->AnalyzeUses(&entry); + } + } } return (modified ? Status::SuccessWithChange : Status::SuccessWithoutChange); @@ -89,7 +114,7 @@ Function* PrivateToLocalPass::FindLocalFunction(const Instruction& inst) const { return target_function; } // namespace opt -void PrivateToLocalPass::MoveVariable(Instruction* variable, +bool PrivateToLocalPass::MoveVariable(Instruction* variable, Function* function) { // The variable needs to be removed from the global section, and placed in the // header of the function. First step remove from the global list. @@ -102,6 +127,9 @@ void PrivateToLocalPass::MoveVariable(Instruction* variable, // Update the type as well. uint32_t new_type_id = GetNewType(variable->type_id()); + if (new_type_id == 0) { + return false; + } variable->SetResultType(new_type_id); // Place the variable at the start of the first basic block. @@ -110,7 +138,7 @@ void PrivateToLocalPass::MoveVariable(Instruction* variable, function->begin()->begin()->InsertBefore(move(var)); // Update uses where the type may have changed. - UpdateUses(variable->result_id()); + return UpdateUses(variable->result_id()); } uint32_t PrivateToLocalPass::GetNewType(uint32_t old_type_id) { @@ -120,7 +148,9 @@ uint32_t PrivateToLocalPass::GetNewType(uint32_t old_type_id) { old_type_inst->GetSingleWordInOperand(kSpvTypePointerTypeIdInIdx); uint32_t new_type_id = type_mgr->FindPointerToType(pointee_type_id, SpvStorageClassFunction); - context()->UpdateDefUse(context()->get_def_use_mgr()->GetDef(new_type_id)); + if (new_type_id != 0) { + context()->UpdateDefUse(context()->get_def_use_mgr()->GetDef(new_type_id)); + } return new_type_id; } @@ -145,7 +175,7 @@ bool PrivateToLocalPass::IsValidUse(const Instruction* inst) const { } } -void PrivateToLocalPass::UpdateUse(Instruction* inst) { +bool PrivateToLocalPass::UpdateUse(Instruction* inst) { // The cases in this switch have to match the cases in |IsValidUse|. If we // don't think it is valid, the optimization will not view the variable as a // candidate, and therefore the use will not be updated. @@ -156,30 +186,42 @@ void PrivateToLocalPass::UpdateUse(Instruction* inst) { // The type is fine because it is the type pointed to, and that does not // change. break; - case SpvOpAccessChain: + case SpvOpAccessChain: { context()->ForgetUses(inst); - inst->SetResultType(GetNewType(inst->type_id())); + uint32_t new_type_id = GetNewType(inst->type_id()); + if (new_type_id == 0) { + return false; + } + inst->SetResultType(new_type_id); context()->AnalyzeUses(inst); // Update uses where the type may have changed. - UpdateUses(inst->result_id()); - break; + if (!UpdateUses(inst->result_id())) { + return false; + } + } break; case SpvOpName: + case SpvOpEntryPoint: // entry points will be updated separately. break; default: assert(spvOpcodeIsDecoration(inst->opcode()) && "Do not know how to update the type for this instruction."); break; } + return true; } -void PrivateToLocalPass::UpdateUses(uint32_t id) { + +bool PrivateToLocalPass::UpdateUses(uint32_t id) { std::vector uses; context()->get_def_use_mgr()->ForEachUser( id, [&uses](Instruction* use) { uses.push_back(use); }); for (Instruction* use : uses) { - UpdateUse(use); + if (!UpdateUse(use)) { + return false; + } } + return true; } } // namespace opt diff --git a/third_party/spirv-tools/source/opt/private_to_local_pass.h b/third_party/spirv-tools/source/opt/private_to_local_pass.h index f706e6e91a..3f9135c091 100644 --- a/third_party/spirv-tools/source/opt/private_to_local_pass.h +++ b/third_party/spirv-tools/source/opt/private_to_local_pass.h @@ -35,13 +35,14 @@ class PrivateToLocalPass : public Pass { IRContext::kAnalysisInstrToBlockMapping | IRContext::kAnalysisDecorations | IRContext::kAnalysisCombinators | IRContext::kAnalysisCFG | IRContext::kAnalysisDominatorAnalysis | - IRContext::kAnalysisNameMap; + IRContext::kAnalysisNameMap | IRContext::kAnalysisConstants | + IRContext::kAnalysisTypes; } private: // Moves |variable| from the private storage class to the function storage - // class of |function|. - void MoveVariable(Instruction* variable, Function* function); + // class of |function|. Returns false if the variable could not be moved. + bool MoveVariable(Instruction* variable, Function* function); // |inst| is an instruction declaring a varible. If that variable is // referenced in a single function and all of uses are valid as defined by @@ -57,13 +58,13 @@ class PrivateToLocalPass : public Pass { // Given the result id of a pointer type, |old_type_id|, this function // returns the id of a the same pointer type except the storage class has // been changed to function. If the type does not already exist, it will be - // created. + // created. Returns 0 if the new type could not be found or generated. uint32_t GetNewType(uint32_t old_type_id); // Updates |inst|, and any instruction dependent on |inst|, to reflect the // change of the base pointer now pointing to the function storage class. - void UpdateUse(Instruction* inst); - void UpdateUses(uint32_t id); + bool UpdateUse(Instruction* inst); + bool UpdateUses(uint32_t id); }; } // namespace opt diff --git a/third_party/spirv-tools/source/opt/process_lines_pass.cpp b/third_party/spirv-tools/source/opt/process_lines_pass.cpp new file mode 100644 index 0000000000..0ae2f75837 --- /dev/null +++ b/third_party/spirv-tools/source/opt/process_lines_pass.cpp @@ -0,0 +1,157 @@ +// Copyright (c) 2018 The Khronos Group Inc. +// Copyright (c) 2018 Valve Corporation +// Copyright (c) 2018 LunarG Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/opt/process_lines_pass.h" + +#include +#include +#include + +namespace { + +// Input Operand Indices +static const int kSpvLineFileInIdx = 0; +static const int kSpvLineLineInIdx = 1; +static const int kSpvLineColInIdx = 2; + +} // anonymous namespace + +namespace spvtools { +namespace opt { + +Pass::Status ProcessLinesPass::Process() { + bool modified = ProcessLines(); + return (modified ? Status::SuccessWithChange : Status::SuccessWithoutChange); +} + +bool ProcessLinesPass::ProcessLines() { + bool modified = false; + uint32_t file_id = 0; + uint32_t line = 0; + uint32_t col = 0; + // Process types, globals, constants + for (Instruction& inst : get_module()->types_values()) + modified |= line_process_func_(&inst, &file_id, &line, &col); + // Process functions + for (Function& function : *get_module()) { + modified |= line_process_func_(&function.DefInst(), &file_id, &line, &col); + function.ForEachParam( + [this, &modified, &file_id, &line, &col](Instruction* param) { + modified |= line_process_func_(param, &file_id, &line, &col); + }); + for (BasicBlock& block : function) { + modified |= + line_process_func_(block.GetLabelInst(), &file_id, &line, &col); + for (Instruction& inst : block) { + modified |= line_process_func_(&inst, &file_id, &line, &col); + // Don't process terminal instruction if preceeded by merge + if (inst.opcode() == SpvOpSelectionMerge || + inst.opcode() == SpvOpLoopMerge) + break; + } + // Nullify line info after each block. + file_id = 0; + } + modified |= line_process_func_(function.EndInst(), &file_id, &line, &col); + } + return modified; +} + +bool ProcessLinesPass::PropagateLine(Instruction* inst, uint32_t* file_id, + uint32_t* line, uint32_t* col) { + bool modified = false; + // only the last debug instruction needs to be considered + auto line_itr = inst->dbg_line_insts().rbegin(); + // if no line instructions, propagate previous info + if (line_itr == inst->dbg_line_insts().rend()) { + // if no current line info, add OpNoLine, else OpLine + if (*file_id == 0) + inst->dbg_line_insts().push_back(Instruction(context(), SpvOpNoLine)); + else + inst->dbg_line_insts().push_back(Instruction( + context(), SpvOpLine, 0, 0, + {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {*file_id}}, + {spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, {*line}}, + {spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, {*col}}})); + modified = true; + } else { + // else pre-existing line instruction, so update source line info + if (line_itr->opcode() == SpvOpNoLine) { + *file_id = 0; + } else { + assert(line_itr->opcode() == SpvOpLine && "unexpected debug inst"); + *file_id = line_itr->GetSingleWordInOperand(kSpvLineFileInIdx); + *line = line_itr->GetSingleWordInOperand(kSpvLineLineInIdx); + *col = line_itr->GetSingleWordInOperand(kSpvLineColInIdx); + } + } + return modified; +} + +bool ProcessLinesPass::EliminateDeadLines(Instruction* inst, uint32_t* file_id, + uint32_t* line, uint32_t* col) { + // If no debug line instructions, return without modifying lines + if (inst->dbg_line_insts().empty()) return false; + // Only the last debug instruction needs to be considered; delete all others + bool modified = inst->dbg_line_insts().size() > 1; + Instruction last_inst = inst->dbg_line_insts().back(); + inst->dbg_line_insts().clear(); + // If last line is OpNoLine + if (last_inst.opcode() == SpvOpNoLine) { + // If no propagated line info, throw away redundant OpNoLine + if (*file_id == 0) { + modified = true; + // Else replace OpNoLine and propagate no line info + } else { + inst->dbg_line_insts().push_back(last_inst); + *file_id = 0; + } + } else { + // Else last line is OpLine + assert(last_inst.opcode() == SpvOpLine && "unexpected debug inst"); + // If propagated info matches last line, throw away last line + if (*file_id == last_inst.GetSingleWordInOperand(kSpvLineFileInIdx) && + *line == last_inst.GetSingleWordInOperand(kSpvLineLineInIdx) && + *col == last_inst.GetSingleWordInOperand(kSpvLineColInIdx)) { + modified = true; + } else { + // Else replace last line and propagate line info + *file_id = last_inst.GetSingleWordInOperand(kSpvLineFileInIdx); + *line = last_inst.GetSingleWordInOperand(kSpvLineLineInIdx); + *col = last_inst.GetSingleWordInOperand(kSpvLineColInIdx); + inst->dbg_line_insts().push_back(last_inst); + } + } + return modified; +} + +ProcessLinesPass::ProcessLinesPass(uint32_t func_id) { + if (func_id == kLinesPropagateLines) { + line_process_func_ = [this](Instruction* inst, uint32_t* file_id, + uint32_t* line, uint32_t* col) { + return PropagateLine(inst, file_id, line, col); + }; + } else { + assert(func_id == kLinesEliminateDeadLines && "unknown Lines param"); + line_process_func_ = [this](Instruction* inst, uint32_t* file_id, + uint32_t* line, uint32_t* col) { + return EliminateDeadLines(inst, file_id, line, col); + }; + } +} + +} // namespace opt +} // namespace spvtools diff --git a/third_party/spirv-tools/source/opt/process_lines_pass.h b/third_party/spirv-tools/source/opt/process_lines_pass.h new file mode 100644 index 0000000000..c988bfd0d8 --- /dev/null +++ b/third_party/spirv-tools/source/opt/process_lines_pass.h @@ -0,0 +1,87 @@ +// Copyright (c) 2018 The Khronos Group Inc. +// Copyright (c) 2018 Valve Corporation +// Copyright (c) 2018 LunarG Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_OPT_PROPAGATE_LINES_PASS_H_ +#define SOURCE_OPT_PROPAGATE_LINES_PASS_H_ + +#include "source/opt/function.h" +#include "source/opt/ir_context.h" +#include "source/opt/pass.h" + +namespace spvtools { +namespace opt { + +namespace { + +// Constructor Parameters +static const int kLinesPropagateLines = 0; +static const int kLinesEliminateDeadLines = 1; + +} // anonymous namespace + +// See optimizer.hpp for documentation. +class ProcessLinesPass : public Pass { + using LineProcessFunction = + std::function; + + public: + ProcessLinesPass(uint32_t func_id); + ~ProcessLinesPass() override = default; + + const char* name() const override { return "propagate-lines"; } + + // See optimizer.hpp for this pass' user documentation. + Status Process() override; + + IRContext::Analysis GetPreservedAnalyses() override { + return IRContext::kAnalysisDefUse | + IRContext::kAnalysisInstrToBlockMapping | + IRContext::kAnalysisDecorations | IRContext::kAnalysisCombinators | + IRContext::kAnalysisCFG | IRContext::kAnalysisDominatorAnalysis | + IRContext::kAnalysisNameMap | IRContext::kAnalysisConstants | + IRContext::kAnalysisTypes; + } + + private: + // If |inst| has no debug line instruction, create one with + // |file_id, line, col|. If |inst| has debug line instructions, set + // |file_id, line, col| from the last. |file_id| equals 0 indicates no line + // info is available. Return true if |inst| modified. + bool PropagateLine(Instruction* inst, uint32_t* file_id, uint32_t* line, + uint32_t* col); + + // If last debug line instruction of |inst| matches |file_id, line, col|, + // delete all debug line instructions of |inst|. If they do not match, + // replace all debug line instructions of |inst| with new line instruction + // set from |file_id, line, col|. If |inst| has no debug line instructions, + // do not modify |inst|. |file_id| equals 0 indicates no line info is + // available. Return true if |inst| modified. + bool EliminateDeadLines(Instruction* inst, uint32_t* file_id, uint32_t* line, + uint32_t* col); + + // Apply lpfn() to all type, constant, global variable and function + // instructions in their physical order. + bool ProcessLines(); + + // A function that calls either PropagateLine or EliminateDeadLines. + // Initialized by the class constructor. + LineProcessFunction line_process_func_; +}; + +} // namespace opt +} // namespace spvtools + +#endif // SOURCE_OPT_PROPAGATE_LINES_PASS_H_ diff --git a/third_party/spirv-tools/source/opt/reduce_load_size.cpp b/third_party/spirv-tools/source/opt/reduce_load_size.cpp index b692c6b544..7b5a015c4b 100644 --- a/third_party/spirv-tools/source/opt/reduce_load_size.cpp +++ b/third_party/spirv-tools/source/opt/reduce_load_size.cpp @@ -139,7 +139,8 @@ bool ReduceLoadSize::ShouldReplaceExtract(Instruction* inst) { all_elements_used = !def_use_mgr->WhileEachUser(op_inst, [&elements_used](Instruction* use) { - if (use->opcode() != SpvOpCompositeExtract) { + if (use->opcode() != SpvOpCompositeExtract || + use->NumInOperands() == 1) { return false; } elements_used.insert(use->GetSingleWordInOperand(1)); diff --git a/third_party/spirv-tools/source/opt/reduce_load_size.h b/third_party/spirv-tools/source/opt/reduce_load_size.h index 724a430bbf..ccac49be6d 100644 --- a/third_party/spirv-tools/source/opt/reduce_load_size.h +++ b/third_party/spirv-tools/source/opt/reduce_load_size.h @@ -36,7 +36,8 @@ class ReduceLoadSize : public Pass { IRContext::kAnalysisInstrToBlockMapping | IRContext::kAnalysisCombinators | IRContext::kAnalysisCFG | IRContext::kAnalysisDominatorAnalysis | - IRContext::kAnalysisLoopAnalysis | IRContext::kAnalysisNameMap; + IRContext::kAnalysisLoopAnalysis | IRContext::kAnalysisNameMap | + IRContext::kAnalysisConstants | IRContext::kAnalysisTypes; } private: diff --git a/third_party/spirv-tools/source/opt/reflect.h b/third_party/spirv-tools/source/opt/reflect.h index fb2de7b151..8106442881 100644 --- a/third_party/spirv-tools/source/opt/reflect.h +++ b/third_party/spirv-tools/source/opt/reflect.h @@ -44,7 +44,9 @@ inline bool IsAnnotationInst(SpvOp opcode) { } inline bool IsTypeInst(SpvOp opcode) { return (opcode >= SpvOpTypeVoid && opcode <= SpvOpTypeForwardPointer) || - opcode == SpvOpTypePipeStorage || opcode == SpvOpTypeNamedBarrier; + opcode == SpvOpTypePipeStorage || opcode == SpvOpTypeNamedBarrier || + opcode == SpvOpTypeAccelerationStructureNV || + opcode == SpvOpTypeCooperativeMatrixNV; } inline bool IsConstantInst(SpvOp opcode) { return opcode >= SpvOpConstantTrue && opcode <= SpvOpSpecConstantOp; diff --git a/third_party/spirv-tools/source/opt/register_pressure.cpp b/third_party/spirv-tools/source/opt/register_pressure.cpp index 34dac1d7b1..cb2467441d 100644 --- a/third_party/spirv-tools/source/opt/register_pressure.cpp +++ b/third_party/spirv-tools/source/opt/register_pressure.cpp @@ -78,9 +78,16 @@ class ComputeRegisterLiveness { // - Second, walk loop forest to propagate registers crossing back-edges // (add iterative values into the liveness set). void Compute() { - cfg_.ForEachBlockInPostOrder(&*function_->begin(), [this](BasicBlock* bb) { - ComputePartialLiveness(bb); - }); + for (BasicBlock& start_bb : *function_) { + if (reg_pressure_->Get(start_bb.id()) != nullptr) { + continue; + } + cfg_.ForEachBlockInPostOrder(&start_bb, [this](BasicBlock* bb) { + if (reg_pressure_->Get(bb->id()) == nullptr) { + ComputePartialLiveness(bb); + } + }); + } DoLoopLivenessUnification(); EvaluateRegisterRequirements(); } diff --git a/third_party/spirv-tools/source/opt/relax_float_ops_pass.cpp b/third_party/spirv-tools/source/opt/relax_float_ops_pass.cpp new file mode 100644 index 0000000000..73f16ddf3f --- /dev/null +++ b/third_party/spirv-tools/source/opt/relax_float_ops_pass.cpp @@ -0,0 +1,178 @@ +// Copyright (c) 2019 The Khronos Group Inc. +// Copyright (c) 2019 Valve Corporation +// Copyright (c) 2019 LunarG Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "relax_float_ops_pass.h" + +#include "source/opt/ir_builder.h" + +namespace spvtools { +namespace opt { + +bool RelaxFloatOpsPass::IsRelaxable(Instruction* inst) { + return target_ops_core_f_rslt_.count(inst->opcode()) != 0 || + target_ops_core_f_opnd_.count(inst->opcode()) != 0 || + sample_ops_.count(inst->opcode()) != 0 || + (inst->opcode() == SpvOpExtInst && + inst->GetSingleWordInOperand(0) == + context()->get_feature_mgr()->GetExtInstImportId_GLSLstd450() && + target_ops_450_.count(inst->GetSingleWordInOperand(1)) != 0); +} + +bool RelaxFloatOpsPass::IsFloat32(Instruction* inst) { + uint32_t ty_id; + if (target_ops_core_f_opnd_.count(inst->opcode()) != 0) { + uint32_t opnd_id = inst->GetSingleWordInOperand(0); + Instruction* opnd_inst = get_def_use_mgr()->GetDef(opnd_id); + ty_id = opnd_inst->type_id(); + } else { + ty_id = inst->type_id(); + if (ty_id == 0) return false; + } + return IsFloat(ty_id, 32); +} + +bool RelaxFloatOpsPass::IsRelaxed(uint32_t r_id) { + for (auto r_inst : get_decoration_mgr()->GetDecorationsFor(r_id, false)) + if (r_inst->opcode() == SpvOpDecorate && + r_inst->GetSingleWordInOperand(1) == SpvDecorationRelaxedPrecision) + return true; + return false; +} + +bool RelaxFloatOpsPass::ProcessInst(Instruction* r_inst) { + uint32_t r_id = r_inst->result_id(); + if (r_id == 0) return false; + if (!IsFloat32(r_inst)) return false; + if (IsRelaxed(r_id)) return false; + if (!IsRelaxable(r_inst)) return false; + get_decoration_mgr()->AddDecoration(r_id, SpvDecorationRelaxedPrecision); + return true; +} + +bool RelaxFloatOpsPass::ProcessFunction(Function* func) { + bool modified = false; + cfg()->ForEachBlockInReversePostOrder( + func->entry().get(), [&modified, this](BasicBlock* bb) { + for (auto ii = bb->begin(); ii != bb->end(); ++ii) + modified |= ProcessInst(&*ii); + }); + return modified; +} + +Pass::Status RelaxFloatOpsPass::ProcessImpl() { + Pass::ProcessFunction pfn = [this](Function* fp) { + return ProcessFunction(fp); + }; + bool modified = context()->ProcessEntryPointCallTree(pfn); + return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange; +} + +Pass::Status RelaxFloatOpsPass::Process() { + Initialize(); + return ProcessImpl(); +} + +void RelaxFloatOpsPass::Initialize() { + target_ops_core_f_rslt_ = { + SpvOpLoad, + SpvOpPhi, + SpvOpVectorExtractDynamic, + SpvOpVectorInsertDynamic, + SpvOpVectorShuffle, + SpvOpCompositeExtract, + SpvOpCompositeConstruct, + SpvOpCompositeInsert, + SpvOpCopyObject, + SpvOpTranspose, + SpvOpConvertSToF, + SpvOpConvertUToF, + SpvOpFConvert, + // SpvOpQuantizeToF16, + SpvOpFNegate, + SpvOpFAdd, + SpvOpFSub, + SpvOpFMul, + SpvOpFDiv, + SpvOpFMod, + SpvOpVectorTimesScalar, + SpvOpMatrixTimesScalar, + SpvOpVectorTimesMatrix, + SpvOpMatrixTimesVector, + SpvOpMatrixTimesMatrix, + SpvOpOuterProduct, + SpvOpDot, + SpvOpSelect, + }; + target_ops_core_f_opnd_ = { + SpvOpFOrdEqual, + SpvOpFUnordEqual, + SpvOpFOrdNotEqual, + SpvOpFUnordNotEqual, + SpvOpFOrdLessThan, + SpvOpFUnordLessThan, + SpvOpFOrdGreaterThan, + SpvOpFUnordGreaterThan, + SpvOpFOrdLessThanEqual, + SpvOpFUnordLessThanEqual, + SpvOpFOrdGreaterThanEqual, + SpvOpFUnordGreaterThanEqual, + }; + target_ops_450_ = { + GLSLstd450Round, GLSLstd450RoundEven, GLSLstd450Trunc, GLSLstd450FAbs, + GLSLstd450FSign, GLSLstd450Floor, GLSLstd450Ceil, GLSLstd450Fract, + GLSLstd450Radians, GLSLstd450Degrees, GLSLstd450Sin, GLSLstd450Cos, + GLSLstd450Tan, GLSLstd450Asin, GLSLstd450Acos, GLSLstd450Atan, + GLSLstd450Sinh, GLSLstd450Cosh, GLSLstd450Tanh, GLSLstd450Asinh, + GLSLstd450Acosh, GLSLstd450Atanh, GLSLstd450Atan2, GLSLstd450Pow, + GLSLstd450Exp, GLSLstd450Log, GLSLstd450Exp2, GLSLstd450Log2, + GLSLstd450Sqrt, GLSLstd450InverseSqrt, GLSLstd450Determinant, + GLSLstd450MatrixInverse, + // TODO(greg-lunarg): GLSLstd450ModfStruct, + GLSLstd450FMin, GLSLstd450FMax, GLSLstd450FClamp, GLSLstd450FMix, + GLSLstd450Step, GLSLstd450SmoothStep, GLSLstd450Fma, + // TODO(greg-lunarg): GLSLstd450FrexpStruct, + GLSLstd450Ldexp, GLSLstd450Length, GLSLstd450Distance, GLSLstd450Cross, + GLSLstd450Normalize, GLSLstd450FaceForward, GLSLstd450Reflect, + GLSLstd450Refract, GLSLstd450NMin, GLSLstd450NMax, GLSLstd450NClamp}; + sample_ops_ = {SpvOpImageSampleImplicitLod, + SpvOpImageSampleExplicitLod, + SpvOpImageSampleDrefImplicitLod, + SpvOpImageSampleDrefExplicitLod, + SpvOpImageSampleProjImplicitLod, + SpvOpImageSampleProjExplicitLod, + SpvOpImageSampleProjDrefImplicitLod, + SpvOpImageSampleProjDrefExplicitLod, + SpvOpImageFetch, + SpvOpImageGather, + SpvOpImageDrefGather, + SpvOpImageRead, + SpvOpImageSparseSampleImplicitLod, + SpvOpImageSparseSampleExplicitLod, + SpvOpImageSparseSampleDrefImplicitLod, + SpvOpImageSparseSampleDrefExplicitLod, + SpvOpImageSparseSampleProjImplicitLod, + SpvOpImageSparseSampleProjExplicitLod, + SpvOpImageSparseSampleProjDrefImplicitLod, + SpvOpImageSparseSampleProjDrefExplicitLod, + SpvOpImageSparseFetch, + SpvOpImageSparseGather, + SpvOpImageSparseDrefGather, + SpvOpImageSparseTexelsResident, + SpvOpImageSparseRead}; +} + +} // namespace opt +} // namespace spvtools diff --git a/third_party/spirv-tools/source/opt/relax_float_ops_pass.h b/third_party/spirv-tools/source/opt/relax_float_ops_pass.h new file mode 100644 index 0000000000..5ee3d73c8a --- /dev/null +++ b/third_party/spirv-tools/source/opt/relax_float_ops_pass.h @@ -0,0 +1,80 @@ +// Copyright (c) 2019 Valve Corporation +// Copyright (c) 2019 LunarG Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef LIBSPIRV_OPT_RELAX_FLOAT_OPS_PASS_H_ +#define LIBSPIRV_OPT_RELAX_FLOAT_OPS_PASS_H_ + +#include "source/opt/ir_builder.h" +#include "source/opt/pass.h" + +namespace spvtools { +namespace opt { + +class RelaxFloatOpsPass : public Pass { + public: + RelaxFloatOpsPass() : Pass() {} + + ~RelaxFloatOpsPass() override = default; + + IRContext::Analysis GetPreservedAnalyses() override { + return IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping; + } + + // See optimizer.hpp for pass user documentation. + Status Process() override; + + const char* name() const override { return "convert-to-half-pass"; } + + private: + // Return true if |inst| can have the RelaxedPrecision decoration applied + // to it. + bool IsRelaxable(Instruction* inst); + + // Return true if |inst| returns scalar, vector or matrix type with base + // float and width 32 + bool IsFloat32(Instruction* inst); + + // Return true if |r_id| is decorated with RelaxedPrecision + bool IsRelaxed(uint32_t r_id); + + // If |inst| is an instruction of float32-based type and is not decorated + // RelaxedPrecision, add such a decoration to the module. + bool ProcessInst(Instruction* inst); + + // Call ProcessInst on every instruction in |func|. + bool ProcessFunction(Function* func); + + Pass::Status ProcessImpl(); + + // Initialize state for converting to half + void Initialize(); + + // Set of float result core operations to be processed + std::unordered_set target_ops_core_f_rslt_; + + // Set of float operand core operations to be processed + std::unordered_set target_ops_core_f_opnd_; + + // Set of 450 extension operations to be processed + std::unordered_set target_ops_450_; + + // Set of sample operations + std::unordered_set sample_ops_; +}; + +} // namespace opt +} // namespace spvtools + +#endif // LIBSPIRV_OPT_RELAX_FLOAT_OPS_PASS_H_ diff --git a/third_party/spirv-tools/source/opt/remove_duplicates_pass.cpp b/third_party/spirv-tools/source/opt/remove_duplicates_pass.cpp index a37e9df9e7..0e65cc8d14 100644 --- a/third_party/spirv-tools/source/opt/remove_duplicates_pass.cpp +++ b/third_party/spirv-tools/source/opt/remove_duplicates_pass.cpp @@ -96,35 +96,67 @@ bool RemoveDuplicatesPass::RemoveDuplicateTypes() const { return modified; } + analysis::TypeManager type_manager(context()->consumer(), context()); + std::vector visited_types; + std::vector visited_forward_pointers; std::vector to_delete; for (auto* i = &*context()->types_values_begin(); i; i = i->NextNode()) { + const bool is_i_forward_pointer = i->opcode() == SpvOpTypeForwardPointer; + // We only care about types. - if (!spvOpcodeGeneratesType((i->opcode())) && - i->opcode() != SpvOpTypeForwardPointer) { + if (!spvOpcodeGeneratesType(i->opcode()) && !is_i_forward_pointer) { continue; } - // Is the current type equal to one of the types we have aready visited? - SpvId id_to_keep = 0u; - // TODO(dneto0): Use a trie to avoid quadratic behaviour? Extract the - // ResultIdTrie from unify_const_pass.cpp for this. - for (auto j : visited_types) { - if (AreTypesEqual(*i, *j, context())) { - id_to_keep = j->result_id(); - break; + if (!is_i_forward_pointer) { + // Is the current type equal to one of the types we have already visited? + SpvId id_to_keep = 0u; + analysis::Type* i_type = type_manager.GetType(i->result_id()); + assert(i_type); + // TODO(dneto0): Use a trie to avoid quadratic behaviour? Extract the + // ResultIdTrie from unify_const_pass.cpp for this. + for (auto j : visited_types) { + analysis::Type* j_type = type_manager.GetType(j->result_id()); + assert(j_type); + if (*i_type == *j_type) { + id_to_keep = j->result_id(); + break; + } } - } - if (id_to_keep == 0u) { - // This is a never seen before type, keep it around. - visited_types.emplace_back(i); + if (id_to_keep == 0u) { + // This is a never seen before type, keep it around. + visited_types.emplace_back(i); + } else { + // The same type has already been seen before, remove this one. + context()->KillNamesAndDecorates(i->result_id()); + context()->ReplaceAllUsesWith(i->result_id(), id_to_keep); + modified = true; + to_delete.emplace_back(i); + } } else { - // The same type has already been seen before, remove this one. - context()->KillNamesAndDecorates(i->result_id()); - context()->ReplaceAllUsesWith(i->result_id(), id_to_keep); - modified = true; - to_delete.emplace_back(i); + analysis::ForwardPointer i_type( + i->GetSingleWordInOperand(0u), + (SpvStorageClass)i->GetSingleWordInOperand(1u)); + i_type.SetTargetPointer( + type_manager.GetType(i_type.target_id())->AsPointer()); + + // TODO(dneto0): Use a trie to avoid quadratic behaviour? Extract the + // ResultIdTrie from unify_const_pass.cpp for this. + const bool found_a_match = + std::find(std::begin(visited_forward_pointers), + std::end(visited_forward_pointers), + i_type) != std::end(visited_forward_pointers); + + if (!found_a_match) { + // This is a never seen before type, keep it around. + visited_forward_pointers.emplace_back(i_type); + } else { + // The same type has already been seen before, remove this one. + modified = true; + to_delete.emplace_back(i); + } } } @@ -151,8 +183,8 @@ bool RemoveDuplicatesPass::RemoveDuplicateDecorations() const { analysis::DecorationManager decoration_manager(context()->module()); for (auto* i = &*context()->annotation_begin(); i;) { - // Is the current decoration equal to one of the decorations we have aready - // visited? + // Is the current decoration equal to one of the decorations we have + // already visited? bool already_visited = false; // TODO(dneto0): Use a trie to avoid quadratic behaviour? Extract the // ResultIdTrie from unify_const_pass.cpp for this. @@ -177,20 +209,5 @@ bool RemoveDuplicatesPass::RemoveDuplicateDecorations() const { return modified; } -bool RemoveDuplicatesPass::AreTypesEqual(const Instruction& inst1, - const Instruction& inst2, - IRContext* context) { - if (inst1.opcode() != inst2.opcode()) return false; - if (!IsTypeInst(inst1.opcode())) return false; - - const analysis::Type* type1 = - context->get_type_mgr()->GetType(inst1.result_id()); - const analysis::Type* type2 = - context->get_type_mgr()->GetType(inst2.result_id()); - if (type1 && type2 && *type1 == *type2) return true; - - return false; -} - } // namespace opt } // namespace spvtools diff --git a/third_party/spirv-tools/source/opt/remove_duplicates_pass.h b/third_party/spirv-tools/source/opt/remove_duplicates_pass.h index 8554a987dc..038caa8b9f 100644 --- a/third_party/spirv-tools/source/opt/remove_duplicates_pass.h +++ b/third_party/spirv-tools/source/opt/remove_duplicates_pass.h @@ -36,12 +36,6 @@ class RemoveDuplicatesPass : public Pass { const char* name() const override { return "remove-duplicates"; } Status Process() override; - // TODO(pierremoreau): Move this function somewhere else (e.g. pass.h or - // within the type manager) - // Returns whether two types are equal, and have the same decorations. - static bool AreTypesEqual(const Instruction& inst1, const Instruction& inst2, - IRContext* context); - private: // Remove duplicate capabilities from the module // diff --git a/third_party/spirv-tools/source/opt/scalar_analysis_nodes.h b/third_party/spirv-tools/source/opt/scalar_analysis_nodes.h index 450522ec3f..b0e3fefd6f 100644 --- a/third_party/spirv-tools/source/opt/scalar_analysis_nodes.h +++ b/third_party/spirv-tools/source/opt/scalar_analysis_nodes.h @@ -171,16 +171,17 @@ class SENode { bool IsCantCompute() const { return GetType() == CanNotCompute; } // Implements a casting method for each type. +// clang-format off #define DeclareCastMethod(target) \ virtual target* As##target() { return nullptr; } \ virtual const target* As##target() const { return nullptr; } - DeclareCastMethod(SEConstantNode); - DeclareCastMethod(SERecurrentNode); - DeclareCastMethod(SEAddNode); - DeclareCastMethod(SEMultiplyNode); - DeclareCastMethod(SENegative); - DeclareCastMethod(SEValueUnknown); - DeclareCastMethod(SECantCompute); + DeclareCastMethod(SEConstantNode) + DeclareCastMethod(SERecurrentNode) + DeclareCastMethod(SEAddNode) + DeclareCastMethod(SEMultiplyNode) + DeclareCastMethod(SENegative) + DeclareCastMethod(SEValueUnknown) + DeclareCastMethod(SECantCompute) #undef DeclareCastMethod // Get the analysis which has this node in its cache. @@ -200,6 +201,7 @@ class SENode { // The number of nodes created. static uint32_t NumberOfNodes; }; +// clang-format on // Function object to handle the hashing of SENodes. Hashing algorithm hashes // the type (as a string), the literal value of any constants, and the child diff --git a/third_party/spirv-tools/source/opt/scalar_replacement_pass.cpp b/third_party/spirv-tools/source/opt/scalar_replacement_pass.cpp index d51dd8ef2c..36c0c0d72e 100644 --- a/third_party/spirv-tools/source/opt/scalar_replacement_pass.cpp +++ b/third_party/spirv-tools/source/opt/scalar_replacement_pass.cpp @@ -60,50 +60,68 @@ Pass::Status ScalarReplacementPass::ProcessFunction(Function* function) { Instruction* varInst = worklist.front(); worklist.pop(); - if (!ReplaceVariable(varInst, &worklist)) - return Status::Failure; - else - status = Status::SuccessWithChange; + Status var_status = ReplaceVariable(varInst, &worklist); + if (var_status == Status::Failure) + return var_status; + else if (var_status == Status::SuccessWithChange) + status = var_status; } return status; } -bool ScalarReplacementPass::ReplaceVariable( +Pass::Status ScalarReplacementPass::ReplaceVariable( Instruction* inst, std::queue* worklist) { std::vector replacements; - CreateReplacementVariables(inst, &replacements); + if (!CreateReplacementVariables(inst, &replacements)) { + return Status::Failure; + } std::vector dead; - dead.push_back(inst); - if (!get_def_use_mgr()->WhileEachUser( - inst, [this, &replacements, &dead](Instruction* user) { - if (!IsAnnotationInst(user->opcode())) { - switch (user->opcode()) { - case SpvOpLoad: - ReplaceWholeLoad(user, replacements); - dead.push_back(user); - break; - case SpvOpStore: - ReplaceWholeStore(user, replacements); - dead.push_back(user); - break; - case SpvOpAccessChain: - case SpvOpInBoundsAccessChain: - if (!ReplaceAccessChain(user, replacements)) return false; - dead.push_back(user); - break; - case SpvOpName: - case SpvOpMemberName: - break; - default: - assert(false && "Unexpected opcode"); - break; + bool replaced_all_uses = get_def_use_mgr()->WhileEachUser( + inst, [this, &replacements, &dead](Instruction* user) { + if (!IsAnnotationInst(user->opcode())) { + switch (user->opcode()) { + case SpvOpLoad: + if (ReplaceWholeLoad(user, replacements)) { + dead.push_back(user); + } else { + return false; } - } - return true; - })) - return false; + break; + case SpvOpStore: + if (ReplaceWholeStore(user, replacements)) { + dead.push_back(user); + } else { + return false; + } + break; + case SpvOpAccessChain: + case SpvOpInBoundsAccessChain: + if (ReplaceAccessChain(user, replacements)) + dead.push_back(user); + else + return false; + break; + case SpvOpName: + case SpvOpMemberName: + break; + default: + assert(false && "Unexpected opcode"); + break; + } + } + return true; + }); + + if (replaced_all_uses) { + dead.push_back(inst); + } else { + return Status::Failure; + } + + // If there are no dead instructions to clean up, return with no changes. + if (dead.empty()) return Status::SuccessWithoutChange; // Clean up some dead code. while (!dead.empty()) { @@ -123,10 +141,10 @@ bool ScalarReplacementPass::ReplaceVariable( } } - return true; + return Status::SuccessWithChange; } -void ScalarReplacementPass::ReplaceWholeLoad( +bool ScalarReplacementPass::ReplaceWholeLoad( Instruction* load, const std::vector& replacements) { // Replaces the load of the entire composite with a load from each replacement // variable followed by a composite construction. @@ -143,6 +161,9 @@ void ScalarReplacementPass::ReplaceWholeLoad( Instruction* type = GetStorageType(var); uint32_t loadId = TakeNextId(); + if (loadId == 0) { + return false; + } std::unique_ptr newLoad( new Instruction(context(), SpvOpLoad, type->result_id(), loadId, std::initializer_list{ @@ -161,6 +182,9 @@ void ScalarReplacementPass::ReplaceWholeLoad( // Construct a new composite. uint32_t compositeId = TakeNextId(); + if (compositeId == 0) { + return false; + } where = load; std::unique_ptr compositeConstruct(new Instruction( context(), SpvOpCompositeConstruct, load->type_id(), compositeId, {})); @@ -173,9 +197,10 @@ void ScalarReplacementPass::ReplaceWholeLoad( get_def_use_mgr()->AnalyzeInstDefUse(&*where); context()->set_instr_block(&*where, block); context()->ReplaceAllUsesWith(load->result_id(), compositeId); + return true; } -void ScalarReplacementPass::ReplaceWholeStore( +bool ScalarReplacementPass::ReplaceWholeStore( Instruction* store, const std::vector& replacements) { // Replaces a store to the whole composite with a series of extract and stores // to each element. @@ -192,6 +217,9 @@ void ScalarReplacementPass::ReplaceWholeStore( Instruction* type = GetStorageType(var); uint32_t extractId = TakeNextId(); + if (extractId == 0) { + return false; + } std::unique_ptr extract(new Instruction( context(), SpvOpCompositeExtract, type->result_id(), extractId, std::initializer_list{ @@ -217,6 +245,7 @@ void ScalarReplacementPass::ReplaceWholeStore( get_def_use_mgr()->AnalyzeInstDefUse(&*iter); context()->set_instr_block(&*iter, block); } + return true; } bool ScalarReplacementPass::ReplaceAccessChain( @@ -225,16 +254,24 @@ bool ScalarReplacementPass::ReplaceAccessChain( // indexes) or a direct use of the replacement variable. uint32_t indexId = chain->GetSingleWordInOperand(1u); const Instruction* index = get_def_use_mgr()->GetDef(indexId); - size_t indexValue = GetConstantInteger(index); - if (indexValue > replacements.size()) { - // Out of bounds access, this is illegal IR. + int64_t indexValue = context() + ->get_constant_mgr() + ->GetConstantFromInst(index) + ->GetSignExtendedValue(); + if (indexValue < 0 || + indexValue >= static_cast(replacements.size())) { + // Out of bounds access, this is illegal IR. Notice that OpAccessChain + // indexing is 0-based, so we should also reject index == size-of-array. return false; } else { - const Instruction* var = replacements[indexValue]; + const Instruction* var = replacements[static_cast(indexValue)]; if (chain->NumInOperands() > 2) { // Replace input access chain with another access chain. BasicBlock::iterator chainIter(chain); uint32_t replacementId = TakeNextId(); + if (replacementId == 0) { + return false; + } std::unique_ptr replacementChain(new Instruction( context(), chain->opcode(), chain->type_id(), replacementId, std::initializer_list{ @@ -257,11 +294,11 @@ bool ScalarReplacementPass::ReplaceAccessChain( return true; } -void ScalarReplacementPass::CreateReplacementVariables( +bool ScalarReplacementPass::CreateReplacementVariables( Instruction* inst, std::vector* replacements) { Instruction* type = GetStorageType(inst); - std::unique_ptr> components_used = + std::unique_ptr> components_used = GetUsedComponents(inst); uint32_t elem = 0; @@ -302,6 +339,8 @@ void ScalarReplacementPass::CreateReplacementVariables( } TransferAnnotations(inst, replacements); + return std::find(replacements->begin(), replacements->end(), nullptr) == + replacements->end(); } void ScalarReplacementPass::TransferAnnotations( @@ -315,6 +354,10 @@ void ScalarReplacementPass::TransferAnnotations( if (decoration == SpvDecorationInvariant || decoration == SpvDecorationRestrict) { for (auto var : *replacements) { + if (var == nullptr) { + continue; + } + std::unique_ptr annotation( new Instruction(context(), SpvOpDecorate, 0, 0, std::initializer_list{ @@ -336,6 +379,11 @@ void ScalarReplacementPass::CreateVariable( std::vector* replacements) { uint32_t ptrId = GetOrCreatePointerType(typeId); uint32_t id = TakeNextId(); + + if (id == 0) { + replacements->push_back(nullptr); + } + std::unique_ptr variable(new Instruction( context(), SpvOpVariable, ptrId, id, std::initializer_list{ @@ -350,6 +398,35 @@ void ScalarReplacementPass::CreateVariable( get_def_use_mgr()->AnalyzeInstDefUse(inst); context()->set_instr_block(inst, block); + // Copy decorations from the member to the new variable. + Instruction* typeInst = GetStorageType(varInst); + for (auto dec_inst : + get_decoration_mgr()->GetDecorationsFor(typeInst->result_id(), false)) { + uint32_t decoration; + if (dec_inst->opcode() != SpvOpMemberDecorate) { + continue; + } + + if (dec_inst->GetSingleWordInOperand(1) != index) { + continue; + } + + decoration = dec_inst->GetSingleWordInOperand(2u); + switch (decoration) { + case SpvDecorationRelaxedPrecision: { + std::unique_ptr new_dec_inst( + new Instruction(context(), SpvOpDecorate, 0, 0, {})); + new_dec_inst->AddOperand(Operand(SPV_OPERAND_TYPE_ID, {id})); + for (uint32_t i = 2; i < dec_inst->NumInOperandWords(); ++i) { + new_dec_inst->AddOperand(Operand(dec_inst->GetInOperand(i))); + } + context()->AddAnnotationInst(std::move(new_dec_inst)); + } break; + default: + break; + } + } + replacements->push_back(inst); } @@ -363,7 +440,7 @@ uint32_t ScalarReplacementPass::GetOrCreatePointerType(uint32_t id) { context()->get_type_mgr()->GetTypeAndPointerType(id, SpvStorageClassFunction); uint32_t ptrId = 0; - if (id == context()->get_type_mgr()->GetId(pointeeTy)) { + if (pointeeTy->IsUniqueType()) { // Non-ambiguous type, just ask the type manager for an id. ptrId = context()->get_type_mgr()->GetTypeInstruction(pointerTy.get()); pointee_to_pointer_[id] = ptrId; @@ -457,49 +534,35 @@ void ScalarReplacementPass::GetOrCreateInitialValue(Instruction* source, } } -size_t ScalarReplacementPass::GetIntegerLiteral(const Operand& op) const { - assert(op.words.size() <= 2); - size_t len = 0; - for (uint32_t i = 0; i != op.words.size(); ++i) { - len |= (op.words[i] << (32 * i)); - } - return len; -} - -size_t ScalarReplacementPass::GetConstantInteger( - const Instruction* constant) const { - assert(get_def_use_mgr()->GetDef(constant->type_id())->opcode() == - SpvOpTypeInt); - assert(constant->opcode() == SpvOpConstant || - constant->opcode() == SpvOpConstantNull); - if (constant->opcode() == SpvOpConstantNull) { - return 0; - } - - const Operand& op = constant->GetInOperand(0u); - return GetIntegerLiteral(op); -} - -size_t ScalarReplacementPass::GetArrayLength( +uint64_t ScalarReplacementPass::GetArrayLength( const Instruction* arrayType) const { assert(arrayType->opcode() == SpvOpTypeArray); const Instruction* length = get_def_use_mgr()->GetDef(arrayType->GetSingleWordInOperand(1u)); - return GetConstantInteger(length); + return context() + ->get_constant_mgr() + ->GetConstantFromInst(length) + ->GetZeroExtendedValue(); } -size_t ScalarReplacementPass::GetNumElements(const Instruction* type) const { +uint64_t ScalarReplacementPass::GetNumElements(const Instruction* type) const { assert(type->opcode() == SpvOpTypeVector || type->opcode() == SpvOpTypeMatrix); const Operand& op = type->GetInOperand(1u); assert(op.words.size() <= 2); - size_t len = 0; - for (uint32_t i = 0; i != op.words.size(); ++i) { - len |= (op.words[i] << (32 * i)); + uint64_t len = 0; + for (size_t i = 0; i != op.words.size(); ++i) { + len |= (static_cast(op.words[i]) << (32ull * i)); } return len; } +bool ScalarReplacementPass::IsSpecConstant(uint32_t id) const { + const Instruction* inst = get_def_use_mgr()->GetDef(id); + assert(inst); + return spvOpcodeIsSpecConstant(inst->opcode()); +} + Instruction* ScalarReplacementPass::GetStorageType( const Instruction* inst) const { assert(inst->opcode() == SpvOpVariable); @@ -515,28 +578,50 @@ bool ScalarReplacementPass::CanReplaceVariable( assert(varInst->opcode() == SpvOpVariable); // Can only replace function scope variables. - if (varInst->GetSingleWordInOperand(0u) != SpvStorageClassFunction) + if (varInst->GetSingleWordInOperand(0u) != SpvStorageClassFunction) { return false; + } - if (!CheckTypeAnnotations(get_def_use_mgr()->GetDef(varInst->type_id()))) + if (!CheckTypeAnnotations(get_def_use_mgr()->GetDef(varInst->type_id()))) { return false; + } const Instruction* typeInst = GetStorageType(varInst); - return CheckType(typeInst) && CheckAnnotations(varInst) && CheckUses(varInst); + if (!CheckType(typeInst)) { + return false; + } + + if (!CheckAnnotations(varInst)) { + return false; + } + + if (!CheckUses(varInst)) { + return false; + } + + return true; } bool ScalarReplacementPass::CheckType(const Instruction* typeInst) const { - if (!CheckTypeAnnotations(typeInst)) return false; + if (!CheckTypeAnnotations(typeInst)) { + return false; + } switch (typeInst->opcode()) { case SpvOpTypeStruct: // Don't bother with empty structs or very large structs. if (typeInst->NumInOperands() == 0 || - IsLargerThanSizeLimit(typeInst->NumInOperands())) + IsLargerThanSizeLimit(typeInst->NumInOperands())) { return false; + } return true; case SpvOpTypeArray: - if (IsLargerThanSizeLimit(GetArrayLength(typeInst))) return false; + if (IsSpecConstant(typeInst->GetSingleWordInOperand(1u))) { + return false; + } + if (IsLargerThanSizeLimit(GetArrayLength(typeInst))) { + return false; + } return true; // TODO(alanbaker): Develop some heuristics for when this should be // re-enabled. @@ -577,6 +662,7 @@ bool ScalarReplacementPass::CheckTypeAnnotations( case SpvDecorationAlignment: case SpvDecorationAlignmentId: case SpvDecorationMaxByteOffset: + case SpvDecorationRelaxedPrecision: break; default: return false; @@ -619,44 +705,51 @@ bool ScalarReplacementPass::CheckUses(const Instruction* inst) const { bool ScalarReplacementPass::CheckUses(const Instruction* inst, VariableStats* stats) const { + uint64_t max_legal_index = GetMaxLegalIndex(inst); + bool ok = true; - get_def_use_mgr()->ForEachUse( - inst, [this, stats, &ok](const Instruction* user, uint32_t index) { - // Annotations are check as a group separately. - if (!IsAnnotationInst(user->opcode())) { - switch (user->opcode()) { - case SpvOpAccessChain: - case SpvOpInBoundsAccessChain: - if (index == 2u) { - uint32_t id = user->GetSingleWordOperand(3u); - const Instruction* opInst = get_def_use_mgr()->GetDef(id); - if (!IsCompileTimeConstantInst(opInst->opcode())) { - ok = false; - } else { - if (!CheckUsesRelaxed(user)) ok = false; - } - stats->num_partial_accesses++; - } else { - ok = false; - } - break; - case SpvOpLoad: - if (!CheckLoad(user, index)) ok = false; - stats->num_full_accesses++; - break; - case SpvOpStore: - if (!CheckStore(user, index)) ok = false; - stats->num_full_accesses++; - break; - case SpvOpName: - case SpvOpMemberName: - break; - default: + get_def_use_mgr()->ForEachUse(inst, [this, max_legal_index, stats, &ok]( + const Instruction* user, + uint32_t index) { + // Annotations are check as a group separately. + if (!IsAnnotationInst(user->opcode())) { + switch (user->opcode()) { + case SpvOpAccessChain: + case SpvOpInBoundsAccessChain: + if (index == 2u && user->NumInOperands() > 1) { + uint32_t id = user->GetSingleWordInOperand(1u); + const Instruction* opInst = get_def_use_mgr()->GetDef(id); + const auto* constant = + context()->get_constant_mgr()->GetConstantFromInst(opInst); + if (!constant) { ok = false; - break; + } else if (constant->GetZeroExtendedValue() >= max_legal_index) { + ok = false; + } else { + if (!CheckUsesRelaxed(user)) ok = false; + } + stats->num_partial_accesses++; + } else { + ok = false; } - } - }); + break; + case SpvOpLoad: + if (!CheckLoad(user, index)) ok = false; + stats->num_full_accesses++; + break; + case SpvOpStore: + if (!CheckStore(user, index)) ok = false; + stats->num_full_accesses++; + break; + case SpvOpName: + case SpvOpMemberName: + break; + default: + ok = false; + break; + } + } + }); return ok; } @@ -706,17 +799,17 @@ bool ScalarReplacementPass::CheckStore(const Instruction* inst, return false; return true; } -bool ScalarReplacementPass::IsLargerThanSizeLimit(size_t length) const { +bool ScalarReplacementPass::IsLargerThanSizeLimit(uint64_t length) const { if (max_num_elements_ == 0) { return false; } return length > max_num_elements_; } -std::unique_ptr> +std::unique_ptr> ScalarReplacementPass::GetUsedComponents(Instruction* inst) { - std::unique_ptr> result( - new std::unordered_set()); + std::unique_ptr> result( + new std::unordered_set()); analysis::DefUseManager* def_use_mgr = context()->get_def_use_mgr(); @@ -727,7 +820,8 @@ ScalarReplacementPass::GetUsedComponents(Instruction* inst) { // Look for extract from the load. std::vector t; if (def_use_mgr->WhileEachUser(use, [&t](Instruction* use2) { - if (use2->opcode() != SpvOpCompositeExtract) { + if (use2->opcode() != SpvOpCompositeExtract || + use2->NumInOperands() <= 1) { return false; } t.push_back(use2->GetSingleWordInOperand(1)); @@ -740,8 +834,10 @@ ScalarReplacementPass::GetUsedComponents(Instruction* inst) { return false; } } + case SpvOpName: + case SpvOpMemberName: case SpvOpStore: - // No components are used. Things are just stored to. + // No components are used. return true; case SpvOpAccessChain: case SpvOpInBoundsAccessChain: { @@ -752,34 +848,14 @@ ScalarReplacementPass::GetUsedComponents(Instruction* inst) { const analysis::Constant* index_const = const_mgr->FindDeclaredConstant(index_id); if (index_const) { - const analysis::Integer* index_type = - index_const->type()->AsInteger(); - assert(index_type); - if (index_type->width() == 32) { - result->insert(index_const->GetU32()); - return true; - } else if (index_type->width() == 64) { - result->insert(index_const->GetU64()); - return true; - } - result.reset(nullptr); - return false; + result->insert(index_const->GetSignExtendedValue()); + return true; } else { // Could be any element. Assuming all are used. result.reset(nullptr); return false; } } - case SpvOpCopyObject: { - // Follow the copy to see which components are used. - auto t = GetUsedComponents(use); - if (!t) { - result.reset(nullptr); - return false; - } - result->insert(t->begin(), t->end()); - return true; - } default: // We do not know what is happening. Have to assume the worst. result.reset(nullptr); @@ -798,9 +874,30 @@ Instruction* ScalarReplacementPass::CreateNullConstant(uint32_t type_id) { const analysis::Constant* null_const = const_mgr->GetConstant(type, {}); Instruction* null_inst = const_mgr->GetDefiningInstruction(null_const, type_id); - context()->UpdateDefUse(null_inst); + if (null_inst != nullptr) { + context()->UpdateDefUse(null_inst); + } return null_inst; } +uint64_t ScalarReplacementPass::GetMaxLegalIndex( + const Instruction* var_inst) const { + assert(var_inst->opcode() == SpvOpVariable && + "|var_inst| must be a variable instruction."); + Instruction* type = GetStorageType(var_inst); + switch (type->opcode()) { + case SpvOpTypeStruct: + return type->NumInOperands(); + case SpvOpTypeArray: + return GetArrayLength(type); + case SpvOpTypeMatrix: + case SpvOpTypeVector: + return GetNumElements(type); + default: + return 0; + } + return 0; +} + } // namespace opt } // namespace spvtools diff --git a/third_party/spirv-tools/source/opt/scalar_replacement_pass.h b/third_party/spirv-tools/source/opt/scalar_replacement_pass.h index c89bbc4015..e20f1f1a5e 100644 --- a/third_party/spirv-tools/source/opt/scalar_replacement_pass.h +++ b/third_party/spirv-tools/source/opt/scalar_replacement_pass.h @@ -52,7 +52,8 @@ class ScalarReplacementPass : public Pass { return IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping | IRContext::kAnalysisDecorations | IRContext::kAnalysisCombinators | - IRContext::kAnalysisCFG | IRContext::kAnalysisNameMap; + IRContext::kAnalysisCFG | IRContext::kAnalysisNameMap | + IRContext::kAnalysisConstants | IRContext::kAnalysisTypes; } private: @@ -116,9 +117,12 @@ class ScalarReplacementPass : public Pass { // for element of the composite type. Uses of |inst| are updated as // appropriate. If the replacement variables are themselves scalarizable, they // get added to |worklist| for further processing. If any replacement - // variable ends up with no uses it is erased. Returns false if any - // subsequent access chain is out of bounds. - bool ReplaceVariable(Instruction* inst, std::queue* worklist); + // variable ends up with no uses it is erased. Returns + // - Status::SuccessWithoutChange if the variable could not be replaced. + // - Status::SuccessWithChange if it made replacements. + // - Status::Failure if it couldn't create replacement variables. + Pass::Status ReplaceVariable(Instruction* inst, + std::queue* worklist); // Returns the underlying storage type for |inst|. // @@ -139,35 +143,34 @@ class ScalarReplacementPass : public Pass { bool CheckStore(const Instruction* inst, uint32_t index) const; // Creates a variable of type |typeId| from the |index|'th element of - // |varInst|. The new variable is added to |replacements|. + // |varInst|. The new variable is added to |replacements|. If the variable + // could not be created, then |nullptr| is appended to |replacements|. void CreateVariable(uint32_t typeId, Instruction* varInst, uint32_t index, std::vector* replacements); // Populates |replacements| with a new OpVariable for each element of |inst|. + // Returns true if the replacement variables were successfully created. // // |inst| must be an OpVariable of a composite type. New variables are // initialized the same as the corresponding index in |inst|. |replacements| // will contain a variable for each element of the composite with matching // indexes (i.e. the 0'th element of |inst| is the 0'th entry of // |replacements|). - void CreateReplacementVariables(Instruction* inst, + bool CreateReplacementVariables(Instruction* inst, std::vector* replacements); - // Returns the value of an OpConstant of integer type. - // - // |constant| must use two or fewer words to generate the value. - size_t GetConstantInteger(const Instruction* constant) const; - - // Returns the integer literal for |op|. - size_t GetIntegerLiteral(const Operand& op) const; - // Returns the array length for |arrayInst|. - size_t GetArrayLength(const Instruction* arrayInst) const; + uint64_t GetArrayLength(const Instruction* arrayInst) const; // Returns the number of elements in |type|. // // |type| must be a vector or matrix type. - size_t GetNumElements(const Instruction* type) const; + uint64_t GetNumElements(const Instruction* type) const; + + // Returns true if |id| is a specialization constant. + // + // |id| must be registered definition. + bool IsSpecConstant(uint32_t id) const; // Returns an id for a pointer to |id|. uint32_t GetOrCreatePointerType(uint32_t id); @@ -185,32 +188,33 @@ class ScalarReplacementPass : public Pass { // Generates a load for each replacement variable and then creates a new // composite by combining all of the loads. // - // |load| must be a load. - void ReplaceWholeLoad(Instruction* load, + // |load| must be a load. Returns true if successful. + bool ReplaceWholeLoad(Instruction* load, const std::vector& replacements); // Replaces the store to the entire composite. // // Generates a composite extract and store for each element in the scalarized - // variable from the original store data input. - void ReplaceWholeStore(Instruction* store, + // variable from the original store data input. Returns true if successful. + bool ReplaceWholeStore(Instruction* store, const std::vector& replacements); // Replaces an access chain to the composite variable with either a direct use // of the appropriate replacement variable or another access chain with the - // replacement variable as the base and one fewer indexes. Returns false if - // the chain has an out of bounds access. + // replacement variable as the base and one fewer indexes. Returns true if + // successful. bool ReplaceAccessChain(Instruction* chain, const std::vector& replacements); // Returns a set containing the which components of the result of |inst| are // potentially used. If the return value is |nullptr|, then every components // is possibly used. - std::unique_ptr> GetUsedComponents( + std::unique_ptr> GetUsedComponents( Instruction* inst); // Returns an instruction defining a null constant with type |type_id|. If // one already exists, it is returned. Otherwise a new one is created. + // Returns |nullptr| if the new constant could not be created. Instruction* CreateNullConstant(uint32_t type_id); // Maps storage type to a pointer type enclosing that type. @@ -219,10 +223,16 @@ class ScalarReplacementPass : public Pass { // Maps type id to OpConstantNull for that type. std::unordered_map type_to_null_; + // Returns the number of elements in the variable |var_inst|. + uint64_t GetMaxLegalIndex(const Instruction* var_inst) const; + + // Returns true if |length| is larger than limit on the size of the variable + // that we will be willing to split. + bool IsLargerThanSizeLimit(uint64_t length) const; + // Limit on the number of members in an object that will be replaced. // 0 means there is no limit. uint32_t max_num_elements_; - bool IsLargerThanSizeLimit(size_t length) const; char name_[55]; }; diff --git a/third_party/spirv-tools/source/opt/simplification_pass.cpp b/third_party/spirv-tools/source/opt/simplification_pass.cpp index 5fbafbdd1c..001f35437a 100644 --- a/third_party/spirv-tools/source/opt/simplification_pass.cpp +++ b/third_party/spirv-tools/source/opt/simplification_pass.cpp @@ -32,6 +32,18 @@ Pass::Status SimplificationPass::Process() { return (modified ? Status::SuccessWithChange : Status::SuccessWithoutChange); } +void SimplificationPass::AddNewOperands( + Instruction* folded_inst, std::unordered_set* inst_seen, + std::vector* work_list) { + analysis::DefUseManager* def_use_mgr = get_def_use_mgr(); + folded_inst->ForEachInId( + [&inst_seen, &def_use_mgr, &work_list](uint32_t* iid) { + Instruction* iid_inst = def_use_mgr->GetDef(*iid); + if (!inst_seen->insert(iid_inst).second) return; + work_list->push_back(iid_inst); + }); +} + bool SimplificationPass::SimplifyFunction(Function* function) { bool modified = false; // Phase 1: Traverse all instructions in dominance order. @@ -44,19 +56,25 @@ bool SimplificationPass::SimplifyFunction(Function* function) { std::unordered_set process_phis; std::unordered_set inst_to_kill; std::unordered_set in_work_list; + std::unordered_set inst_seen; const InstructionFolder& folder = context()->get_instruction_folder(); cfg()->ForEachBlockInReversePostOrder( function->entry().get(), [&modified, &process_phis, &work_list, &in_work_list, &inst_to_kill, - folder, this](BasicBlock* bb) { + &folder, &inst_seen, this](BasicBlock* bb) { for (Instruction* inst = &*bb->begin(); inst; inst = inst->NextNode()) { + inst_seen.insert(inst); if (inst->opcode() == SpvOpPhi) { process_phis.insert(inst); } - if (inst->opcode() == SpvOpCopyObject || - folder.FoldInstruction(inst)) { + bool is_foldable_copy = + inst->opcode() == SpvOpCopyObject && + context()->get_decoration_mgr()->HaveSubsetOfDecorations( + inst->result_id(), inst->GetSingleWordInOperand(0)); + + if (is_foldable_copy || folder.FoldInstruction(inst)) { modified = true; context()->AnalyzeUses(inst); get_def_use_mgr()->ForEachUser(inst, [&work_list, &process_phis, @@ -66,9 +84,20 @@ bool SimplificationPass::SimplifyFunction(Function* function) { work_list.push_back(use); } }); + + AddNewOperands(inst, &inst_seen, &work_list); + if (inst->opcode() == SpvOpCopyObject) { - context()->ReplaceAllUsesWith(inst->result_id(), - inst->GetSingleWordInOperand(0)); + context()->ReplaceAllUsesWithPredicate( + inst->result_id(), inst->GetSingleWordInOperand(0), + [](Instruction* user, uint32_t) { + const auto opcode = user->opcode(); + if (!spvOpcodeIsDebug(opcode) && + !spvOpcodeIsDecoration(opcode)) { + return true; + } + return false; + }); inst_to_kill.insert(inst); in_work_list.insert(inst); } else if (inst->opcode() == SpvOpNop) { @@ -85,7 +114,14 @@ bool SimplificationPass::SimplifyFunction(Function* function) { for (size_t i = 0; i < work_list.size(); ++i) { Instruction* inst = work_list[i]; in_work_list.erase(inst); - if (inst->opcode() == SpvOpCopyObject || folder.FoldInstruction(inst)) { + inst_seen.insert(inst); + + bool is_foldable_copy = + inst->opcode() == SpvOpCopyObject && + context()->get_decoration_mgr()->HaveSubsetOfDecorations( + inst->result_id(), inst->GetSingleWordInOperand(0)); + + if (is_foldable_copy || folder.FoldInstruction(inst)) { modified = true; context()->AnalyzeUses(inst); get_def_use_mgr()->ForEachUser( @@ -96,9 +132,18 @@ bool SimplificationPass::SimplifyFunction(Function* function) { } }); + AddNewOperands(inst, &inst_seen, &work_list); + if (inst->opcode() == SpvOpCopyObject) { - context()->ReplaceAllUsesWith(inst->result_id(), - inst->GetSingleWordInOperand(0)); + context()->ReplaceAllUsesWithPredicate( + inst->result_id(), inst->GetSingleWordInOperand(0), + [](Instruction* user, uint32_t) { + const auto opcode = user->opcode(); + if (!spvOpcodeIsDebug(opcode) && !spvOpcodeIsDecoration(opcode)) { + return true; + } + return false; + }); inst_to_kill.insert(inst); in_work_list.insert(inst); } else if (inst->opcode() == SpvOpNop) { diff --git a/third_party/spirv-tools/source/opt/simplification_pass.h b/third_party/spirv-tools/source/opt/simplification_pass.h index 348c96a033..149874b094 100644 --- a/third_party/spirv-tools/source/opt/simplification_pass.h +++ b/third_party/spirv-tools/source/opt/simplification_pass.h @@ -33,7 +33,8 @@ class SimplificationPass : public Pass { IRContext::kAnalysisInstrToBlockMapping | IRContext::kAnalysisDecorations | IRContext::kAnalysisCombinators | IRContext::kAnalysisCFG | IRContext::kAnalysisDominatorAnalysis | - IRContext::kAnalysisNameMap; + IRContext::kAnalysisNameMap | IRContext::kAnalysisConstants | + IRContext::kAnalysisTypes; } private: @@ -41,6 +42,14 @@ class SimplificationPass : public Pass { // instruction in |function| until nothing else in the function can be // simplified. bool SimplifyFunction(Function* function); + + // FactorAddMul can create |folded_inst| Mul of new Add. If Mul, push any Add + // operand not in |seen_inst| into |worklist|. This is heavily restricted to + // improve compile time but can be expanded for future simplifications which + // simiarly create new operations. + void AddNewOperands(Instruction* folded_inst, + std::unordered_set* inst_seen, + std::vector* work_list); }; } // namespace opt diff --git a/third_party/spirv-tools/source/opt/split_invalid_unreachable_pass.cpp b/third_party/spirv-tools/source/opt/split_invalid_unreachable_pass.cpp new file mode 100644 index 0000000000..31cfbc330b --- /dev/null +++ b/third_party/spirv-tools/source/opt/split_invalid_unreachable_pass.cpp @@ -0,0 +1,95 @@ +// Copyright (c) 2019 Google LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/opt/split_invalid_unreachable_pass.h" + +#include "source/opt/ir_builder.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace opt { + +Pass::Status SplitInvalidUnreachablePass::Process() { + bool changed = false; + std::unordered_set entry_points; + for (auto entry_point : context()->module()->entry_points()) { + entry_points.insert(entry_point.GetSingleWordOperand(1)); + } + + for (auto func = context()->module()->begin(); + func != context()->module()->end(); ++func) { + if (entry_points.find(func->result_id()) == entry_points.end()) continue; + std::unordered_set continue_targets; + std::unordered_set merge_blocks; + std::unordered_set unreachable_blocks; + for (auto block = func->begin(); block != func->end(); ++block) { + unreachable_blocks.insert(&*block); + uint32_t continue_target = block->ContinueBlockIdIfAny(); + if (continue_target != 0) continue_targets.insert(continue_target); + uint32_t merge_block = block->MergeBlockIdIfAny(); + if (merge_block != 0) merge_blocks.insert(merge_block); + } + + cfg()->ForEachBlockInPostOrder( + func->entry().get(), [&unreachable_blocks](BasicBlock* inner_block) { + unreachable_blocks.erase(inner_block); + }); + + for (auto unreachable : unreachable_blocks) { + uint32_t block_id = unreachable->id(); + if (continue_targets.find(block_id) == continue_targets.end() || + merge_blocks.find(block_id) == merge_blocks.end()) { + continue; + } + + std::vector> usages; + context()->get_def_use_mgr()->ForEachUse( + unreachable->GetLabelInst(), + [&usages](Instruction* use, uint32_t idx) { + if ((use->opcode() == SpvOpLoopMerge && idx == 0) || + use->opcode() == SpvOpSelectionMerge) { + usages.push_back(std::make_pair(use, idx)); + } + }); + + for (auto usage : usages) { + Instruction* use; + uint32_t idx; + std::tie(use, idx) = usage; + uint32_t new_id = context()->TakeNextId(); + std::unique_ptr new_label( + new Instruction(context(), SpvOpLabel, 0, new_id, {})); + get_def_use_mgr()->AnalyzeInstDefUse(new_label.get()); + std::unique_ptr new_block( + new BasicBlock(std::move(new_label))); + auto* block_ptr = new_block.get(); + InstructionBuilder builder(context(), new_block.get(), + IRContext::kAnalysisDefUse | + IRContext::kAnalysisInstrToBlockMapping); + builder.AddUnreachable(); + cfg()->RegisterBlock(block_ptr); + (&*func)->InsertBasicBlockBefore(std::move(new_block), unreachable); + use->SetInOperand(0, {new_id}); + get_def_use_mgr()->UpdateDefUse(use); + cfg()->AddEdges(block_ptr); + changed = true; + } + } + } + + return changed ? Status::SuccessWithChange : Status::SuccessWithoutChange; +} + +} // namespace opt +} // namespace spvtools diff --git a/third_party/spirv-tools/source/opt/split_invalid_unreachable_pass.h b/third_party/spirv-tools/source/opt/split_invalid_unreachable_pass.h new file mode 100644 index 0000000000..a5613448e7 --- /dev/null +++ b/third_party/spirv-tools/source/opt/split_invalid_unreachable_pass.h @@ -0,0 +1,51 @@ +// Copyright (c) 2019 Google LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_OPT_SPLIT_INVALID_UNREACHABLE_PASS_H_ +#define SOURCE_OPT_SPLIT_INVALID_UNREACHABLE_PASS_H_ + +#include "source/opt/ir_context.h" +#include "source/opt/module.h" +#include "source/opt/pass.h" + +namespace spvtools { +namespace opt { + +// Attempts to legalize for WebGPU by splitting up invalid unreachable blocks. +// Specifically, looking for cases of unreachable merge-blocks and +// continue-targets that are used more then once, which is illegal in WebGPU. +class SplitInvalidUnreachablePass : public Pass { + public: + const char* name() const override { return "split-invalid-unreachable"; } + Status Process() override; + + IRContext::Analysis GetPreservedAnalyses() override { + return IRContext::kAnalysisInstrToBlockMapping | + IRContext::kAnalysisDecorations | IRContext::kAnalysisCombinators | + IRContext::kAnalysisCFG | IRContext::kAnalysisDominatorAnalysis | + IRContext::kAnalysisLoopAnalysis | IRContext::kAnalysisNameMap | + IRContext::kAnalysisScalarEvolution | + IRContext::kAnalysisRegisterPressure | + IRContext::kAnalysisValueNumberTable | + IRContext::kAnalysisStructuredCFG | + IRContext::kAnalysisBuiltinVarId | + IRContext::kAnalysisIdToFuncMapping | IRContext::kAnalysisTypes | + IRContext::kAnalysisDefUse | IRContext::kAnalysisConstants; + } +}; + +} // namespace opt +} // namespace spvtools + +#endif // SOURCE_OPT_SPLIT_INVALID_UNREACHABLE_PASS_H_ diff --git a/third_party/spirv-tools/source/opt/ssa_rewrite_pass.cpp b/third_party/spirv-tools/source/opt/ssa_rewrite_pass.cpp index 83d2433111..69c3a1f3ed 100644 --- a/third_party/spirv-tools/source/opt/ssa_rewrite_pass.cpp +++ b/third_party/spirv-tools/source/opt/ssa_rewrite_pass.cpp @@ -90,6 +90,7 @@ std::string SSARewriter::PhiCandidate::PrettyPrint(const CFG* cfg) const { SSARewriter::PhiCandidate& SSARewriter::CreatePhiCandidate(uint32_t var_id, BasicBlock* bb) { + // TODO(1841): Handle id overflow. uint32_t phi_result_id = pass_->context()->TakeNextId(); auto result = phi_candidates_.emplace( phi_result_id, PhiCandidate(var_id, phi_result_id, bb)); @@ -101,6 +102,7 @@ void SSARewriter::ReplacePhiUsersWith(const PhiCandidate& phi_to_remove, uint32_t repl_id) { for (uint32_t user_id : phi_to_remove.users()) { PhiCandidate* user_phi = GetPhiCandidate(user_id); + BasicBlock* bb = pass_->context()->get_instr_block(user_id); if (user_phi) { // If the user is a Phi candidate, replace all arguments that refer to // |phi_to_remove.result_id()| with |repl_id|. @@ -109,6 +111,10 @@ void SSARewriter::ReplacePhiUsersWith(const PhiCandidate& phi_to_remove, arg = repl_id; } } + } else if (bb->id() == user_id) { + // The phi candidate is the definition of the variable at basic block + // |bb|. We must change this to the replacement. + WriteVariable(phi_to_remove.var_id(), bb, repl_id); } else { // For regular loads, traverse the |load_replacement_| table looking for // instances of |phi_to_remove|. @@ -258,6 +264,8 @@ uint32_t SSARewriter::GetReachingDef(uint32_t var_id, BasicBlock* bb) { // require a Phi instruction. This will act as |var_id|'s current // definition to break potential cycles. PhiCandidate& phi_candidate = CreatePhiCandidate(var_id, bb); + + // Set the value for |bb| to avoid an infinite recursion. WriteVariable(var_id, bb, phi_candidate.result_id()); val_id = AddPhiOperands(&phi_candidate); } @@ -266,6 +274,9 @@ uint32_t SSARewriter::GetReachingDef(uint32_t var_id, BasicBlock* bb) { // of the CFG, the variable is not defined, so we use undef. if (val_id == 0) { val_id = pass_->GetUndefVal(var_id); + if (val_id == 0) { + return 0; + } } WriteVariable(var_id, bb, val_id); @@ -305,12 +316,15 @@ void SSARewriter::ProcessStore(Instruction* inst, BasicBlock* bb) { } } -void SSARewriter::ProcessLoad(Instruction* inst, BasicBlock* bb) { +bool SSARewriter::ProcessLoad(Instruction* inst, BasicBlock* bb) { uint32_t var_id = 0; (void)pass_->GetPtr(inst, &var_id); if (pass_->IsTargetVar(var_id)) { // Get the immediate reaching definition for |var_id|. uint32_t val_id = GetReachingDef(var_id, bb); + if (val_id == 0) { + return false; + } // Schedule a replacement for the result of this load instruction with // |val_id|. After all the rewriting decisions are made, every use of @@ -329,6 +343,7 @@ void SSARewriter::ProcessLoad(Instruction* inst, BasicBlock* bb) { << " (replacement for %" << load_id << " is %" << val_id << ")\n"; #endif } + return true; } void SSARewriter::PrintPhiCandidates() const { @@ -348,7 +363,7 @@ void SSARewriter::PrintReplacementTable() const { std::cerr << "\n"; } -void SSARewriter::GenerateSSAReplacements(BasicBlock* bb) { +bool SSARewriter::GenerateSSAReplacements(BasicBlock* bb) { #if SSA_REWRITE_DEBUGGING_LEVEL > 1 std::cerr << "Generating SSA replacements for block: " << bb->id() << "\n"; std::cerr << bb->PrettyPrint(SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES) @@ -360,7 +375,9 @@ void SSARewriter::GenerateSSAReplacements(BasicBlock* bb) { if (opcode == SpvOpStore || opcode == SpvOpVariable) { ProcessStore(&inst, bb); } else if (inst.opcode() == SpvOpLoad) { - ProcessLoad(&inst, bb); + if (!ProcessLoad(&inst, bb)) { + return false; + } } } @@ -373,6 +390,7 @@ void SSARewriter::GenerateSSAReplacements(BasicBlock* bb) { PrintReplacementTable(); std::cerr << "\n\n"; #endif + return true; } uint32_t SSARewriter::GetReplacement(std::pair repl) { @@ -434,12 +452,22 @@ bool SSARewriter::ApplyReplacements() { pass_->get_def_use_mgr()->GetDef(phi_candidate->var_id())); std::vector phi_operands; uint32_t arg_ix = 0; + std::unordered_map already_seen; for (uint32_t pred_label : pass_->cfg()->preds(phi_candidate->bb()->id())) { uint32_t op_val_id = GetPhiArgument(phi_candidate, arg_ix++); - phi_operands.push_back( - {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {op_val_id}}); - phi_operands.push_back( - {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {pred_label}}); + if (already_seen.count(pred_label) == 0) { + phi_operands.push_back( + {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {op_val_id}}); + phi_operands.push_back( + {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {pred_label}}); + already_seen[pred_label] = op_val_id; + } else { + // It is possible that there are two edges from the same parent block. + // Since the OpPhi can have only one entry for each parent, we have to + // make sure the two edges are consistent with each other. + assert(already_seen[pred_label] == op_val_id && + "Inconsistent value for duplicate edges."); + } } // Generate a new OpPhi instruction and insert it in its basic @@ -452,7 +480,6 @@ bool SSARewriter::ApplyReplacements() { pass_->context()->set_instr_block(&*phi_inst, phi_candidate->bb()); auto insert_it = phi_candidate->bb()->begin(); insert_it.InsertBefore(std::move(phi_inst)); - pass_->context()->get_decoration_mgr()->CloneDecorations( phi_candidate->var_id(), phi_candidate->result_id(), {SpvDecorationRelaxedPrecision}); @@ -543,7 +570,7 @@ void SSARewriter::FinalizePhiCandidates() { } } -bool SSARewriter::RewriteFunctionIntoSSA(Function* fp) { +Pass::Status SSARewriter::RewriteFunctionIntoSSA(Function* fp) { #if SSA_REWRITE_DEBUGGING_LEVEL > 0 std::cerr << "Function before SSA rewrite:\n" << fp->PrettyPrint(0) << "\n\n\n"; @@ -554,9 +581,17 @@ bool SSARewriter::RewriteFunctionIntoSSA(Function* fp) { // Generate all the SSA replacements and Phi candidates. This will // generate incomplete and trivial Phis. - pass_->cfg()->ForEachBlockInReversePostOrder( - fp->entry().get(), - [this](BasicBlock* bb) { GenerateSSAReplacements(bb); }); + bool succeeded = pass_->cfg()->WhileEachBlockInReversePostOrder( + fp->entry().get(), [this](BasicBlock* bb) { + if (!GenerateSSAReplacements(bb)) { + return false; + } + return true; + }); + + if (!succeeded) { + return Pass::Status::Failure; + } // Remove trivial Phis and add arguments to incomplete Phis. FinalizePhiCandidates(); @@ -569,17 +604,21 @@ bool SSARewriter::RewriteFunctionIntoSSA(Function* fp) { << fp->PrettyPrint(0) << "\n"; #endif - return modified; -} - -Pass::Status SSARewritePass::Process() { - bool modified = false; - for (auto& fn : *get_module()) { - modified |= SSARewriter(this).RewriteFunctionIntoSSA(&fn); - } return modified ? Pass::Status::SuccessWithChange : Pass::Status::SuccessWithoutChange; } +Pass::Status SSARewritePass::Process() { + Status status = Status::SuccessWithoutChange; + for (auto& fn : *get_module()) { + status = + CombineStatus(status, SSARewriter(this).RewriteFunctionIntoSSA(&fn)); + if (status == Status::Failure) { + break; + } + } + return status; +} + } // namespace opt } // namespace spvtools diff --git a/third_party/spirv-tools/source/opt/ssa_rewrite_pass.h b/third_party/spirv-tools/source/opt/ssa_rewrite_pass.h index c0373dc067..bbe89c8afa 100644 --- a/third_party/spirv-tools/source/opt/ssa_rewrite_pass.h +++ b/third_party/spirv-tools/source/opt/ssa_rewrite_pass.h @@ -46,9 +46,9 @@ class SSARewriter { // entry point for the SSA rewrite algorithm. SSA-target variables are // locally defined variables that meet the criteria set by IsSSATargetVar. // - // It returns true if function |fp| was modified. Otherwise, it returns - // false. - bool RewriteFunctionIntoSSA(Function* fp); + // Returns whether the function was modified or not, and whether or not the + // rewrite was successful. + Pass::Status RewriteFunctionIntoSSA(Function* fp); private: class PhiCandidate { @@ -128,8 +128,8 @@ class SSARewriter { // Generates all the SSA rewriting decisions for basic block |bb|. This // populates the Phi candidate table (|phi_candidate_|) and the load - // replacement table (|load_replacement_). - void GenerateSSAReplacements(BasicBlock* bb); + // replacement table (|load_replacement_). Returns true if successful. + bool GenerateSSAReplacements(BasicBlock* bb); // Seals block |bb|. Sealing a basic block means |bb| and all its // predecessors of |bb| have been scanned for loads/stores. @@ -188,6 +188,9 @@ class SSARewriter { // value |val_id|. void WriteVariable(uint32_t var_id, BasicBlock* bb, uint32_t val_id) { defs_at_block_[bb][var_id] = val_id; + if (auto* pc = GetPhiCandidate(val_id)) { + pc->AddUser(bb->id()); + } } // Processes the store operation |inst| in basic block |bb|. This extracts @@ -199,8 +202,8 @@ class SSARewriter { // Processes the load operation |inst| in basic block |bb|. This extracts // the variable ID being stored into, determines whether the variable is an // SSA-target variable, and, if it is, it reads its reaching definition by - // calling |GetReachingDef|. - void ProcessLoad(Instruction* inst, BasicBlock* bb); + // calling |GetReachingDef|. Returns true if successful. + bool ProcessLoad(Instruction* inst, BasicBlock* bb); // Reads the current definition for variable |var_id| in basic block |bb|. // If |var_id| is not defined in block |bb| it walks up the predecessors of diff --git a/third_party/spirv-tools/source/opt/strip_atomic_counter_memory_pass.cpp b/third_party/spirv-tools/source/opt/strip_atomic_counter_memory_pass.cpp new file mode 100644 index 0000000000..47714b7469 --- /dev/null +++ b/third_party/spirv-tools/source/opt/strip_atomic_counter_memory_pass.cpp @@ -0,0 +1,57 @@ +// Copyright (c) 2019 Google LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/opt/strip_atomic_counter_memory_pass.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace opt { + +Pass::Status StripAtomicCounterMemoryPass::Process() { + bool changed = false; + context()->module()->ForEachInst([this, &changed](Instruction* inst) { + auto indices = spvOpcodeMemorySemanticsOperandIndices(inst->opcode()); + if (indices.empty()) return; + + for (auto idx : indices) { + auto mem_sem_id = inst->GetSingleWordOperand(idx); + const auto& mem_sem_inst = + context()->get_def_use_mgr()->GetDef(mem_sem_id); + // The spec explicitly says that this id must be an OpConstant + auto mem_sem_val = mem_sem_inst->GetSingleWordOperand(2); + if (!(mem_sem_val & SpvMemorySemanticsAtomicCounterMemoryMask)) { + continue; + } + mem_sem_val &= ~SpvMemorySemanticsAtomicCounterMemoryMask; + + analysis::Integer int_type(32, false); + const analysis::Type* uint32_type = + context()->get_type_mgr()->GetRegisteredType(&int_type); + auto* new_const = context()->get_constant_mgr()->GetConstant( + uint32_type, {mem_sem_val}); + auto* new_const_inst = + context()->get_constant_mgr()->GetDefiningInstruction(new_const); + auto new_const_id = new_const_inst->result_id(); + + inst->SetOperand(idx, {new_const_id}); + context()->UpdateDefUse(inst); + changed = true; + } + }); + + return changed ? Status::SuccessWithChange : Status::SuccessWithoutChange; +} + +} // namespace opt +} // namespace spvtools diff --git a/third_party/spirv-tools/source/opt/strip_atomic_counter_memory_pass.h b/third_party/spirv-tools/source/opt/strip_atomic_counter_memory_pass.h new file mode 100644 index 0000000000..62e274a197 --- /dev/null +++ b/third_party/spirv-tools/source/opt/strip_atomic_counter_memory_pass.h @@ -0,0 +1,51 @@ +// Copyright (c) 2019 Google LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_OPT_STRIP_ATOMIC_COUNT_MEMORY_PASS_H_ +#define SOURCE_OPT_STRIP_ATOMIC_COUNT_MEMORY_PASS_H_ + +#include "source/opt/ir_context.h" +#include "source/opt/module.h" +#include "source/opt/pass.h" + +namespace spvtools { +namespace opt { + +// Removes the AtomicCounterMemory bit from the value being passed into memory +// semantics. This bit being set is ignored in Vulkan environments and +// forbidden WebGPU ones. +class StripAtomicCounterMemoryPass : public Pass { + public: + const char* name() const override { return "strip-atomic-counter-memory"; } + Status Process() override; + + IRContext::Analysis GetPreservedAnalyses() override { + return IRContext::kAnalysisInstrToBlockMapping | + IRContext::kAnalysisDecorations | IRContext::kAnalysisCombinators | + IRContext::kAnalysisCFG | IRContext::kAnalysisDominatorAnalysis | + IRContext::kAnalysisLoopAnalysis | IRContext::kAnalysisNameMap | + IRContext::kAnalysisScalarEvolution | + IRContext::kAnalysisRegisterPressure | + IRContext::kAnalysisValueNumberTable | + IRContext::kAnalysisStructuredCFG | + IRContext::kAnalysisBuiltinVarId | + IRContext::kAnalysisIdToFuncMapping | IRContext::kAnalysisTypes | + IRContext::kAnalysisDefUse | IRContext::kAnalysisConstants; + } +}; + +} // namespace opt +} // namespace spvtools + +#endif // SOURCE_OPT_STRIP_ATOMIC_COUNT_MEMORY_PASS_H_ diff --git a/third_party/spirv-tools/source/opt/strip_debug_info_pass.cpp b/third_party/spirv-tools/source/opt/strip_debug_info_pass.cpp index 5d9c5fec8a..c86ce57828 100644 --- a/third_party/spirv-tools/source/opt/strip_debug_info_pass.cpp +++ b/third_party/spirv-tools/source/opt/strip_debug_info_pass.cpp @@ -19,16 +19,89 @@ namespace spvtools { namespace opt { Pass::Status StripDebugInfoPass::Process() { - bool modified = !context()->debugs1().empty() || - !context()->debugs2().empty() || - !context()->debugs3().empty(); - context()->debug_clear(); + bool uses_non_semantic_info = false; + for (auto& inst : context()->module()->extensions()) { + const char* ext_name = + reinterpret_cast(&inst.GetInOperand(0).words[0]); + if (0 == std::strcmp(ext_name, "SPV_KHR_non_semantic_info")) { + uses_non_semantic_info = true; + } + } + std::vector to_kill; + + // if we use non-semantic info, it may reference OpString. Do a more + // expensive pass checking the uses of the OpString to see if any are + // OpExtInst on a non-semantic instruction set. If we're not using the + // extension then we can do a simpler pass and kill all debug1 instructions + if (uses_non_semantic_info) { + for (auto& inst : context()->module()->debugs1()) { + switch (inst.opcode()) { + case SpvOpString: { + analysis::DefUseManager* def_use = context()->get_def_use_mgr(); + + // see if this string is used anywhere by a non-semantic instruction + bool no_nonsemantic_use = + def_use->WhileEachUser(&inst, [def_use](Instruction* use) { + if (use->opcode() == SpvOpExtInst) { + auto ext_inst_set = + def_use->GetDef(use->GetSingleWordInOperand(0u)); + const char* extension_name = reinterpret_cast( + &ext_inst_set->GetInOperand(0).words[0]); + if (0 == std::strncmp(extension_name, "NonSemantic.", 12)) { + // found a non-semantic use, return false as we cannot + // remove this OpString + return false; + } + } + + // other instructions can't be a non-semantic use + return true; + }); + + if (no_nonsemantic_use) to_kill.push_back(&inst); + + break; + } + + default: + to_kill.push_back(&inst); + break; + } + } + } else { + for (auto& dbg : context()->debugs1()) to_kill.push_back(&dbg); + } + + for (auto& dbg : context()->debugs2()) to_kill.push_back(&dbg); + for (auto& dbg : context()->debugs3()) to_kill.push_back(&dbg); + for (auto& dbg : context()->ext_inst_debuginfo()) to_kill.push_back(&dbg); + + // OpName must come first, since they may refer to other debug instructions. + // If they are after the instructions that refer to, then they will be killed + // when that instruction is killed, which will lead to a double kill. + std::sort(to_kill.begin(), to_kill.end(), + [](Instruction* lhs, Instruction* rhs) -> bool { + if (lhs->opcode() == SpvOpName && rhs->opcode() != SpvOpName) + return true; + return false; + }); + + bool modified = !to_kill.empty(); + + for (auto* inst : to_kill) context()->KillInst(inst); + + // clear OpLine information context()->module()->ForEachInst([&modified](Instruction* inst) { modified |= !inst->dbg_line_insts().empty(); inst->dbg_line_insts().clear(); }); + if (!get_module()->trailing_dbg_line_info().empty()) { + modified = true; + get_module()->trailing_dbg_line_info().clear(); + } + return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange; } diff --git a/third_party/spirv-tools/source/opt/strip_reflect_info_pass.cpp b/third_party/spirv-tools/source/opt/strip_reflect_info_pass.cpp index 14ce31ff32..8b0f2db7ff 100644 --- a/third_party/spirv-tools/source/opt/strip_reflect_info_pass.cpp +++ b/third_party/spirv-tools/source/opt/strip_reflect_info_pass.cpp @@ -39,6 +39,14 @@ Pass::Status StripReflectInfoPass::Process() { } break; + case SpvOpMemberDecorateStringGOOGLE: + if (inst.GetSingleWordInOperand(2) == SpvDecorationHlslSemanticGOOGLE) { + to_remove.push_back(&inst); + } else { + other_uses_for_decorate_string = true; + } + break; + case SpvOpDecorateId: if (inst.GetSingleWordInOperand(1) == SpvDecorationHlslCounterBufferGOOGLE) { @@ -59,9 +67,55 @@ Pass::Status StripReflectInfoPass::Process() { } else if (!other_uses_for_decorate_string && 0 == std::strcmp(ext_name, "SPV_GOOGLE_decorate_string")) { to_remove.push_back(&inst); + } else if (0 == std::strcmp(ext_name, "SPV_KHR_non_semantic_info")) { + to_remove.push_back(&inst); } } + // clear all debug data now if it hasn't been cleared already, to remove any + // remaining OpString that may have been referenced by non-semantic extinsts + for (auto& dbg : context()->debugs1()) to_remove.push_back(&dbg); + for (auto& dbg : context()->debugs2()) to_remove.push_back(&dbg); + for (auto& dbg : context()->debugs3()) to_remove.push_back(&dbg); + for (auto& dbg : context()->ext_inst_debuginfo()) to_remove.push_back(&dbg); + + // remove any extended inst imports that are non semantic + std::unordered_set non_semantic_sets; + for (auto& inst : context()->module()->ext_inst_imports()) { + assert(inst.opcode() == SpvOpExtInstImport && + "Expecting an import of an extension's instruction set."); + const char* extension_name = + reinterpret_cast(&inst.GetInOperand(0).words[0]); + if (0 == std::strncmp(extension_name, "NonSemantic.", 12)) { + non_semantic_sets.insert(inst.result_id()); + to_remove.push_back(&inst); + } + } + + // if we removed some non-semantic sets, then iterate over the instructions in + // the module to remove any OpExtInst that referenced those sets + if (!non_semantic_sets.empty()) { + context()->module()->ForEachInst( + [&non_semantic_sets, &to_remove](Instruction* inst) { + if (inst->opcode() == SpvOpExtInst) { + if (non_semantic_sets.find(inst->GetSingleWordInOperand(0)) != + non_semantic_sets.end()) { + to_remove.push_back(inst); + } + } + }); + } + + // OpName must come first, since they may refer to other debug instructions. + // If they are after the instructions that refer to, then they will be killed + // when that instruction is killed, which will lead to a double kill. + std::sort(to_remove.begin(), to_remove.end(), + [](Instruction* lhs, Instruction* rhs) -> bool { + if (lhs->opcode() == SpvOpName && rhs->opcode() != SpvOpName) + return true; + return false; + }); + for (auto* inst : to_remove) { modified = true; context()->KillInst(inst); diff --git a/third_party/spirv-tools/source/opt/strip_reflect_info_pass.h b/third_party/spirv-tools/source/opt/strip_reflect_info_pass.h index 935a605e39..4e1999ed36 100644 --- a/third_party/spirv-tools/source/opt/strip_reflect_info_pass.h +++ b/third_party/spirv-tools/source/opt/strip_reflect_info_pass.h @@ -33,7 +33,8 @@ class StripReflectInfoPass : public Pass { return IRContext::kAnalysisInstrToBlockMapping | IRContext::kAnalysisCombinators | IRContext::kAnalysisCFG | IRContext::kAnalysisDominatorAnalysis | - IRContext::kAnalysisLoopAnalysis | IRContext::kAnalysisNameMap; + IRContext::kAnalysisLoopAnalysis | IRContext::kAnalysisNameMap | + IRContext::kAnalysisConstants | IRContext::kAnalysisTypes; } }; diff --git a/third_party/spirv-tools/source/opt/struct_cfg_analysis.cpp b/third_party/spirv-tools/source/opt/struct_cfg_analysis.cpp new file mode 100644 index 0000000000..b16322c1fa --- /dev/null +++ b/third_party/spirv-tools/source/opt/struct_cfg_analysis.cpp @@ -0,0 +1,219 @@ +// Copyright (c) 2018 Google LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/opt/struct_cfg_analysis.h" + +#include "source/opt/ir_context.h" + +namespace { +const uint32_t kMergeNodeIndex = 0; +const uint32_t kContinueNodeIndex = 1; +} // namespace + +namespace spvtools { +namespace opt { + +StructuredCFGAnalysis::StructuredCFGAnalysis(IRContext* ctx) : context_(ctx) { + // If this is not a shader, there are no merge instructions, and not + // structured CFG to analyze. + if (!context_->get_feature_mgr()->HasCapability(SpvCapabilityShader)) { + return; + } + + for (auto& func : *context_->module()) { + AddBlocksInFunction(&func); + } +} + +void StructuredCFGAnalysis::AddBlocksInFunction(Function* func) { + if (func->begin() == func->end()) return; + + std::list order; + context_->cfg()->ComputeStructuredOrder(func, &*func->begin(), &order); + + struct TraversalInfo { + ConstructInfo cinfo; + uint32_t merge_node; + uint32_t continue_node; + }; + + // Set up a stack to keep track of currently active constructs. + std::vector state; + state.emplace_back(); + state[0].cinfo.containing_construct = 0; + state[0].cinfo.containing_loop = 0; + state[0].cinfo.containing_switch = 0; + state[0].cinfo.in_continue = false; + state[0].merge_node = 0; + state[0].continue_node = 0; + + for (BasicBlock* block : order) { + if (context_->cfg()->IsPseudoEntryBlock(block) || + context_->cfg()->IsPseudoExitBlock(block)) { + continue; + } + + if (block->id() == state.back().merge_node) { + state.pop_back(); + } + + // This works because the structured order is designed to keep the blocks in + // the continue construct between the continue header and the merge node. + if (block->id() == state.back().continue_node) { + state.back().cinfo.in_continue = true; + } + + bb_to_construct_.emplace(std::make_pair(block->id(), state.back().cinfo)); + + if (Instruction* merge_inst = block->GetMergeInst()) { + TraversalInfo new_state; + new_state.merge_node = + merge_inst->GetSingleWordInOperand(kMergeNodeIndex); + new_state.cinfo.containing_construct = block->id(); + + if (merge_inst->opcode() == SpvOpLoopMerge) { + new_state.cinfo.containing_loop = block->id(); + new_state.cinfo.containing_switch = 0; + new_state.cinfo.in_continue = false; + new_state.continue_node = + merge_inst->GetSingleWordInOperand(kContinueNodeIndex); + } else { + new_state.cinfo.containing_loop = state.back().cinfo.containing_loop; + new_state.cinfo.in_continue = state.back().cinfo.in_continue; + new_state.continue_node = state.back().continue_node; + + if (merge_inst->NextNode()->opcode() == SpvOpSwitch) { + new_state.cinfo.containing_switch = block->id(); + } else { + new_state.cinfo.containing_switch = + state.back().cinfo.containing_switch; + } + } + + state.emplace_back(new_state); + merge_blocks_.Set(new_state.merge_node); + } + } +} + +uint32_t StructuredCFGAnalysis::ContainingConstruct(Instruction* inst) { + uint32_t bb = context_->get_instr_block(inst)->id(); + return ContainingConstruct(bb); +} + +uint32_t StructuredCFGAnalysis::MergeBlock(uint32_t bb_id) { + uint32_t header_id = ContainingConstruct(bb_id); + if (header_id == 0) { + return 0; + } + + BasicBlock* header = context_->cfg()->block(header_id); + Instruction* merge_inst = header->GetMergeInst(); + return merge_inst->GetSingleWordInOperand(kMergeNodeIndex); +} + +uint32_t StructuredCFGAnalysis::LoopMergeBlock(uint32_t bb_id) { + uint32_t header_id = ContainingLoop(bb_id); + if (header_id == 0) { + return 0; + } + + BasicBlock* header = context_->cfg()->block(header_id); + Instruction* merge_inst = header->GetMergeInst(); + return merge_inst->GetSingleWordInOperand(kMergeNodeIndex); +} + +uint32_t StructuredCFGAnalysis::LoopContinueBlock(uint32_t bb_id) { + uint32_t header_id = ContainingLoop(bb_id); + if (header_id == 0) { + return 0; + } + + BasicBlock* header = context_->cfg()->block(header_id); + Instruction* merge_inst = header->GetMergeInst(); + return merge_inst->GetSingleWordInOperand(kContinueNodeIndex); +} + +uint32_t StructuredCFGAnalysis::SwitchMergeBlock(uint32_t bb_id) { + uint32_t header_id = ContainingSwitch(bb_id); + if (header_id == 0) { + return 0; + } + + BasicBlock* header = context_->cfg()->block(header_id); + Instruction* merge_inst = header->GetMergeInst(); + return merge_inst->GetSingleWordInOperand(kMergeNodeIndex); +} + +bool StructuredCFGAnalysis::IsContinueBlock(uint32_t bb_id) { + assert(bb_id != 0); + return LoopContinueBlock(bb_id) == bb_id; +} + +bool StructuredCFGAnalysis::IsInContainingLoopsContinueConstruct( + uint32_t bb_id) { + auto it = bb_to_construct_.find(bb_id); + if (it == bb_to_construct_.end()) { + return false; + } + return it->second.in_continue; +} + +bool StructuredCFGAnalysis::IsInContinueConstruct(uint32_t bb_id) { + while (bb_id != 0) { + if (IsInContainingLoopsContinueConstruct(bb_id)) { + return true; + } + bb_id = ContainingLoop(bb_id); + } + return false; +} + +bool StructuredCFGAnalysis::IsMergeBlock(uint32_t bb_id) { + return merge_blocks_.Get(bb_id); +} + +std::unordered_set +StructuredCFGAnalysis::FindFuncsCalledFromContinue() { + std::unordered_set called_from_continue; + std::queue funcs_to_process; + + // First collect the functions that are called directly from a continue + // construct. + for (Function& func : *context_->module()) { + for (auto& bb : func) { + if (IsInContainingLoopsContinueConstruct(bb.id())) { + for (const Instruction& inst : bb) { + if (inst.opcode() == SpvOpFunctionCall) { + funcs_to_process.push(inst.GetSingleWordInOperand(0)); + } + } + } + } + } + + // Now collect all of the functions that are indirectly called as well. + while (!funcs_to_process.empty()) { + uint32_t func_id = funcs_to_process.front(); + funcs_to_process.pop(); + Function* func = context_->GetFunction(func_id); + if (called_from_continue.insert(func_id).second) { + context_->AddCalls(func, &funcs_to_process); + } + } + return called_from_continue; +} + +} // namespace opt +} // namespace spvtools diff --git a/third_party/spirv-tools/source/opt/struct_cfg_analysis.h b/third_party/spirv-tools/source/opt/struct_cfg_analysis.h new file mode 100644 index 0000000000..dfae6d4f28 --- /dev/null +++ b/third_party/spirv-tools/source/opt/struct_cfg_analysis.h @@ -0,0 +1,148 @@ +// Copyright (c) 2018 Google LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_OPT_STRUCT_CFG_ANALYSIS_H_ +#define SOURCE_OPT_STRUCT_CFG_ANALYSIS_H_ + +#include +#include + +#include "source/opt/function.h" +#include "source/util/bit_vector.h" + +namespace spvtools { +namespace opt { + +class IRContext; + +// An analysis that, for each basic block, finds the constructs in which it is +// contained, so we can easily get headers and merge nodes. +class StructuredCFGAnalysis { + public: + explicit StructuredCFGAnalysis(IRContext* ctx); + + // Returns the id of the header of the innermost merge construct + // that contains |bb_id|. Returns |0| if |bb_id| is not contained in any + // merge construct. + uint32_t ContainingConstruct(uint32_t bb_id) { + auto it = bb_to_construct_.find(bb_id); + if (it == bb_to_construct_.end()) { + return 0; + } + return it->second.containing_construct; + } + + // Returns the id of the header of the innermost merge construct + // that contains |inst|. Returns |0| if |inst| is not contained in any + // merge construct. + uint32_t ContainingConstruct(Instruction* inst); + + // Returns the id of the merge block of the innermost merge construct + // that contains |bb_id|. Returns |0| if |bb_id| is not contained in any + // merge construct. + uint32_t MergeBlock(uint32_t bb_id); + + // Returns the id of the header of the innermost loop construct + // that contains |bb_id|. Return |0| if |bb_id| is not contained in any loop + // construct. + uint32_t ContainingLoop(uint32_t bb_id) { + auto it = bb_to_construct_.find(bb_id); + if (it == bb_to_construct_.end()) { + return 0; + } + return it->second.containing_loop; + } + + // Returns the id of the merge block of the innermost loop construct + // that contains |bb_id|. Return |0| if |bb_id| is not contained in any loop + // construct. + uint32_t LoopMergeBlock(uint32_t bb_id); + + // Returns the id of the continue block of the innermost loop construct + // that contains |bb_id|. Return |0| if |bb_id| is not contained in any loop + // construct. + uint32_t LoopContinueBlock(uint32_t bb_id); + + // Returns the id of the header of the innermost switch construct + // that contains |bb_id| as long as there is no intervening loop. Returns |0| + // if no such construct exists. + uint32_t ContainingSwitch(uint32_t bb_id) { + auto it = bb_to_construct_.find(bb_id); + if (it == bb_to_construct_.end()) { + return 0; + } + return it->second.containing_switch; + } + // Returns the id of the merge block of the innermost switch construct + // that contains |bb_id| as long as there is no intervening loop. Return |0| + // if no such block exists. + uint32_t SwitchMergeBlock(uint32_t bb_id); + + // Returns true if |bb_id| is the continue block for a loop. + bool IsContinueBlock(uint32_t bb_id); + + // Returns true if |bb_id| is in the continue construct for its inner most + // containing loop. + bool IsInContainingLoopsContinueConstruct(uint32_t bb_id); + + // Returns true if |bb_id| is in the continue construct for any loop in its + // function. + bool IsInContinueConstruct(uint32_t bb_id); + + // Return true if |bb_id| is the merge block for a construct. + bool IsMergeBlock(uint32_t bb_id); + + // Returns the set of function ids that are called directly or indirectly from + // a continue construct. + std::unordered_set FindFuncsCalledFromContinue(); + + private: + // Struct used to hold the information for a basic block. + // |containing_construct| is the header for the innermost containing + // construct, or 0 if no such construct exists. It could be a selection + // construct or a loop construct. + // + // |containing_loop| is the innermost containing loop construct, or 0 if the + // basic bloc is not in a loop. If the basic block is in a selection + // construct that is contained in a loop construct, then these two values will + // not be the same. + // + // |containing_switch| is the innermost contain selection construct with an + // |OpSwitch| for the branch, as long as there is not intervening loop. This + // is used to identify the selection construct from which it can break. + // + // |in_continue| is true of the block is in the continue construct for its + // innermost containing loop. + struct ConstructInfo { + uint32_t containing_construct; + uint32_t containing_loop; + uint32_t containing_switch; + bool in_continue; + }; + + // Populates |bb_to_construct_| with the innermost containing merge and loop + // constructs for each basic block in |func|. + void AddBlocksInFunction(Function* func); + + IRContext* context_; + + // A map from a basic block to the headers of its inner most containing + // constructs. + std::unordered_map bb_to_construct_; + utils::BitVector merge_blocks_; +}; + +} // namespace opt +} // namespace spvtools +#endif // SOURCE_OPT_STRUCT_CFG_ANALYSIS_H_ diff --git a/third_party/spirv-tools/source/opt/type_manager.cpp b/third_party/spirv-tools/source/opt/type_manager.cpp index bd5221b043..166b8281f6 100644 --- a/third_party/spirv-tools/source/opt/type_manager.cpp +++ b/third_party/spirv-tools/source/opt/type_manager.cpp @@ -59,12 +59,20 @@ std::pair> TypeManager::GetTypeAndPointerType( uint32_t TypeManager::GetId(const Type* type) const { auto iter = type_to_id_.find(type); - if (iter != type_to_id_.end()) return (*iter).second; + if (iter != type_to_id_.end()) { + return (*iter).second; + } return 0; } void TypeManager::AnalyzeTypes(const Module& module) { - // First pass through the types. Any types that reference a forward pointer + // First pass through the constants, as some will be needed when traversing + // the types in the next pass. + for (const auto* inst : module.GetConstants()) { + id_to_constant_inst_[inst->result_id()] = inst; + } + + // Then pass through the types. Any types that reference a forward pointer // (directly or indirectly) are incomplete, and are added to incomplete types. for (const auto* inst : module.GetTypes()) { RecordIfTypeDefinition(*inst); @@ -152,7 +160,7 @@ void TypeManager::AnalyzeTypes(const Module& module) { #ifndef NDEBUG // Check if the type pool contains two types that are the same. This - // is an indication that the hashing and comparision are wrong. It + // is an indication that the hashing and comparison are wrong. It // will cause a problem if the type pool gets resized and everything // is rehashed. for (auto& i : type_pool_) { @@ -203,7 +211,12 @@ uint32_t TypeManager::GetTypeInstruction(const Type* type) { if (id != 0) return id; std::unique_ptr typeInst; + // TODO(1841): Handle id overflow. id = context()->TakeNextId(); + if (id == 0) { + return 0; + } + RegisterType(id, *type); switch (type->kind()) { #define DefineParameterlessCase(kind) \ @@ -220,6 +233,7 @@ uint32_t TypeManager::GetTypeInstruction(const Type* type) { DefineParameterlessCase(Queue); DefineParameterlessCase(PipeStorage); DefineParameterlessCase(NamedBarrier); + DefineParameterlessCase(AccelerationStructureNV); #undef DefineParameterlessCase case Type::kInteger: typeInst = MakeUnique( @@ -237,6 +251,9 @@ uint32_t TypeManager::GetTypeInstruction(const Type* type) { break; case Type::kVector: { uint32_t subtype = GetTypeInstruction(type->AsVector()->element_type()); + if (subtype == 0) { + return 0; + } typeInst = MakeUnique(context(), SpvOpTypeVector, 0, id, std::initializer_list{ @@ -247,6 +264,9 @@ uint32_t TypeManager::GetTypeInstruction(const Type* type) { } case Type::kMatrix: { uint32_t subtype = GetTypeInstruction(type->AsMatrix()->element_type()); + if (subtype == 0) { + return 0; + } typeInst = MakeUnique(context(), SpvOpTypeMatrix, 0, id, std::initializer_list{ @@ -258,6 +278,9 @@ uint32_t TypeManager::GetTypeInstruction(const Type* type) { case Type::kImage: { const Image* image = type->AsImage(); uint32_t subtype = GetTypeInstruction(image->sampled_type()); + if (subtype == 0) { + return 0; + } typeInst = MakeUnique( context(), SpvOpTypeImage, 0, id, std::initializer_list{ @@ -279,6 +302,9 @@ uint32_t TypeManager::GetTypeInstruction(const Type* type) { case Type::kSampledImage: { uint32_t subtype = GetTypeInstruction(type->AsSampledImage()->image_type()); + if (subtype == 0) { + return 0; + } typeInst = MakeUnique( context(), SpvOpTypeSampledImage, 0, id, std::initializer_list{{SPV_OPERAND_TYPE_ID, {subtype}}}); @@ -286,6 +312,9 @@ uint32_t TypeManager::GetTypeInstruction(const Type* type) { } case Type::kArray: { uint32_t subtype = GetTypeInstruction(type->AsArray()->element_type()); + if (subtype == 0) { + return 0; + } typeInst = MakeUnique( context(), SpvOpTypeArray, 0, id, std::initializer_list{ @@ -296,6 +325,9 @@ uint32_t TypeManager::GetTypeInstruction(const Type* type) { case Type::kRuntimeArray: { uint32_t subtype = GetTypeInstruction(type->AsRuntimeArray()->element_type()); + if (subtype == 0) { + return 0; + } typeInst = MakeUnique( context(), SpvOpTypeRuntimeArray, 0, id, std::initializer_list{{SPV_OPERAND_TYPE_ID, {subtype}}}); @@ -305,7 +337,11 @@ uint32_t TypeManager::GetTypeInstruction(const Type* type) { std::vector ops; const Struct* structTy = type->AsStruct(); for (auto ty : structTy->element_types()) { - ops.push_back(Operand(SPV_OPERAND_TYPE_ID, {GetTypeInstruction(ty)})); + uint32_t member_type_id = GetTypeInstruction(ty); + if (member_type_id == 0) { + return 0; + } + ops.push_back(Operand(SPV_OPERAND_TYPE_ID, {member_type_id})); } typeInst = MakeUnique(context(), SpvOpTypeStruct, 0, id, ops); @@ -327,6 +363,9 @@ uint32_t TypeManager::GetTypeInstruction(const Type* type) { case Type::kPointer: { const Pointer* pointer = type->AsPointer(); uint32_t subtype = GetTypeInstruction(pointer->pointee_type()); + if (subtype == 0) { + return 0; + } typeInst = MakeUnique( context(), SpvOpTypePointer, 0, id, std::initializer_list{ @@ -338,10 +377,17 @@ uint32_t TypeManager::GetTypeInstruction(const Type* type) { case Type::kFunction: { std::vector ops; const Function* function = type->AsFunction(); - ops.push_back(Operand(SPV_OPERAND_TYPE_ID, - {GetTypeInstruction(function->return_type())})); + uint32_t return_type_id = GetTypeInstruction(function->return_type()); + if (return_type_id == 0) { + return 0; + } + ops.push_back(Operand(SPV_OPERAND_TYPE_ID, {return_type_id})); for (auto ty : function->param_types()) { - ops.push_back(Operand(SPV_OPERAND_TYPE_ID, {GetTypeInstruction(ty)})); + uint32_t paramater_type_id = GetTypeInstruction(ty); + if (paramater_type_id == 0) { + return 0; + } + ops.push_back(Operand(SPV_OPERAND_TYPE_ID, {paramater_type_id})); } typeInst = MakeUnique(context(), SpvOpTypeFunction, 0, id, ops); @@ -363,6 +409,22 @@ uint32_t TypeManager::GetTypeInstruction(const Type* type) { {static_cast( type->AsForwardPointer()->storage_class())}}}); break; + case Type::kCooperativeMatrixNV: { + auto coop_mat = type->AsCooperativeMatrixNV(); + uint32_t const component_type = + GetTypeInstruction(coop_mat->component_type()); + if (component_type == 0) { + return 0; + } + typeInst = MakeUnique( + context(), SpvOpTypeCooperativeMatrixNV, 0, id, + std::initializer_list{ + {SPV_OPERAND_TYPE_ID, {component_type}}, + {SPV_OPERAND_TYPE_SCOPE_ID, {coop_mat->scope_id()}}, + {SPV_OPERAND_TYPE_ID, {coop_mat->rows_id()}}, + {SPV_OPERAND_TYPE_ID, {coop_mat->columns_id()}}}); + break; + } default: assert(false && "Unexpected type"); break; @@ -395,6 +457,7 @@ uint32_t TypeManager::FindPointerToType(uint32_t type_id, } // Must create the pointer type. + // TODO(1841): Handle id overflow. uint32_t resultId = context()->TakeNextId(); std::unique_ptr type_inst( new Instruction(context(), SpvOpTypePointer, 0, resultId, @@ -465,6 +528,7 @@ Type* TypeManager::RebuildType(const Type& type) { DefineNoSubtypeCase(Pipe); DefineNoSubtypeCase(PipeStorage); DefineNoSubtypeCase(NamedBarrier); + DefineNoSubtypeCase(AccelerationStructureNV); #undef DefineNoSubtypeCase case Type::kVector: { const Vector* vec_ty = type.AsVector(); @@ -498,9 +562,8 @@ Type* TypeManager::RebuildType(const Type& type) { } case Type::kArray: { const Array* array_ty = type.AsArray(); - const Type* ele_ty = array_ty->element_type(); rebuilt_ty = - MakeUnique(RebuildType(*ele_ty), array_ty->LengthId()); + MakeUnique(array_ty->element_type(), array_ty->length_info()); break; } case Type::kRuntimeArray: { @@ -557,6 +620,14 @@ Type* TypeManager::RebuildType(const Type& type) { } break; } + case Type::kCooperativeMatrixNV: { + const CooperativeMatrixNV* cm_type = type.AsCooperativeMatrixNV(); + const Type* component_type = cm_type->component_type(); + rebuilt_ty = MakeUnique( + RebuildType(*component_type), cm_type->scope_id(), cm_type->rows_id(), + cm_type->columns_id()); + break; + } default: assert(false && "Unhandled type"); return nullptr; @@ -583,6 +654,9 @@ void TypeManager::RegisterType(uint32_t id, const Type& type) { Type* TypeManager::GetRegisteredType(const Type* type) { uint32_t id = GetTypeInstruction(type); + if (id == 0) { + return nullptr; + } return GetType(id); } @@ -630,15 +704,56 @@ Type* TypeManager::RecordIfTypeDefinition(const Instruction& inst) { case SpvOpTypeSampledImage: type = new SampledImage(GetType(inst.GetSingleWordInOperand(0))); break; - case SpvOpTypeArray: - type = new Array(GetType(inst.GetSingleWordInOperand(0)), - inst.GetSingleWordInOperand(1)); + case SpvOpTypeArray: { + const uint32_t length_id = inst.GetSingleWordInOperand(1); + const Instruction* length_constant_inst = id_to_constant_inst_[length_id]; + assert(length_constant_inst); + + // How will we distinguish one length value from another? + // Determine extra words required to distinguish this array length + // from another. + std::vector extra_words{Array::LengthInfo::kDefiningId}; + // If it is a specialised constant, retrieve its SpecId. + // Only OpSpecConstant has a SpecId. + uint32_t spec_id = 0u; + bool has_spec_id = false; + if (length_constant_inst->opcode() == SpvOpSpecConstant) { + context()->get_decoration_mgr()->ForEachDecoration( + length_id, SpvDecorationSpecId, + [&spec_id, &has_spec_id](const Instruction& decoration) { + assert(decoration.opcode() == SpvOpDecorate); + spec_id = decoration.GetSingleWordOperand(2u); + has_spec_id = true; + }); + } + const auto opcode = length_constant_inst->opcode(); + if (has_spec_id) { + extra_words.push_back(spec_id); + } + if ((opcode == SpvOpConstant) || (opcode == SpvOpSpecConstant)) { + // Always include the literal constant words. In the spec constant + // case, the constant might not be overridden, so it's still + // significant. + extra_words.insert(extra_words.end(), + length_constant_inst->GetOperand(2).words.begin(), + length_constant_inst->GetOperand(2).words.end()); + extra_words[0] = has_spec_id ? Array::LengthInfo::kConstantWithSpecId + : Array::LengthInfo::kConstant; + } else { + assert(extra_words[0] == Array::LengthInfo::kDefiningId); + extra_words.push_back(length_id); + } + assert(extra_words.size() >= 2); + Array::LengthInfo length_info{length_id, extra_words}; + + type = new Array(GetType(inst.GetSingleWordInOperand(0)), length_info); + if (id_to_incomplete_type_.count(inst.GetSingleWordInOperand(0))) { incomplete_types_.emplace_back(inst.result_id(), type); id_to_incomplete_type_[inst.result_id()] = type; return type; } - break; + } break; case SpvOpTypeRuntimeArray: type = new RuntimeArray(GetType(inst.GetSingleWordInOperand(0))); if (id_to_incomplete_type_.count(inst.GetSingleWordInOperand(0))) { @@ -738,6 +853,15 @@ Type* TypeManager::RecordIfTypeDefinition(const Instruction& inst) { case SpvOpTypeNamedBarrier: type = new NamedBarrier(); break; + case SpvOpTypeAccelerationStructureNV: + type = new AccelerationStructureNV(); + break; + case SpvOpTypeCooperativeMatrixNV: + type = new CooperativeMatrixNV(GetType(inst.GetSingleWordInOperand(0)), + inst.GetSingleWordInOperand(1), + inst.GetSingleWordInOperand(2), + inst.GetSingleWordInOperand(3)); + break; default: SPIRV_UNIMPLEMENTED(consumer_, "unhandled type"); break; diff --git a/third_party/spirv-tools/source/opt/type_manager.h b/third_party/spirv-tools/source/opt/type_manager.h index c44969e84f..8fcf8aa632 100644 --- a/third_party/spirv-tools/source/opt/type_manager.h +++ b/third_party/spirv-tools/source/opt/type_manager.h @@ -101,7 +101,8 @@ class TypeManager { std::pair> GetTypeAndPointerType( uint32_t id, SpvStorageClass sc) const; - // Returns an id for a declaration representing |type|. + // Returns an id for a declaration representing |type|. Returns 0 if the type + // does not exists, and could not be generated. // // If |type| is registered, then the registered id is returned. Otherwise, // this function recursively adds type and annotation instructions as @@ -109,7 +110,8 @@ class TypeManager { uint32_t GetTypeInstruction(const Type* type); // Find pointer to type and storage in module, return its resultId. If it is - // not found, a new type is created, and its id is returned. + // not found, a new type is created, and its id is returned. Returns 0 if the + // type could not be created. uint32_t FindPointerToType(uint32_t type_id, SpvStorageClass storage_class); // Registers |id| to |type|. @@ -118,6 +120,7 @@ class TypeManager { // unchanged. void RegisterType(uint32_t id, const Type& type); + // Return the registered type object that is the same as |type|. Type* GetRegisteredType(const Type* type); // Removes knowledge of |id| from the manager. @@ -136,6 +139,61 @@ class TypeManager { const Type* GetMemberType(const Type* parent_type, const std::vector& access_chain); + Type* GetUIntType() { + Integer int_type(32, false); + return GetRegisteredType(&int_type); + } + + uint32_t GetUIntTypeId() { return GetTypeInstruction(GetUIntType()); } + + Type* GetSIntType() { + Integer int_type(32, true); + return GetRegisteredType(&int_type); + } + + uint32_t GetSIntTypeId() { return GetTypeInstruction(GetSIntType()); } + + Type* GetFloatType() { + Float float_type(32); + return GetRegisteredType(&float_type); + } + + uint32_t GetFloatTypeId() { return GetTypeInstruction(GetFloatType()); } + + Type* GetUIntVectorType(uint32_t size) { + Vector vec_type(GetUIntType(), size); + return GetRegisteredType(&vec_type); + } + + uint32_t GetUIntVectorTypeId(uint32_t size) { + return GetTypeInstruction(GetUIntVectorType(size)); + } + + Type* GetSIntVectorType(uint32_t size) { + Vector vec_type(GetSIntType(), size); + return GetRegisteredType(&vec_type); + } + + uint32_t GetSIntVectorTypeId(uint32_t size) { + return GetTypeInstruction(GetSIntVectorType(size)); + } + + Type* GetFloatVectorType(uint32_t size) { + Vector vec_type(GetFloatType(), size); + return GetRegisteredType(&vec_type); + } + + uint32_t GetFloatVectorTypeId(uint32_t size) { + return GetTypeInstruction(GetFloatVectorType(size)); + } + + Type* GetBoolType() { + Bool bool_type; + return GetRegisteredType(&bool_type); + } + + uint32_t GetBoolTypeId() { return GetTypeInstruction(GetBoolType()); } + private: using TypeToIdMap = std::unordered_map; @@ -209,6 +267,8 @@ class TypeManager { IdToTypeMap id_to_incomplete_type_; // Maps ids to their type representations // for incomplete types. + + std::unordered_map id_to_constant_inst_; }; } // namespace analysis diff --git a/third_party/spirv-tools/source/opt/types.cpp b/third_party/spirv-tools/source/opt/types.cpp index 15cff54864..17f8fe920f 100644 --- a/third_party/spirv-tools/source/opt/types.cpp +++ b/third_party/spirv-tools/source/opt/types.cpp @@ -12,14 +12,17 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include "source/opt/types.h" + #include #include #include #include +#include #include -#include "source/opt/types.h" #include "source/util/make_unique.h" +#include "spirv/unified1/spirv.h" namespace spvtools { namespace opt { @@ -99,7 +102,7 @@ std::unique_ptr Type::Clone() const { #define DeclareKindCase(kind) \ case k##kind: \ type = MakeUnique(*this->As##kind()); \ - break; + break DeclareKindCase(Void); DeclareKindCase(Bool); DeclareKindCase(Integer); @@ -123,6 +126,8 @@ std::unique_ptr Type::Clone() const { DeclareKindCase(ForwardPointer); DeclareKindCase(PipeStorage); DeclareKindCase(NamedBarrier); + DeclareKindCase(AccelerationStructureNV); + DeclareKindCase(CooperativeMatrixNV); #undef DeclareKindCase default: assert(false && "Unhandled type"); @@ -142,7 +147,7 @@ bool Type::operator==(const Type& other) const { switch (kind_) { #define DeclareKindCase(kind) \ case k##kind: \ - return As##kind()->IsSame(&other); + return As##kind()->IsSame(&other) DeclareKindCase(Void); DeclareKindCase(Bool); DeclareKindCase(Integer); @@ -166,6 +171,8 @@ bool Type::operator==(const Type& other) const { DeclareKindCase(ForwardPointer); DeclareKindCase(PipeStorage); DeclareKindCase(NamedBarrier); + DeclareKindCase(AccelerationStructureNV); + DeclareKindCase(CooperativeMatrixNV); #undef DeclareKindCase default: assert(false && "Unhandled type"); @@ -190,7 +197,7 @@ void Type::GetHashWords(std::vector* words, #define DeclareKindCase(type) \ case k##type: \ As##type()->GetExtraHashWords(words, seen); \ - break; + break DeclareKindCase(Void); DeclareKindCase(Bool); DeclareKindCase(Integer); @@ -214,6 +221,8 @@ void Type::GetHashWords(std::vector* words, DeclareKindCase(ForwardPointer); DeclareKindCase(PipeStorage); DeclareKindCase(NamedBarrier); + DeclareKindCase(AccelerationStructureNV); + DeclareKindCase(CooperativeMatrixNV); #undef DeclareKindCase default: assert(false && "Unhandled type"); @@ -268,7 +277,7 @@ void Float::GetExtraHashWords(std::vector* words, words->push_back(width_); } -Vector::Vector(Type* type, uint32_t count) +Vector::Vector(const Type* type, uint32_t count) : Type(kVector), element_type_(type), count_(count) { assert(type->AsBool() || type->AsInteger() || type->AsFloat()); } @@ -293,7 +302,7 @@ void Vector::GetExtraHashWords(std::vector* words, words->push_back(count_); } -Matrix::Matrix(Type* type, uint32_t count) +Matrix::Matrix(const Type* type, uint32_t count) : Type(kMatrix), element_type_(type), count_(count) { assert(type->AsVector()); } @@ -380,34 +389,47 @@ void SampledImage::GetExtraHashWords( image_type_->GetHashWords(words, seen); } -Array::Array(Type* type, uint32_t length_id) - : Type(kArray), element_type_(type), length_id_(length_id) { +Array::Array(const Type* type, const Array::LengthInfo& length_info_arg) + : Type(kArray), element_type_(type), length_info_(length_info_arg) { + assert(type != nullptr); assert(!type->AsVoid()); + // We always have a word to say which case we're in, followed + // by at least one more word. + assert(length_info_arg.words.size() >= 2); } bool Array::IsSameImpl(const Type* that, IsSameCache* seen) const { const Array* at = that->AsArray(); if (!at) return false; - return length_id_ == at->length_id_ && - element_type_->IsSameImpl(at->element_type_, seen) && - HasSameDecorations(that); + bool is_same = element_type_->IsSameImpl(at->element_type_, seen); + is_same = is_same && HasSameDecorations(that); + is_same = is_same && (length_info_.words == at->length_info_.words); + return is_same; } std::string Array::str() const { std::ostringstream oss; - oss << "[" << element_type_->str() << ", id(" << length_id_ << ")]"; + oss << "[" << element_type_->str() << ", id(" << LengthId() << "), words("; + const char* spacer = ""; + for (auto w : length_info_.words) { + oss << spacer << w; + spacer = ","; + } + oss << ")]"; return oss.str(); } void Array::GetExtraHashWords(std::vector* words, std::unordered_set* seen) const { element_type_->GetHashWords(words, seen); - words->push_back(length_id_); + // This should mirror the logic in IsSameImpl + words->insert(words->end(), length_info_.words.begin(), + length_info_.words.end()); } void Array::ReplaceElementType(const Type* type) { element_type_ = type; } -RuntimeArray::RuntimeArray(Type* type) +RuntimeArray::RuntimeArray(const Type* type) : Type(kRuntimeArray), element_type_(type) { assert(!type->AsVoid()); } @@ -537,7 +559,12 @@ bool Pointer::IsSameImpl(const Type* that, IsSameCache* seen) const { return HasSameDecorations(that); } -std::string Pointer::str() const { return pointee_type_->str() + "*"; } +std::string Pointer::str() const { + std::ostringstream os; + os << pointee_type_->str() << " " << static_cast(storage_class_) + << "*"; + return os.str(); +} void Pointer::GetExtraHashWords(std::vector* words, std::unordered_set* seen) const { @@ -547,13 +574,11 @@ void Pointer::GetExtraHashWords(std::vector* words, void Pointer::SetPointeeType(const Type* type) { pointee_type_ = type; } -Function::Function(Type* ret_type, const std::vector& params) - : Type(kFunction), return_type_(ret_type), param_types_(params) { - for (auto* t : params) { - (void)t; - assert(!t->AsVoid()); - } -} +Function::Function(const Type* ret_type, const std::vector& params) + : Type(kFunction), return_type_(ret_type), param_types_(params) {} + +Function::Function(const Type* ret_type, std::vector& params) + : Type(kFunction), return_type_(ret_type), param_types_(params) {} bool Function::IsSameImpl(const Type* that, IsSameCache* seen) const { const Function* ft = that->AsFunction(); @@ -608,7 +633,8 @@ void Pipe::GetExtraHashWords(std::vector* words, bool ForwardPointer::IsSameImpl(const Type* that, IsSameCache*) const { const ForwardPointer* fpt = that->AsForwardPointer(); if (!fpt) return false; - return target_id_ == fpt->target_id_ && + return (pointer_ && fpt->pointer_ ? *pointer_ == *fpt->pointer_ + : target_id_ == fpt->target_id_) && storage_class_ == fpt->storage_class_ && HasSameDecorations(that); } @@ -631,6 +657,44 @@ void ForwardPointer::GetExtraHashWords( if (pointer_) pointer_->GetHashWords(words, seen); } +CooperativeMatrixNV::CooperativeMatrixNV(const Type* type, const uint32_t scope, + const uint32_t rows, + const uint32_t columns) + : Type(kCooperativeMatrixNV), + component_type_(type), + scope_id_(scope), + rows_id_(rows), + columns_id_(columns) { + assert(type != nullptr); + assert(scope != 0); + assert(rows != 0); + assert(columns != 0); +} + +std::string CooperativeMatrixNV::str() const { + std::ostringstream oss; + oss << "<" << component_type_->str() << ", " << scope_id_ << ", " << rows_id_ + << ", " << columns_id_ << ">"; + return oss.str(); +} + +void CooperativeMatrixNV::GetExtraHashWords( + std::vector* words, std::unordered_set* pSet) const { + component_type_->GetHashWords(words, pSet); + words->push_back(scope_id_); + words->push_back(rows_id_); + words->push_back(columns_id_); +} + +bool CooperativeMatrixNV::IsSameImpl(const Type* that, + IsSameCache* seen) const { + const CooperativeMatrixNV* mt = that->AsCooperativeMatrixNV(); + if (!mt) return false; + return component_type_->IsSameImpl(mt->component_type_, seen) && + scope_id_ == mt->scope_id_ && rows_id_ == mt->rows_id_ && + columns_id_ == mt->columns_id_ && HasSameDecorations(that); +} + } // namespace analysis } // namespace opt } // namespace spvtools diff --git a/third_party/spirv-tools/source/opt/types.h b/third_party/spirv-tools/source/opt/types.h index 625f342a68..69071ea177 100644 --- a/third_party/spirv-tools/source/opt/types.h +++ b/third_party/spirv-tools/source/opt/types.h @@ -27,6 +27,7 @@ #include #include "source/latest_version_spirv_header.h" +#include "source/opt/instruction.h" #include "spirv-tools/libspirv.h" namespace spvtools { @@ -56,6 +57,8 @@ class Pipe; class ForwardPointer; class PipeStorage; class NamedBarrier; +class AccelerationStructureNV; +class CooperativeMatrixNV; // Abstract class for a SPIR-V type. It has a bunch of As() methods, // which is used as a way to probe the actual . @@ -90,6 +93,8 @@ class Type { kForwardPointer, kPipeStorage, kNamedBarrier, + kAccelerationStructureNV, + kCooperativeMatrixNV }; Type(Kind k) : kind_(k) {} @@ -142,36 +147,6 @@ class Type { // TODO(alanbaker): Update this if variable pointers become a core feature. bool IsUniqueType(bool allowVariablePointers = false) const; -// A bunch of methods for casting this type to a given type. Returns this if the -// cast can be done, nullptr otherwise. -#define DeclareCastMethod(target) \ - virtual target* As##target() { return nullptr; } \ - virtual const target* As##target() const { return nullptr; } - DeclareCastMethod(Void); - DeclareCastMethod(Bool); - DeclareCastMethod(Integer); - DeclareCastMethod(Float); - DeclareCastMethod(Vector); - DeclareCastMethod(Matrix); - DeclareCastMethod(Image); - DeclareCastMethod(Sampler); - DeclareCastMethod(SampledImage); - DeclareCastMethod(Array); - DeclareCastMethod(RuntimeArray); - DeclareCastMethod(Struct); - DeclareCastMethod(Opaque); - DeclareCastMethod(Pointer); - DeclareCastMethod(Function); - DeclareCastMethod(Event); - DeclareCastMethod(DeviceEvent); - DeclareCastMethod(ReserveId); - DeclareCastMethod(Queue); - DeclareCastMethod(Pipe); - DeclareCastMethod(ForwardPointer); - DeclareCastMethod(PipeStorage); - DeclareCastMethod(NamedBarrier); -#undef DeclareCastMethod - bool operator==(const Type& other) const; // Returns the hash value of this type. @@ -193,6 +168,39 @@ class Type { std::vector* words, std::unordered_set* pSet) const = 0; +// A bunch of methods for casting this type to a given type. Returns this if the +// cast can be done, nullptr otherwise. +// clang-format off +#define DeclareCastMethod(target) \ + virtual target* As##target() { return nullptr; } \ + virtual const target* As##target() const { return nullptr; } + DeclareCastMethod(Void) + DeclareCastMethod(Bool) + DeclareCastMethod(Integer) + DeclareCastMethod(Float) + DeclareCastMethod(Vector) + DeclareCastMethod(Matrix) + DeclareCastMethod(Image) + DeclareCastMethod(Sampler) + DeclareCastMethod(SampledImage) + DeclareCastMethod(Array) + DeclareCastMethod(RuntimeArray) + DeclareCastMethod(Struct) + DeclareCastMethod(Opaque) + DeclareCastMethod(Pointer) + DeclareCastMethod(Function) + DeclareCastMethod(Event) + DeclareCastMethod(DeviceEvent) + DeclareCastMethod(ReserveId) + DeclareCastMethod(Queue) + DeclareCastMethod(Pipe) + DeclareCastMethod(ForwardPointer) + DeclareCastMethod(PipeStorage) + DeclareCastMethod(NamedBarrier) + DeclareCastMethod(AccelerationStructureNV) + DeclareCastMethod(CooperativeMatrixNV) +#undef DeclareCastMethod + protected: // Decorations attached to this type. Each decoration is encoded as a vector // of uint32_t numbers. The first uint32_t number is the decoration value, @@ -206,6 +214,7 @@ class Type { Kind kind_; }; +// clang-format on class Integer : public Type { public: @@ -252,7 +261,7 @@ class Float : public Type { class Vector : public Type { public: - Vector(Type* element_type, uint32_t count); + Vector(const Type* element_type, uint32_t count); Vector(const Vector&) = default; std::string str() const override; @@ -274,7 +283,7 @@ class Vector : public Type { class Matrix : public Type { public: - Matrix(Type* element_type, uint32_t count); + Matrix(const Type* element_type, uint32_t count); Matrix(const Matrix&) = default; std::string str() const override; @@ -353,12 +362,36 @@ class SampledImage : public Type { class Array : public Type { public: - Array(Type* element_type, uint32_t length_id); + // Data about the length operand, that helps us distinguish between one + // array length and another. + struct LengthInfo { + // The result id of the instruction defining the length. + const uint32_t id; + enum Case : uint32_t { + kConstant = 0, + kConstantWithSpecId = 1, + kDefiningId = 2 + }; + // Extra words used to distinshish one array length and another. + // - if OpConstant, then it's 0, then the words in the literal constant + // value. + // - if OpSpecConstant, then it's 1, then the SpecID decoration if there + // is one, followed by the words in the literal constant value. + // The spec might not be overridden, in which case we'll end up using + // the literal value. + // - Otherwise, it's an OpSpecConsant, and this 2, then the ID (again). + const std::vector words; + }; + + // Constructs an array type with given element and length. If the length + // is an OpSpecConstant, then |spec_id| should be its SpecId decoration. + Array(const Type* element_type, const LengthInfo& length_info_arg); Array(const Array&) = default; std::string str() const override; const Type* element_type() const { return element_type_; } - uint32_t LengthId() const { return length_id_; } + uint32_t LengthId() const { return length_info_.id; } + const LengthInfo& length_info() const { return length_info_; } Array* AsArray() override { return this; } const Array* AsArray() const override { return this; } @@ -372,12 +405,12 @@ class Array : public Type { bool IsSameImpl(const Type* that, IsSameCache*) const override; const Type* element_type_; - uint32_t length_id_; + const LengthInfo length_info_; }; class RuntimeArray : public Type { public: - RuntimeArray(Type* element_type); + RuntimeArray(const Type* element_type); RuntimeArray(const RuntimeArray&) = default; std::string str() const override; @@ -490,7 +523,8 @@ class Pointer : public Type { class Function : public Type { public: - Function(Type* ret_type, const std::vector& params); + Function(const Type* ret_type, const std::vector& params); + Function(const Type* ret_type, std::vector& params); Function(const Function&) = default; std::string str() const override; @@ -566,6 +600,36 @@ class ForwardPointer : public Type { const Pointer* pointer_; }; +class CooperativeMatrixNV : public Type { + public: + CooperativeMatrixNV(const Type* type, const uint32_t scope, + const uint32_t rows, const uint32_t columns); + CooperativeMatrixNV(const CooperativeMatrixNV&) = default; + + std::string str() const override; + + CooperativeMatrixNV* AsCooperativeMatrixNV() override { return this; } + const CooperativeMatrixNV* AsCooperativeMatrixNV() const override { + return this; + } + + void GetExtraHashWords(std::vector*, + std::unordered_set*) const override; + + const Type* component_type() const { return component_type_; } + uint32_t scope_id() const { return scope_id_; } + uint32_t rows_id() const { return rows_id_; } + uint32_t columns_id() const { return columns_id_; } + + private: + bool IsSameImpl(const Type* that, IsSameCache*) const override; + + const Type* component_type_; + const uint32_t scope_id_; + const uint32_t rows_id_; + const uint32_t columns_id_; +}; + #define DefineParameterlessType(type, name) \ class type : public Type { \ public: \ @@ -594,6 +658,7 @@ DefineParameterlessType(ReserveId, reserve_id); DefineParameterlessType(Queue, queue); DefineParameterlessType(PipeStorage, pipe_storage); DefineParameterlessType(NamedBarrier, named_barrier); +DefineParameterlessType(AccelerationStructureNV, accelerationStructureNV); #undef DefineParameterlessType } // namespace analysis diff --git a/third_party/spirv-tools/source/opt/upgrade_memory_model.cpp b/third_party/spirv-tools/source/opt/upgrade_memory_model.cpp new file mode 100644 index 0000000000..ab252059fa --- /dev/null +++ b/third_party/spirv-tools/source/opt/upgrade_memory_model.cpp @@ -0,0 +1,770 @@ +// Copyright (c) 2018 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 "upgrade_memory_model.h" + +#include + +#include "source/opt/ir_builder.h" +#include "source/opt/ir_context.h" +#include "source/spirv_constant.h" +#include "source/util/make_unique.h" + +namespace spvtools { +namespace opt { + +Pass::Status UpgradeMemoryModel::Process() { + // TODO: This pass needs changes to support cooperative matrices. + if (context()->get_feature_mgr()->HasCapability( + SpvCapabilityCooperativeMatrixNV)) { + return Pass::Status::SuccessWithoutChange; + } + + // Only update Logical GLSL450 to Logical VulkanKHR. + Instruction* memory_model = get_module()->GetMemoryModel(); + if (memory_model->GetSingleWordInOperand(0u) != SpvAddressingModelLogical || + memory_model->GetSingleWordInOperand(1u) != SpvMemoryModelGLSL450) { + return Pass::Status::SuccessWithoutChange; + } + + UpgradeMemoryModelInstruction(); + UpgradeInstructions(); + CleanupDecorations(); + UpgradeBarriers(); + UpgradeMemoryScope(); + + return Pass::Status::SuccessWithChange; +} + +void UpgradeMemoryModel::UpgradeMemoryModelInstruction() { + // Overall changes necessary: + // 1. Add the OpExtension. + // 2. Add the OpCapability. + // 3. Modify the memory model. + Instruction* memory_model = get_module()->GetMemoryModel(); + context()->AddCapability(MakeUnique( + context(), SpvOpCapability, 0, 0, + std::initializer_list{ + {SPV_OPERAND_TYPE_CAPABILITY, {SpvCapabilityVulkanMemoryModelKHR}}})); + const std::string extension = "SPV_KHR_vulkan_memory_model"; + std::vector words(extension.size() / 4 + 1, 0); + char* dst = reinterpret_cast(words.data()); + strncpy(dst, extension.c_str(), extension.size()); + context()->AddExtension( + MakeUnique(context(), SpvOpExtension, 0, 0, + std::initializer_list{ + {SPV_OPERAND_TYPE_LITERAL_STRING, words}})); + memory_model->SetInOperand(1u, {SpvMemoryModelVulkanKHR}); +} + +void UpgradeMemoryModel::UpgradeInstructions() { + // Coherent and Volatile decorations are deprecated. Remove them and replace + // with flags on the memory/image operations. The decorations can occur on + // OpVariable, OpFunctionParameter (of pointer type) and OpStructType (member + // decoration). Trace from the decoration target(s) to the final memory/image + // instructions. Additionally, Workgroup storage class variables and function + // parameters are implicitly coherent in GLSL450. + + // Upgrade modf and frexp first since they generate new stores. + // In SPIR-V 1.4 or later, normalize OpCopyMemory* access operands. + for (auto& func : *get_module()) { + func.ForEachInst([this](Instruction* inst) { + if (inst->opcode() == SpvOpExtInst) { + auto ext_inst = inst->GetSingleWordInOperand(1u); + if (ext_inst == GLSLstd450Modf || ext_inst == GLSLstd450Frexp) { + auto import = + get_def_use_mgr()->GetDef(inst->GetSingleWordInOperand(0u)); + if (reinterpret_cast(import->GetInOperand(0u).words.data()) == + std::string("GLSL.std.450")) { + UpgradeExtInst(inst); + } + } + } else if (get_module()->version() >= SPV_SPIRV_VERSION_WORD(1, 4)) { + if (inst->opcode() == SpvOpCopyMemory || + inst->opcode() == SpvOpCopyMemorySized) { + uint32_t start_operand = inst->opcode() == SpvOpCopyMemory ? 2u : 3u; + if (inst->NumInOperands() > start_operand) { + auto num_access_words = MemoryAccessNumWords( + inst->GetSingleWordInOperand(start_operand)); + if ((num_access_words + start_operand) == inst->NumInOperands()) { + // There is a single memory access operand. Duplicate it to have a + // separate operand for both source and target. + for (uint32_t i = 0; i < num_access_words; ++i) { + auto operand = inst->GetInOperand(start_operand + i); + inst->AddOperand(std::move(operand)); + } + } + } else { + // Add two memory access operands. + inst->AddOperand( + {SPV_OPERAND_TYPE_MEMORY_ACCESS, {SpvMemoryAccessMaskNone}}); + inst->AddOperand( + {SPV_OPERAND_TYPE_MEMORY_ACCESS, {SpvMemoryAccessMaskNone}}); + } + } + } + }); + } + + UpgradeMemoryAndImages(); + UpgradeAtomics(); +} + +void UpgradeMemoryModel::UpgradeMemoryAndImages() { + for (auto& func : *get_module()) { + func.ForEachInst([this](Instruction* inst) { + bool is_coherent = false; + bool is_volatile = false; + bool src_coherent = false; + bool src_volatile = false; + bool dst_coherent = false; + bool dst_volatile = false; + uint32_t start_operand = 0u; + SpvScope scope = SpvScopeQueueFamilyKHR; + SpvScope src_scope = SpvScopeQueueFamilyKHR; + SpvScope dst_scope = SpvScopeQueueFamilyKHR; + switch (inst->opcode()) { + case SpvOpLoad: + case SpvOpStore: + std::tie(is_coherent, is_volatile, scope) = + GetInstructionAttributes(inst->GetSingleWordInOperand(0u)); + break; + case SpvOpImageRead: + case SpvOpImageSparseRead: + case SpvOpImageWrite: + std::tie(is_coherent, is_volatile, scope) = + GetInstructionAttributes(inst->GetSingleWordInOperand(0u)); + break; + case SpvOpCopyMemory: + case SpvOpCopyMemorySized: + std::tie(dst_coherent, dst_volatile, dst_scope) = + GetInstructionAttributes(inst->GetSingleWordInOperand(0u)); + std::tie(src_coherent, src_volatile, src_scope) = + GetInstructionAttributes(inst->GetSingleWordInOperand(1u)); + break; + default: + break; + } + + switch (inst->opcode()) { + case SpvOpLoad: + UpgradeFlags(inst, 1u, is_coherent, is_volatile, kVisibility, + kMemory); + break; + case SpvOpStore: + UpgradeFlags(inst, 2u, is_coherent, is_volatile, kAvailability, + kMemory); + break; + case SpvOpCopyMemory: + case SpvOpCopyMemorySized: + start_operand = inst->opcode() == SpvOpCopyMemory ? 2u : 3u; + if (get_module()->version() >= SPV_SPIRV_VERSION_WORD(1, 4)) { + // There are guaranteed to be two memory access operands at this + // point so treat source and target separately. + uint32_t num_access_words = MemoryAccessNumWords( + inst->GetSingleWordInOperand(start_operand)); + UpgradeFlags(inst, start_operand, dst_coherent, dst_volatile, + kAvailability, kMemory); + UpgradeFlags(inst, start_operand + num_access_words, src_coherent, + src_volatile, kVisibility, kMemory); + } else { + UpgradeFlags(inst, start_operand, dst_coherent, dst_volatile, + kAvailability, kMemory); + UpgradeFlags(inst, start_operand, src_coherent, src_volatile, + kVisibility, kMemory); + } + break; + case SpvOpImageRead: + case SpvOpImageSparseRead: + UpgradeFlags(inst, 2u, is_coherent, is_volatile, kVisibility, kImage); + break; + case SpvOpImageWrite: + UpgradeFlags(inst, 3u, is_coherent, is_volatile, kAvailability, + kImage); + break; + default: + break; + } + + // |is_coherent| is never used for the same instructions as + // |src_coherent| and |dst_coherent|. + if (is_coherent) { + inst->AddOperand( + {SPV_OPERAND_TYPE_SCOPE_ID, {GetScopeConstant(scope)}}); + } + if (get_module()->version() >= SPV_SPIRV_VERSION_WORD(1, 4)) { + // There are two memory access operands. The first is for the target and + // the second is for the source. + if (dst_coherent || src_coherent) { + start_operand = inst->opcode() == SpvOpCopyMemory ? 2u : 3u; + std::vector new_operands; + uint32_t num_access_words = + MemoryAccessNumWords(inst->GetSingleWordInOperand(start_operand)); + // The flags were already updated so subtract if we're adding a + // scope. + if (dst_coherent) --num_access_words; + for (uint32_t i = 0; i < start_operand + num_access_words; ++i) { + new_operands.push_back(inst->GetInOperand(i)); + } + // Add the target scope if necessary. + if (dst_coherent) { + new_operands.push_back( + {SPV_OPERAND_TYPE_SCOPE_ID, {GetScopeConstant(dst_scope)}}); + } + // Copy the remaining current operands. + for (uint32_t i = start_operand + num_access_words; + i < inst->NumInOperands(); ++i) { + new_operands.push_back(inst->GetInOperand(i)); + } + // Add the source scope if necessary. + if (src_coherent) { + new_operands.push_back( + {SPV_OPERAND_TYPE_SCOPE_ID, {GetScopeConstant(src_scope)}}); + } + inst->SetInOperands(std::move(new_operands)); + } + } else { + // According to SPV_KHR_vulkan_memory_model, if both available and + // visible flags are used the first scope operand is for availability + // (writes) and the second is for visibility (reads). + if (dst_coherent) { + inst->AddOperand( + {SPV_OPERAND_TYPE_SCOPE_ID, {GetScopeConstant(dst_scope)}}); + } + if (src_coherent) { + inst->AddOperand( + {SPV_OPERAND_TYPE_SCOPE_ID, {GetScopeConstant(src_scope)}}); + } + } + }); + } +} + +void UpgradeMemoryModel::UpgradeAtomics() { + for (auto& func : *get_module()) { + func.ForEachInst([this](Instruction* inst) { + if (spvOpcodeIsAtomicOp(inst->opcode())) { + bool unused_coherent = false; + bool is_volatile = false; + SpvScope unused_scope = SpvScopeQueueFamilyKHR; + std::tie(unused_coherent, is_volatile, unused_scope) = + GetInstructionAttributes(inst->GetSingleWordInOperand(0)); + + UpgradeSemantics(inst, 2u, is_volatile); + if (inst->opcode() == SpvOpAtomicCompareExchange || + inst->opcode() == SpvOpAtomicCompareExchangeWeak) { + UpgradeSemantics(inst, 3u, is_volatile); + } + } + }); + } +} + +void UpgradeMemoryModel::UpgradeSemantics(Instruction* inst, + uint32_t in_operand, + bool is_volatile) { + if (!is_volatile) return; + + uint32_t semantics_id = inst->GetSingleWordInOperand(in_operand); + const analysis::Constant* constant = + context()->get_constant_mgr()->FindDeclaredConstant(semantics_id); + const analysis::Integer* type = constant->type()->AsInteger(); + assert(type && type->width() == 32); + uint32_t value = 0; + if (type->IsSigned()) { + value = static_cast(constant->GetS32()); + } else { + value = constant->GetU32(); + } + + value |= SpvMemorySemanticsVolatileMask; + auto new_constant = context()->get_constant_mgr()->GetConstant(type, {value}); + auto new_semantics = + context()->get_constant_mgr()->GetDefiningInstruction(new_constant); + inst->SetInOperand(in_operand, {new_semantics->result_id()}); +} + +std::tuple UpgradeMemoryModel::GetInstructionAttributes( + uint32_t id) { + // |id| is a pointer used in a memory/image instruction. Need to determine if + // that pointer points to volatile or coherent memory. Workgroup storage + // class is implicitly coherent and cannot be decorated with volatile, so + // short circuit that case. + Instruction* inst = context()->get_def_use_mgr()->GetDef(id); + analysis::Type* type = context()->get_type_mgr()->GetType(inst->type_id()); + if (type->AsPointer() && + type->AsPointer()->storage_class() == SpvStorageClassWorkgroup) { + return std::make_tuple(true, false, SpvScopeWorkgroup); + } + + bool is_coherent = false; + bool is_volatile = false; + std::unordered_set visited; + std::tie(is_coherent, is_volatile) = + TraceInstruction(context()->get_def_use_mgr()->GetDef(id), + std::vector(), &visited); + + return std::make_tuple(is_coherent, is_volatile, SpvScopeQueueFamilyKHR); +} + +std::pair UpgradeMemoryModel::TraceInstruction( + Instruction* inst, std::vector indices, + std::unordered_set* visited) { + auto iter = cache_.find(std::make_pair(inst->result_id(), indices)); + if (iter != cache_.end()) { + return iter->second; + } + + if (!visited->insert(inst->result_id()).second) { + return std::make_pair(false, false); + } + + // Initialize the cache before |indices| is (potentially) modified. + auto& cached_result = cache_[std::make_pair(inst->result_id(), indices)]; + cached_result.first = false; + cached_result.second = false; + + bool is_coherent = false; + bool is_volatile = false; + switch (inst->opcode()) { + case SpvOpVariable: + case SpvOpFunctionParameter: + is_coherent |= HasDecoration(inst, 0, SpvDecorationCoherent); + is_volatile |= HasDecoration(inst, 0, SpvDecorationVolatile); + if (!is_coherent || !is_volatile) { + bool type_coherent = false; + bool type_volatile = false; + std::tie(type_coherent, type_volatile) = + CheckType(inst->type_id(), indices); + is_coherent |= type_coherent; + is_volatile |= type_volatile; + } + break; + case SpvOpAccessChain: + case SpvOpInBoundsAccessChain: + // Store indices in reverse order. + for (uint32_t i = inst->NumInOperands() - 1; i > 0; --i) { + indices.push_back(inst->GetSingleWordInOperand(i)); + } + break; + case SpvOpPtrAccessChain: + // Store indices in reverse order. Skip the |Element| operand. + for (uint32_t i = inst->NumInOperands() - 1; i > 1; --i) { + indices.push_back(inst->GetSingleWordInOperand(i)); + } + break; + default: + break; + } + + // No point searching further. + if (is_coherent && is_volatile) { + cached_result.first = true; + cached_result.second = true; + return std::make_pair(true, true); + } + + // Variables and function parameters are sources. Continue searching until we + // reach them. + if (inst->opcode() != SpvOpVariable && + inst->opcode() != SpvOpFunctionParameter) { + inst->ForEachInId([this, &is_coherent, &is_volatile, &indices, + &visited](const uint32_t* id_ptr) { + Instruction* op_inst = context()->get_def_use_mgr()->GetDef(*id_ptr); + const analysis::Type* type = + context()->get_type_mgr()->GetType(op_inst->type_id()); + if (type && + (type->AsPointer() || type->AsImage() || type->AsSampledImage())) { + bool operand_coherent = false; + bool operand_volatile = false; + std::tie(operand_coherent, operand_volatile) = + TraceInstruction(op_inst, indices, visited); + is_coherent |= operand_coherent; + is_volatile |= operand_volatile; + } + }); + } + + cached_result.first = is_coherent; + cached_result.second = is_volatile; + return std::make_pair(is_coherent, is_volatile); +} + +std::pair UpgradeMemoryModel::CheckType( + uint32_t type_id, const std::vector& indices) { + bool is_coherent = false; + bool is_volatile = false; + Instruction* type_inst = context()->get_def_use_mgr()->GetDef(type_id); + assert(type_inst->opcode() == SpvOpTypePointer); + Instruction* element_inst = context()->get_def_use_mgr()->GetDef( + type_inst->GetSingleWordInOperand(1u)); + for (int i = (int)indices.size() - 1; i >= 0; --i) { + if (is_coherent && is_volatile) break; + + if (element_inst->opcode() == SpvOpTypePointer) { + element_inst = context()->get_def_use_mgr()->GetDef( + element_inst->GetSingleWordInOperand(1u)); + } else if (element_inst->opcode() == SpvOpTypeStruct) { + uint32_t index = indices.at(i); + Instruction* index_inst = context()->get_def_use_mgr()->GetDef(index); + assert(index_inst->opcode() == SpvOpConstant); + uint64_t value = GetIndexValue(index_inst); + is_coherent |= HasDecoration(element_inst, static_cast(value), + SpvDecorationCoherent); + is_volatile |= HasDecoration(element_inst, static_cast(value), + SpvDecorationVolatile); + element_inst = context()->get_def_use_mgr()->GetDef( + element_inst->GetSingleWordInOperand(static_cast(value))); + } else { + assert(spvOpcodeIsComposite(element_inst->opcode())); + element_inst = context()->get_def_use_mgr()->GetDef( + element_inst->GetSingleWordInOperand(0u)); + } + } + + if (!is_coherent || !is_volatile) { + bool remaining_coherent = false; + bool remaining_volatile = false; + std::tie(remaining_coherent, remaining_volatile) = + CheckAllTypes(element_inst); + is_coherent |= remaining_coherent; + is_volatile |= remaining_volatile; + } + + return std::make_pair(is_coherent, is_volatile); +} + +std::pair UpgradeMemoryModel::CheckAllTypes( + const Instruction* inst) { + std::unordered_set visited; + std::vector stack; + stack.push_back(inst); + + bool is_coherent = false; + bool is_volatile = false; + while (!stack.empty()) { + const Instruction* def = stack.back(); + stack.pop_back(); + + if (!visited.insert(def).second) continue; + + if (def->opcode() == SpvOpTypeStruct) { + // Any member decorated with coherent and/or volatile is enough to have + // the related operation be flagged as coherent and/or volatile. + is_coherent |= HasDecoration(def, std::numeric_limits::max(), + SpvDecorationCoherent); + is_volatile |= HasDecoration(def, std::numeric_limits::max(), + SpvDecorationVolatile); + if (is_coherent && is_volatile) + return std::make_pair(is_coherent, is_volatile); + + // Check the subtypes. + for (uint32_t i = 0; i < def->NumInOperands(); ++i) { + stack.push_back(context()->get_def_use_mgr()->GetDef( + def->GetSingleWordInOperand(i))); + } + } else if (spvOpcodeIsComposite(def->opcode())) { + stack.push_back(context()->get_def_use_mgr()->GetDef( + def->GetSingleWordInOperand(0u))); + } else if (def->opcode() == SpvOpTypePointer) { + stack.push_back(context()->get_def_use_mgr()->GetDef( + def->GetSingleWordInOperand(1u))); + } + } + + return std::make_pair(is_coherent, is_volatile); +} + +uint64_t UpgradeMemoryModel::GetIndexValue(Instruction* index_inst) { + const analysis::Constant* index_constant = + context()->get_constant_mgr()->GetConstantFromInst(index_inst); + assert(index_constant->AsIntConstant()); + if (index_constant->type()->AsInteger()->IsSigned()) { + if (index_constant->type()->AsInteger()->width() == 32) { + return index_constant->GetS32(); + } else { + return index_constant->GetS64(); + } + } else { + if (index_constant->type()->AsInteger()->width() == 32) { + return index_constant->GetU32(); + } else { + return index_constant->GetU64(); + } + } +} + +bool UpgradeMemoryModel::HasDecoration(const Instruction* inst, uint32_t value, + SpvDecoration decoration) { + // If the iteration was terminated early then an appropriate decoration was + // found. + return !context()->get_decoration_mgr()->WhileEachDecoration( + inst->result_id(), decoration, [value](const Instruction& i) { + if (i.opcode() == SpvOpDecorate || i.opcode() == SpvOpDecorateId) { + return false; + } else if (i.opcode() == SpvOpMemberDecorate) { + if (value == i.GetSingleWordInOperand(1u) || + value == std::numeric_limits::max()) + return false; + } + + return true; + }); +} + +void UpgradeMemoryModel::UpgradeFlags(Instruction* inst, uint32_t in_operand, + bool is_coherent, bool is_volatile, + OperationType operation_type, + InstructionType inst_type) { + if (!is_coherent && !is_volatile) return; + + uint32_t flags = 0; + if (inst->NumInOperands() > in_operand) { + flags |= inst->GetSingleWordInOperand(in_operand); + } + if (is_coherent) { + if (inst_type == kMemory) { + flags |= SpvMemoryAccessNonPrivatePointerKHRMask; + if (operation_type == kVisibility) { + flags |= SpvMemoryAccessMakePointerVisibleKHRMask; + } else { + flags |= SpvMemoryAccessMakePointerAvailableKHRMask; + } + } else { + flags |= SpvImageOperandsNonPrivateTexelKHRMask; + if (operation_type == kVisibility) { + flags |= SpvImageOperandsMakeTexelVisibleKHRMask; + } else { + flags |= SpvImageOperandsMakeTexelAvailableKHRMask; + } + } + } + + if (is_volatile) { + if (inst_type == kMemory) { + flags |= SpvMemoryAccessVolatileMask; + } else { + flags |= SpvImageOperandsVolatileTexelKHRMask; + } + } + + if (inst->NumInOperands() > in_operand) { + inst->SetInOperand(in_operand, {flags}); + } else if (inst_type == kMemory) { + inst->AddOperand({SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS, {flags}}); + } else { + inst->AddOperand({SPV_OPERAND_TYPE_OPTIONAL_IMAGE, {flags}}); + } +} + +uint32_t UpgradeMemoryModel::GetScopeConstant(SpvScope scope) { + analysis::Integer int_ty(32, false); + uint32_t int_id = context()->get_type_mgr()->GetTypeInstruction(&int_ty); + const analysis::Constant* constant = + context()->get_constant_mgr()->GetConstant( + context()->get_type_mgr()->GetType(int_id), + {static_cast(scope)}); + return context() + ->get_constant_mgr() + ->GetDefiningInstruction(constant) + ->result_id(); +} + +void UpgradeMemoryModel::CleanupDecorations() { + // All of the volatile and coherent decorations have been dealt with, so now + // we can just remove them. + get_module()->ForEachInst([this](Instruction* inst) { + if (inst->result_id() != 0) { + context()->get_decoration_mgr()->RemoveDecorationsFrom( + inst->result_id(), [](const Instruction& dec) { + switch (dec.opcode()) { + case SpvOpDecorate: + case SpvOpDecorateId: + if (dec.GetSingleWordInOperand(1u) == SpvDecorationCoherent || + dec.GetSingleWordInOperand(1u) == SpvDecorationVolatile) + return true; + break; + case SpvOpMemberDecorate: + if (dec.GetSingleWordInOperand(2u) == SpvDecorationCoherent || + dec.GetSingleWordInOperand(2u) == SpvDecorationVolatile) + return true; + break; + default: + break; + } + return false; + }); + } + }); +} + +void UpgradeMemoryModel::UpgradeBarriers() { + std::vector barriers; + // Collects all the control barriers in |function|. Returns true if the + // function operates on the Output storage class. + ProcessFunction CollectBarriers = [this, &barriers](Function* function) { + bool operates_on_output = false; + for (auto& block : *function) { + block.ForEachInst([this, &barriers, + &operates_on_output](Instruction* inst) { + if (inst->opcode() == SpvOpControlBarrier) { + barriers.push_back(inst); + } else if (!operates_on_output) { + // This instruction operates on output storage class if it is a + // pointer to output type or any input operand is a pointer to output + // type. + analysis::Type* type = + context()->get_type_mgr()->GetType(inst->type_id()); + if (type && type->AsPointer() && + type->AsPointer()->storage_class() == SpvStorageClassOutput) { + operates_on_output = true; + return; + } + inst->ForEachInId([this, &operates_on_output](uint32_t* id_ptr) { + Instruction* op_inst = + context()->get_def_use_mgr()->GetDef(*id_ptr); + analysis::Type* op_type = + context()->get_type_mgr()->GetType(op_inst->type_id()); + if (op_type && op_type->AsPointer() && + op_type->AsPointer()->storage_class() == SpvStorageClassOutput) + operates_on_output = true; + }); + } + }); + } + return operates_on_output; + }; + + std::queue roots; + for (auto& e : get_module()->entry_points()) + if (e.GetSingleWordInOperand(0u) == SpvExecutionModelTessellationControl) { + roots.push(e.GetSingleWordInOperand(1u)); + if (context()->ProcessCallTreeFromRoots(CollectBarriers, &roots)) { + for (auto barrier : barriers) { + // Add OutputMemoryKHR to the semantics of the barriers. + uint32_t semantics_id = barrier->GetSingleWordInOperand(2u); + Instruction* semantics_inst = + context()->get_def_use_mgr()->GetDef(semantics_id); + analysis::Type* semantics_type = + context()->get_type_mgr()->GetType(semantics_inst->type_id()); + uint64_t semantics_value = GetIndexValue(semantics_inst); + const analysis::Constant* constant = + context()->get_constant_mgr()->GetConstant( + semantics_type, {static_cast(semantics_value) | + SpvMemorySemanticsOutputMemoryKHRMask}); + barrier->SetInOperand(2u, {context() + ->get_constant_mgr() + ->GetDefiningInstruction(constant) + ->result_id()}); + } + } + barriers.clear(); + } +} + +void UpgradeMemoryModel::UpgradeMemoryScope() { + get_module()->ForEachInst([this](Instruction* inst) { + // Don't need to handle all the operations that take a scope. + // * Group operations can only be subgroup + // * Non-uniform can only be workgroup or subgroup + // * Named barriers are not supported by Vulkan + // * Workgroup ops (e.g. async_copy) have at most workgroup scope. + if (spvOpcodeIsAtomicOp(inst->opcode())) { + if (IsDeviceScope(inst->GetSingleWordInOperand(1))) { + inst->SetInOperand(1, {GetScopeConstant(SpvScopeQueueFamilyKHR)}); + } + } else if (inst->opcode() == SpvOpControlBarrier) { + if (IsDeviceScope(inst->GetSingleWordInOperand(1))) { + inst->SetInOperand(1, {GetScopeConstant(SpvScopeQueueFamilyKHR)}); + } + } else if (inst->opcode() == SpvOpMemoryBarrier) { + if (IsDeviceScope(inst->GetSingleWordInOperand(0))) { + inst->SetInOperand(0, {GetScopeConstant(SpvScopeQueueFamilyKHR)}); + } + } + }); +} + +bool UpgradeMemoryModel::IsDeviceScope(uint32_t scope_id) { + const analysis::Constant* constant = + context()->get_constant_mgr()->FindDeclaredConstant(scope_id); + assert(constant && "Memory scope must be a constant"); + + const analysis::Integer* type = constant->type()->AsInteger(); + assert(type); + assert(type->width() == 32 || type->width() == 64); + if (type->width() == 32) { + if (type->IsSigned()) + return static_cast(constant->GetS32()) == SpvScopeDevice; + else + return static_cast(constant->GetU32()) == SpvScopeDevice; + } else { + if (type->IsSigned()) + return static_cast(constant->GetS64()) == SpvScopeDevice; + else + return static_cast(constant->GetU64()) == SpvScopeDevice; + } + + assert(false); + return false; +} + +void UpgradeMemoryModel::UpgradeExtInst(Instruction* ext_inst) { + const bool is_modf = ext_inst->GetSingleWordInOperand(1u) == GLSLstd450Modf; + auto ptr_id = ext_inst->GetSingleWordInOperand(3u); + auto ptr_type_id = get_def_use_mgr()->GetDef(ptr_id)->type_id(); + auto pointee_type_id = + get_def_use_mgr()->GetDef(ptr_type_id)->GetSingleWordInOperand(1u); + auto element_type_id = ext_inst->type_id(); + std::vector element_types(2); + element_types[0] = context()->get_type_mgr()->GetType(element_type_id); + element_types[1] = context()->get_type_mgr()->GetType(pointee_type_id); + analysis::Struct struct_type(element_types); + uint32_t struct_id = + context()->get_type_mgr()->GetTypeInstruction(&struct_type); + // Change the operation + GLSLstd450 new_op = is_modf ? GLSLstd450ModfStruct : GLSLstd450FrexpStruct; + ext_inst->SetOperand(3u, {static_cast(new_op)}); + // Remove the pointer argument + ext_inst->RemoveOperand(5u); + // Set the type id to the new struct. + ext_inst->SetResultType(struct_id); + + // The result is now a struct of the original result. The zero'th element is + // old result and should replace the old result. The one'th element needs to + // be stored via a new instruction. + auto where = ext_inst->NextNode(); + InstructionBuilder builder( + context(), where, + IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping); + auto extract_0 = + builder.AddCompositeExtract(element_type_id, ext_inst->result_id(), {0}); + context()->ReplaceAllUsesWith(ext_inst->result_id(), extract_0->result_id()); + // The extract's input was just changed to itself, so fix that. + extract_0->SetInOperand(0u, {ext_inst->result_id()}); + auto extract_1 = + builder.AddCompositeExtract(pointee_type_id, ext_inst->result_id(), {1}); + builder.AddStore(ptr_id, extract_1->result_id()); +} + +uint32_t UpgradeMemoryModel::MemoryAccessNumWords(uint32_t mask) { + uint32_t result = 1; + if (mask & SpvMemoryAccessAlignedMask) ++result; + if (mask & SpvMemoryAccessMakePointerAvailableKHRMask) ++result; + if (mask & SpvMemoryAccessMakePointerVisibleKHRMask) ++result; + return result; +} + +} // namespace opt +} // namespace spvtools diff --git a/third_party/spirv-tools/source/opt/upgrade_memory_model.h b/third_party/spirv-tools/source/opt/upgrade_memory_model.h new file mode 100644 index 0000000000..f75304ed0b --- /dev/null +++ b/third_party/spirv-tools/source/opt/upgrade_memory_model.h @@ -0,0 +1,150 @@ +// Copyright (c) 2018 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_UPGRADE_MEMORY_MODEL_H_ +#define LIBSPIRV_OPT_UPGRADE_MEMORY_MODEL_H_ + +#include +#include + +#include "pass.h" + +namespace spvtools { +namespace opt { + +// Hashing functor for the memoized result store. +struct CacheHash { + size_t operator()( + const std::pair>& item) const { + std::u32string to_hash; + to_hash.push_back(item.first); + for (auto i : item.second) to_hash.push_back(i); + return std::hash()(to_hash); + } +}; + +// Upgrades the memory model from Logical GLSL450 to Logical VulkanKHR. +// +// This pass remove deprecated decorations (Volatile and Coherent) and replaces +// them with new flags on individual instructions. It adds the Output storage +// class semantic to control barriers in tessellation control shaders that have +// an access to Output memory. +class UpgradeMemoryModel : public Pass { + public: + const char* name() const override { return "upgrade-memory-model"; } + Status Process() override; + + private: + // Used to indicate whether the operation performs an availability or + // visibility operation. + enum OperationType { kVisibility, kAvailability }; + + // Used to indicate whether the instruction is a memory or image instruction. + enum InstructionType { kMemory, kImage }; + + // Modifies the OpMemoryModel to use VulkanKHR. Adds the Vulkan memory model + // capability and extension. + void UpgradeMemoryModelInstruction(); + + // Upgrades memory, image and atomic instructions. + // Memory and image instructions convert coherent and volatile decorations + // into flags on the instruction. + // Atomic memory semantics convert volatile decoration into flags on the + // instruction. + void UpgradeInstructions(); + + // Upgrades memory and image operands for instructions that have them. + void UpgradeMemoryAndImages(); + + // Adds the volatile memory semantic if necessary. + void UpgradeAtomics(); + + // Returns whether |id| is coherent and/or volatile. + std::tuple GetInstructionAttributes(uint32_t id); + + // Traces |inst| to determine if it is coherent and/or volatile. + // |indices| tracks the access chain indices seen so far. + std::pair TraceInstruction(Instruction* inst, + std::vector indices, + std::unordered_set* visited); + + // Return true if |inst| is decorated with |decoration|. + // If |inst| is decorated by member decorations then either |value| must + // match the index or |value| must be a maximum allowable value. The max + // value allows any element to match. + bool HasDecoration(const Instruction* inst, uint32_t value, + SpvDecoration decoration); + + // Returns whether |type_id| indexed via |indices| is coherent and/or + // volatile. + std::pair CheckType(uint32_t type_id, + const std::vector& indices); + + // Returns whether any type/element under |inst| is coherent and/or volatile. + std::pair CheckAllTypes(const Instruction* inst); + + // Modifies the flags of |inst| to include the new flags for the Vulkan + // memory model. |operation_type| indicates whether flags should use + // MakeVisible or MakeAvailable variants. |inst_type| indicates whether the + // Pointer or Texel variants of flags should be used. + void UpgradeFlags(Instruction* inst, uint32_t in_operand, bool is_coherent, + bool is_volatile, OperationType operation_type, + InstructionType inst_type); + + // Modifies the semantics at |in_operand| of |inst| to include the volatile + // bit if |is_volatile| is true. + void UpgradeSemantics(Instruction* inst, uint32_t in_operand, + bool is_volatile); + + // Returns the result id for a constant for |scope|. + uint32_t GetScopeConstant(SpvScope scope); + + // Returns the value of |index_inst|. |index_inst| must be an OpConstant of + // integer type.g + uint64_t GetIndexValue(Instruction* index_inst); + + // Removes coherent and volatile decorations. + void CleanupDecorations(); + + // For all tessellation control entry points, if there is an operation on + // Output storage class, then all barriers are modified to include the + // OutputMemoryKHR semantic. + void UpgradeBarriers(); + + // If the Vulkan memory model is specified, device scope actually means + // device scope. The memory scope must be modified to be QueueFamilyKHR + // scope. + void UpgradeMemoryScope(); + + // Returns true if |scope_id| is SpvScopeDevice. + bool IsDeviceScope(uint32_t scope_id); + + // Upgrades GLSL.std.450 modf and frexp. Both instructions are replaced with + // their struct versions. New extracts and a store are added in order to + // facilitate adding memory model flags. + void UpgradeExtInst(Instruction* modf); + + // Returns the number of words taken up by a memory access argument and its + // implied operands. + uint32_t MemoryAccessNumWords(uint32_t mask); + + // Caches the result of TraceInstruction. For a given result id and set of + // indices, stores whether that combination is coherent and/or volatile. + std::unordered_map>, + std::pair, CacheHash> + cache_; +}; +} // namespace opt +} // namespace spvtools +#endif // LIBSPIRV_OPT_UPGRADE_MEMORY_MODEL_H_ diff --git a/third_party/spirv-tools/source/opt/value_number_table.cpp b/third_party/spirv-tools/source/opt/value_number_table.cpp index 1bac63fabe..82549a6dc9 100644 --- a/third_party/spirv-tools/source/opt/value_number_table.cpp +++ b/third_party/spirv-tools/source/opt/value_number_table.cpp @@ -78,8 +78,12 @@ uint32_t ValueNumberTable::AssignValueNumber(Instruction* inst) { return value; } + analysis::DecorationManager* dec_mgr = context()->get_decoration_mgr(); + // When we copy an object, the value numbers should be the same. - if (inst->opcode() == SpvOpCopyObject) { + if (inst->opcode() == SpvOpCopyObject && + dec_mgr->HaveTheSameDecorations(inst->result_id(), + inst->GetSingleWordInOperand(0))) { value = GetValueNumber(inst->GetSingleWordInOperand(0)); if (value != 0) { id_to_value_[inst->result_id()] = value; @@ -89,7 +93,9 @@ uint32_t ValueNumberTable::AssignValueNumber(Instruction* inst) { // Phi nodes are a type of copy. If all of the inputs have the same value // number, then we can assign the result of the phi the same value number. - if (inst->opcode() == SpvOpPhi) { + if (inst->opcode() == SpvOpPhi && inst->NumInOperands() > 0 && + dec_mgr->HaveTheSameDecorations(inst->result_id(), + inst->GetSingleWordInOperand(0))) { value = GetValueNumber(inst->GetSingleWordInOperand(0)); if (value != 0) { for (uint32_t op = 2; op < inst->NumInOperands(); op += 2) { diff --git a/third_party/spirv-tools/source/opt/vector_dce.cpp b/third_party/spirv-tools/source/opt/vector_dce.cpp index 911242e058..92532e31af 100644 --- a/third_party/spirv-tools/source/opt/vector_dce.cpp +++ b/third_party/spirv-tools/source/opt/vector_dce.cpp @@ -66,7 +66,8 @@ void VectorDCE::FindLiveComponents(Function* function, switch (current_inst->opcode()) { case SpvOpCompositeExtract: - MarkExtractUseAsLive(current_inst, live_components, &work_list); + MarkExtractUseAsLive(current_inst, current_item.components, + live_components, &work_list); break; case SpvOpCompositeInsert: MarkInsertUsesAsLive(current_item, live_components, &work_list); @@ -92,6 +93,7 @@ void VectorDCE::FindLiveComponents(Function* function, } void VectorDCE::MarkExtractUseAsLive(const Instruction* current_inst, + const utils::BitVector& live_elements, LiveComponentMap* live_components, std::vector* work_list) { analysis::DefUseManager* def_use_mgr = context()->get_def_use_mgr(); @@ -102,7 +104,11 @@ void VectorDCE::MarkExtractUseAsLive(const Instruction* current_inst, if (HasVectorOrScalarResult(operand_inst)) { WorkListItem new_item; new_item.instruction = operand_inst; - new_item.components.Set(current_inst->GetSingleWordInOperand(1)); + if (current_inst->NumInOperands() < 2) { + new_item.components = live_elements; + } else { + new_item.components.Set(current_inst->GetSingleWordInOperand(1)); + } AddItemToWorkListIfNeeded(new_item, live_components, work_list); } } @@ -113,30 +119,44 @@ void VectorDCE::MarkInsertUsesAsLive( std::vector* work_list) { analysis::DefUseManager* def_use_mgr = context()->get_def_use_mgr(); - uint32_t insert_position = - current_item.instruction->GetSingleWordInOperand(2); + if (current_item.instruction->NumInOperands() > 2) { + uint32_t insert_position = + current_item.instruction->GetSingleWordInOperand(2); - // Add the elements of the composite object that are used. - uint32_t operand_id = - current_item.instruction->GetSingleWordInOperand(kInsertCompositeIdInIdx); - Instruction* operand_inst = def_use_mgr->GetDef(operand_id); + // Add the elements of the composite object that are used. + uint32_t operand_id = current_item.instruction->GetSingleWordInOperand( + kInsertCompositeIdInIdx); + Instruction* operand_inst = def_use_mgr->GetDef(operand_id); - WorkListItem new_item; - new_item.instruction = operand_inst; - new_item.components = current_item.components; - new_item.components.Clear(insert_position); + WorkListItem new_item; + new_item.instruction = operand_inst; + new_item.components = current_item.components; + new_item.components.Clear(insert_position); - AddItemToWorkListIfNeeded(new_item, live_components, work_list); + AddItemToWorkListIfNeeded(new_item, live_components, work_list); - // Add the element being inserted if it is used. - if (current_item.components.Get(insert_position)) { - uint32_t obj_operand_id = + // Add the element being inserted if it is used. + if (current_item.components.Get(insert_position)) { + uint32_t obj_operand_id = + current_item.instruction->GetSingleWordInOperand( + kInsertObjectIdInIdx); + Instruction* obj_operand_inst = def_use_mgr->GetDef(obj_operand_id); + WorkListItem new_item_for_obj; + new_item_for_obj.instruction = obj_operand_inst; + new_item_for_obj.components.Set(0); + AddItemToWorkListIfNeeded(new_item_for_obj, live_components, work_list); + } + } else { + // If there are no indices, then this is a copy of the object being + // inserted. + uint32_t object_id = current_item.instruction->GetSingleWordInOperand(kInsertObjectIdInIdx); - Instruction* obj_operand_inst = def_use_mgr->GetDef(obj_operand_id); - WorkListItem new_item_for_obj; - new_item_for_obj.instruction = obj_operand_inst; - new_item_for_obj.components.Set(0); - AddItemToWorkListIfNeeded(new_item_for_obj, live_components, work_list); + Instruction* object_inst = def_use_mgr->GetDef(object_id); + + WorkListItem new_item; + new_item.instruction = object_inst; + new_item.components = current_item.components; + AddItemToWorkListIfNeeded(new_item, live_components, work_list); } } @@ -323,14 +343,23 @@ bool VectorDCE::RewriteInstructions( bool VectorDCE::RewriteInsertInstruction( Instruction* current_inst, const utils::BitVector& live_components) { // If the value being inserted is not live, then we can skip the insert. - bool modified = false; + + if (current_inst->NumInOperands() == 2) { + // If there are no indices, then this is the same as a copy. + context()->KillNamesAndDecorates(current_inst->result_id()); + uint32_t object_id = + current_inst->GetSingleWordInOperand(kInsertObjectIdInIdx); + context()->ReplaceAllUsesWith(current_inst->result_id(), object_id); + return true; + } + uint32_t insert_index = current_inst->GetSingleWordInOperand(2); if (!live_components.Get(insert_index)) { - modified = true; context()->KillNamesAndDecorates(current_inst->result_id()); uint32_t composite_id = current_inst->GetSingleWordInOperand(kInsertCompositeIdInIdx); context()->ReplaceAllUsesWith(current_inst->result_id(), composite_id); + return true; } // If the values already in the composite are not used, then replace it with @@ -342,9 +371,10 @@ bool VectorDCE::RewriteInsertInstruction( uint32_t undef_id = Type2Undef(current_inst->type_id()); current_inst->SetInOperand(kInsertCompositeIdInIdx, {undef_id}); context()->AnalyzeUses(current_inst); + return true; } - return modified; + return false; } void VectorDCE::AddItemToWorkListIfNeeded( diff --git a/third_party/spirv-tools/source/opt/vector_dce.h b/third_party/spirv-tools/source/opt/vector_dce.h index 48886998da..4f039c53fb 100644 --- a/third_party/spirv-tools/source/opt/vector_dce.h +++ b/third_party/spirv-tools/source/opt/vector_dce.h @@ -53,7 +53,8 @@ class VectorDCE : public MemPass { return IRContext::kAnalysisDefUse | IRContext::kAnalysisCFG | IRContext::kAnalysisInstrToBlockMapping | IRContext::kAnalysisLoopAnalysis | IRContext::kAnalysisDecorations | - IRContext::kAnalysisDominatorAnalysis | IRContext::kAnalysisNameMap; + IRContext::kAnalysisDominatorAnalysis | IRContext::kAnalysisNameMap | + IRContext::kAnalysisConstants | IRContext::kAnalysisTypes; } private: @@ -128,6 +129,7 @@ class VectorDCE : public MemPass { // live. If anything becomes live they are added to |work_list| and // |live_components| is updated accordingly. void MarkExtractUseAsLive(const Instruction* current_inst, + const utils::BitVector& live_elements, LiveComponentMap* live_components, std::vector* work_list); diff --git a/third_party/spirv-tools/source/opt/wrap_opkill.cpp b/third_party/spirv-tools/source/opt/wrap_opkill.cpp new file mode 100644 index 0000000000..ffd7a1050d --- /dev/null +++ b/third_party/spirv-tools/source/opt/wrap_opkill.cpp @@ -0,0 +1,181 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/opt/wrap_opkill.h" + +#include "ir_builder.h" + +namespace spvtools { +namespace opt { + +Pass::Status WrapOpKill::Process() { + bool modified = false; + + auto func_to_process = + context()->GetStructuredCFGAnalysis()->FindFuncsCalledFromContinue(); + for (uint32_t func_id : func_to_process) { + Function* func = context()->GetFunction(func_id); + bool successful = func->WhileEachInst([this, &modified](Instruction* inst) { + if (inst->opcode() == SpvOpKill) { + modified = true; + if (!ReplaceWithFunctionCall(inst)) { + return false; + } + } + return true; + }); + + if (!successful) { + return Status::Failure; + } + } + + if (opkill_function_ != nullptr) { + assert(modified && + "The function should only be generated if something was modified."); + context()->AddFunction(std::move(opkill_function_)); + } + return (modified ? Status::SuccessWithChange : Status::SuccessWithoutChange); +} + +bool WrapOpKill::ReplaceWithFunctionCall(Instruction* inst) { + assert(inst->opcode() == SpvOpKill && + "|inst| must be an OpKill instruction."); + InstructionBuilder ir_builder( + context(), inst, + IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping); + uint32_t func_id = GetOpKillFuncId(); + if (func_id == 0) { + return false; + } + if (ir_builder.AddFunctionCall(GetVoidTypeId(), func_id, {}) == nullptr) { + return false; + } + + Instruction* return_inst = nullptr; + uint32_t return_type_id = GetOwningFunctionsReturnType(inst); + if (return_type_id != GetVoidTypeId()) { + Instruction* undef = ir_builder.AddNullaryOp(return_type_id, SpvOpUndef); + if (undef == nullptr) { + return false; + } + return_inst = + ir_builder.AddUnaryOp(0, SpvOpReturnValue, undef->result_id()); + } else { + return_inst = ir_builder.AddNullaryOp(0, SpvOpReturn); + } + + if (return_inst == nullptr) { + return false; + } + + context()->KillInst(inst); + return true; +} + +uint32_t WrapOpKill::GetVoidTypeId() { + if (void_type_id_ != 0) { + return void_type_id_; + } + + analysis::TypeManager* type_mgr = context()->get_type_mgr(); + analysis::Void void_type; + void_type_id_ = type_mgr->GetTypeInstruction(&void_type); + return void_type_id_; +} + +uint32_t WrapOpKill::GetVoidFunctionTypeId() { + analysis::TypeManager* type_mgr = context()->get_type_mgr(); + analysis::Void void_type; + const analysis::Type* registered_void_type = + type_mgr->GetRegisteredType(&void_type); + + analysis::Function func_type(registered_void_type, {}); + return type_mgr->GetTypeInstruction(&func_type); +} + +uint32_t WrapOpKill::GetOpKillFuncId() { + if (opkill_function_ != nullptr) { + return opkill_function_->result_id(); + } + + uint32_t opkill_func_id = TakeNextId(); + if (opkill_func_id == 0) { + return 0; + } + + uint32_t void_type_id = GetVoidTypeId(); + if (void_type_id == 0) { + return 0; + } + + // Generate the function start instruction + std::unique_ptr func_start(new Instruction( + context(), SpvOpFunction, void_type_id, opkill_func_id, {})); + func_start->AddOperand({SPV_OPERAND_TYPE_FUNCTION_CONTROL, {0}}); + func_start->AddOperand({SPV_OPERAND_TYPE_ID, {GetVoidFunctionTypeId()}}); + opkill_function_.reset(new Function(std::move(func_start))); + + // Generate the function end instruction + std::unique_ptr func_end( + new Instruction(context(), SpvOpFunctionEnd, 0, 0, {})); + opkill_function_->SetFunctionEnd(std::move(func_end)); + + // Create the one basic block for the function. + uint32_t lab_id = TakeNextId(); + if (lab_id == 0) { + return 0; + } + std::unique_ptr label_inst( + new Instruction(context(), SpvOpLabel, 0, lab_id, {})); + std::unique_ptr bb(new BasicBlock(std::move(label_inst))); + + // Add the OpKill to the basic block + std::unique_ptr kill_inst( + new Instruction(context(), SpvOpKill, 0, 0, {})); + bb->AddInstruction(std::move(kill_inst)); + + // Add the bb to the function + opkill_function_->AddBasicBlock(std::move(bb)); + + // Add the function to the module. + if (context()->AreAnalysesValid(IRContext::kAnalysisDefUse)) { + opkill_function_->ForEachInst( + [this](Instruction* inst) { context()->AnalyzeDefUse(inst); }); + } + + if (context()->AreAnalysesValid(IRContext::kAnalysisInstrToBlockMapping)) { + for (BasicBlock& basic_block : *opkill_function_) { + context()->set_instr_block(basic_block.GetLabelInst(), &basic_block); + for (Instruction& inst : basic_block) { + context()->set_instr_block(&inst, &basic_block); + } + } + } + + return opkill_function_->result_id(); +} + +uint32_t WrapOpKill::GetOwningFunctionsReturnType(Instruction* inst) { + BasicBlock* bb = context()->get_instr_block(inst); + if (bb == nullptr) { + return 0; + } + + Function* func = bb->GetParent(); + return func->type_id(); +} + +} // namespace opt +} // namespace spvtools diff --git a/third_party/spirv-tools/source/opt/wrap_opkill.h b/third_party/spirv-tools/source/opt/wrap_opkill.h new file mode 100644 index 0000000000..09f2dfafd8 --- /dev/null +++ b/third_party/spirv-tools/source/opt/wrap_opkill.h @@ -0,0 +1,75 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_OPT_WRAP_OPKILL_H_ +#define SOURCE_OPT_WRAP_OPKILL_H_ + +#include "source/opt/pass.h" + +namespace spvtools { +namespace opt { + +// Documented in optimizer.hpp +class WrapOpKill : public Pass { + public: + WrapOpKill() : void_type_id_(0) {} + + const char* name() const override { return "wrap-opkill"; } + + Status Process() override; + + IRContext::Analysis GetPreservedAnalyses() override { + return IRContext::kAnalysisDefUse | + IRContext::kAnalysisInstrToBlockMapping | + IRContext::kAnalysisDecorations | IRContext::kAnalysisCombinators | + IRContext::kAnalysisNameMap | IRContext::kAnalysisBuiltinVarId | + IRContext::kAnalysisConstants | IRContext::kAnalysisTypes; + } + + private: + // Replaces the OpKill instruction |inst| with a function call to a function + // that contains a single instruction, which is OpKill. An OpUnreachable + // instruction will be placed after the function call. Return true if + // successful. + bool ReplaceWithFunctionCall(Instruction* inst); + + // Returns the id of the void type. + uint32_t GetVoidTypeId(); + + // Returns the id of the function type for a void function with no parameters. + uint32_t GetVoidFunctionTypeId(); + + // Return the id of a function that has return type void, has no parameters, + // and contains a single instruction, which is an OpKill. Returns 0 if the + // function could not be generated. + uint32_t GetOpKillFuncId(); + + // Returns the id of the return type for the function that contains |inst|. + // Returns 0 if |inst| is not in a function. + uint32_t GetOwningFunctionsReturnType(Instruction* inst); + + // The id of the void type. If its value is 0, then the void type has not + // been found or created yet. + uint32_t void_type_id_; + + // The function that is a single instruction, which is an OpKill. The + // function has a void return type and takes no parameters. If the function is + // |nullptr|, then the function has not been generated. + std::unique_ptr opkill_function_; +}; + +} // namespace opt +} // namespace spvtools + +#endif // SOURCE_OPT_WRAP_OPKILL_H_ diff --git a/third_party/spirv-tools/source/pch_source.cpp b/third_party/spirv-tools/source/pch_source.cpp new file mode 100644 index 0000000000..032e29ec4f --- /dev/null +++ b/third_party/spirv-tools/source/pch_source.cpp @@ -0,0 +1,15 @@ +// Copyright (c) 2018 The Khronos Group Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "pch_source.h" diff --git a/third_party/spirv-tools/source/pch_source.h b/third_party/spirv-tools/source/pch_source.h new file mode 100644 index 0000000000..6695ba268b --- /dev/null +++ b/third_party/spirv-tools/source/pch_source.h @@ -0,0 +1,15 @@ +// Copyright (c) 2018 The Khronos Group Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/val/validation_state.h" diff --git a/third_party/spirv-tools/source/print.cpp b/third_party/spirv-tools/source/print.cpp index f75e2d4573..128587ae2d 100644 --- a/third_party/spirv-tools/source/print.cpp +++ b/third_party/spirv-tools/source/print.cpp @@ -15,7 +15,8 @@ #include "source/print.h" #if defined(SPIRV_ANDROID) || defined(SPIRV_LINUX) || defined(SPIRV_MAC) || \ - defined(SPIRV_FREEBSD) + defined(SPIRV_IOS) || defined(SPIRV_FREEBSD) || \ + defined(SPIRV_EMSCRIPTEN) || defined(SPIRV_FUCHSIA) namespace spvtools { clr::reset::operator const char*() { return "\x1b[0m"; } diff --git a/third_party/spirv-tools/source/reduce/CMakeLists.txt b/third_party/spirv-tools/source/reduce/CMakeLists.txt new file mode 100644 index 0000000000..51e9b1d0ff --- /dev/null +++ b/third_party/spirv-tools/source/reduce/CMakeLists.txt @@ -0,0 +1,107 @@ +# Copyright (c) 2018 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. +set(SPIRV_TOOLS_REDUCE_SOURCES + change_operand_reduction_opportunity.h + change_operand_to_undef_reduction_opportunity.h + merge_blocks_reduction_opportunity.h + merge_blocks_reduction_opportunity_finder.h + operand_to_const_reduction_opportunity_finder.h + operand_to_undef_reduction_opportunity_finder.h + operand_to_dominating_id_reduction_opportunity_finder.h + reducer.h + reduction_opportunity.h + reduction_opportunity_finder.h + reduction_pass.h + reduction_util.h + remove_block_reduction_opportunity.h + remove_block_reduction_opportunity_finder.h + remove_instruction_reduction_opportunity.h + remove_function_reduction_opportunity.h + remove_function_reduction_opportunity_finder.h + remove_selection_reduction_opportunity.h + remove_selection_reduction_opportunity_finder.h + remove_unreferenced_instruction_reduction_opportunity_finder.h + structured_loop_to_selection_reduction_opportunity.h + structured_loop_to_selection_reduction_opportunity_finder.h + conditional_branch_to_simple_conditional_branch_opportunity_finder.h + conditional_branch_to_simple_conditional_branch_reduction_opportunity.h + simple_conditional_branch_to_branch_opportunity_finder.h + simple_conditional_branch_to_branch_reduction_opportunity.h + + change_operand_reduction_opportunity.cpp + change_operand_to_undef_reduction_opportunity.cpp + merge_blocks_reduction_opportunity.cpp + merge_blocks_reduction_opportunity_finder.cpp + operand_to_const_reduction_opportunity_finder.cpp + operand_to_undef_reduction_opportunity_finder.cpp + operand_to_dominating_id_reduction_opportunity_finder.cpp + reducer.cpp + reduction_opportunity.cpp + reduction_pass.cpp + reduction_util.cpp + remove_block_reduction_opportunity.cpp + remove_block_reduction_opportunity_finder.cpp + remove_function_reduction_opportunity.cpp + remove_function_reduction_opportunity_finder.cpp + remove_instruction_reduction_opportunity.cpp + remove_selection_reduction_opportunity.cpp + remove_selection_reduction_opportunity_finder.cpp + remove_unreferenced_instruction_reduction_opportunity_finder.cpp + structured_loop_to_selection_reduction_opportunity.cpp + structured_loop_to_selection_reduction_opportunity_finder.cpp + conditional_branch_to_simple_conditional_branch_opportunity_finder.cpp + conditional_branch_to_simple_conditional_branch_reduction_opportunity.cpp + simple_conditional_branch_to_branch_opportunity_finder.cpp + simple_conditional_branch_to_branch_reduction_opportunity.cpp +) + +if(MSVC) + # Enable parallel builds across four cores for this lib + add_definitions(/MP4) +endif() + +spvtools_pch(SPIRV_TOOLS_REDUCE_SOURCES pch_source_reduce) + +add_library(SPIRV-Tools-reduce ${SPIRV_TOOLS_REDUCE_SOURCES}) + +spvtools_default_compile_options(SPIRV-Tools-reduce) +target_include_directories(SPIRV-Tools-reduce + PUBLIC + $ + $ + $ + PRIVATE ${spirv-tools_BINARY_DIR} +) +# The reducer reuses a lot of functionality from the SPIRV-Tools library. +target_link_libraries(SPIRV-Tools-reduce + PUBLIC ${SPIRV_TOOLS} + PUBLIC SPIRV-Tools-opt) + +set_property(TARGET SPIRV-Tools-reduce PROPERTY FOLDER "SPIRV-Tools libraries") +spvtools_check_symbol_exports(SPIRV-Tools-reduce) + +if(ENABLE_SPIRV_TOOLS_INSTALL) + install(TARGETS SPIRV-Tools-reduce EXPORT SPIRV-Tools-reduceTargets + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) + export(EXPORT SPIRV-Tools-reduceTargets FILE SPIRV-Tools-reduceTarget.cmake) + + spvtools_config_package_dir(SPIRV-Tools-reduce PACKAGE_DIR) + install(EXPORT SPIRV-Tools-reduceTargets FILE SPIRV-Tools-reduceTarget.cmake + DESTINATION ${PACKAGE_DIR}) + + spvtools_generate_config_file(SPIRV-Tools-reduce) + install(FILES ${CMAKE_BINARY_DIR}/SPIRV-Tools-reduceConfig.cmake DESTINATION ${PACKAGE_DIR}) +endif(ENABLE_SPIRV_TOOLS_INSTALL) diff --git a/third_party/spirv-tools/source/reduce/change_operand_reduction_opportunity.cpp b/third_party/spirv-tools/source/reduce/change_operand_reduction_opportunity.cpp new file mode 100644 index 0000000000..c3f6fd7ba1 --- /dev/null +++ b/third_party/spirv-tools/source/reduce/change_operand_reduction_opportunity.cpp @@ -0,0 +1,32 @@ +// Copyright (c) 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/reduce/change_operand_reduction_opportunity.h" + +namespace spvtools { +namespace reduce { + +bool ChangeOperandReductionOpportunity::PreconditionHolds() { + // Check that the instruction still has the original operand. + return inst_->NumOperands() > operand_index_ && + inst_->GetOperand(operand_index_).words[0] == original_id_ && + inst_->GetOperand(operand_index_).type == original_type_; +} + +void ChangeOperandReductionOpportunity::Apply() { + inst_->SetOperand(operand_index_, {new_id_}); +} + +} // namespace reduce +} // namespace spvtools diff --git a/third_party/spirv-tools/source/reduce/change_operand_reduction_opportunity.h b/third_party/spirv-tools/source/reduce/change_operand_reduction_opportunity.h new file mode 100644 index 0000000000..18e6ca1dda --- /dev/null +++ b/third_party/spirv-tools/source/reduce/change_operand_reduction_opportunity.h @@ -0,0 +1,54 @@ +// Copyright (c) 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_REDUCE_CHANGE_OPERAND_REDUCTION_OPPORTUNITY_H_ +#define SOURCE_REDUCE_CHANGE_OPERAND_REDUCTION_OPPORTUNITY_H_ + +#include "source/opt/instruction.h" +#include "source/reduce/reduction_opportunity.h" +#include "spirv-tools/libspirv.h" + +namespace spvtools { +namespace reduce { + +// An opportunity to replace an id operand of an instruction with some other id. +class ChangeOperandReductionOpportunity : public ReductionOpportunity { + public: + // Constructs the opportunity to replace operand |operand_index| of |inst| + // with |new_id|. + ChangeOperandReductionOpportunity(opt::Instruction* inst, + uint32_t operand_index, uint32_t new_id) + : inst_(inst), + operand_index_(operand_index), + original_id_(inst->GetOperand(operand_index).words[0]), + original_type_(inst->GetOperand(operand_index).type), + new_id_(new_id) {} + + bool PreconditionHolds() override; + + protected: + void Apply() override; + + private: + opt::Instruction* const inst_; + const uint32_t operand_index_; + const uint32_t original_id_; + const spv_operand_type_t original_type_; + const uint32_t new_id_; +}; + +} // namespace reduce +} // namespace spvtools + +#endif // SOURCE_REDUCE_CHANGE_OPERAND_REDUCTION_OPPORTUNITY_H_ diff --git a/third_party/spirv-tools/source/reduce/change_operand_to_undef_reduction_opportunity.cpp b/third_party/spirv-tools/source/reduce/change_operand_to_undef_reduction_opportunity.cpp new file mode 100644 index 0000000000..8e33da661e --- /dev/null +++ b/third_party/spirv-tools/source/reduce/change_operand_to_undef_reduction_opportunity.cpp @@ -0,0 +1,41 @@ +// Copyright (c) 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/reduce/change_operand_to_undef_reduction_opportunity.h" + +#include "source/opt/ir_context.h" +#include "source/reduce/reduction_util.h" + +namespace spvtools { +namespace reduce { + +bool ChangeOperandToUndefReductionOpportunity::PreconditionHolds() { + // Check that the instruction still has the original operand. + return inst_->NumOperands() > operand_index_ && + inst_->GetOperand(operand_index_).words[0] == original_id_; +} + +void ChangeOperandToUndefReductionOpportunity::Apply() { + auto operand = inst_->GetOperand(operand_index_); + auto operand_id = operand.words[0]; + auto operand_id_def = context_->get_def_use_mgr()->GetDef(operand_id); + auto operand_type_id = operand_id_def->type_id(); + // The opportunity should not exist unless this holds. + assert(operand_type_id); + auto undef_id = FindOrCreateGlobalUndef(context_, operand_type_id); + inst_->SetOperand(operand_index_, {undef_id}); +} + +} // namespace reduce +} // namespace spvtools diff --git a/third_party/spirv-tools/source/reduce/change_operand_to_undef_reduction_opportunity.h b/third_party/spirv-tools/source/reduce/change_operand_to_undef_reduction_opportunity.h new file mode 100644 index 0000000000..ffd3155b0a --- /dev/null +++ b/third_party/spirv-tools/source/reduce/change_operand_to_undef_reduction_opportunity.h @@ -0,0 +1,53 @@ +// Copyright (c) 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_REDUCE_CHANGE_OPERAND_TO_UNDEF_REDUCTION_OPPORTUNITY_H_ +#define SOURCE_REDUCE_CHANGE_OPERAND_TO_UNDEF_REDUCTION_OPPORTUNITY_H_ + +#include "source/opt/instruction.h" +#include "source/reduce/reduction_opportunity.h" +#include "spirv-tools/libspirv.h" + +namespace spvtools { +namespace reduce { + +// An opportunity to replace an id operand of an instruction with undef. +class ChangeOperandToUndefReductionOpportunity : public ReductionOpportunity { + public: + // Constructs the opportunity to replace operand |operand_index| of |inst| + // with undef. + ChangeOperandToUndefReductionOpportunity(opt::IRContext* context, + opt::Instruction* inst, + uint32_t operand_index) + : context_(context), + inst_(inst), + operand_index_(operand_index), + original_id_(inst->GetOperand(operand_index).words[0]) {} + + bool PreconditionHolds() override; + + protected: + void Apply() override; + + private: + opt::IRContext* context_; + opt::Instruction* const inst_; + const uint32_t operand_index_; + const uint32_t original_id_; +}; + +} // namespace reduce +} // namespace spvtools + +#endif // SOURCE_REDUCE_CHANGE_OPERAND_TO_UNDEF_REDUCTION_OPPORTUNITY_H_ diff --git a/third_party/spirv-tools/source/reduce/conditional_branch_to_simple_conditional_branch_opportunity_finder.cpp b/third_party/spirv-tools/source/reduce/conditional_branch_to_simple_conditional_branch_opportunity_finder.cpp new file mode 100644 index 0000000000..0bd93b9b41 --- /dev/null +++ b/third_party/spirv-tools/source/reduce/conditional_branch_to_simple_conditional_branch_opportunity_finder.cpp @@ -0,0 +1,89 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/reduce/conditional_branch_to_simple_conditional_branch_opportunity_finder.h" + +#include "source/reduce/conditional_branch_to_simple_conditional_branch_reduction_opportunity.h" +#include "source/reduce/reduction_util.h" + +namespace spvtools { +namespace reduce { + +using opt::IRContext; +using opt::Instruction; + +std::vector> +ConditionalBranchToSimpleConditionalBranchOpportunityFinder:: + GetAvailableOpportunities(IRContext* context) const { + std::vector> result; + + // Find the opportunities for redirecting all false targets before the + // opportunities for redirecting all true targets because the former + // opportunities disable the latter, and vice versa, and the efficiency of the + // reducer is improved by avoiding contiguous opportunities that disable one + // another. + for (bool redirect_to_true : {true, false}) { + // Consider every function. + for (auto& function : *context->module()) { + // Consider every block in the function. + for (auto& block : function) { + // The terminator must be SpvOpBranchConditional. + Instruction* terminator = block.terminator(); + if (terminator->opcode() != SpvOpBranchConditional) { + continue; + } + + uint32_t true_block_id = + terminator->GetSingleWordInOperand(kTrueBranchOperandIndex); + uint32_t false_block_id = + terminator->GetSingleWordInOperand(kFalseBranchOperandIndex); + + // The conditional branch must not already be simplified. + if (true_block_id == false_block_id) { + continue; + } + + // The redirected target must not be a back-edge to a structured loop + // header. + uint32_t redirected_block_id = + redirect_to_true ? false_block_id : true_block_id; + uint32_t containing_loop_header = + context->GetStructuredCFGAnalysis()->ContainingLoop(block.id()); + // The structured CFG analysis does not include a loop header as part + // of the loop construct, but we want to include it, so handle this + // special case: + if (block.GetLoopMergeInst() != nullptr) { + containing_loop_header = block.id(); + } + if (redirected_block_id == containing_loop_header) { + continue; + } + + result.push_back( + MakeUnique< + ConditionalBranchToSimpleConditionalBranchReductionOpportunity>( + context, block.terminator(), redirect_to_true)); + } + } + } + return result; +} + +std::string +ConditionalBranchToSimpleConditionalBranchOpportunityFinder::GetName() const { + return "ConditionalBranchToSimpleConditionalBranchOpportunityFinder"; +} + +} // namespace reduce +} // namespace spvtools diff --git a/third_party/spirv-tools/source/reduce/conditional_branch_to_simple_conditional_branch_opportunity_finder.h b/third_party/spirv-tools/source/reduce/conditional_branch_to_simple_conditional_branch_opportunity_finder.h new file mode 100644 index 0000000000..c582a889ee --- /dev/null +++ b/third_party/spirv-tools/source/reduce/conditional_branch_to_simple_conditional_branch_opportunity_finder.h @@ -0,0 +1,37 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_REDUCE_SIMPLIFY_SELECTION_OPPORTUNITY_FINDER_H_ +#define SOURCE_REDUCE_SIMPLIFY_SELECTION_OPPORTUNITY_FINDER_H_ + +#include "source/reduce/reduction_opportunity_finder.h" + +namespace spvtools { +namespace reduce { + +// A finder for opportunities to simplify conditional branches into simple +// conditional branches (conditional branches with one target). +class ConditionalBranchToSimpleConditionalBranchOpportunityFinder + : public ReductionOpportunityFinder { + public: + std::vector> GetAvailableOpportunities( + opt::IRContext* context) const override; + + std::string GetName() const override; +}; + +} // namespace reduce +} // namespace spvtools + +#endif // SOURCE_REDUCE_SIMPLIFY_SELECTION_OPPORTUNITY_FINDER_H_ diff --git a/third_party/spirv-tools/source/reduce/conditional_branch_to_simple_conditional_branch_reduction_opportunity.cpp b/third_party/spirv-tools/source/reduce/conditional_branch_to_simple_conditional_branch_reduction_opportunity.cpp new file mode 100644 index 0000000000..d744773bda --- /dev/null +++ b/third_party/spirv-tools/source/reduce/conditional_branch_to_simple_conditional_branch_reduction_opportunity.cpp @@ -0,0 +1,70 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/reduce/conditional_branch_to_simple_conditional_branch_reduction_opportunity.h" + +#include "source/reduce/reduction_util.h" + +namespace spvtools { +namespace reduce { + +using opt::IRContext; +using opt::Instruction; + +ConditionalBranchToSimpleConditionalBranchReductionOpportunity:: + ConditionalBranchToSimpleConditionalBranchReductionOpportunity( + IRContext* context, Instruction* conditional_branch_instruction, + bool redirect_to_true) + : context_(context), + conditional_branch_instruction_(conditional_branch_instruction), + redirect_to_true_(redirect_to_true) {} + +bool ConditionalBranchToSimpleConditionalBranchReductionOpportunity:: + PreconditionHolds() { + // Another opportunity may have already simplified this conditional branch, + // which should disable this opportunity. + return conditional_branch_instruction_->GetSingleWordInOperand( + kTrueBranchOperandIndex) != + conditional_branch_instruction_->GetSingleWordInOperand( + kFalseBranchOperandIndex); +} + +void ConditionalBranchToSimpleConditionalBranchReductionOpportunity::Apply() { + uint32_t operand_to_modify = + redirect_to_true_ ? kFalseBranchOperandIndex : kTrueBranchOperandIndex; + uint32_t operand_to_copy = + redirect_to_true_ ? kTrueBranchOperandIndex : kFalseBranchOperandIndex; + + auto old_successor_block_id = + conditional_branch_instruction_->GetSingleWordInOperand( + operand_to_modify); + + // Do the branch redirection. + conditional_branch_instruction_->SetInOperand( + operand_to_modify, + {conditional_branch_instruction_->GetSingleWordInOperand( + operand_to_copy)}); + + // The old successor block may have phi instructions; these will need to + // respect the change in edges. + AdaptPhiInstructionsForRemovedEdge( + context_->get_instr_block(conditional_branch_instruction_)->id(), + context_->cfg()->block(old_successor_block_id)); + + // We have changed the CFG. + context_->InvalidateAnalysesExceptFor(IRContext::Analysis::kAnalysisNone); +} + +} // namespace reduce +} // namespace spvtools diff --git a/third_party/spirv-tools/source/reduce/conditional_branch_to_simple_conditional_branch_reduction_opportunity.h b/third_party/spirv-tools/source/reduce/conditional_branch_to_simple_conditional_branch_reduction_opportunity.h new file mode 100644 index 0000000000..1f9cb6d18c --- /dev/null +++ b/third_party/spirv-tools/source/reduce/conditional_branch_to_simple_conditional_branch_reduction_opportunity.h @@ -0,0 +1,54 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_REDUCE_SIMPLIFY_CONDITIONAL_BRANCH_REDUCTION_OPPORTUNITY_H_ +#define SOURCE_REDUCE_SIMPLIFY_CONDITIONAL_BRANCH_REDUCTION_OPPORTUNITY_H_ + +#include "source/opt/basic_block.h" +#include "source/reduce/reduction_opportunity.h" + +namespace spvtools { +namespace reduce { + +// An opportunity to simplify a conditional branch to a simple conditional +// branch (a conditional branch with one target). +class ConditionalBranchToSimpleConditionalBranchReductionOpportunity + : public ReductionOpportunity { + public: + // Constructs an opportunity to simplify |conditional_branch_instruction|. If + // |redirect_to_true| is true, the false target will be changed to also point + // to the true target; otherwise, the true target will be changed to also + // point to the false target. + explicit ConditionalBranchToSimpleConditionalBranchReductionOpportunity( + opt::IRContext* context, opt::Instruction* conditional_branch_instruction, + bool redirect_to_true); + + bool PreconditionHolds() override; + + protected: + void Apply() override; + + private: + opt::IRContext* context_; + opt::Instruction* conditional_branch_instruction_; + + // If true, the false target will be changed to point to the true target; + // otherwise, the true target will be changed to point to the false target. + bool redirect_to_true_; +}; + +} // namespace reduce +} // namespace spvtools + +#endif // SOURCE_REDUCE_SIMPLIFY_CONDITIONAL_BRANCH_REDUCTION_OPPORTUNITY_H_ diff --git a/third_party/spirv-tools/source/reduce/merge_blocks_reduction_opportunity.cpp b/third_party/spirv-tools/source/reduce/merge_blocks_reduction_opportunity.cpp new file mode 100644 index 0000000000..42c7843916 --- /dev/null +++ b/third_party/spirv-tools/source/reduce/merge_blocks_reduction_opportunity.cpp @@ -0,0 +1,83 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/reduce/merge_blocks_reduction_opportunity.h" + +#include "source/opt/block_merge_util.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace reduce { + +using opt::BasicBlock; +using opt::Function; +using opt::IRContext; + +MergeBlocksReductionOpportunity::MergeBlocksReductionOpportunity( + IRContext* context, Function* function, BasicBlock* block) { + // Precondition: the terminator has to be OpBranch. + assert(block->terminator()->opcode() == SpvOpBranch); + context_ = context; + function_ = function; + // Get the successor block associated with the OpBranch. + successor_block_ = + context->cfg()->block(block->terminator()->GetSingleWordInOperand(0)); +} + +bool MergeBlocksReductionOpportunity::PreconditionHolds() { + // Merge block opportunities can disable each other. + // Example: Given blocks: A->B->C. + // A is a loop header; B and C are blocks in the loop; C ends with OpReturn. + // There are two opportunities: B and C can be merged with their predecessors. + // Merge C. B now ends with OpReturn. We now just have: A->B. + // Merge B is now disabled, as this would lead to A, a loop header, ending + // with an OpReturn, which is invalid. + + const auto predecessors = context_->cfg()->preds(successor_block_->id()); + assert(1 == predecessors.size() && + "For a successor to be merged into its predecessor, exactly one " + "predecessor must be present."); + const uint32_t predecessor_id = predecessors[0]; + BasicBlock* predecessor_block = context_->get_instr_block(predecessor_id); + return opt::blockmergeutil::CanMergeWithSuccessor(context_, + predecessor_block); +} + +void MergeBlocksReductionOpportunity::Apply() { + // While the original block that targeted the successor may not exist anymore + // (it might have been merged with another block), some block must exist that + // targets the successor. Find it. + + const auto predecessors = context_->cfg()->preds(successor_block_->id()); + assert(1 == predecessors.size() && + "For a successor to be merged into its predecessor, exactly one " + "predecessor must be present."); + const uint32_t predecessor_id = predecessors[0]; + + // We need an iterator pointing to the predecessor, hence the loop. + for (auto bi = function_->begin(); bi != function_->end(); ++bi) { + if (bi->id() == predecessor_id) { + opt::blockmergeutil::MergeWithSuccessor(context_, function_, bi); + // Block merging changes the control flow graph, so invalidate it. + context_->InvalidateAnalysesExceptFor(IRContext::Analysis::kAnalysisNone); + return; + } + } + + assert(false && + "Unreachable: we should have found a block with the desired id."); +} + +} // namespace reduce +} // namespace spvtools diff --git a/third_party/spirv-tools/source/reduce/merge_blocks_reduction_opportunity.h b/third_party/spirv-tools/source/reduce/merge_blocks_reduction_opportunity.h new file mode 100644 index 0000000000..5c9180b9be --- /dev/null +++ b/third_party/spirv-tools/source/reduce/merge_blocks_reduction_opportunity.h @@ -0,0 +1,53 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_REDUCE_MERGE_BLOCKS_REDUCTION_OPPORTUNITY_H_ +#define SOURCE_REDUCE_MERGE_BLOCKS_REDUCTION_OPPORTUNITY_H_ + +#include "source/opt/basic_block.h" +#include "source/opt/function.h" +#include "source/reduce/reduction_opportunity.h" + +namespace spvtools { +namespace reduce { + +// An opportunity to merge two blocks into one. +class MergeBlocksReductionOpportunity : public ReductionOpportunity { + public: + // Creates the opportunity to merge |block| with its successor, where |block| + // is inside |function|, and |context| is the enclosing IR context. + MergeBlocksReductionOpportunity(opt::IRContext* context, + opt::Function* function, + opt::BasicBlock* block); + + bool PreconditionHolds() override; + + protected: + void Apply() override; + + private: + opt::IRContext* context_; + opt::Function* function_; + + // Rather than holding on to the block that can be merged with its successor, + // we hold on to its successor. This is because the predecessor block might + // get merged with *its* predecessor, and so will no longer exist, while the + // successor will continue to exist until this opportunity gets applied. + opt::BasicBlock* successor_block_; +}; + +} // namespace reduce +} // namespace spvtools + +#endif // SOURCE_REDUCE_MERGE_BLOCKS_REDUCTION_OPPORTUNITY_H_ diff --git a/third_party/spirv-tools/source/reduce/merge_blocks_reduction_opportunity_finder.cpp b/third_party/spirv-tools/source/reduce/merge_blocks_reduction_opportunity_finder.cpp new file mode 100644 index 0000000000..89d62632d6 --- /dev/null +++ b/third_party/spirv-tools/source/reduce/merge_blocks_reduction_opportunity_finder.cpp @@ -0,0 +1,48 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/reduce/merge_blocks_reduction_opportunity_finder.h" +#include "source/opt/block_merge_util.h" +#include "source/reduce/merge_blocks_reduction_opportunity.h" + +namespace spvtools { +namespace reduce { + +using opt::IRContext; + +std::string MergeBlocksReductionOpportunityFinder::GetName() const { + return "MergeBlocksReductionOpportunityFinder"; +} + +std::vector> +MergeBlocksReductionOpportunityFinder::GetAvailableOpportunities( + IRContext* context) const { + std::vector> result; + + // Consider every block in every function. + for (auto& function : *context->module()) { + for (auto& block : function) { + // See whether it is possible to merge this block with its successor. + if (opt::blockmergeutil::CanMergeWithSuccessor(context, &block)) { + // It is, so record an opportunity to do this. + result.push_back(spvtools::MakeUnique( + context, &function, &block)); + } + } + } + return result; +} + +} // namespace reduce +} // namespace spvtools diff --git a/third_party/spirv-tools/source/reduce/merge_blocks_reduction_opportunity_finder.h b/third_party/spirv-tools/source/reduce/merge_blocks_reduction_opportunity_finder.h new file mode 100644 index 0000000000..dbf82fec86 --- /dev/null +++ b/third_party/spirv-tools/source/reduce/merge_blocks_reduction_opportunity_finder.h @@ -0,0 +1,42 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_REDUCE_MERGE_BLOCKS_REDUCTION_OPPORTUNITY_FINDER_H_ +#define SOURCE_REDUCE_MERGE_BLOCKS_REDUCTION_OPPORTUNITY_FINDER_H_ + +#include "source/reduce/reduction_opportunity_finder.h" + +namespace spvtools { +namespace reduce { + +// A finder of opportunities to merge blocks together. +class MergeBlocksReductionOpportunityFinder + : public ReductionOpportunityFinder { + public: + MergeBlocksReductionOpportunityFinder() = default; + + ~MergeBlocksReductionOpportunityFinder() override = default; + + std::string GetName() const final; + + std::vector> GetAvailableOpportunities( + opt::IRContext* context) const final; + + private: +}; + +} // namespace reduce +} // namespace spvtools + +#endif // SOURCE_REDUCE_MERGE_BLOCKS_REDUCTION_OPPORTUNITY_FINDER_H_ diff --git a/third_party/spirv-tools/source/reduce/operand_to_const_reduction_opportunity_finder.cpp b/third_party/spirv-tools/source/reduce/operand_to_const_reduction_opportunity_finder.cpp new file mode 100644 index 0000000000..3e0a22488b --- /dev/null +++ b/third_party/spirv-tools/source/reduce/operand_to_const_reduction_opportunity_finder.cpp @@ -0,0 +1,83 @@ +// Copyright (c) 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/reduce/operand_to_const_reduction_opportunity_finder.h" + +#include "source/opt/instruction.h" +#include "source/reduce/change_operand_reduction_opportunity.h" + +namespace spvtools { +namespace reduce { + +using opt::IRContext; + +std::vector> +OperandToConstReductionOpportunityFinder::GetAvailableOpportunities( + IRContext* context) const { + std::vector> result; + assert(result.empty()); + + // We first loop over all constants. This means that all the reduction + // opportunities to replace an operand with a particular constant will be + // contiguous, and in particular it means that multiple, incompatible + // reduction opportunities that try to replace the same operand with distinct + // constants are likely to be discontiguous. This is good because the + // reducer works in the spirit of delta debugging and tries applying large + // contiguous blocks of opportunities early on, and we want to avoid having a + // large block of incompatible opportunities if possible. + for (const auto& constant : context->GetConstants()) { + for (auto& function : *context->module()) { + for (auto& block : function) { + for (auto& inst : block) { + // We iterate through the operands using an explicit index (rather + // than using a lambda) so that we use said index in the construction + // of a ChangeOperandReductionOpportunity + for (uint32_t index = 0; index < inst.NumOperands(); index++) { + const auto& operand = inst.GetOperand(index); + if (spvIsInIdType(operand.type)) { + const auto id = operand.words[0]; + auto def = context->get_def_use_mgr()->GetDef(id); + if (spvOpcodeIsConstant(def->opcode())) { + // The argument is already a constant. + continue; + } + if (def->opcode() == SpvOpFunction) { + // The argument refers to a function, e.g. the function called + // by OpFunctionCall; avoid replacing this with a constant of + // the function's return type. + continue; + } + auto type_id = def->type_id(); + if (type_id) { + if (constant->type_id() == type_id) { + result.push_back( + MakeUnique( + &inst, index, constant->result_id())); + } + } + } + } + } + } + } + } + return result; +} + +std::string OperandToConstReductionOpportunityFinder::GetName() const { + return "OperandToConstReductionOpportunityFinder"; +} + +} // namespace reduce +} // namespace spvtools diff --git a/third_party/spirv-tools/source/reduce/operand_to_const_reduction_opportunity_finder.h b/third_party/spirv-tools/source/reduce/operand_to_const_reduction_opportunity_finder.h new file mode 100644 index 0000000000..93c0dcd3f4 --- /dev/null +++ b/third_party/spirv-tools/source/reduce/operand_to_const_reduction_opportunity_finder.h @@ -0,0 +1,44 @@ +// Copyright (c) 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_REDUCE_OPERAND_TO_CONST_REDUCTION_OPPORTUNITY_FINDER_H_ +#define SOURCE_REDUCE_OPERAND_TO_CONST_REDUCTION_OPPORTUNITY_FINDER_H_ + +#include "source/reduce/reduction_opportunity_finder.h" + +namespace spvtools { +namespace reduce { + +// A finder for opportunities to replace id operands of instructions with ids of +// constants. This reduces the extent to which ids of non-constants are used, +// paving the way for instructions that generate them to be eliminated. +class OperandToConstReductionOpportunityFinder + : public ReductionOpportunityFinder { + public: + OperandToConstReductionOpportunityFinder() = default; + + ~OperandToConstReductionOpportunityFinder() override = default; + + std::string GetName() const final; + + std::vector> GetAvailableOpportunities( + opt::IRContext* context) const final; + + private: +}; + +} // namespace reduce +} // namespace spvtools + +#endif // SOURCE_REDUCE_OPERAND_TO_CONST_REDUCTION_OPPORTUNITY_FINDER_H_ diff --git a/third_party/spirv-tools/source/reduce/operand_to_dominating_id_reduction_opportunity_finder.cpp b/third_party/spirv-tools/source/reduce/operand_to_dominating_id_reduction_opportunity_finder.cpp new file mode 100644 index 0000000000..13beb89023 --- /dev/null +++ b/third_party/spirv-tools/source/reduce/operand_to_dominating_id_reduction_opportunity_finder.cpp @@ -0,0 +1,118 @@ +// Copyright (c) 2018 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/reduce/operand_to_dominating_id_reduction_opportunity_finder.h" + +#include "source/opt/instruction.h" +#include "source/reduce/change_operand_reduction_opportunity.h" + +namespace spvtools { +namespace reduce { + +using opt::Function; +using opt::IRContext; +using opt::Instruction; + +std::vector> +OperandToDominatingIdReductionOpportunityFinder::GetAvailableOpportunities( + IRContext* context) const { + std::vector> result; + + // Go through every instruction in every block, considering it as a potential + // dominator of other instructions. We choose this order for two reasons: + // + // (1) it is profitable for multiple opportunities to replace the same id x by + // different dominating ids y and z to be discontiguous, as they are + // incompatible. + // + // (2) We want to prioritise opportunities to replace an id with a more + // distant dominator. Intuitively, in a human-readable programming language + // if we have a complex expression e with many sub-expressions, we would like + // to prioritise replacing e with its smallest sub-expressions; generalising + // this idea to dominating ids this roughly corresponds to more distant + // dominators. + for (auto& function : *context->module()) { + for (auto dominating_block = function.begin(); + dominating_block != function.end(); ++dominating_block) { + for (auto& dominating_inst : *dominating_block) { + if (dominating_inst.HasResultId() && dominating_inst.type_id()) { + // Consider replacing any operand with matching type in a dominated + // instruction with the id generated by this instruction. + GetOpportunitiesForDominatingInst( + &result, &dominating_inst, dominating_block, &function, context); + } + } + } + } + return result; +} + +void OperandToDominatingIdReductionOpportunityFinder:: + GetOpportunitiesForDominatingInst( + std::vector>* opportunities, + Instruction* candidate_dominator, + Function::iterator candidate_dominator_block, Function* function, + IRContext* context) const { + assert(candidate_dominator->HasResultId()); + assert(candidate_dominator->type_id()); + auto dominator_analysis = context->GetDominatorAnalysis(function); + // SPIR-V requires a block to precede all blocks it dominates, so it suffices + // to search from the candidate dominator block onwards. + for (auto block = candidate_dominator_block; block != function->end(); + ++block) { + if (!dominator_analysis->Dominates(&*candidate_dominator_block, &*block)) { + // If the candidate dominator block doesn't dominate this block then there + // cannot be any of the desired reduction opportunities in this block. + continue; + } + for (auto& inst : *block) { + // We iterate through the operands using an explicit index (rather + // than using a lambda) so that we use said index in the construction + // of a ChangeOperandReductionOpportunity + for (uint32_t index = 0; index < inst.NumOperands(); index++) { + const auto& operand = inst.GetOperand(index); + if (spvIsInIdType(operand.type)) { + const auto id = operand.words[0]; + auto def = context->get_def_use_mgr()->GetDef(id); + assert(def); + if (!context->get_instr_block(def)) { + // The definition does not come from a block; e.g. it might be a + // constant. It is thus not relevant to this pass. + continue; + } + // Sanity check that we don't get here if the argument is a constant. + assert(!context->get_constant_mgr()->GetConstantFromInst(def)); + if (def->type_id() != candidate_dominator->type_id()) { + // The types need to match. + continue; + } + if (candidate_dominator != def && + dominator_analysis->Dominates(candidate_dominator, def)) { + // A hit: the candidate dominator strictly dominates the definition. + opportunities->push_back( + MakeUnique( + &inst, index, candidate_dominator->result_id())); + } + } + } + } + } +} + +std::string OperandToDominatingIdReductionOpportunityFinder::GetName() const { + return "OperandToDominatingIdReductionOpportunityFinder"; +} + +} // namespace reduce +} // namespace spvtools diff --git a/third_party/spirv-tools/source/reduce/operand_to_dominating_id_reduction_opportunity_finder.h b/third_party/spirv-tools/source/reduce/operand_to_dominating_id_reduction_opportunity_finder.h new file mode 100644 index 0000000000..7745ff7014 --- /dev/null +++ b/third_party/spirv-tools/source/reduce/operand_to_dominating_id_reduction_opportunity_finder.h @@ -0,0 +1,56 @@ +// Copyright (c) 2018 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_REDUCE_OPERAND_TO_DOMINATING_ID_REDUCTION_OPPORTUNITY_FINDER_H_ +#define SOURCE_REDUCE_OPERAND_TO_DOMINATING_ID_REDUCTION_OPPORTUNITY_FINDER_H_ + +#include "source/reduce/reduction_opportunity_finder.h" + +namespace spvtools { +namespace reduce { + +// A finder that aims to bring to SPIR-V (and generalize) the idea from +// human-readable languages of e.g. finding opportunities to replace an +// expression with one of its arguments, (x + y) -> x, or with a reference to an +// identifier that was assigned to higher up in the program. The generalization +// of this is to replace an id with a different id of the same type defined in +// some dominating instruction. +// +// If id x is defined and then used several times, changing each use of x to +// some dominating definition may eventually allow the statement defining x +// to be eliminated by another pass. +class OperandToDominatingIdReductionOpportunityFinder + : public ReductionOpportunityFinder { + public: + OperandToDominatingIdReductionOpportunityFinder() = default; + + ~OperandToDominatingIdReductionOpportunityFinder() override = default; + + std::string GetName() const final; + + std::vector> GetAvailableOpportunities( + opt::IRContext* context) const final; + + private: + void GetOpportunitiesForDominatingInst( + std::vector>* opportunities, + opt::Instruction* dominating_instruction, + opt::Function::iterator candidate_dominator_block, + opt::Function* function, opt::IRContext* context) const; +}; + +} // namespace reduce +} // namespace spvtools + +#endif // SOURCE_REDUCE_OPERAND_TO_DOMINATING_ID_REDUCTION_OPPORTUNITY_FINDER_H_ diff --git a/third_party/spirv-tools/source/reduce/operand_to_undef_reduction_opportunity_finder.cpp b/third_party/spirv-tools/source/reduce/operand_to_undef_reduction_opportunity_finder.cpp new file mode 100644 index 0000000000..579b7df67d --- /dev/null +++ b/third_party/spirv-tools/source/reduce/operand_to_undef_reduction_opportunity_finder.cpp @@ -0,0 +1,94 @@ +// Copyright (c) 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/reduce/operand_to_undef_reduction_opportunity_finder.h" + +#include "source/opt/instruction.h" +#include "source/reduce/change_operand_to_undef_reduction_opportunity.h" + +namespace spvtools { +namespace reduce { + +using opt::IRContext; + +std::vector> +OperandToUndefReductionOpportunityFinder::GetAvailableOpportunities( + IRContext* context) const { + std::vector> result; + + for (auto& function : *context->module()) { + for (auto& block : function) { + for (auto& inst : block) { + // Skip instructions that result in a pointer type. + auto type_id = inst.type_id(); + if (type_id) { + auto type_id_def = context->get_def_use_mgr()->GetDef(type_id); + if (type_id_def->opcode() == SpvOpTypePointer) { + continue; + } + } + + // We iterate through the operands using an explicit index (rather + // than using a lambda) so that we use said index in the construction + // of a ChangeOperandToUndefReductionOpportunity + for (uint32_t index = 0; index < inst.NumOperands(); index++) { + const auto& operand = inst.GetOperand(index); + + if (spvIsInIdType(operand.type)) { + const auto operand_id = operand.words[0]; + auto operand_id_def = + context->get_def_use_mgr()->GetDef(operand_id); + + // Skip constant and undef operands. + // We always want the reducer to make the module "smaller", which + // ensures termination. + // Therefore, we assume: id > undef id > constant id. + if (spvOpcodeIsConstantOrUndef(operand_id_def->opcode())) { + continue; + } + + // Don't replace function operands with undef. + if (operand_id_def->opcode() == SpvOpFunction) { + continue; + } + + // Only consider operands that have a type. + auto operand_type_id = operand_id_def->type_id(); + if (operand_type_id) { + auto operand_type_id_def = + context->get_def_use_mgr()->GetDef(operand_type_id); + + // Skip pointer operands. + if (operand_type_id_def->opcode() == SpvOpTypePointer) { + continue; + } + + result.push_back( + MakeUnique( + context, &inst, index)); + } + } + } + } + } + } + return result; +} + +std::string OperandToUndefReductionOpportunityFinder::GetName() const { + return "OperandToUndefReductionOpportunityFinder"; +} + +} // namespace reduce +} // namespace spvtools diff --git a/third_party/spirv-tools/source/reduce/operand_to_undef_reduction_opportunity_finder.h b/third_party/spirv-tools/source/reduce/operand_to_undef_reduction_opportunity_finder.h new file mode 100644 index 0000000000..9cdd8cd563 --- /dev/null +++ b/third_party/spirv-tools/source/reduce/operand_to_undef_reduction_opportunity_finder.h @@ -0,0 +1,43 @@ +// Copyright (c) 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_REDUCE_OPERAND_TO_UNDEF_REDUCTION_OPPORTUNITY_FINDER_H_ +#define SOURCE_REDUCE_OPERAND_TO_UNDEF_REDUCTION_OPPORTUNITY_FINDER_H_ + +#include "source/reduce/reduction_opportunity_finder.h" + +namespace spvtools { +namespace reduce { + +// A finder of opportunities to replace id operands of instructions with ids of +// undef. +class OperandToUndefReductionOpportunityFinder + : public ReductionOpportunityFinder { + public: + OperandToUndefReductionOpportunityFinder() = default; + + ~OperandToUndefReductionOpportunityFinder() override = default; + + std::string GetName() const final; + + std::vector> GetAvailableOpportunities( + opt::IRContext* context) const final; + + private: +}; + +} // namespace reduce +} // namespace spvtools + +#endif // SOURCE_REDUCE_OPERAND_TO_UNDEF_REDUCTION_OPPORTUNITY_FINDER_H_ diff --git a/third_party/spirv-tools/source/reduce/pch_source_reduce.cpp b/third_party/spirv-tools/source/reduce/pch_source_reduce.cpp new file mode 100644 index 0000000000..61e743645d --- /dev/null +++ b/third_party/spirv-tools/source/reduce/pch_source_reduce.cpp @@ -0,0 +1,15 @@ +// Copyright (c) 2018 The Khronos Group Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "pch_source_reduce.h" diff --git a/third_party/spirv-tools/source/reduce/pch_source_reduce.h b/third_party/spirv-tools/source/reduce/pch_source_reduce.h new file mode 100644 index 0000000000..6c0da0c7b5 --- /dev/null +++ b/third_party/spirv-tools/source/reduce/pch_source_reduce.h @@ -0,0 +1,23 @@ +// Copyright (c) 2018 The Khronos Group Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include "source/reduce/change_operand_reduction_opportunity.h" +#include "source/reduce/operand_to_const_reduction_opportunity_finder.h" +#include "source/reduce/reduction_opportunity.h" +#include "source/reduce/reduction_pass.h" +#include "source/reduce/remove_instruction_reduction_opportunity.h" +#include "source/reduce/remove_unreferenced_instruction_reduction_opportunity_finder.h" diff --git a/third_party/spirv-tools/source/reduce/reducer.cpp b/third_party/spirv-tools/source/reduce/reducer.cpp new file mode 100644 index 0000000000..bda41ce945 --- /dev/null +++ b/third_party/spirv-tools/source/reduce/reducer.cpp @@ -0,0 +1,242 @@ +// Copyright (c) 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/reduce/reducer.h" + +#include +#include + +#include "source/reduce/conditional_branch_to_simple_conditional_branch_opportunity_finder.h" +#include "source/reduce/merge_blocks_reduction_opportunity_finder.h" +#include "source/reduce/operand_to_const_reduction_opportunity_finder.h" +#include "source/reduce/operand_to_dominating_id_reduction_opportunity_finder.h" +#include "source/reduce/operand_to_undef_reduction_opportunity_finder.h" +#include "source/reduce/remove_block_reduction_opportunity_finder.h" +#include "source/reduce/remove_function_reduction_opportunity_finder.h" +#include "source/reduce/remove_selection_reduction_opportunity_finder.h" +#include "source/reduce/remove_unreferenced_instruction_reduction_opportunity_finder.h" +#include "source/reduce/simple_conditional_branch_to_branch_opportunity_finder.h" +#include "source/reduce/structured_loop_to_selection_reduction_opportunity_finder.h" +#include "source/spirv_reducer_options.h" + +namespace spvtools { +namespace reduce { + +Reducer::Reducer(spv_target_env target_env) : target_env_(target_env) {} + +Reducer::~Reducer() = default; + +void Reducer::SetMessageConsumer(MessageConsumer c) { + for (auto& pass : passes_) { + pass->SetMessageConsumer(c); + } + for (auto& pass : cleanup_passes_) { + pass->SetMessageConsumer(c); + } + consumer_ = std::move(c); +} + +void Reducer::SetInterestingnessFunction( + Reducer::InterestingnessFunction interestingness_function) { + interestingness_function_ = std::move(interestingness_function); +} + +Reducer::ReductionResultStatus Reducer::Run( + std::vector&& binary_in, std::vector* binary_out, + spv_const_reducer_options options, + spv_validator_options validator_options) { + std::vector current_binary(std::move(binary_in)); + + spvtools::SpirvTools tools(target_env_); + assert(tools.IsValid() && "Failed to create SPIRV-Tools interface"); + + // Keeps track of how many reduction attempts have been tried. Reduction + // bails out if this reaches a given limit. + uint32_t reductions_applied = 0; + + // Initial state should be valid. + if (!tools.Validate(¤t_binary[0], current_binary.size(), + validator_options)) { + consumer_(SPV_MSG_INFO, nullptr, {}, + "Initial binary is invalid; stopping."); + return Reducer::ReductionResultStatus::kInitialStateInvalid; + } + + // Initial state should be interesting. + if (!interestingness_function_(current_binary, reductions_applied)) { + consumer_(SPV_MSG_INFO, nullptr, {}, + "Initial state was not interesting; stopping."); + return Reducer::ReductionResultStatus::kInitialStateNotInteresting; + } + + Reducer::ReductionResultStatus result = + RunPasses(&passes_, options, validator_options, tools, ¤t_binary, + &reductions_applied); + + if (result == Reducer::ReductionResultStatus::kComplete) { + // Cleanup passes. + result = RunPasses(&cleanup_passes_, options, validator_options, tools, + ¤t_binary, &reductions_applied); + } + + if (result == Reducer::ReductionResultStatus::kComplete) { + consumer_(SPV_MSG_INFO, nullptr, {}, "No more to reduce; stopping."); + } + + // Even if the reduction has failed by this point (e.g. due to producing an + // invalid binary), we still update the output binary for better debugging. + *binary_out = std::move(current_binary); + + return result; +} + +void Reducer::AddDefaultReductionPasses() { + AddReductionPass( + spvtools::MakeUnique< + RemoveUnreferencedInstructionReductionOpportunityFinder>(false)); + AddReductionPass( + spvtools::MakeUnique()); + AddReductionPass( + spvtools::MakeUnique()); + AddReductionPass( + spvtools::MakeUnique()); + AddReductionPass(spvtools::MakeUnique< + StructuredLoopToSelectionReductionOpportunityFinder>()); + AddReductionPass( + spvtools::MakeUnique()); + AddReductionPass( + spvtools::MakeUnique()); + AddReductionPass( + spvtools::MakeUnique()); + AddReductionPass( + spvtools::MakeUnique()); + AddReductionPass( + spvtools::MakeUnique< + ConditionalBranchToSimpleConditionalBranchOpportunityFinder>()); + AddReductionPass( + spvtools::MakeUnique()); + + // Cleanup passes. + + AddCleanupReductionPass( + spvtools::MakeUnique< + RemoveUnreferencedInstructionReductionOpportunityFinder>(true)); +} + +void Reducer::AddReductionPass( + std::unique_ptr&& finder) { + passes_.push_back( + spvtools::MakeUnique(target_env_, std::move(finder))); +} + +void Reducer::AddCleanupReductionPass( + std::unique_ptr&& finder) { + cleanup_passes_.push_back( + spvtools::MakeUnique(target_env_, std::move(finder))); +} + +bool Reducer::ReachedStepLimit(uint32_t current_step, + spv_const_reducer_options options) { + return current_step >= options->step_limit; +} + +Reducer::ReductionResultStatus Reducer::RunPasses( + std::vector>* passes, + spv_const_reducer_options options, spv_validator_options validator_options, + const SpirvTools& tools, std::vector* current_binary, + uint32_t* const reductions_applied) { + // Determines whether, on completing one round of reduction passes, it is + // worthwhile trying a further round. + bool another_round_worthwhile = true; + + // Apply round after round of reduction passes until we hit the reduction + // step limit, or deem that another round is not going to be worthwhile. + while (!ReachedStepLimit(*reductions_applied, options) && + another_round_worthwhile) { + // At the start of a round of reduction passes, assume another round will + // not be worthwhile unless we find evidence to the contrary. + another_round_worthwhile = false; + + // Iterate through the available passes. + for (auto& pass : *passes) { + // If this pass hasn't reached its minimum granularity then it's + // worth eventually doing another round of reductions, in order to + // try this pass at a finer granularity. + another_round_worthwhile |= !pass->ReachedMinimumGranularity(); + + // Keep applying this pass at its current granularity until it stops + // working or we hit the reduction step limit. + consumer_(SPV_MSG_INFO, nullptr, {}, + ("Trying pass " + pass->GetName() + ".").c_str()); + do { + auto maybe_result = pass->TryApplyReduction(*current_binary); + if (maybe_result.empty()) { + // For this round, the pass has no more opportunities (chunks) to + // apply, so move on to the next pass. + consumer_( + SPV_MSG_INFO, nullptr, {}, + ("Pass " + pass->GetName() + " did not make a reduction step.") + .c_str()); + break; + } + bool interesting = false; + std::stringstream stringstream; + (*reductions_applied)++; + stringstream << "Pass " << pass->GetName() << " made reduction step " + << *reductions_applied << "."; + consumer_(SPV_MSG_INFO, nullptr, {}, (stringstream.str().c_str())); + if (!tools.Validate(&maybe_result[0], maybe_result.size(), + validator_options)) { + // The reduction step went wrong and an invalid binary was produced. + // By design, this shouldn't happen; this is a safeguard to stop an + // invalid binary from being regarded as interesting. + consumer_(SPV_MSG_INFO, nullptr, {}, + "Reduction step produced an invalid binary."); + if (options->fail_on_validation_error) { + // In this mode, we fail, so we update the current binary so it is + // output for debugging. + *current_binary = std::move(maybe_result); + return Reducer::ReductionResultStatus::kStateInvalid; + } + } else if (interestingness_function_(maybe_result, + *reductions_applied)) { + // Success! The binary produced by this reduction step is + // interesting, so make it the binary of interest henceforth, and + // note that it's worth doing another round of reduction passes. + consumer_(SPV_MSG_INFO, nullptr, {}, "Reduction step succeeded."); + *current_binary = std::move(maybe_result); + interesting = true; + another_round_worthwhile = true; + } + // We must call this before the next call to TryApplyReduction. + pass->NotifyInteresting(interesting); + // Bail out if the reduction step limit has been reached. + } while (!ReachedStepLimit(*reductions_applied, options)); + } + } + + // Report whether reduction completed, or bailed out early due to reaching + // the step limit. + if (ReachedStepLimit(*reductions_applied, options)) { + consumer_(SPV_MSG_INFO, nullptr, {}, + "Reached reduction step limit; stopping."); + return Reducer::ReductionResultStatus::kReachedStepLimit; + } + + // The passes completed successfully, although we may still run more passes. + return Reducer::ReductionResultStatus::kComplete; +} + +} // namespace reduce +} // namespace spvtools diff --git a/third_party/spirv-tools/source/reduce/reducer.h b/third_party/spirv-tools/source/reduce/reducer.h new file mode 100644 index 0000000000..864ce75709 --- /dev/null +++ b/third_party/spirv-tools/source/reduce/reducer.h @@ -0,0 +1,122 @@ +// Copyright (c) 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_REDUCE_REDUCER_H_ +#define SOURCE_REDUCE_REDUCER_H_ + +#include +#include + +#include "source/reduce/reduction_pass.h" +#include "spirv-tools/libspirv.hpp" + +namespace spvtools { +namespace reduce { + +// This class manages the process of applying a reduction -- parameterized by a +// number of reduction passes and an interestingness test, to a SPIR-V binary. +class Reducer { + public: + // Possible statuses that can result from running a reduction. + enum ReductionResultStatus { + kInitialStateNotInteresting, + kReachedStepLimit, + kComplete, + kInitialStateInvalid, + + // Returned when the fail-on-validation-error option is set and a + // reduction step yields a state that fails validation. + kStateInvalid, + }; + + // The type for a function that will take a binary and return true if and + // only if the binary is deemed interesting. (The function also takes an + // integer argument that will be incremented each time the function is + // called; this is for debugging purposes). + // + // The notion of "interesting" depends on what properties of the binary or + // tools that process the binary we are trying to maintain during reduction. + using InterestingnessFunction = + std::function&, uint32_t)>; + + // Constructs an instance with the given target |target_env|, which is used to + // decode the binary to be reduced later. + // + // The constructed instance will have an empty message consumer, which just + // ignores all messages from the library. Use SetMessageConsumer() to supply + // one if messages are of concern. + // + // The constructed instance also needs to have an interestingness function + // set and some reduction passes added to it in order to be useful. + explicit Reducer(spv_target_env target_env); + + // Disables copy/move constructor/assignment operations. + Reducer(const Reducer&) = delete; + Reducer(Reducer&&) = delete; + Reducer& operator=(const Reducer&) = delete; + Reducer& operator=(Reducer&&) = delete; + + // Destructs this instance. + ~Reducer(); + + // Sets the message consumer to the given |consumer|. The |consumer| will be + // invoked once for each message communicated from the library. + void SetMessageConsumer(MessageConsumer consumer); + + // Sets the function that will be used to decide whether a reduced binary + // turned out to be interesting. + void SetInterestingnessFunction( + InterestingnessFunction interestingness_function); + + // Adds all default reduction passes. + void AddDefaultReductionPasses(); + + // Adds a reduction pass based on the given finder to the sequence of passes + // that will be iterated over. + void AddReductionPass(std::unique_ptr&& finder); + + // Adds a cleanup reduction pass based on the given finder to the sequence of + // passes that will run after other passes. + void AddCleanupReductionPass( + std::unique_ptr&& finder); + + // Reduces the given SPIR-V module |binary_out|. + // The reduced binary ends up in |binary_out|. + // A status is returned. + ReductionResultStatus Run(std::vector&& binary_in, + std::vector* binary_out, + spv_const_reducer_options options, + spv_validator_options validator_options); + + private: + static bool ReachedStepLimit(uint32_t current_step, + spv_const_reducer_options options); + + ReductionResultStatus RunPasses( + std::vector>* passes, + spv_const_reducer_options options, + spv_validator_options validator_options, const SpirvTools& tools, + std::vector* current_binary, uint32_t* reductions_applied); + + const spv_target_env target_env_; + MessageConsumer consumer_; + InterestingnessFunction interestingness_function_; + std::vector> passes_; + std::vector> cleanup_passes_; +}; + +} // namespace reduce +} // namespace spvtools + +#endif // SOURCE_REDUCE_REDUCER_H_ diff --git a/third_party/spirv-tools/source/reduce/reduction_opportunity.cpp b/third_party/spirv-tools/source/reduce/reduction_opportunity.cpp new file mode 100644 index 0000000000..77be7848f2 --- /dev/null +++ b/third_party/spirv-tools/source/reduce/reduction_opportunity.cpp @@ -0,0 +1,27 @@ +// Copyright (c) 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/reduce/reduction_opportunity.h" + +namespace spvtools { +namespace reduce { + +void ReductionOpportunity::TryToApply() { + if (PreconditionHolds()) { + Apply(); + } +} + +} // namespace reduce +} // namespace spvtools diff --git a/third_party/spirv-tools/source/reduce/reduction_opportunity.h b/third_party/spirv-tools/source/reduce/reduction_opportunity.h new file mode 100644 index 0000000000..703a50a465 --- /dev/null +++ b/third_party/spirv-tools/source/reduce/reduction_opportunity.h @@ -0,0 +1,47 @@ +// Copyright (c) 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_REDUCE_REDUCTION_OPPORTUNITY_H_ +#define SOURCE_REDUCE_REDUCTION_OPPORTUNITY_H_ + +#include "spirv-tools/libspirv.hpp" + +namespace spvtools { +namespace reduce { + +// Abstract class: an opportunity to apply a reducing transformation. +class ReductionOpportunity { + public: + ReductionOpportunity() = default; + virtual ~ReductionOpportunity() = default; + + // Returns true if this opportunity has not been disabled by the application + // of another conflicting opportunity. + virtual bool PreconditionHolds() = 0; + + // Applies the opportunity, mutating the module from which the opportunity was + // created. It is a no-op if PreconditionHolds() returns false. + void TryToApply(); + + protected: + // Applies the opportunity, mutating the module from which the opportunity was + // created. + // Precondition: PreconditionHolds() must return true. + virtual void Apply() = 0; +}; + +} // namespace reduce +} // namespace spvtools + +#endif // SOURCE_REDUCE_REDUCTION_OPPORTUNITY_H_ diff --git a/third_party/spirv-tools/source/reduce/reduction_opportunity_finder.h b/third_party/spirv-tools/source/reduce/reduction_opportunity_finder.h new file mode 100644 index 0000000000..1837484d70 --- /dev/null +++ b/third_party/spirv-tools/source/reduce/reduction_opportunity_finder.h @@ -0,0 +1,43 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_REDUCE_REDUCTION_OPPORTUNITY_FINDER_H_ +#define SOURCE_REDUCE_REDUCTION_OPPORTUNITY_FINDER_H_ + +#include "source/opt/ir_context.h" +#include "source/reduce/reduction_opportunity.h" + +namespace spvtools { +namespace reduce { + +// Abstract class for finding opportunities for reducing a SPIR-V module. +class ReductionOpportunityFinder { + public: + ReductionOpportunityFinder() = default; + + virtual ~ReductionOpportunityFinder() = default; + + // Finds and returns the reduction opportunities relevant to this pass that + // could be applied to the given SPIR-V module. + virtual std::vector> + GetAvailableOpportunities(opt::IRContext* context) const = 0; + + // Provides a name for the finder. + virtual std::string GetName() const = 0; +}; + +} // namespace reduce +} // namespace spvtools + +#endif // SOURCE_REDUCE_REDUCTION_OPPORTUNITY_FINDER_H_ diff --git a/third_party/spirv-tools/source/reduce/reduction_pass.cpp b/third_party/spirv-tools/source/reduce/reduction_pass.cpp new file mode 100644 index 0000000000..2cb986de91 --- /dev/null +++ b/third_party/spirv-tools/source/reduce/reduction_pass.cpp @@ -0,0 +1,86 @@ +// Copyright (c) 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/reduce/reduction_pass.h" + +#include + +#include "source/opt/build_module.h" + +namespace spvtools { +namespace reduce { + +std::vector ReductionPass::TryApplyReduction( + const std::vector& binary) { + // We represent modules as binaries because (a) attempts at reduction need to + // end up in binary form to be passed on to SPIR-V-consuming tools, and (b) + // when we apply a reduction step we need to do it on a fresh version of the + // module as if the reduction step proves to be uninteresting we need to + // backtrack; re-parsing from binary provides a very clean way of cloning the + // module. + std::unique_ptr context = + BuildModule(target_env_, consumer_, binary.data(), binary.size()); + assert(context); + + std::vector> opportunities = + finder_->GetAvailableOpportunities(context.get()); + + // There is no point in having a granularity larger than the number of + // opportunities, so reduce the granularity in this case. + if (granularity_ > opportunities.size()) { + granularity_ = std::max((uint32_t)1, (uint32_t)opportunities.size()); + } + + assert(granularity_ > 0); + + if (index_ >= opportunities.size()) { + // We have reached the end of the available opportunities and, therefore, + // the end of the round for this pass, so reset the index and decrease the + // granularity for the next round. Return an empty vector to signal the end + // of the round. + index_ = 0; + granularity_ = std::max((uint32_t)1, granularity_ / 2); + return std::vector(); + } + + for (uint32_t i = index_; + i < std::min(index_ + granularity_, (uint32_t)opportunities.size()); + ++i) { + opportunities[i]->TryToApply(); + } + + std::vector result; + context->module()->ToBinary(&result, false); + return result; +} + +void ReductionPass::SetMessageConsumer(MessageConsumer consumer) { + consumer_ = std::move(consumer); +} + +bool ReductionPass::ReachedMinimumGranularity() const { + assert(granularity_ != 0); + return granularity_ == 1; +} + +std::string ReductionPass::GetName() const { return finder_->GetName(); } + +void ReductionPass::NotifyInteresting(bool interesting) { + if (!interesting) { + index_ += granularity_; + } +} + +} // namespace reduce +} // namespace spvtools diff --git a/third_party/spirv-tools/source/reduce/reduction_pass.h b/third_party/spirv-tools/source/reduce/reduction_pass.h new file mode 100644 index 0000000000..f2d937ba68 --- /dev/null +++ b/third_party/spirv-tools/source/reduce/reduction_pass.h @@ -0,0 +1,81 @@ +// Copyright (c) 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_REDUCE_REDUCTION_PASS_H_ +#define SOURCE_REDUCE_REDUCTION_PASS_H_ + +#include + +#include "source/opt/ir_context.h" +#include "source/reduce/reduction_opportunity_finder.h" +#include "spirv-tools/libspirv.hpp" + +namespace spvtools { +namespace reduce { + +// Abstract class representing a reduction pass, which can be repeatedly +// invoked to find and apply particular reduction opportunities to a SPIR-V +// binary. In the spirit of delta debugging, a pass initially tries to apply +// large chunks of reduction opportunities, iterating through available +// opportunities at a given granularity. When an iteration over available +// opportunities completes, the granularity is reduced and iteration starts +// again, until the minimum granularity is reached. +class ReductionPass { + public: + // Constructs a reduction pass with a given target environment, |target_env|, + // and a given finder of reduction opportunities, |finder|. + explicit ReductionPass(const spv_target_env target_env, + std::unique_ptr finder) + : target_env_(target_env), + finder_(std::move(finder)), + index_(0), + granularity_(std::numeric_limits::max()) {} + + // Applies the reduction pass to the given binary by applying a "chunk" of + // reduction opportunities. Returns the new binary if a chunk was applied; in + // this case, before the next call the caller must invoke + // NotifyInteresting(...) to indicate whether the new binary is interesting. + // Returns an empty vector if there are no more chunks left to apply; in this + // case, the index will be reset and the granularity lowered for the next + // round. + std::vector TryApplyReduction(const std::vector& binary); + + // Notifies the reduction pass whether the binary returned from + // TryApplyReduction is interesting, so that the next call to + // TryApplyReduction will avoid applying the same chunk of opportunities. + void NotifyInteresting(bool interesting); + + // Sets a consumer to which relevant messages will be directed. + void SetMessageConsumer(MessageConsumer consumer); + + // Returns true if the granularity with which reduction opportunities are + // applied has reached a minimum. + bool ReachedMinimumGranularity() const; + + // Returns the name associated with this reduction pass (based on its + // associated finder). + std::string GetName() const; + + private: + const spv_target_env target_env_; + const std::unique_ptr finder_; + MessageConsumer consumer_; + uint32_t index_; + uint32_t granularity_; +}; + +} // namespace reduce +} // namespace spvtools + +#endif // SOURCE_REDUCE_REDUCTION_PASS_H_ diff --git a/third_party/spirv-tools/source/reduce/reduction_util.cpp b/third_party/spirv-tools/source/reduce/reduction_util.cpp new file mode 100644 index 0000000000..6f128dcb3a --- /dev/null +++ b/third_party/spirv-tools/source/reduce/reduction_util.cpp @@ -0,0 +1,65 @@ +// Copyright (c) 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/reduce/reduction_util.h" + +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace reduce { + +using opt::IRContext; +using opt::Instruction; + +const uint32_t kTrueBranchOperandIndex = 1; +const uint32_t kFalseBranchOperandIndex = 2; + +uint32_t FindOrCreateGlobalUndef(IRContext* context, uint32_t type_id) { + for (auto& inst : context->module()->types_values()) { + if (inst.opcode() != SpvOpUndef) { + continue; + } + if (inst.type_id() == type_id) { + return inst.result_id(); + } + } + // TODO(2182): this is adapted from MemPass::Type2Undef. In due course it + // would be good to factor out this duplication. + const uint32_t undef_id = context->TakeNextId(); + std::unique_ptr undef_inst( + new Instruction(context, SpvOpUndef, type_id, undef_id, {})); + assert(undef_id == undef_inst->result_id()); + context->module()->AddGlobalValue(std::move(undef_inst)); + return undef_id; +} + +void AdaptPhiInstructionsForRemovedEdge(uint32_t from_id, + opt::BasicBlock* to_block) { + to_block->ForEachPhiInst([&from_id](Instruction* phi_inst) { + Instruction::OperandList new_in_operands; + // Go through the OpPhi's input operands in (variable, parent) pairs. + for (uint32_t index = 0; index < phi_inst->NumInOperands(); index += 2) { + // Keep all pairs where the parent is not the block from which the edge + // is being removed. + if (phi_inst->GetInOperand(index + 1).words[0] != from_id) { + new_in_operands.push_back(phi_inst->GetInOperand(index)); + new_in_operands.push_back(phi_inst->GetInOperand(index + 1)); + } + } + phi_inst->SetInOperands(std::move(new_in_operands)); + }); +} + +} // namespace reduce +} // namespace spvtools diff --git a/third_party/spirv-tools/source/reduce/reduction_util.h b/third_party/spirv-tools/source/reduce/reduction_util.h new file mode 100644 index 0000000000..7e7e153ab1 --- /dev/null +++ b/third_party/spirv-tools/source/reduce/reduction_util.h @@ -0,0 +1,41 @@ +// Copyright (c) 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_REDUCE_REDUCTION_UTIL_H_ +#define SOURCE_REDUCE_REDUCTION_UTIL_H_ + +#include "spirv-tools/libspirv.hpp" + +#include "source/opt/ir_context.h" +#include "source/reduce/reduction_opportunity.h" + +namespace spvtools { +namespace reduce { + +extern const uint32_t kTrueBranchOperandIndex; +extern const uint32_t kFalseBranchOperandIndex; + +// Returns an OpUndef id from the global value list that is of the given type, +// adding one if it does not exist. +uint32_t FindOrCreateGlobalUndef(opt::IRContext* context, uint32_t type_id); + +// Removes any components of |to_block|'s phi instructions relating to +// |from_id|. +void AdaptPhiInstructionsForRemovedEdge(uint32_t from_id, + opt::BasicBlock* to_block); + +} // namespace reduce +} // namespace spvtools + +#endif // SOURCE_REDUCE_REDUCTION_UTIL_H_ diff --git a/third_party/spirv-tools/source/reduce/remove_block_reduction_opportunity.cpp b/third_party/spirv-tools/source/reduce/remove_block_reduction_opportunity.cpp new file mode 100644 index 0000000000..3ad7f72cf1 --- /dev/null +++ b/third_party/spirv-tools/source/reduce/remove_block_reduction_opportunity.cpp @@ -0,0 +1,57 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/reduce/remove_block_reduction_opportunity.h" + +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace reduce { + +using opt::BasicBlock; +using opt::Function; + +RemoveBlockReductionOpportunity::RemoveBlockReductionOpportunity( + Function* function, BasicBlock* block) + : function_(function), block_(block) { + // precondition: + assert(block_->begin() != block_->end() && + block_->begin()->context()->get_def_use_mgr()->NumUsers( + block_->id()) == 0 && + "RemoveBlockReductionOpportunity block must have 0 references"); +} + +bool RemoveBlockReductionOpportunity::PreconditionHolds() { + // Removing other blocks cannot disable this opportunity. + return true; +} + +void RemoveBlockReductionOpportunity::Apply() { + // We need an iterator pointing to the block, hence the loop. + for (auto bi = function_->begin(); bi != function_->end(); ++bi) { + if (bi->id() == block_->id()) { + bi->KillAllInsts(true); + bi.Erase(); + // Block removal changes the function, but we don't use analyses, so no + // need to invalidate them. + return; + } + } + + assert(false && + "Unreachable: we should have found a block with the desired id."); +} + +} // namespace reduce +} // namespace spvtools diff --git a/third_party/spirv-tools/source/reduce/remove_block_reduction_opportunity.h b/third_party/spirv-tools/source/reduce/remove_block_reduction_opportunity.h new file mode 100644 index 0000000000..4b358abc63 --- /dev/null +++ b/third_party/spirv-tools/source/reduce/remove_block_reduction_opportunity.h @@ -0,0 +1,46 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_REDUCE_REMOVE_BLOCK_REDUCTION_OPPORTUNITY_H_ +#define SOURCE_REDUCE_REMOVE_BLOCK_REDUCTION_OPPORTUNITY_H_ + +#include "source/opt/basic_block.h" +#include "source/opt/function.h" +#include "source/reduce/reduction_opportunity.h" + +namespace spvtools { +namespace reduce { + +// An opportunity to remove an unreferenced block. +// See RemoveBlockReductionOpportunityFinder. +class RemoveBlockReductionOpportunity : public ReductionOpportunity { + public: + // Creates the opportunity to remove |block| in |function| in |context|. + RemoveBlockReductionOpportunity(opt::Function* function, + opt::BasicBlock* block); + + bool PreconditionHolds() override; + + protected: + void Apply() override; + + private: + opt::Function* function_; + opt::BasicBlock* block_; +}; + +} // namespace reduce +} // namespace spvtools + +#endif // SOURCE_REDUCE_REMOVE_BLOCK_REDUCTION_OPPORTUNITY_H_ diff --git a/third_party/spirv-tools/source/reduce/remove_block_reduction_opportunity_finder.cpp b/third_party/spirv-tools/source/reduce/remove_block_reduction_opportunity_finder.cpp new file mode 100644 index 0000000000..a3f873f31b --- /dev/null +++ b/third_party/spirv-tools/source/reduce/remove_block_reduction_opportunity_finder.cpp @@ -0,0 +1,98 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/reduce/remove_block_reduction_opportunity_finder.h" + +#include "source/reduce/remove_block_reduction_opportunity.h" + +namespace spvtools { +namespace reduce { + +using opt::Function; +using opt::IRContext; +using opt::Instruction; + +std::string RemoveBlockReductionOpportunityFinder::GetName() const { + return "RemoveBlockReductionOpportunityFinder"; +} + +std::vector> +RemoveBlockReductionOpportunityFinder::GetAvailableOpportunities( + IRContext* context) const { + std::vector> result; + + // Consider every block in every function. + for (auto& function : *context->module()) { + for (auto bi = function.begin(); bi != function.end(); ++bi) { + if (IsBlockValidOpportunity(context, function, bi)) { + result.push_back(spvtools::MakeUnique( + &function, &*bi)); + } + } + } + return result; +} + +bool RemoveBlockReductionOpportunityFinder::IsBlockValidOpportunity( + IRContext* context, Function& function, Function::iterator& bi) { + assert(bi != function.end() && "Block iterator was out of bounds"); + + // Don't remove first block; we don't want to end up with no blocks. + if (bi == function.begin()) { + return false; + } + + // Don't remove blocks with references. + if (context->get_def_use_mgr()->NumUsers(bi->id()) > 0) { + return false; + } + + // Don't remove blocks whose instructions have outside references. + if (!BlockInstructionsHaveNoOutsideReferences(context, bi)) { + return false; + } + + return true; +} + +bool RemoveBlockReductionOpportunityFinder:: + BlockInstructionsHaveNoOutsideReferences(IRContext* context, + const Function::iterator& bi) { + // Get all instructions in block. + std::unordered_set instructions_in_block; + for (const Instruction& instruction : *bi) { + instructions_in_block.insert(instruction.unique_id()); + } + + // For each instruction... + for (const Instruction& instruction : *bi) { + // For each use of the instruction... + bool no_uses_outside_block = context->get_def_use_mgr()->WhileEachUser( + &instruction, [&instructions_in_block](Instruction* user) -> bool { + // If the use is in this block, continue (return true). Otherwise, we + // found an outside use; return false (and stop). + return instructions_in_block.find(user->unique_id()) != + instructions_in_block.end(); + }); + + if (!no_uses_outside_block) { + return false; + } + } + + return true; +} + +} // namespace reduce +} // namespace spvtools diff --git a/third_party/spirv-tools/source/reduce/remove_block_reduction_opportunity_finder.h b/third_party/spirv-tools/source/reduce/remove_block_reduction_opportunity_finder.h new file mode 100644 index 0000000000..83cd04b573 --- /dev/null +++ b/third_party/spirv-tools/source/reduce/remove_block_reduction_opportunity_finder.h @@ -0,0 +1,55 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_REDUCE_REMOVE_BLOCK_REDUCTION_OPPORTUNITY_FINDER_H_ +#define SOURCE_REDUCE_REMOVE_BLOCK_REDUCTION_OPPORTUNITY_FINDER_H_ + +#include "source/opt/function.h" +#include "source/reduce/reduction_opportunity_finder.h" + +namespace spvtools { +namespace reduce { + +// A finder of opportunities to remove a block. The optimizer can remove dead +// code. However, the reducer needs to be able to remove at a fine-grained +// level. +class RemoveBlockReductionOpportunityFinder + : public ReductionOpportunityFinder { + public: + RemoveBlockReductionOpportunityFinder() = default; + + ~RemoveBlockReductionOpportunityFinder() override = default; + + std::string GetName() const final; + + std::vector> GetAvailableOpportunities( + opt::IRContext* context) const final; + + private: + // Returns true if the block |bi| in function |function| is a valid + // opportunity according to various restrictions. + static bool IsBlockValidOpportunity(opt::IRContext* context, + opt::Function& function, + opt::Function::iterator& bi); + + // Returns true if the instructions (definitions) in block |bi| have no + // references, except for references from inside the block itself. + static bool BlockInstructionsHaveNoOutsideReferences( + opt::IRContext* context, const opt::Function::iterator& bi); +}; + +} // namespace reduce +} // namespace spvtools + +#endif // SOURCE_REDUCE_REMOVE_BLOCK_REDUCTION_OPPORTUNITY_FINDER_H_ diff --git a/third_party/spirv-tools/source/reduce/remove_function_reduction_opportunity.cpp b/third_party/spirv-tools/source/reduce/remove_function_reduction_opportunity.cpp new file mode 100644 index 0000000000..ecad670779 --- /dev/null +++ b/third_party/spirv-tools/source/reduce/remove_function_reduction_opportunity.cpp @@ -0,0 +1,41 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/reduce/remove_function_reduction_opportunity.h" + +#include "source/opt/eliminate_dead_functions_util.h" + +namespace spvtools { +namespace reduce { + +bool RemoveFunctionReductionOpportunity::PreconditionHolds() { + // Removing one function cannot influence whether another function can be + // removed. + return true; +} + +void RemoveFunctionReductionOpportunity::Apply() { + for (opt::Module::iterator function_it = context_->module()->begin(); + function_it != context_->module()->end(); ++function_it) { + if (&*function_it == function_) { + opt::eliminatedeadfunctionsutil::EliminateFunction(context_, + &function_it); + return; + } + } + assert(0 && "Function to be removed was not found."); +} + +} // namespace reduce +} // namespace spvtools diff --git a/third_party/spirv-tools/source/reduce/remove_function_reduction_opportunity.h b/third_party/spirv-tools/source/reduce/remove_function_reduction_opportunity.h new file mode 100644 index 0000000000..d8c57db120 --- /dev/null +++ b/third_party/spirv-tools/source/reduce/remove_function_reduction_opportunity.h @@ -0,0 +1,49 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_REDUCE_REMOVE_FUNCTION_REDUCTION_OPPORTUNITY_H_ +#define SOURCE_REDUCE_REMOVE_FUNCTION_REDUCTION_OPPORTUNITY_H_ + +#include "source/opt/function.h" +#include "source/reduce/reduction_opportunity.h" + +namespace spvtools { +namespace reduce { + +// An opportunity to remove an unreferenced function. +class RemoveFunctionReductionOpportunity : public ReductionOpportunity { + public: + // Creates an opportunity to remove |function| from the module represented by + // |context|. + RemoveFunctionReductionOpportunity(opt::IRContext* context, + opt::Function* function) + : context_(context), function_(function) {} + + bool PreconditionHolds() override; + + protected: + void Apply() override; + + private: + // The IR context for the module under analysis. + opt::IRContext* context_; + + // The function that can be removed. + opt::Function* function_; +}; + +} // namespace reduce +} // namespace spvtools + +#endif // SOURCE_REDUCE_REMOVE_FUNCTION_REDUCTION_OPPORTUNITY_H_ diff --git a/third_party/spirv-tools/source/reduce/remove_function_reduction_opportunity_finder.cpp b/third_party/spirv-tools/source/reduce/remove_function_reduction_opportunity_finder.cpp new file mode 100644 index 0000000000..1edb973308 --- /dev/null +++ b/third_party/spirv-tools/source/reduce/remove_function_reduction_opportunity_finder.cpp @@ -0,0 +1,43 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/reduce/remove_function_reduction_opportunity_finder.h" + +#include "source/reduce/remove_function_reduction_opportunity.h" + +namespace spvtools { +namespace reduce { + +std::vector> +RemoveFunctionReductionOpportunityFinder::GetAvailableOpportunities( + opt::IRContext* context) const { + std::vector> result; + // Consider each function. + for (auto& function : *context->module()) { + if (context->get_def_use_mgr()->NumUses(function.result_id()) > 0) { + // If the function is referenced, ignore it. + continue; + } + result.push_back( + MakeUnique(context, &function)); + } + return result; +} + +std::string RemoveFunctionReductionOpportunityFinder::GetName() const { + return "RemoveFunctionReductionOpportunityFinder"; +} + +} // namespace reduce +} // namespace spvtools diff --git a/third_party/spirv-tools/source/reduce/remove_function_reduction_opportunity_finder.h b/third_party/spirv-tools/source/reduce/remove_function_reduction_opportunity_finder.h new file mode 100644 index 0000000000..7952a22966 --- /dev/null +++ b/third_party/spirv-tools/source/reduce/remove_function_reduction_opportunity_finder.h @@ -0,0 +1,42 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_REDUCE_REMOVE_FUNCTION_REDUCTION_OPPORTUNITY_FINDER_H_ +#define SOURCE_REDUCE_REMOVE_FUNCTION_REDUCTION_OPPORTUNITY_FINDER_H_ + +#include "source/reduce/reduction_opportunity_finder.h" + +namespace spvtools { +namespace reduce { + +// A finder of opportunities to remove unreferenced functions. +class RemoveFunctionReductionOpportunityFinder + : public ReductionOpportunityFinder { + public: + RemoveFunctionReductionOpportunityFinder() = default; + + ~RemoveFunctionReductionOpportunityFinder() override = default; + + std::string GetName() const final; + + std::vector> GetAvailableOpportunities( + opt::IRContext* context) const final; + + private: +}; + +} // namespace reduce +} // namespace spvtools + +#endif // SOURCE_REDUCE_REMOVE_FUNCTION_REDUCTION_OPPORTUNITY_FINDER_H_ diff --git a/third_party/spirv-tools/tools/comp/markv_model_factory.h b/third_party/spirv-tools/source/reduce/remove_instruction_reduction_opportunity.cpp similarity index 57% rename from third_party/spirv-tools/tools/comp/markv_model_factory.h rename to third_party/spirv-tools/source/reduce/remove_instruction_reduction_opportunity.cpp index c13898b986..9ca093bf3e 100644 --- a/third_party/spirv-tools/tools/comp/markv_model_factory.h +++ b/third_party/spirv-tools/source/reduce/remove_instruction_reduction_opportunity.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017 Google Inc. +// Copyright (c) 2018 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,26 +12,18 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef TOOLS_COMP_MARKV_MODEL_FACTORY_H_ -#define TOOLS_COMP_MARKV_MODEL_FACTORY_H_ +#include "source/reduce/remove_instruction_reduction_opportunity.h" -#include - -#include "source/comp/markv_model.h" +#include "source/opt/ir_context.h" namespace spvtools { -namespace comp { +namespace reduce { -enum MarkvModelType { - kMarkvModelUnknown = 0, - kMarkvModelShaderLite, - kMarkvModelShaderMid, - kMarkvModelShaderMax, -}; +bool RemoveInstructionReductionOpportunity::PreconditionHolds() { return true; } -std::unique_ptr CreateMarkvModel(MarkvModelType type); +void RemoveInstructionReductionOpportunity::Apply() { + inst_->context()->KillInst(inst_); +} -} // namespace comp +} // namespace reduce } // namespace spvtools - -#endif // TOOLS_COMP_MARKV_MODEL_FACTORY_H_ diff --git a/third_party/spirv-tools/source/reduce/remove_instruction_reduction_opportunity.h b/third_party/spirv-tools/source/reduce/remove_instruction_reduction_opportunity.h new file mode 100644 index 0000000000..07bef50ab1 --- /dev/null +++ b/third_party/spirv-tools/source/reduce/remove_instruction_reduction_opportunity.h @@ -0,0 +1,44 @@ +// Copyright (c) 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_REDUCE_REMOVE_INSTRUCTION_REDUCTION_OPPORTUNITY_H_ +#define SOURCE_REDUCE_REMOVE_INSTRUCTION_REDUCTION_OPPORTUNITY_H_ + +#include "source/opt/instruction.h" +#include "source/reduce/reduction_opportunity.h" + +namespace spvtools { +namespace reduce { + +// An opportunity to remove an instruction from the SPIR-V module. +class RemoveInstructionReductionOpportunity : public ReductionOpportunity { + public: + // Constructs the opportunity to remove |inst|. + explicit RemoveInstructionReductionOpportunity(opt::Instruction* inst) + : inst_(inst) {} + + // Always returns true, as this opportunity can always be applied. + bool PreconditionHolds() override; + + protected: + void Apply() override; + + private: + opt::Instruction* inst_; +}; + +} // namespace reduce +} // namespace spvtools + +#endif // SOURCE_REDUCE_REMOVE_INSTRUCTION_REDUCTION_OPPORTUNITY_H_ diff --git a/third_party/spirv-tools/source/reduce/remove_selection_reduction_opportunity.cpp b/third_party/spirv-tools/source/reduce/remove_selection_reduction_opportunity.cpp new file mode 100644 index 0000000000..96f01475ef --- /dev/null +++ b/third_party/spirv-tools/source/reduce/remove_selection_reduction_opportunity.cpp @@ -0,0 +1,31 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/reduce/remove_selection_reduction_opportunity.h" + +#include "source/opt/basic_block.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace reduce { + +bool RemoveSelectionReductionOpportunity::PreconditionHolds() { return true; } + +void RemoveSelectionReductionOpportunity::Apply() { + auto merge_instruction = header_block_->GetMergeInst(); + merge_instruction->context()->KillInst(merge_instruction); +} + +} // namespace reduce +} // namespace spvtools diff --git a/third_party/spirv-tools/source/reduce/remove_selection_reduction_opportunity.h b/third_party/spirv-tools/source/reduce/remove_selection_reduction_opportunity.h new file mode 100644 index 0000000000..892618e56f --- /dev/null +++ b/third_party/spirv-tools/source/reduce/remove_selection_reduction_opportunity.h @@ -0,0 +1,47 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_REDUCE_REMOVE_SELECTION_REDUCTION_OPPORTUNITY_H_ +#define SOURCE_REDUCE_REMOVE_SELECTION_REDUCTION_OPPORTUNITY_H_ + +#include "source/opt/basic_block.h" +#include "source/reduce/reduction_opportunity.h" + +namespace spvtools { +namespace reduce { + +// An opportunity for removing a selection construct by simply removing the +// OpSelectionMerge instruction; thus, the selection must have already been +// simplified to a point where the instruction can be trivially removed. +class RemoveSelectionReductionOpportunity : public ReductionOpportunity { + public: + // Constructs a reduction opportunity from the selection header |block| in + // |function|. + RemoveSelectionReductionOpportunity(opt::BasicBlock* header_block) + : header_block_(header_block) {} + + bool PreconditionHolds() override; + + protected: + void Apply() override; + + private: + // The header block of the selection. + opt::BasicBlock* header_block_; +}; + +} // namespace reduce +} // namespace spvtools + +#endif // SOURCE_REDUCE_REMOVE_SELECTION_REDUCTION_OPPORTUNITY_H_ diff --git a/third_party/spirv-tools/source/reduce/remove_selection_reduction_opportunity_finder.cpp b/third_party/spirv-tools/source/reduce/remove_selection_reduction_opportunity_finder.cpp new file mode 100644 index 0000000000..45821e2af0 --- /dev/null +++ b/third_party/spirv-tools/source/reduce/remove_selection_reduction_opportunity_finder.cpp @@ -0,0 +1,150 @@ +// Copyright (c) 2019 Google LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/reduce/remove_selection_reduction_opportunity_finder.h" + +#include "source/reduce/remove_selection_reduction_opportunity.h" + +namespace spvtools { +namespace reduce { + +using opt::BasicBlock; +using opt::IRContext; +using opt::Instruction; + +namespace { +const uint32_t kMergeNodeIndex = 0; +const uint32_t kContinueNodeIndex = 1; +} // namespace + +std::string RemoveSelectionReductionOpportunityFinder::GetName() const { + return "RemoveSelectionReductionOpportunityFinder"; +} + +std::vector> +RemoveSelectionReductionOpportunityFinder::GetAvailableOpportunities( + IRContext* context) const { + // Get all loop merge and continue blocks so we can check for these later. + std::unordered_set merge_and_continue_blocks_from_loops; + for (auto& function : *context->module()) { + for (auto& block : function) { + if (auto merge_instruction = block.GetMergeInst()) { + if (merge_instruction->opcode() == SpvOpLoopMerge) { + uint32_t merge_block_id = + merge_instruction->GetSingleWordOperand(kMergeNodeIndex); + uint32_t continue_block_id = + merge_instruction->GetSingleWordOperand(kContinueNodeIndex); + merge_and_continue_blocks_from_loops.insert(merge_block_id); + merge_and_continue_blocks_from_loops.insert(continue_block_id); + } + } + } + } + + // Return all selection headers where the OpSelectionMergeInstruction can be + // removed. + std::vector> result; + for (auto& function : *context->module()) { + for (auto& block : function) { + if (auto merge_instruction = block.GetMergeInst()) { + if (merge_instruction->opcode() == SpvOpSelectionMerge) { + if (CanOpSelectionMergeBeRemoved( + context, block, merge_instruction, + merge_and_continue_blocks_from_loops)) { + result.push_back( + MakeUnique(&block)); + } + } + } + } + } + return result; +} + +bool RemoveSelectionReductionOpportunityFinder::CanOpSelectionMergeBeRemoved( + IRContext* context, const BasicBlock& header_block, + Instruction* merge_instruction, + std::unordered_set merge_and_continue_blocks_from_loops) { + assert(header_block.GetMergeInst() == merge_instruction && + "CanOpSelectionMergeBeRemoved(...): header block and merge " + "instruction mismatch"); + + // The OpSelectionMerge instruction is needed if either of the following are + // true. + // + // 1. The header block has at least two (unique) successors that are not + // merge or continue blocks of a loop. + // + // 2. The predecessors of the merge block are "using" the merge block to avoid + // divergence. In other words, there exists a predecessor of the merge block + // that has a successor that is not the merge block of this construct and not + // a merge or continue block of a loop. + + // 1. + { + uint32_t divergent_successor_count = 0; + + std::unordered_set seen_successors; + + header_block.ForEachSuccessorLabel( + [&seen_successors, &merge_and_continue_blocks_from_loops, + &divergent_successor_count](uint32_t successor) { + // Not already seen. + if (seen_successors.find(successor) == seen_successors.end()) { + seen_successors.insert(successor); + // Not a loop continue or merge. + if (merge_and_continue_blocks_from_loops.find(successor) == + merge_and_continue_blocks_from_loops.end()) { + ++divergent_successor_count; + } + } + }); + + if (divergent_successor_count > 1) { + return false; + } + } + + // 2. + { + uint32_t merge_block_id = + merge_instruction->GetSingleWordOperand(kMergeNodeIndex); + for (uint32_t predecessor_block_id : + context->cfg()->preds(merge_block_id)) { + const BasicBlock* predecessor_block = + context->cfg()->block(predecessor_block_id); + assert(predecessor_block); + bool found_divergent_successor = false; + predecessor_block->ForEachSuccessorLabel( + [&found_divergent_successor, merge_block_id, + &merge_and_continue_blocks_from_loops](uint32_t successor_id) { + // The successor is not the merge block, nor a loop merge or + // continue. + if (successor_id != merge_block_id && + merge_and_continue_blocks_from_loops.find(successor_id) == + merge_and_continue_blocks_from_loops.end()) { + found_divergent_successor = true; + } + }); + if (found_divergent_successor) { + return false; + } + } + } + + return true; +} + +} // namespace reduce +} // namespace spvtools diff --git a/third_party/spirv-tools/source/reduce/remove_selection_reduction_opportunity_finder.h b/third_party/spirv-tools/source/reduce/remove_selection_reduction_opportunity_finder.h new file mode 100644 index 0000000000..848122b8af --- /dev/null +++ b/third_party/spirv-tools/source/reduce/remove_selection_reduction_opportunity_finder.h @@ -0,0 +1,49 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_REDUCE_REMOVE_SELECTION_REDUCTION_OPPORTUNITY_FINDER_H_ +#define SOURCE_REDUCE_REMOVE_SELECTION_REDUCTION_OPPORTUNITY_FINDER_H_ + +#include "source/reduce/reduction_opportunity_finder.h" + +namespace spvtools { +namespace reduce { + +// A finder for opportunities for removing a selection construct by simply +// removing the OpSelectionMerge instruction; thus, the selections must have +// already been simplified to a point where they can be trivially removed. +class RemoveSelectionReductionOpportunityFinder + : public ReductionOpportunityFinder { + public: + RemoveSelectionReductionOpportunityFinder() = default; + + ~RemoveSelectionReductionOpportunityFinder() override = default; + + std::string GetName() const final; + + std::vector> GetAvailableOpportunities( + opt::IRContext* context) const final; + + // Returns true if the OpSelectionMerge instruction |merge_instruction| in + // block |header_block| can be removed. + static bool CanOpSelectionMergeBeRemoved( + opt::IRContext* context, const opt::BasicBlock& header_block, + opt::Instruction* merge_instruction, + std::unordered_set merge_and_continue_blocks_from_loops); +}; + +} // namespace reduce +} // namespace spvtools + +#endif // SOURCE_REDUCE_REMOVE_SELECTION_REDUCTION_OPPORTUNITY_FINDER_H_ diff --git a/third_party/spirv-tools/source/reduce/remove_unreferenced_instruction_reduction_opportunity_finder.cpp b/third_party/spirv-tools/source/reduce/remove_unreferenced_instruction_reduction_opportunity_finder.cpp new file mode 100644 index 0000000000..ce66691155 --- /dev/null +++ b/third_party/spirv-tools/source/reduce/remove_unreferenced_instruction_reduction_opportunity_finder.cpp @@ -0,0 +1,148 @@ +// Copyright (c) 2018 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/reduce/remove_unreferenced_instruction_reduction_opportunity_finder.h" + +#include "source/opcode.h" +#include "source/opt/instruction.h" +#include "source/reduce/remove_instruction_reduction_opportunity.h" + +namespace spvtools { +namespace reduce { + +RemoveUnreferencedInstructionReductionOpportunityFinder:: + RemoveUnreferencedInstructionReductionOpportunityFinder( + bool remove_constants_and_undefs) + : remove_constants_and_undefs_(remove_constants_and_undefs) {} + +std::vector> +RemoveUnreferencedInstructionReductionOpportunityFinder:: + GetAvailableOpportunities(opt::IRContext* context) const { + std::vector> result; + + for (auto& inst : context->module()->debugs1()) { + if (context->get_def_use_mgr()->NumUses(&inst) > 0) { + continue; + } + result.push_back(MakeUnique(&inst)); + } + + for (auto& inst : context->module()->debugs2()) { + if (context->get_def_use_mgr()->NumUses(&inst) > 0) { + continue; + } + result.push_back(MakeUnique(&inst)); + } + + for (auto& inst : context->module()->debugs3()) { + if (context->get_def_use_mgr()->NumUses(&inst) > 0) { + continue; + } + result.push_back(MakeUnique(&inst)); + } + + for (auto& inst : context->module()->ext_inst_debuginfo()) { + if (context->get_def_use_mgr()->NumUses(&inst) > 0) { + continue; + } + result.push_back(MakeUnique(&inst)); + } + + for (auto& inst : context->module()->types_values()) { + if (context->get_def_use_mgr()->NumUsers(&inst) > 0) { + continue; + } + if (!remove_constants_and_undefs_ && + spvOpcodeIsConstantOrUndef(inst.opcode())) { + continue; + } + result.push_back(MakeUnique(&inst)); + } + + for (auto& inst : context->module()->annotations()) { + if (context->get_def_use_mgr()->NumUsers(&inst) > 0) { + continue; + } + + uint32_t decoration = SpvDecorationMax; + switch (inst.opcode()) { + case SpvOpDecorate: + case SpvOpDecorateId: + case SpvOpDecorateString: + decoration = inst.GetSingleWordInOperand(1u); + break; + case SpvOpMemberDecorate: + case SpvOpMemberDecorateString: + decoration = inst.GetSingleWordInOperand(2u); + break; + default: + break; + } + + // We conservatively only remove specific decorations that we believe will + // not change the shader interface, will not make the shader invalid, will + // actually be found in practice, etc. + + switch (decoration) { + case SpvDecorationRelaxedPrecision: + case SpvDecorationNoSignedWrap: + case SpvDecorationNoContraction: + case SpvDecorationNoUnsignedWrap: + case SpvDecorationUserSemantic: + break; + default: + // Give up. + continue; + } + + result.push_back(MakeUnique(&inst)); + } + + for (auto& function : *context->module()) { + for (auto& block : function) { + for (auto& inst : block) { + if (context->get_def_use_mgr()->NumUses(&inst) > 0) { + continue; + } + if (!remove_constants_and_undefs_ && + spvOpcodeIsConstantOrUndef(inst.opcode())) { + continue; + } + if (spvOpcodeIsBlockTerminator(inst.opcode()) || + inst.opcode() == SpvOpSelectionMerge || + inst.opcode() == SpvOpLoopMerge) { + // In this reduction pass we do not want to affect static + // control flow. + continue; + } + // Given that we're in a block, we should only get here if + // the instruction is not directly related to control flow; + // i.e., it's some straightforward instruction with an + // unused result, like an arithmetic operation or function + // call. + result.push_back( + MakeUnique(&inst)); + } + } + } + return result; +} + +std::string RemoveUnreferencedInstructionReductionOpportunityFinder::GetName() + const { + return "RemoveUnreferencedInstructionReductionOpportunityFinder"; +} + +} // namespace reduce +} // namespace spvtools diff --git a/third_party/spirv-tools/source/reduce/remove_unreferenced_instruction_reduction_opportunity_finder.h b/third_party/spirv-tools/source/reduce/remove_unreferenced_instruction_reduction_opportunity_finder.h new file mode 100644 index 0000000000..bc4f137f13 --- /dev/null +++ b/third_party/spirv-tools/source/reduce/remove_unreferenced_instruction_reduction_opportunity_finder.h @@ -0,0 +1,48 @@ +// Copyright (c) 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_REDUCE_REMOVE_UNREFERENCED_INSTRUCTION_REDUCTION_OPPORTUNITY_FINDER_H_ +#define SOURCE_REDUCE_REMOVE_UNREFERENCED_INSTRUCTION_REDUCTION_OPPORTUNITY_FINDER_H_ + +#include "source/reduce/reduction_opportunity_finder.h" + +namespace spvtools { +namespace reduce { + +// A finder for opportunities to remove non-control-flow instructions in blocks +// in cases where the instruction's id is not referenced. As well as making the +// module smaller, removing an instruction that references particular ids may +// create opportunities for subsequently removing the instructions that +// generated those ids. +class RemoveUnreferencedInstructionReductionOpportunityFinder + : public ReductionOpportunityFinder { + public: + explicit RemoveUnreferencedInstructionReductionOpportunityFinder( + bool remove_constants_and_undefs); + + ~RemoveUnreferencedInstructionReductionOpportunityFinder() override = default; + + std::string GetName() const final; + + std::vector> GetAvailableOpportunities( + opt::IRContext* context) const final; + + private: + bool remove_constants_and_undefs_; +}; + +} // namespace reduce +} // namespace spvtools + +#endif // SOURCE_REDUCE_REMOVE_UNREFERENCED_INSTRUCTION_REDUCTION_OPPORTUNITY_FINDER_H_ diff --git a/third_party/spirv-tools/source/reduce/simple_conditional_branch_to_branch_opportunity_finder.cpp b/third_party/spirv-tools/source/reduce/simple_conditional_branch_to_branch_opportunity_finder.cpp new file mode 100644 index 0000000000..17a5c7e49c --- /dev/null +++ b/third_party/spirv-tools/source/reduce/simple_conditional_branch_to_branch_opportunity_finder.cpp @@ -0,0 +1,65 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/reduce/simple_conditional_branch_to_branch_opportunity_finder.h" + +#include "source/reduce/reduction_util.h" +#include "source/reduce/simple_conditional_branch_to_branch_reduction_opportunity.h" + +namespace spvtools { +namespace reduce { + +using opt::IRContext; +using opt::Instruction; + +std::vector> +SimpleConditionalBranchToBranchOpportunityFinder::GetAvailableOpportunities( + IRContext* context) const { + std::vector> result; + + // Consider every function. + for (auto& function : *context->module()) { + // Consider every block in the function. + for (auto& block : function) { + // The terminator must be SpvOpBranchConditional. + Instruction* terminator = block.terminator(); + if (terminator->opcode() != SpvOpBranchConditional) { + continue; + } + // It must not be a selection header, as these cannot be followed by + // OpBranch. + if (block.GetMergeInst() && + block.GetMergeInst()->opcode() == SpvOpSelectionMerge) { + continue; + } + // The conditional branch must be simplified. + if (terminator->GetSingleWordInOperand(kTrueBranchOperandIndex) != + terminator->GetSingleWordInOperand(kFalseBranchOperandIndex)) { + continue; + } + + result.push_back( + MakeUnique( + block.terminator())); + } + } + return result; +} + +std::string SimpleConditionalBranchToBranchOpportunityFinder::GetName() const { + return "SimpleConditionalBranchToBranchOpportunityFinder"; +} + +} // namespace reduce +} // namespace spvtools diff --git a/third_party/spirv-tools/source/reduce/simple_conditional_branch_to_branch_opportunity_finder.h b/third_party/spirv-tools/source/reduce/simple_conditional_branch_to_branch_opportunity_finder.h new file mode 100644 index 0000000000..10b9dce4af --- /dev/null +++ b/third_party/spirv-tools/source/reduce/simple_conditional_branch_to_branch_opportunity_finder.h @@ -0,0 +1,37 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_REDUCE_SIMPLE_CONDITIONAL_BRANCH_TO_BRANCH_OPPORTUNITY_FINDER_H_ +#define SOURCE_REDUCE_SIMPLE_CONDITIONAL_BRANCH_TO_BRANCH_OPPORTUNITY_FINDER_H_ + +#include "source/reduce/reduction_opportunity_finder.h" + +namespace spvtools { +namespace reduce { + +// A finder for opportunities to change simple conditional branches (conditional +// branches with one target) to an OpBranch. +class SimpleConditionalBranchToBranchOpportunityFinder + : public ReductionOpportunityFinder { + public: + std::vector> GetAvailableOpportunities( + opt::IRContext* context) const override; + + std::string GetName() const override; +}; + +} // namespace reduce +} // namespace spvtools + +#endif // SOURCE_REDUCE_SIMPLE_CONDITIONAL_BRANCH_TO_BRANCH_OPPORTUNITY_FINDER_H_ diff --git a/third_party/spirv-tools/source/reduce/simple_conditional_branch_to_branch_reduction_opportunity.cpp b/third_party/spirv-tools/source/reduce/simple_conditional_branch_to_branch_reduction_opportunity.cpp new file mode 100644 index 0000000000..8968b9627d --- /dev/null +++ b/third_party/spirv-tools/source/reduce/simple_conditional_branch_to_branch_reduction_opportunity.cpp @@ -0,0 +1,59 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/reduce/simple_conditional_branch_to_branch_reduction_opportunity.h" + +#include "source/reduce/reduction_util.h" + +namespace spvtools { +namespace reduce { + +using namespace opt; + +SimpleConditionalBranchToBranchReductionOpportunity:: + SimpleConditionalBranchToBranchReductionOpportunity( + Instruction* conditional_branch_instruction) + : conditional_branch_instruction_(conditional_branch_instruction) {} + +bool SimpleConditionalBranchToBranchReductionOpportunity::PreconditionHolds() { + // We find at most one opportunity per conditional branch and simplifying + // another branch cannot disable this opportunity. + return true; +} + +void SimpleConditionalBranchToBranchReductionOpportunity::Apply() { + assert(conditional_branch_instruction_->opcode() == SpvOpBranchConditional && + "SimpleConditionalBranchToBranchReductionOpportunity: branch was not " + "a conditional branch"); + + assert(conditional_branch_instruction_->GetSingleWordInOperand( + kTrueBranchOperandIndex) == + conditional_branch_instruction_->GetSingleWordInOperand( + kFalseBranchOperandIndex) && + "SimpleConditionalBranchToBranchReductionOpportunity: branch was not " + "simple"); + + // OpBranchConditional %condition %block_id %block_id ... + // -> + // OpBranch %block_id + + conditional_branch_instruction_->SetOpcode(SpvOpBranch); + conditional_branch_instruction_->ReplaceOperands( + {{SPV_OPERAND_TYPE_ID, + {conditional_branch_instruction_->GetSingleWordInOperand( + kTrueBranchOperandIndex)}}}); +} + +} // namespace reduce +} // namespace spvtools diff --git a/third_party/spirv-tools/source/reduce/simple_conditional_branch_to_branch_reduction_opportunity.h b/third_party/spirv-tools/source/reduce/simple_conditional_branch_to_branch_reduction_opportunity.h new file mode 100644 index 0000000000..eddb4647e2 --- /dev/null +++ b/third_party/spirv-tools/source/reduce/simple_conditional_branch_to_branch_reduction_opportunity.h @@ -0,0 +1,45 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_REDUCE_SIMPLE_CONDITIONAL_BRANCH_TO_BRANCH_REDUCTION_OPPORTUNITY_H_ +#define SOURCE_REDUCE_SIMPLE_CONDITIONAL_BRANCH_TO_BRANCH_REDUCTION_OPPORTUNITY_H_ + +#include "source/opt/instruction.h" +#include "source/reduce/reduction_opportunity.h" + +namespace spvtools { +namespace reduce { + +// An opportunity to change simple conditional branches (conditional branches +// with one target) to an OpBranch. +class SimpleConditionalBranchToBranchReductionOpportunity + : public ReductionOpportunity { + public: + // Constructs an opportunity to simplify |conditional_branch_instruction|. + explicit SimpleConditionalBranchToBranchReductionOpportunity( + opt::Instruction* conditional_branch_instruction); + + bool PreconditionHolds() override; + + protected: + void Apply() override; + + private: + opt::Instruction* conditional_branch_instruction_; +}; + +} // namespace reduce +} // namespace spvtools + +#endif // SOURCE_REDUCE_SIMPLE_CONDITIONAL_BRANCH_TO_BRANCH_REDUCTION_OPPORTUNITY_H_ diff --git a/third_party/spirv-tools/source/reduce/structured_loop_to_selection_reduction_opportunity.cpp b/third_party/spirv-tools/source/reduce/structured_loop_to_selection_reduction_opportunity.cpp new file mode 100644 index 0000000000..88ea38e7fa --- /dev/null +++ b/third_party/spirv-tools/source/reduce/structured_loop_to_selection_reduction_opportunity.cpp @@ -0,0 +1,343 @@ +// Copyright (c) 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/reduce/structured_loop_to_selection_reduction_opportunity.h" + +#include "source/opt/aggressive_dead_code_elim_pass.h" +#include "source/opt/ir_context.h" +#include "source/reduce/reduction_util.h" + +namespace spvtools { +namespace reduce { + +using opt::BasicBlock; +using opt::IRContext; +using opt::Instruction; +using opt::Operand; + +namespace { +const uint32_t kMergeNodeIndex = 0; +} // namespace + +bool StructuredLoopToSelectionReductionOpportunity::PreconditionHolds() { + // Is the loop header reachable? + return loop_construct_header_->GetLabel() + ->context() + ->GetDominatorAnalysis(enclosing_function_) + ->IsReachable(loop_construct_header_); +} + +void StructuredLoopToSelectionReductionOpportunity::Apply() { + // Force computation of dominator analysis, CFG and structured CFG analysis + // before we start to mess with edges in the function. + context_->GetDominatorAnalysis(enclosing_function_); + context_->cfg(); + context_->GetStructuredCFGAnalysis(); + + // (1) Redirect edges that point to the loop's continue target to their + // closest merge block. + RedirectToClosestMergeBlock(loop_construct_header_->ContinueBlockId()); + + // (2) Redirect edges that point to the loop's merge block to their closest + // merge block (which might be that of an enclosing selection, for instance). + RedirectToClosestMergeBlock(loop_construct_header_->MergeBlockId()); + + // (3) Turn the loop construct header into a selection. + ChangeLoopToSelection(); + + // We have made control flow changes that do not preserve the analyses that + // were performed. + context_->InvalidateAnalysesExceptFor(IRContext::Analysis::kAnalysisNone); + + // (4) By changing CFG edges we may have created scenarios where ids are used + // without being dominated; we fix instances of this. + FixNonDominatedIdUses(); + + // Invalidate the analyses we just used. + context_->InvalidateAnalysesExceptFor(IRContext::Analysis::kAnalysisNone); +} + +void StructuredLoopToSelectionReductionOpportunity::RedirectToClosestMergeBlock( + uint32_t original_target_id) { + // Consider every predecessor of the node with respect to which edges should + // be redirected. + std::set already_seen; + for (auto pred : context_->cfg()->preds(original_target_id)) { + if (already_seen.find(pred) != already_seen.end()) { + // We have already handled this predecessor (this scenario can arise if + // there are multiple edges from a block b to original_target_id). + continue; + } + already_seen.insert(pred); + + if (!context_->GetDominatorAnalysis(enclosing_function_) + ->IsReachable(pred)) { + // We do not care about unreachable predecessors (and dominance + // information, and thus the notion of structured control flow, makes + // little sense for unreachable blocks). + continue; + } + // Find the merge block of the structured control construct that most + // tightly encloses the predecessor. + uint32_t new_merge_target; + // The structured CFG analysis deliberately does not regard a header as + // belonging to the structure that it heads. We want it to, so handle this + // case specially. + if (context_->cfg()->block(pred)->MergeBlockIdIfAny()) { + new_merge_target = context_->cfg()->block(pred)->MergeBlockIdIfAny(); + } else { + new_merge_target = context_->GetStructuredCFGAnalysis()->MergeBlock(pred); + } + assert(new_merge_target != pred); + + if (!new_merge_target) { + // If the loop being transformed is outermost, and the predecessor is + // part of that loop's continue construct, there will be no such + // enclosing control construct. In this case, the continue construct + // will become unreachable anyway, so it is fine not to redirect the + // edge. + continue; + } + + if (new_merge_target != original_target_id) { + // Redirect the edge if it doesn't already point to the desired block. + RedirectEdge(pred, original_target_id, new_merge_target); + } + } +} + +void StructuredLoopToSelectionReductionOpportunity::RedirectEdge( + uint32_t source_id, uint32_t original_target_id, uint32_t new_target_id) { + // Redirect edge source_id->original_target_id to edge + // source_id->new_target_id, where the blocks involved are all different. + assert(source_id != original_target_id); + assert(source_id != new_target_id); + assert(original_target_id != new_target_id); + + // original_target_id must either be the merge target or continue construct + // for the loop being operated on. + assert(original_target_id == loop_construct_header_->MergeBlockId() || + original_target_id == loop_construct_header_->ContinueBlockId()); + + auto terminator = context_->cfg()->block(source_id)->terminator(); + + // Figure out which operands of the terminator need to be considered for + // redirection. + std::vector operand_indices; + if (terminator->opcode() == SpvOpBranch) { + operand_indices = {0}; + } else if (terminator->opcode() == SpvOpBranchConditional) { + operand_indices = {1, 2}; + } else { + assert(terminator->opcode() == SpvOpSwitch); + for (uint32_t label_index = 1; label_index < terminator->NumOperands(); + label_index += 2) { + operand_indices.push_back(label_index); + } + } + + // Redirect the relevant operands, asserting that at least one redirection is + // made. + bool redirected = false; + for (auto operand_index : operand_indices) { + if (terminator->GetSingleWordOperand(operand_index) == original_target_id) { + terminator->SetOperand(operand_index, {new_target_id}); + redirected = true; + } + } + (void)(redirected); + assert(redirected); + + // The old and new targets may have phi instructions; these will need to + // respect the change in edges. + AdaptPhiInstructionsForRemovedEdge( + source_id, context_->cfg()->block(original_target_id)); + AdaptPhiInstructionsForAddedEdge(source_id, + context_->cfg()->block(new_target_id)); +} + +void StructuredLoopToSelectionReductionOpportunity:: + AdaptPhiInstructionsForAddedEdge(uint32_t from_id, BasicBlock* to_block) { + to_block->ForEachPhiInst([this, &from_id](Instruction* phi_inst) { + // Add to the phi operand an (undef, from_id) pair to reflect the added + // edge. + auto undef_id = FindOrCreateGlobalUndef(context_, phi_inst->type_id()); + phi_inst->AddOperand(Operand(SPV_OPERAND_TYPE_ID, {undef_id})); + phi_inst->AddOperand(Operand(SPV_OPERAND_TYPE_ID, {from_id})); + }); +} + +void StructuredLoopToSelectionReductionOpportunity::ChangeLoopToSelection() { + // Change the merge instruction from OpLoopMerge to OpSelectionMerge, with + // the same merge block. + auto loop_merge_inst = loop_construct_header_->GetLoopMergeInst(); + auto const loop_merge_block_id = + loop_merge_inst->GetSingleWordOperand(kMergeNodeIndex); + loop_merge_inst->SetOpcode(SpvOpSelectionMerge); + loop_merge_inst->ReplaceOperands( + {{loop_merge_inst->GetOperand(kMergeNodeIndex).type, + {loop_merge_block_id}}, + {SPV_OPERAND_TYPE_SELECTION_CONTROL, {SpvSelectionControlMaskNone}}}); + + // The loop header either finishes with OpBranch or OpBranchConditional. + // The latter is fine for a selection. In the former case we need to turn + // it into OpBranchConditional. We use "true" as the condition, and make + // the "else" branch be the merge block. + auto terminator = loop_construct_header_->terminator(); + if (terminator->opcode() == SpvOpBranch) { + opt::analysis::Bool temp; + const opt::analysis::Bool* bool_type = + context_->get_type_mgr()->GetRegisteredType(&temp)->AsBool(); + auto const_mgr = context_->get_constant_mgr(); + auto true_const = const_mgr->GetConstant(bool_type, {1}); + auto true_const_result_id = + const_mgr->GetDefiningInstruction(true_const)->result_id(); + auto original_branch_id = terminator->GetSingleWordOperand(0); + terminator->SetOpcode(SpvOpBranchConditional); + terminator->ReplaceOperands({{SPV_OPERAND_TYPE_ID, {true_const_result_id}}, + {SPV_OPERAND_TYPE_ID, {original_branch_id}}, + {SPV_OPERAND_TYPE_ID, {loop_merge_block_id}}}); + if (original_branch_id != loop_merge_block_id) { + AdaptPhiInstructionsForAddedEdge( + loop_construct_header_->id(), + context_->cfg()->block(loop_merge_block_id)); + } + } +} + +void StructuredLoopToSelectionReductionOpportunity::FixNonDominatedIdUses() { + // Consider each instruction in the function. + for (auto& block : *enclosing_function_) { + for (auto& def : block) { + if (def.opcode() == SpvOpVariable) { + // Variables are defined at the start of the function, and can be + // accessed by all blocks, even by unreachable blocks that have no + // dominators, so we do not need to worry about them. + continue; + } + context_->get_def_use_mgr()->ForEachUse(&def, [this, &block, &def]( + Instruction* use, + uint32_t index) { + // Ignore uses outside of blocks, such as in OpDecorate. + if (context_->get_instr_block(use) == nullptr) { + return; + } + // If a use is not appropriately dominated by its definition, + // replace the use with an OpUndef, unless the definition is an + // access chain, in which case replace it with some (possibly fresh) + // variable (as we cannot load from / store to OpUndef). + if (!DefinitionSufficientlyDominatesUse(&def, use, index, block)) { + if (def.opcode() == SpvOpAccessChain) { + auto pointer_type = + context_->get_type_mgr()->GetType(def.type_id())->AsPointer(); + switch (pointer_type->storage_class()) { + case SpvStorageClassFunction: + use->SetOperand( + index, {FindOrCreateFunctionVariable( + context_->get_type_mgr()->GetId(pointer_type))}); + break; + default: + // TODO(2183) Need to think carefully about whether it makes + // sense to add new variables for all storage classes; it's fine + // for Private but might not be OK for input/output storage + // classes for example. + use->SetOperand( + index, {FindOrCreateGlobalVariable( + context_->get_type_mgr()->GetId(pointer_type))}); + break; + } + } else { + use->SetOperand(index, + {FindOrCreateGlobalUndef(context_, def.type_id())}); + } + } + }); + } + } +} + +bool StructuredLoopToSelectionReductionOpportunity:: + DefinitionSufficientlyDominatesUse(Instruction* def, Instruction* use, + uint32_t use_index, + BasicBlock& def_block) { + if (use->opcode() == SpvOpPhi) { + // A use in a phi doesn't need to be dominated by its definition, but the + // associated parent block does need to be dominated by the definition. + return context_->GetDominatorAnalysis(enclosing_function_) + ->Dominates(def_block.id(), use->GetSingleWordOperand(use_index + 1)); + } + // In non-phi cases, a use needs to be dominated by its definition. + return context_->GetDominatorAnalysis(enclosing_function_) + ->Dominates(def, use); +} + +uint32_t +StructuredLoopToSelectionReductionOpportunity::FindOrCreateGlobalVariable( + uint32_t pointer_type_id) { + for (auto& inst : context_->module()->types_values()) { + if (inst.opcode() != SpvOpVariable) { + continue; + } + if (inst.type_id() == pointer_type_id) { + return inst.result_id(); + } + } + const uint32_t variable_id = context_->TakeNextId(); + std::unique_ptr variable_inst( + new Instruction(context_, SpvOpVariable, pointer_type_id, variable_id, + {{SPV_OPERAND_TYPE_STORAGE_CLASS, + {(uint32_t)context_->get_type_mgr() + ->GetType(pointer_type_id) + ->AsPointer() + ->storage_class()}}})); + context_->module()->AddGlobalValue(std::move(variable_inst)); + return variable_id; +} + +uint32_t +StructuredLoopToSelectionReductionOpportunity::FindOrCreateFunctionVariable( + uint32_t pointer_type_id) { + // The pointer type of a function variable must have Function storage class. + assert(context_->get_type_mgr() + ->GetType(pointer_type_id) + ->AsPointer() + ->storage_class() == SpvStorageClassFunction); + + // Go through the instructions in the function's first block until we find a + // suitable variable, or go past all the variables. + BasicBlock::iterator iter = enclosing_function_->begin()->begin(); + for (;; ++iter) { + // We will either find a suitable variable, or find a non-variable + // instruction; we won't exhaust all instructions. + assert(iter != enclosing_function_->begin()->end()); + if (iter->opcode() != SpvOpVariable) { + // If we see a non-variable, we have gone through all the variables. + break; + } + if (iter->type_id() == pointer_type_id) { + return iter->result_id(); + } + } + // At this point, iter refers to the first non-function instruction of the + // function's entry block. + const uint32_t variable_id = context_->TakeNextId(); + std::unique_ptr variable_inst(new Instruction( + context_, SpvOpVariable, pointer_type_id, variable_id, + {{SPV_OPERAND_TYPE_STORAGE_CLASS, {SpvStorageClassFunction}}})); + iter->InsertBefore(std::move(variable_inst)); + return variable_id; +} + +} // namespace reduce +} // namespace spvtools diff --git a/third_party/spirv-tools/source/reduce/structured_loop_to_selection_reduction_opportunity.h b/third_party/spirv-tools/source/reduce/structured_loop_to_selection_reduction_opportunity.h new file mode 100644 index 0000000000..564811f102 --- /dev/null +++ b/third_party/spirv-tools/source/reduce/structured_loop_to_selection_reduction_opportunity.h @@ -0,0 +1,111 @@ +// Copyright (c) 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_REDUCE_CUT_LOOP_REDUCTION_OPPORTUNITY_H_ +#define SOURCE_REDUCE_CUT_LOOP_REDUCTION_OPPORTUNITY_H_ + +#include "source/opt/def_use_manager.h" +#include "source/opt/dominator_analysis.h" +#include "source/opt/function.h" +#include "source/reduce/reduction_opportunity.h" + +namespace spvtools { +namespace reduce { + +// An opportunity to replace a structured loop with a selection. +class StructuredLoopToSelectionReductionOpportunity + : public ReductionOpportunity { + public: + // Constructs an opportunity from a loop header block and the function that + // encloses it. + explicit StructuredLoopToSelectionReductionOpportunity( + opt::IRContext* context, opt::BasicBlock* loop_construct_header, + opt::Function* enclosing_function) + : context_(context), + loop_construct_header_(loop_construct_header), + enclosing_function_(enclosing_function) {} + + // Returns true if the loop header is reachable. A structured loop might + // become unreachable as a result of turning another structured loop into + // a selection. + bool PreconditionHolds() override; + + protected: + void Apply() override; + + private: + // Parameter |original_target_id| is the id of the loop's merge block or + // continue target. This method considers each edge of the form + // b->original_target_id and transforms it into an edge of the form b->c, + // where c is the merge block of the structured control flow construct that + // most tightly contains b. + void RedirectToClosestMergeBlock(uint32_t original_target_id); + + // |source_id|, |original_target_id| and |new_target_id| are required to all + // be distinct, with a CFG edge existing from |source_id| to + // |original_target_id|, and |original_target_id| being either the merge block + // or continue target for the loop being operated on. + // The method removes this edge and adds an edge from + // |source_id| to |new_target_id|. It takes care of fixing up any OpPhi + // instructions associated with |original_target_id| and |new_target_id|. + void RedirectEdge(uint32_t source_id, uint32_t original_target_id, + uint32_t new_target_id); + + // Adds components to |to_block|'s phi instructions to account for a new + // incoming edge from |from_id|. + void AdaptPhiInstructionsForAddedEdge(uint32_t from_id, + opt::BasicBlock* to_block); + + // Turns the OpLoopMerge for the loop into OpSelectionMerge, and adapts the + // following branch instruction accordingly. + void ChangeLoopToSelection(); + + // Fixes any scenarios where, due to CFG changes, ids have uses not dominated + // by their definitions, by changing such uses to uses of OpUndef or of dummy + // variables. + void FixNonDominatedIdUses(); + + // Returns true if and only if at least one of the following holds: + // 1) |def| dominates |use| + // 2) |def| is an OpVariable + // 3) |use| is part of an OpPhi, with associated incoming block b, and |def| + // dominates b. + bool DefinitionSufficientlyDominatesUse(opt::Instruction* def, + opt::Instruction* use, + uint32_t use_index, + opt::BasicBlock& def_block); + + // Checks whether the global value list has an OpVariable of the given pointer + // type, adding one if not, and returns the id of such an OpVariable. + // + // TODO(2184): This will likely be used by other reduction passes, so should + // be factored out in due course. + uint32_t FindOrCreateGlobalVariable(uint32_t pointer_type_id); + + // Checks whether the enclosing function has an OpVariable of the given + // pointer type, adding one if not, and returns the id of such an OpVariable. + // + // TODO(2184): This will likely be used by other reduction passes, so should + // be factored out in due course. + uint32_t FindOrCreateFunctionVariable(uint32_t pointer_type_id); + + opt::IRContext* context_; + opt::BasicBlock* loop_construct_header_; + opt::Function* enclosing_function_; +}; + +} // namespace reduce +} // namespace spvtools + +#endif // SOURCE_REDUCE_CUT_LOOP_REDUCTION_OPPORTUNITY_H_ diff --git a/third_party/spirv-tools/source/reduce/structured_loop_to_selection_reduction_opportunity_finder.cpp b/third_party/spirv-tools/source/reduce/structured_loop_to_selection_reduction_opportunity_finder.cpp new file mode 100644 index 0000000000..085b267226 --- /dev/null +++ b/third_party/spirv-tools/source/reduce/structured_loop_to_selection_reduction_opportunity_finder.cpp @@ -0,0 +1,104 @@ +// Copyright (c) 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/reduce/structured_loop_to_selection_reduction_opportunity_finder.h" + +#include "source/reduce/structured_loop_to_selection_reduction_opportunity.h" + +namespace spvtools { +namespace reduce { + +using opt::IRContext; + +namespace { +const uint32_t kMergeNodeIndex = 0; +const uint32_t kContinueNodeIndex = 1; +} // namespace + +std::vector> +StructuredLoopToSelectionReductionOpportunityFinder::GetAvailableOpportunities( + IRContext* context) const { + std::vector> result; + + std::set merge_block_ids; + for (auto& function : *context->module()) { + for (auto& block : function) { + auto merge_block_id = block.MergeBlockIdIfAny(); + if (merge_block_id) { + merge_block_ids.insert(merge_block_id); + } + } + } + + // Consider each loop construct header in the module. + for (auto& function : *context->module()) { + for (auto& block : function) { + auto loop_merge_inst = block.GetLoopMergeInst(); + if (!loop_merge_inst) { + // This is not a loop construct header. + continue; + } + + uint32_t continue_block_id = + loop_merge_inst->GetSingleWordOperand(kContinueNodeIndex); + + // Check whether the loop construct's continue target is the merge block + // of some structured control flow construct. If it is, we cautiously do + // not consider applying a transformation. + if (merge_block_ids.find(continue_block_id) != merge_block_ids.end()) { + continue; + } + + // Check whether the loop header block is also the continue target. If it + // is, we cautiously do not consider applying a transformation. + if (block.id() == continue_block_id) { + continue; + } + + // Check whether the loop construct header dominates its merge block. + // If not, the merge block must be unreachable in the control flow graph + // so we cautiously do not consider applying a transformation. + auto merge_block_id = + loop_merge_inst->GetSingleWordInOperand(kMergeNodeIndex); + if (!context->GetDominatorAnalysis(&function)->Dominates( + block.id(), merge_block_id)) { + continue; + } + + // Check whether the loop construct merge block postdominates the loop + // construct header. If not (e.g. because the loop contains OpReturn, + // OpKill or OpUnreachable), we cautiously do not consider applying + // a transformation. + if (!context->GetPostDominatorAnalysis(&function)->Dominates( + merge_block_id, block.id())) { + continue; + } + + // We can turn this structured loop into a selection, so add the + // opportunity to do so. + result.push_back( + MakeUnique( + context, &block, &function)); + } + } + return result; +} + +std::string StructuredLoopToSelectionReductionOpportunityFinder::GetName() + const { + return "StructuredLoopToSelectionReductionOpportunityFinder"; +} + +} // namespace reduce +} // namespace spvtools diff --git a/third_party/spirv-tools/source/reduce/structured_loop_to_selection_reduction_opportunity_finder.h b/third_party/spirv-tools/source/reduce/structured_loop_to_selection_reduction_opportunity_finder.h new file mode 100644 index 0000000000..d63d43408a --- /dev/null +++ b/third_party/spirv-tools/source/reduce/structured_loop_to_selection_reduction_opportunity_finder.h @@ -0,0 +1,57 @@ +// Copyright (c) 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_REDUCE_STRUCTURED_LOOP_TO_SELECTION_REDUCTION_OPPORTUNITY_FINDER_H +#define SOURCE_REDUCE_STRUCTURED_LOOP_TO_SELECTION_REDUCTION_OPPORTUNITY_FINDER_H + +#include "source/reduce/reduction_opportunity_finder.h" + +namespace spvtools { +namespace reduce { + +// A finder for opportunities to turn structured loops into selections, +// generalizing from a human-writable language the idea of turning a loop: +// +// while (c) { +// body; +// } +// +// into: +// +// if (c) { +// body; +// } +// +// Applying such opportunities results in continue constructs of transformed +// loops becoming unreachable, so that it may be possible to remove them +// subsequently. +class StructuredLoopToSelectionReductionOpportunityFinder + : public ReductionOpportunityFinder { + public: + StructuredLoopToSelectionReductionOpportunityFinder() = default; + + ~StructuredLoopToSelectionReductionOpportunityFinder() override = default; + + std::string GetName() const final; + + std::vector> GetAvailableOpportunities( + opt::IRContext* context) const final; + + private: +}; + +} // namespace reduce +} // namespace spvtools + +#endif // SOURCE_REDUCE_STRUCTURED_LOOP_TO_SELECTION_REDUCTION_OPPORTUNITY_FINDER_H diff --git a/third_party/spirv-tools/source/spirv_fuzzer_options.cpp b/third_party/spirv-tools/source/spirv_fuzzer_options.cpp new file mode 100644 index 0000000000..b407f148a7 --- /dev/null +++ b/third_party/spirv-tools/source/spirv_fuzzer_options.cpp @@ -0,0 +1,56 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/spirv_fuzzer_options.h" + +namespace { +// The default maximum number of steps for the reducer to run before giving up. +const uint32_t kDefaultStepLimit = 250; +} // namespace + +spv_fuzzer_options_t::spv_fuzzer_options_t() + : has_random_seed(false), + random_seed(0), + replay_validation_enabled(false), + shrinker_step_limit(kDefaultStepLimit), + fuzzer_pass_validation_enabled(false) {} + +SPIRV_TOOLS_EXPORT spv_fuzzer_options spvFuzzerOptionsCreate() { + return new spv_fuzzer_options_t(); +} + +SPIRV_TOOLS_EXPORT void spvFuzzerOptionsDestroy(spv_fuzzer_options options) { + delete options; +} + +SPIRV_TOOLS_EXPORT void spvFuzzerOptionsEnableReplayValidation( + spv_fuzzer_options options) { + options->replay_validation_enabled = true; +} + +SPIRV_TOOLS_EXPORT void spvFuzzerOptionsSetRandomSeed( + spv_fuzzer_options options, uint32_t seed) { + options->has_random_seed = true; + options->random_seed = seed; +} + +SPIRV_TOOLS_EXPORT void spvFuzzerOptionsSetShrinkerStepLimit( + spv_fuzzer_options options, uint32_t shrinker_step_limit) { + options->shrinker_step_limit = shrinker_step_limit; +} + +SPIRV_TOOLS_EXPORT void spvFuzzerOptionsEnableFuzzerPassValidation( + spv_fuzzer_options options) { + options->fuzzer_pass_validation_enabled = true; +} diff --git a/third_party/spirv-tools/source/spirv_fuzzer_options.h b/third_party/spirv-tools/source/spirv_fuzzer_options.h new file mode 100644 index 0000000000..143f77f84e --- /dev/null +++ b/third_party/spirv-tools/source/spirv_fuzzer_options.h @@ -0,0 +1,42 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_SPIRV_FUZZER_OPTIONS_H_ +#define SOURCE_SPIRV_FUZZER_OPTIONS_H_ + +#include "spirv-tools/libspirv.h" + +#include +#include + +// Manages command line options passed to the SPIR-V Fuzzer. New struct +// members may be added for any new option. +struct spv_fuzzer_options_t { + spv_fuzzer_options_t(); + + // See spvFuzzerOptionsSetRandomSeed. + bool has_random_seed; + uint32_t random_seed; + + // See spvFuzzerOptionsEnableReplayValidation. + bool replay_validation_enabled; + + // See spvFuzzerOptionsSetShrinkerStepLimit. + uint32_t shrinker_step_limit; + + // See spvFuzzerOptionsValidateAfterEveryPass. + bool fuzzer_pass_validation_enabled; +}; + +#endif // SOURCE_SPIRV_FUZZER_OPTIONS_H_ diff --git a/third_party/spirv-tools/source/spirv_optimizer_options.cpp b/third_party/spirv-tools/source/spirv_optimizer_options.cpp new file mode 100644 index 0000000000..e92ffc0f42 --- /dev/null +++ b/third_party/spirv-tools/source/spirv_optimizer_options.cpp @@ -0,0 +1,51 @@ +// Copyright (c) 2017 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include + +#include "source/spirv_optimizer_options.h" + +SPIRV_TOOLS_EXPORT spv_optimizer_options spvOptimizerOptionsCreate(void) { + return new spv_optimizer_options_t(); +} + +SPIRV_TOOLS_EXPORT void spvOptimizerOptionsDestroy( + spv_optimizer_options options) { + delete options; +} + +SPIRV_TOOLS_EXPORT void spvOptimizerOptionsSetRunValidator( + spv_optimizer_options options, bool val) { + options->run_validator_ = val; +} + +SPIRV_TOOLS_EXPORT void spvOptimizerOptionsSetValidatorOptions( + spv_optimizer_options options, spv_validator_options val) { + options->val_options_ = *val; +} +SPIRV_TOOLS_EXPORT void spvOptimizerOptionsSetMaxIdBound( + spv_optimizer_options options, uint32_t val) { + options->max_id_bound_ = val; +} + +SPIRV_TOOLS_EXPORT void spvOptimizerOptionsSetPreserveBindings( + spv_optimizer_options options, bool val) { + options->preserve_bindings_ = val; +} + +SPIRV_TOOLS_EXPORT void spvOptimizerOptionsSetPreserveSpecConstants( + spv_optimizer_options options, bool val) { + options->preserve_spec_constants_ = val; +} diff --git a/third_party/spirv-tools/source/spirv_optimizer_options.h b/third_party/spirv-tools/source/spirv_optimizer_options.h new file mode 100644 index 0000000000..aa76d20b18 --- /dev/null +++ b/third_party/spirv-tools/source/spirv_optimizer_options.h @@ -0,0 +1,49 @@ +// Copyright (c) 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_SPIRV_OPTIMIZER_OPTIONS_H_ +#define SOURCE_SPIRV_OPTIMIZER_OPTIONS_H_ + +#include "source/spirv_validator_options.h" +#include "spirv-tools/libspirv.h" + +// Manages command line options passed to the SPIR-V Validator. New struct +// members may be added for any new option. +struct spv_optimizer_options_t { + spv_optimizer_options_t() + : run_validator_(true), + val_options_(), + max_id_bound_(kDefaultMaxIdBound), + preserve_bindings_(false), + preserve_spec_constants_(false) {} + + // When true the validator will be run before optimizations are run. + bool run_validator_; + + // Options to pass to the validator if it is run. + spv_validator_options_t val_options_; + + // The maximum value the id bound for a module can have. The Spir-V spec says + // this value must be at least 0x3FFFFF, but implementations can allow for a + // higher value. + uint32_t max_id_bound_; + + // When true, all binding declarations within the module should be preserved. + bool preserve_bindings_; + + // When true, all specialization constants within the module should be + // preserved. + bool preserve_spec_constants_; +}; +#endif // SOURCE_SPIRV_OPTIMIZER_OPTIONS_H_ diff --git a/third_party/spirv-tools/source/spirv_reducer_options.cpp b/third_party/spirv-tools/source/spirv_reducer_options.cpp new file mode 100644 index 0000000000..5801d0a16f --- /dev/null +++ b/third_party/spirv-tools/source/spirv_reducer_options.cpp @@ -0,0 +1,44 @@ +// Copyright (c) 2018 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 +#include + +#include "source/spirv_reducer_options.h" + +namespace { +// The default maximum number of steps the reducer will take before giving up. +const uint32_t kDefaultStepLimit = 250; +} // namespace + +spv_reducer_options_t::spv_reducer_options_t() + : step_limit(kDefaultStepLimit), fail_on_validation_error(false) {} + +SPIRV_TOOLS_EXPORT spv_reducer_options spvReducerOptionsCreate() { + return new spv_reducer_options_t(); +} + +SPIRV_TOOLS_EXPORT void spvReducerOptionsDestroy(spv_reducer_options options) { + delete options; +} + +SPIRV_TOOLS_EXPORT void spvReducerOptionsSetStepLimit( + spv_reducer_options options, uint32_t step_limit) { + options->step_limit = step_limit; +} + +SPIRV_TOOLS_EXPORT void spvReducerOptionsSetFailOnValidationError( + spv_reducer_options options, bool fail_on_validation_error) { + options->fail_on_validation_error = fail_on_validation_error; +} diff --git a/third_party/spirv-tools/source/spirv_reducer_options.h b/third_party/spirv-tools/source/spirv_reducer_options.h new file mode 100644 index 0000000000..1a431cce23 --- /dev/null +++ b/third_party/spirv-tools/source/spirv_reducer_options.h @@ -0,0 +1,35 @@ +// Copyright (c) 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_SPIRV_REDUCER_OPTIONS_H_ +#define SOURCE_SPIRV_REDUCER_OPTIONS_H_ + +#include "spirv-tools/libspirv.h" + +#include +#include + +// Manages command line options passed to the SPIR-V Reducer. New struct +// members may be added for any new option. +struct spv_reducer_options_t { + spv_reducer_options_t(); + + // See spvReducerOptionsSetStepLimit. + uint32_t step_limit; + + // See spvReducerOptionsSetFailOnValidationError. + bool fail_on_validation_error; +}; + +#endif // SOURCE_SPIRV_REDUCER_OPTIONS_H_ diff --git a/third_party/spirv-tools/source/spirv_target_env.cpp b/third_party/spirv-tools/source/spirv_target_env.cpp index 7a11630c72..e2ff99cb04 100644 --- a/third_party/spirv-tools/source/spirv_target_env.cpp +++ b/third_party/spirv-tools/source/spirv_target_env.cpp @@ -14,8 +14,8 @@ #include "source/spirv_target_env.h" -#include #include +#include #include "source/spirv_constant.h" #include "spirv-tools/libspirv.h" @@ -62,8 +62,15 @@ const char* spvTargetEnvDescription(spv_target_env env) { return "SPIR-V 1.3 (under Vulkan 1.1 semantics)"; case SPV_ENV_WEBGPU_0: return "SPIR-V 1.3 (under WIP WebGPU semantics)"; + case SPV_ENV_UNIVERSAL_1_4: + return "SPIR-V 1.4"; + case SPV_ENV_VULKAN_1_1_SPIRV_1_4: + return "SPIR-V 1.4 (under Vulkan 1.1 semantics)"; + case SPV_ENV_UNIVERSAL_1_5: + return "SPIR-V 1.5"; + case SPV_ENV_VULKAN_1_2: + return "SPIR-V 1.5 (under Vulkan 1.2 semantics)"; } - assert(0 && "Unhandled SPIR-V target environment"); return ""; } @@ -93,79 +100,85 @@ uint32_t spvVersionForTargetEnv(spv_target_env env) { case SPV_ENV_VULKAN_1_1: case SPV_ENV_WEBGPU_0: return SPV_SPIRV_VERSION_WORD(1, 3); + case SPV_ENV_UNIVERSAL_1_4: + case SPV_ENV_VULKAN_1_1_SPIRV_1_4: + return SPV_SPIRV_VERSION_WORD(1, 4); + case SPV_ENV_UNIVERSAL_1_5: + case SPV_ENV_VULKAN_1_2: + return SPV_SPIRV_VERSION_WORD(1, 5); } - assert(0 && "Unhandled SPIR-V target environment"); return SPV_SPIRV_VERSION_WORD(0, 0); } +static const std::pair spvTargetEnvNameMap[] = { + {"vulkan1.1spv1.4", SPV_ENV_VULKAN_1_1_SPIRV_1_4}, + {"vulkan1.0", SPV_ENV_VULKAN_1_0}, + {"vulkan1.1", SPV_ENV_VULKAN_1_1}, + {"vulkan1.2", SPV_ENV_VULKAN_1_2}, + {"spv1.0", SPV_ENV_UNIVERSAL_1_0}, + {"spv1.1", SPV_ENV_UNIVERSAL_1_1}, + {"spv1.2", SPV_ENV_UNIVERSAL_1_2}, + {"spv1.3", SPV_ENV_UNIVERSAL_1_3}, + {"spv1.4", SPV_ENV_UNIVERSAL_1_4}, + {"spv1.5", SPV_ENV_UNIVERSAL_1_5}, + {"opencl1.2embedded", SPV_ENV_OPENCL_EMBEDDED_1_2}, + {"opencl1.2", SPV_ENV_OPENCL_1_2}, + {"opencl2.0embedded", SPV_ENV_OPENCL_EMBEDDED_2_0}, + {"opencl2.0", SPV_ENV_OPENCL_2_0}, + {"opencl2.1embedded", SPV_ENV_OPENCL_EMBEDDED_2_1}, + {"opencl2.1", SPV_ENV_OPENCL_2_1}, + {"opencl2.2embedded", SPV_ENV_OPENCL_EMBEDDED_2_2}, + {"opencl2.2", SPV_ENV_OPENCL_2_2}, + {"opengl4.0", SPV_ENV_OPENGL_4_0}, + {"opengl4.1", SPV_ENV_OPENGL_4_1}, + {"opengl4.2", SPV_ENV_OPENGL_4_2}, + {"opengl4.3", SPV_ENV_OPENGL_4_3}, + {"opengl4.5", SPV_ENV_OPENGL_4_5}, + {"webgpu0", SPV_ENV_WEBGPU_0}, +}; + bool spvParseTargetEnv(const char* s, spv_target_env* env) { auto match = [s](const char* b) { return s && (0 == strncmp(s, b, strlen(b))); }; - if (match("vulkan1.0")) { - if (env) *env = SPV_ENV_VULKAN_1_0; - return true; - } else if (match("vulkan1.1")) { - if (env) *env = SPV_ENV_VULKAN_1_1; - return true; - } else if (match("spv1.0")) { - if (env) *env = SPV_ENV_UNIVERSAL_1_0; - return true; - } else if (match("spv1.1")) { - if (env) *env = SPV_ENV_UNIVERSAL_1_1; - return true; - } else if (match("spv1.2")) { - if (env) *env = SPV_ENV_UNIVERSAL_1_2; - return true; - } else if (match("spv1.3")) { - if (env) *env = SPV_ENV_UNIVERSAL_1_3; - return true; - } else if (match("opencl1.2embedded")) { - if (env) *env = SPV_ENV_OPENCL_EMBEDDED_1_2; - return true; - } else if (match("opencl1.2")) { - if (env) *env = SPV_ENV_OPENCL_1_2; - return true; - } else if (match("opencl2.0embedded")) { - if (env) *env = SPV_ENV_OPENCL_EMBEDDED_2_0; - return true; - } else if (match("opencl2.0")) { - if (env) *env = SPV_ENV_OPENCL_2_0; - return true; - } else if (match("opencl2.1embedded")) { - if (env) *env = SPV_ENV_OPENCL_EMBEDDED_2_1; - return true; - } else if (match("opencl2.1")) { - if (env) *env = SPV_ENV_OPENCL_2_1; - return true; - } else if (match("opencl2.2embedded")) { - if (env) *env = SPV_ENV_OPENCL_EMBEDDED_2_2; - return true; - } else if (match("opencl2.2")) { - if (env) *env = SPV_ENV_OPENCL_2_2; - return true; - } else if (match("opengl4.0")) { - if (env) *env = SPV_ENV_OPENGL_4_0; - return true; - } else if (match("opengl4.1")) { - if (env) *env = SPV_ENV_OPENGL_4_1; - return true; - } else if (match("opengl4.2")) { - if (env) *env = SPV_ENV_OPENGL_4_2; - return true; - } else if (match("opengl4.3")) { - if (env) *env = SPV_ENV_OPENGL_4_3; - return true; - } else if (match("opengl4.5")) { - if (env) *env = SPV_ENV_OPENGL_4_5; - return true; - } else if (match("webgpu0")) { - if (env) *env = SPV_ENV_WEBGPU_0; - return true; - } else { - if (env) *env = SPV_ENV_UNIVERSAL_1_0; - return false; + for (auto& name_env : spvTargetEnvNameMap) { + if (match(name_env.first)) { + if (env) { + *env = name_env.second; + } + return true; + } } + if (env) *env = SPV_ENV_UNIVERSAL_1_0; + return false; +} + +#define VULKAN_VER(MAJOR, MINOR) ((MAJOR << 22) | (MINOR << 12)) +#define SPIRV_VER(MAJOR, MINOR) ((MAJOR << 16) | (MINOR << 8)) + +struct VulkanEnv { + spv_target_env vulkan_env; + uint32_t vulkan_ver; + uint32_t spirv_ver; +}; +// Maps each Vulkan target environment enum to the Vulkan version, and the +// maximum supported SPIR-V version for that Vulkan environment. +// Keep this ordered from least capable to most capable. +static const VulkanEnv ordered_vulkan_envs[] = { + {SPV_ENV_VULKAN_1_0, VULKAN_VER(1, 0), SPIRV_VER(1, 0)}, + {SPV_ENV_VULKAN_1_1, VULKAN_VER(1, 1), SPIRV_VER(1, 3)}, + {SPV_ENV_VULKAN_1_1_SPIRV_1_4, VULKAN_VER(1, 1), SPIRV_VER(1, 4)}, + {SPV_ENV_VULKAN_1_2, VULKAN_VER(1, 2), SPIRV_VER(1, 5)}}; + +bool spvParseVulkanEnv(uint32_t vulkan_ver, uint32_t spirv_ver, + spv_target_env* env) { + for (auto triple : ordered_vulkan_envs) { + if (triple.vulkan_ver >= vulkan_ver && triple.spirv_ver >= spirv_ver) { + *env = triple.vulkan_env; + return true; + } + } + return false; } bool spvIsVulkanEnv(spv_target_env env) { @@ -188,10 +201,180 @@ bool spvIsVulkanEnv(spv_target_env env) { case SPV_ENV_OPENCL_EMBEDDED_2_2: case SPV_ENV_UNIVERSAL_1_3: case SPV_ENV_WEBGPU_0: + case SPV_ENV_UNIVERSAL_1_4: + case SPV_ENV_UNIVERSAL_1_5: return false; case SPV_ENV_VULKAN_1_0: case SPV_ENV_VULKAN_1_1: + case SPV_ENV_VULKAN_1_1_SPIRV_1_4: + case SPV_ENV_VULKAN_1_2: return true; } return false; } + +bool spvIsOpenCLEnv(spv_target_env env) { + switch (env) { + case SPV_ENV_UNIVERSAL_1_0: + case SPV_ENV_VULKAN_1_0: + case SPV_ENV_UNIVERSAL_1_1: + case SPV_ENV_OPENGL_4_0: + case SPV_ENV_OPENGL_4_1: + case SPV_ENV_OPENGL_4_2: + case SPV_ENV_OPENGL_4_3: + case SPV_ENV_OPENGL_4_5: + case SPV_ENV_UNIVERSAL_1_2: + case SPV_ENV_UNIVERSAL_1_3: + case SPV_ENV_VULKAN_1_1: + case SPV_ENV_WEBGPU_0: + case SPV_ENV_UNIVERSAL_1_4: + case SPV_ENV_VULKAN_1_1_SPIRV_1_4: + case SPV_ENV_UNIVERSAL_1_5: + case SPV_ENV_VULKAN_1_2: + return false; + case SPV_ENV_OPENCL_1_2: + case SPV_ENV_OPENCL_EMBEDDED_1_2: + case SPV_ENV_OPENCL_2_0: + case SPV_ENV_OPENCL_EMBEDDED_2_0: + case SPV_ENV_OPENCL_EMBEDDED_2_1: + case SPV_ENV_OPENCL_EMBEDDED_2_2: + case SPV_ENV_OPENCL_2_1: + case SPV_ENV_OPENCL_2_2: + return true; + } + return false; +} + +bool spvIsWebGPUEnv(spv_target_env env) { + switch (env) { + case SPV_ENV_UNIVERSAL_1_0: + case SPV_ENV_VULKAN_1_0: + case SPV_ENV_UNIVERSAL_1_1: + case SPV_ENV_OPENGL_4_0: + case SPV_ENV_OPENGL_4_1: + case SPV_ENV_OPENGL_4_2: + case SPV_ENV_OPENGL_4_3: + case SPV_ENV_OPENGL_4_5: + case SPV_ENV_UNIVERSAL_1_2: + case SPV_ENV_UNIVERSAL_1_3: + case SPV_ENV_VULKAN_1_1: + case SPV_ENV_OPENCL_1_2: + case SPV_ENV_OPENCL_EMBEDDED_1_2: + case SPV_ENV_OPENCL_2_0: + case SPV_ENV_OPENCL_EMBEDDED_2_0: + case SPV_ENV_OPENCL_EMBEDDED_2_1: + case SPV_ENV_OPENCL_EMBEDDED_2_2: + case SPV_ENV_OPENCL_2_1: + case SPV_ENV_OPENCL_2_2: + case SPV_ENV_UNIVERSAL_1_4: + case SPV_ENV_VULKAN_1_1_SPIRV_1_4: + case SPV_ENV_UNIVERSAL_1_5: + case SPV_ENV_VULKAN_1_2: + return false; + case SPV_ENV_WEBGPU_0: + return true; + } + return false; +} + +bool spvIsOpenGLEnv(spv_target_env env) { + switch (env) { + case SPV_ENV_UNIVERSAL_1_0: + case SPV_ENV_VULKAN_1_0: + case SPV_ENV_UNIVERSAL_1_1: + case SPV_ENV_UNIVERSAL_1_2: + case SPV_ENV_UNIVERSAL_1_3: + case SPV_ENV_VULKAN_1_1: + case SPV_ENV_OPENCL_1_2: + case SPV_ENV_OPENCL_EMBEDDED_1_2: + case SPV_ENV_OPENCL_2_0: + case SPV_ENV_OPENCL_EMBEDDED_2_0: + case SPV_ENV_OPENCL_EMBEDDED_2_1: + case SPV_ENV_OPENCL_EMBEDDED_2_2: + case SPV_ENV_OPENCL_2_1: + case SPV_ENV_OPENCL_2_2: + case SPV_ENV_WEBGPU_0: + case SPV_ENV_UNIVERSAL_1_4: + case SPV_ENV_VULKAN_1_1_SPIRV_1_4: + case SPV_ENV_UNIVERSAL_1_5: + case SPV_ENV_VULKAN_1_2: + return false; + case SPV_ENV_OPENGL_4_0: + case SPV_ENV_OPENGL_4_1: + case SPV_ENV_OPENGL_4_2: + case SPV_ENV_OPENGL_4_3: + case SPV_ENV_OPENGL_4_5: + return true; + } + return false; +} + +bool spvIsVulkanOrWebGPUEnv(spv_target_env env) { + return spvIsVulkanEnv(env) || spvIsWebGPUEnv(env); +} + +std::string spvLogStringForEnv(spv_target_env env) { + switch (env) { + case SPV_ENV_OPENCL_1_2: + case SPV_ENV_OPENCL_2_0: + case SPV_ENV_OPENCL_2_1: + case SPV_ENV_OPENCL_2_2: + case SPV_ENV_OPENCL_EMBEDDED_1_2: + case SPV_ENV_OPENCL_EMBEDDED_2_0: + case SPV_ENV_OPENCL_EMBEDDED_2_1: + case SPV_ENV_OPENCL_EMBEDDED_2_2: { + return "OpenCL"; + } + case SPV_ENV_OPENGL_4_0: + case SPV_ENV_OPENGL_4_1: + case SPV_ENV_OPENGL_4_2: + case SPV_ENV_OPENGL_4_3: + case SPV_ENV_OPENGL_4_5: { + return "OpenGL"; + } + case SPV_ENV_VULKAN_1_0: + case SPV_ENV_VULKAN_1_1: + case SPV_ENV_VULKAN_1_1_SPIRV_1_4: { + case SPV_ENV_VULKAN_1_2: + return "Vulkan"; + } + case SPV_ENV_WEBGPU_0: { + return "WebGPU"; + } + case SPV_ENV_UNIVERSAL_1_0: + case SPV_ENV_UNIVERSAL_1_1: + case SPV_ENV_UNIVERSAL_1_2: + case SPV_ENV_UNIVERSAL_1_3: + case SPV_ENV_UNIVERSAL_1_4: + case SPV_ENV_UNIVERSAL_1_5: { + return "Universal"; + } + } + return "Unknown"; +} + +std::string spvTargetEnvList(const int pad, const int wrap) { + std::string ret; + size_t max_line_len = wrap - pad; // The first line isn't padded + std::string line; + std::string sep = ""; + + for (auto& name_env : spvTargetEnvNameMap) { + std::string word = sep + name_env.first; + if (line.length() + word.length() > max_line_len) { + // Adding one word wouldn't fit, commit the line in progress and + // start a new one. + ret += line + "\n"; + line.assign(pad, ' '); + // The first line is done. The max length now comprises the + // padding. + max_line_len = wrap; + } + line += word; + sep = "|"; + } + + ret += line; + + return ret; +} diff --git a/third_party/spirv-tools/source/spirv_target_env.h b/third_party/spirv-tools/source/spirv_target_env.h index 7dc7be1d87..1bdedf917f 100644 --- a/third_party/spirv-tools/source/spirv_target_env.h +++ b/third_party/spirv-tools/source/spirv_target_env.h @@ -15,16 +15,38 @@ #ifndef SOURCE_SPIRV_TARGET_ENV_H_ #define SOURCE_SPIRV_TARGET_ENV_H_ -#include "spirv-tools/libspirv.h" +#include -// Parses s into *env and returns true if successful. If unparsable, returns -// false and sets *env to SPV_ENV_UNIVERSAL_1_0. -bool spvParseTargetEnv(const char* s, spv_target_env* env); +#include "spirv-tools/libspirv.h" // Returns true if |env| is a VULKAN environment, false otherwise. bool spvIsVulkanEnv(spv_target_env env); +// Returns true if |env| is an OPENCL environment, false otherwise. +bool spvIsOpenCLEnv(spv_target_env env); + +// Returns true if |env| is an WEBGPU environment, false otherwise. +bool spvIsWebGPUEnv(spv_target_env env); + +// Returns true if |env| is an OPENGL environment, false otherwise. +bool spvIsOpenGLEnv(spv_target_env env); + +// Returns true if |env| is a VULKAN or WEBGPU environment, false otherwise. +bool spvIsVulkanOrWebGPUEnv(spv_target_env env); + // Returns the version number for the given SPIR-V target environment. uint32_t spvVersionForTargetEnv(spv_target_env env); +// Returns a string to use in logging messages that indicates the class of +// environment, i.e. "Vulkan", "WebGPU", "OpenCL", etc. +std::string spvLogStringForEnv(spv_target_env env); + +// Returns a formatted list of all SPIR-V target environment names that +// can be parsed by spvParseTargetEnv. +// |pad| is the number of space characters that the begining of each line +// except the first one will be padded with. +// |wrap| is the max length of lines the user desires. Word-wrapping will +// occur to satisfy this limit. +std::string spvTargetEnvList(const int pad, const int wrap); + #endif // SOURCE_SPIRV_TARGET_ENV_H_ diff --git a/third_party/spirv-tools/source/spirv_validator_options.cpp b/third_party/spirv-tools/source/spirv_validator_options.cpp index 0c06253649..01aa79747b 100644 --- a/third_party/spirv-tools/source/spirv_validator_options.cpp +++ b/third_party/spirv-tools/source/spirv_validator_options.cpp @@ -12,11 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include "source/spirv_validator_options.h" + #include #include -#include "source/spirv_validator_options.h" - bool spvParseUniversalLimitsOptions(const char* s, spv_validator_limit* type) { auto match = [s](const char* b) { return s && (0 == strncmp(s, b, strlen(b))); @@ -37,6 +37,8 @@ bool spvParseUniversalLimitsOptions(const char* s, spv_validator_limit* type) { *type = spv_validator_limit_max_control_flow_nesting_depth; } else if (match("--max-access-chain-indexes")) { *type = spv_validator_limit_max_access_chain_indexes; + } else if (match("--max-id-bound")) { + *type = spv_validator_limit_max_id_bound; } else { // The command line option for this validator limit has not been added. // Therefore we return false. @@ -73,6 +75,7 @@ void spvValidatorOptionsSetUniversalLimit(spv_validator_options options, max_control_flow_nesting_depth) LIMIT(spv_validator_limit_max_access_chain_indexes, max_access_chain_indexes) + LIMIT(spv_validator_limit_max_id_bound, max_id_bound) #undef LIMIT } } @@ -87,11 +90,27 @@ void spvValidatorOptionsSetRelaxLogicalPointer(spv_validator_options options, options->relax_logical_pointer = val; } +void spvValidatorOptionsSetBeforeHlslLegalization(spv_validator_options options, + bool val) { + options->before_hlsl_legalization = val; + options->relax_logical_pointer = val; +} + void spvValidatorOptionsSetRelaxBlockLayout(spv_validator_options options, bool val) { options->relax_block_layout = val; } +void spvValidatorOptionsSetUniformBufferStandardLayout( + spv_validator_options options, bool val) { + options->uniform_buffer_standard_layout = val; +} + +void spvValidatorOptionsSetScalarBlockLayout(spv_validator_options options, + bool val) { + options->scalar_block_layout = val; +} + void spvValidatorOptionsSetSkipBlockLayout(spv_validator_options options, bool val) { options->skip_block_layout = val; diff --git a/third_party/spirv-tools/source/spirv_validator_options.h b/third_party/spirv-tools/source/spirv_validator_options.h index d264a7e0b0..b7da5d8eae 100644 --- a/third_party/spirv-tools/source/spirv_validator_options.h +++ b/third_party/spirv-tools/source/spirv_validator_options.h @@ -32,6 +32,7 @@ struct validator_universal_limits_t { uint32_t max_function_args{255}; uint32_t max_control_flow_nesting_depth{1023}; uint32_t max_access_chain_indexes{255}; + uint32_t max_id_bound{0x3FFFFF}; }; // Manages command line options passed to the SPIR-V Validator. New struct @@ -42,13 +43,19 @@ struct spv_validator_options_t { relax_struct_store(false), relax_logical_pointer(false), relax_block_layout(false), - skip_block_layout(false) {} + uniform_buffer_standard_layout(false), + scalar_block_layout(false), + skip_block_layout(false), + before_hlsl_legalization(false) {} validator_universal_limits_t universal_limits_; bool relax_struct_store; bool relax_logical_pointer; bool relax_block_layout; + bool uniform_buffer_standard_layout; + bool scalar_block_layout; bool skip_block_layout; + bool before_hlsl_legalization; }; #endif // SOURCE_SPIRV_VALIDATOR_OPTIONS_H_ diff --git a/third_party/spirv-tools/source/table.cpp b/third_party/spirv-tools/source/table.cpp index b10d776da4..8340e8e210 100644 --- a/third_party/spirv-tools/source/table.cpp +++ b/third_party/spirv-tools/source/table.cpp @@ -37,7 +37,11 @@ spv_context spvContextCreate(spv_target_env env) { case SPV_ENV_UNIVERSAL_1_2: case SPV_ENV_UNIVERSAL_1_3: case SPV_ENV_VULKAN_1_1: + case SPV_ENV_VULKAN_1_1_SPIRV_1_4: case SPV_ENV_WEBGPU_0: + case SPV_ENV_UNIVERSAL_1_4: + case SPV_ENV_UNIVERSAL_1_5: + case SPV_ENV_VULKAN_1_2: break; default: return nullptr; diff --git a/third_party/spirv-tools/source/table.h b/third_party/spirv-tools/source/table.h index 64d73dbb96..5adf04a4cc 100644 --- a/third_party/spirv-tools/source/table.h +++ b/third_party/spirv-tools/source/table.h @@ -15,9 +15,8 @@ #ifndef SOURCE_TABLE_H_ #define SOURCE_TABLE_H_ -#include "source/latest_version_spirv_header.h" - #include "source/extensions.h" +#include "source/latest_version_spirv_header.h" #include "spirv-tools/libspirv.hpp" typedef struct spv_opcode_desc_t { @@ -42,6 +41,7 @@ typedef struct spv_opcode_desc_t { // extensions. ~0u means reserved for future use. ~0u and non-empty extension // lists means only available in extensions. const uint32_t minVersion; + const uint32_t lastVersion; } spv_opcode_desc_t; typedef struct spv_operand_desc_t { @@ -60,6 +60,7 @@ typedef struct spv_operand_desc_t { // extensions. ~0u means reserved for future use. ~0u and non-empty extension // lists means only available in extensions. const uint32_t minVersion; + const uint32_t lastVersion; } spv_operand_desc_t; typedef struct spv_operand_desc_group_t { diff --git a/third_party/spirv-tools/source/text.cpp b/third_party/spirv-tools/source/text.cpp index adaf796520..88a8e8ffad 100644 --- a/third_party/spirv-tools/source/text.cpp +++ b/third_party/spirv-tools/source/text.cpp @@ -242,14 +242,37 @@ spv_result_t spvTextEncodeOperand(const spvtools::AssemblyGrammar& grammar, // The assembler accepts the symbolic name for an extended instruction, // and emits its corresponding number. spv_ext_inst_desc extInst; - if (grammar.lookupExtInst(pInst->extInstType, textValue, &extInst)) { - return context->diagnostic() - << "Invalid extended instruction name '" << textValue << "'."; - } - spvInstructionAddWord(pInst, extInst->ext_inst); + if (grammar.lookupExtInst(pInst->extInstType, textValue, &extInst) == + SPV_SUCCESS) { + // if we know about this extended instruction, push the numeric value + spvInstructionAddWord(pInst, extInst->ext_inst); - // Prepare to parse the operands for the extended instructions. - spvPushOperandTypes(extInst->operandTypes, pExpectedOperands); + // Prepare to parse the operands for the extended instructions. + spvPushOperandTypes(extInst->operandTypes, pExpectedOperands); + } else { + // if we don't know this extended instruction and the set isn't + // non-semantic, we cannot process further + if (!spvExtInstIsNonSemantic(pInst->extInstType)) { + return context->diagnostic() + << "Invalid extended instruction name '" << textValue << "'."; + } else { + // for non-semantic instruction sets, as long as the text name is an + // integer value we can encode it since we know the form of all such + // extended instructions + spv_literal_t extInstValue; + if (spvTextToLiteral(textValue, &extInstValue) || + extInstValue.type != SPV_LITERAL_TYPE_UINT_32) { + return context->diagnostic() + << "Couldn't translate unknown extended instruction name '" + << textValue << "' to unsigned integer."; + } + + spvInstructionAddWord(pInst, extInstValue.value.u32); + + // opcode contains an unknown number of IDs. + pExpectedOperands->push_back(SPV_OPERAND_TYPE_VARIABLE_ID); + } + } } break; case SPV_OPERAND_TYPE_SPEC_CONSTANT_OP_NUMBER: { @@ -377,7 +400,8 @@ spv_result_t spvTextEncodeOperand(const spvtools::AssemblyGrammar& grammar, case SPV_OPERAND_TYPE_OPTIONAL_IMAGE: case SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS: case SPV_OPERAND_TYPE_SELECTION_CONTROL: - case SPV_OPERAND_TYPE_DEBUG_INFO_FLAGS: { + case SPV_OPERAND_TYPE_DEBUG_INFO_FLAGS: + case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_INFO_FLAGS: { uint32_t value; if (grammar.parseMaskOperand(type, textValue, &value)) { return context->diagnostic() << "Invalid " << spvOperandTypeStr(type) @@ -546,6 +570,11 @@ spv_result_t spvTextEncodeOpcode(const spvtools::AssemblyGrammar& grammar, << "Expected at the beginning of an instruction, found '" << firstWord << "'."; } + if (!opcodeEntry->hasResult && !result_id.empty()) { + return context->diagnostic() + << "Cannot set ID " << result_id << " because " << opcodeName + << " does not produce a result ID."; + } pInst->opcode = opcodeEntry->opcode; context->setPosition(nextPosition); // Reserve the first word for the instruction. @@ -778,7 +807,7 @@ spv_result_t spvTextToBinary(const spv_const_context context, const size_t input_text_size, spv_binary* pBinary, spv_diagnostic* pDiagnostic) { return spvTextToBinaryWithOptions(context, input_text, input_text_size, - SPV_BINARY_TO_TEXT_OPTION_NONE, pBinary, + SPV_TEXT_TO_BINARY_OPTION_NONE, pBinary, pDiagnostic); } @@ -805,7 +834,8 @@ spv_result_t spvTextToBinaryWithOptions(const spv_const_context context, } void spvTextDestroy(spv_text text) { - if (!text) return; - delete[] text->str; - delete text; + if (text) { + if (text->str) delete[] text->str; + delete text; + } } diff --git a/third_party/spirv-tools/source/text_handler.cpp b/third_party/spirv-tools/source/text_handler.cpp index 5f6e8c41f1..c31f34a6bf 100644 --- a/third_party/spirv-tools/source/text_handler.cpp +++ b/third_party/spirv-tools/source/text_handler.cpp @@ -313,7 +313,7 @@ spv_result_t AssemblyContext::binaryEncodeString(const char* value, pInst->words.back() = 0; char* dest = (char*)&pInst->words[oldWordCount]; - strncpy(dest, value, length); + strncpy(dest, value, length + 1); return SPV_SUCCESS; } diff --git a/third_party/spirv-tools/source/util/bitutils.h b/third_party/spirv-tools/source/util/bitutils.h index 17d61df90a..9ced2f9621 100644 --- a/third_party/spirv-tools/source/util/bitutils.h +++ b/third_party/spirv-tools/source/util/bitutils.h @@ -15,8 +15,10 @@ #ifndef SOURCE_UTIL_BITUTILS_H_ #define SOURCE_UTIL_BITUTILS_H_ +#include #include #include +#include namespace spvtools { namespace utils { @@ -31,6 +33,14 @@ Dest BitwiseCast(Src source) { return dest; } +// Calculates the bit width of the integer type |T|. +template +struct IntegerBitWidth { + static_assert(std::is_integral::value, "Integer type required"); + static const size_t kBitsPerByte = 8; + static const size_t get = sizeof(T) * kBitsPerByte; +}; + // SetBits returns an integer of type with bits set // for position through , counting from the least // significant bit. In particular when Num == 0, no positions are set to 1. @@ -38,7 +48,7 @@ Dest BitwiseCast(Src source) { // a bit that will not fit in the underlying type is set. template struct SetBits { - static_assert(First < sizeof(T) * 8, + static_assert(First < IntegerBitWidth::get, "Tried to set a bit that is shifted too far."); const static T get = (T(1) << First) | SetBits::get; }; @@ -49,6 +59,11 @@ struct SetBits { }; // This is all compile-time so we can put our tests right here. +static_assert(IntegerBitWidth::get == 32, "IntegerBitWidth mismatch"); +static_assert(IntegerBitWidth::get == 32, "IntegerBitWidth mismatch"); +static_assert(IntegerBitWidth::get == 64, "IntegerBitWidth mismatch"); +static_assert(IntegerBitWidth::get == 8, "IntegerBitWidth mismatch"); + static_assert(SetBits::get == uint32_t(0x00000000), "SetBits failed"); static_assert(SetBits::get == uint32_t(0x00000001), @@ -90,6 +105,82 @@ size_t CountSetBits(T word) { return count; } +// Checks if the bit at the |position| is set to '1'. +// Bits zero-indexed starting at the least significant bit. +// |position| must be within the bit width of |T|. +template +bool IsBitAtPositionSet(T word, size_t position) { + static_assert(std::is_integral::value, "Integer type required"); + static_assert(std::is_unsigned::value, "Unsigned type required"); + assert(position < IntegerBitWidth::get && + "position must be less than the bit width"); + return word & T(T(1) << position); +} + +// Returns a value obtained by setting a range of adjacent bits of |word| to +// |value|. Affected bits are within the range: +// [first_position, first_position + num_bits_to_mutate), +// assuming zero-based indexing starting at the least +// significant bit. Bits to mutate must be within the bit width of |T|. +template +T MutateBits(T word, size_t first_position, size_t num_bits_to_mutate, + bool value) { + static_assert(std::is_integral::value, "Integer type required"); + static_assert(std::is_unsigned::value, "Unsigned type required"); + static const size_t word_bit_width = IntegerBitWidth::get; + assert(first_position < word_bit_width && + "Mutated bits must be within bit width"); + assert(first_position + num_bits_to_mutate <= word_bit_width && + "Mutated bits must be within bit width"); + if (num_bits_to_mutate == 0) { + return word; + } + + const T all_ones = ~T(0); + const size_t num_unaffected_low_bits = first_position; + const T unaffected_low_mask = + T(T(all_ones >> num_unaffected_low_bits) << num_unaffected_low_bits); + + const size_t num_unaffected_high_bits = + word_bit_width - (first_position + num_bits_to_mutate); + const T unaffected_high_mask = + T(T(all_ones << num_unaffected_high_bits) >> num_unaffected_high_bits); + + const T mutation_mask = unaffected_low_mask & unaffected_high_mask; + if (value) { + return word | mutation_mask; + } + return word & T(~mutation_mask); +} + +// Returns a value obtained by setting the |num_bits_to_set| highest bits to +// '1'. |num_bits_to_set| must be not be greater than the bit width of |T|. +template +T SetHighBits(T word, size_t num_bits_to_set) { + if (num_bits_to_set == 0) { + return word; + } + const size_t word_bit_width = IntegerBitWidth::get; + assert(num_bits_to_set <= word_bit_width && + "Can't set more bits than bit width"); + return MutateBits(word, word_bit_width - num_bits_to_set, num_bits_to_set, + true); +} + +// Returns a value obtained by setting the |num_bits_to_set| highest bits to +// '0'. |num_bits_to_set| must be not be greater than the bit width of |T|. +template +T ClearHighBits(T word, size_t num_bits_to_set) { + if (num_bits_to_set == 0) { + return word; + } + const size_t word_bit_width = IntegerBitWidth::get; + assert(num_bits_to_set <= word_bit_width && + "Can't clear more bits than bit width"); + return MutateBits(word, word_bit_width - num_bits_to_set, num_bits_to_set, + false); +} + } // namespace utils } // namespace spvtools diff --git a/third_party/spirv-tools/source/util/hex_float.h b/third_party/spirv-tools/source/util/hex_float.h index b7baf093b4..cfc40fa689 100644 --- a/third_party/spirv-tools/source/util/hex_float.h +++ b/third_party/spirv-tools/source/util/hex_float.h @@ -672,7 +672,7 @@ class HexFloat { // If we are Nan or Inf we should pass that through. if (is_inf) { - other.set_value(BitwiseCast( + other.set_value(typename other_T::underlying_type( static_cast( (negate ? other_T::sign_mask : 0) | other_T::exponent_mask))); return; @@ -687,7 +687,7 @@ class HexFloat { // We are some sort of Nan. We try to keep the bit-pattern of the Nan // as close as possible. If we had to shift off bits so we are 0, then we // just set the last bit. - other.set_value(BitwiseCast( + other.set_value(typename other_T::underlying_type( static_cast( (negate ? other_T::sign_mask : 0) | other_T::exponent_mask | (shifted_significand == 0 ? 0x1 : shifted_significand)))); diff --git a/third_party/spirv-tools/source/util/string_utils.cpp b/third_party/spirv-tools/source/util/string_utils.cpp index 29ce2aa4a9..b56c353af9 100644 --- a/third_party/spirv-tools/source/util/string_utils.cpp +++ b/third_party/spirv-tools/source/util/string_utils.cpp @@ -37,5 +37,22 @@ std::string CardinalToOrdinal(size_t cardinal) { return ToString(cardinal) + suffix; } +std::pair SplitFlagArgs(const std::string& flag) { + if (flag.size() < 2) return make_pair(flag, std::string()); + + // Detect the last dash before the pass name. Since we have to + // handle single dash options (-O and -Os), count up to two dashes. + size_t dash_ix = 0; + if (flag[0] == '-' && flag[1] == '-') + dash_ix = 2; + else if (flag[0] == '-') + dash_ix = 1; + + size_t ix = flag.find('='); + return (ix != std::string::npos) + ? make_pair(flag.substr(dash_ix, ix - 2), flag.substr(ix + 1)) + : make_pair(flag.substr(dash_ix), std::string()); +} + } // namespace utils } // namespace spvtools diff --git a/third_party/spirv-tools/source/util/string_utils.h b/third_party/spirv-tools/source/util/string_utils.h index 322c574fb6..4282aa9496 100644 --- a/third_party/spirv-tools/source/util/string_utils.h +++ b/third_party/spirv-tools/source/util/string_utils.h @@ -15,8 +15,10 @@ #ifndef SOURCE_UTIL_STRING_UTILS_H_ #define SOURCE_UTIL_STRING_UTILS_H_ +#include #include #include +#include #include "source/util/string_utils.h" @@ -37,6 +39,53 @@ std::string ToString(T val) { // Converts cardinal number to ordinal number string. std::string CardinalToOrdinal(size_t cardinal); +// Splits the string |flag|, of the form '--pass_name[=pass_args]' into two +// strings "pass_name" and "pass_args". If |flag| has no arguments, the second +// string will be empty. +std::pair SplitFlagArgs(const std::string& flag); + +// Encodes a string as a sequence of words, using the SPIR-V encoding. +inline std::vector MakeVector(std::string input) { + std::vector result; + uint32_t word = 0; + size_t num_bytes = input.size(); + // SPIR-V strings are null-terminated. The byte_index == num_bytes + // case is used to push the terminating null byte. + for (size_t byte_index = 0; byte_index <= num_bytes; byte_index++) { + const auto new_byte = + (byte_index < num_bytes ? uint8_t(input[byte_index]) : uint8_t(0)); + word |= (new_byte << (8 * (byte_index % sizeof(uint32_t)))); + if (3 == (byte_index % sizeof(uint32_t))) { + result.push_back(word); + word = 0; + } + } + // Emit a trailing partial word. + if ((num_bytes + 1) % sizeof(uint32_t)) { + result.push_back(word); + } + return result; +} + +// Decode a string from a sequence of words, using the SPIR-V encoding. +template +inline std::string MakeString(const VectorType& words) { + std::string result; + + for (uint32_t word : words) { + for (int byte_index = 0; byte_index < 4; byte_index++) { + uint32_t extracted_word = (word >> (8 * byte_index)) & 0xFF; + char c = static_cast(extracted_word); + if (c == 0) { + return result; + } + result += c; + } + } + assert(false && "Did not find terminating null for the string."); + return result; +} // namespace utils + } // namespace utils } // namespace spvtools diff --git a/third_party/spirv-tools/source/val/basic_block.h b/third_party/spirv-tools/source/val/basic_block.h index efbd243b67..876105c271 100644 --- a/third_party/spirv-tools/source/val/basic_block.h +++ b/third_party/spirv-tools/source/val/basic_block.h @@ -15,8 +15,8 @@ #ifndef SOURCE_VAL_BASIC_BLOCK_H_ #define SOURCE_VAL_BASIC_BLOCK_H_ -#include #include +#include #include #include #include @@ -28,7 +28,7 @@ namespace val { enum BlockType : uint32_t { kBlockTypeUndefined, - kBlockTypeHeader, + kBlockTypeSelection, kBlockTypeLoop, kBlockTypeMerge, kBlockTypeBreak, diff --git a/third_party/spirv-tools/source/val/construct.cpp b/third_party/spirv-tools/source/val/construct.cpp index c11a065b7f..733856cb84 100644 --- a/third_party/spirv-tools/source/val/construct.cpp +++ b/third_party/spirv-tools/source/val/construct.cpp @@ -19,6 +19,7 @@ #include #include "source/val/function.h" +#include "source/val/validation_state.h" namespace spvtools { namespace val { @@ -73,7 +74,6 @@ Construct::ConstructBlockSet Construct::blocks(Function* function) const { auto header = entry_block(); auto merge = exit_block(); assert(header); - assert(merge); int header_depth = function->GetBlockDepth(const_cast(header)); ConstructBlockSet construct_blocks; std::unordered_set corresponding_headers; @@ -106,7 +106,8 @@ Construct::ConstructBlockSet Construct::blocks(Function* function) const { // A selection construct nested directly within the loop construct is also // at the same depth. It is valid, however, to branch directly to the // continue target from within the selection construct. - if (block_depth == header_depth && type() == ConstructType::kSelection && + if (block != header && block_depth == header_depth && + type() == ConstructType::kSelection && block->is_type(kBlockTypeContinue)) { // Continued to outer construct. continue; @@ -116,7 +117,10 @@ Construct::ConstructBlockSet Construct::blocks(Function* function) const { if (merge != block) { for (auto succ : *block->successors()) { - stack.push_back(succ); + // All blocks in the construct must be dominated by the header. + if (header->dominates(*succ)) { + stack.push_back(succ); + } } } } @@ -124,5 +128,102 @@ Construct::ConstructBlockSet Construct::blocks(Function* function) const { return construct_blocks; } +bool Construct::IsStructuredExit(ValidationState_t& _, BasicBlock* dest) const { + // Structured Exits: + // - Selection: + // - branch to its merge + // - branch to nearest enclosing loop merge or continue + // - branch to nearest enclosing switch selection merge + // - Loop: + // - branch to its merge + // - branch to its continue + // - Continue: + // - branch to loop header + // - branch to loop merge + // + // Note: we will never see a case construct here. + assert(type() != ConstructType::kCase); + if (type() == ConstructType::kLoop) { + auto header = entry_block(); + auto terminator = header->terminator(); + auto index = terminator - &_.ordered_instructions()[0]; + auto merge_inst = &_.ordered_instructions()[index - 1]; + auto merge_block_id = merge_inst->GetOperandAs(0u); + auto continue_block_id = merge_inst->GetOperandAs(1u); + if (dest->id() == merge_block_id || dest->id() == continue_block_id) { + return true; + } + } else if (type() == ConstructType::kContinue) { + auto loop_construct = corresponding_constructs()[0]; + auto header = loop_construct->entry_block(); + auto terminator = header->terminator(); + auto index = terminator - &_.ordered_instructions()[0]; + auto merge_inst = &_.ordered_instructions()[index - 1]; + auto merge_block_id = merge_inst->GetOperandAs(0u); + if (dest == header || dest->id() == merge_block_id) { + return true; + } + } else { + assert(type() == ConstructType::kSelection); + if (dest == exit_block()) { + return true; + } + + // The next block in the traversal is either: + // i. The header block that declares |block| as its merge block. + // ii. The immediate dominator of |block|. + auto NextBlock = [](const BasicBlock* block) -> const BasicBlock* { + for (auto& use : block->label()->uses()) { + if ((use.first->opcode() == SpvOpLoopMerge || + use.first->opcode() == SpvOpSelectionMerge) && + use.second == 1) + return use.first->block(); + } + return block->immediate_dominator(); + }; + + bool seen_switch = false; + auto header = entry_block(); + auto block = NextBlock(header); + while (block) { + auto terminator = block->terminator(); + auto index = terminator - &_.ordered_instructions()[0]; + auto merge_inst = &_.ordered_instructions()[index - 1]; + if (merge_inst->opcode() == SpvOpLoopMerge || + (header->terminator()->opcode() != SpvOpSwitch && + merge_inst->opcode() == SpvOpSelectionMerge && + terminator->opcode() == SpvOpSwitch)) { + auto merge_target = merge_inst->GetOperandAs(0u); + auto merge_block = merge_inst->function()->GetBlock(merge_target).first; + if (merge_block->dominates(*header)) { + block = NextBlock(block); + continue; + } + + if ((!seen_switch || merge_inst->opcode() == SpvOpLoopMerge) && + dest->id() == merge_target) { + return true; + } else if (merge_inst->opcode() == SpvOpLoopMerge) { + auto continue_target = merge_inst->GetOperandAs(1u); + if (dest->id() == continue_target) { + return true; + } + } + + if (terminator->opcode() == SpvOpSwitch) { + seen_switch = true; + } + + // Hit an enclosing loop and didn't break or continue. + if (merge_inst->opcode() == SpvOpLoopMerge) return false; + } + + block = NextBlock(block); + } + } + + return false; +} + } // namespace val } // namespace spvtools diff --git a/third_party/spirv-tools/source/val/construct.h b/third_party/spirv-tools/source/val/construct.h index c7e7a780d6..9476760a35 100644 --- a/third_party/spirv-tools/source/val/construct.h +++ b/third_party/spirv-tools/source/val/construct.h @@ -23,6 +23,7 @@ namespace spvtools { namespace val { +class ValidationState_t; /// Functor for ordering BasicBlocks. BasicBlock pointers must not be null. struct less_than_id { @@ -109,6 +110,24 @@ class Construct { // calculated. ConstructBlockSet blocks(Function* function) const; + // Returns true if |dest| is structured exit from the construct. Structured + // exits depend on the construct type. + // Selection: + // * branch to the associated merge + // * branch to the merge or continue of the innermost loop containing the + // selection + // * branch to the merge block of the innermost switch containing the + // selection + // Loop: + // * branch to the associated merge or continue + // Continue: + // * back-edge to the associated loop header + // * branch to the associated loop merge + // + // Note: the validator does not generate case constructs. Switches are + // checked separately from other constructs. + bool IsStructuredExit(ValidationState_t& _, BasicBlock* dest) const; + private: /// The type of the construct ConstructType type_; diff --git a/third_party/spirv-tools/source/val/function.cpp b/third_party/spirv-tools/source/val/function.cpp index f638fb5b4e..0281770024 100644 --- a/third_party/spirv-tools/source/val/function.cpp +++ b/third_party/spirv-tools/source/val/function.cpp @@ -14,9 +14,8 @@ #include "source/val/function.h" -#include - #include +#include #include #include #include @@ -86,6 +85,12 @@ spv_result_t Function::RegisterLoopMerge(uint32_t merge_id, continue_construct.set_corresponding_constructs({&loop_construct}); loop_construct.set_corresponding_constructs({&continue_construct}); merge_block_header_[&merge_block] = current_block_; + if (continue_target_headers_.find(&continue_target_block) == + continue_target_headers_.end()) { + continue_target_headers_[&continue_target_block] = {current_block_}; + } else { + continue_target_headers_[&continue_target_block].push_back(current_block_); + } return SPV_SUCCESS; } @@ -93,7 +98,7 @@ spv_result_t Function::RegisterLoopMerge(uint32_t merge_id, spv_result_t Function::RegisterSelectionMerge(uint32_t merge_id) { RegisterBlock(merge_id, false); BasicBlock& merge_block = blocks_.at(merge_id); - current_block_->set_type(kBlockTypeHeader); + current_block_->set_type(kBlockTypeSelection); merge_block.set_type(kBlockTypeMerge); merge_block_header_[&merge_block] = current_block_; @@ -311,13 +316,10 @@ int Function::GetBlockDepth(BasicBlock* bb) { if (!bb_dom || bb == bb_dom) { // This block has no dominator, so it's at depth 0. block_depth_[bb] = 0; - } else if (bb->is_type(kBlockTypeMerge)) { - // If this is a merge block, its depth is equal to the block before - // branching. - BasicBlock* header = merge_block_header_[bb]; - assert(header); - block_depth_[bb] = GetBlockDepth(header); } else if (bb->is_type(kBlockTypeContinue)) { + // This rule must precede the rule for merge blocks in order to set up + // depths correctly. If a block is both a merge and continue then the merge + // is nested within the continue's loop (or the graph is incorrect). // The depth of the continue block entry point is 1 + loop header depth. Construct* continue_construct = entry_block_to_construct_[std::make_pair(bb, ConstructType::kContinue)]; @@ -335,7 +337,13 @@ int Function::GetBlockDepth(BasicBlock* bb) { } else { block_depth_[bb] = 1 + GetBlockDepth(loop_header); } - } else if (bb_dom->is_type(kBlockTypeHeader) || + } else if (bb->is_type(kBlockTypeMerge)) { + // If this is a merge block, its depth is equal to the block before + // branching. + BasicBlock* header = merge_block_header_[bb]; + assert(header); + block_depth_[bb] = GetBlockDepth(header); + } else if (bb_dom->is_type(kBlockTypeSelection) || bb_dom->is_type(kBlockTypeLoop)) { // The dominator of the given block is a header block. So, the nesting // depth of this block is: 1 + nesting depth of the header. @@ -383,5 +391,29 @@ bool Function::IsCompatibleWithExecutionModel(SpvExecutionModel model, return return_value; } +bool Function::CheckLimitations(const ValidationState_t& _, + const Function* entry_point, + std::string* reason) const { + bool return_value = true; + std::stringstream ss_reason; + + for (const auto& is_compatible : limitations_) { + std::string message; + if (!is_compatible(_, entry_point, &message)) { + if (!reason) return false; + return_value = false; + if (!message.empty()) { + ss_reason << message << "\n"; + } + } + } + + if (!return_value && reason) { + *reason = ss_reason.str(); + } + + return return_value; +} + } // namespace val } // namespace spvtools diff --git a/third_party/spirv-tools/source/val/function.h b/third_party/spirv-tools/source/val/function.h index a052bbda0b..0d6873d8de 100644 --- a/third_party/spirv-tools/source/val/function.h +++ b/third_party/spirv-tools/source/val/function.h @@ -216,6 +216,16 @@ class Function { execution_model_limitations_.push_back(is_compatible); } + /// Registers limitation with an |is_compatible| functor. + void RegisterLimitation(std::function + is_compatible) { + limitations_.push_back(is_compatible); + } + + bool CheckLimitations(const ValidationState_t& _, const Function* entry_point, + std::string* reason) const; + /// Returns true if the given execution model passes the limitations stored in /// execution_model_limitations_. Returns false otherwise and fills optional /// |reason| parameter. @@ -232,6 +242,28 @@ class Function { return function_call_targets_; } + // Returns the block containing the OpSelectionMerge or OpLoopMerge that + // references |merge_block|. + // Values of |merge_block_header_| inserted by CFGPass, so do not call before + // the first iteration of ordered instructions in + // ValidateBinaryUsingContextAndValidationState has completed. + BasicBlock* GetMergeHeader(BasicBlock* merge_block) { + return merge_block_header_[merge_block]; + } + + // Returns vector of the blocks containing a OpLoopMerge that references + // |continue_target|. + // Values of |continue_target_headers_| inserted by CFGPass, so do not call + // before the first iteration of ordered instructions in + // ValidateBinaryUsingContextAndValidationState has completed. + std::vector GetContinueHeaders(BasicBlock* continue_target) { + if (continue_target_headers_.find(continue_target) == + continue_target_headers_.end()) { + return {}; + } + return continue_target_headers_[continue_target]; + } + private: // Computes the representation of the augmented CFG. // Populates augmented_successors_map_ and augmented_predecessors_map_. @@ -340,6 +372,10 @@ class Function { /// This map provides the header block for a given merge block. std::unordered_map merge_block_header_; + /// This map provides the header blocks for a given continue target. + std::unordered_map> + continue_target_headers_; + /// Stores the control flow nesting depth of a given basic block std::unordered_map block_depth_; @@ -350,6 +386,12 @@ class Function { std::list> execution_model_limitations_; + /// Stores limitations imposed by instructions used within the function. + /// Similar to execution_model_limitations_; + std::list> + limitations_; + /// Stores ids of all functions called from this function. std::set function_call_targets_; }; diff --git a/third_party/spirv-tools/source/val/instruction.h b/third_party/spirv-tools/source/val/instruction.h index 1fa855fca9..617cb0660d 100644 --- a/third_party/spirv-tools/source/val/instruction.h +++ b/third_party/spirv-tools/source/val/instruction.h @@ -21,6 +21,7 @@ #include #include +#include "source/ext_inst.h" #include "source/table.h" #include "spirv-tools/libspirv.h" @@ -85,6 +86,17 @@ class Instruction { return inst_.ext_inst_type; } + bool IsNonSemantic() const { + return opcode() == SpvOp::SpvOpExtInst && + spvExtInstIsNonSemantic(inst_.ext_inst_type); + } + + /// True if this is an OpExtInst for debug info extension. + bool IsDebugInfo() const { + return opcode() == SpvOp::SpvOpExtInst && + spvExtInstIsDebugInfo(inst_.ext_inst_type); + } + // Casts the words belonging to the operand under |index| to |T| and returns. template T GetOperandAs(size_t index) const { diff --git a/third_party/spirv-tools/source/val/validate.cpp b/third_party/spirv-tools/source/val/validate.cpp index 47e572b421..7f4b0dce46 100644 --- a/third_party/spirv-tools/source/val/validate.cpp +++ b/third_party/spirv-tools/source/val/validate.cpp @@ -14,10 +14,9 @@ #include "source/val/validate.h" +#include #include #include - -#include #include #include #include @@ -42,35 +41,16 @@ #include "source/val/validation_state.h" #include "spirv-tools/libspirv.h" +namespace { +// TODO(issue 1950): The validator only returns a single message anyway, so no +// point in generating more than 1 warning. +static uint32_t kDefaultMaxNumOfWarnings = 1; +} // namespace + namespace spvtools { namespace val { namespace { -spv_result_t spvValidateIDs(const spv_instruction_t* pInsts, - const uint64_t count, - const ValidationState_t& state, - spv_position position) { - position->index = SPV_INDEX_INSTRUCTION; - if (auto error = spvValidateInstructionIDs(pInsts, count, state, position)) - return error; - return SPV_SUCCESS; -} - -// TODO(umar): Validate header -// TODO(umar): The binary parser validates the magic word, and the length of the -// header, but nothing else. -spv_result_t setHeader(void* user_data, spv_endianness_t, uint32_t, - uint32_t version, uint32_t generator, uint32_t id_bound, - uint32_t) { - // Record the ID bound so that the validator can ensure no ID is out of bound. - ValidationState_t& _ = *(reinterpret_cast(user_data)); - _.setIdBound(id_bound); - _.setGenerator(generator); - _.setVersion(version); - - return SPV_SUCCESS; -} - // Parses OpExtension instruction and registers extension. void RegisterExtension(ValidationState_t& _, const spv_parsed_instruction_t* inst) { @@ -114,48 +94,6 @@ spv_result_t ProcessInstruction(void* user_data, return SPV_SUCCESS; } -void printDot(const ValidationState_t& _, const BasicBlock& other) { - std::string block_string; - if (other.successors()->empty()) { - block_string += "end "; - } else { - for (auto block : *other.successors()) { - block_string += _.getIdOrName(block->id()) + " "; - } - } - printf("%10s -> {%s\b}\n", _.getIdOrName(other.id()).c_str(), - block_string.c_str()); -} - -void PrintBlocks(ValidationState_t& _, Function func) { - assert(func.first_block()); - - printf("%10s -> %s\n", _.getIdOrName(func.id()).c_str(), - _.getIdOrName(func.first_block()->id()).c_str()); - for (const auto& block : func.ordered_blocks()) { - printDot(_, *block); - } -} - -#ifdef __clang__ -#define UNUSED(func) [[gnu::unused]] func -#elif defined(__GNUC__) -#define UNUSED(func) \ - func __attribute__((unused)); \ - func -#elif defined(_MSC_VER) -#define UNUSED(func) func -#endif - -UNUSED(void PrintDotGraph(ValidationState_t& _, Function func)) { - if (func.first_block()) { - std::string func_name(_.getIdOrName(func.id())); - printf("digraph %s {\n", func_name.c_str()); - PrintBlocks(_, func); - printf("}\n"); - } -} - spv_result_t ValidateForwardDecls(ValidationState_t& _) { if (_.unresolved_forward_id_count() == 0) return SPV_SUCCESS; @@ -173,20 +111,76 @@ spv_result_t ValidateForwardDecls(ValidationState_t& _) { << id_str.substr(0, id_str.size() - 1); } +std::vector CalculateNamesForEntryPoint(ValidationState_t& _, + const uint32_t id) { + auto id_descriptions = _.entry_point_descriptions(id); + auto id_names = std::vector(); + id_names.reserve((id_descriptions.size())); + + for (auto description : id_descriptions) id_names.push_back(description.name); + + return id_names; +} + +spv_result_t ValidateEntryPointNameUnique(ValidationState_t& _, + const uint32_t id) { + auto id_names = CalculateNamesForEntryPoint(_, id); + const auto names = + std::unordered_set(id_names.begin(), id_names.end()); + + if (id_names.size() != names.size()) { + std::sort(id_names.begin(), id_names.end()); + for (size_t i = 0; i < id_names.size() - 1; i++) { + if (id_names[i] == id_names[i + 1]) { + return _.diag(SPV_ERROR_INVALID_BINARY, _.FindDef(id)) + << "Entry point name \"" << id_names[i] + << "\" is not unique, which is not allow in WebGPU env."; + } + } + } + + for (const auto other_id : _.entry_points()) { + if (other_id == id) continue; + const auto other_id_names = CalculateNamesForEntryPoint(_, other_id); + for (const auto other_id_name : other_id_names) { + if (names.find(other_id_name) != names.end()) { + return _.diag(SPV_ERROR_INVALID_BINARY, _.FindDef(id)) + << "Entry point name \"" << other_id_name + << "\" is not unique, which is not allow in WebGPU env."; + } + } + } + + return SPV_SUCCESS; +} + +spv_result_t ValidateEntryPointNamesUnique(ValidationState_t& _) { + for (const auto id : _.entry_points()) { + auto result = ValidateEntryPointNameUnique(_, id); + if (result != SPV_SUCCESS) return result; + } + return SPV_SUCCESS; +} + // Entry point validation. Based on 2.16.1 (Universal Validation Rules) of the // SPIRV spec: // * There is at least one OpEntryPoint instruction, unless the Linkage // capability is being used. // * No function can be targeted by both an OpEntryPoint instruction and an // OpFunctionCall instruction. +// +// Additionally enforces that entry points for Vulkan and WebGPU should not have +// recursion. And that entry names should be unique for WebGPU. spv_result_t ValidateEntryPoints(ValidationState_t& _) { _.ComputeFunctionToEntryPointMapping(); + _.ComputeRecursiveEntryPoints(); if (_.entry_points().empty() && !_.HasCapability(SpvCapabilityLinkage)) { return _.diag(SPV_ERROR_INVALID_BINARY, nullptr) << "No OpEntryPoint instruction was found. This is only allowed if " "the Linkage capability is being used."; } + for (const auto& entry_point : _.entry_points()) { if (_.IsFunctionCallTarget(entry_point)) { return _.diag(SPV_ERROR_INVALID_BINARY, _.FindDef(entry_point)) @@ -194,6 +188,22 @@ spv_result_t ValidateEntryPoints(ValidationState_t& _) { << ") may not be targeted by both an OpEntryPoint instruction and " "an OpFunctionCall instruction."; } + + // For Vulkan and WebGPU, the static function-call graph for an entry point + // must not contain cycles. + if (spvIsVulkanOrWebGPUEnv(_.context()->target_env)) { + if (_.recursive_entry_points().find(entry_point) != + _.recursive_entry_points().end()) { + return _.diag(SPV_ERROR_INVALID_BINARY, _.FindDef(entry_point)) + << "Entry points may not have a call graph with cycles."; + } + } + + // For WebGPU all entry point names must be unique. + if (spvIsWebGPUEnv(_.context()->target_env)) { + const auto result = ValidateEntryPointNamesUnique(_); + if (result != SPV_SUCCESS) return result; + } } return SPV_SUCCESS; @@ -213,6 +223,12 @@ spv_result_t ValidateBinaryUsingContextAndValidationState( << "Invalid SPIR-V magic number."; } + if (spvIsWebGPUEnv(context.target_env) && endian != SPV_ENDIANNESS_LITTLE) { + return DiagnosticStream(position, context.consumer, "", + SPV_ERROR_INVALID_BINARY) + << "WebGPU requires SPIR-V to be little endian."; + } + spv_header_t header; if (spvBinaryHeaderGet(binary.get(), endian, &header)) { return DiagnosticStream(position, context.consumer, "", @@ -230,18 +246,33 @@ spv_result_t ValidateBinaryUsingContextAndValidationState( << spvTargetEnvDescription(context.target_env) << "."; } + if (header.bound > vstate->options()->universal_limits_.max_id_bound) { + return DiagnosticStream(position, context.consumer, "", + SPV_ERROR_INVALID_BINARY) + << "Invalid SPIR-V. The id bound is larger than the max id bound " + << vstate->options()->universal_limits_.max_id_bound << "."; + } + // Look for OpExtension instructions and register extensions. - spvBinaryParse(&context, vstate, words, num_words, + // This parse should not produce any error messages. Hijack the context and + // replace the message consumer so that we do not pollute any state in input + // consumer. + spv_context_t hijacked_context = context; + hijacked_context.consumer = [](spv_message_level_t, const char*, + const spv_position_t&, const char*) {}; + spvBinaryParse(&hijacked_context, vstate, words, num_words, /* parsed_header = */ nullptr, ProcessExtensions, /* diagnostic = */ nullptr); // Parse the module and perform inline validation checks. These checks do // not require the the knowledge of the whole module. - if (auto error = spvBinaryParse(&context, vstate, words, num_words, setHeader, + if (auto error = spvBinaryParse(&context, vstate, words, num_words, + /*parsed_header =*/nullptr, ProcessInstruction, pDiagnostic)) { return error; } + std::vector visited_entry_points; for (auto& instruction : vstate->ordered_instructions()) { { // In order to do this work outside of Process Instruction we need to be @@ -263,6 +294,24 @@ spv_result_t ValidateBinaryUsingContextAndValidationState( vstate->RegisterEntryPoint(entry_point, execution_model, std::move(desc)); + + if (visited_entry_points.size() > 0) { + for (const Instruction* check_inst : visited_entry_points) { + const auto check_execution_model = + check_inst->GetOperandAs(0); + const char* check_str = reinterpret_cast( + check_inst->words().data() + inst->operand(2).offset); + const std::string check_name(check_str); + + if (desc.name == check_name && + execution_model == check_execution_model) { + return vstate->diag(SPV_ERROR_INVALID_DATA, inst) + << "2 Entry points cannot share the same name and " + "ExecutionMode."; + } + } + } + visited_entry_points.push_back(inst); } if (inst->opcode() == SpvOpFunctionCall) { if (!vstate->in_function_body()) { @@ -270,7 +319,15 @@ spv_result_t ValidateBinaryUsingContextAndValidationState( << "A FunctionCall must happen within a function body."; } - vstate->AddFunctionCallTarget(inst->GetOperandAs(2)); + const auto called_id = inst->GetOperandAs(2); + if (spvIsWebGPUEnv(context.target_env) && + !vstate->IsFunctionCallDefined(called_id)) { + return vstate->diag(SPV_ERROR_INVALID_LAYOUT, &instruction) + << "For WebGPU, functions need to be defined before being " + "called."; + } + + vstate->AddFunctionCallTarget(called_id); } if (vstate->in_function_body()) { @@ -286,7 +343,6 @@ spv_result_t ValidateBinaryUsingContextAndValidationState( } if (auto error = CapabilityPass(*vstate, &instruction)) return error; - if (auto error = DataRulesPass(*vstate, &instruction)) return error; if (auto error = ModuleLayoutPass(*vstate, &instruction)) return error; if (auto error = CfgPass(*vstate, &instruction)) return error; if (auto error = InstructionPass(*vstate, &instruction)) return error; @@ -295,8 +351,10 @@ spv_result_t ValidateBinaryUsingContextAndValidationState( { Instruction* inst = const_cast(&instruction); vstate->RegisterInstruction(inst); + if (inst->opcode() == SpvOpTypeForwardPointer) { + vstate->RegisterForwardPointer(inst->GetOperandAs(0)); + } } - if (auto error = UpdateIdUse(*vstate, &instruction)) return error; } if (!vstate->has_memory_model_specified()) @@ -310,21 +368,33 @@ spv_result_t ValidateBinaryUsingContextAndValidationState( // Catch undefined forward references before performing further checks. if (auto error = ValidateForwardDecls(*vstate)) return error; + // ID usage needs be handled in its own iteration of the instructions, + // between the two others. It depends on the first loop to have been + // finished, so that all instructions have been registered. And the following + // loop depends on all of the usage data being populated. Thus it cannot live + // in either of those iterations. + // It should also live after the forward declaration check, since it will + // have problems with missing forward declarations, but give less useful error + // messages. + for (size_t i = 0; i < vstate->ordered_instructions().size(); ++i) { + auto& instruction = vstate->ordered_instructions()[i]; + if (auto error = UpdateIdUse(*vstate, &instruction)) return error; + } + // Validate individual opcodes. for (size_t i = 0; i < vstate->ordered_instructions().size(); ++i) { auto& instruction = vstate->ordered_instructions()[i]; // Keep these passes in the order they appear in the SPIR-V specification // sections to maintain test consistency. - // Miscellaneous + if (auto error = MiscPass(*vstate, &instruction)) return error; if (auto error = DebugPass(*vstate, &instruction)) return error; if (auto error = AnnotationPass(*vstate, &instruction)) return error; - if (auto error = ExtInstPass(*vstate, &instruction)) return error; + if (auto error = ExtensionPass(*vstate, &instruction)) return error; if (auto error = ModeSettingPass(*vstate, &instruction)) return error; if (auto error = TypePass(*vstate, &instruction)) return error; if (auto error = ConstantPass(*vstate, &instruction)) return error; - if (auto error = ValidateMemoryInstructions(*vstate, &instruction)) - return error; + if (auto error = MemoryPass(*vstate, &instruction)) return error; if (auto error = FunctionPass(*vstate, &instruction)) return error; if (auto error = ImagePass(*vstate, &instruction)) return error; if (auto error = ConversionPass(*vstate, &instruction)) return error; @@ -343,11 +413,12 @@ spv_result_t ValidateBinaryUsingContextAndValidationState( if (auto error = NonUniformPass(*vstate, &instruction)) return error; if (auto error = LiteralsPass(*vstate, &instruction)) return error; - // Validate the preconditions involving adjacent instructions. e.g. SpvOpPhi - // must only be preceeded by SpvOpLabel, SpvOpPhi, or SpvOpLine. - if (auto error = ValidateAdjacency(*vstate, i)) return error; } + // Validate the preconditions involving adjacent instructions. e.g. SpvOpPhi + // must only be preceeded by SpvOpLabel, SpvOpPhi, or SpvOpLine. + if (auto error = ValidateAdjacency(*vstate)) return error; + if (auto error = ValidateEntryPoints(*vstate)) return error; // CFG checks are performed after the binary has been parsed // and the CFGPass has collected information about the control flow @@ -362,30 +433,9 @@ spv_result_t ValidateBinaryUsingContextAndValidationState( // those checks register the limitation checked here. for (const auto inst : vstate->ordered_instructions()) { if (auto error = ValidateExecutionLimitations(*vstate, &inst)) return error; + if (auto error = ValidateSmallTypeUses(*vstate, &inst)) return error; } - // NOTE: Copy each instruction for easier processing - std::vector instructions; - // Expect average instruction length to be a bit over 2 words. - instructions.reserve(binary->wordCount / 2); - uint64_t index = SPV_INDEX_INSTRUCTION; - while (index < binary->wordCount) { - uint16_t wordCount; - uint16_t opcode; - spvOpcodeSplit(spvFixWord(binary->code[index], endian), &wordCount, - &opcode); - spv_instruction_t inst; - spvInstructionCopy(&binary->code[index], static_cast(opcode), - wordCount, endian, &inst); - instructions.emplace_back(std::move(inst)); - index += wordCount; - } - - position.index = SPV_INDEX_INSTRUCTION; - if (auto error = spvValidateIDs(instructions.data(), instructions.size(), - *vstate, &position)) - return error; - return SPV_SUCCESS; } @@ -401,8 +451,8 @@ spv_result_t ValidateBinaryAndKeepValidationState( UseDiagnosticAsMessageConsumer(&hijack_context, pDiagnostic); } - vstate->reset( - new ValidationState_t(&hijack_context, options, words, num_words)); + vstate->reset(new ValidationState_t(&hijack_context, options, words, + num_words, kDefaultMaxNumOfWarnings)); return ValidateBinaryUsingContextAndValidationState( hijack_context, words, num_words, pDiagnostic, vstate->get()); @@ -432,7 +482,8 @@ spv_result_t spvValidateBinary(const spv_const_context context, // Create the ValidationState using the context and default options. spvtools::val::ValidationState_t vstate(&hijack_context, default_options, - words, num_words); + words, num_words, + kDefaultMaxNumOfWarnings); spv_result_t result = spvtools::val::ValidateBinaryUsingContextAndValidationState( @@ -454,7 +505,8 @@ spv_result_t spvValidateWithOptions(const spv_const_context context, // Create the ValidationState using the context. spvtools::val::ValidationState_t vstate(&hijack_context, options, - binary->code, binary->wordCount); + binary->code, binary->wordCount, + kDefaultMaxNumOfWarnings); return spvtools::val::ValidateBinaryUsingContextAndValidationState( hijack_context, binary->code, binary->wordCount, pDiagnostic, &vstate); diff --git a/third_party/spirv-tools/source/val/validate.h b/third_party/spirv-tools/source/val/validate.h index 01281180b8..31a775bb3c 100644 --- a/third_party/spirv-tools/source/val/validate.h +++ b/third_party/spirv-tools/source/val/validate.h @@ -63,7 +63,7 @@ spv_result_t UpdateIdUse(ValidationState_t& _, const Instruction* inst); /// @param[in] _ the validation state of the module /// /// @return SPV_SUCCESS if no errors are found. SPV_ERROR_INVALID_ID otherwise -spv_result_t CheckIdDefinitionDominateUse(const ValidationState_t& _); +spv_result_t CheckIdDefinitionDominateUse(ValidationState_t& _); /// @brief This function checks for preconditions involving the adjacent /// instructions. @@ -75,7 +75,7 @@ spv_result_t CheckIdDefinitionDominateUse(const ValidationState_t& _); /// @param[in] _ the validation state of the module /// /// @return SPV_SUCCESS if no errors are found. SPV_ERROR_INVALID_DATA otherwise -spv_result_t ValidateAdjacency(ValidationState_t& _, size_t idx); +spv_result_t ValidateAdjacency(ValidationState_t& _); /// @brief Validates static uses of input and output variables /// @@ -91,8 +91,7 @@ spv_result_t ValidateInterfaces(ValidationState_t& _); /// /// @param[in] _ the validation state of the module /// @return SPV_SUCCESS if no errors are found. -spv_result_t ValidateMemoryInstructions(ValidationState_t& _, - const Instruction* inst); +spv_result_t MemoryPass(ValidationState_t& _, const Instruction* inst); /// @brief Updates the immediate dominator for each of the block edges /// @@ -124,19 +123,15 @@ spv_result_t ControlFlowPass(ValidationState_t& _, const Instruction* inst); /// Performs Id and SSA validation of a module spv_result_t IdPass(ValidationState_t& _, Instruction* inst); -/// Performs validation of the Data Rules subsection of 2.16.1 Universal -/// Validation Rules. -/// TODO(ehsann): add more comments here as more validation code is added. -spv_result_t DataRulesPass(ValidationState_t& _, const Instruction* inst); - /// Performs instruction validation. spv_result_t InstructionPass(ValidationState_t& _, const Instruction* inst); -/// Performs decoration validation. +/// Performs decoration validation. Assumes each decoration on a group +/// has been propagated down to the group members. spv_result_t ValidateDecorations(ValidationState_t& _); /// Performs validation of built-in variables. -spv_result_t ValidateBuiltIns(const ValidationState_t& _); +spv_result_t ValidateBuiltIns(ValidationState_t& _); /// Validates type instructions. spv_result_t TypePass(ValidationState_t& _, const Instruction* inst); @@ -174,8 +169,8 @@ spv_result_t BarriersPass(ValidationState_t& _, const Instruction* inst); /// Validates correctness of literal numbers. spv_result_t LiteralsPass(ValidationState_t& _, const Instruction* inst); -/// Validates correctness of ExtInst instructions. -spv_result_t ExtInstPass(ValidationState_t& _, const Instruction* inst); +/// Validates correctness of extension instructions. +spv_result_t ExtensionPass(ValidationState_t& _, const Instruction* inst); /// Validates correctness of annotation instructions. spv_result_t AnnotationPass(ValidationState_t& _, const Instruction* inst); @@ -199,24 +194,21 @@ spv_result_t ModeSettingPass(ValidationState_t& _, const Instruction* inst); /// Validates correctness of function instructions. spv_result_t FunctionPass(ValidationState_t& _, const Instruction* inst); +/// Validates correctness of miscellaneous instructions. +spv_result_t MiscPass(ValidationState_t& _, const Instruction* inst); + /// Validates execution limitations. /// /// Verifies execution models are allowed for all functionality they contain. spv_result_t ValidateExecutionLimitations(ValidationState_t& _, const Instruction* inst); -/// @brief Validate the ID usage of the instruction stream +/// Validates restricted uses of 8- and 16-bit types. /// -/// @param[in] pInsts stream of instructions -/// @param[in] instCount number of instructions -/// @param[in] usedefs use-def info from module parsing -/// @param[in,out] position current position in the stream -/// -/// @return result code -spv_result_t spvValidateInstructionIDs(const spv_instruction_t* pInsts, - const uint64_t instCount, - const ValidationState_t& state, - spv_position position); +/// Validates shaders that uses 8- or 16-bit storage capabilities, but not full +/// capabilities only have appropriate uses of those types. +spv_result_t ValidateSmallTypeUses(ValidationState_t& _, + const Instruction* inst); /// @brief Validate the ID's within a SPIR-V binary /// diff --git a/third_party/spirv-tools/source/val/validate_adjacency.cpp b/third_party/spirv-tools/source/val/validate_adjacency.cpp index 5ef56be991..64655b0dc7 100644 --- a/third_party/spirv-tools/source/val/validate_adjacency.cpp +++ b/third_party/spirv-tools/source/val/validate_adjacency.cpp @@ -27,56 +27,98 @@ namespace spvtools { namespace val { -spv_result_t ValidateAdjacency(ValidationState_t& _, size_t idx) { - const auto& instructions = _.ordered_instructions(); - const auto& inst = instructions[idx]; +enum { + // Status right after meeting OpFunction. + IN_NEW_FUNCTION, + // Status right after meeting the entry block. + IN_ENTRY_BLOCK, + // Status right after meeting non-entry blocks. + PHI_VALID, + // Status right after meeting non-OpVariable instructions in the entry block + // or non-OpPhi instructions in non-entry blocks, except OpLine. + PHI_AND_VAR_INVALID, +}; - switch (inst.opcode()) { - case SpvOpPhi: - if (idx > 0) { - switch (instructions[idx - 1].opcode()) { - case SpvOpLabel: - case SpvOpPhi: - case SpvOpLine: - break; - default: - return _.diag(SPV_ERROR_INVALID_DATA, &inst) - << "OpPhi must appear before all non-OpPhi instructions " - << "(except for OpLine, which can be mixed with OpPhi)."; +spv_result_t ValidateAdjacency(ValidationState_t& _) { + const auto& instructions = _.ordered_instructions(); + int adjacency_status = PHI_AND_VAR_INVALID; + + for (size_t i = 0; i < instructions.size(); ++i) { + const auto& inst = instructions[i]; + switch (inst.opcode()) { + case SpvOpFunction: + case SpvOpFunctionParameter: + adjacency_status = IN_NEW_FUNCTION; + break; + case SpvOpLabel: + adjacency_status = + adjacency_status == IN_NEW_FUNCTION ? IN_ENTRY_BLOCK : PHI_VALID; + break; + case SpvOpExtInst: + // If it is a debug info instruction, we do not change the status to + // allow debug info instructions before OpVariable in a function. + // TODO(https://gitlab.khronos.org/spirv/SPIR-V/issues/533): We need + // to discuss the location of DebugScope, DebugNoScope, DebugDeclare, + // and DebugValue. + if (!spvExtInstIsDebugInfo(inst.ext_inst_type())) { + adjacency_status = PHI_AND_VAR_INVALID; } - } - break; - case SpvOpLoopMerge: - if (idx != (instructions.size() - 1)) { - switch (instructions[idx + 1].opcode()) { - case SpvOpBranch: - case SpvOpBranchConditional: - break; - default: - return _.diag(SPV_ERROR_INVALID_DATA, &inst) - << "OpLoopMerge must immediately precede either an " - << "OpBranch or OpBranchConditional instruction. " - << "OpLoopMerge must be the second-to-last instruction in " - << "its block."; + break; + case SpvOpPhi: + if (adjacency_status != PHI_VALID) { + return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << "OpPhi must appear within a non-entry block before all " + << "non-OpPhi instructions " + << "(except for OpLine, which can be mixed with OpPhi)."; } - } - break; - case SpvOpSelectionMerge: - if (idx != (instructions.size() - 1)) { - switch (instructions[idx + 1].opcode()) { - case SpvOpBranchConditional: - case SpvOpSwitch: - break; - default: - return _.diag(SPV_ERROR_INVALID_DATA, &inst) - << "OpSelectionMerge must immediately precede either an " - << "OpBranchConditional or OpSwitch instruction. " - << "OpSelectionMerge must be the second-to-last " - << "instruction in its block."; + break; + case SpvOpLine: + case SpvOpNoLine: + break; + case SpvOpLoopMerge: + adjacency_status = PHI_AND_VAR_INVALID; + if (i != (instructions.size() - 1)) { + switch (instructions[i + 1].opcode()) { + case SpvOpBranch: + case SpvOpBranchConditional: + break; + default: + return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << "OpLoopMerge must immediately precede either an " + << "OpBranch or OpBranchConditional instruction. " + << "OpLoopMerge must be the second-to-last instruction in " + << "its block."; + } } - } - default: - break; + break; + case SpvOpSelectionMerge: + adjacency_status = PHI_AND_VAR_INVALID; + if (i != (instructions.size() - 1)) { + switch (instructions[i + 1].opcode()) { + case SpvOpBranchConditional: + case SpvOpSwitch: + break; + default: + return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << "OpSelectionMerge must immediately precede either an " + << "OpBranchConditional or OpSwitch instruction. " + << "OpSelectionMerge must be the second-to-last " + << "instruction in its block."; + } + } + break; + case SpvOpVariable: + if (inst.GetOperandAs(2) == SpvStorageClassFunction && + adjacency_status != IN_ENTRY_BLOCK) { + return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << "All OpVariable instructions in a function must be the " + "first instructions in the first block."; + } + break; + default: + adjacency_status = PHI_AND_VAR_INVALID; + break; + } } return SPV_SUCCESS; diff --git a/third_party/spirv-tools/source/val/validate_annotation.cpp b/third_party/spirv-tools/source/val/validate_annotation.cpp index f1758391d8..df38f1b163 100644 --- a/third_party/spirv-tools/source/val/validate_annotation.cpp +++ b/third_party/spirv-tools/source/val/validate_annotation.cpp @@ -12,16 +12,193 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "source/val/validate.h" - #include "source/opcode.h" +#include "source/spirv_target_env.h" #include "source/val/instruction.h" +#include "source/val/validate.h" #include "source/val/validation_state.h" namespace spvtools { namespace val { namespace { +bool IsValidWebGPUDecoration(uint32_t decoration) { + switch (decoration) { + case SpvDecorationSpecId: + case SpvDecorationBlock: + case SpvDecorationRowMajor: + case SpvDecorationColMajor: + case SpvDecorationArrayStride: + case SpvDecorationMatrixStride: + case SpvDecorationBuiltIn: + case SpvDecorationNoPerspective: + case SpvDecorationFlat: + case SpvDecorationCentroid: + case SpvDecorationRestrict: + case SpvDecorationAliased: + case SpvDecorationNonWritable: + case SpvDecorationNonReadable: + case SpvDecorationUniform: + case SpvDecorationLocation: + case SpvDecorationComponent: + case SpvDecorationIndex: + case SpvDecorationBinding: + case SpvDecorationDescriptorSet: + case SpvDecorationOffset: + case SpvDecorationNoContraction: + return true; + default: + return false; + } +} + +std::string LogStringForDecoration(uint32_t decoration) { + switch (decoration) { + case SpvDecorationRelaxedPrecision: + return "RelaxedPrecision"; + case SpvDecorationSpecId: + return "SpecId"; + case SpvDecorationBlock: + return "Block"; + case SpvDecorationBufferBlock: + return "BufferBlock"; + case SpvDecorationRowMajor: + return "RowMajor"; + case SpvDecorationColMajor: + return "ColMajor"; + case SpvDecorationArrayStride: + return "ArrayStride"; + case SpvDecorationMatrixStride: + return "MatrixStride"; + case SpvDecorationGLSLShared: + return "GLSLShared"; + case SpvDecorationGLSLPacked: + return "GLSLPacked"; + case SpvDecorationCPacked: + return "CPacked"; + case SpvDecorationBuiltIn: + return "BuiltIn"; + case SpvDecorationNoPerspective: + return "NoPerspective"; + case SpvDecorationFlat: + return "Flat"; + case SpvDecorationPatch: + return "Patch"; + case SpvDecorationCentroid: + return "Centroid"; + case SpvDecorationSample: + return "Sample"; + case SpvDecorationInvariant: + return "Invariant"; + case SpvDecorationRestrict: + return "Restrict"; + case SpvDecorationAliased: + return "Aliased"; + case SpvDecorationVolatile: + return "Volatile"; + case SpvDecorationConstant: + return "Constant"; + case SpvDecorationCoherent: + return "Coherent"; + case SpvDecorationNonWritable: + return "NonWritable"; + case SpvDecorationNonReadable: + return "NonReadable"; + case SpvDecorationUniform: + return "Uniform"; + case SpvDecorationSaturatedConversion: + return "SaturatedConversion"; + case SpvDecorationStream: + return "Stream"; + case SpvDecorationLocation: + return "Location"; + case SpvDecorationComponent: + return "Component"; + case SpvDecorationIndex: + return "Index"; + case SpvDecorationBinding: + return "Binding"; + case SpvDecorationDescriptorSet: + return "DescriptorSet"; + case SpvDecorationOffset: + return "Offset"; + case SpvDecorationXfbBuffer: + return "XfbBuffer"; + case SpvDecorationXfbStride: + return "XfbStride"; + case SpvDecorationFuncParamAttr: + return "FuncParamAttr"; + case SpvDecorationFPRoundingMode: + return "FPRoundingMode"; + case SpvDecorationFPFastMathMode: + return "FPFastMathMode"; + case SpvDecorationLinkageAttributes: + return "LinkageAttributes"; + case SpvDecorationNoContraction: + return "NoContraction"; + case SpvDecorationInputAttachmentIndex: + return "InputAttachmentIndex"; + case SpvDecorationAlignment: + return "Alignment"; + case SpvDecorationMaxByteOffset: + return "MaxByteOffset"; + case SpvDecorationAlignmentId: + return "AlignmentId"; + case SpvDecorationMaxByteOffsetId: + return "MaxByteOffsetId"; + case SpvDecorationNoSignedWrap: + return "NoSignedWrap"; + case SpvDecorationNoUnsignedWrap: + return "NoUnsignedWrap"; + case SpvDecorationExplicitInterpAMD: + return "ExplicitInterpAMD"; + case SpvDecorationOverrideCoverageNV: + return "OverrideCoverageNV"; + case SpvDecorationPassthroughNV: + return "PassthroughNV"; + case SpvDecorationViewportRelativeNV: + return "ViewportRelativeNV"; + case SpvDecorationSecondaryViewportRelativeNV: + return "SecondaryViewportRelativeNV"; + case SpvDecorationPerPrimitiveNV: + return "PerPrimitiveNV"; + case SpvDecorationPerViewNV: + return "PerViewNV"; + case SpvDecorationPerTaskNV: + return "PerTaskNV"; + case SpvDecorationPerVertexNV: + return "PerVertexNV"; + case SpvDecorationNonUniformEXT: + return "NonUniformEXT"; + case SpvDecorationRestrictPointerEXT: + return "RestrictPointerEXT"; + case SpvDecorationAliasedPointerEXT: + return "AliasedPointerEXT"; + case SpvDecorationHlslCounterBufferGOOGLE: + return "HlslCounterBufferGOOGLE"; + case SpvDecorationHlslSemanticGOOGLE: + return "HlslSemanticGOOGLE"; + default: + break; + } + return "Unknown"; +} + +// Returns true if the decoration takes ID parameters. +// TODO(dneto): This can be generated from the grammar. +bool DecorationTakesIdParameters(uint32_t type) { + switch (static_cast(type)) { + case SpvDecorationUniformId: + case SpvDecorationAlignmentId: + case SpvDecorationMaxByteOffsetId: + case SpvDecorationHlslCounterBufferGOOGLE: + return true; + default: + break; + } + return false; +} + spv_result_t ValidateDecorate(ValidationState_t& _, const Instruction* inst) { const auto decoration = inst->GetOperandAs(1); if (decoration == SpvDecorationSpecId) { @@ -30,14 +207,39 @@ spv_result_t ValidateDecorate(ValidationState_t& _, const Instruction* inst) { if (!target || !spvOpcodeIsScalarSpecConstant(target->opcode())) { return _.diag(SPV_ERROR_INVALID_ID, inst) << "OpDecorate SpecId decoration target '" - << _.getIdName(decoration) + << _.getIdName(target_id) << "' is not a scalar specialization constant."; } } + + if (spvIsWebGPUEnv(_.context()->target_env) && + !IsValidWebGPUDecoration(decoration)) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "OpDecorate decoration '" << LogStringForDecoration(decoration) + << "' is not valid for the WebGPU execution environment."; + } + + if (DecorationTakesIdParameters(decoration)) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Decorations taking ID parameters may not be used with " + "OpDecorateId"; + } // TODO: Add validations for all decorations. return SPV_SUCCESS; } +spv_result_t ValidateDecorateId(ValidationState_t& _, const Instruction* inst) { + const auto decoration = inst->GetOperandAs(1); + if (!DecorationTakesIdParameters(decoration)) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Decorations that don't take ID parameters may not be used with " + "OpDecorateId"; + } + // TODO: Add validations for these decorations. + // UniformId is covered elsewhere. + return SPV_SUCCESS; +} + spv_result_t ValidateMemberDecorate(ValidationState_t& _, const Instruction* inst) { const auto struct_type_id = inst->GetOperandAs(0); @@ -50,7 +252,7 @@ spv_result_t ValidateMemberDecorate(ValidationState_t& _, const auto member = inst->GetOperandAs(1); const auto member_count = static_cast(struct_type->words().size() - 2); - if (member_count < member) { + if (member_count <= member) { return _.diag(SPV_ERROR_INVALID_ID, inst) << "Index " << member << " provided in OpMemberDecorate for struct " @@ -58,22 +260,38 @@ spv_result_t ValidateMemberDecorate(ValidationState_t& _, << " is out of bounds. The structure has " << member_count << " members. Largest valid index is " << member_count - 1 << "."; } + + const auto decoration = inst->GetOperandAs(2); + if (spvIsWebGPUEnv(_.context()->target_env) && + !IsValidWebGPUDecoration(decoration)) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "OpMemberDecorate decoration '" << _.getIdName(decoration) + << "' is not valid for the WebGPU execution environment."; + } + return SPV_SUCCESS; } spv_result_t ValidateDecorationGroup(ValidationState_t& _, const Instruction* inst) { + if (spvIsWebGPUEnv(_.context()->target_env)) { + return _.diag(SPV_ERROR_INVALID_BINARY, inst) + << "OpDecorationGroup is not allowed in the WebGPU execution " + << "environment."; + } + const auto decoration_group_id = inst->GetOperandAs(0); const auto decoration_group = _.FindDef(decoration_group_id); for (auto pair : decoration_group->uses()) { auto use = pair.first; if (use->opcode() != SpvOpDecorate && use->opcode() != SpvOpGroupDecorate && use->opcode() != SpvOpGroupMemberDecorate && - use->opcode() != SpvOpName) { + use->opcode() != SpvOpName && use->opcode() != SpvOpDecorateId && + !use->IsNonSemantic()) { return _.diag(SPV_ERROR_INVALID_ID, inst) << "Result id of OpDecorationGroup can only " << "be targeted by OpName, OpGroupDecorate, " - << "OpDecorate, and OpGroupMemberDecorate"; + << "OpDecorate, OpDecorateId, and OpGroupMemberDecorate"; } } return SPV_SUCCESS; @@ -81,6 +299,12 @@ spv_result_t ValidateDecorationGroup(ValidationState_t& _, spv_result_t ValidateGroupDecorate(ValidationState_t& _, const Instruction* inst) { + if (spvIsWebGPUEnv(_.context()->target_env)) { + return _.diag(SPV_ERROR_INVALID_BINARY, inst) + << "OpGroupDecorate is not allowed in the WebGPU execution " + << "environment."; + } + const auto decoration_group_id = inst->GetOperandAs(0); auto decoration_group = _.FindDef(decoration_group_id); if (!decoration_group || SpvOpDecorationGroup != decoration_group->opcode()) { @@ -89,11 +313,26 @@ spv_result_t ValidateGroupDecorate(ValidationState_t& _, << _.getIdName(decoration_group_id) << "' is not a decoration group."; } + for (unsigned i = 1; i < inst->operands().size(); ++i) { + auto target_id = inst->GetOperandAs(i); + auto target = _.FindDef(target_id); + if (!target || target->opcode() == SpvOpDecorationGroup) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "OpGroupDecorate may not target OpDecorationGroup '" + << _.getIdName(target_id) << "'"; + } + } return SPV_SUCCESS; } spv_result_t ValidateGroupMemberDecorate(ValidationState_t& _, const Instruction* inst) { + if (spvIsWebGPUEnv(_.context()->target_env)) { + return _.diag(SPV_ERROR_INVALID_BINARY, inst) + << "OpGroupMemberDecorate is not allowed in the WebGPU execution " + << "environment."; + } + const auto decoration_group_id = inst->GetOperandAs(0); const auto decoration_group = _.FindDef(decoration_group_id); if (!decoration_group || SpvOpDecorationGroup != decoration_group->opcode()) { @@ -128,6 +367,80 @@ spv_result_t ValidateGroupMemberDecorate(ValidationState_t& _, return SPV_SUCCESS; } +// Registers necessary decoration(s) for the appropriate IDs based on the +// instruction. +spv_result_t RegisterDecorations(ValidationState_t& _, + const Instruction* inst) { + switch (inst->opcode()) { + case SpvOpDecorate: + case SpvOpDecorateId: { + const uint32_t target_id = inst->word(1); + const SpvDecoration dec_type = static_cast(inst->word(2)); + std::vector dec_params; + if (inst->words().size() > 3) { + dec_params.insert(dec_params.end(), inst->words().begin() + 3, + inst->words().end()); + } + _.RegisterDecorationForId(target_id, Decoration(dec_type, dec_params)); + break; + } + case SpvOpMemberDecorate: { + const uint32_t struct_id = inst->word(1); + const uint32_t index = inst->word(2); + const SpvDecoration dec_type = static_cast(inst->word(3)); + std::vector dec_params; + if (inst->words().size() > 4) { + dec_params.insert(dec_params.end(), inst->words().begin() + 4, + inst->words().end()); + } + _.RegisterDecorationForId(struct_id, + Decoration(dec_type, dec_params, index)); + break; + } + case SpvOpDecorationGroup: { + // We don't need to do anything right now. Assigning decorations to groups + // will be taken care of via OpGroupDecorate. + break; + } + case SpvOpGroupDecorate: { + // Word 1 is the group . All subsequent words are target s that + // are going to be decorated with the decorations. + const uint32_t decoration_group_id = inst->word(1); + std::vector& group_decorations = + _.id_decorations(decoration_group_id); + for (size_t i = 2; i < inst->words().size(); ++i) { + const uint32_t target_id = inst->word(i); + _.RegisterDecorationsForId(target_id, group_decorations.begin(), + group_decorations.end()); + } + break; + } + case SpvOpGroupMemberDecorate: { + // Word 1 is the Decoration Group followed by (struct,literal) + // pairs. All decorations of the group should be applied to all the struct + // members that are specified in the instructions. + const uint32_t decoration_group_id = inst->word(1); + std::vector& group_decorations = + _.id_decorations(decoration_group_id); + // Grammar checks ensures that the number of arguments to this instruction + // is an odd number: 1 decoration group + (id,literal) pairs. + for (size_t i = 2; i + 1 < inst->words().size(); i = i + 2) { + const uint32_t struct_id = inst->word(i); + const uint32_t index = inst->word(i + 1); + // ID validation phase ensures this is in fact a struct instruction and + // that the index is not out of bound. + _.RegisterDecorationsForStructMember(struct_id, index, + group_decorations.begin(), + group_decorations.end()); + } + break; + } + default: + break; + } + return SPV_SUCCESS; +} + } // namespace spv_result_t AnnotationPass(ValidationState_t& _, const Instruction* inst) { @@ -135,6 +448,11 @@ spv_result_t AnnotationPass(ValidationState_t& _, const Instruction* inst) { case SpvOpDecorate: if (auto error = ValidateDecorate(_, inst)) return error; break; + case SpvOpDecorateId: + if (auto error = ValidateDecorateId(_, inst)) return error; + break; + // TODO(dneto): SpvOpDecorateStringGOOGLE + // See https://github.com/KhronosGroup/SPIRV-Tools/issues/2253 case SpvOpMemberDecorate: if (auto error = ValidateMemberDecorate(_, inst)) return error; break; @@ -151,6 +469,10 @@ spv_result_t AnnotationPass(ValidationState_t& _, const Instruction* inst) { break; } + // In order to validate decoration rules, we need to know all the decorations + // that are applied to any given . + RegisterDecorations(_, inst); + return SPV_SUCCESS; } diff --git a/third_party/spirv-tools/source/val/validate_arithmetics.cpp b/third_party/spirv-tools/source/val/validate_arithmetics.cpp index 2314e7dfcb..433330d743 100644 --- a/third_party/spirv-tools/source/val/validate_arithmetics.cpp +++ b/third_party/spirv-tools/source/val/validate_arithmetics.cpp @@ -39,8 +39,11 @@ spv_result_t ArithmeticsPass(ValidationState_t& _, const Instruction* inst) { case SpvOpFRem: case SpvOpFMod: case SpvOpFNegate: { + bool supportsCoopMat = + (opcode != SpvOpFMul && opcode != SpvOpFRem && opcode != SpvOpFMod); if (!_.IsFloatScalarType(result_type) && - !_.IsFloatVectorType(result_type)) + !_.IsFloatVectorType(result_type) && + !(supportsCoopMat && _.IsFloatCooperativeMatrixType(result_type))) return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Expected floating scalar or vector type as Result Type: " << spvOpcodeString(opcode); @@ -58,8 +61,11 @@ spv_result_t ArithmeticsPass(ValidationState_t& _, const Instruction* inst) { case SpvOpUDiv: case SpvOpUMod: { + bool supportsCoopMat = (opcode == SpvOpUDiv); if (!_.IsUnsignedIntScalarType(result_type) && - !_.IsUnsignedIntVectorType(result_type)) + !_.IsUnsignedIntVectorType(result_type) && + !(supportsCoopMat && + _.IsUnsignedIntCooperativeMatrixType(result_type))) return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Expected unsigned int scalar or vector type as Result Type: " << spvOpcodeString(opcode); @@ -82,7 +88,10 @@ spv_result_t ArithmeticsPass(ValidationState_t& _, const Instruction* inst) { case SpvOpSMod: case SpvOpSRem: case SpvOpSNegate: { - if (!_.IsIntScalarType(result_type) && !_.IsIntVectorType(result_type)) + bool supportsCoopMat = + (opcode != SpvOpIMul && opcode != SpvOpSRem && opcode != SpvOpSMod); + if (!_.IsIntScalarType(result_type) && !_.IsIntVectorType(result_type) && + !(supportsCoopMat && _.IsIntCooperativeMatrixType(result_type))) return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Expected int scalar or vector type as Result Type: " << spvOpcodeString(opcode); @@ -94,7 +103,8 @@ spv_result_t ArithmeticsPass(ValidationState_t& _, const Instruction* inst) { ++operand_index) { const uint32_t type_id = _.GetOperandTypeId(inst, operand_index); if (!type_id || - (!_.IsIntScalarType(type_id) && !_.IsIntVectorType(type_id))) + (!_.IsIntScalarType(type_id) && !_.IsIntVectorType(type_id) && + !(supportsCoopMat && _.IsIntCooperativeMatrixType(result_type)))) return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Expected int scalar or vector type as operand: " << spvOpcodeString(opcode) << " operand index " @@ -176,7 +186,8 @@ spv_result_t ArithmeticsPass(ValidationState_t& _, const Instruction* inst) { } case SpvOpMatrixTimesScalar: { - if (!_.IsFloatMatrixType(result_type)) + if (!_.IsFloatMatrixType(result_type) && + !_.IsCooperativeMatrixType(result_type)) return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Expected float matrix type as Result Type: " << spvOpcodeString(opcode); @@ -442,6 +453,92 @@ spv_result_t ArithmeticsPass(ValidationState_t& _, const Instruction* inst) { break; } + case SpvOpCooperativeMatrixMulAddNV: { + const uint32_t D_type_id = _.GetOperandTypeId(inst, 1); + const uint32_t A_type_id = _.GetOperandTypeId(inst, 2); + const uint32_t B_type_id = _.GetOperandTypeId(inst, 3); + const uint32_t C_type_id = _.GetOperandTypeId(inst, 4); + + if (!_.IsCooperativeMatrixType(A_type_id)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Expected cooperative matrix type as A Type: " + << spvOpcodeString(opcode); + } + if (!_.IsCooperativeMatrixType(B_type_id)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Expected cooperative matrix type as B Type: " + << spvOpcodeString(opcode); + } + if (!_.IsCooperativeMatrixType(C_type_id)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Expected cooperative matrix type as C Type: " + << spvOpcodeString(opcode); + } + if (!_.IsCooperativeMatrixType(D_type_id)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Expected cooperative matrix type as Result Type: " + << spvOpcodeString(opcode); + } + + const auto A = _.FindDef(A_type_id); + const auto B = _.FindDef(B_type_id); + const auto C = _.FindDef(C_type_id); + const auto D = _.FindDef(D_type_id); + + std::tuple A_scope, B_scope, C_scope, D_scope, + A_rows, B_rows, C_rows, D_rows, A_cols, B_cols, C_cols, D_cols; + + A_scope = _.EvalInt32IfConst(A->GetOperandAs(2)); + B_scope = _.EvalInt32IfConst(B->GetOperandAs(2)); + C_scope = _.EvalInt32IfConst(C->GetOperandAs(2)); + D_scope = _.EvalInt32IfConst(D->GetOperandAs(2)); + + A_rows = _.EvalInt32IfConst(A->GetOperandAs(3)); + B_rows = _.EvalInt32IfConst(B->GetOperandAs(3)); + C_rows = _.EvalInt32IfConst(C->GetOperandAs(3)); + D_rows = _.EvalInt32IfConst(D->GetOperandAs(3)); + + A_cols = _.EvalInt32IfConst(A->GetOperandAs(4)); + B_cols = _.EvalInt32IfConst(B->GetOperandAs(4)); + C_cols = _.EvalInt32IfConst(C->GetOperandAs(4)); + D_cols = _.EvalInt32IfConst(D->GetOperandAs(4)); + + const auto notEqual = [](std::tuple X, + std::tuple Y) { + return (std::get<1>(X) && std::get<1>(Y) && + std::get<2>(X) != std::get<2>(Y)); + }; + + if (notEqual(A_scope, B_scope) || notEqual(A_scope, C_scope) || + notEqual(A_scope, D_scope) || notEqual(B_scope, C_scope) || + notEqual(B_scope, D_scope) || notEqual(C_scope, D_scope)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Cooperative matrix scopes must match: " + << spvOpcodeString(opcode); + } + + if (notEqual(A_rows, C_rows) || notEqual(A_rows, D_rows) || + notEqual(C_rows, D_rows)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Cooperative matrix 'M' mismatch: " + << spvOpcodeString(opcode); + } + + if (notEqual(B_cols, C_cols) || notEqual(B_cols, D_cols) || + notEqual(C_cols, D_cols)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Cooperative matrix 'N' mismatch: " + << spvOpcodeString(opcode); + } + + if (notEqual(A_cols, B_rows)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Cooperative matrix 'K' mismatch: " + << spvOpcodeString(opcode); + } + break; + } + default: break; } diff --git a/third_party/spirv-tools/source/val/validate_atomics.cpp b/third_party/spirv-tools/source/val/validate_atomics.cpp index becb87200c..b8867ddcc1 100644 --- a/third_party/spirv-tools/source/val/validate_atomics.cpp +++ b/third_party/spirv-tools/source/val/validate_atomics.cpp @@ -21,136 +21,35 @@ #include "source/spirv_target_env.h" #include "source/util/bitutils.h" #include "source/val/instruction.h" +#include "source/val/validate_memory_semantics.h" +#include "source/val/validate_scopes.h" #include "source/val/validation_state.h" +namespace { + +bool IsStorageClassAllowedByUniversalRules(uint32_t storage_class) { + switch (storage_class) { + case SpvStorageClassUniform: + case SpvStorageClassStorageBuffer: + case SpvStorageClassWorkgroup: + case SpvStorageClassCrossWorkgroup: + case SpvStorageClassGeneric: + case SpvStorageClassAtomicCounter: + case SpvStorageClassImage: + case SpvStorageClassFunction: + case SpvStorageClassPhysicalStorageBufferEXT: + return true; + break; + default: + return false; + } +} + +} // namespace + namespace spvtools { namespace val { -// Validates Memory Scope operand. -spv_result_t ValidateMemoryScope(ValidationState_t& _, const Instruction* inst, - uint32_t id) { - const SpvOp opcode = inst->opcode(); - bool is_int32 = false, is_const_int32 = false; - uint32_t value = 0; - std::tie(is_int32, is_const_int32, value) = _.EvalInt32IfConst(id); - - if (!is_int32) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << spvOpcodeString(opcode) << ": expected Scope to be 32-bit int"; - } - - if (!is_const_int32) { - return SPV_SUCCESS; - } - -#if 0 - // TODO(atgoo@github.com): this check fails Vulkan CTS, reenable once fixed. - if (spvIsVulkanEnv(_.context()->target_env)) { - if (value != SpvScopeDevice && value != SpvScopeWorkgroup && - value != SpvScopeInvocation) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << spvOpcodeString(opcode) - << ": in Vulkan environment memory scope is limited to Device, " - "Workgroup and Invocation"; - } - } -#endif - - // TODO(atgoo@github.com) Add checks for OpenCL and OpenGL environments. - - return SPV_SUCCESS; -} - -// Validates a Memory Semantics operand. -spv_result_t ValidateMemorySemantics(ValidationState_t& _, - const Instruction* inst, - uint32_t operand_index) { - const SpvOp opcode = inst->opcode(); - bool is_int32 = false, is_const_int32 = false; - uint32_t flags = 0; - auto memory_semantics_id = inst->GetOperandAs(operand_index); - std::tie(is_int32, is_const_int32, flags) = - _.EvalInt32IfConst(memory_semantics_id); - - if (!is_int32) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << spvOpcodeString(opcode) - << ": expected Memory Semantics to be 32-bit int"; - } - - if (!is_const_int32) { - return SPV_SUCCESS; - } - - if (spvtools::utils::CountSetBits( - flags & - (SpvMemorySemanticsAcquireMask | SpvMemorySemanticsReleaseMask | - SpvMemorySemanticsAcquireReleaseMask | - SpvMemorySemanticsSequentiallyConsistentMask)) > 1) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << spvOpcodeString(opcode) - << ": no more than one of the following Memory Semantics bits can " - "be set at the same time: Acquire, Release, AcquireRelease or " - "SequentiallyConsistent"; - } - - if (flags & SpvMemorySemanticsUniformMemoryMask && - !_.HasCapability(SpvCapabilityShader)) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << spvOpcodeString(opcode) - << ": Memory Semantics UniformMemory requires capability Shader"; - } - - if (flags & SpvMemorySemanticsAtomicCounterMemoryMask && - !_.HasCapability(SpvCapabilityAtomicStorage)) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << spvOpcodeString(opcode) - << ": Memory Semantics UniformMemory requires capability " - "AtomicStorage"; - } - - if (opcode == SpvOpAtomicFlagClear && - (flags & SpvMemorySemanticsAcquireMask || - flags & SpvMemorySemanticsAcquireReleaseMask)) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << "Memory Semantics Acquire and AcquireRelease cannot be used with " - << spvOpcodeString(opcode); - } - - if (opcode == SpvOpAtomicCompareExchange && operand_index == 5 && - (flags & SpvMemorySemanticsReleaseMask || - flags & SpvMemorySemanticsAcquireReleaseMask)) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << spvOpcodeString(opcode) - << ": Memory Semantics Release and AcquireRelease cannot be used " - "for operand Unequal"; - } - - if (spvIsVulkanEnv(_.context()->target_env)) { - if (opcode == SpvOpAtomicLoad && - (flags & SpvMemorySemanticsReleaseMask || - flags & SpvMemorySemanticsAcquireReleaseMask || - flags & SpvMemorySemanticsSequentiallyConsistentMask)) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << "Vulkan spec disallows OpAtomicLoad with Memory Semantics " - "Release, AcquireRelease and SequentiallyConsistent"; - } - - if (opcode == SpvOpAtomicStore && - (flags & SpvMemorySemanticsAcquireMask || - flags & SpvMemorySemanticsAcquireReleaseMask || - flags & SpvMemorySemanticsSequentiallyConsistentMask)) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << "Vulkan spec disallows OpAtomicStore with Memory Semantics " - "Acquire, AcquireRelease and SequentiallyConsistent"; - } - } - - // TODO(atgoo@github.com) Add checks for OpenCL and OpenGL environments. - - return SPV_SUCCESS; -} - // Validates correctness of atomic instructions. spv_result_t AtomicsPass(ValidationState_t& _, const Instruction* inst) { const SpvOp opcode = inst->opcode(); @@ -200,10 +99,33 @@ spv_result_t AtomicsPass(ValidationState_t& _, const Instruction* inst) { } if (spvIsVulkanEnv(_.context()->target_env) && _.GetBitWidth(result_type) != 32) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << spvOpcodeString(opcode) - << ": according to the Vulkan spec atomic Result Type needs " - "to be a 32-bit int scalar type"; + switch (opcode) { + case SpvOpAtomicSMin: + case SpvOpAtomicUMin: + case SpvOpAtomicSMax: + case SpvOpAtomicUMax: + case SpvOpAtomicAnd: + case SpvOpAtomicOr: + case SpvOpAtomicXor: + case SpvOpAtomicIAdd: + case SpvOpAtomicLoad: + case SpvOpAtomicStore: + case SpvOpAtomicExchange: + case SpvOpAtomicCompareExchange: { + if (_.GetBitWidth(result_type) == 64 && + !_.HasCapability(SpvCapabilityInt64Atomics)) + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << spvOpcodeString(opcode) + << ": 64-bit atomics require the Int64Atomics " + "capability"; + } break; + default: + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << spvOpcodeString(opcode) + << ": according to the Vulkan spec atomic Result Type " + "needs " + "to be a 32-bit int scalar type"; + } } } @@ -219,21 +141,42 @@ spv_result_t AtomicsPass(ValidationState_t& _, const Instruction* inst) { << ": expected Pointer to be of type OpTypePointer"; } - switch (storage_class) { - case SpvStorageClassUniform: - case SpvStorageClassWorkgroup: - case SpvStorageClassCrossWorkgroup: - case SpvStorageClassGeneric: - case SpvStorageClassAtomicCounter: - case SpvStorageClassImage: - case SpvStorageClassStorageBuffer: - break; - default: + // Validate storage class against universal rules + if (!IsStorageClassAllowedByUniversalRules(storage_class)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << spvOpcodeString(opcode) + << ": storage class forbidden by universal validation rules."; + } + + // Then Shader rules + if (_.HasCapability(SpvCapabilityShader)) { + if (storage_class == SpvStorageClassFunction) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << spvOpcodeString(opcode) - << ": expected Pointer Storage Class to be Uniform, " - "Workgroup, CrossWorkgroup, Generic, AtomicCounter, Image " - "or StorageBuffer"; + << ": Function storage class forbidden when the Shader " + "capability is declared."; + } + } + + // And finally OpenCL environment rules + if (spvIsOpenCLEnv(_.context()->target_env)) { + if ((storage_class != SpvStorageClassFunction) && + (storage_class != SpvStorageClassWorkgroup) && + (storage_class != SpvStorageClassCrossWorkgroup) && + (storage_class != SpvStorageClassGeneric)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << spvOpcodeString(opcode) + << ": storage class must be Function, Workgroup, " + "CrossWorkGroup or Generic in the OpenCL environment."; + } + + if (_.context()->target_env == SPV_ENV_OPENCL_1_2) { + if (storage_class == SpvStorageClassGeneric) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Storage class cannot be Generic in OpenCL 1.2 " + "environment"; + } + } } if (opcode == SpvOpAtomicFlagTestAndSet || @@ -264,13 +207,37 @@ spv_result_t AtomicsPass(ValidationState_t& _, const Instruction* inst) { return error; } - if (auto error = ValidateMemorySemantics(_, inst, operand_index++)) + const auto equal_semantics_index = operand_index++; + if (auto error = ValidateMemorySemantics(_, inst, equal_semantics_index)) return error; if (opcode == SpvOpAtomicCompareExchange || opcode == SpvOpAtomicCompareExchangeWeak) { - if (auto error = ValidateMemorySemantics(_, inst, operand_index++)) + const auto unequal_semantics_index = operand_index++; + if (auto error = + ValidateMemorySemantics(_, inst, unequal_semantics_index)) return error; + + // Volatile bits must match for equal and unequal semantics. Previous + // checks guarantee they are 32-bit constants, but we need to recheck + // whether they are evaluatable constants. + bool is_int32 = false; + bool is_equal_const = false; + bool is_unequal_const = false; + uint32_t equal_value = 0; + uint32_t unequal_value = 0; + std::tie(is_int32, is_equal_const, equal_value) = _.EvalInt32IfConst( + inst->GetOperandAs(equal_semantics_index)); + std::tie(is_int32, is_unequal_const, unequal_value) = + _.EvalInt32IfConst( + inst->GetOperandAs(unequal_semantics_index)); + if (is_equal_const && is_unequal_const && + ((equal_value & SpvMemorySemanticsVolatileMask) ^ + (unequal_value & SpvMemorySemanticsVolatileMask))) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Volatile mask setting must match for Equal and Unequal " + "memory semantics"; + } } if (opcode == SpvOpAtomicStore) { @@ -278,9 +245,8 @@ spv_result_t AtomicsPass(ValidationState_t& _, const Instruction* inst) { if (value_type != data_type) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << spvOpcodeString(opcode) - << ": expected Value type and the type pointed to by Pointer " - "to" - << " be the same"; + << ": expected Value type and the type pointed to by " + "Pointer to be the same"; } } else if (opcode != SpvOpAtomicLoad && opcode != SpvOpAtomicIIncrement && opcode != SpvOpAtomicIDecrement && diff --git a/third_party/spirv-tools/source/val/validate_barriers.cpp b/third_party/spirv-tools/source/val/validate_barriers.cpp index 0771f2d28a..b499c8c085 100644 --- a/third_party/spirv-tools/source/val/validate_barriers.cpp +++ b/third_party/spirv-tools/source/val/validate_barriers.cpp @@ -14,8 +14,6 @@ // Validates correctness of barrier SPIR-V instructions. -#include "source/val/validate.h" - #include #include "source/diagnostic.h" @@ -24,173 +22,13 @@ #include "source/spirv_target_env.h" #include "source/util/bitutils.h" #include "source/val/instruction.h" +#include "source/val/validate.h" +#include "source/val/validate_memory_semantics.h" +#include "source/val/validate_scopes.h" #include "source/val/validation_state.h" namespace spvtools { namespace val { -namespace { - -// Validates Execution Scope operand. -spv_result_t ValidateExecutionScope(ValidationState_t& _, - const Instruction* inst, uint32_t id) { - const SpvOp opcode = inst->opcode(); - bool is_int32 = false, is_const_int32 = false; - uint32_t value = 0; - std::tie(is_int32, is_const_int32, value) = _.EvalInt32IfConst(id); - - if (!is_int32) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << spvOpcodeString(opcode) - << ": expected Execution Scope to be a 32-bit int"; - } - - if (!is_const_int32) { - return SPV_SUCCESS; - } - - if (spvIsVulkanEnv(_.context()->target_env)) { - if (value != SpvScopeWorkgroup && value != SpvScopeSubgroup) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << spvOpcodeString(opcode) - << ": in Vulkan environment Execution Scope is limited to " - "Workgroup and Subgroup"; - } - - if (_.context()->target_env != SPV_ENV_VULKAN_1_0 && - value != SpvScopeSubgroup) { - _.function(inst->function()->id()) - ->RegisterExecutionModelLimitation([](SpvExecutionModel model, - std::string* message) { - if (model == SpvExecutionModelFragment || - model == SpvExecutionModelVertex || - model == SpvExecutionModelGeometry || - model == SpvExecutionModelTessellationEvaluation) { - if (message) { - *message = - "in Vulkan evironment, OpControlBarrier execution scope " - "must be Subgroup for Fragment, Vertex, Geometry and " - "TessellationEvaluation execution models"; - } - return false; - } - return true; - }); - } - } - - // TODO(atgoo@github.com) Add checks for OpenCL and OpenGL environments. - - return SPV_SUCCESS; -} - -// Validates Memory Scope operand. -spv_result_t ValidateMemoryScope(ValidationState_t& _, const Instruction* inst, - uint32_t id) { - const SpvOp opcode = inst->opcode(); - bool is_int32 = false, is_const_int32 = false; - uint32_t value = 0; - std::tie(is_int32, is_const_int32, value) = _.EvalInt32IfConst(id); - - if (!is_int32) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << spvOpcodeString(opcode) - << ": expected Memory Scope to be a 32-bit int"; - } - - if (!is_const_int32) { - return SPV_SUCCESS; - } - - if (spvIsVulkanEnv(_.context()->target_env)) { - if (value == SpvScopeCrossDevice) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << spvOpcodeString(opcode) - << ": in Vulkan environment, Memory Scope cannot be CrossDevice"; - } - if (_.context()->target_env == SPV_ENV_VULKAN_1_0 && - value != SpvScopeDevice && value != SpvScopeWorkgroup && - value != SpvScopeInvocation) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << spvOpcodeString(opcode) - << ": in Vulkan 1.0 environment Memory Scope is limited to " - "Device, " - "Workgroup and Invocation"; - } - } - - // TODO(atgoo@github.com) Add checks for OpenCL and OpenGL environments. - - return SPV_SUCCESS; -} - -// Validates Memory Semantics operand. -spv_result_t ValidateMemorySemantics(ValidationState_t& _, - const Instruction* inst, uint32_t id) { - const SpvOp opcode = inst->opcode(); - bool is_int32 = false, is_const_int32 = false; - uint32_t value = 0; - std::tie(is_int32, is_const_int32, value) = _.EvalInt32IfConst(id); - - if (!is_int32) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << spvOpcodeString(opcode) - << ": expected Memory Semantics to be a 32-bit int"; - } - - if (!is_const_int32) { - return SPV_SUCCESS; - } - - const size_t num_memory_order_set_bits = spvtools::utils::CountSetBits( - value & (SpvMemorySemanticsAcquireMask | SpvMemorySemanticsReleaseMask | - SpvMemorySemanticsAcquireReleaseMask | - SpvMemorySemanticsSequentiallyConsistentMask)); - - if (num_memory_order_set_bits > 1) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << spvOpcodeString(opcode) - << ": Memory Semantics can have at most one of the following bits " - "set: Acquire, Release, AcquireRelease or SequentiallyConsistent"; - } - - if (spvIsVulkanEnv(_.context()->target_env)) { - const bool includes_storage_class = - value & (SpvMemorySemanticsUniformMemoryMask | - SpvMemorySemanticsWorkgroupMemoryMask | - SpvMemorySemanticsImageMemoryMask); - - if (opcode == SpvOpMemoryBarrier && !num_memory_order_set_bits) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << spvOpcodeString(opcode) - << ": Vulkan specification requires Memory Semantics to have one " - "of the following bits set: Acquire, Release, AcquireRelease " - "or SequentiallyConsistent"; - } - - if (opcode == SpvOpMemoryBarrier && !includes_storage_class) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << spvOpcodeString(opcode) - << ": expected Memory Semantics to include a Vulkan-supported " - "storage class"; - } - -#if 0 - // TODO(atgoo@github.com): this check fails Vulkan CTS, reenable once fixed. - if (opcode == SpvOpControlBarrier && value && !includes_storage_class) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << spvOpcodeString(opcode) - << ": expected Memory Semantics to include a Vulkan-supported " - "storage class if Memory Semantics is not None"; - } -#endif - } - - // TODO(atgoo@github.com) Add checks for OpenCL and OpenGL environments. - - return SPV_SUCCESS; -} - -} // namespace // Validates correctness of barrier instructions. spv_result_t BarriersPass(ValidationState_t& _, const Instruction* inst) { @@ -199,14 +37,15 @@ spv_result_t BarriersPass(ValidationState_t& _, const Instruction* inst) { switch (opcode) { case SpvOpControlBarrier: { - if (spvVersionForTargetEnv(_.context()->target_env) < - SPV_SPIRV_VERSION_WORD(1, 3)) { + if (_.version() < SPV_SPIRV_VERSION_WORD(1, 3)) { _.function(inst->function()->id()) ->RegisterExecutionModelLimitation( [](SpvExecutionModel model, std::string* message) { if (model != SpvExecutionModelTessellationControl && model != SpvExecutionModelGLCompute && - model != SpvExecutionModelKernel) { + model != SpvExecutionModelKernel && + model != SpvExecutionModelTaskNV && + model != SpvExecutionModelMeshNV) { if (message) { *message = "OpControlBarrier requires one of the following " @@ -221,7 +60,6 @@ spv_result_t BarriersPass(ValidationState_t& _, const Instruction* inst) { const uint32_t execution_scope = inst->word(1); const uint32_t memory_scope = inst->word(2); - const uint32_t memory_semantics = inst->word(3); if (auto error = ValidateExecutionScope(_, inst, execution_scope)) { return error; @@ -231,7 +69,7 @@ spv_result_t BarriersPass(ValidationState_t& _, const Instruction* inst) { return error; } - if (auto error = ValidateMemorySemantics(_, inst, memory_semantics)) { + if (auto error = ValidateMemorySemantics(_, inst, 2)) { return error; } break; @@ -239,13 +77,12 @@ spv_result_t BarriersPass(ValidationState_t& _, const Instruction* inst) { case SpvOpMemoryBarrier: { const uint32_t memory_scope = inst->word(1); - const uint32_t memory_semantics = inst->word(2); if (auto error = ValidateMemoryScope(_, inst, memory_scope)) { return error; } - if (auto error = ValidateMemorySemantics(_, inst, memory_semantics)) { + if (auto error = ValidateMemorySemantics(_, inst, 1)) { return error; } break; @@ -277,13 +114,12 @@ spv_result_t BarriersPass(ValidationState_t& _, const Instruction* inst) { } const uint32_t memory_scope = inst->word(2); - const uint32_t memory_semantics = inst->word(3); if (auto error = ValidateMemoryScope(_, inst, memory_scope)) { return error; } - if (auto error = ValidateMemorySemantics(_, inst, memory_semantics)) { + if (auto error = ValidateMemorySemantics(_, inst, 2)) { return error; } break; diff --git a/third_party/spirv-tools/source/val/validate_builtins.cpp b/third_party/spirv-tools/source/val/validate_builtins.cpp index c791e428fb..7623d49c29 100644 --- a/third_party/spirv-tools/source/val/validate_builtins.cpp +++ b/third_party/spirv-tools/source/val/validate_builtins.cpp @@ -55,17 +55,27 @@ std::string GetIdDesc(const Instruction& inst) { // the Vulkan spec. // TODO: If non-Vulkan validation rules are added then it might need // to be refactored. -spv_result_t GetUnderlyingType(const ValidationState_t& _, +spv_result_t GetUnderlyingType(ValidationState_t& _, const Decoration& decoration, const Instruction& inst, uint32_t* underlying_type) { if (decoration.struct_member_index() != Decoration::kInvalidMember) { - assert(inst.opcode() == SpvOpTypeStruct); + if (inst.opcode() != SpvOpTypeStruct) { + return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << GetIdDesc(inst) + << "Attempted to get underlying data type via member index for " + "non-struct type."; + } *underlying_type = inst.word(decoration.struct_member_index() + 2); return SPV_SUCCESS; } - assert(inst.opcode() != SpvOpTypeStruct); + if (inst.opcode() == SpvOpTypeStruct) { + return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << GetIdDesc(inst) + << " did not find an member index to get underlying data type for " + "struct type."; + } if (spvOpcodeIsConstant(inst.opcode())) { *underlying_type = inst.type_id(); @@ -101,12 +111,34 @@ SpvStorageClass GetStorageClass(const Instruction& inst) { return SpvStorageClassMax; } +bool IsBuiltInValidForWebGPU(SpvBuiltIn label) { + switch (label) { + case SpvBuiltInPosition: + case SpvBuiltInVertexIndex: + case SpvBuiltInInstanceIndex: + case SpvBuiltInFrontFacing: + case SpvBuiltInFragCoord: + case SpvBuiltInFragDepth: + case SpvBuiltInNumWorkgroups: + case SpvBuiltInWorkgroupSize: + case SpvBuiltInLocalInvocationId: + case SpvBuiltInGlobalInvocationId: + case SpvBuiltInLocalInvocationIndex: { + return true; + } + default: + break; + } + + return false; +} + // Helper class managing validation of built-ins. // TODO: Generic functionality of this class can be moved into // ValidationState_t to be made available to other users. class BuiltInsValidator { public: - BuiltInsValidator(const ValidationState_t& vstate) : _(vstate) {} + BuiltInsValidator(ValidationState_t& vstate) : _(vstate) {} // Run validation. spv_result_t Run(); @@ -167,11 +199,28 @@ class BuiltInsValidator { const Instruction& inst); spv_result_t ValidateVertexIndexAtDefinition(const Decoration& decoration, const Instruction& inst); + spv_result_t ValidateVertexIdOrInstanceIdAtDefinition( + const Decoration& decoration, const Instruction& inst); + spv_result_t ValidateLocalInvocationIndexAtDefinition( + const Decoration& decoration, const Instruction& inst); spv_result_t ValidateWorkgroupSizeAtDefinition(const Decoration& decoration, const Instruction& inst); // Used for GlobalInvocationId, LocalInvocationId, NumWorkgroups, WorkgroupId. spv_result_t ValidateComputeShaderI32Vec3InputAtDefinition( const Decoration& decoration, const Instruction& inst); + spv_result_t ValidateSMBuiltinsAtDefinition(const Decoration& decoration, + const Instruction& inst); + + // Used for SubgroupEqMask, SubgroupGeMask, SubgroupGtMask, SubgroupLtMask, + // SubgroupLeMask. + spv_result_t ValidateI32Vec4InputAtDefinition(const Decoration& decoration, + const Instruction& inst); + // Used for SubgroupLocalInvocationId, SubgroupSize. + spv_result_t ValidateI32InputAtDefinition(const Decoration& decoration, + const Instruction& inst); + // Used for SubgroupId, NumSubgroups. + spv_result_t ValidateComputeI32InputAtDefinition(const Decoration& decoration, + const Instruction& inst); // The following section contains functions which are called when id defined // by |referenced_inst| is @@ -205,6 +254,11 @@ class BuiltInsValidator { const Instruction& referenced_inst, const Instruction& referenced_from_inst); + spv_result_t ValidateInstanceIdAtReference( + const Decoration& decoration, const Instruction& built_in_inst, + const Instruction& referenced_inst, + const Instruction& referenced_from_inst); + spv_result_t ValidateInstanceIndexAtReference( const Decoration& decoration, const Instruction& built_in_inst, const Instruction& referenced_inst, @@ -260,6 +314,11 @@ class BuiltInsValidator { const Instruction& referenced_inst, const Instruction& referenced_from_inst); + spv_result_t ValidateLocalInvocationIndexAtReference( + const Decoration& decoration, const Instruction& built_in_inst, + const Instruction& referenced_inst, + const Instruction& referenced_from_inst); + spv_result_t ValidateVertexIndexAtReference( const Decoration& decoration, const Instruction& built_in_inst, const Instruction& referenced_inst, @@ -285,6 +344,16 @@ class BuiltInsValidator { const Decoration& decoration, const Instruction& built_in_inst, const Instruction& referenced_inst, const Instruction& referenced_from_inst); + // Used for SubgroupId and NumSubgroups. + spv_result_t ValidateComputeI32InputAtReference( + const Decoration& decoration, const Instruction& built_in_inst, + const Instruction& referenced_inst, + const Instruction& referenced_from_inst); + + spv_result_t ValidateSMBuiltinsAtReference( + 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|. @@ -317,6 +386,13 @@ class BuiltInsValidator { spv_result_t ValidateI32Arr( const Decoration& decoration, const Instruction& inst, const std::function& diag); + spv_result_t ValidateOptionalArrayedI32( + const Decoration& decoration, const Instruction& inst, + const std::function& diag); + spv_result_t ValidateI32Helper( + const Decoration& decoration, const Instruction& inst, + const std::function& diag, + uint32_t underlying_type); spv_result_t ValidateF32( const Decoration& decoration, const Instruction& inst, const std::function& diag); @@ -375,7 +451,7 @@ class BuiltInsValidator { // instruction. void Update(const Instruction& inst); - const ValidationState_t& _; + ValidationState_t& _; // Mapping id -> list of rules which validate instruction referencing the // id. Rules can create new rules and add them to this container. @@ -497,6 +573,30 @@ spv_result_t BuiltInsValidator::ValidateI32( return error; } + return ValidateI32Helper(decoration, inst, diag, underlying_type); +} + +spv_result_t BuiltInsValidator::ValidateOptionalArrayedI32( + const Decoration& decoration, const Instruction& inst, + const std::function& diag) { + uint32_t underlying_type = 0; + if (spv_result_t error = + GetUnderlyingType(_, decoration, inst, &underlying_type)) { + return error; + } + + // Strip the array, if present. + if (_.GetIdOpcode(underlying_type) == SpvOpTypeArray) { + underlying_type = _.FindDef(underlying_type)->word(2u); + } + + return ValidateI32Helper(decoration, inst, diag, underlying_type); +} + +spv_result_t BuiltInsValidator::ValidateI32Helper( + const Decoration& decoration, const Instruction& inst, + const std::function& diag, + uint32_t underlying_type) { if (!_.IsIntScalarType(underlying_type)) { return diag(GetDefinitionDesc(decoration, inst) + " is not an int scalar."); } @@ -863,7 +963,8 @@ spv_result_t BuiltInsValidator::ValidateClipOrCullDistanceAtReference( } case SpvExecutionModelTessellationControl: case SpvExecutionModelTessellationEvaluation: - case SpvExecutionModelGeometry: { + case SpvExecutionModelGeometry: + case SpvExecutionModelMeshNV: { if (decoration.struct_member_index() != Decoration::kInvalidMember) { // The outer level of array is applied on the variable. if (spv_result_t error = ValidateF32Arr( @@ -929,12 +1030,14 @@ spv_result_t BuiltInsValidator::ValidateClipOrCullDistanceAtReference( spv_result_t BuiltInsValidator::ValidateFragCoordAtDefinition( const Decoration& decoration, const Instruction& inst) { - if (spvIsVulkanEnv(_.context()->target_env)) { + if (spvIsVulkanOrWebGPUEnv(_.context()->target_env)) { if (spv_result_t error = ValidateF32Vec( decoration, inst, 4, [this, &inst](const std::string& message) -> spv_result_t { return _.diag(SPV_ERROR_INVALID_DATA, &inst) - << "According to the Vulkan spec BuiltIn FragCoord " + << "According to the " + << spvLogStringForEnv(_.context()->target_env) + << " spec BuiltIn FragCoord " "variable needs to be a 4-component 32-bit float " "vector. " << message; @@ -951,12 +1054,13 @@ spv_result_t BuiltInsValidator::ValidateFragCoordAtReference( const Decoration& decoration, const Instruction& built_in_inst, const Instruction& referenced_inst, const Instruction& referenced_from_inst) { - if (spvIsVulkanEnv(_.context()->target_env)) { + if (spvIsVulkanOrWebGPUEnv(_.context()->target_env)) { const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst); if (storage_class != SpvStorageClassMax && storage_class != SpvStorageClassInput) { return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) - << "Vulkan spec allows BuiltIn FragCoord to be only used for " + << spvLogStringForEnv(_.context()->target_env) + << " spec allows BuiltIn FragCoord to be only used for " "variables with Input storage class. " << GetReferenceDesc(decoration, built_in_inst, referenced_inst, referenced_from_inst) @@ -966,7 +1070,8 @@ spv_result_t BuiltInsValidator::ValidateFragCoordAtReference( for (const SpvExecutionModel execution_model : execution_models_) { if (execution_model != SpvExecutionModelFragment) { return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) - << "Vulkan spec allows BuiltIn FragCoord to be used only with " + << spvLogStringForEnv(_.context()->target_env) + << " spec allows BuiltIn FragCoord to be used only with " "Fragment execution model. " << GetReferenceDesc(decoration, built_in_inst, referenced_inst, referenced_from_inst, execution_model); @@ -986,12 +1091,14 @@ spv_result_t BuiltInsValidator::ValidateFragCoordAtReference( spv_result_t BuiltInsValidator::ValidateFragDepthAtDefinition( const Decoration& decoration, const Instruction& inst) { - if (spvIsVulkanEnv(_.context()->target_env)) { + if (spvIsVulkanOrWebGPUEnv(_.context()->target_env)) { if (spv_result_t error = ValidateF32( decoration, inst, [this, &inst](const std::string& message) -> spv_result_t { return _.diag(SPV_ERROR_INVALID_DATA, &inst) - << "According to the Vulkan spec BuiltIn FragDepth " + << "According to the " + << spvLogStringForEnv(_.context()->target_env) + << " spec BuiltIn FragDepth " "variable needs to be a 32-bit float scalar. " << message; })) { @@ -1007,12 +1114,13 @@ spv_result_t BuiltInsValidator::ValidateFragDepthAtReference( const Decoration& decoration, const Instruction& built_in_inst, const Instruction& referenced_inst, const Instruction& referenced_from_inst) { - if (spvIsVulkanEnv(_.context()->target_env)) { + if (spvIsVulkanOrWebGPUEnv(_.context()->target_env)) { const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst); if (storage_class != SpvStorageClassMax && storage_class != SpvStorageClassOutput) { return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) - << "Vulkan spec allows BuiltIn FragDepth to be only used for " + << spvLogStringForEnv(_.context()->target_env) + << " spec allows BuiltIn FragDepth to be only used for " "variables with Output storage class. " << GetReferenceDesc(decoration, built_in_inst, referenced_inst, referenced_from_inst) @@ -1022,7 +1130,8 @@ spv_result_t BuiltInsValidator::ValidateFragDepthAtReference( for (const SpvExecutionModel execution_model : execution_models_) { if (execution_model != SpvExecutionModelFragment) { return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) - << "Vulkan spec allows BuiltIn FragDepth to be used only with " + << spvLogStringForEnv(_.context()->target_env) + << " spec allows BuiltIn FragDepth to be used only with " "Fragment execution model. " << GetReferenceDesc(decoration, built_in_inst, referenced_inst, referenced_from_inst, execution_model); @@ -1035,7 +1144,8 @@ spv_result_t BuiltInsValidator::ValidateFragDepthAtReference( const auto* modes = _.GetExecutionModes(entry_point); if (!modes || !modes->count(SpvExecutionModeDepthReplacing)) { return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) - << "Vulkan spec requires DepthReplacing execution mode to be " + << spvLogStringForEnv(_.context()->target_env) + << " spec requires DepthReplacing execution mode to be " "declared when using BuiltIn FragDepth. " << GetReferenceDesc(decoration, built_in_inst, referenced_inst, referenced_from_inst); @@ -1055,12 +1165,14 @@ spv_result_t BuiltInsValidator::ValidateFragDepthAtReference( spv_result_t BuiltInsValidator::ValidateFrontFacingAtDefinition( const Decoration& decoration, const Instruction& inst) { - if (spvIsVulkanEnv(_.context()->target_env)) { + if (spvIsVulkanOrWebGPUEnv(_.context()->target_env)) { if (spv_result_t error = ValidateBool( decoration, inst, [this, &inst](const std::string& message) -> spv_result_t { return _.diag(SPV_ERROR_INVALID_DATA, &inst) - << "According to the Vulkan spec BuiltIn FrontFacing " + << "According to the " + << spvLogStringForEnv(_.context()->target_env) + << " spec BuiltIn FrontFacing " "variable needs to be a bool scalar. " << message; })) { @@ -1076,12 +1188,13 @@ spv_result_t BuiltInsValidator::ValidateFrontFacingAtReference( const Decoration& decoration, const Instruction& built_in_inst, const Instruction& referenced_inst, const Instruction& referenced_from_inst) { - if (spvIsVulkanEnv(_.context()->target_env)) { + if (spvIsVulkanOrWebGPUEnv(_.context()->target_env)) { const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst); if (storage_class != SpvStorageClassMax && storage_class != SpvStorageClassInput) { return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) - << "Vulkan spec allows BuiltIn FrontFacing to be only used for " + << spvLogStringForEnv(_.context()->target_env) + << " spec allows BuiltIn FrontFacing to be only used for " "variables with Input storage class. " << GetReferenceDesc(decoration, built_in_inst, referenced_inst, referenced_from_inst) @@ -1091,7 +1204,8 @@ spv_result_t BuiltInsValidator::ValidateFrontFacingAtReference( for (const SpvExecutionModel execution_model : execution_models_) { if (execution_model != SpvExecutionModelFragment) { return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) - << "Vulkan spec allows BuiltIn FrontFacing to be used only with " + << spvLogStringForEnv(_.context()->target_env) + << " spec allows BuiltIn FrontFacing to be used only with " "Fragment execution model. " << GetReferenceDesc(decoration, built_in_inst, referenced_inst, referenced_from_inst, execution_model); @@ -1225,12 +1339,14 @@ spv_result_t BuiltInsValidator::ValidateInvocationIdAtReference( spv_result_t BuiltInsValidator::ValidateInstanceIndexAtDefinition( const Decoration& decoration, const Instruction& inst) { - if (spvIsVulkanEnv(_.context()->target_env)) { + if (spvIsVulkanOrWebGPUEnv(_.context()->target_env)) { if (spv_result_t error = ValidateI32( decoration, inst, [this, &inst](const std::string& message) -> spv_result_t { return _.diag(SPV_ERROR_INVALID_DATA, &inst) - << "According to the Vulkan spec BuiltIn InstanceIndex " + << "According to the " + << spvLogStringForEnv(_.context()->target_env) + << " spec BuiltIn InstanceIndex " "variable needs to be a 32-bit int scalar. " << message; })) { @@ -1246,12 +1362,13 @@ spv_result_t BuiltInsValidator::ValidateInstanceIndexAtReference( const Decoration& decoration, const Instruction& built_in_inst, const Instruction& referenced_inst, const Instruction& referenced_from_inst) { - if (spvIsVulkanEnv(_.context()->target_env)) { + if (spvIsVulkanOrWebGPUEnv(_.context()->target_env)) { const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst); if (storage_class != SpvStorageClassMax && storage_class != SpvStorageClassInput) { return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) - << "Vulkan spec allows BuiltIn InstanceIndex to be only used for " + << spvLogStringForEnv(_.context()->target_env) + << " spec allows BuiltIn InstanceIndex to be only used for " "variables with Input storage class. " << GetReferenceDesc(decoration, built_in_inst, referenced_inst, referenced_from_inst) @@ -1261,7 +1378,8 @@ spv_result_t BuiltInsValidator::ValidateInstanceIndexAtReference( for (const SpvExecutionModel execution_model : execution_models_) { if (execution_model != SpvExecutionModelVertex) { return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) - << "Vulkan spec allows BuiltIn InstanceIndex to be used only " + << spvLogStringForEnv(_.context()->target_env) + << " spec allows BuiltIn InstanceIndex to be used only " "with Vertex execution model. " << GetReferenceDesc(decoration, built_in_inst, referenced_inst, referenced_from_inst, execution_model); @@ -1445,7 +1563,8 @@ spv_result_t BuiltInsValidator::ValidatePointSizeAtReference( } case SpvExecutionModelTessellationControl: case SpvExecutionModelTessellationEvaluation: - case SpvExecutionModelGeometry: { + case SpvExecutionModelGeometry: + case SpvExecutionModelMeshNV: { // PointSize can be a per-vertex variable for tessellation control, // tessellation evaluation and geometry shader stages. In such cases // variables will have an array of 32-bit floats. @@ -1556,10 +1675,12 @@ spv_result_t BuiltInsValidator::ValidatePositionAtReference( } case SpvExecutionModelGeometry: case SpvExecutionModelTessellationControl: - case SpvExecutionModelTessellationEvaluation: { + case SpvExecutionModelTessellationEvaluation: + case SpvExecutionModelMeshNV: { // Position can be a per-vertex variable for tessellation control, - // tessellation evaluation and geometry shader stages. In such cases - // variables will have an array of 4-component 32-bit float vectors. + // tessellation evaluation, geometry and mesh shader stages. In such + // cases variables will have an array of 4-component 32-bit float + // vectors. if (decoration.struct_member_index() != Decoration::kInvalidMember) { // The array is on the variable, so this must be a 4-component // 32-bit float vector. @@ -1606,6 +1727,46 @@ spv_result_t BuiltInsValidator::ValidatePositionAtReference( } } + if (spvIsWebGPUEnv(_.context()->target_env)) { + const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst); + if (storage_class != SpvStorageClassMax && + storage_class != SpvStorageClassOutput) { + return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << "WebGPU spec allows BuiltIn Position 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 SpvExecutionModel execution_model : execution_models_) { + switch (execution_model) { + case SpvExecutionModelVertex: { + if (spv_result_t error = ValidateF32Vec( + decoration, built_in_inst, 4, + [this, &referenced_from_inst]( + const std::string& message) -> spv_result_t { + return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << "According to the WebGPU spec BuiltIn Position " + "variable needs to be a 4-component 32-bit float " + "vector. " + << message; + })) { + return error; + } + break; + } + default: { + return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << "WebGPU spec allows BuiltIn Position to be used only " + "with the Vertex 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( @@ -1619,15 +1780,31 @@ spv_result_t BuiltInsValidator::ValidatePositionAtReference( spv_result_t BuiltInsValidator::ValidatePrimitiveIdAtDefinition( const Decoration& decoration, const Instruction& inst) { if (spvIsVulkanEnv(_.context()->target_env)) { - if (spv_result_t error = ValidateI32( - decoration, inst, - [this, &inst](const std::string& message) -> spv_result_t { - return _.diag(SPV_ERROR_INVALID_DATA, &inst) - << "According to the Vulkan spec BuiltIn PrimitiveId " - "variable needs to be a 32-bit int scalar. " - << message; - })) { - return error; + // PrimitiveId can be a per-primitive variable for mesh shader stage. + // In such cases variable will have an array of 32-bit integers. + if (decoration.struct_member_index() != Decoration::kInvalidMember) { + // This must be a 32-bit int scalar. + if (spv_result_t error = ValidateI32( + decoration, inst, + [this, &inst](const std::string& message) -> spv_result_t { + return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << "According to the Vulkan spec BuiltIn PrimitiveId " + "variable needs to be a 32-bit int scalar. " + << message; + })) { + return error; + } + } else { + if (spv_result_t error = ValidateOptionalArrayedI32( + decoration, inst, + [this, &inst](const std::string& message) -> spv_result_t { + return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << "According to the Vulkan spec BuiltIn PrimitiveId " + "variable needs to be a 32-bit int scalar. " + << message; + })) { + return error; + } } } @@ -1682,7 +1859,14 @@ spv_result_t BuiltInsValidator::ValidatePrimitiveIdAtReference( case SpvExecutionModelFragment: case SpvExecutionModelTessellationControl: case SpvExecutionModelTessellationEvaluation: - case SpvExecutionModelGeometry: { + case SpvExecutionModelGeometry: + case SpvExecutionModelMeshNV: + case SpvExecutionModelRayGenerationNV: + case SpvExecutionModelIntersectionNV: + case SpvExecutionModelAnyHitNV: + case SpvExecutionModelClosestHitNV: + case SpvExecutionModelMissNV: + case SpvExecutionModelCallableNV: { // Ok. break; } @@ -2057,13 +2241,15 @@ spv_result_t BuiltInsValidator::ValidateTessLevelAtReference( spv_result_t BuiltInsValidator::ValidateVertexIndexAtDefinition( const Decoration& decoration, const Instruction& inst) { - if (spvIsVulkanEnv(_.context()->target_env)) { + if (spvIsVulkanOrWebGPUEnv(_.context()->target_env)) { if (spv_result_t error = ValidateI32( decoration, inst, [this, &inst](const std::string& message) -> spv_result_t { return _.diag(SPV_ERROR_INVALID_DATA, &inst) - << "According to the Vulkan spec BuiltIn VertexIndex " - "variable needs to be a 32-bit int scalar. " + << "According to the " + << spvLogStringForEnv(_.context()->target_env) + << " spec BuiltIn VertexIndex variable needs to be a " + "32-bit int scalar. " << message; })) { return error; @@ -2074,16 +2260,126 @@ spv_result_t BuiltInsValidator::ValidateVertexIndexAtDefinition( return ValidateVertexIndexAtReference(decoration, inst, inst, inst); } -spv_result_t BuiltInsValidator::ValidateVertexIndexAtReference( +spv_result_t BuiltInsValidator::ValidateVertexIdOrInstanceIdAtDefinition( + const Decoration& decoration, const Instruction& inst) { + const SpvBuiltIn label = SpvBuiltIn(decoration.params()[0]); + bool allow_instance_id = _.HasCapability(SpvCapabilityRayTracingNV) && + label == SpvBuiltInInstanceId; + if (spvIsVulkanEnv(_.context()->target_env) && !allow_instance_id) { + return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << "Vulkan spec doesn't allow BuiltIn VertexId/InstanceId " + "to be used."; + } + + if (label == SpvBuiltInInstanceId) { + return ValidateInstanceIdAtReference(decoration, inst, inst, inst); + } + return SPV_SUCCESS; +} + +spv_result_t BuiltInsValidator::ValidateInstanceIdAtReference( const Decoration& decoration, const Instruction& built_in_inst, const Instruction& referenced_inst, const Instruction& referenced_from_inst) { if (spvIsVulkanEnv(_.context()->target_env)) { + for (const SpvExecutionModel execution_model : execution_models_) { + switch (execution_model) { + case SpvExecutionModelIntersectionNV: + case SpvExecutionModelClosestHitNV: + case SpvExecutionModelAnyHitNV: + // Do nothing, valid stages + break; + default: + return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << "Vulkan spec allows BuiltIn InstanceId to be used " + "only with IntersectionNV, ClosestHitNV and AnyHitNV " + "execution models. " + << GetReferenceDesc(decoration, built_in_inst, referenced_inst, + referenced_from_inst); + break; + } + } + } + + 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::ValidateInstanceIdAtReference, this, decoration, + built_in_inst, referenced_from_inst, std::placeholders::_1)); + } + + return SPV_SUCCESS; +} + +spv_result_t BuiltInsValidator::ValidateLocalInvocationIndexAtDefinition( + const Decoration& decoration, const Instruction& inst) { + if (spvIsWebGPUEnv(_.context()->target_env)) { + if (spv_result_t error = ValidateI32( + decoration, inst, + [this, &inst](const std::string& message) -> spv_result_t { + return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << "According to the WebGPU spec BuiltIn " + "LocalInvocationIndex variable needs to be a 32-bit " + "int." + << message; + })) { + return error; + } + } + + // Seed at reference checks with this built-in. + return ValidateLocalInvocationIndexAtReference(decoration, inst, inst, inst); +} + +spv_result_t BuiltInsValidator::ValidateLocalInvocationIndexAtReference( + const Decoration& decoration, const Instruction& built_in_inst, + const Instruction& referenced_inst, + const Instruction& referenced_from_inst) { + if (spvIsWebGPUEnv(_.context()->target_env)) { const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst); if (storage_class != SpvStorageClassMax && storage_class != SpvStorageClassInput) { return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) - << "Vulkan spec allows BuiltIn VertexIndex to be only used for " + << "WebGPU spec allows BuiltIn LocalInvocationIndex to be only " + "used for variables with Input storage class. " + << GetReferenceDesc(decoration, built_in_inst, referenced_inst, + referenced_from_inst) + << " " << GetStorageClassDesc(referenced_from_inst); + } + + for (const SpvExecutionModel execution_model : execution_models_) { + if (execution_model != SpvExecutionModelGLCompute) { + return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << "WebGPU spec allows BuiltIn VertexIndex to be used only " + "with GLCompute 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::ValidateLocalInvocationIndexAtReference, + this, decoration, built_in_inst, referenced_from_inst, + std::placeholders::_1)); + } + + return SPV_SUCCESS; +} + +spv_result_t BuiltInsValidator::ValidateVertexIndexAtReference( + const Decoration& decoration, const Instruction& built_in_inst, + const Instruction& referenced_inst, + const Instruction& referenced_from_inst) { + if (spvIsVulkanOrWebGPUEnv(_.context()->target_env)) { + const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst); + if (storage_class != SpvStorageClassMax && + storage_class != SpvStorageClassInput) { + return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << spvLogStringForEnv(_.context()->target_env) + << " spec allows BuiltIn VertexIndex to be only used for " "variables with Input storage class. " << GetReferenceDesc(decoration, built_in_inst, referenced_inst, referenced_from_inst) @@ -2093,8 +2389,8 @@ spv_result_t BuiltInsValidator::ValidateVertexIndexAtReference( for (const SpvExecutionModel execution_model : execution_models_) { if (execution_model != SpvExecutionModelVertex) { return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) - << "Vulkan spec allows BuiltIn VertexIndex to be used only " - "with " + << spvLogStringForEnv(_.context()->target_env) + << " spec allows BuiltIn VertexIndex to be used only with " "Vertex execution model. " << GetReferenceDesc(decoration, built_in_inst, referenced_inst, referenced_from_inst, execution_model); @@ -2115,17 +2411,37 @@ spv_result_t BuiltInsValidator::ValidateVertexIndexAtReference( spv_result_t BuiltInsValidator::ValidateLayerOrViewportIndexAtDefinition( const Decoration& decoration, const Instruction& inst) { if (spvIsVulkanEnv(_.context()->target_env)) { - if (spv_result_t error = ValidateI32( - decoration, inst, - [this, &decoration, - &inst](const std::string& message) -> spv_result_t { - return _.diag(SPV_ERROR_INVALID_DATA, &inst) - << "According to the Vulkan spec BuiltIn " - << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, - decoration.params()[0]) - << "variable needs to be a 32-bit int scalar. " << message; - })) { - return error; + // This can be a per-primitive variable for mesh shader stage. + // In such cases variable will have an array of 32-bit integers. + if (decoration.struct_member_index() != Decoration::kInvalidMember) { + // This must be a 32-bit int scalar. + if (spv_result_t error = ValidateI32( + decoration, inst, + [this, &decoration, + &inst](const std::string& message) -> spv_result_t { + return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << "According to the Vulkan spec BuiltIn " + << _.grammar().lookupOperandName( + SPV_OPERAND_TYPE_BUILT_IN, decoration.params()[0]) + << "variable needs to be a 32-bit int scalar. " + << message; + })) { + return error; + } + } else { + if (spv_result_t error = ValidateOptionalArrayedI32( + decoration, inst, + [this, &decoration, + &inst](const std::string& message) -> spv_result_t { + return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << "According to the Vulkan spec BuiltIn " + << _.grammar().lookupOperandName( + SPV_OPERAND_TYPE_BUILT_IN, decoration.params()[0]) + << "variable needs to be a 32-bit int scalar. " + << message; + })) { + return error; + } } } @@ -2187,20 +2503,21 @@ spv_result_t BuiltInsValidator::ValidateLayerOrViewportIndexAtReference( for (const SpvExecutionModel execution_model : execution_models_) { switch (execution_model) { case SpvExecutionModelGeometry: - case SpvExecutionModelFragment: { + case SpvExecutionModelFragment: + case SpvExecutionModelMeshNV: // Ok. break; - case SpvExecutionModelVertex: - case SpvExecutionModelTessellationEvaluation: - if (!_.HasCapability(SpvCapabilityShaderViewportIndexLayerEXT)) { - return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) - << "Using BuiltIn " - << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, - decoration.params()[0]) - << " in Vertex or Tessellation execution model requires " - "the ShaderViewportIndexLayerEXT capability."; - } - break; + case SpvExecutionModelVertex: + case SpvExecutionModelTessellationEvaluation: { + if (!_.HasCapability(SpvCapabilityShaderViewportIndexLayerEXT)) { + return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << "Using BuiltIn " + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, + decoration.params()[0]) + << " in Vertex or Tessellation execution model requires " + "the ShaderViewportIndexLayerEXT capability."; + } + break; } default: { return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) @@ -2229,13 +2546,15 @@ spv_result_t BuiltInsValidator::ValidateLayerOrViewportIndexAtReference( spv_result_t BuiltInsValidator::ValidateComputeShaderI32Vec3InputAtDefinition( const Decoration& decoration, const Instruction& inst) { - if (spvIsVulkanEnv(_.context()->target_env)) { + if (spvIsVulkanOrWebGPUEnv(_.context()->target_env)) { if (spv_result_t error = ValidateI32Vec( decoration, inst, 3, [this, &decoration, &inst](const std::string& message) -> spv_result_t { return _.diag(SPV_ERROR_INVALID_DATA, &inst) - << "According to the Vulkan spec BuiltIn " + << "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 " @@ -2255,12 +2574,13 @@ spv_result_t BuiltInsValidator::ValidateComputeShaderI32Vec3InputAtReference( const Decoration& decoration, const Instruction& built_in_inst, const Instruction& referenced_inst, const Instruction& referenced_from_inst) { - if (spvIsVulkanEnv(_.context()->target_env)) { + if (spvIsVulkanOrWebGPUEnv(_.context()->target_env)) { const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst); if (storage_class != SpvStorageClassMax && storage_class != SpvStorageClassInput) { return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) - << "Vulkan spec allows BuiltIn " + << spvLogStringForEnv(_.context()->target_env) + << " spec allows BuiltIn " << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, decoration.params()[0]) << " to be only used for variables with Input storage class. " @@ -2270,9 +2590,15 @@ spv_result_t BuiltInsValidator::ValidateComputeShaderI32Vec3InputAtReference( } for (const SpvExecutionModel execution_model : execution_models_) { - if (execution_model != SpvExecutionModelGLCompute) { + bool has_vulkan_model = execution_model == SpvExecutionModelGLCompute || + execution_model == SpvExecutionModelTaskNV || + execution_model == SpvExecutionModelMeshNV; + bool has_webgpu_model = execution_model == SpvExecutionModelGLCompute; + if ((spvIsVulkanEnv(_.context()->target_env) && !has_vulkan_model) || + (spvIsWebGPUEnv(_.context()->target_env) && !has_webgpu_model)) { return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) - << "Vulkan spec allows BuiltIn " + << spvLogStringForEnv(_.context()->target_env) + << " spec allows BuiltIn " << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, decoration.params()[0]) << " to be used only with GLCompute execution model. " @@ -2293,10 +2619,176 @@ spv_result_t BuiltInsValidator::ValidateComputeShaderI32Vec3InputAtReference( return SPV_SUCCESS; } -spv_result_t BuiltInsValidator::ValidateWorkgroupSizeAtDefinition( +spv_result_t BuiltInsValidator::ValidateComputeI32InputAtDefinition( const Decoration& decoration, const Instruction& inst) { if (spvIsVulkanEnv(_.context()->target_env)) { - if (!spvOpcodeIsConstant(inst.opcode())) { + if (decoration.struct_member_index() != Decoration::kInvalidMember) { + return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << "BuiltIn " + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, + decoration.params()[0]) + << " cannot be used as a member decoration "; + } + if (spv_result_t error = ValidateI32( + decoration, inst, + [this, &decoration, + &inst](const std::string& message) -> spv_result_t { + return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << "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 " + "vector. " + << message; + })) { + return error; + } + } + + // Seed at reference checks with this built-in. + return ValidateComputeI32InputAtReference(decoration, inst, inst, inst); +} + +spv_result_t BuiltInsValidator::ValidateComputeI32InputAtReference( + const Decoration& decoration, const Instruction& built_in_inst, + const Instruction& referenced_inst, + const Instruction& referenced_from_inst) { + if (spvIsVulkanEnv(_.context()->target_env)) { + const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst); + if (storage_class != SpvStorageClassMax && + storage_class != SpvStorageClassInput) { + return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << spvLogStringForEnv(_.context()->target_env) + << " spec allows BuiltIn " + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, + decoration.params()[0]) + << " to be only used for variables with Input storage class. " + << GetReferenceDesc(decoration, built_in_inst, referenced_inst, + referenced_from_inst) + << " " << GetStorageClassDesc(referenced_from_inst); + } + + for (const SpvExecutionModel execution_model : execution_models_) { + bool has_vulkan_model = execution_model == SpvExecutionModelGLCompute || + execution_model == SpvExecutionModelTaskNV || + execution_model == SpvExecutionModelMeshNV; + if (spvIsVulkanEnv(_.context()->target_env) && !has_vulkan_model) { + return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << spvLogStringForEnv(_.context()->target_env) + << " spec allows BuiltIn " + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, + decoration.params()[0]) + << " to be used only with GLCompute 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::ValidateComputeI32InputAtReference, this, + decoration, built_in_inst, referenced_from_inst, + std::placeholders::_1)); + } + + return SPV_SUCCESS; +} + +spv_result_t BuiltInsValidator::ValidateI32InputAtDefinition( + const Decoration& decoration, const Instruction& inst) { + if (spvIsVulkanEnv(_.context()->target_env)) { + if (decoration.struct_member_index() != Decoration::kInvalidMember) { + return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << "BuiltIn " + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, + decoration.params()[0]) + << " cannot be used as a member decoration "; + } + if (spv_result_t error = ValidateI32( + decoration, inst, + [this, &decoration, + &inst](const std::string& message) -> spv_result_t { + return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << "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. " << message; + })) { + return error; + } + + const SpvStorageClass storage_class = GetStorageClass(inst); + if (storage_class != SpvStorageClassMax && + storage_class != SpvStorageClassInput) { + return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << spvLogStringForEnv(_.context()->target_env) + << " spec allows BuiltIn " + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, + decoration.params()[0]) + << " to be only used for variables with Input storage class. " + << GetReferenceDesc(decoration, inst, inst, inst) << " " + << GetStorageClassDesc(inst); + } + } + + return SPV_SUCCESS; +} + +spv_result_t BuiltInsValidator::ValidateI32Vec4InputAtDefinition( + const Decoration& decoration, const Instruction& inst) { + if (spvIsVulkanEnv(_.context()->target_env)) { + if (decoration.struct_member_index() != Decoration::kInvalidMember) { + return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << "BuiltIn " + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, + decoration.params()[0]) + << " cannot be used as a member decoration "; + } + if (spv_result_t error = ValidateI32Vec( + decoration, inst, 4, + [this, &decoration, + &inst](const std::string& message) -> spv_result_t { + return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << "According to the " + << spvLogStringForEnv(_.context()->target_env) + << " spec BuiltIn " + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, + decoration.params()[0]) + << " variable needs to be a 4-component 32-bit int " + "vector. " + << message; + })) { + return error; + } + + const SpvStorageClass storage_class = GetStorageClass(inst); + if (storage_class != SpvStorageClassMax && + storage_class != SpvStorageClassInput) { + return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << spvLogStringForEnv(_.context()->target_env) + << " spec allows BuiltIn " + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, + decoration.params()[0]) + << " to be only used for variables with Input storage class. " + << GetReferenceDesc(decoration, inst, inst, inst) << " " + << GetStorageClassDesc(inst); + } + } + + return SPV_SUCCESS; +} + +spv_result_t BuiltInsValidator::ValidateWorkgroupSizeAtDefinition( + const Decoration& decoration, const Instruction& inst) { + if (spvIsVulkanOrWebGPUEnv(_.context()->target_env)) { + if (spvIsVulkanEnv(_.context()->target_env) && + !spvOpcodeIsConstant(inst.opcode())) { return _.diag(SPV_ERROR_INVALID_DATA, &inst) << "Vulkan spec requires BuiltIn WorkgroupSize to be a " "constant. " @@ -2307,9 +2799,10 @@ spv_result_t BuiltInsValidator::ValidateWorkgroupSizeAtDefinition( decoration, inst, 3, [this, &inst](const std::string& message) -> spv_result_t { return _.diag(SPV_ERROR_INVALID_DATA, &inst) - << "According to the Vulkan spec BuiltIn WorkgroupSize " - "variable " - "needs to be a 3-component 32-bit int vector. " + << "According to the " + << spvLogStringForEnv(_.context()->target_env) + << " spec BuiltIn WorkgroupSize variable needs to be a " + "3-component 32-bit int vector. " << message; })) { return error; @@ -2324,11 +2817,12 @@ spv_result_t BuiltInsValidator::ValidateWorkgroupSizeAtReference( const Decoration& decoration, const Instruction& built_in_inst, const Instruction& referenced_inst, const Instruction& referenced_from_inst) { - if (spvIsVulkanEnv(_.context()->target_env)) { + if (spvIsVulkanOrWebGPUEnv(_.context()->target_env)) { for (const SpvExecutionModel execution_model : execution_models_) { if (execution_model != SpvExecutionModelGLCompute) { return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) - << "Vulkan spec allows BuiltIn " + << spvLogStringForEnv(_.context()->target_env) + << " spec allows BuiltIn " << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, decoration.params()[0]) << " to be used only with GLCompute execution model. " @@ -2348,9 +2842,93 @@ spv_result_t BuiltInsValidator::ValidateWorkgroupSizeAtReference( return SPV_SUCCESS; } +spv_result_t BuiltInsValidator::ValidateSMBuiltinsAtDefinition( + const Decoration& decoration, const Instruction& inst) { + if (spvIsVulkanEnv(_.context()->target_env)) { + if (spv_result_t error = ValidateI32( + decoration, inst, + [this, &inst, + &decoration](const std::string& message) -> spv_result_t { + return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << "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 scalar. " + << message; + })) { + return error; + } + } + + // Seed at reference checks with this built-in. + return ValidateSMBuiltinsAtReference(decoration, inst, inst, inst); +} + +spv_result_t BuiltInsValidator::ValidateSMBuiltinsAtReference( + const Decoration& decoration, const Instruction& built_in_inst, + const Instruction& referenced_inst, + const Instruction& referenced_from_inst) { + if (spvIsVulkanEnv(_.context()->target_env)) { + const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst); + if (storage_class != SpvStorageClassMax && + storage_class != SpvStorageClassInput) { + return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << spvLogStringForEnv(_.context()->target_env) + << " spec allows BuiltIn " + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, + decoration.params()[0]) + << " to be only used for " + "variables with Input storage class. " + << GetReferenceDesc(decoration, built_in_inst, referenced_inst, + referenced_from_inst) + << " " << GetStorageClassDesc(referenced_from_inst); + } + } + + 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::ValidateSMBuiltinsAtReference, 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 SpvBuiltIn label = SpvBuiltIn(decoration.params()[0]); + + // Builtins can only be applied to variables, structures or constants. + auto target_opcode = inst.opcode(); + if (target_opcode != SpvOpTypeStruct && target_opcode != SpvOpVariable && + !spvOpcodeIsConstant(target_opcode)) { + return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << "BuiltIns can only target variables, structs or constants"; + } + + if (!spvIsVulkanOrWebGPUEnv(_.context()->target_env)) { + // Early return. All currently implemented rules are based on Vulkan or + // WebGPU spec. + // + // TODO: If you are adding validation rules for environments other than + // Vulkan or WebGPU (or general rules which are not environment + // independent), then you need to modify or remove this condition. Consider + // also adding early returns into BuiltIn-specific rules, so that the system + // doesn't spawn new rules which don't do anything. + return SPV_SUCCESS; + } + + if (spvIsWebGPUEnv(_.context()->target_env) && + !IsBuiltInValidForWebGPU(label)) { + return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << "WebGPU does not allow BuiltIn " + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, + decoration.params()[0]); + } + // If you are adding a new BuiltIn enum, please register it here. // If the newly added enum has validation rules associated with it // consider leaving a TODO and/or creating an issue. @@ -2411,6 +2989,21 @@ spv_result_t BuiltInsValidator::ValidateSingleBuiltInAtDefinition( case SpvBuiltInSamplePosition: { return ValidateSamplePositionAtDefinition(decoration, inst); } + case SpvBuiltInSubgroupId: + case SpvBuiltInNumSubgroups: { + return ValidateComputeI32InputAtDefinition(decoration, inst); + } + case SpvBuiltInSubgroupLocalInvocationId: + case SpvBuiltInSubgroupSize: { + return ValidateI32InputAtDefinition(decoration, inst); + } + case SpvBuiltInSubgroupEqMask: + case SpvBuiltInSubgroupGeMask: + case SpvBuiltInSubgroupGtMask: + case SpvBuiltInSubgroupLeMask: + case SpvBuiltInSubgroupLtMask: { + return ValidateI32Vec4InputAtDefinition(decoration, inst); + } case SpvBuiltInTessCoord: { return ValidateTessCoordAtDefinition(decoration, inst); } @@ -2427,24 +3020,25 @@ spv_result_t BuiltInsValidator::ValidateSingleBuiltInAtDefinition( return ValidateWorkgroupSizeAtDefinition(decoration, inst); } case SpvBuiltInVertexId: - case SpvBuiltInInstanceId: - case SpvBuiltInLocalInvocationIndex: + case SpvBuiltInInstanceId: { + return ValidateVertexIdOrInstanceIdAtDefinition(decoration, inst); + } + case SpvBuiltInLocalInvocationIndex: { + return ValidateLocalInvocationIndexAtDefinition(decoration, inst); + } + case SpvBuiltInWarpsPerSMNV: + case SpvBuiltInSMCountNV: + case SpvBuiltInWarpIDNV: + case SpvBuiltInSMIDNV: { + return ValidateSMBuiltinsAtDefinition(decoration, inst); + } case SpvBuiltInWorkDim: case SpvBuiltInGlobalSize: case SpvBuiltInEnqueuedWorkgroupSize: case SpvBuiltInGlobalOffset: case SpvBuiltInGlobalLinearId: - case SpvBuiltInSubgroupSize: case SpvBuiltInSubgroupMaxSize: - case SpvBuiltInNumSubgroups: case SpvBuiltInNumEnqueuedSubgroups: - case SpvBuiltInSubgroupId: - case SpvBuiltInSubgroupLocalInvocationId: - case SpvBuiltInSubgroupEqMaskKHR: - case SpvBuiltInSubgroupGeMaskKHR: - case SpvBuiltInSubgroupGtMaskKHR: - case SpvBuiltInSubgroupLeMaskKHR: - case SpvBuiltInSubgroupLtMaskKHR: case SpvBuiltInBaseVertex: case SpvBuiltInBaseInstance: case SpvBuiltInDrawIndex: @@ -2464,7 +3058,34 @@ spv_result_t BuiltInsValidator::ValidateSingleBuiltInAtDefinition( case SpvBuiltInPositionPerViewNV: case SpvBuiltInViewportMaskPerViewNV: case SpvBuiltInFullyCoveredEXT: - case SpvBuiltInMax: { + case SpvBuiltInMax: + case SpvBuiltInTaskCountNV: + case SpvBuiltInPrimitiveCountNV: + case SpvBuiltInPrimitiveIndicesNV: + case SpvBuiltInClipDistancePerViewNV: + case SpvBuiltInCullDistancePerViewNV: + case SpvBuiltInLayerPerViewNV: + case SpvBuiltInMeshViewCountNV: + case SpvBuiltInMeshViewIndicesNV: + case SpvBuiltInBaryCoordNV: + case SpvBuiltInBaryCoordNoPerspNV: + case SpvBuiltInFragmentSizeNV: // alias SpvBuiltInFragSizeEXT + case SpvBuiltInInvocationsPerPixelNV: // alias + // SpvBuiltInFragInvocationCountEXT + case SpvBuiltInLaunchIdNV: + case SpvBuiltInLaunchSizeNV: + case SpvBuiltInWorldRayOriginNV: + case SpvBuiltInWorldRayDirectionNV: + case SpvBuiltInObjectRayOriginNV: + case SpvBuiltInObjectRayDirectionNV: + case SpvBuiltInRayTminNV: + case SpvBuiltInRayTmaxNV: + case SpvBuiltInInstanceCustomIndexNV: + case SpvBuiltInObjectToWorldNV: + case SpvBuiltInWorldToObjectNV: + case SpvBuiltInHitTNV: + case SpvBuiltInHitKindNV: + case SpvBuiltInIncomingRayFlagsNV: { // No validation rules (for the moment). break; } @@ -2554,18 +3175,7 @@ spv_result_t BuiltInsValidator::Run() { } // namespace // Validates correctness of built-in variables. -spv_result_t ValidateBuiltIns(const ValidationState_t& _) { - if (!spvIsVulkanEnv(_.context()->target_env)) { - // Early return. All currently implemented rules are based on Vulkan spec. - // - // TODO: If you are adding validation rules for environments other than - // Vulkan (or general rules which are not environment independent), then you - // need to modify or remove this condition. Consider also adding early - // returns into BuiltIn-specific rules, so that the system doesn't spawn new - // rules which don't do anything. - return SPV_SUCCESS; - } - +spv_result_t ValidateBuiltIns(ValidationState_t& _) { BuiltInsValidator validator(_); return validator.Run(); } diff --git a/third_party/spirv-tools/source/val/validate_capability.cpp b/third_party/spirv-tools/source/val/validate_capability.cpp index 4724b9f79d..8a356bf7f0 100644 --- a/third_party/spirv-tools/source/val/validate_capability.cpp +++ b/third_party/spirv-tools/source/val/validate_capability.cpp @@ -55,6 +55,15 @@ bool IsSupportGuaranteedVulkan_1_1(uint32_t capability) { return false; } +bool IsSupportGuaranteedVulkan_1_2(uint32_t capability) { + if (IsSupportGuaranteedVulkan_1_1(capability)) return true; + switch (capability) { + case SpvCapabilityShaderNonUniform: + return true; + } + return false; +} + bool IsSupportOptionalVulkan_1_0(uint32_t capability) { switch (capability) { case SpvCapabilityGeometry: @@ -83,6 +92,11 @@ bool IsSupportOptionalVulkan_1_0(uint32_t capability) { case SpvCapabilityStorageImageReadWithoutFormat: case SpvCapabilityStorageImageWriteWithoutFormat: case SpvCapabilityMultiViewport: + case SpvCapabilityInt64Atomics: + case SpvCapabilityTransformFeedback: + case SpvCapabilityGeometryStreams: + case SpvCapabilityFloat16: + case SpvCapabilityInt8: return true; } return false; @@ -116,6 +130,38 @@ bool IsSupportOptionalVulkan_1_1(uint32_t capability) { return false; } +bool IsSupportOptionalVulkan_1_2(uint32_t capability) { + if (IsSupportOptionalVulkan_1_1(capability)) return true; + + switch (capability) { + case SpvCapabilityDenormPreserve: + case SpvCapabilityDenormFlushToZero: + case SpvCapabilitySignedZeroInfNanPreserve: + case SpvCapabilityRoundingModeRTE: + case SpvCapabilityRoundingModeRTZ: + case SpvCapabilityVulkanMemoryModel: + case SpvCapabilityVulkanMemoryModelDeviceScope: + case SpvCapabilityStorageBuffer8BitAccess: + case SpvCapabilityUniformAndStorageBuffer8BitAccess: + case SpvCapabilityStoragePushConstant8: + case SpvCapabilityShaderViewportIndex: + case SpvCapabilityShaderLayer: + case SpvCapabilityPhysicalStorageBufferAddresses: + case SpvCapabilityRuntimeDescriptorArray: + case SpvCapabilityUniformTexelBufferArrayDynamicIndexing: + case SpvCapabilityStorageTexelBufferArrayDynamicIndexing: + case SpvCapabilityUniformBufferArrayNonUniformIndexing: + case SpvCapabilitySampledImageArrayNonUniformIndexing: + case SpvCapabilityStorageBufferArrayNonUniformIndexing: + case SpvCapabilityStorageImageArrayNonUniformIndexing: + case SpvCapabilityInputAttachmentArrayNonUniformIndexing: + case SpvCapabilityUniformTexelBufferArrayNonUniformIndexing: + case SpvCapabilityStorageTexelBufferArrayNonUniformIndexing: + return true; + } + return false; +} + bool IsSupportGuaranteedOpenCL_1_2(uint32_t capability, bool embedded_profile) { switch (capability) { case SpvCapabilityAddresses: @@ -217,6 +263,19 @@ bool IsEnabledByCapabilityOpenCL_2_0(ValidationState_t& _, return false; } +bool IsSupportGuaranteedWebGPU(uint32_t capability) { + switch (capability) { + case SpvCapabilityMatrix: + case SpvCapabilityShader: + case SpvCapabilitySampled1D: + case SpvCapabilityImage1D: + case SpvCapabilityDerivativeControl: + case SpvCapabilityImageQuery: + return true; + } + return false; +} + } // namespace // Validates that capability declarations use operands allowed in the current @@ -266,6 +325,15 @@ spv_result_t CapabilityPass(ValidationState_t& _, const Instruction* inst) { << " is not allowed by Vulkan 1.1 specification" << " (or requires extension)"; } + } else if (env == SPV_ENV_VULKAN_1_2) { + if (!IsSupportGuaranteedVulkan_1_2(capability) && + !IsSupportOptionalVulkan_1_2(capability) && + !IsEnabledByExtension(_, capability)) { + return _.diag(SPV_ERROR_INVALID_CAPABILITY, inst) + << "Capability " << capability_str() + << " is not allowed by Vulkan 1.2 specification" + << " (or requires extension)"; + } } else if (env == SPV_ENV_OPENCL_1_2 || env == SPV_ENV_OPENCL_EMBEDDED_1_2) { if (!IsSupportGuaranteedOpenCL_1_2(capability, opencl_embedded) && !IsSupportOptionalOpenCL_1_2(capability) && @@ -300,6 +368,14 @@ spv_result_t CapabilityPass(ValidationState_t& _, const Instruction* inst) { << " Profile specification" << " (or requires extension or capability)"; } + } else if (env == SPV_ENV_WEBGPU_0) { + if (!IsSupportGuaranteedWebGPU(capability) && + !IsEnabledByExtension(_, capability)) { + return _.diag(SPV_ERROR_INVALID_CAPABILITY, inst) + << "Capability " << capability_str() + << " is not allowed by WebGPU specification" + << " (or requires extension)"; + } } return SPV_SUCCESS; diff --git a/third_party/spirv-tools/source/val/validate_cfg.cpp b/third_party/spirv-tools/source/val/validate_cfg.cpp index 167f227358..f3019d17fe 100644 --- a/third_party/spirv-tools/source/val/validate_cfg.cpp +++ b/third_party/spirv-tools/source/val/validate_cfg.cpp @@ -12,8 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "source/val/validate.h" - #include #include #include @@ -29,10 +27,12 @@ #include "source/cfa.h" #include "source/opcode.h" +#include "source/spirv_target_env.h" #include "source/spirv_validator_options.h" #include "source/val/basic_block.h" #include "source/val/construct.h" #include "source/val/function.h" +#include "source/val/validate.h" #include "source/val/validation_state.h" namespace spvtools { @@ -40,13 +40,6 @@ namespace val { namespace { spv_result_t ValidatePhi(ValidationState_t& _, const Instruction* inst) { - SpvOp type_op = _.GetIdOpcode(inst->type_id()); - if (!spvOpcodeGeneratesType(type_op)) { - return _.diag(SPV_ERROR_INVALID_ID, inst) - << "OpPhi's type " << _.getIdName(inst->type_id()) - << " is not a type instruction."; - } - auto block = inst->block(); size_t num_in_ops = inst->words().size() - 3; if (num_in_ops % 2 != 0) { @@ -55,6 +48,20 @@ spv_result_t ValidatePhi(ValidationState_t& _, const Instruction* inst) { "basic blocks."; } + const Instruction* type_inst = _.FindDef(inst->type_id()); + assert(type_inst); + + const SpvOp type_opcode = type_inst->opcode(); + if (type_opcode == SpvOpTypePointer && + _.addressing_model() == SpvAddressingModelLogical) { + if (!_.features().variable_pointers && + !_.features().variable_pointers_storage_buffer) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Using pointers with OpPhi requires capability " + << "VariablePointers or VariablePointersStorageBuffer"; + } + } + // Create a uniqued vector of predecessor ids for comparison against // incoming values. OpBranchConditional %cond %label %label produces two // predecessors in the CFG. @@ -105,6 +112,19 @@ spv_result_t ValidatePhi(ValidationState_t& _, const Instruction* inst) { return SPV_SUCCESS; } +spv_result_t ValidateBranch(ValidationState_t& _, const Instruction* inst) { + // target operands must be OpLabel + const auto id = inst->GetOperandAs(0); + const auto target = _.FindDef(id); + if (!target || SpvOpLabel != target->opcode()) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "'Target Label' operands for OpBranch must be the ID " + "of an OpLabel instruction"; + } + + return SPV_SUCCESS; +} + spv_result_t ValidateBranchConditional(ValidationState_t& _, const Instruction* inst) { // num_operands is either 3 or 5 --- if 5, the last two need to be literal @@ -118,7 +138,8 @@ spv_result_t ValidateBranchConditional(ValidationState_t& _, // grab the condition operand and check that it is a bool const auto cond_id = inst->GetOperandAs(0); const auto cond_op = _.FindDef(cond_id); - if (!cond_op || !_.IsBoolScalarType(cond_op->type_id())) { + if (!cond_op || !cond_op->type_id() || + !_.IsBoolScalarType(cond_op->type_id())) { return _.diag(SPV_ERROR_INVALID_ID, inst) << "Condition operand for " "OpBranchConditional must be " "of boolean type"; @@ -147,6 +168,26 @@ spv_result_t ValidateBranchConditional(ValidationState_t& _, return SPV_SUCCESS; } +spv_result_t ValidateSwitch(ValidationState_t& _, const Instruction* inst) { + const auto num_operands = inst->operands().size(); + // At least two operands (selector, default), any more than that are + // literal/target. + + // target operands must be OpLabel + for (size_t i = 2; i < num_operands; i += 2) { + // literal, id + const auto id = inst->GetOperandAs(i + 1); + const auto target = _.FindDef(id); + if (!target || SpvOpLabel != target->opcode()) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "'Target Label' operands for OpSwitch must be IDs of an " + "OpLabel instruction"; + } + } + + return SPV_SUCCESS; +} + spv_result_t ValidateReturnValue(ValidationState_t& _, const Instruction* inst) { const auto value_id = inst->GetOperandAs(0); @@ -188,6 +229,82 @@ spv_result_t ValidateReturnValue(ValidationState_t& _, return SPV_SUCCESS; } +spv_result_t ValidateLoopMerge(ValidationState_t& _, const Instruction* inst) { + const auto merge_id = inst->GetOperandAs(0); + const auto merge = _.FindDef(merge_id); + if (!merge || merge->opcode() != SpvOpLabel) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Merge Block " << _.getIdName(merge_id) << " must be an OpLabel"; + } + if (merge_id == inst->block()->id()) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Merge Block may not be the block containing the OpLoopMerge\n"; + } + + const auto continue_id = inst->GetOperandAs(1); + const auto continue_target = _.FindDef(continue_id); + if (!continue_target || continue_target->opcode() != SpvOpLabel) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Continue Target " << _.getIdName(continue_id) + << " must be an OpLabel"; + } + + if (merge_id == continue_id) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Merge Block and Continue Target must be different ids"; + } + + const auto loop_control = inst->GetOperandAs(2); + if ((loop_control >> SpvLoopControlUnrollShift) & 0x1 && + (loop_control >> SpvLoopControlDontUnrollShift) & 0x1) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Unroll and DontUnroll loop controls must not both be specified"; + } + if ((loop_control >> SpvLoopControlDontUnrollShift) & 0x1 && + (loop_control >> SpvLoopControlPeelCountShift) & 0x1) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) << "PeelCount and DontUnroll " + "loop controls must not " + "both be specified"; + } + if ((loop_control >> SpvLoopControlDontUnrollShift) & 0x1 && + (loop_control >> SpvLoopControlPartialCountShift) & 0x1) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) << "PartialCount and " + "DontUnroll loop controls " + "must not both be specified"; + } + + uint32_t operand = 3; + if ((loop_control >> SpvLoopControlDependencyLengthShift) & 0x1) { + ++operand; + } + if ((loop_control >> SpvLoopControlMinIterationsShift) & 0x1) { + ++operand; + } + if ((loop_control >> SpvLoopControlMaxIterationsShift) & 0x1) { + ++operand; + } + if ((loop_control >> SpvLoopControlIterationMultipleShift) & 0x1) { + if (inst->operands().size() < operand || + inst->GetOperandAs(operand) == 0) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) << "IterationMultiple loop " + "control operand must be " + "greater than zero"; + } + ++operand; + } + if ((loop_control >> SpvLoopControlPeelCountShift) & 0x1) { + ++operand; + } + if ((loop_control >> SpvLoopControlPartialCountShift) & 0x1) { + ++operand; + } + + // That the right number of operands is present is checked by the parser. The + // above code tracks operands for expanded validation checking in the future. + + return SPV_SUCCESS; +} + } // namespace void printDominatorList(const BasicBlock& b) { @@ -303,9 +420,9 @@ std::string ConstructErrorString(const Construct& construct, // |case_fall_through|. Returns SPV_ERROR_INVALID_CFG if the case construct // headed by |target_block| branches to multiple case constructs. spv_result_t FindCaseFallThrough( - const ValidationState_t& _, BasicBlock* target_block, - uint32_t* case_fall_through, const BasicBlock* merge, - const std::unordered_set& case_targets, Function* function) { + ValidationState_t& _, BasicBlock* target_block, uint32_t* case_fall_through, + const BasicBlock* merge, const std::unordered_set& case_targets, + Function* function) { std::vector stack; stack.push_back(target_block); std::unordered_set visited; @@ -343,7 +460,9 @@ spv_result_t FindCaseFallThrough( } if (*case_fall_through == 0u) { - *case_fall_through = block->id(); + if (target_block != block) { + *case_fall_through = block->id(); + } } else if (*case_fall_through != block->id()) { // Case construct has at most one branch to another case construct. return _.diag(SPV_ERROR_INVALID_CFG, target_block->label()) @@ -359,8 +478,7 @@ spv_result_t FindCaseFallThrough( return SPV_SUCCESS; } -spv_result_t StructuredSwitchChecks(const ValidationState_t& _, - Function* function, +spv_result_t StructuredSwitchChecks(ValidationState_t& _, Function* function, const Instruction* switch_inst, const BasicBlock* header, const BasicBlock* merge) { @@ -374,41 +492,54 @@ spv_result_t StructuredSwitchChecks(const ValidationState_t& _, std::map num_fall_through_targeted; uint32_t default_case_fall_through = 0u; uint32_t default_target = switch_inst->GetOperandAs(1u); - std::unordered_set seen; + bool default_appears_multiple_times = false; + for (uint32_t i = 3; i < switch_inst->operands().size(); i += 2) { + if (default_target == switch_inst->GetOperandAs(i)) { + default_appears_multiple_times = true; + break; + } + } + std::unordered_map seen_to_fall_through; for (uint32_t i = 1; i < switch_inst->operands().size(); i += 2) { uint32_t target = switch_inst->GetOperandAs(i); if (target == merge->id()) continue; - if (!seen.insert(target).second) continue; - - const auto target_block = function->GetBlock(target).first; - // OpSwitch must dominate all its case constructs. - if (header->reachable() && target_block->reachable() && - !header->dominates(*target_block)) { - return _.diag(SPV_ERROR_INVALID_CFG, header->label()) - << "Selection header " << _.getIdName(header->id()) - << " does not dominate its case construct " << _.getIdName(target); - } - uint32_t case_fall_through = 0u; - if (auto error = FindCaseFallThrough(_, target_block, &case_fall_through, - merge, case_targets, function)) { - return error; - } - - // Track how many time the fall through case has been targeted. - if (case_fall_through != 0u) { - auto where = num_fall_through_targeted.lower_bound(case_fall_through); - if (where == num_fall_through_targeted.end() || - where->first != case_fall_through) { - num_fall_through_targeted.insert(where, - std::make_pair(case_fall_through, 1)); - } else { - where->second++; + auto seen_iter = seen_to_fall_through.find(target); + if (seen_iter == seen_to_fall_through.end()) { + const auto target_block = function->GetBlock(target).first; + // OpSwitch must dominate all its case constructs. + if (header->reachable() && target_block->reachable() && + !header->dominates(*target_block)) { + return _.diag(SPV_ERROR_INVALID_CFG, header->label()) + << "Selection header " << _.getIdName(header->id()) + << " does not dominate its case construct " + << _.getIdName(target); } + + if (auto error = FindCaseFallThrough(_, target_block, &case_fall_through, + merge, case_targets, function)) { + return error; + } + + // Track how many time the fall through case has been targeted. + if (case_fall_through != 0u) { + auto where = num_fall_through_targeted.lower_bound(case_fall_through); + if (where == num_fall_through_targeted.end() || + where->first != case_fall_through) { + num_fall_through_targeted.insert( + where, std::make_pair(case_fall_through, 1)); + } else { + where->second++; + } + } + seen_to_fall_through.insert(std::make_pair(target, case_fall_through)); + } else { + case_fall_through = seen_iter->second; } - if (case_fall_through == default_target) { + if (case_fall_through == default_target && + !default_appears_multiple_times) { case_fall_through = default_case_fall_through; } if (case_fall_through != 0u) { @@ -458,9 +589,68 @@ spv_result_t StructuredSwitchChecks(const ValidationState_t& _, return SPV_SUCCESS; } +// Validates that all CFG divergences (i.e. conditional branch or switch) are +// structured correctly. Either divergence is preceded by a merge instruction +// or the divergence introduces at most one unseen label. +spv_result_t ValidateStructuredSelections( + ValidationState_t& _, const std::vector& postorder) { + std::unordered_set seen; + for (auto iter = postorder.rbegin(); iter != postorder.rend(); ++iter) { + const auto* block = *iter; + const auto* terminator = block->terminator(); + if (!terminator) continue; + const auto index = terminator - &_.ordered_instructions()[0]; + auto* merge = &_.ordered_instructions()[index - 1]; + // Marks merges and continues as seen. + if (merge->opcode() == SpvOpSelectionMerge) { + seen.insert(merge->GetOperandAs(0)); + } else if (merge->opcode() == SpvOpLoopMerge) { + seen.insert(merge->GetOperandAs(0)); + seen.insert(merge->GetOperandAs(1)); + } else { + // Only track the pointer if it is a merge instruction. + merge = nullptr; + } + + // Skip unreachable blocks. + if (!block->reachable()) continue; + + if (terminator->opcode() == SpvOpBranchConditional) { + const auto true_label = terminator->GetOperandAs(1); + const auto false_label = terminator->GetOperandAs(2); + // Mark the upcoming blocks as seen now, but only error out if this block + // was missing a merge instruction and both labels hadn't been seen + // previously. + const bool both_unseen = + seen.insert(true_label).second && seen.insert(false_label).second; + if (!merge && both_unseen) { + return _.diag(SPV_ERROR_INVALID_CFG, terminator) + << "Selection must be structured"; + } + } else if (terminator->opcode() == SpvOpSwitch) { + uint32_t count = 0; + // Mark the targets as seen now, but only error out if this block was + // missing a merge instruction and there were multiple unseen labels. + for (uint32_t i = 1; i < terminator->operands().size(); i += 2) { + const auto target = terminator->GetOperandAs(i); + if (seen.insert(target).second) { + count++; + } + } + if (!merge && count > 1) { + return _.diag(SPV_ERROR_INVALID_CFG, terminator) + << "Selection must be structured"; + } + } + } + + return SPV_SUCCESS; +} + spv_result_t StructuredControlFlowChecks( - const ValidationState_t& _, Function* function, - const std::vector>& back_edges) { + ValidationState_t& _, Function* function, + const std::vector>& back_edges, + const std::vector& postorder) { /// Check all backedges target only loop headers and have exactly one /// back-edge branching to it @@ -537,22 +727,53 @@ spv_result_t StructuredControlFlowChecks( } } - // Check that for all non-header blocks, all predecessors are within this - // construct. Construct::ConstructBlockSet construct_blocks = construct.blocks(function); + std::string construct_name, header_name, exit_name; + std::tie(construct_name, header_name, exit_name) = + ConstructNames(construct.type()); for (auto block : construct_blocks) { + // Check that all exits from the construct are via structured exits. + for (auto succ : *block->successors()) { + if (block->reachable() && !construct_blocks.count(succ) && + !construct.IsStructuredExit(_, succ)) { + return _.diag(SPV_ERROR_INVALID_CFG, _.FindDef(block->id())) + << "block " << _.getIdName(block->id()) << " exits the " + << construct_name << " headed by " + << _.getIdName(header->id()) + << ", but not via a structured exit"; + } + } if (block == header) continue; + // Check that for all non-header blocks, all predecessors are within this + // construct. for (auto pred : *block->predecessors()) { if (pred->reachable() && !construct_blocks.count(pred)) { - std::string construct_name, header_name, exit_name; - std::tie(construct_name, header_name, exit_name) = - ConstructNames(construct.type()); return _.diag(SPV_ERROR_INVALID_CFG, _.FindDef(pred->id())) << "block " << pred->id() << " branches to the " << construct_name << " construct, but not to the " << header_name << " " << header->id(); } } + + if (block->is_type(BlockType::kBlockTypeSelection) || + block->is_type(BlockType::kBlockTypeLoop)) { + size_t index = (block->terminator() - &_.ordered_instructions()[0]) - 1; + const auto& merge_inst = _.ordered_instructions()[index]; + if (merge_inst.opcode() == SpvOpSelectionMerge || + merge_inst.opcode() == SpvOpLoopMerge) { + uint32_t merge_id = merge_inst.GetOperandAs(0); + auto merge_block = function->GetBlock(merge_id).first; + if (merge_block->reachable() && + !construct_blocks.count(merge_block)) { + return _.diag(SPV_ERROR_INVALID_CFG, _.FindDef(block->id())) + << "Header block " << _.getIdName(block->id()) + << " is contained in the " << construct_name + << " construct headed by " << _.getIdName(header->id()) + << ", but its merge block " << _.getIdName(merge_id) + << " is not"; + } + } + } } // Checks rules for case constructs. @@ -565,6 +786,125 @@ spv_result_t StructuredControlFlowChecks( } } } + + if (auto error = ValidateStructuredSelections(_, postorder)) { + return error; + } + + return SPV_SUCCESS; +} + +spv_result_t PerformWebGPUCfgChecks(ValidationState_t& _, Function* function) { + for (auto& block : function->ordered_blocks()) { + if (block->reachable()) continue; + if (block->is_type(kBlockTypeMerge)) { + // 1. Find the referencing merge and confirm that it is reachable. + BasicBlock* merge_header = function->GetMergeHeader(block); + assert(merge_header != nullptr); + if (!merge_header->reachable()) { + return _.diag(SPV_ERROR_INVALID_CFG, _.FindDef(block->id())) + << "For WebGPU, unreachable merge-blocks must be referenced by " + "a reachable merge instruction."; + } + + // 2. Check that the only instructions are OpLabel and OpUnreachable. + auto* label_inst = block->label(); + auto* terminator_inst = block->terminator(); + assert(label_inst != nullptr); + assert(terminator_inst != nullptr); + + if (terminator_inst->opcode() != SpvOpUnreachable) { + return _.diag(SPV_ERROR_INVALID_CFG, _.FindDef(block->id())) + << "For WebGPU, unreachable merge-blocks must terminate with " + "OpUnreachable."; + } + + auto label_idx = label_inst - &_.ordered_instructions()[0]; + auto terminator_idx = terminator_inst - &_.ordered_instructions()[0]; + if (label_idx + 1 != terminator_idx) { + return _.diag(SPV_ERROR_INVALID_CFG, _.FindDef(block->id())) + << "For WebGPU, unreachable merge-blocks must only contain an " + "OpLabel and OpUnreachable instruction."; + } + + // 3. Use label instruction to confirm there is no uses by branches. + for (auto use : label_inst->uses()) { + const auto* use_inst = use.first; + if (spvOpcodeIsBranch(use_inst->opcode())) { + return _.diag(SPV_ERROR_INVALID_CFG, _.FindDef(block->id())) + << "For WebGPU, unreachable merge-blocks cannot be the target " + "of a branch."; + } + } + } else if (block->is_type(kBlockTypeContinue)) { + // 1. Find referencing loop and confirm that it is reachable. + std::vector continue_headers = + function->GetContinueHeaders(block); + if (continue_headers.empty()) { + return _.diag(SPV_ERROR_INVALID_CFG, _.FindDef(block->id())) + << "For WebGPU, unreachable continue-target must be referenced " + "by a loop instruction."; + } + + std::vector reachable_headers(continue_headers.size()); + auto iter = + std::copy_if(continue_headers.begin(), continue_headers.end(), + reachable_headers.begin(), + [](BasicBlock* header) { return header->reachable(); }); + reachable_headers.resize(std::distance(reachable_headers.begin(), iter)); + + if (reachable_headers.empty()) { + return _.diag(SPV_ERROR_INVALID_CFG, _.FindDef(block->id())) + << "For WebGPU, unreachable continue-target must be referenced " + "by a reachable loop instruction."; + } + + // 2. Check that the only instructions are OpLabel and OpBranch. + auto* label_inst = block->label(); + auto* terminator_inst = block->terminator(); + assert(label_inst != nullptr); + assert(terminator_inst != nullptr); + + if (terminator_inst->opcode() != SpvOpBranch) { + return _.diag(SPV_ERROR_INVALID_CFG, _.FindDef(block->id())) + << "For WebGPU, unreachable continue-target must terminate with " + "OpBranch."; + } + + auto label_idx = label_inst - &_.ordered_instructions()[0]; + auto terminator_idx = terminator_inst - &_.ordered_instructions()[0]; + if (label_idx + 1 != terminator_idx) { + return _.diag(SPV_ERROR_INVALID_CFG, _.FindDef(block->id())) + << "For WebGPU, unreachable continue-target must only contain " + "an OpLabel and an OpBranch instruction."; + } + + // 3. Use label instruction to confirm there is no uses by branches. + for (auto use : label_inst->uses()) { + const auto* use_inst = use.first; + if (spvOpcodeIsBranch(use_inst->opcode())) { + return _.diag(SPV_ERROR_INVALID_CFG, _.FindDef(block->id())) + << "For WebGPU, unreachable continue-target cannot be the " + "target of a branch."; + } + } + + // 4. Confirm that continue-target has a back edge to a reachable loop + // header block. + auto branch_target = terminator_inst->GetOperandAs(0); + for (auto* continue_header : reachable_headers) { + if (branch_target != continue_header->id()) { + return _.diag(SPV_ERROR_INVALID_CFG, _.FindDef(block->id())) + << "For WebGPU, unreachable continue-target must only have a " + "back edge to a single reachable loop instruction."; + } + } + } else { + return _.diag(SPV_ERROR_INVALID_CFG, _.FindDef(block->id())) + << "For WebGPU, all blocks must be reachable, unless they are " + << "degenerate cases of merge-block or continue-target."; + } + } return SPV_SUCCESS; } @@ -607,7 +947,8 @@ spv_result_t PerformCfgChecks(ValidationState_t& _) { auto edges = CFA::CalculateDominators( postorder, function.AugmentedCFGPredecessorsFunction()); for (auto edge : edges) { - edge.first->SetImmediateDominator(edge.second); + if (edge.first != edge.second) + edge.first->SetImmediateDominator(edge.second); } /// calculate post dominators @@ -647,6 +988,13 @@ spv_result_t PerformCfgChecks(ValidationState_t& _) { << _.getIdName(idom->id()); } } + + // For WebGPU check that all unreachable blocks are degenerate cases for + // merge-block or continue-target. + if (spvIsWebGPUEnv(_.context()->target_env)) { + spv_result_t result = PerformWebGPUCfgChecks(_, &function); + if (result != SPV_SUCCESS) return result; + } } // If we have structed control flow, check that no block has a control // flow nesting depth larger than the limit. @@ -665,7 +1013,8 @@ spv_result_t PerformCfgChecks(ValidationState_t& _) { /// Structured control flow checks are only required for shader capabilities if (_.HasCapability(SpvCapabilityShader)) { - if (auto error = StructuredControlFlowChecks(_, &function, back_edges)) + if (auto error = + StructuredControlFlowChecks(_, &function, back_edges, postorder)) return error; } } @@ -755,12 +1104,21 @@ spv_result_t ControlFlowPass(ValidationState_t& _, const Instruction* inst) { case SpvOpPhi: if (auto error = ValidatePhi(_, inst)) return error; break; + case SpvOpBranch: + if (auto error = ValidateBranch(_, inst)) return error; + break; case SpvOpBranchConditional: if (auto error = ValidateBranchConditional(_, inst)) return error; break; case SpvOpReturnValue: if (auto error = ValidateReturnValue(_, inst)) return error; break; + case SpvOpSwitch: + if (auto error = ValidateSwitch(_, inst)) return error; + break; + case SpvOpLoopMerge: + if (auto error = ValidateLoopMerge(_, inst)) return error; + break; default: break; } diff --git a/third_party/spirv-tools/source/val/validate_composites.cpp b/third_party/spirv-tools/source/val/validate_composites.cpp index e3ae670ab0..eb8a3244a4 100644 --- a/third_party/spirv-tools/source/val/validate_composites.cpp +++ b/third_party/spirv-tools/source/val/validate_composites.cpp @@ -18,6 +18,7 @@ #include "source/diagnostic.h" #include "source/opcode.h" +#include "source/spirv_target_env.h" #include "source/val/instruction.h" #include "source/val/validation_state.h" @@ -29,8 +30,8 @@ namespace { // OpCompositeInsert instruction. The function traverses the hierarchy of // nested data structures (structs, arrays, vectors, matrices) as directed by // the sequence of indices in the instruction. May return error if traversal -// fails (encountered non-composite, out of bounds, nesting too deep). -// Returns the type of Composite operand if the instruction has no indices. +// fails (encountered non-composite, out of bounds, no indices, nesting too +// deep). spv_result_t GetExtractInsertValueType(ValidationState_t& _, const Instruction* inst, uint32_t* member_type) { @@ -39,10 +40,15 @@ spv_result_t GetExtractInsertValueType(ValidationState_t& _, uint32_t word_index = opcode == SpvOpCompositeExtract ? 4 : 5; const uint32_t num_words = static_cast(inst->words().size()); const uint32_t composite_id_index = word_index - 1; - const uint32_t num_indices = num_words - word_index; const uint32_t kCompositeExtractInsertMaxNumIndices = 255; - if (num_indices > kCompositeExtractInsertMaxNumIndices) { + + if (num_indices == 0) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Expected at least one index to Op" + << spvOpcodeString(inst->opcode()) << ", zero found"; + + } else if (num_indices > kCompositeExtractInsertMaxNumIndices) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << "The number of indexes in Op" << spvOpcodeString(opcode) << " may not exceed " << kCompositeExtractInsertMaxNumIndices @@ -117,6 +123,10 @@ spv_result_t GetExtractInsertValueType(ValidationState_t& _, *member_type = type_inst->word(component_index + 2); break; } + case SpvOpTypeCooperativeMatrixNV: { + *member_type = type_inst->word(2); + break; + } default: return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Reached non-composite type while indexes still remain to " @@ -148,11 +158,17 @@ spv_result_t ValidateVectorExtractDynamic(ValidationState_t& _, << "Expected Vector component type to be equal to Result Type"; } - const uint32_t index_type = _.GetOperandTypeId(inst, 3); - if (!_.IsIntScalarType(index_type)) { + const auto index = _.FindDef(inst->GetOperandAs(3)); + if (!index || index->type_id() == 0 || !_.IsIntScalarType(index->type_id())) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Expected Index to be int scalar"; } + + if (_.HasCapability(SpvCapabilityShader) && + _.ContainsLimitedUseIntOrFloatType(inst->type_id())) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Cannot extract from a vector of 8- or 16-bit types"; + } return SPV_SUCCESS; } @@ -183,6 +199,12 @@ spv_result_t ValidateVectorInsertDyanmic(ValidationState_t& _, return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Expected Index to be int scalar"; } + + if (_.HasCapability(SpvCapabilityShader) && + _.ContainsLimitedUseIntOrFloatType(inst->type_id())) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Cannot insert into a vector of 8- or 16-bit types"; + } return SPV_SUCCESS; } @@ -314,11 +336,37 @@ spv_result_t ValidateCompositeConstruct(ValidationState_t& _, break; } + case SpvOpTypeCooperativeMatrixNV: { + const auto result_type_inst = _.FindDef(result_type); + assert(result_type_inst); + const auto component_type_id = + result_type_inst->GetOperandAs(1); + + if (3 != num_operands) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Expected single constituent"; + } + + const uint32_t operand_type_id = _.GetOperandTypeId(inst, 2); + + if (operand_type_id != component_type_id) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Expected Constituent type to be equal to the component type"; + } + + break; + } default: { return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Expected Result Type to be a composite type"; } } + + if (_.HasCapability(SpvCapabilityShader) && + _.ContainsLimitedUseIntOrFloatType(inst->type_id())) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Cannot create a composite containing 8- or 16-bit types"; + } return SPV_SUCCESS; } @@ -337,20 +385,26 @@ spv_result_t ValidateCompositeExtract(ValidationState_t& _, "the composite (Op" << spvOpcodeString(_.GetIdOpcode(member_type)) << ")."; } + + if (_.HasCapability(SpvCapabilityShader) && + _.ContainsLimitedUseIntOrFloatType(inst->type_id())) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Cannot extract from a composite of 8- or 16-bit types"; + } + return SPV_SUCCESS; } spv_result_t ValidateCompositeInsert(ValidationState_t& _, const Instruction* inst) { - const SpvOp opcode = inst->opcode(); const uint32_t object_type = _.GetOperandTypeId(inst, 2); const uint32_t composite_type = _.GetOperandTypeId(inst, 3); const uint32_t result_type = inst->type_id(); if (result_type != composite_type) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << "The Result Type must be the same as Composite type in Op" - << spvOpcodeString(opcode) << " yielding Result Id " << result_type - << "."; + << spvOpcodeString(inst->opcode()) << " yielding Result Id " + << result_type << "."; } uint32_t member_type = 0; @@ -366,16 +420,18 @@ spv_result_t ValidateCompositeInsert(ValidationState_t& _, "Composite (Op" << spvOpcodeString(_.GetIdOpcode(member_type)) << ")."; } + + if (_.HasCapability(SpvCapabilityShader) && + _.ContainsLimitedUseIntOrFloatType(inst->type_id())) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Cannot insert into a composite of 8- or 16-bit types"; + } + return SPV_SUCCESS; } spv_result_t ValidateCopyObject(ValidationState_t& _, const Instruction* inst) { const uint32_t result_type = inst->type_id(); - if (!spvOpcodeGeneratesType(_.GetIdOpcode(result_type))) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << "Expected Result Type to be a type"; - } - const uint32_t operand_type = _.GetOperandTypeId(inst, 2); if (operand_type != result_type) { return _.diag(SPV_ERROR_INVALID_DATA, inst) @@ -419,6 +475,12 @@ spv_result_t ValidateTranspose(ValidationState_t& _, const Instruction* inst) { << "Expected number of columns and the column size of Matrix " << "to be the reverse of those of Result Type"; } + + if (_.HasCapability(SpvCapabilityShader) && + _.ContainsLimitedUseIntOrFloatType(inst->type_id())) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Cannot transpose matrices of 16-bit floats"; + } return SPV_SUCCESS; } @@ -469,10 +531,12 @@ spv_result_t ValidateVectorShuffle(ValidationState_t& _, } // All Component literals must either be FFFFFFFF or in [0, N - 1]. + // For WebGPU specifically, Component literals cannot be FFFFFFFF. auto vector1ComponentCount = vector1Type->GetOperandAs(2); auto vector2ComponentCount = vector2Type->GetOperandAs(2); auto N = vector1ComponentCount + vector2ComponentCount; auto firstLiteralIndex = 4; + const auto is_webgpu_env = spvIsWebGPUEnv(_.context()->target_env); for (size_t i = firstLiteralIndex; i < inst->operands().size(); ++i) { auto literal = inst->GetOperandAs(i); if (literal != 0xFFFFFFFF && literal >= N) { @@ -480,6 +544,42 @@ spv_result_t ValidateVectorShuffle(ValidationState_t& _, << "Component index " << literal << " is out of bounds for " << "combined (Vector1 + Vector2) size of " << N << "."; } + + if (is_webgpu_env && literal == 0xFFFFFFFF) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Component literal at operand " << i - firstLiteralIndex + << " cannot be 0xFFFFFFFF in WebGPU execution environment."; + } + } + + if (_.HasCapability(SpvCapabilityShader) && + _.ContainsLimitedUseIntOrFloatType(inst->type_id())) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Cannot shuffle a vector of 8- or 16-bit types"; + } + + return SPV_SUCCESS; +} + +spv_result_t ValidateCopyLogical(ValidationState_t& _, + const Instruction* inst) { + const auto result_type = _.FindDef(inst->type_id()); + const auto source = _.FindDef(inst->GetOperandAs(2u)); + const auto source_type = _.FindDef(source->type_id()); + if (!source_type || !result_type || source_type == result_type) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Result Type must not equal the Operand type"; + } + + if (!_.LogicallyMatch(source_type, result_type, false)) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Result Type does not logically match the Operand type"; + } + + if (_.HasCapability(SpvCapabilityShader) && + _.ContainsLimitedUseIntOrFloatType(inst->type_id())) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Cannot copy composites of 8- or 16-bit types"; } return SPV_SUCCESS; @@ -506,6 +606,8 @@ spv_result_t CompositesPass(ValidationState_t& _, const Instruction* inst) { return ValidateCopyObject(_, inst); case SpvOpTranspose: return ValidateTranspose(_, inst); + case SpvOpCopyLogical: + return ValidateCopyLogical(_, inst); default: break; } diff --git a/third_party/spirv-tools/source/val/validate_constants.cpp b/third_party/spirv-tools/source/val/validate_constants.cpp index 5dbe6c6df2..dea95c8a2e 100644 --- a/third_party/spirv-tools/source/val/validate_constants.cpp +++ b/third_party/spirv-tools/source/val/validate_constants.cpp @@ -12,10 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "source/val/validate.h" - #include "source/opcode.h" #include "source/val/instruction.h" +#include "source/val/validate.h" #include "source/val/validation_state.h" namespace spvtools { @@ -117,15 +116,13 @@ spv_result_t ValidateConstantComposite(ValidationState_t& _, inst->GetOperandAs(constituent_index); const auto constituent = _.FindDef(constituent_id); if (!constituent || - !(SpvOpConstantComposite == constituent->opcode() || - SpvOpSpecConstantComposite == constituent->opcode() || - SpvOpUndef == constituent->opcode())) { + !spvOpcodeIsConstantOrUndef(constituent->opcode())) { // The message says "... or undef" because the spec does not say // undef is a constant. return _.diag(SPV_ERROR_INVALID_ID, inst) << opcode_name << " Constituent '" << _.getIdName(constituent_id) - << "' is not a constant composite or undef."; + << "' is not a constant or undef."; } const auto vector = _.FindDef(constituent->type_id()); if (!vector) { @@ -174,8 +171,7 @@ spv_result_t ValidateConstantComposite(ValidationState_t& _, bool is_const; uint32_t value; std::tie(is_int32, is_const, value) = _.EvalInt32IfConst(length->id()); - if (is_int32 && is_const && !spvOpcodeIsSpecConstant(length->opcode()) && - value != constituent_count) { + if (is_int32 && is_const && value != constituent_count) { return _.diag(SPV_ERROR_INVALID_ID, inst) << opcode_name << " Constituent count does not match " @@ -248,6 +244,36 @@ spv_result_t ValidateConstantComposite(ValidationState_t& _, } } } break; + case SpvOpTypeCooperativeMatrixNV: { + if (1 != constituent_count) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << opcode_name << " Constituent '" + << _.getIdName(inst->type_id()) << "' count must be one."; + } + const auto constituent_id = inst->GetOperandAs(2); + const auto constituent = _.FindDef(constituent_id); + if (!constituent || !spvOpcodeIsConstantOrUndef(constituent->opcode())) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << opcode_name << " Constituent '" + << _.getIdName(constituent_id) + << "' is not a constant or undef."; + } + const auto constituent_type = _.FindDef(constituent->type_id()); + if (!constituent_type) { + return _.diag(SPV_ERROR_INVALID_ID, constituent) + << "Result type is not defined."; + } + + const auto component_type_id = result_type->GetOperandAs(1); + const auto component_type = _.FindDef(component_type_id); + if (!component_type || component_type->id() != constituent_type->id()) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << opcode_name << " Constituent '" + << _.getIdName(constituent_id) + << "' type does not match the Result Type '" + << _.getIdName(result_type->id()) << "'s component type."; + } + } break; default: break; } @@ -278,7 +304,6 @@ bool IsTypeNullable(const std::vector& instruction, case SpvOpTypeBool: case SpvOpTypeInt: case SpvOpTypeFloat: - case SpvOpTypePointer: case SpvOpTypeEvent: case SpvOpTypeDeviceEvent: case SpvOpTypeReserveId: @@ -286,6 +311,7 @@ bool IsTypeNullable(const std::vector& instruction, return true; case SpvOpTypeArray: case SpvOpTypeMatrix: + case SpvOpTypeCooperativeMatrixNV: case SpvOpTypeVector: { auto base_type = _.FindDef(instruction[2]); return base_type && IsTypeNullable(base_type->words(), _); @@ -298,6 +324,11 @@ bool IsTypeNullable(const std::vector& instruction, } return true; } + case SpvOpTypePointer: + if (instruction[2] == SpvStorageClassPhysicalStorageBuffer) { + return false; + } + return true; default: return false; } @@ -315,6 +346,81 @@ spv_result_t ValidateConstantNull(ValidationState_t& _, return SPV_SUCCESS; } +// Validates that OpSpecConstant specializes to either int or float type. +spv_result_t ValidateSpecConstant(ValidationState_t& _, + const Instruction* inst) { + // Operand 0 is the of the type that we're specializing to. + auto type_id = inst->GetOperandAs(0); + auto type_instruction = _.FindDef(type_id); + auto type_opcode = type_instruction->opcode(); + if (type_opcode != SpvOpTypeInt && type_opcode != SpvOpTypeFloat) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Specialization constant " + "must be an integer or " + "floating-point number."; + } + return SPV_SUCCESS; +} + +spv_result_t ValidateSpecConstantOp(ValidationState_t& _, + const Instruction* inst) { + const auto op = inst->GetOperandAs(2); + + // The binary parser already ensures that the op is valid for *some* + // environment. Here we check restrictions. + switch (op) { + case SpvOpQuantizeToF16: + if (!_.HasCapability(SpvCapabilityShader)) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Specialization constant operation " << spvOpcodeString(op) + << " requires Shader capability"; + } + break; + + case SpvOpUConvert: + if (!_.features().uconvert_spec_constant_op && + !_.HasCapability(SpvCapabilityKernel)) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Prior to SPIR-V 1.4, specialization constant operation " + "UConvert requires Kernel capability or extension " + "SPV_AMD_gpu_shader_int16"; + } + break; + + case SpvOpConvertFToS: + case SpvOpConvertSToF: + case SpvOpConvertFToU: + case SpvOpConvertUToF: + case SpvOpConvertPtrToU: + case SpvOpConvertUToPtr: + case SpvOpGenericCastToPtr: + case SpvOpPtrCastToGeneric: + case SpvOpBitcast: + case SpvOpFNegate: + case SpvOpFAdd: + case SpvOpFSub: + case SpvOpFMul: + case SpvOpFDiv: + case SpvOpFRem: + case SpvOpFMod: + case SpvOpAccessChain: + case SpvOpInBoundsAccessChain: + case SpvOpPtrAccessChain: + case SpvOpInBoundsPtrAccessChain: + if (!_.HasCapability(SpvCapabilityKernel)) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Specialization constant operation " << spvOpcodeString(op) + << " requires Kernel capability"; + } + break; + + default: + break; + } + + // TODO(dneto): Validate result type and arguments to the various operations. + return SPV_SUCCESS; +} + } // namespace spv_result_t ConstantPass(ValidationState_t& _, const Instruction* inst) { @@ -335,10 +441,26 @@ spv_result_t ConstantPass(ValidationState_t& _, const Instruction* inst) { case SpvOpConstantNull: if (auto error = ValidateConstantNull(_, inst)) return error; break; + case SpvOpSpecConstant: + if (auto error = ValidateSpecConstant(_, inst)) return error; + break; + case SpvOpSpecConstantOp: + if (auto error = ValidateSpecConstantOp(_, inst)) return error; + break; default: break; } + // Generally disallow creating 8- or 16-bit constants unless the full + // capabilities are present. + if (spvOpcodeIsConstant(inst->opcode()) && + _.HasCapability(SpvCapabilityShader) && + !_.IsPointerType(inst->type_id()) && + _.ContainsLimitedUseIntOrFloatType(inst->type_id())) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Cannot form constants of 8- or 16-bit types"; + } + return SPV_SUCCESS; } diff --git a/third_party/spirv-tools/source/val/validate_conversion.cpp b/third_party/spirv-tools/source/val/validate_conversion.cpp index 9c6f68c6f5..0060d0b7b5 100644 --- a/third_party/spirv-tools/source/val/validate_conversion.cpp +++ b/third_party/spirv-tools/source/val/validate_conversion.cpp @@ -18,6 +18,7 @@ #include "source/diagnostic.h" #include "source/opcode.h" +#include "source/spirv_constant.h" #include "source/val/instruction.h" #include "source/val/validation_state.h" @@ -32,43 +33,61 @@ spv_result_t ConversionPass(ValidationState_t& _, const Instruction* inst) { switch (opcode) { case SpvOpConvertFToU: { if (!_.IsUnsignedIntScalarType(result_type) && - !_.IsUnsignedIntVectorType(result_type)) + !_.IsUnsignedIntVectorType(result_type) && + !_.IsUnsignedIntCooperativeMatrixType(result_type)) return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Expected unsigned int scalar or vector type as Result Type: " << spvOpcodeString(opcode); const uint32_t input_type = _.GetOperandTypeId(inst, 2); if (!input_type || (!_.IsFloatScalarType(input_type) && - !_.IsFloatVectorType(input_type))) + !_.IsFloatVectorType(input_type) && + !_.IsFloatCooperativeMatrixType(input_type))) return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Expected input to be float scalar or vector: " << spvOpcodeString(opcode); - if (_.GetDimension(result_type) != _.GetDimension(input_type)) - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << "Expected input to have the same dimension as Result Type: " - << spvOpcodeString(opcode); + if (_.IsCooperativeMatrixType(result_type) || + _.IsCooperativeMatrixType(input_type)) { + spv_result_t ret = + _.CooperativeMatrixShapesMatch(inst, result_type, input_type); + if (ret != SPV_SUCCESS) return ret; + } else { + if (_.GetDimension(result_type) != _.GetDimension(input_type)) + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Expected input to have the same dimension as Result Type: " + << spvOpcodeString(opcode); + } break; } case SpvOpConvertFToS: { - if (!_.IsIntScalarType(result_type) && !_.IsIntVectorType(result_type)) + if (!_.IsIntScalarType(result_type) && !_.IsIntVectorType(result_type) && + !_.IsIntCooperativeMatrixType(result_type)) return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Expected int scalar or vector type as Result Type: " << spvOpcodeString(opcode); const uint32_t input_type = _.GetOperandTypeId(inst, 2); if (!input_type || (!_.IsFloatScalarType(input_type) && - !_.IsFloatVectorType(input_type))) + !_.IsFloatVectorType(input_type) && + !_.IsFloatCooperativeMatrixType(input_type))) return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Expected input to be float scalar or vector: " << spvOpcodeString(opcode); - if (_.GetDimension(result_type) != _.GetDimension(input_type)) - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << "Expected input to have the same dimension as Result Type: " - << spvOpcodeString(opcode); + if (_.IsCooperativeMatrixType(result_type) || + _.IsCooperativeMatrixType(input_type)) { + spv_result_t ret = + _.CooperativeMatrixShapesMatch(inst, result_type, input_type); + if (ret != SPV_SUCCESS) return ret; + } else { + if (_.GetDimension(result_type) != _.GetDimension(input_type)) + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Expected input to have the same dimension as Result Type: " + << spvOpcodeString(opcode); + } break; } @@ -76,44 +95,62 @@ spv_result_t ConversionPass(ValidationState_t& _, const Instruction* inst) { case SpvOpConvertSToF: case SpvOpConvertUToF: { if (!_.IsFloatScalarType(result_type) && - !_.IsFloatVectorType(result_type)) + !_.IsFloatVectorType(result_type) && + !_.IsFloatCooperativeMatrixType(result_type)) return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Expected float scalar or vector type as Result Type: " << spvOpcodeString(opcode); const uint32_t input_type = _.GetOperandTypeId(inst, 2); if (!input_type || - (!_.IsIntScalarType(input_type) && !_.IsIntVectorType(input_type))) + (!_.IsIntScalarType(input_type) && !_.IsIntVectorType(input_type) && + !_.IsIntCooperativeMatrixType(input_type))) return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Expected input to be int scalar or vector: " << spvOpcodeString(opcode); - if (_.GetDimension(result_type) != _.GetDimension(input_type)) - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << "Expected input to have the same dimension as Result Type: " - << spvOpcodeString(opcode); + if (_.IsCooperativeMatrixType(result_type) || + _.IsCooperativeMatrixType(input_type)) { + spv_result_t ret = + _.CooperativeMatrixShapesMatch(inst, result_type, input_type); + if (ret != SPV_SUCCESS) return ret; + } else { + if (_.GetDimension(result_type) != _.GetDimension(input_type)) + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Expected input to have the same dimension as Result Type: " + << spvOpcodeString(opcode); + } break; } case SpvOpUConvert: { if (!_.IsUnsignedIntScalarType(result_type) && - !_.IsUnsignedIntVectorType(result_type)) + !_.IsUnsignedIntVectorType(result_type) && + !_.IsUnsignedIntCooperativeMatrixType(result_type)) return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Expected unsigned int scalar or vector type as Result Type: " << spvOpcodeString(opcode); const uint32_t input_type = _.GetOperandTypeId(inst, 2); if (!input_type || - (!_.IsIntScalarType(input_type) && !_.IsIntVectorType(input_type))) + (!_.IsIntScalarType(input_type) && !_.IsIntVectorType(input_type) && + !_.IsIntCooperativeMatrixType(input_type))) return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Expected input to be int scalar or vector: " << spvOpcodeString(opcode); - if (_.GetDimension(result_type) != _.GetDimension(input_type)) - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << "Expected input to have the same dimension as Result Type: " - << spvOpcodeString(opcode); + if (_.IsCooperativeMatrixType(result_type) || + _.IsCooperativeMatrixType(input_type)) { + spv_result_t ret = + _.CooperativeMatrixShapesMatch(inst, result_type, input_type); + if (ret != SPV_SUCCESS) return ret; + } else { + if (_.GetDimension(result_type) != _.GetDimension(input_type)) + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Expected input to have the same dimension as Result Type: " + << spvOpcodeString(opcode); + } if (_.GetBitWidth(result_type) == _.GetBitWidth(input_type)) return _.diag(SPV_ERROR_INVALID_DATA, inst) @@ -124,22 +161,31 @@ spv_result_t ConversionPass(ValidationState_t& _, const Instruction* inst) { } case SpvOpSConvert: { - if (!_.IsIntScalarType(result_type) && !_.IsIntVectorType(result_type)) + if (!_.IsIntScalarType(result_type) && !_.IsIntVectorType(result_type) && + !_.IsIntCooperativeMatrixType(result_type)) return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Expected int scalar or vector type as Result Type: " << spvOpcodeString(opcode); const uint32_t input_type = _.GetOperandTypeId(inst, 2); if (!input_type || - (!_.IsIntScalarType(input_type) && !_.IsIntVectorType(input_type))) + (!_.IsIntScalarType(input_type) && !_.IsIntVectorType(input_type) && + !_.IsIntCooperativeMatrixType(input_type))) return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Expected input to be int scalar or vector: " << spvOpcodeString(opcode); - if (_.GetDimension(result_type) != _.GetDimension(input_type)) - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << "Expected input to have the same dimension as Result Type: " - << spvOpcodeString(opcode); + if (_.IsCooperativeMatrixType(result_type) || + _.IsCooperativeMatrixType(input_type)) { + spv_result_t ret = + _.CooperativeMatrixShapesMatch(inst, result_type, input_type); + if (ret != SPV_SUCCESS) return ret; + } else { + if (_.GetDimension(result_type) != _.GetDimension(input_type)) + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Expected input to have the same dimension as Result Type: " + << spvOpcodeString(opcode); + } if (_.GetBitWidth(result_type) == _.GetBitWidth(input_type)) return _.diag(SPV_ERROR_INVALID_DATA, inst) @@ -151,22 +197,31 @@ spv_result_t ConversionPass(ValidationState_t& _, const Instruction* inst) { case SpvOpFConvert: { if (!_.IsFloatScalarType(result_type) && - !_.IsFloatVectorType(result_type)) + !_.IsFloatVectorType(result_type) && + !_.IsFloatCooperativeMatrixType(result_type)) return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Expected float scalar or vector type as Result Type: " << spvOpcodeString(opcode); const uint32_t input_type = _.GetOperandTypeId(inst, 2); if (!input_type || (!_.IsFloatScalarType(input_type) && - !_.IsFloatVectorType(input_type))) + !_.IsFloatVectorType(input_type) && + !_.IsFloatCooperativeMatrixType(input_type))) return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Expected input to be float scalar or vector: " << spvOpcodeString(opcode); - if (_.GetDimension(result_type) != _.GetDimension(input_type)) - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << "Expected input to have the same dimension as Result Type: " - << spvOpcodeString(opcode); + if (_.IsCooperativeMatrixType(result_type) || + _.IsCooperativeMatrixType(input_type)) { + spv_result_t ret = + _.CooperativeMatrixShapesMatch(inst, result_type, input_type); + if (ret != SPV_SUCCESS) return ret; + } else { + if (_.GetDimension(result_type) != _.GetDimension(input_type)) + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Expected input to have the same dimension as Result Type: " + << spvOpcodeString(opcode); + } if (_.GetBitWidth(result_type) == _.GetBitWidth(input_type)) return _.diag(SPV_ERROR_INVALID_DATA, inst) @@ -202,6 +257,23 @@ spv_result_t ConversionPass(ValidationState_t& _, const Instruction* inst) { if (!_.IsPointerType(input_type)) return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Expected input to be a pointer: " << spvOpcodeString(opcode); + + if (_.addressing_model() == SpvAddressingModelLogical) + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Logical addressing not supported: " + << spvOpcodeString(opcode); + + if (_.addressing_model() == + SpvAddressingModelPhysicalStorageBuffer64EXT) { + uint32_t input_storage_class = 0; + uint32_t input_data_type = 0; + _.GetPointerTypeInfo(input_type, &input_data_type, + &input_storage_class); + if (input_storage_class != SpvStorageClassPhysicalStorageBufferEXT) + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Pointer storage class must be PhysicalStorageBufferEXT: " + << spvOpcodeString(opcode); + } break; } @@ -233,9 +305,26 @@ spv_result_t ConversionPass(ValidationState_t& _, const Instruction* inst) { << spvOpcodeString(opcode); const uint32_t input_type = _.GetOperandTypeId(inst, 2); - if (!_.IsIntScalarType(input_type)) + if (!input_type || !_.IsIntScalarType(input_type)) return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Expected int scalar as input: " << spvOpcodeString(opcode); + + if (_.addressing_model() == SpvAddressingModelLogical) + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Logical addressing not supported: " + << spvOpcodeString(opcode); + + if (_.addressing_model() == + SpvAddressingModelPhysicalStorageBuffer64EXT) { + uint32_t result_storage_class = 0; + uint32_t result_data_type = 0; + _.GetPointerTypeInfo(result_type, &result_data_type, + &result_storage_class); + if (result_storage_class != SpvStorageClassPhysicalStorageBufferEXT) + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Pointer storage class must be PhysicalStorageBufferEXT: " + << spvOpcodeString(opcode); + } break; } @@ -379,15 +468,40 @@ spv_result_t ConversionPass(ValidationState_t& _, const Instruction* inst) { << "Expected input to be a pointer or int or float vector " << "or scalar: " << spvOpcodeString(opcode); - if (result_is_pointer && !input_is_pointer && !input_is_int_scalar) - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << "Expected input to be a pointer or int scalar if Result Type " - << "is pointer: " << spvOpcodeString(opcode); + if (_.version() >= SPV_SPIRV_VERSION_WORD(1, 5) || + _.HasExtension(kSPV_KHR_physical_storage_buffer)) { + const bool result_is_int_vector = _.IsIntVectorType(result_type); + const bool result_has_int32 = + _.ContainsSizedIntOrFloatType(result_type, SpvOpTypeInt, 32); + const bool input_is_int_vector = _.IsIntVectorType(input_type); + const bool input_has_int32 = + _.ContainsSizedIntOrFloatType(input_type, SpvOpTypeInt, 32); + if (result_is_pointer && !input_is_pointer && !input_is_int_scalar && + !(input_is_int_vector && input_has_int32)) + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Expected input to be a pointer, int scalar or 32-bit int " + "vector if Result Type is pointer: " + << spvOpcodeString(opcode); - if (input_is_pointer && !result_is_pointer && !result_is_int_scalar) - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << "Pointer can only be converted to another pointer or int " - << "scalar: " << spvOpcodeString(opcode); + if (input_is_pointer && !result_is_pointer && !result_is_int_scalar && + !(result_is_int_vector && result_has_int32)) + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Pointer can only be converted to another pointer, int " + "scalar or 32-bit int vector: " + << spvOpcodeString(opcode); + } else { + if (result_is_pointer && !input_is_pointer && !input_is_int_scalar) + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Expected input to be a pointer or int scalar if Result " + "Type is pointer: " + << spvOpcodeString(opcode); + + if (input_is_pointer && !result_is_pointer && !result_is_int_scalar) + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Pointer can only be converted to another pointer or int " + "scalar: " + << spvOpcodeString(opcode); + } if (!result_is_pointer && !input_is_pointer) { const uint32_t result_size = @@ -406,6 +520,25 @@ spv_result_t ConversionPass(ValidationState_t& _, const Instruction* inst) { break; } + if (_.HasCapability(SpvCapabilityShader)) { + switch (inst->opcode()) { + case SpvOpConvertFToU: + case SpvOpConvertFToS: + case SpvOpConvertSToF: + case SpvOpConvertUToF: + case SpvOpBitcast: + if (_.ContainsLimitedUseIntOrFloatType(inst->type_id()) || + _.ContainsLimitedUseIntOrFloatType(_.GetOperandTypeId(inst, 2u))) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "8- or 16-bit types can only be used with width-only " + "conversions"; + } + break; + default: + break; + } + } + return SPV_SUCCESS; } diff --git a/third_party/spirv-tools/source/val/validate_datarules.cpp b/third_party/spirv-tools/source/val/validate_datarules.cpp deleted file mode 100644 index 129b6bbf98..0000000000 --- a/third_party/spirv-tools/source/val/validate_datarules.cpp +++ /dev/null @@ -1,267 +0,0 @@ -// Copyright (c) 2016 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Ensures Data Rules are followed according to the specifications. - -#include "source/val/validate.h" - -#include -#include -#include - -#include "source/diagnostic.h" -#include "source/opcode.h" -#include "source/operand.h" -#include "source/val/instruction.h" -#include "source/val/validation_state.h" - -namespace spvtools { -namespace val { -namespace { - -// Validates that the number of components in the vector is valid. -// Vector types can only be parameterized as having 2, 3, or 4 components. -// If the Vector16 capability is added, 8 and 16 components are also allowed. -spv_result_t ValidateVecNumComponents(ValidationState_t& _, - const Instruction* inst) { - // Operand 2 specifies the number of components in the vector. - auto num_components = inst->GetOperandAs(2); - if (num_components == 2 || num_components == 3 || num_components == 4) { - return SPV_SUCCESS; - } - if (num_components == 8 || num_components == 16) { - if (_.HasCapability(SpvCapabilityVector16)) { - return SPV_SUCCESS; - } - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << "Having " << num_components << " components for " - << spvOpcodeString(inst->opcode()) - << " requires the Vector16 capability"; - } - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << "Illegal number of components (" << num_components << ") for " - << spvOpcodeString(inst->opcode()); -} - -// Validates that the number of bits specifed for a float type is valid. -// Scalar floating-point types can be parameterized only with 32-bits. -// Float16 capability allows using a 16-bit OpTypeFloat. -// Float16Buffer capability allows creation of a 16-bit OpTypeFloat. -// Float64 capability allows using a 64-bit OpTypeFloat. -spv_result_t ValidateFloatSize(ValidationState_t& _, const Instruction* inst) { - // Operand 1 is the number of bits for this float - auto num_bits = inst->GetOperandAs(1); - if (num_bits == 32) { - return SPV_SUCCESS; - } - if (num_bits == 16) { - if (_.features().declare_float16_type) { - return SPV_SUCCESS; - } - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << "Using a 16-bit floating point " - << "type requires the Float16 or Float16Buffer capability," - " or an extension that explicitly enables 16-bit floating point."; - } - if (num_bits == 64) { - if (_.HasCapability(SpvCapabilityFloat64)) { - return SPV_SUCCESS; - } - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << "Using a 64-bit floating point " - << "type requires the Float64 capability."; - } - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << "Invalid number of bits (" << num_bits << ") used for OpTypeFloat."; -} - -// Validates that the number of bits specified for an Int type is valid. -// Scalar integer types can be parameterized only with 32-bits. -// Int8, Int16, and Int64 capabilities allow using 8-bit, 16-bit, and 64-bit -// integers, respectively. -spv_result_t ValidateIntSize(ValidationState_t& _, const Instruction* inst) { - // Operand 1 is the number of bits for this integer. - auto num_bits = inst->GetOperandAs(1); - if (num_bits == 32) { - return SPV_SUCCESS; - } - if (num_bits == 8) { - if (_.features().declare_int8_type) { - return SPV_SUCCESS; - } - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << "Using an 8-bit integer type requires the Int8 capability," - " or an extension that explicitly enables 8-bit integers."; - } - if (num_bits == 16) { - if (_.features().declare_int16_type) { - return SPV_SUCCESS; - } - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << "Using a 16-bit integer type requires the Int16 capability," - " or an extension that explicitly enables 16-bit integers."; - } - if (num_bits == 64) { - if (_.HasCapability(SpvCapabilityInt64)) { - return SPV_SUCCESS; - } - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << "Using a 64-bit integer type requires the Int64 capability."; - } - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << "Invalid number of bits (" << num_bits << ") used for OpTypeInt."; -} - -// Validates that the matrix is parameterized with floating-point types. -spv_result_t ValidateMatrixColumnType(ValidationState_t& _, - const Instruction* inst) { - // Find the component type of matrix columns (must be vector). - // Operand 1 is the of the type specified for matrix columns. - auto type_id = inst->GetOperandAs(1); - auto col_type_instr = _.FindDef(type_id); - if (col_type_instr->opcode() != SpvOpTypeVector) { - return _.diag(SPV_ERROR_INVALID_ID, inst) - << "Columns in a matrix must be of type vector."; - } - - // Trace back once more to find out the type of components in the vector. - // Operand 1 is the of the type of data in the vector. - auto comp_type_id = - col_type_instr->words()[col_type_instr->operands()[1].offset]; - auto comp_type_instruction = _.FindDef(comp_type_id); - if (comp_type_instruction->opcode() != SpvOpTypeFloat) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Matrix types can only be " - "parameterized with " - "floating-point types."; - } - return SPV_SUCCESS; -} - -// Validates that the matrix has 2,3, or 4 columns. -spv_result_t ValidateMatrixNumCols(ValidationState_t& _, - const Instruction* inst) { - // Operand 2 is the number of columns in the matrix. - auto num_cols = inst->GetOperandAs(2); - if (num_cols != 2 && num_cols != 3 && num_cols != 4) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Matrix types can only be " - "parameterized as having " - "only 2, 3, or 4 columns."; - } - return SPV_SUCCESS; -} - -// Validates that OpSpecConstant specializes to either int or float type. -spv_result_t ValidateSpecConstNumerical(ValidationState_t& _, - const Instruction* inst) { - // Operand 0 is the of the type that we're specializing to. - auto type_id = inst->GetOperandAs(0); - auto type_instruction = _.FindDef(type_id); - auto type_opcode = type_instruction->opcode(); - if (type_opcode != SpvOpTypeInt && type_opcode != SpvOpTypeFloat) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Specialization constant " - "must be an integer or " - "floating-point number."; - } - return SPV_SUCCESS; -} - -// Validates that OpSpecConstantTrue and OpSpecConstantFalse specialize to bool. -spv_result_t ValidateSpecConstBoolean(ValidationState_t& _, - const Instruction* inst) { - // Find out the type that we're specializing to. - auto type_instruction = _.FindDef(inst->type_id()); - if (type_instruction->opcode() != SpvOpTypeBool) { - return _.diag(SPV_ERROR_INVALID_ID, inst) - << "Specialization constant must be a boolean type."; - } - return SPV_SUCCESS; -} - -// Records the of the forward pointer to be used for validation. -spv_result_t ValidateForwardPointer(ValidationState_t& _, - const Instruction* inst) { - // Record the (which is operand 0) to ensure it's used properly. - // OpTypeStruct can only include undefined pointers that are - // previously declared as a ForwardPointer - return (_.RegisterForwardPointer(inst->GetOperandAs(0))); -} - -// Validates that any undefined component of the struct is a forward pointer. -// It is valid to declare a forward pointer, and use its as one of the -// components of a struct. -spv_result_t ValidateStruct(ValidationState_t& _, const Instruction* inst) { - // Struct components are operands 1, 2, etc. - for (unsigned i = 1; i < inst->operands().size(); i++) { - auto type_id = inst->GetOperandAs(i); - auto type_instruction = _.FindDef(type_id); - if (type_instruction == nullptr && !_.IsForwardPointer(type_id)) { - return _.diag(SPV_ERROR_INVALID_ID, inst) - << "Forward reference operands in an OpTypeStruct must first be " - "declared using OpTypeForwardPointer."; - } - } - return SPV_SUCCESS; -} - -} // namespace - -// Validates that Data Rules are followed according to the specifications. -// (Data Rules subsection of 2.16.1 Universal Validation Rules) -spv_result_t DataRulesPass(ValidationState_t& _, const Instruction* inst) { - switch (inst->opcode()) { - case SpvOpTypeVector: { - if (auto error = ValidateVecNumComponents(_, inst)) return error; - break; - } - case SpvOpTypeFloat: { - if (auto error = ValidateFloatSize(_, inst)) return error; - break; - } - case SpvOpTypeInt: { - if (auto error = ValidateIntSize(_, inst)) return error; - break; - } - case SpvOpTypeMatrix: { - if (auto error = ValidateMatrixColumnType(_, inst)) return error; - if (auto error = ValidateMatrixNumCols(_, inst)) return error; - break; - } - // TODO(ehsan): Add OpSpecConstantComposite validation code. - // TODO(ehsan): Add OpSpecConstantOp validation code (if any). - case SpvOpSpecConstant: { - if (auto error = ValidateSpecConstNumerical(_, inst)) return error; - break; - } - case SpvOpSpecConstantFalse: - case SpvOpSpecConstantTrue: { - if (auto error = ValidateSpecConstBoolean(_, inst)) return error; - break; - } - case SpvOpTypeForwardPointer: { - if (auto error = ValidateForwardPointer(_, inst)) return error; - break; - } - case SpvOpTypeStruct: { - if (auto error = ValidateStruct(_, inst)) return error; - break; - } - // TODO(ehsan): add more data rules validation here. - default: { break; } - } - - return SPV_SUCCESS; -} - -} // namespace val -} // namespace spvtools diff --git a/third_party/spirv-tools/source/val/validate_debug.cpp b/third_party/spirv-tools/source/val/validate_debug.cpp index d84ed3801f..0a25d8ab7e 100644 --- a/third_party/spirv-tools/source/val/validate_debug.cpp +++ b/third_party/spirv-tools/source/val/validate_debug.cpp @@ -14,6 +14,8 @@ #include "source/val/validate.h" +#include "source/opcode.h" +#include "source/spirv_target_env.h" #include "source/val/instruction.h" #include "source/val/validation_state.h" diff --git a/third_party/spirv-tools/source/val/validate_decorations.cpp b/third_party/spirv-tools/source/val/validate_decorations.cpp index 64fb54516e..3b44833378 100644 --- a/third_party/spirv-tools/source/val/validate_decorations.cpp +++ b/third_party/spirv-tools/source/val/validate_decorations.cpp @@ -12,19 +12,21 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "source/val/validate.h" - #include #include #include +#include #include +#include #include #include #include "source/diagnostic.h" #include "source/opcode.h" +#include "source/spirv_constant.h" #include "source/spirv_target_env.h" #include "source/spirv_validator_options.h" +#include "source/val/validate_scopes.h" #include "source/val/validation_state.h" namespace spvtools { @@ -44,6 +46,13 @@ struct PairHash { } }; +// A functor for hashing decoration types. +struct SpvDecorationHash { + std::size_t operator()(SpvDecoration dec) const { + return static_cast(dec); + } +}; + // Struct member layout attributes that are inherited through arrays. struct LayoutConstraints { explicit LayoutConstraints( @@ -156,7 +165,8 @@ uint32_t getBaseAlignment(uint32_t member_id, bool roundUp, ValidationState_t& vstate) { const auto inst = vstate.FindDef(member_id); const auto& words = inst->words(); - uint32_t baseAlignment = 0; + // Minimal alignment is byte-aligned. + uint32_t baseAlignment = 1; switch (inst->opcode()) { case SpvOpTypeInt: case SpvOpTypeFloat: @@ -208,6 +218,9 @@ uint32_t getBaseAlignment(uint32_t member_id, bool roundUp, if (roundUp) baseAlignment = align(baseAlignment, 16u); break; } + case SpvOpTypePointer: + baseAlignment = vstate.pointer_size_and_alignment(); + break; default: assert(0); break; @@ -216,23 +229,59 @@ uint32_t getBaseAlignment(uint32_t member_id, bool roundUp, return baseAlignment; } +// Returns scalar alignment of a type. +uint32_t getScalarAlignment(uint32_t type_id, ValidationState_t& vstate) { + const auto inst = vstate.FindDef(type_id); + const auto& words = inst->words(); + switch (inst->opcode()) { + case SpvOpTypeInt: + case SpvOpTypeFloat: + return words[2] / 8; + case SpvOpTypeVector: + case SpvOpTypeMatrix: + case SpvOpTypeArray: + case SpvOpTypeRuntimeArray: { + const auto compositeMemberTypeId = words[2]; + return getScalarAlignment(compositeMemberTypeId, vstate); + } + case SpvOpTypeStruct: { + const auto members = getStructMembers(type_id, vstate); + uint32_t max_member_alignment = 1; + for (uint32_t memberIdx = 0, numMembers = uint32_t(members.size()); + memberIdx < numMembers; ++memberIdx) { + const auto id = members[memberIdx]; + uint32_t member_alignment = getScalarAlignment(id, vstate); + if (member_alignment > max_member_alignment) { + max_member_alignment = member_alignment; + } + } + return max_member_alignment; + } break; + case SpvOpTypePointer: + return vstate.pointer_size_and_alignment(); + default: + assert(0); + break; + } + + return 1; +} + // Returns size of a struct member. Doesn't include padding at the end of struct // or array. Assumes that in the struct case, all members have offsets. -uint32_t getSize(uint32_t member_id, bool roundUp, - const LayoutConstraints& inherited, +uint32_t getSize(uint32_t member_id, const LayoutConstraints& inherited, MemberConstraints& constraints, ValidationState_t& vstate) { const auto inst = vstate.FindDef(member_id); const auto& words = inst->words(); switch (inst->opcode()) { case SpvOpTypeInt: case SpvOpTypeFloat: - return getBaseAlignment(member_id, roundUp, inherited, constraints, - vstate); + return words[2] / 8; case SpvOpTypeVector: { const auto componentId = words[2]; const auto numComponents = words[3]; const auto componentSize = - getSize(componentId, roundUp, inherited, constraints, vstate); + getSize(componentId, inherited, constraints, vstate); const auto size = componentSize * numComponents; return size; } @@ -243,7 +292,7 @@ uint32_t getSize(uint32_t member_id, bool roundUp, const uint32_t num_elem = sizeInst->words()[3]; const uint32_t elem_type = words[2]; const uint32_t elem_size = - getSize(elem_type, roundUp, inherited, constraints, vstate); + getSize(elem_type, inherited, constraints, vstate); // Account for gaps due to alignments in the first N-1 elements, // then add the size of the last element. const auto size = @@ -263,7 +312,7 @@ uint32_t getSize(uint32_t member_id, bool roundUp, const auto num_rows = component_inst->words()[3]; const auto scalar_elem_type = component_inst->words()[2]; const uint32_t scalar_elem_size = - getSize(scalar_elem_type, roundUp, inherited, constraints, vstate); + getSize(scalar_elem_type, inherited, constraints, vstate); return (num_rows - 1) * inherited.matrix_stride + num_columns * scalar_elem_size; } @@ -285,9 +334,10 @@ uint32_t getSize(uint32_t member_id, bool roundUp, // has been checked earlier in the flow. assert(offset != 0xffffffff); const auto& constraint = constraints[std::make_pair(lastMember, lastIdx)]; - return offset + - getSize(lastMember, roundUp, constraint, constraints, vstate); + return offset + getSize(lastMember, constraint, constraints, vstate); } + case SpvOpTypePointer: + return vstate.pointer_size_and_alignment(); default: assert(0); return 0; @@ -305,7 +355,7 @@ bool hasImproperStraddle(uint32_t id, uint32_t offset, const LayoutConstraints& inherited, MemberConstraints& constraints, ValidationState_t& vstate) { - const auto size = getSize(id, false, inherited, constraints, vstate); + const auto size = getSize(id, inherited, constraints, vstate); const auto F = offset; const auto L = offset + size - 1; if (size <= 16) { @@ -329,29 +379,41 @@ bool IsAlignedTo(uint32_t offset, uint32_t alignment) { // or row major-ness. spv_result_t checkLayout(uint32_t struct_id, const char* storage_class_str, const char* decoration_str, bool blockRules, + uint32_t incoming_offset, MemberConstraints& constraints, ValidationState_t& vstate) { if (vstate.options()->skip_block_layout) return SPV_SUCCESS; + // blockRules are the same as bufferBlock rules if the uniform buffer + // standard layout extension is being used. + if (vstate.options()->uniform_buffer_standard_layout) blockRules = false; + + // Relaxed layout and scalar layout can both be in effect at the same time. + // For example, relaxed layout is implied by Vulkan 1.1. But scalar layout + // is more permissive than relaxed layout. + const bool relaxed_block_layout = vstate.IsRelaxedBlockLayout(); + const bool scalar_block_layout = vstate.options()->scalar_block_layout; + auto fail = [&vstate, struct_id, storage_class_str, decoration_str, - blockRules](uint32_t member_idx) -> DiagnosticStream { + blockRules, relaxed_block_layout, + scalar_block_layout](uint32_t member_idx) -> DiagnosticStream { DiagnosticStream ds = std::move(vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(struct_id)) << "Structure id " << struct_id << " decorated as " << decoration_str << " for variable in " << storage_class_str - << " storage class must follow standard " + << " storage class must follow " + << (scalar_block_layout + ? "scalar " + : (relaxed_block_layout ? "relaxed " : "standard ")) << (blockRules ? "uniform buffer" : "storage buffer") << " layout rules: member " << member_idx << " "); return ds; }; - const bool relaxed_block_layout = vstate.IsRelaxedBlockLayout(); const auto& members = getStructMembers(struct_id, vstate); // To check for member overlaps, we want to traverse the members in // offset order. - const bool permit_non_monotonic_member_offsets = - vstate.features().non_monotonic_struct_member_offsets; struct MemberOffsetPair { uint32_t member; uint32_t offset; @@ -372,7 +434,8 @@ spv_result_t checkLayout(uint32_t struct_id, const char* storage_class_str, } } } - member_offsets.push_back(MemberOffsetPair{memberIdx, offset}); + member_offsets.push_back( + MemberOffsetPair{memberIdx, incoming_offset + offset}); } std::stable_sort( member_offsets.begin(), member_offsets.end(), @@ -381,7 +444,6 @@ spv_result_t checkLayout(uint32_t struct_id, const char* storage_class_str, }); // Now scan from lowest offest to highest offset. - uint32_t prevOffset = 0; uint32_t nextValidOffset = 0; for (size_t ordered_member_idx = 0; ordered_member_idx < member_offsets.size(); ordered_member_idx++) { @@ -391,20 +453,25 @@ spv_result_t checkLayout(uint32_t struct_id, const char* storage_class_str, auto id = members[member_offset.member]; const LayoutConstraints& constraint = constraints[std::make_pair(struct_id, uint32_t(memberIdx))]; + // Scalar layout takes precedence because it's more permissive, and implying + // an alignment that divides evenly into the alignment that would otherwise + // be used. const auto alignment = - getBaseAlignment(id, blockRules, constraint, constraints, vstate); + scalar_block_layout + ? getScalarAlignment(id, vstate) + : getBaseAlignment(id, blockRules, constraint, constraints, vstate); const auto inst = vstate.FindDef(id); const auto opcode = inst->opcode(); - const auto size = getSize(id, blockRules, constraint, constraints, vstate); + const auto size = getSize(id, constraint, constraints, vstate); // Check offset. if (offset == 0xffffffff) return fail(memberIdx) << "is missing an Offset decoration"; - if (relaxed_block_layout && opcode == SpvOpTypeVector) { + if (!scalar_block_layout && relaxed_block_layout && + opcode == SpvOpTypeVector) { // In relaxed block layout, the vector offset must be aligned to the // vector's scalar element type. const auto componentId = inst->words()[2]; - const auto scalar_alignment = getBaseAlignment( - componentId, blockRules, constraint, constraints, vstate); + const auto scalar_alignment = getScalarAlignment(componentId, vstate); if (!IsAlignedTo(offset, scalar_alignment)) { return fail(memberIdx) << "at offset " << offset @@ -412,30 +479,17 @@ spv_result_t checkLayout(uint32_t struct_id, const char* storage_class_str, } } else { // Without relaxed block layout, the offset must be divisible by the - // base alignment. + // alignment requirement. if (!IsAlignedTo(offset, alignment)) { return fail(memberIdx) << "at offset " << offset << " is not aligned to " << alignment; } } - // SPIR-V requires struct members to be specified in memory address order, - // and they should not overlap. Vulkan relaxes that rule. - if (!permit_non_monotonic_member_offsets) { - const auto out_of_order = - ordered_member_idx > 0 && - (memberIdx < member_offsets[ordered_member_idx - 1].member); - if (out_of_order) { - return fail(memberIdx) - << "at offset " << offset << " has a higher offset than member " - << member_offsets[ordered_member_idx - 1].member << " at offset " - << prevOffset; - } - } if (offset < nextValidOffset) return fail(memberIdx) << "at offset " << offset << " overlaps previous member ending at offset " << nextValidOffset - 1; - if (relaxed_block_layout) { + if (!scalar_block_layout && relaxed_block_layout) { // Check improper straddle of vectors. if (SpvOpTypeVector == opcode && hasImproperStraddle(id, offset, constraint, constraints, vstate)) @@ -445,9 +499,9 @@ spv_result_t checkLayout(uint32_t struct_id, const char* storage_class_str, // Check struct members recursively. spv_result_t recursive_status = SPV_SUCCESS; if (SpvOpTypeStruct == opcode && - SPV_SUCCESS != (recursive_status = - checkLayout(id, storage_class_str, decoration_str, - blockRules, constraints, vstate))) + SPV_SUCCESS != (recursive_status = checkLayout( + id, storage_class_str, decoration_str, blockRules, + offset, constraints, vstate))) return recursive_status; // Check matrix stride. if (SpvOpTypeMatrix == opcode) { @@ -459,44 +513,91 @@ spv_result_t checkLayout(uint32_t struct_id, const char* storage_class_str, << " not satisfying alignment to " << alignment; } } - // Check arrays. - if (SpvOpTypeArray == opcode) { - const auto typeId = inst->word(2); - const auto arrayInst = vstate.FindDef(typeId); - if (SpvOpTypeStruct == arrayInst->opcode() && - SPV_SUCCESS != (recursive_status = checkLayout( - typeId, storage_class_str, decoration_str, - blockRules, constraints, vstate))) - return recursive_status; + + // Check arrays and runtime arrays recursively. + auto array_inst = inst; + auto array_alignment = alignment; + while (array_inst->opcode() == SpvOpTypeArray || + array_inst->opcode() == SpvOpTypeRuntimeArray) { + const auto typeId = array_inst->word(2); + const auto element_inst = vstate.FindDef(typeId); // Check array stride. - for (auto& decoration : vstate.id_decorations(id)) { - if (SpvDecorationArrayStride == decoration.dec_type() && - !IsAlignedTo(decoration.params()[0], alignment)) - return fail(memberIdx) - << "is an array with stride " << decoration.params()[0] - << " not satisfying alignment to " << alignment; + uint32_t array_stride = 0; + for (auto& decoration : vstate.id_decorations(array_inst->id())) { + if (SpvDecorationArrayStride == decoration.dec_type()) { + array_stride = decoration.params()[0]; + if (array_stride == 0) { + return fail(memberIdx) << "contains an array with stride 0"; + } + if (!IsAlignedTo(array_stride, array_alignment)) + return fail(memberIdx) + << "contains an array with stride " << decoration.params()[0] + << " not satisfying alignment to " << alignment; + } + } + + bool is_int32 = false; + bool is_const = false; + uint32_t num_elements = 0; + if (array_inst->opcode() == SpvOpTypeArray) { + std::tie(is_int32, is_const, num_elements) = + vstate.EvalInt32IfConst(array_inst->word(3)); + } + num_elements = std::max(1u, num_elements); + // Check each element recursively if it is a struct. There is a + // limitation to this check if the array size is a spec constant or is a + // runtime array then we will only check a single element. This means + // some improper straddles might be missed. + for (uint32_t i = 0; i < num_elements; ++i) { + uint32_t next_offset = i * array_stride + offset; + if (SpvOpTypeStruct == element_inst->opcode() && + SPV_SUCCESS != (recursive_status = checkLayout( + typeId, storage_class_str, decoration_str, + blockRules, next_offset, constraints, vstate))) + return recursive_status; + // If offsets accumulate up to a 16-byte multiple stop checking since + // it will just repeat. + if (i > 0 && (next_offset % 16 == 0)) break; + } + + // Proceed to the element in case it is an array. + array_inst = element_inst; + array_alignment = scalar_block_layout + ? getScalarAlignment(array_inst->id(), vstate) + : getBaseAlignment(array_inst->id(), blockRules, + constraint, constraints, vstate); + + const auto element_size = + getSize(element_inst->id(), constraint, constraints, vstate); + if (element_size > array_stride) { + return fail(memberIdx) + << "contains an array with stride " << array_stride + << ", but with an element size of " << element_size; } } nextValidOffset = offset + size; - if (blockRules && (SpvOpTypeArray == opcode || SpvOpTypeStruct == opcode)) { + if (!scalar_block_layout && blockRules && + (SpvOpTypeArray == opcode || SpvOpTypeStruct == opcode)) { // Uniform block rules don't permit anything in the padding of a struct // or array. nextValidOffset = align(nextValidOffset, alignment); } - prevOffset = offset; } return SPV_SUCCESS; } -// Returns true if structure id has given decoration. Handles also nested -// structures. -bool hasDecoration(uint32_t struct_id, SpvDecoration decoration, +// Returns true if variable or structure id has given decoration. Handles also +// nested structures. +bool hasDecoration(uint32_t id, SpvDecoration decoration, ValidationState_t& vstate) { - for (auto& dec : vstate.id_decorations(struct_id)) { + for (auto& dec : vstate.id_decorations(id)) { if (decoration == dec.dec_type()) return true; } - for (auto id : getStructMembers(struct_id, SpvOpTypeStruct, vstate)) { - if (hasDecoration(id, decoration, vstate)) { + if (SpvOpTypeStruct != vstate.FindDef(id)->opcode()) { + return false; + } + for (auto member_id : getStructMembers(id, SpvOpTypeStruct, vstate)) { + if (hasDecoration(member_id, decoration, vstate)) { return true; } } @@ -598,6 +699,7 @@ spv_result_t CheckDecorationsOfEntryPoints(ValidationState_t& vstate) { int num_builtin_inputs = 0; int num_builtin_outputs = 0; for (const auto& desc : descs) { + std::unordered_set seen_vars; for (auto interface : desc.interfaces) { Instruction* var_instr = vstate.FindDef(interface); if (!var_instr || SpvOpVariable != var_instr->opcode()) { @@ -608,14 +710,30 @@ spv_result_t CheckDecorationsOfEntryPoints(ValidationState_t& vstate) { } const SpvStorageClass storage_class = var_instr->GetOperandAs(2); - if (storage_class != SpvStorageClassInput && - storage_class != SpvStorageClassOutput) { - return vstate.diag(SPV_ERROR_INVALID_ID, var_instr) - << "OpEntryPoint interfaces must be OpVariables with " - "Storage Class of Input(1) or Output(3). Found Storage " - "Class " - << storage_class << " for Entry Point id " << entry_point - << "."; + if (vstate.version() >= SPV_SPIRV_VERSION_WORD(1, 4)) { + // Starting in 1.4, OpEntryPoint must list all global variables + // it statically uses and those interfaces must be unique. + if (storage_class == SpvStorageClassFunction) { + return vstate.diag(SPV_ERROR_INVALID_ID, var_instr) + << "OpEntryPoint interfaces should only list global " + "variables"; + } + + if (!seen_vars.insert(var_instr).second) { + return vstate.diag(SPV_ERROR_INVALID_ID, var_instr) + << "Non-unique OpEntryPoint interface " + << vstate.getIdName(interface) << " is disallowed"; + } + } else { + if (storage_class != SpvStorageClassInput && + storage_class != SpvStorageClassOutput) { + return vstate.diag(SPV_ERROR_INVALID_ID, var_instr) + << "OpEntryPoint interfaces must be OpVariables with " + "Storage Class of Input(1) or Output(3). Found Storage " + "Class " + << storage_class << " for Entry Point id " << entry_point + << "."; + } } const uint32_t ptr_id = var_instr->word(1); @@ -664,42 +782,6 @@ spv_result_t CheckDecorationsOfEntryPoints(ValidationState_t& vstate) { return SPV_SUCCESS; } -spv_result_t CheckDescriptorSetArrayOfArrays(ValidationState_t& vstate) { - for (const auto& inst : vstate.ordered_instructions()) { - if (SpvOpVariable != inst.opcode()) continue; - - // Verify this variable is a DescriptorSet - bool has_descriptor_set = false; - for (const auto& decoration : vstate.id_decorations(inst.id())) { - if (SpvDecorationDescriptorSet == decoration.dec_type()) { - has_descriptor_set = true; - break; - } - } - if (!has_descriptor_set) continue; - - const auto* ptrInst = vstate.FindDef(inst.word(1)); - assert(SpvOpTypePointer == ptrInst->opcode()); - - // Check for a first level array - const auto typePtr = vstate.FindDef(ptrInst->word(3)); - if (SpvOpTypeRuntimeArray != typePtr->opcode() && - SpvOpTypeArray != typePtr->opcode()) { - continue; - } - - // Check for a second level array - const auto secondaryTypePtr = vstate.FindDef(typePtr->word(2)); - if (SpvOpTypeRuntimeArray == secondaryTypePtr->opcode() || - SpvOpTypeArray == secondaryTypePtr->opcode()) { - return vstate.diag(SPV_ERROR_INVALID_ID, &inst) - << "Only a single level of array is allowed for descriptor " - "set variables"; - } - } - return SPV_SUCCESS; -} - // Load |constraints| with all the member constraints for structs contained // within the given array type. void ComputeMemberConstraintsForArray(MemberConstraints* constraints, @@ -782,20 +864,97 @@ void ComputeMemberConstraintsForArray(MemberConstraints* constraints, } spv_result_t CheckDecorationsOfBuffers(ValidationState_t& vstate) { + // Set of entry points that are known to use a push constant. + std::unordered_set uses_push_constant; for (const auto& inst : vstate.ordered_instructions()) { const auto& words = inst.words(); if (SpvOpVariable == inst.opcode()) { + const auto var_id = inst.id(); // For storage class / decoration combinations, see Vulkan 14.5.4 "Offset // and Stride Assignment". const auto storageClass = words[3]; const bool uniform = storageClass == SpvStorageClassUniform; + const bool uniform_constant = + storageClass == SpvStorageClassUniformConstant; const bool push_constant = storageClass == SpvStorageClassPushConstant; const bool storage_buffer = storageClass == SpvStorageClassStorageBuffer; - if (uniform || push_constant || storage_buffer) { + + if (spvIsVulkanEnv(vstate.context()->target_env)) { + // Vulkan 14.5.1: There must be no more than one PushConstant block + // per entry point. + if (push_constant) { + auto entry_points = vstate.EntryPointReferences(var_id); + for (auto ep_id : entry_points) { + const bool already_used = !uses_push_constant.insert(ep_id).second; + if (already_used) { + return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(var_id)) + << "Entry point id '" << ep_id + << "' uses more than one PushConstant interface.\n" + << "From Vulkan spec, section 14.5.1:\n" + << "There must be no more than one push constant block " + << "statically used per shader entry point."; + } + } + } + // Vulkan 14.5.2: Check DescriptorSet and Binding decoration for + // UniformConstant which cannot be a struct. + if (uniform_constant) { + auto entry_points = vstate.EntryPointReferences(var_id); + if (!entry_points.empty() && + !hasDecoration(var_id, SpvDecorationDescriptorSet, vstate)) { + return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(var_id)) + << "UniformConstant id '" << var_id + << "' is missing DescriptorSet decoration.\n" + << "From Vulkan spec, section 14.5.2:\n" + << "These variables must have DescriptorSet and Binding " + "decorations specified"; + } + if (!entry_points.empty() && + !hasDecoration(var_id, SpvDecorationBinding, vstate)) { + return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(var_id)) + << "UniformConstant id '" << var_id + << "' is missing Binding decoration.\n" + << "From Vulkan spec, section 14.5.2:\n" + << "These variables must have DescriptorSet and Binding " + "decorations specified"; + } + } + } + + if (spvIsOpenGLEnv(vstate.context()->target_env)) { + bool has_block = hasDecoration(var_id, SpvDecorationBlock, vstate); + bool has_buffer_block = + hasDecoration(var_id, SpvDecorationBufferBlock, vstate); + if ((uniform && (has_block || has_buffer_block)) || + (storage_buffer && has_block)) { + auto entry_points = vstate.EntryPointReferences(var_id); + if (!entry_points.empty() && + !hasDecoration(var_id, SpvDecorationBinding, vstate)) { + return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(var_id)) + << (uniform ? "Uniform" : "Storage Buffer") << " id '" + << var_id << "' is missing Binding decoration.\n" + << "From ARB_gl_spirv extension:\n" + << "Uniform and shader storage block variables must " + << "also be decorated with a *Binding*."; + } + } + } + + const bool phys_storage_buffer = + storageClass == SpvStorageClassPhysicalStorageBufferEXT; + if (uniform || push_constant || storage_buffer || phys_storage_buffer) { const auto ptrInst = vstate.FindDef(words[1]); assert(SpvOpTypePointer == ptrInst->opcode()); - const auto id = ptrInst->words()[3]; - if (SpvOpTypeStruct != vstate.FindDef(id)->opcode()) continue; + auto id = ptrInst->words()[3]; + auto id_inst = vstate.FindDef(id); + // Jump through one level of arraying. + if (id_inst->opcode() == SpvOpTypeArray || + id_inst->opcode() == SpvOpTypeRuntimeArray) { + id = id_inst->GetOperandAs(1u); + id_inst = vstate.FindDef(id); + } + // Struct requirement is checked on variables so just move on here. + if (SpvOpTypeStruct != id_inst->opcode()) continue; MemberConstraints constraints; ComputeMemberConstraintsForStruct(&constraints, id, LayoutConstraints(), vstate); @@ -803,20 +962,93 @@ spv_result_t CheckDecorationsOfBuffers(ValidationState_t& vstate) { const char* sc_str = uniform ? "Uniform" : (push_constant ? "PushConstant" : "StorageBuffer"); + + if (spvIsVulkanEnv(vstate.context()->target_env)) { + const bool block = hasDecoration(id, SpvDecorationBlock, vstate); + const bool buffer_block = + hasDecoration(id, SpvDecorationBufferBlock, vstate); + if (storage_buffer && buffer_block) { + return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(var_id)) + << "Storage buffer id '" << var_id + << " In Vulkan, BufferBlock is disallowed on variables in " + "the StorageBuffer storage class"; + } + // Vulkan 14.5.1/2: Check Block decoration for PushConstant, Uniform + // and StorageBuffer variables. Uniform can also use BufferBlock. + if (push_constant && !block) { + return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(id)) + << "PushConstant id '" << id + << "' is missing Block decoration.\n" + << "From Vulkan spec, section 14.5.1:\n" + << "Such variables must be identified with a Block " + "decoration"; + } + if (storage_buffer && !block) { + return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(id)) + << "StorageBuffer id '" << id + << "' is missing Block decoration.\n" + << "From Vulkan spec, section 14.5.2:\n" + << "Such variables must be identified with a Block " + "decoration"; + } + if (uniform && !block && !buffer_block) { + return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(id)) + << "Uniform id '" << id + << "' is missing Block or BufferBlock decoration.\n" + << "From Vulkan spec, section 14.5.2:\n" + << "Such variables must be identified with a Block or " + "BufferBlock decoration"; + } + // Vulkan 14.5.2: Check DescriptorSet and Binding decoration for + // Uniform and StorageBuffer variables. + if (uniform || storage_buffer) { + auto entry_points = vstate.EntryPointReferences(var_id); + if (!entry_points.empty() && + !hasDecoration(var_id, SpvDecorationDescriptorSet, vstate)) { + return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(var_id)) + << sc_str << " id '" << var_id + << "' is missing DescriptorSet decoration.\n" + << "From Vulkan spec, section 14.5.2:\n" + << "These variables must have DescriptorSet and Binding " + "decorations specified"; + } + if (!entry_points.empty() && + !hasDecoration(var_id, SpvDecorationBinding, vstate)) { + return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(var_id)) + << sc_str << " id '" << var_id + << "' is missing Binding decoration.\n" + << "From Vulkan spec, section 14.5.2:\n" + << "These variables must have DescriptorSet and Binding " + "decorations specified"; + } + } + } + for (const auto& dec : vstate.id_decorations(id)) { const bool blockDeco = SpvDecorationBlock == dec.dec_type(); const bool bufferDeco = SpvDecorationBufferBlock == dec.dec_type(); const bool blockRules = uniform && blockDeco; - const bool bufferRules = (uniform && bufferDeco) || - (push_constant && blockDeco) || - (storage_buffer && blockDeco); + const bool bufferRules = + (uniform && bufferDeco) || (push_constant && blockDeco) || + ((storage_buffer || phys_storage_buffer) && blockDeco); + if (uniform && blockDeco) { + vstate.RegisterPointerToUniformBlock(ptrInst->id()); + vstate.RegisterStructForUniformBlock(id); + } + if ((uniform && bufferDeco) || + ((storage_buffer || phys_storage_buffer) && blockDeco)) { + vstate.RegisterPointerToStorageBuffer(ptrInst->id()); + vstate.RegisterStructForStorageBuffer(id); + } + if (blockRules || bufferRules) { const char* deco_str = blockDeco ? "Block" : "BufferBlock"; spv_result_t recursive_status = SPV_SUCCESS; if (isMissingOffsetInStruct(id, vstate)) { return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(id)) << "Structure id " << id << " decorated as " << deco_str - << " must be explicitly laid out with Offset decorations."; + << " must be explicitly laid out with Offset " + "decorations."; } else if (hasDecoration(id, SpvDecorationGLSLShared, vstate)) { return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(id)) << "Structure id " << id << " decorated as " << deco_str @@ -840,12 +1072,12 @@ spv_result_t CheckDecorationsOfBuffers(ValidationState_t& vstate) { "decorations."; } else if (blockRules && (SPV_SUCCESS != (recursive_status = checkLayout( - id, sc_str, deco_str, true, + id, sc_str, deco_str, true, 0, constraints, vstate)))) { return recursive_status; } else if (bufferRules && (SPV_SUCCESS != (recursive_status = checkLayout( - id, sc_str, deco_str, false, + id, sc_str, deco_str, false, 0, constraints, vstate)))) { return recursive_status; } @@ -857,15 +1089,506 @@ spv_result_t CheckDecorationsOfBuffers(ValidationState_t& vstate) { return SPV_SUCCESS; } +// Returns true if |decoration| cannot be applied to the same id more than once. +bool AtMostOncePerId(SpvDecoration decoration) { + return decoration == SpvDecorationArrayStride; +} + +// Returns true if |decoration| cannot be applied to the same member more than +// once. +bool AtMostOncePerMember(SpvDecoration decoration) { + switch (decoration) { + case SpvDecorationOffset: + case SpvDecorationMatrixStride: + case SpvDecorationRowMajor: + case SpvDecorationColMajor: + return true; + default: + return false; + } +} + +// Returns the string name for |decoration|. +const char* GetDecorationName(SpvDecoration decoration) { + switch (decoration) { + case SpvDecorationAliased: + return "Aliased"; + case SpvDecorationRestrict: + return "Restrict"; + case SpvDecorationArrayStride: + return "ArrayStride"; + case SpvDecorationOffset: + return "Offset"; + case SpvDecorationMatrixStride: + return "MatrixStride"; + case SpvDecorationRowMajor: + return "RowMajor"; + case SpvDecorationColMajor: + return "ColMajor"; + case SpvDecorationBlock: + return "Block"; + case SpvDecorationBufferBlock: + return "BufferBlock"; + default: + return ""; + } +} + +spv_result_t CheckDecorationsCompatibility(ValidationState_t& vstate) { + using PerIDKey = std::tuple; + using PerMemberKey = std::tuple; + + // An Array of pairs where the decorations in the pair cannot both be applied + // to the same id. + static const SpvDecoration mutually_exclusive_per_id[][2] = { + {SpvDecorationBlock, SpvDecorationBufferBlock}, + {SpvDecorationRestrict, SpvDecorationAliased}}; + static const auto num_mutually_exclusive_per_id_pairs = + sizeof(mutually_exclusive_per_id) / (2 * sizeof(SpvDecoration)); + + // An Array of pairs where the decorations in the pair cannot both be applied + // to the same member. + static const SpvDecoration mutually_exclusive_per_member[][2] = { + {SpvDecorationRowMajor, SpvDecorationColMajor}}; + static const auto num_mutually_exclusive_per_mem_pairs = + sizeof(mutually_exclusive_per_member) / (2 * sizeof(SpvDecoration)); + + std::set seen_per_id; + std::set seen_per_member; + + for (const auto& inst : vstate.ordered_instructions()) { + const auto& words = inst.words(); + if (SpvOpDecorate == inst.opcode()) { + const auto id = words[1]; + const auto dec_type = static_cast(words[2]); + const auto k = PerIDKey(dec_type, id); + const auto already_used = !seen_per_id.insert(k).second; + if (already_used && AtMostOncePerId(dec_type)) { + return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(id)) + << "ID '" << id << "' decorated with " + << GetDecorationName(dec_type) + << " multiple times is not allowed."; + } + // Verify certain mutually exclusive decorations are not both applied on + // an ID. + for (uint32_t pair_idx = 0; + pair_idx < num_mutually_exclusive_per_id_pairs; ++pair_idx) { + SpvDecoration excl_dec_type = SpvDecorationMax; + if (mutually_exclusive_per_id[pair_idx][0] == dec_type) { + excl_dec_type = mutually_exclusive_per_id[pair_idx][1]; + } else if (mutually_exclusive_per_id[pair_idx][1] == dec_type) { + excl_dec_type = mutually_exclusive_per_id[pair_idx][0]; + } else { + continue; + } + + const auto excl_k = PerIDKey(excl_dec_type, id); + if (seen_per_id.find(excl_k) != seen_per_id.end()) { + return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(id)) + << "ID '" << id << "' decorated with both " + << GetDecorationName(dec_type) << " and " + << GetDecorationName(excl_dec_type) << " is not allowed."; + } + } + } else if (SpvOpMemberDecorate == inst.opcode()) { + const auto id = words[1]; + const auto member_id = words[2]; + const auto dec_type = static_cast(words[3]); + const auto k = PerMemberKey(dec_type, id, member_id); + const auto already_used = !seen_per_member.insert(k).second; + if (already_used && AtMostOncePerMember(dec_type)) { + return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(id)) + << "ID '" << id << "', member '" << member_id + << "' decorated with " << GetDecorationName(dec_type) + << " multiple times is not allowed."; + } + // Verify certain mutually exclusive decorations are not both applied on + // a (ID, member) tuple. + for (uint32_t pair_idx = 0; + pair_idx < num_mutually_exclusive_per_mem_pairs; ++pair_idx) { + SpvDecoration excl_dec_type = SpvDecorationMax; + if (mutually_exclusive_per_member[pair_idx][0] == dec_type) { + excl_dec_type = mutually_exclusive_per_member[pair_idx][1]; + } else if (mutually_exclusive_per_member[pair_idx][1] == dec_type) { + excl_dec_type = mutually_exclusive_per_member[pair_idx][0]; + } else { + continue; + } + + const auto excl_k = PerMemberKey(excl_dec_type, id, member_id); + if (seen_per_member.find(excl_k) != seen_per_member.end()) { + return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(id)) + << "ID '" << id << "', member '" << member_id + << "' decorated with both " << GetDecorationName(dec_type) + << " and " << GetDecorationName(excl_dec_type) + << " is not allowed."; + } + } + } + } + return SPV_SUCCESS; +} + +spv_result_t CheckVulkanMemoryModelDeprecatedDecorations( + ValidationState_t& vstate) { + if (vstate.memory_model() != SpvMemoryModelVulkanKHR) return SPV_SUCCESS; + + std::string msg; + std::ostringstream str(msg); + for (const auto& def : vstate.all_definitions()) { + const auto inst = def.second; + const auto id = inst->id(); + for (const auto& dec : vstate.id_decorations(id)) { + const auto member = dec.struct_member_index(); + if (dec.dec_type() == SpvDecorationCoherent || + dec.dec_type() == SpvDecorationVolatile) { + str << (dec.dec_type() == SpvDecorationCoherent ? "Coherent" + : "Volatile"); + str << " decoration targeting " << vstate.getIdName(id); + if (member != Decoration::kInvalidMember) { + str << " (member index " << member << ")"; + } + str << " is banned when using the Vulkan memory model."; + return vstate.diag(SPV_ERROR_INVALID_ID, inst) << str.str(); + } + } + } + return SPV_SUCCESS; +} + +// Returns SPV_SUCCESS if validation rules are satisfied for FPRoundingMode +// decorations. Otherwise emits a diagnostic and returns something other than +// SPV_SUCCESS. +spv_result_t CheckFPRoundingModeForShaders(ValidationState_t& vstate, + const Instruction& inst) { + // Validates width-only conversion instruction for floating-point object + // i.e., OpFConvert + if (inst.opcode() != SpvOpFConvert) { + return vstate.diag(SPV_ERROR_INVALID_ID, &inst) + << "FPRoundingMode decoration can be applied only to a " + "width-only conversion instruction for floating-point " + "object."; + } + + // Validates Object operand of an OpStore + for (const auto& use : inst.uses()) { + const auto store = use.first; + if (store->opcode() == SpvOpFConvert) continue; + if (spvOpcodeIsDebug(store->opcode())) continue; + if (store->IsNonSemantic()) continue; + if (spvOpcodeIsDecoration(store->opcode())) continue; + if (store->opcode() != SpvOpStore) { + return vstate.diag(SPV_ERROR_INVALID_ID, &inst) + << "FPRoundingMode decoration can be applied only to the " + "Object operand of an OpStore."; + } + + if (use.second != 2) { + return vstate.diag(SPV_ERROR_INVALID_ID, &inst) + << "FPRoundingMode decoration can be applied only to the " + "Object operand of an OpStore."; + } + + const auto ptr_inst = vstate.FindDef(store->GetOperandAs(0)); + const auto ptr_type = vstate.FindDef(ptr_inst->GetOperandAs(0)); + + const auto half_float_id = ptr_type->GetOperandAs(2); + if (!vstate.IsFloatScalarOrVectorType(half_float_id) || + vstate.GetBitWidth(half_float_id) != 16) { + return vstate.diag(SPV_ERROR_INVALID_ID, &inst) + << "FPRoundingMode decoration can be applied only to the " + "Object operand of an OpStore storing through a pointer " + "to " + "a 16-bit floating-point scalar or vector object."; + } + + // Validates storage class of the pointer to the OpStore + const auto storage = ptr_type->GetOperandAs(1); + if (storage != SpvStorageClassStorageBuffer && + storage != SpvStorageClassUniform && + storage != SpvStorageClassPushConstant && + storage != SpvStorageClassInput && storage != SpvStorageClassOutput && + storage != SpvStorageClassPhysicalStorageBufferEXT) { + return vstate.diag(SPV_ERROR_INVALID_ID, &inst) + << "FPRoundingMode decoration can be applied only to the " + "Object operand of an OpStore in the StorageBuffer, " + "PhysicalStorageBufferEXT, Uniform, PushConstant, Input, or " + "Output Storage Classes."; + } + } + return SPV_SUCCESS; +} + +// Returns SPV_SUCCESS if validation rules are satisfied for the NonWritable +// decoration. Otherwise emits a diagnostic and returns something other than +// SPV_SUCCESS. The |inst| parameter is the object being decorated. This must +// be called after TypePass and AnnotateCheckDecorationsOfBuffers are called. +spv_result_t CheckNonWritableDecoration(ValidationState_t& vstate, + const Instruction& inst, + const Decoration& decoration) { + assert(inst.id() && "Parser ensures the target of the decoration has an ID"); + + if (decoration.struct_member_index() == Decoration::kInvalidMember) { + // The target must be a memory object declaration. + // First, it must be a variable or function parameter. + const auto opcode = inst.opcode(); + const auto type_id = inst.type_id(); + if (opcode != SpvOpVariable && opcode != SpvOpFunctionParameter) { + return vstate.diag(SPV_ERROR_INVALID_ID, &inst) + << "Target of NonWritable decoration must be a memory object " + "declaration (a variable or a function parameter)"; + } + const auto var_storage_class = opcode == SpvOpVariable + ? inst.GetOperandAs(2) + : SpvStorageClassMax; + if ((var_storage_class == SpvStorageClassFunction || + var_storage_class == SpvStorageClassPrivate) && + vstate.features().nonwritable_var_in_function_or_private) { + // New permitted feature in SPIR-V 1.4. + } else if ( + // It may point to a UBO, SSBO, or storage image. + vstate.IsPointerToUniformBlock(type_id) || + vstate.IsPointerToStorageBuffer(type_id) || + vstate.IsPointerToStorageImage(type_id)) { + } else { + return vstate.diag(SPV_ERROR_INVALID_ID, &inst) + << "Target of NonWritable decoration is invalid: must point to a " + "storage image, uniform block, " + << (vstate.features().nonwritable_var_in_function_or_private + ? "storage buffer, or variable in Private or Function " + "storage class" + : "or storage buffer"); + } + } + + return SPV_SUCCESS; +} + +// Returns SPV_SUCCESS if validation rules are satisfied for Uniform or +// UniformId decorations. Otherwise emits a diagnostic and returns something +// other than SPV_SUCCESS. Assumes each decoration on a group has been +// propagated down to the group members. The |inst| parameter is the object +// being decorated. +spv_result_t CheckUniformDecoration(ValidationState_t& vstate, + const Instruction& inst, + const Decoration& decoration) { + const char* const dec_name = + decoration.dec_type() == SpvDecorationUniform ? "Uniform" : "UniformId"; + + // Uniform or UniformId must decorate an "object" + // - has a result ID + // - is an instantiation of a non-void type. So it has a type ID, and that + // type is not void. + + // We already know the result ID is non-zero. + + if (inst.type_id() == 0) { + return vstate.diag(SPV_ERROR_INVALID_ID, &inst) + << dec_name << " decoration applied to a non-object"; + } + if (Instruction* type_inst = vstate.FindDef(inst.type_id())) { + if (type_inst->opcode() == SpvOpTypeVoid) { + return vstate.diag(SPV_ERROR_INVALID_ID, &inst) + << dec_name << " decoration applied to a value with void type"; + } + } else { + // We might never get here because this would have been rejected earlier in + // the flow. + return vstate.diag(SPV_ERROR_INVALID_ID, &inst) + << dec_name << " decoration applied to an object with invalid type"; + } + + // Use of Uniform with OpDecorate is checked elsewhere. + // Use of UniformId with OpDecorateId is checked elsewhere. + + if (decoration.dec_type() == SpvDecorationUniformId) { + assert(decoration.params().size() == 1 && + "Grammar ensures UniformId has one parameter"); + + // The scope id is an execution scope. + if (auto error = + ValidateExecutionScope(vstate, &inst, decoration.params()[0])) + return error; + } + + return SPV_SUCCESS; +} + +// Returns SPV_SUCCESS if validation rules are satisfied for NoSignedWrap or +// NoUnsignedWrap decorations. Otherwise emits a diagnostic and returns +// something other than SPV_SUCCESS. Assumes each decoration on a group has been +// propagated down to the group members. +spv_result_t CheckIntegerWrapDecoration(ValidationState_t& vstate, + const Instruction& inst, + const Decoration& decoration) { + switch (inst.opcode()) { + case SpvOpIAdd: + case SpvOpISub: + case SpvOpIMul: + case SpvOpShiftLeftLogical: + case SpvOpSNegate: + return SPV_SUCCESS; + case SpvOpExtInst: + // TODO(dneto): Only certain extended instructions allow these + // decorations. For now allow anything. + return SPV_SUCCESS; + default: + break; + } + + return vstate.diag(SPV_ERROR_INVALID_ID, &inst) + << (decoration.dec_type() == SpvDecorationNoSignedWrap + ? "NoSignedWrap" + : "NoUnsignedWrap") + << " decoration may not be applied to " + << spvOpcodeString(inst.opcode()); +} + +// Returns SPV_SUCCESS if validation rules are satisfied for the Component +// decoration. Otherwise emits a diagnostic and returns something other than +// SPV_SUCCESS. +spv_result_t CheckComponentDecoration(ValidationState_t& vstate, + const Instruction& inst, + const Decoration& decoration) { + assert(inst.id() && "Parser ensures the target of the decoration has an ID"); + + uint32_t type_id; + if (decoration.struct_member_index() == Decoration::kInvalidMember) { + // The target must be a memory object declaration. + const auto opcode = inst.opcode(); + if (opcode != SpvOpVariable && opcode != SpvOpFunctionParameter) { + return vstate.diag(SPV_ERROR_INVALID_ID, &inst) + << "Target of Component decoration must be a memory object " + "declaration (a variable or a function parameter)"; + } + + // Only valid for the Input and Output Storage Classes. + const auto storage_class = opcode == SpvOpVariable + ? inst.GetOperandAs(2) + : SpvStorageClassMax; + if (storage_class != SpvStorageClassInput && + storage_class != SpvStorageClassOutput && + storage_class != SpvStorageClassMax) { + return vstate.diag(SPV_ERROR_INVALID_ID, &inst) + << "Target of Component decoration is invalid: must point to a " + "Storage Class of Input(1) or Output(3). Found Storage " + "Class " + << storage_class; + } + + type_id = inst.type_id(); + if (vstate.IsPointerType(type_id)) { + const auto pointer = vstate.FindDef(type_id); + type_id = pointer->GetOperandAs(2); + } + } else { + if (inst.opcode() != SpvOpTypeStruct) { + return vstate.diag(SPV_ERROR_INVALID_DATA, &inst) + << "Attempted to get underlying data type via member index for " + "non-struct type."; + } + type_id = inst.word(decoration.struct_member_index() + 2); + } + + if (spvIsVulkanEnv(vstate.context()->target_env)) { + // Strip the array, if present. + if (vstate.GetIdOpcode(type_id) == SpvOpTypeArray) { + type_id = vstate.FindDef(type_id)->word(2u); + } + + if (!vstate.IsIntScalarOrVectorType(type_id) && + !vstate.IsFloatScalarOrVectorType(type_id)) { + return vstate.diag(SPV_ERROR_INVALID_ID, &inst) + << "Component decoration specified for type " + << vstate.getIdName(type_id) << " that is not a scalar or vector"; + } + + // For 16-, and 32-bit types, it is invalid if this sequence of components + // gets larger than 3. + const auto bit_width = vstate.GetBitWidth(type_id); + if (bit_width == 16 || bit_width == 32) { + assert(decoration.params().size() == 1 && + "Grammar ensures Component has one parameter"); + + const auto component = decoration.params()[0]; + const auto last_component = component + vstate.GetDimension(type_id) - 1; + if (last_component > 3) { + return vstate.diag(SPV_ERROR_INVALID_ID, &inst) + << "Sequence of components starting with " << component + << " and ending with " << last_component + << " gets larger than 3"; + } + } + } + + return SPV_SUCCESS; +} + +#define PASS_OR_BAIL_AT_LINE(X, LINE) \ + { \ + spv_result_t e##LINE = (X); \ + if (e##LINE != SPV_SUCCESS) return e##LINE; \ + } +#define PASS_OR_BAIL(X) PASS_OR_BAIL_AT_LINE(X, __LINE__) + +// Check rules for decorations where we start from the decoration rather +// than the decorated object. Assumes each decoration on a group have been +// propagated down to the group members. +spv_result_t CheckDecorationsFromDecoration(ValidationState_t& vstate) { + // Some rules are only checked for shaders. + const bool is_shader = vstate.HasCapability(SpvCapabilityShader); + + for (const auto& kv : vstate.id_decorations()) { + const uint32_t id = kv.first; + const auto& decorations = kv.second; + if (decorations.empty()) continue; + + const Instruction* inst = vstate.FindDef(id); + assert(inst); + + // We assume the decorations applied to a decoration group have already + // been propagated down to the group members. + if (inst->opcode() == SpvOpDecorationGroup) continue; + + for (const auto& decoration : decorations) { + switch (decoration.dec_type()) { + case SpvDecorationComponent: + PASS_OR_BAIL(CheckComponentDecoration(vstate, *inst, decoration)); + break; + case SpvDecorationFPRoundingMode: + if (is_shader) + PASS_OR_BAIL(CheckFPRoundingModeForShaders(vstate, *inst)); + break; + case SpvDecorationNonWritable: + PASS_OR_BAIL(CheckNonWritableDecoration(vstate, *inst, decoration)); + break; + case SpvDecorationUniform: + case SpvDecorationUniformId: + PASS_OR_BAIL(CheckUniformDecoration(vstate, *inst, decoration)); + break; + case SpvDecorationNoSignedWrap: + case SpvDecorationNoUnsignedWrap: + PASS_OR_BAIL(CheckIntegerWrapDecoration(vstate, *inst, decoration)); + break; + default: + break; + } + } + } + return SPV_SUCCESS; +} + } // namespace -// Validates that decorations have been applied properly. spv_result_t ValidateDecorations(ValidationState_t& vstate) { if (auto error = CheckImportedVariableInitialization(vstate)) return error; if (auto error = CheckDecorationsOfEntryPoints(vstate)) return error; if (auto error = CheckDecorationsOfBuffers(vstate)) return error; + if (auto error = CheckDecorationsCompatibility(vstate)) return error; if (auto error = CheckLinkageAttrOfFunctions(vstate)) return error; - if (auto error = CheckDescriptorSetArrayOfArrays(vstate)) return error; + if (auto error = CheckVulkanMemoryModelDeprecatedDecorations(vstate)) + return error; + if (auto error = CheckDecorationsFromDecoration(vstate)) return error; return SPV_SUCCESS; } diff --git a/third_party/spirv-tools/source/val/validate_derivatives.cpp b/third_party/spirv-tools/source/val/validate_derivatives.cpp index 0e0dbbe3d2..067cc964ce 100644 --- a/third_party/spirv-tools/source/val/validate_derivatives.cpp +++ b/third_party/spirv-tools/source/val/validate_derivatives.cpp @@ -46,6 +46,10 @@ spv_result_t DerivativesPass(ValidationState_t& _, const Instruction* inst) { << "Expected Result Type to be float scalar or vector type: " << spvOpcodeString(opcode); } + if (!_.ContainsSizedIntOrFloatType(result_type, SpvOpTypeFloat, 32)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Result type component width must be 32 bits"; + } const uint32_t p_type = _.GetOperandTypeId(inst, 2); if (p_type != result_type) { @@ -53,13 +57,45 @@ spv_result_t DerivativesPass(ValidationState_t& _, const Instruction* inst) { << "Expected P type and Result Type to be the same: " << spvOpcodeString(opcode); } - _.function(inst->function()->id()) - ->RegisterExecutionModelLimitation( - SpvExecutionModelFragment, - std::string("Derivative instructions require Fragment execution " - "model: ") + - spvOpcodeString(opcode)); + ->RegisterExecutionModelLimitation([opcode](SpvExecutionModel model, + std::string* message) { + if (model != SpvExecutionModelFragment && + model != SpvExecutionModelGLCompute) { + if (message) { + *message = + std::string( + "Derivative instructions require Fragment or GLCompute " + "execution model: ") + + spvOpcodeString(opcode); + } + return false; + } + return true; + }); + _.function(inst->function()->id()) + ->RegisterLimitation([opcode](const ValidationState_t& state, + const Function* entry_point, + std::string* message) { + const auto* models = state.GetExecutionModels(entry_point->id()); + const auto* modes = state.GetExecutionModes(entry_point->id()); + if (models->find(SpvExecutionModelGLCompute) != models->end() && + modes->find(SpvExecutionModeDerivativeGroupLinearNV) == + modes->end() && + modes->find(SpvExecutionModeDerivativeGroupQuadsNV) == + modes->end()) { + if (message) { + *message = std::string( + "Derivative instructions require " + "DerivativeGroupQuadsNV " + "or DerivativeGroupLinearNV execution mode for " + "GLCompute execution model: ") + + spvOpcodeString(opcode); + } + return false; + } + return true; + }); break; } diff --git a/third_party/spirv-tools/source/val/validate_execution_limitations.cpp b/third_party/spirv-tools/source/val/validate_execution_limitations.cpp index d449307701..aac1c4987a 100644 --- a/third_party/spirv-tools/source/val/validate_execution_limitations.cpp +++ b/third_party/spirv-tools/source/val/validate_execution_limitations.cpp @@ -53,6 +53,17 @@ spv_result_t ValidateExecutionLimitations(ValidationState_t& _, } } } + + std::string reason; + if (!func->CheckLimitations(_, _.function(entry_id), &reason)) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "OpEntryPoint Entry Point '" << _.getIdName(entry_id) + << "'s callgraph contains function " + << _.getIdName(inst->id()) + << ", which cannot be used with the current execution " + "modes:\n" + << reason; + } } return SPV_SUCCESS; } diff --git a/third_party/spirv-tools/source/val/validate_ext_inst.cpp b/third_party/spirv-tools/source/val/validate_extensions.cpp similarity index 96% rename from third_party/spirv-tools/source/val/validate_ext_inst.cpp rename to third_party/spirv-tools/source/val/validate_extensions.cpp index eb3427090e..070cc4c6ab 100644 --- a/third_party/spirv-tools/source/val/validate_ext_inst.cpp +++ b/third_party/spirv-tools/source/val/validate_extensions.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017 Google Inc. +// Copyright (c) 2018 Google Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Validates correctness of ExtInst SPIR-V instructions. +// Validates correctness of extension SPIR-V instructions. #include "source/val/validate.h" @@ -21,9 +21,12 @@ #include #include "source/diagnostic.h" +#include "source/enum_string_mapping.h" +#include "source/extensions.h" #include "source/latest_version_glsl_std_450_header.h" #include "source/latest_version_opencl_std_header.h" #include "source/opcode.h" +#include "source/spirv_target_env.h" #include "source/val/instruction.h" #include "source/val/validation_state.h" @@ -41,14 +44,51 @@ uint32_t GetSizeTBitWidth(const ValidationState_t& _) { } // anonymous namespace -// Validates correctness of ExtInst instructions. -spv_result_t ExtInstPass(ValidationState_t& _, const Instruction* inst) { - const SpvOp opcode = inst->opcode(); +spv_result_t ValidateExtension(ValidationState_t& _, const Instruction* inst) { + if (spvIsWebGPUEnv(_.context()->target_env)) { + std::string extension = GetExtensionString(&(inst->c_inst())); + + if (extension != ExtensionToString(kSPV_KHR_vulkan_memory_model)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "For WebGPU, the only valid parameter to OpExtension is " + << "\"" << ExtensionToString(kSPV_KHR_vulkan_memory_model) + << "\"."; + } + } + + return SPV_SUCCESS; +} + +spv_result_t ValidateExtInstImport(ValidationState_t& _, + const Instruction* inst) { + const auto name_id = 1; + if (spvIsWebGPUEnv(_.context()->target_env)) { + const std::string name(reinterpret_cast( + inst->words().data() + inst->operands()[name_id].offset)); + if (name != "GLSL.std.450") { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "For WebGPU, the only valid parameter to OpExtInstImport is " + "\"GLSL.std.450\"."; + } + } + + if (!_.HasExtension(kSPV_KHR_non_semantic_info)) { + const std::string name(reinterpret_cast( + inst->words().data() + inst->operands()[name_id].offset)); + if (name.find("NonSemantic.") == 0) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "NonSemantic extended instruction sets cannot be declared " + "without SPV_KHR_non_semantic_info."; + } + } + + return SPV_SUCCESS; +} + +spv_result_t ValidateExtInst(ValidationState_t& _, const Instruction* inst) { const uint32_t result_type = inst->type_id(); const uint32_t num_operands = static_cast(inst->operands().size()); - if (opcode != SpvOpExtInst) return SPV_SUCCESS; - const uint32_t ext_inst_set = inst->word(3); const uint32_t ext_inst_index = inst->word(4); const spv_ext_inst_type_t ext_inst_type = @@ -893,7 +933,58 @@ spv_result_t ExtInstPass(ValidationState_t& _, const Instruction* inst) { case OpenCLLIB::Fract: case OpenCLLIB::Modf: - case OpenCLLIB::Sincos: + case OpenCLLIB::Sincos: { + if (!_.IsFloatScalarOrVectorType(result_type)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << ext_inst_name() << ": " + << "expected Result Type to be a float scalar or vector type"; + } + + const uint32_t num_components = _.GetDimension(result_type); + if (num_components > 4 && num_components != 8 && num_components != 16) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << ext_inst_name() << ": " + << "expected Result Type to be a scalar or a vector with 2, " + "3, 4, 8 or 16 components"; + } + + const uint32_t x_type = _.GetOperandTypeId(inst, 4); + if (result_type != x_type) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << ext_inst_name() << ": " + << "expected type of operand X to be equal to Result Type"; + } + + const uint32_t p_type = _.GetOperandTypeId(inst, 5); + uint32_t p_storage_class = 0; + uint32_t p_data_type = 0; + if (!_.GetPointerTypeInfo(p_type, &p_data_type, &p_storage_class)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << ext_inst_name() << ": " + << "expected the last operand to be a pointer"; + } + + if (p_storage_class != SpvStorageClassGeneric && + p_storage_class != SpvStorageClassCrossWorkgroup && + p_storage_class != SpvStorageClassWorkgroup && + p_storage_class != SpvStorageClassFunction) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << ext_inst_name() << ": " + << "expected storage class of the pointer to be Generic, " + "CrossWorkgroup, Workgroup or Function"; + } + + if (result_type != p_data_type) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << ext_inst_name() << ": " + << "expected data type of the pointer to be equal to Result " + "Type"; + } + break; + } + + case OpenCLLIB::Frexp: + case OpenCLLIB::Lgamma_r: case OpenCLLIB::Remquo: { if (!_.IsFloatScalarOrVectorType(result_type)) { return _.diag(SPV_ERROR_INVALID_DATA, inst) @@ -945,57 +1036,6 @@ spv_result_t ExtInstPass(ValidationState_t& _, const Instruction* inst) { "CrossWorkgroup, Workgroup or Function"; } - if (result_type != p_data_type) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << ext_inst_name() << ": " - << "expected data type of the pointer to be equal to Result " - "Type"; - } - break; - } - - case OpenCLLIB::Frexp: - case OpenCLLIB::Lgamma_r: { - if (!_.IsFloatScalarOrVectorType(result_type)) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << ext_inst_name() << ": " - << "expected Result Type to be a float scalar or vector type"; - } - - const uint32_t num_components = _.GetDimension(result_type); - if (num_components > 4 && num_components != 8 && num_components != 16) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << ext_inst_name() << ": " - << "expected Result Type to be a scalar or a vector with 2, " - "3, 4, 8 or 16 components"; - } - - const uint32_t x_type = _.GetOperandTypeId(inst, 4); - if (result_type != x_type) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << ext_inst_name() << ": " - << "expected type of operand X to be equal to Result Type"; - } - - const uint32_t p_type = _.GetOperandTypeId(inst, 5); - uint32_t p_storage_class = 0; - uint32_t p_data_type = 0; - if (!_.GetPointerTypeInfo(p_type, &p_data_type, &p_storage_class)) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << ext_inst_name() << ": " - << "expected the last operand to be a pointer"; - } - - if (p_storage_class != SpvStorageClassGeneric && - p_storage_class != SpvStorageClassCrossWorkgroup && - p_storage_class != SpvStorageClassWorkgroup && - p_storage_class != SpvStorageClassFunction) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << ext_inst_name() << ": " - << "expected storage class of the pointer to be Generic, " - "CrossWorkgroup, Workgroup or Function"; - } - if (!_.IsIntScalarOrVectorType(p_data_type) || _.GetBitWidth(p_data_type) != 32) { return _.diag(SPV_ERROR_INVALID_DATA, inst) @@ -1517,11 +1557,14 @@ spv_result_t ExtInstPass(ValidationState_t& _, const Instruction* inst) { } if (p_storage_class != SpvStorageClassUniformConstant && - p_storage_class != SpvStorageClassGeneric) { + p_storage_class != SpvStorageClassGeneric && + p_storage_class != SpvStorageClassCrossWorkgroup && + p_storage_class != SpvStorageClassWorkgroup && + p_storage_class != SpvStorageClassFunction) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << ext_inst_name() << ": " - << "expected operand P storage class to be UniformConstant or " - "Generic"; + << "expected operand P storage class to be UniformConstant, " + "Generic, CrossWorkgroup, Workgroup or Function"; } if (_.GetComponentType(result_type) != p_data_type) { @@ -1588,10 +1631,14 @@ spv_result_t ExtInstPass(ValidationState_t& _, const Instruction* inst) { << "expected operand P to be a pointer"; } - if (p_storage_class != SpvStorageClassGeneric) { + if (p_storage_class != SpvStorageClassGeneric && + p_storage_class != SpvStorageClassCrossWorkgroup && + p_storage_class != SpvStorageClassWorkgroup && + p_storage_class != SpvStorageClassFunction) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << ext_inst_name() << ": " - << "expected operand P storage class to be Generic"; + << "expected operand P storage class to be Generic, " + "CrossWorkgroup, Workgroup or Function"; } if (_.GetComponentType(data_type) != p_data_type) { @@ -1986,5 +2033,14 @@ spv_result_t ExtInstPass(ValidationState_t& _, const Instruction* inst) { return SPV_SUCCESS; } +spv_result_t ExtensionPass(ValidationState_t& _, const Instruction* inst) { + const SpvOp opcode = inst->opcode(); + if (opcode == SpvOpExtension) return ValidateExtension(_, inst); + if (opcode == SpvOpExtInstImport) return ValidateExtInstImport(_, inst); + if (opcode == SpvOpExtInst) return ValidateExtInst(_, inst); + + return SPV_SUCCESS; +} + } // namespace val } // namespace spvtools diff --git a/third_party/spirv-tools/source/val/validate_function.cpp b/third_party/spirv-tools/source/val/validate_function.cpp index 39f00fedc7..f130eacdad 100644 --- a/third_party/spirv-tools/source/val/validate_function.cpp +++ b/third_party/spirv-tools/source/val/validate_function.cpp @@ -12,18 +12,47 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "source/val/validate.h" - #include #include "source/opcode.h" #include "source/val/instruction.h" +#include "source/val/validate.h" #include "source/val/validation_state.h" namespace spvtools { namespace val { namespace { +// Returns true if |a| and |b| are instructions defining pointers that point to +// types logically match and the decorations that apply to |b| are a subset +// of the decorations that apply to |a|. +bool DoPointeesLogicallyMatch(val::Instruction* a, val::Instruction* b, + ValidationState_t& _) { + if (a->opcode() != SpvOpTypePointer || b->opcode() != SpvOpTypePointer) { + return false; + } + + const auto& dec_a = _.id_decorations(a->id()); + const auto& dec_b = _.id_decorations(b->id()); + for (const auto& dec : dec_b) { + if (std::find(dec_a.begin(), dec_a.end(), dec) == dec_a.end()) { + return false; + } + } + + uint32_t a_type = a->GetOperandAs(2); + uint32_t b_type = b->GetOperandAs(2); + + if (a_type == b_type) { + return true; + } + + Instruction* a_type_inst = _.FindDef(a_type); + Instruction* b_type_inst = _.FindDef(b_type); + + return _.LogicallyMatch(a_type_inst, b_type_inst, true); +} + spv_result_t ValidateFunction(ValidationState_t& _, const Instruction* inst) { const auto function_type_id = inst->GetOperandAs(3); const auto function_type = _.FindDef(function_type_id); @@ -41,20 +70,25 @@ spv_result_t ValidateFunction(ValidationState_t& _, const Instruction* inst) { << _.getIdName(return_id) << "'."; } + const std::vector acceptable = { + SpvOpDecorate, + SpvOpEnqueueKernel, + SpvOpEntryPoint, + SpvOpExecutionMode, + SpvOpExecutionModeId, + SpvOpFunctionCall, + SpvOpGetKernelNDrangeSubGroupCount, + SpvOpGetKernelNDrangeMaxSubGroupSize, + SpvOpGetKernelWorkGroupSize, + SpvOpGetKernelPreferredWorkGroupSizeMultiple, + SpvOpGetKernelLocalSizeForSubgroupCount, + SpvOpGetKernelMaxNumSubgroups, + SpvOpName}; for (auto& pair : inst->uses()) { const auto* use = pair.first; - const std::vector acceptable = { - SpvOpFunctionCall, - SpvOpEntryPoint, - SpvOpEnqueueKernel, - SpvOpGetKernelNDrangeSubGroupCount, - SpvOpGetKernelNDrangeMaxSubGroupSize, - SpvOpGetKernelWorkGroupSize, - SpvOpGetKernelPreferredWorkGroupSizeMultiple, - SpvOpGetKernelLocalSizeForSubgroupCount, - SpvOpGetKernelMaxNumSubgroups}; if (std::find(acceptable.begin(), acceptable.end(), use->opcode()) == - acceptable.end()) { + acceptable.end() && + !use->IsNonSemantic() && !use->IsDebugInfo()) { return _.diag(SPV_ERROR_INVALID_ID, use) << "Invalid use of function result id " << _.getIdName(inst->id()) << "."; @@ -111,6 +145,79 @@ spv_result_t ValidateFunctionParameter(ValidationState_t& _, << "' does not match the OpTypeFunction parameter " "type of the same index."; } + + // Validate that PhysicalStorageBufferEXT have one of Restrict, Aliased, + // RestrictPointerEXT, or AliasedPointerEXT. + auto param_nonarray_type_id = param_type->id(); + while (_.GetIdOpcode(param_nonarray_type_id) == SpvOpTypeArray) { + param_nonarray_type_id = + _.FindDef(param_nonarray_type_id)->GetOperandAs(1u); + } + if (_.GetIdOpcode(param_nonarray_type_id) == SpvOpTypePointer) { + auto param_nonarray_type = _.FindDef(param_nonarray_type_id); + if (param_nonarray_type->GetOperandAs(1u) == + SpvStorageClassPhysicalStorageBufferEXT) { + // check for Aliased or Restrict + const auto& decorations = _.id_decorations(inst->id()); + + bool foundAliased = std::any_of( + decorations.begin(), decorations.end(), [](const Decoration& d) { + return SpvDecorationAliased == d.dec_type(); + }); + + bool foundRestrict = std::any_of( + decorations.begin(), decorations.end(), [](const Decoration& d) { + return SpvDecorationRestrict == d.dec_type(); + }); + + if (!foundAliased && !foundRestrict) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "OpFunctionParameter " << inst->id() + << ": expected Aliased or Restrict for PhysicalStorageBufferEXT " + "pointer."; + } + if (foundAliased && foundRestrict) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "OpFunctionParameter " << inst->id() + << ": can't specify both Aliased and Restrict for " + "PhysicalStorageBufferEXT pointer."; + } + } else { + const auto pointee_type_id = + param_nonarray_type->GetOperandAs(2); + const auto pointee_type = _.FindDef(pointee_type_id); + if (SpvOpTypePointer == pointee_type->opcode() && + pointee_type->GetOperandAs(1u) == + SpvStorageClassPhysicalStorageBufferEXT) { + // check for AliasedPointerEXT/RestrictPointerEXT + const auto& decorations = _.id_decorations(inst->id()); + + bool foundAliased = std::any_of( + decorations.begin(), decorations.end(), [](const Decoration& d) { + return SpvDecorationAliasedPointerEXT == d.dec_type(); + }); + + bool foundRestrict = std::any_of( + decorations.begin(), decorations.end(), [](const Decoration& d) { + return SpvDecorationRestrictPointerEXT == d.dec_type(); + }); + + if (!foundAliased && !foundRestrict) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "OpFunctionParameter " << inst->id() + << ": expected AliasedPointerEXT or RestrictPointerEXT for " + "PhysicalStorageBufferEXT pointer."; + } + if (foundAliased && foundRestrict) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "OpFunctionParameter " << inst->id() + << ": can't specify both AliasedPointerEXT and " + "RestrictPointerEXT for PhysicalStorageBufferEXT pointer."; + } + } + } + } + return SPV_SUCCESS; } @@ -169,10 +276,58 @@ spv_result_t ValidateFunctionCall(ValidationState_t& _, function_type->GetOperandAs(param_index); const auto parameter_type = _.FindDef(parameter_type_id); if (!parameter_type || argument_type->id() != parameter_type->id()) { - return _.diag(SPV_ERROR_INVALID_ID, inst) - << "OpFunctionCall Argument '" << _.getIdName(argument_id) - << "'s type does not match Function '" - << _.getIdName(parameter_type_id) << "'s parameter type."; + if (!_.options()->before_hlsl_legalization || + !DoPointeesLogicallyMatch(argument_type, parameter_type, _)) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "OpFunctionCall Argument '" << _.getIdName(argument_id) + << "'s type does not match Function '" + << _.getIdName(parameter_type_id) << "'s parameter type."; + } + } + + if (_.addressing_model() == SpvAddressingModelLogical) { + if (parameter_type->opcode() == SpvOpTypePointer && + !_.options()->relax_logical_pointer) { + SpvStorageClass sc = parameter_type->GetOperandAs(1u); + // Validate which storage classes can be pointer operands. + switch (sc) { + case SpvStorageClassUniformConstant: + case SpvStorageClassFunction: + case SpvStorageClassPrivate: + case SpvStorageClassWorkgroup: + case SpvStorageClassAtomicCounter: + // These are always allowed. + break; + case SpvStorageClassStorageBuffer: + if (!_.features().variable_pointers_storage_buffer) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "StorageBuffer pointer operand " + << _.getIdName(argument_id) + << " requires a variable pointers capability"; + } + break; + default: + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Invalid storage class for pointer operand " + << _.getIdName(argument_id); + } + + // Validate memory object declaration requirements. + if (argument->opcode() != SpvOpVariable && + argument->opcode() != SpvOpFunctionParameter) { + const bool ssbo_vptr = + _.features().variable_pointers_storage_buffer && + sc == SpvStorageClassStorageBuffer; + const bool wg_vptr = + _.features().variable_pointers && sc == SpvStorageClassWorkgroup; + const bool uc_ptr = sc == SpvStorageClassUniformConstant; + if (!ssbo_vptr && !wg_vptr && !uc_ptr) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Pointer operand " << _.getIdName(argument_id) + << " must be a memory object declaration"; + } + } + } } } return SPV_SUCCESS; diff --git a/third_party/spirv-tools/source/val/validate_id.cpp b/third_party/spirv-tools/source/val/validate_id.cpp index 9510bb0b3c..c171d310d6 100644 --- a/third_party/spirv-tools/source/val/validate_id.cpp +++ b/third_party/spirv-tools/source/val/validate_id.cpp @@ -36,132 +36,6 @@ namespace spvtools { namespace val { -namespace { - -class idUsage { - public: - idUsage(spv_const_context context, const spv_instruction_t* pInsts, - const uint64_t instCountArg, const SpvMemoryModel memoryModelArg, - const SpvAddressingModel addressingModelArg, - const ValidationState_t& module, - const std::vector& entry_points, spv_position positionArg, - const MessageConsumer& consumer) - : targetEnv(context->target_env), - opcodeTable(context->opcode_table), - operandTable(context->operand_table), - extInstTable(context->ext_inst_table), - firstInst(pInsts), - instCount(instCountArg), - memoryModel(memoryModelArg), - addressingModel(addressingModelArg), - position(positionArg), - consumer_(consumer), - module_(module), - entry_points_(entry_points) {} - - bool isValid(const spv_instruction_t* inst); - - template - bool isValid(const spv_instruction_t* inst, const spv_opcode_desc); - - private: - const spv_target_env targetEnv; - const spv_opcode_table opcodeTable; - const spv_operand_table operandTable; - const spv_ext_inst_table extInstTable; - const spv_instruction_t* const firstInst; - const uint64_t instCount; - const SpvMemoryModel memoryModel; - const SpvAddressingModel addressingModel; - spv_position position; - const MessageConsumer& consumer_; - const ValidationState_t& module_; - std::vector entry_points_; -}; - -#define DIAG(inst) \ - position->index = inst ? inst->LineNum() : -1; \ - std::string disassembly; \ - if (inst) { \ - disassembly = module_.Disassemble( \ - inst->words().data(), static_cast(inst->words().size())); \ - } \ - DiagnosticStream helper(*position, consumer_, disassembly, \ - SPV_ERROR_INVALID_DIAGNOSTIC); \ - helper - -template <> -bool idUsage::isValid(const spv_instruction_t* inst, - const spv_opcode_desc) { - auto resultTypeIndex = 2; - auto resultID = inst->words[resultTypeIndex]; - auto sampledImageInstr = module_.FindDef(resultID); - // We need to validate 2 things: - // * All OpSampledImage instructions must be in the same block in which their - // Result are consumed. - // * Result from OpSampledImage instructions must not appear as operands - // to OpPhi instructions or OpSelect instructions, or any instructions other - // than the image lookup and query instructions specified to take an operand - // whose type is OpTypeSampledImage. - std::vector consumers = module_.getSampledImageConsumers(resultID); - if (!consumers.empty()) { - for (auto consumer_id : consumers) { - auto consumer_instr = module_.FindDef(consumer_id); - auto consumer_opcode = consumer_instr->opcode(); - if (consumer_instr->block() != sampledImageInstr->block()) { - DIAG(sampledImageInstr) - << "All OpSampledImage instructions must be in the same block in " - "which their Result are consumed. OpSampledImage Result " - "Type '" - << module_.getIdName(resultID) - << "' has a consumer in a different basic " - "block. The consumer instruction is '" - << module_.getIdName(consumer_id) << "'."; - return false; - } - // TODO: The following check is incomplete. We should also check that the - // Sampled Image is not used by instructions that should not take - // SampledImage as an argument. We could find the list of valid - // instructions by scanning for "Sampled Image" in the operand description - // field in the grammar file. - if (consumer_opcode == SpvOpPhi || consumer_opcode == SpvOpSelect) { - DIAG(sampledImageInstr) - << "Result from OpSampledImage instruction must not appear as " - "operands of Op" - << spvOpcodeString(static_cast(consumer_opcode)) << "." - << " Found result '" << module_.getIdName(resultID) - << "' as an operand of '" << module_.getIdName(consumer_id) - << "'."; - return false; - } - } - } - return true; -} - -bool idUsage::isValid(const spv_instruction_t* inst) { - spv_opcode_desc opcodeEntry = nullptr; - if (spvOpcodeTableValueLookup(targetEnv, opcodeTable, inst->opcode, - &opcodeEntry)) - return false; -#define CASE(OpCode) \ - case Spv##OpCode: \ - return isValid(inst, opcodeEntry); - switch (inst->opcode) { - CASE(OpSampledImage) - // Other composite opcodes are validated in validate_composites.cpp. - // Arithmetic opcodes are validated in validate_arithmetics.cpp. - // Bitwise opcodes are validated in validate_bitwise.cpp. - // Logical opcodes are validated in validate_logicals.cpp. - // Derivative opcodes are validated in validate_derivatives.cpp. - default: - return true; - } -#undef TODO -#undef CASE -} - -} // namespace spv_result_t UpdateIdUse(ValidationState_t& _, const Instruction* inst) { for (auto& operand : inst->operands()) { @@ -184,14 +58,13 @@ spv_result_t UpdateIdUse(ValidationState_t& _, const Instruction* inst) { /// /// NOTE: This function does NOT check module scoped functions which are /// checked during the initial binary parse in the IdPass below -spv_result_t CheckIdDefinitionDominateUse(const ValidationState_t& _) { +spv_result_t CheckIdDefinitionDominateUse(ValidationState_t& _) { std::vector phi_instructions; std::unordered_set phi_ids; for (const auto& inst : _.ordered_instructions()) { if (inst.id() == 0) continue; if (const Function* func = inst.function()) { if (const BasicBlock* block = inst.block()) { - if (!block->reachable()) continue; // If the Id is defined within a block then make sure all references to // that Id appear in a blocks that are dominated by the defining block for (auto& use_index_pair : inst.uses()) { @@ -258,7 +131,11 @@ spv_result_t CheckIdDefinitionDominateUse(const ValidationState_t& _) { // instruction operand's ID can be forward referenced. spv_result_t IdPass(ValidationState_t& _, Instruction* inst) { auto can_have_forward_declared_ids = - spvOperandCanBeForwardDeclaredFunction(inst->opcode()); + inst->opcode() == SpvOpExtInst && + spvExtInstIsDebugInfo(inst->ext_inst_type()) + ? spvDbgInfoExtOperandCanBeForwardDeclaredFunction( + inst->ext_inst_type(), inst->word(4)) + : spvOperandCanBeForwardDeclaredFunction(inst->opcode()); // Keep track of a result id defined by this instruction. 0 means it // does not define an id. @@ -288,13 +165,65 @@ spv_result_t IdPass(ValidationState_t& _, Instruction* inst) { ret = SPV_SUCCESS; break; case SPV_OPERAND_TYPE_ID: - case SPV_OPERAND_TYPE_TYPE_ID: case SPV_OPERAND_TYPE_MEMORY_SEMANTICS_ID: case SPV_OPERAND_TYPE_SCOPE_ID: - if (_.IsDefinedId(operand_word)) { - ret = SPV_SUCCESS; + if (const auto def = _.FindDef(operand_word)) { + const auto opcode = inst->opcode(); + if (spvOpcodeGeneratesType(def->opcode()) && + !spvOpcodeGeneratesType(opcode) && !spvOpcodeIsDebug(opcode) && + !inst->IsNonSemantic() && !spvOpcodeIsDecoration(opcode) && + opcode != SpvOpFunction && + opcode != SpvOpCooperativeMatrixLengthNV && + !(opcode == SpvOpSpecConstantOp && + inst->word(3) == SpvOpCooperativeMatrixLengthNV)) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Operand " << _.getIdName(operand_word) + << " cannot be a type"; + } else if (def->type_id() == 0 && !spvOpcodeGeneratesType(opcode) && + !spvOpcodeIsDebug(opcode) && !inst->IsNonSemantic() && + !spvOpcodeIsDecoration(opcode) && + !spvOpcodeIsBranch(opcode) && opcode != SpvOpPhi && + opcode != SpvOpExtInst && opcode != SpvOpExtInstImport && + opcode != SpvOpSelectionMerge && + opcode != SpvOpLoopMerge && opcode != SpvOpFunction && + opcode != SpvOpCooperativeMatrixLengthNV && + !(opcode == SpvOpSpecConstantOp && + inst->word(3) == SpvOpCooperativeMatrixLengthNV)) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Operand " << _.getIdName(operand_word) + << " requires a type"; + } else if (def->IsNonSemantic() && !inst->IsNonSemantic()) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Operand " << _.getIdName(operand_word) + << " in semantic instruction cannot be a non-semantic " + "instruction"; + } else { + ret = SPV_SUCCESS; + } } else if (can_have_forward_declared_ids(i)) { - ret = _.ForwardDeclareId(operand_word); + if (inst->opcode() == SpvOpTypeStruct && + !_.IsForwardPointer(operand_word)) { + ret = _.diag(SPV_ERROR_INVALID_ID, inst) + << "Operand " << _.getIdName(operand_word) + << " requires a previous definition"; + } else { + ret = _.ForwardDeclareId(operand_word); + } + } else { + ret = _.diag(SPV_ERROR_INVALID_ID, inst) + << "ID " << _.getIdName(operand_word) + << " has not been defined"; + } + break; + case SPV_OPERAND_TYPE_TYPE_ID: + if (_.IsDefinedId(operand_word)) { + auto* def = _.FindDef(operand_word); + if (!spvOpcodeGeneratesType(def->opcode())) { + ret = _.diag(SPV_ERROR_INVALID_ID, inst) + << "ID " << _.getIdName(operand_word) << " is not a type id"; + } else { + ret = SPV_SUCCESS; + } } else { ret = _.diag(SPV_ERROR_INVALID_ID, inst) << "ID " << _.getIdName(operand_word) @@ -312,18 +241,5 @@ spv_result_t IdPass(ValidationState_t& _, Instruction* inst) { return SPV_SUCCESS; } -spv_result_t spvValidateInstructionIDs(const spv_instruction_t* pInsts, - const uint64_t instCount, - const ValidationState_t& state, - spv_position position) { - idUsage idUsage(state.context(), pInsts, instCount, state.memory_model(), - state.addressing_model(), state, state.entry_points(), - position, state.context()->consumer); - for (uint64_t instIndex = 0; instIndex < instCount; ++instIndex) { - if (!idUsage.isValid(&pInsts[instIndex])) return SPV_ERROR_INVALID_ID; - } - return SPV_SUCCESS; -} - } // namespace val } // namespace spvtools diff --git a/third_party/spirv-tools/source/val/validate_image.cpp b/third_party/spirv-tools/source/val/validate_image.cpp index 0d2dd00c03..bc2753cf9e 100644 --- a/third_party/spirv-tools/source/val/validate_image.cpp +++ b/third_party/spirv-tools/source/val/validate_image.cpp @@ -23,6 +23,7 @@ #include "source/spirv_target_env.h" #include "source/util/bitutils.h" #include "source/val/instruction.h" +#include "source/val/validate_scopes.h" #include "source/val/validation_state.h" namespace spvtools { @@ -55,6 +56,15 @@ bool CheckAllImageOperandsHandled() { case SpvImageOperandsConstOffsetsMask: case SpvImageOperandsSampleMask: case SpvImageOperandsMinLodMask: + + // TODO(dneto): Support image operands related to the Vulkan memory model. + // https://gitlab.khronos.org/spirv/spirv-tools/issues/32 + case SpvImageOperandsMakeTexelAvailableKHRMask: + case SpvImageOperandsMakeTexelVisibleKHRMask: + case SpvImageOperandsNonPrivateTexelKHRMask: + case SpvImageOperandsVolatileTexelKHRMask: + case SpvImageOperandsSignExtendMask: + case SpvImageOperandsZeroExtendMask: return true; } return false; @@ -210,7 +220,14 @@ spv_result_t ValidateImageOperands(ValidationState_t& _, const SpvOp opcode = inst->opcode(); const size_t num_words = inst->words().size(); - size_t expected_num_image_operand_words = spvtools::utils::CountSetBits(mask); + // NonPrivate, Volatile, SignExtend, ZeroExtend take no operand words. + const uint32_t mask_bits_having_operands = + mask & ~uint32_t(SpvImageOperandsNonPrivateTexelKHRMask | + SpvImageOperandsVolatileTexelKHRMask | + SpvImageOperandsSignExtendMask | + SpvImageOperandsZeroExtendMask); + size_t expected_num_image_operand_words = + spvtools::utils::CountSetBits(mask_bits_having_operands); if (mask & SpvImageOperandsGradMask) { // Grad uses two words. ++expected_num_image_operand_words; @@ -486,6 +503,74 @@ spv_result_t ValidateImageOperands(ValidationState_t& _, } } + if (mask & SpvImageOperandsMakeTexelAvailableKHRMask) { + // Checked elsewhere: capability and memory model are correct. + if (opcode != SpvOpImageWrite) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Image Operand MakeTexelAvailableKHR can only be used with Op" + << spvOpcodeString(SpvOpImageWrite) << ": Op" + << spvOpcodeString(opcode); + } + + if (!(mask & SpvImageOperandsNonPrivateTexelKHRMask)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Image Operand MakeTexelAvailableKHR requires " + "NonPrivateTexelKHR is also specified: Op" + << spvOpcodeString(opcode); + } + + const auto available_scope = inst->word(word_index++); + if (auto error = ValidateMemoryScope(_, inst, available_scope)) + return error; + } + + if (mask & SpvImageOperandsMakeTexelVisibleKHRMask) { + // Checked elsewhere: capability and memory model are correct. + if (opcode != SpvOpImageRead && opcode != SpvOpImageSparseRead) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Image Operand MakeTexelVisibleKHR can only be used with Op" + << spvOpcodeString(SpvOpImageRead) << " or Op" + << spvOpcodeString(SpvOpImageSparseRead) << ": Op" + << spvOpcodeString(opcode); + } + + if (!(mask & SpvImageOperandsNonPrivateTexelKHRMask)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Image Operand MakeTexelVisibleKHR requires NonPrivateTexelKHR " + "is also specified: Op" + << spvOpcodeString(opcode); + } + + const auto visible_scope = inst->word(word_index++); + if (auto error = ValidateMemoryScope(_, inst, visible_scope)) return error; + } + + if (mask & SpvImageOperandsSignExtendMask) { + // Checked elsewhere: SPIR-V 1.4 version or later. + + // "The texel value is converted to the target value via sign extension. + // Only valid when the texel type is a scalar or vector of integer type." + // + // We don't have enough information to know what the texel type is. + // In OpenCL, knowledge is deferred until runtime: the image SampledType is + // void, and the Format is Unknown. + // In Vulkan, the texel type is only known in all cases by the pipeline + // setup. + } + + if (mask & SpvImageOperandsZeroExtendMask) { + // Checked elsewhere: SPIR-V 1.4 version or later. + + // "The texel value is converted to the target value via zero extension. + // Only valid when the texel type is a scalar or vector of integer type." + // + // We don't have enough information to know what the texel type is. + // In OpenCL, knowledge is deferred until runtime: the image SampledType is + // void, and the Format is Unknown. + // In Vulkan, the texel type is only known in all cases by the pipeline + // setup. + } + return SPV_SUCCESS; } @@ -633,6 +718,11 @@ spv_result_t ValidateTypeImage(ValidationState_t& _, const Instruction* inst) { << "Expected Sampled Type to be a 32-bit int or float " "scalar type for Vulkan environment"; } + } else if (spvIsOpenCLEnv(_.context()->target_env)) { + if (!_.IsVoidType(info.sampled_type)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Sampled Type must be OpTypeVoid in the OpenCL environment."; + } } else { const SpvOp sampled_type_opcode = _.GetIdOpcode(info.sampled_type); if (sampled_type_opcode != SpvOpTypeVoid && @@ -656,16 +746,39 @@ spv_result_t ValidateTypeImage(ValidationState_t& _, const Instruction* inst) { << "Invalid Arrayed " << info.arrayed << " (must be 0 or 1)"; } + if (spvIsOpenCLEnv(_.context()->target_env)) { + if ((info.arrayed == 1) && (info.dim != SpvDim1D) && + (info.dim != SpvDim2D)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "In the OpenCL environment, Arrayed may only be set to 1 " + << "when Dim is either 1D or 2D."; + } + } + if (info.multisampled > 1) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Invalid MS " << info.multisampled << " (must be 0 or 1)"; } + if (spvIsOpenCLEnv(_.context()->target_env)) { + if (info.multisampled != 0) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "MS must be 0 in the OpenCL environement."; + } + } + if (info.sampled > 2) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Invalid Sampled " << info.sampled << " (must be 0, 1 or 2)"; } + if (spvIsOpenCLEnv(_.context()->target_env)) { + if (info.sampled != 0) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Sampled must be 0 in the OpenCL environment."; + } + } + if (info.dim == SpvDimSubpassData) { if (info.sampled != 2) { return _.diag(SPV_ERROR_INVALID_DATA, inst) @@ -678,7 +791,15 @@ spv_result_t ValidateTypeImage(ValidationState_t& _, const Instruction* inst) { } } - // Format and Access Qualifier are checked elsewhere. + // Format and Access Qualifier are also checked elsewhere. + + if (spvIsOpenCLEnv(_.context()->target_env)) { + if (info.access_qualifier == SpvAccessQualifierMax) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "In the OpenCL environment, the optional Access Qualifier" + << " must be present."; + } + } return SPV_SUCCESS; } @@ -693,6 +814,33 @@ spv_result_t ValidateTypeSampledImage(ValidationState_t& _, return SPV_SUCCESS; } +bool IsAllowedSampledImageOperand(SpvOp opcode) { + switch (opcode) { + case SpvOpSampledImage: + case SpvOpImageSampleImplicitLod: + case SpvOpImageSampleExplicitLod: + case SpvOpImageSampleDrefImplicitLod: + case SpvOpImageSampleDrefExplicitLod: + case SpvOpImageSampleProjImplicitLod: + case SpvOpImageSampleProjExplicitLod: + case SpvOpImageSampleProjDrefImplicitLod: + case SpvOpImageSampleProjDrefExplicitLod: + case SpvOpImageGather: + case SpvOpImageDrefGather: + case SpvOpImage: + case SpvOpImageQueryLod: + case SpvOpImageSparseSampleImplicitLod: + case SpvOpImageSparseSampleExplicitLod: + case SpvOpImageSparseSampleDrefImplicitLod: + case SpvOpImageSparseSampleDrefExplicitLod: + case SpvOpImageSparseGather: + case SpvOpImageSparseDrefGather: + return true; + default: + return false; + } +} + spv_result_t ValidateSampledImage(ValidationState_t& _, const Instruction* inst) { if (_.GetIdOpcode(inst->type_id()) != SpvOpTypeSampledImage) { @@ -737,6 +885,158 @@ spv_result_t ValidateSampledImage(ValidationState_t& _, return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Expected Sampler to be of type OpTypeSampler"; } + + // We need to validate 2 things: + // * All OpSampledImage instructions must be in the same block in which their + // Result are consumed. + // * Result from OpSampledImage instructions must not appear as operands + // to OpPhi instructions or OpSelect instructions, or any instructions other + // than the image lookup and query instructions specified to take an operand + // whose type is OpTypeSampledImage. + std::vector consumers = _.getSampledImageConsumers(inst->id()); + if (!consumers.empty()) { + for (auto consumer_instr : consumers) { + const auto consumer_opcode = consumer_instr->opcode(); + if (consumer_instr->block() != inst->block()) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "All OpSampledImage instructions must be in the same block " + "in " + "which their Result are consumed. OpSampledImage Result " + "Type '" + << _.getIdName(inst->id()) + << "' has a consumer in a different basic " + "block. The consumer instruction is '" + << _.getIdName(consumer_instr->id()) << "'."; + } + + if (consumer_opcode == SpvOpPhi || consumer_opcode == SpvOpSelect) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Result from OpSampledImage instruction must not appear " + "as " + "operands of Op" + << spvOpcodeString(static_cast(consumer_opcode)) << "." + << " Found result '" << _.getIdName(inst->id()) + << "' as an operand of '" + << _.getIdName(consumer_instr->id()) << "'."; + } + + if (!IsAllowedSampledImageOperand(consumer_opcode)) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Result from OpSampledImage instruction must not appear " + "as operand for Op" + << spvOpcodeString(static_cast(consumer_opcode)) + << ", since it is not specificed as taking an " + << "OpTypeSampledImage." + << " Found result '" << _.getIdName(inst->id()) + << "' as an operand of '" + << _.getIdName(consumer_instr->id()) << "'."; + } + } + } + return SPV_SUCCESS; +} + +spv_result_t ValidateImageTexelPointer(ValidationState_t& _, + const Instruction* inst) { + const auto result_type = _.FindDef(inst->type_id()); + if (result_type->opcode() != SpvOpTypePointer) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Expected Result Type to be OpTypePointer"; + } + + const auto storage_class = result_type->GetOperandAs(1); + if (storage_class != SpvStorageClassImage) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Expected Result Type to be OpTypePointer whose Storage Class " + "operand is Image"; + } + + const auto ptr_type = result_type->GetOperandAs(2); + const auto ptr_opcode = _.GetIdOpcode(ptr_type); + if (ptr_opcode != SpvOpTypeInt && ptr_opcode != SpvOpTypeFloat && + ptr_opcode != SpvOpTypeVoid) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Expected Result Type to be OpTypePointer whose Type operand " + "must be a scalar numerical type or OpTypeVoid"; + } + + const auto image_ptr = _.FindDef(_.GetOperandTypeId(inst, 2)); + if (!image_ptr || image_ptr->opcode() != SpvOpTypePointer) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Expected Image to be OpTypePointer"; + } + + const auto image_type = image_ptr->GetOperandAs(2); + if (_.GetIdOpcode(image_type) != SpvOpTypeImage) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Expected Image to be OpTypePointer with Type OpTypeImage"; + } + + ImageTypeInfo info; + if (!GetImageTypeInfo(_, image_type, &info)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Corrupt image type definition"; + } + + if (info.sampled_type != ptr_type) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Expected Image 'Sampled Type' to be the same as the Type " + "pointed to by Result Type"; + } + + if (info.dim == SpvDimSubpassData) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Image Dim SubpassData cannot be used with OpImageTexelPointer"; + } + + const uint32_t coord_type = _.GetOperandTypeId(inst, 3); + if (!coord_type || !_.IsIntScalarOrVectorType(coord_type)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Expected Coordinate to be integer scalar or vector"; + } + + uint32_t expected_coord_size = 0; + if (info.arrayed == 0) { + expected_coord_size = GetPlaneCoordSize(info); + } else if (info.arrayed == 1) { + switch (info.dim) { + case SpvDim1D: + expected_coord_size = 2; + break; + case SpvDimCube: + case SpvDim2D: + expected_coord_size = 3; + break; + default: + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Expected Image 'Dim' must be one of 1D, 2D, or Cube when " + "Arrayed is 1"; + break; + } + } + + const uint32_t actual_coord_size = _.GetDimension(coord_type); + if (expected_coord_size != actual_coord_size) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Expected Coordinate to have " << expected_coord_size + << " components, but given " << actual_coord_size; + } + + const uint32_t sample_type = _.GetOperandTypeId(inst, 4); + if (!sample_type || !_.IsIntScalarType(sample_type)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Expected Sample to be integer scalar"; + } + + if (info.multisampled == 0) { + uint64_t ms = 0; + if (!_.GetConstantValUint64(inst->GetOperandAs(4), &ms) || + ms != 0) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Expected Sample for Image with MS 0 to be a valid for " + "the value 0"; + } + } return SPV_SUCCESS; } @@ -814,6 +1114,17 @@ spv_result_t ValidateImageLod(ValidationState_t& _, const Instruction* inst) { } const uint32_t mask = inst->word(5); + + if (spvIsOpenCLEnv(_.context()->target_env)) { + if (opcode == SpvOpImageSampleExplicitLod) { + if (mask & SpvImageOperandsConstOffsetMask) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "ConstOffset image operand not allowed " + << "in the OpenCL environment."; + } + } + } + if (spv_result_t result = ValidateImageOperands(_, inst, info, mask, /* word_index = */ 6)) return result; @@ -1128,16 +1439,27 @@ spv_result_t ValidateImageRead(ValidationState_t& _, const Instruction* inst) { << " components, but given only " << actual_coord_size; } - if (info.format == SpvImageFormatUnknown && info.dim != SpvDimSubpassData && - !_.HasCapability(SpvCapabilityStorageImageReadWithoutFormat)) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << "Capability StorageImageReadWithoutFormat is required to " - << "read storage image"; + if (spvIsVulkanEnv(_.context()->target_env)) { + if (info.format == SpvImageFormatUnknown && info.dim != SpvDimSubpassData && + !_.HasCapability(SpvCapabilityStorageImageReadWithoutFormat)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Capability StorageImageReadWithoutFormat is required to " + << "read storage image"; + } } if (inst->words().size() <= 5) return SPV_SUCCESS; const uint32_t mask = inst->word(5); + + if (spvIsOpenCLEnv(_.context()->target_env)) { + if (mask & SpvImageOperandsConstOffsetMask) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "ConstOffset image operand not allowed " + << "in the OpenCL environment."; + } + } + if (spv_result_t result = ValidateImageOperands(_, inst, info, mask, /* word_index = */ 6)) return result; @@ -1205,15 +1527,25 @@ spv_result_t ValidateImageWrite(ValidationState_t& _, const Instruction* inst) { } } - if (info.format == SpvImageFormatUnknown && info.dim != SpvDimSubpassData && - !_.HasCapability(SpvCapabilityStorageImageWriteWithoutFormat)) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << "Capability StorageImageWriteWithoutFormat is required to " - "write " - << "to storage image"; + if (spvIsVulkanEnv(_.context()->target_env)) { + if (info.format == SpvImageFormatUnknown && info.dim != SpvDimSubpassData && + !_.HasCapability(SpvCapabilityStorageImageWriteWithoutFormat)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Capability StorageImageWriteWithoutFormat is required to " + "write " + << "to storage image"; + } } - if (inst->words().size() <= 4) return SPV_SUCCESS; + if (inst->words().size() <= 4) { + return SPV_SUCCESS; + } else { + if (spvIsOpenCLEnv(_.context()->target_env)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Optional Image Operands are not allowed in the OpenCL " + << "environment."; + } + } const uint32_t mask = inst->word(4); if (spv_result_t result = @@ -1317,57 +1649,45 @@ spv_result_t ValidateImageQuerySize(ValidationState_t& _, << "Expected Image to be of type OpTypeImage"; } -#if 0 - // TODO(atgoo@github.com) The spec doesn't whitelist all Dims supported by - // GLSL. Need to verify if there is an error and reenable. ImageTypeInfo info; if (!GetImageTypeInfo(_, image_type, &info)) { return _.diag(SPV_ERROR_INVALID_DATA, inst) - << "Corrupt image type definition"; + << "Corrupt image type definition"; } uint32_t expected_num_components = info.arrayed; switch (info.dim) { + case SpvDim1D: case SpvDimBuffer: expected_num_components += 1; break; case SpvDim2D: - if (info.multisampled != 1 && info.sampled != 0 && - info.sampled != 2) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << "Expected either 'MS'=1 or 'Sampled'=0 or 'Sampled'=2 " - << "for 2D dim"; - } + case SpvDimCube: case SpvDimRect: expected_num_components += 2; break; case SpvDim3D: expected_num_components += 3; - if (info.sampled != 0 && - info.sampled != 2) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << "Expected either 'Sampled'=0 or 'Sampled'=2 " - << "for 3D dim"; - } break; default: return _.diag(SPV_ERROR_INVALID_DATA, inst) - << "Image 'Dim' must be Buffer, 2D, 3D or Rect"; + << "Image 'Dim' must be 1D, Buffer, 2D, Cube, 3D or Rect"; } - - if (info.multisampled != 0) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << "Image 'MS' must be 0"; + if (info.dim == SpvDim1D || info.dim == SpvDim2D || info.dim == SpvDim3D || + info.dim == SpvDimCube) { + if (info.multisampled != 1 && info.sampled != 0 && info.sampled != 2) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Image must have either 'MS'=1 or 'Sampled'=0 or 'Sampled'=2"; + } } uint32_t result_num_components = _.GetDimension(result_type); if (result_num_components != expected_num_components) { return _.diag(SPV_ERROR_INVALID_DATA, inst) - << "Result Type has " << result_num_components << " components, " - << "but " << expected_num_components << " expected"; + << "Result Type has " << result_num_components << " components, " + << "but " << expected_num_components << " expected"; } -#endif return SPV_SUCCESS; } @@ -1390,8 +1710,39 @@ spv_result_t ValidateImageQueryLod(ValidationState_t& _, const Instruction* inst) { _.function(inst->function()->id()) ->RegisterExecutionModelLimitation( - SpvExecutionModelFragment, - "OpImageQueryLod requires Fragment execution model"); + [&](SpvExecutionModel model, std::string* message) { + if (model != SpvExecutionModelFragment && + model != SpvExecutionModelGLCompute) { + if (message) { + *message = std::string( + "OpImageQueryLod requires Fragment or GLCompute execution " + "model"); + } + return false; + } + return true; + }); + _.function(inst->function()->id()) + ->RegisterLimitation([](const ValidationState_t& state, + const Function* entry_point, + std::string* message) { + const auto* models = state.GetExecutionModels(entry_point->id()); + const auto* modes = state.GetExecutionModes(entry_point->id()); + if (models->find(SpvExecutionModelGLCompute) != models->end() && + modes->find(SpvExecutionModeDerivativeGroupLinearNV) == + modes->end() && + modes->find(SpvExecutionModeDerivativeGroupQuadsNV) == + modes->end()) { + if (message) { + *message = std::string( + "OpImageQueryLod requires DerivativeGroupQuadsNV " + "or DerivativeGroupLinearNV execution mode for GLCompute " + "execution model"); + } + return false; + } + return true; + }); const uint32_t result_type = inst->type_id(); if (!_.IsFloatVectorType(result_type)) { @@ -1515,9 +1866,44 @@ spv_result_t ImagePass(ValidationState_t& _, const Instruction* inst) { const SpvOp opcode = inst->opcode(); if (IsImplicitLod(opcode)) { _.function(inst->function()->id()) - ->RegisterExecutionModelLimitation( - SpvExecutionModelFragment, - "ImplicitLod instructions require Fragment execution model"); + ->RegisterExecutionModelLimitation([opcode](SpvExecutionModel model, + std::string* message) { + if (model != SpvExecutionModelFragment && + model != SpvExecutionModelGLCompute) { + if (message) { + *message = + std::string( + "ImplicitLod instructions require Fragment or GLCompute " + "execution model: ") + + spvOpcodeString(opcode); + } + return false; + } + return true; + }); + _.function(inst->function()->id()) + ->RegisterLimitation([opcode](const ValidationState_t& state, + const Function* entry_point, + std::string* message) { + const auto* models = state.GetExecutionModels(entry_point->id()); + const auto* modes = state.GetExecutionModes(entry_point->id()); + if (models->find(SpvExecutionModelGLCompute) != models->end() && + modes->find(SpvExecutionModeDerivativeGroupLinearNV) == + modes->end() && + modes->find(SpvExecutionModeDerivativeGroupQuadsNV) == + modes->end()) { + if (message) { + *message = + std::string( + "ImplicitLod instructions require DerivativeGroupQuadsNV " + "or DerivativeGroupLinearNV execution mode for GLCompute " + "execution model: ") + + spvOpcodeString(opcode); + } + return false; + } + return true; + }); } switch (opcode) { @@ -1527,6 +1913,8 @@ spv_result_t ImagePass(ValidationState_t& _, const Instruction* inst) { return ValidateTypeSampledImage(_, inst); case SpvOpSampledImage: return ValidateSampledImage(_, inst); + case SpvOpImageTexelPointer: + return ValidateImageTexelPointer(_, inst); case SpvOpImageSampleImplicitLod: case SpvOpImageSampleExplicitLod: diff --git a/third_party/spirv-tools/source/val/validate_instruction.cpp b/third_party/spirv-tools/source/val/validate_instruction.cpp index 85995caa3e..6478b3cb6f 100644 --- a/third_party/spirv-tools/source/val/validate_instruction.cpp +++ b/third_party/spirv-tools/source/val/validate_instruction.cpp @@ -14,10 +14,9 @@ // Performs validation on instructions that appear inside of a SPIR-V block. -#include "source/val/validate.h" - #include #include +#include #include #include #include @@ -35,6 +34,7 @@ #include "source/spirv_validator_options.h" #include "source/util/string_utils.h" #include "source/val/function.h" +#include "source/val/validate.h" #include "source/val/validation_state.h" namespace spvtools { @@ -86,21 +86,72 @@ CapabilitySet EnablingCapabilitiesForOp(const ValidationState_t& state, return CapabilitySet(); } +// Returns SPV_SUCCESS if, for the given operand, the target environment +// satsifies minimum version requirements, or if the module declares an +// enabling extension for the operand. Otherwise emit a diagnostic and +// return an error code. +spv_result_t OperandVersionExtensionCheck( + ValidationState_t& _, const Instruction* inst, size_t which_operand, + const spv_operand_desc_t& operand_desc, uint32_t word) { + const uint32_t module_version = _.version(); + const uint32_t operand_min_version = operand_desc.minVersion; + const uint32_t operand_last_version = operand_desc.lastVersion; + const bool reserved = operand_min_version == 0xffffffffu; + const bool version_satisfied = !reserved && + (operand_min_version <= module_version) && + (module_version <= operand_last_version); + + if (version_satisfied) { + return SPV_SUCCESS; + } + + if (operand_last_version < module_version) { + return _.diag(SPV_ERROR_WRONG_VERSION, inst) + << spvtools::utils::CardinalToOrdinal(which_operand) + << " operand of " << spvOpcodeString(inst->opcode()) << ": operand " + << operand_desc.name << "(" << word << ") requires SPIR-V version " + << SPV_SPIRV_VERSION_MAJOR_PART(operand_last_version) << "." + << SPV_SPIRV_VERSION_MINOR_PART(operand_last_version) + << " or earlier"; + } + + if (!reserved && operand_desc.numExtensions == 0) { + return _.diag(SPV_ERROR_WRONG_VERSION, inst) + << spvtools::utils::CardinalToOrdinal(which_operand) + << " operand of " << spvOpcodeString(inst->opcode()) << ": operand " + << operand_desc.name << "(" << word << ") requires SPIR-V version " + << SPV_SPIRV_VERSION_MAJOR_PART(operand_min_version) << "." + << SPV_SPIRV_VERSION_MINOR_PART(operand_min_version) << " or later"; + } else { + ExtensionSet required_extensions(operand_desc.numExtensions, + operand_desc.extensions); + if (!_.HasAnyOfExtensions(required_extensions)) { + return _.diag(SPV_ERROR_MISSING_EXTENSION, inst) + << spvtools::utils::CardinalToOrdinal(which_operand) + << " operand of " << spvOpcodeString(inst->opcode()) + << ": operand " << operand_desc.name << "(" << word + << ") requires one of these extensions: " + << ExtensionSetToString(required_extensions); + } + } + return SPV_SUCCESS; +} + // Returns SPV_SUCCESS if the given operand is enabled by capabilities declared // in the module. Otherwise issues an error message and returns // SPV_ERROR_INVALID_CAPABILITY. -spv_result_t CheckRequiredCapabilities(const ValidationState_t& state, +spv_result_t CheckRequiredCapabilities(ValidationState_t& state, const Instruction* inst, size_t which_operand, - spv_operand_type_t type, - uint32_t operand) { + const spv_parsed_operand_t& operand, + uint32_t word) { // Mere mention of PointSize, ClipDistance, or CullDistance in a Builtin // decoration does not require the associated capability. The use of such // a variable value should trigger the capability requirement, but that's // not implemented yet. This rule is independent of target environment. // See https://github.com/KhronosGroup/SPIRV-Tools/issues/365 - if (type == SPV_OPERAND_TYPE_BUILT_IN) { - switch (operand) { + if (operand.type == SPV_OPERAND_TYPE_BUILT_IN) { + switch (word) { case SpvBuiltInPointSize: case SpvBuiltInClipDistance: case SpvBuiltInCullDistance: @@ -108,14 +159,14 @@ spv_result_t CheckRequiredCapabilities(const ValidationState_t& state, default: break; } - } else if (type == SPV_OPERAND_TYPE_FP_ROUNDING_MODE) { + } else if (operand.type == SPV_OPERAND_TYPE_FP_ROUNDING_MODE) { // Allow all FP rounding modes if requested if (state.features().free_fp_rounding_mode) { return SPV_SUCCESS; } - } else if (type == SPV_OPERAND_TYPE_GROUP_OPERATION && + } else if (operand.type == SPV_OPERAND_TYPE_GROUP_OPERATION && state.features().group_ops_reduce_and_scans && - (operand <= uint32_t(SpvGroupOperationExclusiveScan))) { + (word <= uint32_t(SpvGroupOperationExclusiveScan))) { // Allow certain group operations if requested. return SPV_SUCCESS; } @@ -123,10 +174,10 @@ spv_result_t CheckRequiredCapabilities(const ValidationState_t& state, CapabilitySet enabling_capabilities; spv_operand_desc operand_desc = nullptr; const auto lookup_result = - state.grammar().lookupOperand(type, operand, &operand_desc); + state.grammar().lookupOperand(operand.type, word, &operand_desc); if (lookup_result == SPV_SUCCESS) { // Allow FPRoundingMode decoration if requested. - if (type == SPV_OPERAND_TYPE_DECORATION && + if (operand.type == SPV_OPERAND_TYPE_DECORATION && operand_desc->value == SpvDecorationFPRoundingMode) { if (state.features().free_fp_rounding_mode) return SPV_SUCCESS; @@ -142,36 +193,27 @@ spv_result_t CheckRequiredCapabilities(const ValidationState_t& state, operand_desc->capabilities, operand_desc->numCapabilities); } - if (!state.HasAnyOfCapabilities(enabling_capabilities)) { - return state.diag(SPV_ERROR_INVALID_CAPABILITY, inst) - << "Operand " << which_operand << " of " - << spvOpcodeString(inst->opcode()) - << " requires one of these capabilities: " - << ToString(enabling_capabilities, state.grammar()); + // When encountering an OpCapability instruction, the instruction pass + // registers a capability with the module *before* checking capabilities. + // So in the case of an OpCapability instruction, don't bother checking + // enablement by another capability. + if (inst->opcode() != SpvOpCapability) { + const bool enabled_by_cap = + state.HasAnyOfCapabilities(enabling_capabilities); + if (!enabling_capabilities.IsEmpty() && !enabled_by_cap) { + return state.diag(SPV_ERROR_INVALID_CAPABILITY, inst) + << "Operand " << which_operand << " of " + << spvOpcodeString(inst->opcode()) + << " requires one of these capabilities: " + << ToString(enabling_capabilities, state.grammar()); + } } + return OperandVersionExtensionCheck(state, inst, which_operand, + *operand_desc, word); } - return SPV_SUCCESS; } -// Returns operand's required extensions. -ExtensionSet RequiredExtensions(const ValidationState_t& state, - spv_operand_type_t type, uint32_t operand) { - spv_operand_desc operand_desc; - if (state.grammar().lookupOperand(type, operand, &operand_desc) == - SPV_SUCCESS) { - assert(operand_desc); - // If this operand is incorporated into core SPIR-V before or in the current - // target environment, we don't require extensions anymore. - if (spvVersionForTargetEnv(state.grammar().target_env()) >= - operand_desc->minVersion) - return {}; - return {operand_desc->numExtensions, operand_desc->extensions}; - } - - return {}; -} - // Returns SPV_ERROR_INVALID_BINARY and emits a diagnostic if the instruction // is explicitly reserved in the SPIR-V core spec. Otherwise return // SPV_SUCCESS. @@ -195,23 +237,6 @@ spv_result_t ReservedCheck(ValidationState_t& _, const Instruction* inst) { return SPV_SUCCESS; } -// Returns SPV_ERROR_INVALID_BINARY and emits a diagnostic if the instruction -// is invalid because of an execution environment constraint. -spv_result_t EnvironmentCheck(ValidationState_t& _, const Instruction* inst) { - const SpvOp opcode = inst->opcode(); - switch (opcode) { - case SpvOpUndef: - if (_.features().bans_op_undef) { - return _.diag(SPV_ERROR_INVALID_BINARY, inst) - << "OpUndef is disallowed"; - } - break; - default: - break; - } - return SPV_SUCCESS; -} - // Returns SPV_ERROR_INVALID_CAPABILITY and emits a diagnostic if the // instruction is invalid because the required capability isn't declared // in the module. @@ -232,7 +257,7 @@ spv_result_t CapabilityCheck(ValidationState_t& _, const Instruction* inst) { for (uint32_t mask_bit = 0x80000000; mask_bit; mask_bit >>= 1) { if (word & mask_bit) { spv_result_t status = - CheckRequiredCapabilities(_, inst, i + 1, operand.type, mask_bit); + CheckRequiredCapabilities(_, inst, i + 1, operand, mask_bit); if (status != SPV_SUCCESS) return status; } } @@ -243,34 +268,13 @@ spv_result_t CapabilityCheck(ValidationState_t& _, const Instruction* inst) { } else { // Check the operand word as a whole. spv_result_t status = - CheckRequiredCapabilities(_, inst, i + 1, operand.type, word); + CheckRequiredCapabilities(_, inst, i + 1, operand, word); if (status != SPV_SUCCESS) return status; } } return SPV_SUCCESS; } -// Checks that all extensions required by the given instruction's operands were -// declared in the module. -spv_result_t ExtensionCheck(ValidationState_t& _, const Instruction* inst) { - const SpvOp opcode = inst->opcode(); - for (size_t operand_index = 0; operand_index < inst->operands().size(); - ++operand_index) { - const auto& operand = inst->operand(operand_index); - const uint32_t word = inst->word(operand.offset); - const ExtensionSet required_extensions = - RequiredExtensions(_, operand.type, word); - if (!_.HasAnyOfExtensions(required_extensions)) { - return _.diag(SPV_ERROR_MISSING_EXTENSION, inst) - << spvtools::utils::CardinalToOrdinal(operand_index + 1) - << " operand of " << spvOpcodeString(opcode) << ": operand " - << word << " requires one of these extensions: " - << ExtensionSetToString(required_extensions); - } - } - return SPV_SUCCESS; -} - // Checks that the instruction can be used in this target environment's base // version. Assumes that CapabilityCheck has checked direct capability // dependencies for the opcode. @@ -282,6 +286,15 @@ spv_result_t VersionCheck(ValidationState_t& _, const Instruction* inst) { (void)r; const auto min_version = inst_desc->minVersion; + const auto last_version = inst_desc->lastVersion; + const auto module_version = _.version(); + + if (last_version < module_version) { + return _.diag(SPV_ERROR_WRONG_VERSION, inst) + << spvOpcodeString(opcode) << " requires SPIR-V version " + << SPV_SPIRV_VERSION_MAJOR_PART(last_version) << "." + << SPV_SPIRV_VERSION_MINOR_PART(last_version) << " or earlier"; + } if (inst_desc->numCapabilities > 0u) { // We already checked that the direct capability dependency has been @@ -291,22 +304,23 @@ spv_result_t VersionCheck(ValidationState_t& _, const Instruction* inst) { ExtensionSet exts(inst_desc->numExtensions, inst_desc->extensions); if (exts.IsEmpty()) { - // If no extensions can enable this instruction, then emit error messages - // only concerning core SPIR-V versions if errors happen. + // If no extensions can enable this instruction, then emit error + // messages only concerning core SPIR-V versions if errors happen. if (min_version == ~0u) { return _.diag(SPV_ERROR_WRONG_VERSION, inst) << spvOpcodeString(opcode) << " is reserved for future use."; } - if (spvVersionForTargetEnv(_.grammar().target_env()) < min_version) { + if (module_version < min_version) { return _.diag(SPV_ERROR_WRONG_VERSION, inst) << spvOpcodeString(opcode) << " requires " << spvTargetEnvDescription( static_cast(min_version)) << " at minimum."; } - // Otherwise, we only error out when no enabling extensions are registered. } else if (!_.HasAnyOfExtensions(exts)) { + // Otherwise, we only error out when no enabling extensions are + // registered. if (min_version == ~0u) { return _.diag(SPV_ERROR_MISSING_EXTENSION, inst) << spvOpcodeString(opcode) @@ -314,11 +328,11 @@ spv_result_t VersionCheck(ValidationState_t& _, const Instruction* inst) { << ExtensionSetToString(exts); } - if (static_cast(_.grammar().target_env()) < min_version) { + if (module_version < min_version) { return _.diag(SPV_ERROR_WRONG_VERSION, inst) - << spvOpcodeString(opcode) << " requires " - << spvTargetEnvDescription( - static_cast(min_version)) + << spvOpcodeString(opcode) << " requires SPIR-V version " + << SPV_SPIRV_VERSION_MAJOR_PART(min_version) << "." + << SPV_SPIRV_VERSION_MINOR_PART(min_version) << " at minimum or one of the following extensions: " << ExtensionSetToString(exts); } @@ -355,11 +369,10 @@ spv_result_t LimitCheckStruct(ValidationState_t& _, const Instruction* inst) { // Section 2.17 of SPIRV Spec specifies that the "Structure Nesting Depth" // must be less than or equal to 255. - // This is interpreted as structures including other structures as members. - // The code does not follow pointers or look into arrays to see if we reach a - // structure downstream. - // The nesting depth of a struct is 1+(largest depth of any member). - // Scalars are at depth 0. + // This is interpreted as structures including other structures as + // members. The code does not follow pointers or look into arrays to see + // if we reach a structure downstream. The nesting depth of a struct is + // 1+(largest depth of any member). Scalars are at depth 0. uint32_t max_member_depth = 0; // Struct members start at word 2 of OpTypeStruct instruction. for (size_t word_i = 2; word_i < inst->words().size(); ++word_i) { @@ -382,8 +395,8 @@ spv_result_t LimitCheckStruct(ValidationState_t& _, const Instruction* inst) { return SPV_SUCCESS; } -// Checks that the number of (literal, label) pairs in OpSwitch is within the -// limit. +// Checks that the number of (literal, label) pairs in OpSwitch is within +// the limit. spv_result_t LimitCheckSwitch(ValidationState_t& _, const Instruction* inst) { if (SpvOpSwitch == inst->opcode()) { // The instruction syntax is as follows: @@ -402,7 +415,8 @@ spv_result_t LimitCheckSwitch(ValidationState_t& _, const Instruction* inst) { return SPV_SUCCESS; } -// Ensure the number of variables of the given class does not exceed the limit. +// Ensure the number of variables of the given class does not exceed the +// limit. spv_result_t LimitCheckNumVars(ValidationState_t& _, const uint32_t var_id, const SpvStorageClass storage_class) { if (SpvStorageClassFunction == storage_class) { @@ -429,88 +443,16 @@ spv_result_t LimitCheckNumVars(ValidationState_t& _, const uint32_t var_id, return SPV_SUCCESS; } -// Registers necessary decoration(s) for the appropriate IDs based on the -// instruction. -spv_result_t RegisterDecorations(ValidationState_t& _, - const Instruction* inst) { - switch (inst->opcode()) { - case SpvOpDecorate: { - const uint32_t target_id = inst->word(1); - const SpvDecoration dec_type = static_cast(inst->word(2)); - std::vector dec_params; - if (inst->words().size() > 3) { - dec_params.insert(dec_params.end(), inst->words().begin() + 3, - inst->words().end()); - } - _.RegisterDecorationForId(target_id, Decoration(dec_type, dec_params)); - break; - } - case SpvOpMemberDecorate: { - const uint32_t struct_id = inst->word(1); - const uint32_t index = inst->word(2); - const SpvDecoration dec_type = static_cast(inst->word(3)); - std::vector dec_params; - if (inst->words().size() > 4) { - dec_params.insert(dec_params.end(), inst->words().begin() + 4, - inst->words().end()); - } - _.RegisterDecorationForId(struct_id, - Decoration(dec_type, dec_params, index)); - break; - } - case SpvOpDecorationGroup: { - // We don't need to do anything right now. Assigning decorations to groups - // will be taken care of via OpGroupDecorate. - break; - } - case SpvOpGroupDecorate: { - // Word 1 is the group . All subsequent words are target s that - // are going to be decorated with the decorations. - const uint32_t decoration_group_id = inst->word(1); - std::vector& group_decorations = - _.id_decorations(decoration_group_id); - for (size_t i = 2; i < inst->words().size(); ++i) { - const uint32_t target_id = inst->word(i); - _.RegisterDecorationsForId(target_id, group_decorations.begin(), - group_decorations.end()); - } - break; - } - case SpvOpGroupMemberDecorate: { - // Word 1 is the Decoration Group followed by (struct,literal) - // pairs. All decorations of the group should be applied to all the struct - // members that are specified in the instructions. - const uint32_t decoration_group_id = inst->word(1); - std::vector& group_decorations = - _.id_decorations(decoration_group_id); - // Grammar checks ensures that the number of arguments to this instruction - // is an odd number: 1 decoration group + (id,literal) pairs. - for (size_t i = 2; i + 1 < inst->words().size(); i = i + 2) { - const uint32_t struct_id = inst->word(i); - const uint32_t index = inst->word(i + 1); - // ID validation phase ensures this is in fact a struct instruction and - // that the index is not out of bound. - _.RegisterDecorationsForStructMember(struct_id, index, - group_decorations.begin(), - group_decorations.end()); - } - break; - } - default: - break; - } - return SPV_SUCCESS; -} - // Parses OpExtension instruction and logs warnings if unsuccessful. -void CheckIfKnownExtension(ValidationState_t& _, const Instruction* inst) { +spv_result_t CheckIfKnownExtension(ValidationState_t& _, + const Instruction* inst) { const std::string extension_str = GetExtensionString(&(inst->c_inst())); Extension extension; if (!GetExtensionFromString(extension_str.c_str(), &extension)) { - _.diag(SPV_ERROR_INVALID_BINARY, inst) - << "Found unrecognized extension " << extension_str; - return; + return _.diag(SPV_WARNING, inst) + << "Found unrecognized extension " << extension_str; } + return SPV_SUCCESS; } } // namespace @@ -537,48 +479,9 @@ spv_result_t InstructionPass(ValidationState_t& _, const Instruction* inst) { if (auto error = LimitCheckNumVars(_, inst->id(), storage_class)) { return error; } - if (storage_class == SpvStorageClassGeneric) - return _.diag(SPV_ERROR_INVALID_BINARY, inst) - << "OpVariable storage class cannot be Generic"; - if (_.current_layout_section() == kLayoutFunctionDefinitions) { - if (storage_class != SpvStorageClassFunction) { - return _.diag(SPV_ERROR_INVALID_LAYOUT, inst) - << "Variables must have a function[7] storage class inside" - " of a function"; - } - if (_.current_function().IsFirstBlock( - _.current_function().current_block()->id()) == false) { - return _.diag(SPV_ERROR_INVALID_CFG, inst) - << "Variables can only be defined " - "in the first block of a " - "function"; - } - } else { - if (storage_class == SpvStorageClassFunction) { - return _.diag(SPV_ERROR_INVALID_LAYOUT, inst) - << "Variables can not have a function[7] storage class " - "outside of a function"; - } - } } - // SPIR-V Spec 2.16.3: Validation Rules for Kernel Capabilities: The - // Signedness in OpTypeInt must always be 0. - if (SpvOpTypeInt == inst->opcode() && _.HasCapability(SpvCapabilityKernel) && - inst->GetOperandAs(2) != 0u) { - return _.diag(SPV_ERROR_INVALID_BINARY, inst) - << "The Signedness in OpTypeInt " - "must always be 0 when Kernel " - "capability is used."; - } - - // In order to validate decoration rules, we need to know all the decorations - // that are applied to any given . - RegisterDecorations(_, inst); - - if (auto error = ExtensionCheck(_, inst)) return error; if (auto error = ReservedCheck(_, inst)) return error; - if (auto error = EnvironmentCheck(_, inst)) return error; if (auto error = CapabilityCheck(_, inst)) return error; if (auto error = LimitCheckIdBound(_, inst)) return error; if (auto error = LimitCheckStruct(_, inst)) return error; diff --git a/third_party/spirv-tools/source/val/validate_interfaces.cpp b/third_party/spirv-tools/source/val/validate_interfaces.cpp index fffc6da1ae..c85b673ddd 100644 --- a/third_party/spirv-tools/source/val/validate_interfaces.cpp +++ b/third_party/spirv-tools/source/val/validate_interfaces.cpp @@ -12,14 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "source/val/validate.h" - #include #include #include "source/diagnostic.h" +#include "source/spirv_constant.h" +#include "source/spirv_target_env.h" #include "source/val/function.h" #include "source/val/instruction.h" +#include "source/val/validate.h" #include "source/val/validation_state.h" namespace spvtools { @@ -27,10 +28,16 @@ namespace val { namespace { // Returns true if \c inst is an input or output variable. -bool is_interface_variable(const Instruction* inst) { - return inst->opcode() == SpvOpVariable && - (inst->word(3u) == SpvStorageClassInput || - inst->word(3u) == SpvStorageClassOutput); +bool is_interface_variable(const Instruction* inst, bool is_spv_1_4) { + if (is_spv_1_4) { + // Starting in SPIR-V 1.4, all global variables are interface variables. + return inst->opcode() == SpvOpVariable && + inst->word(3u) != SpvStorageClassFunction; + } else { + return inst->opcode() == SpvOpVariable && + (inst->word(3u) == SpvStorageClassInput || + inst->word(3u) == SpvStorageClassOutput); + } } // Checks that \c var is listed as an interface in all the entry points that use @@ -85,9 +92,8 @@ spv_result_t check_interface_variable(ValidationState_t& _, } if (!found) { return _.diag(SPV_ERROR_INVALID_ID, var) - << (var->word(3u) == SpvStorageClassInput ? "Input" : "Output") - << " variable id <" << var->id() << "> is used by entry point '" - << desc.name << "' id <" << id + << "Interface variable id <" << var->id() + << "> is used by entry point '" << desc.name << "' id <" << id << ">, but is not listed as an interface"; } } @@ -99,8 +105,9 @@ spv_result_t check_interface_variable(ValidationState_t& _, } // namespace spv_result_t ValidateInterfaces(ValidationState_t& _) { + bool is_spv_1_4 = _.version() >= SPV_SPIRV_VERSION_WORD(1, 4); for (auto& inst : _.ordered_instructions()) { - if (is_interface_variable(&inst)) { + if (is_interface_variable(&inst, is_spv_1_4)) { if (auto error = check_interface_variable(_, &inst)) { return error; } diff --git a/third_party/spirv-tools/source/val/validate_layout.cpp b/third_party/spirv-tools/source/val/validate_layout.cpp index 53c28355fe..707ad5248e 100644 --- a/third_party/spirv-tools/source/val/validate_layout.cpp +++ b/third_party/spirv-tools/source/val/validate_layout.cpp @@ -14,15 +14,16 @@ // Source code for logical layout validation as described in section 2.4 -#include "source/val/validate.h" - #include +#include "DebugInfo.h" +#include "OpenCLDebugInfo100.h" #include "source/diagnostic.h" #include "source/opcode.h" #include "source/operand.h" #include "source/val/function.h" #include "source/val/instruction.h" +#include "source/val/validate.h" #include "source/val/validation_state.h" namespace spvtools { @@ -34,6 +35,77 @@ namespace { // checked. spv_result_t ModuleScopedInstructions(ValidationState_t& _, const Instruction* inst, SpvOp opcode) { + switch (opcode) { + case SpvOpExtInst: + if (spvExtInstIsNonSemantic(inst->ext_inst_type())) { + // non-semantic extinst opcodes are allowed beginning in the types + // section, but since they must name a return type they cannot be the + // first instruction in the types section. Therefore check that we are + // already in it. + if (_.current_layout_section() < kLayoutTypes) { + return _.diag(SPV_ERROR_INVALID_LAYOUT, inst) + << "Non-semantic OpExtInst must not appear before types " + << "section"; + } + } else if (spvExtInstIsDebugInfo(inst->ext_inst_type())) { + const uint32_t ext_inst_index = inst->word(4); + bool local_debug_info = false; + if (inst->ext_inst_type() == SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100) { + const OpenCLDebugInfo100Instructions ext_inst_key = + OpenCLDebugInfo100Instructions(ext_inst_index); + if (ext_inst_key == OpenCLDebugInfo100DebugScope || + ext_inst_key == OpenCLDebugInfo100DebugNoScope || + ext_inst_key == OpenCLDebugInfo100DebugDeclare || + ext_inst_key == OpenCLDebugInfo100DebugValue) { + local_debug_info = true; + } + } else { + const DebugInfoInstructions ext_inst_key = + DebugInfoInstructions(ext_inst_index); + if (ext_inst_key == DebugInfoDebugScope || + ext_inst_key == DebugInfoDebugNoScope || + ext_inst_key == DebugInfoDebugDeclare || + ext_inst_key == DebugInfoDebugValue) { + local_debug_info = true; + } + } + + if (local_debug_info) { + if (_.in_function_body() == false) { + // DebugScope, DebugNoScope, DebugDeclare, DebugValue must + // appear in a function body. + return _.diag(SPV_ERROR_INVALID_LAYOUT, inst) + << "DebugScope, DebugNoScope, DebugDeclare, DebugValue " + << "of debug info extension must appear in a function " + << "body"; + } + } else { + // Debug info extinst opcodes other than DebugScope, DebugNoScope, + // DebugDeclare, DebugValue must be placed between section 9 (types, + // constants, global variables) and section 10 (function + // declarations). + if (_.current_layout_section() < kLayoutTypes || + _.current_layout_section() >= kLayoutFunctionDeclarations) { + return _.diag(SPV_ERROR_INVALID_LAYOUT, inst) + << "Debug info extension instructions other than " + << "DebugScope, DebugNoScope, DebugDeclare, DebugValue " + << "must appear between section 9 (types, constants, " + << "global variables) and section 10 (function " + << "declarations)"; + } + } + } else { + // otherwise they must be used in a block + if (_.current_layout_section() < kLayoutFunctionDefinitions) { + return _.diag(SPV_ERROR_INVALID_LAYOUT, inst) + << spvOpcodeString(opcode) << " must appear in a block"; + } + } + break; + default: + break; + } + while (_.IsOpcodeInCurrentLayoutSection(opcode) == false) { _.ProgressToNextLayoutSectionOrder(); @@ -144,6 +216,76 @@ spv_result_t FunctionScopedInstructions(ValidationState_t& _, } break; + case SpvOpExtInst: + if (spvExtInstIsNonSemantic(inst->ext_inst_type())) { + // non-semantic extinst opcodes are allowed beginning in the types + // section, but must either be placed outside a function declaration, + // or inside a block. + if (_.current_layout_section() < kLayoutTypes) { + return _.diag(SPV_ERROR_INVALID_LAYOUT, inst) + << "Non-semantic OpExtInst must not appear before types " + << "section"; + } else if (_.in_function_body() && _.in_block() == false) { + return _.diag(SPV_ERROR_INVALID_LAYOUT, inst) + << "Non-semantic OpExtInst within function definition must " + "appear in a block"; + } + } else if (spvExtInstIsDebugInfo(inst->ext_inst_type())) { + const uint32_t ext_inst_index = inst->word(4); + bool local_debug_info = false; + if (inst->ext_inst_type() == SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100) { + const OpenCLDebugInfo100Instructions ext_inst_key = + OpenCLDebugInfo100Instructions(ext_inst_index); + if (ext_inst_key == OpenCLDebugInfo100DebugScope || + ext_inst_key == OpenCLDebugInfo100DebugNoScope || + ext_inst_key == OpenCLDebugInfo100DebugDeclare || + ext_inst_key == OpenCLDebugInfo100DebugValue) { + local_debug_info = true; + } + } else { + const DebugInfoInstructions ext_inst_key = + DebugInfoInstructions(ext_inst_index); + if (ext_inst_key == DebugInfoDebugScope || + ext_inst_key == DebugInfoDebugNoScope || + ext_inst_key == DebugInfoDebugDeclare || + ext_inst_key == DebugInfoDebugValue) { + local_debug_info = true; + } + } + + if (local_debug_info) { + if (_.in_function_body() == false) { + // DebugScope, DebugNoScope, DebugDeclare, DebugValue must + // appear in a function body. + return _.diag(SPV_ERROR_INVALID_LAYOUT, inst) + << "DebugScope, DebugNoScope, DebugDeclare, DebugValue " + << "of debug info extension must appear in a function " + << "body"; + } + } else { + // Debug info extinst opcodes other than DebugScope, DebugNoScope, + // DebugDeclare, DebugValue must be placed between section 9 (types, + // constants, global variables) and section 10 (function + // declarations). + if (_.current_layout_section() < kLayoutTypes || + _.current_layout_section() >= kLayoutFunctionDeclarations) { + return _.diag(SPV_ERROR_INVALID_LAYOUT, inst) + << "Debug info extension instructions other than " + << "DebugScope, DebugNoScope, DebugDeclare, DebugValue " + << "must appear between section 9 (types, constants, " + << "global variables) and section 10 (function " + << "declarations)"; + } + } + } else { + // otherwise they must be used in a block + if (_.in_block() == false) { + return _.diag(SPV_ERROR_INVALID_LAYOUT, inst) + << spvOpcodeString(opcode) << " must appear in a block"; + } + } + break; + default: if (_.current_layout_section() == kLayoutFunctionDeclarations && _.in_function_body()) { diff --git a/third_party/spirv-tools/source/val/validate_logicals.cpp b/third_party/spirv-tools/source/val/validate_logicals.cpp index 9c637c4233..5886dbf504 100644 --- a/third_party/spirv-tools/source/val/validate_logicals.cpp +++ b/third_party/spirv-tools/source/val/validate_logicals.cpp @@ -151,10 +151,19 @@ spv_result_t LogicalsPass(ValidationState_t& _, const Instruction* inst) { const Instruction* type_inst = _.FindDef(result_type); assert(type_inst); + const auto composites = _.features().select_between_composites; + auto fail = [&_, composites, inst, opcode]() -> spv_result_t { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Expected scalar or " + << (composites ? "composite" : "vector") + << " type as Result Type: " << spvOpcodeString(opcode); + }; + const SpvOp type_opcode = type_inst->opcode(); switch (type_opcode) { case SpvOpTypePointer: { - if (!_.features().variable_pointers && + if (_.addressing_model() == SpvAddressingModelLogical && + !_.features().variable_pointers && !_.features().variable_pointers_storage_buffer) return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Using pointers with OpSelect requires capability " @@ -173,35 +182,48 @@ spv_result_t LogicalsPass(ValidationState_t& _, const Instruction* inst) { break; } - default: { + // Not RuntimeArray because of other rules. + case SpvOpTypeArray: + case SpvOpTypeMatrix: + case SpvOpTypeStruct: { + if (!composites) return fail(); + break; + }; + + default: + return fail(); + } + + const uint32_t condition_type = _.GetOperandTypeId(inst, 2); + const uint32_t left_type = _.GetOperandTypeId(inst, 3); + const uint32_t right_type = _.GetOperandTypeId(inst, 4); + + if (!condition_type || (!_.IsBoolScalarType(condition_type) && + !_.IsBoolVectorType(condition_type))) + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Expected bool scalar or vector type as condition: " + << spvOpcodeString(opcode); + + if (_.GetDimension(condition_type) != dimension) { + // If the condition is a vector type, then the result must also be a + // vector with matching dimensions. In SPIR-V 1.4, a scalar condition + // can be used to select between vector types. |composites| is a + // proxy for SPIR-V 1.4 functionality. + if (!composites || _.IsBoolVectorType(condition_type)) { return _.diag(SPV_ERROR_INVALID_DATA, inst) - << "Expected scalar or vector type as Result Type: " + << "Expected vector sizes of Result Type and the condition " + "to be equal: " << spvOpcodeString(opcode); } } + + if (result_type != left_type || result_type != right_type) + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Expected both objects to be of Result Type: " + << spvOpcodeString(opcode); + + break; } - - const uint32_t condition_type = _.GetOperandTypeId(inst, 2); - const uint32_t left_type = _.GetOperandTypeId(inst, 3); - const uint32_t right_type = _.GetOperandTypeId(inst, 4); - - if (!condition_type || (!_.IsBoolScalarType(condition_type) && - !_.IsBoolVectorType(condition_type))) - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << "Expected bool scalar or vector type as condition: " - << spvOpcodeString(opcode); - - if (_.GetDimension(condition_type) != dimension) - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << "Expected vector sizes of Result Type and the condition to be" - << " equal: " << spvOpcodeString(opcode); - - if (result_type != left_type || result_type != right_type) - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << "Expected both objects to be of Result Type: " - << spvOpcodeString(opcode); - - break; } case SpvOpIEqual: diff --git a/third_party/spirv-tools/source/val/validate_memory.cpp b/third_party/spirv-tools/source/val/validate_memory.cpp index 18c3cca0f3..bff8b20ee5 100644 --- a/third_party/spirv-tools/source/val/validate_memory.cpp +++ b/third_party/spirv-tools/source/val/validate_memory.cpp @@ -12,14 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "source/val/validate.h" - #include #include #include #include "source/opcode.h" +#include "source/spirv_target_env.h" #include "source/val/instruction.h" +#include "source/val/validate.h" +#include "source/val/validate_scopes.h" #include "source/val/validation_state.h" namespace spvtools { @@ -35,6 +36,21 @@ bool HaveSameLayoutDecorations(ValidationState_t&, const Instruction*, bool HasConflictingMemberOffsets(const std::vector&, const std::vector&); +bool IsAllowedTypeOrArrayOfSame(ValidationState_t& _, const Instruction* type, + std::initializer_list allowed) { + if (std::find(allowed.begin(), allowed.end(), type->opcode()) != + allowed.end()) { + return true; + } + if (type->opcode() == SpvOpTypeArray || + type->opcode() == SpvOpTypeRuntimeArray) { + auto elem_type = _.FindDef(type->word(2)); + return std::find(allowed.begin(), allowed.end(), elem_type->opcode()) != + allowed.end(); + } + return false; +} + // Returns true if the two instructions represent structs that, as far as the // validator can tell, have the exact same data layout. bool AreLayoutCompatibleStructs(ValidationState_t& _, const Instruction* type1, @@ -57,9 +73,9 @@ bool AreLayoutCompatibleStructs(ValidationState_t& _, const Instruction* type1, bool HaveLayoutCompatibleMembers(ValidationState_t& _, const Instruction* type1, const Instruction* type2) { assert(type1->opcode() == SpvOpTypeStruct && - "type1 must be and OpTypeStruct instruction."); + "type1 must be an OpTypeStruct instruction."); assert(type2->opcode() == SpvOpTypeStruct && - "type2 must be and OpTypeStruct instruction."); + "type2 must be an OpTypeStruct instruction."); const auto& type1_operands = type1->operands(); const auto& type2_operands = type2->operands(); if (type1_operands.size() != type2_operands.size()) { @@ -84,9 +100,9 @@ bool HaveLayoutCompatibleMembers(ValidationState_t& _, const Instruction* type1, bool HaveSameLayoutDecorations(ValidationState_t& _, const Instruction* type1, const Instruction* type2) { assert(type1->opcode() == SpvOpTypeStruct && - "type1 must be and OpTypeStruct instruction."); + "type1 must be an OpTypeStruct instruction."); assert(type2->opcode() == SpvOpTypeStruct && - "type2 must be and OpTypeStruct instruction."); + "type2 must be an OpTypeStruct instruction."); const std::vector& type1_decorations = _.id_decorations(type1->id()); const std::vector& type2_decorations = @@ -139,40 +155,715 @@ bool HasConflictingMemberOffsets( return false; } -spv_result_t ValidateVariable(ValidationState_t& _, const Instruction& inst) { - auto result_type = _.FindDef(inst.type_id()); - if (!result_type || result_type->opcode() != SpvOpTypePointer) { - return _.diag(SPV_ERROR_INVALID_ID, &inst) - << "OpVariable Result Type '" << _.getIdName(inst.type_id()) - << "' is not a pointer type."; +// If |skip_builtin| is true, returns true if |storage| contains bool within +// it and no storage that contains the bool is builtin. +// If |skip_builtin| is false, returns true if |storage| contains bool within +// it. +bool ContainsInvalidBool(ValidationState_t& _, const Instruction* storage, + bool skip_builtin) { + if (skip_builtin) { + for (const Decoration& decoration : _.id_decorations(storage->id())) { + if (decoration.dec_type() == SpvDecorationBuiltIn) return false; + } } - const auto initializer_index = 3; - if (initializer_index < inst.operands().size()) { - const auto initializer_id = inst.GetOperandAs(initializer_index); - const auto initializer = _.FindDef(initializer_id); - const auto storage_class_index = 2; - const auto is_module_scope_var = - initializer && (initializer->opcode() == SpvOpVariable) && - (initializer->GetOperandAs(storage_class_index) != - SpvStorageClassFunction); - const auto is_constant = - initializer && spvOpcodeIsConstant(initializer->opcode()); - if (!initializer || !(is_constant || is_module_scope_var)) { - return _.diag(SPV_ERROR_INVALID_ID, &inst) - << "OpVariable Initializer '" << _.getIdName(initializer_id) - << "' is not a constant or module-scope variable."; + const size_t elem_type_index = 1; + uint32_t elem_type_id; + Instruction* elem_type; + + switch (storage->opcode()) { + case SpvOpTypeBool: + return true; + case SpvOpTypeVector: + case SpvOpTypeMatrix: + case SpvOpTypeArray: + case SpvOpTypeRuntimeArray: + elem_type_id = storage->GetOperandAs(elem_type_index); + elem_type = _.FindDef(elem_type_id); + return ContainsInvalidBool(_, elem_type, skip_builtin); + case SpvOpTypeStruct: + for (size_t member_type_index = 1; + member_type_index < storage->operands().size(); + ++member_type_index) { + auto member_type_id = + storage->GetOperandAs(member_type_index); + auto member_type = _.FindDef(member_type_id); + if (ContainsInvalidBool(_, member_type, skip_builtin)) return true; + } + default: + break; + } + return false; +} + +bool ContainsCooperativeMatrix(ValidationState_t& _, + const Instruction* storage) { + const size_t elem_type_index = 1; + uint32_t elem_type_id; + Instruction* elem_type; + + switch (storage->opcode()) { + case SpvOpTypeCooperativeMatrixNV: + return true; + case SpvOpTypeArray: + case SpvOpTypeRuntimeArray: + elem_type_id = storage->GetOperandAs(elem_type_index); + elem_type = _.FindDef(elem_type_id); + return ContainsCooperativeMatrix(_, elem_type); + case SpvOpTypeStruct: + for (size_t member_type_index = 1; + member_type_index < storage->operands().size(); + ++member_type_index) { + auto member_type_id = + storage->GetOperandAs(member_type_index); + auto member_type = _.FindDef(member_type_id); + if (ContainsCooperativeMatrix(_, member_type)) return true; + } + break; + default: + break; + } + return false; +} + +std::pair GetStorageClass( + ValidationState_t& _, const Instruction* inst) { + SpvStorageClass dst_sc = SpvStorageClassMax; + SpvStorageClass src_sc = SpvStorageClassMax; + switch (inst->opcode()) { + case SpvOpCooperativeMatrixLoadNV: + case SpvOpLoad: { + auto load_pointer = _.FindDef(inst->GetOperandAs(2)); + auto load_pointer_type = _.FindDef(load_pointer->type_id()); + dst_sc = load_pointer_type->GetOperandAs(1); + break; + } + case SpvOpCooperativeMatrixStoreNV: + case SpvOpStore: { + auto store_pointer = _.FindDef(inst->GetOperandAs(0)); + auto store_pointer_type = _.FindDef(store_pointer->type_id()); + dst_sc = store_pointer_type->GetOperandAs(1); + break; + } + case SpvOpCopyMemory: + case SpvOpCopyMemorySized: { + auto dst = _.FindDef(inst->GetOperandAs(0)); + auto dst_type = _.FindDef(dst->type_id()); + dst_sc = dst_type->GetOperandAs(1); + auto src = _.FindDef(inst->GetOperandAs(1)); + auto src_type = _.FindDef(src->type_id()); + src_sc = src_type->GetOperandAs(1); + break; + } + default: + break; + } + + return std::make_pair(dst_sc, src_sc); +} + +// Returns the number of instruction words taken up by a memory access +// argument and its implied operands. +int MemoryAccessNumWords(uint32_t mask) { + int result = 1; // Count the mask + if (mask & SpvMemoryAccessAlignedMask) ++result; + if (mask & SpvMemoryAccessMakePointerAvailableKHRMask) ++result; + if (mask & SpvMemoryAccessMakePointerVisibleKHRMask) ++result; + return result; +} + +// Returns the scope ID operand for MakeAvailable memory access with mask +// at the given operand index. +// This function is only called for OpLoad, OpStore, OpCopyMemory and +// OpCopyMemorySized, OpCooperativeMatrixLoadNV, and +// OpCooperativeMatrixStoreNV. +uint32_t GetMakeAvailableScope(const Instruction* inst, uint32_t mask, + uint32_t mask_index) { + assert(mask & SpvMemoryAccessMakePointerAvailableKHRMask); + uint32_t this_bit = uint32_t(SpvMemoryAccessMakePointerAvailableKHRMask); + uint32_t index = + mask_index - 1 + MemoryAccessNumWords(mask & (this_bit | (this_bit - 1))); + return inst->GetOperandAs(index); +} + +// This function is only called for OpLoad, OpStore, OpCopyMemory, +// OpCopyMemorySized, OpCooperativeMatrixLoadNV, and +// OpCooperativeMatrixStoreNV. +uint32_t GetMakeVisibleScope(const Instruction* inst, uint32_t mask, + uint32_t mask_index) { + assert(mask & SpvMemoryAccessMakePointerVisibleKHRMask); + uint32_t this_bit = uint32_t(SpvMemoryAccessMakePointerVisibleKHRMask); + uint32_t index = + mask_index - 1 + MemoryAccessNumWords(mask & (this_bit | (this_bit - 1))); + return inst->GetOperandAs(index); +} + +bool DoesStructContainRTA(const ValidationState_t& _, const Instruction* inst) { + for (size_t member_index = 1; member_index < inst->operands().size(); + ++member_index) { + const auto member_id = inst->GetOperandAs(member_index); + const auto member_type = _.FindDef(member_id); + if (member_type->opcode() == SpvOpTypeRuntimeArray) return true; + } + return false; +} + +spv_result_t CheckMemoryAccess(ValidationState_t& _, const Instruction* inst, + uint32_t index) { + SpvStorageClass dst_sc, src_sc; + std::tie(dst_sc, src_sc) = GetStorageClass(_, inst); + if (inst->operands().size() <= index) { + if (src_sc == SpvStorageClassPhysicalStorageBufferEXT || + dst_sc == SpvStorageClassPhysicalStorageBufferEXT) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Memory accesses with PhysicalStorageBufferEXT must use " + "Aligned."; + } + return SPV_SUCCESS; + } + + const uint32_t mask = inst->GetOperandAs(index); + if (mask & SpvMemoryAccessMakePointerAvailableKHRMask) { + if (inst->opcode() == SpvOpLoad || + inst->opcode() == SpvOpCooperativeMatrixLoadNV) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "MakePointerAvailableKHR cannot be used with OpLoad."; + } + + if (!(mask & SpvMemoryAccessNonPrivatePointerKHRMask)) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "NonPrivatePointerKHR must be specified if " + "MakePointerAvailableKHR is specified."; + } + + // Check the associated scope for MakeAvailableKHR. + const auto available_scope = GetMakeAvailableScope(inst, mask, index); + if (auto error = ValidateMemoryScope(_, inst, available_scope)) + return error; + } + + if (mask & SpvMemoryAccessMakePointerVisibleKHRMask) { + if (inst->opcode() == SpvOpStore || + inst->opcode() == SpvOpCooperativeMatrixStoreNV) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "MakePointerVisibleKHR cannot be used with OpStore."; + } + + if (!(mask & SpvMemoryAccessNonPrivatePointerKHRMask)) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "NonPrivatePointerKHR must be specified if " + << "MakePointerVisibleKHR is specified."; + } + + // Check the associated scope for MakeVisibleKHR. + const auto visible_scope = GetMakeVisibleScope(inst, mask, index); + if (auto error = ValidateMemoryScope(_, inst, visible_scope)) return error; + } + + if (mask & SpvMemoryAccessNonPrivatePointerKHRMask) { + if (dst_sc != SpvStorageClassUniform && + dst_sc != SpvStorageClassWorkgroup && + dst_sc != SpvStorageClassCrossWorkgroup && + dst_sc != SpvStorageClassGeneric && dst_sc != SpvStorageClassImage && + dst_sc != SpvStorageClassStorageBuffer && + dst_sc != SpvStorageClassPhysicalStorageBufferEXT) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "NonPrivatePointerKHR requires a pointer in Uniform, " + << "Workgroup, CrossWorkgroup, Generic, Image or StorageBuffer " + << "storage classes."; + } + if (src_sc != SpvStorageClassMax && src_sc != SpvStorageClassUniform && + src_sc != SpvStorageClassWorkgroup && + src_sc != SpvStorageClassCrossWorkgroup && + src_sc != SpvStorageClassGeneric && src_sc != SpvStorageClassImage && + src_sc != SpvStorageClassStorageBuffer && + src_sc != SpvStorageClassPhysicalStorageBufferEXT) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "NonPrivatePointerKHR requires a pointer in Uniform, " + << "Workgroup, CrossWorkgroup, Generic, Image or StorageBuffer " + << "storage classes."; + } + } + + if (!(mask & SpvMemoryAccessAlignedMask)) { + if (src_sc == SpvStorageClassPhysicalStorageBufferEXT || + dst_sc == SpvStorageClassPhysicalStorageBufferEXT) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Memory accesses with PhysicalStorageBufferEXT must use " + "Aligned."; } } return SPV_SUCCESS; } -spv_result_t ValidateLoad(ValidationState_t& _, const Instruction& inst) { - const auto result_type = _.FindDef(inst.type_id()); +spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) { + auto result_type = _.FindDef(inst->type_id()); + if (!result_type || result_type->opcode() != SpvOpTypePointer) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "OpVariable Result Type '" << _.getIdName(inst->type_id()) + << "' is not a pointer type."; + } + + const auto initializer_index = 3; + const auto storage_class_index = 2; + if (initializer_index < inst->operands().size()) { + const auto initializer_id = inst->GetOperandAs(initializer_index); + const auto initializer = _.FindDef(initializer_id); + const auto is_module_scope_var = + initializer && (initializer->opcode() == SpvOpVariable) && + (initializer->GetOperandAs(storage_class_index) != + SpvStorageClassFunction); + const auto is_constant = + initializer && spvOpcodeIsConstant(initializer->opcode()); + if (!initializer || !(is_constant || is_module_scope_var)) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "OpVariable Initializer '" << _.getIdName(initializer_id) + << "' is not a constant or module-scope variable."; + } + if (initializer->type_id() != result_type->GetOperandAs(2u)) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Initializer type must match the type pointed to by the Result " + "Type"; + } + } + + auto storage_class = inst->GetOperandAs(storage_class_index); + if (storage_class != SpvStorageClassWorkgroup && + storage_class != SpvStorageClassCrossWorkgroup && + storage_class != SpvStorageClassPrivate && + storage_class != SpvStorageClassFunction && + storage_class != SpvStorageClassRayPayloadNV && + storage_class != SpvStorageClassIncomingRayPayloadNV && + storage_class != SpvStorageClassHitAttributeNV && + storage_class != SpvStorageClassCallableDataNV && + storage_class != SpvStorageClassIncomingCallableDataNV) { + const auto storage_index = 2; + const auto storage_id = result_type->GetOperandAs(storage_index); + const auto storage = _.FindDef(storage_id); + bool storage_input_or_output = storage_class == SpvStorageClassInput || + storage_class == SpvStorageClassOutput; + bool builtin = false; + if (storage_input_or_output) { + for (const Decoration& decoration : _.id_decorations(inst->id())) { + if (decoration.dec_type() == SpvDecorationBuiltIn) { + builtin = true; + break; + } + } + } + if (!(storage_input_or_output && builtin) && + ContainsInvalidBool(_, storage, storage_input_or_output)) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "If OpTypeBool is stored in conjunction with OpVariable, it " + << "can only be used with non-externally visible shader Storage " + << "Classes: Workgroup, CrossWorkgroup, Private, and Function"; + } + } + + if (!_.IsValidStorageClass(storage_class)) { + return _.diag(SPV_ERROR_INVALID_BINARY, inst) + << "Invalid storage class for target environment"; + } + + if (storage_class == SpvStorageClassGeneric) { + return _.diag(SPV_ERROR_INVALID_BINARY, inst) + << "OpVariable storage class cannot be Generic"; + } + + if (inst->function() && storage_class != SpvStorageClassFunction) { + return _.diag(SPV_ERROR_INVALID_LAYOUT, inst) + << "Variables must have a function[7] storage class inside" + " of a function"; + } + + if (!inst->function() && storage_class == SpvStorageClassFunction) { + return _.diag(SPV_ERROR_INVALID_LAYOUT, inst) + << "Variables can not have a function[7] storage class " + "outside of a function"; + } + + // SPIR-V 3.32.8: Check that pointer type and variable type have the same + // storage class. + const auto result_storage_class_index = 1; + const auto result_storage_class = + result_type->GetOperandAs(result_storage_class_index); + if (storage_class != result_storage_class) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "From SPIR-V spec, section 3.32.8 on OpVariable:\n" + << "Its Storage Class operand must be the same as the Storage Class " + << "operand of the result type."; + } + + // Variable pointer related restrictions. + const auto pointee = _.FindDef(result_type->word(3)); + if (_.addressing_model() == SpvAddressingModelLogical && + !_.options()->relax_logical_pointer) { + // VariablePointersStorageBuffer is implied by VariablePointers. + if (pointee->opcode() == SpvOpTypePointer) { + if (!_.HasCapability(SpvCapabilityVariablePointersStorageBuffer)) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "In Logical addressing, variables may not allocate a pointer " + << "type"; + } else if (storage_class != SpvStorageClassFunction && + storage_class != SpvStorageClassPrivate) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "In Logical addressing with variable pointers, variables " + << "that allocate pointers must be in Function or Private " + << "storage classes"; + } + } + } + + // Vulkan 14.5.1: Check type of PushConstant variables. + // Vulkan 14.5.2: Check type of UniformConstant and Uniform variables. + if (spvIsVulkanEnv(_.context()->target_env)) { + if (storage_class == SpvStorageClassPushConstant) { + if (!IsAllowedTypeOrArrayOfSame(_, pointee, {SpvOpTypeStruct})) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "PushConstant OpVariable '" << _.getIdName(inst->id()) + << "' has illegal type.\n" + << "From Vulkan spec, section 14.5.1:\n" + << "Such variables must be typed as OpTypeStruct, " + << "or an array of this type"; + } + } + + if (storage_class == SpvStorageClassUniformConstant) { + if (!IsAllowedTypeOrArrayOfSame( + _, pointee, + {SpvOpTypeImage, SpvOpTypeSampler, SpvOpTypeSampledImage, + SpvOpTypeAccelerationStructureNV})) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "UniformConstant OpVariable '" << _.getIdName(inst->id()) + << "' has illegal type.\n" + << "From Vulkan spec, section 14.5.2:\n" + << "Variables identified with the UniformConstant storage class " + << "are used only as handles to refer to opaque resources. Such " + << "variables must be typed as OpTypeImage, OpTypeSampler, " + << "OpTypeSampledImage, OpTypeAccelerationStructureNV, " + << "or an array of one of these types."; + } + } + + if (storage_class == SpvStorageClassUniform) { + if (!IsAllowedTypeOrArrayOfSame(_, pointee, {SpvOpTypeStruct})) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Uniform OpVariable '" << _.getIdName(inst->id()) + << "' has illegal type.\n" + << "From Vulkan spec, section 14.5.2:\n" + << "Variables identified with the Uniform storage class are " + << "used to access transparent buffer backed resources. Such " + << "variables must be typed as OpTypeStruct, or an array of " + << "this type"; + } + } + + if (storage_class == SpvStorageClassStorageBuffer) { + if (!IsAllowedTypeOrArrayOfSame(_, pointee, {SpvOpTypeStruct})) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "StorageBuffer OpVariable '" << _.getIdName(inst->id()) + << "' has illegal type.\n" + << "From Vulkan spec, section 14.5.2:\n" + << "Variables identified with the StorageBuffer storage class " + "are used to access transparent buffer backed resources. " + "Such variables must be typed as OpTypeStruct, or an array " + "of this type"; + } + } + } + + // WebGPU & Vulkan Appendix A: Check that if contains initializer, then + // storage class is Output, Private, or Function. + if (inst->operands().size() > 3 && storage_class != SpvStorageClassOutput && + storage_class != SpvStorageClassPrivate && + storage_class != SpvStorageClassFunction) { + if (spvIsVulkanOrWebGPUEnv(_.context()->target_env)) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "OpVariable, '" << _.getIdName(inst->id()) + << "', has a disallowed initializer & storage class " + << "combination.\n" + << "From " << spvLogStringForEnv(_.context()->target_env) + << " spec:\n" + << "Variable declarations that include initializers must have " + << "one of the following storage classes: Output, Private, or " + << "Function"; + } + } + + // WebGPU: All variables with storage class Output, Private, or Function MUST + // have an initializer. + if (spvIsWebGPUEnv(_.context()->target_env) && inst->operands().size() <= 3 && + (storage_class == SpvStorageClassOutput || + storage_class == SpvStorageClassPrivate || + storage_class == SpvStorageClassFunction)) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "OpVariable, '" << _.getIdName(inst->id()) + << "', must have an initializer.\n" + << "From WebGPU execution environment spec:\n" + << "All variables in the following storage classes must have an " + << "initializer: Output, Private, or Function"; + } + + if (storage_class == SpvStorageClassPhysicalStorageBufferEXT) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "PhysicalStorageBufferEXT must not be used with OpVariable."; + } + + auto pointee_base = pointee; + while (pointee_base->opcode() == SpvOpTypeArray) { + pointee_base = _.FindDef(pointee_base->GetOperandAs(1u)); + } + if (pointee_base->opcode() == SpvOpTypePointer) { + if (pointee_base->GetOperandAs(1u) == + SpvStorageClassPhysicalStorageBufferEXT) { + // check for AliasedPointerEXT/RestrictPointerEXT + bool foundAliased = + _.HasDecoration(inst->id(), SpvDecorationAliasedPointerEXT); + bool foundRestrict = + _.HasDecoration(inst->id(), SpvDecorationRestrictPointerEXT); + if (!foundAliased && !foundRestrict) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "OpVariable " << inst->id() + << ": expected AliasedPointerEXT or RestrictPointerEXT for " + << "PhysicalStorageBufferEXT pointer."; + } + if (foundAliased && foundRestrict) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "OpVariable " << inst->id() + << ": can't specify both AliasedPointerEXT and " + << "RestrictPointerEXT for PhysicalStorageBufferEXT pointer."; + } + } + } + + // Vulkan specific validation rules for OpTypeRuntimeArray + const auto type_index = 2; + const auto value_id = result_type->GetOperandAs(type_index); + auto value_type = _.FindDef(value_id); + if (spvIsVulkanEnv(_.context()->target_env)) { + // OpTypeRuntimeArray should only ever be in a container like OpTypeStruct, + // so should never appear as a bare variable. + // Unless the module has the RuntimeDescriptorArrayEXT capability. + if (value_type && value_type->opcode() == SpvOpTypeRuntimeArray) { + if (!_.HasCapability(SpvCapabilityRuntimeDescriptorArrayEXT)) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "OpVariable, '" << _.getIdName(inst->id()) + << "', is attempting to create memory for an illegal type, " + << "OpTypeRuntimeArray.\nFor Vulkan OpTypeRuntimeArray can only " + << "appear as the final member of an OpTypeStruct, thus cannot " + << "be instantiated via OpVariable"; + } else { + // A bare variable OpTypeRuntimeArray is allowed in this context, but + // still need to check the storage class. + if (storage_class != SpvStorageClassStorageBuffer && + storage_class != SpvStorageClassUniform && + storage_class != SpvStorageClassUniformConstant) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "For Vulkan with RuntimeDescriptorArrayEXT, a variable " + << "containing OpTypeRuntimeArray must have storage class of " + << "StorageBuffer, Uniform, or UniformConstant."; + } + } + } + + // If an OpStruct has an OpTypeRuntimeArray somewhere within it, then it + // must either have the storage class StorageBuffer and be decorated + // with Block, or it must be in the Uniform storage class and be decorated + // as BufferBlock. + if (value_type && value_type->opcode() == SpvOpTypeStruct) { + if (DoesStructContainRTA(_, value_type)) { + if (storage_class == SpvStorageClassStorageBuffer) { + if (!_.HasDecoration(value_id, SpvDecorationBlock)) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "For Vulkan, an OpTypeStruct variable containing an " + << "OpTypeRuntimeArray must be decorated with Block if it " + << "has storage class StorageBuffer."; + } + } else if (storage_class == SpvStorageClassUniform) { + if (!_.HasDecoration(value_id, SpvDecorationBufferBlock)) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "For Vulkan, an OpTypeStruct variable containing an " + << "OpTypeRuntimeArray must be decorated with BufferBlock " + << "if it has storage class Uniform."; + } + } else { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "For Vulkan, OpTypeStruct variables containing " + << "OpTypeRuntimeArray must have storage class of " + << "StorageBuffer or Uniform."; + } + } + } + } + + // WebGPU specific validation rules for OpTypeRuntimeArray + if (spvIsWebGPUEnv(_.context()->target_env)) { + // OpTypeRuntimeArray should only ever be in an OpTypeStruct, + // so should never appear as a bare variable. + if (value_type && value_type->opcode() == SpvOpTypeRuntimeArray) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "OpVariable, '" << _.getIdName(inst->id()) + << "', is attempting to create memory for an illegal type, " + << "OpTypeRuntimeArray.\nFor WebGPU OpTypeRuntimeArray can only " + << "appear as the final member of an OpTypeStruct, thus cannot " + << "be instantiated via OpVariable"; + } + + // If an OpStruct has an OpTypeRuntimeArray somewhere within it, then it + // must have the storage class StorageBuffer and be decorated + // with Block. + if (value_type && value_type->opcode() == SpvOpTypeStruct) { + if (DoesStructContainRTA(_, value_type)) { + if (storage_class == SpvStorageClassStorageBuffer) { + if (!_.HasDecoration(value_id, SpvDecorationBlock)) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "For WebGPU, an OpTypeStruct variable containing an " + << "OpTypeRuntimeArray must be decorated with Block if it " + << "has storage class StorageBuffer."; + } + } else { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "For WebGPU, OpTypeStruct variables containing " + << "OpTypeRuntimeArray must have storage class of " + << "StorageBuffer"; + } + } + } + } + + // Cooperative matrix types can only be allocated in Function or Private + if ((storage_class != SpvStorageClassFunction && + storage_class != SpvStorageClassPrivate) && + ContainsCooperativeMatrix(_, pointee)) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Cooperative matrix types (or types containing them) can only be " + "allocated " + << "in Function or Private storage classes or as function " + "parameters"; + } + + if (_.HasCapability(SpvCapabilityShader)) { + // Don't allow variables containing 16-bit elements without the appropriate + // capabilities. + if ((!_.HasCapability(SpvCapabilityInt16) && + _.ContainsSizedIntOrFloatType(value_id, SpvOpTypeInt, 16)) || + (!_.HasCapability(SpvCapabilityFloat16) && + _.ContainsSizedIntOrFloatType(value_id, SpvOpTypeFloat, 16))) { + auto underlying_type = value_type; + while (underlying_type->opcode() == SpvOpTypePointer) { + storage_class = underlying_type->GetOperandAs(1u); + underlying_type = + _.FindDef(underlying_type->GetOperandAs(2u)); + } + bool storage_class_ok = true; + std::string sc_name = _.grammar().lookupOperandName( + SPV_OPERAND_TYPE_STORAGE_CLASS, storage_class); + switch (storage_class) { + case SpvStorageClassStorageBuffer: + case SpvStorageClassPhysicalStorageBufferEXT: + if (!_.HasCapability(SpvCapabilityStorageBuffer16BitAccess)) { + storage_class_ok = false; + } + break; + case SpvStorageClassUniform: + if (!_.HasCapability( + SpvCapabilityUniformAndStorageBuffer16BitAccess)) { + if (underlying_type->opcode() == SpvOpTypeArray || + underlying_type->opcode() == SpvOpTypeRuntimeArray) { + underlying_type = + _.FindDef(underlying_type->GetOperandAs(1u)); + } + if (!_.HasCapability(SpvCapabilityStorageBuffer16BitAccess) || + !_.HasDecoration(underlying_type->id(), + SpvDecorationBufferBlock)) { + storage_class_ok = false; + } + } + break; + case SpvStorageClassPushConstant: + if (!_.HasCapability(SpvCapabilityStoragePushConstant16)) { + storage_class_ok = false; + } + break; + case SpvStorageClassInput: + case SpvStorageClassOutput: + if (!_.HasCapability(SpvCapabilityStorageInputOutput16)) { + storage_class_ok = false; + } + break; + default: + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Cannot allocate a variable containing a 16-bit type in " + << sc_name << " storage class"; + } + if (!storage_class_ok) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Allocating a variable containing a 16-bit element in " + << sc_name << " storage class requires an additional capability"; + } + } + // Don't allow variables containing 8-bit elements without the appropriate + // capabilities. + if (!_.HasCapability(SpvCapabilityInt8) && + _.ContainsSizedIntOrFloatType(value_id, SpvOpTypeInt, 8)) { + auto underlying_type = value_type; + while (underlying_type->opcode() == SpvOpTypePointer) { + storage_class = underlying_type->GetOperandAs(1u); + underlying_type = + _.FindDef(underlying_type->GetOperandAs(2u)); + } + bool storage_class_ok = true; + std::string sc_name = _.grammar().lookupOperandName( + SPV_OPERAND_TYPE_STORAGE_CLASS, storage_class); + switch (storage_class) { + case SpvStorageClassStorageBuffer: + case SpvStorageClassPhysicalStorageBufferEXT: + if (!_.HasCapability(SpvCapabilityStorageBuffer8BitAccess)) { + storage_class_ok = false; + } + break; + case SpvStorageClassUniform: + if (!_.HasCapability( + SpvCapabilityUniformAndStorageBuffer8BitAccess)) { + if (underlying_type->opcode() == SpvOpTypeArray || + underlying_type->opcode() == SpvOpTypeRuntimeArray) { + underlying_type = + _.FindDef(underlying_type->GetOperandAs(1u)); + } + if (!_.HasCapability(SpvCapabilityStorageBuffer8BitAccess) || + !_.HasDecoration(underlying_type->id(), + SpvDecorationBufferBlock)) { + storage_class_ok = false; + } + } + break; + case SpvStorageClassPushConstant: + if (!_.HasCapability(SpvCapabilityStoragePushConstant8)) { + storage_class_ok = false; + } + break; + default: + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Cannot allocate a variable containing a 8-bit type in " + << sc_name << " storage class"; + } + if (!storage_class_ok) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Allocating a variable containing a 8-bit element in " + << sc_name << " storage class requires an additional capability"; + } + } + } + + return SPV_SUCCESS; +} + +spv_result_t ValidateLoad(ValidationState_t& _, const Instruction* inst) { + const auto result_type = _.FindDef(inst->type_id()); if (!result_type) { - return _.diag(SPV_ERROR_INVALID_ID, &inst) - << "OpLoad Result Type '" << _.getIdName(inst.type_id()) + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "OpLoad Result Type '" << _.getIdName(inst->type_id()) << "' is not defined."; } @@ -180,7 +871,7 @@ spv_result_t ValidateLoad(ValidationState_t& _, const Instruction& inst) { _.features().variable_pointers || _.features().variable_pointers_storage_buffer; const auto pointer_index = 2; - const auto pointer_id = inst.GetOperandAs(pointer_index); + const auto pointer_id = inst->GetOperandAs(pointer_index); const auto pointer = _.FindDef(pointer_id); if (!pointer || ((_.addressing_model() == SpvAddressingModelLogical) && @@ -188,35 +879,49 @@ spv_result_t ValidateLoad(ValidationState_t& _, const Instruction& inst) { !spvOpcodeReturnsLogicalPointer(pointer->opcode())) || (uses_variable_pointers && !spvOpcodeReturnsLogicalVariablePointer(pointer->opcode()))))) { - return _.diag(SPV_ERROR_INVALID_ID, &inst) + return _.diag(SPV_ERROR_INVALID_ID, inst) << "OpLoad Pointer '" << _.getIdName(pointer_id) << "' is not a logical pointer."; } const auto pointer_type = _.FindDef(pointer->type_id()); if (!pointer_type || pointer_type->opcode() != SpvOpTypePointer) { - return _.diag(SPV_ERROR_INVALID_ID, &inst) + return _.diag(SPV_ERROR_INVALID_ID, inst) << "OpLoad type for pointer '" << _.getIdName(pointer_id) << "' is not a pointer type."; } const auto pointee_type = _.FindDef(pointer_type->GetOperandAs(2)); if (!pointee_type || result_type->id() != pointee_type->id()) { - return _.diag(SPV_ERROR_INVALID_ID, &inst) - << "OpLoad Result Type '" << _.getIdName(inst.type_id()) + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "OpLoad Result Type '" << _.getIdName(inst->type_id()) << "' does not match Pointer '" << _.getIdName(pointer->id()) << "'s type."; } + if (auto error = CheckMemoryAccess(_, inst, 3)) return error; + + if (_.HasCapability(SpvCapabilityShader) && + _.ContainsLimitedUseIntOrFloatType(inst->type_id()) && + result_type->opcode() != SpvOpTypePointer) { + if (result_type->opcode() != SpvOpTypeInt && + result_type->opcode() != SpvOpTypeFloat && + result_type->opcode() != SpvOpTypeVector && + result_type->opcode() != SpvOpTypeMatrix) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "8- or 16-bit loads must be a scalar, vector or matrix type"; + } + } + return SPV_SUCCESS; } -spv_result_t ValidateStore(ValidationState_t& _, const Instruction& inst) { +spv_result_t ValidateStore(ValidationState_t& _, const Instruction* inst) { const bool uses_variable_pointer = _.features().variable_pointers || _.features().variable_pointers_storage_buffer; const auto pointer_index = 0; - const auto pointer_id = inst.GetOperandAs(pointer_index); + const auto pointer_id = inst->GetOperandAs(pointer_index); const auto pointer = _.FindDef(pointer_id); if (!pointer || (_.addressing_model() == SpvAddressingModelLogical && @@ -224,20 +929,20 @@ spv_result_t ValidateStore(ValidationState_t& _, const Instruction& inst) { !spvOpcodeReturnsLogicalPointer(pointer->opcode())) || (uses_variable_pointer && !spvOpcodeReturnsLogicalVariablePointer(pointer->opcode()))))) { - return _.diag(SPV_ERROR_INVALID_ID, &inst) + return _.diag(SPV_ERROR_INVALID_ID, inst) << "OpStore Pointer '" << _.getIdName(pointer_id) << "' is not a logical pointer."; } const auto pointer_type = _.FindDef(pointer->type_id()); if (!pointer_type || pointer_type->opcode() != SpvOpTypePointer) { - return _.diag(SPV_ERROR_INVALID_ID, &inst) + return _.diag(SPV_ERROR_INVALID_ID, inst) << "OpStore type for pointer '" << _.getIdName(pointer_id) << "' is not a pointer type."; } const auto type_id = pointer_type->GetOperandAs(2); const auto type = _.FindDef(type_id); if (!type || SpvOpTypeVoid == type->opcode()) { - return _.diag(SPV_ERROR_INVALID_ID, &inst) + return _.diag(SPV_ERROR_INVALID_ID, inst) << "OpStore Pointer '" << _.getIdName(pointer_id) << "'s type is void."; } @@ -247,7 +952,7 @@ spv_result_t ValidateStore(ValidationState_t& _, const Instruction& inst) { uint32_t data_type; uint32_t storage_class; if (!_.GetPointerTypeInfo(pointer_type->id(), &data_type, &storage_class)) { - return _.diag(SPV_ERROR_INVALID_ID, &inst) + return _.diag(SPV_ERROR_INVALID_ID, inst) << "OpStore Pointer '" << _.getIdName(pointer_id) << "' is not pointer type"; } @@ -255,23 +960,42 @@ spv_result_t ValidateStore(ValidationState_t& _, const Instruction& inst) { if (storage_class == SpvStorageClassUniformConstant || storage_class == SpvStorageClassInput || storage_class == SpvStorageClassPushConstant) { - return _.diag(SPV_ERROR_INVALID_ID, &inst) + return _.diag(SPV_ERROR_INVALID_ID, inst) << "OpStore Pointer '" << _.getIdName(pointer_id) << "' storage class is read-only"; } + + if (spvIsVulkanEnv(_.context()->target_env) && + storage_class == SpvStorageClassUniform) { + auto base_ptr = _.TracePointer(pointer); + if (base_ptr->opcode() == SpvOpVariable) { + // If it's not a variable a different check should catch the problem. + auto base_type = _.FindDef(base_ptr->GetOperandAs(0)); + // Get the pointed-to type. + base_type = _.FindDef(base_type->GetOperandAs(2u)); + if (base_type->opcode() == SpvOpTypeArray || + base_type->opcode() == SpvOpTypeRuntimeArray) { + base_type = _.FindDef(base_type->GetOperandAs(1u)); + } + if (_.HasDecoration(base_type->id(), SpvDecorationBlock)) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "In the Vulkan environment, cannot store to Uniform Blocks"; + } + } + } } const auto object_index = 1; - const auto object_id = inst.GetOperandAs(object_index); + const auto object_id = inst->GetOperandAs(object_index); const auto object = _.FindDef(object_id); if (!object || !object->type_id()) { - return _.diag(SPV_ERROR_INVALID_ID, &inst) + return _.diag(SPV_ERROR_INVALID_ID, inst) << "OpStore Object '" << _.getIdName(object_id) << "' is not an object."; } const auto object_type = _.FindDef(object->type_id()); if (!object_type || SpvOpTypeVoid == object_type->opcode()) { - return _.diag(SPV_ERROR_INVALID_ID, &inst) + return _.diag(SPV_ERROR_INVALID_ID, inst) << "OpStore Object '" << _.getIdName(object_id) << "'s type is void."; } @@ -279,7 +1003,7 @@ spv_result_t ValidateStore(ValidationState_t& _, const Instruction& inst) { if (type->id() != object_type->id()) { if (!_.options()->relax_struct_store || type->opcode() != SpvOpTypeStruct || object_type->opcode() != SpvOpTypeStruct) { - return _.diag(SPV_ERROR_INVALID_ID, &inst) + return _.diag(SPV_ERROR_INVALID_ID, inst) << "OpStore Pointer '" << _.getIdName(pointer_id) << "'s type does not match Object '" << _.getIdName(object->id()) << "'s type."; @@ -287,30 +1011,90 @@ spv_result_t ValidateStore(ValidationState_t& _, const Instruction& inst) { // TODO: Check for layout compatible matricies and arrays as well. if (!AreLayoutCompatibleStructs(_, type, object_type)) { - return _.diag(SPV_ERROR_INVALID_ID, &inst) + return _.diag(SPV_ERROR_INVALID_ID, inst) << "OpStore Pointer '" << _.getIdName(pointer_id) << "'s layout does not match Object '" << _.getIdName(object->id()) << "'s layout."; } } + + if (auto error = CheckMemoryAccess(_, inst, 2)) return error; + + if (_.HasCapability(SpvCapabilityShader) && + _.ContainsLimitedUseIntOrFloatType(inst->type_id()) && + object_type->opcode() != SpvOpTypePointer) { + if (object_type->opcode() != SpvOpTypeInt && + object_type->opcode() != SpvOpTypeFloat && + object_type->opcode() != SpvOpTypeVector && + object_type->opcode() != SpvOpTypeMatrix) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "8- or 16-bit stores must be a scalar, vector or matrix type"; + } + } + return SPV_SUCCESS; } -spv_result_t ValidateCopyMemory(ValidationState_t& _, const Instruction& inst) { +spv_result_t ValidateCopyMemoryMemoryAccess(ValidationState_t& _, + const Instruction* inst) { + assert(inst->opcode() == SpvOpCopyMemory || + inst->opcode() == SpvOpCopyMemorySized); + const uint32_t first_access_index = inst->opcode() == SpvOpCopyMemory ? 2 : 3; + if (inst->operands().size() > first_access_index) { + if (auto error = CheckMemoryAccess(_, inst, first_access_index)) + return error; + + const auto first_access = inst->GetOperandAs(first_access_index); + const uint32_t second_access_index = + first_access_index + MemoryAccessNumWords(first_access); + if (inst->operands().size() > second_access_index) { + if (_.features().copy_memory_permits_two_memory_accesses) { + if (auto error = CheckMemoryAccess(_, inst, second_access_index)) + return error; + + // In the two-access form in SPIR-V 1.4 and later: + // - the first is the target (write) access and it can't have + // make-visible. + // - the second is the source (read) access and it can't have + // make-available. + if (first_access & SpvMemoryAccessMakePointerVisibleKHRMask) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Target memory access must not include " + "MakePointerVisibleKHR"; + } + const auto second_access = + inst->GetOperandAs(second_access_index); + if (second_access & SpvMemoryAccessMakePointerAvailableKHRMask) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Source memory access must not include " + "MakePointerAvailableKHR"; + } + } else { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << spvOpcodeString(static_cast(inst->opcode())) + << " with two memory access operands requires SPIR-V 1.4 or " + "later"; + } + } + } + return SPV_SUCCESS; +} + +spv_result_t ValidateCopyMemory(ValidationState_t& _, const Instruction* inst) { const auto target_index = 0; - const auto target_id = inst.GetOperandAs(target_index); + const auto target_id = inst->GetOperandAs(target_index); const auto target = _.FindDef(target_id); if (!target) { - return _.diag(SPV_ERROR_INVALID_ID, &inst) + return _.diag(SPV_ERROR_INVALID_ID, inst) << "Target operand '" << _.getIdName(target_id) << "' is not defined."; } const auto source_index = 1; - const auto source_id = inst.GetOperandAs(source_index); + const auto source_id = inst->GetOperandAs(source_index); const auto source = _.FindDef(source_id); if (!source) { - return _.diag(SPV_ERROR_INVALID_ID, &inst) + return _.diag(SPV_ERROR_INVALID_ID, inst) << "Source operand '" << _.getIdName(source_id) << "' is not defined."; } @@ -318,7 +1102,7 @@ spv_result_t ValidateCopyMemory(ValidationState_t& _, const Instruction& inst) { const auto target_pointer_type = _.FindDef(target->type_id()); if (!target_pointer_type || target_pointer_type->opcode() != SpvOpTypePointer) { - return _.diag(SPV_ERROR_INVALID_ID, &inst) + return _.diag(SPV_ERROR_INVALID_ID, inst) << "Target operand '" << _.getIdName(target_id) << "' is not a pointer."; } @@ -326,16 +1110,16 @@ spv_result_t ValidateCopyMemory(ValidationState_t& _, const Instruction& inst) { const auto source_pointer_type = _.FindDef(source->type_id()); if (!source_pointer_type || source_pointer_type->opcode() != SpvOpTypePointer) { - return _.diag(SPV_ERROR_INVALID_ID, &inst) + return _.diag(SPV_ERROR_INVALID_ID, inst) << "Source operand '" << _.getIdName(source_id) << "' is not a pointer."; } - if (inst.opcode() == SpvOpCopyMemory) { + if (inst->opcode() == SpvOpCopyMemory) { const auto target_type = _.FindDef(target_pointer_type->GetOperandAs(2)); if (!target_type || target_type->opcode() == SpvOpTypeVoid) { - return _.diag(SPV_ERROR_INVALID_ID, &inst) + return _.diag(SPV_ERROR_INVALID_ID, inst) << "Target operand '" << _.getIdName(target_id) << "' cannot be a void pointer."; } @@ -343,29 +1127,31 @@ spv_result_t ValidateCopyMemory(ValidationState_t& _, const Instruction& inst) { const auto source_type = _.FindDef(source_pointer_type->GetOperandAs(2)); if (!source_type || source_type->opcode() == SpvOpTypeVoid) { - return _.diag(SPV_ERROR_INVALID_ID, &inst) + return _.diag(SPV_ERROR_INVALID_ID, inst) << "Source operand '" << _.getIdName(source_id) << "' cannot be a void pointer."; } if (target_type->id() != source_type->id()) { - return _.diag(SPV_ERROR_INVALID_ID, &inst) + return _.diag(SPV_ERROR_INVALID_ID, inst) << "Target '" << _.getIdName(source_id) << "'s type does not match Source '" << _.getIdName(source_type->id()) << "'s type."; } + + if (auto error = CheckMemoryAccess(_, inst, 2)) return error; } else { - const auto size_id = inst.GetOperandAs(2); + const auto size_id = inst->GetOperandAs(2); const auto size = _.FindDef(size_id); if (!size) { - return _.diag(SPV_ERROR_INVALID_ID, &inst) + return _.diag(SPV_ERROR_INVALID_ID, inst) << "Size operand '" << _.getIdName(size_id) << "' is not defined."; } const auto size_type = _.FindDef(size->type_id()); if (!_.IsIntScalarType(size_type->id())) { - return _.diag(SPV_ERROR_INVALID_ID, &inst) + return _.diag(SPV_ERROR_INVALID_ID, inst) << "Size operand '" << _.getIdName(size_id) << "' must be a scalar integer type."; } @@ -373,13 +1159,13 @@ spv_result_t ValidateCopyMemory(ValidationState_t& _, const Instruction& inst) { bool is_zero = true; switch (size->opcode()) { case SpvOpConstantNull: - return _.diag(SPV_ERROR_INVALID_ID, &inst) + return _.diag(SPV_ERROR_INVALID_ID, inst) << "Size operand '" << _.getIdName(size_id) << "' cannot be a constant zero."; case SpvOpConstant: if (size_type->word(3) == 1 && size->word(size->words().size() - 1) & 0x80000000) { - return _.diag(SPV_ERROR_INVALID_ID, &inst) + return _.diag(SPV_ERROR_INVALID_ID, inst) << "Size operand '" << _.getIdName(size_id) << "' cannot have the sign bit set to 1."; } @@ -387,7 +1173,7 @@ spv_result_t ValidateCopyMemory(ValidationState_t& _, const Instruction& inst) { is_zero &= (size->word(i) == 0); } if (is_zero) { - return _.diag(SPV_ERROR_INVALID_ID, &inst) + return _.diag(SPV_ERROR_INVALID_ID, inst) << "Size operand '" << _.getIdName(size_id) << "' cannot be a constant zero."; } @@ -396,21 +1182,36 @@ spv_result_t ValidateCopyMemory(ValidationState_t& _, const Instruction& inst) { // Cannot infer any other opcodes. break; } + + if (auto error = CheckMemoryAccess(_, inst, 3)) return error; } + if (auto error = ValidateCopyMemoryMemoryAccess(_, inst)) return error; + + // Get past the pointers to avoid checking a pointer copy. + auto sub_type = _.FindDef(target_pointer_type->GetOperandAs(2)); + while (sub_type->opcode() == SpvOpTypePointer) { + sub_type = _.FindDef(sub_type->GetOperandAs(2)); + } + if (_.HasCapability(SpvCapabilityShader) && + _.ContainsLimitedUseIntOrFloatType(sub_type->id())) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Cannot copy memory of objects containing 8- or 16-bit types"; + } + return SPV_SUCCESS; } spv_result_t ValidateAccessChain(ValidationState_t& _, - const Instruction& inst) { + const Instruction* inst) { std::string instr_name = - "Op" + std::string(spvOpcodeString(static_cast(inst.opcode()))); + "Op" + std::string(spvOpcodeString(static_cast(inst->opcode()))); // The result type must be OpTypePointer. - auto result_type = _.FindDef(inst.type_id()); + auto result_type = _.FindDef(inst->type_id()); if (SpvOpTypePointer != result_type->opcode()) { - return _.diag(SPV_ERROR_INVALID_ID, &inst) + return _.diag(SPV_ERROR_INVALID_ID, inst) << "The Result Type of " << instr_name << " '" - << _.getIdName(inst.id()) << "' must be OpTypePointer. Found Op" + << _.getIdName(inst->id()) << "' must be OpTypePointer. Found Op" << spvOpcodeString(static_cast(result_type->opcode())) << "."; } @@ -421,11 +1222,11 @@ spv_result_t ValidateAccessChain(ValidationState_t& _, // Base must be a pointer, pointing to the base of a composite object. const auto base_index = 2; - const auto base_id = inst.GetOperandAs(base_index); + const auto base_id = inst->GetOperandAs(base_index); const auto base = _.FindDef(base_id); const auto base_type = _.FindDef(base->type_id()); if (!base_type || SpvOpTypePointer != base_type->opcode()) { - return _.diag(SPV_ERROR_INVALID_ID, &inst) + return _.diag(SPV_ERROR_INVALID_ID, inst) << "The Base '" << _.getIdName(base_id) << "' in " << instr_name << " instruction must be a pointer."; } @@ -435,7 +1236,7 @@ spv_result_t ValidateAccessChain(ValidationState_t& _, auto result_type_storage_class = result_type->word(2); auto base_type_storage_class = base_type->word(2); if (result_type_storage_class != base_type_storage_class) { - return _.diag(SPV_ERROR_INVALID_ID, &inst) + return _.diag(SPV_ERROR_INVALID_ID, inst) << "The result pointer storage class and base " "pointer storage class in " << instr_name << " do not match."; @@ -447,9 +1248,9 @@ spv_result_t ValidateAccessChain(ValidationState_t& _, // Check Universal Limit (SPIR-V Spec. Section 2.17). // The number of indexes passed to OpAccessChain may not exceed 255 // The instruction includes 4 words + N words (for N indexes) - size_t num_indexes = inst.words().size() - 4; - if (inst.opcode() == SpvOpPtrAccessChain || - inst.opcode() == SpvOpInBoundsPtrAccessChain) { + size_t num_indexes = inst->words().size() - 4; + if (inst->opcode() == SpvOpPtrAccessChain || + inst->opcode() == SpvOpInBoundsPtrAccessChain) { // In pointer access chains, the element operand is required, but not // counted as an index. --num_indexes; @@ -457,7 +1258,7 @@ spv_result_t ValidateAccessChain(ValidationState_t& _, const size_t num_indexes_limit = _.options()->universal_limits_.max_access_chain_indexes; if (num_indexes > num_indexes_limit) { - return _.diag(SPV_ERROR_INVALID_ID, &inst) + return _.diag(SPV_ERROR_INVALID_ID, inst) << "The number of indexes in " << instr_name << " may not exceed " << num_indexes_limit << ". Found " << num_indexes << " indexes."; } @@ -469,28 +1270,29 @@ spv_result_t ValidateAccessChain(ValidationState_t& _, // on. Once any non-composite type is reached, there must be no remaining // (unused) indexes. auto starting_index = 4; - if (inst.opcode() == SpvOpPtrAccessChain || - inst.opcode() == SpvOpInBoundsPtrAccessChain) { + if (inst->opcode() == SpvOpPtrAccessChain || + inst->opcode() == SpvOpInBoundsPtrAccessChain) { ++starting_index; } - for (size_t i = starting_index; i < inst.words().size(); ++i) { - const uint32_t cur_word = inst.words()[i]; + for (size_t i = starting_index; i < inst->words().size(); ++i) { + const uint32_t cur_word = inst->words()[i]; // Earlier ID checks ensure that cur_word definition exists. auto cur_word_instr = _.FindDef(cur_word); // The index must be a scalar integer type (See OpAccessChain in the Spec.) auto index_type = _.FindDef(cur_word_instr->type_id()); if (!index_type || SpvOpTypeInt != index_type->opcode()) { - return _.diag(SPV_ERROR_INVALID_ID, &inst) + return _.diag(SPV_ERROR_INVALID_ID, inst) << "Indexes passed to " << instr_name << " must be of type integer."; } switch (type_pointee->opcode()) { case SpvOpTypeMatrix: case SpvOpTypeVector: + case SpvOpTypeCooperativeMatrixNV: case SpvOpTypeArray: case SpvOpTypeRuntimeArray: { - // In OpTypeMatrix, OpTypeVector, OpTypeArray, and OpTypeRuntimeArray, - // word 2 is the Element Type. + // In OpTypeMatrix, OpTypeVector, SpvOpTypeCooperativeMatrixNV, + // OpTypeArray, and OpTypeRuntimeArray, word 2 is the Element Type. type_pointee = _.FindDef(type_pointee->word(2)); break; } @@ -539,7 +1341,7 @@ spv_result_t ValidateAccessChain(ValidationState_t& _, // At this point, we have fully walked down from the base using the indeces. // The type being pointed to should be the same as the result type. if (type_pointee->id() != result_type_pointee->id()) { - return _.diag(SPV_ERROR_INVALID_ID, &inst) + return _.diag(SPV_ERROR_INVALID_ID, inst) << instr_name << " result type (Op" << spvOpcodeString(static_cast(result_type_pointee->opcode())) << ") does not match the type that results from indexing into the " @@ -552,32 +1354,304 @@ spv_result_t ValidateAccessChain(ValidationState_t& _, return SPV_SUCCESS; } +spv_result_t ValidatePtrAccessChain(ValidationState_t& _, + const Instruction* inst) { + if (_.addressing_model() == SpvAddressingModelLogical) { + if (!_.features().variable_pointers && + !_.features().variable_pointers_storage_buffer) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Generating variable pointers requires capability " + << "VariablePointers or VariablePointersStorageBuffer"; + } + } + return ValidateAccessChain(_, inst); +} + +spv_result_t ValidateArrayLength(ValidationState_t& state, + const Instruction* inst) { + std::string instr_name = + "Op" + std::string(spvOpcodeString(static_cast(inst->opcode()))); + + // Result type must be a 32-bit unsigned int. + auto result_type = state.FindDef(inst->type_id()); + if (result_type->opcode() != SpvOpTypeInt || + result_type->GetOperandAs(1) != 32 || + result_type->GetOperandAs(2) != 0) { + return state.diag(SPV_ERROR_INVALID_ID, inst) + << "The Result Type of " << instr_name << " '" + << state.getIdName(inst->id()) + << "' must be OpTypeInt with width 32 and signedness 0."; + } + + // The structure that is passed in must be an pointer to a structure, whose + // last element is a runtime array. + auto pointer = state.FindDef(inst->GetOperandAs(2)); + auto pointer_type = state.FindDef(pointer->type_id()); + if (pointer_type->opcode() != SpvOpTypePointer) { + return state.diag(SPV_ERROR_INVALID_ID, inst) + << "The Struture's type in " << instr_name << " '" + << state.getIdName(inst->id()) + << "' must be a pointer to an OpTypeStruct."; + } + + auto structure_type = state.FindDef(pointer_type->GetOperandAs(2)); + if (structure_type->opcode() != SpvOpTypeStruct) { + return state.diag(SPV_ERROR_INVALID_ID, inst) + << "The Struture's type in " << instr_name << " '" + << state.getIdName(inst->id()) + << "' must be a pointer to an OpTypeStruct."; + } + + auto num_of_members = structure_type->operands().size() - 1; + auto last_member = + state.FindDef(structure_type->GetOperandAs(num_of_members)); + if (last_member->opcode() != SpvOpTypeRuntimeArray) { + return state.diag(SPV_ERROR_INVALID_ID, inst) + << "The Struture's last member in " << instr_name << " '" + << state.getIdName(inst->id()) << "' must be an OpTypeRuntimeArray."; + } + + // The array member must the the index of the last element (the run time + // array). + if (inst->GetOperandAs(3) != num_of_members - 1) { + return state.diag(SPV_ERROR_INVALID_ID, inst) + << "The array member in " << instr_name << " '" + << state.getIdName(inst->id()) + << "' must be an the last member of the struct."; + } + return SPV_SUCCESS; +} + +spv_result_t ValidateCooperativeMatrixLengthNV(ValidationState_t& state, + const Instruction* inst) { + std::string instr_name = + "Op" + std::string(spvOpcodeString(static_cast(inst->opcode()))); + + // Result type must be a 32-bit unsigned int. + auto result_type = state.FindDef(inst->type_id()); + if (result_type->opcode() != SpvOpTypeInt || + result_type->GetOperandAs(1) != 32 || + result_type->GetOperandAs(2) != 0) { + return state.diag(SPV_ERROR_INVALID_ID, inst) + << "The Result Type of " << instr_name << " '" + << state.getIdName(inst->id()) + << "' must be OpTypeInt with width 32 and signedness 0."; + } + + auto type_id = inst->GetOperandAs(2); + auto type = state.FindDef(type_id); + if (type->opcode() != SpvOpTypeCooperativeMatrixNV) { + return state.diag(SPV_ERROR_INVALID_ID, inst) + << "The type in " << instr_name << " '" + << state.getIdName(type_id) + << "' must be OpTypeCooperativeMatrixNV."; + } + return SPV_SUCCESS; +} + +spv_result_t ValidateCooperativeMatrixLoadStoreNV(ValidationState_t& _, + const Instruction* inst) { + uint32_t type_id; + const char* opname; + if (inst->opcode() == SpvOpCooperativeMatrixLoadNV) { + type_id = inst->type_id(); + opname = "SpvOpCooperativeMatrixLoadNV"; + } else { + // get Object operand's type + type_id = _.FindDef(inst->GetOperandAs(1))->type_id(); + opname = "SpvOpCooperativeMatrixStoreNV"; + } + + auto matrix_type = _.FindDef(type_id); + + if (matrix_type->opcode() != SpvOpTypeCooperativeMatrixNV) { + if (inst->opcode() == SpvOpCooperativeMatrixLoadNV) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "SpvOpCooperativeMatrixLoadNV Result Type '" + << _.getIdName(type_id) << "' is not a cooperative matrix type."; + } else { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "SpvOpCooperativeMatrixStoreNV Object type '" + << _.getIdName(type_id) << "' is not a cooperative matrix type."; + } + } + + const bool uses_variable_pointers = + _.features().variable_pointers || + _.features().variable_pointers_storage_buffer; + const auto pointer_index = + (inst->opcode() == SpvOpCooperativeMatrixLoadNV) ? 2u : 0u; + const auto pointer_id = inst->GetOperandAs(pointer_index); + const auto pointer = _.FindDef(pointer_id); + if (!pointer || + ((_.addressing_model() == SpvAddressingModelLogical) && + ((!uses_variable_pointers && + !spvOpcodeReturnsLogicalPointer(pointer->opcode())) || + (uses_variable_pointers && + !spvOpcodeReturnsLogicalVariablePointer(pointer->opcode()))))) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << opname << " Pointer '" << _.getIdName(pointer_id) + << "' is not a logical pointer."; + } + + const auto pointer_type_id = pointer->type_id(); + const auto pointer_type = _.FindDef(pointer_type_id); + if (!pointer_type || pointer_type->opcode() != SpvOpTypePointer) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << opname << " type for pointer '" << _.getIdName(pointer_id) + << "' is not a pointer type."; + } + + const auto storage_class_index = 1u; + const auto storage_class = + pointer_type->GetOperandAs(storage_class_index); + + if (storage_class != SpvStorageClassWorkgroup && + storage_class != SpvStorageClassStorageBuffer && + storage_class != SpvStorageClassPhysicalStorageBufferEXT) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << opname << " storage class for pointer type '" + << _.getIdName(pointer_type_id) + << "' is not Workgroup or StorageBuffer."; + } + + const auto pointee_id = pointer_type->GetOperandAs(2); + const auto pointee_type = _.FindDef(pointee_id); + if (!pointee_type || !(_.IsIntScalarOrVectorType(pointee_id) || + _.IsFloatScalarOrVectorType(pointee_id))) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << opname << " Pointer '" << _.getIdName(pointer->id()) + << "'s Type must be a scalar or vector type."; + } + + const auto stride_index = + (inst->opcode() == SpvOpCooperativeMatrixLoadNV) ? 3u : 2u; + const auto stride_id = inst->GetOperandAs(stride_index); + const auto stride = _.FindDef(stride_id); + if (!stride || !_.IsIntScalarType(stride->type_id())) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Stride operand '" << _.getIdName(stride_id) + << "' must be a scalar integer type."; + } + + const auto colmajor_index = + (inst->opcode() == SpvOpCooperativeMatrixLoadNV) ? 4u : 3u; + const auto colmajor_id = inst->GetOperandAs(colmajor_index); + const auto colmajor = _.FindDef(colmajor_id); + if (!colmajor || !_.IsBoolScalarType(colmajor->type_id()) || + !(spvOpcodeIsConstant(colmajor->opcode()) || + spvOpcodeIsSpecConstant(colmajor->opcode()))) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Column Major operand '" << _.getIdName(colmajor_id) + << "' must be a boolean constant instruction."; + } + + const auto memory_access_index = + (inst->opcode() == SpvOpCooperativeMatrixLoadNV) ? 5u : 4u; + if (inst->operands().size() > memory_access_index) { + if (auto error = CheckMemoryAccess(_, inst, memory_access_index)) + return error; + } + + return SPV_SUCCESS; +} + +spv_result_t ValidatePtrComparison(ValidationState_t& _, + const Instruction* inst) { + if (_.addressing_model() == SpvAddressingModelLogical && + !_.features().variable_pointers_storage_buffer) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Instruction cannot be used without a variable pointers " + "capability"; + } + + const auto result_type = _.FindDef(inst->type_id()); + if (inst->opcode() == SpvOpPtrDiff) { + if (!result_type || result_type->opcode() != SpvOpTypeInt) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Result Type must be an integer scalar"; + } + } else { + if (!result_type || result_type->opcode() != SpvOpTypeBool) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Result Type must be OpTypeBool"; + } + } + + const auto op1 = _.FindDef(inst->GetOperandAs(2u)); + const auto op2 = _.FindDef(inst->GetOperandAs(3u)); + if (!op1 || !op2 || op1->type_id() != op2->type_id()) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "The types of Operand 1 and Operand 2 must match"; + } + const auto op1_type = _.FindDef(op1->type_id()); + if (!op1_type || op1_type->opcode() != SpvOpTypePointer) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Operand type must be a pointer"; + } + + SpvStorageClass sc = op1_type->GetOperandAs(1u); + if (_.addressing_model() == SpvAddressingModelLogical) { + if (sc != SpvStorageClassWorkgroup && sc != SpvStorageClassStorageBuffer) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Invalid pointer storage class"; + } + + if (sc == SpvStorageClassWorkgroup && !_.features().variable_pointers) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Workgroup storage class pointer requires VariablePointers " + "capability to be specified"; + } + } else if (sc == SpvStorageClassPhysicalStorageBuffer) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Cannot use a pointer in the PhysicalStorageBuffer storage class"; + } + + return SPV_SUCCESS; +} + } // namespace -spv_result_t ValidateMemoryInstructions(ValidationState_t& _, - const Instruction* inst) { +spv_result_t MemoryPass(ValidationState_t& _, const Instruction* inst) { switch (inst->opcode()) { case SpvOpVariable: - if (auto error = ValidateVariable(_, *inst)) return error; + if (auto error = ValidateVariable(_, inst)) return error; break; case SpvOpLoad: - if (auto error = ValidateLoad(_, *inst)) return error; + if (auto error = ValidateLoad(_, inst)) return error; break; case SpvOpStore: - if (auto error = ValidateStore(_, *inst)) return error; + if (auto error = ValidateStore(_, inst)) return error; break; case SpvOpCopyMemory: case SpvOpCopyMemorySized: - if (auto error = ValidateCopyMemory(_, *inst)) return error; + if (auto error = ValidateCopyMemory(_, inst)) return error; + break; + case SpvOpPtrAccessChain: + if (auto error = ValidatePtrAccessChain(_, inst)) return error; break; case SpvOpAccessChain: case SpvOpInBoundsAccessChain: - case SpvOpPtrAccessChain: case SpvOpInBoundsPtrAccessChain: - if (auto error = ValidateAccessChain(_, *inst)) return error; + if (auto error = ValidateAccessChain(_, inst)) return error; + break; + case SpvOpArrayLength: + if (auto error = ValidateArrayLength(_, inst)) return error; + break; + case SpvOpCooperativeMatrixLoadNV: + case SpvOpCooperativeMatrixStoreNV: + if (auto error = ValidateCooperativeMatrixLoadStoreNV(_, inst)) + return error; + break; + case SpvOpCooperativeMatrixLengthNV: + if (auto error = ValidateCooperativeMatrixLengthNV(_, inst)) return error; + break; + case SpvOpPtrEqual: + case SpvOpPtrNotEqual: + case SpvOpPtrDiff: + if (auto error = ValidatePtrComparison(_, inst)) return error; break; case SpvOpImageTexelPointer: - case SpvOpArrayLength: case SpvOpGenericPtrMemSemantics: default: break; @@ -585,6 +1659,5 @@ spv_result_t ValidateMemoryInstructions(ValidationState_t& _, return SPV_SUCCESS; } - } // namespace val } // namespace spvtools diff --git a/third_party/spirv-tools/source/val/validate_memory_semantics.cpp b/third_party/spirv-tools/source/val/validate_memory_semantics.cpp new file mode 100644 index 0000000000..4c582f09f4 --- /dev/null +++ b/third_party/spirv-tools/source/val/validate_memory_semantics.cpp @@ -0,0 +1,295 @@ +// Copyright (c) 2018 Google LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/val/validate_memory_semantics.h" + +#include "source/diagnostic.h" +#include "source/spirv_target_env.h" +#include "source/util/bitutils.h" +#include "source/val/instruction.h" +#include "source/val/validation_state.h" + +namespace spvtools { +namespace val { + +spv_result_t ValidateMemorySemantics(ValidationState_t& _, + const Instruction* inst, + uint32_t operand_index) { + const SpvOp opcode = inst->opcode(); + const auto id = inst->GetOperandAs(operand_index); + bool is_int32 = false, is_const_int32 = false; + uint32_t value = 0; + std::tie(is_int32, is_const_int32, value) = _.EvalInt32IfConst(id); + + if (!is_int32) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << spvOpcodeString(opcode) + << ": expected Memory Semantics to be a 32-bit int"; + } + + if (!is_const_int32) { + if (_.HasCapability(SpvCapabilityShader) && + !_.HasCapability(SpvCapabilityCooperativeMatrixNV)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Memory Semantics ids must be OpConstant when Shader " + "capability is present"; + } + + if (_.HasCapability(SpvCapabilityShader) && + _.HasCapability(SpvCapabilityCooperativeMatrixNV) && + !spvOpcodeIsConstant(_.GetIdOpcode(id))) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Memory Semantics must be a constant instruction when " + "CooperativeMatrixNV capability is present"; + } + return SPV_SUCCESS; + } + + if (spvIsWebGPUEnv(_.context()->target_env)) { + uint32_t valid_bits; + switch (inst->opcode()) { + case SpvOpControlBarrier: + if (!(value & SpvMemorySemanticsAcquireReleaseMask)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "For WebGPU, AcquireRelease must be set for Memory " + "Semantics of OpControlBarrier."; + } + + if (!(value & SpvMemorySemanticsWorkgroupMemoryMask)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "For WebGPU, WorkgroupMemory must be set for Memory " + "Semantics of OpControlBarrier."; + } + + valid_bits = SpvMemorySemanticsAcquireReleaseMask | + SpvMemorySemanticsWorkgroupMemoryMask; + if (value & ~valid_bits) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "For WebGPU only WorkgroupMemory and AcquireRelease may be " + "set for Memory Semantics of OpControlBarrier."; + } + break; + case SpvOpMemoryBarrier: + if (!(value & SpvMemorySemanticsImageMemoryMask)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "For WebGPU, ImageMemory must be set for Memory Semantics " + "of OpMemoryBarrier."; + } + valid_bits = SpvMemorySemanticsImageMemoryMask; + if (value & ~valid_bits) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "For WebGPU only ImageMemory may be set for Memory " + "Semantics of OpMemoryBarrier."; + } + break; + default: + if (spvOpcodeIsAtomicOp(inst->opcode())) { + if (value != 0) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "For WebGPU Memory no bits may be set for Memory " + "Semantics of OpAtomic* instructions."; + } + } + break; + } + } + + const size_t num_memory_order_set_bits = spvtools::utils::CountSetBits( + value & (SpvMemorySemanticsAcquireMask | SpvMemorySemanticsReleaseMask | + SpvMemorySemanticsAcquireReleaseMask | + SpvMemorySemanticsSequentiallyConsistentMask)); + + if (num_memory_order_set_bits > 1) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << spvOpcodeString(opcode) + << ": Memory Semantics can have at most one of the following " + "bits " + "set: Acquire, Release, AcquireRelease or " + "SequentiallyConsistent"; + } + + if (_.memory_model() == SpvMemoryModelVulkanKHR && + value & SpvMemorySemanticsSequentiallyConsistentMask) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "SequentiallyConsistent memory " + "semantics cannot be used with " + "the VulkanKHR memory model."; + } + + if (value & SpvMemorySemanticsMakeAvailableKHRMask && + !_.HasCapability(SpvCapabilityVulkanMemoryModelKHR)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << spvOpcodeString(opcode) + << ": Memory Semantics MakeAvailableKHR requires capability " + << "VulkanMemoryModelKHR"; + } + + if (value & SpvMemorySemanticsMakeVisibleKHRMask && + !_.HasCapability(SpvCapabilityVulkanMemoryModelKHR)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << spvOpcodeString(opcode) + << ": Memory Semantics MakeVisibleKHR requires capability " + << "VulkanMemoryModelKHR"; + } + + if (value & SpvMemorySemanticsOutputMemoryKHRMask && + !_.HasCapability(SpvCapabilityVulkanMemoryModelKHR)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << spvOpcodeString(opcode) + << ": Memory Semantics OutputMemoryKHR requires capability " + << "VulkanMemoryModelKHR"; + } + + if (value & SpvMemorySemanticsVolatileMask) { + if (!_.HasCapability(SpvCapabilityVulkanMemoryModelKHR)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << spvOpcodeString(opcode) + << ": Memory Semantics Volatile requires capability " + "VulkanMemoryModelKHR"; + } + + if (!spvOpcodeIsAtomicOp(inst->opcode())) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Memory Semantics Volatile can only be used with atomic " + "instructions"; + } + } + + if (value & SpvMemorySemanticsUniformMemoryMask && + !_.HasCapability(SpvCapabilityShader)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << spvOpcodeString(opcode) + << ": Memory Semantics UniformMemory requires capability Shader"; + } + + // Checking for SpvCapabilityAtomicStorage is intentionally not done here. See + // https://github.com/KhronosGroup/glslang/issues/1618 for the reasoning why. + + if (value & (SpvMemorySemanticsMakeAvailableKHRMask | + SpvMemorySemanticsMakeVisibleKHRMask)) { + const bool includes_storage_class = + value & (SpvMemorySemanticsUniformMemoryMask | + SpvMemorySemanticsSubgroupMemoryMask | + SpvMemorySemanticsWorkgroupMemoryMask | + SpvMemorySemanticsCrossWorkgroupMemoryMask | + SpvMemorySemanticsAtomicCounterMemoryMask | + SpvMemorySemanticsImageMemoryMask | + SpvMemorySemanticsOutputMemoryKHRMask); + + if (!includes_storage_class) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << spvOpcodeString(opcode) + << ": expected Memory Semantics to include a storage class"; + } + } + + if (value & SpvMemorySemanticsMakeVisibleKHRMask && + !(value & (SpvMemorySemanticsAcquireMask | + SpvMemorySemanticsAcquireReleaseMask))) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << spvOpcodeString(opcode) + << ": MakeVisibleKHR Memory Semantics also requires either Acquire " + "or AcquireRelease Memory Semantics"; + } + + if (value & SpvMemorySemanticsMakeAvailableKHRMask && + !(value & (SpvMemorySemanticsReleaseMask | + SpvMemorySemanticsAcquireReleaseMask))) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << spvOpcodeString(opcode) + << ": MakeAvailableKHR Memory Semantics also requires either " + "Release or AcquireRelease Memory Semantics"; + } + + if (spvIsVulkanEnv(_.context()->target_env)) { + const bool includes_storage_class = + value & (SpvMemorySemanticsUniformMemoryMask | + SpvMemorySemanticsWorkgroupMemoryMask | + SpvMemorySemanticsImageMemoryMask | + SpvMemorySemanticsOutputMemoryKHRMask); + + if (opcode == SpvOpMemoryBarrier && !num_memory_order_set_bits) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << spvOpcodeString(opcode) + << ": Vulkan specification requires Memory Semantics to have " + "one " + "of the following bits set: Acquire, Release, " + "AcquireRelease " + "or SequentiallyConsistent"; + } + + if (opcode == SpvOpMemoryBarrier && !includes_storage_class) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << spvOpcodeString(opcode) + << ": expected Memory Semantics to include a Vulkan-supported " + "storage class"; + } + +#if 0 + // TODO(atgoo@github.com): this check fails Vulkan CTS, reenable once fixed. + if (opcode == SpvOpControlBarrier && value && !includes_storage_class) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << spvOpcodeString(opcode) + << ": expected Memory Semantics to include a Vulkan-supported " + "storage class if Memory Semantics is not None"; + } +#endif + } + + if (opcode == SpvOpAtomicFlagClear && + (value & SpvMemorySemanticsAcquireMask || + value & SpvMemorySemanticsAcquireReleaseMask)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Memory Semantics Acquire and AcquireRelease cannot be used " + "with " + << spvOpcodeString(opcode); + } + + if (opcode == SpvOpAtomicCompareExchange && operand_index == 5 && + (value & SpvMemorySemanticsReleaseMask || + value & SpvMemorySemanticsAcquireReleaseMask)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << spvOpcodeString(opcode) + << ": Memory Semantics Release and AcquireRelease cannot be " + "used " + "for operand Unequal"; + } + + if (spvIsVulkanEnv(_.context()->target_env)) { + if (opcode == SpvOpAtomicLoad && + (value & SpvMemorySemanticsReleaseMask || + value & SpvMemorySemanticsAcquireReleaseMask || + value & SpvMemorySemanticsSequentiallyConsistentMask)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Vulkan spec disallows OpAtomicLoad with Memory Semantics " + "Release, AcquireRelease and SequentiallyConsistent"; + } + + if (opcode == SpvOpAtomicStore && + (value & SpvMemorySemanticsAcquireMask || + value & SpvMemorySemanticsAcquireReleaseMask || + value & SpvMemorySemanticsSequentiallyConsistentMask)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Vulkan spec disallows OpAtomicStore with Memory Semantics " + "Acquire, AcquireRelease and SequentiallyConsistent"; + } + } + + // TODO(atgoo@github.com) Add checks for OpenCL and OpenGL environments. + + return SPV_SUCCESS; +} + +} // namespace val +} // namespace spvtools diff --git a/third_party/spirv-tools/source/val/validate_memory_semantics.h b/third_party/spirv-tools/source/val/validate_memory_semantics.h new file mode 100644 index 0000000000..72a3e10048 --- /dev/null +++ b/third_party/spirv-tools/source/val/validate_memory_semantics.h @@ -0,0 +1,28 @@ +// Copyright (c) 2018 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. + +// Validates correctness of memory semantics for SPIR-V instructions. + +#include "source/opcode.h" +#include "source/val/validate.h" + +namespace spvtools { +namespace val { + +spv_result_t ValidateMemorySemantics(ValidationState_t& _, + const Instruction* inst, + uint32_t operand_index); + +} // namespace val +} // namespace spvtools diff --git a/third_party/spirv-tools/source/val/validate_misc.cpp b/third_party/spirv-tools/source/val/validate_misc.cpp new file mode 100644 index 0000000000..f0deedfad6 --- /dev/null +++ b/third_party/spirv-tools/source/val/validate_misc.cpp @@ -0,0 +1,163 @@ +// Copyright (c) 2018 Google LLC. +// Copyright (c) 2019 NVIDIA Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/val/validate.h" + +#include "source/opcode.h" +#include "source/spirv_target_env.h" +#include "source/val/instruction.h" +#include "source/val/validate_scopes.h" +#include "source/val/validation_state.h" + +namespace spvtools { +namespace val { +namespace { + +spv_result_t ValidateUndef(ValidationState_t& _, const Instruction* inst) { + if (_.HasCapability(SpvCapabilityShader) && + _.ContainsLimitedUseIntOrFloatType(inst->type_id()) && + !_.IsPointerType(inst->type_id())) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Cannot create undefined values with 8- or 16-bit types"; + } + + if (spvIsWebGPUEnv(_.context()->target_env)) { + return _.diag(SPV_ERROR_INVALID_BINARY, inst) << "OpUndef is disallowed"; + } + + return SPV_SUCCESS; +} + +spv_result_t ValidateShaderClock(ValidationState_t& _, + const Instruction* inst) { + const uint32_t scope = inst->GetOperandAs(2); + if (auto error = ValidateScope(_, inst, scope)) { + return error; + } + + bool is_int32 = false, is_const_int32 = false; + uint32_t value = 0; + std::tie(is_int32, is_const_int32, value) = _.EvalInt32IfConst(scope); + if (is_const_int32 && value != SpvScopeSubgroup && value != SpvScopeDevice) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Scope must be Subgroup or Device"; + } + + // Result Type must be a 64 - bit unsigned integer type or + // a vector of two - components of 32 - + // bit unsigned integer type + const uint32_t result_type = inst->type_id(); + if (!(_.IsUnsignedIntScalarType(result_type) && + _.GetBitWidth(result_type) == 64) && + !(_.IsUnsignedIntVectorType(result_type) && + _.GetDimension(result_type) == 2 && _.GetBitWidth(result_type) == 32)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Expected Value to be a " + "vector of two components" + " of unsigned integer" + " or 64bit unsigned integer"; + } + + return SPV_SUCCESS; +} + +} // namespace + +spv_result_t MiscPass(ValidationState_t& _, const Instruction* inst) { + switch (inst->opcode()) { + case SpvOpUndef: + if (auto error = ValidateUndef(_, inst)) return error; + break; + default: + break; + } + switch (inst->opcode()) { + case SpvOpBeginInvocationInterlockEXT: + case SpvOpEndInvocationInterlockEXT: + _.function(inst->function()->id()) + ->RegisterExecutionModelLimitation( + SpvExecutionModelFragment, + "OpBeginInvocationInterlockEXT/OpEndInvocationInterlockEXT " + "require Fragment execution model"); + + _.function(inst->function()->id()) + ->RegisterLimitation([](const ValidationState_t& state, + const Function* entry_point, + std::string* message) { + const auto* execution_modes = + state.GetExecutionModes(entry_point->id()); + + auto find_interlock = [](const SpvExecutionMode& mode) { + switch (mode) { + case SpvExecutionModePixelInterlockOrderedEXT: + case SpvExecutionModePixelInterlockUnorderedEXT: + case SpvExecutionModeSampleInterlockOrderedEXT: + case SpvExecutionModeSampleInterlockUnorderedEXT: + case SpvExecutionModeShadingRateInterlockOrderedEXT: + case SpvExecutionModeShadingRateInterlockUnorderedEXT: + return true; + default: + return false; + } + }; + + bool found = false; + if (execution_modes) { + auto i = std::find_if(execution_modes->begin(), + execution_modes->end(), find_interlock); + found = (i != execution_modes->end()); + } + + if (!found) { + *message = + "OpBeginInvocationInterlockEXT/OpEndInvocationInterlockEXT " + "require a fragment shader interlock execution mode."; + return false; + } + return true; + }); + break; + case SpvOpDemoteToHelperInvocationEXT: + _.function(inst->function()->id()) + ->RegisterExecutionModelLimitation( + SpvExecutionModelFragment, + "OpDemoteToHelperInvocationEXT requires Fragment execution " + "model"); + break; + case SpvOpIsHelperInvocationEXT: { + const uint32_t result_type = inst->type_id(); + _.function(inst->function()->id()) + ->RegisterExecutionModelLimitation( + SpvExecutionModelFragment, + "OpIsHelperInvocationEXT requires Fragment execution model"); + if (!_.IsBoolScalarType(result_type)) + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Expected bool scalar type as Result Type: " + << spvOpcodeString(inst->opcode()); + break; + } + case SpvOpReadClockKHR: + if (auto error = ValidateShaderClock(_, inst)) { + return error; + } + break; + default: + break; + } + + return SPV_SUCCESS; +} + +} // namespace val +} // namespace spvtools diff --git a/third_party/spirv-tools/source/val/validate_mode_setting.cpp b/third_party/spirv-tools/source/val/validate_mode_setting.cpp index 60e7c0a1d1..e020f5ae6a 100644 --- a/third_party/spirv-tools/source/val/validate_mode_setting.cpp +++ b/third_party/spirv-tools/source/val/validate_mode_setting.cpp @@ -17,6 +17,7 @@ #include #include "source/opcode.h" +#include "source/spirv_target_env.h" #include "source/val/instruction.h" #include "source/val/validation_state.h" @@ -32,12 +33,11 @@ spv_result_t ValidateEntryPoint(ValidationState_t& _, const Instruction* inst) { << "OpEntryPoint Entry Point '" << _.getIdName(entry_point_id) << "' is not a function."; } - // don't check kernel function signatures + + // Only check the shader execution models const SpvExecutionModel execution_model = inst->GetOperandAs(0); if (execution_model != SpvExecutionModelKernel) { - // TODO: Check the entry point signature is void main(void), may be subject - // to change const auto entry_point_type_id = entry_point->GetOperandAs(3); const auto entry_point_type = _.FindDef(entry_point_type_id); if (!entry_point_type || 3 != entry_point_type->words().size()) { @@ -53,6 +53,191 @@ spv_result_t ValidateEntryPoint(ValidationState_t& _, const Instruction* inst) { << "OpEntryPoint Entry Point '" << _.getIdName(entry_point_id) << "'s function return type is not void."; } + + const auto* execution_modes = _.GetExecutionModes(entry_point_id); + if (_.HasCapability(SpvCapabilityShader)) { + switch (execution_model) { + case SpvExecutionModelFragment: + if (execution_modes && + execution_modes->count(SpvExecutionModeOriginUpperLeft) && + execution_modes->count(SpvExecutionModeOriginLowerLeft)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Fragment execution model entry points can only specify " + "one of OriginUpperLeft or OriginLowerLeft execution " + "modes."; + } + if (!execution_modes || + (!execution_modes->count(SpvExecutionModeOriginUpperLeft) && + !execution_modes->count(SpvExecutionModeOriginLowerLeft))) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Fragment execution model entry points require either an " + "OriginUpperLeft or OriginLowerLeft execution mode."; + } + if (execution_modes && + 1 < std::count_if(execution_modes->begin(), execution_modes->end(), + [](const SpvExecutionMode& mode) { + switch (mode) { + case SpvExecutionModeDepthGreater: + case SpvExecutionModeDepthLess: + case SpvExecutionModeDepthUnchanged: + return true; + default: + return false; + } + })) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Fragment execution model entry points can specify at most " + "one of DepthGreater, DepthLess or DepthUnchanged " + "execution modes."; + } + if (execution_modes && + 1 < std::count_if( + execution_modes->begin(), execution_modes->end(), + [](const SpvExecutionMode& mode) { + switch (mode) { + case SpvExecutionModePixelInterlockOrderedEXT: + case SpvExecutionModePixelInterlockUnorderedEXT: + case SpvExecutionModeSampleInterlockOrderedEXT: + case SpvExecutionModeSampleInterlockUnorderedEXT: + case SpvExecutionModeShadingRateInterlockOrderedEXT: + case SpvExecutionModeShadingRateInterlockUnorderedEXT: + return true; + default: + return false; + } + })) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Fragment execution model entry points can specify at most " + "one fragment shader interlock execution mode."; + } + break; + case SpvExecutionModelTessellationControl: + case SpvExecutionModelTessellationEvaluation: + if (execution_modes && + 1 < std::count_if(execution_modes->begin(), execution_modes->end(), + [](const SpvExecutionMode& mode) { + switch (mode) { + case SpvExecutionModeSpacingEqual: + case SpvExecutionModeSpacingFractionalEven: + case SpvExecutionModeSpacingFractionalOdd: + return true; + default: + return false; + } + })) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Tessellation execution model entry points can specify at " + "most one of SpacingEqual, SpacingFractionalOdd or " + "SpacingFractionalEven execution modes."; + } + if (execution_modes && + 1 < std::count_if(execution_modes->begin(), execution_modes->end(), + [](const SpvExecutionMode& mode) { + switch (mode) { + case SpvExecutionModeTriangles: + case SpvExecutionModeQuads: + case SpvExecutionModeIsolines: + return true; + default: + return false; + } + })) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Tessellation execution model entry points can specify at " + "most one of Triangles, Quads or Isolines execution modes."; + } + if (execution_modes && + 1 < std::count_if(execution_modes->begin(), execution_modes->end(), + [](const SpvExecutionMode& mode) { + switch (mode) { + case SpvExecutionModeVertexOrderCw: + case SpvExecutionModeVertexOrderCcw: + return true; + default: + return false; + } + })) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Tessellation execution model entry points can specify at " + "most one of VertexOrderCw or VertexOrderCcw execution " + "modes."; + } + break; + case SpvExecutionModelGeometry: + if (!execution_modes || + 1 != std::count_if(execution_modes->begin(), execution_modes->end(), + [](const SpvExecutionMode& mode) { + switch (mode) { + case SpvExecutionModeInputPoints: + case SpvExecutionModeInputLines: + case SpvExecutionModeInputLinesAdjacency: + case SpvExecutionModeTriangles: + case SpvExecutionModeInputTrianglesAdjacency: + return true; + default: + return false; + } + })) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Geometry execution model entry points must specify " + "exactly one of InputPoints, InputLines, " + "InputLinesAdjacency, Triangles or InputTrianglesAdjacency " + "execution modes."; + } + if (!execution_modes || + 1 != std::count_if(execution_modes->begin(), execution_modes->end(), + [](const SpvExecutionMode& mode) { + switch (mode) { + case SpvExecutionModeOutputPoints: + case SpvExecutionModeOutputLineStrip: + case SpvExecutionModeOutputTriangleStrip: + return true; + default: + return false; + } + })) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Geometry execution model entry points must specify " + "exactly one of OutputPoints, OutputLineStrip or " + "OutputTriangleStrip execution modes."; + } + break; + default: + break; + } + } + + if (spvIsVulkanEnv(_.context()->target_env)) { + switch (execution_model) { + case SpvExecutionModelGLCompute: + if (!execution_modes || + !execution_modes->count(SpvExecutionModeLocalSize)) { + bool ok = false; + for (auto& i : _.ordered_instructions()) { + if (i.opcode() == SpvOpDecorate) { + if (i.operands().size() > 2) { + if (i.GetOperandAs(1) == SpvDecorationBuiltIn && + i.GetOperandAs(2) == SpvBuiltInWorkgroupSize) { + ok = true; + break; + } + } + } + } + if (!ok) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "In the Vulkan environment, GLCompute execution model " + "entry points require either the LocalSize execution " + "mode or an object decorated with WorkgroupSize must be " + "specified."; + } + } + break; + default: + break; + } + } + return SPV_SUCCESS; } @@ -68,6 +253,273 @@ spv_result_t ValidateExecutionMode(ValidationState_t& _, << "' is not the Entry Point " "operand of an OpEntryPoint."; } + + const auto mode = inst->GetOperandAs(1); + if (inst->opcode() == SpvOpExecutionModeId) { + size_t operand_count = inst->operands().size(); + for (size_t i = 2; i < operand_count; ++i) { + const auto operand_id = inst->GetOperandAs(2); + const auto* operand_inst = _.FindDef(operand_id); + if (mode == SpvExecutionModeSubgroupsPerWorkgroupId || + mode == SpvExecutionModeLocalSizeHintId || + mode == SpvExecutionModeLocalSizeId) { + 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."; + } + } + } else if (mode == SpvExecutionModeSubgroupsPerWorkgroupId || + mode == SpvExecutionModeLocalSizeHintId || + mode == SpvExecutionModeLocalSizeId) { + 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 " + "Operands that are not id operands."; + } + + const auto* models = _.GetExecutionModels(entry_point_id); + switch (mode) { + case SpvExecutionModeInvocations: + case SpvExecutionModeInputPoints: + case SpvExecutionModeInputLines: + case SpvExecutionModeInputLinesAdjacency: + case SpvExecutionModeInputTrianglesAdjacency: + case SpvExecutionModeOutputLineStrip: + case SpvExecutionModeOutputTriangleStrip: + if (!std::all_of(models->begin(), models->end(), + [](const SpvExecutionModel& model) { + return model == SpvExecutionModelGeometry; + })) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Execution mode can only be used with the Geometry execution " + "model."; + } + break; + case SpvExecutionModeOutputPoints: + if (!std::all_of(models->begin(), models->end(), + [&_](const SpvExecutionModel& model) { + switch (model) { + case SpvExecutionModelGeometry: + return true; + case SpvExecutionModelMeshNV: + return _.HasCapability(SpvCapabilityMeshShadingNV); + default: + return false; + } + })) { + if (_.HasCapability(SpvCapabilityMeshShadingNV)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Execution mode can only be used with the Geometry or " + "MeshNV execution model."; + } else { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Execution mode can only be used with the Geometry " + "execution " + "model."; + } + } + break; + case SpvExecutionModeSpacingEqual: + case SpvExecutionModeSpacingFractionalEven: + case SpvExecutionModeSpacingFractionalOdd: + case SpvExecutionModeVertexOrderCw: + case SpvExecutionModeVertexOrderCcw: + case SpvExecutionModePointMode: + case SpvExecutionModeQuads: + case SpvExecutionModeIsolines: + if (!std::all_of( + models->begin(), models->end(), + [](const SpvExecutionModel& model) { + return (model == SpvExecutionModelTessellationControl) || + (model == SpvExecutionModelTessellationEvaluation); + })) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Execution mode can only be used with a tessellation " + "execution model."; + } + break; + case SpvExecutionModeTriangles: + if (!std::all_of(models->begin(), models->end(), + [](const SpvExecutionModel& model) { + switch (model) { + case SpvExecutionModelGeometry: + case SpvExecutionModelTessellationControl: + case SpvExecutionModelTessellationEvaluation: + return true; + default: + return false; + } + })) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Execution mode can only be used with a Geometry or " + "tessellation execution model."; + } + break; + case SpvExecutionModeOutputVertices: + if (!std::all_of(models->begin(), models->end(), + [&_](const SpvExecutionModel& model) { + switch (model) { + case SpvExecutionModelGeometry: + case SpvExecutionModelTessellationControl: + case SpvExecutionModelTessellationEvaluation: + return true; + case SpvExecutionModelMeshNV: + return _.HasCapability(SpvCapabilityMeshShadingNV); + default: + return false; + } + })) { + if (_.HasCapability(SpvCapabilityMeshShadingNV)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Execution mode can only be used with a Geometry, " + "tessellation or MeshNV execution model."; + } else { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Execution mode can only be used with a Geometry or " + "tessellation execution model."; + } + } + break; + case SpvExecutionModePixelCenterInteger: + case SpvExecutionModeOriginUpperLeft: + case SpvExecutionModeOriginLowerLeft: + case SpvExecutionModeEarlyFragmentTests: + case SpvExecutionModeDepthReplacing: + case SpvExecutionModeDepthGreater: + case SpvExecutionModeDepthLess: + case SpvExecutionModeDepthUnchanged: + case SpvExecutionModePixelInterlockOrderedEXT: + case SpvExecutionModePixelInterlockUnorderedEXT: + case SpvExecutionModeSampleInterlockOrderedEXT: + case SpvExecutionModeSampleInterlockUnorderedEXT: + case SpvExecutionModeShadingRateInterlockOrderedEXT: + case SpvExecutionModeShadingRateInterlockUnorderedEXT: + if (!std::all_of(models->begin(), models->end(), + [](const SpvExecutionModel& model) { + return model == SpvExecutionModelFragment; + })) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Execution mode can only be used with the Fragment execution " + "model."; + } + break; + case SpvExecutionModeLocalSizeHint: + case SpvExecutionModeVecTypeHint: + case SpvExecutionModeContractionOff: + case SpvExecutionModeLocalSizeHintId: + if (!std::all_of(models->begin(), models->end(), + [](const SpvExecutionModel& model) { + return model == SpvExecutionModelKernel; + })) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Execution mode can only be used with the Kernel execution " + "model."; + } + break; + case SpvExecutionModeLocalSize: + case SpvExecutionModeLocalSizeId: + if (!std::all_of(models->begin(), models->end(), + [&_](const SpvExecutionModel& model) { + switch (model) { + case SpvExecutionModelKernel: + case SpvExecutionModelGLCompute: + return true; + case SpvExecutionModelTaskNV: + case SpvExecutionModelMeshNV: + return _.HasCapability(SpvCapabilityMeshShadingNV); + default: + return false; + } + })) { + if (_.HasCapability(SpvCapabilityMeshShadingNV)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Execution mode can only be used with a Kernel, GLCompute, " + "MeshNV, or TaskNV execution model."; + } else { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Execution mode can only be used with a Kernel or " + "GLCompute " + "execution model."; + } + } + default: + break; + } + + if (spvIsVulkanEnv(_.context()->target_env)) { + if (mode == SpvExecutionModeOriginLowerLeft) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "In the Vulkan environment, the OriginLowerLeft execution mode " + "must not be used."; + } + if (mode == SpvExecutionModePixelCenterInteger) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "In the Vulkan environment, the PixelCenterInteger execution " + "mode must not be used."; + } + } + + if (spvIsWebGPUEnv(_.context()->target_env)) { + if (mode != SpvExecutionModeOriginUpperLeft && + mode != SpvExecutionModeDepthReplacing && + mode != SpvExecutionModeDepthGreater && + mode != SpvExecutionModeDepthLess && + mode != SpvExecutionModeDepthUnchanged && + mode != SpvExecutionModeLocalSize && + mode != SpvExecutionModeLocalSizeHint) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Execution mode must be one of OriginUpperLeft, " + "DepthReplacing, DepthGreater, DepthLess, DepthUnchanged, " + "LocalSize, or LocalSizeHint for WebGPU environment."; + } + } + + return SPV_SUCCESS; +} + +spv_result_t ValidateMemoryModel(ValidationState_t& _, + const Instruction* inst) { + // Already produced an error if multiple memory model instructions are + // present. + if (_.memory_model() != SpvMemoryModelVulkanKHR && + _.HasCapability(SpvCapabilityVulkanMemoryModelKHR)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "VulkanMemoryModelKHR capability must only be specified if " + "the VulkanKHR memory model is used."; + } + + if (spvIsWebGPUEnv(_.context()->target_env)) { + if (_.addressing_model() != SpvAddressingModelLogical) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Addressing model must be Logical for WebGPU environment."; + } + if (_.memory_model() != SpvMemoryModelVulkanKHR) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Memory model must be VulkanKHR for WebGPU environment."; + } + } + + if (spvIsOpenCLEnv(_.context()->target_env)) { + if ((_.addressing_model() != SpvAddressingModelPhysical32) && + (_.addressing_model() != SpvAddressingModelPhysical64)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Addressing model must be Physical32 or Physical64 " + << "in the OpenCL environment."; + } + if (_.memory_model() != SpvMemoryModelOpenCL) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Memory model must be OpenCL in the OpenCL environment."; + } + } + return SPV_SUCCESS; } @@ -79,8 +531,12 @@ spv_result_t ModeSettingPass(ValidationState_t& _, const Instruction* inst) { if (auto error = ValidateEntryPoint(_, inst)) return error; break; case SpvOpExecutionMode: + case SpvOpExecutionModeId: if (auto error = ValidateExecutionMode(_, inst)) return error; break; + case SpvOpMemoryModel: + if (auto error = ValidateMemoryModel(_, inst)) return error; + break; default: break; } diff --git a/third_party/spirv-tools/source/val/validate_non_uniform.cpp b/third_party/spirv-tools/source/val/validate_non_uniform.cpp index 89e82c6162..8dcf9743f5 100644 --- a/third_party/spirv-tools/source/val/validate_non_uniform.cpp +++ b/third_party/spirv-tools/source/val/validate_non_uniform.cpp @@ -22,44 +22,31 @@ #include "source/spirv_target_env.h" #include "source/util/bitutils.h" #include "source/val/instruction.h" +#include "source/val/validate_scopes.h" #include "source/val/validation_state.h" namespace spvtools { namespace val { namespace { -spv_result_t ValidateExecutionScope(ValidationState_t& _, - const Instruction* inst, uint32_t scope) { - SpvOp opcode = inst->opcode(); - bool is_int32 = false, is_const_int32 = false; - uint32_t value = 0; - std::tie(is_int32, is_const_int32, value) = _.EvalInt32IfConst(scope); +spv_result_t ValidateGroupNonUniformBallotBitCount(ValidationState_t& _, + const Instruction* inst) { + // Scope is already checked by ValidateExecutionScope() above. - if (!is_int32) { + const uint32_t result_type = inst->type_id(); + if (!_.IsUnsignedIntScalarType(result_type)) { return _.diag(SPV_ERROR_INVALID_DATA, inst) - << spvOpcodeString(opcode) - << ": expected Execution Scope to be a 32-bit int"; + << "Expected Result Type to be an unsigned integer type scalar."; } - if (!is_const_int32) { - return SPV_SUCCESS; + const auto value = inst->GetOperandAs(4); + const auto value_type = _.FindDef(value)->type_id(); + if (!_.IsUnsignedIntVectorType(value_type) || + _.GetDimension(value_type) != 4) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Expected Value to be a " + "vector of four components " + "of integer type scalar"; } - - if (spvIsVulkanEnv(_.context()->target_env) && - _.context()->target_env != SPV_ENV_VULKAN_1_0 && - value != SpvScopeSubgroup) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << spvOpcodeString(opcode) - << ": in Vulkan environment Execution scope is limited to " - "Subgroup"; - } - - if (value != SpvScopeSubgroup && value != SpvScopeWorkgroup) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << spvOpcodeString(opcode) - << ": Execution scope is limited to Subgroup or Workgroup"; - } - return SPV_SUCCESS; } @@ -76,6 +63,13 @@ spv_result_t NonUniformPass(ValidationState_t& _, const Instruction* inst) { } } + switch (opcode) { + case SpvOpGroupNonUniformBallotBitCount: + return ValidateGroupNonUniformBallotBitCount(_, inst); + default: + break; + } + return SPV_SUCCESS; } diff --git a/third_party/spirv-tools/source/val/validate_scopes.cpp b/third_party/spirv-tools/source/val/validate_scopes.cpp new file mode 100644 index 0000000000..320d828218 --- /dev/null +++ b/third_party/spirv-tools/source/val/validate_scopes.cpp @@ -0,0 +1,272 @@ +// Copyright (c) 2018 Google LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/val/validate_scopes.h" + +#include "source/diagnostic.h" +#include "source/spirv_target_env.h" +#include "source/val/instruction.h" +#include "source/val/validation_state.h" + +namespace spvtools { +namespace val { + +bool IsValidScope(uint32_t scope) { + // Deliberately avoid a default case so we have to update the list when the + // scopes list changes. + switch (static_cast(scope)) { + case SpvScopeCrossDevice: + case SpvScopeDevice: + case SpvScopeWorkgroup: + case SpvScopeSubgroup: + case SpvScopeInvocation: + case SpvScopeQueueFamilyKHR: + return true; + case SpvScopeMax: + break; + } + return false; +} + +spv_result_t ValidateScope(ValidationState_t& _, const Instruction* inst, + uint32_t scope) { + SpvOp opcode = inst->opcode(); + bool is_int32 = false, is_const_int32 = false; + uint32_t value = 0; + std::tie(is_int32, is_const_int32, value) = _.EvalInt32IfConst(scope); + + if (!is_int32) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << spvOpcodeString(opcode) << ": expected scope to be a 32-bit int"; + } + + if (!is_const_int32) { + if (_.HasCapability(SpvCapabilityShader) && + !_.HasCapability(SpvCapabilityCooperativeMatrixNV)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Scope ids must be OpConstant when Shader capability is " + << "present"; + } + if (_.HasCapability(SpvCapabilityShader) && + _.HasCapability(SpvCapabilityCooperativeMatrixNV) && + !spvOpcodeIsConstant(_.GetIdOpcode(scope))) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Scope ids must be constant or specialization constant when " + << "CooperativeMatrixNV capability is present"; + } + } + + if (is_const_int32 && !IsValidScope(value)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Invalid scope value:\n " << _.Disassemble(*_.FindDef(scope)); + } + + return SPV_SUCCESS; +} + +spv_result_t ValidateExecutionScope(ValidationState_t& _, + const Instruction* inst, uint32_t scope) { + SpvOp opcode = inst->opcode(); + bool is_int32 = false, is_const_int32 = false; + uint32_t value = 0; + std::tie(is_int32, is_const_int32, value) = _.EvalInt32IfConst(scope); + + if (auto error = ValidateScope(_, inst, scope)) { + return error; + } + + if (!is_const_int32) { + return SPV_SUCCESS; + } + + // Vulkan specific rules + if (spvIsVulkanEnv(_.context()->target_env)) { + // 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 != SpvScopeSubgroup) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << spvOpcodeString(opcode) + << ": in Vulkan environment Execution scope is limited to " + << "Subgroup"; + } + } + + // If OpControlBarrier is used in fragment, vertex, tessellation evaluation, + // or geometry stages, the execution Scope must be Subgroup. + if (opcode == SpvOpControlBarrier && value != SpvScopeSubgroup) { + _.function(inst->function()->id()) + ->RegisterExecutionModelLimitation([](SpvExecutionModel model, + std::string* message) { + if (model == SpvExecutionModelFragment || + model == SpvExecutionModelVertex || + model == SpvExecutionModelGeometry || + model == SpvExecutionModelTessellationEvaluation) { + if (message) { + *message = + "in Vulkan evironment, OpControlBarrier execution scope " + "must be Subgroup for Fragment, Vertex, Geometry and " + "TessellationEvaluation execution models"; + } + return false; + } + return true; + }); + } + + // Vulkan generic rules + // Scope for execution must be limited to Workgroup or Subgroup + if (value != SpvScopeWorkgroup && value != SpvScopeSubgroup) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << spvOpcodeString(opcode) + << ": in Vulkan environment Execution Scope is limited to " + << "Workgroup and Subgroup"; + } + } + + // WebGPU Specific rules + if (spvIsWebGPUEnv(_.context()->target_env)) { + if (value != SpvScopeWorkgroup) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << spvOpcodeString(opcode) + << ": in WebGPU environment Execution Scope is limited to " + << "Workgroup"; + } + } + + // TODO(atgoo@github.com) Add checks for OpenCL and OpenGL environments. + + // General SPIRV rules + // Scope for execution must be limited to Workgroup or Subgroup for + // non-uniform operations + if (spvOpcodeIsNonUniformGroupOperation(opcode) && + value != SpvScopeSubgroup && value != SpvScopeWorkgroup) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << spvOpcodeString(opcode) + << ": Execution scope is limited to Subgroup or Workgroup"; + } + + return SPV_SUCCESS; +} + +spv_result_t ValidateMemoryScope(ValidationState_t& _, const Instruction* inst, + uint32_t scope) { + const SpvOp opcode = inst->opcode(); + bool is_int32 = false, is_const_int32 = false; + uint32_t value = 0; + std::tie(is_int32, is_const_int32, value) = _.EvalInt32IfConst(scope); + + if (auto error = ValidateScope(_, inst, scope)) { + return error; + } + + if (!is_const_int32) { + return SPV_SUCCESS; + } + + if (value == SpvScopeQueueFamilyKHR) { + if (_.HasCapability(SpvCapabilityVulkanMemoryModelKHR)) { + return SPV_SUCCESS; + } else { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << spvOpcodeString(opcode) + << ": Memory Scope QueueFamilyKHR requires capability " + << "VulkanMemoryModelKHR"; + } + } + + if (value == SpvScopeDevice && + _.HasCapability(SpvCapabilityVulkanMemoryModelKHR) && + !_.HasCapability(SpvCapabilityVulkanMemoryModelDeviceScopeKHR)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Use of device scope with VulkanKHR memory model requires the " + << "VulkanMemoryModelDeviceScopeKHR capability"; + } + + // Vulkan Specific rules + if (spvIsVulkanEnv(_.context()->target_env)) { + if (value == SpvScopeCrossDevice) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << spvOpcodeString(opcode) + << ": in Vulkan environment, Memory Scope cannot be CrossDevice"; + } + // Vulkan 1.0 specifc rules + if (_.context()->target_env == SPV_ENV_VULKAN_1_0 && + value != SpvScopeDevice && value != SpvScopeWorkgroup && + value != SpvScopeInvocation) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << spvOpcodeString(opcode) + << ": in Vulkan 1.0 environment Memory Scope is limited to " + << "Device, Workgroup and Invocation"; + } + // Vulkan 1.1 specifc rules + if ((_.context()->target_env == SPV_ENV_VULKAN_1_1 || + _.context()->target_env == SPV_ENV_VULKAN_1_2) && + value != SpvScopeDevice && value != SpvScopeWorkgroup && + value != SpvScopeSubgroup && value != SpvScopeInvocation) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << spvOpcodeString(opcode) + << ": in Vulkan 1.1 and 1.2 environment Memory Scope is limited " + << "to Device, Workgroup and Invocation"; + } + } + + // WebGPU specific rules + if (spvIsWebGPUEnv(_.context()->target_env)) { + switch (inst->opcode()) { + case SpvOpControlBarrier: + if (value != SpvScopeWorkgroup) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << spvOpcodeString(opcode) + << ": in WebGPU environment Memory Scope is limited to " + << "Workgroup for OpControlBarrier"; + } + break; + case SpvOpMemoryBarrier: + if (value != SpvScopeWorkgroup) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << spvOpcodeString(opcode) + << ": in WebGPU environment Memory Scope is limited to " + << "Workgroup for OpMemoryBarrier"; + } + break; + default: + if (spvOpcodeIsAtomicOp(inst->opcode())) { + if (value != SpvScopeQueueFamilyKHR) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << spvOpcodeString(opcode) + << ": in WebGPU environment Memory Scope is limited to " + << "QueueFamilyKHR for OpAtomic* operations"; + } + } + + if (value != SpvScopeWorkgroup && value != SpvScopeInvocation && + value != SpvScopeQueueFamilyKHR) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << spvOpcodeString(opcode) + << ": in WebGPU environment Memory Scope is limited to " + << "Workgroup, Invocation, and QueueFamilyKHR"; + } + break; + } + } + + // TODO(atgoo@github.com) Add checks for OpenCL and OpenGL environments. + + return SPV_SUCCESS; +} + +} // namespace val +} // namespace spvtools diff --git a/third_party/spirv-tools/source/val/validate_scopes.h b/third_party/spirv-tools/source/val/validate_scopes.h new file mode 100644 index 0000000000..ba8b301a8b --- /dev/null +++ b/third_party/spirv-tools/source/val/validate_scopes.h @@ -0,0 +1,33 @@ +// Copyright (c) 2018 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. + +// Validates correctness of scopes for SPIR-V instructions. + +#include "source/opcode.h" +#include "source/val/validate.h" + +namespace spvtools { +namespace val { + +spv_result_t ValidateScope(ValidationState_t& _, const Instruction* inst, + uint32_t scope); + +spv_result_t ValidateExecutionScope(ValidationState_t& _, + const Instruction* inst, uint32_t scope); + +spv_result_t ValidateMemoryScope(ValidationState_t& _, const Instruction* inst, + uint32_t scope); + +} // namespace val +} // namespace spvtools diff --git a/third_party/spirv-tools/source/val/validate_small_type_uses.cpp b/third_party/spirv-tools/source/val/validate_small_type_uses.cpp new file mode 100644 index 0000000000..9db82e7c75 --- /dev/null +++ b/third_party/spirv-tools/source/val/validate_small_type_uses.cpp @@ -0,0 +1,57 @@ +// Copyright (c) 2019 Google LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/val/validate.h" + +#include "source/val/instruction.h" +#include "source/val/validation_state.h" + +namespace spvtools { +namespace val { + +spv_result_t ValidateSmallTypeUses(ValidationState_t& _, + const Instruction* inst) { + if (!_.HasCapability(SpvCapabilityShader) || inst->type_id() == 0 || + !_.ContainsLimitedUseIntOrFloatType(inst->type_id())) { + return SPV_SUCCESS; + } + + if (_.IsPointerType(inst->type_id())) return SPV_SUCCESS; + + // The validator should previously have checked ways to generate 8- or 16-bit + // types. So we only need to considervalid paths from source to sink. + // When restricted, uses of 8- or 16-bit types can only be stores, + // width-only conversions, decorations and copy object. + for (auto use : inst->uses()) { + const auto* user = use.first; + switch (user->opcode()) { + case SpvOpDecorate: + case SpvOpDecorateId: + case SpvOpCopyObject: + case SpvOpStore: + case SpvOpFConvert: + case SpvOpUConvert: + case SpvOpSConvert: + break; + default: + return _.diag(SPV_ERROR_INVALID_ID, user) + << "Invalid use of 8- or 16-bit result"; + } + } + + return SPV_SUCCESS; +} + +} // namespace val +} // namespace spvtools diff --git a/third_party/spirv-tools/source/val/validate_type.cpp b/third_party/spirv-tools/source/val/validate_type.cpp index b0cedcac96..5924c69fa4 100644 --- a/third_party/spirv-tools/source/val/validate_type.cpp +++ b/third_party/spirv-tools/source/val/validate_type.cpp @@ -14,34 +14,45 @@ // Ensures type declarations are unique unless allowed by the specification. -#include "source/val/validate.h" - #include "source/opcode.h" +#include "source/spirv_target_env.h" #include "source/val/instruction.h" +#include "source/val/validate.h" #include "source/val/validation_state.h" +#include "spirv/unified1/spirv.h" namespace spvtools { namespace val { namespace { -// True if the integer constant is > 0. |const_words| are words of the -// constant-defining instruction (either OpConstant or -// OpSpecConstant). typeWords are the words of the constant's-type-defining -// OpTypeInt. -bool AboveZero(const std::vector& const_words, - const std::vector& type_words) { - const uint32_t width = type_words[2]; - const bool is_signed = type_words[3] > 0; +// Returns, as an int64_t, the literal value from an OpConstant or the +// default value of an OpSpecConstant, assuming it is an integral type. +// For signed integers, relies the rule that literal value is sign extended +// to fill out to word granularity. Assumes that the constant value +// has +int64_t ConstantLiteralAsInt64(uint32_t width, + const std::vector& const_words) { const uint32_t lo_word = const_words[3]; - if (width > 32) { - // The spec currently doesn't allow integers wider than 64 bits. - const uint32_t hi_word = const_words[4]; // Must exist, per spec. - if (is_signed && (hi_word >> 31)) return false; - return (lo_word | hi_word) > 0; - } else { - if (is_signed && (lo_word >> 31)) return false; - return lo_word > 0; - } + if (width <= 32) return int32_t(lo_word); + assert(width <= 64); + assert(const_words.size() > 4); + const uint32_t hi_word = const_words[4]; // Must exist, per spec. + return static_cast(uint64_t(lo_word) | uint64_t(hi_word) << 32); +} + +// Returns, as an uint64_t, the literal value from an OpConstant or the +// default value of an OpSpecConstant, assuming it is an integral type. +// For signed integers, relies the rule that literal value is sign extended +// to fill out to word granularity. Assumes that the constant value +// has +int64_t ConstantLiteralAsUint64(uint32_t width, + const std::vector& const_words) { + const uint32_t lo_word = const_words[3]; + if (width <= 32) return lo_word; + assert(width <= 64); + assert(const_words.size() > 4); + const uint32_t hi_word = const_words[4]; // Must exist, per spec. + return (uint64_t(lo_word) | uint64_t(hi_word) << 32); } // Validates that type declarations are unique, unless multiple declarations @@ -66,6 +77,90 @@ spv_result_t ValidateUniqueness(ValidationState_t& _, const Instruction* inst) { return SPV_SUCCESS; } +spv_result_t ValidateTypeInt(ValidationState_t& _, const Instruction* inst) { + // Validates that the number of bits specified for an Int type is valid. + // Scalar integer types can be parameterized only with 32-bits. + // Int8, Int16, and Int64 capabilities allow using 8-bit, 16-bit, and 64-bit + // integers, respectively. + auto num_bits = inst->GetOperandAs(1); + if (num_bits != 32) { + if (num_bits == 8) { + if (_.features().declare_int8_type) { + return SPV_SUCCESS; + } + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Using an 8-bit integer type requires the Int8 capability," + " or an extension that explicitly enables 8-bit integers."; + } else if (num_bits == 16) { + if (_.features().declare_int16_type) { + return SPV_SUCCESS; + } + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Using a 16-bit integer type requires the Int16 capability," + " or an extension that explicitly enables 16-bit integers."; + } else if (num_bits == 64) { + if (_.HasCapability(SpvCapabilityInt64)) { + return SPV_SUCCESS; + } + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Using a 64-bit integer type requires the Int64 capability."; + } else { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Invalid number of bits (" << num_bits + << ") used for OpTypeInt."; + } + } + + const auto signedness_index = 2; + const auto signedness = inst->GetOperandAs(signedness_index); + if (signedness != 0 && signedness != 1) { + return _.diag(SPV_ERROR_INVALID_VALUE, inst) + << "OpTypeInt has invalid signedness:"; + } + + // SPIR-V Spec 2.16.3: Validation Rules for Kernel Capabilities: The + // Signedness in OpTypeInt must always be 0. + if (SpvOpTypeInt == inst->opcode() && _.HasCapability(SpvCapabilityKernel) && + inst->GetOperandAs(2) != 0u) { + return _.diag(SPV_ERROR_INVALID_BINARY, inst) + << "The Signedness in OpTypeInt " + "must always be 0 when Kernel " + "capability is used."; + } + + return SPV_SUCCESS; +} + +spv_result_t ValidateTypeFloat(ValidationState_t& _, const Instruction* inst) { + // Validates that the number of bits specified for an Int type is valid. + // Scalar integer types can be parameterized only with 32-bits. + // Int8, Int16, and Int64 capabilities allow using 8-bit, 16-bit, and 64-bit + // integers, respectively. + auto num_bits = inst->GetOperandAs(1); + if (num_bits == 32) { + return SPV_SUCCESS; + } + if (num_bits == 16) { + if (_.features().declare_float16_type) { + return SPV_SUCCESS; + } + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Using a 16-bit floating point " + << "type requires the Float16 or Float16Buffer capability," + " or an extension that explicitly enables 16-bit floating point."; + } + if (num_bits == 64) { + if (_.HasCapability(SpvCapabilityFloat64)) { + return SPV_SUCCESS; + } + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Using a 64-bit floating point " + << "type requires the Float64 capability."; + } + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Invalid number of bits (" << num_bits << ") used for OpTypeFloat."; +} + spv_result_t ValidateTypeVector(ValidationState_t& _, const Instruction* inst) { const auto component_index = 1; const auto component_id = inst->GetOperandAs(component_index); @@ -75,6 +170,27 @@ spv_result_t ValidateTypeVector(ValidationState_t& _, const Instruction* inst) { << "OpTypeVector Component Type '" << _.getIdName(component_id) << "' is not a scalar type."; } + + // Validates that the number of components in the vector is valid. + // Vector types can only be parameterized as having 2, 3, or 4 components. + // If the Vector16 capability is added, 8 and 16 components are also allowed. + auto num_components = inst->GetOperandAs(2); + if (num_components == 2 || num_components == 3 || num_components == 4) { + return SPV_SUCCESS; + } else if (num_components == 8 || num_components == 16) { + if (_.HasCapability(SpvCapabilityVector16)) { + return SPV_SUCCESS; + } + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Having " << num_components << " components for " + << spvOpcodeString(inst->opcode()) + << " requires the Vector16 capability"; + } else { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Illegal number of components (" << num_components << ") for " + << spvOpcodeString(inst->opcode()); + } + return SPV_SUCCESS; } @@ -84,9 +200,27 @@ spv_result_t ValidateTypeMatrix(ValidationState_t& _, const Instruction* inst) { const auto column_type = _.FindDef(column_type_id); if (!column_type || SpvOpTypeVector != column_type->opcode()) { return _.diag(SPV_ERROR_INVALID_ID, inst) - << "OpTypeMatrix Column Type '" << _.getIdName(column_type_id) - << "' is not a vector."; + << "Columns in a matrix must be of type vector."; } + + // Trace back once more to find out the type of components in the vector. + // Operand 1 is the of the type of data in the vector. + const auto comp_type_id = column_type->GetOperandAs(1); + auto comp_type_instruction = _.FindDef(comp_type_id); + if (comp_type_instruction->opcode() != SpvOpTypeFloat) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Matrix types can only be " + "parameterized with " + "floating-point types."; + } + + // Validates that the matrix has 2,3, or 4 columns. + auto num_cols = inst->GetOperandAs(2); + if (num_cols != 2 && num_cols != 3 && num_cols != 4) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Matrix types can only be " + "parameterized as having " + "only 2, 3, or 4 columns."; + } + return SPV_SUCCESS; } @@ -99,6 +233,21 @@ spv_result_t ValidateTypeArray(ValidationState_t& _, const Instruction* inst) { << "OpTypeArray Element Type '" << _.getIdName(element_type_id) << "' is not a type."; } + + if (element_type->opcode() == SpvOpTypeVoid) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "OpTypeArray Element Type '" << _.getIdName(element_type_id) + << "' is a void type."; + } + + if (spvIsVulkanOrWebGPUEnv(_.context()->target_env) && + element_type->opcode() == SpvOpTypeRuntimeArray) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "OpTypeArray Element Type '" << _.getIdName(element_type_id) + << "' is not valid in " + << spvLogStringForEnv(_.context()->target_env) << " environments."; + } + const auto length_index = 2; const auto length_id = inst->GetOperandAs(length_index); const auto length = _.FindDef(length_id); @@ -120,14 +269,33 @@ spv_result_t ValidateTypeArray(ValidationState_t& _, const Instruction* inst) { switch (length->opcode()) { case SpvOpSpecConstant: - case SpvOpConstant: - if (AboveZero(length->words(), const_result_type->words())) break; - // Else fall through! - case SpvOpConstantNull: { + case SpvOpConstant: { + auto& type_words = const_result_type->words(); + const bool is_signed = type_words[3] > 0; + const uint32_t width = type_words[2]; + const int64_t ivalue = ConstantLiteralAsInt64(width, length->words()); + if (ivalue == 0 || (ivalue < 0 && is_signed)) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "OpTypeArray Length '" << _.getIdName(length_id) + << "' default value must be at least 1: found " << ivalue; + } + if (spvIsWebGPUEnv(_.context()->target_env)) { + // WebGPU has maximum integer width of 32 bits, and max array size + // is one more than the max signed integer representation. + const uint64_t max_permitted = (uint64_t(1) << 31); + const uint64_t uvalue = ConstantLiteralAsUint64(width, length->words()); + if (uvalue > max_permitted) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "OpTypeArray Length '" << _.getIdName(length_id) + << "' size exceeds max value " << max_permitted + << " permitted by WebGPU: got " << uvalue; + } + } + } break; + case SpvOpConstantNull: return _.diag(SPV_ERROR_INVALID_ID, inst) << "OpTypeArray Length '" << _.getIdName(length_id) << "' default value must be at least 1."; - } case SpvOpSpecConstantOp: // Assume it's OK, rather than try to evaluate the operation. break; @@ -147,14 +315,63 @@ spv_result_t ValidateTypeRuntimeArray(ValidationState_t& _, << "OpTypeRuntimeArray Element Type '" << _.getIdName(element_id) << "' is not a type."; } + + if (element_type->opcode() == SpvOpTypeVoid) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "OpTypeRuntimeArray Element Type '" + << _.getIdName(element_id) << "' is a void type."; + } + + if (spvIsVulkanOrWebGPUEnv(_.context()->target_env) && + element_type->opcode() == SpvOpTypeRuntimeArray) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "OpTypeRuntimeArray Element Type '" + << _.getIdName(element_id) << "' is not valid in " + << spvLogStringForEnv(_.context()->target_env) << " environments."; + } + return SPV_SUCCESS; } +bool ContainsOpaqueType(ValidationState_t& _, const Instruction* str) { + const size_t elem_type_index = 1; + uint32_t elem_type_id; + Instruction* elem_type; + + if (spvOpcodeIsBaseOpaqueType(str->opcode())) { + return true; + } + + switch (str->opcode()) { + case SpvOpTypeArray: + case SpvOpTypeRuntimeArray: + elem_type_id = str->GetOperandAs(elem_type_index); + elem_type = _.FindDef(elem_type_id); + return ContainsOpaqueType(_, elem_type); + case SpvOpTypeStruct: + for (size_t member_type_index = 1; + member_type_index < str->operands().size(); ++member_type_index) { + auto member_type_id = str->GetOperandAs(member_type_index); + auto member_type = _.FindDef(member_type_id); + if (ContainsOpaqueType(_, member_type)) return true; + } + break; + default: + break; + } + return false; +} + spv_result_t ValidateTypeStruct(ValidationState_t& _, const Instruction* inst) { const uint32_t struct_id = inst->GetOperandAs(0); for (size_t member_type_index = 1; member_type_index < inst->operands().size(); ++member_type_index) { auto member_type_id = inst->GetOperandAs(member_type_index); + if (member_type_id == inst->id()) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Structure members may not be self references"; + } + auto member_type = _.FindDef(member_type_id); if (!member_type || !spvOpcodeGeneratesType(member_type->opcode())) { return _.diag(SPV_ERROR_INVALID_ID, inst) @@ -170,34 +387,49 @@ spv_result_t ValidateTypeStruct(ValidationState_t& _, const Instruction* inst) { return _.diag(SPV_ERROR_INVALID_ID, inst) << "Structure " << _.getIdName(member_type_id) << " contains members with BuiltIn decoration. Therefore this " - "structure may not be contained as a member of another " - "structure " - "type. Structure " - << _.getIdName(struct_id) << " contains structure " - << _.getIdName(member_type_id) << "."; + << "structure may not be contained as a member of another " + << "structure " + << "type. Structure " << _.getIdName(struct_id) + << " contains structure " << _.getIdName(member_type_id) + << "."; } - if (_.IsForwardPointer(member_type_id)) { - if (member_type->opcode() != SpvOpTypePointer) { + + if (spvIsVulkanOrWebGPUEnv(_.context()->target_env) && + member_type->opcode() == SpvOpTypeRuntimeArray) { + const bool is_last_member = + member_type_index == inst->operands().size() - 1; + if (!is_last_member) { return _.diag(SPV_ERROR_INVALID_ID, inst) - << "Found a forward reference to a non-pointer " - "type in OpTypeStruct instruction."; - } - // If we're dealing with a forward pointer: - // Find out the type that the pointer is pointing to (must be struct) - // word 3 is the of the type being pointed to. - auto type_pointing_to = _.FindDef(member_type->words()[3]); - if (type_pointing_to && type_pointing_to->opcode() != SpvOpTypeStruct) { - // Forward declared operands of a struct may only point to a struct. - return _.diag(SPV_ERROR_INVALID_ID, inst) - << "A forward reference operand in an OpTypeStruct must be an " - "OpTypePointer that points to an OpTypeStruct. " - "Found OpTypePointer that points to Op" - << spvOpcodeString( - static_cast(type_pointing_to->opcode())) - << "."; + << "In " << spvLogStringForEnv(_.context()->target_env) + << ", OpTypeRuntimeArray must only be used for the last member " + "of an OpTypeStruct"; } } } + + bool has_nested_blockOrBufferBlock_struct = false; + // Struct members start at word 2 of OpTypeStruct instruction. + for (size_t word_i = 2; word_i < inst->words().size(); ++word_i) { + auto member = inst->word(word_i); + auto memberTypeInstr = _.FindDef(member); + if (memberTypeInstr && SpvOpTypeStruct == memberTypeInstr->opcode()) { + if (_.HasDecoration(memberTypeInstr->id(), SpvDecorationBlock) || + _.HasDecoration(memberTypeInstr->id(), SpvDecorationBufferBlock) || + _.GetHasNestedBlockOrBufferBlockStruct(memberTypeInstr->id())) + has_nested_blockOrBufferBlock_struct = true; + } + } + + _.SetHasNestedBlockOrBufferBlockStruct(inst->id(), + has_nested_blockOrBufferBlock_struct); + if (_.GetHasNestedBlockOrBufferBlockStruct(inst->id()) && + (_.HasDecoration(inst->id(), SpvDecorationBufferBlock) || + _.HasDecoration(inst->id(), SpvDecorationBlock))) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "rules: A Block or BufferBlock cannot be nested within another " + "Block or BufferBlock. "; + } + std::unordered_set built_in_members; for (auto decoration : _.id_decorations(struct_id)) { if (decoration.dec_type() == SpvDecorationBuiltIn && @@ -210,26 +442,56 @@ spv_result_t ValidateTypeStruct(ValidationState_t& _, const Instruction* inst) { if (num_builtin_members > 0 && num_builtin_members != num_struct_members) { return _.diag(SPV_ERROR_INVALID_ID, inst) << "When BuiltIn decoration is applied to a structure-type member, " - "all members of that structure type must also be decorated with " - "BuiltIn (No allowed mixing of built-in variables and " - "non-built-in variables within a single structure). Structure id " + << "all members of that structure type must also be decorated with " + << "BuiltIn (No allowed mixing of built-in variables and " + << "non-built-in variables within a single structure). Structure id " << struct_id << " does not meet this requirement."; } if (num_builtin_members > 0) { _.RegisterStructTypeWithBuiltInMember(struct_id); } + + if (spvIsVulkanEnv(_.context()->target_env) && + !_.options()->before_hlsl_legalization && ContainsOpaqueType(_, inst)) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "In " << spvLogStringForEnv(_.context()->target_env) + << ", OpTypeStruct must not contain an opaque type."; + } + return SPV_SUCCESS; } spv_result_t ValidateTypePointer(ValidationState_t& _, const Instruction* inst) { - const auto type_id = inst->GetOperandAs(2); - const auto type = _.FindDef(type_id); + auto type_id = inst->GetOperandAs(2); + auto type = _.FindDef(type_id); if (!type || !spvOpcodeGeneratesType(type->opcode())) { return _.diag(SPV_ERROR_INVALID_ID, inst) << "OpTypePointer Type '" << _.getIdName(type_id) << "' is not a type."; } + // See if this points to a storage image. + const auto storage_class = inst->GetOperandAs(1); + if (storage_class == SpvStorageClassUniformConstant) { + // Unpack an optional level of arraying. + if (type->opcode() == SpvOpTypeArray || + type->opcode() == SpvOpTypeRuntimeArray) { + type_id = type->GetOperandAs(1); + type = _.FindDef(type_id); + } + if (type->opcode() == SpvOpTypeImage) { + const auto sampled = type->GetOperandAs(6); + // 2 indicates this image is known to be be used without a sampler, i.e. + // a storage image. + if (sampled == 2) _.RegisterPointerToStorageImage(inst->id()); + } + } + + if (!_.IsValidStorageClass(storage_class)) { + return _.diag(SPV_ERROR_INVALID_BINARY, inst) + << "Invalid storage class for target environment"; + } + return SPV_SUCCESS; } @@ -252,6 +514,12 @@ spv_result_t ValidateTypeFunction(ValidationState_t& _, << "OpTypeFunction Parameter Type '" << _.getIdName(param_id) << "' is not a type."; } + + if (param_type->opcode() == SpvOpTypeVoid) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "OpTypeFunction Parameter Type '" << _.getIdName(param_id) + << "' cannot be OpTypeVoid."; + } } const uint32_t num_function_args_limit = _.options()->universal_limits_.max_function_args; @@ -262,17 +530,111 @@ spv_result_t ValidateTypeFunction(ValidationState_t& _, << _.getIdName(inst->GetOperandAs(0)) << "' has " << num_args << " arguments."; } + + // The only valid uses of OpTypeFunction are in an OpFunction, debugging, or + // decoration instruction. + for (auto& pair : inst->uses()) { + const auto* use = pair.first; + if (use->opcode() != SpvOpFunction && !spvOpcodeIsDebug(use->opcode()) && + !use->IsNonSemantic() && !spvOpcodeIsDecoration(use->opcode())) { + return _.diag(SPV_ERROR_INVALID_ID, use) + << "Invalid use of function type result id " + << _.getIdName(inst->id()) << "."; + } + } + return SPV_SUCCESS; } +spv_result_t ValidateTypeForwardPointer(ValidationState_t& _, + const Instruction* inst) { + const auto pointer_type_id = inst->GetOperandAs(0); + const auto pointer_type_inst = _.FindDef(pointer_type_id); + if (pointer_type_inst->opcode() != SpvOpTypePointer) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Pointer type in OpTypeForwardPointer is not a pointer type."; + } + + if (inst->GetOperandAs(1) != + pointer_type_inst->GetOperandAs(1)) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Storage class in OpTypeForwardPointer does not match the " + << "pointer definition."; + } + + const auto pointee_type_id = pointer_type_inst->GetOperandAs(2); + const auto pointee_type = _.FindDef(pointee_type_id); + if (!pointee_type || pointee_type->opcode() != SpvOpTypeStruct) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Forward pointers must point to a structure"; + } + + return SPV_SUCCESS; +} + +spv_result_t ValidateTypeCooperativeMatrixNV(ValidationState_t& _, + const Instruction* inst) { + const auto component_type_index = 1; + const auto component_type_id = + inst->GetOperandAs(component_type_index); + const auto component_type = _.FindDef(component_type_id); + if (!component_type || (SpvOpTypeFloat != component_type->opcode() && + SpvOpTypeInt != component_type->opcode())) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "OpTypeCooperativeMatrixNV Component Type '" + << _.getIdName(component_type_id) + << "' is not a scalar numerical type."; + } + + const auto scope_index = 2; + const auto scope_id = inst->GetOperandAs(scope_index); + const auto scope = _.FindDef(scope_id); + if (!scope || !_.IsIntScalarType(scope->type_id()) || + !spvOpcodeIsConstant(scope->opcode())) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "OpTypeCooperativeMatrixNV Scope '" << _.getIdName(scope_id) + << "' is not a constant instruction with scalar integer type."; + } + + const auto rows_index = 3; + const auto rows_id = inst->GetOperandAs(rows_index); + const auto rows = _.FindDef(rows_id); + if (!rows || !_.IsIntScalarType(rows->type_id()) || + !spvOpcodeIsConstant(rows->opcode())) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "OpTypeCooperativeMatrixNV Rows '" << _.getIdName(rows_id) + << "' is not a constant instruction with scalar integer type."; + } + + const auto cols_index = 4; + const auto cols_id = inst->GetOperandAs(cols_index); + const auto cols = _.FindDef(cols_id); + if (!cols || !_.IsIntScalarType(cols->type_id()) || + !spvOpcodeIsConstant(cols->opcode())) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "OpTypeCooperativeMatrixNV Cols '" << _.getIdName(rows_id) + << "' is not a constant instruction with scalar integer type."; + } + + return SPV_SUCCESS; +} } // namespace spv_result_t TypePass(ValidationState_t& _, const Instruction* inst) { - if (!spvOpcodeGeneratesType(inst->opcode())) return SPV_SUCCESS; + if (!spvOpcodeGeneratesType(inst->opcode()) && + inst->opcode() != SpvOpTypeForwardPointer) { + return SPV_SUCCESS; + } if (auto error = ValidateUniqueness(_, inst)) return error; switch (inst->opcode()) { + case SpvOpTypeInt: + if (auto error = ValidateTypeInt(_, inst)) return error; + break; + case SpvOpTypeFloat: + if (auto error = ValidateTypeFloat(_, inst)) return error; + break; case SpvOpTypeVector: if (auto error = ValidateTypeVector(_, inst)) return error; break; @@ -294,6 +656,12 @@ spv_result_t TypePass(ValidationState_t& _, const Instruction* inst) { case SpvOpTypeFunction: if (auto error = ValidateTypeFunction(_, inst)) return error; break; + case SpvOpTypeForwardPointer: + if (auto error = ValidateTypeForwardPointer(_, inst)) return error; + break; + case SpvOpTypeCooperativeMatrixNV: + if (auto error = ValidateTypeCooperativeMatrixNV(_, inst)) return error; + break; default: break; } diff --git a/third_party/spirv-tools/source/val/validation_state.cpp b/third_party/spirv-tools/source/val/validation_state.cpp index 8fea3c689b..51aebbe513 100644 --- a/third_party/spirv-tools/source/val/validation_state.cpp +++ b/third_party/spirv-tools/source/val/validation_state.cpp @@ -19,6 +19,7 @@ #include #include "source/opcode.h" +#include "source/spirv_constant.h" #include "source/spirv_target_env.h" #include "source/val/basic_block.h" #include "source/val/construct.h" @@ -92,6 +93,9 @@ bool IsInstructionInLayoutSection(ModuleLayoutSection layout, SpvOp op) { case SpvOpLine: case SpvOpNoLine: case SpvOpUndef: + // SpvOpExtInst is only allowed here for certain extended instruction + // sets. This will be checked separately + case SpvOpExtInst: out = true; break; default: break; @@ -146,12 +150,37 @@ spv_result_t CountInstructions(void* user_data, return SPV_SUCCESS; } +spv_result_t setHeader(void* user_data, spv_endianness_t, uint32_t, + uint32_t version, uint32_t generator, uint32_t id_bound, + uint32_t) { + ValidationState_t& vstate = + *(reinterpret_cast(user_data)); + vstate.setIdBound(id_bound); + vstate.setGenerator(generator); + vstate.setVersion(version); + + return SPV_SUCCESS; +} + +// Add features based on SPIR-V core version number. +void UpdateFeaturesBasedOnSpirvVersion(ValidationState_t::Feature* features, + uint32_t version) { + assert(features); + if (version >= SPV_SPIRV_VERSION_WORD(1, 4)) { + features->select_between_composites = true; + features->copy_memory_permits_two_memory_accesses = true; + features->uconvert_spec_constant_op = true; + features->nonwritable_var_in_function_or_private = true; + } +} + } // namespace ValidationState_t::ValidationState_t(const spv_const_context ctx, const spv_const_validator_options opt, const uint32_t* words, - const size_t num_words) + const size_t num_words, + const uint32_t max_warnings) : context_(ctx), options_(opt), words_(words), @@ -167,40 +196,45 @@ ValidationState_t::ValidationState_t(const spv_const_context ctx, global_vars_(), local_vars_(), struct_nesting_depth_(), + struct_has_nested_blockorbufferblock_struct_(), grammar_(ctx), addressing_model_(SpvAddressingModelMax), memory_model_(SpvMemoryModelMax), - in_function_(false) { + pointer_size_and_alignment_(0), + in_function_(false), + num_of_warnings_(0), + max_num_of_warnings_(max_warnings) { assert(opt && "Validator options may not be Null."); const auto env = context_->target_env; if (spvIsVulkanEnv(env)) { - features_.non_monotonic_struct_member_offsets = true; - // Vulkan 1.1 includes VK_KHR_relaxed_block_layout in core. if (env != SPV_ENV_VULKAN_1_0) { features_.env_relaxed_block_layout = true; } } - switch (env) { - case SPV_ENV_WEBGPU_0: - features_.bans_op_undef = true; - break; - default: - break; - } - // Only attempt to count if we have words, otherwise let the other validation // fail and generate an error. if (num_words > 0) { // Count the number of instructions in the binary. - spvBinaryParse(ctx, this, words, num_words, - /* parsed_header = */ nullptr, CountInstructions, + // This parse should not produce any error messages. Hijack the context and + // replace the message consumer so that we do not pollute any state in input + // consumer. + spv_context_t hijacked_context = *ctx; + hijacked_context.consumer = [](spv_message_level_t, const char*, + const spv_position_t&, const char*) {}; + spvBinaryParse(&hijacked_context, this, words, num_words, setHeader, + CountInstructions, /* diagnostic = */ nullptr); preallocateStorage(); } + UpdateFeaturesBasedOnSpirvVersion(&features_, version_); + + friendly_mapper_ = spvtools::MakeUnique( + context_, words_, num_words_); + name_mapper_ = friendly_mapper_->GetNameMapper(); } void ValidationState_t::preallocateStorage() { @@ -232,21 +266,10 @@ void ValidationState_t::AssignNameToId(uint32_t id, std::string name) { } std::string ValidationState_t::getIdName(uint32_t id) const { - std::stringstream out; - out << id; - if (operand_names_.find(id) != end(operand_names_)) { - out << "[" << operand_names_.at(id) << "]"; - } - return out.str(); -} + const std::string id_name = name_mapper_(id); -std::string ValidationState_t::getIdOrName(uint32_t id) const { std::stringstream out; - if (operand_names_.find(id) != std::end(operand_names_)) { - out << operand_names_.at(id); - } else { - out << id; - } + out << id << "[%" << id_name << "]"; return out.str(); } @@ -293,7 +316,18 @@ bool ValidationState_t::IsOpcodeInCurrentLayoutSection(SpvOp op) { } DiagnosticStream ValidationState_t::diag(spv_result_t error_code, - const Instruction* inst) const { + const Instruction* inst) { + if (error_code == SPV_WARNING) { + if (num_of_warnings_ == max_num_of_warnings_) { + DiagnosticStream({0, 0, 0}, context_->consumer, "", error_code) + << "Other warnings have been suppressed.\n"; + } + if (num_of_warnings_ >= max_num_of_warnings_) { + return DiagnosticStream({0, 0, 0}, nullptr, "", error_code); + } + ++num_of_warnings_; + } + std::string disassembly; if (inst) disassembly = Disassemble(*inst); @@ -353,6 +387,9 @@ void ValidationState_t::RegisterCapability(SpvCapability cap) { features_.group_ops_reduce_and_scans = true; break; case SpvCapabilityInt8: + features_.use_int8_type = true; + features_.declare_int8_type = true; + break; case SpvCapabilityStorageBuffer8BitAccess: case SpvCapabilityUniformAndStorageBuffer8BitAccess: case SpvCapabilityStoragePushConstant8: @@ -392,10 +429,16 @@ void ValidationState_t::RegisterExtension(Extension ext) { switch (ext) { case kSPV_AMD_gpu_shader_half_float: + case kSPV_AMD_gpu_shader_half_float_fetch: // SPV_AMD_gpu_shader_half_float enables float16 type. // https://github.com/KhronosGroup/SPIRV-Tools/issues/1375 features_.declare_float16_type = true; break; + case kSPV_AMD_gpu_shader_int16: + // This is not yet in the extension, but it's recommended for it. + // See https://github.com/KhronosGroup/glslang/issues/848 + features_.uconvert_spec_constant_op = true; + break; case kSPV_AMD_shader_ballot: // The grammar doesn't encode the fact that SPV_AMD_shader_ballot // enables the use of group operations Reduce, InclusiveScan, @@ -420,6 +463,17 @@ bool ValidationState_t::HasAnyOfExtensions( void ValidationState_t::set_addressing_model(SpvAddressingModel am) { addressing_model_ = am; + switch (am) { + case SpvAddressingModelPhysical32: + pointer_size_and_alignment_ = 4; + break; + default: + // fall through + case SpvAddressingModelPhysical64: + case SpvAddressingModelPhysicalStorageBuffer64EXT: + pointer_size_and_alignment_ = 8; + break; + } } SpvAddressingModel ValidationState_t::addressing_model() const { @@ -507,15 +561,15 @@ void ValidationState_t::RegisterInstruction(Instruction* inst) { const uint32_t operand_word = inst->word(operand.offset); Instruction* operand_inst = FindDef(operand_word); if (operand_inst && SpvOpSampledImage == operand_inst->opcode()) { - RegisterSampledImageConsumer(operand_word, inst->id()); + RegisterSampledImageConsumer(operand_word, inst); } } } } -std::vector ValidationState_t::getSampledImageConsumers( +std::vector ValidationState_t::getSampledImageConsumers( uint32_t sampled_image_id) const { - std::vector result; + std::vector result; auto iter = sampled_image_consumers_.find(sampled_image_id); if (iter != sampled_image_consumers_.end()) { result = iter->second; @@ -524,8 +578,8 @@ std::vector ValidationState_t::getSampledImageConsumers( } void ValidationState_t::RegisterSampledImageConsumer(uint32_t sampled_image_id, - uint32_t consumer_id) { - sampled_image_consumers_[sampled_image_id].push_back(consumer_id); + Instruction* consumer) { + sampled_image_consumers_[sampled_image_id].push_back(consumer); } uint32_t ValidationState_t::getIdBound() const { return id_bound_; } @@ -577,6 +631,9 @@ uint32_t ValidationState_t::GetComponentType(uint32_t id) const { case SpvOpTypeMatrix: return GetComponentType(inst->word(2)); + case SpvOpTypeCooperativeMatrixNV: + return inst->word(2); + default: break; } @@ -601,6 +658,10 @@ uint32_t ValidationState_t::GetDimension(uint32_t id) const { case SpvOpTypeMatrix: return inst->word(3); + case SpvOpTypeCooperativeMatrixNV: + // Actual dimension isn't known, return 0 + return 0; + default: break; } @@ -625,6 +686,12 @@ uint32_t ValidationState_t::GetBitWidth(uint32_t id) const { return 0; } +bool ValidationState_t::IsVoidType(uint32_t id) const { + const Instruction* inst = FindDef(id); + assert(inst); + return inst->opcode() == SpvOpTypeVoid; +} + bool ValidationState_t::IsFloatScalarType(uint32_t id) const { const Instruction* inst = FindDef(id); assert(inst); @@ -829,6 +896,86 @@ bool ValidationState_t::GetPointerTypeInfo(uint32_t id, uint32_t* data_type, return true; } +bool ValidationState_t::IsCooperativeMatrixType(uint32_t id) const { + const Instruction* inst = FindDef(id); + assert(inst); + return inst->opcode() == SpvOpTypeCooperativeMatrixNV; +} + +bool ValidationState_t::IsFloatCooperativeMatrixType(uint32_t id) const { + if (!IsCooperativeMatrixType(id)) return false; + return IsFloatScalarType(FindDef(id)->word(2)); +} + +bool ValidationState_t::IsIntCooperativeMatrixType(uint32_t id) const { + if (!IsCooperativeMatrixType(id)) return false; + return IsIntScalarType(FindDef(id)->word(2)); +} + +bool ValidationState_t::IsUnsignedIntCooperativeMatrixType(uint32_t id) const { + if (!IsCooperativeMatrixType(id)) return false; + return IsUnsignedIntScalarType(FindDef(id)->word(2)); +} + +spv_result_t ValidationState_t::CooperativeMatrixShapesMatch( + const Instruction* inst, uint32_t m1, uint32_t m2) { + const auto m1_type = FindDef(m1); + const auto m2_type = FindDef(m2); + + if (m1_type->opcode() != SpvOpTypeCooperativeMatrixNV || + m2_type->opcode() != SpvOpTypeCooperativeMatrixNV) { + return diag(SPV_ERROR_INVALID_DATA, inst) + << "Expected cooperative matrix types"; + } + + uint32_t m1_scope_id = m1_type->GetOperandAs(2); + uint32_t m1_rows_id = m1_type->GetOperandAs(3); + uint32_t m1_cols_id = m1_type->GetOperandAs(4); + + uint32_t m2_scope_id = m2_type->GetOperandAs(2); + uint32_t m2_rows_id = m2_type->GetOperandAs(3); + uint32_t m2_cols_id = m2_type->GetOperandAs(4); + + bool m1_is_int32 = false, m1_is_const_int32 = false, m2_is_int32 = false, + m2_is_const_int32 = false; + uint32_t m1_value = 0, m2_value = 0; + + std::tie(m1_is_int32, m1_is_const_int32, m1_value) = + EvalInt32IfConst(m1_scope_id); + std::tie(m2_is_int32, m2_is_const_int32, m2_value) = + EvalInt32IfConst(m2_scope_id); + + if (m1_is_const_int32 && m2_is_const_int32 && m1_value != m2_value) { + return diag(SPV_ERROR_INVALID_DATA, inst) + << "Expected scopes of Matrix and Result Type to be " + << "identical"; + } + + std::tie(m1_is_int32, m1_is_const_int32, m1_value) = + EvalInt32IfConst(m1_rows_id); + std::tie(m2_is_int32, m2_is_const_int32, m2_value) = + EvalInt32IfConst(m2_rows_id); + + if (m1_is_const_int32 && m2_is_const_int32 && m1_value != m2_value) { + return diag(SPV_ERROR_INVALID_DATA, inst) + << "Expected rows of Matrix type and Result Type to be " + << "identical"; + } + + std::tie(m1_is_int32, m1_is_const_int32, m1_value) = + EvalInt32IfConst(m1_cols_id); + std::tie(m2_is_int32, m2_is_const_int32, m2_value) = + EvalInt32IfConst(m2_cols_id); + + if (m1_is_const_int32 && m2_is_const_int32 && m1_value != m2_value) { + return diag(SPV_ERROR_INVALID_DATA, inst) + << "Expected columns of Matrix type and Result Type to be " + << "identical"; + } + + return SPV_SUCCESS; +} + uint32_t ValidationState_t::GetOperandTypeId(const Instruction* inst, size_t operand_index) const { return GetTypeId(inst->GetOperandAs(operand_index)); @@ -857,7 +1004,7 @@ bool ValidationState_t::GetConstantValUint64(uint32_t id, uint64_t* val) const { } std::tuple ValidationState_t::EvalInt32IfConst( - uint32_t id) { + uint32_t id) const { const Instruction* const inst = FindDef(id); assert(inst); const uint32_t type = inst->type_id(); @@ -866,10 +1013,17 @@ std::tuple ValidationState_t::EvalInt32IfConst( return std::make_tuple(false, false, 0); } - if (inst->opcode() != SpvOpConstant && inst->opcode() != SpvOpSpecConstant) { + // Spec constant values cannot be evaluated so don't consider constant for + // the purpose of this method. + if (!spvOpcodeIsConstant(inst->opcode()) || + spvOpcodeIsSpecConstant(inst->opcode())) { return std::make_tuple(true, false, 0); } + if (inst->opcode() == SpvOpConstantNull) { + return std::make_tuple(true, true, 0); + } + assert(inst->words().size() == 4); return std::make_tuple(true, true, inst->word(3)); } @@ -897,6 +1051,39 @@ void ValidationState_t::ComputeFunctionToEntryPointMapping() { } } +void ValidationState_t::ComputeRecursiveEntryPoints() { + for (const Function func : functions()) { + std::stack call_stack; + std::set visited; + + for (const uint32_t new_call : func.function_call_targets()) { + call_stack.push(new_call); + } + + while (!call_stack.empty()) { + const uint32_t called_func_id = call_stack.top(); + call_stack.pop(); + + if (!visited.insert(called_func_id).second) continue; + + if (called_func_id == func.id()) { + for (const uint32_t entry_point : + function_to_entry_points_[called_func_id]) + recursive_entry_points_.insert(entry_point); + break; + } + + const Function* called_func = function(called_func_id); + if (called_func) { + // Other checks should error out on this invalid SPIR-V. + for (const uint32_t new_call : called_func->function_call_targets()) { + call_stack.push(new_call); + } + } + } + } +} + const std::vector& ValidationState_t::FunctionEntryPoints( uint32_t func) const { auto iter = function_to_entry_points_.find(func); @@ -907,6 +1094,34 @@ const std::vector& ValidationState_t::FunctionEntryPoints( } } +std::set ValidationState_t::EntryPointReferences(uint32_t id) const { + std::set referenced_entry_points; + const auto inst = FindDef(id); + if (!inst) return referenced_entry_points; + + std::vector stack; + stack.push_back(inst); + while (!stack.empty()) { + const auto current_inst = stack.back(); + stack.pop_back(); + + if (const auto func = current_inst->function()) { + // Instruction lives in a function, we can stop searching. + const auto function_entry_points = FunctionEntryPoints(func->id()); + referenced_entry_points.insert(function_entry_points.begin(), + function_entry_points.end()); + } else { + // Instruction is in the global scope, keep searching its uses. + for (auto pair : current_inst->uses()) { + const auto next_inst = pair.first; + stack.push_back(next_inst); + } + } + } + + return referenced_entry_points; +} + std::string ValidationState_t::Disassemble(const Instruction& inst) const { const spv_parsed_instruction_t& c_inst(inst.c_inst()); return Disassemble(c_inst.words, c_inst.num_words); @@ -921,5 +1136,188 @@ std::string ValidationState_t::Disassemble(const uint32_t* words, words_, num_words_, disassembly_options); } +bool ValidationState_t::LogicallyMatch(const Instruction* lhs, + const Instruction* rhs, + bool check_decorations) { + if (lhs->opcode() != rhs->opcode()) { + return false; + } + + if (check_decorations) { + const auto& dec_a = id_decorations(lhs->id()); + const auto& dec_b = id_decorations(rhs->id()); + + for (const auto& dec : dec_b) { + if (std::find(dec_a.begin(), dec_a.end(), dec) == dec_a.end()) { + return false; + } + } + } + + if (lhs->opcode() == SpvOpTypeArray) { + // Size operands must match. + if (lhs->GetOperandAs(2u) != rhs->GetOperandAs(2u)) { + return false; + } + + // Elements must match or logically match. + const auto lhs_ele_id = lhs->GetOperandAs(1u); + const auto rhs_ele_id = rhs->GetOperandAs(1u); + if (lhs_ele_id == rhs_ele_id) { + return true; + } + + const auto lhs_ele = FindDef(lhs_ele_id); + const auto rhs_ele = FindDef(rhs_ele_id); + if (!lhs_ele || !rhs_ele) { + return false; + } + return LogicallyMatch(lhs_ele, rhs_ele, check_decorations); + } else if (lhs->opcode() == SpvOpTypeStruct) { + // Number of elements must match. + if (lhs->operands().size() != rhs->operands().size()) { + return false; + } + + for (size_t i = 1u; i < lhs->operands().size(); ++i) { + const auto lhs_ele_id = lhs->GetOperandAs(i); + const auto rhs_ele_id = rhs->GetOperandAs(i); + // Elements must match or logically match. + if (lhs_ele_id == rhs_ele_id) { + continue; + } + + const auto lhs_ele = FindDef(lhs_ele_id); + const auto rhs_ele = FindDef(rhs_ele_id); + if (!lhs_ele || !rhs_ele) { + return false; + } + + if (!LogicallyMatch(lhs_ele, rhs_ele, check_decorations)) { + return false; + } + } + + // All checks passed. + return true; + } + + // No other opcodes are acceptable at this point. Arrays and structs are + // caught above and if they're elements are not arrays or structs they are + // required to match exactly. + return false; +} + +const Instruction* ValidationState_t::TracePointer( + const Instruction* inst) const { + auto base_ptr = inst; + while (base_ptr->opcode() == SpvOpAccessChain || + base_ptr->opcode() == SpvOpInBoundsAccessChain || + base_ptr->opcode() == SpvOpPtrAccessChain || + base_ptr->opcode() == SpvOpInBoundsPtrAccessChain || + base_ptr->opcode() == SpvOpCopyObject) { + base_ptr = FindDef(base_ptr->GetOperandAs(2u)); + } + return base_ptr; +} + +bool ValidationState_t::ContainsSizedIntOrFloatType(uint32_t id, SpvOp type, + uint32_t width) const { + if (type != SpvOpTypeInt && type != SpvOpTypeFloat) return false; + + const auto inst = FindDef(id); + if (!inst) return false; + + if (inst->opcode() == type) { + return inst->GetOperandAs(1u) == width; + } + + switch (inst->opcode()) { + case SpvOpTypeArray: + case SpvOpTypeRuntimeArray: + case SpvOpTypeVector: + case SpvOpTypeMatrix: + case SpvOpTypeImage: + case SpvOpTypeSampledImage: + case SpvOpTypeCooperativeMatrixNV: + return ContainsSizedIntOrFloatType(inst->GetOperandAs(1u), type, + width); + case SpvOpTypePointer: + if (IsForwardPointer(id)) return false; + return ContainsSizedIntOrFloatType(inst->GetOperandAs(2u), type, + width); + case SpvOpTypeFunction: + case SpvOpTypeStruct: { + for (uint32_t i = 1; i < inst->operands().size(); ++i) { + if (ContainsSizedIntOrFloatType(inst->GetOperandAs(i), type, + width)) + return true; + } + return false; + } + default: + return false; + } +} + +bool ValidationState_t::ContainsLimitedUseIntOrFloatType(uint32_t id) const { + if ((!HasCapability(SpvCapabilityInt16) && + ContainsSizedIntOrFloatType(id, SpvOpTypeInt, 16)) || + (!HasCapability(SpvCapabilityInt8) && + ContainsSizedIntOrFloatType(id, SpvOpTypeInt, 8)) || + (!HasCapability(SpvCapabilityFloat16) && + ContainsSizedIntOrFloatType(id, SpvOpTypeFloat, 16))) { + return true; + } + return false; +} + +bool ValidationState_t::IsValidStorageClass( + SpvStorageClass storage_class) const { + if (spvIsWebGPUEnv(context()->target_env)) { + switch (storage_class) { + case SpvStorageClassUniformConstant: + case SpvStorageClassUniform: + case SpvStorageClassStorageBuffer: + case SpvStorageClassInput: + case SpvStorageClassOutput: + case SpvStorageClassImage: + case SpvStorageClassWorkgroup: + case SpvStorageClassPrivate: + case SpvStorageClassFunction: + return true; + default: + return false; + } + } + + if (spvIsVulkanEnv(context()->target_env)) { + switch (storage_class) { + case SpvStorageClassUniformConstant: + case SpvStorageClassUniform: + case SpvStorageClassStorageBuffer: + case SpvStorageClassInput: + case SpvStorageClassOutput: + case SpvStorageClassImage: + case SpvStorageClassWorkgroup: + case SpvStorageClassPrivate: + case SpvStorageClassFunction: + case SpvStorageClassPushConstant: + case SpvStorageClassPhysicalStorageBuffer: + case SpvStorageClassRayPayloadNV: + case SpvStorageClassIncomingRayPayloadNV: + case SpvStorageClassHitAttributeNV: + case SpvStorageClassCallableDataNV: + case SpvStorageClassIncomingCallableDataNV: + case SpvStorageClassShaderRecordBufferNV: + return true; + default: + return false; + } + } + + return true; +} + } // namespace val } // namespace spvtools diff --git a/third_party/spirv-tools/source/val/validation_state.h b/third_party/spirv-tools/source/val/validation_state.h index 769985918a..e5d31acf6e 100644 --- a/third_party/spirv-tools/source/val/validation_state.h +++ b/third_party/spirv-tools/source/val/validation_state.h @@ -15,6 +15,7 @@ #ifndef SOURCE_VAL_VALIDATION_STATE_H_ #define SOURCE_VAL_VALIDATION_STATE_H_ +#include #include #include #include @@ -28,6 +29,7 @@ #include "source/disassemble.h" #include "source/enum_set.h" #include "source/latest_version_spirv_header.h" +#include "source/name_mapper.h" #include "source/spirv_definition.h" #include "source/spirv_validator_options.h" #include "source/val/decoration.h" @@ -77,24 +79,50 @@ class ValidationState_t { // Permit group oerations Reduce, InclusiveScan, ExclusiveScan bool group_ops_reduce_and_scans = false; - // Disallows the use of OpUndef - bool bans_op_undef = false; - // Allow OpTypeInt with 8 bit width? bool declare_int8_type = false; - // Allow non-monotonic offsets for struct members? - // Vulkan permits this. - bool non_monotonic_struct_member_offsets = false; - // Target environment uses relaxed block layout. // This is true for Vulkan 1.1 or later. bool env_relaxed_block_layout = false; + + // Allow an OpTypeInt with 8 bit width to be used in more than just int + // conversion opcodes + bool use_int8_type = false; + + // Use scalar block layout. See VK_EXT_scalar_block_layout: + // Defines scalar alignment: + // - scalar alignment equals the scalar size in bytes + // - array alignment is same as its element alignment + // - array alignment is max alignment of any of its members + // - vector alignment is same as component alignment + // - matrix alignment is same as component alignment + // For struct in Uniform, StorageBuffer, PushConstant: + // - Offset of a member is multiple of scalar alignment of that member + // - ArrayStride and MatrixStride are multiples of scalar alignment + // Members need not be listed in offset order + bool scalar_block_layout = false; + + // SPIR-V 1.4 allows us to select between any two composite values + // of the same type. + bool select_between_composites = false; + + // SPIR-V 1.4 allows two memory access operands for OpCopyMemory and + // OpCopyMemorySized. + bool copy_memory_permits_two_memory_accesses = false; + + // SPIR-V 1.4 allows UConvert as a spec constant op in any environment. + // The Kernel capability already enables it, separately from this flag. + bool uconvert_spec_constant_op = false; + + // SPIR-V 1.4 allows Function and Private variables to be NonWritable + bool nonwritable_var_in_function_or_private = false; }; ValidationState_t(const spv_const_context context, const spv_const_validator_options opt, - const uint32_t* words, const size_t num_words); + const uint32_t* words, const size_t num_words, + const uint32_t max_warnings); /// Returns the context spv_const_context context() const { return context_; } @@ -140,9 +168,6 @@ class ValidationState_t { /// Mutator function for ID bound. void setIdBound(uint32_t bound); - /// Like getIdName but does not display the id if the \p id has a name - std::string getIdOrName(uint32_t id) const; - /// Returns the number of ID which have been forward referenced but not /// defined size_t unresolved_forward_id_count() const; @@ -173,7 +198,7 @@ class ValidationState_t { /// Determines if the op instruction is part of the current section bool IsOpcodeInCurrentLayoutSection(SpvOp op); - DiagnosticStream diag(spv_result_t error_code, const Instruction* inst) const; + DiagnosticStream diag(spv_result_t error_code, const Instruction* inst); /// Returns the function states std::vector& functions(); @@ -210,6 +235,12 @@ class ValidationState_t { /// Returns a list of entry point function ids const std::vector& entry_points() const { return entry_points_; } + /// Returns the set of entry points that root call graphs that contain + /// recursion. + const std::set& recursive_entry_points() const { + return recursive_entry_points_; + } + /// Registers execution mode for the given entry point. void RegisterExecutionModeForEntryPoint(uint32_t entry_point, SpvExecutionMode execution_mode) { @@ -249,9 +280,19 @@ class ValidationState_t { /// Note: called after fully parsing the binary. void ComputeFunctionToEntryPointMapping(); + /// Traverse call tree and computes recursive_entry_points_. + /// Note: called after fully parsing the binary and calling + /// ComputeFunctionToEntryPointMapping. + void ComputeRecursiveEntryPoints(); + /// Returns all the entry points that can call |func|. const std::vector& FunctionEntryPoints(uint32_t func) const; + /// Returns all the entry points that statically use |id|. + /// + /// Note: requires ComputeFunctionToEntryPointMapping to have been called. + std::set EntryPointReferences(uint32_t id) const; + /// Inserts an to the set of functions that are target of OpFunctionCall. void AddFunctionCallTarget(const uint32_t id) { function_call_targets_.insert(id); @@ -263,6 +304,9 @@ class ValidationState_t { return (function_call_targets_.find(id) != function_call_targets_.end()); } + bool IsFunctionCallDefined(const uint32_t id) { + return (id_to_function_.find(id) != id_to_function_.end()); + } /// Registers the capability and its dependent capabilities void RegisterCapability(SpvCapability cap); @@ -283,6 +327,12 @@ class ValidationState_t { return module_capabilities_.Contains(cap); } + /// Returns a reference to the set of capabilities in the module. + /// This is provided for debuggability. + const CapabilitySet& module_capabilities() const { + return module_capabilities_; + } + /// Returns true if the extension is enabled in the module. bool HasExtension(Extension ext) const { return module_extensions_.Contains(ext); @@ -308,6 +358,11 @@ class ValidationState_t { /// Returns the addressing model of this module, or Logical if uninitialized. SpvAddressingModel addressing_model() const; + /// Returns the addressing model of this module, or Logical if uninitialized. + uint32_t pointer_size_and_alignment() const { + return pointer_size_and_alignment_; + } + /// Sets the memory model of this module. void set_memory_model(SpvMemoryModel mm); @@ -328,7 +383,11 @@ class ValidationState_t { /// Registers the decoration for the given void RegisterDecorationForId(uint32_t id, const Decoration& dec) { - id_decorations_[id].push_back(dec); + auto& dec_list = id_decorations_[id]; + auto lb = std::find(dec_list.begin(), dec_list.end(), dec); + if (lb == dec_list.end()) { + dec_list.push_back(dec); + } } /// Registers the list of decorations for the given @@ -356,17 +415,23 @@ class ValidationState_t { std::vector& id_decorations(uint32_t id) { return id_decorations_[id]; } - const std::vector& id_decorations(uint32_t id) const { - // TODO: This would throw or generate SIGABRT if id has no - // decorations. Remove/refactor this function. - return id_decorations_.at(id); - } // Returns const pointer to the internal decoration container. const std::map>& id_decorations() const { return id_decorations_; } + /// Returns true if the given id has the given decoration , + /// otherwise returns false. + bool HasDecoration(uint32_t id, SpvDecoration dec) { + const auto& decorations = id_decorations_.find(id); + if (decorations == id_decorations_.end()) return false; + + return std::any_of( + decorations->second.begin(), decorations->second.end(), + [dec](const Decoration& d) { return dec == d.dec_type(); }); + } + /// Finds id's def, if it exists. If found, returns the definition otherwise /// nullptr const Instruction* FindDef(uint32_t id) const; @@ -385,13 +450,13 @@ class ValidationState_t { return all_definitions_; } - /// Returns a vector containing the Ids of instructions that consume the given + /// Returns a vector containing the instructions that consume the given /// SampledImage id. - std::vector getSampledImageConsumers(uint32_t id) const; + std::vector getSampledImageConsumers(uint32_t id) const; /// Records cons_id as a consumer of sampled_image_id. void RegisterSampledImageConsumer(uint32_t sampled_image_id, - uint32_t cons_id); + Instruction* consumer); /// Returns the set of Global Variables. std::unordered_set& global_vars() { return global_vars_; } @@ -427,6 +492,18 @@ class ValidationState_t { return struct_nesting_depth_[id]; } + /// Records the has a nested block/bufferblock decorated struct for a given + /// struct ID + void SetHasNestedBlockOrBufferBlockStruct(uint32_t id, bool has) { + struct_has_nested_blockorbufferblock_struct_[id] = has; + } + + /// For a given struct ID returns true if it has a nested block/bufferblock + /// decorated struct + bool GetHasNestedBlockOrBufferBlockStruct(uint32_t id) { + return struct_has_nested_blockorbufferblock_struct_[id]; + } + /// Records that the structure type has a member decorated with a built-in. void RegisterStructTypeWithBuiltInMember(uint32_t id) { builtin_structs_.insert(id); @@ -478,6 +555,7 @@ class ValidationState_t { // Returns true iff |id| is a type corresponding to the name of the function. // Only works for types not for objects. + bool IsVoidType(uint32_t id) const; bool IsFloatScalarType(uint32_t id) const; bool IsFloatVectorType(uint32_t id) const; bool IsFloatScalarOrVectorType(uint32_t id) const; @@ -493,6 +571,18 @@ class ValidationState_t { bool IsBoolVectorType(uint32_t id) const; bool IsBoolScalarOrVectorType(uint32_t id) const; bool IsPointerType(uint32_t id) const; + bool IsCooperativeMatrixType(uint32_t id) const; + bool IsFloatCooperativeMatrixType(uint32_t id) const; + bool IsIntCooperativeMatrixType(uint32_t id) const; + bool IsUnsignedIntCooperativeMatrixType(uint32_t id) const; + + // Returns true if |id| is a type id that contains |type| (or integer or + // floating point type) of |width| bits. + bool ContainsSizedIntOrFloatType(uint32_t id, SpvOp type, + uint32_t width) const; + // Returns true if |id| is a type id that contains a 8- or 16-bit int or + // 16-bit float that is not generally enabled for use. + bool ContainsLimitedUseIntOrFloatType(uint32_t id) const; // Gets value from OpConstant and OpSpecConstant as uint64. // Returns false on failure (no instruction, wrong instruction, not int). @@ -515,9 +605,68 @@ class ValidationState_t { bool GetPointerTypeInfo(uint32_t id, uint32_t* data_type, uint32_t* storage_class) const; + // Is the ID the type of a pointer to a uniform block: Block-decorated struct + // in uniform storage class? The result is only valid after internal method + // CheckDecorationsOfBuffers has been called. + bool IsPointerToUniformBlock(uint32_t type_id) const { + return pointer_to_uniform_block_.find(type_id) != + pointer_to_uniform_block_.cend(); + } + // Save the ID of a pointer to uniform block. + void RegisterPointerToUniformBlock(uint32_t type_id) { + pointer_to_uniform_block_.insert(type_id); + } + // Is the ID the type of a struct used as a uniform block? + // The result is only valid after internal method CheckDecorationsOfBuffers + // has been called. + bool IsStructForUniformBlock(uint32_t type_id) const { + return struct_for_uniform_block_.find(type_id) != + struct_for_uniform_block_.cend(); + } + // Save the ID of a struct of a uniform block. + void RegisterStructForUniformBlock(uint32_t type_id) { + struct_for_uniform_block_.insert(type_id); + } + // Is the ID the type of a pointer to a storage buffer: BufferBlock-decorated + // struct in uniform storage class, or Block-decorated struct in StorageBuffer + // storage class? The result is only valid after internal method + // CheckDecorationsOfBuffers has been called. + bool IsPointerToStorageBuffer(uint32_t type_id) const { + return pointer_to_storage_buffer_.find(type_id) != + pointer_to_storage_buffer_.cend(); + } + // Save the ID of a pointer to a storage buffer. + void RegisterPointerToStorageBuffer(uint32_t type_id) { + pointer_to_storage_buffer_.insert(type_id); + } + // Is the ID the type of a struct for storage buffer? + // The result is only valid after internal method CheckDecorationsOfBuffers + // has been called. + bool IsStructForStorageBuffer(uint32_t type_id) const { + return struct_for_storage_buffer_.find(type_id) != + struct_for_storage_buffer_.cend(); + } + // Save the ID of a struct of a storage buffer. + void RegisterStructForStorageBuffer(uint32_t type_id) { + struct_for_storage_buffer_.insert(type_id); + } + + // Is the ID the type of a pointer to a storage image? That is, the pointee + // type is an image type which is known to not use a sampler. + bool IsPointerToStorageImage(uint32_t type_id) const { + return pointer_to_storage_image_.find(type_id) != + pointer_to_storage_image_.cend(); + } + // Save the ID of a pointer to a storage image. + void RegisterPointerToStorageImage(uint32_t type_id) { + pointer_to_storage_image_.insert(type_id); + } + // Tries to evaluate a 32-bit signed or unsigned scalar integer constant. // Returns tuple . - std::tuple EvalInt32IfConst(uint32_t id); + // OpSpecConstant* return |is_const_int32| as false since their values cannot + // be relied upon during validation. + std::tuple EvalInt32IfConst(uint32_t id) const; // Returns the disassembly string for the given instruction. std::string Disassemble(const Instruction& inst) const; @@ -525,6 +674,39 @@ class ValidationState_t { // Returns the disassembly string for the given instruction. std::string Disassemble(const uint32_t* words, uint16_t num_words) const; + // Returns whether type m1 and type m2 are cooperative matrices with + // the same "shape" (matching scope, rows, cols). If any are specialization + // constants, we assume they can match because we can't prove they don't. + spv_result_t CooperativeMatrixShapesMatch(const Instruction* inst, + uint32_t m1, uint32_t m2); + + // Returns true if |lhs| and |rhs| logically match and, if the decorations of + // |rhs| are a subset of |lhs|. + // + // 1. Must both be either OpTypeArray or OpTypeStruct + // 2. If OpTypeArray, then + // * Length must be the same + // * Element type must match or logically match + // 3. If OpTypeStruct, then + // * Both have same number of elements + // * Element N for both structs must match or logically match + // + // If |check_decorations| is false, then the decorations are not checked. + bool LogicallyMatch(const Instruction* lhs, const Instruction* rhs, + bool check_decorations); + + // Traces |inst| to find a single base pointer. Returns the base pointer. + // Will trace through the following instructions: + // * OpAccessChain + // * OpInBoundsAccessChain + // * OpPtrAccessChain + // * OpInBoundsPtrAccessChain + // * OpCopyObject + const Instruction* TracePointer(const Instruction* inst) const; + + // Validates the storage class for the target environment. + bool IsValidStorageClass(SpvStorageClass storage_class) const; + private: ValidationState_t(const ValidationState_t&); @@ -556,7 +738,8 @@ class ValidationState_t { /// Stores a vector of instructions that use the result of a given /// OpSampledImage instruction. - std::unordered_map> sampled_image_consumers_; + std::unordered_map> + sampled_image_consumers_; /// A map of operand IDs and their names defined by the OpName instruction std::unordered_map operand_names_; @@ -588,6 +771,10 @@ class ValidationState_t { std::unordered_map> entry_point_descriptions_; + /// IDs that are entry points, ie, arguments to OpEntryPoint, and root a call + /// graph that recurses. + std::set recursive_entry_points_; + /// Functions IDs that are target of OpFunctionCall. std::unordered_set function_call_targets_; @@ -606,6 +793,10 @@ class ValidationState_t { /// Structure Nesting Depth std::unordered_map struct_nesting_depth_; + /// Structure has nested blockorbufferblock struct + std::unordered_map + struct_has_nested_blockorbufferblock_struct_; + /// Stores the list of decorations for a given std::map> id_decorations_; @@ -619,6 +810,9 @@ class ValidationState_t { SpvAddressingModel addressing_model_; SpvMemoryModel memory_model_; + // pointer size derived from addressing model. Assumes all storage classes + // have the same pointer size (for physical pointer types). + uint32_t pointer_size_and_alignment_; /// NOTE: See correspoding getter functions bool in_function_; @@ -644,6 +838,31 @@ class ValidationState_t { /// module which can (indirectly) call the function. std::unordered_map> function_to_entry_points_; const std::vector empty_ids_; + + // The IDs of types of pointers to Block-decorated structs in Uniform storage + // class. This is populated at the start of ValidateDecorations. + std::unordered_set pointer_to_uniform_block_; + // The IDs of struct types for uniform blocks. + // This is populated at the start of ValidateDecorations. + std::unordered_set struct_for_uniform_block_; + // The IDs of types of pointers to BufferBlock-decorated structs in Uniform + // storage class, or Block-decorated structs in StorageBuffer storage class. + // This is populated at the start of ValidateDecorations. + std::unordered_set pointer_to_storage_buffer_; + // The IDs of struct types for storage buffers. + // This is populated at the start of ValidateDecorations. + std::unordered_set struct_for_storage_buffer_; + // The IDs of types of pointers to storage images. This is populated in the + // TypePass. + std::unordered_set pointer_to_storage_image_; + + /// Maps ids to friendly names. + std::unique_ptr friendly_mapper_; + spvtools::NameMapper name_mapper_; + + /// Variables used to reduce the number of diagnostic messages. + uint32_t num_of_warnings_; + uint32_t max_num_of_warnings_; }; } // namespace val diff --git a/third_party/spirv-tools/test/CMakeLists.txt b/third_party/spirv-tools/test/CMakeLists.txt index 1fdf5a2122..70999f9978 100644 --- a/third_party/spirv-tools/test/CMakeLists.txt +++ b/third_party/spirv-tools/test/CMakeLists.txt @@ -30,12 +30,16 @@ endif() function(add_spvtools_unittest) if (NOT "${SPIRV_SKIP_TESTS}" AND TARGET gmock_main) - set(one_value_args TARGET) + set(one_value_args TARGET PCH_FILE) set(multi_value_args SRCS LIBS ENVIRONMENT) cmake_parse_arguments( ARG "" "${one_value_args}" "${multi_value_args}" ${ARGN}) set(target test_${ARG_TARGET}) - add_executable(${target} ${ARG_SRCS}) + set(SRC_COPY ${ARG_SRCS}) + if (DEFINED ARG_PCH_FILE) + spvtools_pch(SRC_COPY ${ARG_PCH_FILE}) + endif() + add_executable(${target} ${SRC_COPY}) spvtools_default_compile_options(${target}) if(${COMPILER_IS_LIKE_GNU}) target_compile_options(${target} PRIVATE -Wno-undef) @@ -93,16 +97,20 @@ set(TEST_SOURCES binary_to_text_test.cpp binary_to_text.literal_test.cpp comment_test.cpp + diagnostic_test.cpp enum_string_mapping_test.cpp enum_set_test.cpp + ext_inst.cldebug100_test.cpp ext_inst.debuginfo_test.cpp ext_inst.glsl_test.cpp + ext_inst.non_semantic_test.cpp ext_inst.opencl_test.cpp fix_word_test.cpp generator_magic_number_test.cpp hex_float_test.cpp immediate_int_test.cpp libspirv_macros_test.cpp + log_test.cpp named_id_test.cpp name_mapper_test.cpp opcode_make_test.cpp @@ -112,7 +120,10 @@ set(TEST_SOURCES operand_capabilities_test.cpp operand_test.cpp operand_pattern_test.cpp + parse_number_test.cpp + preserve_numeric_ids_test.cpp software_version_test.cpp + string_utils_test.cpp target_env_test.cpp text_advance_test.cpp text_destroy_test.cpp @@ -120,6 +131,7 @@ set(TEST_SOURCES text_start_new_inst_test.cpp text_to_binary.annotation_test.cpp text_to_binary.barrier_test.cpp + text_to_binary.composite_test.cpp text_to_binary.constant_test.cpp text_to_binary.control_flow_test.cpp text_to_binary_test.cpp @@ -142,16 +154,13 @@ set(TEST_SOURCES unit_spirv.cpp ) +spvtools_pch(TEST_SOURCES pch_test) + add_spvtools_unittest( TARGET spirv_unit_tests SRCS ${TEST_SOURCES} LIBS ${SPIRV_TOOLS}) -add_spvtools_unittest( - TARGET diagnostic - SRCS diagnostic_test.cpp - LIBS ${SPIRV_TOOLS}) - add_spvtools_unittest( TARGET c_interface SRCS c_interface_test.cpp @@ -168,16 +177,6 @@ add_spvtools_unittest( SRCS cpp_interface_test.cpp LIBS SPIRV-Tools-opt) -add_spvtools_unittest( - TARGET parse_number - SRCS parse_number_test.cpp - LIBS ${SPIRV_TOOLS}) - -add_spvtools_unittest( - TARGET string_utils - SRCS string_utils_test.cpp - LIBS ${SPIRV_TOOLS}) - if (${SPIRV_TIMER_ENABLED}) add_spvtools_unittest( TARGET timer @@ -185,42 +184,11 @@ add_spvtools_unittest( LIBS ${SPIRV_TOOLS}) endif() -add_spvtools_unittest( - TARGET log - SRCS log_test.cpp - LIBS ${SPIRV_TOOLS}) -add_spvtools_unittest( - TARGET preserve_numeric_ids - SRCS preserve_numeric_ids_test.cpp - LIBS ${SPIRV_TOOLS}) - -add_spvtools_unittest( - TARGET bit_stream - SRCS bit_stream.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/../source/comp/bit_stream.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/../source/comp/bit_stream.h - LIBS ${SPIRV_TOOLS}) - -add_spvtools_unittest( - TARGET huffman_codec - SRCS huffman_codec.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/../source/comp/bit_stream.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/../source/comp/bit_stream.h - ${CMAKE_CURRENT_SOURCE_DIR}/../source/comp/huffman_codec.h - LIBS ${SPIRV_TOOLS}) - -add_spvtools_unittest( - TARGET move_to_front - SRCS move_to_front_test.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/../source/comp/move_to_front.h - ${CMAKE_CURRENT_SOURCE_DIR}/../source/comp/move_to_front.cpp - LIBS ${SPIRV_TOOLS}) - -add_subdirectory(comp) add_subdirectory(link) add_subdirectory(opt) -add_subdirectory(stats) +add_subdirectory(reduce) +add_subdirectory(fuzz) add_subdirectory(tools) add_subdirectory(util) add_subdirectory(val) diff --git a/third_party/spirv-tools/test/assembly_context_test.cpp b/third_party/spirv-tools/test/assembly_context_test.cpp index b6d60b95d9..c8aa06be71 100644 --- a/third_party/spirv-tools/test/assembly_context_test.cpp +++ b/third_party/spirv-tools/test/assembly_context_test.cpp @@ -17,6 +17,7 @@ #include "gmock/gmock.h" #include "source/instruction.h" +#include "source/util/string_utils.h" #include "test/unit_spirv.h" namespace spvtools { @@ -40,13 +41,12 @@ TEST_P(EncodeStringTest, Sample) { ASSERT_EQ(SPV_SUCCESS, context.binaryEncodeString(GetParam().str.c_str(), &inst)); // We already trust MakeVector - EXPECT_THAT(inst.words, - Eq(Concatenate({GetParam().initial_contents, - spvtest::MakeVector(GetParam().str)}))); + EXPECT_THAT(inst.words, Eq(Concatenate({GetParam().initial_contents, + utils::MakeVector(GetParam().str)}))); } // clang-format off -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( BinaryEncodeString, EncodeStringTest, ::testing::ValuesIn(std::vector{ // Use cases that exercise at least one to two words, @@ -70,7 +70,7 @@ INSTANTIATE_TEST_CASE_P( // A very long string, encoded after an initial word. // SPIR-V limits strings to 65535 characters. {std::string(65535, 'a'), {1}}, - }),); + })); // clang-format on } // namespace diff --git a/third_party/spirv-tools/test/assembly_format_test.cpp b/third_party/spirv-tools/test/assembly_format_test.cpp index 59e500b813..718e6d3ced 100644 --- a/third_party/spirv-tools/test/assembly_format_test.cpp +++ b/third_party/spirv-tools/test/assembly_format_test.cpp @@ -20,7 +20,7 @@ namespace { using spvtest::ScopedContext; using spvtest::TextToBinaryTest; -TEST_F(TextToBinaryTest, NotPlacingResultIDAtTheBeginning) { +TEST_F(TextToBinaryTest, InstOpcodeProducesResultIDButNoIDDefinedFails) { SetText("OpTypeMatrix %1 %2 1000"); EXPECT_EQ(SPV_ERROR_INVALID_TEXT, spvTextToBinary(ScopedContext().context, text.str, text.length, @@ -33,5 +33,18 @@ TEST_F(TextToBinaryTest, NotPlacingResultIDAtTheBeginning) { EXPECT_EQ(0u, diagnostic->position.line); } +TEST_F(TextToBinaryTest, + InstDefinesResultIDButOpcodeDoesNotProduceAResultFails) { + SetText("\n\n%foo = OpName %1 \"bar\""); + EXPECT_EQ(SPV_ERROR_INVALID_TEXT, + spvTextToBinary(ScopedContext().context, text.str, text.length, + &binary, &diagnostic)); + ASSERT_NE(nullptr, diagnostic); + EXPECT_STREQ( + "Cannot set ID %foo because OpName does not produce a result ID.", + diagnostic->error); + EXPECT_EQ(2u, diagnostic->position.line); +} + } // namespace } // namespace svptools diff --git a/third_party/spirv-tools/test/binary_header_get_test.cpp b/third_party/spirv-tools/test/binary_header_get_test.cpp index e771f1a39c..f8f6bdbd80 100644 --- a/third_party/spirv-tools/test/binary_header_get_test.cpp +++ b/third_party/spirv-tools/test/binary_header_get_test.cpp @@ -51,7 +51,8 @@ TEST_F(BinaryHeaderGet, Default) { ASSERT_EQ(SPV_SUCCESS, spvBinaryHeaderGet(&const_bin, endian, &header)); ASSERT_EQ(static_cast(SpvMagicNumber), header.magic); - ASSERT_EQ(0x00010300u, header.version); + // Expect SPIRV-Headers updated to SPIR-V 1.5. + ASSERT_EQ(0x00010500u, header.version); ASSERT_EQ(static_cast(SPV_GENERATOR_CODEPLAY), header.generator); ASSERT_EQ(1u, header.bound); ASSERT_EQ(0u, header.schema); diff --git a/third_party/spirv-tools/test/binary_parse_test.cpp b/third_party/spirv-tools/test/binary_parse_test.cpp index 7d97001586..54664fce7c 100644 --- a/third_party/spirv-tools/test/binary_parse_test.cpp +++ b/third_party/spirv-tools/test/binary_parse_test.cpp @@ -21,6 +21,7 @@ #include "gmock/gmock.h" #include "source/latest_version_opencl_std_header.h" #include "source/table.h" +#include "source/util/string_utils.h" #include "test/test_fixture.h" #include "test/unit_spirv.h" @@ -39,7 +40,7 @@ namespace { using ::spvtest::Concatenate; using ::spvtest::MakeInstruction; -using ::spvtest::MakeVector; +using utils::MakeVector; using ::spvtest::ScopedContext; using ::testing::_; using ::testing::AnyOf; @@ -197,6 +198,8 @@ ParsedInstruction MakeParsedInt32TypeInstruction(uint32_t result_id) { class BinaryParseTest : public spvtest::TextToBinaryTestBase<::testing::Test> { protected: + ~BinaryParseTest() { spvDiagnosticDestroy(diagnostic_); } + void Parse(const SpirvVector& words, spv_result_t expected_result, bool flip_words = false) { SpirvVector flipped_words(words); @@ -267,52 +270,48 @@ TEST_F(BinaryParseTest, NullDiagnosticsIsOkForBadParse) { TEST_F(BinaryParseTest, NullConsumerNullDiagnosticsForBadParse) { auto words = CompileSuccessfully(""); - auto ctx = spvContextCreate(SPV_ENV_UNIVERSAL_1_1); - SetContextMessageConsumer(ctx, nullptr); + auto ctx = spvtools::Context(SPV_ENV_UNIVERSAL_1_1); + ctx.SetMessageConsumer(nullptr); words.push_back(0xffffffff); // Certainly invalid instruction header. EXPECT_HEADER(1).WillOnce(Return(SPV_SUCCESS)); EXPECT_CALL(client_, Instruction(_)).Times(0); // No instruction callback. EXPECT_EQ(SPV_ERROR_INVALID_BINARY, - spvBinaryParse(ctx, &client_, words.data(), words.size(), + spvBinaryParse(ctx.CContext(), &client_, words.data(), words.size(), invoke_header, invoke_instruction, nullptr)); - - spvContextDestroy(ctx); } TEST_F(BinaryParseTest, SpecifyConsumerNullDiagnosticsForGoodParse) { const auto words = CompileSuccessfully(""); - auto ctx = spvContextCreate(SPV_ENV_UNIVERSAL_1_1); + auto ctx = spvtools::Context(SPV_ENV_UNIVERSAL_1_1); int invocation = 0; - SetContextMessageConsumer( - ctx, [&invocation](spv_message_level_t, const char*, - const spv_position_t&, const char*) { ++invocation; }); + ctx.SetMessageConsumer([&invocation](spv_message_level_t, const char*, + const spv_position_t&, + const char*) { ++invocation; }); EXPECT_HEADER(1).WillOnce(Return(SPV_SUCCESS)); EXPECT_CALL(client_, Instruction(_)).Times(0); // No instruction callback. EXPECT_EQ(SPV_SUCCESS, - spvBinaryParse(ctx, &client_, words.data(), words.size(), + spvBinaryParse(ctx.CContext(), &client_, words.data(), words.size(), invoke_header, invoke_instruction, nullptr)); EXPECT_EQ(0, invocation); - - spvContextDestroy(ctx); } TEST_F(BinaryParseTest, SpecifyConsumerNullDiagnosticsForBadParse) { auto words = CompileSuccessfully(""); - auto ctx = spvContextCreate(SPV_ENV_UNIVERSAL_1_1); + auto ctx = spvtools::Context(SPV_ENV_UNIVERSAL_1_1); int invocation = 0; - SetContextMessageConsumer( - ctx, [&invocation](spv_message_level_t level, const char* source, - const spv_position_t& position, const char* message) { + ctx.SetMessageConsumer( + [&invocation](spv_message_level_t level, const char* source, + const spv_position_t& position, const char* message) { ++invocation; EXPECT_EQ(SPV_MSG_ERROR, level); EXPECT_STREQ("input", source); EXPECT_EQ(0u, position.line); EXPECT_EQ(0u, position.column); - EXPECT_EQ(5u, position.index); + EXPECT_EQ(1u, position.index); EXPECT_STREQ("Invalid opcode: 65535", message); }); @@ -320,52 +319,46 @@ TEST_F(BinaryParseTest, SpecifyConsumerNullDiagnosticsForBadParse) { EXPECT_HEADER(1).WillOnce(Return(SPV_SUCCESS)); EXPECT_CALL(client_, Instruction(_)).Times(0); // No instruction callback. EXPECT_EQ(SPV_ERROR_INVALID_BINARY, - spvBinaryParse(ctx, &client_, words.data(), words.size(), + spvBinaryParse(ctx.CContext(), &client_, words.data(), words.size(), invoke_header, invoke_instruction, nullptr)); EXPECT_EQ(1, invocation); - - spvContextDestroy(ctx); } TEST_F(BinaryParseTest, SpecifyConsumerSpecifyDiagnosticsForGoodParse) { const auto words = CompileSuccessfully(""); - auto ctx = spvContextCreate(SPV_ENV_UNIVERSAL_1_1); + auto ctx = spvtools::Context(SPV_ENV_UNIVERSAL_1_1); int invocation = 0; - SetContextMessageConsumer( - ctx, [&invocation](spv_message_level_t, const char*, - const spv_position_t&, const char*) { ++invocation; }); + ctx.SetMessageConsumer([&invocation](spv_message_level_t, const char*, + const spv_position_t&, + const char*) { ++invocation; }); EXPECT_HEADER(1).WillOnce(Return(SPV_SUCCESS)); EXPECT_CALL(client_, Instruction(_)).Times(0); // No instruction callback. EXPECT_EQ(SPV_SUCCESS, - spvBinaryParse(ctx, &client_, words.data(), words.size(), + spvBinaryParse(ctx.CContext(), &client_, words.data(), words.size(), invoke_header, invoke_instruction, &diagnostic_)); EXPECT_EQ(0, invocation); EXPECT_EQ(nullptr, diagnostic_); - - spvContextDestroy(ctx); } TEST_F(BinaryParseTest, SpecifyConsumerSpecifyDiagnosticsForBadParse) { auto words = CompileSuccessfully(""); - auto ctx = spvContextCreate(SPV_ENV_UNIVERSAL_1_1); + auto ctx = spvtools::Context(SPV_ENV_UNIVERSAL_1_1); int invocation = 0; - SetContextMessageConsumer( - ctx, [&invocation](spv_message_level_t, const char*, - const spv_position_t&, const char*) { ++invocation; }); + ctx.SetMessageConsumer([&invocation](spv_message_level_t, const char*, + const spv_position_t&, + const char*) { ++invocation; }); words.push_back(0xffffffff); // Certainly invalid instruction header. EXPECT_HEADER(1).WillOnce(Return(SPV_SUCCESS)); EXPECT_CALL(client_, Instruction(_)).Times(0); // No instruction callback. EXPECT_EQ(SPV_ERROR_INVALID_BINARY, - spvBinaryParse(ctx, &client_, words.data(), words.size(), + spvBinaryParse(ctx.CContext(), &client_, words.data(), words.size(), invoke_header, invoke_instruction, &diagnostic_)); EXPECT_EQ(0, invocation); EXPECT_STREQ("Invalid opcode: 65535", diagnostic_->error); - - spvContextDestroy(ctx); } TEST_F(BinaryParseTest, @@ -569,7 +562,7 @@ TEST_P(BinaryParseWordsAndCountDiagnosticTest, WordAndCountCases) { EXPECT_THAT(diagnostic->error, Eq(GetParam().expected_diagnostic)); } -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( BinaryParseDiagnostic, BinaryParseWordsAndCountDiagnosticTest, ::testing::ValuesIn(std::vector{ {nullptr, 0, "Missing module."}, @@ -583,7 +576,7 @@ INSTANTIATE_TEST_CASE_P( "Module has incomplete header: only 3 words instead of 5"}, {kHeaderForBound1, 4, "Module has incomplete header: only 4 words instead of 5"}, - }), ); + })); // A binary parser diagnostic test case where a vector of words is // provided. We'll use this to express cases that can't be created @@ -606,7 +599,7 @@ TEST_P(BinaryParseWordVectorDiagnosticTest, WordVectorCases) { EXPECT_THAT(diagnostic->error, Eq(GetParam().expected_diagnostic)); } -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( BinaryParseDiagnostic, BinaryParseWordVectorDiagnosticTest, ::testing::ValuesIn(std::vector{ {Concatenate({ExpectedHeaderForBound(1), {spvOpcodeMake(0, SpvOpNop)}}), @@ -824,7 +817,7 @@ INSTANTIATE_TEST_CASE_P( MakeInstruction(SpvOpConstant, {1, 2, 42}), }), "Type Id 1 is not a scalar numeric type"}, - }), ); + })); // A binary parser diagnostic case generated from an assembly text input. struct AssemblyDiagnosticCase { @@ -844,7 +837,7 @@ TEST_P(BinaryParseAssemblyDiagnosticTest, AssemblyCases) { EXPECT_THAT(diagnostic->error, Eq(GetParam().expected_diagnostic)); } -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( BinaryParseDiagnostic, BinaryParseAssemblyDiagnosticTest, ::testing::ValuesIn(std::vector{ {"%1 = OpConstant !0 42", "Error: Type Id is 0"}, @@ -890,11 +883,11 @@ INSTANTIATE_TEST_CASE_P( "Invalid function control operand: 31 has invalid mask component 16"}, {"OpLoopMerge %1 %2 !1027", "Invalid loop control operand: 1027 has invalid mask component 1024"}, - {"%2 = OpImageFetch %1 %image %coord !511", - "Invalid image operand: 511 has invalid mask component 256"}, + {"%2 = OpImageFetch %1 %image %coord !32770", + "Invalid image operand: 32770 has invalid mask component 32768"}, {"OpSelectionMerge %1 !7", "Invalid selection control operand: 7 has invalid mask component 4"}, - }), ); + })); } // namespace } // namespace spvtools diff --git a/third_party/spirv-tools/test/binary_to_text.literal_test.cpp b/third_party/spirv-tools/test/binary_to_text.literal_test.cpp index bcfb0f016d..02daac761b 100644 --- a/third_party/spirv-tools/test/binary_to_text.literal_test.cpp +++ b/third_party/spirv-tools/test/binary_to_text.literal_test.cpp @@ -32,7 +32,7 @@ TEST_P(RoundTripLiteralsTest, Sample) { } // clang-format off -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( StringLiterals, RoundTripLiteralsTest, ::testing::ValuesIn(std::vector{ "OpName %1 \"\"\n", // empty @@ -49,7 +49,7 @@ INSTANTIATE_TEST_CASE_P( "OpName %1 \"\\\"foo\nbar\\\"\"\n", // escaped quote "OpName %1 \"\\\\foo\nbar\\\\\"\n", // escaped backslash "OpName %1 \"\xE4\xBA\xB2\"\n", // UTF-8 - }),); + })); // clang-format on using RoundTripSpecialCaseLiteralsTest = spvtest::TextToBinaryTestBase< @@ -63,13 +63,13 @@ TEST_P(RoundTripSpecialCaseLiteralsTest, Sample) { } // clang-format off -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( StringLiterals, RoundTripSpecialCaseLiteralsTest, ::testing::ValuesIn(std::vector>{ {"OpName %1 \"\\foo\"\n", "OpName %1 \"foo\"\n"}, // Escape f {"OpName %1 \"\\\nfoo\"\n", "OpName %1 \"\nfoo\"\n"}, // Escape newline {"OpName %1 \"\\\xE4\xBA\xB2\"\n", "OpName %1 \"\xE4\xBA\xB2\"\n"}, // Escape utf-8 - }),); + })); // clang-format on } // namespace diff --git a/third_party/spirv-tools/test/binary_to_text_test.cpp b/third_party/spirv-tools/test/binary_to_text_test.cpp index 016041f492..e8a02fd59b 100644 --- a/third_party/spirv-tools/test/binary_to_text_test.cpp +++ b/third_party/spirv-tools/test/binary_to_text_test.cpp @@ -34,8 +34,12 @@ using ::testing::HasSubstr; class BinaryToText : public ::testing::Test { public: - BinaryToText() : context(spvContextCreate(SPV_ENV_UNIVERSAL_1_0)) {} - ~BinaryToText() { spvContextDestroy(context); } + BinaryToText() + : context(spvContextCreate(SPV_ENV_UNIVERSAL_1_0)), binary(nullptr) {} + ~BinaryToText() { + spvBinaryDestroy(binary); + spvContextDestroy(context); + } virtual void SetUp() { const char* textStr = R"( @@ -63,17 +67,20 @@ class BinaryToText : public ::testing::Test { spv_diagnostic diagnostic = nullptr; spv_result_t error = spvTextToBinary(context, text.str, text.length, &binary, &diagnostic); - if (error) { - spvDiagnosticPrint(diagnostic); - spvDiagnosticDestroy(diagnostic); - ASSERT_EQ(SPV_SUCCESS, error); - } + spvDiagnosticPrint(diagnostic); + spvDiagnosticDestroy(diagnostic); + ASSERT_EQ(SPV_SUCCESS, error); } - virtual void TearDown() { spvBinaryDestroy(binary); } + virtual void TearDown() { + spvBinaryDestroy(binary); + binary = nullptr; + } // Compiles the given assembly text, and saves it into 'binary'. void CompileSuccessfully(std::string text) { + spvBinaryDestroy(binary); + binary = nullptr; spv_diagnostic diagnostic = nullptr; EXPECT_EQ(SPV_SUCCESS, spvTextToBinary(context, text.c_str(), text.size(), &binary, &diagnostic)); @@ -164,7 +171,7 @@ TEST_P(BinaryToTextFail, EncodeSuccessfullyDecodeFailed) { Eq(GetParam().expected_error_message)); } -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( InvalidIds, BinaryToTextFail, ::testing::ValuesIn(std::vector{ {"", spvtest::MakeInstruction(SpvOpTypeVoid, {0}), @@ -189,9 +196,9 @@ INSTANTIATE_TEST_CASE_P( "%2 = OpTypeVector %1 4", spvtest::MakeInstruction(SpvOpConstant, {2, 3, 999}), "Type Id 2 is not a scalar numeric type"}, - }), ); + })); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( InvalidIdsCheckedDuringLiteralCaseParsing, BinaryToTextFail, ::testing::ValuesIn(std::vector{ {"", spvtest::MakeInstruction(SpvOpSwitch, {1, 2, 3, 4}), @@ -205,7 +212,7 @@ INSTANTIATE_TEST_CASE_P( {"%1 = OpTypeFloat 32\n%2 = OpConstant %1 1.5", spvtest::MakeInstruction(SpvOpSwitch, {2, 3, 4, 5}), "Invalid OpSwitch: selector id 2 is not a scalar integer"}, - }), ); + })); TEST_F(TextToBinaryTest, OneInstruction) { const std::string input = "OpSource OpenCL_C 12\n"; @@ -236,7 +243,7 @@ TEST_P(RoundTripInstructionsTest, Sample) { } // clang-format off -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( NumericLiterals, RoundTripInstructionsTest, // This test is independent of environment, so just test the one. Combine(::testing::Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1, @@ -268,10 +275,10 @@ INSTANTIATE_TEST_CASE_P( "%1 = OpTypeFloat 64\n%2 = OpConstant %1 -0x1.0002p+1024\n", // NaN "%1 = OpTypeFloat 64\n%2 = OpConstant %1 0x1p+1024\n", // Inf "%1 = OpTypeFloat 64\n%2 = OpConstant %1 -0x1p+1024\n", // -Inf - })), ); + }))); // clang-format on -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( MemoryAccessMasks, RoundTripInstructionsTest, Combine(::testing::Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1, SPV_ENV_UNIVERSAL_1_2, SPV_ENV_UNIVERSAL_1_3), @@ -285,9 +292,9 @@ INSTANTIATE_TEST_CASE_P( "OpStore %1 %2 Volatile|Aligned 16\n", "OpStore %1 %2 Volatile|Nontemporal\n", "OpStore %1 %2 Volatile|Aligned|Nontemporal 32\n", - })), ); + }))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( FPFastMathModeMasks, RoundTripInstructionsTest, Combine( ::testing::Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1, @@ -303,9 +310,9 @@ INSTANTIATE_TEST_CASE_P( "OpDecorate %1 FPFastMathMode NotNaN|NotInf\n", "OpDecorate %1 FPFastMathMode NSZ|AllowRecip\n", "OpDecorate %1 FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|Fast\n", - })), ); + }))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( LoopControlMasks, RoundTripInstructionsTest, Combine(::testing::Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1, SPV_ENV_UNIVERSAL_1_3, SPV_ENV_UNIVERSAL_1_2), @@ -314,18 +321,18 @@ INSTANTIATE_TEST_CASE_P( "OpLoopMerge %1 %2 Unroll\n", "OpLoopMerge %1 %2 DontUnroll\n", "OpLoopMerge %1 %2 Unroll|DontUnroll\n", - })), ); + }))); -INSTANTIATE_TEST_CASE_P(LoopControlMasksV11, RoundTripInstructionsTest, - Combine(::testing::Values(SPV_ENV_UNIVERSAL_1_1, - SPV_ENV_UNIVERSAL_1_2, - SPV_ENV_UNIVERSAL_1_3), - ::testing::ValuesIn(std::vector{ - "OpLoopMerge %1 %2 DependencyInfinite\n", - "OpLoopMerge %1 %2 DependencyLength 8\n", - })), ); +INSTANTIATE_TEST_SUITE_P(LoopControlMasksV11, RoundTripInstructionsTest, + Combine(::testing::Values(SPV_ENV_UNIVERSAL_1_1, + SPV_ENV_UNIVERSAL_1_2, + SPV_ENV_UNIVERSAL_1_3), + ::testing::ValuesIn(std::vector{ + "OpLoopMerge %1 %2 DependencyInfinite\n", + "OpLoopMerge %1 %2 DependencyLength 8\n", + }))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SelectionControlMasks, RoundTripInstructionsTest, Combine(::testing::Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1, SPV_ENV_UNIVERSAL_1_3, SPV_ENV_UNIVERSAL_1_2), @@ -334,9 +341,9 @@ INSTANTIATE_TEST_CASE_P( "OpSelectionMerge %1 Flatten\n", "OpSelectionMerge %1 DontFlatten\n", "OpSelectionMerge %1 Flatten|DontFlatten\n", - })), ); + }))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( FunctionControlMasks, RoundTripInstructionsTest, Combine(::testing::Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1, SPV_ENV_UNIVERSAL_1_2, SPV_ENV_UNIVERSAL_1_3), @@ -348,9 +355,9 @@ INSTANTIATE_TEST_CASE_P( "%2 = OpFunction %1 Const %3\n", "%2 = OpFunction %1 Inline|Pure|Const %3\n", "%2 = OpFunction %1 DontInline|Const %3\n", - })), ); + }))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( ImageMasks, RoundTripInstructionsTest, Combine(::testing::Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1, SPV_ENV_UNIVERSAL_1_2, SPV_ENV_UNIVERSAL_1_3), @@ -371,9 +378,9 @@ INSTANTIATE_TEST_CASE_P( "%2 = OpImageFetch %1 %3 %4 Sample|MinLod %5 %6\n", "%2 = OpImageFetch %1 %3 %4" " Bias|Lod|Grad|ConstOffset|Offset|ConstOffsets|Sample|MinLod" - " %5 %6 %7 %8 %9 %10 %11 %12 %13\n"})), ); + " %5 %6 %7 %8 %9 %10 %11 %12 %13\n"}))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( NewInstructionsInSPIRV1_2, RoundTripInstructionsTest, Combine(::testing::Values(SPV_ENV_UNIVERSAL_1_2, SPV_ENV_UNIVERSAL_1_3), ::testing::ValuesIn(std::vector{ @@ -382,7 +389,7 @@ INSTANTIATE_TEST_CASE_P( "OpExecutionModeId %1 LocalSizeHintId %2\n", "OpDecorateId %1 AlignmentId %2\n", "OpDecorateId %1 MaxByteOffsetId %2\n", - })), ); + }))); using MaskSorting = TextToBinaryTest; @@ -530,23 +537,23 @@ TEST_P(GeneratorStringTest, Sample) { spvTextDestroy(decoded_text); } -INSTANTIATE_TEST_CASE_P(GeneratorStrings, GeneratorStringTest, - ::testing::ValuesIn(std::vector{ - {SPV_GENERATOR_KHRONOS, 12, "Khronos; 12"}, - {SPV_GENERATOR_LUNARG, 99, "LunarG; 99"}, - {SPV_GENERATOR_VALVE, 1, "Valve; 1"}, - {SPV_GENERATOR_CODEPLAY, 65535, "Codeplay; 65535"}, - {SPV_GENERATOR_NVIDIA, 19, "NVIDIA; 19"}, - {SPV_GENERATOR_ARM, 1000, "ARM; 1000"}, - {SPV_GENERATOR_KHRONOS_LLVM_TRANSLATOR, 38, - "Khronos LLVM/SPIR-V Translator; 38"}, - {SPV_GENERATOR_KHRONOS_ASSEMBLER, 2, - "Khronos SPIR-V Tools Assembler; 2"}, - {SPV_GENERATOR_KHRONOS_GLSLANG, 1, - "Khronos Glslang Reference Front End; 1"}, - {1000, 18, "Unknown(1000); 18"}, - {65535, 32767, "Unknown(65535); 32767"}, - }), ); +INSTANTIATE_TEST_SUITE_P(GeneratorStrings, GeneratorStringTest, + ::testing::ValuesIn(std::vector{ + {SPV_GENERATOR_KHRONOS, 12, "Khronos; 12"}, + {SPV_GENERATOR_LUNARG, 99, "LunarG; 99"}, + {SPV_GENERATOR_VALVE, 1, "Valve; 1"}, + {SPV_GENERATOR_CODEPLAY, 65535, "Codeplay; 65535"}, + {SPV_GENERATOR_NVIDIA, 19, "NVIDIA; 19"}, + {SPV_GENERATOR_ARM, 1000, "ARM; 1000"}, + {SPV_GENERATOR_KHRONOS_LLVM_TRANSLATOR, 38, + "Khronos LLVM/SPIR-V Translator; 38"}, + {SPV_GENERATOR_KHRONOS_ASSEMBLER, 2, + "Khronos SPIR-V Tools Assembler; 2"}, + {SPV_GENERATOR_KHRONOS_GLSLANG, 1, + "Khronos Glslang Reference Front End; 1"}, + {1000, 18, "Unknown(1000); 18"}, + {65535, 32767, "Unknown(65535); 32767"}, + })); // TODO(dneto): Test new instructions and enums in SPIR-V 1.3 diff --git a/third_party/spirv-tools/test/bit_stream.cpp b/third_party/spirv-tools/test/bit_stream.cpp deleted file mode 100644 index f02faf3c6e..0000000000 --- a/third_party/spirv-tools/test/bit_stream.cpp +++ /dev/null @@ -1,1025 +0,0 @@ -// Copyright (c) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include -#include -#include -#include - -#include "gmock/gmock.h" -#include "source/comp/bit_stream.h" - -namespace spvtools { -namespace comp { -namespace { - -// Converts |buffer| to a stream of '0' and '1'. -template -std::string BufferToStream(const std::vector& buffer) { - std::stringstream ss; - for (auto it = buffer.begin(); it != buffer.end(); ++it) { - std::string str = std::bitset(*it).to_string(); - // Strings generated by std::bitset::to_string are read right to left. - // Reversing to left to right. - std::reverse(str.begin(), str.end()); - ss << str; - } - return ss.str(); -} - -// Converts a left-to-right input string of '0' and '1' to a buffer of |T| -// words. -template -std::vector StreamToBuffer(std::string str) { - // The input string is left-to-right, the input argument of std::bitset needs - // to right-to-left. Instead of reversing tokens, reverse the entire string - // and iterate tokens from end to begin. - std::reverse(str.begin(), str.end()); - const int word_size = static_cast(sizeof(T) * 8); - const int str_length = static_cast(str.length()); - std::vector buffer; - buffer.reserve(NumBitsToNumWords(str.length())); - for (int index = str_length - word_size; index >= 0; index -= word_size) { - buffer.push_back(static_cast( - std::bitset(str, index, word_size).to_ullong())); - } - const size_t suffix_length = str.length() % word_size; - if (suffix_length != 0) { - buffer.push_back(static_cast( - std::bitset(str, 0, suffix_length).to_ullong())); - } - return buffer; -} - -// Adds '0' chars at the end of the string until the size is a multiple of N. -template -std::string PadToWord(std::string&& str) { - const size_t tail_length = str.size() % N; - if (tail_length != 0) str += std::string(N - tail_length, '0'); - return std::move(str); -} - -// Adds '0' chars at the end of the string until the size is a multiple of N. -template -std::string PadToWord(const std::string& str) { - return PadToWord(std::string(str)); -} - -// Converts a left-to-right stream of bits to std::bitset. -template -std::bitset StreamToBitset(std::string str) { - std::reverse(str.begin(), str.end()); - return std::bitset(str); -} - -// Converts a left-to-right stream of bits to uint64. -uint64_t StreamToBits(std::string str) { - std::reverse(str.begin(), str.end()); - return std::bitset<64>(str).to_ullong(); -} - -// A simple and inefficient implementatition of BitWriterInterface, -// using std::stringstream. Intended for tests only. -class BitWriterStringStream : public BitWriterInterface { - public: - void WriteBits(uint64_t bits, size_t num_bits) override { - assert(num_bits <= 64); - ss_ << BitsToStream(bits, num_bits); - } - - size_t GetNumBits() const override { return ss_.str().size(); } - - std::vector GetDataCopy() const override { - return StreamToBuffer(ss_.str()); - } - - std::string GetStreamRaw() const { return ss_.str(); } - - private: - std::stringstream ss_; -}; - -// A simple and inefficient implementatition of BitReaderInterface. -// Intended for tests only. -class BitReaderFromString : public BitReaderInterface { - public: - explicit BitReaderFromString(std::string&& str) - : str_(std::move(str)), pos_(0) {} - - explicit BitReaderFromString(const std::vector& buffer) - : str_(BufferToStream(buffer)), pos_(0) {} - - explicit BitReaderFromString(const std::vector& buffer) - : str_(PadToWord<64>(BufferToStream(buffer))), pos_(0) {} - - size_t ReadBits(uint64_t* bits, size_t num_bits) override { - if (ReachedEnd()) return 0; - std::string sub = str_.substr(pos_, num_bits); - *bits = StreamToBits(sub); - pos_ += sub.length(); - return sub.length(); - } - - size_t GetNumReadBits() const override { return pos_; } - - bool ReachedEnd() const override { return pos_ >= str_.length(); } - - private: - std::string str_; - size_t pos_; -}; - -TEST(NumBitsToNumWords, Word8) { - EXPECT_EQ(0u, NumBitsToNumWords<8>(0)); - EXPECT_EQ(1u, NumBitsToNumWords<8>(1)); - EXPECT_EQ(1u, NumBitsToNumWords<8>(7)); - EXPECT_EQ(1u, NumBitsToNumWords<8>(8)); - EXPECT_EQ(2u, NumBitsToNumWords<8>(9)); - EXPECT_EQ(2u, NumBitsToNumWords<8>(16)); - EXPECT_EQ(3u, NumBitsToNumWords<8>(17)); - EXPECT_EQ(3u, NumBitsToNumWords<8>(23)); - EXPECT_EQ(3u, NumBitsToNumWords<8>(24)); - EXPECT_EQ(4u, NumBitsToNumWords<8>(25)); -} - -TEST(NumBitsToNumWords, Word64) { - EXPECT_EQ(0u, NumBitsToNumWords<64>(0)); - EXPECT_EQ(1u, NumBitsToNumWords<64>(1)); - EXPECT_EQ(1u, NumBitsToNumWords<64>(64)); - EXPECT_EQ(2u, NumBitsToNumWords<64>(65)); - EXPECT_EQ(2u, NumBitsToNumWords<64>(128)); - EXPECT_EQ(3u, NumBitsToNumWords<64>(129)); -} - -TEST(ZigZagCoding, Encode0) { - EXPECT_EQ(0u, EncodeZigZag(0, 0)); - EXPECT_EQ(1u, EncodeZigZag(-1, 0)); - EXPECT_EQ(2u, EncodeZigZag(1, 0)); - EXPECT_EQ(3u, EncodeZigZag(-2, 0)); - EXPECT_EQ(std::numeric_limits::max() - 1, - EncodeZigZag(std::numeric_limits::max(), 0)); - EXPECT_EQ(std::numeric_limits::max(), - EncodeZigZag(std::numeric_limits::min(), 0)); -} - -TEST(ZigZagCoding, Decode0) { - EXPECT_EQ(0, DecodeZigZag(0, 0)); - EXPECT_EQ(-1, DecodeZigZag(1, 0)); - EXPECT_EQ(1, DecodeZigZag(2, 0)); - EXPECT_EQ(-2, DecodeZigZag(3, 0)); - EXPECT_EQ(std::numeric_limits::min(), - DecodeZigZag(std::numeric_limits::max(), 0)); - EXPECT_EQ(std::numeric_limits::max(), - DecodeZigZag(std::numeric_limits::max() - 1, 0)); -} - -TEST(ZigZagCoding, Encode1) { - EXPECT_EQ(0u, EncodeZigZag(0, 1)); - EXPECT_EQ(1u, EncodeZigZag(1, 1)); - EXPECT_EQ(2u, EncodeZigZag(-1, 1)); - EXPECT_EQ(3u, EncodeZigZag(-2, 1)); - EXPECT_EQ(4u, EncodeZigZag(2, 1)); - EXPECT_EQ(5u, EncodeZigZag(3, 1)); - EXPECT_EQ(6u, EncodeZigZag(-3, 1)); - EXPECT_EQ(7u, EncodeZigZag(-4, 1)); - EXPECT_EQ(std::numeric_limits::max() - 2, - EncodeZigZag(std::numeric_limits::max(), 1)); - EXPECT_EQ(std::numeric_limits::max() - 1, - EncodeZigZag(std::numeric_limits::min() + 1, 1)); - EXPECT_EQ(std::numeric_limits::max(), - EncodeZigZag(std::numeric_limits::min(), 1)); -} - -TEST(ZigZagCoding, Decode1) { - EXPECT_EQ(0, DecodeZigZag(0, 1)); - EXPECT_EQ(1, DecodeZigZag(1, 1)); - EXPECT_EQ(-1, DecodeZigZag(2, 1)); - EXPECT_EQ(-2, DecodeZigZag(3, 1)); - EXPECT_EQ(2, DecodeZigZag(4, 1)); - EXPECT_EQ(3, DecodeZigZag(5, 1)); - EXPECT_EQ(-3, DecodeZigZag(6, 1)); - EXPECT_EQ(-4, DecodeZigZag(7, 1)); - EXPECT_EQ(std::numeric_limits::min(), - DecodeZigZag(std::numeric_limits::max(), 1)); - EXPECT_EQ(std::numeric_limits::min() + 1, - DecodeZigZag(std::numeric_limits::max() - 1, 1)); - EXPECT_EQ(std::numeric_limits::max(), - DecodeZigZag(std::numeric_limits::max() - 2, 1)); -} - -TEST(ZigZagCoding, Encode2) { - EXPECT_EQ(0u, EncodeZigZag(0, 2)); - EXPECT_EQ(1u, EncodeZigZag(1, 2)); - EXPECT_EQ(2u, EncodeZigZag(2, 2)); - EXPECT_EQ(3u, EncodeZigZag(3, 2)); - EXPECT_EQ(4u, EncodeZigZag(-1, 2)); - EXPECT_EQ(5u, EncodeZigZag(-2, 2)); - EXPECT_EQ(6u, EncodeZigZag(-3, 2)); - EXPECT_EQ(7u, EncodeZigZag(-4, 2)); - EXPECT_EQ(8u, EncodeZigZag(4, 2)); - EXPECT_EQ(9u, EncodeZigZag(5, 2)); - EXPECT_EQ(10u, EncodeZigZag(6, 2)); - EXPECT_EQ(11u, EncodeZigZag(7, 2)); - EXPECT_EQ(12u, EncodeZigZag(-5, 2)); - EXPECT_EQ(13u, EncodeZigZag(-6, 2)); - EXPECT_EQ(14u, EncodeZigZag(-7, 2)); - EXPECT_EQ(15u, EncodeZigZag(-8, 2)); - EXPECT_EQ(std::numeric_limits::max() - 4, - EncodeZigZag(std::numeric_limits::max(), 2)); - EXPECT_EQ(std::numeric_limits::max() - 3, - EncodeZigZag(std::numeric_limits::min() + 3, 2)); - EXPECT_EQ(std::numeric_limits::max() - 2, - EncodeZigZag(std::numeric_limits::min() + 2, 2)); - EXPECT_EQ(std::numeric_limits::max() - 1, - EncodeZigZag(std::numeric_limits::min() + 1, 2)); - EXPECT_EQ(std::numeric_limits::max(), - EncodeZigZag(std::numeric_limits::min(), 2)); -} - -TEST(ZigZagCoding, Decode2) { - EXPECT_EQ(0, DecodeZigZag(0, 2)); - EXPECT_EQ(1, DecodeZigZag(1, 2)); - EXPECT_EQ(2, DecodeZigZag(2, 2)); - EXPECT_EQ(3, DecodeZigZag(3, 2)); - EXPECT_EQ(-1, DecodeZigZag(4, 2)); - EXPECT_EQ(-2, DecodeZigZag(5, 2)); - EXPECT_EQ(-3, DecodeZigZag(6, 2)); - EXPECT_EQ(-4, DecodeZigZag(7, 2)); - EXPECT_EQ(4, DecodeZigZag(8, 2)); - EXPECT_EQ(5, DecodeZigZag(9, 2)); - EXPECT_EQ(6, DecodeZigZag(10, 2)); - EXPECT_EQ(7, DecodeZigZag(11, 2)); - EXPECT_EQ(-5, DecodeZigZag(12, 2)); - EXPECT_EQ(-6, DecodeZigZag(13, 2)); - EXPECT_EQ(-7, DecodeZigZag(14, 2)); - EXPECT_EQ(-8, DecodeZigZag(15, 2)); - EXPECT_EQ(std::numeric_limits::min(), - DecodeZigZag(std::numeric_limits::max(), 2)); - EXPECT_EQ(std::numeric_limits::min() + 1, - DecodeZigZag(std::numeric_limits::max() - 1, 2)); - EXPECT_EQ(std::numeric_limits::min() + 2, - DecodeZigZag(std::numeric_limits::max() - 2, 2)); - EXPECT_EQ(std::numeric_limits::min() + 3, - DecodeZigZag(std::numeric_limits::max() - 3, 2)); - EXPECT_EQ(std::numeric_limits::max(), - DecodeZigZag(std::numeric_limits::max() - 4, 2)); -} - -TEST(ZigZagCoding, Encode63) { - EXPECT_EQ(0u, EncodeZigZag(0, 63)); - - for (int64_t i = 0; i < 0xFFFFFFFF; i += 1234567) { - const int64_t positive_val = GetLowerBits(i * i * i + i * i, 63) | 1UL; - ASSERT_EQ(static_cast(positive_val), - EncodeZigZag(positive_val, 63)); - ASSERT_EQ((1ULL << 63) - 1 + positive_val, EncodeZigZag(-positive_val, 63)); - } - - EXPECT_EQ((1ULL << 63) - 1, - EncodeZigZag(std::numeric_limits::max(), 63)); - EXPECT_EQ(std::numeric_limits::max() - 1, - EncodeZigZag(std::numeric_limits::min() + 1, 63)); - EXPECT_EQ(std::numeric_limits::max(), - EncodeZigZag(std::numeric_limits::min(), 63)); -} - -TEST(BufToStream, UInt8_Empty) { - const std::string expected_bits = ""; - std::vector buffer = StreamToBuffer(expected_bits); - EXPECT_TRUE(buffer.empty()); - const std::string result_bits = BufferToStream(buffer); - EXPECT_EQ(expected_bits, result_bits); -} - -TEST(BufToStream, UInt8_OneWord) { - const std::string expected_bits = "00101100"; - std::vector buffer = StreamToBuffer(expected_bits); - EXPECT_EQ(std::vector({static_cast( - StreamToBitset<8>(expected_bits).to_ulong())}), - buffer); - const std::string result_bits = BufferToStream(buffer); - EXPECT_EQ(expected_bits, result_bits); -} - -TEST(BufToStream, UInt8_MultipleWords) { - const std::string expected_bits = - "00100010" - "01101010" - "01111101" - "00100010"; - std::vector buffer = StreamToBuffer(expected_bits); - EXPECT_EQ(std::vector({ - static_cast(StreamToBitset<8>("00100010").to_ulong()), - static_cast(StreamToBitset<8>("01101010").to_ulong()), - static_cast(StreamToBitset<8>("01111101").to_ulong()), - static_cast(StreamToBitset<8>("00100010").to_ulong()), - }), - buffer); - const std::string result_bits = BufferToStream(buffer); - EXPECT_EQ(expected_bits, result_bits); -} - -TEST(BufToStream, UInt64_Empty) { - const std::string expected_bits = ""; - std::vector buffer = StreamToBuffer(expected_bits); - EXPECT_TRUE(buffer.empty()); - const std::string result_bits = BufferToStream(buffer); - EXPECT_EQ(expected_bits, result_bits); -} - -TEST(BufToStream, UInt64_OneWord) { - const std::string expected_bits = - "0001000111101110011001101010101000100010110011000100010010001000"; - std::vector buffer = StreamToBuffer(expected_bits); - ASSERT_EQ(1u, buffer.size()); - EXPECT_EQ(0x1122334455667788u, buffer[0]); - const std::string result_bits = BufferToStream(buffer); - EXPECT_EQ(expected_bits, result_bits); -} - -TEST(BufToStream, UInt64_Unaligned) { - const std::string expected_bits = - "0010001001101010011111010010001001001010000111110010010010010101" - "0010001001101010011111111111111111111111"; - std::vector buffer = StreamToBuffer(expected_bits); - EXPECT_EQ(std::vector({ - StreamToBits(expected_bits.substr(0, 64)), - StreamToBits(expected_bits.substr(64, 64)), - }), - buffer); - const std::string result_bits = BufferToStream(buffer); - EXPECT_EQ(PadToWord<64>(expected_bits), result_bits); -} - -TEST(BufToStream, UInt64_MultipleWords) { - const std::string expected_bits = - "0010001001101010011111010010001001001010000111110010010010010101" - "0010001001101010011111111111111111111111000111110010010010010111" - "0000000000000000000000000000000000000000000000000010010011111111"; - std::vector buffer = StreamToBuffer(expected_bits); - EXPECT_EQ(std::vector({ - StreamToBits(expected_bits.substr(0, 64)), - StreamToBits(expected_bits.substr(64, 64)), - StreamToBits(expected_bits.substr(128, 64)), - }), - buffer); - const std::string result_bits = BufferToStream(buffer); - EXPECT_EQ(expected_bits, result_bits); -} - -TEST(PadToWord, Test) { - EXPECT_EQ("10100000", PadToWord<8>("101")); - EXPECT_EQ( - "10100000" - "00000000", - PadToWord<16>("101")); - EXPECT_EQ( - "10100000" - "00000000" - "00000000" - "00000000", - PadToWord<32>("101")); - EXPECT_EQ( - "10100000" - "00000000" - "00000000" - "00000000" - "00000000" - "00000000" - "00000000" - "00000000", - PadToWord<64>("101")); -} - -TEST(BitWriterStringStream, Empty) { - BitWriterStringStream writer; - EXPECT_EQ(0u, writer.GetNumBits()); - EXPECT_EQ(0u, writer.GetDataSizeBytes()); - EXPECT_EQ("", writer.GetStreamRaw()); -} - -TEST(BitWriterStringStream, WriteBits) { - BitWriterStringStream writer; - const uint64_t bits1 = 0x1 | 0x2 | 0x10; - writer.WriteBits(bits1, 5); - EXPECT_EQ(5u, writer.GetNumBits()); - EXPECT_EQ(1u, writer.GetDataSizeBytes()); - EXPECT_EQ("11001", writer.GetStreamRaw()); -} - -TEST(BitWriterStringStream, WriteUnencodedU8) { - BitWriterStringStream writer; - const uint8_t bits = 127; - writer.WriteUnencoded(bits); - EXPECT_EQ(8u, writer.GetNumBits()); - EXPECT_EQ("11111110", writer.GetStreamRaw()); -} - -TEST(BitWriterStringStream, WriteUnencodedS64) { - BitWriterStringStream writer; - const int64_t bits = std::numeric_limits::min() + 7; - writer.WriteUnencoded(bits); - EXPECT_EQ(64u, writer.GetNumBits()); - EXPECT_EQ("1110000000000000000000000000000000000000000000000000000000000001", - writer.GetStreamRaw()); -} - -TEST(BitWriterStringStream, WriteMultiple) { - BitWriterStringStream writer; - - std::string expected_result; - - const uint64_t b2_val = 0x4 | 0x2 | 0x40; - const std::string bits2 = BitsToStream(b2_val, 8); - writer.WriteBits(b2_val, 8); - - const uint64_t val = 0x1 | 0x2 | 0x10; - const std::string bits3 = BitsToStream(val, 8); - writer.WriteBits(val, 8); - - const std::string expected = bits2 + bits3; - - EXPECT_EQ(expected.length(), writer.GetNumBits()); - EXPECT_EQ(2u, writer.GetDataSizeBytes()); - EXPECT_EQ(expected, writer.GetStreamRaw()); - - EXPECT_EQ(PadToWord<8>(expected), BufferToStream(writer.GetDataCopy())); -} - -TEST(BitWriterWord64, Empty) { - BitWriterWord64 writer; - EXPECT_EQ(0u, writer.GetNumBits()); - EXPECT_EQ(0u, writer.GetDataSizeBytes()); -} - -TEST(BitWriterWord64, WriteBits) { - BitWriterWord64 writer; - const uint64_t bits1 = 0x1 | 0x2 | 0x10; - writer.WriteBits(bits1, 5); - writer.WriteBits(bits1, 5); - writer.WriteBits(bits1, 5); - EXPECT_EQ(15u, writer.GetNumBits()); - EXPECT_EQ(2u, writer.GetDataSizeBytes()); -} - -TEST(BitWriterWord64, WriteZeroBits) { - BitWriterWord64 writer; - writer.WriteBits(0, 0); - writer.WriteBits(1, 0); - EXPECT_EQ(0u, writer.GetNumBits()); - writer.WriteBits(1, 1); - writer.WriteBits(0, 0); - writer.WriteBits(0, 63); - EXPECT_EQ(64u, writer.GetNumBits()); - writer.WriteBits(0, 0); - writer.WriteBits(7, 3); - writer.WriteBits(0, 0); -} - -TEST(BitWriterWord64, ComparisonTestWriteLotsOfBits) { - BitWriterStringStream writer1; - BitWriterWord64 writer2(16384); - - for (uint64_t i = 0; i < 65000; i += 25) { - writer1.WriteBits(i, 16); - writer2.WriteBits(i, 16); - ASSERT_EQ(writer1.GetNumBits(), writer2.GetNumBits()); - } -} - -TEST(GetLowerBits, Test) { - EXPECT_EQ(0u, GetLowerBits(255, 0)); - EXPECT_EQ(1u, GetLowerBits(255, 1)); - EXPECT_EQ(3u, GetLowerBits(255, 2)); - EXPECT_EQ(7u, GetLowerBits(255, 3)); - EXPECT_EQ(15u, GetLowerBits(255, 4)); - EXPECT_EQ(31u, GetLowerBits(255, 5)); - EXPECT_EQ(63u, GetLowerBits(255, 6)); - EXPECT_EQ(127u, GetLowerBits(255, 7)); - EXPECT_EQ(255u, GetLowerBits(255, 8)); - EXPECT_EQ(0xFFu, GetLowerBits(0xFFFFFFFF, 8)); - EXPECT_EQ(0xFFFFu, GetLowerBits(0xFFFFFFFF, 16)); - EXPECT_EQ(0xFFFFFFu, GetLowerBits(0xFFFFFFFF, 24)); - EXPECT_EQ(0xFFFFFFu, GetLowerBits(0xFFFFFFFFFFFF, 24)); - EXPECT_EQ(0xFFFFFFFFFFFFFFFFu, - GetLowerBits(0xFFFFFFFFFFFFFFFFu, 64)); - EXPECT_EQ(StreamToBits("1010001110"), - GetLowerBits(StreamToBits("1010001110111101111111"), 10)); -} - -TEST(BitReaderFromString, FromU8) { - std::vector buffer = { - 0xAA, - 0xBB, - 0xCC, - 0xDD, - }; - - const std::string total_stream = - "01010101" - "11011101" - "00110011" - "10111011"; - - BitReaderFromString reader(buffer); - - uint64_t bits = 0; - EXPECT_EQ(2u, reader.ReadBits(&bits, 2)); - EXPECT_EQ(PadToWord<64>("01"), BitsToStream(bits)); - EXPECT_EQ(20u, reader.ReadBits(&bits, 20)); - EXPECT_EQ(PadToWord<64>("01010111011101001100"), BitsToStream(bits)); - EXPECT_EQ(20u, reader.ReadBits(&bits, 20)); - EXPECT_EQ(PadToWord<64>("11101110110000000000"), BitsToStream(bits)); - EXPECT_EQ(22u, reader.ReadBits(&bits, 30)); - EXPECT_EQ(PadToWord<64>("0000000000000000000000"), BitsToStream(bits)); - EXPECT_TRUE(reader.ReachedEnd()); -} - -TEST(BitReaderFromString, FromU64) { - std::vector buffer = { - 0xAAAAAAAAAAAAAAAA, - 0xBBBBBBBBBBBBBBBB, - 0xCCCCCCCCCCCCCCCC, - 0xDDDDDDDDDDDDDDDD, - }; - - const std::string total_stream = - "0101010101010101010101010101010101010101010101010101010101010101" - "1101110111011101110111011101110111011101110111011101110111011101" - "0011001100110011001100110011001100110011001100110011001100110011" - "1011101110111011101110111011101110111011101110111011101110111011"; - - BitReaderFromString reader(buffer); - - uint64_t bits = 0; - size_t pos = 0; - size_t to_read = 5; - while (reader.ReadBits(&bits, to_read) > 0) { - EXPECT_EQ(BitsToStream(bits), - PadToWord<64>(total_stream.substr(pos, to_read))); - pos += to_read; - to_read = (to_read + 35) % 64 + 1; - } - EXPECT_TRUE(reader.ReachedEnd()); -} - -TEST(BitReaderWord64, ReadBitsSingleByte) { - BitReaderWord64 reader(std::vector({uint8_t(0xF0)})); - EXPECT_FALSE(reader.ReachedEnd()); - - uint64_t bits = 0; - EXPECT_EQ(1u, reader.ReadBits(&bits, 1)); - EXPECT_EQ(0u, bits); - EXPECT_EQ(2u, reader.ReadBits(&bits, 2)); - EXPECT_EQ(0u, bits); - EXPECT_EQ(2u, reader.ReadBits(&bits, 2)); - EXPECT_EQ(2u, bits); - EXPECT_EQ(2u, reader.ReadBits(&bits, 2)); - EXPECT_EQ(3u, bits); - EXPECT_FALSE(reader.OnlyZeroesLeft()); - EXPECT_FALSE(reader.ReachedEnd()); - EXPECT_EQ(2u, reader.ReadBits(&bits, 2)); - EXPECT_EQ(1u, bits); - EXPECT_TRUE(reader.OnlyZeroesLeft()); - EXPECT_FALSE(reader.ReachedEnd()); - EXPECT_EQ(55u, reader.ReadBits(&bits, 64)); - EXPECT_EQ(0u, bits); - EXPECT_TRUE(reader.ReachedEnd()); -} - -TEST(BitReaderWord64, ReadBitsTwoWords) { - std::vector buffer = {0x0000000000000001, 0x0000000000FFFFFF}; - - BitReaderWord64 reader(std::move(buffer)); - - uint64_t bits = 0; - EXPECT_EQ(1u, reader.ReadBits(&bits, 1)); - EXPECT_EQ(1u, bits); - EXPECT_EQ(62u, reader.ReadBits(&bits, 62)); - EXPECT_EQ(0u, bits); - EXPECT_EQ(2u, reader.ReadBits(&bits, 2)); - EXPECT_EQ(2u, bits); - EXPECT_EQ(3u, reader.ReadBits(&bits, 3)); - EXPECT_EQ(7u, bits); - EXPECT_FALSE(reader.OnlyZeroesLeft()); - EXPECT_EQ(32u, reader.ReadBits(&bits, 32)); - EXPECT_EQ(0xFFFFFu, bits); - EXPECT_TRUE(reader.OnlyZeroesLeft()); - EXPECT_FALSE(reader.ReachedEnd()); - EXPECT_EQ(28u, reader.ReadBits(&bits, 32)); - EXPECT_EQ(0u, bits); - EXPECT_TRUE(reader.ReachedEnd()); -} - -TEST(BitReaderFromString, ReadUnencodedU8) { - BitReaderFromString reader("11111110"); - uint8_t val = 0; - ASSERT_TRUE(reader.ReadUnencoded(&val)); - EXPECT_EQ(8u, reader.GetNumReadBits()); - EXPECT_EQ(127, val); -} - -TEST(BitReaderFromString, ReadUnencodedU16Fail) { - BitReaderFromString reader("11111110"); - uint16_t val = 0; - ASSERT_FALSE(reader.ReadUnencoded(&val)); -} - -TEST(BitReaderFromString, ReadUnencodedS64) { - BitReaderFromString reader( - "1110000000000000000000000000000000000000000000000000000000000001"); - int64_t val = 0; - ASSERT_TRUE(reader.ReadUnencoded(&val)); - EXPECT_EQ(64u, reader.GetNumReadBits()); - EXPECT_EQ(std::numeric_limits::min() + 7, val); -} - -TEST(BitReaderWord64, FromU8) { - std::vector buffer = { - 0xAA, - 0xBB, - 0xCC, - 0xDD, - }; - - BitReaderWord64 reader(std::move(buffer)); - - uint64_t bits = 0; - EXPECT_EQ(2u, reader.ReadBits(&bits, 2)); - EXPECT_EQ(PadToWord<64>("01"), BitsToStream(bits)); - EXPECT_EQ(20u, reader.ReadBits(&bits, 20)); - EXPECT_EQ(PadToWord<64>("01010111011101001100"), BitsToStream(bits)); - EXPECT_EQ(20u, reader.ReadBits(&bits, 20)); - EXPECT_EQ(PadToWord<64>("11101110110000000000"), BitsToStream(bits)); - EXPECT_EQ(22u, reader.ReadBits(&bits, 30)); - EXPECT_EQ(PadToWord<64>("0000000000000000000000"), BitsToStream(bits)); - EXPECT_TRUE(reader.ReachedEnd()); -} - -TEST(BitReaderWord64, FromU64) { - std::vector buffer = { - 0xAAAAAAAAAAAAAAAA, - 0xBBBBBBBBBBBBBBBB, - 0xCCCCCCCCCCCCCCCC, - 0xDDDDDDDDDDDDDDDD, - }; - - const std::string total_stream = - "0101010101010101010101010101010101010101010101010101010101010101" - "1101110111011101110111011101110111011101110111011101110111011101" - "0011001100110011001100110011001100110011001100110011001100110011" - "1011101110111011101110111011101110111011101110111011101110111011"; - - BitReaderWord64 reader(std::move(buffer)); - - uint64_t bits = 0; - size_t pos = 0; - size_t to_read = 5; - while (reader.ReadBits(&bits, to_read) > 0) { - EXPECT_EQ(BitsToStream(bits), - PadToWord<64>(total_stream.substr(pos, to_read))); - pos += to_read; - to_read = (to_read + 35) % 64 + 1; - } - EXPECT_TRUE(reader.ReachedEnd()); -} - -TEST(BitReaderWord64, ComparisonLotsOfU8) { - std::vector buffer; - for (uint32_t i = 0; i < 10003; ++i) { - buffer.push_back(static_cast(i % 255)); - } - - BitReaderFromString reader1(buffer); - BitReaderWord64 reader2(std::move(buffer)); - - uint64_t bits1 = 0, bits2 = 0; - size_t to_read = 5; - while (reader1.ReadBits(&bits1, to_read) > 0) { - reader2.ReadBits(&bits2, to_read); - EXPECT_EQ(bits1, bits2); - to_read = (to_read + 35) % 64 + 1; - } - - EXPECT_EQ(0u, reader2.ReadBits(&bits2, 1)); -} - -TEST(BitReaderWord64, ComparisonLotsOfU64) { - std::vector buffer; - for (uint64_t i = 0; i < 1000; ++i) { - buffer.push_back(i); - } - - BitReaderFromString reader1(buffer); - BitReaderWord64 reader2(std::move(buffer)); - - uint64_t bits1 = 0, bits2 = 0; - size_t to_read = 5; - while (reader1.ReadBits(&bits1, to_read) > 0) { - reader2.ReadBits(&bits2, to_read); - EXPECT_EQ(bits1, bits2); - to_read = (to_read + 35) % 64 + 1; - } - - EXPECT_EQ(0u, reader2.ReadBits(&bits2, 1)); -} - -TEST(ReadWriteWord64, ReadWriteLotsOfBits) { - BitWriterWord64 writer(16384); - for (uint64_t i = 0; i < 65000; i += 25) { - const uint64_t num_bits = i % 64 + 1; - const uint64_t bits = i >> (64 - num_bits); - writer.WriteBits(bits, size_t(num_bits)); - } - - BitReaderWord64 reader(writer.GetDataCopy()); - for (uint64_t i = 0; i < 65000; i += 25) { - const uint64_t num_bits = i % 64 + 1; - const uint64_t expected_bits = i >> (64 - num_bits); - uint64_t bits = 0; - reader.ReadBits(&bits, size_t(num_bits)); - EXPECT_EQ(expected_bits, bits); - } - - EXPECT_TRUE(reader.OnlyZeroesLeft()); -} - -TEST(VariableWidthWrite, Write0U) { - BitWriterStringStream writer; - writer.WriteVariableWidthU64(0, 2); - EXPECT_EQ("000", writer.GetStreamRaw()); - writer.WriteVariableWidthU32(0, 2); - EXPECT_EQ( - "000" - "000", - writer.GetStreamRaw()); - writer.WriteVariableWidthU16(0, 2); - EXPECT_EQ( - "000" - "000" - "000", - writer.GetStreamRaw()); -} - -TEST(VariableWidthWrite, WriteSmallUnsigned) { - BitWriterStringStream writer; - writer.WriteVariableWidthU64(1, 2); - EXPECT_EQ("100", writer.GetStreamRaw()); - writer.WriteVariableWidthU32(2, 2); - EXPECT_EQ( - "100" - "010", - writer.GetStreamRaw()); - writer.WriteVariableWidthU16(3, 2); - EXPECT_EQ( - "100" - "010" - "110", - writer.GetStreamRaw()); -} - -TEST(VariableWidthWrite, WriteSmallSigned) { - BitWriterStringStream writer; - writer.WriteVariableWidthS64(1, 2, 0); - EXPECT_EQ("010", writer.GetStreamRaw()); - writer.WriteVariableWidthS64(-1, 2, 0); - EXPECT_EQ( - "010" - "100", - writer.GetStreamRaw()); -} - -TEST(VariableWidthWrite, U64Val127ChunkLength7) { - BitWriterStringStream writer; - writer.WriteVariableWidthU64(127, 7); - EXPECT_EQ( - "1111111" - "0", - writer.GetStreamRaw()); -} - -TEST(VariableWidthWrite, U32Val255ChunkLength7) { - BitWriterStringStream writer; - writer.WriteVariableWidthU32(255, 7); - EXPECT_EQ( - "1111111" - "1" - "1000000" - "0", - writer.GetStreamRaw()); -} - -TEST(VariableWidthWrite, U16Val2ChunkLength4) { - BitWriterStringStream writer; - writer.WriteVariableWidthU16(2, 4); - EXPECT_EQ( - "0100" - "0", - writer.GetStreamRaw()); -} - -TEST(VariableWidthWrite, U64ValAAAAChunkLength2) { - BitWriterStringStream writer; - writer.WriteVariableWidthU64(0xAAAA, 2); - EXPECT_EQ( - "01" - "1" - "01" - "1" - "01" - "1" - "01" - "1" - "01" - "1" - "01" - "1" - "01" - "1" - "01" - "0", - writer.GetStreamRaw()); -} - -TEST(VariableWidthRead, U64Val127ChunkLength7) { - BitReaderFromString reader( - "1111111" - "0"); - uint64_t val = 0; - ASSERT_TRUE(reader.ReadVariableWidthU64(&val, 7)); - EXPECT_EQ(127u, val); -} - -TEST(VariableWidthRead, U32Val255ChunkLength7) { - BitReaderFromString reader( - "1111111" - "1" - "1000000" - "0"); - uint32_t val = 0; - ASSERT_TRUE(reader.ReadVariableWidthU32(&val, 7)); - EXPECT_EQ(255u, val); -} - -TEST(VariableWidthRead, U16Val2ChunkLength4) { - BitReaderFromString reader( - "0100" - "0"); - uint16_t val = 0; - ASSERT_TRUE(reader.ReadVariableWidthU16(&val, 4)); - EXPECT_EQ(2u, val); -} - -TEST(VariableWidthRead, U64ValAAAAChunkLength2) { - BitReaderFromString reader( - "01" - "1" - "01" - "1" - "01" - "1" - "01" - "1" - "01" - "1" - "01" - "1" - "01" - "1" - "01" - "0"); - uint64_t val = 0; - ASSERT_TRUE(reader.ReadVariableWidthU64(&val, 2)); - EXPECT_EQ(0xAAAAu, val); -} - -TEST(VariableWidthRead, FailTooShort) { - BitReaderFromString reader("00000001100000"); - uint64_t val = 0; - ASSERT_FALSE(reader.ReadVariableWidthU64(&val, 7)); -} - -TEST(VariableWidthWriteRead, SingleWriteReadU64) { - for (uint64_t i = 0; i < 1000000; i += 1234) { - const uint64_t val = i * i * i; - const size_t chunk_length = size_t(i % 16 + 1); - - BitWriterWord64 writer; - writer.WriteVariableWidthU64(val, chunk_length); - - BitReaderWord64 reader(writer.GetDataCopy()); - uint64_t read_val = 0; - ASSERT_TRUE(reader.ReadVariableWidthU64(&read_val, chunk_length)); - - ASSERT_EQ(val, read_val) << "Chunk length " << chunk_length; - } -} - -TEST(VariableWidthWriteRead, SingleWriteReadS64) { - for (int64_t i = 0; i < 1000000; i += 4321) { - const int64_t val = i * i * (i % 2 ? -i : i); - const size_t chunk_length = size_t(i % 16 + 1); - const size_t zigzag_exponent = size_t(i % 13); - - BitWriterWord64 writer; - writer.WriteVariableWidthS64(val, chunk_length, zigzag_exponent); - - BitReaderWord64 reader(writer.GetDataCopy()); - int64_t read_val = 0; - ASSERT_TRUE( - reader.ReadVariableWidthS64(&read_val, chunk_length, zigzag_exponent)); - - ASSERT_EQ(val, read_val) << "Chunk length " << chunk_length; - } -} - -TEST(VariableWidthWriteRead, SingleWriteReadU32) { - for (uint32_t i = 0; i < 100000; i += 123) { - const uint32_t val = i * i; - const size_t chunk_length = i % 16 + 1; - - BitWriterWord64 writer; - writer.WriteVariableWidthU32(val, chunk_length); - - BitReaderWord64 reader(writer.GetDataCopy()); - uint32_t read_val = 0; - ASSERT_TRUE(reader.ReadVariableWidthU32(&read_val, chunk_length)); - - ASSERT_EQ(val, read_val) << "Chunk length " << chunk_length; - } -} - -TEST(VariableWidthWriteRead, SingleWriteReadU16) { - for (int i = 0; i < 65536; i += 123) { - const uint16_t val = static_cast(i); - const size_t chunk_length = val % 10 + 1; - - BitWriterWord64 writer; - writer.WriteVariableWidthU16(val, chunk_length); - - BitReaderWord64 reader(writer.GetDataCopy()); - uint16_t read_val = 0; - ASSERT_TRUE(reader.ReadVariableWidthU16(&read_val, chunk_length)); - - ASSERT_EQ(val, read_val) << "Chunk length " << chunk_length; - } -} - -TEST(VariableWidthWriteRead, SmallNumbersChunkLength4) { - const std::vector expected_values = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; - - BitWriterWord64 writer; - for (uint64_t val : expected_values) { - writer.WriteVariableWidthU64(val, 4); - } - - EXPECT_EQ(50u, writer.GetNumBits()); - - std::vector actual_values; - BitReaderWord64 reader(writer.GetDataCopy()); - while (!reader.OnlyZeroesLeft()) { - uint64_t val = 0; - ASSERT_TRUE(reader.ReadVariableWidthU64(&val, 4)); - actual_values.push_back(val); - } - - EXPECT_EQ(expected_values, actual_values); -} - -TEST(VariableWidthWriteRead, VariedNumbersChunkLength8) { - const std::vector expected_values = {1000, 0, 255, 4294967296}; - const size_t kExpectedNumBits = 9 * (2 + 1 + 1 + 5); - - BitWriterWord64 writer; - for (uint64_t val : expected_values) { - writer.WriteVariableWidthU64(val, 8); - } - - EXPECT_EQ(kExpectedNumBits, writer.GetNumBits()); - - std::vector actual_values; - BitReaderWord64 reader(writer.GetDataCopy()); - while (!reader.OnlyZeroesLeft()) { - uint64_t val = 0; - ASSERT_TRUE(reader.ReadVariableWidthU64(&val, 8)); - actual_values.push_back(val); - } - - EXPECT_EQ(expected_values, actual_values); -} - -} // namespace -} // namespace comp -} // namespace spvtools diff --git a/third_party/spirv-tools/test/c_interface_test.cpp b/third_party/spirv-tools/test/c_interface_test.cpp index 1b735be5d7..841bb2c6b1 100644 --- a/third_party/spirv-tools/test/c_interface_test.cpp +++ b/third_party/spirv-tools/test/c_interface_test.cpp @@ -107,7 +107,7 @@ TEST(CInterface, DefaultConsumerNullDiagnosticForInvalidValidating) { } TEST(CInterface, SpecifyConsumerNullDiagnosticForAssembling) { - const char input_text[] = "%1 = OpName\n"; + const char input_text[] = " OpName\n"; auto context = spvContextCreate(SPV_ENV_UNIVERSAL_1_1); int invocation = 0; @@ -150,7 +150,7 @@ TEST(CInterface, SpecifyConsumerNullDiagnosticForDisassembling) { EXPECT_STREQ("input", source); EXPECT_EQ(0u, position.line); EXPECT_EQ(0u, position.column); - EXPECT_EQ(5u, position.index); + EXPECT_EQ(1u, position.index); EXPECT_STREQ("Invalid opcode: 65535", message); }); @@ -213,7 +213,7 @@ TEST(CInterface, SpecifyConsumerNullDiagnosticForValidating) { // When having both a consumer and an diagnostic object, the diagnostic object // should take priority. TEST(CInterface, SpecifyConsumerSpecifyDiagnosticForAssembling) { - const char input_text[] = "%1 = OpName"; + const char input_text[] = " OpName"; auto context = spvContextCreate(SPV_ENV_UNIVERSAL_1_1); int invocation = 0; diff --git a/third_party/spirv-tools/test/comment_test.cpp b/third_party/spirv-tools/test/comment_test.cpp index f46b72ac58..49f8df651c 100644 --- a/third_party/spirv-tools/test/comment_test.cpp +++ b/third_party/spirv-tools/test/comment_test.cpp @@ -15,6 +15,7 @@ #include #include "gmock/gmock.h" +#include "source/util/string_utils.h" #include "test/test_fixture.h" #include "test/unit_spirv.h" @@ -23,7 +24,7 @@ namespace { using spvtest::Concatenate; using spvtest::MakeInstruction; -using spvtest::MakeVector; +using utils::MakeVector; using spvtest::TextToBinaryTest; using testing::Eq; diff --git a/third_party/spirv-tools/test/comp/markv_codec_test.cpp b/third_party/spirv-tools/test/comp/markv_codec_test.cpp deleted file mode 100644 index 76918f7479..0000000000 --- a/third_party/spirv-tools/test/comp/markv_codec_test.cpp +++ /dev/null @@ -1,829 +0,0 @@ -// Copyright (c) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Tests for unique type declaration rules validator. - -#include -#include -#include -#include - -#include "gmock/gmock.h" -#include "source/comp/markv.h" -#include "test/test_fixture.h" -#include "test/unit_spirv.h" -#include "tools/comp/markv_model_factory.h" - -namespace spvtools { -namespace comp { -namespace { - -using spvtest::ScopedContext; -using MarkvTest = ::testing::TestWithParam; - -void DiagnosticsMessageHandler(spv_message_level_t level, const char*, - const spv_position_t& position, - const char* message) { - switch (level) { - case SPV_MSG_FATAL: - case SPV_MSG_INTERNAL_ERROR: - case SPV_MSG_ERROR: - std::cerr << "error: " << position.index << ": " << message << std::endl; - break; - case SPV_MSG_WARNING: - std::cout << "warning: " << position.index << ": " << message - << std::endl; - break; - case SPV_MSG_INFO: - std::cout << "info: " << position.index << ": " << message << std::endl; - break; - default: - break; - } -} - -// Compiles |code| to SPIR-V |words|. -void Compile(const std::string& code, std::vector* words, - uint32_t options = SPV_TEXT_TO_BINARY_OPTION_NONE, - spv_target_env env = SPV_ENV_UNIVERSAL_1_2) { - ScopedContext ctx(env); - SetContextMessageConsumer(ctx.context, DiagnosticsMessageHandler); - - spv_binary spirv_binary; - ASSERT_EQ(SPV_SUCCESS, - spvTextToBinaryWithOptions(ctx.context, code.c_str(), code.size(), - options, &spirv_binary, nullptr)); - - *words = std::vector(spirv_binary->code, - spirv_binary->code + spirv_binary->wordCount); - - spvBinaryDestroy(spirv_binary); -} - -// Disassembles SPIR-V |words| to |out_text|. -void Disassemble(const std::vector& words, std::string* out_text, - spv_target_env env = SPV_ENV_UNIVERSAL_1_2) { - ScopedContext ctx(env); - SetContextMessageConsumer(ctx.context, DiagnosticsMessageHandler); - - spv_text text = nullptr; - ASSERT_EQ(SPV_SUCCESS, spvBinaryToText(ctx.context, words.data(), - words.size(), 0, &text, nullptr)); - assert(text); - - *out_text = std::string(text->str, text->length); - spvTextDestroy(text); -} - -// Encodes/decodes |original|, assembles/dissasembles |original|, then compares -// the results of the two operations. -void TestEncodeDecode(MarkvModelType model_type, - const std::string& original_text) { - ScopedContext ctx(SPV_ENV_UNIVERSAL_1_2); - std::unique_ptr model = CreateMarkvModel(model_type); - MarkvCodecOptions options; - - std::vector expected_binary; - Compile(original_text, &expected_binary); - ASSERT_FALSE(expected_binary.empty()); - - std::string expected_text; - Disassemble(expected_binary, &expected_text); - ASSERT_FALSE(expected_text.empty()); - - std::vector binary_to_encode; - Compile(original_text, &binary_to_encode, - SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - ASSERT_FALSE(binary_to_encode.empty()); - - std::stringstream encoder_comments; - const auto output_to_string_stream = - [&encoder_comments](const std::string& str) { encoder_comments << str; }; - - std::vector markv; - ASSERT_EQ(SPV_SUCCESS, - SpirvToMarkv(ctx.context, binary_to_encode, options, *model, - DiagnosticsMessageHandler, output_to_string_stream, - MarkvDebugConsumer(), &markv)); - ASSERT_FALSE(markv.empty()); - - std::vector decoded_binary; - ASSERT_EQ(SPV_SUCCESS, - MarkvToSpirv(ctx.context, markv, options, *model, - DiagnosticsMessageHandler, MarkvLogConsumer(), - MarkvDebugConsumer(), &decoded_binary)); - ASSERT_FALSE(decoded_binary.empty()); - - EXPECT_EQ(expected_binary, decoded_binary) << encoder_comments.str(); - - std::string decoded_text; - Disassemble(decoded_binary, &decoded_text); - ASSERT_FALSE(decoded_text.empty()); - - EXPECT_EQ(expected_text, decoded_text) << encoder_comments.str(); -} - -void TestEncodeDecodeShaderMainBody(MarkvModelType model_type, - const std::string& body) { - const std::string prefix = - R"( -OpCapability Shader -OpCapability Int64 -OpCapability Float64 -%ext_inst = OpExtInstImport "GLSL.std.450" -OpMemoryModel Logical GLSL450 -OpEntryPoint Fragment %main "main" -%void = OpTypeVoid -%func = OpTypeFunction %void -%bool = OpTypeBool -%f32 = OpTypeFloat 32 -%u32 = OpTypeInt 32 0 -%s32 = OpTypeInt 32 1 -%f64 = OpTypeFloat 64 -%u64 = OpTypeInt 64 0 -%s64 = OpTypeInt 64 1 -%boolvec2 = OpTypeVector %bool 2 -%s32vec2 = OpTypeVector %s32 2 -%u32vec2 = OpTypeVector %u32 2 -%f32vec2 = OpTypeVector %f32 2 -%f64vec2 = OpTypeVector %f64 2 -%boolvec3 = OpTypeVector %bool 3 -%u32vec3 = OpTypeVector %u32 3 -%s32vec3 = OpTypeVector %s32 3 -%f32vec3 = OpTypeVector %f32 3 -%f64vec3 = OpTypeVector %f64 3 -%boolvec4 = OpTypeVector %bool 4 -%u32vec4 = OpTypeVector %u32 4 -%s32vec4 = OpTypeVector %s32 4 -%f32vec4 = OpTypeVector %f32 4 -%f64vec4 = OpTypeVector %f64 4 - -%f32_0 = OpConstant %f32 0 -%f32_1 = OpConstant %f32 1 -%f32_2 = OpConstant %f32 2 -%f32_3 = OpConstant %f32 3 -%f32_4 = OpConstant %f32 4 -%f32_pi = OpConstant %f32 3.14159 - -%s32_0 = OpConstant %s32 0 -%s32_1 = OpConstant %s32 1 -%s32_2 = OpConstant %s32 2 -%s32_3 = OpConstant %s32 3 -%s32_4 = OpConstant %s32 4 -%s32_m1 = OpConstant %s32 -1 - -%u32_0 = OpConstant %u32 0 -%u32_1 = OpConstant %u32 1 -%u32_2 = OpConstant %u32 2 -%u32_3 = OpConstant %u32 3 -%u32_4 = OpConstant %u32 4 - -%u32vec2_01 = OpConstantComposite %u32vec2 %u32_0 %u32_1 -%u32vec2_12 = OpConstantComposite %u32vec2 %u32_1 %u32_2 -%u32vec3_012 = OpConstantComposite %u32vec3 %u32_0 %u32_1 %u32_2 -%u32vec3_123 = OpConstantComposite %u32vec3 %u32_1 %u32_2 %u32_3 -%u32vec4_0123 = OpConstantComposite %u32vec4 %u32_0 %u32_1 %u32_2 %u32_3 -%u32vec4_1234 = OpConstantComposite %u32vec4 %u32_1 %u32_2 %u32_3 %u32_4 - -%s32vec2_01 = OpConstantComposite %s32vec2 %s32_0 %s32_1 -%s32vec2_12 = OpConstantComposite %s32vec2 %s32_1 %s32_2 -%s32vec3_012 = OpConstantComposite %s32vec3 %s32_0 %s32_1 %s32_2 -%s32vec3_123 = OpConstantComposite %s32vec3 %s32_1 %s32_2 %s32_3 -%s32vec4_0123 = OpConstantComposite %s32vec4 %s32_0 %s32_1 %s32_2 %s32_3 -%s32vec4_1234 = OpConstantComposite %s32vec4 %s32_1 %s32_2 %s32_3 %s32_4 - -%f32vec2_01 = OpConstantComposite %f32vec2 %f32_0 %f32_1 -%f32vec2_12 = OpConstantComposite %f32vec2 %f32_1 %f32_2 -%f32vec3_012 = OpConstantComposite %f32vec3 %f32_0 %f32_1 %f32_2 -%f32vec3_123 = OpConstantComposite %f32vec3 %f32_1 %f32_2 %f32_3 -%f32vec4_0123 = OpConstantComposite %f32vec4 %f32_0 %f32_1 %f32_2 %f32_3 -%f32vec4_1234 = OpConstantComposite %f32vec4 %f32_1 %f32_2 %f32_3 %f32_4 - -%main = OpFunction %void None %func -%main_entry = OpLabel)"; - - const std::string suffix = - R"( -OpReturn -OpFunctionEnd)"; - - TestEncodeDecode(model_type, prefix + body + suffix); -} - -TEST_P(MarkvTest, U32Literal) { - TestEncodeDecode(GetParam(), R"( -OpCapability Shader -OpCapability Linkage -OpMemoryModel Logical GLSL450 -%u32 = OpTypeInt 32 0 -%100 = OpConstant %u32 0 -%200 = OpConstant %u32 1 -%300 = OpConstant %u32 4294967295 -)"); -} - -TEST_P(MarkvTest, S32Literal) { - TestEncodeDecode(GetParam(), R"( -OpCapability Shader -OpCapability Linkage -OpMemoryModel Logical GLSL450 -%s32 = OpTypeInt 32 1 -%100 = OpConstant %s32 0 -%200 = OpConstant %s32 1 -%300 = OpConstant %s32 -1 -%400 = OpConstant %s32 2147483647 -%500 = OpConstant %s32 -2147483648 -)"); -} - -TEST_P(MarkvTest, U64Literal) { - TestEncodeDecode(GetParam(), R"( -OpCapability Shader -OpCapability Linkage -OpCapability Int64 -OpMemoryModel Logical GLSL450 -%u64 = OpTypeInt 64 0 -%100 = OpConstant %u64 0 -%200 = OpConstant %u64 1 -%300 = OpConstant %u64 18446744073709551615 -)"); -} - -TEST_P(MarkvTest, S64Literal) { - TestEncodeDecode(GetParam(), R"( -OpCapability Shader -OpCapability Linkage -OpCapability Int64 -OpMemoryModel Logical GLSL450 -%s64 = OpTypeInt 64 1 -%100 = OpConstant %s64 0 -%200 = OpConstant %s64 1 -%300 = OpConstant %s64 -1 -%400 = OpConstant %s64 9223372036854775807 -%500 = OpConstant %s64 -9223372036854775808 -)"); -} - -TEST_P(MarkvTest, U16Literal) { - TestEncodeDecode(GetParam(), R"( -OpCapability Shader -OpCapability Linkage -OpCapability Int16 -OpMemoryModel Logical GLSL450 -%u16 = OpTypeInt 16 0 -%100 = OpConstant %u16 0 -%200 = OpConstant %u16 1 -%300 = OpConstant %u16 65535 -)"); -} - -TEST_P(MarkvTest, S16Literal) { - TestEncodeDecode(GetParam(), R"( -OpCapability Shader -OpCapability Linkage -OpCapability Int16 -OpMemoryModel Logical GLSL450 -%s16 = OpTypeInt 16 1 -%100 = OpConstant %s16 0 -%200 = OpConstant %s16 1 -%300 = OpConstant %s16 -1 -%400 = OpConstant %s16 32767 -%500 = OpConstant %s16 -32768 -)"); -} - -TEST_P(MarkvTest, F32Literal) { - TestEncodeDecode(GetParam(), R"( -OpCapability Shader -OpCapability Linkage -OpMemoryModel Logical GLSL450 -%f32 = OpTypeFloat 32 -%100 = OpConstant %f32 0 -%200 = OpConstant %f32 1 -%300 = OpConstant %f32 0.1 -%400 = OpConstant %f32 -0.1 -)"); -} - -TEST_P(MarkvTest, F64Literal) { - TestEncodeDecode(GetParam(), R"( -OpCapability Shader -OpCapability Linkage -OpCapability Float64 -OpMemoryModel Logical GLSL450 -%f64 = OpTypeFloat 64 -%100 = OpConstant %f64 0 -%200 = OpConstant %f64 1 -%300 = OpConstant %f64 0.1 -%400 = OpConstant %f64 -0.1 -)"); -} - -TEST_P(MarkvTest, F16Literal) { - TestEncodeDecode(GetParam(), R"( -OpCapability Shader -OpCapability Linkage -OpCapability Float16 -OpMemoryModel Logical GLSL450 -%f16 = OpTypeFloat 16 -%100 = OpConstant %f16 0 -%200 = OpConstant %f16 1 -%300 = OpConstant %f16 0.1 -%400 = OpConstant %f16 -0.1 -)"); -} - -TEST_P(MarkvTest, StringLiteral) { - TestEncodeDecode(GetParam(), R"( -OpCapability Shader -OpCapability Linkage -OpExtension "SPV_KHR_16bit_storage" -OpExtension "xxx" -OpExtension "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -OpExtension "" -OpMemoryModel Logical GLSL450 -)"); -} - -TEST_P(MarkvTest, WithFunction) { - TestEncodeDecode(GetParam(), R"( -OpCapability Addresses -OpCapability Kernel -OpCapability GenericPointer -OpCapability Linkage -OpExtension "SPV_KHR_16bit_storage" -OpMemoryModel Physical32 OpenCL -%f32 = OpTypeFloat 32 -%u32 = OpTypeInt 32 0 -%void = OpTypeVoid -%void_func = OpTypeFunction %void -%100 = OpConstant %u32 1 -%200 = OpConstant %u32 2 -%main = OpFunction %void None %void_func -%entry_main = OpLabel -%300 = OpIAdd %u32 %100 %200 -OpReturn -OpFunctionEnd -)"); -} - -TEST_P(MarkvTest, WithMultipleFunctions) { - TestEncodeDecode(GetParam(), R"( -OpCapability Addresses -OpCapability Kernel -OpCapability GenericPointer -OpCapability Linkage -OpMemoryModel Physical32 OpenCL -%f32 = OpTypeFloat 32 -%one = OpConstant %f32 1 -%void = OpTypeVoid -%void_func = OpTypeFunction %void -%f32_func = OpTypeFunction %f32 %f32 -%sqr_plus_one = OpFunction %f32 None %f32_func -%x = OpFunctionParameter %f32 -%100 = OpLabel -%x2 = OpFMul %f32 %x %x -%x2p1 = OpFunctionCall %f32 %plus_one %x2 -OpReturnValue %x2p1 -OpFunctionEnd -%plus_one = OpFunction %f32 None %f32_func -%y = OpFunctionParameter %f32 -%200 = OpLabel -%yp1 = OpFAdd %f32 %y %one -OpReturnValue %yp1 -OpFunctionEnd -%main = OpFunction %void None %void_func -%entry_main = OpLabel -%1p1 = OpFunctionCall %f32 %sqr_plus_one %one -OpReturn -OpFunctionEnd -)"); -} - -TEST_P(MarkvTest, ForwardDeclaredId) { - TestEncodeDecode(GetParam(), R"( -OpCapability Addresses -OpCapability Kernel -OpCapability GenericPointer -OpCapability Linkage -OpMemoryModel Physical32 OpenCL -OpEntryPoint Kernel %1 "simple_kernel" -%2 = OpTypeInt 32 0 -%3 = OpTypeVector %2 2 -%4 = OpConstant %2 2 -%5 = OpTypeArray %2 %4 -%6 = OpTypeVoid -%7 = OpTypeFunction %6 -%1 = OpFunction %6 None %7 -%8 = OpLabel -OpReturn -OpFunctionEnd -)"); -} - -TEST_P(MarkvTest, WithSwitch) { - TestEncodeDecode(GetParam(), R"( -OpCapability Addresses -OpCapability Kernel -OpCapability GenericPointer -OpCapability Linkage -OpCapability Int64 -OpMemoryModel Physical32 OpenCL -%u64 = OpTypeInt 64 0 -%void = OpTypeVoid -%void_func = OpTypeFunction %void -%val = OpConstant %u64 1 -%main = OpFunction %void None %void_func -%entry_main = OpLabel -OpSwitch %val %default 1 %case1 1000000000000 %case2 -%case1 = OpLabel -OpNop -OpBranch %after_switch -%case2 = OpLabel -OpNop -OpBranch %after_switch -%default = OpLabel -OpNop -OpBranch %after_switch -%after_switch = OpLabel -OpReturn -OpFunctionEnd -)"); -} - -TEST_P(MarkvTest, WithLoop) { - TestEncodeDecode(GetParam(), R"( -OpCapability Addresses -OpCapability Kernel -OpCapability GenericPointer -OpCapability Linkage -OpMemoryModel Physical32 OpenCL -%void = OpTypeVoid -%void_func = OpTypeFunction %void -%main = OpFunction %void None %void_func -%entry_main = OpLabel -OpLoopMerge %merge %continue DontUnroll|DependencyLength 10 -OpBranch %begin_loop -%begin_loop = OpLabel -OpNop -OpBranch %continue -%continue = OpLabel -OpNop -OpBranch %begin_loop -%merge = OpLabel -OpReturn -OpFunctionEnd -)"); -} - -TEST_P(MarkvTest, WithDecorate) { - TestEncodeDecode(GetParam(), R"( -OpCapability Shader -OpCapability Linkage -OpMemoryModel Logical GLSL450 -OpDecorate %1 ArrayStride 4 -OpDecorate %1 Uniform -%2 = OpTypeFloat 32 -%1 = OpTypeRuntimeArray %2 -)"); -} - -TEST_P(MarkvTest, WithExtInst) { - TestEncodeDecode(GetParam(), R"( -OpCapability Addresses -OpCapability Kernel -OpCapability GenericPointer -OpCapability Linkage -%opencl = OpExtInstImport "OpenCL.std" -OpMemoryModel Physical32 OpenCL -%f32 = OpTypeFloat 32 -%void = OpTypeVoid -%void_func = OpTypeFunction %void -%100 = OpConstant %f32 1.1 -%main = OpFunction %void None %void_func -%entry_main = OpLabel -%200 = OpExtInst %f32 %opencl cos %100 -OpReturn -OpFunctionEnd -)"); -} - -TEST_P(MarkvTest, F32Mul) { - TestEncodeDecodeShaderMainBody(GetParam(), R"( -%val1 = OpFMul %f32 %f32_0 %f32_1 -%val2 = OpFMul %f32 %f32_2 %f32_0 -%val3 = OpFMul %f32 %f32_pi %f32_2 -%val4 = OpFMul %f32 %f32_1 %f32_1 -)"); -} - -TEST_P(MarkvTest, U32Mul) { - TestEncodeDecodeShaderMainBody(GetParam(), R"( -%val1 = OpIMul %u32 %u32_0 %u32_1 -%val2 = OpIMul %u32 %u32_2 %u32_0 -%val3 = OpIMul %u32 %u32_3 %u32_2 -%val4 = OpIMul %u32 %u32_1 %u32_1 -)"); -} - -TEST_P(MarkvTest, S32Mul) { - TestEncodeDecodeShaderMainBody(GetParam(), R"( -%val1 = OpIMul %s32 %s32_0 %s32_1 -%val2 = OpIMul %s32 %s32_2 %s32_0 -%val3 = OpIMul %s32 %s32_m1 %s32_2 -%val4 = OpIMul %s32 %s32_1 %s32_1 -)"); -} - -TEST_P(MarkvTest, F32Add) { - TestEncodeDecodeShaderMainBody(GetParam(), R"( -%val1 = OpFAdd %f32 %f32_0 %f32_1 -%val2 = OpFAdd %f32 %f32_2 %f32_0 -%val3 = OpFAdd %f32 %f32_pi %f32_2 -%val4 = OpFAdd %f32 %f32_1 %f32_1 -)"); -} - -TEST_P(MarkvTest, U32Add) { - TestEncodeDecodeShaderMainBody(GetParam(), R"( -%val1 = OpIAdd %u32 %u32_0 %u32_1 -%val2 = OpIAdd %u32 %u32_2 %u32_0 -%val3 = OpIAdd %u32 %u32_3 %u32_2 -%val4 = OpIAdd %u32 %u32_1 %u32_1 -)"); -} - -TEST_P(MarkvTest, S32Add) { - TestEncodeDecodeShaderMainBody(GetParam(), R"( -%val1 = OpIAdd %s32 %s32_0 %s32_1 -%val2 = OpIAdd %s32 %s32_2 %s32_0 -%val3 = OpIAdd %s32 %s32_m1 %s32_2 -%val4 = OpIAdd %s32 %s32_1 %s32_1 -)"); -} - -TEST_P(MarkvTest, F32Dot) { - TestEncodeDecodeShaderMainBody(GetParam(), R"( -%dot2_1 = OpDot %f32 %f32vec2_01 %f32vec2_12 -%dot2_2 = OpDot %f32 %f32vec2_01 %f32vec2_01 -%dot2_3 = OpDot %f32 %f32vec2_12 %f32vec2_12 -%dot3_1 = OpDot %f32 %f32vec3_012 %f32vec3_123 -%dot3_2 = OpDot %f32 %f32vec3_012 %f32vec3_012 -%dot3_3 = OpDot %f32 %f32vec3_123 %f32vec3_123 -%dot4_1 = OpDot %f32 %f32vec4_0123 %f32vec4_1234 -%dot4_2 = OpDot %f32 %f32vec4_0123 %f32vec4_0123 -%dot4_3 = OpDot %f32 %f32vec4_1234 %f32vec4_1234 -)"); -} - -TEST_P(MarkvTest, F32VectorCompositeConstruct) { - TestEncodeDecodeShaderMainBody(GetParam(), R"( -%cc1 = OpCompositeConstruct %f32vec4 %f32vec2_01 %f32vec2_12 -%cc2 = OpCompositeConstruct %f32vec3 %f32vec2_01 %f32_2 -%cc3 = OpCompositeConstruct %f32vec2 %f32_1 %f32_2 -%cc4 = OpCompositeConstruct %f32vec4 %f32_1 %f32_2 %cc3 -)"); -} - -TEST_P(MarkvTest, U32VectorCompositeConstruct) { - TestEncodeDecodeShaderMainBody(GetParam(), R"( -%cc1 = OpCompositeConstruct %u32vec4 %u32vec2_01 %u32vec2_12 -%cc2 = OpCompositeConstruct %u32vec3 %u32vec2_01 %u32_2 -%cc3 = OpCompositeConstruct %u32vec2 %u32_1 %u32_2 -%cc4 = OpCompositeConstruct %u32vec4 %u32_1 %u32_2 %cc3 -)"); -} - -TEST_P(MarkvTest, S32VectorCompositeConstruct) { - TestEncodeDecodeShaderMainBody(GetParam(), R"( -%cc1 = OpCompositeConstruct %u32vec4 %u32vec2_01 %u32vec2_12 -%cc2 = OpCompositeConstruct %u32vec3 %u32vec2_01 %u32_2 -%cc3 = OpCompositeConstruct %u32vec2 %u32_1 %u32_2 -%cc4 = OpCompositeConstruct %u32vec4 %u32_1 %u32_2 %cc3 -)"); -} - -TEST_P(MarkvTest, F32VectorCompositeExtract) { - TestEncodeDecodeShaderMainBody(GetParam(), R"( -%f32vec4_3210 = OpCompositeConstruct %f32vec4 %f32_3 %f32_2 %f32_1 %f32_0 -%f32vec3_013 = OpCompositeExtract %f32vec3 %f32vec4_0123 0 1 3 -)"); -} - -TEST_P(MarkvTest, F32VectorComparison) { - TestEncodeDecodeShaderMainBody(GetParam(), R"( -%f32vec4_3210 = OpCompositeConstruct %f32vec4 %f32_3 %f32_2 %f32_1 %f32_0 -%c1 = OpFOrdEqual %boolvec4 %f32vec4_0123 %f32vec4_3210 -%c2 = OpFUnordEqual %boolvec4 %f32vec4_0123 %f32vec4_3210 -%c3 = OpFOrdNotEqual %boolvec4 %f32vec4_0123 %f32vec4_3210 -%c4 = OpFUnordNotEqual %boolvec4 %f32vec4_0123 %f32vec4_3210 -%c5 = OpFOrdLessThan %boolvec4 %f32vec4_0123 %f32vec4_3210 -%c6 = OpFUnordLessThan %boolvec4 %f32vec4_0123 %f32vec4_3210 -%c7 = OpFOrdGreaterThan %boolvec4 %f32vec4_0123 %f32vec4_3210 -%c8 = OpFUnordGreaterThan %boolvec4 %f32vec4_0123 %f32vec4_3210 -%c9 = OpFOrdLessThanEqual %boolvec4 %f32vec4_0123 %f32vec4_3210 -%c10 = OpFUnordLessThanEqual %boolvec4 %f32vec4_0123 %f32vec4_3210 -%c11 = OpFOrdGreaterThanEqual %boolvec4 %f32vec4_0123 %f32vec4_3210 -%c12 = OpFUnordGreaterThanEqual %boolvec4 %f32vec4_0123 %f32vec4_3210 -)"); -} - -TEST_P(MarkvTest, VectorShuffle) { - TestEncodeDecodeShaderMainBody(GetParam(), R"( -%f32vec4_3210 = OpCompositeConstruct %f32vec4 %f32_3 %f32_2 %f32_1 %f32_0 -%sh1 = OpVectorShuffle %f32vec2 %f32vec4_0123 %f32vec4_3210 3 6 -%sh2 = OpVectorShuffle %f32vec3 %f32vec2_01 %f32vec4_3210 0 3 4 -)"); -} - -TEST_P(MarkvTest, VectorTimesScalar) { - TestEncodeDecodeShaderMainBody(GetParam(), R"( -%f32vec4_3210 = OpCompositeConstruct %f32vec4 %f32_3 %f32_2 %f32_1 %f32_0 -%res1 = OpVectorTimesScalar %f32vec4 %f32vec4_0123 %f32_2 -%res2 = OpVectorTimesScalar %f32vec4 %f32vec4_3210 %f32_2 -)"); -} - -TEST_P(MarkvTest, SpirvSpecSample) { - TestEncodeDecode(GetParam(), R"( - OpCapability Shader - %1 = OpExtInstImport "GLSL.std.450" - OpMemoryModel Logical GLSL450 - OpEntryPoint Fragment %4 "main" %31 %33 %42 %57 - OpExecutionMode %4 OriginLowerLeft - -; Debug information - OpSource GLSL 450 - OpName %4 "main" - OpName %9 "scale" - OpName %17 "S" - OpMemberName %17 0 "b" - OpMemberName %17 1 "v" - OpMemberName %17 2 "i" - OpName %18 "blockName" - OpMemberName %18 0 "s" - OpMemberName %18 1 "cond" - OpName %20 "" - OpName %31 "color" - OpName %33 "color1" - OpName %42 "color2" - OpName %48 "i" - OpName %57 "multiplier" - -; Annotations (non-debug) - OpDecorate %15 ArrayStride 16 - OpMemberDecorate %17 0 Offset 0 - OpMemberDecorate %17 1 Offset 16 - OpMemberDecorate %17 2 Offset 96 - OpMemberDecorate %18 0 Offset 0 - OpMemberDecorate %18 1 Offset 112 - OpDecorate %18 Block - OpDecorate %20 DescriptorSet 0 - OpDecorate %42 NoPerspective - -; All types, variables, and constants - %2 = OpTypeVoid - %3 = OpTypeFunction %2 ; void () - %6 = OpTypeFloat 32 ; 32-bit float - %7 = OpTypeVector %6 4 ; vec4 - %8 = OpTypePointer Function %7 ; function-local vec4* - %10 = OpConstant %6 1 - %11 = OpConstant %6 2 - %12 = OpConstantComposite %7 %10 %10 %11 %10 ; vec4(1.0, 1.0, 2.0, 1.0) - %13 = OpTypeInt 32 0 ; 32-bit int, sign-less - %14 = OpConstant %13 5 - %15 = OpTypeArray %7 %14 - %16 = OpTypeInt 32 1 - %17 = OpTypeStruct %13 %15 %16 - %18 = OpTypeStruct %17 %13 - %19 = OpTypePointer Uniform %18 - %20 = OpVariable %19 Uniform - %21 = OpConstant %16 1 - %22 = OpTypePointer Uniform %13 - %25 = OpTypeBool - %26 = OpConstant %13 0 - %30 = OpTypePointer Output %7 - %31 = OpVariable %30 Output - %32 = OpTypePointer Input %7 - %33 = OpVariable %32 Input - %35 = OpConstant %16 0 - %36 = OpConstant %16 2 - %37 = OpTypePointer Uniform %7 - %42 = OpVariable %32 Input - %47 = OpTypePointer Function %16 - %55 = OpConstant %16 4 - %57 = OpVariable %32 Input - -; All functions - %4 = OpFunction %2 None %3 ; main() - %5 = OpLabel - %9 = OpVariable %8 Function - %48 = OpVariable %47 Function - OpStore %9 %12 - %23 = OpAccessChain %22 %20 %21 ; location of cond - %24 = OpLoad %13 %23 ; load 32-bit int from cond - %27 = OpINotEqual %25 %24 %26 ; convert to bool - OpSelectionMerge %29 None ; structured if - OpBranchConditional %27 %28 %41 ; if cond - %28 = OpLabel ; then - %34 = OpLoad %7 %33 - %38 = OpAccessChain %37 %20 %35 %21 %36 ; s.v[2] - %39 = OpLoad %7 %38 - %40 = OpFAdd %7 %34 %39 - OpStore %31 %40 - OpBranch %29 - %41 = OpLabel ; else - %43 = OpLoad %7 %42 - %44 = OpExtInst %7 %1 Sqrt %43 ; extended instruction sqrt - %45 = OpLoad %7 %9 - %46 = OpFMul %7 %44 %45 - OpStore %31 %46 - OpBranch %29 - %29 = OpLabel ; endif - OpStore %48 %35 - OpBranch %49 - %49 = OpLabel - OpLoopMerge %51 %52 None ; structured loop - OpBranch %53 - %53 = OpLabel - %54 = OpLoad %16 %48 - %56 = OpSLessThan %25 %54 %55 ; i < 4 ? - OpBranchConditional %56 %50 %51 ; body or break - %50 = OpLabel ; body - %58 = OpLoad %7 %57 - %59 = OpLoad %7 %31 - %60 = OpFMul %7 %59 %58 - OpStore %31 %60 - OpBranch %52 - %52 = OpLabel ; continue target - %61 = OpLoad %16 %48 - %62 = OpIAdd %16 %61 %21 ; ++i - OpStore %48 %62 - OpBranch %49 ; loop back - %51 = OpLabel ; loop merge point - OpReturn - OpFunctionEnd -)"); -} - -TEST_P(MarkvTest, SampleFromDeadBranchEliminationTest) { - TestEncodeDecode(GetParam(), R"( -OpCapability Shader -%1 = OpExtInstImport "GLSL.std.450" -OpMemoryModel Logical GLSL450 -OpEntryPoint Fragment %main "main" %gl_FragColor -OpExecutionMode %main OriginUpperLeft -OpSource GLSL 140 -OpName %main "main" -OpName %gl_FragColor "gl_FragColor" -%void = OpTypeVoid -%5 = OpTypeFunction %void -%bool = OpTypeBool -%true = OpConstantTrue %bool -%float = OpTypeFloat 32 -%v4float = OpTypeVector %float 4 -%_ptr_Function_v4float = OpTypePointer Function %v4float -%float_0 = OpConstant %float 0 -%12 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0 -%float_1 = OpConstant %float 1 -%14 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1 -%_ptr_Output_v4float = OpTypePointer Output %v4float -%gl_FragColor = OpVariable %_ptr_Output_v4float Output -%_ptr_Input_v4float = OpTypePointer Input %v4float -%main = OpFunction %void None %5 -%17 = OpLabel -OpSelectionMerge %18 None -OpBranchConditional %true %19 %20 -%19 = OpLabel -OpBranch %18 -%20 = OpLabel -OpBranch %18 -%18 = OpLabel -%21 = OpPhi %v4float %12 %19 %14 %20 -OpStore %gl_FragColor %21 -OpReturn -OpFunctionEnd -)"); -} - -INSTANTIATE_TEST_CASE_P(AllMarkvModels, MarkvTest, - ::testing::ValuesIn(std::vector{ - kMarkvModelShaderLite, - kMarkvModelShaderMid, - kMarkvModelShaderMax, - }), ); - -} // namespace -} // namespace comp -} // namespace spvtools diff --git a/third_party/spirv-tools/test/cpp_interface_test.cpp b/third_party/spirv-tools/test/cpp_interface_test.cpp index bcc2cd6c75..538d40fd44 100644 --- a/third_party/spirv-tools/test/cpp_interface_test.cpp +++ b/third_party/spirv-tools/test/cpp_interface_test.cpp @@ -36,6 +36,10 @@ OpMemoryModel Logical GLSL450 )"; } +// When we assemble with a target environment of SPIR-V 1.1, we expect +// the following in the module header version word. +const uint32_t kExpectedSpvVersion = 0x10100; + TEST(CppInterface, SuccessfulRoundTrip) { const std::string input_text = "%2 = OpSizeOf %1 %3\n"; SpirvTools t(SPV_ENV_UNIVERSAL_1_1); @@ -44,7 +48,7 @@ TEST(CppInterface, SuccessfulRoundTrip) { EXPECT_TRUE(t.Assemble(input_text, &binary)); EXPECT_TRUE(binary.size() > 5u); EXPECT_EQ(SpvMagicNumber, binary[0]); - EXPECT_EQ(SpvVersion, binary[1]); + EXPECT_EQ(kExpectedSpvVersion, binary[1]); // This cannot pass validation since %1 is not defined. t.SetMessageConsumer([](spv_message_level_t level, const char* source, @@ -54,7 +58,8 @@ TEST(CppInterface, SuccessfulRoundTrip) { EXPECT_EQ(0u, position.line); EXPECT_EQ(0u, position.column); EXPECT_EQ(1u, position.index); - EXPECT_STREQ("ID 1 has not been defined\n %2 = OpSizeOf %1 %3\n", message); + EXPECT_STREQ("ID 1[%1] has not been defined\n %2 = OpSizeOf %1 %3\n", + message); }); EXPECT_FALSE(t.Validate(binary)); @@ -70,7 +75,7 @@ TEST(CppInterface, AssembleEmptyModule) { // We only have the header. EXPECT_EQ(5u, binary.size()); EXPECT_EQ(SpvMagicNumber, binary[0]); - EXPECT_EQ(SpvVersion, binary[1]); + EXPECT_EQ(kExpectedSpvVersion, binary[1]); } TEST(CppInterface, AssembleOverloads) { @@ -81,21 +86,21 @@ TEST(CppInterface, AssembleOverloads) { EXPECT_TRUE(t.Assemble(input_text, &binary)); EXPECT_TRUE(binary.size() > 5u); EXPECT_EQ(SpvMagicNumber, binary[0]); - EXPECT_EQ(SpvVersion, binary[1]); + EXPECT_EQ(kExpectedSpvVersion, binary[1]); } { std::vector binary; EXPECT_TRUE(t.Assemble(input_text.data(), input_text.size(), &binary)); EXPECT_TRUE(binary.size() > 5u); EXPECT_EQ(SpvMagicNumber, binary[0]); - EXPECT_EQ(SpvVersion, binary[1]); + EXPECT_EQ(kExpectedSpvVersion, binary[1]); } { // Ignore the last newline. std::vector binary; EXPECT_TRUE(t.Assemble(input_text.data(), input_text.size() - 1, &binary)); EXPECT_TRUE(binary.size() > 5u); EXPECT_EQ(SpvMagicNumber, binary[0]); - EXPECT_EQ(SpvVersion, binary[1]); + EXPECT_EQ(kExpectedSpvVersion, binary[1]); } } diff --git a/third_party/spirv-tools/test/enum_set_test.cpp b/third_party/spirv-tools/test/enum_set_test.cpp index ddacd42147..047d6427c7 100644 --- a/third_party/spirv-tools/test/enum_set_test.cpp +++ b/third_party/spirv-tools/test/enum_set_test.cpp @@ -267,24 +267,24 @@ TEST_P(CapabilitySetForEachTest, OperatorEqualsSelfAssign) { EXPECT_THAT(ElementsIn(assigned), Eq(GetParam().expected)); } -INSTANTIATE_TEST_CASE_P(Samples, CapabilitySetForEachTest, - ValuesIn(std::vector{ - {{}, {}}, - {{SpvCapabilityMatrix}, {SpvCapabilityMatrix}}, - {{SpvCapabilityKernel, SpvCapabilityShader}, - {SpvCapabilityShader, SpvCapabilityKernel}}, - {{static_cast(999)}, - {static_cast(999)}}, - {{static_cast(0x7fffffff)}, - {static_cast(0x7fffffff)}}, - // Mixture and out of order - {{static_cast(0x7fffffff), - static_cast(100), - SpvCapabilityShader, SpvCapabilityMatrix}, - {SpvCapabilityMatrix, SpvCapabilityShader, - static_cast(100), - static_cast(0x7fffffff)}}, - }), ); +INSTANTIATE_TEST_SUITE_P(Samples, CapabilitySetForEachTest, + ValuesIn(std::vector{ + {{}, {}}, + {{SpvCapabilityMatrix}, {SpvCapabilityMatrix}}, + {{SpvCapabilityKernel, SpvCapabilityShader}, + {SpvCapabilityShader, SpvCapabilityKernel}}, + {{static_cast(999)}, + {static_cast(999)}}, + {{static_cast(0x7fffffff)}, + {static_cast(0x7fffffff)}}, + // Mixture and out of order + {{static_cast(0x7fffffff), + static_cast(100), + SpvCapabilityShader, SpvCapabilityMatrix}, + {SpvCapabilityMatrix, SpvCapabilityShader, + static_cast(100), + static_cast(0x7fffffff)}}, + })); } // namespace } // namespace spvtools diff --git a/third_party/spirv-tools/test/enum_string_mapping_test.cpp b/third_party/spirv-tools/test/enum_string_mapping_test.cpp index b525d6014a..a0379c18cf 100644 --- a/third_party/spirv-tools/test/enum_string_mapping_test.cpp +++ b/third_party/spirv-tools/test/enum_string_mapping_test.cpp @@ -64,7 +64,7 @@ TEST_P(CapabilityTest, TestCapabilityToString) { EXPECT_EQ(capability_str, result_str); } -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( AllExtensions, ExtensionTest, ValuesIn(std::vector>({ {Extension::kSPV_KHR_16bit_storage, "SPV_KHR_16bit_storage"}, @@ -89,13 +89,13 @@ INSTANTIATE_TEST_CASE_P( {Extension::kSPV_KHR_8bit_storage, "SPV_KHR_8bit_storage"}, }))); -INSTANTIATE_TEST_CASE_P(UnknownExtensions, UnknownExtensionTest, - Values("", "SPV_KHR_", "SPV_KHR_device_group_ERROR", - /*alphabetically before all extensions*/ "A", - /*alphabetically after all extensions*/ "Z", - "SPV_ERROR_random_string_hfsdklhlktherh")); +INSTANTIATE_TEST_SUITE_P(UnknownExtensions, UnknownExtensionTest, + Values("", "SPV_KHR_", "SPV_KHR_device_group_ERROR", + /*alphabetically before all extensions*/ "A", + /*alphabetically after all extensions*/ "Z", + "SPV_ERROR_random_string_hfsdklhlktherh")); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( AllCapabilities, CapabilityTest, ValuesIn(std::vector>( {{SpvCapabilityMatrix, "Matrix"}, @@ -189,7 +189,7 @@ INSTANTIATE_TEST_CASE_P( "ShaderViewportIndexLayerEXT"}, {SpvCapabilityShaderViewportMaskNV, "ShaderViewportMaskNV"}, {SpvCapabilityShaderStereoViewNV, "ShaderStereoViewNV"}, - {SpvCapabilityPerViewAttributesNV, "PerViewAttributesNV"}})), ); + {SpvCapabilityPerViewAttributesNV, "PerViewAttributesNV"}}))); } // namespace } // namespace spvtools diff --git a/third_party/spirv-tools/test/ext_inst.cldebug100_test.cpp b/third_party/spirv-tools/test/ext_inst.cldebug100_test.cpp new file mode 100644 index 0000000000..4f1e10672d --- /dev/null +++ b/third_party/spirv-tools/test/ext_inst.cldebug100_test.cpp @@ -0,0 +1,1070 @@ +// Copyright (c) 2017-2019 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 +#include + +#include "OpenCLDebugInfo100.h" +#include "gmock/gmock.h" +#include "source/util/string_utils.h" +#include "spirv/unified1/spirv.h" +#include "test/test_fixture.h" +#include "test/unit_spirv.h" + +// This file tests the correctness of encoding and decoding of instructions +// involving the OpenCL.DebugInfo.100 extended instruction set. +// Validation is not checked here. + +namespace spvtools { +namespace { + +using spvtest::Concatenate; +using spvtest::MakeInstruction; +using testing::Eq; +using utils::MakeVector; + +// Test values of enums vs. what is written in the spec. + +TEST(ExtInstCLDebugInfo, InstructionValues) { + EXPECT_EQ(0, OpenCLDebugInfo100DebugInfoNone); + EXPECT_EQ(1, OpenCLDebugInfo100DebugCompilationUnit); + EXPECT_EQ(2, OpenCLDebugInfo100DebugTypeBasic); + EXPECT_EQ(3, OpenCLDebugInfo100DebugTypePointer); + EXPECT_EQ(4, OpenCLDebugInfo100DebugTypeQualifier); + EXPECT_EQ(5, OpenCLDebugInfo100DebugTypeArray); + EXPECT_EQ(6, OpenCLDebugInfo100DebugTypeVector); + EXPECT_EQ(7, OpenCLDebugInfo100DebugTypedef); + EXPECT_EQ(8, OpenCLDebugInfo100DebugTypeFunction); + EXPECT_EQ(9, OpenCLDebugInfo100DebugTypeEnum); + EXPECT_EQ(10, OpenCLDebugInfo100DebugTypeComposite); + EXPECT_EQ(11, OpenCLDebugInfo100DebugTypeMember); + EXPECT_EQ(12, OpenCLDebugInfo100DebugTypeInheritance); + EXPECT_EQ(13, OpenCLDebugInfo100DebugTypePtrToMember); + EXPECT_EQ(14, OpenCLDebugInfo100DebugTypeTemplate); + EXPECT_EQ(15, OpenCLDebugInfo100DebugTypeTemplateParameter); + EXPECT_EQ(16, OpenCLDebugInfo100DebugTypeTemplateTemplateParameter); + EXPECT_EQ(17, OpenCLDebugInfo100DebugTypeTemplateParameterPack); + EXPECT_EQ(18, OpenCLDebugInfo100DebugGlobalVariable); + EXPECT_EQ(19, OpenCLDebugInfo100DebugFunctionDeclaration); + EXPECT_EQ(20, OpenCLDebugInfo100DebugFunction); + EXPECT_EQ(21, OpenCLDebugInfo100DebugLexicalBlock); + EXPECT_EQ(22, OpenCLDebugInfo100DebugLexicalBlockDiscriminator); + EXPECT_EQ(23, OpenCLDebugInfo100DebugScope); + EXPECT_EQ(24, OpenCLDebugInfo100DebugNoScope); + EXPECT_EQ(25, OpenCLDebugInfo100DebugInlinedAt); + EXPECT_EQ(26, OpenCLDebugInfo100DebugLocalVariable); + EXPECT_EQ(27, OpenCLDebugInfo100DebugInlinedVariable); + EXPECT_EQ(28, OpenCLDebugInfo100DebugDeclare); + EXPECT_EQ(29, OpenCLDebugInfo100DebugValue); + EXPECT_EQ(30, OpenCLDebugInfo100DebugOperation); + EXPECT_EQ(31, OpenCLDebugInfo100DebugExpression); + EXPECT_EQ(32, OpenCLDebugInfo100DebugMacroDef); + EXPECT_EQ(33, OpenCLDebugInfo100DebugMacroUndef); + EXPECT_EQ(34, OpenCLDebugInfo100DebugImportedEntity); + EXPECT_EQ(35, OpenCLDebugInfo100DebugSource); +} + +TEST(ExtInstCLDebugInfo, InfoFlagValues) { + EXPECT_EQ(1 << 0, OpenCLDebugInfo100FlagIsProtected); + EXPECT_EQ(1 << 1, OpenCLDebugInfo100FlagIsPrivate); + EXPECT_EQ(((1 << 0) | (1 << 1)), OpenCLDebugInfo100FlagIsPublic); + EXPECT_EQ(1 << 2, OpenCLDebugInfo100FlagIsLocal); + EXPECT_EQ(1 << 3, OpenCLDebugInfo100FlagIsDefinition); + EXPECT_EQ(1 << 4, OpenCLDebugInfo100FlagFwdDecl); + EXPECT_EQ(1 << 5, OpenCLDebugInfo100FlagArtificial); + EXPECT_EQ(1 << 6, OpenCLDebugInfo100FlagExplicit); + EXPECT_EQ(1 << 7, OpenCLDebugInfo100FlagPrototyped); + EXPECT_EQ(1 << 8, OpenCLDebugInfo100FlagObjectPointer); + EXPECT_EQ(1 << 9, OpenCLDebugInfo100FlagStaticMember); + EXPECT_EQ(1 << 10, OpenCLDebugInfo100FlagIndirectVariable); + EXPECT_EQ(1 << 11, OpenCLDebugInfo100FlagLValueReference); + EXPECT_EQ(1 << 12, OpenCLDebugInfo100FlagRValueReference); + EXPECT_EQ(1 << 13, OpenCLDebugInfo100FlagIsOptimized); + EXPECT_EQ(1 << 14, OpenCLDebugInfo100FlagIsEnumClass); + EXPECT_EQ(1 << 15, OpenCLDebugInfo100FlagTypePassByValue); + EXPECT_EQ(1 << 16, OpenCLDebugInfo100FlagTypePassByReference); +} + +TEST(ExtInstCLDebugInfo, BaseTypeAttributeEndodingValues) { + EXPECT_EQ(0, OpenCLDebugInfo100Unspecified); + EXPECT_EQ(1, OpenCLDebugInfo100Address); + EXPECT_EQ(2, OpenCLDebugInfo100Boolean); + EXPECT_EQ(3, OpenCLDebugInfo100Float); + EXPECT_EQ(4, OpenCLDebugInfo100Signed); + EXPECT_EQ(5, OpenCLDebugInfo100SignedChar); + EXPECT_EQ(6, OpenCLDebugInfo100Unsigned); + EXPECT_EQ(7, OpenCLDebugInfo100UnsignedChar); +} + +TEST(ExtInstCLDebugInfo, CompositeTypeValues) { + EXPECT_EQ(0, OpenCLDebugInfo100Class); + EXPECT_EQ(1, OpenCLDebugInfo100Structure); + EXPECT_EQ(2, OpenCLDebugInfo100Union); +} + +TEST(ExtInstCLDebugInfo, TypeQualifierValues) { + EXPECT_EQ(0, OpenCLDebugInfo100ConstType); + EXPECT_EQ(1, OpenCLDebugInfo100VolatileType); + EXPECT_EQ(2, OpenCLDebugInfo100RestrictType); + EXPECT_EQ(3, OpenCLDebugInfo100AtomicType); +} + +TEST(ExtInstCLDebugInfo, DebugOperationValues) { + EXPECT_EQ(0, OpenCLDebugInfo100Deref); + EXPECT_EQ(1, OpenCLDebugInfo100Plus); + EXPECT_EQ(2, OpenCLDebugInfo100Minus); + EXPECT_EQ(3, OpenCLDebugInfo100PlusUconst); + EXPECT_EQ(4, OpenCLDebugInfo100BitPiece); + EXPECT_EQ(5, OpenCLDebugInfo100Swap); + EXPECT_EQ(6, OpenCLDebugInfo100Xderef); + EXPECT_EQ(7, OpenCLDebugInfo100StackValue); + EXPECT_EQ(8, OpenCLDebugInfo100Constu); + EXPECT_EQ(9, OpenCLDebugInfo100Fragment); +} + +TEST(ExtInstCLDebugInfo, ImportedEntityValues) { + EXPECT_EQ(0, OpenCLDebugInfo100ImportedModule); + EXPECT_EQ(1, OpenCLDebugInfo100ImportedDeclaration); +} + +// Test round trip through assembler and disassembler. + +struct InstructionCase { + uint32_t opcode; + std::string name; + std::string operands; + std::vector expected_operands; +}; + +using ExtInstCLDebugInfo100RoundTripTest = + spvtest::TextToBinaryTestBase<::testing::TestWithParam>; +using ExtInstCLDebugInfo100RoundTripTestExplicit = spvtest::TextToBinaryTest; + +TEST_P(ExtInstCLDebugInfo100RoundTripTest, ParameterizedExtInst) { + const std::string input = + "%1 = OpExtInstImport \"OpenCL.DebugInfo.100\"\n" + "%3 = OpExtInst %2 %1 " + + GetParam().name + GetParam().operands + "\n"; + // First make sure it assembles correctly. + std::cout << input << std::endl; + EXPECT_THAT(CompiledInstructions(input), + Eq(Concatenate( + {MakeInstruction(SpvOpExtInstImport, {1}, + MakeVector("OpenCL.DebugInfo.100")), + MakeInstruction(SpvOpExtInst, {2, 3, 1, GetParam().opcode}, + GetParam().expected_operands)}))) + << input; + // Now check the round trip through the disassembler. + EXPECT_THAT(EncodeAndDecodeSuccessfully(input), input) << input; +} + +#define EPREFIX "Debug" + +#define CASE_0(Enum) \ + { \ + uint32_t(OpenCLDebugInfo100Debug##Enum), EPREFIX #Enum, "", {} \ + } + +#define CASE_ILL(Enum, L0, L1) \ + { \ + uint32_t(OpenCLDebugInfo100Debug##Enum), EPREFIX #Enum, \ + " %4 " #L0 " " #L1, { \ + 4, L0, L1 \ + } \ + } + +#define CASE_IL(Enum, L0) \ + { \ + uint32_t(OpenCLDebugInfo100Debug##Enum), EPREFIX #Enum, " %4 " #L0, { \ + 4, L0 \ + } \ + } + +#define CASE_I(Enum) \ + { \ + uint32_t(OpenCLDebugInfo100Debug##Enum), EPREFIX #Enum, " %4", { 4 } \ + } + +#define CASE_II(Enum) \ + { \ + uint32_t(OpenCLDebugInfo100Debug##Enum), EPREFIX #Enum, " %4 %5", { 4, 5 } \ + } + +#define CASE_III(Enum) \ + { \ + uint32_t(OpenCLDebugInfo100Debug##Enum), EPREFIX #Enum, " %4 %5 %6", { \ + 4, 5, 6 \ + } \ + } + +#define CASE_IIII(Enum) \ + { \ + uint32_t(OpenCLDebugInfo100Debug##Enum), EPREFIX #Enum, " %4 %5 %6 %7", { \ + 4, 5, 6, 7 \ + } \ + } + +#define CASE_IIIII(Enum) \ + { \ + uint32_t(OpenCLDebugInfo100Debug##Enum), EPREFIX #Enum, " %4 %5 %6 %7 %8", \ + { \ + 4, 5, 6, 7, 8 \ + } \ + } + +#define CASE_IIIIII(Enum) \ + { \ + uint32_t(OpenCLDebugInfo100Debug##Enum), EPREFIX #Enum, \ + " %4 %5 %6 %7 %8 %9", { \ + 4, 5, 6, 7, 8, 9 \ + } \ + } + +#define CASE_IIIIIII(Enum) \ + { \ + uint32_t(OpenCLDebugInfo100Debug##Enum), EPREFIX #Enum, \ + " %4 %5 %6 %7 %8 %9 %10", { \ + 4, 5, 6, 7, 8, 9, 10 \ + } \ + } + +#define CASE_IIILLI(Enum, L0, L1) \ + { \ + uint32_t(OpenCLDebugInfo100Debug##Enum), EPREFIX #Enum, \ + " %4 %5 %6 " #L0 " " #L1 " %7", { \ + 4, 5, 6, L0, L1, 7 \ + } \ + } + +#define CASE_IIILLIF(Enum, L0, L1, Fstr, Fnum) \ + { \ + uint32_t(OpenCLDebugInfo100Debug##Enum), EPREFIX #Enum, \ + " %4 %5 %6 " #L0 " " #L1 " %7 " Fstr, { \ + 4, 5, 6, L0, L1, 7, Fnum \ + } \ + } + +#define CASE_IIILLIFL(Enum, L0, L1, Fstr, Fnum, L2) \ + { \ + uint32_t(OpenCLDebugInfo100Debug##Enum), EPREFIX #Enum, \ + " %4 %5 %6 " #L0 " " #L1 " %7 " Fstr " " #L2, { \ + 4, 5, 6, L0, L1, 7, Fnum, L2 \ + } \ + } + +#define CASE_IIILLIL(Enum, L0, L1, L2) \ + { \ + uint32_t(OpenCLDebugInfo100Debug##Enum), EPREFIX #Enum, \ + " %4 %5 %6 " #L0 " " #L1 " %7 " #L2, { \ + 4, 5, 6, L0, L1, 7, L2 \ + } \ + } + +#define CASE_IE(Enum, E0) \ + { \ + uint32_t(OpenCLDebugInfo100Debug##Enum), EPREFIX #Enum, " %4 " #E0, { \ + 4, uint32_t(OpenCLDebugInfo100##E0) \ + } \ + } + +#define CASE_IEIILLI(Enum, E0, L1, L2) \ + { \ + uint32_t(OpenCLDebugInfo100Debug##Enum), EPREFIX #Enum, \ + " %4 " #E0 " %5 %6 " #L1 " " #L2 " %7", { \ + 4, uint32_t(OpenCLDebugInfo100##E0), 5, 6, L1, L2, 7 \ + } \ + } + +#define CASE_IIE(Enum, E0) \ + { \ + uint32_t(OpenCLDebugInfo100Debug##Enum), EPREFIX #Enum, " %4 %5 " #E0, { \ + 4, 5, uint32_t(OpenCLDebugInfo100##E0) \ + } \ + } + +#define CASE_ISF(Enum, S0, Fstr, Fnum) \ + { \ + uint32_t(OpenCLDebugInfo100Debug##Enum), EPREFIX #Enum, \ + " %4 " #S0 " " Fstr, { \ + 4, uint32_t(SpvStorageClass##S0), Fnum \ + } \ + } + +#define CASE_LII(Enum, L0) \ + { \ + uint32_t(OpenCLDebugInfo100Debug##Enum), EPREFIX #Enum, " " #L0 " %4 %5", \ + { \ + L0, 4, 5 \ + } \ + } + +#define CASE_LLIe(Enum, L0, L1, RawEnumName, RawEnumValue) \ + { \ + uint32_t(OpenCLDebugInfo100Debug##Enum), EPREFIX #Enum, \ + " " #L0 " " #L1 " %4 " RawEnumName, { \ + L0, L1, 4, RawEnumValue \ + } \ + } + +#define CASE_ILI(Enum, L0) \ + { \ + uint32_t(OpenCLDebugInfo100Debug##Enum), EPREFIX #Enum, " %4 " #L0 " %5", \ + { \ + 4, L0, 5 \ + } \ + } + +#define CASE_ILII(Enum, L0) \ + { \ + uint32_t(OpenCLDebugInfo100Debug##Enum), EPREFIX #Enum, \ + " %4 " #L0 " %5 %6", { \ + 4, L0, 5, 6 \ + } \ + } + +#define CASE_ILLII(Enum, L0, L1) \ + { \ + uint32_t(OpenCLDebugInfo100Debug##Enum), EPREFIX #Enum, \ + " %4 " #L0 " " #L1 " %5 %6", { \ + 4, L0, L1, 5, 6 \ + } \ + } + +#define CASE_IIILLIIF(Enum, L0, L1, Fstr, Fnum) \ + { \ + uint32_t(OpenCLDebugInfo100Debug##Enum), EPREFIX #Enum, \ + " %4 %5 %6 " #L0 " " #L1 " %7 %8 " Fstr, { \ + 4, 5, 6, L0, L1, 7, 8, Fnum \ + } \ + } + +#define CASE_IIILLIIFII(Enum, L0, L1, Fstr, Fnum) \ + { \ + uint32_t(OpenCLDebugInfo100Debug##Enum), EPREFIX #Enum, \ + " %4 %5 %6 " #L0 " " #L1 " %7 %8 " Fstr " %9 %10", { \ + 4, 5, 6, L0, L1, 7, 8, Fnum, 9, 10 \ + } \ + } + +#define CASE_IIILLIIFIIII(Enum, L0, L1, Fstr, Fnum) \ + { \ + uint32_t(OpenCLDebugInfo100Debug##Enum), EPREFIX #Enum, \ + " %4 %5 %6 " #L0 " " #L1 " %7 %8 " Fstr " %9 %10 %11 %12", { \ + 4, 5, 6, L0, L1, 7, 8, Fnum, 9, 10, 11, 12 \ + } \ + } + +#define CASE_IIILLIIFIIIIII(Enum, L0, L1, Fstr, Fnum) \ + { \ + uint32_t(OpenCLDebugInfo100Debug##Enum), EPREFIX #Enum, \ + " %4 %5 %6 " #L0 " " #L1 " %7 %8 " Fstr " %9 %10 %11 %12 %13 %14", { \ + 4, 5, 6, L0, L1, 7, 8, Fnum, 9, 10, 11, 12, 13, 14 \ + } \ + } + +#define CASE_IEILLIIIF(Enum, E0, L0, L1, Fstr, Fnum) \ + { \ + uint32_t(OpenCLDebugInfo100Debug##Enum), EPREFIX #Enum, \ + " %4 " #E0 " %5 " #L0 " " #L1 " %6 %7 %8 " Fstr, { \ + 4, uint32_t(OpenCLDebugInfo100##E0), 5, L0, L1, 6, 7, 8, Fnum \ + } \ + } + +#define CASE_IEILLIIIFI(Enum, E0, L0, L1, Fstr, Fnum) \ + { \ + uint32_t(OpenCLDebugInfo100Debug##Enum), EPREFIX #Enum, \ + " %4 " #E0 " %5 " #L0 " " #L1 " %6 %7 %8 " Fstr " %9", { \ + 4, uint32_t(OpenCLDebugInfo100##E0), 5, L0, L1, 6, 7, 8, Fnum, 9 \ + } \ + } + +#define CASE_IEILLIIIFII(Enum, E0, L0, L1, Fstr, Fnum) \ + { \ + uint32_t(OpenCLDebugInfo100Debug##Enum), EPREFIX #Enum, \ + " %4 " #E0 " %5 " #L0 " " #L1 " %6 %7 %8 " Fstr " %9 %10", { \ + 4, uint32_t(OpenCLDebugInfo100##E0), 5, L0, L1, 6, 7, 8, Fnum, 9, 10 \ + } \ + } + +#define CASE_IEILLIIIFIII(Enum, E0, L0, L1, Fstr, Fnum) \ + { \ + uint32_t(OpenCLDebugInfo100Debug##Enum), EPREFIX #Enum, \ + " %4 " #E0 " %5 " #L0 " " #L1 " %6 %7 %8 " Fstr " %9 %10 %11", { \ + 4, uint32_t(OpenCLDebugInfo100##E0), 5, L0, L1, 6, 7, 8, Fnum, 9, 10, 11 \ + } \ + } + +#define CASE_IEILLIIIFIIII(Enum, E0, L0, L1, Fstr, Fnum) \ + { \ + uint32_t(OpenCLDebugInfo100Debug##Enum), EPREFIX #Enum, \ + " %4 " #E0 " %5 " #L0 " " #L1 " %6 %7 %8 " Fstr " %9 %10 %11 %12", { \ + 4, uint32_t(OpenCLDebugInfo100##E0), 5, L0, L1, 6, 7, 8, Fnum, 9, 10, \ + 11, 12 \ + } \ + } + +#define CASE_IIILLIIIF(Enum, L0, L1, Fstr, Fnum) \ + { \ + uint32_t(OpenCLDebugInfo100Debug##Enum), EPREFIX #Enum, \ + " %4 %5 %6 " #L0 " " #L1 " %7 %8 %9 " Fstr, { \ + 4, 5, 6, L0, L1, 7, 8, 9, Fnum \ + } \ + } + +#define CASE_IIILLIIIFI(Enum, L0, L1, Fstr, Fnum) \ + { \ + uint32_t(OpenCLDebugInfo100Debug##Enum), EPREFIX #Enum, \ + " %4 %5 %6 " #L0 " " #L1 " %7 %8 %9 " Fstr " %10", { \ + 4, 5, 6, L0, L1, 7, 8, 9, Fnum, 10 \ + } \ + } + +#define CASE_IIIIF(Enum, Fstr, Fnum) \ + { \ + uint32_t(OpenCLDebugInfo100Debug##Enum), EPREFIX #Enum, \ + " %4 %5 %6 %7 " Fstr, { \ + 4, 5, 6, 7, Fnum \ + } \ + } + +#define CASE_IIILL(Enum, L0, L1) \ + { \ + uint32_t(OpenCLDebugInfo100Debug##Enum), EPREFIX #Enum, \ + " %4 %5 %6 " #L0 " " #L1, { \ + 4, 5, 6, L0, L1 \ + } \ + } + +#define CASE_IIIILL(Enum, L0, L1) \ + { \ + uint32_t(OpenCLDebugInfo100Debug##Enum), EPREFIX #Enum, \ + " %4 %5 %6 %7 " #L0 " " #L1, { \ + 4, 5, 6, 7, L0, L1 \ + } \ + } + +#define CASE_IILLI(Enum, L0, L1) \ + { \ + uint32_t(OpenCLDebugInfo100Debug##Enum), EPREFIX #Enum, \ + " %4 %5 " #L0 " " #L1 " %6", { \ + 4, 5, L0, L1, 6 \ + } \ + } + +#define CASE_IILLII(Enum, L0, L1) \ + { \ + uint32_t(OpenCLDebugInfo100Debug##Enum), EPREFIX #Enum, \ + " %4 %5 " #L0 " " #L1 " %6 %7", { \ + 4, 5, L0, L1, 6, 7 \ + } \ + } + +#define CASE_IILLIII(Enum, L0, L1) \ + { \ + uint32_t(OpenCLDebugInfo100Debug##Enum), EPREFIX #Enum, \ + " %4 %5 " #L0 " " #L1 " %6 %7 %8", { \ + 4, 5, L0, L1, 6, 7, 8 \ + } \ + } + +#define CASE_IILLIIII(Enum, L0, L1) \ + { \ + uint32_t(OpenCLDebugInfo100Debug##Enum), EPREFIX #Enum, \ + " %4 %5 " #L0 " " #L1 " %6 %7 %8 %9", { \ + 4, 5, L0, L1, 6, 7, 8, 9 \ + } \ + } + +#define CASE_IIILLIIFLI(Enum, L0, L1, Fstr, Fnum, L2) \ + { \ + uint32_t(OpenCLDebugInfo100Debug##Enum), EPREFIX #Enum, \ + " %4 %5 %6 " #L0 " " #L1 " %7 %8 " Fstr " " #L2 " %9", { \ + 4, 5, 6, L0, L1, 7, 8, Fnum, L2, 9 \ + } \ + } + +#define CASE_IIILLIIFLII(Enum, L0, L1, Fstr, Fnum, L2) \ + { \ + uint32_t(OpenCLDebugInfo100Debug##Enum), EPREFIX #Enum, \ + " %4 %5 %6 " #L0 " " #L1 " %7 %8 " Fstr " " #L2 " %9 %10", { \ + 4, 5, 6, L0, L1, 7, 8, Fnum, L2, 9, 10 \ + } \ + } + +#define CASE_E(Enum, E0) \ + { \ + uint32_t(OpenCLDebugInfo100Debug##Enum), EPREFIX #Enum, " " #E0, { \ + uint32_t(OpenCLDebugInfo100##E0) \ + } \ + } + +#define CASE_EI(Enum, E0) \ + { \ + uint32_t(OpenCLDebugInfo100Debug##Enum), EPREFIX #Enum, " " #E0 " %4", { \ + uint32_t(OpenCLDebugInfo100##E0), 4 \ + } \ + } + +#define CASE_EII(Enum, E0) \ + { \ + uint32_t(OpenCLDebugInfo100Debug##Enum), EPREFIX #Enum, " " #E0 " %4 %5", \ + { \ + uint32_t(OpenCLDebugInfo100##E0), 4, 5 \ + } \ + } + +#define CASE_EIII(Enum, E0) \ + { \ + uint32_t(OpenCLDebugInfo100Debug##Enum), EPREFIX #Enum, \ + " " #E0 " %4 %5 %6", { \ + uint32_t(OpenCLDebugInfo100##E0), 4, 5, 6 \ + } \ + } + +#define CASE_EIIII(Enum, E0) \ + { \ + uint32_t(OpenCLDebugInfo100Debug##Enum), EPREFIX #Enum, \ + " " #E0 " %4 %5 %6 %7", { \ + uint32_t(OpenCLDebugInfo100##E0), 4, 5, 6, 7 \ + } \ + } + +#define CASE_EIIIII(Enum, E0) \ + { \ + uint32_t(OpenCLDebugInfo100Debug##Enum), EPREFIX #Enum, \ + " " #E0 " %4 %5 %6 %7 %8", { \ + uint32_t(OpenCLDebugInfo100##E0), 4, 5, 6, 7, 8 \ + } \ + } + +#define CASE_EL(Enum, E0, L0) \ + { \ + uint32_t(OpenCLDebugInfo100Debug##Enum), EPREFIX #Enum, " " #E0 " " #L0, { \ + uint32_t(OpenCLDebugInfo100##E0), L0 \ + } \ + } + +#define CASE_ELL(Enum, E0, L0, L1) \ + { \ + uint32_t(OpenCLDebugInfo100Debug##Enum), EPREFIX #Enum, \ + " " #E0 " " #L0 " " #L1, { \ + uint32_t(OpenCLDebugInfo100##E0), L0, L1 \ + } \ + } + +// OpenCL.DebugInfo.100 4.1 Missing Debugging Information +INSTANTIATE_TEST_SUITE_P(OpenCLDebugInfo100DebugInfoNone, + ExtInstCLDebugInfo100RoundTripTest, + ::testing::ValuesIn(std::vector({ + CASE_0(InfoNone), // enum value 0 + }))); + +// OpenCL.DebugInfo.100 4.2 Compilation Unit +INSTANTIATE_TEST_SUITE_P( + OpenCLDebugInfo100DebugCompilationUnit, ExtInstCLDebugInfo100RoundTripTest, + ::testing::ValuesIn(std::vector({ + CASE_LLIe(CompilationUnit, 100, 42, "HLSL", SpvSourceLanguageHLSL), + }))); + +INSTANTIATE_TEST_SUITE_P( + OpenCLDebugInfo100DebugSource, ExtInstCLDebugInfo100RoundTripTest, + ::testing::ValuesIn(std::vector({ + // TODO(dneto): Should this be a list of sourc texts, + // to accomodate length limits? + CASE_I(Source), + CASE_II(Source), + }))); + +// OpenCL.DebugInfo.100 4.3 Type instructions +INSTANTIATE_TEST_SUITE_P(OpenCLDebugInfo100DebugTypeBasic, + ExtInstCLDebugInfo100RoundTripTest, + ::testing::ValuesIn(std::vector({ + CASE_IIE(TypeBasic, Unspecified), + CASE_IIE(TypeBasic, Address), + CASE_IIE(TypeBasic, Boolean), + CASE_IIE(TypeBasic, Float), + CASE_IIE(TypeBasic, Signed), + CASE_IIE(TypeBasic, SignedChar), + CASE_IIE(TypeBasic, Unsigned), + CASE_IIE(TypeBasic, UnsignedChar), + }))); + +// The FlagIsPublic is value is (1 << 0) | (1 << 2) which is the same +// as the bitwise-OR of FlagIsProtected and FlagIsPrivate. +// The disassembler will emit the compound expression instead. +// There is no simple fix for this. This enum is not really a mask +// for the bottom two bits. +TEST_F(ExtInstCLDebugInfo100RoundTripTestExplicit, FlagIsPublic) { + const std::string prefix = + "%1 = OpExtInstImport \"DebugInfo\"\n" + "%3 = OpExtInst %2 %1 DebugTypePointer %4 Private "; + const std::string input = prefix + "FlagIsPublic\n"; + const std::string expected = prefix + "FlagIsProtected|FlagIsPrivate\n"; + // First make sure it assembles correctly. + EXPECT_THAT( + CompiledInstructions(input), + Eq(Concatenate( + {MakeInstruction(SpvOpExtInstImport, {1}, MakeVector("DebugInfo")), + MakeInstruction(SpvOpExtInst, + {2, 3, 1, OpenCLDebugInfo100DebugTypePointer, 4, + uint32_t(SpvStorageClassPrivate), + OpenCLDebugInfo100FlagIsPublic})}))) + << input; + // Now check the round trip through the disassembler. + EXPECT_THAT(EncodeAndDecodeSuccessfully(input), Eq(expected)) << input; +} + +INSTANTIATE_TEST_SUITE_P( + OpenCLDebugInfo100DebugTypePointer, ExtInstCLDebugInfo100RoundTripTest, + ::testing::ValuesIn(std::vector({ + + //// Use each flag independently. + CASE_ISF(TypePointer, Private, "FlagIsProtected", + uint32_t(OpenCLDebugInfo100FlagIsProtected)), + CASE_ISF(TypePointer, Private, "FlagIsPrivate", + uint32_t(OpenCLDebugInfo100FlagIsPrivate)), + + // FlagIsPublic is tested above. + + CASE_ISF(TypePointer, Private, "FlagIsLocal", + uint32_t(OpenCLDebugInfo100FlagIsLocal)), + CASE_ISF(TypePointer, Private, "FlagIsDefinition", + uint32_t(OpenCLDebugInfo100FlagIsDefinition)), + CASE_ISF(TypePointer, Private, "FlagFwdDecl", + uint32_t(OpenCLDebugInfo100FlagFwdDecl)), + CASE_ISF(TypePointer, Private, "FlagArtificial", + uint32_t(OpenCLDebugInfo100FlagArtificial)), + CASE_ISF(TypePointer, Private, "FlagExplicit", + uint32_t(OpenCLDebugInfo100FlagExplicit)), + CASE_ISF(TypePointer, Private, "FlagPrototyped", + uint32_t(OpenCLDebugInfo100FlagPrototyped)), + CASE_ISF(TypePointer, Private, "FlagObjectPointer", + uint32_t(OpenCLDebugInfo100FlagObjectPointer)), + CASE_ISF(TypePointer, Private, "FlagStaticMember", + uint32_t(OpenCLDebugInfo100FlagStaticMember)), + CASE_ISF(TypePointer, Private, "FlagIndirectVariable", + uint32_t(OpenCLDebugInfo100FlagIndirectVariable)), + CASE_ISF(TypePointer, Private, "FlagLValueReference", + uint32_t(OpenCLDebugInfo100FlagLValueReference)), + CASE_ISF(TypePointer, Private, "FlagIsOptimized", + uint32_t(OpenCLDebugInfo100FlagIsOptimized)), + CASE_ISF(TypePointer, Private, "FlagIsEnumClass", + uint32_t(OpenCLDebugInfo100FlagIsEnumClass)), + CASE_ISF(TypePointer, Private, "FlagTypePassByValue", + uint32_t(OpenCLDebugInfo100FlagTypePassByValue)), + CASE_ISF(TypePointer, Private, "FlagTypePassByReference", + uint32_t(OpenCLDebugInfo100FlagTypePassByReference)), + + //// Use flags in combination, and try different storage classes. + CASE_ISF(TypePointer, Function, "FlagIsProtected|FlagIsPrivate", + uint32_t(OpenCLDebugInfo100FlagIsProtected) | + uint32_t(OpenCLDebugInfo100FlagIsPrivate)), + CASE_ISF( + TypePointer, Workgroup, + "FlagIsPrivate|FlagFwdDecl|FlagIndirectVariable|FlagIsOptimized", + uint32_t(OpenCLDebugInfo100FlagIsPrivate) | + uint32_t(OpenCLDebugInfo100FlagFwdDecl) | + uint32_t(OpenCLDebugInfo100FlagIndirectVariable) | + uint32_t(OpenCLDebugInfo100FlagIsOptimized)), + + }))); + +INSTANTIATE_TEST_SUITE_P(OpenCLDebugInfo100DebugTypeQualifier, + ExtInstCLDebugInfo100RoundTripTest, + ::testing::ValuesIn(std::vector({ + CASE_IE(TypeQualifier, ConstType), + CASE_IE(TypeQualifier, VolatileType), + CASE_IE(TypeQualifier, RestrictType), + CASE_IE(TypeQualifier, AtomicType), + }))); + +INSTANTIATE_TEST_SUITE_P(OpenCLDebugInfo100DebugTypeArray, + ExtInstCLDebugInfo100RoundTripTest, + ::testing::ValuesIn(std::vector({ + CASE_II(TypeArray), + CASE_III(TypeArray), + CASE_IIII(TypeArray), + CASE_IIIII(TypeArray), + }))); + +INSTANTIATE_TEST_SUITE_P(OpenCLDebugInfo100DebugTypeVector, + ExtInstCLDebugInfo100RoundTripTest, + ::testing::ValuesIn(std::vector({ + CASE_IL(TypeVector, 2), + CASE_IL(TypeVector, 3), + CASE_IL(TypeVector, 4), + CASE_IL(TypeVector, 16), + }))); + +INSTANTIATE_TEST_SUITE_P(OpenCLDebugInfo100DebugTypedef, + ExtInstCLDebugInfo100RoundTripTest, + ::testing::ValuesIn(std::vector({ + CASE_IIILLI(Typedef, 12, 13), + CASE_IIILLI(Typedef, 14, 99), + }))); + +INSTANTIATE_TEST_SUITE_P(OpenCLDebugInfo100DebugTypeFunction, + ExtInstCLDebugInfo100RoundTripTest, + ::testing::ValuesIn(std::vector({ + CASE_EI(TypeFunction, FlagIsProtected), + CASE_EII(TypeFunction, FlagIsDefinition), + CASE_EIII(TypeFunction, FlagArtificial), + CASE_EIIII(TypeFunction, FlagExplicit), + CASE_EIIIII(TypeFunction, FlagIsPrivate), + }))); + +INSTANTIATE_TEST_SUITE_P( + OpenCLDebugInfo100DebugTypeEnum, ExtInstCLDebugInfo100RoundTripTest, + ::testing::ValuesIn(std::vector({ + CASE_IIILLIIFII( + TypeEnum, 12, 13, + "FlagIsPrivate|FlagFwdDecl|FlagIndirectVariable|FlagIsOptimized", + uint32_t(OpenCLDebugInfo100FlagIsPrivate) | + uint32_t(OpenCLDebugInfo100FlagFwdDecl) | + uint32_t(OpenCLDebugInfo100FlagIndirectVariable) | + uint32_t(OpenCLDebugInfo100FlagIsOptimized)), + CASE_IIILLIIFIIII(TypeEnum, 17, 18, "FlagStaticMember", + uint32_t(OpenCLDebugInfo100FlagStaticMember)), + CASE_IIILLIIFIIIIII(TypeEnum, 99, 1, "FlagStaticMember", + uint32_t(OpenCLDebugInfo100FlagStaticMember)), + }))); + +INSTANTIATE_TEST_SUITE_P( + OpenCLDebugInfo100DebugTypeComposite, ExtInstCLDebugInfo100RoundTripTest, + ::testing::ValuesIn(std::vector({ + CASE_IEILLIIIF( + TypeComposite, Class, 12, 13, + "FlagIsPrivate|FlagFwdDecl|FlagIndirectVariable|FlagIsOptimized", + uint32_t(OpenCLDebugInfo100FlagIsPrivate) | + uint32_t(OpenCLDebugInfo100FlagFwdDecl) | + uint32_t(OpenCLDebugInfo100FlagIndirectVariable) | + uint32_t(OpenCLDebugInfo100FlagIsOptimized)), + // Cover all tag values: Class, Structure, Union + CASE_IEILLIIIF(TypeComposite, Class, 12, 13, "FlagIsPrivate", + uint32_t(OpenCLDebugInfo100FlagIsPrivate)), + CASE_IEILLIIIF(TypeComposite, Structure, 12, 13, "FlagIsPrivate", + uint32_t(OpenCLDebugInfo100FlagIsPrivate)), + CASE_IEILLIIIF(TypeComposite, Union, 12, 13, "FlagIsPrivate", + uint32_t(OpenCLDebugInfo100FlagIsPrivate)), + // Now add members + CASE_IEILLIIIFI(TypeComposite, Class, 9, 10, "FlagIsPrivate", + uint32_t(OpenCLDebugInfo100FlagIsPrivate)), + CASE_IEILLIIIFII(TypeComposite, Class, 9, 10, "FlagIsPrivate", + uint32_t(OpenCLDebugInfo100FlagIsPrivate)), + CASE_IEILLIIIFIII(TypeComposite, Class, 9, 10, "FlagIsPrivate", + uint32_t(OpenCLDebugInfo100FlagIsPrivate)), + CASE_IEILLIIIFIIII(TypeComposite, Class, 9, 10, "FlagIsPrivate", + uint32_t(OpenCLDebugInfo100FlagIsPrivate)), + }))); + +INSTANTIATE_TEST_SUITE_P( + OpenCLDebugInfo100DebugTypeMember, ExtInstCLDebugInfo100RoundTripTest, + ::testing::ValuesIn(std::vector({ + CASE_IIILLIIIF(TypeMember, 12, 13, "FlagIsPrivate", + uint32_t(OpenCLDebugInfo100FlagIsPrivate)), + CASE_IIILLIIIF(TypeMember, 99, 100, "FlagIsPrivate|FlagFwdDecl", + uint32_t(OpenCLDebugInfo100FlagIsPrivate) | + uint32_t(OpenCLDebugInfo100FlagFwdDecl)), + // Add the optional Id argument. + CASE_IIILLIIIFI(TypeMember, 12, 13, "FlagIsPrivate", + uint32_t(OpenCLDebugInfo100FlagIsPrivate)), + }))); + +INSTANTIATE_TEST_SUITE_P( + OpenCLDebugInfo100DebugTypeInheritance, ExtInstCLDebugInfo100RoundTripTest, + ::testing::ValuesIn(std::vector({ + CASE_IIIIF(TypeInheritance, "FlagIsPrivate", + uint32_t(OpenCLDebugInfo100FlagIsPrivate)), + CASE_IIIIF(TypeInheritance, "FlagIsPrivate|FlagFwdDecl", + uint32_t(OpenCLDebugInfo100FlagIsPrivate) | + uint32_t(OpenCLDebugInfo100FlagFwdDecl)), + }))); + +INSTANTIATE_TEST_SUITE_P(OpenCLDebugInfo100DebugTypePtrToMember, + ExtInstCLDebugInfo100RoundTripTest, + ::testing::ValuesIn(std::vector({ + CASE_II(TypePtrToMember), + }))); + +// OpenCL.DebugInfo.100 4.4 Templates + +INSTANTIATE_TEST_SUITE_P(OpenCLDebugInfo100DebugTypeTemplate, + ExtInstCLDebugInfo100RoundTripTest, + ::testing::ValuesIn(std::vector({ + CASE_II(TypeTemplate), + CASE_III(TypeTemplate), + CASE_IIII(TypeTemplate), + CASE_IIIII(TypeTemplate), + }))); + +INSTANTIATE_TEST_SUITE_P(OpenCLDebugInfo100DebugTypeTemplateParameter, + ExtInstCLDebugInfo100RoundTripTest, + ::testing::ValuesIn(std::vector({ + CASE_IIIILL(TypeTemplateParameter, 1, 2), + CASE_IIIILL(TypeTemplateParameter, 99, 102), + CASE_IIIILL(TypeTemplateParameter, 10, 7), + }))); + +INSTANTIATE_TEST_SUITE_P(OpenCLDebugInfo100DebugTypeTemplateTemplateParameter, + ExtInstCLDebugInfo100RoundTripTest, + ::testing::ValuesIn(std::vector({ + CASE_IIILL(TypeTemplateTemplateParameter, 1, 2), + CASE_IIILL(TypeTemplateTemplateParameter, 99, 102), + CASE_IIILL(TypeTemplateTemplateParameter, 10, 7), + }))); + +INSTANTIATE_TEST_SUITE_P(OpenCLDebugInfo100DebugTypeTemplateParameterPack, + ExtInstCLDebugInfo100RoundTripTest, + ::testing::ValuesIn(std::vector({ + CASE_IILLI(TypeTemplateParameterPack, 1, 2), + CASE_IILLII(TypeTemplateParameterPack, 99, 102), + CASE_IILLIII(TypeTemplateParameterPack, 10, 7), + CASE_IILLIIII(TypeTemplateParameterPack, 10, 7), + }))); + +// OpenCL.DebugInfo.100 4.5 Global Variables + +INSTANTIATE_TEST_SUITE_P( + OpenCLDebugInfo100DebugGlobalVariable, ExtInstCLDebugInfo100RoundTripTest, + ::testing::ValuesIn(std::vector({ + CASE_IIILLIIIF(GlobalVariable, 1, 2, "FlagIsOptimized", + uint32_t(OpenCLDebugInfo100FlagIsOptimized)), + CASE_IIILLIIIF(GlobalVariable, 42, 43, "FlagIsOptimized", + uint32_t(OpenCLDebugInfo100FlagIsOptimized)), + CASE_IIILLIIIFI(GlobalVariable, 1, 2, "FlagIsOptimized", + uint32_t(OpenCLDebugInfo100FlagIsOptimized)), + CASE_IIILLIIIFI(GlobalVariable, 42, 43, "FlagIsOptimized", + uint32_t(OpenCLDebugInfo100FlagIsOptimized)), + }))); + +// OpenCL.DebugInfo.100 4.6 Functions + +INSTANTIATE_TEST_SUITE_P( + OpenCLDebugInfo100DebugFunctionDeclaration, + ExtInstCLDebugInfo100RoundTripTest, + ::testing::ValuesIn(std::vector({ + CASE_IIILLIIF(FunctionDeclaration, 1, 2, "FlagIsOptimized", + uint32_t(OpenCLDebugInfo100FlagIsOptimized)), + CASE_IIILLIIF(FunctionDeclaration, 42, 43, "FlagFwdDecl", + uint32_t(OpenCLDebugInfo100FlagFwdDecl)), + }))); + +INSTANTIATE_TEST_SUITE_P( + OpenCLDebugInfo100DebugFunction, ExtInstCLDebugInfo100RoundTripTest, + ::testing::ValuesIn(std::vector({ + CASE_IIILLIIFLI(Function, 1, 2, "FlagIsOptimized", + uint32_t(OpenCLDebugInfo100FlagIsOptimized), 3), + CASE_IIILLIIFLI(Function, 42, 43, "FlagFwdDecl", + uint32_t(OpenCLDebugInfo100FlagFwdDecl), 44), + // Add the optional declaration Id. + CASE_IIILLIIFLII(Function, 1, 2, "FlagIsOptimized", + uint32_t(OpenCLDebugInfo100FlagIsOptimized), 3), + CASE_IIILLIIFLII(Function, 42, 43, "FlagFwdDecl", + uint32_t(OpenCLDebugInfo100FlagFwdDecl), 44), + }))); + +// OpenCL.DebugInfo.100 4.7 Local Information + +INSTANTIATE_TEST_SUITE_P(OpenCLDebugInfo100DebugLexicalBlock, + ExtInstCLDebugInfo100RoundTripTest, + ::testing::ValuesIn(std::vector({ + CASE_ILLII(LexicalBlock, 1, 2), + CASE_ILLII(LexicalBlock, 42, 43), + }))); + +INSTANTIATE_TEST_SUITE_P(OpenCLDebugInfo100DebugLexicalBlockDiscriminator, + ExtInstCLDebugInfo100RoundTripTest, + ::testing::ValuesIn(std::vector({ + CASE_ILI(LexicalBlockDiscriminator, 1), + CASE_ILI(LexicalBlockDiscriminator, 42), + }))); + +INSTANTIATE_TEST_SUITE_P(OpenCLDebugInfo100DebugScope, + ExtInstCLDebugInfo100RoundTripTest, + ::testing::ValuesIn(std::vector({ + CASE_I(Scope), + CASE_II(Scope), + }))); + +INSTANTIATE_TEST_SUITE_P(OpenCLDebugInfo100DebugNoScope, + ExtInstCLDebugInfo100RoundTripTest, + ::testing::ValuesIn(std::vector({ + CASE_0(NoScope), + }))); + +INSTANTIATE_TEST_SUITE_P(OpenCLDebugInfo100DebugInlinedAt, + ExtInstCLDebugInfo100RoundTripTest, + ::testing::ValuesIn(std::vector({ + CASE_LII(InlinedAt, 1), + CASE_LII(InlinedAt, 42), + }))); + +// OpenCL.DebugInfo.100 4.8 Local Variables + +INSTANTIATE_TEST_SUITE_P( + OpenCLDebugInfo100DebugLocalVariable, ExtInstCLDebugInfo100RoundTripTest, + ::testing::ValuesIn(std::vector({ + CASE_IIILLIF(LocalVariable, 1, 2, "FlagIsPrivate", + OpenCLDebugInfo100FlagIsPrivate), + CASE_IIILLIF(LocalVariable, 4, 5, "FlagIsProtected", + OpenCLDebugInfo100FlagIsProtected), + CASE_IIILLIFL(LocalVariable, 9, 99, "FlagIsProtected", + OpenCLDebugInfo100FlagIsProtected, 195), + CASE_IIILLIFL(LocalVariable, 19, 199, "FlagIsPrivate", + OpenCLDebugInfo100FlagIsPrivate, 195), + }))); + +INSTANTIATE_TEST_SUITE_P(OpenCLDebugInfo100DebugInlinedVariable, + ExtInstCLDebugInfo100RoundTripTest, + ::testing::ValuesIn(std::vector({ + CASE_II(InlinedVariable), + }))); + +INSTANTIATE_TEST_SUITE_P(OpenCLDebugInfo100DebugDebugDeclare, + ExtInstCLDebugInfo100RoundTripTest, + ::testing::ValuesIn(std::vector({ + CASE_III(Declare), + }))); + +INSTANTIATE_TEST_SUITE_P( + OpenCLDebugInfo100DebugDebugValue, ExtInstCLDebugInfo100RoundTripTest, + ::testing::ValuesIn(std::vector({ + CASE_IIII(Value), + CASE_IIIII(Value), + CASE_IIIIII(Value), + // Test up to 3 id parameters. We can always try more. + CASE_IIIIIII(Value), + }))); + +INSTANTIATE_TEST_SUITE_P(OpenCLDebugInfo100DebugDebugOperation, + ExtInstCLDebugInfo100RoundTripTest, + ::testing::ValuesIn(std::vector({ + CASE_E(Operation, Deref), + CASE_E(Operation, Plus), + CASE_E(Operation, Minus), + CASE_EL(Operation, PlusUconst, 1), + CASE_EL(Operation, PlusUconst, 42), + CASE_ELL(Operation, BitPiece, 1, 2), + CASE_ELL(Operation, BitPiece, 4, 5), + CASE_E(Operation, Swap), + CASE_E(Operation, Xderef), + CASE_E(Operation, StackValue), + CASE_EL(Operation, Constu, 1), + CASE_EL(Operation, Constu, 42), + CASE_ELL(Operation, Fragment, 100, 200), + CASE_ELL(Operation, Fragment, 8, 9), + }))); + +INSTANTIATE_TEST_SUITE_P(OpenCLDebugInfo100DebugDebugExpression, + ExtInstCLDebugInfo100RoundTripTest, + ::testing::ValuesIn(std::vector({ + CASE_0(Expression), + CASE_I(Expression), + CASE_II(Expression), + CASE_III(Expression), + CASE_IIII(Expression), + CASE_IIIII(Expression), + CASE_IIIIII(Expression), + CASE_IIIIIII(Expression), + }))); + +// OpenCL.DebugInfo.100 4.9 Macros + +INSTANTIATE_TEST_SUITE_P(OpenCLDebugInfo100DebugMacroDef, + ExtInstCLDebugInfo100RoundTripTest, + ::testing::ValuesIn(std::vector({ + CASE_ILI(MacroDef, 1), + CASE_ILI(MacroDef, 42), + CASE_ILII(MacroDef, 1), + CASE_ILII(MacroDef, 42), + }))); + +INSTANTIATE_TEST_SUITE_P(OpenCLDebugInfo100DebugMacroUndef, + ExtInstCLDebugInfo100RoundTripTest, + ::testing::ValuesIn(std::vector({ + CASE_ILI(MacroUndef, 1), + CASE_ILI(MacroUndef, 42), + }))); + +// OpenCL.DebugInfo.100 4.10 Imported Entities + +INSTANTIATE_TEST_SUITE_P( + OpenCLDebugInfo100DebugImportedEntity, ExtInstCLDebugInfo100RoundTripTest, + ::testing::ValuesIn(std::vector({ + // ID Name + // Literal Tag + // ID Source + // ID Entity + // Literal Number Line + // Literal Number Column + // ID Parent + CASE_IEIILLI(ImportedEntity, ImportedModule, 67, 68), + CASE_IEIILLI(ImportedEntity, ImportedDeclaration, 42, 43), + }))); + +#undef EPREFIX +#undef CASE_0 +#undef CASE_ILL +#undef CASE_IL +#undef CASE_I +#undef CASE_II +#undef CASE_III +#undef CASE_IIII +#undef CASE_IIIII +#undef CASE_IIIIII +#undef CASE_IIIIIII +#undef CASE_IIILLI +#undef CASE_IIILLIL +#undef CASE_IE +#undef CASE_IEIILLI +#undef CASE_IIE +#undef CASE_ISF +#undef CASE_LII +#undef CASE_LLIe +#undef CASE_ILI +#undef CASE_ILII +#undef CASE_ILLII +#undef CASE_IIILLIF +#undef CASE_IIILLIFL +#undef CASE_IIILLIIF +#undef CASE_IIILLIIFII +#undef CASE_IIILLIIFIIII +#undef CASE_IIILLIIFIIIIII +#undef CASE_IEILLIIIF +#undef CASE_IEILLIIIFI +#undef CASE_IEILLIIIFII +#undef CASE_IEILLIIIFIII +#undef CASE_IEILLIIIFIIII +#undef CASE_IIILLIIIF +#undef CASE_IIILLIIIFI +#undef CASE_IIIIF +#undef CASE_IIILL +#undef CASE_IIIILL +#undef CASE_IILLI +#undef CASE_IILLII +#undef CASE_IILLIII +#undef CASE_IILLIIII +#undef CASE_IIILLIIFLI +#undef CASE_IIILLIIFLII +#undef CASE_E +#undef CASE_EI +#undef CASE_EII +#undef CASE_EIII +#undef CASE_EIIII +#undef CASE_EIIIII +#undef CASE_EL +#undef CASE_ELL + +} // namespace +} // namespace spvtools diff --git a/third_party/spirv-tools/test/ext_inst.debuginfo_test.cpp b/third_party/spirv-tools/test/ext_inst.debuginfo_test.cpp index 15fa8f7656..9090c24739 100644 --- a/third_party/spirv-tools/test/ext_inst.debuginfo_test.cpp +++ b/third_party/spirv-tools/test/ext_inst.debuginfo_test.cpp @@ -17,6 +17,7 @@ #include "DebugInfo.h" #include "gmock/gmock.h" +#include "source/util/string_utils.h" #include "test/test_fixture.h" #include "test/unit_spirv.h" @@ -31,7 +32,7 @@ namespace { using spvtest::Concatenate; using spvtest::MakeInstruction; -using spvtest::MakeVector; +using utils::MakeVector; using testing::Eq; struct InstructionCase { @@ -368,30 +369,30 @@ TEST_P(ExtInstDebugInfoRoundTripTest, ParameterizedExtInst) { } // DebugInfo 4.1 Absent Debugging Information -INSTANTIATE_TEST_CASE_P(DebugInfoDebugInfoNone, ExtInstDebugInfoRoundTripTest, - ::testing::ValuesIn(std::vector({ - CASE_0(InfoNone), // enum value 0 - })), ); +INSTANTIATE_TEST_SUITE_P(DebugInfoDebugInfoNone, ExtInstDebugInfoRoundTripTest, + ::testing::ValuesIn(std::vector({ + CASE_0(InfoNone), // enum value 0 + }))); // DebugInfo 4.2 Compilation Unit -INSTANTIATE_TEST_CASE_P(DebugInfoDebugCompilationUnit, - ExtInstDebugInfoRoundTripTest, - ::testing::ValuesIn(std::vector({ - CASE_ILL(CompilationUnit, 100, 42), - })), ); +INSTANTIATE_TEST_SUITE_P(DebugInfoDebugCompilationUnit, + ExtInstDebugInfoRoundTripTest, + ::testing::ValuesIn(std::vector({ + CASE_ILL(CompilationUnit, 100, 42), + }))); // DebugInfo 4.3 Type instructions -INSTANTIATE_TEST_CASE_P(DebugInfoDebugTypeBasic, ExtInstDebugInfoRoundTripTest, - ::testing::ValuesIn(std::vector({ - CASE_IIE(TypeBasic, Unspecified), - CASE_IIE(TypeBasic, Address), - CASE_IIE(TypeBasic, Boolean), - CASE_IIE(TypeBasic, Float), - CASE_IIE(TypeBasic, Signed), - CASE_IIE(TypeBasic, SignedChar), - CASE_IIE(TypeBasic, Unsigned), - CASE_IIE(TypeBasic, UnsignedChar), - })), ); +INSTANTIATE_TEST_SUITE_P(DebugInfoDebugTypeBasic, ExtInstDebugInfoRoundTripTest, + ::testing::ValuesIn(std::vector({ + CASE_IIE(TypeBasic, Unspecified), + CASE_IIE(TypeBasic, Address), + CASE_IIE(TypeBasic, Boolean), + CASE_IIE(TypeBasic, Float), + CASE_IIE(TypeBasic, Signed), + CASE_IIE(TypeBasic, SignedChar), + CASE_IIE(TypeBasic, Unsigned), + CASE_IIE(TypeBasic, UnsignedChar), + }))); // The FlagIsPublic is value is (1 << 0) | (1 << 2) which is the same // as the bitwise-OR of FlagIsProtected and FlagIsPrivate. @@ -417,7 +418,7 @@ TEST_F(ExtInstDebugInfoRoundTripTestExplicit, FlagIsPublic) { EXPECT_THAT(EncodeAndDecodeSuccessfully(input), Eq(expected)) << input; } -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( DebugInfoDebugTypePointer, ExtInstDebugInfoRoundTripTest, ::testing::ValuesIn(std::vector({ @@ -463,49 +464,50 @@ INSTANTIATE_TEST_CASE_P( uint32_t(DebugInfoFlagIndirectVariable) | uint32_t(DebugInfoFlagIsOptimized)), - })), ); + }))); -INSTANTIATE_TEST_CASE_P(DebugInfoDebugTypeQualifier, - ExtInstDebugInfoRoundTripTest, - ::testing::ValuesIn(std::vector({ - CASE_IE(TypeQualifier, ConstType), - CASE_IE(TypeQualifier, VolatileType), - CASE_IE(TypeQualifier, RestrictType), - })), ); +INSTANTIATE_TEST_SUITE_P(DebugInfoDebugTypeQualifier, + ExtInstDebugInfoRoundTripTest, + ::testing::ValuesIn(std::vector({ + CASE_IE(TypeQualifier, ConstType), + CASE_IE(TypeQualifier, VolatileType), + CASE_IE(TypeQualifier, RestrictType), + }))); -INSTANTIATE_TEST_CASE_P(DebugInfoDebugTypeArray, ExtInstDebugInfoRoundTripTest, - ::testing::ValuesIn(std::vector({ - CASE_II(TypeArray), - CASE_III(TypeArray), - CASE_IIII(TypeArray), - CASE_IIIII(TypeArray), - })), ); +INSTANTIATE_TEST_SUITE_P(DebugInfoDebugTypeArray, ExtInstDebugInfoRoundTripTest, + ::testing::ValuesIn(std::vector({ + CASE_II(TypeArray), + CASE_III(TypeArray), + CASE_IIII(TypeArray), + CASE_IIIII(TypeArray), + }))); -INSTANTIATE_TEST_CASE_P(DebugInfoDebugTypeVector, ExtInstDebugInfoRoundTripTest, - ::testing::ValuesIn(std::vector({ - CASE_IL(TypeVector, 2), - CASE_IL(TypeVector, 3), - CASE_IL(TypeVector, 4), - CASE_IL(TypeVector, 16), - })), ); +INSTANTIATE_TEST_SUITE_P(DebugInfoDebugTypeVector, + ExtInstDebugInfoRoundTripTest, + ::testing::ValuesIn(std::vector({ + CASE_IL(TypeVector, 2), + CASE_IL(TypeVector, 3), + CASE_IL(TypeVector, 4), + CASE_IL(TypeVector, 16), + }))); -INSTANTIATE_TEST_CASE_P(DebugInfoDebugTypedef, ExtInstDebugInfoRoundTripTest, - ::testing::ValuesIn(std::vector({ - CASE_IIILLI(Typedef, 12, 13), - CASE_IIILLI(Typedef, 14, 99), - })), ); +INSTANTIATE_TEST_SUITE_P(DebugInfoDebugTypedef, ExtInstDebugInfoRoundTripTest, + ::testing::ValuesIn(std::vector({ + CASE_IIILLI(Typedef, 12, 13), + CASE_IIILLI(Typedef, 14, 99), + }))); -INSTANTIATE_TEST_CASE_P(DebugInfoDebugTypeFunction, - ExtInstDebugInfoRoundTripTest, - ::testing::ValuesIn(std::vector({ - CASE_I(TypeFunction), - CASE_II(TypeFunction), - CASE_III(TypeFunction), - CASE_IIII(TypeFunction), - CASE_IIIII(TypeFunction), - })), ); +INSTANTIATE_TEST_SUITE_P(DebugInfoDebugTypeFunction, + ExtInstDebugInfoRoundTripTest, + ::testing::ValuesIn(std::vector({ + CASE_I(TypeFunction), + CASE_II(TypeFunction), + CASE_III(TypeFunction), + CASE_IIII(TypeFunction), + CASE_IIIII(TypeFunction), + }))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( DebugInfoDebugTypeEnum, ExtInstDebugInfoRoundTripTest, ::testing::ValuesIn(std::vector({ CASE_IIILLIIFII( @@ -518,9 +520,9 @@ INSTANTIATE_TEST_CASE_P( uint32_t(DebugInfoFlagStaticMember)), CASE_IIILLIIFIIIIII(TypeEnum, 99, 1, "FlagStaticMember", uint32_t(DebugInfoFlagStaticMember)), - })), ); + }))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( DebugInfoDebugTypeComposite, ExtInstDebugInfoRoundTripTest, ::testing::ValuesIn(std::vector({ CASE_IEILLIIF( @@ -545,22 +547,22 @@ INSTANTIATE_TEST_CASE_P( uint32_t(DebugInfoFlagIsPrivate)), CASE_IEILLIIFIIII(TypeComposite, Class, 9, 10, "FlagIsPrivate", uint32_t(DebugInfoFlagIsPrivate)), - })), ); + }))); -INSTANTIATE_TEST_CASE_P(DebugInfoDebugTypeMember, ExtInstDebugInfoRoundTripTest, - ::testing::ValuesIn(std::vector({ - CASE_IIILLIIIF(TypeMember, 12, 13, "FlagIsPrivate", - uint32_t(DebugInfoFlagIsPrivate)), - CASE_IIILLIIIF(TypeMember, 99, 100, - "FlagIsPrivate|FlagFwdDecl", - uint32_t(DebugInfoFlagIsPrivate) | - uint32_t(DebugInfoFlagFwdDecl)), - // Add the optional Id argument. - CASE_IIILLIIIFI(TypeMember, 12, 13, "FlagIsPrivate", - uint32_t(DebugInfoFlagIsPrivate)), - })), ); +INSTANTIATE_TEST_SUITE_P( + DebugInfoDebugTypeMember, ExtInstDebugInfoRoundTripTest, + ::testing::ValuesIn(std::vector({ + CASE_IIILLIIIF(TypeMember, 12, 13, "FlagIsPrivate", + uint32_t(DebugInfoFlagIsPrivate)), + CASE_IIILLIIIF(TypeMember, 99, 100, "FlagIsPrivate|FlagFwdDecl", + uint32_t(DebugInfoFlagIsPrivate) | + uint32_t(DebugInfoFlagFwdDecl)), + // Add the optional Id argument. + CASE_IIILLIIIFI(TypeMember, 12, 13, "FlagIsPrivate", + uint32_t(DebugInfoFlagIsPrivate)), + }))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( DebugInfoDebugTypeInheritance, ExtInstDebugInfoRoundTripTest, ::testing::ValuesIn(std::vector({ CASE_IIIIF(TypeInheritance, "FlagIsPrivate", @@ -568,53 +570,53 @@ INSTANTIATE_TEST_CASE_P( CASE_IIIIF(TypeInheritance, "FlagIsPrivate|FlagFwdDecl", uint32_t(DebugInfoFlagIsPrivate) | uint32_t(DebugInfoFlagFwdDecl)), - })), ); + }))); -INSTANTIATE_TEST_CASE_P(DebugInfoDebugTypePtrToMember, - ExtInstDebugInfoRoundTripTest, - ::testing::ValuesIn(std::vector({ - CASE_II(TypePtrToMember), - })), ); +INSTANTIATE_TEST_SUITE_P(DebugInfoDebugTypePtrToMember, + ExtInstDebugInfoRoundTripTest, + ::testing::ValuesIn(std::vector({ + CASE_II(TypePtrToMember), + }))); // DebugInfo 4.4 Templates -INSTANTIATE_TEST_CASE_P(DebugInfoDebugTypeTemplate, - ExtInstDebugInfoRoundTripTest, - ::testing::ValuesIn(std::vector({ - CASE_II(TypeTemplate), - CASE_III(TypeTemplate), - CASE_IIII(TypeTemplate), - CASE_IIIII(TypeTemplate), - })), ); +INSTANTIATE_TEST_SUITE_P(DebugInfoDebugTypeTemplate, + ExtInstDebugInfoRoundTripTest, + ::testing::ValuesIn(std::vector({ + CASE_II(TypeTemplate), + CASE_III(TypeTemplate), + CASE_IIII(TypeTemplate), + CASE_IIIII(TypeTemplate), + }))); -INSTANTIATE_TEST_CASE_P(DebugInfoDebugTypeTemplateParameter, - ExtInstDebugInfoRoundTripTest, - ::testing::ValuesIn(std::vector({ - CASE_IIIILL(TypeTemplateParameter, 1, 2), - CASE_IIIILL(TypeTemplateParameter, 99, 102), - CASE_IIIILL(TypeTemplateParameter, 10, 7), - })), ); +INSTANTIATE_TEST_SUITE_P(DebugInfoDebugTypeTemplateParameter, + ExtInstDebugInfoRoundTripTest, + ::testing::ValuesIn(std::vector({ + CASE_IIIILL(TypeTemplateParameter, 1, 2), + CASE_IIIILL(TypeTemplateParameter, 99, 102), + CASE_IIIILL(TypeTemplateParameter, 10, 7), + }))); -INSTANTIATE_TEST_CASE_P(DebugInfoDebugTypeTemplateTemplateParameter, - ExtInstDebugInfoRoundTripTest, - ::testing::ValuesIn(std::vector({ - CASE_IIILL(TypeTemplateTemplateParameter, 1, 2), - CASE_IIILL(TypeTemplateTemplateParameter, 99, 102), - CASE_IIILL(TypeTemplateTemplateParameter, 10, 7), - })), ); +INSTANTIATE_TEST_SUITE_P(DebugInfoDebugTypeTemplateTemplateParameter, + ExtInstDebugInfoRoundTripTest, + ::testing::ValuesIn(std::vector({ + CASE_IIILL(TypeTemplateTemplateParameter, 1, 2), + CASE_IIILL(TypeTemplateTemplateParameter, 99, 102), + CASE_IIILL(TypeTemplateTemplateParameter, 10, 7), + }))); -INSTANTIATE_TEST_CASE_P(DebugInfoDebugTypeTemplateParameterPack, - ExtInstDebugInfoRoundTripTest, - ::testing::ValuesIn(std::vector({ - CASE_IILLI(TypeTemplateParameterPack, 1, 2), - CASE_IILLII(TypeTemplateParameterPack, 99, 102), - CASE_IILLIII(TypeTemplateParameterPack, 10, 7), - CASE_IILLIIII(TypeTemplateParameterPack, 10, 7), - })), ); +INSTANTIATE_TEST_SUITE_P(DebugInfoDebugTypeTemplateParameterPack, + ExtInstDebugInfoRoundTripTest, + ::testing::ValuesIn(std::vector({ + CASE_IILLI(TypeTemplateParameterPack, 1, 2), + CASE_IILLII(TypeTemplateParameterPack, 99, 102), + CASE_IILLIII(TypeTemplateParameterPack, 10, 7), + CASE_IILLIIII(TypeTemplateParameterPack, 10, 7), + }))); // DebugInfo 4.5 Global Variables -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( DebugInfoDebugGlobalVariable, ExtInstDebugInfoRoundTripTest, ::testing::ValuesIn(std::vector({ CASE_IIILLIIIF(GlobalVariable, 1, 2, "FlagIsOptimized", @@ -625,20 +627,20 @@ INSTANTIATE_TEST_CASE_P( uint32_t(DebugInfoFlagIsOptimized)), CASE_IIILLIIIFI(GlobalVariable, 42, 43, "FlagIsOptimized", uint32_t(DebugInfoFlagIsOptimized)), - })), ); + }))); // DebugInfo 4.6 Functions -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( DebugInfoDebugFunctionDeclaration, ExtInstDebugInfoRoundTripTest, ::testing::ValuesIn(std::vector({ CASE_IIILLIIF(FunctionDeclaration, 1, 2, "FlagIsOptimized", uint32_t(DebugInfoFlagIsOptimized)), CASE_IIILLIIF(FunctionDeclaration, 42, 43, "FlagFwdDecl", uint32_t(DebugInfoFlagFwdDecl)), - })), ); + }))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( DebugInfoDebugFunction, ExtInstDebugInfoRoundTripTest, ::testing::ValuesIn(std::vector({ CASE_IIILLIIFLI(Function, 1, 2, "FlagIsOptimized", @@ -650,65 +652,65 @@ INSTANTIATE_TEST_CASE_P( uint32_t(DebugInfoFlagIsOptimized), 3), CASE_IIILLIIFLII(Function, 42, 43, "FlagFwdDecl", uint32_t(DebugInfoFlagFwdDecl), 44), - })), ); + }))); // DebugInfo 4.7 Local Information -INSTANTIATE_TEST_CASE_P(DebugInfoDebugLexicalBlock, - ExtInstDebugInfoRoundTripTest, - ::testing::ValuesIn(std::vector({ - CASE_ILLII(LexicalBlock, 1, 2), - CASE_ILLII(LexicalBlock, 42, 43), - })), ); +INSTANTIATE_TEST_SUITE_P(DebugInfoDebugLexicalBlock, + ExtInstDebugInfoRoundTripTest, + ::testing::ValuesIn(std::vector({ + CASE_ILLII(LexicalBlock, 1, 2), + CASE_ILLII(LexicalBlock, 42, 43), + }))); -INSTANTIATE_TEST_CASE_P(DebugInfoDebugLexicalBlockDiscriminator, - ExtInstDebugInfoRoundTripTest, - ::testing::ValuesIn(std::vector({ - CASE_ILI(LexicalBlockDiscriminator, 1), - CASE_ILI(LexicalBlockDiscriminator, 42), - })), ); +INSTANTIATE_TEST_SUITE_P(DebugInfoDebugLexicalBlockDiscriminator, + ExtInstDebugInfoRoundTripTest, + ::testing::ValuesIn(std::vector({ + CASE_ILI(LexicalBlockDiscriminator, 1), + CASE_ILI(LexicalBlockDiscriminator, 42), + }))); -INSTANTIATE_TEST_CASE_P(DebugInfoDebugScope, ExtInstDebugInfoRoundTripTest, - ::testing::ValuesIn(std::vector({ - CASE_I(Scope), - CASE_II(Scope), - })), ); +INSTANTIATE_TEST_SUITE_P(DebugInfoDebugScope, ExtInstDebugInfoRoundTripTest, + ::testing::ValuesIn(std::vector({ + CASE_I(Scope), + CASE_II(Scope), + }))); -INSTANTIATE_TEST_CASE_P(DebugInfoDebugNoScope, ExtInstDebugInfoRoundTripTest, - ::testing::ValuesIn(std::vector({ - CASE_0(NoScope), - })), ); +INSTANTIATE_TEST_SUITE_P(DebugInfoDebugNoScope, ExtInstDebugInfoRoundTripTest, + ::testing::ValuesIn(std::vector({ + CASE_0(NoScope), + }))); -INSTANTIATE_TEST_CASE_P(DebugInfoDebugInlinedAt, ExtInstDebugInfoRoundTripTest, - ::testing::ValuesIn(std::vector({ - CASE_LII(InlinedAt, 1), - CASE_LII(InlinedAt, 42), - })), ); +INSTANTIATE_TEST_SUITE_P(DebugInfoDebugInlinedAt, ExtInstDebugInfoRoundTripTest, + ::testing::ValuesIn(std::vector({ + CASE_LII(InlinedAt, 1), + CASE_LII(InlinedAt, 42), + }))); // DebugInfo 4.8 Local Variables -INSTANTIATE_TEST_CASE_P(DebugInfoDebugLocalVariable, - ExtInstDebugInfoRoundTripTest, - ::testing::ValuesIn(std::vector({ - CASE_IIILLI(LocalVariable, 1, 2), - CASE_IIILLI(LocalVariable, 42, 43), - CASE_IIILLIL(LocalVariable, 1, 2, 3), - CASE_IIILLIL(LocalVariable, 42, 43, 44), - })), ); +INSTANTIATE_TEST_SUITE_P(DebugInfoDebugLocalVariable, + ExtInstDebugInfoRoundTripTest, + ::testing::ValuesIn(std::vector({ + CASE_IIILLI(LocalVariable, 1, 2), + CASE_IIILLI(LocalVariable, 42, 43), + CASE_IIILLIL(LocalVariable, 1, 2, 3), + CASE_IIILLIL(LocalVariable, 42, 43, 44), + }))); -INSTANTIATE_TEST_CASE_P(DebugInfoDebugInlinedVariable, - ExtInstDebugInfoRoundTripTest, - ::testing::ValuesIn(std::vector({ - CASE_II(InlinedVariable), - })), ); +INSTANTIATE_TEST_SUITE_P(DebugInfoDebugInlinedVariable, + ExtInstDebugInfoRoundTripTest, + ::testing::ValuesIn(std::vector({ + CASE_II(InlinedVariable), + }))); -INSTANTIATE_TEST_CASE_P(DebugInfoDebugDebugDeclare, - ExtInstDebugInfoRoundTripTest, - ::testing::ValuesIn(std::vector({ - CASE_III(Declare), - })), ); +INSTANTIATE_TEST_SUITE_P(DebugInfoDebugDebugDeclare, + ExtInstDebugInfoRoundTripTest, + ::testing::ValuesIn(std::vector({ + CASE_III(Declare), + }))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( DebugInfoDebugDebugValue, ExtInstDebugInfoRoundTripTest, ::testing::ValuesIn(std::vector({ CASE_III(Value), @@ -717,53 +719,54 @@ INSTANTIATE_TEST_CASE_P( CASE_IIIIII(Value), // Test up to 4 id parameters. We can always try more. CASE_IIIIIII(Value), - })), ); + }))); -INSTANTIATE_TEST_CASE_P(DebugInfoDebugDebugOperation, - ExtInstDebugInfoRoundTripTest, - ::testing::ValuesIn(std::vector({ - CASE_E(Operation, Deref), - CASE_E(Operation, Plus), - CASE_E(Operation, Minus), - CASE_EL(Operation, PlusUconst, 1), - CASE_EL(Operation, PlusUconst, 42), - CASE_ELL(Operation, BitPiece, 1, 2), - CASE_ELL(Operation, BitPiece, 4, 5), - CASE_E(Operation, Swap), - CASE_E(Operation, Xderef), - CASE_E(Operation, StackValue), - CASE_EL(Operation, Constu, 1), - CASE_EL(Operation, Constu, 42), - })), ); +INSTANTIATE_TEST_SUITE_P(DebugInfoDebugDebugOperation, + ExtInstDebugInfoRoundTripTest, + ::testing::ValuesIn(std::vector({ + CASE_E(Operation, Deref), + CASE_E(Operation, Plus), + CASE_E(Operation, Minus), + CASE_EL(Operation, PlusUconst, 1), + CASE_EL(Operation, PlusUconst, 42), + CASE_ELL(Operation, BitPiece, 1, 2), + CASE_ELL(Operation, BitPiece, 4, 5), + CASE_E(Operation, Swap), + CASE_E(Operation, Xderef), + CASE_E(Operation, StackValue), + CASE_EL(Operation, Constu, 1), + CASE_EL(Operation, Constu, 42), + }))); -INSTANTIATE_TEST_CASE_P(DebugInfoDebugDebugExpression, - ExtInstDebugInfoRoundTripTest, - ::testing::ValuesIn(std::vector({ - CASE_0(Expression), - CASE_I(Expression), - CASE_II(Expression), - CASE_III(Expression), - CASE_IIII(Expression), - CASE_IIIII(Expression), - CASE_IIIIII(Expression), - CASE_IIIIIII(Expression), - })), ); +INSTANTIATE_TEST_SUITE_P(DebugInfoDebugDebugExpression, + ExtInstDebugInfoRoundTripTest, + ::testing::ValuesIn(std::vector({ + CASE_0(Expression), + CASE_I(Expression), + CASE_II(Expression), + CASE_III(Expression), + CASE_IIII(Expression), + CASE_IIIII(Expression), + CASE_IIIIII(Expression), + CASE_IIIIIII(Expression), + }))); // DebugInfo 4.9 Macros -INSTANTIATE_TEST_CASE_P(DebugInfoDebugMacroDef, ExtInstDebugInfoRoundTripTest, - ::testing::ValuesIn(std::vector({ - CASE_ILI(MacroDef, 1), - CASE_ILI(MacroDef, 42), - CASE_ILII(MacroDef, 1), - CASE_ILII(MacroDef, 42), - })), ); +INSTANTIATE_TEST_SUITE_P(DebugInfoDebugMacroDef, ExtInstDebugInfoRoundTripTest, + ::testing::ValuesIn(std::vector({ + CASE_ILI(MacroDef, 1), + CASE_ILI(MacroDef, 42), + CASE_ILII(MacroDef, 1), + CASE_ILII(MacroDef, 42), + }))); -INSTANTIATE_TEST_CASE_P(DebugInfoDebugMacroUndef, ExtInstDebugInfoRoundTripTest, - ::testing::ValuesIn(std::vector({ - CASE_ILI(MacroUndef, 1), - CASE_ILI(MacroUndef, 42), - })), ); +INSTANTIATE_TEST_SUITE_P(DebugInfoDebugMacroUndef, + ExtInstDebugInfoRoundTripTest, + ::testing::ValuesIn(std::vector({ + CASE_ILI(MacroUndef, 1), + CASE_ILI(MacroUndef, 42), + }))); #undef CASE_0 #undef CASE_ILL diff --git a/third_party/spirv-tools/test/ext_inst.glsl_test.cpp b/third_party/spirv-tools/test/ext_inst.glsl_test.cpp index 991c487f1a..41d222f47e 100644 --- a/third_party/spirv-tools/test/ext_inst.glsl_test.cpp +++ b/third_party/spirv-tools/test/ext_inst.glsl_test.cpp @@ -61,7 +61,7 @@ OpFunctionEnd ; Generator: Khronos SPIR-V Tools Assembler; 0 ; Bound: 9 ; Schema: 0)"; - spv_binary binary; + spv_binary binary = nullptr; spv_diagnostic diagnostic; spv_result_t error = spvTextToBinary(context, spirv.c_str(), spirv.size(), &binary, &diagnostic); @@ -102,10 +102,11 @@ OpFunctionEnd } EXPECT_EQ(spirv_header + spirv, output_text->str); spvTextDestroy(output_text); + spvBinaryDestroy(binary); spvContextDestroy(context); } -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( ExtInstParameters, ExtInstGLSLstd450RoundTripTest, ::testing::ValuesIn(std::vector({ // We are only testing the correctness of encoding and decoding here. @@ -197,7 +198,7 @@ INSTANTIATE_TEST_CASE_P( {"NMin", "%5 %5", 79, 7, {5, 5}}, {"NMax", "%5 %5", 80, 7, {5, 5}}, {"NClamp", "%5 %5 %5", 81, 8, {5, 5, 5}}, - })), ); + }))); } // namespace } // namespace spvtools diff --git a/third_party/spirv-tools/test/ext_inst.non_semantic_test.cpp b/third_party/spirv-tools/test/ext_inst.non_semantic_test.cpp new file mode 100644 index 0000000000..870684e9bf --- /dev/null +++ b/third_party/spirv-tools/test/ext_inst.non_semantic_test.cpp @@ -0,0 +1,90 @@ +// Copyright (c) 2015-2016 The Khronos Group Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Assembler tests for non-semantic extended instructions + +#include +#include + +#include "gmock/gmock.h" +#include "test/test_fixture.h" +#include "test/unit_spirv.h" + +using ::testing::Eq; + +namespace spvtools { +namespace { + +using NonSemanticRoundTripTest = RoundTripTest; +using NonSemanticTextToBinaryTest = spvtest::TextToBinaryTest; + +TEST_F(NonSemanticRoundTripTest, NonSemanticInsts) { + std::string spirv = R"(OpExtension "SPV_KHR_non_semantic_info" +%1 = OpExtInstImport "NonSemantic.Testing.ExtInst" +%2 = OpTypeVoid +%3 = OpExtInst %2 %1 132384681 %2 +%4 = OpTypeInt 32 0 +%5 = OpConstant %4 123 +%6 = OpString "Test string" +%7 = OpExtInst %4 %1 82198732 %5 %6 +%8 = OpExtInstImport "NonSemantic.Testing.AnotherUnknownExtInstSet" +%9 = OpExtInst %4 %8 613874321 %7 %5 %6 +)"; + std::string disassembly = EncodeAndDecodeSuccessfully( + spirv, SPV_BINARY_TO_TEXT_OPTION_NONE, SPV_ENV_UNIVERSAL_1_0); + EXPECT_THAT(disassembly, Eq(spirv)); +} + +TEST_F(NonSemanticTextToBinaryTest, InvalidExtInstSetName) { + std::string spirv = R"(OpExtension "SPV_KHR_non_semantic_info" +%1 = OpExtInstImport "NonSemantic_Testing_ExtInst" +)"; + + EXPECT_THAT( + CompileFailure(spirv), + Eq("Invalid extended instruction import 'NonSemantic_Testing_ExtInst'")); +} + +TEST_F(NonSemanticTextToBinaryTest, NonSemanticIntParameter) { + std::string spirv = R"(OpExtension "SPV_KHR_non_semantic_info" +%1 = OpExtInstImport "NonSemantic.Testing.ExtInst" +%2 = OpTypeVoid +%3 = OpExtInst %2 %1 1 99999 +)"; + + EXPECT_THAT(CompileFailure(spirv), Eq("Expected id to start with %.")); +} + +TEST_F(NonSemanticTextToBinaryTest, NonSemanticFloatParameter) { + std::string spirv = R"(OpExtension "SPV_KHR_non_semantic_info" +%1 = OpExtInstImport "NonSemantic.Testing.ExtInst" +%2 = OpTypeVoid +%3 = OpExtInst %2 %1 1 3.141592 +)"; + + EXPECT_THAT(CompileFailure(spirv), Eq("Expected id to start with %.")); +} + +TEST_F(NonSemanticTextToBinaryTest, NonSemanticStringParameter) { + std::string spirv = R"(OpExtension "SPV_KHR_non_semantic_info" +%1 = OpExtInstImport "NonSemantic.Testing.ExtInst" +%2 = OpTypeVoid +%3 = OpExtInst %2 %1 1 "foobar" +)"; + + EXPECT_THAT(CompileFailure(spirv), Eq("Expected id to start with %.")); +} + +} // namespace +} // namespace spvtools diff --git a/third_party/spirv-tools/test/ext_inst.opencl_test.cpp b/third_party/spirv-tools/test/ext_inst.opencl_test.cpp index 06bc5e848a..7547d92240 100644 --- a/third_party/spirv-tools/test/ext_inst.opencl_test.cpp +++ b/third_party/spirv-tools/test/ext_inst.opencl_test.cpp @@ -17,6 +17,7 @@ #include "gmock/gmock.h" #include "source/latest_version_opencl_std_header.h" +#include "source/util/string_utils.h" #include "test/test_fixture.h" #include "test/unit_spirv.h" @@ -25,7 +26,7 @@ namespace { using spvtest::Concatenate; using spvtest::MakeInstruction; -using spvtest::MakeVector; +using utils::MakeVector; using spvtest::TextToBinaryTest; using testing::Eq; @@ -90,7 +91,7 @@ TEST_P(ExtInstOpenCLStdRoundTripTest, ParameterizedExtInst) { // clang-format off // OpenCL.std: 2.1 Math extended instructions -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( OpenCLMath, ExtInstOpenCLStdRoundTripTest, ::testing::ValuesIn(std::vector({ // We are only testing the correctness of encoding and decoding here. @@ -190,10 +191,10 @@ INSTANTIATE_TEST_CASE_P( CASE1(Native_sin, native_sin), CASE1(Native_sqrt, native_sqrt), CASE1(Native_tan, native_tan), // enum value 94 - })),); + }))); // OpenCL.std: 2.1 Integer instructions -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( OpenCLInteger, ExtInstOpenCLStdRoundTripTest, ::testing::ValuesIn(std::vector({ CASE1(SAbs, s_abs), // enum value 141 @@ -230,10 +231,10 @@ INSTANTIATE_TEST_CASE_P( CASE2(UAbs_diff, u_abs_diff), CASE2(UMul_hi, u_mul_hi), CASE3(UMad_hi, u_mad_hi), // enum value 204 - })),); + }))); // OpenCL.std: 2.3 Common instrucitons -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( OpenCLCommon, ExtInstOpenCLStdRoundTripTest, ::testing::ValuesIn(std::vector({ CASE3(FClamp, fclamp), // enum value 95 @@ -245,10 +246,10 @@ INSTANTIATE_TEST_CASE_P( CASE2(Step, step), CASE3(Smoothstep, smoothstep), CASE1(Sign, sign), // enum value 103 - })),); + }))); // OpenCL.std: 2.4 Geometric instructions -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( OpenCLGeometric, ExtInstOpenCLStdRoundTripTest, ::testing::ValuesIn(std::vector({ CASE2(Cross, cross), // enum value 104 @@ -258,18 +259,18 @@ INSTANTIATE_TEST_CASE_P( CASE2(Fast_distance, fast_distance), CASE1(Fast_length, fast_length), CASE1(Fast_normalize, fast_normalize), // enum value 110 - })),); + }))); // OpenCL.std: 2.5 Relational instructions -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( OpenCLRelational, ExtInstOpenCLStdRoundTripTest, ::testing::ValuesIn(std::vector({ CASE3(Bitselect, bitselect), // enum value 186 CASE3(Select, select), // enum value 187 - })),); + }))); // OpenCL.std: 2.6 Vector data load and store instructions -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( OpenCLVectorLoadStore, ExtInstOpenCLStdRoundTripTest, ::testing::ValuesIn(std::vector({ // The last argument to Vloadn must be one of 2, 3, 4, 8, 16. @@ -306,20 +307,20 @@ INSTANTIATE_TEST_CASE_P( CASE3Round(Vstorea_halfn_r, vstorea_halfn_r, RTZ), CASE3Round(Vstorea_halfn_r, vstorea_halfn_r, RTP), CASE3Round(Vstorea_halfn_r, vstorea_halfn_r, RTN), - })),); + }))); // OpenCL.std: 2.7 Miscellaneous vector instructions -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( OpenCLMiscellaneousVector, ExtInstOpenCLStdRoundTripTest, ::testing::ValuesIn(std::vector({ CASE2(Shuffle, shuffle), CASE3(Shuffle2, shuffle2), - })),); + }))); // OpenCL.std: 2.8 Miscellaneous instructions #define PREFIX uint32_t(OpenCLLIB::Entrypoints::Printf), "printf" -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( OpenCLMiscPrintf, ExtInstOpenCLStdRoundTripTest, ::testing::ValuesIn(std::vector({ // Printf is interesting because it takes a variable number of arguments. @@ -338,14 +339,14 @@ INSTANTIATE_TEST_CASE_P( {4, 5, 6, 7, 8, 9, 10, 11, 12, 13}}, {PREFIX, "%4 %5 %6 %7 %8 %9 %10 %11 %12 %13 %14", {4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}}, - })),); + }))); #undef PREFIX -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( OpenCLMiscPrefetch, ExtInstOpenCLStdRoundTripTest, ::testing::ValuesIn(std::vector({ CASE2(Prefetch, prefetch), - })),); + }))); // OpenCL.std: 2.9.1 Image encoding // No new instructions defined in this section. diff --git a/third_party/spirv-tools/test/fuzz/CMakeLists.txt b/third_party/spirv-tools/test/fuzz/CMakeLists.txt new file mode 100644 index 0000000000..732d9fed05 --- /dev/null +++ b/third_party/spirv-tools/test/fuzz/CMakeLists.txt @@ -0,0 +1,78 @@ +# Copyright (c) 2019 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. + +if (${SPIRV_BUILD_FUZZER}) + + set(SOURCES + fuzz_test_util.h + + data_synonym_transformation_test.cpp + equivalence_relation_test.cpp + fact_manager_test.cpp + fuzz_test_util.cpp + fuzzer_pass_add_useful_constructs_test.cpp + fuzzer_pass_donate_modules_test.cpp + instruction_descriptor_test.cpp + transformation_add_constant_boolean_test.cpp + transformation_add_constant_composite_test.cpp + transformation_add_constant_scalar_test.cpp + transformation_add_dead_block_test.cpp + transformation_add_dead_break_test.cpp + transformation_add_dead_continue_test.cpp + transformation_add_function_test.cpp + transformation_add_global_undef_test.cpp + transformation_add_global_variable_test.cpp + transformation_add_no_contraction_decoration_test.cpp + transformation_add_type_array_test.cpp + transformation_add_type_boolean_test.cpp + transformation_add_type_float_test.cpp + transformation_add_type_function_test.cpp + transformation_add_type_int_test.cpp + transformation_add_type_matrix_test.cpp + transformation_add_type_pointer_test.cpp + transformation_add_type_struct_test.cpp + transformation_add_type_vector_test.cpp + transformation_composite_construct_test.cpp + transformation_composite_extract_test.cpp + transformation_copy_object_test.cpp + transformation_merge_blocks_test.cpp + transformation_move_block_down_test.cpp + transformation_outline_function_test.cpp + transformation_replace_boolean_constant_with_constant_binary_test.cpp + transformation_replace_constant_with_uniform_test.cpp + transformation_replace_id_with_synonym_test.cpp + transformation_set_function_control_test.cpp + transformation_set_loop_control_test.cpp + transformation_set_memory_operands_mask_test.cpp + transformation_set_selection_control_test.cpp + transformation_split_block_test.cpp + transformation_vector_shuffle_test.cpp + uniform_buffer_element_descriptor_test.cpp) + + if (${SPIRV_ENABLE_LONG_FUZZER_TESTS}) + # These are long-running tests that depend on random seeds. We do not want + # to run them during regular whole-project CI because they may reveal + # spirv-fuzz bugs in changes that are totally unrelated to spirv-fuzz, + # which would be counfounding. Instead, they should be run regularly but + # separately. + set(SOURCES ${SOURCES} + fuzzer_replayer_test.cpp + fuzzer_shrinker_test.cpp) + endif() + + add_spvtools_unittest(TARGET fuzz + SRCS ${SOURCES} + LIBS SPIRV-Tools-fuzz + ) +endif() diff --git a/third_party/spirv-tools/test/fuzz/data_synonym_transformation_test.cpp b/third_party/spirv-tools/test/fuzz/data_synonym_transformation_test.cpp new file mode 100644 index 0000000000..21ea068ffc --- /dev/null +++ b/third_party/spirv-tools/test/fuzz/data_synonym_transformation_test.cpp @@ -0,0 +1,1122 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/data_descriptor.h" +#include "source/fuzz/id_use_descriptor.h" +#include "source/fuzz/instruction_descriptor.h" +#include "source/fuzz/transformation_composite_extract.h" +#include "source/fuzz/transformation_replace_id_with_synonym.h" +#include "source/fuzz/transformation_vector_shuffle.h" +#include "test/fuzz/fuzz_test_util.h" + +namespace spvtools { +namespace fuzz { +namespace { + +// This file captures tests that check correctness of the collective use of a +// number of transformations that relate to data synonyms. + +protobufs::Fact MakeSynonymFact(uint32_t first_id, + std::vector&& first_indices, + uint32_t second_id, + std::vector&& second_indices) { + protobufs::FactDataSynonym data_synonym_fact; + *data_synonym_fact.mutable_data1() = + MakeDataDescriptor(first_id, std::move(first_indices)); + *data_synonym_fact.mutable_data2() = + MakeDataDescriptor(second_id, std::move(second_indices)); + protobufs::Fact result; + *result.mutable_data_synonym_fact() = data_synonym_fact; + return result; +} + +TEST(DataSynonymTransformationTest, ArrayCompositeSynonyms) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %11 "A" + OpName %20 "B" + OpName %31 "g" + OpName %35 "h" + OpDecorate %11 RelaxedPrecision + OpDecorate %22 RelaxedPrecision + OpDecorate %27 RelaxedPrecision + OpDecorate %35 RelaxedPrecision + OpDecorate %36 RelaxedPrecision + OpDecorate %40 RelaxedPrecision + OpDecorate %41 RelaxedPrecision + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypeInt 32 0 + %8 = OpConstant %7 3 + %9 = OpTypeArray %6 %8 + %10 = OpTypePointer Function %9 + %12 = OpConstant %6 0 + %13 = OpConstant %6 3 + %14 = OpTypePointer Function %6 + %16 = OpTypeFloat 32 + %17 = OpConstant %7 4 + %18 = OpTypeArray %16 %17 + %19 = OpTypePointer Function %18 + %24 = OpTypePointer Function %16 + %28 = OpConstant %16 42 + %30 = OpConstant %6 2 + %34 = OpConstant %6 1 + %38 = OpConstant %6 42 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %11 = OpVariable %10 Function + %20 = OpVariable %19 Function + %31 = OpVariable %24 Function + %35 = OpVariable %14 Function + %15 = OpAccessChain %14 %11 %12 + %21 = OpAccessChain %14 %11 %12 + %22 = OpLoad %6 %21 + %100 = OpCompositeConstruct %9 %12 %13 %22 + OpStore %15 %13 + %23 = OpConvertSToF %16 %22 + %25 = OpAccessChain %24 %20 %12 + OpStore %25 %23 + %26 = OpAccessChain %14 %11 %12 + %27 = OpLoad %6 %26 + %29 = OpAccessChain %24 %20 %27 + OpStore %29 %28 + %32 = OpLoad %16 %31 + %101 = OpCompositeConstruct %18 %28 %23 %32 %23 + %50 = OpCopyObject %16 %23 + %51 = OpCopyObject %16 %23 + %33 = OpAccessChain %24 %20 %30 + OpStore %33 %28 + OpStore %33 %32 + %36 = OpLoad %6 %35 + %37 = OpAccessChain %14 %11 %34 + OpStore %37 %36 + %39 = OpAccessChain %14 %11 %12 + %40 = OpLoad %6 %39 + %41 = OpIAdd %6 %38 %40 + %42 = OpAccessChain %14 %11 %30 + OpStore %42 %41 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + fact_manager.AddFact(MakeSynonymFact(12, {}, 100, {0}), context.get()); + fact_manager.AddFact(MakeSynonymFact(13, {}, 100, {1}), context.get()); + fact_manager.AddFact(MakeSynonymFact(22, {}, 100, {2}), context.get()); + fact_manager.AddFact(MakeSynonymFact(28, {}, 101, {0}), context.get()); + fact_manager.AddFact(MakeSynonymFact(23, {}, 101, {1}), context.get()); + fact_manager.AddFact(MakeSynonymFact(32, {}, 101, {2}), context.get()); + fact_manager.AddFact(MakeSynonymFact(23, {}, 101, {3}), context.get()); + + // Replace %12 with %100[0] in '%25 = OpAccessChain %24 %20 %12' + auto instruction_descriptor_1 = + MakeInstructionDescriptor(25, SpvOpAccessChain, 0); + auto good_extract_1 = + TransformationCompositeExtract(instruction_descriptor_1, 102, 100, {0}); + // Bad: id already in use + auto bad_extract_1 = TransformationCompositeExtract( + MakeInstructionDescriptor(25, SpvOpAccessChain, 0), 25, 100, {0}); + ASSERT_TRUE(good_extract_1.IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(bad_extract_1.IsApplicable(context.get(), fact_manager)); + good_extract_1.Apply(context.get(), &fact_manager); + auto replacement_1 = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor(12, instruction_descriptor_1, 1), 102); + ASSERT_TRUE(replacement_1.IsApplicable(context.get(), fact_manager)); + replacement_1.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + // Replace %13 with %100[1] in 'OpStore %15 %13' + auto instruction_descriptor_2 = MakeInstructionDescriptor(100, SpvOpStore, 0); + auto good_extract_2 = + TransformationCompositeExtract(instruction_descriptor_2, 103, 100, {1}); + // No bad example provided here. + ASSERT_TRUE(good_extract_2.IsApplicable(context.get(), fact_manager)); + good_extract_2.Apply(context.get(), &fact_manager); + auto replacement_2 = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor(13, instruction_descriptor_2, 1), 103); + ASSERT_TRUE(replacement_2.IsApplicable(context.get(), fact_manager)); + replacement_2.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + // Replace %22 with %100[2] in '%23 = OpConvertSToF %16 %22' + auto instruction_descriptor_3 = + MakeInstructionDescriptor(23, SpvOpConvertSToF, 0); + auto good_extract_3 = + TransformationCompositeExtract(instruction_descriptor_3, 104, 100, {2}); + ASSERT_TRUE(good_extract_3.IsApplicable(context.get(), fact_manager)); + good_extract_3.Apply(context.get(), &fact_manager); + auto replacement_3 = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor(22, instruction_descriptor_3, 0), 104); + // Bad: wrong input operand index + auto bad_replacement_3 = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor(22, instruction_descriptor_3, 1), 104); + ASSERT_TRUE(replacement_3.IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(bad_replacement_3.IsApplicable(context.get(), fact_manager)); + replacement_3.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + // Replace %28 with %101[0] in 'OpStore %33 %28' + auto instruction_descriptor_4 = MakeInstructionDescriptor(33, SpvOpStore, 0); + auto good_extract_4 = + TransformationCompositeExtract(instruction_descriptor_4, 105, 101, {0}); + // Bad: instruction descriptor does not identify an appropriate instruction + auto bad_extract_4 = TransformationCompositeExtract( + MakeInstructionDescriptor(33, SpvOpCopyObject, 0), 105, 101, {0}); + ASSERT_TRUE(good_extract_4.IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(bad_extract_4.IsApplicable(context.get(), fact_manager)); + good_extract_4.Apply(context.get(), &fact_manager); + auto replacement_4 = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor(28, instruction_descriptor_4, 1), 105); + ASSERT_TRUE(replacement_4.IsApplicable(context.get(), fact_manager)); + replacement_4.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + // Replace %23 with %101[1] in '%50 = OpCopyObject %16 %23' + auto instruction_descriptor_5 = + MakeInstructionDescriptor(50, SpvOpCopyObject, 0); + auto good_extract_5 = + TransformationCompositeExtract(instruction_descriptor_5, 106, 101, {1}); + ASSERT_TRUE(good_extract_5.IsApplicable(context.get(), fact_manager)); + good_extract_5.Apply(context.get(), &fact_manager); + auto replacement_5 = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor(23, instruction_descriptor_5, 0), 106); + // Bad: wrong synonym fact being used + auto bad_replacement_5 = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor(23, instruction_descriptor_5, 0), 105); + ASSERT_TRUE(replacement_5.IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(bad_replacement_5.IsApplicable(context.get(), fact_manager)); + replacement_5.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + // Replace %32 with %101[2] in 'OpStore %33 %32' + auto instruction_descriptor_6 = MakeInstructionDescriptor(33, SpvOpStore, 1); + auto good_extract_6 = + TransformationCompositeExtract(instruction_descriptor_6, 107, 101, {2}); + // Bad: id 1001 does not exist + auto bad_extract_6 = + TransformationCompositeExtract(instruction_descriptor_6, 107, 1001, {2}); + ASSERT_TRUE(good_extract_6.IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(bad_extract_6.IsApplicable(context.get(), fact_manager)); + good_extract_6.Apply(context.get(), &fact_manager); + auto replacement_6 = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor(32, instruction_descriptor_6, 1), 107); + ASSERT_TRUE(replacement_6.IsApplicable(context.get(), fact_manager)); + replacement_6.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + // Replace %23 with %101[3] in '%51 = OpCopyObject %16 %23' + auto instruction_descriptor_7 = + MakeInstructionDescriptor(51, SpvOpCopyObject, 0); + auto good_extract_7 = + TransformationCompositeExtract(instruction_descriptor_7, 108, 101, {3}); + ASSERT_TRUE(good_extract_7.IsApplicable(context.get(), fact_manager)); + good_extract_7.Apply(context.get(), &fact_manager); + auto replacement_7 = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor(23, instruction_descriptor_7, 0), 108); + // Bad: use id 0 is invalid + auto bad_replacement_7 = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor(0, instruction_descriptor_7, 0), 108); + ASSERT_TRUE(replacement_7.IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(bad_replacement_7.IsApplicable(context.get(), fact_manager)); + replacement_7.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + const std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %11 "A" + OpName %20 "B" + OpName %31 "g" + OpName %35 "h" + OpDecorate %11 RelaxedPrecision + OpDecorate %22 RelaxedPrecision + OpDecorate %27 RelaxedPrecision + OpDecorate %35 RelaxedPrecision + OpDecorate %36 RelaxedPrecision + OpDecorate %40 RelaxedPrecision + OpDecorate %41 RelaxedPrecision + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypeInt 32 0 + %8 = OpConstant %7 3 + %9 = OpTypeArray %6 %8 + %10 = OpTypePointer Function %9 + %12 = OpConstant %6 0 + %13 = OpConstant %6 3 + %14 = OpTypePointer Function %6 + %16 = OpTypeFloat 32 + %17 = OpConstant %7 4 + %18 = OpTypeArray %16 %17 + %19 = OpTypePointer Function %18 + %24 = OpTypePointer Function %16 + %28 = OpConstant %16 42 + %30 = OpConstant %6 2 + %34 = OpConstant %6 1 + %38 = OpConstant %6 42 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %11 = OpVariable %10 Function + %20 = OpVariable %19 Function + %31 = OpVariable %24 Function + %35 = OpVariable %14 Function + %15 = OpAccessChain %14 %11 %12 + %21 = OpAccessChain %14 %11 %12 + %22 = OpLoad %6 %21 + %100 = OpCompositeConstruct %9 %12 %13 %22 + %103 = OpCompositeExtract %6 %100 1 + OpStore %15 %103 + %104 = OpCompositeExtract %6 %100 2 + %23 = OpConvertSToF %16 %104 + %102 = OpCompositeExtract %6 %100 0 + %25 = OpAccessChain %24 %20 %102 + OpStore %25 %23 + %26 = OpAccessChain %14 %11 %12 + %27 = OpLoad %6 %26 + %29 = OpAccessChain %24 %20 %27 + OpStore %29 %28 + %32 = OpLoad %16 %31 + %101 = OpCompositeConstruct %18 %28 %23 %32 %23 + %106 = OpCompositeExtract %16 %101 1 + %50 = OpCopyObject %16 %106 + %108 = OpCompositeExtract %16 %101 3 + %51 = OpCopyObject %16 %108 + %33 = OpAccessChain %24 %20 %30 + %105 = OpCompositeExtract %16 %101 0 + OpStore %33 %105 + %107 = OpCompositeExtract %16 %101 2 + OpStore %33 %107 + %36 = OpLoad %6 %35 + %37 = OpAccessChain %14 %11 %34 + OpStore %37 %36 + %39 = OpAccessChain %14 %11 %12 + %40 = OpLoad %6 %39 + %41 = OpIAdd %6 %38 %40 + %42 = OpAccessChain %14 %11 %30 + OpStore %42 %41 + OpReturn + OpFunctionEnd + )"; + + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +TEST(DataSynonymTransformationTest, MatrixCompositeSynonyms) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %10 "m" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypeVector %6 4 + %50 = OpUndef %7 + %8 = OpTypeMatrix %7 3 + %9 = OpTypePointer Function %8 + %11 = OpTypeInt 32 1 + %12 = OpConstant %11 0 + %13 = OpConstant %6 1 + %14 = OpConstantComposite %7 %13 %13 %13 %13 + %15 = OpTypePointer Function %7 + %17 = OpConstant %11 1 + %18 = OpConstant %6 2 + %19 = OpConstantComposite %7 %18 %18 %18 %18 + %21 = OpConstant %11 2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %10 = OpVariable %9 Function + %16 = OpAccessChain %15 %10 %12 + OpStore %16 %14 + %20 = OpAccessChain %15 %10 %17 + OpStore %20 %19 + %22 = OpAccessChain %15 %10 %12 + %23 = OpLoad %7 %22 + %24 = OpAccessChain %15 %10 %17 + %25 = OpLoad %7 %24 + %100 = OpCompositeConstruct %8 %23 %25 %50 + %26 = OpFAdd %7 %23 %25 + %27 = OpAccessChain %15 %10 %21 + OpStore %27 %26 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + fact_manager.AddFact(MakeSynonymFact(23, {}, 100, {0}), context.get()); + fact_manager.AddFact(MakeSynonymFact(25, {}, 100, {1}), context.get()); + fact_manager.AddFact(MakeSynonymFact(50, {}, 100, {2}), context.get()); + + // Replace %23 with %100[0] in '%26 = OpFAdd %7 %23 %25' + auto instruction_descriptor_1 = MakeInstructionDescriptor(26, SpvOpFAdd, 0); + auto extract_1 = + TransformationCompositeExtract(instruction_descriptor_1, 101, 100, {0}); + ASSERT_TRUE(extract_1.IsApplicable(context.get(), fact_manager)); + extract_1.Apply(context.get(), &fact_manager); + auto replacement_1 = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor(23, instruction_descriptor_1, 0), 101); + ASSERT_TRUE(replacement_1.IsApplicable(context.get(), fact_manager)); + replacement_1.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + // Replace %25 with %100[1] in '%26 = OpFAdd %7 %23 %25' + auto instruction_descriptor_2 = MakeInstructionDescriptor(26, SpvOpFAdd, 0); + auto extract_2 = + TransformationCompositeExtract(instruction_descriptor_2, 102, 100, {1}); + ASSERT_TRUE(extract_2.IsApplicable(context.get(), fact_manager)); + extract_2.Apply(context.get(), &fact_manager); + auto replacement_2 = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor(25, instruction_descriptor_2, 1), 102); + ASSERT_TRUE(replacement_2.IsApplicable(context.get(), fact_manager)); + replacement_2.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + const std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %10 "m" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypeVector %6 4 + %50 = OpUndef %7 + %8 = OpTypeMatrix %7 3 + %9 = OpTypePointer Function %8 + %11 = OpTypeInt 32 1 + %12 = OpConstant %11 0 + %13 = OpConstant %6 1 + %14 = OpConstantComposite %7 %13 %13 %13 %13 + %15 = OpTypePointer Function %7 + %17 = OpConstant %11 1 + %18 = OpConstant %6 2 + %19 = OpConstantComposite %7 %18 %18 %18 %18 + %21 = OpConstant %11 2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %10 = OpVariable %9 Function + %16 = OpAccessChain %15 %10 %12 + OpStore %16 %14 + %20 = OpAccessChain %15 %10 %17 + OpStore %20 %19 + %22 = OpAccessChain %15 %10 %12 + %23 = OpLoad %7 %22 + %24 = OpAccessChain %15 %10 %17 + %25 = OpLoad %7 %24 + %100 = OpCompositeConstruct %8 %23 %25 %50 + %101 = OpCompositeExtract %7 %100 0 + %102 = OpCompositeExtract %7 %100 1 + %26 = OpFAdd %7 %101 %102 + %27 = OpAccessChain %15 %10 %21 + OpStore %27 %26 + OpReturn + OpFunctionEnd + )"; + + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +TEST(DataSynonymTransformationTest, StructCompositeSynonyms) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %9 "Inner" + OpMemberName %9 0 "a" + OpMemberName %9 1 "b" + OpName %11 "i1" + OpName %17 "i2" + OpName %31 "Point" + OpMemberName %31 0 "x" + OpMemberName %31 1 "y" + OpMemberName %31 2 "z" + OpName %32 "Outer" + OpMemberName %32 0 "c" + OpMemberName %32 1 "d" + OpName %34 "o1" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypeFloat 32 + %8 = OpTypeVector %7 2 + %9 = OpTypeStruct %6 %8 + %10 = OpTypePointer Function %9 + %12 = OpConstant %6 1 + %13 = OpConstant %7 2 + %14 = OpConstant %7 3 + %15 = OpConstantComposite %8 %13 %14 + %16 = OpConstantComposite %9 %12 %15 + %18 = OpConstant %6 0 + %19 = OpTypePointer Function %6 + %24 = OpTypePointer Function %8 + %27 = OpConstant %7 4 + %31 = OpTypeStruct %7 %7 %7 + %32 = OpTypeStruct %9 %31 + %33 = OpTypePointer Function %32 + %36 = OpConstant %7 10 + %37 = OpTypeInt 32 0 + %38 = OpConstant %37 0 + %39 = OpTypePointer Function %7 + %42 = OpConstant %37 1 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %11 = OpVariable %10 Function + %17 = OpVariable %10 Function + %34 = OpVariable %33 Function + %101 = OpCompositeConstruct %31 %27 %36 %27 + OpStore %11 %16 + %20 = OpAccessChain %19 %11 %18 + %21 = OpLoad %6 %20 + %22 = OpIAdd %6 %21 %12 + %102 = OpCompositeConstruct %9 %22 %15 + %23 = OpAccessChain %19 %17 %18 + OpStore %23 %22 + %25 = OpAccessChain %24 %17 %12 + %26 = OpLoad %8 %25 + %28 = OpCompositeConstruct %8 %27 %27 + %29 = OpFAdd %8 %26 %28 + %30 = OpAccessChain %24 %17 %12 + OpStore %30 %29 + %35 = OpLoad %9 %11 + %40 = OpAccessChain %39 %11 %12 %38 + %41 = OpLoad %7 %40 + %43 = OpAccessChain %39 %11 %12 %42 + %44 = OpLoad %7 %43 + %45 = OpCompositeConstruct %31 %36 %41 %44 + %100 = OpCompositeConstruct %32 %16 %45 + %46 = OpCompositeConstruct %32 %35 %45 + OpStore %34 %46 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + fact_manager.AddFact(MakeSynonymFact(16, {}, 100, {0}), context.get()); + fact_manager.AddFact(MakeSynonymFact(45, {}, 100, {1}), context.get()); + fact_manager.AddFact(MakeSynonymFact(27, {}, 101, {0}), context.get()); + fact_manager.AddFact(MakeSynonymFact(36, {}, 101, {1}), context.get()); + fact_manager.AddFact(MakeSynonymFact(27, {}, 101, {2}), context.get()); + fact_manager.AddFact(MakeSynonymFact(22, {}, 102, {0}), context.get()); + fact_manager.AddFact(MakeSynonymFact(15, {}, 102, {1}), context.get()); + + // Replace %45 with %100[1] in '%46 = OpCompositeConstruct %32 %35 %45' + auto instruction_descriptor_1 = + MakeInstructionDescriptor(46, SpvOpCompositeConstruct, 0); + auto extract_1 = + TransformationCompositeExtract(instruction_descriptor_1, 201, 100, {1}); + ASSERT_TRUE(extract_1.IsApplicable(context.get(), fact_manager)); + extract_1.Apply(context.get(), &fact_manager); + auto replacement_1 = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor(45, instruction_descriptor_1, 1), 201); + ASSERT_TRUE(replacement_1.IsApplicable(context.get(), fact_manager)); + replacement_1.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + // Replace second occurrence of %27 with %101[0] in '%28 = + // OpCompositeConstruct %8 %27 %27' + auto instruction_descriptor_2 = + MakeInstructionDescriptor(28, SpvOpCompositeConstruct, 0); + auto extract_2 = + TransformationCompositeExtract(instruction_descriptor_2, 202, 101, {0}); + ASSERT_TRUE(extract_2.IsApplicable(context.get(), fact_manager)); + extract_2.Apply(context.get(), &fact_manager); + auto replacement_2 = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor(27, instruction_descriptor_2, 1), 202); + ASSERT_TRUE(replacement_2.IsApplicable(context.get(), fact_manager)); + replacement_2.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + // Replace %36 with %101[1] in '%45 = OpCompositeConstruct %31 %36 %41 %44' + auto instruction_descriptor_3 = + MakeInstructionDescriptor(45, SpvOpCompositeConstruct, 0); + auto extract_3 = + TransformationCompositeExtract(instruction_descriptor_3, 203, 101, {1}); + ASSERT_TRUE(extract_3.IsApplicable(context.get(), fact_manager)); + extract_3.Apply(context.get(), &fact_manager); + auto replacement_3 = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor(36, instruction_descriptor_3, 0), 203); + ASSERT_TRUE(replacement_3.IsApplicable(context.get(), fact_manager)); + replacement_3.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + // Replace first occurrence of %27 with %101[2] in '%28 = OpCompositeConstruct + // %8 %27 %27' + auto instruction_descriptor_4 = + MakeInstructionDescriptor(28, SpvOpCompositeConstruct, 0); + auto extract_4 = + TransformationCompositeExtract(instruction_descriptor_4, 204, 101, {2}); + ASSERT_TRUE(extract_4.IsApplicable(context.get(), fact_manager)); + extract_4.Apply(context.get(), &fact_manager); + auto replacement_4 = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor(27, instruction_descriptor_4, 0), 204); + ASSERT_TRUE(replacement_4.IsApplicable(context.get(), fact_manager)); + replacement_4.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + // Replace %22 with %102[0] in 'OpStore %23 %22' + auto instruction_descriptor_5 = MakeInstructionDescriptor(23, SpvOpStore, 0); + auto extract_5 = + TransformationCompositeExtract(instruction_descriptor_5, 205, 102, {0}); + ASSERT_TRUE(extract_5.IsApplicable(context.get(), fact_manager)); + extract_5.Apply(context.get(), &fact_manager); + auto replacement_5 = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor(22, instruction_descriptor_5, 1), 205); + ASSERT_TRUE(replacement_5.IsApplicable(context.get(), fact_manager)); + replacement_5.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + const std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %9 "Inner" + OpMemberName %9 0 "a" + OpMemberName %9 1 "b" + OpName %11 "i1" + OpName %17 "i2" + OpName %31 "Point" + OpMemberName %31 0 "x" + OpMemberName %31 1 "y" + OpMemberName %31 2 "z" + OpName %32 "Outer" + OpMemberName %32 0 "c" + OpMemberName %32 1 "d" + OpName %34 "o1" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypeFloat 32 + %8 = OpTypeVector %7 2 + %9 = OpTypeStruct %6 %8 + %10 = OpTypePointer Function %9 + %12 = OpConstant %6 1 + %13 = OpConstant %7 2 + %14 = OpConstant %7 3 + %15 = OpConstantComposite %8 %13 %14 + %16 = OpConstantComposite %9 %12 %15 + %18 = OpConstant %6 0 + %19 = OpTypePointer Function %6 + %24 = OpTypePointer Function %8 + %27 = OpConstant %7 4 + %31 = OpTypeStruct %7 %7 %7 + %32 = OpTypeStruct %9 %31 + %33 = OpTypePointer Function %32 + %36 = OpConstant %7 10 + %37 = OpTypeInt 32 0 + %38 = OpConstant %37 0 + %39 = OpTypePointer Function %7 + %42 = OpConstant %37 1 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %11 = OpVariable %10 Function + %17 = OpVariable %10 Function + %34 = OpVariable %33 Function + %101 = OpCompositeConstruct %31 %27 %36 %27 + OpStore %11 %16 + %20 = OpAccessChain %19 %11 %18 + %21 = OpLoad %6 %20 + %22 = OpIAdd %6 %21 %12 + %102 = OpCompositeConstruct %9 %22 %15 + %23 = OpAccessChain %19 %17 %18 + %205 = OpCompositeExtract %6 %102 0 + OpStore %23 %205 + %25 = OpAccessChain %24 %17 %12 + %26 = OpLoad %8 %25 + %202 = OpCompositeExtract %7 %101 0 + %204 = OpCompositeExtract %7 %101 2 + %28 = OpCompositeConstruct %8 %204 %202 + %29 = OpFAdd %8 %26 %28 + %30 = OpAccessChain %24 %17 %12 + OpStore %30 %29 + %35 = OpLoad %9 %11 + %40 = OpAccessChain %39 %11 %12 %38 + %41 = OpLoad %7 %40 + %43 = OpAccessChain %39 %11 %12 %42 + %44 = OpLoad %7 %43 + %203 = OpCompositeExtract %7 %101 1 + %45 = OpCompositeConstruct %31 %203 %41 %44 + %100 = OpCompositeConstruct %32 %16 %45 + %201 = OpCompositeExtract %31 %100 1 + %46 = OpCompositeConstruct %32 %35 %201 + OpStore %34 %46 + OpReturn + OpFunctionEnd + )"; + + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +TEST(DataSynonymTransformationTest, VectorCompositeSynonyms) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %8 "f" + OpName %12 "v2" + OpName %18 "v3" + OpName %23 "v4" + OpName %32 "b" + OpName %36 "bv2" + OpName %41 "bv3" + OpName %50 "bv4" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 42 + %10 = OpTypeVector %6 2 + %11 = OpTypePointer Function %10 + %16 = OpTypeVector %6 3 + %17 = OpTypePointer Function %16 + %21 = OpTypeVector %6 4 + %22 = OpTypePointer Function %21 + %30 = OpTypeBool + %31 = OpTypePointer Function %30 + %33 = OpConstantFalse %30 + %34 = OpTypeVector %30 2 + %35 = OpTypePointer Function %34 + %37 = OpConstantTrue %30 + %38 = OpConstantComposite %34 %37 %37 + %39 = OpTypeVector %30 3 + %40 = OpTypePointer Function %39 + %48 = OpTypeVector %30 4 + %49 = OpTypePointer Function %48 + %51 = OpTypeInt 32 0 + %52 = OpConstant %51 2 + %55 = OpConstant %6 0 + %57 = OpConstant %51 1 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %12 = OpVariable %11 Function + %18 = OpVariable %17 Function + %23 = OpVariable %22 Function + %32 = OpVariable %31 Function + %36 = OpVariable %35 Function + %41 = OpVariable %40 Function + %50 = OpVariable %49 Function + OpStore %8 %9 + %13 = OpLoad %6 %8 + %14 = OpLoad %6 %8 + %15 = OpCompositeConstruct %10 %13 %14 + OpStore %12 %15 + %19 = OpLoad %10 %12 + %20 = OpVectorShuffle %16 %19 %19 0 0 1 + OpStore %18 %20 + %24 = OpLoad %16 %18 + %25 = OpLoad %6 %8 + %26 = OpCompositeExtract %6 %24 0 + %27 = OpCompositeExtract %6 %24 1 + %28 = OpCompositeExtract %6 %24 2 + %29 = OpCompositeConstruct %21 %26 %27 %28 %25 + OpStore %23 %29 + OpStore %32 %33 + OpStore %36 %38 + %42 = OpLoad %30 %32 + %43 = OpLoad %34 %36 + %44 = OpVectorShuffle %34 %43 %43 0 0 + %45 = OpCompositeExtract %30 %44 0 + %46 = OpCompositeExtract %30 %44 1 + %47 = OpCompositeConstruct %39 %42 %45 %46 + OpStore %41 %47 + %53 = OpAccessChain %7 %23 %52 + %54 = OpLoad %6 %53 + + %100 = OpCompositeConstruct %21 %20 %54 + %101 = OpCompositeConstruct %21 %15 %19 + %102 = OpCompositeConstruct %16 %27 %15 + %103 = OpCompositeConstruct %48 %33 %47 + %104 = OpCompositeConstruct %34 %42 %45 + %105 = OpCompositeConstruct %39 %38 %46 + + %86 = OpCopyObject %30 %33 + %56 = OpFOrdNotEqual %30 %54 %55 + %80 = OpCopyObject %16 %20 + %58 = OpAccessChain %7 %18 %57 + %59 = OpLoad %6 %58 + %60 = OpFOrdNotEqual %30 %59 %55 + %61 = OpLoad %34 %36 + %62 = OpLogicalAnd %30 %45 %46 + %63 = OpLogicalOr %30 %45 %46 + %64 = OpCompositeConstruct %48 %56 %60 %62 %63 + OpStore %12 %15 + %81 = OpVectorShuffle %16 %19 %19 0 0 1 + %82 = OpCompositeConstruct %21 %26 %27 %28 %25 + %83 = OpCopyObject %10 %15 + %84 = OpCopyObject %39 %47 + OpStore %50 %64 + %85 = OpCopyObject %30 %42 + OpStore %36 %38 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + fact_manager.AddFact(MakeSynonymFact(20, {0}, 100, {0}), context.get()); + fact_manager.AddFact(MakeSynonymFact(20, {1}, 100, {1}), context.get()); + fact_manager.AddFact(MakeSynonymFact(20, {2}, 100, {2}), context.get()); + fact_manager.AddFact(MakeSynonymFact(54, {}, 100, {3}), context.get()); + fact_manager.AddFact(MakeSynonymFact(15, {0}, 101, {0}), context.get()); + fact_manager.AddFact(MakeSynonymFact(15, {1}, 101, {1}), context.get()); + fact_manager.AddFact(MakeSynonymFact(19, {0}, 101, {2}), context.get()); + fact_manager.AddFact(MakeSynonymFact(19, {1}, 101, {3}), context.get()); + fact_manager.AddFact(MakeSynonymFact(27, {}, 102, {0}), context.get()); + fact_manager.AddFact(MakeSynonymFact(15, {0}, 102, {1}), context.get()); + fact_manager.AddFact(MakeSynonymFact(15, {1}, 102, {2}), context.get()); + fact_manager.AddFact(MakeSynonymFact(33, {}, 103, {0}), context.get()); + fact_manager.AddFact(MakeSynonymFact(47, {0}, 103, {1}), context.get()); + fact_manager.AddFact(MakeSynonymFact(47, {1}, 103, {2}), context.get()); + fact_manager.AddFact(MakeSynonymFact(47, {2}, 103, {3}), context.get()); + fact_manager.AddFact(MakeSynonymFact(42, {}, 104, {0}), context.get()); + fact_manager.AddFact(MakeSynonymFact(45, {}, 104, {1}), context.get()); + fact_manager.AddFact(MakeSynonymFact(38, {0}, 105, {0}), context.get()); + fact_manager.AddFact(MakeSynonymFact(38, {1}, 105, {1}), context.get()); + fact_manager.AddFact(MakeSynonymFact(46, {}, 105, {2}), context.get()); + + // Replace %20 with %100[0:2] in '%80 = OpCopyObject %16 %20' + auto instruction_descriptor_1 = + MakeInstructionDescriptor(80, SpvOpCopyObject, 0); + auto shuffle_1 = TransformationVectorShuffle(instruction_descriptor_1, 200, + 100, 100, {0, 1, 2}); + ASSERT_TRUE(shuffle_1.IsApplicable(context.get(), fact_manager)); + shuffle_1.Apply(context.get(), &fact_manager); + auto replacement_1 = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor(20, instruction_descriptor_1, 0), 200); + ASSERT_TRUE(replacement_1.IsApplicable(context.get(), fact_manager)); + replacement_1.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + // Replace %54 with %100[3] in '%56 = OpFOrdNotEqual %30 %54 %55' + auto instruction_descriptor_2 = + MakeInstructionDescriptor(56, SpvOpFOrdNotEqual, 0); + auto extract_2 = + TransformationCompositeExtract(instruction_descriptor_2, 201, 100, {3}); + + ASSERT_TRUE(extract_2.IsApplicable(context.get(), fact_manager)); + extract_2.Apply(context.get(), &fact_manager); + auto replacement_2 = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor(54, instruction_descriptor_2, 0), 201); + ASSERT_TRUE(replacement_2.IsApplicable(context.get(), fact_manager)); + replacement_2.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + // Replace %15 with %101[0:1] in 'OpStore %12 %15' + auto instruction_descriptor_3 = MakeInstructionDescriptor(64, SpvOpStore, 0); + auto shuffle_3 = TransformationVectorShuffle(instruction_descriptor_3, 202, + 101, 101, {0, 1}); + ASSERT_TRUE(shuffle_3.IsApplicable(context.get(), fact_manager)); + shuffle_3.Apply(context.get(), &fact_manager); + auto replacement_3 = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor(15, instruction_descriptor_3, 1), 202); + ASSERT_TRUE(replacement_3.IsApplicable(context.get(), fact_manager)); + replacement_3.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + // Replace %19 with %101[2:3] in '%81 = OpVectorShuffle %16 %19 %19 0 0 1' + auto instruction_descriptor_4 = + MakeInstructionDescriptor(81, SpvOpVectorShuffle, 0); + auto shuffle_4 = TransformationVectorShuffle(instruction_descriptor_4, 203, + 101, 101, {2, 3}); + ASSERT_TRUE(shuffle_4.IsApplicable(context.get(), fact_manager)); + shuffle_4.Apply(context.get(), &fact_manager); + auto replacement_4 = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor(19, instruction_descriptor_4, 0), 203); + ASSERT_TRUE(replacement_4.IsApplicable(context.get(), fact_manager)); + replacement_4.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + // Replace %27 with %102[0] in '%82 = OpCompositeConstruct %21 %26 %27 %28 + // %25' + auto instruction_descriptor_5 = + MakeInstructionDescriptor(82, SpvOpCompositeConstruct, 0); + auto extract_5 = + TransformationCompositeExtract(instruction_descriptor_5, 204, 102, {0}); + + ASSERT_TRUE(extract_5.IsApplicable(context.get(), fact_manager)); + extract_5.Apply(context.get(), &fact_manager); + auto replacement_5 = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor(27, instruction_descriptor_5, 1), 204); + ASSERT_TRUE(replacement_5.IsApplicable(context.get(), fact_manager)); + replacement_5.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + // Replace %15 with %102[1:2] in '%83 = OpCopyObject %10 %15' + auto instruction_descriptor_6 = + MakeInstructionDescriptor(83, SpvOpCopyObject, 0); + auto shuffle_6 = TransformationVectorShuffle(instruction_descriptor_6, 205, + 102, 102, {1, 2}); + ASSERT_TRUE(shuffle_6.IsApplicable(context.get(), fact_manager)); + shuffle_6.Apply(context.get(), &fact_manager); + auto replacement_6 = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor(15, instruction_descriptor_6, 0), 205); + ASSERT_TRUE(replacement_6.IsApplicable(context.get(), fact_manager)); + replacement_6.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + // Replace %33 with %103[0] in '%86 = OpCopyObject %30 %33' + auto instruction_descriptor_7 = + MakeInstructionDescriptor(86, SpvOpCopyObject, 0); + auto extract_7 = + TransformationCompositeExtract(instruction_descriptor_7, 206, 103, {0}); + ASSERT_TRUE(extract_7.IsApplicable(context.get(), fact_manager)); + extract_7.Apply(context.get(), &fact_manager); + auto replacement_7 = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor(33, instruction_descriptor_7, 0), 206); + ASSERT_TRUE(replacement_7.IsApplicable(context.get(), fact_manager)); + replacement_7.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + // Replace %47 with %103[1:3] in '%84 = OpCopyObject %39 %47' + auto instruction_descriptor_8 = + MakeInstructionDescriptor(84, SpvOpCopyObject, 0); + auto shuffle_8 = TransformationVectorShuffle(instruction_descriptor_8, 207, + 103, 103, {1, 2, 3}); + ASSERT_TRUE(shuffle_8.IsApplicable(context.get(), fact_manager)); + shuffle_8.Apply(context.get(), &fact_manager); + auto replacement_8 = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor(47, instruction_descriptor_8, 0), 207); + ASSERT_TRUE(replacement_8.IsApplicable(context.get(), fact_manager)); + replacement_8.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + // Replace %42 with %104[0] in '%85 = OpCopyObject %30 %42' + auto instruction_descriptor_9 = + MakeInstructionDescriptor(85, SpvOpCopyObject, 0); + auto extract_9 = + TransformationCompositeExtract(instruction_descriptor_9, 208, 104, {0}); + ASSERT_TRUE(extract_9.IsApplicable(context.get(), fact_manager)); + extract_9.Apply(context.get(), &fact_manager); + auto replacement_9 = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor(42, instruction_descriptor_9, 0), 208); + ASSERT_TRUE(replacement_9.IsApplicable(context.get(), fact_manager)); + replacement_9.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + // Replace %45 with %104[1] in '%63 = OpLogicalOr %30 %45 %46' + auto instruction_descriptor_10 = + MakeInstructionDescriptor(63, SpvOpLogicalOr, 0); + auto extract_10 = + TransformationCompositeExtract(instruction_descriptor_10, 209, 104, {1}); + ASSERT_TRUE(extract_10.IsApplicable(context.get(), fact_manager)); + extract_10.Apply(context.get(), &fact_manager); + auto replacement_10 = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor(45, instruction_descriptor_10, 0), 209); + ASSERT_TRUE(replacement_10.IsApplicable(context.get(), fact_manager)); + replacement_10.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + // Replace %38 with %105[0:1] in 'OpStore %36 %38' + auto instruction_descriptor_11 = MakeInstructionDescriptor(85, SpvOpStore, 0); + auto shuffle_11 = TransformationVectorShuffle(instruction_descriptor_11, 210, + 105, 105, {0, 1}); + ASSERT_TRUE(shuffle_11.IsApplicable(context.get(), fact_manager)); + shuffle_11.Apply(context.get(), &fact_manager); + auto replacement_11 = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor(38, instruction_descriptor_11, 1), 210); + ASSERT_TRUE(replacement_11.IsApplicable(context.get(), fact_manager)); + replacement_11.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + // Replace %46 with %105[2] in '%62 = OpLogicalAnd %30 %45 %46' + auto instruction_descriptor_12 = + MakeInstructionDescriptor(62, SpvOpLogicalAnd, 0); + auto extract_12 = + TransformationCompositeExtract(instruction_descriptor_12, 211, 105, {2}); + ASSERT_TRUE(extract_12.IsApplicable(context.get(), fact_manager)); + extract_12.Apply(context.get(), &fact_manager); + auto replacement_12 = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor(46, instruction_descriptor_12, 1), 211); + ASSERT_TRUE(replacement_12.IsApplicable(context.get(), fact_manager)); + replacement_12.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + const std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %8 "f" + OpName %12 "v2" + OpName %18 "v3" + OpName %23 "v4" + OpName %32 "b" + OpName %36 "bv2" + OpName %41 "bv3" + OpName %50 "bv4" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 42 + %10 = OpTypeVector %6 2 + %11 = OpTypePointer Function %10 + %16 = OpTypeVector %6 3 + %17 = OpTypePointer Function %16 + %21 = OpTypeVector %6 4 + %22 = OpTypePointer Function %21 + %30 = OpTypeBool + %31 = OpTypePointer Function %30 + %33 = OpConstantFalse %30 + %34 = OpTypeVector %30 2 + %35 = OpTypePointer Function %34 + %37 = OpConstantTrue %30 + %38 = OpConstantComposite %34 %37 %37 + %39 = OpTypeVector %30 3 + %40 = OpTypePointer Function %39 + %48 = OpTypeVector %30 4 + %49 = OpTypePointer Function %48 + %51 = OpTypeInt 32 0 + %52 = OpConstant %51 2 + %55 = OpConstant %6 0 + %57 = OpConstant %51 1 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %12 = OpVariable %11 Function + %18 = OpVariable %17 Function + %23 = OpVariable %22 Function + %32 = OpVariable %31 Function + %36 = OpVariable %35 Function + %41 = OpVariable %40 Function + %50 = OpVariable %49 Function + OpStore %8 %9 + %13 = OpLoad %6 %8 + %14 = OpLoad %6 %8 + %15 = OpCompositeConstruct %10 %13 %14 + OpStore %12 %15 + %19 = OpLoad %10 %12 + %20 = OpVectorShuffle %16 %19 %19 0 0 1 + OpStore %18 %20 + %24 = OpLoad %16 %18 + %25 = OpLoad %6 %8 + %26 = OpCompositeExtract %6 %24 0 + %27 = OpCompositeExtract %6 %24 1 + %28 = OpCompositeExtract %6 %24 2 + %29 = OpCompositeConstruct %21 %26 %27 %28 %25 + OpStore %23 %29 + OpStore %32 %33 + OpStore %36 %38 + %42 = OpLoad %30 %32 + %43 = OpLoad %34 %36 + %44 = OpVectorShuffle %34 %43 %43 0 0 + %45 = OpCompositeExtract %30 %44 0 + %46 = OpCompositeExtract %30 %44 1 + %47 = OpCompositeConstruct %39 %42 %45 %46 + OpStore %41 %47 + %53 = OpAccessChain %7 %23 %52 + %54 = OpLoad %6 %53 + + %100 = OpCompositeConstruct %21 %20 %54 + %101 = OpCompositeConstruct %21 %15 %19 + %102 = OpCompositeConstruct %16 %27 %15 + %103 = OpCompositeConstruct %48 %33 %47 + %104 = OpCompositeConstruct %34 %42 %45 + %105 = OpCompositeConstruct %39 %38 %46 + + %206 = OpCompositeExtract %30 %103 0 + %86 = OpCopyObject %30 %206 + %201 = OpCompositeExtract %6 %100 3 + %56 = OpFOrdNotEqual %30 %201 %55 + %200 = OpVectorShuffle %16 %100 %100 0 1 2 + %80 = OpCopyObject %16 %200 + %58 = OpAccessChain %7 %18 %57 + %59 = OpLoad %6 %58 + %60 = OpFOrdNotEqual %30 %59 %55 + %61 = OpLoad %34 %36 + %211 = OpCompositeExtract %30 %105 2 + %62 = OpLogicalAnd %30 %45 %211 + %209 = OpCompositeExtract %30 %104 1 + %63 = OpLogicalOr %30 %209 %46 + %64 = OpCompositeConstruct %48 %56 %60 %62 %63 + %202 = OpVectorShuffle %10 %101 %101 0 1 + OpStore %12 %202 + %203 = OpVectorShuffle %10 %101 %101 2 3 + %81 = OpVectorShuffle %16 %203 %19 0 0 1 + %204 = OpCompositeExtract %6 %102 0 + %82 = OpCompositeConstruct %21 %26 %204 %28 %25 + %205 = OpVectorShuffle %10 %102 %102 1 2 + %83 = OpCopyObject %10 %205 + %207 = OpVectorShuffle %39 %103 %103 1 2 3 + %84 = OpCopyObject %39 %207 + OpStore %50 %64 + %208 = OpCompositeExtract %30 %104 0 + %85 = OpCopyObject %30 %208 + %210 = OpVectorShuffle %34 %105 %105 0 1 + OpStore %36 %210 + OpReturn + OpFunctionEnd + )"; + + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +} // namespace +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/test/fuzz/equivalence_relation_test.cpp b/third_party/spirv-tools/test/fuzz/equivalence_relation_test.cpp new file mode 100644 index 0000000000..3f2ea58fe8 --- /dev/null +++ b/third_party/spirv-tools/test/fuzz/equivalence_relation_test.cpp @@ -0,0 +1,145 @@ +// Copyright (c) 2019 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 + +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include "source/fuzz/equivalence_relation.h" + +namespace spvtools { +namespace fuzz { +namespace { + +struct UInt32Equals { + bool operator()(const uint32_t* first, const uint32_t* second) const { + return *first == *second; + } +}; + +struct UInt32Hash { + size_t operator()(const uint32_t* element) const { + return static_cast(*element); + } +}; + +std::vector ToUIntVector( + const std::vector& pointers) { + std::vector result; + for (auto pointer : pointers) { + result.push_back(*pointer); + } + return result; +} + +TEST(EquivalenceRelationTest, BasicTest) { + EquivalenceRelation relation; + ASSERT_TRUE(relation.GetAllKnownValues().empty()); + + for (uint32_t element = 2; element < 80; element += 2) { + relation.MakeEquivalent(0, element); + relation.MakeEquivalent(element - 1, element + 1); + } + + for (uint32_t element = 82; element < 100; element += 2) { + relation.MakeEquivalent(80, element); + relation.MakeEquivalent(element - 1, element + 1); + } + + relation.MakeEquivalent(78, 80); + + std::vector class1; + for (uint32_t element = 0; element < 98; element += 2) { + ASSERT_TRUE(relation.IsEquivalent(0, element)); + ASSERT_TRUE(relation.IsEquivalent(element, element + 2)); + class1.push_back(element); + } + class1.push_back(98); + + ASSERT_THAT(ToUIntVector(relation.GetEquivalenceClass(0)), + testing::WhenSorted(class1)); + ASSERT_THAT(ToUIntVector(relation.GetEquivalenceClass(4)), + testing::WhenSorted(class1)); + ASSERT_THAT(ToUIntVector(relation.GetEquivalenceClass(40)), + testing::WhenSorted(class1)); + + std::vector class2; + for (uint32_t element = 1; element < 79; element += 2) { + ASSERT_TRUE(relation.IsEquivalent(1, element)); + ASSERT_TRUE(relation.IsEquivalent(element, element + 2)); + class2.push_back(element); + } + class2.push_back(79); + ASSERT_THAT(ToUIntVector(relation.GetEquivalenceClass(1)), + testing::WhenSorted(class2)); + ASSERT_THAT(ToUIntVector(relation.GetEquivalenceClass(11)), + testing::WhenSorted(class2)); + ASSERT_THAT(ToUIntVector(relation.GetEquivalenceClass(31)), + testing::WhenSorted(class2)); + + std::vector class3; + for (uint32_t element = 81; element < 99; element += 2) { + ASSERT_TRUE(relation.IsEquivalent(81, element)); + ASSERT_TRUE(relation.IsEquivalent(element, element + 2)); + class3.push_back(element); + } + class3.push_back(99); + ASSERT_THAT(ToUIntVector(relation.GetEquivalenceClass(81)), + testing::WhenSorted(class3)); + ASSERT_THAT(ToUIntVector(relation.GetEquivalenceClass(91)), + testing::WhenSorted(class3)); + ASSERT_THAT(ToUIntVector(relation.GetEquivalenceClass(99)), + testing::WhenSorted(class3)); + + bool first = true; + std::vector previous_class; + for (auto representative : relation.GetEquivalenceClassRepresentatives()) { + std::vector current_class = + relation.GetEquivalenceClass(*representative); + ASSERT_TRUE(std::find(current_class.begin(), current_class.end(), + representative) != current_class.end()); + if (!first) { + ASSERT_TRUE(std::find(previous_class.begin(), previous_class.end(), + representative) == previous_class.end()); + } + previous_class = current_class; + first = false; + } +} + +TEST(EquivalenceRelationTest, DeterministicEquivalenceClassOrder) { + EquivalenceRelation relation1; + EquivalenceRelation relation2; + + for (uint32_t i = 0; i < 1000; ++i) { + if (i >= 10) { + relation1.MakeEquivalent(i, i - 10); + relation2.MakeEquivalent(i, i - 10); + } + } + + // We constructed the equivalence relations in the same way, so we would like + // them to have identical representatives, and identically-ordered equivalence + // classes per representative. + ASSERT_THAT(ToUIntVector(relation1.GetEquivalenceClassRepresentatives()), + ToUIntVector(relation2.GetEquivalenceClassRepresentatives())); + for (auto representative : relation1.GetEquivalenceClassRepresentatives()) { + ASSERT_THAT(ToUIntVector(relation1.GetEquivalenceClass(*representative)), + ToUIntVector(relation2.GetEquivalenceClass(*representative))); + } +} + +} // namespace +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/test/fuzz/fact_manager_test.cpp b/third_party/spirv-tools/test/fuzz/fact_manager_test.cpp new file mode 100644 index 0000000000..b3f32cd513 --- /dev/null +++ b/third_party/spirv-tools/test/fuzz/fact_manager_test.cpp @@ -0,0 +1,1178 @@ +// Copyright (c) 2019 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 + +#include "source/fuzz/fact_manager.h" +#include "source/fuzz/uniform_buffer_element_descriptor.h" +#include "test/fuzz/fuzz_test_util.h" + +namespace spvtools { +namespace fuzz { +namespace { + +using opt::analysis::BoolConstant; +using opt::analysis::FloatConstant; +using opt::analysis::IntConstant; +using opt::analysis::ScalarConstant; + +using opt::analysis::Bool; +using opt::analysis::Float; +using opt::analysis::Integer; +using opt::analysis::Type; + +bool AddFactHelper( + FactManager* fact_manager, opt::IRContext* context, + std::vector&& words, + const protobufs::UniformBufferElementDescriptor& descriptor) { + protobufs::FactConstantUniform constant_uniform_fact; + for (auto word : words) { + constant_uniform_fact.add_constant_word(word); + } + *constant_uniform_fact.mutable_uniform_buffer_element_descriptor() = + descriptor; + protobufs::Fact fact; + *fact.mutable_constant_uniform_fact() = constant_uniform_fact; + return fact_manager->AddFact(fact, context); +} + +TEST(FactManagerTest, ConstantsAvailableViaUniforms) { + std::string shader = R"( + OpCapability Shader + OpCapability Int64 + OpCapability Float64 + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource GLSL 450 + OpName %4 "main" + OpDecorate %100 DescriptorSet 0 + OpDecorate %100 Binding 0 + OpDecorate %200 DescriptorSet 0 + OpDecorate %200 Binding 1 + OpDecorate %300 DescriptorSet 0 + OpDecorate %300 Binding 2 + OpDecorate %400 DescriptorSet 0 + OpDecorate %400 Binding 3 + OpDecorate %500 DescriptorSet 0 + OpDecorate %500 Binding 4 + OpDecorate %600 DescriptorSet 0 + OpDecorate %600 Binding 5 + OpDecorate %700 DescriptorSet 0 + OpDecorate %700 Binding 6 + OpDecorate %800 DescriptorSet 1 + OpDecorate %800 Binding 0 + OpDecorate %900 DescriptorSet 1 + OpDecorate %900 Binding 1 + OpDecorate %1000 DescriptorSet 1 + OpDecorate %1000 Binding 2 + OpDecorate %1100 DescriptorSet 1 + OpDecorate %1100 Binding 3 + OpDecorate %1200 DescriptorSet 1 + OpDecorate %1200 Binding 4 + OpDecorate %1300 DescriptorSet 1 + OpDecorate %1300 Binding 5 + OpDecorate %1400 DescriptorSet 1 + OpDecorate %1400 Binding 6 + OpDecorate %1500 DescriptorSet 2 + OpDecorate %1500 Binding 0 + OpDecorate %1600 DescriptorSet 2 + OpDecorate %1600 Binding 1 + OpDecorate %1700 DescriptorSet 2 + OpDecorate %1700 Binding 2 + OpDecorate %1800 DescriptorSet 2 + OpDecorate %1800 Binding 3 + OpDecorate %1900 DescriptorSet 2 + OpDecorate %1900 Binding 4 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %10 = OpTypeInt 32 0 + %11 = OpTypeInt 32 1 + %12 = OpTypeInt 64 0 + %13 = OpTypeInt 64 1 + %15 = OpTypeFloat 32 + %16 = OpTypeFloat 64 + %17 = OpConstant %11 5 + %18 = OpConstant %11 20 + %19 = OpTypeVector %10 4 + %20 = OpConstant %11 6 + %21 = OpTypeVector %12 4 + %22 = OpConstant %11 10 + %23 = OpTypeVector %11 4 + + %102 = OpTypeStruct %10 %10 %23 + %101 = OpTypePointer Uniform %102 + %100 = OpVariable %101 Uniform + + %203 = OpTypeArray %23 %17 + %202 = OpTypeArray %203 %18 + %201 = OpTypePointer Uniform %202 + %200 = OpVariable %201 Uniform + + %305 = OpTypeStruct %16 %16 %16 %11 %16 + %304 = OpTypeStruct %16 %16 %305 + %303 = OpTypeStruct %304 + %302 = OpTypeStruct %10 %303 + %301 = OpTypePointer Uniform %302 + %300 = OpVariable %301 Uniform + + %400 = OpVariable %101 Uniform + + %500 = OpVariable %201 Uniform + + %604 = OpTypeArray %13 %20 + %603 = OpTypeArray %604 %20 + %602 = OpTypeArray %603 %20 + %601 = OpTypePointer Uniform %602 + %600 = OpVariable %601 Uniform + + %703 = OpTypeArray %13 %20 + %702 = OpTypeArray %703 %20 + %701 = OpTypePointer Uniform %702 + %700 = OpVariable %701 Uniform + + %802 = OpTypeStruct %702 %602 %19 %202 %302 + %801 = OpTypePointer Uniform %802 + %800 = OpVariable %801 Uniform + + %902 = OpTypeStruct %702 %802 %19 %202 %302 + %901 = OpTypePointer Uniform %902 + %900 = OpVariable %901 Uniform + + %1003 = OpTypeStruct %802 + %1002 = OpTypeArray %1003 %20 + %1001 = OpTypePointer Uniform %1002 + %1000 = OpVariable %1001 Uniform + + %1101 = OpTypePointer Uniform %21 + %1100 = OpVariable %1101 Uniform + + %1202 = OpTypeArray %21 %20 + %1201 = OpTypePointer Uniform %1202 + %1200 = OpVariable %1201 Uniform + + %1302 = OpTypeArray %21 %20 + %1301 = OpTypePointer Uniform %1302 + %1300 = OpVariable %1301 Uniform + + %1402 = OpTypeArray %15 %22 + %1401 = OpTypePointer Uniform %1402 + %1400 = OpVariable %1401 Uniform + + %1501 = OpTypePointer Uniform %1402 + %1500 = OpVariable %1501 Uniform + + %1602 = OpTypeArray %1402 %22 + %1601 = OpTypePointer Uniform %1602 + %1600 = OpVariable %1601 Uniform + + %1704 = OpTypeStruct %16 %16 %16 + %1703 = OpTypeArray %1704 %22 + %1702 = OpTypeArray %1703 %22 + %1701 = OpTypePointer Uniform %1702 + %1700 = OpVariable %1701 Uniform + + %1800 = OpVariable %1701 Uniform + + %1906 = OpTypeStruct %16 + %1905 = OpTypeStruct %1906 + %1904 = OpTypeStruct %1905 + %1903 = OpTypeStruct %1904 + %1902 = OpTypeStruct %1903 + %1901 = OpTypePointer Uniform %1902 + %1900 = OpVariable %1901 Uniform + + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + uint32_t buffer_int32_min[1]; + uint32_t buffer_int64_1[2]; + uint32_t buffer_int64_max[2]; + uint32_t buffer_uint64_1[2]; + uint32_t buffer_uint64_max[2]; + uint32_t buffer_float_10[1]; + uint32_t buffer_double_10[2]; + uint32_t buffer_double_20[2]; + + { + int32_t temp = std::numeric_limits::min(); + std::memcpy(&buffer_int32_min, &temp, sizeof(temp)); + } + + { + int64_t temp = 1; + std::memcpy(&buffer_int64_1, &temp, sizeof(temp)); + } + + { + int64_t temp = std::numeric_limits::max(); + std::memcpy(&buffer_int64_max, &temp, sizeof(temp)); + } + + { + uint64_t temp = 1; + std::memcpy(&buffer_uint64_1, &temp, sizeof(temp)); + } + + { + uint64_t temp = std::numeric_limits::max(); + std::memcpy(&buffer_uint64_max, &temp, sizeof(temp)); + } + + { + float temp = 10.0f; + std::memcpy(&buffer_float_10, &temp, sizeof(float)); + } + + { + double temp = 10.0; + std::memcpy(&buffer_double_10, &temp, sizeof(temp)); + } + + { + double temp = 20.0; + std::memcpy(&buffer_double_20, &temp, sizeof(temp)); + } + + FactManager fact_manager; + + uint32_t type_int32_id = 11; + uint32_t type_int64_id = 13; + uint32_t type_uint32_id = 10; + uint32_t type_uint64_id = 12; + uint32_t type_float_id = 15; + uint32_t type_double_id = 16; + + // Initially there should be no facts about uniforms. + ASSERT_TRUE(fact_manager + .GetConstantsAvailableFromUniformsForType(context.get(), + type_uint32_id) + .empty()); + + // In the comments that follow we write v[...][...] to refer to uniform + // variable v indexed with some given indices, when in practice v is + // identified via a (descriptor set, binding) pair. + + // 100[2][3] == int(1) + ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), {1}, + MakeUniformBufferElementDescriptor(0, 0, {2, 3}))); + + // 200[1][2][3] == int(1) + ASSERT_TRUE( + AddFactHelper(&fact_manager, context.get(), {1}, + MakeUniformBufferElementDescriptor(0, 1, {1, 2, 3}))); + + // 300[1][0][2][3] == int(1) + ASSERT_TRUE( + AddFactHelper(&fact_manager, context.get(), {1}, + MakeUniformBufferElementDescriptor(0, 2, {1, 0, 2, 3}))); + + // 400[2][3] = int32_min + ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), {buffer_int32_min[0]}, + MakeUniformBufferElementDescriptor(0, 3, {2, 3}))); + + // 500[1][2][3] = int32_min + ASSERT_TRUE( + AddFactHelper(&fact_manager, context.get(), {buffer_int32_min[0]}, + MakeUniformBufferElementDescriptor(0, 4, {1, 2, 3}))); + + // 600[1][2][3] = int64_max + ASSERT_TRUE(AddFactHelper( + &fact_manager, context.get(), {buffer_int64_max[0], buffer_int64_max[1]}, + MakeUniformBufferElementDescriptor(0, 5, {1, 2, 3}))); + + // 700[1][1] = int64_max + ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), + {buffer_int64_max[0], buffer_int64_max[1]}, + MakeUniformBufferElementDescriptor(0, 6, {1, 1}))); + + // 800[2][3] = uint(1) + ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), {1}, + MakeUniformBufferElementDescriptor(1, 0, {2, 3}))); + + // 900[1][2][3] = uint(1) + ASSERT_TRUE( + AddFactHelper(&fact_manager, context.get(), {1}, + MakeUniformBufferElementDescriptor(1, 1, {1, 2, 3}))); + + // 1000[1][0][2][3] = uint(1) + ASSERT_TRUE( + AddFactHelper(&fact_manager, context.get(), {1}, + MakeUniformBufferElementDescriptor(1, 2, {1, 0, 2, 3}))); + + // 1100[0] = uint64(1) + ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), + {buffer_uint64_1[0], buffer_uint64_1[1]}, + MakeUniformBufferElementDescriptor(1, 3, {0}))); + + // 1200[0][0] = uint64_max + ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), + {buffer_uint64_max[0], buffer_uint64_max[1]}, + MakeUniformBufferElementDescriptor(1, 4, {0, 0}))); + + // 1300[1][0] = uint64_max + ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), + {buffer_uint64_max[0], buffer_uint64_max[1]}, + MakeUniformBufferElementDescriptor(1, 5, {1, 0}))); + + // 1400[6] = float(10.0) + ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), {buffer_float_10[0]}, + MakeUniformBufferElementDescriptor(1, 6, {6}))); + + // 1500[7] = float(10.0) + ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), {buffer_float_10[0]}, + MakeUniformBufferElementDescriptor(2, 0, {7}))); + + // 1600[9][9] = float(10.0) + ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), {buffer_float_10[0]}, + MakeUniformBufferElementDescriptor(2, 1, {9, 9}))); + + // 1700[9][9][1] = double(10.0) + ASSERT_TRUE(AddFactHelper( + &fact_manager, context.get(), {buffer_double_10[0], buffer_double_10[1]}, + MakeUniformBufferElementDescriptor(2, 2, {9, 9, 1}))); + + // 1800[9][9][2] = double(10.0) + ASSERT_TRUE(AddFactHelper( + &fact_manager, context.get(), {buffer_double_10[0], buffer_double_10[1]}, + MakeUniformBufferElementDescriptor(2, 3, {9, 9, 2}))); + + // 1900[0][0][0][0][0] = double(20.0) + ASSERT_TRUE(AddFactHelper( + &fact_manager, context.get(), {buffer_double_20[0], buffer_double_20[1]}, + MakeUniformBufferElementDescriptor(2, 4, {0, 0, 0, 0, 0}))); + + opt::Instruction::OperandList operands = { + {SPV_OPERAND_TYPE_LITERAL_INTEGER, {1}}}; + context->module()->AddGlobalValue(MakeUnique( + context.get(), SpvOpConstant, type_int32_id, 50, operands)); + operands = {{SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_int32_min[0]}}}; + context->module()->AddGlobalValue(MakeUnique( + context.get(), SpvOpConstant, type_int32_id, 51, operands)); + operands = {{SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_int64_max[0]}}, + {SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_int64_max[1]}}}; + context->module()->AddGlobalValue(MakeUnique( + context.get(), SpvOpConstant, type_int64_id, 52, operands)); + operands = {{SPV_OPERAND_TYPE_LITERAL_INTEGER, {1}}}; + context->module()->AddGlobalValue(MakeUnique( + context.get(), SpvOpConstant, type_uint32_id, 53, operands)); + operands = {{SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_uint64_1[0]}}, + {SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_uint64_1[1]}}}; + context->module()->AddGlobalValue(MakeUnique( + context.get(), SpvOpConstant, type_uint64_id, 54, operands)); + operands = {{SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_uint64_max[0]}}, + {SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_uint64_max[1]}}}; + context->module()->AddGlobalValue(MakeUnique( + context.get(), SpvOpConstant, type_uint64_id, 55, operands)); + operands = {{SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_float_10[0]}}}; + context->module()->AddGlobalValue(MakeUnique( + context.get(), SpvOpConstant, type_float_id, 56, operands)); + operands = {{SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_double_10[0]}}, + {SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_double_10[1]}}}; + context->module()->AddGlobalValue(MakeUnique( + context.get(), SpvOpConstant, type_double_id, 57, operands)); + operands = {{SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_double_20[0]}}, + {SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_double_20[1]}}}; + context->module()->AddGlobalValue(MakeUnique( + context.get(), SpvOpConstant, type_double_id, 58, operands)); + + // A duplicate of the constant with id 59. + operands = {{SPV_OPERAND_TYPE_LITERAL_INTEGER, {1}}}; + context->module()->AddGlobalValue(MakeUnique( + context.get(), SpvOpConstant, type_int32_id, 59, operands)); + + context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone); + + // Constants 1 and int32_min are available. + ASSERT_EQ(2, fact_manager + .GetConstantsAvailableFromUniformsForType(context.get(), + type_int32_id) + .size()); + // Constant int64_max is available. + ASSERT_EQ(1, fact_manager + .GetConstantsAvailableFromUniformsForType(context.get(), + type_int64_id) + .size()); + // Constant 1u is available. + ASSERT_EQ(1, fact_manager + .GetConstantsAvailableFromUniformsForType(context.get(), + type_uint32_id) + .size()); + // Constants 1u and uint64_max are available. + ASSERT_EQ(2, fact_manager + .GetConstantsAvailableFromUniformsForType(context.get(), + type_uint64_id) + .size()); + // Constant 10.0 is available. + ASSERT_EQ(1, fact_manager + .GetConstantsAvailableFromUniformsForType(context.get(), + type_float_id) + .size()); + // Constants 10.0 and 20.0 are available. + ASSERT_EQ(2, fact_manager + .GetConstantsAvailableFromUniformsForType(context.get(), + type_double_id) + .size()); + + ASSERT_EQ(std::numeric_limits::max(), + context->get_constant_mgr() + ->FindDeclaredConstant( + fact_manager.GetConstantsAvailableFromUniformsForType( + context.get(), type_int64_id)[0]) + ->AsIntConstant() + ->GetS64()); + ASSERT_EQ(1, context->get_constant_mgr() + ->FindDeclaredConstant( + fact_manager.GetConstantsAvailableFromUniformsForType( + context.get(), type_uint32_id)[0]) + ->AsIntConstant() + ->GetU32()); + ASSERT_EQ(10.0f, + context->get_constant_mgr() + ->FindDeclaredConstant( + fact_manager.GetConstantsAvailableFromUniformsForType( + context.get(), type_float_id)[0]) + ->AsFloatConstant() + ->GetFloat()); + const std::vector& double_constant_ids = + fact_manager.GetConstantsAvailableFromUniformsForType(context.get(), + type_double_id); + ASSERT_EQ(10.0, context->get_constant_mgr() + ->FindDeclaredConstant(double_constant_ids[0]) + ->AsFloatConstant() + ->GetDouble()); + ASSERT_EQ(20.0, context->get_constant_mgr() + ->FindDeclaredConstant(double_constant_ids[1]) + ->AsFloatConstant() + ->GetDouble()); + + const std::vector + descriptors_for_double_10 = fact_manager.GetUniformDescriptorsForConstant( + context.get(), double_constant_ids[0]); + ASSERT_EQ(2, descriptors_for_double_10.size()); + { + auto temp = MakeUniformBufferElementDescriptor(2, 2, {9, 9, 1}); + ASSERT_TRUE(UniformBufferElementDescriptorEquals()( + &temp, &descriptors_for_double_10[0])); + } + { + auto temp = MakeUniformBufferElementDescriptor(2, 3, {9, 9, 2}); + ASSERT_TRUE(UniformBufferElementDescriptorEquals()( + &temp, &descriptors_for_double_10[1])); + } + const std::vector + descriptors_for_double_20 = fact_manager.GetUniformDescriptorsForConstant( + context.get(), double_constant_ids[1]); + ASSERT_EQ(1, descriptors_for_double_20.size()); + { + auto temp = MakeUniformBufferElementDescriptor(2, 4, {0, 0, 0, 0, 0}); + ASSERT_TRUE(UniformBufferElementDescriptorEquals()( + &temp, &descriptors_for_double_20[0])); + } + + auto constant_1_id = fact_manager.GetConstantFromUniformDescriptor( + context.get(), MakeUniformBufferElementDescriptor(2, 3, {9, 9, 2})); + ASSERT_TRUE(constant_1_id); + + auto constant_2_id = fact_manager.GetConstantFromUniformDescriptor( + context.get(), MakeUniformBufferElementDescriptor(2, 4, {0, 0, 0, 0, 0})); + ASSERT_TRUE(constant_2_id); + + ASSERT_EQ(double_constant_ids[0], constant_1_id); + + ASSERT_EQ(double_constant_ids[1], constant_2_id); +} + +TEST(FactManagerTest, TwoConstantsWithSameValue) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %8 "x" + OpName %10 "buf" + OpMemberName %10 0 "a" + OpName %12 "" + OpDecorate %8 RelaxedPrecision + OpMemberDecorate %10 0 RelaxedPrecision + OpMemberDecorate %10 0 Offset 0 + OpDecorate %10 Block + OpDecorate %12 DescriptorSet 0 + OpDecorate %12 Binding 0 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 1 + %20 = OpConstant %6 1 + %10 = OpTypeStruct %6 + %11 = OpTypePointer Uniform %10 + %12 = OpVariable %11 Uniform + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + OpStore %8 %9 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + auto uniform_buffer_element_descriptor = + MakeUniformBufferElementDescriptor(0, 0, {0}); + + // (0, 0, [0]) = int(1) + ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), {1}, + uniform_buffer_element_descriptor)); + auto constants = + fact_manager.GetConstantsAvailableFromUniformsForType(context.get(), 6); + ASSERT_EQ(1, constants.size()); + ASSERT_TRUE(constants[0] == 9 || constants[0] == 20); + + auto constant = fact_manager.GetConstantFromUniformDescriptor( + context.get(), uniform_buffer_element_descriptor); + ASSERT_TRUE(constant == 9 || constant == 20); + + // Because the constants with ids 9 and 20 are equal, we should get the same + // single uniform buffer element descriptor when we look up the descriptors + // for either one of them. + for (auto constant_id : {9u, 20u}) { + auto descriptors = fact_manager.GetUniformDescriptorsForConstant( + context.get(), constant_id); + ASSERT_EQ(1, descriptors.size()); + ASSERT_TRUE(UniformBufferElementDescriptorEquals()( + &uniform_buffer_element_descriptor, &descriptors[0])); + } +} + +TEST(FactManagerTest, NonFiniteFactsAreNotValid) { + std::string shader = R"( + OpCapability Shader + OpCapability Float64 + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %7 "buf" + OpMemberName %7 0 "f" + OpMemberName %7 1 "d" + OpName %9 "" + OpMemberDecorate %7 0 Offset 0 + OpMemberDecorate %7 1 Offset 8 + OpDecorate %7 Block + OpDecorate %9 DescriptorSet 0 + OpDecorate %9 Binding 0 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %10 = OpTypeFloat 64 + %7 = OpTypeStruct %6 %10 + %8 = OpTypePointer Uniform %7 + %9 = OpVariable %8 Uniform + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + auto uniform_buffer_element_descriptor_f = + MakeUniformBufferElementDescriptor(0, 0, {0}); + + auto uniform_buffer_element_descriptor_d = + MakeUniformBufferElementDescriptor(0, 0, {1}); + + if (std::numeric_limits::has_infinity) { + // f == +inf + float positive_infinity_float = std::numeric_limits::infinity(); + uint32_t words[1]; + memcpy(words, &positive_infinity_float, sizeof(float)); + ASSERT_FALSE(AddFactHelper(&fact_manager, context.get(), {words[0]}, + uniform_buffer_element_descriptor_f)); + // f == -inf + float negative_infinity_float = std::numeric_limits::infinity(); + memcpy(words, &negative_infinity_float, sizeof(float)); + ASSERT_FALSE(AddFactHelper(&fact_manager, context.get(), {words[0]}, + uniform_buffer_element_descriptor_f)); + } + + if (std::numeric_limits::has_quiet_NaN) { + // f == NaN + float quiet_nan_float = std::numeric_limits::quiet_NaN(); + uint32_t words[1]; + memcpy(words, &quiet_nan_float, sizeof(float)); + ASSERT_FALSE(AddFactHelper(&fact_manager, context.get(), {words[0]}, + uniform_buffer_element_descriptor_f)); + } + + if (std::numeric_limits::has_infinity) { + // d == +inf + double positive_infinity_double = std::numeric_limits::infinity(); + uint32_t words[2]; + memcpy(words, &positive_infinity_double, sizeof(double)); + ASSERT_FALSE(AddFactHelper(&fact_manager, context.get(), + {words[0], words[1]}, + uniform_buffer_element_descriptor_d)); + // d == -inf + double negative_infinity_double = -std::numeric_limits::infinity(); + memcpy(words, &negative_infinity_double, sizeof(double)); + ASSERT_FALSE(AddFactHelper(&fact_manager, context.get(), + {words[0], words[1]}, + uniform_buffer_element_descriptor_d)); + } + + if (std::numeric_limits::has_quiet_NaN) { + // d == NaN + double quiet_nan_double = std::numeric_limits::quiet_NaN(); + uint32_t words[2]; + memcpy(words, &quiet_nan_double, sizeof(double)); + ASSERT_FALSE(AddFactHelper(&fact_manager, context.get(), + {words[0], words[1]}, + uniform_buffer_element_descriptor_d)); + } +} + +TEST(FactManagerTest, AmbiguousFact) { + // This test came from the following GLSL: + // + // #version 310 es + // + // precision highp float; + // + // layout(set = 0, binding = 0) uniform buf { + // float f; + // }; + // + // layout(set = 0, binding = 0) uniform buf2 { + // float g; + // }; + // + // void main() { + // + // } + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %7 "buf" + OpMemberName %7 0 "f" + OpName %9 "" + OpName %10 "buf2" + OpMemberName %10 0 "g" + OpName %12 "" + OpMemberDecorate %7 0 Offset 0 + OpDecorate %7 Block + OpDecorate %9 DescriptorSet 0 + OpDecorate %9 Binding 0 + OpMemberDecorate %10 0 Offset 0 + OpDecorate %10 Block + OpDecorate %12 DescriptorSet 0 + OpDecorate %12 Binding 0 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypeStruct %6 + %8 = OpTypePointer Uniform %7 + %9 = OpVariable %8 Uniform + %10 = OpTypeStruct %6 + %11 = OpTypePointer Uniform %10 + %12 = OpVariable %11 Uniform + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + auto uniform_buffer_element_descriptor = + MakeUniformBufferElementDescriptor(0, 0, {0}); + + // The fact cannot be added because it is ambiguous: there are two uniforms + // with descriptor set 0 and binding 0. + ASSERT_FALSE(AddFactHelper(&fact_manager, context.get(), {1}, + uniform_buffer_element_descriptor)); +} + +TEST(FactManagerTest, DataSynonymFacts) { + // The SPIR-V types and constants come from the following code. The body of + // the SPIR-V function then constructs a composite that is synonymous with + // myT. + // + // #version 310 es + // + // precision highp float; + // + // struct S { + // int a; + // uvec2 b; + // }; + // + // struct T { + // bool c[5]; + // mat4x2 d; + // S e; + // }; + // + // void main() { + // T myT = T(bool[5](true, false, true, false, true), + // mat4x2(vec2(1.0, 2.0), vec2(3.0, 4.0), + // vec2(5.0, 6.0), vec2(7.0, 8.0)), + // S(10, uvec2(100u, 200u))); + // } + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %15 "S" + OpMemberName %15 0 "a" + OpMemberName %15 1 "b" + OpName %16 "T" + OpMemberName %16 0 "c" + OpMemberName %16 1 "d" + OpMemberName %16 2 "e" + OpName %18 "myT" + OpMemberDecorate %15 0 RelaxedPrecision + OpMemberDecorate %15 1 RelaxedPrecision + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeBool + %7 = OpTypeInt 32 0 + %8 = OpConstant %7 5 + %9 = OpTypeArray %6 %8 + %10 = OpTypeFloat 32 + %11 = OpTypeVector %10 2 + %12 = OpTypeMatrix %11 4 + %13 = OpTypeInt 32 1 + %14 = OpTypeVector %7 2 + %15 = OpTypeStruct %13 %14 + %16 = OpTypeStruct %9 %12 %15 + %17 = OpTypePointer Function %16 + %19 = OpConstantTrue %6 + %20 = OpConstantFalse %6 + %21 = OpConstantComposite %9 %19 %20 %19 %20 %19 + %22 = OpConstant %10 1 + %23 = OpConstant %10 2 + %24 = OpConstantComposite %11 %22 %23 + %25 = OpConstant %10 3 + %26 = OpConstant %10 4 + %27 = OpConstantComposite %11 %25 %26 + %28 = OpConstant %10 5 + %29 = OpConstant %10 6 + %30 = OpConstantComposite %11 %28 %29 + %31 = OpConstant %10 7 + %32 = OpConstant %10 8 + %33 = OpConstantComposite %11 %31 %32 + %34 = OpConstantComposite %12 %24 %27 %30 %33 + %35 = OpConstant %13 10 + %36 = OpConstant %7 100 + %37 = OpConstant %7 200 + %38 = OpConstantComposite %14 %36 %37 + %39 = OpConstantComposite %15 %35 %38 + %40 = OpConstantComposite %16 %21 %34 %39 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %18 = OpVariable %17 Function + OpStore %18 %40 + %100 = OpCompositeConstruct %9 %19 %20 %19 %20 %19 + %101 = OpCompositeConstruct %11 %22 %23 + %102 = OpCompositeConstruct %11 %25 %26 + %103 = OpCompositeConstruct %11 %28 %29 + %104 = OpCompositeConstruct %11 %31 %32 + %105 = OpCompositeConstruct %12 %101 %102 %103 %104 + %106 = OpCompositeConstruct %14 %36 %37 + %107 = OpCompositeConstruct %15 %35 %106 + %108 = OpCompositeConstruct %16 %100 %105 %107 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + ASSERT_FALSE(fact_manager.IsSynonymous( + MakeDataDescriptor(24, {}), MakeDataDescriptor(101, {}), context.get())); + ASSERT_FALSE(fact_manager.IsSynonymous(MakeDataDescriptor(24, {0}), + MakeDataDescriptor(101, {0}), + context.get())); + ASSERT_FALSE(fact_manager.IsSynonymous(MakeDataDescriptor(24, {1}), + MakeDataDescriptor(101, {1}), + context.get())); + ASSERT_FALSE(fact_manager.IsSynonymous(MakeDataDescriptor(24, {0}), + MakeDataDescriptor(101, {1}), + context.get())); + + fact_manager.AddFactDataSynonym(MakeDataDescriptor(24, {}), + MakeDataDescriptor(101, {}), context.get()); + ASSERT_TRUE(fact_manager.IsSynonymous( + MakeDataDescriptor(24, {}), MakeDataDescriptor(101, {}), context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(24, {0}), + MakeDataDescriptor(101, {0}), + context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(24, {1}), + MakeDataDescriptor(101, {1}), + context.get())); + ASSERT_FALSE(fact_manager.IsSynonymous(MakeDataDescriptor(24, {0}), + MakeDataDescriptor(101, {1}), + context.get())); + + ASSERT_FALSE(fact_manager.IsSynonymous( + MakeDataDescriptor(27, {}), MakeDataDescriptor(102, {}), context.get())); + ASSERT_FALSE(fact_manager.IsSynonymous(MakeDataDescriptor(27, {0}), + MakeDataDescriptor(102, {0}), + context.get())); + ASSERT_FALSE(fact_manager.IsSynonymous(MakeDataDescriptor(27, {1}), + MakeDataDescriptor(102, {1}), + context.get())); + fact_manager.AddFactDataSynonym(MakeDataDescriptor(27, {0}), + MakeDataDescriptor(102, {0}), context.get()); + ASSERT_FALSE(fact_manager.IsSynonymous( + MakeDataDescriptor(27, {}), MakeDataDescriptor(102, {}), context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(27, {0}), + MakeDataDescriptor(102, {0}), + context.get())); + ASSERT_FALSE(fact_manager.IsSynonymous(MakeDataDescriptor(27, {1}), + MakeDataDescriptor(102, {1}), + context.get())); + fact_manager.AddFactDataSynonym(MakeDataDescriptor(27, {1}), + MakeDataDescriptor(102, {1}), context.get()); + ASSERT_TRUE(fact_manager.IsSynonymous( + MakeDataDescriptor(27, {}), MakeDataDescriptor(102, {}), context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(27, {0}), + MakeDataDescriptor(102, {0}), + context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(27, {1}), + MakeDataDescriptor(102, {1}), + context.get())); + + ASSERT_FALSE(fact_manager.IsSynonymous( + MakeDataDescriptor(30, {}), MakeDataDescriptor(103, {}), context.get())); + ASSERT_FALSE(fact_manager.IsSynonymous(MakeDataDescriptor(30, {0}), + MakeDataDescriptor(103, {0}), + context.get())); + ASSERT_FALSE(fact_manager.IsSynonymous(MakeDataDescriptor(30, {1}), + MakeDataDescriptor(103, {1}), + context.get())); + ASSERT_FALSE(fact_manager.IsSynonymous( + MakeDataDescriptor(33, {}), MakeDataDescriptor(104, {}), context.get())); + ASSERT_FALSE(fact_manager.IsSynonymous(MakeDataDescriptor(33, {0}), + MakeDataDescriptor(104, {0}), + context.get())); + ASSERT_FALSE(fact_manager.IsSynonymous(MakeDataDescriptor(33, {1}), + MakeDataDescriptor(104, {1}), + context.get())); + ASSERT_FALSE(fact_manager.IsSynonymous( + MakeDataDescriptor(34, {}), MakeDataDescriptor(105, {}), context.get())); + ASSERT_FALSE(fact_manager.IsSynonymous(MakeDataDescriptor(34, {0}), + MakeDataDescriptor(105, {0}), + context.get())); + ASSERT_FALSE(fact_manager.IsSynonymous(MakeDataDescriptor(34, {1}), + MakeDataDescriptor(105, {1}), + context.get())); + ASSERT_FALSE(fact_manager.IsSynonymous(MakeDataDescriptor(34, {2}), + MakeDataDescriptor(105, {2}), + context.get())); + ASSERT_FALSE(fact_manager.IsSynonymous(MakeDataDescriptor(34, {3}), + MakeDataDescriptor(105, {3}), + context.get())); + fact_manager.AddFactDataSynonym(MakeDataDescriptor(30, {}), + MakeDataDescriptor(103, {}), context.get()); + fact_manager.AddFactDataSynonym(MakeDataDescriptor(33, {}), + MakeDataDescriptor(104, {}), context.get()); + fact_manager.AddFactDataSynonym(MakeDataDescriptor(34, {0}), + MakeDataDescriptor(105, {0}), context.get()); + fact_manager.AddFactDataSynonym(MakeDataDescriptor(34, {1}), + MakeDataDescriptor(105, {1}), context.get()); + fact_manager.AddFactDataSynonym(MakeDataDescriptor(34, {2}), + MakeDataDescriptor(105, {2}), context.get()); + ASSERT_TRUE(fact_manager.IsSynonymous( + MakeDataDescriptor(30, {}), MakeDataDescriptor(103, {}), context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(30, {0}), + MakeDataDescriptor(103, {0}), + context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(30, {1}), + MakeDataDescriptor(103, {1}), + context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous( + MakeDataDescriptor(33, {}), MakeDataDescriptor(104, {}), context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(33, {0}), + MakeDataDescriptor(104, {0}), + context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(33, {1}), + MakeDataDescriptor(104, {1}), + context.get())); + ASSERT_FALSE(fact_manager.IsSynonymous( + MakeDataDescriptor(34, {}), MakeDataDescriptor(105, {}), context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(34, {0}), + MakeDataDescriptor(105, {0}), + context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(34, {1}), + MakeDataDescriptor(105, {1}), + context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(34, {2}), + MakeDataDescriptor(105, {2}), + context.get())); + ASSERT_FALSE(fact_manager.IsSynonymous(MakeDataDescriptor(34, {3}), + MakeDataDescriptor(105, {3}), + context.get())); + + fact_manager.AddFactDataSynonym(MakeDataDescriptor(34, {3}), + MakeDataDescriptor(105, {3}), context.get()); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(33, {0}), + MakeDataDescriptor(104, {0}), + context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(34, {3}), + MakeDataDescriptor(105, {3}), + context.get())); + + ASSERT_FALSE(fact_manager.IsSynonymous( + MakeDataDescriptor(21, {}), MakeDataDescriptor(100, {}), context.get())); + fact_manager.AddFactDataSynonym(MakeDataDescriptor(21, {0}), + MakeDataDescriptor(100, {0}), context.get()); + fact_manager.AddFactDataSynonym(MakeDataDescriptor(21, {1}), + MakeDataDescriptor(100, {1}), context.get()); + fact_manager.AddFactDataSynonym(MakeDataDescriptor(21, {2}), + MakeDataDescriptor(100, {2}), context.get()); + fact_manager.AddFactDataSynonym(MakeDataDescriptor(21, {3}), + MakeDataDescriptor(100, {3}), context.get()); + fact_manager.AddFactDataSynonym(MakeDataDescriptor(21, {4}), + MakeDataDescriptor(100, {4}), context.get()); + ASSERT_TRUE(fact_manager.IsSynonymous( + MakeDataDescriptor(21, {}), MakeDataDescriptor(100, {}), context.get())); + + ASSERT_FALSE(fact_manager.IsSynonymous(MakeDataDescriptor(39, {0}), + MakeDataDescriptor(107, {0}), + context.get())); + ASSERT_FALSE(fact_manager.IsSynonymous( + MakeDataDescriptor(35, {}), MakeDataDescriptor(39, {0}), context.get())); + fact_manager.AddFactDataSynonym(MakeDataDescriptor(39, {0}), + MakeDataDescriptor(35, {}), context.get()); + ASSERT_FALSE(fact_manager.IsSynonymous(MakeDataDescriptor(39, {0}), + MakeDataDescriptor(107, {0}), + context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous( + MakeDataDescriptor(35, {}), MakeDataDescriptor(39, {0}), context.get())); + + ASSERT_FALSE(fact_manager.IsSynonymous( + MakeDataDescriptor(38, {0}), MakeDataDescriptor(36, {}), context.get())); + ASSERT_FALSE(fact_manager.IsSynonymous( + MakeDataDescriptor(38, {1}), MakeDataDescriptor(37, {}), context.get())); + ASSERT_FALSE(fact_manager.IsSynonymous( + MakeDataDescriptor(106, {0}), MakeDataDescriptor(36, {}), context.get())); + ASSERT_FALSE(fact_manager.IsSynonymous( + MakeDataDescriptor(106, {1}), MakeDataDescriptor(37, {}), context.get())); + ASSERT_FALSE(fact_manager.IsSynonymous( + MakeDataDescriptor(38, {}), MakeDataDescriptor(106, {}), context.get())); + fact_manager.AddFactDataSynonym(MakeDataDescriptor(38, {0}), + MakeDataDescriptor(36, {}), context.get()); + fact_manager.AddFactDataSynonym(MakeDataDescriptor(106, {0}), + MakeDataDescriptor(36, {}), context.get()); + fact_manager.AddFactDataSynonym(MakeDataDescriptor(38, {1}), + MakeDataDescriptor(37, {}), context.get()); + fact_manager.AddFactDataSynonym(MakeDataDescriptor(106, {1}), + MakeDataDescriptor(37, {}), context.get()); + ASSERT_TRUE(fact_manager.IsSynonymous( + MakeDataDescriptor(38, {0}), MakeDataDescriptor(36, {}), context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous( + MakeDataDescriptor(38, {1}), MakeDataDescriptor(37, {}), context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous( + MakeDataDescriptor(106, {0}), MakeDataDescriptor(36, {}), context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous( + MakeDataDescriptor(106, {1}), MakeDataDescriptor(37, {}), context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous( + MakeDataDescriptor(38, {}), MakeDataDescriptor(106, {}), context.get())); + + ASSERT_FALSE(fact_manager.IsSynonymous( + MakeDataDescriptor(40, {}), MakeDataDescriptor(108, {}), context.get())); + fact_manager.AddFactDataSynonym(MakeDataDescriptor(107, {0}), + MakeDataDescriptor(35, {}), context.get()); + fact_manager.AddFactDataSynonym(MakeDataDescriptor(40, {0}), + MakeDataDescriptor(108, {0}), context.get()); + fact_manager.AddFactDataSynonym(MakeDataDescriptor(40, {1}), + MakeDataDescriptor(108, {1}), context.get()); + fact_manager.AddFactDataSynonym(MakeDataDescriptor(40, {2}), + MakeDataDescriptor(108, {2}), context.get()); + ASSERT_TRUE(fact_manager.IsSynonymous( + MakeDataDescriptor(40, {}), MakeDataDescriptor(108, {}), context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {0}), + MakeDataDescriptor(108, {0}), + context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {1}), + MakeDataDescriptor(108, {1}), + context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {2}), + MakeDataDescriptor(108, {2}), + context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {0, 0}), + MakeDataDescriptor(108, {0, 0}), + context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {0, 1}), + MakeDataDescriptor(108, {0, 1}), + context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {0, 2}), + MakeDataDescriptor(108, {0, 2}), + context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {0, 3}), + MakeDataDescriptor(108, {0, 3}), + context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {0, 4}), + MakeDataDescriptor(108, {0, 4}), + context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {1, 0}), + MakeDataDescriptor(108, {1, 0}), + context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {1, 1}), + MakeDataDescriptor(108, {1, 1}), + context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {1, 2}), + MakeDataDescriptor(108, {1, 2}), + context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {1, 3}), + MakeDataDescriptor(108, {1, 3}), + context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {1, 0, 0}), + MakeDataDescriptor(108, {1, 0, 0}), + context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {1, 1, 0}), + MakeDataDescriptor(108, {1, 1, 0}), + context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {1, 2, 0}), + MakeDataDescriptor(108, {1, 2, 0}), + context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {1, 3, 0}), + MakeDataDescriptor(108, {1, 3, 0}), + context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {1, 0, 1}), + MakeDataDescriptor(108, {1, 0, 1}), + context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {1, 1, 1}), + MakeDataDescriptor(108, {1, 1, 1}), + context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {1, 2, 1}), + MakeDataDescriptor(108, {1, 2, 1}), + context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {1, 3, 1}), + MakeDataDescriptor(108, {1, 3, 1}), + context.get())); + + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {2, 0}), + MakeDataDescriptor(108, {2, 0}), + context.get())); + + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {2, 1}), + MakeDataDescriptor(108, {2, 1}), + context.get())); + + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {2, 1, 0}), + MakeDataDescriptor(108, {2, 1, 0}), + context.get())); + + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {2, 1, 1}), + MakeDataDescriptor(108, {2, 1, 1}), + context.get())); +} + +TEST(FactManagerTest, RecursiveAdditionOfFacts) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %12 "main" + OpExecutionMode %12 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypeVector %6 4 + %8 = OpTypeMatrix %7 4 + %9 = OpConstant %6 0 + %10 = OpConstantComposite %7 %9 %9 %9 %9 + %11 = OpConstantComposite %8 %10 %10 %10 %10 + %12 = OpFunction %2 None %3 + %13 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + fact_manager.AddFactDataSynonym(MakeDataDescriptor(10, {}), + MakeDataDescriptor(11, {2}), context.get()); + + ASSERT_TRUE(fact_manager.IsSynonymous( + MakeDataDescriptor(10, {}), MakeDataDescriptor(11, {2}), context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(10, {0}), + MakeDataDescriptor(11, {2, 0}), + context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(10, {1}), + MakeDataDescriptor(11, {2, 1}), + context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(10, {2}), + MakeDataDescriptor(11, {2, 2}), + context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(10, {3}), + MakeDataDescriptor(11, {2, 3}), + context.get())); +} + +} // namespace +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/test/fuzz/fuzz_test_util.cpp b/third_party/spirv-tools/test/fuzz/fuzz_test_util.cpp new file mode 100644 index 0000000000..c717961aa1 --- /dev/null +++ b/third_party/spirv-tools/test/fuzz/fuzz_test_util.cpp @@ -0,0 +1,126 @@ +// Copyright (c) 2019 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 "test/fuzz/fuzz_test_util.h" + +#include +#include + +#include "tools/io.h" + +namespace spvtools { +namespace fuzz { + +bool IsEqual(const spv_target_env env, + const std::vector& expected_binary, + const std::vector& actual_binary) { + if (expected_binary == actual_binary) { + return true; + } + SpirvTools t(env); + std::string expected_disassembled; + std::string actual_disassembled; + if (!t.Disassemble(expected_binary, &expected_disassembled, + kFuzzDisassembleOption)) { + return false; + } + if (!t.Disassemble(actual_binary, &actual_disassembled, + kFuzzDisassembleOption)) { + return false; + } + // Using expect gives us a string diff if the strings are not the same. + EXPECT_EQ(expected_disassembled, actual_disassembled); + // We then return the result of the equality comparison, to be used by an + // assertion in the test root function. + return expected_disassembled == actual_disassembled; +} + +bool IsEqual(const spv_target_env env, const std::string& expected_text, + const std::vector& actual_binary) { + std::vector expected_binary; + SpirvTools t(env); + if (!t.Assemble(expected_text, &expected_binary, kFuzzAssembleOption)) { + return false; + } + return IsEqual(env, expected_binary, actual_binary); +} + +bool IsEqual(const spv_target_env env, const std::string& expected_text, + const opt::IRContext* actual_ir) { + std::vector actual_binary; + actual_ir->module()->ToBinary(&actual_binary, false); + return IsEqual(env, expected_text, actual_binary); +} + +bool IsEqual(const spv_target_env env, const opt::IRContext* ir_1, + const opt::IRContext* ir_2) { + std::vector binary_1; + ir_1->module()->ToBinary(&binary_1, false); + std::vector binary_2; + ir_2->module()->ToBinary(&binary_2, false); + return IsEqual(env, binary_1, binary_2); +} + +bool IsValid(spv_target_env env, const opt::IRContext* ir) { + std::vector binary; + ir->module()->ToBinary(&binary, false); + SpirvTools t(env); + t.SetMessageConsumer(kConsoleMessageConsumer); + return t.Validate(binary); +} + +std::string ToString(spv_target_env env, const opt::IRContext* ir) { + std::vector binary; + ir->module()->ToBinary(&binary, false); + return ToString(env, binary); +} + +std::string ToString(spv_target_env env, const std::vector& binary) { + SpirvTools t(env); + std::string result; + t.Disassemble(binary, &result, kFuzzDisassembleOption); + return result; +} + +void DumpShader(opt::IRContext* context, const char* filename) { + std::vector binary; + context->module()->ToBinary(&binary, false); + DumpShader(binary, filename); +} + +void DumpShader(const std::vector& binary, const char* filename) { + auto write_file_succeeded = + WriteFile(filename, "wb", &binary[0], binary.size()); + if (!write_file_succeeded) { + std::cerr << "Failed to dump shader" << std::endl; + } +} + +void DumpTransformationsJson( + const protobufs::TransformationSequence& transformations, + const char* filename) { + std::string json_string; + auto json_options = google::protobuf::util::JsonOptions(); + json_options.add_whitespace = true; + auto json_generation_status = google::protobuf::util::MessageToJsonString( + transformations, &json_string, json_options); + if (json_generation_status == google::protobuf::util::Status::OK) { + std::ofstream transformations_json_file(filename); + transformations_json_file << json_string; + transformations_json_file.close(); + } +} + +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/test/fuzz/fuzz_test_util.h b/third_party/spirv-tools/test/fuzz/fuzz_test_util.h new file mode 100644 index 0000000000..9e08bf6891 --- /dev/null +++ b/third_party/spirv-tools/test/fuzz/fuzz_test_util.h @@ -0,0 +1,113 @@ +// Copyright (c) 2019 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 TEST_FUZZ_FUZZ_TEST_UTIL_H_ +#define TEST_FUZZ_FUZZ_TEST_UTIL_H_ + +#include "gtest/gtest.h" + +#include + +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "source/opt/build_module.h" +#include "source/opt/ir_context.h" +#include "spirv-tools/libspirv.h" + +namespace spvtools { +namespace fuzz { + +// Returns true if and only if the given binaries are bit-wise equal. +bool IsEqual(spv_target_env env, const std::vector& expected_binary, + const std::vector& actual_binary); + +// Assembles the given text and returns true if and only if the resulting binary +// is bit-wise equal to the given binary. +bool IsEqual(spv_target_env env, const std::string& expected_text, + const std::vector& actual_binary); + +// Assembles the given text and turns the given IR into binary, then returns +// true if and only if the resulting binaries are bit-wise equal. +bool IsEqual(spv_target_env env, const std::string& expected_text, + const opt::IRContext* actual_ir); + +// Turns the given IRs into binaries, then returns true if and only if the +// resulting binaries are bit-wise equal. +bool IsEqual(spv_target_env env, const opt::IRContext* ir_1, + const opt::IRContext* ir_2); + +// Assembles the given IR context and returns true if and only if +// the resulting binary is valid. +bool IsValid(spv_target_env env, const opt::IRContext* ir); + +// Assembles the given IR context, then returns its disassembly as a string. +// Useful for debugging. +std::string ToString(spv_target_env env, const opt::IRContext* ir); + +// Returns the disassembly of the given binary as a string. +// Useful for debugging. +std::string ToString(spv_target_env env, const std::vector& binary); + +// Assembly options for writing fuzzer tests. It simplifies matters if +// numeric ids do not change. +const uint32_t kFuzzAssembleOption = + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS; +// Disassembly options for writing fuzzer tests. +const uint32_t kFuzzDisassembleOption = + SPV_BINARY_TO_TEXT_OPTION_NO_HEADER | SPV_BINARY_TO_TEXT_OPTION_INDENT; + +// A silent message consumer. +const spvtools::MessageConsumer kSilentConsumer = + [](spv_message_level_t, const char*, const spv_position_t&, + const char*) -> void {}; + +const spvtools::MessageConsumer kConsoleMessageConsumer = + [](spv_message_level_t level, const char*, const spv_position_t& position, + const char* message) -> void { + switch (level) { + case SPV_MSG_FATAL: + case SPV_MSG_INTERNAL_ERROR: + case SPV_MSG_ERROR: + std::cerr << "error: line " << position.index << ": " << message + << std::endl; + break; + case SPV_MSG_WARNING: + std::cout << "warning: line " << position.index << ": " << message + << std::endl; + break; + case SPV_MSG_INFO: + std::cout << "info: line " << position.index << ": " << message + << std::endl; + break; + default: + break; + } +}; + +// Dumps the SPIRV-V module in |context| to file |filename|. Useful for +// interactive debugging. +void DumpShader(opt::IRContext* context, const char* filename); + +// Dumps |binary| to file |filename|. Useful for interactive debugging. +void DumpShader(const std::vector& binary, const char* filename); + +// Dumps |transformations| to file |filename| in JSON format. Useful for +// interactive debugging. +void DumpTransformationsJson( + const protobufs::TransformationSequence& transformations, + const char* filename); + +} // namespace fuzz +} // namespace spvtools + +#endif // TEST_FUZZ_FUZZ_TEST_UTIL_H_ diff --git a/third_party/spirv-tools/test/fuzz/fuzzer_pass_add_useful_constructs_test.cpp b/third_party/spirv-tools/test/fuzz/fuzzer_pass_add_useful_constructs_test.cpp new file mode 100644 index 0000000000..89f006e078 --- /dev/null +++ b/third_party/spirv-tools/test/fuzz/fuzzer_pass_add_useful_constructs_test.cpp @@ -0,0 +1,393 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/fuzzer_pass_add_useful_constructs.h" +#include "source/fuzz/pseudo_random_generator.h" +#include "source/fuzz/uniform_buffer_element_descriptor.h" +#include "test/fuzz/fuzz_test_util.h" + +namespace spvtools { +namespace fuzz { +namespace { + +bool AddFactHelper( + FactManager* fact_manager, opt::IRContext* context, uint32_t word, + const protobufs::UniformBufferElementDescriptor& descriptor) { + protobufs::FactConstantUniform constant_uniform_fact; + constant_uniform_fact.add_constant_word(word); + *constant_uniform_fact.mutable_uniform_buffer_element_descriptor() = + descriptor; + protobufs::Fact fact; + *fact.mutable_constant_uniform_fact() = constant_uniform_fact; + return fact_manager->AddFact(fact, context); +} + +TEST(FuzzerPassAddUsefulConstructsTest, CheckBasicStuffIsAdded) { + // The SPIR-V came from the following empty GLSL shader: + // + // #version 450 + // + // void main() + // { + // } + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource GLSL 450 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + FuzzerContext fuzzer_context(MakeUnique(0).get(), 100); + protobufs::TransformationSequence transformation_sequence; + + FuzzerPassAddUsefulConstructs pass(context.get(), &fact_manager, + &fuzzer_context, &transformation_sequence); + pass.Apply(); + ASSERT_TRUE(IsValid(env, context.get())); + + std::string after = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource GLSL 450 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %100 = OpTypeBool + %101 = OpTypeInt 32 1 + %102 = OpTypeInt 32 0 + %103 = OpTypeFloat 32 + %104 = OpConstantTrue %100 + %105 = OpConstantFalse %100 + %106 = OpConstant %101 0 + %107 = OpConstant %101 1 + %108 = OpConstant %102 0 + %109 = OpConstant %102 1 + %110 = OpConstant %103 0 + %111 = OpConstant %103 1 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after, context.get())); +} + +TEST(FuzzerPassAddUsefulConstructsTest, + CheckTypesIndicesAndConstantsAddedForUniformFacts) { + // The SPIR-V came from the following GLSL shader: + // + // #version 450 + // + // struct S { + // int x; + // float y; + // int z; + // int w; + // }; + // + // uniform buf { + // S s; + // uint w[10]; + // }; + // + // void main() { + // } + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource GLSL 450 + OpName %4 "main" + OpName %8 "S" + OpMemberName %8 0 "x" + OpMemberName %8 1 "y" + OpMemberName %8 2 "z" + OpMemberName %8 3 "w" + OpName %12 "buf" + OpMemberName %12 0 "s" + OpMemberName %12 1 "w" + OpName %14 "" + OpMemberDecorate %8 0 Offset 0 + OpMemberDecorate %8 1 Offset 4 + OpMemberDecorate %8 2 Offset 8 + OpMemberDecorate %8 3 Offset 12 + OpDecorate %11 ArrayStride 16 + OpMemberDecorate %12 0 Offset 0 + OpMemberDecorate %12 1 Offset 16 + OpDecorate %12 Block + OpDecorate %14 DescriptorSet 0 + OpDecorate %14 Binding 0 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypeFloat 32 + %8 = OpTypeStruct %6 %7 %6 %6 + %9 = OpTypeInt 32 0 + %10 = OpConstant %9 10 + %11 = OpTypeArray %9 %10 + %12 = OpTypeStruct %8 %11 + %13 = OpTypePointer Uniform %12 + %14 = OpVariable %13 Uniform + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + FuzzerContext fuzzer_context(MakeUnique(0).get(), 100); + protobufs::TransformationSequence transformation_sequence; + + // Add some uniform facts. + + // buf.s.x == 200 + ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), 200, + MakeUniformBufferElementDescriptor(0, 0, {0, 0}))); + + // buf.s.y == 0.5 + const float float_value = 0.5; + uint32_t float_value_as_uint; + memcpy(&float_value_as_uint, &float_value, sizeof(float_value)); + ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), float_value_as_uint, + MakeUniformBufferElementDescriptor(0, 0, {0, 1}))); + + // buf.s.z == 300 + ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), 300, + MakeUniformBufferElementDescriptor(0, 0, {0, 2}))); + + // buf.s.w == 400 + ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), 400, + MakeUniformBufferElementDescriptor(0, 0, {0, 3}))); + + // buf.w[6] = 22 + ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), 22, + MakeUniformBufferElementDescriptor(0, 0, {1, 6}))); + + // buf.w[8] = 23 + ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), 23, + MakeUniformBufferElementDescriptor(0, 0, {1, 8}))); + + // Assert some things about the module that are not true prior to adding the + // pass + + { + // No uniform int pointer + opt::analysis::Integer temp_type_signed_int(32, true); + opt::analysis::Integer* registered_type_signed_int = + context->get_type_mgr() + ->GetRegisteredType(&temp_type_signed_int) + ->AsInteger(); + opt::analysis::Pointer type_pointer_uniform_signed_int( + registered_type_signed_int, SpvStorageClassUniform); + ASSERT_EQ(0, + context->get_type_mgr()->GetId(&type_pointer_uniform_signed_int)); + + // No uniform uint pointer + opt::analysis::Integer temp_type_unsigned_int(32, false); + opt::analysis::Integer* registered_type_unsigned_int = + context->get_type_mgr() + ->GetRegisteredType(&temp_type_unsigned_int) + ->AsInteger(); + opt::analysis::Pointer type_pointer_uniform_unsigned_int( + registered_type_unsigned_int, SpvStorageClassUniform); + ASSERT_EQ( + 0, context->get_type_mgr()->GetId(&type_pointer_uniform_unsigned_int)); + + // No uniform float pointer + opt::analysis::Float temp_type_float(32); + opt::analysis::Float* registered_type_float = + context->get_type_mgr()->GetRegisteredType(&temp_type_float)->AsFloat(); + opt::analysis::Pointer type_pointer_uniform_float(registered_type_float, + SpvStorageClassUniform); + ASSERT_EQ(0, context->get_type_mgr()->GetId(&type_pointer_uniform_float)); + + // No int constants 200, 300 nor 400 + opt::analysis::IntConstant int_constant_200(registered_type_signed_int, + {200}); + opt::analysis::IntConstant int_constant_300(registered_type_signed_int, + {300}); + opt::analysis::IntConstant int_constant_400(registered_type_signed_int, + {400}); + ASSERT_EQ(nullptr, + context->get_constant_mgr()->FindConstant(&int_constant_200)); + ASSERT_EQ(nullptr, + context->get_constant_mgr()->FindConstant(&int_constant_300)); + ASSERT_EQ(nullptr, + context->get_constant_mgr()->FindConstant(&int_constant_400)); + + // No float constant 0.5 + opt::analysis::FloatConstant float_constant_zero_point_five( + registered_type_float, {float_value_as_uint}); + ASSERT_EQ(nullptr, context->get_constant_mgr()->FindConstant( + &float_constant_zero_point_five)); + + // No uint constant 22 + opt::analysis::IntConstant uint_constant_22(registered_type_unsigned_int, + {22}); + ASSERT_EQ(nullptr, + context->get_constant_mgr()->FindConstant(&uint_constant_22)); + + // No uint constant 23 + opt::analysis::IntConstant uint_constant_23(registered_type_unsigned_int, + {23}); + ASSERT_EQ(nullptr, + context->get_constant_mgr()->FindConstant(&uint_constant_23)); + + // No int constants 0, 1, 2, 3, 6, 8 + opt::analysis::IntConstant int_constant_0(registered_type_signed_int, {0}); + opt::analysis::IntConstant int_constant_1(registered_type_signed_int, {1}); + opt::analysis::IntConstant int_constant_2(registered_type_signed_int, {2}); + opt::analysis::IntConstant int_constant_3(registered_type_signed_int, {3}); + opt::analysis::IntConstant int_constant_6(registered_type_signed_int, {6}); + opt::analysis::IntConstant int_constant_8(registered_type_signed_int, {8}); + ASSERT_EQ(nullptr, + context->get_constant_mgr()->FindConstant(&int_constant_0)); + ASSERT_EQ(nullptr, + context->get_constant_mgr()->FindConstant(&int_constant_1)); + ASSERT_EQ(nullptr, + context->get_constant_mgr()->FindConstant(&int_constant_2)); + ASSERT_EQ(nullptr, + context->get_constant_mgr()->FindConstant(&int_constant_3)); + ASSERT_EQ(nullptr, + context->get_constant_mgr()->FindConstant(&int_constant_6)); + ASSERT_EQ(nullptr, + context->get_constant_mgr()->FindConstant(&int_constant_8)); + } + + FuzzerPassAddUsefulConstructs pass(context.get(), &fact_manager, + &fuzzer_context, &transformation_sequence); + pass.Apply(); + ASSERT_TRUE(IsValid(env, context.get())); + + // Now assert some things about the module that should be true following the + // pass. + + // We reconstruct all necessary types and constants to guard against the type + // and constant managers for the module having been invalidated. + + { + // Uniform int pointer now present + opt::analysis::Integer temp_type_signed_int(32, true); + opt::analysis::Integer* registered_type_signed_int = + context->get_type_mgr() + ->GetRegisteredType(&temp_type_signed_int) + ->AsInteger(); + opt::analysis::Pointer type_pointer_uniform_signed_int( + registered_type_signed_int, SpvStorageClassUniform); + ASSERT_NE(0, + context->get_type_mgr()->GetId(&type_pointer_uniform_signed_int)); + + // Uniform uint pointer now present + opt::analysis::Integer temp_type_unsigned_int(32, false); + opt::analysis::Integer* registered_type_unsigned_int = + context->get_type_mgr() + ->GetRegisteredType(&temp_type_unsigned_int) + ->AsInteger(); + opt::analysis::Pointer type_pointer_uniform_unsigned_int( + registered_type_unsigned_int, SpvStorageClassUniform); + ASSERT_NE( + 0, context->get_type_mgr()->GetId(&type_pointer_uniform_unsigned_int)); + + // Uniform float pointer now present + opt::analysis::Float temp_type_float(32); + opt::analysis::Float* registered_type_float = + context->get_type_mgr()->GetRegisteredType(&temp_type_float)->AsFloat(); + opt::analysis::Pointer type_pointer_uniform_float(registered_type_float, + SpvStorageClassUniform); + ASSERT_NE(0, context->get_type_mgr()->GetId(&type_pointer_uniform_float)); + + // int constants 200, 300, 400 now present + opt::analysis::IntConstant int_constant_200(registered_type_signed_int, + {200}); + opt::analysis::IntConstant int_constant_300(registered_type_signed_int, + {300}); + opt::analysis::IntConstant int_constant_400(registered_type_signed_int, + {400}); + ASSERT_NE(nullptr, + context->get_constant_mgr()->FindConstant(&int_constant_200)); + ASSERT_NE(nullptr, + context->get_constant_mgr()->FindConstant(&int_constant_300)); + ASSERT_NE(nullptr, + context->get_constant_mgr()->FindConstant(&int_constant_400)); + + // float constant 0.5 now present + opt::analysis::FloatConstant float_constant_zero_point_five( + registered_type_float, {float_value_as_uint}); + ASSERT_NE(nullptr, context->get_constant_mgr()->FindConstant( + &float_constant_zero_point_five)); + + // uint constant 22 now present + opt::analysis::IntConstant uint_constant_22(registered_type_unsigned_int, + {22}); + ASSERT_NE(nullptr, + context->get_constant_mgr()->FindConstant(&uint_constant_22)); + + // uint constant 23 now present + opt::analysis::IntConstant uint_constant_23(registered_type_unsigned_int, + {23}); + ASSERT_NE(nullptr, + context->get_constant_mgr()->FindConstant(&uint_constant_23)); + + // int constants 0, 1, 2, 3, 6, 8 now present + opt::analysis::IntConstant int_constant_0(registered_type_signed_int, {0}); + opt::analysis::IntConstant int_constant_1(registered_type_signed_int, {1}); + opt::analysis::IntConstant int_constant_2(registered_type_signed_int, {2}); + opt::analysis::IntConstant int_constant_3(registered_type_signed_int, {3}); + opt::analysis::IntConstant int_constant_6(registered_type_signed_int, {6}); + opt::analysis::IntConstant int_constant_8(registered_type_signed_int, {8}); + ASSERT_NE(nullptr, + context->get_constant_mgr()->FindConstant(&int_constant_0)); + ASSERT_NE(nullptr, + context->get_constant_mgr()->FindConstant(&int_constant_1)); + ASSERT_NE(nullptr, + context->get_constant_mgr()->FindConstant(&int_constant_2)); + ASSERT_NE(nullptr, + context->get_constant_mgr()->FindConstant(&int_constant_3)); + ASSERT_NE(nullptr, + context->get_constant_mgr()->FindConstant(&int_constant_6)); + ASSERT_NE(nullptr, + context->get_constant_mgr()->FindConstant(&int_constant_8)); + } +} + +} // namespace +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/test/fuzz/fuzzer_pass_donate_modules_test.cpp b/third_party/spirv-tools/test/fuzz/fuzzer_pass_donate_modules_test.cpp new file mode 100644 index 0000000000..0d202b7a98 --- /dev/null +++ b/third_party/spirv-tools/test/fuzz/fuzzer_pass_donate_modules_test.cpp @@ -0,0 +1,673 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/fuzzer_pass_donate_modules.h" +#include "source/fuzz/pseudo_random_generator.h" +#include "test/fuzz/fuzz_test_util.h" + +namespace spvtools { +namespace fuzz { +namespace { + +TEST(FuzzerPassDonateModulesTest, BasicDonation) { + std::string recipient_shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %10 "m" + OpName %16 "v" + OpDecorate %16 RelaxedPrecision + OpDecorate %20 RelaxedPrecision + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypeVector %6 3 + %8 = OpTypeMatrix %7 2 + %9 = OpTypePointer Private %8 + %10 = OpVariable %9 Private + %11 = OpTypeInt 32 1 + %12 = OpConstant %11 0 + %13 = OpTypeInt 32 0 + %14 = OpTypeVector %13 4 + %15 = OpTypePointer Private %14 + %16 = OpVariable %15 Private + %17 = OpConstant %13 2 + %18 = OpTypePointer Private %13 + %22 = OpConstant %13 0 + %23 = OpTypePointer Private %6 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %19 = OpAccessChain %18 %16 %17 + %20 = OpLoad %13 %19 + %21 = OpConvertUToF %6 %20 + %24 = OpAccessChain %23 %10 %12 %22 + OpStore %24 %21 + OpReturn + OpFunctionEnd + )"; + + std::string donor_shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %12 "bar(mf24;" + OpName %11 "m" + OpName %20 "foo(vu4;" + OpName %19 "v" + OpName %23 "x" + OpName %26 "param" + OpName %29 "result" + OpName %31 "i" + OpName %81 "param" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypeVector %6 4 + %8 = OpTypeMatrix %7 2 + %9 = OpTypePointer Function %8 + %10 = OpTypeFunction %6 %9 + %14 = OpTypeInt 32 0 + %15 = OpTypeVector %14 4 + %16 = OpTypePointer Function %15 + %17 = OpTypeInt 32 1 + %18 = OpTypeFunction %17 %16 + %22 = OpTypePointer Function %17 + %24 = OpConstant %14 2 + %25 = OpConstantComposite %15 %24 %24 %24 %24 + %28 = OpTypePointer Function %6 + %30 = OpConstant %6 0 + %32 = OpConstant %17 0 + %39 = OpConstant %17 10 + %40 = OpTypeBool + %43 = OpConstant %17 3 + %50 = OpConstant %17 1 + %55 = OpConstant %14 0 + %56 = OpTypePointer Function %14 + %59 = OpConstant %14 1 + %65 = OpConstant %17 2 + %68 = OpConstant %6 1 + %69 = OpConstant %6 2 + %70 = OpConstant %6 3 + %71 = OpConstant %6 4 + %72 = OpConstant %14 3 + %76 = OpConstant %6 6 + %77 = OpConstant %6 7 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %23 = OpVariable %22 Function + %26 = OpVariable %16 Function + OpStore %26 %25 + %27 = OpFunctionCall %17 %20 %26 + OpStore %23 %27 + OpReturn + OpFunctionEnd + %12 = OpFunction %6 None %10 + %11 = OpFunctionParameter %9 + %13 = OpLabel + %29 = OpVariable %28 Function + %31 = OpVariable %22 Function + OpStore %29 %30 + OpStore %31 %32 + OpBranch %33 + %33 = OpLabel + OpLoopMerge %35 %36 None + OpBranch %37 + %37 = OpLabel + %38 = OpLoad %17 %31 + %41 = OpSLessThan %40 %38 %39 + OpBranchConditional %41 %34 %35 + %34 = OpLabel + %42 = OpLoad %17 %31 + %44 = OpExtInst %17 %1 SClamp %42 %32 %43 + %45 = OpAccessChain %28 %11 %32 %44 + %46 = OpLoad %6 %45 + %47 = OpLoad %6 %29 + %48 = OpFAdd %6 %47 %46 + OpStore %29 %48 + OpBranch %36 + %36 = OpLabel + %49 = OpLoad %17 %31 + %51 = OpIAdd %17 %49 %50 + OpStore %31 %51 + OpBranch %33 + %35 = OpLabel + %52 = OpLoad %6 %29 + OpReturnValue %52 + OpFunctionEnd + %20 = OpFunction %17 None %18 + %19 = OpFunctionParameter %16 + %21 = OpLabel + %81 = OpVariable %9 Function + %57 = OpAccessChain %56 %19 %55 + %58 = OpLoad %14 %57 + %60 = OpAccessChain %56 %19 %59 + %61 = OpLoad %14 %60 + %62 = OpUGreaterThan %40 %58 %61 + OpSelectionMerge %64 None + OpBranchConditional %62 %63 %67 + %63 = OpLabel + OpReturnValue %65 + %67 = OpLabel + %73 = OpAccessChain %56 %19 %72 + %74 = OpLoad %14 %73 + %75 = OpConvertUToF %6 %74 + %78 = OpCompositeConstruct %7 %30 %68 %69 %70 + %79 = OpCompositeConstruct %7 %71 %75 %76 %77 + %80 = OpCompositeConstruct %8 %78 %79 + OpStore %81 %80 + %82 = OpFunctionCall %6 %12 %81 + %83 = OpConvertFToS %17 %82 + OpReturnValue %83 + %64 = OpLabel + %85 = OpUndef %17 + OpReturnValue %85 + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto recipient_context = + BuildModule(env, consumer, recipient_shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, recipient_context.get())); + + const auto donor_context = + BuildModule(env, consumer, donor_shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, donor_context.get())); + + FactManager fact_manager; + + auto prng = MakeUnique(0); + FuzzerContext fuzzer_context(prng.get(), 100); + protobufs::TransformationSequence transformation_sequence; + + FuzzerPassDonateModules fuzzer_pass(recipient_context.get(), &fact_manager, + &fuzzer_context, &transformation_sequence, + {}); + + fuzzer_pass.DonateSingleModule(donor_context.get(), false); + + // We just check that the result is valid. Checking to what it should be + // exactly equal to would be very fragile. + ASSERT_TRUE(IsValid(env, recipient_context.get())); +} + +TEST(FuzzerPassDonateModulesTest, DonationWithUniforms) { + // This test checks that when donating a shader that contains uniforms, + // uniform variables and associated pointer types are demoted from having + // Uniform storage class to Private storage class. + std::string recipient_and_donor_shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpMemberDecorate %9 0 Offset 0 + OpDecorate %9 Block + OpDecorate %11 DescriptorSet 0 + OpDecorate %11 Binding 0 + OpMemberDecorate %19 0 Offset 0 + OpDecorate %19 Block + OpDecorate %21 DescriptorSet 0 + OpDecorate %21 Binding 1 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypePointer Function %6 + %9 = OpTypeStruct %6 + %10 = OpTypePointer Uniform %9 + %11 = OpVariable %10 Uniform + %12 = OpTypeInt 32 1 + %13 = OpConstant %12 0 + %14 = OpTypePointer Uniform %6 + %17 = OpTypePointer Function %12 + %19 = OpTypeStruct %12 + %20 = OpTypePointer Uniform %19 + %21 = OpVariable %20 Uniform + %22 = OpTypePointer Uniform %12 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %18 = OpVariable %17 Function + %15 = OpAccessChain %14 %11 %13 + %16 = OpLoad %6 %15 + OpStore %8 %16 + %23 = OpAccessChain %22 %21 %13 + %24 = OpLoad %12 %23 + OpStore %18 %24 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto recipient_context = BuildModule( + env, consumer, recipient_and_donor_shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, recipient_context.get())); + + const auto donor_context = BuildModule( + env, consumer, recipient_and_donor_shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, donor_context.get())); + + FactManager fact_manager; + + FuzzerContext fuzzer_context(MakeUnique(0).get(), 100); + protobufs::TransformationSequence transformation_sequence; + + FuzzerPassDonateModules fuzzer_pass(recipient_context.get(), &fact_manager, + &fuzzer_context, &transformation_sequence, + {}); + + fuzzer_pass.DonateSingleModule(donor_context.get(), false); + + ASSERT_TRUE(IsValid(env, recipient_context.get())); + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpMemberDecorate %9 0 Offset 0 + OpDecorate %9 Block + OpDecorate %11 DescriptorSet 0 + OpDecorate %11 Binding 0 + OpMemberDecorate %19 0 Offset 0 + OpDecorate %19 Block + OpDecorate %21 DescriptorSet 0 + OpDecorate %21 Binding 1 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypePointer Function %6 + %9 = OpTypeStruct %6 + %10 = OpTypePointer Uniform %9 + %11 = OpVariable %10 Uniform + %12 = OpTypeInt 32 1 + %13 = OpConstant %12 0 + %14 = OpTypePointer Uniform %6 + %17 = OpTypePointer Function %12 + %19 = OpTypeStruct %12 + %20 = OpTypePointer Uniform %19 + %21 = OpVariable %20 Uniform + %22 = OpTypePointer Uniform %12 + %100 = OpTypePointer Function %6 + %101 = OpTypeStruct %6 + %102 = OpTypePointer Private %101 + %103 = OpVariable %102 Private + %104 = OpConstant %12 0 + %105 = OpTypePointer Private %6 + %106 = OpTypePointer Function %12 + %107 = OpTypeStruct %12 + %108 = OpTypePointer Private %107 + %109 = OpVariable %108 Private + %110 = OpTypePointer Private %12 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %18 = OpVariable %17 Function + %15 = OpAccessChain %14 %11 %13 + %16 = OpLoad %6 %15 + OpStore %8 %16 + %23 = OpAccessChain %22 %21 %13 + %24 = OpLoad %12 %23 + OpStore %18 %24 + OpReturn + OpFunctionEnd + %111 = OpFunction %2 None %3 + %112 = OpLabel + %113 = OpVariable %100 Function + %114 = OpVariable %106 Function + %115 = OpAccessChain %105 %103 %104 + %116 = OpLoad %6 %115 + OpStore %113 %116 + %117 = OpAccessChain %110 %109 %104 + %118 = OpLoad %12 %117 + OpStore %114 %118 + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_transformation, recipient_context.get())); +} + +TEST(FuzzerPassDonateModulesTest, DonationWithInputAndOutputVariables) { + // This test checks that when donating a shader that contains input and output + // variables, such variables and associated pointer types are demoted to have + // the Private storage class. + std::string recipient_and_donor_shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" %9 %11 + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpDecorate %9 Location 0 + OpDecorate %11 Location 1 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypeVector %6 4 + %8 = OpTypePointer Output %7 + %9 = OpVariable %8 Output + %10 = OpTypePointer Input %7 + %11 = OpVariable %10 Input + %4 = OpFunction %2 None %3 + %5 = OpLabel + %12 = OpLoad %7 %11 + OpStore %9 %12 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto recipient_context = BuildModule( + env, consumer, recipient_and_donor_shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, recipient_context.get())); + + const auto donor_context = BuildModule( + env, consumer, recipient_and_donor_shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, donor_context.get())); + + FactManager fact_manager; + + FuzzerContext fuzzer_context(MakeUnique(0).get(), 100); + protobufs::TransformationSequence transformation_sequence; + + FuzzerPassDonateModules fuzzer_pass(recipient_context.get(), &fact_manager, + &fuzzer_context, &transformation_sequence, + {}); + + fuzzer_pass.DonateSingleModule(donor_context.get(), false); + + ASSERT_TRUE(IsValid(env, recipient_context.get())); + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" %9 %11 + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpDecorate %9 Location 0 + OpDecorate %11 Location 1 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypeVector %6 4 + %8 = OpTypePointer Output %7 + %9 = OpVariable %8 Output + %10 = OpTypePointer Input %7 + %11 = OpVariable %10 Input + %100 = OpTypePointer Private %7 + %101 = OpVariable %100 Private + %102 = OpTypePointer Private %7 + %103 = OpVariable %102 Private + %4 = OpFunction %2 None %3 + %5 = OpLabel + %12 = OpLoad %7 %11 + OpStore %9 %12 + OpReturn + OpFunctionEnd + %104 = OpFunction %2 None %3 + %105 = OpLabel + %106 = OpLoad %7 %103 + OpStore %101 %106 + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_transformation, recipient_context.get())); +} + +TEST(FuzzerPassDonateModulesTest, DonateFunctionTypeWithDifferentPointers) { + std::string recipient_and_donor_shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 0 + %7 = OpTypePointer Function %6 + %8 = OpTypeFunction %2 %7 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %9 = OpVariable %7 Function + %10 = OpFunctionCall %2 %11 %9 + OpReturn + OpFunctionEnd + %11 = OpFunction %2 None %8 + %12 = OpFunctionParameter %7 + %13 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_5; + const auto consumer = nullptr; + const auto recipient_context = BuildModule( + env, consumer, recipient_and_donor_shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, recipient_context.get())); + + const auto donor_context = BuildModule( + env, consumer, recipient_and_donor_shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, donor_context.get())); + + FactManager fact_manager; + + FuzzerContext fuzzer_context(MakeUnique(0).get(), 100); + protobufs::TransformationSequence transformation_sequence; + + FuzzerPassDonateModules fuzzer_pass(recipient_context.get(), &fact_manager, + &fuzzer_context, &transformation_sequence, + {}); + + fuzzer_pass.DonateSingleModule(donor_context.get(), false); + + // We just check that the result is valid. Checking to what it should be + // exactly equal to would be very fragile. + ASSERT_TRUE(IsValid(env, recipient_context.get())); +} + +TEST(FuzzerPassDonateModulesTest, Miscellaneous1) { + std::string recipient_shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + + std::string donor_shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %6 "foo(" + OpName %10 "x" + OpName %12 "i" + OpName %33 "i" + OpName %42 "j" + OpDecorate %10 RelaxedPrecision + OpDecorate %12 RelaxedPrecision + OpDecorate %19 RelaxedPrecision + OpDecorate %23 RelaxedPrecision + OpDecorate %24 RelaxedPrecision + OpDecorate %25 RelaxedPrecision + OpDecorate %26 RelaxedPrecision + OpDecorate %27 RelaxedPrecision + OpDecorate %28 RelaxedPrecision + OpDecorate %30 RelaxedPrecision + OpDecorate %33 RelaxedPrecision + OpDecorate %39 RelaxedPrecision + OpDecorate %42 RelaxedPrecision + OpDecorate %49 RelaxedPrecision + OpDecorate %52 RelaxedPrecision + OpDecorate %53 RelaxedPrecision + OpDecorate %58 RelaxedPrecision + OpDecorate %59 RelaxedPrecision + OpDecorate %60 RelaxedPrecision + OpDecorate %63 RelaxedPrecision + OpDecorate %64 RelaxedPrecision + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %8 = OpTypeInt 32 1 + %9 = OpTypePointer Function %8 + %11 = OpConstant %8 2 + %13 = OpConstant %8 0 + %20 = OpConstant %8 100 + %21 = OpTypeBool + %29 = OpConstant %8 1 + %40 = OpConstant %8 10 + %43 = OpConstant %8 20 + %61 = OpConstant %8 4 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %33 = OpVariable %9 Function + %42 = OpVariable %9 Function + %32 = OpFunctionCall %2 %6 + OpStore %33 %13 + OpBranch %34 + %34 = OpLabel + OpLoopMerge %36 %37 None + OpBranch %38 + %38 = OpLabel + %39 = OpLoad %8 %33 + %41 = OpSLessThan %21 %39 %40 + OpBranchConditional %41 %35 %36 + %35 = OpLabel + OpStore %42 %43 + OpBranch %44 + %44 = OpLabel + OpLoopMerge %46 %47 None + OpBranch %48 + %48 = OpLabel + %49 = OpLoad %8 %42 + %50 = OpSGreaterThan %21 %49 %13 + OpBranchConditional %50 %45 %46 + %45 = OpLabel + %51 = OpFunctionCall %2 %6 + %52 = OpLoad %8 %42 + %53 = OpISub %8 %52 %29 + OpStore %42 %53 + OpBranch %47 + %47 = OpLabel + OpBranch %44 + %46 = OpLabel + OpBranch %54 + %54 = OpLabel + OpLoopMerge %56 %57 None + OpBranch %55 + %55 = OpLabel + %58 = OpLoad %8 %33 + %59 = OpIAdd %8 %58 %29 + OpStore %33 %59 + OpBranch %57 + %57 = OpLabel + %60 = OpLoad %8 %33 + %62 = OpSLessThan %21 %60 %61 + OpBranchConditional %62 %54 %56 + %56 = OpLabel + OpBranch %37 + %37 = OpLabel + %63 = OpLoad %8 %33 + %64 = OpIAdd %8 %63 %29 + OpStore %33 %64 + OpBranch %34 + %36 = OpLabel + OpReturn + OpFunctionEnd + %6 = OpFunction %2 None %3 + %7 = OpLabel + %10 = OpVariable %9 Function + %12 = OpVariable %9 Function + OpStore %10 %11 + OpStore %12 %13 + OpBranch %14 + %14 = OpLabel + OpLoopMerge %16 %17 None + OpBranch %18 + %18 = OpLabel + %19 = OpLoad %8 %12 + %22 = OpSLessThan %21 %19 %20 + OpBranchConditional %22 %15 %16 + %15 = OpLabel + %23 = OpLoad %8 %12 + %24 = OpLoad %8 %10 + %25 = OpIAdd %8 %24 %23 + OpStore %10 %25 + %26 = OpLoad %8 %10 + %27 = OpIMul %8 %26 %11 + OpStore %10 %27 + OpBranch %17 + %17 = OpLabel + %28 = OpLoad %8 %12 + %30 = OpIAdd %8 %28 %29 + OpStore %12 %30 + OpBranch %14 + %16 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_5; + const auto consumer = nullptr; + const auto recipient_context = + BuildModule(env, consumer, recipient_shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, recipient_context.get())); + + const auto donor_context = + BuildModule(env, consumer, donor_shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, donor_context.get())); + + FactManager fact_manager; + + FuzzerContext fuzzer_context(MakeUnique(0).get(), 100); + protobufs::TransformationSequence transformation_sequence; + + FuzzerPassDonateModules fuzzer_pass(recipient_context.get(), &fact_manager, + &fuzzer_context, &transformation_sequence, + {}); + + fuzzer_pass.DonateSingleModule(donor_context.get(), false); + + // We just check that the result is valid. Checking to what it should be + // exactly equal to would be very fragile. + ASSERT_TRUE(IsValid(env, recipient_context.get())); +} + +} // namespace +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/test/fuzz/fuzzer_replayer_test.cpp b/third_party/spirv-tools/test/fuzz/fuzzer_replayer_test.cpp new file mode 100644 index 0000000000..f444695dc5 --- /dev/null +++ b/third_party/spirv-tools/test/fuzz/fuzzer_replayer_test.cpp @@ -0,0 +1,1641 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/fuzzer.h" +#include "source/fuzz/fuzzer_util.h" +#include "source/fuzz/replayer.h" +#include "source/fuzz/uniform_buffer_element_descriptor.h" +#include "test/fuzz/fuzz_test_util.h" + +namespace spvtools { +namespace fuzz { +namespace { + +const uint32_t kNumFuzzerRuns = 20; + +// The SPIR-V came from this GLSL: +// +// #version 310 es +// +// void foo() { +// int x; +// x = 2; +// for (int i = 0; i < 100; i++) { +// x += i; +// x = x * 2; +// } +// return; +// } +// +// void main() { +// foo(); +// for (int i = 0; i < 10; i++) { +// int j = 20; +// while(j > 0) { +// foo(); +// j--; +// } +// do { +// i++; +// } while(i < 4); +// } +// } + +const std::string kTestShader1 = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %6 "foo(" + OpName %10 "x" + OpName %12 "i" + OpName %33 "i" + OpName %42 "j" + OpDecorate %10 RelaxedPrecision + OpDecorate %12 RelaxedPrecision + OpDecorate %19 RelaxedPrecision + OpDecorate %23 RelaxedPrecision + OpDecorate %24 RelaxedPrecision + OpDecorate %25 RelaxedPrecision + OpDecorate %26 RelaxedPrecision + OpDecorate %27 RelaxedPrecision + OpDecorate %28 RelaxedPrecision + OpDecorate %30 RelaxedPrecision + OpDecorate %33 RelaxedPrecision + OpDecorate %39 RelaxedPrecision + OpDecorate %42 RelaxedPrecision + OpDecorate %49 RelaxedPrecision + OpDecorate %52 RelaxedPrecision + OpDecorate %53 RelaxedPrecision + OpDecorate %58 RelaxedPrecision + OpDecorate %59 RelaxedPrecision + OpDecorate %60 RelaxedPrecision + OpDecorate %63 RelaxedPrecision + OpDecorate %64 RelaxedPrecision + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %8 = OpTypeInt 32 1 + %9 = OpTypePointer Function %8 + %11 = OpConstant %8 2 + %13 = OpConstant %8 0 + %20 = OpConstant %8 100 + %21 = OpTypeBool + %29 = OpConstant %8 1 + %40 = OpConstant %8 10 + %43 = OpConstant %8 20 + %61 = OpConstant %8 4 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %33 = OpVariable %9 Function + %42 = OpVariable %9 Function + %32 = OpFunctionCall %2 %6 + OpStore %33 %13 + OpBranch %34 + %34 = OpLabel + OpLoopMerge %36 %37 None + OpBranch %38 + %38 = OpLabel + %39 = OpLoad %8 %33 + %41 = OpSLessThan %21 %39 %40 + OpBranchConditional %41 %35 %36 + %35 = OpLabel + OpStore %42 %43 + OpBranch %44 + %44 = OpLabel + OpLoopMerge %46 %47 None + OpBranch %48 + %48 = OpLabel + %49 = OpLoad %8 %42 + %50 = OpSGreaterThan %21 %49 %13 + OpBranchConditional %50 %45 %46 + %45 = OpLabel + %51 = OpFunctionCall %2 %6 + %52 = OpLoad %8 %42 + %53 = OpISub %8 %52 %29 + OpStore %42 %53 + OpBranch %47 + %47 = OpLabel + OpBranch %44 + %46 = OpLabel + OpBranch %54 + %54 = OpLabel + OpLoopMerge %56 %57 None + OpBranch %55 + %55 = OpLabel + %58 = OpLoad %8 %33 + %59 = OpIAdd %8 %58 %29 + OpStore %33 %59 + OpBranch %57 + %57 = OpLabel + %60 = OpLoad %8 %33 + %62 = OpSLessThan %21 %60 %61 + OpBranchConditional %62 %54 %56 + %56 = OpLabel + OpBranch %37 + %37 = OpLabel + %63 = OpLoad %8 %33 + %64 = OpIAdd %8 %63 %29 + OpStore %33 %64 + OpBranch %34 + %36 = OpLabel + OpReturn + OpFunctionEnd + %6 = OpFunction %2 None %3 + %7 = OpLabel + %10 = OpVariable %9 Function + %12 = OpVariable %9 Function + OpStore %10 %11 + OpStore %12 %13 + OpBranch %14 + %14 = OpLabel + OpLoopMerge %16 %17 None + OpBranch %18 + %18 = OpLabel + %19 = OpLoad %8 %12 + %22 = OpSLessThan %21 %19 %20 + OpBranchConditional %22 %15 %16 + %15 = OpLabel + %23 = OpLoad %8 %12 + %24 = OpLoad %8 %10 + %25 = OpIAdd %8 %24 %23 + OpStore %10 %25 + %26 = OpLoad %8 %10 + %27 = OpIMul %8 %26 %11 + OpStore %10 %27 + OpBranch %17 + %17 = OpLabel + %28 = OpLoad %8 %12 + %30 = OpIAdd %8 %28 %29 + OpStore %12 %30 + OpBranch %14 + %16 = OpLabel + OpReturn + OpFunctionEnd + )"; + +// The SPIR-V came from this GLSL, which was then optimized using spirv-opt +// with the -O argument: +// +// #version 310 es +// +// precision highp float; +// +// layout(location = 0) out vec4 _GLF_color; +// +// layout(set = 0, binding = 0) uniform buf0 { +// vec2 injectionSwitch; +// }; +// layout(set = 0, binding = 1) uniform buf1 { +// vec2 resolution; +// }; +// bool checkSwap(float a, float b) +// { +// return gl_FragCoord.y < resolution.y / 2.0 ? a > b : a < b; +// } +// void main() +// { +// float data[10]; +// for(int i = 0; i < 10; i++) +// { +// data[i] = float(10 - i) * injectionSwitch.y; +// } +// for(int i = 0; i < 9; i++) +// { +// for(int j = 0; j < 10; j++) +// { +// if(j < i + 1) +// { +// continue; +// } +// bool doSwap = checkSwap(data[i], data[j]); +// if(doSwap) +// { +// float temp = data[i]; +// data[i] = data[j]; +// data[j] = temp; +// } +// } +// } +// if(gl_FragCoord.x < resolution.x / 2.0) +// { +// _GLF_color = vec4(data[0] / 10.0, data[5] / 10.0, data[9] / 10.0, 1.0); +// } +// else +// { +// _GLF_color = vec4(data[5] / 10.0, data[9] / 10.0, data[0] / 10.0, 1.0); +// } +// } + +const std::string kTestShader2 = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" %16 %139 %25 %68 + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %16 "gl_FragCoord" + OpName %23 "buf1" + OpMemberName %23 0 "resolution" + OpName %25 "" + OpName %61 "data" + OpName %66 "buf0" + OpMemberName %66 0 "injectionSwitch" + OpName %68 "" + OpName %139 "_GLF_color" + OpDecorate %16 BuiltIn FragCoord + OpMemberDecorate %23 0 Offset 0 + OpDecorate %23 Block + OpDecorate %25 DescriptorSet 0 + OpDecorate %25 Binding 1 + OpDecorate %64 RelaxedPrecision + OpMemberDecorate %66 0 Offset 0 + OpDecorate %66 Block + OpDecorate %68 DescriptorSet 0 + OpDecorate %68 Binding 0 + OpDecorate %75 RelaxedPrecision + OpDecorate %95 RelaxedPrecision + OpDecorate %126 RelaxedPrecision + OpDecorate %128 RelaxedPrecision + OpDecorate %139 Location 0 + OpDecorate %182 RelaxedPrecision + OpDecorate %183 RelaxedPrecision + OpDecorate %184 RelaxedPrecision + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypePointer Function %6 + %8 = OpTypeBool + %14 = OpTypeVector %6 4 + %15 = OpTypePointer Input %14 + %16 = OpVariable %15 Input + %17 = OpTypeInt 32 0 + %18 = OpConstant %17 1 + %19 = OpTypePointer Input %6 + %22 = OpTypeVector %6 2 + %23 = OpTypeStruct %22 + %24 = OpTypePointer Uniform %23 + %25 = OpVariable %24 Uniform + %26 = OpTypeInt 32 1 + %27 = OpConstant %26 0 + %28 = OpTypePointer Uniform %6 + %56 = OpConstant %26 10 + %58 = OpConstant %17 10 + %59 = OpTypeArray %6 %58 + %60 = OpTypePointer Function %59 + %66 = OpTypeStruct %22 + %67 = OpTypePointer Uniform %66 + %68 = OpVariable %67 Uniform + %74 = OpConstant %26 1 + %83 = OpConstant %26 9 + %129 = OpConstant %17 0 + %138 = OpTypePointer Output %14 + %139 = OpVariable %138 Output + %144 = OpConstant %26 5 + %151 = OpConstant %6 1 + %194 = OpConstant %6 0.5 + %195 = OpConstant %6 0.100000001 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %61 = OpVariable %60 Function + OpBranch %50 + %50 = OpLabel + %182 = OpPhi %26 %27 %5 %75 %51 + %57 = OpSLessThan %8 %182 %56 + OpLoopMerge %52 %51 None + OpBranchConditional %57 %51 %52 + %51 = OpLabel + %64 = OpISub %26 %56 %182 + %65 = OpConvertSToF %6 %64 + %69 = OpAccessChain %28 %68 %27 %18 + %70 = OpLoad %6 %69 + %71 = OpFMul %6 %65 %70 + %72 = OpAccessChain %7 %61 %182 + OpStore %72 %71 + %75 = OpIAdd %26 %182 %74 + OpBranch %50 + %52 = OpLabel + OpBranch %77 + %77 = OpLabel + %183 = OpPhi %26 %27 %52 %128 %88 + %84 = OpSLessThan %8 %183 %83 + OpLoopMerge %79 %88 None + OpBranchConditional %84 %78 %79 + %78 = OpLabel + OpBranch %86 + %86 = OpLabel + %184 = OpPhi %26 %27 %78 %126 %89 + %92 = OpSLessThan %8 %184 %56 + OpLoopMerge %1000 %89 None + OpBranchConditional %92 %87 %1000 + %87 = OpLabel + %95 = OpIAdd %26 %183 %74 + %96 = OpSLessThan %8 %184 %95 + OpSelectionMerge %98 None + OpBranchConditional %96 %97 %98 + %97 = OpLabel + OpBranch %89 + %98 = OpLabel + %104 = OpAccessChain %7 %61 %183 + %105 = OpLoad %6 %104 + %107 = OpAccessChain %7 %61 %184 + %108 = OpLoad %6 %107 + %166 = OpAccessChain %19 %16 %18 + %167 = OpLoad %6 %166 + %168 = OpAccessChain %28 %25 %27 %18 + %169 = OpLoad %6 %168 + %170 = OpFMul %6 %169 %194 + %171 = OpFOrdLessThan %8 %167 %170 + OpSelectionMerge %172 None + OpBranchConditional %171 %173 %174 + %173 = OpLabel + %177 = OpFOrdGreaterThan %8 %105 %108 + OpBranch %172 + %174 = OpLabel + %180 = OpFOrdLessThan %8 %105 %108 + OpBranch %172 + %172 = OpLabel + %186 = OpPhi %8 %177 %173 %180 %174 + OpSelectionMerge %112 None + OpBranchConditional %186 %111 %112 + %111 = OpLabel + %116 = OpLoad %6 %104 + %120 = OpLoad %6 %107 + OpStore %104 %120 + OpStore %107 %116 + OpBranch %112 + %112 = OpLabel + OpBranch %89 + %89 = OpLabel + %126 = OpIAdd %26 %184 %74 + OpBranch %86 + %1000 = OpLabel + OpBranch %88 + %88 = OpLabel + %128 = OpIAdd %26 %183 %74 + OpBranch %77 + %79 = OpLabel + %130 = OpAccessChain %19 %16 %129 + %131 = OpLoad %6 %130 + %132 = OpAccessChain %28 %25 %27 %129 + %133 = OpLoad %6 %132 + %134 = OpFMul %6 %133 %194 + %135 = OpFOrdLessThan %8 %131 %134 + OpSelectionMerge %137 None + OpBranchConditional %135 %136 %153 + %136 = OpLabel + %140 = OpAccessChain %7 %61 %27 + %141 = OpLoad %6 %140 + %143 = OpFMul %6 %141 %195 + %145 = OpAccessChain %7 %61 %144 + %146 = OpLoad %6 %145 + %147 = OpFMul %6 %146 %195 + %148 = OpAccessChain %7 %61 %83 + %149 = OpLoad %6 %148 + %150 = OpFMul %6 %149 %195 + %152 = OpCompositeConstruct %14 %143 %147 %150 %151 + OpStore %139 %152 + OpBranch %137 + %153 = OpLabel + %154 = OpAccessChain %7 %61 %144 + %155 = OpLoad %6 %154 + %156 = OpFMul %6 %155 %195 + %157 = OpAccessChain %7 %61 %83 + %158 = OpLoad %6 %157 + %159 = OpFMul %6 %158 %195 + %160 = OpAccessChain %7 %61 %27 + %161 = OpLoad %6 %160 + %162 = OpFMul %6 %161 %195 + %163 = OpCompositeConstruct %14 %156 %159 %162 %151 + OpStore %139 %163 + OpBranch %137 + %137 = OpLabel + OpReturn + OpFunctionEnd + )"; + +// The SPIR-V came from this GLSL, which was then optimized using spirv-opt +// with the -O argument: +// +// #version 310 es +// +// precision highp float; +// +// layout(location = 0) out vec4 _GLF_color; +// +// layout(set = 0, binding = 0) uniform buf0 { +// vec2 resolution; +// }; +// void main(void) +// { +// float A[50]; +// for( +// int i = 0; +// i < 200; +// i ++ +// ) +// { +// if(i >= int(resolution.x)) +// { +// break; +// } +// if((4 * (i / 4)) == i) +// { +// A[i / 4] = float(i); +// } +// } +// for( +// int i = 0; +// i < 50; +// i ++ +// ) +// { +// if(i < int(gl_FragCoord.x)) +// { +// break; +// } +// if(i > 0) +// { +// A[i] += A[i - 1]; +// } +// } +// if(int(gl_FragCoord.x) < 20) +// { +// _GLF_color = vec4(A[0] / resolution.x, A[4] / resolution.y, 1.0, 1.0); +// } +// else +// if(int(gl_FragCoord.x) < 40) +// { +// _GLF_color = vec4(A[5] / resolution.x, A[9] / resolution.y, 1.0, 1.0); +// } +// else +// if(int(gl_FragCoord.x) < 60) +// { +// _GLF_color = vec4(A[10] / resolution.x, A[14] / resolution.y, +// 1.0, 1.0); +// } +// else +// if(int(gl_FragCoord.x) < 80) +// { +// _GLF_color = vec4(A[15] / resolution.x, A[19] / resolution.y, +// 1.0, 1.0); +// } +// else +// if(int(gl_FragCoord.x) < 100) +// { +// _GLF_color = vec4(A[20] / resolution.x, A[24] / resolution.y, +// 1.0, 1.0); +// } +// else +// if(int(gl_FragCoord.x) < 120) +// { +// _GLF_color = vec4(A[25] / resolution.x, A[29] / resolution.y, +// 1.0, 1.0); +// } +// else +// if(int(gl_FragCoord.x) < 140) +// { +// _GLF_color = vec4(A[30] / resolution.x, A[34] / resolution.y, +// 1.0, 1.0); +// } +// else +// if(int(gl_FragCoord.x) < 160) +// { +// _GLF_color = vec4(A[35] / resolution.x, A[39] / +// resolution.y, 1.0, 1.0); +// } +// else +// if(int(gl_FragCoord.x) < 180) +// { +// _GLF_color = vec4(A[40] / resolution.x, A[44] / +// resolution.y, 1.0, 1.0); +// } +// else +// if(int(gl_FragCoord.x) < 180) +// { +// _GLF_color = vec4(A[45] / resolution.x, A[49] / +// resolution.y, 1.0, 1.0); +// } +// else +// { +// discard; +// } +// } + +const std::string kTestShader3 = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" %68 %100 %24 + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %22 "buf0" + OpMemberName %22 0 "resolution" + OpName %24 "" + OpName %46 "A" + OpName %68 "gl_FragCoord" + OpName %100 "_GLF_color" + OpMemberDecorate %22 0 Offset 0 + OpDecorate %22 Block + OpDecorate %24 DescriptorSet 0 + OpDecorate %24 Binding 0 + OpDecorate %37 RelaxedPrecision + OpDecorate %38 RelaxedPrecision + OpDecorate %55 RelaxedPrecision + OpDecorate %68 BuiltIn FragCoord + OpDecorate %83 RelaxedPrecision + OpDecorate %91 RelaxedPrecision + OpDecorate %100 Location 0 + OpDecorate %302 RelaxedPrecision + OpDecorate %304 RelaxedPrecision + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %9 = OpConstant %6 0 + %16 = OpConstant %6 200 + %17 = OpTypeBool + %20 = OpTypeFloat 32 + %21 = OpTypeVector %20 2 + %22 = OpTypeStruct %21 + %23 = OpTypePointer Uniform %22 + %24 = OpVariable %23 Uniform + %25 = OpTypeInt 32 0 + %26 = OpConstant %25 0 + %27 = OpTypePointer Uniform %20 + %35 = OpConstant %6 4 + %43 = OpConstant %25 50 + %44 = OpTypeArray %20 %43 + %45 = OpTypePointer Function %44 + %51 = OpTypePointer Function %20 + %54 = OpConstant %6 1 + %63 = OpConstant %6 50 + %66 = OpTypeVector %20 4 + %67 = OpTypePointer Input %66 + %68 = OpVariable %67 Input + %69 = OpTypePointer Input %20 + %95 = OpConstant %6 20 + %99 = OpTypePointer Output %66 + %100 = OpVariable %99 Output + %108 = OpConstant %25 1 + %112 = OpConstant %20 1 + %118 = OpConstant %6 40 + %122 = OpConstant %6 5 + %128 = OpConstant %6 9 + %139 = OpConstant %6 60 + %143 = OpConstant %6 10 + %149 = OpConstant %6 14 + %160 = OpConstant %6 80 + %164 = OpConstant %6 15 + %170 = OpConstant %6 19 + %181 = OpConstant %6 100 + %190 = OpConstant %6 24 + %201 = OpConstant %6 120 + %205 = OpConstant %6 25 + %211 = OpConstant %6 29 + %222 = OpConstant %6 140 + %226 = OpConstant %6 30 + %232 = OpConstant %6 34 + %243 = OpConstant %6 160 + %247 = OpConstant %6 35 + %253 = OpConstant %6 39 + %264 = OpConstant %6 180 + %273 = OpConstant %6 44 + %287 = OpConstant %6 45 + %293 = OpConstant %6 49 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %46 = OpVariable %45 Function + OpBranch %10 + %10 = OpLabel + %302 = OpPhi %6 %9 %5 %55 %42 + %18 = OpSLessThan %17 %302 %16 + OpLoopMerge %12 %42 None + OpBranchConditional %18 %11 %12 + %11 = OpLabel + %28 = OpAccessChain %27 %24 %9 %26 + %29 = OpLoad %20 %28 + %30 = OpConvertFToS %6 %29 + %31 = OpSGreaterThanEqual %17 %302 %30 + OpSelectionMerge %33 None + OpBranchConditional %31 %32 %33 + %32 = OpLabel + OpBranch %12 + %33 = OpLabel + %37 = OpSDiv %6 %302 %35 + %38 = OpIMul %6 %35 %37 + %40 = OpIEqual %17 %38 %302 + OpBranchConditional %40 %41 %42 + %41 = OpLabel + %50 = OpConvertSToF %20 %302 + %52 = OpAccessChain %51 %46 %37 + OpStore %52 %50 + OpBranch %42 + %42 = OpLabel + %55 = OpIAdd %6 %302 %54 + OpBranch %10 + %12 = OpLabel + OpBranch %57 + %57 = OpLabel + %304 = OpPhi %6 %9 %12 %91 %80 + %64 = OpSLessThan %17 %304 %63 + OpLoopMerge %59 %80 None + OpBranchConditional %64 %58 %59 + %58 = OpLabel + %70 = OpAccessChain %69 %68 %26 + %71 = OpLoad %20 %70 + %72 = OpConvertFToS %6 %71 + %73 = OpSLessThan %17 %304 %72 + OpSelectionMerge %75 None + OpBranchConditional %73 %74 %75 + %74 = OpLabel + OpBranch %59 + %75 = OpLabel + %78 = OpSGreaterThan %17 %304 %9 + OpBranchConditional %78 %79 %80 + %79 = OpLabel + %83 = OpISub %6 %304 %54 + %84 = OpAccessChain %51 %46 %83 + %85 = OpLoad %20 %84 + %86 = OpAccessChain %51 %46 %304 + %87 = OpLoad %20 %86 + %88 = OpFAdd %20 %87 %85 + OpStore %86 %88 + OpBranch %80 + %80 = OpLabel + %91 = OpIAdd %6 %304 %54 + OpBranch %57 + %59 = OpLabel + %92 = OpAccessChain %69 %68 %26 + %93 = OpLoad %20 %92 + %94 = OpConvertFToS %6 %93 + %96 = OpSLessThan %17 %94 %95 + OpSelectionMerge %98 None + OpBranchConditional %96 %97 %114 + %97 = OpLabel + %101 = OpAccessChain %51 %46 %9 + %102 = OpLoad %20 %101 + %103 = OpAccessChain %27 %24 %9 %26 + %104 = OpLoad %20 %103 + %105 = OpFDiv %20 %102 %104 + %106 = OpAccessChain %51 %46 %35 + %107 = OpLoad %20 %106 + %109 = OpAccessChain %27 %24 %9 %108 + %110 = OpLoad %20 %109 + %111 = OpFDiv %20 %107 %110 + %113 = OpCompositeConstruct %66 %105 %111 %112 %112 + OpStore %100 %113 + OpBranch %98 + %114 = OpLabel + %119 = OpSLessThan %17 %94 %118 + OpSelectionMerge %121 None + OpBranchConditional %119 %120 %135 + %120 = OpLabel + %123 = OpAccessChain %51 %46 %122 + %124 = OpLoad %20 %123 + %125 = OpAccessChain %27 %24 %9 %26 + %126 = OpLoad %20 %125 + %127 = OpFDiv %20 %124 %126 + %129 = OpAccessChain %51 %46 %128 + %130 = OpLoad %20 %129 + %131 = OpAccessChain %27 %24 %9 %108 + %132 = OpLoad %20 %131 + %133 = OpFDiv %20 %130 %132 + %134 = OpCompositeConstruct %66 %127 %133 %112 %112 + OpStore %100 %134 + OpBranch %121 + %135 = OpLabel + %140 = OpSLessThan %17 %94 %139 + OpSelectionMerge %142 None + OpBranchConditional %140 %141 %156 + %141 = OpLabel + %144 = OpAccessChain %51 %46 %143 + %145 = OpLoad %20 %144 + %146 = OpAccessChain %27 %24 %9 %26 + %147 = OpLoad %20 %146 + %148 = OpFDiv %20 %145 %147 + %150 = OpAccessChain %51 %46 %149 + %151 = OpLoad %20 %150 + %152 = OpAccessChain %27 %24 %9 %108 + %153 = OpLoad %20 %152 + %154 = OpFDiv %20 %151 %153 + %155 = OpCompositeConstruct %66 %148 %154 %112 %112 + OpStore %100 %155 + OpBranch %142 + %156 = OpLabel + %161 = OpSLessThan %17 %94 %160 + OpSelectionMerge %163 None + OpBranchConditional %161 %162 %177 + %162 = OpLabel + %165 = OpAccessChain %51 %46 %164 + %166 = OpLoad %20 %165 + %167 = OpAccessChain %27 %24 %9 %26 + %168 = OpLoad %20 %167 + %169 = OpFDiv %20 %166 %168 + %171 = OpAccessChain %51 %46 %170 + %172 = OpLoad %20 %171 + %173 = OpAccessChain %27 %24 %9 %108 + %174 = OpLoad %20 %173 + %175 = OpFDiv %20 %172 %174 + %176 = OpCompositeConstruct %66 %169 %175 %112 %112 + OpStore %100 %176 + OpBranch %163 + %177 = OpLabel + %182 = OpSLessThan %17 %94 %181 + OpSelectionMerge %184 None + OpBranchConditional %182 %183 %197 + %183 = OpLabel + %185 = OpAccessChain %51 %46 %95 + %186 = OpLoad %20 %185 + %187 = OpAccessChain %27 %24 %9 %26 + %188 = OpLoad %20 %187 + %189 = OpFDiv %20 %186 %188 + %191 = OpAccessChain %51 %46 %190 + %192 = OpLoad %20 %191 + %193 = OpAccessChain %27 %24 %9 %108 + %194 = OpLoad %20 %193 + %195 = OpFDiv %20 %192 %194 + %196 = OpCompositeConstruct %66 %189 %195 %112 %112 + OpStore %100 %196 + OpBranch %184 + %197 = OpLabel + %202 = OpSLessThan %17 %94 %201 + OpSelectionMerge %204 None + OpBranchConditional %202 %203 %218 + %203 = OpLabel + %206 = OpAccessChain %51 %46 %205 + %207 = OpLoad %20 %206 + %208 = OpAccessChain %27 %24 %9 %26 + %209 = OpLoad %20 %208 + %210 = OpFDiv %20 %207 %209 + %212 = OpAccessChain %51 %46 %211 + %213 = OpLoad %20 %212 + %214 = OpAccessChain %27 %24 %9 %108 + %215 = OpLoad %20 %214 + %216 = OpFDiv %20 %213 %215 + %217 = OpCompositeConstruct %66 %210 %216 %112 %112 + OpStore %100 %217 + OpBranch %204 + %218 = OpLabel + %223 = OpSLessThan %17 %94 %222 + OpSelectionMerge %225 None + OpBranchConditional %223 %224 %239 + %224 = OpLabel + %227 = OpAccessChain %51 %46 %226 + %228 = OpLoad %20 %227 + %229 = OpAccessChain %27 %24 %9 %26 + %230 = OpLoad %20 %229 + %231 = OpFDiv %20 %228 %230 + %233 = OpAccessChain %51 %46 %232 + %234 = OpLoad %20 %233 + %235 = OpAccessChain %27 %24 %9 %108 + %236 = OpLoad %20 %235 + %237 = OpFDiv %20 %234 %236 + %238 = OpCompositeConstruct %66 %231 %237 %112 %112 + OpStore %100 %238 + OpBranch %225 + %239 = OpLabel + %244 = OpSLessThan %17 %94 %243 + OpSelectionMerge %246 None + OpBranchConditional %244 %245 %260 + %245 = OpLabel + %248 = OpAccessChain %51 %46 %247 + %249 = OpLoad %20 %248 + %250 = OpAccessChain %27 %24 %9 %26 + %251 = OpLoad %20 %250 + %252 = OpFDiv %20 %249 %251 + %254 = OpAccessChain %51 %46 %253 + %255 = OpLoad %20 %254 + %256 = OpAccessChain %27 %24 %9 %108 + %257 = OpLoad %20 %256 + %258 = OpFDiv %20 %255 %257 + %259 = OpCompositeConstruct %66 %252 %258 %112 %112 + OpStore %100 %259 + OpBranch %246 + %260 = OpLabel + %265 = OpSLessThan %17 %94 %264 + OpSelectionMerge %267 None + OpBranchConditional %265 %266 %280 + %266 = OpLabel + %268 = OpAccessChain %51 %46 %118 + %269 = OpLoad %20 %268 + %270 = OpAccessChain %27 %24 %9 %26 + %271 = OpLoad %20 %270 + %272 = OpFDiv %20 %269 %271 + %274 = OpAccessChain %51 %46 %273 + %275 = OpLoad %20 %274 + %276 = OpAccessChain %27 %24 %9 %108 + %277 = OpLoad %20 %276 + %278 = OpFDiv %20 %275 %277 + %279 = OpCompositeConstruct %66 %272 %278 %112 %112 + OpStore %100 %279 + OpBranch %267 + %280 = OpLabel + OpSelectionMerge %285 None + OpBranchConditional %265 %285 %300 + %285 = OpLabel + %288 = OpAccessChain %51 %46 %287 + %289 = OpLoad %20 %288 + %290 = OpAccessChain %27 %24 %9 %26 + %291 = OpLoad %20 %290 + %292 = OpFDiv %20 %289 %291 + %294 = OpAccessChain %51 %46 %293 + %295 = OpLoad %20 %294 + %296 = OpAccessChain %27 %24 %9 %108 + %297 = OpLoad %20 %296 + %298 = OpFDiv %20 %295 %297 + %299 = OpCompositeConstruct %66 %292 %298 %112 %112 + OpStore %100 %299 + OpBranch %267 + %300 = OpLabel + OpKill + %267 = OpLabel + OpBranch %246 + %246 = OpLabel + OpBranch %225 + %225 = OpLabel + OpBranch %204 + %204 = OpLabel + OpBranch %184 + %184 = OpLabel + OpBranch %163 + %163 = OpLabel + OpBranch %142 + %142 = OpLabel + OpBranch %121 + %121 = OpLabel + OpBranch %98 + %98 = OpLabel + OpReturn + OpFunctionEnd + )"; + +// The SPIR-V comes from the 'matrices_smart_loops' GLSL shader that ships +// with GraphicsFuzz. + +const std::string kTestShader4 = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" %327 %363 %65 %70 %80 %90 %99 %108 %117 %126 %135 %144 %333 + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %8 "matrix_number" + OpName %12 "cols" + OpName %23 "rows" + OpName %31 "c" + OpName %41 "r" + OpName %65 "m22" + OpName %68 "buf0" + OpMemberName %68 0 "one" + OpName %70 "" + OpName %80 "m23" + OpName %90 "m24" + OpName %99 "m32" + OpName %108 "m33" + OpName %117 "m34" + OpName %126 "m42" + OpName %135 "m43" + OpName %144 "m44" + OpName %164 "sum_index" + OpName %165 "cols" + OpName %173 "rows" + OpName %184 "sums" + OpName %189 "c" + OpName %198 "r" + OpName %325 "region_x" + OpName %327 "gl_FragCoord" + OpName %331 "buf1" + OpMemberName %331 0 "resolution" + OpName %333 "" + OpName %340 "region_y" + OpName %348 "overall_region" + OpName %363 "_GLF_color" + OpDecorate %8 RelaxedPrecision + OpDecorate %12 RelaxedPrecision + OpDecorate %19 RelaxedPrecision + OpDecorate %23 RelaxedPrecision + OpDecorate %29 RelaxedPrecision + OpDecorate %31 RelaxedPrecision + OpDecorate %38 RelaxedPrecision + OpDecorate %39 RelaxedPrecision + OpDecorate %41 RelaxedPrecision + OpDecorate %47 RelaxedPrecision + OpDecorate %48 RelaxedPrecision + OpDecorate %50 RelaxedPrecision + OpDecorate %66 RelaxedPrecision + OpDecorate %67 RelaxedPrecision + OpMemberDecorate %68 0 Offset 0 + OpDecorate %68 Block + OpDecorate %70 DescriptorSet 0 + OpDecorate %70 Binding 0 + OpDecorate %81 RelaxedPrecision + OpDecorate %82 RelaxedPrecision + OpDecorate %91 RelaxedPrecision + OpDecorate %92 RelaxedPrecision + OpDecorate %100 RelaxedPrecision + OpDecorate %101 RelaxedPrecision + OpDecorate %109 RelaxedPrecision + OpDecorate %110 RelaxedPrecision + OpDecorate %118 RelaxedPrecision + OpDecorate %119 RelaxedPrecision + OpDecorate %127 RelaxedPrecision + OpDecorate %128 RelaxedPrecision + OpDecorate %136 RelaxedPrecision + OpDecorate %137 RelaxedPrecision + OpDecorate %145 RelaxedPrecision + OpDecorate %146 RelaxedPrecision + OpDecorate %152 RelaxedPrecision + OpDecorate %154 RelaxedPrecision + OpDecorate %155 RelaxedPrecision + OpDecorate %156 RelaxedPrecision + OpDecorate %157 RelaxedPrecision + OpDecorate %159 RelaxedPrecision + OpDecorate %160 RelaxedPrecision + OpDecorate %161 RelaxedPrecision + OpDecorate %162 RelaxedPrecision + OpDecorate %163 RelaxedPrecision + OpDecorate %164 RelaxedPrecision + OpDecorate %165 RelaxedPrecision + OpDecorate %171 RelaxedPrecision + OpDecorate %173 RelaxedPrecision + OpDecorate %179 RelaxedPrecision + OpDecorate %185 RelaxedPrecision + OpDecorate %189 RelaxedPrecision + OpDecorate %195 RelaxedPrecision + OpDecorate %196 RelaxedPrecision + OpDecorate %198 RelaxedPrecision + OpDecorate %204 RelaxedPrecision + OpDecorate %205 RelaxedPrecision + OpDecorate %207 RelaxedPrecision + OpDecorate %218 RelaxedPrecision + OpDecorate %219 RelaxedPrecision + OpDecorate %220 RelaxedPrecision + OpDecorate %228 RelaxedPrecision + OpDecorate %229 RelaxedPrecision + OpDecorate %230 RelaxedPrecision + OpDecorate %238 RelaxedPrecision + OpDecorate %239 RelaxedPrecision + OpDecorate %240 RelaxedPrecision + OpDecorate %248 RelaxedPrecision + OpDecorate %249 RelaxedPrecision + OpDecorate %250 RelaxedPrecision + OpDecorate %258 RelaxedPrecision + OpDecorate %259 RelaxedPrecision + OpDecorate %260 RelaxedPrecision + OpDecorate %268 RelaxedPrecision + OpDecorate %269 RelaxedPrecision + OpDecorate %270 RelaxedPrecision + OpDecorate %278 RelaxedPrecision + OpDecorate %279 RelaxedPrecision + OpDecorate %280 RelaxedPrecision + OpDecorate %288 RelaxedPrecision + OpDecorate %289 RelaxedPrecision + OpDecorate %290 RelaxedPrecision + OpDecorate %298 RelaxedPrecision + OpDecorate %299 RelaxedPrecision + OpDecorate %300 RelaxedPrecision + OpDecorate %309 RelaxedPrecision + OpDecorate %310 RelaxedPrecision + OpDecorate %311 RelaxedPrecision + OpDecorate %312 RelaxedPrecision + OpDecorate %313 RelaxedPrecision + OpDecorate %319 RelaxedPrecision + OpDecorate %320 RelaxedPrecision + OpDecorate %321 RelaxedPrecision + OpDecorate %322 RelaxedPrecision + OpDecorate %323 RelaxedPrecision + OpDecorate %324 RelaxedPrecision + OpDecorate %325 RelaxedPrecision + OpDecorate %327 BuiltIn FragCoord + OpMemberDecorate %331 0 Offset 0 + OpDecorate %331 Block + OpDecorate %333 DescriptorSet 0 + OpDecorate %333 Binding 1 + OpDecorate %339 RelaxedPrecision + OpDecorate %340 RelaxedPrecision + OpDecorate %347 RelaxedPrecision + OpDecorate %348 RelaxedPrecision + OpDecorate %349 RelaxedPrecision + OpDecorate %351 RelaxedPrecision + OpDecorate %352 RelaxedPrecision + OpDecorate %353 RelaxedPrecision + OpDecorate %354 RelaxedPrecision + OpDecorate %356 RelaxedPrecision + OpDecorate %363 Location 0 + OpDecorate %364 RelaxedPrecision + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 0 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 0 + %10 = OpTypeInt 32 1 + %11 = OpTypePointer Function %10 + %13 = OpConstant %10 2 + %20 = OpConstant %10 4 + %21 = OpTypeBool + %32 = OpConstant %10 0 + %61 = OpTypeFloat 32 + %62 = OpTypeVector %61 2 + %63 = OpTypeMatrix %62 2 + %64 = OpTypePointer Private %63 + %65 = OpVariable %64 Private + %68 = OpTypeStruct %61 + %69 = OpTypePointer Uniform %68 + %70 = OpVariable %69 Uniform + %71 = OpTypePointer Uniform %61 + %74 = OpTypePointer Private %61 + %77 = OpTypeVector %61 3 + %78 = OpTypeMatrix %77 2 + %79 = OpTypePointer Private %78 + %80 = OpVariable %79 Private + %87 = OpTypeVector %61 4 + %88 = OpTypeMatrix %87 2 + %89 = OpTypePointer Private %88 + %90 = OpVariable %89 Private + %97 = OpTypeMatrix %62 3 + %98 = OpTypePointer Private %97 + %99 = OpVariable %98 Private + %106 = OpTypeMatrix %77 3 + %107 = OpTypePointer Private %106 + %108 = OpVariable %107 Private + %115 = OpTypeMatrix %87 3 + %116 = OpTypePointer Private %115 + %117 = OpVariable %116 Private + %124 = OpTypeMatrix %62 4 + %125 = OpTypePointer Private %124 + %126 = OpVariable %125 Private + %133 = OpTypeMatrix %77 4 + %134 = OpTypePointer Private %133 + %135 = OpVariable %134 Private + %142 = OpTypeMatrix %87 4 + %143 = OpTypePointer Private %142 + %144 = OpVariable %143 Private + %153 = OpConstant %10 1 + %158 = OpConstant %6 1 + %181 = OpConstant %6 9 + %182 = OpTypeArray %61 %181 + %183 = OpTypePointer Function %182 + %186 = OpConstant %61 0 + %187 = OpTypePointer Function %61 + %314 = OpConstant %61 16 + %326 = OpTypePointer Input %87 + %327 = OpVariable %326 Input + %328 = OpTypePointer Input %61 + %331 = OpTypeStruct %62 + %332 = OpTypePointer Uniform %331 + %333 = OpVariable %332 Uniform + %336 = OpConstant %61 3 + %350 = OpConstant %10 3 + %357 = OpConstant %10 9 + %362 = OpTypePointer Output %87 + %363 = OpVariable %362 Output + %368 = OpConstant %61 1 + %374 = OpConstantComposite %87 %186 %186 %186 %368 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %12 = OpVariable %11 Function + %23 = OpVariable %11 Function + %31 = OpVariable %11 Function + %41 = OpVariable %11 Function + %164 = OpVariable %11 Function + %165 = OpVariable %11 Function + %173 = OpVariable %11 Function + %184 = OpVariable %183 Function + %189 = OpVariable %11 Function + %198 = OpVariable %11 Function + %325 = OpVariable %11 Function + %340 = OpVariable %11 Function + %348 = OpVariable %11 Function + OpStore %8 %9 + OpStore %12 %13 + OpBranch %14 + %14 = OpLabel + OpLoopMerge %16 %17 None + OpBranch %18 + %18 = OpLabel + %19 = OpLoad %10 %12 + %22 = OpSLessThanEqual %21 %19 %20 + OpBranchConditional %22 %15 %16 + %15 = OpLabel + OpStore %23 %13 + OpBranch %24 + %24 = OpLabel + OpLoopMerge %26 %27 None + OpBranch %28 + %28 = OpLabel + %29 = OpLoad %10 %23 + %30 = OpSLessThanEqual %21 %29 %20 + OpBranchConditional %30 %25 %26 + %25 = OpLabel + OpStore %31 %32 + OpBranch %33 + %33 = OpLabel + OpLoopMerge %35 %36 None + OpBranch %37 + %37 = OpLabel + %38 = OpLoad %10 %31 + %39 = OpLoad %10 %12 + %40 = OpSLessThan %21 %38 %39 + OpBranchConditional %40 %34 %35 + %34 = OpLabel + OpStore %41 %32 + OpBranch %42 + %42 = OpLabel + OpLoopMerge %44 %45 None + OpBranch %46 + %46 = OpLabel + %47 = OpLoad %10 %41 + %48 = OpLoad %10 %23 + %49 = OpSLessThan %21 %47 %48 + OpBranchConditional %49 %43 %44 + %43 = OpLabel + %50 = OpLoad %6 %8 + OpSelectionMerge %60 None + OpSwitch %50 %60 0 %51 1 %52 2 %53 3 %54 4 %55 5 %56 6 %57 7 %58 8 %59 + %51 = OpLabel + %66 = OpLoad %10 %31 + %67 = OpLoad %10 %41 + %72 = OpAccessChain %71 %70 %32 + %73 = OpLoad %61 %72 + %75 = OpAccessChain %74 %65 %66 %67 + OpStore %75 %73 + OpBranch %60 + %52 = OpLabel + %81 = OpLoad %10 %31 + %82 = OpLoad %10 %41 + %83 = OpAccessChain %71 %70 %32 + %84 = OpLoad %61 %83 + %85 = OpAccessChain %74 %80 %81 %82 + OpStore %85 %84 + OpBranch %60 + %53 = OpLabel + %91 = OpLoad %10 %31 + %92 = OpLoad %10 %41 + %93 = OpAccessChain %71 %70 %32 + %94 = OpLoad %61 %93 + %95 = OpAccessChain %74 %90 %91 %92 + OpStore %95 %94 + OpBranch %60 + %54 = OpLabel + %100 = OpLoad %10 %31 + %101 = OpLoad %10 %41 + %102 = OpAccessChain %71 %70 %32 + %103 = OpLoad %61 %102 + %104 = OpAccessChain %74 %99 %100 %101 + OpStore %104 %103 + OpBranch %60 + %55 = OpLabel + %109 = OpLoad %10 %31 + %110 = OpLoad %10 %41 + %111 = OpAccessChain %71 %70 %32 + %112 = OpLoad %61 %111 + %113 = OpAccessChain %74 %108 %109 %110 + OpStore %113 %112 + OpBranch %60 + %56 = OpLabel + %118 = OpLoad %10 %31 + %119 = OpLoad %10 %41 + %120 = OpAccessChain %71 %70 %32 + %121 = OpLoad %61 %120 + %122 = OpAccessChain %74 %117 %118 %119 + OpStore %122 %121 + OpBranch %60 + %57 = OpLabel + %127 = OpLoad %10 %31 + %128 = OpLoad %10 %41 + %129 = OpAccessChain %71 %70 %32 + %130 = OpLoad %61 %129 + %131 = OpAccessChain %74 %126 %127 %128 + OpStore %131 %130 + OpBranch %60 + %58 = OpLabel + %136 = OpLoad %10 %31 + %137 = OpLoad %10 %41 + %138 = OpAccessChain %71 %70 %32 + %139 = OpLoad %61 %138 + %140 = OpAccessChain %74 %135 %136 %137 + OpStore %140 %139 + OpBranch %60 + %59 = OpLabel + %145 = OpLoad %10 %31 + %146 = OpLoad %10 %41 + %147 = OpAccessChain %71 %70 %32 + %148 = OpLoad %61 %147 + %149 = OpAccessChain %74 %144 %145 %146 + OpStore %149 %148 + OpBranch %60 + %60 = OpLabel + OpBranch %45 + %45 = OpLabel + %152 = OpLoad %10 %41 + %154 = OpIAdd %10 %152 %153 + OpStore %41 %154 + OpBranch %42 + %44 = OpLabel + OpBranch %36 + %36 = OpLabel + %155 = OpLoad %10 %31 + %156 = OpIAdd %10 %155 %153 + OpStore %31 %156 + OpBranch %33 + %35 = OpLabel + %157 = OpLoad %6 %8 + %159 = OpIAdd %6 %157 %158 + OpStore %8 %159 + OpBranch %27 + %27 = OpLabel + %160 = OpLoad %10 %23 + %161 = OpIAdd %10 %160 %153 + OpStore %23 %161 + OpBranch %24 + %26 = OpLabel + OpBranch %17 + %17 = OpLabel + %162 = OpLoad %10 %12 + %163 = OpIAdd %10 %162 %153 + OpStore %12 %163 + OpBranch %14 + %16 = OpLabel + OpStore %164 %32 + OpStore %165 %13 + OpBranch %166 + %166 = OpLabel + OpLoopMerge %168 %169 None + OpBranch %170 + %170 = OpLabel + %171 = OpLoad %10 %165 + %172 = OpSLessThanEqual %21 %171 %20 + OpBranchConditional %172 %167 %168 + %167 = OpLabel + OpStore %173 %13 + OpBranch %174 + %174 = OpLabel + OpLoopMerge %176 %177 None + OpBranch %178 + %178 = OpLabel + %179 = OpLoad %10 %173 + %180 = OpSLessThanEqual %21 %179 %20 + OpBranchConditional %180 %175 %176 + %175 = OpLabel + %185 = OpLoad %10 %164 + %188 = OpAccessChain %187 %184 %185 + OpStore %188 %186 + OpStore %189 %32 + OpBranch %190 + %190 = OpLabel + OpLoopMerge %192 %193 None + OpBranch %194 + %194 = OpLabel + %195 = OpLoad %10 %189 + %196 = OpLoad %10 %165 + %197 = OpSLessThan %21 %195 %196 + OpBranchConditional %197 %191 %192 + %191 = OpLabel + OpStore %198 %32 + OpBranch %199 + %199 = OpLabel + OpLoopMerge %201 %202 None + OpBranch %203 + %203 = OpLabel + %204 = OpLoad %10 %198 + %205 = OpLoad %10 %173 + %206 = OpSLessThan %21 %204 %205 + OpBranchConditional %206 %200 %201 + %200 = OpLabel + %207 = OpLoad %10 %164 + OpSelectionMerge %217 None + OpSwitch %207 %217 0 %208 1 %209 2 %210 3 %211 4 %212 5 %213 6 %214 7 %215 8 %216 + %208 = OpLabel + %218 = OpLoad %10 %164 + %219 = OpLoad %10 %189 + %220 = OpLoad %10 %198 + %221 = OpAccessChain %74 %65 %219 %220 + %222 = OpLoad %61 %221 + %223 = OpAccessChain %187 %184 %218 + %224 = OpLoad %61 %223 + %225 = OpFAdd %61 %224 %222 + %226 = OpAccessChain %187 %184 %218 + OpStore %226 %225 + OpBranch %217 + %209 = OpLabel + %228 = OpLoad %10 %164 + %229 = OpLoad %10 %189 + %230 = OpLoad %10 %198 + %231 = OpAccessChain %74 %80 %229 %230 + %232 = OpLoad %61 %231 + %233 = OpAccessChain %187 %184 %228 + %234 = OpLoad %61 %233 + %235 = OpFAdd %61 %234 %232 + %236 = OpAccessChain %187 %184 %228 + OpStore %236 %235 + OpBranch %217 + %210 = OpLabel + %238 = OpLoad %10 %164 + %239 = OpLoad %10 %189 + %240 = OpLoad %10 %198 + %241 = OpAccessChain %74 %90 %239 %240 + %242 = OpLoad %61 %241 + %243 = OpAccessChain %187 %184 %238 + %244 = OpLoad %61 %243 + %245 = OpFAdd %61 %244 %242 + %246 = OpAccessChain %187 %184 %238 + OpStore %246 %245 + OpBranch %217 + %211 = OpLabel + %248 = OpLoad %10 %164 + %249 = OpLoad %10 %189 + %250 = OpLoad %10 %198 + %251 = OpAccessChain %74 %99 %249 %250 + %252 = OpLoad %61 %251 + %253 = OpAccessChain %187 %184 %248 + %254 = OpLoad %61 %253 + %255 = OpFAdd %61 %254 %252 + %256 = OpAccessChain %187 %184 %248 + OpStore %256 %255 + OpBranch %217 + %212 = OpLabel + %258 = OpLoad %10 %164 + %259 = OpLoad %10 %189 + %260 = OpLoad %10 %198 + %261 = OpAccessChain %74 %108 %259 %260 + %262 = OpLoad %61 %261 + %263 = OpAccessChain %187 %184 %258 + %264 = OpLoad %61 %263 + %265 = OpFAdd %61 %264 %262 + %266 = OpAccessChain %187 %184 %258 + OpStore %266 %265 + OpBranch %217 + %213 = OpLabel + %268 = OpLoad %10 %164 + %269 = OpLoad %10 %189 + %270 = OpLoad %10 %198 + %271 = OpAccessChain %74 %117 %269 %270 + %272 = OpLoad %61 %271 + %273 = OpAccessChain %187 %184 %268 + %274 = OpLoad %61 %273 + %275 = OpFAdd %61 %274 %272 + %276 = OpAccessChain %187 %184 %268 + OpStore %276 %275 + OpBranch %217 + %214 = OpLabel + %278 = OpLoad %10 %164 + %279 = OpLoad %10 %189 + %280 = OpLoad %10 %198 + %281 = OpAccessChain %74 %126 %279 %280 + %282 = OpLoad %61 %281 + %283 = OpAccessChain %187 %184 %278 + %284 = OpLoad %61 %283 + %285 = OpFAdd %61 %284 %282 + %286 = OpAccessChain %187 %184 %278 + OpStore %286 %285 + OpBranch %217 + %215 = OpLabel + %288 = OpLoad %10 %164 + %289 = OpLoad %10 %189 + %290 = OpLoad %10 %198 + %291 = OpAccessChain %74 %135 %289 %290 + %292 = OpLoad %61 %291 + %293 = OpAccessChain %187 %184 %288 + %294 = OpLoad %61 %293 + %295 = OpFAdd %61 %294 %292 + %296 = OpAccessChain %187 %184 %288 + OpStore %296 %295 + OpBranch %217 + %216 = OpLabel + %298 = OpLoad %10 %164 + %299 = OpLoad %10 %189 + %300 = OpLoad %10 %198 + %301 = OpAccessChain %74 %144 %299 %300 + %302 = OpLoad %61 %301 + %303 = OpAccessChain %187 %184 %298 + %304 = OpLoad %61 %303 + %305 = OpFAdd %61 %304 %302 + %306 = OpAccessChain %187 %184 %298 + OpStore %306 %305 + OpBranch %217 + %217 = OpLabel + OpBranch %202 + %202 = OpLabel + %309 = OpLoad %10 %198 + %310 = OpIAdd %10 %309 %153 + OpStore %198 %310 + OpBranch %199 + %201 = OpLabel + OpBranch %193 + %193 = OpLabel + %311 = OpLoad %10 %189 + %312 = OpIAdd %10 %311 %153 + OpStore %189 %312 + OpBranch %190 + %192 = OpLabel + %313 = OpLoad %10 %164 + %315 = OpAccessChain %187 %184 %313 + %316 = OpLoad %61 %315 + %317 = OpFDiv %61 %316 %314 + %318 = OpAccessChain %187 %184 %313 + OpStore %318 %317 + %319 = OpLoad %10 %164 + %320 = OpIAdd %10 %319 %153 + OpStore %164 %320 + OpBranch %177 + %177 = OpLabel + %321 = OpLoad %10 %173 + %322 = OpIAdd %10 %321 %153 + OpStore %173 %322 + OpBranch %174 + %176 = OpLabel + OpBranch %169 + %169 = OpLabel + %323 = OpLoad %10 %165 + %324 = OpIAdd %10 %323 %153 + OpStore %165 %324 + OpBranch %166 + %168 = OpLabel + %329 = OpAccessChain %328 %327 %9 + %330 = OpLoad %61 %329 + %334 = OpAccessChain %71 %333 %32 %9 + %335 = OpLoad %61 %334 + %337 = OpFDiv %61 %335 %336 + %338 = OpFDiv %61 %330 %337 + %339 = OpConvertFToS %10 %338 + OpStore %325 %339 + %341 = OpAccessChain %328 %327 %158 + %342 = OpLoad %61 %341 + %343 = OpAccessChain %71 %333 %32 %9 + %344 = OpLoad %61 %343 + %345 = OpFDiv %61 %344 %336 + %346 = OpFDiv %61 %342 %345 + %347 = OpConvertFToS %10 %346 + OpStore %340 %347 + %349 = OpLoad %10 %340 + %351 = OpIMul %10 %349 %350 + %352 = OpLoad %10 %325 + %353 = OpIAdd %10 %351 %352 + OpStore %348 %353 + %354 = OpLoad %10 %348 + %355 = OpSGreaterThan %21 %354 %32 + %356 = OpLoad %10 %348 + %358 = OpSLessThan %21 %356 %357 + %359 = OpLogicalAnd %21 %355 %358 + OpSelectionMerge %361 None + OpBranchConditional %359 %360 %373 + %360 = OpLabel + %364 = OpLoad %10 %348 + %365 = OpAccessChain %187 %184 %364 + %366 = OpLoad %61 %365 + %367 = OpCompositeConstruct %77 %366 %366 %366 + %369 = OpCompositeExtract %61 %367 0 + %370 = OpCompositeExtract %61 %367 1 + %371 = OpCompositeExtract %61 %367 2 + %372 = OpCompositeConstruct %87 %369 %370 %371 %368 + OpStore %363 %372 + OpBranch %361 + %373 = OpLabel + OpStore %363 %374 + OpBranch %361 + %361 = OpLabel + OpReturn + OpFunctionEnd + )"; + +void AddConstantUniformFact(protobufs::FactSequence* facts, + uint32_t descriptor_set, uint32_t binding, + std::vector&& indices, uint32_t value) { + protobufs::FactConstantUniform fact; + *fact.mutable_uniform_buffer_element_descriptor() = + MakeUniformBufferElementDescriptor(descriptor_set, binding, + std::move(indices)); + *fact.mutable_constant_word()->Add() = value; + protobufs::Fact temp; + *temp.mutable_constant_uniform_fact() = fact; + *facts->mutable_fact()->Add() = temp; +} + +// Reinterpret the bits of |value| as a 32-bit unsigned int +uint32_t FloatBitsAsUint(float value) { + uint32_t result; + memcpy(&result, &value, sizeof(float)); + return result; +} + +// Assembles the given |shader| text, and then runs the fuzzer |num_runs| +// times, using successive seeds starting from |initial_seed|. Checks that +// the binary produced after each fuzzer run is valid, and that replaying +// the transformations that were applied during fuzzing leads to an +// identical binary. +void RunFuzzerAndReplayer(const std::string& shader, + const protobufs::FactSequence& initial_facts, + uint32_t initial_seed, uint32_t num_runs) { + const auto env = SPV_ENV_UNIVERSAL_1_5; + + std::vector binary_in; + SpirvTools t(env); + t.SetMessageConsumer(kConsoleMessageConsumer); + ASSERT_TRUE(t.Assemble(shader, &binary_in, kFuzzAssembleOption)); + ASSERT_TRUE(t.Validate(binary_in)); + + std::vector donor_suppliers; + for (auto donor : + {&kTestShader1, &kTestShader2, &kTestShader3, &kTestShader4}) { + donor_suppliers.emplace_back([donor]() { + return BuildModule(env, kConsoleMessageConsumer, *donor, + kFuzzAssembleOption); + }); + } + + for (uint32_t seed = initial_seed; seed < initial_seed + num_runs; seed++) { + std::vector fuzzer_binary_out; + protobufs::TransformationSequence fuzzer_transformation_sequence_out; + + Fuzzer fuzzer(env, seed, true); + fuzzer.SetMessageConsumer(kSilentConsumer); + auto fuzzer_result_status = + fuzzer.Run(binary_in, initial_facts, donor_suppliers, + &fuzzer_binary_out, &fuzzer_transformation_sequence_out); + ASSERT_EQ(Fuzzer::FuzzerResultStatus::kComplete, fuzzer_result_status); + ASSERT_TRUE(t.Validate(fuzzer_binary_out)); + + std::vector replayer_binary_out; + protobufs::TransformationSequence replayer_transformation_sequence_out; + + Replayer replayer(env, false); + replayer.SetMessageConsumer(kSilentConsumer); + auto replayer_result_status = replayer.Run( + binary_in, initial_facts, fuzzer_transformation_sequence_out, + &replayer_binary_out, &replayer_transformation_sequence_out); + ASSERT_EQ(Replayer::ReplayerResultStatus::kComplete, + replayer_result_status); + + // After replaying the transformations applied by the fuzzer, exactly those + // transformations should have been applied, and the binary resulting from + // replay should be identical to that which resulted from fuzzing. + std::string fuzzer_transformations_string; + std::string replayer_transformations_string; + fuzzer_transformation_sequence_out.SerializeToString( + &fuzzer_transformations_string); + replayer_transformation_sequence_out.SerializeToString( + &replayer_transformations_string); + ASSERT_EQ(fuzzer_transformations_string, replayer_transformations_string); + ASSERT_EQ(fuzzer_binary_out, replayer_binary_out); + } +} + +TEST(FuzzerReplayerTest, Miscellaneous1) { + // Do some fuzzer runs, starting from an initial seed of 0 (seed value chosen + // arbitrarily). + RunFuzzerAndReplayer(kTestShader1, protobufs::FactSequence(), 0, + kNumFuzzerRuns); +} + +TEST(FuzzerReplayerTest, Miscellaneous2) { + // Do some fuzzer runs, starting from an initial seed of 10 (seed value chosen + // arbitrarily). + RunFuzzerAndReplayer(kTestShader2, protobufs::FactSequence(), 10, + kNumFuzzerRuns); +} + +TEST(FuzzerReplayerTest, Miscellaneous3) { + // Add the facts "resolution.x == 250" and "resolution.y == 100". + protobufs::FactSequence facts; + AddConstantUniformFact(&facts, 0, 0, {0, 0}, 250); + AddConstantUniformFact(&facts, 0, 0, {0, 1}, 100); + + // Do some fuzzer runs, starting from an initial seed of 94 (seed value chosen + // arbitrarily). + RunFuzzerAndReplayer(kTestShader3, facts, 94, kNumFuzzerRuns); +} + +TEST(FuzzerReplayerTest, Miscellaneous4) { + // Add the facts: + // - "one == 1.0" + // - "resolution.y == 256.0", + protobufs::FactSequence facts; + AddConstantUniformFact(&facts, 0, 0, {0}, FloatBitsAsUint(1.0)); + AddConstantUniformFact(&facts, 0, 1, {0, 0}, FloatBitsAsUint(256.0)); + AddConstantUniformFact(&facts, 0, 1, {0, 1}, FloatBitsAsUint(256.0)); + + // Do some fuzzer runs, starting from an initial seed of 14 (seed value chosen + // arbitrarily). + RunFuzzerAndReplayer(kTestShader4, facts, 14, kNumFuzzerRuns); +} + +} // namespace +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/test/fuzz/fuzzer_shrinker_test.cpp b/third_party/spirv-tools/test/fuzz/fuzzer_shrinker_test.cpp new file mode 100644 index 0000000000..c906a1e519 --- /dev/null +++ b/third_party/spirv-tools/test/fuzz/fuzzer_shrinker_test.cpp @@ -0,0 +1,1116 @@ +// Copyright (c) 2019 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 +#include + +#include "source/fuzz/fuzzer.h" +#include "source/fuzz/fuzzer_util.h" +#include "source/fuzz/pseudo_random_generator.h" +#include "source/fuzz/shrinker.h" +#include "source/fuzz/uniform_buffer_element_descriptor.h" +#include "test/fuzz/fuzz_test_util.h" + +namespace spvtools { +namespace fuzz { +namespace { + +// The following SPIR-V came from this GLSL: +// +// #version 310 es +// +// void foo() { +// int x; +// x = 2; +// for (int i = 0; i < 100; i++) { +// x += i; +// x = x * 2; +// } +// return; +// } +// +// void main() { +// foo(); +// for (int i = 0; i < 10; i++) { +// int j = 20; +// while(j > 0) { +// foo(); +// j--; +// } +// do { +// i++; +// } while(i < 4); +// } +// } + +const std::string kTestShader1 = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %6 "foo(" + OpName %10 "x" + OpName %12 "i" + OpName %33 "i" + OpName %42 "j" + OpDecorate %10 RelaxedPrecision + OpDecorate %12 RelaxedPrecision + OpDecorate %19 RelaxedPrecision + OpDecorate %23 RelaxedPrecision + OpDecorate %24 RelaxedPrecision + OpDecorate %25 RelaxedPrecision + OpDecorate %26 RelaxedPrecision + OpDecorate %27 RelaxedPrecision + OpDecorate %28 RelaxedPrecision + OpDecorate %30 RelaxedPrecision + OpDecorate %33 RelaxedPrecision + OpDecorate %39 RelaxedPrecision + OpDecorate %42 RelaxedPrecision + OpDecorate %49 RelaxedPrecision + OpDecorate %52 RelaxedPrecision + OpDecorate %53 RelaxedPrecision + OpDecorate %58 RelaxedPrecision + OpDecorate %59 RelaxedPrecision + OpDecorate %60 RelaxedPrecision + OpDecorate %63 RelaxedPrecision + OpDecorate %64 RelaxedPrecision + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %8 = OpTypeInt 32 1 + %9 = OpTypePointer Function %8 + %11 = OpConstant %8 2 + %13 = OpConstant %8 0 + %20 = OpConstant %8 100 + %21 = OpTypeBool + %29 = OpConstant %8 1 + %40 = OpConstant %8 10 + %43 = OpConstant %8 20 + %61 = OpConstant %8 4 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %33 = OpVariable %9 Function + %42 = OpVariable %9 Function + %32 = OpFunctionCall %2 %6 + OpStore %33 %13 + OpBranch %34 + %34 = OpLabel + OpLoopMerge %36 %37 None + OpBranch %38 + %38 = OpLabel + %39 = OpLoad %8 %33 + %41 = OpSLessThan %21 %39 %40 + OpBranchConditional %41 %35 %36 + %35 = OpLabel + OpStore %42 %43 + OpBranch %44 + %44 = OpLabel + OpLoopMerge %46 %47 None + OpBranch %48 + %48 = OpLabel + %49 = OpLoad %8 %42 + %50 = OpSGreaterThan %21 %49 %13 + OpBranchConditional %50 %45 %46 + %45 = OpLabel + %51 = OpFunctionCall %2 %6 + %52 = OpLoad %8 %42 + %53 = OpISub %8 %52 %29 + OpStore %42 %53 + OpBranch %47 + %47 = OpLabel + OpBranch %44 + %46 = OpLabel + OpBranch %54 + %54 = OpLabel + OpLoopMerge %56 %57 None + OpBranch %55 + %55 = OpLabel + %58 = OpLoad %8 %33 + %59 = OpIAdd %8 %58 %29 + OpStore %33 %59 + OpBranch %57 + %57 = OpLabel + %60 = OpLoad %8 %33 + %62 = OpSLessThan %21 %60 %61 + OpBranchConditional %62 %54 %56 + %56 = OpLabel + OpBranch %37 + %37 = OpLabel + %63 = OpLoad %8 %33 + %64 = OpIAdd %8 %63 %29 + OpStore %33 %64 + OpBranch %34 + %36 = OpLabel + OpReturn + OpFunctionEnd + %6 = OpFunction %2 None %3 + %7 = OpLabel + %10 = OpVariable %9 Function + %12 = OpVariable %9 Function + OpStore %10 %11 + OpStore %12 %13 + OpBranch %14 + %14 = OpLabel + OpLoopMerge %16 %17 None + OpBranch %18 + %18 = OpLabel + %19 = OpLoad %8 %12 + %22 = OpSLessThan %21 %19 %20 + OpBranchConditional %22 %15 %16 + %15 = OpLabel + %23 = OpLoad %8 %12 + %24 = OpLoad %8 %10 + %25 = OpIAdd %8 %24 %23 + OpStore %10 %25 + %26 = OpLoad %8 %10 + %27 = OpIMul %8 %26 %11 + OpStore %10 %27 + OpBranch %17 + %17 = OpLabel + %28 = OpLoad %8 %12 + %30 = OpIAdd %8 %28 %29 + OpStore %12 %30 + OpBranch %14 + %16 = OpLabel + OpReturn + OpFunctionEnd + + )"; + +// The following SPIR-V came from this GLSL, which was then optimized using +// spirv-opt with the -O argument: +// +// #version 310 es +// +// precision highp float; +// +// layout(location = 0) out vec4 _GLF_color; +// +// layout(set = 0, binding = 0) uniform buf0 { +// vec2 injectionSwitch; +// }; +// layout(set = 0, binding = 1) uniform buf1 { +// vec2 resolution; +// }; +// bool checkSwap(float a, float b) +// { +// return gl_FragCoord.y < resolution.y / 2.0 ? a > b : a < b; +// } +// void main() +// { +// float data[10]; +// for(int i = 0; i < 10; i++) +// { +// data[i] = float(10 - i) * injectionSwitch.y; +// } +// for(int i = 0; i < 9; i++) +// { +// for(int j = 0; j < 10; j++) +// { +// if(j < i + 1) +// { +// continue; +// } +// bool doSwap = checkSwap(data[i], data[j]); +// if(doSwap) +// { +// float temp = data[i]; +// data[i] = data[j]; +// data[j] = temp; +// } +// } +// } +// if(gl_FragCoord.x < resolution.x / 2.0) +// { +// _GLF_color = vec4(data[0] / 10.0, data[5] / 10.0, data[9] / 10.0, 1.0); +// } +// else +// { +// _GLF_color = vec4(data[5] / 10.0, data[9] / 10.0, data[0] / 10.0, 1.0); +// } +// } + +const std::string kTestShader2 = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" %16 %139 %25 %68 + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %16 "gl_FragCoord" + OpName %23 "buf1" + OpMemberName %23 0 "resolution" + OpName %25 "" + OpName %61 "data" + OpName %66 "buf0" + OpMemberName %66 0 "injectionSwitch" + OpName %68 "" + OpName %139 "_GLF_color" + OpDecorate %16 BuiltIn FragCoord + OpMemberDecorate %23 0 Offset 0 + OpDecorate %23 Block + OpDecorate %25 DescriptorSet 0 + OpDecorate %25 Binding 1 + OpDecorate %64 RelaxedPrecision + OpMemberDecorate %66 0 Offset 0 + OpDecorate %66 Block + OpDecorate %68 DescriptorSet 0 + OpDecorate %68 Binding 0 + OpDecorate %75 RelaxedPrecision + OpDecorate %95 RelaxedPrecision + OpDecorate %126 RelaxedPrecision + OpDecorate %128 RelaxedPrecision + OpDecorate %139 Location 0 + OpDecorate %182 RelaxedPrecision + OpDecorate %183 RelaxedPrecision + OpDecorate %184 RelaxedPrecision + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypePointer Function %6 + %8 = OpTypeBool + %14 = OpTypeVector %6 4 + %15 = OpTypePointer Input %14 + %16 = OpVariable %15 Input + %17 = OpTypeInt 32 0 + %18 = OpConstant %17 1 + %19 = OpTypePointer Input %6 + %22 = OpTypeVector %6 2 + %23 = OpTypeStruct %22 + %24 = OpTypePointer Uniform %23 + %25 = OpVariable %24 Uniform + %26 = OpTypeInt 32 1 + %27 = OpConstant %26 0 + %28 = OpTypePointer Uniform %6 + %56 = OpConstant %26 10 + %58 = OpConstant %17 10 + %59 = OpTypeArray %6 %58 + %60 = OpTypePointer Function %59 + %66 = OpTypeStruct %22 + %67 = OpTypePointer Uniform %66 + %68 = OpVariable %67 Uniform + %74 = OpConstant %26 1 + %83 = OpConstant %26 9 + %129 = OpConstant %17 0 + %138 = OpTypePointer Output %14 + %139 = OpVariable %138 Output + %144 = OpConstant %26 5 + %151 = OpConstant %6 1 + %194 = OpConstant %6 0.5 + %195 = OpConstant %6 0.100000001 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %61 = OpVariable %60 Function + OpBranch %50 + %50 = OpLabel + %182 = OpPhi %26 %27 %5 %75 %51 + %57 = OpSLessThan %8 %182 %56 + OpLoopMerge %52 %51 None + OpBranchConditional %57 %51 %52 + %51 = OpLabel + %64 = OpISub %26 %56 %182 + %65 = OpConvertSToF %6 %64 + %69 = OpAccessChain %28 %68 %27 %18 + %70 = OpLoad %6 %69 + %71 = OpFMul %6 %65 %70 + %72 = OpAccessChain %7 %61 %182 + OpStore %72 %71 + %75 = OpIAdd %26 %182 %74 + OpBranch %50 + %52 = OpLabel + OpBranch %77 + %77 = OpLabel + %183 = OpPhi %26 %27 %52 %128 %88 + %84 = OpSLessThan %8 %183 %83 + OpLoopMerge %79 %88 None + OpBranchConditional %84 %78 %79 + %78 = OpLabel + OpBranch %86 + %86 = OpLabel + %184 = OpPhi %26 %27 %78 %126 %89 + %92 = OpSLessThan %8 %184 %56 + OpLoopMerge %1000 %89 None + OpBranchConditional %92 %87 %1000 + %87 = OpLabel + %95 = OpIAdd %26 %183 %74 + %96 = OpSLessThan %8 %184 %95 + OpSelectionMerge %98 None + OpBranchConditional %96 %97 %98 + %97 = OpLabel + OpBranch %89 + %98 = OpLabel + %104 = OpAccessChain %7 %61 %183 + %105 = OpLoad %6 %104 + %107 = OpAccessChain %7 %61 %184 + %108 = OpLoad %6 %107 + %166 = OpAccessChain %19 %16 %18 + %167 = OpLoad %6 %166 + %168 = OpAccessChain %28 %25 %27 %18 + %169 = OpLoad %6 %168 + %170 = OpFMul %6 %169 %194 + %171 = OpFOrdLessThan %8 %167 %170 + OpSelectionMerge %172 None + OpBranchConditional %171 %173 %174 + %173 = OpLabel + %177 = OpFOrdGreaterThan %8 %105 %108 + OpBranch %172 + %174 = OpLabel + %180 = OpFOrdLessThan %8 %105 %108 + OpBranch %172 + %172 = OpLabel + %186 = OpPhi %8 %177 %173 %180 %174 + OpSelectionMerge %112 None + OpBranchConditional %186 %111 %112 + %111 = OpLabel + %116 = OpLoad %6 %104 + %120 = OpLoad %6 %107 + OpStore %104 %120 + OpStore %107 %116 + OpBranch %112 + %112 = OpLabel + OpBranch %89 + %89 = OpLabel + %126 = OpIAdd %26 %184 %74 + OpBranch %86 + %1000 = OpLabel + OpBranch %88 + %88 = OpLabel + %128 = OpIAdd %26 %183 %74 + OpBranch %77 + %79 = OpLabel + %130 = OpAccessChain %19 %16 %129 + %131 = OpLoad %6 %130 + %132 = OpAccessChain %28 %25 %27 %129 + %133 = OpLoad %6 %132 + %134 = OpFMul %6 %133 %194 + %135 = OpFOrdLessThan %8 %131 %134 + OpSelectionMerge %137 None + OpBranchConditional %135 %136 %153 + %136 = OpLabel + %140 = OpAccessChain %7 %61 %27 + %141 = OpLoad %6 %140 + %143 = OpFMul %6 %141 %195 + %145 = OpAccessChain %7 %61 %144 + %146 = OpLoad %6 %145 + %147 = OpFMul %6 %146 %195 + %148 = OpAccessChain %7 %61 %83 + %149 = OpLoad %6 %148 + %150 = OpFMul %6 %149 %195 + %152 = OpCompositeConstruct %14 %143 %147 %150 %151 + OpStore %139 %152 + OpBranch %137 + %153 = OpLabel + %154 = OpAccessChain %7 %61 %144 + %155 = OpLoad %6 %154 + %156 = OpFMul %6 %155 %195 + %157 = OpAccessChain %7 %61 %83 + %158 = OpLoad %6 %157 + %159 = OpFMul %6 %158 %195 + %160 = OpAccessChain %7 %61 %27 + %161 = OpLoad %6 %160 + %162 = OpFMul %6 %161 %195 + %163 = OpCompositeConstruct %14 %156 %159 %162 %151 + OpStore %139 %163 + OpBranch %137 + %137 = OpLabel + OpReturn + OpFunctionEnd + )"; + +// The following SPIR-V came from this GLSL, which was then optimized using +// spirv-opt with the -O argument: +// +// #version 310 es +// +// precision highp float; +// +// layout(location = 0) out vec4 _GLF_color; +// +// layout(set = 0, binding = 0) uniform buf0 { +// vec2 resolution; +// }; +// void main(void) +// { +// float A[50]; +// for( +// int i = 0; +// i < 200; +// i ++ +// ) +// { +// if(i >= int(resolution.x)) +// { +// break; +// } +// if((4 * (i / 4)) == i) +// { +// A[i / 4] = float(i); +// } +// } +// for( +// int i = 0; +// i < 50; +// i ++ +// ) +// { +// if(i < int(gl_FragCoord.x)) +// { +// break; +// } +// if(i > 0) +// { +// A[i] += A[i - 1]; +// } +// } +// if(int(gl_FragCoord.x) < 20) +// { +// _GLF_color = vec4(A[0] / resolution.x, A[4] / resolution.y, 1.0, 1.0); +// } +// else +// if(int(gl_FragCoord.x) < 40) +// { +// _GLF_color = vec4(A[5] / resolution.x, A[9] / resolution.y, 1.0, 1.0); +// } +// else +// if(int(gl_FragCoord.x) < 60) +// { +// _GLF_color = vec4(A[10] / resolution.x, A[14] / resolution.y, +// 1.0, 1.0); +// } +// else +// if(int(gl_FragCoord.x) < 80) +// { +// _GLF_color = vec4(A[15] / resolution.x, A[19] / resolution.y, +// 1.0, 1.0); +// } +// else +// if(int(gl_FragCoord.x) < 100) +// { +// _GLF_color = vec4(A[20] / resolution.x, A[24] / resolution.y, +// 1.0, 1.0); +// } +// else +// if(int(gl_FragCoord.x) < 120) +// { +// _GLF_color = vec4(A[25] / resolution.x, A[29] / resolution.y, +// 1.0, 1.0); +// } +// else +// if(int(gl_FragCoord.x) < 140) +// { +// _GLF_color = vec4(A[30] / resolution.x, A[34] / resolution.y, +// 1.0, 1.0); +// } +// else +// if(int(gl_FragCoord.x) < 160) +// { +// _GLF_color = vec4(A[35] / resolution.x, A[39] / +// resolution.y, 1.0, 1.0); +// } +// else +// if(int(gl_FragCoord.x) < 180) +// { +// _GLF_color = vec4(A[40] / resolution.x, A[44] / +// resolution.y, 1.0, 1.0); +// } +// else +// if(int(gl_FragCoord.x) < 180) +// { +// _GLF_color = vec4(A[45] / resolution.x, A[49] / +// resolution.y, 1.0, 1.0); +// } +// else +// { +// discard; +// } +// } + +const std::string kTestShader3 = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" %68 %100 %24 + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %22 "buf0" + OpMemberName %22 0 "resolution" + OpName %24 "" + OpName %46 "A" + OpName %68 "gl_FragCoord" + OpName %100 "_GLF_color" + OpMemberDecorate %22 0 Offset 0 + OpDecorate %22 Block + OpDecorate %24 DescriptorSet 0 + OpDecorate %24 Binding 0 + OpDecorate %37 RelaxedPrecision + OpDecorate %38 RelaxedPrecision + OpDecorate %55 RelaxedPrecision + OpDecorate %68 BuiltIn FragCoord + OpDecorate %83 RelaxedPrecision + OpDecorate %91 RelaxedPrecision + OpDecorate %100 Location 0 + OpDecorate %302 RelaxedPrecision + OpDecorate %304 RelaxedPrecision + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %9 = OpConstant %6 0 + %16 = OpConstant %6 200 + %17 = OpTypeBool + %20 = OpTypeFloat 32 + %21 = OpTypeVector %20 2 + %22 = OpTypeStruct %21 + %23 = OpTypePointer Uniform %22 + %24 = OpVariable %23 Uniform + %25 = OpTypeInt 32 0 + %26 = OpConstant %25 0 + %27 = OpTypePointer Uniform %20 + %35 = OpConstant %6 4 + %43 = OpConstant %25 50 + %44 = OpTypeArray %20 %43 + %45 = OpTypePointer Function %44 + %51 = OpTypePointer Function %20 + %54 = OpConstant %6 1 + %63 = OpConstant %6 50 + %66 = OpTypeVector %20 4 + %67 = OpTypePointer Input %66 + %68 = OpVariable %67 Input + %69 = OpTypePointer Input %20 + %95 = OpConstant %6 20 + %99 = OpTypePointer Output %66 + %100 = OpVariable %99 Output + %108 = OpConstant %25 1 + %112 = OpConstant %20 1 + %118 = OpConstant %6 40 + %122 = OpConstant %6 5 + %128 = OpConstant %6 9 + %139 = OpConstant %6 60 + %143 = OpConstant %6 10 + %149 = OpConstant %6 14 + %160 = OpConstant %6 80 + %164 = OpConstant %6 15 + %170 = OpConstant %6 19 + %181 = OpConstant %6 100 + %190 = OpConstant %6 24 + %201 = OpConstant %6 120 + %205 = OpConstant %6 25 + %211 = OpConstant %6 29 + %222 = OpConstant %6 140 + %226 = OpConstant %6 30 + %232 = OpConstant %6 34 + %243 = OpConstant %6 160 + %247 = OpConstant %6 35 + %253 = OpConstant %6 39 + %264 = OpConstant %6 180 + %273 = OpConstant %6 44 + %287 = OpConstant %6 45 + %293 = OpConstant %6 49 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %46 = OpVariable %45 Function + OpBranch %10 + %10 = OpLabel + %302 = OpPhi %6 %9 %5 %55 %42 + %18 = OpSLessThan %17 %302 %16 + OpLoopMerge %12 %42 None + OpBranchConditional %18 %11 %12 + %11 = OpLabel + %28 = OpAccessChain %27 %24 %9 %26 + %29 = OpLoad %20 %28 + %30 = OpConvertFToS %6 %29 + %31 = OpSGreaterThanEqual %17 %302 %30 + OpSelectionMerge %33 None + OpBranchConditional %31 %32 %33 + %32 = OpLabel + OpBranch %12 + %33 = OpLabel + %37 = OpSDiv %6 %302 %35 + %38 = OpIMul %6 %35 %37 + %40 = OpIEqual %17 %38 %302 + OpBranchConditional %40 %41 %42 + %41 = OpLabel + %50 = OpConvertSToF %20 %302 + %52 = OpAccessChain %51 %46 %37 + OpStore %52 %50 + OpBranch %42 + %42 = OpLabel + %55 = OpIAdd %6 %302 %54 + OpBranch %10 + %12 = OpLabel + OpBranch %57 + %57 = OpLabel + %304 = OpPhi %6 %9 %12 %91 %80 + %64 = OpSLessThan %17 %304 %63 + OpLoopMerge %59 %80 None + OpBranchConditional %64 %58 %59 + %58 = OpLabel + %70 = OpAccessChain %69 %68 %26 + %71 = OpLoad %20 %70 + %72 = OpConvertFToS %6 %71 + %73 = OpSLessThan %17 %304 %72 + OpSelectionMerge %75 None + OpBranchConditional %73 %74 %75 + %74 = OpLabel + OpBranch %59 + %75 = OpLabel + %78 = OpSGreaterThan %17 %304 %9 + OpBranchConditional %78 %79 %80 + %79 = OpLabel + %83 = OpISub %6 %304 %54 + %84 = OpAccessChain %51 %46 %83 + %85 = OpLoad %20 %84 + %86 = OpAccessChain %51 %46 %304 + %87 = OpLoad %20 %86 + %88 = OpFAdd %20 %87 %85 + OpStore %86 %88 + OpBranch %80 + %80 = OpLabel + %91 = OpIAdd %6 %304 %54 + OpBranch %57 + %59 = OpLabel + %92 = OpAccessChain %69 %68 %26 + %93 = OpLoad %20 %92 + %94 = OpConvertFToS %6 %93 + %96 = OpSLessThan %17 %94 %95 + OpSelectionMerge %98 None + OpBranchConditional %96 %97 %114 + %97 = OpLabel + %101 = OpAccessChain %51 %46 %9 + %102 = OpLoad %20 %101 + %103 = OpAccessChain %27 %24 %9 %26 + %104 = OpLoad %20 %103 + %105 = OpFDiv %20 %102 %104 + %106 = OpAccessChain %51 %46 %35 + %107 = OpLoad %20 %106 + %109 = OpAccessChain %27 %24 %9 %108 + %110 = OpLoad %20 %109 + %111 = OpFDiv %20 %107 %110 + %113 = OpCompositeConstruct %66 %105 %111 %112 %112 + OpStore %100 %113 + OpBranch %98 + %114 = OpLabel + %119 = OpSLessThan %17 %94 %118 + OpSelectionMerge %121 None + OpBranchConditional %119 %120 %135 + %120 = OpLabel + %123 = OpAccessChain %51 %46 %122 + %124 = OpLoad %20 %123 + %125 = OpAccessChain %27 %24 %9 %26 + %126 = OpLoad %20 %125 + %127 = OpFDiv %20 %124 %126 + %129 = OpAccessChain %51 %46 %128 + %130 = OpLoad %20 %129 + %131 = OpAccessChain %27 %24 %9 %108 + %132 = OpLoad %20 %131 + %133 = OpFDiv %20 %130 %132 + %134 = OpCompositeConstruct %66 %127 %133 %112 %112 + OpStore %100 %134 + OpBranch %121 + %135 = OpLabel + %140 = OpSLessThan %17 %94 %139 + OpSelectionMerge %142 None + OpBranchConditional %140 %141 %156 + %141 = OpLabel + %144 = OpAccessChain %51 %46 %143 + %145 = OpLoad %20 %144 + %146 = OpAccessChain %27 %24 %9 %26 + %147 = OpLoad %20 %146 + %148 = OpFDiv %20 %145 %147 + %150 = OpAccessChain %51 %46 %149 + %151 = OpLoad %20 %150 + %152 = OpAccessChain %27 %24 %9 %108 + %153 = OpLoad %20 %152 + %154 = OpFDiv %20 %151 %153 + %155 = OpCompositeConstruct %66 %148 %154 %112 %112 + OpStore %100 %155 + OpBranch %142 + %156 = OpLabel + %161 = OpSLessThan %17 %94 %160 + OpSelectionMerge %163 None + OpBranchConditional %161 %162 %177 + %162 = OpLabel + %165 = OpAccessChain %51 %46 %164 + %166 = OpLoad %20 %165 + %167 = OpAccessChain %27 %24 %9 %26 + %168 = OpLoad %20 %167 + %169 = OpFDiv %20 %166 %168 + %171 = OpAccessChain %51 %46 %170 + %172 = OpLoad %20 %171 + %173 = OpAccessChain %27 %24 %9 %108 + %174 = OpLoad %20 %173 + %175 = OpFDiv %20 %172 %174 + %176 = OpCompositeConstruct %66 %169 %175 %112 %112 + OpStore %100 %176 + OpBranch %163 + %177 = OpLabel + %182 = OpSLessThan %17 %94 %181 + OpSelectionMerge %184 None + OpBranchConditional %182 %183 %197 + %183 = OpLabel + %185 = OpAccessChain %51 %46 %95 + %186 = OpLoad %20 %185 + %187 = OpAccessChain %27 %24 %9 %26 + %188 = OpLoad %20 %187 + %189 = OpFDiv %20 %186 %188 + %191 = OpAccessChain %51 %46 %190 + %192 = OpLoad %20 %191 + %193 = OpAccessChain %27 %24 %9 %108 + %194 = OpLoad %20 %193 + %195 = OpFDiv %20 %192 %194 + %196 = OpCompositeConstruct %66 %189 %195 %112 %112 + OpStore %100 %196 + OpBranch %184 + %197 = OpLabel + %202 = OpSLessThan %17 %94 %201 + OpSelectionMerge %204 None + OpBranchConditional %202 %203 %218 + %203 = OpLabel + %206 = OpAccessChain %51 %46 %205 + %207 = OpLoad %20 %206 + %208 = OpAccessChain %27 %24 %9 %26 + %209 = OpLoad %20 %208 + %210 = OpFDiv %20 %207 %209 + %212 = OpAccessChain %51 %46 %211 + %213 = OpLoad %20 %212 + %214 = OpAccessChain %27 %24 %9 %108 + %215 = OpLoad %20 %214 + %216 = OpFDiv %20 %213 %215 + %217 = OpCompositeConstruct %66 %210 %216 %112 %112 + OpStore %100 %217 + OpBranch %204 + %218 = OpLabel + %223 = OpSLessThan %17 %94 %222 + OpSelectionMerge %225 None + OpBranchConditional %223 %224 %239 + %224 = OpLabel + %227 = OpAccessChain %51 %46 %226 + %228 = OpLoad %20 %227 + %229 = OpAccessChain %27 %24 %9 %26 + %230 = OpLoad %20 %229 + %231 = OpFDiv %20 %228 %230 + %233 = OpAccessChain %51 %46 %232 + %234 = OpLoad %20 %233 + %235 = OpAccessChain %27 %24 %9 %108 + %236 = OpLoad %20 %235 + %237 = OpFDiv %20 %234 %236 + %238 = OpCompositeConstruct %66 %231 %237 %112 %112 + OpStore %100 %238 + OpBranch %225 + %239 = OpLabel + %244 = OpSLessThan %17 %94 %243 + OpSelectionMerge %246 None + OpBranchConditional %244 %245 %260 + %245 = OpLabel + %248 = OpAccessChain %51 %46 %247 + %249 = OpLoad %20 %248 + %250 = OpAccessChain %27 %24 %9 %26 + %251 = OpLoad %20 %250 + %252 = OpFDiv %20 %249 %251 + %254 = OpAccessChain %51 %46 %253 + %255 = OpLoad %20 %254 + %256 = OpAccessChain %27 %24 %9 %108 + %257 = OpLoad %20 %256 + %258 = OpFDiv %20 %255 %257 + %259 = OpCompositeConstruct %66 %252 %258 %112 %112 + OpStore %100 %259 + OpBranch %246 + %260 = OpLabel + %265 = OpSLessThan %17 %94 %264 + OpSelectionMerge %267 None + OpBranchConditional %265 %266 %280 + %266 = OpLabel + %268 = OpAccessChain %51 %46 %118 + %269 = OpLoad %20 %268 + %270 = OpAccessChain %27 %24 %9 %26 + %271 = OpLoad %20 %270 + %272 = OpFDiv %20 %269 %271 + %274 = OpAccessChain %51 %46 %273 + %275 = OpLoad %20 %274 + %276 = OpAccessChain %27 %24 %9 %108 + %277 = OpLoad %20 %276 + %278 = OpFDiv %20 %275 %277 + %279 = OpCompositeConstruct %66 %272 %278 %112 %112 + OpStore %100 %279 + OpBranch %267 + %280 = OpLabel + OpSelectionMerge %285 None + OpBranchConditional %265 %285 %300 + %285 = OpLabel + %288 = OpAccessChain %51 %46 %287 + %289 = OpLoad %20 %288 + %290 = OpAccessChain %27 %24 %9 %26 + %291 = OpLoad %20 %290 + %292 = OpFDiv %20 %289 %291 + %294 = OpAccessChain %51 %46 %293 + %295 = OpLoad %20 %294 + %296 = OpAccessChain %27 %24 %9 %108 + %297 = OpLoad %20 %296 + %298 = OpFDiv %20 %295 %297 + %299 = OpCompositeConstruct %66 %292 %298 %112 %112 + OpStore %100 %299 + OpBranch %267 + %300 = OpLabel + OpKill + %267 = OpLabel + OpBranch %246 + %246 = OpLabel + OpBranch %225 + %225 = OpLabel + OpBranch %204 + %204 = OpLabel + OpBranch %184 + %184 = OpLabel + OpBranch %163 + %163 = OpLabel + OpBranch %142 + %142 = OpLabel + OpBranch %121 + %121 = OpLabel + OpBranch %98 + %98 = OpLabel + OpReturn + OpFunctionEnd + )"; + +// Abstract class exposing an interestingness function as a virtual method. +class InterestingnessTest { + public: + virtual ~InterestingnessTest() = default; + + // Abstract method that subclasses should implement for specific notions of + // interestingness. Its signature matches Shrinker::InterestingnessFunction. + // Argument |binary| is the SPIR-V binary to be checked; |counter| is used for + // debugging purposes. + virtual bool Interesting(const std::vector& binary, + uint32_t counter) = 0; + + // Yields the Interesting instance method wrapped in a function object. + Shrinker::InterestingnessFunction AsFunction() { + return std::bind(&InterestingnessTest::Interesting, this, + std::placeholders::_1, std::placeholders::_2); + } +}; + +// A test that says all binaries are interesting. +class AlwaysInteresting : public InterestingnessTest { + public: + bool Interesting(const std::vector&, uint32_t) override { + return true; + } +}; + +// A test that says a binary is interesting first time round, and uninteresting +// thereafter. +class OnlyInterestingFirstTime : public InterestingnessTest { + public: + explicit OnlyInterestingFirstTime() : first_time_(true) {} + + bool Interesting(const std::vector&, uint32_t) override { + if (first_time_) { + first_time_ = false; + return true; + } + return false; + } + + private: + bool first_time_; +}; + +// A test that says a binary is interesting first time round, after which +// interestingness ping pongs between false and true. +class PingPong : public InterestingnessTest { + public: + explicit PingPong() : interesting_(false) {} + + bool Interesting(const std::vector&, uint32_t) override { + interesting_ = !interesting_; + return interesting_; + } + + private: + bool interesting_; +}; + +// A test that says a binary is interesting first time round, thereafter +// decides at random whether it is interesting. This allows the logic of the +// shrinker to be exercised quite a bit. +class InterestingThenRandom : public InterestingnessTest { + public: + InterestingThenRandom(const PseudoRandomGenerator& random_generator) + : first_time_(true), random_generator_(random_generator) {} + + bool Interesting(const std::vector&, uint32_t) override { + if (first_time_) { + first_time_ = false; + return true; + } + return random_generator_.RandomBool(); + } + + private: + bool first_time_; + PseudoRandomGenerator random_generator_; +}; + +// |binary_in| and |initial_facts| are a SPIR-V binary and sequence of facts to +// which |transformation_sequence_in| can be applied. Shrinking of +// |transformation_sequence_in| gets performed with respect to +// |interestingness_function|. If |expected_binary_out| is non-empty, it must +// match the binary obtained by applying the final shrunk set of +// transformations, in which case the number of such transformations should +// equal |expected_transformations_out_size|. +// +// The |step_limit| parameter restricts the number of steps that the shrinker +// will try; it can be set to something small for a faster (but less thorough) +// test. +void RunAndCheckShrinker( + const spv_target_env& target_env, const std::vector& binary_in, + const protobufs::FactSequence& initial_facts, + const protobufs::TransformationSequence& transformation_sequence_in, + const Shrinker::InterestingnessFunction& interestingness_function, + const std::vector& expected_binary_out, + uint32_t expected_transformations_out_size, uint32_t step_limit) { + // Run the shrinker. + Shrinker shrinker(target_env, step_limit, false); + shrinker.SetMessageConsumer(kSilentConsumer); + + std::vector binary_out; + protobufs::TransformationSequence transformations_out; + Shrinker::ShrinkerResultStatus shrinker_result_status = + shrinker.Run(binary_in, initial_facts, transformation_sequence_in, + interestingness_function, &binary_out, &transformations_out); + ASSERT_TRUE(Shrinker::ShrinkerResultStatus::kComplete == + shrinker_result_status || + Shrinker::ShrinkerResultStatus::kStepLimitReached == + shrinker_result_status); + + // If a non-empty expected binary was provided, check that it matches the + // result of shrinking and that the expected number of transformations remain. + if (!expected_binary_out.empty()) { + ASSERT_EQ(expected_binary_out, binary_out); + ASSERT_EQ(expected_transformations_out_size, + static_cast(transformations_out.transformation_size())); + } +} + +// Assembles the given |shader| text, and then: +// - Runs the fuzzer with |seed| to yield a set of transformations +// - Shrinks the transformation with various interestingness functions, +// asserting some properties about the result each time +void RunFuzzerAndShrinker(const std::string& shader, + const protobufs::FactSequence& initial_facts, + uint32_t seed) { + const auto env = SPV_ENV_UNIVERSAL_1_5; + + std::vector binary_in; + SpirvTools t(env); + t.SetMessageConsumer(kConsoleMessageConsumer); + ASSERT_TRUE(t.Assemble(shader, &binary_in, kFuzzAssembleOption)); + ASSERT_TRUE(t.Validate(binary_in)); + + std::vector donor_suppliers; + for (auto donor : {&kTestShader1, &kTestShader2, &kTestShader3}) { + donor_suppliers.emplace_back([donor]() { + return BuildModule(env, kConsoleMessageConsumer, *donor, + kFuzzAssembleOption); + }); + } + + // Run the fuzzer and check that it successfully yields a valid binary. + std::vector fuzzer_binary_out; + protobufs::TransformationSequence fuzzer_transformation_sequence_out; + Fuzzer fuzzer(env, seed, true); + fuzzer.SetMessageConsumer(kSilentConsumer); + auto fuzzer_result_status = + fuzzer.Run(binary_in, initial_facts, donor_suppliers, &fuzzer_binary_out, + &fuzzer_transformation_sequence_out); + ASSERT_EQ(Fuzzer::FuzzerResultStatus::kComplete, fuzzer_result_status); + ASSERT_TRUE(t.Validate(fuzzer_binary_out)); + + const uint32_t kReasonableStepLimit = 50; + const uint32_t kSmallStepLimit = 20; + + // With the AlwaysInteresting test, we should quickly shrink to the original + // binary with no transformations remaining. + RunAndCheckShrinker( + env, binary_in, initial_facts, fuzzer_transformation_sequence_out, + AlwaysInteresting().AsFunction(), binary_in, 0, kReasonableStepLimit); + + // With the OnlyInterestingFirstTime test, no shrinking should be achieved. + RunAndCheckShrinker( + env, binary_in, initial_facts, fuzzer_transformation_sequence_out, + OnlyInterestingFirstTime().AsFunction(), fuzzer_binary_out, + static_cast( + fuzzer_transformation_sequence_out.transformation_size()), + kReasonableStepLimit); + + // The PingPong test is unpredictable; passing an empty expected binary + // means that we don't check anything beyond that shrinking completes + // successfully. + RunAndCheckShrinker(env, binary_in, initial_facts, + fuzzer_transformation_sequence_out, + PingPong().AsFunction(), {}, 0, kSmallStepLimit); + + // The InterestingThenRandom test is unpredictable; passing an empty + // expected binary means that we do not check anything about shrinking + // results. + RunAndCheckShrinker( + env, binary_in, initial_facts, fuzzer_transformation_sequence_out, + InterestingThenRandom(PseudoRandomGenerator(seed)).AsFunction(), {}, 0, + kSmallStepLimit); +} + +TEST(FuzzerShrinkerTest, Miscellaneous1) { + RunFuzzerAndShrinker(kTestShader1, protobufs::FactSequence(), 2); +} + +TEST(FuzzerShrinkerTest, Miscellaneous2) { + RunFuzzerAndShrinker(kTestShader2, protobufs::FactSequence(), 19); +} + +TEST(FuzzerShrinkerTest, Miscellaneous3) { + // Add the facts "resolution.x == 250" and "resolution.y == 100". + protobufs::FactSequence facts; + { + protobufs::FactConstantUniform resolution_x_eq_250; + *resolution_x_eq_250.mutable_uniform_buffer_element_descriptor() = + MakeUniformBufferElementDescriptor(0, 0, {0, 0}); + *resolution_x_eq_250.mutable_constant_word()->Add() = 250; + protobufs::Fact temp; + *temp.mutable_constant_uniform_fact() = resolution_x_eq_250; + *facts.mutable_fact()->Add() = temp; + } + { + protobufs::FactConstantUniform resolution_y_eq_100; + *resolution_y_eq_100.mutable_uniform_buffer_element_descriptor() = + MakeUniformBufferElementDescriptor(0, 0, {0, 1}); + *resolution_y_eq_100.mutable_constant_word()->Add() = 100; + protobufs::Fact temp; + *temp.mutable_constant_uniform_fact() = resolution_y_eq_100; + *facts.mutable_fact()->Add() = temp; + } + + // Do 2 fuzzer runs, starting from an initial seed of 194 (seed value chosen + // arbitrarily). + RunFuzzerAndShrinker(kTestShader3, facts, 194); +} + +} // namespace +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/test/fuzz/instruction_descriptor_test.cpp b/third_party/spirv-tools/test/fuzz/instruction_descriptor_test.cpp new file mode 100644 index 0000000000..5165cfb07a --- /dev/null +++ b/third_party/spirv-tools/test/fuzz/instruction_descriptor_test.cpp @@ -0,0 +1,69 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/instruction_descriptor.h" +#include "test/fuzz/fuzz_test_util.h" + +namespace spvtools { +namespace fuzz { +namespace { + +TEST(InstructionDescriptorTest, BasicTest) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 0 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 0 + %10 = OpTypeInt 32 1 + %11 = OpTypePointer Function %10 + %13 = OpConstant %10 2 + %32 = OpConstant %10 0 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %164 = OpVariable %11 Function + %165 = OpVariable %11 Function + OpBranch %16 + %16 = OpLabel + OpStore %164 %32 + OpStore %165 %13 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + for (auto& function : *context->module()) { + for (auto& block : function) { + for (auto inst_it = block.cbegin(); inst_it != block.cend(); ++inst_it) { + ASSERT_EQ(&*inst_it, + FindInstruction(MakeInstructionDescriptor(block, inst_it), + context.get())); + } + } + } +} + +} // namespace +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/test/fuzz/transformation_add_constant_boolean_test.cpp b/third_party/spirv-tools/test/fuzz/transformation_add_constant_boolean_test.cpp new file mode 100644 index 0000000000..f51c46bf41 --- /dev/null +++ b/third_party/spirv-tools/test/fuzz/transformation_add_constant_boolean_test.cpp @@ -0,0 +1,141 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_add_constant_boolean.h" +#include "test/fuzz/fuzz_test_util.h" + +namespace spvtools { +namespace fuzz { +namespace { + +TEST(TransformationAddConstantBooleanTest, NeitherPresentInitiallyAddBoth) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %6 = OpTypeBool + %3 = OpTypeFunction %2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + // True and false can both be added as neither is present. + ASSERT_TRUE(TransformationAddConstantBoolean(7, true).IsApplicable( + context.get(), fact_manager)); + ASSERT_TRUE(TransformationAddConstantBoolean(7, false).IsApplicable( + context.get(), fact_manager)); + + // Id 5 is already taken. + ASSERT_FALSE(TransformationAddConstantBoolean(5, true).IsApplicable( + context.get(), fact_manager)); + + auto add_true = TransformationAddConstantBoolean(7, true); + auto add_false = TransformationAddConstantBoolean(8, false); + + ASSERT_TRUE(add_true.IsApplicable(context.get(), fact_manager)); + add_true.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + // Having added true, we cannot add it again with the same id. + ASSERT_FALSE(add_true.IsApplicable(context.get(), fact_manager)); + // But we can add it with a different id. + auto add_true_again = TransformationAddConstantBoolean(100, true); + ASSERT_TRUE(add_true_again.IsApplicable(context.get(), fact_manager)); + add_true_again.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(add_false.IsApplicable(context.get(), fact_manager)); + add_false.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + // Having added false, we cannot add it again with the same id. + ASSERT_FALSE(add_false.IsApplicable(context.get(), fact_manager)); + // But we can add it with a different id. + auto add_false_again = TransformationAddConstantBoolean(101, false); + ASSERT_TRUE(add_false_again.IsApplicable(context.get(), fact_manager)); + add_false_again.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %6 = OpTypeBool + %3 = OpTypeFunction %2 + %7 = OpConstantTrue %6 + %100 = OpConstantTrue %6 + %8 = OpConstantFalse %6 + %101 = OpConstantFalse %6 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +TEST(TransformationAddConstantBooleanTest, NoOpTypeBoolPresent) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + // Neither true nor false can be added as OpTypeBool is not present. + ASSERT_FALSE(TransformationAddConstantBoolean(6, true).IsApplicable( + context.get(), fact_manager)); + ASSERT_FALSE(TransformationAddConstantBoolean(6, false).IsApplicable( + context.get(), fact_manager)); +} + +} // namespace +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/test/fuzz/transformation_add_constant_composite_test.cpp b/third_party/spirv-tools/test/fuzz/transformation_add_constant_composite_test.cpp new file mode 100644 index 0000000000..5ce171ba9b --- /dev/null +++ b/third_party/spirv-tools/test/fuzz/transformation_add_constant_composite_test.cpp @@ -0,0 +1,158 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_add_constant_composite.h" +#include "test/fuzz/fuzz_test_util.h" + +namespace spvtools { +namespace fuzz { +namespace { + +TEST(TransformationAddConstantCompositeTest, BasicTest) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypeVector %6 2 + %8 = OpTypeMatrix %7 3 + %11 = OpConstant %6 0 + %12 = OpConstant %6 1 + %14 = OpConstant %6 2 + %15 = OpConstant %6 3 + %17 = OpConstant %6 4 + %18 = OpConstant %6 5 + %21 = OpTypeInt 32 1 + %22 = OpTypeInt 32 0 + %23 = OpConstant %22 3 + %24 = OpTypeArray %21 %23 + %25 = OpTypeBool + %26 = OpTypeStruct %24 %25 + %29 = OpConstant %21 1 + %30 = OpConstant %21 2 + %31 = OpConstant %21 3 + %33 = OpConstantFalse %25 + %35 = OpTypeVector %6 3 + %38 = OpConstant %6 6 + %39 = OpConstant %6 7 + %40 = OpConstant %6 8 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + // Too few ids + ASSERT_FALSE(TransformationAddConstantComposite(103, 8, {100, 101}) + .IsApplicable(context.get(), fact_manager)); + // Too many ids + ASSERT_FALSE(TransformationAddConstantComposite(101, 7, {14, 15, 14}) + .IsApplicable(context.get(), fact_manager)); + // Id already in use + ASSERT_FALSE(TransformationAddConstantComposite(40, 7, {11, 12}) + .IsApplicable(context.get(), fact_manager)); + // %39 is not a type + ASSERT_FALSE(TransformationAddConstantComposite(100, 39, {11, 12}) + .IsApplicable(context.get(), fact_manager)); + + TransformationAddConstantComposite transformations[] = { + // %100 = OpConstantComposite %7 %11 %12 + TransformationAddConstantComposite(100, 7, {11, 12}), + + // %101 = OpConstantComposite %7 %14 %15 + TransformationAddConstantComposite(101, 7, {14, 15}), + + // %102 = OpConstantComposite %7 %17 %18 + TransformationAddConstantComposite(102, 7, {17, 18}), + + // %103 = OpConstantComposite %8 %100 %101 %102 + TransformationAddConstantComposite(103, 8, {100, 101, 102}), + + // %104 = OpConstantComposite %24 %29 %30 %31 + TransformationAddConstantComposite(104, 24, {29, 30, 31}), + + // %105 = OpConstantComposite %26 %104 %33 + TransformationAddConstantComposite(105, 26, {104, 33}), + + // %106 = OpConstantComposite %35 %38 %39 %40 + TransformationAddConstantComposite(106, 35, {38, 39, 40})}; + + for (auto& transformation : transformations) { + ASSERT_TRUE(transformation.IsApplicable(context.get(), fact_manager)); + transformation.Apply(context.get(), &fact_manager); + } + ASSERT_TRUE(IsValid(env, context.get())); + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypeVector %6 2 + %8 = OpTypeMatrix %7 3 + %11 = OpConstant %6 0 + %12 = OpConstant %6 1 + %14 = OpConstant %6 2 + %15 = OpConstant %6 3 + %17 = OpConstant %6 4 + %18 = OpConstant %6 5 + %21 = OpTypeInt 32 1 + %22 = OpTypeInt 32 0 + %23 = OpConstant %22 3 + %24 = OpTypeArray %21 %23 + %25 = OpTypeBool + %26 = OpTypeStruct %24 %25 + %29 = OpConstant %21 1 + %30 = OpConstant %21 2 + %31 = OpConstant %21 3 + %33 = OpConstantFalse %25 + %35 = OpTypeVector %6 3 + %38 = OpConstant %6 6 + %39 = OpConstant %6 7 + %40 = OpConstant %6 8 + %100 = OpConstantComposite %7 %11 %12 + %101 = OpConstantComposite %7 %14 %15 + %102 = OpConstantComposite %7 %17 %18 + %103 = OpConstantComposite %8 %100 %101 %102 + %104 = OpConstantComposite %24 %29 %30 %31 + %105 = OpConstantComposite %26 %104 %33 + %106 = OpConstantComposite %35 %38 %39 %40 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +} // namespace +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/test/fuzz/transformation_add_constant_scalar_test.cpp b/third_party/spirv-tools/test/fuzz/transformation_add_constant_scalar_test.cpp new file mode 100644 index 0000000000..b15611124e --- /dev/null +++ b/third_party/spirv-tools/test/fuzz/transformation_add_constant_scalar_test.cpp @@ -0,0 +1,187 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_add_constant_scalar.h" +#include "test/fuzz/fuzz_test_util.h" + +namespace spvtools { +namespace fuzz { +namespace { + +TEST(TransformationAddConstantScalarTest, BasicTest) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %8 "x" + OpName %12 "y" + OpName %16 "z" + OpDecorate %8 RelaxedPrecision + OpDecorate %12 RelaxedPrecision + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 1 + %10 = OpTypeInt 32 0 + %11 = OpTypePointer Function %10 + %13 = OpConstant %10 2 + %14 = OpTypeFloat 32 + %15 = OpTypePointer Function %14 + %17 = OpConstant %14 3 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %12 = OpVariable %11 Function + %16 = OpVariable %15 Function + OpStore %8 %9 + OpStore %12 %13 + OpStore %16 %17 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + const float float_values[2] = {3.0, 30.0}; + uint32_t uint_for_float[2]; + memcpy(uint_for_float, float_values, sizeof(float_values)); + + auto add_signed_int_1 = TransformationAddConstantScalar(100, 6, {1}); + auto add_signed_int_10 = TransformationAddConstantScalar(101, 6, {10}); + auto add_unsigned_int_2 = TransformationAddConstantScalar(102, 10, {2}); + auto add_unsigned_int_20 = TransformationAddConstantScalar(103, 10, {20}); + auto add_float_3 = + TransformationAddConstantScalar(104, 14, {uint_for_float[0]}); + auto add_float_30 = + TransformationAddConstantScalar(105, 14, {uint_for_float[1]}); + auto bad_add_float_30_id_already_used = + TransformationAddConstantScalar(104, 14, {uint_for_float[1]}); + auto bad_id_already_used = TransformationAddConstantScalar(1, 6, {1}); + auto bad_no_data = TransformationAddConstantScalar(100, 6, {}); + auto bad_too_much_data = TransformationAddConstantScalar(100, 6, {1, 2}); + auto bad_type_id_does_not_exist = + TransformationAddConstantScalar(108, 2020, {uint_for_float[0]}); + auto bad_type_id_is_not_a_type = TransformationAddConstantScalar(109, 9, {0}); + auto bad_type_id_is_void = TransformationAddConstantScalar(110, 2, {0}); + auto bad_type_id_is_pointer = TransformationAddConstantScalar(111, 11, {0}); + + // Id is already in use. + ASSERT_FALSE(bad_id_already_used.IsApplicable(context.get(), fact_manager)); + + // At least one word of data must be provided. + ASSERT_FALSE(bad_no_data.IsApplicable(context.get(), fact_manager)); + + // Cannot give two data words for a 32-bit type. + ASSERT_FALSE(bad_too_much_data.IsApplicable(context.get(), fact_manager)); + + // Type id does not exist + ASSERT_FALSE( + bad_type_id_does_not_exist.IsApplicable(context.get(), fact_manager)); + + // Type id is not a type + ASSERT_FALSE( + bad_type_id_is_not_a_type.IsApplicable(context.get(), fact_manager)); + + // Type id is void + ASSERT_FALSE(bad_type_id_is_void.IsApplicable(context.get(), fact_manager)); + + // Type id is pointer + ASSERT_FALSE( + bad_type_id_is_pointer.IsApplicable(context.get(), fact_manager)); + + ASSERT_TRUE(add_signed_int_1.IsApplicable(context.get(), fact_manager)); + add_signed_int_1.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(add_signed_int_10.IsApplicable(context.get(), fact_manager)); + add_signed_int_10.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(add_unsigned_int_2.IsApplicable(context.get(), fact_manager)); + add_unsigned_int_2.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(add_unsigned_int_20.IsApplicable(context.get(), fact_manager)); + add_unsigned_int_20.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(add_float_3.IsApplicable(context.get(), fact_manager)); + add_float_3.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(add_float_30.IsApplicable(context.get(), fact_manager)); + add_float_30.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_FALSE(bad_add_float_30_id_already_used.IsApplicable(context.get(), + fact_manager)); + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %8 "x" + OpName %12 "y" + OpName %16 "z" + OpDecorate %8 RelaxedPrecision + OpDecorate %12 RelaxedPrecision + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 1 + %10 = OpTypeInt 32 0 + %11 = OpTypePointer Function %10 + %13 = OpConstant %10 2 + %14 = OpTypeFloat 32 + %15 = OpTypePointer Function %14 + %17 = OpConstant %14 3 + %100 = OpConstant %6 1 + %101 = OpConstant %6 10 + %102 = OpConstant %10 2 + %103 = OpConstant %10 20 + %104 = OpConstant %14 3 + %105 = OpConstant %14 30 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %12 = OpVariable %11 Function + %16 = OpVariable %15 Function + OpStore %8 %9 + OpStore %12 %13 + OpStore %16 %17 + OpReturn + OpFunctionEnd + )"; + + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +} // namespace +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/test/fuzz/transformation_add_dead_block_test.cpp b/third_party/spirv-tools/test/fuzz/transformation_add_dead_block_test.cpp new file mode 100644 index 0000000000..f89140f817 --- /dev/null +++ b/third_party/spirv-tools/test/fuzz/transformation_add_dead_block_test.cpp @@ -0,0 +1,321 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_add_dead_block.h" +#include "test/fuzz/fuzz_test_util.h" + +namespace spvtools { +namespace fuzz { +namespace { + +TEST(TransformationAddDeadBlockTest, BasicTest) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeBool + %7 = OpConstantTrue %6 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpBranch %8 + %8 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + // Id 4 is already in use + ASSERT_FALSE(TransformationAddDeadBlock(4, 5, true) + .IsApplicable(context.get(), fact_manager)); + + // Id 7 is not a block + ASSERT_FALSE(TransformationAddDeadBlock(100, 7, true) + .IsApplicable(context.get(), fact_manager)); + + TransformationAddDeadBlock transformation(100, 5, true); + ASSERT_TRUE(transformation.IsApplicable(context.get(), fact_manager)); + transformation.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(fact_manager.BlockIsDead(100)); + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeBool + %7 = OpConstantTrue %6 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpSelectionMerge %8 None + OpBranchConditional %7 %8 %100 + %100 = OpLabel + OpBranch %8 + %8 = OpLabel + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +TEST(TransformationAddDeadBlockTest, TargetBlockMustNotBeSelectionMerge) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeBool + %7 = OpConstantTrue %6 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpSelectionMerge %10 None + OpBranchConditional %7 %8 %9 + %8 = OpLabel + OpBranch %10 + %9 = OpLabel + OpBranch %10 + %10 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + ASSERT_FALSE(TransformationAddDeadBlock(100, 9, true) + .IsApplicable(context.get(), fact_manager)); +} + +TEST(TransformationAddDeadBlockTest, TargetBlockMustNotBeLoopMergeOrContinue) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeBool + %7 = OpConstantTrue %6 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpBranch %8 + %8 = OpLabel + OpLoopMerge %11 %12 None + OpBranchConditional %7 %9 %10 + %9 = OpLabel + OpBranch %12 + %10 = OpLabel + OpBranch %11 + %12 = OpLabel + OpBranch %8 + %11 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + // Bad because 9's successor is the loop continue target. + ASSERT_FALSE(TransformationAddDeadBlock(100, 9, true) + .IsApplicable(context.get(), fact_manager)); + // Bad because 10's successor is the loop merge. + ASSERT_FALSE(TransformationAddDeadBlock(100, 10, true) + .IsApplicable(context.get(), fact_manager)); +} + +TEST(TransformationAddDeadBlockTest, SourceBlockMustNotBeLoopHead) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeBool + %7 = OpConstantTrue %6 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpBranch %8 + %8 = OpLabel + OpLoopMerge %11 %12 None + OpBranch %9 + %9 = OpLabel + OpBranchConditional %7 %11 %12 + %12 = OpLabel + OpBranch %8 + %11 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + // Bad because 8 is a loop head. + ASSERT_FALSE(TransformationAddDeadBlock(100, 8, true) + .IsApplicable(context.get(), fact_manager)); +} + +TEST(TransformationAddDeadBlockTest, OpPhiInTarget) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeBool + %7 = OpConstantTrue %6 + %9 = OpTypeInt 32 0 + %10 = OpConstant %9 1 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpBranch %8 + %8 = OpLabel + %12 = OpPhi %6 %7 %5 + %13 = OpPhi %9 %10 %5 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + TransformationAddDeadBlock transformation(100, 5, true); + ASSERT_TRUE(transformation.IsApplicable(context.get(), fact_manager)); + transformation.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(fact_manager.BlockIsDead(100)); + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeBool + %7 = OpConstantTrue %6 + %9 = OpTypeInt 32 0 + %10 = OpConstant %9 1 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpSelectionMerge %8 None + OpBranchConditional %7 %8 %100 + %100 = OpLabel + OpBranch %8 + %8 = OpLabel + %12 = OpPhi %6 %7 %5 %7 %100 + %13 = OpPhi %9 %10 %5 %10 %100 + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +TEST(TransformationAddDeadBlockTest, BackEdge) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeBool + %7 = OpConstantTrue %6 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpBranch %8 + %8 = OpLabel + OpLoopMerge %10 %9 None + OpBranchConditional %7 %9 %10 + %9 = OpLabel + OpBranch %8 + %10 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + // 9 is a back edge block, so it would not be OK to add a dead block here, + // as then both 9 and the dead block would branch to the loop header, 8. + ASSERT_FALSE(TransformationAddDeadBlock(100, 9, true) + .IsApplicable(context.get(), fact_manager)); +} + +} // namespace +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/test/fuzz/transformation_add_dead_break_test.cpp b/third_party/spirv-tools/test/fuzz/transformation_add_dead_break_test.cpp new file mode 100644 index 0000000000..d60fc1fc52 --- /dev/null +++ b/third_party/spirv-tools/test/fuzz/transformation_add_dead_break_test.cpp @@ -0,0 +1,2610 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_add_dead_break.h" +#include "test/fuzz/fuzz_test_util.h" + +namespace spvtools { +namespace fuzz { +namespace { + +TEST(TransformationAddDeadBreakTest, BreaksOutOfSimpleIf) { + // For a simple if-then-else, checks that some dead break scenarios are + // possible, and sanity-checks that some illegal scenarios are indeed not + // allowed. + + // The SPIR-V for this test is adapted from the following GLSL, by separating + // some assignments into their own basic blocks, and adding constants for true + // and false: + // + // void main() { + // int x; + // int y; + // x = 1; + // if (x < y) { + // x = 2; + // x = 3; + // } else { + // y = 2; + // y = 3; + // } + // x = y; + // } + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %8 "x" + OpName %11 "y" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 1 + %13 = OpTypeBool + %17 = OpConstant %6 2 + %18 = OpConstant %6 3 + %25 = OpConstantTrue %13 + %26 = OpConstantFalse %13 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %11 = OpVariable %7 Function + OpStore %8 %9 + %10 = OpLoad %6 %8 + %12 = OpLoad %6 %11 + %14 = OpSLessThan %13 %10 %12 + OpSelectionMerge %16 None + OpBranchConditional %14 %15 %19 + %15 = OpLabel + OpStore %8 %17 + OpBranch %21 + %21 = OpLabel + OpStore %8 %18 + OpBranch %22 + %22 = OpLabel + OpBranch %16 + %19 = OpLabel + OpStore %11 %17 + OpBranch %23 + %23 = OpLabel + OpStore %11 %18 + OpBranch %24 + %24 = OpLabel + OpBranch %16 + %16 = OpLabel + %20 = OpLoad %6 %11 + OpStore %8 %20 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + FactManager fact_manager; + + const uint32_t merge_block = 16; + + // These are all possibilities. + ASSERT_TRUE(TransformationAddDeadBreak(15, merge_block, true, {}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(TransformationAddDeadBreak(15, merge_block, false, {}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(TransformationAddDeadBreak(21, merge_block, true, {}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(TransformationAddDeadBreak(21, merge_block, false, {}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(TransformationAddDeadBreak(22, merge_block, true, {}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(TransformationAddDeadBreak(22, merge_block, false, {}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(TransformationAddDeadBreak(19, merge_block, true, {}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(TransformationAddDeadBreak(19, merge_block, false, {}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(TransformationAddDeadBreak(23, merge_block, true, {}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(TransformationAddDeadBreak(23, merge_block, false, {}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(TransformationAddDeadBreak(24, merge_block, true, {}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(TransformationAddDeadBreak(24, merge_block, false, {}) + .IsApplicable(context.get(), fact_manager)); + + // Inapplicable: 100 is not a block id. + ASSERT_FALSE(TransformationAddDeadBreak(100, merge_block, true, {}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(TransformationAddDeadBreak(15, 100, true, {}) + .IsApplicable(context.get(), fact_manager)); + + // Inapplicable: 24 is not a merge block. + ASSERT_FALSE(TransformationAddDeadBreak(15, 24, true, {}) + .IsApplicable(context.get(), fact_manager)); + + // These are the transformations we will apply. + auto transformation1 = TransformationAddDeadBreak(15, merge_block, true, {}); + auto transformation2 = TransformationAddDeadBreak(21, merge_block, false, {}); + auto transformation3 = TransformationAddDeadBreak(22, merge_block, true, {}); + auto transformation4 = TransformationAddDeadBreak(19, merge_block, false, {}); + auto transformation5 = TransformationAddDeadBreak(23, merge_block, true, {}); + auto transformation6 = TransformationAddDeadBreak(24, merge_block, false, {}); + + ASSERT_TRUE(transformation1.IsApplicable(context.get(), fact_manager)); + transformation1.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation2.IsApplicable(context.get(), fact_manager)); + transformation2.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation3.IsApplicable(context.get(), fact_manager)); + transformation3.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation4.IsApplicable(context.get(), fact_manager)); + transformation4.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation5.IsApplicable(context.get(), fact_manager)); + transformation5.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation6.IsApplicable(context.get(), fact_manager)); + transformation6.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %8 "x" + OpName %11 "y" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 1 + %13 = OpTypeBool + %17 = OpConstant %6 2 + %18 = OpConstant %6 3 + %25 = OpConstantTrue %13 + %26 = OpConstantFalse %13 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %11 = OpVariable %7 Function + OpStore %8 %9 + %10 = OpLoad %6 %8 + %12 = OpLoad %6 %11 + %14 = OpSLessThan %13 %10 %12 + OpSelectionMerge %16 None + OpBranchConditional %14 %15 %19 + %15 = OpLabel + OpStore %8 %17 + OpBranchConditional %25 %21 %16 + %21 = OpLabel + OpStore %8 %18 + OpBranchConditional %26 %16 %22 + %22 = OpLabel + OpBranchConditional %25 %16 %16 + %19 = OpLabel + OpStore %11 %17 + OpBranchConditional %26 %16 %23 + %23 = OpLabel + OpStore %11 %18 + OpBranchConditional %25 %24 %16 + %24 = OpLabel + OpBranchConditional %26 %16 %16 + %16 = OpLabel + %20 = OpLoad %6 %11 + OpStore %8 %20 + OpReturn + OpFunctionEnd + )"; + + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +TEST(TransformationAddDeadBreakTest, BreakOutOfNestedIfs) { + // Checks some allowed and disallowed scenarios for nests of ifs. + + // The SPIR-V for this test is adapted from the following GLSL: + // + // void main() { + // int x; + // int y; + // x = 1; + // if (x < y) { + // x = 2; + // x = 3; + // if (x == y) { + // y = 3; + // } + // } else { + // y = 2; + // y = 3; + // } + // if (x == y) { + // x = 2; + // } + // x = y; + // } + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %8 "x" + OpName %11 "y" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 1 + %13 = OpTypeBool + %17 = OpConstant %6 2 + %18 = OpConstant %6 3 + %31 = OpConstantTrue %13 + %32 = OpConstantFalse %13 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %11 = OpVariable %7 Function + OpStore %8 %9 + %10 = OpLoad %6 %8 + %12 = OpLoad %6 %11 + %14 = OpSLessThan %13 %10 %12 + OpSelectionMerge %16 None + OpBranchConditional %14 %15 %24 + %15 = OpLabel + OpStore %8 %17 + OpBranch %33 + %33 = OpLabel + OpStore %8 %18 + %19 = OpLoad %6 %8 + OpBranch %34 + %34 = OpLabel + %20 = OpLoad %6 %11 + %21 = OpIEqual %13 %19 %20 + OpSelectionMerge %23 None + OpBranchConditional %21 %22 %23 + %22 = OpLabel + OpStore %11 %18 + OpBranch %35 + %35 = OpLabel + OpBranch %23 + %23 = OpLabel + OpBranch %16 + %24 = OpLabel + OpStore %11 %17 + OpBranch %36 + %36 = OpLabel + OpStore %11 %18 + OpBranch %16 + %16 = OpLabel + %25 = OpLoad %6 %8 + OpBranch %37 + %37 = OpLabel + %26 = OpLoad %6 %11 + %27 = OpIEqual %13 %25 %26 + OpSelectionMerge %29 None + OpBranchConditional %27 %28 %29 + %28 = OpLabel + OpStore %8 %17 + OpBranch %38 + %38 = OpLabel + OpBranch %29 + %29 = OpLabel + %30 = OpLoad %6 %11 + OpStore %8 %30 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + // The header and merge blocks + const uint32_t header_inner = 34; + const uint32_t merge_inner = 23; + const uint32_t header_outer = 5; + const uint32_t merge_outer = 16; + const uint32_t header_after = 37; + const uint32_t merge_after = 29; + + // The non-merge-nor-header blocks in each construct + const uint32_t inner_block_1 = 22; + const uint32_t inner_block_2 = 35; + const uint32_t outer_block_1 = 15; + const uint32_t outer_block_2 = 33; + const uint32_t outer_block_3 = 24; + const uint32_t outer_block_4 = 36; + const uint32_t after_block_1 = 28; + const uint32_t after_block_2 = 38; + + // Fine to break from a construct to its merge + ASSERT_TRUE(TransformationAddDeadBreak(inner_block_1, merge_inner, true, {}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(TransformationAddDeadBreak(inner_block_2, merge_inner, false, {}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(TransformationAddDeadBreak(outer_block_1, merge_outer, true, {}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(TransformationAddDeadBreak(outer_block_2, merge_outer, false, {}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(TransformationAddDeadBreak(outer_block_3, merge_outer, true, {}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(TransformationAddDeadBreak(outer_block_4, merge_outer, false, {}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(TransformationAddDeadBreak(after_block_1, merge_after, true, {}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(TransformationAddDeadBreak(after_block_2, merge_after, false, {}) + .IsApplicable(context.get(), fact_manager)); + + // Not OK to break to the wrong merge (whether enclosing or not) + ASSERT_FALSE(TransformationAddDeadBreak(inner_block_1, merge_outer, true, {}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(TransformationAddDeadBreak(inner_block_2, merge_after, false, {}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(TransformationAddDeadBreak(outer_block_1, merge_inner, true, {}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(TransformationAddDeadBreak(outer_block_2, merge_after, false, {}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(TransformationAddDeadBreak(after_block_1, merge_inner, true, {}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(TransformationAddDeadBreak(after_block_2, merge_outer, false, {}) + .IsApplicable(context.get(), fact_manager)); + + // Not OK to break from header (as it does not branch unconditionally) + ASSERT_FALSE(TransformationAddDeadBreak(header_inner, merge_inner, true, {}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(TransformationAddDeadBreak(header_outer, merge_outer, false, {}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(TransformationAddDeadBreak(header_after, merge_after, true, {}) + .IsApplicable(context.get(), fact_manager)); + + // Not OK to break to non-merge + ASSERT_FALSE( + TransformationAddDeadBreak(inner_block_1, inner_block_2, true, {}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE( + TransformationAddDeadBreak(outer_block_2, after_block_1, false, {}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(TransformationAddDeadBreak(outer_block_1, header_after, true, {}) + .IsApplicable(context.get(), fact_manager)); + + auto transformation1 = + TransformationAddDeadBreak(inner_block_1, merge_inner, true, {}); + auto transformation2 = + TransformationAddDeadBreak(inner_block_2, merge_inner, false, {}); + auto transformation3 = + TransformationAddDeadBreak(outer_block_1, merge_outer, true, {}); + auto transformation4 = + TransformationAddDeadBreak(outer_block_2, merge_outer, false, {}); + auto transformation5 = + TransformationAddDeadBreak(outer_block_3, merge_outer, true, {}); + auto transformation6 = + TransformationAddDeadBreak(outer_block_4, merge_outer, false, {}); + auto transformation7 = + TransformationAddDeadBreak(after_block_1, merge_after, true, {}); + auto transformation8 = + TransformationAddDeadBreak(after_block_2, merge_after, false, {}); + + ASSERT_TRUE(transformation1.IsApplicable(context.get(), fact_manager)); + transformation1.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation2.IsApplicable(context.get(), fact_manager)); + transformation2.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation3.IsApplicable(context.get(), fact_manager)); + transformation3.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation4.IsApplicable(context.get(), fact_manager)); + transformation4.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation5.IsApplicable(context.get(), fact_manager)); + transformation5.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation6.IsApplicable(context.get(), fact_manager)); + transformation6.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation7.IsApplicable(context.get(), fact_manager)); + transformation7.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation8.IsApplicable(context.get(), fact_manager)); + transformation8.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %8 "x" + OpName %11 "y" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 1 + %13 = OpTypeBool + %17 = OpConstant %6 2 + %18 = OpConstant %6 3 + %31 = OpConstantTrue %13 + %32 = OpConstantFalse %13 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %11 = OpVariable %7 Function + OpStore %8 %9 + %10 = OpLoad %6 %8 + %12 = OpLoad %6 %11 + %14 = OpSLessThan %13 %10 %12 + OpSelectionMerge %16 None + OpBranchConditional %14 %15 %24 + %15 = OpLabel + OpStore %8 %17 + OpBranchConditional %31 %33 %16 + %33 = OpLabel + OpStore %8 %18 + %19 = OpLoad %6 %8 + OpBranchConditional %32 %16 %34 + %34 = OpLabel + %20 = OpLoad %6 %11 + %21 = OpIEqual %13 %19 %20 + OpSelectionMerge %23 None + OpBranchConditional %21 %22 %23 + %22 = OpLabel + OpStore %11 %18 + OpBranchConditional %31 %35 %23 + %35 = OpLabel + OpBranchConditional %32 %23 %23 + %23 = OpLabel + OpBranch %16 + %24 = OpLabel + OpStore %11 %17 + OpBranchConditional %31 %36 %16 + %36 = OpLabel + OpStore %11 %18 + OpBranchConditional %32 %16 %16 + %16 = OpLabel + %25 = OpLoad %6 %8 + OpBranch %37 + %37 = OpLabel + %26 = OpLoad %6 %11 + %27 = OpIEqual %13 %25 %26 + OpSelectionMerge %29 None + OpBranchConditional %27 %28 %29 + %28 = OpLabel + OpStore %8 %17 + OpBranchConditional %31 %38 %29 + %38 = OpLabel + OpBranchConditional %32 %29 %29 + %29 = OpLabel + %30 = OpLoad %6 %11 + OpStore %8 %30 + OpReturn + OpFunctionEnd + )"; + + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +TEST(TransformationAddDeadBreakTest, BreakOutOfNestedSwitches) { + // Checks some allowed and disallowed scenarios for nests of switches. + + // The SPIR-V for this test is adapted from the following GLSL: + // + // void main() { + // int x; + // int y; + // x = 1; + // if (x < y) { + // switch (x) { + // case 0: + // case 1: + // if (x == y) { + // } + // x = 2; + // break; + // case 3: + // if (y == 4) { + // y = 2; + // x = 3; + // } + // case 10: + // break; + // default: + // switch (y) { + // case 1: + // break; + // case 2: + // x = 4; + // y = 2; + // default: + // x = 3; + // break; + // } + // } + // } else { + // switch (y) { + // case 1: + // x = 4; + // case 2: + // y = 3; + // default: + // x = y; + // break; + // } + // } + // } + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %8 "x" + OpName %11 "y" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 1 + %13 = OpTypeBool + %29 = OpConstant %6 2 + %32 = OpConstant %6 4 + %36 = OpConstant %6 3 + %60 = OpConstantTrue %13 + %61 = OpConstantFalse %13 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %11 = OpVariable %7 Function + OpStore %8 %9 + %10 = OpLoad %6 %8 + %12 = OpLoad %6 %11 + %14 = OpSLessThan %13 %10 %12 + OpSelectionMerge %16 None + OpBranchConditional %14 %15 %47 + %15 = OpLabel + %17 = OpLoad %6 %8 + OpSelectionMerge %22 None + OpSwitch %17 %21 0 %18 1 %18 3 %19 10 %20 + %21 = OpLabel + %38 = OpLoad %6 %11 + OpSelectionMerge %42 None + OpSwitch %38 %41 1 %39 2 %40 + %41 = OpLabel + OpStore %8 %36 + OpBranch %42 + %39 = OpLabel + OpBranch %42 + %40 = OpLabel + OpStore %8 %32 + OpStore %11 %29 + OpBranch %41 + %42 = OpLabel + OpBranch %22 + %18 = OpLabel + %23 = OpLoad %6 %8 + OpBranch %63 + %63 = OpLabel + %24 = OpLoad %6 %11 + %25 = OpIEqual %13 %23 %24 + OpSelectionMerge %27 None + OpBranchConditional %25 %26 %27 + %26 = OpLabel + OpBranch %27 + %27 = OpLabel + OpStore %8 %29 + OpBranch %22 + %19 = OpLabel + %31 = OpLoad %6 %11 + %33 = OpIEqual %13 %31 %32 + OpSelectionMerge %35 None + OpBranchConditional %33 %34 %35 + %34 = OpLabel + OpStore %11 %29 + OpBranch %62 + %62 = OpLabel + OpStore %8 %36 + OpBranch %35 + %35 = OpLabel + OpBranch %20 + %20 = OpLabel + OpBranch %22 + %22 = OpLabel + OpBranch %16 + %47 = OpLabel + %48 = OpLoad %6 %11 + OpSelectionMerge %52 None + OpSwitch %48 %51 1 %49 2 %50 + %51 = OpLabel + %53 = OpLoad %6 %11 + OpStore %8 %53 + OpBranch %52 + %49 = OpLabel + OpStore %8 %32 + OpBranch %50 + %50 = OpLabel + OpStore %11 %36 + OpBranch %51 + %52 = OpLabel + OpBranch %16 + %16 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + // The header and merge blocks + const uint32_t header_outer_if = 5; + const uint32_t merge_outer_if = 16; + const uint32_t header_then_outer_switch = 15; + const uint32_t merge_then_outer_switch = 22; + const uint32_t header_then_inner_switch = 21; + const uint32_t merge_then_inner_switch = 42; + const uint32_t header_else_switch = 47; + const uint32_t merge_else_switch = 52; + const uint32_t header_inner_if_1 = 19; + const uint32_t merge_inner_if_1 = 35; + const uint32_t header_inner_if_2 = 63; + const uint32_t merge_inner_if_2 = 27; + + // The non-merge-nor-header blocks in each construct + const uint32_t then_outer_switch_block_1 = 18; + const uint32_t then_inner_switch_block_1 = 39; + const uint32_t then_inner_switch_block_2 = 40; + const uint32_t then_inner_switch_block_3 = 41; + const uint32_t else_switch_block_1 = 49; + const uint32_t else_switch_block_2 = 50; + const uint32_t else_switch_block_3 = 51; + const uint32_t inner_if_1_block_1 = 34; + const uint32_t inner_if_1_block_2 = 62; + const uint32_t inner_if_2_block_1 = 26; + + // Fine to branch straight to direct merge block for a construct + ASSERT_TRUE(TransformationAddDeadBreak(then_outer_switch_block_1, + merge_then_outer_switch, true, {}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(TransformationAddDeadBreak(then_inner_switch_block_1, + merge_then_inner_switch, false, {}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(TransformationAddDeadBreak(then_inner_switch_block_2, + merge_then_inner_switch, true, {}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(TransformationAddDeadBreak(then_inner_switch_block_3, + merge_then_inner_switch, true, {}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(TransformationAddDeadBreak(else_switch_block_1, merge_else_switch, + false, {}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(TransformationAddDeadBreak(else_switch_block_2, merge_else_switch, + true, {}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(TransformationAddDeadBreak(else_switch_block_3, merge_else_switch, + false, {}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE( + TransformationAddDeadBreak(inner_if_1_block_1, merge_inner_if_1, true, {}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(TransformationAddDeadBreak(inner_if_1_block_2, merge_inner_if_1, + false, {}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE( + TransformationAddDeadBreak(inner_if_2_block_1, merge_inner_if_2, true, {}) + .IsApplicable(context.get(), fact_manager)); + + // Not OK to break out of a switch from a selection construct inside the + // switch. + ASSERT_FALSE(TransformationAddDeadBreak(inner_if_1_block_1, + merge_then_outer_switch, true, {}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(TransformationAddDeadBreak(inner_if_1_block_2, + merge_then_outer_switch, false, {}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(TransformationAddDeadBreak(inner_if_2_block_1, + merge_then_outer_switch, true, {}) + .IsApplicable(context.get(), fact_manager)); + + // Some miscellaneous inapplicable cases. + ASSERT_FALSE( + TransformationAddDeadBreak(header_outer_if, merge_outer_if, true, {}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(TransformationAddDeadBreak(header_inner_if_1, inner_if_1_block_2, + false, {}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(TransformationAddDeadBreak(header_then_inner_switch, + header_then_outer_switch, false, {}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(TransformationAddDeadBreak(header_else_switch, + then_inner_switch_block_3, false, {}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(TransformationAddDeadBreak(header_inner_if_2, header_inner_if_2, + false, {}) + .IsApplicable(context.get(), fact_manager)); + + auto transformation1 = TransformationAddDeadBreak( + then_outer_switch_block_1, merge_then_outer_switch, true, {}); + auto transformation2 = TransformationAddDeadBreak( + then_inner_switch_block_1, merge_then_inner_switch, false, {}); + auto transformation3 = TransformationAddDeadBreak( + then_inner_switch_block_2, merge_then_inner_switch, true, {}); + auto transformation4 = TransformationAddDeadBreak( + then_inner_switch_block_3, merge_then_inner_switch, true, {}); + auto transformation5 = TransformationAddDeadBreak( + else_switch_block_1, merge_else_switch, false, {}); + auto transformation6 = TransformationAddDeadBreak( + else_switch_block_2, merge_else_switch, true, {}); + auto transformation7 = TransformationAddDeadBreak( + else_switch_block_3, merge_else_switch, false, {}); + auto transformation8 = TransformationAddDeadBreak(inner_if_1_block_1, + merge_inner_if_1, true, {}); + auto transformation9 = TransformationAddDeadBreak( + inner_if_1_block_2, merge_inner_if_1, false, {}); + auto transformation10 = TransformationAddDeadBreak( + inner_if_2_block_1, merge_inner_if_2, true, {}); + + ASSERT_TRUE(transformation1.IsApplicable(context.get(), fact_manager)); + transformation1.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation2.IsApplicable(context.get(), fact_manager)); + transformation2.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation3.IsApplicable(context.get(), fact_manager)); + transformation3.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation4.IsApplicable(context.get(), fact_manager)); + transformation4.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation5.IsApplicable(context.get(), fact_manager)); + transformation5.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation6.IsApplicable(context.get(), fact_manager)); + transformation6.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation7.IsApplicable(context.get(), fact_manager)); + transformation7.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation8.IsApplicable(context.get(), fact_manager)); + transformation8.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation9.IsApplicable(context.get(), fact_manager)); + transformation9.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation10.IsApplicable(context.get(), fact_manager)); + transformation10.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %8 "x" + OpName %11 "y" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 1 + %13 = OpTypeBool + %29 = OpConstant %6 2 + %32 = OpConstant %6 4 + %36 = OpConstant %6 3 + %60 = OpConstantTrue %13 + %61 = OpConstantFalse %13 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %11 = OpVariable %7 Function + OpStore %8 %9 + %10 = OpLoad %6 %8 + %12 = OpLoad %6 %11 + %14 = OpSLessThan %13 %10 %12 + OpSelectionMerge %16 None + OpBranchConditional %14 %15 %47 + %15 = OpLabel + %17 = OpLoad %6 %8 + OpSelectionMerge %22 None + OpSwitch %17 %21 0 %18 1 %18 3 %19 10 %20 + %21 = OpLabel + %38 = OpLoad %6 %11 + OpSelectionMerge %42 None + OpSwitch %38 %41 1 %39 2 %40 + %41 = OpLabel + OpStore %8 %36 + OpBranchConditional %60 %42 %42 + %39 = OpLabel + OpBranchConditional %61 %42 %42 + %40 = OpLabel + OpStore %8 %32 + OpStore %11 %29 + OpBranchConditional %60 %41 %42 + %42 = OpLabel + OpBranch %22 + %18 = OpLabel + %23 = OpLoad %6 %8 + OpBranchConditional %60 %63 %22 + %63 = OpLabel + %24 = OpLoad %6 %11 + %25 = OpIEqual %13 %23 %24 + OpSelectionMerge %27 None + OpBranchConditional %25 %26 %27 + %26 = OpLabel + OpBranchConditional %60 %27 %27 + %27 = OpLabel + OpStore %8 %29 + OpBranch %22 + %19 = OpLabel + %31 = OpLoad %6 %11 + %33 = OpIEqual %13 %31 %32 + OpSelectionMerge %35 None + OpBranchConditional %33 %34 %35 + %34 = OpLabel + OpStore %11 %29 + OpBranchConditional %60 %62 %35 + %62 = OpLabel + OpStore %8 %36 + OpBranchConditional %61 %35 %35 + %35 = OpLabel + OpBranch %20 + %20 = OpLabel + OpBranch %22 + %22 = OpLabel + OpBranch %16 + %47 = OpLabel + %48 = OpLoad %6 %11 + OpSelectionMerge %52 None + OpSwitch %48 %51 1 %49 2 %50 + %51 = OpLabel + %53 = OpLoad %6 %11 + OpStore %8 %53 + OpBranchConditional %61 %52 %52 + %49 = OpLabel + OpStore %8 %32 + OpBranchConditional %61 %52 %50 + %50 = OpLabel + OpStore %11 %36 + OpBranchConditional %60 %51 %52 + %52 = OpLabel + OpBranch %16 + %16 = OpLabel + OpReturn + OpFunctionEnd + )"; + + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +TEST(TransformationAddDeadBreakTest, BreakOutOfLoopNest) { + // Checks some allowed and disallowed scenarios for a nest of loops, including + // breaking from an if or switch right out of a loop. + + // The SPIR-V for this test is adapted from the following GLSL: + // + // void main() { + // int x, y; + // do { + // x++; + // for (int j = 0; j < 100; j++) { + // y++; + // if (x == y) { + // x++; + // if (x == 2) { + // y++; + // } + // switch (x) { + // case 0: + // x = 2; + // default: + // break; + // } + // } + // } + // } while (x > y); + // + // for (int i = 0; i < 100; i++) { + // x++; + // } + // } + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %12 "x" + OpName %16 "j" + OpName %27 "y" + OpName %55 "i" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %10 = OpTypeInt 32 1 + %11 = OpTypePointer Function %10 + %14 = OpConstant %10 1 + %17 = OpConstant %10 0 + %24 = OpConstant %10 100 + %25 = OpTypeBool + %38 = OpConstant %10 2 + %67 = OpConstantTrue %25 + %68 = OpConstantFalse %25 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %12 = OpVariable %11 Function + %16 = OpVariable %11 Function + %27 = OpVariable %11 Function + %55 = OpVariable %11 Function + OpBranch %6 + %6 = OpLabel + OpLoopMerge %8 %9 None + OpBranch %7 + %7 = OpLabel + %13 = OpLoad %10 %12 + %15 = OpIAdd %10 %13 %14 + OpStore %12 %15 + OpStore %16 %17 + OpBranch %18 + %18 = OpLabel + OpLoopMerge %20 %21 None + OpBranch %22 + %22 = OpLabel + %23 = OpLoad %10 %16 + %26 = OpSLessThan %25 %23 %24 + OpBranchConditional %26 %19 %20 + %19 = OpLabel + %28 = OpLoad %10 %27 + %29 = OpIAdd %10 %28 %14 + OpStore %27 %29 + %30 = OpLoad %10 %12 + %31 = OpLoad %10 %27 + %32 = OpIEqual %25 %30 %31 + OpSelectionMerge %34 None + OpBranchConditional %32 %33 %34 + %33 = OpLabel + %35 = OpLoad %10 %12 + %36 = OpIAdd %10 %35 %14 + OpStore %12 %36 + %37 = OpLoad %10 %12 + %39 = OpIEqual %25 %37 %38 + OpSelectionMerge %41 None + OpBranchConditional %39 %40 %41 + %40 = OpLabel + %42 = OpLoad %10 %27 + %43 = OpIAdd %10 %42 %14 + OpStore %27 %43 + OpBranch %41 + %41 = OpLabel + %44 = OpLoad %10 %12 + OpSelectionMerge %47 None + OpSwitch %44 %46 0 %45 + %46 = OpLabel + OpBranch %47 + %45 = OpLabel + OpStore %12 %38 + OpBranch %46 + %47 = OpLabel + OpBranch %34 + %34 = OpLabel + OpBranch %21 + %21 = OpLabel + %50 = OpLoad %10 %16 + %51 = OpIAdd %10 %50 %14 + OpStore %16 %51 + OpBranch %18 + %20 = OpLabel + OpBranch %9 + %9 = OpLabel + %52 = OpLoad %10 %12 + %53 = OpLoad %10 %27 + %54 = OpSGreaterThan %25 %52 %53 + OpBranchConditional %54 %6 %8 + %8 = OpLabel + OpStore %55 %17 + OpBranch %56 + %56 = OpLabel + OpLoopMerge %58 %59 None + OpBranch %60 + %60 = OpLabel + %61 = OpLoad %10 %55 + %62 = OpSLessThan %25 %61 %24 + OpBranchConditional %62 %57 %58 + %57 = OpLabel + %63 = OpLoad %10 %12 + %64 = OpIAdd %10 %63 %14 + OpStore %12 %64 + OpBranch %59 + %59 = OpLabel + %65 = OpLoad %10 %55 + %66 = OpIAdd %10 %65 %14 + OpStore %55 %66 + OpBranch %56 + %58 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + // The header and merge blocks + const uint32_t header_do_while = 6; + const uint32_t merge_do_while = 8; + const uint32_t header_for_j = 18; + const uint32_t merge_for_j = 20; + const uint32_t header_for_i = 56; + const uint32_t merge_for_i = 58; + const uint32_t header_switch = 41; + const uint32_t merge_switch = 47; + const uint32_t header_if_x_eq_y = 19; + const uint32_t merge_if_x_eq_y = 34; + const uint32_t header_if_x_eq_2 = 33; + const uint32_t merge_if_x_eq_2 = 41; + + // Loop continue targets + const uint32_t continue_do_while = 9; + const uint32_t continue_for_j = 21; + const uint32_t continue_for_i = 59; + + // Some blocks in these constructs + const uint32_t block_in_inner_if = 40; + const uint32_t block_switch_case = 46; + const uint32_t block_switch_default = 45; + const uint32_t block_in_for_i_loop = 57; + + // Fine to break from any loop header to its merge + ASSERT_TRUE( + TransformationAddDeadBreak(header_do_while, merge_do_while, true, {}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(TransformationAddDeadBreak(header_for_i, merge_for_i, false, {}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(TransformationAddDeadBreak(header_for_j, merge_for_j, true, {}) + .IsApplicable(context.get(), fact_manager)); + + // Fine to break from any of the blocks in constructs in the "for j" loop to + // that loop's merge + ASSERT_TRUE( + TransformationAddDeadBreak(block_in_inner_if, merge_for_j, false, {}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE( + TransformationAddDeadBreak(block_switch_case, merge_for_j, true, {}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE( + TransformationAddDeadBreak(block_switch_default, merge_for_j, false, {}) + .IsApplicable(context.get(), fact_manager)); + + // Fine to break from the body of the "for i" loop to that loop's merge + ASSERT_TRUE( + TransformationAddDeadBreak(block_in_for_i_loop, merge_for_i, true, {}) + .IsApplicable(context.get(), fact_manager)); + + // Not OK to break from multiple loops + ASSERT_FALSE( + TransformationAddDeadBreak(block_in_inner_if, merge_do_while, false, {}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE( + TransformationAddDeadBreak(block_switch_case, merge_do_while, true, {}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(TransformationAddDeadBreak(block_switch_default, merge_do_while, + false, {}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE( + TransformationAddDeadBreak(header_for_j, merge_do_while, true, {}) + .IsApplicable(context.get(), fact_manager)); + + // Not OK to break loop from its continue construct + ASSERT_FALSE( + TransformationAddDeadBreak(continue_do_while, merge_do_while, true, {}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE( + TransformationAddDeadBreak(continue_for_j, merge_for_j, false, {}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(TransformationAddDeadBreak(continue_for_i, merge_for_i, true, {}) + .IsApplicable(context.get(), fact_manager)); + + // Not OK to break out of multiple non-loop constructs if not breaking to a + // loop merge + ASSERT_FALSE( + TransformationAddDeadBreak(block_in_inner_if, merge_if_x_eq_y, false, {}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE( + TransformationAddDeadBreak(block_switch_case, merge_if_x_eq_y, true, {}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(TransformationAddDeadBreak(block_switch_default, merge_if_x_eq_y, + false, {}) + .IsApplicable(context.get(), fact_manager)); + + // Some miscellaneous inapplicable transformations + ASSERT_FALSE( + TransformationAddDeadBreak(header_if_x_eq_2, header_if_x_eq_y, false, {}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE( + TransformationAddDeadBreak(merge_if_x_eq_2, merge_switch, false, {}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE( + TransformationAddDeadBreak(header_switch, header_switch, false, {}) + .IsApplicable(context.get(), fact_manager)); + + auto transformation1 = + TransformationAddDeadBreak(header_do_while, merge_do_while, true, {}); + auto transformation2 = + TransformationAddDeadBreak(header_for_i, merge_for_i, false, {}); + auto transformation3 = + TransformationAddDeadBreak(header_for_j, merge_for_j, true, {}); + auto transformation4 = + TransformationAddDeadBreak(block_in_inner_if, merge_for_j, false, {}); + auto transformation5 = + TransformationAddDeadBreak(block_switch_case, merge_for_j, true, {}); + auto transformation6 = + TransformationAddDeadBreak(block_switch_default, merge_for_j, false, {}); + auto transformation7 = + TransformationAddDeadBreak(block_in_for_i_loop, merge_for_i, true, {}); + + ASSERT_TRUE(transformation1.IsApplicable(context.get(), fact_manager)); + transformation1.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation2.IsApplicable(context.get(), fact_manager)); + transformation2.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation3.IsApplicable(context.get(), fact_manager)); + transformation3.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation4.IsApplicable(context.get(), fact_manager)); + transformation4.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation5.IsApplicable(context.get(), fact_manager)); + transformation5.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation6.IsApplicable(context.get(), fact_manager)); + transformation6.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation7.IsApplicable(context.get(), fact_manager)); + transformation7.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %12 "x" + OpName %16 "j" + OpName %27 "y" + OpName %55 "i" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %10 = OpTypeInt 32 1 + %11 = OpTypePointer Function %10 + %14 = OpConstant %10 1 + %17 = OpConstant %10 0 + %24 = OpConstant %10 100 + %25 = OpTypeBool + %38 = OpConstant %10 2 + %67 = OpConstantTrue %25 + %68 = OpConstantFalse %25 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %12 = OpVariable %11 Function + %16 = OpVariable %11 Function + %27 = OpVariable %11 Function + %55 = OpVariable %11 Function + OpBranch %6 + %6 = OpLabel + OpLoopMerge %8 %9 None + OpBranchConditional %67 %7 %8 + %7 = OpLabel + %13 = OpLoad %10 %12 + %15 = OpIAdd %10 %13 %14 + OpStore %12 %15 + OpStore %16 %17 + OpBranch %18 + %18 = OpLabel + OpLoopMerge %20 %21 None + OpBranchConditional %67 %22 %20 + %22 = OpLabel + %23 = OpLoad %10 %16 + %26 = OpSLessThan %25 %23 %24 + OpBranchConditional %26 %19 %20 + %19 = OpLabel + %28 = OpLoad %10 %27 + %29 = OpIAdd %10 %28 %14 + OpStore %27 %29 + %30 = OpLoad %10 %12 + %31 = OpLoad %10 %27 + %32 = OpIEqual %25 %30 %31 + OpSelectionMerge %34 None + OpBranchConditional %32 %33 %34 + %33 = OpLabel + %35 = OpLoad %10 %12 + %36 = OpIAdd %10 %35 %14 + OpStore %12 %36 + %37 = OpLoad %10 %12 + %39 = OpIEqual %25 %37 %38 + OpSelectionMerge %41 None + OpBranchConditional %39 %40 %41 + %40 = OpLabel + %42 = OpLoad %10 %27 + %43 = OpIAdd %10 %42 %14 + OpStore %27 %43 + OpBranchConditional %68 %20 %41 + %41 = OpLabel + %44 = OpLoad %10 %12 + OpSelectionMerge %47 None + OpSwitch %44 %46 0 %45 + %46 = OpLabel + OpBranchConditional %67 %47 %20 + %45 = OpLabel + OpStore %12 %38 + OpBranchConditional %68 %20 %46 + %47 = OpLabel + OpBranch %34 + %34 = OpLabel + OpBranch %21 + %21 = OpLabel + %50 = OpLoad %10 %16 + %51 = OpIAdd %10 %50 %14 + OpStore %16 %51 + OpBranch %18 + %20 = OpLabel + OpBranch %9 + %9 = OpLabel + %52 = OpLoad %10 %12 + %53 = OpLoad %10 %27 + %54 = OpSGreaterThan %25 %52 %53 + OpBranchConditional %54 %6 %8 + %8 = OpLabel + OpStore %55 %17 + OpBranch %56 + %56 = OpLabel + OpLoopMerge %58 %59 None + OpBranchConditional %68 %58 %60 + %60 = OpLabel + %61 = OpLoad %10 %55 + %62 = OpSLessThan %25 %61 %24 + OpBranchConditional %62 %57 %58 + %57 = OpLabel + %63 = OpLoad %10 %12 + %64 = OpIAdd %10 %63 %14 + OpStore %12 %64 + OpBranchConditional %67 %59 %58 + %59 = OpLabel + %65 = OpLoad %10 %55 + %66 = OpIAdd %10 %65 %14 + OpStore %55 %66 + OpBranch %56 + %58 = OpLabel + OpReturn + OpFunctionEnd + )"; + + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +TEST(TransformationAddDeadBreakTest, NoBreakFromContinueConstruct) { + // Checks that it is illegal to break straight from a continue construct. + + // The SPIR-V for this test is adapted from the following GLSL: + // + // void main() { + // for (int i = 0; i < 100; i++) { + // } + // } + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %8 "i" + OpDecorate %8 RelaxedPrecision + OpDecorate %15 RelaxedPrecision + OpDecorate %19 RelaxedPrecision + OpDecorate %21 RelaxedPrecision + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 0 + %16 = OpConstant %6 100 + %17 = OpTypeBool + %22 = OpConstantTrue %17 + %20 = OpConstant %6 1 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + OpStore %8 %9 + OpBranch %10 + %10 = OpLabel + OpLoopMerge %12 %13 None + OpBranch %14 + %14 = OpLabel + %15 = OpLoad %6 %8 + %18 = OpSLessThan %17 %15 %16 + OpBranchConditional %18 %11 %12 + %11 = OpLabel + OpBranch %13 + %13 = OpLabel + %19 = OpLoad %6 %8 + %21 = OpIAdd %6 %19 %20 + OpBranch %23 + %23 = OpLabel + OpStore %8 %21 + OpBranch %10 + %12 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + // Not OK to break loop from its continue construct + ASSERT_FALSE(TransformationAddDeadBreak(13, 12, true, {}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(TransformationAddDeadBreak(23, 12, true, {}) + .IsApplicable(context.get(), fact_manager)); +} + +TEST(TransformationAddDeadBreakTest, SelectionInContinueConstruct) { + // Considers some scenarios where there is a selection construct in a loop's + // continue construct. + + // The SPIR-V for this test is adapted from the following GLSL: + // + // void main() { + // for (int i = 0; i < 100; i = (i < 50 ? i + 2 : i + 1)) { + // } + // } + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %8 "i" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 0 + %16 = OpConstant %6 100 + %17 = OpTypeBool + %99 = OpConstantTrue %17 + %20 = OpConstant %6 50 + %26 = OpConstant %6 2 + %30 = OpConstant %6 1 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %22 = OpVariable %7 Function + OpStore %8 %9 + OpBranch %10 + %10 = OpLabel + OpLoopMerge %12 %13 None + OpBranch %14 + %14 = OpLabel + %15 = OpLoad %6 %8 + %18 = OpSLessThan %17 %15 %16 + OpBranchConditional %18 %11 %12 + %11 = OpLabel + OpBranch %13 + %13 = OpLabel + %19 = OpLoad %6 %8 + %21 = OpSLessThan %17 %19 %20 + OpSelectionMerge %24 None + OpBranchConditional %21 %23 %28 + %23 = OpLabel + %25 = OpLoad %6 %8 + OpBranch %100 + %100 = OpLabel + %27 = OpIAdd %6 %25 %26 + OpStore %22 %27 + OpBranch %24 + %28 = OpLabel + %29 = OpLoad %6 %8 + OpBranch %101 + %101 = OpLabel + %31 = OpIAdd %6 %29 %30 + OpStore %22 %31 + OpBranch %24 + %24 = OpLabel + %32 = OpLoad %6 %22 + OpStore %8 %32 + OpBranch %10 + %12 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + const uint32_t loop_merge = 12; + const uint32_t selection_merge = 24; + const uint32_t in_selection_1 = 23; + const uint32_t in_selection_2 = 100; + const uint32_t in_selection_3 = 28; + const uint32_t in_selection_4 = 101; + + // Not OK to jump from the selection to the loop merge, as this would break + // from the loop's continue construct. + ASSERT_FALSE(TransformationAddDeadBreak(in_selection_1, loop_merge, true, {}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(TransformationAddDeadBreak(in_selection_2, loop_merge, true, {}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(TransformationAddDeadBreak(in_selection_3, loop_merge, true, {}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(TransformationAddDeadBreak(in_selection_4, loop_merge, true, {}) + .IsApplicable(context.get(), fact_manager)); + + // But fine to jump from the selection to its merge. + + auto transformation1 = + TransformationAddDeadBreak(in_selection_1, selection_merge, true, {}); + auto transformation2 = + TransformationAddDeadBreak(in_selection_2, selection_merge, true, {}); + auto transformation3 = + TransformationAddDeadBreak(in_selection_3, selection_merge, true, {}); + auto transformation4 = + TransformationAddDeadBreak(in_selection_4, selection_merge, true, {}); + + ASSERT_TRUE(transformation1.IsApplicable(context.get(), fact_manager)); + transformation1.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation2.IsApplicable(context.get(), fact_manager)); + transformation2.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation3.IsApplicable(context.get(), fact_manager)); + transformation3.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation4.IsApplicable(context.get(), fact_manager)); + transformation4.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %8 "i" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 0 + %16 = OpConstant %6 100 + %17 = OpTypeBool + %99 = OpConstantTrue %17 + %20 = OpConstant %6 50 + %26 = OpConstant %6 2 + %30 = OpConstant %6 1 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %22 = OpVariable %7 Function + OpStore %8 %9 + OpBranch %10 + %10 = OpLabel + OpLoopMerge %12 %13 None + OpBranch %14 + %14 = OpLabel + %15 = OpLoad %6 %8 + %18 = OpSLessThan %17 %15 %16 + OpBranchConditional %18 %11 %12 + %11 = OpLabel + OpBranch %13 + %13 = OpLabel + %19 = OpLoad %6 %8 + %21 = OpSLessThan %17 %19 %20 + OpSelectionMerge %24 None + OpBranchConditional %21 %23 %28 + %23 = OpLabel + %25 = OpLoad %6 %8 + OpBranchConditional %99 %100 %24 + %100 = OpLabel + %27 = OpIAdd %6 %25 %26 + OpStore %22 %27 + OpBranchConditional %99 %24 %24 + %28 = OpLabel + %29 = OpLoad %6 %8 + OpBranchConditional %99 %101 %24 + %101 = OpLabel + %31 = OpIAdd %6 %29 %30 + OpStore %22 %31 + OpBranchConditional %99 %24 %24 + %24 = OpLabel + %32 = OpLoad %6 %22 + OpStore %8 %32 + OpBranch %10 + %12 = OpLabel + OpReturn + OpFunctionEnd + )"; + + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +TEST(TransformationAddDeadBreakTest, LoopInContinueConstruct) { + // Considers some scenarios where there is a loop in a loop's continue + // construct. + + // The SPIR-V for this test is adapted from the following GLSL, with inlining + // applied so that the loop from foo is in the main loop's continue construct: + // + // int foo() { + // int result = 0; + // for (int j = 0; j < 10; j++) { + // result++; + // } + // return result; + // } + // + // void main() { + // for (int i = 0; i < 100; i += foo()) { + // } + // } + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %31 "i" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypeFunction %6 + %10 = OpTypePointer Function %6 + %12 = OpConstant %6 0 + %20 = OpConstant %6 10 + %21 = OpTypeBool + %100 = OpConstantTrue %21 + %24 = OpConstant %6 1 + %38 = OpConstant %6 100 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %43 = OpVariable %10 Function + %44 = OpVariable %10 Function + %45 = OpVariable %10 Function + %31 = OpVariable %10 Function + OpStore %31 %12 + OpBranch %32 + %32 = OpLabel + OpLoopMerge %34 %35 None + OpBranch %36 + %36 = OpLabel + %37 = OpLoad %6 %31 + %39 = OpSLessThan %21 %37 %38 + OpBranchConditional %39 %33 %34 + %33 = OpLabel + OpBranch %35 + %35 = OpLabel + OpStore %43 %12 + OpStore %44 %12 + OpBranch %46 + %46 = OpLabel + OpLoopMerge %47 %48 None + OpBranch %49 + %49 = OpLabel + %50 = OpLoad %6 %44 + %51 = OpSLessThan %21 %50 %20 + OpBranchConditional %51 %52 %47 + %52 = OpLabel + %53 = OpLoad %6 %43 + OpBranch %101 + %101 = OpLabel + %54 = OpIAdd %6 %53 %24 + OpStore %43 %54 + OpBranch %48 + %48 = OpLabel + %55 = OpLoad %6 %44 + %56 = OpIAdd %6 %55 %24 + OpStore %44 %56 + OpBranch %46 + %47 = OpLabel + %57 = OpLoad %6 %43 + OpStore %45 %57 + %40 = OpLoad %6 %45 + %41 = OpLoad %6 %31 + %42 = OpIAdd %6 %41 %40 + OpStore %31 %42 + OpBranch %32 + %34 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + const uint32_t outer_loop_merge = 34; + const uint32_t outer_loop_block = 33; + const uint32_t inner_loop_merge = 47; + const uint32_t inner_loop_block = 52; + + // Some inapplicable cases + ASSERT_FALSE( + TransformationAddDeadBreak(inner_loop_block, outer_loop_merge, true, {}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE( + TransformationAddDeadBreak(outer_loop_block, inner_loop_merge, true, {}) + .IsApplicable(context.get(), fact_manager)); + + auto transformation1 = + TransformationAddDeadBreak(inner_loop_block, inner_loop_merge, true, {}); + auto transformation2 = + TransformationAddDeadBreak(outer_loop_block, outer_loop_merge, true, {}); + + ASSERT_TRUE(transformation1.IsApplicable(context.get(), fact_manager)); + transformation1.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation2.IsApplicable(context.get(), fact_manager)); + transformation2.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %31 "i" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypeFunction %6 + %10 = OpTypePointer Function %6 + %12 = OpConstant %6 0 + %20 = OpConstant %6 10 + %21 = OpTypeBool + %100 = OpConstantTrue %21 + %24 = OpConstant %6 1 + %38 = OpConstant %6 100 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %43 = OpVariable %10 Function + %44 = OpVariable %10 Function + %45 = OpVariable %10 Function + %31 = OpVariable %10 Function + OpStore %31 %12 + OpBranch %32 + %32 = OpLabel + OpLoopMerge %34 %35 None + OpBranch %36 + %36 = OpLabel + %37 = OpLoad %6 %31 + %39 = OpSLessThan %21 %37 %38 + OpBranchConditional %39 %33 %34 + %33 = OpLabel + OpBranchConditional %100 %35 %34 + %35 = OpLabel + OpStore %43 %12 + OpStore %44 %12 + OpBranch %46 + %46 = OpLabel + OpLoopMerge %47 %48 None + OpBranch %49 + %49 = OpLabel + %50 = OpLoad %6 %44 + %51 = OpSLessThan %21 %50 %20 + OpBranchConditional %51 %52 %47 + %52 = OpLabel + %53 = OpLoad %6 %43 + OpBranchConditional %100 %101 %47 + %101 = OpLabel + %54 = OpIAdd %6 %53 %24 + OpStore %43 %54 + OpBranch %48 + %48 = OpLabel + %55 = OpLoad %6 %44 + %56 = OpIAdd %6 %55 %24 + OpStore %44 %56 + OpBranch %46 + %47 = OpLabel + %57 = OpLoad %6 %43 + OpStore %45 %57 + %40 = OpLoad %6 %45 + %41 = OpLoad %6 %31 + %42 = OpIAdd %6 %41 %40 + OpStore %31 %42 + OpBranch %32 + %34 = OpLabel + OpReturn + OpFunctionEnd + )"; + + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +TEST(TransformationAddDeadBreakTest, PhiInstructions) { + // Checks that the transformation works in the presence of phi instructions. + + // The SPIR-V for this test is adapted from the following GLSL, with a bit of + // extra and artificial work to get some interesting uses of OpPhi: + // + // void main() { + // int x; int y; + // float f; + // x = 2; + // f = 3.0; + // if (x > y) { + // x = 3; + // f = 4.0; + // } else { + // x = x + 2; + // f = f + 10.0; + // } + // while (x < y) { + // x = x + 1; + // f = f + 1.0; + // } + // y = x; + // f = f + 3.0; + // } + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %8 "x" + OpName %12 "f" + OpName %15 "y" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 2 + %10 = OpTypeFloat 32 + %11 = OpTypePointer Function %10 + %13 = OpConstant %10 3 + %17 = OpTypeBool + %80 = OpConstantTrue %17 + %21 = OpConstant %6 3 + %22 = OpConstant %10 4 + %27 = OpConstant %10 10 + %38 = OpConstant %6 1 + %41 = OpConstant %10 1 + %46 = OpUndef %6 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %12 = OpVariable %11 Function + %15 = OpVariable %7 Function + OpStore %8 %9 + OpStore %12 %13 + %18 = OpSGreaterThan %17 %9 %46 + OpSelectionMerge %20 None + OpBranchConditional %18 %19 %23 + %19 = OpLabel + OpStore %8 %21 + OpStore %12 %22 + OpBranch %20 + %23 = OpLabel + %25 = OpIAdd %6 %9 %9 + OpStore %8 %25 + OpBranch %70 + %70 = OpLabel + %28 = OpFAdd %10 %13 %27 + OpStore %12 %28 + OpBranch %20 + %20 = OpLabel + %52 = OpPhi %10 %22 %19 %28 %70 + %48 = OpPhi %6 %21 %19 %25 %70 + OpBranch %29 + %29 = OpLabel + %51 = OpPhi %10 %52 %20 %42 %32 + %47 = OpPhi %6 %48 %20 %39 %32 + OpLoopMerge %31 %32 None + OpBranch %33 + %33 = OpLabel + %36 = OpSLessThan %17 %47 %46 + OpBranchConditional %36 %30 %31 + %30 = OpLabel + %39 = OpIAdd %6 %47 %38 + OpStore %8 %39 + OpBranch %75 + %75 = OpLabel + %42 = OpFAdd %10 %51 %41 + OpStore %12 %42 + OpBranch %32 + %32 = OpLabel + OpBranch %29 + %31 = OpLabel + %71 = OpPhi %6 %47 %33 + %72 = OpPhi %10 %51 %33 + OpStore %15 %71 + %45 = OpFAdd %10 %72 %13 + OpStore %12 %45 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + // Some inapplicable transformations + // Not applicable because there is already an edge 19->20, so the OpPhis at 20 + // do not need to be updated + ASSERT_FALSE(TransformationAddDeadBreak(19, 20, true, {13, 21}) + .IsApplicable(context.get(), fact_manager)); + // Not applicable because two OpPhis (not zero) need to be updated at 20 + ASSERT_FALSE(TransformationAddDeadBreak(23, 20, true, {}) + .IsApplicable(context.get(), fact_manager)); + // Not applicable because two OpPhis (not just one) need to be updated at 20 + ASSERT_FALSE(TransformationAddDeadBreak(23, 20, true, {13}) + .IsApplicable(context.get(), fact_manager)); + // Not applicable because the given ids do not have types that match the + // OpPhis at 20, in order + ASSERT_FALSE(TransformationAddDeadBreak(23, 20, true, {21, 13}) + .IsApplicable(context.get(), fact_manager)); + // Not applicable because id 23 is a label + ASSERT_FALSE(TransformationAddDeadBreak(23, 20, true, {21, 23}) + .IsApplicable(context.get(), fact_manager)); + // Not applicable because 101 is not an id + ASSERT_FALSE(TransformationAddDeadBreak(23, 20, true, {21, 101}) + .IsApplicable(context.get(), fact_manager)); + // Not applicable because ids 51 and 47 are not available at the end of block + // 23 + ASSERT_FALSE(TransformationAddDeadBreak(23, 20, true, {51, 47}) + .IsApplicable(context.get(), fact_manager)); + + // Not applicable because OpConstantFalse is not present in the module + ASSERT_FALSE(TransformationAddDeadBreak(19, 20, false, {}) + .IsApplicable(context.get(), fact_manager)); + + auto transformation1 = TransformationAddDeadBreak(19, 20, true, {}); + auto transformation2 = TransformationAddDeadBreak(23, 20, true, {13, 21}); + auto transformation3 = TransformationAddDeadBreak(70, 20, true, {}); + auto transformation4 = TransformationAddDeadBreak(30, 31, true, {21, 13}); + auto transformation5 = TransformationAddDeadBreak(75, 31, true, {47, 51}); + + ASSERT_TRUE(transformation1.IsApplicable(context.get(), fact_manager)); + transformation1.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation2.IsApplicable(context.get(), fact_manager)); + transformation2.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation3.IsApplicable(context.get(), fact_manager)); + transformation3.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation4.IsApplicable(context.get(), fact_manager)); + transformation4.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation5.IsApplicable(context.get(), fact_manager)); + transformation5.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %8 "x" + OpName %12 "f" + OpName %15 "y" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 2 + %10 = OpTypeFloat 32 + %11 = OpTypePointer Function %10 + %13 = OpConstant %10 3 + %17 = OpTypeBool + %80 = OpConstantTrue %17 + %21 = OpConstant %6 3 + %22 = OpConstant %10 4 + %27 = OpConstant %10 10 + %38 = OpConstant %6 1 + %41 = OpConstant %10 1 + %46 = OpUndef %6 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %12 = OpVariable %11 Function + %15 = OpVariable %7 Function + OpStore %8 %9 + OpStore %12 %13 + %18 = OpSGreaterThan %17 %9 %46 + OpSelectionMerge %20 None + OpBranchConditional %18 %19 %23 + %19 = OpLabel + OpStore %8 %21 + OpStore %12 %22 + OpBranchConditional %80 %20 %20 + %23 = OpLabel + %25 = OpIAdd %6 %9 %9 + OpStore %8 %25 + OpBranchConditional %80 %70 %20 + %70 = OpLabel + %28 = OpFAdd %10 %13 %27 + OpStore %12 %28 + OpBranchConditional %80 %20 %20 + %20 = OpLabel + %52 = OpPhi %10 %22 %19 %28 %70 %13 %23 + %48 = OpPhi %6 %21 %19 %25 %70 %21 %23 + OpBranch %29 + %29 = OpLabel + %51 = OpPhi %10 %52 %20 %42 %32 + %47 = OpPhi %6 %48 %20 %39 %32 + OpLoopMerge %31 %32 None + OpBranch %33 + %33 = OpLabel + %36 = OpSLessThan %17 %47 %46 + OpBranchConditional %36 %30 %31 + %30 = OpLabel + %39 = OpIAdd %6 %47 %38 + OpStore %8 %39 + OpBranchConditional %80 %75 %31 + %75 = OpLabel + %42 = OpFAdd %10 %51 %41 + OpStore %12 %42 + OpBranchConditional %80 %32 %31 + %32 = OpLabel + OpBranch %29 + %31 = OpLabel + %71 = OpPhi %6 %47 %33 %21 %30 %47 %75 + %72 = OpPhi %10 %51 %33 %13 %30 %51 %75 + OpStore %15 %71 + %45 = OpFAdd %10 %72 %13 + OpStore %12 %45 + OpReturn + OpFunctionEnd + )"; + + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +TEST(TransformationAddDeadBreakTest, RespectDominanceRules1) { + // Right after the loop, an OpCopyObject defined by the loop is used. Adding + // a dead break would prevent that use from being dominated by its definition, + // so is not allowed. + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %10 = OpTypeBool + %11 = OpConstantFalse %10 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpBranch %100 + %100 = OpLabel + OpLoopMerge %101 %102 None + OpBranch %103 + %103 = OpLabel + %200 = OpCopyObject %10 %11 + OpBranch %104 + %104 = OpLabel + OpBranch %102 + %102 = OpLabel + OpBranchConditional %11 %100 %101 + %101 = OpLabel + %201 = OpCopyObject %10 %200 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + auto bad_transformation = TransformationAddDeadBreak(100, 101, false, {}); + ASSERT_FALSE(bad_transformation.IsApplicable(context.get(), fact_manager)); +} + +TEST(TransformationAddDeadBreakTest, RespectDominanceRules2) { + // This example captures the following idiom: + // + // if { + // L1: + // } + // definition; + // L2: + // use; + // + // Adding a dead jump from L1 to L2 would lead to 'definition' no longer + // dominating 'use', and so is not allowed. + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %10 = OpTypeBool + %11 = OpConstantFalse %10 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpBranch %100 + %100 = OpLabel + OpSelectionMerge %101 None + OpBranchConditional %11 %102 %103 + %102 = OpLabel + OpBranch %103 + %103 = OpLabel + %200 = OpCopyObject %10 %11 + OpBranch %101 + %101 = OpLabel + %201 = OpCopyObject %10 %200 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + auto bad_transformation = TransformationAddDeadBreak(102, 101, false, {}); + ASSERT_FALSE(bad_transformation.IsApplicable(context.get(), fact_manager)); +} + +TEST(TransformationAddDeadBreakTest, RespectDominanceRules3) { + // Right after the loop, an OpCopyObject defined by the loop is used in an + // OpPhi. Adding a dead break is OK in this case, due to the use being in an + // OpPhi. + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %10 = OpTypeBool + %11 = OpConstantFalse %10 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpBranch %100 + %100 = OpLabel + OpLoopMerge %101 %102 None + OpBranch %103 + %103 = OpLabel + %200 = OpCopyObject %10 %11 + OpBranch %104 + %104 = OpLabel + OpBranch %102 + %102 = OpLabel + OpBranchConditional %11 %100 %101 + %101 = OpLabel + %201 = OpPhi %10 %200 %102 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + auto good_transformation = TransformationAddDeadBreak(100, 101, false, {11}); + ASSERT_TRUE(good_transformation.IsApplicable(context.get(), fact_manager)); + + good_transformation.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %10 = OpTypeBool + %11 = OpConstantFalse %10 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpBranch %100 + %100 = OpLabel + OpLoopMerge %101 %102 None + OpBranchConditional %11 %101 %103 + %103 = OpLabel + %200 = OpCopyObject %10 %11 + OpBranch %104 + %104 = OpLabel + OpBranch %102 + %102 = OpLabel + OpBranchConditional %11 %100 %101 + %101 = OpLabel + %201 = OpPhi %10 %200 %102 %11 %100 + OpReturn + OpFunctionEnd + )"; + + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +TEST(TransformationAddDeadBreakTest, RespectDominanceRules4) { + // This example captures the following idiom: + // + // if { + // L1: + // } + // definition; + // L2: + // use in OpPhi; + // + // Adding a dead jump from L1 to L2 is OK, due to 'use' being in an OpPhi. + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %10 = OpTypeBool + %11 = OpConstantFalse %10 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpBranch %100 + %100 = OpLabel + OpSelectionMerge %101 None + OpBranchConditional %11 %102 %103 + %102 = OpLabel + OpBranch %103 + %103 = OpLabel + %200 = OpCopyObject %10 %11 + OpBranch %101 + %101 = OpLabel + %201 = OpPhi %10 %200 %103 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + auto good_transformation = TransformationAddDeadBreak(102, 101, false, {11}); + ASSERT_TRUE(good_transformation.IsApplicable(context.get(), fact_manager)); + + good_transformation.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %10 = OpTypeBool + %11 = OpConstantFalse %10 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpBranch %100 + %100 = OpLabel + OpSelectionMerge %101 None + OpBranchConditional %11 %102 %103 + %102 = OpLabel + OpBranchConditional %11 %101 %103 + %103 = OpLabel + %200 = OpCopyObject %10 %11 + OpBranch %101 + %101 = OpLabel + %201 = OpPhi %10 %200 %103 %11 %102 + OpReturn + OpFunctionEnd + )"; + + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +TEST(TransformationAddDeadBreakTest, RespectDominanceRules5) { + // After, but not right after, the loop, an OpCopyObject defined by the loop + // is used in an OpPhi. Adding a dead break is not OK in this case. + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %10 = OpTypeBool + %11 = OpConstantFalse %10 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpBranch %100 + %100 = OpLabel + OpLoopMerge %101 %102 None + OpBranch %103 + %103 = OpLabel + %200 = OpCopyObject %10 %11 + OpBranch %104 + %104 = OpLabel + OpBranch %102 + %102 = OpLabel + OpBranchConditional %11 %100 %101 + %101 = OpLabel + OpBranch %105 + %105 = OpLabel + %201 = OpPhi %10 %200 %101 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + auto bad_transformation = TransformationAddDeadBreak(100, 101, false, {}); + ASSERT_FALSE(bad_transformation.IsApplicable(context.get(), fact_manager)); +} + +TEST(TransformationAddDeadBreakTest, RespectDominanceRules6) { + // This example captures the following idiom: + // + // if { + // L1: + // } + // definition; + // L2: + // goto L3; + // L3: + // use in OpPhi; + // + // Adding a dead jump from L1 to L2 not OK, due to the use in an OpPhi being + // in L3. + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %10 = OpTypeBool + %11 = OpConstantFalse %10 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpBranch %100 + %100 = OpLabel + OpSelectionMerge %101 None + OpBranchConditional %11 %102 %103 + %102 = OpLabel + OpBranch %103 + %103 = OpLabel + %200 = OpCopyObject %10 %11 + OpBranch %101 + %101 = OpLabel + OpBranch %150 + %150 = OpLabel + %201 = OpPhi %10 %200 %101 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + auto bad_transformation = TransformationAddDeadBreak(102, 101, false, {}); + ASSERT_FALSE(bad_transformation.IsApplicable(context.get(), fact_manager)); +} + +TEST(TransformationAddDeadBreakTest, RespectDominanceRules7) { + // This example - a variation on an earlier test - captures the following + // idiom: + // + // loop { + // L1: + // } + // definition; + // L2: + // use; + // + // Adding a dead jump from L1 to L2 would lead to 'definition' no longer + // dominating 'use', and so is not allowed. + // + // This version of the test captures the case where L1 appears after the + // loop merge (which SPIR-V dominance rules allow). + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %10 = OpTypeBool + %11 = OpConstantFalse %10 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpBranch %100 + %100 = OpLabel + OpLoopMerge %101 %104 None + OpBranchConditional %11 %102 %103 + %103 = OpLabel + %200 = OpCopyObject %10 %11 + OpBranch %101 + %101 = OpLabel + %201 = OpCopyObject %10 %200 + OpReturn + %102 = OpLabel + OpBranch %103 + %104 = OpLabel + OpBranch %100 + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + auto bad_transformation = TransformationAddDeadBreak(102, 101, false, {}); + ASSERT_FALSE(bad_transformation.IsApplicable(context.get(), fact_manager)); +} + +TEST(TransformationAddDeadBreakTest, RespectDominanceRules8) { + // A variation of RespectDominanceRules8 where the defining block appears + // in the loop, but after the definition of interest. + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %10 = OpTypeBool + %11 = OpConstantFalse %10 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpBranch %100 + %100 = OpLabel + OpLoopMerge %101 %104 None + OpBranchConditional %11 %102 %103 + %103 = OpLabel + %200 = OpCopyObject %10 %11 + OpBranch %101 + %102 = OpLabel + OpBranch %103 + %101 = OpLabel + %201 = OpCopyObject %10 %200 + OpReturn + %104 = OpLabel + OpBranch %100 + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + auto bad_transformation = TransformationAddDeadBreak(102, 101, false, {}); + ASSERT_FALSE(bad_transformation.IsApplicable(context.get(), fact_manager)); +} + +TEST(TransformationAddDeadBreakTest, + BreakWouldDisobeyDominanceBlockOrderingRules) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeBool + %9 = OpConstantTrue %6 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpBranch %10 + %10 = OpLabel + OpLoopMerge %16 %15 None + OpBranch %11 + %11 = OpLabel + OpSelectionMerge %14 None + OpBranchConditional %9 %12 %13 + %14 = OpLabel + OpBranch %15 + %12 = OpLabel + OpBranch %16 + %13 = OpLabel + OpBranch %16 + %15 = OpLabel + OpBranch %10 + %16 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + // Bad because 14 comes before 12 in the module, and 14 has no predecessors. + // This means that an edge from 12 to 14 will lead to 12 dominating 14, which + // is illegal if 12 appears after 14. + auto bad_transformation = TransformationAddDeadBreak(12, 14, true, {}); + ASSERT_FALSE(bad_transformation.IsApplicable(context.get(), fact_manager)); +} + +} // namespace +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/test/fuzz/transformation_add_dead_continue_test.cpp b/third_party/spirv-tools/test/fuzz/transformation_add_dead_continue_test.cpp new file mode 100644 index 0000000000..ff93da8a92 --- /dev/null +++ b/third_party/spirv-tools/test/fuzz/transformation_add_dead_continue_test.cpp @@ -0,0 +1,1562 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_add_dead_continue.h" +#include "test/fuzz/fuzz_test_util.h" + +namespace spvtools { +namespace fuzz { +namespace { + +TEST(TransformationAddDeadContinueTest, SimpleExample) { + // For a simple loop, checks that some dead continue scenarios are possible, + // sanity-checks that some illegal scenarios are indeed not allowed, and then + // applies a transformation. + + // The SPIR-V for this test is adapted from the following GLSL, by separating + // some assignments into their own basic blocks, and adding constants for true + // and false: + // + // void main() { + // int x = 0; + // for (int i = 0; i < 10; i++) { + // x = x + i; + // x = x + i; + // } + // } + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %8 "x" + OpName %10 "i" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 0 + %17 = OpConstant %6 10 + %18 = OpTypeBool + %41 = OpConstantTrue %18 + %42 = OpConstantFalse %18 + %27 = OpConstant %6 1 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %10 = OpVariable %7 Function + OpStore %8 %9 + OpStore %10 %9 + OpBranch %11 + %11 = OpLabel + OpLoopMerge %13 %14 None + OpBranch %15 + %15 = OpLabel + %16 = OpLoad %6 %10 + %19 = OpSLessThan %18 %16 %17 + OpBranchConditional %19 %12 %13 + %12 = OpLabel + %20 = OpLoad %6 %8 + %21 = OpLoad %6 %10 + %22 = OpIAdd %6 %20 %21 + OpStore %8 %22 + OpBranch %40 + %40 = OpLabel + %23 = OpLoad %6 %8 + %24 = OpLoad %6 %10 + %25 = OpIAdd %6 %23 %24 + OpStore %8 %25 + OpBranch %14 + %14 = OpLabel + %26 = OpLoad %6 %10 + %28 = OpIAdd %6 %26 %27 + OpStore %10 %28 + OpBranch %11 + %13 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + FactManager fact_manager; + + // These are all possibilities. + ASSERT_TRUE(TransformationAddDeadContinue(11, true, {}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(TransformationAddDeadContinue(11, false, {}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(TransformationAddDeadContinue(12, true, {}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(TransformationAddDeadContinue(12, false, {}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(TransformationAddDeadContinue(40, true, {}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(TransformationAddDeadContinue(40, false, {}) + .IsApplicable(context.get(), fact_manager)); + + // Inapplicable: 100 is not a block id. + ASSERT_FALSE(TransformationAddDeadContinue(100, true, {}) + .IsApplicable(context.get(), fact_manager)); + + // Inapplicable: 10 is not in a loop. + ASSERT_FALSE(TransformationAddDeadContinue(10, true, {}) + .IsApplicable(context.get(), fact_manager)); + + // Inapplicable: 15 does not branch unconditionally to a single successor. + ASSERT_FALSE(TransformationAddDeadContinue(15, true, {}) + .IsApplicable(context.get(), fact_manager)); + + // Inapplicable: 13 is not in a loop and has no successor. + ASSERT_FALSE(TransformationAddDeadContinue(13, true, {}) + .IsApplicable(context.get(), fact_manager)); + + // Inapplicable: 14 is the loop continue target, so it's not OK to jump to + // the loop continue from there. + ASSERT_FALSE(TransformationAddDeadContinue(14, false, {}) + .IsApplicable(context.get(), fact_manager)); + + // These are the transformations we will apply. + auto transformation1 = TransformationAddDeadContinue(11, true, {}); + auto transformation2 = TransformationAddDeadContinue(12, false, {}); + auto transformation3 = TransformationAddDeadContinue(40, true, {}); + + ASSERT_TRUE(transformation1.IsApplicable(context.get(), fact_manager)); + transformation1.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation2.IsApplicable(context.get(), fact_manager)); + transformation2.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(transformation3.IsApplicable(context.get(), fact_manager)); + transformation3.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %8 "x" + OpName %10 "i" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 0 + %17 = OpConstant %6 10 + %18 = OpTypeBool + %41 = OpConstantTrue %18 + %42 = OpConstantFalse %18 + %27 = OpConstant %6 1 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %10 = OpVariable %7 Function + OpStore %8 %9 + OpStore %10 %9 + OpBranch %11 + %11 = OpLabel + OpLoopMerge %13 %14 None + OpBranchConditional %41 %15 %14 + %15 = OpLabel + %16 = OpLoad %6 %10 + %19 = OpSLessThan %18 %16 %17 + OpBranchConditional %19 %12 %13 + %12 = OpLabel + %20 = OpLoad %6 %8 + %21 = OpLoad %6 %10 + %22 = OpIAdd %6 %20 %21 + OpStore %8 %22 + OpBranchConditional %42 %14 %40 + %40 = OpLabel + %23 = OpLoad %6 %8 + %24 = OpLoad %6 %10 + %25 = OpIAdd %6 %23 %24 + OpStore %8 %25 + OpBranchConditional %41 %14 %14 + %14 = OpLabel + %26 = OpLoad %6 %10 + %28 = OpIAdd %6 %26 %27 + OpStore %10 %28 + OpBranch %11 + %13 = OpLabel + OpReturn + OpFunctionEnd + )"; + + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +TEST(TransformationAddDeadContinueTest, LoopNest) { + // Checks some allowed and disallowed scenarios for a nest of loops, including + // continuing a loop from an if or switch. + + // The SPIR-V for this test is adapted from the following GLSL: + // + // void main() { + // int x, y; + // do { + // x++; + // for (int j = 0; j < 100; j++) { + // y++; + // if (x == y) { + // x++; + // if (x == 2) { + // y++; + // } + // switch (x) { + // case 0: + // x = 2; + // default: + // break; + // } + // } + // } + // } while (x > y); + // + // for (int i = 0; i < 100; i++) { + // x++; + // } + // } + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %12 "x" + OpName %16 "j" + OpName %27 "y" + OpName %55 "i" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %10 = OpTypeInt 32 1 + %11 = OpTypePointer Function %10 + %14 = OpConstant %10 1 + %17 = OpConstant %10 0 + %24 = OpConstant %10 100 + %25 = OpTypeBool + %38 = OpConstant %10 2 + %67 = OpConstantTrue %25 + %68 = OpConstantFalse %25 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %12 = OpVariable %11 Function + %16 = OpVariable %11 Function + %27 = OpVariable %11 Function + %55 = OpVariable %11 Function + OpBranch %6 + %6 = OpLabel + OpLoopMerge %8 %9 None + OpBranch %7 + %7 = OpLabel + %13 = OpLoad %10 %12 + %15 = OpIAdd %10 %13 %14 + OpStore %12 %15 + OpStore %16 %17 + OpBranch %18 + %18 = OpLabel + OpLoopMerge %20 %21 None + OpBranch %22 + %22 = OpLabel + %23 = OpLoad %10 %16 + %26 = OpSLessThan %25 %23 %24 + OpBranchConditional %26 %19 %20 + %19 = OpLabel + %28 = OpLoad %10 %27 + %29 = OpIAdd %10 %28 %14 + OpStore %27 %29 + %30 = OpLoad %10 %12 + %31 = OpLoad %10 %27 + %32 = OpIEqual %25 %30 %31 + OpSelectionMerge %34 None + OpBranchConditional %32 %33 %34 + %33 = OpLabel + %35 = OpLoad %10 %12 + %36 = OpIAdd %10 %35 %14 + OpStore %12 %36 + %37 = OpLoad %10 %12 + %39 = OpIEqual %25 %37 %38 + OpSelectionMerge %41 None + OpBranchConditional %39 %40 %41 + %40 = OpLabel + %42 = OpLoad %10 %27 + %43 = OpIAdd %10 %42 %14 + OpStore %27 %43 + OpBranch %41 + %41 = OpLabel + %44 = OpLoad %10 %12 + OpSelectionMerge %47 None + OpSwitch %44 %46 0 %45 + %46 = OpLabel + OpBranch %47 + %45 = OpLabel + OpStore %12 %38 + OpBranch %46 + %47 = OpLabel + OpBranch %34 + %34 = OpLabel + OpBranch %21 + %21 = OpLabel + %50 = OpLoad %10 %16 + %51 = OpIAdd %10 %50 %14 + OpStore %16 %51 + OpBranch %18 + %20 = OpLabel + OpBranch %9 + %9 = OpLabel + %52 = OpLoad %10 %12 + %53 = OpLoad %10 %27 + %54 = OpSGreaterThan %25 %52 %53 + OpBranchConditional %54 %6 %8 + %8 = OpLabel + OpStore %55 %17 + OpBranch %56 + %56 = OpLabel + OpLoopMerge %58 %59 None + OpBranch %60 + %60 = OpLabel + %61 = OpLoad %10 %55 + %62 = OpSLessThan %25 %61 %24 + OpBranchConditional %62 %57 %58 + %57 = OpLabel + %63 = OpLoad %10 %12 + %64 = OpIAdd %10 %63 %14 + OpStore %12 %64 + OpBranch %59 + %59 = OpLabel + %65 = OpLoad %10 %55 + %66 = OpIAdd %10 %65 %14 + OpStore %55 %66 + OpBranch %56 + %58 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + std::vector good = {6, 7, 18, 20, 34, 40, 45, 46, 47, 56, 57}; + std::vector bad = {5, 8, 9, 19, 21, 22, 33, 41, 58, 59, 60}; + + for (uint32_t from_block : bad) { + ASSERT_FALSE(TransformationAddDeadContinue(from_block, true, {}) + .IsApplicable(context.get(), fact_manager)); + } + for (uint32_t from_block : good) { + const TransformationAddDeadContinue transformation(from_block, true, {}); + ASSERT_TRUE(transformation.IsApplicable(context.get(), fact_manager)); + transformation.Apply(context.get(), &fact_manager); + ASSERT_FALSE(transformation.IsApplicable(context.get(), fact_manager)); + } + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %12 "x" + OpName %16 "j" + OpName %27 "y" + OpName %55 "i" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %10 = OpTypeInt 32 1 + %11 = OpTypePointer Function %10 + %14 = OpConstant %10 1 + %17 = OpConstant %10 0 + %24 = OpConstant %10 100 + %25 = OpTypeBool + %38 = OpConstant %10 2 + %67 = OpConstantTrue %25 + %68 = OpConstantFalse %25 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %12 = OpVariable %11 Function + %16 = OpVariable %11 Function + %27 = OpVariable %11 Function + %55 = OpVariable %11 Function + OpBranch %6 + %6 = OpLabel + OpLoopMerge %8 %9 None + OpBranchConditional %67 %7 %9 + %7 = OpLabel + %13 = OpLoad %10 %12 + %15 = OpIAdd %10 %13 %14 + OpStore %12 %15 + OpStore %16 %17 + OpBranchConditional %67 %18 %9 + %18 = OpLabel + OpLoopMerge %20 %21 None + OpBranchConditional %67 %22 %21 + %22 = OpLabel + %23 = OpLoad %10 %16 + %26 = OpSLessThan %25 %23 %24 + OpBranchConditional %26 %19 %20 + %19 = OpLabel + %28 = OpLoad %10 %27 + %29 = OpIAdd %10 %28 %14 + OpStore %27 %29 + %30 = OpLoad %10 %12 + %31 = OpLoad %10 %27 + %32 = OpIEqual %25 %30 %31 + OpSelectionMerge %34 None + OpBranchConditional %32 %33 %34 + %33 = OpLabel + %35 = OpLoad %10 %12 + %36 = OpIAdd %10 %35 %14 + OpStore %12 %36 + %37 = OpLoad %10 %12 + %39 = OpIEqual %25 %37 %38 + OpSelectionMerge %41 None + OpBranchConditional %39 %40 %41 + %40 = OpLabel + %42 = OpLoad %10 %27 + %43 = OpIAdd %10 %42 %14 + OpStore %27 %43 + OpBranchConditional %67 %41 %21 + %41 = OpLabel + %44 = OpLoad %10 %12 + OpSelectionMerge %47 None + OpSwitch %44 %46 0 %45 + %46 = OpLabel + OpBranchConditional %67 %47 %21 + %45 = OpLabel + OpStore %12 %38 + OpBranchConditional %67 %46 %21 + %47 = OpLabel + OpBranchConditional %67 %34 %21 + %34 = OpLabel + OpBranchConditional %67 %21 %21 + %21 = OpLabel + %50 = OpLoad %10 %16 + %51 = OpIAdd %10 %50 %14 + OpStore %16 %51 + OpBranch %18 + %20 = OpLabel + OpBranchConditional %67 %9 %9 + %9 = OpLabel + %52 = OpLoad %10 %12 + %53 = OpLoad %10 %27 + %54 = OpSGreaterThan %25 %52 %53 + OpBranchConditional %54 %6 %8 + %8 = OpLabel + OpStore %55 %17 + OpBranch %56 + %56 = OpLabel + OpLoopMerge %58 %59 None + OpBranchConditional %67 %60 %59 + %60 = OpLabel + %61 = OpLoad %10 %55 + %62 = OpSLessThan %25 %61 %24 + OpBranchConditional %62 %57 %58 + %57 = OpLabel + %63 = OpLoad %10 %12 + %64 = OpIAdd %10 %63 %14 + OpStore %12 %64 + OpBranchConditional %67 %59 %59 + %59 = OpLabel + %65 = OpLoad %10 %55 + %66 = OpIAdd %10 %65 %14 + OpStore %55 %66 + OpBranch %56 + %58 = OpLabel + OpReturn + OpFunctionEnd + )"; + + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +TEST(TransformationAddDeadConditionalTest, LoopInContinueConstruct) { + // Considers some scenarios where there is a loop in a loop's continue + // construct. + + // The SPIR-V for this test is adapted from the following GLSL, with inlining + // applied so that the loop from foo is in the main loop's continue construct: + // + // int foo() { + // int result = 0; + // for (int j = 0; j < 10; j++) { + // result++; + // } + // return result; + // } + // + // void main() { + // for (int i = 0; i < 100; i += foo()) { + // } + // } + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %31 "i" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypeFunction %6 + %10 = OpTypePointer Function %6 + %12 = OpConstant %6 0 + %20 = OpConstant %6 10 + %21 = OpTypeBool + %100 = OpConstantFalse %21 + %24 = OpConstant %6 1 + %38 = OpConstant %6 100 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %43 = OpVariable %10 Function + %44 = OpVariable %10 Function + %45 = OpVariable %10 Function + %31 = OpVariable %10 Function + OpStore %31 %12 + OpBranch %32 + %32 = OpLabel + OpLoopMerge %34 %35 None + OpBranch %36 + %36 = OpLabel + %37 = OpLoad %6 %31 + %39 = OpSLessThan %21 %37 %38 + OpBranchConditional %39 %33 %34 + %33 = OpLabel + OpBranch %35 + %35 = OpLabel + OpStore %43 %12 + OpStore %44 %12 + OpBranch %46 + %46 = OpLabel + OpLoopMerge %47 %48 None + OpBranch %49 + %49 = OpLabel + %50 = OpLoad %6 %44 + %51 = OpSLessThan %21 %50 %20 + OpBranchConditional %51 %52 %47 + %52 = OpLabel + %53 = OpLoad %6 %43 + OpBranch %101 + %101 = OpLabel + %54 = OpIAdd %6 %53 %24 + OpStore %43 %54 + OpBranch %48 + %48 = OpLabel + %55 = OpLoad %6 %44 + %56 = OpIAdd %6 %55 %24 + OpStore %44 %56 + OpBranch %46 + %47 = OpLabel + %57 = OpLoad %6 %43 + OpStore %45 %57 + %40 = OpLoad %6 %45 + %41 = OpLoad %6 %31 + %42 = OpIAdd %6 %41 %40 + OpStore %31 %42 + OpBranch %32 + %34 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + std::vector good = {32, 33, 46, 52, 101}; + std::vector bad = {5, 34, 36, 35, 47, 49, 48}; + + for (uint32_t from_block : bad) { + ASSERT_FALSE(TransformationAddDeadContinue(from_block, false, {}) + .IsApplicable(context.get(), fact_manager)); + } + for (uint32_t from_block : good) { + const TransformationAddDeadContinue transformation(from_block, false, {}); + ASSERT_TRUE(transformation.IsApplicable(context.get(), fact_manager)); + transformation.Apply(context.get(), &fact_manager); + ASSERT_FALSE(transformation.IsApplicable(context.get(), fact_manager)); + } + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %31 "i" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypeFunction %6 + %10 = OpTypePointer Function %6 + %12 = OpConstant %6 0 + %20 = OpConstant %6 10 + %21 = OpTypeBool + %100 = OpConstantFalse %21 + %24 = OpConstant %6 1 + %38 = OpConstant %6 100 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %43 = OpVariable %10 Function + %44 = OpVariable %10 Function + %45 = OpVariable %10 Function + %31 = OpVariable %10 Function + OpStore %31 %12 + OpBranch %32 + %32 = OpLabel + OpLoopMerge %34 %35 None + OpBranchConditional %100 %35 %36 + %36 = OpLabel + %37 = OpLoad %6 %31 + %39 = OpSLessThan %21 %37 %38 + OpBranchConditional %39 %33 %34 + %33 = OpLabel + OpBranchConditional %100 %35 %35 + %35 = OpLabel + OpStore %43 %12 + OpStore %44 %12 + OpBranch %46 + %46 = OpLabel + OpLoopMerge %47 %48 None + OpBranchConditional %100 %48 %49 + %49 = OpLabel + %50 = OpLoad %6 %44 + %51 = OpSLessThan %21 %50 %20 + OpBranchConditional %51 %52 %47 + %52 = OpLabel + %53 = OpLoad %6 %43 + OpBranchConditional %100 %48 %101 + %101 = OpLabel + %54 = OpIAdd %6 %53 %24 + OpStore %43 %54 + OpBranchConditional %100 %48 %48 + %48 = OpLabel + %55 = OpLoad %6 %44 + %56 = OpIAdd %6 %55 %24 + OpStore %44 %56 + OpBranch %46 + %47 = OpLabel + %57 = OpLoad %6 %43 + OpStore %45 %57 + %40 = OpLoad %6 %45 + %41 = OpLoad %6 %31 + %42 = OpIAdd %6 %41 %40 + OpStore %31 %42 + OpBranch %32 + %34 = OpLabel + OpReturn + OpFunctionEnd + )"; + + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +TEST(TransformationAddDeadContinueTest, PhiInstructions) { + // Checks that the transformation works in the presence of phi instructions. + + // The SPIR-V for this test is adapted from the following GLSL, with a bit of + // extra and artificial work to get some interesting uses of OpPhi: + // + // void main() { + // int x; int y; + // float f; + // x = 2; + // f = 3.0; + // if (x > y) { + // x = 3; + // f = 4.0; + // } else { + // x = x + 2; + // f = f + 10.0; + // } + // while (x < y) { + // x = x + 1; + // f = f + 1.0; + // } + // y = x; + // f = f + 3.0; + // } + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %8 "x" + OpName %12 "f" + OpName %15 "y" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 2 + %10 = OpTypeFloat 32 + %11 = OpTypePointer Function %10 + %13 = OpConstant %10 3 + %17 = OpTypeBool + %80 = OpConstantTrue %17 + %21 = OpConstant %6 3 + %22 = OpConstant %10 4 + %27 = OpConstant %10 10 + %38 = OpConstant %6 1 + %41 = OpConstant %10 1 + %46 = OpUndef %6 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %12 = OpVariable %11 Function + %15 = OpVariable %7 Function + OpStore %8 %9 + OpStore %12 %13 + %18 = OpSGreaterThan %17 %9 %46 + OpSelectionMerge %20 None + OpBranchConditional %18 %19 %23 + %19 = OpLabel + OpStore %8 %21 + OpStore %12 %22 + OpBranch %20 + %23 = OpLabel + %25 = OpIAdd %6 %9 %9 + OpStore %8 %25 + OpBranch %70 + %70 = OpLabel + %28 = OpFAdd %10 %13 %27 + OpStore %12 %28 + OpBranch %20 + %20 = OpLabel + %52 = OpPhi %10 %22 %19 %28 %70 + %48 = OpPhi %6 %21 %19 %25 %70 + OpBranch %29 + %29 = OpLabel + %51 = OpPhi %10 %52 %20 %100 %32 + %47 = OpPhi %6 %48 %20 %101 %32 + OpLoopMerge %31 %32 None + OpBranch %33 + %33 = OpLabel + %36 = OpSLessThan %17 %47 %46 + OpBranchConditional %36 %30 %31 + %30 = OpLabel + %39 = OpIAdd %6 %47 %38 + OpStore %8 %39 + OpBranch %75 + %75 = OpLabel + %42 = OpFAdd %10 %51 %41 + OpStore %12 %42 + OpBranch %32 + %32 = OpLabel + %100 = OpPhi %10 %42 %75 + %101 = OpPhi %6 %39 %75 + OpBranch %29 + %31 = OpLabel + %71 = OpPhi %6 %47 %33 + %72 = OpPhi %10 %51 %33 + OpStore %15 %71 + %45 = OpFAdd %10 %72 %13 + OpStore %12 %45 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + std::vector bad = {5, 19, 20, 23, 31, 32, 33, 70}; + + std::vector good = {29, 30, 75}; + + for (uint32_t from_block : bad) { + ASSERT_FALSE(TransformationAddDeadContinue(from_block, true, {}) + .IsApplicable(context.get(), fact_manager)); + } + auto transformation1 = TransformationAddDeadContinue(29, true, {13, 21}); + ASSERT_TRUE(transformation1.IsApplicable(context.get(), fact_manager)); + transformation1.Apply(context.get(), &fact_manager); + + auto transformation2 = TransformationAddDeadContinue(30, true, {22, 46}); + ASSERT_TRUE(transformation2.IsApplicable(context.get(), fact_manager)); + transformation2.Apply(context.get(), &fact_manager); + + // 75 already has the continue block as a successor, so we should not provide + // phi ids. + auto transformationBad = TransformationAddDeadContinue(75, true, {27, 46}); + ASSERT_FALSE(transformationBad.IsApplicable(context.get(), fact_manager)); + + auto transformation3 = TransformationAddDeadContinue(75, true, {}); + ASSERT_TRUE(transformation3.IsApplicable(context.get(), fact_manager)); + transformation3.Apply(context.get(), &fact_manager); + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %8 "x" + OpName %12 "f" + OpName %15 "y" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 2 + %10 = OpTypeFloat 32 + %11 = OpTypePointer Function %10 + %13 = OpConstant %10 3 + %17 = OpTypeBool + %80 = OpConstantTrue %17 + %21 = OpConstant %6 3 + %22 = OpConstant %10 4 + %27 = OpConstant %10 10 + %38 = OpConstant %6 1 + %41 = OpConstant %10 1 + %46 = OpUndef %6 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %12 = OpVariable %11 Function + %15 = OpVariable %7 Function + OpStore %8 %9 + OpStore %12 %13 + %18 = OpSGreaterThan %17 %9 %46 + OpSelectionMerge %20 None + OpBranchConditional %18 %19 %23 + %19 = OpLabel + OpStore %8 %21 + OpStore %12 %22 + OpBranch %20 + %23 = OpLabel + %25 = OpIAdd %6 %9 %9 + OpStore %8 %25 + OpBranch %70 + %70 = OpLabel + %28 = OpFAdd %10 %13 %27 + OpStore %12 %28 + OpBranch %20 + %20 = OpLabel + %52 = OpPhi %10 %22 %19 %28 %70 + %48 = OpPhi %6 %21 %19 %25 %70 + OpBranch %29 + %29 = OpLabel + %51 = OpPhi %10 %52 %20 %100 %32 + %47 = OpPhi %6 %48 %20 %101 %32 + OpLoopMerge %31 %32 None + OpBranchConditional %80 %33 %32 + %33 = OpLabel + %36 = OpSLessThan %17 %47 %46 + OpBranchConditional %36 %30 %31 + %30 = OpLabel + %39 = OpIAdd %6 %47 %38 + OpStore %8 %39 + OpBranchConditional %80 %75 %32 + %75 = OpLabel + %42 = OpFAdd %10 %51 %41 + OpStore %12 %42 + OpBranchConditional %80 %32 %32 + %32 = OpLabel + %100 = OpPhi %10 %42 %75 %13 %29 %22 %30 + %101 = OpPhi %6 %39 %75 %21 %29 %46 %30 + OpBranch %29 + %31 = OpLabel + %71 = OpPhi %6 %47 %33 + %72 = OpPhi %10 %51 %33 + OpStore %15 %71 + %45 = OpFAdd %10 %72 %13 + OpStore %12 %45 + OpReturn + OpFunctionEnd + )"; + + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +TEST(TransformationAddDeadContinueTest, RespectDominanceRules1) { + // Checks that a dead continue cannot be added if it would prevent a block + // later in the loop from dominating the loop's continue construct, in the + // case where said block defines and id that is used in the loop's continue + // construct. + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %10 = OpTypeBool + %11 = OpConstantFalse %10 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpBranch %6 + %6 = OpLabel + OpLoopMerge %8 %9 None + OpBranch %7 + %7 = OpLabel + %21 = OpCopyObject %10 %11 + OpBranch %9 + %9 = OpLabel + %20 = OpPhi %10 %21 %7 + OpBranchConditional %11 %6 %8 + %8 = OpLabel + OpBranch %12 + %12 = OpLabel + OpLoopMerge %14 %15 None + OpBranch %13 + %13 = OpLabel + OpBranch %22 + %22 = OpLabel + %23 = OpCopyObject %10 %11 + OpBranch %25 + %25 = OpLabel + OpBranch %15 + %15 = OpLabel + %26 = OpCopyObject %10 %23 + OpBranchConditional %11 %12 %14 + %14 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + // This transformation is not applicable because the dead continue from the + // loop body prevents the definition of %23 later in the loop body from + // dominating its use in the loop's continue target. + auto bad_transformation = TransformationAddDeadContinue(13, false, {}); + ASSERT_FALSE(bad_transformation.IsApplicable(context.get(), fact_manager)); + + auto good_transformation_1 = TransformationAddDeadContinue(7, false, {}); + ASSERT_TRUE(good_transformation_1.IsApplicable(context.get(), fact_manager)); + good_transformation_1.Apply(context.get(), &fact_manager); + + auto good_transformation_2 = TransformationAddDeadContinue(22, false, {}); + ASSERT_TRUE(good_transformation_2.IsApplicable(context.get(), fact_manager)); + good_transformation_2.Apply(context.get(), &fact_manager); + + // This transformation is OK, because the definition of %21 in the loop body + // is only used in an OpPhi in the loop's continue target. + auto good_transformation_3 = TransformationAddDeadContinue(6, false, {11}); + ASSERT_TRUE(good_transformation_3.IsApplicable(context.get(), fact_manager)); + good_transformation_3.Apply(context.get(), &fact_manager); + + std::string after_transformations = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %10 = OpTypeBool + %11 = OpConstantFalse %10 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpBranch %6 + %6 = OpLabel + OpLoopMerge %8 %9 None + OpBranchConditional %11 %9 %7 + %7 = OpLabel + %21 = OpCopyObject %10 %11 + OpBranchConditional %11 %9 %9 + %9 = OpLabel + %20 = OpPhi %10 %21 %7 %11 %6 + OpBranchConditional %11 %6 %8 + %8 = OpLabel + OpBranch %12 + %12 = OpLabel + OpLoopMerge %14 %15 None + OpBranch %13 + %13 = OpLabel + OpBranch %22 + %22 = OpLabel + %23 = OpCopyObject %10 %11 + OpBranchConditional %11 %15 %25 + %25 = OpLabel + OpBranch %15 + %15 = OpLabel + %26 = OpCopyObject %10 %23 + OpBranchConditional %11 %12 %14 + %14 = OpLabel + OpReturn + OpFunctionEnd + )"; + + ASSERT_TRUE(IsEqual(env, after_transformations, context.get())); +} + +TEST(TransformationAddDeadContinueTest, RespectDominanceRules2) { + // Checks that a dead continue cannot be added if it would lead to a use after + // the loop failing to be dominated by its definition. + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %10 = OpTypeBool + %11 = OpConstantFalse %10 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpBranch %100 + %100 = OpLabel + OpLoopMerge %101 %102 None + OpBranch %103 + %103 = OpLabel + %200 = OpCopyObject %10 %11 + OpBranch %104 + %104 = OpLabel + OpBranch %102 + %102 = OpLabel + OpBranchConditional %11 %100 %101 + %101 = OpLabel + %201 = OpCopyObject %10 %200 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + // This transformation would shortcut the part of the loop body that defines + // an id used after the loop. + auto bad_transformation = TransformationAddDeadContinue(100, false, {}); + ASSERT_FALSE(bad_transformation.IsApplicable(context.get(), fact_manager)); +} + +TEST(TransformationAddDeadContinueTest, RespectDominanceRules3) { + // Checks that a dead continue cannot be added if it would lead to a dominance + // problem with an id used in an OpPhi after the loop. + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %10 = OpTypeBool + %11 = OpConstantFalse %10 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpBranch %100 + %100 = OpLabel + OpLoopMerge %101 %102 None + OpBranch %103 + %103 = OpLabel + %200 = OpCopyObject %10 %11 + OpBranch %104 + %104 = OpLabel + OpBranch %102 + %102 = OpLabel + OpBranchConditional %11 %100 %101 + %101 = OpLabel + %201 = OpPhi %10 %200 %102 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + // This transformation would shortcut the part of the loop body that defines + // an id used after the loop. + auto bad_transformation = TransformationAddDeadContinue(100, false, {}); + ASSERT_FALSE(bad_transformation.IsApplicable(context.get(), fact_manager)); +} + +TEST(TransformationAddDeadContinueTest, Miscellaneous1) { + // A miscellaneous test that exposed a bug in spirv-fuzz. + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" %586 %623 + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpMemberDecorate %34 0 Offset 0 + OpDecorate %34 Block + OpDecorate %36 DescriptorSet 0 + OpDecorate %36 Binding 0 + OpDecorate %586 BuiltIn FragCoord + OpMemberDecorate %591 0 Offset 0 + OpDecorate %591 Block + OpDecorate %593 DescriptorSet 0 + OpDecorate %593 Binding 1 + OpDecorate %623 Location 0 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 0 + %16 = OpConstant %6 2 + %17 = OpTypeBool + %27 = OpTypeFloat 32 + %28 = OpTypeVector %27 2 + %29 = OpTypeMatrix %28 2 + %30 = OpTypePointer Private %29 + %31 = OpVariable %30 Private + %34 = OpTypeStruct %27 + %35 = OpTypePointer Uniform %34 + %36 = OpVariable %35 Uniform + %37 = OpTypePointer Uniform %27 + %40 = OpTypePointer Private %27 + %43 = OpConstant %6 1 + %62 = OpConstant %6 3 + %64 = OpTypeVector %27 3 + %65 = OpTypeMatrix %64 2 + %66 = OpTypePointer Private %65 + %67 = OpVariable %66 Private + %92 = OpConstant %6 4 + %94 = OpTypeVector %27 4 + %95 = OpTypeMatrix %94 2 + %96 = OpTypePointer Private %95 + %97 = OpVariable %96 Private + %123 = OpTypeMatrix %28 3 + %124 = OpTypePointer Private %123 + %125 = OpVariable %124 Private + %151 = OpTypeMatrix %64 3 + %152 = OpTypePointer Private %151 + %153 = OpVariable %152 Private + %179 = OpTypeMatrix %94 3 + %180 = OpTypePointer Private %179 + %181 = OpVariable %180 Private + %207 = OpTypeMatrix %28 4 + %208 = OpTypePointer Private %207 + %209 = OpVariable %208 Private + %235 = OpTypeMatrix %64 4 + %236 = OpTypePointer Private %235 + %237 = OpVariable %236 Private + %263 = OpTypeMatrix %94 4 + %264 = OpTypePointer Private %263 + %265 = OpVariable %264 Private + %275 = OpTypeInt 32 0 + %276 = OpConstant %275 9 + %277 = OpTypeArray %27 %276 + %278 = OpTypePointer Function %277 + %280 = OpConstant %27 0 + %281 = OpTypePointer Function %27 + %311 = OpConstant %27 16 + %448 = OpConstant %6 5 + %482 = OpConstant %6 6 + %516 = OpConstant %6 7 + %550 = OpConstant %6 8 + %585 = OpTypePointer Input %94 + %586 = OpVariable %585 Input + %587 = OpConstant %275 0 + %588 = OpTypePointer Input %27 + %591 = OpTypeStruct %28 + %592 = OpTypePointer Uniform %591 + %593 = OpVariable %592 Uniform + %596 = OpConstant %27 3 + %601 = OpConstant %275 1 + %617 = OpConstant %6 9 + %622 = OpTypePointer Output %94 + %623 = OpVariable %622 Output + %628 = OpConstant %27 1 + %634 = OpConstantComposite %94 %280 %280 %280 %628 + %635 = OpUndef %6 + %636 = OpUndef %17 + %637 = OpUndef %27 + %638 = OpUndef %64 + %639 = OpUndef %94 + %640 = OpConstantTrue %17 + %736 = OpConstantFalse %17 + %642 = OpVariable %37 Uniform + %643 = OpVariable %40 Private + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpBranch %164 + %164 = OpLabel + OpLoopMerge %166 %167 None + OpBranch %165 + %165 = OpLabel + OpBranch %172 + %172 = OpLabel + OpSelectionMerge %174 None + OpBranchConditional %640 %174 %174 + %174 = OpLabel + %785 = OpCopyObject %6 %43 + OpBranch %167 + %167 = OpLabel + %190 = OpIAdd %6 %9 %785 + OpBranchConditional %640 %164 %166 + %166 = OpLabel + OpBranch %196 + %196 = OpLabel + OpBranch %194 + %194 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + // This transformation would shortcut the part of the loop body that defines + // an id used in the continue target. + auto bad_transformation = TransformationAddDeadContinue(165, false, {}); + ASSERT_FALSE(bad_transformation.IsApplicable(context.get(), fact_manager)); +} + +TEST(TransformationAddDeadContinueTest, Miscellaneous2) { + // A miscellaneous test that exposed a bug in spirv-fuzz. + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %51 = OpTypeBool + %395 = OpConstantTrue %51 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpBranch %389 + %389 = OpLabel + OpLoopMerge %388 %391 None + OpBranch %339 + %339 = OpLabel + OpSelectionMerge %396 None + OpBranchConditional %395 %388 %396 + %396 = OpLabel + OpBranch %1552 + %1552 = OpLabel + OpLoopMerge %1553 %1554 None + OpBranch %1556 + %1556 = OpLabel + OpLoopMerge %1557 %1570 None + OpBranchConditional %395 %1562 %1557 + %1562 = OpLabel + OpBranchConditional %395 %1571 %1570 + %1571 = OpLabel + OpBranch %1557 + %1570 = OpLabel + OpBranch %1556 + %1557 = OpLabel + OpSelectionMerge %1586 None + OpBranchConditional %395 %1553 %1586 + %1586 = OpLabel + OpBranch %1553 + %1554 = OpLabel + OpBranch %1552 + %1553 = OpLabel + OpBranch %388 + %391 = OpLabel + OpBranch %389 + %388 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + // This transformation would introduce a branch from a continue target to + // itself. + auto bad_transformation = TransformationAddDeadContinue(1554, true, {}); + ASSERT_FALSE(bad_transformation.IsApplicable(context.get(), fact_manager)); +} + +TEST(TransformationAddDeadContinueTest, Miscellaneous3) { + // A miscellaneous test that exposed a bug in spirv-fuzz. + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %85 = OpTypeBool + %434 = OpConstantFalse %85 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpBranch %234 + %234 = OpLabel + OpLoopMerge %235 %236 None + OpBranch %259 + %259 = OpLabel + OpLoopMerge %260 %274 None + OpBranchConditional %434 %265 %260 + %265 = OpLabel + OpBranch %275 + %275 = OpLabel + OpBranch %260 + %274 = OpLabel + OpBranch %259 + %260 = OpLabel + OpSelectionMerge %298 None + OpBranchConditional %434 %299 %300 + %300 = OpLabel + OpBranch %235 + %298 = OpLabel + OpUnreachable + %236 = OpLabel + OpBranch %234 + %299 = OpLabel + OpBranch %235 + %235 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + auto bad_transformation = TransformationAddDeadContinue(299, false, {}); + + // The continue edge would connect %299 to the previously-unreachable %236, + // making %299 dominate %236, and breaking the rule that block ordering must + // respect dominance. + ASSERT_FALSE(bad_transformation.IsApplicable(context.get(), fact_manager)); +} + +TEST(TransformationAddDeadContinueTest, Miscellaneous4) { + // A miscellaneous test that exposed a bug in spirv-fuzz. + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %8 "i" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 0 + %16 = OpConstant %6 100 + %17 = OpTypeBool + %100 = OpConstantFalse %17 + %21 = OpConstant %6 1 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + OpStore %8 %9 + OpBranch %10 + %13 = OpLabel + %20 = OpLoad %6 %8 + %22 = OpIAdd %6 %20 %21 + OpStore %8 %22 + OpBranch %10 + %10 = OpLabel + OpLoopMerge %12 %13 None + OpBranch %14 + %14 = OpLabel + %15 = OpLoad %6 %8 + %18 = OpSLessThan %17 %15 %16 + OpBranchConditional %18 %11 %12 + %11 = OpLabel + OpBranch %12 + %12 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + auto bad_transformation = TransformationAddDeadContinue(10, false, {}); + + // The continue edge would connect %10 to the previously-unreachable %13, + // making %10 dominate %13, and breaking the rule that block ordering must + // respect dominance. + ASSERT_FALSE(bad_transformation.IsApplicable(context.get(), fact_manager)); +} + +TEST(TransformationAddDeadContinueTest, Miscellaneous5) { + // A miscellaneous test that exposed a bug in spirv-fuzz. + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeBool + %7 = OpTypePointer Function %6 + %9 = OpConstantTrue %6 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpBranch %98 + %98 = OpLabel + OpLoopMerge %100 %101 None + OpBranch %99 + %99 = OpLabel + OpSelectionMerge %111 None + OpBranchConditional %9 %110 %111 + %110 = OpLabel + OpBranch %100 + %111 = OpLabel + %200 = OpCopyObject %6 %9 + OpBranch %101 + %101 = OpLabel + %201 = OpCopyObject %6 %200 + OpBranchConditional %9 %98 %100 + %100 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + auto bad_transformation = TransformationAddDeadContinue(110, true, {}); + + // The continue edge would lead to the use of %200 in block %101 no longer + // being dominated by its definition in block %111. + ASSERT_FALSE(bad_transformation.IsApplicable(context.get(), fact_manager)); +} + +TEST(TransformationAddDeadContinueTest, Miscellaneous6) { + // A miscellaneous test that exposed a bug in spirv-fuzz. + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeBool + %9 = OpConstantTrue %6 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpBranch %10 + %10 = OpLabel + OpLoopMerge %13 %12 None + OpBranch %11 + %11 = OpLabel + %20 = OpCopyObject %6 %9 + OpBranch %12 + %12 = OpLabel + OpBranchConditional %9 %10 %13 + %13 = OpLabel + %21 = OpCopyObject %6 %20 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + auto bad_transformation = TransformationAddDeadContinue(10, true, {}); + + ASSERT_FALSE(bad_transformation.IsApplicable(context.get(), fact_manager)); +} + +} // namespace +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/test/fuzz/transformation_add_function_test.cpp b/third_party/spirv-tools/test/fuzz/transformation_add_function_test.cpp new file mode 100644 index 0000000000..040d27ca5e --- /dev/null +++ b/third_party/spirv-tools/test/fuzz/transformation_add_function_test.cpp @@ -0,0 +1,2850 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_add_function.h" +#include "source/fuzz/instruction_message.h" +#include "test/fuzz/fuzz_test_util.h" + +namespace spvtools { +namespace fuzz { +namespace { + +protobufs::AccessChainClampingInfo MakeAccessClampingInfo( + uint32_t access_chain_id, + const std::vector>& compare_and_select_ids) { + protobufs::AccessChainClampingInfo result; + result.set_access_chain_id(access_chain_id); + for (auto& compare_and_select_id : compare_and_select_ids) { + auto pair = result.add_compare_and_select_ids(); + pair->set_first(compare_and_select_id.first); + pair->set_second(compare_and_select_id.second); + } + return result; +} + +std::vector GetInstructionsForFunction( + spv_target_env env, const MessageConsumer& consumer, + const std::string& donor, uint32_t function_id) { + std::vector result; + const auto donor_context = + BuildModule(env, consumer, donor, kFuzzAssembleOption); + assert(IsValid(env, donor_context.get()) && "The given donor must be valid."); + for (auto& function : *donor_context->module()) { + if (function.result_id() == function_id) { + function.ForEachInst([&result](opt::Instruction* inst) { + opt::Instruction::OperandList input_operands; + for (uint32_t i = 0; i < inst->NumInOperands(); i++) { + input_operands.push_back(inst->GetInOperand(i)); + } + result.push_back(MakeInstructionMessage(inst->opcode(), inst->type_id(), + inst->result_id(), + input_operands)); + }); + break; + } + } + assert(!result.empty() && "The required function should have been found."); + return result; +} + +// Returns true if and only if every pointer parameter and variable associated +// with |function_id| in |context| is known by |fact_manager| to be arbitrary, +// with the exception of |loop_limiter_id|, which must not be arbitrary. (It +// can be 0 if no loop limiter is expected, and 0 should not be deemed +// arbitrary). +bool AllVariablesAndParametersExceptLoopLimiterAreArbitrary( + opt::IRContext* context, const FactManager& fact_manager, + uint32_t function_id, uint32_t loop_limiter_id) { + // Look at all the functions until the function of interest is found. + for (auto& function : *context->module()) { + if (function.result_id() != function_id) { + continue; + } + // Check that the parameters are all arbitrary. + bool found_non_arbitrary_parameter = false; + function.ForEachParam( + [context, &fact_manager, + &found_non_arbitrary_parameter](opt::Instruction* inst) { + if (context->get_def_use_mgr()->GetDef(inst->type_id())->opcode() == + SpvOpTypePointer && + !fact_manager.VariableValueIsArbitrary(inst->result_id())) { + found_non_arbitrary_parameter = true; + } + }); + if (found_non_arbitrary_parameter) { + // A non-arbitrary parameter was found. + return false; + } + // Look through the instructions in the function's first block. + for (auto& inst : *function.begin()) { + if (inst.opcode() != SpvOpVariable) { + // We have found a non-variable instruction; this means we have gotten + // past all variables, so we are done. + return true; + } + // The variable should be arbitrary if and only if it is not the loop + // limiter. + if ((inst.result_id() == loop_limiter_id) == + fact_manager.VariableValueIsArbitrary(inst.result_id())) { + return false; + } + } + assert(false && + "We should have processed all variables and returned by " + "this point."); + } + assert(false && "We should have found the function of interest."); + return true; +} + +TEST(TransformationAddFunctionTest, BasicTest) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %8 = OpTypeFloat 32 + %9 = OpTypePointer Function %8 + %10 = OpTypeFunction %8 %7 %9 + %18 = OpConstant %8 0 + %20 = OpConstant %6 0 + %28 = OpTypeBool + %37 = OpConstant %6 1 + %42 = OpTypePointer Private %8 + %43 = OpVariable %42 Private + %47 = OpConstant %8 1 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + TransformationAddFunction transformation1(std::vector( + {MakeInstructionMessage( + SpvOpFunction, 8, 13, + {{SPV_OPERAND_TYPE_FUNCTION_CONTROL, {SpvFunctionControlMaskNone}}, + {SPV_OPERAND_TYPE_ID, {10}}}), + MakeInstructionMessage(SpvOpFunctionParameter, 7, 11, {}), + MakeInstructionMessage(SpvOpFunctionParameter, 9, 12, {}), + MakeInstructionMessage(SpvOpLabel, 0, 14, {}), + MakeInstructionMessage( + SpvOpVariable, 9, 17, + {{SPV_OPERAND_TYPE_STORAGE_CLASS, {SpvStorageClassFunction}}}), + MakeInstructionMessage( + SpvOpVariable, 7, 19, + {{SPV_OPERAND_TYPE_STORAGE_CLASS, {SpvStorageClassFunction}}}), + MakeInstructionMessage( + SpvOpStore, 0, 0, + {{SPV_OPERAND_TYPE_ID, {17}}, {SPV_OPERAND_TYPE_ID, {18}}}), + MakeInstructionMessage( + SpvOpStore, 0, 0, + {{SPV_OPERAND_TYPE_ID, {19}}, {SPV_OPERAND_TYPE_ID, {20}}}), + MakeInstructionMessage(SpvOpBranch, 0, 0, {{SPV_OPERAND_TYPE_ID, {21}}}), + MakeInstructionMessage(SpvOpLabel, 0, 21, {}), + MakeInstructionMessage( + SpvOpLoopMerge, 0, 0, + {{SPV_OPERAND_TYPE_ID, {23}}, + {SPV_OPERAND_TYPE_ID, {24}}, + {SPV_OPERAND_TYPE_LOOP_CONTROL, {SpvLoopControlMaskNone}}}), + MakeInstructionMessage(SpvOpBranch, 0, 0, {{SPV_OPERAND_TYPE_ID, {25}}}), + MakeInstructionMessage(SpvOpLabel, 0, 25, {}), + MakeInstructionMessage(SpvOpLoad, 6, 26, {{SPV_OPERAND_TYPE_ID, {19}}}), + MakeInstructionMessage(SpvOpLoad, 6, 27, {{SPV_OPERAND_TYPE_ID, {11}}}), + MakeInstructionMessage( + SpvOpSLessThan, 28, 29, + {{SPV_OPERAND_TYPE_ID, {26}}, {SPV_OPERAND_TYPE_ID, {27}}}), + MakeInstructionMessage(SpvOpBranchConditional, 0, 0, + {{SPV_OPERAND_TYPE_ID, {29}}, + {SPV_OPERAND_TYPE_ID, {22}}, + {SPV_OPERAND_TYPE_ID, {23}}}), + MakeInstructionMessage(SpvOpLabel, 0, 22, {}), + MakeInstructionMessage(SpvOpLoad, 8, 30, {{SPV_OPERAND_TYPE_ID, {12}}}), + MakeInstructionMessage(SpvOpLoad, 6, 31, {{SPV_OPERAND_TYPE_ID, {19}}}), + MakeInstructionMessage(SpvOpConvertSToF, 8, 32, + {{SPV_OPERAND_TYPE_ID, {31}}}), + MakeInstructionMessage( + SpvOpFMul, 8, 33, + {{SPV_OPERAND_TYPE_ID, {30}}, {SPV_OPERAND_TYPE_ID, {32}}}), + MakeInstructionMessage(SpvOpLoad, 8, 34, {{SPV_OPERAND_TYPE_ID, {17}}}), + MakeInstructionMessage( + SpvOpFAdd, 8, 35, + {{SPV_OPERAND_TYPE_ID, {34}}, {SPV_OPERAND_TYPE_ID, {33}}}), + MakeInstructionMessage( + SpvOpStore, 0, 0, + {{SPV_OPERAND_TYPE_ID, {17}}, {SPV_OPERAND_TYPE_ID, {35}}}), + MakeInstructionMessage(SpvOpBranch, 0, 0, {{SPV_OPERAND_TYPE_ID, {24}}}), + MakeInstructionMessage(SpvOpLabel, 0, 24, {}), + MakeInstructionMessage(SpvOpLoad, 6, 36, {{SPV_OPERAND_TYPE_ID, {19}}}), + MakeInstructionMessage( + SpvOpIAdd, 6, 38, + {{SPV_OPERAND_TYPE_ID, {36}}, {SPV_OPERAND_TYPE_ID, {37}}}), + MakeInstructionMessage( + SpvOpStore, 0, 0, + {{SPV_OPERAND_TYPE_ID, {19}}, {SPV_OPERAND_TYPE_ID, {38}}}), + MakeInstructionMessage(SpvOpBranch, 0, 0, {{SPV_OPERAND_TYPE_ID, {21}}}), + MakeInstructionMessage(SpvOpLabel, 0, 23, {}), + MakeInstructionMessage(SpvOpLoad, 8, 39, {{SPV_OPERAND_TYPE_ID, {17}}}), + MakeInstructionMessage(SpvOpReturnValue, 0, 0, + {{SPV_OPERAND_TYPE_ID, {39}}}), + MakeInstructionMessage(SpvOpFunctionEnd, 0, 0, {})})); + + ASSERT_TRUE(transformation1.IsApplicable(context.get(), fact_manager)); + transformation1.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + std::string after_transformation1 = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %8 = OpTypeFloat 32 + %9 = OpTypePointer Function %8 + %10 = OpTypeFunction %8 %7 %9 + %18 = OpConstant %8 0 + %20 = OpConstant %6 0 + %28 = OpTypeBool + %37 = OpConstant %6 1 + %42 = OpTypePointer Private %8 + %43 = OpVariable %42 Private + %47 = OpConstant %8 1 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + %13 = OpFunction %8 None %10 + %11 = OpFunctionParameter %7 + %12 = OpFunctionParameter %9 + %14 = OpLabel + %17 = OpVariable %9 Function + %19 = OpVariable %7 Function + OpStore %17 %18 + OpStore %19 %20 + OpBranch %21 + %21 = OpLabel + OpLoopMerge %23 %24 None + OpBranch %25 + %25 = OpLabel + %26 = OpLoad %6 %19 + %27 = OpLoad %6 %11 + %29 = OpSLessThan %28 %26 %27 + OpBranchConditional %29 %22 %23 + %22 = OpLabel + %30 = OpLoad %8 %12 + %31 = OpLoad %6 %19 + %32 = OpConvertSToF %8 %31 + %33 = OpFMul %8 %30 %32 + %34 = OpLoad %8 %17 + %35 = OpFAdd %8 %34 %33 + OpStore %17 %35 + OpBranch %24 + %24 = OpLabel + %36 = OpLoad %6 %19 + %38 = OpIAdd %6 %36 %37 + OpStore %19 %38 + OpBranch %21 + %23 = OpLabel + %39 = OpLoad %8 %17 + OpReturnValue %39 + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_transformation1, context.get())); + ASSERT_TRUE(fact_manager.BlockIsDead(14)); + ASSERT_TRUE(fact_manager.BlockIsDead(21)); + ASSERT_TRUE(fact_manager.BlockIsDead(22)); + ASSERT_TRUE(fact_manager.BlockIsDead(23)); + ASSERT_TRUE(fact_manager.BlockIsDead(24)); + ASSERT_TRUE(fact_manager.BlockIsDead(25)); + + TransformationAddFunction transformation2(std::vector( + {MakeInstructionMessage( + SpvOpFunction, 2, 15, + {{SPV_OPERAND_TYPE_FUNCTION_CONTROL, {SpvFunctionControlMaskNone}}, + {SPV_OPERAND_TYPE_ID, {3}}}), + MakeInstructionMessage(SpvOpLabel, 0, 16, {}), + MakeInstructionMessage( + SpvOpVariable, 7, 44, + {{SPV_OPERAND_TYPE_STORAGE_CLASS, {SpvStorageClassFunction}}}), + MakeInstructionMessage( + SpvOpVariable, 9, 45, + {{SPV_OPERAND_TYPE_STORAGE_CLASS, {SpvStorageClassFunction}}}), + MakeInstructionMessage( + SpvOpVariable, 7, 48, + {{SPV_OPERAND_TYPE_STORAGE_CLASS, {SpvStorageClassFunction}}}), + MakeInstructionMessage( + SpvOpVariable, 9, 49, + {{SPV_OPERAND_TYPE_STORAGE_CLASS, {SpvStorageClassFunction}}}), + MakeInstructionMessage( + SpvOpStore, 0, 0, + {{SPV_OPERAND_TYPE_ID, {44}}, {SPV_OPERAND_TYPE_ID, {20}}}), + MakeInstructionMessage( + SpvOpStore, 0, 0, + {{SPV_OPERAND_TYPE_ID, {45}}, {SPV_OPERAND_TYPE_ID, {18}}}), + MakeInstructionMessage(SpvOpFunctionCall, 8, 46, + {{SPV_OPERAND_TYPE_ID, {13}}, + {SPV_OPERAND_TYPE_ID, {44}}, + {SPV_OPERAND_TYPE_ID, {45}}}), + MakeInstructionMessage( + SpvOpStore, 0, 0, + {{SPV_OPERAND_TYPE_ID, {48}}, {SPV_OPERAND_TYPE_ID, {37}}}), + MakeInstructionMessage( + SpvOpStore, 0, 0, + {{SPV_OPERAND_TYPE_ID, {49}}, {SPV_OPERAND_TYPE_ID, {47}}}), + MakeInstructionMessage(SpvOpFunctionCall, 8, 50, + {{SPV_OPERAND_TYPE_ID, {13}}, + {SPV_OPERAND_TYPE_ID, {48}}, + {SPV_OPERAND_TYPE_ID, {49}}}), + MakeInstructionMessage( + SpvOpFAdd, 8, 51, + {{SPV_OPERAND_TYPE_ID, {46}}, {SPV_OPERAND_TYPE_ID, {50}}}), + MakeInstructionMessage( + SpvOpStore, 0, 0, + {{SPV_OPERAND_TYPE_ID, {43}}, {SPV_OPERAND_TYPE_ID, {51}}}), + MakeInstructionMessage(SpvOpReturn, 0, 0, {}), + MakeInstructionMessage(SpvOpFunctionEnd, 0, 0, {})})); + + ASSERT_TRUE(transformation2.IsApplicable(context.get(), fact_manager)); + transformation2.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + std::string after_transformation2 = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %8 = OpTypeFloat 32 + %9 = OpTypePointer Function %8 + %10 = OpTypeFunction %8 %7 %9 + %18 = OpConstant %8 0 + %20 = OpConstant %6 0 + %28 = OpTypeBool + %37 = OpConstant %6 1 + %42 = OpTypePointer Private %8 + %43 = OpVariable %42 Private + %47 = OpConstant %8 1 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + %13 = OpFunction %8 None %10 + %11 = OpFunctionParameter %7 + %12 = OpFunctionParameter %9 + %14 = OpLabel + %17 = OpVariable %9 Function + %19 = OpVariable %7 Function + OpStore %17 %18 + OpStore %19 %20 + OpBranch %21 + %21 = OpLabel + OpLoopMerge %23 %24 None + OpBranch %25 + %25 = OpLabel + %26 = OpLoad %6 %19 + %27 = OpLoad %6 %11 + %29 = OpSLessThan %28 %26 %27 + OpBranchConditional %29 %22 %23 + %22 = OpLabel + %30 = OpLoad %8 %12 + %31 = OpLoad %6 %19 + %32 = OpConvertSToF %8 %31 + %33 = OpFMul %8 %30 %32 + %34 = OpLoad %8 %17 + %35 = OpFAdd %8 %34 %33 + OpStore %17 %35 + OpBranch %24 + %24 = OpLabel + %36 = OpLoad %6 %19 + %38 = OpIAdd %6 %36 %37 + OpStore %19 %38 + OpBranch %21 + %23 = OpLabel + %39 = OpLoad %8 %17 + OpReturnValue %39 + OpFunctionEnd + %15 = OpFunction %2 None %3 + %16 = OpLabel + %44 = OpVariable %7 Function + %45 = OpVariable %9 Function + %48 = OpVariable %7 Function + %49 = OpVariable %9 Function + OpStore %44 %20 + OpStore %45 %18 + %46 = OpFunctionCall %8 %13 %44 %45 + OpStore %48 %37 + OpStore %49 %47 + %50 = OpFunctionCall %8 %13 %48 %49 + %51 = OpFAdd %8 %46 %50 + OpStore %43 %51 + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_transformation2, context.get())); + ASSERT_TRUE(fact_manager.BlockIsDead(16)); +} + +TEST(TransformationAddFunctionTest, InapplicableTransformations) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %8 = OpTypeFloat 32 + %9 = OpTypePointer Function %8 + %10 = OpTypeFunction %8 %7 %9 + %18 = OpConstant %8 0 + %20 = OpConstant %6 0 + %28 = OpTypeBool + %37 = OpConstant %6 1 + %42 = OpTypePointer Private %8 + %43 = OpVariable %42 Private + %47 = OpConstant %8 1 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + %13 = OpFunction %8 None %10 + %11 = OpFunctionParameter %7 + %12 = OpFunctionParameter %9 + %14 = OpLabel + %17 = OpVariable %9 Function + %19 = OpVariable %7 Function + OpStore %17 %18 + OpStore %19 %20 + OpBranch %21 + %21 = OpLabel + OpLoopMerge %23 %24 None + OpBranch %25 + %25 = OpLabel + %26 = OpLoad %6 %19 + %27 = OpLoad %6 %11 + %29 = OpSLessThan %28 %26 %27 + OpBranchConditional %29 %22 %23 + %22 = OpLabel + %30 = OpLoad %8 %12 + %31 = OpLoad %6 %19 + %32 = OpConvertSToF %8 %31 + %33 = OpFMul %8 %30 %32 + %34 = OpLoad %8 %17 + %35 = OpFAdd %8 %34 %33 + OpStore %17 %35 + OpBranch %24 + %24 = OpLabel + %36 = OpLoad %6 %19 + %38 = OpIAdd %6 %36 %37 + OpStore %19 %38 + OpBranch %21 + %23 = OpLabel + %39 = OpLoad %8 %17 + OpReturnValue %39 + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + // No instructions + ASSERT_FALSE( + TransformationAddFunction(std::vector({})) + .IsApplicable(context.get(), fact_manager)); + + // No function begin + ASSERT_FALSE( + TransformationAddFunction( + std::vector( + {MakeInstructionMessage(SpvOpFunctionParameter, 7, 11, {}), + MakeInstructionMessage(SpvOpFunctionParameter, 9, 12, {}), + MakeInstructionMessage(SpvOpLabel, 0, 14, {})})) + .IsApplicable(context.get(), fact_manager)); + + // No OpLabel + ASSERT_FALSE( + TransformationAddFunction( + std::vector( + {MakeInstructionMessage(SpvOpFunction, 8, 13, + {{SPV_OPERAND_TYPE_FUNCTION_CONTROL, + {SpvFunctionControlMaskNone}}, + {SPV_OPERAND_TYPE_ID, {10}}}), + MakeInstructionMessage(SpvOpReturnValue, 0, 0, + {{SPV_OPERAND_TYPE_ID, {39}}}), + MakeInstructionMessage(SpvOpFunctionEnd, 0, 0, {})})) + .IsApplicable(context.get(), fact_manager)); + + // Abrupt end of instructions + ASSERT_FALSE(TransformationAddFunction( + std::vector({MakeInstructionMessage( + SpvOpFunction, 8, 13, + {{SPV_OPERAND_TYPE_FUNCTION_CONTROL, + {SpvFunctionControlMaskNone}}, + {SPV_OPERAND_TYPE_ID, {10}}})})) + .IsApplicable(context.get(), fact_manager)); + + // No function end + ASSERT_FALSE( + TransformationAddFunction( + std::vector( + {MakeInstructionMessage(SpvOpFunction, 8, 13, + {{SPV_OPERAND_TYPE_FUNCTION_CONTROL, + {SpvFunctionControlMaskNone}}, + {SPV_OPERAND_TYPE_ID, {10}}}), + MakeInstructionMessage(SpvOpLabel, 0, 14, {}), + MakeInstructionMessage(SpvOpReturnValue, 0, 0, + {{SPV_OPERAND_TYPE_ID, {39}}})})) + .IsApplicable(context.get(), fact_manager)); +} + +TEST(TransformationAddFunctionTest, LoopLimiters) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 0 + %7 = OpTypePointer Function %6 + %8 = OpConstant %6 0 + %9 = OpConstant %6 1 + %10 = OpConstant %6 5 + %11 = OpTypeBool + %12 = OpConstantTrue %11 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + + std::vector instructions; + instructions.push_back(MakeInstructionMessage( + SpvOpFunction, 2, 30, + {{SPV_OPERAND_TYPE_FUNCTION_CONTROL, {SpvFunctionControlMaskNone}}, + {SPV_OPERAND_TYPE_TYPE_ID, {3}}})); + instructions.push_back(MakeInstructionMessage(SpvOpLabel, 0, 31, {})); + instructions.push_back( + MakeInstructionMessage(SpvOpBranch, 0, 0, {{SPV_OPERAND_TYPE_ID, {20}}})); + instructions.push_back(MakeInstructionMessage(SpvOpLabel, 0, 20, {})); + instructions.push_back(MakeInstructionMessage( + SpvOpLoopMerge, 0, 0, + {{SPV_OPERAND_TYPE_ID, {21}}, + {SPV_OPERAND_TYPE_ID, {22}}, + {SPV_OPERAND_TYPE_LOOP_CONTROL, {SpvLoopControlMaskNone}}})); + instructions.push_back(MakeInstructionMessage(SpvOpBranchConditional, 0, 0, + {{SPV_OPERAND_TYPE_ID, {12}}, + {SPV_OPERAND_TYPE_ID, {23}}, + {SPV_OPERAND_TYPE_ID, {21}}})); + instructions.push_back(MakeInstructionMessage(SpvOpLabel, 0, 23, {})); + instructions.push_back(MakeInstructionMessage( + SpvOpLoopMerge, 0, 0, + {{SPV_OPERAND_TYPE_ID, {25}}, + {SPV_OPERAND_TYPE_ID, {26}}, + {SPV_OPERAND_TYPE_LOOP_CONTROL, {SpvLoopControlMaskNone}}})); + instructions.push_back( + MakeInstructionMessage(SpvOpBranch, 0, 0, {{SPV_OPERAND_TYPE_ID, {28}}})); + instructions.push_back(MakeInstructionMessage(SpvOpLabel, 0, 28, {})); + instructions.push_back(MakeInstructionMessage(SpvOpBranchConditional, 0, 0, + {{SPV_OPERAND_TYPE_ID, {12}}, + {SPV_OPERAND_TYPE_ID, {26}}, + {SPV_OPERAND_TYPE_ID, {25}}})); + instructions.push_back(MakeInstructionMessage(SpvOpLabel, 0, 26, {})); + instructions.push_back( + MakeInstructionMessage(SpvOpBranch, 0, 0, {{SPV_OPERAND_TYPE_ID, {23}}})); + instructions.push_back(MakeInstructionMessage(SpvOpLabel, 0, 25, {})); + instructions.push_back(MakeInstructionMessage( + SpvOpLoopMerge, 0, 0, + {{SPV_OPERAND_TYPE_ID, {24}}, + {SPV_OPERAND_TYPE_ID, {27}}, + {SPV_OPERAND_TYPE_LOOP_CONTROL, {SpvLoopControlMaskNone}}})); + instructions.push_back(MakeInstructionMessage(SpvOpBranchConditional, 0, 0, + {{SPV_OPERAND_TYPE_ID, {12}}, + {SPV_OPERAND_TYPE_ID, {24}}, + {SPV_OPERAND_TYPE_ID, {27}}})); + instructions.push_back(MakeInstructionMessage(SpvOpLabel, 0, 27, {})); + instructions.push_back( + MakeInstructionMessage(SpvOpBranch, 0, 0, {{SPV_OPERAND_TYPE_ID, {25}}})); + instructions.push_back(MakeInstructionMessage(SpvOpLabel, 0, 24, {})); + instructions.push_back( + MakeInstructionMessage(SpvOpBranch, 0, 0, {{SPV_OPERAND_TYPE_ID, {22}}})); + instructions.push_back(MakeInstructionMessage(SpvOpLabel, 0, 22, {})); + instructions.push_back( + MakeInstructionMessage(SpvOpBranch, 0, 0, {{SPV_OPERAND_TYPE_ID, {20}}})); + instructions.push_back(MakeInstructionMessage(SpvOpLabel, 0, 21, {})); + instructions.push_back(MakeInstructionMessage(SpvOpReturn, 0, 0, {})); + instructions.push_back(MakeInstructionMessage(SpvOpFunctionEnd, 0, 0, {})); + + FactManager fact_manager1; + FactManager fact_manager2; + + const auto context1 = BuildModule(env, consumer, shader, kFuzzAssembleOption); + const auto context2 = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context1.get())); + + TransformationAddFunction add_dead_function(instructions); + ASSERT_TRUE(add_dead_function.IsApplicable(context1.get(), fact_manager1)); + add_dead_function.Apply(context1.get(), &fact_manager1); + ASSERT_TRUE(IsValid(env, context1.get())); + // The added function should not be deemed livesafe. + ASSERT_FALSE(fact_manager1.FunctionIsLivesafe(30)); + // All variables/parameters in the function should be deemed arbitrary. + ASSERT_TRUE(AllVariablesAndParametersExceptLoopLimiterAreArbitrary( + context1.get(), fact_manager1, 30, 0)); + + std::string added_as_dead_code = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 0 + %7 = OpTypePointer Function %6 + %8 = OpConstant %6 0 + %9 = OpConstant %6 1 + %10 = OpConstant %6 5 + %11 = OpTypeBool + %12 = OpConstantTrue %11 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + %30 = OpFunction %2 None %3 + %31 = OpLabel + OpBranch %20 + %20 = OpLabel + OpLoopMerge %21 %22 None + OpBranchConditional %12 %23 %21 + %23 = OpLabel + OpLoopMerge %25 %26 None + OpBranch %28 + %28 = OpLabel + OpBranchConditional %12 %26 %25 + %26 = OpLabel + OpBranch %23 + %25 = OpLabel + OpLoopMerge %24 %27 None + OpBranchConditional %12 %24 %27 + %27 = OpLabel + OpBranch %25 + %24 = OpLabel + OpBranch %22 + %22 = OpLabel + OpBranch %20 + %21 = OpLabel + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, added_as_dead_code, context1.get())); + + protobufs::LoopLimiterInfo loop_limiter1; + loop_limiter1.set_loop_header_id(20); + loop_limiter1.set_load_id(101); + loop_limiter1.set_increment_id(102); + loop_limiter1.set_compare_id(103); + loop_limiter1.set_logical_op_id(104); + + protobufs::LoopLimiterInfo loop_limiter2; + loop_limiter2.set_loop_header_id(23); + loop_limiter2.set_load_id(105); + loop_limiter2.set_increment_id(106); + loop_limiter2.set_compare_id(107); + loop_limiter2.set_logical_op_id(108); + + protobufs::LoopLimiterInfo loop_limiter3; + loop_limiter3.set_loop_header_id(25); + loop_limiter3.set_load_id(109); + loop_limiter3.set_increment_id(110); + loop_limiter3.set_compare_id(111); + loop_limiter3.set_logical_op_id(112); + + std::vector loop_limiters = { + loop_limiter1, loop_limiter2, loop_limiter3}; + + TransformationAddFunction add_livesafe_function(instructions, 100, 10, + loop_limiters, 0, {}); + ASSERT_TRUE( + add_livesafe_function.IsApplicable(context2.get(), fact_manager2)); + add_livesafe_function.Apply(context2.get(), &fact_manager2); + ASSERT_TRUE(IsValid(env, context2.get())); + // The added function should indeed be deemed livesafe. + ASSERT_TRUE(fact_manager2.FunctionIsLivesafe(30)); + // All variables/parameters in the function should be deemed arbitrary, + // except the loop limiter. + ASSERT_TRUE(AllVariablesAndParametersExceptLoopLimiterAreArbitrary( + context2.get(), fact_manager2, 30, 100)); + std::string added_as_livesafe_code = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 0 + %7 = OpTypePointer Function %6 + %8 = OpConstant %6 0 + %9 = OpConstant %6 1 + %10 = OpConstant %6 5 + %11 = OpTypeBool + %12 = OpConstantTrue %11 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + %30 = OpFunction %2 None %3 + %31 = OpLabel + %100 = OpVariable %7 Function %8 + OpBranch %20 + %20 = OpLabel + OpLoopMerge %21 %22 None + OpBranchConditional %12 %23 %21 + %23 = OpLabel + OpLoopMerge %25 %26 None + OpBranch %28 + %28 = OpLabel + OpBranchConditional %12 %26 %25 + %26 = OpLabel + %105 = OpLoad %6 %100 + %106 = OpIAdd %6 %105 %9 + OpStore %100 %106 + %107 = OpUGreaterThanEqual %11 %105 %10 + OpBranchConditional %107 %25 %23 + %25 = OpLabel + OpLoopMerge %24 %27 None + OpBranchConditional %12 %24 %27 + %27 = OpLabel + %109 = OpLoad %6 %100 + %110 = OpIAdd %6 %109 %9 + OpStore %100 %110 + %111 = OpUGreaterThanEqual %11 %109 %10 + OpBranchConditional %111 %24 %25 + %24 = OpLabel + OpBranch %22 + %22 = OpLabel + %101 = OpLoad %6 %100 + %102 = OpIAdd %6 %101 %9 + OpStore %100 %102 + %103 = OpUGreaterThanEqual %11 %101 %10 + OpBranchConditional %103 %21 %20 + %21 = OpLabel + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, added_as_livesafe_code, context2.get())); +} + +TEST(TransformationAddFunctionTest, KillAndUnreachableInVoidFunction) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %8 = OpTypeFunction %2 %7 + %13 = OpConstant %6 2 + %14 = OpTypeBool + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + + std::vector instructions; + + instructions.push_back(MakeInstructionMessage( + SpvOpFunction, 2, 10, + {{SPV_OPERAND_TYPE_FUNCTION_CONTROL, {SpvFunctionControlMaskNone}}, + {SPV_OPERAND_TYPE_TYPE_ID, {8}}})); + instructions.push_back( + MakeInstructionMessage(SpvOpFunctionParameter, 7, 9, {})); + instructions.push_back(MakeInstructionMessage(SpvOpLabel, 0, 11, {})); + instructions.push_back( + MakeInstructionMessage(SpvOpLoad, 6, 12, {{SPV_OPERAND_TYPE_ID, {9}}})); + instructions.push_back(MakeInstructionMessage( + SpvOpIEqual, 14, 15, + {{SPV_OPERAND_TYPE_ID, {12}}, {SPV_OPERAND_TYPE_ID, {13}}})); + instructions.push_back(MakeInstructionMessage( + SpvOpSelectionMerge, 0, 0, + {{SPV_OPERAND_TYPE_ID, {17}}, + {SPV_OPERAND_TYPE_SELECTION_CONTROL, {SpvSelectionControlMaskNone}}})); + instructions.push_back(MakeInstructionMessage(SpvOpBranchConditional, 0, 0, + {{SPV_OPERAND_TYPE_ID, {15}}, + {SPV_OPERAND_TYPE_ID, {16}}, + {SPV_OPERAND_TYPE_ID, {17}}})); + instructions.push_back(MakeInstructionMessage(SpvOpLabel, 0, 16, {})); + instructions.push_back(MakeInstructionMessage(SpvOpUnreachable, 0, 0, {})); + instructions.push_back(MakeInstructionMessage(SpvOpLabel, 0, 17, {})); + instructions.push_back(MakeInstructionMessage(SpvOpKill, 0, 0, {})); + instructions.push_back(MakeInstructionMessage(SpvOpFunctionEnd, 0, 0, {})); + + FactManager fact_manager1; + FactManager fact_manager2; + + const auto context1 = BuildModule(env, consumer, shader, kFuzzAssembleOption); + const auto context2 = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context1.get())); + + TransformationAddFunction add_dead_function(instructions); + ASSERT_TRUE(add_dead_function.IsApplicable(context1.get(), fact_manager1)); + add_dead_function.Apply(context1.get(), &fact_manager1); + ASSERT_TRUE(IsValid(env, context1.get())); + // The added function should not be deemed livesafe. + ASSERT_FALSE(fact_manager1.FunctionIsLivesafe(10)); + // All variables/parameters in the function should be deemed arbitrary. + ASSERT_TRUE(AllVariablesAndParametersExceptLoopLimiterAreArbitrary( + context1.get(), fact_manager1, 10, 0)); + + std::string added_as_dead_code = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %8 = OpTypeFunction %2 %7 + %13 = OpConstant %6 2 + %14 = OpTypeBool + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + %10 = OpFunction %2 None %8 + %9 = OpFunctionParameter %7 + %11 = OpLabel + %12 = OpLoad %6 %9 + %15 = OpIEqual %14 %12 %13 + OpSelectionMerge %17 None + OpBranchConditional %15 %16 %17 + %16 = OpLabel + OpUnreachable + %17 = OpLabel + OpKill + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, added_as_dead_code, context1.get())); + + TransformationAddFunction add_livesafe_function(instructions, 0, 0, {}, 0, + {}); + ASSERT_TRUE( + add_livesafe_function.IsApplicable(context2.get(), fact_manager2)); + add_livesafe_function.Apply(context2.get(), &fact_manager2); + ASSERT_TRUE(IsValid(env, context2.get())); + // The added function should indeed be deemed livesafe. + ASSERT_TRUE(fact_manager2.FunctionIsLivesafe(10)); + // All variables/parameters in the function should be deemed arbitrary. + ASSERT_TRUE(AllVariablesAndParametersExceptLoopLimiterAreArbitrary( + context2.get(), fact_manager2, 10, 0)); + std::string added_as_livesafe_code = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %8 = OpTypeFunction %2 %7 + %13 = OpConstant %6 2 + %14 = OpTypeBool + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + %10 = OpFunction %2 None %8 + %9 = OpFunctionParameter %7 + %11 = OpLabel + %12 = OpLoad %6 %9 + %15 = OpIEqual %14 %12 %13 + OpSelectionMerge %17 None + OpBranchConditional %15 %16 %17 + %16 = OpLabel + OpReturn + %17 = OpLabel + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, added_as_livesafe_code, context2.get())); +} + +TEST(TransformationAddFunctionTest, KillAndUnreachableInNonVoidFunction) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %8 = OpTypeFunction %2 %7 + %50 = OpTypeFunction %6 %7 + %13 = OpConstant %6 2 + %14 = OpTypeBool + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + + std::vector instructions; + + instructions.push_back(MakeInstructionMessage( + SpvOpFunction, 6, 10, + {{SPV_OPERAND_TYPE_FUNCTION_CONTROL, {SpvFunctionControlMaskNone}}, + {SPV_OPERAND_TYPE_TYPE_ID, {50}}})); + instructions.push_back( + MakeInstructionMessage(SpvOpFunctionParameter, 7, 9, {})); + instructions.push_back(MakeInstructionMessage(SpvOpLabel, 0, 11, {})); + instructions.push_back( + MakeInstructionMessage(SpvOpLoad, 6, 12, {{SPV_OPERAND_TYPE_ID, {9}}})); + instructions.push_back(MakeInstructionMessage( + SpvOpIEqual, 14, 15, + {{SPV_OPERAND_TYPE_ID, {12}}, {SPV_OPERAND_TYPE_ID, {13}}})); + instructions.push_back(MakeInstructionMessage( + SpvOpSelectionMerge, 0, 0, + {{SPV_OPERAND_TYPE_ID, {17}}, + {SPV_OPERAND_TYPE_SELECTION_CONTROL, {SpvSelectionControlMaskNone}}})); + instructions.push_back(MakeInstructionMessage(SpvOpBranchConditional, 0, 0, + {{SPV_OPERAND_TYPE_ID, {15}}, + {SPV_OPERAND_TYPE_ID, {16}}, + {SPV_OPERAND_TYPE_ID, {17}}})); + instructions.push_back(MakeInstructionMessage(SpvOpLabel, 0, 16, {})); + instructions.push_back(MakeInstructionMessage(SpvOpUnreachable, 0, 0, {})); + instructions.push_back(MakeInstructionMessage(SpvOpLabel, 0, 17, {})); + instructions.push_back(MakeInstructionMessage(SpvOpKill, 0, 0, {})); + instructions.push_back(MakeInstructionMessage(SpvOpFunctionEnd, 0, 0, {})); + + FactManager fact_manager1; + FactManager fact_manager2; + + const auto context1 = BuildModule(env, consumer, shader, kFuzzAssembleOption); + const auto context2 = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context1.get())); + + TransformationAddFunction add_dead_function(instructions); + ASSERT_TRUE(add_dead_function.IsApplicable(context1.get(), fact_manager1)); + add_dead_function.Apply(context1.get(), &fact_manager1); + ASSERT_TRUE(IsValid(env, context1.get())); + // The added function should not be deemed livesafe. + ASSERT_FALSE(fact_manager1.FunctionIsLivesafe(10)); + // All variables/parameters in the function should be deemed arbitrary. + ASSERT_TRUE(AllVariablesAndParametersExceptLoopLimiterAreArbitrary( + context1.get(), fact_manager1, 10, 0)); + + std::string added_as_dead_code = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %8 = OpTypeFunction %2 %7 + %50 = OpTypeFunction %6 %7 + %13 = OpConstant %6 2 + %14 = OpTypeBool + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + %10 = OpFunction %6 None %50 + %9 = OpFunctionParameter %7 + %11 = OpLabel + %12 = OpLoad %6 %9 + %15 = OpIEqual %14 %12 %13 + OpSelectionMerge %17 None + OpBranchConditional %15 %16 %17 + %16 = OpLabel + OpUnreachable + %17 = OpLabel + OpKill + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, added_as_dead_code, context1.get())); + + TransformationAddFunction add_livesafe_function(instructions, 0, 0, {}, 13, + {}); + ASSERT_TRUE( + add_livesafe_function.IsApplicable(context2.get(), fact_manager2)); + add_livesafe_function.Apply(context2.get(), &fact_manager2); + ASSERT_TRUE(IsValid(env, context2.get())); + // The added function should indeed be deemed livesafe. + ASSERT_TRUE(fact_manager2.FunctionIsLivesafe(10)); + // All variables/parameters in the function should be deemed arbitrary. + ASSERT_TRUE(AllVariablesAndParametersExceptLoopLimiterAreArbitrary( + context2.get(), fact_manager2, 10, 0)); + std::string added_as_livesafe_code = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %8 = OpTypeFunction %2 %7 + %50 = OpTypeFunction %6 %7 + %13 = OpConstant %6 2 + %14 = OpTypeBool + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + %10 = OpFunction %6 None %50 + %9 = OpFunctionParameter %7 + %11 = OpLabel + %12 = OpLoad %6 %9 + %15 = OpIEqual %14 %12 %13 + OpSelectionMerge %17 None + OpBranchConditional %15 %16 %17 + %16 = OpLabel + OpReturnValue %13 + %17 = OpLabel + OpReturnValue %13 + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, added_as_livesafe_code, context2.get())); +} + +TEST(TransformationAddFunctionTest, ClampedAccessChains) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %100 = OpTypeBool + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %15 = OpTypeInt 32 0 + %102 = OpTypePointer Function %15 + %8 = OpTypeFunction %2 %7 %102 %7 + %16 = OpConstant %15 5 + %17 = OpTypeArray %6 %16 + %18 = OpTypeArray %17 %16 + %19 = OpTypePointer Private %18 + %20 = OpVariable %19 Private + %21 = OpConstant %6 0 + %23 = OpTypePointer Private %6 + %26 = OpTypePointer Function %17 + %29 = OpTypePointer Private %17 + %33 = OpConstant %6 4 + %200 = OpConstant %15 4 + %35 = OpConstant %15 10 + %36 = OpTypeArray %6 %35 + %37 = OpTypePointer Private %36 + %38 = OpVariable %37 Private + %54 = OpTypeFloat 32 + %55 = OpTypeVector %54 4 + %56 = OpTypePointer Private %55 + %57 = OpVariable %56 Private + %59 = OpTypeVector %54 3 + %60 = OpTypeMatrix %59 2 + %61 = OpTypePointer Private %60 + %62 = OpVariable %61 Private + %64 = OpTypePointer Private %54 + %69 = OpConstant %54 2 + %71 = OpConstant %6 1 + %72 = OpConstant %6 2 + %201 = OpConstant %15 2 + %73 = OpConstant %6 3 + %202 = OpConstant %15 3 + %203 = OpConstant %6 1 + %204 = OpConstant %6 9 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + + std::vector instructions; + + instructions.push_back(MakeInstructionMessage( + SpvOpFunction, 2, 12, + {{SPV_OPERAND_TYPE_FUNCTION_CONTROL, {SpvFunctionControlMaskNone}}, + {SPV_OPERAND_TYPE_TYPE_ID, {8}}})); + instructions.push_back( + MakeInstructionMessage(SpvOpFunctionParameter, 7, 9, {})); + instructions.push_back( + MakeInstructionMessage(SpvOpFunctionParameter, 102, 10, {})); + instructions.push_back( + MakeInstructionMessage(SpvOpFunctionParameter, 7, 11, {})); + instructions.push_back(MakeInstructionMessage(SpvOpLabel, 0, 13, {})); + + instructions.push_back(MakeInstructionMessage( + SpvOpVariable, 7, 14, + {{SPV_OPERAND_TYPE_STORAGE_CLASS, {SpvStorageClassFunction}}})); + instructions.push_back(MakeInstructionMessage( + SpvOpVariable, 26, 27, + {{SPV_OPERAND_TYPE_STORAGE_CLASS, {SpvStorageClassFunction}}})); + instructions.push_back( + MakeInstructionMessage(SpvOpLoad, 6, 22, {{SPV_OPERAND_TYPE_ID, {11}}})); + instructions.push_back(MakeInstructionMessage(SpvOpAccessChain, 23, 24, + {{SPV_OPERAND_TYPE_ID, {20}}, + {SPV_OPERAND_TYPE_ID, {21}}, + {SPV_OPERAND_TYPE_ID, {22}}})); + instructions.push_back( + MakeInstructionMessage(SpvOpLoad, 6, 25, {{SPV_OPERAND_TYPE_ID, {24}}})); + instructions.push_back(MakeInstructionMessage( + SpvOpStore, 0, 0, + {{SPV_OPERAND_TYPE_ID, {14}}, {SPV_OPERAND_TYPE_ID, {25}}})); + instructions.push_back( + MakeInstructionMessage(SpvOpLoad, 15, 28, {{SPV_OPERAND_TYPE_ID, {10}}})); + instructions.push_back(MakeInstructionMessage( + SpvOpAccessChain, 29, 30, + {{SPV_OPERAND_TYPE_ID, {20}}, {SPV_OPERAND_TYPE_ID, {28}}})); + instructions.push_back( + MakeInstructionMessage(SpvOpLoad, 17, 31, {{SPV_OPERAND_TYPE_ID, {30}}})); + instructions.push_back(MakeInstructionMessage( + SpvOpStore, 0, 0, + {{SPV_OPERAND_TYPE_ID, {27}}, {SPV_OPERAND_TYPE_ID, {31}}})); + instructions.push_back( + MakeInstructionMessage(SpvOpLoad, 6, 32, {{SPV_OPERAND_TYPE_ID, {9}}})); + instructions.push_back(MakeInstructionMessage( + SpvOpInBoundsAccessChain, 7, 34, + {{SPV_OPERAND_TYPE_ID, {27}}, {SPV_OPERAND_TYPE_ID, {32}}})); + instructions.push_back(MakeInstructionMessage( + SpvOpStore, 0, 0, + {{SPV_OPERAND_TYPE_ID, {34}}, {SPV_OPERAND_TYPE_ID, {33}}})); + instructions.push_back( + MakeInstructionMessage(SpvOpLoad, 6, 39, {{SPV_OPERAND_TYPE_ID, {9}}})); + instructions.push_back(MakeInstructionMessage( + SpvOpAccessChain, 23, 40, + {{SPV_OPERAND_TYPE_ID, {38}}, {SPV_OPERAND_TYPE_ID, {33}}})); + instructions.push_back( + MakeInstructionMessage(SpvOpLoad, 6, 41, {{SPV_OPERAND_TYPE_ID, {40}}})); + instructions.push_back(MakeInstructionMessage( + SpvOpInBoundsAccessChain, 23, 42, + {{SPV_OPERAND_TYPE_ID, {38}}, {SPV_OPERAND_TYPE_ID, {39}}})); + instructions.push_back(MakeInstructionMessage( + SpvOpStore, 0, 0, + {{SPV_OPERAND_TYPE_ID, {42}}, {SPV_OPERAND_TYPE_ID, {41}}})); + instructions.push_back( + MakeInstructionMessage(SpvOpLoad, 15, 43, {{SPV_OPERAND_TYPE_ID, {10}}})); + instructions.push_back( + MakeInstructionMessage(SpvOpLoad, 6, 44, {{SPV_OPERAND_TYPE_ID, {11}}})); + instructions.push_back( + MakeInstructionMessage(SpvOpLoad, 6, 45, {{SPV_OPERAND_TYPE_ID, {9}}})); + instructions.push_back( + MakeInstructionMessage(SpvOpLoad, 15, 46, {{SPV_OPERAND_TYPE_ID, {10}}})); + instructions.push_back(MakeInstructionMessage( + SpvOpIAdd, 6, 47, + {{SPV_OPERAND_TYPE_ID, {45}}, {SPV_OPERAND_TYPE_ID, {46}}})); + instructions.push_back(MakeInstructionMessage( + SpvOpAccessChain, 23, 48, + {{SPV_OPERAND_TYPE_ID, {38}}, {SPV_OPERAND_TYPE_ID, {47}}})); + instructions.push_back( + MakeInstructionMessage(SpvOpLoad, 6, 49, {{SPV_OPERAND_TYPE_ID, {48}}})); + instructions.push_back(MakeInstructionMessage(SpvOpInBoundsAccessChain, 23, + 50, + {{SPV_OPERAND_TYPE_ID, {20}}, + {SPV_OPERAND_TYPE_ID, {43}}, + {SPV_OPERAND_TYPE_ID, {44}}})); + instructions.push_back( + MakeInstructionMessage(SpvOpLoad, 6, 51, {{SPV_OPERAND_TYPE_ID, {50}}})); + instructions.push_back(MakeInstructionMessage( + SpvOpIAdd, 6, 52, + {{SPV_OPERAND_TYPE_ID, {51}}, {SPV_OPERAND_TYPE_ID, {49}}})); + instructions.push_back(MakeInstructionMessage(SpvOpAccessChain, 23, 53, + {{SPV_OPERAND_TYPE_ID, {20}}, + {SPV_OPERAND_TYPE_ID, {43}}, + {SPV_OPERAND_TYPE_ID, {44}}})); + instructions.push_back(MakeInstructionMessage( + SpvOpStore, 0, 0, + {{SPV_OPERAND_TYPE_ID, {53}}, {SPV_OPERAND_TYPE_ID, {52}}})); + instructions.push_back( + MakeInstructionMessage(SpvOpLoad, 15, 58, {{SPV_OPERAND_TYPE_ID, {10}}})); + instructions.push_back( + MakeInstructionMessage(SpvOpLoad, 6, 63, {{SPV_OPERAND_TYPE_ID, {11}}})); + instructions.push_back(MakeInstructionMessage(SpvOpAccessChain, 64, 65, + {{SPV_OPERAND_TYPE_ID, {62}}, + {SPV_OPERAND_TYPE_ID, {21}}, + {SPV_OPERAND_TYPE_ID, {63}}})); + instructions.push_back(MakeInstructionMessage(SpvOpAccessChain, 64, 101, + {{SPV_OPERAND_TYPE_ID, {62}}, + {SPV_OPERAND_TYPE_ID, {45}}, + {SPV_OPERAND_TYPE_ID, {46}}})); + instructions.push_back( + MakeInstructionMessage(SpvOpLoad, 54, 66, {{SPV_OPERAND_TYPE_ID, {65}}})); + instructions.push_back(MakeInstructionMessage( + SpvOpAccessChain, 64, 67, + {{SPV_OPERAND_TYPE_ID, {57}}, {SPV_OPERAND_TYPE_ID, {58}}})); + instructions.push_back(MakeInstructionMessage( + SpvOpStore, 0, 0, + {{SPV_OPERAND_TYPE_ID, {67}}, {SPV_OPERAND_TYPE_ID, {66}}})); + instructions.push_back( + MakeInstructionMessage(SpvOpLoad, 6, 68, {{SPV_OPERAND_TYPE_ID, {9}}})); + instructions.push_back(MakeInstructionMessage( + SpvOpInBoundsAccessChain, 64, 70, + {{SPV_OPERAND_TYPE_ID, {57}}, {SPV_OPERAND_TYPE_ID, {68}}})); + instructions.push_back(MakeInstructionMessage( + SpvOpStore, 0, 0, + {{SPV_OPERAND_TYPE_ID, {70}}, {SPV_OPERAND_TYPE_ID, {69}}})); + instructions.push_back(MakeInstructionMessage(SpvOpReturn, 0, 0, {})); + instructions.push_back(MakeInstructionMessage(SpvOpFunctionEnd, 0, 0, {})); + + FactManager fact_manager1; + FactManager fact_manager2; + + const auto context1 = BuildModule(env, consumer, shader, kFuzzAssembleOption); + const auto context2 = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context1.get())); + + TransformationAddFunction add_dead_function(instructions); + ASSERT_TRUE(add_dead_function.IsApplicable(context1.get(), fact_manager1)); + add_dead_function.Apply(context1.get(), &fact_manager1); + ASSERT_TRUE(IsValid(env, context1.get())); + // The function should not be deemed livesafe + ASSERT_FALSE(fact_manager1.FunctionIsLivesafe(12)); + // All variables/parameters in the function should be deemed arbitrary. + ASSERT_TRUE(AllVariablesAndParametersExceptLoopLimiterAreArbitrary( + context1.get(), fact_manager1, 12, 0)); + + std::string added_as_dead_code = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %100 = OpTypeBool + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %15 = OpTypeInt 32 0 + %102 = OpTypePointer Function %15 + %8 = OpTypeFunction %2 %7 %102 %7 + %16 = OpConstant %15 5 + %17 = OpTypeArray %6 %16 + %18 = OpTypeArray %17 %16 + %19 = OpTypePointer Private %18 + %20 = OpVariable %19 Private + %21 = OpConstant %6 0 + %23 = OpTypePointer Private %6 + %26 = OpTypePointer Function %17 + %29 = OpTypePointer Private %17 + %33 = OpConstant %6 4 + %200 = OpConstant %15 4 + %35 = OpConstant %15 10 + %36 = OpTypeArray %6 %35 + %37 = OpTypePointer Private %36 + %38 = OpVariable %37 Private + %54 = OpTypeFloat 32 + %55 = OpTypeVector %54 4 + %56 = OpTypePointer Private %55 + %57 = OpVariable %56 Private + %59 = OpTypeVector %54 3 + %60 = OpTypeMatrix %59 2 + %61 = OpTypePointer Private %60 + %62 = OpVariable %61 Private + %64 = OpTypePointer Private %54 + %69 = OpConstant %54 2 + %71 = OpConstant %6 1 + %72 = OpConstant %6 2 + %201 = OpConstant %15 2 + %73 = OpConstant %6 3 + %202 = OpConstant %15 3 + %203 = OpConstant %6 1 + %204 = OpConstant %6 9 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + %12 = OpFunction %2 None %8 + %9 = OpFunctionParameter %7 + %10 = OpFunctionParameter %102 + %11 = OpFunctionParameter %7 + %13 = OpLabel + %14 = OpVariable %7 Function + %27 = OpVariable %26 Function + %22 = OpLoad %6 %11 + %24 = OpAccessChain %23 %20 %21 %22 + %25 = OpLoad %6 %24 + OpStore %14 %25 + %28 = OpLoad %15 %10 + %30 = OpAccessChain %29 %20 %28 + %31 = OpLoad %17 %30 + OpStore %27 %31 + %32 = OpLoad %6 %9 + %34 = OpInBoundsAccessChain %7 %27 %32 + OpStore %34 %33 + %39 = OpLoad %6 %9 + %40 = OpAccessChain %23 %38 %33 + %41 = OpLoad %6 %40 + %42 = OpInBoundsAccessChain %23 %38 %39 + OpStore %42 %41 + %43 = OpLoad %15 %10 + %44 = OpLoad %6 %11 + %45 = OpLoad %6 %9 + %46 = OpLoad %15 %10 + %47 = OpIAdd %6 %45 %46 + %48 = OpAccessChain %23 %38 %47 + %49 = OpLoad %6 %48 + %50 = OpInBoundsAccessChain %23 %20 %43 %44 + %51 = OpLoad %6 %50 + %52 = OpIAdd %6 %51 %49 + %53 = OpAccessChain %23 %20 %43 %44 + OpStore %53 %52 + %58 = OpLoad %15 %10 + %63 = OpLoad %6 %11 + %65 = OpAccessChain %64 %62 %21 %63 + %101 = OpAccessChain %64 %62 %45 %46 + %66 = OpLoad %54 %65 + %67 = OpAccessChain %64 %57 %58 + OpStore %67 %66 + %68 = OpLoad %6 %9 + %70 = OpInBoundsAccessChain %64 %57 %68 + OpStore %70 %69 + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, added_as_dead_code, context1.get())); + + std::vector access_chain_clamping_info; + access_chain_clamping_info.push_back( + MakeAccessClampingInfo(24, {{1001, 2001}, {1002, 2002}})); + access_chain_clamping_info.push_back( + MakeAccessClampingInfo(30, {{1003, 2003}})); + access_chain_clamping_info.push_back( + MakeAccessClampingInfo(34, {{1004, 2004}})); + access_chain_clamping_info.push_back( + MakeAccessClampingInfo(40, {{1005, 2005}})); + access_chain_clamping_info.push_back( + MakeAccessClampingInfo(42, {{1006, 2006}})); + access_chain_clamping_info.push_back( + MakeAccessClampingInfo(48, {{1007, 2007}})); + access_chain_clamping_info.push_back( + MakeAccessClampingInfo(50, {{1008, 2008}, {1009, 2009}})); + access_chain_clamping_info.push_back( + MakeAccessClampingInfo(53, {{1010, 2010}, {1011, 2011}})); + access_chain_clamping_info.push_back( + MakeAccessClampingInfo(65, {{1012, 2012}, {1013, 2013}})); + access_chain_clamping_info.push_back( + MakeAccessClampingInfo(101, {{1014, 2014}, {1015, 2015}})); + access_chain_clamping_info.push_back( + MakeAccessClampingInfo(67, {{1016, 2016}})); + access_chain_clamping_info.push_back( + MakeAccessClampingInfo(70, {{1017, 2017}})); + + TransformationAddFunction add_livesafe_function(instructions, 0, 0, {}, 13, + access_chain_clamping_info); + ASSERT_TRUE( + add_livesafe_function.IsApplicable(context2.get(), fact_manager2)); + add_livesafe_function.Apply(context2.get(), &fact_manager2); + ASSERT_TRUE(IsValid(env, context2.get())); + // The function should be deemed livesafe + ASSERT_TRUE(fact_manager2.FunctionIsLivesafe(12)); + // All variables/parameters in the function should be deemed arbitrary. + ASSERT_TRUE(AllVariablesAndParametersExceptLoopLimiterAreArbitrary( + context2.get(), fact_manager2, 12, 0)); + std::string added_as_livesafe_code = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %100 = OpTypeBool + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %15 = OpTypeInt 32 0 + %102 = OpTypePointer Function %15 + %8 = OpTypeFunction %2 %7 %102 %7 + %16 = OpConstant %15 5 + %17 = OpTypeArray %6 %16 + %18 = OpTypeArray %17 %16 + %19 = OpTypePointer Private %18 + %20 = OpVariable %19 Private + %21 = OpConstant %6 0 + %23 = OpTypePointer Private %6 + %26 = OpTypePointer Function %17 + %29 = OpTypePointer Private %17 + %33 = OpConstant %6 4 + %200 = OpConstant %15 4 + %35 = OpConstant %15 10 + %36 = OpTypeArray %6 %35 + %37 = OpTypePointer Private %36 + %38 = OpVariable %37 Private + %54 = OpTypeFloat 32 + %55 = OpTypeVector %54 4 + %56 = OpTypePointer Private %55 + %57 = OpVariable %56 Private + %59 = OpTypeVector %54 3 + %60 = OpTypeMatrix %59 2 + %61 = OpTypePointer Private %60 + %62 = OpVariable %61 Private + %64 = OpTypePointer Private %54 + %69 = OpConstant %54 2 + %71 = OpConstant %6 1 + %72 = OpConstant %6 2 + %201 = OpConstant %15 2 + %73 = OpConstant %6 3 + %202 = OpConstant %15 3 + %203 = OpConstant %6 1 + %204 = OpConstant %6 9 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + %12 = OpFunction %2 None %8 + %9 = OpFunctionParameter %7 + %10 = OpFunctionParameter %102 + %11 = OpFunctionParameter %7 + %13 = OpLabel + %14 = OpVariable %7 Function + %27 = OpVariable %26 Function + %22 = OpLoad %6 %11 + %1002 = OpULessThanEqual %100 %22 %33 + %2002 = OpSelect %6 %1002 %22 %33 + %24 = OpAccessChain %23 %20 %21 %2002 + %25 = OpLoad %6 %24 + OpStore %14 %25 + %28 = OpLoad %15 %10 + %1003 = OpULessThanEqual %100 %28 %200 + %2003 = OpSelect %15 %1003 %28 %200 + %30 = OpAccessChain %29 %20 %2003 + %31 = OpLoad %17 %30 + OpStore %27 %31 + %32 = OpLoad %6 %9 + %1004 = OpULessThanEqual %100 %32 %33 + %2004 = OpSelect %6 %1004 %32 %33 + %34 = OpInBoundsAccessChain %7 %27 %2004 + OpStore %34 %33 + %39 = OpLoad %6 %9 + %40 = OpAccessChain %23 %38 %33 + %41 = OpLoad %6 %40 + %1006 = OpULessThanEqual %100 %39 %204 + %2006 = OpSelect %6 %1006 %39 %204 + %42 = OpInBoundsAccessChain %23 %38 %2006 + OpStore %42 %41 + %43 = OpLoad %15 %10 + %44 = OpLoad %6 %11 + %45 = OpLoad %6 %9 + %46 = OpLoad %15 %10 + %47 = OpIAdd %6 %45 %46 + %1007 = OpULessThanEqual %100 %47 %204 + %2007 = OpSelect %6 %1007 %47 %204 + %48 = OpAccessChain %23 %38 %2007 + %49 = OpLoad %6 %48 + %1008 = OpULessThanEqual %100 %43 %200 + %2008 = OpSelect %15 %1008 %43 %200 + %1009 = OpULessThanEqual %100 %44 %33 + %2009 = OpSelect %6 %1009 %44 %33 + %50 = OpInBoundsAccessChain %23 %20 %2008 %2009 + %51 = OpLoad %6 %50 + %52 = OpIAdd %6 %51 %49 + %1010 = OpULessThanEqual %100 %43 %200 + %2010 = OpSelect %15 %1010 %43 %200 + %1011 = OpULessThanEqual %100 %44 %33 + %2011 = OpSelect %6 %1011 %44 %33 + %53 = OpAccessChain %23 %20 %2010 %2011 + OpStore %53 %52 + %58 = OpLoad %15 %10 + %63 = OpLoad %6 %11 + %1013 = OpULessThanEqual %100 %63 %72 + %2013 = OpSelect %6 %1013 %63 %72 + %65 = OpAccessChain %64 %62 %21 %2013 + %1014 = OpULessThanEqual %100 %45 %71 + %2014 = OpSelect %6 %1014 %45 %71 + %1015 = OpULessThanEqual %100 %46 %201 + %2015 = OpSelect %15 %1015 %46 %201 + %101 = OpAccessChain %64 %62 %2014 %2015 + %66 = OpLoad %54 %65 + %1016 = OpULessThanEqual %100 %58 %202 + %2016 = OpSelect %15 %1016 %58 %202 + %67 = OpAccessChain %64 %57 %2016 + OpStore %67 %66 + %68 = OpLoad %6 %9 + %1017 = OpULessThanEqual %100 %68 %73 + %2017 = OpSelect %6 %1017 %68 %73 + %70 = OpInBoundsAccessChain %64 %57 %2017 + OpStore %70 %69 + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, added_as_livesafe_code, context2.get())); +} + +TEST(TransformationAddFunctionTest, LivesafeCanCallLivesafe) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + %6 = OpFunction %2 None %3 + %7 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + + std::vector instructions; + + instructions.push_back(MakeInstructionMessage( + SpvOpFunction, 2, 8, + {{SPV_OPERAND_TYPE_FUNCTION_CONTROL, {SpvFunctionControlMaskNone}}, + {SPV_OPERAND_TYPE_TYPE_ID, {3}}})); + instructions.push_back(MakeInstructionMessage(SpvOpLabel, 0, 9, {})); + instructions.push_back(MakeInstructionMessage(SpvOpFunctionCall, 2, 11, + {{SPV_OPERAND_TYPE_ID, {6}}})); + instructions.push_back(MakeInstructionMessage(SpvOpReturn, 0, 0, {})); + instructions.push_back(MakeInstructionMessage(SpvOpFunctionEnd, 0, 0, {})); + + FactManager fact_manager1; + FactManager fact_manager2; + + // Mark function 6 as livesafe. + fact_manager2.AddFactFunctionIsLivesafe(6); + + const auto context1 = BuildModule(env, consumer, shader, kFuzzAssembleOption); + const auto context2 = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context1.get())); + + TransformationAddFunction add_dead_function(instructions); + ASSERT_TRUE(add_dead_function.IsApplicable(context1.get(), fact_manager1)); + add_dead_function.Apply(context1.get(), &fact_manager1); + ASSERT_TRUE(IsValid(env, context1.get())); + // The function should not be deemed livesafe + ASSERT_FALSE(fact_manager1.FunctionIsLivesafe(8)); + // All variables/parameters in the function should be deemed arbitrary. + ASSERT_TRUE(AllVariablesAndParametersExceptLoopLimiterAreArbitrary( + context1.get(), fact_manager1, 8, 0)); + + std::string added_as_live_or_dead_code = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + %6 = OpFunction %2 None %3 + %7 = OpLabel + OpReturn + OpFunctionEnd + %8 = OpFunction %2 None %3 + %9 = OpLabel + %11 = OpFunctionCall %2 %6 + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, added_as_live_or_dead_code, context1.get())); + + TransformationAddFunction add_livesafe_function(instructions, 0, 0, {}, 0, + {}); + ASSERT_TRUE( + add_livesafe_function.IsApplicable(context2.get(), fact_manager2)); + add_livesafe_function.Apply(context2.get(), &fact_manager2); + ASSERT_TRUE(IsValid(env, context2.get())); + // The function should be deemed livesafe + ASSERT_TRUE(fact_manager2.FunctionIsLivesafe(8)); + // All variables/parameters in the function should be deemed arbitrary. + ASSERT_TRUE(AllVariablesAndParametersExceptLoopLimiterAreArbitrary( + context2.get(), fact_manager2, 8, 0)); + ASSERT_TRUE(IsEqual(env, added_as_live_or_dead_code, context2.get())); +} + +TEST(TransformationAddFunctionTest, LivesafeOnlyCallsLivesafe) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + %6 = OpFunction %2 None %3 + %7 = OpLabel + OpKill + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + + std::vector instructions; + + instructions.push_back(MakeInstructionMessage( + SpvOpFunction, 2, 8, + {{SPV_OPERAND_TYPE_FUNCTION_CONTROL, {SpvFunctionControlMaskNone}}, + {SPV_OPERAND_TYPE_TYPE_ID, {3}}})); + instructions.push_back(MakeInstructionMessage(SpvOpLabel, 0, 9, {})); + instructions.push_back(MakeInstructionMessage(SpvOpFunctionCall, 2, 11, + {{SPV_OPERAND_TYPE_ID, {6}}})); + instructions.push_back(MakeInstructionMessage(SpvOpReturn, 0, 0, {})); + instructions.push_back(MakeInstructionMessage(SpvOpFunctionEnd, 0, 0, {})); + + FactManager fact_manager1; + FactManager fact_manager2; + + const auto context1 = BuildModule(env, consumer, shader, kFuzzAssembleOption); + const auto context2 = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context1.get())); + + TransformationAddFunction add_dead_function(instructions); + ASSERT_TRUE(add_dead_function.IsApplicable(context1.get(), fact_manager1)); + add_dead_function.Apply(context1.get(), &fact_manager1); + ASSERT_TRUE(IsValid(env, context1.get())); + // The function should not be deemed livesafe + ASSERT_FALSE(fact_manager1.FunctionIsLivesafe(8)); + // All variables/parameters in the function should be deemed arbitrary. + ASSERT_TRUE(AllVariablesAndParametersExceptLoopLimiterAreArbitrary( + context1.get(), fact_manager1, 8, 0)); + + std::string added_as_dead_code = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + %6 = OpFunction %2 None %3 + %7 = OpLabel + OpKill + OpFunctionEnd + %8 = OpFunction %2 None %3 + %9 = OpLabel + %11 = OpFunctionCall %2 %6 + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, added_as_dead_code, context1.get())); + + TransformationAddFunction add_livesafe_function(instructions, 0, 0, {}, 0, + {}); + ASSERT_FALSE( + add_livesafe_function.IsApplicable(context2.get(), fact_manager2)); +} + +TEST(TransformationAddFunctionTest, + LoopLimitersBackEdgeBlockEndsWithConditional1) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %8 = OpTypeInt 32 1 + %9 = OpTypePointer Function %8 + %11 = OpConstant %8 0 + %18 = OpConstant %8 10 + %19 = OpTypeBool + %26 = OpConstantTrue %19 + %27 = OpConstantFalse %19 + %28 = OpTypeInt 32 0 + %29 = OpTypePointer Function %28 + %30 = OpConstant %28 0 + %31 = OpConstant %28 1 + %32 = OpConstant %28 5 + %22 = OpConstant %8 1 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + + std::string donor = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %8 = OpTypeInt 32 1 + %9 = OpTypePointer Function %8 + %11 = OpConstant %8 0 + %18 = OpConstant %8 10 + %19 = OpTypeBool + %26 = OpConstantTrue %19 + %27 = OpConstantFalse %19 + %28 = OpTypeInt 32 0 + %29 = OpTypePointer Function %28 + %30 = OpConstant %28 0 + %31 = OpConstant %28 1 + %32 = OpConstant %28 5 + %22 = OpConstant %8 1 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + %6 = OpFunction %2 None %3 + %7 = OpLabel + %10 = OpVariable %9 Function + OpStore %10 %11 + OpBranch %12 + %12 = OpLabel + OpLoopMerge %14 %15 None + OpBranch %15 + %15 = OpLabel + %17 = OpLoad %8 %10 + %20 = OpSLessThan %19 %17 %18 + %21 = OpLoad %8 %10 + %23 = OpIAdd %8 %21 %22 + OpStore %10 %23 + OpBranchConditional %20 %12 %14 + %14 = OpLabel + OpReturn + OpFunctionEnd + )"; + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + + FactManager fact_manager; + + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + // Make a sequence of instruction messages corresponding to function %8 in + // |donor|. + std::vector instructions = + GetInstructionsForFunction(env, consumer, donor, 6); + + protobufs::LoopLimiterInfo loop_limiter_info; + loop_limiter_info.set_loop_header_id(12); + loop_limiter_info.set_load_id(102); + loop_limiter_info.set_increment_id(103); + loop_limiter_info.set_compare_id(104); + loop_limiter_info.set_logical_op_id(105); + TransformationAddFunction add_livesafe_function(instructions, 100, 32, + {loop_limiter_info}, 0, {}); + ASSERT_TRUE(add_livesafe_function.IsApplicable(context.get(), fact_manager)); + add_livesafe_function.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + std::string expected = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %8 = OpTypeInt 32 1 + %9 = OpTypePointer Function %8 + %11 = OpConstant %8 0 + %18 = OpConstant %8 10 + %19 = OpTypeBool + %26 = OpConstantTrue %19 + %27 = OpConstantFalse %19 + %28 = OpTypeInt 32 0 + %29 = OpTypePointer Function %28 + %30 = OpConstant %28 0 + %31 = OpConstant %28 1 + %32 = OpConstant %28 5 + %22 = OpConstant %8 1 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + %6 = OpFunction %2 None %3 + %7 = OpLabel + %100 = OpVariable %29 Function %30 + %10 = OpVariable %9 Function + OpStore %10 %11 + OpBranch %12 + %12 = OpLabel + OpLoopMerge %14 %15 None + OpBranch %15 + %15 = OpLabel + %17 = OpLoad %8 %10 + %20 = OpSLessThan %19 %17 %18 + %21 = OpLoad %8 %10 + %23 = OpIAdd %8 %21 %22 + OpStore %10 %23 + %102 = OpLoad %28 %100 + %103 = OpIAdd %28 %102 %31 + OpStore %100 %103 + %104 = OpULessThan %19 %102 %32 + %105 = OpLogicalAnd %19 %20 %104 + OpBranchConditional %105 %12 %14 + %14 = OpLabel + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, expected, context.get())); +} + +TEST(TransformationAddFunctionTest, + LoopLimitersBackEdgeBlockEndsWithConditional2) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %8 = OpTypeInt 32 1 + %9 = OpTypePointer Function %8 + %11 = OpConstant %8 0 + %18 = OpConstant %8 10 + %19 = OpTypeBool + %26 = OpConstantTrue %19 + %27 = OpConstantFalse %19 + %28 = OpTypeInt 32 0 + %29 = OpTypePointer Function %28 + %30 = OpConstant %28 0 + %31 = OpConstant %28 1 + %32 = OpConstant %28 5 + %22 = OpConstant %8 1 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + + std::string donor = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %8 = OpTypeInt 32 1 + %9 = OpTypePointer Function %8 + %11 = OpConstant %8 0 + %18 = OpConstant %8 10 + %19 = OpTypeBool + %26 = OpConstantTrue %19 + %27 = OpConstantFalse %19 + %28 = OpTypeInt 32 0 + %29 = OpTypePointer Function %28 + %30 = OpConstant %28 0 + %31 = OpConstant %28 1 + %32 = OpConstant %28 5 + %22 = OpConstant %8 1 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + %6 = OpFunction %2 None %3 + %7 = OpLabel + %10 = OpVariable %9 Function + OpStore %10 %11 + OpBranch %12 + %12 = OpLabel + OpLoopMerge %14 %15 None + OpBranch %15 + %15 = OpLabel + %17 = OpLoad %8 %10 + %20 = OpSLessThan %19 %17 %18 + %21 = OpLoad %8 %10 + %23 = OpIAdd %8 %21 %22 + OpStore %10 %23 + %50 = OpLogicalNot %19 %20 + OpBranchConditional %50 %14 %12 + %14 = OpLabel + OpReturn + OpFunctionEnd + )"; + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + + FactManager fact_manager; + + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + // Make a sequence of instruction messages corresponding to function %8 in + // |donor|. + std::vector instructions = + GetInstructionsForFunction(env, consumer, donor, 6); + + protobufs::LoopLimiterInfo loop_limiter_info; + loop_limiter_info.set_loop_header_id(12); + loop_limiter_info.set_load_id(102); + loop_limiter_info.set_increment_id(103); + loop_limiter_info.set_compare_id(104); + loop_limiter_info.set_logical_op_id(105); + TransformationAddFunction add_livesafe_function(instructions, 100, 32, + {loop_limiter_info}, 0, {}); + ASSERT_TRUE(add_livesafe_function.IsApplicable(context.get(), fact_manager)); + add_livesafe_function.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + std::string expected = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %8 = OpTypeInt 32 1 + %9 = OpTypePointer Function %8 + %11 = OpConstant %8 0 + %18 = OpConstant %8 10 + %19 = OpTypeBool + %26 = OpConstantTrue %19 + %27 = OpConstantFalse %19 + %28 = OpTypeInt 32 0 + %29 = OpTypePointer Function %28 + %30 = OpConstant %28 0 + %31 = OpConstant %28 1 + %32 = OpConstant %28 5 + %22 = OpConstant %8 1 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + %6 = OpFunction %2 None %3 + %7 = OpLabel + %100 = OpVariable %29 Function %30 + %10 = OpVariable %9 Function + OpStore %10 %11 + OpBranch %12 + %12 = OpLabel + OpLoopMerge %14 %15 None + OpBranch %15 + %15 = OpLabel + %17 = OpLoad %8 %10 + %20 = OpSLessThan %19 %17 %18 + %21 = OpLoad %8 %10 + %23 = OpIAdd %8 %21 %22 + OpStore %10 %23 + %50 = OpLogicalNot %19 %20 + %102 = OpLoad %28 %100 + %103 = OpIAdd %28 %102 %31 + OpStore %100 %103 + %104 = OpUGreaterThanEqual %19 %102 %32 + %105 = OpLogicalOr %19 %50 %104 + OpBranchConditional %105 %14 %12 + %14 = OpLabel + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, expected, context.get())); +} + +TEST(TransformationAddFunctionTest, LoopLimitersHeaderIsBackEdgeBlock) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %8 = OpTypeInt 32 1 + %9 = OpTypePointer Function %8 + %11 = OpConstant %8 0 + %18 = OpConstant %8 10 + %19 = OpTypeBool + %26 = OpConstantTrue %19 + %27 = OpConstantFalse %19 + %28 = OpTypeInt 32 0 + %29 = OpTypePointer Function %28 + %30 = OpConstant %28 0 + %31 = OpConstant %28 1 + %32 = OpConstant %28 5 + %22 = OpConstant %8 1 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + + std::string donor = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %8 = OpTypeInt 32 1 + %9 = OpTypePointer Function %8 + %11 = OpConstant %8 0 + %18 = OpConstant %8 10 + %19 = OpTypeBool + %26 = OpConstantTrue %19 + %27 = OpConstantFalse %19 + %28 = OpTypeInt 32 0 + %29 = OpTypePointer Function %28 + %30 = OpConstant %28 0 + %31 = OpConstant %28 1 + %32 = OpConstant %28 5 + %22 = OpConstant %8 1 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + %6 = OpFunction %2 None %3 + %7 = OpLabel + %10 = OpVariable %9 Function + OpStore %10 %11 + OpBranch %12 + %12 = OpLabel + %17 = OpLoad %8 %10 + %20 = OpSLessThan %19 %17 %18 + %21 = OpLoad %8 %10 + %23 = OpIAdd %8 %21 %22 + OpStore %10 %23 + %50 = OpLogicalNot %19 %20 + OpLoopMerge %14 %12 None + OpBranchConditional %50 %14 %12 + %14 = OpLabel + OpReturn + OpFunctionEnd + )"; + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + + FactManager fact_manager; + + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + // Make a sequence of instruction messages corresponding to function %8 in + // |donor|. + std::vector instructions = + GetInstructionsForFunction(env, consumer, donor, 6); + + protobufs::LoopLimiterInfo loop_limiter_info; + loop_limiter_info.set_loop_header_id(12); + loop_limiter_info.set_load_id(102); + loop_limiter_info.set_increment_id(103); + loop_limiter_info.set_compare_id(104); + loop_limiter_info.set_logical_op_id(105); + TransformationAddFunction add_livesafe_function(instructions, 100, 32, + {loop_limiter_info}, 0, {}); + ASSERT_TRUE(add_livesafe_function.IsApplicable(context.get(), fact_manager)); + add_livesafe_function.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + std::string expected = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %8 = OpTypeInt 32 1 + %9 = OpTypePointer Function %8 + %11 = OpConstant %8 0 + %18 = OpConstant %8 10 + %19 = OpTypeBool + %26 = OpConstantTrue %19 + %27 = OpConstantFalse %19 + %28 = OpTypeInt 32 0 + %29 = OpTypePointer Function %28 + %30 = OpConstant %28 0 + %31 = OpConstant %28 1 + %32 = OpConstant %28 5 + %22 = OpConstant %8 1 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + %6 = OpFunction %2 None %3 + %7 = OpLabel + %100 = OpVariable %29 Function %30 + %10 = OpVariable %9 Function + OpStore %10 %11 + OpBranch %12 + %12 = OpLabel + %17 = OpLoad %8 %10 + %20 = OpSLessThan %19 %17 %18 + %21 = OpLoad %8 %10 + %23 = OpIAdd %8 %21 %22 + OpStore %10 %23 + %50 = OpLogicalNot %19 %20 + %102 = OpLoad %28 %100 + %103 = OpIAdd %28 %102 %31 + OpStore %100 %103 + %104 = OpUGreaterThanEqual %19 %102 %32 + %105 = OpLogicalOr %19 %50 %104 + OpLoopMerge %14 %12 None + OpBranchConditional %105 %14 %12 + %14 = OpLabel + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, expected, context.get())); +} + +TEST(TransformationAddFunctionTest, InfiniteLoop1) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %8 = OpTypeInt 32 1 + %9 = OpTypePointer Function %8 + %11 = OpConstant %8 0 + %18 = OpConstant %8 10 + %19 = OpTypeBool + %26 = OpConstantTrue %19 + %27 = OpConstantFalse %19 + %28 = OpTypeInt 32 0 + %29 = OpTypePointer Function %28 + %30 = OpConstant %28 0 + %31 = OpConstant %28 1 + %32 = OpConstant %28 5 + %22 = OpConstant %8 1 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + + std::string donor = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %8 = OpTypeInt 32 1 + %9 = OpTypePointer Function %8 + %11 = OpConstant %8 0 + %18 = OpConstant %8 10 + %19 = OpTypeBool + %26 = OpConstantTrue %19 + %27 = OpConstantFalse %19 + %28 = OpTypeInt 32 0 + %29 = OpTypePointer Function %28 + %30 = OpConstant %28 0 + %31 = OpConstant %28 1 + %32 = OpConstant %28 5 + %22 = OpConstant %8 1 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + %6 = OpFunction %2 None %3 + %7 = OpLabel + %10 = OpVariable %9 Function + OpStore %10 %11 + OpBranch %12 + %12 = OpLabel + OpLoopMerge %14 %12 None + OpBranch %12 + %14 = OpLabel + OpReturn + OpFunctionEnd + )"; + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + + FactManager fact_manager; + + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + // Make a sequence of instruction messages corresponding to function %8 in + // |donor|. + std::vector instructions = + GetInstructionsForFunction(env, consumer, donor, 6); + + protobufs::LoopLimiterInfo loop_limiter_info; + loop_limiter_info.set_loop_header_id(12); + loop_limiter_info.set_load_id(102); + loop_limiter_info.set_increment_id(103); + loop_limiter_info.set_compare_id(104); + loop_limiter_info.set_logical_op_id(105); + TransformationAddFunction add_livesafe_function(instructions, 100, 32, + {loop_limiter_info}, 0, {}); + ASSERT_TRUE(add_livesafe_function.IsApplicable(context.get(), fact_manager)); + add_livesafe_function.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + std::string expected = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %8 = OpTypeInt 32 1 + %9 = OpTypePointer Function %8 + %11 = OpConstant %8 0 + %18 = OpConstant %8 10 + %19 = OpTypeBool + %26 = OpConstantTrue %19 + %27 = OpConstantFalse %19 + %28 = OpTypeInt 32 0 + %29 = OpTypePointer Function %28 + %30 = OpConstant %28 0 + %31 = OpConstant %28 1 + %32 = OpConstant %28 5 + %22 = OpConstant %8 1 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + %6 = OpFunction %2 None %3 + %7 = OpLabel + %100 = OpVariable %29 Function %30 + %10 = OpVariable %9 Function + OpStore %10 %11 + OpBranch %12 + %12 = OpLabel + %102 = OpLoad %28 %100 + %103 = OpIAdd %28 %102 %31 + OpStore %100 %103 + %104 = OpUGreaterThanEqual %19 %102 %32 + OpLoopMerge %14 %12 None + OpBranchConditional %104 %14 %12 + %14 = OpLabel + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, expected, context.get())); +} + +TEST(TransformationAddFunctionTest, UnreachableContinueConstruct) { + // This captures the case where the loop's continue construct is statically + // unreachable. In this case the loop cannot iterate and so we do not add + // a loop limiter. (The reason we do not just add one anyway is that + // detecting which block would be the back-edge block is difficult in the + // absence of reliable dominance information.) + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %8 = OpTypeInt 32 1 + %9 = OpTypePointer Function %8 + %11 = OpConstant %8 0 + %18 = OpConstant %8 10 + %19 = OpTypeBool + %23 = OpConstant %8 1 + %26 = OpConstantTrue %19 + %27 = OpConstantFalse %19 + %28 = OpTypeInt 32 0 + %29 = OpTypePointer Function %28 + %30 = OpConstant %28 0 + %31 = OpConstant %28 1 + %32 = OpConstant %28 5 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + + std::string donor = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %8 = OpTypeInt 32 1 + %9 = OpTypePointer Function %8 + %11 = OpConstant %8 0 + %18 = OpConstant %8 10 + %19 = OpTypeBool + %23 = OpConstant %8 1 + %26 = OpConstantTrue %19 + %27 = OpConstantFalse %19 + %28 = OpTypeInt 32 0 + %29 = OpTypePointer Function %28 + %30 = OpConstant %28 0 + %31 = OpConstant %28 1 + %32 = OpConstant %28 5 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + %6 = OpFunction %2 None %3 + %7 = OpLabel + %10 = OpVariable %9 Function + OpStore %10 %11 + OpBranch %12 + %12 = OpLabel + OpLoopMerge %14 %15 None + OpBranch %16 + %16 = OpLabel + %17 = OpLoad %8 %10 + %20 = OpSLessThan %19 %17 %18 + OpBranchConditional %20 %13 %14 + %13 = OpLabel + OpBranch %14 + %15 = OpLabel + %22 = OpLoad %8 %10 + %24 = OpIAdd %8 %22 %23 + OpStore %10 %24 + OpBranch %12 + %14 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + + FactManager fact_manager; + + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + // Make a sequence of instruction messages corresponding to function %8 in + // |donor|. + std::vector instructions = + GetInstructionsForFunction(env, consumer, donor, 6); + + protobufs::LoopLimiterInfo loop_limiter_info; + loop_limiter_info.set_loop_header_id(12); + loop_limiter_info.set_load_id(102); + loop_limiter_info.set_increment_id(103); + loop_limiter_info.set_compare_id(104); + loop_limiter_info.set_logical_op_id(105); + TransformationAddFunction add_livesafe_function(instructions, 100, 32, + {loop_limiter_info}, 0, {}); + ASSERT_TRUE(add_livesafe_function.IsApplicable(context.get(), fact_manager)); + add_livesafe_function.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + std::string expected = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %8 = OpTypeInt 32 1 + %9 = OpTypePointer Function %8 + %11 = OpConstant %8 0 + %18 = OpConstant %8 10 + %19 = OpTypeBool + %23 = OpConstant %8 1 + %26 = OpConstantTrue %19 + %27 = OpConstantFalse %19 + %28 = OpTypeInt 32 0 + %29 = OpTypePointer Function %28 + %30 = OpConstant %28 0 + %31 = OpConstant %28 1 + %32 = OpConstant %28 5 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + %6 = OpFunction %2 None %3 + %7 = OpLabel + %100 = OpVariable %29 Function %30 + %10 = OpVariable %9 Function + OpStore %10 %11 + OpBranch %12 + %12 = OpLabel + OpLoopMerge %14 %15 None + OpBranch %16 + %16 = OpLabel + %17 = OpLoad %8 %10 + %20 = OpSLessThan %19 %17 %18 + OpBranchConditional %20 %13 %14 + %13 = OpLabel + OpBranch %14 + %15 = OpLabel + %22 = OpLoad %8 %10 + %24 = OpIAdd %8 %22 %23 + OpStore %10 %24 + OpBranch %12 + %14 = OpLabel + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, expected, context.get())); +} + +TEST(TransformationAddFunctionTest, LoopLimitersAndOpPhi1) { + // This captures the scenario where breaking a loop due to a loop limiter + // requires patching up OpPhi instructions occurring at the loop merge block. + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %50 = OpTypeInt 32 0 + %51 = OpConstant %50 0 + %52 = OpConstant %50 1 + %53 = OpTypePointer Function %50 + %7 = OpTypeFunction %6 + %10 = OpTypePointer Function %6 + %12 = OpConstant %6 0 + %19 = OpConstant %6 100 + %20 = OpTypeBool + %23 = OpConstant %6 20 + %28 = OpConstant %6 1 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + + std::string donor = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypeFunction %6 + %10 = OpTypePointer Function %6 + %12 = OpConstant %6 0 + %19 = OpConstant %6 100 + %20 = OpTypeBool + %23 = OpConstant %6 20 + %28 = OpConstant %6 1 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %36 = OpFunctionCall %6 %8 + OpReturn + OpFunctionEnd + %8 = OpFunction %6 None %7 + %9 = OpLabel + %11 = OpVariable %10 Function + OpStore %11 %12 + OpBranch %13 + %13 = OpLabel + %37 = OpPhi %6 %12 %9 %32 %16 + OpLoopMerge %15 %16 None + OpBranch %17 + %17 = OpLabel + %21 = OpSLessThan %20 %37 %19 + OpBranchConditional %21 %14 %15 + %14 = OpLabel + %24 = OpSGreaterThan %20 %37 %23 + OpSelectionMerge %26 None + OpBranchConditional %24 %25 %26 + %25 = OpLabel + %29 = OpIAdd %6 %37 %28 + OpStore %11 %29 + OpBranch %15 + %26 = OpLabel + OpBranch %16 + %16 = OpLabel + %32 = OpIAdd %6 %37 %28 + OpStore %11 %32 + OpBranch %13 + %15 = OpLabel + %38 = OpPhi %6 %37 %17 %29 %25 + OpReturnValue %38 + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + + FactManager fact_manager; + + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + // Make a sequence of instruction messages corresponding to function %8 in + // |donor|. + std::vector instructions = + GetInstructionsForFunction(env, consumer, donor, 8); + + protobufs::LoopLimiterInfo loop_limiter_info; + loop_limiter_info.set_loop_header_id(13); + loop_limiter_info.set_load_id(102); + loop_limiter_info.set_increment_id(103); + loop_limiter_info.set_compare_id(104); + loop_limiter_info.set_logical_op_id(105); + + TransformationAddFunction no_op_phi_data(instructions, 100, 28, + {loop_limiter_info}, 0, {}); + // The loop limiter info is not good enough; it does not include ids to patch + // up the OpPhi at the loop merge. + ASSERT_FALSE(no_op_phi_data.IsApplicable(context.get(), fact_manager)); + + // Add a phi id for the new edge from the loop back edge block to the loop + // merge. + loop_limiter_info.add_phi_id(28); + TransformationAddFunction with_op_phi_data(instructions, 100, 28, + {loop_limiter_info}, 0, {}); + ASSERT_TRUE(with_op_phi_data.IsApplicable(context.get(), fact_manager)); + with_op_phi_data.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + std::string expected = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %50 = OpTypeInt 32 0 + %51 = OpConstant %50 0 + %52 = OpConstant %50 1 + %53 = OpTypePointer Function %50 + %7 = OpTypeFunction %6 + %10 = OpTypePointer Function %6 + %12 = OpConstant %6 0 + %19 = OpConstant %6 100 + %20 = OpTypeBool + %23 = OpConstant %6 20 + %28 = OpConstant %6 1 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + %8 = OpFunction %6 None %7 + %9 = OpLabel + %100 = OpVariable %53 Function %51 + %11 = OpVariable %10 Function + OpStore %11 %12 + OpBranch %13 + %13 = OpLabel + %37 = OpPhi %6 %12 %9 %32 %16 + OpLoopMerge %15 %16 None + OpBranch %17 + %17 = OpLabel + %21 = OpSLessThan %20 %37 %19 + OpBranchConditional %21 %14 %15 + %14 = OpLabel + %24 = OpSGreaterThan %20 %37 %23 + OpSelectionMerge %26 None + OpBranchConditional %24 %25 %26 + %25 = OpLabel + %29 = OpIAdd %6 %37 %28 + OpStore %11 %29 + OpBranch %15 + %26 = OpLabel + OpBranch %16 + %16 = OpLabel + %32 = OpIAdd %6 %37 %28 + OpStore %11 %32 + %102 = OpLoad %50 %100 + %103 = OpIAdd %50 %102 %52 + OpStore %100 %103 + %104 = OpUGreaterThanEqual %20 %102 %28 + OpBranchConditional %104 %15 %13 + %15 = OpLabel + %38 = OpPhi %6 %37 %17 %29 %25 %28 %16 + OpReturnValue %38 + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, expected, context.get())); +} + +TEST(TransformationAddFunctionTest, LoopLimitersAndOpPhi2) { + // This captures the scenario where the loop merge block already has an OpPhi + // with the loop back edge block as a predecessor. + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %50 = OpTypeInt 32 0 + %51 = OpConstant %50 0 + %52 = OpConstant %50 1 + %53 = OpTypePointer Function %50 + %7 = OpTypeFunction %6 + %10 = OpTypePointer Function %6 + %12 = OpConstant %6 0 + %19 = OpConstant %6 100 + %20 = OpTypeBool + %60 = OpConstantTrue %20 + %23 = OpConstant %6 20 + %28 = OpConstant %6 1 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + + std::string donor = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %50 = OpTypeInt 32 0 + %51 = OpConstant %50 0 + %52 = OpConstant %50 1 + %53 = OpTypePointer Function %50 + %7 = OpTypeFunction %6 + %10 = OpTypePointer Function %6 + %12 = OpConstant %6 0 + %19 = OpConstant %6 100 + %20 = OpTypeBool + %60 = OpConstantTrue %20 + %23 = OpConstant %6 20 + %28 = OpConstant %6 1 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + %8 = OpFunction %6 None %7 + %9 = OpLabel + %11 = OpVariable %10 Function + OpStore %11 %12 + OpBranch %13 + %13 = OpLabel + %37 = OpPhi %6 %12 %9 %32 %16 + OpLoopMerge %15 %16 None + OpBranch %17 + %17 = OpLabel + %21 = OpSLessThan %20 %37 %19 + OpBranchConditional %21 %14 %15 + %14 = OpLabel + %24 = OpSGreaterThan %20 %37 %23 + OpSelectionMerge %26 None + OpBranchConditional %24 %25 %26 + %25 = OpLabel + %29 = OpIAdd %6 %37 %28 + OpStore %11 %29 + OpBranch %15 + %26 = OpLabel + OpBranch %16 + %16 = OpLabel + %32 = OpIAdd %6 %37 %28 + OpStore %11 %32 + OpBranchConditional %60 %15 %13 + %15 = OpLabel + %38 = OpPhi %6 %37 %17 %29 %25 %23 %16 + OpReturnValue %38 + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + + FactManager fact_manager; + + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + // Make a sequence of instruction messages corresponding to function %8 in + // |donor|. + std::vector instructions = + GetInstructionsForFunction(env, consumer, donor, 8); + + protobufs::LoopLimiterInfo loop_limiter_info; + loop_limiter_info.set_loop_header_id(13); + loop_limiter_info.set_load_id(102); + loop_limiter_info.set_increment_id(103); + loop_limiter_info.set_compare_id(104); + loop_limiter_info.set_logical_op_id(105); + + TransformationAddFunction transformation(instructions, 100, 28, + {loop_limiter_info}, 0, {}); + ASSERT_TRUE(transformation.IsApplicable(context.get(), fact_manager)); + transformation.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + std::string expected = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %50 = OpTypeInt 32 0 + %51 = OpConstant %50 0 + %52 = OpConstant %50 1 + %53 = OpTypePointer Function %50 + %7 = OpTypeFunction %6 + %10 = OpTypePointer Function %6 + %12 = OpConstant %6 0 + %19 = OpConstant %6 100 + %20 = OpTypeBool + %60 = OpConstantTrue %20 + %23 = OpConstant %6 20 + %28 = OpConstant %6 1 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + %8 = OpFunction %6 None %7 + %9 = OpLabel + %100 = OpVariable %53 Function %51 + %11 = OpVariable %10 Function + OpStore %11 %12 + OpBranch %13 + %13 = OpLabel + %37 = OpPhi %6 %12 %9 %32 %16 + OpLoopMerge %15 %16 None + OpBranch %17 + %17 = OpLabel + %21 = OpSLessThan %20 %37 %19 + OpBranchConditional %21 %14 %15 + %14 = OpLabel + %24 = OpSGreaterThan %20 %37 %23 + OpSelectionMerge %26 None + OpBranchConditional %24 %25 %26 + %25 = OpLabel + %29 = OpIAdd %6 %37 %28 + OpStore %11 %29 + OpBranch %15 + %26 = OpLabel + OpBranch %16 + %16 = OpLabel + %32 = OpIAdd %6 %37 %28 + OpStore %11 %32 + %102 = OpLoad %50 %100 + %103 = OpIAdd %50 %102 %52 + OpStore %100 %103 + %104 = OpUGreaterThanEqual %20 %102 %28 + %105 = OpLogicalOr %20 %60 %104 + OpBranchConditional %105 %15 %13 + %15 = OpLabel + %38 = OpPhi %6 %37 %17 %29 %25 %23 %16 + OpReturnValue %38 + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, expected, context.get())); +} + +} // namespace +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/test/fuzz/transformation_add_global_undef_test.cpp b/third_party/spirv-tools/test/fuzz/transformation_add_global_undef_test.cpp new file mode 100644 index 0000000000..c14f7e9169 --- /dev/null +++ b/third_party/spirv-tools/test/fuzz/transformation_add_global_undef_test.cpp @@ -0,0 +1,118 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_add_global_undef.h" +#include "test/fuzz/fuzz_test_util.h" + +namespace spvtools { +namespace fuzz { +namespace { + +TEST(TransformationAddGlobalUndefTest, BasicTest) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypeInt 32 1 + %8 = OpTypeVector %6 2 + %9 = OpTypeVector %6 3 + %10 = OpTypeVector %6 4 + %11 = OpTypeVector %7 2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + // Id already in use + ASSERT_FALSE(TransformationAddGlobalUndef(4, 11).IsApplicable(context.get(), + fact_manager)); + // %1 is not a type + ASSERT_FALSE(TransformationAddGlobalUndef(100, 1).IsApplicable(context.get(), + fact_manager)); + + // %3 is a function type + ASSERT_FALSE(TransformationAddGlobalUndef(100, 3).IsApplicable(context.get(), + fact_manager)); + + TransformationAddGlobalUndef transformations[] = { + // %100 = OpUndef %6 + TransformationAddGlobalUndef(100, 6), + + // %101 = OpUndef %7 + TransformationAddGlobalUndef(101, 7), + + // %102 = OpUndef %8 + TransformationAddGlobalUndef(102, 8), + + // %103 = OpUndef %9 + TransformationAddGlobalUndef(103, 9), + + // %104 = OpUndef %10 + TransformationAddGlobalUndef(104, 10), + + // %105 = OpUndef %11 + TransformationAddGlobalUndef(105, 11)}; + + for (auto& transformation : transformations) { + ASSERT_TRUE(transformation.IsApplicable(context.get(), fact_manager)); + transformation.Apply(context.get(), &fact_manager); + } + ASSERT_TRUE(IsValid(env, context.get())); + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypeInt 32 1 + %8 = OpTypeVector %6 2 + %9 = OpTypeVector %6 3 + %10 = OpTypeVector %6 4 + %11 = OpTypeVector %7 2 + %100 = OpUndef %6 + %101 = OpUndef %7 + %102 = OpUndef %8 + %103 = OpUndef %9 + %104 = OpUndef %10 + %105 = OpUndef %11 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +} // namespace +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/test/fuzz/transformation_add_global_variable_test.cpp b/third_party/spirv-tools/test/fuzz/transformation_add_global_variable_test.cpp new file mode 100644 index 0000000000..7fb4fa0860 --- /dev/null +++ b/third_party/spirv-tools/test/fuzz/transformation_add_global_variable_test.cpp @@ -0,0 +1,285 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_add_global_variable.h" +#include "test/fuzz/fuzz_test_util.h" + +namespace spvtools { +namespace fuzz { +namespace { + +TEST(TransformationAddGlobalVariableTest, BasicTest) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypeInt 32 1 + %8 = OpTypeVector %6 2 + %9 = OpTypePointer Function %6 + %10 = OpTypePointer Private %6 + %20 = OpTypePointer Uniform %6 + %11 = OpTypePointer Function %7 + %12 = OpTypePointer Private %7 + %13 = OpTypePointer Private %8 + %14 = OpVariable %10 Private + %15 = OpVariable %20 Uniform + %16 = OpConstant %7 1 + %17 = OpTypePointer Private %10 + %18 = OpTypeBool + %19 = OpTypePointer Private %18 + %21 = OpConstantTrue %18 + %22 = OpConstantFalse %18 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + // Id already in use + ASSERT_FALSE(TransformationAddGlobalVariable(4, 10, 0, true) + .IsApplicable(context.get(), fact_manager)); + // %1 is not a type + ASSERT_FALSE(TransformationAddGlobalVariable(100, 1, 0, false) + .IsApplicable(context.get(), fact_manager)); + + // %7 is not a pointer type + ASSERT_FALSE(TransformationAddGlobalVariable(100, 7, 0, true) + .IsApplicable(context.get(), fact_manager)); + + // %9 does not have Private storage class + ASSERT_FALSE(TransformationAddGlobalVariable(100, 9, 0, false) + .IsApplicable(context.get(), fact_manager)); + + // %15 does not have Private storage class + ASSERT_FALSE(TransformationAddGlobalVariable(100, 15, 0, true) + .IsApplicable(context.get(), fact_manager)); + + // %10 is a pointer to float, while %16 is an int constant + ASSERT_FALSE(TransformationAddGlobalVariable(100, 10, 16, false) + .IsApplicable(context.get(), fact_manager)); + + // %10 is a Private pointer to float, while %15 is a variable with type + // Uniform float pointer + ASSERT_FALSE(TransformationAddGlobalVariable(100, 10, 15, true) + .IsApplicable(context.get(), fact_manager)); + + // %12 is a Private pointer to int, while %10 is a variable with type + // Private float pointer + ASSERT_FALSE(TransformationAddGlobalVariable(100, 12, 10, false) + .IsApplicable(context.get(), fact_manager)); + + // %10 is pointer-to-float, and %14 has type pointer-to-float; that's not OK + // since the initializer's type should be the *pointee* type. + ASSERT_FALSE(TransformationAddGlobalVariable(104, 10, 14, true) + .IsApplicable(context.get(), fact_manager)); + + // This would work in principle, but logical addressing does not allow + // a pointer to a pointer. + ASSERT_FALSE(TransformationAddGlobalVariable(104, 17, 14, false) + .IsApplicable(context.get(), fact_manager)); + + TransformationAddGlobalVariable transformations[] = { + // %100 = OpVariable %12 Private + TransformationAddGlobalVariable(100, 12, 0, true), + + // %101 = OpVariable %10 Private + TransformationAddGlobalVariable(101, 10, 0, false), + + // %102 = OpVariable %13 Private + TransformationAddGlobalVariable(102, 13, 0, true), + + // %103 = OpVariable %12 Private %16 + TransformationAddGlobalVariable(103, 12, 16, false), + + // %104 = OpVariable %19 Private %21 + TransformationAddGlobalVariable(104, 19, 21, true), + + // %105 = OpVariable %19 Private %22 + TransformationAddGlobalVariable(105, 19, 22, false)}; + + for (auto& transformation : transformations) { + ASSERT_TRUE(transformation.IsApplicable(context.get(), fact_manager)); + transformation.Apply(context.get(), &fact_manager); + } + ASSERT_TRUE(fact_manager.VariableValueIsArbitrary(100)); + ASSERT_TRUE(fact_manager.VariableValueIsArbitrary(102)); + ASSERT_TRUE(fact_manager.VariableValueIsArbitrary(104)); + ASSERT_FALSE(fact_manager.VariableValueIsArbitrary(101)); + ASSERT_FALSE(fact_manager.VariableValueIsArbitrary(103)); + ASSERT_FALSE(fact_manager.VariableValueIsArbitrary(105)); + + ASSERT_TRUE(IsValid(env, context.get())); + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypeInt 32 1 + %8 = OpTypeVector %6 2 + %9 = OpTypePointer Function %6 + %10 = OpTypePointer Private %6 + %20 = OpTypePointer Uniform %6 + %11 = OpTypePointer Function %7 + %12 = OpTypePointer Private %7 + %13 = OpTypePointer Private %8 + %14 = OpVariable %10 Private + %15 = OpVariable %20 Uniform + %16 = OpConstant %7 1 + %17 = OpTypePointer Private %10 + %18 = OpTypeBool + %19 = OpTypePointer Private %18 + %21 = OpConstantTrue %18 + %22 = OpConstantFalse %18 + %100 = OpVariable %12 Private + %101 = OpVariable %10 Private + %102 = OpVariable %13 Private + %103 = OpVariable %12 Private %16 + %104 = OpVariable %19 Private %21 + %105 = OpVariable %19 Private %22 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +TEST(TransformationAddGlobalVariableTest, TestEntryPointInterfaceEnlargement) { + // This checks that when global variables are added to a SPIR-V 1.4+ module, + // they are also added to entry points of that module. + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "m1" + OpEntryPoint Vertex %5 "m2" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypeInt 32 1 + %8 = OpTypeVector %6 2 + %9 = OpTypePointer Function %6 + %10 = OpTypePointer Private %6 + %20 = OpTypePointer Uniform %6 + %11 = OpTypePointer Function %7 + %12 = OpTypePointer Private %7 + %13 = OpTypePointer Private %8 + %14 = OpVariable %10 Private + %15 = OpVariable %20 Uniform + %16 = OpConstant %7 1 + %17 = OpTypePointer Private %10 + %18 = OpTypeBool + %19 = OpTypePointer Private %18 + %21 = OpConstantTrue %18 + %4 = OpFunction %2 None %3 + %30 = OpLabel + OpReturn + OpFunctionEnd + %5 = OpFunction %2 None %3 + %31 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + TransformationAddGlobalVariable transformations[] = { + // %100 = OpVariable %12 Private + TransformationAddGlobalVariable(100, 12, 0, true), + + // %101 = OpVariable %12 Private %16 + TransformationAddGlobalVariable(101, 12, 16, false), + + // %102 = OpVariable %19 Private %21 + TransformationAddGlobalVariable(102, 19, 21, true)}; + + for (auto& transformation : transformations) { + ASSERT_TRUE(transformation.IsApplicable(context.get(), fact_manager)); + transformation.Apply(context.get(), &fact_manager); + } + ASSERT_TRUE(fact_manager.VariableValueIsArbitrary(100)); + ASSERT_TRUE(fact_manager.VariableValueIsArbitrary(102)); + ASSERT_FALSE(fact_manager.VariableValueIsArbitrary(101)); + ASSERT_TRUE(IsValid(env, context.get())); + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "m1" %100 %101 %102 + OpEntryPoint Vertex %5 "m2" %100 %101 %102 + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypeInt 32 1 + %8 = OpTypeVector %6 2 + %9 = OpTypePointer Function %6 + %10 = OpTypePointer Private %6 + %20 = OpTypePointer Uniform %6 + %11 = OpTypePointer Function %7 + %12 = OpTypePointer Private %7 + %13 = OpTypePointer Private %8 + %14 = OpVariable %10 Private + %15 = OpVariable %20 Uniform + %16 = OpConstant %7 1 + %17 = OpTypePointer Private %10 + %18 = OpTypeBool + %19 = OpTypePointer Private %18 + %21 = OpConstantTrue %18 + %100 = OpVariable %12 Private + %101 = OpVariable %12 Private %16 + %102 = OpVariable %19 Private %21 + %4 = OpFunction %2 None %3 + %30 = OpLabel + OpReturn + OpFunctionEnd + %5 = OpFunction %2 None %3 + %31 = OpLabel + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +} // namespace +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/test/fuzz/transformation_add_no_contraction_decoration_test.cpp b/third_party/spirv-tools/test/fuzz/transformation_add_no_contraction_decoration_test.cpp new file mode 100644 index 0000000000..b1a87ead37 --- /dev/null +++ b/third_party/spirv-tools/test/fuzz/transformation_add_no_contraction_decoration_test.cpp @@ -0,0 +1,194 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_add_no_contraction_decoration.h" +#include "test/fuzz/fuzz_test_util.h" + +namespace spvtools { +namespace fuzz { +namespace { + +TEST(TransformationAddNoContractionDecorationTest, BasicScenarios) { + // This is a simple transformation and this test handles the main cases. + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %8 "x" + OpName %10 "y" + OpName %14 "i" + OpDecorate %32 NoContraction + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 0 + %11 = OpConstant %6 2 + %12 = OpTypeInt 32 1 + %13 = OpTypePointer Function %12 + %15 = OpConstant %12 0 + %22 = OpConstant %12 10 + %23 = OpTypeBool + %31 = OpConstant %6 3.5999999 + %38 = OpConstant %12 1 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %10 = OpVariable %7 Function + %14 = OpVariable %13 Function + OpStore %8 %9 + OpStore %10 %11 + OpStore %14 %15 + OpBranch %16 + %16 = OpLabel + OpLoopMerge %18 %19 None + OpBranch %20 + %20 = OpLabel + %21 = OpLoad %12 %14 + %24 = OpSLessThan %23 %21 %22 + OpBranchConditional %24 %17 %18 + %17 = OpLabel + %25 = OpLoad %6 %10 + %26 = OpLoad %6 %10 + %27 = OpFMul %6 %25 %26 + %28 = OpLoad %6 %8 + %29 = OpFAdd %6 %28 %27 + OpStore %8 %29 + %30 = OpLoad %6 %10 + %32 = OpFDiv %6 %30 %31 + OpStore %10 %32 + %33 = OpLoad %12 %14 + %34 = OpConvertSToF %6 %33 + %35 = OpLoad %6 %8 + %36 = OpFAdd %6 %35 %34 + OpStore %8 %36 + OpBranch %19 + %19 = OpLabel + %37 = OpLoad %12 %14 + %39 = OpIAdd %12 %37 %38 + OpStore %14 %39 + OpBranch %16 + %18 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + FactManager fact_manager; + + // Invalid: 200 is not an id + ASSERT_FALSE(TransformationAddNoContractionDecoration(200).IsApplicable( + context.get(), fact_manager)); + // Invalid: 17 is a block id + ASSERT_FALSE(TransformationAddNoContractionDecoration(17).IsApplicable( + context.get(), fact_manager)); + // Invalid: 24 is not arithmetic + ASSERT_FALSE(TransformationAddNoContractionDecoration(24).IsApplicable( + context.get(), fact_manager)); + + // It is valid to add NoContraction to each of these ids (and it's fine to + // have duplicates of the decoration, in the case of 32). + for (uint32_t result_id : {32u, 32u, 27u, 29u, 39u}) { + TransformationAddNoContractionDecoration transformation(result_id); + ASSERT_TRUE(transformation.IsApplicable(context.get(), fact_manager)); + transformation.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + } + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %8 "x" + OpName %10 "y" + OpName %14 "i" + OpDecorate %32 NoContraction + OpDecorate %32 NoContraction + OpDecorate %32 NoContraction + OpDecorate %27 NoContraction + OpDecorate %29 NoContraction + OpDecorate %39 NoContraction + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 0 + %11 = OpConstant %6 2 + %12 = OpTypeInt 32 1 + %13 = OpTypePointer Function %12 + %15 = OpConstant %12 0 + %22 = OpConstant %12 10 + %23 = OpTypeBool + %31 = OpConstant %6 3.5999999 + %38 = OpConstant %12 1 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %10 = OpVariable %7 Function + %14 = OpVariable %13 Function + OpStore %8 %9 + OpStore %10 %11 + OpStore %14 %15 + OpBranch %16 + %16 = OpLabel + OpLoopMerge %18 %19 None + OpBranch %20 + %20 = OpLabel + %21 = OpLoad %12 %14 + %24 = OpSLessThan %23 %21 %22 + OpBranchConditional %24 %17 %18 + %17 = OpLabel + %25 = OpLoad %6 %10 + %26 = OpLoad %6 %10 + %27 = OpFMul %6 %25 %26 + %28 = OpLoad %6 %8 + %29 = OpFAdd %6 %28 %27 + OpStore %8 %29 + %30 = OpLoad %6 %10 + %32 = OpFDiv %6 %30 %31 + OpStore %10 %32 + %33 = OpLoad %12 %14 + %34 = OpConvertSToF %6 %33 + %35 = OpLoad %6 %8 + %36 = OpFAdd %6 %35 %34 + OpStore %8 %36 + OpBranch %19 + %19 = OpLabel + %37 = OpLoad %12 %14 + %39 = OpIAdd %12 %37 %38 + OpStore %14 %39 + OpBranch %16 + %18 = OpLabel + OpReturn + OpFunctionEnd + )"; + + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +} // namespace +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/test/fuzz/transformation_add_type_array_test.cpp b/third_party/spirv-tools/test/fuzz/transformation_add_type_array_test.cpp new file mode 100644 index 0000000000..2bcbe73e03 --- /dev/null +++ b/third_party/spirv-tools/test/fuzz/transformation_add_type_array_test.cpp @@ -0,0 +1,136 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_add_type_array.h" +#include "test/fuzz/fuzz_test_util.h" + +namespace spvtools { +namespace fuzz { +namespace { + +TEST(TransformationAddTypeArrayTest, BasicTest) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypeInt 32 1 + %8 = OpTypeVector %6 2 + %9 = OpTypeVector %6 3 + %10 = OpTypeVector %6 4 + %11 = OpTypeVector %7 2 + %12 = OpConstant %7 3 + %13 = OpConstant %7 0 + %14 = OpConstant %7 -1 + %15 = OpTypeInt 32 0 + %16 = OpConstant %15 5 + %17 = OpConstant %15 0 + %18 = OpConstant %6 1 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + // Id already in use + ASSERT_FALSE(TransformationAddTypeArray(4, 10, 16).IsApplicable( + context.get(), fact_manager)); + // %1 is not a type + ASSERT_FALSE(TransformationAddTypeArray(100, 1, 16) + .IsApplicable(context.get(), fact_manager)); + + // %3 is a function type + ASSERT_FALSE(TransformationAddTypeArray(100, 3, 16) + .IsApplicable(context.get(), fact_manager)); + + // %2 is not a constant + ASSERT_FALSE(TransformationAddTypeArray(100, 11, 2) + .IsApplicable(context.get(), fact_manager)); + + // %18 is not an integer + ASSERT_FALSE(TransformationAddTypeArray(100, 11, 18) + .IsApplicable(context.get(), fact_manager)); + + // %13 is signed 0 + ASSERT_FALSE(TransformationAddTypeArray(100, 11, 13) + .IsApplicable(context.get(), fact_manager)); + + // %14 is negative + ASSERT_FALSE(TransformationAddTypeArray(100, 11, 14) + .IsApplicable(context.get(), fact_manager)); + + // %17 is unsigned 0 + ASSERT_FALSE(TransformationAddTypeArray(100, 11, 17) + .IsApplicable(context.get(), fact_manager)); + + TransformationAddTypeArray transformations[] = { + // %100 = OpTypeArray %10 %16 + TransformationAddTypeArray(100, 10, 16), + + // %101 = OpTypeArray %7 %12 + TransformationAddTypeArray(101, 7, 12)}; + + for (auto& transformation : transformations) { + ASSERT_TRUE(transformation.IsApplicable(context.get(), fact_manager)); + transformation.Apply(context.get(), &fact_manager); + } + ASSERT_TRUE(IsValid(env, context.get())); + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypeInt 32 1 + %8 = OpTypeVector %6 2 + %9 = OpTypeVector %6 3 + %10 = OpTypeVector %6 4 + %11 = OpTypeVector %7 2 + %12 = OpConstant %7 3 + %13 = OpConstant %7 0 + %14 = OpConstant %7 -1 + %15 = OpTypeInt 32 0 + %16 = OpConstant %15 5 + %17 = OpConstant %15 0 + %18 = OpConstant %6 1 + %100 = OpTypeArray %10 %16 + %101 = OpTypeArray %7 %12 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +} // namespace +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/test/fuzz/transformation_add_type_boolean_test.cpp b/third_party/spirv-tools/test/fuzz/transformation_add_type_boolean_test.cpp new file mode 100644 index 0000000000..9975953bac --- /dev/null +++ b/third_party/spirv-tools/test/fuzz/transformation_add_type_boolean_test.cpp @@ -0,0 +1,80 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_add_type_boolean.h" +#include "test/fuzz/fuzz_test_util.h" + +namespace spvtools { +namespace fuzz { +namespace { + +TEST(TransformationAddTypeBooleanTest, BasicTest) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + // Not applicable because id 1 is already in use. + ASSERT_FALSE(TransformationAddTypeBoolean(1).IsApplicable(context.get(), + fact_manager)); + + auto add_type_bool = TransformationAddTypeBoolean(100); + ASSERT_TRUE(add_type_bool.IsApplicable(context.get(), fact_manager)); + add_type_bool.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + // Not applicable as we already have this type now. + ASSERT_FALSE(TransformationAddTypeBoolean(101).IsApplicable(context.get(), + fact_manager)); + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %100 = OpTypeBool + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +} // namespace +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/test/fuzz/transformation_add_type_float_test.cpp b/third_party/spirv-tools/test/fuzz/transformation_add_type_float_test.cpp new file mode 100644 index 0000000000..67408da5a0 --- /dev/null +++ b/third_party/spirv-tools/test/fuzz/transformation_add_type_float_test.cpp @@ -0,0 +1,80 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_add_type_float.h" +#include "test/fuzz/fuzz_test_util.h" + +namespace spvtools { +namespace fuzz { +namespace { + +TEST(TransformationAddTypeFloatTest, BasicTest) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + // Not applicable because id 1 is already in use. + ASSERT_FALSE(TransformationAddTypeFloat(1, 32).IsApplicable(context.get(), + fact_manager)); + + auto add_type_float_32 = TransformationAddTypeFloat(100, 32); + ASSERT_TRUE(add_type_float_32.IsApplicable(context.get(), fact_manager)); + add_type_float_32.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + // Not applicable as we already have this type now. + ASSERT_FALSE(TransformationAddTypeFloat(101, 32).IsApplicable(context.get(), + fact_manager)); + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %100 = OpTypeFloat 32 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +} // namespace +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/test/fuzz/transformation_add_type_function_test.cpp b/third_party/spirv-tools/test/fuzz/transformation_add_type_function_test.cpp new file mode 100644 index 0000000000..46bd436bbf --- /dev/null +++ b/third_party/spirv-tools/test/fuzz/transformation_add_type_function_test.cpp @@ -0,0 +1,134 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_add_type_function.h" +#include "test/fuzz/fuzz_test_util.h" + +namespace spvtools { +namespace fuzz { +namespace { + +TEST(TransformationAddTypeFunctionTest, BasicTest) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %8 = OpTypeFunction %2 %7 + %12 = OpTypeFloat 32 + %13 = OpTypeStruct %6 %12 + %14 = OpTypePointer Function %13 + %200 = OpTypePointer Function %13 + %15 = OpTypeVector %12 3 + %16 = OpTypePointer Function %15 + %17 = OpTypeVector %12 2 + %18 = OpTypeFunction %17 %14 %16 + %23 = OpConstant %12 1 + %24 = OpConstantComposite %17 %23 %23 + %27 = OpConstant %6 3 + %30 = OpConstant %6 1 + %31 = OpConstant %12 2 + %32 = OpConstantComposite %13 %30 %31 + %33 = OpConstantComposite %15 %23 %23 %23 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + // Id already in use + ASSERT_FALSE(TransformationAddTypeFunction(4, 12, {12, 16, 14}) + .IsApplicable(context.get(), fact_manager)); + // %1 is not a type + ASSERT_FALSE(TransformationAddTypeFunction(100, 1, {12, 16, 14}) + .IsApplicable(context.get(), fact_manager)); + + // %18 is a function type + ASSERT_FALSE(TransformationAddTypeFunction(100, 12, {18}) + .IsApplicable(context.get(), fact_manager)); + + // A function of this signature already exists + ASSERT_FALSE(TransformationAddTypeFunction(100, 17, {14, 16}) + .IsApplicable(context.get(), fact_manager)); + + TransformationAddTypeFunction transformations[] = { + // %100 = OpTypeFunction %12 %12 %16 %14 + TransformationAddTypeFunction(100, 12, {12, 16, 14}), + + // %101 = OpTypeFunction %12 + TransformationAddTypeFunction(101, 12, {}), + + // %102 = OpTypeFunction %17 %200 %16 + TransformationAddTypeFunction(102, 17, {200, 16})}; + + for (auto& transformation : transformations) { + ASSERT_TRUE(transformation.IsApplicable(context.get(), fact_manager)); + transformation.Apply(context.get(), &fact_manager); + } + ASSERT_TRUE(IsValid(env, context.get())); + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %8 = OpTypeFunction %2 %7 + %12 = OpTypeFloat 32 + %13 = OpTypeStruct %6 %12 + %14 = OpTypePointer Function %13 + %200 = OpTypePointer Function %13 + %15 = OpTypeVector %12 3 + %16 = OpTypePointer Function %15 + %17 = OpTypeVector %12 2 + %18 = OpTypeFunction %17 %14 %16 + %23 = OpConstant %12 1 + %24 = OpConstantComposite %17 %23 %23 + %27 = OpConstant %6 3 + %30 = OpConstant %6 1 + %31 = OpConstant %12 2 + %32 = OpConstantComposite %13 %30 %31 + %33 = OpConstantComposite %15 %23 %23 %23 + %100 = OpTypeFunction %12 %12 %16 %14 + %101 = OpTypeFunction %12 + %102 = OpTypeFunction %17 %200 %16 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +} // namespace +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/test/fuzz/transformation_add_type_int_test.cpp b/third_party/spirv-tools/test/fuzz/transformation_add_type_int_test.cpp new file mode 100644 index 0000000000..c6f884c203 --- /dev/null +++ b/third_party/spirv-tools/test/fuzz/transformation_add_type_int_test.cpp @@ -0,0 +1,93 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_add_type_int.h" +#include "test/fuzz/fuzz_test_util.h" + +namespace spvtools { +namespace fuzz { +namespace { + +TEST(TransformationAddTypeIntTest, BasicTest) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + // Not applicable because id 1 is already in use. + ASSERT_FALSE(TransformationAddTypeInt(1, 32, false) + .IsApplicable(context.get(), fact_manager)); + + auto add_type_signed_int_32 = TransformationAddTypeInt(100, 32, true); + auto add_type_unsigned_int_32 = TransformationAddTypeInt(101, 32, false); + auto add_type_signed_int_32_again = TransformationAddTypeInt(102, 32, true); + auto add_type_unsigned_int_32_again = + TransformationAddTypeInt(103, 32, false); + + ASSERT_TRUE(add_type_signed_int_32.IsApplicable(context.get(), fact_manager)); + add_type_signed_int_32.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE( + add_type_unsigned_int_32.IsApplicable(context.get(), fact_manager)); + add_type_unsigned_int_32.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + // Not applicable as we already have these types now. + ASSERT_FALSE( + add_type_signed_int_32_again.IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE( + add_type_unsigned_int_32_again.IsApplicable(context.get(), fact_manager)); + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %100 = OpTypeInt 32 1 + %101 = OpTypeInt 32 0 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +} // namespace +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/test/fuzz/transformation_add_type_matrix_test.cpp b/third_party/spirv-tools/test/fuzz/transformation_add_type_matrix_test.cpp new file mode 100644 index 0000000000..84f27e9653 --- /dev/null +++ b/third_party/spirv-tools/test/fuzz/transformation_add_type_matrix_test.cpp @@ -0,0 +1,130 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_add_type_matrix.h" +#include "test/fuzz/fuzz_test_util.h" + +namespace spvtools { +namespace fuzz { +namespace { + +TEST(TransformationAddTypeMatrixTest, BasicTest) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypeInt 32 1 + %8 = OpTypeVector %6 2 + %9 = OpTypeVector %6 3 + %10 = OpTypeVector %6 4 + %11 = OpTypeVector %7 2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + // Id already in use + ASSERT_FALSE(TransformationAddTypeMatrix(4, 9, 2).IsApplicable(context.get(), + fact_manager)); + // %1 is not a type + ASSERT_FALSE(TransformationAddTypeMatrix(100, 1, 2).IsApplicable( + context.get(), fact_manager)); + + // %11 is not a floating-point vector + ASSERT_FALSE(TransformationAddTypeMatrix(100, 11, 2) + .IsApplicable(context.get(), fact_manager)); + + TransformationAddTypeMatrix transformations[] = { + // %100 = OpTypeMatrix %8 2 + TransformationAddTypeMatrix(100, 8, 2), + + // %101 = OpTypeMatrix %8 3 + TransformationAddTypeMatrix(101, 8, 3), + + // %102 = OpTypeMatrix %8 4 + TransformationAddTypeMatrix(102, 8, 4), + + // %103 = OpTypeMatrix %9 2 + TransformationAddTypeMatrix(103, 9, 2), + + // %104 = OpTypeMatrix %9 3 + TransformationAddTypeMatrix(104, 9, 3), + + // %105 = OpTypeMatrix %9 4 + TransformationAddTypeMatrix(105, 9, 4), + + // %106 = OpTypeMatrix %10 2 + TransformationAddTypeMatrix(106, 10, 2), + + // %107 = OpTypeMatrix %10 3 + TransformationAddTypeMatrix(107, 10, 3), + + // %108 = OpTypeMatrix %10 4 + TransformationAddTypeMatrix(108, 10, 4)}; + + for (auto& transformation : transformations) { + ASSERT_TRUE(transformation.IsApplicable(context.get(), fact_manager)); + transformation.Apply(context.get(), &fact_manager); + } + ASSERT_TRUE(IsValid(env, context.get())); + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypeInt 32 1 + %8 = OpTypeVector %6 2 + %9 = OpTypeVector %6 3 + %10 = OpTypeVector %6 4 + %11 = OpTypeVector %7 2 + %100 = OpTypeMatrix %8 2 + %101 = OpTypeMatrix %8 3 + %102 = OpTypeMatrix %8 4 + %103 = OpTypeMatrix %9 2 + %104 = OpTypeMatrix %9 3 + %105 = OpTypeMatrix %9 4 + %106 = OpTypeMatrix %10 2 + %107 = OpTypeMatrix %10 3 + %108 = OpTypeMatrix %10 4 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +} // namespace +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/test/fuzz/transformation_add_type_pointer_test.cpp b/third_party/spirv-tools/test/fuzz/transformation_add_type_pointer_test.cpp new file mode 100644 index 0000000000..e36707f54a --- /dev/null +++ b/third_party/spirv-tools/test/fuzz/transformation_add_type_pointer_test.cpp @@ -0,0 +1,206 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_add_type_pointer.h" +#include "test/fuzz/fuzz_test_util.h" + +namespace spvtools { +namespace fuzz { +namespace { + +TEST(TransformationAddTypePointerTest, BasicTest) { + // The SPIR-V was obtained from this GLSL: + // + // #version 450 + // + // int x; + // float y; + // vec2 z; + // + // struct T { + // int a, b; + // }; + // + // struct S { + // T t; + // int u; + // }; + // + // void main() { + // S myS = S(T(1, 2), 3); + // myS.u = x; + // } + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource GLSL 450 + OpName %4 "main" + OpName %7 "T" + OpMemberName %7 0 "a" + OpMemberName %7 1 "b" + OpName %8 "S" + OpMemberName %8 0 "t" + OpMemberName %8 1 "u" + OpName %10 "myS" + OpName %17 "x" + OpName %23 "y" + OpName %26 "z" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypeStruct %6 %6 + %8 = OpTypeStruct %7 %6 + %9 = OpTypePointer Function %8 + %11 = OpConstant %6 1 + %12 = OpConstant %6 2 + %13 = OpConstantComposite %7 %11 %12 + %14 = OpConstant %6 3 + %15 = OpConstantComposite %8 %13 %14 + %16 = OpTypePointer Private %6 + %17 = OpVariable %16 Private + %19 = OpTypePointer Function %6 + %21 = OpTypeFloat 32 + %22 = OpTypePointer Private %21 + %23 = OpVariable %22 Private + %24 = OpTypeVector %21 2 + %25 = OpTypePointer Private %24 + %26 = OpVariable %25 Private + %4 = OpFunction %2 None %3 + %5 = OpLabel + %10 = OpVariable %9 Function + OpStore %10 %15 + %18 = OpLoad %6 %17 + %20 = OpAccessChain %19 %10 %11 + OpStore %20 %18 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + auto bad_type_id_does_not_exist = + TransformationAddTypePointer(100, SpvStorageClassFunction, 101); + auto bad_type_id_is_not_type = + TransformationAddTypePointer(100, SpvStorageClassFunction, 23); + auto bad_result_id_is_not_fresh = + TransformationAddTypePointer(17, SpvStorageClassFunction, 21); + + auto good_new_private_pointer_to_t = + TransformationAddTypePointer(101, SpvStorageClassPrivate, 7); + auto good_new_uniform_pointer_to_t = + TransformationAddTypePointer(102, SpvStorageClassUniform, 7); + auto good_another_function_pointer_to_s = + TransformationAddTypePointer(103, SpvStorageClassFunction, 8); + auto good_new_uniform_pointer_to_s = + TransformationAddTypePointer(104, SpvStorageClassUniform, 8); + auto good_another_private_pointer_to_float = + TransformationAddTypePointer(105, SpvStorageClassPrivate, 21); + auto good_new_private_pointer_to_private_pointer_to_float = + TransformationAddTypePointer(106, SpvStorageClassPrivate, 105); + auto good_new_uniform_pointer_to_vec2 = + TransformationAddTypePointer(107, SpvStorageClassUniform, 24); + auto good_new_private_pointer_to_uniform_pointer_to_vec2 = + TransformationAddTypePointer(108, SpvStorageClassPrivate, 107); + + ASSERT_FALSE( + bad_type_id_does_not_exist.IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE( + bad_type_id_is_not_type.IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE( + bad_result_id_is_not_fresh.IsApplicable(context.get(), fact_manager)); + + for (auto& transformation : + {good_new_private_pointer_to_t, good_new_uniform_pointer_to_t, + good_another_function_pointer_to_s, good_new_uniform_pointer_to_s, + good_another_private_pointer_to_float, + good_new_private_pointer_to_private_pointer_to_float, + good_new_uniform_pointer_to_vec2, + good_new_private_pointer_to_uniform_pointer_to_vec2}) { + ASSERT_TRUE(transformation.IsApplicable(context.get(), fact_manager)); + transformation.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + } + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource GLSL 450 + OpName %4 "main" + OpName %7 "T" + OpMemberName %7 0 "a" + OpMemberName %7 1 "b" + OpName %8 "S" + OpMemberName %8 0 "t" + OpMemberName %8 1 "u" + OpName %10 "myS" + OpName %17 "x" + OpName %23 "y" + OpName %26 "z" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypeStruct %6 %6 + %8 = OpTypeStruct %7 %6 + %9 = OpTypePointer Function %8 + %11 = OpConstant %6 1 + %12 = OpConstant %6 2 + %13 = OpConstantComposite %7 %11 %12 + %14 = OpConstant %6 3 + %15 = OpConstantComposite %8 %13 %14 + %16 = OpTypePointer Private %6 + %17 = OpVariable %16 Private + %19 = OpTypePointer Function %6 + %21 = OpTypeFloat 32 + %22 = OpTypePointer Private %21 + %23 = OpVariable %22 Private + %24 = OpTypeVector %21 2 + %25 = OpTypePointer Private %24 + %26 = OpVariable %25 Private + %101 = OpTypePointer Private %7 + %102 = OpTypePointer Uniform %7 + %103 = OpTypePointer Function %8 + %104 = OpTypePointer Uniform %8 + %105 = OpTypePointer Private %21 + %106 = OpTypePointer Private %105 + %107 = OpTypePointer Uniform %24 + %108 = OpTypePointer Private %107 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %10 = OpVariable %9 Function + OpStore %10 %15 + %18 = OpLoad %6 %17 + %20 = OpAccessChain %19 %10 %11 + OpStore %20 %18 + OpReturn + OpFunctionEnd + )"; + + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +} // namespace +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/test/fuzz/transformation_add_type_struct_test.cpp b/third_party/spirv-tools/test/fuzz/transformation_add_type_struct_test.cpp new file mode 100644 index 0000000000..ae68c9a256 --- /dev/null +++ b/third_party/spirv-tools/test/fuzz/transformation_add_type_struct_test.cpp @@ -0,0 +1,110 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_add_type_struct.h" +#include "test/fuzz/fuzz_test_util.h" + +namespace spvtools { +namespace fuzz { +namespace { + +TEST(TransformationAddTypeStructTest, BasicTest) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypeInt 32 1 + %8 = OpTypeVector %6 2 + %9 = OpTypeVector %6 3 + %10 = OpTypeVector %6 4 + %11 = OpTypeVector %7 2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + // Id already in use + ASSERT_FALSE(TransformationAddTypeStruct(4, {}).IsApplicable(context.get(), + fact_manager)); + // %1 is not a type + ASSERT_FALSE(TransformationAddTypeStruct(100, {1}).IsApplicable( + context.get(), fact_manager)); + + // %3 is a function type + ASSERT_FALSE(TransformationAddTypeStruct(100, {3}).IsApplicable( + context.get(), fact_manager)); + + TransformationAddTypeStruct transformations[] = { + // %100 = OpTypeStruct %6 %7 %8 %9 %10 %11 + TransformationAddTypeStruct(100, {6, 7, 8, 9, 10, 11}), + + // %101 = OpTypeStruct + TransformationAddTypeStruct(101, {}), + + // %102 = OpTypeStruct %6 + TransformationAddTypeStruct(102, {6}), + + // %103 = OpTypeStruct %6 %6 + TransformationAddTypeStruct(103, {6, 6})}; + + for (auto& transformation : transformations) { + ASSERT_TRUE(transformation.IsApplicable(context.get(), fact_manager)); + transformation.Apply(context.get(), &fact_manager); + } + ASSERT_TRUE(IsValid(env, context.get())); + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypeInt 32 1 + %8 = OpTypeVector %6 2 + %9 = OpTypeVector %6 3 + %10 = OpTypeVector %6 4 + %11 = OpTypeVector %7 2 + %100 = OpTypeStruct %6 %7 %8 %9 %10 %11 + %101 = OpTypeStruct + %102 = OpTypeStruct %6 + %103 = OpTypeStruct %6 %6 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +} // namespace +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/test/fuzz/transformation_add_type_vector_test.cpp b/third_party/spirv-tools/test/fuzz/transformation_add_type_vector_test.cpp new file mode 100644 index 0000000000..6ac4498ee6 --- /dev/null +++ b/third_party/spirv-tools/test/fuzz/transformation_add_type_vector_test.cpp @@ -0,0 +1,102 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_add_type_vector.h" +#include "test/fuzz/fuzz_test_util.h" + +namespace spvtools { +namespace fuzz { +namespace { + +TEST(TransformationAddTypeVectorTest, BasicTest) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypeInt 32 1 + %8 = OpTypeInt 32 0 + %9 = OpTypeBool + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + // Id already in use + ASSERT_FALSE(TransformationAddTypeVector(4, 6, 2).IsApplicable(context.get(), + fact_manager)); + // %1 is not a type + ASSERT_FALSE(TransformationAddTypeVector(100, 1, 2).IsApplicable( + context.get(), fact_manager)); + + TransformationAddTypeVector transformations[] = { + // %100 = OpTypeVector %6 2 + TransformationAddTypeVector(100, 6, 2), + + // %101 = OpTypeVector %7 3 + TransformationAddTypeVector(101, 7, 3), + + // %102 = OpTypeVector %8 4 + TransformationAddTypeVector(102, 8, 4), + + // %103 = OpTypeVector %9 2 + TransformationAddTypeVector(103, 9, 2)}; + + for (auto& transformation : transformations) { + ASSERT_TRUE(transformation.IsApplicable(context.get(), fact_manager)); + transformation.Apply(context.get(), &fact_manager); + } + ASSERT_TRUE(IsValid(env, context.get())); + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypeInt 32 1 + %8 = OpTypeInt 32 0 + %9 = OpTypeBool + %100 = OpTypeVector %6 2 + %101 = OpTypeVector %7 3 + %102 = OpTypeVector %8 4 + %103 = OpTypeVector %9 2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +} // namespace +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/test/fuzz/transformation_composite_construct_test.cpp b/third_party/spirv-tools/test/fuzz/transformation_composite_construct_test.cpp new file mode 100644 index 0000000000..d303368ad4 --- /dev/null +++ b/third_party/spirv-tools/test/fuzz/transformation_composite_construct_test.cpp @@ -0,0 +1,1356 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_composite_construct.h" +#include "source/fuzz/data_descriptor.h" +#include "source/fuzz/instruction_descriptor.h" +#include "test/fuzz/fuzz_test_util.h" + +namespace spvtools { +namespace fuzz { +namespace { + +TEST(TransformationCompositeConstructTest, ConstructArrays) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %11 "floats" + OpName %22 "x" + OpName %39 "vecs" + OpName %49 "bools" + OpName %60 "many_uvec3s" + OpDecorate %60 RelaxedPrecision + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypeInt 32 0 + %8 = OpConstant %7 2 + %9 = OpTypeArray %6 %8 + %10 = OpTypePointer Function %9 + %12 = OpTypeInt 32 1 + %13 = OpConstant %12 0 + %14 = OpConstant %6 1 + %15 = OpTypePointer Function %6 + %17 = OpConstant %12 1 + %18 = OpConstant %6 2 + %20 = OpTypeVector %6 2 + %21 = OpTypePointer Function %20 + %32 = OpTypeBool + %36 = OpConstant %7 3 + %37 = OpTypeArray %20 %36 + %38 = OpTypePointer Private %37 + %39 = OpVariable %38 Private + %40 = OpConstant %6 3 + %41 = OpConstantComposite %20 %40 %40 + %42 = OpTypePointer Private %20 + %44 = OpConstant %12 2 + %47 = OpTypeArray %32 %36 + %48 = OpTypePointer Function %47 + %50 = OpConstantTrue %32 + %51 = OpTypePointer Function %32 + %56 = OpTypeVector %7 3 + %57 = OpTypeArray %56 %8 + %58 = OpTypeArray %57 %8 + %59 = OpTypePointer Function %58 + %61 = OpConstant %7 4 + %62 = OpConstantComposite %56 %61 %61 %61 + %63 = OpTypePointer Function %56 + %65 = OpConstant %7 5 + %66 = OpConstantComposite %56 %65 %65 %65 + %67 = OpConstant %7 6 + %68 = OpConstantComposite %56 %67 %67 %67 + %69 = OpConstantComposite %57 %66 %68 + %100 = OpUndef %57 + %70 = OpTypePointer Function %57 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %11 = OpVariable %10 Function + %22 = OpVariable %21 Function + %49 = OpVariable %48 Function + %60 = OpVariable %59 Function + %16 = OpAccessChain %15 %11 %13 + OpStore %16 %14 + %19 = OpAccessChain %15 %11 %17 + OpStore %19 %18 + %23 = OpAccessChain %15 %11 %13 + %24 = OpLoad %6 %23 + %25 = OpAccessChain %15 %11 %17 + %26 = OpLoad %6 %25 + %27 = OpCompositeConstruct %20 %24 %26 + OpStore %22 %27 + %28 = OpAccessChain %15 %11 %13 + %29 = OpLoad %6 %28 + %30 = OpAccessChain %15 %11 %17 + %31 = OpLoad %6 %30 + %33 = OpFOrdGreaterThan %32 %29 %31 + OpSelectionMerge %35 None + OpBranchConditional %33 %34 %35 + %34 = OpLabel + %43 = OpAccessChain %42 %39 %17 + OpStore %43 %41 + %45 = OpLoad %20 %22 + %46 = OpAccessChain %42 %39 %44 + OpStore %46 %45 + OpBranch %35 + %35 = OpLabel + %52 = OpAccessChain %51 %49 %13 + OpStore %52 %50 + %53 = OpAccessChain %51 %49 %13 + %54 = OpLoad %32 %53 + %55 = OpAccessChain %51 %49 %17 + OpStore %55 %54 + %64 = OpAccessChain %63 %60 %13 %13 + OpStore %64 %62 + %71 = OpAccessChain %70 %60 %17 + OpStore %71 %69 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + // Make a vec2[3] + TransformationCompositeConstruct make_vec2_array_length_3( + 37, {41, 45, 27}, MakeInstructionDescriptor(46, SpvOpAccessChain, 0), + 200); + // Bad: there are too many components + TransformationCompositeConstruct make_vec2_array_length_3_bad( + 37, {41, 45, 27, 27}, MakeInstructionDescriptor(46, SpvOpAccessChain, 0), + 200); + ASSERT_TRUE( + make_vec2_array_length_3.IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE( + make_vec2_array_length_3_bad.IsApplicable(context.get(), fact_manager)); + make_vec2_array_length_3.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous( + MakeDataDescriptor(41, {}), MakeDataDescriptor(200, {0}), context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous( + MakeDataDescriptor(45, {}), MakeDataDescriptor(200, {1}), context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous( + MakeDataDescriptor(27, {}), MakeDataDescriptor(200, {2}), context.get())); + + // Make a float[2] + TransformationCompositeConstruct make_float_array_length_2( + 9, {24, 40}, MakeInstructionDescriptor(71, SpvOpStore, 0), 201); + // Bad: %41 does not have type float + TransformationCompositeConstruct make_float_array_length_2_bad( + 9, {41, 40}, MakeInstructionDescriptor(71, SpvOpStore, 0), 201); + ASSERT_TRUE( + make_float_array_length_2.IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE( + make_float_array_length_2_bad.IsApplicable(context.get(), fact_manager)); + make_float_array_length_2.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous( + MakeDataDescriptor(24, {}), MakeDataDescriptor(201, {0}), context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous( + MakeDataDescriptor(40, {}), MakeDataDescriptor(201, {1}), context.get())); + + // Make a bool[3] + TransformationCompositeConstruct make_bool_array_length_3( + 47, {33, 50, 50}, MakeInstructionDescriptor(33, SpvOpSelectionMerge, 0), + 202); + // Bad: %54 is not available at the desired program point. + TransformationCompositeConstruct make_bool_array_length_3_bad( + 47, {33, 54, 50}, MakeInstructionDescriptor(33, SpvOpSelectionMerge, 0), + 202); + ASSERT_TRUE( + make_bool_array_length_3.IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE( + make_bool_array_length_3_bad.IsApplicable(context.get(), fact_manager)); + make_bool_array_length_3.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous( + MakeDataDescriptor(33, {}), MakeDataDescriptor(202, {0}), context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous( + MakeDataDescriptor(50, {}), MakeDataDescriptor(202, {1}), context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous( + MakeDataDescriptor(50, {}), MakeDataDescriptor(202, {2}), context.get())); + + // make a uvec3[2][2] + TransformationCompositeConstruct make_uvec3_array_length_2_2( + 58, {69, 100}, MakeInstructionDescriptor(64, SpvOpStore, 0), 203); + // Bad: Skip count 100 is too large. + TransformationCompositeConstruct make_uvec3_array_length_2_2_bad( + 58, {33, 54}, MakeInstructionDescriptor(64, SpvOpStore, 100), 203); + ASSERT_TRUE( + make_uvec3_array_length_2_2.IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(make_uvec3_array_length_2_2_bad.IsApplicable(context.get(), + fact_manager)); + make_uvec3_array_length_2_2.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous( + MakeDataDescriptor(69, {}), MakeDataDescriptor(203, {0}), context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(100, {}), + MakeDataDescriptor(203, {1}), + context.get())); + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %11 "floats" + OpName %22 "x" + OpName %39 "vecs" + OpName %49 "bools" + OpName %60 "many_uvec3s" + OpDecorate %60 RelaxedPrecision + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypeInt 32 0 + %8 = OpConstant %7 2 + %9 = OpTypeArray %6 %8 + %10 = OpTypePointer Function %9 + %12 = OpTypeInt 32 1 + %13 = OpConstant %12 0 + %14 = OpConstant %6 1 + %15 = OpTypePointer Function %6 + %17 = OpConstant %12 1 + %18 = OpConstant %6 2 + %20 = OpTypeVector %6 2 + %21 = OpTypePointer Function %20 + %32 = OpTypeBool + %36 = OpConstant %7 3 + %37 = OpTypeArray %20 %36 + %38 = OpTypePointer Private %37 + %39 = OpVariable %38 Private + %40 = OpConstant %6 3 + %41 = OpConstantComposite %20 %40 %40 + %42 = OpTypePointer Private %20 + %44 = OpConstant %12 2 + %47 = OpTypeArray %32 %36 + %48 = OpTypePointer Function %47 + %50 = OpConstantTrue %32 + %51 = OpTypePointer Function %32 + %56 = OpTypeVector %7 3 + %57 = OpTypeArray %56 %8 + %58 = OpTypeArray %57 %8 + %59 = OpTypePointer Function %58 + %61 = OpConstant %7 4 + %62 = OpConstantComposite %56 %61 %61 %61 + %63 = OpTypePointer Function %56 + %65 = OpConstant %7 5 + %66 = OpConstantComposite %56 %65 %65 %65 + %67 = OpConstant %7 6 + %68 = OpConstantComposite %56 %67 %67 %67 + %69 = OpConstantComposite %57 %66 %68 + %100 = OpUndef %57 + %70 = OpTypePointer Function %57 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %11 = OpVariable %10 Function + %22 = OpVariable %21 Function + %49 = OpVariable %48 Function + %60 = OpVariable %59 Function + %16 = OpAccessChain %15 %11 %13 + OpStore %16 %14 + %19 = OpAccessChain %15 %11 %17 + OpStore %19 %18 + %23 = OpAccessChain %15 %11 %13 + %24 = OpLoad %6 %23 + %25 = OpAccessChain %15 %11 %17 + %26 = OpLoad %6 %25 + %27 = OpCompositeConstruct %20 %24 %26 + OpStore %22 %27 + %28 = OpAccessChain %15 %11 %13 + %29 = OpLoad %6 %28 + %30 = OpAccessChain %15 %11 %17 + %31 = OpLoad %6 %30 + %33 = OpFOrdGreaterThan %32 %29 %31 + %202 = OpCompositeConstruct %47 %33 %50 %50 + OpSelectionMerge %35 None + OpBranchConditional %33 %34 %35 + %34 = OpLabel + %43 = OpAccessChain %42 %39 %17 + OpStore %43 %41 + %45 = OpLoad %20 %22 + %200 = OpCompositeConstruct %37 %41 %45 %27 + %46 = OpAccessChain %42 %39 %44 + OpStore %46 %45 + OpBranch %35 + %35 = OpLabel + %52 = OpAccessChain %51 %49 %13 + OpStore %52 %50 + %53 = OpAccessChain %51 %49 %13 + %54 = OpLoad %32 %53 + %55 = OpAccessChain %51 %49 %17 + OpStore %55 %54 + %64 = OpAccessChain %63 %60 %13 %13 + %203 = OpCompositeConstruct %58 %69 %100 + OpStore %64 %62 + %71 = OpAccessChain %70 %60 %17 + %201 = OpCompositeConstruct %9 %24 %40 + OpStore %71 %69 + OpReturn + OpFunctionEnd + )"; + + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +TEST(TransformationCompositeConstructTest, ConstructMatrices) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %9 "v1" + OpName %12 "v2" + OpName %14 "v3" + OpName %19 "v4" + OpName %26 "v5" + OpName %29 "v6" + OpName %34 "m34" + OpName %37 "m43" + OpName %43 "vecs" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypeVector %6 3 + %8 = OpTypePointer Function %7 + %10 = OpConstant %6 1 + %11 = OpConstantComposite %7 %10 %10 %10 + %17 = OpTypeVector %6 4 + %18 = OpTypePointer Function %17 + %21 = OpConstant %6 2 + %32 = OpTypeMatrix %17 3 + %33 = OpTypePointer Private %32 + %34 = OpVariable %33 Private + %35 = OpTypeMatrix %7 4 + %36 = OpTypePointer Private %35 + %37 = OpVariable %36 Private + %38 = OpTypeVector %6 2 + %39 = OpTypeInt 32 0 + %40 = OpConstant %39 3 + %41 = OpTypeArray %38 %40 + %42 = OpTypePointer Private %41 + %43 = OpVariable %42 Private + %100 = OpUndef %7 + %101 = OpUndef %17 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %9 = OpVariable %8 Function + %12 = OpVariable %8 Function + %14 = OpVariable %8 Function + %19 = OpVariable %18 Function + %26 = OpVariable %18 Function + %29 = OpVariable %18 Function + OpStore %9 %11 + %13 = OpLoad %7 %9 + OpStore %12 %13 + %15 = OpLoad %7 %12 + %16 = OpVectorShuffle %7 %15 %15 2 1 0 + OpStore %14 %16 + %20 = OpLoad %7 %14 + %22 = OpCompositeExtract %6 %20 0 + %23 = OpCompositeExtract %6 %20 1 + %24 = OpCompositeExtract %6 %20 2 + %25 = OpCompositeConstruct %17 %22 %23 %24 %21 + OpStore %19 %25 + %27 = OpLoad %17 %19 + %28 = OpVectorShuffle %17 %27 %27 3 2 1 0 + OpStore %26 %28 + %30 = OpLoad %7 %9 + %31 = OpVectorShuffle %17 %30 %30 0 0 1 1 + OpStore %29 %31 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + // make a mat3x4 + TransformationCompositeConstruct make_mat34( + 32, {25, 28, 31}, MakeInstructionDescriptor(31, SpvOpReturn, 0), 200); + // Bad: %35 is mat4x3, not mat3x4. + TransformationCompositeConstruct make_mat34_bad( + 35, {25, 28, 31}, MakeInstructionDescriptor(31, SpvOpReturn, 0), 200); + ASSERT_TRUE(make_mat34.IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(make_mat34_bad.IsApplicable(context.get(), fact_manager)); + make_mat34.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous( + MakeDataDescriptor(25, {}), MakeDataDescriptor(200, {0}), context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous( + MakeDataDescriptor(28, {}), MakeDataDescriptor(200, {1}), context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous( + MakeDataDescriptor(31, {}), MakeDataDescriptor(200, {2}), context.get())); + + // make a mat4x3 + TransformationCompositeConstruct make_mat43( + 35, {11, 13, 16, 100}, MakeInstructionDescriptor(31, SpvOpStore, 0), 201); + // Bad: %25 does not match the matrix's column type. + TransformationCompositeConstruct make_mat43_bad( + 35, {25, 13, 16, 100}, MakeInstructionDescriptor(31, SpvOpStore, 0), 201); + ASSERT_TRUE(make_mat43.IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(make_mat43_bad.IsApplicable(context.get(), fact_manager)); + make_mat43.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous( + MakeDataDescriptor(11, {}), MakeDataDescriptor(201, {0}), context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous( + MakeDataDescriptor(13, {}), MakeDataDescriptor(201, {1}), context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous( + MakeDataDescriptor(16, {}), MakeDataDescriptor(201, {2}), context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(100, {}), + MakeDataDescriptor(201, {3}), + context.get())); + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %9 "v1" + OpName %12 "v2" + OpName %14 "v3" + OpName %19 "v4" + OpName %26 "v5" + OpName %29 "v6" + OpName %34 "m34" + OpName %37 "m43" + OpName %43 "vecs" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypeVector %6 3 + %8 = OpTypePointer Function %7 + %10 = OpConstant %6 1 + %11 = OpConstantComposite %7 %10 %10 %10 + %17 = OpTypeVector %6 4 + %18 = OpTypePointer Function %17 + %21 = OpConstant %6 2 + %32 = OpTypeMatrix %17 3 + %33 = OpTypePointer Private %32 + %34 = OpVariable %33 Private + %35 = OpTypeMatrix %7 4 + %36 = OpTypePointer Private %35 + %37 = OpVariable %36 Private + %38 = OpTypeVector %6 2 + %39 = OpTypeInt 32 0 + %40 = OpConstant %39 3 + %41 = OpTypeArray %38 %40 + %42 = OpTypePointer Private %41 + %43 = OpVariable %42 Private + %100 = OpUndef %7 + %101 = OpUndef %17 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %9 = OpVariable %8 Function + %12 = OpVariable %8 Function + %14 = OpVariable %8 Function + %19 = OpVariable %18 Function + %26 = OpVariable %18 Function + %29 = OpVariable %18 Function + OpStore %9 %11 + %13 = OpLoad %7 %9 + OpStore %12 %13 + %15 = OpLoad %7 %12 + %16 = OpVectorShuffle %7 %15 %15 2 1 0 + OpStore %14 %16 + %20 = OpLoad %7 %14 + %22 = OpCompositeExtract %6 %20 0 + %23 = OpCompositeExtract %6 %20 1 + %24 = OpCompositeExtract %6 %20 2 + %25 = OpCompositeConstruct %17 %22 %23 %24 %21 + OpStore %19 %25 + %27 = OpLoad %17 %19 + %28 = OpVectorShuffle %17 %27 %27 3 2 1 0 + OpStore %26 %28 + %30 = OpLoad %7 %9 + %31 = OpVectorShuffle %17 %30 %30 0 0 1 1 + %201 = OpCompositeConstruct %35 %11 %13 %16 %100 + OpStore %29 %31 + %200 = OpCompositeConstruct %32 %25 %28 %31 + OpReturn + OpFunctionEnd + )"; + + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +TEST(TransformationCompositeConstructTest, ConstructStructs) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %9 "Inner" + OpMemberName %9 0 "a" + OpMemberName %9 1 "b" + OpName %11 "i1" + OpName %22 "i2" + OpName %33 "Outer" + OpMemberName %33 0 "c" + OpMemberName %33 1 "d" + OpMemberName %33 2 "e" + OpName %35 "o" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypeVector %6 2 + %8 = OpTypeInt 32 1 + %9 = OpTypeStruct %7 %8 + %10 = OpTypePointer Function %9 + %12 = OpConstant %8 0 + %13 = OpConstant %6 2 + %14 = OpTypeInt 32 0 + %15 = OpConstant %14 0 + %16 = OpTypePointer Function %6 + %18 = OpConstant %8 1 + %19 = OpConstant %8 3 + %20 = OpTypePointer Function %8 + %23 = OpTypePointer Function %7 + %31 = OpConstant %14 2 + %32 = OpTypeArray %9 %31 + %33 = OpTypeStruct %32 %9 %6 + %34 = OpTypePointer Function %33 + %36 = OpConstant %6 1 + %37 = OpConstantComposite %7 %36 %13 + %38 = OpConstant %8 2 + %39 = OpConstantComposite %9 %37 %38 + %40 = OpConstant %6 3 + %41 = OpConstant %6 4 + %42 = OpConstantComposite %7 %40 %41 + %56 = OpConstant %6 5 + %100 = OpUndef %9 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %11 = OpVariable %10 Function + %22 = OpVariable %10 Function + %35 = OpVariable %34 Function + %17 = OpAccessChain %16 %11 %12 %15 + OpStore %17 %13 + %21 = OpAccessChain %20 %11 %18 + OpStore %21 %19 + %24 = OpAccessChain %23 %11 %12 + %25 = OpLoad %7 %24 + %26 = OpAccessChain %23 %22 %12 + OpStore %26 %25 + %27 = OpAccessChain %20 %11 %18 + %28 = OpLoad %8 %27 + %29 = OpIAdd %8 %28 %18 + %30 = OpAccessChain %20 %22 %18 + OpStore %30 %29 + %43 = OpAccessChain %20 %11 %18 + %44 = OpLoad %8 %43 + %45 = OpCompositeConstruct %9 %42 %44 + %46 = OpCompositeConstruct %32 %39 %45 + %47 = OpLoad %9 %22 + %48 = OpCompositeConstruct %33 %46 %47 %40 + OpStore %35 %48 + %49 = OpLoad %9 %11 + %50 = OpAccessChain %10 %35 %12 %12 + OpStore %50 %49 + %51 = OpLoad %9 %22 + %52 = OpAccessChain %10 %35 %12 %18 + OpStore %52 %51 + %53 = OpAccessChain %10 %35 %12 %12 + %54 = OpLoad %9 %53 + %55 = OpAccessChain %10 %35 %18 + OpStore %55 %54 + %57 = OpAccessChain %16 %35 %38 + OpStore %57 %56 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + // make an Inner + TransformationCompositeConstruct make_inner( + 9, {25, 19}, MakeInstructionDescriptor(57, SpvOpAccessChain, 0), 200); + // Bad: Too few fields to make the struct. + TransformationCompositeConstruct make_inner_bad( + 9, {25}, MakeInstructionDescriptor(57, SpvOpAccessChain, 0), 200); + ASSERT_TRUE(make_inner.IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(make_inner_bad.IsApplicable(context.get(), fact_manager)); + make_inner.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous( + MakeDataDescriptor(25, {}), MakeDataDescriptor(200, {0}), context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous( + MakeDataDescriptor(19, {}), MakeDataDescriptor(200, {1}), context.get())); + + // make an Outer + TransformationCompositeConstruct make_outer( + 33, {46, 200, 56}, MakeInstructionDescriptor(200, SpvOpAccessChain, 0), + 201); + // Bad: %200 is not available at the desired program point. + TransformationCompositeConstruct make_outer_bad( + 33, {46, 200, 56}, + MakeInstructionDescriptor(200, SpvOpCompositeConstruct, 0), 201); + ASSERT_TRUE(make_outer.IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(make_outer_bad.IsApplicable(context.get(), fact_manager)); + make_outer.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous( + MakeDataDescriptor(46, {}), MakeDataDescriptor(201, {0}), context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(200, {}), + MakeDataDescriptor(201, {1}), + context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous( + MakeDataDescriptor(56, {}), MakeDataDescriptor(201, {2}), context.get())); + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %9 "Inner" + OpMemberName %9 0 "a" + OpMemberName %9 1 "b" + OpName %11 "i1" + OpName %22 "i2" + OpName %33 "Outer" + OpMemberName %33 0 "c" + OpMemberName %33 1 "d" + OpMemberName %33 2 "e" + OpName %35 "o" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypeVector %6 2 + %8 = OpTypeInt 32 1 + %9 = OpTypeStruct %7 %8 + %10 = OpTypePointer Function %9 + %12 = OpConstant %8 0 + %13 = OpConstant %6 2 + %14 = OpTypeInt 32 0 + %15 = OpConstant %14 0 + %16 = OpTypePointer Function %6 + %18 = OpConstant %8 1 + %19 = OpConstant %8 3 + %20 = OpTypePointer Function %8 + %23 = OpTypePointer Function %7 + %31 = OpConstant %14 2 + %32 = OpTypeArray %9 %31 + %33 = OpTypeStruct %32 %9 %6 + %34 = OpTypePointer Function %33 + %36 = OpConstant %6 1 + %37 = OpConstantComposite %7 %36 %13 + %38 = OpConstant %8 2 + %39 = OpConstantComposite %9 %37 %38 + %40 = OpConstant %6 3 + %41 = OpConstant %6 4 + %42 = OpConstantComposite %7 %40 %41 + %56 = OpConstant %6 5 + %100 = OpUndef %9 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %11 = OpVariable %10 Function + %22 = OpVariable %10 Function + %35 = OpVariable %34 Function + %17 = OpAccessChain %16 %11 %12 %15 + OpStore %17 %13 + %21 = OpAccessChain %20 %11 %18 + OpStore %21 %19 + %24 = OpAccessChain %23 %11 %12 + %25 = OpLoad %7 %24 + %26 = OpAccessChain %23 %22 %12 + OpStore %26 %25 + %27 = OpAccessChain %20 %11 %18 + %28 = OpLoad %8 %27 + %29 = OpIAdd %8 %28 %18 + %30 = OpAccessChain %20 %22 %18 + OpStore %30 %29 + %43 = OpAccessChain %20 %11 %18 + %44 = OpLoad %8 %43 + %45 = OpCompositeConstruct %9 %42 %44 + %46 = OpCompositeConstruct %32 %39 %45 + %47 = OpLoad %9 %22 + %48 = OpCompositeConstruct %33 %46 %47 %40 + OpStore %35 %48 + %49 = OpLoad %9 %11 + %50 = OpAccessChain %10 %35 %12 %12 + OpStore %50 %49 + %51 = OpLoad %9 %22 + %52 = OpAccessChain %10 %35 %12 %18 + OpStore %52 %51 + %53 = OpAccessChain %10 %35 %12 %12 + %54 = OpLoad %9 %53 + %55 = OpAccessChain %10 %35 %18 + OpStore %55 %54 + %200 = OpCompositeConstruct %9 %25 %19 + %201 = OpCompositeConstruct %33 %46 %200 %56 + %57 = OpAccessChain %16 %35 %38 + OpStore %57 %56 + OpReturn + OpFunctionEnd + )"; + + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +TEST(TransformationCompositeConstructTest, ConstructVectors) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %9 "v2" + OpName %27 "v3" + OpName %46 "v4" + OpName %53 "iv2" + OpName %61 "uv3" + OpName %72 "bv4" + OpName %88 "uv2" + OpName %95 "bv3" + OpName %104 "bv2" + OpName %116 "iv3" + OpName %124 "iv4" + OpName %133 "uv4" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypeVector %6 2 + %8 = OpTypePointer Function %7 + %10 = OpConstant %6 1 + %11 = OpConstant %6 2 + %12 = OpConstantComposite %7 %10 %11 + %13 = OpTypeInt 32 0 + %14 = OpConstant %13 0 + %15 = OpTypePointer Function %6 + %18 = OpConstant %13 1 + %21 = OpTypeBool + %25 = OpTypeVector %6 3 + %26 = OpTypePointer Function %25 + %33 = OpConstant %6 3 + %34 = OpConstant %6 -0.756802499 + %38 = OpConstant %13 2 + %44 = OpTypeVector %6 4 + %45 = OpTypePointer Function %44 + %50 = OpTypeInt 32 1 + %51 = OpTypeVector %50 2 + %52 = OpTypePointer Function %51 + %57 = OpTypePointer Function %50 + %59 = OpTypeVector %13 3 + %60 = OpTypePointer Function %59 + %65 = OpConstant %13 3 + %67 = OpTypePointer Function %13 + %70 = OpTypeVector %21 4 + %71 = OpTypePointer Function %70 + %73 = OpConstantTrue %21 + %74 = OpTypePointer Function %21 + %86 = OpTypeVector %13 2 + %87 = OpTypePointer Function %86 + %93 = OpTypeVector %21 3 + %94 = OpTypePointer Function %93 + %102 = OpTypeVector %21 2 + %103 = OpTypePointer Function %102 + %111 = OpConstantFalse %21 + %114 = OpTypeVector %50 3 + %115 = OpTypePointer Function %114 + %117 = OpConstant %50 3 + %122 = OpTypeVector %50 4 + %123 = OpTypePointer Function %122 + %131 = OpTypeVector %13 4 + %132 = OpTypePointer Function %131 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %9 = OpVariable %8 Function + %27 = OpVariable %26 Function + %46 = OpVariable %45 Function + %53 = OpVariable %52 Function + %61 = OpVariable %60 Function + %72 = OpVariable %71 Function + %88 = OpVariable %87 Function + %95 = OpVariable %94 Function + %104 = OpVariable %103 Function + %116 = OpVariable %115 Function + %124 = OpVariable %123 Function + %133 = OpVariable %132 Function + OpStore %9 %12 + %16 = OpAccessChain %15 %9 %14 + %17 = OpLoad %6 %16 + %19 = OpAccessChain %15 %9 %18 + %20 = OpLoad %6 %19 + %22 = OpFOrdGreaterThan %21 %17 %20 + OpSelectionMerge %24 None + OpBranchConditional %22 %23 %101 + %23 = OpLabel + %28 = OpAccessChain %15 %9 %14 + %29 = OpLoad %6 %28 + %30 = OpAccessChain %15 %9 %18 + %31 = OpLoad %6 %30 + %32 = OpFAdd %6 %29 %31 + %35 = OpCompositeConstruct %25 %32 %33 %34 + OpStore %27 %35 + %36 = OpAccessChain %15 %27 %14 + %37 = OpLoad %6 %36 + %39 = OpAccessChain %15 %27 %38 + %40 = OpLoad %6 %39 + %41 = OpFOrdLessThan %21 %37 %40 + OpSelectionMerge %43 None + OpBranchConditional %41 %42 %69 + %42 = OpLabel + %47 = OpAccessChain %15 %9 %18 + %48 = OpLoad %6 %47 + %49 = OpAccessChain %15 %46 %14 + OpStore %49 %48 + %54 = OpAccessChain %15 %27 %38 + %55 = OpLoad %6 %54 + %56 = OpConvertFToS %50 %55 + %58 = OpAccessChain %57 %53 %14 + OpStore %58 %56 + %62 = OpAccessChain %15 %46 %14 + %63 = OpLoad %6 %62 + %64 = OpConvertFToU %13 %63 + %66 = OpIAdd %13 %64 %65 + %68 = OpAccessChain %67 %61 %14 + OpStore %68 %66 + OpBranch %43 + %69 = OpLabel + %75 = OpAccessChain %74 %72 %14 + OpStore %75 %73 + %76 = OpAccessChain %74 %72 %14 + %77 = OpLoad %21 %76 + %78 = OpLogicalNot %21 %77 + %79 = OpAccessChain %74 %72 %18 + OpStore %79 %78 + %80 = OpAccessChain %74 %72 %14 + %81 = OpLoad %21 %80 + %82 = OpAccessChain %74 %72 %18 + %83 = OpLoad %21 %82 + %84 = OpLogicalAnd %21 %81 %83 + %85 = OpAccessChain %74 %72 %38 + OpStore %85 %84 + %89 = OpAccessChain %67 %88 %14 + %90 = OpLoad %13 %89 + %91 = OpINotEqual %21 %90 %14 + %92 = OpAccessChain %74 %72 %65 + OpStore %92 %91 + OpBranch %43 + %43 = OpLabel + %96 = OpLoad %70 %72 + %97 = OpCompositeExtract %21 %96 0 + %98 = OpCompositeExtract %21 %96 1 + %99 = OpCompositeExtract %21 %96 2 + %100 = OpCompositeConstruct %93 %97 %98 %99 + OpStore %95 %100 + OpBranch %24 + %101 = OpLabel + %105 = OpAccessChain %67 %88 %14 + %106 = OpLoad %13 %105 + %107 = OpINotEqual %21 %106 %14 + %108 = OpCompositeConstruct %102 %107 %107 + OpStore %104 %108 + OpBranch %24 + %24 = OpLabel + %109 = OpAccessChain %74 %104 %18 + %110 = OpLoad %21 %109 + %112 = OpLogicalOr %21 %110 %111 + %113 = OpAccessChain %74 %104 %14 + OpStore %113 %112 + %118 = OpAccessChain %57 %116 %14 + OpStore %118 %117 + %119 = OpAccessChain %57 %116 %14 + %120 = OpLoad %50 %119 + %121 = OpAccessChain %57 %53 %18 + OpStore %121 %120 + %125 = OpAccessChain %57 %116 %14 + %126 = OpLoad %50 %125 + %127 = OpAccessChain %57 %53 %18 + %128 = OpLoad %50 %127 + %129 = OpIAdd %50 %126 %128 + %130 = OpAccessChain %57 %124 %65 + OpStore %130 %129 + %134 = OpAccessChain %57 %116 %14 + %135 = OpLoad %50 %134 + %136 = OpBitcast %13 %135 + %137 = OpAccessChain %67 %133 %14 + OpStore %137 %136 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + TransformationCompositeConstruct make_vec2( + 7, {17, 11}, MakeInstructionDescriptor(100, SpvOpStore, 0), 200); + // Bad: not enough data for a vec2 + TransformationCompositeConstruct make_vec2_bad( + 7, {11}, MakeInstructionDescriptor(100, SpvOpStore, 0), 200); + ASSERT_TRUE(make_vec2.IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(make_vec2_bad.IsApplicable(context.get(), fact_manager)); + make_vec2.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous( + MakeDataDescriptor(17, {}), MakeDataDescriptor(200, {0}), context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous( + MakeDataDescriptor(11, {}), MakeDataDescriptor(200, {1}), context.get())); + + TransformationCompositeConstruct make_vec3( + 25, {12, 32}, MakeInstructionDescriptor(35, SpvOpCompositeConstruct, 0), + 201); + // Bad: too much data for a vec3 + TransformationCompositeConstruct make_vec3_bad( + 25, {12, 32, 32}, + MakeInstructionDescriptor(35, SpvOpCompositeConstruct, 0), 201); + ASSERT_TRUE(make_vec3.IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(make_vec3_bad.IsApplicable(context.get(), fact_manager)); + make_vec3.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(12, {0}), + MakeDataDescriptor(201, {0}), + context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(12, {1}), + MakeDataDescriptor(201, {1}), + context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous( + MakeDataDescriptor(32, {}), MakeDataDescriptor(201, {2}), context.get())); + + TransformationCompositeConstruct make_vec4( + 44, {32, 32, 10, 11}, MakeInstructionDescriptor(75, SpvOpAccessChain, 0), + 202); + // Bad: id 48 is not available at the insertion points + TransformationCompositeConstruct make_vec4_bad( + 44, {48, 32, 10, 11}, MakeInstructionDescriptor(75, SpvOpAccessChain, 0), + 202); + ASSERT_TRUE(make_vec4.IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(make_vec4_bad.IsApplicable(context.get(), fact_manager)); + make_vec4.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous( + MakeDataDescriptor(32, {}), MakeDataDescriptor(202, {0}), context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous( + MakeDataDescriptor(32, {}), MakeDataDescriptor(202, {1}), context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous( + MakeDataDescriptor(10, {}), MakeDataDescriptor(202, {2}), context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous( + MakeDataDescriptor(11, {}), MakeDataDescriptor(202, {3}), context.get())); + + TransformationCompositeConstruct make_ivec2( + 51, {126, 120}, MakeInstructionDescriptor(128, SpvOpLoad, 0), 203); + // Bad: if 128 is not available at the instruction that defines 128 + TransformationCompositeConstruct make_ivec2_bad( + 51, {128, 120}, MakeInstructionDescriptor(128, SpvOpLoad, 0), 203); + ASSERT_TRUE(make_ivec2.IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(make_ivec2_bad.IsApplicable(context.get(), fact_manager)); + make_ivec2.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(126, {}), + MakeDataDescriptor(203, {0}), + context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(120, {}), + MakeDataDescriptor(203, {1}), + context.get())); + + TransformationCompositeConstruct make_ivec3( + 114, {56, 117, 56}, MakeInstructionDescriptor(66, SpvOpAccessChain, 0), + 204); + // Bad because 1300 is not an id + TransformationCompositeConstruct make_ivec3_bad( + 114, {56, 117, 1300}, MakeInstructionDescriptor(66, SpvOpAccessChain, 0), + 204); + ASSERT_TRUE(make_ivec3.IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(make_ivec3_bad.IsApplicable(context.get(), fact_manager)); + make_ivec3.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous( + MakeDataDescriptor(56, {}), MakeDataDescriptor(204, {0}), context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(117, {}), + MakeDataDescriptor(204, {1}), + context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous( + MakeDataDescriptor(56, {}), MakeDataDescriptor(204, {2}), context.get())); + + TransformationCompositeConstruct make_ivec4( + 122, {56, 117, 117, 117}, MakeInstructionDescriptor(66, SpvOpIAdd, 0), + 205); + // Bad because 86 is the wrong type. + TransformationCompositeConstruct make_ivec4_bad( + 86, {56, 117, 117, 117}, MakeInstructionDescriptor(66, SpvOpIAdd, 0), + 205); + ASSERT_TRUE(make_ivec4.IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(make_ivec4_bad.IsApplicable(context.get(), fact_manager)); + make_ivec4.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous( + MakeDataDescriptor(56, {}), MakeDataDescriptor(205, {0}), context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(117, {}), + MakeDataDescriptor(205, {1}), + context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(117, {}), + MakeDataDescriptor(205, {2}), + context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(117, {}), + MakeDataDescriptor(205, {3}), + context.get())); + + TransformationCompositeConstruct make_uvec2( + 86, {18, 38}, MakeInstructionDescriptor(133, SpvOpAccessChain, 0), 206); + TransformationCompositeConstruct make_uvec2_bad( + 86, {18, 38}, MakeInstructionDescriptor(133, SpvOpAccessChain, 200), 206); + ASSERT_TRUE(make_uvec2.IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(make_uvec2_bad.IsApplicable(context.get(), fact_manager)); + make_uvec2.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous( + MakeDataDescriptor(18, {}), MakeDataDescriptor(206, {0}), context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous( + MakeDataDescriptor(38, {}), MakeDataDescriptor(206, {1}), context.get())); + + TransformationCompositeConstruct make_uvec3( + 59, {14, 18, 136}, MakeInstructionDescriptor(137, SpvOpReturn, 0), 207); + // Bad because 1300 is not an id + TransformationCompositeConstruct make_uvec3_bad( + 59, {14, 18, 1300}, MakeInstructionDescriptor(137, SpvOpReturn, 0), 207); + ASSERT_TRUE(make_uvec3.IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(make_uvec3_bad.IsApplicable(context.get(), fact_manager)); + make_uvec3.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous( + MakeDataDescriptor(14, {}), MakeDataDescriptor(207, {0}), context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous( + MakeDataDescriptor(18, {}), MakeDataDescriptor(207, {1}), context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(136, {}), + MakeDataDescriptor(207, {2}), + context.get())); + + TransformationCompositeConstruct make_uvec4( + 131, {14, 18, 136, 136}, + MakeInstructionDescriptor(137, SpvOpAccessChain, 0), 208); + // Bad because 86 is the wrong type. + TransformationCompositeConstruct make_uvec4_bad( + 86, {14, 18, 136, 136}, + MakeInstructionDescriptor(137, SpvOpAccessChain, 0), 208); + ASSERT_TRUE(make_uvec4.IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(make_uvec4_bad.IsApplicable(context.get(), fact_manager)); + make_uvec4.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous( + MakeDataDescriptor(14, {}), MakeDataDescriptor(208, {0}), context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous( + MakeDataDescriptor(18, {}), MakeDataDescriptor(208, {1}), context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(136, {}), + MakeDataDescriptor(208, {2}), + context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(136, {}), + MakeDataDescriptor(208, {3}), + context.get())); + + TransformationCompositeConstruct make_bvec2( + 102, + { + 111, + 41, + }, + MakeInstructionDescriptor(75, SpvOpAccessChain, 0), 209); + // Bad because 0 is not a valid base instruction id + TransformationCompositeConstruct make_bvec2_bad( + 102, + { + 111, + 41, + }, + MakeInstructionDescriptor(0, SpvOpExtInstImport, 0), 209); + ASSERT_TRUE(make_bvec2.IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(make_bvec2_bad.IsApplicable(context.get(), fact_manager)); + make_bvec2.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(111, {}), + MakeDataDescriptor(209, {0}), + context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous( + MakeDataDescriptor(41, {}), MakeDataDescriptor(209, {1}), context.get())); + + TransformationCompositeConstruct make_bvec3( + 93, {108, 73}, MakeInstructionDescriptor(108, SpvOpStore, 0), 210); + // Bad because there are too many components for a bvec3 + TransformationCompositeConstruct make_bvec3_bad( + 93, {108, 108}, MakeInstructionDescriptor(108, SpvOpStore, 0), 210); + ASSERT_TRUE(make_bvec3.IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(make_bvec3_bad.IsApplicable(context.get(), fact_manager)); + make_bvec3.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(108, {0}), + MakeDataDescriptor(210, {0}), + context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(108, {1}), + MakeDataDescriptor(210, {1}), + context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous( + MakeDataDescriptor(73, {}), MakeDataDescriptor(210, {2}), context.get())); + + TransformationCompositeConstruct make_bvec4( + 70, {108, 108}, MakeInstructionDescriptor(108, SpvOpBranch, 0), 211); + // Bad because 21 is a type, not a result id + TransformationCompositeConstruct make_bvec4_bad( + 70, {21, 108}, MakeInstructionDescriptor(108, SpvOpBranch, 0), 211); + ASSERT_TRUE(make_bvec4.IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(make_bvec4_bad.IsApplicable(context.get(), fact_manager)); + make_bvec4.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(108, {0}), + MakeDataDescriptor(211, {0}), + context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(108, {1}), + MakeDataDescriptor(211, {1}), + context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(108, {0}), + MakeDataDescriptor(211, {2}), + context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(108, {1}), + MakeDataDescriptor(211, {3}), + context.get())); + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %9 "v2" + OpName %27 "v3" + OpName %46 "v4" + OpName %53 "iv2" + OpName %61 "uv3" + OpName %72 "bv4" + OpName %88 "uv2" + OpName %95 "bv3" + OpName %104 "bv2" + OpName %116 "iv3" + OpName %124 "iv4" + OpName %133 "uv4" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypeVector %6 2 + %8 = OpTypePointer Function %7 + %10 = OpConstant %6 1 + %11 = OpConstant %6 2 + %12 = OpConstantComposite %7 %10 %11 + %13 = OpTypeInt 32 0 + %14 = OpConstant %13 0 + %15 = OpTypePointer Function %6 + %18 = OpConstant %13 1 + %21 = OpTypeBool + %25 = OpTypeVector %6 3 + %26 = OpTypePointer Function %25 + %33 = OpConstant %6 3 + %34 = OpConstant %6 -0.756802499 + %38 = OpConstant %13 2 + %44 = OpTypeVector %6 4 + %45 = OpTypePointer Function %44 + %50 = OpTypeInt 32 1 + %51 = OpTypeVector %50 2 + %52 = OpTypePointer Function %51 + %57 = OpTypePointer Function %50 + %59 = OpTypeVector %13 3 + %60 = OpTypePointer Function %59 + %65 = OpConstant %13 3 + %67 = OpTypePointer Function %13 + %70 = OpTypeVector %21 4 + %71 = OpTypePointer Function %70 + %73 = OpConstantTrue %21 + %74 = OpTypePointer Function %21 + %86 = OpTypeVector %13 2 + %87 = OpTypePointer Function %86 + %93 = OpTypeVector %21 3 + %94 = OpTypePointer Function %93 + %102 = OpTypeVector %21 2 + %103 = OpTypePointer Function %102 + %111 = OpConstantFalse %21 + %114 = OpTypeVector %50 3 + %115 = OpTypePointer Function %114 + %117 = OpConstant %50 3 + %122 = OpTypeVector %50 4 + %123 = OpTypePointer Function %122 + %131 = OpTypeVector %13 4 + %132 = OpTypePointer Function %131 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %9 = OpVariable %8 Function + %27 = OpVariable %26 Function + %46 = OpVariable %45 Function + %53 = OpVariable %52 Function + %61 = OpVariable %60 Function + %72 = OpVariable %71 Function + %88 = OpVariable %87 Function + %95 = OpVariable %94 Function + %104 = OpVariable %103 Function + %116 = OpVariable %115 Function + %124 = OpVariable %123 Function + %133 = OpVariable %132 Function + OpStore %9 %12 + %206 = OpCompositeConstruct %86 %18 %38 + %16 = OpAccessChain %15 %9 %14 + %17 = OpLoad %6 %16 + %19 = OpAccessChain %15 %9 %18 + %20 = OpLoad %6 %19 + %22 = OpFOrdGreaterThan %21 %17 %20 + OpSelectionMerge %24 None + OpBranchConditional %22 %23 %101 + %23 = OpLabel + %28 = OpAccessChain %15 %9 %14 + %29 = OpLoad %6 %28 + %30 = OpAccessChain %15 %9 %18 + %31 = OpLoad %6 %30 + %32 = OpFAdd %6 %29 %31 + %201 = OpCompositeConstruct %25 %12 %32 + %35 = OpCompositeConstruct %25 %32 %33 %34 + OpStore %27 %35 + %36 = OpAccessChain %15 %27 %14 + %37 = OpLoad %6 %36 + %39 = OpAccessChain %15 %27 %38 + %40 = OpLoad %6 %39 + %41 = OpFOrdLessThan %21 %37 %40 + OpSelectionMerge %43 None + OpBranchConditional %41 %42 %69 + %42 = OpLabel + %47 = OpAccessChain %15 %9 %18 + %48 = OpLoad %6 %47 + %49 = OpAccessChain %15 %46 %14 + OpStore %49 %48 + %54 = OpAccessChain %15 %27 %38 + %55 = OpLoad %6 %54 + %56 = OpConvertFToS %50 %55 + %58 = OpAccessChain %57 %53 %14 + OpStore %58 %56 + %62 = OpAccessChain %15 %46 %14 + %63 = OpLoad %6 %62 + %64 = OpConvertFToU %13 %63 + %205 = OpCompositeConstruct %122 %56 %117 %117 %117 + %66 = OpIAdd %13 %64 %65 + %204 = OpCompositeConstruct %114 %56 %117 %56 + %68 = OpAccessChain %67 %61 %14 + OpStore %68 %66 + OpBranch %43 + %69 = OpLabel + %202 = OpCompositeConstruct %44 %32 %32 %10 %11 + %209 = OpCompositeConstruct %102 %111 %41 + %75 = OpAccessChain %74 %72 %14 + OpStore %75 %73 + %76 = OpAccessChain %74 %72 %14 + %77 = OpLoad %21 %76 + %78 = OpLogicalNot %21 %77 + %79 = OpAccessChain %74 %72 %18 + OpStore %79 %78 + %80 = OpAccessChain %74 %72 %14 + %81 = OpLoad %21 %80 + %82 = OpAccessChain %74 %72 %18 + %83 = OpLoad %21 %82 + %84 = OpLogicalAnd %21 %81 %83 + %85 = OpAccessChain %74 %72 %38 + OpStore %85 %84 + %89 = OpAccessChain %67 %88 %14 + %90 = OpLoad %13 %89 + %91 = OpINotEqual %21 %90 %14 + %92 = OpAccessChain %74 %72 %65 + OpStore %92 %91 + OpBranch %43 + %43 = OpLabel + %96 = OpLoad %70 %72 + %97 = OpCompositeExtract %21 %96 0 + %98 = OpCompositeExtract %21 %96 1 + %99 = OpCompositeExtract %21 %96 2 + %100 = OpCompositeConstruct %93 %97 %98 %99 + %200 = OpCompositeConstruct %7 %17 %11 + OpStore %95 %100 + OpBranch %24 + %101 = OpLabel + %105 = OpAccessChain %67 %88 %14 + %106 = OpLoad %13 %105 + %107 = OpINotEqual %21 %106 %14 + %108 = OpCompositeConstruct %102 %107 %107 + %210 = OpCompositeConstruct %93 %108 %73 + OpStore %104 %108 + %211 = OpCompositeConstruct %70 %108 %108 + OpBranch %24 + %24 = OpLabel + %109 = OpAccessChain %74 %104 %18 + %110 = OpLoad %21 %109 + %112 = OpLogicalOr %21 %110 %111 + %113 = OpAccessChain %74 %104 %14 + OpStore %113 %112 + %118 = OpAccessChain %57 %116 %14 + OpStore %118 %117 + %119 = OpAccessChain %57 %116 %14 + %120 = OpLoad %50 %119 + %121 = OpAccessChain %57 %53 %18 + OpStore %121 %120 + %125 = OpAccessChain %57 %116 %14 + %126 = OpLoad %50 %125 + %127 = OpAccessChain %57 %53 %18 + %203 = OpCompositeConstruct %51 %126 %120 + %128 = OpLoad %50 %127 + %129 = OpIAdd %50 %126 %128 + %130 = OpAccessChain %57 %124 %65 + OpStore %130 %129 + %134 = OpAccessChain %57 %116 %14 + %135 = OpLoad %50 %134 + %136 = OpBitcast %13 %135 + %208 = OpCompositeConstruct %131 %14 %18 %136 %136 + %137 = OpAccessChain %67 %133 %14 + OpStore %137 %136 + %207 = OpCompositeConstruct %59 %14 %18 %136 + OpReturn + OpFunctionEnd + )"; + + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +} // namespace +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/test/fuzz/transformation_composite_extract_test.cpp b/third_party/spirv-tools/test/fuzz/transformation_composite_extract_test.cpp new file mode 100644 index 0000000000..5cc211513a --- /dev/null +++ b/third_party/spirv-tools/test/fuzz/transformation_composite_extract_test.cpp @@ -0,0 +1,398 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_composite_extract.h" +#include "source/fuzz/instruction_descriptor.h" +#include "test/fuzz/fuzz_test_util.h" + +namespace spvtools { +namespace fuzz { +namespace { + +TEST(TransformationCompositeExtractTest, BasicTest) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %8 "a" + OpName %10 "b" + OpName %17 "FunnyPoint" + OpMemberName %17 0 "x" + OpMemberName %17 1 "y" + OpMemberName %17 2 "z" + OpName %19 "p" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %12 = OpTypeBool + %16 = OpTypeFloat 32 + %17 = OpTypeStruct %16 %16 %6 + %81 = OpTypeStruct %17 %16 + %18 = OpTypePointer Function %17 + %20 = OpConstant %6 0 + %23 = OpTypePointer Function %16 + %26 = OpConstant %6 1 + %30 = OpConstant %6 2 + %80 = OpUndef %16 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %10 = OpVariable %7 Function + %19 = OpVariable %18 Function + %9 = OpLoad %6 %8 + %11 = OpLoad %6 %10 + %100 = OpCompositeConstruct %17 %80 %80 %26 + %104 = OpCompositeConstruct %81 %100 %80 + %13 = OpIEqual %12 %9 %11 + OpSelectionMerge %15 None + OpBranchConditional %13 %14 %25 + %14 = OpLabel + %21 = OpLoad %6 %8 + %22 = OpConvertSToF %16 %21 + %101 = OpCompositeConstruct %17 %22 %80 %30 + %24 = OpAccessChain %23 %19 %20 + OpStore %24 %22 + OpBranch %15 + %25 = OpLabel + %27 = OpLoad %6 %10 + %28 = OpConvertSToF %16 %27 + %102 = OpCompositeConstruct %17 %80 %28 %27 + %29 = OpAccessChain %23 %19 %26 + OpStore %29 %28 + OpBranch %15 + %15 = OpLabel + %31 = OpAccessChain %23 %19 %20 + %32 = OpLoad %16 %31 + %33 = OpAccessChain %23 %19 %26 + %34 = OpLoad %16 %33 + %103 = OpCompositeConstruct %17 %34 %32 %9 + %35 = OpFAdd %16 %32 %34 + %36 = OpConvertFToS %6 %35 + %37 = OpAccessChain %7 %19 %30 + OpStore %37 %36 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + // Instruction does not exist. + ASSERT_FALSE(TransformationCompositeExtract( + MakeInstructionDescriptor(36, SpvOpIAdd, 0), 200, 101, {0}) + .IsApplicable(context.get(), fact_manager)); + + // Id for composite is not a composite. + ASSERT_FALSE(TransformationCompositeExtract( + MakeInstructionDescriptor(36, SpvOpIAdd, 0), 200, 27, {}) + .IsApplicable(context.get(), fact_manager)); + + // Composite does not dominate instruction being inserted before. + ASSERT_FALSE( + TransformationCompositeExtract( + MakeInstructionDescriptor(37, SpvOpAccessChain, 0), 200, 101, {0}) + .IsApplicable(context.get(), fact_manager)); + + // Too many indices for extraction from struct composite. + ASSERT_FALSE( + TransformationCompositeExtract( + MakeInstructionDescriptor(24, SpvOpAccessChain, 0), 200, 101, {0, 0}) + .IsApplicable(context.get(), fact_manager)); + + // Too many indices for extraction from struct composite. + ASSERT_FALSE( + TransformationCompositeExtract( + MakeInstructionDescriptor(13, SpvOpIEqual, 0), 200, 104, {0, 0, 0}) + .IsApplicable(context.get(), fact_manager)); + + // Out of bounds index for extraction from struct composite. + ASSERT_FALSE( + TransformationCompositeExtract( + MakeInstructionDescriptor(13, SpvOpIEqual, 0), 200, 104, {0, 3}) + .IsApplicable(context.get(), fact_manager)); + + // Result id already used. + ASSERT_FALSE(TransformationCompositeExtract( + MakeInstructionDescriptor(35, SpvOpFAdd, 0), 80, 103, {0}) + .IsApplicable(context.get(), fact_manager)); + + TransformationCompositeExtract transformation_1( + MakeInstructionDescriptor(36, SpvOpConvertFToS, 0), 201, 100, {2}); + ASSERT_TRUE(transformation_1.IsApplicable(context.get(), fact_manager)); + transformation_1.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + TransformationCompositeExtract transformation_2( + MakeInstructionDescriptor(37, SpvOpAccessChain, 0), 202, 104, {0, 2}); + ASSERT_TRUE(transformation_2.IsApplicable(context.get(), fact_manager)); + transformation_2.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + TransformationCompositeExtract transformation_3( + MakeInstructionDescriptor(29, SpvOpAccessChain, 0), 203, 104, {0}); + ASSERT_TRUE(transformation_3.IsApplicable(context.get(), fact_manager)); + transformation_3.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + TransformationCompositeExtract transformation_4( + MakeInstructionDescriptor(24, SpvOpStore, 0), 204, 101, {0}); + ASSERT_TRUE(transformation_4.IsApplicable(context.get(), fact_manager)); + transformation_4.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + TransformationCompositeExtract transformation_5( + MakeInstructionDescriptor(29, SpvOpBranch, 0), 205, 102, {2}); + ASSERT_TRUE(transformation_5.IsApplicable(context.get(), fact_manager)); + transformation_5.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + TransformationCompositeExtract transformation_6( + MakeInstructionDescriptor(37, SpvOpReturn, 0), 206, 103, {1}); + ASSERT_TRUE(transformation_6.IsApplicable(context.get(), fact_manager)); + transformation_6.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(201, {}), + MakeDataDescriptor(100, {2}), + context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(202, {}), + MakeDataDescriptor(104, {0, 2}), + context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(203, {}), + MakeDataDescriptor(104, {0}), + context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(204, {}), + MakeDataDescriptor(101, {0}), + context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(205, {}), + MakeDataDescriptor(102, {2}), + context.get())); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(206, {}), + MakeDataDescriptor(103, {1}), + context.get())); + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %8 "a" + OpName %10 "b" + OpName %17 "FunnyPoint" + OpMemberName %17 0 "x" + OpMemberName %17 1 "y" + OpMemberName %17 2 "z" + OpName %19 "p" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %12 = OpTypeBool + %16 = OpTypeFloat 32 + %17 = OpTypeStruct %16 %16 %6 + %81 = OpTypeStruct %17 %16 + %18 = OpTypePointer Function %17 + %20 = OpConstant %6 0 + %23 = OpTypePointer Function %16 + %26 = OpConstant %6 1 + %30 = OpConstant %6 2 + %80 = OpUndef %16 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %10 = OpVariable %7 Function + %19 = OpVariable %18 Function + %9 = OpLoad %6 %8 + %11 = OpLoad %6 %10 + %100 = OpCompositeConstruct %17 %80 %80 %26 + %104 = OpCompositeConstruct %81 %100 %80 + %13 = OpIEqual %12 %9 %11 + OpSelectionMerge %15 None + OpBranchConditional %13 %14 %25 + %14 = OpLabel + %21 = OpLoad %6 %8 + %22 = OpConvertSToF %16 %21 + %101 = OpCompositeConstruct %17 %22 %80 %30 + %24 = OpAccessChain %23 %19 %20 + %204 = OpCompositeExtract %16 %101 0 + OpStore %24 %22 + OpBranch %15 + %25 = OpLabel + %27 = OpLoad %6 %10 + %28 = OpConvertSToF %16 %27 + %102 = OpCompositeConstruct %17 %80 %28 %27 + %203 = OpCompositeExtract %17 %104 0 + %29 = OpAccessChain %23 %19 %26 + OpStore %29 %28 + %205 = OpCompositeExtract %6 %102 2 + OpBranch %15 + %15 = OpLabel + %31 = OpAccessChain %23 %19 %20 + %32 = OpLoad %16 %31 + %33 = OpAccessChain %23 %19 %26 + %34 = OpLoad %16 %33 + %103 = OpCompositeConstruct %17 %34 %32 %9 + %35 = OpFAdd %16 %32 %34 + %201 = OpCompositeExtract %6 %100 2 + %36 = OpConvertFToS %6 %35 + %202 = OpCompositeExtract %6 %104 0 2 + %37 = OpAccessChain %7 %19 %30 + OpStore %37 %36 + %206 = OpCompositeExtract %16 %103 1 + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +TEST(TransformationCompositeExtractTest, IllegalInsertionPoints) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" %51 %27 + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %25 "buf" + OpMemberName %25 0 "value" + OpName %27 "" + OpName %51 "color" + OpMemberDecorate %25 0 Offset 0 + OpDecorate %25 Block + OpDecorate %27 DescriptorSet 0 + OpDecorate %27 Binding 0 + OpDecorate %51 Location 0 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypeVector %6 4 + %10 = OpConstant %6 0.300000012 + %11 = OpConstant %6 0.400000006 + %12 = OpConstant %6 0.5 + %13 = OpConstant %6 1 + %14 = OpConstantComposite %7 %10 %11 %12 %13 + %15 = OpTypeInt 32 1 + %18 = OpConstant %15 0 + %25 = OpTypeStruct %6 + %26 = OpTypePointer Uniform %25 + %27 = OpVariable %26 Uniform + %28 = OpTypePointer Uniform %6 + %32 = OpTypeBool + %103 = OpConstantTrue %32 + %34 = OpConstant %6 0.100000001 + %48 = OpConstant %15 1 + %50 = OpTypePointer Output %7 + %51 = OpVariable %50 Output + %100 = OpTypePointer Function %6 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %101 = OpVariable %100 Function + %102 = OpVariable %100 Function + OpBranch %19 + %19 = OpLabel + %60 = OpPhi %7 %14 %5 %58 %20 + %59 = OpPhi %15 %18 %5 %49 %20 + %29 = OpAccessChain %28 %27 %18 + %30 = OpLoad %6 %29 + %31 = OpConvertFToS %15 %30 + %33 = OpSLessThan %32 %59 %31 + OpLoopMerge %21 %20 None + OpBranchConditional %33 %20 %21 + %20 = OpLabel + %39 = OpCompositeExtract %6 %60 0 + %40 = OpFAdd %6 %39 %34 + %55 = OpCompositeInsert %7 %40 %60 0 + %44 = OpCompositeExtract %6 %60 1 + %45 = OpFSub %6 %44 %34 + %58 = OpCompositeInsert %7 %45 %55 1 + %49 = OpIAdd %15 %59 %48 + OpBranch %19 + %21 = OpLabel + OpStore %51 %60 + OpSelectionMerge %105 None + OpBranchConditional %103 %104 %105 + %104 = OpLabel + OpBranch %105 + %105 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + // Cannot insert before the OpVariables of a function. + ASSERT_FALSE( + TransformationCompositeExtract( + MakeInstructionDescriptor(101, SpvOpVariable, 0), 200, 14, {0}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE( + TransformationCompositeExtract( + MakeInstructionDescriptor(101, SpvOpVariable, 1), 200, 14, {1}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE( + TransformationCompositeExtract( + MakeInstructionDescriptor(102, SpvOpVariable, 0), 200, 14, {1}) + .IsApplicable(context.get(), fact_manager)); + // OK to insert right after the OpVariables. + ASSERT_FALSE(TransformationCompositeExtract( + MakeInstructionDescriptor(102, SpvOpBranch, 1), 200, 14, {1}) + .IsApplicable(context.get(), fact_manager)); + + // Cannot insert before the OpPhis of a block. + ASSERT_FALSE(TransformationCompositeExtract( + MakeInstructionDescriptor(60, SpvOpPhi, 0), 200, 14, {2}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(TransformationCompositeExtract( + MakeInstructionDescriptor(59, SpvOpPhi, 0), 200, 14, {3}) + .IsApplicable(context.get(), fact_manager)); + // OK to insert after the OpPhis. + ASSERT_TRUE( + TransformationCompositeExtract( + MakeInstructionDescriptor(59, SpvOpAccessChain, 0), 200, 14, {3}) + .IsApplicable(context.get(), fact_manager)); + + // Cannot insert before OpLoopMerge + ASSERT_FALSE(TransformationCompositeExtract( + MakeInstructionDescriptor(33, SpvOpBranchConditional, 0), + 200, 14, {3}) + .IsApplicable(context.get(), fact_manager)); + + // Cannot insert before OpSelectionMerge + ASSERT_FALSE(TransformationCompositeExtract( + MakeInstructionDescriptor(21, SpvOpBranchConditional, 0), + 200, 14, {2}) + .IsApplicable(context.get(), fact_manager)); +} + +} // namespace +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/test/fuzz/transformation_copy_object_test.cpp b/third_party/spirv-tools/test/fuzz/transformation_copy_object_test.cpp new file mode 100644 index 0000000000..a33f58de3e --- /dev/null +++ b/third_party/spirv-tools/test/fuzz/transformation_copy_object_test.cpp @@ -0,0 +1,631 @@ +// Copyright (c) 2019 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 +#include +#include + +#include "source/fuzz/data_descriptor.h" +#include "source/fuzz/instruction_descriptor.h" +#include "source/fuzz/transformation_copy_object.h" +#include "test/fuzz/fuzz_test_util.h" + +namespace spvtools { +namespace fuzz { +namespace { + +TEST(TransformationCopyObjectTest, CopyBooleanConstants) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %6 = OpTypeBool + %7 = OpConstantTrue %6 + %8 = OpConstantFalse %6 + %3 = OpTypeFunction %2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + ASSERT_EQ(0, + fact_manager.GetIdsForWhichSynonymsAreKnown(context.get()).size()); + + { + TransformationCopyObject copy_true( + 7, MakeInstructionDescriptor(5, SpvOpReturn, 0), 100); + ASSERT_TRUE(copy_true.IsApplicable(context.get(), fact_manager)); + copy_true.Apply(context.get(), &fact_manager); + + std::vector ids_for_which_synonyms_are_known = + fact_manager.GetIdsForWhichSynonymsAreKnown(context.get()); + ASSERT_EQ(2, ids_for_which_synonyms_are_known.size()); + ASSERT_TRUE(std::find(ids_for_which_synonyms_are_known.begin(), + ids_for_which_synonyms_are_known.end(), + 7) != ids_for_which_synonyms_are_known.end()); + ASSERT_EQ(2, fact_manager.GetSynonymsForId(7, context.get()).size()); + protobufs::DataDescriptor descriptor_100 = MakeDataDescriptor(100, {}); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(7, {}), + descriptor_100, context.get())); + } + + { + TransformationCopyObject copy_false( + 8, MakeInstructionDescriptor(100, SpvOpReturn, 0), 101); + ASSERT_TRUE(copy_false.IsApplicable(context.get(), fact_manager)); + copy_false.Apply(context.get(), &fact_manager); + std::vector ids_for_which_synonyms_are_known = + fact_manager.GetIdsForWhichSynonymsAreKnown(context.get()); + ASSERT_EQ(4, ids_for_which_synonyms_are_known.size()); + ASSERT_TRUE(std::find(ids_for_which_synonyms_are_known.begin(), + ids_for_which_synonyms_are_known.end(), + 8) != ids_for_which_synonyms_are_known.end()); + ASSERT_EQ(2, fact_manager.GetSynonymsForId(8, context.get()).size()); + protobufs::DataDescriptor descriptor_101 = MakeDataDescriptor(101, {}); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(8, {}), + descriptor_101, context.get())); + } + + { + TransformationCopyObject copy_false_again( + 101, MakeInstructionDescriptor(5, SpvOpReturn, 0), 102); + ASSERT_TRUE(copy_false_again.IsApplicable(context.get(), fact_manager)); + copy_false_again.Apply(context.get(), &fact_manager); + std::vector ids_for_which_synonyms_are_known = + fact_manager.GetIdsForWhichSynonymsAreKnown(context.get()); + ASSERT_EQ(5, ids_for_which_synonyms_are_known.size()); + ASSERT_TRUE(std::find(ids_for_which_synonyms_are_known.begin(), + ids_for_which_synonyms_are_known.end(), + 101) != ids_for_which_synonyms_are_known.end()); + ASSERT_EQ(3, fact_manager.GetSynonymsForId(101, context.get()).size()); + protobufs::DataDescriptor descriptor_102 = MakeDataDescriptor(102, {}); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(101, {}), + descriptor_102, context.get())); + } + + { + TransformationCopyObject copy_true_again( + 7, MakeInstructionDescriptor(102, SpvOpReturn, 0), 103); + ASSERT_TRUE(copy_true_again.IsApplicable(context.get(), fact_manager)); + copy_true_again.Apply(context.get(), &fact_manager); + std::vector ids_for_which_synonyms_are_known = + fact_manager.GetIdsForWhichSynonymsAreKnown(context.get()); + ASSERT_EQ(6, ids_for_which_synonyms_are_known.size()); + ASSERT_TRUE(std::find(ids_for_which_synonyms_are_known.begin(), + ids_for_which_synonyms_are_known.end(), + 7) != ids_for_which_synonyms_are_known.end()); + ASSERT_EQ(3, fact_manager.GetSynonymsForId(7, context.get()).size()); + protobufs::DataDescriptor descriptor_103 = MakeDataDescriptor(103, {}); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(7, {}), + descriptor_103, context.get())); + } + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %6 = OpTypeBool + %7 = OpConstantTrue %6 + %8 = OpConstantFalse %6 + %3 = OpTypeFunction %2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %100 = OpCopyObject %6 %7 + %101 = OpCopyObject %6 %8 + %102 = OpCopyObject %6 %101 + %103 = OpCopyObject %6 %7 + OpReturn + OpFunctionEnd + )"; + + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +TEST(TransformationCopyObjectTest, CheckIllegalCases) { + // The following SPIR-V comes from this GLSL, pushed through spirv-opt + // and then doctored a bit. + // + // #version 310 es + // + // precision highp float; + // + // struct S { + // int a; + // float b; + // }; + // + // layout(set = 0, binding = 2) uniform block { + // S s; + // lowp float f; + // int ii; + // } ubuf; + // + // layout(location = 0) out vec4 color; + // + // void main() { + // float c = 0.0; + // lowp float d = 0.0; + // S localS = ubuf.s; + // for (int i = 0; i < ubuf.s.a; i++) { + // switch (ubuf.ii) { + // case 0: + // c += 0.1; + // d += 0.2; + // case 1: + // c += 0.1; + // if (c > d) { + // d += 0.2; + // } else { + // d += c; + // } + // break; + // default: + // i += 1; + // localS.b += d; + // } + // } + // color = vec4(c, d, localS.b, 1.0); + // } + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" %80 + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %12 "S" + OpMemberName %12 0 "a" + OpMemberName %12 1 "b" + OpName %15 "S" + OpMemberName %15 0 "a" + OpMemberName %15 1 "b" + OpName %16 "block" + OpMemberName %16 0 "s" + OpMemberName %16 1 "f" + OpMemberName %16 2 "ii" + OpName %18 "ubuf" + OpName %80 "color" + OpMemberDecorate %12 0 RelaxedPrecision + OpMemberDecorate %15 0 RelaxedPrecision + OpMemberDecorate %15 0 Offset 0 + OpMemberDecorate %15 1 Offset 4 + OpMemberDecorate %16 0 Offset 0 + OpMemberDecorate %16 1 RelaxedPrecision + OpMemberDecorate %16 1 Offset 16 + OpMemberDecorate %16 2 RelaxedPrecision + OpMemberDecorate %16 2 Offset 20 + OpDecorate %16 Block + OpDecorate %18 DescriptorSet 0 + OpDecorate %18 Binding 2 + OpDecorate %38 RelaxedPrecision + OpDecorate %43 RelaxedPrecision + OpDecorate %53 RelaxedPrecision + OpDecorate %62 RelaxedPrecision + OpDecorate %69 RelaxedPrecision + OpDecorate %77 RelaxedPrecision + OpDecorate %80 Location 0 + OpDecorate %101 RelaxedPrecision + OpDecorate %102 RelaxedPrecision + OpDecorate %96 RelaxedPrecision + OpDecorate %108 RelaxedPrecision + OpDecorate %107 RelaxedPrecision + OpDecorate %98 RelaxedPrecision + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %9 = OpConstant %6 0 + %11 = OpTypeInt 32 1 + %12 = OpTypeStruct %11 %6 + %15 = OpTypeStruct %11 %6 + %16 = OpTypeStruct %15 %6 %11 + %17 = OpTypePointer Uniform %16 + %18 = OpVariable %17 Uniform + %19 = OpConstant %11 0 + %20 = OpTypePointer Uniform %15 + %27 = OpConstant %11 1 + %36 = OpTypePointer Uniform %11 + %39 = OpTypeBool + %41 = OpConstant %11 2 + %48 = OpConstant %6 0.100000001 + %51 = OpConstant %6 0.200000003 + %78 = OpTypeVector %6 4 + %79 = OpTypePointer Output %78 + %80 = OpVariable %79 Output + %85 = OpConstant %6 1 + %95 = OpUndef %12 + %112 = OpTypePointer Uniform %6 + %113 = OpTypeInt 32 0 + %114 = OpConstant %113 1 + %179 = OpTypePointer Function %39 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %180 = OpVariable %179 Function + %181 = OpVariable %179 Function + %182 = OpVariable %179 Function + %21 = OpAccessChain %20 %18 %19 + %115 = OpAccessChain %112 %21 %114 + %116 = OpLoad %6 %115 + %90 = OpCompositeInsert %12 %116 %95 1 + OpBranch %30 + %30 = OpLabel + %99 = OpPhi %12 %90 %5 %109 %47 + %98 = OpPhi %6 %9 %5 %107 %47 + %97 = OpPhi %6 %9 %5 %105 %47 + %96 = OpPhi %11 %19 %5 %77 %47 + %37 = OpAccessChain %36 %18 %19 %19 + %38 = OpLoad %11 %37 + %40 = OpSLessThan %39 %96 %38 + OpLoopMerge %32 %47 None + OpBranchConditional %40 %31 %32 + %31 = OpLabel + %42 = OpAccessChain %36 %18 %41 + %43 = OpLoad %11 %42 + OpSelectionMerge %45 None + OpSwitch %43 %46 0 %44 1 %45 + %46 = OpLabel + %69 = OpIAdd %11 %96 %27 + %72 = OpCompositeExtract %6 %99 1 + %73 = OpFAdd %6 %72 %98 + %93 = OpCompositeInsert %12 %73 %99 1 + OpBranch %47 + %44 = OpLabel + %50 = OpFAdd %6 %97 %48 + %53 = OpFAdd %6 %98 %51 + OpBranch %45 + %45 = OpLabel + %101 = OpPhi %6 %98 %31 %53 %44 + %100 = OpPhi %6 %97 %31 %50 %44 + %55 = OpFAdd %6 %100 %48 + %58 = OpFOrdGreaterThan %39 %55 %101 + OpSelectionMerge %60 None + OpBranchConditional %58 %59 %63 + %59 = OpLabel + %62 = OpFAdd %6 %101 %51 + OpBranch %60 + %63 = OpLabel + %66 = OpFAdd %6 %101 %55 + OpBranch %60 + %60 = OpLabel + %108 = OpPhi %6 %62 %59 %66 %63 + OpBranch %47 + %47 = OpLabel + %109 = OpPhi %12 %93 %46 %99 %60 + %107 = OpPhi %6 %98 %46 %108 %60 + %105 = OpPhi %6 %97 %46 %55 %60 + %102 = OpPhi %11 %69 %46 %96 %60 + %77 = OpIAdd %11 %102 %27 + OpBranch %30 + %32 = OpLabel + %84 = OpCompositeExtract %6 %99 1 + %86 = OpCompositeConstruct %78 %97 %98 %84 %85 + OpStore %80 %86 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + // Inapplicable because %18 is decorated. + ASSERT_FALSE(TransformationCopyObject( + 18, MakeInstructionDescriptor(21, SpvOpAccessChain, 0), 200) + .IsApplicable(context.get(), fact_manager)); + + // Inapplicable because %77 is decorated. + ASSERT_FALSE(TransformationCopyObject( + 77, MakeInstructionDescriptor(77, SpvOpBranch, 0), 200) + .IsApplicable(context.get(), fact_manager)); + + // Inapplicable because %80 is decorated. + ASSERT_FALSE(TransformationCopyObject( + 80, MakeInstructionDescriptor(77, SpvOpIAdd, 0), 200) + .IsApplicable(context.get(), fact_manager)); + + // Inapplicable because %84 is not available at the requested point + ASSERT_FALSE( + TransformationCopyObject( + 84, MakeInstructionDescriptor(32, SpvOpCompositeExtract, 0), 200) + .IsApplicable(context.get(), fact_manager)); + + // Fine because %84 is available at the requested point + ASSERT_TRUE( + TransformationCopyObject( + 84, MakeInstructionDescriptor(32, SpvOpCompositeConstruct, 0), 200) + .IsApplicable(context.get(), fact_manager)); + + // Inapplicable because id %9 is already in use + ASSERT_FALSE( + TransformationCopyObject( + 84, MakeInstructionDescriptor(32, SpvOpCompositeConstruct, 0), 9) + .IsApplicable(context.get(), fact_manager)); + + // Inapplicable because the requested point does not exist + ASSERT_FALSE(TransformationCopyObject( + 84, MakeInstructionDescriptor(86, SpvOpReturn, 2), 200) + .IsApplicable(context.get(), fact_manager)); + + // Inapplicable because %9 is not in a function + ASSERT_FALSE(TransformationCopyObject( + 9, MakeInstructionDescriptor(9, SpvOpTypeInt, 0), 200) + .IsApplicable(context.get(), fact_manager)); + + // Inapplicable because the insert point is right before, or inside, a chunk + // of OpPhis + ASSERT_FALSE(TransformationCopyObject( + 9, MakeInstructionDescriptor(30, SpvOpPhi, 0), 200) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(TransformationCopyObject( + 9, MakeInstructionDescriptor(99, SpvOpPhi, 1), 200) + .IsApplicable(context.get(), fact_manager)); + + // OK, because the insert point is just after a chunk of OpPhis. + ASSERT_TRUE(TransformationCopyObject( + 9, MakeInstructionDescriptor(96, SpvOpAccessChain, 0), 200) + .IsApplicable(context.get(), fact_manager)); + + // Inapplicable because the insert point is right after an OpSelectionMerge + ASSERT_FALSE( + TransformationCopyObject( + 9, MakeInstructionDescriptor(58, SpvOpBranchConditional, 0), 200) + .IsApplicable(context.get(), fact_manager)); + + // OK, because the insert point is right before the OpSelectionMerge + ASSERT_TRUE(TransformationCopyObject( + 9, MakeInstructionDescriptor(58, SpvOpSelectionMerge, 0), 200) + .IsApplicable(context.get(), fact_manager)); + + // Inapplicable because the insert point is right after an OpSelectionMerge + ASSERT_FALSE(TransformationCopyObject( + 9, MakeInstructionDescriptor(43, SpvOpSwitch, 0), 200) + .IsApplicable(context.get(), fact_manager)); + + // OK, because the insert point is right before the OpSelectionMerge + ASSERT_TRUE(TransformationCopyObject( + 9, MakeInstructionDescriptor(43, SpvOpSelectionMerge, 0), 200) + .IsApplicable(context.get(), fact_manager)); + + // Inapplicable because the insert point is right after an OpLoopMerge + ASSERT_FALSE( + TransformationCopyObject( + 9, MakeInstructionDescriptor(40, SpvOpBranchConditional, 0), 200) + .IsApplicable(context.get(), fact_manager)); + + // OK, because the insert point is right before the OpLoopMerge + ASSERT_TRUE(TransformationCopyObject( + 9, MakeInstructionDescriptor(40, SpvOpLoopMerge, 0), 200) + .IsApplicable(context.get(), fact_manager)); + + // Inapplicable because id %300 does not exist + ASSERT_FALSE(TransformationCopyObject( + 300, MakeInstructionDescriptor(40, SpvOpLoopMerge, 0), 200) + .IsApplicable(context.get(), fact_manager)); + + // Inapplicable because the following instruction is OpVariable + ASSERT_FALSE(TransformationCopyObject( + 9, MakeInstructionDescriptor(180, SpvOpVariable, 0), 200) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(TransformationCopyObject( + 9, MakeInstructionDescriptor(181, SpvOpVariable, 0), 200) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(TransformationCopyObject( + 9, MakeInstructionDescriptor(182, SpvOpVariable, 0), 200) + .IsApplicable(context.get(), fact_manager)); + + // OK, because this is just past the group of OpVariable instructions. + ASSERT_TRUE(TransformationCopyObject( + 9, MakeInstructionDescriptor(182, SpvOpAccessChain, 0), 200) + .IsApplicable(context.get(), fact_manager)); +} + +TEST(TransformationCopyObjectTest, MiscellaneousCopies) { + // The following SPIR-V comes from this GLSL: + // + // #version 310 es + // + // precision highp float; + // + // float g; + // + // vec4 h; + // + // void main() { + // int a; + // int b; + // b = int(g); + // h.x = float(a); + // } + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %8 "b" + OpName %11 "g" + OpName %16 "h" + OpName %17 "a" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpTypeFloat 32 + %10 = OpTypePointer Private %9 + %11 = OpVariable %10 Private + %14 = OpTypeVector %9 4 + %15 = OpTypePointer Private %14 + %16 = OpVariable %15 Private + %20 = OpTypeInt 32 0 + %21 = OpConstant %20 0 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %17 = OpVariable %7 Function + %12 = OpLoad %9 %11 + %13 = OpConvertFToS %6 %12 + OpStore %8 %13 + %18 = OpLoad %6 %17 + %19 = OpConvertSToF %9 %18 + %22 = OpAccessChain %10 %16 %21 + OpStore %22 %19 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + std::vector transformations = { + TransformationCopyObject(19, MakeInstructionDescriptor(22, SpvOpStore, 0), + 100), + TransformationCopyObject( + 22, MakeInstructionDescriptor(22, SpvOpCopyObject, 0), 101), + TransformationCopyObject( + 12, MakeInstructionDescriptor(22, SpvOpCopyObject, 0), 102), + TransformationCopyObject( + 11, MakeInstructionDescriptor(22, SpvOpCopyObject, 0), 103), + TransformationCopyObject( + 16, MakeInstructionDescriptor(22, SpvOpCopyObject, 0), 104), + TransformationCopyObject( + 8, MakeInstructionDescriptor(22, SpvOpCopyObject, 0), 105), + TransformationCopyObject( + 17, MakeInstructionDescriptor(22, SpvOpCopyObject, 0), 106)}; + + for (auto& transformation : transformations) { + ASSERT_TRUE(transformation.IsApplicable(context.get(), fact_manager)); + transformation.Apply(context.get(), &fact_manager); + } + + ASSERT_TRUE(IsValid(env, context.get())); + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %8 "b" + OpName %11 "g" + OpName %16 "h" + OpName %17 "a" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpTypeFloat 32 + %10 = OpTypePointer Private %9 + %11 = OpVariable %10 Private + %14 = OpTypeVector %9 4 + %15 = OpTypePointer Private %14 + %16 = OpVariable %15 Private + %20 = OpTypeInt 32 0 + %21 = OpConstant %20 0 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %17 = OpVariable %7 Function + %12 = OpLoad %9 %11 + %13 = OpConvertFToS %6 %12 + OpStore %8 %13 + %18 = OpLoad %6 %17 + %19 = OpConvertSToF %9 %18 + %22 = OpAccessChain %10 %16 %21 + %106 = OpCopyObject %7 %17 + %105 = OpCopyObject %7 %8 + %104 = OpCopyObject %15 %16 + %103 = OpCopyObject %10 %11 + %102 = OpCopyObject %9 %12 + %101 = OpCopyObject %10 %22 + %100 = OpCopyObject %9 %19 + OpStore %22 %19 + OpReturn + OpFunctionEnd + )"; + + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +TEST(TransformationCopyObjectTest, DoNotCopyNullOrUndefPointers) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %8 = OpConstantNull %7 + %9 = OpUndef %7 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + // Illegal to copy null. + ASSERT_FALSE(TransformationCopyObject( + 8, MakeInstructionDescriptor(5, SpvOpReturn, 0), 100) + .IsApplicable(context.get(), fact_manager)); + + // Illegal to copy an OpUndef of pointer type. + ASSERT_FALSE(TransformationCopyObject( + 9, MakeInstructionDescriptor(5, SpvOpReturn, 0), 100) + .IsApplicable(context.get(), fact_manager)); +} + +} // namespace +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/test/fuzz/transformation_merge_blocks_test.cpp b/third_party/spirv-tools/test/fuzz/transformation_merge_blocks_test.cpp new file mode 100644 index 0000000000..e2b4aa65a9 --- /dev/null +++ b/third_party/spirv-tools/test/fuzz/transformation_merge_blocks_test.cpp @@ -0,0 +1,675 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_merge_blocks.h" + +#include "test/fuzz/fuzz_test_util.h" + +namespace spvtools { +namespace fuzz { +namespace { + +TEST(TransformationMergeBlocksTest, BlockDoesNotExist) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpBranch %6 + %6 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + ASSERT_FALSE( + TransformationMergeBlocks(3).IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE( + TransformationMergeBlocks(7).IsApplicable(context.get(), fact_manager)); +} + +TEST(TransformationMergeBlocksTest, DoNotMergeFirstBlockHasMultipleSuccessors) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %7 = OpTypeBool + %8 = OpConstantTrue %7 + %3 = OpTypeFunction %2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpSelectionMerge %10 None + OpBranchConditional %8 %6 %9 + %6 = OpLabel + OpBranch %10 + %9 = OpLabel + OpBranch %10 + %10 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + ASSERT_FALSE( + TransformationMergeBlocks(6).IsApplicable(context.get(), fact_manager)); +} + +TEST(TransformationMergeBlocksTest, + DoNotMergeSecondBlockHasMultiplePredecessors) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %7 = OpTypeBool + %8 = OpConstantTrue %7 + %3 = OpTypeFunction %2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpSelectionMerge %10 None + OpBranchConditional %8 %6 %9 + %6 = OpLabel + OpBranch %10 + %9 = OpLabel + OpBranch %10 + %10 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + ASSERT_FALSE( + TransformationMergeBlocks(10).IsApplicable(context.get(), fact_manager)); +} + +TEST(TransformationMergeBlocksTest, MergeWhenSecondBlockIsSelectionMerge) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %7 = OpTypeBool + %8 = OpConstantTrue %7 + %3 = OpTypeFunction %2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpSelectionMerge %10 None + OpBranchConditional %8 %6 %9 + %6 = OpLabel + OpBranch %11 + %9 = OpLabel + OpBranch %11 + %11 = OpLabel + OpBranch %10 + %10 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + TransformationMergeBlocks transformation(10); + ASSERT_TRUE(transformation.IsApplicable(context.get(), fact_manager)); + transformation.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %7 = OpTypeBool + %8 = OpConstantTrue %7 + %3 = OpTypeFunction %2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpSelectionMerge %11 None + OpBranchConditional %8 %6 %9 + %6 = OpLabel + OpBranch %11 + %9 = OpLabel + OpBranch %11 + %11 = OpLabel + OpReturn + OpFunctionEnd + )"; + + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +TEST(TransformationMergeBlocksTest, MergeWhenSecondBlockIsLoopMerge) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %7 = OpTypeBool + %8 = OpConstantTrue %7 + %3 = OpTypeFunction %2 + %4 = OpFunction %2 None %3 + %12 = OpLabel + OpBranch %5 + %5 = OpLabel + OpLoopMerge %10 %11 None + OpBranch %6 + %6 = OpLabel + OpBranchConditional %8 %9 %11 + %9 = OpLabel + OpBranch %10 + %11 = OpLabel + OpBranch %5 + %10 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + TransformationMergeBlocks transformation(10); + ASSERT_TRUE(transformation.IsApplicable(context.get(), fact_manager)); + transformation.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %7 = OpTypeBool + %8 = OpConstantTrue %7 + %3 = OpTypeFunction %2 + %4 = OpFunction %2 None %3 + %12 = OpLabel + OpBranch %5 + %5 = OpLabel + OpLoopMerge %9 %11 None + OpBranch %6 + %6 = OpLabel + OpBranchConditional %8 %9 %11 + %9 = OpLabel + OpReturn + %11 = OpLabel + OpBranch %5 + OpFunctionEnd + )"; + + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +TEST(TransformationMergeBlocksTest, MergeWhenSecondBlockIsLoopContinue) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %7 = OpTypeBool + %8 = OpConstantTrue %7 + %3 = OpTypeFunction %2 + %4 = OpFunction %2 None %3 + %13 = OpLabel + OpBranch %5 + %5 = OpLabel + OpLoopMerge %10 %11 None + OpBranch %6 + %6 = OpLabel + OpSelectionMerge %9 None + OpBranchConditional %8 %9 %12 + %12 = OpLabel + OpBranch %11 + %11 = OpLabel + OpBranch %5 + %9 = OpLabel + OpBranch %10 + %10 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + TransformationMergeBlocks transformation(11); + ASSERT_TRUE(transformation.IsApplicable(context.get(), fact_manager)); + transformation.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %7 = OpTypeBool + %8 = OpConstantTrue %7 + %3 = OpTypeFunction %2 + %4 = OpFunction %2 None %3 + %13 = OpLabel + OpBranch %5 + %5 = OpLabel + OpLoopMerge %10 %12 None + OpBranch %6 + %6 = OpLabel + OpSelectionMerge %9 None + OpBranchConditional %8 %9 %12 + %12 = OpLabel + OpBranch %5 + %9 = OpLabel + OpBranch %10 + %10 = OpLabel + OpReturn + OpFunctionEnd + )"; + + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +TEST(TransformationMergeBlocksTest, MergeWhenSecondBlockStartsWithOpPhi) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %7 = OpTypeBool + %8 = OpUndef %7 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpBranch %6 + %6 = OpLabel + %9 = OpPhi %7 %8 %5 + %10 = OpCopyObject %7 %9 + OpBranch %11 + %11 = OpLabel + %12 = OpCopyObject %7 %9 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + TransformationMergeBlocks transformation(6); + ASSERT_TRUE(transformation.IsApplicable(context.get(), fact_manager)); + transformation.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %7 = OpTypeBool + %8 = OpUndef %7 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %10 = OpCopyObject %7 %8 + OpBranch %11 + %11 = OpLabel + %12 = OpCopyObject %7 %8 + OpReturn + OpFunctionEnd + )"; + + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +TEST(TransformationMergeBlocksTest, BasicMerge) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 2 + %11 = OpConstant %6 3 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %10 = OpVariable %7 Function + OpStore %8 %9 + OpBranch %100 + %100 = OpLabel + OpStore %10 %11 + %12 = OpLoad %6 %10 + %13 = OpLoad %6 %8 + OpBranch %101 + %101 = OpLabel + %14 = OpIAdd %6 %13 %12 + OpStore %8 %14 + %15 = OpLoad %6 %8 + OpBranch %102 + %102 = OpLabel + %16 = OpLoad %6 %10 + %17 = OpIMul %6 %16 %15 + OpBranch %103 + %103 = OpLabel + OpStore %10 %17 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + for (auto& transformation : + {TransformationMergeBlocks(100), TransformationMergeBlocks(101), + TransformationMergeBlocks(102), TransformationMergeBlocks(103)}) { + ASSERT_TRUE(transformation.IsApplicable(context.get(), fact_manager)); + transformation.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + } + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 2 + %11 = OpConstant %6 3 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %10 = OpVariable %7 Function + OpStore %8 %9 + OpStore %10 %11 + %12 = OpLoad %6 %10 + %13 = OpLoad %6 %8 + %14 = OpIAdd %6 %13 %12 + OpStore %8 %14 + %15 = OpLoad %6 %8 + %16 = OpLoad %6 %10 + %17 = OpIMul %6 %16 %15 + OpStore %10 %17 + OpReturn + OpFunctionEnd + )"; + + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +TEST(TransformationMergeBlocksTest, MergeWhenSecondBlockIsSelectionHeader) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 2 + %11 = OpConstant %6 3 + %50 = OpTypeBool + %51 = OpConstantTrue %50 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %10 = OpVariable %7 Function + OpStore %8 %9 + OpBranch %100 + %100 = OpLabel + OpStore %10 %11 + %12 = OpLoad %6 %10 + %13 = OpLoad %6 %8 + OpBranch %101 + %101 = OpLabel + OpSelectionMerge %103 None + OpBranchConditional %51 %102 %103 + %102 = OpLabel + %14 = OpIAdd %6 %13 %12 + OpStore %8 %14 + OpBranch %103 + %103 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + for (auto& transformation : + {TransformationMergeBlocks(101), TransformationMergeBlocks(100)}) { + ASSERT_TRUE(transformation.IsApplicable(context.get(), fact_manager)); + transformation.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + } + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 2 + %11 = OpConstant %6 3 + %50 = OpTypeBool + %51 = OpConstantTrue %50 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %10 = OpVariable %7 Function + OpStore %8 %9 + OpStore %10 %11 + %12 = OpLoad %6 %10 + %13 = OpLoad %6 %8 + OpSelectionMerge %103 None + OpBranchConditional %51 %102 %103 + %102 = OpLabel + %14 = OpIAdd %6 %13 %12 + OpStore %8 %14 + OpBranch %103 + %103 = OpLabel + OpReturn + OpFunctionEnd + )"; + + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +TEST(TransformationMergeBlocksTest, + MergeWhenFirstBlockIsLoopMergeFollowedByUnconditionalBranch) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 2 + %11 = OpConstant %6 3 + %50 = OpTypeBool + %51 = OpConstantTrue %50 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %10 = OpVariable %7 Function + OpStore %8 %9 + OpBranch %100 + %100 = OpLabel + OpLoopMerge %102 %103 None + OpBranch %101 + %101 = OpLabel + %200 = OpCopyObject %6 %9 + OpBranchConditional %51 %102 %103 + %103 = OpLabel + OpBranch %100 + %102 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + TransformationMergeBlocks transformation(101); + ASSERT_TRUE(transformation.IsApplicable(context.get(), fact_manager)); + transformation.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 2 + %11 = OpConstant %6 3 + %50 = OpTypeBool + %51 = OpConstantTrue %50 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %10 = OpVariable %7 Function + OpStore %8 %9 + OpBranch %100 + %100 = OpLabel + %200 = OpCopyObject %6 %9 + OpLoopMerge %102 %103 None + OpBranchConditional %51 %102 %103 + %103 = OpLabel + OpBranch %100 + %102 = OpLabel + OpReturn + OpFunctionEnd + )"; + + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +} // namespace +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/test/fuzz/transformation_move_block_down_test.cpp b/third_party/spirv-tools/test/fuzz/transformation_move_block_down_test.cpp new file mode 100644 index 0000000000..02761a2cf3 --- /dev/null +++ b/third_party/spirv-tools/test/fuzz/transformation_move_block_down_test.cpp @@ -0,0 +1,670 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_move_block_down.h" +#include "test/fuzz/fuzz_test_util.h" + +namespace spvtools { +namespace fuzz { +namespace { + +TEST(TransformationMoveBlockDownTest, NoMovePossible1) { + // Block 11 cannot be moved down as it dominates block 12. + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpDecorate %8 RelaxedPrecision + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 1 + %10 = OpConstant %6 2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + OpBranch %11 + %11 = OpLabel + OpStore %8 %9 + OpBranch %12 + %12 = OpLabel + OpStore %8 %10 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + + FactManager fact_manager; + + auto transformation = TransformationMoveBlockDown(11); + ASSERT_FALSE(transformation.IsApplicable(context.get(), fact_manager)); +} + +TEST(TransformationMoveBlockDownTest, NoMovePossible2) { + // Block 5 cannot be moved down as it is the entry block. + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpDecorate %8 RelaxedPrecision + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 1 + %10 = OpConstant %6 2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + OpStore %8 %9 + OpStore %8 %10 + OpReturn + %11 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + + FactManager fact_manager; + + auto transformation = TransformationMoveBlockDown(5); + ASSERT_FALSE(transformation.IsApplicable(context.get(), fact_manager)); +} + +TEST(TransformationMoveBlockDownTest, NoMovePossible3) { + // Block 100 does not exist, so cannot be moved down. + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpDecorate %8 RelaxedPrecision + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 1 + %10 = OpConstant %6 2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + OpBranch %11 + %11 = OpLabel + OpStore %8 %9 + OpBranch %12 + %12 = OpLabel + OpStore %8 %10 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + + FactManager fact_manager; + + auto transformation = TransformationMoveBlockDown(100); + ASSERT_FALSE(transformation.IsApplicable(context.get(), fact_manager)); +} + +TEST(TransformationMoveBlockDownTest, NoMovePossible4) { + // Block 12 is the last block in its function, so cannot be moved down. + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpDecorate %8 RelaxedPrecision + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 1 + %10 = OpConstant %6 2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + OpBranch %11 + %11 = OpLabel + OpStore %8 %9 + OpBranch %12 + %12 = OpLabel + OpStore %8 %10 + OpReturn + OpFunctionEnd + %13 = OpFunction %2 None %3 + %14 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + + FactManager fact_manager; + + auto transformation = TransformationMoveBlockDown(12); + ASSERT_FALSE(transformation.IsApplicable(context.get(), fact_manager)); +} + +TEST(TransformationMoveBlockDownTest, ManyMovesPossible) { + // The SPIR-V arising from this shader has lots of opportunities for moving + // blocks around. + // + // void main() { + // int x; + // int y; + // if (x < y) { + // x = 1; + // if (y == x) { + // x = 3; + // } else { + // x = 4; + // } + // } else { + // if (y < x) { + // x = 5; + // } else { + // x = 6; + // } + // } + // } + + std::string before_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %8 "x" + OpName %10 "y" + OpDecorate %8 RelaxedPrecision + OpDecorate %9 RelaxedPrecision + OpDecorate %10 RelaxedPrecision + OpDecorate %11 RelaxedPrecision + OpDecorate %17 RelaxedPrecision + OpDecorate %18 RelaxedPrecision + OpDecorate %26 RelaxedPrecision + OpDecorate %27 RelaxedPrecision + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %12 = OpTypeBool + %16 = OpConstant %6 1 + %22 = OpConstant %6 3 + %24 = OpConstant %6 4 + %31 = OpConstant %6 5 + %33 = OpConstant %6 6 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %10 = OpVariable %7 Function + %9 = OpLoad %6 %8 + %11 = OpLoad %6 %10 + %13 = OpSLessThan %12 %9 %11 + OpSelectionMerge %15 None + OpBranchConditional %13 %14 %25 + %14 = OpLabel + OpStore %8 %16 + %17 = OpLoad %6 %10 + %18 = OpLoad %6 %8 + %19 = OpIEqual %12 %17 %18 + OpSelectionMerge %21 None + OpBranchConditional %19 %20 %23 + %20 = OpLabel + OpStore %8 %22 + OpBranch %21 + %23 = OpLabel + OpStore %8 %24 + OpBranch %21 + %21 = OpLabel + OpBranch %15 + %25 = OpLabel + %26 = OpLoad %6 %10 + %27 = OpLoad %6 %8 + %28 = OpSLessThan %12 %26 %27 + OpSelectionMerge %30 None + OpBranchConditional %28 %29 %32 + %29 = OpLabel + OpStore %8 %31 + OpBranch %30 + %32 = OpLabel + OpStore %8 %33 + OpBranch %30 + %30 = OpLabel + OpBranch %15 + %15 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = + BuildModule(env, consumer, before_transformation, kFuzzAssembleOption); + + FactManager fact_manager; + + // The block ids are: 5 14 20 23 21 25 29 32 30 15 + // We make a transformation to move each of them down, plus a transformation + // to move a non-block, 27, down. + auto move_down_5 = TransformationMoveBlockDown(5); + auto move_down_14 = TransformationMoveBlockDown(14); + auto move_down_20 = TransformationMoveBlockDown(20); + auto move_down_23 = TransformationMoveBlockDown(23); + auto move_down_21 = TransformationMoveBlockDown(21); + auto move_down_25 = TransformationMoveBlockDown(25); + auto move_down_29 = TransformationMoveBlockDown(29); + auto move_down_32 = TransformationMoveBlockDown(32); + auto move_down_30 = TransformationMoveBlockDown(30); + auto move_down_15 = TransformationMoveBlockDown(15); + auto move_down_27 = TransformationMoveBlockDown(27); + + // Dominance is as follows: + // 5 dominates everything else + // 14 dominates 20, 23, 21 + // 20 dominates nothing + // 23 dominates nothing + // 21 dominates nothing + // 25 dominates 29, 32, 30 + // 29 dominates nothing + // 32 dominates nothing + // 30 dominates nothing + // 15 dominates nothing + + // Current ordering: 5 14 20 23 21 25 29 32 30 15 + ASSERT_FALSE(move_down_5.IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(move_down_14.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_20.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_23.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_21.IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(move_down_25.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_29.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_32.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_30.IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(move_down_15.IsApplicable(context.get(), fact_manager)); + + // Let's bubble 20 all the way down. + + move_down_20.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + // Current ordering: 5 14 23 20 21 25 29 32 30 15 + ASSERT_FALSE(move_down_5.IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(move_down_14.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_23.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_20.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_21.IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(move_down_25.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_29.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_32.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_30.IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(move_down_15.IsApplicable(context.get(), fact_manager)); + + move_down_20.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + // Current ordering: 5 14 23 21 20 25 29 32 30 15 + ASSERT_FALSE(move_down_5.IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(move_down_14.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_23.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_21.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_20.IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(move_down_25.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_29.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_32.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_30.IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(move_down_15.IsApplicable(context.get(), fact_manager)); + + move_down_20.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + // Current ordering: 5 14 23 21 25 20 29 32 30 15 + ASSERT_FALSE(move_down_5.IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(move_down_14.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_23.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_21.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_25.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_20.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_29.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_32.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_30.IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(move_down_15.IsApplicable(context.get(), fact_manager)); + + move_down_20.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + // Current ordering: 5 14 23 21 25 29 20 32 30 15 + ASSERT_FALSE(move_down_5.IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(move_down_14.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_23.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_21.IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(move_down_25.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_29.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_20.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_32.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_30.IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(move_down_15.IsApplicable(context.get(), fact_manager)); + + move_down_20.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + // Current ordering: 5 14 23 21 25 29 32 20 30 15 + ASSERT_FALSE(move_down_5.IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(move_down_14.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_23.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_21.IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(move_down_25.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_29.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_32.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_20.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_30.IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(move_down_15.IsApplicable(context.get(), fact_manager)); + + move_down_20.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + // Current ordering: 5 14 23 21 25 29 32 30 20 15 + ASSERT_FALSE(move_down_5.IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(move_down_14.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_23.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_21.IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(move_down_25.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_29.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_32.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_30.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_20.IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(move_down_15.IsApplicable(context.get(), fact_manager)); + + move_down_20.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + std::string after_bubbling_20_down = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %8 "x" + OpName %10 "y" + OpDecorate %8 RelaxedPrecision + OpDecorate %9 RelaxedPrecision + OpDecorate %10 RelaxedPrecision + OpDecorate %11 RelaxedPrecision + OpDecorate %17 RelaxedPrecision + OpDecorate %18 RelaxedPrecision + OpDecorate %26 RelaxedPrecision + OpDecorate %27 RelaxedPrecision + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %12 = OpTypeBool + %16 = OpConstant %6 1 + %22 = OpConstant %6 3 + %24 = OpConstant %6 4 + %31 = OpConstant %6 5 + %33 = OpConstant %6 6 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %10 = OpVariable %7 Function + %9 = OpLoad %6 %8 + %11 = OpLoad %6 %10 + %13 = OpSLessThan %12 %9 %11 + OpSelectionMerge %15 None + OpBranchConditional %13 %14 %25 + %14 = OpLabel + OpStore %8 %16 + %17 = OpLoad %6 %10 + %18 = OpLoad %6 %8 + %19 = OpIEqual %12 %17 %18 + OpSelectionMerge %21 None + OpBranchConditional %19 %20 %23 + %23 = OpLabel + OpStore %8 %24 + OpBranch %21 + %21 = OpLabel + OpBranch %15 + %25 = OpLabel + %26 = OpLoad %6 %10 + %27 = OpLoad %6 %8 + %28 = OpSLessThan %12 %26 %27 + OpSelectionMerge %30 None + OpBranchConditional %28 %29 %32 + %29 = OpLabel + OpStore %8 %31 + OpBranch %30 + %32 = OpLabel + OpStore %8 %33 + OpBranch %30 + %30 = OpLabel + OpBranch %15 + %15 = OpLabel + OpReturn + %20 = OpLabel + OpStore %8 %22 + OpBranch %21 + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_bubbling_20_down, context.get())); + + // Current ordering: 5 14 23 21 25 29 32 30 15 20 + ASSERT_FALSE(move_down_5.IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(move_down_14.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_23.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_21.IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(move_down_25.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_29.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_32.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_30.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_15.IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(move_down_20.IsApplicable(context.get(), fact_manager)); + + move_down_23.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + // Current ordering: 5 14 21 23 25 29 32 30 15 20 + ASSERT_FALSE(move_down_5.IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(move_down_14.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_21.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_23.IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(move_down_25.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_29.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_32.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_30.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_15.IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(move_down_20.IsApplicable(context.get(), fact_manager)); + + move_down_23.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + // Current ordering: 5 14 21 25 23 29 32 30 15 20 + ASSERT_FALSE(move_down_5.IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(move_down_14.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_21.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_25.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_23.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_29.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_32.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_30.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_15.IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(move_down_20.IsApplicable(context.get(), fact_manager)); + + move_down_21.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + // Current ordering: 5 14 25 21 23 29 32 30 15 20 + ASSERT_FALSE(move_down_5.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_14.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_21.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_25.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_23.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_29.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_32.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_30.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_15.IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(move_down_20.IsApplicable(context.get(), fact_manager)); + + move_down_14.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + std::string after_more_shuffling = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %8 "x" + OpName %10 "y" + OpDecorate %8 RelaxedPrecision + OpDecorate %9 RelaxedPrecision + OpDecorate %10 RelaxedPrecision + OpDecorate %11 RelaxedPrecision + OpDecorate %17 RelaxedPrecision + OpDecorate %18 RelaxedPrecision + OpDecorate %26 RelaxedPrecision + OpDecorate %27 RelaxedPrecision + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %12 = OpTypeBool + %16 = OpConstant %6 1 + %22 = OpConstant %6 3 + %24 = OpConstant %6 4 + %31 = OpConstant %6 5 + %33 = OpConstant %6 6 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %10 = OpVariable %7 Function + %9 = OpLoad %6 %8 + %11 = OpLoad %6 %10 + %13 = OpSLessThan %12 %9 %11 + OpSelectionMerge %15 None + OpBranchConditional %13 %14 %25 + %25 = OpLabel + %26 = OpLoad %6 %10 + %27 = OpLoad %6 %8 + %28 = OpSLessThan %12 %26 %27 + OpSelectionMerge %30 None + OpBranchConditional %28 %29 %32 + %14 = OpLabel + OpStore %8 %16 + %17 = OpLoad %6 %10 + %18 = OpLoad %6 %8 + %19 = OpIEqual %12 %17 %18 + OpSelectionMerge %21 None + OpBranchConditional %19 %20 %23 + %21 = OpLabel + OpBranch %15 + %23 = OpLabel + OpStore %8 %24 + OpBranch %21 + %29 = OpLabel + OpStore %8 %31 + OpBranch %30 + %32 = OpLabel + OpStore %8 %33 + OpBranch %30 + %30 = OpLabel + OpBranch %15 + %15 = OpLabel + OpReturn + %20 = OpLabel + OpStore %8 %22 + OpBranch %21 + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_more_shuffling, context.get())); + + // Final ordering: 5 25 14 21 23 29 32 30 15 20 + ASSERT_FALSE(move_down_5.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_25.IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(move_down_14.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_21.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_23.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_29.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_32.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_30.IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(move_down_15.IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(move_down_20.IsApplicable(context.get(), fact_manager)); +} + +TEST(TransformationMoveBlockDownTest, DoNotMoveUnreachable) { + // Block 6 is unreachable, so cannot be moved down. + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %10 = OpTypeInt 32 1 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + %6 = OpLabel + %7 = OpUndef %10 + OpBranch %8 + %8 = OpLabel + %9 = OpCopyObject %10 %7 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + auto transformation = TransformationMoveBlockDown(6); + ASSERT_FALSE(transformation.IsApplicable(context.get(), fact_manager)); +} + +} // namespace +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/test/fuzz/transformation_outline_function_test.cpp b/third_party/spirv-tools/test/fuzz/transformation_outline_function_test.cpp new file mode 100644 index 0000000000..7313538b09 --- /dev/null +++ b/third_party/spirv-tools/test/fuzz/transformation_outline_function_test.cpp @@ -0,0 +1,2789 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_outline_function.h" +#include "test/fuzz/fuzz_test_util.h" + +namespace spvtools { +namespace fuzz { +namespace { + +TEST(TransformationOutlineFunctionTest, TrivialOutline) { + // This tests outlining of a single, empty basic block. + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + TransformationOutlineFunction transformation(5, 5, /* not relevant */ 200, + 100, 101, 102, 103, + /* not relevant */ 201, {}, {}); + ASSERT_TRUE(transformation.IsApplicable(context.get(), fact_manager)); + transformation.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %103 = OpFunctionCall %2 %101 + OpReturn + OpFunctionEnd + %101 = OpFunction %2 None %3 + %102 = OpLabel + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +TEST(TransformationOutlineFunctionTest, + DoNotOutlineIfRegionStartsWithOpVariable) { + // This checks that we do not outline the first block of a function if it + // contains OpVariable. + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %7 = OpTypeBool + %8 = OpTypePointer Function %7 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %6 = OpVariable %8 Function + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + TransformationOutlineFunction transformation(5, 5, /* not relevant */ 200, + 100, 101, 102, 103, + /* not relevant */ 201, {}, {}); + ASSERT_FALSE(transformation.IsApplicable(context.get(), fact_manager)); +} + +TEST(TransformationOutlineFunctionTest, OutlineInterestingControlFlowNoState) { + // This tests outlining of some non-trivial control flow, but such that the + // basic blocks in the control flow do not actually do anything. + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %20 = OpTypeBool + %21 = OpConstantTrue %20 + %3 = OpTypeFunction %2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpBranch %6 + %6 = OpLabel + OpBranch %7 + %7 = OpLabel + OpSelectionMerge %9 None + OpBranchConditional %21 %8 %9 + %8 = OpLabel + OpBranch %9 + %9 = OpLabel + OpLoopMerge %12 %11 None + OpBranch %10 + %10 = OpLabel + OpBranchConditional %21 %11 %12 + %11 = OpLabel + OpBranch %9 + %12 = OpLabel + OpBranch %13 + %13 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + TransformationOutlineFunction transformation(6, 13, /* not relevant */ + 200, 100, 101, 102, 103, + /* not relevant */ 201, {}, {}); + ASSERT_TRUE(transformation.IsApplicable(context.get(), fact_manager)); + transformation.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %20 = OpTypeBool + %21 = OpConstantTrue %20 + %3 = OpTypeFunction %2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpBranch %6 + %6 = OpLabel + %103 = OpFunctionCall %2 %101 + OpReturn + OpFunctionEnd + %101 = OpFunction %2 None %3 + %102 = OpLabel + OpBranch %7 + %7 = OpLabel + OpSelectionMerge %9 None + OpBranchConditional %21 %8 %9 + %8 = OpLabel + OpBranch %9 + %9 = OpLabel + OpLoopMerge %12 %11 None + OpBranch %10 + %10 = OpLabel + OpBranchConditional %21 %11 %12 + %11 = OpLabel + OpBranch %9 + %12 = OpLabel + OpBranch %13 + %13 = OpLabel + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +TEST(TransformationOutlineFunctionTest, OutlineCodeThatGeneratesUnusedIds) { + // This tests outlining of a single basic block that does some computation, + // but that does not use nor generate ids required outside of the outlined + // region. + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %20 = OpTypeInt 32 1 + %21 = OpConstant %20 5 + %3 = OpTypeFunction %2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpBranch %6 + %6 = OpLabel + %7 = OpCopyObject %20 %21 + %8 = OpCopyObject %20 %21 + %9 = OpIAdd %20 %7 %8 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + TransformationOutlineFunction transformation(6, 6, /* not relevant */ 200, + 100, 101, 102, 103, + /* not relevant */ 201, {}, {}); + ASSERT_TRUE(transformation.IsApplicable(context.get(), fact_manager)); + transformation.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %20 = OpTypeInt 32 1 + %21 = OpConstant %20 5 + %3 = OpTypeFunction %2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpBranch %6 + %6 = OpLabel + %103 = OpFunctionCall %2 %101 + OpReturn + OpFunctionEnd + %101 = OpFunction %2 None %3 + %102 = OpLabel + %7 = OpCopyObject %20 %21 + %8 = OpCopyObject %20 %21 + %9 = OpIAdd %20 %7 %8 + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +TEST(TransformationOutlineFunctionTest, OutlineCodeThatGeneratesSingleUsedId) { + // This tests outlining of a block that generates an id that is used in a + // later block. + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %20 = OpTypeInt 32 1 + %21 = OpConstant %20 5 + %3 = OpTypeFunction %2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpBranch %6 + %6 = OpLabel + %7 = OpCopyObject %20 %21 + %8 = OpCopyObject %20 %21 + %9 = OpIAdd %20 %7 %8 + OpBranch %10 + %10 = OpLabel + %11 = OpCopyObject %20 %9 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + TransformationOutlineFunction transformation(6, 6, 99, 100, 101, 102, 103, + 105, {}, {{9, 104}}); + ASSERT_TRUE(transformation.IsApplicable(context.get(), fact_manager)); + transformation.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %20 = OpTypeInt 32 1 + %21 = OpConstant %20 5 + %3 = OpTypeFunction %2 + %99 = OpTypeStruct %20 + %100 = OpTypeFunction %99 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpBranch %6 + %6 = OpLabel + %103 = OpFunctionCall %99 %101 + %9 = OpCompositeExtract %20 %103 0 + OpBranch %10 + %10 = OpLabel + %11 = OpCopyObject %20 %9 + OpReturn + OpFunctionEnd + %101 = OpFunction %99 None %100 + %102 = OpLabel + %7 = OpCopyObject %20 %21 + %8 = OpCopyObject %20 %21 + %104 = OpIAdd %20 %7 %8 + %105 = OpCompositeConstruct %99 %104 + OpReturnValue %105 + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +TEST(TransformationOutlineFunctionTest, OutlineDiamondThatGeneratesSeveralIds) { + // This tests outlining of several blocks that generate a number of ids that + // are used in later blocks. + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %20 = OpTypeInt 32 1 + %21 = OpConstant %20 5 + %22 = OpTypeBool + %3 = OpTypeFunction %2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpBranch %6 + %6 = OpLabel + %7 = OpCopyObject %20 %21 + %8 = OpCopyObject %20 %21 + %9 = OpSLessThan %22 %7 %8 + OpSelectionMerge %12 None + OpBranchConditional %9 %10 %11 + %10 = OpLabel + %13 = OpIAdd %20 %7 %8 + OpBranch %12 + %11 = OpLabel + %14 = OpIAdd %20 %7 %7 + OpBranch %12 + %12 = OpLabel + %15 = OpPhi %20 %13 %10 %14 %11 + OpBranch %80 + %80 = OpLabel + OpBranch %16 + %16 = OpLabel + %17 = OpCopyObject %20 %15 + %18 = OpCopyObject %22 %9 + %19 = OpIAdd %20 %7 %8 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + TransformationOutlineFunction transformation( + 6, 80, 100, 101, 102, 103, 104, 105, {}, + {{15, 106}, {9, 107}, {7, 108}, {8, 109}}); + ASSERT_TRUE(transformation.IsApplicable(context.get(), fact_manager)); + transformation.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %20 = OpTypeInt 32 1 + %21 = OpConstant %20 5 + %22 = OpTypeBool + %3 = OpTypeFunction %2 + %100 = OpTypeStruct %20 %20 %22 %20 + %101 = OpTypeFunction %100 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpBranch %6 + %6 = OpLabel + %104 = OpFunctionCall %100 %102 + %7 = OpCompositeExtract %20 %104 0 + %8 = OpCompositeExtract %20 %104 1 + %9 = OpCompositeExtract %22 %104 2 + %15 = OpCompositeExtract %20 %104 3 + OpBranch %16 + %16 = OpLabel + %17 = OpCopyObject %20 %15 + %18 = OpCopyObject %22 %9 + %19 = OpIAdd %20 %7 %8 + OpReturn + OpFunctionEnd + %102 = OpFunction %100 None %101 + %103 = OpLabel + %108 = OpCopyObject %20 %21 + %109 = OpCopyObject %20 %21 + %107 = OpSLessThan %22 %108 %109 + OpSelectionMerge %12 None + OpBranchConditional %107 %10 %11 + %10 = OpLabel + %13 = OpIAdd %20 %108 %109 + OpBranch %12 + %11 = OpLabel + %14 = OpIAdd %20 %108 %108 + OpBranch %12 + %12 = OpLabel + %106 = OpPhi %20 %13 %10 %14 %11 + OpBranch %80 + %80 = OpLabel + %105 = OpCompositeConstruct %100 %108 %109 %107 %106 + OpReturnValue %105 + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +TEST(TransformationOutlineFunctionTest, OutlineCodeThatUsesASingleId) { + // This tests outlining of a block that uses an id defined earlier. + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %20 = OpTypeInt 32 1 + %21 = OpConstant %20 5 + %3 = OpTypeFunction %2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %7 = OpCopyObject %20 %21 + OpBranch %6 + %6 = OpLabel + %8 = OpCopyObject %20 %7 + OpBranch %10 + %10 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + TransformationOutlineFunction transformation(6, 6, 100, 101, 102, 103, 104, + 105, {{7, 106}}, {}); + ASSERT_TRUE(transformation.IsApplicable(context.get(), fact_manager)); + transformation.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %20 = OpTypeInt 32 1 + %21 = OpConstant %20 5 + %3 = OpTypeFunction %2 + %101 = OpTypeFunction %2 %20 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %7 = OpCopyObject %20 %21 + OpBranch %6 + %6 = OpLabel + %104 = OpFunctionCall %2 %102 %7 + OpBranch %10 + %10 = OpLabel + OpReturn + OpFunctionEnd + %102 = OpFunction %2 None %101 + %106 = OpFunctionParameter %20 + %103 = OpLabel + %8 = OpCopyObject %20 %106 + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +TEST(TransformationOutlineFunctionTest, OutlineCodeThatUsesAVariable) { + // This tests outlining of a block that uses a variable. + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %20 = OpTypeInt 32 1 + %21 = OpConstant %20 5 + %3 = OpTypeFunction %2 + %12 = OpTypePointer Function %20 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %13 = OpVariable %12 Function + OpBranch %6 + %6 = OpLabel + %8 = OpLoad %20 %13 + OpBranch %10 + %10 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + TransformationOutlineFunction transformation(6, 6, 100, 101, 102, 103, 104, + 105, {{13, 106}}, {}); + ASSERT_TRUE(transformation.IsApplicable(context.get(), fact_manager)); + transformation.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %20 = OpTypeInt 32 1 + %21 = OpConstant %20 5 + %3 = OpTypeFunction %2 + %12 = OpTypePointer Function %20 + %101 = OpTypeFunction %2 %12 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %13 = OpVariable %12 Function + OpBranch %6 + %6 = OpLabel + %104 = OpFunctionCall %2 %102 %13 + OpBranch %10 + %10 = OpLabel + OpReturn + OpFunctionEnd + %102 = OpFunction %2 None %101 + %106 = OpFunctionParameter %12 + %103 = OpLabel + %8 = OpLoad %20 %106 + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +TEST(TransformationOutlineFunctionTest, OutlineCodeThatUsesAParameter) { + // This tests outlining of a block that uses a function parameter. + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %10 "foo(i1;" + OpName %9 "x" + OpName %18 "param" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %8 = OpTypeFunction %6 %7 + %13 = OpConstant %6 1 + %17 = OpConstant %6 3 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %18 = OpVariable %7 Function + OpStore %18 %17 + %19 = OpFunctionCall %6 %10 %18 + OpReturn + OpFunctionEnd + %10 = OpFunction %6 None %8 + %9 = OpFunctionParameter %7 + %11 = OpLabel + %12 = OpLoad %6 %9 + %14 = OpIAdd %6 %12 %13 + OpReturnValue %14 + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + TransformationOutlineFunction transformation(11, 11, 100, 101, 102, 103, 104, + 105, {{9, 106}}, {{14, 107}}); + ASSERT_TRUE(transformation.IsApplicable(context.get(), fact_manager)); + transformation.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %10 "foo(i1;" + OpName %9 "x" + OpName %18 "param" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %8 = OpTypeFunction %6 %7 + %13 = OpConstant %6 1 + %17 = OpConstant %6 3 + %100 = OpTypeStruct %6 + %101 = OpTypeFunction %100 %7 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %18 = OpVariable %7 Function + OpStore %18 %17 + %19 = OpFunctionCall %6 %10 %18 + OpReturn + OpFunctionEnd + %10 = OpFunction %6 None %8 + %9 = OpFunctionParameter %7 + %11 = OpLabel + %104 = OpFunctionCall %100 %102 %9 + %14 = OpCompositeExtract %6 %104 0 + OpReturnValue %14 + OpFunctionEnd + %102 = OpFunction %100 None %101 + %106 = OpFunctionParameter %7 + %103 = OpLabel + %12 = OpLoad %6 %106 + %107 = OpIAdd %6 %12 %13 + %105 = OpCompositeConstruct %100 %107 + OpReturnValue %105 + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +TEST(TransformationOutlineFunctionTest, + DoNotOutlineIfLoopMergeIsOutsideRegion) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %9 = OpTypeBool + %10 = OpConstantTrue %9 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpBranch %6 + %6 = OpLabel + OpLoopMerge %7 %8 None + OpBranch %8 + %8 = OpLabel + OpBranchConditional %10 %6 %7 + %7 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + TransformationOutlineFunction transformation(6, 8, 100, 101, 102, 103, 104, + 105, {}, {}); + ASSERT_FALSE(transformation.IsApplicable(context.get(), fact_manager)); +} + +TEST(TransformationOutlineFunctionTest, DoNotOutlineIfRegionInvolvesReturn) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %20 = OpTypeBool + %21 = OpConstantTrue %20 + %3 = OpTypeFunction %2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpBranch %6 + %6 = OpLabel + OpBranch %7 + %7 = OpLabel + OpSelectionMerge %10 None + OpBranchConditional %21 %8 %9 + %8 = OpLabel + OpReturn + %9 = OpLabel + OpBranch %10 + %10 = OpLabel + OpBranch %11 + %11 = OpLabel + OpBranch %12 + %12 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + TransformationOutlineFunction transformation(6, 11, /* not relevant */ 200, + 100, 101, 102, 103, + /* not relevant */ 201, {}, {}); + ASSERT_FALSE(transformation.IsApplicable(context.get(), fact_manager)); +} + +TEST(TransformationOutlineFunctionTest, DoNotOutlineIfRegionInvolvesKill) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %20 = OpTypeBool + %21 = OpConstantTrue %20 + %3 = OpTypeFunction %2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpBranch %6 + %6 = OpLabel + OpBranch %7 + %7 = OpLabel + OpSelectionMerge %10 None + OpBranchConditional %21 %8 %9 + %8 = OpLabel + OpKill + %9 = OpLabel + OpBranch %10 + %10 = OpLabel + OpBranch %11 + %11 = OpLabel + OpBranch %12 + %12 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + TransformationOutlineFunction transformation(6, 11, /* not relevant */ 200, + 100, 101, 102, 103, + /* not relevant */ 201, {}, {}); + ASSERT_FALSE(transformation.IsApplicable(context.get(), fact_manager)); +} + +TEST(TransformationOutlineFunctionTest, + DoNotOutlineIfRegionInvolvesUnreachable) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %20 = OpTypeBool + %21 = OpConstantTrue %20 + %3 = OpTypeFunction %2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpBranch %6 + %6 = OpLabel + OpBranch %7 + %7 = OpLabel + OpSelectionMerge %10 None + OpBranchConditional %21 %8 %9 + %8 = OpLabel + OpBranch %10 + %9 = OpLabel + OpUnreachable + %10 = OpLabel + OpBranch %11 + %11 = OpLabel + OpBranch %12 + %12 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + TransformationOutlineFunction transformation(6, 11, /* not relevant */ 200, + 100, 101, 102, 103, + /* not relevant */ 201, {}, {}); + ASSERT_FALSE(transformation.IsApplicable(context.get(), fact_manager)); +} + +TEST(TransformationOutlineFunctionTest, + DoNotOutlineIfSelectionMergeIsOutsideRegion) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %9 = OpTypeBool + %10 = OpConstantTrue %9 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpBranch %6 + %6 = OpLabel + OpSelectionMerge %7 None + OpBranchConditional %10 %8 %7 + %8 = OpLabel + OpBranch %7 + %7 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + TransformationOutlineFunction transformation(6, 8, 100, 101, 102, 103, 104, + 105, {}, {}); + ASSERT_FALSE(transformation.IsApplicable(context.get(), fact_manager)); +} + +TEST(TransformationOutlineFunctionTest, DoNotOutlineIfLoopHeadIsOutsideRegion) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %9 = OpTypeBool + %10 = OpConstantTrue %9 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpBranch %6 + %6 = OpLabel + OpLoopMerge %8 %11 None + OpBranch %7 + %7 = OpLabel + OpBranchConditional %10 %11 %8 + %11 = OpLabel + OpBranch %6 + %8 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + TransformationOutlineFunction transformation(7, 8, 100, 101, 102, 103, 104, + 105, {}, {}); + ASSERT_FALSE(transformation.IsApplicable(context.get(), fact_manager)); +} + +TEST(TransformationOutlineFunctionTest, + DoNotOutlineIfLoopContinueIsOutsideRegion) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %9 = OpTypeBool + %10 = OpConstantTrue %9 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpBranch %6 + %6 = OpLabel + OpLoopMerge %7 %8 None + OpBranch %7 + %8 = OpLabel + OpBranch %6 + %7 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + TransformationOutlineFunction transformation(6, 7, 100, 101, 102, 103, 104, + 105, {}, {}); + ASSERT_FALSE(transformation.IsApplicable(context.get(), fact_manager)); +} + +TEST(TransformationOutlineFunctionTest, + DoNotOutlineWithLoopCarriedPhiDependence) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %9 = OpTypeBool + %10 = OpConstantTrue %9 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpBranch %6 + %6 = OpLabel + %12 = OpPhi %9 %10 %5 %13 %8 + OpLoopMerge %7 %8 None + OpBranch %8 + %8 = OpLabel + %13 = OpCopyObject %9 %10 + OpBranchConditional %10 %6 %7 + %7 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + TransformationOutlineFunction transformation(6, 7, 100, 101, 102, 103, 104, + 105, {}, {}); + ASSERT_FALSE(transformation.IsApplicable(context.get(), fact_manager)); +} + +TEST(TransformationOutlineFunctionTest, + DoNotOutlineSelectionHeaderNotInRegion) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeBool + %7 = OpConstantTrue %6 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpSelectionMerge %10 None + OpBranchConditional %7 %8 %8 + %8 = OpLabel + OpBranch %9 + %9 = OpLabel + OpBranch %10 + %10 = OpLabel + OpBranch %11 + %11 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + TransformationOutlineFunction transformation(8, 11, 100, 101, 102, 103, 104, + 105, {}, {}); + ASSERT_FALSE(transformation.IsApplicable(context.get(), fact_manager)); +} + +TEST(TransformationOutlineFunctionTest, OutlineRegionEndingWithReturnVoid) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %20 = OpTypeInt 32 0 + %21 = OpConstant %20 1 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %22 = OpCopyObject %20 %21 + OpBranch %54 + %54 = OpLabel + OpBranch %57 + %57 = OpLabel + %23 = OpCopyObject %20 %22 + OpBranch %58 + %58 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_5; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + TransformationOutlineFunction transformation( + /*entry_block*/ 54, + /*exit_block*/ 58, + /*new_function_struct_return_type_id*/ 200, + /*new_function_type_id*/ 201, + /*new_function_id*/ 202, + /*new_function_region_entry_block*/ 203, + /*new_caller_result_id*/ 204, + /*new_callee_result_id*/ 205, + /*input_id_to_fresh_id*/ {{22, 206}}, + /*output_id_to_fresh_id*/ {}); + + ASSERT_TRUE(transformation.IsApplicable(context.get(), fact_manager)); + transformation.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %20 = OpTypeInt 32 0 + %21 = OpConstant %20 1 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %201 = OpTypeFunction %2 %20 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %22 = OpCopyObject %20 %21 + OpBranch %54 + %54 = OpLabel + %204 = OpFunctionCall %2 %202 %22 + OpReturn + OpFunctionEnd + %202 = OpFunction %2 None %201 + %206 = OpFunctionParameter %20 + %203 = OpLabel + OpBranch %57 + %57 = OpLabel + %23 = OpCopyObject %20 %206 + OpBranch %58 + %58 = OpLabel + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +TEST(TransformationOutlineFunctionTest, OutlineRegionEndingWithReturnValue) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %20 = OpTypeInt 32 0 + %21 = OpConstant %20 1 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %30 = OpTypeFunction %20 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %6 = OpFunctionCall %20 %100 + OpReturn + OpFunctionEnd + %100 = OpFunction %20 None %30 + %8 = OpLabel + %31 = OpCopyObject %20 %21 + OpBranch %9 + %9 = OpLabel + %32 = OpCopyObject %20 %31 + OpBranch %10 + %10 = OpLabel + OpReturnValue %32 + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_5; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + TransformationOutlineFunction transformation( + /*entry_block*/ 9, + /*exit_block*/ 10, + /*new_function_struct_return_type_id*/ 200, + /*new_function_type_id*/ 201, + /*new_function_id*/ 202, + /*new_function_region_entry_block*/ 203, + /*new_caller_result_id*/ 204, + /*new_callee_result_id*/ 205, + /*input_id_to_fresh_id*/ {{31, 206}}, + /*output_id_to_fresh_id*/ {{32, 207}}); + + ASSERT_TRUE(transformation.IsApplicable(context.get(), fact_manager)); + transformation.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %20 = OpTypeInt 32 0 + %21 = OpConstant %20 1 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %30 = OpTypeFunction %20 + %200 = OpTypeStruct %20 + %201 = OpTypeFunction %200 %20 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %6 = OpFunctionCall %20 %100 + OpReturn + OpFunctionEnd + %100 = OpFunction %20 None %30 + %8 = OpLabel + %31 = OpCopyObject %20 %21 + OpBranch %9 + %9 = OpLabel + %204 = OpFunctionCall %200 %202 %31 + %32 = OpCompositeExtract %20 %204 0 + OpReturnValue %32 + OpFunctionEnd + %202 = OpFunction %200 None %201 + %206 = OpFunctionParameter %20 + %203 = OpLabel + %207 = OpCopyObject %20 %206 + OpBranch %10 + %10 = OpLabel + %205 = OpCompositeConstruct %200 %207 + OpReturnValue %205 + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +TEST(TransformationOutlineFunctionTest, + OutlineRegionEndingWithConditionalBranch) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %20 = OpTypeBool + %21 = OpConstantTrue %20 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpBranch %54 + %54 = OpLabel + %6 = OpCopyObject %20 %21 + OpSelectionMerge %8 None + OpBranchConditional %6 %7 %8 + %7 = OpLabel + OpBranch %8 + %8 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_5; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + TransformationOutlineFunction transformation( + /*entry_block*/ 54, + /*exit_block*/ 54, + /*new_function_struct_return_type_id*/ 200, + /*new_function_type_id*/ 201, + /*new_function_id*/ 202, + /*new_function_region_entry_block*/ 203, + /*new_caller_result_id*/ 204, + /*new_callee_result_id*/ 205, + /*input_id_to_fresh_id*/ {{}}, + /*output_id_to_fresh_id*/ {{6, 206}}); + + ASSERT_TRUE(transformation.IsApplicable(context.get(), fact_manager)); + transformation.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %20 = OpTypeBool + %21 = OpConstantTrue %20 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %200 = OpTypeStruct %20 + %201 = OpTypeFunction %200 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpBranch %54 + %54 = OpLabel + %204 = OpFunctionCall %200 %202 + %6 = OpCompositeExtract %20 %204 0 + OpSelectionMerge %8 None + OpBranchConditional %6 %7 %8 + %7 = OpLabel + OpBranch %8 + %8 = OpLabel + OpReturn + OpFunctionEnd + %202 = OpFunction %200 None %201 + %203 = OpLabel + %206 = OpCopyObject %20 %21 + %205 = OpCompositeConstruct %200 %206 + OpReturnValue %205 + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +TEST(TransformationOutlineFunctionTest, + OutlineRegionEndingWithConditionalBranch2) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %20 = OpTypeBool + %21 = OpConstantTrue %20 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %6 = OpCopyObject %20 %21 + OpBranch %54 + %54 = OpLabel + OpSelectionMerge %8 None + OpBranchConditional %6 %7 %8 + %7 = OpLabel + OpBranch %8 + %8 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_5; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + TransformationOutlineFunction transformation( + /*entry_block*/ 54, + /*exit_block*/ 54, + /*new_function_struct_return_type_id*/ 200, + /*new_function_type_id*/ 201, + /*new_function_id*/ 202, + /*new_function_region_entry_block*/ 203, + /*new_caller_result_id*/ 204, + /*new_callee_result_id*/ 205, + /*input_id_to_fresh_id*/ {}, + /*output_id_to_fresh_id*/ {}); + + ASSERT_TRUE(transformation.IsApplicable(context.get(), fact_manager)); + transformation.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %20 = OpTypeBool + %21 = OpConstantTrue %20 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %6 = OpCopyObject %20 %21 + OpBranch %54 + %54 = OpLabel + %204 = OpFunctionCall %2 %202 + OpSelectionMerge %8 None + OpBranchConditional %6 %7 %8 + %7 = OpLabel + OpBranch %8 + %8 = OpLabel + OpReturn + OpFunctionEnd + %202 = OpFunction %2 None %3 + %203 = OpLabel + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +TEST(TransformationOutlineFunctionTest, DoNotOutlineRegionThatStartsWithOpPhi) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeBool + %7 = OpConstantTrue %6 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpBranch %21 + %21 = OpLabel + %22 = OpPhi %6 %7 %5 + %23 = OpCopyObject %6 %22 + OpBranch %24 + %24 = OpLabel + %25 = OpCopyObject %6 %23 + %26 = OpCopyObject %6 %22 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_5; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + TransformationOutlineFunction transformation( + /*entry_block*/ 21, + /*exit_block*/ 21, + /*new_function_struct_return_type_id*/ 200, + /*new_function_type_id*/ 201, + /*new_function_id*/ 202, + /*new_function_region_entry_block*/ 204, + /*new_caller_result_id*/ 205, + /*new_callee_result_id*/ 206, + /*input_id_to_fresh_id*/ {{22, 207}}, + /*output_id_to_fresh_id*/ {{23, 208}}); + + ASSERT_FALSE(transformation.IsApplicable(context.get(), fact_manager)); +} + +TEST(TransformationOutlineFunctionTest, + DoNotOutlineRegionThatStartsWithLoopHeader) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeBool + %7 = OpConstantTrue %6 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpBranch %21 + %21 = OpLabel + OpLoopMerge %22 %23 None + OpBranch %24 + %24 = OpLabel + OpBranchConditional %7 %22 %23 + %23 = OpLabel + OpBranch %21 + %22 = OpLabel + OpBranch %25 + %25 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_5; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + TransformationOutlineFunction transformation( + /*entry_block*/ 21, + /*exit_block*/ 24, + /*new_function_struct_return_type_id*/ 200, + /*new_function_type_id*/ 201, + /*new_function_id*/ 202, + /*new_function_region_entry_block*/ 204, + /*new_caller_result_id*/ 205, + /*new_callee_result_id*/ 206, + /*input_id_to_fresh_id*/ {}, + /*output_id_to_fresh_id*/ {}); + + ASSERT_FALSE(transformation.IsApplicable(context.get(), fact_manager)); +} + +TEST(TransformationOutlineFunctionTest, + DoNotOutlineRegionThatEndsWithLoopMerge) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeBool + %7 = OpConstantTrue %6 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpBranch %21 + %21 = OpLabel + OpLoopMerge %22 %23 None + OpBranch %24 + %24 = OpLabel + OpBranchConditional %7 %22 %23 + %23 = OpLabel + OpBranch %21 + %22 = OpLabel + OpBranch %25 + %25 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_5; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + TransformationOutlineFunction transformation( + /*entry_block*/ 5, + /*exit_block*/ 22, + /*new_function_struct_return_type_id*/ 200, + /*new_function_type_id*/ 201, + /*new_function_id*/ 202, + /*new_function_region_entry_block*/ 204, + /*new_caller_result_id*/ 205, + /*new_callee_result_id*/ 206, + /*input_id_to_fresh_id*/ {}, + /*output_id_to_fresh_id*/ {}); + + ASSERT_FALSE(transformation.IsApplicable(context.get(), fact_manager)); +} + +TEST(TransformationOutlineFunctionTest, DoNotOutlineRegionThatUsesAccessChain) { + // An access chain result is a pointer, but it cannot be passed as a function + // parameter, as it is not a memory object. + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypeVector %6 4 + %8 = OpTypePointer Function %7 + %9 = OpTypePointer Function %6 + %18 = OpTypeInt 32 0 + %19 = OpConstant %18 0 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %10 = OpVariable %8 Function + OpBranch %11 + %11 = OpLabel + %12 = OpAccessChain %9 %10 %19 + OpBranch %13 + %13 = OpLabel + %14 = OpLoad %6 %12 + OpBranch %15 + %15 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_5; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + TransformationOutlineFunction transformation( + /*entry_block*/ 13, + /*exit_block*/ 15, + /*new_function_struct_return_type_id*/ 200, + /*new_function_type_id*/ 201, + /*new_function_id*/ 202, + /*new_function_region_entry_block*/ 204, + /*new_caller_result_id*/ 205, + /*new_callee_result_id*/ 206, + /*input_id_to_fresh_id*/ {{12, 207}}, + /*output_id_to_fresh_id*/ {}); + + ASSERT_FALSE(transformation.IsApplicable(context.get(), fact_manager)); +} + +TEST(TransformationOutlineFunctionTest, + DoNotOutlineRegionThatUsesCopiedObject) { + // Copying a variable leads to a pointer, but one that cannot be passed as a + // function parameter, as it is not a memory object. + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypeVector %6 4 + %8 = OpTypePointer Function %7 + %9 = OpTypePointer Function %6 + %18 = OpTypeInt 32 0 + %19 = OpConstant %18 0 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %10 = OpVariable %8 Function + OpBranch %11 + %11 = OpLabel + %20 = OpCopyObject %8 %10 + OpBranch %13 + %13 = OpLabel + %12 = OpAccessChain %9 %20 %19 + %14 = OpLoad %6 %12 + OpBranch %15 + %15 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_5; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + TransformationOutlineFunction transformation( + /*entry_block*/ 13, + /*exit_block*/ 15, + /*new_function_struct_return_type_id*/ 200, + /*new_function_type_id*/ 201, + /*new_function_id*/ 202, + /*new_function_region_entry_block*/ 204, + /*new_caller_result_id*/ 205, + /*new_callee_result_id*/ 206, + /*input_id_to_fresh_id*/ {{20, 207}}, + /*output_id_to_fresh_id*/ {}); + + ASSERT_FALSE(transformation.IsApplicable(context.get(), fact_manager)); +} + +TEST(TransformationOutlineFunctionTest, + DoOutlineRegionThatUsesPointerParameter) { + // The region being outlined reads from a function parameter of pointer type. + // This is OK: the function parameter can itself be passed on as a function + // parameter. + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %8 = OpTypeFunction %2 %7 + %13 = OpConstant %6 2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %15 = OpVariable %7 Function + %16 = OpVariable %7 Function + %17 = OpLoad %6 %15 + OpStore %16 %17 + %18 = OpFunctionCall %2 %10 %16 + %19 = OpLoad %6 %16 + OpStore %15 %19 + OpReturn + OpFunctionEnd + %10 = OpFunction %2 None %8 + %9 = OpFunctionParameter %7 + %11 = OpLabel + %12 = OpLoad %6 %9 + %14 = OpIAdd %6 %12 %13 + OpBranch %20 + %20 = OpLabel + OpStore %9 %14 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_5; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + TransformationOutlineFunction transformation( + /*entry_block*/ 11, + /*exit_block*/ 11, + /*new_function_struct_return_type_id*/ 200, + /*new_function_type_id*/ 201, + /*new_function_id*/ 202, + /*new_function_region_entry_block*/ 204, + /*new_caller_result_id*/ 205, + /*new_callee_result_id*/ 206, + /*input_id_to_fresh_id*/ {{9, 207}}, + /*output_id_to_fresh_id*/ {{14, 208}}); + + ASSERT_TRUE(transformation.IsApplicable(context.get(), fact_manager)); + transformation.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %8 = OpTypeFunction %2 %7 + %13 = OpConstant %6 2 + %200 = OpTypeStruct %6 + %201 = OpTypeFunction %200 %7 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %15 = OpVariable %7 Function + %16 = OpVariable %7 Function + %17 = OpLoad %6 %15 + OpStore %16 %17 + %18 = OpFunctionCall %2 %10 %16 + %19 = OpLoad %6 %16 + OpStore %15 %19 + OpReturn + OpFunctionEnd + %10 = OpFunction %2 None %8 + %9 = OpFunctionParameter %7 + %11 = OpLabel + %205 = OpFunctionCall %200 %202 %9 + %14 = OpCompositeExtract %6 %205 0 + OpBranch %20 + %20 = OpLabel + OpStore %9 %14 + OpReturn + OpFunctionEnd + %202 = OpFunction %200 None %201 + %207 = OpFunctionParameter %7 + %204 = OpLabel + %12 = OpLoad %6 %207 + %208 = OpIAdd %6 %12 %13 + %206 = OpCompositeConstruct %200 %208 + OpReturnValue %206 + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +TEST(TransformationOutlineFunctionTest, OutlineLivesafe) { + // In the following, %30 is a livesafe function, with arbitrary parameter + // %200 and arbitrary local variable %201. Variable %100 is a loop limiter, + // which is not arbitrary. The test checks that the outlined function is + // livesafe, and that the parameters corresponding to %200 and %201 have the + // arbitrary fact associated with them. + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 0 + %7 = OpTypePointer Function %6 + %199 = OpTypeFunction %2 %7 + %8 = OpConstant %6 0 + %9 = OpConstant %6 1 + %10 = OpConstant %6 5 + %11 = OpTypeBool + %12 = OpConstantTrue %11 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + %30 = OpFunction %2 None %199 + %200 = OpFunctionParameter %7 + %31 = OpLabel + %100 = OpVariable %7 Function %8 + %201 = OpVariable %7 Function %8 + OpBranch %198 + %198 = OpLabel + OpBranch %20 + %20 = OpLabel + %101 = OpLoad %6 %100 + %102 = OpIAdd %6 %101 %9 + %202 = OpLoad %6 %200 + OpStore %201 %202 + OpStore %100 %102 + %103 = OpUGreaterThanEqual %11 %101 %10 + OpLoopMerge %21 %22 None + OpBranchConditional %103 %21 %104 + %104 = OpLabel + OpBranchConditional %12 %23 %21 + %23 = OpLabel + %105 = OpLoad %6 %100 + %106 = OpIAdd %6 %105 %9 + OpStore %100 %106 + %107 = OpUGreaterThanEqual %11 %105 %10 + OpLoopMerge %25 %26 None + OpBranchConditional %107 %25 %108 + %108 = OpLabel + OpBranch %28 + %28 = OpLabel + OpBranchConditional %12 %26 %25 + %26 = OpLabel + OpBranch %23 + %25 = OpLabel + %109 = OpLoad %6 %100 + %110 = OpIAdd %6 %109 %9 + OpStore %100 %110 + %111 = OpUGreaterThanEqual %11 %109 %10 + OpLoopMerge %24 %27 None + OpBranchConditional %111 %24 %112 + %112 = OpLabel + OpBranchConditional %12 %24 %27 + %27 = OpLabel + OpBranch %25 + %24 = OpLabel + OpBranch %22 + %22 = OpLabel + OpBranch %20 + %21 = OpLabel + OpBranch %197 + %197 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_5; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + fact_manager.AddFactFunctionIsLivesafe(30); + fact_manager.AddFactValueOfVariableIsArbitrary(200); + fact_manager.AddFactValueOfVariableIsArbitrary(201); + + TransformationOutlineFunction transformation( + /*entry_block*/ 198, + /*exit_block*/ 197, + /*new_function_struct_return_type_id*/ 400, + /*new_function_type_id*/ 401, + /*new_function_id*/ 402, + /*new_function_region_entry_block*/ 404, + /*new_caller_result_id*/ 405, + /*new_callee_result_id*/ 406, + /*input_id_to_fresh_id*/ {{100, 407}, {200, 408}, {201, 409}}, + /*output_id_to_fresh_id*/ {}); + + ASSERT_TRUE(transformation.IsApplicable(context.get(), fact_manager)); + transformation.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + // The original function should still be livesafe. + ASSERT_TRUE(fact_manager.FunctionIsLivesafe(30)); + // The outlined function should be livesafe. + ASSERT_TRUE(fact_manager.FunctionIsLivesafe(402)); + // The variable and parameter that were originally arbitrary should still be. + ASSERT_TRUE(fact_manager.VariableValueIsArbitrary(200)); + ASSERT_TRUE(fact_manager.VariableValueIsArbitrary(201)); + // The loop limiter should still be non-arbitrary. + ASSERT_FALSE(fact_manager.VariableValueIsArbitrary(100)); + // The parameters for the original arbitrary variables should be arbitrary. + ASSERT_TRUE(fact_manager.VariableValueIsArbitrary(408)); + ASSERT_TRUE(fact_manager.VariableValueIsArbitrary(409)); + // The parameter for the loop limiter should not be arbitrary. + ASSERT_FALSE(fact_manager.VariableValueIsArbitrary(407)); + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 0 + %7 = OpTypePointer Function %6 + %199 = OpTypeFunction %2 %7 + %8 = OpConstant %6 0 + %9 = OpConstant %6 1 + %10 = OpConstant %6 5 + %11 = OpTypeBool + %12 = OpConstantTrue %11 + %401 = OpTypeFunction %2 %7 %7 %7 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + %30 = OpFunction %2 None %199 + %200 = OpFunctionParameter %7 + %31 = OpLabel + %100 = OpVariable %7 Function %8 + %201 = OpVariable %7 Function %8 + OpBranch %198 + %198 = OpLabel + %405 = OpFunctionCall %2 %402 %200 %100 %201 + OpReturn + OpFunctionEnd + %402 = OpFunction %2 None %401 + %408 = OpFunctionParameter %7 + %407 = OpFunctionParameter %7 + %409 = OpFunctionParameter %7 + %404 = OpLabel + OpBranch %20 + %20 = OpLabel + %101 = OpLoad %6 %407 + %102 = OpIAdd %6 %101 %9 + %202 = OpLoad %6 %408 + OpStore %409 %202 + OpStore %407 %102 + %103 = OpUGreaterThanEqual %11 %101 %10 + OpLoopMerge %21 %22 None + OpBranchConditional %103 %21 %104 + %104 = OpLabel + OpBranchConditional %12 %23 %21 + %23 = OpLabel + %105 = OpLoad %6 %407 + %106 = OpIAdd %6 %105 %9 + OpStore %407 %106 + %107 = OpUGreaterThanEqual %11 %105 %10 + OpLoopMerge %25 %26 None + OpBranchConditional %107 %25 %108 + %108 = OpLabel + OpBranch %28 + %28 = OpLabel + OpBranchConditional %12 %26 %25 + %26 = OpLabel + OpBranch %23 + %25 = OpLabel + %109 = OpLoad %6 %407 + %110 = OpIAdd %6 %109 %9 + OpStore %407 %110 + %111 = OpUGreaterThanEqual %11 %109 %10 + OpLoopMerge %24 %27 None + OpBranchConditional %111 %24 %112 + %112 = OpLabel + OpBranchConditional %12 %24 %27 + %27 = OpLabel + OpBranch %25 + %24 = OpLabel + OpBranch %22 + %22 = OpLabel + OpBranch %20 + %21 = OpLabel + OpBranch %197 + %197 = OpLabel + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +TEST(TransformationOutlineFunctionTest, OutlineWithDeadBlocks1) { + // This checks that if all blocks in the region being outlined were dead, all + // blocks in the outlined function will be dead. + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %10 "foo(i1;" + OpName %9 "x" + OpName %12 "y" + OpName %21 "i" + OpName %46 "param" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %8 = OpTypeFunction %2 %7 + %13 = OpConstant %6 2 + %14 = OpTypeBool + %15 = OpConstantFalse %14 + %22 = OpConstant %6 0 + %29 = OpConstant %6 10 + %41 = OpConstant %6 1 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %46 = OpVariable %7 Function + OpStore %46 %13 + %47 = OpFunctionCall %2 %10 %46 + OpReturn + OpFunctionEnd + %10 = OpFunction %2 None %8 + %9 = OpFunctionParameter %7 + %11 = OpLabel + %12 = OpVariable %7 Function + %21 = OpVariable %7 Function + OpStore %12 %13 + OpSelectionMerge %17 None + OpBranchConditional %15 %16 %17 + %16 = OpLabel + %18 = OpLoad %6 %9 + OpStore %12 %18 + %19 = OpLoad %6 %9 + %20 = OpIAdd %6 %19 %13 + OpStore %9 %20 + OpStore %21 %22 + OpBranch %23 + %23 = OpLabel + OpLoopMerge %25 %26 None + OpBranch %27 + %27 = OpLabel + %28 = OpLoad %6 %21 + %30 = OpSLessThan %14 %28 %29 + OpBranchConditional %30 %24 %25 + %24 = OpLabel + %31 = OpLoad %6 %9 + %32 = OpLoad %6 %21 + %33 = OpSGreaterThan %14 %31 %32 + OpSelectionMerge %35 None + OpBranchConditional %33 %34 %35 + %34 = OpLabel + OpBranch %26 + %35 = OpLabel + %37 = OpLoad %6 %9 + %38 = OpLoad %6 %12 + %39 = OpIAdd %6 %38 %37 + OpStore %12 %39 + OpBranch %26 + %26 = OpLabel + %40 = OpLoad %6 %21 + %42 = OpIAdd %6 %40 %41 + OpStore %21 %42 + OpBranch %23 + %25 = OpLabel + OpBranch %50 + %50 = OpLabel + OpBranch %17 + %17 = OpLabel + %43 = OpLoad %6 %9 + %44 = OpLoad %6 %12 + %45 = OpIAdd %6 %44 %43 + OpStore %12 %45 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_5; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + for (uint32_t block_id : {16u, 23u, 24u, 26u, 27u, 34u, 35u, 50u}) { + fact_manager.AddFactBlockIsDead(block_id); + } + + TransformationOutlineFunction transformation( + /*entry_block*/ 16, + /*exit_block*/ 50, + /*new_function_struct_return_type_id*/ 200, + /*new_function_type_id*/ 201, + /*new_function_id*/ 202, + /*new_function_region_entry_block*/ 203, + /*new_caller_result_id*/ 204, + /*new_callee_result_id*/ 205, + /*input_id_to_fresh_id*/ {{9, 206}, {12, 207}, {21, 208}}, + /*output_id_to_fresh_id*/ {}); + + ASSERT_TRUE(transformation.IsApplicable(context.get(), fact_manager)); + transformation.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + // All the original blocks, plus the new function entry block, should be dead. + for (uint32_t block_id : {16u, 23u, 24u, 26u, 27u, 34u, 35u, 50u, 203u}) { + ASSERT_TRUE(fact_manager.BlockIsDead(block_id)); + } +} + +TEST(TransformationOutlineFunctionTest, OutlineWithDeadBlocks2) { + // This checks that if some, but not all, blocks in the outlined region are + // dead, those (but not others) will be dead in the outlined function. + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" %8 + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeBool + %7 = OpTypePointer Private %6 + %8 = OpVariable %7 Private + %9 = OpConstantFalse %6 + %10 = OpTypePointer Function %6 + %12 = OpConstantTrue %6 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %11 = OpVariable %10 Function + OpBranch %30 + %30 = OpLabel + OpStore %8 %9 + OpBranch %31 + %31 = OpLabel + OpStore %11 %12 + OpSelectionMerge %36 None + OpBranchConditional %9 %32 %33 + %32 = OpLabel + OpBranch %34 + %33 = OpLabel + OpBranch %36 + %34 = OpLabel + OpBranch %35 + %35 = OpLabel + OpBranch %36 + %36 = OpLabel + OpBranch %37 + %37 = OpLabel + %13 = OpLoad %6 %8 + OpStore %11 %13 + %14 = OpLoad %6 %11 + OpStore %8 %14 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_5; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + for (uint32_t block_id : {32u, 34u, 35u}) { + fact_manager.AddFactBlockIsDead(block_id); + } + + TransformationOutlineFunction transformation( + /*entry_block*/ 30, + /*exit_block*/ 37, + /*new_function_struct_return_type_id*/ 200, + /*new_function_type_id*/ 201, + /*new_function_id*/ 202, + /*new_function_region_entry_block*/ 203, + /*new_caller_result_id*/ 204, + /*new_callee_result_id*/ 205, + /*input_id_to_fresh_id*/ {{11, 206}}, + /*output_id_to_fresh_id*/ {}); + + ASSERT_TRUE(transformation.IsApplicable(context.get(), fact_manager)); + transformation.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + // The blocks that were originally dead, but not others, should be dead. + for (uint32_t block_id : {32u, 34u, 35u}) { + ASSERT_TRUE(fact_manager.BlockIsDead(block_id)); + } + for (uint32_t block_id : {5u, 30u, 31u, 33u, 36u, 37u, 203u}) { + ASSERT_FALSE(fact_manager.BlockIsDead(block_id)); + } +} + +TEST(TransformationOutlineFunctionTest, + OutlineWithArbitraryVariablesAndParameters) { + // This checks that if the outlined region uses a mixture of arbitrary and + // non-arbitrary variables and parameters, these properties are preserved + // during outlining. + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %8 = OpTypeFunction %2 %7 %7 + %13 = OpConstant %6 2 + %15 = OpConstant %6 3 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + %11 = OpFunction %2 None %8 + %9 = OpFunctionParameter %7 + %10 = OpFunctionParameter %7 + %12 = OpLabel + %14 = OpVariable %7 Function + %20 = OpVariable %7 Function + OpBranch %50 + %50 = OpLabel + OpStore %9 %13 + OpStore %14 %15 + %16 = OpLoad %6 %14 + OpStore %10 %16 + %17 = OpLoad %6 %9 + %18 = OpLoad %6 %10 + %19 = OpIAdd %6 %17 %18 + OpStore %14 %19 + %21 = OpLoad %6 %9 + OpStore %20 %21 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_5; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + fact_manager.AddFactValueOfVariableIsArbitrary(9); + fact_manager.AddFactValueOfVariableIsArbitrary(14); + + TransformationOutlineFunction transformation( + /*entry_block*/ 50, + /*exit_block*/ 50, + /*new_function_struct_return_type_id*/ 200, + /*new_function_type_id*/ 201, + /*new_function_id*/ 202, + /*new_function_region_entry_block*/ 203, + /*new_caller_result_id*/ 204, + /*new_callee_result_id*/ 205, + /*input_id_to_fresh_id*/ {{9, 206}, {10, 207}, {14, 208}, {20, 209}}, + /*output_id_to_fresh_id*/ {}); + + ASSERT_TRUE(transformation.IsApplicable(context.get(), fact_manager)); + transformation.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + // The variables that were originally abitrary, plus input parameters + // corresponding to them, should be arbitrary. The rest should not be. + for (uint32_t variable_id : {9u, 14u, 206u, 208u}) { + ASSERT_TRUE(fact_manager.VariableValueIsArbitrary(variable_id)); + } + for (uint32_t variable_id : {10u, 20u, 207u, 209u}) { + ASSERT_FALSE(fact_manager.BlockIsDead(variable_id)); + } +} + +TEST(TransformationOutlineFunctionTest, Miscellaneous1) { + // This tests outlining of some non-trivial code. + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" %85 + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %28 "buf" + OpMemberName %28 0 "u1" + OpMemberName %28 1 "u2" + OpName %30 "" + OpName %85 "color" + OpMemberDecorate %28 0 Offset 0 + OpMemberDecorate %28 1 Offset 4 + OpDecorate %28 Block + OpDecorate %30 DescriptorSet 0 + OpDecorate %30 Binding 0 + OpDecorate %85 Location 0 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypeVector %6 4 + %10 = OpConstant %6 1 + %11 = OpConstant %6 2 + %12 = OpConstant %6 3 + %13 = OpConstant %6 4 + %14 = OpConstantComposite %7 %10 %11 %12 %13 + %15 = OpTypeInt 32 1 + %18 = OpConstant %15 0 + %28 = OpTypeStruct %6 %6 + %29 = OpTypePointer Uniform %28 + %30 = OpVariable %29 Uniform + %31 = OpTypePointer Uniform %6 + %35 = OpTypeBool + %39 = OpConstant %15 1 + %84 = OpTypePointer Output %7 + %85 = OpVariable %84 Output + %114 = OpConstant %15 8 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpBranch %22 + %22 = OpLabel + %103 = OpPhi %15 %18 %5 %106 %43 + %102 = OpPhi %7 %14 %5 %107 %43 + %101 = OpPhi %15 %18 %5 %40 %43 + %32 = OpAccessChain %31 %30 %18 + %33 = OpLoad %6 %32 + %34 = OpConvertFToS %15 %33 + %36 = OpSLessThan %35 %101 %34 + OpLoopMerge %24 %43 None + OpBranchConditional %36 %23 %24 + %23 = OpLabel + %40 = OpIAdd %15 %101 %39 + OpBranch %150 + %150 = OpLabel + OpBranch %41 + %41 = OpLabel + %107 = OpPhi %7 %102 %150 %111 %65 + %106 = OpPhi %15 %103 %150 %110 %65 + %104 = OpPhi %15 %40 %150 %81 %65 + %47 = OpAccessChain %31 %30 %39 + %48 = OpLoad %6 %47 + %49 = OpConvertFToS %15 %48 + %50 = OpSLessThan %35 %104 %49 + OpLoopMerge %1000 %65 None + OpBranchConditional %50 %42 %1000 + %42 = OpLabel + %60 = OpIAdd %15 %106 %114 + %63 = OpSGreaterThan %35 %104 %60 + OpBranchConditional %63 %64 %65 + %64 = OpLabel + %71 = OpCompositeExtract %6 %107 0 + %72 = OpFAdd %6 %71 %11 + %97 = OpCompositeInsert %7 %72 %107 0 + %76 = OpCompositeExtract %6 %107 3 + %77 = OpConvertFToS %15 %76 + %79 = OpIAdd %15 %60 %77 + OpBranch %65 + %65 = OpLabel + %111 = OpPhi %7 %107 %42 %97 %64 + %110 = OpPhi %15 %60 %42 %79 %64 + %81 = OpIAdd %15 %104 %39 + OpBranch %41 + %1000 = OpLabel + OpBranch %1001 + %1001 = OpLabel + OpBranch %43 + %43 = OpLabel + OpBranch %22 + %24 = OpLabel + %87 = OpCompositeExtract %6 %102 0 + %91 = OpConvertSToF %6 %103 + %92 = OpCompositeConstruct %7 %87 %11 %91 %10 + OpStore %85 %92 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + TransformationOutlineFunction transformation( + /*entry_block*/ 150, + /*exit_block*/ 1001, + /*new_function_struct_return_type_id*/ 200, + /*new_function_type_id*/ 201, + /*new_function_id*/ 202, + /*new_function_region_entry_block*/ 203, + /*new_caller_result_id*/ 204, + /*new_callee_result_id*/ 205, + /*input_id_to_fresh_id*/ {{102, 300}, {103, 301}, {40, 302}}, + /*output_id_to_fresh_id*/ {{106, 400}, {107, 401}}); + + ASSERT_TRUE(transformation.IsApplicable(context.get(), fact_manager)); + transformation.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" %85 + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %28 "buf" + OpMemberName %28 0 "u1" + OpMemberName %28 1 "u2" + OpName %30 "" + OpName %85 "color" + OpMemberDecorate %28 0 Offset 0 + OpMemberDecorate %28 1 Offset 4 + OpDecorate %28 Block + OpDecorate %30 DescriptorSet 0 + OpDecorate %30 Binding 0 + OpDecorate %85 Location 0 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypeVector %6 4 + %10 = OpConstant %6 1 + %11 = OpConstant %6 2 + %12 = OpConstant %6 3 + %13 = OpConstant %6 4 + %14 = OpConstantComposite %7 %10 %11 %12 %13 + %15 = OpTypeInt 32 1 + %18 = OpConstant %15 0 + %28 = OpTypeStruct %6 %6 + %29 = OpTypePointer Uniform %28 + %30 = OpVariable %29 Uniform + %31 = OpTypePointer Uniform %6 + %35 = OpTypeBool + %39 = OpConstant %15 1 + %84 = OpTypePointer Output %7 + %85 = OpVariable %84 Output + %114 = OpConstant %15 8 + %200 = OpTypeStruct %7 %15 + %201 = OpTypeFunction %200 %15 %7 %15 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpBranch %22 + %22 = OpLabel + %103 = OpPhi %15 %18 %5 %106 %43 + %102 = OpPhi %7 %14 %5 %107 %43 + %101 = OpPhi %15 %18 %5 %40 %43 + %32 = OpAccessChain %31 %30 %18 + %33 = OpLoad %6 %32 + %34 = OpConvertFToS %15 %33 + %36 = OpSLessThan %35 %101 %34 + OpLoopMerge %24 %43 None + OpBranchConditional %36 %23 %24 + %23 = OpLabel + %40 = OpIAdd %15 %101 %39 + OpBranch %150 + %150 = OpLabel + %204 = OpFunctionCall %200 %202 %103 %102 %40 + %107 = OpCompositeExtract %7 %204 0 + %106 = OpCompositeExtract %15 %204 1 + OpBranch %43 + %43 = OpLabel + OpBranch %22 + %24 = OpLabel + %87 = OpCompositeExtract %6 %102 0 + %91 = OpConvertSToF %6 %103 + %92 = OpCompositeConstruct %7 %87 %11 %91 %10 + OpStore %85 %92 + OpReturn + OpFunctionEnd + %202 = OpFunction %200 None %201 + %301 = OpFunctionParameter %15 + %300 = OpFunctionParameter %7 + %302 = OpFunctionParameter %15 + %203 = OpLabel + OpBranch %41 + %41 = OpLabel + %401 = OpPhi %7 %300 %203 %111 %65 + %400 = OpPhi %15 %301 %203 %110 %65 + %104 = OpPhi %15 %302 %203 %81 %65 + %47 = OpAccessChain %31 %30 %39 + %48 = OpLoad %6 %47 + %49 = OpConvertFToS %15 %48 + %50 = OpSLessThan %35 %104 %49 + OpLoopMerge %1000 %65 None + OpBranchConditional %50 %42 %1000 + %42 = OpLabel + %60 = OpIAdd %15 %400 %114 + %63 = OpSGreaterThan %35 %104 %60 + OpBranchConditional %63 %64 %65 + %64 = OpLabel + %71 = OpCompositeExtract %6 %401 0 + %72 = OpFAdd %6 %71 %11 + %97 = OpCompositeInsert %7 %72 %401 0 + %76 = OpCompositeExtract %6 %401 3 + %77 = OpConvertFToS %15 %76 + %79 = OpIAdd %15 %60 %77 + OpBranch %65 + %65 = OpLabel + %111 = OpPhi %7 %401 %42 %97 %64 + %110 = OpPhi %15 %60 %42 %79 %64 + %81 = OpIAdd %15 %104 %39 + OpBranch %41 + %1000 = OpLabel + OpBranch %1001 + %1001 = OpLabel + %205 = OpCompositeConstruct %200 %401 %400 + OpReturnValue %205 + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +TEST(TransformationOutlineFunctionTest, Miscellaneous2) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %21 = OpTypeBool + %167 = OpConstantTrue %21 + %168 = OpConstantFalse %21 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpBranch %34 + %34 = OpLabel + OpLoopMerge %36 %37 None + OpBranchConditional %168 %37 %38 + %38 = OpLabel + OpBranchConditional %168 %37 %36 + %37 = OpLabel + OpBranch %34 + %36 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_5; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + TransformationOutlineFunction transformation( + /*entry_block*/ 38, + /*exit_block*/ 36, + /*new_function_struct_return_type_id*/ 200, + /*new_function_type_id*/ 201, + /*new_function_id*/ 202, + /*new_function_region_entry_block*/ 203, + /*new_caller_result_id*/ 204, + /*new_callee_result_id*/ 205, + /*input_id_to_fresh_id*/ {}, + /*output_id_to_fresh_id*/ {}); + + ASSERT_FALSE(transformation.IsApplicable(context.get(), fact_manager)); +} + +TEST(TransformationOutlineFunctionTest, Miscellaneous3) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %6 "main" + OpExecutionMode %6 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %21 = OpTypeBool + %167 = OpConstantTrue %21 + %6 = OpFunction %2 None %3 + %7 = OpLabel + OpBranch %80 + %80 = OpLabel + OpBranch %14 + %14 = OpLabel + OpLoopMerge %16 %17 None + OpBranch %18 + %18 = OpLabel + OpBranchConditional %167 %15 %16 + %15 = OpLabel + OpBranch %17 + %16 = OpLabel + OpBranch %81 + %81 = OpLabel + OpReturn + %17 = OpLabel + OpBranch %14 + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_5; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + TransformationOutlineFunction transformation( + /*entry_block*/ 80, + /*exit_block*/ 81, + /*new_function_struct_return_type_id*/ 300, + /*new_function_type_id*/ 301, + /*new_function_id*/ 302, + /*new_function_region_entry_block*/ 304, + /*new_caller_result_id*/ 305, + /*new_callee_result_id*/ 306, + /*input_id_to_fresh_id*/ {}, + /*output_id_to_fresh_id*/ {}); + + ASSERT_TRUE(transformation.IsApplicable(context.get(), fact_manager)); + transformation.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %6 "main" + OpExecutionMode %6 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %21 = OpTypeBool + %167 = OpConstantTrue %21 + %6 = OpFunction %2 None %3 + %7 = OpLabel + OpBranch %80 + %80 = OpLabel + %305 = OpFunctionCall %2 %302 + OpReturn + OpFunctionEnd + %302 = OpFunction %2 None %3 + %304 = OpLabel + OpBranch %14 + %14 = OpLabel + OpLoopMerge %16 %17 None + OpBranch %18 + %18 = OpLabel + OpBranchConditional %167 %15 %16 + %15 = OpLabel + OpBranch %17 + %16 = OpLabel + OpBranch %81 + %81 = OpLabel + OpReturn + %17 = OpLabel + OpBranch %14 + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +TEST(TransformationOutlineFunctionTest, Miscellaneous4) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %6 "main" + OpExecutionMode %6 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %21 = OpTypeBool + %100 = OpTypeInt 32 0 + %101 = OpTypePointer Function %100 + %102 = OpTypePointer Function %100 + %103 = OpTypeFunction %2 %101 + %6 = OpFunction %2 None %3 + %7 = OpLabel + %104 = OpVariable %102 Function + OpBranch %80 + %80 = OpLabel + %105 = OpLoad %100 %104 + OpBranch %106 + %106 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_5; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + TransformationOutlineFunction transformation( + /*entry_block*/ 80, + /*exit_block*/ 106, + /*new_function_struct_return_type_id*/ 300, + /*new_function_type_id*/ 301, + /*new_function_id*/ 302, + /*new_function_region_entry_block*/ 304, + /*new_caller_result_id*/ 305, + /*new_callee_result_id*/ 306, + /*input_id_to_fresh_id*/ {{104, 307}}, + /*output_id_to_fresh_id*/ {}); + + ASSERT_TRUE(transformation.IsApplicable(context.get(), fact_manager)); + transformation.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %6 "main" + OpExecutionMode %6 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %21 = OpTypeBool + %100 = OpTypeInt 32 0 + %101 = OpTypePointer Function %100 + %102 = OpTypePointer Function %100 + %103 = OpTypeFunction %2 %101 + %301 = OpTypeFunction %2 %102 + %6 = OpFunction %2 None %3 + %7 = OpLabel + %104 = OpVariable %102 Function + OpBranch %80 + %80 = OpLabel + %305 = OpFunctionCall %2 %302 %104 + OpReturn + OpFunctionEnd + %302 = OpFunction %2 None %301 + %307 = OpFunctionParameter %102 + %304 = OpLabel + %105 = OpLoad %100 %307 + OpBranch %106 + %106 = OpLabel + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +} // namespace +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/test/fuzz/transformation_replace_boolean_constant_with_constant_binary_test.cpp b/third_party/spirv-tools/test/fuzz/transformation_replace_boolean_constant_with_constant_binary_test.cpp new file mode 100644 index 0000000000..bfc7fa77cb --- /dev/null +++ b/third_party/spirv-tools/test/fuzz/transformation_replace_boolean_constant_with_constant_binary_test.cpp @@ -0,0 +1,655 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_replace_boolean_constant_with_constant_binary.h" + +#include "source/fuzz/fuzzer_util.h" +#include "source/fuzz/id_use_descriptor.h" +#include "source/fuzz/instruction_descriptor.h" +#include "test/fuzz/fuzz_test_util.h" + +namespace spvtools { +namespace fuzz { +namespace { + +TEST(TransformationReplaceBooleanConstantWithConstantBinaryTest, + BasicReplacements) { + // The test came from the following pseudo-GLSL, where int64 and uint64 denote + // 64-bit integer types (they were replaced with int and uint during + // translation to SPIR-V, and the generated SPIR-V has been doctored to + // accommodate them). + // + // #version 450 + // + // void main() { + // double d1, d2; + // d1 = 1.0; + // d2 = 2.0; + // float f1, f2; + // f1 = 4.0; + // f2 = 8.0; + // int i1, i2; + // i1 = 100; + // i2 = 200; + // + // uint u1, u2; + // u1 = 300u; + // u2 = 400u; + // + // int64 i64_1, i64_2; + // i64_1 = 500; + // i64_2 = 600; + // + // uint64 u64_1, u64_2; + // u64_1 = 700u; + // u64_2 = 800u; + // + // bool b, c, d, e; + // b = true; + // c = false; + // d = true || c; + // c = c && false; + // } + std::string shader = R"( + OpCapability Shader + OpCapability Float64 + OpCapability Int64 + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource GLSL 450 + OpName %4 "main" + OpName %8 "d1" + OpName %10 "d2" + OpName %14 "f1" + OpName %16 "f2" + OpName %20 "i1" + OpName %22 "i2" + OpName %26 "u1" + OpName %28 "u2" + OpName %30 "i64_1" + OpName %32 "i64_2" + OpName %34 "u64_1" + OpName %36 "u64_2" + OpName %40 "b" + OpName %42 "c" + OpName %44 "d" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 64 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 1 + %11 = OpConstant %6 2 + %12 = OpTypeFloat 32 + %13 = OpTypePointer Function %12 + %15 = OpConstant %12 4 + %17 = OpConstant %12 8 + %18 = OpTypeInt 32 1 + %60 = OpTypeInt 64 1 + %61 = OpTypePointer Function %60 + %19 = OpTypePointer Function %18 + %21 = OpConstant %18 -100 + %23 = OpConstant %18 200 + %24 = OpTypeInt 32 0 + %62 = OpTypeInt 64 0 + %63 = OpTypePointer Function %62 + %25 = OpTypePointer Function %24 + %27 = OpConstant %24 300 + %29 = OpConstant %24 400 + %31 = OpConstant %60 -600 + %33 = OpConstant %60 -500 + %35 = OpConstant %62 700 + %37 = OpConstant %62 800 + %38 = OpTypeBool + %39 = OpTypePointer Function %38 + %41 = OpConstantTrue %38 + %43 = OpConstantFalse %38 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %10 = OpVariable %7 Function + %14 = OpVariable %13 Function + %16 = OpVariable %13 Function + %20 = OpVariable %19 Function + %22 = OpVariable %19 Function + %26 = OpVariable %25 Function + %28 = OpVariable %25 Function + %30 = OpVariable %61 Function + %32 = OpVariable %61 Function + %34 = OpVariable %63 Function + %36 = OpVariable %63 Function + %40 = OpVariable %39 Function + %42 = OpVariable %39 Function + %44 = OpVariable %39 Function + OpStore %8 %9 + OpStore %10 %11 + OpStore %14 %15 + OpStore %16 %17 + OpStore %20 %21 + OpStore %22 %23 + OpStore %26 %27 + OpStore %28 %29 + OpStore %30 %31 + OpStore %32 %33 + OpStore %34 %35 + OpStore %36 %37 + OpStore %40 %41 + OpStore %42 %43 + %45 = OpLoad %38 %42 + %46 = OpLogicalOr %38 %41 %45 + OpStore %44 %46 + %47 = OpLoad %38 %42 + %48 = OpLogicalAnd %38 %47 %43 + OpStore %42 %48 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + std::vector uses_of_true = { + MakeIdUseDescriptor(41, MakeInstructionDescriptor(44, SpvOpStore, 12), 1), + MakeIdUseDescriptor(41, MakeInstructionDescriptor(46, SpvOpLogicalOr, 0), + 0)}; + + std::vector uses_of_false = { + MakeIdUseDescriptor(43, MakeInstructionDescriptor(44, SpvOpStore, 13), 1), + MakeIdUseDescriptor(43, MakeInstructionDescriptor(48, SpvOpLogicalAnd, 0), + 1)}; + + const uint32_t fresh_id = 100; + + std::vector fp_gt_opcodes = { + SpvOpFOrdGreaterThan, SpvOpFOrdGreaterThanEqual, SpvOpFUnordGreaterThan, + SpvOpFUnordGreaterThanEqual}; + + std::vector fp_lt_opcodes = {SpvOpFOrdLessThan, SpvOpFOrdLessThanEqual, + SpvOpFUnordLessThan, + SpvOpFUnordLessThanEqual}; + + std::vector int_gt_opcodes = {SpvOpSGreaterThan, + SpvOpSGreaterThanEqual}; + + std::vector int_lt_opcodes = {SpvOpSLessThan, SpvOpSLessThanEqual}; + + std::vector uint_gt_opcodes = {SpvOpUGreaterThan, + SpvOpUGreaterThanEqual}; + + std::vector uint_lt_opcodes = {SpvOpULessThan, SpvOpULessThanEqual}; + +#define CHECK_OPERATOR(USE_DESCRIPTOR, LHS_ID, RHS_ID, OPCODE, FRESH_ID) \ + ASSERT_TRUE(TransformationReplaceBooleanConstantWithConstantBinary( \ + USE_DESCRIPTOR, LHS_ID, RHS_ID, OPCODE, FRESH_ID) \ + .IsApplicable(context.get(), fact_manager)); \ + ASSERT_FALSE(TransformationReplaceBooleanConstantWithConstantBinary( \ + USE_DESCRIPTOR, RHS_ID, LHS_ID, OPCODE, FRESH_ID) \ + .IsApplicable(context.get(), fact_manager)); + +#define CHECK_TRANSFORMATION_APPLICABILITY(GT_OPCODES, LT_OPCODES, SMALL_ID, \ + LARGE_ID) \ + for (auto gt_opcode : GT_OPCODES) { \ + for (auto& true_use : uses_of_true) { \ + CHECK_OPERATOR(true_use, LARGE_ID, SMALL_ID, gt_opcode, fresh_id); \ + } \ + for (auto& false_use : uses_of_false) { \ + CHECK_OPERATOR(false_use, SMALL_ID, LARGE_ID, gt_opcode, fresh_id); \ + } \ + } \ + for (auto lt_opcode : LT_OPCODES) { \ + for (auto& true_use : uses_of_true) { \ + CHECK_OPERATOR(true_use, SMALL_ID, LARGE_ID, lt_opcode, fresh_id); \ + } \ + for (auto& false_use : uses_of_false) { \ + CHECK_OPERATOR(false_use, LARGE_ID, SMALL_ID, lt_opcode, fresh_id); \ + } \ + } + + // Float + { CHECK_TRANSFORMATION_APPLICABILITY(fp_gt_opcodes, fp_lt_opcodes, 15, 17); } + + // Double + { CHECK_TRANSFORMATION_APPLICABILITY(fp_gt_opcodes, fp_lt_opcodes, 9, 11); } + + // Int32 + { + CHECK_TRANSFORMATION_APPLICABILITY(int_gt_opcodes, int_lt_opcodes, 21, 23); + } + + // Int64 + { + CHECK_TRANSFORMATION_APPLICABILITY(int_gt_opcodes, int_lt_opcodes, 31, 33); + } + + // Uint32 + { + CHECK_TRANSFORMATION_APPLICABILITY(uint_gt_opcodes, uint_lt_opcodes, 27, + 29); + } + + // Uint64 + { + CHECK_TRANSFORMATION_APPLICABILITY(uint_gt_opcodes, uint_lt_opcodes, 35, + 37); + } + + // Target id is not fresh + ASSERT_FALSE(TransformationReplaceBooleanConstantWithConstantBinary( + uses_of_true[0], 15, 17, SpvOpFOrdLessThan, 15) + .IsApplicable(context.get(), fact_manager)); + + // LHS id does not exist + ASSERT_FALSE(TransformationReplaceBooleanConstantWithConstantBinary( + uses_of_true[0], 300, 17, SpvOpFOrdLessThan, 200) + .IsApplicable(context.get(), fact_manager)); + + // RHS id does not exist + ASSERT_FALSE(TransformationReplaceBooleanConstantWithConstantBinary( + uses_of_true[0], 15, 300, SpvOpFOrdLessThan, 200) + .IsApplicable(context.get(), fact_manager)); + + // LHS and RHS ids do not match type + ASSERT_FALSE(TransformationReplaceBooleanConstantWithConstantBinary( + uses_of_true[0], 11, 17, SpvOpFOrdLessThan, 200) + .IsApplicable(context.get(), fact_manager)); + + // Opcode not appropriate + ASSERT_FALSE(TransformationReplaceBooleanConstantWithConstantBinary( + uses_of_true[0], 15, 17, SpvOpFDiv, 200) + .IsApplicable(context.get(), fact_manager)); + + auto replace_true_with_double_comparison = + TransformationReplaceBooleanConstantWithConstantBinary( + uses_of_true[0], 11, 9, SpvOpFUnordGreaterThan, 100); + auto replace_true_with_uint32_comparison = + TransformationReplaceBooleanConstantWithConstantBinary( + uses_of_true[1], 27, 29, SpvOpULessThanEqual, 101); + auto replace_false_with_float_comparison = + TransformationReplaceBooleanConstantWithConstantBinary( + uses_of_false[0], 17, 15, SpvOpFOrdLessThan, 102); + auto replace_false_with_sint64_comparison = + TransformationReplaceBooleanConstantWithConstantBinary( + uses_of_false[1], 33, 31, SpvOpSLessThan, 103); + + ASSERT_TRUE(replace_true_with_double_comparison.IsApplicable(context.get(), + fact_manager)); + replace_true_with_double_comparison.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + ASSERT_TRUE(replace_true_with_uint32_comparison.IsApplicable(context.get(), + fact_manager)); + replace_true_with_uint32_comparison.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + ASSERT_TRUE(replace_false_with_float_comparison.IsApplicable(context.get(), + fact_manager)); + replace_false_with_float_comparison.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + ASSERT_TRUE(replace_false_with_sint64_comparison.IsApplicable(context.get(), + fact_manager)); + replace_false_with_sint64_comparison.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + std::string after = R"( + OpCapability Shader + OpCapability Float64 + OpCapability Int64 + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource GLSL 450 + OpName %4 "main" + OpName %8 "d1" + OpName %10 "d2" + OpName %14 "f1" + OpName %16 "f2" + OpName %20 "i1" + OpName %22 "i2" + OpName %26 "u1" + OpName %28 "u2" + OpName %30 "i64_1" + OpName %32 "i64_2" + OpName %34 "u64_1" + OpName %36 "u64_2" + OpName %40 "b" + OpName %42 "c" + OpName %44 "d" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 64 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 1 + %11 = OpConstant %6 2 + %12 = OpTypeFloat 32 + %13 = OpTypePointer Function %12 + %15 = OpConstant %12 4 + %17 = OpConstant %12 8 + %18 = OpTypeInt 32 1 + %60 = OpTypeInt 64 1 + %61 = OpTypePointer Function %60 + %19 = OpTypePointer Function %18 + %21 = OpConstant %18 -100 + %23 = OpConstant %18 200 + %24 = OpTypeInt 32 0 + %62 = OpTypeInt 64 0 + %63 = OpTypePointer Function %62 + %25 = OpTypePointer Function %24 + %27 = OpConstant %24 300 + %29 = OpConstant %24 400 + %31 = OpConstant %60 -600 + %33 = OpConstant %60 -500 + %35 = OpConstant %62 700 + %37 = OpConstant %62 800 + %38 = OpTypeBool + %39 = OpTypePointer Function %38 + %41 = OpConstantTrue %38 + %43 = OpConstantFalse %38 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %10 = OpVariable %7 Function + %14 = OpVariable %13 Function + %16 = OpVariable %13 Function + %20 = OpVariable %19 Function + %22 = OpVariable %19 Function + %26 = OpVariable %25 Function + %28 = OpVariable %25 Function + %30 = OpVariable %61 Function + %32 = OpVariable %61 Function + %34 = OpVariable %63 Function + %36 = OpVariable %63 Function + %40 = OpVariable %39 Function + %42 = OpVariable %39 Function + %44 = OpVariable %39 Function + OpStore %8 %9 + OpStore %10 %11 + OpStore %14 %15 + OpStore %16 %17 + OpStore %20 %21 + OpStore %22 %23 + OpStore %26 %27 + OpStore %28 %29 + OpStore %30 %31 + OpStore %32 %33 + OpStore %34 %35 + OpStore %36 %37 + %100 = OpFUnordGreaterThan %38 %11 %9 + OpStore %40 %100 + %102 = OpFOrdLessThan %38 %17 %15 + OpStore %42 %102 + %45 = OpLoad %38 %42 + %101 = OpULessThanEqual %38 %27 %29 + %46 = OpLogicalOr %38 %101 %45 + OpStore %44 %46 + %47 = OpLoad %38 %42 + %103 = OpSLessThan %38 %33 %31 + %48 = OpLogicalAnd %38 %47 %103 + OpStore %42 %48 + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after, context.get())); + + if (std::numeric_limits::has_quiet_NaN) { + double quiet_nan_double = std::numeric_limits::quiet_NaN(); + uint32_t words[2]; + memcpy(words, &quiet_nan_double, sizeof(double)); + opt::Instruction::OperandList operands = { + {SPV_OPERAND_TYPE_LITERAL_INTEGER, {words[0]}}, + {SPV_OPERAND_TYPE_LITERAL_INTEGER, {words[1]}}}; + context->module()->AddGlobalValue(MakeUnique( + context.get(), SpvOpConstant, 6, 200, operands)); + fuzzerutil::UpdateModuleIdBound(context.get(), 200); + ASSERT_TRUE(IsValid(env, context.get())); + // The transformation is not applicable because %200 is NaN. + ASSERT_FALSE(TransformationReplaceBooleanConstantWithConstantBinary( + uses_of_true[0], 11, 200, SpvOpFOrdLessThan, 300) + .IsApplicable(context.get(), fact_manager)); + } + if (std::numeric_limits::has_infinity) { + double positive_infinity_double = std::numeric_limits::infinity(); + uint32_t words[2]; + memcpy(words, &positive_infinity_double, sizeof(double)); + opt::Instruction::OperandList operands = { + {SPV_OPERAND_TYPE_LITERAL_INTEGER, {words[0]}}, + {SPV_OPERAND_TYPE_LITERAL_INTEGER, {words[1]}}}; + context->module()->AddGlobalValue(MakeUnique( + context.get(), SpvOpConstant, 6, 201, operands)); + fuzzerutil::UpdateModuleIdBound(context.get(), 201); + ASSERT_TRUE(IsValid(env, context.get())); + // Even though the double constant %11 is less than the infinity %201, the + // transformation is restricted to only apply to finite values. + ASSERT_FALSE(TransformationReplaceBooleanConstantWithConstantBinary( + uses_of_true[0], 11, 201, SpvOpFOrdLessThan, 300) + .IsApplicable(context.get(), fact_manager)); + } + if (std::numeric_limits::has_infinity) { + float positive_infinity_float = std::numeric_limits::infinity(); + float negative_infinity_float = -1 * positive_infinity_float; + uint32_t words_positive_infinity[1]; + uint32_t words_negative_infinity[1]; + memcpy(words_positive_infinity, &positive_infinity_float, sizeof(float)); + memcpy(words_negative_infinity, &negative_infinity_float, sizeof(float)); + opt::Instruction::OperandList operands_positive_infinity = { + {SPV_OPERAND_TYPE_LITERAL_INTEGER, {words_positive_infinity[0]}}}; + context->module()->AddGlobalValue(MakeUnique( + context.get(), SpvOpConstant, 12, 202, operands_positive_infinity)); + fuzzerutil::UpdateModuleIdBound(context.get(), 202); + opt::Instruction::OperandList operands = { + {SPV_OPERAND_TYPE_LITERAL_INTEGER, {words_negative_infinity[0]}}}; + context->module()->AddGlobalValue(MakeUnique( + context.get(), SpvOpConstant, 12, 203, operands)); + fuzzerutil::UpdateModuleIdBound(context.get(), 203); + ASSERT_TRUE(IsValid(env, context.get())); + // Even though the negative infinity at %203 is less than the positive + // infinity %202, the transformation is restricted to only apply to finite + // values. + ASSERT_FALSE(TransformationReplaceBooleanConstantWithConstantBinary( + uses_of_true[0], 203, 202, SpvOpFOrdLessThan, 300) + .IsApplicable(context.get(), fact_manager)); + } +} + +TEST(TransformationReplaceBooleanConstantWithConstantBinaryTest, + MergeInstructions) { + // The test came from the following GLSL: + // + // void main() { + // int x = 1; + // int y = 2; + // if (true) { + // x = 2; + // } + // while(false) { + // y = 2; + // } + // } + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource GLSL 450 + OpName %4 "main" + OpName %8 "x" + OpName %10 "y" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 1 + %11 = OpConstant %6 2 + %12 = OpTypeBool + %13 = OpConstantTrue %12 + %21 = OpConstantFalse %12 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %10 = OpVariable %7 Function + OpStore %8 %9 + OpStore %10 %11 + OpSelectionMerge %15 None + OpBranchConditional %13 %14 %15 + %14 = OpLabel + OpStore %8 %11 + OpBranch %15 + %15 = OpLabel + OpBranch %16 + %16 = OpLabel + OpLoopMerge %18 %19 None + OpBranchConditional %21 %17 %18 + %17 = OpLabel + OpStore %10 %11 + OpBranch %19 + %19 = OpLabel + OpBranch %16 + %18 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + auto use_of_true_in_if = MakeIdUseDescriptor( + 13, MakeInstructionDescriptor(10, SpvOpBranchConditional, 0), 0); + auto use_of_false_in_while = MakeIdUseDescriptor( + 21, MakeInstructionDescriptor(16, SpvOpBranchConditional, 0), 0); + + auto replacement_1 = TransformationReplaceBooleanConstantWithConstantBinary( + use_of_true_in_if, 9, 11, SpvOpSLessThan, 100); + auto replacement_2 = TransformationReplaceBooleanConstantWithConstantBinary( + use_of_false_in_while, 9, 11, SpvOpSGreaterThanEqual, 101); + + ASSERT_TRUE(replacement_1.IsApplicable(context.get(), fact_manager)); + replacement_1.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(replacement_2.IsApplicable(context.get(), fact_manager)); + replacement_2.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + std::string after = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource GLSL 450 + OpName %4 "main" + OpName %8 "x" + OpName %10 "y" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 1 + %11 = OpConstant %6 2 + %12 = OpTypeBool + %13 = OpConstantTrue %12 + %21 = OpConstantFalse %12 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %10 = OpVariable %7 Function + OpStore %8 %9 + OpStore %10 %11 + %100 = OpSLessThan %12 %9 %11 + OpSelectionMerge %15 None + OpBranchConditional %100 %14 %15 + %14 = OpLabel + OpStore %8 %11 + OpBranch %15 + %15 = OpLabel + OpBranch %16 + %16 = OpLabel + %101 = OpSGreaterThanEqual %12 %9 %11 + OpLoopMerge %18 %19 None + OpBranchConditional %101 %17 %18 + %17 = OpLabel + OpStore %10 %11 + OpBranch %19 + %19 = OpLabel + OpBranch %16 + %18 = OpLabel + OpReturn + OpFunctionEnd + )"; + + ASSERT_TRUE(IsEqual(env, after, context.get())); +} + +TEST(TransformationReplaceBooleanConstantWithConstantBinaryTest, OpPhi) { + // Hand-written SPIR-V to check applicability of the transformation on an + // OpPhi argument. + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeBool + %7 = OpTypePointer Function %6 + %9 = OpConstantTrue %6 + %16 = OpConstantFalse %6 + %10 = OpTypeInt 32 1 + %11 = OpTypePointer Function %10 + %13 = OpConstant %10 0 + %15 = OpConstant %10 1 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpSelectionMerge %20 None + OpBranchConditional %9 %21 %22 + %21 = OpLabel + OpBranch %20 + %22 = OpLabel + OpBranch %20 + %20 = OpLabel + %23 = OpPhi %6 %9 %21 %16 %22 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + auto replacement = TransformationReplaceBooleanConstantWithConstantBinary( + MakeIdUseDescriptor(9, MakeInstructionDescriptor(23, SpvOpPhi, 0), 0), 13, + 15, SpvOpSLessThan, 100); + + ASSERT_FALSE(replacement.IsApplicable(context.get(), fact_manager)); +} + +} // namespace +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/test/fuzz/transformation_replace_constant_with_uniform_test.cpp b/third_party/spirv-tools/test/fuzz/transformation_replace_constant_with_uniform_test.cpp new file mode 100644 index 0000000000..ac2e3f9a63 --- /dev/null +++ b/third_party/spirv-tools/test/fuzz/transformation_replace_constant_with_uniform_test.cpp @@ -0,0 +1,1447 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_replace_constant_with_uniform.h" +#include "source/fuzz/instruction_descriptor.h" +#include "source/fuzz/uniform_buffer_element_descriptor.h" +#include "test/fuzz/fuzz_test_util.h" + +namespace spvtools { +namespace fuzz { +namespace { + +bool AddFactHelper( + FactManager* fact_manager, opt::IRContext* context, uint32_t word, + const protobufs::UniformBufferElementDescriptor& descriptor) { + protobufs::FactConstantUniform constant_uniform_fact; + constant_uniform_fact.add_constant_word(word); + *constant_uniform_fact.mutable_uniform_buffer_element_descriptor() = + descriptor; + protobufs::Fact fact; + *fact.mutable_constant_uniform_fact() = constant_uniform_fact; + return fact_manager->AddFact(fact, context); +} + +TEST(TransformationReplaceConstantWithUniformTest, BasicReplacements) { + // This test came from the following GLSL: + // + // #version 450 + // + // uniform blockname { + // int a; + // int b; + // int c; + // }; + // + // void main() + // { + // int x; + // x = 1; + // x = x + 2; + // x = 3 + x; + // } + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource GLSL 450 + OpName %4 "main" + OpName %8 "x" + OpName %16 "blockname" + OpMemberName %16 0 "a" + OpMemberName %16 1 "b" + OpMemberName %16 2 "c" + OpName %18 "" + OpMemberDecorate %16 0 Offset 0 + OpMemberDecorate %16 1 Offset 4 + OpMemberDecorate %16 2 Offset 8 + OpDecorate %16 Block + OpDecorate %18 DescriptorSet 0 + OpDecorate %18 Binding 0 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %50 = OpConstant %6 0 + %9 = OpConstant %6 1 + %11 = OpConstant %6 2 + %14 = OpConstant %6 3 + %16 = OpTypeStruct %6 %6 %6 + %17 = OpTypePointer Uniform %16 + %51 = OpTypePointer Uniform %6 + %18 = OpVariable %17 Uniform + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + OpStore %8 %9 + %10 = OpLoad %6 %8 + %12 = OpIAdd %6 %10 %11 + OpStore %8 %12 + %13 = OpLoad %6 %8 + %15 = OpIAdd %6 %14 %13 + OpStore %8 %15 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + protobufs::UniformBufferElementDescriptor blockname_a = + MakeUniformBufferElementDescriptor(0, 0, {0}); + protobufs::UniformBufferElementDescriptor blockname_b = + MakeUniformBufferElementDescriptor(0, 0, {1}); + protobufs::UniformBufferElementDescriptor blockname_c = + MakeUniformBufferElementDescriptor(0, 0, {2}); + + ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), 1, blockname_a)); + ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), 2, blockname_b)); + ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), 3, blockname_c)); + + // The constant ids are 9, 11 and 14, for 1, 2 and 3 respectively. + protobufs::IdUseDescriptor use_of_9_in_store = + MakeIdUseDescriptor(9, MakeInstructionDescriptor(8, SpvOpStore, 0), 1); + protobufs::IdUseDescriptor use_of_11_in_add = + MakeIdUseDescriptor(11, MakeInstructionDescriptor(12, SpvOpIAdd, 0), 1); + protobufs::IdUseDescriptor use_of_14_in_add = + MakeIdUseDescriptor(14, MakeInstructionDescriptor(15, SpvOpIAdd, 0), 0); + + // These transformations work: they match the facts. + auto transformation_use_of_9_in_store = + TransformationReplaceConstantWithUniform(use_of_9_in_store, blockname_a, + 100, 101); + ASSERT_TRUE(transformation_use_of_9_in_store.IsApplicable(context.get(), + fact_manager)); + auto transformation_use_of_11_in_add = + TransformationReplaceConstantWithUniform(use_of_11_in_add, blockname_b, + 102, 103); + ASSERT_TRUE(transformation_use_of_11_in_add.IsApplicable(context.get(), + fact_manager)); + auto transformation_use_of_14_in_add = + TransformationReplaceConstantWithUniform(use_of_14_in_add, blockname_c, + 104, 105); + ASSERT_TRUE(transformation_use_of_14_in_add.IsApplicable(context.get(), + fact_manager)); + + // The transformations are not applicable if we change which uniforms are + // applied to which constants. + ASSERT_FALSE(TransformationReplaceConstantWithUniform(use_of_9_in_store, + blockname_b, 101, 102) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(TransformationReplaceConstantWithUniform(use_of_11_in_add, + blockname_c, 101, 102) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(TransformationReplaceConstantWithUniform(use_of_14_in_add, + blockname_a, 101, 102) + .IsApplicable(context.get(), fact_manager)); + + // The following transformations do not apply because the uniform descriptors + // are not sensible. + protobufs::UniformBufferElementDescriptor nonsense_uniform_descriptor1 = + MakeUniformBufferElementDescriptor(1, 2, {0}); + protobufs::UniformBufferElementDescriptor nonsense_uniform_descriptor2 = + MakeUniformBufferElementDescriptor(0, 0, {5}); + ASSERT_FALSE(TransformationReplaceConstantWithUniform( + use_of_9_in_store, nonsense_uniform_descriptor1, 101, 102) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(TransformationReplaceConstantWithUniform( + use_of_9_in_store, nonsense_uniform_descriptor2, 101, 102) + .IsApplicable(context.get(), fact_manager)); + + // The following transformation does not apply because the id descriptor is + // not sensible. + protobufs::IdUseDescriptor nonsense_id_use_descriptor = + MakeIdUseDescriptor(9, MakeInstructionDescriptor(15, SpvOpIAdd, 0), 0); + ASSERT_FALSE(TransformationReplaceConstantWithUniform( + nonsense_id_use_descriptor, blockname_a, 101, 102) + .IsApplicable(context.get(), fact_manager)); + + // The following transformations do not apply because the ids are not fresh. + ASSERT_FALSE(TransformationReplaceConstantWithUniform(use_of_11_in_add, + blockname_b, 15, 103) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(TransformationReplaceConstantWithUniform(use_of_11_in_add, + blockname_b, 102, 15) + .IsApplicable(context.get(), fact_manager)); + + // Apply the use of 9 in a store. + transformation_use_of_9_in_store.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + std::string after_replacing_use_of_9_in_store = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource GLSL 450 + OpName %4 "main" + OpName %8 "x" + OpName %16 "blockname" + OpMemberName %16 0 "a" + OpMemberName %16 1 "b" + OpMemberName %16 2 "c" + OpName %18 "" + OpMemberDecorate %16 0 Offset 0 + OpMemberDecorate %16 1 Offset 4 + OpMemberDecorate %16 2 Offset 8 + OpDecorate %16 Block + OpDecorate %18 DescriptorSet 0 + OpDecorate %18 Binding 0 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %50 = OpConstant %6 0 + %9 = OpConstant %6 1 + %11 = OpConstant %6 2 + %14 = OpConstant %6 3 + %16 = OpTypeStruct %6 %6 %6 + %17 = OpTypePointer Uniform %16 + %51 = OpTypePointer Uniform %6 + %18 = OpVariable %17 Uniform + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %100 = OpAccessChain %51 %18 %50 + %101 = OpLoad %6 %100 + OpStore %8 %101 + %10 = OpLoad %6 %8 + %12 = OpIAdd %6 %10 %11 + OpStore %8 %12 + %13 = OpLoad %6 %8 + %15 = OpIAdd %6 %14 %13 + OpStore %8 %15 + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_replacing_use_of_9_in_store, context.get())); + + ASSERT_TRUE(transformation_use_of_11_in_add.IsApplicable(context.get(), + fact_manager)); + // Apply the use of 11 in an add. + transformation_use_of_11_in_add.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + std::string after_replacing_use_of_11_in_add = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource GLSL 450 + OpName %4 "main" + OpName %8 "x" + OpName %16 "blockname" + OpMemberName %16 0 "a" + OpMemberName %16 1 "b" + OpMemberName %16 2 "c" + OpName %18 "" + OpMemberDecorate %16 0 Offset 0 + OpMemberDecorate %16 1 Offset 4 + OpMemberDecorate %16 2 Offset 8 + OpDecorate %16 Block + OpDecorate %18 DescriptorSet 0 + OpDecorate %18 Binding 0 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %50 = OpConstant %6 0 + %9 = OpConstant %6 1 + %11 = OpConstant %6 2 + %14 = OpConstant %6 3 + %16 = OpTypeStruct %6 %6 %6 + %17 = OpTypePointer Uniform %16 + %51 = OpTypePointer Uniform %6 + %18 = OpVariable %17 Uniform + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %100 = OpAccessChain %51 %18 %50 + %101 = OpLoad %6 %100 + OpStore %8 %101 + %10 = OpLoad %6 %8 + %102 = OpAccessChain %51 %18 %9 + %103 = OpLoad %6 %102 + %12 = OpIAdd %6 %10 %103 + OpStore %8 %12 + %13 = OpLoad %6 %8 + %15 = OpIAdd %6 %14 %13 + OpStore %8 %15 + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_replacing_use_of_11_in_add, context.get())); + + ASSERT_TRUE(transformation_use_of_14_in_add.IsApplicable(context.get(), + fact_manager)); + // Apply the use of 15 in an add. + transformation_use_of_14_in_add.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + std::string after_replacing_use_of_14_in_add = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource GLSL 450 + OpName %4 "main" + OpName %8 "x" + OpName %16 "blockname" + OpMemberName %16 0 "a" + OpMemberName %16 1 "b" + OpMemberName %16 2 "c" + OpName %18 "" + OpMemberDecorate %16 0 Offset 0 + OpMemberDecorate %16 1 Offset 4 + OpMemberDecorate %16 2 Offset 8 + OpDecorate %16 Block + OpDecorate %18 DescriptorSet 0 + OpDecorate %18 Binding 0 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %50 = OpConstant %6 0 + %9 = OpConstant %6 1 + %11 = OpConstant %6 2 + %14 = OpConstant %6 3 + %16 = OpTypeStruct %6 %6 %6 + %17 = OpTypePointer Uniform %16 + %51 = OpTypePointer Uniform %6 + %18 = OpVariable %17 Uniform + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %100 = OpAccessChain %51 %18 %50 + %101 = OpLoad %6 %100 + OpStore %8 %101 + %10 = OpLoad %6 %8 + %102 = OpAccessChain %51 %18 %9 + %103 = OpLoad %6 %102 + %12 = OpIAdd %6 %10 %103 + OpStore %8 %12 + %13 = OpLoad %6 %8 + %104 = OpAccessChain %51 %18 %11 + %105 = OpLoad %6 %104 + %15 = OpIAdd %6 %105 %13 + OpStore %8 %15 + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_replacing_use_of_14_in_add, context.get())); +} + +TEST(TransformationReplaceConstantWithUniformTest, NestedStruct) { + // This test came from the following GLSL: + // + // #version 450 + // + // struct U { + // int x; // == 4 + // }; + // + // struct T { + // int x; // == 3 + // U y; + // }; + // + // struct S { + // T x; + // int y; // == 2 + // }; + // + // uniform blockname { + // int x; // == 1 + // S y; + // }; + // + // void foo(int a) { } + // + // void main() + // { + // int x; + // x = 1; + // x = x + 2; + // x = 3 + x; + // foo(4); + // } + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource GLSL 450 + OpName %4 "main" + OpName %10 "foo(i1;" + OpName %9 "a" + OpName %12 "x" + OpName %21 "param" + OpName %23 "U" + OpMemberName %23 0 "x" + OpName %24 "T" + OpMemberName %24 0 "x" + OpMemberName %24 1 "y" + OpName %25 "S" + OpMemberName %25 0 "x" + OpMemberName %25 1 "y" + OpName %26 "blockname" + OpMemberName %26 0 "x" + OpMemberName %26 1 "y" + OpName %28 "" + OpMemberDecorate %23 0 Offset 0 + OpMemberDecorate %24 0 Offset 0 + OpMemberDecorate %24 1 Offset 16 + OpMemberDecorate %25 0 Offset 0 + OpMemberDecorate %25 1 Offset 32 + OpMemberDecorate %26 0 Offset 0 + OpMemberDecorate %26 1 Offset 16 + OpDecorate %26 Block + OpDecorate %28 DescriptorSet 0 + OpDecorate %28 Binding 0 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %8 = OpTypeFunction %2 %7 + %50 = OpConstant %6 0 + %13 = OpConstant %6 1 + %15 = OpConstant %6 2 + %17 = OpConstant %6 3 + %20 = OpConstant %6 4 + %23 = OpTypeStruct %6 + %24 = OpTypeStruct %6 %23 + %25 = OpTypeStruct %24 %6 + %26 = OpTypeStruct %6 %25 + %27 = OpTypePointer Uniform %26 + %51 = OpTypePointer Uniform %6 + %28 = OpVariable %27 Uniform + %4 = OpFunction %2 None %3 + %5 = OpLabel + %12 = OpVariable %7 Function + %21 = OpVariable %7 Function + OpStore %12 %13 + %14 = OpLoad %6 %12 + %16 = OpIAdd %6 %14 %15 + OpStore %12 %16 + %18 = OpLoad %6 %12 + %19 = OpIAdd %6 %17 %18 + OpStore %12 %19 + OpStore %21 %20 + %22 = OpFunctionCall %2 %10 %21 + OpReturn + OpFunctionEnd + %10 = OpFunction %2 None %8 + %9 = OpFunctionParameter %7 + %11 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + protobufs::UniformBufferElementDescriptor blockname_1 = + MakeUniformBufferElementDescriptor(0, 0, {0}); + protobufs::UniformBufferElementDescriptor blockname_2 = + MakeUniformBufferElementDescriptor(0, 0, {1, 1}); + protobufs::UniformBufferElementDescriptor blockname_3 = + MakeUniformBufferElementDescriptor(0, 0, {1, 0, 0}); + protobufs::UniformBufferElementDescriptor blockname_4 = + MakeUniformBufferElementDescriptor(0, 0, {1, 0, 1, 0}); + + ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), 1, blockname_1)); + ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), 2, blockname_2)); + ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), 3, blockname_3)); + ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), 4, blockname_4)); + + // The constant ids are 13, 15, 17 and 20, for 1, 2, 3 and 4 respectively. + protobufs::IdUseDescriptor use_of_13_in_store = + MakeIdUseDescriptor(13, MakeInstructionDescriptor(21, SpvOpStore, 0), 1); + protobufs::IdUseDescriptor use_of_15_in_add = + MakeIdUseDescriptor(15, MakeInstructionDescriptor(16, SpvOpIAdd, 0), 1); + protobufs::IdUseDescriptor use_of_17_in_add = + MakeIdUseDescriptor(17, MakeInstructionDescriptor(19, SpvOpIAdd, 0), 0); + protobufs::IdUseDescriptor use_of_20_in_store = + MakeIdUseDescriptor(20, MakeInstructionDescriptor(19, SpvOpStore, 1), 1); + + // These transformations work: they match the facts. + auto transformation_use_of_13_in_store = + TransformationReplaceConstantWithUniform(use_of_13_in_store, blockname_1, + 100, 101); + ASSERT_TRUE(transformation_use_of_13_in_store.IsApplicable(context.get(), + fact_manager)); + auto transformation_use_of_15_in_add = + TransformationReplaceConstantWithUniform(use_of_15_in_add, blockname_2, + 102, 103); + ASSERT_TRUE(transformation_use_of_15_in_add.IsApplicable(context.get(), + fact_manager)); + auto transformation_use_of_17_in_add = + TransformationReplaceConstantWithUniform(use_of_17_in_add, blockname_3, + 104, 105); + ASSERT_TRUE(transformation_use_of_17_in_add.IsApplicable(context.get(), + fact_manager)); + auto transformation_use_of_20_in_store = + TransformationReplaceConstantWithUniform(use_of_20_in_store, blockname_4, + 106, 107); + ASSERT_TRUE(transformation_use_of_20_in_store.IsApplicable(context.get(), + fact_manager)); + + ASSERT_TRUE(transformation_use_of_13_in_store.IsApplicable(context.get(), + fact_manager)); + ASSERT_TRUE(transformation_use_of_15_in_add.IsApplicable(context.get(), + fact_manager)); + ASSERT_TRUE(transformation_use_of_17_in_add.IsApplicable(context.get(), + fact_manager)); + ASSERT_TRUE(transformation_use_of_20_in_store.IsApplicable(context.get(), + fact_manager)); + + transformation_use_of_13_in_store.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + ASSERT_FALSE(transformation_use_of_13_in_store.IsApplicable(context.get(), + fact_manager)); + ASSERT_TRUE(transformation_use_of_15_in_add.IsApplicable(context.get(), + fact_manager)); + ASSERT_TRUE(transformation_use_of_17_in_add.IsApplicable(context.get(), + fact_manager)); + ASSERT_TRUE(transformation_use_of_20_in_store.IsApplicable(context.get(), + fact_manager)); + + transformation_use_of_15_in_add.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + ASSERT_FALSE(transformation_use_of_13_in_store.IsApplicable(context.get(), + fact_manager)); + ASSERT_FALSE(transformation_use_of_15_in_add.IsApplicable(context.get(), + fact_manager)); + ASSERT_TRUE(transformation_use_of_17_in_add.IsApplicable(context.get(), + fact_manager)); + ASSERT_TRUE(transformation_use_of_20_in_store.IsApplicable(context.get(), + fact_manager)); + + transformation_use_of_17_in_add.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + ASSERT_FALSE(transformation_use_of_13_in_store.IsApplicable(context.get(), + fact_manager)); + ASSERT_FALSE(transformation_use_of_15_in_add.IsApplicable(context.get(), + fact_manager)); + ASSERT_FALSE(transformation_use_of_17_in_add.IsApplicable(context.get(), + fact_manager)); + ASSERT_TRUE(transformation_use_of_20_in_store.IsApplicable(context.get(), + fact_manager)); + + transformation_use_of_20_in_store.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + ASSERT_FALSE(transformation_use_of_13_in_store.IsApplicable(context.get(), + fact_manager)); + ASSERT_FALSE(transformation_use_of_15_in_add.IsApplicable(context.get(), + fact_manager)); + ASSERT_FALSE(transformation_use_of_17_in_add.IsApplicable(context.get(), + fact_manager)); + ASSERT_FALSE(transformation_use_of_20_in_store.IsApplicable(context.get(), + fact_manager)); + + std::string after = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource GLSL 450 + OpName %4 "main" + OpName %10 "foo(i1;" + OpName %9 "a" + OpName %12 "x" + OpName %21 "param" + OpName %23 "U" + OpMemberName %23 0 "x" + OpName %24 "T" + OpMemberName %24 0 "x" + OpMemberName %24 1 "y" + OpName %25 "S" + OpMemberName %25 0 "x" + OpMemberName %25 1 "y" + OpName %26 "blockname" + OpMemberName %26 0 "x" + OpMemberName %26 1 "y" + OpName %28 "" + OpMemberDecorate %23 0 Offset 0 + OpMemberDecorate %24 0 Offset 0 + OpMemberDecorate %24 1 Offset 16 + OpMemberDecorate %25 0 Offset 0 + OpMemberDecorate %25 1 Offset 32 + OpMemberDecorate %26 0 Offset 0 + OpMemberDecorate %26 1 Offset 16 + OpDecorate %26 Block + OpDecorate %28 DescriptorSet 0 + OpDecorate %28 Binding 0 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %8 = OpTypeFunction %2 %7 + %50 = OpConstant %6 0 + %13 = OpConstant %6 1 + %15 = OpConstant %6 2 + %17 = OpConstant %6 3 + %20 = OpConstant %6 4 + %23 = OpTypeStruct %6 + %24 = OpTypeStruct %6 %23 + %25 = OpTypeStruct %24 %6 + %26 = OpTypeStruct %6 %25 + %27 = OpTypePointer Uniform %26 + %51 = OpTypePointer Uniform %6 + %28 = OpVariable %27 Uniform + %4 = OpFunction %2 None %3 + %5 = OpLabel + %12 = OpVariable %7 Function + %21 = OpVariable %7 Function + %100 = OpAccessChain %51 %28 %50 + %101 = OpLoad %6 %100 + OpStore %12 %101 + %14 = OpLoad %6 %12 + %102 = OpAccessChain %51 %28 %13 %13 + %103 = OpLoad %6 %102 + %16 = OpIAdd %6 %14 %103 + OpStore %12 %16 + %18 = OpLoad %6 %12 + %104 = OpAccessChain %51 %28 %13 %50 %50 + %105 = OpLoad %6 %104 + %19 = OpIAdd %6 %105 %18 + OpStore %12 %19 + %106 = OpAccessChain %51 %28 %13 %50 %13 %50 + %107 = OpLoad %6 %106 + OpStore %21 %107 + %22 = OpFunctionCall %2 %10 %21 + OpReturn + OpFunctionEnd + %10 = OpFunction %2 None %8 + %9 = OpFunctionParameter %7 + %11 = OpLabel + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after, context.get())); +} + +TEST(TransformationReplaceConstantWithUniformTest, NoUniformIntPointerPresent) { + // This test came from the following GLSL: + // + // #version 450 + // + // uniform blockname { + // int x; // == 0 + // }; + // + // void main() + // { + // int a; + // a = 0; + // } + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource GLSL 450 + OpName %4 "main" + OpName %8 "a" + OpName %10 "blockname" + OpMemberName %10 0 "x" + OpName %12 "" + OpMemberDecorate %10 0 Offset 0 + OpDecorate %10 Block + OpDecorate %12 DescriptorSet 0 + OpDecorate %12 Binding 0 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 0 + %10 = OpTypeStruct %6 + %11 = OpTypePointer Uniform %10 + %12 = OpVariable %11 Uniform + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + OpStore %8 %9 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + protobufs::UniformBufferElementDescriptor blockname_0 = + MakeUniformBufferElementDescriptor(0, 0, {0}); + + ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), 0, blockname_0)); + + // The constant id is 9 for 0. + protobufs::IdUseDescriptor use_of_9_in_store = + MakeIdUseDescriptor(9, MakeInstructionDescriptor(8, SpvOpStore, 0), 1); + + // This transformation is not available because no uniform pointer to integer + // type is present: + ASSERT_FALSE(TransformationReplaceConstantWithUniform(use_of_9_in_store, + blockname_0, 100, 101) + .IsApplicable(context.get(), fact_manager)); +} + +TEST(TransformationReplaceConstantWithUniformTest, NoConstantPresentForIndex) { + // This test came from the following GLSL: + // + // #version 450 + // + // uniform blockname { + // int x; // == 0 + // int y; // == 9 + // }; + // + // void main() + // { + // int a; + // a = 9; + // } + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource GLSL 450 + OpName %4 "main" + OpName %8 "a" + OpName %10 "blockname" + OpMemberName %10 0 "x" + OpMemberName %10 1 "y" + OpName %12 "" + OpMemberDecorate %10 0 Offset 0 + OpMemberDecorate %10 1 Offset 4 + OpDecorate %10 Block + OpDecorate %12 DescriptorSet 0 + OpDecorate %12 Binding 0 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 9 + %10 = OpTypeStruct %6 %6 + %11 = OpTypePointer Uniform %10 + %50 = OpTypePointer Uniform %6 + %12 = OpVariable %11 Uniform + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + OpStore %8 %9 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + protobufs::UniformBufferElementDescriptor blockname_0 = + MakeUniformBufferElementDescriptor(0, 0, {0}); + protobufs::UniformBufferElementDescriptor blockname_9 = + MakeUniformBufferElementDescriptor(0, 0, {1}); + + ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), 9, blockname_9)); + + // The constant id is 9 for 9. + protobufs::IdUseDescriptor use_of_9_in_store = + MakeIdUseDescriptor(9, MakeInstructionDescriptor(8, SpvOpStore, 0), 1); + + // This transformation is not available because no constant is present for the + // index 1 required to index into the uniform buffer: + ASSERT_FALSE(TransformationReplaceConstantWithUniform(use_of_9_in_store, + blockname_9, 100, 101) + .IsApplicable(context.get(), fact_manager)); +} + +TEST(TransformationReplaceConstantWithUniformTest, + NoIntTypePresentToEnableIndexing) { + // This test came from the following GLSL: + // + // #version 450 + // + // uniform blockname { + // float f; // == 9 + // }; + // + // void main() + // { + // float a; + // a = 3.0; + // } + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource GLSL 450 + OpName %4 "main" + OpName %8 "a" + OpName %10 "blockname" + OpMemberName %10 0 "f" + OpName %12 "" + OpMemberDecorate %10 0 Offset 0 + OpDecorate %10 Block + OpDecorate %12 DescriptorSet 0 + OpDecorate %12 Binding 0 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 3 + %10 = OpTypeStruct %6 + %11 = OpTypePointer Uniform %10 + %12 = OpVariable %11 Uniform + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + OpStore %8 %9 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + protobufs::UniformBufferElementDescriptor blockname_3 = + MakeUniformBufferElementDescriptor(0, 0, {0}); + + uint32_t float_data[1]; + float temp = 3.0; + memcpy(&float_data[0], &temp, sizeof(float)); + ASSERT_TRUE( + AddFactHelper(&fact_manager, context.get(), float_data[0], blockname_3)); + + // The constant id is 9 for 3.0. + protobufs::IdUseDescriptor use_of_9_in_store = + MakeIdUseDescriptor(9, MakeInstructionDescriptor(8, SpvOpStore, 0), 1); + + // This transformation is not available because no integer type is present to + // allow a constant index to be expressed: + ASSERT_FALSE(TransformationReplaceConstantWithUniform(use_of_9_in_store, + blockname_3, 100, 101) + .IsApplicable(context.get(), fact_manager)); +} + +TEST(TransformationReplaceConstantWithUniformTest, + UniformFactsDoNotMatchConstants) { + // This test came from the following GLSL: + // + // #version 450 + // + // uniform blockname { + // int x; // == 9 + // int y; // == 10 + // }; + // + // void main() + // { + // int a; + // int b; + // a = 9; + // b = 10; + // } + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource GLSL 450 + OpName %4 "main" + OpName %8 "a" + OpName %10 "b" + OpName %12 "blockname" + OpMemberName %12 0 "x" + OpMemberName %12 1 "y" + OpName %14 "" + OpMemberDecorate %12 0 Offset 0 + OpMemberDecorate %12 1 Offset 4 + OpDecorate %12 Block + OpDecorate %14 DescriptorSet 0 + OpDecorate %14 Binding 0 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 9 + %11 = OpConstant %6 10 + %50 = OpConstant %6 0 + %51 = OpConstant %6 1 + %12 = OpTypeStruct %6 %6 + %13 = OpTypePointer Uniform %12 + %52 = OpTypePointer Uniform %6 + %14 = OpVariable %13 Uniform + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %10 = OpVariable %7 Function + OpStore %8 %9 + OpStore %10 %11 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + protobufs::UniformBufferElementDescriptor blockname_9 = + MakeUniformBufferElementDescriptor(0, 0, {0}); + protobufs::UniformBufferElementDescriptor blockname_10 = + MakeUniformBufferElementDescriptor(0, 0, {1}); + + ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), 9, blockname_9)); + ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), 10, blockname_10)); + + // The constant ids for 9 and 10 are 9 and 11 respectively + protobufs::IdUseDescriptor use_of_9_in_store = + MakeIdUseDescriptor(9, MakeInstructionDescriptor(10, SpvOpStore, 0), 1); + protobufs::IdUseDescriptor use_of_11_in_store = + MakeIdUseDescriptor(11, MakeInstructionDescriptor(10, SpvOpStore, 1), 1); + + // These are right: + ASSERT_TRUE(TransformationReplaceConstantWithUniform(use_of_9_in_store, + blockname_9, 100, 101) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(TransformationReplaceConstantWithUniform(use_of_11_in_store, + blockname_10, 102, 103) + .IsApplicable(context.get(), fact_manager)); + + // These are wrong because the constants do not match the facts about + // uniforms. + ASSERT_FALSE(TransformationReplaceConstantWithUniform(use_of_11_in_store, + blockname_9, 100, 101) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(TransformationReplaceConstantWithUniform(use_of_9_in_store, + blockname_10, 102, 103) + .IsApplicable(context.get(), fact_manager)); +} + +TEST(TransformationReplaceConstantWithUniformTest, ComplexReplacements) { + // The following GLSL was the basis for this test: + + // #version 450 + // + // struct T { + // float a[5]; // [1.0, 1.5, 1.75, 1.875, 1.9375] + // ivec4 b; // (1, 2, 3, 4) + // vec3 c; // (2.0, 2.5, 2.75) + // uint d; // 42u + // bool e; // Not used in test + // }; + // + // uniform block { + // T f; + // int g; // 22 + // uvec2 h; // (100u, 200u) + // }; + // + // void main() + // { + // T myT; + // + // myT.a[0] = 1.9375; + // myT.a[1] = 1.875; + // myT.a[2] = 1.75; + // myT.a[3] = 1.5; + // myT.a[4] = 1.0; + // + // myT.b.x = 4; + // myT.b.y = 3; + // myT.b.z = 2; + // myT.b.w = 1; + // + // myT.b.r = 22; + // + // myT.c[0] = 2.75; + // myT.c[0] = 2.5; + // myT.c[0] = 2.0; + // + // myT.d = 42u; + // myT.d = 100u; + // myT.d = 200u; + // + // myT.e = true; // No attempt to replace 'true' by a uniform value + // + // } + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource GLSL 450 + OpName %4 "main" + OpName %14 "T" + OpMemberName %14 0 "a" + OpMemberName %14 1 "b" + OpMemberName %14 2 "c" + OpMemberName %14 3 "d" + OpMemberName %14 4 "e" + OpName %16 "myT" + OpName %61 "T" + OpMemberName %61 0 "a" + OpMemberName %61 1 "b" + OpMemberName %61 2 "c" + OpMemberName %61 3 "d" + OpMemberName %61 4 "e" + OpName %63 "block" + OpMemberName %63 0 "f" + OpMemberName %63 1 "g" + OpMemberName %63 2 "h" + OpName %65 "" + OpDecorate %60 ArrayStride 16 + OpMemberDecorate %61 0 Offset 0 + OpMemberDecorate %61 1 Offset 80 + OpMemberDecorate %61 2 Offset 96 + OpMemberDecorate %61 3 Offset 108 + OpMemberDecorate %61 4 Offset 112 + OpMemberDecorate %63 0 Offset 0 + OpMemberDecorate %63 1 Offset 128 + OpMemberDecorate %63 2 Offset 136 + OpDecorate %63 Block + OpDecorate %65 DescriptorSet 0 + OpDecorate %65 Binding 0 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypeInt 32 0 + %8 = OpConstant %7 5 + %9 = OpTypeArray %6 %8 + %10 = OpTypeInt 32 1 + %11 = OpTypeVector %10 4 + %12 = OpTypeVector %6 3 + %13 = OpTypeBool + %14 = OpTypeStruct %9 %11 %12 %7 %13 + %15 = OpTypePointer Function %14 + %17 = OpConstant %10 0 + %18 = OpConstant %6 1.9375 + %19 = OpTypePointer Function %6 + %21 = OpConstant %10 1 + %22 = OpConstant %6 1.875 + %24 = OpConstant %10 2 + %25 = OpConstant %6 1.75 + %27 = OpConstant %10 3 + %28 = OpConstant %6 1.5 + %30 = OpConstant %10 4 + %31 = OpConstant %6 1 + %33 = OpConstant %7 0 + %34 = OpTypePointer Function %10 + %36 = OpConstant %7 1 + %38 = OpConstant %7 2 + %40 = OpConstant %7 3 + %42 = OpConstant %10 22 + %44 = OpConstant %6 2.75 + %46 = OpConstant %6 2.5 + %48 = OpConstant %6 2 + %50 = OpConstant %7 42 + %51 = OpTypePointer Function %7 + %53 = OpConstant %7 100 + %55 = OpConstant %7 200 + %57 = OpConstantTrue %13 + %58 = OpTypePointer Function %13 + %60 = OpTypeArray %6 %8 + %61 = OpTypeStruct %60 %11 %12 %7 %7 + %62 = OpTypeVector %7 2 + %63 = OpTypeStruct %61 %10 %62 + %64 = OpTypePointer Uniform %63 + %100 = OpTypePointer Uniform %10 + %101 = OpTypePointer Uniform %7 + %102 = OpTypePointer Uniform %6 + %103 = OpTypePointer Uniform %13 + %65 = OpVariable %64 Uniform + %4 = OpFunction %2 None %3 + %5 = OpLabel + %16 = OpVariable %15 Function + %20 = OpAccessChain %19 %16 %17 %17 + OpStore %20 %18 + %23 = OpAccessChain %19 %16 %17 %21 + OpStore %23 %22 + %26 = OpAccessChain %19 %16 %17 %24 + OpStore %26 %25 + %29 = OpAccessChain %19 %16 %17 %27 + OpStore %29 %28 + %32 = OpAccessChain %19 %16 %17 %30 + OpStore %32 %31 + %35 = OpAccessChain %34 %16 %21 %33 + OpStore %35 %30 + %37 = OpAccessChain %34 %16 %21 %36 + OpStore %37 %27 + %39 = OpAccessChain %34 %16 %21 %38 + OpStore %39 %24 + %41 = OpAccessChain %34 %16 %21 %40 + OpStore %41 %21 + %43 = OpAccessChain %34 %16 %21 %33 + OpStore %43 %42 + %45 = OpAccessChain %19 %16 %24 %33 + OpStore %45 %44 + %47 = OpAccessChain %19 %16 %24 %33 + OpStore %47 %46 + %49 = OpAccessChain %19 %16 %24 %33 + OpStore %49 %48 + %52 = OpAccessChain %51 %16 %27 + OpStore %52 %50 + %54 = OpAccessChain %51 %16 %27 + OpStore %54 %53 + %56 = OpAccessChain %51 %16 %27 + OpStore %56 %55 + %59 = OpAccessChain %58 %16 %30 + OpStore %59 %57 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + const float float_array_values[5] = {1.0, 1.5, 1.75, 1.875, 1.9375}; + uint32_t float_array_data[5]; + memcpy(&float_array_data, &float_array_values, sizeof(float_array_values)); + + const float float_vector_values[3] = {2.0, 2.5, 2.75}; + uint32_t float_vector_data[3]; + memcpy(&float_vector_data, &float_vector_values, sizeof(float_vector_values)); + + protobufs::UniformBufferElementDescriptor uniform_f_a_0 = + MakeUniformBufferElementDescriptor(0, 0, {0, 0, 0}); + protobufs::UniformBufferElementDescriptor uniform_f_a_1 = + MakeUniformBufferElementDescriptor(0, 0, {0, 0, 1}); + protobufs::UniformBufferElementDescriptor uniform_f_a_2 = + MakeUniformBufferElementDescriptor(0, 0, {0, 0, 2}); + protobufs::UniformBufferElementDescriptor uniform_f_a_3 = + MakeUniformBufferElementDescriptor(0, 0, {0, 0, 3}); + protobufs::UniformBufferElementDescriptor uniform_f_a_4 = + MakeUniformBufferElementDescriptor(0, 0, {0, 0, 4}); + + protobufs::UniformBufferElementDescriptor uniform_f_b_x = + MakeUniformBufferElementDescriptor(0, 0, {0, 1, 0}); + protobufs::UniformBufferElementDescriptor uniform_f_b_y = + MakeUniformBufferElementDescriptor(0, 0, {0, 1, 1}); + protobufs::UniformBufferElementDescriptor uniform_f_b_z = + MakeUniformBufferElementDescriptor(0, 0, {0, 1, 2}); + protobufs::UniformBufferElementDescriptor uniform_f_b_w = + MakeUniformBufferElementDescriptor(0, 0, {0, 1, 3}); + + protobufs::UniformBufferElementDescriptor uniform_f_c_x = + MakeUniformBufferElementDescriptor(0, 0, {0, 2, 0}); + protobufs::UniformBufferElementDescriptor uniform_f_c_y = + MakeUniformBufferElementDescriptor(0, 0, {0, 2, 1}); + protobufs::UniformBufferElementDescriptor uniform_f_c_z = + MakeUniformBufferElementDescriptor(0, 0, {0, 2, 2}); + + protobufs::UniformBufferElementDescriptor uniform_f_d = + MakeUniformBufferElementDescriptor(0, 0, {0, 3}); + + protobufs::UniformBufferElementDescriptor uniform_g = + MakeUniformBufferElementDescriptor(0, 0, {1}); + + protobufs::UniformBufferElementDescriptor uniform_h_x = + MakeUniformBufferElementDescriptor(0, 0, {2, 0}); + protobufs::UniformBufferElementDescriptor uniform_h_y = + MakeUniformBufferElementDescriptor(0, 0, {2, 1}); + + ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), float_array_data[0], + uniform_f_a_0)); + ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), float_array_data[1], + uniform_f_a_1)); + ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), float_array_data[2], + uniform_f_a_2)); + ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), float_array_data[3], + uniform_f_a_3)); + ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), float_array_data[4], + uniform_f_a_4)); + + ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), 1, uniform_f_b_x)); + ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), 2, uniform_f_b_y)); + ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), 3, uniform_f_b_z)); + ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), 4, uniform_f_b_w)); + + ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), float_vector_data[0], + uniform_f_c_x)); + ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), float_vector_data[1], + uniform_f_c_y)); + ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), float_vector_data[2], + uniform_f_c_z)); + + ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), 42, uniform_f_d)); + + ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), 22, uniform_g)); + + ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), 100, uniform_h_x)); + ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), 200, uniform_h_y)); + + std::vector transformations; + + transformations.emplace_back(TransformationReplaceConstantWithUniform( + MakeIdUseDescriptor(18, MakeInstructionDescriptor(20, SpvOpStore, 0), 1), + uniform_f_a_4, 200, 201)); + transformations.emplace_back(TransformationReplaceConstantWithUniform( + MakeIdUseDescriptor(22, MakeInstructionDescriptor(23, SpvOpStore, 0), 1), + uniform_f_a_3, 202, 203)); + transformations.emplace_back(TransformationReplaceConstantWithUniform( + MakeIdUseDescriptor(25, MakeInstructionDescriptor(26, SpvOpStore, 0), 1), + uniform_f_a_2, 204, 205)); + transformations.emplace_back(TransformationReplaceConstantWithUniform( + MakeIdUseDescriptor(28, MakeInstructionDescriptor(29, SpvOpStore, 0), 1), + uniform_f_a_1, 206, 207)); + transformations.emplace_back(TransformationReplaceConstantWithUniform( + MakeIdUseDescriptor(31, MakeInstructionDescriptor(32, SpvOpStore, 0), 1), + uniform_f_a_0, 208, 209)); + + transformations.emplace_back(TransformationReplaceConstantWithUniform( + MakeIdUseDescriptor(30, MakeInstructionDescriptor(35, SpvOpStore, 0), 1), + uniform_f_b_w, 210, 211)); + transformations.emplace_back(TransformationReplaceConstantWithUniform( + MakeIdUseDescriptor(27, MakeInstructionDescriptor(37, SpvOpStore, 0), 1), + uniform_f_b_z, 212, 213)); + transformations.emplace_back(TransformationReplaceConstantWithUniform( + MakeIdUseDescriptor(24, MakeInstructionDescriptor(39, SpvOpStore, 0), 1), + uniform_f_b_y, 214, 215)); + transformations.emplace_back(TransformationReplaceConstantWithUniform( + MakeIdUseDescriptor(21, MakeInstructionDescriptor(41, SpvOpStore, 0), 1), + uniform_f_b_x, 216, 217)); + + transformations.emplace_back(TransformationReplaceConstantWithUniform( + MakeIdUseDescriptor(44, MakeInstructionDescriptor(45, SpvOpStore, 0), 1), + uniform_f_c_z, 220, 221)); + transformations.emplace_back(TransformationReplaceConstantWithUniform( + MakeIdUseDescriptor(46, MakeInstructionDescriptor(47, SpvOpStore, 0), 1), + uniform_f_c_y, 222, 223)); + transformations.emplace_back(TransformationReplaceConstantWithUniform( + MakeIdUseDescriptor(48, MakeInstructionDescriptor(49, SpvOpStore, 0), 1), + uniform_f_c_x, 224, 225)); + + transformations.emplace_back(TransformationReplaceConstantWithUniform( + MakeIdUseDescriptor(50, MakeInstructionDescriptor(52, SpvOpStore, 0), 1), + uniform_f_d, 226, 227)); + + transformations.emplace_back(TransformationReplaceConstantWithUniform( + MakeIdUseDescriptor(53, MakeInstructionDescriptor(54, SpvOpStore, 0), 1), + uniform_h_x, 228, 229)); + transformations.emplace_back(TransformationReplaceConstantWithUniform( + MakeIdUseDescriptor(55, MakeInstructionDescriptor(56, SpvOpStore, 0), 1), + uniform_h_y, 230, 231)); + + transformations.emplace_back(TransformationReplaceConstantWithUniform( + MakeIdUseDescriptor(42, MakeInstructionDescriptor(43, SpvOpStore, 0), 1), + uniform_g, 218, 219)); + + for (auto& transformation : transformations) { + ASSERT_TRUE(transformation.IsApplicable(context.get(), fact_manager)); + transformation.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + } + + std::string after = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource GLSL 450 + OpName %4 "main" + OpName %14 "T" + OpMemberName %14 0 "a" + OpMemberName %14 1 "b" + OpMemberName %14 2 "c" + OpMemberName %14 3 "d" + OpMemberName %14 4 "e" + OpName %16 "myT" + OpName %61 "T" + OpMemberName %61 0 "a" + OpMemberName %61 1 "b" + OpMemberName %61 2 "c" + OpMemberName %61 3 "d" + OpMemberName %61 4 "e" + OpName %63 "block" + OpMemberName %63 0 "f" + OpMemberName %63 1 "g" + OpMemberName %63 2 "h" + OpName %65 "" + OpDecorate %60 ArrayStride 16 + OpMemberDecorate %61 0 Offset 0 + OpMemberDecorate %61 1 Offset 80 + OpMemberDecorate %61 2 Offset 96 + OpMemberDecorate %61 3 Offset 108 + OpMemberDecorate %61 4 Offset 112 + OpMemberDecorate %63 0 Offset 0 + OpMemberDecorate %63 1 Offset 128 + OpMemberDecorate %63 2 Offset 136 + OpDecorate %63 Block + OpDecorate %65 DescriptorSet 0 + OpDecorate %65 Binding 0 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypeInt 32 0 + %8 = OpConstant %7 5 + %9 = OpTypeArray %6 %8 + %10 = OpTypeInt 32 1 + %11 = OpTypeVector %10 4 + %12 = OpTypeVector %6 3 + %13 = OpTypeBool + %14 = OpTypeStruct %9 %11 %12 %7 %13 + %15 = OpTypePointer Function %14 + %17 = OpConstant %10 0 + %18 = OpConstant %6 1.9375 + %19 = OpTypePointer Function %6 + %21 = OpConstant %10 1 + %22 = OpConstant %6 1.875 + %24 = OpConstant %10 2 + %25 = OpConstant %6 1.75 + %27 = OpConstant %10 3 + %28 = OpConstant %6 1.5 + %30 = OpConstant %10 4 + %31 = OpConstant %6 1 + %33 = OpConstant %7 0 + %34 = OpTypePointer Function %10 + %36 = OpConstant %7 1 + %38 = OpConstant %7 2 + %40 = OpConstant %7 3 + %42 = OpConstant %10 22 + %44 = OpConstant %6 2.75 + %46 = OpConstant %6 2.5 + %48 = OpConstant %6 2 + %50 = OpConstant %7 42 + %51 = OpTypePointer Function %7 + %53 = OpConstant %7 100 + %55 = OpConstant %7 200 + %57 = OpConstantTrue %13 + %58 = OpTypePointer Function %13 + %60 = OpTypeArray %6 %8 + %61 = OpTypeStruct %60 %11 %12 %7 %7 + %62 = OpTypeVector %7 2 + %63 = OpTypeStruct %61 %10 %62 + %64 = OpTypePointer Uniform %63 + %100 = OpTypePointer Uniform %10 + %101 = OpTypePointer Uniform %7 + %102 = OpTypePointer Uniform %6 + %103 = OpTypePointer Uniform %13 + %65 = OpVariable %64 Uniform + %4 = OpFunction %2 None %3 + %5 = OpLabel + %16 = OpVariable %15 Function + %20 = OpAccessChain %19 %16 %17 %17 + %200 = OpAccessChain %102 %65 %17 %17 %30 + %201 = OpLoad %6 %200 + OpStore %20 %201 + %23 = OpAccessChain %19 %16 %17 %21 + %202 = OpAccessChain %102 %65 %17 %17 %27 + %203 = OpLoad %6 %202 + OpStore %23 %203 + %26 = OpAccessChain %19 %16 %17 %24 + %204 = OpAccessChain %102 %65 %17 %17 %24 + %205 = OpLoad %6 %204 + OpStore %26 %205 + %29 = OpAccessChain %19 %16 %17 %27 + %206 = OpAccessChain %102 %65 %17 %17 %21 + %207 = OpLoad %6 %206 + OpStore %29 %207 + %32 = OpAccessChain %19 %16 %17 %30 + %208 = OpAccessChain %102 %65 %17 %17 %17 + %209 = OpLoad %6 %208 + OpStore %32 %209 + %35 = OpAccessChain %34 %16 %21 %33 + %210 = OpAccessChain %100 %65 %17 %21 %27 + %211 = OpLoad %10 %210 + OpStore %35 %211 + %37 = OpAccessChain %34 %16 %21 %36 + %212 = OpAccessChain %100 %65 %17 %21 %24 + %213 = OpLoad %10 %212 + OpStore %37 %213 + %39 = OpAccessChain %34 %16 %21 %38 + %214 = OpAccessChain %100 %65 %17 %21 %21 + %215 = OpLoad %10 %214 + OpStore %39 %215 + %41 = OpAccessChain %34 %16 %21 %40 + %216 = OpAccessChain %100 %65 %17 %21 %17 + %217 = OpLoad %10 %216 + OpStore %41 %217 + %43 = OpAccessChain %34 %16 %21 %33 + %218 = OpAccessChain %100 %65 %21 + %219 = OpLoad %10 %218 + OpStore %43 %219 + %45 = OpAccessChain %19 %16 %24 %33 + %220 = OpAccessChain %102 %65 %17 %24 %24 + %221 = OpLoad %6 %220 + OpStore %45 %221 + %47 = OpAccessChain %19 %16 %24 %33 + %222 = OpAccessChain %102 %65 %17 %24 %21 + %223 = OpLoad %6 %222 + OpStore %47 %223 + %49 = OpAccessChain %19 %16 %24 %33 + %224 = OpAccessChain %102 %65 %17 %24 %17 + %225 = OpLoad %6 %224 + OpStore %49 %225 + %52 = OpAccessChain %51 %16 %27 + %226 = OpAccessChain %101 %65 %17 %27 + %227 = OpLoad %7 %226 + OpStore %52 %227 + %54 = OpAccessChain %51 %16 %27 + %228 = OpAccessChain %101 %65 %24 %17 + %229 = OpLoad %7 %228 + OpStore %54 %229 + %56 = OpAccessChain %51 %16 %27 + %230 = OpAccessChain %101 %65 %24 %21 + %231 = OpLoad %7 %230 + OpStore %56 %231 + %59 = OpAccessChain %58 %16 %30 + OpStore %59 %57 + OpReturn + OpFunctionEnd + )"; + + ASSERT_TRUE(IsEqual(env, after, context.get())); +} + +} // namespace +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/test/fuzz/transformation_replace_id_with_synonym_test.cpp b/third_party/spirv-tools/test/fuzz/transformation_replace_id_with_synonym_test.cpp new file mode 100644 index 0000000000..41b6116678 --- /dev/null +++ b/third_party/spirv-tools/test/fuzz/transformation_replace_id_with_synonym_test.cpp @@ -0,0 +1,1217 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_replace_id_with_synonym.h" +#include "source/fuzz/data_descriptor.h" +#include "source/fuzz/id_use_descriptor.h" +#include "source/fuzz/instruction_descriptor.h" +#include "test/fuzz/fuzz_test_util.h" + +namespace spvtools { +namespace fuzz { +namespace { + +// The following shader was obtained from this GLSL, which was then optimized +// with spirv-opt -O and manually edited to include some uses of OpCopyObject +// (to introduce id synonyms). +// +// #version 310 es +// +// precision highp int; +// precision highp float; +// +// layout(set = 0, binding = 0) uniform buf { +// int a; +// int b; +// int c; +// }; +// +// layout(location = 0) out vec4 color; +// +// void main() { +// int x = a; +// float f = 0.0; +// while (x < b) { +// switch(x % 4) { +// case 0: +// color[0] = f; +// break; +// case 1: +// color[1] = f; +// break; +// case 2: +// color[2] = f; +// break; +// case 3: +// color[3] = f; +// break; +// default: +// break; +// } +// if (x > c) { +// x++; +// } else { +// x += 2; +// } +// } +// color[0] += color[1] + float(x); +// } +const std::string kComplexShader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" %42 + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %9 "buf" + OpMemberName %9 0 "a" + OpMemberName %9 1 "b" + OpMemberName %9 2 "c" + OpName %11 "" + OpName %42 "color" + OpMemberDecorate %9 0 Offset 0 + OpMemberDecorate %9 1 Offset 4 + OpMemberDecorate %9 2 Offset 8 + OpDecorate %9 Block + OpDecorate %11 DescriptorSet 0 + OpDecorate %11 Binding 0 + OpDecorate %42 Location 0 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %9 = OpTypeStruct %6 %6 %6 + %10 = OpTypePointer Uniform %9 + %11 = OpVariable %10 Uniform + %12 = OpConstant %6 0 + %13 = OpTypePointer Uniform %6 + %16 = OpTypeFloat 32 + %19 = OpConstant %16 0 + %26 = OpConstant %6 1 + %29 = OpTypeBool + %32 = OpConstant %6 4 + %40 = OpTypeVector %16 4 + %41 = OpTypePointer Output %40 + %42 = OpVariable %41 Output + %44 = OpTypeInt 32 0 + %45 = OpConstant %44 0 + %46 = OpTypePointer Output %16 + %50 = OpConstant %44 1 + %54 = OpConstant %44 2 + %58 = OpConstant %44 3 + %64 = OpConstant %6 2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %209 = OpCopyObject %6 %12 + %14 = OpAccessChain %13 %11 %12 + %15 = OpLoad %6 %14 + %200 = OpCopyObject %6 %15 + OpBranch %20 + %20 = OpLabel + %84 = OpPhi %6 %15 %5 %86 %69 + %27 = OpAccessChain %13 %11 %26 + %28 = OpLoad %6 %27 + %207 = OpCopyObject %6 %84 + %201 = OpCopyObject %6 %15 + %30 = OpSLessThan %29 %84 %28 + OpLoopMerge %22 %69 None + OpBranchConditional %30 %21 %22 + %21 = OpLabel + %33 = OpSMod %6 %84 %32 + %208 = OpCopyObject %6 %33 + OpSelectionMerge %39 None + OpSwitch %33 %38 0 %34 1 %35 2 %36 3 %37 + %38 = OpLabel + %202 = OpCopyObject %6 %15 + OpBranch %39 + %34 = OpLabel + %210 = OpCopyObject %16 %19 + %47 = OpAccessChain %46 %42 %45 + OpStore %47 %19 + OpBranch %39 + %35 = OpLabel + %51 = OpAccessChain %46 %42 %50 + OpStore %51 %19 + OpBranch %39 + %36 = OpLabel + %204 = OpCopyObject %44 %54 + %55 = OpAccessChain %46 %42 %54 + %203 = OpCopyObject %46 %55 + OpStore %55 %19 + OpBranch %39 + %37 = OpLabel + %59 = OpAccessChain %46 %42 %58 + OpStore %59 %19 + OpBranch %39 + %39 = OpLabel + %300 = OpIAdd %6 %15 %15 + %65 = OpAccessChain %13 %11 %64 + %66 = OpLoad %6 %65 + %67 = OpSGreaterThan %29 %84 %66 + OpSelectionMerge %1000 None + OpBranchConditional %67 %68 %72 + %68 = OpLabel + %71 = OpIAdd %6 %84 %26 + OpBranch %1000 + %72 = OpLabel + %74 = OpIAdd %6 %84 %64 + %205 = OpCopyObject %6 %74 + OpBranch %1000 + %1000 = OpLabel + %86 = OpPhi %6 %71 %68 %74 %72 + %301 = OpPhi %6 %71 %68 %15 %72 + OpBranch %69 + %69 = OpLabel + OpBranch %20 + %22 = OpLabel + %75 = OpAccessChain %46 %42 %50 + %76 = OpLoad %16 %75 + %78 = OpConvertSToF %16 %84 + %80 = OpAccessChain %46 %42 %45 + %206 = OpCopyObject %16 %78 + %81 = OpLoad %16 %80 + %79 = OpFAdd %16 %76 %78 + %82 = OpFAdd %16 %81 %79 + OpStore %80 %82 + OpReturn + OpFunctionEnd +)"; + +protobufs::Fact MakeSynonymFact(uint32_t first, uint32_t second) { + protobufs::FactDataSynonym data_synonym_fact; + *data_synonym_fact.mutable_data1() = MakeDataDescriptor(first, {}); + *data_synonym_fact.mutable_data2() = MakeDataDescriptor(second, {}); + protobufs::Fact result; + *result.mutable_data_synonym_fact() = data_synonym_fact; + return result; +} + +// Equips the fact manager with synonym facts for the above shader. +void SetUpIdSynonyms(FactManager* fact_manager, opt::IRContext* context) { + fact_manager->AddFact(MakeSynonymFact(15, 200), context); + fact_manager->AddFact(MakeSynonymFact(15, 201), context); + fact_manager->AddFact(MakeSynonymFact(15, 202), context); + fact_manager->AddFact(MakeSynonymFact(55, 203), context); + fact_manager->AddFact(MakeSynonymFact(54, 204), context); + fact_manager->AddFact(MakeSynonymFact(74, 205), context); + fact_manager->AddFact(MakeSynonymFact(78, 206), context); + fact_manager->AddFact(MakeSynonymFact(84, 207), context); + fact_manager->AddFact(MakeSynonymFact(33, 208), context); + fact_manager->AddFact(MakeSynonymFact(12, 209), context); + fact_manager->AddFact(MakeSynonymFact(19, 210), context); +} + +TEST(TransformationReplaceIdWithSynonymTest, IllegalTransformations) { + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = + BuildModule(env, consumer, kComplexShader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + SetUpIdSynonyms(&fact_manager, context.get()); + + // %202 cannot replace %15 as in-operand 0 of %300, since %202 does not + // dominate %300. + auto synonym_does_not_dominate_use = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor(15, MakeInstructionDescriptor(300, SpvOpIAdd, 0), 0), + 202); + ASSERT_FALSE( + synonym_does_not_dominate_use.IsApplicable(context.get(), fact_manager)); + + // %202 cannot replace %15 as in-operand 2 of %301, since this is the OpPhi's + // incoming value for block %72, and %202 does not dominate %72. + auto synonym_does_not_dominate_use_op_phi = + TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor(15, MakeInstructionDescriptor(301, SpvOpPhi, 0), + 2), + 202); + ASSERT_FALSE(synonym_does_not_dominate_use_op_phi.IsApplicable(context.get(), + fact_manager)); + + // %200 is not a synonym for %84 + auto id_in_use_is_not_synonymous = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor( + 84, MakeInstructionDescriptor(67, SpvOpSGreaterThan, 0), 0), + 200); + ASSERT_FALSE( + id_in_use_is_not_synonymous.IsApplicable(context.get(), fact_manager)); + + // %86 is not a synonym for anything (and in particular not for %74) + auto id_has_no_synonyms = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor(86, MakeInstructionDescriptor(84, SpvOpPhi, 0), 2), + 74); + ASSERT_FALSE(id_has_no_synonyms.IsApplicable(context.get(), fact_manager)); + + // This would lead to %207 = 'OpCopyObject %type %207' if it were allowed + auto synonym_use_is_in_synonym_definition = + TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor( + 84, MakeInstructionDescriptor(207, SpvOpCopyObject, 0), 0), + 207); + ASSERT_FALSE(synonym_use_is_in_synonym_definition.IsApplicable(context.get(), + fact_manager)); + + // The id use descriptor does not lead to a use (%84 is not used in the + // definition of %207) + auto bad_id_use_descriptor = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor( + 84, MakeInstructionDescriptor(200, SpvOpCopyObject, 0), 0), + 207); + ASSERT_FALSE(bad_id_use_descriptor.IsApplicable(context.get(), fact_manager)); + + // This replacement would lead to an access chain into a struct using a + // non-constant index. + auto bad_access_chain = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor( + 12, MakeInstructionDescriptor(14, SpvOpAccessChain, 0), 1), + 209); + ASSERT_FALSE(bad_access_chain.IsApplicable(context.get(), fact_manager)); +} + +TEST(TransformationReplaceIdWithSynonymTest, LegalTransformations) { + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = + BuildModule(env, consumer, kComplexShader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + SetUpIdSynonyms(&fact_manager, context.get()); + + auto global_constant_synonym = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor(19, MakeInstructionDescriptor(47, SpvOpStore, 0), 1), + 210); + ASSERT_TRUE( + global_constant_synonym.IsApplicable(context.get(), fact_manager)); + global_constant_synonym.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + auto replace_vector_access_chain_index = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor( + 54, MakeInstructionDescriptor(55, SpvOpAccessChain, 0), 1), + 204); + ASSERT_TRUE(replace_vector_access_chain_index.IsApplicable(context.get(), + fact_manager)); + replace_vector_access_chain_index.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + // This is an interesting case because it replaces something that is being + // copied with something that is already a synonym. + auto regular_replacement = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor( + 15, MakeInstructionDescriptor(202, SpvOpCopyObject, 0), 0), + 201); + ASSERT_TRUE(regular_replacement.IsApplicable(context.get(), fact_manager)); + regular_replacement.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + auto regular_replacement2 = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor(55, MakeInstructionDescriptor(203, SpvOpStore, 0), 0), + 203); + ASSERT_TRUE(regular_replacement2.IsApplicable(context.get(), fact_manager)); + regular_replacement2.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + auto good_op_phi = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor(74, MakeInstructionDescriptor(86, SpvOpPhi, 0), 2), + 205); + ASSERT_TRUE(good_op_phi.IsApplicable(context.get(), fact_manager)); + good_op_phi.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + const std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" %42 + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %9 "buf" + OpMemberName %9 0 "a" + OpMemberName %9 1 "b" + OpMemberName %9 2 "c" + OpName %11 "" + OpName %42 "color" + OpMemberDecorate %9 0 Offset 0 + OpMemberDecorate %9 1 Offset 4 + OpMemberDecorate %9 2 Offset 8 + OpDecorate %9 Block + OpDecorate %11 DescriptorSet 0 + OpDecorate %11 Binding 0 + OpDecorate %42 Location 0 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %9 = OpTypeStruct %6 %6 %6 + %10 = OpTypePointer Uniform %9 + %11 = OpVariable %10 Uniform + %12 = OpConstant %6 0 + %13 = OpTypePointer Uniform %6 + %16 = OpTypeFloat 32 + %19 = OpConstant %16 0 + %26 = OpConstant %6 1 + %29 = OpTypeBool + %32 = OpConstant %6 4 + %40 = OpTypeVector %16 4 + %41 = OpTypePointer Output %40 + %42 = OpVariable %41 Output + %44 = OpTypeInt 32 0 + %45 = OpConstant %44 0 + %46 = OpTypePointer Output %16 + %50 = OpConstant %44 1 + %54 = OpConstant %44 2 + %58 = OpConstant %44 3 + %64 = OpConstant %6 2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %209 = OpCopyObject %6 %12 + %14 = OpAccessChain %13 %11 %12 + %15 = OpLoad %6 %14 + %200 = OpCopyObject %6 %15 + OpBranch %20 + %20 = OpLabel + %84 = OpPhi %6 %15 %5 %86 %69 + %27 = OpAccessChain %13 %11 %26 + %28 = OpLoad %6 %27 + %207 = OpCopyObject %6 %84 + %201 = OpCopyObject %6 %15 + %30 = OpSLessThan %29 %84 %28 + OpLoopMerge %22 %69 None + OpBranchConditional %30 %21 %22 + %21 = OpLabel + %33 = OpSMod %6 %84 %32 + %208 = OpCopyObject %6 %33 + OpSelectionMerge %39 None + OpSwitch %33 %38 0 %34 1 %35 2 %36 3 %37 + %38 = OpLabel + %202 = OpCopyObject %6 %201 + OpBranch %39 + %34 = OpLabel + %210 = OpCopyObject %16 %19 + %47 = OpAccessChain %46 %42 %45 + OpStore %47 %210 + OpBranch %39 + %35 = OpLabel + %51 = OpAccessChain %46 %42 %50 + OpStore %51 %19 + OpBranch %39 + %36 = OpLabel + %204 = OpCopyObject %44 %54 + %55 = OpAccessChain %46 %42 %204 + %203 = OpCopyObject %46 %55 + OpStore %203 %19 + OpBranch %39 + %37 = OpLabel + %59 = OpAccessChain %46 %42 %58 + OpStore %59 %19 + OpBranch %39 + %39 = OpLabel + %300 = OpIAdd %6 %15 %15 + %65 = OpAccessChain %13 %11 %64 + %66 = OpLoad %6 %65 + %67 = OpSGreaterThan %29 %84 %66 + OpSelectionMerge %1000 None + OpBranchConditional %67 %68 %72 + %68 = OpLabel + %71 = OpIAdd %6 %84 %26 + OpBranch %1000 + %72 = OpLabel + %74 = OpIAdd %6 %84 %64 + %205 = OpCopyObject %6 %74 + OpBranch %1000 + %1000 = OpLabel + %86 = OpPhi %6 %71 %68 %205 %72 + %301 = OpPhi %6 %71 %68 %15 %72 + OpBranch %69 + %69 = OpLabel + OpBranch %20 + %22 = OpLabel + %75 = OpAccessChain %46 %42 %50 + %76 = OpLoad %16 %75 + %78 = OpConvertSToF %16 %84 + %80 = OpAccessChain %46 %42 %45 + %206 = OpCopyObject %16 %78 + %81 = OpLoad %16 %80 + %79 = OpFAdd %16 %76 %78 + %82 = OpFAdd %16 %81 %79 + OpStore %80 %82 + OpReturn + OpFunctionEnd + )"; + + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +TEST(TransformationReplaceIdWithSynonymTest, SynonymsOfVariables) { + // The following SPIR-V comes from this GLSL, with object copies added: + // + // #version 310 es + // + // precision highp int; + // + // int g; + // + // void main() { + // int l; + // l = g; + // g = l; + // } + const std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %8 "l" + OpName %10 "g" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpTypePointer Private %6 + %10 = OpVariable %9 Private + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %100 = OpCopyObject %9 %10 + %101 = OpCopyObject %7 %8 + %11 = OpLoad %6 %10 + OpStore %8 %11 + %12 = OpLoad %6 %8 + OpStore %10 %12 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + fact_manager.AddFact(MakeSynonymFact(10, 100), context.get()); + fact_manager.AddFact(MakeSynonymFact(8, 101), context.get()); + + // Replace %10 with %100 in: + // %11 = OpLoad %6 %10 + auto replacement1 = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor(10, MakeInstructionDescriptor(11, SpvOpLoad, 0), 0), + 100); + ASSERT_TRUE(replacement1.IsApplicable(context.get(), fact_manager)); + replacement1.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + // Replace %8 with %101 in: + // OpStore %8 %11 + auto replacement2 = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor(8, MakeInstructionDescriptor(11, SpvOpStore, 0), 0), + 101); + ASSERT_TRUE(replacement2.IsApplicable(context.get(), fact_manager)); + replacement2.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + // Replace %8 with %101 in: + // %12 = OpLoad %6 %8 + auto replacement3 = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor(8, MakeInstructionDescriptor(12, SpvOpLoad, 0), 0), + 101); + ASSERT_TRUE(replacement3.IsApplicable(context.get(), fact_manager)); + replacement3.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + // Replace %10 with %100 in: + // OpStore %10 %12 + auto replacement4 = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor(10, MakeInstructionDescriptor(12, SpvOpStore, 0), 0), + 100); + ASSERT_TRUE(replacement4.IsApplicable(context.get(), fact_manager)); + replacement4.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + const std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %8 "l" + OpName %10 "g" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpTypePointer Private %6 + %10 = OpVariable %9 Private + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %100 = OpCopyObject %9 %10 + %101 = OpCopyObject %7 %8 + %11 = OpLoad %6 %100 + OpStore %101 %11 + %12 = OpLoad %6 %101 + OpStore %100 %12 + OpReturn + OpFunctionEnd + )"; + + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +TEST(TransformationReplaceIdWithSynonymTest, + SynonymOfVariableNoGoodInFunctionCall) { + // The following SPIR-V comes from this GLSL, with an object copy added: + // + // #version 310 es + // + // precision highp int; + // + // void foo(int x) { } + // + // void main() { + // int a; + // a = 2; + // foo(a); + // } + const std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %10 "foo(i1;" + OpName %9 "x" + OpName %12 "a" + OpName %14 "param" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %8 = OpTypeFunction %2 %7 + %13 = OpConstant %6 2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %12 = OpVariable %7 Function + %14 = OpVariable %7 Function + OpStore %12 %13 + %15 = OpLoad %6 %12 + OpStore %14 %15 + %100 = OpCopyObject %7 %14 + %16 = OpFunctionCall %2 %10 %14 + OpReturn + OpFunctionEnd + %10 = OpFunction %2 None %8 + %9 = OpFunctionParameter %7 + %11 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + fact_manager.AddFact(MakeSynonymFact(14, 100), context.get()); + + // Replace %14 with %100 in: + // %16 = OpFunctionCall %2 %10 %14 + auto replacement = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor( + 14, MakeInstructionDescriptor(16, SpvOpFunctionCall, 0), 1), + 100); + ASSERT_FALSE(replacement.IsApplicable(context.get(), fact_manager)); +} + +TEST(TransformationReplaceIdWithSynonymTest, SynonymsOfAccessChainIndices) { + // The following SPIR-V comes from this GLSL, with object copies added: + // + // #version 310 es + // + // precision highp float; + // precision highp int; + // + // struct S { + // int[3] a; + // vec4 b; + // bool c; + // } d; + // + // float[20] e; + // + // struct T { + // float f; + // S g; + // } h; + // + // T[4] i; + // + // void main() { + // d.a[2] = 10; + // d.b[3] = 11.0; + // d.c = false; + // e[17] = 12.0; + // h.f = 13.0; + // h.g.a[1] = 14; + // h.g.b[0] = 15.0; + // h.g.c = true; + // i[0].f = 16.0; + // i[1].g.a[0] = 17; + // i[2].g.b[1] = 18.0; + // i[3].g.c = true; + // } + const std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %13 "S" + OpMemberName %13 0 "a" + OpMemberName %13 1 "b" + OpMemberName %13 2 "c" + OpName %15 "d" + OpName %31 "e" + OpName %35 "T" + OpMemberName %35 0 "f" + OpMemberName %35 1 "g" + OpName %37 "h" + OpName %50 "i" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypeInt 32 0 + %8 = OpConstant %7 3 + %9 = OpTypeArray %6 %8 + %10 = OpTypeFloat 32 + %11 = OpTypeVector %10 4 + %12 = OpTypeBool + %13 = OpTypeStruct %9 %11 %12 + %14 = OpTypePointer Private %13 + %15 = OpVariable %14 Private + %16 = OpConstant %6 0 + %17 = OpConstant %6 2 + %18 = OpConstant %6 10 + %19 = OpTypePointer Private %6 + %21 = OpConstant %6 1 + %22 = OpConstant %10 11 + %23 = OpTypePointer Private %10 + %25 = OpConstantFalse %12 + %26 = OpTypePointer Private %12 + %28 = OpConstant %7 20 + %29 = OpTypeArray %10 %28 + %30 = OpTypePointer Private %29 + %31 = OpVariable %30 Private + %32 = OpConstant %6 17 + %33 = OpConstant %10 12 + %35 = OpTypeStruct %10 %13 + %36 = OpTypePointer Private %35 + %37 = OpVariable %36 Private + %38 = OpConstant %10 13 + %40 = OpConstant %6 14 + %42 = OpConstant %10 15 + %43 = OpConstant %7 0 + %45 = OpConstantTrue %12 + %47 = OpConstant %7 4 + %48 = OpTypeArray %35 %47 + %49 = OpTypePointer Private %48 + %50 = OpVariable %49 Private + %51 = OpConstant %10 16 + %54 = OpConstant %10 18 + %55 = OpConstant %7 1 + %57 = OpConstant %6 3 + %4 = OpFunction %2 None %3 + %5 = OpLabel + + %100 = OpCopyObject %6 %16 ; 0 + %101 = OpCopyObject %6 %21 ; 1 + %102 = OpCopyObject %6 %17 ; 2 + %103 = OpCopyObject %6 %57 ; 3 + %104 = OpCopyObject %6 %18 ; 10 + %105 = OpCopyObject %6 %40 ; 14 + %106 = OpCopyObject %6 %32 ; 17 + %107 = OpCopyObject %7 %43 ; 0 + %108 = OpCopyObject %7 %55 ; 1 + %109 = OpCopyObject %7 %8 ; 3 + %110 = OpCopyObject %7 %47 ; 4 + %111 = OpCopyObject %7 %28 ; 20 + %112 = OpCopyObject %12 %45 ; true + + %20 = OpAccessChain %19 %15 %16 %17 + OpStore %20 %18 + %24 = OpAccessChain %23 %15 %21 %8 + OpStore %24 %22 + %27 = OpAccessChain %26 %15 %17 + OpStore %27 %25 + %34 = OpAccessChain %23 %31 %32 + OpStore %34 %33 + %39 = OpAccessChain %23 %37 %16 + OpStore %39 %38 + %41 = OpAccessChain %19 %37 %21 %16 %21 + OpStore %41 %40 + %44 = OpAccessChain %23 %37 %21 %21 %43 + OpStore %44 %42 + %46 = OpAccessChain %26 %37 %21 %17 + OpStore %46 %45 + %52 = OpAccessChain %23 %50 %16 %16 + OpStore %52 %51 + %53 = OpAccessChain %19 %50 %21 %21 %16 %16 + OpStore %53 %32 + %56 = OpAccessChain %23 %50 %17 %21 %21 %55 + OpStore %56 %54 + %58 = OpAccessChain %26 %50 %57 %21 %17 + OpStore %58 %45 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + // Add synonym facts corresponding to the OpCopyObject operations that have + // been applied to all constants in the module. + fact_manager.AddFact(MakeSynonymFact(16, 100), context.get()); + fact_manager.AddFact(MakeSynonymFact(21, 101), context.get()); + fact_manager.AddFact(MakeSynonymFact(17, 102), context.get()); + fact_manager.AddFact(MakeSynonymFact(57, 103), context.get()); + fact_manager.AddFact(MakeSynonymFact(18, 104), context.get()); + fact_manager.AddFact(MakeSynonymFact(40, 105), context.get()); + fact_manager.AddFact(MakeSynonymFact(32, 106), context.get()); + fact_manager.AddFact(MakeSynonymFact(43, 107), context.get()); + fact_manager.AddFact(MakeSynonymFact(55, 108), context.get()); + fact_manager.AddFact(MakeSynonymFact(8, 109), context.get()); + fact_manager.AddFact(MakeSynonymFact(47, 110), context.get()); + fact_manager.AddFact(MakeSynonymFact(28, 111), context.get()); + fact_manager.AddFact(MakeSynonymFact(45, 112), context.get()); + + // Replacements of the form %16 -> %100 + + // %20 = OpAccessChain %19 %15 *%16* %17 + // Corresponds to d.*a*[2] + // The index %16 used for a cannot be replaced + auto replacement1 = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor( + 16, MakeInstructionDescriptor(20, SpvOpAccessChain, 0), 1), + 100); + ASSERT_FALSE(replacement1.IsApplicable(context.get(), fact_manager)); + + // %39 = OpAccessChain %23 %37 *%16* + // Corresponds to h.*f* + // The index %16 used for f cannot be replaced + auto replacement2 = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor( + 16, MakeInstructionDescriptor(39, SpvOpAccessChain, 0), 1), + 100); + ASSERT_FALSE(replacement2.IsApplicable(context.get(), fact_manager)); + + // %41 = OpAccessChain %19 %37 %21 *%16* %21 + // Corresponds to h.g.*a*[1] + // The index %16 used for a cannot be replaced + auto replacement3 = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor( + 16, MakeInstructionDescriptor(41, SpvOpAccessChain, 0), 2), + 100); + ASSERT_FALSE(replacement3.IsApplicable(context.get(), fact_manager)); + + // %52 = OpAccessChain %23 %50 *%16* %16 + // Corresponds to i[*0*].f + // The index %16 used for 0 *can* be replaced + auto replacement4 = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor( + 16, MakeInstructionDescriptor(52, SpvOpAccessChain, 0), 1), + 100); + ASSERT_TRUE(replacement4.IsApplicable(context.get(), fact_manager)); + replacement4.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + // %52 = OpAccessChain %23 %50 %16 *%16* + // Corresponds to i[0].*f* + // The index %16 used for f cannot be replaced + auto replacement5 = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor( + 16, MakeInstructionDescriptor(52, SpvOpAccessChain, 0), 2), + 100); + ASSERT_FALSE(replacement5.IsApplicable(context.get(), fact_manager)); + + // %53 = OpAccessChain %19 %50 %21 %21 *%16* %16 + // Corresponds to i[1].g.*a*[0] + // The index %16 used for a cannot be replaced + auto replacement6 = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor( + 16, MakeInstructionDescriptor(53, SpvOpAccessChain, 0), 3), + 100); + ASSERT_FALSE(replacement6.IsApplicable(context.get(), fact_manager)); + + // %53 = OpAccessChain %19 %50 %21 %21 %16 *%16* + // Corresponds to i[1].g.a[*0*] + // The index %16 used for 0 *can* be replaced + auto replacement7 = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor( + 16, MakeInstructionDescriptor(53, SpvOpAccessChain, 0), 4), + 100); + ASSERT_TRUE(replacement7.IsApplicable(context.get(), fact_manager)); + replacement7.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + // Replacements of the form %21 -> %101 + + // %24 = OpAccessChain %23 %15 *%21* %8 + // Corresponds to d.*b*[3] + // The index %24 used for b cannot be replaced + auto replacement8 = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor( + 21, MakeInstructionDescriptor(24, SpvOpAccessChain, 0), 1), + 101); + ASSERT_FALSE(replacement8.IsApplicable(context.get(), fact_manager)); + + // %41 = OpAccessChain %19 %37 *%21* %16 %21 + // Corresponds to h.*g*.a[1] + // The index %24 used for g cannot be replaced + auto replacement9 = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor( + 21, MakeInstructionDescriptor(41, SpvOpAccessChain, 0), 1), + 101); + ASSERT_FALSE(replacement9.IsApplicable(context.get(), fact_manager)); + + // %41 = OpAccessChain %19 %37 %21 %16 *%21* + // Corresponds to h.g.a[*1*] + // The index %24 used for 1 *can* be replaced + auto replacement10 = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor( + 21, MakeInstructionDescriptor(41, SpvOpAccessChain, 0), 3), + 101); + ASSERT_TRUE(replacement10.IsApplicable(context.get(), fact_manager)); + replacement10.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + // %44 = OpAccessChain %23 %37 *%21* %21 %43 + // Corresponds to h.*g*.b[0] + // The index %24 used for g cannot be replaced + auto replacement11 = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor( + 21, MakeInstructionDescriptor(44, SpvOpAccessChain, 0), 1), + 101); + ASSERT_FALSE(replacement11.IsApplicable(context.get(), fact_manager)); + + // %44 = OpAccessChain %23 %37 %21 *%21* %43 + // Corresponds to h.g.*b*[0] + // The index %24 used for b cannot be replaced + auto replacement12 = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor( + 21, MakeInstructionDescriptor(44, SpvOpAccessChain, 0), 2), + 101); + ASSERT_FALSE(replacement12.IsApplicable(context.get(), fact_manager)); + + // %46 = OpAccessChain %26 %37 *%21* %17 + // Corresponds to h.*g*.c + // The index %24 used for g cannot be replaced + auto replacement13 = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor( + 21, MakeInstructionDescriptor(46, SpvOpAccessChain, 0), 1), + 101); + ASSERT_FALSE(replacement13.IsApplicable(context.get(), fact_manager)); + + // %53 = OpAccessChain %19 %50 *%21* %21 %16 %16 + // Corresponds to i[*1*].g.a[0] + // The index %24 used for 1 *can* be replaced + auto replacement14 = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor( + 21, MakeInstructionDescriptor(53, SpvOpAccessChain, 0), 1), + 101); + ASSERT_TRUE(replacement14.IsApplicable(context.get(), fact_manager)); + replacement14.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + // %53 = OpAccessChain %19 %50 %21 *%21* %16 %16 + // Corresponds to i[1].*g*.a[0] + // The index %24 used for g cannot be replaced + auto replacement15 = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor( + 21, MakeInstructionDescriptor(53, SpvOpAccessChain, 0), 2), + 101); + ASSERT_FALSE(replacement15.IsApplicable(context.get(), fact_manager)); + + // %56 = OpAccessChain %23 %50 %17 *%21* %21 %55 + // Corresponds to i[2].*g*.b[1] + // The index %24 used for g cannot be replaced + auto replacement16 = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor( + 21, MakeInstructionDescriptor(56, SpvOpAccessChain, 0), 2), + 101); + ASSERT_FALSE(replacement16.IsApplicable(context.get(), fact_manager)); + + // %56 = OpAccessChain %23 %50 %17 %21 *%21* %55 + // Corresponds to i[2].g.*b*[1] + // The index %24 used for b cannot be replaced + auto replacement17 = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor( + 21, MakeInstructionDescriptor(56, SpvOpAccessChain, 0), 3), + 101); + ASSERT_FALSE(replacement17.IsApplicable(context.get(), fact_manager)); + + // %58 = OpAccessChain %26 %50 %57 *%21* %17 + // Corresponds to i[3].*g*.c + // The index %24 used for g cannot be replaced + auto replacement18 = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor( + 21, MakeInstructionDescriptor(58, SpvOpAccessChain, 0), 2), + 101); + ASSERT_FALSE(replacement18.IsApplicable(context.get(), fact_manager)); + + // Replacements of the form %17 -> %102 + + // %20 = OpAccessChain %19 %15 %16 %17 + // Corresponds to d.a[*2*] + // The index %17 used for 2 *can* be replaced + auto replacement19 = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor( + 17, MakeInstructionDescriptor(20, SpvOpAccessChain, 0), 2), + 102); + ASSERT_TRUE(replacement19.IsApplicable(context.get(), fact_manager)); + replacement19.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + // %27 = OpAccessChain %26 %15 %17 + // Corresponds to d.c + // The index %17 used for c cannot be replaced + auto replacement20 = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor( + 17, MakeInstructionDescriptor(27, SpvOpAccessChain, 0), 1), + 102); + ASSERT_FALSE(replacement20.IsApplicable(context.get(), fact_manager)); + + // %46 = OpAccessChain %26 %37 %21 %17 + // Corresponds to h.g.*c* + // The index %17 used for c cannot be replaced + auto replacement21 = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor( + 17, MakeInstructionDescriptor(46, SpvOpAccessChain, 0), 2), + 102); + ASSERT_FALSE(replacement21.IsApplicable(context.get(), fact_manager)); + + // %56 = OpAccessChain %23 %50 %17 %21 %21 %55 + // Corresponds to i[*2*].g.b[1] + // The index %17 used for 2 *can* be replaced + auto replacement22 = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor( + 17, MakeInstructionDescriptor(56, SpvOpAccessChain, 0), 1), + 102); + ASSERT_TRUE(replacement22.IsApplicable(context.get(), fact_manager)); + replacement22.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + // %58 = OpAccessChain %26 %50 %57 %21 %17 + // Corresponds to i[3].g.*c* + // The index %17 used for c cannot be replaced + auto replacement23 = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor( + 17, MakeInstructionDescriptor(58, SpvOpAccessChain, 0), 3), + 102); + ASSERT_FALSE(replacement23.IsApplicable(context.get(), fact_manager)); + + // Replacements of the form %57 -> %103 + + // %58 = OpAccessChain %26 %50 *%57* %21 %17 + // Corresponds to i[*3*].g.c + // The index %57 used for 3 *can* be replaced + auto replacement24 = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor( + 57, MakeInstructionDescriptor(58, SpvOpAccessChain, 0), 1), + 103); + ASSERT_TRUE(replacement24.IsApplicable(context.get(), fact_manager)); + replacement24.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + // Replacements of the form %32 -> %106 + + // %34 = OpAccessChain %23 %31 *%32* + // Corresponds to e[*17*] + // The index %32 used for 17 *can* be replaced + auto replacement25 = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor( + 32, MakeInstructionDescriptor(34, SpvOpAccessChain, 0), 1), + 106); + ASSERT_TRUE(replacement25.IsApplicable(context.get(), fact_manager)); + replacement25.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + // Replacements of the form %43 -> %107 + + // %44 = OpAccessChain %23 %37 %21 %21 *%43* + // Corresponds to h.g.b[*0*] + // The index %43 used for 0 *can* be replaced + auto replacement26 = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor( + 43, MakeInstructionDescriptor(44, SpvOpAccessChain, 0), 3), + 107); + ASSERT_TRUE(replacement26.IsApplicable(context.get(), fact_manager)); + replacement26.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + // Replacements of the form %55 -> %108 + + // %56 = OpAccessChain %23 %50 %17 %21 %21 *%55* + // Corresponds to i[2].g.b[*1*] + // The index %55 used for 1 *can* be replaced + auto replacement27 = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor( + 55, MakeInstructionDescriptor(56, SpvOpAccessChain, 0), 4), + 108); + ASSERT_TRUE(replacement27.IsApplicable(context.get(), fact_manager)); + replacement27.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + // Replacements of the form %8 -> %109 + + // %24 = OpAccessChain %23 %15 %21 *%8* + // Corresponds to d.b[*3*] + // The index %8 used for 3 *can* be replaced + auto replacement28 = TransformationReplaceIdWithSynonym( + MakeIdUseDescriptor(8, MakeInstructionDescriptor(24, SpvOpAccessChain, 0), + 2), + 109); + ASSERT_TRUE(replacement28.IsApplicable(context.get(), fact_manager)); + replacement28.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + const std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %13 "S" + OpMemberName %13 0 "a" + OpMemberName %13 1 "b" + OpMemberName %13 2 "c" + OpName %15 "d" + OpName %31 "e" + OpName %35 "T" + OpMemberName %35 0 "f" + OpMemberName %35 1 "g" + OpName %37 "h" + OpName %50 "i" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypeInt 32 0 + %8 = OpConstant %7 3 + %9 = OpTypeArray %6 %8 + %10 = OpTypeFloat 32 + %11 = OpTypeVector %10 4 + %12 = OpTypeBool + %13 = OpTypeStruct %9 %11 %12 + %14 = OpTypePointer Private %13 + %15 = OpVariable %14 Private + %16 = OpConstant %6 0 + %17 = OpConstant %6 2 + %18 = OpConstant %6 10 + %19 = OpTypePointer Private %6 + %21 = OpConstant %6 1 + %22 = OpConstant %10 11 + %23 = OpTypePointer Private %10 + %25 = OpConstantFalse %12 + %26 = OpTypePointer Private %12 + %28 = OpConstant %7 20 + %29 = OpTypeArray %10 %28 + %30 = OpTypePointer Private %29 + %31 = OpVariable %30 Private + %32 = OpConstant %6 17 + %33 = OpConstant %10 12 + %35 = OpTypeStruct %10 %13 + %36 = OpTypePointer Private %35 + %37 = OpVariable %36 Private + %38 = OpConstant %10 13 + %40 = OpConstant %6 14 + %42 = OpConstant %10 15 + %43 = OpConstant %7 0 + %45 = OpConstantTrue %12 + %47 = OpConstant %7 4 + %48 = OpTypeArray %35 %47 + %49 = OpTypePointer Private %48 + %50 = OpVariable %49 Private + %51 = OpConstant %10 16 + %54 = OpConstant %10 18 + %55 = OpConstant %7 1 + %57 = OpConstant %6 3 + %4 = OpFunction %2 None %3 + %5 = OpLabel + + %100 = OpCopyObject %6 %16 ; 0 + %101 = OpCopyObject %6 %21 ; 1 + %102 = OpCopyObject %6 %17 ; 2 + %103 = OpCopyObject %6 %57 ; 3 + %104 = OpCopyObject %6 %18 ; 10 + %105 = OpCopyObject %6 %40 ; 14 + %106 = OpCopyObject %6 %32 ; 17 + %107 = OpCopyObject %7 %43 ; 0 + %108 = OpCopyObject %7 %55 ; 1 + %109 = OpCopyObject %7 %8 ; 3 + %110 = OpCopyObject %7 %47 ; 4 + %111 = OpCopyObject %7 %28 ; 20 + %112 = OpCopyObject %12 %45 ; true + + %20 = OpAccessChain %19 %15 %16 %102 + OpStore %20 %18 + %24 = OpAccessChain %23 %15 %21 %109 + OpStore %24 %22 + %27 = OpAccessChain %26 %15 %17 + OpStore %27 %25 + %34 = OpAccessChain %23 %31 %106 + OpStore %34 %33 + %39 = OpAccessChain %23 %37 %16 + OpStore %39 %38 + %41 = OpAccessChain %19 %37 %21 %16 %101 + OpStore %41 %40 + %44 = OpAccessChain %23 %37 %21 %21 %107 + OpStore %44 %42 + %46 = OpAccessChain %26 %37 %21 %17 + OpStore %46 %45 + %52 = OpAccessChain %23 %50 %100 %16 + OpStore %52 %51 + %53 = OpAccessChain %19 %50 %101 %21 %16 %100 + OpStore %53 %32 + %56 = OpAccessChain %23 %50 %102 %21 %21 %108 + OpStore %56 %54 + %58 = OpAccessChain %26 %50 %103 %21 %17 + OpStore %58 %45 + OpReturn + OpFunctionEnd + )"; + + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +} // namespace +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/test/fuzz/transformation_set_function_control_test.cpp b/third_party/spirv-tools/test/fuzz/transformation_set_function_control_test.cpp new file mode 100644 index 0000000000..536e965e39 --- /dev/null +++ b/third_party/spirv-tools/test/fuzz/transformation_set_function_control_test.cpp @@ -0,0 +1,251 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_set_function_control.h" +#include "test/fuzz/fuzz_test_util.h" + +namespace spvtools { +namespace fuzz { +namespace { + +TEST(TransformationSetFunctionControlTest, VariousScenarios) { + // This is a simple transformation; this test captures the important things + // to check for. + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" %54 + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %11 "foo(i1;i1;" + OpName %9 "a" + OpName %10 "b" + OpName %13 "bar(" + OpName %17 "baz(i1;" + OpName %16 "x" + OpName %21 "boo(i1;i1;" + OpName %19 "a" + OpName %20 "b" + OpName %29 "g" + OpName %42 "param" + OpName %44 "param" + OpName %45 "param" + OpName %48 "param" + OpName %49 "param" + OpName %54 "color" + OpDecorate %54 Location 0 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %8 = OpTypeFunction %6 %7 %7 + %15 = OpTypeFunction %6 %7 + %28 = OpTypePointer Private %6 + %29 = OpVariable %28 Private + %30 = OpConstant %6 2 + %31 = OpConstant %6 5 + %51 = OpTypeFloat 32 + %52 = OpTypeVector %51 4 + %53 = OpTypePointer Output %52 + %54 = OpVariable %53 Output + %4 = OpFunction %2 None %3 + %5 = OpLabel + %42 = OpVariable %7 Function + %44 = OpVariable %7 Function + %45 = OpVariable %7 Function + %48 = OpVariable %7 Function + %49 = OpVariable %7 Function + %41 = OpFunctionCall %2 %13 + OpStore %42 %30 + %43 = OpFunctionCall %6 %17 %42 + OpStore %44 %31 + %46 = OpLoad %6 %29 + OpStore %45 %46 + %47 = OpFunctionCall %6 %21 %44 %45 + OpStore %48 %43 + OpStore %49 %47 + %50 = OpFunctionCall %6 %11 %48 %49 + OpReturn + OpFunctionEnd + %11 = OpFunction %6 Const %8 + %9 = OpFunctionParameter %7 + %10 = OpFunctionParameter %7 + %12 = OpLabel + %23 = OpLoad %6 %9 + %24 = OpLoad %6 %10 + %25 = OpIAdd %6 %23 %24 + OpReturnValue %25 + OpFunctionEnd + %13 = OpFunction %2 Inline %3 + %14 = OpLabel + OpStore %29 %30 + OpReturn + OpFunctionEnd + %17 = OpFunction %6 Pure|DontInline %15 + %16 = OpFunctionParameter %7 + %18 = OpLabel + %32 = OpLoad %6 %16 + %33 = OpIAdd %6 %31 %32 + OpReturnValue %33 + OpFunctionEnd + %21 = OpFunction %6 DontInline %8 + %19 = OpFunctionParameter %7 + %20 = OpFunctionParameter %7 + %22 = OpLabel + %36 = OpLoad %6 %19 + %37 = OpLoad %6 %20 + %38 = OpIMul %6 %36 %37 + OpReturnValue %38 + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + + FactManager fact_manager; + + // %36 is not a function + ASSERT_FALSE(TransformationSetFunctionControl(36, SpvFunctionControlMaskNone) + .IsApplicable(context.get(), fact_manager)); + // Cannot add the Pure function control to %4 as it did not already have it + ASSERT_FALSE(TransformationSetFunctionControl(4, SpvFunctionControlPureMask) + .IsApplicable(context.get(), fact_manager)); + // Cannot add the Const function control to %21 as it did not already + // have it + ASSERT_FALSE(TransformationSetFunctionControl(21, SpvFunctionControlConstMask) + .IsApplicable(context.get(), fact_manager)); + + // Set to None, removing Const + TransformationSetFunctionControl transformation1(11, + SpvFunctionControlMaskNone); + ASSERT_TRUE(transformation1.IsApplicable(context.get(), fact_manager)); + transformation1.Apply(context.get(), &fact_manager); + + // Set to Inline; silly to do it on an entry point, but it is allowed + TransformationSetFunctionControl transformation2( + 4, SpvFunctionControlInlineMask); + ASSERT_TRUE(transformation2.IsApplicable(context.get(), fact_manager)); + transformation2.Apply(context.get(), &fact_manager); + + // Set to Pure, removing DontInline + TransformationSetFunctionControl transformation3(17, + SpvFunctionControlPureMask); + ASSERT_TRUE(transformation3.IsApplicable(context.get(), fact_manager)); + transformation3.Apply(context.get(), &fact_manager); + + // Change from Inline to DontInline + TransformationSetFunctionControl transformation4( + 13, SpvFunctionControlDontInlineMask); + ASSERT_TRUE(transformation4.IsApplicable(context.get(), fact_manager)); + transformation4.Apply(context.get(), &fact_manager); + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" %54 + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %11 "foo(i1;i1;" + OpName %9 "a" + OpName %10 "b" + OpName %13 "bar(" + OpName %17 "baz(i1;" + OpName %16 "x" + OpName %21 "boo(i1;i1;" + OpName %19 "a" + OpName %20 "b" + OpName %29 "g" + OpName %42 "param" + OpName %44 "param" + OpName %45 "param" + OpName %48 "param" + OpName %49 "param" + OpName %54 "color" + OpDecorate %54 Location 0 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %8 = OpTypeFunction %6 %7 %7 + %15 = OpTypeFunction %6 %7 + %28 = OpTypePointer Private %6 + %29 = OpVariable %28 Private + %30 = OpConstant %6 2 + %31 = OpConstant %6 5 + %51 = OpTypeFloat 32 + %52 = OpTypeVector %51 4 + %53 = OpTypePointer Output %52 + %54 = OpVariable %53 Output + %4 = OpFunction %2 Inline %3 + %5 = OpLabel + %42 = OpVariable %7 Function + %44 = OpVariable %7 Function + %45 = OpVariable %7 Function + %48 = OpVariable %7 Function + %49 = OpVariable %7 Function + %41 = OpFunctionCall %2 %13 + OpStore %42 %30 + %43 = OpFunctionCall %6 %17 %42 + OpStore %44 %31 + %46 = OpLoad %6 %29 + OpStore %45 %46 + %47 = OpFunctionCall %6 %21 %44 %45 + OpStore %48 %43 + OpStore %49 %47 + %50 = OpFunctionCall %6 %11 %48 %49 + OpReturn + OpFunctionEnd + %11 = OpFunction %6 None %8 + %9 = OpFunctionParameter %7 + %10 = OpFunctionParameter %7 + %12 = OpLabel + %23 = OpLoad %6 %9 + %24 = OpLoad %6 %10 + %25 = OpIAdd %6 %23 %24 + OpReturnValue %25 + OpFunctionEnd + %13 = OpFunction %2 DontInline %3 + %14 = OpLabel + OpStore %29 %30 + OpReturn + OpFunctionEnd + %17 = OpFunction %6 Pure %15 + %16 = OpFunctionParameter %7 + %18 = OpLabel + %32 = OpLoad %6 %16 + %33 = OpIAdd %6 %31 %32 + OpReturnValue %33 + OpFunctionEnd + %21 = OpFunction %6 DontInline %8 + %19 = OpFunctionParameter %7 + %20 = OpFunctionParameter %7 + %22 = OpLabel + %36 = OpLoad %6 %19 + %37 = OpLoad %6 %20 + %38 = OpIMul %6 %36 %37 + OpReturnValue %38 + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +} // namespace +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/test/fuzz/transformation_set_loop_control_test.cpp b/third_party/spirv-tools/test/fuzz/transformation_set_loop_control_test.cpp new file mode 100644 index 0000000000..83953ec0e6 --- /dev/null +++ b/third_party/spirv-tools/test/fuzz/transformation_set_loop_control_test.cpp @@ -0,0 +1,968 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_set_loop_control.h" +#include "test/fuzz/fuzz_test_util.h" + +namespace spvtools { +namespace fuzz { +namespace { + +TEST(TransformationSetLoopControlTest, VariousScenarios) { + // This test features loops with various different controls, and goes through + // a number of acceptable and unacceptable transformations to those controls. + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 0 + %16 = OpConstant %6 100 + %17 = OpTypeBool + %20 = OpConstant %6 1 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %22 = OpVariable %7 Function + %32 = OpVariable %7 Function + %42 = OpVariable %7 Function + %52 = OpVariable %7 Function + %62 = OpVariable %7 Function + %72 = OpVariable %7 Function + %82 = OpVariable %7 Function + %92 = OpVariable %7 Function + %102 = OpVariable %7 Function + %112 = OpVariable %7 Function + %122 = OpVariable %7 Function + OpStore %8 %9 + OpBranch %10 + %10 = OpLabel + %132 = OpPhi %6 %9 %5 %21 %13 + OpLoopMerge %12 %13 None + OpBranch %14 + %14 = OpLabel + %18 = OpSLessThan %17 %132 %16 + OpBranchConditional %18 %11 %12 + %11 = OpLabel + OpBranch %13 + %13 = OpLabel + %21 = OpIAdd %6 %132 %20 + OpStore %8 %21 + OpBranch %10 + %12 = OpLabel + OpStore %22 %9 + OpBranch %23 + %23 = OpLabel + %133 = OpPhi %6 %9 %12 %31 %26 + OpLoopMerge %25 %26 Unroll + OpBranch %27 + %27 = OpLabel + %29 = OpSLessThan %17 %133 %16 + OpBranchConditional %29 %24 %25 + %24 = OpLabel + OpBranch %26 + %26 = OpLabel + %31 = OpIAdd %6 %133 %20 + OpStore %22 %31 + OpBranch %23 + %25 = OpLabel + OpStore %32 %9 + OpBranch %33 + %33 = OpLabel + %134 = OpPhi %6 %9 %25 %41 %36 + OpLoopMerge %35 %36 DontUnroll + OpBranch %37 + %37 = OpLabel + %39 = OpSLessThan %17 %134 %16 + OpBranchConditional %39 %34 %35 + %34 = OpLabel + OpBranch %36 + %36 = OpLabel + %41 = OpIAdd %6 %134 %20 + OpStore %32 %41 + OpBranch %33 + %35 = OpLabel + OpStore %42 %9 + OpBranch %43 + %43 = OpLabel + %135 = OpPhi %6 %9 %35 %51 %46 + OpLoopMerge %45 %46 DependencyInfinite + OpBranch %47 + %47 = OpLabel + %49 = OpSLessThan %17 %135 %16 + OpBranchConditional %49 %44 %45 + %44 = OpLabel + OpBranch %46 + %46 = OpLabel + %51 = OpIAdd %6 %135 %20 + OpStore %42 %51 + OpBranch %43 + %45 = OpLabel + OpStore %52 %9 + OpBranch %53 + %53 = OpLabel + %136 = OpPhi %6 %9 %45 %61 %56 + OpLoopMerge %55 %56 DependencyLength 3 + OpBranch %57 + %57 = OpLabel + %59 = OpSLessThan %17 %136 %16 + OpBranchConditional %59 %54 %55 + %54 = OpLabel + OpBranch %56 + %56 = OpLabel + %61 = OpIAdd %6 %136 %20 + OpStore %52 %61 + OpBranch %53 + %55 = OpLabel + OpStore %62 %9 + OpBranch %63 + %63 = OpLabel + %137 = OpPhi %6 %9 %55 %71 %66 + OpLoopMerge %65 %66 MinIterations 10 + OpBranch %67 + %67 = OpLabel + %69 = OpSLessThan %17 %137 %16 + OpBranchConditional %69 %64 %65 + %64 = OpLabel + OpBranch %66 + %66 = OpLabel + %71 = OpIAdd %6 %137 %20 + OpStore %62 %71 + OpBranch %63 + %65 = OpLabel + OpStore %72 %9 + OpBranch %73 + %73 = OpLabel + %138 = OpPhi %6 %9 %65 %81 %76 + OpLoopMerge %75 %76 MaxIterations 50 + OpBranch %77 + %77 = OpLabel + %79 = OpSLessThan %17 %138 %16 + OpBranchConditional %79 %74 %75 + %74 = OpLabel + OpBranch %76 + %76 = OpLabel + %81 = OpIAdd %6 %138 %20 + OpStore %72 %81 + OpBranch %73 + %75 = OpLabel + OpStore %82 %9 + OpBranch %83 + %83 = OpLabel + %139 = OpPhi %6 %9 %75 %91 %86 + OpLoopMerge %85 %86 IterationMultiple 4 + OpBranch %87 + %87 = OpLabel + %89 = OpSLessThan %17 %139 %16 + OpBranchConditional %89 %84 %85 + %84 = OpLabel + OpBranch %86 + %86 = OpLabel + %91 = OpIAdd %6 %139 %20 + OpStore %82 %91 + OpBranch %83 + %85 = OpLabel + OpStore %92 %9 + OpBranch %93 + %93 = OpLabel + %140 = OpPhi %6 %9 %85 %101 %96 + OpLoopMerge %95 %96 PeelCount 2 + OpBranch %97 + %97 = OpLabel + %99 = OpSLessThan %17 %140 %16 + OpBranchConditional %99 %94 %95 + %94 = OpLabel + OpBranch %96 + %96 = OpLabel + %101 = OpIAdd %6 %140 %20 + OpStore %92 %101 + OpBranch %93 + %95 = OpLabel + OpStore %102 %9 + OpBranch %103 + %103 = OpLabel + %141 = OpPhi %6 %9 %95 %111 %106 + OpLoopMerge %105 %106 PartialCount 3 + OpBranch %107 + %107 = OpLabel + %109 = OpSLessThan %17 %141 %16 + OpBranchConditional %109 %104 %105 + %104 = OpLabel + OpBranch %106 + %106 = OpLabel + %111 = OpIAdd %6 %141 %20 + OpStore %102 %111 + OpBranch %103 + %105 = OpLabel + OpStore %112 %9 + OpBranch %113 + %113 = OpLabel + %142 = OpPhi %6 %9 %105 %121 %116 + OpLoopMerge %115 %116 Unroll|PeelCount|PartialCount 3 4 + OpBranch %117 + %117 = OpLabel + %119 = OpSLessThan %17 %142 %16 + OpBranchConditional %119 %114 %115 + %114 = OpLabel + OpBranch %116 + %116 = OpLabel + %121 = OpIAdd %6 %142 %20 + OpStore %112 %121 + OpBranch %113 + %115 = OpLabel + OpStore %122 %9 + OpBranch %123 + %123 = OpLabel + %143 = OpPhi %6 %9 %115 %131 %126 + OpLoopMerge %125 %126 DependencyLength|MinIterations|MaxIterations|IterationMultiple|PeelCount|PartialCount 2 5 90 4 7 14 + OpBranch %127 + %127 = OpLabel + %129 = OpSLessThan %17 %143 %16 + OpBranchConditional %129 %124 %125 + %124 = OpLabel + OpBranch %126 + %126 = OpLabel + %131 = OpIAdd %6 %143 %20 + OpStore %122 %131 + OpBranch %123 + %125 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + // These are the loop headers together with the selection controls of their + // merge instructions: + // %10 None + // %23 Unroll + // %33 DontUnroll + // %43 DependencyInfinite + // %53 DependencyLength 3 + // %63 MinIterations 10 + // %73 MaxIterations 50 + // %83 IterationMultiple 4 + // %93 PeelCount 2 + // %103 PartialCount 3 + // %113 Unroll|PeelCount|PartialCount 3 4 + // %123 + // DependencyLength|MinIterations|MaxIterations|IterationMultiple|PeelCount|PartialCount + // 2 5 90 4 7 14 + + ASSERT_TRUE(TransformationSetLoopControl(10, SpvLoopControlMaskNone, 0, 0) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(TransformationSetLoopControl(10, SpvLoopControlUnrollMask, 0, 0) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE( + TransformationSetLoopControl(10, SpvLoopControlDontUnrollMask, 0, 0) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(TransformationSetLoopControl( + 10, SpvLoopControlDependencyInfiniteMask, 0, 0) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE( + TransformationSetLoopControl(10, SpvLoopControlDependencyLengthMask, 0, 0) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE( + TransformationSetLoopControl(10, SpvLoopControlMinIterationsMask, 0, 0) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE( + TransformationSetLoopControl(10, SpvLoopControlMaxIterationsMask, 0, 0) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(TransformationSetLoopControl( + 10, SpvLoopControlIterationMultipleMask, 0, 0) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE( + TransformationSetLoopControl(10, SpvLoopControlPeelCountMask, 3, 0) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE( + TransformationSetLoopControl(10, SpvLoopControlPeelCountMask, 3, 3) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE( + TransformationSetLoopControl(10, SpvLoopControlPartialCountMask, 0, 3) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE( + TransformationSetLoopControl(10, SpvLoopControlPartialCountMask, 3, 3) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(TransformationSetLoopControl( + 10, + SpvLoopControlPeelCountMask | SpvLoopControlPartialCountMask, + 3, 3) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(TransformationSetLoopControl(10, + SpvLoopControlUnrollMask | + SpvLoopControlPeelCountMask | + SpvLoopControlPartialCountMask, + 3, 3) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(TransformationSetLoopControl(10, + SpvLoopControlDontUnrollMask | + SpvLoopControlPeelCountMask | + SpvLoopControlPartialCountMask, + 3, 3) + .IsApplicable(context.get(), fact_manager)); + + ASSERT_TRUE(TransformationSetLoopControl(23, SpvLoopControlMaskNone, 0, 0) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(TransformationSetLoopControl(23, SpvLoopControlUnrollMask, 0, 0) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE( + TransformationSetLoopControl(23, SpvLoopControlDontUnrollMask, 0, 0) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(TransformationSetLoopControl( + 23, + SpvLoopControlPeelCountMask | SpvLoopControlPartialCountMask, + 3, 3) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE( + TransformationSetLoopControl(23, SpvLoopControlMaxIterationsMask, 2, 3) + .IsApplicable(context.get(), fact_manager)); + + ASSERT_TRUE(TransformationSetLoopControl(33, SpvLoopControlMaskNone, 0, 0) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(TransformationSetLoopControl(33, SpvLoopControlUnrollMask, 0, 0) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE( + TransformationSetLoopControl(33, SpvLoopControlDontUnrollMask, 0, 0) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE( + TransformationSetLoopControl(33, SpvLoopControlMinIterationsMask, 0, 0) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE( + TransformationSetLoopControl( + 33, SpvLoopControlUnrollMask | SpvLoopControlPeelCountMask, 5, 0) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(TransformationSetLoopControl(33, + SpvLoopControlDontUnrollMask | + SpvLoopControlPartialCountMask, + 0, 10) + .IsApplicable(context.get(), fact_manager)); + + ASSERT_TRUE(TransformationSetLoopControl(43, SpvLoopControlMaskNone, 0, 0) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(TransformationSetLoopControl(43, SpvLoopControlUnrollMask, 0, 0) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE( + TransformationSetLoopControl(43, SpvLoopControlDontUnrollMask, 0, 0) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(TransformationSetLoopControl( + 43, + SpvLoopControlMaskNone | SpvLoopControlDependencyInfiniteMask, + 0, 0) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE( + TransformationSetLoopControl( + 43, SpvLoopControlUnrollMask | SpvLoopControlDependencyInfiniteMask, + 0, 0) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE( + TransformationSetLoopControl( + 43, + SpvLoopControlDontUnrollMask | SpvLoopControlDependencyInfiniteMask, + 0, 0) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE( + TransformationSetLoopControl(43, + SpvLoopControlDependencyInfiniteMask | + SpvLoopControlDependencyLengthMask, + 0, 0) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE( + TransformationSetLoopControl( + 43, SpvLoopControlUnrollMask | SpvLoopControlPeelCountMask, 5, 0) + .IsApplicable(context.get(), fact_manager)); + + ASSERT_TRUE(TransformationSetLoopControl(53, SpvLoopControlMaskNone, 0, 0) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(TransformationSetLoopControl(53, SpvLoopControlUnrollMask, 0, 0) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE( + TransformationSetLoopControl(53, SpvLoopControlDontUnrollMask, 0, 0) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE( + TransformationSetLoopControl(53, SpvLoopControlMaxIterationsMask, 0, 0) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE( + TransformationSetLoopControl( + 53, SpvLoopControlMaskNone | SpvLoopControlDependencyLengthMask, 0, 0) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE( + TransformationSetLoopControl( + 53, SpvLoopControlUnrollMask | SpvLoopControlDependencyInfiniteMask, + 0, 0) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE( + TransformationSetLoopControl( + 53, SpvLoopControlDontUnrollMask | SpvLoopControlDependencyLengthMask, + 0, 0) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE( + TransformationSetLoopControl(53, + SpvLoopControlDependencyInfiniteMask | + SpvLoopControlDependencyLengthMask, + 0, 0) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE( + TransformationSetLoopControl( + 53, + SpvLoopControlUnrollMask | SpvLoopControlDependencyLengthMask | + SpvLoopControlPeelCountMask | SpvLoopControlPartialCountMask, + 5, 3) + .IsApplicable(context.get(), fact_manager)); + + ASSERT_TRUE(TransformationSetLoopControl(63, SpvLoopControlMaskNone, 0, 0) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(TransformationSetLoopControl(63, SpvLoopControlUnrollMask, 0, 0) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE( + TransformationSetLoopControl(63, SpvLoopControlDontUnrollMask, 0, 0) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(TransformationSetLoopControl(63, + SpvLoopControlUnrollMask | + SpvLoopControlMinIterationsMask | + SpvLoopControlPeelCountMask | + SpvLoopControlPartialCountMask, + 5, 3) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(TransformationSetLoopControl(63, + SpvLoopControlUnrollMask | + SpvLoopControlMinIterationsMask | + SpvLoopControlPeelCountMask, + 23, 0) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(TransformationSetLoopControl( + 63, + SpvLoopControlUnrollMask | SpvLoopControlMinIterationsMask | + SpvLoopControlPeelCountMask, + 2, 23) + .IsApplicable(context.get(), fact_manager)); + + ASSERT_TRUE(TransformationSetLoopControl(73, SpvLoopControlMaskNone, 0, 0) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(TransformationSetLoopControl(73, SpvLoopControlUnrollMask, 0, 0) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE( + TransformationSetLoopControl(73, SpvLoopControlDontUnrollMask, 0, 0) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(TransformationSetLoopControl( + 73, + SpvLoopControlUnrollMask | SpvLoopControlMinIterationsMask | + SpvLoopControlPeelCountMask | + SpvLoopControlPartialCountMask, + 5, 3) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(TransformationSetLoopControl(73, + SpvLoopControlUnrollMask | + SpvLoopControlMaxIterationsMask | + SpvLoopControlPeelCountMask, + 23, 0) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(TransformationSetLoopControl( + 73, + SpvLoopControlUnrollMask | SpvLoopControlMaxIterationsMask | + SpvLoopControlPeelCountMask, + 2, 23) + .IsApplicable(context.get(), fact_manager)); + + ASSERT_TRUE(TransformationSetLoopControl(83, SpvLoopControlMaskNone, 0, 0) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(TransformationSetLoopControl(83, SpvLoopControlUnrollMask, 0, 0) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE( + TransformationSetLoopControl(83, SpvLoopControlDontUnrollMask, 0, 0) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(TransformationSetLoopControl( + 83, + SpvLoopControlUnrollMask | SpvLoopControlMinIterationsMask | + SpvLoopControlPeelCountMask | + SpvLoopControlPartialCountMask, + 5, 3) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE( + TransformationSetLoopControl(83, + SpvLoopControlUnrollMask | + SpvLoopControlIterationMultipleMask | + SpvLoopControlPeelCountMask, + 23, 0) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE( + TransformationSetLoopControl(83, + SpvLoopControlUnrollMask | + SpvLoopControlIterationMultipleMask | + SpvLoopControlPeelCountMask, + 2, 23) + .IsApplicable(context.get(), fact_manager)); + + ASSERT_TRUE(TransformationSetLoopControl(93, SpvLoopControlMaskNone, 0, 0) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(TransformationSetLoopControl(93, SpvLoopControlUnrollMask, 0, 0) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE( + TransformationSetLoopControl(93, SpvLoopControlDontUnrollMask, 0, 0) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE( + TransformationSetLoopControl(93, SpvLoopControlPeelCountMask, 8, 0) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE( + TransformationSetLoopControl(93, SpvLoopControlPeelCountMask, 8, 8) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE( + TransformationSetLoopControl(93, SpvLoopControlPartialCountMask, 0, 8) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(TransformationSetLoopControl( + 93, + SpvLoopControlPeelCountMask | SpvLoopControlPartialCountMask, + 16, 8) + .IsApplicable(context.get(), fact_manager)); + + ASSERT_TRUE(TransformationSetLoopControl(103, SpvLoopControlMaskNone, 0, 0) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(TransformationSetLoopControl(103, SpvLoopControlUnrollMask, 0, 0) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE( + TransformationSetLoopControl(103, SpvLoopControlDontUnrollMask, 0, 0) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE( + TransformationSetLoopControl(103, SpvLoopControlPartialCountMask, 0, 60) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(TransformationSetLoopControl(103, + SpvLoopControlDontUnrollMask | + SpvLoopControlPartialCountMask, + 0, 60) + .IsApplicable(context.get(), fact_manager)); + + ASSERT_TRUE(TransformationSetLoopControl(113, SpvLoopControlMaskNone, 0, 0) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(TransformationSetLoopControl(113, SpvLoopControlUnrollMask, 0, 0) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE( + TransformationSetLoopControl(113, SpvLoopControlDontUnrollMask, 0, 0) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE( + TransformationSetLoopControl(113, SpvLoopControlPeelCountMask, 12, 0) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE( + TransformationSetLoopControl( + 113, + SpvLoopControlIterationMultipleMask | SpvLoopControlPeelCountMask, 12, + 0) + .IsApplicable(context.get(), fact_manager)); + + ASSERT_TRUE(TransformationSetLoopControl(123, SpvLoopControlMaskNone, 0, 0) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(TransformationSetLoopControl(123, SpvLoopControlUnrollMask, 0, 0) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE( + TransformationSetLoopControl(123, SpvLoopControlDontUnrollMask, 0, 0) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE( + TransformationSetLoopControl( + 123, + SpvLoopControlMinIterationsMask | SpvLoopControlMaxIterationsMask | + SpvLoopControlIterationMultipleMask | + SpvLoopControlPeelCountMask | SpvLoopControlPartialCountMask, + 7, 8) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(TransformationSetLoopControl(123, + SpvLoopControlUnrollMask | + SpvLoopControlMinIterationsMask | + SpvLoopControlMaxIterationsMask | + SpvLoopControlPartialCountMask, + 0, 9) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(TransformationSetLoopControl( + 123, + SpvLoopControlUnrollMask | SpvLoopControlMinIterationsMask | + SpvLoopControlMaxIterationsMask | + SpvLoopControlPartialCountMask, + 7, 9) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE( + TransformationSetLoopControl( + 123, + SpvLoopControlDontUnrollMask | SpvLoopControlMinIterationsMask | + SpvLoopControlMaxIterationsMask | SpvLoopControlPartialCountMask, + 7, 9) + .IsApplicable(context.get(), fact_manager)); + + TransformationSetLoopControl(10, + SpvLoopControlUnrollMask | + SpvLoopControlPeelCountMask | + SpvLoopControlPartialCountMask, + 3, 3) + .Apply(context.get(), &fact_manager); + TransformationSetLoopControl(23, SpvLoopControlDontUnrollMask, 0, 0) + .Apply(context.get(), &fact_manager); + TransformationSetLoopControl(33, SpvLoopControlUnrollMask, 0, 0) + .Apply(context.get(), &fact_manager); + TransformationSetLoopControl( + 43, SpvLoopControlDontUnrollMask | SpvLoopControlDependencyInfiniteMask, + 0, 0) + .Apply(context.get(), &fact_manager); + TransformationSetLoopControl(53, SpvLoopControlMaskNone, 0, 0) + .Apply(context.get(), &fact_manager); + TransformationSetLoopControl(63, + SpvLoopControlUnrollMask | + SpvLoopControlMinIterationsMask | + SpvLoopControlPeelCountMask, + 23, 0) + .Apply(context.get(), &fact_manager); + TransformationSetLoopControl(73, + SpvLoopControlUnrollMask | + SpvLoopControlMaxIterationsMask | + SpvLoopControlPeelCountMask, + 23, 0) + .Apply(context.get(), &fact_manager); + TransformationSetLoopControl(83, SpvLoopControlDontUnrollMask, 0, 0) + .Apply(context.get(), &fact_manager); + TransformationSetLoopControl( + 93, SpvLoopControlPeelCountMask | SpvLoopControlPartialCountMask, 16, 8) + .Apply(context.get(), &fact_manager); + TransformationSetLoopControl(103, SpvLoopControlPartialCountMask, 0, 60) + .Apply(context.get(), &fact_manager); + TransformationSetLoopControl(113, SpvLoopControlPeelCountMask, 12, 0) + .Apply(context.get(), &fact_manager); + TransformationSetLoopControl( + 123, + SpvLoopControlUnrollMask | SpvLoopControlMinIterationsMask | + SpvLoopControlMaxIterationsMask | SpvLoopControlPartialCountMask, + 0, 9) + .Apply(context.get(), &fact_manager); + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 0 + %16 = OpConstant %6 100 + %17 = OpTypeBool + %20 = OpConstant %6 1 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %22 = OpVariable %7 Function + %32 = OpVariable %7 Function + %42 = OpVariable %7 Function + %52 = OpVariable %7 Function + %62 = OpVariable %7 Function + %72 = OpVariable %7 Function + %82 = OpVariable %7 Function + %92 = OpVariable %7 Function + %102 = OpVariable %7 Function + %112 = OpVariable %7 Function + %122 = OpVariable %7 Function + OpStore %8 %9 + OpBranch %10 + %10 = OpLabel + %132 = OpPhi %6 %9 %5 %21 %13 + OpLoopMerge %12 %13 Unroll|PeelCount|PartialCount 3 3 + OpBranch %14 + %14 = OpLabel + %18 = OpSLessThan %17 %132 %16 + OpBranchConditional %18 %11 %12 + %11 = OpLabel + OpBranch %13 + %13 = OpLabel + %21 = OpIAdd %6 %132 %20 + OpStore %8 %21 + OpBranch %10 + %12 = OpLabel + OpStore %22 %9 + OpBranch %23 + %23 = OpLabel + %133 = OpPhi %6 %9 %12 %31 %26 + OpLoopMerge %25 %26 DontUnroll + OpBranch %27 + %27 = OpLabel + %29 = OpSLessThan %17 %133 %16 + OpBranchConditional %29 %24 %25 + %24 = OpLabel + OpBranch %26 + %26 = OpLabel + %31 = OpIAdd %6 %133 %20 + OpStore %22 %31 + OpBranch %23 + %25 = OpLabel + OpStore %32 %9 + OpBranch %33 + %33 = OpLabel + %134 = OpPhi %6 %9 %25 %41 %36 + OpLoopMerge %35 %36 Unroll + OpBranch %37 + %37 = OpLabel + %39 = OpSLessThan %17 %134 %16 + OpBranchConditional %39 %34 %35 + %34 = OpLabel + OpBranch %36 + %36 = OpLabel + %41 = OpIAdd %6 %134 %20 + OpStore %32 %41 + OpBranch %33 + %35 = OpLabel + OpStore %42 %9 + OpBranch %43 + %43 = OpLabel + %135 = OpPhi %6 %9 %35 %51 %46 + OpLoopMerge %45 %46 DontUnroll|DependencyInfinite + OpBranch %47 + %47 = OpLabel + %49 = OpSLessThan %17 %135 %16 + OpBranchConditional %49 %44 %45 + %44 = OpLabel + OpBranch %46 + %46 = OpLabel + %51 = OpIAdd %6 %135 %20 + OpStore %42 %51 + OpBranch %43 + %45 = OpLabel + OpStore %52 %9 + OpBranch %53 + %53 = OpLabel + %136 = OpPhi %6 %9 %45 %61 %56 + OpLoopMerge %55 %56 None + OpBranch %57 + %57 = OpLabel + %59 = OpSLessThan %17 %136 %16 + OpBranchConditional %59 %54 %55 + %54 = OpLabel + OpBranch %56 + %56 = OpLabel + %61 = OpIAdd %6 %136 %20 + OpStore %52 %61 + OpBranch %53 + %55 = OpLabel + OpStore %62 %9 + OpBranch %63 + %63 = OpLabel + %137 = OpPhi %6 %9 %55 %71 %66 + OpLoopMerge %65 %66 Unroll|MinIterations|PeelCount 10 23 + OpBranch %67 + %67 = OpLabel + %69 = OpSLessThan %17 %137 %16 + OpBranchConditional %69 %64 %65 + %64 = OpLabel + OpBranch %66 + %66 = OpLabel + %71 = OpIAdd %6 %137 %20 + OpStore %62 %71 + OpBranch %63 + %65 = OpLabel + OpStore %72 %9 + OpBranch %73 + %73 = OpLabel + %138 = OpPhi %6 %9 %65 %81 %76 + OpLoopMerge %75 %76 Unroll|MaxIterations|PeelCount 50 23 + OpBranch %77 + %77 = OpLabel + %79 = OpSLessThan %17 %138 %16 + OpBranchConditional %79 %74 %75 + %74 = OpLabel + OpBranch %76 + %76 = OpLabel + %81 = OpIAdd %6 %138 %20 + OpStore %72 %81 + OpBranch %73 + %75 = OpLabel + OpStore %82 %9 + OpBranch %83 + %83 = OpLabel + %139 = OpPhi %6 %9 %75 %91 %86 + OpLoopMerge %85 %86 DontUnroll + OpBranch %87 + %87 = OpLabel + %89 = OpSLessThan %17 %139 %16 + OpBranchConditional %89 %84 %85 + %84 = OpLabel + OpBranch %86 + %86 = OpLabel + %91 = OpIAdd %6 %139 %20 + OpStore %82 %91 + OpBranch %83 + %85 = OpLabel + OpStore %92 %9 + OpBranch %93 + %93 = OpLabel + %140 = OpPhi %6 %9 %85 %101 %96 + OpLoopMerge %95 %96 PeelCount|PartialCount 16 8 + OpBranch %97 + %97 = OpLabel + %99 = OpSLessThan %17 %140 %16 + OpBranchConditional %99 %94 %95 + %94 = OpLabel + OpBranch %96 + %96 = OpLabel + %101 = OpIAdd %6 %140 %20 + OpStore %92 %101 + OpBranch %93 + %95 = OpLabel + OpStore %102 %9 + OpBranch %103 + %103 = OpLabel + %141 = OpPhi %6 %9 %95 %111 %106 + OpLoopMerge %105 %106 PartialCount 60 + OpBranch %107 + %107 = OpLabel + %109 = OpSLessThan %17 %141 %16 + OpBranchConditional %109 %104 %105 + %104 = OpLabel + OpBranch %106 + %106 = OpLabel + %111 = OpIAdd %6 %141 %20 + OpStore %102 %111 + OpBranch %103 + %105 = OpLabel + OpStore %112 %9 + OpBranch %113 + %113 = OpLabel + %142 = OpPhi %6 %9 %105 %121 %116 + OpLoopMerge %115 %116 PeelCount 12 + OpBranch %117 + %117 = OpLabel + %119 = OpSLessThan %17 %142 %16 + OpBranchConditional %119 %114 %115 + %114 = OpLabel + OpBranch %116 + %116 = OpLabel + %121 = OpIAdd %6 %142 %20 + OpStore %112 %121 + OpBranch %113 + %115 = OpLabel + OpStore %122 %9 + OpBranch %123 + %123 = OpLabel + %143 = OpPhi %6 %9 %115 %131 %126 + OpLoopMerge %125 %126 Unroll|MinIterations|MaxIterations|PartialCount 5 90 9 + OpBranch %127 + %127 = OpLabel + %129 = OpSLessThan %17 %143 %16 + OpBranchConditional %129 %124 %125 + %124 = OpLabel + OpBranch %126 + %126 = OpLabel + %131 = OpIAdd %6 %143 %20 + OpStore %122 %131 + OpBranch %123 + %125 = OpLabel + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +TEST(TransformationSetLoopControlTest, CheckSPIRVVersionsRespected) { + // This test checks that we do not allow introducing PeelCount and + // PartialCount loop controls if the SPIR-V version being used does not + // support them. + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %8 "i" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 0 + %16 = OpConstant %6 10 + %17 = OpTypeBool + %20 = OpConstant %6 1 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + OpStore %8 %9 + OpBranch %10 + %10 = OpLabel + OpLoopMerge %12 %13 None + OpBranch %14 + %14 = OpLabel + %15 = OpLoad %6 %8 + %18 = OpSLessThan %17 %15 %16 + OpBranchConditional %18 %11 %12 + %11 = OpLabel + OpBranch %13 + %13 = OpLabel + %19 = OpLoad %6 %8 + %21 = OpIAdd %6 %19 %20 + OpStore %8 %21 + OpBranch %10 + %12 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto consumer = nullptr; + const auto context_1_0 = + BuildModule(SPV_ENV_UNIVERSAL_1_0, consumer, shader, kFuzzAssembleOption); + const auto context_1_1 = + BuildModule(SPV_ENV_UNIVERSAL_1_1, consumer, shader, kFuzzAssembleOption); + const auto context_1_2 = + BuildModule(SPV_ENV_UNIVERSAL_1_2, consumer, shader, kFuzzAssembleOption); + const auto context_1_3 = + BuildModule(SPV_ENV_UNIVERSAL_1_3, consumer, shader, kFuzzAssembleOption); + const auto context_1_4 = + BuildModule(SPV_ENV_UNIVERSAL_1_4, consumer, shader, kFuzzAssembleOption); + const auto context_1_5 = + BuildModule(SPV_ENV_UNIVERSAL_1_5, consumer, shader, kFuzzAssembleOption); + + FactManager fact_manager; + + TransformationSetLoopControl set_peel_and_partial( + 10, SpvLoopControlPeelCountMask | SpvLoopControlPartialCountMask, 4, 4); + + // PeelCount and PartialCount were introduced in SPIRV 1.4, so are not valid + // in the context of older versions. + ASSERT_FALSE( + set_peel_and_partial.IsApplicable(context_1_0.get(), fact_manager)); + ASSERT_FALSE( + set_peel_and_partial.IsApplicable(context_1_1.get(), fact_manager)); + ASSERT_FALSE( + set_peel_and_partial.IsApplicable(context_1_2.get(), fact_manager)); + ASSERT_FALSE( + set_peel_and_partial.IsApplicable(context_1_3.get(), fact_manager)); + + ASSERT_TRUE( + set_peel_and_partial.IsApplicable(context_1_4.get(), fact_manager)); + ASSERT_TRUE( + set_peel_and_partial.IsApplicable(context_1_5.get(), fact_manager)); +} + +} // namespace +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/test/fuzz/transformation_set_memory_operands_mask_test.cpp b/third_party/spirv-tools/test/fuzz/transformation_set_memory_operands_mask_test.cpp new file mode 100644 index 0000000000..ad4dc2567e --- /dev/null +++ b/third_party/spirv-tools/test/fuzz/transformation_set_memory_operands_mask_test.cpp @@ -0,0 +1,432 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_set_memory_operands_mask.h" +#include "source/fuzz/instruction_descriptor.h" +#include "test/fuzz/fuzz_test_util.h" + +namespace spvtools { +namespace fuzz { +namespace { + +TEST(TransformationSetMemoryOperandsMaskTest, PreSpirv14) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %7 "Point3D" + OpMemberName %7 0 "x" + OpMemberName %7 1 "y" + OpMemberName %7 2 "z" + OpName %12 "global_points" + OpName %15 "block" + OpMemberName %15 0 "in_points" + OpMemberName %15 1 "in_point" + OpName %17 "" + OpName %133 "local_points" + OpMemberDecorate %7 0 Offset 0 + OpMemberDecorate %7 1 Offset 4 + OpMemberDecorate %7 2 Offset 8 + OpDecorate %10 ArrayStride 16 + OpMemberDecorate %15 0 Offset 0 + OpMemberDecorate %15 1 Offset 192 + OpDecorate %15 Block + OpDecorate %17 DescriptorSet 0 + OpDecorate %17 Binding 0 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypeStruct %6 %6 %6 + %8 = OpTypeInt 32 0 + %9 = OpConstant %8 12 + %10 = OpTypeArray %7 %9 + %11 = OpTypePointer Private %10 + %12 = OpVariable %11 Private + %15 = OpTypeStruct %10 %7 + %16 = OpTypePointer Uniform %15 + %17 = OpVariable %16 Uniform + %18 = OpTypeInt 32 1 + %19 = OpConstant %18 0 + %20 = OpTypePointer Uniform %10 + %24 = OpTypePointer Private %7 + %27 = OpTypePointer Private %6 + %30 = OpConstant %18 1 + %132 = OpTypePointer Function %10 + %135 = OpTypePointer Uniform %7 + %145 = OpTypePointer Function %7 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %133 = OpVariable %132 Function + %21 = OpAccessChain %20 %17 %19 + OpCopyMemory %12 %21 Aligned 16 + OpCopyMemory %133 %12 Volatile + %136 = OpAccessChain %135 %17 %30 + %138 = OpAccessChain %24 %12 %19 + OpCopyMemory %138 %136 None + %146 = OpAccessChain %145 %133 %30 + %147 = OpLoad %7 %146 Volatile|Nontemporal|Aligned 16 + %148 = OpAccessChain %24 %12 %19 + OpStore %148 %147 Nontemporal + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + // Not OK: the instruction is not a memory access. + ASSERT_FALSE(TransformationSetMemoryOperandsMask( + MakeInstructionDescriptor(21, SpvOpAccessChain, 0), + SpvMemoryAccessMaskNone, 0) + .IsApplicable(context.get(), fact_manager)); + + // Not OK to remove Aligned + ASSERT_FALSE(TransformationSetMemoryOperandsMask( + MakeInstructionDescriptor(147, SpvOpLoad, 0), + SpvMemoryAccessVolatileMask | SpvMemoryAccessNontemporalMask, + 0) + .IsApplicable(context.get(), fact_manager)); + + TransformationSetMemoryOperandsMask transformation1( + MakeInstructionDescriptor(147, SpvOpLoad, 0), + SpvMemoryAccessAlignedMask | SpvMemoryAccessVolatileMask, 0); + ASSERT_TRUE(transformation1.IsApplicable(context.get(), fact_manager)); + transformation1.Apply(context.get(), &fact_manager); + + // Not OK to remove Aligned + ASSERT_FALSE(TransformationSetMemoryOperandsMask( + MakeInstructionDescriptor(21, SpvOpCopyMemory, 0), + SpvMemoryAccessMaskNone, 0) + .IsApplicable(context.get(), fact_manager)); + + // OK: leaves the mask as is + ASSERT_TRUE(TransformationSetMemoryOperandsMask( + MakeInstructionDescriptor(21, SpvOpCopyMemory, 0), + SpvMemoryAccessAlignedMask, 0) + .IsApplicable(context.get(), fact_manager)); + + // OK: adds Nontemporal and Volatile + TransformationSetMemoryOperandsMask transformation2( + MakeInstructionDescriptor(21, SpvOpCopyMemory, 0), + SpvMemoryAccessAlignedMask | SpvMemoryAccessNontemporalMask | + SpvMemoryAccessVolatileMask, + 0); + ASSERT_TRUE(transformation2.IsApplicable(context.get(), fact_manager)); + transformation2.Apply(context.get(), &fact_manager); + + // Not OK to remove Volatile + ASSERT_FALSE(TransformationSetMemoryOperandsMask( + MakeInstructionDescriptor(21, SpvOpCopyMemory, 1), + SpvMemoryAccessNontemporalMask, 0) + .IsApplicable(context.get(), fact_manager)); + + // Not OK to add Aligned + ASSERT_FALSE(TransformationSetMemoryOperandsMask( + MakeInstructionDescriptor(21, SpvOpCopyMemory, 1), + SpvMemoryAccessAlignedMask | SpvMemoryAccessVolatileMask, 0) + .IsApplicable(context.get(), fact_manager)); + + // OK: adds Nontemporal + TransformationSetMemoryOperandsMask transformation3( + MakeInstructionDescriptor(21, SpvOpCopyMemory, 1), + SpvMemoryAccessNontemporalMask | SpvMemoryAccessVolatileMask, 0); + ASSERT_TRUE(transformation3.IsApplicable(context.get(), fact_manager)); + transformation3.Apply(context.get(), &fact_manager); + + // OK: adds Nontemporal and Volatile + TransformationSetMemoryOperandsMask transformation4( + MakeInstructionDescriptor(138, SpvOpCopyMemory, 0), + SpvMemoryAccessNontemporalMask | SpvMemoryAccessVolatileMask, 0); + ASSERT_TRUE(transformation4.IsApplicable(context.get(), fact_manager)); + transformation4.Apply(context.get(), &fact_manager); + + // OK: removes Nontemporal, adds Volatile + TransformationSetMemoryOperandsMask transformation5( + MakeInstructionDescriptor(148, SpvOpStore, 0), + SpvMemoryAccessVolatileMask, 0); + ASSERT_TRUE(transformation5.IsApplicable(context.get(), fact_manager)); + transformation5.Apply(context.get(), &fact_manager); + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %7 "Point3D" + OpMemberName %7 0 "x" + OpMemberName %7 1 "y" + OpMemberName %7 2 "z" + OpName %12 "global_points" + OpName %15 "block" + OpMemberName %15 0 "in_points" + OpMemberName %15 1 "in_point" + OpName %17 "" + OpName %133 "local_points" + OpMemberDecorate %7 0 Offset 0 + OpMemberDecorate %7 1 Offset 4 + OpMemberDecorate %7 2 Offset 8 + OpDecorate %10 ArrayStride 16 + OpMemberDecorate %15 0 Offset 0 + OpMemberDecorate %15 1 Offset 192 + OpDecorate %15 Block + OpDecorate %17 DescriptorSet 0 + OpDecorate %17 Binding 0 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypeStruct %6 %6 %6 + %8 = OpTypeInt 32 0 + %9 = OpConstant %8 12 + %10 = OpTypeArray %7 %9 + %11 = OpTypePointer Private %10 + %12 = OpVariable %11 Private + %15 = OpTypeStruct %10 %7 + %16 = OpTypePointer Uniform %15 + %17 = OpVariable %16 Uniform + %18 = OpTypeInt 32 1 + %19 = OpConstant %18 0 + %20 = OpTypePointer Uniform %10 + %24 = OpTypePointer Private %7 + %27 = OpTypePointer Private %6 + %30 = OpConstant %18 1 + %132 = OpTypePointer Function %10 + %135 = OpTypePointer Uniform %7 + %145 = OpTypePointer Function %7 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %133 = OpVariable %132 Function + %21 = OpAccessChain %20 %17 %19 + OpCopyMemory %12 %21 Aligned|Nontemporal|Volatile 16 + OpCopyMemory %133 %12 Nontemporal|Volatile + %136 = OpAccessChain %135 %17 %30 + %138 = OpAccessChain %24 %12 %19 + OpCopyMemory %138 %136 Nontemporal|Volatile + %146 = OpAccessChain %145 %133 %30 + %147 = OpLoad %7 %146 Aligned|Volatile 16 + %148 = OpAccessChain %24 %12 %19 + OpStore %148 %147 Volatile + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +TEST(TransformationSetMemoryOperandsMaskTest, Spirv14) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" %12 %17 + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %7 "Point3D" + OpMemberName %7 0 "x" + OpMemberName %7 1 "y" + OpMemberName %7 2 "z" + OpName %12 "global_points" + OpName %15 "block" + OpMemberName %15 0 "in_points" + OpMemberName %15 1 "in_point" + OpName %17 "" + OpName %133 "local_points" + OpMemberDecorate %7 0 Offset 0 + OpMemberDecorate %7 1 Offset 4 + OpMemberDecorate %7 2 Offset 8 + OpDecorate %10 ArrayStride 16 + OpMemberDecorate %15 0 Offset 0 + OpMemberDecorate %15 1 Offset 192 + OpDecorate %15 Block + OpDecorate %17 DescriptorSet 0 + OpDecorate %17 Binding 0 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypeStruct %6 %6 %6 + %8 = OpTypeInt 32 0 + %9 = OpConstant %8 12 + %10 = OpTypeArray %7 %9 + %11 = OpTypePointer Private %10 + %12 = OpVariable %11 Private + %15 = OpTypeStruct %10 %7 + %16 = OpTypePointer Uniform %15 + %17 = OpVariable %16 Uniform + %18 = OpTypeInt 32 1 + %19 = OpConstant %18 0 + %20 = OpTypePointer Uniform %10 + %24 = OpTypePointer Private %7 + %27 = OpTypePointer Private %6 + %30 = OpConstant %18 1 + %132 = OpTypePointer Function %10 + %135 = OpTypePointer Uniform %7 + %145 = OpTypePointer Function %7 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %133 = OpVariable %132 Function + %21 = OpAccessChain %20 %17 %19 + OpCopyMemory %12 %21 Aligned 16 Nontemporal|Aligned 16 + OpCopyMemory %133 %12 Volatile + %136 = OpAccessChain %135 %17 %30 + %138 = OpAccessChain %24 %12 %19 + OpCopyMemory %138 %136 None Aligned 16 + OpCopyMemory %138 %136 Aligned 16 + %146 = OpAccessChain %145 %133 %30 + %147 = OpLoad %7 %146 Volatile|Nontemporal|Aligned 16 + %148 = OpAccessChain %24 %12 %19 + OpStore %148 %147 Nontemporal + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + TransformationSetMemoryOperandsMask transformation1( + MakeInstructionDescriptor(21, SpvOpCopyMemory, 0), + SpvMemoryAccessAlignedMask | SpvMemoryAccessVolatileMask, 1); + // Bad: cannot remove aligned + ASSERT_FALSE(TransformationSetMemoryOperandsMask( + MakeInstructionDescriptor(21, SpvOpCopyMemory, 0), + SpvMemoryAccessVolatileMask, 1) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(transformation1.IsApplicable(context.get(), fact_manager)); + transformation1.Apply(context.get(), &fact_manager); + + TransformationSetMemoryOperandsMask transformation2( + MakeInstructionDescriptor(21, SpvOpCopyMemory, 1), + SpvMemoryAccessNontemporalMask | SpvMemoryAccessVolatileMask, 1); + // Bad: cannot remove volatile + ASSERT_FALSE(TransformationSetMemoryOperandsMask( + MakeInstructionDescriptor(21, SpvOpCopyMemory, 1), + SpvMemoryAccessNontemporalMask, 0) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(transformation2.IsApplicable(context.get(), fact_manager)); + transformation2.Apply(context.get(), &fact_manager); + + TransformationSetMemoryOperandsMask transformation3( + MakeInstructionDescriptor(138, SpvOpCopyMemory, 0), + SpvMemoryAccessAlignedMask | SpvMemoryAccessNontemporalMask, 1); + // Bad: the first mask is None, so Aligned cannot be added to it. + ASSERT_FALSE(TransformationSetMemoryOperandsMask( + MakeInstructionDescriptor(138, SpvOpCopyMemory, 0), + SpvMemoryAccessAlignedMask | SpvMemoryAccessNontemporalMask, + 0) + .IsApplicable(context.get(), fact_manager)); + ASSERT_TRUE(transformation3.IsApplicable(context.get(), fact_manager)); + transformation3.Apply(context.get(), &fact_manager); + + TransformationSetMemoryOperandsMask transformation4( + MakeInstructionDescriptor(138, SpvOpCopyMemory, 1), + SpvMemoryAccessVolatileMask, 1); + ASSERT_TRUE(transformation4.IsApplicable(context.get(), fact_manager)); + transformation4.Apply(context.get(), &fact_manager); + + TransformationSetMemoryOperandsMask transformation5( + MakeInstructionDescriptor(147, SpvOpLoad, 0), + SpvMemoryAccessVolatileMask | SpvMemoryAccessAlignedMask, 0); + ASSERT_TRUE(transformation5.IsApplicable(context.get(), fact_manager)); + transformation5.Apply(context.get(), &fact_manager); + + TransformationSetMemoryOperandsMask transformation6( + MakeInstructionDescriptor(148, SpvOpStore, 0), SpvMemoryAccessMaskNone, + 0); + ASSERT_TRUE(transformation6.IsApplicable(context.get(), fact_manager)); + transformation6.Apply(context.get(), &fact_manager); + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" %12 %17 + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %7 "Point3D" + OpMemberName %7 0 "x" + OpMemberName %7 1 "y" + OpMemberName %7 2 "z" + OpName %12 "global_points" + OpName %15 "block" + OpMemberName %15 0 "in_points" + OpMemberName %15 1 "in_point" + OpName %17 "" + OpName %133 "local_points" + OpMemberDecorate %7 0 Offset 0 + OpMemberDecorate %7 1 Offset 4 + OpMemberDecorate %7 2 Offset 8 + OpDecorate %10 ArrayStride 16 + OpMemberDecorate %15 0 Offset 0 + OpMemberDecorate %15 1 Offset 192 + OpDecorate %15 Block + OpDecorate %17 DescriptorSet 0 + OpDecorate %17 Binding 0 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypeStruct %6 %6 %6 + %8 = OpTypeInt 32 0 + %9 = OpConstant %8 12 + %10 = OpTypeArray %7 %9 + %11 = OpTypePointer Private %10 + %12 = OpVariable %11 Private + %15 = OpTypeStruct %10 %7 + %16 = OpTypePointer Uniform %15 + %17 = OpVariable %16 Uniform + %18 = OpTypeInt 32 1 + %19 = OpConstant %18 0 + %20 = OpTypePointer Uniform %10 + %24 = OpTypePointer Private %7 + %27 = OpTypePointer Private %6 + %30 = OpConstant %18 1 + %132 = OpTypePointer Function %10 + %135 = OpTypePointer Uniform %7 + %145 = OpTypePointer Function %7 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %133 = OpVariable %132 Function + %21 = OpAccessChain %20 %17 %19 + OpCopyMemory %12 %21 Aligned 16 Aligned|Volatile 16 + OpCopyMemory %133 %12 Volatile Nontemporal|Volatile + %136 = OpAccessChain %135 %17 %30 + %138 = OpAccessChain %24 %12 %19 + OpCopyMemory %138 %136 None Aligned|Nontemporal 16 + OpCopyMemory %138 %136 Aligned 16 Volatile + %146 = OpAccessChain %145 %133 %30 + %147 = OpLoad %7 %146 Volatile|Aligned 16 + %148 = OpAccessChain %24 %12 %19 + OpStore %148 %147 None + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +} // namespace +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/test/fuzz/transformation_set_selection_control_test.cpp b/third_party/spirv-tools/test/fuzz/transformation_set_selection_control_test.cpp new file mode 100644 index 0000000000..9696417b0d --- /dev/null +++ b/third_party/spirv-tools/test/fuzz/transformation_set_selection_control_test.cpp @@ -0,0 +1,219 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_set_selection_control.h" +#include "test/fuzz/fuzz_test_util.h" + +namespace spvtools { +namespace fuzz { +namespace { + +TEST(TransformationSetSelectionControlTest, VariousScenarios) { + // This is a simple transformation; this test captures the important things + // to check for. + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %8 "i" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 0 + %16 = OpConstant %6 10 + %17 = OpTypeBool + %20 = OpConstant %6 3 + %25 = OpConstant %6 1 + %28 = OpConstant %6 2 + %38 = OpConstant %6 4 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + OpStore %8 %9 + OpBranch %10 + %10 = OpLabel + OpLoopMerge %12 %13 None + OpBranch %14 + %14 = OpLabel + %15 = OpLoad %6 %8 + %18 = OpSLessThan %17 %15 %16 + OpBranchConditional %18 %11 %12 + %11 = OpLabel + %19 = OpLoad %6 %8 + %21 = OpSGreaterThan %17 %19 %20 + OpSelectionMerge %23 Flatten + OpBranchConditional %21 %22 %23 + %22 = OpLabel + %24 = OpLoad %6 %8 + %26 = OpIAdd %6 %24 %25 + OpStore %8 %26 + OpBranch %23 + %23 = OpLabel + %27 = OpLoad %6 %8 + %29 = OpSLessThan %17 %27 %28 + OpSelectionMerge %31 DontFlatten + OpBranchConditional %29 %30 %31 + %30 = OpLabel + %32 = OpLoad %6 %8 + %33 = OpISub %6 %32 %25 + OpStore %8 %33 + OpBranch %31 + %31 = OpLabel + %34 = OpLoad %6 %8 + OpSelectionMerge %37 None + OpSwitch %34 %36 0 %35 + %36 = OpLabel + OpBranch %37 + %35 = OpLabel + %39 = OpLoad %6 %8 + %40 = OpIAdd %6 %39 %38 + OpStore %8 %40 + OpBranch %36 + %37 = OpLabel + OpBranch %13 + %13 = OpLabel + %43 = OpLoad %6 %8 + %44 = OpIAdd %6 %43 %25 + OpStore %8 %44 + OpBranch %10 + %12 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + + FactManager fact_manager; + + // %44 is not a block + ASSERT_FALSE( + TransformationSetSelectionControl(44, SpvSelectionControlFlattenMask) + .IsApplicable(context.get(), fact_manager)); + // %13 does not end with OpSelectionMerge + ASSERT_FALSE( + TransformationSetSelectionControl(13, SpvSelectionControlMaskNone) + .IsApplicable(context.get(), fact_manager)); + // %10 ends in OpLoopMerge, not OpSelectionMerge + ASSERT_FALSE( + TransformationSetSelectionControl(10, SpvSelectionControlMaskNone) + .IsApplicable(context.get(), fact_manager)); + + TransformationSetSelectionControl transformation1( + 11, SpvSelectionControlDontFlattenMask); + ASSERT_TRUE(transformation1.IsApplicable(context.get(), fact_manager)); + transformation1.Apply(context.get(), &fact_manager); + + TransformationSetSelectionControl transformation2( + 23, SpvSelectionControlFlattenMask); + ASSERT_TRUE(transformation2.IsApplicable(context.get(), fact_manager)); + transformation2.Apply(context.get(), &fact_manager); + + TransformationSetSelectionControl transformation3( + 31, SpvSelectionControlMaskNone); + ASSERT_TRUE(transformation3.IsApplicable(context.get(), fact_manager)); + transformation3.Apply(context.get(), &fact_manager); + + TransformationSetSelectionControl transformation4( + 31, SpvSelectionControlFlattenMask); + ASSERT_TRUE(transformation4.IsApplicable(context.get(), fact_manager)); + transformation4.Apply(context.get(), &fact_manager); + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %8 "i" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 0 + %16 = OpConstant %6 10 + %17 = OpTypeBool + %20 = OpConstant %6 3 + %25 = OpConstant %6 1 + %28 = OpConstant %6 2 + %38 = OpConstant %6 4 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + OpStore %8 %9 + OpBranch %10 + %10 = OpLabel + OpLoopMerge %12 %13 None + OpBranch %14 + %14 = OpLabel + %15 = OpLoad %6 %8 + %18 = OpSLessThan %17 %15 %16 + OpBranchConditional %18 %11 %12 + %11 = OpLabel + %19 = OpLoad %6 %8 + %21 = OpSGreaterThan %17 %19 %20 + OpSelectionMerge %23 DontFlatten + OpBranchConditional %21 %22 %23 + %22 = OpLabel + %24 = OpLoad %6 %8 + %26 = OpIAdd %6 %24 %25 + OpStore %8 %26 + OpBranch %23 + %23 = OpLabel + %27 = OpLoad %6 %8 + %29 = OpSLessThan %17 %27 %28 + OpSelectionMerge %31 Flatten + OpBranchConditional %29 %30 %31 + %30 = OpLabel + %32 = OpLoad %6 %8 + %33 = OpISub %6 %32 %25 + OpStore %8 %33 + OpBranch %31 + %31 = OpLabel + %34 = OpLoad %6 %8 + OpSelectionMerge %37 Flatten + OpSwitch %34 %36 0 %35 + %36 = OpLabel + OpBranch %37 + %35 = OpLabel + %39 = OpLoad %6 %8 + %40 = OpIAdd %6 %39 %38 + OpStore %8 %40 + OpBranch %36 + %37 = OpLabel + OpBranch %13 + %13 = OpLabel + %43 = OpLoad %6 %8 + %44 = OpIAdd %6 %43 %25 + OpStore %8 %44 + OpBranch %10 + %12 = OpLabel + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +} // namespace +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/test/fuzz/transformation_split_block_test.cpp b/third_party/spirv-tools/test/fuzz/transformation_split_block_test.cpp new file mode 100644 index 0000000000..09007a5b6d --- /dev/null +++ b/third_party/spirv-tools/test/fuzz/transformation_split_block_test.cpp @@ -0,0 +1,850 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_split_block.h" +#include "source/fuzz/instruction_descriptor.h" +#include "test/fuzz/fuzz_test_util.h" + +namespace spvtools { +namespace fuzz { +namespace { + +TEST(TransformationSplitBlockTest, NotApplicable) { + // The SPIR-V in this test came from the following fragment shader, with + // local store elimination applied to get some OpPhi instructions. + // + // void main() { + // int x; + // int i; + // for (i = 0; i < 100; i++) { + // x += i; + // } + // } + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %8 "i" + OpName %19 "x" + OpDecorate %8 RelaxedPrecision + OpDecorate %19 RelaxedPrecision + OpDecorate %22 RelaxedPrecision + OpDecorate %25 RelaxedPrecision + OpDecorate %26 RelaxedPrecision + OpDecorate %27 RelaxedPrecision + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 0 + %16 = OpConstant %6 100 + %17 = OpTypeBool + %24 = OpConstant %6 1 + %28 = OpUndef %6 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %19 = OpVariable %7 Function + OpStore %8 %9 + OpBranch %10 + %10 = OpLabel + %27 = OpPhi %6 %28 %5 %22 %13 + %26 = OpPhi %6 %9 %5 %25 %13 + OpLoopMerge %12 %13 None + OpBranch %14 + %14 = OpLabel + %18 = OpSLessThan %17 %26 %16 + OpBranchConditional %18 %11 %12 + %11 = OpLabel + %22 = OpIAdd %6 %27 %26 + OpStore %19 %22 + OpBranch %13 + %13 = OpLabel + %25 = OpIAdd %6 %26 %24 + OpStore %8 %25 + OpBranch %10 + %12 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + + FactManager fact_manager; + + // No split before OpVariable + ASSERT_FALSE(TransformationSplitBlock( + MakeInstructionDescriptor(8, SpvOpVariable, 0), 100) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(TransformationSplitBlock( + MakeInstructionDescriptor(8, SpvOpVariable, 1), 100) + .IsApplicable(context.get(), fact_manager)); + + // No split before OpLabel + ASSERT_FALSE(TransformationSplitBlock( + MakeInstructionDescriptor(14, SpvOpLabel, 0), 100) + .IsApplicable(context.get(), fact_manager)); + + // No split if base instruction is outside a function + ASSERT_FALSE( + TransformationSplitBlock(MakeInstructionDescriptor(1, SpvOpLabel, 0), 100) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(TransformationSplitBlock( + MakeInstructionDescriptor(1, SpvOpExecutionMode, 0), 100) + .IsApplicable(context.get(), fact_manager)); + + // No split if block is loop header + ASSERT_FALSE( + TransformationSplitBlock(MakeInstructionDescriptor(27, SpvOpPhi, 0), 100) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE( + TransformationSplitBlock(MakeInstructionDescriptor(27, SpvOpPhi, 1), 100) + .IsApplicable(context.get(), fact_manager)); + + // No split if base instruction does not exist + ASSERT_FALSE( + TransformationSplitBlock(MakeInstructionDescriptor(88, SpvOpIAdd, 0), 100) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(TransformationSplitBlock( + MakeInstructionDescriptor(88, SpvOpIMul, 22), 100) + .IsApplicable(context.get(), fact_manager)); + + // No split if too many instructions with the desired opcode are skipped + ASSERT_FALSE( + TransformationSplitBlock( + MakeInstructionDescriptor(18, SpvOpBranchConditional, 1), 100) + .IsApplicable(context.get(), fact_manager)); + + // No split if id in use + ASSERT_FALSE(TransformationSplitBlock( + MakeInstructionDescriptor(18, SpvOpSLessThan, 0), 27) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(TransformationSplitBlock( + MakeInstructionDescriptor(18, SpvOpSLessThan, 0), 14) + .IsApplicable(context.get(), fact_manager)); +} + +TEST(TransformationSplitBlockTest, SplitBlockSeveralTimes) { + // The SPIR-V in this test came from the following fragment shader: + // + // void main() { + // int a; + // int b; + // a = 1; + // b = a; + // a = b; + // b = 2; + // b++; + // } + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %8 "a" + OpName %10 "b" + OpDecorate %8 RelaxedPrecision + OpDecorate %10 RelaxedPrecision + OpDecorate %11 RelaxedPrecision + OpDecorate %12 RelaxedPrecision + OpDecorate %14 RelaxedPrecision + OpDecorate %15 RelaxedPrecision + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 1 + %13 = OpConstant %6 2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %10 = OpVariable %7 Function + OpStore %8 %9 + %11 = OpLoad %6 %8 + OpStore %10 %11 + %12 = OpLoad %6 %10 + OpStore %8 %12 + OpStore %10 %13 + %14 = OpLoad %6 %10 + %15 = OpIAdd %6 %14 %9 + OpStore %10 %15 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + + FactManager fact_manager; + + auto split_1 = TransformationSplitBlock( + MakeInstructionDescriptor(5, SpvOpStore, 0), 100); + ASSERT_TRUE(split_1.IsApplicable(context.get(), fact_manager)); + split_1.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + std::string after_split_1 = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %8 "a" + OpName %10 "b" + OpDecorate %8 RelaxedPrecision + OpDecorate %10 RelaxedPrecision + OpDecorate %11 RelaxedPrecision + OpDecorate %12 RelaxedPrecision + OpDecorate %14 RelaxedPrecision + OpDecorate %15 RelaxedPrecision + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 1 + %13 = OpConstant %6 2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %10 = OpVariable %7 Function + OpBranch %100 + %100 = OpLabel + OpStore %8 %9 + %11 = OpLoad %6 %8 + OpStore %10 %11 + %12 = OpLoad %6 %10 + OpStore %8 %12 + OpStore %10 %13 + %14 = OpLoad %6 %10 + %15 = OpIAdd %6 %14 %9 + OpStore %10 %15 + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_split_1, context.get())); + + auto split_2 = TransformationSplitBlock( + MakeInstructionDescriptor(11, SpvOpStore, 0), 101); + ASSERT_TRUE(split_2.IsApplicable(context.get(), fact_manager)); + split_2.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + std::string after_split_2 = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %8 "a" + OpName %10 "b" + OpDecorate %8 RelaxedPrecision + OpDecorate %10 RelaxedPrecision + OpDecorate %11 RelaxedPrecision + OpDecorate %12 RelaxedPrecision + OpDecorate %14 RelaxedPrecision + OpDecorate %15 RelaxedPrecision + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 1 + %13 = OpConstant %6 2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %10 = OpVariable %7 Function + OpBranch %100 + %100 = OpLabel + OpStore %8 %9 + %11 = OpLoad %6 %8 + OpBranch %101 + %101 = OpLabel + OpStore %10 %11 + %12 = OpLoad %6 %10 + OpStore %8 %12 + OpStore %10 %13 + %14 = OpLoad %6 %10 + %15 = OpIAdd %6 %14 %9 + OpStore %10 %15 + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_split_2, context.get())); + + auto split_3 = TransformationSplitBlock( + MakeInstructionDescriptor(14, SpvOpLoad, 0), 102); + ASSERT_TRUE(split_3.IsApplicable(context.get(), fact_manager)); + split_3.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + std::string after_split_3 = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %8 "a" + OpName %10 "b" + OpDecorate %8 RelaxedPrecision + OpDecorate %10 RelaxedPrecision + OpDecorate %11 RelaxedPrecision + OpDecorate %12 RelaxedPrecision + OpDecorate %14 RelaxedPrecision + OpDecorate %15 RelaxedPrecision + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 1 + %13 = OpConstant %6 2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %10 = OpVariable %7 Function + OpBranch %100 + %100 = OpLabel + OpStore %8 %9 + %11 = OpLoad %6 %8 + OpBranch %101 + %101 = OpLabel + OpStore %10 %11 + %12 = OpLoad %6 %10 + OpStore %8 %12 + OpStore %10 %13 + OpBranch %102 + %102 = OpLabel + %14 = OpLoad %6 %10 + %15 = OpIAdd %6 %14 %9 + OpStore %10 %15 + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_split_3, context.get())); +} + +TEST(TransformationSplitBlockTest, SplitBlockBeforeSelectBranch) { + // The SPIR-V in this test came from the following fragment shader: + // + // void main() { + // int x, y; + // x = 2; + // if (x < y) { + // y = 3; + // } else { + // y = 4; + // } + // } + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %8 "x" + OpName %11 "y" + OpDecorate %8 RelaxedPrecision + OpDecorate %10 RelaxedPrecision + OpDecorate %11 RelaxedPrecision + OpDecorate %12 RelaxedPrecision + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 2 + %13 = OpTypeBool + %17 = OpConstant %6 3 + %19 = OpConstant %6 4 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %11 = OpVariable %7 Function + OpStore %8 %9 + %10 = OpLoad %6 %8 + %12 = OpLoad %6 %11 + %14 = OpSLessThan %13 %10 %12 + OpSelectionMerge %16 None + OpBranchConditional %14 %15 %18 + %15 = OpLabel + OpStore %11 %17 + OpBranch %16 + %18 = OpLabel + OpStore %11 %19 + OpBranch %16 + %16 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + + FactManager fact_manager; + + // Illegal to split between the merge and the conditional branch. + ASSERT_FALSE( + TransformationSplitBlock( + MakeInstructionDescriptor(14, SpvOpBranchConditional, 0), 100) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE( + TransformationSplitBlock( + MakeInstructionDescriptor(12, SpvOpBranchConditional, 0), 100) + .IsApplicable(context.get(), fact_manager)); + + auto split = TransformationSplitBlock( + MakeInstructionDescriptor(14, SpvOpSelectionMerge, 0), 100); + ASSERT_TRUE(split.IsApplicable(context.get(), fact_manager)); + split.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + std::string after_split = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %8 "x" + OpName %11 "y" + OpDecorate %8 RelaxedPrecision + OpDecorate %10 RelaxedPrecision + OpDecorate %11 RelaxedPrecision + OpDecorate %12 RelaxedPrecision + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 2 + %13 = OpTypeBool + %17 = OpConstant %6 3 + %19 = OpConstant %6 4 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %11 = OpVariable %7 Function + OpStore %8 %9 + %10 = OpLoad %6 %8 + %12 = OpLoad %6 %11 + %14 = OpSLessThan %13 %10 %12 + OpBranch %100 + %100 = OpLabel + OpSelectionMerge %16 None + OpBranchConditional %14 %15 %18 + %15 = OpLabel + OpStore %11 %17 + OpBranch %16 + %18 = OpLabel + OpStore %11 %19 + OpBranch %16 + %16 = OpLabel + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_split, context.get())); +} + +TEST(TransformationSplitBlockTest, SplitBlockBeforeSwitchBranch) { + // The SPIR-V in this test came from the following fragment shader: + // + // void main() { + // int x, y; + // switch (y) { + // case 1: + // x = 2; + // case 2: + // break; + // case 3: + // x = 4; + // default: + // x = 6; + // } + // } + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %8 "y" + OpName %15 "x" + OpDecorate %8 RelaxedPrecision + OpDecorate %9 RelaxedPrecision + OpDecorate %15 RelaxedPrecision + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %16 = OpConstant %6 2 + %18 = OpConstant %6 4 + %19 = OpConstant %6 6 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %15 = OpVariable %7 Function + %9 = OpLoad %6 %8 + OpSelectionMerge %14 None + OpSwitch %9 %13 1 %10 2 %11 3 %12 + %13 = OpLabel + OpStore %15 %19 + OpBranch %14 + %10 = OpLabel + OpStore %15 %16 + OpBranch %11 + %11 = OpLabel + OpBranch %14 + %12 = OpLabel + OpStore %15 %18 + OpBranch %13 + %14 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + + FactManager fact_manager; + + // Illegal to split between the merge and the conditional branch. + ASSERT_FALSE(TransformationSplitBlock( + MakeInstructionDescriptor(9, SpvOpSwitch, 0), 100) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(TransformationSplitBlock( + MakeInstructionDescriptor(15, SpvOpSwitch, 0), 100) + .IsApplicable(context.get(), fact_manager)); + + auto split = TransformationSplitBlock( + MakeInstructionDescriptor(9, SpvOpSelectionMerge, 0), 100); + ASSERT_TRUE(split.IsApplicable(context.get(), fact_manager)); + split.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + std::string after_split = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %8 "y" + OpName %15 "x" + OpDecorate %8 RelaxedPrecision + OpDecorate %9 RelaxedPrecision + OpDecorate %15 RelaxedPrecision + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %16 = OpConstant %6 2 + %18 = OpConstant %6 4 + %19 = OpConstant %6 6 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %15 = OpVariable %7 Function + %9 = OpLoad %6 %8 + OpBranch %100 + %100 = OpLabel + OpSelectionMerge %14 None + OpSwitch %9 %13 1 %10 2 %11 3 %12 + %13 = OpLabel + OpStore %15 %19 + OpBranch %14 + %10 = OpLabel + OpStore %15 %16 + OpBranch %11 + %11 = OpLabel + OpBranch %14 + %12 = OpLabel + OpStore %15 %18 + OpBranch %13 + %14 = OpLabel + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_split, context.get())); +} + +TEST(TransformationSplitBlockTest, NoSplitDuringOpPhis) { + // The SPIR-V in this test came from the following fragment shader, with + // local store elimination applied to get some OpPhi instructions. + // + // void main() { + // int x; + // int i; + // for (i = 0; i < 100; i++) { + // x += i; + // } + // } + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %8 "i" + OpName %19 "x" + OpDecorate %8 RelaxedPrecision + OpDecorate %19 RelaxedPrecision + OpDecorate %22 RelaxedPrecision + OpDecorate %25 RelaxedPrecision + OpDecorate %26 RelaxedPrecision + OpDecorate %27 RelaxedPrecision + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 0 + %16 = OpConstant %6 100 + %17 = OpTypeBool + %24 = OpConstant %6 1 + %28 = OpUndef %6 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %19 = OpVariable %7 Function + OpStore %8 %9 + OpBranch %10 + %10 = OpLabel + %27 = OpPhi %6 %28 %5 %22 %13 + %26 = OpPhi %6 %9 %5 %25 %13 + OpBranch %50 + %50 = OpLabel + OpLoopMerge %12 %13 None + OpBranch %14 + %14 = OpLabel + %18 = OpSLessThan %17 %26 %16 + OpBranchConditional %18 %11 %12 + %11 = OpLabel + %22 = OpIAdd %6 %27 %26 + OpStore %19 %22 + OpBranch %13 + %13 = OpLabel + %25 = OpIAdd %6 %26 %24 + OpStore %8 %25 + OpBranch %50 + %12 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + + FactManager fact_manager; + + // We cannot split before OpPhi instructions, since the number of incoming + // blocks may not appropriately match after splitting. + ASSERT_FALSE( + TransformationSplitBlock(MakeInstructionDescriptor(26, SpvOpPhi, 0), 100) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE( + TransformationSplitBlock(MakeInstructionDescriptor(27, SpvOpPhi, 0), 100) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE( + TransformationSplitBlock(MakeInstructionDescriptor(27, SpvOpPhi, 1), 100) + .IsApplicable(context.get(), fact_manager)); +} + +TEST(TransformationSplitBlockTest, SplitOpPhiWithSinglePredecessor) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %8 "x" + OpName %10 "y" + OpDecorate %8 RelaxedPrecision + OpDecorate %10 RelaxedPrecision + OpDecorate %11 RelaxedPrecision + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 1 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %10 = OpVariable %7 Function + OpStore %8 %9 + %11 = OpLoad %6 %8 + OpBranch %20 + %20 = OpLabel + %21 = OpPhi %6 %11 %5 + OpStore %10 %21 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + + FactManager fact_manager; + + ASSERT_TRUE( + TransformationSplitBlock(MakeInstructionDescriptor(21, SpvOpPhi, 0), 100) + .IsApplicable(context.get(), fact_manager)); + // An equivalent transformation to the above, just described with respect to a + // different base instruction. + auto split = + TransformationSplitBlock(MakeInstructionDescriptor(20, SpvOpPhi, 0), 100); + ASSERT_TRUE(split.IsApplicable(context.get(), fact_manager)); + split.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + std::string after_split = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %8 "x" + OpName %10 "y" + OpDecorate %8 RelaxedPrecision + OpDecorate %10 RelaxedPrecision + OpDecorate %11 RelaxedPrecision + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 1 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %10 = OpVariable %7 Function + OpStore %8 %9 + %11 = OpLoad %6 %8 + OpBranch %20 + %20 = OpLabel + OpBranch %100 + %100 = OpLabel + %21 = OpPhi %6 %11 %20 + OpStore %10 %21 + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_split, context.get())); +} + +TEST(TransformationSplitBlockTest, DeadBlockShouldSplitToTwoDeadBlocks) { + // This checks that if a block B is marked as dead, it should split into a + // pair of dead blocks. + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeBool + %7 = OpConstantFalse %6 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpSelectionMerge %9 None + OpBranchConditional %7 %8 %9 + %8 = OpLabel + OpBranch %9 + %9 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + + FactManager fact_manager; + + // Record the fact that block 8 is dead. + fact_manager.AddFactBlockIsDead(8); + + auto split = TransformationSplitBlock( + MakeInstructionDescriptor(8, SpvOpBranch, 0), 100); + ASSERT_TRUE(split.IsApplicable(context.get(), fact_manager)); + split.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(fact_manager.BlockIsDead(8)); + ASSERT_TRUE(fact_manager.BlockIsDead(100)); + + std::string after_split = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeBool + %7 = OpConstantFalse %6 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpSelectionMerge %9 None + OpBranchConditional %7 %8 %9 + %8 = OpLabel + OpBranch %100 + %100 = OpLabel + OpBranch %9 + %9 = OpLabel + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_split, context.get())); +} + +} // namespace +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/test/fuzz/transformation_vector_shuffle_test.cpp b/third_party/spirv-tools/test/fuzz/transformation_vector_shuffle_test.cpp new file mode 100644 index 0000000000..385c38b444 --- /dev/null +++ b/third_party/spirv-tools/test/fuzz/transformation_vector_shuffle_test.cpp @@ -0,0 +1,532 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/transformation_vector_shuffle.h" +#include "source/fuzz/instruction_descriptor.h" +#include "test/fuzz/fuzz_test_util.h" + +namespace spvtools { +namespace fuzz { +namespace { + +TEST(TransformationVectorShuffle, BasicTest) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeBool + %7 = OpTypeVector %6 2 + %10 = OpConstantTrue %6 + %11 = OpConstantFalse %6 + %12 = OpConstantComposite %7 %10 %11 + %112 = OpUndef %7 + %13 = OpTypeVector %6 3 + %16 = OpConstantComposite %13 %10 %11 %10 + %17 = OpTypeVector %6 4 + %20 = OpConstantComposite %17 %10 %11 %10 %11 + %21 = OpTypeInt 32 1 + %22 = OpTypeVector %21 2 + %25 = OpConstant %21 1 + %26 = OpConstant %21 0 + %27 = OpConstantComposite %22 %25 %26 + %28 = OpTypeVector %21 3 + %31 = OpConstantComposite %28 %25 %26 %25 + %32 = OpTypeVector %21 4 + %33 = OpTypePointer Function %32 + %35 = OpConstantComposite %32 %25 %26 %25 %26 + %36 = OpTypeInt 32 0 + %37 = OpTypeVector %36 2 + %40 = OpConstant %36 1 + %41 = OpConstant %36 0 + %42 = OpConstantComposite %37 %40 %41 + %43 = OpTypeVector %36 3 + %46 = OpConstantComposite %43 %40 %41 %40 + %47 = OpTypeVector %36 4 + %50 = OpConstantComposite %47 %40 %41 %40 %41 + %51 = OpTypeFloat 32 + %55 = OpConstant %51 1 + %56 = OpConstant %51 0 + %58 = OpTypeVector %51 3 + %61 = OpConstantComposite %58 %55 %56 %55 + %62 = OpTypeVector %51 4 + %65 = OpConstantComposite %62 %55 %56 %55 %56 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpSelectionMerge %100 None + OpBranchConditional %10 %101 %102 + %101 = OpLabel + %103 = OpCompositeConstruct %62 %55 %55 %55 %56 + OpBranch %100 + %102 = OpLabel + OpBranch %100 + %100 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + fact_manager.AddFactDataSynonym(MakeDataDescriptor(10, {}), + MakeDataDescriptor(12, {0}), context.get()); + fact_manager.AddFactDataSynonym(MakeDataDescriptor(11, {}), + MakeDataDescriptor(12, {1}), context.get()); + + fact_manager.AddFactDataSynonym(MakeDataDescriptor(10, {}), + MakeDataDescriptor(16, {0}), context.get()); + fact_manager.AddFactDataSynonym(MakeDataDescriptor(11, {}), + MakeDataDescriptor(16, {1}), context.get()); + fact_manager.AddFactDataSynonym(MakeDataDescriptor(10, {}), + MakeDataDescriptor(16, {2}), context.get()); + + fact_manager.AddFactDataSynonym(MakeDataDescriptor(10, {}), + MakeDataDescriptor(20, {0}), context.get()); + fact_manager.AddFactDataSynonym(MakeDataDescriptor(11, {}), + MakeDataDescriptor(20, {1}), context.get()); + fact_manager.AddFactDataSynonym(MakeDataDescriptor(10, {}), + MakeDataDescriptor(20, {2}), context.get()); + fact_manager.AddFactDataSynonym(MakeDataDescriptor(11, {}), + MakeDataDescriptor(20, {3}), context.get()); + + fact_manager.AddFactDataSynonym(MakeDataDescriptor(25, {}), + MakeDataDescriptor(27, {0}), context.get()); + fact_manager.AddFactDataSynonym(MakeDataDescriptor(26, {}), + MakeDataDescriptor(27, {1}), context.get()); + + fact_manager.AddFactDataSynonym(MakeDataDescriptor(25, {}), + MakeDataDescriptor(31, {0}), context.get()); + fact_manager.AddFactDataSynonym(MakeDataDescriptor(26, {}), + MakeDataDescriptor(31, {1}), context.get()); + fact_manager.AddFactDataSynonym(MakeDataDescriptor(25, {}), + MakeDataDescriptor(31, {2}), context.get()); + + fact_manager.AddFactDataSynonym(MakeDataDescriptor(25, {}), + MakeDataDescriptor(35, {0}), context.get()); + fact_manager.AddFactDataSynonym(MakeDataDescriptor(26, {}), + MakeDataDescriptor(35, {1}), context.get()); + fact_manager.AddFactDataSynonym(MakeDataDescriptor(25, {}), + MakeDataDescriptor(35, {2}), context.get()); + fact_manager.AddFactDataSynonym(MakeDataDescriptor(26, {}), + MakeDataDescriptor(35, {3}), context.get()); + + fact_manager.AddFactDataSynonym(MakeDataDescriptor(40, {}), + MakeDataDescriptor(42, {0}), context.get()); + fact_manager.AddFactDataSynonym(MakeDataDescriptor(41, {}), + MakeDataDescriptor(42, {1}), context.get()); + + fact_manager.AddFactDataSynonym(MakeDataDescriptor(40, {}), + MakeDataDescriptor(46, {0}), context.get()); + fact_manager.AddFactDataSynonym(MakeDataDescriptor(41, {}), + MakeDataDescriptor(46, {1}), context.get()); + fact_manager.AddFactDataSynonym(MakeDataDescriptor(40, {}), + MakeDataDescriptor(46, {2}), context.get()); + + fact_manager.AddFactDataSynonym(MakeDataDescriptor(40, {}), + MakeDataDescriptor(50, {0}), context.get()); + fact_manager.AddFactDataSynonym(MakeDataDescriptor(41, {}), + MakeDataDescriptor(50, {1}), context.get()); + fact_manager.AddFactDataSynonym(MakeDataDescriptor(40, {}), + MakeDataDescriptor(50, {2}), context.get()); + fact_manager.AddFactDataSynonym(MakeDataDescriptor(41, {}), + MakeDataDescriptor(50, {3}), context.get()); + + fact_manager.AddFactDataSynonym(MakeDataDescriptor(55, {}), + MakeDataDescriptor(61, {0}), context.get()); + fact_manager.AddFactDataSynonym(MakeDataDescriptor(56, {}), + MakeDataDescriptor(61, {1}), context.get()); + fact_manager.AddFactDataSynonym(MakeDataDescriptor(55, {}), + MakeDataDescriptor(61, {2}), context.get()); + + fact_manager.AddFactDataSynonym(MakeDataDescriptor(55, {}), + MakeDataDescriptor(65, {0}), context.get()); + fact_manager.AddFactDataSynonym(MakeDataDescriptor(56, {}), + MakeDataDescriptor(65, {1}), context.get()); + fact_manager.AddFactDataSynonym(MakeDataDescriptor(55, {}), + MakeDataDescriptor(65, {2}), context.get()); + fact_manager.AddFactDataSynonym(MakeDataDescriptor(56, {}), + MakeDataDescriptor(65, {3}), context.get()); + + // %103 does not dominate the return instruction. + ASSERT_FALSE(TransformationVectorShuffle( + MakeInstructionDescriptor(100, SpvOpReturn, 0), 200, 103, 65, + {3, 5, 7}) + .IsApplicable(context.get(), fact_manager)); + + // Illegal to shuffle a bvec2 and a vec3 + ASSERT_FALSE(TransformationVectorShuffle( + MakeInstructionDescriptor(100, SpvOpReturn, 0), 200, 112, 61, + {0, 2, 4}) + .IsApplicable(context.get(), fact_manager)); + + // Illegal to shuffle an ivec2 and a uvec4 + ASSERT_FALSE(TransformationVectorShuffle( + MakeInstructionDescriptor(100, SpvOpReturn, 0), 200, 27, 50, + {1, 3, 5}) + .IsApplicable(context.get(), fact_manager)); + + // Vector 1 does not exist + ASSERT_FALSE(TransformationVectorShuffle( + MakeInstructionDescriptor(100, SpvOpReturn, 0), 200, 300, 50, + {1, 3, 5}) + .IsApplicable(context.get(), fact_manager)); + + // Vector 2 does not exist + ASSERT_FALSE(TransformationVectorShuffle( + MakeInstructionDescriptor(100, SpvOpReturn, 0), 200, 27, 300, + {1, 3, 5}) + .IsApplicable(context.get(), fact_manager)); + + // Index out of range + ASSERT_FALSE( + TransformationVectorShuffle( + MakeInstructionDescriptor(100, SpvOpReturn, 0), 200, 12, 112, {0, 20}) + .IsApplicable(context.get(), fact_manager)); + + // Too many indices + ASSERT_FALSE(TransformationVectorShuffle( + MakeInstructionDescriptor(100, SpvOpReturn, 0), 200, 12, 112, + {0, 1, 0, 1, 0, 1, 0, 1}) + .IsApplicable(context.get(), fact_manager)); + + // Too few indices + ASSERT_FALSE( + TransformationVectorShuffle( + MakeInstructionDescriptor(100, SpvOpReturn, 0), 200, 12, 112, {}) + .IsApplicable(context.get(), fact_manager)); + + // Too few indices again + ASSERT_FALSE( + TransformationVectorShuffle( + MakeInstructionDescriptor(100, SpvOpReturn, 0), 200, 12, 112, {0}) + .IsApplicable(context.get(), fact_manager)); + + // Indices define unknown type: we do not have vec2 + ASSERT_FALSE( + TransformationVectorShuffle( + MakeInstructionDescriptor(100, SpvOpReturn, 0), 200, 65, 65, {0, 1}) + .IsApplicable(context.get(), fact_manager)); + + // The instruction to insert before does not exist + ASSERT_FALSE(TransformationVectorShuffle( + MakeInstructionDescriptor(100, SpvOpCompositeConstruct, 1), + 201, 20, 12, {0xFFFFFFFF, 3, 5}) + .IsApplicable(context.get(), fact_manager)); + + // The 'fresh' id is already in use + ASSERT_FALSE( + TransformationVectorShuffle( + MakeInstructionDescriptor(100, SpvOpReturn, 0), 12, 12, 112, {}) + .IsApplicable(context.get(), fact_manager)); + + protobufs::DataDescriptor temp_dd; + + TransformationVectorShuffle transformation1( + MakeInstructionDescriptor(100, SpvOpReturn, 0), 200, 12, 112, {1, 0}); + ASSERT_TRUE(transformation1.IsApplicable(context.get(), fact_manager)); + transformation1.Apply(context.get(), &fact_manager); + temp_dd = MakeDataDescriptor(200, {0}); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(11, {}), temp_dd, + context.get())); + temp_dd = MakeDataDescriptor(200, {1}); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(10, {}), temp_dd, + context.get())); + + TransformationVectorShuffle transformation2( + MakeInstructionDescriptor(100, SpvOpReturn, 0), 201, 20, 12, + {0xFFFFFFFF, 3, 5}); + ASSERT_TRUE(transformation2.IsApplicable(context.get(), fact_manager)); + transformation2.Apply(context.get(), &fact_manager); + temp_dd = MakeDataDescriptor(201, {1}); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(11, {}), temp_dd, + context.get())); + temp_dd = MakeDataDescriptor(201, {2}); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(11, {}), temp_dd, + context.get())); + + TransformationVectorShuffle transformation3( + MakeInstructionDescriptor(100, SpvOpReturn, 0), 202, 27, 35, {5, 4, 1}); + ASSERT_TRUE(transformation3.IsApplicable(context.get(), fact_manager)); + transformation3.Apply(context.get(), &fact_manager); + temp_dd = MakeDataDescriptor(202, {0}); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(26, {}), temp_dd, + context.get())); + temp_dd = MakeDataDescriptor(202, {1}); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(25, {}), temp_dd, + context.get())); + temp_dd = MakeDataDescriptor(202, {2}); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(26, {}), temp_dd, + context.get())); + + TransformationVectorShuffle transformation4( + MakeInstructionDescriptor(100, SpvOpReturn, 0), 203, 42, 46, {0, 1}); + ASSERT_TRUE(transformation4.IsApplicable(context.get(), fact_manager)); + transformation4.Apply(context.get(), &fact_manager); + temp_dd = MakeDataDescriptor(203, {0}); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {}), temp_dd, + context.get())); + temp_dd = MakeDataDescriptor(203, {1}); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(41, {}), temp_dd, + context.get())); + + TransformationVectorShuffle transformation5( + MakeInstructionDescriptor(100, SpvOpReturn, 0), 204, 42, 46, {2, 3, 4}); + ASSERT_TRUE(transformation5.IsApplicable(context.get(), fact_manager)); + transformation5.Apply(context.get(), &fact_manager); + temp_dd = MakeDataDescriptor(204, {0}); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {}), temp_dd, + context.get())); + temp_dd = MakeDataDescriptor(204, {1}); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(41, {}), temp_dd, + context.get())); + temp_dd = MakeDataDescriptor(204, {2}); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {}), temp_dd, + context.get())); + + TransformationVectorShuffle transformation6( + MakeInstructionDescriptor(100, SpvOpReturn, 0), 205, 42, 42, + {0, 1, 2, 3}); + ASSERT_TRUE(transformation6.IsApplicable(context.get(), fact_manager)); + transformation6.Apply(context.get(), &fact_manager); + temp_dd = MakeDataDescriptor(205, {0}); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {}), temp_dd, + context.get())); + temp_dd = MakeDataDescriptor(205, {1}); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(41, {}), temp_dd, + context.get())); + temp_dd = MakeDataDescriptor(205, {2}); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(40, {}), temp_dd, + context.get())); + temp_dd = MakeDataDescriptor(205, {3}); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(41, {}), temp_dd, + context.get())); + + // swizzle vec4 from vec4 and vec4 using some undefs + TransformationVectorShuffle transformation7( + MakeInstructionDescriptor(100, SpvOpReturn, 0), 206, 65, 65, + {0xFFFFFFFF, 3, 6, 0xFFFFFFFF}); + ASSERT_TRUE(transformation7.IsApplicable(context.get(), fact_manager)); + transformation7.Apply(context.get(), &fact_manager); + temp_dd = MakeDataDescriptor(206, {1}); + ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(56, {}), temp_dd, + context.get())); + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeBool + %7 = OpTypeVector %6 2 + %10 = OpConstantTrue %6 + %11 = OpConstantFalse %6 + %12 = OpConstantComposite %7 %10 %11 + %112 = OpUndef %7 + %13 = OpTypeVector %6 3 + %16 = OpConstantComposite %13 %10 %11 %10 + %17 = OpTypeVector %6 4 + %20 = OpConstantComposite %17 %10 %11 %10 %11 + %21 = OpTypeInt 32 1 + %22 = OpTypeVector %21 2 + %25 = OpConstant %21 1 + %26 = OpConstant %21 0 + %27 = OpConstantComposite %22 %25 %26 + %28 = OpTypeVector %21 3 + %31 = OpConstantComposite %28 %25 %26 %25 + %32 = OpTypeVector %21 4 + %33 = OpTypePointer Function %32 + %35 = OpConstantComposite %32 %25 %26 %25 %26 + %36 = OpTypeInt 32 0 + %37 = OpTypeVector %36 2 + %40 = OpConstant %36 1 + %41 = OpConstant %36 0 + %42 = OpConstantComposite %37 %40 %41 + %43 = OpTypeVector %36 3 + %46 = OpConstantComposite %43 %40 %41 %40 + %47 = OpTypeVector %36 4 + %50 = OpConstantComposite %47 %40 %41 %40 %41 + %51 = OpTypeFloat 32 + %55 = OpConstant %51 1 + %56 = OpConstant %51 0 + %58 = OpTypeVector %51 3 + %61 = OpConstantComposite %58 %55 %56 %55 + %62 = OpTypeVector %51 4 + %65 = OpConstantComposite %62 %55 %56 %55 %56 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpSelectionMerge %100 None + OpBranchConditional %10 %101 %102 + %101 = OpLabel + %103 = OpCompositeConstruct %62 %55 %55 %55 %56 + OpBranch %100 + %102 = OpLabel + OpBranch %100 + %100 = OpLabel + %200 = OpVectorShuffle %7 %12 %112 1 0 + %201 = OpVectorShuffle %13 %20 %12 0xFFFFFFFF 3 5 + %202 = OpVectorShuffle %28 %27 %35 5 4 1 + %203 = OpVectorShuffle %37 %42 %46 0 1 + %204 = OpVectorShuffle %43 %42 %46 2 3 4 + %205 = OpVectorShuffle %47 %42 %42 0 1 2 3 + %206 = OpVectorShuffle %62 %65 %65 0xFFFFFFFF 3 6 0xFFFFFFFF + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +TEST(TransformationVectorShuffleTest, IllegalInsertionPoints) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" %51 %27 + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %25 "buf" + OpMemberName %25 0 "value" + OpName %27 "" + OpName %51 "color" + OpMemberDecorate %25 0 Offset 0 + OpDecorate %25 Block + OpDecorate %27 DescriptorSet 0 + OpDecorate %27 Binding 0 + OpDecorate %51 Location 0 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypeVector %6 4 + %150 = OpTypeVector %6 2 + %10 = OpConstant %6 0.300000012 + %11 = OpConstant %6 0.400000006 + %12 = OpConstant %6 0.5 + %13 = OpConstant %6 1 + %14 = OpConstantComposite %7 %10 %11 %12 %13 + %15 = OpTypeInt 32 1 + %18 = OpConstant %15 0 + %25 = OpTypeStruct %6 + %26 = OpTypePointer Uniform %25 + %27 = OpVariable %26 Uniform + %28 = OpTypePointer Uniform %6 + %32 = OpTypeBool + %103 = OpConstantTrue %32 + %34 = OpConstant %6 0.100000001 + %48 = OpConstant %15 1 + %50 = OpTypePointer Output %7 + %51 = OpVariable %50 Output + %100 = OpTypePointer Function %6 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %101 = OpVariable %100 Function + %102 = OpVariable %100 Function + OpBranch %19 + %19 = OpLabel + %60 = OpPhi %7 %14 %5 %58 %20 + %59 = OpPhi %15 %18 %5 %49 %20 + %29 = OpAccessChain %28 %27 %18 + %30 = OpLoad %6 %29 + %31 = OpConvertFToS %15 %30 + %33 = OpSLessThan %32 %59 %31 + OpLoopMerge %21 %20 None + OpBranchConditional %33 %20 %21 + %20 = OpLabel + %39 = OpCompositeExtract %6 %60 0 + %40 = OpFAdd %6 %39 %34 + %55 = OpCompositeInsert %7 %40 %60 0 + %44 = OpCompositeExtract %6 %60 1 + %45 = OpFSub %6 %44 %34 + %58 = OpCompositeInsert %7 %45 %55 1 + %49 = OpIAdd %15 %59 %48 + OpBranch %19 + %21 = OpLabel + OpStore %51 %60 + OpSelectionMerge %105 None + OpBranchConditional %103 %104 %105 + %104 = OpLabel + OpBranch %105 + %105 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + // Cannot insert before the OpVariables of a function. + ASSERT_FALSE( + TransformationVectorShuffle( + MakeInstructionDescriptor(101, SpvOpVariable, 0), 200, 14, 14, {0, 1}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE( + TransformationVectorShuffle( + MakeInstructionDescriptor(101, SpvOpVariable, 1), 200, 14, 14, {1, 2}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE( + TransformationVectorShuffle( + MakeInstructionDescriptor(102, SpvOpVariable, 0), 200, 14, 14, {1, 2}) + .IsApplicable(context.get(), fact_manager)); + // OK to insert right after the OpVariables. + ASSERT_FALSE( + TransformationVectorShuffle( + MakeInstructionDescriptor(102, SpvOpBranch, 1), 200, 14, 14, {1, 1}) + .IsApplicable(context.get(), fact_manager)); + + // Cannot insert before the OpPhis of a block. + ASSERT_FALSE( + TransformationVectorShuffle(MakeInstructionDescriptor(60, SpvOpPhi, 0), + 200, 14, 14, {2, 0}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE( + TransformationVectorShuffle(MakeInstructionDescriptor(59, SpvOpPhi, 0), + 200, 14, 14, {3, 0}) + .IsApplicable(context.get(), fact_manager)); + // OK to insert after the OpPhis. + ASSERT_TRUE(TransformationVectorShuffle( + MakeInstructionDescriptor(59, SpvOpAccessChain, 0), 200, 14, + 14, {3, 4}) + .IsApplicable(context.get(), fact_manager)); + + // Cannot insert before OpLoopMerge + ASSERT_FALSE(TransformationVectorShuffle( + MakeInstructionDescriptor(33, SpvOpBranchConditional, 0), + 200, 14, 14, {3}) + .IsApplicable(context.get(), fact_manager)); + + // Cannot insert before OpSelectionMerge + ASSERT_FALSE(TransformationVectorShuffle( + MakeInstructionDescriptor(21, SpvOpBranchConditional, 0), + 200, 14, 14, {2}) + .IsApplicable(context.get(), fact_manager)); +} + +} // namespace +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/test/fuzz/uniform_buffer_element_descriptor_test.cpp b/third_party/spirv-tools/test/fuzz/uniform_buffer_element_descriptor_test.cpp new file mode 100644 index 0000000000..6c6d52a047 --- /dev/null +++ b/third_party/spirv-tools/test/fuzz/uniform_buffer_element_descriptor_test.cpp @@ -0,0 +1,84 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/fuzz/uniform_buffer_element_descriptor.h" +#include "test/fuzz/fuzz_test_util.h" + +namespace spvtools { +namespace fuzz { +namespace { + +TEST(UniformBufferElementDescriptorTest, TestEquality) { + // Test that equality works as expected for various buffer element + // descriptors. + + protobufs::UniformBufferElementDescriptor descriptor1 = + MakeUniformBufferElementDescriptor(0, 0, {1, 2, 3}); + protobufs::UniformBufferElementDescriptor descriptor2 = + MakeUniformBufferElementDescriptor(0, 0, {1, 2, 3}); + protobufs::UniformBufferElementDescriptor descriptor3 = + MakeUniformBufferElementDescriptor(0, 1, {1, 2, 3}); + protobufs::UniformBufferElementDescriptor descriptor4 = + MakeUniformBufferElementDescriptor(1, 0, {1, 2, 3}); + protobufs::UniformBufferElementDescriptor descriptor5 = + MakeUniformBufferElementDescriptor(1, 1, {1, 2, 3}); + protobufs::UniformBufferElementDescriptor descriptor6 = + MakeUniformBufferElementDescriptor(0, 0, {1, 2, 4}); + protobufs::UniformBufferElementDescriptor descriptor7 = + MakeUniformBufferElementDescriptor(0, 0, {1, 2}); + + ASSERT_TRUE( + UniformBufferElementDescriptorEquals()(&descriptor1, &descriptor1)); + ASSERT_TRUE( + UniformBufferElementDescriptorEquals()(&descriptor1, &descriptor2)); + ASSERT_TRUE( + UniformBufferElementDescriptorEquals()(&descriptor3, &descriptor3)); + ASSERT_TRUE( + UniformBufferElementDescriptorEquals()(&descriptor4, &descriptor4)); + ASSERT_TRUE( + UniformBufferElementDescriptorEquals()(&descriptor5, &descriptor5)); + ASSERT_TRUE( + UniformBufferElementDescriptorEquals()(&descriptor6, &descriptor6)); + ASSERT_TRUE( + UniformBufferElementDescriptorEquals()(&descriptor7, &descriptor7)); + + ASSERT_FALSE( + UniformBufferElementDescriptorEquals()(&descriptor1, &descriptor3)); + ASSERT_FALSE( + UniformBufferElementDescriptorEquals()(&descriptor3, &descriptor1)); + + ASSERT_FALSE( + UniformBufferElementDescriptorEquals()(&descriptor1, &descriptor4)); + ASSERT_FALSE( + UniformBufferElementDescriptorEquals()(&descriptor4, &descriptor1)); + + ASSERT_FALSE( + UniformBufferElementDescriptorEquals()(&descriptor1, &descriptor5)); + ASSERT_FALSE( + UniformBufferElementDescriptorEquals()(&descriptor5, &descriptor1)); + + ASSERT_FALSE( + UniformBufferElementDescriptorEquals()(&descriptor1, &descriptor6)); + ASSERT_FALSE( + UniformBufferElementDescriptorEquals()(&descriptor6, &descriptor1)); + + ASSERT_FALSE( + UniformBufferElementDescriptorEquals()(&descriptor1, &descriptor7)); + ASSERT_FALSE( + UniformBufferElementDescriptorEquals()(&descriptor7, &descriptor1)); +} + +} // namespace +} // namespace fuzz +} // namespace spvtools diff --git a/third_party/spirv-tools/test/fuzzers/BUILD.gn b/third_party/spirv-tools/test/fuzzers/BUILD.gn index df8291a563..be1258a459 100644 --- a/third_party/spirv-tools/test/fuzzers/BUILD.gn +++ b/third_party/spirv-tools/test/fuzzers/BUILD.gn @@ -16,7 +16,7 @@ import("//testing/libfuzzer/fuzzer_test.gni") import("//testing/test.gni") config("fuzzer_config") { - configs = [ "../..:spvtools_config" ] + configs = [ "../..:spvtools_internal_config" ] } group("fuzzers") { @@ -33,10 +33,16 @@ if (!build_with_chromium || use_fuzzing_engine) { testonly = true deps = [ - ":spvtools_val_fuzzer", + ":spvtools_as_fuzzer", + ":spvtools_binary_parser_fuzzer", + ":spvtools_dis_fuzzer", ":spvtools_opt_legalization_fuzzer", ":spvtools_opt_performance_fuzzer", ":spvtools_opt_size_fuzzer", + ":spvtools_opt_webgputovulkan_fuzzer", + ":spvtools_opt_vulkantowebgpu_fuzzer", + ":spvtools_val_fuzzer", + ":spvtools_val_webgpu_fuzzer", ] } } @@ -62,6 +68,24 @@ template("spvtools_fuzzer") { } } +spvtools_fuzzer("spvtools_as_fuzzer_src") { + sources = [ + "spvtools_as_fuzzer.cpp", + ] +} + +spvtools_fuzzer("spvtools_binary_parser_fuzzer_src") { + sources = [ + "spvtools_binary_parser_fuzzer.cpp", + ] +} + +spvtools_fuzzer("spvtools_dis_fuzzer_src") { + sources = [ + "spvtools_dis_fuzzer.cpp", + ] +} + spvtools_fuzzer("spvtools_opt_performance_fuzzer_src") { sources = [ "spvtools_opt_performance_fuzzer.cpp", @@ -80,13 +104,59 @@ spvtools_fuzzer("spvtools_opt_size_fuzzer_src") { ] } + +spvtools_fuzzer("spvtools_opt_webgputovulkan_fuzzer_src") { + sources = [ + "spvtools_opt_webgputovulkan_fuzzer.cpp", + ] +} + +spvtools_fuzzer("spvtools_opt_vulkantowebgpu_fuzzer_src") { + sources = [ + "spvtools_opt_vulkantowebgpu_fuzzer.cpp", + ] +} + spvtools_fuzzer("spvtools_val_fuzzer_src") { sources = [ "spvtools_val_fuzzer.cpp", ] } +spvtools_fuzzer("spvtools_val_webgpu_fuzzer_src") { + sources = [ + "spvtools_val_webgpu_fuzzer.cpp", + ] +} + if (!build_with_chromium || use_fuzzing_engine) { + fuzzer_test("spvtools_as_fuzzer") { + sources = [] + deps = [ + ":spvtools_as_fuzzer_src", + ] + # Intentionally doesn't use the seed corpus, because it consumes + # part of the input as not part of the file. + } + + fuzzer_test("spvtools_binary_parser_fuzzer") { + sources = [] + deps = [ + ":spvtools_binary_parser_fuzzer_src", + ] + # Intentionally doesn't use the seed corpus, because it consumes + # part of the input as not part of the file. + } + + fuzzer_test("spvtools_dis_fuzzer") { + sources = [] + deps = [ + ":spvtools_dis_fuzzer_src", + ] + # Intentionally doesn't use the seed corpus, because it consumes + # part of the input as not part of the file. + } + fuzzer_test("spvtools_opt_performance_fuzzer") { sources = [] deps = [ @@ -111,6 +181,22 @@ if (!build_with_chromium || use_fuzzing_engine) { seed_corpus = "corpora/spv" } + fuzzer_test("spvtools_opt_webgputovulkan_fuzzer") { + sources = [] + deps = [ + ":spvtools_opt_webgputovulkan_fuzzer_src", + ] + seed_corpus = "corpora/spv" + } + + fuzzer_test("spvtools_opt_vulkantowebgpu_fuzzer") { + sources = [] + deps = [ + ":spvtools_opt_vulkantowebgpu_fuzzer_src", + ] + seed_corpus = "corpora/spv" + } + fuzzer_test("spvtools_val_fuzzer") { sources = [] deps = [ @@ -118,4 +204,12 @@ if (!build_with_chromium || use_fuzzing_engine) { ] seed_corpus = "corpora/spv" } + + fuzzer_test("spvtools_val_webgpu_fuzzer") { + sources = [] + deps = [ + ":spvtools_val_webgpu_fuzzer_src", + ] + seed_corpus = "corpora/spv" + } } diff --git a/third_party/spirv-tools/test/fuzzers/spvtools_as_fuzzer.cpp b/third_party/spirv-tools/test/fuzzers/spvtools_as_fuzzer.cpp new file mode 100644 index 0000000000..8cecb05f5d --- /dev/null +++ b/third_party/spirv-tools/test/fuzzers/spvtools_as_fuzzer.cpp @@ -0,0 +1,72 @@ +// Copyright (c) 2019 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include // memcpy +#include + +#include "source/spirv_target_env.h" +#include "spirv-tools/libspirv.hpp" + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + if (size < sizeof(spv_target_env) + 1) return 0; + + const spv_context context = + spvContextCreate(*reinterpret_cast(data)); + if (context == nullptr) return 0; + + data += sizeof(spv_target_env); + size -= sizeof(spv_target_env); + + std::vector input; + + std::vector input_str; + size_t char_count = input.size() * sizeof(uint32_t) / sizeof(char); + input_str.resize(char_count); + memcpy(input_str.data(), input.data(), input.size() * sizeof(uint32_t)); + + spv_binary binary = nullptr; + spv_diagnostic diagnostic = nullptr; + spvTextToBinaryWithOptions(context, input_str.data(), input_str.size(), + SPV_TEXT_TO_BINARY_OPTION_NONE, &binary, + &diagnostic); + if (diagnostic) { + spvDiagnosticPrint(diagnostic); + spvDiagnosticDestroy(diagnostic); + diagnostic = nullptr; + } + + if (binary) { + spvBinaryDestroy(binary); + binary = nullptr; + } + + spvTextToBinaryWithOptions(context, input_str.data(), input_str.size(), + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS, + &binary, &diagnostic); + if (diagnostic) { + spvDiagnosticPrint(diagnostic); + spvDiagnosticDestroy(diagnostic); + diagnostic = nullptr; + } + + if (binary) { + spvBinaryDestroy(binary); + binary = nullptr; + } + + spvContextDestroy(context); + + return 0; +} diff --git a/third_party/spirv-tools/test/fuzzers/spvtools_binary_parser_fuzzer.cpp b/third_party/spirv-tools/test/fuzzers/spvtools_binary_parser_fuzzer.cpp new file mode 100644 index 0000000000..76ba4d9e95 --- /dev/null +++ b/third_party/spirv-tools/test/fuzzers/spvtools_binary_parser_fuzzer.cpp @@ -0,0 +1,44 @@ +// Copyright (c) 2018 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include + +#include "spirv-tools/libspirv.hpp" + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + if (size < sizeof(spv_target_env) + 1) return 0; + + const spv_context context = + spvContextCreate(*reinterpret_cast(data)); + if (context == nullptr) return 0; + + data += sizeof(spv_target_env); + size -= sizeof(spv_target_env); + + std::vector input; + input.resize(size >> 2); + + size_t count = 0; + for (size_t i = 0; (i + 3) < size; i += 4) { + input[count++] = data[i] | (data[i + 1] << 8) | (data[i + 2] << 16) | + (data[i + 3]) << 24; + } + + spvBinaryParse(context, nullptr, input.data(), input.size(), nullptr, nullptr, + nullptr); + + spvContextDestroy(context); + return 0; +} diff --git a/third_party/spirv-tools/test/fuzzers/spvtools_dis_fuzzer.cpp b/third_party/spirv-tools/test/fuzzers/spvtools_dis_fuzzer.cpp new file mode 100644 index 0000000000..ca9a52d869 --- /dev/null +++ b/third_party/spirv-tools/test/fuzzers/spvtools_dis_fuzzer.cpp @@ -0,0 +1,71 @@ +// Copyright (c) 2019 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include // memcpy +#include + +#include "source/spirv_target_env.h" +#include "spirv-tools/libspirv.hpp" + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + if (size < sizeof(spv_target_env) + 1) return 0; + + const spv_context context = + spvContextCreate(*reinterpret_cast(data)); + if (context == nullptr) return 0; + + data += sizeof(spv_target_env); + size -= sizeof(spv_target_env); + + std::vector input; + input.resize(size >> 2); + size_t count = 0; + for (size_t i = 0; (i + 3) < size; i += 4) { + input[count++] = data[i] | (data[i + 1] << 8) | (data[i + 2] << 16) | + (data[i + 3]) << 24; + } + + std::vector input_str; + size_t char_count = input.size() * sizeof(uint32_t) / sizeof(char); + input_str.resize(char_count); + memcpy(input_str.data(), input.data(), input.size() * sizeof(uint32_t)); + + spv_text text = nullptr; + spv_diagnostic diagnostic = nullptr; + + for (uint32_t options = SPV_BINARY_TO_TEXT_OPTION_NONE; + options < + (SPV_BINARY_TO_TEXT_OPTION_PRINT | SPV_BINARY_TO_TEXT_OPTION_COLOR | + SPV_BINARY_TO_TEXT_OPTION_INDENT | + SPV_BINARY_TO_TEXT_OPTION_SHOW_BYTE_OFFSET | + SPV_BINARY_TO_TEXT_OPTION_NO_HEADER | + SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES); + options++) { + spvBinaryToText(context, input.data(), input.size(), options, &text, + &diagnostic); + if (diagnostic) { + spvDiagnosticDestroy(diagnostic); + diagnostic = nullptr; + } + + if (text) { + spvTextDestroy(text); + text = nullptr; + } + } + + spvContextDestroy(context); + return 0; +} diff --git a/third_party/spirv-tools/test/fuzzers/spvtools_opt_vulkantowebgpu_fuzzer.cpp b/third_party/spirv-tools/test/fuzzers/spvtools_opt_vulkantowebgpu_fuzzer.cpp new file mode 100644 index 0000000000..9371c0df08 --- /dev/null +++ b/third_party/spirv-tools/test/fuzzers/spvtools_opt_vulkantowebgpu_fuzzer.cpp @@ -0,0 +1,38 @@ +// Copyright (c) 2019 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include + +#include "spirv-tools/optimizer.hpp" + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + spvtools::Optimizer optimizer(SPV_ENV_VULKAN_1_1); + optimizer.SetMessageConsumer([](spv_message_level_t, const char*, + const spv_position_t&, const char*) {}); + + std::vector input; + input.resize(size >> 2); + + size_t count = 0; + for (size_t i = 0; (i + 3) < size; i += 4) { + input[count++] = data[i] | (data[i + 1] << 8) | (data[i + 2] << 16) | + (data[i + 3]) << 24; + } + + optimizer.RegisterVulkanToWebGPUPasses(); + optimizer.Run(input.data(), input.size(), &input); + + return 0; +} diff --git a/third_party/spirv-tools/test/fuzzers/spvtools_opt_webgputovulkan_fuzzer.cpp b/third_party/spirv-tools/test/fuzzers/spvtools_opt_webgputovulkan_fuzzer.cpp new file mode 100644 index 0000000000..78ddbb75c0 --- /dev/null +++ b/third_party/spirv-tools/test/fuzzers/spvtools_opt_webgputovulkan_fuzzer.cpp @@ -0,0 +1,38 @@ +// Copyright (c) 2019 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include + +#include "spirv-tools/optimizer.hpp" + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + spvtools::Optimizer optimizer(SPV_ENV_WEBGPU_0); + optimizer.SetMessageConsumer([](spv_message_level_t, const char*, + const spv_position_t&, const char*) {}); + + std::vector input; + input.resize(size >> 2); + + size_t count = 0; + for (size_t i = 0; (i + 3) < size; i += 4) { + input[count++] = data[i] | (data[i + 1] << 8) | (data[i + 2] << 16) | + (data[i + 3]) << 24; + } + + optimizer.RegisterWebGPUToVulkanPasses(); + optimizer.Run(input.data(), input.size(), &input); + + return 0; +} diff --git a/third_party/spirv-tools/test/fuzzers/spvtools_val_webgpu_fuzzer.cpp b/third_party/spirv-tools/test/fuzzers/spvtools_val_webgpu_fuzzer.cpp new file mode 100644 index 0000000000..bed6e1a21f --- /dev/null +++ b/third_party/spirv-tools/test/fuzzers/spvtools_val_webgpu_fuzzer.cpp @@ -0,0 +1,36 @@ +// Copyright (c) 2019 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include + +#include "spirv-tools/libspirv.hpp" + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + spvtools::SpirvTools tools(SPV_ENV_WEBGPU_0); + tools.SetMessageConsumer([](spv_message_level_t, const char*, + const spv_position_t&, const char*) {}); + + std::vector input; + input.resize(size >> 2); + + size_t count = 0; + for (size_t i = 0; (i + 3) < size; i += 4) { + input[count++] = data[i] | (data[i + 1] << 8) | (data[i + 2] << 16) | + (data[i + 3]) << 24; + } + + tools.Validate(input); + return 0; +} diff --git a/third_party/spirv-tools/test/generator_magic_number_test.cpp b/third_party/spirv-tools/test/generator_magic_number_test.cpp index bc5fdf57a5..7131ac4569 100644 --- a/third_party/spirv-tools/test/generator_magic_number_test.cpp +++ b/third_party/spirv-tools/test/generator_magic_number_test.cpp @@ -34,7 +34,7 @@ TEST_P(GeneratorMagicNumberTest, Single) { GetParam().name()); } -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( Registered, GeneratorMagicNumberTest, ::testing::ValuesIn(std::vector>{ {SPV_GENERATOR_KHRONOS, "Khronos"}, @@ -47,16 +47,16 @@ INSTANTIATE_TEST_CASE_P( "Khronos LLVM/SPIR-V Translator"}, {SPV_GENERATOR_KHRONOS_ASSEMBLER, "Khronos SPIR-V Tools Assembler"}, {SPV_GENERATOR_KHRONOS_GLSLANG, "Khronos Glslang Reference Front End"}, - }), ); + })); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( Unregistered, GeneratorMagicNumberTest, ::testing::ValuesIn(std::vector>{ // We read registered entries from the SPIR-V XML Registry file // which can change over time. {spv_generator_t(1000), "Unknown"}, {spv_generator_t(9999), "Unknown"}, - }), ); + })); } // namespace } // namespace spvtools diff --git a/third_party/spirv-tools/test/hex_float_test.cpp b/third_party/spirv-tools/test/hex_float_test.cpp index 6b805f34ca..c422f75638 100644 --- a/third_party/spirv-tools/test/hex_float_test.cpp +++ b/third_party/spirv-tools/test/hex_float_test.cpp @@ -81,7 +81,7 @@ TEST_P(HexDoubleTest, DecodeCorrectly) { EXPECT_THAT(Decode(GetParam().second), Eq(GetParam().first)); } -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( Float32Tests, HexFloatTest, ::testing::ValuesIn(std::vector, std::string>>({ {0.f, "0x0p+0"}, @@ -131,9 +131,9 @@ INSTANTIATE_TEST_CASE_P( {float(ldexp(1.0, -127) / 2.0 + (ldexp(1.0, -127) / 4.0f)), "0x1.8p-128"}, - })), ); + }))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( Float32NanTests, HexFloatTest, ::testing::ValuesIn(std::vector, std::string>>({ // Various NAN and INF cases @@ -149,9 +149,9 @@ INSTANTIATE_TEST_CASE_P( {uint32_t(0x7f800c00), "0x1.0018p+128"}, // +nan {uint32_t(0x7F80F000), "0x1.01ep+128"}, // +nan {uint32_t(0x7FFFFFFF), "0x1.fffffep+128"}, // +nan - })), ); + }))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( Float64Tests, HexDoubleTest, ::testing::ValuesIn( std::vector, std::string>>({ @@ -222,9 +222,9 @@ INSTANTIATE_TEST_CASE_P( {ldexp(1.0, -1023) / 2.0 + (ldexp(1.0, -1023) / 4.0), "0x1.8p-1024"}, - })), ); + }))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( Float64NanTests, HexDoubleTest, ::testing::ValuesIn(std::vector< std::pair, std::string>>({ @@ -241,7 +241,7 @@ INSTANTIATE_TEST_CASE_P( {uint64_t(0x7FF0000000000001LL), "0x1.0000000000001p+1024"}, // -nan {uint64_t(0x7FF0000300000000LL), "0x1.00003p+1024"}, // -nan {uint64_t(0x7FFFFFFFFFFFFFFFLL), "0x1.fffffffffffffp+1024"}, // -nan - })), ); + }))); // Tests that encoding a value and decoding it again restores // the same value. @@ -263,14 +263,14 @@ TEST_P(RoundTripDoubleTest, CanStoreAccurately) { EXPECT_THAT(GetParam(), Eq(res.getAsFloat())); } -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( Float32StoreTests, RoundTripFloatTest, ::testing::ValuesIn(std::vector( {// Value requiring more than 6 digits of precision to be // represented accurately. 3.0000002f}))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( Float64StoreTests, RoundTripDoubleTest, ::testing::ValuesIn(std::vector( {// Value requiring more than 15 digits of precision to be @@ -300,7 +300,7 @@ TEST_P(DecodeHexDoubleTest, DecodeCorrectly) { EXPECT_THAT(Decode(GetParam().first), Eq(GetParam().second)); } -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( Float32DecodeTests, DecodeHexFloatTest, ::testing::ValuesIn(std::vector>>({ {"0x0p+000", 0.f}, @@ -320,9 +320,9 @@ INSTANTIATE_TEST_CASE_P( {"0xFFp+0", 255.f}, {"0x0.8p+0", 0.5f}, {"0x0.4p+0", 0.25f}, - })), ); + }))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( Float32DecodeInfTests, DecodeHexFloatTest, ::testing::ValuesIn(std::vector>>({ // inf cases @@ -330,9 +330,9 @@ INSTANTIATE_TEST_CASE_P( {"0x32p+127", uint32_t(0x7F800000)}, // inf {"0x32p+500", uint32_t(0x7F800000)}, // inf {"-0x32p+127", uint32_t(0xFF800000)}, // -inf - })), ); + }))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( Float64DecodeTests, DecodeHexDoubleTest, ::testing::ValuesIn( std::vector>>({ @@ -353,9 +353,9 @@ INSTANTIATE_TEST_CASE_P( {"0xFFp+0", 255.}, {"0x0.8p+0", 0.5}, {"0x0.4p+0", 0.25}, - })), ); + }))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( Float64DecodeInfTests, DecodeHexDoubleTest, ::testing::ValuesIn( std::vector>>({ @@ -364,7 +364,7 @@ INSTANTIATE_TEST_CASE_P( {"0x32p+1023", uint64_t(0x7FF0000000000000)}, // inf {"0x32p+5000", uint64_t(0x7FF0000000000000)}, // inf {"-0x32p+1023", uint64_t(0xFFF0000000000000)}, // -inf - })), ); + }))); TEST(FloatProxy, ValidConversion) { EXPECT_THAT(FloatProxy(1.f).getAsFloat(), Eq(1.0f)); @@ -503,7 +503,7 @@ TEST_P(FloatProxyDoubleTest, EncodeCorrectly) { Eq(GetParam().second)); } -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( Float32Tests, FloatProxyFloatTest, ::testing::ValuesIn(std::vector, std::string>>({ // Zero @@ -533,9 +533,9 @@ INSTANTIATE_TEST_CASE_P( {std::numeric_limits::infinity(), "0x1p+128"}, {-std::numeric_limits::infinity(), "-0x1p+128"}, - })), ); + }))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( Float64Tests, FloatProxyDoubleTest, ::testing::ValuesIn( std::vector, std::string>>({ @@ -570,7 +570,7 @@ INSTANTIATE_TEST_CASE_P( {std::numeric_limits::infinity(), "0x1p+1024"}, {-std::numeric_limits::infinity(), "-0x1p+1024"}, - })), ); + }))); // double is used so that unbiased_exponent can be used with the output // of ldexp directly. @@ -673,11 +673,16 @@ TEST(HexFloatOperationTest, NormalizedSignificand) { // For denormalized numbers we expect the normalized significand to // shift as if it were normalized. This means, in practice that the // top_most set bit will be cut off. Looks very similar to above (on purpose) - EXPECT_EQ(bits_set({}), normalized_significand({0}, -127)); - EXPECT_EQ(bits_set({3}), normalized_significand({0, 4}, -128)); - EXPECT_EQ(bits_set({3}), normalized_significand({0, 4}, -127)); - EXPECT_EQ(bits_set({}), normalized_significand({22}, -127)); - EXPECT_EQ(bits_set({0}), normalized_significand({21, 22}, -127)); + EXPECT_EQ(bits_set({}), + normalized_significand({0}, static_cast(-127))); + EXPECT_EQ(bits_set({3}), + normalized_significand({0, 4}, static_cast(-128))); + EXPECT_EQ(bits_set({3}), + normalized_significand({0, 4}, static_cast(-127))); + EXPECT_EQ(bits_set({}), + normalized_significand({22}, static_cast(-127))); + EXPECT_EQ(bits_set({0}), + normalized_significand({21, 22}, static_cast(-127))); } // Returns the 32-bit floating point value created by @@ -787,7 +792,7 @@ TEST_P(HexFloatRoundTest, RoundDownToFP16) { } // clang-format off -INSTANTIATE_TEST_CASE_P(F32ToF16, HexFloatRoundTest, +INSTANTIATE_TEST_SUITE_P(F32ToF16, HexFloatRoundTest, ::testing::ValuesIn(std::vector( { {float_fractions({0}), std::make_pair(half_bits_set({}), false), RD::kToZero}, @@ -833,7 +838,7 @@ INSTANTIATE_TEST_CASE_P(F32ToF16, HexFloatRoundTest, {static_cast(ldexp(float_fractions({0, 1, 11, 13}), -129)), std::make_pair(half_bits_set({0, 9}), false), RD::kToPositiveInfinity}, {static_cast(ldexp(float_fractions({0, 1, 11, 13}), -131)), std::make_pair(half_bits_set({0}), false), RD::kToNegativeInfinity}, {static_cast(ldexp(float_fractions({0, 1, 11, 13}), -130)), std::make_pair(half_bits_set({0, 9}), false), RD::kToNearestEven}, - })),); + }))); // clang-format on struct UpCastSignificandCase { @@ -867,7 +872,7 @@ TEST_P(HexFloatRoundUpSignificandTest, Widening) { } } -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( F16toF32, HexFloatRoundUpSignificandTest, // 0xFC00 of the source 16-bit hex value cover the sign and the exponent. // They are ignored for this test. @@ -876,7 +881,7 @@ INSTANTIATE_TEST_CASE_P( {0x0F00, 0x600000}, {0x0F01, 0x602000}, {0x0FFF, 0x7FE000}, - })), ); + }))); struct DownCastTest { float source_float; @@ -918,7 +923,7 @@ TEST_P(HexFloatFP32To16Tests, NarrowingCasts) { const uint16_t positive_infinity = 0x7C00; const uint16_t negative_infinity = 0xFC00; -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( F32ToF16, HexFloatFP32To16Tests, ::testing::ValuesIn(std::vector({ // Exactly representable as half. @@ -1009,7 +1014,7 @@ INSTANTIATE_TEST_CASE_P( RD::kToNearestEven}}, // Nans are below because we cannot test for equality. - })), ); + }))); struct UpCastCase { uint16_t source_half; @@ -1038,7 +1043,7 @@ TEST_P(HexFloatFP16To32Tests, WideningCasts) { } } -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( F16ToF32, HexFloatFP16To32Tests, ::testing::ValuesIn(std::vector({ {0x0000, 0.f}, @@ -1059,7 +1064,7 @@ INSTANTIATE_TEST_CASE_P( // inf {0x7C00, std::numeric_limits::infinity()}, {0xFC00, -std::numeric_limits::infinity()}, - })), ); + }))); TEST(HexFloatOperationTests, NanTests) { using HF = HexFloat>; @@ -1132,7 +1137,7 @@ FloatParseCase GoodFloatParseCase(std::string literal, bool negate_value, return FloatParseCase{literal, negate_value, true, proxy_expected_value}; } -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( FloatParse, ParseNormalFloatTest, ::testing::ValuesIn(std::vector>{ // Failing cases due to trivially incorrect syntax. @@ -1164,7 +1169,7 @@ INSTANTIATE_TEST_CASE_P( // We can't have -1e40 and negate_value == true since // that represents an original case of "--1e40" which // is invalid. - }), ); + })); using ParseNormalFloat16Test = ::testing::TestWithParam>; @@ -1183,7 +1188,7 @@ TEST_P(ParseNormalFloat16Test, Samples) { } } -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( Float16Parse, ParseNormalFloat16Test, ::testing::ValuesIn(std::vector>{ // Failing cases due to trivially incorrect syntax. @@ -1207,7 +1212,7 @@ INSTANTIATE_TEST_CASE_P( BadFloatParseCase("-2.0", true, uint16_t{0}), BadFloatParseCase("+0.0", true, uint16_t{0}), BadFloatParseCase("+2.0", true, uint16_t{0}), - }), ); + })); // A test case for detecting infinities. template @@ -1230,7 +1235,7 @@ TEST_P(FloatProxyParseOverflowFloatTest, Sample) { } } -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( FloatOverflow, FloatProxyParseOverflowFloatTest, ::testing::ValuesIn(std::vector>({ {"0", true, 0.0f}, @@ -1242,7 +1247,7 @@ INSTANTIATE_TEST_CASE_P( {"-1e40", false, -FLT_MAX}, {"1e400", false, FLT_MAX}, {"-1e400", false, -FLT_MAX}, - })), ); + }))); using FloatProxyParseOverflowDoubleTest = ::testing::TestWithParam>; @@ -1257,7 +1262,7 @@ TEST_P(FloatProxyParseOverflowDoubleTest, Sample) { } } -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( DoubleOverflow, FloatProxyParseOverflowDoubleTest, ::testing::ValuesIn(std::vector>({ {"0", true, 0.0}, @@ -1269,7 +1274,7 @@ INSTANTIATE_TEST_CASE_P( {"-1e40", true, -1e40}, {"1e400", false, DBL_MAX}, {"-1e400", false, -DBL_MAX}, - })), ); + }))); using FloatProxyParseOverflowFloat16Test = ::testing::TestWithParam>; @@ -1286,7 +1291,7 @@ TEST_P(FloatProxyParseOverflowFloat16Test, Sample) { } } -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( Float16Overflow, FloatProxyParseOverflowFloat16Test, ::testing::ValuesIn(std::vector>({ {"0", true, uint16_t{0}}, @@ -1300,7 +1305,7 @@ INSTANTIATE_TEST_CASE_P( {"-1e38", false, uint16_t{0xfbff}}, {"-1e40", false, uint16_t{0xfbff}}, {"-1e400", false, uint16_t{0xfbff}}, - })), ); + }))); TEST(FloatProxy, Max) { EXPECT_THAT(FloatProxy::max().getAsFloat().get_value(), diff --git a/third_party/spirv-tools/test/huffman_codec.cpp b/third_party/spirv-tools/test/huffman_codec.cpp deleted file mode 100644 index 58a7810613..0000000000 --- a/third_party/spirv-tools/test/huffman_codec.cpp +++ /dev/null @@ -1,317 +0,0 @@ -// Copyright (c) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include -#include -#include -#include -#include -#include - -#include "gmock/gmock.h" -#include "source/comp/bit_stream.h" -#include "source/comp/huffman_codec.h" - -namespace spvtools { -namespace comp { -namespace { - -const std::map& GetTestSet() { - static const std::map hist = { - {"a", 4}, {"e", 7}, {"f", 3}, {"h", 2}, {"i", 3}, - {"m", 2}, {"n", 2}, {"s", 2}, {"t", 2}, {"l", 1}, - {"o", 2}, {"p", 1}, {"r", 1}, {"u", 1}, {"x", 1}, - }; - - return hist; -} - -class TestBitReader { - public: - TestBitReader(const std::string& bits) : bits_(bits) {} - - bool ReadBit(bool* bit) { - if (pos_ < bits_.length()) { - *bit = bits_[pos_++] == '0' ? false : true; - return true; - } - return false; - } - - private: - std::string bits_; - size_t pos_ = 0; -}; - -TEST(Huffman, PrintTree) { - HuffmanCodec huffman(GetTestSet()); - std::stringstream ss; - huffman.PrintTree(ss); - - // clang-format off - const std::string expected = std::string(R"( -15-----7------e - 8------4------a - 4------2------m - 2------n -19-----8------4------2------o - 2------s - 4------2------t - 2------1------l - 1------p - 11-----5------2------1------r - 1------u - 3------f - 6------3------i - 3------1------x - 2------h -)").substr(1); - // clang-format on - - EXPECT_EQ(expected, ss.str()); -} - -TEST(Huffman, PrintTable) { - HuffmanCodec huffman(GetTestSet()); - std::stringstream ss; - huffman.PrintTable(ss); - - const std::string expected = std::string(R"( -e 7 11 -a 4 101 -i 3 0001 -f 3 0010 -t 2 0101 -s 2 0110 -o 2 0111 -n 2 1000 -m 2 1001 -h 2 00000 -x 1 00001 -u 1 00110 -r 1 00111 -p 1 01000 -l 1 01001 -)") - .substr(1); - - EXPECT_EQ(expected, ss.str()); -} - -TEST(Huffman, TestValidity) { - HuffmanCodec huffman(GetTestSet()); - const auto& encoding_table = huffman.GetEncodingTable(); - std::vector codes; - for (const auto& entry : encoding_table) { - codes.push_back(BitsToStream(entry.second.first, entry.second.second)); - } - - std::sort(codes.begin(), codes.end()); - - ASSERT_LT(codes.size(), 20u) << "Inefficient test ahead"; - - for (size_t i = 0; i < codes.size(); ++i) { - for (size_t j = i + 1; j < codes.size(); ++j) { - ASSERT_FALSE(codes[i] == codes[j].substr(0, codes[i].length())) - << codes[i] << " is prefix of " << codes[j]; - } - } -} - -TEST(Huffman, TestEncode) { - HuffmanCodec huffman(GetTestSet()); - - uint64_t bits = 0; - size_t num_bits = 0; - - EXPECT_TRUE(huffman.Encode("e", &bits, &num_bits)); - EXPECT_EQ(2u, num_bits); - EXPECT_EQ("11", BitsToStream(bits, num_bits)); - - EXPECT_TRUE(huffman.Encode("a", &bits, &num_bits)); - EXPECT_EQ(3u, num_bits); - EXPECT_EQ("101", BitsToStream(bits, num_bits)); - - EXPECT_TRUE(huffman.Encode("x", &bits, &num_bits)); - EXPECT_EQ(5u, num_bits); - EXPECT_EQ("00001", BitsToStream(bits, num_bits)); - - EXPECT_FALSE(huffman.Encode("y", &bits, &num_bits)); -} - -TEST(Huffman, TestDecode) { - HuffmanCodec huffman(GetTestSet()); - TestBitReader bit_reader( - "01001" - "0001" - "1000" - "00110" - "00001" - "00"); - auto read_bit = [&bit_reader](bool* bit) { return bit_reader.ReadBit(bit); }; - - std::string decoded; - - ASSERT_TRUE(huffman.DecodeFromStream(read_bit, &decoded)); - EXPECT_EQ("l", decoded); - - ASSERT_TRUE(huffman.DecodeFromStream(read_bit, &decoded)); - EXPECT_EQ("i", decoded); - - ASSERT_TRUE(huffman.DecodeFromStream(read_bit, &decoded)); - EXPECT_EQ("n", decoded); - - ASSERT_TRUE(huffman.DecodeFromStream(read_bit, &decoded)); - EXPECT_EQ("u", decoded); - - ASSERT_TRUE(huffman.DecodeFromStream(read_bit, &decoded)); - EXPECT_EQ("x", decoded); - - ASSERT_FALSE(huffman.DecodeFromStream(read_bit, &decoded)); -} - -TEST(Huffman, TestDecodeNumbers) { - const std::map hist = {{1, 10}, {2, 5}, {3, 15}}; - HuffmanCodec huffman(hist); - - TestBitReader bit_reader( - "1" - "1" - "01" - "00" - "01" - "1"); - auto read_bit = [&bit_reader](bool* bit) { return bit_reader.ReadBit(bit); }; - - uint32_t decoded; - - ASSERT_TRUE(huffman.DecodeFromStream(read_bit, &decoded)); - EXPECT_EQ(3u, decoded); - - ASSERT_TRUE(huffman.DecodeFromStream(read_bit, &decoded)); - EXPECT_EQ(3u, decoded); - - ASSERT_TRUE(huffman.DecodeFromStream(read_bit, &decoded)); - EXPECT_EQ(2u, decoded); - - ASSERT_TRUE(huffman.DecodeFromStream(read_bit, &decoded)); - EXPECT_EQ(1u, decoded); - - ASSERT_TRUE(huffman.DecodeFromStream(read_bit, &decoded)); - EXPECT_EQ(2u, decoded); - - ASSERT_TRUE(huffman.DecodeFromStream(read_bit, &decoded)); - EXPECT_EQ(3u, decoded); -} - -TEST(Huffman, SerializeToTextU64) { - const std::map hist = {{1001, 10}, {1002, 5}, {1003, 15}}; - HuffmanCodec huffman(hist); - - const std::string code = huffman.SerializeToText(2); - - const std::string expected = R"((5, { - {0, 0, 0}, - {1001, 0, 0}, - {1002, 0, 0}, - {1003, 0, 0}, - {0, 1, 2}, - {0, 4, 3}, - }))"; - - ASSERT_EQ(expected, code); -} - -TEST(Huffman, SerializeToTextString) { - const std::map hist = { - {"aaa", 10}, {"bbb", 20}, {"ccc", 15}}; - HuffmanCodec huffman(hist); - - const std::string code = huffman.SerializeToText(4); - - const std::string expected = R"((5, { - {"", 0, 0}, - {"aaa", 0, 0}, - {"bbb", 0, 0}, - {"ccc", 0, 0}, - {"", 3, 1}, - {"", 4, 2}, - }))"; - - ASSERT_EQ(expected, code); -} - -TEST(Huffman, CreateFromTextString) { - std::vector::Node> nodes = { - {}, - {"root", 2, 3}, - {"left", 0, 0}, - {"right", 0, 0}, - }; - - HuffmanCodec huffman(1, std::move(nodes)); - - std::stringstream ss; - huffman.PrintTree(ss); - - const std::string expected = std::string(R"( -0------right -0------left -)") - .substr(1); - - EXPECT_EQ(expected, ss.str()); -} - -TEST(Huffman, CreateFromTextU64) { - HuffmanCodec huffman(5, { - {0, 0, 0}, - {1001, 0, 0}, - {1002, 0, 0}, - {1003, 0, 0}, - {0, 1, 2}, - {0, 4, 3}, - }); - - std::stringstream ss; - huffman.PrintTree(ss); - - const std::string expected = std::string(R"( -0------1003 -0------0------1002 - 0------1001 -)") - .substr(1); - - EXPECT_EQ(expected, ss.str()); - - TestBitReader bit_reader("01"); - auto read_bit = [&bit_reader](bool* bit) { return bit_reader.ReadBit(bit); }; - - uint64_t decoded = 0; - ASSERT_TRUE(huffman.DecodeFromStream(read_bit, &decoded)); - EXPECT_EQ(1002u, decoded); - - uint64_t bits = 0; - size_t num_bits = 0; - - EXPECT_TRUE(huffman.Encode(1001, &bits, &num_bits)); - EXPECT_EQ(2u, num_bits); - EXPECT_EQ("00", BitsToStream(bits, num_bits)); -} - -} // namespace -} // namespace comp -} // namespace spvtools diff --git a/third_party/spirv-tools/test/link/CMakeLists.txt b/third_party/spirv-tools/test/link/CMakeLists.txt index 06aeb91649..ee41b91617 100644 --- a/third_party/spirv-tools/test/link/CMakeLists.txt +++ b/third_party/spirv-tools/test/link/CMakeLists.txt @@ -23,5 +23,6 @@ add_spvtools_unittest(TARGET link memory_model_test.cpp partial_linkage_test.cpp unique_ids_test.cpp + type_match_test.cpp LIBS SPIRV-Tools-opt SPIRV-Tools-link ) diff --git a/third_party/spirv-tools/test/link/linker_fixture.h b/third_party/spirv-tools/test/link/linker_fixture.h index 303f1bfd57..7bb122354d 100644 --- a/third_party/spirv-tools/test/link/linker_fixture.h +++ b/third_party/spirv-tools/test/link/linker_fixture.h @@ -19,6 +19,8 @@ #include #include +#include "effcee/effcee.h" +#include "re2/re2.h" #include "source/spirv_constant.h" #include "spirv-tools/linker.hpp" #include "test/unit_spirv.h" @@ -80,6 +82,101 @@ class LinkerTest : public ::testing::Test { return spvtools::Link(context_, binaries, linked_binary, options); } + // Assembles and links a vector of SPIR-V bodies based on the |templateBody|. + // Template arguments to be replaced are written as {a,b,...}. + // SPV_ERROR_INVALID_TEXT is returned if the assembling failed for any of the + // resulting bodies (or errors in the template), and SPV_ERROR_INVALID_POINTER + // if |linked_binary| is a null pointer. + spv_result_t ExpandAndLink( + const std::string& templateBody, spvtest::Binary* linked_binary, + spvtools::LinkerOptions options = spvtools::LinkerOptions()) { + if (!linked_binary) return SPV_ERROR_INVALID_POINTER; + + // Find out how many template arguments there are, we assume they all have + // the same number. We'll error later if they don't. + re2::StringPiece temp(templateBody); + re2::StringPiece x; + int cnt = 0; + if (!RE2::FindAndConsume(&temp, "{")) return SPV_ERROR_INVALID_TEXT; + while (RE2::FindAndConsume(&temp, "([,}])", &x) && x[0] == ',') cnt++; + cnt++; + if (cnt <= 1) return SPV_ERROR_INVALID_TEXT; + + // Construct a regex for a single common strip and template expansion. + std::string regex("([^{]*){"); + for (int i = 0; i < cnt; i++) regex += (i > 0) ? ",([^,]*)" : "([^,]*)"; + regex += "}"; + RE2 pattern(regex); + + // Prepare the RE2::Args for processing. + re2::StringPiece common; + std::vector variants(cnt); + std::vector args(cnt + 1); + args[0] = RE2::Arg(&common); + std::vector pargs(cnt + 1); + pargs[0] = &args[0]; + for (int i = 0; i < cnt; i++) { + args[i + 1] = RE2::Arg(&variants[i]); + pargs[i + 1] = &args[i + 1]; + } + + // Reset and construct the bodies bit by bit. + std::vector bodies(cnt); + re2::StringPiece temp2(templateBody); + while (RE2::ConsumeN(&temp2, pattern, pargs.data(), cnt + 1)) { + for (int i = 0; i < cnt; i++) { + bodies[i].append(common.begin(), common.end()); + bodies[i].append(variants[i].begin(), variants[i].end()); + } + } + RE2::Consume(&temp2, "([^{]*)", &common); + for (int i = 0; i < cnt; i++) + bodies[i].append(common.begin(), common.end()); + + // Run through the assemble and link stages of the process. + return AssembleAndLink(bodies, linked_binary, options); + } + + // Expand the |templateBody| and link the results as with ExpandAndLink, + // then disassemble and test that the result matches the |expected|. + void ExpandAndCheck( + const std::string& templateBody, const std::string& expected, + const spvtools::LinkerOptions options = spvtools::LinkerOptions()) { + spvtest::Binary linked_binary; + spv_result_t res = ExpandAndLink(templateBody, &linked_binary, options); + EXPECT_EQ(SPV_SUCCESS, res) << GetErrorMessage() << "\nExpanded from:\n" + << templateBody; + if (res == SPV_SUCCESS) { + std::string result; + EXPECT_TRUE( + tools_.Disassemble(linked_binary, &result, disassemble_options_)) + << GetErrorMessage(); + EXPECT_EQ(expected, result); + } + } + + // An alternative to ExpandAndCheck, which uses the |templateBody| as the + // match pattern for the disassembled linked result. + void ExpandAndMatch( + const std::string& templateBody, + const spvtools::LinkerOptions options = spvtools::LinkerOptions()) { + spvtest::Binary linked_binary; + spv_result_t res = ExpandAndLink(templateBody, &linked_binary, options); + EXPECT_EQ(SPV_SUCCESS, res) << GetErrorMessage() << "\nExpanded from:\n" + << templateBody; + if (res == SPV_SUCCESS) { + std::string result; + EXPECT_TRUE( + tools_.Disassemble(linked_binary, &result, disassemble_options_)) + << GetErrorMessage(); + auto match_res = effcee::Match(result, templateBody); + EXPECT_EQ(effcee::Result::Status::Ok, match_res.status()) + << match_res.message() << "\nExpanded from:\n" + << templateBody << "\nChecking result:\n" + << result; + } + } + // Links the given SPIR-V binaries together; SPV_ERROR_INVALID_POINTER is // returned if |linked_binary| is a null pointer. spv_result_t Link( diff --git a/third_party/spirv-tools/test/link/matching_imports_to_exports_test.cpp b/third_party/spirv-tools/test/link/matching_imports_to_exports_test.cpp index 59e62d51b8..e76c69fb31 100644 --- a/third_party/spirv-tools/test/link/matching_imports_to_exports_test.cpp +++ b/third_party/spirv-tools/test/link/matching_imports_to_exports_test.cpp @@ -399,5 +399,78 @@ OpFunctionEnd EXPECT_EQ(expected_res, res_body); } +TEST_F(MatchingImportsToExports, NamesAndDecorations) { + const std::string body1 = R"( +OpCapability Kernel +OpCapability Linkage +OpName %1 "foo" +OpName %3 "param" +OpDecorate %1 LinkageAttributes "foo" Import +OpDecorate %2 Restrict +OpDecorate %4 NonWritable +%2 = OpDecorationGroup +OpGroupDecorate %2 %3 %4 +%5 = OpTypeVoid +%6 = OpTypeInt 32 0 +%9 = OpTypePointer Function %6 +%7 = OpTypeFunction %5 %9 +%1 = OpFunction %5 None %7 +%3 = OpFunctionParameter %9 +OpFunctionEnd +%8 = OpFunction %5 None %7 +%4 = OpFunctionParameter %9 +OpFunctionEnd +)"; + const std::string body2 = R"( +OpCapability Kernel +OpCapability Linkage +OpName %1 "foo" +OpName %2 "param" +OpDecorate %1 LinkageAttributes "foo" Export +OpDecorate %2 Restrict +%3 = OpTypeVoid +%4 = OpTypeInt 32 0 +%7 = OpTypePointer Function %4 +%5 = OpTypeFunction %3 %7 +%1 = OpFunction %3 None %5 +%2 = OpFunctionParameter %7 +%6 = OpLabel +OpReturn +OpFunctionEnd +)"; + + spvtest::Binary linked_binary; + EXPECT_EQ(SPV_SUCCESS, AssembleAndLink({body1, body2}, &linked_binary)) + << GetErrorMessage(); + + const std::string expected_res = R"(OpCapability Kernel +OpName %1 "foo" +OpName %2 "param" +OpModuleProcessed "Linked by SPIR-V Tools Linker" +OpDecorate %3 Restrict +OpDecorate %4 NonWritable +%3 = OpDecorationGroup +OpGroupDecorate %3 %4 +OpDecorate %2 Restrict +%5 = OpTypeVoid +%6 = OpTypeInt 32 0 +%7 = OpTypePointer Function %6 +%8 = OpTypeFunction %5 %7 +%9 = OpFunction %5 None %8 +%4 = OpFunctionParameter %7 +OpFunctionEnd +%1 = OpFunction %5 None %8 +%2 = OpFunctionParameter %7 +%10 = OpLabel +OpReturn +OpFunctionEnd +)"; + std::string res_body; + SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER); + EXPECT_EQ(SPV_SUCCESS, Disassemble(linked_binary, &res_body)) + << GetErrorMessage(); + EXPECT_EQ(expected_res, res_body); +} + } // namespace } // namespace spvtools diff --git a/third_party/spirv-tools/test/link/type_match_test.cpp b/third_party/spirv-tools/test/link/type_match_test.cpp new file mode 100644 index 0000000000..dae70c163f --- /dev/null +++ b/third_party/spirv-tools/test/link/type_match_test.cpp @@ -0,0 +1,148 @@ +// Copyright (c) 2019 The Khronos Group Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "gmock/gmock.h" +#include "test/link/linker_fixture.h" + +namespace spvtools { +namespace { + +using TypeMatch = spvtest::LinkerTest; + +// Basic types +#define PartInt(D, N) D(N) " = OpTypeInt 32 0" +#define PartFloat(D, N) D(N) " = OpTypeFloat 32" +#define PartOpaque(D, N) D(N) " = OpTypeOpaque \"bar\"" +#define PartSampler(D, N) D(N) " = OpTypeSampler" +#define PartEvent(D, N) D(N) " = OpTypeEvent" +#define PartDeviceEvent(D, N) D(N) " = OpTypeDeviceEvent" +#define PartReserveId(D, N) D(N) " = OpTypeReserveId" +#define PartQueue(D, N) D(N) " = OpTypeQueue" +#define PartPipe(D, N) D(N) " = OpTypePipe ReadWrite" +#define PartPipeStorage(D, N) D(N) " = OpTypePipeStorage" +#define PartNamedBarrier(D, N) D(N) " = OpTypeNamedBarrier" + +// Compound types +#define PartVector(DR, DA, N, T) DR(N) " = OpTypeVector " DA(T) " 3" +#define PartMatrix(DR, DA, N, T) DR(N) " = OpTypeMatrix " DA(T) " 4" +#define PartImage(DR, DA, N, T) \ + DR(N) " = OpTypeImage " DA(T) " 2D 0 0 0 0 Rgba32f" +#define PartSampledImage(DR, DA, N, T) DR(N) " = OpTypeSampledImage " DA(T) +#define PartArray(DR, DA, N, T) DR(N) " = OpTypeArray " DA(T) " " DA(const) +#define PartRuntimeArray(DR, DA, N, T) DR(N) " = OpTypeRuntimeArray " DA(T) +#define PartStruct(DR, DA, N, T) DR(N) " = OpTypeStruct " DA(T) " " DA(T) +#define PartPointer(DR, DA, N, T) DR(N) " = OpTypePointer Workgroup " DA(T) +#define PartFunction(DR, DA, N, T) DR(N) " = OpTypeFunction " DA(T) " " DA(T) + +#define CheckDecoRes(S) "[[" #S ":%\\w+]]" +#define CheckDecoArg(S) "[[" #S "]]" +#define InstDeco(S) "%" #S + +#define MatchPart1(F, N) \ + "; CHECK: " Part##F(CheckDecoRes, N) "\n" Part##F(InstDeco, N) "\n" +#define MatchPart2(F, N, T) \ + "; CHECK: " Part##F(CheckDecoRes, CheckDecoArg, N, T) "\n" Part##F( \ + InstDeco, InstDeco, N, T) "\n" + +#define MatchF(N, CODE) \ + TEST_F(TypeMatch, N) { \ + const std::string base = \ + "OpCapability Linkage\n" \ + "OpCapability NamedBarrier\n" \ + "OpCapability PipeStorage\n" \ + "OpCapability Pipes\n" \ + "OpCapability DeviceEnqueue\n" \ + "OpCapability Kernel\n" \ + "OpCapability Shader\n" \ + "OpCapability Addresses\n" \ + "OpDecorate %var LinkageAttributes \"foo\" " \ + "{Import,Export}\n" \ + "; CHECK: [[baseint:%\\w+]] = OpTypeInt 32 1\n" \ + "%baseint = OpTypeInt 32 1\n" \ + "; CHECK: [[const:%\\w+]] = OpConstant [[baseint]] 3\n" \ + "%const = OpConstant %baseint 3\n" CODE \ + "; CHECK: OpVariable [[type]] Uniform\n" \ + "%var = OpVariable %type Uniform"; \ + ExpandAndMatch(base); \ + } + +#define Match1(T) MatchF(Type##T, MatchPart1(T, type)) +#define Match2(T, A) \ + MatchF(T##OfType##A, MatchPart1(A, a) MatchPart2(T, type, a)) +#define Match3(T, A, B) \ + MatchF(T##Of##A##Of##B, \ + MatchPart1(B, b) MatchPart2(A, a, b) MatchPart2(T, type, a)) + +// clang-format off +// Basic types +Match1(Int) +Match1(Float) +Match1(Opaque) +Match1(Sampler) +Match1(Event) +Match1(DeviceEvent) +Match1(ReserveId) +Match1(Queue) +Match1(Pipe) +Match1(PipeStorage) +Match1(NamedBarrier) + +// Simpler (restricted) compound types +Match2(Vector, Float) +Match3(Matrix, Vector, Float) +Match2(Image, Float) + +// Unrestricted compound types +#define MatchCompounds1(A) \ + Match2(RuntimeArray, A) \ + Match2(Struct, A) \ + Match2(Pointer, A) \ + Match2(Function, A) \ + Match2(Array, A) +#define MatchCompounds2(A, B) \ + Match3(RuntimeArray, A, B) \ + Match3(Struct, A, B) \ + Match3(Pointer, A, B) \ + Match3(Function, A, B) \ + Match3(Array, A, B) + +MatchCompounds1(Float) +MatchCompounds2(Array, Float) +MatchCompounds2(RuntimeArray, Float) +MatchCompounds2(Struct, Float) +MatchCompounds2(Pointer, Float) +MatchCompounds2(Function, Float) +// clang-format on + +// ForwardPointer tests, which don't fit into the previous mold +#define MatchFpF(N, CODE) \ + MatchF(N, \ + "; CHECK: OpTypeForwardPointer [[type:%\\w+]] Workgroup\n" \ + "OpTypeForwardPointer %type Workgroup\n" CODE \ + "; CHECK: [[type]] = OpTypePointer Workgroup [[realtype]]\n" \ + "%type = OpTypePointer Workgroup %realtype\n") +#define MatchFp1(T) MatchFpF(ForwardPointerOf##T, MatchPart1(T, realtype)) +#define MatchFp2(T, A) \ + MatchFpF(ForwardPointerOf##T, MatchPart1(A, a) MatchPart2(T, realtype, a)) + + // clang-format off +MatchFp1(Float) +MatchFp2(Array, Float) +MatchFp2(RuntimeArray, Float) +MatchFp2(Struct, Float) +MatchFp2(Function, Float) +// clang-format on + +} // namespace +} // namespace spvtools diff --git a/third_party/spirv-tools/test/move_to_front_test.cpp b/third_party/spirv-tools/test/move_to_front_test.cpp deleted file mode 100644 index c95d38656c..0000000000 --- a/third_party/spirv-tools/test/move_to_front_test.cpp +++ /dev/null @@ -1,828 +0,0 @@ -// Copyright (c) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include -#include -#include -#include - -#include "gmock/gmock.h" -#include "source/comp/move_to_front.h" - -namespace spvtools { -namespace comp { -namespace { - -// Class used to test the inner workings of MoveToFront. -class MoveToFrontTester : public MoveToFront { - public: - // Inserts the value in the internal tree data structure. For testing only. - void TestInsert(uint32_t val) { InsertNode(CreateNode(val, val)); } - - // Removes the value from the internal tree data structure. For testing only. - void TestRemove(uint32_t val) { - const auto it = value_to_node_.find(val); - assert(it != value_to_node_.end()); - RemoveNode(it->second); - } - - // Prints the internal tree data structure to |out|. For testing only. - void PrintTree(std::ostream& out, bool print_timestamp = false) const { - if (root_) PrintTreeInternal(out, root_, 1, print_timestamp); - } - - // Returns node handle corresponding to the value. The value may not be in the - // tree. - uint32_t GetNodeHandle(uint32_t value) const { - const auto it = value_to_node_.find(value); - if (it == value_to_node_.end()) return 0; - - return it->second; - } - - // Returns total node count (both those in the tree and removed, - // but not the NIL singleton). - size_t GetTotalNodeCount() const { - assert(nodes_.size()); - return nodes_.size() - 1; - } - - uint32_t GetLastAccessedValue() const { return last_accessed_value_; } - - private: - // Prints the internal tree data structure for debug purposes in the following - // format: - // 10H3S4----5H1S1-----D2 - // 15H2S2----12H1S1----D3 - // Right links are horizontal, left links step down one line. - // 5H1S1 is read as value 5, height 1, size 1. Optionally node label can also - // contain timestamp (5H1S1T15). D3 stands for depth 3. - void PrintTreeInternal(std::ostream& out, uint32_t node, size_t depth, - bool print_timestamp) const; -}; - -void MoveToFrontTester::PrintTreeInternal(std::ostream& out, uint32_t node, - size_t depth, - bool print_timestamp) const { - if (!node) { - out << "D" << depth - 1 << std::endl; - return; - } - - const size_t kTextFieldWvaluethWithoutTimestamp = 10; - const size_t kTextFieldWvaluethWithTimestamp = 14; - const size_t text_field_wvalueth = print_timestamp - ? kTextFieldWvaluethWithTimestamp - : kTextFieldWvaluethWithoutTimestamp; - - std::stringstream label; - label << ValueOf(node) << "H" << HeightOf(node) << "S" << SizeOf(node); - if (print_timestamp) label << "T" << TimestampOf(node); - const size_t label_length = label.str().length(); - if (label_length < text_field_wvalueth) - label << std::string(text_field_wvalueth - label_length, '-'); - - out << label.str(); - - PrintTreeInternal(out, RightOf(node), depth + 1, print_timestamp); - - if (LeftOf(node)) { - out << std::string(depth * text_field_wvalueth, ' '); - PrintTreeInternal(out, LeftOf(node), depth + 1, print_timestamp); - } -} - -void CheckTree(const MoveToFrontTester& mtf, const std::string& expected, - bool print_timestamp = false) { - std::stringstream ss; - mtf.PrintTree(ss, print_timestamp); - EXPECT_EQ(expected, ss.str()); -} - -TEST(MoveToFront, EmptyTree) { - MoveToFrontTester mtf; - CheckTree(mtf, std::string()); -} - -TEST(MoveToFront, InsertLeftRotation) { - MoveToFrontTester mtf; - - mtf.TestInsert(30); - mtf.TestInsert(20); - - CheckTree(mtf, std::string(R"( -30H2S2----20H1S1----D2 -)") - .substr(1)); - - mtf.TestInsert(10); - CheckTree(mtf, std::string(R"( -20H2S3----10H1S1----D2 - 30H1S1----D2 -)") - .substr(1)); -} - -TEST(MoveToFront, InsertRightRotation) { - MoveToFrontTester mtf; - - mtf.TestInsert(10); - mtf.TestInsert(20); - - CheckTree(mtf, std::string(R"( -10H2S2----D1 - 20H1S1----D2 -)") - .substr(1)); - - mtf.TestInsert(30); - CheckTree(mtf, std::string(R"( -20H2S3----10H1S1----D2 - 30H1S1----D2 -)") - .substr(1)); -} - -TEST(MoveToFront, InsertRightLeftRotation) { - MoveToFrontTester mtf; - - mtf.TestInsert(30); - mtf.TestInsert(20); - - CheckTree(mtf, std::string(R"( -30H2S2----20H1S1----D2 -)") - .substr(1)); - - mtf.TestInsert(25); - CheckTree(mtf, std::string(R"( -25H2S3----20H1S1----D2 - 30H1S1----D2 -)") - .substr(1)); -} - -TEST(MoveToFront, InsertLeftRightRotation) { - MoveToFrontTester mtf; - - mtf.TestInsert(10); - mtf.TestInsert(20); - - CheckTree(mtf, std::string(R"( -10H2S2----D1 - 20H1S1----D2 -)") - .substr(1)); - - mtf.TestInsert(15); - CheckTree(mtf, std::string(R"( -15H2S3----10H1S1----D2 - 20H1S1----D2 -)") - .substr(1)); -} - -TEST(MoveToFront, RemoveSingleton) { - MoveToFrontTester mtf; - - mtf.TestInsert(10); - CheckTree(mtf, std::string(R"( -10H1S1----D1 -)") - .substr(1)); - - mtf.TestRemove(10); - CheckTree(mtf, ""); -} - -TEST(MoveToFront, RemoveRootWithScapegoat) { - MoveToFrontTester mtf; - - mtf.TestInsert(10); - mtf.TestInsert(5); - mtf.TestInsert(15); - CheckTree(mtf, std::string(R"( -10H2S3----5H1S1-----D2 - 15H1S1----D2 -)") - .substr(1)); - - mtf.TestRemove(10); - CheckTree(mtf, std::string(R"( -15H2S2----5H1S1-----D2 -)") - .substr(1)); -} - -TEST(MoveToFront, RemoveRightRotation) { - MoveToFrontTester mtf; - - mtf.TestInsert(10); - mtf.TestInsert(5); - mtf.TestInsert(15); - mtf.TestInsert(20); - CheckTree(mtf, std::string(R"( -10H3S4----5H1S1-----D2 - 15H2S2----D2 - 20H1S1----D3 -)") - .substr(1)); - - mtf.TestRemove(5); - - CheckTree(mtf, std::string(R"( -15H2S3----10H1S1----D2 - 20H1S1----D2 -)") - .substr(1)); -} - -TEST(MoveToFront, RemoveLeftRotation) { - MoveToFrontTester mtf; - - mtf.TestInsert(10); - mtf.TestInsert(15); - mtf.TestInsert(5); - mtf.TestInsert(1); - CheckTree(mtf, std::string(R"( -10H3S4----5H2S2-----1H1S1-----D3 - 15H1S1----D2 -)") - .substr(1)); - - mtf.TestRemove(15); - - CheckTree(mtf, std::string(R"( -5H2S3-----1H1S1-----D2 - 10H1S1----D2 -)") - .substr(1)); -} - -TEST(MoveToFront, RemoveLeftRightRotation) { - MoveToFrontTester mtf; - - mtf.TestInsert(10); - mtf.TestInsert(15); - mtf.TestInsert(5); - mtf.TestInsert(12); - CheckTree(mtf, std::string(R"( -10H3S4----5H1S1-----D2 - 15H2S2----12H1S1----D3 -)") - .substr(1)); - - mtf.TestRemove(5); - - CheckTree(mtf, std::string(R"( -12H2S3----10H1S1----D2 - 15H1S1----D2 -)") - .substr(1)); -} - -TEST(MoveToFront, RemoveRightLeftRotation) { - MoveToFrontTester mtf; - - mtf.TestInsert(10); - mtf.TestInsert(15); - mtf.TestInsert(5); - mtf.TestInsert(8); - CheckTree(mtf, std::string(R"( -10H3S4----5H2S2-----D2 - 8H1S1-----D3 - 15H1S1----D2 -)") - .substr(1)); - - mtf.TestRemove(15); - - CheckTree(mtf, std::string(R"( -8H2S3-----5H1S1-----D2 - 10H1S1----D2 -)") - .substr(1)); -} - -TEST(MoveToFront, MultipleOperations) { - MoveToFrontTester mtf; - std::vector vals = {5, 11, 12, 16, 15, 6, 14, 2, - 7, 10, 4, 8, 9, 3, 1, 13}; - - for (uint32_t i : vals) { - mtf.TestInsert(i); - } - - CheckTree(mtf, std::string(R"( -11H5S16---5H4S10----3H3S4-----2H2S2-----1H1S1-----D5 - 4H1S1-----D4 - 7H3S5-----6H1S1-----D4 - 9H2S3-----8H1S1-----D5 - 10H1S1----D5 - 15H3S5----13H2S3----12H1S1----D4 - 14H1S1----D4 - 16H1S1----D3 -)") - .substr(1)); - - mtf.TestRemove(11); - - CheckTree(mtf, std::string(R"( -10H5S15---5H4S9-----3H3S4-----2H2S2-----1H1S1-----D5 - 4H1S1-----D4 - 7H3S4-----6H1S1-----D4 - 9H2S2-----8H1S1-----D5 - 15H3S5----13H2S3----12H1S1----D4 - 14H1S1----D4 - 16H1S1----D3 -)") - .substr(1)); - - mtf.TestInsert(11); - - CheckTree(mtf, std::string(R"( -10H5S16---5H4S9-----3H3S4-----2H2S2-----1H1S1-----D5 - 4H1S1-----D4 - 7H3S4-----6H1S1-----D4 - 9H2S2-----8H1S1-----D5 - 13H3S6----12H2S2----11H1S1----D4 - 15H2S3----14H1S1----D4 - 16H1S1----D4 -)") - .substr(1)); - - mtf.TestRemove(5); - - CheckTree(mtf, std::string(R"( -10H5S15---6H4S8-----3H3S4-----2H2S2-----1H1S1-----D5 - 4H1S1-----D4 - 8H2S3-----7H1S1-----D4 - 9H1S1-----D4 - 13H3S6----12H2S2----11H1S1----D4 - 15H2S3----14H1S1----D4 - 16H1S1----D4 -)") - .substr(1)); - - mtf.TestInsert(5); - - CheckTree(mtf, std::string(R"( -10H5S16---6H4S9-----3H3S5-----2H2S2-----1H1S1-----D5 - 4H2S2-----D4 - 5H1S1-----D5 - 8H2S3-----7H1S1-----D4 - 9H1S1-----D4 - 13H3S6----12H2S2----11H1S1----D4 - 15H2S3----14H1S1----D4 - 16H1S1----D4 -)") - .substr(1)); - - mtf.TestRemove(2); - mtf.TestRemove(1); - mtf.TestRemove(4); - mtf.TestRemove(3); - mtf.TestRemove(6); - mtf.TestRemove(5); - mtf.TestRemove(7); - mtf.TestRemove(9); - - CheckTree(mtf, std::string(R"( -13H4S8----10H3S4----8H1S1-----D3 - 12H2S2----11H1S1----D4 - 15H2S3----14H1S1----D3 - 16H1S1----D3 -)") - .substr(1)); -} - -TEST(MoveToFront, BiggerScaleTreeTest) { - MoveToFrontTester mtf; - std::set all_vals; - - const uint32_t kMagic1 = 2654435761; - const uint32_t kMagic2 = 10000; - - for (uint32_t i = 1; i < 1000; ++i) { - const uint32_t val = (i * kMagic1) % kMagic2; - if (!all_vals.count(val)) { - mtf.TestInsert(val); - all_vals.insert(val); - } - } - - for (uint32_t i = 1; i < 1000; ++i) { - const uint32_t val = (i * kMagic1) % kMagic2; - if (val % 2 == 0) { - mtf.TestRemove(val); - all_vals.erase(val); - } - } - - for (uint32_t i = 1000; i < 2000; ++i) { - const uint32_t val = (i * kMagic1) % kMagic2; - if (!all_vals.count(val)) { - mtf.TestInsert(val); - all_vals.insert(val); - } - } - - for (uint32_t i = 1; i < 2000; ++i) { - const uint32_t val = (i * kMagic1) % kMagic2; - if (val > 50) { - mtf.TestRemove(val); - all_vals.erase(val); - } - } - - EXPECT_EQ(all_vals, std::set({2, 4, 11, 13, 24, 33, 35, 37, 46})); - - CheckTree(mtf, std::string(R"( -33H4S9----11H3S5----2H2S2-----D3 - 4H1S1-----D4 - 13H2S2----D3 - 24H1S1----D4 - 37H2S3----35H1S1----D3 - 46H1S1----D3 -)") - .substr(1)); -} - -TEST(MoveToFront, RankFromValue) { - MoveToFrontTester mtf; - - uint32_t rank = 0; - EXPECT_FALSE(mtf.RankFromValue(1, &rank)); - - EXPECT_TRUE(mtf.Insert(1)); - EXPECT_TRUE(mtf.Insert(2)); - EXPECT_TRUE(mtf.Insert(3)); - EXPECT_FALSE(mtf.Insert(2)); - CheckTree(mtf, - std::string(R"( -2H2S3T2-------1H1S1T1-------D2 - 3H1S1T3-------D2 -)") - .substr(1), - /* print_timestamp = */ true); - - EXPECT_FALSE(mtf.RankFromValue(4, &rank)); - - EXPECT_TRUE(mtf.RankFromValue(1, &rank)); - EXPECT_EQ(3u, rank); - - CheckTree(mtf, - std::string(R"( -3H2S3T3-------2H1S1T2-------D2 - 1H1S1T4-------D2 -)") - .substr(1), - /* print_timestamp = */ true); - - EXPECT_TRUE(mtf.RankFromValue(1, &rank)); - EXPECT_EQ(1u, rank); - - EXPECT_TRUE(mtf.RankFromValue(3, &rank)); - EXPECT_EQ(2u, rank); - - EXPECT_TRUE(mtf.RankFromValue(2, &rank)); - EXPECT_EQ(3u, rank); - - EXPECT_TRUE(mtf.Insert(40)); - - EXPECT_TRUE(mtf.RankFromValue(1, &rank)); - EXPECT_EQ(4u, rank); - - EXPECT_TRUE(mtf.Insert(50)); - - EXPECT_TRUE(mtf.RankFromValue(1, &rank)); - EXPECT_EQ(2u, rank); - - CheckTree(mtf, - std::string(R"( -2H3S5T6-------3H1S1T5-------D2 - 50H2S3T9------40H1S1T7------D3 - 1H1S1T10------D3 -)") - .substr(1), - /* print_timestamp = */ true); - - EXPECT_TRUE(mtf.RankFromValue(50, &rank)); - EXPECT_EQ(2u, rank); - - EXPECT_EQ(5u, mtf.GetSize()); - CheckTree(mtf, - std::string(R"( -2H3S5T6-------3H1S1T5-------D2 - 1H2S3T10------40H1S1T7------D3 - 50H1S1T11-----D3 -)") - .substr(1), - /* print_timestamp = */ true); - - EXPECT_FALSE(mtf.RankFromValue(0, &rank)); - EXPECT_FALSE(mtf.RankFromValue(20, &rank)); -} - -TEST(MoveToFront, ValueFromRank) { - MoveToFrontTester mtf; - - uint32_t value = 0; - EXPECT_FALSE(mtf.ValueFromRank(0, &value)); - EXPECT_FALSE(mtf.ValueFromRank(1, &value)); - - EXPECT_TRUE(mtf.Insert(1)); - EXPECT_EQ(1u, mtf.GetLastAccessedValue()); - EXPECT_TRUE(mtf.Insert(2)); - EXPECT_EQ(2u, mtf.GetLastAccessedValue()); - EXPECT_TRUE(mtf.Insert(3)); - EXPECT_EQ(3u, mtf.GetLastAccessedValue()); - - EXPECT_TRUE(mtf.ValueFromRank(3, &value)); - EXPECT_EQ(1u, value); - EXPECT_EQ(1u, mtf.GetLastAccessedValue()); - - EXPECT_TRUE(mtf.ValueFromRank(1, &value)); - EXPECT_EQ(1u, value); - EXPECT_EQ(1u, mtf.GetLastAccessedValue()); - - CheckTree(mtf, - std::string(R"( -3H2S3T3-------2H1S1T2-------D2 - 1H1S1T4-------D2 -)") - .substr(1), - /* print_timestamp = */ true); - - EXPECT_TRUE(mtf.ValueFromRank(2, &value)); - EXPECT_EQ(3u, value); - - EXPECT_EQ(3u, mtf.GetSize()); - - CheckTree(mtf, - std::string(R"( -1H2S3T4-------2H1S1T2-------D2 - 3H1S1T5-------D2 -)") - .substr(1), - /* print_timestamp = */ true); - - EXPECT_TRUE(mtf.ValueFromRank(3, &value)); - EXPECT_EQ(2u, value); - - CheckTree(mtf, - std::string(R"( -3H2S3T5-------1H1S1T4-------D2 - 2H1S1T6-------D2 -)") - .substr(1), - /* print_timestamp = */ true); - - EXPECT_TRUE(mtf.Insert(10)); - CheckTree(mtf, - std::string(R"( -3H3S4T5-------1H1S1T4-------D2 - 2H2S2T6-------D2 - 10H1S1T7------D3 -)") - .substr(1), - /* print_timestamp = */ true); - - EXPECT_TRUE(mtf.ValueFromRank(1, &value)); - EXPECT_EQ(10u, value); -} - -TEST(MoveToFront, Remove) { - MoveToFrontTester mtf; - - EXPECT_FALSE(mtf.Remove(1)); - EXPECT_EQ(0u, mtf.GetTotalNodeCount()); - - EXPECT_TRUE(mtf.Insert(1)); - EXPECT_TRUE(mtf.Insert(2)); - EXPECT_TRUE(mtf.Insert(3)); - - CheckTree(mtf, - std::string(R"( -2H2S3T2-------1H1S1T1-------D2 - 3H1S1T3-------D2 -)") - .substr(1), - /* print_timestamp = */ true); - - EXPECT_EQ(1u, mtf.GetNodeHandle(1)); - EXPECT_EQ(3u, mtf.GetTotalNodeCount()); - EXPECT_TRUE(mtf.Remove(1)); - EXPECT_EQ(3u, mtf.GetTotalNodeCount()); - - CheckTree(mtf, - std::string(R"( -2H2S2T2-------D1 - 3H1S1T3-------D2 -)") - .substr(1), - /* print_timestamp = */ true); - - uint32_t value = 0; - EXPECT_TRUE(mtf.ValueFromRank(2, &value)); - EXPECT_EQ(2u, value); - - CheckTree(mtf, - std::string(R"( -3H2S2T3-------D1 - 2H1S1T4-------D2 -)") - .substr(1), - /* print_timestamp = */ true); - - EXPECT_TRUE(mtf.Insert(1)); - EXPECT_EQ(1u, mtf.GetNodeHandle(1)); - EXPECT_EQ(3u, mtf.GetTotalNodeCount()); -} - -TEST(MoveToFront, LargerScale) { - MoveToFrontTester mtf; - uint32_t value = 0; - uint32_t rank = 0; - - for (uint32_t i = 1; i < 1000; ++i) { - ASSERT_TRUE(mtf.Insert(i)); - ASSERT_EQ(i, mtf.GetSize()); - - ASSERT_TRUE(mtf.RankFromValue(i, &rank)); - ASSERT_EQ(1u, rank); - - ASSERT_TRUE(mtf.ValueFromRank(1, &value)); - ASSERT_EQ(i, value); - } - - ASSERT_TRUE(mtf.ValueFromRank(999, &value)); - ASSERT_EQ(1u, value); - - ASSERT_TRUE(mtf.ValueFromRank(999, &value)); - ASSERT_EQ(2u, value); - - ASSERT_TRUE(mtf.ValueFromRank(999, &value)); - ASSERT_EQ(3u, value); - - ASSERT_TRUE(mtf.ValueFromRank(999, &value)); - ASSERT_EQ(4u, value); - - ASSERT_TRUE(mtf.ValueFromRank(999, &value)); - ASSERT_EQ(5u, value); - - ASSERT_TRUE(mtf.ValueFromRank(999, &value)); - ASSERT_EQ(6u, value); - - ASSERT_TRUE(mtf.ValueFromRank(101, &value)); - ASSERT_EQ(905u, value); - - ASSERT_TRUE(mtf.ValueFromRank(101, &value)); - ASSERT_EQ(906u, value); - - ASSERT_TRUE(mtf.ValueFromRank(101, &value)); - ASSERT_EQ(907u, value); - - ASSERT_TRUE(mtf.ValueFromRank(201, &value)); - ASSERT_EQ(805u, value); - - ASSERT_TRUE(mtf.ValueFromRank(201, &value)); - ASSERT_EQ(806u, value); - - ASSERT_TRUE(mtf.ValueFromRank(201, &value)); - ASSERT_EQ(807u, value); - - ASSERT_TRUE(mtf.ValueFromRank(301, &value)); - ASSERT_EQ(705u, value); - - ASSERT_TRUE(mtf.ValueFromRank(301, &value)); - ASSERT_EQ(706u, value); - - ASSERT_TRUE(mtf.ValueFromRank(301, &value)); - ASSERT_EQ(707u, value); - - ASSERT_TRUE(mtf.RankFromValue(605, &rank)); - ASSERT_EQ(401u, rank); - - ASSERT_TRUE(mtf.RankFromValue(606, &rank)); - ASSERT_EQ(401u, rank); - - ASSERT_TRUE(mtf.RankFromValue(607, &rank)); - ASSERT_EQ(401u, rank); - - ASSERT_TRUE(mtf.ValueFromRank(1, &value)); - ASSERT_EQ(607u, value); - - ASSERT_TRUE(mtf.ValueFromRank(2, &value)); - ASSERT_EQ(606u, value); - - ASSERT_TRUE(mtf.ValueFromRank(3, &value)); - ASSERT_EQ(605u, value); - - ASSERT_TRUE(mtf.ValueFromRank(4, &value)); - ASSERT_EQ(707u, value); - - ASSERT_TRUE(mtf.ValueFromRank(5, &value)); - ASSERT_EQ(706u, value); - - ASSERT_TRUE(mtf.ValueFromRank(6, &value)); - ASSERT_EQ(705u, value); - - ASSERT_TRUE(mtf.ValueFromRank(7, &value)); - ASSERT_EQ(807u, value); - - ASSERT_TRUE(mtf.ValueFromRank(8, &value)); - ASSERT_EQ(806u, value); - - ASSERT_TRUE(mtf.ValueFromRank(9, &value)); - ASSERT_EQ(805u, value); - - ASSERT_TRUE(mtf.ValueFromRank(10, &value)); - ASSERT_EQ(907u, value); - - ASSERT_TRUE(mtf.ValueFromRank(11, &value)); - ASSERT_EQ(906u, value); - - ASSERT_TRUE(mtf.ValueFromRank(12, &value)); - ASSERT_EQ(905u, value); - - ASSERT_TRUE(mtf.ValueFromRank(13, &value)); - ASSERT_EQ(6u, value); - - ASSERT_TRUE(mtf.ValueFromRank(14, &value)); - ASSERT_EQ(5u, value); - - ASSERT_TRUE(mtf.ValueFromRank(15, &value)); - ASSERT_EQ(4u, value); - - ASSERT_TRUE(mtf.ValueFromRank(16, &value)); - ASSERT_EQ(3u, value); - - ASSERT_TRUE(mtf.ValueFromRank(17, &value)); - ASSERT_EQ(2u, value); - - ASSERT_TRUE(mtf.ValueFromRank(18, &value)); - ASSERT_EQ(1u, value); - - ASSERT_TRUE(mtf.ValueFromRank(19, &value)); - ASSERT_EQ(999u, value); - - ASSERT_TRUE(mtf.ValueFromRank(20, &value)); - ASSERT_EQ(998u, value); - - ASSERT_TRUE(mtf.ValueFromRank(21, &value)); - ASSERT_EQ(997u, value); - - ASSERT_TRUE(mtf.RankFromValue(997, &rank)); - ASSERT_EQ(1u, rank); - - ASSERT_TRUE(mtf.RankFromValue(998, &rank)); - ASSERT_EQ(2u, rank); - - ASSERT_TRUE(mtf.RankFromValue(996, &rank)); - ASSERT_EQ(22u, rank); - - ASSERT_TRUE(mtf.Remove(995)); - - ASSERT_TRUE(mtf.RankFromValue(994, &rank)); - ASSERT_EQ(23u, rank); - - for (uint32_t i = 10; i < 1000; ++i) { - if (i != 995) { - ASSERT_TRUE(mtf.Remove(i)); - } else { - ASSERT_FALSE(mtf.Remove(i)); - } - } - - CheckTree(mtf, - std::string(R"( -6H4S9T1029----8H2S3T8-------7H1S1T7-------D3 - 9H1S1T9-------D3 - 2H3S5T1033----4H2S3T1031----5H1S1T1030----D4 - 3H1S1T1032----D4 - 1H1S1T1034----D3 -)") - .substr(1), - /* print_timestamp = */ true); - - ASSERT_TRUE(mtf.Insert(1000)); - ASSERT_TRUE(mtf.ValueFromRank(1, &value)); - ASSERT_EQ(1000u, value); -} - -} // namespace -} // namespace comp -} // namespace spvtools diff --git a/third_party/spirv-tools/test/name_mapper_test.cpp b/third_party/spirv-tools/test/name_mapper_test.cpp index 9a9ee8aa01..00fbeed684 100644 --- a/third_party/spirv-tools/test/name_mapper_test.cpp +++ b/third_party/spirv-tools/test/name_mapper_test.cpp @@ -54,31 +54,31 @@ TEST_P(FriendlyNameTest, SingleMapping) { << " for id " << GetParam().id; } -INSTANTIATE_TEST_CASE_P(ScalarType, FriendlyNameTest, - ::testing::ValuesIn(std::vector{ - {"%1 = OpTypeVoid", 1, "void"}, - {"%1 = OpTypeBool", 1, "bool"}, - {"%1 = OpTypeInt 8 0", 1, "uchar"}, - {"%1 = OpTypeInt 8 1", 1, "char"}, - {"%1 = OpTypeInt 16 0", 1, "ushort"}, - {"%1 = OpTypeInt 16 1", 1, "short"}, - {"%1 = OpTypeInt 32 0", 1, "uint"}, - {"%1 = OpTypeInt 32 1", 1, "int"}, - {"%1 = OpTypeInt 64 0", 1, "ulong"}, - {"%1 = OpTypeInt 64 1", 1, "long"}, - {"%1 = OpTypeInt 1 0", 1, "u1"}, - {"%1 = OpTypeInt 1 1", 1, "i1"}, - {"%1 = OpTypeInt 33 0", 1, "u33"}, - {"%1 = OpTypeInt 33 1", 1, "i33"}, +INSTANTIATE_TEST_SUITE_P(ScalarType, FriendlyNameTest, + ::testing::ValuesIn(std::vector{ + {"%1 = OpTypeVoid", 1, "void"}, + {"%1 = OpTypeBool", 1, "bool"}, + {"%1 = OpTypeInt 8 0", 1, "uchar"}, + {"%1 = OpTypeInt 8 1", 1, "char"}, + {"%1 = OpTypeInt 16 0", 1, "ushort"}, + {"%1 = OpTypeInt 16 1", 1, "short"}, + {"%1 = OpTypeInt 32 0", 1, "uint"}, + {"%1 = OpTypeInt 32 1", 1, "int"}, + {"%1 = OpTypeInt 64 0", 1, "ulong"}, + {"%1 = OpTypeInt 64 1", 1, "long"}, + {"%1 = OpTypeInt 1 0", 1, "u1"}, + {"%1 = OpTypeInt 1 1", 1, "i1"}, + {"%1 = OpTypeInt 33 0", 1, "u33"}, + {"%1 = OpTypeInt 33 1", 1, "i33"}, - {"%1 = OpTypeFloat 16", 1, "half"}, - {"%1 = OpTypeFloat 32", 1, "float"}, - {"%1 = OpTypeFloat 64", 1, "double"}, - {"%1 = OpTypeFloat 10", 1, "fp10"}, - {"%1 = OpTypeFloat 55", 1, "fp55"}, - }), ); + {"%1 = OpTypeFloat 16", 1, "half"}, + {"%1 = OpTypeFloat 32", 1, "float"}, + {"%1 = OpTypeFloat 64", 1, "double"}, + {"%1 = OpTypeFloat 10", 1, "fp10"}, + {"%1 = OpTypeFloat 55", 1, "fp55"}, + })); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( VectorType, FriendlyNameTest, ::testing::ValuesIn(std::vector{ {"%1 = OpTypeBool %2 = OpTypeVector %1 1", 2, "v1bool"}, @@ -97,9 +97,9 @@ INSTANTIATE_TEST_CASE_P( // OpName overrides the element name. {"OpName %1 \"time\" %1 = OpTypeFloat 32 %2 = OpTypeVector %1 2", 2, "v2time"}, - }), ); + })); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( MatrixType, FriendlyNameTest, ::testing::ValuesIn(std::vector{ {"%1 = OpTypeBool %2 = OpTypeVector %1 2 %3 = OpTypeMatrix %2 2", 3, @@ -114,9 +114,9 @@ INSTANTIATE_TEST_CASE_P( {"OpName %2 \"lat_long\" %1 = OpTypeFloat 32 %2 = OpTypeVector %1 2 %3 " "= OpTypeMatrix %2 4", 3, "mat4lat_long"}, - }), ); + })); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( OpName, FriendlyNameTest, ::testing::ValuesIn(std::vector{ {"OpName %1 \"abcdefg\"", 1, "abcdefg"}, @@ -146,38 +146,38 @@ INSTANTIATE_TEST_CASE_P( // OpName can override other inferences. We assume valid instruction // ordering, where OpName precedes type definitions. {"OpName %1 \"myfloat\" %1 = OpTypeFloat 32", 1, "myfloat"}, - }), ); + })); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( UniquenessHeuristic, FriendlyNameTest, ::testing::ValuesIn(std::vector{ {"%1 = OpTypeVoid %2 = OpTypeVoid %3 = OpTypeVoid", 1, "void"}, {"%1 = OpTypeVoid %2 = OpTypeVoid %3 = OpTypeVoid", 2, "void_0"}, {"%1 = OpTypeVoid %2 = OpTypeVoid %3 = OpTypeVoid", 3, "void_1"}, - }), ); + })); -INSTANTIATE_TEST_CASE_P(Arrays, FriendlyNameTest, - ::testing::ValuesIn(std::vector{ - {"OpName %2 \"FortyTwo\" %1 = OpTypeFloat 32 " - "%2 = OpConstant %1 42 %3 = OpTypeArray %1 %2", - 3, "_arr_float_FortyTwo"}, - {"%1 = OpTypeInt 32 0 " - "%2 = OpTypeRuntimeArray %1", - 2, "_runtimearr_uint"}, - }), ); +INSTANTIATE_TEST_SUITE_P(Arrays, FriendlyNameTest, + ::testing::ValuesIn(std::vector{ + {"OpName %2 \"FortyTwo\" %1 = OpTypeFloat 32 " + "%2 = OpConstant %1 42 %3 = OpTypeArray %1 %2", + 3, "_arr_float_FortyTwo"}, + {"%1 = OpTypeInt 32 0 " + "%2 = OpTypeRuntimeArray %1", + 2, "_runtimearr_uint"}, + })); -INSTANTIATE_TEST_CASE_P(Structs, FriendlyNameTest, - ::testing::ValuesIn(std::vector{ - {"%1 = OpTypeBool " - "%2 = OpTypeStruct %1 %1 %1", - 2, "_struct_2"}, - {"%1 = OpTypeBool " - "%2 = OpTypeStruct %1 %1 %1 " - "%3 = OpTypeStruct %2 %2", - 3, "_struct_3"}, - }), ); +INSTANTIATE_TEST_SUITE_P(Structs, FriendlyNameTest, + ::testing::ValuesIn(std::vector{ + {"%1 = OpTypeBool " + "%2 = OpTypeStruct %1 %1 %1", + 2, "_struct_2"}, + {"%1 = OpTypeBool " + "%2 = OpTypeStruct %1 %1 %1 " + "%3 = OpTypeStruct %2 %2", + 3, "_struct_3"}, + })); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( Pointer, FriendlyNameTest, ::testing::ValuesIn(std::vector{ {"%1 = OpTypeFloat 32 %2 = OpTypePointer Workgroup %1", 2, @@ -189,22 +189,22 @@ INSTANTIATE_TEST_CASE_P( {"%1 = OpTypeBool OpTypeForwardPointer %2 Private %2 = OpTypePointer " "Private %1", 2, "_ptr_Private_bool"}, - }), ); + })); -INSTANTIATE_TEST_CASE_P(ExoticTypes, FriendlyNameTest, - ::testing::ValuesIn(std::vector{ - {"%1 = OpTypeEvent", 1, "Event"}, - {"%1 = OpTypeDeviceEvent", 1, "DeviceEvent"}, - {"%1 = OpTypeReserveId", 1, "ReserveId"}, - {"%1 = OpTypeQueue", 1, "Queue"}, - {"%1 = OpTypeOpaque \"hello world!\"", 1, - "Opaque_hello_world_"}, - {"%1 = OpTypePipe ReadOnly", 1, "PipeReadOnly"}, - {"%1 = OpTypePipe WriteOnly", 1, "PipeWriteOnly"}, - {"%1 = OpTypePipe ReadWrite", 1, "PipeReadWrite"}, - {"%1 = OpTypePipeStorage", 1, "PipeStorage"}, - {"%1 = OpTypeNamedBarrier", 1, "NamedBarrier"}, - }), ); +INSTANTIATE_TEST_SUITE_P(ExoticTypes, FriendlyNameTest, + ::testing::ValuesIn(std::vector{ + {"%1 = OpTypeEvent", 1, "Event"}, + {"%1 = OpTypeDeviceEvent", 1, "DeviceEvent"}, + {"%1 = OpTypeReserveId", 1, "ReserveId"}, + {"%1 = OpTypeQueue", 1, "Queue"}, + {"%1 = OpTypeOpaque \"hello world!\"", 1, + "Opaque_hello_world_"}, + {"%1 = OpTypePipe ReadOnly", 1, "PipeReadOnly"}, + {"%1 = OpTypePipe WriteOnly", 1, "PipeWriteOnly"}, + {"%1 = OpTypePipe ReadWrite", 1, "PipeReadWrite"}, + {"%1 = OpTypePipeStorage", 1, "PipeStorage"}, + {"%1 = OpTypeNamedBarrier", 1, "NamedBarrier"}, + })); // Makes a test case for a BuiltIn variable declaration. NameIdCase BuiltInCase(std::string assembly_name, std::string expected) { @@ -226,7 +226,7 @@ NameIdCase BuiltInGLCase(std::string assembly_name) { return BuiltInCase(assembly_name, std::string("gl_") + assembly_name); } -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( BuiltIns, FriendlyNameTest, ::testing::ValuesIn(std::vector{ BuiltInGLCase("Position"), @@ -275,15 +275,15 @@ INSTANTIATE_TEST_CASE_P( BuiltInCase("SubgroupGtMaskKHR"), BuiltInCase("SubgroupLeMaskKHR"), BuiltInCase("SubgroupLtMaskKHR"), - }), ); + })); -INSTANTIATE_TEST_CASE_P(DebugNameOverridesBuiltin, FriendlyNameTest, - ::testing::ValuesIn(std::vector{ - {"OpName %1 \"foo\" OpDecorate %1 BuiltIn WorkDim " - "%1 = OpVariable %2 Input", - 1, "foo"}}), ); +INSTANTIATE_TEST_SUITE_P(DebugNameOverridesBuiltin, FriendlyNameTest, + ::testing::ValuesIn(std::vector{ + {"OpName %1 \"foo\" OpDecorate %1 BuiltIn WorkDim " + "%1 = OpVariable %2 Input", + 1, "foo"}})); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SimpleIntegralConstants, FriendlyNameTest, ::testing::ValuesIn(std::vector{ {"%1 = OpTypeInt 32 0 %2 = OpConstant %1 0", 2, "uint_0"}, @@ -301,9 +301,9 @@ INSTANTIATE_TEST_CASE_P( {"%1 = OpTypeInt 33 0 %2 = OpConstant %1 0", 2, "u33_0"}, {"%1 = OpTypeInt 33 1 %2 = OpConstant %1 10", 2, "i33_10"}, {"%1 = OpTypeInt 33 1 %2 = OpConstant %1 -19", 2, "i33_n19"}, - }), ); + })); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SimpleFloatConstants, FriendlyNameTest, ::testing::ValuesIn(std::vector{ {"%1 = OpTypeFloat 16\n%2 = OpConstant %1 0x1.ff4p+16", 2, @@ -334,14 +334,14 @@ INSTANTIATE_TEST_CASE_P( "double_0x1p_1024"}, // Inf {"%1 = OpTypeFloat 64\n%2 = OpConstant %1 -0x1p+1024", 2, "double_n0x1p_1024"}, // -Inf - }), ); + })); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( BooleanConstants, FriendlyNameTest, ::testing::ValuesIn(std::vector{ {"%1 = OpTypeBool\n%2 = OpConstantTrue %1", 2, "true"}, {"%1 = OpTypeBool\n%2 = OpConstantFalse %1", 2, "false"}, - }), ); + })); } // namespace } // namespace spvtools diff --git a/third_party/spirv-tools/test/named_id_test.cpp b/third_party/spirv-tools/test/named_id_test.cpp index 4ba54adc3a..01f09be5d3 100644 --- a/third_party/spirv-tools/test/named_id_test.cpp +++ b/third_party/spirv-tools/test/named_id_test.cpp @@ -65,7 +65,7 @@ TEST_P(IdValidityTest, IdTypes) { } } -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( ValidAndInvalidIds, IdValidityTest, ::testing::ValuesIn(std::vector( {{"%1", true}, {"%2abc", true}, {"%3Def", true}, @@ -81,7 +81,7 @@ INSTANTIATE_TEST_CASE_P( {"%foo_@_bar", false}, {"%", false}, {"5", false}, {"32", false}, {"foo", false}, - {"a%bar", false}})), ); + {"a%bar", false}}))); } // namespace } // namespace spvtools diff --git a/third_party/spirv-tools/test/opcode_require_capabilities_test.cpp b/third_party/spirv-tools/test/opcode_require_capabilities_test.cpp index 32bf1dc085..07e86f87b3 100644 --- a/third_party/spirv-tools/test/opcode_require_capabilities_test.cpp +++ b/third_party/spirv-tools/test/opcode_require_capabilities_test.cpp @@ -42,7 +42,7 @@ TEST_P(OpcodeTableCapabilitiesTest, TableEntryMatchesExpectedCapabilities) { ElementsIn(CapabilitySet(entry->numCapabilities, entry->capabilities))); } -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( TableRowTest, OpcodeTableCapabilitiesTest, // Spot-check a few opcodes. ::testing::Values( @@ -72,7 +72,7 @@ INSTANTIATE_TEST_CASE_P( CapabilitySet{SpvCapabilityNamedBarrier}}, ExpectedOpCodeCapabilities{ SpvOpGetKernelMaxNumSubgroups, - CapabilitySet{SpvCapabilitySubgroupDispatch}}), ); + CapabilitySet{SpvCapabilitySubgroupDispatch}})); } // namespace } // namespace spvtools diff --git a/third_party/spirv-tools/test/opcode_table_get_test.cpp b/third_party/spirv-tools/test/opcode_table_get_test.cpp index 6f80ad7d8c..5ebd6c113d 100644 --- a/third_party/spirv-tools/test/opcode_table_get_test.cpp +++ b/third_party/spirv-tools/test/opcode_table_get_test.cpp @@ -32,8 +32,8 @@ TEST_P(GetTargetOpcodeTableGetTest, InvalidPointerTable) { ASSERT_EQ(SPV_ERROR_INVALID_POINTER, spvOpcodeTableGet(nullptr, GetParam())); } -INSTANTIATE_TEST_CASE_P(OpcodeTableGet, GetTargetOpcodeTableGetTest, - ValuesIn(spvtest::AllTargetEnvironments())); +INSTANTIATE_TEST_SUITE_P(OpcodeTableGet, GetTargetOpcodeTableGetTest, + ValuesIn(spvtest::AllTargetEnvironments())); } // namespace } // namespace spvtools diff --git a/third_party/spirv-tools/test/operand_capabilities_test.cpp b/third_party/spirv-tools/test/operand_capabilities_test.cpp index 0aeb505f0c..11955970ea 100644 --- a/third_party/spirv-tools/test/operand_capabilities_test.cpp +++ b/third_party/spirv-tools/test/operand_capabilities_test.cpp @@ -91,7 +91,7 @@ TEST_P(EnumCapabilityTest, Sample) { } // See SPIR-V Section 3.3 Execution Model -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( ExecutionModel, EnumCapabilityTest, Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1), ValuesIn(std::vector{ @@ -104,30 +104,30 @@ INSTANTIATE_TEST_CASE_P( CASE1(EXECUTION_MODEL, ExecutionModelFragment, Shader), CASE1(EXECUTION_MODEL, ExecutionModelGLCompute, Shader), CASE1(EXECUTION_MODEL, ExecutionModelKernel, Kernel), - })), ); + }))); // See SPIR-V Section 3.4 Addressing Model -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( AddressingModel, EnumCapabilityTest, Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1), ValuesIn(std::vector{ CASE0(ADDRESSING_MODEL, AddressingModelLogical), CASE1(ADDRESSING_MODEL, AddressingModelPhysical32, Addresses), CASE1(ADDRESSING_MODEL, AddressingModelPhysical64, Addresses), - })), ); + }))); // See SPIR-V Section 3.5 Memory Model -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( MemoryModel, EnumCapabilityTest, Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1), ValuesIn(std::vector{ CASE1(MEMORY_MODEL, MemoryModelSimple, Shader), CASE1(MEMORY_MODEL, MemoryModelGLSL450, Shader), CASE1(MEMORY_MODEL, MemoryModelOpenCL, Kernel), - })), ); + }))); // See SPIR-V Section 3.6 Execution Mode -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( ExecutionMode, EnumCapabilityTest, Combine( Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1), @@ -161,16 +161,17 @@ INSTANTIATE_TEST_CASE_P( Geometry), CASE1(EXECUTION_MODE, ExecutionModeQuads, Tessellation), CASE1(EXECUTION_MODE, ExecutionModeIsolines, Tessellation), - CASE2(EXECUTION_MODE, ExecutionModeOutputVertices, Geometry, - Tessellation), - CASE1(EXECUTION_MODE, ExecutionModeOutputPoints, Geometry), + CASE3(EXECUTION_MODE, ExecutionModeOutputVertices, Geometry, + Tessellation, MeshShadingNV), + CASE2(EXECUTION_MODE, ExecutionModeOutputPoints, Geometry, + MeshShadingNV), CASE1(EXECUTION_MODE, ExecutionModeOutputLineStrip, Geometry), CASE1(EXECUTION_MODE, ExecutionModeOutputTriangleStrip, Geometry), CASE1(EXECUTION_MODE, ExecutionModeVecTypeHint, Kernel), CASE1(EXECUTION_MODE, ExecutionModeContractionOff, Kernel), - })), ); + }))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( ExecutionModeV11, EnumCapabilityTest, Combine(Values(SPV_ENV_UNIVERSAL_1_1), ValuesIn(std::vector{ @@ -179,10 +180,10 @@ INSTANTIATE_TEST_CASE_P( CASE1(EXECUTION_MODE, ExecutionModeSubgroupSize, SubgroupDispatch), CASE1(EXECUTION_MODE, ExecutionModeSubgroupsPerWorkgroup, - SubgroupDispatch)})), ); + SubgroupDispatch)}))); // See SPIR-V Section 3.7 Storage Class -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( StorageClass, EnumCapabilityTest, Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1), ValuesIn(std::vector{ @@ -198,24 +199,24 @@ INSTANTIATE_TEST_CASE_P( CASE1(STORAGE_CLASS, StorageClassPushConstant, Shader), CASE1(STORAGE_CLASS, StorageClassAtomicCounter, AtomicStorage), CASE0(STORAGE_CLASS, StorageClassImage), - })), ); + }))); // See SPIR-V Section 3.8 Dim -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( Dim, EnumCapabilityTest, Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1), ValuesIn(std::vector{ - CASE1(DIMENSIONALITY, Dim1D, Sampled1D), - CASE0(DIMENSIONALITY, Dim2D), + CASE2(DIMENSIONALITY, Dim1D, Sampled1D, Image1D), + CASE3(DIMENSIONALITY, Dim2D, Kernel, Shader, ImageMSArray), CASE0(DIMENSIONALITY, Dim3D), - CASE1(DIMENSIONALITY, DimCube, Shader), - CASE1(DIMENSIONALITY, DimRect, SampledRect), - CASE1(DIMENSIONALITY, DimBuffer, SampledBuffer), + CASE2(DIMENSIONALITY, DimCube, Shader, ImageCubeArray), + CASE2(DIMENSIONALITY, DimRect, SampledRect, ImageRect), + CASE2(DIMENSIONALITY, DimBuffer, SampledBuffer, ImageBuffer), CASE1(DIMENSIONALITY, DimSubpassData, InputAttachment), - })), ); + }))); // See SPIR-V Section 3.9 Sampler Addressing Mode -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SamplerAddressingMode, EnumCapabilityTest, Combine( Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1), @@ -227,19 +228,19 @@ INSTANTIATE_TEST_CASE_P( CASE1(SAMPLER_ADDRESSING_MODE, SamplerAddressingModeRepeat, Kernel), CASE1(SAMPLER_ADDRESSING_MODE, SamplerAddressingModeRepeatMirrored, Kernel), - })), ); + }))); // See SPIR-V Section 3.10 Sampler Filter Mode -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SamplerFilterMode, EnumCapabilityTest, Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1), ValuesIn(std::vector{ CASE1(SAMPLER_FILTER_MODE, SamplerFilterModeNearest, Kernel), CASE1(SAMPLER_FILTER_MODE, SamplerFilterModeLinear, Kernel), - })), ); + }))); // See SPIR-V Section 3.11 Image Format -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( ImageFormat, EnumCapabilityTest, Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1), ValuesIn(std::vector{ @@ -285,10 +286,10 @@ INSTANTIATE_TEST_CASE_P( CASE1(SAMPLER_IMAGE_FORMAT, ImageFormatR16ui, StorageImageExtendedFormats), CASE1(SAMPLER_IMAGE_FORMAT, ImageFormatR8ui, StorageImageExtendedFormats), // clang-format on - })), ); + }))); // See SPIR-V Section 3.12 Image Channel Order -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( ImageChannelOrder, EnumCapabilityTest, Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1), ValuesIn(std::vector{ @@ -313,10 +314,10 @@ INSTANTIATE_TEST_CASE_P( CASE1(IMAGE_CHANNEL_ORDER, ImageChannelOrdersRGBA, Kernel), CASE1(IMAGE_CHANNEL_ORDER, ImageChannelOrdersBGRA, Kernel), CASE1(IMAGE_CHANNEL_ORDER, ImageChannelOrderABGR, Kernel), - })), ); + }))); // See SPIR-V Section 3.13 Image Channel Data Type -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( ImageChannelDataType, EnumCapabilityTest, Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1), ValuesIn(std::vector{ @@ -339,10 +340,10 @@ INSTANTIATE_TEST_CASE_P( CASE1(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataTypeUnormInt24, Kernel), CASE1(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataTypeUnormInt101010_2, Kernel), // clang-format on - })), ); + }))); // See SPIR-V Section 3.14 Image Operands -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( ImageOperands, EnumCapabilityTest, Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1), ValuesIn(std::vector{ @@ -357,10 +358,10 @@ INSTANTIATE_TEST_CASE_P( CASE0(OPTIONAL_IMAGE, ImageOperandsSampleMask), CASE1(OPTIONAL_IMAGE, ImageOperandsMinLodMask, MinLod), // clang-format on - })), ); + }))); // See SPIR-V Section 3.15 FP Fast Math Mode -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( FPFastMathMode, EnumCapabilityTest, Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1), ValuesIn(std::vector{ @@ -370,29 +371,29 @@ INSTANTIATE_TEST_CASE_P( CASE1(FP_FAST_MATH_MODE, FPFastMathModeNSZMask, Kernel), CASE1(FP_FAST_MATH_MODE, FPFastMathModeAllowRecipMask, Kernel), CASE1(FP_FAST_MATH_MODE, FPFastMathModeFastMask, Kernel), - })), ); + }))); // See SPIR-V Section 3.17 Linkage Type -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( LinkageType, EnumCapabilityTest, Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1), ValuesIn(std::vector{ CASE1(LINKAGE_TYPE, LinkageTypeExport, Linkage), CASE1(LINKAGE_TYPE, LinkageTypeImport, Linkage), - })), ); + }))); // See SPIR-V Section 3.18 Access Qualifier -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( AccessQualifier, EnumCapabilityTest, Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1), ValuesIn(std::vector{ CASE1(ACCESS_QUALIFIER, AccessQualifierReadOnly, Kernel), CASE1(ACCESS_QUALIFIER, AccessQualifierWriteOnly, Kernel), CASE1(ACCESS_QUALIFIER, AccessQualifierReadWrite, Kernel), - })), ); + }))); // See SPIR-V Section 3.19 Function Parameter Attribute -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( FunctionParameterAttribute, EnumCapabilityTest, Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1), ValuesIn(std::vector{ @@ -406,10 +407,10 @@ INSTANTIATE_TEST_CASE_P( CASE1(FUNCTION_PARAMETER_ATTRIBUTE, FunctionParameterAttributeNoWrite, Kernel), CASE1(FUNCTION_PARAMETER_ATTRIBUTE, FunctionParameterAttributeNoReadWrite, Kernel), // clang-format on - })), ); + }))); // See SPIR-V Section 3.20 Decoration -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( Decoration, EnumCapabilityTest, Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1), ValuesIn(std::vector{ @@ -459,25 +460,25 @@ INSTANTIATE_TEST_CASE_P( CASE1(DECORATION, DecorationInputAttachmentIndex, InputAttachment), CASE1(DECORATION, DecorationAlignment, Kernel), - })), ); + }))); #if 0 // SpecId has different requirements in v1.0 and v1.1: -INSTANTIATE_TEST_CASE_P(DecorationSpecIdV10, EnumCapabilityTest, +INSTANTIATE_TEST_SUITE_P(DecorationSpecIdV10, EnumCapabilityTest, Combine(Values(SPV_ENV_UNIVERSAL_1_0), ValuesIn(std::vector{CASE1( - DECORATION, DecorationSpecId, Shader)})), ); + DECORATION, DecorationSpecId, Shader)}))); #endif -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( DecorationV11, EnumCapabilityTest, Combine(Values(SPV_ENV_UNIVERSAL_1_1), ValuesIn(std::vector{ CASE2(DECORATION, DecorationSpecId, Shader, Kernel), - CASE1(DECORATION, DecorationMaxByteOffset, Addresses)})), ); + CASE1(DECORATION, DecorationMaxByteOffset, Addresses)}))); // See SPIR-V Section 3.21 BuiltIn -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( BuiltIn, EnumCapabilityTest, Combine( Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1), @@ -490,10 +491,11 @@ INSTANTIATE_TEST_CASE_P( CASE1(BUILT_IN, BuiltInCullDistance, CullDistance), // Bug 1407, 15234 CASE1(BUILT_IN, BuiltInVertexId, Shader), CASE1(BUILT_IN, BuiltInInstanceId, Shader), - CASE2(BUILT_IN, BuiltInPrimitiveId, Geometry, Tessellation), + CASE3(BUILT_IN, BuiltInPrimitiveId, Geometry, Tessellation, + RayTracingNV), CASE2(BUILT_IN, BuiltInInvocationId, Geometry, Tessellation), - CASE1(BUILT_IN, BuiltInLayer, Geometry), - CASE1(BUILT_IN, BuiltInViewportIndex, MultiViewport), // Bug 15234 + CASE2(BUILT_IN, BuiltInLayer, Geometry, ShaderViewportIndexLayerEXT), + CASE2(BUILT_IN, BuiltInViewportIndex, MultiViewport, ShaderViewportIndexLayerEXT), // Bug 15234 CASE1(BUILT_IN, BuiltInTessLevelOuter, Tessellation), CASE1(BUILT_IN, BuiltInTessLevelInner, Tessellation), CASE1(BUILT_IN, BuiltInTessCoord, Tessellation), @@ -528,38 +530,50 @@ INSTANTIATE_TEST_CASE_P( CASE1(BUILT_IN, BuiltInVertexIndex, Shader), CASE1(BUILT_IN, BuiltInInstanceIndex, Shader), // clang-format on - })), ); + }))); + +INSTANTIATE_TEST_SUITE_P( + BuiltInV1_5, EnumCapabilityTest, + Combine( + Values(SPV_ENV_UNIVERSAL_1_5), + ValuesIn(std::vector{ + // SPIR-V 1.5 adds new capabilities to enable these two builtins. + CASE3(BUILT_IN, BuiltInLayer, Geometry, ShaderLayer, + ShaderViewportIndexLayerEXT), + CASE3(BUILT_IN, BuiltInViewportIndex, MultiViewport, + ShaderViewportIndex, ShaderViewportIndexLayerEXT), + }))); // See SPIR-V Section 3.22 Selection Control -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SelectionControl, EnumCapabilityTest, Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1), ValuesIn(std::vector{ CASE0(SELECTION_CONTROL, SelectionControlMaskNone), CASE0(SELECTION_CONTROL, SelectionControlFlattenMask), CASE0(SELECTION_CONTROL, SelectionControlDontFlattenMask), - })), ); + }))); // See SPIR-V Section 3.23 Loop Control -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( LoopControl, EnumCapabilityTest, Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1), ValuesIn(std::vector{ CASE0(LOOP_CONTROL, LoopControlMaskNone), CASE0(LOOP_CONTROL, LoopControlUnrollMask), CASE0(LOOP_CONTROL, LoopControlDontUnrollMask), - })), ); + }))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( LoopControlV11, EnumCapabilityTest, Combine(Values(SPV_ENV_UNIVERSAL_1_1), ValuesIn(std::vector{ CASE0(LOOP_CONTROL, LoopControlDependencyInfiniteMask), CASE0(LOOP_CONTROL, LoopControlDependencyLengthMask), - })), ); + }))); // See SPIR-V Section 3.24 Function Control -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( FunctionControl, EnumCapabilityTest, Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1), ValuesIn(std::vector{ @@ -568,10 +582,10 @@ INSTANTIATE_TEST_CASE_P( CASE0(FUNCTION_CONTROL, FunctionControlDontInlineMask), CASE0(FUNCTION_CONTROL, FunctionControlPureMask), CASE0(FUNCTION_CONTROL, FunctionControlConstMask), - })), ); + }))); // See SPIR-V Section 3.25 Memory Semantics -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( MemorySemantics, EnumCapabilityTest, Combine( Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1), @@ -590,10 +604,10 @@ INSTANTIATE_TEST_CASE_P( CASE1(MEMORY_SEMANTICS_ID, MemorySemanticsAtomicCounterMemoryMask, AtomicStorage), // Bug 15234 CASE0(MEMORY_SEMANTICS_ID, MemorySemanticsImageMemoryMask), - })), ); + }))); // See SPIR-V Section 3.26 Memory Access -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( MemoryAccess, EnumCapabilityTest, Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1), ValuesIn(std::vector{ @@ -601,22 +615,24 @@ INSTANTIATE_TEST_CASE_P( CASE0(OPTIONAL_MEMORY_ACCESS, MemoryAccessVolatileMask), CASE0(OPTIONAL_MEMORY_ACCESS, MemoryAccessAlignedMask), CASE0(OPTIONAL_MEMORY_ACCESS, MemoryAccessNontemporalMask), - })), ); + }))); // See SPIR-V Section 3.27 Scope -INSTANTIATE_TEST_CASE_P(Scope, EnumCapabilityTest, - Combine(Values(SPV_ENV_UNIVERSAL_1_0, - SPV_ENV_UNIVERSAL_1_1), - ValuesIn(std::vector{ - CASE0(SCOPE_ID, ScopeCrossDevice), - CASE0(SCOPE_ID, ScopeDevice), - CASE0(SCOPE_ID, ScopeWorkgroup), - CASE0(SCOPE_ID, ScopeSubgroup), - CASE0(SCOPE_ID, ScopeInvocation), - })), ); +INSTANTIATE_TEST_SUITE_P( + Scope, EnumCapabilityTest, + Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1, + SPV_ENV_UNIVERSAL_1_2, SPV_ENV_UNIVERSAL_1_3), + ValuesIn(std::vector{ + CASE0(SCOPE_ID, ScopeCrossDevice), + CASE0(SCOPE_ID, ScopeDevice), + CASE0(SCOPE_ID, ScopeWorkgroup), + CASE0(SCOPE_ID, ScopeSubgroup), + CASE0(SCOPE_ID, ScopeInvocation), + CASE1(SCOPE_ID, ScopeQueueFamilyKHR, VulkanMemoryModelKHR), + }))); // See SPIR-V Section 3.28 Group Operation -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( GroupOperation, EnumCapabilityTest, Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1), ValuesIn(std::vector{ @@ -626,10 +642,10 @@ INSTANTIATE_TEST_CASE_P( GroupNonUniformArithmetic, GroupNonUniformBallot), CASE3(GROUP_OPERATION, GroupOperationExclusiveScan, Kernel, GroupNonUniformArithmetic, GroupNonUniformBallot), - })), ); + }))); // See SPIR-V Section 3.29 Kernel Enqueue Flags -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( KernelEnqueueFlags, EnumCapabilityTest, Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1), ValuesIn(std::vector{ @@ -637,20 +653,20 @@ INSTANTIATE_TEST_CASE_P( CASE1(KERNEL_ENQ_FLAGS, KernelEnqueueFlagsWaitKernel, Kernel), CASE1(KERNEL_ENQ_FLAGS, KernelEnqueueFlagsWaitWorkGroup, Kernel), - })), ); + }))); // See SPIR-V Section 3.30 Kernel Profiling Info -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( KernelProfilingInfo, EnumCapabilityTest, Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1), ValuesIn(std::vector{ CASE0(KERNEL_PROFILING_INFO, KernelProfilingInfoMaskNone), CASE1(KERNEL_PROFILING_INFO, KernelProfilingInfoCmdExecTimeMask, Kernel), - })), ); + }))); // See SPIR-V Section 3.31 Capability -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( CapabilityDependsOn, EnumCapabilityTest, Combine( Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1), @@ -713,16 +729,16 @@ INSTANTIATE_TEST_CASE_P( CASE1(CAPABILITY, CapabilityStorageImageWriteWithoutFormat, Shader), CASE1(CAPABILITY, CapabilityMultiViewport, Geometry), // clang-format on - })), ); + }))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( CapabilityDependsOnV11, EnumCapabilityTest, Combine(Values(SPV_ENV_UNIVERSAL_1_1), ValuesIn(std::vector{ CASE1(CAPABILITY, CapabilitySubgroupDispatch, DeviceEnqueue), CASE1(CAPABILITY, CapabilityNamedBarrier, Kernel), CASE1(CAPABILITY, CapabilityPipeStorage, Pipes), - })), ); + }))); #undef CASE0 #undef CASE1 diff --git a/third_party/spirv-tools/test/operand_pattern_test.cpp b/third_party/spirv-tools/test/operand_pattern_test.cpp index b3e3024908..1caf008fb3 100644 --- a/third_party/spirv-tools/test/operand_pattern_test.cpp +++ b/third_party/spirv-tools/test/operand_pattern_test.cpp @@ -84,14 +84,16 @@ TEST_P(MaskExpansionTest, Sample) { #define PREFIX1 \ SPV_OPERAND_TYPE_STORAGE_CLASS, SPV_OPERAND_TYPE_SAMPLER_FILTER_MODE, \ SPV_OPERAND_TYPE_ID -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( OperandPattern, MaskExpansionTest, ::testing::ValuesIn(std::vector{ // No bits means no change. {SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS, 0, {PREFIX0}, {PREFIX0}}, - // Unknown bits means no change. + // Unknown bits means no change. Use all bits that aren't in the + // grammar. + // The last mask enum is 0x20 {SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS, - 0xfffffffc, + 0xffffffc0, {PREFIX1}, {PREFIX1}}, // Volatile has no operands. @@ -109,7 +111,7 @@ INSTANTIATE_TEST_CASE_P( SpvMemoryAccessVolatileMask | SpvMemoryAccessAlignedMask, {PREFIX1}, {PREFIX1, SPV_OPERAND_TYPE_LITERAL_INTEGER}}, - }), ); + })); #undef PREFIX0 #undef PREFIX1 @@ -135,9 +137,9 @@ TEST_P(MatchableOperandExpansionTest, MatchableOperandsDontExpand) { } } -INSTANTIATE_TEST_CASE_P(MatchableOperandExpansion, - MatchableOperandExpansionTest, - ::testing::ValuesIn(allOperandTypes()), ); +INSTANTIATE_TEST_SUITE_P(MatchableOperandExpansion, + MatchableOperandExpansionTest, + ::testing::ValuesIn(allOperandTypes())); using VariableOperandExpansionTest = ::testing::TestWithParam; @@ -155,9 +157,9 @@ TEST_P(VariableOperandExpansionTest, NonMatchableOperandsExpand) { } } -INSTANTIATE_TEST_CASE_P(NonMatchableOperandExpansion, - VariableOperandExpansionTest, - ::testing::ValuesIn(allOperandTypes()), ); +INSTANTIATE_TEST_SUITE_P(NonMatchableOperandExpansion, + VariableOperandExpansionTest, + ::testing::ValuesIn(allOperandTypes())); TEST(AlternatePatternFollowingImmediate, Empty) { EXPECT_THAT(spvAlternatePatternFollowingImmediate({}), diff --git a/third_party/spirv-tools/test/operand_test.cpp b/third_party/spirv-tools/test/operand_test.cpp index 08522c323e..4e2c3215b4 100644 --- a/third_party/spirv-tools/test/operand_test.cpp +++ b/third_party/spirv-tools/test/operand_test.cpp @@ -33,10 +33,10 @@ TEST_P(GetTargetTest, InvalidPointerTable) { ASSERT_EQ(SPV_ERROR_INVALID_POINTER, spvOperandTableGet(nullptr, GetParam())); } -INSTANTIATE_TEST_CASE_P(OperandTableGet, GetTargetTest, - ValuesIn(std::vector{ - SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1, - SPV_ENV_VULKAN_1_0}), ); +INSTANTIATE_TEST_SUITE_P(OperandTableGet, GetTargetTest, + ValuesIn(std::vector{ + SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1, + SPV_ENV_VULKAN_1_0})); TEST(OperandString, AllAreDefinedExceptVariable) { // None has no string, so don't test it. diff --git a/third_party/spirv-tools/test/opt/CMakeLists.txt b/third_party/spirv-tools/test/opt/CMakeLists.txt index f2741f6735..327f265632 100644 --- a/third_party/spirv-tools/test/opt/CMakeLists.txt +++ b/third_party/spirv-tools/test/opt/CMakeLists.txt @@ -15,325 +15,93 @@ add_subdirectory(dominator_tree) add_subdirectory(loop_optimizations) -add_spvtools_unittest(TARGET instruction - SRCS instruction_test.cpp - LIBS SPIRV-Tools-opt -) - -add_spvtools_unittest(TARGET instruction_list - SRCS instruction_list_test.cpp - LIBS SPIRV-Tools-opt -) - -add_spvtools_unittest(TARGET ir_loader - SRCS ir_loader_test.cpp - LIBS SPIRV-Tools-opt -) - -add_spvtools_unittest(TARGET pass_manager - SRCS module_utils.h - pass_manager_test.cpp - LIBS SPIRV-Tools-opt -) - -add_spvtools_unittest(TARGET optimizer - SRCS optimizer_test.cpp - LIBS SPIRV-Tools-opt -) - -add_spvtools_unittest(TARGET pass_strip_debug_info - SRCS strip_debug_info_test.cpp pass_utils.cpp - LIBS SPIRV-Tools-opt -) - -add_spvtools_unittest(TARGET pass_strip_reflect_info - SRCS strip_reflect_info_test.cpp pass_utils.cpp - LIBS SPIRV-Tools-opt -) - -add_spvtools_unittest(TARGET pass_compact_ids - SRCS compact_ids_test.cpp pass_utils.cpp - LIBS SPIRV-Tools-opt -) - -add_spvtools_unittest(TARGET pass_flatten_decoration - SRCS flatten_decoration_test.cpp pass_utils.cpp - LIBS SPIRV-Tools-opt -) - -add_spvtools_unittest(TARGET pass_freeze_spec_const - SRCS freeze_spec_const_test.cpp pass_utils.cpp - LIBS SPIRV-Tools-opt -) - -add_spvtools_unittest(TARGET pass_block_merge - SRCS block_merge_test.cpp pass_utils.cpp - LIBS SPIRV-Tools-opt -) - -add_spvtools_unittest(TARGET pass_inline - SRCS inline_test.cpp pass_utils.cpp - LIBS SPIRV-Tools-opt -) - -add_spvtools_unittest(TARGET pass_inline_opaque - SRCS inline_opaque_test.cpp pass_utils.cpp - LIBS SPIRV-Tools-opt -) - -add_spvtools_unittest(TARGET pass_insert_extract_elim - SRCS insert_extract_elim_test.cpp pass_utils.cpp - LIBS SPIRV-Tools-opt -) - -add_spvtools_unittest(TARGET pass_dead_insert_elim - SRCS dead_insert_elim_test.cpp pass_utils.cpp - LIBS SPIRV-Tools-opt -) - -add_spvtools_unittest(TARGET pass_local_ssa_elim - SRCS local_ssa_elim_test.cpp pass_utils.cpp - LIBS SPIRV-Tools-opt -) - -add_spvtools_unittest(TARGET pass_local_single_block_elim - SRCS local_single_block_elim.cpp pass_utils.cpp - LIBS SPIRV-Tools-opt -) - -add_spvtools_unittest(TARGET pass_local_access_chain_convert - SRCS local_access_chain_convert_test.cpp pass_utils.cpp - LIBS SPIRV-Tools-opt -) - -add_spvtools_unittest(TARGET pass_local_single_store_elim - SRCS local_single_store_elim_test.cpp pass_utils.cpp - LIBS SPIRV-Tools-opt -) - -add_spvtools_unittest(TARGET pass_dead_branch_elim - SRCS dead_branch_elim_test.cpp pass_utils.cpp - LIBS SPIRV-Tools-opt -) - -add_spvtools_unittest(TARGET pass_dead_variable_elim - SRCS dead_variable_elim_test.cpp pass_utils.cpp - LIBS SPIRV-Tools-opt -) - -add_spvtools_unittest(TARGET pass_aggressive_dce - SRCS aggressive_dead_code_elim_test.cpp pass_utils.cpp - LIBS SPIRV-Tools-opt -) - -add_spvtools_unittest(TARGET pass_common_uniform_elim - SRCS common_uniform_elim_test.cpp pass_utils.cpp - LIBS SPIRV-Tools-opt -) - -add_spvtools_unittest(TARGET pass_eliminate_dead_const - SRCS eliminate_dead_const_test.cpp pass_utils.cpp - LIBS SPIRV-Tools-opt -) - -add_spvtools_unittest(TARGET pass_eliminate_dead_functions - SRCS eliminate_dead_functions_test.cpp pass_utils.cpp - LIBS SPIRV-Tools-opt -) - -add_spvtools_unittest(TARGET pass_pass - SRCS pass_test.cpp pass_utils.cpp - LIBS SPIRV-Tools-opt -) - -add_spvtools_unittest(TARGET pass_utils - SRCS utils_test.cpp pass_utils.cpp - LIBS SPIRV-Tools-opt -) - -add_spvtools_unittest(TARGET def_use - SRCS def_use_test.cpp pass_utils.cpp - LIBS SPIRV-Tools-opt -) - -add_spvtools_unittest(TARGET assembly_builder - SRCS assembly_builder_test.cpp pass_utils.cpp - LIBS SPIRV-Tools-opt -) - -add_spvtools_unittest(TARGET types - SRCS types_test.cpp - LIBS SPIRV-Tools-opt -) - -add_spvtools_unittest(TARGET type_manager - SRCS type_manager_test.cpp - LIBS SPIRV-Tools-opt -) - -add_spvtools_unittest(TARGET iterator - SRCS iterator_test.cpp - LIBS SPIRV-Tools-opt -) - -add_spvtools_unittest(TARGET module - SRCS module_utils.h +add_spvtools_unittest(TARGET opt + SRCS aggressive_dead_code_elim_test.cpp + amd_ext_to_khr.cpp + assembly_builder_test.cpp + block_merge_test.cpp + ccp_test.cpp + cfg_cleanup_test.cpp + cfg_test.cpp + code_sink_test.cpp + combine_access_chains_test.cpp + compact_ids_test.cpp + constants_test.cpp + constant_manager_test.cpp + convert_relaxed_to_half_test.cpp + copy_prop_array_test.cpp + dead_branch_elim_test.cpp + dead_insert_elim_test.cpp + dead_variable_elim_test.cpp + decompose_initialized_variables_test.cpp + decoration_manager_test.cpp + def_use_test.cpp + desc_sroa_test.cpp + eliminate_dead_const_test.cpp + eliminate_dead_functions_test.cpp + eliminate_dead_member_test.cpp + feature_manager_test.cpp + fix_storage_class_test.cpp + flatten_decoration_test.cpp + fold_spec_const_op_composite_test.cpp + fold_test.cpp + freeze_spec_const_test.cpp + function_test.cpp + generate_webgpu_initializers_test.cpp + graphics_robust_access_test.cpp + if_conversion_test.cpp + inline_opaque_test.cpp + inline_test.cpp + insert_extract_elim_test.cpp + inst_bindless_check_test.cpp + inst_buff_addr_check_test.cpp + instruction_list_test.cpp + instruction_test.cpp + ir_builder.cpp + ir_context_test.cpp + ir_loader_test.cpp + iterator_test.cpp + legalize_vector_shuffle_test.cpp + line_debug_info_test.cpp + local_access_chain_convert_test.cpp + local_redundancy_elimination_test.cpp + local_single_block_elim.cpp + local_single_store_elim_test.cpp + local_ssa_elim_test.cpp module_test.cpp + module_utils.h + optimizer_test.cpp + pass_manager_test.cpp + pass_merge_return_test.cpp + pass_remove_duplicates_test.cpp + pass_utils.cpp + private_to_local_test.cpp + process_lines_test.cpp + propagator_test.cpp + reduce_load_size_test.cpp + redundancy_elimination_test.cpp + register_liveness.cpp + relax_float_ops_test.cpp + replace_invalid_opc_test.cpp + scalar_analysis.cpp + scalar_replacement_test.cpp + set_spec_const_default_value_test.cpp + simplification_test.cpp + split_invalid_unreachable_test.cpp + strength_reduction_test.cpp + strip_atomic_counter_memory_test.cpp + strip_debug_info_test.cpp + strip_reflect_info_test.cpp + struct_cfg_analysis_test.cpp + type_manager_test.cpp + types_test.cpp + unify_const_test.cpp + upgrade_memory_model_test.cpp + utils_test.cpp pass_utils.cpp + value_table_test.cpp + vector_dce_test.cpp + workaround1209_test.cpp + wrap_opkill_test.cpp LIBS SPIRV-Tools-opt + PCH_FILE pch_test_opt ) - -add_spvtools_unittest(TARGET pass_fold_spec_const_op_composite - SRCS fold_spec_const_op_composite_test.cpp pass_utils.cpp - LIBS SPIRV-Tools-opt -) - -add_spvtools_unittest(TARGET pass_unify_const - SRCS unify_const_test.cpp - LIBS SPIRV-Tools-opt -) - -add_spvtools_unittest(TARGET pass_set_spec_const_default_value - SRCS set_spec_const_default_value_test.cpp pass_utils.cpp - LIBS SPIRV-Tools-opt -) - -add_spvtools_unittest(TARGET line_debug_info - SRCS line_debug_info_test.cpp pass_utils.cpp - LIBS SPIRV-Tools-opt -) - -add_spvtools_unittest(TARGET pass_strength_reduction - SRCS strength_reduction_test.cpp pass_utils.cpp - LIBS SPIRV-Tools-opt -) - -add_spvtools_unittest(TARGET pass_scalar_replacement - SRCS scalar_replacement_test.cpp pass_utils.cpp - LIBS SPIRV-Tools-opt -) - -add_spvtools_unittest(TARGET cfg_cleanup - SRCS cfg_cleanup_test.cpp pass_utils.cpp - LIBS SPIRV-Tools-opt -) - -add_spvtools_unittest(TARGET ir_context - SRCS ir_context_test.cpp pass_utils.cpp - LIBS SPIRV-Tools-opt -) - -add_spvtools_unittest(TARGET feature_manager - SRCS feature_manager_test.cpp - LIBS SPIRV-Tools-opt -) - -add_spvtools_unittest(TARGET pass_merge_return - SRCS pass_merge_return_test.cpp pass_utils.cpp - LIBS SPIRV-Tools-opt -) - -add_spvtools_unittest(TARGET value_table - SRCS value_table_test.cpp pass_utils.cpp - LIBS SPIRV-Tools-opt -) - -add_spvtools_unittest(TARGET local_redundancy_elimination - SRCS local_redundancy_elimination_test.cpp pass_utils.cpp - LIBS SPIRV-Tools-opt -) - -add_spvtools_unittest(TARGET propagator - SRCS propagator_test.cpp - LIBS SPIRV-Tools-opt -) - -add_spvtools_unittest(TARGET redundancy_elimination - SRCS redundancy_elimination_test.cpp pass_utils.cpp - LIBS SPIRV-Tools-opt -) - -add_spvtools_unittest(TARGET private_to_local - SRCS private_to_local_test.cpp pass_utils.cpp - LIBS SPIRV-Tools-opt -) - -add_spvtools_unittest(TARGET decoration_manager - SRCS decoration_manager_test.cpp - LIBS SPIRV-Tools-opt -) - -add_spvtools_unittest(TARGET pass_remove_duplicates - SRCS pass_remove_duplicates_test.cpp - LIBS SPIRV-Tools-opt -) - -add_spvtools_unittest(TARGET ccp - SRCS ccp_test.cpp - LIBS SPIRV-Tools-opt -) - -add_spvtools_unittest(TARGET pass_workaround1209 - SRCS workaround1209_test.cpp pass_utils.cpp - LIBS SPIRV-Tools-opt -) - -add_spvtools_unittest(TARGET pass_if_conversion - SRCS if_conversion_test.cpp pass_utils.cpp - LIBS SPIRV-Tools-opt -) - -add_spvtools_unittest(TARGET ir_builder - SRCS ir_builder.cpp - LIBS SPIRV-Tools-opt -) - -add_spvtools_unittest(TARGET instruction_folding - SRCS fold_test.cpp pass_utils.cpp - LIBS SPIRV-Tools-opt -) - -add_spvtools_unittest(TARGET replace_invalid_opc - SRCS replace_invalid_opc_test.cpp pass_utils.cpp - LIBS SPIRV-Tools-opt -) - -add_spvtools_unittest(TARGET register_liveness - SRCS register_liveness.cpp - LIBS SPIRV-Tools-opt -) - -add_spvtools_unittest(TARGET simplification - SRCS simplification_test.cpp pass_utils.cpp - LIBS SPIRV-Tools-opt -) - -add_spvtools_unittest(TARGET copy_prop_array - SRCS copy_prop_array_test.cpp pass_utils.cpp - LIBS SPIRV-Tools-opt -) - -add_spvtools_unittest(TARGET scalar_analysis - SRCS scalar_analysis.cpp pass_utils.cpp - LIBS SPIRV-Tools-opt -) - -add_spvtools_unittest(TARGET vector_dce - SRCS vector_dce_test.cpp pass_utils.cpp - LIBS SPIRV-Tools-opt -) - -add_spvtools_unittest(TARGET reduce_load_size - SRCS reduce_load_size_test.cpp pass_utils.cpp - LIBS SPIRV-Tools-opt -) - -add_spvtools_unittest(TARGET constant_manager - SRCS constant_manager_test.cpp - LIBS SPIRV-Tools-opt -) - -add_spvtools_unittest(TARGET combine_access_chains - SRCS combine_access_chains_test.cpp - LIBS SPIRV-Tools-opt -) - diff --git a/third_party/spirv-tools/test/opt/aggressive_dead_code_elim_test.cpp b/third_party/spirv-tools/test/opt/aggressive_dead_code_elim_test.cpp index 287fcef0f6..e7303baab6 100644 --- a/third_party/spirv-tools/test/opt/aggressive_dead_code_elim_test.cpp +++ b/third_party/spirv-tools/test/opt/aggressive_dead_code_elim_test.cpp @@ -3597,6 +3597,8 @@ OpFunctionEnd SinglePassRunAndCheck(assembly, assembly, true, true); } +// This is not valid input and ADCE does not support variable pointers and only +// supports shaders. TEST_F(AggressiveDCETest, PointerVariable) { // ADCE is able to handle code that contains a load whose base address // comes from a load and not an OpVariable. I want to see an instruction @@ -3693,6 +3695,10 @@ OpReturn OpFunctionEnd )"; + // The input is not valid and ADCE only supports shaders, but not variable + // pointers. Workaround this by enabling relaxed logical pointers in the + // validator. + ValidatorOptions()->relax_logical_pointer = true; SinglePassRunAndCheck(before, after, true, true); } @@ -3805,7 +3811,7 @@ OpName %output "output" %6 = OpTypeFunction %void %float = OpTypeFloat 32 %_ptr_Private_float = OpTypePointer Private %float -%initializer = OpVariable %_ptr_Private_float Private +%initializer = OpConstant %float 0 %live = OpVariable %_ptr_Private_float Private %initializer %_ptr_Output_float = OpTypePointer Output %float %output = OpVariable %_ptr_Output_float Output @@ -3873,7 +3879,6 @@ OpFunctionEnd SinglePassRunAndCheck(before, after, true, true); } -#ifdef SPIRV_EFFCEE TEST_F(AggressiveDCETest, DeadNestedSwitch) { const std::string text = R"( ; CHECK: OpLabel @@ -3919,7 +3924,6 @@ OpFunctionEnd SinglePassRunAndMatch(text, true); } -#endif // SPIRV_EFFCEE TEST_F(AggressiveDCETest, LiveNestedSwitch) { const std::string text = R"(OpCapability Shader @@ -4095,7 +4099,6 @@ OpFunctionEnd /* skip_nop = */ true); } -#ifdef SPIRV_EFFCEE TEST_F(AggressiveDCETest, BasicAllDeadConstants) { const std::string text = R"( ; CHECK-NOT: OpConstant @@ -4126,7 +4129,6 @@ TEST_F(AggressiveDCETest, BasicAllDeadConstants) { SinglePassRunAndMatch(text, true); } -#endif // SPIRV_EFFCEE TEST_F(AggressiveDCETest, BasicNoneDeadConstants) { const std::vector text = { @@ -4184,7 +4186,7 @@ TEST_F(AggressiveDCETest, BasicNoneDeadConstants) { JoinAllInsts(text), JoinAllInsts(text), /* skip_nop = */ true); } -struct EliminateDeadConstantTestCase { +struct AggressiveEliminateDeadConstantTestCase { // Type declarations and constants that should be kept. std::vector used_consts; // Instructions that refer to constants, this is added to create uses for @@ -4196,7 +4198,8 @@ struct EliminateDeadConstantTestCase { std::vector checks; }; -// All types that are potentially required in EliminateDeadConstantTest. +// All types that are potentially required in +// AggressiveEliminateDeadConstantTest. const std::vector CommonTypes = { // clang-format off // scalar types @@ -4232,11 +4235,10 @@ const std::vector CommonTypes = { // clang-format on }; -using EliminateDeadConstantTest = - PassTest<::testing::TestWithParam>; +using AggressiveEliminateDeadConstantTest = + PassTest<::testing::TestWithParam>; -#ifdef SPIRV_EFFCEE -TEST_P(EliminateDeadConstantTest, Custom) { +TEST_P(AggressiveEliminateDeadConstantTest, Custom) { auto& tc = GetParam(); AssemblyBuilder builder; builder.AppendTypesConstantsGlobals(CommonTypes) @@ -4252,9 +4254,9 @@ TEST_P(EliminateDeadConstantTest, Custom) { SinglePassRunAndMatch(assembly_with_dead_const, false); } -INSTANTIATE_TEST_CASE_P( - ScalarTypeConstants, EliminateDeadConstantTest, - ::testing::ValuesIn(std::vector({ +INSTANTIATE_TEST_SUITE_P( + ScalarTypeConstants, AggressiveEliminateDeadConstantTest, + ::testing::ValuesIn(std::vector({ // clang-format off // Scalar type constants, one dead constant and one used constant. { @@ -4344,9 +4346,9 @@ INSTANTIATE_TEST_CASE_P( // clang-format on }))); -INSTANTIATE_TEST_CASE_P( - VectorTypeConstants, EliminateDeadConstantTest, - ::testing::ValuesIn(std::vector({ +INSTANTIATE_TEST_SUITE_P( + VectorTypeConstants, AggressiveEliminateDeadConstantTest, + ::testing::ValuesIn(std::vector({ // clang-format off // Tests eliminating dead constant type ivec2. One dead constant vector // and one used constant vector, each built from its own group of @@ -4471,9 +4473,9 @@ INSTANTIATE_TEST_CASE_P( // clang-format on }))); -INSTANTIATE_TEST_CASE_P( - StructTypeConstants, EliminateDeadConstantTest, - ::testing::ValuesIn(std::vector({ +INSTANTIATE_TEST_SUITE_P( + StructTypeConstants, AggressiveEliminateDeadConstantTest, + ::testing::ValuesIn(std::vector({ // clang-format off // A plain struct type dead constants. All of its components are dead // constants too. @@ -4642,9 +4644,9 @@ INSTANTIATE_TEST_CASE_P( // clang-format on }))); -INSTANTIATE_TEST_CASE_P( - ScalarTypeSpecConstants, EliminateDeadConstantTest, - ::testing::ValuesIn(std::vector({ +INSTANTIATE_TEST_SUITE_P( + ScalarTypeSpecConstants, AggressiveEliminateDeadConstantTest, + ::testing::ValuesIn(std::vector({ // clang-format off // All scalar type spec constants. { @@ -4695,9 +4697,9 @@ INSTANTIATE_TEST_CASE_P( // clang-format on }))); -INSTANTIATE_TEST_CASE_P( - VectorTypeSpecConstants, EliminateDeadConstantTest, - ::testing::ValuesIn(std::vector({ +INSTANTIATE_TEST_SUITE_P( + VectorTypeSpecConstants, AggressiveEliminateDeadConstantTest, + ::testing::ValuesIn(std::vector({ // clang-format off // Bool vector type spec constants. One vector has all component dead, // another vector has one dead boolean and one used boolean. @@ -4817,9 +4819,9 @@ INSTANTIATE_TEST_CASE_P( // clang-format on }))); -INSTANTIATE_TEST_CASE_P( - SpecConstantOp, EliminateDeadConstantTest, - ::testing::ValuesIn(std::vector({ +INSTANTIATE_TEST_SUITE_P( + SpecConstantOp, AggressiveEliminateDeadConstantTest, + ::testing::ValuesIn(std::vector({ // clang-format off // Cast operations: uint <-> int <-> bool { @@ -4999,9 +5001,9 @@ INSTANTIATE_TEST_CASE_P( // clang-format on }))); -INSTANTIATE_TEST_CASE_P( - LongDefUseChain, EliminateDeadConstantTest, - ::testing::ValuesIn(std::vector({ +INSTANTIATE_TEST_SUITE_P( + LongDefUseChain, AggressiveEliminateDeadConstantTest, + ::testing::ValuesIn(std::vector({ // clang-format off // Long Def-Use chain with binary operations. { @@ -5109,10 +5111,46 @@ OpFunctionEnd SinglePassRunAndMatch(text, true); } +TEST_F(AggressiveDCETest, DeadDecorationGroupAndValidDecorationMgr) { + // The decoration group should be eliminated because the target of group + // decorate is dead. + const std::string text = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpDecorate %1 Restrict +OpDecorate %1 Aliased +%1 = OpDecorationGroup +OpGroupDecorate %1 %var +%void = OpTypeVoid +%func = OpTypeFunction %void +%uint = OpTypeInt 32 0 +%uint_ptr = OpTypePointer Function %uint +%main = OpFunction %void None %func +%2 = OpLabel +%var = OpVariable %uint_ptr Function +OpReturn +OpFunctionEnd + )"; + + auto pass = MakeUnique(); + auto consumer = [](spv_message_level_t, const char*, const spv_position_t&, + const char* message) { + std::cerr << message << std::endl; + }; + auto context = BuildModule(SPV_ENV_UNIVERSAL_1_1, consumer, text); + + // Build the decoration manager before the pass. + context->get_decoration_mgr(); + + const auto status = pass->Run(context.get()); + EXPECT_EQ(status, Pass::Status::SuccessWithChange); +} + TEST_F(AggressiveDCETest, ParitallyDeadDecorationGroup) { const std::string text = R"( ; CHECK: OpDecorate [[grp:%\w+]] Restrict -; CHECK: OpDecorate [[grp]] Aliased ; CHECK: [[grp]] = OpDecorationGroup ; CHECK: OpGroupDecorate [[grp]] [[output:%\w+]] ; CHECK: [[output]] = OpVariable {{%\w+}} Output @@ -5122,7 +5160,6 @@ OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %main "main" %output OpExecutionMode %main OriginUpperLeft OpDecorate %1 Restrict -OpDecorate %1 Aliased %1 = OpDecorationGroup OpGroupDecorate %1 %var %output %void = OpTypeVoid @@ -5146,7 +5183,6 @@ OpFunctionEnd TEST_F(AggressiveDCETest, ParitallyDeadDecorationGroupDifferentGroupDecorate) { const std::string text = R"( ; CHECK: OpDecorate [[grp:%\w+]] Restrict -; CHECK: OpDecorate [[grp]] Aliased ; CHECK: [[grp]] = OpDecorationGroup ; CHECK: OpGroupDecorate [[grp]] [[output:%\w+]] ; CHECK-NOT: OpGroupDecorate @@ -5157,7 +5193,6 @@ OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %main "main" %output OpExecutionMode %main OriginUpperLeft OpDecorate %1 Restrict -OpDecorate %1 Aliased %1 = OpDecorationGroup OpGroupDecorate %1 %output OpGroupDecorate %1 %var @@ -5209,7 +5244,7 @@ OpFunctionEnd TEST_F(AggressiveDCETest, PartiallyDeadGroupMemberDecorate) { const std::string text = R"( ; CHECK: OpDecorate [[grp:%\w+]] Offset 0 -; CHECK: OpDecorate [[grp]] Uniform +; CHECK: OpDecorate [[grp]] RelaxedPrecision ; CHECK: [[grp]] = OpDecorationGroup ; CHECK: OpGroupMemberDecorate [[grp]] [[output:%\w+]] 1 ; CHECK: [[output]] = OpTypeStruct @@ -5219,7 +5254,7 @@ OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %main "main" %output OpExecutionMode %main OriginUpperLeft OpDecorate %1 Offset 0 -OpDecorate %1 Uniform +OpDecorate %1 RelaxedPrecision %1 = OpDecorationGroup OpGroupMemberDecorate %1 %var_struct 0 %output_struct 1 %void = OpTypeVoid @@ -5248,7 +5283,7 @@ TEST_F(AggressiveDCETest, PartiallyDeadGroupMemberDecorateDifferentGroupDecorate) { const std::string text = R"( ; CHECK: OpDecorate [[grp:%\w+]] Offset 0 -; CHECK: OpDecorate [[grp]] Uniform +; CHECK: OpDecorate [[grp]] RelaxedPrecision ; CHECK: [[grp]] = OpDecorationGroup ; CHECK: OpGroupMemberDecorate [[grp]] [[output:%\w+]] 1 ; CHECK-NOT: OpGroupMemberDecorate @@ -5259,7 +5294,7 @@ OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %main "main" %output OpExecutionMode %main OriginUpperLeft OpDecorate %1 Offset 0 -OpDecorate %1 Uniform +OpDecorate %1 RelaxedPrecision %1 = OpDecorationGroup OpGroupMemberDecorate %1 %var_struct 0 OpGroupMemberDecorate %1 %output_struct 1 @@ -5309,7 +5344,6 @@ OpFunctionEnd SinglePassRunAndMatch(text, true); } -#endif // SPIRV_EFFCEE // Test for #1214 TEST_F(AggressiveDCETest, LoopHeaderIsAlsoAnotherLoopMerge) { @@ -5523,6 +5557,7 @@ TEST_F(AggressiveDCETest, SafelyRemoveDecorateString) { OpExtension "SPV_GOOGLE_hlsl_functionality1" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %1 "main" +OpExecutionMode %1 OriginUpperLeft )"; const std::string body_before = @@ -5812,6 +5847,920 @@ OpFunctionEnd SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); SinglePassRunAndCheck(test, test, true, true); } + +TEST_F(AggressiveDCETest, CountingLoopNotEliminated) { + // #version 310 es + // + // precision highp float; + // precision highp int; + // + // layout(location = 0) out vec4 _GLF_color; + // + // void main() + // { + // float data[1]; + // for (int c = 0; c < 1; c++) { + // if (true) { + // do { + // for (int i = 0; i < 1; i++) { + // data[i] = 1.0; + // } + // } while (false); + // } + // } + // _GLF_color = vec4(data[0], 0.0, 0.0, 1.0); + // } + const std::string test = + R"(OpCapability Shader +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %_GLF_color +OpExecutionMode %main OriginUpperLeft +OpSource ESSL 310 +OpName %main "main" +OpName %c "c" +OpName %i "i" +OpName %data "data" +OpName %_GLF_color "_GLF_color" +OpDecorate %_GLF_color Location 0 +%void = OpTypeVoid +%8 = OpTypeFunction %void +%int = OpTypeInt 32 1 +%_ptr_Function_int = OpTypePointer Function %int +%int_0 = OpConstant %int 0 +%int_1 = OpConstant %int 1 +%bool = OpTypeBool +%float = OpTypeFloat 32 +%uint = OpTypeInt 32 0 +%uint_1 = OpConstant %uint 1 +%_arr_float_uint_1 = OpTypeArray %float %uint_1 +%_ptr_Function__arr_float_uint_1 = OpTypePointer Function %_arr_float_uint_1 +%float_1 = OpConstant %float 1 +%_ptr_Function_float = OpTypePointer Function %float +%false = OpConstantFalse %bool +%v4float = OpTypeVector %float 4 +%_ptr_Output_v4float = OpTypePointer Output %v4float +%_GLF_color = OpVariable %_ptr_Output_v4float Output +%float_0 = OpConstant %float 0 +%main = OpFunction %void None %8 +%26 = OpLabel +%c = OpVariable %_ptr_Function_int Function +%i = OpVariable %_ptr_Function_int Function +%data = OpVariable %_ptr_Function__arr_float_uint_1 Function +OpStore %c %int_0 +OpBranch %27 +%27 = OpLabel +OpLoopMerge %28 %29 None +OpBranch %30 +%30 = OpLabel +%31 = OpLoad %int %c +%32 = OpSLessThan %bool %31 %int_1 +OpBranchConditional %32 %33 %28 +%33 = OpLabel +OpBranch %34 +%34 = OpLabel +OpBranch %35 +%35 = OpLabel +OpLoopMerge %36 %37 None +OpBranch %38 +%38 = OpLabel +OpStore %i %int_0 +OpBranch %39 +%39 = OpLabel +OpLoopMerge %40 %41 None +OpBranch %42 +%42 = OpLabel +%43 = OpLoad %int %i +%44 = OpSLessThan %bool %43 %int_1 +OpBranchConditional %44 %46 %40 +%46 = OpLabel +%47 = OpLoad %int %i +%48 = OpAccessChain %_ptr_Function_float %data %47 +OpStore %48 %float_1 +OpBranch %41 +%41 = OpLabel +%49 = OpLoad %int %i +%50 = OpIAdd %int %49 %int_1 +OpStore %i %50 +OpBranch %39 +%40 = OpLabel +OpBranch %37 +%37 = OpLabel +OpBranchConditional %false %35 %36 +%36 = OpLabel +OpBranch %45 +%45 = OpLabel +OpBranch %29 +%29 = OpLabel +%51 = OpLoad %int %c +%52 = OpIAdd %int %51 %int_1 +OpStore %c %52 +OpBranch %27 +%28 = OpLabel +%53 = OpAccessChain %_ptr_Function_float %data %int_0 +%54 = OpLoad %float %53 +%55 = OpCompositeConstruct %v4float %54 %float_0 %float_0 %float_1 +OpStore %_GLF_color %55 +OpReturn +OpFunctionEnd +)"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck(test, test, true, true); +} + +TEST_F(AggressiveDCETest, EliminateLoopWithUnreachable) { + // #version 430 + // + // layout(std430) buffer U_t + // { + // float g_F[10]; + // float g_S; + // }; + // + // layout(location = 0)out float o; + // + // void main(void) + // { + // // Useless loop + // for (int i = 0; i<10; i++) { + // if (g_F[i] == 0.0) + // break; + // else + // break; + // // Unreachable merge block created here. + // // Need to edit SPIR-V to change to OpUnreachable + // } + // o = g_S; + // } + + const std::string before = + R"(OpCapability Shader +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %o +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 430 +OpName %main "main" +OpName %i "i" +OpName %U_t "U_t" +OpMemberName %U_t 0 "g_F" +OpMemberName %U_t 1 "g_S" +OpName %_ "" +OpName %o "o" +OpDecorate %_arr_float_uint_10 ArrayStride 4 +OpMemberDecorate %U_t 0 Offset 0 +OpMemberDecorate %U_t 1 Offset 40 +OpDecorate %U_t BufferBlock +OpDecorate %_ DescriptorSet 0 +OpDecorate %o Location 0 +%void = OpTypeVoid +%9 = OpTypeFunction %void +%int = OpTypeInt 32 1 +%_ptr_Function_int = OpTypePointer Function %int +%int_0 = OpConstant %int 0 +%int_10 = OpConstant %int 10 +%bool = OpTypeBool +%float = OpTypeFloat 32 +%uint = OpTypeInt 32 0 +%uint_10 = OpConstant %uint 10 +%_arr_float_uint_10 = OpTypeArray %float %uint_10 +%U_t = OpTypeStruct %_arr_float_uint_10 %float +%_ptr_Uniform_U_t = OpTypePointer Uniform %U_t +%_ = OpVariable %_ptr_Uniform_U_t Uniform +%_ptr_Uniform_float = OpTypePointer Uniform %float +%float_0 = OpConstant %float 0 +%int_1 = OpConstant %int 1 +%_ptr_Output_float = OpTypePointer Output %float +%o = OpVariable %_ptr_Output_float Output +%main = OpFunction %void None %9 +%23 = OpLabel +%i = OpVariable %_ptr_Function_int Function +OpStore %i %int_0 +OpBranch %24 +%24 = OpLabel +OpLoopMerge %25 %26 None +OpBranch %27 +%27 = OpLabel +%28 = OpLoad %int %i +%29 = OpSLessThan %bool %28 %int_10 +OpBranchConditional %29 %30 %25 +%30 = OpLabel +%31 = OpLoad %int %i +%32 = OpAccessChain %_ptr_Uniform_float %_ %int_0 %31 +%33 = OpLoad %float %32 +%34 = OpFOrdEqual %bool %33 %float_0 +OpSelectionMerge %35 None +OpBranchConditional %34 %36 %37 +%36 = OpLabel +OpBranch %25 +%37 = OpLabel +OpBranch %25 +%35 = OpLabel +OpUnreachable +%26 = OpLabel +%38 = OpLoad %int %i +%39 = OpIAdd %int %38 %int_1 +OpStore %i %39 +OpBranch %24 +%25 = OpLabel +%40 = OpAccessChain %_ptr_Uniform_float %_ %int_1 +%41 = OpLoad %float %40 +OpStore %o %41 +OpReturn +OpFunctionEnd +)"; + + const std::string after = + R"(OpCapability Shader +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %o +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 430 +OpName %main "main" +OpName %U_t "U_t" +OpMemberName %U_t 0 "g_F" +OpMemberName %U_t 1 "g_S" +OpName %_ "" +OpName %o "o" +OpDecorate %_arr_float_uint_10 ArrayStride 4 +OpMemberDecorate %U_t 0 Offset 0 +OpMemberDecorate %U_t 1 Offset 40 +OpDecorate %U_t BufferBlock +OpDecorate %_ DescriptorSet 0 +OpDecorate %o Location 0 +%void = OpTypeVoid +%9 = OpTypeFunction %void +%int = OpTypeInt 32 1 +%float = OpTypeFloat 32 +%uint = OpTypeInt 32 0 +%uint_10 = OpConstant %uint 10 +%_arr_float_uint_10 = OpTypeArray %float %uint_10 +%U_t = OpTypeStruct %_arr_float_uint_10 %float +%_ptr_Uniform_U_t = OpTypePointer Uniform %U_t +%_ = OpVariable %_ptr_Uniform_U_t Uniform +%_ptr_Uniform_float = OpTypePointer Uniform %float +%int_1 = OpConstant %int 1 +%_ptr_Output_float = OpTypePointer Output %float +%o = OpVariable %_ptr_Output_float Output +%main = OpFunction %void None %9 +%23 = OpLabel +OpBranch %24 +%24 = OpLabel +OpBranch %25 +%25 = OpLabel +%40 = OpAccessChain %_ptr_Uniform_float %_ %int_1 +%41 = OpLoad %float %40 +OpStore %o %41 +OpReturn +OpFunctionEnd +)"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck(before, after, true, true); +} + +TEST_F(AggressiveDCETest, DeadHlslCounterBufferGOOGLE) { + // We are able to remove "local2" because it is not loaded, but have to keep + // the stores to "local1". + const std::string test = + R"( +; CHECK-NOT: OpDecorateId +; CHECK: [[var:%\w+]] = OpVariable +; CHECK-NOT: OpVariable +; CHECK: [[ac:%\w+]] = OpAccessChain {{%\w+}} [[var]] +; CHECK: OpStore [[ac]] + OpCapability Shader + OpExtension "SPV_GOOGLE_hlsl_functionality1" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "main" + OpExecutionMode %1 LocalSize 32 1 1 + OpSource HLSL 600 + OpDecorate %_runtimearr_v2float ArrayStride 8 + OpMemberDecorate %_struct_3 0 Offset 0 + OpDecorate %_struct_3 BufferBlock + OpMemberDecorate %_struct_4 0 Offset 0 + OpDecorate %_struct_4 BufferBlock + OpDecorateId %5 HlslCounterBufferGOOGLE %6 + OpDecorate %5 DescriptorSet 0 + OpDecorate %5 Binding 0 + OpDecorate %6 DescriptorSet 0 + OpDecorate %6 Binding 1 + %float = OpTypeFloat 32 + %v2float = OpTypeVector %float 2 +%_runtimearr_v2float = OpTypeRuntimeArray %v2float + %_struct_3 = OpTypeStruct %_runtimearr_v2float +%_ptr_Uniform__struct_3 = OpTypePointer Uniform %_struct_3 + %int = OpTypeInt 32 1 + %_struct_4 = OpTypeStruct %int +%_ptr_Uniform__struct_4 = OpTypePointer Uniform %_struct_4 + %void = OpTypeVoid + %13 = OpTypeFunction %void + %19 = OpConstantNull %v2float + %int_0 = OpConstant %int 0 +%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float + %5 = OpVariable %_ptr_Uniform__struct_3 Uniform + %6 = OpVariable %_ptr_Uniform__struct_4 Uniform + %1 = OpFunction %void None %13 + %22 = OpLabel + %23 = OpAccessChain %_ptr_Uniform_v2float %5 %int_0 %int_0 + OpStore %23 %19 + OpReturn + OpFunctionEnd +)"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndMatch(test, true); +} + +TEST_F(AggressiveDCETest, Dead) { + // We are able to remove "local2" because it is not loaded, but have to keep + // the stores to "local1". + const std::string test = + R"( +; CHECK: OpCapability +; CHECK-NOT: OpMemberDecorateStringGOOGLE +; CHECK: OpFunctionEnd + OpCapability Shader + OpExtension "SPV_GOOGLE_hlsl_functionality1" + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %VSMain "VSMain" + OpSource HLSL 500 + OpName %VSMain "VSMain" + OpName %PSInput "PSInput" + OpMemberName %PSInput 0 "Pos" + OpMemberName %PSInput 1 "uv" + OpMemberDecorateStringGOOGLE %PSInput 0 HlslSemanticGOOGLE "SV_POSITION" + OpMemberDecorateStringGOOGLE %PSInput 1 HlslSemanticGOOGLE "TEX_COORD" + %void = OpTypeVoid + %5 = OpTypeFunction %void + %float = OpTypeFloat 32 +%v2float = OpTypeVector %float 2 +%v4float = OpTypeVector %float 4 +%PSInput = OpTypeStruct %v4float %v2float + %VSMain = OpFunction %void None %5 + %9 = OpLabel + OpReturn + OpFunctionEnd +)"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndMatch(test, true); +} + +TEST_F(AggressiveDCETest, DeadInfiniteLoop) { + const std::string test = R"( +; CHECK: OpSwitch {{%\w+}} {{%\w+}} {{\w+}} {{%\w+}} {{\w+}} [[block:%\w+]] +; CHECK: [[block]] = OpLabel +; CHECK-NEXT: OpBranch [[block:%\w+]] +; CHECK: [[block]] = OpLabel +; CHECK-NEXT: OpBranch [[block:%\w+]] +; CHECK: [[block]] = OpLabel +; CHECK-NEXT: OpReturn + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + %6 = OpTypeVoid + %7 = OpTypeFunction %6 + %8 = OpTypeFloat 32 + %9 = OpTypeVector %8 3 + %10 = OpTypeFunction %9 + %11 = OpConstant %8 1 + %12 = OpConstantComposite %9 %11 %11 %11 + %13 = OpTypeInt 32 1 + %32 = OpUndef %13 + %2 = OpFunction %6 None %7 + %33 = OpLabel + OpBranch %34 + %34 = OpLabel + OpLoopMerge %35 %36 None + OpBranch %37 + %37 = OpLabel + %38 = OpFunctionCall %9 %39 + OpSelectionMerge %40 None + OpSwitch %32 %40 14 %41 58 %42 + %42 = OpLabel + OpBranch %43 + %43 = OpLabel + OpLoopMerge %44 %45 None + OpBranch %45 + %45 = OpLabel + OpBranch %43 + %44 = OpLabel + OpUnreachable + %41 = OpLabel + OpBranch %36 + %40 = OpLabel + OpBranch %36 + %36 = OpLabel + OpBranch %34 + %35 = OpLabel + OpReturn + OpFunctionEnd + %39 = OpFunction %9 None %10 + %46 = OpLabel + OpReturnValue %12 + OpFunctionEnd +)"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndMatch(test, true); +} + +TEST_F(AggressiveDCETest, DeadInfiniteLoopReturnValue) { + const std::string test = R"( +; CHECK: [[vec3:%\w+]] = OpTypeVector +; CHECK: [[undef:%\w+]] = OpUndef [[vec3]] +; CHECK: OpSwitch {{%\w+}} {{%\w+}} {{\w+}} {{%\w+}} {{\w+}} [[block:%\w+]] +; CHECK: [[block]] = OpLabel +; CHECK-NEXT: OpBranch [[block:%\w+]] +; CHECK: [[block]] = OpLabel +; CHECK-NEXT: OpBranch [[block:%\w+]] +; CHECK: [[block]] = OpLabel +; CHECK-NEXT: OpReturnValue [[undef]] + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + %6 = OpTypeVoid + %7 = OpTypeFunction %6 + %8 = OpTypeFloat 32 + %9 = OpTypeVector %8 3 + %10 = OpTypeFunction %9 + %11 = OpConstant %8 1 + %12 = OpConstantComposite %9 %11 %11 %11 + %13 = OpTypeInt 32 1 + %32 = OpUndef %13 + %2 = OpFunction %6 None %7 + %entry = OpLabel + %call = OpFunctionCall %9 %func + OpReturn + OpFunctionEnd + %func = OpFunction %9 None %10 + %33 = OpLabel + OpBranch %34 + %34 = OpLabel + OpLoopMerge %35 %36 None + OpBranch %37 + %37 = OpLabel + %38 = OpFunctionCall %9 %39 + OpSelectionMerge %40 None + OpSwitch %32 %40 14 %41 58 %42 + %42 = OpLabel + OpBranch %43 + %43 = OpLabel + OpLoopMerge %44 %45 None + OpBranch %45 + %45 = OpLabel + OpBranch %43 + %44 = OpLabel + OpUnreachable + %41 = OpLabel + OpBranch %36 + %40 = OpLabel + OpBranch %36 + %36 = OpLabel + OpBranch %34 + %35 = OpLabel + OpReturnValue %12 + OpFunctionEnd + %39 = OpFunction %9 None %10 + %46 = OpLabel + OpReturnValue %12 + OpFunctionEnd +)"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndMatch(test, true); +} + +TEST_F(AggressiveDCETest, TestVariablePointer) { + const std::string before = + R"(OpCapability Shader +OpCapability VariablePointers +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %2 "main" +OpExecutionMode %2 LocalSize 1 1 1 +OpSource GLSL 450 +OpMemberDecorate %_struct_3 0 Offset 0 +OpDecorate %_struct_3 Block +OpDecorate %4 DescriptorSet 0 +OpDecorate %4 Binding 0 +OpDecorate %_ptr_StorageBuffer_int ArrayStride 4 +OpDecorate %_arr_int_int_128 ArrayStride 4 +%void = OpTypeVoid +%8 = OpTypeFunction %void +%int = OpTypeInt 32 1 +%int_128 = OpConstant %int 128 +%_arr_int_int_128 = OpTypeArray %int %int_128 +%_struct_3 = OpTypeStruct %_arr_int_int_128 +%_ptr_StorageBuffer__struct_3 = OpTypePointer StorageBuffer %_struct_3 +%4 = OpVariable %_ptr_StorageBuffer__struct_3 StorageBuffer +%bool = OpTypeBool +%true = OpConstantTrue %bool +%int_0 = OpConstant %int 0 +%int_1 = OpConstant %int 1 +%_ptr_StorageBuffer_int = OpTypePointer StorageBuffer %int +%2 = OpFunction %void None %8 +%16 = OpLabel +%17 = OpAccessChain %_ptr_StorageBuffer_int %4 %int_0 %int_0 +OpBranch %18 +%18 = OpLabel +%19 = OpPhi %_ptr_StorageBuffer_int %17 %16 %20 %21 +OpLoopMerge %22 %21 None +OpBranchConditional %true %23 %22 +%23 = OpLabel +OpStore %19 %int_0 +OpBranch %21 +%21 = OpLabel +%20 = OpPtrAccessChain %_ptr_StorageBuffer_int %19 %int_1 +OpBranch %18 +%22 = OpLabel +OpReturn +OpFunctionEnd +)"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck(before, before, true, true); +} + +TEST_F(AggressiveDCETest, DeadInputInterfaceV13) { + const std::string spirv = R"( +; CHECK: OpEntryPoint GLCompute %main "main" [[var:%\w+]] +; CHECK: [[var]] = OpVariable +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" %dead +OpExecutionMode %main LocalSize 1 1 1 +OpName %main "main" +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%ptr_input_int = OpTypePointer Input %int +%dead = OpVariable %ptr_input_int Input +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + SetTargetEnv(SPV_ENV_UNIVERSAL_1_3); + SinglePassRunAndMatch(spirv, true); +} + +TEST_F(AggressiveDCETest, DeadInputInterfaceV14) { + const std::string spirv = R"( +; CHECK: OpEntryPoint GLCompute %main "main" [[var:%\w+]] +; CHECK: [[var]] = OpVariable +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" %dead +OpExecutionMode %main LocalSize 1 1 1 +OpName %main "main" +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%ptr_input_int = OpTypePointer Input %int +%dead = OpVariable %ptr_input_int Input +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + SetTargetEnv(SPV_ENV_UNIVERSAL_1_4); + SinglePassRunAndMatch(spirv, true); +} + +TEST_F(AggressiveDCETest, DeadInterfaceV14) { + const std::string spirv = R"( +; CHECK-NOT: OpEntryPoint GLCompute %main "main" % +; CHECK: OpEntryPoint GLCompute %main "main" +; CHECK-NOT: OpVariable +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" %dead +OpExecutionMode %main LocalSize 1 1 1 +OpName %main "main" +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%ptr_private_int = OpTypePointer Private %int +%dead = OpVariable %ptr_private_int Private +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + SetTargetEnv(SPV_ENV_UNIVERSAL_1_4); + SinglePassRunAndMatch(spirv, true); +} + +TEST_F(AggressiveDCETest, DeadInterfacesV14) { + const std::string spirv = R"( +; CHECK: OpEntryPoint GLCompute %main "main" %live1 %live2 +; CHECK-NOT: %dead +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" %live1 %dead1 %dead2 %live2 +OpExecutionMode %main LocalSize 1 1 1 +OpName %main "main" +OpName %live1 "live1" +OpName %live2 "live2" +OpName %dead1 "dead1" +OpName %dead2 "dead2" +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int0 = OpConstant %int 0 +%ptr_ssbo_int = OpTypePointer StorageBuffer %int +%live1 = OpVariable %ptr_ssbo_int StorageBuffer +%live2 = OpVariable %ptr_ssbo_int StorageBuffer +%dead1 = OpVariable %ptr_ssbo_int StorageBuffer +%dead2 = OpVariable %ptr_ssbo_int StorageBuffer +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpStore %live1 %int0 +OpStore %live2 %int0 +OpReturn +OpFunctionEnd +)"; + + SetTargetEnv(SPV_ENV_UNIVERSAL_1_4); + SinglePassRunAndMatch(spirv, true); +} + +TEST_F(AggressiveDCETest, PreserveBindings) { + const std::string spirv = R"( +; CHECK: OpDecorate %unusedSampler DescriptorSet 0 +; CHECK: OpDecorate %unusedSampler Binding 0 +OpCapability Shader +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 430 +OpName %main "main" +OpName %unusedSampler "unusedSampler" +OpDecorate %unusedSampler DescriptorSet 0 +OpDecorate %unusedSampler Binding 0 +%void = OpTypeVoid +%5 = OpTypeFunction %void +%float = OpTypeFloat 32 +%7 = OpTypeImage %float 2D 0 0 0 1 Unknown +%8 = OpTypeSampledImage %7 +%_ptr_UniformConstant_8 = OpTypePointer UniformConstant %8 +%unusedSampler = OpVariable %_ptr_UniformConstant_8 UniformConstant +%main = OpFunction %void None %5 +%10 = OpLabel +OpReturn +OpFunctionEnd +)"; + + SetTargetEnv(SPV_ENV_UNIVERSAL_1_4); + + OptimizerOptions()->preserve_bindings_ = true; + + SinglePassRunAndMatch(spirv, true); +} + +TEST_F(AggressiveDCETest, PreserveSpecConstants) { + const std::string spirv = R"( +; CHECK: OpName %specConstant "specConstant" +; CHECK: %specConstant = OpSpecConstant %int 0 +OpCapability Shader +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 430 +OpName %main "main" +OpName %specConstant "specConstant" +OpDecorate %specConstant SpecId 0 +%void = OpTypeVoid +%3 = OpTypeFunction %void +%int = OpTypeInt 32 1 +%specConstant = OpSpecConstant %int 0 +%main = OpFunction %void None %3 +%5 = OpLabel +OpReturn +OpFunctionEnd +)"; + + SetTargetEnv(SPV_ENV_UNIVERSAL_1_4); + + OptimizerOptions()->preserve_spec_constants_ = true; + + SinglePassRunAndMatch(spirv, true); +} + +TEST_F(AggressiveDCETest, LiveDecorateId) { + const std::string spirv = R"(OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %1 "main" %2 +OpExecutionMode %1 LocalSize 8 1 1 +OpDecorate %2 DescriptorSet 0 +OpDecorate %2 Binding 0 +OpDecorateId %3 UniformId %uint_2 +%void = OpTypeVoid +%uint = OpTypeInt 32 0 +%uint_2 = OpConstant %uint 2 +%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint +%2 = OpVariable %_ptr_StorageBuffer_uint StorageBuffer +%8 = OpTypeFunction %void +%1 = OpFunction %void None %8 +%9 = OpLabel +%3 = OpLoad %uint %2 +OpStore %2 %3 +OpReturn +OpFunctionEnd +)"; + + SetTargetEnv(SPV_ENV_UNIVERSAL_1_4); + OptimizerOptions()->preserve_spec_constants_ = true; + SinglePassRunAndCheck(spirv, spirv, true); +} + +TEST_F(AggressiveDCETest, LiveDecorateIdOnGroup) { + const std::string spirv = R"(OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %1 "main" %2 +OpExecutionMode %1 LocalSize 8 1 1 +OpDecorate %2 DescriptorSet 0 +OpDecorate %2 Binding 0 +OpDecorateId %3 UniformId %uint_2 +%3 = OpDecorationGroup +OpGroupDecorate %3 %5 +%void = OpTypeVoid +%uint = OpTypeInt 32 0 +%uint_2 = OpConstant %uint 2 +%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint +%2 = OpVariable %_ptr_StorageBuffer_uint StorageBuffer +%9 = OpTypeFunction %void +%1 = OpFunction %void None %9 +%10 = OpLabel +%5 = OpLoad %uint %2 +OpStore %2 %5 +OpReturn +OpFunctionEnd +)"; + + SetTargetEnv(SPV_ENV_UNIVERSAL_1_4); + OptimizerOptions()->preserve_spec_constants_ = true; + SinglePassRunAndCheck(spirv, spirv, true); +} + +TEST_F(AggressiveDCETest, NoEliminateForwardPointer) { + // clang-format off + // + // #version 450 + // #extension GL_EXT_buffer_reference : enable + // + // // forward reference + // layout(buffer_reference) buffer blockType; + // + // layout(buffer_reference, std430, buffer_reference_align = 16) buffer blockType { + // int x; + // blockType next; + // }; + // + // layout(std430) buffer rootBlock { + // blockType root; + // } r; + // + // void main() + // { + // blockType b = r.root; + // b = b.next; + // b.x = 531; + // } + // + // clang-format on + + const std::string predefs1 = + R"(OpCapability Shader +OpCapability PhysicalStorageBufferAddresses +OpExtension "SPV_EXT_physical_storage_buffer" +OpExtension "SPV_KHR_storage_buffer_storage_class" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel PhysicalStorageBuffer64 GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpSource GLSL 450 +OpSourceExtension "GL_EXT_buffer_reference" +)"; + + const std::string names_before = + R"(OpName %main "main" +OpName %blockType "blockType" +OpMemberName %blockType 0 "x" +OpMemberName %blockType 1 "next" +OpName %b "b" +OpName %rootBlock "rootBlock" +OpMemberName %rootBlock 0 "root" +OpName %r "r" +OpMemberDecorate %blockType 0 Offset 0 +OpMemberDecorate %blockType 1 Offset 8 +OpDecorate %blockType Block +OpDecorate %b AliasedPointer +OpMemberDecorate %rootBlock 0 Offset 0 +OpDecorate %rootBlock Block +OpDecorate %r DescriptorSet 0 +OpDecorate %r Binding 0 +)"; + + const std::string names_after = + R"(OpName %main "main" +OpName %blockType "blockType" +OpMemberName %blockType 0 "x" +OpMemberName %blockType 1 "next" +OpName %rootBlock "rootBlock" +OpMemberName %rootBlock 0 "root" +OpName %r "r" +OpMemberDecorate %blockType 0 Offset 0 +OpMemberDecorate %blockType 1 Offset 8 +OpDecorate %blockType Block +OpMemberDecorate %rootBlock 0 Offset 0 +OpDecorate %rootBlock Block +OpDecorate %r DescriptorSet 0 +OpDecorate %r Binding 0 +)"; + + const std::string predefs2_before = + R"(%void = OpTypeVoid +%3 = OpTypeFunction %void +OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_blockType PhysicalStorageBuffer +%int = OpTypeInt 32 1 +%blockType = OpTypeStruct %int %_ptr_PhysicalStorageBuffer_blockType +%_ptr_PhysicalStorageBuffer_blockType = OpTypePointer PhysicalStorageBuffer %blockType +%_ptr_Function__ptr_PhysicalStorageBuffer_blockType = OpTypePointer Function %_ptr_PhysicalStorageBuffer_blockType +%rootBlock = OpTypeStruct %_ptr_PhysicalStorageBuffer_blockType +%_ptr_StorageBuffer_rootBlock = OpTypePointer StorageBuffer %rootBlock +%r = OpVariable %_ptr_StorageBuffer_rootBlock StorageBuffer +%int_0 = OpConstant %int 0 +%_ptr_StorageBuffer__ptr_PhysicalStorageBuffer_blockType = OpTypePointer StorageBuffer %_ptr_PhysicalStorageBuffer_blockType +%int_1 = OpConstant %int 1 +%_ptr_PhysicalStorageBuffer__ptr_PhysicalStorageBuffer_blockType = OpTypePointer PhysicalStorageBuffer %_ptr_PhysicalStorageBuffer_blockType +%int_531 = OpConstant %int 531 +%_ptr_PhysicalStorageBuffer_int = OpTypePointer PhysicalStorageBuffer %int +)"; + + const std::string predefs2_after = + R"(%void = OpTypeVoid +%8 = OpTypeFunction %void +OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_blockType PhysicalStorageBuffer +%int = OpTypeInt 32 1 +%blockType = OpTypeStruct %int %_ptr_PhysicalStorageBuffer_blockType +%_ptr_PhysicalStorageBuffer_blockType = OpTypePointer PhysicalStorageBuffer %blockType +%rootBlock = OpTypeStruct %_ptr_PhysicalStorageBuffer_blockType +%_ptr_StorageBuffer_rootBlock = OpTypePointer StorageBuffer %rootBlock +%r = OpVariable %_ptr_StorageBuffer_rootBlock StorageBuffer +%int_0 = OpConstant %int 0 +%_ptr_StorageBuffer__ptr_PhysicalStorageBuffer_blockType = OpTypePointer StorageBuffer %_ptr_PhysicalStorageBuffer_blockType +%int_1 = OpConstant %int 1 +%_ptr_PhysicalStorageBuffer__ptr_PhysicalStorageBuffer_blockType = OpTypePointer PhysicalStorageBuffer %_ptr_PhysicalStorageBuffer_blockType +%int_531 = OpConstant %int 531 +%_ptr_PhysicalStorageBuffer_int = OpTypePointer PhysicalStorageBuffer %int +)"; + + const std::string func_before = + R"(%main = OpFunction %void None %3 +%5 = OpLabel +%b = OpVariable %_ptr_Function__ptr_PhysicalStorageBuffer_blockType Function +%16 = OpAccessChain %_ptr_StorageBuffer__ptr_PhysicalStorageBuffer_blockType %r %int_0 +%17 = OpLoad %_ptr_PhysicalStorageBuffer_blockType %16 +%21 = OpAccessChain %_ptr_PhysicalStorageBuffer__ptr_PhysicalStorageBuffer_blockType %17 %int_1 +%22 = OpLoad %_ptr_PhysicalStorageBuffer_blockType %21 Aligned 8 +OpStore %b %22 +%26 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %22 %int_0 +OpStore %26 %int_531 Aligned 16 +OpReturn +OpFunctionEnd +)"; + + const std::string func_after = + R"(%main = OpFunction %void None %8 +%19 = OpLabel +%20 = OpAccessChain %_ptr_StorageBuffer__ptr_PhysicalStorageBuffer_blockType %r %int_0 +%21 = OpLoad %_ptr_PhysicalStorageBuffer_blockType %20 +%22 = OpAccessChain %_ptr_PhysicalStorageBuffer__ptr_PhysicalStorageBuffer_blockType %21 %int_1 +%23 = OpLoad %_ptr_PhysicalStorageBuffer_blockType %22 Aligned 8 +%24 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %23 %int_0 +OpStore %24 %int_531 Aligned 16 +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndCheck( + predefs1 + names_before + predefs2_before + func_before, + predefs1 + names_after + predefs2_after + func_after, true, true); +} + // TODO(greg-lunarg): Add tests to verify handling of these cases: // // Check that logical addressing required diff --git a/third_party/spirv-tools/test/opt/amd_ext_to_khr.cpp b/third_party/spirv-tools/test/opt/amd_ext_to_khr.cpp new file mode 100644 index 0000000000..3340e898ce --- /dev/null +++ b/third_party/spirv-tools/test/opt/amd_ext_to_khr.cpp @@ -0,0 +1,953 @@ +// Copyright (c) 2019 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 + +#include "gmock/gmock.h" +#include "test/opt/pass_fixture.h" +#include "test/opt/pass_utils.h" + +namespace spvtools { +namespace opt { +namespace { + +using AmdExtToKhrTest = PassTest<::testing::Test>; + +using ::testing::HasSubstr; + +std::string GetTest(std::string op_code, std::string new_op_code) { + const std::string text = R"( +; CHECK: OpCapability Shader +; CHECK-NOT: OpExtension "SPV_AMD_shader_ballot" +; CHECK: OpFunction +; CHECK-NEXT: OpLabel +; CHECK-NEXT: [[undef:%\w+]] = OpUndef %uint +; CHECK-NEXT: )" + new_op_code + + R"( %uint %uint_3 Reduce [[undef]] + OpCapability Shader + OpCapability Groups + OpExtension "SPV_AMD_shader_ballot" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "func" + OpExecutionMode %1 OriginUpperLeft + %void = OpTypeVoid + %3 = OpTypeFunction %void + %uint = OpTypeInt 32 0 + %uint_3 = OpConstant %uint 3 + %1 = OpFunction %void None %3 + %6 = OpLabel + %7 = OpUndef %uint + %8 = )" + op_code + + R"( %uint %uint_3 Reduce %7 + OpReturn + OpFunctionEnd + +)"; + return text; +} + +TEST_F(AmdExtToKhrTest, ReplaceGroupIAddNonUniformAMD) { + std::string text = + GetTest("OpGroupIAddNonUniformAMD", "OpGroupNonUniformIAdd"); + SinglePassRunAndMatch(text, true); +} +TEST_F(AmdExtToKhrTest, ReplaceGroupFAddNonUniformAMD) { + std::string text = + GetTest("OpGroupFAddNonUniformAMD", "OpGroupNonUniformFAdd"); + SinglePassRunAndMatch(text, true); +} +TEST_F(AmdExtToKhrTest, ReplaceGroupUMinNonUniformAMD) { + std::string text = + GetTest("OpGroupUMinNonUniformAMD", "OpGroupNonUniformUMin"); + SinglePassRunAndMatch(text, true); +} +TEST_F(AmdExtToKhrTest, ReplaceGroupSMinNonUniformAMD) { + std::string text = + GetTest("OpGroupSMinNonUniformAMD", "OpGroupNonUniformSMin"); + SinglePassRunAndMatch(text, true); +} +TEST_F(AmdExtToKhrTest, ReplaceGroupFMinNonUniformAMD) { + std::string text = + GetTest("OpGroupFMinNonUniformAMD", "OpGroupNonUniformFMin"); + SinglePassRunAndMatch(text, true); +} +TEST_F(AmdExtToKhrTest, ReplaceGroupUMaxNonUniformAMD) { + std::string text = + GetTest("OpGroupUMaxNonUniformAMD", "OpGroupNonUniformUMax"); + SinglePassRunAndMatch(text, true); +} +TEST_F(AmdExtToKhrTest, ReplaceGroupSMaxNonUniformAMD) { + std::string text = + GetTest("OpGroupSMaxNonUniformAMD", "OpGroupNonUniformSMax"); + SinglePassRunAndMatch(text, true); +} +TEST_F(AmdExtToKhrTest, ReplaceGroupFMaxNonUniformAMD) { + std::string text = + GetTest("OpGroupFMaxNonUniformAMD", "OpGroupNonUniformFMax"); + SinglePassRunAndMatch(text, true); +} + +TEST_F(AmdExtToKhrTest, ReplaceMbcntAMD) { + const std::string text = R"( +; CHECK: OpCapability Shader +; CHECK-NOT: OpExtension "SPV_AMD_shader_ballot" +; CHECK-NOT: OpExtInstImport "SPV_AMD_shader_ballot" +; CHECK: OpDecorate [[var:%\w+]] BuiltIn SubgroupLtMask +; CHECK: [[var]] = OpVariable %_ptr_Input_v4uint Input +; CHECK: OpFunction +; CHECK-NEXT: OpLabel +; CHECK-NEXT: [[ld:%\w+]] = OpLoad %v4uint [[var]] +; CHECK-NEXT: [[shuffle:%\w+]] = OpVectorShuffle %v2uint [[ld]] [[ld]] 0 1 +; CHECK-NEXT: [[bitcast:%\w+]] = OpBitcast %ulong [[shuffle]] +; CHECK-NEXT: [[and:%\w+]] = OpBitwiseAnd %ulong [[bitcast]] %ulong_0 +; CHECK-NEXT: [[result:%\w+]] = OpBitCount %uint [[and]] + OpCapability Shader + OpCapability Int64 + OpExtension "SPV_AMD_shader_ballot" + %1 = OpExtInstImport "SPV_AMD_shader_ballot" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "func" + OpExecutionMode %2 OriginUpperLeft + %void = OpTypeVoid + %4 = OpTypeFunction %void + %uint = OpTypeInt 32 0 + %ulong = OpTypeInt 64 0 + %ulong_0 = OpConstant %ulong 0 + %2 = OpFunction %void None %4 + %8 = OpLabel + %9 = OpExtInst %uint %1 MbcntAMD %ulong_0 + OpReturn + OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(AmdExtToKhrTest, ReplaceSwizzleInvocationsAMD) { + const std::string text = R"( +; CHECK: OpCapability Shader +; CHECK-NOT: OpExtension "SPV_AMD_shader_ballot" +; CHECK-NOT: OpExtInstImport "SPV_AMD_shader_ballot" +; CHECK: OpDecorate [[var:%\w+]] BuiltIn SubgroupLocalInvocationId +; CHECK: [[subgroup:%\w+]] = OpConstant %uint 3 +; CHECK: [[offset:%\w+]] = OpConstantComposite %v4uint +; CHECK: [[var]] = OpVariable %_ptr_Input_uint Input +; CHECK: [[uint_max:%\w+]] = OpConstant %uint 4294967295 +; CHECK: [[ballot_value:%\w+]] = OpConstantComposite %v4uint [[uint_max]] [[uint_max]] [[uint_max]] [[uint_max]] +; CHECK: [[null:%\w+]] = OpConstantNull [[type:%\w+]] +; CHECK: OpFunction +; CHECK-NEXT: OpLabel +; CHECK-NEXT: [[data:%\w+]] = OpUndef [[type]] +; CHECK-NEXT: [[id:%\w+]] = OpLoad %uint [[var]] +; CHECK-NEXT: [[quad_idx:%\w+]] = OpBitwiseAnd %uint [[id]] %uint_3 +; CHECK-NEXT: [[quad_ldr:%\w+]] = OpBitwiseXor %uint [[id]] [[quad_idx]] +; CHECK-NEXT: [[my_offset:%\w+]] = OpVectorExtractDynamic %uint [[offset]] [[quad_idx]] +; CHECK-NEXT: [[target_inv:%\w+]] = OpIAdd %uint [[quad_ldr]] [[my_offset]] +; CHECK-NEXT: [[is_active:%\w+]] = OpGroupNonUniformBallotBitExtract %bool [[subgroup]] [[ballot_value]] [[target_inv]] +; CHECK-NEXT: [[shuffle:%\w+]] = OpGroupNonUniformShuffle [[type]] [[subgroup]] [[data]] [[target_inv]] +; CHECK-NEXT: [[result:%\w+]] = OpSelect [[type]] [[is_active]] [[shuffle]] [[null]] + OpCapability Shader + OpExtension "SPV_AMD_shader_ballot" + %ext = OpExtInstImport "SPV_AMD_shader_ballot" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "func" + OpExecutionMode %1 OriginUpperLeft + %void = OpTypeVoid + %3 = OpTypeFunction %void + %uint = OpTypeInt 32 0 + %uint_x = OpConstant %uint 1 + %uint_y = OpConstant %uint 2 + %uint_z = OpConstant %uint 3 + %uint_w = OpConstant %uint 0 + %v4uint = OpTypeVector %uint 4 + %offset = OpConstantComposite %v4uint %uint_x %uint_y %uint_z %uint_x + %1 = OpFunction %void None %3 + %6 = OpLabel + %data = OpUndef %uint + %9 = OpExtInst %uint %ext SwizzleInvocationsAMD %data %offset + OpReturn + OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} +TEST_F(AmdExtToKhrTest, ReplaceSwizzleInvocationsMaskedAMD) { + const std::string text = R"( +; CHECK: OpCapability Shader +; CHECK-NOT: OpExtension "SPV_AMD_shader_ballot" +; CHECK-NOT: OpExtInstImport "SPV_AMD_shader_ballot" +; CHECK: OpDecorate [[var:%\w+]] BuiltIn SubgroupLocalInvocationId +; CHECK: [[x:%\w+]] = OpConstant %uint 19 +; CHECK: [[y:%\w+]] = OpConstant %uint 12 +; CHECK: [[z:%\w+]] = OpConstant %uint 16 +; CHECK: [[var]] = OpVariable %_ptr_Input_uint Input +; CHECK: [[mask_extend:%\w+]] = OpConstant %uint 4294967264 +; CHECK: [[uint_max:%\w+]] = OpConstant %uint 4294967295 +; CHECK: [[subgroup:%\w+]] = OpConstant %uint 3 +; CHECK: [[ballot_value:%\w+]] = OpConstantComposite %v4uint [[uint_max]] [[uint_max]] [[uint_max]] [[uint_max]] +; CHECK: [[null:%\w+]] = OpConstantNull [[type:%\w+]] +; CHECK: OpFunction +; CHECK-NEXT: OpLabel +; CHECK-NEXT: [[data:%\w+]] = OpUndef [[type]] +; CHECK-NEXT: [[id:%\w+]] = OpLoad %uint [[var]] +; CHECK-NEXT: [[and_mask:%\w+]] = OpBitwiseOr %uint [[x]] [[mask_extend]] +; CHECK-NEXT: [[and:%\w+]] = OpBitwiseAnd %uint [[id]] [[and_mask]] +; CHECK-NEXT: [[or:%\w+]] = OpBitwiseOr %uint [[and]] [[y]] +; CHECK-NEXT: [[target_inv:%\w+]] = OpBitwiseXor %uint [[or]] [[z]] +; CHECK-NEXT: [[is_active:%\w+]] = OpGroupNonUniformBallotBitExtract %bool [[subgroup]] [[ballot_value]] [[target_inv]] +; CHECK-NEXT: [[shuffle:%\w+]] = OpGroupNonUniformShuffle [[type]] [[subgroup]] [[data]] [[target_inv]] +; CHECK-NEXT: [[result:%\w+]] = OpSelect [[type]] [[is_active]] [[shuffle]] [[null]] + OpCapability Shader + OpExtension "SPV_AMD_shader_ballot" + %ext = OpExtInstImport "SPV_AMD_shader_ballot" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "func" + OpExecutionMode %1 OriginUpperLeft + %void = OpTypeVoid + %3 = OpTypeFunction %void + %uint = OpTypeInt 32 0 + %uint_x = OpConstant %uint 19 + %uint_y = OpConstant %uint 12 + %uint_z = OpConstant %uint 16 + %v3uint = OpTypeVector %uint 3 + %mask = OpConstantComposite %v3uint %uint_x %uint_y %uint_z + %1 = OpFunction %void None %3 + %6 = OpLabel + %data = OpUndef %uint + %9 = OpExtInst %uint %ext SwizzleInvocationsMaskedAMD %data %mask + OpReturn + OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(AmdExtToKhrTest, ReplaceWriteInvocationAMD) { + const std::string text = R"( +; CHECK: OpCapability Shader +; CHECK-NOT: OpExtension "SPV_AMD_shader_ballot" +; CHECK-NOT: OpExtInstImport "SPV_AMD_shader_ballot" +; CHECK: OpDecorate [[var:%\w+]] BuiltIn SubgroupLocalInvocationId +; CHECK: [[var]] = OpVariable %_ptr_Input_uint Input +; CHECK: OpFunction +; CHECK-NEXT: OpLabel +; CHECK-NEXT: [[input_val:%\w+]] = OpUndef %uint +; CHECK-NEXT: [[write_val:%\w+]] = OpUndef %uint +; CHECK-NEXT: [[ld:%\w+]] = OpLoad %uint [[var]] +; CHECK-NEXT: [[cmp:%\w+]] = OpIEqual %bool [[ld]] %uint_3 +; CHECK-NEXT: [[result:%\w+]] = OpSelect %uint [[cmp]] [[write_val]] [[input_val]] + OpCapability Shader + OpExtension "SPV_AMD_shader_ballot" + %ext = OpExtInstImport "SPV_AMD_shader_ballot" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "func" + OpExecutionMode %1 OriginUpperLeft + %void = OpTypeVoid + %3 = OpTypeFunction %void + %uint = OpTypeInt 32 0 + %uint_3 = OpConstant %uint 3 + %1 = OpFunction %void None %3 + %6 = OpLabel + %7 = OpUndef %uint + %8 = OpUndef %uint + %9 = OpExtInst %uint %ext WriteInvocationAMD %7 %8 %uint_3 + OpReturn + OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(AmdExtToKhrTest, ReplaceFMin3AMD) { + const std::string text = R"( +; CHECK: OpCapability Shader +; CHECK-NOT: OpExtension "SPV_AMD_shader_trinary_minmax" +; CHECK-NOT: OpExtInstImport "SPV_AMD_shader_trinary_minmax" +; CHECK: [[ext:%\w+]] = OpExtInstImport "GLSL.std.450" +; CHECK: [[type:%\w+]] = OpTypeFloat 32 +; CHECK: OpFunction +; CHECK-NEXT: OpLabel +; CHECK-NEXT: [[x:%\w+]] = OpUndef [[type]] +; CHECK-NEXT: [[y:%\w+]] = OpUndef [[type]] +; CHECK-NEXT: [[z:%\w+]] = OpUndef [[type]] +; CHECK-NEXT: [[temp:%\w+]] = OpExtInst [[type]] [[ext]] FMin [[x]] [[y]] +; CHECK-NEXT: [[result:%\w+]] = OpExtInst [[type]] [[ext]] FMin [[temp]] [[z]] + OpCapability Shader + OpExtension "SPV_AMD_shader_trinary_minmax" + %ext = OpExtInstImport "SPV_AMD_shader_trinary_minmax" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "func" + OpExecutionMode %1 OriginUpperLeft + %void = OpTypeVoid + %3 = OpTypeFunction %void + %uint = OpTypeInt 32 0 + %float = OpTypeFloat 32 + %uint_3 = OpConstant %uint 3 + %1 = OpFunction %void None %3 + %6 = OpLabel + %7 = OpUndef %float + %8 = OpUndef %float + %9 = OpUndef %float + %10 = OpExtInst %float %ext FMin3AMD %7 %8 %9 + OpReturn + OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(AmdExtToKhrTest, ReplaceSMin3AMD) { + const std::string text = R"( +; CHECK: OpCapability Shader +; CHECK-NOT: OpExtension "SPV_AMD_shader_trinary_minmax" +; CHECK-NOT: OpExtInstImport "SPV_AMD_shader_trinary_minmax" +; CHECK: [[ext:%\w+]] = OpExtInstImport "GLSL.std.450" +; CHECK: [[type:%\w+]] = OpTypeInt 32 1 +; CHECK: OpFunction +; CHECK-NEXT: OpLabel +; CHECK-NEXT: [[x:%\w+]] = OpUndef [[type]] +; CHECK-NEXT: [[y:%\w+]] = OpUndef [[type]] +; CHECK-NEXT: [[z:%\w+]] = OpUndef [[type]] +; CHECK-NEXT: [[temp:%\w+]] = OpExtInst [[type]] [[ext]] SMin [[x]] [[y]] +; CHECK-NEXT: [[result:%\w+]] = OpExtInst [[type]] [[ext]] SMin [[temp]] [[z]] + OpCapability Shader + OpExtension "SPV_AMD_shader_trinary_minmax" + %ext = OpExtInstImport "SPV_AMD_shader_trinary_minmax" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "func" + OpExecutionMode %1 OriginUpperLeft + %void = OpTypeVoid + %3 = OpTypeFunction %void + %uint = OpTypeInt 32 0 + %int = OpTypeInt 32 1 + %float = OpTypeFloat 32 + %uint_3 = OpConstant %uint 3 + %1 = OpFunction %void None %3 + %6 = OpLabel + %7 = OpUndef %int + %8 = OpUndef %int + %9 = OpUndef %int + %10 = OpExtInst %int %ext SMin3AMD %7 %8 %9 + OpReturn + OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(AmdExtToKhrTest, ReplaceUMin3AMD) { + const std::string text = R"( +; CHECK: OpCapability Shader +; CHECK-NOT: OpExtension "SPV_AMD_shader_trinary_minmax" +; CHECK-NOT: OpExtInstImport "SPV_AMD_shader_trinary_minmax" +; CHECK: [[ext:%\w+]] = OpExtInstImport "GLSL.std.450" +; CHECK: [[type:%\w+]] = OpTypeInt 32 0 +; CHECK: OpFunction +; CHECK-NEXT: OpLabel +; CHECK-NEXT: [[x:%\w+]] = OpUndef [[type]] +; CHECK-NEXT: [[y:%\w+]] = OpUndef [[type]] +; CHECK-NEXT: [[z:%\w+]] = OpUndef [[type]] +; CHECK-NEXT: [[temp:%\w+]] = OpExtInst [[type]] [[ext]] UMin [[x]] [[y]] +; CHECK-NEXT: [[result:%\w+]] = OpExtInst [[type]] [[ext]] UMin [[temp]] [[z]] + OpCapability Shader + OpExtension "SPV_AMD_shader_trinary_minmax" + %ext = OpExtInstImport "SPV_AMD_shader_trinary_minmax" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "func" + OpExecutionMode %1 OriginUpperLeft + %void = OpTypeVoid + %3 = OpTypeFunction %void + %uint = OpTypeInt 32 0 + %int = OpTypeInt 32 1 + %float = OpTypeFloat 32 + %uint_3 = OpConstant %uint 3 + %1 = OpFunction %void None %3 + %6 = OpLabel + %7 = OpUndef %uint + %8 = OpUndef %uint + %9 = OpUndef %uint + %10 = OpExtInst %uint %ext UMin3AMD %7 %8 %9 + OpReturn + OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(AmdExtToKhrTest, ReplaceFMax3AMD) { + const std::string text = R"( +; CHECK: OpCapability Shader +; CHECK-NOT: OpExtension "SPV_AMD_shader_trinary_minmax" +; CHECK-NOT: OpExtInstImport "SPV_AMD_shader_trinary_minmax" +; CHECK: [[ext:%\w+]] = OpExtInstImport "GLSL.std.450" +; CHECK: [[type:%\w+]] = OpTypeFloat 32 +; CHECK: OpFunction +; CHECK-NEXT: OpLabel +; CHECK-NEXT: [[x:%\w+]] = OpUndef [[type]] +; CHECK-NEXT: [[y:%\w+]] = OpUndef [[type]] +; CHECK-NEXT: [[z:%\w+]] = OpUndef [[type]] +; CHECK-NEXT: [[temp:%\w+]] = OpExtInst [[type]] [[ext]] FMax [[x]] [[y]] +; CHECK-NEXT: [[result:%\w+]] = OpExtInst [[type]] [[ext]] FMax [[temp]] [[z]] + OpCapability Shader + OpExtension "SPV_AMD_shader_trinary_minmax" + %ext = OpExtInstImport "SPV_AMD_shader_trinary_minmax" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "func" + OpExecutionMode %1 OriginUpperLeft + %void = OpTypeVoid + %3 = OpTypeFunction %void + %uint = OpTypeInt 32 0 + %float = OpTypeFloat 32 + %uint_3 = OpConstant %uint 3 + %1 = OpFunction %void None %3 + %6 = OpLabel + %7 = OpUndef %float + %8 = OpUndef %float + %9 = OpUndef %float + %10 = OpExtInst %float %ext FMax3AMD %7 %8 %9 + OpReturn + OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(AmdExtToKhrTest, ReplaceSMax3AMD) { + const std::string text = R"( +; CHECK: OpCapability Shader +; CHECK-NOT: OpExtension "SPV_AMD_shader_trinary_minmax" +; CHECK-NOT: OpExtInstImport "SPV_AMD_shader_trinary_minmax" +; CHECK: [[ext:%\w+]] = OpExtInstImport "GLSL.std.450" +; CHECK: [[type:%\w+]] = OpTypeInt 32 1 +; CHECK: OpFunction +; CHECK-NEXT: OpLabel +; CHECK-NEXT: [[x:%\w+]] = OpUndef [[type]] +; CHECK-NEXT: [[y:%\w+]] = OpUndef [[type]] +; CHECK-NEXT: [[z:%\w+]] = OpUndef [[type]] +; CHECK-NEXT: [[temp:%\w+]] = OpExtInst [[type]] [[ext]] SMax [[x]] [[y]] +; CHECK-NEXT: [[result:%\w+]] = OpExtInst [[type]] [[ext]] SMax [[temp]] [[z]] + OpCapability Shader + OpExtension "SPV_AMD_shader_trinary_minmax" + %ext = OpExtInstImport "SPV_AMD_shader_trinary_minmax" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "func" + OpExecutionMode %1 OriginUpperLeft + %void = OpTypeVoid + %3 = OpTypeFunction %void + %uint = OpTypeInt 32 0 + %int = OpTypeInt 32 1 + %float = OpTypeFloat 32 + %uint_3 = OpConstant %uint 3 + %1 = OpFunction %void None %3 + %6 = OpLabel + %7 = OpUndef %int + %8 = OpUndef %int + %9 = OpUndef %int + %10 = OpExtInst %int %ext SMax3AMD %7 %8 %9 + OpReturn + OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(AmdExtToKhrTest, ReplaceUMax3AMD) { + const std::string text = R"( +; CHECK: OpCapability Shader +; CHECK-NOT: OpExtension "SPV_AMD_shader_trinary_minmax" +; CHECK-NOT: OpExtInstImport "SPV_AMD_shader_trinary_minmax" +; CHECK: [[ext:%\w+]] = OpExtInstImport "GLSL.std.450" +; CHECK: [[type:%\w+]] = OpTypeInt 32 0 +; CHECK: OpFunction +; CHECK-NEXT: OpLabel +; CHECK-NEXT: [[x:%\w+]] = OpUndef [[type]] +; CHECK-NEXT: [[y:%\w+]] = OpUndef [[type]] +; CHECK-NEXT: [[z:%\w+]] = OpUndef [[type]] +; CHECK-NEXT: [[temp:%\w+]] = OpExtInst [[type]] [[ext]] UMax [[x]] [[y]] +; CHECK-NEXT: [[result:%\w+]] = OpExtInst [[type]] [[ext]] UMax [[temp]] [[z]] + OpCapability Shader + OpExtension "SPV_AMD_shader_trinary_minmax" + %ext = OpExtInstImport "SPV_AMD_shader_trinary_minmax" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "func" + OpExecutionMode %1 OriginUpperLeft + %void = OpTypeVoid + %3 = OpTypeFunction %void + %uint = OpTypeInt 32 0 + %int = OpTypeInt 32 1 + %float = OpTypeFloat 32 + %uint_3 = OpConstant %uint 3 + %1 = OpFunction %void None %3 + %6 = OpLabel + %7 = OpUndef %uint + %8 = OpUndef %uint + %9 = OpUndef %uint + %10 = OpExtInst %uint %ext UMax3AMD %7 %8 %9 + OpReturn + OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(AmdExtToKhrTest, ReplaceVecUMax3AMD) { + const std::string text = R"( +; CHECK: OpCapability Shader +; CHECK-NOT: OpExtension "SPV_AMD_shader_trinary_minmax" +; CHECK-NOT: OpExtInstImport "SPV_AMD_shader_trinary_minmax" +; CHECK: [[ext:%\w+]] = OpExtInstImport "GLSL.std.450" +; CHECK: [[type:%\w+]] = OpTypeVector +; CHECK: OpFunction +; CHECK-NEXT: OpLabel +; CHECK-NEXT: [[x:%\w+]] = OpUndef [[type]] +; CHECK-NEXT: [[y:%\w+]] = OpUndef [[type]] +; CHECK-NEXT: [[z:%\w+]] = OpUndef [[type]] +; CHECK-NEXT: [[temp:%\w+]] = OpExtInst [[type]] [[ext]] UMax [[x]] [[y]] +; CHECK-NEXT: [[result:%\w+]] = OpExtInst [[type]] [[ext]] UMax [[temp]] [[z]] + OpCapability Shader + OpExtension "SPV_AMD_shader_trinary_minmax" + %ext = OpExtInstImport "SPV_AMD_shader_trinary_minmax" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "func" + OpExecutionMode %1 OriginUpperLeft + %void = OpTypeVoid + %3 = OpTypeFunction %void + %uint = OpTypeInt 32 0 + %vec = OpTypeVector %uint 4 + %int = OpTypeInt 32 1 + %float = OpTypeFloat 32 + %uint_3 = OpConstant %uint 3 + %1 = OpFunction %void None %3 + %6 = OpLabel + %7 = OpUndef %vec + %8 = OpUndef %vec + %9 = OpUndef %vec + %10 = OpExtInst %vec %ext UMax3AMD %7 %8 %9 + OpReturn + OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(AmdExtToKhrTest, ReplaceFMid3AMD) { + const std::string text = R"( +; CHECK: OpCapability Shader +; CHECK-NOT: OpExtension "SPV_AMD_shader_trinary_minmax" +; CHECK-NOT: OpExtInstImport "SPV_AMD_shader_trinary_minmax" +; CHECK: [[ext:%\w+]] = OpExtInstImport "GLSL.std.450" +; CHECK: [[type:%\w+]] = OpTypeFloat 32 +; CHECK: OpFunction +; CHECK-NEXT: OpLabel +; CHECK-NEXT: [[x:%\w+]] = OpUndef [[type]] +; CHECK-NEXT: [[y:%\w+]] = OpUndef [[type]] +; CHECK-NEXT: [[z:%\w+]] = OpUndef [[type]] +; CHECK-NEXT: [[min:%\w+]] = OpExtInst [[type]] [[ext]] FMin [[y]] [[z]] +; CHECK-NEXT: [[max:%\w+]] = OpExtInst [[type]] [[ext]] FMax [[y]] [[z]] +; CHECK-NEXT: [[result:%\w+]] = OpExtInst [[type]] [[ext]] FClamp [[x]] [[min]] [[max]] + OpCapability Shader + OpExtension "SPV_AMD_shader_trinary_minmax" + %ext = OpExtInstImport "SPV_AMD_shader_trinary_minmax" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "func" + OpExecutionMode %1 OriginUpperLeft + %void = OpTypeVoid + %3 = OpTypeFunction %void + %uint = OpTypeInt 32 0 + %float = OpTypeFloat 32 + %uint_3 = OpConstant %uint 3 + %1 = OpFunction %void None %3 + %6 = OpLabel + %7 = OpUndef %float + %8 = OpUndef %float + %9 = OpUndef %float + %10 = OpExtInst %float %ext FMid3AMD %7 %8 %9 + OpReturn + OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(AmdExtToKhrTest, ReplaceSMid3AMD) { + const std::string text = R"( +; CHECK: OpCapability Shader +; CHECK-NOT: OpExtension "SPV_AMD_shader_trinary_minmax" +; CHECK-NOT: OpExtInstImport "SPV_AMD_shader_trinary_minmax" +; CHECK: [[ext:%\w+]] = OpExtInstImport "GLSL.std.450" +; CHECK: [[type:%\w+]] = OpTypeInt 32 1 +; CHECK: OpFunction +; CHECK-NEXT: OpLabel +; CHECK-NEXT: [[x:%\w+]] = OpUndef [[type]] +; CHECK-NEXT: [[y:%\w+]] = OpUndef [[type]] +; CHECK-NEXT: [[z:%\w+]] = OpUndef [[type]] +; CHECK-NEXT: [[min:%\w+]] = OpExtInst [[type]] [[ext]] SMin [[y]] [[z]] +; CHECK-NEXT: [[max:%\w+]] = OpExtInst [[type]] [[ext]] SMax [[y]] [[z]] +; CHECK-NEXT: [[result:%\w+]] = OpExtInst [[type]] [[ext]] SClamp [[x]] [[min]] [[max]] + OpCapability Shader + OpExtension "SPV_AMD_shader_trinary_minmax" + %ext = OpExtInstImport "SPV_AMD_shader_trinary_minmax" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "func" + OpExecutionMode %1 OriginUpperLeft + %void = OpTypeVoid + %3 = OpTypeFunction %void + %uint = OpTypeInt 32 0 + %int = OpTypeInt 32 1 + %float = OpTypeFloat 32 + %uint_3 = OpConstant %uint 3 + %1 = OpFunction %void None %3 + %6 = OpLabel + %7 = OpUndef %int + %8 = OpUndef %int + %9 = OpUndef %int + %10 = OpExtInst %int %ext SMid3AMD %7 %8 %9 + OpReturn + OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(AmdExtToKhrTest, ReplaceUMid3AMD) { + const std::string text = R"( +; CHECK: OpCapability Shader +; CHECK-NOT: OpExtension "SPV_AMD_shader_trinary_minmax" +; CHECK-NOT: OpExtInstImport "SPV_AMD_shader_trinary_minmax" +; CHECK: [[ext:%\w+]] = OpExtInstImport "GLSL.std.450" +; CHECK: [[type:%\w+]] = OpTypeInt 32 0 +; CHECK: OpFunction +; CHECK-NEXT: OpLabel +; CHECK-NEXT: [[x:%\w+]] = OpUndef [[type]] +; CHECK-NEXT: [[y:%\w+]] = OpUndef [[type]] +; CHECK-NEXT: [[z:%\w+]] = OpUndef [[type]] +; CHECK-NEXT: [[min:%\w+]] = OpExtInst [[type]] [[ext]] UMin [[y]] [[z]] +; CHECK-NEXT: [[max:%\w+]] = OpExtInst [[type]] [[ext]] UMax [[y]] [[z]] +; CHECK-NEXT: [[result:%\w+]] = OpExtInst [[type]] [[ext]] UClamp [[x]] [[min]] [[max]] + OpCapability Shader + OpExtension "SPV_AMD_shader_trinary_minmax" + %ext = OpExtInstImport "SPV_AMD_shader_trinary_minmax" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "func" + OpExecutionMode %1 OriginUpperLeft + %void = OpTypeVoid + %3 = OpTypeFunction %void + %uint = OpTypeInt 32 0 + %int = OpTypeInt 32 1 + %float = OpTypeFloat 32 + %uint_3 = OpConstant %uint 3 + %1 = OpFunction %void None %3 + %6 = OpLabel + %7 = OpUndef %uint + %8 = OpUndef %uint + %9 = OpUndef %uint + %10 = OpExtInst %uint %ext UMid3AMD %7 %8 %9 + OpReturn + OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(AmdExtToKhrTest, ReplaceVecUMid3AMD) { + const std::string text = R"( +; CHECK: OpCapability Shader +; CHECK-NOT: OpExtension "SPV_AMD_shader_trinary_minmax" +; CHECK-NOT: OpExtInstImport "SPV_AMD_shader_trinary_minmax" +; CHECK: [[ext:%\w+]] = OpExtInstImport "GLSL.std.450" +; CHECK: [[type:%\w+]] = OpTypeVector +; CHECK: OpFunction +; CHECK-NEXT: OpLabel +; CHECK-NEXT: [[x:%\w+]] = OpUndef [[type]] +; CHECK-NEXT: [[y:%\w+]] = OpUndef [[type]] +; CHECK-NEXT: [[z:%\w+]] = OpUndef [[type]] +; CHECK-NEXT: [[min:%\w+]] = OpExtInst [[type]] [[ext]] UMin [[y]] [[z]] +; CHECK-NEXT: [[max:%\w+]] = OpExtInst [[type]] [[ext]] UMax [[y]] [[z]] +; CHECK-NEXT: [[result:%\w+]] = OpExtInst [[type]] [[ext]] UClamp [[x]] [[min]] [[max]] + OpCapability Shader + OpExtension "SPV_AMD_shader_trinary_minmax" + %ext = OpExtInstImport "SPV_AMD_shader_trinary_minmax" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "func" + OpExecutionMode %1 OriginUpperLeft + %void = OpTypeVoid + %3 = OpTypeFunction %void + %uint = OpTypeInt 32 0 + %vec = OpTypeVector %uint 3 + %int = OpTypeInt 32 1 + %float = OpTypeFloat 32 + %uint_3 = OpConstant %uint 3 + %1 = OpFunction %void None %3 + %6 = OpLabel + %7 = OpUndef %vec + %8 = OpUndef %vec + %9 = OpUndef %vec + %10 = OpExtInst %vec %ext UMid3AMD %7 %8 %9 + OpReturn + OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(AmdExtToKhrTest, ReplaceCubeFaceCoordAMD) { + // Sorry for the Check test. The code sequence is so long, I do not think + // that a match test would be anymore legible. This tests the replacement of + // the CubeFaceCoordAMD instruction. + const std::string before = R"( + OpCapability Shader + OpExtension "SPV_KHR_storage_buffer_storage_class" + OpExtension "SPV_AMD_gcn_shader" + %1 = OpExtInstImport "SPV_AMD_gcn_shader" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %2 "main" + OpExecutionMode %2 LocalSize 1 1 1 + %void = OpTypeVoid + %4 = OpTypeFunction %void + %float = OpTypeFloat 32 + %v2float = OpTypeVector %float 2 + %v3float = OpTypeVector %float 3 + %2 = OpFunction %void None %4 + %8 = OpLabel + %9 = OpUndef %v3float + %10 = OpExtInst %v2float %1 CubeFaceCoordAMD %9 + OpReturn + OpFunctionEnd +)"; + + const std::string after = R"(OpCapability Shader +OpExtension "SPV_KHR_storage_buffer_storage_class" +%12 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %2 "main" +OpExecutionMode %2 LocalSize 1 1 1 +%void = OpTypeVoid +%4 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v2float = OpTypeVector %float 2 +%v3float = OpTypeVector %float 3 +%bool = OpTypeBool +%float_0 = OpConstant %float 0 +%float_2 = OpConstant %float 2 +%float_0_5 = OpConstant %float 0.5 +%16 = OpConstantComposite %v2float %float_0_5 %float_0_5 +%2 = OpFunction %void None %4 +%8 = OpLabel +%9 = OpUndef %v3float +%17 = OpCompositeExtract %float %9 0 +%18 = OpCompositeExtract %float %9 1 +%19 = OpCompositeExtract %float %9 2 +%20 = OpFNegate %float %17 +%21 = OpFNegate %float %18 +%22 = OpFNegate %float %19 +%23 = OpExtInst %float %12 FAbs %17 +%24 = OpExtInst %float %12 FAbs %18 +%25 = OpExtInst %float %12 FAbs %19 +%26 = OpFOrdLessThan %bool %19 %float_0 +%27 = OpFOrdLessThan %bool %18 %float_0 +%28 = OpFOrdLessThan %bool %17 %float_0 +%29 = OpExtInst %float %12 FMax %23 %24 +%30 = OpExtInst %float %12 FMax %25 %29 +%31 = OpFMul %float %float_2 %30 +%32 = OpFOrdGreaterThanEqual %bool %25 %29 +%33 = OpLogicalNot %bool %32 +%34 = OpFOrdGreaterThanEqual %bool %24 %23 +%35 = OpLogicalAnd %bool %33 %34 +%36 = OpSelect %float %26 %20 %17 +%37 = OpSelect %float %28 %19 %22 +%38 = OpSelect %float %35 %17 %37 +%39 = OpSelect %float %32 %36 %38 +%40 = OpSelect %float %27 %22 %19 +%41 = OpSelect %float %35 %40 %21 +%42 = OpCompositeConstruct %v2float %39 %41 +%43 = OpCompositeConstruct %v2float %31 %31 +%44 = OpFDiv %v2float %42 %43 +%10 = OpFAdd %v2float %44 %16 +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndCheck(before, after, true); +} + +TEST_F(AmdExtToKhrTest, ReplaceCubeFaceIndexAMD) { + // Sorry for the Check test. The code sequence is so long, I do not think + // that a match test would be anymore legible. This tests the replacement of + // the CubeFaceIndexAMD instruction. + const std::string before = R"(OpCapability Shader +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpExtension "SPV_AMD_gcn_shader" +%1 = OpExtInstImport "SPV_AMD_gcn_shader" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %2 "main" +OpExecutionMode %2 LocalSize 1 1 1 +%void = OpTypeVoid +%4 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v3float = OpTypeVector %float 3 +%2 = OpFunction %void None %4 +%7 = OpLabel +%8 = OpUndef %v3float +%9 = OpExtInst %float %1 CubeFaceIndexAMD %8 +OpReturn +OpFunctionEnd +)"; + + const std::string after = R"(OpCapability Shader +OpExtension "SPV_KHR_storage_buffer_storage_class" +%11 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %2 "main" +OpExecutionMode %2 LocalSize 1 1 1 +%void = OpTypeVoid +%4 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v3float = OpTypeVector %float 3 +%bool = OpTypeBool +%float_0 = OpConstant %float 0 +%float_1 = OpConstant %float 1 +%float_2 = OpConstant %float 2 +%float_3 = OpConstant %float 3 +%float_4 = OpConstant %float 4 +%float_5 = OpConstant %float 5 +%2 = OpFunction %void None %4 +%7 = OpLabel +%8 = OpUndef %v3float +%18 = OpCompositeExtract %float %8 0 +%19 = OpCompositeExtract %float %8 1 +%20 = OpCompositeExtract %float %8 2 +%21 = OpExtInst %float %11 FAbs %18 +%22 = OpExtInst %float %11 FAbs %19 +%23 = OpExtInst %float %11 FAbs %20 +%24 = OpFOrdLessThan %bool %20 %float_0 +%25 = OpFOrdLessThan %bool %19 %float_0 +%26 = OpFOrdLessThan %bool %18 %float_0 +%27 = OpExtInst %float %11 FMax %21 %22 +%28 = OpFOrdGreaterThanEqual %bool %23 %27 +%29 = OpFOrdGreaterThanEqual %bool %22 %21 +%30 = OpSelect %float %24 %float_5 %float_4 +%31 = OpSelect %float %25 %float_3 %float_2 +%32 = OpSelect %float %26 %float_1 %float_0 +%33 = OpSelect %float %29 %31 %32 +%9 = OpSelect %float %28 %30 %33 +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndCheck(before, after, true); +} + +TEST_F(AmdExtToKhrTest, SetVersion) { + const std::string text = R"( + OpCapability Shader + OpCapability Int64 + OpExtension "SPV_AMD_shader_ballot" + %1 = OpExtInstImport "SPV_AMD_shader_ballot" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "func" + OpExecutionMode %2 OriginUpperLeft + %void = OpTypeVoid + %4 = OpTypeFunction %void + %uint = OpTypeInt 32 0 + %ulong = OpTypeInt 64 0 + %ulong_0 = OpConstant %ulong 0 + %2 = OpFunction %void None %4 + %8 = OpLabel + %9 = OpExtInst %uint %1 MbcntAMD %ulong_0 + OpReturn + OpFunctionEnd +)"; + + // Set the version to 1.1 and make sure it is upgraded to 1.3. + SetTargetEnv(SPV_ENV_UNIVERSAL_1_1); + SetDisassembleOptions(0); + auto result = SinglePassRunAndDisassemble( + text, /* skip_nop = */ true, /* skip_validation = */ false); + + EXPECT_EQ(Pass::Status::SuccessWithChange, std::get<1>(result)); + const std::string& output = std::get<0>(result); + EXPECT_THAT(output, HasSubstr("Version: 1.3")); +} + +TEST_F(AmdExtToKhrTest, SetVersion1) { + const std::string text = R"( + OpCapability Shader + OpCapability Int64 + OpExtension "SPV_AMD_shader_ballot" + %1 = OpExtInstImport "SPV_AMD_shader_ballot" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "func" + OpExecutionMode %2 OriginUpperLeft + %void = OpTypeVoid + %4 = OpTypeFunction %void + %uint = OpTypeInt 32 0 + %ulong = OpTypeInt 64 0 + %ulong_0 = OpConstant %ulong 0 + %2 = OpFunction %void None %4 + %8 = OpLabel + %9 = OpExtInst %uint %1 MbcntAMD %ulong_0 + OpReturn + OpFunctionEnd +)"; + + // Set the version to 1.4 and make sure it is stays the same. + SetTargetEnv(SPV_ENV_UNIVERSAL_1_4); + SetDisassembleOptions(0); + auto result = SinglePassRunAndDisassemble( + text, /* skip_nop = */ true, /* skip_validation = */ false); + + EXPECT_EQ(Pass::Status::SuccessWithChange, std::get<1>(result)); + const std::string& output = std::get<0>(result); + EXPECT_THAT(output, HasSubstr("Version: 1.4")); +} + +TEST_F(AmdExtToKhrTest, TimeAMD) { + const std::string text = R"( + OpCapability Shader + OpCapability Int64 + OpExtension "SPV_AMD_gcn_shader" +; CHECK-NOT: OpExtension "SPV_AMD_gcn_shader" +; CHECK: OpExtension "SPV_KHR_shader_clock" + %1 = OpExtInstImport "GLSL.std.450" + %2 = OpExtInstImport "SPV_AMD_gcn_shader" +; CHECK-NOT: OpExtInstImport "SPV_AMD_gcn_shader" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" + OpExecutionMode %main OriginUpperLeft + OpSource GLSL 450 + OpSourceExtension "GL_AMD_gcn_shader" + OpSourceExtension "GL_ARB_gpu_shader_int64" + OpName %main "main" + OpName %time "time" + %void = OpTypeVoid + %6 = OpTypeFunction %void + %ulong = OpTypeInt 64 0 +%_ptr_Function_ulong = OpTypePointer Function %ulong + %main = OpFunction %void None %6 + %9 = OpLabel + %time = OpVariable %_ptr_Function_ulong Function +; CHECK: [[uint:%\w+]] = OpTypeInt 32 0 +; CHECK: [[uint_3:%\w+]] = OpConstant [[uint]] 3 + %10 = OpExtInst %ulong %2 TimeAMD +; CHECK: %10 = OpReadClockKHR %ulong [[uint_3]] + OpStore %time %10 + OpReturn + OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} +} // namespace +} // namespace opt +} // namespace spvtools diff --git a/third_party/spirv-tools/test/opt/block_merge_test.cpp b/third_party/spirv-tools/test/opt/block_merge_test.cpp index aaa70cd4a7..f1460c5f79 100644 --- a/third_party/spirv-tools/test/opt/block_merge_test.cpp +++ b/third_party/spirv-tools/test/opt/block_merge_test.cpp @@ -273,7 +273,6 @@ OpFunctionEnd true); } -#ifdef SPIRV_EFFCEE TEST_F(BlockMergeTest, PhiInSuccessorOfMergedBlock) { const std::string text = R"( ; CHECK: OpSelectionMerge [[merge:%\w+]] None @@ -287,6 +286,7 @@ TEST_F(BlockMergeTest, PhiInSuccessorOfMergedBlock) { OpCapability Shader OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft %void = OpTypeVoid %bool = OpTypeBool %true = OpConstantTrue %bool @@ -324,6 +324,7 @@ TEST_F(BlockMergeTest, UpdateMergeInstruction) { OpCapability Shader OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft %void = OpTypeVoid %bool = OpTypeBool %true = OpConstantTrue %bool @@ -358,6 +359,7 @@ TEST_F(BlockMergeTest, TwoMergeBlocksCannotBeMerged) { OpCapability Shader OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft %void = OpTypeVoid %bool = OpTypeBool %true = OpConstantTrue %bool @@ -398,6 +400,7 @@ TEST_F(BlockMergeTest, MergeContinue) { OpCapability Shader OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft %void = OpTypeVoid %bool = OpTypeBool %true = OpConstantTrue %bool @@ -420,6 +423,42 @@ OpFunctionEnd SinglePassRunAndMatch(text, true); } +TEST_F(BlockMergeTest, MergeContinueWithOpLine) { + const std::string text = R"( +; CHECK: OpBranch [[header:%\w+]] +; CHECK: [[header]] = OpLabel +; CHECK-NEXT: OpLogicalAnd +; CHECK-NEXT: OpLine {{%\w+}} 1 1 +; CHECK-NEXT: OpLoopMerge {{%\w+}} [[header]] None +; CHECK-NEXT: OpBranch [[header]] +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +%src = OpString "test.shader" +%void = OpTypeVoid +%bool = OpTypeBool +%true = OpConstantTrue %bool +%false = OpConstantFalse %bool +%functy = OpTypeFunction %void +%func = OpFunction %void None %functy +%entry = OpLabel +OpBranch %header +%header = OpLabel +OpLoopMerge %merge %continue None +OpBranch %continue +%continue = OpLabel +%op = OpLogicalAnd %bool %true %false +OpLine %src 1 1 +OpBranch %header +%merge = OpLabel +OpUnreachable +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + TEST_F(BlockMergeTest, TwoHeadersCannotBeMerged) { const std::string text = R"( ; CHECK: OpBranch [[loop_header:%\w+]] @@ -431,6 +470,7 @@ TEST_F(BlockMergeTest, TwoHeadersCannotBeMerged) { OpCapability Shader OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft %void = OpTypeVoid %bool = OpTypeBool %true = OpConstantTrue %bool @@ -443,10 +483,53 @@ OpBranch %header OpLoopMerge %merge %continue None OpBranch %inner_header %inner_header = OpLabel -OpSelectionMerge %continue None -OpBranchConditional %true %then %continue +OpSelectionMerge %if_merge None +OpBranchConditional %true %then %if_merge %then = OpLabel OpBranch %continue +%if_merge = OpLabel +OpBranch %continue +%continue = OpLabel +OpBranchConditional %false %merge %header +%merge = OpLabel +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(BlockMergeTest, CannotMergeContinue) { + const std::string text = R"( +; CHECK: OpBranch [[loop_header:%\w+]] +; CHECK: [[loop_header]] = OpLabel +; CHECK-NEXT: OpLoopMerge {{%\w+}} [[continue:%\w+]] +; CHECK-NEXT: OpBranchConditional {{%\w+}} [[if_header:%\w+]] +; CHECK: [[if_header]] = OpLabel +; CHECK-NEXT: OpSelectionMerge +; CHECK: [[continue]] = OpLabel +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +%void = OpTypeVoid +%bool = OpTypeBool +%true = OpConstantTrue %bool +%false = OpConstantFalse %bool +%functy = OpTypeFunction %void +%func = OpFunction %void None %functy +%entry = OpLabel +OpBranch %header +%header = OpLabel +OpLoopMerge %merge %continue None +OpBranchConditional %true %inner_header %merge +%inner_header = OpLabel +OpSelectionMerge %if_merge None +OpBranchConditional %true %then %if_merge +%then = OpLabel +OpBranch %continue +%if_merge = OpLabel +OpBranch %continue %continue = OpLabel OpBranchConditional %false %merge %header %merge = OpLabel @@ -479,6 +562,8 @@ TEST_F(BlockMergeTest, RemoveStructuredDeclaration) { ; CHECK-NOT: OpLoopMerge ; CHECK: OpReturn ; CHECK: [[continue:%\w+]] = OpLabel +; CHECK-NEXT: OpBranch [[block:%\w+]] +; CHECK: [[block]] = OpLabel ; CHECK-NEXT: OpBranch [[header]] OpCapability Shader %1 = OpExtInstImport "GLSL.std.450" @@ -532,6 +617,7 @@ TEST_F(BlockMergeTest, DontMergeKill) { OpCapability Shader OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft %void = OpTypeVoid %bool = OpTypeBool %functy = OpTypeFunction %void @@ -564,6 +650,7 @@ TEST_F(BlockMergeTest, DontMergeUnreachable) { OpCapability Shader OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft %void = OpTypeVoid %bool = OpTypeBool %functy = OpTypeFunction %void @@ -582,7 +669,7 @@ OpUnreachable OpFunctionEnd )"; - SinglePassRunAndMatch(text, true); + SinglePassRunAndMatch(text, false); } TEST_F(BlockMergeTest, DontMergeReturn) { @@ -596,6 +683,7 @@ TEST_F(BlockMergeTest, DontMergeReturn) { OpCapability Shader OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft %void = OpTypeVoid %bool = OpTypeBool %functy = OpTypeFunction %void @@ -628,6 +716,7 @@ TEST_F(BlockMergeTest, DontMergeSwitch) { OpCapability Shader OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft %void = OpTypeVoid %bool = OpTypeBool %int = OpTypeInt 32 1 @@ -664,6 +753,7 @@ TEST_F(BlockMergeTest, DontMergeReturnValue) { OpCapability Shader OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft %void = OpTypeVoid %bool = OpTypeBool %functy = OpTypeFunction %void @@ -691,7 +781,226 @@ OpFunctionEnd SinglePassRunAndMatch(text, true); } -#endif // SPIRV_EFFCEE + +TEST_F(BlockMergeTest, MergeHeaders) { + // Merge two headers when the second is the merge block of the first. + const std::string text = R"( +; CHECK: OpFunction +; CHECK-NEXT: OpLabel +; CHECK-NEXT: OpBranch [[header:%\w+]] +; CHECK-NEXT: [[header]] = OpLabel +; CHECK-NEXT: OpSelectionMerge [[merge:%\w+]] +; CHECK: [[merge]] = OpLabel +; CHEKC: OpReturn +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +%void = OpTypeVoid +%bool = OpTypeBool +%functy = OpTypeFunction %void +%otherfuncty = OpTypeFunction %bool +%true = OpConstantTrue %bool +%func = OpFunction %void None %functy +%1 = OpLabel +OpBranch %5 +%5 = OpLabel +OpLoopMerge %8 %7 None +OpBranch %8 +%7 = OpLabel +OpBranch %5 +%8 = OpLabel +OpSelectionMerge %m None +OpBranchConditional %true %a %m +%a = OpLabel +OpBranch %m +%m = OpLabel +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(BlockMergeTest, OpPhiInSuccessor) { + // Checks that when merging blocks A and B, the OpPhi at the start of B is + // removed and uses of its definition are replaced appropriately. + const std::string prefix = + R"(OpCapability Shader +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpSource ESSL 310 +OpName %main "main" +OpName %x "x" +OpName %y "y" +%void = OpTypeVoid +%6 = OpTypeFunction %void +%int = OpTypeInt 32 1 +%_ptr_Function_int = OpTypePointer Function %int +%int_1 = OpConstant %int 1 +%main = OpFunction %void None %6 +%10 = OpLabel +%x = OpVariable %_ptr_Function_int Function +%y = OpVariable %_ptr_Function_int Function +OpStore %x %int_1 +%11 = OpLoad %int %x +)"; + + const std::string suffix_before = + R"(OpBranch %12 +%12 = OpLabel +%13 = OpPhi %int %11 %10 +OpStore %y %13 +OpReturn +OpFunctionEnd +)"; + + const std::string suffix_after = + R"(OpStore %y %11 +OpReturn +OpFunctionEnd +)"; + SinglePassRunAndCheck(prefix + suffix_before, + prefix + suffix_after, true, true); +} + +TEST_F(BlockMergeTest, MultipleOpPhisInSuccessor) { + // Checks that when merging blocks A and B, the OpPhis at the start of B are + // removed and uses of their definitions are replaced appropriately. + const std::string prefix = + R"(OpCapability Shader +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpSource ESSL 310 +OpName %main "main" +OpName %S "S" +OpMemberName %S 0 "x" +OpMemberName %S 1 "f" +OpName %s "s" +OpName %g "g" +OpName %y "y" +OpName %t "t" +OpName %z "z" +%void = OpTypeVoid +%10 = OpTypeFunction %void +%int = OpTypeInt 32 1 +%float = OpTypeFloat 32 +%S = OpTypeStruct %int %float +%_ptr_Function_S = OpTypePointer Function %S +%int_1 = OpConstant %int 1 +%float_2 = OpConstant %float 2 +%16 = OpConstantComposite %S %int_1 %float_2 +%_ptr_Function_float = OpTypePointer Function %float +%_ptr_Function_int = OpTypePointer Function %int +%int_3 = OpConstant %int 3 +%int_0 = OpConstant %int 0 +%main = OpFunction %void None %10 +%21 = OpLabel +%s = OpVariable %_ptr_Function_S Function +%g = OpVariable %_ptr_Function_float Function +%y = OpVariable %_ptr_Function_int Function +%t = OpVariable %_ptr_Function_S Function +%z = OpVariable %_ptr_Function_float Function +OpStore %s %16 +OpStore %g %float_2 +OpStore %y %int_3 +%22 = OpLoad %S %s +OpStore %t %22 +%23 = OpAccessChain %_ptr_Function_float %s %int_1 +%24 = OpLoad %float %23 +%25 = OpLoad %float %g +)"; + + const std::string suffix_before = + R"(OpBranch %26 +%26 = OpLabel +%27 = OpPhi %float %24 %21 +%28 = OpPhi %float %25 %21 +%29 = OpFAdd %float %27 %28 +%30 = OpAccessChain %_ptr_Function_int %s %int_0 +%31 = OpLoad %int %30 +OpBranch %32 +%32 = OpLabel +%33 = OpPhi %float %29 %26 +%34 = OpPhi %int %31 %26 +%35 = OpConvertSToF %float %34 +OpBranch %36 +%36 = OpLabel +%37 = OpPhi %float %35 %32 +%38 = OpFSub %float %33 %37 +%39 = OpLoad %int %y +OpBranch %40 +%40 = OpLabel +%41 = OpPhi %float %38 %36 +%42 = OpPhi %int %39 %36 +%43 = OpConvertSToF %float %42 +%44 = OpFAdd %float %41 %43 +OpStore %z %44 +OpReturn +OpFunctionEnd +)"; + + const std::string suffix_after = + R"(%29 = OpFAdd %float %24 %25 +%30 = OpAccessChain %_ptr_Function_int %s %int_0 +%31 = OpLoad %int %30 +%35 = OpConvertSToF %float %31 +%38 = OpFSub %float %29 %35 +%39 = OpLoad %int %y +%43 = OpConvertSToF %float %39 +%44 = OpFAdd %float %38 %43 +OpStore %z %44 +OpReturn +OpFunctionEnd +)"; + SinglePassRunAndCheck(prefix + suffix_before, + prefix + suffix_after, true, true); +} + +TEST_F(BlockMergeTest, UnreachableLoop) { + const std::string spirv = R"(OpCapability Shader +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpSource ESSL 310 +OpName %main "main" +%void = OpTypeVoid +%4 = OpTypeFunction %void +%int = OpTypeInt 32 1 +%_ptr_Function_int = OpTypePointer Function %int +%bool = OpTypeBool +%false = OpConstantFalse %bool +%main = OpFunction %void None %4 +%9 = OpLabel +OpBranch %10 +%11 = OpLabel +OpLoopMerge %12 %13 None +OpBranchConditional %false %13 %14 +%13 = OpLabel +OpSelectionMerge %15 None +OpBranchConditional %false %16 %17 +%16 = OpLabel +OpBranch %15 +%17 = OpLabel +OpBranch %15 +%15 = OpLabel +OpBranch %11 +%14 = OpLabel +OpReturn +%12 = OpLabel +OpBranch %10 +%10 = OpLabel +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndCheck(spirv, spirv, true, true); +} // TODO(greg-lunarg): Add tests to verify handling of these cases: // diff --git a/third_party/spirv-tools/test/opt/ccp_test.cpp b/third_party/spirv-tools/test/opt/ccp_test.cpp index 5ccea71fba..920c0f4d5b 100644 --- a/third_party/spirv-tools/test/opt/ccp_test.cpp +++ b/third_party/spirv-tools/test/opt/ccp_test.cpp @@ -26,8 +26,6 @@ namespace { using CCPTest = PassTest<::testing::Test>; -// TODO(dneto): Add Effcee as required dependency, and make this unconditional. -#ifdef SPIRV_EFFCEE TEST_F(CCPTest, PropagateThroughPhis) { const std::string spv_asm = R"( OpCapability Shader @@ -572,10 +570,10 @@ TEST_F(CCPTest, SkipSpecConstantInstrucitons) { %10 = OpSpecConstantFalse %bool %main = OpFunction %void None %4 %11 = OpLabel - %12 = OpBranchConditional %10 %l1 %l2 - %l1 = OpLabel + OpBranchConditional %10 %L1 %L2 + %L1 = OpLabel OpReturn - %l2 = OpLabel + %L2 = OpLabel OpReturn OpFunctionEnd )"; @@ -589,6 +587,7 @@ TEST_F(CCPTest, UpdateSubsequentPhisToVarying) { OpCapability Shader OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %func "func" %in +OpExecutionMode %func OriginUpperLeft %void = OpTypeVoid %bool = OpTypeBool %int = OpTypeInt 32 1 @@ -743,6 +742,7 @@ TEST_F(CCPTest, NullBranchCondition) { OpCapability Shader OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft %void = OpTypeVoid %bool = OpTypeBool %int = OpTypeInt 32 1 @@ -774,6 +774,7 @@ TEST_F(CCPTest, UndefBranchCondition) { OpCapability Shader OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft %void = OpTypeVoid %bool = OpTypeBool %int = OpTypeInt 32 1 @@ -805,6 +806,7 @@ TEST_F(CCPTest, NullSwitchCondition) { OpCapability Shader OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft %void = OpTypeVoid %int = OpTypeInt 32 1 %null = OpConstantNull %int @@ -835,6 +837,7 @@ TEST_F(CCPTest, UndefSwitchCondition) { OpCapability Shader OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft %void = OpTypeVoid %int = OpTypeInt 32 1 %undef = OpUndef %int @@ -865,6 +868,7 @@ TEST_F(CCPTest, CompositeConstructOfGlobalValue) { OpCapability Shader OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %func "func" %in +OpExecutionMode %func OriginUpperLeft %void = OpTypeVoid %int = OpTypeInt 32 1 %bool = OpTypeBool @@ -891,7 +895,35 @@ OpFunctionEnd SinglePassRunAndMatch(text, true); } -#endif + +TEST_F(CCPTest, FoldWithDecoration) { + const std::string text = R"( +; CHECK: OpCapability +; CHECK-NOT: OpDecorate +; CHECK: OpFunctionEnd + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpSource ESSL 310 + OpDecorate %3 RelaxedPrecision + %void = OpTypeVoid + %5 = OpTypeFunction %void + %float = OpTypeFloat 32 + %v3float = OpTypeVector %float 3 + %float_0 = OpConstant %float 0 + %v4float = OpTypeVector %float 4 + %10 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0 + %2 = OpFunction %void None %5 + %11 = OpLabel + %3 = OpVectorShuffle %v3float %10 %10 0 1 2 + OpReturn + OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} } // namespace } // namespace opt diff --git a/third_party/spirv-tools/test/opt/cfg_cleanup_test.cpp b/third_party/spirv-tools/test/opt/cfg_cleanup_test.cpp index 369c766706..3498f00bb1 100644 --- a/third_party/spirv-tools/test/opt/cfg_cleanup_test.cpp +++ b/third_party/spirv-tools/test/opt/cfg_cleanup_test.cpp @@ -91,6 +91,7 @@ TEST_F(CFGCleanupTest, RemoveDecorations) { %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %main "main" + OpExecutionMode %main OriginUpperLeft OpName %main "main" OpName %x "x" OpName %dead "dead" @@ -123,6 +124,7 @@ TEST_F(CFGCleanupTest, RemoveDecorations) { %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft OpName %main "main" OpName %x "x" OpDecorate %x RelaxedPrecision @@ -153,6 +155,7 @@ TEST_F(CFGCleanupTest, UpdatePhis) { %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %main "main" %y %outparm + OpExecutionMode %main OriginUpperLeft OpName %main "main" OpName %y "y" OpName %outparm "outparm" @@ -194,6 +197,7 @@ TEST_F(CFGCleanupTest, UpdatePhis) { %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %main "main" %y %outparm +OpExecutionMode %main OriginUpperLeft OpName %main "main" OpName %y "y" OpName %outparm "outparm" @@ -272,6 +276,7 @@ TEST_F(CFGCleanupTest, RemovePhiArgsFromFarBlocks) { %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %main "main" %y %outparm + OpExecutionMode %main OriginUpperLeft OpName %main "main" OpName %y "y" OpName %outparm "outparm" @@ -319,6 +324,7 @@ TEST_F(CFGCleanupTest, RemovePhiArgsFromFarBlocks) { %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %main "main" %y %outparm +OpExecutionMode %main OriginUpperLeft OpName %main "main" OpName %y "y" OpName %outparm "outparm" @@ -370,6 +376,7 @@ TEST_F(CFGCleanupTest, RemovePhiConstantArgs) { %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %main "main" %y %outparm + OpExecutionMode %main OriginUpperLeft OpName %main "main" OpName %y "y" OpName %outparm "outparm" @@ -410,6 +417,7 @@ TEST_F(CFGCleanupTest, RemovePhiConstantArgs) { %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %main "main" %y %outparm +OpExecutionMode %main OriginUpperLeft OpName %main "main" OpName %y "y" OpName %outparm "outparm" diff --git a/third_party/spirv-tools/test/opt/cfg_test.cpp b/third_party/spirv-tools/test/opt/cfg_test.cpp new file mode 100644 index 0000000000..2cfc9f374e --- /dev/null +++ b/third_party/spirv-tools/test/opt/cfg_test.cpp @@ -0,0 +1,205 @@ +// Copyright (c) 2019 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 + +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include "source/opt/ir_context.h" +#include "test/opt/pass_fixture.h" +#include "test/opt/pass_utils.h" + +namespace spvtools { +namespace opt { +namespace { + +using ::testing::ContainerEq; + +using CFGTest = PassTest<::testing::Test>; + +TEST_F(CFGTest, ForEachBlockInPostOrderIf) { + const std::string test = R"( +OpCapability Shader +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Vertex %main "main" +OpName %main "main" +%bool = OpTypeBool +%true = OpConstantTrue %bool +%void = OpTypeVoid +%4 = OpTypeFunction %void +%uint = OpTypeInt 32 0 +%5 = OpConstant %uint 5 +%main = OpFunction %void None %4 +%8 = OpLabel +OpSelectionMerge %10 None +OpBranchConditional %true %9 %10 +%9 = OpLabel +OpBranch %10 +%10 = OpLabel +OpReturn +OpFunctionEnd +)"; + + std::unique_ptr context = + BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, test, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + ASSERT_NE(nullptr, context); + + CFG* cfg = context->cfg(); + Module* module = context->module(); + Function* function = &*module->begin(); + std::vector order; + cfg->ForEachBlockInPostOrder(&*function->begin(), [&order](BasicBlock* bb) { + order.push_back(bb->id()); + }); + + std::vector expected_result = {10, 9, 8}; + EXPECT_THAT(order, ContainerEq(expected_result)); +} + +TEST_F(CFGTest, ForEachBlockInPostOrderLoop) { + const std::string test = R"( +OpCapability Shader +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Vertex %main "main" +OpName %main "main" +%bool = OpTypeBool +%true = OpConstantTrue %bool +%void = OpTypeVoid +%4 = OpTypeFunction %void +%uint = OpTypeInt 32 0 +%5 = OpConstant %uint 5 +%main = OpFunction %void None %4 +%8 = OpLabel +OpBranch %9 +%9 = OpLabel +OpLoopMerge %11 %10 None +OpBranchConditional %true %11 %10 +%10 = OpLabel +OpBranch %9 +%11 = OpLabel +OpReturn +OpFunctionEnd +)"; + + std::unique_ptr context = + BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, test, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + ASSERT_NE(nullptr, context); + + CFG* cfg = context->cfg(); + Module* module = context->module(); + Function* function = &*module->begin(); + std::vector order; + cfg->ForEachBlockInPostOrder(&*function->begin(), [&order](BasicBlock* bb) { + order.push_back(bb->id()); + }); + + std::vector expected_result1 = {10, 11, 9, 8}; + std::vector expected_result2 = {11, 10, 9, 8}; + EXPECT_THAT(order, AnyOf(ContainerEq(expected_result1), + ContainerEq(expected_result2))); +} + +TEST_F(CFGTest, ForEachBlockInReversePostOrderIf) { + const std::string test = R"( +OpCapability Shader +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Vertex %main "main" +OpName %main "main" +%bool = OpTypeBool +%true = OpConstantTrue %bool +%void = OpTypeVoid +%4 = OpTypeFunction %void +%uint = OpTypeInt 32 0 +%5 = OpConstant %uint 5 +%main = OpFunction %void None %4 +%8 = OpLabel +OpSelectionMerge %10 None +OpBranchConditional %true %9 %10 +%9 = OpLabel +OpBranch %10 +%10 = OpLabel +OpReturn +OpFunctionEnd +)"; + + std::unique_ptr context = + BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, test, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + ASSERT_NE(nullptr, context); + + CFG* cfg = context->cfg(); + Module* module = context->module(); + Function* function = &*module->begin(); + std::vector order; + cfg->ForEachBlockInReversePostOrder( + &*function->begin(), + [&order](BasicBlock* bb) { order.push_back(bb->id()); }); + + std::vector expected_result = {8, 9, 10}; + EXPECT_THAT(order, ContainerEq(expected_result)); +} + +TEST_F(CFGTest, ForEachBlockInReversePostOrderLoop) { + const std::string test = R"( +OpCapability Shader +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Vertex %main "main" +OpName %main "main" +%bool = OpTypeBool +%true = OpConstantTrue %bool +%void = OpTypeVoid +%4 = OpTypeFunction %void +%uint = OpTypeInt 32 0 +%5 = OpConstant %uint 5 +%main = OpFunction %void None %4 +%8 = OpLabel +OpBranch %9 +%9 = OpLabel +OpLoopMerge %11 %10 None +OpBranchConditional %true %11 %10 +%10 = OpLabel +OpBranch %9 +%11 = OpLabel +OpReturn +OpFunctionEnd +)"; + + std::unique_ptr context = + BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, test, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + ASSERT_NE(nullptr, context); + + CFG* cfg = context->cfg(); + Module* module = context->module(); + Function* function = &*module->begin(); + std::vector order; + cfg->ForEachBlockInReversePostOrder( + &*function->begin(), + [&order](BasicBlock* bb) { order.push_back(bb->id()); }); + + std::vector expected_result1 = {8, 9, 10, 11}; + std::vector expected_result2 = {8, 9, 11, 10}; + EXPECT_THAT(order, AnyOf(ContainerEq(expected_result1), + ContainerEq(expected_result2))); +} + +} // namespace +} // namespace opt +} // namespace spvtools diff --git a/third_party/spirv-tools/test/opt/code_sink_test.cpp b/third_party/spirv-tools/test/opt/code_sink_test.cpp new file mode 100644 index 0000000000..f1bd12756a --- /dev/null +++ b/third_party/spirv-tools/test/opt/code_sink_test.cpp @@ -0,0 +1,557 @@ +// Copyright (c) 2019 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 + +#include "gmock/gmock.h" +#include "test/opt/assembly_builder.h" +#include "test/opt/pass_fixture.h" +#include "test/opt/pass_utils.h" + +namespace spvtools { +namespace opt { +namespace { + +using CodeSinkTest = PassTest<::testing::Test>; + +TEST_F(CodeSinkTest, MoveToNextBlock) { + const std::string text = R"( +;CHECK: OpFunction +;CHECK: OpLabel +;CHECK: OpLabel +;CHECK: [[ac:%\w+]] = OpAccessChain +;CHECK: [[ld:%\w+]] = OpLoad %uint [[ac]] +;CHECK: OpCopyObject %uint [[ld]] + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "main" + %void = OpTypeVoid + %uint = OpTypeInt 32 0 + %uint_0 = OpConstant %uint 0 + %uint_4 = OpConstant %uint 4 +%_arr_uint_uint_4 = OpTypeArray %uint %uint_4 +%_ptr_Uniform_uint = OpTypePointer Uniform %uint +%_ptr_Uniform__arr_uint_uint_4 = OpTypePointer Uniform %_arr_uint_uint_4 + %9 = OpVariable %_ptr_Uniform__arr_uint_uint_4 Uniform + %10 = OpTypeFunction %void + %1 = OpFunction %void None %10 + %11 = OpLabel + %12 = OpAccessChain %_ptr_Uniform_uint %9 %uint_0 + %13 = OpLoad %uint %12 + OpBranch %14 + %14 = OpLabel + %15 = OpCopyObject %uint %13 + OpReturn + OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(CodeSinkTest, MovePastSelection) { + const std::string text = R"( +;CHECK: OpFunction +;CHECK: OpLabel +;CHECK: OpSelectionMerge [[merge_bb:%\w+]] +;CHECK: [[merge_bb]] = OpLabel +;CHECK: [[ac:%\w+]] = OpAccessChain +;CHECK: [[ld:%\w+]] = OpLoad %uint [[ac]] +;CHECK: OpCopyObject %uint [[ld]] + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "main" + %void = OpTypeVoid + %bool = OpTypeBool + %true = OpConstantTrue %bool + %uint = OpTypeInt 32 0 + %uint_0 = OpConstant %uint 0 + %uint_4 = OpConstant %uint 4 +%_arr_uint_uint_4 = OpTypeArray %uint %uint_4 +%_ptr_Uniform_uint = OpTypePointer Uniform %uint +%_ptr_Uniform__arr_uint_uint_4 = OpTypePointer Uniform %_arr_uint_uint_4 + %11 = OpVariable %_ptr_Uniform__arr_uint_uint_4 Uniform + %12 = OpTypeFunction %void + %1 = OpFunction %void None %12 + %13 = OpLabel + %14 = OpAccessChain %_ptr_Uniform_uint %11 %uint_0 + %15 = OpLoad %uint %14 + OpSelectionMerge %16 None + OpBranchConditional %true %17 %16 + %17 = OpLabel + OpBranch %16 + %16 = OpLabel + %18 = OpCopyObject %uint %15 + OpReturn + OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(CodeSinkTest, MoveIntoSelection) { + const std::string text = R"( +;CHECK: OpFunction +;CHECK: OpLabel +;CHECK: OpSelectionMerge [[merge_bb:%\w+]] +;CHECK-NEXT: OpBranchConditional %true [[bb:%\w+]] [[merge_bb]] +;CHECK: [[bb]] = OpLabel +;CHECK-NEXT: [[ac:%\w+]] = OpAccessChain +;CHECK-NEXT: [[ld:%\w+]] = OpLoad %uint [[ac]] +;CHECK-NEXT: OpCopyObject %uint [[ld]] + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "main" + %void = OpTypeVoid + %bool = OpTypeBool + %true = OpConstantTrue %bool + %uint = OpTypeInt 32 0 + %uint_0 = OpConstant %uint 0 + %uint_4 = OpConstant %uint 4 +%_arr_uint_uint_4 = OpTypeArray %uint %uint_4 +%_ptr_Uniform_uint = OpTypePointer Uniform %uint +%_ptr_Uniform__arr_uint_uint_4 = OpTypePointer Uniform %_arr_uint_uint_4 + %11 = OpVariable %_ptr_Uniform__arr_uint_uint_4 Uniform + %12 = OpTypeFunction %void + %1 = OpFunction %void None %12 + %13 = OpLabel + %14 = OpAccessChain %_ptr_Uniform_uint %11 %uint_0 + %15 = OpLoad %uint %14 + OpSelectionMerge %16 None + OpBranchConditional %true %17 %16 + %17 = OpLabel + %18 = OpCopyObject %uint %15 + OpBranch %16 + %16 = OpLabel + OpReturn + OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(CodeSinkTest, LeaveBeforeSelection) { + const std::string text = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "main" + %void = OpTypeVoid + %bool = OpTypeBool + %true = OpConstantTrue %bool + %uint = OpTypeInt 32 0 + %uint_0 = OpConstant %uint 0 + %uint_4 = OpConstant %uint 4 +%_arr_uint_uint_4 = OpTypeArray %uint %uint_4 +%_ptr_Uniform_uint = OpTypePointer Uniform %uint +%_ptr_Uniform__arr_uint_uint_4 = OpTypePointer Uniform %_arr_uint_uint_4 + %11 = OpVariable %_ptr_Uniform__arr_uint_uint_4 Uniform + %12 = OpTypeFunction %void + %1 = OpFunction %void None %12 + %13 = OpLabel + %14 = OpAccessChain %_ptr_Uniform_uint %11 %uint_0 + %15 = OpLoad %uint %14 + OpSelectionMerge %16 None + OpBranchConditional %true %17 %20 + %20 = OpLabel + OpBranch %16 + %17 = OpLabel + %18 = OpCopyObject %uint %15 + OpBranch %16 + %16 = OpLabel + %19 = OpCopyObject %uint %15 + OpReturn + OpFunctionEnd +)"; + + auto result = SinglePassRunAndDisassemble( + text, /* skip_nop = */ true, /* do_validation = */ true); + EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)); +} + +TEST_F(CodeSinkTest, LeaveAloneUseInSameBlock) { + const std::string text = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "main" + %void = OpTypeVoid + %bool = OpTypeBool + %true = OpConstantTrue %bool + %uint = OpTypeInt 32 0 + %uint_0 = OpConstant %uint 0 + %uint_4 = OpConstant %uint 4 +%_arr_uint_uint_4 = OpTypeArray %uint %uint_4 +%_ptr_Uniform_uint = OpTypePointer Uniform %uint +%_ptr_Uniform__arr_uint_uint_4 = OpTypePointer Uniform %_arr_uint_uint_4 + %11 = OpVariable %_ptr_Uniform__arr_uint_uint_4 Uniform + %12 = OpTypeFunction %void + %1 = OpFunction %void None %12 + %13 = OpLabel + %14 = OpAccessChain %_ptr_Uniform_uint %11 %uint_0 + %15 = OpLoad %uint %14 + %cond = OpIEqual %bool %15 %uint_0 + OpSelectionMerge %16 None + OpBranchConditional %cond %17 %16 + %17 = OpLabel + OpBranch %16 + %16 = OpLabel + %19 = OpCopyObject %uint %15 + OpReturn + OpFunctionEnd +)"; + + auto result = SinglePassRunAndDisassemble( + text, /* skip_nop = */ true, /* do_validation = */ true); + EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)); +} + +TEST_F(CodeSinkTest, DontMoveIntoLoop) { + const std::string text = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "main" + %void = OpTypeVoid + %bool = OpTypeBool + %true = OpConstantTrue %bool + %uint = OpTypeInt 32 0 + %uint_0 = OpConstant %uint 0 + %uint_4 = OpConstant %uint 4 +%_arr_uint_uint_4 = OpTypeArray %uint %uint_4 +%_ptr_Uniform_uint = OpTypePointer Uniform %uint +%_ptr_Uniform__arr_uint_uint_4 = OpTypePointer Uniform %_arr_uint_uint_4 + %11 = OpVariable %_ptr_Uniform__arr_uint_uint_4 Uniform + %12 = OpTypeFunction %void + %1 = OpFunction %void None %12 + %13 = OpLabel + %14 = OpAccessChain %_ptr_Uniform_uint %11 %uint_0 + %15 = OpLoad %uint %14 + OpBranch %17 + %17 = OpLabel + OpLoopMerge %merge %cont None + OpBranch %cont + %cont = OpLabel + %cond = OpIEqual %bool %15 %uint_0 + OpBranchConditional %cond %merge %17 + %merge = OpLabel + OpReturn + OpFunctionEnd +)"; + + auto result = SinglePassRunAndDisassemble( + text, /* skip_nop = */ true, /* do_validation = */ true); + EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)); +} + +TEST_F(CodeSinkTest, DontMoveIntoLoop2) { + const std::string text = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "main" + %void = OpTypeVoid + %bool = OpTypeBool + %true = OpConstantTrue %bool + %uint = OpTypeInt 32 0 + %uint_0 = OpConstant %uint 0 + %uint_4 = OpConstant %uint 4 +%_arr_uint_uint_4 = OpTypeArray %uint %uint_4 +%_ptr_Uniform_uint = OpTypePointer Uniform %uint +%_ptr_Uniform__arr_uint_uint_4 = OpTypePointer Uniform %_arr_uint_uint_4 + %11 = OpVariable %_ptr_Uniform__arr_uint_uint_4 Uniform + %12 = OpTypeFunction %void + %1 = OpFunction %void None %12 + %13 = OpLabel + %14 = OpAccessChain %_ptr_Uniform_uint %11 %uint_0 + %15 = OpLoad %uint %14 + OpSelectionMerge %16 None + OpBranchConditional %true %17 %16 + %17 = OpLabel + OpLoopMerge %merge %cont None + OpBranch %cont + %cont = OpLabel + %cond = OpIEqual %bool %15 %uint_0 + OpBranchConditional %cond %merge %17 + %merge = OpLabel + OpBranch %16 + %16 = OpLabel + OpReturn + OpFunctionEnd +)"; + + auto result = SinglePassRunAndDisassemble( + text, /* skip_nop = */ true, /* do_validation = */ true); + EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)); +} + +TEST_F(CodeSinkTest, DontMoveSelectionUsedInBothSides) { + const std::string text = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "main" + %void = OpTypeVoid + %bool = OpTypeBool + %true = OpConstantTrue %bool + %uint = OpTypeInt 32 0 + %uint_0 = OpConstant %uint 0 + %uint_4 = OpConstant %uint 4 +%_arr_uint_uint_4 = OpTypeArray %uint %uint_4 +%_ptr_Uniform_uint = OpTypePointer Uniform %uint +%_ptr_Uniform__arr_uint_uint_4 = OpTypePointer Uniform %_arr_uint_uint_4 + %11 = OpVariable %_ptr_Uniform__arr_uint_uint_4 Uniform + %12 = OpTypeFunction %void + %1 = OpFunction %void None %12 + %13 = OpLabel + %14 = OpAccessChain %_ptr_Uniform_uint %11 %uint_0 + %15 = OpLoad %uint %14 + OpSelectionMerge %16 None + OpBranchConditional %true %17 %20 + %20 = OpLabel + %19 = OpCopyObject %uint %15 + OpBranch %16 + %17 = OpLabel + %18 = OpCopyObject %uint %15 + OpBranch %16 + %16 = OpLabel + OpReturn + OpFunctionEnd +)"; + + auto result = SinglePassRunAndDisassemble( + text, /* skip_nop = */ true, /* do_validation = */ true); + EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)); +} + +TEST_F(CodeSinkTest, DontMoveBecauseOfStore) { + const std::string text = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "main" + %void = OpTypeVoid + %bool = OpTypeBool + %true = OpConstantTrue %bool + %uint = OpTypeInt 32 0 + %uint_0 = OpConstant %uint 0 + %uint_4 = OpConstant %uint 4 +%_arr_uint_uint_4 = OpTypeArray %uint %uint_4 +%_ptr_Uniform_uint = OpTypePointer Uniform %uint +%_ptr_Uniform__arr_uint_uint_4 = OpTypePointer Uniform %_arr_uint_uint_4 + %11 = OpVariable %_ptr_Uniform__arr_uint_uint_4 Uniform + %12 = OpTypeFunction %void + %1 = OpFunction %void None %12 + %13 = OpLabel + %14 = OpAccessChain %_ptr_Uniform_uint %11 %uint_0 + %15 = OpLoad %uint %14 + OpStore %14 %15 + OpSelectionMerge %16 None + OpBranchConditional %true %17 %20 + %20 = OpLabel + OpBranch %16 + %17 = OpLabel + %18 = OpCopyObject %uint %15 + OpBranch %16 + %16 = OpLabel + OpReturn + OpFunctionEnd +)"; + + auto result = SinglePassRunAndDisassemble( + text, /* skip_nop = */ true, /* do_validation = */ true); + EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)); +} + +TEST_F(CodeSinkTest, MoveReadOnlyLoadWithSync) { + const std::string text = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "main" + %void = OpTypeVoid + %bool = OpTypeBool + %true = OpConstantTrue %bool + %uint = OpTypeInt 32 0 + %uint_0 = OpConstant %uint 0 + %uint_4 = OpConstant %uint 4 +%mem_semantics = OpConstant %uint 0x42 ; Uniform memeory arquire +%_arr_uint_uint_4 = OpTypeArray %uint %uint_4 +%_ptr_Uniform_uint = OpTypePointer Uniform %uint +%_ptr_Uniform__arr_uint_uint_4 = OpTypePointer Uniform %_arr_uint_uint_4 + %11 = OpVariable %_ptr_Uniform__arr_uint_uint_4 Uniform + %12 = OpTypeFunction %void + %1 = OpFunction %void None %12 + %13 = OpLabel + %14 = OpAccessChain %_ptr_Uniform_uint %11 %uint_0 + %15 = OpLoad %uint %14 + OpMemoryBarrier %uint_4 %mem_semantics + OpSelectionMerge %16 None + OpBranchConditional %true %17 %20 + %20 = OpLabel + OpBranch %16 + %17 = OpLabel + %18 = OpCopyObject %uint %15 + OpBranch %16 + %16 = OpLabel + OpReturn + OpFunctionEnd +)"; + + auto result = SinglePassRunAndDisassemble( + text, /* skip_nop = */ true, /* do_validation = */ true); + EXPECT_EQ(Pass::Status::SuccessWithChange, std::get<1>(result)); +} + +TEST_F(CodeSinkTest, DontMoveBecauseOfSync) { + const std::string text = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "main" + OpDecorate %_arr_uint_uint_4 BufferBlock + OpMemberDecorate %_arr_uint_uint_4 0 Offset 0 + %void = OpTypeVoid + %bool = OpTypeBool + %true = OpConstantTrue %bool + %uint = OpTypeInt 32 0 + %uint_0 = OpConstant %uint 0 + %uint_4 = OpConstant %uint 4 +%mem_semantics = OpConstant %uint 0x42 ; Uniform memeory arquire +%_arr_uint_uint_4 = OpTypeStruct %uint +%_ptr_Uniform_uint = OpTypePointer Uniform %uint +%_ptr_Uniform__arr_uint_uint_4 = OpTypePointer Uniform %_arr_uint_uint_4 + %11 = OpVariable %_ptr_Uniform__arr_uint_uint_4 Uniform + %12 = OpTypeFunction %void + %1 = OpFunction %void None %12 + %13 = OpLabel + %14 = OpAccessChain %_ptr_Uniform_uint %11 %uint_0 + %15 = OpLoad %uint %14 + OpMemoryBarrier %uint_4 %mem_semantics + OpSelectionMerge %16 None + OpBranchConditional %true %17 %20 + %20 = OpLabel + OpBranch %16 + %17 = OpLabel + %18 = OpCopyObject %uint %15 + OpBranch %16 + %16 = OpLabel + OpReturn + OpFunctionEnd +)"; + + auto result = SinglePassRunAndDisassemble( + text, /* skip_nop = */ true, /* do_validation = */ true); + EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)); +} + +TEST_F(CodeSinkTest, DontMoveBecauseOfAtomicWithSync) { + const std::string text = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "main" + OpDecorate %_arr_uint_uint_4 BufferBlock + OpMemberDecorate %_arr_uint_uint_4 0 Offset 0 + %void = OpTypeVoid + %bool = OpTypeBool + %true = OpConstantTrue %bool + %uint = OpTypeInt 32 0 + %uint_0 = OpConstant %uint 0 + %uint_4 = OpConstant %uint 4 +%mem_semantics = OpConstant %uint 0x42 ; Uniform memeory arquire +%_arr_uint_uint_4 = OpTypeStruct %uint +%_ptr_Uniform_uint = OpTypePointer Uniform %uint +%_ptr_Uniform__arr_uint_uint_4 = OpTypePointer Uniform %_arr_uint_uint_4 + %11 = OpVariable %_ptr_Uniform__arr_uint_uint_4 Uniform + %12 = OpTypeFunction %void + %1 = OpFunction %void None %12 + %13 = OpLabel + %14 = OpAccessChain %_ptr_Uniform_uint %11 %uint_0 + %15 = OpLoad %uint %14 + %al = OpAtomicLoad %uint %14 %uint_4 %mem_semantics + OpSelectionMerge %16 None + OpBranchConditional %true %17 %20 + %20 = OpLabel + OpBranch %16 + %17 = OpLabel + %18 = OpCopyObject %uint %15 + OpBranch %16 + %16 = OpLabel + OpReturn + OpFunctionEnd +)"; + + auto result = SinglePassRunAndDisassemble( + text, /* skip_nop = */ true, /* do_validation = */ true); + EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)); +} + +TEST_F(CodeSinkTest, MoveWithAtomicWithoutSync) { + const std::string text = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "main" + OpDecorate %_arr_uint_uint_4 BufferBlock + OpMemberDecorate %_arr_uint_uint_4 0 Offset 0 + %void = OpTypeVoid + %bool = OpTypeBool + %true = OpConstantTrue %bool + %uint = OpTypeInt 32 0 + %uint_0 = OpConstant %uint 0 + %uint_4 = OpConstant %uint 4 +%_arr_uint_uint_4 = OpTypeStruct %uint +%_ptr_Uniform_uint = OpTypePointer Uniform %uint +%_ptr_Uniform__arr_uint_uint_4 = OpTypePointer Uniform %_arr_uint_uint_4 + %11 = OpVariable %_ptr_Uniform__arr_uint_uint_4 Uniform + %12 = OpTypeFunction %void + %1 = OpFunction %void None %12 + %13 = OpLabel + %14 = OpAccessChain %_ptr_Uniform_uint %11 %uint_0 + %15 = OpLoad %uint %14 + %al = OpAtomicLoad %uint %14 %uint_4 %uint_0 + OpSelectionMerge %16 None + OpBranchConditional %true %17 %20 + %20 = OpLabel + OpBranch %16 + %17 = OpLabel + %18 = OpCopyObject %uint %15 + OpBranch %16 + %16 = OpLabel + OpReturn + OpFunctionEnd +)"; + + auto result = SinglePassRunAndDisassemble( + text, /* skip_nop = */ true, /* do_validation = */ true); + EXPECT_EQ(Pass::Status::SuccessWithChange, std::get<1>(result)); +} + +TEST_F(CodeSinkTest, DecorationOnLoad) { + const std::string text = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "main" %2 + OpDecorate %3 RelaxedPrecision + %void = OpTypeVoid + %5 = OpTypeFunction %void + %float = OpTypeFloat 32 +%_ptr_Input_float = OpTypePointer Input %float + %2 = OpVariable %_ptr_Input_float Input + %1 = OpFunction %void None %5 + %8 = OpLabel + %3 = OpLoad %float %2 + OpReturn + OpFunctionEnd +)"; + + // We just want to make sure the code does not crash. + auto result = SinglePassRunAndDisassemble( + text, /* skip_nop = */ true, /* do_validation = */ true); + EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)); +} + +} // namespace +} // namespace opt +} // namespace spvtools diff --git a/third_party/spirv-tools/test/opt/combine_access_chains_test.cpp b/third_party/spirv-tools/test/opt/combine_access_chains_test.cpp index ab9e185b68..aed14c9deb 100644 --- a/third_party/spirv-tools/test/opt/combine_access_chains_test.cpp +++ b/third_party/spirv-tools/test/opt/combine_access_chains_test.cpp @@ -25,7 +25,6 @@ namespace { using CombineAccessChainsTest = PassTest<::testing::Test>; -#ifdef SPIRV_EFFCEE TEST_F(CombineAccessChainsTest, PtrAccessChainFromAccessChainConstant) { const std::string text = R"( ; CHECK: [[int:%\w+]] = OpTypeInt 32 0 @@ -38,6 +37,7 @@ OpCapability VariablePointers OpExtension "SPV_KHR_variable_pointers" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft %void = OpTypeVoid %uint = OpTypeInt 32 0 %uint_0 = OpConstant %uint 0 @@ -71,6 +71,7 @@ OpCapability VariablePointers OpExtension "SPV_KHR_variable_pointers" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft %void = OpTypeVoid %uint = OpTypeInt 32 0 %uint_0 = OpConstant %uint 0 @@ -104,6 +105,7 @@ OpCapability VariablePointers OpExtension "SPV_KHR_variable_pointers" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft %void = OpTypeVoid %uint = OpTypeInt 32 0 %uint_0 = OpConstant %uint 0 @@ -139,6 +141,7 @@ OpCapability VariablePointers OpExtension "SPV_KHR_variable_pointers" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft %void = OpTypeVoid %uint = OpTypeInt 32 0 %uint_0 = OpConstant %uint 0 @@ -177,6 +180,7 @@ OpCapability VariablePointers OpExtension "SPV_KHR_variable_pointers" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft %void = OpTypeVoid %uint = OpTypeInt 32 0 %uint_0 = OpConstant %uint 0 @@ -219,6 +223,7 @@ OpCapability VariablePointers OpExtension "SPV_KHR_variable_pointers" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft %void = OpTypeVoid %uint = OpTypeInt 32 0 %uint_0 = OpConstant %uint 0 @@ -255,6 +260,7 @@ OpCapability VariablePointers OpExtension "SPV_KHR_variable_pointers" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft %void = OpTypeVoid %uint = OpTypeInt 32 0 %uint_0 = OpConstant %uint 0 @@ -289,6 +295,7 @@ OpCapability VariablePointers OpExtension "SPV_KHR_variable_pointers" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft %void = OpTypeVoid %uint = OpTypeInt 32 0 %uint_0 = OpConstant %uint 0 @@ -326,6 +333,7 @@ OpCapability VariablePointers OpExtension "SPV_KHR_variable_pointers" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft %void = OpTypeVoid %uint = OpTypeInt 32 0 %uint_0 = OpConstant %uint 0 @@ -361,6 +369,7 @@ OpCapability VariablePointers OpExtension "SPV_KHR_variable_pointers" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft %void = OpTypeVoid %uint = OpTypeInt 32 0 %uint_0 = OpConstant %uint 0 @@ -399,6 +408,7 @@ OpCapability VariablePointers OpExtension "SPV_KHR_variable_pointers" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft %void = OpTypeVoid %uint = OpTypeInt 32 0 %uint_0 = OpConstant %uint 0 @@ -435,6 +445,7 @@ OpCapability VariablePointers OpExtension "SPV_KHR_variable_pointers" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft %void = OpTypeVoid %uint = OpTypeInt 32 0 %uint_0 = OpConstant %uint 0 @@ -468,6 +479,7 @@ OpCapability VariablePointers OpExtension "SPV_KHR_variable_pointers" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft %void = OpTypeVoid %uint = OpTypeInt 32 0 %uint_0 = OpConstant %uint 0 @@ -505,6 +517,7 @@ OpCapability VariablePointers OpExtension "SPV_KHR_variable_pointers" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft %void = OpTypeVoid %uint = OpTypeInt 32 0 %uint_0 = OpConstant %uint 0 @@ -543,6 +556,7 @@ OpCapability Addresses OpExtension "SPV_KHR_variable_pointers" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft %void = OpTypeVoid %uint = OpTypeInt 32 0 %uint_0 = OpConstant %uint 0 @@ -579,6 +593,7 @@ OpCapability Addresses OpExtension "SPV_KHR_variable_pointers" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft %void = OpTypeVoid %uint = OpTypeInt 32 0 %uint_0 = OpConstant %uint 0 @@ -616,6 +631,7 @@ OpCapability Addresses OpExtension "SPV_KHR_variable_pointers" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft %void = OpTypeVoid %uint = OpTypeInt 32 0 %uint_0 = OpConstant %uint 0 @@ -646,6 +662,7 @@ TEST_F(CombineAccessChainsTest, NoIndexAccessChains) { OpCapability Shader OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft %void = OpTypeVoid %uint = OpTypeInt 32 0 %ptr_Workgroup_uint = OpTypePointer Workgroup %uint @@ -673,6 +690,7 @@ OpCapability VariablePointers OpExtension "SPV_KHR_variable_pointers" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft %void = OpTypeVoid %uint = OpTypeInt 32 0 %uint_0 = OpConstant %uint 0 @@ -700,6 +718,7 @@ OpCapability VariablePointers OpExtension "SPV_KHR_variable_pointers" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft %void = OpTypeVoid %uint = OpTypeInt 32 0 %uint_0 = OpConstant %uint 0 @@ -729,6 +748,7 @@ OpCapability Addresses OpExtension "SPV_KHR_variable_pointers" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft %void = OpTypeVoid %uint = OpTypeInt 32 0 %int = OpTypeInt 32 1 @@ -747,7 +767,6 @@ OpFunctionEnd SinglePassRunAndMatch(text, true); } -#endif // SPIRV_EFFCEE } // namespace } // namespace opt diff --git a/third_party/spirv-tools/test/opt/common_uniform_elim_test.cpp b/third_party/spirv-tools/test/opt/common_uniform_elim_test.cpp deleted file mode 100644 index f5199ed875..0000000000 --- a/third_party/spirv-tools/test/opt/common_uniform_elim_test.cpp +++ /dev/null @@ -1,1341 +0,0 @@ -// Copyright (c) 2017 Valve Corporation -// Copyright (c) 2017 LunarG Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include - -#include "test/opt/pass_fixture.h" - -namespace spvtools { -namespace opt { -namespace { - -using CommonUniformElimTest = PassTest<::testing::Test>; - -TEST_F(CommonUniformElimTest, Basic1) { - // Note: This test exemplifies the following: - // - Common uniform (%_) load floated to nearest non-controlled block - // - Common extract (g_F) floated to non-controlled block - // - Non-common extract (g_F2) not floated, but common uniform load shared - // - // #version 140 - // in vec4 BaseColor; - // in float fi; - // - // layout(std140) uniform U_t - // { - // float g_F; - // float g_F2; - // } ; - // - // void main() - // { - // vec4 v = BaseColor; - // if (fi > 0) { - // v = v * g_F; - // } - // else { - // float f2 = g_F2 - g_F; - // v = v * f2; - // } - // gl_FragColor = v; - // } - - const std::string predefs = - R"(OpCapability Shader -%1 = OpExtInstImport "GLSL.std.450" -OpMemoryModel Logical GLSL450 -OpEntryPoint Fragment %main "main" %BaseColor %fi %gl_FragColor -OpExecutionMode %main OriginUpperLeft -OpSource GLSL 140 -OpName %main "main" -OpName %v "v" -OpName %BaseColor "BaseColor" -OpName %fi "fi" -OpName %U_t "U_t" -OpMemberName %U_t 0 "g_F" -OpMemberName %U_t 1 "g_F2" -OpName %_ "" -OpName %f2 "f2" -OpName %gl_FragColor "gl_FragColor" -OpMemberDecorate %U_t 0 Offset 0 -OpMemberDecorate %U_t 1 Offset 4 -OpDecorate %U_t Block -OpDecorate %_ DescriptorSet 0 -%void = OpTypeVoid -%11 = OpTypeFunction %void -%float = OpTypeFloat 32 -%v4float = OpTypeVector %float 4 -%_ptr_Function_v4float = OpTypePointer Function %v4float -%_ptr_Input_v4float = OpTypePointer Input %v4float -%BaseColor = OpVariable %_ptr_Input_v4float Input -%_ptr_Input_float = OpTypePointer Input %float -%fi = OpVariable %_ptr_Input_float Input -%float_0 = OpConstant %float 0 -%bool = OpTypeBool -%U_t = OpTypeStruct %float %float -%_ptr_Uniform_U_t = OpTypePointer Uniform %U_t -%_ = OpVariable %_ptr_Uniform_U_t Uniform -%int = OpTypeInt 32 1 -%int_0 = OpConstant %int 0 -%_ptr_Uniform_float = OpTypePointer Uniform %float -%_ptr_Function_float = OpTypePointer Function %float -%int_1 = OpConstant %int 1 -%_ptr_Output_v4float = OpTypePointer Output %v4float -%gl_FragColor = OpVariable %_ptr_Output_v4float Output -)"; - - const std::string before = - R"(%main = OpFunction %void None %11 -%26 = OpLabel -%v = OpVariable %_ptr_Function_v4float Function -%f2 = OpVariable %_ptr_Function_float Function -%27 = OpLoad %v4float %BaseColor -OpStore %v %27 -%28 = OpLoad %float %fi -%29 = OpFOrdGreaterThan %bool %28 %float_0 -OpSelectionMerge %30 None -OpBranchConditional %29 %31 %32 -%31 = OpLabel -%33 = OpLoad %v4float %v -%34 = OpAccessChain %_ptr_Uniform_float %_ %int_0 -%35 = OpLoad %float %34 -%36 = OpVectorTimesScalar %v4float %33 %35 -OpStore %v %36 -OpBranch %30 -%32 = OpLabel -%37 = OpAccessChain %_ptr_Uniform_float %_ %int_1 -%38 = OpLoad %float %37 -%39 = OpAccessChain %_ptr_Uniform_float %_ %int_0 -%40 = OpLoad %float %39 -%41 = OpFSub %float %38 %40 -OpStore %f2 %41 -%42 = OpLoad %v4float %v -%43 = OpLoad %float %f2 -%44 = OpVectorTimesScalar %v4float %42 %43 -OpStore %v %44 -OpBranch %30 -%30 = OpLabel -%45 = OpLoad %v4float %v -OpStore %gl_FragColor %45 -OpReturn -OpFunctionEnd -)"; - - const std::string after = - R"(%main = OpFunction %void None %11 -%26 = OpLabel -%v = OpVariable %_ptr_Function_v4float Function -%f2 = OpVariable %_ptr_Function_float Function -%52 = OpLoad %U_t %_ -%53 = OpCompositeExtract %float %52 0 -%27 = OpLoad %v4float %BaseColor -OpStore %v %27 -%28 = OpLoad %float %fi -%29 = OpFOrdGreaterThan %bool %28 %float_0 -OpSelectionMerge %30 None -OpBranchConditional %29 %31 %32 -%31 = OpLabel -%33 = OpLoad %v4float %v -%36 = OpVectorTimesScalar %v4float %33 %53 -OpStore %v %36 -OpBranch %30 -%32 = OpLabel -%49 = OpCompositeExtract %float %52 1 -%41 = OpFSub %float %49 %53 -OpStore %f2 %41 -%42 = OpLoad %v4float %v -%43 = OpLoad %float %f2 -%44 = OpVectorTimesScalar %v4float %42 %43 -OpStore %v %44 -OpBranch %30 -%30 = OpLabel -%45 = OpLoad %v4float %v -OpStore %gl_FragColor %45 -OpReturn -OpFunctionEnd -)"; - - SinglePassRunAndCheck(predefs + before, - predefs + after, true, true); -} - -TEST_F(CommonUniformElimTest, Basic2) { - // Note: This test exemplifies the following: - // - Common uniform (%_) load floated to nearest non-controlled block - // - Common extract (g_F) floated to non-controlled block - // - Non-common extract (g_F2) not floated, but common uniform load shared - // - // #version 140 - // in vec4 BaseColor; - // in float fi; - // in float fi2; - // - // layout(std140) uniform U_t - // { - // float g_F; - // float g_F2; - // } ; - // - // void main() - // { - // float f = fi; - // if (f < 0) - // f = -f; - // if (fi2 > 0) { - // f = f * g_F; - // } - // else { - // f = g_F2 - g_F; - // } - // gl_FragColor = f * BaseColor; - // } - - const std::string predefs = - R"(OpCapability Shader -%1 = OpExtInstImport "GLSL.std.450" -OpMemoryModel Logical GLSL450 -OpEntryPoint Fragment %main "main" %fi %fi2 %gl_FragColor %BaseColor -OpExecutionMode %main OriginUpperLeft -OpSource GLSL 140 -OpName %main "main" -OpName %f "f" -OpName %fi "fi" -OpName %fi2 "fi2" -OpName %U_t "U_t" -OpMemberName %U_t 0 "g_F" -OpMemberName %U_t 1 "g_F2" -OpName %_ "" -OpName %gl_FragColor "gl_FragColor" -OpName %BaseColor "BaseColor" -OpMemberDecorate %U_t 0 Offset 0 -OpMemberDecorate %U_t 1 Offset 4 -OpDecorate %U_t Block -OpDecorate %_ DescriptorSet 0 -%void = OpTypeVoid -%11 = OpTypeFunction %void -%float = OpTypeFloat 32 -%_ptr_Function_float = OpTypePointer Function %float -%_ptr_Input_float = OpTypePointer Input %float -%fi = OpVariable %_ptr_Input_float Input -%float_0 = OpConstant %float 0 -%bool = OpTypeBool -%fi2 = OpVariable %_ptr_Input_float Input -%U_t = OpTypeStruct %float %float -%_ptr_Uniform_U_t = OpTypePointer Uniform %U_t -%_ = OpVariable %_ptr_Uniform_U_t Uniform -%int = OpTypeInt 32 1 -%int_0 = OpConstant %int 0 -%_ptr_Uniform_float = OpTypePointer Uniform %float -%int_1 = OpConstant %int 1 -%v4float = OpTypeVector %float 4 -%_ptr_Output_v4float = OpTypePointer Output %v4float -%gl_FragColor = OpVariable %_ptr_Output_v4float Output -%_ptr_Input_v4float = OpTypePointer Input %v4float -%BaseColor = OpVariable %_ptr_Input_v4float Input -)"; - - const std::string before = - R"(%main = OpFunction %void None %11 -%25 = OpLabel -%f = OpVariable %_ptr_Function_float Function -%26 = OpLoad %float %fi -OpStore %f %26 -%27 = OpLoad %float %f -%28 = OpFOrdLessThan %bool %27 %float_0 -OpSelectionMerge %29 None -OpBranchConditional %28 %30 %29 -%30 = OpLabel -%31 = OpLoad %float %f -%32 = OpFNegate %float %31 -OpStore %f %32 -OpBranch %29 -%29 = OpLabel -%33 = OpLoad %float %fi2 -%34 = OpFOrdGreaterThan %bool %33 %float_0 -OpSelectionMerge %35 None -OpBranchConditional %34 %36 %37 -%36 = OpLabel -%38 = OpLoad %float %f -%39 = OpAccessChain %_ptr_Uniform_float %_ %int_0 -%40 = OpLoad %float %39 -%41 = OpFMul %float %38 %40 -OpStore %f %41 -OpBranch %35 -%37 = OpLabel -%42 = OpAccessChain %_ptr_Uniform_float %_ %int_1 -%43 = OpLoad %float %42 -%44 = OpAccessChain %_ptr_Uniform_float %_ %int_0 -%45 = OpLoad %float %44 -%46 = OpFSub %float %43 %45 -OpStore %f %46 -OpBranch %35 -%35 = OpLabel -%47 = OpLoad %v4float %BaseColor -%48 = OpLoad %float %f -%49 = OpVectorTimesScalar %v4float %47 %48 -OpStore %gl_FragColor %49 -OpReturn -OpFunctionEnd -)"; - - const std::string after = - R"(%main = OpFunction %void None %11 -%25 = OpLabel -%f = OpVariable %_ptr_Function_float Function -%26 = OpLoad %float %fi -OpStore %f %26 -%27 = OpLoad %float %f -%28 = OpFOrdLessThan %bool %27 %float_0 -OpSelectionMerge %29 None -OpBranchConditional %28 %30 %29 -%30 = OpLabel -%31 = OpLoad %float %f -%32 = OpFNegate %float %31 -OpStore %f %32 -OpBranch %29 -%29 = OpLabel -%56 = OpLoad %U_t %_ -%57 = OpCompositeExtract %float %56 0 -%33 = OpLoad %float %fi2 -%34 = OpFOrdGreaterThan %bool %33 %float_0 -OpSelectionMerge %35 None -OpBranchConditional %34 %36 %37 -%36 = OpLabel -%38 = OpLoad %float %f -%41 = OpFMul %float %38 %57 -OpStore %f %41 -OpBranch %35 -%37 = OpLabel -%53 = OpCompositeExtract %float %56 1 -%46 = OpFSub %float %53 %57 -OpStore %f %46 -OpBranch %35 -%35 = OpLabel -%47 = OpLoad %v4float %BaseColor -%48 = OpLoad %float %f -%49 = OpVectorTimesScalar %v4float %47 %48 -OpStore %gl_FragColor %49 -OpReturn -OpFunctionEnd -)"; - - SinglePassRunAndCheck(predefs + before, - predefs + after, true, true); -} - -TEST_F(CommonUniformElimTest, Basic3) { - // Note: This test exemplifies the following: - // - Existing common uniform (%_) load kept in place and shared - // - // #version 140 - // in vec4 BaseColor; - // in float fi; - // - // layout(std140) uniform U_t - // { - // bool g_B; - // float g_F; - // } ; - // - // void main() - // { - // vec4 v = BaseColor; - // if (g_B) - // v = v * g_F; - // gl_FragColor = v; - // } - - const std::string predefs = - R"(OpCapability Shader -%1 = OpExtInstImport "GLSL.std.450" -OpMemoryModel Logical GLSL450 -OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor %fi -OpExecutionMode %main OriginUpperLeft -OpSource GLSL 140 -OpName %main "main" -OpName %v "v" -OpName %BaseColor "BaseColor" -OpName %U_t "U_t" -OpMemberName %U_t 0 "g_B" -OpMemberName %U_t 1 "g_F" -OpName %_ "" -OpName %gl_FragColor "gl_FragColor" -OpName %fi "fi" -OpMemberDecorate %U_t 0 Offset 0 -OpMemberDecorate %U_t 1 Offset 4 -OpDecorate %U_t Block -OpDecorate %_ DescriptorSet 0 -%void = OpTypeVoid -%10 = OpTypeFunction %void -%float = OpTypeFloat 32 -%v4float = OpTypeVector %float 4 -%_ptr_Function_v4float = OpTypePointer Function %v4float -%_ptr_Input_v4float = OpTypePointer Input %v4float -%BaseColor = OpVariable %_ptr_Input_v4float Input -%uint = OpTypeInt 32 0 -%U_t = OpTypeStruct %uint %float -%_ptr_Uniform_U_t = OpTypePointer Uniform %U_t -%_ = OpVariable %_ptr_Uniform_U_t Uniform -%int = OpTypeInt 32 1 -%int_0 = OpConstant %int 0 -%_ptr_Uniform_uint = OpTypePointer Uniform %uint -%bool = OpTypeBool -%uint_0 = OpConstant %uint 0 -%int_1 = OpConstant %int 1 -%_ptr_Uniform_float = OpTypePointer Uniform %float -%_ptr_Output_v4float = OpTypePointer Output %v4float -%gl_FragColor = OpVariable %_ptr_Output_v4float Output -%_ptr_Input_float = OpTypePointer Input %float -%fi = OpVariable %_ptr_Input_float Input -)"; - - const std::string before = - R"(%main = OpFunction %void None %10 -%26 = OpLabel -%v = OpVariable %_ptr_Function_v4float Function -%27 = OpLoad %v4float %BaseColor -OpStore %v %27 -%28 = OpAccessChain %_ptr_Uniform_uint %_ %int_0 -%29 = OpLoad %uint %28 -%30 = OpINotEqual %bool %29 %uint_0 -OpSelectionMerge %31 None -OpBranchConditional %30 %32 %31 -%32 = OpLabel -%33 = OpLoad %v4float %v -%34 = OpAccessChain %_ptr_Uniform_float %_ %int_1 -%35 = OpLoad %float %34 -%36 = OpVectorTimesScalar %v4float %33 %35 -OpStore %v %36 -OpBranch %31 -%31 = OpLabel -%37 = OpLoad %v4float %v -OpStore %gl_FragColor %37 -OpReturn -OpFunctionEnd -)"; - - const std::string after = - R"(%main = OpFunction %void None %10 -%26 = OpLabel -%v = OpVariable %_ptr_Function_v4float Function -%27 = OpLoad %v4float %BaseColor -OpStore %v %27 -%38 = OpLoad %U_t %_ -%39 = OpCompositeExtract %uint %38 0 -%30 = OpINotEqual %bool %39 %uint_0 -OpSelectionMerge %31 None -OpBranchConditional %30 %32 %31 -%32 = OpLabel -%33 = OpLoad %v4float %v -%41 = OpCompositeExtract %float %38 1 -%36 = OpVectorTimesScalar %v4float %33 %41 -OpStore %v %36 -OpBranch %31 -%31 = OpLabel -%37 = OpLoad %v4float %v -OpStore %gl_FragColor %37 -OpReturn -OpFunctionEnd -)"; - - SinglePassRunAndCheck(predefs + before, - predefs + after, true, true); -} - -TEST_F(CommonUniformElimTest, Loop) { - // Note: This test exemplifies the following: - // - Common extract (g_F) shared between two loops - // #version 140 - // in vec4 BC; - // in vec4 BC2; - // - // layout(std140) uniform U_t - // { - // float g_F; - // } ; - // - // void main() - // { - // vec4 v = BC; - // for (int i = 0; i < 4; i++) - // v[i] = v[i] / g_F; - // vec4 v2 = BC2; - // for (int i = 0; i < 4; i++) - // v2[i] = v2[i] * g_F; - // gl_FragColor = v + v2; - // } - - const std::string predefs = - R"(OpCapability Shader -%1 = OpExtInstImport "GLSL.std.450" -OpMemoryModel Logical GLSL450 -OpEntryPoint Fragment %main "main" %BC %BC2 %gl_FragColor -OpExecutionMode %main OriginUpperLeft -OpSource GLSL 140 -OpName %main "main" -OpName %v "v" -OpName %BC "BC" -OpName %i "i" -OpName %U_t "U_t" -OpMemberName %U_t 0 "g_F" -OpName %_ "" -OpName %v2 "v2" -OpName %BC2 "BC2" -OpName %i_0 "i" -OpName %gl_FragColor "gl_FragColor" -OpMemberDecorate %U_t 0 Offset 0 -OpDecorate %U_t Block -OpDecorate %_ DescriptorSet 0 -%void = OpTypeVoid -%13 = OpTypeFunction %void -%float = OpTypeFloat 32 -%v4float = OpTypeVector %float 4 -%_ptr_Function_v4float = OpTypePointer Function %v4float -%_ptr_Input_v4float = OpTypePointer Input %v4float -%BC = OpVariable %_ptr_Input_v4float Input -%int = OpTypeInt 32 1 -%_ptr_Function_int = OpTypePointer Function %int -%int_0 = OpConstant %int 0 -%int_4 = OpConstant %int 4 -%bool = OpTypeBool -%_ptr_Function_float = OpTypePointer Function %float -%U_t = OpTypeStruct %float -%_ptr_Uniform_U_t = OpTypePointer Uniform %U_t -%_ = OpVariable %_ptr_Uniform_U_t Uniform -%_ptr_Uniform_float = OpTypePointer Uniform %float -%int_1 = OpConstant %int 1 -%BC2 = OpVariable %_ptr_Input_v4float Input -%_ptr_Output_v4float = OpTypePointer Output %v4float -%gl_FragColor = OpVariable %_ptr_Output_v4float Output -)"; - - const std::string before = - R"(%main = OpFunction %void None %13 -%28 = OpLabel -%v = OpVariable %_ptr_Function_v4float Function -%i = OpVariable %_ptr_Function_int Function -%v2 = OpVariable %_ptr_Function_v4float Function -%i_0 = OpVariable %_ptr_Function_int Function -%29 = OpLoad %v4float %BC -OpStore %v %29 -OpStore %i %int_0 -OpBranch %30 -%30 = OpLabel -OpLoopMerge %31 %32 None -OpBranch %33 -%33 = OpLabel -%34 = OpLoad %int %i -%35 = OpSLessThan %bool %34 %int_4 -OpBranchConditional %35 %36 %31 -%36 = OpLabel -%37 = OpLoad %int %i -%38 = OpLoad %int %i -%39 = OpAccessChain %_ptr_Function_float %v %38 -%40 = OpLoad %float %39 -%41 = OpAccessChain %_ptr_Uniform_float %_ %int_0 -%42 = OpLoad %float %41 -%43 = OpFDiv %float %40 %42 -%44 = OpAccessChain %_ptr_Function_float %v %37 -OpStore %44 %43 -OpBranch %32 -%32 = OpLabel -%45 = OpLoad %int %i -%46 = OpIAdd %int %45 %int_1 -OpStore %i %46 -OpBranch %30 -%31 = OpLabel -%47 = OpLoad %v4float %BC2 -OpStore %v2 %47 -OpStore %i_0 %int_0 -OpBranch %48 -%48 = OpLabel -OpLoopMerge %49 %50 None -OpBranch %51 -%51 = OpLabel -%52 = OpLoad %int %i_0 -%53 = OpSLessThan %bool %52 %int_4 -OpBranchConditional %53 %54 %49 -%54 = OpLabel -%55 = OpLoad %int %i_0 -%56 = OpLoad %int %i_0 -%57 = OpAccessChain %_ptr_Function_float %v2 %56 -%58 = OpLoad %float %57 -%59 = OpAccessChain %_ptr_Uniform_float %_ %int_0 -%60 = OpLoad %float %59 -%61 = OpFMul %float %58 %60 -%62 = OpAccessChain %_ptr_Function_float %v2 %55 -OpStore %62 %61 -OpBranch %50 -%50 = OpLabel -%63 = OpLoad %int %i_0 -%64 = OpIAdd %int %63 %int_1 -OpStore %i_0 %64 -OpBranch %48 -%49 = OpLabel -%65 = OpLoad %v4float %v -%66 = OpLoad %v4float %v2 -%67 = OpFAdd %v4float %65 %66 -OpStore %gl_FragColor %67 -OpReturn -OpFunctionEnd -)"; - - const std::string after = - R"(%main = OpFunction %void None %13 -%28 = OpLabel -%v = OpVariable %_ptr_Function_v4float Function -%i = OpVariable %_ptr_Function_int Function -%v2 = OpVariable %_ptr_Function_v4float Function -%i_0 = OpVariable %_ptr_Function_int Function -%72 = OpLoad %U_t %_ -%73 = OpCompositeExtract %float %72 0 -%29 = OpLoad %v4float %BC -OpStore %v %29 -OpStore %i %int_0 -OpBranch %30 -%30 = OpLabel -OpLoopMerge %31 %32 None -OpBranch %33 -%33 = OpLabel -%34 = OpLoad %int %i -%35 = OpSLessThan %bool %34 %int_4 -OpBranchConditional %35 %36 %31 -%36 = OpLabel -%37 = OpLoad %int %i -%38 = OpLoad %int %i -%39 = OpAccessChain %_ptr_Function_float %v %38 -%40 = OpLoad %float %39 -%43 = OpFDiv %float %40 %73 -%44 = OpAccessChain %_ptr_Function_float %v %37 -OpStore %44 %43 -OpBranch %32 -%32 = OpLabel -%45 = OpLoad %int %i -%46 = OpIAdd %int %45 %int_1 -OpStore %i %46 -OpBranch %30 -%31 = OpLabel -%47 = OpLoad %v4float %BC2 -OpStore %v2 %47 -OpStore %i_0 %int_0 -OpBranch %48 -%48 = OpLabel -OpLoopMerge %49 %50 None -OpBranch %51 -%51 = OpLabel -%52 = OpLoad %int %i_0 -%53 = OpSLessThan %bool %52 %int_4 -OpBranchConditional %53 %54 %49 -%54 = OpLabel -%55 = OpLoad %int %i_0 -%56 = OpLoad %int %i_0 -%57 = OpAccessChain %_ptr_Function_float %v2 %56 -%58 = OpLoad %float %57 -%61 = OpFMul %float %58 %73 -%62 = OpAccessChain %_ptr_Function_float %v2 %55 -OpStore %62 %61 -OpBranch %50 -%50 = OpLabel -%63 = OpLoad %int %i_0 -%64 = OpIAdd %int %63 %int_1 -OpStore %i_0 %64 -OpBranch %48 -%49 = OpLabel -%65 = OpLoad %v4float %v -%66 = OpLoad %v4float %v2 -%67 = OpFAdd %v4float %65 %66 -OpStore %gl_FragColor %67 -OpReturn -OpFunctionEnd -)"; - - SinglePassRunAndCheck(predefs + before, - predefs + after, true, true); -} - -TEST_F(CommonUniformElimTest, Volatile1) { - // Note: This test exemplifies the following: - // - Same test as Basic1 with the exception that - // the Load of g_F in else-branch is volatile - // - Common uniform (%_) load floated to nearest non-controlled block - // - // #version 140 - // in vec4 BaseColor; - // in float fi; - // - // layout(std140) uniform U_t - // { - // float g_F; - // float g_F2; - // } ; - // - // void main() - // { - // vec4 v = BaseColor; - // if (fi > 0) { - // v = v * g_F; - // } - // else { - // float f2 = g_F2 - g_F; - // v = v * f2; - // } - // gl_FragColor = v; - // } - - const std::string predefs = - R"(OpCapability Shader -%1 = OpExtInstImport "GLSL.std.450" -OpMemoryModel Logical GLSL450 -OpEntryPoint Fragment %main "main" %BaseColor %fi %gl_FragColor -OpExecutionMode %main OriginUpperLeft -OpSource GLSL 140 -OpName %main "main" -OpName %v "v" -OpName %BaseColor "BaseColor" -OpName %fi "fi" -OpName %U_t "U_t" -OpMemberName %U_t 0 "g_F" -OpMemberName %U_t 1 "g_F2" -OpName %_ "" -OpName %f2 "f2" -OpName %gl_FragColor "gl_FragColor" -OpMemberDecorate %U_t 0 Offset 0 -OpMemberDecorate %U_t 1 Offset 4 -OpDecorate %U_t Block -OpDecorate %_ DescriptorSet 0 -%void = OpTypeVoid -%11 = OpTypeFunction %void -%float = OpTypeFloat 32 -%v4float = OpTypeVector %float 4 -%_ptr_Function_v4float = OpTypePointer Function %v4float -%_ptr_Input_v4float = OpTypePointer Input %v4float -%BaseColor = OpVariable %_ptr_Input_v4float Input -%_ptr_Input_float = OpTypePointer Input %float -%fi = OpVariable %_ptr_Input_float Input -%float_0 = OpConstant %float 0 -%bool = OpTypeBool -%U_t = OpTypeStruct %float %float -%_ptr_Uniform_U_t = OpTypePointer Uniform %U_t -%_ = OpVariable %_ptr_Uniform_U_t Uniform -%int = OpTypeInt 32 1 -%int_0 = OpConstant %int 0 -%_ptr_Uniform_float = OpTypePointer Uniform %float -%_ptr_Function_float = OpTypePointer Function %float -%int_1 = OpConstant %int 1 -%_ptr_Output_v4float = OpTypePointer Output %v4float -%gl_FragColor = OpVariable %_ptr_Output_v4float Output -)"; - - const std::string before = - R"(%main = OpFunction %void None %11 -%26 = OpLabel -%v = OpVariable %_ptr_Function_v4float Function -%f2 = OpVariable %_ptr_Function_float Function -%27 = OpLoad %v4float %BaseColor -OpStore %v %27 -%28 = OpLoad %float %fi -%29 = OpFOrdGreaterThan %bool %28 %float_0 -OpSelectionMerge %30 None -OpBranchConditional %29 %31 %32 -%31 = OpLabel -%33 = OpLoad %v4float %v -%34 = OpAccessChain %_ptr_Uniform_float %_ %int_0 -%35 = OpLoad %float %34 -%36 = OpVectorTimesScalar %v4float %33 %35 -OpStore %v %36 -OpBranch %30 -%32 = OpLabel -%37 = OpAccessChain %_ptr_Uniform_float %_ %int_1 -%38 = OpLoad %float %37 -%39 = OpAccessChain %_ptr_Uniform_float %_ %int_0 -%40 = OpLoad %float %39 Volatile -%41 = OpFSub %float %38 %40 -OpStore %f2 %41 -%42 = OpLoad %v4float %v -%43 = OpLoad %float %f2 -%44 = OpVectorTimesScalar %v4float %42 %43 -OpStore %v %44 -OpBranch %30 -%30 = OpLabel -%45 = OpLoad %v4float %v -OpStore %gl_FragColor %45 -OpReturn -OpFunctionEnd -)"; - - const std::string after = - R"(%main = OpFunction %void None %11 -%26 = OpLabel -%v = OpVariable %_ptr_Function_v4float Function -%f2 = OpVariable %_ptr_Function_float Function -%50 = OpLoad %U_t %_ -%27 = OpLoad %v4float %BaseColor -OpStore %v %27 -%28 = OpLoad %float %fi -%29 = OpFOrdGreaterThan %bool %28 %float_0 -OpSelectionMerge %30 None -OpBranchConditional %29 %31 %32 -%31 = OpLabel -%33 = OpLoad %v4float %v -%47 = OpCompositeExtract %float %50 0 -%36 = OpVectorTimesScalar %v4float %33 %47 -OpStore %v %36 -OpBranch %30 -%32 = OpLabel -%49 = OpCompositeExtract %float %50 1 -%39 = OpAccessChain %_ptr_Uniform_float %_ %int_0 -%40 = OpLoad %float %39 Volatile -%41 = OpFSub %float %49 %40 -OpStore %f2 %41 -%42 = OpLoad %v4float %v -%43 = OpLoad %float %f2 -%44 = OpVectorTimesScalar %v4float %42 %43 -OpStore %v %44 -OpBranch %30 -%30 = OpLabel -%45 = OpLoad %v4float %v -OpStore %gl_FragColor %45 -OpReturn -OpFunctionEnd -)"; - - SinglePassRunAndCheck(predefs + before, - predefs + after, true, true); -} - -TEST_F(CommonUniformElimTest, Volatile2) { - // Note: This test exemplifies the following: - // - Same test as Basic1 with the exception that - // U_t is Volatile. - // - No optimizations are applied - // - // #version 430 - // in vec4 BaseColor; - // in float fi; - // - // layout(std430) volatile buffer U_t - // { - // float g_F; - // float g_F2; - // }; - // - // - // void main(void) - // { - // vec4 v = BaseColor; - // if (fi > 0) { - // v = v * g_F; - // } else { - // float f2 = g_F2 - g_F; - // v = v * f2; - // } - // } - - const std::string text = - R"(OpCapability Shader -%1 = OpExtInstImport "GLSL.std.450" -OpMemoryModel Logical GLSL450 -OpEntryPoint Fragment %main "main" %BaseColor %fi -OpExecutionMode %main OriginUpperLeft -OpSource GLSL 430 -OpName %main "main" -OpName %v "v" -OpName %BaseColor "BaseColor" -OpName %fi "fi" -OpName %U_t "U_t" -OpMemberName %U_t 0 "g_F" -OpMemberName %U_t 1 "g_F2" -OpName %_ "" -OpName %f2 "f2" -OpDecorate %BaseColor Location 0 -OpDecorate %fi Location 0 -OpMemberDecorate %U_t 0 Volatile -OpMemberDecorate %U_t 0 Offset 0 -OpMemberDecorate %U_t 1 Volatile -OpMemberDecorate %U_t 1 Offset 4 -OpDecorate %U_t BufferBlock -OpDecorate %_ DescriptorSet 0 -%void = OpTypeVoid -%3 = OpTypeFunction %void -%float = OpTypeFloat 32 -%v4float = OpTypeVector %float 4 -%_ptr_Function_v4float = OpTypePointer Function %v4float -%_ptr_Input_v4float = OpTypePointer Input %v4float -%BaseColor = OpVariable %_ptr_Input_v4float Input -%_ptr_Input_float = OpTypePointer Input %float -%fi = OpVariable %_ptr_Input_float Input -%float_0 = OpConstant %float 0 -%bool = OpTypeBool -%U_t = OpTypeStruct %float %float -%_ptr_Uniform_U_t = OpTypePointer Uniform %U_t -%_ = OpVariable %_ptr_Uniform_U_t Uniform -%int = OpTypeInt 32 1 -%int_0 = OpConstant %int 0 -%_ptr_Uniform_float = OpTypePointer Uniform %float -%_ptr_Function_float = OpTypePointer Function %float -%int_1 = OpConstant %int 1 -%main = OpFunction %void None %3 -%5 = OpLabel -%v = OpVariable %_ptr_Function_v4float Function -%f2 = OpVariable %_ptr_Function_float Function -%12 = OpLoad %v4float %BaseColor -OpStore %v %12 -%15 = OpLoad %float %fi -%18 = OpFOrdGreaterThan %bool %15 %float_0 -OpSelectionMerge %20 None -OpBranchConditional %18 %19 %31 -%19 = OpLabel -%21 = OpLoad %v4float %v -%28 = OpAccessChain %_ptr_Uniform_float %_ %int_0 -%29 = OpLoad %float %28 -%30 = OpVectorTimesScalar %v4float %21 %29 -OpStore %v %30 -OpBranch %20 -%31 = OpLabel -%35 = OpAccessChain %_ptr_Uniform_float %_ %int_1 -%36 = OpLoad %float %35 -%37 = OpAccessChain %_ptr_Uniform_float %_ %int_0 -%38 = OpLoad %float %37 -%39 = OpFSub %float %36 %38 -OpStore %f2 %39 -%40 = OpLoad %v4float %v -%41 = OpLoad %float %f2 -%42 = OpVectorTimesScalar %v4float %40 %41 -OpStore %v %42 -OpBranch %20 -%20 = OpLabel -OpReturn -OpFunctionEnd -)"; - - Pass::Status res = std::get<1>( - SinglePassRunAndDisassemble(text, true, false)); - EXPECT_EQ(res, Pass::Status::SuccessWithoutChange); -} - -TEST_F(CommonUniformElimTest, Volatile3) { - // Note: This test exemplifies the following: - // - Same test as Volatile2 with the exception that - // the nested struct S is volatile - // - No optimizations are applied - // - // #version 430 - // in vec4 BaseColor; - // in float fi; - // - // struct S { - // volatile float a; - // }; - // - // layout(std430) buffer U_t - // { - // S g_F; - // S g_F2; - // }; - // - // - // void main(void) - // { - // vec4 v = BaseColor; - // if (fi > 0) { - // v = v * g_F.a; - // } else { - // float f2 = g_F2.a - g_F.a; - // v = v * f2; - // } - // } - - const std::string text = - R"(OpCapability Shader -%1 = OpExtInstImport "GLSL.std.450" -OpMemoryModel Logical GLSL450 -OpEntryPoint Fragment %main "main" %BaseColor %fi -OpExecutionMode %main OriginUpperLeft -OpSource GLSL 430 -OpName %main "main" -OpName %v "v" -OpName %BaseColor "BaseColor" -OpName %fi "fi" -OpName %S "S" -OpMemberName %S 0 "a" -OpName %U_t "U_t" -OpMemberName %U_t 0 "g_F" -OpMemberName %U_t 1 "g_F2" -OpName %_ "" -OpName %f2 "f2" -OpDecorate %BaseColor Location 0 -OpDecorate %fi Location 0 -OpMemberDecorate %S 0 Offset 0 -OpMemberDecorate %S 0 Volatile -OpMemberDecorate %U_t 0 Offset 0 -OpMemberDecorate %U_t 1 Offset 4 -OpDecorate %U_t BufferBlock -OpDecorate %_ DescriptorSet 0 -%void = OpTypeVoid -%3 = OpTypeFunction %void -%float = OpTypeFloat 32 -%v4float = OpTypeVector %float 4 -%_ptr_Function_v4float = OpTypePointer Function %v4float -%_ptr_Input_v4float = OpTypePointer Input %v4float -%BaseColor = OpVariable %_ptr_Input_v4float Input -%_ptr_Input_float = OpTypePointer Input %float -%fi = OpVariable %_ptr_Input_float Input -%float_0 = OpConstant %float 0 -%bool = OpTypeBool -%S = OpTypeStruct %float -%U_t = OpTypeStruct %S %S -%_ptr_Uniform_U_t = OpTypePointer Uniform %U_t -%_ = OpVariable %_ptr_Uniform_U_t Uniform -%int = OpTypeInt 32 1 -%int_0 = OpConstant %int 0 -%_ptr_Uniform_float = OpTypePointer Uniform %float -%_ptr_Function_float = OpTypePointer Function %float -%int_1 = OpConstant %int 1 -%main = OpFunction %void None %3 -%5 = OpLabel -%v = OpVariable %_ptr_Function_v4float Function -%f2 = OpVariable %_ptr_Function_float Function -%12 = OpLoad %v4float %BaseColor -OpStore %v %12 -%15 = OpLoad %float %fi -%18 = OpFOrdGreaterThan %bool %15 %float_0 -OpSelectionMerge %20 None -OpBranchConditional %18 %19 %32 -%19 = OpLabel -%21 = OpLoad %v4float %v -%29 = OpAccessChain %_ptr_Uniform_float %_ %int_0 %int_0 -%30 = OpLoad %float %29 -%31 = OpVectorTimesScalar %v4float %21 %30 -OpStore %v %31 -OpBranch %20 -%32 = OpLabel -%36 = OpAccessChain %_ptr_Uniform_float %_ %int_1 %int_0 -%37 = OpLoad %float %36 -%38 = OpAccessChain %_ptr_Uniform_float %_ %int_0 %int_0 -%39 = OpLoad %float %38 -%40 = OpFSub %float %37 %39 -OpStore %f2 %40 -%41 = OpLoad %v4float %v -%42 = OpLoad %float %f2 -%43 = OpVectorTimesScalar %v4float %41 %42 -OpStore %v %43 -OpBranch %20 -%20 = OpLabel -OpReturn -OpFunctionEnd -)"; - - Pass::Status res = std::get<1>( - SinglePassRunAndDisassemble(text, true, false)); - EXPECT_EQ(res, Pass::Status::SuccessWithoutChange); -} - -TEST_F(CommonUniformElimTest, IteratorDanglingPointer) { - // Note: This test exemplifies the following: - // - Existing common uniform (%_) load kept in place and shared - // - // #version 140 - // in vec4 BaseColor; - // in float fi; - // - // layout(std140) uniform U_t - // { - // bool g_B; - // float g_F; - // } ; - // - // uniform float alpha; - // uniform bool alpha_B; - // - // void main() - // { - // vec4 v = BaseColor; - // if (g_B) { - // v = v * g_F; - // if (alpha_B) - // v = v * alpha; - // else - // v = v * fi; - // } - // gl_FragColor = v; - // } - - const std::string predefs = - R"(OpCapability Shader -%1 = OpExtInstImport "GLSL.std.450" -OpMemoryModel Logical GLSL450 -OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor %fi -OpExecutionMode %main OriginUpperLeft -OpSource GLSL 140 -OpName %main "main" -OpName %v "v" -OpName %BaseColor "BaseColor" -OpName %U_t "U_t" -OpMemberName %U_t 0 "g_B" -OpMemberName %U_t 1 "g_F" -OpName %alpha "alpha" -OpName %alpha_B "alpha_B" -OpName %_ "" -OpName %gl_FragColor "gl_FragColor" -OpName %fi "fi" -OpMemberDecorate %U_t 0 Offset 0 -OpMemberDecorate %U_t 1 Offset 4 -OpDecorate %U_t Block -OpDecorate %_ DescriptorSet 0 -%void = OpTypeVoid -%12 = OpTypeFunction %void -%float = OpTypeFloat 32 -%v4float = OpTypeVector %float 4 -%_ptr_Function_v4float = OpTypePointer Function %v4float -%_ptr_Input_v4float = OpTypePointer Input %v4float -%BaseColor = OpVariable %_ptr_Input_v4float Input -%uint = OpTypeInt 32 0 -%U_t = OpTypeStruct %uint %float -%_ptr_Uniform_U_t = OpTypePointer Uniform %U_t -%_ = OpVariable %_ptr_Uniform_U_t Uniform -%int = OpTypeInt 32 1 -%int_0 = OpConstant %int 0 -%_ptr_Uniform_uint = OpTypePointer Uniform %uint -%bool = OpTypeBool -%uint_0 = OpConstant %uint 0 -%int_1 = OpConstant %int 1 -%_ptr_Uniform_float = OpTypePointer Uniform %float -%_ptr_Output_v4float = OpTypePointer Output %v4float -%gl_FragColor = OpVariable %_ptr_Output_v4float Output -%_ptr_Input_float = OpTypePointer Input %float -%fi = OpVariable %_ptr_Input_float Input -%alpha = OpVariable %_ptr_Uniform_float Uniform -%alpha_B = OpVariable %_ptr_Uniform_uint Uniform -)"; - - const std::string before = - R"(%main = OpFunction %void None %12 -%26 = OpLabel -%v = OpVariable %_ptr_Function_v4float Function -%27 = OpLoad %v4float %BaseColor -OpStore %v %27 -%28 = OpAccessChain %_ptr_Uniform_uint %_ %int_0 -%29 = OpLoad %uint %28 -%30 = OpINotEqual %bool %29 %uint_0 -OpSelectionMerge %31 None -OpBranchConditional %30 %31 %32 -%32 = OpLabel -%47 = OpLoad %v4float %v -OpStore %gl_FragColor %47 -OpReturn -%31 = OpLabel -%33 = OpAccessChain %_ptr_Uniform_float %_ %int_1 -%34 = OpLoad %float %33 -%35 = OpLoad %v4float %v -%36 = OpVectorTimesScalar %v4float %35 %34 -OpStore %v %36 -%37 = OpLoad %uint %alpha_B -%38 = OpIEqual %bool %37 %uint_0 -OpSelectionMerge %43 None -OpBranchConditional %38 %43 %39 -%39 = OpLabel -%40 = OpLoad %float %alpha -%41 = OpLoad %v4float %v -%42 = OpVectorTimesScalar %v4float %41 %40 -OpStore %v %42 -OpBranch %50 -%50 = OpLabel -%51 = OpLoad %v4float %v -OpStore %gl_FragColor %51 -OpReturn -%43 = OpLabel -%44 = OpLoad %float %fi -%45 = OpLoad %v4float %v -%46 = OpVectorTimesScalar %v4float %45 %44 -OpStore %v %46 -OpBranch %60 -%60 = OpLabel -%61 = OpLoad %v4float %v -OpStore %gl_FragColor %61 -OpReturn -OpFunctionEnd -)"; - - const std::string after = - R"(%main = OpFunction %void None %12 -%28 = OpLabel -%v = OpVariable %_ptr_Function_v4float Function -%29 = OpLoad %v4float %BaseColor -OpStore %v %29 -%54 = OpLoad %U_t %_ -%55 = OpCompositeExtract %uint %54 0 -%32 = OpINotEqual %bool %55 %uint_0 -OpSelectionMerge %33 None -OpBranchConditional %32 %33 %34 -%34 = OpLabel -%35 = OpLoad %v4float %v -OpStore %gl_FragColor %35 -OpReturn -%33 = OpLabel -%58 = OpLoad %float %alpha -%57 = OpCompositeExtract %float %54 1 -%38 = OpLoad %v4float %v -%39 = OpVectorTimesScalar %v4float %38 %57 -OpStore %v %39 -%40 = OpLoad %uint %alpha_B -%41 = OpIEqual %bool %40 %uint_0 -OpSelectionMerge %42 None -OpBranchConditional %41 %42 %43 -%43 = OpLabel -%45 = OpLoad %v4float %v -%46 = OpVectorTimesScalar %v4float %45 %58 -OpStore %v %46 -OpBranch %47 -%47 = OpLabel -%48 = OpLoad %v4float %v -OpStore %gl_FragColor %48 -OpReturn -%42 = OpLabel -%49 = OpLoad %float %fi -%50 = OpLoad %v4float %v -%51 = OpVectorTimesScalar %v4float %50 %49 -OpStore %v %51 -OpBranch %52 -%52 = OpLabel -%53 = OpLoad %v4float %v -OpStore %gl_FragColor %53 -OpReturn -OpFunctionEnd -)"; - - SinglePassRunAndCheck(predefs + before, - predefs + after, true, true); -} - -#ifdef SPIRV_EFFCEE -TEST_F(CommonUniformElimTest, MixedConstantAndNonConstantIndexes) { - const std::string text = R"( -; CHECK: [[var:%\w+]] = OpVariable {{%\w+}} Uniform -; CHECK: %501 = OpLabel -; CHECK: [[ld:%\w+]] = OpLoad -; CHECK-NOT: OpCompositeExtract {{%\w+}} {{%\w+}} 0 2 484 -; CHECK: OpAccessChain {{%\w+}} [[var]] %int_0 %int_2 [[ld]] - OpCapability Shader - %1 = OpExtInstImport "GLSL.std.450" - OpMemoryModel Logical GLSL450 - OpEntryPoint Fragment %4 "ringeffectLayer_px" %gl_FragCoord %178 %182 - OpExecutionMode %4 OriginUpperLeft - OpSource HLSL 500 - OpDecorate %_arr_v4float_uint_10 ArrayStride 16 - OpMemberDecorate %_struct_20 0 Offset 0 - OpMemberDecorate %_struct_20 1 Offset 16 - OpMemberDecorate %_struct_20 2 Offset 32 - OpMemberDecorate %_struct_21 0 Offset 0 - OpDecorate %_struct_21 Block - OpDecorate %23 DescriptorSet 0 - OpDecorate %gl_FragCoord BuiltIn FragCoord - OpDecorate %178 Location 0 - OpDecorate %182 Location 0 - %void = OpTypeVoid - %3 = OpTypeFunction %void - %float = OpTypeFloat 32 - %v4float = OpTypeVector %float 4 - %v2float = OpTypeVector %float 2 -%_ptr_Function_v2float = OpTypePointer Function %v2float - %uint = OpTypeInt 32 0 - %uint_10 = OpConstant %uint 10 -%_arr_v4float_uint_10 = OpTypeArray %v4float %uint_10 - %_struct_20 = OpTypeStruct %v4float %v4float %_arr_v4float_uint_10 - %_struct_21 = OpTypeStruct %_struct_20 -%_ptr_Uniform__struct_21 = OpTypePointer Uniform %_struct_21 - %23 = OpVariable %_ptr_Uniform__struct_21 Uniform - %int = OpTypeInt 32 1 - %int_0 = OpConstant %int 0 -%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float -%_ptr_Uniform_float = OpTypePointer Uniform %float - %uint_3 = OpConstant %uint 3 -%_ptr_Function_v4float = OpTypePointer Function %v4float - %float_0 = OpConstant %float 0 - %43 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0 -%_ptr_Function_int = OpTypePointer Function %int - %int_5 = OpConstant %int 5 - %bool = OpTypeBool - %int_1 = OpConstant %int 1 - %int_2 = OpConstant %int 2 - %uint_5 = OpConstant %uint 5 -%_arr_v2float_uint_5 = OpTypeArray %v2float %uint_5 -%_ptr_Function__arr_v2float_uint_5 = OpTypePointer Function %_arr_v2float_uint_5 - %82 = OpTypeImage %float 2D 0 0 0 1 Unknown -%_ptr_UniformConstant_82 = OpTypePointer UniformConstant %82 - %86 = OpTypeSampler -%_ptr_UniformConstant_86 = OpTypePointer UniformConstant %86 - %90 = OpTypeSampledImage %82 - %v3float = OpTypeVector %float 3 -%_ptr_Input_v4float = OpTypePointer Input %v4float -%gl_FragCoord = OpVariable %_ptr_Input_v4float Input - %178 = OpVariable %_ptr_Input_v4float Input -%_ptr_Output_v4float = OpTypePointer Output %v4float - %182 = OpVariable %_ptr_Output_v4float Output - %4 = OpFunction %void None %3 - %5 = OpLabel - %483 = OpVariable %_ptr_Function_v4float Function - %484 = OpVariable %_ptr_Function_int Function - %486 = OpVariable %_ptr_Function__arr_v2float_uint_5 Function - %179 = OpLoad %v4float %178 - %493 = OpAccessChain %_ptr_Uniform_float %23 %int_0 %int_0 %uint_3 - %494 = OpLoad %float %493 - OpStore %483 %43 - OpStore %484 %int_0 - OpBranch %495 - %495 = OpLabel - OpLoopMerge %496 %497 None - OpBranch %498 - %498 = OpLabel - %499 = OpLoad %int %484 - %500 = OpSLessThan %bool %499 %int_5 - OpBranchConditional %500 %501 %496 - %501 = OpLabel - %504 = OpVectorShuffle %v2float %179 %179 0 1 - %505 = OpLoad %int %484 - %506 = OpAccessChain %_ptr_Uniform_v4float %23 %int_0 %int_2 %505 - %507 = OpLoad %v4float %506 - %508 = OpVectorShuffle %v2float %507 %507 0 1 - %509 = OpFAdd %v2float %504 %508 - %512 = OpAccessChain %_ptr_Uniform_v4float %23 %int_0 %int_1 - %513 = OpLoad %v4float %512 - %514 = OpVectorShuffle %v2float %513 %513 0 1 - %517 = OpVectorShuffle %v2float %513 %513 2 3 - %518 = OpExtInst %v2float %1 FClamp %509 %514 %517 - %519 = OpAccessChain %_ptr_Function_v2float %486 %505 - OpStore %519 %518 - OpBranch %497 - %497 = OpLabel - %520 = OpLoad %int %484 - %521 = OpIAdd %int %520 %int_1 - OpStore %484 %521 - OpBranch %495 - %496 = OpLabel - OpReturn - OpFunctionEnd -)"; - - SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(text, true); -} -#endif // SPIRV_EFFCEE -// TODO(greg-lunarg): Add tests to verify handling of these cases: -// -// Disqualifying cases: extensions, decorations, non-logical addressing, -// non-structured control flow -// Others? - -} // namespace -} // namespace opt -} // namespace spvtools diff --git a/third_party/spirv-tools/test/opt/constant_manager_test.cpp b/third_party/spirv-tools/test/opt/constant_manager_test.cpp index 57dea65120..14e14ec20e 100644 --- a/third_party/spirv-tools/test/opt/constant_manager_test.cpp +++ b/third_party/spirv-tools/test/opt/constant_manager_test.cpp @@ -82,6 +82,28 @@ TEST_F(ConstantManagerTest, GetDefiningInstruction2) { EXPECT_EQ(const_inst_2->result_id(), 4); } +TEST_F(ConstantManagerTest, GetDefiningInstructionIdOverflow) { + const std::string text = R"( +%1 = OpTypeInt 32 0 +%3 = OpConstant %1 1 +%4 = OpConstant %1 2 + )"; + + std::unique_ptr context = + BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + ASSERT_NE(context, nullptr); + + // Set the id bound to the max, so the new constant cannot be generated. + context->module()->SetIdBound(context->max_id_bound()); + + Type* int_type = context->get_type_mgr()->GetType(1); + IntConstant int_constant(int_type->AsInteger(), {3}); + Instruction* inst = + context->get_constant_mgr()->GetDefiningInstruction(&int_constant, 1); + EXPECT_EQ(inst, nullptr); +} + } // namespace } // namespace analysis } // namespace opt diff --git a/third_party/spirv-tools/test/opt/constants_test.cpp b/third_party/spirv-tools/test/opt/constants_test.cpp new file mode 100644 index 0000000000..55c92a513f --- /dev/null +++ b/third_party/spirv-tools/test/opt/constants_test.cpp @@ -0,0 +1,167 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/opt/constants.h" + +#include + +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include "source/opt/types.h" + +namespace spvtools { +namespace opt { +namespace analysis { +namespace { + +using ConstantTest = ::testing::Test; +using ::testing::ValuesIn; + +template +struct GetExtendedValueCase { + bool is_signed; + int width; + std::vector words; + T expected_value; +}; + +using GetSignExtendedValueCase = GetExtendedValueCase; +using GetZeroExtendedValueCase = GetExtendedValueCase; + +using GetSignExtendedValueTest = + ::testing::TestWithParam; +using GetZeroExtendedValueTest = + ::testing::TestWithParam; + +TEST_P(GetSignExtendedValueTest, Case) { + Integer type(GetParam().width, GetParam().is_signed); + IntConstant value(&type, GetParam().words); + + EXPECT_EQ(GetParam().expected_value, value.GetSignExtendedValue()); +} + +TEST_P(GetZeroExtendedValueTest, Case) { + Integer type(GetParam().width, GetParam().is_signed); + IntConstant value(&type, GetParam().words); + + EXPECT_EQ(GetParam().expected_value, value.GetZeroExtendedValue()); +} + +const uint32_t k32ones = ~uint32_t(0); +const uint64_t k64ones = ~uint64_t(0); +const int64_t kSBillion = 1000 * 1000 * 1000; +const uint64_t kUBillion = 1000 * 1000 * 1000; + +INSTANTIATE_TEST_SUITE_P(AtMost32Bits, GetSignExtendedValueTest, + ValuesIn(std::vector{ + // 4 bits + {false, 4, {0}, 0}, + {false, 4, {7}, 7}, + {false, 4, {15}, 15}, + {true, 4, {0}, 0}, + {true, 4, {7}, 7}, + {true, 4, {0xfffffff8}, -8}, + {true, 4, {k32ones}, -1}, + // 16 bits + {false, 16, {0}, 0}, + {false, 16, {32767}, 32767}, + {false, 16, {32768}, 32768}, + {false, 16, {65000}, 65000}, + {true, 16, {0}, 0}, + {true, 16, {32767}, 32767}, + {true, 16, {0xfffffff8}, -8}, + {true, 16, {k32ones}, -1}, + // 32 bits + {false, 32, {0}, 0}, + {false, 32, {1000000}, 1000000}, + {true, 32, {0xfffffff8}, -8}, + {true, 32, {k32ones}, -1}, + })); + +INSTANTIATE_TEST_SUITE_P(AtMost64Bits, GetSignExtendedValueTest, + ValuesIn(std::vector{ + // 48 bits + {false, 48, {0, 0}, 0}, + {false, 48, {5, 0}, 5}, + {false, 48, {0xfffffff8, k32ones}, -8}, + {false, 48, {k32ones, k32ones}, -1}, + {false, 48, {0xdcd65000, 1}, 8 * kSBillion}, + {true, 48, {0xfffffff8, k32ones}, -8}, + {true, 48, {k32ones, k32ones}, -1}, + {true, 48, {0xdcd65000, 1}, 8 * kSBillion}, + + // 64 bits + {false, 64, {12, 0}, 12}, + {false, 64, {0xdcd65000, 1}, 8 * kSBillion}, + {false, 48, {0xfffffff8, k32ones}, -8}, + {false, 64, {k32ones, k32ones}, -1}, + {true, 64, {12, 0}, 12}, + {true, 64, {0xdcd65000, 1}, 8 * kSBillion}, + {true, 48, {0xfffffff8, k32ones}, -8}, + {true, 64, {k32ones, k32ones}, -1}, + })); + +INSTANTIATE_TEST_SUITE_P(AtMost32Bits, GetZeroExtendedValueTest, + ValuesIn(std::vector{ + // 4 bits + {false, 4, {0}, 0}, + {false, 4, {7}, 7}, + {false, 4, {15}, 15}, + {true, 4, {0}, 0}, + {true, 4, {7}, 7}, + {true, 4, {0xfffffff8}, 0xfffffff8}, + {true, 4, {k32ones}, k32ones}, + // 16 bits + {false, 16, {0}, 0}, + {false, 16, {32767}, 32767}, + {false, 16, {32768}, 32768}, + {false, 16, {65000}, 65000}, + {true, 16, {0}, 0}, + {true, 16, {32767}, 32767}, + {true, 16, {0xfffffff8}, 0xfffffff8}, + {true, 16, {k32ones}, k32ones}, + // 32 bits + {false, 32, {0}, 0}, + {false, 32, {1000000}, 1000000}, + {true, 32, {0xfffffff8}, 0xfffffff8}, + {true, 32, {k32ones}, k32ones}, + })); + +INSTANTIATE_TEST_SUITE_P(AtMost64Bits, GetZeroExtendedValueTest, + ValuesIn(std::vector{ + // 48 bits + {false, 48, {0, 0}, 0}, + {false, 48, {5, 0}, 5}, + {false, 48, {0xfffffff8, k32ones}, uint64_t(-8)}, + {false, 48, {k32ones, k32ones}, uint64_t(-1)}, + {false, 48, {0xdcd65000, 1}, 8 * kUBillion}, + {true, 48, {0xfffffff8, k32ones}, uint64_t(-8)}, + {true, 48, {k32ones, k32ones}, uint64_t(-1)}, + {true, 48, {0xdcd65000, 1}, 8 * kUBillion}, + + // 64 bits + {false, 64, {12, 0}, 12}, + {false, 64, {0xdcd65000, 1}, 8 * kUBillion}, + {false, 48, {0xfffffff8, k32ones}, uint64_t(-8)}, + {false, 64, {k32ones, k32ones}, k64ones}, + {true, 64, {12, 0}, 12}, + {true, 64, {0xdcd65000, 1}, 8 * kUBillion}, + {true, 48, {0xfffffff8, k32ones}, uint64_t(-8)}, + {true, 64, {k32ones, k32ones}, k64ones}, + })); + +} // namespace +} // namespace analysis +} // namespace opt +} // namespace spvtools diff --git a/third_party/spirv-tools/test/opt/convert_relaxed_to_half_test.cpp b/third_party/spirv-tools/test/opt/convert_relaxed_to_half_test.cpp new file mode 100644 index 0000000000..c138154773 --- /dev/null +++ b/third_party/spirv-tools/test/opt/convert_relaxed_to_half_test.cpp @@ -0,0 +1,1336 @@ +// Copyright (c) 2019 Valve Corporation +// Copyright (c) 2019 LunarG Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Convert Relaxed to Half tests + +#include +#include + +#include "test/opt/assembly_builder.h" +#include "test/opt/pass_fixture.h" +#include "test/opt/pass_utils.h" + +namespace spvtools { +namespace opt { +namespace { + +using ConvertToHalfTest = PassTest<::testing::Test>; + +TEST_F(ConvertToHalfTest, ConvertToHalfBasic) { + // The resulting SPIR-V was processed with --relax-float-ops. + // + // clang-format off + // + // SamplerState g_sSamp : register(s0); + // uniform Texture1D g_tTex1df4 : register(t0); + // + // struct PS_INPUT + // { + // float Tex0 : TEXCOORD0; + // }; + // + // struct PS_OUTPUT + // { + // float4 Color : SV_Target0; + // }; + // + // cbuffer cbuff{ + // float c; + // } + // + // PS_OUTPUT main(PS_INPUT i) + // { + // PS_OUTPUT psout; + // psout.Color = g_tTex1df4.Sample(g_sSamp, i.Tex0) * c; + // return psout; + // } + // + // clang-format on + + const std::string defs_before = + R"(OpCapability Shader +OpCapability Sampled1D +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %i_Tex0 %_entryPointOutput_Color +OpExecutionMode %main OriginUpperLeft +OpSource HLSL 500 +OpName %main "main" +OpName %g_tTex1df4 "g_tTex1df4" +OpName %g_sSamp "g_sSamp" +OpName %cbuff "cbuff" +OpMemberName %cbuff 0 "c" +OpName %_ "" +OpName %i_Tex0 "i.Tex0" +OpName %_entryPointOutput_Color "@entryPointOutput.Color" +OpDecorate %g_tTex1df4 DescriptorSet 0 +OpDecorate %g_tTex1df4 Binding 0 +OpDecorate %g_sSamp DescriptorSet 0 +OpDecorate %g_sSamp Binding 0 +OpMemberDecorate %cbuff 0 Offset 0 +OpDecorate %cbuff Block +OpDecorate %_ DescriptorSet 0 +OpDecorate %_ Binding 1 +OpDecorate %i_Tex0 Location 0 +OpDecorate %_entryPointOutput_Color Location 0 +OpDecorate %48 RelaxedPrecision +OpDecorate %63 RelaxedPrecision +OpDecorate %65 RelaxedPrecision +OpDecorate %66 RelaxedPrecision +%void = OpTypeVoid +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v4float = OpTypeVector %float 4 +%int = OpTypeInt 32 1 +%int_0 = OpConstant %int 0 +%19 = OpTypeImage %float 1D 0 0 0 1 Unknown +%_ptr_UniformConstant_19 = OpTypePointer UniformConstant %19 +%g_tTex1df4 = OpVariable %_ptr_UniformConstant_19 UniformConstant +%23 = OpTypeSampler +%_ptr_UniformConstant_23 = OpTypePointer UniformConstant %23 +%g_sSamp = OpVariable %_ptr_UniformConstant_23 UniformConstant +%27 = OpTypeSampledImage %19 +%cbuff = OpTypeStruct %float +%_ptr_Uniform_cbuff = OpTypePointer Uniform %cbuff +%_ = OpVariable %_ptr_Uniform_cbuff Uniform +%_ptr_Uniform_float = OpTypePointer Uniform %float +%_ptr_Input_float = OpTypePointer Input %float +%i_Tex0 = OpVariable %_ptr_Input_float Input +%_ptr_Output_v4float = OpTypePointer Output %v4float +%_entryPointOutput_Color = OpVariable %_ptr_Output_v4float Output +)"; + + const std::string defs_after = + R"(OpCapability Shader +OpCapability Sampled1D +OpCapability Float16 +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %i_Tex0 %_entryPointOutput_Color +OpExecutionMode %main OriginUpperLeft +OpSource HLSL 500 +OpName %main "main" +OpName %g_tTex1df4 "g_tTex1df4" +OpName %g_sSamp "g_sSamp" +OpName %cbuff "cbuff" +OpMemberName %cbuff 0 "c" +OpName %_ "" +OpName %i_Tex0 "i.Tex0" +OpName %_entryPointOutput_Color "@entryPointOutput.Color" +OpDecorate %g_tTex1df4 DescriptorSet 0 +OpDecorate %g_tTex1df4 Binding 0 +OpDecorate %g_sSamp DescriptorSet 0 +OpDecorate %g_sSamp Binding 0 +OpMemberDecorate %cbuff 0 Offset 0 +OpDecorate %cbuff Block +OpDecorate %_ DescriptorSet 0 +OpDecorate %_ Binding 1 +OpDecorate %i_Tex0 Location 0 +OpDecorate %_entryPointOutput_Color Location 0 +%void = OpTypeVoid +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v4float = OpTypeVector %float 4 +%int = OpTypeInt 32 1 +%int_0 = OpConstant %int 0 +%19 = OpTypeImage %float 1D 0 0 0 1 Unknown +%_ptr_UniformConstant_19 = OpTypePointer UniformConstant %19 +%g_tTex1df4 = OpVariable %_ptr_UniformConstant_19 UniformConstant +%23 = OpTypeSampler +%_ptr_UniformConstant_23 = OpTypePointer UniformConstant %23 +%g_sSamp = OpVariable %_ptr_UniformConstant_23 UniformConstant +%27 = OpTypeSampledImage %19 +%cbuff = OpTypeStruct %float +%_ptr_Uniform_cbuff = OpTypePointer Uniform %cbuff +%_ = OpVariable %_ptr_Uniform_cbuff Uniform +%_ptr_Uniform_float = OpTypePointer Uniform %float +%_ptr_Input_float = OpTypePointer Input %float +%i_Tex0 = OpVariable %_ptr_Input_float Input +%_ptr_Output_v4float = OpTypePointer Output %v4float +%_entryPointOutput_Color = OpVariable %_ptr_Output_v4float Output +%half = OpTypeFloat 16 +%v4half = OpTypeVector %half 4 +)"; + + const std::string func_before = + R"(%main = OpFunction %void None %3 +%5 = OpLabel +%48 = OpLoad %float %i_Tex0 +%58 = OpLoad %19 %g_tTex1df4 +%59 = OpLoad %23 %g_sSamp +%60 = OpSampledImage %27 %58 %59 +%63 = OpImageSampleImplicitLod %v4float %60 %48 +%64 = OpAccessChain %_ptr_Uniform_float %_ %int_0 +%65 = OpLoad %float %64 +%66 = OpVectorTimesScalar %v4float %63 %65 +OpStore %_entryPointOutput_Color %66 +OpReturn +OpFunctionEnd +)"; + + const std::string func_after = + R"(%main = OpFunction %void None %3 +%5 = OpLabel +%48 = OpLoad %float %i_Tex0 +%58 = OpLoad %19 %g_tTex1df4 +%59 = OpLoad %23 %g_sSamp +%60 = OpSampledImage %27 %58 %59 +%63 = OpImageSampleImplicitLod %v4float %60 %48 +%64 = OpAccessChain %_ptr_Uniform_float %_ %int_0 +%65 = OpLoad %float %64 +%69 = OpFConvert %v4half %63 +%70 = OpFConvert %half %65 +%66 = OpVectorTimesScalar %v4half %69 %70 +%71 = OpFConvert %v4float %66 +OpStore %_entryPointOutput_Color %71 +OpReturn +OpFunctionEnd +)"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck(defs_before + func_before, + defs_after + func_after, true, true); +} + +TEST_F(ConvertToHalfTest, ConvertToHalfWithDrefSample) { + // The resulting SPIR-V was processed with --relax-float-ops. + // + // clang-format off + // + // SamplerComparisonState g_sSamp : register(s0); + // uniform Texture1D g_tTex1df4 : register(t0); + // + // cbuffer cbuff{ + // float c1; + // float c2; + // }; + // + // struct PS_INPUT + // { + // float Tex0 : TEXCOORD0; + // float Tex1 : TEXCOORD1; + // }; + // + // struct PS_OUTPUT + // { + // float Color : SV_Target0; + // }; + // + // PS_OUTPUT main(PS_INPUT i) + // { + // PS_OUTPUT psout; + // float txval10 = g_tTex1df4.SampleCmp(g_sSamp, i.Tex0 * 0.1, c1 + 0.1); + // float txval11 = g_tTex1df4.SampleCmp(g_sSamp, i.Tex1 * 0.2, c2 + 0.2); + // float t = txval10 + txval11; + // float t2 = t / 2.0; + // psout.Color = t2; + // return psout; + // } + // + // clang-format on + + const std::string defs_before = + R"(OpCapability Shader +OpCapability Sampled1D +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %i_Tex0 %i_Tex1 %_entryPointOutput_Color +OpExecutionMode %main OriginUpperLeft +OpSource HLSL 500 +OpName %main "main" +OpName %g_tTex1df4 "g_tTex1df4" +OpName %g_sSamp "g_sSamp" +OpName %cbuff "cbuff" +OpMemberName %cbuff 0 "c1" +OpMemberName %cbuff 1 "c2" +OpName %_ "" +OpName %i_Tex0 "i.Tex0" +OpName %i_Tex1 "i.Tex1" +OpName %_entryPointOutput_Color "@entryPointOutput.Color" +OpDecorate %g_tTex1df4 DescriptorSet 0 +OpDecorate %g_tTex1df4 Binding 0 +OpDecorate %g_sSamp DescriptorSet 0 +OpDecorate %g_sSamp Binding 0 +OpMemberDecorate %cbuff 0 Offset 0 +OpMemberDecorate %cbuff 1 Offset 4 +OpDecorate %cbuff Block +OpDecorate %_ DescriptorSet 0 +OpDecorate %_ Binding 1 +OpDecorate %i_Tex0 Location 0 +OpDecorate %i_Tex1 Location 1 +OpDecorate %_entryPointOutput_Color Location 0 +OpDecorate %100 RelaxedPrecision +OpDecorate %76 RelaxedPrecision +OpDecorate %79 RelaxedPrecision +OpDecorate %98 RelaxedPrecision +OpDecorate %101 RelaxedPrecision +OpDecorate %110 RelaxedPrecision +OpDecorate %102 RelaxedPrecision +OpDecorate %112 RelaxedPrecision +OpDecorate %104 RelaxedPrecision +OpDecorate %113 RelaxedPrecision +OpDecorate %114 RelaxedPrecision +OpDecorate %116 RelaxedPrecision +OpDecorate %119 RelaxedPrecision +OpDecorate %121 RelaxedPrecision +%void = OpTypeVoid +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 +%16 = OpTypeImage %float 1D 1 0 0 1 Unknown +%_ptr_UniformConstant_16 = OpTypePointer UniformConstant %16 +%g_tTex1df4 = OpVariable %_ptr_UniformConstant_16 UniformConstant +%20 = OpTypeSampler +%_ptr_UniformConstant_20 = OpTypePointer UniformConstant %20 +%g_sSamp = OpVariable %_ptr_UniformConstant_20 UniformConstant +%24 = OpTypeSampledImage %16 +%int = OpTypeInt 32 1 +%int_0 = OpConstant %int 0 +%float_0_100000001 = OpConstant %float 0.100000001 +%cbuff = OpTypeStruct %float %float +%_ptr_Uniform_cbuff = OpTypePointer Uniform %cbuff +%_ = OpVariable %_ptr_Uniform_cbuff Uniform +%_ptr_Uniform_float = OpTypePointer Uniform %float +%v2float = OpTypeVector %float 2 +%int_1 = OpConstant %int 1 +%float_0_200000003 = OpConstant %float 0.200000003 +%_ptr_Input_float = OpTypePointer Input %float +%i_Tex0 = OpVariable %_ptr_Input_float Input +%i_Tex1 = OpVariable %_ptr_Input_float Input +%_ptr_Output_float = OpTypePointer Output %float +%_entryPointOutput_Color = OpVariable %_ptr_Output_float Output +%float_0_5 = OpConstant %float 0.5 +)"; + + const std::string defs_after = + R"(OpCapability Shader +OpCapability Sampled1D +OpCapability Float16 +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %i_Tex0 %i_Tex1 %_entryPointOutput_Color +OpExecutionMode %main OriginUpperLeft +OpSource HLSL 500 +OpName %main "main" +OpName %g_tTex1df4 "g_tTex1df4" +OpName %g_sSamp "g_sSamp" +OpName %cbuff "cbuff" +OpMemberName %cbuff 0 "c1" +OpMemberName %cbuff 1 "c2" +OpName %_ "" +OpName %i_Tex0 "i.Tex0" +OpName %i_Tex1 "i.Tex1" +OpName %_entryPointOutput_Color "@entryPointOutput.Color" +OpDecorate %g_tTex1df4 DescriptorSet 0 +OpDecorate %g_tTex1df4 Binding 0 +OpDecorate %g_sSamp DescriptorSet 0 +OpDecorate %g_sSamp Binding 0 +OpMemberDecorate %cbuff 0 Offset 0 +OpMemberDecorate %cbuff 1 Offset 4 +OpDecorate %cbuff Block +OpDecorate %_ DescriptorSet 0 +OpDecorate %_ Binding 1 +OpDecorate %i_Tex0 Location 0 +OpDecorate %i_Tex1 Location 1 +OpDecorate %_entryPointOutput_Color Location 0 +%void = OpTypeVoid +%25 = OpTypeFunction %void +%float = OpTypeFloat 32 +%27 = OpTypeImage %float 1D 1 0 0 1 Unknown +%_ptr_UniformConstant_27 = OpTypePointer UniformConstant %27 +%g_tTex1df4 = OpVariable %_ptr_UniformConstant_27 UniformConstant +%29 = OpTypeSampler +%_ptr_UniformConstant_29 = OpTypePointer UniformConstant %29 +%g_sSamp = OpVariable %_ptr_UniformConstant_29 UniformConstant +%31 = OpTypeSampledImage %27 +%int = OpTypeInt 32 1 +%int_0 = OpConstant %int 0 +%float_0_100000001 = OpConstant %float 0.100000001 +%cbuff = OpTypeStruct %float %float +%_ptr_Uniform_cbuff = OpTypePointer Uniform %cbuff +%_ = OpVariable %_ptr_Uniform_cbuff Uniform +%_ptr_Uniform_float = OpTypePointer Uniform %float +%v2float = OpTypeVector %float 2 +%int_1 = OpConstant %int 1 +%float_0_200000003 = OpConstant %float 0.200000003 +%_ptr_Input_float = OpTypePointer Input %float +%i_Tex0 = OpVariable %_ptr_Input_float Input +%i_Tex1 = OpVariable %_ptr_Input_float Input +%_ptr_Output_float = OpTypePointer Output %float +%_entryPointOutput_Color = OpVariable %_ptr_Output_float Output +%float_0_5 = OpConstant %float 0.5 +%half = OpTypeFloat 16 +%v2half = OpTypeVector %half 2 +)"; + + const std::string func_before = + R"(%main = OpFunction %void None %3 +%5 = OpLabel +%76 = OpLoad %float %i_Tex0 +%79 = OpLoad %float %i_Tex1 +%93 = OpLoad %16 %g_tTex1df4 +%94 = OpLoad %20 %g_sSamp +%95 = OpSampledImage %24 %93 %94 +%98 = OpFMul %float %76 %float_0_100000001 +%99 = OpAccessChain %_ptr_Uniform_float %_ %int_0 +%100 = OpLoad %float %99 +%101 = OpFAdd %float %100 %float_0_100000001 +%102 = OpCompositeConstruct %v2float %98 %101 +%104 = OpImageSampleDrefImplicitLod %float %95 %102 %101 +%105 = OpLoad %16 %g_tTex1df4 +%106 = OpLoad %20 %g_sSamp +%107 = OpSampledImage %24 %105 %106 +%110 = OpFMul %float %79 %float_0_200000003 +%111 = OpAccessChain %_ptr_Uniform_float %_ %int_1 +%112 = OpLoad %float %111 +%113 = OpFAdd %float %112 %float_0_200000003 +%114 = OpCompositeConstruct %v2float %110 %113 +%116 = OpImageSampleDrefImplicitLod %float %107 %114 %113 +%119 = OpFAdd %float %104 %116 +%121 = OpFMul %float %119 %float_0_5 +OpStore %_entryPointOutput_Color %121 +OpReturn +OpFunctionEnd +)"; + + const std::string func_after = + R"(%main = OpFunction %void None %25 +%43 = OpLabel +%11 = OpLoad %float %i_Tex0 +%12 = OpLoad %float %i_Tex1 +%44 = OpLoad %27 %g_tTex1df4 +%45 = OpLoad %29 %g_sSamp +%46 = OpSampledImage %31 %44 %45 +%53 = OpFConvert %half %11 +%54 = OpFConvert %half %float_0_100000001 +%13 = OpFMul %half %53 %54 +%47 = OpAccessChain %_ptr_Uniform_float %_ %int_0 +%10 = OpLoad %float %47 +%55 = OpFConvert %half %10 +%56 = OpFConvert %half %float_0_100000001 +%14 = OpFAdd %half %55 %56 +%16 = OpCompositeConstruct %v2half %13 %14 +%58 = OpFConvert %float %14 +%18 = OpImageSampleDrefImplicitLod %float %46 %16 %58 +%48 = OpLoad %27 %g_tTex1df4 +%49 = OpLoad %29 %g_sSamp +%50 = OpSampledImage %31 %48 %49 +%59 = OpFConvert %half %12 +%60 = OpFConvert %half %float_0_200000003 +%15 = OpFMul %half %59 %60 +%51 = OpAccessChain %_ptr_Uniform_float %_ %int_1 +%17 = OpLoad %float %51 +%61 = OpFConvert %half %17 +%62 = OpFConvert %half %float_0_200000003 +%19 = OpFAdd %half %61 %62 +%20 = OpCompositeConstruct %v2half %15 %19 +%63 = OpFConvert %float %19 +%21 = OpImageSampleDrefImplicitLod %float %50 %20 %63 +%64 = OpFConvert %half %18 +%65 = OpFConvert %half %21 +%22 = OpFAdd %half %64 %65 +%66 = OpFConvert %half %float_0_5 +%23 = OpFMul %half %22 %66 +%67 = OpFConvert %float %23 +OpStore %_entryPointOutput_Color %67 +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndCheck(defs_before + func_before, + defs_after + func_after, true, true); +} + +TEST_F(ConvertToHalfTest, ConvertToHalfWithVectorMatrixMult) { + // The resulting SPIR-V was processed with --relax-float-ops. + // + // clang-format off + // + // SamplerState g_sSamp : register(s0); + // uniform Texture1D g_tTex1df4 : register(t0); + // + // struct PS_OUTPUT + // { + // float4 Color : SV_Target0; + // }; + // + // cbuffer cbuff{ + // float4x4 M; + // } + // + // PS_OUTPUT main() + // { + // PS_OUTPUT psout; + // float4 txval10 = g_tTex1df4.Sample(g_sSamp, 0.1); + // float4 t = mul(txval10, M); + // psout.Color = t; + // return psout; + //} + // + // clang-format on + + const std::string defs_before = + R"(OpCapability Shader +OpCapability Sampled1D +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %_entryPointOutput_Color +OpExecutionMode %main OriginUpperLeft +OpSource HLSL 500 +OpName %main "main" +OpName %g_tTex1df4 "g_tTex1df4" +OpName %g_sSamp "g_sSamp" +OpName %cbuff "cbuff" +OpMemberName %cbuff 0 "M" +OpName %_ "" +OpName %_entryPointOutput_Color "@entryPointOutput.Color" +OpDecorate %g_tTex1df4 DescriptorSet 0 +OpDecorate %g_tTex1df4 Binding 0 +OpDecorate %g_sSamp DescriptorSet 0 +OpDecorate %g_sSamp Binding 0 +OpMemberDecorate %cbuff 0 RowMajor +OpMemberDecorate %cbuff 0 Offset 0 +OpMemberDecorate %cbuff 0 MatrixStride 16 +OpDecorate %cbuff Block +OpDecorate %_ DescriptorSet 0 +OpDecorate %_ Binding 1 +OpDecorate %_entryPointOutput_Color Location 0 +OpDecorate %56 RelaxedPrecision +OpDecorate %58 RelaxedPrecision +OpDecorate %60 RelaxedPrecision +%void = OpTypeVoid +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v4float = OpTypeVector %float 4 +%14 = OpTypeImage %float 1D 0 0 0 1 Unknown +%_ptr_UniformConstant_14 = OpTypePointer UniformConstant %14 +%g_tTex1df4 = OpVariable %_ptr_UniformConstant_14 UniformConstant +%18 = OpTypeSampler +%_ptr_UniformConstant_18 = OpTypePointer UniformConstant %18 +%g_sSamp = OpVariable %_ptr_UniformConstant_18 UniformConstant +%22 = OpTypeSampledImage %14 +%float_0_100000001 = OpConstant %float 0.100000001 +%mat4v4float = OpTypeMatrix %v4float 4 +%cbuff = OpTypeStruct %mat4v4float +%_ptr_Uniform_cbuff = OpTypePointer Uniform %cbuff +%_ = OpVariable %_ptr_Uniform_cbuff Uniform +%int = OpTypeInt 32 1 +%int_0 = OpConstant %int 0 +%_ptr_Uniform_mat4v4float = OpTypePointer Uniform %mat4v4float +%_ptr_Output_v4float = OpTypePointer Output %v4float +%_entryPointOutput_Color = OpVariable %_ptr_Output_v4float Output +)"; + + const std::string defs_after = + R"(OpCapability Shader +OpCapability Sampled1D +OpCapability Float16 +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %_entryPointOutput_Color +OpExecutionMode %main OriginUpperLeft +OpSource HLSL 500 +OpName %main "main" +OpName %g_tTex1df4 "g_tTex1df4" +OpName %g_sSamp "g_sSamp" +OpName %cbuff "cbuff" +OpMemberName %cbuff 0 "M" +OpName %_ "" +OpName %_entryPointOutput_Color "@entryPointOutput.Color" +OpDecorate %g_tTex1df4 DescriptorSet 0 +OpDecorate %g_tTex1df4 Binding 0 +OpDecorate %g_sSamp DescriptorSet 0 +OpDecorate %g_sSamp Binding 0 +OpMemberDecorate %cbuff 0 RowMajor +OpMemberDecorate %cbuff 0 Offset 0 +OpMemberDecorate %cbuff 0 MatrixStride 16 +OpDecorate %cbuff Block +OpDecorate %_ DescriptorSet 0 +OpDecorate %_ Binding 1 +OpDecorate %_entryPointOutput_Color Location 0 +%void = OpTypeVoid +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v4float = OpTypeVector %float 4 +%14 = OpTypeImage %float 1D 0 0 0 1 Unknown +%_ptr_UniformConstant_14 = OpTypePointer UniformConstant %14 +%g_tTex1df4 = OpVariable %_ptr_UniformConstant_14 UniformConstant +%18 = OpTypeSampler +%_ptr_UniformConstant_18 = OpTypePointer UniformConstant %18 +%g_sSamp = OpVariable %_ptr_UniformConstant_18 UniformConstant +%22 = OpTypeSampledImage %14 +%float_0_100000001 = OpConstant %float 0.100000001 +%mat4v4float = OpTypeMatrix %v4float 4 +%cbuff = OpTypeStruct %mat4v4float +%_ptr_Uniform_cbuff = OpTypePointer Uniform %cbuff +%_ = OpVariable %_ptr_Uniform_cbuff Uniform +%int = OpTypeInt 32 1 +%int_0 = OpConstant %int 0 +%_ptr_Uniform_mat4v4float = OpTypePointer Uniform %mat4v4float +%_ptr_Output_v4float = OpTypePointer Output %v4float +%_entryPointOutput_Color = OpVariable %_ptr_Output_v4float Output +%half = OpTypeFloat 16 +%v4half = OpTypeVector %half 4 +%mat4v4half = OpTypeMatrix %v4half 4 +)"; + + const std::string func_before = + R"(%main = OpFunction %void None %3 +%5 = OpLabel +%53 = OpLoad %14 %g_tTex1df4 +%54 = OpLoad %18 %g_sSamp +%55 = OpSampledImage %22 %53 %54 +%56 = OpImageSampleImplicitLod %v4float %55 %float_0_100000001 +%57 = OpAccessChain %_ptr_Uniform_mat4v4float %_ %int_0 +%58 = OpLoad %mat4v4float %57 +%60 = OpMatrixTimesVector %v4float %58 %56 +OpStore %_entryPointOutput_Color %60 +OpReturn +OpFunctionEnd +)"; + + const std::string func_after = + R"(%main = OpFunction %void None %3 +%5 = OpLabel +%53 = OpLoad %14 %g_tTex1df4 +%54 = OpLoad %18 %g_sSamp +%55 = OpSampledImage %22 %53 %54 +%56 = OpImageSampleImplicitLod %v4float %55 %float_0_100000001 +%57 = OpAccessChain %_ptr_Uniform_mat4v4float %_ %int_0 +%58 = OpLoad %mat4v4float %57 +%67 = OpCompositeExtract %v4float %58 0 +%68 = OpFConvert %v4half %67 +%69 = OpCompositeExtract %v4float %58 1 +%70 = OpFConvert %v4half %69 +%71 = OpCompositeExtract %v4float %58 2 +%72 = OpFConvert %v4half %71 +%73 = OpCompositeExtract %v4float %58 3 +%74 = OpFConvert %v4half %73 +%75 = OpCompositeConstruct %mat4v4half %68 %70 %72 %74 +%64 = OpCopyObject %mat4v4float %58 +%65 = OpFConvert %v4half %56 +%60 = OpMatrixTimesVector %v4half %75 %65 +%66 = OpFConvert %v4float %60 +OpStore %_entryPointOutput_Color %66 +OpReturn +OpFunctionEnd +)"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck(defs_before + func_before, + defs_after + func_after, true, true); +} + +TEST_F(ConvertToHalfTest, ConvertToHalfWithPhi) { + // The resulting SPIR-V was processed with --relax-float-ops. + // + // clang-format off + // + // SamplerState g_sSamp : register(s0); + // uniform Texture1D g_tTex1df4 : register(t0); + // + // struct PS_OUTPUT + // { + // float4 Color : SV_Target0; + // }; + // + // cbuffer cbuff{ + // bool b; + // float4x4 M; + // } + // + // PS_OUTPUT main() + // { + // PS_OUTPUT psout; + // float4 t; + // + // if (b) + // t = g_tTex1df4.Sample(g_sSamp, 0.1); + // else + // t = float4(0.0, 0.0, 0.0, 0.0); + // + // float4 t2 = t * 2.0; + // psout.Color = t2; + // return psout; + // } + // + // clang-format on + + const std::string defs_before = + R"(OpCapability Shader +OpCapability Sampled1D +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %_entryPointOutput_Color +OpExecutionMode %main OriginUpperLeft +OpSource HLSL 500 +OpName %main "main" +OpName %cbuff "cbuff" +OpMemberName %cbuff 0 "b" +OpMemberName %cbuff 1 "M" +OpName %_ "" +OpName %g_tTex1df4 "g_tTex1df4" +OpName %g_sSamp "g_sSamp" +OpName %_entryPointOutput_Color "@entryPointOutput.Color" +OpMemberDecorate %cbuff 0 Offset 0 +OpMemberDecorate %cbuff 1 RowMajor +OpMemberDecorate %cbuff 1 Offset 16 +OpMemberDecorate %cbuff 1 MatrixStride 16 +OpDecorate %cbuff Block +OpDecorate %_ DescriptorSet 0 +OpDecorate %_ Binding 1 +OpDecorate %g_tTex1df4 DescriptorSet 0 +OpDecorate %g_tTex1df4 Binding 0 +OpDecorate %g_sSamp DescriptorSet 0 +OpDecorate %g_sSamp Binding 0 +OpDecorate %_entryPointOutput_Color Location 0 +OpDecorate %72 RelaxedPrecision +OpDecorate %85 RelaxedPrecision +OpDecorate %74 RelaxedPrecision +%void = OpTypeVoid +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v4float = OpTypeVector %float 4 +%uint = OpTypeInt 32 0 +%mat4v4float = OpTypeMatrix %v4float 4 +%cbuff = OpTypeStruct %uint %mat4v4float +%_ptr_Uniform_cbuff = OpTypePointer Uniform %cbuff +%_ = OpVariable %_ptr_Uniform_cbuff Uniform +%int = OpTypeInt 32 1 +%int_0 = OpConstant %int 0 +%_ptr_Uniform_uint = OpTypePointer Uniform %uint +%bool = OpTypeBool +%uint_0 = OpConstant %uint 0 +%29 = OpTypeImage %float 1D 0 0 0 1 Unknown +%_ptr_UniformConstant_29 = OpTypePointer UniformConstant %29 +%g_tTex1df4 = OpVariable %_ptr_UniformConstant_29 UniformConstant +%33 = OpTypeSampler +%_ptr_UniformConstant_33 = OpTypePointer UniformConstant %33 +%g_sSamp = OpVariable %_ptr_UniformConstant_33 UniformConstant +%37 = OpTypeSampledImage %29 +%float_0_100000001 = OpConstant %float 0.100000001 +%float_0 = OpConstant %float 0 +%43 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0 +%float_2 = OpConstant %float 2 +%_ptr_Output_v4float = OpTypePointer Output %v4float +%_entryPointOutput_Color = OpVariable %_ptr_Output_v4float Output +)"; + + const std::string defs_after = + R"(OpCapability Shader +OpCapability Sampled1D +OpCapability Float16 +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %_entryPointOutput_Color +OpExecutionMode %main OriginUpperLeft +OpSource HLSL 500 +OpName %main "main" +OpName %cbuff "cbuff" +OpMemberName %cbuff 0 "b" +OpMemberName %cbuff 1 "M" +OpName %_ "" +OpName %g_tTex1df4 "g_tTex1df4" +OpName %g_sSamp "g_sSamp" +OpName %_entryPointOutput_Color "@entryPointOutput.Color" +OpMemberDecorate %cbuff 0 Offset 0 +OpMemberDecorate %cbuff 1 RowMajor +OpMemberDecorate %cbuff 1 Offset 16 +OpMemberDecorate %cbuff 1 MatrixStride 16 +OpDecorate %cbuff Block +OpDecorate %_ DescriptorSet 0 +OpDecorate %_ Binding 1 +OpDecorate %g_tTex1df4 DescriptorSet 0 +OpDecorate %g_tTex1df4 Binding 0 +OpDecorate %g_sSamp DescriptorSet 0 +OpDecorate %g_sSamp Binding 0 +OpDecorate %_entryPointOutput_Color Location 0 +%void = OpTypeVoid +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v4float = OpTypeVector %float 4 +%uint = OpTypeInt 32 0 +%mat4v4float = OpTypeMatrix %v4float 4 +%cbuff = OpTypeStruct %uint %mat4v4float +%_ptr_Uniform_cbuff = OpTypePointer Uniform %cbuff +%_ = OpVariable %_ptr_Uniform_cbuff Uniform +%int = OpTypeInt 32 1 +%int_0 = OpConstant %int 0 +%_ptr_Uniform_uint = OpTypePointer Uniform %uint +%bool = OpTypeBool +%uint_0 = OpConstant %uint 0 +%29 = OpTypeImage %float 1D 0 0 0 1 Unknown +%_ptr_UniformConstant_29 = OpTypePointer UniformConstant %29 +%g_tTex1df4 = OpVariable %_ptr_UniformConstant_29 UniformConstant +%33 = OpTypeSampler +%_ptr_UniformConstant_33 = OpTypePointer UniformConstant %33 +%g_sSamp = OpVariable %_ptr_UniformConstant_33 UniformConstant +%37 = OpTypeSampledImage %29 +%float_0_100000001 = OpConstant %float 0.100000001 +%float_0 = OpConstant %float 0 +%43 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0 +%float_2 = OpConstant %float 2 +%_ptr_Output_v4float = OpTypePointer Output %v4float +%_entryPointOutput_Color = OpVariable %_ptr_Output_v4float Output +%half = OpTypeFloat 16 +%v4half = OpTypeVector %half 4 +)"; + + const std::string func_before = + R"(%main = OpFunction %void None %3 +%5 = OpLabel +%63 = OpAccessChain %_ptr_Uniform_uint %_ %int_0 +%64 = OpLoad %uint %63 +%65 = OpINotEqual %bool %64 %uint_0 +OpSelectionMerge %66 None +OpBranchConditional %65 %67 %68 +%67 = OpLabel +%69 = OpLoad %29 %g_tTex1df4 +%70 = OpLoad %33 %g_sSamp +%71 = OpSampledImage %37 %69 %70 +%72 = OpImageSampleImplicitLod %v4float %71 %float_0_100000001 +OpBranch %66 +%68 = OpLabel +OpBranch %66 +%66 = OpLabel +%85 = OpPhi %v4float %72 %67 %43 %68 +%74 = OpVectorTimesScalar %v4float %85 %float_2 +OpStore %_entryPointOutput_Color %74 +OpReturn +OpFunctionEnd +)"; + + const std::string func_after = + R"(%main = OpFunction %void None %3 +%5 = OpLabel +%63 = OpAccessChain %_ptr_Uniform_uint %_ %int_0 +%64 = OpLoad %uint %63 +%65 = OpINotEqual %bool %64 %uint_0 +OpSelectionMerge %66 None +OpBranchConditional %65 %67 %68 +%67 = OpLabel +%69 = OpLoad %29 %g_tTex1df4 +%70 = OpLoad %33 %g_sSamp +%71 = OpSampledImage %37 %69 %70 +%72 = OpImageSampleImplicitLod %v4float %71 %float_0_100000001 +%88 = OpFConvert %v4half %72 +OpBranch %66 +%68 = OpLabel +%89 = OpFConvert %v4half %43 +OpBranch %66 +%66 = OpLabel +%85 = OpPhi %v4half %88 %67 %89 %68 +%90 = OpFConvert %half %float_2 +%74 = OpVectorTimesScalar %v4half %85 %90 +%91 = OpFConvert %v4float %74 +OpStore %_entryPointOutput_Color %91 +OpReturn +OpFunctionEnd +)"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck(defs_before + func_before, + defs_after + func_after, true, true); +} + +TEST_F(ConvertToHalfTest, ConvertToHalfWithLoopAndFConvert) { + // The resulting SPIR-V was processed with --relax-float-ops. + // + // The loop causes an FConvert to be generated at the bottom of the loop + // for the Phi. The FConvert is later processed and turned into a (dead) + // copy. + // + // clang-format off + // + // struct PS_OUTPUT + // { + // float4 Color : SV_Target0; + // }; + // + // cbuffer cbuff{ + // float4 a[10]; + // } + // + // PS_OUTPUT main() + // { + // PS_OUTPUT psout; + // float4 t = 0.0;; + // + // for (int i = 0; i<10; ++i) + // t = t + a[i]; + // + // float4 t2 = t / 10.0; + // psout.Color = t2; + // return psout; + // } + // + // clang-format on + + const std::string defs_before = + R"(OpCapability Shader +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %_entryPointOutput_Color +OpExecutionMode %main OriginUpperLeft +OpSource HLSL 500 +OpName %main "main" +OpName %cbuff "cbuff" +OpMemberName %cbuff 0 "a" +OpName %_ "" +OpName %_entryPointOutput_Color "@entryPointOutput.Color" +OpDecorate %_arr_v4float_uint_10 ArrayStride 16 +OpMemberDecorate %cbuff 0 Offset 0 +OpDecorate %cbuff Block +OpDecorate %_ DescriptorSet 0 +OpDecorate %_ Binding 0 +OpDecorate %_entryPointOutput_Color Location 0 +OpDecorate %96 RelaxedPrecision +OpDecorate %81 RelaxedPrecision +OpDecorate %75 RelaxedPrecision +OpDecorate %76 RelaxedPrecision +%void = OpTypeVoid +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v4float = OpTypeVector %float 4 +%float_0 = OpConstant %float 0 +%15 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0 +%int = OpTypeInt 32 1 +%int_0 = OpConstant %int 0 +%int_10 = OpConstant %int 10 +%bool = OpTypeBool +%uint = OpTypeInt 32 0 +%uint_10 = OpConstant %uint 10 +%_arr_v4float_uint_10 = OpTypeArray %v4float %uint_10 +%cbuff = OpTypeStruct %_arr_v4float_uint_10 +%_ptr_Uniform_cbuff = OpTypePointer Uniform %cbuff +%_ = OpVariable %_ptr_Uniform_cbuff Uniform +%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float +%int_1 = OpConstant %int 1 +%_ptr_Output_v4float = OpTypePointer Output %v4float +%_entryPointOutput_Color = OpVariable %_ptr_Output_v4float Output +%float_0_100000001 = OpConstant %float 0.100000001 +%94 = OpConstantComposite %v4float %float_0_100000001 %float_0_100000001 %float_0_100000001 %float_0_100000001 +)"; + + const std::string defs_after = + R"(OpCapability Shader +OpCapability Float16 +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %_entryPointOutput_Color +OpExecutionMode %main OriginUpperLeft +OpSource HLSL 500 +OpName %main "main" +OpName %cbuff "cbuff" +OpMemberName %cbuff 0 "a" +OpName %_ "" +OpName %_entryPointOutput_Color "@entryPointOutput.Color" +OpDecorate %_arr_v4float_uint_10 ArrayStride 16 +OpMemberDecorate %cbuff 0 Offset 0 +OpDecorate %cbuff Block +OpDecorate %_ DescriptorSet 0 +OpDecorate %_ Binding 0 +OpDecorate %_entryPointOutput_Color Location 0 +%void = OpTypeVoid +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v4float = OpTypeVector %float 4 +%float_0 = OpConstant %float 0 +%15 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0 +%int = OpTypeInt 32 1 +%int_0 = OpConstant %int 0 +%int_10 = OpConstant %int 10 +%bool = OpTypeBool +%uint = OpTypeInt 32 0 +%uint_10 = OpConstant %uint 10 +%_arr_v4float_uint_10 = OpTypeArray %v4float %uint_10 +%cbuff = OpTypeStruct %_arr_v4float_uint_10 +%_ptr_Uniform_cbuff = OpTypePointer Uniform %cbuff +%_ = OpVariable %_ptr_Uniform_cbuff Uniform +%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float +%int_1 = OpConstant %int 1 +%_ptr_Output_v4float = OpTypePointer Output %v4float +%_entryPointOutput_Color = OpVariable %_ptr_Output_v4float Output +%float_0_100000001 = OpConstant %float 0.100000001 +%94 = OpConstantComposite %v4float %float_0_100000001 %float_0_100000001 %float_0_100000001 %float_0_100000001 +%half = OpTypeFloat 16 +%v4half = OpTypeVector %half 4 +)"; + + const std::string func_before = + R"(%main = OpFunction %void None %3 +%5 = OpLabel +OpBranch %65 +%65 = OpLabel +%96 = OpPhi %v4float %15 %5 %76 %71 +%95 = OpPhi %int %int_0 %5 %78 %71 +%70 = OpSLessThan %bool %95 %int_10 +OpLoopMerge %66 %71 None +OpBranchConditional %70 %71 %66 +%71 = OpLabel +%74 = OpAccessChain %_ptr_Uniform_v4float %_ %int_0 %95 +%75 = OpLoad %v4float %74 +%76 = OpFAdd %v4float %96 %75 +%78 = OpIAdd %int %95 %int_1 +OpBranch %65 +%66 = OpLabel +%81 = OpFMul %v4float %96 %94 +OpStore %_entryPointOutput_Color %81 +OpReturn +OpFunctionEnd +)"; + + const std::string func_after = + R"(%main = OpFunction %void None %3 +%5 = OpLabel +%99 = OpFConvert %v4half %15 +OpBranch %65 +%65 = OpLabel +%96 = OpPhi %v4half %99 %5 %100 %71 +%95 = OpPhi %int %int_0 %5 %78 %71 +%70 = OpSLessThan %bool %95 %int_10 +OpLoopMerge %66 %71 None +OpBranchConditional %70 %71 %66 +%71 = OpLabel +%74 = OpAccessChain %_ptr_Uniform_v4float %_ %int_0 %95 +%75 = OpLoad %v4float %74 +%103 = OpFConvert %v4half %75 +%76 = OpFAdd %v4half %96 %103 +%78 = OpIAdd %int %95 %int_1 +%100 = OpCopyObject %v4half %76 +OpBranch %65 +%66 = OpLabel +%101 = OpFConvert %v4half %94 +%81 = OpFMul %v4half %96 %101 +%102 = OpFConvert %v4float %81 +OpStore %_entryPointOutput_Color %102 +OpReturn +OpFunctionEnd +)"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck(defs_before + func_before, + defs_after + func_after, true, true); +} + +TEST_F(ConvertToHalfTest, ConvertToHalfWithExtracts) { + // The resulting SPIR-V was processed with --relax-float-ops. + // + // The extra converts in the func_after can be DCE'd. + // + // clang-format off + // + // SamplerState g_sSamp : register(s0); + // uniform Texture1D g_tTex1df4 : register(t0); + // + // struct PS_INPUT + // { + // float Tex0 : TEXCOORD0; + // }; + // + // struct PS_OUTPUT + // { + // float4 Color : SV_Target0; + // }; + // + // cbuffer cbuff{ + // float c; + // } + // + // PS_OUTPUT main(PS_INPUT i) + // { + // PS_OUTPUT psout; + // float4 tx = g_tTex1df4.Sample(g_sSamp, i.Tex0); + // float4 t = float4(tx.y, tx.z, tx.x, tx.w) * c; + // psout.Color = t; + // return psout; + // } + // + // clang-format on + + const std::string defs_before = + R"(OpCapability Shader +OpCapability Sampled1D +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %i_Tex0 %_entryPointOutput_Color +OpExecutionMode %main OriginUpperLeft +OpSource HLSL 500 +OpName %main "main" +OpName %g_tTex1df4 "g_tTex1df4" +OpName %g_sSamp "g_sSamp" +OpName %cbuff "cbuff" +OpMemberName %cbuff 0 "c" +OpName %_ "" +OpName %i_Tex0 "i.Tex0" +OpName %_entryPointOutput_Color "@entryPointOutput.Color" +OpDecorate %g_tTex1df4 DescriptorSet 0 +OpDecorate %g_tTex1df4 Binding 0 +OpDecorate %g_sSamp DescriptorSet 0 +OpDecorate %g_sSamp Binding 0 +OpMemberDecorate %cbuff 0 Offset 0 +OpDecorate %cbuff Block +OpDecorate %_ DescriptorSet 0 +OpDecorate %_ Binding 1 +OpDecorate %i_Tex0 Location 0 +OpDecorate %_entryPointOutput_Color Location 0 +OpDecorate %65 RelaxedPrecision +OpDecorate %82 RelaxedPrecision +OpDecorate %84 RelaxedPrecision +OpDecorate %86 RelaxedPrecision +OpDecorate %88 RelaxedPrecision +OpDecorate %90 RelaxedPrecision +OpDecorate %91 RelaxedPrecision +OpDecorate %93 RelaxedPrecision +OpDecorate %94 RelaxedPrecision +%void = OpTypeVoid +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v4float = OpTypeVector %float 4 +%17 = OpTypeImage %float 1D 0 0 0 1 Unknown +%_ptr_UniformConstant_17 = OpTypePointer UniformConstant %17 +%g_tTex1df4 = OpVariable %_ptr_UniformConstant_17 UniformConstant +%21 = OpTypeSampler +%_ptr_UniformConstant_21 = OpTypePointer UniformConstant %21 +%g_sSamp = OpVariable %_ptr_UniformConstant_21 UniformConstant +%25 = OpTypeSampledImage %17 +%int = OpTypeInt 32 1 +%int_0 = OpConstant %int 0 +%cbuff = OpTypeStruct %float +%_ptr_Uniform_cbuff = OpTypePointer Uniform %cbuff +%_ = OpVariable %_ptr_Uniform_cbuff Uniform +%_ptr_Uniform_float = OpTypePointer Uniform %float +%_ptr_Input_float = OpTypePointer Input %float +%i_Tex0 = OpVariable %_ptr_Input_float Input +%_ptr_Output_v4float = OpTypePointer Output %v4float +%_entryPointOutput_Color = OpVariable %_ptr_Output_v4float Output +)"; + + const std::string defs_after = + R"(OpCapability Shader +OpCapability Sampled1D +OpCapability Float16 +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %i_Tex0 %_entryPointOutput_Color +OpExecutionMode %main OriginUpperLeft +OpSource HLSL 500 +OpName %main "main" +OpName %g_tTex1df4 "g_tTex1df4" +OpName %g_sSamp "g_sSamp" +OpName %cbuff "cbuff" +OpMemberName %cbuff 0 "c" +OpName %_ "" +OpName %i_Tex0 "i.Tex0" +OpName %_entryPointOutput_Color "@entryPointOutput.Color" +OpDecorate %g_tTex1df4 DescriptorSet 0 +OpDecorate %g_tTex1df4 Binding 0 +OpDecorate %g_sSamp DescriptorSet 0 +OpDecorate %g_sSamp Binding 0 +OpMemberDecorate %cbuff 0 Offset 0 +OpDecorate %cbuff Block +OpDecorate %_ DescriptorSet 0 +OpDecorate %_ Binding 1 +OpDecorate %i_Tex0 Location 0 +OpDecorate %_entryPointOutput_Color Location 0 +%void = OpTypeVoid +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v4float = OpTypeVector %float 4 +%17 = OpTypeImage %float 1D 0 0 0 1 Unknown +%_ptr_UniformConstant_17 = OpTypePointer UniformConstant %17 +%g_tTex1df4 = OpVariable %_ptr_UniformConstant_17 UniformConstant +%21 = OpTypeSampler +%_ptr_UniformConstant_21 = OpTypePointer UniformConstant %21 +%g_sSamp = OpVariable %_ptr_UniformConstant_21 UniformConstant +%25 = OpTypeSampledImage %17 +%int = OpTypeInt 32 1 +%int_0 = OpConstant %int 0 +%cbuff = OpTypeStruct %float +%_ptr_Uniform_cbuff = OpTypePointer Uniform %cbuff +%_ = OpVariable %_ptr_Uniform_cbuff Uniform +%_ptr_Uniform_float = OpTypePointer Uniform %float +%_ptr_Input_float = OpTypePointer Input %float +%i_Tex0 = OpVariable %_ptr_Input_float Input +%_ptr_Output_v4float = OpTypePointer Output %v4float +%_entryPointOutput_Color = OpVariable %_ptr_Output_v4float Output +%half = OpTypeFloat 16 +%v4half = OpTypeVector %half 4 +)"; + + const std::string func_before = + R"(%main = OpFunction %void None %3 +%5 = OpLabel +%65 = OpLoad %float %i_Tex0 +%77 = OpLoad %17 %g_tTex1df4 +%78 = OpLoad %21 %g_sSamp +%79 = OpSampledImage %25 %77 %78 +%82 = OpImageSampleImplicitLod %v4float %79 %65 +%84 = OpCompositeExtract %float %82 1 +%86 = OpCompositeExtract %float %82 2 +%88 = OpCompositeExtract %float %82 0 +%90 = OpCompositeExtract %float %82 3 +%91 = OpCompositeConstruct %v4float %84 %86 %88 %90 +%92 = OpAccessChain %_ptr_Uniform_float %_ %int_0 +%93 = OpLoad %float %92 +%94 = OpVectorTimesScalar %v4float %91 %93 +OpStore %_entryPointOutput_Color %94 +OpReturn +OpFunctionEnd +)"; + + const std::string func_after = + R"(%main = OpFunction %void None %3 +%5 = OpLabel +%65 = OpLoad %float %i_Tex0 +%77 = OpLoad %17 %g_tTex1df4 +%78 = OpLoad %21 %g_sSamp +%79 = OpSampledImage %25 %77 %78 +%82 = OpImageSampleImplicitLod %v4float %79 %65 +%97 = OpFConvert %v4half %82 +%84 = OpCompositeExtract %half %97 1 +%98 = OpFConvert %v4half %82 +%86 = OpCompositeExtract %half %98 2 +%99 = OpFConvert %v4half %82 +%88 = OpCompositeExtract %half %99 0 +%100 = OpFConvert %v4half %82 +%90 = OpCompositeExtract %half %100 3 +%91 = OpCompositeConstruct %v4half %84 %86 %88 %90 +%92 = OpAccessChain %_ptr_Uniform_float %_ %int_0 +%93 = OpLoad %float %92 +%101 = OpFConvert %half %93 +%94 = OpVectorTimesScalar %v4half %91 %101 +%102 = OpFConvert %v4float %94 +OpStore %_entryPointOutput_Color %102 +OpReturn +OpFunctionEnd +)"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck(defs_before + func_before, + defs_after + func_after, true, true); +} + +TEST_F(ConvertToHalfTest, ConvertToHalfWithClosure) { + // Include as many contiguous composite instructions as possible into + // half-precision computations + // + // Compiled with glslang -V -Os + // + // clang-format off + // + // #version 410 core + // + // precision mediump float; + // + // layout(location = 1) in vec3 foo; + // layout(location = 2) in mat2 bar; + // layout(location = 1) out vec3 res; + // + // vec3 func(vec3 tap, mat2 M) { + // return vec3(M * tap.xy, 1.0); + // } + // + // void main() { + // res = func(foo, bar); + // } + // + // clang-format on + + const std::string defs = + R"(OpCapability Shader +; CHECK: OpCapability Float16 +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %res %foo %bar +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 410 +OpName %main "main" +OpName %res "res" +OpName %foo "foo" +OpName %bar "bar" +OpDecorate %res RelaxedPrecision +; CHECK-NOT: OpDecorate %res RelaxedPrecision +OpDecorate %res Location 1 +OpDecorate %foo RelaxedPrecision +; CHECK-NOT: OpDecorate %foo RelaxedPrecision +OpDecorate %foo Location 1 +OpDecorate %bar RelaxedPrecision +; CHECK-NOT: OpDecorate %bar RelaxedPrecision +OpDecorate %bar Location 2 +OpDecorate %34 RelaxedPrecision +OpDecorate %36 RelaxedPrecision +OpDecorate %41 RelaxedPrecision +OpDecorate %42 RelaxedPrecision +; CHECK-NOT: OpDecorate %34 RelaxedPrecision +; CHECK-NOT: OpDecorate %36 RelaxedPrecision +; CHECK-NOT: OpDecorate %41 RelaxedPrecision +; CHECK-NOT: OpDecorate %42 RelaxedPrecision +%void = OpTypeVoid +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v3float = OpTypeVector %float 3 +%v2float = OpTypeVector %float 2 +%mat2v2float = OpTypeMatrix %v2float 2 +%float_1 = OpConstant %float 1 +%_ptr_Output_v3float = OpTypePointer Output %v3float +%res = OpVariable %_ptr_Output_v3float Output +%_ptr_Input_v3float = OpTypePointer Input %v3float +%foo = OpVariable %_ptr_Input_v3float Input +%_ptr_Input_mat2v2float = OpTypePointer Input %mat2v2float +%bar = OpVariable %_ptr_Input_mat2v2float Input +)"; + + const std::string func = + R"(%main = OpFunction %void None %3 +%5 = OpLabel +%34 = OpLoad %v3float %foo +%36 = OpLoad %mat2v2float %bar +; CHECK: %48 = OpFConvert %v3half %34 +; CHECK: %49 = OpFConvert %v3half %34 +%41 = OpVectorShuffle %v2float %34 %34 0 1 +; CHECK-NOT: %41 = OpVectorShuffle %v2float %34 %34 0 1 +; CHECK: %41 = OpVectorShuffle %v2half %48 %49 0 1 +%42 = OpMatrixTimesVector %v2float %36 %41 +; CHECK-NOT: %42 = OpMatrixTimesVector %v2float %36 %41 +; CHECK: %55 = OpCompositeExtract %v2float %36 0 +; CHECK: %56 = OpFConvert %v2half %55 +; CHECK: %57 = OpCompositeExtract %v2float %36 1 +; CHECK: %58 = OpFConvert %v2half %57 +; CHECK: %59 = OpCompositeConstruct %mat2v2half %56 %58 +; CHECK: %52 = OpCopyObject %mat2v2float %36 +; CHECK: %42 = OpMatrixTimesVector %v2half %59 %41 +%43 = OpCompositeExtract %float %42 0 +%44 = OpCompositeExtract %float %42 1 +; CHECK-NOT: %43 = OpCompositeExtract %float %42 0 +; CHECK-NOT: %44 = OpCompositeExtract %float %42 1 +; CHECK: %43 = OpCompositeExtract %half %42 0 +; CHECK: %44 = OpCompositeExtract %half %42 1 +%45 = OpCompositeConstruct %v3float %43 %44 %float_1 +; CHECK-NOT: %45 = OpCompositeConstruct %v3float %43 %44 %float_1 +; CHECK: %53 = OpFConvert %float %43 +; CHECK: %54 = OpFConvert %float %44 +; CHECK: %45 = OpCompositeConstruct %v3float %53 %54 %float_1 +OpStore %res %45 +OpReturn +OpFunctionEnd +)"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndMatch(defs + func, true); +} + +} // namespace +} // namespace opt +} // namespace spvtools diff --git a/third_party/spirv-tools/test/opt/copy_prop_array_test.cpp b/third_party/spirv-tools/test/opt/copy_prop_array_test.cpp index dcce77d224..1afee9cf91 100644 --- a/third_party/spirv-tools/test/opt/copy_prop_array_test.cpp +++ b/third_party/spirv-tools/test/opt/copy_prop_array_test.cpp @@ -25,7 +25,6 @@ namespace { using CopyPropArrayPassTest = PassTest<::testing::Test>; -#ifdef SPIRV_EFFCEE TEST_F(CopyPropArrayPassTest, BasicPropagateArray) { const std::string before = R"( @@ -431,7 +430,7 @@ TEST_F(CopyPropArrayPassTest, DecomposeObjectForArrayStore) { ; CHECK: [[extract1:%\w+]] = OpCompositeExtract %v4float [[load]] 0 ; CHECK: [[extract2:%\w+]] = OpCompositeExtract %v4float [[load]] 1 ; CHECK: [[construct:%\w+]] = OpCompositeConstruct %_arr_v4float_uint_2_0 [[extract1]] [[extract2]] -; CHEKC: OpStore %26 [[construct]] +; CHECK: OpStore %26 [[construct]] OpStore %26 %41 %42 = OpAccessChain %_ptr_Function_v4float %26 %28 %43 = OpLoad %v4float %42 @@ -519,7 +518,7 @@ TEST_F(CopyPropArrayPassTest, DecomposeObjectForStructStore) { ; CHECK: [[extract1:%\w+]] = OpCompositeExtract %float [[load]] 0 ; CHECK: [[extract2:%\w+]] = OpCompositeExtract %uint [[load]] 1 ; CHECK: [[construct:%\w+]] = OpCompositeConstruct [[struct]] [[extract1]] [[extract2]] -; CHEKC: OpStore %26 [[construct]] +; CHECK: OpStore %26 [[construct]] OpStore %26 %41 %42 = OpAccessChain %_ptr_Function_v4float %26 %28 %43 = OpLoad %v4float %42 @@ -620,8 +619,314 @@ OpFunctionEnd SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES); SinglePassRunAndMatch(before, false); } -#endif // SPIRV_EFFCEE +TEST_F(CopyPropArrayPassTest, IsomorphicTypes1) { + const std::string before = + R"( +; CHECK: [[int:%\w+]] = OpTypeInt 32 0 +; CHECK: [[s1:%\w+]] = OpTypeStruct [[int]] +; CHECK: [[s2:%\w+]] = OpTypeStruct [[s1]] +; CHECK: [[a1:%\w+]] = OpTypeArray [[s2]] +; CHECK: [[s3:%\w+]] = OpTypeStruct [[a1]] +; CHECK: [[p_s3:%\w+]] = OpTypePointer Uniform [[s3]] +; CHECK: [[global_var:%\w+]] = OpVariable [[p_s3]] Uniform +; CHECK: [[p_a1:%\w+]] = OpTypePointer Uniform [[a1]] +; CHECK: [[p_s2:%\w+]] = OpTypePointer Uniform [[s2]] +; CHECK: [[ac1:%\w+]] = OpAccessChain [[p_a1]] [[global_var]] %uint_0 +; CHECK: [[ac2:%\w+]] = OpAccessChain [[p_s2]] [[ac1]] %uint_0 +; CHECK: [[ld:%\w+]] = OpLoad [[s2]] [[ac2]] +; CHECK: [[ex:%\w+]] = OpCompositeExtract [[s1]] [[ld]] + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "PS_main" + OpExecutionMode %2 OriginUpperLeft + OpSource HLSL 600 + OpDecorate %3 DescriptorSet 0 + OpDecorate %3 Binding 101 + %uint = OpTypeInt 32 0 + %uint_1 = OpConstant %uint 1 + %s1 = OpTypeStruct %uint + %s2 = OpTypeStruct %s1 +%a1 = OpTypeArray %s2 %uint_1 + %s3 = OpTypeStruct %a1 + %s1_1 = OpTypeStruct %uint +%_ptr_Uniform_uint = OpTypePointer Uniform %uint + %void = OpTypeVoid + %13 = OpTypeFunction %void + %uint_0 = OpConstant %uint 0 + %s1_0 = OpTypeStruct %uint + %s2_0 = OpTypeStruct %s1_0 +%a1_0 = OpTypeArray %s2_0 %uint_1 + %s3_0 = OpTypeStruct %a1_0 +%p_s3 = OpTypePointer Uniform %s3 +%p_s3_0 = OpTypePointer Function %s3_0 + %3 = OpVariable %p_s3 Uniform +%p_a1_0 = OpTypePointer Function %a1_0 +%p_s2_0 = OpTypePointer Function %s2_0 + %2 = OpFunction %void None %13 + %20 = OpLabel + %21 = OpVariable %p_a1_0 Function + %22 = OpLoad %s3 %3 + %23 = OpCompositeExtract %a1 %22 0 + %24 = OpCompositeExtract %s2 %23 0 + %25 = OpCompositeExtract %s1 %24 0 + %26 = OpCompositeExtract %uint %25 0 + %27 = OpCompositeConstruct %s1_0 %26 + %32 = OpCompositeConstruct %s2_0 %27 + %28 = OpCompositeConstruct %a1_0 %32 + OpStore %21 %28 + %29 = OpAccessChain %p_s2_0 %21 %uint_0 + %30 = OpLoad %s2 %29 + %31 = OpCompositeExtract %s1 %30 0 + OpReturn + OpFunctionEnd +)"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER | + SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES); + SinglePassRunAndMatch(before, false); +} + +TEST_F(CopyPropArrayPassTest, IsomorphicTypes2) { + const std::string before = + R"( +; CHECK: [[int:%\w+]] = OpTypeInt 32 0 +; CHECK: [[s1:%\w+]] = OpTypeStruct [[int]] +; CHECK: [[s2:%\w+]] = OpTypeStruct [[s1]] +; CHECK: [[a1:%\w+]] = OpTypeArray [[s2]] +; CHECK: [[s3:%\w+]] = OpTypeStruct [[a1]] +; CHECK: [[p_s3:%\w+]] = OpTypePointer Uniform [[s3]] +; CHECK: [[global_var:%\w+]] = OpVariable [[p_s3]] Uniform +; CHECK: [[p_s2:%\w+]] = OpTypePointer Uniform [[s2]] +; CHECK: [[p_s1:%\w+]] = OpTypePointer Uniform [[s1]] +; CHECK: [[ac1:%\w+]] = OpAccessChain [[p_s2]] [[global_var]] %uint_0 %uint_0 +; CHECK: [[ac2:%\w+]] = OpAccessChain [[p_s1]] [[ac1]] %uint_0 +; CHECK: [[ld:%\w+]] = OpLoad [[s1]] [[ac2]] +; CHECK: [[ex:%\w+]] = OpCompositeExtract [[int]] [[ld]] + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "PS_main" + OpExecutionMode %2 OriginUpperLeft + OpSource HLSL 600 + OpDecorate %3 DescriptorSet 0 + OpDecorate %3 Binding 101 + %uint = OpTypeInt 32 0 + %uint_1 = OpConstant %uint 1 + %_struct_6 = OpTypeStruct %uint + %_struct_7 = OpTypeStruct %_struct_6 +%_arr__struct_7_uint_1 = OpTypeArray %_struct_7 %uint_1 + %_struct_9 = OpTypeStruct %_arr__struct_7_uint_1 + %_struct_10 = OpTypeStruct %uint +%_ptr_Uniform_uint = OpTypePointer Uniform %uint + %void = OpTypeVoid + %13 = OpTypeFunction %void + %uint_0 = OpConstant %uint 0 + %_struct_15 = OpTypeStruct %uint +%_arr__struct_15_uint_1 = OpTypeArray %_struct_15 %uint_1 +%_ptr_Uniform__struct_9 = OpTypePointer Uniform %_struct_9 +%_ptr_Function__struct_15 = OpTypePointer Function %_struct_15 + %3 = OpVariable %_ptr_Uniform__struct_9 Uniform +%_ptr_Function__arr__struct_15_uint_1 = OpTypePointer Function %_arr__struct_15_uint_1 + %2 = OpFunction %void None %13 + %20 = OpLabel + %21 = OpVariable %_ptr_Function__arr__struct_15_uint_1 Function + %22 = OpLoad %_struct_9 %3 + %23 = OpCompositeExtract %_arr__struct_7_uint_1 %22 0 + %24 = OpCompositeExtract %_struct_7 %23 0 + %25 = OpCompositeExtract %_struct_6 %24 0 + %26 = OpCompositeExtract %uint %25 0 + %27 = OpCompositeConstruct %_struct_15 %26 + %28 = OpCompositeConstruct %_arr__struct_15_uint_1 %27 + OpStore %21 %28 + %29 = OpAccessChain %_ptr_Function__struct_15 %21 %uint_0 + %30 = OpLoad %_struct_15 %29 + %31 = OpCompositeExtract %uint %30 0 + OpReturn + OpFunctionEnd +)"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER | + SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES); + SinglePassRunAndMatch(before, false); +} + +TEST_F(CopyPropArrayPassTest, IsomorphicTypes3) { + const std::string before = + R"( +; CHECK: [[int:%\w+]] = OpTypeInt 32 0 +; CHECK: [[s1:%\w+]] = OpTypeStruct [[int]] +; CHECK: [[s2:%\w+]] = OpTypeStruct [[s1]] +; CHECK: [[a1:%\w+]] = OpTypeArray [[s2]] +; CHECK: [[s3:%\w+]] = OpTypeStruct [[a1]] +; CHECK: [[s1_1:%\w+]] = OpTypeStruct [[int]] +; CHECK: [[p_s3:%\w+]] = OpTypePointer Uniform [[s3]] +; CHECK: [[p_s1_1:%\w+]] = OpTypePointer Function [[s1_1]] +; CHECK: [[global_var:%\w+]] = OpVariable [[p_s3]] Uniform +; CHECK: [[p_s2:%\w+]] = OpTypePointer Uniform [[s2]] +; CHECK: [[p_s1:%\w+]] = OpTypePointer Uniform [[s1]] +; CHECK: [[var:%\w+]] = OpVariable [[p_s1_1]] Function +; CHECK: [[ac1:%\w+]] = OpAccessChain [[p_s2]] [[global_var]] %uint_0 %uint_0 +; CHECK: [[ac2:%\w+]] = OpAccessChain [[p_s1]] [[ac1]] %uint_0 +; CHECK: [[ld:%\w+]] = OpLoad [[s1]] [[ac2]] +; CHECK: [[ex:%\w+]] = OpCompositeExtract [[int]] [[ld]] +; CHECK: [[copy:%\w+]] = OpCompositeConstruct [[s1_1]] [[ex]] +; CHECK: OpStore [[var]] [[copy]] + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "PS_main" + OpExecutionMode %2 OriginUpperLeft + OpSource HLSL 600 + OpDecorate %3 DescriptorSet 0 + OpDecorate %3 Binding 101 + %uint = OpTypeInt 32 0 + %uint_1 = OpConstant %uint 1 + %_struct_6 = OpTypeStruct %uint + %_struct_7 = OpTypeStruct %_struct_6 +%_arr__struct_7_uint_1 = OpTypeArray %_struct_7 %uint_1 + %_struct_9 = OpTypeStruct %_arr__struct_7_uint_1 +%_ptr_Uniform_uint = OpTypePointer Uniform %uint + %void = OpTypeVoid + %13 = OpTypeFunction %void + %uint_0 = OpConstant %uint 0 + %_struct_15 = OpTypeStruct %uint + %_struct_10 = OpTypeStruct %uint +%_arr__struct_15_uint_1 = OpTypeArray %_struct_15 %uint_1 +%_ptr_Uniform__struct_9 = OpTypePointer Uniform %_struct_9 +%_ptr_Function__struct_15 = OpTypePointer Function %_struct_15 + %3 = OpVariable %_ptr_Uniform__struct_9 Uniform +%_ptr_Function__arr__struct_15_uint_1 = OpTypePointer Function %_arr__struct_15_uint_1 + %2 = OpFunction %void None %13 + %20 = OpLabel + %21 = OpVariable %_ptr_Function__arr__struct_15_uint_1 Function + %var = OpVariable %_ptr_Function__struct_15 Function + %22 = OpLoad %_struct_9 %3 + %23 = OpCompositeExtract %_arr__struct_7_uint_1 %22 0 + %24 = OpCompositeExtract %_struct_7 %23 0 + %25 = OpCompositeExtract %_struct_6 %24 0 + %26 = OpCompositeExtract %uint %25 0 + %27 = OpCompositeConstruct %_struct_15 %26 + %28 = OpCompositeConstruct %_arr__struct_15_uint_1 %27 + OpStore %21 %28 + %29 = OpAccessChain %_ptr_Function__struct_15 %21 %uint_0 + %30 = OpLoad %_struct_15 %29 + OpStore %var %30 + OpReturn + OpFunctionEnd +)"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER | + SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES); + SinglePassRunAndMatch(before, false); +} + +TEST_F(CopyPropArrayPassTest, BadMergingTwoObjects) { + // The second element in the |OpCompositeConstruct| is from a different + // object. + const std::string text = + R"(OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpName %type_ConstBuf "type.ConstBuf" +OpMemberName %type_ConstBuf 0 "TexSizeU" +OpMemberName %type_ConstBuf 1 "TexSizeV" +OpName %ConstBuf "ConstBuf" +OpName %main "main" +OpMemberDecorate %type_ConstBuf 0 Offset 0 +OpMemberDecorate %type_ConstBuf 1 Offset 8 +OpDecorate %type_ConstBuf Block +OpDecorate %ConstBuf DescriptorSet 0 +OpDecorate %ConstBuf Binding 2 +%float = OpTypeFloat 32 +%v2float = OpTypeVector %float 2 +%type_ConstBuf = OpTypeStruct %v2float %v2float +%_ptr_Uniform_type_ConstBuf = OpTypePointer Uniform %type_ConstBuf +%void = OpTypeVoid +%9 = OpTypeFunction %void +%uint = OpTypeInt 32 0 +%int_0 = OpConstant %uint 0 +%uint_2 = OpConstant %uint 2 +%_arr_v2float_uint_2 = OpTypeArray %v2float %uint_2 +%_ptr_Function__arr_v2float_uint_2 = OpTypePointer Function %_arr_v2float_uint_2 +%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float +%ConstBuf = OpVariable %_ptr_Uniform_type_ConstBuf Uniform +%main = OpFunction %void None %9 +%24 = OpLabel +%25 = OpVariable %_ptr_Function__arr_v2float_uint_2 Function +%27 = OpAccessChain %_ptr_Uniform_v2float %ConstBuf %int_0 +%28 = OpLoad %v2float %27 +%29 = OpAccessChain %_ptr_Uniform_v2float %ConstBuf %int_0 +%30 = OpLoad %v2float %29 +%31 = OpFNegate %v2float %30 +%37 = OpCompositeConstruct %_arr_v2float_uint_2 %28 %31 +OpStore %25 %37 +OpReturn +OpFunctionEnd +)"; + + auto result = SinglePassRunAndDisassemble( + text, /* skip_nop = */ true, /* do_validation = */ false); + EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)); +} + +TEST_F(CopyPropArrayPassTest, SecondElementNotContained) { + // The second element in the |OpCompositeConstruct| is not a memory object. + // Make sure no change happends. + const std::string text = + R"(OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpName %type_ConstBuf "type.ConstBuf" +OpMemberName %type_ConstBuf 0 "TexSizeU" +OpMemberName %type_ConstBuf 1 "TexSizeV" +OpName %ConstBuf "ConstBuf" +OpName %main "main" +OpMemberDecorate %type_ConstBuf 0 Offset 0 +OpMemberDecorate %type_ConstBuf 1 Offset 8 +OpDecorate %type_ConstBuf Block +OpDecorate %ConstBuf DescriptorSet 0 +OpDecorate %ConstBuf Binding 2 +OpDecorate %ConstBuf2 DescriptorSet 1 +OpDecorate %ConstBuf2 Binding 2 +%float = OpTypeFloat 32 +%v2float = OpTypeVector %float 2 +%type_ConstBuf = OpTypeStruct %v2float %v2float +%_ptr_Uniform_type_ConstBuf = OpTypePointer Uniform %type_ConstBuf +%void = OpTypeVoid +%9 = OpTypeFunction %void +%uint = OpTypeInt 32 0 +%int_0 = OpConstant %uint 0 +%int_1 = OpConstant %uint 1 +%uint_2 = OpConstant %uint 2 +%_arr_v2float_uint_2 = OpTypeArray %v2float %uint_2 +%_ptr_Function__arr_v2float_uint_2 = OpTypePointer Function %_arr_v2float_uint_2 +%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float +%ConstBuf = OpVariable %_ptr_Uniform_type_ConstBuf Uniform +%ConstBuf2 = OpVariable %_ptr_Uniform_type_ConstBuf Uniform +%main = OpFunction %void None %9 +%24 = OpLabel +%25 = OpVariable %_ptr_Function__arr_v2float_uint_2 Function +%27 = OpAccessChain %_ptr_Uniform_v2float %ConstBuf %int_0 +%28 = OpLoad %v2float %27 +%29 = OpAccessChain %_ptr_Uniform_v2float %ConstBuf2 %int_1 +%30 = OpLoad %v2float %29 +%37 = OpCompositeConstruct %_arr_v2float_uint_2 %28 %30 +OpStore %25 %37 +OpReturn +OpFunctionEnd +)"; + + auto result = SinglePassRunAndDisassemble( + text, /* skip_nop = */ true, /* do_validation = */ false); + EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)); +} // This test will place a load before the store. We cannot propagate in this // case. TEST_F(CopyPropArrayPassTest, LoadBeforeStore) { @@ -852,7 +1157,7 @@ OpDecorate %MyCBuffer Binding 0 OpStore %23 %35 %36 = OpAccessChain %_ptr_Function_v4float %23 %24 %37 = OpLoad %v4float %36 -%39 = OpStore %36 %v4const + OpStore %36 %v4const OpStore %out_var_SV_Target %37 OpReturn OpFunctionEnd @@ -1266,6 +1571,57 @@ OpFunctionEnd SinglePassRunAndCheck(before, after, true, true); } +TEST_F(CopyPropArrayPassTest, IndexIsNullConstnat) { + const std::string text = R"( +; CHECK: [[var:%\w+]] = OpVariable {{%\w+}} Uniform +; CHECK: [[null:%\w+]] = OpConstantNull %uint +; CHECK: [[ac1:%\w+]] = OpAccessChain %_ptr_Uniform__arr_uint_uint_1 [[var]] %uint_0 %uint_0 +; CHECK: OpAccessChain %_ptr_Uniform_uint [[ac1]] [[null]] +; CHECK-NEXT: OpReturn + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" + OpExecutionMode %main OriginUpperLeft + OpSource HLSL 600 + OpDecorate %myCBuffer DescriptorSet 0 + OpDecorate %myCBuffer Binding 0 + OpDecorate %_arr_v4float_uint_1 ArrayStride 16 + OpMemberDecorate %MyConstantBuffer 0 Offset 0 + OpMemberDecorate %type_myCBuffer 0 Offset 0 + OpDecorate %type_myCBuffer Block + %uint = OpTypeInt 32 0 + %int_0 = OpConstant %uint 0 + %uint_1 = OpConstant %uint 1 +%_arr_v4float_uint_1 = OpTypeArray %uint %uint_1 +%MyConstantBuffer = OpTypeStruct %_arr_v4float_uint_1 +%type_myCBuffer = OpTypeStruct %MyConstantBuffer +%_ptr_Uniform_type_myCBuffer = OpTypePointer Uniform %type_myCBuffer +%_arr_v4float_uint_1_0 = OpTypeArray %uint %uint_1 + %void = OpTypeVoid + %19 = OpTypeFunction %void +%_ptr_Function_v4float = OpTypePointer Function %uint +%_ptr_Uniform_MyConstantBuffer = OpTypePointer Uniform %MyConstantBuffer + %myCBuffer = OpVariable %_ptr_Uniform_type_myCBuffer Uniform +%_ptr_Function__arr_v4float_uint_1_0 = OpTypePointer Function %_arr_v4float_uint_1_0 + %23 = OpConstantNull %uint + %main = OpFunction %void None %19 + %24 = OpLabel + %25 = OpVariable %_ptr_Function__arr_v4float_uint_1_0 Function + %26 = OpAccessChain %_ptr_Uniform_MyConstantBuffer %myCBuffer %int_0 + %27 = OpLoad %MyConstantBuffer %26 + %28 = OpCompositeExtract %_arr_v4float_uint_1 %27 0 + %29 = OpCompositeExtract %uint %28 0 + %30 = OpCompositeConstruct %_arr_v4float_uint_1_0 %29 + OpStore %25 %30 + %31 = OpAccessChain %_ptr_Function_v4float %25 %23 + OpReturn + OpFunctionEnd +)"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndMatch(text, true); +} + } // namespace } // namespace opt } // namespace spvtools diff --git a/third_party/spirv-tools/test/opt/dead_branch_elim_test.cpp b/third_party/spirv-tools/test/opt/dead_branch_elim_test.cpp index 29084e3bb3..3dcc0f7701 100644 --- a/third_party/spirv-tools/test/opt/dead_branch_elim_test.cpp +++ b/third_party/spirv-tools/test/opt/dead_branch_elim_test.cpp @@ -1348,7 +1348,6 @@ OpFunctionEnd true, true); } -#ifdef SPIRV_EFFCEE TEST_F(DeadBranchElimTest, LeaveContinueBackedge) { const std::string text = R"( ; CHECK: OpLoopMerge [[merge:%\w+]] [[continue:%\w+]] None @@ -1379,6 +1378,7 @@ OpFunctionEnd SinglePassRunAndMatch(text, true); } + TEST_F(DeadBranchElimTest, LeaveContinueBackedgeExtraBlock) { const std::string text = R"( ; CHECK: OpBranch [[header:%\w+]] @@ -2018,6 +2018,7 @@ TEST_F(DeadBranchElimTest, ReorderBlocks) { OpCapability Shader OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft %void = OpTypeVoid %bool = OpTypeBool %true = OpConstantTrue %bool @@ -2045,6 +2046,7 @@ TEST_F(DeadBranchElimTest, ReorderBlocksMultiple) { OpCapability Shader OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft %void = OpTypeVoid %bool = OpTypeBool %true = OpConstantTrue %bool @@ -2073,6 +2075,7 @@ TEST_F(DeadBranchElimTest, ReorderBlocksMultiple2) { OpCapability Shader OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft %void = OpTypeVoid %bool = OpTypeBool %true = OpConstantTrue %bool @@ -2193,7 +2196,1038 @@ OpFunctionEnd SinglePassRunAndMatch(predefs + body, true); } -#endif + +TEST_F(DeadBranchElimTest, SelectionMergeWithConditionalExit) { + // Checks that if a selection merge construct contains a conditional branch + // to the merge node, then we keep the OpSelectionMerge on that branch. + const std::string predefs = R"( +OpCapability Shader +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 140 +%void = OpTypeVoid +%func_type = OpTypeFunction %void +%bool = OpTypeBool +%true = OpConstantTrue %bool +%uint = OpTypeInt 32 0 +%undef_int = OpUndef %uint +)"; + + const std::string body = + R"( +; CHECK: OpLoopMerge [[loop_merge:%\w+]] +; CHECK-NEXT: OpBranch [[bb1:%\w+]] +; CHECK: [[bb1]] = OpLabel +; CHECK-NEXT: OpBranch [[bb2:%\w+]] +; CHECK: [[bb2]] = OpLabel +; CHECK-NEXT: OpSelectionMerge [[sel_merge:%\w+]] None +; CHECK-NEXT: OpSwitch {{%\w+}} [[sel_merge]] 1 [[bb3:%\w+]] +; CHECK: [[bb3]] = OpLabel +; CHECK-NEXT: OpBranch [[sel_merge]] +; CHECK: [[sel_merge]] = OpLabel +; CHECK-NEXT: OpBranch [[loop_merge]] +; CHECK: [[loop_merge]] = OpLabel +; CHECK-NEXT: OpReturn +%main = OpFunction %void None %func_type +%entry_bb = OpLabel +OpBranch %loop_header +%loop_header = OpLabel +OpLoopMerge %loop_merge %cont None +OpBranch %bb1 +%bb1 = OpLabel +OpSelectionMerge %sel_merge None +OpBranchConditional %true %bb2 %bb4 +%bb2 = OpLabel +OpSwitch %undef_int %sel_merge 1 %bb3 +%bb3 = OpLabel +OpBranch %sel_merge +%bb4 = OpLabel +OpBranch %sel_merge +%sel_merge = OpLabel +OpBranch %loop_merge +%cont = OpLabel +OpBranch %loop_header +%loop_merge = OpLabel +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(predefs + body, true); +} + +TEST_F(DeadBranchElimTest, SelectionMergeWithExitToLoop) { + // Checks that if a selection merge construct contains a conditional branch + // to a loop surrounding the selection merge, then we do not keep the + // OpSelectionMerge instruction. + const std::string predefs = R"( +OpCapability Shader +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 140 +%void = OpTypeVoid +%func_type = OpTypeFunction %void +%bool = OpTypeBool +%true = OpConstantTrue %bool +%undef_bool = OpUndef %bool +)"; + + const std::string body = + R"( +; CHECK: OpLoopMerge [[loop_merge:%\w+]] +; CHECK-NEXT: OpBranch [[bb1:%\w+]] +; CHECK: [[bb1]] = OpLabel +; CHECK-NEXT: OpBranch [[bb2:%\w+]] +; CHECK: [[bb2]] = OpLabel +; CHECK-NEXT: OpBranchConditional {{%\w+}} [[bb3:%\w+]] [[loop_merge]] +; CHECK: [[bb3]] = OpLabel +; CHECK-NEXT: OpBranch [[sel_merge:%\w+]] +; CHECK: [[sel_merge]] = OpLabel +; CHECK-NEXT: OpBranch [[loop_merge]] +; CHECK: [[loop_merge]] = OpLabel +; CHECK-NEXT: OpReturn +%main = OpFunction %void None %func_type +%entry_bb = OpLabel +OpBranch %loop_header +%loop_header = OpLabel +OpLoopMerge %loop_merge %cont None +OpBranch %bb1 +%bb1 = OpLabel +OpSelectionMerge %sel_merge None +OpBranchConditional %true %bb2 %bb4 +%bb2 = OpLabel +OpBranchConditional %undef_bool %bb3 %loop_merge +%bb3 = OpLabel +OpBranch %sel_merge +%bb4 = OpLabel +OpBranch %sel_merge +%sel_merge = OpLabel +OpBranch %loop_merge +%cont = OpLabel +OpBranch %loop_header +%loop_merge = OpLabel +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(predefs + body, true); +} + +TEST_F(DeadBranchElimTest, SelectionMergeWithExitToLoopContinue) { + // Checks that if a selection merge construct contains a conditional branch + // to continue of a loop surrounding the selection merge, then we do not keep + // the OpSelectionMerge instruction. + const std::string predefs = R"( +OpCapability Shader +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 140 +%void = OpTypeVoid +%func_type = OpTypeFunction %void +%bool = OpTypeBool +%true = OpConstantTrue %bool +%undef_bool = OpUndef %bool +)"; + + const std::string body = + R"(; +; CHECK: OpLabel +; CHECK: [[loop_header:%\w+]] = OpLabel +; CHECK: OpLoopMerge [[loop_merge:%\w+]] [[loop_cont:%\w+]] +; CHECK-NEXT: OpBranch [[bb1:%\w+]] +; CHECK: [[bb1]] = OpLabel +; CHECK-NEXT: OpBranch [[bb2:%\w+]] +; CHECK: [[bb2]] = OpLabel +; CHECK-NEXT: OpBranchConditional {{%\w+}} [[bb3:%\w+]] [[loop_cont]] +; CHECK: [[bb3]] = OpLabel +; CHECK-NEXT: OpBranch [[sel_merge:%\w+]] +; CHECK: [[sel_merge]] = OpLabel +; CHECK-NEXT: OpBranch [[loop_merge]] +; CHECK: [[loop_cont]] = OpLabel +; CHECK-NEXT: OpBranch [[loop_header]] +; CHECK: [[loop_merge]] = OpLabel +; CHECK-NEXT: OpReturn +%main = OpFunction %void None %func_type +%entry_bb = OpLabel +OpBranch %loop_header +%loop_header = OpLabel +OpLoopMerge %loop_merge %cont None +OpBranch %bb1 +%bb1 = OpLabel +OpSelectionMerge %sel_merge None +OpBranchConditional %true %bb2 %bb4 +%bb2 = OpLabel +OpBranchConditional %undef_bool %bb3 %cont +%bb3 = OpLabel +OpBranch %sel_merge +%bb4 = OpLabel +OpBranch %sel_merge +%sel_merge = OpLabel +OpBranch %loop_merge +%cont = OpLabel +OpBranch %loop_header +%loop_merge = OpLabel +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(predefs + body, true); +} + +TEST_F(DeadBranchElimTest, SelectionMergeWithExitToLoop2) { + // Same as |SelectionMergeWithExitToLoop|, except the switch goes to the loop + // merge or the selection merge. In this case, we do not need an + // OpSelectionMerge either. + const std::string predefs = R"( +OpCapability Shader +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 140 +%void = OpTypeVoid +%func_type = OpTypeFunction %void +%bool = OpTypeBool +%true = OpConstantTrue %bool +%undef_bool = OpUndef %bool +)"; + + const std::string body = + R"( +; CHECK: OpLoopMerge [[loop_merge:%\w+]] +; CHECK-NEXT: OpBranch [[bb1:%\w+]] +; CHECK: [[bb1]] = OpLabel +; CHECK-NEXT: OpBranch [[bb2:%\w+]] +; CHECK: [[bb2]] = OpLabel +; CHECK-NEXT: OpBranchConditional {{%\w+}} [[sel_merge:%\w+]] [[loop_merge]] +; CHECK: [[sel_merge]] = OpLabel +; CHECK-NEXT: OpBranch [[loop_merge]] +; CHECK: [[loop_merge]] = OpLabel +; CHECK-NEXT: OpReturn +%main = OpFunction %void None %func_type +%entry_bb = OpLabel +OpBranch %loop_header +%loop_header = OpLabel +OpLoopMerge %loop_merge %cont None +OpBranch %bb1 +%bb1 = OpLabel +OpSelectionMerge %sel_merge None +OpBranchConditional %true %bb2 %bb4 +%bb2 = OpLabel +OpBranchConditional %undef_bool %sel_merge %loop_merge +%bb4 = OpLabel +OpBranch %sel_merge +%sel_merge = OpLabel +OpBranch %loop_merge +%cont = OpLabel +OpBranch %loop_header +%loop_merge = OpLabel +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(predefs + body, true); +} + +TEST_F(DeadBranchElimTest, SelectionMergeWithExitToLoopContinue2) { + // Same as |SelectionMergeWithExitToLoopContinue|, except the branch goes to + // the loop continue or the selection merge. In this case, we do not need an + // OpSelectionMerge either. + const std::string predefs = R"( +OpCapability Shader +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 140 +%void = OpTypeVoid +%func_type = OpTypeFunction %void +%bool = OpTypeBool +%true = OpConstantTrue %bool +%undef_bool = OpUndef %bool +)"; + + const std::string body = + R"( +; CHECK: OpLabel +; CHECK: [[loop_header:%\w+]] = OpLabel +; CHECK: OpLoopMerge [[loop_merge:%\w+]] [[loop_cont:%\w+]] +; CHECK-NEXT: OpBranch [[bb1:%\w+]] +; CHECK: [[bb1]] = OpLabel +; CHECK-NEXT: OpBranch [[bb2:%\w+]] +; CHECK: [[bb2]] = OpLabel +; CHECK-NEXT: OpBranchConditional {{%\w+}} [[sel_merge:%\w+]] [[loop_cont]] +; CHECK: [[sel_merge]] = OpLabel +; CHECK-NEXT: OpBranch [[loop_merge]] +; CHECK: [[loop_cont]] = OpLabel +; CHECK: OpBranch [[loop_header]] +; CHECK: [[loop_merge]] = OpLabel +; CHECK-NEXT: OpReturn +%main = OpFunction %void None %func_type +%entry_bb = OpLabel +OpBranch %loop_header +%loop_header = OpLabel +OpLoopMerge %loop_merge %cont None +OpBranch %bb1 +%bb1 = OpLabel +OpSelectionMerge %sel_merge None +OpBranchConditional %true %bb2 %bb4 +%bb2 = OpLabel +OpBranchConditional %undef_bool %sel_merge %cont +%bb4 = OpLabel +OpBranch %sel_merge +%sel_merge = OpLabel +OpBranch %loop_merge +%cont = OpLabel +OpBranch %loop_header +%loop_merge = OpLabel +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(predefs + body, true); +} + +TEST_F(DeadBranchElimTest, SelectionMergeWithExitToLoop3) { + // Checks that if a selection merge construct contains a conditional branch + // to the merge of a surrounding loop, the selection merge, and another block + // inside the selection merge, then we must keep the OpSelectionMerge + // instruction on that branch. + const std::string predefs = R"( +OpCapability Shader +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 140 +%void = OpTypeVoid +%func_type = OpTypeFunction %void +%bool = OpTypeBool +%true = OpConstantTrue %bool +%uint = OpTypeInt 32 0 +%undef_int = OpUndef %uint +)"; + + const std::string body = + R"( +; CHECK: OpLoopMerge [[loop_merge:%\w+]] +; CHECK-NEXT: OpBranch [[bb1:%\w+]] +; CHECK: [[bb1]] = OpLabel +; CHECK-NEXT: OpBranch [[bb2:%\w+]] +; CHECK: [[bb2]] = OpLabel +; CHECK-NEXT: OpSelectionMerge [[sel_merge:%\w+]] None +; CHECK-NEXT: OpSwitch {{%\w+}} [[sel_merge]] 0 [[loop_merge]] 1 [[bb3:%\w+]] +; CHECK: [[bb3]] = OpLabel +; CHECK-NEXT: OpBranch [[sel_merge]] +; CHECK: [[sel_merge]] = OpLabel +; CHECK-NEXT: OpBranch [[loop_merge]] +; CHECK: [[loop_merge]] = OpLabel +; CHECK-NEXT: OpReturn +%main = OpFunction %void None %func_type +%entry_bb = OpLabel +OpBranch %loop_header +%loop_header = OpLabel +OpLoopMerge %loop_merge %cont None +OpBranch %bb1 +%bb1 = OpLabel +OpSelectionMerge %sel_merge None +OpBranchConditional %true %bb2 %bb4 +%bb2 = OpLabel +OpSwitch %undef_int %sel_merge 0 %loop_merge 1 %bb3 +%bb3 = OpLabel +OpBranch %sel_merge +%bb4 = OpLabel +OpBranch %sel_merge +%sel_merge = OpLabel +OpBranch %loop_merge +%cont = OpLabel +OpBranch %loop_header +%loop_merge = OpLabel +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(predefs + body, true); +} + +TEST_F(DeadBranchElimTest, SelectionMergeWithExitToLoopContinue3) { + // Checks that if a selection merge construct contains a conditional branch + // to the merge of a surrounding loop, the selection merge, and another block + // inside the selection merge, then we must keep the OpSelectionMerge + // instruction on that branch. + const std::string predefs = R"( +OpCapability Shader +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 140 +%void = OpTypeVoid +%func_type = OpTypeFunction %void +%bool = OpTypeBool +%true = OpConstantTrue %bool +%uint = OpTypeInt 32 0 +%undef_int = OpUndef %uint +)"; + + const std::string body = + R"( +; CHECK: OpLabel +; CHECK: [[loop_header:%\w+]] = OpLabel +; CHECK: OpLoopMerge [[loop_merge:%\w+]] [[loop_continue:%\w+]] +; CHECK-NEXT: OpBranch [[bb1:%\w+]] +; CHECK: [[bb1]] = OpLabel +; CHECK-NEXT: OpBranch [[bb2:%\w+]] +; CHECK: [[bb2]] = OpLabel +; CHECK-NEXT: OpSelectionMerge [[sel_merge:%\w+]] None +; CHECK-NEXT: OpSwitch {{%\w+}} [[sel_merge]] 0 [[loop_continue]] 1 [[bb3:%\w+]] +; CHECK: [[bb3]] = OpLabel +; CHECK-NEXT: OpBranch [[sel_merge]] +; CHECK: [[sel_merge]] = OpLabel +; CHECK-NEXT: OpBranch [[loop_merge]] +; CHECK: [[loop_continue]] = OpLabel +; CHECK-NEXT: OpBranch [[loop_header]] +; CHECK: [[loop_merge]] = OpLabel +; CHECK-NEXT: OpReturn +%main = OpFunction %void None %func_type +%entry_bb = OpLabel +OpBranch %loop_header +%loop_header = OpLabel +OpLoopMerge %loop_merge %cont None +OpBranch %bb1 +%bb1 = OpLabel +OpSelectionMerge %sel_merge None +OpBranchConditional %true %bb2 %bb4 +%bb2 = OpLabel +OpSwitch %undef_int %sel_merge 0 %cont 1 %bb3 +%bb3 = OpLabel +OpBranch %sel_merge +%bb4 = OpLabel +OpBranch %sel_merge +%sel_merge = OpLabel +OpBranch %loop_merge +%cont = OpLabel +OpBranch %loop_header +%loop_merge = OpLabel +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(predefs + body, true); +} + +TEST_F(DeadBranchElimTest, SelectionMergeWithExitToLoop4) { + // Same as |SelectionMergeWithExitToLoop|, except the branch in the selection + // construct is an |OpSwitch| instead of an |OpConditionalBranch|. The + // OpSelectionMerge instruction is not needed in this case either. + const std::string predefs = R"( +OpCapability Shader +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 140 +%void = OpTypeVoid +%func_type = OpTypeFunction %void +%bool = OpTypeBool +%true = OpConstantTrue %bool +%uint = OpTypeInt 32 0 +%undef_int = OpUndef %uint +)"; + + const std::string body = + R"( +; CHECK: OpLoopMerge [[loop_merge:%\w+]] +; CHECK-NEXT: OpBranch [[bb1:%\w+]] +; CHECK: [[bb1]] = OpLabel +; CHECK-NEXT: OpBranch [[bb2:%\w+]] +; CHECK: [[bb2]] = OpLabel +; CHECK-NEXT: OpSwitch {{%\w+}} [[bb3:%\w+]] 0 [[loop_merge]] 1 [[bb3:%\w+]] +; CHECK: [[bb3]] = OpLabel +; CHECK-NEXT: OpBranch [[sel_merge:%\w+]] +; CHECK: [[sel_merge]] = OpLabel +; CHECK-NEXT: OpBranch [[loop_merge]] +; CHECK: [[loop_merge]] = OpLabel +; CHECK-NEXT: OpReturn +%main = OpFunction %void None %func_type +%entry_bb = OpLabel +OpBranch %loop_header +%loop_header = OpLabel +OpLoopMerge %loop_merge %cont None +OpBranch %bb1 +%bb1 = OpLabel +OpSelectionMerge %sel_merge None +OpBranchConditional %true %bb2 %bb4 +%bb2 = OpLabel +OpSwitch %undef_int %bb3 0 %loop_merge 1 %bb3 +%bb3 = OpLabel +OpBranch %sel_merge +%bb4 = OpLabel +OpBranch %sel_merge +%sel_merge = OpLabel +OpBranch %loop_merge +%cont = OpLabel +OpBranch %loop_header +%loop_merge = OpLabel +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(predefs + body, true); +} + +TEST_F(DeadBranchElimTest, SelectionMergeWithExitToLoopContinue4) { + // Same as |SelectionMergeWithExitToLoopContinue|, except the branch in the + // selection construct is an |OpSwitch| instead of an |OpConditionalBranch|. + // The OpSelectionMerge instruction is not needed in this case either. + const std::string predefs = R"( +OpCapability Shader +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 140 +%void = OpTypeVoid +%func_type = OpTypeFunction %void +%bool = OpTypeBool +%true = OpConstantTrue %bool +%uint = OpTypeInt 32 0 +%undef_int = OpUndef %uint +)"; + + const std::string body = + R"( +; CHECK: OpLoopMerge [[loop_merge:%\w+]] [[loop_cont:%\w+]] +; CHECK-NEXT: OpBranch [[bb1:%\w+]] +; CHECK: [[bb1]] = OpLabel +; CHECK-NEXT: OpBranch [[bb2:%\w+]] +; CHECK: [[bb2]] = OpLabel +; CHECK-NEXT: OpSwitch {{%\w+}} [[bb3:%\w+]] 0 [[loop_cont]] 1 [[bb3:%\w+]] +; CHECK: [[bb3]] = OpLabel +; CHECK-NEXT: OpBranch [[sel_merge:%\w+]] +; CHECK: [[sel_merge]] = OpLabel +; CHECK-NEXT: OpBranch [[loop_merge]] +; CHECK: [[loop_merge]] = OpLabel +; CHECK-NEXT: OpReturn +%main = OpFunction %void None %func_type +%entry_bb = OpLabel +OpBranch %loop_header +%loop_header = OpLabel +OpLoopMerge %loop_merge %cont None +OpBranch %bb1 +%bb1 = OpLabel +OpSelectionMerge %sel_merge None +OpBranchConditional %true %bb2 %bb4 +%bb2 = OpLabel +OpSwitch %undef_int %bb3 0 %cont 1 %bb3 +%bb3 = OpLabel +OpBranch %sel_merge +%bb4 = OpLabel +OpBranch %sel_merge +%sel_merge = OpLabel +OpBranch %loop_merge +%cont = OpLabel +OpBranch %loop_header +%loop_merge = OpLabel +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(predefs + body, true); +} + +TEST_F(DeadBranchElimTest, SelectionMergeSameAsLoopContinue) { + // Same as |SelectionMergeWithExitToLoopContinue|, except the branch in the + // selection construct is an |OpSwitch| instead of an |OpConditionalBranch|. + // The OpSelectionMerge instruction is not needed in this case either. + const std::string predefs = R"( +OpCapability Shader +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 140 +%void = OpTypeVoid +%func_type = OpTypeFunction %void +%bool = OpTypeBool +%true = OpConstantTrue %bool +%uint = OpTypeInt 32 0 +%undef_bool = OpUndef %bool +)"; + + const std::string body = + R"( +; CHECK: OpLabel +; CHECK: [[loop_header:%\w+]] = OpLabel +; CHECK: OpLoopMerge [[loop_merge:%\w+]] [[loop_cont:%\w+]] +; CHECK-NEXT: OpBranch [[bb1:%\w+]] +; CHECK: [[bb1]] = OpLabel +; CHECK-NEXT: OpBranch [[bb2:%\w+]] +; CHECK: [[bb2]] = OpLabel +; CHECK-NEXT: OpSelectionMerge [[loop_cont]] +; CHECK-NEXT: OpBranchConditional {{%\w+}} [[bb3:%\w+]] [[loop_cont]] +; CHECK: [[bb3]] = OpLabel +; CHECK-NEXT: OpBranch [[loop_cont]] +; CHECK: [[loop_cont]] = OpLabel +; CHECK-NEXT: OpBranchConditional {{%\w+}} [[loop_header]] [[loop_merge]] +; CHECK: [[loop_merge]] = OpLabel +; CHECK-NEXT: OpReturn +%main = OpFunction %void None %func_type +%entry_bb = OpLabel +OpBranch %loop_header +%loop_header = OpLabel +OpLoopMerge %loop_merge %cont None +OpBranch %bb1 +%bb1 = OpLabel +OpSelectionMerge %cont None +OpBranchConditional %true %bb2 %bb4 +%bb2 = OpLabel +OpBranchConditional %undef_bool %bb3 %cont +%bb3 = OpLabel +OpBranch %cont +%bb4 = OpLabel +OpBranch %cont +%cont = OpLabel +OpBranchConditional %undef_bool %loop_header %loop_merge +%loop_merge = OpLabel +OpReturn +OpFunctionEnd +)"; + + // The selection merge in the loop naming the continue target as merge is + // invalid, but handled by this pass so validation is disabled. + SinglePassRunAndMatch(predefs + body, false); +} + +TEST_F(DeadBranchElimTest, SelectionMergeWithNestedLoop) { + const std::string body = + R"( +; CHECK: OpSelectionMerge [[merge1:%\w+]] +; CHECK: [[merge1]] = OpLabel +; CHECK-NEXT: OpBranch [[preheader:%\w+]] +; CHECK: [[preheader]] = OpLabel +; CHECK-NOT: OpLabel +; CHECK: OpBranch [[header:%\w+]] +; CHECK: [[header]] = OpLabel +; CHECK-NOT: OpLabel +; CHECK: OpLoopMerge [[merge2:%\w+]] +; CHECK: [[merge2]] = OpLabel +; CHECK-NEXT: OpUnreachable + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" + OpExecutionMode %main OriginUpperLeft + OpSource ESSL 310 + OpName %main "main" + OpName %h "h" + OpName %i "i" + %void = OpTypeVoid + %3 = OpTypeFunction %void + %bool = OpTypeBool + %_ptr_Function_bool = OpTypePointer Function %bool + %true = OpConstantTrue %bool + %int = OpTypeInt 32 1 + %_ptr_Function_int = OpTypePointer Function %int + %int_1 = OpConstant %int 1 + %int_0 = OpConstant %int 0 + %27 = OpUndef %bool + %main = OpFunction %void None %3 + %5 = OpLabel + %h = OpVariable %_ptr_Function_bool Function + %i = OpVariable %_ptr_Function_int Function + OpSelectionMerge %11 None + OpBranchConditional %27 %10 %11 + %10 = OpLabel + OpBranch %11 + %11 = OpLabel + OpSelectionMerge %14 None + OpBranchConditional %true %13 %14 + %13 = OpLabel + OpStore %i %int_1 + OpBranch %19 + %19 = OpLabel + OpLoopMerge %21 %22 None + OpBranch %23 + %23 = OpLabel + %26 = OpSGreaterThan %bool %int_1 %int_0 + OpBranchConditional %true %20 %21 + %20 = OpLabel + OpBranch %22 + %22 = OpLabel + OpBranch %19 + %21 = OpLabel + OpBranch %14 + %14 = OpLabel + OpReturn + OpFunctionEnd +)"; + + SinglePassRunAndMatch(body, true); +} + +TEST_F(DeadBranchElimTest, DontFoldBackedge) { + const std::string body = + R"(OpCapability Shader +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %2 "main" +OpExecutionMode %2 OriginUpperLeft +%void = OpTypeVoid +%4 = OpTypeFunction %void +%bool = OpTypeBool +%false = OpConstantFalse %bool +%2 = OpFunction %void None %4 +%7 = OpLabel +OpBranch %8 +%8 = OpLabel +OpLoopMerge %9 %10 None +OpBranch %11 +%11 = OpLabel +%12 = OpUndef %bool +OpSelectionMerge %10 None +OpBranchConditional %12 %13 %10 +%13 = OpLabel +OpBranch %9 +%10 = OpLabel +OpBranch %14 +%14 = OpLabel +OpBranchConditional %false %8 %9 +%9 = OpLabel +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndCheck(body, body, true); +} + +TEST_F(DeadBranchElimTest, FoldBackedgeToHeader) { + const std::string body = + R"( +; CHECK: OpLabel +; CHECK: [[header:%\w+]] = OpLabel +; CHECK-NEXT: OpLoopMerge {{%\w+}} [[cont:%\w+]] +; CHECK: [[cont]] = OpLabel +; This branch may not be in the continue block, but must come after it. +; CHECK: OpBranch [[header]] +OpCapability Shader +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %2 "main" +OpExecutionMode %2 OriginUpperLeft +%void = OpTypeVoid +%4 = OpTypeFunction %void +%bool = OpTypeBool +%true = OpConstantTrue %bool +%2 = OpFunction %void None %4 +%7 = OpLabel +OpBranch %8 +%8 = OpLabel +OpLoopMerge %9 %10 None +OpBranch %11 +%11 = OpLabel +%12 = OpUndef %bool +OpSelectionMerge %10 None +OpBranchConditional %12 %13 %10 +%13 = OpLabel +OpBranch %9 +%10 = OpLabel +OpBranch %14 +%14 = OpLabel +OpBranchConditional %true %8 %9 +%9 = OpLabel +OpReturn +OpFunctionEnd +)"; + + // The selection merge in the loop naming the continue target as merge is + // invalid, but handled by this pass so validation is disabled. + SinglePassRunAndMatch(body, false); +} + +TEST_F(DeadBranchElimTest, UnreachableMergeAndContinueSameBlock) { + const std::string spirv = R"( +; CHECK: OpLabel +; CHECK: [[outer:%\w+]] = OpLabel +; CHECK-NEXT: OpLoopMerge [[outer_merge:%\w+]] [[outer_cont:%\w+]] None +; CHECK-NEXT: OpBranch [[inner:%\w+]] +; CHECK: [[inner]] = OpLabel +; CHECK: OpLoopMerge [[outer_cont]] [[inner_cont:%\w+]] None +; CHECK: [[inner_cont]] = OpLabel +; CHECK-NEXT: OpBranch [[inner]] +; CHECK: [[outer_cont]] = OpLabel +; CHECK-NEXT: OpBranch [[outer]] +; CHECK: [[outer_merge]] = OpLabel +; CHECK-NEXT: OpUnreachable +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +%void = OpTypeVoid +%bool = OpTypeBool +%true = OpConstantTrue %bool +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpBranch %outer_loop +%outer_loop = OpLabel +OpLoopMerge %outer_merge %outer_continue None +OpBranch %inner_loop +%inner_loop = OpLabel +OpLoopMerge %outer_continue %inner_continue None +OpBranch %inner_body +%inner_body = OpLabel +OpSelectionMerge %inner_continue None +OpBranchConditional %true %ret %inner_continue +%ret = OpLabel +OpReturn +%inner_continue = OpLabel +OpBranchConditional %true %outer_continue %inner_loop +%outer_continue = OpLabel +OpBranchConditional %true %outer_merge %outer_loop +%outer_merge = OpLabel +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(spirv, true); +} + +// Fold a switch with a nested break. The only case should be the default. +TEST_F(DeadBranchElimTest, FoldSwitchWithNestedBreak) { + const std::string spirv = R"( +; CHECK: OpSwitch %int_3 [[case_bb:%\w+]]{{[[:space:]]}} +; CHECK: [[case_bb]] = OpLabel +; CHECK-NEXT: OpUndef +; CHECK-NEXT: OpSelectionMerge + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %2 "main" + OpSource GLSL 450 + %void = OpTypeVoid + %4 = OpTypeFunction %void + %int = OpTypeInt 32 1 +%_ptr_Function_int = OpTypePointer Function %int + %int_3 = OpConstant %int 3 + %int_1 = OpConstant %int 1 + %bool = OpTypeBool + %2 = OpFunction %void None %4 + %10 = OpLabel + OpSelectionMerge %11 None + OpSwitch %int_3 %12 3 %13 + %12 = OpLabel + OpBranch %11 + %13 = OpLabel + %14 = OpUndef %bool + OpSelectionMerge %15 None + OpBranchConditional %14 %16 %15 + %16 = OpLabel + OpBranch %11 + %15 = OpLabel + OpBranch %11 + %11 = OpLabel + OpReturn + OpFunctionEnd +)"; + + SinglePassRunAndMatch(spirv, true); +} + +TEST_F(DeadBranchElimTest, FoldBranchWithBreakToSwitch) { + const std::string spirv = R"( +; CHECK: OpSelectionMerge [[sel_merge:%\w+]] +; CHECK-NEXT: OpSwitch {{%\w+}} {{%\w+}} 3 [[bb:%\w+]] +; CHECK: [[bb]] = OpLabel +; CHECK-NEXT: OpBranch [[bb2:%\w+]] +; CHECK: [[bb2]] = OpLabel +; CHECK-NOT: OpSelectionMerge +; CHECK: OpFunctionEnd + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %2 "main" + OpSource GLSL 450 + %void = OpTypeVoid + %4 = OpTypeFunction %void + %int = OpTypeInt 32 1 +%_ptr_Function_int = OpTypePointer Function %int + %int_3 = OpConstant %int 3 + %int_1 = OpConstant %int 1 + %bool = OpTypeBool + %true = OpConstantTrue %bool + %2 = OpFunction %void None %4 + %10 = OpLabel + %undef_int = OpUndef %int + OpSelectionMerge %11 None + OpSwitch %undef_int %12 3 %13 + %12 = OpLabel + OpBranch %11 + %13 = OpLabel + OpSelectionMerge %15 None + OpBranchConditional %true %16 %15 + %16 = OpLabel + %14 = OpUndef %bool + OpBranchConditional %14 %11 %17 + %17 = OpLabel + OpBranch %15 + %15 = OpLabel + OpBranch %11 + %11 = OpLabel + OpReturn + OpFunctionEnd +)"; + + SinglePassRunAndMatch(spirv, true); +} + +TEST_F(DeadBranchElimTest, IfInSwitch) { + // #version 310 es + // + // void main() + // { + // switch(0) + // { + // case 0: + // if(false) + // { + // } + // else + // { + // } + // } + // } + + const std::string before = + R"(OpCapability Shader +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpSource ESSL 310 +OpName %main "main" +%void = OpTypeVoid +%3 = OpTypeFunction %void +%int = OpTypeInt 32 1 +%int_0 = OpConstant %int 0 +%bool = OpTypeBool +%false = OpConstantFalse %bool +%main = OpFunction %void None %3 +%5 = OpLabel +OpSelectionMerge %9 None +OpSwitch %int_0 %9 0 %8 +%8 = OpLabel +OpSelectionMerge %13 None +OpBranchConditional %false %12 %13 +%12 = OpLabel +OpBranch %13 +%13 = OpLabel +OpBranch %9 +%9 = OpLabel +OpReturn +OpFunctionEnd +)"; + + const std::string after = + R"(OpCapability Shader +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpSource ESSL 310 +OpName %main "main" +%void = OpTypeVoid +%4 = OpTypeFunction %void +%int = OpTypeInt 32 1 +%int_0 = OpConstant %int 0 +%bool = OpTypeBool +%false = OpConstantFalse %bool +%main = OpFunction %void None %4 +%9 = OpLabel +OpBranch %11 +%11 = OpLabel +OpBranch %12 +%12 = OpLabel +OpBranch %10 +%10 = OpLabel +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndCheck(before, after, true, true); +} + +TEST_F(DeadBranchElimTest, BreakInNestedHeaderWithSingleCase) { + const std::string text = R"(OpCapability Shader +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 450 +OpName %main "main" +%void = OpTypeVoid +%4 = OpTypeFunction %void +%bool = OpTypeBool +%uint = OpTypeInt 32 0 +%uint_0 = OpConstant %uint 0 +%8 = OpUndef %bool +%main = OpFunction %void None %4 +%9 = OpLabel +OpSelectionMerge %10 None +OpSwitch %uint_0 %11 +%11 = OpLabel +OpSelectionMerge %12 None +OpBranchConditional %8 %10 %12 +%12 = OpLabel +OpBranch %10 +%10 = OpLabel +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndCheck(text, text, true, true); +} + +TEST_F(DeadBranchElimTest, BreakInNestedHeaderWithTwoCases) { + const std::string text = R"( +; CHECK: OpSelectionMerge [[merge:%\w+]] None +; CHECK-NEXT: OpSwitch %uint_0 [[bb:%\w+\n]] +OpCapability Shader +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 450 +OpName %main "main" +%void = OpTypeVoid +%4 = OpTypeFunction %void +%bool = OpTypeBool +%uint = OpTypeInt 32 0 +%uint_0 = OpConstant %uint 0 +%8 = OpUndef %bool +%main = OpFunction %void None %4 +%9 = OpLabel +OpSelectionMerge %10 None +OpSwitch %uint_0 %11 1 %12 +%11 = OpLabel +OpSelectionMerge %13 None +OpBranchConditional %8 %10 %13 +%13 = OpLabel +OpBranch %10 +%12 = OpLabel +OpBranch %10 +%10 = OpLabel +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} // TODO(greg-lunarg): Add tests to verify handling of these cases: // diff --git a/third_party/spirv-tools/test/opt/dead_variable_elim_test.cpp b/third_party/spirv-tools/test/opt/dead_variable_elim_test.cpp index fca13a8e2f..a55ee62a55 100644 --- a/third_party/spirv-tools/test/opt/dead_variable_elim_test.cpp +++ b/third_party/spirv-tools/test/opt/dead_variable_elim_test.cpp @@ -217,7 +217,7 @@ OpName %initializer "initializer" %6 = OpTypeFunction %void %float = OpTypeFloat 32 %_ptr_Private_float = OpTypePointer Private %float -%initializer = OpVariable %_ptr_Private_float Private +%initializer = OpConstant %float 0 %live = OpVariable %_ptr_Private_float Private %initializer %main = OpFunction %void None %6 %9 = OpLabel diff --git a/third_party/spirv-tools/test/opt/decompose_initialized_variables_test.cpp b/third_party/spirv-tools/test/opt/decompose_initialized_variables_test.cpp new file mode 100644 index 0000000000..06ba59a584 --- /dev/null +++ b/third_party/spirv-tools/test/opt/decompose_initialized_variables_test.cpp @@ -0,0 +1,252 @@ +// Copyright (c) 2019 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 + +#include "test/opt/pass_fixture.h" +#include "test/opt/pass_utils.h" + +namespace spvtools { +namespace opt { +namespace { + +using DecomposeInitializedVariablesTest = PassTest<::testing::Test>; + +std::string single_entry_header = R"(OpCapability Shader +OpCapability VulkanMemoryModel +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical Vulkan +OpEntryPoint Vertex %1 "shader" +%uint = OpTypeInt 32 0 +%uint_1 = OpConstant %uint 1 +%4 = OpConstantNull %uint +%void = OpTypeVoid +%6 = OpTypeFunction %void +)"; + +std::string GetFunctionTest(std::string body) { + auto result = single_entry_header; + result += "%_ptr_Function_uint = OpTypePointer Function %uint\n"; + result += "%1 = OpFunction %void None %6\n"; + result += "%8 = OpLabel\n"; + result += body + "\n"; + result += "OpReturn\n"; + result += "OpFunctionEnd\n"; + return result; +} + +TEST_F(DecomposeInitializedVariablesTest, FunctionChanged) { + std::string input = "%9 = OpVariable %_ptr_Function_uint Function %uint_1"; + std::string expected = R"(%9 = OpVariable %_ptr_Function_uint Function +OpStore %9 %uint_1)"; + + SinglePassRunAndCheck( + GetFunctionTest(input), GetFunctionTest(expected), + /* skip_nop = */ false); +} + +TEST_F(DecomposeInitializedVariablesTest, FunctionUnchanged) { + std::string input = "%9 = OpVariable %_ptr_Function_uint Function"; + + SinglePassRunAndCheck( + GetFunctionTest(input), GetFunctionTest(input), /* skip_nop = */ false); +} + +TEST_F(DecomposeInitializedVariablesTest, FunctionMultipleVariables) { + std::string input = R"(%9 = OpVariable %_ptr_Function_uint Function %uint_1 +%10 = OpVariable %_ptr_Function_uint Function %4)"; + std::string expected = R"(%9 = OpVariable %_ptr_Function_uint Function +%10 = OpVariable %_ptr_Function_uint Function +OpStore %9 %uint_1 +OpStore %10 %4)"; + + SinglePassRunAndCheck( + GetFunctionTest(input), GetFunctionTest(expected), + /* skip_nop = */ false); +} + +std::string GetGlobalTest(std::string storage_class, bool initialized, + bool decomposed) { + auto result = single_entry_header; + + result += "%_ptr_" + storage_class + "_uint = OpTypePointer " + + storage_class + " %uint\n"; + if (initialized) { + result += "%8 = OpVariable %_ptr_" + storage_class + "_uint " + + storage_class + " %4\n"; + } else { + result += "%8 = OpVariable %_ptr_" + storage_class + "_uint " + + storage_class + "\n"; + } + result += R"(%1 = OpFunction %void None %9 +%9 = OpLabel +)"; + if (decomposed) result += "OpStore %8 %4\n"; + result += R"(OpReturn +OpFunctionEnd +)"; + return result; +} + +TEST_F(DecomposeInitializedVariablesTest, PrivateChanged) { + std::string input = GetGlobalTest("Private", true, false); + std::string expected = GetGlobalTest("Private", false, true); + SinglePassRunAndCheck( + input, expected, /* skip_nop = */ false); +} + +TEST_F(DecomposeInitializedVariablesTest, PrivateUnchanged) { + std::string input = GetGlobalTest("Private", false, false); + SinglePassRunAndCheck( + input, input, /* skip_nop = */ false); +} + +TEST_F(DecomposeInitializedVariablesTest, OutputChanged) { + std::string input = GetGlobalTest("Output", true, false); + std::string expected = GetGlobalTest("Output", false, true); + SinglePassRunAndCheck( + input, expected, /* skip_nop = */ false); +} + +TEST_F(DecomposeInitializedVariablesTest, OutputUnchanged) { + std::string input = GetGlobalTest("Output", false, false); + SinglePassRunAndCheck( + input, input, /* skip_nop = */ false); +} + +std::string multiple_entry_header = R"(OpCapability Shader +OpCapability VulkanMemoryModel +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical Vulkan +OpEntryPoint Vertex %1 "vertex" +OpEntryPoint Fragment %2 "fragment" +%uint = OpTypeInt 32 0 +%4 = OpConstantNull %uint +%void = OpTypeVoid +%6 = OpTypeFunction %void +)"; + +std::string GetGlobalMultipleEntryTest(std::string storage_class, + bool initialized, bool decomposed) { + auto result = multiple_entry_header; + result += "%_ptr_" + storage_class + "_uint = OpTypePointer " + + storage_class + " %uint\n"; + if (initialized) { + result += "%8 = OpVariable %_ptr_" + storage_class + "_uint " + + storage_class + " %4\n"; + } else { + result += "%8 = OpVariable %_ptr_" + storage_class + "_uint " + + storage_class + "\n"; + } + result += R"(%1 = OpFunction %void None %9 +%9 = OpLabel +)"; + if (decomposed) result += "OpStore %8 %4\n"; + result += R"(OpReturn +OpFunctionEnd +%2 = OpFunction %void None %10 +%10 = OpLabel +)"; + if (decomposed) result += "OpStore %8 %4\n"; + result += R"(OpReturn +OpFunctionEnd +)"; + + return result; +} + +TEST_F(DecomposeInitializedVariablesTest, PrivateMultipleEntryChanged) { + std::string input = GetGlobalMultipleEntryTest("Private", true, false); + std::string expected = GetGlobalMultipleEntryTest("Private", false, true); + SinglePassRunAndCheck( + input, expected, /* skip_nop = */ false); +} + +TEST_F(DecomposeInitializedVariablesTest, PrivateMultipleEntryUnchanged) { + std::string input = GetGlobalMultipleEntryTest("Private", false, false); + SinglePassRunAndCheck( + input, input, /* skip_nop = */ false); +} + +TEST_F(DecomposeInitializedVariablesTest, OutputMultipleEntryChanged) { + std::string input = GetGlobalMultipleEntryTest("Output", true, false); + std::string expected = GetGlobalMultipleEntryTest("Output", false, true); + SinglePassRunAndCheck( + input, expected, /* skip_nop = */ false); +} + +TEST_F(DecomposeInitializedVariablesTest, OutputMultipleEntryUnchanged) { + std::string input = GetGlobalMultipleEntryTest("Output", false, false); + SinglePassRunAndCheck( + input, input, /* skip_nop = */ false); +} + +std::string GetGlobalWithNonEntryPointTest(std::string storage_class, + bool initialized, bool decomposed) { + auto result = single_entry_header; + result += "%_ptr_" + storage_class + "_uint = OpTypePointer " + + storage_class + " %uint\n"; + if (initialized) { + result += "%8 = OpVariable %_ptr_" + storage_class + "_uint " + + storage_class + " %4\n"; + } else { + result += "%8 = OpVariable %_ptr_" + storage_class + "_uint " + + storage_class + "\n"; + } + result += R"(%1 = OpFunction %void None %9 +%9 = OpLabel +)"; + if (decomposed) result += "OpStore %8 %4\n"; + result += R"(OpReturn +OpFunctionEnd +%10 = OpFunction %void None %11 +%11 = OpLabel +OpReturn +OpFunctionEnd +)"; + + return result; +} + +TEST_F(DecomposeInitializedVariablesTest, PrivateWithNonEntryPointChanged) { + std::string input = GetGlobalWithNonEntryPointTest("Private", true, false); + std::string expected = GetGlobalWithNonEntryPointTest("Private", false, true); + SinglePassRunAndCheck( + input, expected, /* skip_nop = */ false); +} + +TEST_F(DecomposeInitializedVariablesTest, PrivateWithNonEntryPointUnchanged) { + std::string input = GetGlobalWithNonEntryPointTest("Private", false, false); + // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck( + input, input, /* skip_nop = */ false); +} + +TEST_F(DecomposeInitializedVariablesTest, OutputWithNonEntryPointChanged) { + std::string input = GetGlobalWithNonEntryPointTest("Output", true, false); + std::string expected = GetGlobalWithNonEntryPointTest("Output", false, true); + SinglePassRunAndCheck( + input, expected, /* skip_nop = */ false); +} + +TEST_F(DecomposeInitializedVariablesTest, OutputWithNonEntryPointUnchanged) { + std::string input = GetGlobalWithNonEntryPointTest("Output", false, false); + // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck( + input, input, /* skip_nop = */ false); +} + +} // namespace +} // namespace opt +} // namespace spvtools diff --git a/third_party/spirv-tools/test/opt/decoration_manager_test.cpp b/third_party/spirv-tools/test/opt/decoration_manager_test.cpp index cf82e8e665..fcfbff0600 100644 --- a/third_party/spirv-tools/test/opt/decoration_manager_test.cpp +++ b/third_party/spirv-tools/test/opt/decoration_manager_test.cpp @@ -22,6 +22,7 @@ #include "source/opt/decoration_manager.h" #include "source/opt/ir_context.h" #include "source/spirv_constant.h" +#include "source/util/string_utils.h" #include "test/unit_spirv.h" namespace spvtools { @@ -29,7 +30,7 @@ namespace opt { namespace analysis { namespace { -using spvtest::MakeVector; +using utils::MakeVector; class DecorationManagerTest : public ::testing::Test { public: @@ -422,6 +423,7 @@ OpGroupDecorate %2 %1 %3 OpCapability Linkage OpMemoryModel Logical GLSL450 OpDecorate %1 Constant +%2 = OpDecorationGroup %4 = OpTypeInt 32 0 %1 = OpVariable %4 Uniform %3 = OpVariable %4 Uniform @@ -708,8 +710,8 @@ OpDecorate %1 Aliased EXPECT_THAT(GetErrorMessage(), ""); std::string expected_decorations = - R"(OpDecorateStringGOOGLE %5 HlslSemanticGOOGLE "blah" -OpDecorateId %5 HlslCounterBufferGOOGLE %2 + R"(OpDecorateString %5 UserSemantic "blah" +OpDecorateId %5 CounterBuffer %2 OpDecorate %5 Aliased )"; EXPECT_THAT(ToText(decorations), expected_decorations); @@ -719,11 +721,11 @@ OpCapability Linkage OpExtension "SPV_GOOGLE_hlsl_functionality1" OpExtension "SPV_GOOGLE_decorate_string" OpMemoryModel Logical GLSL450 -OpDecorateStringGOOGLE %1 HlslSemanticGOOGLE "blah" -OpDecorateId %1 HlslCounterBufferGOOGLE %2 +OpDecorateString %1 UserSemantic "blah" +OpDecorateId %1 CounterBuffer %2 OpDecorate %1 Aliased -OpDecorateStringGOOGLE %5 HlslSemanticGOOGLE "blah" -OpDecorateId %5 HlslCounterBufferGOOGLE %2 +OpDecorateString %5 UserSemantic "blah" +OpDecorateId %5 CounterBuffer %2 OpDecorate %5 Aliased %3 = OpTypeInt 32 0 %4 = OpTypePointer Uniform %3 @@ -1276,6 +1278,232 @@ OpDecorateStringGOOGLE %2 HlslSemanticGOOGLE "hello" EXPECT_FALSE(decoManager->HaveTheSameDecorations(1u, 2u)); } +TEST_F(DecorationManagerTest, SubSetTestOpDecorate1) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpDecorate %1 Restrict +OpDecorate %2 Constant +OpDecorate %2 Restrict +OpDecorate %1 Constant +%u32 = OpTypeInt 32 0 +%1 = OpVariable %u32 Uniform +%2 = OpVariable %u32 Uniform +)"; + DecorationManager* decoManager = GetDecorationManager(spirv); + EXPECT_THAT(GetErrorMessage(), ""); + EXPECT_TRUE(decoManager->HaveSubsetOfDecorations(1u, 2u)); +} + +TEST_F(DecorationManagerTest, SubSetTestOpDecorate2) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpDecorate %1 Restrict +OpDecorate %2 Constant +OpDecorate %2 Restrict +%u32 = OpTypeInt 32 0 +%1 = OpVariable %u32 Uniform +%2 = OpVariable %u32 Uniform +)"; + DecorationManager* decoManager = GetDecorationManager(spirv); + EXPECT_THAT(GetErrorMessage(), ""); + EXPECT_TRUE(decoManager->HaveSubsetOfDecorations(1u, 2u)); +} + +TEST_F(DecorationManagerTest, SubSetTestOpDecorate3) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpDecorate %1 Constant +OpDecorate %2 Constant +OpDecorate %2 Restrict +%u32 = OpTypeInt 32 0 +%1 = OpVariable %u32 Uniform +%2 = OpVariable %u32 Uniform +)"; + DecorationManager* decoManager = GetDecorationManager(spirv); + EXPECT_THAT(GetErrorMessage(), ""); + EXPECT_TRUE(decoManager->HaveSubsetOfDecorations(1u, 2u)); +} + +TEST_F(DecorationManagerTest, SubSetTestOpDecorate4) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpDecorate %1 Restrict +OpDecorate %2 Constant +OpDecorate %2 Restrict +OpDecorate %1 Constant +%u32 = OpTypeInt 32 0 +%1 = OpVariable %u32 Uniform +%2 = OpVariable %u32 Uniform +)"; + DecorationManager* decoManager = GetDecorationManager(spirv); + EXPECT_THAT(GetErrorMessage(), ""); + EXPECT_TRUE(decoManager->HaveSubsetOfDecorations(2u, 1u)); +} + +TEST_F(DecorationManagerTest, SubSetTestOpDecorate5) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpDecorate %1 Restrict +OpDecorate %2 Constant +OpDecorate %2 Restrict +%u32 = OpTypeInt 32 0 +%1 = OpVariable %u32 Uniform +%2 = OpVariable %u32 Uniform +)"; + DecorationManager* decoManager = GetDecorationManager(spirv); + EXPECT_THAT(GetErrorMessage(), ""); + EXPECT_FALSE(decoManager->HaveSubsetOfDecorations(2u, 1u)); +} + +TEST_F(DecorationManagerTest, SubSetTestOpDecorate6) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpDecorate %1 Constant +OpDecorate %2 Constant +OpDecorate %2 Restrict +%u32 = OpTypeInt 32 0 +%1 = OpVariable %u32 Uniform +%2 = OpVariable %u32 Uniform +)"; + DecorationManager* decoManager = GetDecorationManager(spirv); + EXPECT_THAT(GetErrorMessage(), ""); + EXPECT_FALSE(decoManager->HaveSubsetOfDecorations(2u, 1u)); +} + +TEST_F(DecorationManagerTest, SubSetTestOpDecorate7) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpDecorate %1 Constant +OpDecorate %2 Constant +OpDecorate %2 Restrict +OpDecorate %1 Invariant +%u32 = OpTypeInt 32 0 +%1 = OpVariable %u32 Uniform +%2 = OpVariable %u32 Uniform +)"; + DecorationManager* decoManager = GetDecorationManager(spirv); + EXPECT_THAT(GetErrorMessage(), ""); + EXPECT_FALSE(decoManager->HaveSubsetOfDecorations(2u, 1u)); + EXPECT_FALSE(decoManager->HaveSubsetOfDecorations(1u, 2u)); +} + +TEST_F(DecorationManagerTest, SubSetTestOpMemberDecorate1) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpMemberDecorate %1 0 Offset 0 +OpMemberDecorate %1 0 Offset 4 +OpMemberDecorate %2 0 Offset 0 +OpMemberDecorate %2 0 Offset 4 +%u32 = OpTypeInt 32 0 +%1 = OpTypeStruct %u32 %u32 %u32 +%2 = OpTypeStruct %u32 %u32 %u32 +)"; + DecorationManager* decoManager = GetDecorationManager(spirv); + EXPECT_THAT(GetErrorMessage(), ""); + EXPECT_TRUE(decoManager->HaveSubsetOfDecorations(1u, 2u)); + EXPECT_TRUE(decoManager->HaveSubsetOfDecorations(2u, 1u)); +} + +TEST_F(DecorationManagerTest, SubSetTestOpMemberDecorate2) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpMemberDecorate %1 0 Offset 0 +OpMemberDecorate %2 0 Offset 0 +OpMemberDecorate %2 0 Offset 4 +%u32 = OpTypeInt 32 0 +%1 = OpTypeStruct %u32 %u32 %u32 +%2 = OpTypeStruct %u32 %u32 %u32 +)"; + DecorationManager* decoManager = GetDecorationManager(spirv); + EXPECT_THAT(GetErrorMessage(), ""); + EXPECT_TRUE(decoManager->HaveSubsetOfDecorations(1u, 2u)); + EXPECT_FALSE(decoManager->HaveSubsetOfDecorations(2u, 1u)); +} + +TEST_F(DecorationManagerTest, SubSetTestOpDecorateId1) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpDecorateId %1 AlignmentId %2 +%u32 = OpTypeInt 32 0 +%1 = OpVariable %u32 Uniform +%3 = OpVariable %u32 Uniform +%2 = OpSpecConstant %u32 0 +)"; + DecorationManager* decoManager = GetDecorationManager(spirv); + EXPECT_THAT(GetErrorMessage(), ""); + EXPECT_FALSE(decoManager->HaveSubsetOfDecorations(1u, 3u)); + EXPECT_TRUE(decoManager->HaveSubsetOfDecorations(3u, 1u)); +} + +TEST_F(DecorationManagerTest, SubSetTestOpDecorateId2) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpDecorateId %1 AlignmentId %2 +OpDecorateId %3 AlignmentId %4 +%u32 = OpTypeInt 32 0 +%1 = OpVariable %u32 Uniform +%3 = OpVariable %u32 Uniform +%2 = OpSpecConstant %u32 0 +%4 = OpSpecConstant %u32 1 +)"; + DecorationManager* decoManager = GetDecorationManager(spirv); + EXPECT_THAT(GetErrorMessage(), ""); + EXPECT_FALSE(decoManager->HaveSubsetOfDecorations(1u, 3u)); + EXPECT_FALSE(decoManager->HaveSubsetOfDecorations(3u, 1u)); +} + +TEST_F(DecorationManagerTest, SubSetTestOpDecorateString1) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpExtension "SPV_GOOGLE_hlsl_functionality1" +OpExtension "SPV_GOOGLE_decorate_string" +OpMemoryModel Logical GLSL450 +OpDecorateString %1 HlslSemanticGOOGLE "hello" +OpDecorateString %2 HlslSemanticGOOGLE "world" +)"; + DecorationManager* decoManager = GetDecorationManager(spirv); + EXPECT_THAT(GetErrorMessage(), ""); + EXPECT_FALSE(decoManager->HaveSubsetOfDecorations(1u, 2u)); + EXPECT_FALSE(decoManager->HaveSubsetOfDecorations(2u, 1u)); +} + +TEST_F(DecorationManagerTest, SubSetTestOpDecorateString2) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpExtension "SPV_GOOGLE_hlsl_functionality1" +OpExtension "SPV_GOOGLE_decorate_string" +OpMemoryModel Logical GLSL450 +OpDecorateString %1 HlslSemanticGOOGLE "hello" +)"; + DecorationManager* decoManager = GetDecorationManager(spirv); + EXPECT_THAT(GetErrorMessage(), ""); + EXPECT_FALSE(decoManager->HaveSubsetOfDecorations(1u, 2u)); + EXPECT_TRUE(decoManager->HaveSubsetOfDecorations(2u, 1u)); +} } // namespace } // namespace analysis } // namespace opt diff --git a/third_party/spirv-tools/test/opt/def_use_test.cpp b/third_party/spirv-tools/test/opt/def_use_test.cpp index 3b856ce7fb..cfdad74a15 100644 --- a/third_party/spirv-tools/test/opt/def_use_test.cpp +++ b/third_party/spirv-tools/test/opt/def_use_test.cpp @@ -206,7 +206,7 @@ TEST_P(ParseDefUseTest, Case) { } // clang-format off -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( TestCase, ParseDefUseTest, ::testing::ValuesIn(std::vector{ {"", {{}, {}}}, // no instruction @@ -629,7 +629,7 @@ TEST_P(ReplaceUseTest, Case) { } // clang-format off -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( TestCase, ReplaceUseTest, ::testing::ValuesIn(std::vector{ { // no use, no replace request @@ -981,7 +981,7 @@ TEST_P(KillDefTest, Case) { } // clang-format off -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( TestCase, KillDefTest, ::testing::ValuesIn(std::vector{ { // no def, no use, no kill @@ -1343,7 +1343,7 @@ TEST_P(AnalyzeInstDefUseTest, Case) { } // clang-format off -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( TestCase, AnalyzeInstDefUseTest, ::testing::ValuesIn(std::vector{ { // A type declaring instruction. @@ -1464,7 +1464,7 @@ TEST_P(KillInstTest, Case) { } // clang-format off -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( TestCase, KillInstTest, ::testing::ValuesIn(std::vector{ // Kill id defining instructions. @@ -1588,7 +1588,7 @@ TEST_P(GetAnnotationsTest, Case) { } // clang-format off -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( TestCase, GetAnnotationsTest, ::testing::ValuesIn(std::vector{ // empty diff --git a/third_party/spirv-tools/test/opt/desc_sroa_test.cpp b/third_party/spirv-tools/test/opt/desc_sroa_test.cpp new file mode 100644 index 0000000000..11074c3476 --- /dev/null +++ b/third_party/spirv-tools/test/opt/desc_sroa_test.cpp @@ -0,0 +1,270 @@ +// Copyright (c) 2019 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 + +#include "gmock/gmock.h" +#include "test/opt/assembly_builder.h" +#include "test/opt/pass_fixture.h" +#include "test/opt/pass_utils.h" + +namespace spvtools { +namespace opt { +namespace { + +using DescriptorScalarReplacementTest = PassTest<::testing::Test>; + +TEST_F(DescriptorScalarReplacementTest, ExpandTexture) { + const std::string text = R"( +; CHECK: OpDecorate [[var1:%\w+]] DescriptorSet 0 +; CHECK: OpDecorate [[var1]] Binding 0 +; CHECK: OpDecorate [[var2:%\w+]] DescriptorSet 0 +; CHECK: OpDecorate [[var2]] Binding 1 +; CHECK: OpDecorate [[var3:%\w+]] DescriptorSet 0 +; CHECK: OpDecorate [[var3]] Binding 2 +; CHECK: OpDecorate [[var4:%\w+]] DescriptorSet 0 +; CHECK: OpDecorate [[var4]] Binding 3 +; CHECK: OpDecorate [[var5:%\w+]] DescriptorSet 0 +; CHECK: OpDecorate [[var5]] Binding 4 +; CHECK: [[image_type:%\w+]] = OpTypeImage +; CHECK: [[ptr_type:%\w+]] = OpTypePointer UniformConstant [[image_type]] +; CHECK: [[var1]] = OpVariable [[ptr_type]] UniformConstant +; CHECK: [[var2]] = OpVariable [[ptr_type]] UniformConstant +; CHECK: [[var3]] = OpVariable [[ptr_type]] UniformConstant +; CHECK: [[var4]] = OpVariable [[ptr_type]] UniformConstant +; CHECK: [[var5]] = OpVariable [[ptr_type]] UniformConstant +; CHECK: OpLoad [[image_type]] [[var1]] +; CHECK: OpLoad [[image_type]] [[var2]] +; CHECK: OpLoad [[image_type]] [[var3]] +; CHECK: OpLoad [[image_type]] [[var4]] +; CHECK: OpLoad [[image_type]] [[var5]] + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" + OpExecutionMode %main OriginUpperLeft + OpSource HLSL 600 + OpDecorate %MyTextures DescriptorSet 0 + OpDecorate %MyTextures Binding 0 + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 + %int_1 = OpConstant %int 1 + %int_2 = OpConstant %int 2 + %int_3 = OpConstant %int 3 + %int_4 = OpConstant %int 4 + %uint = OpTypeInt 32 0 + %uint_5 = OpConstant %uint 5 + %float = OpTypeFloat 32 +%type_2d_image = OpTypeImage %float 2D 2 0 0 1 Unknown +%_arr_type_2d_image_uint_5 = OpTypeArray %type_2d_image %uint_5 +%_ptr_UniformConstant__arr_type_2d_image_uint_5 = OpTypePointer UniformConstant %_arr_type_2d_image_uint_5 + %v2float = OpTypeVector %float 2 + %void = OpTypeVoid + %26 = OpTypeFunction %void +%_ptr_UniformConstant_type_2d_image = OpTypePointer UniformConstant %type_2d_image + %MyTextures = OpVariable %_ptr_UniformConstant__arr_type_2d_image_uint_5 UniformConstant + %main = OpFunction %void None %26 + %28 = OpLabel + %29 = OpUndef %v2float + %30 = OpAccessChain %_ptr_UniformConstant_type_2d_image %MyTextures %int_0 + %31 = OpLoad %type_2d_image %30 + %35 = OpAccessChain %_ptr_UniformConstant_type_2d_image %MyTextures %int_1 + %36 = OpLoad %type_2d_image %35 + %40 = OpAccessChain %_ptr_UniformConstant_type_2d_image %MyTextures %int_2 + %41 = OpLoad %type_2d_image %40 + %45 = OpAccessChain %_ptr_UniformConstant_type_2d_image %MyTextures %int_3 + %46 = OpLoad %type_2d_image %45 + %50 = OpAccessChain %_ptr_UniformConstant_type_2d_image %MyTextures %int_4 + %51 = OpLoad %type_2d_image %50 + OpReturn + OpFunctionEnd + + )"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(DescriptorScalarReplacementTest, ExpandSampler) { + const std::string text = R"( +; CHECK: OpDecorate [[var1:%\w+]] DescriptorSet 0 +; CHECK: OpDecorate [[var1]] Binding 1 +; CHECK: OpDecorate [[var2:%\w+]] DescriptorSet 0 +; CHECK: OpDecorate [[var2]] Binding 2 +; CHECK: OpDecorate [[var3:%\w+]] DescriptorSet 0 +; CHECK: OpDecorate [[var3]] Binding 3 +; CHECK: [[sampler_type:%\w+]] = OpTypeSampler +; CHECK: [[ptr_type:%\w+]] = OpTypePointer UniformConstant [[sampler_type]] +; CHECK: [[var1]] = OpVariable [[ptr_type]] UniformConstant +; CHECK: [[var2]] = OpVariable [[ptr_type]] UniformConstant +; CHECK: [[var3]] = OpVariable [[ptr_type]] UniformConstant +; CHECK: OpLoad [[sampler_type]] [[var1]] +; CHECK: OpLoad [[sampler_type]] [[var2]] +; CHECK: OpLoad [[sampler_type]] [[var3]] + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" + OpExecutionMode %main OriginUpperLeft + OpSource HLSL 600 + OpDecorate %MySampler DescriptorSet 0 + OpDecorate %MySampler Binding 1 + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 + %int_1 = OpConstant %int 1 + %int_2 = OpConstant %int 2 + %uint = OpTypeInt 32 0 + %uint_3 = OpConstant %uint 3 +%type_sampler = OpTypeSampler +%_arr_type_sampler_uint_3 = OpTypeArray %type_sampler %uint_3 +%_ptr_UniformConstant__arr_type_sampler_uint_3 = OpTypePointer UniformConstant %_arr_type_sampler_uint_3 + %void = OpTypeVoid + %26 = OpTypeFunction %void +%_ptr_UniformConstant_type_sampler = OpTypePointer UniformConstant %type_sampler + %MySampler = OpVariable %_ptr_UniformConstant__arr_type_sampler_uint_3 UniformConstant + %main = OpFunction %void None %26 + %28 = OpLabel + %31 = OpAccessChain %_ptr_UniformConstant_type_sampler %MySampler %int_0 + %32 = OpLoad %type_sampler %31 + %35 = OpAccessChain %_ptr_UniformConstant_type_sampler %MySampler %int_1 + %36 = OpLoad %type_sampler %35 + %40 = OpAccessChain %_ptr_UniformConstant_type_sampler %MySampler %int_2 + %41 = OpLoad %type_sampler %40 + OpReturn + OpFunctionEnd + )"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(DescriptorScalarReplacementTest, ExpandSSBO) { + // Tests the expansion of an SSBO. Also check that an access chain with more + // than 1 index is correctly handled. + const std::string text = R"( +; CHECK: OpDecorate [[var1:%\w+]] DescriptorSet 0 +; CHECK: OpDecorate [[var1]] Binding 0 +; CHECK: OpDecorate [[var2:%\w+]] DescriptorSet 0 +; CHECK: OpDecorate [[var2]] Binding 1 +; CHECK: OpTypeStruct +; CHECK: [[struct_type:%\w+]] = OpTypeStruct +; CHECK: [[ptr_type:%\w+]] = OpTypePointer Uniform [[struct_type]] +; CHECK: [[var1]] = OpVariable [[ptr_type]] Uniform +; CHECK: [[var2]] = OpVariable [[ptr_type]] Uniform +; CHECK: [[ac1:%\w+]] = OpAccessChain %_ptr_Uniform_v4float [[var1]] %uint_0 %uint_0 %uint_0 +; CHECK: OpLoad %v4float [[ac1]] +; CHECK: [[ac2:%\w+]] = OpAccessChain %_ptr_Uniform_v4float [[var2]] %uint_0 %uint_0 %uint_0 +; CHECK: OpLoad %v4float [[ac2]] + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" + OpExecutionMode %main OriginUpperLeft + OpSource HLSL 600 + OpDecorate %buffers DescriptorSet 0 + OpDecorate %buffers Binding 0 + OpMemberDecorate %S 0 Offset 0 + OpDecorate %_runtimearr_S ArrayStride 16 + OpMemberDecorate %type_StructuredBuffer_S 0 Offset 0 + OpMemberDecorate %type_StructuredBuffer_S 0 NonWritable + OpDecorate %type_StructuredBuffer_S BufferBlock + %uint = OpTypeInt 32 0 + %uint_0 = OpConstant %uint 0 + %uint_1 = OpConstant %uint 1 + %uint_2 = OpConstant %uint 2 + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 + %S = OpTypeStruct %v4float +%_runtimearr_S = OpTypeRuntimeArray %S +%type_StructuredBuffer_S = OpTypeStruct %_runtimearr_S +%_arr_type_StructuredBuffer_S_uint_2 = OpTypeArray %type_StructuredBuffer_S %uint_2 +%_ptr_Uniform__arr_type_StructuredBuffer_S_uint_2 = OpTypePointer Uniform %_arr_type_StructuredBuffer_S_uint_2 +%_ptr_Uniform_type_StructuredBuffer_S = OpTypePointer Uniform %type_StructuredBuffer_S + %void = OpTypeVoid + %19 = OpTypeFunction %void +%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float + %buffers = OpVariable %_ptr_Uniform__arr_type_StructuredBuffer_S_uint_2 Uniform + %main = OpFunction %void None %19 + %21 = OpLabel + %22 = OpAccessChain %_ptr_Uniform_v4float %buffers %uint_0 %uint_0 %uint_0 %uint_0 + %23 = OpLoad %v4float %22 + %24 = OpAccessChain %_ptr_Uniform_type_StructuredBuffer_S %buffers %uint_1 + %25 = OpAccessChain %_ptr_Uniform_v4float %24 %uint_0 %uint_0 %uint_0 + %26 = OpLoad %v4float %25 + OpReturn + OpFunctionEnd + )"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(DescriptorScalarReplacementTest, NameNewVariables) { + // Checks that if the original variable has a name, then the new variables + // will have a name derived from that name. + const std::string text = R"( +; CHECK: OpName [[var1:%\w+]] "SSBO[0]" +; CHECK: OpName [[var2:%\w+]] "SSBO[1]" +; CHECK: OpDecorate [[var1]] DescriptorSet 0 +; CHECK: OpDecorate [[var1]] Binding 0 +; CHECK: OpDecorate [[var2]] DescriptorSet 0 +; CHECK: OpDecorate [[var2]] Binding 1 +; CHECK: OpTypeStruct +; CHECK: [[struct_type:%\w+]] = OpTypeStruct +; CHECK: [[ptr_type:%\w+]] = OpTypePointer Uniform [[struct_type]] +; CHECK: [[var1]] = OpVariable [[ptr_type]] Uniform +; CHECK: [[var2]] = OpVariable [[ptr_type]] Uniform +; CHECK: [[ac1:%\w+]] = OpAccessChain %_ptr_Uniform_v4float [[var1]] %uint_0 %uint_0 %uint_0 +; CHECK: OpLoad %v4float [[ac1]] +; CHECK: [[ac2:%\w+]] = OpAccessChain %_ptr_Uniform_v4float [[var2]] %uint_0 %uint_0 %uint_0 +; CHECK: OpLoad %v4float [[ac2]] + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" + OpExecutionMode %main OriginUpperLeft + OpSource HLSL 600 + OpName %buffers "SSBO" + OpDecorate %buffers DescriptorSet 0 + OpDecorate %buffers Binding 0 + OpMemberDecorate %S 0 Offset 0 + OpDecorate %_runtimearr_S ArrayStride 16 + OpMemberDecorate %type_StructuredBuffer_S 0 Offset 0 + OpMemberDecorate %type_StructuredBuffer_S 0 NonWritable + OpDecorate %type_StructuredBuffer_S BufferBlock + %uint = OpTypeInt 32 0 + %uint_0 = OpConstant %uint 0 + %uint_1 = OpConstant %uint 1 + %uint_2 = OpConstant %uint 2 + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 + %S = OpTypeStruct %v4float +%_runtimearr_S = OpTypeRuntimeArray %S +%type_StructuredBuffer_S = OpTypeStruct %_runtimearr_S +%_arr_type_StructuredBuffer_S_uint_2 = OpTypeArray %type_StructuredBuffer_S %uint_2 +%_ptr_Uniform__arr_type_StructuredBuffer_S_uint_2 = OpTypePointer Uniform %_arr_type_StructuredBuffer_S_uint_2 +%_ptr_Uniform_type_StructuredBuffer_S = OpTypePointer Uniform %type_StructuredBuffer_S + %void = OpTypeVoid + %19 = OpTypeFunction %void +%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float + %buffers = OpVariable %_ptr_Uniform__arr_type_StructuredBuffer_S_uint_2 Uniform + %main = OpFunction %void None %19 + %21 = OpLabel + %22 = OpAccessChain %_ptr_Uniform_v4float %buffers %uint_0 %uint_0 %uint_0 %uint_0 + %23 = OpLoad %v4float %22 + %24 = OpAccessChain %_ptr_Uniform_type_StructuredBuffer_S %buffers %uint_1 + %25 = OpAccessChain %_ptr_Uniform_v4float %24 %uint_0 %uint_0 %uint_0 + %26 = OpLoad %v4float %25 + OpReturn + OpFunctionEnd + )"; + + SinglePassRunAndMatch(text, true); +} +} // namespace +} // namespace opt +} // namespace spvtools diff --git a/third_party/spirv-tools/test/opt/dominator_tree/CMakeLists.txt b/third_party/spirv-tools/test/opt/dominator_tree/CMakeLists.txt index f95a56da87..813d628a0d 100644 --- a/third_party/spirv-tools/test/opt/dominator_tree/CMakeLists.txt +++ b/third_party/spirv-tools/test/opt/dominator_tree/CMakeLists.txt @@ -27,4 +27,5 @@ add_spvtools_unittest(TARGET dominator_analysis unreachable_for.cpp unreachable_for_post.cpp LIBS SPIRV-Tools-opt + PCH_FILE pch_test_opt_dom ) diff --git a/third_party/spirv-tools/test/opt/dominator_tree/pch_test_opt_dom.cpp b/third_party/spirv-tools/test/opt/dominator_tree/pch_test_opt_dom.cpp new file mode 100644 index 0000000000..a28310e571 --- /dev/null +++ b/third_party/spirv-tools/test/opt/dominator_tree/pch_test_opt_dom.cpp @@ -0,0 +1,15 @@ +// Copyright (c) 2018 The Khronos Group Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "pch_test_opt_dom.h" diff --git a/third_party/spirv-tools/test/opt/dominator_tree/pch_test_opt_dom.h b/third_party/spirv-tools/test/opt/dominator_tree/pch_test_opt_dom.h new file mode 100644 index 0000000000..4e8106fbfc --- /dev/null +++ b/third_party/spirv-tools/test/opt/dominator_tree/pch_test_opt_dom.h @@ -0,0 +1,25 @@ +// Copyright (c) 2018 The Khronos Group Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "gmock/gmock.h" +#include "source/opt/iterator.h" +#include "source/opt/loop_dependence.h" +#include "source/opt/loop_descriptor.h" +#include "source/opt/pass.h" +#include "source/opt/scalar_analysis.h" +#include "source/opt/tree_iterator.h" +#include "test/opt/assembly_builder.h" +#include "test/opt/function_utils.h" +#include "test/opt/pass_fixture.h" +#include "test/opt/pass_utils.h" diff --git a/third_party/spirv-tools/test/opt/eliminate_dead_const_test.cpp b/third_party/spirv-tools/test/opt/eliminate_dead_const_test.cpp index 7fac866cec..59f06f9f25 100644 --- a/third_party/spirv-tools/test/opt/eliminate_dead_const_test.cpp +++ b/third_party/spirv-tools/test/opt/eliminate_dead_const_test.cpp @@ -197,7 +197,7 @@ TEST_P(EliminateDeadConstantTest, Custom) { assembly_with_dead_const, expected, /* skip_nop = */ true); } -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( ScalarTypeConstants, EliminateDeadConstantTest, ::testing::ValuesIn(std::vector({ // clang-format off @@ -265,7 +265,7 @@ INSTANTIATE_TEST_CASE_P( // clang-format on }))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( VectorTypeConstants, EliminateDeadConstantTest, ::testing::ValuesIn(std::vector({ // clang-format off @@ -358,7 +358,7 @@ INSTANTIATE_TEST_CASE_P( // clang-format on }))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( StructTypeConstants, EliminateDeadConstantTest, ::testing::ValuesIn(std::vector({ // clang-format off @@ -485,7 +485,7 @@ INSTANTIATE_TEST_CASE_P( // clang-format on }))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( ScalarTypeSpecConstants, EliminateDeadConstantTest, ::testing::ValuesIn(std::vector({ // clang-format off @@ -522,7 +522,7 @@ INSTANTIATE_TEST_CASE_P( // clang-format on }))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( VectorTypeSpecConstants, EliminateDeadConstantTest, ::testing::ValuesIn(std::vector({ // clang-format off @@ -617,7 +617,7 @@ INSTANTIATE_TEST_CASE_P( // clang-format on }))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SpecConstantOp, EliminateDeadConstantTest, ::testing::ValuesIn(std::vector({ // clang-format off @@ -768,7 +768,7 @@ INSTANTIATE_TEST_CASE_P( // clang-format on }))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( LongDefUseChain, EliminateDeadConstantTest, ::testing::ValuesIn(std::vector({ // clang-format off diff --git a/third_party/spirv-tools/test/opt/eliminate_dead_member_test.cpp b/third_party/spirv-tools/test/opt/eliminate_dead_member_test.cpp new file mode 100644 index 0000000000..b6925d7d78 --- /dev/null +++ b/third_party/spirv-tools/test/opt/eliminate_dead_member_test.cpp @@ -0,0 +1,1088 @@ +// Copyright (c) 2019 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 "assembly_builder.h" +#include "gmock/gmock.h" +#include "pass_fixture.h" +#include "pass_utils.h" + +namespace { + +using namespace spvtools; + +using EliminateDeadMemberTest = opt::PassTest<::testing::Test>; + +TEST_F(EliminateDeadMemberTest, RemoveMember1) { + // Test that the member "y" is removed. + // Update OpMemberName for |y| and |z|. + // Update OpMemberDecorate for |y| and |z|. + // Update OpAccessChain for access to |z|. + const std::string text = R"( +; CHECK: OpName +; CHECK-NEXT: OpMemberName %type__Globals 0 "x" +; CHECK-NEXT: OpMemberName %type__Globals 1 "z" +; CHECK-NOT: OpMemberName +; CHECK: OpMemberDecorate %type__Globals 0 Offset 0 +; CHECK: OpMemberDecorate %type__Globals 1 Offset 8 +; CHECK: %type__Globals = OpTypeStruct %float %float +; CHECK: OpAccessChain %_ptr_Uniform_float %_Globals %int_0 +; CHECK: OpAccessChain %_ptr_Uniform_float %_Globals %uint_1 + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %main "main" %in_var_Position %gl_Position + OpSource HLSL 600 + OpName %type__Globals "type.$Globals" + OpMemberName %type__Globals 0 "x" + OpMemberName %type__Globals 1 "y" + OpMemberName %type__Globals 2 "z" + OpName %_Globals "$Globals" + OpName %in_var_Position "in.var.Position" + OpName %main "main" + OpDecorate %gl_Position BuiltIn Position + OpDecorate %in_var_Position Location 0 + OpDecorate %_Globals DescriptorSet 0 + OpDecorate %_Globals Binding 0 + OpMemberDecorate %type__Globals 0 Offset 0 + OpMemberDecorate %type__Globals 1 Offset 4 + OpMemberDecorate %type__Globals 2 Offset 8 + OpDecorate %type__Globals Block + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 + %float = OpTypeFloat 32 + %int_2 = OpConstant %int 2 +%type__Globals = OpTypeStruct %float %float %float +%_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals + %v4float = OpTypeVector %float 4 +%_ptr_Input_v4float = OpTypePointer Input %v4float +%_ptr_Output_v4float = OpTypePointer Output %v4float + %void = OpTypeVoid + %15 = OpTypeFunction %void +%_ptr_Uniform_float = OpTypePointer Uniform %float + %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform +%in_var_Position = OpVariable %_ptr_Input_v4float Input +%gl_Position = OpVariable %_ptr_Output_v4float Output + %main = OpFunction %void None %15 + %17 = OpLabel + %18 = OpLoad %v4float %in_var_Position + %19 = OpAccessChain %_ptr_Uniform_float %_Globals %int_0 + %20 = OpLoad %float %19 + %21 = OpCompositeExtract %float %18 0 + %22 = OpFAdd %float %21 %20 + %23 = OpCompositeInsert %v4float %22 %18 0 + %24 = OpCompositeExtract %float %18 1 + %25 = OpCompositeInsert %v4float %24 %23 1 + %26 = OpAccessChain %_ptr_Uniform_float %_Globals %int_2 + %27 = OpLoad %float %26 + %28 = OpCompositeExtract %float %18 2 + %29 = OpFAdd %float %28 %27 + %30 = OpCompositeInsert %v4float %29 %25 2 + OpStore %gl_Position %30 + OpReturn + OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(EliminateDeadMemberTest, RemoveMemberWithGroupDecorations) { + // Test that the member "y" is removed. + // Update OpGroupMemberDecorate for %type__Globals member 1 and 2. + // Update OpAccessChain for access to %type__Globals member 2. + const std::string text = R"( +; CHECK: OpDecorate [[gr1:%\w+]] Offset 0 +; CHECK: OpDecorate [[gr2:%\w+]] Offset 4 +; CHECK: OpDecorate [[gr3:%\w+]] Offset 8 +; CHECK: [[gr1]] = OpDecorationGroup +; CHECK: [[gr2]] = OpDecorationGroup +; CHECK: [[gr3]] = OpDecorationGroup +; CHECK: OpGroupMemberDecorate [[gr1]] %type__Globals 0 +; CHECK-NOT: OpGroupMemberDecorate [[gr2]] +; CHECK: OpGroupMemberDecorate [[gr3]] %type__Globals 1 +; CHECK: %type__Globals = OpTypeStruct %float %float +; CHECK: OpAccessChain %_ptr_Uniform_float %_Globals %int_0 +; CHECK: OpAccessChain %_ptr_Uniform_float %_Globals %uint_1 + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %main "main" %in_var_Position %gl_Position + OpSource HLSL 600 + OpName %type__Globals "type.$Globals" + OpName %_Globals "$Globals" + OpDecorate %gl_Position BuiltIn Position + OpDecorate %in_var_Position Location 0 + OpDecorate %_Globals DescriptorSet 0 + OpDecorate %_Globals Binding 0 + OpDecorate %gr1 Offset 0 + OpDecorate %gr2 Offset 4 + OpDecorate %gr3 Offset 8 + OpDecorate %type__Globals Block + %gr1 = OpDecorationGroup + %gr2 = OpDecorationGroup + %gr3 = OpDecorationGroup + OpGroupMemberDecorate %gr1 %type__Globals 0 + OpGroupMemberDecorate %gr2 %type__Globals 1 + OpGroupMemberDecorate %gr3 %type__Globals 2 + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 + %float = OpTypeFloat 32 + %int_2 = OpConstant %int 2 +%type__Globals = OpTypeStruct %float %float %float +%_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals + %v4float = OpTypeVector %float 4 +%_ptr_Input_v4float = OpTypePointer Input %v4float +%_ptr_Output_v4float = OpTypePointer Output %v4float + %void = OpTypeVoid + %15 = OpTypeFunction %void +%_ptr_Uniform_float = OpTypePointer Uniform %float + %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform +%in_var_Position = OpVariable %_ptr_Input_v4float Input +%gl_Position = OpVariable %_ptr_Output_v4float Output + %main = OpFunction %void None %15 + %17 = OpLabel + %18 = OpLoad %v4float %in_var_Position + %19 = OpAccessChain %_ptr_Uniform_float %_Globals %int_0 + %20 = OpLoad %float %19 + %21 = OpCompositeExtract %float %18 0 + %22 = OpFAdd %float %21 %20 + %23 = OpCompositeInsert %v4float %22 %18 0 + %24 = OpCompositeExtract %float %18 1 + %25 = OpCompositeInsert %v4float %24 %23 1 + %26 = OpAccessChain %_ptr_Uniform_float %_Globals %int_2 + %27 = OpLoad %float %26 + %28 = OpCompositeExtract %float %18 2 + %29 = OpFAdd %float %28 %27 + %30 = OpCompositeInsert %v4float %29 %25 2 + OpStore %gl_Position %30 + OpReturn + OpFunctionEnd +)"; + + // Skipping validation because of a bug in the validator. See issue #2376. + SinglePassRunAndMatch(text, false); +} + +TEST_F(EliminateDeadMemberTest, RemoveMemberUpdateConstant) { + // Test that the member "x" is removed. + // Update the OpConstantComposite instruction. + const std::string text = R"( +; CHECK: OpName +; CHECK-NEXT: OpMemberName %type__Globals 0 "y" +; CHECK-NEXT: OpMemberName %type__Globals 1 "z" +; CHECK-NOT: OpMemberName +; CHECK: OpMemberDecorate %type__Globals 0 Offset 4 +; CHECK: OpMemberDecorate %type__Globals 1 Offset 8 +; CHECK: %type__Globals = OpTypeStruct %float %float +; CHECK: OpConstantComposite %type__Globals %float_1 %float_2 +; CHECK: OpAccessChain %_ptr_Uniform_float %_Globals %uint_0 +; CHECK: OpAccessChain %_ptr_Uniform_float %_Globals %uint_1 + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %main "main" %in_var_Position %gl_Position + OpSource HLSL 600 + OpName %type__Globals "type.$Globals" + OpMemberName %type__Globals 0 "x" + OpMemberName %type__Globals 1 "y" + OpMemberName %type__Globals 2 "z" + OpName %_Globals "$Globals" + OpName %in_var_Position "in.var.Position" + OpName %main "main" + OpDecorate %gl_Position BuiltIn Position + OpDecorate %in_var_Position Location 0 + OpDecorate %_Globals DescriptorSet 0 + OpDecorate %_Globals Binding 0 + OpMemberDecorate %type__Globals 0 Offset 0 + OpMemberDecorate %type__Globals 1 Offset 4 + OpMemberDecorate %type__Globals 2 Offset 8 + OpDecorate %type__Globals Block + %int = OpTypeInt 32 1 + %int_1 = OpConstant %int 1 + %float = OpTypeFloat 32 + %float_0 = OpConstant %float 0 + %float_1 = OpConstant %float 1 + %float_2 = OpConstant %float 2 + %int_2 = OpConstant %int 2 +%type__Globals = OpTypeStruct %float %float %float + %13 = OpConstantComposite %type__Globals %float_0 %float_1 %float_2 +%_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals + %v4float = OpTypeVector %float 4 +%_ptr_Input_v4float = OpTypePointer Input %v4float +%_ptr_Output_v4float = OpTypePointer Output %v4float + %void = OpTypeVoid + %19 = OpTypeFunction %void +%_ptr_Uniform_float = OpTypePointer Uniform %float + %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform +%in_var_Position = OpVariable %_ptr_Input_v4float Input +%gl_Position = OpVariable %_ptr_Output_v4float Output + %main = OpFunction %void None %19 + %21 = OpLabel + %22 = OpLoad %v4float %in_var_Position + %23 = OpAccessChain %_ptr_Uniform_float %_Globals %int_1 + %24 = OpLoad %float %23 + %25 = OpCompositeExtract %float %22 0 + %26 = OpFAdd %float %25 %24 + %27 = OpCompositeInsert %v4float %26 %22 0 + %28 = OpCompositeExtract %float %22 1 + %29 = OpCompositeInsert %v4float %28 %27 1 + %30 = OpAccessChain %_ptr_Uniform_float %_Globals %int_2 + %31 = OpLoad %float %30 + %32 = OpCompositeExtract %float %22 2 + %33 = OpFAdd %float %32 %31 + %34 = OpCompositeInsert %v4float %33 %29 2 + OpStore %gl_Position %34 + OpReturn + OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(EliminateDeadMemberTest, RemoveMemberUpdateCompositeConstruct) { + // Test that the member "x" is removed. + // Update the OpConstantComposite instruction. + const std::string text = R"( +; CHECK: OpName +; CHECK-NEXT: OpMemberName %type__Globals 0 "y" +; CHECK-NEXT: OpMemberName %type__Globals 1 "z" +; CHECK-NOT: OpMemberName +; CHECK: OpMemberDecorate %type__Globals 0 Offset 4 +; CHECK: OpMemberDecorate %type__Globals 1 Offset 8 +; CHECK: %type__Globals = OpTypeStruct %float %float +; CHECK: OpCompositeConstruct %type__Globals %float_1 %float_2 +; CHECK: OpAccessChain %_ptr_Uniform_float %_Globals %uint_0 +; CHECK: OpAccessChain %_ptr_Uniform_float %_Globals %uint_1 + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %main "main" %in_var_Position %gl_Position + OpSource HLSL 600 + OpName %type__Globals "type.$Globals" + OpMemberName %type__Globals 0 "x" + OpMemberName %type__Globals 1 "y" + OpMemberName %type__Globals 2 "z" + OpName %_Globals "$Globals" + OpName %in_var_Position "in.var.Position" + OpName %main "main" + OpDecorate %gl_Position BuiltIn Position + OpDecorate %in_var_Position Location 0 + OpDecorate %_Globals DescriptorSet 0 + OpDecorate %_Globals Binding 0 + OpMemberDecorate %type__Globals 0 Offset 0 + OpMemberDecorate %type__Globals 1 Offset 4 + OpMemberDecorate %type__Globals 2 Offset 8 + OpDecorate %type__Globals Block + %int = OpTypeInt 32 1 + %int_1 = OpConstant %int 1 + %float = OpTypeFloat 32 + %float_0 = OpConstant %float 0 + %float_1 = OpConstant %float 1 + %float_2 = OpConstant %float 2 + %int_2 = OpConstant %int 2 +%type__Globals = OpTypeStruct %float %float %float +%_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals + %v4float = OpTypeVector %float 4 +%_ptr_Input_v4float = OpTypePointer Input %v4float +%_ptr_Output_v4float = OpTypePointer Output %v4float + %void = OpTypeVoid + %19 = OpTypeFunction %void +%_ptr_Uniform_float = OpTypePointer Uniform %float + %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform +%in_var_Position = OpVariable %_ptr_Input_v4float Input +%gl_Position = OpVariable %_ptr_Output_v4float Output + %main = OpFunction %void None %19 + %21 = OpLabel + %13 = OpCompositeConstruct %type__Globals %float_0 %float_1 %float_2 + %22 = OpLoad %v4float %in_var_Position + %23 = OpAccessChain %_ptr_Uniform_float %_Globals %int_1 + %24 = OpLoad %float %23 + %25 = OpCompositeExtract %float %22 0 + %26 = OpFAdd %float %25 %24 + %27 = OpCompositeInsert %v4float %26 %22 0 + %28 = OpCompositeExtract %float %22 1 + %29 = OpCompositeInsert %v4float %28 %27 1 + %30 = OpAccessChain %_ptr_Uniform_float %_Globals %int_2 + %31 = OpLoad %float %30 + %32 = OpCompositeExtract %float %22 2 + %33 = OpFAdd %float %32 %31 + %34 = OpCompositeInsert %v4float %33 %29 2 + OpStore %gl_Position %34 + OpReturn + OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(EliminateDeadMemberTest, RemoveMembersUpdateInserExtract1) { + // Test that the members "x" and "z" are removed. + // Update the OpCompositeExtract instruction. + // Remove the OpCompositeInsert instruction since the member being inserted is + // dead. + const std::string text = R"( +; CHECK: OpName +; CHECK-NEXT: OpMemberName %type__Globals 0 "y" +; CHECK-NOT: OpMemberName +; CHECK: OpMemberDecorate %type__Globals 0 Offset 4 +; CHECK-NOT: OpMemberDecorate %type__Globals 1 Offset +; CHECK: %type__Globals = OpTypeStruct %float +; CHECK: [[ld:%\w+]] = OpLoad %type__Globals %_Globals +; CHECK: OpCompositeExtract %float [[ld]] 0 +; CHECK-NOT: OpCompositeInsert +; CHECK: OpReturn + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %main "main" + OpSource HLSL 600 + OpName %type__Globals "type.$Globals" + OpMemberName %type__Globals 0 "x" + OpMemberName %type__Globals 1 "y" + OpMemberName %type__Globals 2 "z" + OpName %_Globals "$Globals" + OpName %main "main" + OpDecorate %_Globals DescriptorSet 0 + OpDecorate %_Globals Binding 0 + OpMemberDecorate %type__Globals 0 Offset 0 + OpMemberDecorate %type__Globals 1 Offset 4 + OpMemberDecorate %type__Globals 2 Offset 8 + OpDecorate %type__Globals Block + %float = OpTypeFloat 32 +%type__Globals = OpTypeStruct %float %float %float +%_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals + %void = OpTypeVoid + %7 = OpTypeFunction %void + %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform + %main = OpFunction %void None %7 + %8 = OpLabel + %9 = OpLoad %type__Globals %_Globals + %10 = OpCompositeExtract %float %9 1 + %11 = OpCompositeInsert %type__Globals %10 %9 2 + OpReturn + OpFunctionEnd + +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(EliminateDeadMemberTest, RemoveMembersUpdateInserExtract2) { + // Test that the members "x" and "z" are removed. + // Update the OpCompositeExtract instruction. + // Update the OpCompositeInsert instruction. + const std::string text = R"( +; CHECK: OpName +; CHECK-NEXT: OpMemberName %type__Globals 0 "y" +; CHECK-NOT: OpMemberName +; CHECK: OpMemberDecorate %type__Globals 0 Offset 4 +; CHECK-NOT: OpMemberDecorate %type__Globals 1 Offset +; CHECK: %type__Globals = OpTypeStruct %float +; CHECK: [[ld:%\w+]] = OpLoad %type__Globals %_Globals +; CHECK: [[ex:%\w+]] = OpCompositeExtract %float [[ld]] 0 +; CHECK: OpCompositeInsert %type__Globals [[ex]] [[ld]] 0 +; CHECK: OpReturn + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %main "main" + OpSource HLSL 600 + OpName %type__Globals "type.$Globals" + OpMemberName %type__Globals 0 "x" + OpMemberName %type__Globals 1 "y" + OpMemberName %type__Globals 2 "z" + OpName %_Globals "$Globals" + OpName %main "main" + OpDecorate %_Globals DescriptorSet 0 + OpDecorate %_Globals Binding 0 + OpMemberDecorate %type__Globals 0 Offset 0 + OpMemberDecorate %type__Globals 1 Offset 4 + OpMemberDecorate %type__Globals 2 Offset 8 + OpDecorate %type__Globals Block + %float = OpTypeFloat 32 +%type__Globals = OpTypeStruct %float %float %float +%_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals + %void = OpTypeVoid + %7 = OpTypeFunction %void + %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform + %main = OpFunction %void None %7 + %8 = OpLabel + %9 = OpLoad %type__Globals %_Globals + %10 = OpCompositeExtract %float %9 1 + %11 = OpCompositeInsert %type__Globals %10 %9 1 + OpReturn + OpFunctionEnd + +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(EliminateDeadMemberTest, RemoveMembersUpdateInserExtract3) { + // Test that the members "x" and "z" are removed, and one member from the + // substruct. Update the OpCompositeExtract instruction. Update the + // OpCompositeInsert instruction. + const std::string text = R"( +; CHECK: OpName +; CHECK-NEXT: OpMemberName %type__Globals 0 "y" +; CHECK-NOT: OpMemberName +; CHECK: OpMemberDecorate %type__Globals 0 Offset 16 +; CHECK-NOT: OpMemberDecorate %type__Globals 1 Offset +; CHECK: OpMemberDecorate [[struct:%\w+]] 0 Offset 4 +; CHECK: [[struct:%\w+]] = OpTypeStruct %float +; CHECK: %type__Globals = OpTypeStruct [[struct]] +; CHECK: [[ld:%\w+]] = OpLoad %type__Globals %_Globals +; CHECK: [[ex:%\w+]] = OpCompositeExtract %float [[ld]] 0 0 +; CHECK: OpCompositeInsert %type__Globals [[ex]] [[ld]] 0 0 +; CHECK: OpReturn + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %main "main" + OpSource HLSL 600 + OpName %type__Globals "type.$Globals" + OpMemberName %type__Globals 0 "x" + OpMemberName %type__Globals 1 "y" + OpMemberName %type__Globals 2 "z" + OpName %_Globals "$Globals" + OpName %main "main" + OpDecorate %_Globals DescriptorSet 0 + OpDecorate %_Globals Binding 0 + OpMemberDecorate %type__Globals 0 Offset 0 + OpMemberDecorate %type__Globals 1 Offset 16 + OpMemberDecorate %type__Globals 2 Offset 24 + OpMemberDecorate %_struct_6 0 Offset 0 + OpMemberDecorate %_struct_6 1 Offset 4 + OpDecorate %type__Globals Block + %float = OpTypeFloat 32 + %_struct_6 = OpTypeStruct %float %float +%type__Globals = OpTypeStruct %float %_struct_6 %float +%_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals + %void = OpTypeVoid + %7 = OpTypeFunction %void + %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform + %main = OpFunction %void None %7 + %8 = OpLabel + %9 = OpLoad %type__Globals %_Globals + %10 = OpCompositeExtract %float %9 1 1 + %11 = OpCompositeInsert %type__Globals %10 %9 1 1 + OpReturn + OpFunctionEnd + +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(EliminateDeadMemberTest, RemoveMembersUpdateInserExtract4) { + // Test that the members "x" and "z" are removed, and one member from the + // substruct. Update the OpCompositeExtract instruction. Update the + // OpCompositeInsert instruction. + const std::string text = R"( +; CHECK: OpName +; CHECK-NEXT: OpMemberName %type__Globals 0 "y" +; CHECK-NOT: OpMemberName +; CHECK: OpMemberDecorate %type__Globals 0 Offset 16 +; CHECK-NOT: OpMemberDecorate %type__Globals 1 Offset +; CHECK: OpMemberDecorate [[struct:%\w+]] 0 Offset 4 +; CHECK: [[struct:%\w+]] = OpTypeStruct %float +; CHECK: [[array:%\w+]] = OpTypeArray [[struct]] +; CHECK: %type__Globals = OpTypeStruct [[array]] +; CHECK: [[ld:%\w+]] = OpLoad %type__Globals %_Globals +; CHECK: [[ex:%\w+]] = OpCompositeExtract %float [[ld]] 0 1 0 +; CHECK: OpCompositeInsert %type__Globals [[ex]] [[ld]] 0 1 0 +; CHECK: OpReturn + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %main "main" + OpSource HLSL 600 + OpName %type__Globals "type.$Globals" + OpMemberName %type__Globals 0 "x" + OpMemberName %type__Globals 1 "y" + OpMemberName %type__Globals 2 "z" + OpName %_Globals "$Globals" + OpName %main "main" + OpDecorate %_Globals DescriptorSet 0 + OpDecorate %_Globals Binding 0 + OpMemberDecorate %type__Globals 0 Offset 0 + OpMemberDecorate %type__Globals 1 Offset 16 + OpMemberDecorate %type__Globals 2 Offset 80 + OpMemberDecorate %_struct_6 0 Offset 0 + OpMemberDecorate %_struct_6 1 Offset 4 + OpDecorate %array ArrayStride 16 + OpDecorate %type__Globals Block + %uint = OpTypeInt 32 0 ; 32-bit int, sign-less + %uint_4 = OpConstant %uint 4 + %float = OpTypeFloat 32 + %_struct_6 = OpTypeStruct %float %float + %array = OpTypeArray %_struct_6 %uint_4 +%type__Globals = OpTypeStruct %float %array %float +%_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals + %void = OpTypeVoid + %7 = OpTypeFunction %void + %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform + %main = OpFunction %void None %7 + %8 = OpLabel + %9 = OpLoad %type__Globals %_Globals + %10 = OpCompositeExtract %float %9 1 1 1 + %11 = OpCompositeInsert %type__Globals %10 %9 1 1 1 + OpReturn + OpFunctionEnd + +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(EliminateDeadMemberTest, RemoveMembersUpdateArrayLength) { + // Test that the members "x" and "y" are removed. + // Member "z" is live because of the OpArrayLength instruction. + // Update the OpArrayLength instruction. + const std::string text = R"( +; CHECK: OpName +; CHECK-NEXT: OpMemberName %type__Globals 0 "z" +; CHECK-NOT: OpMemberName +; CHECK: OpMemberDecorate %type__Globals 0 Offset 16 +; CHECK-NOT: OpMemberDecorate %type__Globals 1 Offset +; CHECK: %type__Globals = OpTypeStruct %_runtimearr_float +; CHECK: OpArrayLength %uint %_Globals 0 + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %main "main" + OpSource HLSL 600 + OpName %type__Globals "type.$Globals" + OpMemberName %type__Globals 0 "x" + OpMemberName %type__Globals 1 "y" + OpMemberName %type__Globals 2 "z" + OpName %_Globals "$Globals" + OpName %main "main" + OpDecorate %_Globals DescriptorSet 0 + OpDecorate %_Globals Binding 0 + OpDecorate %_runtimearr_float ArrayStride 16 + OpMemberDecorate %type__Globals 0 Offset 0 + OpMemberDecorate %type__Globals 1 Offset 4 + OpMemberDecorate %type__Globals 2 Offset 16 + OpDecorate %type__Globals Block + %uint = OpTypeInt 32 0 + %float = OpTypeFloat 32 +%_runtimearr_float = OpTypeRuntimeArray %float +%type__Globals = OpTypeStruct %float %float %_runtimearr_float +%_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals + %void = OpTypeVoid + %9 = OpTypeFunction %void + %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform + %main = OpFunction %void None %9 + %10 = OpLabel + %11 = OpLoad %type__Globals %_Globals + %12 = OpArrayLength %uint %_Globals 2 + OpReturn + OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(EliminateDeadMemberTest, KeepMembersOpStore) { + // Test that all members are kept because of an OpStore. + // No change expected. + const std::string text = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %main "main" + OpSource HLSL 600 + OpName %type__Globals "type.$Globals" + OpMemberName %type__Globals 0 "x" + OpMemberName %type__Globals 1 "y" + OpMemberName %type__Globals 2 "z" + OpName %_Globals "$Globals" + OpName %_Globals "$Globals2" + OpName %main "main" + OpDecorate %_Globals DescriptorSet 0 + OpDecorate %_Globals Binding 0 + OpMemberDecorate %type__Globals 0 Offset 0 + OpMemberDecorate %type__Globals 1 Offset 4 + OpMemberDecorate %type__Globals 2 Offset 16 + OpDecorate %type__Globals Block + %uint = OpTypeInt 32 0 + %float = OpTypeFloat 32 +%type__Globals = OpTypeStruct %float %float %float +%_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals + %void = OpTypeVoid + %9 = OpTypeFunction %void + %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform + %_Globals2 = OpVariable %_ptr_Uniform_type__Globals Uniform + %main = OpFunction %void None %9 + %10 = OpLabel + %11 = OpLoad %type__Globals %_Globals + OpStore %_Globals2 %11 + OpReturn + OpFunctionEnd +)"; + + auto result = SinglePassRunAndDisassemble( + text, /* skip_nop = */ true, /* do_validation = */ true); + EXPECT_EQ(opt::Pass::Status::SuccessWithoutChange, std::get<1>(result)); +} + +TEST_F(EliminateDeadMemberTest, KeepMembersOpCopyMemory) { + // Test that all members are kept because of an OpCopyMemory. + // No change expected. + const std::string text = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %main "main" + OpSource HLSL 600 + OpName %type__Globals "type.$Globals" + OpMemberName %type__Globals 0 "x" + OpMemberName %type__Globals 1 "y" + OpMemberName %type__Globals 2 "z" + OpName %_Globals "$Globals" + OpName %_Globals "$Globals2" + OpName %main "main" + OpDecorate %_Globals DescriptorSet 0 + OpDecorate %_Globals Binding 0 + OpMemberDecorate %type__Globals 0 Offset 0 + OpMemberDecorate %type__Globals 1 Offset 4 + OpMemberDecorate %type__Globals 2 Offset 16 + OpDecorate %type__Globals Block + %uint = OpTypeInt 32 0 + %float = OpTypeFloat 32 +%type__Globals = OpTypeStruct %float %float %float +%_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals + %void = OpTypeVoid + %9 = OpTypeFunction %void + %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform + %_Globals2 = OpVariable %_ptr_Uniform_type__Globals Uniform + %main = OpFunction %void None %9 + %10 = OpLabel + OpCopyMemory %_Globals2 %_Globals + OpReturn + OpFunctionEnd +)"; + + auto result = SinglePassRunAndDisassemble( + text, /* skip_nop = */ true, /* do_validation = */ true); + EXPECT_EQ(opt::Pass::Status::SuccessWithoutChange, std::get<1>(result)); +} + +TEST_F(EliminateDeadMemberTest, KeepMembersOpCopyMemorySized) { + // Test that all members are kept because of an OpCopyMemorySized. + // No change expected. + const std::string text = R"( + OpCapability Shader + OpCapability Addresses + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %main "main" + OpSource HLSL 600 + OpName %type__Globals "type.$Globals" + OpMemberName %type__Globals 0 "x" + OpMemberName %type__Globals 1 "y" + OpMemberName %type__Globals 2 "z" + OpName %_Globals "$Globals" + OpName %_Globals "$Globals2" + OpName %main "main" + OpDecorate %_Globals DescriptorSet 0 + OpDecorate %_Globals Binding 0 + OpMemberDecorate %type__Globals 0 Offset 0 + OpMemberDecorate %type__Globals 1 Offset 4 + OpMemberDecorate %type__Globals 2 Offset 16 + OpDecorate %type__Globals Block + %uint = OpTypeInt 32 0 + %uint_20 = OpConstant %uint 20 + %float = OpTypeFloat 32 +%type__Globals = OpTypeStruct %float %float %float +%_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals + %void = OpTypeVoid + %9 = OpTypeFunction %void + %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform + %_Globals2 = OpVariable %_ptr_Uniform_type__Globals Uniform + %main = OpFunction %void None %9 + %10 = OpLabel + OpCopyMemorySized %_Globals2 %_Globals %uint_20 + OpReturn + OpFunctionEnd +)"; + + auto result = SinglePassRunAndDisassemble( + text, /* skip_nop = */ true, /* do_validation = */ true); + EXPECT_EQ(opt::Pass::Status::SuccessWithoutChange, std::get<1>(result)); +} + +TEST_F(EliminateDeadMemberTest, KeepMembersOpReturnValue) { + // Test that all members are kept because of an OpCopyMemorySized. + // No change expected. + const std::string text = R"( + OpCapability Shader + OpCapability Linkage + OpMemoryModel Logical GLSL450 + OpSource HLSL 600 + OpName %type__Globals "type.$Globals" + OpMemberName %type__Globals 0 "x" + OpMemberName %type__Globals 1 "y" + OpMemberName %type__Globals 2 "z" + OpName %_Globals "$Globals" + OpName %_Globals "$Globals2" + OpName %main "main" + OpDecorate %_Globals DescriptorSet 0 + OpDecorate %_Globals Binding 0 + OpMemberDecorate %type__Globals 0 Offset 0 + OpMemberDecorate %type__Globals 1 Offset 4 + OpMemberDecorate %type__Globals 2 Offset 16 + OpDecorate %type__Globals Block + %uint = OpTypeInt 32 0 + %uint_20 = OpConstant %uint 20 + %float = OpTypeFloat 32 +%type__Globals = OpTypeStruct %float %float %float +%_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals + %void = OpTypeVoid + %9 = OpTypeFunction %type__Globals + %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform + %_Globals2 = OpVariable %_ptr_Uniform_type__Globals Uniform + %main = OpFunction %type__Globals None %9 + %10 = OpLabel + %11 = OpLoad %type__Globals %_Globals + OpReturnValue %11 + OpFunctionEnd +)"; + + auto result = SinglePassRunAndDisassemble( + text, /* skip_nop = */ true, /* do_validation = */ true); + EXPECT_EQ(opt::Pass::Status::SuccessWithoutChange, std::get<1>(result)); +} + +TEST_F(EliminateDeadMemberTest, RemoveMemberAccessChainWithArrays) { + // Leave only 1 member in each of the structs. + // Update OpMemberName, OpMemberDecorate, and OpAccessChain. + const std::string text = R"( +; CHECK: OpName +; CHECK-NEXT: OpMemberName %type__Globals 0 "y" +; CHECK-NOT: OpMemberName +; CHECK: OpMemberDecorate %type__Globals 0 Offset 16 +; CHECK: OpMemberDecorate [[struct:%\w+]] 0 Offset 4 +; CHECK: [[struct]] = OpTypeStruct %float +; CHECK: [[array:%\w+]] = OpTypeArray [[struct]] +; CHECK: %type__Globals = OpTypeStruct [[array]] +; CHECK: [[undef:%\w+]] = OpUndef %uint +; CHECK: OpAccessChain %_ptr_Uniform_float %_Globals [[undef]] %uint_0 [[undef]] %uint_0 + OpCapability Shader + OpCapability VariablePointersStorageBuffer + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %main "main" + OpSource HLSL 600 + OpName %type__Globals "type.$Globals" + OpMemberName %type__Globals 0 "x" + OpMemberName %type__Globals 1 "y" + OpMemberName %type__Globals 2 "z" + OpName %_Globals "$Globals" + OpName %main "main" + OpDecorate %_Globals DescriptorSet 0 + OpDecorate %_Globals Binding 0 + OpMemberDecorate %type__Globals 0 Offset 0 + OpMemberDecorate %type__Globals 1 Offset 16 + OpMemberDecorate %type__Globals 2 Offset 48 + OpMemberDecorate %_struct_4 0 Offset 0 + OpMemberDecorate %_struct_4 1 Offset 4 + OpDecorate %_arr__struct_4_uint_2 ArrayStride 16 + OpDecorate %type__Globals Block + %uint = OpTypeInt 32 0 + %uint_0 = OpConstant %uint 0 + %uint_1 = OpConstant %uint 1 + %uint_2 = OpConstant %uint 2 + %uint_3 = OpConstant %uint 3 + %float = OpTypeFloat 32 + %_struct_4 = OpTypeStruct %float %float +%_arr__struct_4_uint_2 = OpTypeArray %_struct_4 %uint_2 +%type__Globals = OpTypeStruct %float %_arr__struct_4_uint_2 %float +%_arr_type__Globals_uint_3 = OpTypeArray %type__Globals %uint_3 +%_ptr_Uniform__arr_type__Globals_uint_3 = OpTypePointer Uniform %_arr_type__Globals_uint_3 + %void = OpTypeVoid + %15 = OpTypeFunction %void +%_ptr_Uniform_float = OpTypePointer Uniform %float + %_Globals = OpVariable %_ptr_Uniform__arr_type__Globals_uint_3 Uniform + %main = OpFunction %void None %15 + %17 = OpLabel + %18 = OpUndef %uint + %19 = OpAccessChain %_ptr_Uniform_float %_Globals %18 %uint_1 %18 %uint_1 + OpReturn + OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(EliminateDeadMemberTest, RemoveMemberInboundsAccessChain) { + // Test that the member "y" is removed. + // Update OpMemberName for |y| and |z|. + // Update OpMemberDecorate for |y| and |z|. + // Update OpInboundsAccessChain for access to |z|. + const std::string text = R"( +; CHECK: OpName +; CHECK-NEXT: OpMemberName %type__Globals 0 "x" +; CHECK-NEXT: OpMemberName %type__Globals 1 "z" +; CHECK-NOT: OpMemberName +; CHECK: OpMemberDecorate %type__Globals 0 Offset 0 +; CHECK: OpMemberDecorate %type__Globals 1 Offset 8 +; CHECK: %type__Globals = OpTypeStruct %float %float +; CHECK: OpInBoundsAccessChain %_ptr_Uniform_float %_Globals %int_0 +; CHECK: OpInBoundsAccessChain %_ptr_Uniform_float %_Globals %uint_1 + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %main "main" %in_var_Position %gl_Position + OpSource HLSL 600 + OpName %type__Globals "type.$Globals" + OpMemberName %type__Globals 0 "x" + OpMemberName %type__Globals 1 "y" + OpMemberName %type__Globals 2 "z" + OpName %_Globals "$Globals" + OpName %in_var_Position "in.var.Position" + OpName %main "main" + OpDecorate %gl_Position BuiltIn Position + OpDecorate %in_var_Position Location 0 + OpDecorate %_Globals DescriptorSet 0 + OpDecorate %_Globals Binding 0 + OpMemberDecorate %type__Globals 0 Offset 0 + OpMemberDecorate %type__Globals 1 Offset 4 + OpMemberDecorate %type__Globals 2 Offset 8 + OpDecorate %type__Globals Block + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 + %float = OpTypeFloat 32 + %int_2 = OpConstant %int 2 +%type__Globals = OpTypeStruct %float %float %float +%_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals + %v4float = OpTypeVector %float 4 +%_ptr_Input_v4float = OpTypePointer Input %v4float +%_ptr_Output_v4float = OpTypePointer Output %v4float + %void = OpTypeVoid + %15 = OpTypeFunction %void +%_ptr_Uniform_float = OpTypePointer Uniform %float + %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform +%in_var_Position = OpVariable %_ptr_Input_v4float Input +%gl_Position = OpVariable %_ptr_Output_v4float Output + %main = OpFunction %void None %15 + %17 = OpLabel + %18 = OpLoad %v4float %in_var_Position + %19 = OpInBoundsAccessChain %_ptr_Uniform_float %_Globals %int_0 + %20 = OpLoad %float %19 + %21 = OpCompositeExtract %float %18 0 + %22 = OpFAdd %float %21 %20 + %23 = OpCompositeInsert %v4float %22 %18 0 + %24 = OpCompositeExtract %float %18 1 + %25 = OpCompositeInsert %v4float %24 %23 1 + %26 = OpInBoundsAccessChain %_ptr_Uniform_float %_Globals %int_2 + %27 = OpLoad %float %26 + %28 = OpCompositeExtract %float %18 2 + %29 = OpFAdd %float %28 %27 + %30 = OpCompositeInsert %v4float %29 %25 2 + OpStore %gl_Position %30 + OpReturn + OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(EliminateDeadMemberTest, RemoveMemberPtrAccessChain) { + // Test that the member "y" is removed. + // Update OpMemberName for |y| and |z|. + // Update OpMemberDecorate for |y| and |z|. + // Update OpInboundsAccessChain for access to |z|. + const std::string text = R"( +; CHECK: OpName +; CHECK-NEXT: OpMemberName %type__Globals 0 "x" +; CHECK-NEXT: OpMemberName %type__Globals 1 "z" +; CHECK-NOT: OpMemberName +; CHECK: OpMemberDecorate %type__Globals 0 Offset 0 +; CHECK: OpMemberDecorate %type__Globals 1 Offset 16 +; CHECK: %type__Globals = OpTypeStruct %float %float +; CHECK: [[ac:%\w+]] = OpAccessChain %_ptr_Uniform_type__Globals %_Globals %uint_0 +; CHECK: OpPtrAccessChain %_ptr_Uniform_float [[ac]] %uint_1 %uint_0 +; CHECK: OpPtrAccessChain %_ptr_Uniform_float [[ac]] %uint_0 %uint_1 + OpCapability Shader + OpCapability VariablePointersStorageBuffer + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %main "main" + OpSource HLSL 600 + OpName %type__Globals "type.$Globals" + OpMemberName %type__Globals 0 "x" + OpMemberName %type__Globals 1 "y" + OpMemberName %type__Globals 2 "z" + OpName %_Globals "$Globals" + OpName %main "main" + OpDecorate %_Globals DescriptorSet 0 + OpDecorate %_Globals Binding 0 + OpMemberDecorate %type__Globals 0 Offset 0 + OpMemberDecorate %type__Globals 1 Offset 4 + OpMemberDecorate %type__Globals 2 Offset 16 + OpDecorate %type__Globals Block + %uint = OpTypeInt 32 0 + %uint_0 = OpConstant %uint 0 + %uint_1 = OpConstant %uint 1 + %uint_2 = OpConstant %uint 2 + %uint_3 = OpConstant %uint 3 + %float = OpTypeFloat 32 +%type__Globals = OpTypeStruct %float %float %float +%_arr_type__Globals_uint_3 = OpTypeArray %type__Globals %uint_3 +%_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals +%_ptr_Uniform__arr_type__Globals_uint_3 = OpTypePointer Uniform %_arr_type__Globals_uint_3 + %void = OpTypeVoid + %14 = OpTypeFunction %void +%_ptr_Uniform_float = OpTypePointer Uniform %float + %_Globals = OpVariable %_ptr_Uniform__arr_type__Globals_uint_3 Uniform + %main = OpFunction %void None %14 + %16 = OpLabel + %17 = OpAccessChain %_ptr_Uniform_type__Globals %_Globals %uint_0 + %18 = OpPtrAccessChain %_ptr_Uniform_float %17 %uint_1 %uint_0 + %19 = OpPtrAccessChain %_ptr_Uniform_float %17 %uint_0 %uint_2 + OpReturn + OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(EliminateDeadMemberTest, RemoveMemberInBoundsPtrAccessChain) { + // Test that the member "y" is removed. + // Update OpMemberName for |y| and |z|. + // Update OpMemberDecorate for |y| and |z|. + // Update OpInboundsAccessChain for access to |z|. + const std::string text = R"( +; CHECK: OpName +; CHECK-NEXT: OpMemberName %type__Globals 0 "x" +; CHECK-NEXT: OpMemberName %type__Globals 1 "z" +; CHECK-NOT: OpMemberName +; CHECK: OpMemberDecorate %type__Globals 0 Offset 0 +; CHECK: OpMemberDecorate %type__Globals 1 Offset 16 +; CHECK: %type__Globals = OpTypeStruct %float %float +; CHECK: [[ac:%\w+]] = OpAccessChain %_ptr_Uniform_type__Globals %_Globals %uint_0 +; CHECK: OpInBoundsPtrAccessChain %_ptr_Uniform_float [[ac]] %uint_1 %uint_0 +; CHECK: OpInBoundsPtrAccessChain %_ptr_Uniform_float [[ac]] %uint_0 %uint_1 + OpCapability Shader + OpCapability Addresses + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %main "main" + OpSource HLSL 600 + OpName %type__Globals "type.$Globals" + OpMemberName %type__Globals 0 "x" + OpMemberName %type__Globals 1 "y" + OpMemberName %type__Globals 2 "z" + OpName %_Globals "$Globals" + OpName %main "main" + OpDecorate %_Globals DescriptorSet 0 + OpDecorate %_Globals Binding 0 + OpMemberDecorate %type__Globals 0 Offset 0 + OpMemberDecorate %type__Globals 1 Offset 4 + OpMemberDecorate %type__Globals 2 Offset 16 + OpDecorate %type__Globals Block + %uint = OpTypeInt 32 0 + %uint_0 = OpConstant %uint 0 + %uint_1 = OpConstant %uint 1 + %uint_2 = OpConstant %uint 2 + %uint_3 = OpConstant %uint 3 + %float = OpTypeFloat 32 +%type__Globals = OpTypeStruct %float %float %float +%_arr_type__Globals_uint_3 = OpTypeArray %type__Globals %uint_3 +%_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals +%_ptr_Uniform__arr_type__Globals_uint_3 = OpTypePointer Uniform %_arr_type__Globals_uint_3 + %void = OpTypeVoid + %14 = OpTypeFunction %void +%_ptr_Uniform_float = OpTypePointer Uniform %float + %_Globals = OpVariable %_ptr_Uniform__arr_type__Globals_uint_3 Uniform + %main = OpFunction %void None %14 + %16 = OpLabel + %17 = OpAccessChain %_ptr_Uniform_type__Globals %_Globals %uint_0 + %18 = OpInBoundsPtrAccessChain %_ptr_Uniform_float %17 %uint_1 %uint_0 + %19 = OpInBoundsPtrAccessChain %_ptr_Uniform_float %17 %uint_0 %uint_2 + OpReturn + OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(EliminateDeadMemberTest, DontRemoveModfStructResultTypeMembers) { + const std::string text = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" + OpExecutionMode %main OriginUpperLeft + OpSource HLSL 600 + %float = OpTypeFloat 32 + %void = OpTypeVoid + %21 = OpTypeFunction %void +%ModfStructType = OpTypeStruct %float %float +%main = OpFunction %void None %21 + %22 = OpLabel + %23 = OpUndef %float + %24 = OpExtInst %ModfStructType %1 ModfStruct %23 + %25 = OpCompositeExtract %float %24 1 + OpReturn + OpFunctionEnd +)"; + + auto result = SinglePassRunAndDisassemble( + text, /* skip_nop = */ true, /* do_validation = */ true); + EXPECT_EQ(opt::Pass::Status::SuccessWithoutChange, std::get<1>(result)); +} + +TEST_F(EliminateDeadMemberTest, DontChangeInputStructs) { + // The input for a shader has to match the type of the output from the + // previous shader in the pipeline. Because of that, we cannot change the + // types of input variables. + const std::string text = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %input_var + OpExecutionMode %main OriginUpperLeft + OpSource HLSL 600 + %float = OpTypeFloat 32 + %void = OpTypeVoid + %21 = OpTypeFunction %void +%in_var_type = OpTypeStruct %float %float +%in_ptr_type = OpTypePointer Input %in_var_type +%input_var = OpVariable %in_ptr_type Input +%main = OpFunction %void None %21 + %22 = OpLabel + OpReturn + OpFunctionEnd +)"; + + auto result = SinglePassRunAndDisassemble( + text, /* skip_nop = */ true, /* do_validation = */ true); + EXPECT_EQ(opt::Pass::Status::SuccessWithoutChange, std::get<1>(result)); +} + +TEST_F(EliminateDeadMemberTest, DontChangeOutputStructs) { + // The output for a shader has to match the type of the output from the + // previous shader in the pipeline. Because of that, we cannot change the + // types of output variables. + const std::string text = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %output_var + OpExecutionMode %main OriginUpperLeft + OpSource HLSL 600 + %float = OpTypeFloat 32 + %void = OpTypeVoid + %21 = OpTypeFunction %void +%out_var_type = OpTypeStruct %float %float +%out_ptr_type = OpTypePointer Output %out_var_type +%output_var = OpVariable %out_ptr_type Output +%main = OpFunction %void None %21 + %22 = OpLabel + OpReturn + OpFunctionEnd +)"; + + auto result = SinglePassRunAndDisassemble( + text, /* skip_nop = */ true, /* do_validation = */ true); + EXPECT_EQ(opt::Pass::Status::SuccessWithoutChange, std::get<1>(result)); +} + +} // namespace diff --git a/third_party/spirv-tools/test/opt/fix_storage_class_test.cpp b/third_party/spirv-tools/test/opt/fix_storage_class_test.cpp new file mode 100644 index 0000000000..4c8504ae12 --- /dev/null +++ b/third_party/spirv-tools/test/opt/fix_storage_class_test.cpp @@ -0,0 +1,840 @@ +// Copyright (c) 2019 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 + +#include "gmock/gmock.h" +#include "test/opt/assembly_builder.h" +#include "test/opt/pass_fixture.h" +#include "test/opt/pass_utils.h" + +namespace spvtools { +namespace opt { +namespace { + +using FixStorageClassTest = PassTest<::testing::Test>; + +TEST_F(FixStorageClassTest, FixAccessChain) { + const std::string text = R"( +; CHECK: OpAccessChain %_ptr_Workgroup_float +; CHECK: OpAccessChain %_ptr_Uniform_float + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "testMain" %gl_GlobalInvocationID %gl_LocalInvocationID %gl_WorkGroupID + OpExecutionMode %1 LocalSize 8 8 1 + OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId + OpDecorate %gl_LocalInvocationID BuiltIn LocalInvocationId + OpDecorate %gl_WorkGroupID BuiltIn WorkgroupId + OpDecorate %8 DescriptorSet 0 + OpDecorate %8 Binding 0 + OpDecorate %_runtimearr_float ArrayStride 4 + OpMemberDecorate %_struct_7 0 Offset 0 + OpDecorate %_struct_7 BufferBlock + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 + %float = OpTypeFloat 32 + %float_2 = OpConstant %float 2 + %uint = OpTypeInt 32 0 + %uint_10 = OpConstant %uint 10 +%_arr_float_uint_10 = OpTypeArray %float %uint_10 +%ptr = OpTypePointer Function %_arr_float_uint_10 +%_arr__arr_float_uint_10_uint_10 = OpTypeArray %_arr_float_uint_10 %uint_10 + %_struct_5 = OpTypeStruct %_arr__arr_float_uint_10_uint_10 +%_ptr_Workgroup__struct_5 = OpTypePointer Workgroup %_struct_5 +%_runtimearr_float = OpTypeRuntimeArray %float + %_struct_7 = OpTypeStruct %_runtimearr_float +%_ptr_Uniform__struct_7 = OpTypePointer Uniform %_struct_7 + %v3uint = OpTypeVector %uint 3 +%_ptr_Input_v3uint = OpTypePointer Input %v3uint + %void = OpTypeVoid + %30 = OpTypeFunction %void +%_ptr_Function_float = OpTypePointer Function %float +%_ptr_Uniform_float = OpTypePointer Uniform %float + %6 = OpVariable %_ptr_Workgroup__struct_5 Workgroup + %8 = OpVariable %_ptr_Uniform__struct_7 Uniform +%gl_GlobalInvocationID = OpVariable %_ptr_Input_v3uint Input +%gl_LocalInvocationID = OpVariable %_ptr_Input_v3uint Input +%gl_WorkGroupID = OpVariable %_ptr_Input_v3uint Input + %1 = OpFunction %void None %30 + %38 = OpLabel + %44 = OpLoad %v3uint %gl_LocalInvocationID + %50 = OpAccessChain %_ptr_Function_float %6 %int_0 %int_0 %int_0 + %51 = OpLoad %float %50 + %52 = OpFMul %float %float_2 %51 + OpStore %50 %52 + %55 = OpLoad %float %50 + %59 = OpCompositeExtract %uint %44 0 + %60 = OpAccessChain %_ptr_Uniform_float %8 %int_0 %59 + OpStore %60 %55 + OpReturn + OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, false); +} + +TEST_F(FixStorageClassTest, FixLinkedAccessChain) { + const std::string text = R"( +; CHECK: OpAccessChain %_ptr_Workgroup__arr_float_uint_10 +; CHECK: OpAccessChain %_ptr_Workgroup_float +; CHECK: OpAccessChain %_ptr_Uniform_float + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "testMain" %gl_GlobalInvocationID %gl_LocalInvocationID %gl_WorkGroupID + OpExecutionMode %1 LocalSize 8 8 1 + OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId + OpDecorate %gl_LocalInvocationID BuiltIn LocalInvocationId + OpDecorate %gl_WorkGroupID BuiltIn WorkgroupId + OpDecorate %5 DescriptorSet 0 + OpDecorate %5 Binding 0 + OpDecorate %_runtimearr_float ArrayStride 4 + OpMemberDecorate %_struct_7 0 Offset 0 + OpDecorate %_struct_7 BufferBlock + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 + %float = OpTypeFloat 32 + %float_2 = OpConstant %float 2 + %uint = OpTypeInt 32 0 + %uint_10 = OpConstant %uint 10 +%_arr_float_uint_10 = OpTypeArray %float %uint_10 +%_ptr_Function__arr_float_uint_10 = OpTypePointer Function %_arr_float_uint_10 +%_ptr = OpTypePointer Function %_arr_float_uint_10 +%_arr__arr_float_uint_10_uint_10 = OpTypeArray %_arr_float_uint_10 %uint_10 + %_struct_17 = OpTypeStruct %_arr__arr_float_uint_10_uint_10 +%_ptr_Workgroup__struct_17 = OpTypePointer Workgroup %_struct_17 +%_runtimearr_float = OpTypeRuntimeArray %float + %_struct_7 = OpTypeStruct %_runtimearr_float +%_ptr_Uniform__struct_7 = OpTypePointer Uniform %_struct_7 + %v3uint = OpTypeVector %uint 3 +%_ptr_Input_v3uint = OpTypePointer Input %v3uint + %void = OpTypeVoid + %23 = OpTypeFunction %void +%_ptr_Function_float = OpTypePointer Function %float +%_ptr_Uniform_float = OpTypePointer Uniform %float + %27 = OpVariable %_ptr_Workgroup__struct_17 Workgroup + %5 = OpVariable %_ptr_Uniform__struct_7 Uniform +%gl_GlobalInvocationID = OpVariable %_ptr_Input_v3uint Input +%gl_LocalInvocationID = OpVariable %_ptr_Input_v3uint Input +%gl_WorkGroupID = OpVariable %_ptr_Input_v3uint Input + %1 = OpFunction %void None %23 + %28 = OpLabel + %29 = OpLoad %v3uint %gl_LocalInvocationID + %30 = OpAccessChain %_ptr_Function__arr_float_uint_10 %27 %int_0 %int_0 + %31 = OpAccessChain %_ptr_Function_float %30 %int_0 + %32 = OpLoad %float %31 + %33 = OpFMul %float %float_2 %32 + OpStore %31 %33 + %34 = OpLoad %float %31 + %35 = OpCompositeExtract %uint %29 0 + %36 = OpAccessChain %_ptr_Uniform_float %5 %int_0 %35 + OpStore %36 %34 + OpReturn + OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, false); +} + +TEST_F(FixStorageClassTest, FixCopyObject) { + const std::string text = R"( +; CHECK: OpCopyObject %_ptr_Workgroup__struct_17 +; CHECK: OpAccessChain %_ptr_Workgroup_float +; CHECK: OpAccessChain %_ptr_Uniform_float + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "testMain" %gl_GlobalInvocationID %gl_LocalInvocationID %gl_WorkGroupID + OpExecutionMode %1 LocalSize 8 8 1 + OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId + OpDecorate %gl_LocalInvocationID BuiltIn LocalInvocationId + OpDecorate %gl_WorkGroupID BuiltIn WorkgroupId + OpDecorate %8 DescriptorSet 0 + OpDecorate %8 Binding 0 + OpDecorate %_runtimearr_float ArrayStride 4 + OpMemberDecorate %_struct_7 0 Offset 0 + OpDecorate %_struct_7 BufferBlock + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 + %float = OpTypeFloat 32 + %float_2 = OpConstant %float 2 + %uint = OpTypeInt 32 0 + %uint_10 = OpConstant %uint 10 +%_arr_float_uint_10 = OpTypeArray %float %uint_10 +%ptr = OpTypePointer Function %_arr_float_uint_10 +%_arr__arr_float_uint_10_uint_10 = OpTypeArray %_arr_float_uint_10 %uint_10 + %_struct_17 = OpTypeStruct %_arr__arr_float_uint_10_uint_10 +%_ptr_Workgroup__struct_17 = OpTypePointer Workgroup %_struct_17 +%_ptr_Function__struct_17 = OpTypePointer Function %_struct_17 +%_runtimearr_float = OpTypeRuntimeArray %float + %_struct_7 = OpTypeStruct %_runtimearr_float +%_ptr_Uniform__struct_7 = OpTypePointer Uniform %_struct_7 + %v3uint = OpTypeVector %uint 3 +%_ptr_Input_v3uint = OpTypePointer Input %v3uint + %void = OpTypeVoid + %30 = OpTypeFunction %void +%_ptr_Function_float = OpTypePointer Function %float +%_ptr_Uniform_float = OpTypePointer Uniform %float + %6 = OpVariable %_ptr_Workgroup__struct_17 Workgroup + %8 = OpVariable %_ptr_Uniform__struct_7 Uniform +%gl_GlobalInvocationID = OpVariable %_ptr_Input_v3uint Input +%gl_LocalInvocationID = OpVariable %_ptr_Input_v3uint Input +%gl_WorkGroupID = OpVariable %_ptr_Input_v3uint Input + %1 = OpFunction %void None %30 + %38 = OpLabel + %44 = OpLoad %v3uint %gl_LocalInvocationID + %cp = OpCopyObject %_ptr_Function__struct_17 %6 + %50 = OpAccessChain %_ptr_Function_float %cp %int_0 %int_0 %int_0 + %51 = OpLoad %float %50 + %52 = OpFMul %float %float_2 %51 + OpStore %50 %52 + %55 = OpLoad %float %50 + %59 = OpCompositeExtract %uint %44 0 + %60 = OpAccessChain %_ptr_Uniform_float %8 %int_0 %59 + OpStore %60 %55 + OpReturn + OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, false); +} + +TEST_F(FixStorageClassTest, FixPhiInSelMerge) { + const std::string text = R"( +; CHECK: OpPhi %_ptr_Workgroup__struct_19 +; CHECK: OpAccessChain %_ptr_Workgroup_float +; CHECK: OpAccessChain %_ptr_Uniform_float + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "testMain" %gl_GlobalInvocationID %gl_LocalInvocationID %gl_WorkGroupID + OpExecutionMode %1 LocalSize 8 8 1 + OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId + OpDecorate %gl_LocalInvocationID BuiltIn LocalInvocationId + OpDecorate %gl_WorkGroupID BuiltIn WorkgroupId + OpDecorate %5 DescriptorSet 0 + OpDecorate %5 Binding 0 + OpDecorate %_runtimearr_float ArrayStride 4 + OpMemberDecorate %_struct_7 0 Offset 0 + OpDecorate %_struct_7 BufferBlock + %bool = OpTypeBool + %true = OpConstantTrue %bool + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 + %float = OpTypeFloat 32 + %float_2 = OpConstant %float 2 + %uint = OpTypeInt 32 0 + %uint_10 = OpConstant %uint 10 +%_arr_float_uint_10 = OpTypeArray %float %uint_10 +%_ptr_Function__arr_float_uint_10 = OpTypePointer Function %_arr_float_uint_10 +%_arr__arr_float_uint_10_uint_10 = OpTypeArray %_arr_float_uint_10 %uint_10 + %_struct_19 = OpTypeStruct %_arr__arr_float_uint_10_uint_10 +%_ptr_Workgroup__struct_19 = OpTypePointer Workgroup %_struct_19 +%_ptr_Function__struct_19 = OpTypePointer Function %_struct_19 +%_runtimearr_float = OpTypeRuntimeArray %float + %_struct_7 = OpTypeStruct %_runtimearr_float +%_ptr_Uniform__struct_7 = OpTypePointer Uniform %_struct_7 + %v3uint = OpTypeVector %uint 3 +%_ptr_Input_v3uint = OpTypePointer Input %v3uint + %void = OpTypeVoid + %25 = OpTypeFunction %void +%_ptr_Function_float = OpTypePointer Function %float +%_ptr_Uniform_float = OpTypePointer Uniform %float + %28 = OpVariable %_ptr_Workgroup__struct_19 Workgroup + %29 = OpVariable %_ptr_Workgroup__struct_19 Workgroup + %5 = OpVariable %_ptr_Uniform__struct_7 Uniform +%gl_GlobalInvocationID = OpVariable %_ptr_Input_v3uint Input +%gl_LocalInvocationID = OpVariable %_ptr_Input_v3uint Input +%gl_WorkGroupID = OpVariable %_ptr_Input_v3uint Input + %1 = OpFunction %void None %25 + %30 = OpLabel + OpSelectionMerge %31 None + OpBranchConditional %true %32 %31 + %32 = OpLabel + OpBranch %31 + %31 = OpLabel + %33 = OpPhi %_ptr_Function__struct_19 %28 %30 %29 %32 + %34 = OpLoad %v3uint %gl_LocalInvocationID + %35 = OpAccessChain %_ptr_Function_float %33 %int_0 %int_0 %int_0 + %36 = OpLoad %float %35 + %37 = OpFMul %float %float_2 %36 + OpStore %35 %37 + %38 = OpLoad %float %35 + %39 = OpCompositeExtract %uint %34 0 + %40 = OpAccessChain %_ptr_Uniform_float %5 %int_0 %39 + OpStore %40 %38 + OpReturn + OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, false); +} + +TEST_F(FixStorageClassTest, FixPhiInLoop) { + const std::string text = R"( +; CHECK: OpPhi %_ptr_Workgroup__struct_19 +; CHECK: OpAccessChain %_ptr_Workgroup_float +; CHECK: OpAccessChain %_ptr_Uniform_float + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "testMain" %gl_GlobalInvocationID %gl_LocalInvocationID %gl_WorkGroupID + OpExecutionMode %1 LocalSize 8 8 1 + OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId + OpDecorate %gl_LocalInvocationID BuiltIn LocalInvocationId + OpDecorate %gl_WorkGroupID BuiltIn WorkgroupId + OpDecorate %5 DescriptorSet 0 + OpDecorate %5 Binding 0 + OpDecorate %_runtimearr_float ArrayStride 4 + OpMemberDecorate %_struct_7 0 Offset 0 + OpDecorate %_struct_7 BufferBlock + %bool = OpTypeBool + %true = OpConstantTrue %bool + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 + %float = OpTypeFloat 32 + %float_2 = OpConstant %float 2 + %uint = OpTypeInt 32 0 + %uint_10 = OpConstant %uint 10 +%_arr_float_uint_10 = OpTypeArray %float %uint_10 +%_ptr_Function__arr_float_uint_10 = OpTypePointer Function %_arr_float_uint_10 +%_arr__arr_float_uint_10_uint_10 = OpTypeArray %_arr_float_uint_10 %uint_10 + %_struct_19 = OpTypeStruct %_arr__arr_float_uint_10_uint_10 +%_ptr_Workgroup__struct_19 = OpTypePointer Workgroup %_struct_19 +%_ptr_Function__struct_19 = OpTypePointer Function %_struct_19 +%_runtimearr_float = OpTypeRuntimeArray %float + %_struct_7 = OpTypeStruct %_runtimearr_float +%_ptr_Uniform__struct_7 = OpTypePointer Uniform %_struct_7 + %v3uint = OpTypeVector %uint 3 +%_ptr_Input_v3uint = OpTypePointer Input %v3uint + %void = OpTypeVoid + %25 = OpTypeFunction %void +%_ptr_Function_float = OpTypePointer Function %float +%_ptr_Uniform_float = OpTypePointer Uniform %float + %28 = OpVariable %_ptr_Workgroup__struct_19 Workgroup + %29 = OpVariable %_ptr_Workgroup__struct_19 Workgroup + %5 = OpVariable %_ptr_Uniform__struct_7 Uniform +%gl_GlobalInvocationID = OpVariable %_ptr_Input_v3uint Input +%gl_LocalInvocationID = OpVariable %_ptr_Input_v3uint Input +%gl_WorkGroupID = OpVariable %_ptr_Input_v3uint Input + %1 = OpFunction %void None %25 + %30 = OpLabel + OpSelectionMerge %31 None + OpBranchConditional %true %32 %31 + %32 = OpLabel + OpBranch %31 + %31 = OpLabel + %33 = OpPhi %_ptr_Function__struct_19 %28 %30 %29 %32 + %34 = OpLoad %v3uint %gl_LocalInvocationID + %35 = OpAccessChain %_ptr_Function_float %33 %int_0 %int_0 %int_0 + %36 = OpLoad %float %35 + %37 = OpFMul %float %float_2 %36 + OpStore %35 %37 + %38 = OpLoad %float %35 + %39 = OpCompositeExtract %uint %34 0 + %40 = OpAccessChain %_ptr_Uniform_float %5 %int_0 %39 + OpStore %40 %38 + OpReturn + OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, false); +} + +TEST_F(FixStorageClassTest, DontChangeFunctionCalls) { + const std::string text = R"(OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %1 "testMain" +OpExecutionMode %1 LocalSize 8 8 1 +OpDecorate %2 DescriptorSet 0 +OpDecorate %2 Binding 0 +%int = OpTypeInt 32 1 +%_ptr_Function_int = OpTypePointer Function %int +%_ptr_Workgroup_int = OpTypePointer Workgroup %int +%_ptr_Uniform_int = OpTypePointer Uniform %int +%void = OpTypeVoid +%8 = OpTypeFunction %void +%9 = OpTypeFunction %_ptr_Uniform_int %_ptr_Function_int +%10 = OpVariable %_ptr_Workgroup_int Workgroup +%2 = OpVariable %_ptr_Uniform_int Uniform +%1 = OpFunction %void None %8 +%11 = OpLabel +%12 = OpFunctionCall %_ptr_Uniform_int %13 %10 +OpReturn +OpFunctionEnd +%13 = OpFunction %_ptr_Uniform_int None %9 +%14 = OpFunctionParameter %_ptr_Function_int +%15 = OpLabel +OpReturnValue %2 +OpFunctionEnd +)"; + + SinglePassRunAndCheck(text, text, false, false); +} + +TEST_F(FixStorageClassTest, FixSelect) { + const std::string text = R"( +; CHECK: OpSelect %_ptr_Workgroup__struct_19 +; CHECK: OpAccessChain %_ptr_Workgroup_float +; CHECK: OpAccessChain %_ptr_Uniform_float + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "testMain" %gl_GlobalInvocationID %gl_LocalInvocationID %gl_WorkGroupID + OpExecutionMode %1 LocalSize 8 8 1 + OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId + OpDecorate %gl_LocalInvocationID BuiltIn LocalInvocationId + OpDecorate %gl_WorkGroupID BuiltIn WorkgroupId + OpDecorate %5 DescriptorSet 0 + OpDecorate %5 Binding 0 + OpDecorate %_runtimearr_float ArrayStride 4 + OpMemberDecorate %_struct_7 0 Offset 0 + OpDecorate %_struct_7 BufferBlock + %bool = OpTypeBool + %true = OpConstantTrue %bool + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 + %float = OpTypeFloat 32 + %float_2 = OpConstant %float 2 + %uint = OpTypeInt 32 0 + %uint_10 = OpConstant %uint 10 +%_arr_float_uint_10 = OpTypeArray %float %uint_10 +%_ptr_Function__arr_float_uint_10 = OpTypePointer Function %_arr_float_uint_10 +%_arr__arr_float_uint_10_uint_10 = OpTypeArray %_arr_float_uint_10 %uint_10 + %_struct_19 = OpTypeStruct %_arr__arr_float_uint_10_uint_10 +%_ptr_Workgroup__struct_19 = OpTypePointer Workgroup %_struct_19 +%_ptr_Function__struct_19 = OpTypePointer Function %_struct_19 +%_runtimearr_float = OpTypeRuntimeArray %float + %_struct_7 = OpTypeStruct %_runtimearr_float +%_ptr_Uniform__struct_7 = OpTypePointer Uniform %_struct_7 + %v3uint = OpTypeVector %uint 3 +%_ptr_Input_v3uint = OpTypePointer Input %v3uint + %void = OpTypeVoid + %25 = OpTypeFunction %void +%_ptr_Function_float = OpTypePointer Function %float +%_ptr_Uniform_float = OpTypePointer Uniform %float + %28 = OpVariable %_ptr_Workgroup__struct_19 Workgroup + %29 = OpVariable %_ptr_Workgroup__struct_19 Workgroup + %5 = OpVariable %_ptr_Uniform__struct_7 Uniform +%gl_GlobalInvocationID = OpVariable %_ptr_Input_v3uint Input +%gl_LocalInvocationID = OpVariable %_ptr_Input_v3uint Input +%gl_WorkGroupID = OpVariable %_ptr_Input_v3uint Input + %1 = OpFunction %void None %25 + %30 = OpLabel + %33 = OpSelect %_ptr_Function__struct_19 %true %28 %29 + %34 = OpLoad %v3uint %gl_LocalInvocationID + %35 = OpAccessChain %_ptr_Function_float %33 %int_0 %int_0 %int_0 + %36 = OpLoad %float %35 + %37 = OpFMul %float %float_2 %36 + OpStore %35 %37 + %38 = OpLoad %float %35 + %39 = OpCompositeExtract %uint %34 0 + %40 = OpAccessChain %_ptr_Uniform_float %5 %int_0 %39 + OpStore %40 %38 + OpReturn + OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, false); +} + +TEST_F(FixStorageClassTest, BitCast) { + const std::string text = R"(OpCapability VariablePointersStorageBuffer +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %1 "main" +%void = OpTypeVoid +%3 = OpTypeFunction %void +%_ptr_Output_void = OpTypePointer Output %void +%_ptr_Private__ptr_Output_void = OpTypePointer Private %_ptr_Output_void +%6 = OpVariable %_ptr_Private__ptr_Output_void Private +%1 = OpFunction %void Inline %3 +%7 = OpLabel +%8 = OpBitcast %_ptr_Output_void %6 +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndCheck(text, text, false); +} + +TEST_F(FixStorageClassTest, FixLinkedAccessChain2) { + // This case is similar to FixLinkedAccessChain. The difference is that the + // first OpAccessChain instruction starts as workgroup storage class. Only + // the second one needs to change. + const std::string text = R"( +; CHECK: OpAccessChain %_ptr_Workgroup__arr_float_uint_10 +; CHECK: OpAccessChain %_ptr_Workgroup_float +; CHECK: OpAccessChain %_ptr_Uniform_float + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "testMain" %gl_GlobalInvocationID %gl_LocalInvocationID %gl_WorkGroupID + OpExecutionMode %1 LocalSize 8 8 1 + OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId + OpDecorate %gl_LocalInvocationID BuiltIn LocalInvocationId + OpDecorate %gl_WorkGroupID BuiltIn WorkgroupId + OpDecorate %5 DescriptorSet 0 + OpDecorate %5 Binding 0 + OpDecorate %_runtimearr_float ArrayStride 4 + OpMemberDecorate %_struct_7 0 Offset 0 + OpDecorate %_struct_7 BufferBlock + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 + %float = OpTypeFloat 32 + %float_2 = OpConstant %float 2 + %uint = OpTypeInt 32 0 + %uint_10 = OpConstant %uint 10 +%_arr_float_uint_10 = OpTypeArray %float %uint_10 +%_ptr_Workgroup__arr_float_uint_10 = OpTypePointer Workgroup %_arr_float_uint_10 +%_ptr = OpTypePointer Function %_arr_float_uint_10 +%_arr__arr_float_uint_10_uint_10 = OpTypeArray %_arr_float_uint_10 %uint_10 + %_struct_17 = OpTypeStruct %_arr__arr_float_uint_10_uint_10 +%_ptr_Workgroup__struct_17 = OpTypePointer Workgroup %_struct_17 +%_runtimearr_float = OpTypeRuntimeArray %float + %_struct_7 = OpTypeStruct %_runtimearr_float +%_ptr_Uniform__struct_7 = OpTypePointer Uniform %_struct_7 + %v3uint = OpTypeVector %uint 3 +%_ptr_Input_v3uint = OpTypePointer Input %v3uint + %void = OpTypeVoid + %23 = OpTypeFunction %void +%_ptr_Function_float = OpTypePointer Function %float +%_ptr_Uniform_float = OpTypePointer Uniform %float + %27 = OpVariable %_ptr_Workgroup__struct_17 Workgroup + %5 = OpVariable %_ptr_Uniform__struct_7 Uniform +%gl_GlobalInvocationID = OpVariable %_ptr_Input_v3uint Input +%gl_LocalInvocationID = OpVariable %_ptr_Input_v3uint Input +%gl_WorkGroupID = OpVariable %_ptr_Input_v3uint Input + %1 = OpFunction %void None %23 + %28 = OpLabel + %29 = OpLoad %v3uint %gl_LocalInvocationID + %30 = OpAccessChain %_ptr_Workgroup__arr_float_uint_10 %27 %int_0 %int_0 + %31 = OpAccessChain %_ptr_Function_float %30 %int_0 + %32 = OpLoad %float %31 + %33 = OpFMul %float %float_2 %32 + OpStore %31 %33 + %34 = OpLoad %float %31 + %35 = OpCompositeExtract %uint %29 0 + %36 = OpAccessChain %_ptr_Uniform_float %5 %int_0 %35 + OpStore %36 %34 + OpReturn + OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, false); +} + +using FixTypeTest = PassTest<::testing::Test>; + +TEST_F(FixTypeTest, FixAccessChain) { + const std::string text = R"( +; CHECK: [[ac1:%\w+]] = OpAccessChain %_ptr_Uniform_S %A %int_0 %uint_0 +; CHECK: [[ac2:%\w+]] = OpAccessChain %_ptr_Uniform_T [[ac1]] %int_0 + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" + OpExecutionMode %main LocalSize 1 1 1 + OpSource HLSL 600 + OpName %type_RWStructuredBuffer_S "type.RWStructuredBuffer.S" + OpName %S "S" + OpMemberName %S 0 "t" + OpName %T "T" + OpMemberName %T 0 "a" + OpName %A "A" + OpName %type_ACSBuffer_counter "type.ACSBuffer.counter" + OpMemberName %type_ACSBuffer_counter 0 "counter" + OpName %counter_var_A "counter.var.A" + OpName %main "main" + OpName %S_0 "S" + OpMemberName %S_0 0 "t" + OpName %T_0 "T" + OpMemberName %T_0 0 "a" + OpDecorate %A DescriptorSet 0 + OpDecorate %A Binding 0 + OpDecorate %counter_var_A DescriptorSet 0 + OpDecorate %counter_var_A Binding 1 + OpMemberDecorate %T 0 Offset 0 + OpMemberDecorate %S 0 Offset 0 + OpDecorate %_runtimearr_S ArrayStride 4 + OpMemberDecorate %type_RWStructuredBuffer_S 0 Offset 0 + OpDecorate %type_RWStructuredBuffer_S BufferBlock + OpMemberDecorate %type_ACSBuffer_counter 0 Offset 0 + OpDecorate %type_ACSBuffer_counter BufferBlock + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 + %uint = OpTypeInt 32 0 + %uint_0 = OpConstant %uint 0 + %T = OpTypeStruct %int + %S = OpTypeStruct %T +%_runtimearr_S = OpTypeRuntimeArray %S +%type_RWStructuredBuffer_S = OpTypeStruct %_runtimearr_S +%_ptr_Uniform_type_RWStructuredBuffer_S = OpTypePointer Uniform %type_RWStructuredBuffer_S +%type_ACSBuffer_counter = OpTypeStruct %int +%_ptr_Uniform_type_ACSBuffer_counter = OpTypePointer Uniform %type_ACSBuffer_counter + %void = OpTypeVoid + %18 = OpTypeFunction %void + %T_0 = OpTypeStruct %int + %S_0 = OpTypeStruct %T_0 +%_ptr_Function_S_0 = OpTypePointer Function %S_0 +%_ptr_Uniform_S = OpTypePointer Uniform %S +%_ptr_Uniform_T = OpTypePointer Uniform %T + %22 = OpTypeFunction %T_0 %_ptr_Function_S_0 +%_ptr_Function_T_0 = OpTypePointer Function %T_0 + %A = OpVariable %_ptr_Uniform_type_RWStructuredBuffer_S Uniform +%counter_var_A = OpVariable %_ptr_Uniform_type_ACSBuffer_counter Uniform + %main = OpFunction %void None %18 + %24 = OpLabel + %25 = OpVariable %_ptr_Function_T_0 Function + %26 = OpVariable %_ptr_Function_S_0 Function + %27 = OpAccessChain %_ptr_Uniform_S %A %int_0 %uint_0 + %28 = OpAccessChain %_ptr_Function_T_0 %27 %int_0 + OpReturn + OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, false); +} + +TEST_F(FixTypeTest, FixLoad) { + const std::string text = R"( +; CHECK: [[ac1:%\w+]] = OpAccessChain %_ptr_Uniform_S %A %int_0 %uint_0 +; CHECK: [[ac2:%\w+]] = OpAccessChain %_ptr_Uniform_T [[ac1]] %int_0 +; CHECK: [[ld:%\w+]] = OpLoad %T [[ac2]] + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" + OpExecutionMode %main LocalSize 1 1 1 + OpSource HLSL 600 + OpName %type_RWStructuredBuffer_S "type.RWStructuredBuffer.S" + OpName %S "S" + OpMemberName %S 0 "t" + OpName %T "T" + OpMemberName %T 0 "a" + OpName %A "A" + OpName %type_ACSBuffer_counter "type.ACSBuffer.counter" + OpMemberName %type_ACSBuffer_counter 0 "counter" + OpName %counter_var_A "counter.var.A" + OpName %main "main" + OpName %S_0 "S" + OpMemberName %S_0 0 "t" + OpName %T_0 "T" + OpMemberName %T_0 0 "a" + OpDecorate %A DescriptorSet 0 + OpDecorate %A Binding 0 + OpDecorate %counter_var_A DescriptorSet 0 + OpDecorate %counter_var_A Binding 1 + OpMemberDecorate %T 0 Offset 0 + OpMemberDecorate %S 0 Offset 0 + OpDecorate %_runtimearr_S ArrayStride 4 + OpMemberDecorate %type_RWStructuredBuffer_S 0 Offset 0 + OpDecorate %type_RWStructuredBuffer_S BufferBlock + OpMemberDecorate %type_ACSBuffer_counter 0 Offset 0 + OpDecorate %type_ACSBuffer_counter BufferBlock + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 + %uint = OpTypeInt 32 0 + %uint_0 = OpConstant %uint 0 + %T = OpTypeStruct %int + %S = OpTypeStruct %T +%_runtimearr_S = OpTypeRuntimeArray %S +%type_RWStructuredBuffer_S = OpTypeStruct %_runtimearr_S +%_ptr_Uniform_type_RWStructuredBuffer_S = OpTypePointer Uniform %type_RWStructuredBuffer_S +%type_ACSBuffer_counter = OpTypeStruct %int +%_ptr_Uniform_type_ACSBuffer_counter = OpTypePointer Uniform %type_ACSBuffer_counter + %void = OpTypeVoid + %18 = OpTypeFunction %void + %T_0 = OpTypeStruct %int + %S_0 = OpTypeStruct %T_0 +%_ptr_Function_S_0 = OpTypePointer Function %S_0 +%_ptr_Uniform_S = OpTypePointer Uniform %S +%_ptr_Uniform_T = OpTypePointer Uniform %T + %22 = OpTypeFunction %T_0 %_ptr_Function_S_0 +%_ptr_Function_T_0 = OpTypePointer Function %T_0 + %A = OpVariable %_ptr_Uniform_type_RWStructuredBuffer_S Uniform +%counter_var_A = OpVariable %_ptr_Uniform_type_ACSBuffer_counter Uniform + %main = OpFunction %void None %18 + %24 = OpLabel + %25 = OpVariable %_ptr_Function_T_0 Function + %26 = OpVariable %_ptr_Function_S_0 Function + %27 = OpAccessChain %_ptr_Uniform_S %A %int_0 %uint_0 + %28 = OpAccessChain %_ptr_Uniform_T %27 %int_0 + %29 = OpLoad %T_0 %28 + OpReturn + OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, false); +} + +TEST_F(FixTypeTest, FixStore) { + const std::string text = R"( +; CHECK: [[ld:%\w+]] = OpLoad %T +; CHECK: OpStore + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" + OpExecutionMode %main LocalSize 1 1 1 + OpSource HLSL 600 + OpName %type_RWStructuredBuffer_S "type.RWStructuredBuffer.S" + OpName %S "S" + OpMemberName %S 0 "t" + OpName %T "T" + OpMemberName %T 0 "a" + OpName %A "A" + OpName %type_ACSBuffer_counter "type.ACSBuffer.counter" + OpMemberName %type_ACSBuffer_counter 0 "counter" + OpName %counter_var_A "counter.var.A" + OpName %main "main" + OpName %S_0 "S" + OpMemberName %S_0 0 "t" + OpName %T_0 "T" + OpMemberName %T_0 0 "a" + OpDecorate %A DescriptorSet 0 + OpDecorate %A Binding 0 + OpDecorate %counter_var_A DescriptorSet 0 + OpDecorate %counter_var_A Binding 1 + OpMemberDecorate %T 0 Offset 0 + OpMemberDecorate %S 0 Offset 0 + OpDecorate %_runtimearr_S ArrayStride 4 + OpMemberDecorate %type_RWStructuredBuffer_S 0 Offset 0 + OpDecorate %type_RWStructuredBuffer_S BufferBlock + OpMemberDecorate %type_ACSBuffer_counter 0 Offset 0 + OpDecorate %type_ACSBuffer_counter BufferBlock + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 + %uint = OpTypeInt 32 0 + %uint_0 = OpConstant %uint 0 + %T = OpTypeStruct %int + %S = OpTypeStruct %T +%_runtimearr_S = OpTypeRuntimeArray %S +%type_RWStructuredBuffer_S = OpTypeStruct %_runtimearr_S +%_ptr_Uniform_type_RWStructuredBuffer_S = OpTypePointer Uniform %type_RWStructuredBuffer_S +%type_ACSBuffer_counter = OpTypeStruct %int +%_ptr_Uniform_type_ACSBuffer_counter = OpTypePointer Uniform %type_ACSBuffer_counter + %void = OpTypeVoid + %18 = OpTypeFunction %void + %T_0 = OpTypeStruct %int + %S_0 = OpTypeStruct %T_0 +%_ptr_Function_S_0 = OpTypePointer Function %S_0 +%_ptr_Uniform_S = OpTypePointer Uniform %S +%_ptr_Uniform_T = OpTypePointer Uniform %T + %22 = OpTypeFunction %T_0 %_ptr_Function_S_0 +%_ptr_Function_T_0 = OpTypePointer Function %T_0 + %A = OpVariable %_ptr_Uniform_type_RWStructuredBuffer_S Uniform +%counter_var_A = OpVariable %_ptr_Uniform_type_ACSBuffer_counter Uniform + %main = OpFunction %void None %18 + %24 = OpLabel + %25 = OpVariable %_ptr_Function_T_0 Function + %26 = OpVariable %_ptr_Function_S_0 Function + %27 = OpAccessChain %_ptr_Uniform_S %A %int_0 %uint_0 + %28 = OpAccessChain %_ptr_Uniform_T %27 %int_0 + %29 = OpLoad %T %28 + OpStore %25 %29 + OpReturn + OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, false); +} + +TEST_F(FixTypeTest, FixSelect) { + const std::string text = R"( +; CHECK: OpSelect %_ptr_Uniform__struct_3 + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "main" + OpExecutionMode %1 LocalSize 1 1 1 + OpSource HLSL 600 + OpDecorate %2 DescriptorSet 0 + OpDecorate %2 Binding 0 + OpMemberDecorate %_struct_3 0 Offset 0 + OpDecorate %_runtimearr__struct_3 ArrayStride 4 + OpMemberDecorate %_struct_5 0 Offset 0 + OpDecorate %_struct_5 BufferBlock + %uint = OpTypeInt 32 0 + %uint_0 = OpConstant %uint 0 + %uint_1 = OpConstant %uint 1 + %_struct_3 = OpTypeStruct %uint +%_runtimearr__struct_3 = OpTypeRuntimeArray %_struct_3 + %_struct_5 = OpTypeStruct %_runtimearr__struct_3 +%_ptr_Uniform__struct_5 = OpTypePointer Uniform %_struct_5 + %void = OpTypeVoid + %11 = OpTypeFunction %void + %_struct_12 = OpTypeStruct %uint +%_ptr_Function__struct_12 = OpTypePointer Function %_struct_12 +%_ptr_Uniform_uint = OpTypePointer Uniform %uint + %bool = OpTypeBool +%_ptr_Uniform__struct_3 = OpTypePointer Uniform %_struct_3 + %2 = OpVariable %_ptr_Uniform__struct_5 Uniform + %1 = OpFunction %void None %11 + %17 = OpLabel + %18 = OpAccessChain %_ptr_Uniform_uint %2 %uint_0 %uint_0 %uint_0 + %19 = OpLoad %uint %18 + %20 = OpSGreaterThan %bool %19 %uint_0 + %21 = OpAccessChain %_ptr_Uniform__struct_3 %2 %uint_0 %uint_0 + %22 = OpAccessChain %_ptr_Uniform__struct_3 %2 %uint_0 %uint_1 + %23 = OpSelect %_ptr_Function__struct_12 %20 %21 %22 + OpReturn + OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, false); +} + +TEST_F(FixTypeTest, FixPhiInLoop) { + const std::string text = R"( +; CHECK: [[ac_init:%\w+]] = OpAccessChain %_ptr_Uniform__struct_3 +; CHECK: [[ac_phi:%\w+]] = OpPhi %_ptr_Uniform__struct_3 [[ac_init]] {{%\w+}} [[ac_update:%\w+]] {{%\w+}} +; CHECK: [[ac_update]] = OpPtrAccessChain %_ptr_Uniform__struct_3 [[ac_phi]] %int_1 + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "main" + OpExecutionMode %1 LocalSize 1 1 1 + OpSource HLSL 600 + OpDecorate %2 DescriptorSet 0 + OpDecorate %2 Binding 0 + OpMemberDecorate %_struct_3 0 Offset 0 + OpDecorate %_runtimearr__struct_3 ArrayStride 4 + OpMemberDecorate %_struct_5 0 Offset 0 + OpDecorate %_struct_5 BufferBlock + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 + %int_1 = OpConstant %int 1 + %_struct_3 = OpTypeStruct %int + %_struct_9 = OpTypeStruct %int +%_runtimearr__struct_3 = OpTypeRuntimeArray %_struct_3 + %_struct_5 = OpTypeStruct %_runtimearr__struct_3 +%_ptr_Uniform__struct_5 = OpTypePointer Uniform %_struct_5 + %void = OpTypeVoid + %12 = OpTypeFunction %void + %bool = OpTypeBool +%_ptr_Uniform__struct_3 = OpTypePointer Uniform %_struct_3 +%_ptr_Function__struct_9 = OpTypePointer Function %_struct_9 + %2 = OpVariable %_ptr_Uniform__struct_5 Uniform + %1 = OpFunction %void None %12 + %16 = OpLabel + %17 = OpAccessChain %_ptr_Uniform__struct_3 %2 %int_0 %int_0 + OpBranch %18 + %18 = OpLabel + %20 = OpPhi %_ptr_Function__struct_9 %17 %16 %21 %22 + %23 = OpUndef %bool + OpLoopMerge %24 %22 None + OpBranchConditional %23 %22 %24 + %22 = OpLabel + %21 = OpPtrAccessChain %_ptr_Function__struct_9 %20 %int_1 + OpBranch %18 + %24 = OpLabel + OpReturn + OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, false); +} + +} // namespace +} // namespace opt +} // namespace spvtools diff --git a/third_party/spirv-tools/test/opt/flatten_decoration_test.cpp b/third_party/spirv-tools/test/opt/flatten_decoration_test.cpp index 483ee6e53c..d8d8867715 100644 --- a/third_party/spirv-tools/test/opt/flatten_decoration_test.cpp +++ b/third_party/spirv-tools/test/opt/flatten_decoration_test.cpp @@ -31,6 +31,7 @@ std::string PreambleAssembly() { R"(OpCapability Shader OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %main "main" %hue %saturation %value +OpExecutionMode %main OriginUpperLeft OpName %main "main" OpName %void_fn "void_fn" OpName %hue "hue" @@ -80,158 +81,158 @@ TEST_P(FlattenDecorationTest, TransformsDecorations) { SinglePassRunAndCheck(before, after, false, true); } -INSTANTIATE_TEST_CASE_P(NoUses, FlattenDecorationTest, - ::testing::ValuesIn(std::vector{ - // No OpDecorationGroup - {"", ""}, +INSTANTIATE_TEST_SUITE_P(NoUses, FlattenDecorationTest, + ::testing::ValuesIn(std::vector{ + // No OpDecorationGroup + {"", ""}, - // OpDecorationGroup without any uses, and - // no OpName. - {"%group = OpDecorationGroup\n", ""}, + // OpDecorationGroup without any uses, and + // no OpName. + {"%group = OpDecorationGroup\n", ""}, - // OpDecorationGroup without any uses, and - // with OpName targeting it. Proves you must - // remove the names as well. - {"OpName %group \"group\"\n" - "%group = OpDecorationGroup\n", - ""}, + // OpDecorationGroup without any uses, and + // with OpName targeting it. Proves you must + // remove the names as well. + {"OpName %group \"group\"\n" + "%group = OpDecorationGroup\n", + ""}, - // OpDecorationGroup with decorations that - // target it, but no uses in OpGroupDecorate - // or OpGroupMemberDecorate instructions. - {"OpDecorate %group Flat\n" - "OpDecorate %group NoPerspective\n" - "%group = OpDecorationGroup\n", - ""}, - }), ); + // OpDecorationGroup with decorations that + // target it, but no uses in OpGroupDecorate + // or OpGroupMemberDecorate instructions. + {"OpDecorate %group Flat\n" + "OpDecorate %group NoPerspective\n" + "%group = OpDecorationGroup\n", + ""}, + })); -INSTANTIATE_TEST_CASE_P(OpGroupDecorate, FlattenDecorationTest, - ::testing::ValuesIn(std::vector{ - // One OpGroupDecorate - {"OpName %group \"group\"\n" - "OpDecorate %group Flat\n" - "OpDecorate %group NoPerspective\n" - "%group = OpDecorationGroup\n" - "OpGroupDecorate %group %hue %saturation\n", - "OpDecorate %hue Flat\n" - "OpDecorate %saturation Flat\n" - "OpDecorate %hue NoPerspective\n" - "OpDecorate %saturation NoPerspective\n"}, - // Multiple OpGroupDecorate - {"OpName %group \"group\"\n" - "OpDecorate %group Flat\n" - "OpDecorate %group NoPerspective\n" - "%group = OpDecorationGroup\n" - "OpGroupDecorate %group %hue %value\n" - "OpGroupDecorate %group %saturation\n", - "OpDecorate %hue Flat\n" - "OpDecorate %value Flat\n" - "OpDecorate %saturation Flat\n" - "OpDecorate %hue NoPerspective\n" - "OpDecorate %value NoPerspective\n" - "OpDecorate %saturation NoPerspective\n"}, - // Two group decorations, interleaved - {"OpName %group0 \"group0\"\n" - "OpName %group1 \"group1\"\n" - "OpDecorate %group0 Flat\n" - "OpDecorate %group1 NoPerspective\n" - "%group0 = OpDecorationGroup\n" - "%group1 = OpDecorationGroup\n" - "OpGroupDecorate %group0 %hue %value\n" - "OpGroupDecorate %group1 %saturation\n", - "OpDecorate %hue Flat\n" - "OpDecorate %value Flat\n" - "OpDecorate %saturation NoPerspective\n"}, - // Decoration with operands - {"OpName %group \"group\"\n" - "OpDecorate %group Location 42\n" - "%group = OpDecorationGroup\n" - "OpGroupDecorate %group %hue %saturation\n", - "OpDecorate %hue Location 42\n" - "OpDecorate %saturation Location 42\n"}, - }), ); +INSTANTIATE_TEST_SUITE_P(OpGroupDecorate, FlattenDecorationTest, + ::testing::ValuesIn(std::vector{ + // One OpGroupDecorate + {"OpName %group \"group\"\n" + "OpDecorate %group Flat\n" + "OpDecorate %group NoPerspective\n" + "%group = OpDecorationGroup\n" + "OpGroupDecorate %group %hue %saturation\n", + "OpDecorate %hue Flat\n" + "OpDecorate %saturation Flat\n" + "OpDecorate %hue NoPerspective\n" + "OpDecorate %saturation NoPerspective\n"}, + // Multiple OpGroupDecorate + {"OpName %group \"group\"\n" + "OpDecorate %group Flat\n" + "OpDecorate %group NoPerspective\n" + "%group = OpDecorationGroup\n" + "OpGroupDecorate %group %hue %value\n" + "OpGroupDecorate %group %saturation\n", + "OpDecorate %hue Flat\n" + "OpDecorate %value Flat\n" + "OpDecorate %saturation Flat\n" + "OpDecorate %hue NoPerspective\n" + "OpDecorate %value NoPerspective\n" + "OpDecorate %saturation NoPerspective\n"}, + // Two group decorations, interleaved + {"OpName %group0 \"group0\"\n" + "OpName %group1 \"group1\"\n" + "OpDecorate %group0 Flat\n" + "OpDecorate %group1 NoPerspective\n" + "%group0 = OpDecorationGroup\n" + "%group1 = OpDecorationGroup\n" + "OpGroupDecorate %group0 %hue %value\n" + "OpGroupDecorate %group1 %saturation\n", + "OpDecorate %hue Flat\n" + "OpDecorate %value Flat\n" + "OpDecorate %saturation NoPerspective\n"}, + // Decoration with operands + {"OpName %group \"group\"\n" + "OpDecorate %group Location 42\n" + "%group = OpDecorationGroup\n" + "OpGroupDecorate %group %hue %saturation\n", + "OpDecorate %hue Location 42\n" + "OpDecorate %saturation Location 42\n"}, + })); -INSTANTIATE_TEST_CASE_P(OpGroupMemberDecorate, FlattenDecorationTest, - ::testing::ValuesIn(std::vector{ - // One OpGroupMemberDecorate - {"OpName %group \"group\"\n" - "OpDecorate %group Flat\n" - "OpDecorate %group Offset 16\n" - "%group = OpDecorationGroup\n" - "OpGroupMemberDecorate %group %Point 1\n", - "OpMemberDecorate %Point 1 Flat\n" - "OpMemberDecorate %Point 1 Offset 16\n"}, - // Multiple OpGroupMemberDecorate using the same - // decoration group. - {"OpName %group \"group\"\n" - "OpDecorate %group Flat\n" - "OpDecorate %group NoPerspective\n" - "OpDecorate %group Offset 8\n" - "%group = OpDecorationGroup\n" - "OpGroupMemberDecorate %group %Point 2\n" - "OpGroupMemberDecorate %group %Camera 1\n", - "OpMemberDecorate %Point 2 Flat\n" - "OpMemberDecorate %Camera 1 Flat\n" - "OpMemberDecorate %Point 2 NoPerspective\n" - "OpMemberDecorate %Camera 1 NoPerspective\n" - "OpMemberDecorate %Point 2 Offset 8\n" - "OpMemberDecorate %Camera 1 Offset 8\n"}, - // Two groups of member decorations, interleaved. - // Decoration is with and without operands. - {"OpName %group0 \"group0\"\n" - "OpName %group1 \"group1\"\n" - "OpDecorate %group0 Flat\n" - "OpDecorate %group0 Offset 8\n" - "OpDecorate %group1 NoPerspective\n" - "OpDecorate %group1 Offset 16\n" - "%group0 = OpDecorationGroup\n" - "%group1 = OpDecorationGroup\n" - "OpGroupMemberDecorate %group0 %Point 0\n" - "OpGroupMemberDecorate %group1 %Point 2\n", - "OpMemberDecorate %Point 0 Flat\n" - "OpMemberDecorate %Point 0 Offset 8\n" - "OpMemberDecorate %Point 2 NoPerspective\n" - "OpMemberDecorate %Point 2 Offset 16\n"}, - }), ); +INSTANTIATE_TEST_SUITE_P(OpGroupMemberDecorate, FlattenDecorationTest, + ::testing::ValuesIn(std::vector{ + // One OpGroupMemberDecorate + {"OpName %group \"group\"\n" + "OpDecorate %group Flat\n" + "OpDecorate %group Offset 16\n" + "%group = OpDecorationGroup\n" + "OpGroupMemberDecorate %group %Point 1\n", + "OpMemberDecorate %Point 1 Flat\n" + "OpMemberDecorate %Point 1 Offset 16\n"}, + // Multiple OpGroupMemberDecorate using the same + // decoration group. + {"OpName %group \"group\"\n" + "OpDecorate %group Flat\n" + "OpDecorate %group NoPerspective\n" + "OpDecorate %group Offset 8\n" + "%group = OpDecorationGroup\n" + "OpGroupMemberDecorate %group %Point 2\n" + "OpGroupMemberDecorate %group %Camera 1\n", + "OpMemberDecorate %Point 2 Flat\n" + "OpMemberDecorate %Camera 1 Flat\n" + "OpMemberDecorate %Point 2 NoPerspective\n" + "OpMemberDecorate %Camera 1 NoPerspective\n" + "OpMemberDecorate %Point 2 Offset 8\n" + "OpMemberDecorate %Camera 1 Offset 8\n"}, + // Two groups of member decorations, interleaved. + // Decoration is with and without operands. + {"OpName %group0 \"group0\"\n" + "OpName %group1 \"group1\"\n" + "OpDecorate %group0 Flat\n" + "OpDecorate %group0 Offset 8\n" + "OpDecorate %group1 NoPerspective\n" + "OpDecorate %group1 Offset 16\n" + "%group0 = OpDecorationGroup\n" + "%group1 = OpDecorationGroup\n" + "OpGroupMemberDecorate %group0 %Point 0\n" + "OpGroupMemberDecorate %group1 %Point 2\n", + "OpMemberDecorate %Point 0 Flat\n" + "OpMemberDecorate %Point 0 Offset 8\n" + "OpMemberDecorate %Point 2 NoPerspective\n" + "OpMemberDecorate %Point 2 Offset 16\n"}, + })); -INSTANTIATE_TEST_CASE_P(UnrelatedDecorations, FlattenDecorationTest, - ::testing::ValuesIn(std::vector{ - // A non-group non-member decoration is untouched. - {"OpDecorate %hue Centroid\n" - "OpDecorate %saturation Flat\n", - "OpDecorate %hue Centroid\n" - "OpDecorate %saturation Flat\n"}, - // A non-group member decoration is untouched. - {"OpMemberDecorate %Point 0 Offset 0\n" - "OpMemberDecorate %Point 1 Offset 4\n" - "OpMemberDecorate %Point 1 Flat\n", - "OpMemberDecorate %Point 0 Offset 0\n" - "OpMemberDecorate %Point 1 Offset 4\n" - "OpMemberDecorate %Point 1 Flat\n"}, - // A non-group non-member decoration survives any - // replacement of group decorations. - {"OpName %group \"group\"\n" - "OpDecorate %group Flat\n" - "OpDecorate %hue Centroid\n" - "OpDecorate %group NoPerspective\n" - "%group = OpDecorationGroup\n" - "OpGroupDecorate %group %hue %saturation\n", - "OpDecorate %hue Flat\n" - "OpDecorate %saturation Flat\n" - "OpDecorate %hue Centroid\n" - "OpDecorate %hue NoPerspective\n" - "OpDecorate %saturation NoPerspective\n"}, - // A non-group member decoration survives any - // replacement of group decorations. - {"OpDecorate %group Offset 0\n" - "OpDecorate %group Flat\n" - "OpMemberDecorate %Point 1 Offset 4\n" - "%group = OpDecorationGroup\n" - "OpGroupMemberDecorate %group %Point 0\n", - "OpMemberDecorate %Point 0 Offset 0\n" - "OpMemberDecorate %Point 0 Flat\n" - "OpMemberDecorate %Point 1 Offset 4\n"}, - }), ); +INSTANTIATE_TEST_SUITE_P(UnrelatedDecorations, FlattenDecorationTest, + ::testing::ValuesIn(std::vector{ + // A non-group non-member decoration is untouched. + {"OpDecorate %hue Centroid\n" + "OpDecorate %saturation Flat\n", + "OpDecorate %hue Centroid\n" + "OpDecorate %saturation Flat\n"}, + // A non-group member decoration is untouched. + {"OpMemberDecorate %Point 0 Offset 0\n" + "OpMemberDecorate %Point 1 Offset 4\n" + "OpMemberDecorate %Point 1 Flat\n", + "OpMemberDecorate %Point 0 Offset 0\n" + "OpMemberDecorate %Point 1 Offset 4\n" + "OpMemberDecorate %Point 1 Flat\n"}, + // A non-group non-member decoration survives any + // replacement of group decorations. + {"OpName %group \"group\"\n" + "OpDecorate %group Flat\n" + "OpDecorate %hue Centroid\n" + "OpDecorate %group NoPerspective\n" + "%group = OpDecorationGroup\n" + "OpGroupDecorate %group %hue %saturation\n", + "OpDecorate %hue Flat\n" + "OpDecorate %saturation Flat\n" + "OpDecorate %hue Centroid\n" + "OpDecorate %hue NoPerspective\n" + "OpDecorate %saturation NoPerspective\n"}, + // A non-group member decoration survives any + // replacement of group decorations. + {"OpDecorate %group Offset 0\n" + "OpDecorate %group Flat\n" + "OpMemberDecorate %Point 1 Offset 4\n" + "%group = OpDecorationGroup\n" + "OpGroupMemberDecorate %group %Point 0\n", + "OpMemberDecorate %Point 0 Offset 0\n" + "OpMemberDecorate %Point 0 Flat\n" + "OpMemberDecorate %Point 1 Offset 4\n"}, + })); } // namespace } // namespace opt diff --git a/third_party/spirv-tools/test/opt/fold_spec_const_op_composite_test.cpp b/third_party/spirv-tools/test/opt/fold_spec_const_op_composite_test.cpp index 8ecfd5c788..7eddf7e99f 100644 --- a/third_party/spirv-tools/test/opt/fold_spec_const_op_composite_test.cpp +++ b/third_party/spirv-tools/test/opt/fold_spec_const_op_composite_test.cpp @@ -112,8 +112,12 @@ std::vector CommonTypesAndConstants() { // clang-format off // scalar types "%bool = OpTypeBool", + "%ushort = OpTypeInt 16 0", + "%short = OpTypeInt 16 1", "%uint = OpTypeInt 32 0", "%int = OpTypeInt 32 1", + "%ulong = OpTypeInt 64 0", + "%long = OpTypeInt 64 1", "%float = OpTypeFloat 32", "%double = OpTypeFloat 64", // vector types @@ -122,6 +126,8 @@ std::vector CommonTypesAndConstants() { "%v2int = OpTypeVector %int 2", "%v3int = OpTypeVector %int 3", "%v4int = OpTypeVector %int 4", + "%v2long = OpTypeVector %long 2", + "%v2ulong = OpTypeVector %ulong 2", "%v2float = OpTypeVector %float 2", "%v2double = OpTypeVector %double 2", // variable pointer types @@ -145,6 +151,8 @@ std::vector CommonTypesAndConstants() { "%bool_null = OpConstantNull %bool", "%signed_zero = OpConstant %int 0", "%unsigned_zero = OpConstant %uint 0", + "%long_zero = OpConstant %long 0", + "%ulong_zero = OpConstant %ulong 0", "%signed_one = OpConstant %int 1", "%unsigned_one = OpConstant %uint 1", "%signed_two = OpConstant %int 2", @@ -153,6 +161,7 @@ std::vector CommonTypesAndConstants() { "%unsigned_three = OpConstant %uint 3", "%signed_null = OpConstantNull %int", "%unsigned_null = OpConstantNull %uint", + "%signed_minus_one = OpConstant %int -1", // vector constants: "%bool_true_vec = OpConstantComposite %v2bool %bool_true %bool_true", "%bool_false_vec = OpConstantComposite %v2bool %bool_false %bool_false", @@ -167,6 +176,7 @@ std::vector CommonTypesAndConstants() { "%unsigned_three_vec = OpConstantComposite %v2uint %unsigned_three %unsigned_three", "%signed_null_vec = OpConstantNull %v2int", "%unsigned_null_vec = OpConstantNull %v2uint", + "%signed_minus_one_vec = OpConstantComposite %v2int %signed_minus_one %signed_minus_one", "%v4int_0_1_2_3 = OpConstantComposite %v4int %signed_zero %signed_one %signed_two %signed_three", // clang-format on }; @@ -224,7 +234,7 @@ TEST_P(FoldSpecConstantOpAndCompositePassTest, ParamTestCase) { // Tests that OpSpecConstantComposite opcodes are replace with // OpConstantComposite correctly. -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( Composite, FoldSpecConstantOpAndCompositePassTest, ::testing::ValuesIn(std::vector< FoldSpecConstantOpAndCompositePassTestCase>({ @@ -325,16 +335,29 @@ INSTANTIATE_TEST_CASE_P( "%inner = OpConstantComposite %inner_struct %bool_true %signed_one %undef", "%outer = OpSpecConstantComposite %outer_struct %inner %signed_one", }, + }, + // Fold an QuantizetoF16 instruction + { + // original + { + "%float_1 = OpConstant %float 1", + "%quant_float = OpSpecConstantOp %float QuantizeToF16 %float_1", + }, + // expected + { + "%float_1 = OpConstant %float 1", + "%quant_float = OpConstant %float 1", + }, } // clang-format on }))); // Tests for operations that resulting in different types. -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( Cast, FoldSpecConstantOpAndCompositePassTest, - ::testing::ValuesIn( - std::vector({ - // clang-format off + ::testing::ValuesIn(std::vector< + FoldSpecConstantOpAndCompositePassTestCase>({ + // clang-format off // int -> bool scalar { // original @@ -562,12 +585,112 @@ INSTANTIATE_TEST_CASE_P( "%spec_uint_from_null = OpConstantComposite %v2uint %unsigned_zero %unsigned_zero", }, }, - // clang-format on - }))); + + // UConvert scalar + { + // original + { + "%spec_uint_zero = OpSpecConstantOp %uint UConvert %bool_false", + "%spec_uint_one = OpSpecConstantOp %uint UConvert %bool_true", + "%spec_ulong_zero = OpSpecConstantOp %ulong UConvert %unsigned_zero", + "%spec_ulong_one = OpSpecConstantOp %ulong UConvert %unsigned_one", + "%spec_short_zero = OpSpecConstantOp %ushort UConvert %unsigned_zero", + "%spec_short_one = OpSpecConstantOp %ushort UConvert %unsigned_one", + "%uint_max = OpConstant %uint 4294967295", + "%spec_ushort_max = OpSpecConstantOp %ushort UConvert %uint_max", + "%uint_0xDDDDDDDD = OpConstant %uint 3722304989", + "%spec_ushort_0xDDDD = OpSpecConstantOp %ushort UConvert %uint_0xDDDDDDDD", + }, + // expected + { + "%spec_uint_zero = OpConstant %uint 0", + "%spec_uint_one = OpConstant %uint 1", + "%spec_ulong_zero = OpConstant %ulong 0", + "%spec_ulong_one = OpConstant %ulong 1", + "%spec_short_zero = OpConstant %ushort 0", + "%spec_short_one = OpConstant %ushort 1", + "%uint_max = OpConstant %uint 4294967295", + "%spec_ushort_max = OpConstant %ushort 65535", + "%uint_0xDDDDDDDD = OpConstant %uint 3722304989", + "%spec_ushort_0xDDDD = OpConstant %ushort 56797", + }, + }, + + // SConvert scalar + { + // original + { + "%spec_long_zero = OpSpecConstantOp %long SConvert %signed_zero", + "%spec_long_one = OpSpecConstantOp %long SConvert %signed_one", + "%spec_long_minus_one = OpSpecConstantOp %long SConvert %signed_minus_one", + "%spec_short_minus_one_trunc = OpSpecConstantOp %short SConvert %signed_minus_one", + "%int_2_to_17_minus_one = OpConstant %int 131071", + "%spec_short_minus_one_trunc2 = OpSpecConstantOp %short SConvert %int_2_to_17_minus_one", + }, + // expected + { + "%spec_long_zero = OpConstant %long 0", + "%spec_long_one = OpConstant %long 1", + "%spec_long_minus_one = OpConstant %long -1", + "%spec_short_minus_one_trunc = OpConstant %short -1", + "%int_2_to_17_minus_one = OpConstant %int 131071", + "%spec_short_minus_one_trunc2 = OpConstant %short -1", + }, + }, + + // UConvert vector + { + // original + { + "%spec_v2uint_zero = OpSpecConstantOp %v2uint UConvert %bool_false_vec", + "%spec_v2uint_one = OpSpecConstantOp %v2uint UConvert %bool_true_vec", + "%spec_v2ulong_zero = OpSpecConstantOp %v2ulong UConvert %unsigned_zero_vec", + "%spec_v2ulong_one = OpSpecConstantOp %v2ulong UConvert %unsigned_one_vec", + }, + // expected + { + "%uint_0 = OpConstant %uint 0", + "%uint_0_0 = OpConstant %uint 0", + "%spec_v2uint_zero = OpConstantComposite %v2uint %unsigned_zero %unsigned_zero", + "%uint_1 = OpConstant %uint 1", + "%uint_1_0 = OpConstant %uint 1", + "%spec_v2uint_one = OpConstantComposite %v2uint %unsigned_one %unsigned_one", + "%ulong_0 = OpConstant %ulong 0", + "%ulong_0_0 = OpConstant %ulong 0", + "%spec_v2ulong_zero = OpConstantComposite %v2ulong %ulong_zero %ulong_zero", + "%ulong_1 = OpConstant %ulong 1", + "%ulong_1_0 = OpConstant %ulong 1", + "%spec_v2ulong_one = OpConstantComposite %v2ulong %ulong_1 %ulong_1", + }, + }, + + // SConvert vector + { + // original + { + "%spec_v2long_zero = OpSpecConstantOp %v2long SConvert %signed_zero_vec", + "%spec_v2long_one = OpSpecConstantOp %v2long SConvert %signed_one_vec", + "%spec_v2long_minus_one = OpSpecConstantOp %v2long SConvert %signed_minus_one_vec", + }, + // expected + { + "%long_0 = OpConstant %long 0", + "%long_0_0 = OpConstant %long 0", + "%spec_v2long_zero = OpConstantComposite %v2long %long_zero %long_zero", + "%long_1 = OpConstant %long 1", + "%long_1_0 = OpConstant %long 1", + "%spec_v2long_one = OpConstantComposite %v2long %long_1 %long_1", + "%long_n1 = OpConstant %long -1", + "%long_n1_0 = OpConstant %long -1", + "%spec_v2long_minus_one = OpConstantComposite %v2long %long_n1 %long_n1", + }, + }, + // clang-format on + }))); // Tests about boolean scalar logical operations and comparison operations with // scalar int/uint type. -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( Logical, FoldSpecConstantOpAndCompositePassTest, ::testing::ValuesIn(std::vector< FoldSpecConstantOpAndCompositePassTestCase>({ @@ -636,7 +759,7 @@ INSTANTIATE_TEST_CASE_P( }))); // Tests about arithmetic operations for scalar int and uint types. -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( ScalarArithmetic, FoldSpecConstantOpAndCompositePassTest, ::testing::ValuesIn(std::vector< FoldSpecConstantOpAndCompositePassTestCase>({ @@ -821,7 +944,7 @@ INSTANTIATE_TEST_CASE_P( }))); // Tests about arithmetic operations for vector int and uint types. -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( VectorArithmetic, FoldSpecConstantOpAndCompositePassTest, ::testing::ValuesIn(std::vector< FoldSpecConstantOpAndCompositePassTestCase>({ @@ -838,7 +961,7 @@ INSTANTIATE_TEST_CASE_P( { "%int_n1 = OpConstant %int -1", "%int_n1_0 = OpConstant %int -1", - "%v2int_minus_1 = OpConstantComposite %v2int %int_n1 %int_n1", + "%v2int_minus_1 = OpConstantComposite %v2int %signed_minus_one %signed_minus_one", "%int_n2 = OpConstant %int -2", "%int_n2_0 = OpConstant %int -2", "%v2int_minus_2 = OpConstantComposite %v2int %int_n2 %int_n2", @@ -943,13 +1066,13 @@ INSTANTIATE_TEST_CASE_P( "%7_srem_3 = OpConstantComposite %v2int %signed_one %signed_one", "%int_n1 = OpConstant %int -1", "%int_n1_0 = OpConstant %int -1", - "%minus_7_srem_3 = OpConstantComposite %v2int %int_n1 %int_n1", + "%minus_7_srem_3 = OpConstantComposite %v2int %signed_minus_one %signed_minus_one", "%int_1_1 = OpConstant %int 1", "%int_1_2 = OpConstant %int 1", "%7_srem_minus_3 = OpConstantComposite %v2int %signed_one %signed_one", "%int_n1_1 = OpConstant %int -1", "%int_n1_2 = OpConstant %int -1", - "%minus_7_srem_minus_3 = OpConstantComposite %v2int %int_n1 %int_n1", + "%minus_7_srem_minus_3 = OpConstantComposite %v2int %signed_minus_one %signed_minus_one", // smod "%int_1_3 = OpConstant %int 1", "%int_1_4 = OpConstant %int 1", @@ -962,7 +1085,7 @@ INSTANTIATE_TEST_CASE_P( "%7_smod_minus_3 = OpConstantComposite %v2int %int_n2 %int_n2", "%int_n1_3 = OpConstant %int -1", "%int_n1_4 = OpConstant %int -1", - "%minus_7_smod_minus_3 = OpConstantComposite %v2int %int_n1 %int_n1", + "%minus_7_smod_minus_3 = OpConstantComposite %v2int %signed_minus_one %signed_minus_one", // umod "%uint_1 = OpConstant %uint 1", "%uint_1_0 = OpConstant %uint 1", @@ -1005,7 +1128,7 @@ INSTANTIATE_TEST_CASE_P( "%unsigned_right_shift_logical = OpConstantComposite %v2uint %unsigned_one %unsigned_one", "%int_n1 = OpConstant %int -1", "%int_n1_0 = OpConstant %int -1", - "%signed_right_shift_arithmetic = OpConstantComposite %v2int %int_n1 %int_n1", + "%signed_right_shift_arithmetic = OpConstantComposite %v2int %signed_minus_one %signed_minus_one", }, }, // Skip folding if any vector operands or components of the operands @@ -1043,7 +1166,7 @@ INSTANTIATE_TEST_CASE_P( }))); // Tests for SpecConstantOp CompositeExtract instruction -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( CompositeExtract, FoldSpecConstantOpAndCompositePassTest, ::testing::ValuesIn(std::vector< FoldSpecConstantOpAndCompositePassTestCase>({ @@ -1135,14 +1258,14 @@ INSTANTIATE_TEST_CASE_P( "%outer = OpConstantComposite %outer_struct %inner %signed_one", "%extract_inner = OpSpecConstantOp %inner_struct CompositeExtract %outer 0", "%extract_int = OpSpecConstantOp %int CompositeExtract %outer 1", - "%extract_inner_float = OpSpecConstantOp %int CompositeExtract %outer 0 2", + "%extract_inner_float = OpSpecConstantOp %float CompositeExtract %outer 0 2", }, // expected { "%float_1 = OpConstant %float 1", "%inner = OpConstantComposite %inner_struct %bool_true %signed_null %float_1", "%outer = OpConstantComposite %outer_struct %inner %signed_one", - "%extract_inner = OpConstantComposite %flat_struct %bool_true %signed_null %float_1", + "%extract_inner = OpConstantComposite %inner_struct %bool_true %signed_null %float_1", "%extract_int = OpConstant %int 1", "%extract_inner_float = OpConstant %float 1", }, @@ -1217,7 +1340,7 @@ INSTANTIATE_TEST_CASE_P( }))); // Tests the swizzle operations for spec const vectors. -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( VectorShuffle, FoldSpecConstantOpAndCompositePassTest, ::testing::ValuesIn(std::vector< FoldSpecConstantOpAndCompositePassTestCase>({ @@ -1256,13 +1379,9 @@ INSTANTIATE_TEST_CASE_P( }, // expected { - "%60 = OpConstantNull %int", "%a = OpConstantComposite %v2int %signed_null %signed_null", - "%62 = OpConstantNull %int", "%b = OpConstantComposite %v2int %signed_zero %signed_one", - "%64 = OpConstantNull %int", "%c = OpConstantComposite %v2int %signed_three %signed_null", - "%66 = OpConstantNull %int", "%d = OpConstantComposite %v2int %signed_null %signed_null", } }, @@ -1310,7 +1429,7 @@ INSTANTIATE_TEST_CASE_P( }))); // Test with long use-def chain. -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( LongDefUseChain, FoldSpecConstantOpAndCompositePassTest, ::testing::ValuesIn(std::vector< FoldSpecConstantOpAndCompositePassTestCase>({ diff --git a/third_party/spirv-tools/test/opt/fold_test.cpp b/third_party/spirv-tools/test/opt/fold_test.cpp index b1e5758866..db0192450e 100644 --- a/third_party/spirv-tools/test/opt/fold_test.cpp +++ b/third_party/spirv-tools/test/opt/fold_test.cpp @@ -11,33 +11,30 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include "source/opt/fold.h" + #include #include #include #include #include +#include "effcee/effcee.h" #include "gmock/gmock.h" #include "gtest/gtest.h" #include "source/opt/build_module.h" #include "source/opt/def_use_manager.h" -#include "source/opt/fold.h" #include "source/opt/ir_context.h" #include "source/opt/module.h" #include "spirv-tools/libspirv.hpp" #include "test/opt/pass_utils.h" -#ifdef SPIRV_EFFCEE -#include "effcee/effcee.h" -#endif - namespace spvtools { namespace opt { namespace { using ::testing::Contains; -#ifdef SPIRV_EFFCEE std::string Disassemble(const std::string& original, IRContext* context, uint32_t disassemble_options = 0) { std::vector optimized_bin; @@ -60,7 +57,6 @@ void Match(const std::string& original, IRContext* context, << match_result.message() << "\nChecking result:\n" << disassembly; } -#endif template struct InstructionFoldingCase { @@ -147,6 +143,7 @@ OpName %main "main" %v4double = OpTypeVector %double 4 %v2float = OpTypeVector %float 2 %v2double = OpTypeVector %double 2 +%v2half = OpTypeVector %half 2 %v2bool = OpTypeVector %bool 2 %struct_v2int_int_int = OpTypeStruct %v2int %int %int %_ptr_int = OpTypePointer Function %int @@ -173,6 +170,7 @@ OpName %main "main" %int_2 = OpConstant %int 2 %int_3 = OpConstant %int 3 %int_4 = OpConstant %int 4 +%int_n24 = OpConstant %int -24 %int_min = OpConstant %int -2147483648 %int_max = OpConstant %int 2147483647 %long_0 = OpConstant %long 0 @@ -184,6 +182,7 @@ OpName %main "main" %uint_3 = OpConstant %uint 3 %uint_4 = OpConstant %uint 4 %uint_32 = OpConstant %uint 32 +%uint_42 = OpConstant %uint 42 %uint_max = OpConstant %uint 4294967295 %v2int_undef = OpUndef %v2int %v2int_0_0 = OpConstantComposite %v2int %int_0 %int_0 @@ -208,13 +207,22 @@ OpName %main "main" %float_2 = OpConstant %float 2 %float_3 = OpConstant %float 3 %float_4 = OpConstant %float 4 +%float_2049 = OpConstant %float 2049 +%float_n2049 = OpConstant %float -2049 %float_0p5 = OpConstant %float 0.5 +%float_0p2 = OpConstant %float 0.2 +%float_pi = OpConstant %float 1.5555 +%float_1e16 = OpConstant %float 1e16 +%float_n1e16 = OpConstant %float -1e16 +%float_1en16 = OpConstant %float 1e-16 +%float_n1en16 = OpConstant %float -1e-16 %v2float_0_0 = OpConstantComposite %v2float %float_0 %float_0 %v2float_2_2 = OpConstantComposite %v2float %float_2 %float_2 %v2float_2_3 = OpConstantComposite %v2float %float_2 %float_3 %v2float_3_2 = OpConstantComposite %v2float %float_3 %float_2 %v2float_4_4 = OpConstantComposite %v2float %float_4 %float_4 %v2float_2_0p5 = OpConstantComposite %v2float %float_2 %float_0p5 +%v2float_0p2_0p5 = OpConstantComposite %v2float %float_0p2 %float_0p5 %v2float_null = OpConstantNull %v2float %double_n1 = OpConstant %double -1 %105 = OpConstant %double 0 ; Need a def with an numerical id to define id maps. @@ -224,7 +232,9 @@ OpName %main "main" %double_2 = OpConstant %double 2 %double_3 = OpConstant %double 3 %double_4 = OpConstant %double 4 +%double_5 = OpConstant %double 5 %double_0p5 = OpConstant %double 0.5 +%double_0p2 = OpConstant %double 0.2 %v2double_0_0 = OpConstantComposite %v2double %double_0 %double_0 %v2double_2_2 = OpConstantComposite %v2double %double_2 %double_2 %v2double_2_3 = OpConstantComposite %v2double %double_2 %double_3 @@ -234,6 +244,7 @@ OpName %main "main" %v2double_null = OpConstantNull %v2double %108 = OpConstant %half 0 %half_1 = OpConstant %half 1 +%half_0_1 = OpConstantComposite %v2half %108 %half_1 %106 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0 %v4float_0_0_0_0 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0 %v4float_0_0_0_1 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_1 @@ -268,7 +279,7 @@ const std::string& HeaderWithNaN() { } // clang-format off -INSTANTIATE_TEST_CASE_P(TestCase, IntegerInstructionFoldingTest, +INSTANTIATE_TEST_SUITE_P(TestCase, IntegerInstructionFoldingTest, ::testing::Values( // Test case 0: fold 0*n InstructionFoldingCase( @@ -439,7 +450,265 @@ INSTANTIATE_TEST_CASE_P(TestCase, IntegerInstructionFoldingTest, "%2 = OpBitwiseAnd %uint %load %uint_0\n" + "OpReturn\n" + "OpFunctionEnd", - 2, 0) + 2, 0), + // Test case 17: fold 1/0 (signed) + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpSDiv %int %int_1 %int_0\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 0), + // Test case 18: fold 1/0 (unsigned) + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpUDiv %uint %uint_1 %uint_0\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 0), + // Test case 19: fold OpSRem 1 0 (signed) + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpSRem %int %int_1 %int_0\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 0), + // Test case 20: fold 1%0 (signed) + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpSMod %int %int_1 %int_0\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 0), + // Test case 21: fold 1%0 (unsigned) + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpUMod %uint %uint_1 %uint_0\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 0), + // Test case 22: fold unsigned n >> 42 (undefined, so set to zero). + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%n = OpVariable %_ptr_uint Function\n" + + "%load = OpLoad %uint %n\n" + + "%2 = OpShiftRightLogical %uint %load %uint_42\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 0), + // Test case 23: fold signed n >> 42 (undefined, so set to zero). + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%n = OpVariable %_ptr_int Function\n" + + "%load = OpLoad %int %n\n" + + "%2 = OpShiftRightLogical %int %load %uint_42\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 0), + // Test case 24: fold n << 42 (undefined, so set to zero). + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%n = OpVariable %_ptr_int Function\n" + + "%load = OpLoad %int %n\n" + + "%2 = OpShiftLeftLogical %int %load %uint_42\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 0), + // Test case 25: fold -24 >> 32 (defined as -1) + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpShiftRightArithmetic %int %int_n24 %uint_32\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, -1), + // Test case 26: fold 2 >> 32 (signed) + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpShiftRightArithmetic %int %int_2 %uint_32\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 0), + // Test case 27: fold 2 >> 32 (unsigned) + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpShiftRightLogical %int %int_2 %uint_32\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 0), + // Test case 28: fold 2 << 32 + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpShiftLeftLogical %int %int_2 %uint_32\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 0), + // Test case 29: fold -INT_MIN + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpSNegate %int %int_min\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, std::numeric_limits::min()), + // Test case 30: fold UMin 3 4 + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpExtInst %uint %1 UMin %uint_3 %uint_4\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 3), + // Test case 31: fold UMin 4 2 + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpExtInst %uint %1 UMin %uint_4 %uint_2\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 2), + // Test case 32: fold SMin 3 4 + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpExtInst %int %1 UMin %int_3 %int_4\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 3), + // Test case 33: fold SMin 4 2 + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpExtInst %int %1 SMin %int_4 %int_2\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 2), + // Test case 34: fold UMax 3 4 + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpExtInst %uint %1 UMax %uint_3 %uint_4\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 4), + // Test case 35: fold UMax 3 2 + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpExtInst %uint %1 UMax %uint_3 %uint_2\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 3), + // Test case 36: fold SMax 3 4 + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpExtInst %int %1 UMax %int_3 %int_4\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 4), + // Test case 37: fold SMax 3 2 + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpExtInst %int %1 SMax %int_3 %int_2\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 3), + // Test case 38: fold UClamp 2 3 4 + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpExtInst %uint %1 UClamp %uint_2 %uint_3 %uint_4\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 3), + // Test case 39: fold UClamp 2 0 4 + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpExtInst %uint %1 UClamp %uint_2 %uint_0 %uint_4\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 2), + // Test case 40: fold UClamp 2 0 1 + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpExtInst %uint %1 UClamp %uint_2 %uint_0 %uint_1\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 1), + // Test case 41: fold SClamp 2 3 4 + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpExtInst %int %1 SClamp %int_2 %int_3 %int_4\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 3), + // Test case 42: fold SClamp 2 0 4 + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpExtInst %int %1 SClamp %int_2 %int_0 %int_4\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 2), + // Test case 43: fold SClamp 2 0 1 + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpExtInst %int %1 SClamp %int_2 %int_0 %int_1\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 1), + // Test case 44: SClamp 1 2 x + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%undef = OpUndef %int\n" + + "%2 = OpExtInst %int %1 SClamp %int_1 %int_2 %undef\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 2), + // Test case 45: SClamp 2 x 1 + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%undef = OpUndef %int\n" + + "%2 = OpExtInst %int %1 SClamp %int_2 %undef %int_1\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 1), + // Test case 44: UClamp 1 2 x + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%undef = OpUndef %uint\n" + + "%2 = OpExtInst %uint %1 UClamp %uint_1 %uint_2 %undef\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 2), + // Test case 45: UClamp 2 x 1 + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%undef = OpUndef %uint\n" + + "%2 = OpExtInst %uint %1 UClamp %uint_2 %undef %uint_1\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 1) )); // clang-format on @@ -483,7 +752,7 @@ TEST_P(IntVectorInstructionFoldingTest, Case) { } // clang-format off -INSTANTIATE_TEST_CASE_P(TestCase, IntVectorInstructionFoldingTest, +INSTANTIATE_TEST_SUITE_P(TestCase, IntVectorInstructionFoldingTest, ::testing::Values( // Test case 0: fold 0*n InstructionFoldingCase>( @@ -525,6 +794,58 @@ INSTANTIATE_TEST_CASE_P(TestCase, IntVectorInstructionFoldingTest, )); // clang-format on +using FloatVectorInstructionFoldingTest = + ::testing::TestWithParam>>; + +TEST_P(FloatVectorInstructionFoldingTest, Case) { + const auto& tc = GetParam(); + + // Build module. + std::unique_ptr context = + BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + ASSERT_NE(nullptr, context); + + // Fold the instruction to test. + analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr(); + Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold); + SpvOp original_opcode = inst->opcode(); + bool succeeded = context->get_instruction_folder().FoldInstruction(inst); + + // Make sure the instruction folded as expected. + EXPECT_EQ(succeeded, inst == nullptr || inst->opcode() != original_opcode); + if (succeeded && inst != nullptr) { + EXPECT_EQ(inst->opcode(), SpvOpCopyObject); + inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0)); + std::vector opcodes = {SpvOpConstantComposite}; + EXPECT_THAT(opcodes, Contains(inst->opcode())); + analysis::ConstantManager* const_mrg = context->get_constant_mgr(); + const analysis::Constant* result = const_mrg->GetConstantFromInst(inst); + EXPECT_NE(result, nullptr); + if (result != nullptr) { + const std::vector& componenets = + result->AsVectorConstant()->GetComponents(); + EXPECT_EQ(componenets.size(), tc.expected_result.size()); + for (size_t i = 0; i < componenets.size(); i++) { + EXPECT_EQ(tc.expected_result[i], componenets[i]->GetFloat()); + } + } + } +} + +// clang-format off +INSTANTIATE_TEST_SUITE_P(TestCase, FloatVectorInstructionFoldingTest, +::testing::Values( + // Test case 0: FMix {2.0, 2.0}, {2.0, 3.0} {0.2,0.5} + InstructionFoldingCase>( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpExtInst %v2float %1 FMix %v2float_2_3 %v2float_0_0 %v2float_0p2_0p5\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, {1.6f,1.5f}) +)); +// clang-format on using BooleanInstructionFoldingTest = ::testing::TestWithParam>; @@ -560,7 +881,7 @@ TEST_P(BooleanInstructionFoldingTest, Case) { } // clang-format off -INSTANTIATE_TEST_CASE_P(TestCase, BooleanInstructionFoldingTest, +INSTANTIATE_TEST_SUITE_P(TestCase, BooleanInstructionFoldingTest, ::testing::Values( // Test case 0: fold true || n InstructionFoldingCase( @@ -764,7 +1085,7 @@ INSTANTIATE_TEST_CASE_P(TestCase, BooleanInstructionFoldingTest, 2, true) )); -INSTANTIATE_TEST_CASE_P(FClampAndCmpLHS, BooleanInstructionFoldingTest, +INSTANTIATE_TEST_SUITE_P(FClampAndCmpLHS, BooleanInstructionFoldingTest, ::testing::Values( // Test case 0: fold 0.0 > clamp(n, 0.0, 1.0) InstructionFoldingCase( @@ -944,7 +1265,7 @@ INSTANTIATE_TEST_CASE_P(FClampAndCmpLHS, BooleanInstructionFoldingTest, 2, false) )); -INSTANTIATE_TEST_CASE_P(FClampAndCmpRHS, BooleanInstructionFoldingTest, +INSTANTIATE_TEST_SUITE_P(FClampAndCmpRHS, BooleanInstructionFoldingTest, ::testing::Values( // Test case 0: fold clamp(n, 0.0, 1.0) > 1.0 InstructionFoldingCase( @@ -1164,7 +1485,11 @@ TEST_P(FloatInstructionFoldingTest, Case) { const_mrg->GetConstantFromInst(inst)->AsFloatConstant(); EXPECT_NE(result, nullptr); if (result != nullptr) { - EXPECT_EQ(result->GetFloatValue(), tc.expected_result); + if (!std::isnan(tc.expected_result)) { + EXPECT_EQ(result->GetFloatValue(), tc.expected_result); + } else { + EXPECT_TRUE(std::isnan(result->GetFloatValue())); + } } } } @@ -1174,7 +1499,7 @@ TEST_P(FloatInstructionFoldingTest, Case) { // specification. // clang-format off -INSTANTIATE_TEST_CASE_P(FloatConstantFoldingTest, FloatInstructionFoldingTest, +INSTANTIATE_TEST_SUITE_P(FloatConstantFoldingTest, FloatInstructionFoldingTest, ::testing::Values( // Test case 0: Fold 2.0 - 1.0 InstructionFoldingCase( @@ -1279,7 +1604,257 @@ INSTANTIATE_TEST_CASE_P(FloatConstantFoldingTest, FloatInstructionFoldingTest, "%2 = OpFNegate %float %float_2\n" + "OpReturn\n" + "OpFunctionEnd", - 2, -2) + 2, -2), + // Test case 12: QuantizeToF16 1.0 + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpQuantizeToF16 %float %float_1\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 1.0), + // Test case 13: QuantizeToF16 positive non exact + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpQuantizeToF16 %float %float_2049\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 2048), + // Test case 14: QuantizeToF16 negative non exact + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpQuantizeToF16 %float %float_n2049\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, -2048), + // Test case 15: QuantizeToF16 large positive + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpQuantizeToF16 %float %float_1e16\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, std::numeric_limits::infinity()), + // Test case 16: QuantizeToF16 large negative + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpQuantizeToF16 %float %float_n1e16\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, -std::numeric_limits::infinity()), + // Test case 17: QuantizeToF16 small positive + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpQuantizeToF16 %float %float_1en16\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 0.0), + // Test case 18: QuantizeToF16 small negative + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpQuantizeToF16 %float %float_n1en16\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 0.0), + // Test case 19: QuantizeToF16 nan + InstructionFoldingCase( + HeaderWithNaN() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpQuantizeToF16 %float %float_nan\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, std::numeric_limits::quiet_NaN()), + // Test case 20: FMix 1.0 4.0 0.2 + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpExtInst %float %1 FMix %float_1 %float_4 %float_0p2\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 1.6f), + // Test case 21: FMin 1.0 4.0 + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpExtInst %float %1 FMin %float_1 %float_4\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 1.0f), + // Test case 22: FMin 4.0 0.2 + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpExtInst %float %1 FMin %float_4 %float_0p2\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 0.2f), + // Test case 23: FMax 1.0 4.0 + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpExtInst %float %1 FMax %float_1 %float_4\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 4.0f), + // Test case 24: FMax 1.0 0.2 + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpExtInst %float %1 FMax %float_1 %float_0p2\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 1.0f), + // Test case 25: FClamp 1.0 0.2 4.0 + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpExtInst %float %1 FClamp %float_1 %float_0p2 %float_4\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 1.0f), + // Test case 26: FClamp 0.2 2.0 4.0 + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpExtInst %float %1 FClamp %float_0p2 %float_2 %float_4\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 2.0f), + // Test case 27: FClamp 2049.0 2.0 4.0 + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpExtInst %float %1 FClamp %float_2049 %float_2 %float_4\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 4.0f), + // Test case 28: FClamp 1.0 2.0 x + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%undef = OpUndef %float\n" + + "%2 = OpExtInst %float %1 FClamp %float_1 %float_2 %undef\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 2.0), + // Test case 29: FClamp 1.0 x 0.5 + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%undef = OpUndef %float\n" + + "%2 = OpExtInst %float %1 FClamp %float_1 %undef %float_0p5\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 0.5), + // Test case 30: Sin 0.0 + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpExtInst %float %1 Sin %float_0\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 0.0), + // Test case 31: Cos 0.0 + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpExtInst %float %1 Cos %float_0\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 1.0), + // Test case 32: Tan 0.0 + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpExtInst %float %1 Tan %float_0\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 0.0), + // Test case 33: Asin 0.0 + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpExtInst %float %1 Asin %float_0\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 0.0), + // Test case 34: Acos 1.0 + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpExtInst %float %1 Acos %float_1\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 0.0), + // Test case 35: Atan 0.0 + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpExtInst %float %1 Atan %float_0\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 0.0), + // Test case 36: Exp 0.0 + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpExtInst %float %1 Exp %float_0\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 1.0), + // Test case 37: Log 1.0 + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpExtInst %float %1 Log %float_1\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 0.0), + // Test case 38: Exp2 2.0 + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpExtInst %float %1 Exp2 %float_2\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 4.0), + // Test case 39: Log2 4.0 + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpExtInst %float %1 Log2 %float_4\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 2.0), + // Test case 40: Sqrt 4.0 + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpExtInst %float %1 Sqrt %float_4\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 2.0), + // Test case 41: Atan2 0.0 1.0 + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpExtInst %float %1 Atan2 %float_0 %float_1\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 0.0), + // Test case 42: Pow 2.0 3.0 + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpExtInst %float %1 Pow %float_2 %float_3\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 8.0) )); // clang-format on @@ -1317,7 +1892,7 @@ TEST_P(DoubleInstructionFoldingTest, Case) { } // clang-format off -INSTANTIATE_TEST_CASE_P(DoubleConstantFoldingTest, DoubleInstructionFoldingTest, +INSTANTIATE_TEST_SUITE_P(DoubleConstantFoldingTest, DoubleInstructionFoldingTest, ::testing::Values( // Test case 0: Fold 2.0 - 1.0 InstructionFoldingCase( @@ -1422,12 +1997,104 @@ INSTANTIATE_TEST_CASE_P(DoubleConstantFoldingTest, DoubleInstructionFoldingTest, "%2 = OpFNegate %double %double_2\n" + "OpReturn\n" + "OpFunctionEnd", - 2, -2) + 2, -2), + // Test case 12: FMin 1.0 4.0 + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpExtInst %double %1 FMin %double_1 %double_4\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 1.0), + // Test case 13: FMin 4.0 0.2 + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpExtInst %double %1 FMin %double_4 %double_0p2\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 0.2), + // Test case 14: FMax 1.0 4.0 + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpExtInst %double %1 FMax %double_1 %double_4\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 4.0), + // Test case 15: FMax 1.0 0.2 + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpExtInst %double %1 FMax %double_1 %double_0p2\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 1.0), + // Test case 16: FClamp 1.0 0.2 4.0 + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpExtInst %double %1 FClamp %double_1 %double_0p2 %double_4\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 1.0), + // Test case 17: FClamp 0.2 2.0 4.0 + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpExtInst %double %1 FClamp %double_0p2 %double_2 %double_4\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 2.0), + // Test case 18: FClamp 5.0 2.0 4.0 + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpExtInst %double %1 FClamp %double_5 %double_2 %double_4\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 4.0), + // Test case 19: FClamp 1.0 2.0 x + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%undef = OpUndef %double\n" + + "%2 = OpExtInst %double %1 FClamp %double_1 %double_2 %undef\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 2.0), + // Test case 20: FClamp 1.0 x 0.5 + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%undef = OpUndef %double\n" + + "%2 = OpExtInst %double %1 FClamp %double_1 %undef %double_0p5\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 0.5), + // Test case 21: Sqrt 4.0 + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%undef = OpUndef %double\n" + + "%2 = OpExtInst %double %1 Sqrt %double_4\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 2.0), + // Test case 22: Pow 2.0 3.0 + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%undef = OpUndef %double\n" + + "%2 = OpExtInst %double %1 Pow %double_2 %double_3\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 8.0) )); // clang-format on // clang-format off -INSTANTIATE_TEST_CASE_P(DoubleOrderedCompareConstantFoldingTest, BooleanInstructionFoldingTest, +INSTANTIATE_TEST_SUITE_P(DoubleOrderedCompareConstantFoldingTest, BooleanInstructionFoldingTest, ::testing::Values( // Test case 0: fold 1.0 == 2.0 InstructionFoldingCase( @@ -1559,7 +2226,7 @@ INSTANTIATE_TEST_CASE_P(DoubleOrderedCompareConstantFoldingTest, BooleanInstruct 2, true) )); -INSTANTIATE_TEST_CASE_P(DoubleUnorderedCompareConstantFoldingTest, BooleanInstructionFoldingTest, +INSTANTIATE_TEST_SUITE_P(DoubleUnorderedCompareConstantFoldingTest, BooleanInstructionFoldingTest, ::testing::Values( // Test case 0: fold 1.0 == 2.0 InstructionFoldingCase( @@ -1691,7 +2358,7 @@ INSTANTIATE_TEST_CASE_P(DoubleUnorderedCompareConstantFoldingTest, BooleanInstru 2, true) )); -INSTANTIATE_TEST_CASE_P(FloatOrderedCompareConstantFoldingTest, BooleanInstructionFoldingTest, +INSTANTIATE_TEST_SUITE_P(FloatOrderedCompareConstantFoldingTest, BooleanInstructionFoldingTest, ::testing::Values( // Test case 0: fold 1.0 == 2.0 InstructionFoldingCase( @@ -1823,7 +2490,7 @@ INSTANTIATE_TEST_CASE_P(FloatOrderedCompareConstantFoldingTest, BooleanInstructi 2, true) )); -INSTANTIATE_TEST_CASE_P(FloatUnorderedCompareConstantFoldingTest, BooleanInstructionFoldingTest, +INSTANTIATE_TEST_SUITE_P(FloatUnorderedCompareConstantFoldingTest, BooleanInstructionFoldingTest, ::testing::Values( // Test case 0: fold 1.0 == 2.0 InstructionFoldingCase( @@ -1955,7 +2622,7 @@ INSTANTIATE_TEST_CASE_P(FloatUnorderedCompareConstantFoldingTest, BooleanInstruc 2, true) )); -INSTANTIATE_TEST_CASE_P(DoubleNaNCompareConstantFoldingTest, BooleanInstructionFoldingTest, +INSTANTIATE_TEST_SUITE_P(DoubleNaNCompareConstantFoldingTest, BooleanInstructionFoldingTest, ::testing::Values( // Test case 0: fold NaN == 0 (ord) InstructionFoldingCase( @@ -1991,7 +2658,7 @@ INSTANTIATE_TEST_CASE_P(DoubleNaNCompareConstantFoldingTest, BooleanInstructionF 2, true) )); -INSTANTIATE_TEST_CASE_P(FloatNaNCompareConstantFoldingTest, BooleanInstructionFoldingTest, +INSTANTIATE_TEST_SUITE_P(FloatNaNCompareConstantFoldingTest, BooleanInstructionFoldingTest, ::testing::Values( // Test case 0: fold NaN == 0 (ord) InstructionFoldingCase( @@ -2073,7 +2740,7 @@ TEST_P(IntegerInstructionFoldingTestWithMap, Case) { } } // clang-format off -INSTANTIATE_TEST_CASE_P(TestCase, IntegerInstructionFoldingTestWithMap, +INSTANTIATE_TEST_SUITE_P(TestCase, IntegerInstructionFoldingTestWithMap, ::testing::Values( // Test case 0: fold %3 = 0; %3 * n InstructionFoldingCaseWithMap( @@ -2123,7 +2790,7 @@ TEST_P(BooleanInstructionFoldingTestWithMap, Case) { } // clang-format off -INSTANTIATE_TEST_CASE_P(TestCase, BooleanInstructionFoldingTestWithMap, +INSTANTIATE_TEST_SUITE_P(TestCase, BooleanInstructionFoldingTestWithMap, ::testing::Values( // Test case 0: fold %3 = true; %3 || n InstructionFoldingCaseWithMap( @@ -2173,7 +2840,7 @@ TEST_P(GeneralInstructionFoldingTest, Case) { } // clang-format off -INSTANTIATE_TEST_CASE_P(IntegerArithmeticTestCases, GeneralInstructionFoldingTest, +INSTANTIATE_TEST_SUITE_P(IntegerArithmeticTestCases, GeneralInstructionFoldingTest, ::testing::Values( // Test case 0: Don't fold n * m InstructionFoldingCase( @@ -2633,7 +3300,7 @@ INSTANTIATE_TEST_CASE_P(IntegerArithmeticTestCases, GeneralInstructionFoldingTes 2, 3) )); -INSTANTIATE_TEST_CASE_P(CompositeExtractFoldingTest, GeneralInstructionFoldingTest, +INSTANTIATE_TEST_SUITE_P(CompositeExtractFoldingTest, GeneralInstructionFoldingTest, ::testing::Values( // Test case 0: fold Insert feeding extract InstructionFoldingCase( @@ -2778,10 +3445,20 @@ INSTANTIATE_TEST_CASE_P(CompositeExtractFoldingTest, GeneralInstructionFoldingTe "%4 = OpCompositeExtract %int %3 0\n" + "OpReturn\n" + "OpFunctionEnd", - 4, INT_7_ID) + 4, INT_7_ID), + // Test case 13: https://github.com/KhronosGroup/SPIRV-Tools/issues/2608 + // Out of bounds access. Do not fold. + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1\n" + + "%3 = OpCompositeExtract %float %2 4\n" + + "OpReturn\n" + + "OpFunctionEnd", + 3, 0) )); -INSTANTIATE_TEST_CASE_P(CompositeConstructFoldingTest, GeneralInstructionFoldingTest, +INSTANTIATE_TEST_SUITE_P(CompositeConstructFoldingTest, GeneralInstructionFoldingTest, ::testing::Values( // Test case 0: fold Extracts feeding construct InstructionFoldingCase( @@ -2841,10 +3518,20 @@ INSTANTIATE_TEST_CASE_P(CompositeConstructFoldingTest, GeneralInstructionFolding "%2 = OpCompositeConstruct %v2int %103 %103\n" + "OpReturn\n" + "OpFunctionEnd", - 2, VEC2_0_ID) + 2, VEC2_0_ID), + // Test case 5: Don't segfault when trying to fold an OpCompositeConstruct + // for an empty struct, and we reached the id limit. + InstructionFoldingCase( + Header() + "%empty_struct = OpTypeStruct\n" + + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%4194303 = OpCompositeConstruct %empty_struct\n" + + "OpReturn\n" + + "OpFunctionEnd", + 4194303, 0) )); -INSTANTIATE_TEST_CASE_P(PhiFoldingTest, GeneralInstructionFoldingTest, +INSTANTIATE_TEST_SUITE_P(PhiFoldingTest, GeneralInstructionFoldingTest, ::testing::Values( // Test case 0: Fold phi with the same values for all edges. InstructionFoldingCase( @@ -2886,7 +3573,7 @@ INSTANTIATE_TEST_CASE_P(PhiFoldingTest, GeneralInstructionFoldingTest, 2, 0) )); -INSTANTIATE_TEST_CASE_P(FloatRedundantFoldingTest, GeneralInstructionFoldingTest, +INSTANTIATE_TEST_SUITE_P(FloatRedundantFoldingTest, GeneralInstructionFoldingTest, ::testing::Values( // Test case 0: Don't fold n + 1.0 InstructionFoldingCase( @@ -3064,7 +3751,7 @@ INSTANTIATE_TEST_CASE_P(FloatRedundantFoldingTest, GeneralInstructionFoldingTest "OpReturn\n" + "OpFunctionEnd", 3, 2), - // Test case 15: Fold vector fsub with null + // Test case 17: Fold vector fsub with null InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + @@ -3074,7 +3761,7 @@ INSTANTIATE_TEST_CASE_P(FloatRedundantFoldingTest, GeneralInstructionFoldingTest "OpReturn\n" + "OpFunctionEnd", 3, 2), - // Test case 16: Fold 0.0(half) * n + // Test case 18: Fold 0.0(half) * n InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + @@ -3084,7 +3771,7 @@ INSTANTIATE_TEST_CASE_P(FloatRedundantFoldingTest, GeneralInstructionFoldingTest "OpReturn\n" + "OpFunctionEnd", 2, HALF_0_ID), - // Test case 17: Don't fold 1.0(half) * n + // Test case 19: Don't fold 1.0(half) * n InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + @@ -3094,17 +3781,33 @@ INSTANTIATE_TEST_CASE_P(FloatRedundantFoldingTest, GeneralInstructionFoldingTest "OpReturn\n" + "OpFunctionEnd", 2, 0), - // Test case 18: Don't fold 1.0 * 1.0 (half) + // Test case 20: Don't fold 1.0 * 1.0 (half) InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpFMul %half %half_1 %half_1\n" + "OpReturn\n" + "OpFunctionEnd", + 2, 0), + // Test case 21: Don't fold (0.0, 1.0) * (0.0, 1.0) (half) + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpFMul %v2half %half_0_1 %half_0_1\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 0), + // Test case 22: Don't fold (0.0, 1.0) dotp (0.0, 1.0) (half) + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpDot %half %half_0_1 %half_0_1\n" + + "OpReturn\n" + + "OpFunctionEnd", 2, 0) )); -INSTANTIATE_TEST_CASE_P(DoubleRedundantFoldingTest, GeneralInstructionFoldingTest, +INSTANTIATE_TEST_SUITE_P(DoubleRedundantFoldingTest, GeneralInstructionFoldingTest, ::testing::Values( // Test case 0: Don't fold n + 1.0 InstructionFoldingCase( @@ -3264,7 +3967,7 @@ INSTANTIATE_TEST_CASE_P(DoubleRedundantFoldingTest, GeneralInstructionFoldingTes 2, 4) )); -INSTANTIATE_TEST_CASE_P(FloatVectorRedundantFoldingTest, GeneralInstructionFoldingTest, +INSTANTIATE_TEST_SUITE_P(FloatVectorRedundantFoldingTest, GeneralInstructionFoldingTest, ::testing::Values( // Test case 0: Don't fold a * vec4(0.0, 0.0, 0.0, 1.0) InstructionFoldingCase( @@ -3298,7 +4001,7 @@ INSTANTIATE_TEST_CASE_P(FloatVectorRedundantFoldingTest, GeneralInstructionFoldi 2, 3) )); -INSTANTIATE_TEST_CASE_P(DoubleVectorRedundantFoldingTest, GeneralInstructionFoldingTest, +INSTANTIATE_TEST_SUITE_P(DoubleVectorRedundantFoldingTest, GeneralInstructionFoldingTest, ::testing::Values( // Test case 0: Don't fold a * vec4(0.0, 0.0, 0.0, 1.0) InstructionFoldingCase( @@ -3332,7 +4035,7 @@ INSTANTIATE_TEST_CASE_P(DoubleVectorRedundantFoldingTest, GeneralInstructionFold 2, 3) )); -INSTANTIATE_TEST_CASE_P(IntegerRedundantFoldingTest, GeneralInstructionFoldingTest, +INSTANTIATE_TEST_SUITE_P(IntegerRedundantFoldingTest, GeneralInstructionFoldingTest, ::testing::Values( // Test case 0: Don't fold n + 1 InstructionFoldingCase( @@ -3416,7 +4119,7 @@ INSTANTIATE_TEST_CASE_P(IntegerRedundantFoldingTest, GeneralInstructionFoldingTe 2, 3) )); -INSTANTIATE_TEST_CASE_P(ClampAndCmpLHS, GeneralInstructionFoldingTest, +INSTANTIATE_TEST_SUITE_P(ClampAndCmpLHS, GeneralInstructionFoldingTest, ::testing::Values( // Test case 0: Don't Fold 0.0 < clamp(-1, 1) InstructionFoldingCase( @@ -3552,7 +4255,7 @@ INSTANTIATE_TEST_CASE_P(ClampAndCmpLHS, GeneralInstructionFoldingTest, 2, 0) )); -INSTANTIATE_TEST_CASE_P(ClampAndCmpRHS, GeneralInstructionFoldingTest, +INSTANTIATE_TEST_SUITE_P(ClampAndCmpRHS, GeneralInstructionFoldingTest, ::testing::Values( // Test case 0: Don't Fold clamp(-1, 1) < 0.0 InstructionFoldingCase( @@ -3688,7 +4391,7 @@ INSTANTIATE_TEST_CASE_P(ClampAndCmpRHS, GeneralInstructionFoldingTest, 2, 0) )); -INSTANTIATE_TEST_CASE_P(FToIConstantFoldingTest, IntegerInstructionFoldingTest, +INSTANTIATE_TEST_SUITE_P(FToIConstantFoldingTest, IntegerInstructionFoldingTest, ::testing::Values( // Test case 0: Fold int(3.0) InstructionFoldingCase( @@ -3708,7 +4411,7 @@ INSTANTIATE_TEST_CASE_P(FToIConstantFoldingTest, IntegerInstructionFoldingTest, 2, 3) )); -INSTANTIATE_TEST_CASE_P(IToFConstantFoldingTest, FloatInstructionFoldingTest, +INSTANTIATE_TEST_SUITE_P(IToFConstantFoldingTest, FloatInstructionFoldingTest, ::testing::Values( // Test case 0: Fold float(3) InstructionFoldingCase( @@ -3763,7 +4466,7 @@ TEST_P(ToNegateFoldingTest, Case) { } // clang-format off -INSTANTIATE_TEST_CASE_P(FloatRedundantSubFoldingTest, ToNegateFoldingTest, +INSTANTIATE_TEST_SUITE_P(FloatRedundantSubFoldingTest, ToNegateFoldingTest, ::testing::Values( // Test case 0: Don't fold 1.0 - n InstructionFoldingCase( @@ -3807,7 +4510,7 @@ INSTANTIATE_TEST_CASE_P(FloatRedundantSubFoldingTest, ToNegateFoldingTest, 2, 3) )); -INSTANTIATE_TEST_CASE_P(DoubleRedundantSubFoldingTest, ToNegateFoldingTest, +INSTANTIATE_TEST_SUITE_P(DoubleRedundantSubFoldingTest, ToNegateFoldingTest, ::testing::Values( // Test case 0: Don't fold 1.0 - n InstructionFoldingCase( @@ -3851,7 +4554,6 @@ INSTANTIATE_TEST_CASE_P(DoubleRedundantSubFoldingTest, ToNegateFoldingTest, 2, 3) )); -#ifdef SPIRV_EFFCEE using MatchingInstructionFoldingTest = ::testing::TestWithParam>; @@ -3875,7 +4577,7 @@ TEST_P(MatchingInstructionFoldingTest, Case) { } } -INSTANTIATE_TEST_CASE_P(RedundantIntegerMatching, MatchingInstructionFoldingTest, +INSTANTIATE_TEST_SUITE_P(RedundantIntegerMatching, MatchingInstructionFoldingTest, ::testing::Values( // Test case 0: Fold 0 + n (change sign) InstructionFoldingCase( @@ -3905,7 +4607,7 @@ INSTANTIATE_TEST_CASE_P(RedundantIntegerMatching, MatchingInstructionFoldingTest 2, true) )); -INSTANTIATE_TEST_CASE_P(MergeNegateTest, MatchingInstructionFoldingTest, +INSTANTIATE_TEST_SUITE_P(MergeNegateTest, MatchingInstructionFoldingTest, ::testing::Values( // Test case 0: fold consecutive fnegate // -(-x) = x @@ -3927,7 +4629,7 @@ INSTANTIATE_TEST_CASE_P(MergeNegateTest, MatchingInstructionFoldingTest, InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + - "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2\n" + + "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2{{[[:space:]]}}\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" + "; CHECK: %4 = OpFMul [[float]] [[ld]] [[float_n2]]\n" + "%main = OpFunction %void None %void_func\n" + @@ -3944,7 +4646,7 @@ INSTANTIATE_TEST_CASE_P(MergeNegateTest, MatchingInstructionFoldingTest, InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + - "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2\n" + + "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2{{[[:space:]]}}\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" + "; CHECK: %4 = OpFMul [[float]] [[ld]] [[float_n2]]\n" + "%main = OpFunction %void None %void_func\n" + @@ -3978,7 +4680,7 @@ INSTANTIATE_TEST_CASE_P(MergeNegateTest, MatchingInstructionFoldingTest, InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + - "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2\n" + + "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2{{[[:space:]]}}\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" + "; CHECK: %4 = OpFDiv [[float]] [[float_n2]] [[ld]]\n" + "%main = OpFunction %void None %void_func\n" + @@ -3995,7 +4697,7 @@ INSTANTIATE_TEST_CASE_P(MergeNegateTest, MatchingInstructionFoldingTest, InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + - "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2\n" + + "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2{{[[:space:]]}}\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" + "; CHECK: %4 = OpFSub [[float]] [[float_n2]] [[ld]]\n" + "%main = OpFunction %void None %void_func\n" + @@ -4012,7 +4714,7 @@ INSTANTIATE_TEST_CASE_P(MergeNegateTest, MatchingInstructionFoldingTest, InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + - "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2\n" + + "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2{{[[:space:]]}}\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" + "; CHECK: %4 = OpFSub [[float]] [[float_n2]] [[ld]]\n" + "%main = OpFunction %void None %void_func\n" + @@ -4094,7 +4796,7 @@ INSTANTIATE_TEST_CASE_P(MergeNegateTest, MatchingInstructionFoldingTest, Header() + "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" + "; CHECK: OpConstant [[int]] -2147483648\n" + - "; CHECK: [[int_n2:%\\w+]] = OpConstant [[int]] -2\n" + + "; CHECK: [[int_n2:%\\w+]] = OpConstant [[int]] -2{{[[:space:]]}}\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" + "; CHECK: %4 = OpISub [[int]] [[int_n2]] [[ld]]\n" + "%main = OpFunction %void None %void_func\n" + @@ -4112,7 +4814,7 @@ INSTANTIATE_TEST_CASE_P(MergeNegateTest, MatchingInstructionFoldingTest, Header() + "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" + "; CHECK: OpConstant [[int]] -2147483648\n" + - "; CHECK: [[int_n2:%\\w+]] = OpConstant [[int]] -2\n" + + "; CHECK: [[int_n2:%\\w+]] = OpConstant [[int]] -2{{[[:space:]]}}\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" + "; CHECK: %4 = OpISub [[int]] [[int_n2]] [[ld]]\n" + "%main = OpFunction %void None %void_func\n" + @@ -4163,7 +4865,7 @@ INSTANTIATE_TEST_CASE_P(MergeNegateTest, MatchingInstructionFoldingTest, InstructionFoldingCase( Header() + "; CHECK: [[long:%\\w+]] = OpTypeInt 64 1\n" + - "; CHECK: [[long_n2:%\\w+]] = OpConstant [[long]] -2\n" + + "; CHECK: [[long_n2:%\\w+]] = OpConstant [[long]] -2{{[[:space:]]}}\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" + "; CHECK: %4 = OpISub [[long]] [[long_n2]] [[ld]]\n" + "%main = OpFunction %void None %void_func\n" + @@ -4213,11 +4915,11 @@ INSTANTIATE_TEST_CASE_P(MergeNegateTest, MatchingInstructionFoldingTest, InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + - "; CHECK: [[v4float:%\\w+]] = OpTypeVector [[float]] 4\n" + - "; CHECK: [[float_n1:%\\w+]] = OpConstant [[float]] -1\n" + - "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1\n" + - "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2\n" + - "; CHECK: [[float_n3:%\\w+]] = OpConstant [[float]] -3\n" + + "; CHECK: [[v4float:%\\w+]] = OpTypeVector [[float]] 4{{[[:space:]]}}\n" + + "; CHECK: [[float_n1:%\\w+]] = OpConstant [[float]] -1{{[[:space:]]}}\n" + + "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1{{[[:space:]]}}\n" + + "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2{{[[:space:]]}}\n" + + "; CHECK: [[float_n3:%\\w+]] = OpConstant [[float]] -3{{[[:space:]]}}\n" + "; CHECK: [[v4float_1_n2_n1_n3:%\\w+]] = OpConstantComposite [[v4float]] [[float_1]] [[float_n2]] [[float_n1]] [[float_n3]]\n" + "; CHECK: %2 = OpCopyObject [[v4float]] [[v4float_1_n2_n1_n3]]\n" + "%main = OpFunction %void None %void_func\n" + @@ -4242,7 +4944,7 @@ INSTANTIATE_TEST_CASE_P(MergeNegateTest, MatchingInstructionFoldingTest, 2, true) )); -INSTANTIATE_TEST_CASE_P(ReciprocalFDivTest, MatchingInstructionFoldingTest, +INSTANTIATE_TEST_SUITE_P(ReciprocalFDivTest, MatchingInstructionFoldingTest, ::testing::Values( // Test case 0: scalar reicprocal // x / 0.5 = x * 2.0 @@ -4323,7 +5025,7 @@ INSTANTIATE_TEST_CASE_P(ReciprocalFDivTest, MatchingInstructionFoldingTest, 3, false) )); -INSTANTIATE_TEST_CASE_P(MergeMulTest, MatchingInstructionFoldingTest, +INSTANTIATE_TEST_SUITE_P(MergeMulTest, MatchingInstructionFoldingTest, ::testing::Values( // Test case 0: fold consecutive fmuls // (x * 3.0) * 2.0 = x * 6.0 @@ -4586,9 +5288,9 @@ INSTANTIATE_TEST_CASE_P(MergeMulTest, MatchingInstructionFoldingTest, InstructionFoldingCase( Header() + "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" + - "; CHECK: [[v2int:%\\w+]] = OpTypeVector [[int]] 2\n" + - "; CHECK: OpConstant [[int]] -2147483648\n" + - "; CHECK: [[int_n2:%\\w+]] = OpConstant [[int]] -2\n" + + "; CHECK: [[v2int:%\\w+]] = OpTypeVector [[int]] 2{{[[:space:]]}}\n" + + "; CHECK: OpConstant [[int]] -2147483648{{[[:space:]]}}\n" + + "; CHECK: [[int_n2:%\\w+]] = OpConstant [[int]] -2{{[[:space:]]}}\n" + "; CHECK: [[v2int_n2_n2:%\\w+]] = OpConstantComposite [[v2int]] [[int_n2]] [[int_n2]]\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[v2int]]\n" + "; CHECK: %4 = OpIMul [[v2int]] [[ld]] [[v2int_n2_n2]]\n" + @@ -4606,9 +5308,9 @@ INSTANTIATE_TEST_CASE_P(MergeMulTest, MatchingInstructionFoldingTest, InstructionFoldingCase( Header() + "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" + - "; CHECK: [[v2int:%\\w+]] = OpTypeVector [[int]] 2\n" + - "; CHECK: OpConstant [[int]] -2147483648\n" + - "; CHECK: [[int_n2:%\\w+]] = OpConstant [[int]] -2\n" + + "; CHECK: [[v2int:%\\w+]] = OpTypeVector [[int]] 2{{[[:space:]]}}\n" + + "; CHECK: OpConstant [[int]] -2147483648{{[[:space:]]}}\n" + + "; CHECK: [[int_n2:%\\w+]] = OpConstant [[int]] -2{{[[:space:]]}}\n" + "; CHECK: [[v2int_n2_n2:%\\w+]] = OpConstantComposite [[v2int]] [[int_n2]] [[int_n2]]\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[v2int]]\n" + "; CHECK: %4 = OpIMul [[v2int]] [[ld]] [[v2int_n2_n2]]\n" + @@ -4739,7 +5441,7 @@ INSTANTIATE_TEST_CASE_P(MergeMulTest, MatchingInstructionFoldingTest, 5, true) )); -INSTANTIATE_TEST_CASE_P(MergeDivTest, MatchingInstructionFoldingTest, +INSTANTIATE_TEST_SUITE_P(MergeDivTest, MatchingInstructionFoldingTest, ::testing::Values( // Test case 0: merge consecutive fdiv // 4.0 / (2.0 / x) = 2.0 * x @@ -4902,7 +5604,7 @@ INSTANTIATE_TEST_CASE_P(MergeDivTest, MatchingInstructionFoldingTest, Header() + "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" + "; CHECK: OpConstant [[int]] -2147483648\n" + - "; CHECK: [[int_n2:%\\w+]] = OpConstant [[int]] -2\n" + + "; CHECK: [[int_n2:%\\w+]] = OpConstant [[int]] -2{{[[:space:]]}}\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" + "; CHECK: %4 = OpSDiv [[int]] [[ld]] [[int_n2]]\n" + "%main = OpFunction %void None %void_func\n" + @@ -4920,7 +5622,7 @@ INSTANTIATE_TEST_CASE_P(MergeDivTest, MatchingInstructionFoldingTest, Header() + "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" + "; CHECK: OpConstant [[int]] -2147483648\n" + - "; CHECK: [[int_n2:%\\w+]] = OpConstant [[int]] -2\n" + + "; CHECK: [[int_n2:%\\w+]] = OpConstant [[int]] -2{{[[:space:]]}}\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" + "; CHECK: %4 = OpSDiv [[int]] [[int_n2]] [[ld]]\n" + "%main = OpFunction %void None %void_func\n" + @@ -4985,7 +5687,7 @@ INSTANTIATE_TEST_CASE_P(MergeDivTest, MatchingInstructionFoldingTest, 5, true) )); -INSTANTIATE_TEST_CASE_P(MergeAddTest, MatchingInstructionFoldingTest, +INSTANTIATE_TEST_SUITE_P(MergeAddTest, MatchingInstructionFoldingTest, ::testing::Values( // Test case 0: merge add of negate // (-x) + 2 = 2 - x @@ -5193,14 +5895,140 @@ INSTANTIATE_TEST_CASE_P(MergeAddTest, MatchingInstructionFoldingTest, 4, true) )); -INSTANTIATE_TEST_CASE_P(MergeSubTest, MatchingInstructionFoldingTest, +INSTANTIATE_TEST_SUITE_P(MergeGenericAddSub, MatchingInstructionFoldingTest, +::testing::Values( + // Test case 0: merge of add of sub + // (a - b) + b => a + InstructionFoldingCase( + Header() + + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + + "; CHECK: %6 = OpCopyObject [[float]] %3\n" + + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%var0 = OpVariable %_ptr_float Function\n" + + "%var1 = OpVariable %_ptr_float Function\n" + + "%3 = OpLoad %float %var0\n" + + "%4 = OpLoad %float %var1\n" + + "%5 = OpFSub %float %3 %4\n" + + "%6 = OpFAdd %float %5 %4\n" + + "OpReturn\n" + + "OpFunctionEnd\n", + 6, true), + // Test case 1: merge of add of sub + // b + (a - b) => a + InstructionFoldingCase( + Header() + + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + + "; CHECK: %6 = OpCopyObject [[float]] %3\n" + + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%var0 = OpVariable %_ptr_float Function\n" + + "%var1 = OpVariable %_ptr_float Function\n" + + "%3 = OpLoad %float %var0\n" + + "%4 = OpLoad %float %var1\n" + + "%5 = OpFSub %float %3 %4\n" + + "%6 = OpFAdd %float %4 %5\n" + + "OpReturn\n" + + "OpFunctionEnd\n", + 6, true) +)); + +INSTANTIATE_TEST_SUITE_P(FactorAddMul, MatchingInstructionFoldingTest, +::testing::Values( + // Test case 0: factor of add of muls + // (a * b) + (a * c) => a * (b + c) + InstructionFoldingCase( + Header() + + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + + "; CHECK: [[newadd:%\\w+]] = OpFAdd [[float]] %4 %5\n" + + "; CHECK: %9 = OpFMul [[float]] %6 [[newadd]]\n" + + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%var0 = OpVariable %_ptr_float Function\n" + + "%var1 = OpVariable %_ptr_float Function\n" + + "%var2 = OpVariable %_ptr_float Function\n" + + "%4 = OpLoad %float %var0\n" + + "%5 = OpLoad %float %var1\n" + + "%6 = OpLoad %float %var2\n" + + "%7 = OpFMul %float %6 %4\n" + + "%8 = OpFMul %float %6 %5\n" + + "%9 = OpFAdd %float %7 %8\n" + + "OpReturn\n" + + "OpFunctionEnd\n", + 9, true), + // Test case 1: factor of add of muls + // (b * a) + (a * c) => a * (b + c) + InstructionFoldingCase( + Header() + + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + + "; CHECK: [[newadd:%\\w+]] = OpFAdd [[float]] %4 %5\n" + + "; CHECK: %9 = OpFMul [[float]] %6 [[newadd]]\n" + + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%var0 = OpVariable %_ptr_float Function\n" + + "%var1 = OpVariable %_ptr_float Function\n" + + "%var2 = OpVariable %_ptr_float Function\n" + + "%4 = OpLoad %float %var0\n" + + "%5 = OpLoad %float %var1\n" + + "%6 = OpLoad %float %var2\n" + + "%7 = OpFMul %float %4 %6\n" + + "%8 = OpFMul %float %6 %5\n" + + "%9 = OpFAdd %float %7 %8\n" + + "OpReturn\n" + + "OpFunctionEnd\n", + 9, true), + // Test case 2: factor of add of muls + // (a * b) + (c * a) => a * (b + c) + InstructionFoldingCase( + Header() + + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + + "; CHECK: [[newadd:%\\w+]] = OpFAdd [[float]] %4 %5\n" + + "; CHECK: %9 = OpFMul [[float]] %6 [[newadd]]\n" + + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%var0 = OpVariable %_ptr_float Function\n" + + "%var1 = OpVariable %_ptr_float Function\n" + + "%var2 = OpVariable %_ptr_float Function\n" + + "%4 = OpLoad %float %var0\n" + + "%5 = OpLoad %float %var1\n" + + "%6 = OpLoad %float %var2\n" + + "%7 = OpFMul %float %6 %4\n" + + "%8 = OpFMul %float %5 %6\n" + + "%9 = OpFAdd %float %7 %8\n" + + "OpReturn\n" + + "OpFunctionEnd\n", + 9, true), + // Test case 3: factor of add of muls + // (b * a) + (c * a) => a * (b + c) + InstructionFoldingCase( + Header() + + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + + "; CHECK: [[newadd:%\\w+]] = OpFAdd [[float]] %4 %5\n" + + "; CHECK: %9 = OpFMul [[float]] %6 [[newadd]]\n" + + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%var0 = OpVariable %_ptr_float Function\n" + + "%var1 = OpVariable %_ptr_float Function\n" + + "%var2 = OpVariable %_ptr_float Function\n" + + "%4 = OpLoad %float %var0\n" + + "%5 = OpLoad %float %var1\n" + + "%6 = OpLoad %float %var2\n" + + "%7 = OpFMul %float %4 %6\n" + + "%8 = OpFMul %float %5 %6\n" + + "%9 = OpFAdd %float %7 %8\n" + + "OpReturn\n" + + "OpFunctionEnd\n", + 9, true) +)); + +INSTANTIATE_TEST_SUITE_P(MergeSubTest, MatchingInstructionFoldingTest, ::testing::Values( // Test case 0: merge sub of negate // (-x) - 2 = -2 - x InstructionFoldingCase( Header() + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + - "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2\n" + + "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2{{[[:space:]]}}\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" + "; CHECK: %4 = OpFSub [[float]] [[float_n2]] [[ld]]\n" + "%main = OpFunction %void None %void_func\n" + @@ -5234,7 +6062,7 @@ INSTANTIATE_TEST_CASE_P(MergeSubTest, MatchingInstructionFoldingTest, InstructionFoldingCase( Header() + "; CHECK: [[long:%\\w+]] = OpTypeInt 64 1\n" + - "; CHECK: [[long_n2:%\\w+]] = OpConstant [[long]] -2\n" + + "; CHECK: [[long_n2:%\\w+]] = OpConstant [[long]] -2{{[[:space:]]}}\n" + "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" + "; CHECK: %4 = OpISub [[long]] [[long_n2]] [[ld]]\n" + "%main = OpFunction %void None %void_func\n" + @@ -5415,10 +6243,27 @@ INSTANTIATE_TEST_CASE_P(MergeSubTest, MatchingInstructionFoldingTest, "%4 = OpFSub %float %float_2 %3\n" + "OpReturn\n" + "OpFunctionEnd\n", + 4, true), + // Test case 13: merge subtract of subtract with mixed types. + // 2 - (1 - x) = x + 1 + InstructionFoldingCase( + Header() + + "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" + + "; CHECK: [[int_1:%\\w+]] = OpConstant [[int]] 1\n" + + "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" + + "; CHECK: %4 = OpIAdd [[int]] [[ld]] [[int_1]]\n" + + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%var = OpVariable %_ptr_int Function\n" + + "%2 = OpLoad %int %var\n" + + "%3 = OpISub %int %uint_1 %2\n" + + "%4 = OpISub %int %int_2 %3\n" + + "OpReturn\n" + + "OpFunctionEnd\n", 4, true) )); -INSTANTIATE_TEST_CASE_P(SelectFoldingTest, MatchingInstructionFoldingTest, +INSTANTIATE_TEST_SUITE_P(SelectFoldingTest, MatchingInstructionFoldingTest, ::testing::Values( // Test case 0: Fold select with the same values for both sides InstructionFoldingCase( @@ -5526,7 +6371,7 @@ INSTANTIATE_TEST_CASE_P(SelectFoldingTest, MatchingInstructionFoldingTest, 4, true) )); -INSTANTIATE_TEST_CASE_P(CompositeExtractMatchingTest, MatchingInstructionFoldingTest, +INSTANTIATE_TEST_SUITE_P(CompositeExtractMatchingTest, MatchingInstructionFoldingTest, ::testing::Values( // Test case 0: Extracting from result of consecutive shuffles of differing // size. @@ -5669,7 +6514,7 @@ INSTANTIATE_TEST_CASE_P(CompositeExtractMatchingTest, MatchingInstructionFolding 4, true) )); -INSTANTIATE_TEST_CASE_P(DotProductMatchingTest, MatchingInstructionFoldingTest, +INSTANTIATE_TEST_SUITE_P(DotProductMatchingTest, MatchingInstructionFoldingTest, ::testing::Values( // Test case 0: Using OpDot to extract last element. InstructionFoldingCase( @@ -5785,9 +6630,9 @@ TEST_P(MatchingInstructionWithNoResultFoldingTest, Case) { } } -INSTANTIATE_TEST_CASE_P(StoreMatchingTest, MatchingInstructionWithNoResultFoldingTest, +INSTANTIATE_TEST_SUITE_P(StoreMatchingTest, MatchingInstructionWithNoResultFoldingTest, ::testing::Values( - // Test case 0: Using OpDot to extract last element. + // Test case 0: Remove store of undef. InstructionFoldingCase( Header() + "; CHECK: OpLabel\n" + @@ -5800,10 +6645,21 @@ INSTANTIATE_TEST_CASE_P(StoreMatchingTest, MatchingInstructionWithNoResultFoldin "OpStore %n %undef\n" + "OpReturn\n" + "OpFunctionEnd", - 0 /* OpStore */, true) + 0 /* OpStore */, true), + // Test case 1: Keep volatile store. + InstructionFoldingCase( + Header() + + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%n = OpVariable %_ptr_v4double Function\n" + + "%undef = OpUndef %v4double\n" + + "OpStore %n %undef Volatile\n" + + "OpReturn\n" + + "OpFunctionEnd", + 0 /* OpStore */, false) )); -INSTANTIATE_TEST_CASE_P(VectorShuffleMatchingTest, MatchingInstructionWithNoResultFoldingTest, +INSTANTIATE_TEST_SUITE_P(VectorShuffleMatchingTest, MatchingInstructionWithNoResultFoldingTest, ::testing::Values( // Test case 0: Basic test 1 InstructionFoldingCase( @@ -6075,7 +6931,371 @@ INSTANTIATE_TEST_CASE_P(VectorShuffleMatchingTest, MatchingInstructionWithNoResu "OpFunctionEnd", 9, true) )); -#endif + +using EntryPointFoldingTest = +::testing::TestWithParam>; + +TEST_P(EntryPointFoldingTest, Case) { + const auto& tc = GetParam(); + + // Build module. + std::unique_ptr context = + BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + ASSERT_NE(nullptr, context); + + // Fold the instruction to test. + Instruction* inst = nullptr; + inst = &*context->module()->entry_points().begin(); + assert(inst && "Invalid test. Could not find entry point instruction to fold."); + std::unique_ptr original_inst(inst->Clone(context.get())); + bool succeeded = context->get_instruction_folder().FoldInstruction(inst); + EXPECT_EQ(succeeded, tc.expected_result); + if (succeeded) { + Match(tc.test_body, context.get()); + } +} + +INSTANTIATE_TEST_SUITE_P(OpEntryPointFoldingTest, EntryPointFoldingTest, +::testing::Values( + // Test case 0: Basic test 1 + InstructionFoldingCase(std::string() + + "; CHECK: OpEntryPoint Fragment %2 \"main\" %3\n" + + "OpCapability Shader\n" + + "%1 = OpExtInstImport \"GLSL.std.450\"\n" + + "OpMemoryModel Logical GLSL450\n" + + "OpEntryPoint Fragment %2 \"main\" %3 %3 %3\n" + + "OpExecutionMode %2 OriginUpperLeft\n" + + "OpSource GLSL 430\n" + + "OpDecorate %3 Location 0\n" + + "%void = OpTypeVoid\n" + + "%5 = OpTypeFunction %void\n" + + "%float = OpTypeFloat 32\n" + + "%v4float = OpTypeVector %float 4\n" + + "%_ptr_Output_v4float = OpTypePointer Output %v4float\n" + + "%3 = OpVariable %_ptr_Output_v4float Output\n" + + "%int = OpTypeInt 32 1\n" + + "%int_0 = OpConstant %int 0\n" + +"%_ptr_PushConstant_v4float = OpTypePointer PushConstant %v4float\n" + + "%2 = OpFunction %void None %5\n" + + "%12 = OpLabel\n" + + "OpReturn\n" + + "OpFunctionEnd\n", + 9, true), + InstructionFoldingCase(std::string() + + "; CHECK: OpEntryPoint Fragment %2 \"main\" %3 %4\n" + + "OpCapability Shader\n" + + "%1 = OpExtInstImport \"GLSL.std.450\"\n" + + "OpMemoryModel Logical GLSL450\n" + + "OpEntryPoint Fragment %2 \"main\" %3 %4 %3\n" + + "OpExecutionMode %2 OriginUpperLeft\n" + + "OpSource GLSL 430\n" + + "OpDecorate %3 Location 0\n" + + "%void = OpTypeVoid\n" + + "%5 = OpTypeFunction %void\n" + + "%float = OpTypeFloat 32\n" + + "%v4float = OpTypeVector %float 4\n" + + "%_ptr_Output_v4float = OpTypePointer Output %v4float\n" + + "%3 = OpVariable %_ptr_Output_v4float Output\n" + + "%4 = OpVariable %_ptr_Output_v4float Output\n" + + "%int = OpTypeInt 32 1\n" + + "%int_0 = OpConstant %int 0\n" + +"%_ptr_PushConstant_v4float = OpTypePointer PushConstant %v4float\n" + + "%2 = OpFunction %void None %5\n" + + "%12 = OpLabel\n" + + "OpReturn\n" + + "OpFunctionEnd\n", + 9, true), + InstructionFoldingCase(std::string() + + "; CHECK: OpEntryPoint Fragment %2 \"main\" %4 %3\n" + + "OpCapability Shader\n" + + "%1 = OpExtInstImport \"GLSL.std.450\"\n" + + "OpMemoryModel Logical GLSL450\n" + + "OpEntryPoint Fragment %2 \"main\" %4 %4 %3\n" + + "OpExecutionMode %2 OriginUpperLeft\n" + + "OpSource GLSL 430\n" + + "OpDecorate %3 Location 0\n" + + "%void = OpTypeVoid\n" + + "%5 = OpTypeFunction %void\n" + + "%float = OpTypeFloat 32\n" + + "%v4float = OpTypeVector %float 4\n" + + "%_ptr_Output_v4float = OpTypePointer Output %v4float\n" + + "%3 = OpVariable %_ptr_Output_v4float Output\n" + + "%4 = OpVariable %_ptr_Output_v4float Output\n" + + "%int = OpTypeInt 32 1\n" + + "%int_0 = OpConstant %int 0\n" + +"%_ptr_PushConstant_v4float = OpTypePointer PushConstant %v4float\n" + + "%2 = OpFunction %void None %5\n" + + "%12 = OpLabel\n" + + "OpReturn\n" + + "OpFunctionEnd\n", + 9, true) +)); + +using SPV14FoldingTest = +::testing::TestWithParam>; + +TEST_P(SPV14FoldingTest, Case) { + const auto& tc = GetParam(); + + // Build module. + std::unique_ptr context = + BuildModule(SPV_ENV_UNIVERSAL_1_4, nullptr, tc.test_body, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + ASSERT_NE(nullptr, context); + + // Fold the instruction to test. + analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr(); + Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold); + std::unique_ptr original_inst(inst->Clone(context.get())); + bool succeeded = context->get_instruction_folder().FoldInstruction(inst); + EXPECT_EQ(succeeded, tc.expected_result); + if (succeeded) { + Match(tc.test_body, context.get()); + } +} + +INSTANTIATE_TEST_SUITE_P(SPV14FoldingTest, SPV14FoldingTest, +::testing::Values( + // Test case 0: select vectors with scalar condition. + InstructionFoldingCase(std::string() + +"; CHECK-NOT: OpSelect\n" + +"; CHECK: %3 = OpCopyObject {{%\\w+}} %1\n" + +"OpCapability Shader\n" + +"OpCapability Linkage\n" + +"%void = OpTypeVoid\n" + +"%bool = OpTypeBool\n" + +"%true = OpConstantTrue %bool\n" + +"%int = OpTypeInt 32 0\n" + +"%int4 = OpTypeVector %int 4\n" + +"%int_0 = OpConstant %int 0\n" + +"%int_1 = OpConstant %int 1\n" + +"%1 = OpUndef %int4\n" + +"%2 = OpUndef %int4\n" + +"%void_fn = OpTypeFunction %void\n" + +"%func = OpFunction %void None %void_fn\n" + +"%entry = OpLabel\n" + +"%3 = OpSelect %int4 %true %1 %2\n" + +"OpReturn\n" + +"OpFunctionEnd\n" +, + 3, true), + // Test case 1: select struct with scalar condition. + InstructionFoldingCase(std::string() + +"; CHECK-NOT: OpSelect\n" + +"; CHECK: %3 = OpCopyObject {{%\\w+}} %2\n" + +"OpCapability Shader\n" + +"OpCapability Linkage\n" + +"%void = OpTypeVoid\n" + +"%bool = OpTypeBool\n" + +"%true = OpConstantFalse %bool\n" + +"%int = OpTypeInt 32 0\n" + +"%struct = OpTypeStruct %int %int %int %int\n" + +"%int_0 = OpConstant %int 0\n" + +"%int_1 = OpConstant %int 1\n" + +"%1 = OpUndef %struct\n" + +"%2 = OpUndef %struct\n" + +"%void_fn = OpTypeFunction %void\n" + +"%func = OpFunction %void None %void_fn\n" + +"%entry = OpLabel\n" + +"%3 = OpSelect %struct %true %1 %2\n" + +"OpReturn\n" + +"OpFunctionEnd\n" +, + 3, true), + // Test case 1: select array with scalar condition. + InstructionFoldingCase(std::string() + +"; CHECK-NOT: OpSelect\n" + +"; CHECK: %3 = OpCopyObject {{%\\w+}} %2\n" + +"OpCapability Shader\n" + +"OpCapability Linkage\n" + +"%void = OpTypeVoid\n" + +"%bool = OpTypeBool\n" + +"%true = OpConstantFalse %bool\n" + +"%int = OpTypeInt 32 0\n" + +"%int_0 = OpConstant %int 0\n" + +"%int_1 = OpConstant %int 1\n" + +"%int_4 = OpConstant %int 4\n" + +"%array = OpTypeStruct %int %int %int %int\n" + +"%1 = OpUndef %array\n" + +"%2 = OpUndef %array\n" + +"%void_fn = OpTypeFunction %void\n" + +"%func = OpFunction %void None %void_fn\n" + +"%entry = OpLabel\n" + +"%3 = OpSelect %array %true %1 %2\n" + +"OpReturn\n" + +"OpFunctionEnd\n" +, + 3, true) +)); + +std::string FloatControlsHeader(const std::string& capabilities) { + std::string header = R"( +OpCapability Shader +)" + capabilities + R"( +%void = OpTypeVoid +%float = OpTypeFloat 32 +%float_0 = OpConstant %float 0 +%float_1 = OpConstant %float 1 +%void_fn = OpTypeFunction %void +%func = OpFunction %void None %void_fn +%entry = OpLabel +)"; + + return header; +} + +using FloatControlsFoldingTest = +::testing::TestWithParam>; + +TEST_P(FloatControlsFoldingTest, Case) { + const auto& tc = GetParam(); + + // Build module. + std::unique_ptr context = + BuildModule(SPV_ENV_UNIVERSAL_1_4, nullptr, tc.test_body, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + ASSERT_NE(nullptr, context); + + // Fold the instruction to test. + analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr(); + Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold); + std::unique_ptr original_inst(inst->Clone(context.get())); + bool succeeded = context->get_instruction_folder().FoldInstruction(inst); + EXPECT_EQ(succeeded, tc.expected_result); + if (succeeded) { + Match(tc.test_body, context.get()); + } +} + +INSTANTIATE_TEST_SUITE_P(FloatControlsFoldingTest, FloatControlsFoldingTest, +::testing::Values( + // Test case 0: no folding with DenormPreserve + InstructionFoldingCase(FloatControlsHeader("OpCapability DenormPreserve") + + "%1 = OpFAdd %float %float_0 %float_1\n" + + "OpReturn\n" + + "OpFunctionEnd\n" +, + 1, false), + // Test case 1: no folding with DenormFlushToZero + InstructionFoldingCase(FloatControlsHeader("OpCapability DenormFlushToZero") + + "%1 = OpFAdd %float %float_0 %float_1\n" + + "OpReturn\n" + + "OpFunctionEnd\n" +, + 1, false), + // Test case 2: no folding with SignedZeroInfNanPreserve + InstructionFoldingCase(FloatControlsHeader("OpCapability SignedZeroInfNanPreserve") + + "%1 = OpFAdd %float %float_0 %float_1\n" + + "OpReturn\n" + + "OpFunctionEnd\n" +, + 1, false), + // Test case 3: no folding with RoundingModeRTE + InstructionFoldingCase(FloatControlsHeader("OpCapability RoundingModeRTE") + + "%1 = OpFAdd %float %float_0 %float_1\n" + + "OpReturn\n" + + "OpFunctionEnd\n" +, + 1, false), + // Test case 4: no folding with RoundingModeRTZ + InstructionFoldingCase(FloatControlsHeader("OpCapability RoundingModeRTZ") + + "%1 = OpFAdd %float %float_0 %float_1\n" + + "OpReturn\n" + + "OpFunctionEnd\n" +, + 1, false) +)); + +std::string ImageOperandsTestBody(const std::string& image_instruction) { + std::string body = R"( + OpCapability Shader + OpCapability ImageGatherExtended + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" + OpExecutionMode %main OriginUpperLeft + OpDecorate %Texture DescriptorSet 0 + OpDecorate %Texture Binding 0 + %int = OpTypeInt 32 1 + %int_n1 = OpConstant %int -1 + %5 = OpConstant %int 0 + %float = OpTypeFloat 32 + %float_0 = OpConstant %float 0 +%type_2d_image = OpTypeImage %float 2D 2 0 0 1 Unknown +%type_sampled_image = OpTypeSampledImage %type_2d_image +%type_sampler = OpTypeSampler +%_ptr_UniformConstant_type_sampler = OpTypePointer UniformConstant %type_sampler +%_ptr_UniformConstant_type_2d_image = OpTypePointer UniformConstant %type_2d_image + %_ptr_int = OpTypePointer Function %int + %v2int = OpTypeVector %int 2 + %10 = OpTypeVector %float 4 + %void = OpTypeVoid + %22 = OpTypeFunction %void + %v2float = OpTypeVector %float 2 + %v3int = OpTypeVector %int 3 + %Texture = OpVariable %_ptr_UniformConstant_type_2d_image UniformConstant + %gSampler = OpVariable %_ptr_UniformConstant_type_sampler UniformConstant + %101 = OpConstantComposite %v2int %int_n1 %int_n1 + %20 = OpConstantComposite %v2float %float_0 %float_0 + %main = OpFunction %void None %22 + %23 = OpLabel + %var = OpVariable %_ptr_int Function + %88 = OpLoad %type_2d_image %Texture + %val = OpLoad %int %var + %sampler = OpLoad %type_sampler %gSampler + %26 = OpSampledImage %type_sampled_image %88 %sampler +)" + image_instruction + R"( + OpReturn + OpFunctionEnd +)"; + + return body; +} + +INSTANTIATE_TEST_SUITE_P(ImageOperandsBitmaskFoldingTest, MatchingInstructionWithNoResultFoldingTest, +::testing::Values( + // Test case 0: OpImageFetch without Offset + InstructionFoldingCase(ImageOperandsTestBody( + "%89 = OpImageFetch %10 %88 %101 Lod %5 \n") + , 89, false), + // Test case 1: OpImageFetch with non-const offset + InstructionFoldingCase(ImageOperandsTestBody( + "%89 = OpImageFetch %10 %88 %101 Lod|Offset %5 %val \n") + , 89, false), + // Test case 2: OpImageFetch with Lod and Offset + InstructionFoldingCase(ImageOperandsTestBody( + " %89 = OpImageFetch %10 %88 %101 Lod|Offset %5 %101 \n" + "; CHECK: %89 = OpImageFetch %10 %88 %101 Lod|ConstOffset %5 %101 \n") + , 89, true), + // Test case 3: OpImageFetch with Bias and Offset + InstructionFoldingCase(ImageOperandsTestBody( + " %89 = OpImageFetch %10 %88 %101 Bias|Offset %5 %101 \n" + "; CHECK: %89 = OpImageFetch %10 %88 %101 Bias|ConstOffset %5 %101 \n") + , 89, true), + // Test case 4: OpImageFetch with Grad and Offset. + // Grad adds 2 operands to the instruction. + InstructionFoldingCase(ImageOperandsTestBody( + " %89 = OpImageFetch %10 %88 %101 Grad|Offset %5 %5 %101 \n" + "; CHECK: %89 = OpImageFetch %10 %88 %101 Grad|ConstOffset %5 %5 %101 \n") + , 89, true), + // Test case 5: OpImageFetch with Offset and MinLod. + // This is an example of a case where the bitmask bit-offset is larger than + // that of the Offset. + InstructionFoldingCase(ImageOperandsTestBody( + " %89 = OpImageFetch %10 %88 %101 Offset|MinLod %101 %5 \n" + "; CHECK: %89 = OpImageFetch %10 %88 %101 ConstOffset|MinLod %101 %5 \n") + , 89, true), + // Test case 6: OpImageGather with constant Offset + InstructionFoldingCase(ImageOperandsTestBody( + " %89 = OpImageGather %10 %26 %20 %5 Offset %101 \n" + "; CHECK: %89 = OpImageGather %10 %26 %20 %5 ConstOffset %101 \n") + , 89, true), + // Test case 7: OpImageWrite with constant Offset + InstructionFoldingCase(ImageOperandsTestBody( + " OpImageWrite %88 %5 %101 Offset %101 \n" + "; CHECK: OpImageWrite %88 %5 %101 ConstOffset %101 \n") + , 0 /* No result-id */, true) +)); } // namespace } // namespace opt diff --git a/third_party/spirv-tools/test/opt/freeze_spec_const_test.cpp b/third_party/spirv-tools/test/opt/freeze_spec_const_test.cpp index 5cc7843b11..e5999cec63 100644 --- a/third_party/spirv-tools/test/opt/freeze_spec_const_test.cpp +++ b/third_party/spirv-tools/test/opt/freeze_spec_const_test.cpp @@ -47,7 +47,7 @@ TEST_P(FreezeSpecConstantValueTypeTest, PrimaryType) { } // Test each primary type. -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( PrimaryTypeSpecConst, FreezeSpecConstantValueTypeTest, ::testing::ValuesIn(std::vector({ // Type declaration, original spec constant definition, expected frozen diff --git a/third_party/spirv-tools/test/opt/function_test.cpp b/third_party/spirv-tools/test/opt/function_test.cpp new file mode 100644 index 0000000000..38ab298767 --- /dev/null +++ b/third_party/spirv-tools/test/opt/function_test.cpp @@ -0,0 +1,173 @@ +// Copyright (c) 2018 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 +#include +#include +#include + +#include "function_utils.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include "source/opt/build_module.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace opt { +namespace { + +using ::testing::Eq; + +TEST(FunctionTest, IsNotRecursive) { + const std::string text = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %1 "main" +OpExecutionMode %1 OriginUpperLeft +OpDecorate %2 DescriptorSet 439418829 +%void = OpTypeVoid +%4 = OpTypeFunction %void +%float = OpTypeFloat 32 +%_struct_6 = OpTypeStruct %float %float +%7 = OpTypeFunction %_struct_6 +%1 = OpFunction %void Pure|Const %4 +%8 = OpLabel +%2 = OpFunctionCall %_struct_6 %9 +OpKill +OpFunctionEnd +%9 = OpFunction %_struct_6 None %7 +%10 = OpLabel +%11 = OpFunctionCall %_struct_6 %12 +OpUnreachable +OpFunctionEnd +%12 = OpFunction %_struct_6 None %7 +%13 = OpLabel +OpUnreachable +OpFunctionEnd +)"; + + std::unique_ptr ctx = + spvtools::BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + auto* func = spvtest::GetFunction(ctx->module(), 9); + EXPECT_FALSE(func->IsRecursive()); + + func = spvtest::GetFunction(ctx->module(), 12); + EXPECT_FALSE(func->IsRecursive()); +} + +TEST(FunctionTest, IsDirectlyRecursive) { + const std::string text = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %1 "main" +OpExecutionMode %1 OriginUpperLeft +OpDecorate %2 DescriptorSet 439418829 +%void = OpTypeVoid +%4 = OpTypeFunction %void +%float = OpTypeFloat 32 +%_struct_6 = OpTypeStruct %float %float +%7 = OpTypeFunction %_struct_6 +%1 = OpFunction %void Pure|Const %4 +%8 = OpLabel +%2 = OpFunctionCall %_struct_6 %9 +OpKill +OpFunctionEnd +%9 = OpFunction %_struct_6 None %7 +%10 = OpLabel +%11 = OpFunctionCall %_struct_6 %9 +OpUnreachable +OpFunctionEnd +)"; + + std::unique_ptr ctx = + spvtools::BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + auto* func = spvtest::GetFunction(ctx->module(), 9); + EXPECT_TRUE(func->IsRecursive()); +} + +TEST(FunctionTest, IsIndirectlyRecursive) { + const std::string text = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %1 "main" +OpExecutionMode %1 OriginUpperLeft +OpDecorate %2 DescriptorSet 439418829 +%void = OpTypeVoid +%4 = OpTypeFunction %void +%float = OpTypeFloat 32 +%_struct_6 = OpTypeStruct %float %float +%7 = OpTypeFunction %_struct_6 +%1 = OpFunction %void Pure|Const %4 +%8 = OpLabel +%2 = OpFunctionCall %_struct_6 %9 +OpKill +OpFunctionEnd +%9 = OpFunction %_struct_6 None %7 +%10 = OpLabel +%11 = OpFunctionCall %_struct_6 %12 +OpUnreachable +OpFunctionEnd +%12 = OpFunction %_struct_6 None %7 +%13 = OpLabel +%14 = OpFunctionCall %_struct_6 %9 +OpUnreachable +OpFunctionEnd +)"; + + std::unique_ptr ctx = + spvtools::BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + auto* func = spvtest::GetFunction(ctx->module(), 9); + EXPECT_TRUE(func->IsRecursive()); + + func = spvtest::GetFunction(ctx->module(), 12); + EXPECT_TRUE(func->IsRecursive()); +} + +TEST(FunctionTest, IsNotRecuriseCallingRecursive) { + const std::string text = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %1 "main" +OpExecutionMode %1 OriginUpperLeft +OpDecorate %2 DescriptorSet 439418829 +%void = OpTypeVoid +%4 = OpTypeFunction %void +%float = OpTypeFloat 32 +%_struct_6 = OpTypeStruct %float %float +%7 = OpTypeFunction %_struct_6 +%1 = OpFunction %void Pure|Const %4 +%8 = OpLabel +%2 = OpFunctionCall %_struct_6 %9 +OpKill +OpFunctionEnd +%9 = OpFunction %_struct_6 None %7 +%10 = OpLabel +%11 = OpFunctionCall %_struct_6 %9 +OpUnreachable +OpFunctionEnd +)"; + + std::unique_ptr ctx = + spvtools::BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + auto* func = spvtest::GetFunction(ctx->module(), 1); + EXPECT_FALSE(func->IsRecursive()); +} + +} // namespace +} // namespace opt +} // namespace spvtools diff --git a/third_party/spirv-tools/test/opt/generate_webgpu_initializers_test.cpp b/third_party/spirv-tools/test/opt/generate_webgpu_initializers_test.cpp new file mode 100644 index 0000000000..4aab2ce21f --- /dev/null +++ b/third_party/spirv-tools/test/opt/generate_webgpu_initializers_test.cpp @@ -0,0 +1,347 @@ +// Copyright (c) 2019 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 + +#include "test/opt/pass_fixture.h" +#include "test/opt/pass_utils.h" + +namespace spvtools { +namespace opt { +namespace { + +typedef std::tuple GenerateWebGPUInitializersParam; + +using GlobalVariableTest = + PassTest<::testing::TestWithParam>; +using LocalVariableTest = + PassTest<::testing::TestWithParam>; + +using GenerateWebGPUInitializersTest = PassTest<::testing::Test>; + +void operator+=(std::vector& lhs, const char* rhs) { + lhs.push_back(rhs); +} + +void operator+=(std::vector& lhs, + const std::vector& rhs) { + lhs.reserve(lhs.size() + rhs.size()); + for (auto* c : rhs) lhs.push_back(c); +} + +std::string GetGlobalVariableTestString(std::string ptr_str, + std::string var_str, + std::string const_str = "") { + std::vector result = { + // clang-format off + "OpCapability Shader", + "OpCapability VulkanMemoryModel", + "OpExtension \"SPV_KHR_vulkan_memory_model\"", + "OpMemoryModel Logical Vulkan", + "OpEntryPoint Vertex %1 \"shader\"", + "%uint = OpTypeInt 32 0", + ptr_str.c_str()}; + // clang-format on + + if (!const_str.empty()) result += const_str.c_str(); + + result += { + // clang-format off + var_str.c_str(), + "%uint_0 = OpConstant %uint 0", + "%void = OpTypeVoid", + "%7 = OpTypeFunction %void", + "%1 = OpFunction %void None %7", + "%8 = OpLabel", + "OpStore %4 %uint_0", + "OpReturn", + "OpFunctionEnd" + // clang-format on + }; + return JoinAllInsts(result); +} + +std::string GetPointerString(std::string storage_type) { + std::string result = "%_ptr_"; + result += storage_type + "_uint = OpTypePointer "; + result += storage_type + " %uint"; + return result; +} + +std::string GetGlobalVariableString(std::string storage_type, + bool initialized) { + std::string result = "%4 = OpVariable %_ptr_"; + result += storage_type + "_uint "; + result += storage_type; + if (initialized) result += " %9"; + return result; +} + +std::string GetUninitializedGlobalVariableTestString(std::string storage_type) { + return GetGlobalVariableTestString( + GetPointerString(storage_type), + GetGlobalVariableString(storage_type, false)); +} + +std::string GetNullConstantString() { return "%9 = OpConstantNull %uint"; } + +std::string GetInitializedGlobalVariableTestString(std::string storage_type) { + return GetGlobalVariableTestString( + GetPointerString(storage_type), + GetGlobalVariableString(storage_type, true), GetNullConstantString()); +} + +TEST_P(GlobalVariableTest, Check) { + std::string storage_class = std::get<0>(GetParam()); + bool changed = std::get<1>(GetParam()); + std::string input = GetUninitializedGlobalVariableTestString(storage_class); + std::string expected = + changed ? GetInitializedGlobalVariableTestString(storage_class) : input; + + SinglePassRunAndCheck(input, expected, + /* skip_nop = */ false); +} + +// clang-format off +INSTANTIATE_TEST_SUITE_P( + GenerateWebGPUInitializers, GlobalVariableTest, + ::testing::ValuesIn(std::vector({ + std::make_tuple("Private", true), + std::make_tuple("Output", true), + std::make_tuple("Function", true), + std::make_tuple("UniformConstant", false), + std::make_tuple("Input", false), + std::make_tuple("Uniform", false), + std::make_tuple("Workgroup", false) + }))); +// clang-format on + +std::string GetLocalVariableTestString(std::string ptr_str, std::string var_str, + std::string const_str = "") { + std::vector result = { + // clang-format off + "OpCapability Shader", + "OpCapability VulkanMemoryModel", + "OpExtension \"SPV_KHR_vulkan_memory_model\"", + "OpMemoryModel Logical Vulkan", + "OpEntryPoint Vertex %1 \"shader\"", + "%uint = OpTypeInt 32 0", + ptr_str.c_str(), + "%uint_0 = OpConstant %uint 0", + "%void = OpTypeVoid", + "%6 = OpTypeFunction %void"}; + // clang-format on + + if (!const_str.empty()) result += const_str.c_str(); + + result += { + // clang-format off + "%1 = OpFunction %void None %6", + "%7 = OpLabel", + var_str.c_str(), + "OpStore %8 %uint_0" + // clang-format on + }; + return JoinAllInsts(result); +} + +std::string GetLocalVariableString(std::string storage_type, bool initialized) { + std::string result = "%8 = OpVariable %_ptr_"; + result += storage_type + "_uint "; + result += storage_type; + if (initialized) result += " %9"; + return result; +} + +std::string GetUninitializedLocalVariableTestString(std::string storage_type) { + return GetLocalVariableTestString( + GetPointerString(storage_type), + GetLocalVariableString(storage_type, false)); +} + +std::string GetInitializedLocalVariableTestString(std::string storage_type) { + return GetLocalVariableTestString(GetPointerString(storage_type), + GetLocalVariableString(storage_type, true), + GetNullConstantString()); +} + +TEST_P(LocalVariableTest, Check) { + std::string storage_class = std::get<0>(GetParam()); + bool changed = std::get<1>(GetParam()); + + std::string input = GetUninitializedLocalVariableTestString(storage_class); + std::string expected = + changed ? GetInitializedLocalVariableTestString(storage_class) : input; + + SinglePassRunAndCheck(input, expected, + /* skip_nop = */ false); +} + +// clang-format off +INSTANTIATE_TEST_SUITE_P( + GenerateWebGPUInitializers, LocalVariableTest, + ::testing::ValuesIn(std::vector({ + std::make_tuple("Private", true), + std::make_tuple("Output", true), + std::make_tuple("Function", true), + std::make_tuple("UniformConstant", false), + std::make_tuple("Input", false), + std::make_tuple("Uniform", false), + std::make_tuple("Workgroup", false) + }))); +// clang-format on + +TEST_F(GenerateWebGPUInitializersTest, AlreadyInitializedUnchanged) { + std::vector spirv = { + // clang-format off + "OpCapability Shader", + "OpCapability VulkanMemoryModel", + "OpExtension \"SPV_KHR_vulkan_memory_model\"", + "OpMemoryModel Logical Vulkan", + "OpEntryPoint Vertex %1 \"shader\"", + "%uint = OpTypeInt 32 0", + "%_ptr_Private_uint = OpTypePointer Private %uint", + "%uint_0 = OpConstant %uint 0", + "%5 = OpVariable %_ptr_Private_uint Private %uint_0", + "%void = OpTypeVoid", + "%7 = OpTypeFunction %void", + "%1 = OpFunction %void None %7", + "%8 = OpLabel", + "OpReturn", + "OpFunctionEnd" + // clang-format on + }; + std::string str = JoinAllInsts(spirv); + + SinglePassRunAndCheck(str, str, + /* skip_nop = */ false); +} + +TEST_F(GenerateWebGPUInitializersTest, AmbigiousArrays) { + std::vector input_spirv = { + // clang-format off + "OpCapability Shader", + "OpCapability VulkanMemoryModel", + "OpExtension \"SPV_KHR_vulkan_memory_model\"", + "OpMemoryModel Logical Vulkan", + "OpEntryPoint Vertex %1 \"shader\"", + "%uint = OpTypeInt 32 0", + "%uint_2 = OpConstant %uint 2", + "%_arr_uint_uint_2 = OpTypeArray %uint %uint_2", + "%_arr_uint_uint_2_0 = OpTypeArray %uint %uint_2", + "%_ptr_Private__arr_uint_uint_2 = OpTypePointer Private %_arr_uint_uint_2", +"%_ptr_Private__arr_uint_uint_2_0 = OpTypePointer Private %_arr_uint_uint_2_0", + "%8 = OpConstantNull %_arr_uint_uint_2_0", + "%9 = OpVariable %_ptr_Private__arr_uint_uint_2 Private", + "%10 = OpVariable %_ptr_Private__arr_uint_uint_2_0 Private %8", + "%void = OpTypeVoid", + "%12 = OpTypeFunction %void", + "%1 = OpFunction %void None %12", + "%13 = OpLabel", + "OpReturn", + "OpFunctionEnd" + // clang-format on + }; + std::string input_str = JoinAllInsts(input_spirv); + + std::vector expected_spirv = { + // clang-format off + "OpCapability Shader", + "OpCapability VulkanMemoryModel", + "OpExtension \"SPV_KHR_vulkan_memory_model\"", + "OpMemoryModel Logical Vulkan", + "OpEntryPoint Vertex %1 \"shader\"", + "%uint = OpTypeInt 32 0", + "%uint_2 = OpConstant %uint 2", + "%_arr_uint_uint_2 = OpTypeArray %uint %uint_2", + "%_arr_uint_uint_2_0 = OpTypeArray %uint %uint_2", + "%_ptr_Private__arr_uint_uint_2 = OpTypePointer Private %_arr_uint_uint_2", +"%_ptr_Private__arr_uint_uint_2_0 = OpTypePointer Private %_arr_uint_uint_2_0", + "%8 = OpConstantNull %_arr_uint_uint_2_0", + "%14 = OpConstantNull %_arr_uint_uint_2", + "%9 = OpVariable %_ptr_Private__arr_uint_uint_2 Private %14", + "%10 = OpVariable %_ptr_Private__arr_uint_uint_2_0 Private %8", + "%void = OpTypeVoid", + "%12 = OpTypeFunction %void", + "%1 = OpFunction %void None %12", + "%13 = OpLabel", + "OpReturn", + "OpFunctionEnd" + // clang-format on + }; + std::string expected_str = JoinAllInsts(expected_spirv); + + SinglePassRunAndCheck(input_str, expected_str, + /* skip_nop = */ false); +} + +TEST_F(GenerateWebGPUInitializersTest, AmbigiousStructs) { + std::vector input_spirv = { + // clang-format off + "OpCapability Shader", + "OpCapability VulkanMemoryModel", + "OpExtension \"SPV_KHR_vulkan_memory_model\"", + "OpMemoryModel Logical Vulkan", + "OpEntryPoint Vertex %1 \"shader\"", + "%uint = OpTypeInt 32 0", + "%_struct_3 = OpTypeStruct %uint", + "%_struct_4 = OpTypeStruct %uint", +"%_ptr_Private__struct_3 = OpTypePointer Private %_struct_3", +"%_ptr_Private__struct_4 = OpTypePointer Private %_struct_4", + "%7 = OpConstantNull %_struct_3", + "%8 = OpVariable %_ptr_Private__struct_3 Private %7", + "%9 = OpVariable %_ptr_Private__struct_4 Private", + "%void = OpTypeVoid", + "%11 = OpTypeFunction %void", + "%1 = OpFunction %void None %11", + "%12 = OpLabel", + "OpReturn", + "OpFunctionEnd" + // clang-format on + }; + std::string input_str = JoinAllInsts(input_spirv); + + std::vector expected_spirv = { + // clang-format off + "OpCapability Shader", + "OpCapability VulkanMemoryModel", + "OpExtension \"SPV_KHR_vulkan_memory_model\"", + "OpMemoryModel Logical Vulkan", + "OpEntryPoint Vertex %1 \"shader\"", + "%uint = OpTypeInt 32 0", + "%_struct_3 = OpTypeStruct %uint", + "%_struct_4 = OpTypeStruct %uint", +"%_ptr_Private__struct_3 = OpTypePointer Private %_struct_3", +"%_ptr_Private__struct_4 = OpTypePointer Private %_struct_4", + "%7 = OpConstantNull %_struct_3", + "%8 = OpVariable %_ptr_Private__struct_3 Private %7", + "%13 = OpConstantNull %_struct_4", + "%9 = OpVariable %_ptr_Private__struct_4 Private %13", + "%void = OpTypeVoid", + "%11 = OpTypeFunction %void", + "%1 = OpFunction %void None %11", + "%12 = OpLabel", + "OpReturn", + "OpFunctionEnd" + // clang-format on + }; + std::string expected_str = JoinAllInsts(expected_spirv); + + SinglePassRunAndCheck(input_str, expected_str, + /* skip_nop = */ false); +} + +} // namespace +} // namespace opt +} // namespace spvtools diff --git a/third_party/spirv-tools/test/opt/graphics_robust_access_test.cpp b/third_party/spirv-tools/test/opt/graphics_robust_access_test.cpp new file mode 100644 index 0000000000..d38571e79f --- /dev/null +++ b/third_party/spirv-tools/test/opt/graphics_robust_access_test.cpp @@ -0,0 +1,1401 @@ +// Copyright (c) 2019 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 +#include +#include +#include + +#include "gmock/gmock.h" +#include "pass_fixture.h" +#include "pass_utils.h" +#include "source/opt/graphics_robust_access_pass.h" + +namespace { + +using namespace spvtools; + +using opt::GraphicsRobustAccessPass; +using GraphicsRobustAccessTest = opt::PassTest<::testing::Test>; + +// Test incompatible module, determined at module-level. + +TEST_F(GraphicsRobustAccessTest, FailNotShader) { + const std::string text = R"( +; CHECK: Can only process Shader modules +OpCapability Kernel +)"; + + SinglePassRunAndFail(text); +} + +TEST_F(GraphicsRobustAccessTest, FailCantProcessVariablePointers) { + const std::string text = R"( +; CHECK: Can't process modules with VariablePointers capability +OpCapability VariablePointers +)"; + + SinglePassRunAndFail(text); +} + +TEST_F(GraphicsRobustAccessTest, FailCantProcessVariablePointersStorageBuffer) { + const std::string text = R"( +; CHECK: Can't process modules with VariablePointersStorageBuffer capability +OpCapability VariablePointersStorageBuffer +)"; + + SinglePassRunAndFail(text); +} + +TEST_F(GraphicsRobustAccessTest, FailCantProcessRuntimeDescriptorArrayEXT) { + const std::string text = R"( +; CHECK: Can't process modules with RuntimeDescriptorArrayEXT capability +OpCapability RuntimeDescriptorArrayEXT +)"; + + SinglePassRunAndFail(text); +} + +TEST_F(GraphicsRobustAccessTest, FailCantProcessPhysical32AddressingModel) { + const std::string text = R"( +; CHECK: Addressing model must be Logical. Found OpMemoryModel Physical32 OpenCL +OpCapability Shader +OpMemoryModel Physical32 OpenCL +)"; + + SinglePassRunAndFail(text); +} + +TEST_F(GraphicsRobustAccessTest, FailCantProcessPhysical64AddressingModel) { + const std::string text = R"( +; CHECK: Addressing model must be Logical. Found OpMemoryModel Physical64 OpenCL +OpCapability Shader +OpMemoryModel Physical64 OpenCL +)"; + + SinglePassRunAndFail(text); +} + +TEST_F(GraphicsRobustAccessTest, + FailCantProcessPhysicalStorageBuffer64EXTAddressingModel) { + const std::string text = R"( +; CHECK: Addressing model must be Logical. Found OpMemoryModel PhysicalStorageBuffer64 GLSL450 +OpCapability Shader +OpMemoryModel PhysicalStorageBuffer64EXT GLSL450 +)"; + + SinglePassRunAndFail(text); +} + +// Test access chains + +// Returns the names of access chain instructions handled by the pass. +// For the purposes of this pass, regular and in-bounds access chains are the +// same.) +std::vector AccessChains() { + return {"OpAccessChain", "OpInBoundsAccessChain"}; +} + +std::string ShaderPreamble() { + return R"( + OpCapability Shader + OpMemoryModel Logical Simple + OpEntryPoint GLCompute %main "main" +)"; +} + +std::string ShaderPreamble(const std::vector& names) { + std::ostringstream os; + os << ShaderPreamble(); + for (auto& name : names) { + os << " OpName %" << name << " \"" << name << "\"\n"; + } + return os.str(); +} + +std::string ShaderPreambleAC() { + return ShaderPreamble({"ac", "ptr_ty", "var"}); +} + +std::string ShaderPreambleAC(const std::vector& names) { + auto names2 = names; + names2.push_back("ac"); + names2.push_back("ptr_ty"); + names2.push_back("var"); + return ShaderPreamble(names2); +} + +std::string DecoSSBO() { + return R"( + OpDecorate %ssbo_s BufferBlock + OpMemberDecorate %ssbo_s 0 Offset 0 + OpMemberDecorate %ssbo_s 1 Offset 4 + OpMemberDecorate %ssbo_s 2 Offset 16 + OpDecorate %var DescriptorSet 0 + OpDecorate %var Binding 0 +)"; +} + +std::string TypesVoid() { + return R"( + %void = OpTypeVoid + %void_fn = OpTypeFunction %void +)"; +} + +std::string TypesInt() { + return R"( + %uint = OpTypeInt 32 0 + %int = OpTypeInt 32 1 +)"; +} + +std::string TypesFloat() { + return R"( + %float = OpTypeFloat 32 +)"; +} + +std::string TypesShort() { + return R"( + %ushort = OpTypeInt 16 0 + %short = OpTypeInt 16 1 +)"; +} + +std::string TypesLong() { + return R"( + %ulong = OpTypeInt 64 0 + %long = OpTypeInt 64 1 +)"; +} + +std::string MainPrefix() { + return R"( + %main = OpFunction %void None %void_fn + %entry = OpLabel +)"; +} + +std::string MainSuffix() { + return R"( + OpReturn + OpFunctionEnd +)"; +} + +std::string ACCheck(const std::string& access_chain_inst, + const std::string& original, + const std::string& transformed) { + return "\n ; CHECK: %ac = " + access_chain_inst + " %ptr_ty %var" + + (transformed.empty() ? "" : " ") + transformed + + "\n ; CHECK-NOT: " + access_chain_inst + + "\n ; CHECK-NEXT: OpReturn" + "\n %ac = " + + access_chain_inst + " %ptr_ty %var " + (original.empty() ? "" : " ") + + original + "\n"; +} + +std::string ACCheckFail(const std::string& access_chain_inst, + const std::string& original, + const std::string& transformed) { + return "\n ; CHECK: %ac = " + access_chain_inst + " %ptr_ty %var" + + (transformed.empty() ? "" : " ") + transformed + + "\n ; CHECK-NOT: " + access_chain_inst + + "\n ; CHECK-NOT: OpReturn" + "\n %ac = " + + access_chain_inst + " %ptr_ty %var " + (original.empty() ? "" : " ") + + original + "\n"; +} + +// Access chain into: +// Vector +// Vector sizes 2, 3, 4 +// Matrix +// Matrix columns 2, 4 +// Component is vector 2, 4 +// Array +// Struct +// TODO(dneto): RuntimeArray + +TEST_F(GraphicsRobustAccessTest, ACVectorLeastInboundConstantUntouched) { + for (auto* ac : AccessChains()) { + std::ostringstream shaders; + shaders << ShaderPreambleAC() << TypesVoid() << TypesInt() << R"( + %uvec2 = OpTypeVector %uint 2 + %var_ty = OpTypePointer Function %uvec2 + %ptr_ty = OpTypePointer Function %uint + %uint_0 = OpConstant %uint 0 + )" + << MainPrefix() << R"( + %var = OpVariable %var_ty Function)" << ACCheck(ac, "%uint_0", "%uint_0") + << MainSuffix(); + SinglePassRunAndMatch(shaders.str(), true); + } +} + +TEST_F(GraphicsRobustAccessTest, ACVectorMostInboundConstantUntouched) { + for (auto* ac : AccessChains()) { + std::ostringstream shaders; + shaders << ShaderPreambleAC() << TypesVoid() << TypesInt() << R"( + %v4uint = OpTypeVector %uint 4 + %var_ty = OpTypePointer Function %v4uint + %ptr_ty = OpTypePointer Function %uint + %uint_3 = OpConstant %uint 3 + )" + << MainPrefix() << R"( + %var = OpVariable %var_ty Function)" << ACCheck(ac, "%uint_3", "%uint_3") + << MainSuffix(); + SinglePassRunAndMatch(shaders.str(), true); + } +} + +TEST_F(GraphicsRobustAccessTest, ACVectorExcessConstantClamped) { + for (auto* ac : AccessChains()) { + std::ostringstream shaders; + shaders << ShaderPreambleAC() << TypesVoid() << TypesInt() << R"( + %v4uint = OpTypeVector %uint 4 + %var_ty = OpTypePointer Function %v4uint + %ptr_ty = OpTypePointer Function %uint + %uint_4 = OpConstant %uint 4 + )" + << MainPrefix() << R"( + %var = OpVariable %var_ty Function)" << ACCheck(ac, "%uint_4", "%int_3") + << MainSuffix(); + SinglePassRunAndMatch(shaders.str(), true); + } +} + +TEST_F(GraphicsRobustAccessTest, ACVectorNegativeConstantClamped) { + for (auto* ac : AccessChains()) { + std::ostringstream shaders; + shaders << ShaderPreambleAC() << TypesVoid() << TypesInt() << R"( + %v4uint = OpTypeVector %uint 4 + %var_ty = OpTypePointer Function %v4uint + %ptr_ty = OpTypePointer Function %uint + %int_n1 = OpConstant %int -1 + )" + << MainPrefix() << R"( + ; CHECK: %int_0 = OpConstant %int 0 + %var = OpVariable %var_ty Function)" << ACCheck(ac, "%int_n1", "%int_0") + << MainSuffix(); + SinglePassRunAndMatch(shaders.str(), true); + } +} + +// Like the previous test, but ensures the pass knows how to modify an index +// which does not come first in the access chain. +TEST_F(GraphicsRobustAccessTest, ACVectorInArrayNegativeConstantClamped) { + for (auto* ac : AccessChains()) { + std::ostringstream shaders; + shaders << ShaderPreambleAC() << TypesVoid() << TypesInt() << R"( + %v4uint = OpTypeVector %uint 4 + %uint_1 = OpConstant %uint 1 + %uint_2 = OpConstant %uint 2 + %arr = OpTypeArray %v4uint %uint_2 + %var_ty = OpTypePointer Function %arr + %ptr_ty = OpTypePointer Function %uint + %int_n1 = OpConstant %int -1 + )" + << MainPrefix() << R"( + ; CHECK: %int_0 = OpConstant %int 0 + %var = OpVariable %var_ty Function)" + << ACCheck(ac, "%uint_1 %int_n1", "%uint_1 %int_0") << MainSuffix(); + SinglePassRunAndMatch(shaders.str(), true); + } +} + +TEST_F(GraphicsRobustAccessTest, ACVectorGeneralClamped) { + for (auto* ac : AccessChains()) { + std::ostringstream shaders; + shaders << ShaderPreambleAC({"i"}) << TypesVoid() << TypesInt() << R"( + %v4uint = OpTypeVector %uint 4 + %var_ty = OpTypePointer Function %v4uint + %ptr_ty = OpTypePointer Function %uint + %i = OpUndef %int)" + << MainPrefix() << R"( + ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450" + ; CHECK-DAG: %int_0 = OpConstant %int 0 + ; CHECK-DAG: %int_3 = OpConstant %int 3 + ; CHECK: OpLabel + ; CHECK: %[[clamp:\w+]] = OpExtInst %int %[[GLSLSTD450]] SClamp %i %int_0 %int_3 + %var = OpVariable %var_ty Function)" << ACCheck(ac, "%i", "%[[clamp]]") + << MainSuffix(); + SinglePassRunAndMatch(shaders.str(), true); + } +} + +TEST_F(GraphicsRobustAccessTest, ACVectorGeneralShortClamped) { + // Show that signed 16 bit integers are clamped as well. + for (auto* ac : AccessChains()) { + std::ostringstream shaders; + shaders << "OpCapability Int16\n" + << ShaderPreambleAC({"i"}) << TypesVoid() << TypesShort() << + R"( + %v4short = OpTypeVector %short 4 + %var_ty = OpTypePointer Function %v4short + %ptr_ty = OpTypePointer Function %short + %i = OpUndef %short)" + << MainPrefix() << R"( + ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450" + ; CHECK-NOT: = OpTypeInt 32 + ; CHECK-DAG: %short_0 = OpConstant %short 0 + ; CHECK-DAG: %short_3 = OpConstant %short 3 + ; CHECK-NOT: = OpTypeInt 32 + ; CHECK: OpLabel + ; CHECK: %[[clamp:\w+]] = OpExtInst %short %[[GLSLSTD450]] SClamp %i %short_0 %short_3 + %var = OpVariable %var_ty Function)" << ACCheck(ac, "%i", "%[[clamp]]") + << MainSuffix(); + SinglePassRunAndMatch(shaders.str(), true); + } +} + +TEST_F(GraphicsRobustAccessTest, ACVectorGeneralUShortClamped) { + // Show that unsigned 16 bit integers are clamped as well. + for (auto* ac : AccessChains()) { + std::ostringstream shaders; + shaders << "OpCapability Int16\n" + << ShaderPreambleAC({"i"}) << TypesVoid() << TypesShort() << + R"( + %v4ushort = OpTypeVector %ushort 4 + %var_ty = OpTypePointer Function %v4ushort + %ptr_ty = OpTypePointer Function %ushort + %i = OpUndef %ushort)" + << MainPrefix() << R"( + ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450" + ; CHECK-NOT: = OpTypeInt 32 + ; CHECK-DAG: %short_0 = OpConstant %short 0 + ; CHECK-DAG: %short_3 = OpConstant %short 3 + ; CHECK-NOT: = OpTypeInt 32 + ; CHECK: OpLabel + ; CHECK: %[[clamp:\w+]] = OpExtInst %ushort %[[GLSLSTD450]] SClamp %i %short_0 %short_3 + %var = OpVariable %var_ty Function)" << ACCheck(ac, "%i", "%[[clamp]]") + << MainSuffix(); + SinglePassRunAndMatch(shaders.str(), true); + } +} + +TEST_F(GraphicsRobustAccessTest, ACVectorGeneralLongClamped) { + // Show that signed 64 bit integers are clamped as well. + for (auto* ac : AccessChains()) { + std::ostringstream shaders; + shaders << "OpCapability Int64\n" + << ShaderPreambleAC({"i"}) << TypesVoid() << TypesLong() << + R"( + %v4long = OpTypeVector %long 4 + %var_ty = OpTypePointer Function %v4long + %ptr_ty = OpTypePointer Function %long + %i = OpUndef %long)" + << MainPrefix() << R"( + ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450" + ; CHECK-NOT: = OpTypeInt 32 + ; CHECK-DAG: %long_0 = OpConstant %long 0 + ; CHECK-DAG: %long_3 = OpConstant %long 3 + ; CHECK-NOT: = OpTypeInt 32 + ; CHECK: OpLabel + ; CHECK: %[[clamp:\w+]] = OpExtInst %long %[[GLSLSTD450]] SClamp %i %long_0 %long_3 + %var = OpVariable %var_ty Function)" << ACCheck(ac, "%i", "%[[clamp]]") + << MainSuffix(); + SinglePassRunAndMatch(shaders.str(), true); + } +} + +TEST_F(GraphicsRobustAccessTest, ACVectorGeneralULongClamped) { + // Show that unsigned 64 bit integers are clamped as well. + for (auto* ac : AccessChains()) { + std::ostringstream shaders; + shaders << "OpCapability Int64\n" + << ShaderPreambleAC({"i"}) << TypesVoid() << TypesLong() << + R"( + %v4ulong = OpTypeVector %ulong 4 + %var_ty = OpTypePointer Function %v4ulong + %ptr_ty = OpTypePointer Function %ulong + %i = OpUndef %ulong)" + << MainPrefix() << R"( + ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450" + ; CHECK-NOT: = OpTypeInt 32 + ; CHECK-DAG: %long_0 = OpConstant %long 0 + ; CHECK-DAG: %long_3 = OpConstant %long 3 + ; CHECK-NOT: = OpTypeInt 32 + ; CHECK: OpLabel + ; CHECK: %[[clamp:\w+]] = OpExtInst %ulong %[[GLSLSTD450]] SClamp %i %long_0 %long_3 + %var = OpVariable %var_ty Function)" << ACCheck(ac, "%i", "%[[clamp]]") + << MainSuffix(); + SinglePassRunAndMatch(shaders.str(), true); + } +} + +TEST_F(GraphicsRobustAccessTest, ACMatrixLeastInboundConstantUntouched) { + for (auto* ac : AccessChains()) { + std::ostringstream shaders; + shaders << ShaderPreambleAC() << TypesVoid() << TypesInt() + << TypesFloat() << R"( + %v2float = OpTypeVector %float 2 + %mat4v2float = OpTypeMatrix %v2float 4 + %var_ty = OpTypePointer Function %mat4v2float + %ptr_ty = OpTypePointer Function %float + %uint_0 = OpConstant %uint 0 + %uint_1 = OpConstant %uint 1 + )" << MainPrefix() << R"( + %var = OpVariable %var_ty Function)" + << ACCheck(ac, "%uint_0 %uint_1", "%uint_0 %uint_1") + << MainSuffix(); + SinglePassRunAndMatch(shaders.str(), true); + } +} + +TEST_F(GraphicsRobustAccessTest, ACMatrixMostInboundConstantUntouched) { + for (auto* ac : AccessChains()) { + std::ostringstream shaders; + shaders << ShaderPreambleAC() << TypesVoid() << TypesInt() + << TypesFloat() << R"( + %v2float = OpTypeVector %float 2 + %mat4v2float = OpTypeMatrix %v2float 4 + %var_ty = OpTypePointer Function %mat4v2float + %ptr_ty = OpTypePointer Function %float + %uint_1 = OpConstant %uint 1 + %uint_3 = OpConstant %uint 3 + )" << MainPrefix() << R"( + %var = OpVariable %var_ty Function)" + << ACCheck(ac, "%uint_3 %uint_1", "%uint_3 %uint_1") + << MainSuffix(); + SinglePassRunAndMatch(shaders.str(), true); + } +} + +TEST_F(GraphicsRobustAccessTest, ACMatrixExcessConstantClamped) { + for (auto* ac : AccessChains()) { + std::ostringstream shaders; + shaders << ShaderPreambleAC() << TypesVoid() << TypesInt() + << TypesFloat() << R"( + %v2float = OpTypeVector %float 2 + %mat4v2float = OpTypeMatrix %v2float 4 + %var_ty = OpTypePointer Function %mat4v2float + %ptr_ty = OpTypePointer Function %float + %uint_1 = OpConstant %uint 1 + %uint_4 = OpConstant %uint 4 + )" << MainPrefix() << R"( + ; CHECK: %int_3 = OpConstant %int 3 + %var = OpVariable %var_ty Function)" + << ACCheck(ac, "%uint_4 %uint_1", "%int_3 %uint_1") << MainSuffix(); + SinglePassRunAndMatch(shaders.str(), true); + } +} + +TEST_F(GraphicsRobustAccessTest, ACMatrixNegativeConstantClamped) { + for (auto* ac : AccessChains()) { + std::ostringstream shaders; + shaders << ShaderPreambleAC() << TypesVoid() << TypesInt() + << TypesFloat() << R"( + %v2float = OpTypeVector %float 2 + %mat4v2float = OpTypeMatrix %v2float 4 + %var_ty = OpTypePointer Function %mat4v2float + %ptr_ty = OpTypePointer Function %float + %uint_1 = OpConstant %uint 1 + %int_n1 = OpConstant %int -1 + )" << MainPrefix() << R"( + ; CHECK: %int_0 = OpConstant %int 0 + %var = OpVariable %var_ty Function)" + << ACCheck(ac, "%int_n1 %uint_1", "%int_0 %uint_1") << MainSuffix(); + SinglePassRunAndMatch(shaders.str(), true); + } +} + +TEST_F(GraphicsRobustAccessTest, ACMatrixGeneralClamped) { + for (auto* ac : AccessChains()) { + std::ostringstream shaders; + shaders << ShaderPreambleAC({"i"}) << TypesVoid() << TypesInt() + << TypesFloat() << R"( + %v2float = OpTypeVector %float 2 + %mat4v2float = OpTypeMatrix %v2float 4 + %var_ty = OpTypePointer Function %mat4v2float + %ptr_ty = OpTypePointer Function %float + %uint_1 = OpConstant %uint 1 + %i = OpUndef %int + )" << MainPrefix() << R"( + ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450" + ; CHECK-DAG: %int_0 = OpConstant %int 0 + ; CHECK-DAG: %int_3 = OpConstant %int 3 + ; CHECK: OpLabel + ; CHECK: %[[clamp:\w+]] = OpExtInst %int %[[GLSLSTD450]] SClamp %i %int_0 %int_3 + %var = OpVariable %var_ty Function)" + << ACCheck(ac, "%i %uint_1", "%[[clamp]] %uint_1") << MainSuffix(); + SinglePassRunAndMatch(shaders.str(), true); + } +} + +TEST_F(GraphicsRobustAccessTest, ACArrayLeastInboundConstantUntouched) { + for (auto* ac : AccessChains()) { + std::ostringstream shaders; + shaders << ShaderPreambleAC() << TypesVoid() << TypesInt() + << TypesFloat() << R"( + %uint_200 = OpConstant %uint 200 + %arr = OpTypeArray %float %uint_200 + %var_ty = OpTypePointer Function %arr + %ptr_ty = OpTypePointer Function %float + %int_0 = OpConstant %int 0 + )" << MainPrefix() << R"( + %var = OpVariable %var_ty Function)" + << ACCheck(ac, "%int_0", "%int_0") << MainSuffix(); + SinglePassRunAndMatch(shaders.str(), true); + } +} + +TEST_F(GraphicsRobustAccessTest, ACArrayMostInboundConstantUntouched) { + for (auto* ac : AccessChains()) { + std::ostringstream shaders; + shaders << ShaderPreambleAC() << TypesVoid() << TypesInt() + << TypesFloat() << R"( + %uint_200 = OpConstant %uint 200 + %arr = OpTypeArray %float %uint_200 + %var_ty = OpTypePointer Function %arr + %ptr_ty = OpTypePointer Function %float + %int_199 = OpConstant %int 199 + )" << MainPrefix() << R"( + %var = OpVariable %var_ty Function)" + << ACCheck(ac, "%int_199", "%int_199") << MainSuffix(); + SinglePassRunAndMatch(shaders.str(), true); + } +} + +TEST_F(GraphicsRobustAccessTest, ACArrayGeneralClamped) { + for (auto* ac : AccessChains()) { + std::ostringstream shaders; + shaders << ShaderPreambleAC({"i"}) << TypesVoid() << TypesInt() + << TypesFloat() << R"( + %uint_200 = OpConstant %uint 200 + %arr = OpTypeArray %float %uint_200 + %var_ty = OpTypePointer Function %arr + %ptr_ty = OpTypePointer Function %float + %i = OpUndef %int + )" << MainPrefix() << R"( + ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450" + ; CHECK-DAG: %int_0 = OpConstant %int 0 + ; CHECK-DAG: %int_199 = OpConstant %int 199 + ; CHECK: OpLabel + ; CHECK: %[[clamp:\w+]] = OpExtInst %int %[[GLSLSTD450]] SClamp %i %int_0 %int_199 + %var = OpVariable %var_ty Function)" + << ACCheck(ac, "%i", "%[[clamp]]") << MainSuffix(); + SinglePassRunAndMatch(shaders.str(), true); + } +} + +TEST_F(GraphicsRobustAccessTest, ACArrayGeneralShortIndexUIntBoundsClamped) { + // Index is signed short, array bounds overflows the index type. + for (auto* ac : AccessChains()) { + std::ostringstream shaders; + shaders << "OpCapability Int16\n" + << ShaderPreambleAC({"i"}) << TypesVoid() << TypesInt() + << TypesShort() << TypesFloat() << R"( + %uint_70000 = OpConstant %uint 70000 ; overflows 16bits + %arr = OpTypeArray %float %uint_70000 + %var_ty = OpTypePointer Function %arr + %ptr_ty = OpTypePointer Function %float + %i = OpUndef %short + )" << MainPrefix() << R"( + ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450" + ; CHECK-DAG: %int_0 = OpConstant %int 0 + ; CHECK-DAG: %int_69999 = OpConstant %int 69999 + ; CHECK: OpLabel + ; CHECK: %[[i_ext:\w+]] = OpSConvert %uint %i + ; CHECK: %[[clamp:\w+]] = OpExtInst %uint %[[GLSLSTD450]] SClamp %[[i_ext]] %int_0 %int_69999 + %var = OpVariable %var_ty Function)" + << ACCheck(ac, "%i", "%[[clamp]]") << MainSuffix(); + SinglePassRunAndMatch(shaders.str(), true); + } +} + +TEST_F(GraphicsRobustAccessTest, ACArrayGeneralUShortIndexIntBoundsClamped) { + // Index is unsigned short, array bounds overflows the index type. + for (auto* ac : AccessChains()) { + std::ostringstream shaders; + shaders << "OpCapability Int16\n" + << ShaderPreambleAC({"i"}) << TypesVoid() << TypesInt() + << TypesShort() << TypesFloat() << R"( + %int_70000 = OpConstant %int 70000 ; overflows 16bits + %arr = OpTypeArray %float %int_70000 + %var_ty = OpTypePointer Function %arr + %ptr_ty = OpTypePointer Function %float + %i = OpUndef %ushort + )" << MainPrefix() << R"( + ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450" + ; CHECK-DAG: %int_0 = OpConstant %int 0 + ; CHECK-DAG: %int_69999 = OpConstant %int 69999 + ; CHECK: OpLabel + ; CHECK: %[[i_ext:\w+]] = OpUConvert %uint %i + ; CHECK: %[[clamp:\w+]] = OpExtInst %uint %[[GLSLSTD450]] SClamp %[[i_ext]] %int_0 %int_69999 + %var = OpVariable %var_ty Function)" + << ACCheck(ac, "%i", "%[[clamp]]") << MainSuffix(); + SinglePassRunAndMatch(shaders.str(), true); + } +} + +TEST_F(GraphicsRobustAccessTest, ACArrayGeneralUIntIndexShortBoundsClamped) { + // Signed int index i is wider than the array bounds type. + for (auto* ac : AccessChains()) { + std::ostringstream shaders; + shaders << "OpCapability Int16\n" + << ShaderPreambleAC({"i"}) << TypesVoid() << TypesInt() + << TypesShort() << TypesFloat() << R"( + %short_200 = OpConstant %short 200 + %arr = OpTypeArray %float %short_200 + %var_ty = OpTypePointer Function %arr + %ptr_ty = OpTypePointer Function %float + %i = OpUndef %uint + )" << MainPrefix() << R"( + ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450" + ; CHECK-DAG: %int_0 = OpConstant %int 0 + ; CHECK-DAG: %int_199 = OpConstant %int 199 + ; CHECK: OpLabel + ; CHECK: %[[clamp:\w+]] = OpExtInst %uint %[[GLSLSTD450]] SClamp %i %int_0 %int_199 + %var = OpVariable %var_ty Function)" + << ACCheck(ac, "%i", "%[[clamp]]") << MainSuffix(); + SinglePassRunAndMatch(shaders.str(), true); + } +} + +TEST_F(GraphicsRobustAccessTest, ACArrayGeneralIntIndexUShortBoundsClamped) { + // Unsigned int index i is wider than the array bounds type. + for (auto* ac : AccessChains()) { + std::ostringstream shaders; + shaders << "OpCapability Int16\n" + << ShaderPreambleAC({"i"}) << TypesVoid() << TypesInt() + << TypesShort() << TypesFloat() << R"( + %ushort_200 = OpConstant %ushort 200 + %arr = OpTypeArray %float %ushort_200 + %var_ty = OpTypePointer Function %arr + %ptr_ty = OpTypePointer Function %float + %i = OpUndef %int + )" << MainPrefix() << R"( + ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450" + ; CHECK-DAG: %int_0 = OpConstant %int 0 + ; CHECK-DAG: %int_199 = OpConstant %int 199 + ; CHECK: OpLabel + ; CHECK: %[[clamp:\w+]] = OpExtInst %int %[[GLSLSTD450]] SClamp %i %int_0 %int_199 + %var = OpVariable %var_ty Function)" + << ACCheck(ac, "%i", "%[[clamp]]") << MainSuffix(); + SinglePassRunAndMatch(shaders.str(), true); + } +} + +TEST_F(GraphicsRobustAccessTest, ACArrayGeneralLongIndexUIntBoundsClamped) { + // Signed long index i is wider than the array bounds type. + for (auto* ac : AccessChains()) { + std::ostringstream shaders; + shaders << "OpCapability Int64\n" + << ShaderPreambleAC({"i"}) << TypesVoid() << TypesInt() + << TypesLong() << TypesFloat() << R"( + %uint_200 = OpConstant %uint 200 + %arr = OpTypeArray %float %uint_200 + %var_ty = OpTypePointer Function %arr + %ptr_ty = OpTypePointer Function %float + %i = OpUndef %long + )" << MainPrefix() << R"( + ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450" + ; CHECK-DAG: %long_0 = OpConstant %long 0 + ; CHECK-DAG: %long_199 = OpConstant %long 199 + ; CHECK: OpLabel + ; CHECK: %[[clamp:\w+]] = OpExtInst %long %[[GLSLSTD450]] SClamp %i %long_0 %long_199 + %var = OpVariable %var_ty Function)" + << ACCheck(ac, "%i", "%[[clamp]]") << MainSuffix(); + SinglePassRunAndMatch(shaders.str(), true); + } +} + +TEST_F(GraphicsRobustAccessTest, ACArrayGeneralULongIndexIntBoundsClamped) { + // Unsigned long index i is wider than the array bounds type. + for (auto* ac : AccessChains()) { + std::ostringstream shaders; + shaders << "OpCapability Int64\n" + << ShaderPreambleAC({"i"}) << TypesVoid() << TypesInt() + << TypesLong() << TypesFloat() << R"( + %int_200 = OpConstant %int 200 + %arr = OpTypeArray %float %int_200 + %var_ty = OpTypePointer Function %arr + %ptr_ty = OpTypePointer Function %float + %i = OpUndef %ulong + )" << MainPrefix() << R"( + ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450" + ; CHECK-DAG: %long_0 = OpConstant %long 0 + ; CHECK-DAG: %long_199 = OpConstant %long 199 + ; CHECK: OpLabel + ; CHECK: %[[clamp:\w+]] = OpExtInst %ulong %[[GLSLSTD450]] SClamp %i %long_0 %long_199 + %var = OpVariable %var_ty Function)" + << ACCheck(ac, "%i", "%[[clamp]]") << MainSuffix(); + SinglePassRunAndMatch(shaders.str(), true); + } +} + +TEST_F(GraphicsRobustAccessTest, + ACArrayGeneralShortIndeArrayBiggerThanShortMaxClipsToShortIntMax) { + for (auto* ac : AccessChains()) { + std::ostringstream shaders; + shaders << "OpCapability Int16\n" + << ShaderPreambleAC({"i"}) << TypesVoid() << TypesShort() + << TypesInt() << TypesFloat() << R"( + %uint_50000 = OpConstant %uint 50000 + %arr = OpTypeArray %float %uint_50000 + %var_ty = OpTypePointer Function %arr + %ptr_ty = OpTypePointer Function %float + %i = OpUndef %ushort + )" << MainPrefix() << R"( + ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450" + ; CHECK-DAG: %short_0 = OpConstant %short 0 + ; CHECK-DAG: %[[intmax:\w+]] = OpConstant %short 32767 + ; CHECK: OpLabel + ; CHECK: %[[clamp:\w+]] = OpExtInst %ushort %[[GLSLSTD450]] SClamp %i %short_0 %[[intmax]] + %var = OpVariable %var_ty Function)" + << ACCheck(ac, "%i", "%[[clamp]]") << MainSuffix(); + SinglePassRunAndMatch(shaders.str(), true); + } +} + +TEST_F(GraphicsRobustAccessTest, + ACArrayGeneralIntIndexArrayBiggerThanIntMaxClipsToSignedIntMax) { + for (auto* ac : AccessChains()) { + std::ostringstream shaders; + shaders << ShaderPreambleAC({"i"}) << TypesVoid() << TypesInt() + << TypesFloat() << R"( + %uint_3000000000 = OpConstant %uint 3000000000 + %arr = OpTypeArray %float %uint_3000000000 + %var_ty = OpTypePointer Function %arr + %ptr_ty = OpTypePointer Function %float + %i = OpUndef %uint + )" << MainPrefix() << R"( + ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450" + ; CHECK-DAG: %int_0 = OpConstant %int 0 + ; CHECK-DAG: %[[intmax:\w+]] = OpConstant %int 2147483647 + ; CHECK: OpLabel + ; CHECK: %[[clamp:\w+]] = OpExtInst %uint %[[GLSLSTD450]] SClamp %i %int_0 %[[intmax]] + %var = OpVariable %var_ty Function)" + << ACCheck(ac, "%i", "%[[clamp]]") << MainSuffix(); + SinglePassRunAndMatch(shaders.str(), true); + } +} + +TEST_F(GraphicsRobustAccessTest, + ACArrayGeneralLongIndexArrayBiggerThanLongMaxClipsToSignedLongMax) { + for (auto* ac : AccessChains()) { + std::ostringstream shaders; + shaders << "OpCapability Int64\n" + << ShaderPreambleAC({"i"}) << TypesVoid() << TypesInt() + << TypesLong() + << TypesFloat() + // 2^63 == 9,223,372,036,854,775,807 + << R"( + %ulong_9223372036854775999 = OpConstant %ulong 9223372036854775999 + %arr = OpTypeArray %float %ulong_9223372036854775999 + %var_ty = OpTypePointer Function %arr + %ptr_ty = OpTypePointer Function %float + %i = OpUndef %ulong + )" + << MainPrefix() << R"( + ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450" + ; CHECK-DAG: %long_0 = OpConstant %long 0 + ; CHECK-DAG: %[[intmax:\w+]] = OpConstant %long 9223372036854775807 + ; CHECK: OpLabel + ; CHECK: %[[clamp:\w+]] = OpExtInst %ulong %[[GLSLSTD450]] SClamp %i %long_0 %[[intmax]] + %var = OpVariable %var_ty Function)" << ACCheck(ac, "%i", "%[[clamp]]") + << MainSuffix(); + SinglePassRunAndMatch(shaders.str(), true); + } +} + +TEST_F(GraphicsRobustAccessTest, ACArraySpecIdSizedAlwaysClamped) { + for (auto* ac : AccessChains()) { + std::ostringstream shaders; + shaders << ShaderPreambleAC({"spec200"}) << R"( + OpDecorate %spec200 SpecId 0 )" << TypesVoid() << TypesInt() + << TypesFloat() << R"( + %spec200 = OpSpecConstant %int 200 + %arr = OpTypeArray %float %spec200 + %var_ty = OpTypePointer Function %arr + %ptr_ty = OpTypePointer Function %float + %uint_5 = OpConstant %uint 5 + )" << MainPrefix() << R"( + ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450" + ; CHECK-DAG: %uint_0 = OpConstant %uint 0 + ; CHECK-DAG: %uint_1 = OpConstant %uint 1 + ; CHECK-DAG: %[[uint_intmax:\w+]] = OpConstant %uint 2147483647 + ; CHECK: OpLabel + ; CHECK: %[[max:\w+]] = OpISub %uint %spec200 %uint_1 + ; CHECK: %[[smin:\w+]] = OpExtInst %uint %[[GLSLSTD450]] UMin %[[max]] %[[uint_intmax]] + ; CHECK: %[[clamp:\w+]] = OpExtInst %uint %[[GLSLSTD450]] SClamp %uint_5 %uint_0 %[[smin]] + %var = OpVariable %var_ty Function)" + << ACCheck(ac, "%uint_5", "%[[clamp]]") << MainSuffix(); + SinglePassRunAndMatch(shaders.str(), true); + } +} + +TEST_F(GraphicsRobustAccessTest, ACStructLeastUntouched) { + for (auto* ac : AccessChains()) { + std::ostringstream shaders; + shaders << ShaderPreambleAC() << TypesVoid() << TypesInt() + << TypesFloat() << R"( + %struct = OpTypeStruct %float %float %float + %var_ty = OpTypePointer Function %struct + %ptr_ty = OpTypePointer Function %float + %int_0 = OpConstant %int 0 + )" << MainPrefix() << R"( + %var = OpVariable %var_ty Function)" + << ACCheck(ac, "%int_0", "%int_0") << MainSuffix(); + SinglePassRunAndMatch(shaders.str(), true); + } +} + +TEST_F(GraphicsRobustAccessTest, ACStructMostUntouched) { + for (auto* ac : AccessChains()) { + std::ostringstream shaders; + shaders << ShaderPreambleAC() << TypesVoid() << TypesInt() + << TypesFloat() << R"( + %struct = OpTypeStruct %float %float %float + %var_ty = OpTypePointer Function %struct + %ptr_ty = OpTypePointer Function %float + %int_2 = OpConstant %int 2 + )" << MainPrefix() << R"( + %var = OpVariable %var_ty Function)" + << ACCheck(ac, "%int_2", "%int_2") << MainSuffix(); + SinglePassRunAndMatch(shaders.str(), true); + } +} + +TEST_F(GraphicsRobustAccessTest, ACStructSpecConstantFail) { + for (auto* ac : AccessChains()) { + std::ostringstream shaders; + shaders << ShaderPreambleAC({"struct", "spec200"}) + << "OpDecorate %spec200 SpecId 0\n" + << + + TypesVoid() << TypesInt() << TypesFloat() << R"( + %spec200 = OpSpecConstant %int 200 + %struct = OpTypeStruct %float %float %float + %var_ty = OpTypePointer Function %struct + %ptr_ty = OpTypePointer Function %float + )" << MainPrefix() << R"( + %var = OpVariable %var_ty Function + ; CHECK: Member index into struct is not a constant integer + ; CHECK-SAME: %spec200 = OpSpecConstant %int 200 + )" + << ACCheckFail(ac, "%spec200", "%spec200") << MainSuffix(); + SinglePassRunAndFail(shaders.str()); + } +} + +TEST_F(GraphicsRobustAccessTest, ACStructFloatConstantFail) { + for (auto* ac : AccessChains()) { + std::ostringstream shaders; + shaders << ShaderPreambleAC({"struct"}) << + + TypesVoid() << TypesInt() << TypesFloat() << R"( + %float_2 = OpConstant %float 2 + %struct = OpTypeStruct %float %float %float + %var_ty = OpTypePointer Function %struct + %ptr_ty = OpTypePointer Function %float + )" << MainPrefix() << R"( + %var = OpVariable %var_ty Function + ; CHECK: Member index into struct is not a constant integer + ; CHECK-SAME: %float_2 = OpConstant %float 2 + )" + << ACCheckFail(ac, "%float_2", "%float_2") << MainSuffix(); + SinglePassRunAndFail(shaders.str()); + } +} + +TEST_F(GraphicsRobustAccessTest, ACStructNonConstantFail) { + for (auto* ac : AccessChains()) { + std::ostringstream shaders; + shaders << ShaderPreambleAC({"struct", "i"}) << + + TypesVoid() << TypesInt() << TypesFloat() << R"( + %float_2 = OpConstant %float 2 + %struct = OpTypeStruct %float %float %float + %var_ty = OpTypePointer Function %struct + %ptr_ty = OpTypePointer Function %float + %i = OpUndef %int + )" << MainPrefix() << R"( + %var = OpVariable %var_ty Function + ; CHECK: Member index into struct is not a constant integer + ; CHECK-SAME: %i = OpUndef %int + )" + << ACCheckFail(ac, "%i", "%i") << MainSuffix(); + SinglePassRunAndFail(shaders.str()); + } +} + +TEST_F(GraphicsRobustAccessTest, ACStructExcessFail) { + for (auto* ac : AccessChains()) { + std::ostringstream shaders; + shaders << ShaderPreambleAC({"struct", "i"}) << TypesVoid() << TypesInt() + << TypesFloat() << R"( + %struct = OpTypeStruct %float %float %float + %var_ty = OpTypePointer Function %struct + %ptr_ty = OpTypePointer Function %float + %i = OpConstant %int 4 + )" << MainPrefix() << R"( + %var = OpVariable %var_ty Function + ; CHECK: Member index 4 is out of bounds for struct type: + ; CHECK-SAME: %struct = OpTypeStruct %float %float %float + )" + << ACCheckFail(ac, "%i", "%i") << MainSuffix(); + SinglePassRunAndFail(shaders.str()); + } +} + +TEST_F(GraphicsRobustAccessTest, ACStructNegativeFail) { + for (auto* ac : AccessChains()) { + std::ostringstream shaders; + shaders << ShaderPreambleAC({"struct", "i"}) << TypesVoid() << TypesInt() + << TypesFloat() << R"( + %struct = OpTypeStruct %float %float %float + %var_ty = OpTypePointer Function %struct + %ptr_ty = OpTypePointer Function %float + %i = OpConstant %int -1 + )" << MainPrefix() << R"( + %var = OpVariable %var_ty Function + ; CHECK: Member index -1 is out of bounds for struct type: + ; CHECK-SAME: %struct = OpTypeStruct %float %float %float + )" + << ACCheckFail(ac, "%i", "%i") << MainSuffix(); + SinglePassRunAndFail(shaders.str()); + } +} + +TEST_F(GraphicsRobustAccessTest, ACRTArrayLeastInboundClamped) { + for (auto* ac : AccessChains()) { + std::ostringstream shaders; + shaders << ShaderPreambleAC() << "OpDecorate %rtarr ArrayStride 4 " + << DecoSSBO() << TypesVoid() << TypesInt() << TypesFloat() << R"( + %rtarr = OpTypeRuntimeArray %float + %ssbo_s = OpTypeStruct %uint %uint %rtarr + %var_ty = OpTypePointer Uniform %ssbo_s + %ptr_ty = OpTypePointer Uniform %float + %var = OpVariable %var_ty Uniform + %int_0 = OpConstant %int 0 + %int_2 = OpConstant %int 2 + ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450" + ; CHECK-DAG: %int_1 = OpConstant %int 1 + ; CHECK-DAG: %[[intmax:\w+]] = OpConstant %int 2147483647 + ; CHECK: OpLabel + ; CHECK: %[[arrlen:\w+]] = OpArrayLength %uint %var 2 + ; CHECK: %[[max:\w+]] = OpISub %int %[[arrlen]] %int_1 + ; CHECK: %[[smin:\w+]] = OpExtInst %int %[[GLSLSTD450]] UMin %[[max]] %[[intmax]] + ; CHECK: %[[clamp:\w+]] = OpExtInst %int %[[GLSLSTD450]] SClamp %int_0 %int_0 %[[smin]] + )" + << MainPrefix() << ACCheck(ac, "%int_2 %int_0", "%int_2 %[[clamp]]") + << MainSuffix(); + SinglePassRunAndMatch(shaders.str(), true); + } +} + +TEST_F(GraphicsRobustAccessTest, ACRTArrayGeneralShortIndexClamped) { + for (auto* ac : AccessChains()) { + std::ostringstream shaders; + shaders << "OpCapability Int16\n" + << ShaderPreambleAC({"i"}) << "OpDecorate %rtarr ArrayStride 4 " + << DecoSSBO() << TypesVoid() << TypesShort() << TypesFloat() << R"( + %rtarr = OpTypeRuntimeArray %float + %ssbo_s = OpTypeStruct %short %short %rtarr + %var_ty = OpTypePointer Uniform %ssbo_s + %ptr_ty = OpTypePointer Uniform %float + %var = OpVariable %var_ty Uniform + %short_2 = OpConstant %short 2 + %i = OpUndef %short + ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450" + ; CHECK: %uint = OpTypeInt 32 0 + ; CHECK-DAG: %uint_1 = OpConstant %uint 1 + ; CHECK-DAG: %uint_0 = OpConstant %uint 0 + ; CHECK-DAG: %[[intmax:\w+]] = OpConstant %uint 2147483647 + ; CHECK: OpLabel + ; CHECK: %[[arrlen:\w+]] = OpArrayLength %uint %var 2 + ; CHECK-DAG: %[[max:\w+]] = OpISub %uint %[[arrlen]] %uint_1 + ; CHECK-DAG: %[[i_ext:\w+]] = OpSConvert %uint %i + ; CHECK: %[[smin:\w+]] = OpExtInst %uint %[[GLSLSTD450]] UMin %[[max]] %[[intmax]] + ; CHECK: %[[clamp:\w+]] = OpExtInst %uint %[[GLSLSTD450]] SClamp %[[i_ext]] %uint_0 %[[smin]] + )" + << MainPrefix() << ACCheck(ac, "%short_2 %i", "%short_2 %[[clamp]]") + << MainSuffix(); + SinglePassRunAndMatch(shaders.str(), true); + } +} + +TEST_F(GraphicsRobustAccessTest, ACRTArrayGeneralUShortIndexClamped) { + for (auto* ac : AccessChains()) { + std::ostringstream shaders; + shaders << "OpCapability Int16\n" + << ShaderPreambleAC({"i"}) << "OpDecorate %rtarr ArrayStride 4 " + << DecoSSBO() << TypesVoid() << TypesShort() << TypesFloat() << R"( + %rtarr = OpTypeRuntimeArray %float + %ssbo_s = OpTypeStruct %short %short %rtarr + %var_ty = OpTypePointer Uniform %ssbo_s + %ptr_ty = OpTypePointer Uniform %float + %var = OpVariable %var_ty Uniform + %short_2 = OpConstant %short 2 + %i = OpUndef %ushort + ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450" + ; CHECK: %uint = OpTypeInt 32 0 + ; CHECK-DAG: %uint_1 = OpConstant %uint 1 + ; CHECK-DAG: %uint_0 = OpConstant %uint 0 + ; CHECK-DAG: %[[intmax:\w+]] = OpConstant %uint 2147483647 + ; CHECK: OpLabel + ; CHECK: %[[arrlen:\w+]] = OpArrayLength %uint %var 2 + ; CHECK-DAG: %[[max:\w+]] = OpISub %uint %[[arrlen]] %uint_1 + ; CHECK-DAG: %[[i_ext:\w+]] = OpSConvert %uint %i + ; CHECK: %[[smin:\w+]] = OpExtInst %uint %[[GLSLSTD450]] UMin %[[max]] %[[intmax]] + ; CHECK: %[[clamp:\w+]] = OpExtInst %uint %[[GLSLSTD450]] SClamp %[[i_ext]] %uint_0 %[[smin]] + )" + << MainPrefix() << ACCheck(ac, "%short_2 %i", "%short_2 %[[clamp]]") + << MainSuffix(); + SinglePassRunAndMatch(shaders.str(), true); + } +} + +TEST_F(GraphicsRobustAccessTest, ACRTArrayGeneralIntIndexClamped) { + for (auto* ac : AccessChains()) { + std::ostringstream shaders; + shaders << ShaderPreambleAC({"i"}) << "OpDecorate %rtarr ArrayStride 4 " + << DecoSSBO() << TypesVoid() << TypesInt() << TypesFloat() << R"( + %rtarr = OpTypeRuntimeArray %float + %ssbo_s = OpTypeStruct %int %int %rtarr + %var_ty = OpTypePointer Uniform %ssbo_s + %ptr_ty = OpTypePointer Uniform %float + %var = OpVariable %var_ty Uniform + %int_2 = OpConstant %int 2 + %i = OpUndef %int + ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450" + ; CHECK-DAG: %int_1 = OpConstant %int 1 + ; CHECK-DAG: %int_0 = OpConstant %int 0 + ; CHECK-DAG: %[[intmax:\w+]] = OpConstant %int 2147483647 + ; CHECK: OpLabel + ; CHECK: %[[arrlen:\w+]] = OpArrayLength %uint %var 2 + ; CHECK: %[[max:\w+]] = OpISub %int %[[arrlen]] %int_1 + ; CHECK: %[[smin:\w+]] = OpExtInst %int %[[GLSLSTD450]] UMin %[[max]] %[[intmax]] + ; CHECK: %[[clamp:\w+]] = OpExtInst %int %[[GLSLSTD450]] SClamp %i %int_0 %[[smin]] + )" + << MainPrefix() << ACCheck(ac, "%int_2 %i", "%int_2 %[[clamp]]") + << MainSuffix(); + SinglePassRunAndMatch(shaders.str(), true); + } +} + +TEST_F(GraphicsRobustAccessTest, ACRTArrayGeneralUIntIndexClamped) { + for (auto* ac : AccessChains()) { + std::ostringstream shaders; + shaders << ShaderPreambleAC({"i"}) << "OpDecorate %rtarr ArrayStride 4 " + << DecoSSBO() << TypesVoid() << TypesInt() << TypesFloat() << R"( + %rtarr = OpTypeRuntimeArray %float + %ssbo_s = OpTypeStruct %int %int %rtarr + %var_ty = OpTypePointer Uniform %ssbo_s + %ptr_ty = OpTypePointer Uniform %float + %var = OpVariable %var_ty Uniform + %int_2 = OpConstant %int 2 + %i = OpUndef %uint + ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450" + ; CHECK-DAG: %uint_1 = OpConstant %uint 1 + ; CHECK-DAG: %uint_0 = OpConstant %uint 0 + ; CHECK-DAG: %[[intmax:\w+]] = OpConstant %uint 2147483647 + ; CHECK: OpLabel + ; CHECK: %[[arrlen:\w+]] = OpArrayLength %uint %var 2 + ; CHECK: %[[max:\w+]] = OpISub %uint %[[arrlen]] %uint_1 + ; CHECK: %[[smin:\w+]] = OpExtInst %uint %[[GLSLSTD450]] UMin %[[max]] %[[intmax]] + ; CHECK: %[[clamp:\w+]] = OpExtInst %uint %[[GLSLSTD450]] SClamp %i %uint_0 %[[smin]] + )" + << MainPrefix() << ACCheck(ac, "%int_2 %i", "%int_2 %[[clamp]]") + << MainSuffix(); + SinglePassRunAndMatch(shaders.str(), true); + } +} + +TEST_F(GraphicsRobustAccessTest, ACRTArrayGeneralLongIndexClamped) { + for (auto* ac : AccessChains()) { + std::ostringstream shaders; + shaders << "OpCapability Int64" << ShaderPreambleAC({"i"}) + << "OpDecorate %rtarr ArrayStride 4 " << DecoSSBO() << TypesVoid() + << TypesInt() << TypesLong() << TypesFloat() << R"( + %rtarr = OpTypeRuntimeArray %float + %ssbo_s = OpTypeStruct %int %int %rtarr + %var_ty = OpTypePointer Uniform %ssbo_s + %ptr_ty = OpTypePointer Uniform %float + %var = OpVariable %var_ty Uniform + %int_2 = OpConstant %int 2 + %i = OpUndef %long + ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450" + ; CHECK-DAG: %long_0 = OpConstant %long 0 + ; CHECK-DAG: %long_1 = OpConstant %long 1 + ; CHECK-DAG: %[[longmax:\w+]] = OpConstant %long 9223372036854775807 + ; CHECK: OpLabel + ; CHECK: %[[arrlen:\w+]] = OpArrayLength %uint %var 2 + ; CHECK: %[[arrlen_ext:\w+]] = OpUConvert %ulong %[[arrlen]] + ; CHECK: %[[max:\w+]] = OpISub %long %[[arrlen_ext]] %long_1 + ; CHECK: %[[smin:\w+]] = OpExtInst %long %[[GLSLSTD450]] UMin %[[max]] %[[longmax]] + ; CHECK: %[[clamp:\w+]] = OpExtInst %long %[[GLSLSTD450]] SClamp %i %long_0 %[[smin]] + )" << MainPrefix() + << ACCheck(ac, "%int_2 %i", "%int_2 %[[clamp]]") << MainSuffix(); + SinglePassRunAndMatch(shaders.str(), true); + } +} + +TEST_F(GraphicsRobustAccessTest, ACRTArrayGeneralULongIndexClamped) { + for (auto* ac : AccessChains()) { + std::ostringstream shaders; + shaders << "OpCapability Int64" << ShaderPreambleAC({"i"}) + << "OpDecorate %rtarr ArrayStride 4 " << DecoSSBO() << TypesVoid() + << TypesInt() << TypesLong() << TypesFloat() << R"( + %rtarr = OpTypeRuntimeArray %float + %ssbo_s = OpTypeStruct %int %int %rtarr + %var_ty = OpTypePointer Uniform %ssbo_s + %ptr_ty = OpTypePointer Uniform %float + %var = OpVariable %var_ty Uniform + %int_2 = OpConstant %int 2 + %i = OpUndef %ulong + ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450" + ; CHECK-DAG: %ulong_0 = OpConstant %ulong 0 + ; CHECK-DAG: %ulong_1 = OpConstant %ulong 1 + ; CHECK-DAG: %[[longmax:\w+]] = OpConstant %ulong 9223372036854775807 + ; CHECK: OpLabel + ; CHECK: %[[arrlen:\w+]] = OpArrayLength %uint %var 2 + ; CHECK: %[[arrlen_ext:\w+]] = OpUConvert %ulong %[[arrlen]] + ; CHECK: %[[max:\w+]] = OpISub %ulong %[[arrlen_ext]] %ulong_1 + ; CHECK: %[[smin:\w+]] = OpExtInst %ulong %[[GLSLSTD450]] UMin %[[max]] %[[longmax]] + ; CHECK: %[[clamp:\w+]] = OpExtInst %ulong %[[GLSLSTD450]] SClamp %i %ulong_0 %[[smin]] + )" << MainPrefix() + << ACCheck(ac, "%int_2 %i", "%int_2 %[[clamp]]") << MainSuffix(); + SinglePassRunAndMatch(shaders.str(), true); + } +} + +TEST_F(GraphicsRobustAccessTest, ACRTArrayStructVectorElem) { + // The point of this test is that the access chain can have indices past the + // index into the runtime array. For good measure, the index into the final + // struct is out of bounds. We have to clamp that index too. + for (auto* ac : AccessChains()) { + std::ostringstream shaders; + shaders << ShaderPreambleAC({"i", "j"}) + << "OpDecorate %rtarr ArrayStride 32\n" + << DecoSSBO() << "OpMemberDecorate %rtelem 0 Offset 0\n" + << "OpMemberDecorate %rtelem 1 Offset 16\n" + << TypesVoid() << TypesInt() << TypesFloat() << R"( + %v4float = OpTypeVector %float 4 + %rtelem = OpTypeStruct %v4float %v4float + %rtarr = OpTypeRuntimeArray %rtelem + %ssbo_s = OpTypeStruct %int %int %rtarr + %var_ty = OpTypePointer Uniform %ssbo_s + %ptr_ty = OpTypePointer Uniform %float + %var = OpVariable %var_ty Uniform + %int_1 = OpConstant %int 1 + %int_2 = OpConstant %int 2 + %i = OpUndef %int + %j = OpUndef %int + ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450" + ; CHECK-DAG: %int_0 = OpConstant %int 0 + ; CHECK-DAG: %int_3 = OpConstant %int 3 + ; CHECK-DAG: %[[intmax:\w+]] = OpConstant %int 2147483647 + ; CHECK: OpLabel + ; CHECK: %[[arrlen:\w+]] = OpArrayLength %uint %var 2 + ; CHECK: %[[max:\w+]] = OpISub %int %[[arrlen]] %int_1 + ; CHECK: %[[smin:\w+]] = OpExtInst %int %[[GLSLSTD450]] UMin %[[max]] %[[intmax]] + ; CHECK: %[[clamp_i:\w+]] = OpExtInst %int %[[GLSLSTD450]] SClamp %i %int_0 %[[smin]] + ; CHECK: %[[clamp_j:\w+]] = OpExtInst %int %[[GLSLSTD450]] SClamp %j %int_0 %int_3 + )" << MainPrefix() + << ACCheck(ac, "%int_2 %i %int_1 %j", + "%int_2 %[[clamp_i]] %int_1 %[[clamp_j]]") + << MainSuffix(); + SinglePassRunAndMatch(shaders.str(), true); + } +} + +TEST_F(GraphicsRobustAccessTest, ACArrayRTArrayStructVectorElem) { + // Now add an additional level of arrays around the Block-decorated struct. + for (auto* ac : AccessChains()) { + std::ostringstream shaders; + shaders << ShaderPreambleAC({"i", "ssbo_s"}) + << "OpDecorate %rtarr ArrayStride 32\n" + << DecoSSBO() << "OpMemberDecorate %rtelem 0 Offset 0\n" + << "OpMemberDecorate %rtelem 1 Offset 16\n" + << TypesVoid() << TypesInt() << TypesFloat() << R"( + %v4float = OpTypeVector %float 4 + %rtelem = OpTypeStruct %v4float %v4float + %rtarr = OpTypeRuntimeArray %rtelem + %ssbo_s = OpTypeStruct %int %int %rtarr + %arr_size = OpConstant %int 10 + %arr_ssbo = OpTypeArray %ssbo_s %arr_size + %var_ty = OpTypePointer Uniform %arr_ssbo + %ptr_ty = OpTypePointer Uniform %float + %var = OpVariable %var_ty Uniform + %int_1 = OpConstant %int 1 + %int_2 = OpConstant %int 2 + %int_17 = OpConstant %int 17 + %i = OpUndef %int + ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450" + ; CHECK-DAG: %[[ssbo_p:\w+]] = OpTypePointer Uniform %ssbo_s + ; CHECK-DAG: %int_0 = OpConstant %int 0 + ; CHECK-DAG: %int_9 = OpConstant %int 9 + ; CHECK-DAG: %[[intmax:\w+]] = OpConstant %int 2147483647 + ; CHECK: OpLabel + ; This access chain is manufatured only so we can compute the array length. + ; Note that the %int_9 is already clamped + ; CHECK: %[[ssbo_base:\w+]] = )" << ac + << R"( %[[ssbo_p]] %var %int_9 + ; CHECK: %[[arrlen:\w+]] = OpArrayLength %uint %[[ssbo_base]] 2 + ; CHECK: %[[max:\w+]] = OpISub %int %[[arrlen]] %int_1 + ; CHECK: %[[smin:\w+]] = OpExtInst %int %[[GLSLSTD450]] UMin %[[max]] %[[intmax]] + ; CHECK: %[[clamp_i:\w+]] = OpExtInst %int %[[GLSLSTD450]] SClamp %i %int_0 %[[smin]] + )" << MainPrefix() + << ACCheck(ac, "%int_17 %int_2 %i %int_1 %int_2", + "%int_9 %int_2 %[[clamp_i]] %int_1 %int_2") + << MainSuffix(); + SinglePassRunAndMatch(shaders.str(), true); + } +} + +TEST_F(GraphicsRobustAccessTest, ACSplitACArrayRTArrayStructVectorElem) { + // Split the address calculation across two access chains. Force + // the transform to walk up the access chains to find the base variable. + for (auto* ac : AccessChains()) { + std::ostringstream shaders; + shaders << ShaderPreambleAC({"i", "j", "k", "ssbo_s", "ssbo_pty", + "rtarr_pty", "ac_ssbo", "ac_rtarr"}) + << "OpDecorate %rtarr ArrayStride 32\n" + << DecoSSBO() << "OpMemberDecorate %rtelem 0 Offset 0\n" + << "OpMemberDecorate %rtelem 1 Offset 16\n" + << TypesVoid() << TypesInt() << TypesFloat() << R"( + %v4float = OpTypeVector %float 4 + %rtelem = OpTypeStruct %v4float %v4float + %rtarr = OpTypeRuntimeArray %rtelem + %ssbo_s = OpTypeStruct %int %int %rtarr + %arr_size = OpConstant %int 10 + %arr_ssbo = OpTypeArray %ssbo_s %arr_size + %var_ty = OpTypePointer Uniform %arr_ssbo + %ssbo_pty = OpTypePointer Uniform %ssbo_s + %rtarr_pty = OpTypePointer Uniform %rtarr + %ptr_ty = OpTypePointer Uniform %float + %var = OpVariable %var_ty Uniform + %int_1 = OpConstant %int 1 + %int_2 = OpConstant %int 2 + %i = OpUndef %int + %j = OpUndef %int + %k = OpUndef %int + ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450" + ; CHECK-DAG: %int_0 = OpConstant %int 0 + ; CHECK-DAG: %int_9 = OpConstant %int 9 + ; CHECK-DAG: %int_3 = OpConstant %int 3 + ; CHECK-DAG: %[[intmax:\w+]] = OpConstant %int 2147483647 + ; CHECK: OpLabel + ; CHECK: %[[clamp_i:\w+]] = OpExtInst %int %[[GLSLSTD450]] SClamp %i %int_0 %int_9 + ; CHECK: %ac_ssbo = )" << ac + << R"( %ssbo_pty %var %[[clamp_i]] + ; CHECK: %ac_rtarr = )" + << ac << R"( %rtarr_pty %ac_ssbo %int_2 + + ; This is the interesting bit. This array length is needed for an OpAccessChain + ; computing %ac, but the algorithm had to track back through %ac_rtarr's + ; definition to find the base pointer %ac_ssbo. + ; CHECK: %[[arrlen:\w+]] = OpArrayLength %uint %ac_ssbo 2 + ; CHECK: %[[max:\w+]] = OpISub %int %[[arrlen]] %int_1 + ; CHECK: %[[smin:\w+]] = OpExtInst %int %[[GLSLSTD450]] UMin %[[max]] %[[intmax]] + ; CHECK: %[[clamp_j:\w+]] = OpExtInst %int %[[GLSLSTD450]] SClamp %j %int_0 %[[smin]] + ; CHECK: %[[clamp_k:\w+]] = OpExtInst %int %[[GLSLSTD450]] SClamp %k %int_0 %int_3 + ; CHECK: %ac = )" << ac + << R"( %ptr_ty %ac_rtarr %[[clamp_j]] %int_1 %[[clamp_k]] + ; CHECK-NOT: AccessChain + )" << MainPrefix() + << "%ac_ssbo = " << ac << " %ssbo_pty %var %i\n" + << "%ac_rtarr = " << ac << " %rtarr_pty %ac_ssbo %int_2\n" + << "%ac = " << ac << " %ptr_ty %ac_rtarr %j %int_1 %k\n" + + << MainSuffix(); + SinglePassRunAndMatch(shaders.str(), true); + } +} + +TEST_F(GraphicsRobustAccessTest, + ACSplitACArrayRTArrayStructVectorElemAcrossBasicBlocks) { + // Split the address calculation across two access chains. Force + // the transform to walk up the access chains to find the base variable. + // This time, put the different access chains in different basic blocks. + // This sanity checks that we keep the instruction-to-block mapping + // consistent. + for (auto* ac : AccessChains()) { + std::ostringstream shaders; + shaders << ShaderPreambleAC({"i", "j", "k", "bb1", "bb2", "ssbo_s", + "ssbo_pty", "rtarr_pty", "ac_ssbo", + "ac_rtarr"}) + << "OpDecorate %rtarr ArrayStride 32\n" + << DecoSSBO() << "OpMemberDecorate %rtelem 0 Offset 0\n" + << "OpMemberDecorate %rtelem 1 Offset 16\n" + << TypesVoid() << TypesInt() << TypesFloat() << R"( + %v4float = OpTypeVector %float 4 + %rtelem = OpTypeStruct %v4float %v4float + %rtarr = OpTypeRuntimeArray %rtelem + %ssbo_s = OpTypeStruct %int %int %rtarr + %arr_size = OpConstant %int 10 + %arr_ssbo = OpTypeArray %ssbo_s %arr_size + %var_ty = OpTypePointer Uniform %arr_ssbo + %ssbo_pty = OpTypePointer Uniform %ssbo_s + %rtarr_pty = OpTypePointer Uniform %rtarr + %ptr_ty = OpTypePointer Uniform %float + %var = OpVariable %var_ty Uniform + %int_1 = OpConstant %int 1 + %int_2 = OpConstant %int 2 + %i = OpUndef %int + %j = OpUndef %int + %k = OpUndef %int + ; CHECK: %[[GLSLSTD450:\w+]] = OpExtInstImport "GLSL.std.450" + ; CHECK-DAG: %int_0 = OpConstant %int 0 + ; CHECK-DAG: %int_9 = OpConstant %int 9 + ; CHECK-DAG: %int_3 = OpConstant %int 3 + ; CHECK-DAG: %[[intmax:\w+]] = OpConstant %int 2147483647 + ; CHECK: OpLabel + ; CHECK: %[[clamp_i:\w+]] = OpExtInst %int %[[GLSLSTD450]] SClamp %i %int_0 %int_9 + ; CHECK: %ac_ssbo = )" << ac + << R"( %ssbo_pty %var %[[clamp_i]] + ; CHECK: %bb1 = OpLabel + ; CHECK: %ac_rtarr = )" + << ac << R"( %rtarr_pty %ac_ssbo %int_2 + ; CHECK: %bb2 = OpLabel + + ; This is the interesting bit. This array length is needed for an OpAccessChain + ; computing %ac, but the algorithm had to track back through %ac_rtarr's + ; definition to find the base pointer %ac_ssbo. + ; CHECK: %[[arrlen:\w+]] = OpArrayLength %uint %ac_ssbo 2 + ; CHECK: %[[max:\w+]] = OpISub %int %[[arrlen]] %int_1 + ; CHECK: %[[smin:\w+]] = OpExtInst %int %[[GLSLSTD450]] UMin %[[max]] %[[intmax]] + ; CHECK: %[[clamp_j:\w+]] = OpExtInst %int %[[GLSLSTD450]] SClamp %j %int_0 %[[smin]] + ; CHECK: %[[clamp_k:\w+]] = OpExtInst %int %[[GLSLSTD450]] SClamp %k %int_0 %int_3 + ; CHECK: %ac = )" << ac + << R"( %ptr_ty %ac_rtarr %[[clamp_j]] %int_1 %[[clamp_k]] + ; CHECK-NOT: AccessChain + )" << MainPrefix() + << "%ac_ssbo = " << ac << " %ssbo_pty %var %i\n" + << "OpBranch %bb1\n%bb1 = OpLabel\n" + << "%ac_rtarr = " << ac << " %rtarr_pty %ac_ssbo %int_2\n" + << "OpBranch %bb2\n%bb2 = OpLabel\n" + << "%ac = " << ac << " %ptr_ty %ac_rtarr %j %int_1 %k\n" + + << MainSuffix(); + SinglePassRunAndMatch(shaders.str(), true); + } +} + +// TODO(dneto): Test access chain index wider than 64 bits? +// TODO(dneto): Test struct access chain index wider than 64 bits? +// TODO(dneto): OpImageTexelPointer +// - all Dim types: 1D 2D Cube 3D Rect Buffer +// - all Dim types that can be arrayed: 1D 2D 3D +// - sample index: set to 0 if not multisampled +// - Dim (2D, Cube Rect} with multisampling +// -1 0 max excess +// TODO(dneto): Test OpImageTexelPointer with coordinate component index other +// than 32 bits. + +} // namespace diff --git a/third_party/spirv-tools/test/opt/if_conversion_test.cpp b/third_party/spirv-tools/test/opt/if_conversion_test.cpp index a62a15e88f..aa5adea6e8 100644 --- a/third_party/spirv-tools/test/opt/if_conversion_test.cpp +++ b/third_party/spirv-tools/test/opt/if_conversion_test.cpp @@ -25,7 +25,6 @@ namespace { using IfConversionTest = PassTest<::testing::Test>; -#ifdef SPIRV_EFFCEE TEST_F(IfConversionTest, TestSimpleIfThenElse) { const std::string text = R"( ; CHECK: OpSelectionMerge [[merge:%\w+]] @@ -302,7 +301,6 @@ TEST_F(IfConversionTest, CodeMotionMultipleInstructions) { SinglePassRunAndMatch(text, true); } -#endif // SPIRV_EFFCEE TEST_F(IfConversionTest, NoCommonDominator) { const std::string text = R"(OpCapability Shader @@ -377,14 +375,12 @@ OpEntryPoint Vertex %1 "func" %2 OpSelectionMerge %12 None OpBranchConditional %true %13 %12 %13 = OpLabel -OpBranchConditional %true %14 %15 +OpBranchConditional %true %14 %12 %14 = OpLabel OpBranch %12 -%15 = OpLabel -OpBranch %12 %12 = OpLabel -%16 = OpPhi %uint %uint_0 %11 %uint_0 %14 %uint_1 %15 -OpStore %2 %16 +%15 = OpPhi %uint %uint_0 %11 %uint_0 %13 %uint_1 %14 +OpStore %2 %15 OpReturn OpFunctionEnd )"; @@ -469,6 +465,45 @@ OpFunctionEnd SinglePassRunAndCheck(text, text, true, true); } +TEST_F(IfConversionTest, InvalidCommonDominator) { + const std::string text = R"(OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%float = OpTypeFloat 32 +%float_0 = OpConstant %float 0 +%float_1 = OpConstant %float 1 +%bool = OpTypeBool +%true = OpConstantTrue %bool +%1 = OpTypeFunction %void +%2 = OpFunction %void None %1 +%3 = OpLabel +OpBranch %4 +%4 = OpLabel +OpLoopMerge %5 %6 None +OpBranch %7 +%7 = OpLabel +OpSelectionMerge %8 None +OpBranchConditional %true %8 %9 +%9 = OpLabel +OpSelectionMerge %10 None +OpBranchConditional %true %10 %5 +%10 = OpLabel +OpBranch %8 +%8 = OpLabel +OpBranch %6 +%6 = OpLabel +OpBranchConditional %true %4 %5 +%5 = OpLabel +%11 = OpPhi %float %float_0 %6 %float_1 %9 +OpReturn +OpFunctionEnd +)"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck(text, text, true, true); +} + } // namespace } // namespace opt } // namespace spvtools diff --git a/third_party/spirv-tools/test/opt/inline_test.cpp b/third_party/spirv-tools/test/opt/inline_test.cpp index 4eab77da4f..f44c04a052 100644 --- a/third_party/spirv-tools/test/opt/inline_test.cpp +++ b/third_party/spirv-tools/test/opt/inline_test.cpp @@ -1819,7 +1819,7 @@ OpFunctionEnd %9 = OpLabel OpBranch %10 %10 = OpLabel -OpLoopMerge %12 %13 None +OpLoopMerge %12 %10 None OpBranch %13 %13 = OpLabel OpBranchConditional %true %10 %12 @@ -1980,7 +1980,7 @@ OpFunctionEnd OpBranch %13 %13 = OpLabel %14 = OpCopyObject %bool %false -OpLoopMerge %16 %19 None +OpLoopMerge %16 %13 None OpBranch %17 %17 = OpLabel %18 = OpCopyObject %bool %true @@ -2144,19 +2144,12 @@ OpFunctionEnd OpBranch %19 %19 = OpLabel %20 = OpCopyObject %int %int_2 -OpLoopMerge %23 %26 None -OpBranch %25 -%25 = OpLabel -OpLoopMerge %26 %27 None -OpBranch %28 -%28 = OpLabel -%29 = OpCopyObject %int %int_0 -OpBranch %26 -%30 = OpLabel -%31 = OpCopyObject %int %int_1 +%25 = OpCopyObject %int %int_0 +OpLoopMerge %23 %19 None OpBranch %26 %27 = OpLabel -OpBranchConditional %false %25 %26 +%28 = OpCopyObject %int %int_1 +OpBranch %26 %26 = OpLabel %22 = OpCopyObject %int %int_3 OpBranchConditional %true %19 %23 @@ -2226,23 +2219,16 @@ OpFunctionEnd R"(%1 = OpFunction %void None %9 %20 = OpLabel %21 = OpCopyObject %int %int_3 -OpBranch %24 -%24 = OpLabel -OpLoopMerge %25 %26 None -OpBranch %27 -%27 = OpLabel -%28 = OpCopyObject %int %int_0 -OpBranch %29 -%29 = OpLabel -%30 = OpPhi %int %28 %27 -%31 = OpCopyObject %int %int_1 +%24 = OpCopyObject %int %int_0 OpBranch %25 -%32 = OpLabel -%33 = OpCopyObject %int %int_2 -OpBranch %25 -%26 = OpLabel -OpBranchConditional %false %24 %25 %25 = OpLabel +%26 = OpPhi %int %24 %20 +%27 = OpCopyObject %int %int_1 +OpBranch %28 +%29 = OpLabel +%30 = OpCopyObject %int %int_2 +OpBranch %28 +%28 = OpLabel %23 = OpCopyObject %int %int_4 OpReturn OpFunctionEnd @@ -2253,6 +2239,223 @@ OpFunctionEnd false, true); } +TEST_F(InlineTest, NonInlinableCalleeWithSingleReturn) { + // The case from https://github.com/KhronosGroup/SPIRV-Tools/issues/2018 + // + // The callee has a single return, but cannot be inlined because the + // return is inside a loop. + + const std::string predefs = + R"(OpCapability Shader +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %_GLF_color +OpExecutionMode %main OriginUpperLeft +OpSource ESSL 310 +OpName %main "main" +OpName %f_ "f(" +OpName %i "i" +OpName %_GLF_color "_GLF_color" +OpDecorate %_GLF_color Location 0 +%void = OpTypeVoid +%7 = OpTypeFunction %void +%float = OpTypeFloat 32 +%9 = OpTypeFunction %float +%float_1 = OpConstant %float 1 +%bool = OpTypeBool +%false = OpConstantFalse %bool +%int = OpTypeInt 32 1 +%_ptr_Function_int = OpTypePointer Function %int +%int_0 = OpConstant %int 0 +%int_1 = OpConstant %int 1 +%v4float = OpTypeVector %float 4 +%_ptr_Output_v4float = OpTypePointer Output %v4float +%_GLF_color = OpVariable %_ptr_Output_v4float Output +%float_0 = OpConstant %float 0 +%20 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0 +%21 = OpConstantComposite %v4float %float_0 %float_1 %float_0 %float_1 +)"; + + const std::string caller = + R"(%main = OpFunction %void None %7 +%22 = OpLabel +%i = OpVariable %_ptr_Function_int Function +OpStore %i %int_0 +OpBranch %23 +%23 = OpLabel +OpLoopMerge %24 %25 None +OpBranch %26 +%26 = OpLabel +%27 = OpLoad %int %i +%28 = OpSLessThan %bool %27 %int_1 +OpBranchConditional %28 %29 %24 +%29 = OpLabel +OpStore %_GLF_color %20 +%30 = OpFunctionCall %float %f_ +OpBranch %25 +%25 = OpLabel +%31 = OpLoad %int %i +%32 = OpIAdd %int %31 %int_1 +OpStore %i %32 +OpBranch %23 +%24 = OpLabel +OpStore %_GLF_color %21 +OpReturn +OpFunctionEnd +)"; + + const std::string callee = + R"(%f_ = OpFunction %float None %9 +%33 = OpLabel +OpBranch %34 +%34 = OpLabel +OpLoopMerge %35 %36 None +OpBranch %37 +%37 = OpLabel +OpReturnValue %float_1 +%36 = OpLabel +OpBranch %34 +%35 = OpLabel +OpUnreachable +OpFunctionEnd +)"; + + SinglePassRunAndCheck( + predefs + caller + callee, predefs + caller + callee, false, true); +} + +TEST_F(InlineTest, CalleeWithSingleReturnNeedsSingleTripLoopWrapper) { + // The case from https://github.com/KhronosGroup/SPIRV-Tools/issues/2018 + // + // The callee has a single return, but needs single-trip loop wrapper + // to be inlined because the return is in a selection structure. + + const std::string predefs = + R"(OpCapability Shader +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %_GLF_color +OpExecutionMode %main OriginUpperLeft +OpSource ESSL 310 +OpName %main "main" +OpName %f_ "f(" +OpName %i "i" +OpName %_GLF_color "_GLF_color" +OpDecorate %_GLF_color Location 0 +%void = OpTypeVoid +%7 = OpTypeFunction %void +%float = OpTypeFloat 32 +%9 = OpTypeFunction %float +%float_1 = OpConstant %float 1 +%bool = OpTypeBool +%false = OpConstantFalse %bool +%true = OpConstantTrue %bool +%int = OpTypeInt 32 1 +%_ptr_Function_int = OpTypePointer Function %int +%int_0 = OpConstant %int 0 +%int_1 = OpConstant %int 1 +%v4float = OpTypeVector %float 4 +%_ptr_Output_v4float = OpTypePointer Output %v4float +%_GLF_color = OpVariable %_ptr_Output_v4float Output +%float_0 = OpConstant %float 0 +%21 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0 +%22 = OpConstantComposite %v4float %float_0 %float_1 %float_0 %float_1 +)"; + + const std::string new_predefs = + R"(%_ptr_Function_float = OpTypePointer Function %float +)"; + + const std::string main_before = + R"(%main = OpFunction %void None %7 +%23 = OpLabel +%i = OpVariable %_ptr_Function_int Function +OpStore %i %int_0 +OpBranch %24 +%24 = OpLabel +OpLoopMerge %25 %26 None +OpBranch %27 +%27 = OpLabel +%28 = OpLoad %int %i +%29 = OpSLessThan %bool %28 %int_1 +OpBranchConditional %29 %30 %25 +%30 = OpLabel +OpStore %_GLF_color %21 +%31 = OpFunctionCall %float %f_ +OpBranch %26 +%26 = OpLabel +%32 = OpLoad %int %i +%33 = OpIAdd %int %32 %int_1 +OpStore %i %33 +OpBranch %24 +%25 = OpLabel +OpStore %_GLF_color %22 +OpReturn +OpFunctionEnd +)"; + + const std::string main_after = + R"(%main = OpFunction %void None %7 +%23 = OpLabel +%38 = OpVariable %_ptr_Function_float Function +%i = OpVariable %_ptr_Function_int Function +OpStore %i %int_0 +OpBranch %24 +%24 = OpLabel +OpLoopMerge %25 %26 None +OpBranch %27 +%27 = OpLabel +%28 = OpLoad %int %i +%29 = OpSLessThan %bool %28 %int_1 +OpBranchConditional %29 %30 %25 +%30 = OpLabel +OpStore %_GLF_color %21 +OpBranch %39 +%39 = OpLabel +OpLoopMerge %40 %41 None +OpBranch %42 +%42 = OpLabel +OpSelectionMerge %43 None +OpBranchConditional %true %44 %43 +%44 = OpLabel +OpStore %38 %float_1 +OpBranch %40 +%43 = OpLabel +OpStore %38 %float_1 +OpBranch %40 +%41 = OpLabel +OpBranchConditional %false %39 %40 +%40 = OpLabel +%31 = OpLoad %float %38 +OpBranch %26 +%26 = OpLabel +%32 = OpLoad %int %i +%33 = OpIAdd %int %32 %int_1 +OpStore %i %33 +OpBranch %24 +%25 = OpLabel +OpStore %_GLF_color %22 +OpReturn +OpFunctionEnd +)"; + + const std::string callee = + R"(%f_ = OpFunction %float None %9 +%34 = OpLabel +OpSelectionMerge %35 None +OpBranchConditional %true %36 %35 +%36 = OpLabel +OpReturnValue %float_1 +%35 = OpLabel +OpReturnValue %float_1 +OpFunctionEnd +)"; + + SinglePassRunAndCheck( + predefs + main_before + callee, + predefs + new_predefs + main_after + callee, false, true); +} + TEST_F(InlineTest, Decorated1) { // Same test as Simple with the difference // that OpFAdd in the outlined function is @@ -2589,179 +2792,6 @@ TEST_F(InlineTest, SetParent) { } } -#ifdef SPIRV_EFFCEE -TEST_F(InlineTest, OpKill) { - const std::string text = R"( -; CHECK: OpFunction -; CHECK-NEXT: OpLabel -; CHECK-NEXT: OpKill -; CHECK-NEXT: OpLabel -; CHECK-NEXT: OpReturn -; CHECK-NEXT: OpFunctionEnd -OpCapability Shader -OpMemoryModel Logical GLSL450 -OpEntryPoint Fragment %main "main" -%void = OpTypeVoid -%voidfuncty = OpTypeFunction %void -%main = OpFunction %void None %voidfuncty -%1 = OpLabel -%2 = OpFunctionCall %void %func -OpReturn -OpFunctionEnd -%func = OpFunction %void None %voidfuncty -%3 = OpLabel -OpKill -OpFunctionEnd -)"; - - SinglePassRunAndMatch(text, true); -} - -TEST_F(InlineTest, OpKillWithTrailingInstructions) { - const std::string text = R"( -; CHECK: OpFunction -; CHECK-NEXT: OpLabel -; CHECK-NEXT: [[var:%\w+]] = OpVariable -; CHECK-NEXT: OpKill -; CHECK-NEXT: OpLabel -; CHECK-NEXT: OpStore [[var]] -; CHECK-NEXT: OpReturn -; CHECK-NEXT: OpFunctionEnd -OpCapability Shader -OpMemoryModel Logical GLSL450 -OpEntryPoint Fragment %main "main" -%void = OpTypeVoid -%bool = OpTypeBool -%true = OpConstantTrue %bool -%bool_func_ptr = OpTypePointer Function %bool -%voidfuncty = OpTypeFunction %void -%main = OpFunction %void None %voidfuncty -%1 = OpLabel -%2 = OpVariable %bool_func_ptr Function -%3 = OpFunctionCall %void %func -OpStore %2 %true -OpReturn -OpFunctionEnd -%func = OpFunction %void None %voidfuncty -%4 = OpLabel -OpKill -OpFunctionEnd -)"; - - SinglePassRunAndMatch(text, true); -} - -TEST_F(InlineTest, OpKillInIf) { - const std::string text = R"( -; CHECK: OpFunction -; CHECK: OpLabel -; CHECK: [[var:%\w+]] = OpVariable -; CHECK-NEXT: [[ld:%\w+]] = OpLoad {{%\w+}} [[var]] -; CHECK-NEXT: OpBranch [[label:%\w+]] -; CHECK-NEXT: [[label]] = OpLabel -; CHECK-NEXT: OpLoopMerge [[loop_merge:%\w+]] [[continue:%\w+]] None -; CHECK-NEXT: OpBranch [[label:%\w+]] -; CHECK-NEXT: [[label]] = OpLabel -; CHECK-NEXT: OpSelectionMerge [[sel_merge:%\w+]] None -; CHECK-NEXT: OpBranchConditional {{%\w+}} [[kill_label:%\w+]] [[label:%\w+]] -; CHECK-NEXT: [[kill_label]] = OpLabel -; CHECK-NEXT: OpKill -; CHECK-NEXT: [[label]] = OpLabel -; CHECK-NEXT: OpBranch [[loop_merge]] -; CHECK-NEXT: [[sel_merge]] = OpLabel -; CHECK-NEXT: OpBranch [[loop_merge]] -; CHECK-NEXT: [[continue]] = OpLabel -; CHECK-NEXT: OpBranchConditional -; CHECK-NEXT: [[loop_merge]] = OpLabel -; CHECK-NEXT: OpStore [[var]] [[ld]] -; CHECK-NEXT: OpReturn -; CHECK-NEXT: OpFunctionEnd -OpCapability Shader -OpMemoryModel Logical GLSL450 -OpEntryPoint Fragment %main "main" -%void = OpTypeVoid -%bool = OpTypeBool -%true = OpConstantTrue %bool -%bool_func_ptr = OpTypePointer Function %bool -%voidfuncty = OpTypeFunction %void -%main = OpFunction %void None %voidfuncty -%1 = OpLabel -%2 = OpVariable %bool_func_ptr Function -%3 = OpLoad %bool %2 -%4 = OpFunctionCall %void %func -OpStore %2 %3 -OpReturn -OpFunctionEnd -%func = OpFunction %void None %voidfuncty -%5 = OpLabel -OpSelectionMerge %6 None -OpBranchConditional %true %7 %8 -%7 = OpLabel -OpKill -%8 = OpLabel -OpReturn -%6 = OpLabel -OpReturn -OpFunctionEnd -)"; - - SinglePassRunAndMatch(text, true); -} - -TEST_F(InlineTest, OpKillInLoop) { - const std::string text = R"( -; CHECK: OpFunction -; CHECK: OpLabel -; CHECK: [[var:%\w+]] = OpVariable -; CHECK-NEXT: [[ld:%\w+]] = OpLoad {{%\w+}} [[var]] -; CHECK-NEXT: OpBranch [[loop:%\w+]] -; CHECK-NEXT: [[loop]] = OpLabel -; CHECK-NEXT: OpLoopMerge [[loop_merge:%\w+]] [[continue:%\w+]] None -; CHECK-NEXT: OpBranch [[label:%\w+]] -; CHECK-NEXT: [[label]] = OpLabel -; CHECK-NEXT: OpKill -; CHECK-NEXT: [[loop_merge]] = OpLabel -; CHECK-NEXT: OpBranch [[label:%\w+]] -; CHECK-NEXT: [[continue]] = OpLabel -; CHECK-NEXT: OpBranch [[loop]] -; CHECK-NEXT: [[label]] = OpLabel -; CHECK-NEXT: OpStore [[var]] [[ld]] -; CHECK-NEXT: OpReturn -; CHECK-NEXT: OpFunctionEnd -OpCapability Shader -OpMemoryModel Logical GLSL450 -OpEntryPoint Fragment %main "main" -%void = OpTypeVoid -%bool = OpTypeBool -%true = OpConstantTrue %bool -%voidfuncty = OpTypeFunction %void -%bool_func_ptr = OpTypePointer Function %bool -%main = OpFunction %void None %voidfuncty -%1 = OpLabel -%2 = OpVariable %bool_func_ptr Function -%3 = OpLoad %bool %2 -%4 = OpFunctionCall %void %func -OpStore %2 %3 -OpReturn -OpFunctionEnd -%func = OpFunction %void None %voidfuncty -%5 = OpLabel -OpBranch %10 -%10 = OpLabel -OpLoopMerge %6 %7 None -OpBranch %8 -%8 = OpLabel -OpKill -%6 = OpLabel -OpReturn -%7 = OpLabel -OpBranch %10 -OpFunctionEnd -)"; - - SinglePassRunAndMatch(text, true); -} - TEST_F(InlineTest, OpVariableWithInit) { // Check that there is a store that corresponds to the initializer. This // test makes sure that is a store to the variable in the loop and before any @@ -2840,14 +2870,171 @@ TEST_F(InlineTest, OpVariableWithInit) { SinglePassRunAndMatch(text, true); } -#endif + +TEST_F(InlineTest, DontInlineDirectlyRecursiveFunc) { + // Test that the name of the result id of the call is deleted. + const std::string test = + R"(OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %1 "main" +OpExecutionMode %1 OriginUpperLeft +OpDecorate %2 DescriptorSet 439418829 +%void = OpTypeVoid +%4 = OpTypeFunction %void +%float = OpTypeFloat 32 +%_struct_6 = OpTypeStruct %float %float +%15 = OpConstantNull %_struct_6 +%7 = OpTypeFunction %_struct_6 +%1 = OpFunction %void Pure|Const %4 +%8 = OpLabel +%2 = OpFunctionCall %_struct_6 %9 +OpKill +OpFunctionEnd +%9 = OpFunction %_struct_6 None %7 +%10 = OpLabel +%11 = OpFunctionCall %_struct_6 %9 +OpReturnValue %15 +OpFunctionEnd +)"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck(test, test, false, true); +} + +TEST_F(InlineTest, DontInlineInDirectlyRecursiveFunc) { + // Test that the name of the result id of the call is deleted. + const std::string test = + R"(OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %1 "main" +OpExecutionMode %1 OriginUpperLeft +OpDecorate %2 DescriptorSet 439418829 +%void = OpTypeVoid +%4 = OpTypeFunction %void +%float = OpTypeFloat 32 +%_struct_6 = OpTypeStruct %float %float +%15 = OpConstantNull %_struct_6 +%7 = OpTypeFunction %_struct_6 +%1 = OpFunction %void Pure|Const %4 +%8 = OpLabel +%2 = OpFunctionCall %_struct_6 %9 +OpKill +OpFunctionEnd +%9 = OpFunction %_struct_6 None %7 +%10 = OpLabel +%11 = OpFunctionCall %_struct_6 %12 +OpReturnValue %15 +OpFunctionEnd +%12 = OpFunction %_struct_6 None %7 +%13 = OpLabel +%14 = OpFunctionCall %_struct_6 %9 +OpReturnValue %15 +OpFunctionEnd +)"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck(test, test, false, true); +} + +TEST_F(InlineTest, DontInlineFuncWithOpKillInContinue) { + const std::string test = + R"(OpCapability Shader +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 330 +OpName %main "main" +OpName %kill_ "kill(" +%void = OpTypeVoid +%3 = OpTypeFunction %void +%bool = OpTypeBool +%true = OpConstantTrue %bool +%main = OpFunction %void None %3 +%5 = OpLabel +OpBranch %9 +%9 = OpLabel +OpLoopMerge %11 %12 None +OpBranch %13 +%13 = OpLabel +OpBranchConditional %true %10 %11 +%10 = OpLabel +OpBranch %12 +%12 = OpLabel +%16 = OpFunctionCall %void %kill_ +OpBranch %9 +%11 = OpLabel +OpReturn +OpFunctionEnd +%kill_ = OpFunction %void None %3 +%7 = OpLabel +OpKill +OpFunctionEnd +)"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck(test, test, false, true); +} + +TEST_F(InlineTest, InlineFuncWithOpKillNotInContinue) { + const std::string before = + R"(OpCapability Shader +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 330 +OpName %main "main" +OpName %kill_ "kill(" +%void = OpTypeVoid +%3 = OpTypeFunction %void +%bool = OpTypeBool +%true = OpConstantTrue %bool +%main = OpFunction %void None %3 +%5 = OpLabel +%16 = OpFunctionCall %void %kill_ +OpReturn +OpFunctionEnd +%kill_ = OpFunction %void None %3 +%7 = OpLabel +OpKill +OpFunctionEnd +)"; + + const std::string after = + R"(OpCapability Shader +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 330 +OpName %main "main" +OpName %kill_ "kill(" +%void = OpTypeVoid +%3 = OpTypeFunction %void +%bool = OpTypeBool +%true = OpConstantTrue %bool +%main = OpFunction %void None %3 +%5 = OpLabel +OpKill +%17 = OpLabel +OpReturn +OpFunctionEnd +%kill_ = OpFunction %void None %3 +%7 = OpLabel +OpKill +OpFunctionEnd +)"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck(before, after, false, true); +} // TODO(greg-lunarg): Add tests to verify handling of these cases: // // Empty modules // Modules without function definitions // Modules in which all functions do not call other functions -// Recursive functions (calling self & calling each other) // Caller and callee both accessing the same global variable // Functions with OpLine & OpNoLine // Others? diff --git a/third_party/spirv-tools/test/opt/inst_bindless_check_test.cpp b/third_party/spirv-tools/test/opt/inst_bindless_check_test.cpp new file mode 100644 index 0000000000..d867b01f50 --- /dev/null +++ b/third_party/spirv-tools/test/opt/inst_bindless_check_test.cpp @@ -0,0 +1,7195 @@ +// Copyright (c) 2017 Valve Corporation +// Copyright (c) 2017 LunarG Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Bindless Check Instrumentation Tests. + +#include +#include + +#include "test/opt/assembly_builder.h" +#include "test/opt/pass_fixture.h" +#include "test/opt/pass_utils.h" + +namespace spvtools { +namespace opt { +namespace { + +using InstBindlessTest = PassTest<::testing::Test>; + +TEST_F(InstBindlessTest, NoInstrumentConstIndexInbounds) { + // Texture2D g_tColor[128]; + // + // SamplerState g_sAniso; + // + // struct PS_INPUT + // { + // float2 vTextureCoords : TEXCOORD2; + // }; + // + // struct PS_OUTPUT + // { + // float4 vColor : SV_Target0; + // }; + // + // PS_OUTPUT MainPs(PS_INPUT i) + // { + // PS_OUTPUT ps_output; + // + // ps_output.vColor = g_tColor[ 37 ].Sample(g_sAniso, i.vTextureCoords.xy); + // return ps_output; + // } + + const std::string before = + R"(OpCapability Shader +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor +OpExecutionMode %MainPs OriginUpperLeft +OpSource HLSL 500 +OpName %MainPs "MainPs" +OpName %g_tColor "g_tColor" +OpName %g_sAniso "g_sAniso" +OpName %i_vTextureCoords "i.vTextureCoords" +OpName %_entryPointOutput_vColor "@entryPointOutput.vColor" +OpDecorate %g_tColor DescriptorSet 3 +OpDecorate %g_tColor Binding 0 +OpDecorate %g_sAniso DescriptorSet 0 +OpDecorate %i_vTextureCoords Location 0 +OpDecorate %_entryPointOutput_vColor Location 0 +%void = OpTypeVoid +%8 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v2float = OpTypeVector %float 2 +%v4float = OpTypeVector %float 4 +%int = OpTypeInt 32 1 +%int_0 = OpConstant %int 0 +%int_37 = OpConstant %int 37 +%15 = OpTypeImage %float 2D 0 0 0 1 Unknown +%uint = OpTypeInt 32 0 +%uint_128 = OpConstant %uint 128 +%_arr_15_uint_128 = OpTypeArray %15 %uint_128 +%_ptr_UniformConstant__arr_15_uint_128 = OpTypePointer UniformConstant %_arr_15_uint_128 +%g_tColor = OpVariable %_ptr_UniformConstant__arr_15_uint_128 UniformConstant +%_ptr_UniformConstant_15 = OpTypePointer UniformConstant %15 +%21 = OpTypeSampler +%_ptr_UniformConstant_21 = OpTypePointer UniformConstant %21 +%g_sAniso = OpVariable %_ptr_UniformConstant_21 UniformConstant +%23 = OpTypeSampledImage %15 +%_ptr_Input_v2float = OpTypePointer Input %v2float +%i_vTextureCoords = OpVariable %_ptr_Input_v2float Input +%_ptr_Output_v4float = OpTypePointer Output %v4float +%_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output +%MainPs = OpFunction %void None %8 +%26 = OpLabel +%27 = OpLoad %v2float %i_vTextureCoords +%28 = OpAccessChain %_ptr_UniformConstant_15 %g_tColor %int_37 +%29 = OpLoad %15 %28 +%30 = OpLoad %21 %g_sAniso +%31 = OpSampledImage %23 %29 %30 +%32 = OpImageSampleImplicitLod %v4float %31 %27 +OpStore %_entryPointOutput_vColor %32 +OpReturn +OpFunctionEnd +)"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck(before, before, true, true, 7u, + 23u, false, false); +} + +TEST_F(InstBindlessTest, NoInstrumentNonBindless) { + // This test verifies that the pass will correctly not instrument vanilla + // texture sample. + // + // Texture2D g_tColor; + // + // SamplerState g_sAniso; + // + // struct PS_INPUT + // { + // float2 vTextureCoords : TEXCOORD2; + // }; + // + // struct PS_OUTPUT + // { + // float4 vColor : SV_Target0; + // }; + // + // PS_OUTPUT MainPs(PS_INPUT i) + // { + // PS_OUTPUT ps_output; + // ps_output.vColor = + // g_tColor.Sample(g_sAniso, i.vTextureCoords.xy); + // return ps_output; + // } + + const std::string whole_file = + R"(OpCapability Shader +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor +OpExecutionMode %MainPs OriginUpperLeft +OpSource HLSL 500 +OpName %MainPs "MainPs" +OpName %g_tColor "g_tColor" +OpName %g_sAniso "g_sAniso" +OpName %i_vTextureCoords "i.vTextureCoords" +OpName %_entryPointOutput_vColor "@entryPointOutput.vColor" +OpDecorate %g_tColor DescriptorSet 0 +OpDecorate %g_tColor Binding 0 +OpDecorate %g_sAniso DescriptorSet 0 +OpDecorate %g_sAniso Binding 0 +OpDecorate %i_vTextureCoords Location 0 +OpDecorate %_entryPointOutput_vColor Location 0 +%void = OpTypeVoid +%8 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v2float = OpTypeVector %float 2 +%v4float = OpTypeVector %float 4 +%12 = OpTypeImage %float 2D 0 0 0 1 Unknown +%_ptr_UniformConstant_12 = OpTypePointer UniformConstant %12 +%g_tColor = OpVariable %_ptr_UniformConstant_12 UniformConstant +%14 = OpTypeSampler +%_ptr_UniformConstant_14 = OpTypePointer UniformConstant %14 +%g_sAniso = OpVariable %_ptr_UniformConstant_14 UniformConstant +%16 = OpTypeSampledImage %12 +%_ptr_Input_v2float = OpTypePointer Input %v2float +%i_vTextureCoords = OpVariable %_ptr_Input_v2float Input +%_ptr_Output_v4float = OpTypePointer Output %v4float +%_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output +%MainPs = OpFunction %void None %8 +%19 = OpLabel +%20 = OpLoad %v2float %i_vTextureCoords +%21 = OpLoad %12 %g_tColor +%22 = OpLoad %14 %g_sAniso +%23 = OpSampledImage %16 %21 %22 +%24 = OpImageSampleImplicitLod %v4float %23 %20 +OpStore %_entryPointOutput_vColor %24 +OpReturn +OpFunctionEnd +)"; + + // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck(whole_file, whole_file, true, + true, 7u, 23u, false, false); +} + +TEST_F(InstBindlessTest, Simple) { + // Texture2D g_tColor[128]; + // + // layout(push_constant) cbuffer PerViewConstantBuffer_t + // { + // uint g_nDataIdx; + // }; + // + // SamplerState g_sAniso; + // + // struct PS_INPUT + // { + // float2 vTextureCoords : TEXCOORD2; + // }; + // + // struct PS_OUTPUT + // { + // float4 vColor : SV_Target0; + // }; + // + // PS_OUTPUT MainPs(PS_INPUT i) + // { + // PS_OUTPUT ps_output; + // ps_output.vColor = + // g_tColor[ g_nDataIdx ].Sample(g_sAniso, i.vTextureCoords.xy); + // return ps_output; + // } + + const std::string entry_before = + R"(OpCapability Shader +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor +OpExecutionMode %MainPs OriginUpperLeft +OpSource HLSL 500 +)"; + + const std::string entry_after = + R"(OpCapability Shader +OpExtension "SPV_KHR_storage_buffer_storage_class" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord +OpExecutionMode %MainPs OriginUpperLeft +OpSource HLSL 500 +)"; + + const std::string names_annots = + R"(OpName %MainPs "MainPs" +OpName %g_tColor "g_tColor" +OpName %PerViewConstantBuffer_t "PerViewConstantBuffer_t" +OpMemberName %PerViewConstantBuffer_t 0 "g_nDataIdx" +OpName %_ "" +OpName %g_sAniso "g_sAniso" +OpName %i_vTextureCoords "i.vTextureCoords" +OpName %_entryPointOutput_vColor "@entryPointOutput.vColor" +OpDecorate %g_tColor DescriptorSet 3 +OpDecorate %g_tColor Binding 0 +OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0 +OpDecorate %PerViewConstantBuffer_t Block +OpDecorate %g_sAniso DescriptorSet 0 +OpDecorate %i_vTextureCoords Location 0 +OpDecorate %_entryPointOutput_vColor Location 0 +)"; + + const std::string new_annots = + R"(OpDecorate %_runtimearr_uint ArrayStride 4 +OpDecorate %_struct_55 Block +OpMemberDecorate %_struct_55 0 Offset 0 +OpMemberDecorate %_struct_55 1 Offset 4 +OpDecorate %57 DescriptorSet 7 +OpDecorate %57 Binding 0 +OpDecorate %gl_FragCoord BuiltIn FragCoord +)"; + + const std::string consts_types_vars = + R"(%void = OpTypeVoid +%10 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v2float = OpTypeVector %float 2 +%v4float = OpTypeVector %float 4 +%int = OpTypeInt 32 1 +%int_0 = OpConstant %int 0 +%16 = OpTypeImage %float 2D 0 0 0 1 Unknown +%uint = OpTypeInt 32 0 +%uint_128 = OpConstant %uint 128 +%_arr_16_uint_128 = OpTypeArray %16 %uint_128 +%_ptr_UniformConstant__arr_16_uint_128 = OpTypePointer UniformConstant %_arr_16_uint_128 +%g_tColor = OpVariable %_ptr_UniformConstant__arr_16_uint_128 UniformConstant +%PerViewConstantBuffer_t = OpTypeStruct %uint +%_ptr_PushConstant_PerViewConstantBuffer_t = OpTypePointer PushConstant %PerViewConstantBuffer_t +%_ = OpVariable %_ptr_PushConstant_PerViewConstantBuffer_t PushConstant +%_ptr_PushConstant_uint = OpTypePointer PushConstant %uint +%_ptr_UniformConstant_16 = OpTypePointer UniformConstant %16 +%24 = OpTypeSampler +%_ptr_UniformConstant_24 = OpTypePointer UniformConstant %24 +%g_sAniso = OpVariable %_ptr_UniformConstant_24 UniformConstant +%26 = OpTypeSampledImage %16 +%_ptr_Input_v2float = OpTypePointer Input %v2float +%i_vTextureCoords = OpVariable %_ptr_Input_v2float Input +%_ptr_Output_v4float = OpTypePointer Output %v4float +%_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output +)"; + + const std::string new_consts_types_vars = + R"(%uint_0 = OpConstant %uint 0 +%bool = OpTypeBool +%48 = OpTypeFunction %void %uint %uint %uint %uint +%_runtimearr_uint = OpTypeRuntimeArray %uint +%_struct_55 = OpTypeStruct %uint %_runtimearr_uint +%_ptr_StorageBuffer__struct_55 = OpTypePointer StorageBuffer %_struct_55 +%57 = OpVariable %_ptr_StorageBuffer__struct_55 StorageBuffer +%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint +%uint_10 = OpConstant %uint 10 +%uint_4 = OpConstant %uint 4 +%uint_1 = OpConstant %uint 1 +%uint_23 = OpConstant %uint 23 +%uint_2 = OpConstant %uint 2 +%uint_3 = OpConstant %uint 3 +%_ptr_Input_v4float = OpTypePointer Input %v4float +%gl_FragCoord = OpVariable %_ptr_Input_v4float Input +%v4uint = OpTypeVector %uint 4 +%uint_5 = OpConstant %uint 5 +%uint_7 = OpConstant %uint 7 +%uint_8 = OpConstant %uint 8 +%uint_9 = OpConstant %uint 9 +%uint_56 = OpConstant %uint 56 +%103 = OpConstantNull %v4float +)"; + + const std::string func_pt1 = + R"(%MainPs = OpFunction %void None %10 +%29 = OpLabel +%30 = OpLoad %v2float %i_vTextureCoords +%31 = OpAccessChain %_ptr_PushConstant_uint %_ %int_0 +%32 = OpLoad %uint %31 +%33 = OpAccessChain %_ptr_UniformConstant_16 %g_tColor %32 +%34 = OpLoad %16 %33 +%35 = OpLoad %24 %g_sAniso +%36 = OpSampledImage %26 %34 %35 +)"; + + const std::string func_pt2_before = + R"(%37 = OpImageSampleImplicitLod %v4float %36 %30 +OpStore %_entryPointOutput_vColor %37 +OpReturn +OpFunctionEnd +)"; + + const std::string func_pt2_after = + R"(%40 = OpULessThan %bool %32 %uint_128 +OpSelectionMerge %41 None +OpBranchConditional %40 %42 %43 +%42 = OpLabel +%44 = OpLoad %16 %33 +%45 = OpSampledImage %26 %44 %35 +%46 = OpImageSampleImplicitLod %v4float %45 %30 +OpBranch %41 +%43 = OpLabel +%102 = OpFunctionCall %void %47 %uint_56 %uint_0 %32 %uint_128 +OpBranch %41 +%41 = OpLabel +%104 = OpPhi %v4float %46 %42 %103 %43 +OpStore %_entryPointOutput_vColor %104 +OpReturn +OpFunctionEnd +)"; + + const std::string output_func = + R"(%47 = OpFunction %void None %48 +%49 = OpFunctionParameter %uint +%50 = OpFunctionParameter %uint +%51 = OpFunctionParameter %uint +%52 = OpFunctionParameter %uint +%53 = OpLabel +%59 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_0 +%62 = OpAtomicIAdd %uint %59 %uint_4 %uint_0 %uint_10 +%63 = OpIAdd %uint %62 %uint_10 +%64 = OpArrayLength %uint %57 1 +%65 = OpULessThanEqual %bool %63 %64 +OpSelectionMerge %66 None +OpBranchConditional %65 %67 %66 +%67 = OpLabel +%68 = OpIAdd %uint %62 %uint_0 +%70 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %68 +OpStore %70 %uint_10 +%72 = OpIAdd %uint %62 %uint_1 +%73 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %72 +OpStore %73 %uint_23 +%75 = OpIAdd %uint %62 %uint_2 +%76 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %75 +OpStore %76 %49 +%78 = OpIAdd %uint %62 %uint_3 +%79 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %78 +OpStore %79 %uint_4 +%82 = OpLoad %v4float %gl_FragCoord +%84 = OpBitcast %v4uint %82 +%85 = OpCompositeExtract %uint %84 0 +%86 = OpIAdd %uint %62 %uint_4 +%87 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %86 +OpStore %87 %85 +%88 = OpCompositeExtract %uint %84 1 +%90 = OpIAdd %uint %62 %uint_5 +%91 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %90 +OpStore %91 %88 +%93 = OpIAdd %uint %62 %uint_7 +%94 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %93 +OpStore %94 %50 +%96 = OpIAdd %uint %62 %uint_8 +%97 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %96 +OpStore %97 %51 +%99 = OpIAdd %uint %62 %uint_9 +%100 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %99 +OpStore %100 %52 +OpBranch %66 +%66 = OpLabel +OpReturn +OpFunctionEnd +)"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck( + entry_before + names_annots + consts_types_vars + func_pt1 + + func_pt2_before, + entry_after + names_annots + new_annots + consts_types_vars + + new_consts_types_vars + func_pt1 + func_pt2_after + output_func, + true, true, 7u, 23u, false, false); +} + +TEST_F(InstBindlessTest, InstrumentMultipleInstructions) { + // Texture2D g_tColor[128]; + // + // layout(push_constant) cbuffer PerViewConstantBuffer_t + // { + // uint g_nDataIdx; + // uint g_nDataIdx2; + // }; + // + // SamplerState g_sAniso; + // + // struct PS_INPUT + // { + // float2 vTextureCoords : TEXCOORD2; + // }; + // + // struct PS_OUTPUT + // { + // float4 vColor : SV_Target0; + // }; + // + // PS_OUTPUT MainPs(PS_INPUT i) + // { + // PS_OUTPUT ps_output; + // + // float t = g_tColor[g_nDataIdx ].Sample(g_sAniso, i.vTextureCoords.xy); + // float t2 = g_tColor[g_nDataIdx2].Sample(g_sAniso, i.vTextureCoords.xy); + // ps_output.vColor = t + t2; + // return ps_output; + // } + + const std::string defs_before = + R"(OpCapability Shader +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor +OpExecutionMode %MainPs OriginUpperLeft +OpSource HLSL 500 +OpName %MainPs "MainPs" +OpName %g_tColor "g_tColor" +OpName %PerViewConstantBuffer_t "PerViewConstantBuffer_t" +OpMemberName %PerViewConstantBuffer_t 0 "g_nDataIdx" +OpName %_ "" +OpName %g_sAniso "g_sAniso" +OpName %i_vTextureCoords "i.vTextureCoords" +OpName %_entryPointOutput_vColor "@entryPointOutput.vColor" +OpDecorate %g_tColor DescriptorSet 3 +OpDecorate %g_tColor Binding 0 +OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0 +OpMemberDecorate %PerViewConstantBuffer_t 1 Offset 4 +OpDecorate %PerViewConstantBuffer_t Block +OpDecorate %g_sAniso DescriptorSet 0 +OpDecorate %i_vTextureCoords Location 0 +OpDecorate %_entryPointOutput_vColor Location 0 +%void = OpTypeVoid +%10 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v2float = OpTypeVector %float 2 +%v4float = OpTypeVector %float 4 +%int = OpTypeInt 32 1 +%int_0 = OpConstant %int 0 +%int_1 = OpConstant %int 1 +%17 = OpTypeImage %float 2D 0 0 0 1 Unknown +%uint = OpTypeInt 32 0 +%uint_128 = OpConstant %uint 128 +%_arr_17_uint_128 = OpTypeArray %17 %uint_128 +%_ptr_UniformConstant__arr_17_uint_128 = OpTypePointer UniformConstant %_arr_17_uint_128 +%g_tColor = OpVariable %_ptr_UniformConstant__arr_17_uint_128 UniformConstant +%PerViewConstantBuffer_t = OpTypeStruct %uint %uint +%_ptr_PushConstant_PerViewConstantBuffer_t = OpTypePointer PushConstant %PerViewConstantBuffer_t +%_ = OpVariable %_ptr_PushConstant_PerViewConstantBuffer_t PushConstant +%_ptr_PushConstant_uint = OpTypePointer PushConstant %uint +%_ptr_UniformConstant_17 = OpTypePointer UniformConstant %17 +%25 = OpTypeSampler +%_ptr_UniformConstant_25 = OpTypePointer UniformConstant %25 +%g_sAniso = OpVariable %_ptr_UniformConstant_25 UniformConstant +%27 = OpTypeSampledImage %17 +%_ptr_Input_v2float = OpTypePointer Input %v2float +%i_vTextureCoords = OpVariable %_ptr_Input_v2float Input +%_ptr_Output_v4float = OpTypePointer Output %v4float +%_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output +)"; + + const std::string defs_after = + R"(OpCapability Shader +OpExtension "SPV_KHR_storage_buffer_storage_class" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord +OpExecutionMode %MainPs OriginUpperLeft +OpSource HLSL 500 +OpName %MainPs "MainPs" +OpName %g_tColor "g_tColor" +OpName %PerViewConstantBuffer_t "PerViewConstantBuffer_t" +OpMemberName %PerViewConstantBuffer_t 0 "g_nDataIdx" +OpName %_ "" +OpName %g_sAniso "g_sAniso" +OpName %i_vTextureCoords "i.vTextureCoords" +OpName %_entryPointOutput_vColor "@entryPointOutput.vColor" +OpDecorate %g_tColor DescriptorSet 3 +OpDecorate %g_tColor Binding 0 +OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0 +OpMemberDecorate %PerViewConstantBuffer_t 1 Offset 4 +OpDecorate %PerViewConstantBuffer_t Block +OpDecorate %g_sAniso DescriptorSet 0 +OpDecorate %i_vTextureCoords Location 0 +OpDecorate %_entryPointOutput_vColor Location 0 +OpDecorate %_runtimearr_uint ArrayStride 4 +OpDecorate %_struct_63 Block +OpMemberDecorate %_struct_63 0 Offset 0 +OpMemberDecorate %_struct_63 1 Offset 4 +OpDecorate %65 DescriptorSet 7 +OpDecorate %65 Binding 0 +OpDecorate %gl_FragCoord BuiltIn FragCoord +%void = OpTypeVoid +%10 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v2float = OpTypeVector %float 2 +%v4float = OpTypeVector %float 4 +%int = OpTypeInt 32 1 +%int_0 = OpConstant %int 0 +%int_1 = OpConstant %int 1 +%17 = OpTypeImage %float 2D 0 0 0 1 Unknown +%uint = OpTypeInt 32 0 +%uint_128 = OpConstant %uint 128 +%_arr_17_uint_128 = OpTypeArray %17 %uint_128 +%_ptr_UniformConstant__arr_17_uint_128 = OpTypePointer UniformConstant %_arr_17_uint_128 +%g_tColor = OpVariable %_ptr_UniformConstant__arr_17_uint_128 UniformConstant +%PerViewConstantBuffer_t = OpTypeStruct %uint %uint +%_ptr_PushConstant_PerViewConstantBuffer_t = OpTypePointer PushConstant %PerViewConstantBuffer_t +%_ = OpVariable %_ptr_PushConstant_PerViewConstantBuffer_t PushConstant +%_ptr_PushConstant_uint = OpTypePointer PushConstant %uint +%_ptr_UniformConstant_17 = OpTypePointer UniformConstant %17 +%25 = OpTypeSampler +%_ptr_UniformConstant_25 = OpTypePointer UniformConstant %25 +%g_sAniso = OpVariable %_ptr_UniformConstant_25 UniformConstant +%27 = OpTypeSampledImage %17 +%_ptr_Input_v2float = OpTypePointer Input %v2float +%i_vTextureCoords = OpVariable %_ptr_Input_v2float Input +%_ptr_Output_v4float = OpTypePointer Output %v4float +%_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output +%uint_0 = OpConstant %uint 0 +%bool = OpTypeBool +%56 = OpTypeFunction %void %uint %uint %uint %uint +%_runtimearr_uint = OpTypeRuntimeArray %uint +%_struct_63 = OpTypeStruct %uint %_runtimearr_uint +%_ptr_StorageBuffer__struct_63 = OpTypePointer StorageBuffer %_struct_63 +%65 = OpVariable %_ptr_StorageBuffer__struct_63 StorageBuffer +%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint +%uint_10 = OpConstant %uint 10 +%uint_4 = OpConstant %uint 4 +%uint_1 = OpConstant %uint 1 +%uint_23 = OpConstant %uint 23 +%uint_2 = OpConstant %uint 2 +%uint_3 = OpConstant %uint 3 +%_ptr_Input_v4float = OpTypePointer Input %v4float +%gl_FragCoord = OpVariable %_ptr_Input_v4float Input +%v4uint = OpTypeVector %uint 4 +%uint_5 = OpConstant %uint 5 +%uint_7 = OpConstant %uint 7 +%uint_8 = OpConstant %uint 8 +%uint_9 = OpConstant %uint 9 +%uint_58 = OpConstant %uint 58 +%111 = OpConstantNull %v4float +%uint_64 = OpConstant %uint 64 +)"; + + const std::string func_before = + R"(%MainPs = OpFunction %void None %10 +%30 = OpLabel +%31 = OpLoad %v2float %i_vTextureCoords +%32 = OpAccessChain %_ptr_PushConstant_uint %_ %int_0 +%33 = OpLoad %uint %32 +%34 = OpAccessChain %_ptr_UniformConstant_17 %g_tColor %33 +%35 = OpLoad %17 %34 +%36 = OpLoad %25 %g_sAniso +%37 = OpSampledImage %27 %35 %36 +%38 = OpImageSampleImplicitLod %v4float %37 %31 +%39 = OpAccessChain %_ptr_PushConstant_uint %_ %int_1 +%40 = OpLoad %uint %39 +%41 = OpAccessChain %_ptr_UniformConstant_17 %g_tColor %40 +%42 = OpLoad %17 %41 +%43 = OpSampledImage %27 %42 %36 +%44 = OpImageSampleImplicitLod %v4float %43 %31 +%45 = OpFAdd %v4float %38 %44 +OpStore %_entryPointOutput_vColor %45 +OpReturn +OpFunctionEnd +)"; + + const std::string func_after = + R"(%MainPs = OpFunction %void None %10 +%30 = OpLabel +%31 = OpLoad %v2float %i_vTextureCoords +%32 = OpAccessChain %_ptr_PushConstant_uint %_ %int_0 +%33 = OpLoad %uint %32 +%34 = OpAccessChain %_ptr_UniformConstant_17 %g_tColor %33 +%35 = OpLoad %17 %34 +%36 = OpLoad %25 %g_sAniso +%37 = OpSampledImage %27 %35 %36 +%48 = OpULessThan %bool %33 %uint_128 +OpSelectionMerge %49 None +OpBranchConditional %48 %50 %51 +%50 = OpLabel +%52 = OpLoad %17 %34 +%53 = OpSampledImage %27 %52 %36 +%54 = OpImageSampleImplicitLod %v4float %53 %31 +OpBranch %49 +%51 = OpLabel +%110 = OpFunctionCall %void %55 %uint_58 %uint_0 %33 %uint_128 +OpBranch %49 +%49 = OpLabel +%112 = OpPhi %v4float %54 %50 %111 %51 +%39 = OpAccessChain %_ptr_PushConstant_uint %_ %int_1 +%40 = OpLoad %uint %39 +%41 = OpAccessChain %_ptr_UniformConstant_17 %g_tColor %40 +%42 = OpLoad %17 %41 +%43 = OpSampledImage %27 %42 %36 +%113 = OpULessThan %bool %40 %uint_128 +OpSelectionMerge %114 None +OpBranchConditional %113 %115 %116 +%115 = OpLabel +%117 = OpLoad %17 %41 +%118 = OpSampledImage %27 %117 %36 +%119 = OpImageSampleImplicitLod %v4float %118 %31 +OpBranch %114 +%116 = OpLabel +%121 = OpFunctionCall %void %55 %uint_64 %uint_0 %40 %uint_128 +OpBranch %114 +%114 = OpLabel +%122 = OpPhi %v4float %119 %115 %111 %116 +%45 = OpFAdd %v4float %112 %122 +OpStore %_entryPointOutput_vColor %45 +OpReturn +OpFunctionEnd +)"; + + const std::string output_func = + R"(%55 = OpFunction %void None %56 +%57 = OpFunctionParameter %uint +%58 = OpFunctionParameter %uint +%59 = OpFunctionParameter %uint +%60 = OpFunctionParameter %uint +%61 = OpLabel +%67 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_0 +%70 = OpAtomicIAdd %uint %67 %uint_4 %uint_0 %uint_10 +%71 = OpIAdd %uint %70 %uint_10 +%72 = OpArrayLength %uint %65 1 +%73 = OpULessThanEqual %bool %71 %72 +OpSelectionMerge %74 None +OpBranchConditional %73 %75 %74 +%75 = OpLabel +%76 = OpIAdd %uint %70 %uint_0 +%78 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %76 +OpStore %78 %uint_10 +%80 = OpIAdd %uint %70 %uint_1 +%81 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %80 +OpStore %81 %uint_23 +%83 = OpIAdd %uint %70 %uint_2 +%84 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %83 +OpStore %84 %57 +%86 = OpIAdd %uint %70 %uint_3 +%87 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %86 +OpStore %87 %uint_4 +%90 = OpLoad %v4float %gl_FragCoord +%92 = OpBitcast %v4uint %90 +%93 = OpCompositeExtract %uint %92 0 +%94 = OpIAdd %uint %70 %uint_4 +%95 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %94 +OpStore %95 %93 +%96 = OpCompositeExtract %uint %92 1 +%98 = OpIAdd %uint %70 %uint_5 +%99 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %98 +OpStore %99 %96 +%101 = OpIAdd %uint %70 %uint_7 +%102 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %101 +OpStore %102 %58 +%104 = OpIAdd %uint %70 %uint_8 +%105 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %104 +OpStore %105 %59 +%107 = OpIAdd %uint %70 %uint_9 +%108 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %107 +OpStore %108 %60 +OpBranch %74 +%74 = OpLabel +OpReturn +OpFunctionEnd +)"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck( + defs_before + func_before, defs_after + func_after + output_func, true, + true, 7u, 23u, false, false); +} + +TEST_F(InstBindlessTest, InstrumentOpImage) { + // This test verifies that the pass will correctly instrument shader + // using OpImage. This test was created by editing the SPIR-V + // from the Simple test. + + const std::string defs_before = + R"(OpCapability Shader +OpCapability StorageImageReadWithoutFormat +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor +OpExecutionMode %MainPs OriginUpperLeft +OpSource HLSL 500 +OpName %MainPs "MainPs" +OpName %g_tColor "g_tColor" +OpName %PerViewConstantBuffer_t "PerViewConstantBuffer_t" +OpMemberName %PerViewConstantBuffer_t 0 "g_nDataIdx" +OpName %_ "" +OpName %i_vTextureCoords "i.vTextureCoords" +OpName %_entryPointOutput_vColor "@entryPointOutput.vColor" +OpDecorate %g_tColor DescriptorSet 3 +OpDecorate %g_tColor Binding 0 +OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0 +OpDecorate %PerViewConstantBuffer_t Block +OpDecorate %i_vTextureCoords Location 0 +OpDecorate %_entryPointOutput_vColor Location 0 +%void = OpTypeVoid +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v4float = OpTypeVector %float 4 +%int = OpTypeInt 32 1 +%v2int = OpTypeVector %int 2 +%int_0 = OpConstant %int 0 +%20 = OpTypeImage %float 2D 0 0 0 0 Unknown +%uint = OpTypeInt 32 0 +%uint_128 = OpConstant %uint 128 +%39 = OpTypeSampledImage %20 +%_arr_39_uint_128 = OpTypeArray %39 %uint_128 +%_ptr_UniformConstant__arr_39_uint_128 = OpTypePointer UniformConstant %_arr_39_uint_128 +%g_tColor = OpVariable %_ptr_UniformConstant__arr_39_uint_128 UniformConstant +%PerViewConstantBuffer_t = OpTypeStruct %uint +%_ptr_PushConstant_PerViewConstantBuffer_t = OpTypePointer PushConstant %PerViewConstantBuffer_t +%_ = OpVariable %_ptr_PushConstant_PerViewConstantBuffer_t PushConstant +%_ptr_PushConstant_uint = OpTypePointer PushConstant %uint +%_ptr_UniformConstant_39 = OpTypePointer UniformConstant %39 +%_ptr_Input_v2int = OpTypePointer Input %v2int +%i_vTextureCoords = OpVariable %_ptr_Input_v2int Input +%_ptr_Output_v4float = OpTypePointer Output %v4float +%_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output +)"; + + const std::string defs_after = + R"(OpCapability Shader +OpCapability StorageImageReadWithoutFormat +OpExtension "SPV_KHR_storage_buffer_storage_class" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord +OpExecutionMode %MainPs OriginUpperLeft +OpSource HLSL 500 +OpName %MainPs "MainPs" +OpName %g_tColor "g_tColor" +OpName %PerViewConstantBuffer_t "PerViewConstantBuffer_t" +OpMemberName %PerViewConstantBuffer_t 0 "g_nDataIdx" +OpName %_ "" +OpName %i_vTextureCoords "i.vTextureCoords" +OpName %_entryPointOutput_vColor "@entryPointOutput.vColor" +OpDecorate %g_tColor DescriptorSet 3 +OpDecorate %g_tColor Binding 0 +OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0 +OpDecorate %PerViewConstantBuffer_t Block +OpDecorate %i_vTextureCoords Location 0 +OpDecorate %_entryPointOutput_vColor Location 0 +OpDecorate %_runtimearr_uint ArrayStride 4 +OpDecorate %_struct_51 Block +OpMemberDecorate %_struct_51 0 Offset 0 +OpMemberDecorate %_struct_51 1 Offset 4 +OpDecorate %53 DescriptorSet 7 +OpDecorate %53 Binding 0 +OpDecorate %gl_FragCoord BuiltIn FragCoord +%void = OpTypeVoid +%9 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v4float = OpTypeVector %float 4 +%int = OpTypeInt 32 1 +%v2int = OpTypeVector %int 2 +%int_0 = OpConstant %int 0 +%15 = OpTypeImage %float 2D 0 0 0 0 Unknown +%uint = OpTypeInt 32 0 +%uint_128 = OpConstant %uint 128 +%18 = OpTypeSampledImage %15 +%_arr_18_uint_128 = OpTypeArray %18 %uint_128 +%_ptr_UniformConstant__arr_18_uint_128 = OpTypePointer UniformConstant %_arr_18_uint_128 +%g_tColor = OpVariable %_ptr_UniformConstant__arr_18_uint_128 UniformConstant +%PerViewConstantBuffer_t = OpTypeStruct %uint +%_ptr_PushConstant_PerViewConstantBuffer_t = OpTypePointer PushConstant %PerViewConstantBuffer_t +%_ = OpVariable %_ptr_PushConstant_PerViewConstantBuffer_t PushConstant +%_ptr_PushConstant_uint = OpTypePointer PushConstant %uint +%_ptr_UniformConstant_18 = OpTypePointer UniformConstant %18 +%_ptr_Input_v2int = OpTypePointer Input %v2int +%i_vTextureCoords = OpVariable %_ptr_Input_v2int Input +%_ptr_Output_v4float = OpTypePointer Output %v4float +%_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output +%uint_0 = OpConstant %uint 0 +%bool = OpTypeBool +%44 = OpTypeFunction %void %uint %uint %uint %uint +%_runtimearr_uint = OpTypeRuntimeArray %uint +%_struct_51 = OpTypeStruct %uint %_runtimearr_uint +%_ptr_StorageBuffer__struct_51 = OpTypePointer StorageBuffer %_struct_51 +%53 = OpVariable %_ptr_StorageBuffer__struct_51 StorageBuffer +%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint +%uint_10 = OpConstant %uint 10 +%uint_4 = OpConstant %uint 4 +%uint_1 = OpConstant %uint 1 +%uint_23 = OpConstant %uint 23 +%uint_2 = OpConstant %uint 2 +%uint_3 = OpConstant %uint 3 +%_ptr_Input_v4float = OpTypePointer Input %v4float +%gl_FragCoord = OpVariable %_ptr_Input_v4float Input +%v4uint = OpTypeVector %uint 4 +%uint_5 = OpConstant %uint 5 +%uint_7 = OpConstant %uint 7 +%uint_8 = OpConstant %uint 8 +%uint_9 = OpConstant %uint 9 +%uint_51 = OpConstant %uint 51 +%99 = OpConstantNull %v4float +)"; + + const std::string func_before = + R"(%MainPs = OpFunction %void None %3 +%5 = OpLabel +%53 = OpLoad %v2int %i_vTextureCoords +%63 = OpAccessChain %_ptr_PushConstant_uint %_ %int_0 +%64 = OpLoad %uint %63 +%65 = OpAccessChain %_ptr_UniformConstant_39 %g_tColor %64 +%66 = OpLoad %39 %65 +%75 = OpImage %20 %66 +%71 = OpImageRead %v4float %75 %53 +OpStore %_entryPointOutput_vColor %71 +OpReturn +OpFunctionEnd +)"; + + const std::string func_after = + R"(%MainPs = OpFunction %void None %9 +%26 = OpLabel +%27 = OpLoad %v2int %i_vTextureCoords +%28 = OpAccessChain %_ptr_PushConstant_uint %_ %int_0 +%29 = OpLoad %uint %28 +%30 = OpAccessChain %_ptr_UniformConstant_18 %g_tColor %29 +%31 = OpLoad %18 %30 +%32 = OpImage %15 %31 +%36 = OpULessThan %bool %29 %uint_128 +OpSelectionMerge %37 None +OpBranchConditional %36 %38 %39 +%38 = OpLabel +%40 = OpLoad %18 %30 +%41 = OpImage %15 %40 +%42 = OpImageRead %v4float %41 %27 +OpBranch %37 +%39 = OpLabel +%98 = OpFunctionCall %void %43 %uint_51 %uint_0 %29 %uint_128 +OpBranch %37 +%37 = OpLabel +%100 = OpPhi %v4float %42 %38 %99 %39 +OpStore %_entryPointOutput_vColor %100 +OpReturn +OpFunctionEnd +)"; + + const std::string output_func = + R"(%43 = OpFunction %void None %44 +%45 = OpFunctionParameter %uint +%46 = OpFunctionParameter %uint +%47 = OpFunctionParameter %uint +%48 = OpFunctionParameter %uint +%49 = OpLabel +%55 = OpAccessChain %_ptr_StorageBuffer_uint %53 %uint_0 +%58 = OpAtomicIAdd %uint %55 %uint_4 %uint_0 %uint_10 +%59 = OpIAdd %uint %58 %uint_10 +%60 = OpArrayLength %uint %53 1 +%61 = OpULessThanEqual %bool %59 %60 +OpSelectionMerge %62 None +OpBranchConditional %61 %63 %62 +%63 = OpLabel +%64 = OpIAdd %uint %58 %uint_0 +%66 = OpAccessChain %_ptr_StorageBuffer_uint %53 %uint_1 %64 +OpStore %66 %uint_10 +%68 = OpIAdd %uint %58 %uint_1 +%69 = OpAccessChain %_ptr_StorageBuffer_uint %53 %uint_1 %68 +OpStore %69 %uint_23 +%71 = OpIAdd %uint %58 %uint_2 +%72 = OpAccessChain %_ptr_StorageBuffer_uint %53 %uint_1 %71 +OpStore %72 %45 +%74 = OpIAdd %uint %58 %uint_3 +%75 = OpAccessChain %_ptr_StorageBuffer_uint %53 %uint_1 %74 +OpStore %75 %uint_4 +%78 = OpLoad %v4float %gl_FragCoord +%80 = OpBitcast %v4uint %78 +%81 = OpCompositeExtract %uint %80 0 +%82 = OpIAdd %uint %58 %uint_4 +%83 = OpAccessChain %_ptr_StorageBuffer_uint %53 %uint_1 %82 +OpStore %83 %81 +%84 = OpCompositeExtract %uint %80 1 +%86 = OpIAdd %uint %58 %uint_5 +%87 = OpAccessChain %_ptr_StorageBuffer_uint %53 %uint_1 %86 +OpStore %87 %84 +%89 = OpIAdd %uint %58 %uint_7 +%90 = OpAccessChain %_ptr_StorageBuffer_uint %53 %uint_1 %89 +OpStore %90 %46 +%92 = OpIAdd %uint %58 %uint_8 +%93 = OpAccessChain %_ptr_StorageBuffer_uint %53 %uint_1 %92 +OpStore %93 %47 +%95 = OpIAdd %uint %58 %uint_9 +%96 = OpAccessChain %_ptr_StorageBuffer_uint %53 %uint_1 %95 +OpStore %96 %48 +OpBranch %62 +%62 = OpLabel +OpReturn +OpFunctionEnd +)"; + + // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck( + defs_before + func_before, defs_after + func_after + output_func, true, + true, 7u, 23u, false, false); +} + +TEST_F(InstBindlessTest, InstrumentSampledImage) { + // This test verifies that the pass will correctly instrument shader + // using sampled image. This test was created by editing the SPIR-V + // from the Simple test. + + const std::string defs_before = + R"(OpCapability Shader +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor +OpExecutionMode %MainPs OriginUpperLeft +OpSource HLSL 500 +OpName %MainPs "MainPs" +OpName %g_tColor "g_tColor" +OpName %PerViewConstantBuffer_t "PerViewConstantBuffer_t" +OpMemberName %PerViewConstantBuffer_t 0 "g_nDataIdx" +OpName %_ "" +OpName %i_vTextureCoords "i.vTextureCoords" +OpName %_entryPointOutput_vColor "@entryPointOutput.vColor" +OpDecorate %g_tColor DescriptorSet 3 +OpDecorate %g_tColor Binding 0 +OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0 +OpDecorate %PerViewConstantBuffer_t Block +OpDecorate %i_vTextureCoords Location 0 +OpDecorate %_entryPointOutput_vColor Location 0 +%void = OpTypeVoid +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v2float = OpTypeVector %float 2 +%v4float = OpTypeVector %float 4 +%int = OpTypeInt 32 1 +%int_0 = OpConstant %int 0 +%20 = OpTypeImage %float 2D 0 0 0 1 Unknown +%uint = OpTypeInt 32 0 +%uint_128 = OpConstant %uint 128 +%39 = OpTypeSampledImage %20 +%_arr_39_uint_128 = OpTypeArray %39 %uint_128 +%_ptr_UniformConstant__arr_39_uint_128 = OpTypePointer UniformConstant %_arr_39_uint_128 +%g_tColor = OpVariable %_ptr_UniformConstant__arr_39_uint_128 UniformConstant +%PerViewConstantBuffer_t = OpTypeStruct %uint +%_ptr_PushConstant_PerViewConstantBuffer_t = OpTypePointer PushConstant %PerViewConstantBuffer_t +%_ = OpVariable %_ptr_PushConstant_PerViewConstantBuffer_t PushConstant +%_ptr_PushConstant_uint = OpTypePointer PushConstant %uint +%_ptr_UniformConstant_39 = OpTypePointer UniformConstant %39 +%_ptr_Input_v2float = OpTypePointer Input %v2float +%i_vTextureCoords = OpVariable %_ptr_Input_v2float Input +%_ptr_Output_v4float = OpTypePointer Output %v4float +%_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output +)"; + + const std::string defs_after = + R"(OpCapability Shader +OpExtension "SPV_KHR_storage_buffer_storage_class" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord +OpExecutionMode %MainPs OriginUpperLeft +OpSource HLSL 500 +OpName %MainPs "MainPs" +OpName %g_tColor "g_tColor" +OpName %PerViewConstantBuffer_t "PerViewConstantBuffer_t" +OpMemberName %PerViewConstantBuffer_t 0 "g_nDataIdx" +OpName %_ "" +OpName %i_vTextureCoords "i.vTextureCoords" +OpName %_entryPointOutput_vColor "@entryPointOutput.vColor" +OpDecorate %g_tColor DescriptorSet 3 +OpDecorate %g_tColor Binding 0 +OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0 +OpDecorate %PerViewConstantBuffer_t Block +OpDecorate %i_vTextureCoords Location 0 +OpDecorate %_entryPointOutput_vColor Location 0 +OpDecorate %_runtimearr_uint ArrayStride 4 +OpDecorate %_struct_49 Block +OpMemberDecorate %_struct_49 0 Offset 0 +OpMemberDecorate %_struct_49 1 Offset 4 +OpDecorate %51 DescriptorSet 7 +OpDecorate %51 Binding 0 +OpDecorate %gl_FragCoord BuiltIn FragCoord +%void = OpTypeVoid +%9 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v2float = OpTypeVector %float 2 +%v4float = OpTypeVector %float 4 +%int = OpTypeInt 32 1 +%int_0 = OpConstant %int 0 +%15 = OpTypeImage %float 2D 0 0 0 1 Unknown +%uint = OpTypeInt 32 0 +%uint_128 = OpConstant %uint 128 +%18 = OpTypeSampledImage %15 +%_arr_18_uint_128 = OpTypeArray %18 %uint_128 +%_ptr_UniformConstant__arr_18_uint_128 = OpTypePointer UniformConstant %_arr_18_uint_128 +%g_tColor = OpVariable %_ptr_UniformConstant__arr_18_uint_128 UniformConstant +%PerViewConstantBuffer_t = OpTypeStruct %uint +%_ptr_PushConstant_PerViewConstantBuffer_t = OpTypePointer PushConstant %PerViewConstantBuffer_t +%_ = OpVariable %_ptr_PushConstant_PerViewConstantBuffer_t PushConstant +%_ptr_PushConstant_uint = OpTypePointer PushConstant %uint +%_ptr_UniformConstant_18 = OpTypePointer UniformConstant %18 +%_ptr_Input_v2float = OpTypePointer Input %v2float +%i_vTextureCoords = OpVariable %_ptr_Input_v2float Input +%_ptr_Output_v4float = OpTypePointer Output %v4float +%_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output +%uint_0 = OpConstant %uint 0 +%bool = OpTypeBool +%42 = OpTypeFunction %void %uint %uint %uint %uint +%_runtimearr_uint = OpTypeRuntimeArray %uint +%_struct_49 = OpTypeStruct %uint %_runtimearr_uint +%_ptr_StorageBuffer__struct_49 = OpTypePointer StorageBuffer %_struct_49 +%51 = OpVariable %_ptr_StorageBuffer__struct_49 StorageBuffer +%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint +%uint_10 = OpConstant %uint 10 +%uint_4 = OpConstant %uint 4 +%uint_1 = OpConstant %uint 1 +%uint_23 = OpConstant %uint 23 +%uint_2 = OpConstant %uint 2 +%uint_3 = OpConstant %uint 3 +%_ptr_Input_v4float = OpTypePointer Input %v4float +%gl_FragCoord = OpVariable %_ptr_Input_v4float Input +%v4uint = OpTypeVector %uint 4 +%uint_5 = OpConstant %uint 5 +%uint_7 = OpConstant %uint 7 +%uint_8 = OpConstant %uint 8 +%uint_9 = OpConstant %uint 9 +%uint_49 = OpConstant %uint 49 +%97 = OpConstantNull %v4float +)"; + + const std::string func_before = + R"(%MainPs = OpFunction %void None %3 +%5 = OpLabel +%53 = OpLoad %v2float %i_vTextureCoords +%63 = OpAccessChain %_ptr_PushConstant_uint %_ %int_0 +%64 = OpLoad %uint %63 +%65 = OpAccessChain %_ptr_UniformConstant_39 %g_tColor %64 +%66 = OpLoad %39 %65 +%71 = OpImageSampleImplicitLod %v4float %66 %53 +OpStore %_entryPointOutput_vColor %71 +OpReturn +OpFunctionEnd +)"; + + const std::string func_after = + R"(%MainPs = OpFunction %void None %9 +%26 = OpLabel +%27 = OpLoad %v2float %i_vTextureCoords +%28 = OpAccessChain %_ptr_PushConstant_uint %_ %int_0 +%29 = OpLoad %uint %28 +%30 = OpAccessChain %_ptr_UniformConstant_18 %g_tColor %29 +%31 = OpLoad %18 %30 +%35 = OpULessThan %bool %29 %uint_128 +OpSelectionMerge %36 None +OpBranchConditional %35 %37 %38 +%37 = OpLabel +%39 = OpLoad %18 %30 +%40 = OpImageSampleImplicitLod %v4float %39 %27 +OpBranch %36 +%38 = OpLabel +%96 = OpFunctionCall %void %41 %uint_49 %uint_0 %29 %uint_128 +OpBranch %36 +%36 = OpLabel +%98 = OpPhi %v4float %40 %37 %97 %38 +OpStore %_entryPointOutput_vColor %98 +OpReturn +OpFunctionEnd +)"; + + const std::string output_func = + R"(%41 = OpFunction %void None %42 +%43 = OpFunctionParameter %uint +%44 = OpFunctionParameter %uint +%45 = OpFunctionParameter %uint +%46 = OpFunctionParameter %uint +%47 = OpLabel +%53 = OpAccessChain %_ptr_StorageBuffer_uint %51 %uint_0 +%56 = OpAtomicIAdd %uint %53 %uint_4 %uint_0 %uint_10 +%57 = OpIAdd %uint %56 %uint_10 +%58 = OpArrayLength %uint %51 1 +%59 = OpULessThanEqual %bool %57 %58 +OpSelectionMerge %60 None +OpBranchConditional %59 %61 %60 +%61 = OpLabel +%62 = OpIAdd %uint %56 %uint_0 +%64 = OpAccessChain %_ptr_StorageBuffer_uint %51 %uint_1 %62 +OpStore %64 %uint_10 +%66 = OpIAdd %uint %56 %uint_1 +%67 = OpAccessChain %_ptr_StorageBuffer_uint %51 %uint_1 %66 +OpStore %67 %uint_23 +%69 = OpIAdd %uint %56 %uint_2 +%70 = OpAccessChain %_ptr_StorageBuffer_uint %51 %uint_1 %69 +OpStore %70 %43 +%72 = OpIAdd %uint %56 %uint_3 +%73 = OpAccessChain %_ptr_StorageBuffer_uint %51 %uint_1 %72 +OpStore %73 %uint_4 +%76 = OpLoad %v4float %gl_FragCoord +%78 = OpBitcast %v4uint %76 +%79 = OpCompositeExtract %uint %78 0 +%80 = OpIAdd %uint %56 %uint_4 +%81 = OpAccessChain %_ptr_StorageBuffer_uint %51 %uint_1 %80 +OpStore %81 %79 +%82 = OpCompositeExtract %uint %78 1 +%84 = OpIAdd %uint %56 %uint_5 +%85 = OpAccessChain %_ptr_StorageBuffer_uint %51 %uint_1 %84 +OpStore %85 %82 +%87 = OpIAdd %uint %56 %uint_7 +%88 = OpAccessChain %_ptr_StorageBuffer_uint %51 %uint_1 %87 +OpStore %88 %44 +%90 = OpIAdd %uint %56 %uint_8 +%91 = OpAccessChain %_ptr_StorageBuffer_uint %51 %uint_1 %90 +OpStore %91 %45 +%93 = OpIAdd %uint %56 %uint_9 +%94 = OpAccessChain %_ptr_StorageBuffer_uint %51 %uint_1 %93 +OpStore %94 %46 +OpBranch %60 +%60 = OpLabel +OpReturn +OpFunctionEnd +)"; + + // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck( + defs_before + func_before, defs_after + func_after + output_func, true, + true, 7u, 23u, false, false); +} + +TEST_F(InstBindlessTest, InstrumentImageWrite) { + // This test verifies that the pass will correctly instrument shader + // doing bindless image write. This test was created by editing the SPIR-V + // from the Simple test. + + const std::string defs_before = + R"(OpCapability Shader +OpCapability StorageImageWriteWithoutFormat +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor +OpExecutionMode %MainPs OriginUpperLeft +OpSource HLSL 500 +OpName %MainPs "MainPs" +OpName %g_tColor "g_tColor" +OpName %PerViewConstantBuffer_t "PerViewConstantBuffer_t" +OpMemberName %PerViewConstantBuffer_t 0 "g_nDataIdx" +OpName %_ "" +OpName %i_vTextureCoords "i.vTextureCoords" +OpName %_entryPointOutput_vColor "@entryPointOutput.vColor" +OpDecorate %g_tColor DescriptorSet 3 +OpDecorate %g_tColor Binding 0 +OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0 +OpDecorate %PerViewConstantBuffer_t Block +OpDecorate %i_vTextureCoords Location 0 +OpDecorate %_entryPointOutput_vColor Location 0 +%void = OpTypeVoid +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v2float = OpTypeVector %float 2 +%v4float = OpTypeVector %float 4 +%int = OpTypeInt 32 1 +%v2int = OpTypeVector %int 2 +%int_0 = OpConstant %int 0 +%20 = OpTypeImage %float 2D 0 0 0 0 Unknown +%uint = OpTypeInt 32 0 +%uint_128 = OpConstant %uint 128 +%80 = OpConstantNull %v4float +%_arr_20_uint_128 = OpTypeArray %20 %uint_128 +%_ptr_UniformConstant__arr_20_uint_128 = OpTypePointer UniformConstant %_arr_20_uint_128 +%g_tColor = OpVariable %_ptr_UniformConstant__arr_20_uint_128 UniformConstant +%PerViewConstantBuffer_t = OpTypeStruct %uint +%_ptr_PushConstant_PerViewConstantBuffer_t = OpTypePointer PushConstant %PerViewConstantBuffer_t +%_ = OpVariable %_ptr_PushConstant_PerViewConstantBuffer_t PushConstant +%_ptr_PushConstant_uint = OpTypePointer PushConstant %uint +%_ptr_UniformConstant_20 = OpTypePointer UniformConstant %20 +%_ptr_Input_v2int = OpTypePointer Input %v2int +%i_vTextureCoords = OpVariable %_ptr_Input_v2int Input +%_ptr_Output_v4float = OpTypePointer Output %v4float +%_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output +)"; + + const std::string defs_after = + R"(OpCapability Shader +OpCapability StorageImageWriteWithoutFormat +OpExtension "SPV_KHR_storage_buffer_storage_class" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord +OpExecutionMode %MainPs OriginUpperLeft +OpSource HLSL 500 +OpName %MainPs "MainPs" +OpName %g_tColor "g_tColor" +OpName %PerViewConstantBuffer_t "PerViewConstantBuffer_t" +OpMemberName %PerViewConstantBuffer_t 0 "g_nDataIdx" +OpName %_ "" +OpName %i_vTextureCoords "i.vTextureCoords" +OpName %_entryPointOutput_vColor "@entryPointOutput.vColor" +OpDecorate %g_tColor DescriptorSet 3 +OpDecorate %g_tColor Binding 0 +OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0 +OpDecorate %PerViewConstantBuffer_t Block +OpDecorate %i_vTextureCoords Location 0 +OpDecorate %_entryPointOutput_vColor Location 0 +OpDecorate %_runtimearr_uint ArrayStride 4 +OpDecorate %_struct_48 Block +OpMemberDecorate %_struct_48 0 Offset 0 +OpMemberDecorate %_struct_48 1 Offset 4 +OpDecorate %50 DescriptorSet 7 +OpDecorate %50 Binding 0 +OpDecorate %gl_FragCoord BuiltIn FragCoord +%void = OpTypeVoid +%9 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v2float = OpTypeVector %float 2 +%v4float = OpTypeVector %float 4 +%int = OpTypeInt 32 1 +%v2int = OpTypeVector %int 2 +%int_0 = OpConstant %int 0 +%16 = OpTypeImage %float 2D 0 0 0 0 Unknown +%uint = OpTypeInt 32 0 +%uint_128 = OpConstant %uint 128 +%19 = OpConstantNull %v4float +%_arr_16_uint_128 = OpTypeArray %16 %uint_128 +%_ptr_UniformConstant__arr_16_uint_128 = OpTypePointer UniformConstant %_arr_16_uint_128 +%g_tColor = OpVariable %_ptr_UniformConstant__arr_16_uint_128 UniformConstant +%PerViewConstantBuffer_t = OpTypeStruct %uint +%_ptr_PushConstant_PerViewConstantBuffer_t = OpTypePointer PushConstant %PerViewConstantBuffer_t +%_ = OpVariable %_ptr_PushConstant_PerViewConstantBuffer_t PushConstant +%_ptr_PushConstant_uint = OpTypePointer PushConstant %uint +%_ptr_UniformConstant_16 = OpTypePointer UniformConstant %16 +%_ptr_Input_v2int = OpTypePointer Input %v2int +%i_vTextureCoords = OpVariable %_ptr_Input_v2int Input +%_ptr_Output_v4float = OpTypePointer Output %v4float +%_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output +%uint_0 = OpConstant %uint 0 +%bool = OpTypeBool +%41 = OpTypeFunction %void %uint %uint %uint %uint +%_runtimearr_uint = OpTypeRuntimeArray %uint +%_struct_48 = OpTypeStruct %uint %_runtimearr_uint +%_ptr_StorageBuffer__struct_48 = OpTypePointer StorageBuffer %_struct_48 +%50 = OpVariable %_ptr_StorageBuffer__struct_48 StorageBuffer +%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint +%uint_10 = OpConstant %uint 10 +%uint_4 = OpConstant %uint 4 +%uint_1 = OpConstant %uint 1 +%uint_23 = OpConstant %uint 23 +%uint_2 = OpConstant %uint 2 +%uint_3 = OpConstant %uint 3 +%_ptr_Input_v4float = OpTypePointer Input %v4float +%gl_FragCoord = OpVariable %_ptr_Input_v4float Input +%v4uint = OpTypeVector %uint 4 +%uint_5 = OpConstant %uint 5 +%uint_7 = OpConstant %uint 7 +%uint_8 = OpConstant %uint 8 +%uint_9 = OpConstant %uint 9 +%uint_51 = OpConstant %uint 51 +)"; + + const std::string func_before = + R"(%MainPs = OpFunction %void None %3 +%5 = OpLabel +%53 = OpLoad %v2int %i_vTextureCoords +%63 = OpAccessChain %_ptr_PushConstant_uint %_ %int_0 +%64 = OpLoad %uint %63 +%65 = OpAccessChain %_ptr_UniformConstant_20 %g_tColor %64 +%66 = OpLoad %20 %65 +OpImageWrite %66 %53 %80 +OpStore %_entryPointOutput_vColor %80 +OpReturn +OpFunctionEnd +)"; + + const std::string func_after = + R"(%MainPs = OpFunction %void None %9 +%27 = OpLabel +%28 = OpLoad %v2int %i_vTextureCoords +%29 = OpAccessChain %_ptr_PushConstant_uint %_ %int_0 +%30 = OpLoad %uint %29 +%31 = OpAccessChain %_ptr_UniformConstant_16 %g_tColor %30 +%32 = OpLoad %16 %31 +%35 = OpULessThan %bool %30 %uint_128 +OpSelectionMerge %36 None +OpBranchConditional %35 %37 %38 +%37 = OpLabel +%39 = OpLoad %16 %31 +OpImageWrite %39 %28 %19 +OpBranch %36 +%38 = OpLabel +%95 = OpFunctionCall %void %40 %uint_51 %uint_0 %30 %uint_128 +OpBranch %36 +%36 = OpLabel +OpStore %_entryPointOutput_vColor %19 +OpReturn +OpFunctionEnd +)"; + + const std::string output_func = + R"(%40 = OpFunction %void None %41 +%42 = OpFunctionParameter %uint +%43 = OpFunctionParameter %uint +%44 = OpFunctionParameter %uint +%45 = OpFunctionParameter %uint +%46 = OpLabel +%52 = OpAccessChain %_ptr_StorageBuffer_uint %50 %uint_0 +%55 = OpAtomicIAdd %uint %52 %uint_4 %uint_0 %uint_10 +%56 = OpIAdd %uint %55 %uint_10 +%57 = OpArrayLength %uint %50 1 +%58 = OpULessThanEqual %bool %56 %57 +OpSelectionMerge %59 None +OpBranchConditional %58 %60 %59 +%60 = OpLabel +%61 = OpIAdd %uint %55 %uint_0 +%63 = OpAccessChain %_ptr_StorageBuffer_uint %50 %uint_1 %61 +OpStore %63 %uint_10 +%65 = OpIAdd %uint %55 %uint_1 +%66 = OpAccessChain %_ptr_StorageBuffer_uint %50 %uint_1 %65 +OpStore %66 %uint_23 +%68 = OpIAdd %uint %55 %uint_2 +%69 = OpAccessChain %_ptr_StorageBuffer_uint %50 %uint_1 %68 +OpStore %69 %42 +%71 = OpIAdd %uint %55 %uint_3 +%72 = OpAccessChain %_ptr_StorageBuffer_uint %50 %uint_1 %71 +OpStore %72 %uint_4 +%75 = OpLoad %v4float %gl_FragCoord +%77 = OpBitcast %v4uint %75 +%78 = OpCompositeExtract %uint %77 0 +%79 = OpIAdd %uint %55 %uint_4 +%80 = OpAccessChain %_ptr_StorageBuffer_uint %50 %uint_1 %79 +OpStore %80 %78 +%81 = OpCompositeExtract %uint %77 1 +%83 = OpIAdd %uint %55 %uint_5 +%84 = OpAccessChain %_ptr_StorageBuffer_uint %50 %uint_1 %83 +OpStore %84 %81 +%86 = OpIAdd %uint %55 %uint_7 +%87 = OpAccessChain %_ptr_StorageBuffer_uint %50 %uint_1 %86 +OpStore %87 %43 +%89 = OpIAdd %uint %55 %uint_8 +%90 = OpAccessChain %_ptr_StorageBuffer_uint %50 %uint_1 %89 +OpStore %90 %44 +%92 = OpIAdd %uint %55 %uint_9 +%93 = OpAccessChain %_ptr_StorageBuffer_uint %50 %uint_1 %92 +OpStore %93 %45 +OpBranch %59 +%59 = OpLabel +OpReturn +OpFunctionEnd +)"; + + // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck( + defs_before + func_before, defs_after + func_after + output_func, true, + true, 7u, 23u, false, false); +} + +TEST_F(InstBindlessTest, InstrumentVertexSimple) { + // This test verifies that the pass will correctly instrument shader + // doing bindless image write. This test was created by editing the SPIR-V + // from the Simple test. + + const std::string defs_before = + R"(OpCapability Shader +OpCapability Sampled1D +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Vertex %main "main" %_ %coords2D +OpSource GLSL 450 +OpName %main "main" +OpName %lod "lod" +OpName %coords1D "coords1D" +OpName %gl_PerVertex "gl_PerVertex" +OpMemberName %gl_PerVertex 0 "gl_Position" +OpMemberName %gl_PerVertex 1 "gl_PointSize" +OpMemberName %gl_PerVertex 2 "gl_ClipDistance" +OpMemberName %gl_PerVertex 3 "gl_CullDistance" +OpName %_ "" +OpName %texSampler1D "texSampler1D" +OpName %foo "foo" +OpMemberName %foo 0 "g_idx" +OpName %__0 "" +OpName %coords2D "coords2D" +OpMemberDecorate %gl_PerVertex 0 BuiltIn Position +OpMemberDecorate %gl_PerVertex 1 BuiltIn PointSize +OpMemberDecorate %gl_PerVertex 2 BuiltIn ClipDistance +OpMemberDecorate %gl_PerVertex 3 BuiltIn CullDistance +OpDecorate %gl_PerVertex Block +OpDecorate %texSampler1D DescriptorSet 0 +OpDecorate %texSampler1D Binding 3 +OpMemberDecorate %foo 0 Offset 0 +OpDecorate %foo Block +OpDecorate %__0 DescriptorSet 0 +OpDecorate %__0 Binding 5 +OpDecorate %coords2D Location 0 +%void = OpTypeVoid +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 +%_ptr_Function_float = OpTypePointer Function %float +%float_3 = OpConstant %float 3 +%float_1_78900003 = OpConstant %float 1.78900003 +%v4float = OpTypeVector %float 4 +%uint = OpTypeInt 32 0 +%uint_1 = OpConstant %uint 1 +%_arr_float_uint_1 = OpTypeArray %float %uint_1 +%gl_PerVertex = OpTypeStruct %v4float %float %_arr_float_uint_1 %_arr_float_uint_1 +%_ptr_Output_gl_PerVertex = OpTypePointer Output %gl_PerVertex +%_ = OpVariable %_ptr_Output_gl_PerVertex Output +%int = OpTypeInt 32 1 +%int_0 = OpConstant %int 0 +%21 = OpTypeImage %float 1D 0 0 0 1 Unknown +%22 = OpTypeSampledImage %21 +%uint_128 = OpConstant %uint 128 +%_arr_22_uint_128 = OpTypeArray %22 %uint_128 +%_ptr_UniformConstant__arr_22_uint_128 = OpTypePointer UniformConstant %_arr_22_uint_128 +%texSampler1D = OpVariable %_ptr_UniformConstant__arr_22_uint_128 UniformConstant +%foo = OpTypeStruct %int +%_ptr_Uniform_foo = OpTypePointer Uniform %foo +%__0 = OpVariable %_ptr_Uniform_foo Uniform +%_ptr_Uniform_int = OpTypePointer Uniform %int +%_ptr_UniformConstant_22 = OpTypePointer UniformConstant %22 +%_ptr_Output_v4float = OpTypePointer Output %v4float +%v2float = OpTypeVector %float 2 +%_ptr_Input_v2float = OpTypePointer Input %v2float +%coords2D = OpVariable %_ptr_Input_v2float Input +)"; + + const std::string defs_after = + R"(OpCapability Shader +OpCapability Sampled1D +OpExtension "SPV_KHR_storage_buffer_storage_class" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Vertex %main "main" %_ %coords2D %gl_VertexIndex %gl_InstanceIndex +OpSource GLSL 450 +OpName %main "main" +OpName %lod "lod" +OpName %coords1D "coords1D" +OpName %gl_PerVertex "gl_PerVertex" +OpMemberName %gl_PerVertex 0 "gl_Position" +OpMemberName %gl_PerVertex 1 "gl_PointSize" +OpMemberName %gl_PerVertex 2 "gl_ClipDistance" +OpMemberName %gl_PerVertex 3 "gl_CullDistance" +OpName %_ "" +OpName %texSampler1D "texSampler1D" +OpName %foo "foo" +OpMemberName %foo 0 "g_idx" +OpName %__0 "" +OpName %coords2D "coords2D" +OpMemberDecorate %gl_PerVertex 0 BuiltIn Position +OpMemberDecorate %gl_PerVertex 1 BuiltIn PointSize +OpMemberDecorate %gl_PerVertex 2 BuiltIn ClipDistance +OpMemberDecorate %gl_PerVertex 3 BuiltIn CullDistance +OpDecorate %gl_PerVertex Block +OpDecorate %texSampler1D DescriptorSet 0 +OpDecorate %texSampler1D Binding 3 +OpMemberDecorate %foo 0 Offset 0 +OpDecorate %foo Block +OpDecorate %__0 DescriptorSet 0 +OpDecorate %__0 Binding 5 +OpDecorate %coords2D Location 0 +OpDecorate %_runtimearr_uint ArrayStride 4 +OpDecorate %_struct_61 Block +OpMemberDecorate %_struct_61 0 Offset 0 +OpMemberDecorate %_struct_61 1 Offset 4 +OpDecorate %63 DescriptorSet 7 +OpDecorate %63 Binding 0 +OpDecorate %gl_VertexIndex BuiltIn VertexIndex +OpDecorate %gl_InstanceIndex BuiltIn InstanceIndex +%void = OpTypeVoid +%12 = OpTypeFunction %void +%float = OpTypeFloat 32 +%_ptr_Function_float = OpTypePointer Function %float +%float_3 = OpConstant %float 3 +%float_1_78900003 = OpConstant %float 1.78900003 +%v4float = OpTypeVector %float 4 +%uint = OpTypeInt 32 0 +%uint_1 = OpConstant %uint 1 +%_arr_float_uint_1 = OpTypeArray %float %uint_1 +%gl_PerVertex = OpTypeStruct %v4float %float %_arr_float_uint_1 %_arr_float_uint_1 +%_ptr_Output_gl_PerVertex = OpTypePointer Output %gl_PerVertex +%_ = OpVariable %_ptr_Output_gl_PerVertex Output +%int = OpTypeInt 32 1 +%int_0 = OpConstant %int 0 +%24 = OpTypeImage %float 1D 0 0 0 1 Unknown +%25 = OpTypeSampledImage %24 +%uint_128 = OpConstant %uint 128 +%_arr_25_uint_128 = OpTypeArray %25 %uint_128 +%_ptr_UniformConstant__arr_25_uint_128 = OpTypePointer UniformConstant %_arr_25_uint_128 +%texSampler1D = OpVariable %_ptr_UniformConstant__arr_25_uint_128 UniformConstant +%foo = OpTypeStruct %int +%_ptr_Uniform_foo = OpTypePointer Uniform %foo +%__0 = OpVariable %_ptr_Uniform_foo Uniform +%_ptr_Uniform_int = OpTypePointer Uniform %int +%_ptr_UniformConstant_25 = OpTypePointer UniformConstant %25 +%_ptr_Output_v4float = OpTypePointer Output %v4float +%v2float = OpTypeVector %float 2 +%_ptr_Input_v2float = OpTypePointer Input %v2float +%coords2D = OpVariable %_ptr_Input_v2float Input +%uint_0 = OpConstant %uint 0 +%bool = OpTypeBool +%54 = OpTypeFunction %void %uint %uint %uint %uint +%_runtimearr_uint = OpTypeRuntimeArray %uint +%_struct_61 = OpTypeStruct %uint %_runtimearr_uint +%_ptr_StorageBuffer__struct_61 = OpTypePointer StorageBuffer %_struct_61 +%63 = OpVariable %_ptr_StorageBuffer__struct_61 StorageBuffer +%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint +%uint_10 = OpConstant %uint 10 +%uint_4 = OpConstant %uint 4 +%uint_23 = OpConstant %uint 23 +%uint_2 = OpConstant %uint 2 +%uint_3 = OpConstant %uint 3 +%_ptr_Input_uint = OpTypePointer Input %uint +%gl_VertexIndex = OpVariable %_ptr_Input_uint Input +%gl_InstanceIndex = OpVariable %_ptr_Input_uint Input +%uint_5 = OpConstant %uint 5 +%uint_7 = OpConstant %uint 7 +%uint_8 = OpConstant %uint 8 +%uint_9 = OpConstant %uint 9 +%uint_74 = OpConstant %uint 74 +%106 = OpConstantNull %v4float +)"; + + const std::string func_before = + R"(%main = OpFunction %void None %3 +%5 = OpLabel +%lod = OpVariable %_ptr_Function_float Function +%coords1D = OpVariable %_ptr_Function_float Function +OpStore %lod %float_3 +OpStore %coords1D %float_1_78900003 +%31 = OpAccessChain %_ptr_Uniform_int %__0 %int_0 +%32 = OpLoad %int %31 +%34 = OpAccessChain %_ptr_UniformConstant_22 %texSampler1D %32 +%35 = OpLoad %22 %34 +%36 = OpLoad %float %coords1D +%37 = OpLoad %float %lod +%38 = OpImageSampleExplicitLod %v4float %35 %36 Lod %37 +%40 = OpAccessChain %_ptr_Output_v4float %_ %int_0 +OpStore %40 %38 +OpReturn +OpFunctionEnd +)"; + + const std::string func_after = + R"(%main = OpFunction %void None %12 +%35 = OpLabel +%lod = OpVariable %_ptr_Function_float Function +%coords1D = OpVariable %_ptr_Function_float Function +OpStore %lod %float_3 +OpStore %coords1D %float_1_78900003 +%36 = OpAccessChain %_ptr_Uniform_int %__0 %int_0 +%37 = OpLoad %int %36 +%38 = OpAccessChain %_ptr_UniformConstant_25 %texSampler1D %37 +%39 = OpLoad %25 %38 +%40 = OpLoad %float %coords1D +%41 = OpLoad %float %lod +%46 = OpULessThan %bool %37 %uint_128 +OpSelectionMerge %47 None +OpBranchConditional %46 %48 %49 +%48 = OpLabel +%50 = OpLoad %25 %38 +%51 = OpImageSampleExplicitLod %v4float %50 %40 Lod %41 +OpBranch %47 +%49 = OpLabel +%52 = OpBitcast %uint %37 +%105 = OpFunctionCall %void %53 %uint_74 %uint_0 %52 %uint_128 +OpBranch %47 +%47 = OpLabel +%107 = OpPhi %v4float %51 %48 %106 %49 +%43 = OpAccessChain %_ptr_Output_v4float %_ %int_0 +OpStore %43 %107 +OpReturn +OpFunctionEnd +)"; + + const std::string output_func = + R"(%53 = OpFunction %void None %54 +%55 = OpFunctionParameter %uint +%56 = OpFunctionParameter %uint +%57 = OpFunctionParameter %uint +%58 = OpFunctionParameter %uint +%59 = OpLabel +%65 = OpAccessChain %_ptr_StorageBuffer_uint %63 %uint_0 +%68 = OpAtomicIAdd %uint %65 %uint_4 %uint_0 %uint_10 +%69 = OpIAdd %uint %68 %uint_10 +%70 = OpArrayLength %uint %63 1 +%71 = OpULessThanEqual %bool %69 %70 +OpSelectionMerge %72 None +OpBranchConditional %71 %73 %72 +%73 = OpLabel +%74 = OpIAdd %uint %68 %uint_0 +%75 = OpAccessChain %_ptr_StorageBuffer_uint %63 %uint_1 %74 +OpStore %75 %uint_10 +%77 = OpIAdd %uint %68 %uint_1 +%78 = OpAccessChain %_ptr_StorageBuffer_uint %63 %uint_1 %77 +OpStore %78 %uint_23 +%80 = OpIAdd %uint %68 %uint_2 +%81 = OpAccessChain %_ptr_StorageBuffer_uint %63 %uint_1 %80 +OpStore %81 %55 +%83 = OpIAdd %uint %68 %uint_3 +%84 = OpAccessChain %_ptr_StorageBuffer_uint %63 %uint_1 %83 +OpStore %84 %uint_0 +%87 = OpLoad %uint %gl_VertexIndex +%88 = OpIAdd %uint %68 %uint_4 +%89 = OpAccessChain %_ptr_StorageBuffer_uint %63 %uint_1 %88 +OpStore %89 %87 +%91 = OpLoad %uint %gl_InstanceIndex +%93 = OpIAdd %uint %68 %uint_5 +%94 = OpAccessChain %_ptr_StorageBuffer_uint %63 %uint_1 %93 +OpStore %94 %91 +%96 = OpIAdd %uint %68 %uint_7 +%97 = OpAccessChain %_ptr_StorageBuffer_uint %63 %uint_1 %96 +OpStore %97 %56 +%99 = OpIAdd %uint %68 %uint_8 +%100 = OpAccessChain %_ptr_StorageBuffer_uint %63 %uint_1 %99 +OpStore %100 %57 +%102 = OpIAdd %uint %68 %uint_9 +%103 = OpAccessChain %_ptr_StorageBuffer_uint %63 %uint_1 %102 +OpStore %103 %58 +OpBranch %72 +%72 = OpLabel +OpReturn +OpFunctionEnd +)"; + + // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck( + defs_before + func_before, defs_after + func_after + output_func, true, + true, 7u, 23u, false, false); +} + +TEST_F(InstBindlessTest, InstrumentTeseSimple) { + // This test verifies that the pass will correctly instrument tessellation + // evaluation shader doing bindless buffer load. + // + // clang-format off + // + // #version 450 + // #extension GL_EXT_nonuniform_qualifier : enable + // + // layout(std140, set = 0, binding = 0) uniform ufoo { uint index; } uniform_index_buffer; + // + // layout(set = 0, binding = 1) buffer bfoo { vec4 val; } adds[11]; + // + // layout(triangles, equal_spacing, cw) in; + // + // void main() { + // gl_Position = adds[uniform_index_buffer.index].val; + // } + // + // clang-format on + + const std::string defs_before = + R"(OpCapability Tessellation +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint TessellationEvaluation %main "main" %_ +OpExecutionMode %main Triangles +OpExecutionMode %main SpacingEqual +OpExecutionMode %main VertexOrderCw +OpSource GLSL 450 +OpSourceExtension "GL_EXT_nonuniform_qualifier" +OpName %main "main" +OpName %gl_PerVertex "gl_PerVertex" +OpMemberName %gl_PerVertex 0 "gl_Position" +OpMemberName %gl_PerVertex 1 "gl_PointSize" +OpMemberName %gl_PerVertex 2 "gl_ClipDistance" +OpMemberName %gl_PerVertex 3 "gl_CullDistance" +OpName %_ "" +OpName %bfoo "bfoo" +OpMemberName %bfoo 0 "val" +OpName %adds "adds" +OpName %ufoo "ufoo" +OpMemberName %ufoo 0 "index" +OpName %uniform_index_buffer "uniform_index_buffer" +OpMemberDecorate %gl_PerVertex 0 BuiltIn Position +OpMemberDecorate %gl_PerVertex 1 BuiltIn PointSize +OpMemberDecorate %gl_PerVertex 2 BuiltIn ClipDistance +OpMemberDecorate %gl_PerVertex 3 BuiltIn CullDistance +OpDecorate %gl_PerVertex Block +OpMemberDecorate %bfoo 0 Offset 0 +OpDecorate %bfoo Block +OpDecorate %adds DescriptorSet 0 +OpDecorate %adds Binding 1 +OpMemberDecorate %ufoo 0 Offset 0 +OpDecorate %ufoo Block +OpDecorate %uniform_index_buffer DescriptorSet 0 +OpDecorate %uniform_index_buffer Binding 0 +%void = OpTypeVoid +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v4float = OpTypeVector %float 4 +%uint = OpTypeInt 32 0 +%uint_1 = OpConstant %uint 1 +%_arr_float_uint_1 = OpTypeArray %float %uint_1 +%gl_PerVertex = OpTypeStruct %v4float %float %_arr_float_uint_1 %_arr_float_uint_1 +%_ptr_Output_gl_PerVertex = OpTypePointer Output %gl_PerVertex +%_ = OpVariable %_ptr_Output_gl_PerVertex Output +%int = OpTypeInt 32 1 +%int_0 = OpConstant %int 0 +%bfoo = OpTypeStruct %v4float +%uint_11 = OpConstant %uint 11 +%_arr_bfoo_uint_11 = OpTypeArray %bfoo %uint_11 +%_ptr_StorageBuffer__arr_bfoo_uint_11 = OpTypePointer StorageBuffer %_arr_bfoo_uint_11 +%adds = OpVariable %_ptr_StorageBuffer__arr_bfoo_uint_11 StorageBuffer +%ufoo = OpTypeStruct %uint +%_ptr_Uniform_ufoo = OpTypePointer Uniform %ufoo +%uniform_index_buffer = OpVariable %_ptr_Uniform_ufoo Uniform +%_ptr_Uniform_uint = OpTypePointer Uniform %uint +%_ptr_StorageBuffer_v4float = OpTypePointer StorageBuffer %v4float +%_ptr_Output_v4float = OpTypePointer Output %v4float +)"; + + const std::string defs_after = + R"(OpCapability Tessellation +OpExtension "SPV_KHR_storage_buffer_storage_class" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint TessellationEvaluation %main "main" %_ %gl_PrimitiveID %gl_TessCoord +OpExecutionMode %main Triangles +OpExecutionMode %main SpacingEqual +OpExecutionMode %main VertexOrderCw +OpSource GLSL 450 +OpSourceExtension "GL_EXT_nonuniform_qualifier" +OpName %main "main" +OpName %gl_PerVertex "gl_PerVertex" +OpMemberName %gl_PerVertex 0 "gl_Position" +OpMemberName %gl_PerVertex 1 "gl_PointSize" +OpMemberName %gl_PerVertex 2 "gl_ClipDistance" +OpMemberName %gl_PerVertex 3 "gl_CullDistance" +OpName %_ "" +OpName %bfoo "bfoo" +OpMemberName %bfoo 0 "val" +OpName %adds "adds" +OpName %ufoo "ufoo" +OpMemberName %ufoo 0 "index" +OpName %uniform_index_buffer "uniform_index_buffer" +OpMemberDecorate %gl_PerVertex 0 BuiltIn Position +OpMemberDecorate %gl_PerVertex 1 BuiltIn PointSize +OpMemberDecorate %gl_PerVertex 2 BuiltIn ClipDistance +OpMemberDecorate %gl_PerVertex 3 BuiltIn CullDistance +OpDecorate %gl_PerVertex Block +OpMemberDecorate %bfoo 0 Offset 0 +OpDecorate %bfoo Block +OpDecorate %adds DescriptorSet 0 +OpDecorate %adds Binding 1 +OpMemberDecorate %ufoo 0 Offset 0 +OpDecorate %ufoo Block +OpDecorate %uniform_index_buffer DescriptorSet 0 +OpDecorate %uniform_index_buffer Binding 0 +OpDecorate %_runtimearr_uint ArrayStride 4 +OpDecorate %_struct_47 Block +OpMemberDecorate %_struct_47 0 Offset 0 +OpMemberDecorate %_struct_47 1 Offset 4 +OpDecorate %49 DescriptorSet 7 +OpDecorate %49 Binding 0 +OpDecorate %gl_PrimitiveID BuiltIn PrimitiveId +OpDecorate %gl_TessCoord BuiltIn TessCoord +%void = OpTypeVoid +%10 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v4float = OpTypeVector %float 4 +%uint = OpTypeInt 32 0 +%uint_1 = OpConstant %uint 1 +%_arr_float_uint_1 = OpTypeArray %float %uint_1 +%gl_PerVertex = OpTypeStruct %v4float %float %_arr_float_uint_1 %_arr_float_uint_1 +%_ptr_Output_gl_PerVertex = OpTypePointer Output %gl_PerVertex +%_ = OpVariable %_ptr_Output_gl_PerVertex Output +%int = OpTypeInt 32 1 +%int_0 = OpConstant %int 0 +%bfoo = OpTypeStruct %v4float +%uint_11 = OpConstant %uint 11 +%_arr_bfoo_uint_11 = OpTypeArray %bfoo %uint_11 +%_ptr_StorageBuffer__arr_bfoo_uint_11 = OpTypePointer StorageBuffer %_arr_bfoo_uint_11 +%adds = OpVariable %_ptr_StorageBuffer__arr_bfoo_uint_11 StorageBuffer +%ufoo = OpTypeStruct %uint +%_ptr_Uniform_ufoo = OpTypePointer Uniform %ufoo +%uniform_index_buffer = OpVariable %_ptr_Uniform_ufoo Uniform +%_ptr_Uniform_uint = OpTypePointer Uniform %uint +%_ptr_StorageBuffer_v4float = OpTypePointer StorageBuffer %v4float +%_ptr_Output_v4float = OpTypePointer Output %v4float +%uint_0 = OpConstant %uint 0 +%bool = OpTypeBool +%40 = OpTypeFunction %void %uint %uint %uint %uint +%_runtimearr_uint = OpTypeRuntimeArray %uint +%_struct_47 = OpTypeStruct %uint %_runtimearr_uint +%_ptr_StorageBuffer__struct_47 = OpTypePointer StorageBuffer %_struct_47 +%49 = OpVariable %_ptr_StorageBuffer__struct_47 StorageBuffer +%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint +%uint_10 = OpConstant %uint 10 +%uint_4 = OpConstant %uint 4 +%uint_23 = OpConstant %uint 23 +%uint_2 = OpConstant %uint 2 +%uint_3 = OpConstant %uint 3 +%_ptr_Input_uint = OpTypePointer Input %uint +%gl_PrimitiveID = OpVariable %_ptr_Input_uint Input +%v3float = OpTypeVector %float 3 +%_ptr_Input_v3float = OpTypePointer Input %v3float +%gl_TessCoord = OpVariable %_ptr_Input_v3float Input +%v3uint = OpTypeVector %uint 3 +%uint_5 = OpConstant %uint 5 +%uint_6 = OpConstant %uint 6 +%uint_7 = OpConstant %uint 7 +%uint_8 = OpConstant %uint 8 +%uint_9 = OpConstant %uint 9 +%uint_63 = OpConstant %uint 63 +%101 = OpConstantNull %v4float +)"; + + const std::string func_before = + R"(%main = OpFunction %void None %3 +%5 = OpLabel +%25 = OpAccessChain %_ptr_Uniform_uint %uniform_index_buffer %int_0 +%26 = OpLoad %uint %25 +%28 = OpAccessChain %_ptr_StorageBuffer_v4float %adds %26 %int_0 +%29 = OpLoad %v4float %28 +%31 = OpAccessChain %_ptr_Output_v4float %_ %int_0 +OpStore %31 %29 +OpReturn +OpFunctionEnd +)"; + + const std::string func_after = + R"(%main = OpFunction %void None %10 +%26 = OpLabel +%27 = OpAccessChain %_ptr_Uniform_uint %uniform_index_buffer %int_0 +%28 = OpLoad %uint %27 +%29 = OpAccessChain %_ptr_StorageBuffer_v4float %adds %28 %int_0 +%34 = OpULessThan %bool %28 %uint_11 +OpSelectionMerge %35 None +OpBranchConditional %34 %36 %37 +%36 = OpLabel +%38 = OpLoad %v4float %29 +OpBranch %35 +%37 = OpLabel +%100 = OpFunctionCall %void %39 %uint_63 %uint_0 %28 %uint_11 +OpBranch %35 +%35 = OpLabel +%102 = OpPhi %v4float %38 %36 %101 %37 +%31 = OpAccessChain %_ptr_Output_v4float %_ %int_0 +OpStore %31 %102 +OpReturn +OpFunctionEnd +)"; + + const std::string output_func = + R"(%39 = OpFunction %void None %40 +%41 = OpFunctionParameter %uint +%42 = OpFunctionParameter %uint +%43 = OpFunctionParameter %uint +%44 = OpFunctionParameter %uint +%45 = OpLabel +%51 = OpAccessChain %_ptr_StorageBuffer_uint %49 %uint_0 +%54 = OpAtomicIAdd %uint %51 %uint_4 %uint_0 %uint_10 +%55 = OpIAdd %uint %54 %uint_10 +%56 = OpArrayLength %uint %49 1 +%57 = OpULessThanEqual %bool %55 %56 +OpSelectionMerge %58 None +OpBranchConditional %57 %59 %58 +%59 = OpLabel +%60 = OpIAdd %uint %54 %uint_0 +%61 = OpAccessChain %_ptr_StorageBuffer_uint %49 %uint_1 %60 +OpStore %61 %uint_10 +%63 = OpIAdd %uint %54 %uint_1 +%64 = OpAccessChain %_ptr_StorageBuffer_uint %49 %uint_1 %63 +OpStore %64 %uint_23 +%66 = OpIAdd %uint %54 %uint_2 +%67 = OpAccessChain %_ptr_StorageBuffer_uint %49 %uint_1 %66 +OpStore %67 %41 +%69 = OpIAdd %uint %54 %uint_3 +%70 = OpAccessChain %_ptr_StorageBuffer_uint %49 %uint_1 %69 +OpStore %70 %uint_2 +%73 = OpLoad %uint %gl_PrimitiveID +%74 = OpIAdd %uint %54 %uint_4 +%75 = OpAccessChain %_ptr_StorageBuffer_uint %49 %uint_1 %74 +OpStore %75 %73 +%79 = OpLoad %v3float %gl_TessCoord +%81 = OpBitcast %v3uint %79 +%82 = OpCompositeExtract %uint %81 0 +%83 = OpCompositeExtract %uint %81 1 +%85 = OpIAdd %uint %54 %uint_5 +%86 = OpAccessChain %_ptr_StorageBuffer_uint %49 %uint_1 %85 +OpStore %86 %82 +%88 = OpIAdd %uint %54 %uint_6 +%89 = OpAccessChain %_ptr_StorageBuffer_uint %49 %uint_1 %88 +OpStore %89 %83 +%91 = OpIAdd %uint %54 %uint_7 +%92 = OpAccessChain %_ptr_StorageBuffer_uint %49 %uint_1 %91 +OpStore %92 %42 +%94 = OpIAdd %uint %54 %uint_8 +%95 = OpAccessChain %_ptr_StorageBuffer_uint %49 %uint_1 %94 +OpStore %95 %43 +%97 = OpIAdd %uint %54 %uint_9 +%98 = OpAccessChain %_ptr_StorageBuffer_uint %49 %uint_1 %97 +OpStore %98 %44 +OpBranch %58 +%58 = OpLabel +OpReturn +OpFunctionEnd +)"; + + // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck( + defs_before + func_before, defs_after + func_after + output_func, true, + true, 7u, 23u, false, false); +} + +TEST_F(InstBindlessTest, MultipleDebugFunctions) { + // Same source as Simple, but compiled -g and not optimized, especially not + // inlined. The OpSource has had the source extracted for the sake of brevity. + + const std::string defs_before = + R"(OpCapability Shader +%2 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor +OpExecutionMode %MainPs OriginUpperLeft +%1 = OpString "foo5.frag" +OpSource HLSL 500 %1 +OpName %MainPs "MainPs" +OpName %PS_INPUT "PS_INPUT" +OpMemberName %PS_INPUT 0 "vTextureCoords" +OpName %PS_OUTPUT "PS_OUTPUT" +OpMemberName %PS_OUTPUT 0 "vColor" +OpName %_MainPs_struct_PS_INPUT_vf21_ "@MainPs(struct-PS_INPUT-vf21;" +OpName %i "i" +OpName %ps_output "ps_output" +OpName %g_tColor "g_tColor" +OpName %PerViewConstantBuffer_t "PerViewConstantBuffer_t" +OpMemberName %PerViewConstantBuffer_t 0 "g_nDataIdx" +OpName %_ "" +OpName %g_sAniso "g_sAniso" +OpName %i_0 "i" +OpName %i_vTextureCoords "i.vTextureCoords" +OpName %_entryPointOutput_vColor "@entryPointOutput.vColor" +OpName %param "param" +OpDecorate %g_tColor DescriptorSet 0 +OpDecorate %g_tColor Binding 0 +OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0 +OpDecorate %PerViewConstantBuffer_t Block +OpDecorate %g_sAniso DescriptorSet 0 +OpDecorate %g_sAniso Binding 1 +OpDecorate %i_vTextureCoords Location 0 +OpDecorate %_entryPointOutput_vColor Location 0 +%void = OpTypeVoid +%4 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v2float = OpTypeVector %float 2 +%PS_INPUT = OpTypeStruct %v2float +%_ptr_Function_PS_INPUT = OpTypePointer Function %PS_INPUT +%v4float = OpTypeVector %float 4 +%PS_OUTPUT = OpTypeStruct %v4float +%13 = OpTypeFunction %PS_OUTPUT %_ptr_Function_PS_INPUT +%_ptr_Function_PS_OUTPUT = OpTypePointer Function %PS_OUTPUT +%int = OpTypeInt 32 1 +%int_0 = OpConstant %int 0 +%21 = OpTypeImage %float 2D 0 0 0 1 Unknown +%uint = OpTypeInt 32 0 +%uint_128 = OpConstant %uint 128 +%_arr_21_uint_128 = OpTypeArray %21 %uint_128 +%_ptr_UniformConstant__arr_21_uint_128 = OpTypePointer UniformConstant %_arr_21_uint_128 +%g_tColor = OpVariable %_ptr_UniformConstant__arr_21_uint_128 UniformConstant +%PerViewConstantBuffer_t = OpTypeStruct %uint +%_ptr_PushConstant_PerViewConstantBuffer_t = OpTypePointer PushConstant %PerViewConstantBuffer_t +%_ = OpVariable %_ptr_PushConstant_PerViewConstantBuffer_t PushConstant +%_ptr_PushConstant_uint = OpTypePointer PushConstant %uint +%_ptr_UniformConstant_21 = OpTypePointer UniformConstant %21 +%36 = OpTypeSampler +%_ptr_UniformConstant_36 = OpTypePointer UniformConstant %36 +%g_sAniso = OpVariable %_ptr_UniformConstant_36 UniformConstant +%40 = OpTypeSampledImage %21 +%_ptr_Function_v2float = OpTypePointer Function %v2float +%_ptr_Function_v4float = OpTypePointer Function %v4float +%_ptr_Input_v2float = OpTypePointer Input %v2float +%i_vTextureCoords = OpVariable %_ptr_Input_v2float Input +%_ptr_Output_v4float = OpTypePointer Output %v4float +%_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output +)"; + + const std::string defs_after = + R"(OpCapability Shader +OpExtension "SPV_KHR_storage_buffer_storage_class" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord +OpExecutionMode %MainPs OriginUpperLeft +%5 = OpString "foo5.frag" +OpSource HLSL 500 %5 +OpName %MainPs "MainPs" +OpName %PS_INPUT "PS_INPUT" +OpMemberName %PS_INPUT 0 "vTextureCoords" +OpName %PS_OUTPUT "PS_OUTPUT" +OpMemberName %PS_OUTPUT 0 "vColor" +OpName %_MainPs_struct_PS_INPUT_vf21_ "@MainPs(struct-PS_INPUT-vf21;" +OpName %i "i" +OpName %ps_output "ps_output" +OpName %g_tColor "g_tColor" +OpName %PerViewConstantBuffer_t "PerViewConstantBuffer_t" +OpMemberName %PerViewConstantBuffer_t 0 "g_nDataIdx" +OpName %_ "" +OpName %g_sAniso "g_sAniso" +OpName %i_0 "i" +OpName %i_vTextureCoords "i.vTextureCoords" +OpName %_entryPointOutput_vColor "@entryPointOutput.vColor" +OpName %param "param" +OpDecorate %g_tColor DescriptorSet 0 +OpDecorate %g_tColor Binding 0 +OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0 +OpDecorate %PerViewConstantBuffer_t Block +OpDecorate %g_sAniso DescriptorSet 0 +OpDecorate %g_sAniso Binding 1 +OpDecorate %i_vTextureCoords Location 0 +OpDecorate %_entryPointOutput_vColor Location 0 +OpDecorate %_runtimearr_uint ArrayStride 4 +OpDecorate %_struct_77 Block +OpMemberDecorate %_struct_77 0 Offset 0 +OpMemberDecorate %_struct_77 1 Offset 4 +OpDecorate %79 DescriptorSet 7 +OpDecorate %79 Binding 0 +OpDecorate %gl_FragCoord BuiltIn FragCoord +%void = OpTypeVoid +%18 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v2float = OpTypeVector %float 2 +%PS_INPUT = OpTypeStruct %v2float +%_ptr_Function_PS_INPUT = OpTypePointer Function %PS_INPUT +%v4float = OpTypeVector %float 4 +%PS_OUTPUT = OpTypeStruct %v4float +%23 = OpTypeFunction %PS_OUTPUT %_ptr_Function_PS_INPUT +%_ptr_Function_PS_OUTPUT = OpTypePointer Function %PS_OUTPUT +%int = OpTypeInt 32 1 +%int_0 = OpConstant %int 0 +%27 = OpTypeImage %float 2D 0 0 0 1 Unknown +%uint = OpTypeInt 32 0 +%uint_128 = OpConstant %uint 128 +%_arr_27_uint_128 = OpTypeArray %27 %uint_128 +%_ptr_UniformConstant__arr_27_uint_128 = OpTypePointer UniformConstant %_arr_27_uint_128 +%g_tColor = OpVariable %_ptr_UniformConstant__arr_27_uint_128 UniformConstant +%PerViewConstantBuffer_t = OpTypeStruct %uint +%_ptr_PushConstant_PerViewConstantBuffer_t = OpTypePointer PushConstant %PerViewConstantBuffer_t +%_ = OpVariable %_ptr_PushConstant_PerViewConstantBuffer_t PushConstant +%_ptr_PushConstant_uint = OpTypePointer PushConstant %uint +%_ptr_UniformConstant_27 = OpTypePointer UniformConstant %27 +%35 = OpTypeSampler +%_ptr_UniformConstant_35 = OpTypePointer UniformConstant %35 +%g_sAniso = OpVariable %_ptr_UniformConstant_35 UniformConstant +%37 = OpTypeSampledImage %27 +%_ptr_Function_v2float = OpTypePointer Function %v2float +%_ptr_Function_v4float = OpTypePointer Function %v4float +%_ptr_Input_v2float = OpTypePointer Input %v2float +%i_vTextureCoords = OpVariable %_ptr_Input_v2float Input +%_ptr_Output_v4float = OpTypePointer Output %v4float +%_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output +%uint_0 = OpConstant %uint 0 +%bool = OpTypeBool +%70 = OpTypeFunction %void %uint %uint %uint %uint +%_runtimearr_uint = OpTypeRuntimeArray %uint +%_struct_77 = OpTypeStruct %uint %_runtimearr_uint +%_ptr_StorageBuffer__struct_77 = OpTypePointer StorageBuffer %_struct_77 +%79 = OpVariable %_ptr_StorageBuffer__struct_77 StorageBuffer +%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint +%uint_10 = OpConstant %uint 10 +%uint_4 = OpConstant %uint 4 +%uint_1 = OpConstant %uint 1 +%uint_23 = OpConstant %uint 23 +%uint_2 = OpConstant %uint 2 +%uint_3 = OpConstant %uint 3 +%_ptr_Input_v4float = OpTypePointer Input %v4float +%gl_FragCoord = OpVariable %_ptr_Input_v4float Input +%v4uint = OpTypeVector %uint 4 +%uint_5 = OpConstant %uint 5 +%uint_7 = OpConstant %uint 7 +%uint_8 = OpConstant %uint 8 +%uint_9 = OpConstant %uint 9 +%uint_93 = OpConstant %uint 93 +%125 = OpConstantNull %v4float +)"; + + const std::string func1_before = + R"(%MainPs = OpFunction %void None %4 +%6 = OpLabel +%i_0 = OpVariable %_ptr_Function_PS_INPUT Function +%param = OpVariable %_ptr_Function_PS_INPUT Function +OpLine %1 21 0 +%54 = OpLoad %v2float %i_vTextureCoords +%55 = OpAccessChain %_ptr_Function_v2float %i_0 %int_0 +OpStore %55 %54 +%59 = OpLoad %PS_INPUT %i_0 +OpStore %param %59 +%60 = OpFunctionCall %PS_OUTPUT %_MainPs_struct_PS_INPUT_vf21_ %param +%61 = OpCompositeExtract %v4float %60 0 +OpStore %_entryPointOutput_vColor %61 +OpReturn +OpFunctionEnd +)"; + + const std::string func1_after = + R"(%MainPs = OpFunction %void None %18 +%42 = OpLabel +%i_0 = OpVariable %_ptr_Function_PS_INPUT Function +%param = OpVariable %_ptr_Function_PS_INPUT Function +OpLine %5 21 0 +%43 = OpLoad %v2float %i_vTextureCoords +%44 = OpAccessChain %_ptr_Function_v2float %i_0 %int_0 +OpStore %44 %43 +%45 = OpLoad %PS_INPUT %i_0 +OpStore %param %45 +%46 = OpFunctionCall %PS_OUTPUT %_MainPs_struct_PS_INPUT_vf21_ %param +%47 = OpCompositeExtract %v4float %46 0 +OpStore %_entryPointOutput_vColor %47 +OpReturn +OpFunctionEnd +)"; + + const std::string func2_before = + R"(%_MainPs_struct_PS_INPUT_vf21_ = OpFunction %PS_OUTPUT None %13 +%i = OpFunctionParameter %_ptr_Function_PS_INPUT +%16 = OpLabel +%ps_output = OpVariable %_ptr_Function_PS_OUTPUT Function +OpLine %1 24 0 +%31 = OpAccessChain %_ptr_PushConstant_uint %_ %int_0 +%32 = OpLoad %uint %31 +%34 = OpAccessChain %_ptr_UniformConstant_21 %g_tColor %32 +%35 = OpLoad %21 %34 +%39 = OpLoad %36 %g_sAniso +%41 = OpSampledImage %40 %35 %39 +%43 = OpAccessChain %_ptr_Function_v2float %i %int_0 +%44 = OpLoad %v2float %43 +%45 = OpImageSampleImplicitLod %v4float %41 %44 +%47 = OpAccessChain %_ptr_Function_v4float %ps_output %int_0 +OpStore %47 %45 +OpLine %1 25 0 +%48 = OpLoad %PS_OUTPUT %ps_output +OpReturnValue %48 +OpFunctionEnd +)"; + + const std::string func2_after = + R"(%_MainPs_struct_PS_INPUT_vf21_ = OpFunction %PS_OUTPUT None %23 +%i = OpFunctionParameter %_ptr_Function_PS_INPUT +%48 = OpLabel +%ps_output = OpVariable %_ptr_Function_PS_OUTPUT Function +OpLine %5 24 0 +%49 = OpAccessChain %_ptr_PushConstant_uint %_ %int_0 +%50 = OpLoad %uint %49 +%51 = OpAccessChain %_ptr_UniformConstant_27 %g_tColor %50 +%52 = OpLoad %27 %51 +%53 = OpLoad %35 %g_sAniso +%54 = OpSampledImage %37 %52 %53 +%55 = OpAccessChain %_ptr_Function_v2float %i %int_0 +%56 = OpLoad %v2float %55 +%62 = OpULessThan %bool %50 %uint_128 +OpSelectionMerge %63 None +OpBranchConditional %62 %64 %65 +%64 = OpLabel +%66 = OpLoad %27 %51 +%67 = OpSampledImage %37 %66 %53 +%68 = OpImageSampleImplicitLod %v4float %67 %56 +OpBranch %63 +%65 = OpLabel +%124 = OpFunctionCall %void %69 %uint_93 %uint_0 %50 %uint_128 +OpBranch %63 +%63 = OpLabel +%126 = OpPhi %v4float %68 %64 %125 %65 +%58 = OpAccessChain %_ptr_Function_v4float %ps_output %int_0 +OpStore %58 %126 +OpLine %5 25 0 +%59 = OpLoad %PS_OUTPUT %ps_output +OpReturnValue %59 +OpFunctionEnd +)"; + + const std::string output_func = + R"(%69 = OpFunction %void None %70 +%71 = OpFunctionParameter %uint +%72 = OpFunctionParameter %uint +%73 = OpFunctionParameter %uint +%74 = OpFunctionParameter %uint +%75 = OpLabel +%81 = OpAccessChain %_ptr_StorageBuffer_uint %79 %uint_0 +%84 = OpAtomicIAdd %uint %81 %uint_4 %uint_0 %uint_10 +%85 = OpIAdd %uint %84 %uint_10 +%86 = OpArrayLength %uint %79 1 +%87 = OpULessThanEqual %bool %85 %86 +OpSelectionMerge %88 None +OpBranchConditional %87 %89 %88 +%89 = OpLabel +%90 = OpIAdd %uint %84 %uint_0 +%92 = OpAccessChain %_ptr_StorageBuffer_uint %79 %uint_1 %90 +OpStore %92 %uint_10 +%94 = OpIAdd %uint %84 %uint_1 +%95 = OpAccessChain %_ptr_StorageBuffer_uint %79 %uint_1 %94 +OpStore %95 %uint_23 +%97 = OpIAdd %uint %84 %uint_2 +%98 = OpAccessChain %_ptr_StorageBuffer_uint %79 %uint_1 %97 +OpStore %98 %71 +%100 = OpIAdd %uint %84 %uint_3 +%101 = OpAccessChain %_ptr_StorageBuffer_uint %79 %uint_1 %100 +OpStore %101 %uint_4 +%104 = OpLoad %v4float %gl_FragCoord +%106 = OpBitcast %v4uint %104 +%107 = OpCompositeExtract %uint %106 0 +%108 = OpIAdd %uint %84 %uint_4 +%109 = OpAccessChain %_ptr_StorageBuffer_uint %79 %uint_1 %108 +OpStore %109 %107 +%110 = OpCompositeExtract %uint %106 1 +%112 = OpIAdd %uint %84 %uint_5 +%113 = OpAccessChain %_ptr_StorageBuffer_uint %79 %uint_1 %112 +OpStore %113 %110 +%115 = OpIAdd %uint %84 %uint_7 +%116 = OpAccessChain %_ptr_StorageBuffer_uint %79 %uint_1 %115 +OpStore %116 %72 +%118 = OpIAdd %uint %84 %uint_8 +%119 = OpAccessChain %_ptr_StorageBuffer_uint %79 %uint_1 %118 +OpStore %119 %73 +%121 = OpIAdd %uint %84 %uint_9 +%122 = OpAccessChain %_ptr_StorageBuffer_uint %79 %uint_1 %121 +OpStore %122 %74 +OpBranch %88 +%88 = OpLabel +OpReturn +OpFunctionEnd +)"; + + // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck( + defs_before + func1_before + func2_before, + defs_after + func1_after + func2_after + output_func, true, true, 7u, 23u, + false, false); +} + +TEST_F(InstBindlessTest, RuntimeArray) { + // This test verifies that the pass will correctly instrument shader + // with runtime descriptor array. This test was created by editing the + // SPIR-V from the Simple test. + + const std::string defs_before = + R"(OpCapability Shader +OpCapability RuntimeDescriptorArray +OpExtension "SPV_EXT_descriptor_indexing" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor +OpExecutionMode %MainPs OriginUpperLeft +OpSource HLSL 500 +OpName %MainPs "MainPs" +OpName %g_tColor "g_tColor" +OpName %PerViewConstantBuffer_t "PerViewConstantBuffer_t" +OpMemberName %PerViewConstantBuffer_t 0 "g_nDataIdx" +OpName %_ "" +OpName %g_sAniso "g_sAniso" +OpName %i_vTextureCoords "i.vTextureCoords" +OpName %_entryPointOutput_vColor "@entryPointOutput.vColor" +OpDecorate %g_tColor DescriptorSet 1 +OpDecorate %g_tColor Binding 2 +OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0 +OpDecorate %PerViewConstantBuffer_t Block +OpDecorate %g_sAniso DescriptorSet 1 +OpDecorate %g_sAniso Binding 0 +OpDecorate %i_vTextureCoords Location 0 +OpDecorate %_entryPointOutput_vColor Location 0 +%void = OpTypeVoid +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v2float = OpTypeVector %float 2 +%v4float = OpTypeVector %float 4 +%int = OpTypeInt 32 1 +%int_0 = OpConstant %int 0 +%20 = OpTypeImage %float 2D 0 0 0 1 Unknown +%uint = OpTypeInt 32 0 +%uint_1 = OpConstant %uint 1 +%_rarr_20 = OpTypeRuntimeArray %20 +%_ptr_UniformConstant__arr_20 = OpTypePointer UniformConstant %_rarr_20 +%g_tColor = OpVariable %_ptr_UniformConstant__arr_20 UniformConstant +%PerViewConstantBuffer_t = OpTypeStruct %uint +%_ptr_PushConstant_PerViewConstantBuffer_t = OpTypePointer PushConstant %PerViewConstantBuffer_t +%_ = OpVariable %_ptr_PushConstant_PerViewConstantBuffer_t PushConstant +%_ptr_PushConstant_uint = OpTypePointer PushConstant %uint +%_ptr_UniformConstant_20 = OpTypePointer UniformConstant %20 +%35 = OpTypeSampler +%_ptr_UniformConstant_35 = OpTypePointer UniformConstant %35 +%g_sAniso = OpVariable %_ptr_UniformConstant_35 UniformConstant +%39 = OpTypeSampledImage %20 +%_ptr_Input_v2float = OpTypePointer Input %v2float +%i_vTextureCoords = OpVariable %_ptr_Input_v2float Input +%_ptr_Output_v4float = OpTypePointer Output %v4float +%_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output +)"; + + const std::string defs_after = + R"(OpCapability Shader +OpCapability RuntimeDescriptorArray +OpExtension "SPV_EXT_descriptor_indexing" +OpExtension "SPV_KHR_storage_buffer_storage_class" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord +OpExecutionMode %MainPs OriginUpperLeft +OpSource HLSL 500 +OpName %MainPs "MainPs" +OpName %g_tColor "g_tColor" +OpName %PerViewConstantBuffer_t "PerViewConstantBuffer_t" +OpMemberName %PerViewConstantBuffer_t 0 "g_nDataIdx" +OpName %_ "" +OpName %g_sAniso "g_sAniso" +OpName %i_vTextureCoords "i.vTextureCoords" +OpName %_entryPointOutput_vColor "@entryPointOutput.vColor" +OpDecorate %g_tColor DescriptorSet 1 +OpDecorate %g_tColor Binding 2 +OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0 +OpDecorate %PerViewConstantBuffer_t Block +OpDecorate %g_sAniso DescriptorSet 1 +OpDecorate %g_sAniso Binding 0 +OpDecorate %i_vTextureCoords Location 0 +OpDecorate %_entryPointOutput_vColor Location 0 +OpDecorate %_runtimearr_uint ArrayStride 4 +OpDecorate %_struct_46 Block +OpMemberDecorate %_struct_46 0 Offset 0 +OpDecorate %48 DescriptorSet 7 +OpDecorate %48 Binding 1 +OpDecorate %_struct_71 Block +OpMemberDecorate %_struct_71 0 Offset 0 +OpMemberDecorate %_struct_71 1 Offset 4 +OpDecorate %73 DescriptorSet 7 +OpDecorate %73 Binding 0 +OpDecorate %gl_FragCoord BuiltIn FragCoord +%void = OpTypeVoid +%10 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v2float = OpTypeVector %float 2 +%v4float = OpTypeVector %float 4 +%int = OpTypeInt 32 1 +%int_0 = OpConstant %int 0 +%16 = OpTypeImage %float 2D 0 0 0 1 Unknown +%uint = OpTypeInt 32 0 +%uint_1 = OpConstant %uint 1 +%_runtimearr_16 = OpTypeRuntimeArray %16 +%_ptr_UniformConstant__runtimearr_16 = OpTypePointer UniformConstant %_runtimearr_16 +%g_tColor = OpVariable %_ptr_UniformConstant__runtimearr_16 UniformConstant +%PerViewConstantBuffer_t = OpTypeStruct %uint +%_ptr_PushConstant_PerViewConstantBuffer_t = OpTypePointer PushConstant %PerViewConstantBuffer_t +%_ = OpVariable %_ptr_PushConstant_PerViewConstantBuffer_t PushConstant +%_ptr_PushConstant_uint = OpTypePointer PushConstant %uint +%_ptr_UniformConstant_16 = OpTypePointer UniformConstant %16 +%24 = OpTypeSampler +%_ptr_UniformConstant_24 = OpTypePointer UniformConstant %24 +%g_sAniso = OpVariable %_ptr_UniformConstant_24 UniformConstant +%26 = OpTypeSampledImage %16 +%_ptr_Input_v2float = OpTypePointer Input %v2float +%i_vTextureCoords = OpVariable %_ptr_Input_v2float Input +%_ptr_Output_v4float = OpTypePointer Output %v4float +%_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output +%uint_0 = OpConstant %uint 0 +%uint_2 = OpConstant %uint 2 +%41 = OpTypeFunction %uint %uint %uint +%_runtimearr_uint = OpTypeRuntimeArray %uint +%_struct_46 = OpTypeStruct %_runtimearr_uint +%_ptr_StorageBuffer__struct_46 = OpTypePointer StorageBuffer %_struct_46 +%48 = OpVariable %_ptr_StorageBuffer__struct_46 StorageBuffer +%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint +%bool = OpTypeBool +%65 = OpTypeFunction %void %uint %uint %uint %uint +%_struct_71 = OpTypeStruct %uint %_runtimearr_uint +%_ptr_StorageBuffer__struct_71 = OpTypePointer StorageBuffer %_struct_71 +%73 = OpVariable %_ptr_StorageBuffer__struct_71 StorageBuffer +%uint_10 = OpConstant %uint 10 +%uint_4 = OpConstant %uint 4 +%uint_23 = OpConstant %uint 23 +%uint_3 = OpConstant %uint 3 +%_ptr_Input_v4float = OpTypePointer Input %v4float +%gl_FragCoord = OpVariable %_ptr_Input_v4float Input +%v4uint = OpTypeVector %uint 4 +%uint_5 = OpConstant %uint 5 +%uint_7 = OpConstant %uint 7 +%uint_8 = OpConstant %uint 8 +%uint_9 = OpConstant %uint 9 +%uint_59 = OpConstant %uint 59 +%116 = OpConstantNull %v4float +%119 = OpTypeFunction %uint %uint %uint %uint %uint +)"; + + const std::string func_before = + R"(%MainPs = OpFunction %void None %3 +%5 = OpLabel +%53 = OpLoad %v2float %i_vTextureCoords +%63 = OpAccessChain %_ptr_PushConstant_uint %_ %int_0 +%64 = OpLoad %uint %63 +%65 = OpAccessChain %_ptr_UniformConstant_20 %g_tColor %64 +%66 = OpLoad %20 %65 +%67 = OpLoad %35 %g_sAniso +%68 = OpSampledImage %39 %66 %67 +%71 = OpImageSampleImplicitLod %v4float %68 %53 +OpStore %_entryPointOutput_vColor %71 +OpReturn +OpFunctionEnd +)"; + + const std::string func_after = + R"(%MainPs = OpFunction %void None %10 +%29 = OpLabel +%30 = OpLoad %v2float %i_vTextureCoords +%31 = OpAccessChain %_ptr_PushConstant_uint %_ %int_0 +%32 = OpLoad %uint %31 +%33 = OpAccessChain %_ptr_UniformConstant_16 %g_tColor %32 +%34 = OpLoad %16 %33 +%35 = OpLoad %24 %g_sAniso +%36 = OpSampledImage %26 %34 %35 +%55 = OpFunctionCall %uint %40 %uint_2 %uint_2 +%57 = OpULessThan %bool %32 %55 +OpSelectionMerge %58 None +OpBranchConditional %57 %59 %60 +%59 = OpLabel +%61 = OpLoad %16 %33 +%62 = OpSampledImage %26 %61 %35 +%136 = OpFunctionCall %uint %118 %uint_0 %uint_1 %uint_2 %32 +%137 = OpINotEqual %bool %136 %uint_0 +OpSelectionMerge %138 None +OpBranchConditional %137 %139 %140 +%139 = OpLabel +%141 = OpLoad %16 %33 +%142 = OpSampledImage %26 %141 %35 +%143 = OpImageSampleImplicitLod %v4float %142 %30 +OpBranch %138 +%140 = OpLabel +%144 = OpFunctionCall %void %64 %uint_59 %uint_1 %32 %uint_0 +OpBranch %138 +%138 = OpLabel +%145 = OpPhi %v4float %143 %139 %116 %140 +OpBranch %58 +%60 = OpLabel +%115 = OpFunctionCall %void %64 %uint_59 %uint_0 %32 %55 +OpBranch %58 +%58 = OpLabel +%117 = OpPhi %v4float %145 %138 %116 %60 +OpStore %_entryPointOutput_vColor %117 +OpReturn +OpFunctionEnd +)"; + + const std::string new_funcs = + R"(%40 = OpFunction %uint None %41 +%42 = OpFunctionParameter %uint +%43 = OpFunctionParameter %uint +%44 = OpLabel +%50 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_0 %42 +%51 = OpLoad %uint %50 +%52 = OpIAdd %uint %51 %43 +%53 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_0 %52 +%54 = OpLoad %uint %53 +OpReturnValue %54 +OpFunctionEnd +%64 = OpFunction %void None %65 +%66 = OpFunctionParameter %uint +%67 = OpFunctionParameter %uint +%68 = OpFunctionParameter %uint +%69 = OpFunctionParameter %uint +%70 = OpLabel +%74 = OpAccessChain %_ptr_StorageBuffer_uint %73 %uint_0 +%77 = OpAtomicIAdd %uint %74 %uint_4 %uint_0 %uint_10 +%78 = OpIAdd %uint %77 %uint_10 +%79 = OpArrayLength %uint %73 1 +%80 = OpULessThanEqual %bool %78 %79 +OpSelectionMerge %81 None +OpBranchConditional %80 %82 %81 +%82 = OpLabel +%83 = OpIAdd %uint %77 %uint_0 +%84 = OpAccessChain %_ptr_StorageBuffer_uint %73 %uint_1 %83 +OpStore %84 %uint_10 +%86 = OpIAdd %uint %77 %uint_1 +%87 = OpAccessChain %_ptr_StorageBuffer_uint %73 %uint_1 %86 +OpStore %87 %uint_23 +%88 = OpIAdd %uint %77 %uint_2 +%89 = OpAccessChain %_ptr_StorageBuffer_uint %73 %uint_1 %88 +OpStore %89 %66 +%91 = OpIAdd %uint %77 %uint_3 +%92 = OpAccessChain %_ptr_StorageBuffer_uint %73 %uint_1 %91 +OpStore %92 %uint_4 +%95 = OpLoad %v4float %gl_FragCoord +%97 = OpBitcast %v4uint %95 +%98 = OpCompositeExtract %uint %97 0 +%99 = OpIAdd %uint %77 %uint_4 +%100 = OpAccessChain %_ptr_StorageBuffer_uint %73 %uint_1 %99 +OpStore %100 %98 +%101 = OpCompositeExtract %uint %97 1 +%103 = OpIAdd %uint %77 %uint_5 +%104 = OpAccessChain %_ptr_StorageBuffer_uint %73 %uint_1 %103 +OpStore %104 %101 +%106 = OpIAdd %uint %77 %uint_7 +%107 = OpAccessChain %_ptr_StorageBuffer_uint %73 %uint_1 %106 +OpStore %107 %67 +%109 = OpIAdd %uint %77 %uint_8 +%110 = OpAccessChain %_ptr_StorageBuffer_uint %73 %uint_1 %109 +OpStore %110 %68 +%112 = OpIAdd %uint %77 %uint_9 +%113 = OpAccessChain %_ptr_StorageBuffer_uint %73 %uint_1 %112 +OpStore %113 %69 +OpBranch %81 +%81 = OpLabel +OpReturn +OpFunctionEnd +%118 = OpFunction %uint None %119 +%120 = OpFunctionParameter %uint +%121 = OpFunctionParameter %uint +%122 = OpFunctionParameter %uint +%123 = OpFunctionParameter %uint +%124 = OpLabel +%125 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_0 %120 +%126 = OpLoad %uint %125 +%127 = OpIAdd %uint %126 %121 +%128 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_0 %127 +%129 = OpLoad %uint %128 +%130 = OpIAdd %uint %129 %122 +%131 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_0 %130 +%132 = OpLoad %uint %131 +%133 = OpIAdd %uint %132 %123 +%134 = OpAccessChain %_ptr_StorageBuffer_uint %48 %uint_0 %133 +%135 = OpLoad %uint %134 +OpReturnValue %135 +OpFunctionEnd +)"; + + // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck( + defs_before + func_before, defs_after + func_after + new_funcs, true, + true, 7u, 23u, true, true); +} + +TEST_F(InstBindlessTest, InstrumentInitCheckOnScalarDescriptor) { + // This test verifies that the pass will correctly instrument vanilla + // texture sample on a scalar descriptor with an initialization check if the + // input_init_enable argument is set to true. This can happen when the + // descriptor indexing extension is enabled in the API but the SPIR-V + // does not have the extension enabled because it does not contain a + // runtime array. This is the same shader as NoInstrumentNonBindless. + + const std::string defs_before = + R"(OpCapability Shader +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor +OpExecutionMode %MainPs OriginUpperLeft +OpSource HLSL 500 +OpName %MainPs "MainPs" +OpName %g_tColor "g_tColor" +OpName %g_sAniso "g_sAniso" +OpName %i_vTextureCoords "i.vTextureCoords" +OpName %_entryPointOutput_vColor "@entryPointOutput.vColor" +OpDecorate %g_tColor DescriptorSet 0 +OpDecorate %g_tColor Binding 0 +OpDecorate %g_sAniso DescriptorSet 0 +OpDecorate %g_sAniso Binding 0 +OpDecorate %i_vTextureCoords Location 0 +OpDecorate %_entryPointOutput_vColor Location 0 +%void = OpTypeVoid +%8 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v2float = OpTypeVector %float 2 +%v4float = OpTypeVector %float 4 +%12 = OpTypeImage %float 2D 0 0 0 1 Unknown +%_ptr_UniformConstant_12 = OpTypePointer UniformConstant %12 +%g_tColor = OpVariable %_ptr_UniformConstant_12 UniformConstant +%14 = OpTypeSampler +%_ptr_UniformConstant_14 = OpTypePointer UniformConstant %14 +%g_sAniso = OpVariable %_ptr_UniformConstant_14 UniformConstant +%16 = OpTypeSampledImage %12 +%_ptr_Input_v2float = OpTypePointer Input %v2float +%i_vTextureCoords = OpVariable %_ptr_Input_v2float Input +%_ptr_Output_v4float = OpTypePointer Output %v4float +%_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output +)"; + + const std::string defs_after = + R"(OpCapability Shader +OpExtension "SPV_KHR_storage_buffer_storage_class" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord +OpExecutionMode %MainPs OriginUpperLeft +OpSource HLSL 500 +OpName %MainPs "MainPs" +OpName %g_tColor "g_tColor" +OpName %g_sAniso "g_sAniso" +OpName %i_vTextureCoords "i.vTextureCoords" +OpName %_entryPointOutput_vColor "@entryPointOutput.vColor" +OpDecorate %g_tColor DescriptorSet 0 +OpDecorate %g_tColor Binding 0 +OpDecorate %g_sAniso DescriptorSet 0 +OpDecorate %g_sAniso Binding 0 +OpDecorate %i_vTextureCoords Location 0 +OpDecorate %_entryPointOutput_vColor Location 0 +OpDecorate %_runtimearr_uint ArrayStride 4 +OpDecorate %_struct_35 Block +OpMemberDecorate %_struct_35 0 Offset 0 +OpDecorate %37 DescriptorSet 7 +OpDecorate %37 Binding 1 +OpDecorate %_struct_67 Block +OpMemberDecorate %_struct_67 0 Offset 0 +OpMemberDecorate %_struct_67 1 Offset 4 +OpDecorate %69 DescriptorSet 7 +OpDecorate %69 Binding 0 +OpDecorate %gl_FragCoord BuiltIn FragCoord +%void = OpTypeVoid +%8 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v2float = OpTypeVector %float 2 +%v4float = OpTypeVector %float 4 +%12 = OpTypeImage %float 2D 0 0 0 1 Unknown +%_ptr_UniformConstant_12 = OpTypePointer UniformConstant %12 +%g_tColor = OpVariable %_ptr_UniformConstant_12 UniformConstant +%14 = OpTypeSampler +%_ptr_UniformConstant_14 = OpTypePointer UniformConstant %14 +%g_sAniso = OpVariable %_ptr_UniformConstant_14 UniformConstant +%16 = OpTypeSampledImage %12 +%_ptr_Input_v2float = OpTypePointer Input %v2float +%i_vTextureCoords = OpVariable %_ptr_Input_v2float Input +%_ptr_Output_v4float = OpTypePointer Output %v4float +%_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output +%uint = OpTypeInt 32 0 +%uint_0 = OpConstant %uint 0 +%28 = OpTypeFunction %uint %uint %uint %uint %uint +%_runtimearr_uint = OpTypeRuntimeArray %uint +%_struct_35 = OpTypeStruct %_runtimearr_uint +%_ptr_StorageBuffer__struct_35 = OpTypePointer StorageBuffer %_struct_35 +%37 = OpVariable %_ptr_StorageBuffer__struct_35 StorageBuffer +%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint +%bool = OpTypeBool +%uint_1 = OpConstant %uint 1 +%61 = OpTypeFunction %void %uint %uint %uint %uint +%_struct_67 = OpTypeStruct %uint %_runtimearr_uint +%_ptr_StorageBuffer__struct_67 = OpTypePointer StorageBuffer %_struct_67 +%69 = OpVariable %_ptr_StorageBuffer__struct_67 StorageBuffer +%uint_10 = OpConstant %uint 10 +%uint_4 = OpConstant %uint 4 +%uint_23 = OpConstant %uint 23 +%uint_2 = OpConstant %uint 2 +%uint_3 = OpConstant %uint 3 +%_ptr_Input_v4float = OpTypePointer Input %v4float +%gl_FragCoord = OpVariable %_ptr_Input_v4float Input +%v4uint = OpTypeVector %uint 4 +%uint_5 = OpConstant %uint 5 +%uint_7 = OpConstant %uint 7 +%uint_8 = OpConstant %uint 8 +%uint_9 = OpConstant %uint 9 +%uint_39 = OpConstant %uint 39 +%113 = OpConstantNull %v4float +)"; + + const std::string func_before = + R"(%MainPs = OpFunction %void None %8 +%19 = OpLabel +%20 = OpLoad %v2float %i_vTextureCoords +%21 = OpLoad %12 %g_tColor +%22 = OpLoad %14 %g_sAniso +%23 = OpSampledImage %16 %21 %22 +%24 = OpImageSampleImplicitLod %v4float %23 %20 +OpStore %_entryPointOutput_vColor %24 +OpReturn +OpFunctionEnd +)"; + + const std::string func_after = + R"(%MainPs = OpFunction %void None %8 +%19 = OpLabel +%20 = OpLoad %v2float %i_vTextureCoords +%21 = OpLoad %12 %g_tColor +%22 = OpLoad %14 %g_sAniso +%23 = OpSampledImage %16 %21 %22 +%50 = OpFunctionCall %uint %27 %uint_0 %uint_0 %uint_0 %uint_0 +%52 = OpINotEqual %bool %50 %uint_0 +OpSelectionMerge %54 None +OpBranchConditional %52 %55 %56 +%55 = OpLabel +%57 = OpLoad %12 %g_tColor +%58 = OpSampledImage %16 %57 %22 +%59 = OpImageSampleImplicitLod %v4float %58 %20 +OpBranch %54 +%56 = OpLabel +%112 = OpFunctionCall %void %60 %uint_39 %uint_1 %uint_0 %uint_0 +OpBranch %54 +%54 = OpLabel +%114 = OpPhi %v4float %59 %55 %113 %56 +OpStore %_entryPointOutput_vColor %114 +OpReturn +OpFunctionEnd +)"; + + const std::string new_funcs = + R"(%27 = OpFunction %uint None %28 +%29 = OpFunctionParameter %uint +%30 = OpFunctionParameter %uint +%31 = OpFunctionParameter %uint +%32 = OpFunctionParameter %uint +%33 = OpLabel +%39 = OpAccessChain %_ptr_StorageBuffer_uint %37 %uint_0 %29 +%40 = OpLoad %uint %39 +%41 = OpIAdd %uint %40 %30 +%42 = OpAccessChain %_ptr_StorageBuffer_uint %37 %uint_0 %41 +%43 = OpLoad %uint %42 +%44 = OpIAdd %uint %43 %31 +%45 = OpAccessChain %_ptr_StorageBuffer_uint %37 %uint_0 %44 +%46 = OpLoad %uint %45 +%47 = OpIAdd %uint %46 %32 +%48 = OpAccessChain %_ptr_StorageBuffer_uint %37 %uint_0 %47 +%49 = OpLoad %uint %48 +OpReturnValue %49 +OpFunctionEnd +%60 = OpFunction %void None %61 +%62 = OpFunctionParameter %uint +%63 = OpFunctionParameter %uint +%64 = OpFunctionParameter %uint +%65 = OpFunctionParameter %uint +%66 = OpLabel +%70 = OpAccessChain %_ptr_StorageBuffer_uint %69 %uint_0 +%73 = OpAtomicIAdd %uint %70 %uint_4 %uint_0 %uint_10 +%74 = OpIAdd %uint %73 %uint_10 +%75 = OpArrayLength %uint %69 1 +%76 = OpULessThanEqual %bool %74 %75 +OpSelectionMerge %77 None +OpBranchConditional %76 %78 %77 +%78 = OpLabel +%79 = OpIAdd %uint %73 %uint_0 +%80 = OpAccessChain %_ptr_StorageBuffer_uint %69 %uint_1 %79 +OpStore %80 %uint_10 +%82 = OpIAdd %uint %73 %uint_1 +%83 = OpAccessChain %_ptr_StorageBuffer_uint %69 %uint_1 %82 +OpStore %83 %uint_23 +%85 = OpIAdd %uint %73 %uint_2 +%86 = OpAccessChain %_ptr_StorageBuffer_uint %69 %uint_1 %85 +OpStore %86 %62 +%88 = OpIAdd %uint %73 %uint_3 +%89 = OpAccessChain %_ptr_StorageBuffer_uint %69 %uint_1 %88 +OpStore %89 %uint_4 +%92 = OpLoad %v4float %gl_FragCoord +%94 = OpBitcast %v4uint %92 +%95 = OpCompositeExtract %uint %94 0 +%96 = OpIAdd %uint %73 %uint_4 +%97 = OpAccessChain %_ptr_StorageBuffer_uint %69 %uint_1 %96 +OpStore %97 %95 +%98 = OpCompositeExtract %uint %94 1 +%100 = OpIAdd %uint %73 %uint_5 +%101 = OpAccessChain %_ptr_StorageBuffer_uint %69 %uint_1 %100 +OpStore %101 %98 +%103 = OpIAdd %uint %73 %uint_7 +%104 = OpAccessChain %_ptr_StorageBuffer_uint %69 %uint_1 %103 +OpStore %104 %63 +%106 = OpIAdd %uint %73 %uint_8 +%107 = OpAccessChain %_ptr_StorageBuffer_uint %69 %uint_1 %106 +OpStore %107 %64 +%109 = OpIAdd %uint %73 %uint_9 +%110 = OpAccessChain %_ptr_StorageBuffer_uint %69 %uint_1 %109 +OpStore %110 %65 +OpBranch %77 +%77 = OpLabel +OpReturn +OpFunctionEnd +)"; + + // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck( + defs_before + func_before, defs_after + func_after + new_funcs, true, + true, 7u, 23u, true, true); +} + +TEST_F(InstBindlessTest, SPV14AddToEntryPoint) { + const std::string text = R"( +; CHECK: OpEntryPoint Fragment {{%\w+}} "foo" {{%\w+}} {{%\w+}} {{%\w+}} [[v1:%\w+]] [[v2:%\w+]] +; CHECK: OpDecorate [[v1]] DescriptorSet 7 +; CHECK: OpDecorate [[v2]] DescriptorSet 7 +; CHECK: [[v1]] = OpVariable {{%\w+}} StorageBuffer +; CHECK: [[v2]] = OpVariable {{%\w+}} StorageBuffer +OpCapability Shader +OpExtension "SPV_EXT_descriptor_indexing" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %foo "foo" %gid %image_var %sampler_var +OpExecutionMode %foo OriginUpperLeft +OpDecorate %image_var DescriptorSet 0 +OpDecorate %image_var Binding 0 +OpDecorate %sampler_var DescriptorSet 0 +OpDecorate %sampler_var Binding 1 +OpDecorate %gid DescriptorSet 0 +OpDecorate %gid Binding 2 +OpDecorate %struct Block +OpMemberDecorate %struct 0 Offset 0 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%v3int = OpTypeVector %int 3 +%float = OpTypeFloat 32 +%v3float = OpTypeVector %float 3 +%v4float = OpTypeVector %float 4 +%struct = OpTypeStruct %v3int +%ptr_ssbo_struct = OpTypePointer StorageBuffer %struct +%ptr_ssbo_v3int = OpTypePointer StorageBuffer %v3int +%gid = OpVariable %ptr_ssbo_struct StorageBuffer +%image = OpTypeImage %float 3D 0 0 0 1 Unknown +%ptr_uc_image = OpTypePointer UniformConstant %image +%sampler = OpTypeSampler +%ptr_uc_sampler = OpTypePointer UniformConstant %sampler +%image_var = OpVariable %ptr_uc_image UniformConstant +%sampler_var = OpVariable %ptr_uc_sampler UniformConstant +%sampled = OpTypeSampledImage %image +%void_fn = OpTypeFunction %void +%foo = OpFunction %void None %void_fn +%entry = OpLabel +%ld_image = OpLoad %image %image_var +%ld_sampler = OpLoad %sampler %sampler_var +%gep = OpAccessChain %ptr_ssbo_v3int %gid %int_0 +%ld_gid = OpLoad %v3int %gep +%convert = OpConvertUToF %v3float %ld_gid +%sampled_image = OpSampledImage %sampled %ld_image %ld_sampler +%sample = OpImageSampleImplicitLod %v4float %sampled_image %convert +OpReturn +OpFunctionEnd +)"; + + SetTargetEnv(SPV_ENV_VULKAN_1_1_SPIRV_1_4); + SinglePassRunAndMatch(text, true, 7u, 23u, true, true); +} + +TEST_F(InstBindlessTest, SPV14AddToEntryPoints) { + const std::string text = R"( +; CHECK: OpEntryPoint Fragment {{%\w+}} "foo" {{%\w+}} {{%\w+}} {{%\w+}} [[v1:%\w+]] [[v2:%\w+]] +; CHECK: OpEntryPoint Fragment {{%\w+}} "bar" {{%\w+}} {{%\w+}} {{%\w+}} [[v1:%\w+]] [[v2:%\w+]] +; CHECK: OpDecorate [[v1]] DescriptorSet 7 +; CHECK: OpDecorate [[v2]] DescriptorSet 7 +; CHECK: [[v1]] = OpVariable {{%\w+}} StorageBuffer +; CHECK: [[v2]] = OpVariable {{%\w+}} StorageBuffer +OpCapability Shader +OpExtension "SPV_EXT_descriptor_indexing" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %foo "foo" %gid %image_var %sampler_var +OpEntryPoint Fragment %foo "bar" %gid %image_var %sampler_var +OpExecutionMode %foo OriginUpperLeft +OpDecorate %image_var DescriptorSet 0 +OpDecorate %image_var Binding 0 +OpDecorate %sampler_var DescriptorSet 0 +OpDecorate %sampler_var Binding 1 +OpDecorate %gid DescriptorSet 0 +OpDecorate %gid Binding 2 +OpDecorate %struct Block +OpMemberDecorate %struct 0 Offset 0 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%v3int = OpTypeVector %int 3 +%float = OpTypeFloat 32 +%v3float = OpTypeVector %float 3 +%v4float = OpTypeVector %float 4 +%struct = OpTypeStruct %v3int +%ptr_ssbo_struct = OpTypePointer StorageBuffer %struct +%ptr_ssbo_v3int = OpTypePointer StorageBuffer %v3int +%gid = OpVariable %ptr_ssbo_struct StorageBuffer +%image = OpTypeImage %float 3D 0 0 0 1 Unknown +%ptr_uc_image = OpTypePointer UniformConstant %image +%sampler = OpTypeSampler +%ptr_uc_sampler = OpTypePointer UniformConstant %sampler +%image_var = OpVariable %ptr_uc_image UniformConstant +%sampler_var = OpVariable %ptr_uc_sampler UniformConstant +%sampled = OpTypeSampledImage %image +%void_fn = OpTypeFunction %void +%foo = OpFunction %void None %void_fn +%entry = OpLabel +%ld_image = OpLoad %image %image_var +%ld_sampler = OpLoad %sampler %sampler_var +%gep = OpAccessChain %ptr_ssbo_v3int %gid %int_0 +%ld_gid = OpLoad %v3int %gep +%convert = OpConvertUToF %v3float %ld_gid +%sampled_image = OpSampledImage %sampled %ld_image %ld_sampler +%sample = OpImageSampleImplicitLod %v4float %sampled_image %convert +OpReturn +OpFunctionEnd +)"; + + SetTargetEnv(SPV_ENV_VULKAN_1_1_SPIRV_1_4); + SinglePassRunAndMatch(text, true, 7u, 23u, true, true); +} + +TEST_F(InstBindlessTest, InstBoundsAndInitLoadUnsizedUBOArray) { + // #version 450 + // #extension GL_EXT_nonuniform_qualifier : enable + // + // layout(location=0) in nonuniformEXT flat int nu_ii; + // layout(location=0) out float b; + // + // layout(binding=3) uniform uname { float a; } uniformBuffer[]; + // + // void main() + // { + // b = uniformBuffer[nu_ii].a; + // } + + const std::string defs_before = + R"(OpCapability Shader +OpCapability ShaderNonUniform +OpCapability RuntimeDescriptorArray +OpCapability UniformBufferArrayNonUniformIndexing +OpExtension "SPV_EXT_descriptor_indexing" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %b %nu_ii +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 450 +OpSourceExtension "GL_EXT_nonuniform_qualifier" +OpName %main "main" +OpName %b "b" +OpName %uname "uname" +OpMemberName %uname 0 "a" +OpName %uniformBuffer "uniformBuffer" +OpName %nu_ii "nu_ii" +OpDecorate %b Location 0 +OpMemberDecorate %uname 0 Offset 0 +OpDecorate %uname Block +OpDecorate %uniformBuffer DescriptorSet 0 +OpDecorate %uniformBuffer Binding 3 +OpDecorate %nu_ii Flat +OpDecorate %nu_ii Location 0 +OpDecorate %nu_ii NonUniform +OpDecorate %16 NonUniform +OpDecorate %20 NonUniform +%void = OpTypeVoid +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 +%_ptr_Output_float = OpTypePointer Output %float +%b = OpVariable %_ptr_Output_float Output +%uname = OpTypeStruct %float +%_runtimearr_uname = OpTypeRuntimeArray %uname +%_ptr_Uniform__runtimearr_uname = OpTypePointer Uniform %_runtimearr_uname +%uniformBuffer = OpVariable %_ptr_Uniform__runtimearr_uname Uniform +%int = OpTypeInt 32 1 +%_ptr_Input_int = OpTypePointer Input %int +%nu_ii = OpVariable %_ptr_Input_int Input +%int_0 = OpConstant %int 0 +%_ptr_Uniform_float = OpTypePointer Uniform %float +)"; + + const std::string defs_after = + R"(OpCapability Shader +OpCapability ShaderNonUniform +OpCapability RuntimeDescriptorArray +OpCapability UniformBufferArrayNonUniformIndexing +OpExtension "SPV_EXT_descriptor_indexing" +OpExtension "SPV_KHR_storage_buffer_storage_class" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %b %nu_ii %gl_FragCoord +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 450 +OpSourceExtension "GL_EXT_nonuniform_qualifier" +OpName %main "main" +OpName %b "b" +OpName %uname "uname" +OpMemberName %uname 0 "a" +OpName %uniformBuffer "uniformBuffer" +OpName %nu_ii "nu_ii" +OpDecorate %b Location 0 +OpMemberDecorate %uname 0 Offset 0 +OpDecorate %uname Block +OpDecorate %uniformBuffer DescriptorSet 0 +OpDecorate %uniformBuffer Binding 3 +OpDecorate %nu_ii Flat +OpDecorate %nu_ii Location 0 +OpDecorate %nu_ii NonUniform +OpDecorate %7 NonUniform +OpDecorate %102 NonUniform +OpDecorate %_runtimearr_uint ArrayStride 4 +OpDecorate %_struct_31 Block +OpMemberDecorate %_struct_31 0 Offset 0 +OpDecorate %33 DescriptorSet 7 +OpDecorate %33 Binding 1 +OpDecorate %130 NonUniform +OpDecorate %_struct_55 Block +OpMemberDecorate %_struct_55 0 Offset 0 +OpMemberDecorate %_struct_55 1 Offset 4 +OpDecorate %57 DescriptorSet 7 +OpDecorate %57 Binding 0 +OpDecorate %gl_FragCoord BuiltIn FragCoord +OpDecorate %127 NonUniform +%void = OpTypeVoid +%10 = OpTypeFunction %void +%float = OpTypeFloat 32 +%_ptr_Output_float = OpTypePointer Output %float +%b = OpVariable %_ptr_Output_float Output +%uname = OpTypeStruct %float +%_runtimearr_uname = OpTypeRuntimeArray %uname +%_ptr_Uniform__runtimearr_uname = OpTypePointer Uniform %_runtimearr_uname +%uniformBuffer = OpVariable %_ptr_Uniform__runtimearr_uname Uniform +%int = OpTypeInt 32 1 +%_ptr_Input_int = OpTypePointer Input %int +%nu_ii = OpVariable %_ptr_Input_int Input +%int_0 = OpConstant %int 0 +%_ptr_Uniform_float = OpTypePointer Uniform %float +%uint = OpTypeInt 32 0 +%uint_0 = OpConstant %uint 0 +%uint_1 = OpConstant %uint 1 +%uint_3 = OpConstant %uint 3 +%26 = OpTypeFunction %uint %uint %uint +%_runtimearr_uint = OpTypeRuntimeArray %uint +%_struct_31 = OpTypeStruct %_runtimearr_uint +%_ptr_StorageBuffer__struct_31 = OpTypePointer StorageBuffer %_struct_31 +%33 = OpVariable %_ptr_StorageBuffer__struct_31 StorageBuffer +%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint +%bool = OpTypeBool +%49 = OpTypeFunction %void %uint %uint %uint %uint +%_struct_55 = OpTypeStruct %uint %_runtimearr_uint +%_ptr_StorageBuffer__struct_55 = OpTypePointer StorageBuffer %_struct_55 +%57 = OpVariable %_ptr_StorageBuffer__struct_55 StorageBuffer +%uint_10 = OpConstant %uint 10 +%uint_4 = OpConstant %uint 4 +%uint_23 = OpConstant %uint 23 +%uint_2 = OpConstant %uint 2 +%v4float = OpTypeVector %float 4 +%_ptr_Input_v4float = OpTypePointer Input %v4float +%gl_FragCoord = OpVariable %_ptr_Input_v4float Input +%v4uint = OpTypeVector %uint 4 +%uint_5 = OpConstant %uint 5 +%uint_7 = OpConstant %uint 7 +%uint_8 = OpConstant %uint 8 +%uint_9 = OpConstant %uint 9 +%uint_45 = OpConstant %uint 45 +%101 = OpConstantNull %float +%105 = OpTypeFunction %uint %uint %uint %uint %uint +)"; + + const std::string func_before = + R"(%main = OpFunction %void None %3 +%5 = OpLabel +%16 = OpLoad %int %nu_ii +%19 = OpAccessChain %_ptr_Uniform_float %uniformBuffer %16 %int_0 +%20 = OpLoad %float %19 +OpStore %b %20 +OpReturn +OpFunctionEnd +)"; + + const std::string func_after = + R"(%main = OpFunction %void None %10 +%19 = OpLabel +%7 = OpLoad %int %nu_ii +%20 = OpAccessChain %_ptr_Uniform_float %uniformBuffer %7 %int_0 +%40 = OpFunctionCall %uint %25 %uint_1 %uint_3 +%42 = OpULessThan %bool %7 %40 +OpSelectionMerge %43 None +OpBranchConditional %42 %44 %45 +%44 = OpLabel +%103 = OpBitcast %uint %7 +%122 = OpFunctionCall %uint %104 %uint_0 %uint_0 %uint_3 %103 +%123 = OpINotEqual %bool %122 %uint_0 +OpSelectionMerge %124 None +OpBranchConditional %123 %125 %126 +%125 = OpLabel +%127 = OpLoad %float %20 +OpBranch %124 +%126 = OpLabel +%128 = OpBitcast %uint %7 +%129 = OpFunctionCall %void %48 %uint_45 %uint_1 %128 %uint_0 +OpBranch %124 +%124 = OpLabel +%130 = OpPhi %float %127 %125 %101 %126 +OpBranch %43 +%45 = OpLabel +%47 = OpBitcast %uint %7 +%100 = OpFunctionCall %void %48 %uint_45 %uint_0 %47 %40 +OpBranch %43 +%43 = OpLabel +%102 = OpPhi %float %130 %124 %101 %45 +OpStore %b %102 +OpReturn +OpFunctionEnd +)"; + + const std::string new_funcs = + R"(%25 = OpFunction %uint None %26 +%27 = OpFunctionParameter %uint +%28 = OpFunctionParameter %uint +%29 = OpLabel +%35 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %27 +%36 = OpLoad %uint %35 +%37 = OpIAdd %uint %36 %28 +%38 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %37 +%39 = OpLoad %uint %38 +OpReturnValue %39 +OpFunctionEnd +%48 = OpFunction %void None %49 +%50 = OpFunctionParameter %uint +%51 = OpFunctionParameter %uint +%52 = OpFunctionParameter %uint +%53 = OpFunctionParameter %uint +%54 = OpLabel +%58 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_0 +%61 = OpAtomicIAdd %uint %58 %uint_4 %uint_0 %uint_10 +%62 = OpIAdd %uint %61 %uint_10 +%63 = OpArrayLength %uint %57 1 +%64 = OpULessThanEqual %bool %62 %63 +OpSelectionMerge %65 None +OpBranchConditional %64 %66 %65 +%66 = OpLabel +%67 = OpIAdd %uint %61 %uint_0 +%68 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %67 +OpStore %68 %uint_10 +%70 = OpIAdd %uint %61 %uint_1 +%71 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %70 +OpStore %71 %uint_23 +%73 = OpIAdd %uint %61 %uint_2 +%74 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %73 +OpStore %74 %50 +%75 = OpIAdd %uint %61 %uint_3 +%76 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %75 +OpStore %76 %uint_4 +%80 = OpLoad %v4float %gl_FragCoord +%82 = OpBitcast %v4uint %80 +%83 = OpCompositeExtract %uint %82 0 +%84 = OpIAdd %uint %61 %uint_4 +%85 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %84 +OpStore %85 %83 +%86 = OpCompositeExtract %uint %82 1 +%88 = OpIAdd %uint %61 %uint_5 +%89 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %88 +OpStore %89 %86 +%91 = OpIAdd %uint %61 %uint_7 +%92 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %91 +OpStore %92 %51 +%94 = OpIAdd %uint %61 %uint_8 +%95 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %94 +OpStore %95 %52 +%97 = OpIAdd %uint %61 %uint_9 +%98 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %97 +OpStore %98 %53 +OpBranch %65 +%65 = OpLabel +OpReturn +OpFunctionEnd +%104 = OpFunction %uint None %105 +%106 = OpFunctionParameter %uint +%107 = OpFunctionParameter %uint +%108 = OpFunctionParameter %uint +%109 = OpFunctionParameter %uint +%110 = OpLabel +%111 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %106 +%112 = OpLoad %uint %111 +%113 = OpIAdd %uint %112 %107 +%114 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %113 +%115 = OpLoad %uint %114 +%116 = OpIAdd %uint %115 %108 +%117 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %116 +%118 = OpLoad %uint %117 +%119 = OpIAdd %uint %118 %109 +%120 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %119 +%121 = OpLoad %uint %120 +OpReturnValue %121 +OpFunctionEnd +)"; + + // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck( + defs_before + func_before, defs_after + func_after + new_funcs, true, + true, 7u, 23u, true, true); +} + +TEST_F(InstBindlessTest, InstBoundsAndInitLoadUnsizedSSBOArrayDeprecated) { + // #version 450 + // #extension GL_EXT_nonuniform_qualifier : enable + // + // layout(location=0) in nonuniformEXT flat int nu_ii; + // layout(location=0) out float b; + // + // layout(binding=3) buffer bname { float b; } storageBuffer[]; + // + // void main() + // { + // b = storageBuffer[nu_ii].b; + // } + + const std::string defs_before = + R"(OpCapability Shader +OpCapability ShaderNonUniform +OpCapability RuntimeDescriptorArray +OpCapability StorageBufferArrayNonUniformIndexing +OpExtension "SPV_EXT_descriptor_indexing" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %b %nu_ii +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 450 +OpSourceExtension "GL_EXT_nonuniform_qualifier" +OpName %main "main" +OpName %b "b" +OpName %bname "bname" +OpMemberName %bname 0 "a" +OpName %storageBuffer "storageBuffer" +OpName %nu_ii "nu_ii" +OpDecorate %b Location 0 +OpMemberDecorate %bname 0 Offset 0 +OpDecorate %bname Block +OpDecorate %storageBuffer DescriptorSet 0 +OpDecorate %storageBuffer Binding 3 +OpDecorate %nu_ii Flat +OpDecorate %nu_ii Location 0 +OpDecorate %nu_ii NonUniform +OpDecorate %16 NonUniform +OpDecorate %20 NonUniform +%void = OpTypeVoid +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 +%_ptr_Output_float = OpTypePointer Output %float +%b = OpVariable %_ptr_Output_float Output +%bname = OpTypeStruct %float +%_runtimearr_bname = OpTypeRuntimeArray %bname +%_ptr_StorageBuffer__runtimearr_bname = OpTypePointer StorageBuffer %_runtimearr_bname +%storageBuffer = OpVariable %_ptr_StorageBuffer__runtimearr_bname StorageBuffer +%int = OpTypeInt 32 1 +%_ptr_Input_int = OpTypePointer Input %int +%nu_ii = OpVariable %_ptr_Input_int Input +%int_0 = OpConstant %int 0 +%_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float +)"; + + const std::string defs_after = + R"(OpCapability Shader +OpCapability ShaderNonUniform +OpCapability RuntimeDescriptorArray +OpCapability StorageBufferArrayNonUniformIndexing +OpExtension "SPV_EXT_descriptor_indexing" +OpExtension "SPV_KHR_storage_buffer_storage_class" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %b %nu_ii %gl_FragCoord +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 450 +OpSourceExtension "GL_EXT_nonuniform_qualifier" +OpName %main "main" +OpName %b "b" +OpName %bname "bname" +OpMemberName %bname 0 "a" +OpName %storageBuffer "storageBuffer" +OpName %nu_ii "nu_ii" +OpDecorate %b Location 0 +OpMemberDecorate %bname 0 Offset 0 +OpDecorate %bname Block +OpDecorate %storageBuffer DescriptorSet 0 +OpDecorate %storageBuffer Binding 3 +OpDecorate %nu_ii Flat +OpDecorate %nu_ii Location 0 +OpDecorate %nu_ii NonUniform +OpDecorate %7 NonUniform +OpDecorate %102 NonUniform +OpDecorate %_runtimearr_uint ArrayStride 4 +OpDecorate %_struct_31 Block +OpMemberDecorate %_struct_31 0 Offset 0 +OpDecorate %33 DescriptorSet 7 +OpDecorate %33 Binding 1 +OpDecorate %130 NonUniform +OpDecorate %_struct_55 Block +OpMemberDecorate %_struct_55 0 Offset 0 +OpMemberDecorate %_struct_55 1 Offset 4 +OpDecorate %57 DescriptorSet 7 +OpDecorate %57 Binding 0 +OpDecorate %gl_FragCoord BuiltIn FragCoord +OpDecorate %127 NonUniform +%void = OpTypeVoid +%10 = OpTypeFunction %void +%float = OpTypeFloat 32 +%_ptr_Output_float = OpTypePointer Output %float +%b = OpVariable %_ptr_Output_float Output +%bname = OpTypeStruct %float +%_runtimearr_bname = OpTypeRuntimeArray %bname +%_ptr_StorageBuffer__runtimearr_bname = OpTypePointer StorageBuffer %_runtimearr_bname +%storageBuffer = OpVariable %_ptr_StorageBuffer__runtimearr_bname StorageBuffer +%int = OpTypeInt 32 1 +%_ptr_Input_int = OpTypePointer Input %int +%nu_ii = OpVariable %_ptr_Input_int Input +%int_0 = OpConstant %int 0 +%_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float +%uint = OpTypeInt 32 0 +%uint_0 = OpConstant %uint 0 +%uint_1 = OpConstant %uint 1 +%uint_3 = OpConstant %uint 3 +%26 = OpTypeFunction %uint %uint %uint +%_runtimearr_uint = OpTypeRuntimeArray %uint +%_struct_31 = OpTypeStruct %_runtimearr_uint +%_ptr_StorageBuffer__struct_31 = OpTypePointer StorageBuffer %_struct_31 +%33 = OpVariable %_ptr_StorageBuffer__struct_31 StorageBuffer +%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint +%bool = OpTypeBool +%49 = OpTypeFunction %void %uint %uint %uint %uint +%_struct_55 = OpTypeStruct %uint %_runtimearr_uint +%_ptr_StorageBuffer__struct_55 = OpTypePointer StorageBuffer %_struct_55 +%57 = OpVariable %_ptr_StorageBuffer__struct_55 StorageBuffer +%uint_10 = OpConstant %uint 10 +%uint_4 = OpConstant %uint 4 +%uint_23 = OpConstant %uint 23 +%uint_2 = OpConstant %uint 2 +%v4float = OpTypeVector %float 4 +%_ptr_Input_v4float = OpTypePointer Input %v4float +%gl_FragCoord = OpVariable %_ptr_Input_v4float Input +%v4uint = OpTypeVector %uint 4 +%uint_5 = OpConstant %uint 5 +%uint_7 = OpConstant %uint 7 +%uint_8 = OpConstant %uint 8 +%uint_9 = OpConstant %uint 9 +%uint_45 = OpConstant %uint 45 +%101 = OpConstantNull %float +%105 = OpTypeFunction %uint %uint %uint %uint %uint +)"; + + const std::string func_before = + R"(%main = OpFunction %void None %3 +%5 = OpLabel +%16 = OpLoad %int %nu_ii +%19 = OpAccessChain %_ptr_StorageBuffer_float %storageBuffer %16 %int_0 +%20 = OpLoad %float %19 +OpStore %b %20 +OpReturn +OpFunctionEnd +)"; + + const std::string func_after = + R"(%main = OpFunction %void None %10 +%19 = OpLabel +%7 = OpLoad %int %nu_ii +%20 = OpAccessChain %_ptr_StorageBuffer_float %storageBuffer %7 %int_0 +%40 = OpFunctionCall %uint %25 %uint_1 %uint_3 +%42 = OpULessThan %bool %7 %40 +OpSelectionMerge %43 None +OpBranchConditional %42 %44 %45 +%44 = OpLabel +%103 = OpBitcast %uint %7 +%122 = OpFunctionCall %uint %104 %uint_0 %uint_0 %uint_3 %103 +%123 = OpINotEqual %bool %122 %uint_0 +OpSelectionMerge %124 None +OpBranchConditional %123 %125 %126 +%125 = OpLabel +%127 = OpLoad %float %20 +OpBranch %124 +%126 = OpLabel +%128 = OpBitcast %uint %7 +%129 = OpFunctionCall %void %48 %uint_45 %uint_1 %128 %uint_0 +OpBranch %124 +%124 = OpLabel +%130 = OpPhi %float %127 %125 %101 %126 +OpBranch %43 +%45 = OpLabel +%47 = OpBitcast %uint %7 +%100 = OpFunctionCall %void %48 %uint_45 %uint_0 %47 %40 +OpBranch %43 +%43 = OpLabel +%102 = OpPhi %float %130 %124 %101 %45 +OpStore %b %102 +OpReturn +OpFunctionEnd +)"; + + const std::string new_funcs = + R"(%25 = OpFunction %uint None %26 +%27 = OpFunctionParameter %uint +%28 = OpFunctionParameter %uint +%29 = OpLabel +%35 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %27 +%36 = OpLoad %uint %35 +%37 = OpIAdd %uint %36 %28 +%38 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %37 +%39 = OpLoad %uint %38 +OpReturnValue %39 +OpFunctionEnd +%48 = OpFunction %void None %49 +%50 = OpFunctionParameter %uint +%51 = OpFunctionParameter %uint +%52 = OpFunctionParameter %uint +%53 = OpFunctionParameter %uint +%54 = OpLabel +%58 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_0 +%61 = OpAtomicIAdd %uint %58 %uint_4 %uint_0 %uint_10 +%62 = OpIAdd %uint %61 %uint_10 +%63 = OpArrayLength %uint %57 1 +%64 = OpULessThanEqual %bool %62 %63 +OpSelectionMerge %65 None +OpBranchConditional %64 %66 %65 +%66 = OpLabel +%67 = OpIAdd %uint %61 %uint_0 +%68 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %67 +OpStore %68 %uint_10 +%70 = OpIAdd %uint %61 %uint_1 +%71 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %70 +OpStore %71 %uint_23 +%73 = OpIAdd %uint %61 %uint_2 +%74 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %73 +OpStore %74 %50 +%75 = OpIAdd %uint %61 %uint_3 +%76 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %75 +OpStore %76 %uint_4 +%80 = OpLoad %v4float %gl_FragCoord +%82 = OpBitcast %v4uint %80 +%83 = OpCompositeExtract %uint %82 0 +%84 = OpIAdd %uint %61 %uint_4 +%85 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %84 +OpStore %85 %83 +%86 = OpCompositeExtract %uint %82 1 +%88 = OpIAdd %uint %61 %uint_5 +%89 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %88 +OpStore %89 %86 +%91 = OpIAdd %uint %61 %uint_7 +%92 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %91 +OpStore %92 %51 +%94 = OpIAdd %uint %61 %uint_8 +%95 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %94 +OpStore %95 %52 +%97 = OpIAdd %uint %61 %uint_9 +%98 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %97 +OpStore %98 %53 +OpBranch %65 +%65 = OpLabel +OpReturn +OpFunctionEnd +%104 = OpFunction %uint None %105 +%106 = OpFunctionParameter %uint +%107 = OpFunctionParameter %uint +%108 = OpFunctionParameter %uint +%109 = OpFunctionParameter %uint +%110 = OpLabel +%111 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %106 +%112 = OpLoad %uint %111 +%113 = OpIAdd %uint %112 %107 +%114 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %113 +%115 = OpLoad %uint %114 +%116 = OpIAdd %uint %115 %108 +%117 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %116 +%118 = OpLoad %uint %117 +%119 = OpIAdd %uint %118 %109 +%120 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %119 +%121 = OpLoad %uint %120 +OpReturnValue %121 +OpFunctionEnd +)"; + + // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck( + defs_before + func_before, defs_after + func_after + new_funcs, true, + true, 7u, 23u, true, true); +} + +TEST_F(InstBindlessTest, InstBoundsAndInitLoadUnsizedSSBOArray) { + // Same as Deprecated but declaring as StorageBuffer Block + + const std::string defs_before = + R"(OpCapability Shader +OpCapability ShaderNonUniform +OpCapability RuntimeDescriptorArray +OpCapability StorageBufferArrayNonUniformIndexing +OpExtension "SPV_EXT_descriptor_indexing" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %b %nu_ii +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 450 +OpSourceExtension "GL_EXT_nonuniform_qualifier" +OpName %main "main" +OpName %b "b" +OpName %bname "bname" +OpMemberName %bname 0 "a" +OpName %storageBuffer "storageBuffer" +OpName %nu_ii "nu_ii" +OpDecorate %b Location 0 +OpMemberDecorate %bname 0 Offset 0 +OpDecorate %bname Block +OpDecorate %storageBuffer DescriptorSet 0 +OpDecorate %storageBuffer Binding 3 +OpDecorate %nu_ii Flat +OpDecorate %nu_ii Location 0 +OpDecorate %nu_ii NonUniform +OpDecorate %16 NonUniform +OpDecorate %20 NonUniform +%void = OpTypeVoid +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 +%_ptr_Output_float = OpTypePointer Output %float +%b = OpVariable %_ptr_Output_float Output +%bname = OpTypeStruct %float +%_runtimearr_bname = OpTypeRuntimeArray %bname +%_ptr_StorageBuffer__runtimearr_bname = OpTypePointer StorageBuffer %_runtimearr_bname +%storageBuffer = OpVariable %_ptr_StorageBuffer__runtimearr_bname StorageBuffer +%int = OpTypeInt 32 1 +%_ptr_Input_int = OpTypePointer Input %int +%nu_ii = OpVariable %_ptr_Input_int Input +%int_0 = OpConstant %int 0 +%_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float +)"; + + const std::string defs_after = + R"(OpCapability Shader +OpCapability ShaderNonUniform +OpCapability RuntimeDescriptorArray +OpCapability StorageBufferArrayNonUniformIndexing +OpExtension "SPV_EXT_descriptor_indexing" +OpExtension "SPV_KHR_storage_buffer_storage_class" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %b %nu_ii %gl_FragCoord +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 450 +OpSourceExtension "GL_EXT_nonuniform_qualifier" +OpName %main "main" +OpName %b "b" +OpName %bname "bname" +OpMemberName %bname 0 "a" +OpName %storageBuffer "storageBuffer" +OpName %nu_ii "nu_ii" +OpDecorate %b Location 0 +OpMemberDecorate %bname 0 Offset 0 +OpDecorate %bname Block +OpDecorate %storageBuffer DescriptorSet 0 +OpDecorate %storageBuffer Binding 3 +OpDecorate %nu_ii Flat +OpDecorate %nu_ii Location 0 +OpDecorate %nu_ii NonUniform +OpDecorate %7 NonUniform +OpDecorate %102 NonUniform +OpDecorate %_runtimearr_uint ArrayStride 4 +OpDecorate %_struct_31 Block +OpMemberDecorate %_struct_31 0 Offset 0 +OpDecorate %33 DescriptorSet 7 +OpDecorate %33 Binding 1 +OpDecorate %130 NonUniform +OpDecorate %_struct_55 Block +OpMemberDecorate %_struct_55 0 Offset 0 +OpMemberDecorate %_struct_55 1 Offset 4 +OpDecorate %57 DescriptorSet 7 +OpDecorate %57 Binding 0 +OpDecorate %gl_FragCoord BuiltIn FragCoord +OpDecorate %127 NonUniform +%void = OpTypeVoid +%10 = OpTypeFunction %void +%float = OpTypeFloat 32 +%_ptr_Output_float = OpTypePointer Output %float +%b = OpVariable %_ptr_Output_float Output +%bname = OpTypeStruct %float +%_runtimearr_bname = OpTypeRuntimeArray %bname +%_ptr_StorageBuffer__runtimearr_bname = OpTypePointer StorageBuffer %_runtimearr_bname +%storageBuffer = OpVariable %_ptr_StorageBuffer__runtimearr_bname StorageBuffer +%int = OpTypeInt 32 1 +%_ptr_Input_int = OpTypePointer Input %int +%nu_ii = OpVariable %_ptr_Input_int Input +%int_0 = OpConstant %int 0 +%_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float +%uint = OpTypeInt 32 0 +%uint_0 = OpConstant %uint 0 +%uint_1 = OpConstant %uint 1 +%uint_3 = OpConstant %uint 3 +%26 = OpTypeFunction %uint %uint %uint +%_runtimearr_uint = OpTypeRuntimeArray %uint +%_struct_31 = OpTypeStruct %_runtimearr_uint +%_ptr_StorageBuffer__struct_31 = OpTypePointer StorageBuffer %_struct_31 +%33 = OpVariable %_ptr_StorageBuffer__struct_31 StorageBuffer +%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint +%bool = OpTypeBool +%49 = OpTypeFunction %void %uint %uint %uint %uint +%_struct_55 = OpTypeStruct %uint %_runtimearr_uint +%_ptr_StorageBuffer__struct_55 = OpTypePointer StorageBuffer %_struct_55 +%57 = OpVariable %_ptr_StorageBuffer__struct_55 StorageBuffer +%uint_10 = OpConstant %uint 10 +%uint_4 = OpConstant %uint 4 +%uint_23 = OpConstant %uint 23 +%uint_2 = OpConstant %uint 2 +%v4float = OpTypeVector %float 4 +%_ptr_Input_v4float = OpTypePointer Input %v4float +%gl_FragCoord = OpVariable %_ptr_Input_v4float Input +%v4uint = OpTypeVector %uint 4 +%uint_5 = OpConstant %uint 5 +%uint_7 = OpConstant %uint 7 +%uint_8 = OpConstant %uint 8 +%uint_9 = OpConstant %uint 9 +%uint_45 = OpConstant %uint 45 +%101 = OpConstantNull %float +%105 = OpTypeFunction %uint %uint %uint %uint %uint +)"; + + const std::string func_before = + R"(%main = OpFunction %void None %3 +%5 = OpLabel +%16 = OpLoad %int %nu_ii +%19 = OpAccessChain %_ptr_StorageBuffer_float %storageBuffer %16 %int_0 +%20 = OpLoad %float %19 +OpStore %b %20 +OpReturn +OpFunctionEnd +)"; + + const std::string func_after = + R"(%main = OpFunction %void None %10 +%19 = OpLabel +%7 = OpLoad %int %nu_ii +%20 = OpAccessChain %_ptr_StorageBuffer_float %storageBuffer %7 %int_0 +%40 = OpFunctionCall %uint %25 %uint_1 %uint_3 +%42 = OpULessThan %bool %7 %40 +OpSelectionMerge %43 None +OpBranchConditional %42 %44 %45 +%44 = OpLabel +%103 = OpBitcast %uint %7 +%122 = OpFunctionCall %uint %104 %uint_0 %uint_0 %uint_3 %103 +%123 = OpINotEqual %bool %122 %uint_0 +OpSelectionMerge %124 None +OpBranchConditional %123 %125 %126 +%125 = OpLabel +%127 = OpLoad %float %20 +OpBranch %124 +%126 = OpLabel +%128 = OpBitcast %uint %7 +%129 = OpFunctionCall %void %48 %uint_45 %uint_1 %128 %uint_0 +OpBranch %124 +%124 = OpLabel +%130 = OpPhi %float %127 %125 %101 %126 +OpBranch %43 +%45 = OpLabel +%47 = OpBitcast %uint %7 +%100 = OpFunctionCall %void %48 %uint_45 %uint_0 %47 %40 +OpBranch %43 +%43 = OpLabel +%102 = OpPhi %float %130 %124 %101 %45 +OpStore %b %102 +OpReturn +OpFunctionEnd +)"; + + const std::string new_funcs = + R"(%25 = OpFunction %uint None %26 +%27 = OpFunctionParameter %uint +%28 = OpFunctionParameter %uint +%29 = OpLabel +%35 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %27 +%36 = OpLoad %uint %35 +%37 = OpIAdd %uint %36 %28 +%38 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %37 +%39 = OpLoad %uint %38 +OpReturnValue %39 +OpFunctionEnd +%48 = OpFunction %void None %49 +%50 = OpFunctionParameter %uint +%51 = OpFunctionParameter %uint +%52 = OpFunctionParameter %uint +%53 = OpFunctionParameter %uint +%54 = OpLabel +%58 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_0 +%61 = OpAtomicIAdd %uint %58 %uint_4 %uint_0 %uint_10 +%62 = OpIAdd %uint %61 %uint_10 +%63 = OpArrayLength %uint %57 1 +%64 = OpULessThanEqual %bool %62 %63 +OpSelectionMerge %65 None +OpBranchConditional %64 %66 %65 +%66 = OpLabel +%67 = OpIAdd %uint %61 %uint_0 +%68 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %67 +OpStore %68 %uint_10 +%70 = OpIAdd %uint %61 %uint_1 +%71 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %70 +OpStore %71 %uint_23 +%73 = OpIAdd %uint %61 %uint_2 +%74 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %73 +OpStore %74 %50 +%75 = OpIAdd %uint %61 %uint_3 +%76 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %75 +OpStore %76 %uint_4 +%80 = OpLoad %v4float %gl_FragCoord +%82 = OpBitcast %v4uint %80 +%83 = OpCompositeExtract %uint %82 0 +%84 = OpIAdd %uint %61 %uint_4 +%85 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %84 +OpStore %85 %83 +%86 = OpCompositeExtract %uint %82 1 +%88 = OpIAdd %uint %61 %uint_5 +%89 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %88 +OpStore %89 %86 +%91 = OpIAdd %uint %61 %uint_7 +%92 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %91 +OpStore %92 %51 +%94 = OpIAdd %uint %61 %uint_8 +%95 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %94 +OpStore %95 %52 +%97 = OpIAdd %uint %61 %uint_9 +%98 = OpAccessChain %_ptr_StorageBuffer_uint %57 %uint_1 %97 +OpStore %98 %53 +OpBranch %65 +%65 = OpLabel +OpReturn +OpFunctionEnd +%104 = OpFunction %uint None %105 +%106 = OpFunctionParameter %uint +%107 = OpFunctionParameter %uint +%108 = OpFunctionParameter %uint +%109 = OpFunctionParameter %uint +%110 = OpLabel +%111 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %106 +%112 = OpLoad %uint %111 +%113 = OpIAdd %uint %112 %107 +%114 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %113 +%115 = OpLoad %uint %114 +%116 = OpIAdd %uint %115 %108 +%117 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %116 +%118 = OpLoad %uint %117 +%119 = OpIAdd %uint %118 %109 +%120 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %119 +%121 = OpLoad %uint %120 +OpReturnValue %121 +OpFunctionEnd +)"; + + // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck( + defs_before + func_before, defs_after + func_after + new_funcs, true, + true, 7u, 23u, true, true); +} + +TEST_F(InstBindlessTest, InstInitLoadUBOScalar) { + // #version 450 + // #extension GL_EXT_nonuniform_qualifier : enable + // + // layout(location=0) out float b; + // layout(binding=3) uniform uname { float a; } uniformBuffer; + // + // void main() + // { + // b = uniformBuffer.a; + // } + + const std::string defs_before = + R"(OpCapability Shader +OpExtension "SPV_EXT_descriptor_indexing" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %b +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 450 +OpSourceExtension "GL_EXT_nonuniform_qualifier" +OpName %main "main" +OpName %b "b" +OpName %uname "uname" +OpMemberName %uname 0 "a" +OpName %uniformBuffer "uniformBuffer" +OpDecorate %b Location 0 +OpMemberDecorate %uname 0 Offset 0 +OpDecorate %uname Block +OpDecorate %uniformBuffer DescriptorSet 0 +OpDecorate %uniformBuffer Binding 3 +%void = OpTypeVoid +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 +%_ptr_Output_float = OpTypePointer Output %float +%b = OpVariable %_ptr_Output_float Output +%uname = OpTypeStruct %float +%_ptr_Uniform_uname = OpTypePointer Uniform %uname +%uniformBuffer = OpVariable %_ptr_Uniform_uname Uniform +%int = OpTypeInt 32 1 +%int_0 = OpConstant %int 0 +%_ptr_Uniform_float = OpTypePointer Uniform %float +)"; + + const std::string defs_after = + R"(OpCapability Shader +OpExtension "SPV_EXT_descriptor_indexing" +OpExtension "SPV_KHR_storage_buffer_storage_class" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %b %gl_FragCoord +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 450 +OpSourceExtension "GL_EXT_nonuniform_qualifier" +OpName %main "main" +OpName %b "b" +OpName %uname "uname" +OpMemberName %uname 0 "a" +OpName %uniformBuffer "uniformBuffer" +OpDecorate %b Location 0 +OpMemberDecorate %uname 0 Offset 0 +OpDecorate %uname Block +OpDecorate %uniformBuffer DescriptorSet 0 +OpDecorate %uniformBuffer Binding 3 +OpDecorate %_runtimearr_uint ArrayStride 4 +OpDecorate %_struct_28 Block +OpMemberDecorate %_struct_28 0 Offset 0 +OpDecorate %30 DescriptorSet 7 +OpDecorate %30 Binding 1 +OpDecorate %_struct_58 Block +OpMemberDecorate %_struct_58 0 Offset 0 +OpMemberDecorate %_struct_58 1 Offset 4 +OpDecorate %60 DescriptorSet 7 +OpDecorate %60 Binding 0 +OpDecorate %gl_FragCoord BuiltIn FragCoord +%void = OpTypeVoid +%7 = OpTypeFunction %void +%float = OpTypeFloat 32 +%_ptr_Output_float = OpTypePointer Output %float +%b = OpVariable %_ptr_Output_float Output +%uname = OpTypeStruct %float +%_ptr_Uniform_uname = OpTypePointer Uniform %uname +%uniformBuffer = OpVariable %_ptr_Uniform_uname Uniform +%int = OpTypeInt 32 1 +%int_0 = OpConstant %int 0 +%_ptr_Uniform_float = OpTypePointer Uniform %float +%uint = OpTypeInt 32 0 +%uint_0 = OpConstant %uint 0 +%uint_3 = OpConstant %uint 3 +%21 = OpTypeFunction %uint %uint %uint %uint %uint +%_runtimearr_uint = OpTypeRuntimeArray %uint +%_struct_28 = OpTypeStruct %_runtimearr_uint +%_ptr_StorageBuffer__struct_28 = OpTypePointer StorageBuffer %_struct_28 +%30 = OpVariable %_ptr_StorageBuffer__struct_28 StorageBuffer +%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint +%bool = OpTypeBool +%uint_1 = OpConstant %uint 1 +%52 = OpTypeFunction %void %uint %uint %uint %uint +%_struct_58 = OpTypeStruct %uint %_runtimearr_uint +%_ptr_StorageBuffer__struct_58 = OpTypePointer StorageBuffer %_struct_58 +%60 = OpVariable %_ptr_StorageBuffer__struct_58 StorageBuffer +%uint_10 = OpConstant %uint 10 +%uint_4 = OpConstant %uint 4 +%uint_23 = OpConstant %uint 23 +%uint_2 = OpConstant %uint 2 +%v4float = OpTypeVector %float 4 +%_ptr_Input_v4float = OpTypePointer Input %v4float +%gl_FragCoord = OpVariable %_ptr_Input_v4float Input +%v4uint = OpTypeVector %uint 4 +%uint_5 = OpConstant %uint 5 +%uint_7 = OpConstant %uint 7 +%uint_8 = OpConstant %uint 8 +%uint_9 = OpConstant %uint 9 +%uint_32 = OpConstant %uint 32 +%104 = OpConstantNull %float +)"; + + const std::string func_before = + R"(%main = OpFunction %void None %3 +%5 = OpLabel +%15 = OpAccessChain %_ptr_Uniform_float %uniformBuffer %int_0 +%16 = OpLoad %float %15 +OpStore %b %16 +OpReturn +OpFunctionEnd +)"; + + const std::string func_after = + R"(%main = OpFunction %void None %7 +%14 = OpLabel +%15 = OpAccessChain %_ptr_Uniform_float %uniformBuffer %int_0 +%43 = OpFunctionCall %uint %20 %uint_0 %uint_0 %uint_3 %uint_0 +%45 = OpINotEqual %bool %43 %uint_0 +OpSelectionMerge %47 None +OpBranchConditional %45 %48 %49 +%48 = OpLabel +%50 = OpLoad %float %15 +OpBranch %47 +%49 = OpLabel +%103 = OpFunctionCall %void %51 %uint_32 %uint_1 %uint_0 %uint_0 +OpBranch %47 +%47 = OpLabel +%105 = OpPhi %float %50 %48 %104 %49 +OpStore %b %105 +OpReturn +OpFunctionEnd +)"; + + const std::string new_funcs = + R"(%20 = OpFunction %uint None %21 +%22 = OpFunctionParameter %uint +%23 = OpFunctionParameter %uint +%24 = OpFunctionParameter %uint +%25 = OpFunctionParameter %uint +%26 = OpLabel +%32 = OpAccessChain %_ptr_StorageBuffer_uint %30 %uint_0 %22 +%33 = OpLoad %uint %32 +%34 = OpIAdd %uint %33 %23 +%35 = OpAccessChain %_ptr_StorageBuffer_uint %30 %uint_0 %34 +%36 = OpLoad %uint %35 +%37 = OpIAdd %uint %36 %24 +%38 = OpAccessChain %_ptr_StorageBuffer_uint %30 %uint_0 %37 +%39 = OpLoad %uint %38 +%40 = OpIAdd %uint %39 %25 +%41 = OpAccessChain %_ptr_StorageBuffer_uint %30 %uint_0 %40 +%42 = OpLoad %uint %41 +OpReturnValue %42 +OpFunctionEnd +%51 = OpFunction %void None %52 +%53 = OpFunctionParameter %uint +%54 = OpFunctionParameter %uint +%55 = OpFunctionParameter %uint +%56 = OpFunctionParameter %uint +%57 = OpLabel +%61 = OpAccessChain %_ptr_StorageBuffer_uint %60 %uint_0 +%64 = OpAtomicIAdd %uint %61 %uint_4 %uint_0 %uint_10 +%65 = OpIAdd %uint %64 %uint_10 +%66 = OpArrayLength %uint %60 1 +%67 = OpULessThanEqual %bool %65 %66 +OpSelectionMerge %68 None +OpBranchConditional %67 %69 %68 +%69 = OpLabel +%70 = OpIAdd %uint %64 %uint_0 +%71 = OpAccessChain %_ptr_StorageBuffer_uint %60 %uint_1 %70 +OpStore %71 %uint_10 +%73 = OpIAdd %uint %64 %uint_1 +%74 = OpAccessChain %_ptr_StorageBuffer_uint %60 %uint_1 %73 +OpStore %74 %uint_23 +%76 = OpIAdd %uint %64 %uint_2 +%77 = OpAccessChain %_ptr_StorageBuffer_uint %60 %uint_1 %76 +OpStore %77 %53 +%78 = OpIAdd %uint %64 %uint_3 +%79 = OpAccessChain %_ptr_StorageBuffer_uint %60 %uint_1 %78 +OpStore %79 %uint_4 +%83 = OpLoad %v4float %gl_FragCoord +%85 = OpBitcast %v4uint %83 +%86 = OpCompositeExtract %uint %85 0 +%87 = OpIAdd %uint %64 %uint_4 +%88 = OpAccessChain %_ptr_StorageBuffer_uint %60 %uint_1 %87 +OpStore %88 %86 +%89 = OpCompositeExtract %uint %85 1 +%91 = OpIAdd %uint %64 %uint_5 +%92 = OpAccessChain %_ptr_StorageBuffer_uint %60 %uint_1 %91 +OpStore %92 %89 +%94 = OpIAdd %uint %64 %uint_7 +%95 = OpAccessChain %_ptr_StorageBuffer_uint %60 %uint_1 %94 +OpStore %95 %54 +%97 = OpIAdd %uint %64 %uint_8 +%98 = OpAccessChain %_ptr_StorageBuffer_uint %60 %uint_1 %97 +OpStore %98 %55 +%100 = OpIAdd %uint %64 %uint_9 +%101 = OpAccessChain %_ptr_StorageBuffer_uint %60 %uint_1 %100 +OpStore %101 %56 +OpBranch %68 +%68 = OpLabel +OpReturn +OpFunctionEnd +)"; + + // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck( + defs_before + func_before, defs_after + func_after + new_funcs, true, + true, 7u, 23u, true, true); +} + +TEST_F(InstBindlessTest, InstBoundsInitStoreUnsizedSSBOArray) { + // #version 450 + // #extension GL_EXT_nonuniform_qualifier : enable + // + // layout(location=0) in nonuniformEXT flat int nu_ii; + // layout(location=1) in float b; + // + // layout(binding=4) buffer bname { float b; } storageBuffer[]; + // + // void main() + // { + // storageBuffer[nu_ii].b = b; + // } + + const std::string defs_before = + R"(OpCapability Shader +OpCapability ShaderNonUniform +OpCapability RuntimeDescriptorArray +OpCapability StorageBufferArrayNonUniformIndexing +OpExtension "SPV_EXT_descriptor_indexing" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %nu_ii %b +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 450 +OpSourceExtension "GL_EXT_nonuniform_qualifier" +OpName %main "main" +OpName %bname "bname" +OpMemberName %bname 0 "b" +OpName %storageBuffer "storageBuffer" +OpName %nu_ii "nu_ii" +OpName %b "b" +OpMemberDecorate %bname 0 Offset 0 +OpDecorate %bname BufferBlock +OpDecorate %storageBuffer DescriptorSet 0 +OpDecorate %storageBuffer Binding 4 +OpDecorate %nu_ii Flat +OpDecorate %nu_ii Location 0 +OpDecorate %nu_ii NonUniform +OpDecorate %14 NonUniform +OpDecorate %b Location 1 +%void = OpTypeVoid +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 +%bname = OpTypeStruct %float +%_runtimearr_bname = OpTypeRuntimeArray %bname +%_ptr_Uniform__runtimearr_bname = OpTypePointer Uniform %_runtimearr_bname +%storageBuffer = OpVariable %_ptr_Uniform__runtimearr_bname Uniform +%int = OpTypeInt 32 1 +%_ptr_Input_int = OpTypePointer Input %int +%nu_ii = OpVariable %_ptr_Input_int Input +%int_0 = OpConstant %int 0 +%_ptr_Input_float = OpTypePointer Input %float +%b = OpVariable %_ptr_Input_float Input +%_ptr_Uniform_float = OpTypePointer Uniform %float +)"; + + const std::string defs_after = + R"(OpCapability Shader +OpCapability ShaderNonUniform +OpCapability RuntimeDescriptorArray +OpCapability StorageBufferArrayNonUniformIndexing +OpExtension "SPV_EXT_descriptor_indexing" +OpExtension "SPV_KHR_storage_buffer_storage_class" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %nu_ii %b %gl_FragCoord +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 450 +OpSourceExtension "GL_EXT_nonuniform_qualifier" +OpName %main "main" +OpName %bname "bname" +OpMemberName %bname 0 "b" +OpName %storageBuffer "storageBuffer" +OpName %nu_ii "nu_ii" +OpName %b "b" +OpMemberDecorate %bname 0 Offset 0 +OpDecorate %bname BufferBlock +OpDecorate %storageBuffer DescriptorSet 0 +OpDecorate %storageBuffer Binding 4 +OpDecorate %nu_ii Flat +OpDecorate %nu_ii Location 0 +OpDecorate %nu_ii NonUniform +OpDecorate %7 NonUniform +OpDecorate %b Location 1 +OpDecorate %_runtimearr_uint ArrayStride 4 +OpDecorate %_struct_31 Block +OpMemberDecorate %_struct_31 0 Offset 0 +OpDecorate %33 DescriptorSet 7 +OpDecorate %33 Binding 1 +OpDecorate %_struct_54 Block +OpMemberDecorate %_struct_54 0 Offset 0 +OpMemberDecorate %_struct_54 1 Offset 4 +OpDecorate %56 DescriptorSet 7 +OpDecorate %56 Binding 0 +OpDecorate %gl_FragCoord BuiltIn FragCoord +%void = OpTypeVoid +%9 = OpTypeFunction %void +%float = OpTypeFloat 32 +%bname = OpTypeStruct %float +%_runtimearr_bname = OpTypeRuntimeArray %bname +%_ptr_Uniform__runtimearr_bname = OpTypePointer Uniform %_runtimearr_bname +%storageBuffer = OpVariable %_ptr_Uniform__runtimearr_bname Uniform +%int = OpTypeInt 32 1 +%_ptr_Input_int = OpTypePointer Input %int +%nu_ii = OpVariable %_ptr_Input_int Input +%int_0 = OpConstant %int 0 +%_ptr_Input_float = OpTypePointer Input %float +%b = OpVariable %_ptr_Input_float Input +%_ptr_Uniform_float = OpTypePointer Uniform %float +%uint = OpTypeInt 32 0 +%uint_0 = OpConstant %uint 0 +%uint_1 = OpConstant %uint 1 +%uint_4 = OpConstant %uint 4 +%26 = OpTypeFunction %uint %uint %uint +%_runtimearr_uint = OpTypeRuntimeArray %uint +%_struct_31 = OpTypeStruct %_runtimearr_uint +%_ptr_StorageBuffer__struct_31 = OpTypePointer StorageBuffer %_struct_31 +%33 = OpVariable %_ptr_StorageBuffer__struct_31 StorageBuffer +%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint +%bool = OpTypeBool +%48 = OpTypeFunction %void %uint %uint %uint %uint +%_struct_54 = OpTypeStruct %uint %_runtimearr_uint +%_ptr_StorageBuffer__struct_54 = OpTypePointer StorageBuffer %_struct_54 +%56 = OpVariable %_ptr_StorageBuffer__struct_54 StorageBuffer +%uint_10 = OpConstant %uint 10 +%uint_23 = OpConstant %uint 23 +%uint_2 = OpConstant %uint 2 +%uint_3 = OpConstant %uint 3 +%v4float = OpTypeVector %float 4 +%_ptr_Input_v4float = OpTypePointer Input %v4float +%gl_FragCoord = OpVariable %_ptr_Input_v4float Input +%v4uint = OpTypeVector %uint 4 +%uint_5 = OpConstant %uint 5 +%uint_7 = OpConstant %uint 7 +%uint_8 = OpConstant %uint 8 +%uint_9 = OpConstant %uint 9 +%uint_45 = OpConstant %uint 45 +%102 = OpTypeFunction %uint %uint %uint %uint %uint +)"; + + const std::string func_before = + R"(%main = OpFunction %void None %3 +%5 = OpLabel +%14 = OpLoad %int %nu_ii +%18 = OpLoad %float %b +%20 = OpAccessChain %_ptr_Uniform_float %storageBuffer %14 %int_0 +OpStore %20 %18 +OpReturn +OpFunctionEnd +)"; + + const std::string func_after = + R"(%main = OpFunction %void None %9 +%18 = OpLabel +%7 = OpLoad %int %nu_ii +%19 = OpLoad %float %b +%20 = OpAccessChain %_ptr_Uniform_float %storageBuffer %7 %int_0 +%40 = OpFunctionCall %uint %25 %uint_1 %uint_4 +%42 = OpULessThan %bool %7 %40 +OpSelectionMerge %43 None +OpBranchConditional %42 %44 %45 +%44 = OpLabel +%100 = OpBitcast %uint %7 +%119 = OpFunctionCall %uint %101 %uint_0 %uint_0 %uint_4 %100 +%120 = OpINotEqual %bool %119 %uint_0 +OpSelectionMerge %121 None +OpBranchConditional %120 %122 %123 +%122 = OpLabel +OpStore %20 %19 +OpBranch %121 +%123 = OpLabel +%124 = OpBitcast %uint %7 +%125 = OpFunctionCall %void %47 %uint_45 %uint_1 %124 %uint_0 +OpBranch %121 +%121 = OpLabel +OpBranch %43 +%45 = OpLabel +%46 = OpBitcast %uint %7 +%99 = OpFunctionCall %void %47 %uint_45 %uint_0 %46 %40 +OpBranch %43 +%43 = OpLabel +OpReturn +OpFunctionEnd +)"; + + const std::string new_funcs = + R"(%25 = OpFunction %uint None %26 +%27 = OpFunctionParameter %uint +%28 = OpFunctionParameter %uint +%29 = OpLabel +%35 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %27 +%36 = OpLoad %uint %35 +%37 = OpIAdd %uint %36 %28 +%38 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %37 +%39 = OpLoad %uint %38 +OpReturnValue %39 +OpFunctionEnd +%47 = OpFunction %void None %48 +%49 = OpFunctionParameter %uint +%50 = OpFunctionParameter %uint +%51 = OpFunctionParameter %uint +%52 = OpFunctionParameter %uint +%53 = OpLabel +%57 = OpAccessChain %_ptr_StorageBuffer_uint %56 %uint_0 +%59 = OpAtomicIAdd %uint %57 %uint_4 %uint_0 %uint_10 +%60 = OpIAdd %uint %59 %uint_10 +%61 = OpArrayLength %uint %56 1 +%62 = OpULessThanEqual %bool %60 %61 +OpSelectionMerge %63 None +OpBranchConditional %62 %64 %63 +%64 = OpLabel +%65 = OpIAdd %uint %59 %uint_0 +%66 = OpAccessChain %_ptr_StorageBuffer_uint %56 %uint_1 %65 +OpStore %66 %uint_10 +%68 = OpIAdd %uint %59 %uint_1 +%69 = OpAccessChain %_ptr_StorageBuffer_uint %56 %uint_1 %68 +OpStore %69 %uint_23 +%71 = OpIAdd %uint %59 %uint_2 +%72 = OpAccessChain %_ptr_StorageBuffer_uint %56 %uint_1 %71 +OpStore %72 %49 +%74 = OpIAdd %uint %59 %uint_3 +%75 = OpAccessChain %_ptr_StorageBuffer_uint %56 %uint_1 %74 +OpStore %75 %uint_4 +%79 = OpLoad %v4float %gl_FragCoord +%81 = OpBitcast %v4uint %79 +%82 = OpCompositeExtract %uint %81 0 +%83 = OpIAdd %uint %59 %uint_4 +%84 = OpAccessChain %_ptr_StorageBuffer_uint %56 %uint_1 %83 +OpStore %84 %82 +%85 = OpCompositeExtract %uint %81 1 +%87 = OpIAdd %uint %59 %uint_5 +%88 = OpAccessChain %_ptr_StorageBuffer_uint %56 %uint_1 %87 +OpStore %88 %85 +%90 = OpIAdd %uint %59 %uint_7 +%91 = OpAccessChain %_ptr_StorageBuffer_uint %56 %uint_1 %90 +OpStore %91 %50 +%93 = OpIAdd %uint %59 %uint_8 +%94 = OpAccessChain %_ptr_StorageBuffer_uint %56 %uint_1 %93 +OpStore %94 %51 +%96 = OpIAdd %uint %59 %uint_9 +%97 = OpAccessChain %_ptr_StorageBuffer_uint %56 %uint_1 %96 +OpStore %97 %52 +OpBranch %63 +%63 = OpLabel +OpReturn +OpFunctionEnd +%101 = OpFunction %uint None %102 +%103 = OpFunctionParameter %uint +%104 = OpFunctionParameter %uint +%105 = OpFunctionParameter %uint +%106 = OpFunctionParameter %uint +%107 = OpLabel +%108 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %103 +%109 = OpLoad %uint %108 +%110 = OpIAdd %uint %109 %104 +%111 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %110 +%112 = OpLoad %uint %111 +%113 = OpIAdd %uint %112 %105 +%114 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %113 +%115 = OpLoad %uint %114 +%116 = OpIAdd %uint %115 %106 +%117 = OpAccessChain %_ptr_StorageBuffer_uint %33 %uint_0 %116 +%118 = OpLoad %uint %117 +OpReturnValue %118 +OpFunctionEnd +)"; + + // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck( + defs_before + func_before, defs_after + func_after + new_funcs, true, + true, 7u, 23u, true, true); +} + +TEST_F(InstBindlessTest, InstBoundsInitLoadSizedUBOArray) { + // #version 450 + // #extension GL_EXT_nonuniform_qualifier : enable + // + // layout(location=0) in nonuniformEXT flat int nu_ii; + // layout(location=0) out float b; + // + // layout(binding=3) uniform uname { float a; } uniformBuffer[128]; + // + // void main() + // { + // b = uniformBuffer[nu_ii].a; + // } + + const std::string defs_before = + R"(OpCapability Shader +OpCapability ShaderNonUniform +OpCapability UniformBufferArrayNonUniformIndexing +OpExtension "SPV_EXT_descriptor_indexing" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %b %nu_ii +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 450 +OpSourceExtension "GL_EXT_nonuniform_qualifier" +OpName %main "main" +OpName %b "b" +OpName %uname "uname" +OpMemberName %uname 0 "a" +OpName %uniformBuffer "uniformBuffer" +OpName %nu_ii "nu_ii" +OpDecorate %b Location 0 +OpMemberDecorate %uname 0 Offset 0 +OpDecorate %uname Block +OpDecorate %uniformBuffer DescriptorSet 0 +OpDecorate %uniformBuffer Binding 3 +OpDecorate %nu_ii Flat +OpDecorate %nu_ii Location 0 +OpDecorate %nu_ii NonUniform +OpDecorate %18 NonUniform +OpDecorate %22 NonUniform +%void = OpTypeVoid +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 +%_ptr_Output_float = OpTypePointer Output %float +%b = OpVariable %_ptr_Output_float Output +%uname = OpTypeStruct %float +%uint = OpTypeInt 32 0 +%uint_128 = OpConstant %uint 128 +%_arr_uname_uint_128 = OpTypeArray %uname %uint_128 +%_ptr_Uniform__arr_uname_uint_128 = OpTypePointer Uniform %_arr_uname_uint_128 +%uniformBuffer = OpVariable %_ptr_Uniform__arr_uname_uint_128 Uniform +%int = OpTypeInt 32 1 +%_ptr_Input_int = OpTypePointer Input %int +%nu_ii = OpVariable %_ptr_Input_int Input +%int_0 = OpConstant %int 0 +%_ptr_Uniform_float = OpTypePointer Uniform %float +)"; + + const std::string defs_after = + R"(OpCapability Shader +OpCapability ShaderNonUniform +OpCapability UniformBufferArrayNonUniformIndexing +OpExtension "SPV_EXT_descriptor_indexing" +OpExtension "SPV_KHR_storage_buffer_storage_class" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %b %nu_ii %gl_FragCoord +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 450 +OpSourceExtension "GL_EXT_nonuniform_qualifier" +OpName %main "main" +OpName %b "b" +OpName %uname "uname" +OpMemberName %uname 0 "a" +OpName %uniformBuffer "uniformBuffer" +OpName %nu_ii "nu_ii" +OpDecorate %b Location 0 +OpMemberDecorate %uname 0 Offset 0 +OpDecorate %uname Block +OpDecorate %uniformBuffer DescriptorSet 0 +OpDecorate %uniformBuffer Binding 3 +OpDecorate %nu_ii Flat +OpDecorate %nu_ii Location 0 +OpDecorate %nu_ii NonUniform +OpDecorate %7 NonUniform +OpDecorate %89 NonUniform +OpDecorate %120 NonUniform +OpDecorate %_runtimearr_uint ArrayStride 4 +OpDecorate %_struct_39 Block +OpMemberDecorate %_struct_39 0 Offset 0 +OpMemberDecorate %_struct_39 1 Offset 4 +OpDecorate %41 DescriptorSet 7 +OpDecorate %41 Binding 0 +OpDecorate %gl_FragCoord BuiltIn FragCoord +OpDecorate %_struct_98 Block +OpMemberDecorate %_struct_98 0 Offset 0 +OpDecorate %100 DescriptorSet 7 +OpDecorate %100 Binding 1 +OpDecorate %117 NonUniform +%void = OpTypeVoid +%10 = OpTypeFunction %void +%float = OpTypeFloat 32 +%_ptr_Output_float = OpTypePointer Output %float +%b = OpVariable %_ptr_Output_float Output +%uname = OpTypeStruct %float +%uint = OpTypeInt 32 0 +%uint_128 = OpConstant %uint 128 +%_arr_uname_uint_128 = OpTypeArray %uname %uint_128 +%_ptr_Uniform__arr_uname_uint_128 = OpTypePointer Uniform %_arr_uname_uint_128 +%uniformBuffer = OpVariable %_ptr_Uniform__arr_uname_uint_128 Uniform +%int = OpTypeInt 32 1 +%_ptr_Input_int = OpTypePointer Input %int +%nu_ii = OpVariable %_ptr_Input_int Input +%int_0 = OpConstant %int 0 +%_ptr_Uniform_float = OpTypePointer Uniform %float +%uint_0 = OpConstant %uint 0 +%bool = OpTypeBool +%32 = OpTypeFunction %void %uint %uint %uint %uint +%_runtimearr_uint = OpTypeRuntimeArray %uint +%_struct_39 = OpTypeStruct %uint %_runtimearr_uint +%_ptr_StorageBuffer__struct_39 = OpTypePointer StorageBuffer %_struct_39 +%41 = OpVariable %_ptr_StorageBuffer__struct_39 StorageBuffer +%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint +%uint_10 = OpConstant %uint 10 +%uint_4 = OpConstant %uint 4 +%uint_1 = OpConstant %uint 1 +%uint_23 = OpConstant %uint 23 +%uint_2 = OpConstant %uint 2 +%uint_3 = OpConstant %uint 3 +%v4float = OpTypeVector %float 4 +%_ptr_Input_v4float = OpTypePointer Input %v4float +%gl_FragCoord = OpVariable %_ptr_Input_v4float Input +%v4uint = OpTypeVector %uint 4 +%uint_5 = OpConstant %uint 5 +%uint_7 = OpConstant %uint 7 +%uint_8 = OpConstant %uint 8 +%uint_9 = OpConstant %uint 9 +%uint_46 = OpConstant %uint 46 +%88 = OpConstantNull %float +%92 = OpTypeFunction %uint %uint %uint %uint %uint +%_struct_98 = OpTypeStruct %_runtimearr_uint +%_ptr_StorageBuffer__struct_98 = OpTypePointer StorageBuffer %_struct_98 +%100 = OpVariable %_ptr_StorageBuffer__struct_98 StorageBuffer +)"; + + const std::string func_before = + R"(%main = OpFunction %void None %3 +%5 = OpLabel +%18 = OpLoad %int %nu_ii +%21 = OpAccessChain %_ptr_Uniform_float %uniformBuffer %18 %int_0 +%22 = OpLoad %float %21 +OpStore %b %22 +OpReturn +OpFunctionEnd +)"; + + const std::string func_after = + R"(%main = OpFunction %void None %10 +%21 = OpLabel +%7 = OpLoad %int %nu_ii +%22 = OpAccessChain %_ptr_Uniform_float %uniformBuffer %7 %int_0 +%25 = OpULessThan %bool %7 %uint_128 +OpSelectionMerge %26 None +OpBranchConditional %25 %27 %28 +%27 = OpLabel +%90 = OpBitcast %uint %7 +%112 = OpFunctionCall %uint %91 %uint_0 %uint_0 %uint_3 %90 +%113 = OpINotEqual %bool %112 %uint_0 +OpSelectionMerge %114 None +OpBranchConditional %113 %115 %116 +%115 = OpLabel +%117 = OpLoad %float %22 +OpBranch %114 +%116 = OpLabel +%118 = OpBitcast %uint %7 +%119 = OpFunctionCall %void %31 %uint_46 %uint_1 %118 %uint_0 +OpBranch %114 +%114 = OpLabel +%120 = OpPhi %float %117 %115 %88 %116 +OpBranch %26 +%28 = OpLabel +%30 = OpBitcast %uint %7 +%87 = OpFunctionCall %void %31 %uint_46 %uint_0 %30 %uint_128 +OpBranch %26 +%26 = OpLabel +%89 = OpPhi %float %120 %114 %88 %28 +OpStore %b %89 +OpReturn +OpFunctionEnd +)"; + + const std::string new_funcs = + R"(%31 = OpFunction %void None %32 +%33 = OpFunctionParameter %uint +%34 = OpFunctionParameter %uint +%35 = OpFunctionParameter %uint +%36 = OpFunctionParameter %uint +%37 = OpLabel +%43 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 +%46 = OpAtomicIAdd %uint %43 %uint_4 %uint_0 %uint_10 +%47 = OpIAdd %uint %46 %uint_10 +%48 = OpArrayLength %uint %41 1 +%49 = OpULessThanEqual %bool %47 %48 +OpSelectionMerge %50 None +OpBranchConditional %49 %51 %50 +%51 = OpLabel +%52 = OpIAdd %uint %46 %uint_0 +%54 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_1 %52 +OpStore %54 %uint_10 +%56 = OpIAdd %uint %46 %uint_1 +%57 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_1 %56 +OpStore %57 %uint_23 +%59 = OpIAdd %uint %46 %uint_2 +%60 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_1 %59 +OpStore %60 %33 +%62 = OpIAdd %uint %46 %uint_3 +%63 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_1 %62 +OpStore %63 %uint_4 +%67 = OpLoad %v4float %gl_FragCoord +%69 = OpBitcast %v4uint %67 +%70 = OpCompositeExtract %uint %69 0 +%71 = OpIAdd %uint %46 %uint_4 +%72 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_1 %71 +OpStore %72 %70 +%73 = OpCompositeExtract %uint %69 1 +%75 = OpIAdd %uint %46 %uint_5 +%76 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_1 %75 +OpStore %76 %73 +%78 = OpIAdd %uint %46 %uint_7 +%79 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_1 %78 +OpStore %79 %34 +%81 = OpIAdd %uint %46 %uint_8 +%82 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_1 %81 +OpStore %82 %35 +%84 = OpIAdd %uint %46 %uint_9 +%85 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_1 %84 +OpStore %85 %36 +OpBranch %50 +%50 = OpLabel +OpReturn +OpFunctionEnd +%91 = OpFunction %uint None %92 +%93 = OpFunctionParameter %uint +%94 = OpFunctionParameter %uint +%95 = OpFunctionParameter %uint +%96 = OpFunctionParameter %uint +%97 = OpLabel +%101 = OpAccessChain %_ptr_StorageBuffer_uint %100 %uint_0 %93 +%102 = OpLoad %uint %101 +%103 = OpIAdd %uint %102 %94 +%104 = OpAccessChain %_ptr_StorageBuffer_uint %100 %uint_0 %103 +%105 = OpLoad %uint %104 +%106 = OpIAdd %uint %105 %95 +%107 = OpAccessChain %_ptr_StorageBuffer_uint %100 %uint_0 %106 +%108 = OpLoad %uint %107 +%109 = OpIAdd %uint %108 %96 +%110 = OpAccessChain %_ptr_StorageBuffer_uint %100 %uint_0 %109 +%111 = OpLoad %uint %110 +OpReturnValue %111 +OpFunctionEnd +)"; + + // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck( + defs_before + func_before, defs_after + func_after + new_funcs, true, + true, 7u, 23u, true, true); +} + +TEST_F(InstBindlessTest, + InstBoundsComputeShaderInitLoadVariableSizedSampledImagesArray) { + // #version 450 + // #extension GL_EXT_nonuniform_qualifier : enable + // + // layout (local_size_x = 1, local_size_y = 1) in; + // + // layout(set = 0, binding = 0, std140) buffer Input { + // uint index; + // float red; + // } sbo; + // + // layout(set = 0, binding = 1, rgba32f) readonly uniform image2D images[]; + // + // void main() + // { + // sbo.red = imageLoad(images[sbo.index], ivec2(0, 0)).r; + // } + + const std::string defs_before = + R"(OpCapability Shader +OpCapability RuntimeDescriptorArray +OpExtension "SPV_EXT_descriptor_indexing" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpSource GLSL 450 +OpSourceExtension "GL_EXT_nonuniform_qualifier" +OpName %main "main" +OpName %Input "Input" +OpMemberName %Input 0 "index" +OpMemberName %Input 1 "red" +OpName %sbo "sbo" +OpName %images "images" +OpMemberDecorate %Input 0 Offset 0 +OpMemberDecorate %Input 1 Offset 4 +OpDecorate %Input BufferBlock +OpDecorate %sbo DescriptorSet 0 +OpDecorate %sbo Binding 0 +OpDecorate %images DescriptorSet 0 +OpDecorate %images Binding 1 +OpDecorate %images NonWritable +%void = OpTypeVoid +%3 = OpTypeFunction %void +%uint = OpTypeInt 32 0 +%float = OpTypeFloat 32 +%Input = OpTypeStruct %uint %float +%_ptr_Uniform_Input = OpTypePointer Uniform %Input +%sbo = OpVariable %_ptr_Uniform_Input Uniform +%int = OpTypeInt 32 1 +%int_1 = OpConstant %int 1 +%13 = OpTypeImage %float 2D 0 0 0 2 Rgba32f +%_runtimearr_13 = OpTypeRuntimeArray %13 +%_ptr_UniformConstant__runtimearr_13 = OpTypePointer UniformConstant %_runtimearr_13 +%images = OpVariable %_ptr_UniformConstant__runtimearr_13 UniformConstant +%int_0 = OpConstant %int 0 +%_ptr_Uniform_uint = OpTypePointer Uniform %uint +%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13 +%v2int = OpTypeVector %int 2 +%25 = OpConstantComposite %v2int %int_0 %int_0 +%v4float = OpTypeVector %float 4 +%uint_0 = OpConstant %uint 0 +%_ptr_Uniform_float = OpTypePointer Uniform %float +)"; + + const std::string defs_after = + R"(OpCapability Shader +OpCapability RuntimeDescriptorArray +OpExtension "SPV_EXT_descriptor_indexing" +OpExtension "SPV_KHR_storage_buffer_storage_class" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" %gl_GlobalInvocationID +OpExecutionMode %main LocalSize 1 1 1 +OpSource GLSL 450 +OpSourceExtension "GL_EXT_nonuniform_qualifier" +OpName %main "main" +OpName %Input "Input" +OpMemberName %Input 0 "index" +OpMemberName %Input 1 "red" +OpName %sbo "sbo" +OpName %images "images" +OpMemberDecorate %Input 0 Offset 0 +OpMemberDecorate %Input 1 Offset 4 +OpDecorate %Input BufferBlock +OpDecorate %sbo DescriptorSet 0 +OpDecorate %sbo Binding 0 +OpDecorate %images DescriptorSet 0 +OpDecorate %images Binding 1 +OpDecorate %images NonWritable +OpDecorate %_runtimearr_uint ArrayStride 4 +OpDecorate %_struct_39 Block +OpMemberDecorate %_struct_39 0 Offset 0 +OpDecorate %41 DescriptorSet 7 +OpDecorate %41 Binding 1 +OpDecorate %_struct_63 Block +OpMemberDecorate %_struct_63 0 Offset 0 +OpMemberDecorate %_struct_63 1 Offset 4 +OpDecorate %65 DescriptorSet 7 +OpDecorate %65 Binding 0 +OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId +%void = OpTypeVoid +%7 = OpTypeFunction %void +%uint = OpTypeInt 32 0 +%float = OpTypeFloat 32 +%Input = OpTypeStruct %uint %float +%_ptr_Uniform_Input = OpTypePointer Uniform %Input +%sbo = OpVariable %_ptr_Uniform_Input Uniform +%int = OpTypeInt 32 1 +%int_1 = OpConstant %int 1 +%13 = OpTypeImage %float 2D 0 0 0 2 Rgba32f +%_runtimearr_13 = OpTypeRuntimeArray %13 +%_ptr_UniformConstant__runtimearr_13 = OpTypePointer UniformConstant %_runtimearr_13 +%images = OpVariable %_ptr_UniformConstant__runtimearr_13 UniformConstant +%int_0 = OpConstant %int 0 +%_ptr_Uniform_uint = OpTypePointer Uniform %uint +%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13 +%v2int = OpTypeVector %int 2 +%20 = OpConstantComposite %v2int %int_0 %int_0 +%v4float = OpTypeVector %float 4 +%uint_0 = OpConstant %uint 0 +%_ptr_Uniform_float = OpTypePointer Uniform %float +%uint_1 = OpConstant %uint 1 +%34 = OpTypeFunction %uint %uint %uint +%_runtimearr_uint = OpTypeRuntimeArray %uint +%_struct_39 = OpTypeStruct %_runtimearr_uint +%_ptr_StorageBuffer__struct_39 = OpTypePointer StorageBuffer %_struct_39 +%41 = OpVariable %_ptr_StorageBuffer__struct_39 StorageBuffer +%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint +%bool = OpTypeBool +%57 = OpTypeFunction %void %uint %uint %uint %uint +%_struct_63 = OpTypeStruct %uint %_runtimearr_uint +%_ptr_StorageBuffer__struct_63 = OpTypePointer StorageBuffer %_struct_63 +%65 = OpVariable %_ptr_StorageBuffer__struct_63 StorageBuffer +%uint_10 = OpConstant %uint 10 +%uint_4 = OpConstant %uint 4 +%uint_23 = OpConstant %uint 23 +%uint_2 = OpConstant %uint 2 +%uint_5 = OpConstant %uint 5 +%uint_3 = OpConstant %uint 3 +%v3uint = OpTypeVector %uint 3 +%_ptr_Input_v3uint = OpTypePointer Input %v3uint +%gl_GlobalInvocationID = OpVariable %_ptr_Input_v3uint Input +%uint_6 = OpConstant %uint 6 +%uint_7 = OpConstant %uint 7 +%uint_8 = OpConstant %uint 8 +%uint_9 = OpConstant %uint 9 +%uint_50 = OpConstant %uint 50 +%112 = OpConstantNull %v4float +%115 = OpTypeFunction %uint %uint %uint %uint %uint +%uint_47 = OpConstant %uint 47 +%140 = OpConstantNull %uint +%uint_53 = OpConstant %uint 53 +)"; + + const std::string func_before = + R"(%main = OpFunction %void None %3 +%5 = OpLabel +%19 = OpAccessChain %_ptr_Uniform_uint %sbo %int_0 +%20 = OpLoad %uint %19 +%22 = OpAccessChain %_ptr_UniformConstant_13 %images %20 +%23 = OpLoad %13 %22 +%27 = OpImageRead %v4float %23 %25 +%29 = OpCompositeExtract %float %27 0 +%31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 +OpStore %31 %29 +OpReturn +OpFunctionEnd +)"; + + const std::string func_after = + R"(%main = OpFunction %void None %7 +%24 = OpLabel +%25 = OpAccessChain %_ptr_Uniform_uint %sbo %int_0 +%132 = OpFunctionCall %uint %114 %uint_0 %uint_0 %uint_0 %uint_0 +%133 = OpINotEqual %bool %132 %uint_0 +OpSelectionMerge %134 None +OpBranchConditional %133 %135 %136 +%135 = OpLabel +%137 = OpLoad %uint %25 +OpBranch %134 +%136 = OpLabel +%139 = OpFunctionCall %void %56 %uint_47 %uint_1 %uint_0 %uint_0 +OpBranch %134 +%134 = OpLabel +%141 = OpPhi %uint %137 %135 %140 %136 +%27 = OpAccessChain %_ptr_UniformConstant_13 %images %141 +%28 = OpLoad %13 %27 +%48 = OpFunctionCall %uint %33 %uint_1 %uint_1 +%50 = OpULessThan %bool %141 %48 +OpSelectionMerge %51 None +OpBranchConditional %50 %52 %53 +%52 = OpLabel +%54 = OpLoad %13 %27 +%142 = OpFunctionCall %uint %114 %uint_0 %uint_0 %uint_1 %141 +%143 = OpINotEqual %bool %142 %uint_0 +OpSelectionMerge %144 None +OpBranchConditional %143 %145 %146 +%145 = OpLabel +%147 = OpLoad %13 %27 +%148 = OpImageRead %v4float %147 %20 +OpBranch %144 +%146 = OpLabel +%149 = OpFunctionCall %void %56 %uint_50 %uint_1 %141 %uint_0 +OpBranch %144 +%144 = OpLabel +%150 = OpPhi %v4float %148 %145 %112 %146 +OpBranch %51 +%53 = OpLabel +%111 = OpFunctionCall %void %56 %uint_50 %uint_0 %141 %48 +OpBranch %51 +%51 = OpLabel +%113 = OpPhi %v4float %150 %144 %112 %53 +%30 = OpCompositeExtract %float %113 0 +%31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 +%151 = OpFunctionCall %uint %114 %uint_0 %uint_0 %uint_0 %uint_0 +%152 = OpINotEqual %bool %151 %uint_0 +OpSelectionMerge %153 None +OpBranchConditional %152 %154 %155 +%154 = OpLabel +OpStore %31 %30 +OpBranch %153 +%155 = OpLabel +%157 = OpFunctionCall %void %56 %uint_53 %uint_1 %uint_0 %uint_0 +OpBranch %153 +%153 = OpLabel +OpReturn +OpFunctionEnd +)"; + + const std::string new_funcs = + R"(%33 = OpFunction %uint None %34 +%35 = OpFunctionParameter %uint +%36 = OpFunctionParameter %uint +%37 = OpLabel +%43 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %35 +%44 = OpLoad %uint %43 +%45 = OpIAdd %uint %44 %36 +%46 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %45 +%47 = OpLoad %uint %46 +OpReturnValue %47 +OpFunctionEnd +%56 = OpFunction %void None %57 +%58 = OpFunctionParameter %uint +%59 = OpFunctionParameter %uint +%60 = OpFunctionParameter %uint +%61 = OpFunctionParameter %uint +%62 = OpLabel +%66 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_0 +%69 = OpAtomicIAdd %uint %66 %uint_4 %uint_0 %uint_10 +%70 = OpIAdd %uint %69 %uint_10 +%71 = OpArrayLength %uint %65 1 +%72 = OpULessThanEqual %bool %70 %71 +OpSelectionMerge %73 None +OpBranchConditional %72 %74 %73 +%74 = OpLabel +%75 = OpIAdd %uint %69 %uint_0 +%76 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %75 +OpStore %76 %uint_10 +%78 = OpIAdd %uint %69 %uint_1 +%79 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %78 +OpStore %79 %uint_23 +%81 = OpIAdd %uint %69 %uint_2 +%82 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %81 +OpStore %82 %58 +%85 = OpIAdd %uint %69 %uint_3 +%86 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %85 +OpStore %86 %uint_5 +%90 = OpLoad %v3uint %gl_GlobalInvocationID +%91 = OpCompositeExtract %uint %90 0 +%92 = OpCompositeExtract %uint %90 1 +%93 = OpCompositeExtract %uint %90 2 +%94 = OpIAdd %uint %69 %uint_4 +%95 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %94 +OpStore %95 %91 +%96 = OpIAdd %uint %69 %uint_5 +%97 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %96 +OpStore %97 %92 +%99 = OpIAdd %uint %69 %uint_6 +%100 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %99 +OpStore %100 %93 +%102 = OpIAdd %uint %69 %uint_7 +%103 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %102 +OpStore %103 %59 +%105 = OpIAdd %uint %69 %uint_8 +%106 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %105 +OpStore %106 %60 +%108 = OpIAdd %uint %69 %uint_9 +%109 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %108 +OpStore %109 %61 +OpBranch %73 +%73 = OpLabel +OpReturn +OpFunctionEnd +%114 = OpFunction %uint None %115 +%116 = OpFunctionParameter %uint +%117 = OpFunctionParameter %uint +%118 = OpFunctionParameter %uint +%119 = OpFunctionParameter %uint +%120 = OpLabel +%121 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %116 +%122 = OpLoad %uint %121 +%123 = OpIAdd %uint %122 %117 +%124 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %123 +%125 = OpLoad %uint %124 +%126 = OpIAdd %uint %125 %118 +%127 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %126 +%128 = OpLoad %uint %127 +%129 = OpIAdd %uint %128 %119 +%130 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %129 +%131 = OpLoad %uint %130 +OpReturnValue %131 +OpFunctionEnd +)"; + + // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck( + defs_before + func_before, defs_after + func_after + new_funcs, true, + true, 7u, 23u, true, true); +} + +TEST_F(InstBindlessTest, + InstBoundsRayGenerationInitLoadVariableSizedSampledImagesArray) { + // #version 460 + // #extension GL_EXT_nonuniform_qualifier : require + // #extension GL_NV_ray_tracing : require + // + // layout(set = 0, binding = 0, std140) buffer StorageBuffer { + // uint index; + // float red; + // } sbo; + // + // layout(set = 0, binding = 1, rgba32f) readonly uniform image2D images[]; + // + // void main() + // { + // sbo.red = imageLoad(images[sbo.index], ivec2(0, 0)).r; + // } + + const std::string defs_before = + R"(OpCapability RuntimeDescriptorArray +OpCapability RayTracingNV +OpExtension "SPV_EXT_descriptor_indexing" +OpExtension "SPV_NV_ray_tracing" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint RayGenerationNV %main "main" +OpSource GLSL 460 +OpSourceExtension "GL_EXT_nonuniform_qualifier" +OpSourceExtension "GL_NV_ray_tracing" +OpName %main "main" +OpName %StorageBuffer "StorageBuffer" +OpMemberName %StorageBuffer 0 "index" +OpMemberName %StorageBuffer 1 "red" +OpName %sbo "sbo" +OpName %images "images" +OpMemberDecorate %StorageBuffer 0 Offset 0 +OpMemberDecorate %StorageBuffer 1 Offset 4 +OpDecorate %StorageBuffer BufferBlock +OpDecorate %sbo DescriptorSet 0 +OpDecorate %sbo Binding 0 +OpDecorate %images DescriptorSet 0 +OpDecorate %images Binding 1 +OpDecorate %images NonWritable +%void = OpTypeVoid +)"; + + const std::string defs_after = + R"(OpCapability RuntimeDescriptorArray +OpCapability RayTracingNV +OpExtension "SPV_EXT_descriptor_indexing" +OpExtension "SPV_NV_ray_tracing" +OpExtension "SPV_KHR_storage_buffer_storage_class" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint RayGenerationNV %main "main" %89 +OpSource GLSL 460 +OpSourceExtension "GL_EXT_nonuniform_qualifier" +OpSourceExtension "GL_NV_ray_tracing" +OpName %main "main" +OpName %StorageBuffer "StorageBuffer" +OpMemberName %StorageBuffer 0 "index" +OpMemberName %StorageBuffer 1 "red" +OpName %sbo "sbo" +OpName %images "images" +OpMemberDecorate %StorageBuffer 0 Offset 0 +OpMemberDecorate %StorageBuffer 1 Offset 4 +OpDecorate %StorageBuffer BufferBlock +OpDecorate %sbo DescriptorSet 0 +OpDecorate %sbo Binding 0 +OpDecorate %images DescriptorSet 0 +OpDecorate %images Binding 1 +OpDecorate %images NonWritable +OpDecorate %_runtimearr_uint ArrayStride 4 +OpDecorate %_struct_39 Block +OpMemberDecorate %_struct_39 0 Offset 0 +OpDecorate %41 DescriptorSet 7 +OpDecorate %41 Binding 1 +OpDecorate %_struct_63 Block +OpMemberDecorate %_struct_63 0 Offset 0 +OpMemberDecorate %_struct_63 1 Offset 4 +OpDecorate %65 DescriptorSet 7 +OpDecorate %65 Binding 0 +OpDecorate %89 BuiltIn LaunchIdNV +%void = OpTypeVoid +)"; + + const std::string func_before = + R"(%3 = OpTypeFunction %void +%uint = OpTypeInt 32 0 +%float = OpTypeFloat 32 +%StorageBuffer = OpTypeStruct %uint %float +%_ptr_Uniform_StorageBuffer = OpTypePointer Uniform %StorageBuffer +%sbo = OpVariable %_ptr_Uniform_StorageBuffer Uniform +%int = OpTypeInt 32 1 +%int_1 = OpConstant %int 1 +%13 = OpTypeImage %float 2D 0 0 0 2 Rgba32f +%_runtimearr_13 = OpTypeRuntimeArray %13 +%_ptr_UniformConstant__runtimearr_13 = OpTypePointer UniformConstant %_runtimearr_13 +%images = OpVariable %_ptr_UniformConstant__runtimearr_13 UniformConstant +%int_0 = OpConstant %int 0 +%_ptr_Uniform_uint = OpTypePointer Uniform %uint +%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13 +%v2int = OpTypeVector %int 2 +%25 = OpConstantComposite %v2int %int_0 %int_0 +%v4float = OpTypeVector %float 4 +%uint_0 = OpConstant %uint 0 +%_ptr_Uniform_float = OpTypePointer Uniform %float +%main = OpFunction %void None %3 +%5 = OpLabel +%19 = OpAccessChain %_ptr_Uniform_uint %sbo %int_0 +%20 = OpLoad %uint %19 +%22 = OpAccessChain %_ptr_UniformConstant_13 %images %20 +%23 = OpLoad %13 %22 +%27 = OpImageRead %v4float %23 %25 +%29 = OpCompositeExtract %float %27 0 +%31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 +OpStore %31 %29 +OpReturn +OpFunctionEnd +)"; + + const std::string func_after = + R"(%7 = OpTypeFunction %void +%uint = OpTypeInt 32 0 +%float = OpTypeFloat 32 +%StorageBuffer = OpTypeStruct %uint %float +%_ptr_Uniform_StorageBuffer = OpTypePointer Uniform %StorageBuffer +%sbo = OpVariable %_ptr_Uniform_StorageBuffer Uniform +%int = OpTypeInt 32 1 +%int_1 = OpConstant %int 1 +%13 = OpTypeImage %float 2D 0 0 0 2 Rgba32f +%_runtimearr_13 = OpTypeRuntimeArray %13 +%_ptr_UniformConstant__runtimearr_13 = OpTypePointer UniformConstant %_runtimearr_13 +%images = OpVariable %_ptr_UniformConstant__runtimearr_13 UniformConstant +%int_0 = OpConstant %int 0 +%_ptr_Uniform_uint = OpTypePointer Uniform %uint +%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13 +%v2int = OpTypeVector %int 2 +%20 = OpConstantComposite %v2int %int_0 %int_0 +%v4float = OpTypeVector %float 4 +%uint_0 = OpConstant %uint 0 +%_ptr_Uniform_float = OpTypePointer Uniform %float +%uint_1 = OpConstant %uint 1 +%34 = OpTypeFunction %uint %uint %uint +%_runtimearr_uint = OpTypeRuntimeArray %uint +%_struct_39 = OpTypeStruct %_runtimearr_uint +%_ptr_StorageBuffer__struct_39 = OpTypePointer StorageBuffer %_struct_39 +%41 = OpVariable %_ptr_StorageBuffer__struct_39 StorageBuffer +%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint +%bool = OpTypeBool +%57 = OpTypeFunction %void %uint %uint %uint %uint +%_struct_63 = OpTypeStruct %uint %_runtimearr_uint +%_ptr_StorageBuffer__struct_63 = OpTypePointer StorageBuffer %_struct_63 +%65 = OpVariable %_ptr_StorageBuffer__struct_63 StorageBuffer +%uint_10 = OpConstant %uint 10 +%uint_4 = OpConstant %uint 4 +%uint_23 = OpConstant %uint 23 +%uint_2 = OpConstant %uint 2 +%uint_5313 = OpConstant %uint 5313 +%uint_3 = OpConstant %uint 3 +%v3uint = OpTypeVector %uint 3 +%_ptr_Input_v3uint = OpTypePointer Input %v3uint +%89 = OpVariable %_ptr_Input_v3uint Input +%uint_5 = OpConstant %uint 5 +%uint_6 = OpConstant %uint 6 +%uint_7 = OpConstant %uint 7 +%uint_8 = OpConstant %uint 8 +%uint_9 = OpConstant %uint 9 +%uint_51 = OpConstant %uint 51 +%113 = OpConstantNull %v4float +%116 = OpTypeFunction %uint %uint %uint %uint %uint +%uint_48 = OpConstant %uint 48 +%141 = OpConstantNull %uint +%uint_54 = OpConstant %uint 54 +%main = OpFunction %void None %7 +%24 = OpLabel +%25 = OpAccessChain %_ptr_Uniform_uint %sbo %int_0 +%133 = OpFunctionCall %uint %115 %uint_0 %uint_0 %uint_0 %uint_0 +%134 = OpINotEqual %bool %133 %uint_0 +OpSelectionMerge %135 None +OpBranchConditional %134 %136 %137 +%136 = OpLabel +%138 = OpLoad %uint %25 +OpBranch %135 +%137 = OpLabel +%140 = OpFunctionCall %void %56 %uint_48 %uint_1 %uint_0 %uint_0 +OpBranch %135 +%135 = OpLabel +%142 = OpPhi %uint %138 %136 %141 %137 +%27 = OpAccessChain %_ptr_UniformConstant_13 %images %142 +%28 = OpLoad %13 %27 +%48 = OpFunctionCall %uint %33 %uint_1 %uint_1 +%50 = OpULessThan %bool %142 %48 +OpSelectionMerge %51 None +OpBranchConditional %50 %52 %53 +%52 = OpLabel +%54 = OpLoad %13 %27 +%143 = OpFunctionCall %uint %115 %uint_0 %uint_0 %uint_1 %142 +%144 = OpINotEqual %bool %143 %uint_0 +OpSelectionMerge %145 None +OpBranchConditional %144 %146 %147 +%146 = OpLabel +%148 = OpLoad %13 %27 +%149 = OpImageRead %v4float %148 %20 +OpBranch %145 +%147 = OpLabel +%150 = OpFunctionCall %void %56 %uint_51 %uint_1 %142 %uint_0 +OpBranch %145 +%145 = OpLabel +%151 = OpPhi %v4float %149 %146 %113 %147 +OpBranch %51 +%53 = OpLabel +%112 = OpFunctionCall %void %56 %uint_51 %uint_0 %142 %48 +OpBranch %51 +%51 = OpLabel +%114 = OpPhi %v4float %151 %145 %113 %53 +%30 = OpCompositeExtract %float %114 0 +%31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 +%152 = OpFunctionCall %uint %115 %uint_0 %uint_0 %uint_0 %uint_0 +%153 = OpINotEqual %bool %152 %uint_0 +OpSelectionMerge %154 None +OpBranchConditional %153 %155 %156 +%155 = OpLabel +OpStore %31 %30 +OpBranch %154 +%156 = OpLabel +%158 = OpFunctionCall %void %56 %uint_54 %uint_1 %uint_0 %uint_0 +OpBranch %154 +%154 = OpLabel +OpReturn +OpFunctionEnd +)"; + + const std::string new_funcs = + R"(%33 = OpFunction %uint None %34 +%35 = OpFunctionParameter %uint +%36 = OpFunctionParameter %uint +%37 = OpLabel +%43 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %35 +%44 = OpLoad %uint %43 +%45 = OpIAdd %uint %44 %36 +%46 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %45 +%47 = OpLoad %uint %46 +OpReturnValue %47 +OpFunctionEnd +%56 = OpFunction %void None %57 +%58 = OpFunctionParameter %uint +%59 = OpFunctionParameter %uint +%60 = OpFunctionParameter %uint +%61 = OpFunctionParameter %uint +%62 = OpLabel +%66 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_0 +%69 = OpAtomicIAdd %uint %66 %uint_4 %uint_0 %uint_10 +%70 = OpIAdd %uint %69 %uint_10 +%71 = OpArrayLength %uint %65 1 +%72 = OpULessThanEqual %bool %70 %71 +OpSelectionMerge %73 None +OpBranchConditional %72 %74 %73 +%74 = OpLabel +%75 = OpIAdd %uint %69 %uint_0 +%76 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %75 +OpStore %76 %uint_10 +%78 = OpIAdd %uint %69 %uint_1 +%79 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %78 +OpStore %79 %uint_23 +%81 = OpIAdd %uint %69 %uint_2 +%82 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %81 +OpStore %82 %58 +%85 = OpIAdd %uint %69 %uint_3 +%86 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %85 +OpStore %86 %uint_5313 +%90 = OpLoad %v3uint %89 +%91 = OpCompositeExtract %uint %90 0 +%92 = OpCompositeExtract %uint %90 1 +%93 = OpCompositeExtract %uint %90 2 +%94 = OpIAdd %uint %69 %uint_4 +%95 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %94 +OpStore %95 %91 +%97 = OpIAdd %uint %69 %uint_5 +%98 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %97 +OpStore %98 %92 +%100 = OpIAdd %uint %69 %uint_6 +%101 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %100 +OpStore %101 %93 +%103 = OpIAdd %uint %69 %uint_7 +%104 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %103 +OpStore %104 %59 +%106 = OpIAdd %uint %69 %uint_8 +%107 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %106 +OpStore %107 %60 +%109 = OpIAdd %uint %69 %uint_9 +%110 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %109 +OpStore %110 %61 +OpBranch %73 +%73 = OpLabel +OpReturn +OpFunctionEnd +%115 = OpFunction %uint None %116 +%117 = OpFunctionParameter %uint +%118 = OpFunctionParameter %uint +%119 = OpFunctionParameter %uint +%120 = OpFunctionParameter %uint +%121 = OpLabel +%122 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %117 +%123 = OpLoad %uint %122 +%124 = OpIAdd %uint %123 %118 +%125 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %124 +%126 = OpLoad %uint %125 +%127 = OpIAdd %uint %126 %119 +%128 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %127 +%129 = OpLoad %uint %128 +%130 = OpIAdd %uint %129 %120 +%131 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %130 +%132 = OpLoad %uint %131 +OpReturnValue %132 +OpFunctionEnd +)"; + + // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck( + defs_before + func_before, defs_after + func_after + new_funcs, true, + true, 7u, 23u, true, true); +} + +TEST_F(InstBindlessTest, + InstBoundsIntersectionInitLoadVariableSizedSampledImagesArray) { + // #version 460 + // #extension GL_EXT_nonuniform_qualifier : require + // #extension GL_NV_ray_tracing : require + // + // layout(set = 0, binding = 0, std140) buffer StorageBuffer { + // uint index; + // float red; + // } sbo; + // + // layout(set = 0, binding = 1, rgba32f) readonly uniform image2D images[]; + // + // void main() + // { + // sbo.red = imageLoad(images[sbo.index], ivec2(0, 0)).r; + // } + + const std::string defs_before = + R"(OpCapability RuntimeDescriptorArray +OpCapability RayTracingNV +OpExtension "SPV_EXT_descriptor_indexing" +OpExtension "SPV_NV_ray_tracing" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint IntersectionNV %main "main" +OpSource GLSL 460 +OpSourceExtension "GL_EXT_nonuniform_qualifier" +OpSourceExtension "GL_NV_ray_tracing" +OpName %main "main" +OpName %StorageBuffer "StorageBuffer" +OpMemberName %StorageBuffer 0 "index" +OpMemberName %StorageBuffer 1 "red" +OpName %sbo "sbo" +OpName %images "images" +OpMemberDecorate %StorageBuffer 0 Offset 0 +OpMemberDecorate %StorageBuffer 1 Offset 4 +OpDecorate %StorageBuffer BufferBlock +OpDecorate %sbo DescriptorSet 0 +OpDecorate %sbo Binding 0 +OpDecorate %images DescriptorSet 0 +OpDecorate %images Binding 1 +OpDecorate %images NonWritable +%void = OpTypeVoid +)"; + + const std::string defs_after = + R"(OpCapability RuntimeDescriptorArray +OpCapability RayTracingNV +OpExtension "SPV_EXT_descriptor_indexing" +OpExtension "SPV_NV_ray_tracing" +OpExtension "SPV_KHR_storage_buffer_storage_class" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint IntersectionNV %main "main" %89 +OpSource GLSL 460 +OpSourceExtension "GL_EXT_nonuniform_qualifier" +OpSourceExtension "GL_NV_ray_tracing" +OpName %main "main" +OpName %StorageBuffer "StorageBuffer" +OpMemberName %StorageBuffer 0 "index" +OpMemberName %StorageBuffer 1 "red" +OpName %sbo "sbo" +OpName %images "images" +OpMemberDecorate %StorageBuffer 0 Offset 0 +OpMemberDecorate %StorageBuffer 1 Offset 4 +OpDecorate %StorageBuffer BufferBlock +OpDecorate %sbo DescriptorSet 0 +OpDecorate %sbo Binding 0 +OpDecorate %images DescriptorSet 0 +OpDecorate %images Binding 1 +OpDecorate %images NonWritable +OpDecorate %_runtimearr_uint ArrayStride 4 +OpDecorate %_struct_39 Block +OpMemberDecorate %_struct_39 0 Offset 0 +OpDecorate %41 DescriptorSet 7 +OpDecorate %41 Binding 1 +OpDecorate %_struct_63 Block +OpMemberDecorate %_struct_63 0 Offset 0 +OpMemberDecorate %_struct_63 1 Offset 4 +OpDecorate %65 DescriptorSet 7 +OpDecorate %65 Binding 0 +OpDecorate %89 BuiltIn LaunchIdNV +%void = OpTypeVoid +)"; + + const std::string func_before = + R"(%3 = OpTypeFunction %void +%uint = OpTypeInt 32 0 +%float = OpTypeFloat 32 +%StorageBuffer = OpTypeStruct %uint %float +%_ptr_Uniform_StorageBuffer = OpTypePointer Uniform %StorageBuffer +%sbo = OpVariable %_ptr_Uniform_StorageBuffer Uniform +%int = OpTypeInt 32 1 +%int_1 = OpConstant %int 1 +%13 = OpTypeImage %float 2D 0 0 0 2 Rgba32f +%_runtimearr_13 = OpTypeRuntimeArray %13 +%_ptr_UniformConstant__runtimearr_13 = OpTypePointer UniformConstant %_runtimearr_13 +%images = OpVariable %_ptr_UniformConstant__runtimearr_13 UniformConstant +%int_0 = OpConstant %int 0 +%_ptr_Uniform_uint = OpTypePointer Uniform %uint +%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13 +%v2int = OpTypeVector %int 2 +%25 = OpConstantComposite %v2int %int_0 %int_0 +%v4float = OpTypeVector %float 4 +%uint_0 = OpConstant %uint 0 +%_ptr_Uniform_float = OpTypePointer Uniform %float +%main = OpFunction %void None %3 +%5 = OpLabel +%19 = OpAccessChain %_ptr_Uniform_uint %sbo %int_0 +%20 = OpLoad %uint %19 +%22 = OpAccessChain %_ptr_UniformConstant_13 %images %20 +%23 = OpLoad %13 %22 +%27 = OpImageRead %v4float %23 %25 +%29 = OpCompositeExtract %float %27 0 +%31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 +OpStore %31 %29 +OpReturn +OpFunctionEnd +)"; + + const std::string func_after = + R"(%7 = OpTypeFunction %void +%uint = OpTypeInt 32 0 +%float = OpTypeFloat 32 +%StorageBuffer = OpTypeStruct %uint %float +%_ptr_Uniform_StorageBuffer = OpTypePointer Uniform %StorageBuffer +%sbo = OpVariable %_ptr_Uniform_StorageBuffer Uniform +%int = OpTypeInt 32 1 +%int_1 = OpConstant %int 1 +%13 = OpTypeImage %float 2D 0 0 0 2 Rgba32f +%_runtimearr_13 = OpTypeRuntimeArray %13 +%_ptr_UniformConstant__runtimearr_13 = OpTypePointer UniformConstant %_runtimearr_13 +%images = OpVariable %_ptr_UniformConstant__runtimearr_13 UniformConstant +%int_0 = OpConstant %int 0 +%_ptr_Uniform_uint = OpTypePointer Uniform %uint +%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13 +%v2int = OpTypeVector %int 2 +%20 = OpConstantComposite %v2int %int_0 %int_0 +%v4float = OpTypeVector %float 4 +%uint_0 = OpConstant %uint 0 +%_ptr_Uniform_float = OpTypePointer Uniform %float +%uint_1 = OpConstant %uint 1 +%34 = OpTypeFunction %uint %uint %uint +%_runtimearr_uint = OpTypeRuntimeArray %uint +%_struct_39 = OpTypeStruct %_runtimearr_uint +%_ptr_StorageBuffer__struct_39 = OpTypePointer StorageBuffer %_struct_39 +%41 = OpVariable %_ptr_StorageBuffer__struct_39 StorageBuffer +%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint +%bool = OpTypeBool +%57 = OpTypeFunction %void %uint %uint %uint %uint +%_struct_63 = OpTypeStruct %uint %_runtimearr_uint +%_ptr_StorageBuffer__struct_63 = OpTypePointer StorageBuffer %_struct_63 +%65 = OpVariable %_ptr_StorageBuffer__struct_63 StorageBuffer +%uint_10 = OpConstant %uint 10 +%uint_4 = OpConstant %uint 4 +%uint_23 = OpConstant %uint 23 +%uint_2 = OpConstant %uint 2 +%uint_5314 = OpConstant %uint 5314 +%uint_3 = OpConstant %uint 3 +%v3uint = OpTypeVector %uint 3 +%_ptr_Input_v3uint = OpTypePointer Input %v3uint +%89 = OpVariable %_ptr_Input_v3uint Input +%uint_5 = OpConstant %uint 5 +%uint_6 = OpConstant %uint 6 +%uint_7 = OpConstant %uint 7 +%uint_8 = OpConstant %uint 8 +%uint_9 = OpConstant %uint 9 +%uint_51 = OpConstant %uint 51 +%113 = OpConstantNull %v4float +%116 = OpTypeFunction %uint %uint %uint %uint %uint +%uint_48 = OpConstant %uint 48 +%141 = OpConstantNull %uint +%uint_54 = OpConstant %uint 54 +%main = OpFunction %void None %7 +%24 = OpLabel +%25 = OpAccessChain %_ptr_Uniform_uint %sbo %int_0 +%133 = OpFunctionCall %uint %115 %uint_0 %uint_0 %uint_0 %uint_0 +%134 = OpINotEqual %bool %133 %uint_0 +OpSelectionMerge %135 None +OpBranchConditional %134 %136 %137 +%136 = OpLabel +%138 = OpLoad %uint %25 +OpBranch %135 +%137 = OpLabel +%140 = OpFunctionCall %void %56 %uint_48 %uint_1 %uint_0 %uint_0 +OpBranch %135 +%135 = OpLabel +%142 = OpPhi %uint %138 %136 %141 %137 +%27 = OpAccessChain %_ptr_UniformConstant_13 %images %142 +%28 = OpLoad %13 %27 +%48 = OpFunctionCall %uint %33 %uint_1 %uint_1 +%50 = OpULessThan %bool %142 %48 +OpSelectionMerge %51 None +OpBranchConditional %50 %52 %53 +%52 = OpLabel +%54 = OpLoad %13 %27 +%143 = OpFunctionCall %uint %115 %uint_0 %uint_0 %uint_1 %142 +%144 = OpINotEqual %bool %143 %uint_0 +OpSelectionMerge %145 None +OpBranchConditional %144 %146 %147 +%146 = OpLabel +%148 = OpLoad %13 %27 +%149 = OpImageRead %v4float %148 %20 +OpBranch %145 +%147 = OpLabel +%150 = OpFunctionCall %void %56 %uint_51 %uint_1 %142 %uint_0 +OpBranch %145 +%145 = OpLabel +%151 = OpPhi %v4float %149 %146 %113 %147 +OpBranch %51 +%53 = OpLabel +%112 = OpFunctionCall %void %56 %uint_51 %uint_0 %142 %48 +OpBranch %51 +%51 = OpLabel +%114 = OpPhi %v4float %151 %145 %113 %53 +%30 = OpCompositeExtract %float %114 0 +%31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 +%152 = OpFunctionCall %uint %115 %uint_0 %uint_0 %uint_0 %uint_0 +%153 = OpINotEqual %bool %152 %uint_0 +OpSelectionMerge %154 None +OpBranchConditional %153 %155 %156 +%155 = OpLabel +OpStore %31 %30 +OpBranch %154 +%156 = OpLabel +%158 = OpFunctionCall %void %56 %uint_54 %uint_1 %uint_0 %uint_0 +OpBranch %154 +%154 = OpLabel +OpReturn +OpFunctionEnd +)"; + + const std::string new_funcs = + R"(%33 = OpFunction %uint None %34 +%35 = OpFunctionParameter %uint +%36 = OpFunctionParameter %uint +%37 = OpLabel +%43 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %35 +%44 = OpLoad %uint %43 +%45 = OpIAdd %uint %44 %36 +%46 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %45 +%47 = OpLoad %uint %46 +OpReturnValue %47 +OpFunctionEnd +%56 = OpFunction %void None %57 +%58 = OpFunctionParameter %uint +%59 = OpFunctionParameter %uint +%60 = OpFunctionParameter %uint +%61 = OpFunctionParameter %uint +%62 = OpLabel +%66 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_0 +%69 = OpAtomicIAdd %uint %66 %uint_4 %uint_0 %uint_10 +%70 = OpIAdd %uint %69 %uint_10 +%71 = OpArrayLength %uint %65 1 +%72 = OpULessThanEqual %bool %70 %71 +OpSelectionMerge %73 None +OpBranchConditional %72 %74 %73 +%74 = OpLabel +%75 = OpIAdd %uint %69 %uint_0 +%76 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %75 +OpStore %76 %uint_10 +%78 = OpIAdd %uint %69 %uint_1 +%79 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %78 +OpStore %79 %uint_23 +%81 = OpIAdd %uint %69 %uint_2 +%82 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %81 +OpStore %82 %58 +%85 = OpIAdd %uint %69 %uint_3 +%86 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %85 +OpStore %86 %uint_5314 +%90 = OpLoad %v3uint %89 +%91 = OpCompositeExtract %uint %90 0 +%92 = OpCompositeExtract %uint %90 1 +%93 = OpCompositeExtract %uint %90 2 +%94 = OpIAdd %uint %69 %uint_4 +%95 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %94 +OpStore %95 %91 +%97 = OpIAdd %uint %69 %uint_5 +%98 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %97 +OpStore %98 %92 +%100 = OpIAdd %uint %69 %uint_6 +%101 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %100 +OpStore %101 %93 +%103 = OpIAdd %uint %69 %uint_7 +%104 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %103 +OpStore %104 %59 +%106 = OpIAdd %uint %69 %uint_8 +%107 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %106 +OpStore %107 %60 +%109 = OpIAdd %uint %69 %uint_9 +%110 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %109 +OpStore %110 %61 +OpBranch %73 +%73 = OpLabel +OpReturn +OpFunctionEnd +%115 = OpFunction %uint None %116 +%117 = OpFunctionParameter %uint +%118 = OpFunctionParameter %uint +%119 = OpFunctionParameter %uint +%120 = OpFunctionParameter %uint +%121 = OpLabel +%122 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %117 +%123 = OpLoad %uint %122 +%124 = OpIAdd %uint %123 %118 +%125 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %124 +%126 = OpLoad %uint %125 +%127 = OpIAdd %uint %126 %119 +%128 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %127 +%129 = OpLoad %uint %128 +%130 = OpIAdd %uint %129 %120 +%131 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %130 +%132 = OpLoad %uint %131 +OpReturnValue %132 +OpFunctionEnd +)"; + + // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck( + defs_before + func_before, defs_after + func_after + new_funcs, true, + true, 7u, 23u, true, true); +} + +TEST_F(InstBindlessTest, + InstBoundsAnyHitInitLoadVariableSizedSampledImagesArray) { + // #version 460 + // #extension GL_EXT_nonuniform_qualifier : require + // #extension GL_NV_ray_tracing : require + // + // layout(set = 0, binding = 0, std140) buffer StorageBuffer { + // uint index; + // float red; + // } sbo; + // + // layout(set = 0, binding = 1, rgba32f) readonly uniform image2D images[]; + // + // void main() + // { + // sbo.red = imageLoad(images[sbo.index], ivec2(0, 0)).r; + // } + + const std::string defs_before = + R"(OpCapability RuntimeDescriptorArray +OpCapability RayTracingNV +OpExtension "SPV_EXT_descriptor_indexing" +OpExtension "SPV_NV_ray_tracing" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint AnyHitNV %main "main" +OpSource GLSL 460 +OpSourceExtension "GL_EXT_nonuniform_qualifier" +OpSourceExtension "GL_NV_ray_tracing" +OpName %main "main" +OpName %StorageBuffer "StorageBuffer" +OpMemberName %StorageBuffer 0 "index" +OpMemberName %StorageBuffer 1 "red" +OpName %sbo "sbo" +OpName %images "images" +OpMemberDecorate %StorageBuffer 0 Offset 0 +OpMemberDecorate %StorageBuffer 1 Offset 4 +OpDecorate %StorageBuffer BufferBlock +OpDecorate %sbo DescriptorSet 0 +OpDecorate %sbo Binding 0 +OpDecorate %images DescriptorSet 0 +OpDecorate %images Binding 1 +OpDecorate %images NonWritable +%void = OpTypeVoid +)"; + + const std::string defs_after = + R"(OpCapability RuntimeDescriptorArray +OpCapability RayTracingNV +OpExtension "SPV_EXT_descriptor_indexing" +OpExtension "SPV_NV_ray_tracing" +OpExtension "SPV_KHR_storage_buffer_storage_class" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint AnyHitNV %main "main" %89 +OpSource GLSL 460 +OpSourceExtension "GL_EXT_nonuniform_qualifier" +OpSourceExtension "GL_NV_ray_tracing" +OpName %main "main" +OpName %StorageBuffer "StorageBuffer" +OpMemberName %StorageBuffer 0 "index" +OpMemberName %StorageBuffer 1 "red" +OpName %sbo "sbo" +OpName %images "images" +OpMemberDecorate %StorageBuffer 0 Offset 0 +OpMemberDecorate %StorageBuffer 1 Offset 4 +OpDecorate %StorageBuffer BufferBlock +OpDecorate %sbo DescriptorSet 0 +OpDecorate %sbo Binding 0 +OpDecorate %images DescriptorSet 0 +OpDecorate %images Binding 1 +OpDecorate %images NonWritable +OpDecorate %_runtimearr_uint ArrayStride 4 +OpDecorate %_struct_39 Block +OpMemberDecorate %_struct_39 0 Offset 0 +OpDecorate %41 DescriptorSet 7 +OpDecorate %41 Binding 1 +OpDecorate %_struct_63 Block +OpMemberDecorate %_struct_63 0 Offset 0 +OpMemberDecorate %_struct_63 1 Offset 4 +OpDecorate %65 DescriptorSet 7 +OpDecorate %65 Binding 0 +OpDecorate %89 BuiltIn LaunchIdNV +%void = OpTypeVoid +)"; + + const std::string func_before = + R"(%3 = OpTypeFunction %void +%uint = OpTypeInt 32 0 +%float = OpTypeFloat 32 +%StorageBuffer = OpTypeStruct %uint %float +%_ptr_Uniform_StorageBuffer = OpTypePointer Uniform %StorageBuffer +%sbo = OpVariable %_ptr_Uniform_StorageBuffer Uniform +%int = OpTypeInt 32 1 +%int_1 = OpConstant %int 1 +%13 = OpTypeImage %float 2D 0 0 0 2 Rgba32f +%_runtimearr_13 = OpTypeRuntimeArray %13 +%_ptr_UniformConstant__runtimearr_13 = OpTypePointer UniformConstant %_runtimearr_13 +%images = OpVariable %_ptr_UniformConstant__runtimearr_13 UniformConstant +%int_0 = OpConstant %int 0 +%_ptr_Uniform_uint = OpTypePointer Uniform %uint +%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13 +%v2int = OpTypeVector %int 2 +%25 = OpConstantComposite %v2int %int_0 %int_0 +%v4float = OpTypeVector %float 4 +%uint_0 = OpConstant %uint 0 +%_ptr_Uniform_float = OpTypePointer Uniform %float +%main = OpFunction %void None %3 +%5 = OpLabel +%19 = OpAccessChain %_ptr_Uniform_uint %sbo %int_0 +%20 = OpLoad %uint %19 +%22 = OpAccessChain %_ptr_UniformConstant_13 %images %20 +%23 = OpLoad %13 %22 +%27 = OpImageRead %v4float %23 %25 +%29 = OpCompositeExtract %float %27 0 +%31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 +OpStore %31 %29 +OpReturn +OpFunctionEnd +)"; + + const std::string func_after = + R"(%7 = OpTypeFunction %void +%uint = OpTypeInt 32 0 +%float = OpTypeFloat 32 +%StorageBuffer = OpTypeStruct %uint %float +%_ptr_Uniform_StorageBuffer = OpTypePointer Uniform %StorageBuffer +%sbo = OpVariable %_ptr_Uniform_StorageBuffer Uniform +%int = OpTypeInt 32 1 +%int_1 = OpConstant %int 1 +%13 = OpTypeImage %float 2D 0 0 0 2 Rgba32f +%_runtimearr_13 = OpTypeRuntimeArray %13 +%_ptr_UniformConstant__runtimearr_13 = OpTypePointer UniformConstant %_runtimearr_13 +%images = OpVariable %_ptr_UniformConstant__runtimearr_13 UniformConstant +%int_0 = OpConstant %int 0 +%_ptr_Uniform_uint = OpTypePointer Uniform %uint +%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13 +%v2int = OpTypeVector %int 2 +%20 = OpConstantComposite %v2int %int_0 %int_0 +%v4float = OpTypeVector %float 4 +%uint_0 = OpConstant %uint 0 +%_ptr_Uniform_float = OpTypePointer Uniform %float +%uint_1 = OpConstant %uint 1 +%34 = OpTypeFunction %uint %uint %uint +%_runtimearr_uint = OpTypeRuntimeArray %uint +%_struct_39 = OpTypeStruct %_runtimearr_uint +%_ptr_StorageBuffer__struct_39 = OpTypePointer StorageBuffer %_struct_39 +%41 = OpVariable %_ptr_StorageBuffer__struct_39 StorageBuffer +%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint +%bool = OpTypeBool +%57 = OpTypeFunction %void %uint %uint %uint %uint +%_struct_63 = OpTypeStruct %uint %_runtimearr_uint +%_ptr_StorageBuffer__struct_63 = OpTypePointer StorageBuffer %_struct_63 +%65 = OpVariable %_ptr_StorageBuffer__struct_63 StorageBuffer +%uint_10 = OpConstant %uint 10 +%uint_4 = OpConstant %uint 4 +%uint_23 = OpConstant %uint 23 +%uint_2 = OpConstant %uint 2 +%uint_5315 = OpConstant %uint 5315 +%uint_3 = OpConstant %uint 3 +%v3uint = OpTypeVector %uint 3 +%_ptr_Input_v3uint = OpTypePointer Input %v3uint +%89 = OpVariable %_ptr_Input_v3uint Input +%uint_5 = OpConstant %uint 5 +%uint_6 = OpConstant %uint 6 +%uint_7 = OpConstant %uint 7 +%uint_8 = OpConstant %uint 8 +%uint_9 = OpConstant %uint 9 +%uint_51 = OpConstant %uint 51 +%113 = OpConstantNull %v4float +%116 = OpTypeFunction %uint %uint %uint %uint %uint +%uint_48 = OpConstant %uint 48 +%141 = OpConstantNull %uint +%uint_54 = OpConstant %uint 54 +%main = OpFunction %void None %7 +%24 = OpLabel +%25 = OpAccessChain %_ptr_Uniform_uint %sbo %int_0 +%133 = OpFunctionCall %uint %115 %uint_0 %uint_0 %uint_0 %uint_0 +%134 = OpINotEqual %bool %133 %uint_0 +OpSelectionMerge %135 None +OpBranchConditional %134 %136 %137 +%136 = OpLabel +%138 = OpLoad %uint %25 +OpBranch %135 +%137 = OpLabel +%140 = OpFunctionCall %void %56 %uint_48 %uint_1 %uint_0 %uint_0 +OpBranch %135 +%135 = OpLabel +%142 = OpPhi %uint %138 %136 %141 %137 +%27 = OpAccessChain %_ptr_UniformConstant_13 %images %142 +%28 = OpLoad %13 %27 +%48 = OpFunctionCall %uint %33 %uint_1 %uint_1 +%50 = OpULessThan %bool %142 %48 +OpSelectionMerge %51 None +OpBranchConditional %50 %52 %53 +%52 = OpLabel +%54 = OpLoad %13 %27 +%143 = OpFunctionCall %uint %115 %uint_0 %uint_0 %uint_1 %142 +%144 = OpINotEqual %bool %143 %uint_0 +OpSelectionMerge %145 None +OpBranchConditional %144 %146 %147 +%146 = OpLabel +%148 = OpLoad %13 %27 +%149 = OpImageRead %v4float %148 %20 +OpBranch %145 +%147 = OpLabel +%150 = OpFunctionCall %void %56 %uint_51 %uint_1 %142 %uint_0 +OpBranch %145 +%145 = OpLabel +%151 = OpPhi %v4float %149 %146 %113 %147 +OpBranch %51 +%53 = OpLabel +%112 = OpFunctionCall %void %56 %uint_51 %uint_0 %142 %48 +OpBranch %51 +%51 = OpLabel +%114 = OpPhi %v4float %151 %145 %113 %53 +%30 = OpCompositeExtract %float %114 0 +%31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 +%152 = OpFunctionCall %uint %115 %uint_0 %uint_0 %uint_0 %uint_0 +%153 = OpINotEqual %bool %152 %uint_0 +OpSelectionMerge %154 None +OpBranchConditional %153 %155 %156 +%155 = OpLabel +OpStore %31 %30 +OpBranch %154 +%156 = OpLabel +%158 = OpFunctionCall %void %56 %uint_54 %uint_1 %uint_0 %uint_0 +OpBranch %154 +%154 = OpLabel +OpReturn +OpFunctionEnd +)"; + + const std::string new_funcs = + R"(%33 = OpFunction %uint None %34 +%35 = OpFunctionParameter %uint +%36 = OpFunctionParameter %uint +%37 = OpLabel +%43 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %35 +%44 = OpLoad %uint %43 +%45 = OpIAdd %uint %44 %36 +%46 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %45 +%47 = OpLoad %uint %46 +OpReturnValue %47 +OpFunctionEnd +%56 = OpFunction %void None %57 +%58 = OpFunctionParameter %uint +%59 = OpFunctionParameter %uint +%60 = OpFunctionParameter %uint +%61 = OpFunctionParameter %uint +%62 = OpLabel +%66 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_0 +%69 = OpAtomicIAdd %uint %66 %uint_4 %uint_0 %uint_10 +%70 = OpIAdd %uint %69 %uint_10 +%71 = OpArrayLength %uint %65 1 +%72 = OpULessThanEqual %bool %70 %71 +OpSelectionMerge %73 None +OpBranchConditional %72 %74 %73 +%74 = OpLabel +%75 = OpIAdd %uint %69 %uint_0 +%76 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %75 +OpStore %76 %uint_10 +%78 = OpIAdd %uint %69 %uint_1 +%79 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %78 +OpStore %79 %uint_23 +%81 = OpIAdd %uint %69 %uint_2 +%82 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %81 +OpStore %82 %58 +%85 = OpIAdd %uint %69 %uint_3 +%86 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %85 +OpStore %86 %uint_5315 +%90 = OpLoad %v3uint %89 +%91 = OpCompositeExtract %uint %90 0 +%92 = OpCompositeExtract %uint %90 1 +%93 = OpCompositeExtract %uint %90 2 +%94 = OpIAdd %uint %69 %uint_4 +%95 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %94 +OpStore %95 %91 +%97 = OpIAdd %uint %69 %uint_5 +%98 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %97 +OpStore %98 %92 +%100 = OpIAdd %uint %69 %uint_6 +%101 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %100 +OpStore %101 %93 +%103 = OpIAdd %uint %69 %uint_7 +%104 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %103 +OpStore %104 %59 +%106 = OpIAdd %uint %69 %uint_8 +%107 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %106 +OpStore %107 %60 +%109 = OpIAdd %uint %69 %uint_9 +%110 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %109 +OpStore %110 %61 +OpBranch %73 +%73 = OpLabel +OpReturn +OpFunctionEnd +%115 = OpFunction %uint None %116 +%117 = OpFunctionParameter %uint +%118 = OpFunctionParameter %uint +%119 = OpFunctionParameter %uint +%120 = OpFunctionParameter %uint +%121 = OpLabel +%122 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %117 +%123 = OpLoad %uint %122 +%124 = OpIAdd %uint %123 %118 +%125 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %124 +%126 = OpLoad %uint %125 +%127 = OpIAdd %uint %126 %119 +%128 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %127 +%129 = OpLoad %uint %128 +%130 = OpIAdd %uint %129 %120 +%131 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %130 +%132 = OpLoad %uint %131 +OpReturnValue %132 +OpFunctionEnd +)"; + + // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck( + defs_before + func_before, defs_after + func_after + new_funcs, true, + true, 7u, 23u, true, true); +} + +TEST_F(InstBindlessTest, + InstBoundsClosestHitInitLoadVariableSizedSampledImagesArray) { + // #version 460 + // #extension GL_EXT_nonuniform_qualifier : require + // #extension GL_NV_ray_tracing : require + // + // layout(set = 0, binding = 0, std140) buffer StorageBuffer { + // uint index; + // float red; + // } sbo; + // + // layout(set = 0, binding = 1, rgba32f) readonly uniform image2D images[]; + // + // void main() + // { + // sbo.red = imageLoad(images[sbo.index], ivec2(0, 0)).r; + // } + + const std::string defs_before = + R"(OpCapability RuntimeDescriptorArray +OpCapability RayTracingNV +OpExtension "SPV_EXT_descriptor_indexing" +OpExtension "SPV_NV_ray_tracing" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint ClosestHitNV %main "main" +OpSource GLSL 460 +OpSourceExtension "GL_EXT_nonuniform_qualifier" +OpSourceExtension "GL_NV_ray_tracing" +OpName %main "main" +OpName %StorageBuffer "StorageBuffer" +OpMemberName %StorageBuffer 0 "index" +OpMemberName %StorageBuffer 1 "red" +OpName %sbo "sbo" +OpName %images "images" +OpMemberDecorate %StorageBuffer 0 Offset 0 +OpMemberDecorate %StorageBuffer 1 Offset 4 +OpDecorate %StorageBuffer BufferBlock +OpDecorate %sbo DescriptorSet 0 +OpDecorate %sbo Binding 0 +OpDecorate %images DescriptorSet 0 +OpDecorate %images Binding 1 +OpDecorate %images NonWritable +%void = OpTypeVoid +)"; + + const std::string defs_after = + R"(OpCapability RuntimeDescriptorArray +OpCapability RayTracingNV +OpExtension "SPV_EXT_descriptor_indexing" +OpExtension "SPV_NV_ray_tracing" +OpExtension "SPV_KHR_storage_buffer_storage_class" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint ClosestHitNV %main "main" %89 +OpSource GLSL 460 +OpSourceExtension "GL_EXT_nonuniform_qualifier" +OpSourceExtension "GL_NV_ray_tracing" +OpName %main "main" +OpName %StorageBuffer "StorageBuffer" +OpMemberName %StorageBuffer 0 "index" +OpMemberName %StorageBuffer 1 "red" +OpName %sbo "sbo" +OpName %images "images" +OpMemberDecorate %StorageBuffer 0 Offset 0 +OpMemberDecorate %StorageBuffer 1 Offset 4 +OpDecorate %StorageBuffer BufferBlock +OpDecorate %sbo DescriptorSet 0 +OpDecorate %sbo Binding 0 +OpDecorate %images DescriptorSet 0 +OpDecorate %images Binding 1 +OpDecorate %images NonWritable +OpDecorate %_runtimearr_uint ArrayStride 4 +OpDecorate %_struct_39 Block +OpMemberDecorate %_struct_39 0 Offset 0 +OpDecorate %41 DescriptorSet 7 +OpDecorate %41 Binding 1 +OpDecorate %_struct_63 Block +OpMemberDecorate %_struct_63 0 Offset 0 +OpMemberDecorate %_struct_63 1 Offset 4 +OpDecorate %65 DescriptorSet 7 +OpDecorate %65 Binding 0 +OpDecorate %89 BuiltIn LaunchIdNV +%void = OpTypeVoid +)"; + + const std::string func_before = + R"(%3 = OpTypeFunction %void +%uint = OpTypeInt 32 0 +%float = OpTypeFloat 32 +%StorageBuffer = OpTypeStruct %uint %float +%_ptr_Uniform_StorageBuffer = OpTypePointer Uniform %StorageBuffer +%sbo = OpVariable %_ptr_Uniform_StorageBuffer Uniform +%int = OpTypeInt 32 1 +%int_1 = OpConstant %int 1 +%13 = OpTypeImage %float 2D 0 0 0 2 Rgba32f +%_runtimearr_13 = OpTypeRuntimeArray %13 +%_ptr_UniformConstant__runtimearr_13 = OpTypePointer UniformConstant %_runtimearr_13 +%images = OpVariable %_ptr_UniformConstant__runtimearr_13 UniformConstant +%int_0 = OpConstant %int 0 +%_ptr_Uniform_uint = OpTypePointer Uniform %uint +%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13 +%v2int = OpTypeVector %int 2 +%25 = OpConstantComposite %v2int %int_0 %int_0 +%v4float = OpTypeVector %float 4 +%uint_0 = OpConstant %uint 0 +%_ptr_Uniform_float = OpTypePointer Uniform %float +%main = OpFunction %void None %3 +%5 = OpLabel +%19 = OpAccessChain %_ptr_Uniform_uint %sbo %int_0 +%20 = OpLoad %uint %19 +%22 = OpAccessChain %_ptr_UniformConstant_13 %images %20 +%23 = OpLoad %13 %22 +%27 = OpImageRead %v4float %23 %25 +%29 = OpCompositeExtract %float %27 0 +%31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 +OpStore %31 %29 +OpReturn +OpFunctionEnd +)"; + + const std::string func_after = + R"(%7 = OpTypeFunction %void +%uint = OpTypeInt 32 0 +%float = OpTypeFloat 32 +%StorageBuffer = OpTypeStruct %uint %float +%_ptr_Uniform_StorageBuffer = OpTypePointer Uniform %StorageBuffer +%sbo = OpVariable %_ptr_Uniform_StorageBuffer Uniform +%int = OpTypeInt 32 1 +%int_1 = OpConstant %int 1 +%13 = OpTypeImage %float 2D 0 0 0 2 Rgba32f +%_runtimearr_13 = OpTypeRuntimeArray %13 +%_ptr_UniformConstant__runtimearr_13 = OpTypePointer UniformConstant %_runtimearr_13 +%images = OpVariable %_ptr_UniformConstant__runtimearr_13 UniformConstant +%int_0 = OpConstant %int 0 +%_ptr_Uniform_uint = OpTypePointer Uniform %uint +%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13 +%v2int = OpTypeVector %int 2 +%20 = OpConstantComposite %v2int %int_0 %int_0 +%v4float = OpTypeVector %float 4 +%uint_0 = OpConstant %uint 0 +%_ptr_Uniform_float = OpTypePointer Uniform %float +%uint_1 = OpConstant %uint 1 +%34 = OpTypeFunction %uint %uint %uint +%_runtimearr_uint = OpTypeRuntimeArray %uint +%_struct_39 = OpTypeStruct %_runtimearr_uint +%_ptr_StorageBuffer__struct_39 = OpTypePointer StorageBuffer %_struct_39 +%41 = OpVariable %_ptr_StorageBuffer__struct_39 StorageBuffer +%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint +%bool = OpTypeBool +%57 = OpTypeFunction %void %uint %uint %uint %uint +%_struct_63 = OpTypeStruct %uint %_runtimearr_uint +%_ptr_StorageBuffer__struct_63 = OpTypePointer StorageBuffer %_struct_63 +%65 = OpVariable %_ptr_StorageBuffer__struct_63 StorageBuffer +%uint_10 = OpConstant %uint 10 +%uint_4 = OpConstant %uint 4 +%uint_23 = OpConstant %uint 23 +%uint_2 = OpConstant %uint 2 +%uint_5316 = OpConstant %uint 5316 +%uint_3 = OpConstant %uint 3 +%v3uint = OpTypeVector %uint 3 +%_ptr_Input_v3uint = OpTypePointer Input %v3uint +%89 = OpVariable %_ptr_Input_v3uint Input +%uint_5 = OpConstant %uint 5 +%uint_6 = OpConstant %uint 6 +%uint_7 = OpConstant %uint 7 +%uint_8 = OpConstant %uint 8 +%uint_9 = OpConstant %uint 9 +%uint_51 = OpConstant %uint 51 +%113 = OpConstantNull %v4float +%116 = OpTypeFunction %uint %uint %uint %uint %uint +%uint_48 = OpConstant %uint 48 +%141 = OpConstantNull %uint +%uint_54 = OpConstant %uint 54 +%main = OpFunction %void None %7 +%24 = OpLabel +%25 = OpAccessChain %_ptr_Uniform_uint %sbo %int_0 +%133 = OpFunctionCall %uint %115 %uint_0 %uint_0 %uint_0 %uint_0 +%134 = OpINotEqual %bool %133 %uint_0 +OpSelectionMerge %135 None +OpBranchConditional %134 %136 %137 +%136 = OpLabel +%138 = OpLoad %uint %25 +OpBranch %135 +%137 = OpLabel +%140 = OpFunctionCall %void %56 %uint_48 %uint_1 %uint_0 %uint_0 +OpBranch %135 +%135 = OpLabel +%142 = OpPhi %uint %138 %136 %141 %137 +%27 = OpAccessChain %_ptr_UniformConstant_13 %images %142 +%28 = OpLoad %13 %27 +%48 = OpFunctionCall %uint %33 %uint_1 %uint_1 +%50 = OpULessThan %bool %142 %48 +OpSelectionMerge %51 None +OpBranchConditional %50 %52 %53 +%52 = OpLabel +%54 = OpLoad %13 %27 +%143 = OpFunctionCall %uint %115 %uint_0 %uint_0 %uint_1 %142 +%144 = OpINotEqual %bool %143 %uint_0 +OpSelectionMerge %145 None +OpBranchConditional %144 %146 %147 +%146 = OpLabel +%148 = OpLoad %13 %27 +%149 = OpImageRead %v4float %148 %20 +OpBranch %145 +%147 = OpLabel +%150 = OpFunctionCall %void %56 %uint_51 %uint_1 %142 %uint_0 +OpBranch %145 +%145 = OpLabel +%151 = OpPhi %v4float %149 %146 %113 %147 +OpBranch %51 +%53 = OpLabel +%112 = OpFunctionCall %void %56 %uint_51 %uint_0 %142 %48 +OpBranch %51 +%51 = OpLabel +%114 = OpPhi %v4float %151 %145 %113 %53 +%30 = OpCompositeExtract %float %114 0 +%31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 +%152 = OpFunctionCall %uint %115 %uint_0 %uint_0 %uint_0 %uint_0 +%153 = OpINotEqual %bool %152 %uint_0 +OpSelectionMerge %154 None +OpBranchConditional %153 %155 %156 +%155 = OpLabel +OpStore %31 %30 +OpBranch %154 +%156 = OpLabel +%158 = OpFunctionCall %void %56 %uint_54 %uint_1 %uint_0 %uint_0 +OpBranch %154 +%154 = OpLabel +OpReturn +OpFunctionEnd +)"; + + const std::string new_funcs = + R"(%33 = OpFunction %uint None %34 +%35 = OpFunctionParameter %uint +%36 = OpFunctionParameter %uint +%37 = OpLabel +%43 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %35 +%44 = OpLoad %uint %43 +%45 = OpIAdd %uint %44 %36 +%46 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %45 +%47 = OpLoad %uint %46 +OpReturnValue %47 +OpFunctionEnd +%56 = OpFunction %void None %57 +%58 = OpFunctionParameter %uint +%59 = OpFunctionParameter %uint +%60 = OpFunctionParameter %uint +%61 = OpFunctionParameter %uint +%62 = OpLabel +%66 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_0 +%69 = OpAtomicIAdd %uint %66 %uint_4 %uint_0 %uint_10 +%70 = OpIAdd %uint %69 %uint_10 +%71 = OpArrayLength %uint %65 1 +%72 = OpULessThanEqual %bool %70 %71 +OpSelectionMerge %73 None +OpBranchConditional %72 %74 %73 +%74 = OpLabel +%75 = OpIAdd %uint %69 %uint_0 +%76 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %75 +OpStore %76 %uint_10 +%78 = OpIAdd %uint %69 %uint_1 +%79 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %78 +OpStore %79 %uint_23 +%81 = OpIAdd %uint %69 %uint_2 +%82 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %81 +OpStore %82 %58 +%85 = OpIAdd %uint %69 %uint_3 +%86 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %85 +OpStore %86 %uint_5316 +%90 = OpLoad %v3uint %89 +%91 = OpCompositeExtract %uint %90 0 +%92 = OpCompositeExtract %uint %90 1 +%93 = OpCompositeExtract %uint %90 2 +%94 = OpIAdd %uint %69 %uint_4 +%95 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %94 +OpStore %95 %91 +%97 = OpIAdd %uint %69 %uint_5 +%98 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %97 +OpStore %98 %92 +%100 = OpIAdd %uint %69 %uint_6 +%101 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %100 +OpStore %101 %93 +%103 = OpIAdd %uint %69 %uint_7 +%104 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %103 +OpStore %104 %59 +%106 = OpIAdd %uint %69 %uint_8 +%107 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %106 +OpStore %107 %60 +%109 = OpIAdd %uint %69 %uint_9 +%110 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %109 +OpStore %110 %61 +OpBranch %73 +%73 = OpLabel +OpReturn +OpFunctionEnd +%115 = OpFunction %uint None %116 +%117 = OpFunctionParameter %uint +%118 = OpFunctionParameter %uint +%119 = OpFunctionParameter %uint +%120 = OpFunctionParameter %uint +%121 = OpLabel +%122 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %117 +%123 = OpLoad %uint %122 +%124 = OpIAdd %uint %123 %118 +%125 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %124 +%126 = OpLoad %uint %125 +%127 = OpIAdd %uint %126 %119 +%128 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %127 +%129 = OpLoad %uint %128 +%130 = OpIAdd %uint %129 %120 +%131 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %130 +%132 = OpLoad %uint %131 +OpReturnValue %132 +OpFunctionEnd +)"; + + // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck( + defs_before + func_before, defs_after + func_after + new_funcs, true, + true, 7u, 23u, true, true); +} + +TEST_F(InstBindlessTest, + InstBoundsMissInitLoadVariableSizedSampledImagesArray) { + // #version 460 + // #extension GL_EXT_nonuniform_qualifier : require + // #extension GL_NV_ray_tracing : require + // + // layout(set = 0, binding = 0, std140) buffer StorageBuffer { + // uint index; + // float red; + // } sbo; + // + // layout(set = 0, binding = 1, rgba32f) readonly uniform image2D images[]; + // + // void main() + // { + // sbo.red = imageLoad(images[sbo.index], ivec2(0, 0)).r; + // } + + const std::string defs_before = + R"(OpCapability RuntimeDescriptorArray +OpCapability RayTracingNV +OpExtension "SPV_EXT_descriptor_indexing" +OpExtension "SPV_NV_ray_tracing" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint MissNV %main "main" +OpSource GLSL 460 +OpSourceExtension "GL_EXT_nonuniform_qualifier" +OpSourceExtension "GL_NV_ray_tracing" +OpName %main "main" +OpName %StorageBuffer "StorageBuffer" +OpMemberName %StorageBuffer 0 "index" +OpMemberName %StorageBuffer 1 "red" +OpName %sbo "sbo" +OpName %images "images" +OpMemberDecorate %StorageBuffer 0 Offset 0 +OpMemberDecorate %StorageBuffer 1 Offset 4 +OpDecorate %StorageBuffer BufferBlock +OpDecorate %sbo DescriptorSet 0 +OpDecorate %sbo Binding 0 +OpDecorate %images DescriptorSet 0 +OpDecorate %images Binding 1 +OpDecorate %images NonWritable +%void = OpTypeVoid +)"; + + const std::string defs_after = + R"(OpCapability RuntimeDescriptorArray +OpCapability RayTracingNV +OpExtension "SPV_EXT_descriptor_indexing" +OpExtension "SPV_NV_ray_tracing" +OpExtension "SPV_KHR_storage_buffer_storage_class" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint MissNV %main "main" %89 +OpSource GLSL 460 +OpSourceExtension "GL_EXT_nonuniform_qualifier" +OpSourceExtension "GL_NV_ray_tracing" +OpName %main "main" +OpName %StorageBuffer "StorageBuffer" +OpMemberName %StorageBuffer 0 "index" +OpMemberName %StorageBuffer 1 "red" +OpName %sbo "sbo" +OpName %images "images" +OpMemberDecorate %StorageBuffer 0 Offset 0 +OpMemberDecorate %StorageBuffer 1 Offset 4 +OpDecorate %StorageBuffer BufferBlock +OpDecorate %sbo DescriptorSet 0 +OpDecorate %sbo Binding 0 +OpDecorate %images DescriptorSet 0 +OpDecorate %images Binding 1 +OpDecorate %images NonWritable +OpDecorate %_runtimearr_uint ArrayStride 4 +OpDecorate %_struct_39 Block +OpMemberDecorate %_struct_39 0 Offset 0 +OpDecorate %41 DescriptorSet 7 +OpDecorate %41 Binding 1 +OpDecorate %_struct_63 Block +OpMemberDecorate %_struct_63 0 Offset 0 +OpMemberDecorate %_struct_63 1 Offset 4 +OpDecorate %65 DescriptorSet 7 +OpDecorate %65 Binding 0 +OpDecorate %89 BuiltIn LaunchIdNV +%void = OpTypeVoid +)"; + + const std::string func_before = + R"(%3 = OpTypeFunction %void +%uint = OpTypeInt 32 0 +%float = OpTypeFloat 32 +%StorageBuffer = OpTypeStruct %uint %float +%_ptr_Uniform_StorageBuffer = OpTypePointer Uniform %StorageBuffer +%sbo = OpVariable %_ptr_Uniform_StorageBuffer Uniform +%int = OpTypeInt 32 1 +%int_1 = OpConstant %int 1 +%13 = OpTypeImage %float 2D 0 0 0 2 Rgba32f +%_runtimearr_13 = OpTypeRuntimeArray %13 +%_ptr_UniformConstant__runtimearr_13 = OpTypePointer UniformConstant %_runtimearr_13 +%images = OpVariable %_ptr_UniformConstant__runtimearr_13 UniformConstant +%int_0 = OpConstant %int 0 +%_ptr_Uniform_uint = OpTypePointer Uniform %uint +%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13 +%v2int = OpTypeVector %int 2 +%25 = OpConstantComposite %v2int %int_0 %int_0 +%v4float = OpTypeVector %float 4 +%uint_0 = OpConstant %uint 0 +%_ptr_Uniform_float = OpTypePointer Uniform %float +%main = OpFunction %void None %3 +%5 = OpLabel +%19 = OpAccessChain %_ptr_Uniform_uint %sbo %int_0 +%20 = OpLoad %uint %19 +%22 = OpAccessChain %_ptr_UniformConstant_13 %images %20 +%23 = OpLoad %13 %22 +%27 = OpImageRead %v4float %23 %25 +%29 = OpCompositeExtract %float %27 0 +%31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 +OpStore %31 %29 +OpReturn +OpFunctionEnd +)"; + + const std::string func_after = + R"(%7 = OpTypeFunction %void +%uint = OpTypeInt 32 0 +%float = OpTypeFloat 32 +%StorageBuffer = OpTypeStruct %uint %float +%_ptr_Uniform_StorageBuffer = OpTypePointer Uniform %StorageBuffer +%sbo = OpVariable %_ptr_Uniform_StorageBuffer Uniform +%int = OpTypeInt 32 1 +%int_1 = OpConstant %int 1 +%13 = OpTypeImage %float 2D 0 0 0 2 Rgba32f +%_runtimearr_13 = OpTypeRuntimeArray %13 +%_ptr_UniformConstant__runtimearr_13 = OpTypePointer UniformConstant %_runtimearr_13 +%images = OpVariable %_ptr_UniformConstant__runtimearr_13 UniformConstant +%int_0 = OpConstant %int 0 +%_ptr_Uniform_uint = OpTypePointer Uniform %uint +%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13 +%v2int = OpTypeVector %int 2 +%20 = OpConstantComposite %v2int %int_0 %int_0 +%v4float = OpTypeVector %float 4 +%uint_0 = OpConstant %uint 0 +%_ptr_Uniform_float = OpTypePointer Uniform %float +%uint_1 = OpConstant %uint 1 +%34 = OpTypeFunction %uint %uint %uint +%_runtimearr_uint = OpTypeRuntimeArray %uint +%_struct_39 = OpTypeStruct %_runtimearr_uint +%_ptr_StorageBuffer__struct_39 = OpTypePointer StorageBuffer %_struct_39 +%41 = OpVariable %_ptr_StorageBuffer__struct_39 StorageBuffer +%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint +%bool = OpTypeBool +%57 = OpTypeFunction %void %uint %uint %uint %uint +%_struct_63 = OpTypeStruct %uint %_runtimearr_uint +%_ptr_StorageBuffer__struct_63 = OpTypePointer StorageBuffer %_struct_63 +%65 = OpVariable %_ptr_StorageBuffer__struct_63 StorageBuffer +%uint_10 = OpConstant %uint 10 +%uint_4 = OpConstant %uint 4 +%uint_23 = OpConstant %uint 23 +%uint_2 = OpConstant %uint 2 +%uint_5317 = OpConstant %uint 5317 +%uint_3 = OpConstant %uint 3 +%v3uint = OpTypeVector %uint 3 +%_ptr_Input_v3uint = OpTypePointer Input %v3uint +%89 = OpVariable %_ptr_Input_v3uint Input +%uint_5 = OpConstant %uint 5 +%uint_6 = OpConstant %uint 6 +%uint_7 = OpConstant %uint 7 +%uint_8 = OpConstant %uint 8 +%uint_9 = OpConstant %uint 9 +%uint_51 = OpConstant %uint 51 +%113 = OpConstantNull %v4float +%116 = OpTypeFunction %uint %uint %uint %uint %uint +%uint_48 = OpConstant %uint 48 +%141 = OpConstantNull %uint +%uint_54 = OpConstant %uint 54 +%main = OpFunction %void None %7 +%24 = OpLabel +%25 = OpAccessChain %_ptr_Uniform_uint %sbo %int_0 +%133 = OpFunctionCall %uint %115 %uint_0 %uint_0 %uint_0 %uint_0 +%134 = OpINotEqual %bool %133 %uint_0 +OpSelectionMerge %135 None +OpBranchConditional %134 %136 %137 +%136 = OpLabel +%138 = OpLoad %uint %25 +OpBranch %135 +%137 = OpLabel +%140 = OpFunctionCall %void %56 %uint_48 %uint_1 %uint_0 %uint_0 +OpBranch %135 +%135 = OpLabel +%142 = OpPhi %uint %138 %136 %141 %137 +%27 = OpAccessChain %_ptr_UniformConstant_13 %images %142 +%28 = OpLoad %13 %27 +%48 = OpFunctionCall %uint %33 %uint_1 %uint_1 +%50 = OpULessThan %bool %142 %48 +OpSelectionMerge %51 None +OpBranchConditional %50 %52 %53 +%52 = OpLabel +%54 = OpLoad %13 %27 +%143 = OpFunctionCall %uint %115 %uint_0 %uint_0 %uint_1 %142 +%144 = OpINotEqual %bool %143 %uint_0 +OpSelectionMerge %145 None +OpBranchConditional %144 %146 %147 +%146 = OpLabel +%148 = OpLoad %13 %27 +%149 = OpImageRead %v4float %148 %20 +OpBranch %145 +%147 = OpLabel +%150 = OpFunctionCall %void %56 %uint_51 %uint_1 %142 %uint_0 +OpBranch %145 +%145 = OpLabel +%151 = OpPhi %v4float %149 %146 %113 %147 +OpBranch %51 +%53 = OpLabel +%112 = OpFunctionCall %void %56 %uint_51 %uint_0 %142 %48 +OpBranch %51 +%51 = OpLabel +%114 = OpPhi %v4float %151 %145 %113 %53 +%30 = OpCompositeExtract %float %114 0 +%31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 +%152 = OpFunctionCall %uint %115 %uint_0 %uint_0 %uint_0 %uint_0 +%153 = OpINotEqual %bool %152 %uint_0 +OpSelectionMerge %154 None +OpBranchConditional %153 %155 %156 +%155 = OpLabel +OpStore %31 %30 +OpBranch %154 +%156 = OpLabel +%158 = OpFunctionCall %void %56 %uint_54 %uint_1 %uint_0 %uint_0 +OpBranch %154 +%154 = OpLabel +OpReturn +OpFunctionEnd +)"; + + const std::string new_funcs = + R"(%33 = OpFunction %uint None %34 +%35 = OpFunctionParameter %uint +%36 = OpFunctionParameter %uint +%37 = OpLabel +%43 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %35 +%44 = OpLoad %uint %43 +%45 = OpIAdd %uint %44 %36 +%46 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %45 +%47 = OpLoad %uint %46 +OpReturnValue %47 +OpFunctionEnd +%56 = OpFunction %void None %57 +%58 = OpFunctionParameter %uint +%59 = OpFunctionParameter %uint +%60 = OpFunctionParameter %uint +%61 = OpFunctionParameter %uint +%62 = OpLabel +%66 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_0 +%69 = OpAtomicIAdd %uint %66 %uint_4 %uint_0 %uint_10 +%70 = OpIAdd %uint %69 %uint_10 +%71 = OpArrayLength %uint %65 1 +%72 = OpULessThanEqual %bool %70 %71 +OpSelectionMerge %73 None +OpBranchConditional %72 %74 %73 +%74 = OpLabel +%75 = OpIAdd %uint %69 %uint_0 +%76 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %75 +OpStore %76 %uint_10 +%78 = OpIAdd %uint %69 %uint_1 +%79 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %78 +OpStore %79 %uint_23 +%81 = OpIAdd %uint %69 %uint_2 +%82 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %81 +OpStore %82 %58 +%85 = OpIAdd %uint %69 %uint_3 +%86 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %85 +OpStore %86 %uint_5317 +%90 = OpLoad %v3uint %89 +%91 = OpCompositeExtract %uint %90 0 +%92 = OpCompositeExtract %uint %90 1 +%93 = OpCompositeExtract %uint %90 2 +%94 = OpIAdd %uint %69 %uint_4 +%95 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %94 +OpStore %95 %91 +%97 = OpIAdd %uint %69 %uint_5 +%98 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %97 +OpStore %98 %92 +%100 = OpIAdd %uint %69 %uint_6 +%101 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %100 +OpStore %101 %93 +%103 = OpIAdd %uint %69 %uint_7 +%104 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %103 +OpStore %104 %59 +%106 = OpIAdd %uint %69 %uint_8 +%107 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %106 +OpStore %107 %60 +%109 = OpIAdd %uint %69 %uint_9 +%110 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %109 +OpStore %110 %61 +OpBranch %73 +%73 = OpLabel +OpReturn +OpFunctionEnd +%115 = OpFunction %uint None %116 +%117 = OpFunctionParameter %uint +%118 = OpFunctionParameter %uint +%119 = OpFunctionParameter %uint +%120 = OpFunctionParameter %uint +%121 = OpLabel +%122 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %117 +%123 = OpLoad %uint %122 +%124 = OpIAdd %uint %123 %118 +%125 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %124 +%126 = OpLoad %uint %125 +%127 = OpIAdd %uint %126 %119 +%128 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %127 +%129 = OpLoad %uint %128 +%130 = OpIAdd %uint %129 %120 +%131 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %130 +%132 = OpLoad %uint %131 +OpReturnValue %132 +OpFunctionEnd +)"; + + // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck( + defs_before + func_before, defs_after + func_after + new_funcs, true, + true, 7u, 23u, true, true); +} + +TEST_F(InstBindlessTest, + InstBoundsCallableInitLoadVariableSizedSampledImagesArray) { + // #version 460 + // #extension GL_EXT_nonuniform_qualifier : require + // #extension GL_NV_ray_tracing : require + // + // layout(set = 0, binding = 0, std140) buffer StorageBuffer { + // uint index; + // float red; + // } sbo; + // + // layout(set = 0, binding = 1, rgba32f) readonly uniform image2D images[]; + // + // void main() + // { + // sbo.red = imageLoad(images[sbo.index], ivec2(0, 0)).r; + // } + + const std::string defs_before = + R"(OpCapability RuntimeDescriptorArray +OpCapability RayTracingNV +OpExtension "SPV_EXT_descriptor_indexing" +OpExtension "SPV_NV_ray_tracing" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint CallableNV %main "main" +OpSource GLSL 460 +OpSourceExtension "GL_EXT_nonuniform_qualifier" +OpSourceExtension "GL_NV_ray_tracing" +OpName %main "main" +OpName %StorageBuffer "StorageBuffer" +OpMemberName %StorageBuffer 0 "index" +OpMemberName %StorageBuffer 1 "red" +OpName %sbo "sbo" +OpName %images "images" +OpMemberDecorate %StorageBuffer 0 Offset 0 +OpMemberDecorate %StorageBuffer 1 Offset 4 +OpDecorate %StorageBuffer BufferBlock +OpDecorate %sbo DescriptorSet 0 +OpDecorate %sbo Binding 0 +OpDecorate %images DescriptorSet 0 +OpDecorate %images Binding 1 +OpDecorate %images NonWritable +%void = OpTypeVoid +)"; + + const std::string defs_after = + R"(OpCapability RuntimeDescriptorArray +OpCapability RayTracingNV +OpExtension "SPV_EXT_descriptor_indexing" +OpExtension "SPV_NV_ray_tracing" +OpExtension "SPV_KHR_storage_buffer_storage_class" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint CallableNV %main "main" %89 +OpSource GLSL 460 +OpSourceExtension "GL_EXT_nonuniform_qualifier" +OpSourceExtension "GL_NV_ray_tracing" +OpName %main "main" +OpName %StorageBuffer "StorageBuffer" +OpMemberName %StorageBuffer 0 "index" +OpMemberName %StorageBuffer 1 "red" +OpName %sbo "sbo" +OpName %images "images" +OpMemberDecorate %StorageBuffer 0 Offset 0 +OpMemberDecorate %StorageBuffer 1 Offset 4 +OpDecorate %StorageBuffer BufferBlock +OpDecorate %sbo DescriptorSet 0 +OpDecorate %sbo Binding 0 +OpDecorate %images DescriptorSet 0 +OpDecorate %images Binding 1 +OpDecorate %images NonWritable +OpDecorate %_runtimearr_uint ArrayStride 4 +OpDecorate %_struct_39 Block +OpMemberDecorate %_struct_39 0 Offset 0 +OpDecorate %41 DescriptorSet 7 +OpDecorate %41 Binding 1 +OpDecorate %_struct_63 Block +OpMemberDecorate %_struct_63 0 Offset 0 +OpMemberDecorate %_struct_63 1 Offset 4 +OpDecorate %65 DescriptorSet 7 +OpDecorate %65 Binding 0 +OpDecorate %89 BuiltIn LaunchIdNV +%void = OpTypeVoid +)"; + + const std::string func_before = + R"(%3 = OpTypeFunction %void +%uint = OpTypeInt 32 0 +%float = OpTypeFloat 32 +%StorageBuffer = OpTypeStruct %uint %float +%_ptr_Uniform_StorageBuffer = OpTypePointer Uniform %StorageBuffer +%sbo = OpVariable %_ptr_Uniform_StorageBuffer Uniform +%int = OpTypeInt 32 1 +%int_1 = OpConstant %int 1 +%13 = OpTypeImage %float 2D 0 0 0 2 Rgba32f +%_runtimearr_13 = OpTypeRuntimeArray %13 +%_ptr_UniformConstant__runtimearr_13 = OpTypePointer UniformConstant %_runtimearr_13 +%images = OpVariable %_ptr_UniformConstant__runtimearr_13 UniformConstant +%int_0 = OpConstant %int 0 +%_ptr_Uniform_uint = OpTypePointer Uniform %uint +%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13 +%v2int = OpTypeVector %int 2 +%25 = OpConstantComposite %v2int %int_0 %int_0 +%v4float = OpTypeVector %float 4 +%uint_0 = OpConstant %uint 0 +%_ptr_Uniform_float = OpTypePointer Uniform %float +%main = OpFunction %void None %3 +%5 = OpLabel +%19 = OpAccessChain %_ptr_Uniform_uint %sbo %int_0 +%20 = OpLoad %uint %19 +%22 = OpAccessChain %_ptr_UniformConstant_13 %images %20 +%23 = OpLoad %13 %22 +%27 = OpImageRead %v4float %23 %25 +%29 = OpCompositeExtract %float %27 0 +%31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 +OpStore %31 %29 +OpReturn +OpFunctionEnd +)"; + + const std::string func_after = + R"(%7 = OpTypeFunction %void +%uint = OpTypeInt 32 0 +%float = OpTypeFloat 32 +%StorageBuffer = OpTypeStruct %uint %float +%_ptr_Uniform_StorageBuffer = OpTypePointer Uniform %StorageBuffer +%sbo = OpVariable %_ptr_Uniform_StorageBuffer Uniform +%int = OpTypeInt 32 1 +%int_1 = OpConstant %int 1 +%13 = OpTypeImage %float 2D 0 0 0 2 Rgba32f +%_runtimearr_13 = OpTypeRuntimeArray %13 +%_ptr_UniformConstant__runtimearr_13 = OpTypePointer UniformConstant %_runtimearr_13 +%images = OpVariable %_ptr_UniformConstant__runtimearr_13 UniformConstant +%int_0 = OpConstant %int 0 +%_ptr_Uniform_uint = OpTypePointer Uniform %uint +%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13 +%v2int = OpTypeVector %int 2 +%20 = OpConstantComposite %v2int %int_0 %int_0 +%v4float = OpTypeVector %float 4 +%uint_0 = OpConstant %uint 0 +%_ptr_Uniform_float = OpTypePointer Uniform %float +%uint_1 = OpConstant %uint 1 +%34 = OpTypeFunction %uint %uint %uint +%_runtimearr_uint = OpTypeRuntimeArray %uint +%_struct_39 = OpTypeStruct %_runtimearr_uint +%_ptr_StorageBuffer__struct_39 = OpTypePointer StorageBuffer %_struct_39 +%41 = OpVariable %_ptr_StorageBuffer__struct_39 StorageBuffer +%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint +%bool = OpTypeBool +%57 = OpTypeFunction %void %uint %uint %uint %uint +%_struct_63 = OpTypeStruct %uint %_runtimearr_uint +%_ptr_StorageBuffer__struct_63 = OpTypePointer StorageBuffer %_struct_63 +%65 = OpVariable %_ptr_StorageBuffer__struct_63 StorageBuffer +%uint_10 = OpConstant %uint 10 +%uint_4 = OpConstant %uint 4 +%uint_23 = OpConstant %uint 23 +%uint_2 = OpConstant %uint 2 +%uint_5318 = OpConstant %uint 5318 +%uint_3 = OpConstant %uint 3 +%v3uint = OpTypeVector %uint 3 +%_ptr_Input_v3uint = OpTypePointer Input %v3uint +%89 = OpVariable %_ptr_Input_v3uint Input +%uint_5 = OpConstant %uint 5 +%uint_6 = OpConstant %uint 6 +%uint_7 = OpConstant %uint 7 +%uint_8 = OpConstant %uint 8 +%uint_9 = OpConstant %uint 9 +%uint_51 = OpConstant %uint 51 +%113 = OpConstantNull %v4float +%116 = OpTypeFunction %uint %uint %uint %uint %uint +%uint_48 = OpConstant %uint 48 +%141 = OpConstantNull %uint +%uint_54 = OpConstant %uint 54 +%main = OpFunction %void None %7 +%24 = OpLabel +%25 = OpAccessChain %_ptr_Uniform_uint %sbo %int_0 +%133 = OpFunctionCall %uint %115 %uint_0 %uint_0 %uint_0 %uint_0 +%134 = OpINotEqual %bool %133 %uint_0 +OpSelectionMerge %135 None +OpBranchConditional %134 %136 %137 +%136 = OpLabel +%138 = OpLoad %uint %25 +OpBranch %135 +%137 = OpLabel +%140 = OpFunctionCall %void %56 %uint_48 %uint_1 %uint_0 %uint_0 +OpBranch %135 +%135 = OpLabel +%142 = OpPhi %uint %138 %136 %141 %137 +%27 = OpAccessChain %_ptr_UniformConstant_13 %images %142 +%28 = OpLoad %13 %27 +%48 = OpFunctionCall %uint %33 %uint_1 %uint_1 +%50 = OpULessThan %bool %142 %48 +OpSelectionMerge %51 None +OpBranchConditional %50 %52 %53 +%52 = OpLabel +%54 = OpLoad %13 %27 +%143 = OpFunctionCall %uint %115 %uint_0 %uint_0 %uint_1 %142 +%144 = OpINotEqual %bool %143 %uint_0 +OpSelectionMerge %145 None +OpBranchConditional %144 %146 %147 +%146 = OpLabel +%148 = OpLoad %13 %27 +%149 = OpImageRead %v4float %148 %20 +OpBranch %145 +%147 = OpLabel +%150 = OpFunctionCall %void %56 %uint_51 %uint_1 %142 %uint_0 +OpBranch %145 +%145 = OpLabel +%151 = OpPhi %v4float %149 %146 %113 %147 +OpBranch %51 +%53 = OpLabel +%112 = OpFunctionCall %void %56 %uint_51 %uint_0 %142 %48 +OpBranch %51 +%51 = OpLabel +%114 = OpPhi %v4float %151 %145 %113 %53 +%30 = OpCompositeExtract %float %114 0 +%31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 +%152 = OpFunctionCall %uint %115 %uint_0 %uint_0 %uint_0 %uint_0 +%153 = OpINotEqual %bool %152 %uint_0 +OpSelectionMerge %154 None +OpBranchConditional %153 %155 %156 +%155 = OpLabel +OpStore %31 %30 +OpBranch %154 +%156 = OpLabel +%158 = OpFunctionCall %void %56 %uint_54 %uint_1 %uint_0 %uint_0 +OpBranch %154 +%154 = OpLabel +OpReturn +OpFunctionEnd +)"; + + const std::string new_funcs = + R"(%33 = OpFunction %uint None %34 +%35 = OpFunctionParameter %uint +%36 = OpFunctionParameter %uint +%37 = OpLabel +%43 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %35 +%44 = OpLoad %uint %43 +%45 = OpIAdd %uint %44 %36 +%46 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %45 +%47 = OpLoad %uint %46 +OpReturnValue %47 +OpFunctionEnd +%56 = OpFunction %void None %57 +%58 = OpFunctionParameter %uint +%59 = OpFunctionParameter %uint +%60 = OpFunctionParameter %uint +%61 = OpFunctionParameter %uint +%62 = OpLabel +%66 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_0 +%69 = OpAtomicIAdd %uint %66 %uint_4 %uint_0 %uint_10 +%70 = OpIAdd %uint %69 %uint_10 +%71 = OpArrayLength %uint %65 1 +%72 = OpULessThanEqual %bool %70 %71 +OpSelectionMerge %73 None +OpBranchConditional %72 %74 %73 +%74 = OpLabel +%75 = OpIAdd %uint %69 %uint_0 +%76 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %75 +OpStore %76 %uint_10 +%78 = OpIAdd %uint %69 %uint_1 +%79 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %78 +OpStore %79 %uint_23 +%81 = OpIAdd %uint %69 %uint_2 +%82 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %81 +OpStore %82 %58 +%85 = OpIAdd %uint %69 %uint_3 +%86 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %85 +OpStore %86 %uint_5318 +%90 = OpLoad %v3uint %89 +%91 = OpCompositeExtract %uint %90 0 +%92 = OpCompositeExtract %uint %90 1 +%93 = OpCompositeExtract %uint %90 2 +%94 = OpIAdd %uint %69 %uint_4 +%95 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %94 +OpStore %95 %91 +%97 = OpIAdd %uint %69 %uint_5 +%98 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %97 +OpStore %98 %92 +%100 = OpIAdd %uint %69 %uint_6 +%101 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %100 +OpStore %101 %93 +%103 = OpIAdd %uint %69 %uint_7 +%104 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %103 +OpStore %104 %59 +%106 = OpIAdd %uint %69 %uint_8 +%107 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %106 +OpStore %107 %60 +%109 = OpIAdd %uint %69 %uint_9 +%110 = OpAccessChain %_ptr_StorageBuffer_uint %65 %uint_1 %109 +OpStore %110 %61 +OpBranch %73 +%73 = OpLabel +OpReturn +OpFunctionEnd +%115 = OpFunction %uint None %116 +%117 = OpFunctionParameter %uint +%118 = OpFunctionParameter %uint +%119 = OpFunctionParameter %uint +%120 = OpFunctionParameter %uint +%121 = OpLabel +%122 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %117 +%123 = OpLoad %uint %122 +%124 = OpIAdd %uint %123 %118 +%125 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %124 +%126 = OpLoad %uint %125 +%127 = OpIAdd %uint %126 %119 +%128 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %127 +%129 = OpLoad %uint %128 +%130 = OpIAdd %uint %129 %120 +%131 = OpAccessChain %_ptr_StorageBuffer_uint %41 %uint_0 %130 +%132 = OpLoad %uint %131 +OpReturnValue %132 +OpFunctionEnd +)"; + + // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck( + defs_before + func_before, defs_after + func_after + new_funcs, true, + true, 7u, 23u, true, true); +} + +TEST_F(InstBindlessTest, InstBoundsInitSameBlockOpReplication) { + // Test that same block ops like OpSampledImage are replicated properly + // where needed. + // + // clang-format off + // + // #version 450 core + // #extension GL_EXT_nonuniform_qualifier : enable + // + // layout(location = 0) in vec2 inTexcoord; + // layout(location = 0) out vec4 outColor; + // + // layout(set = 0, binding = 0) uniform Uniforms { + // vec2 var0; + // } uniforms; + // + // layout(set = 0, binding = 1) uniform sampler uniformSampler; + // layout(set = 0, binding = 2) uniform texture2D uniformTex; + // layout(set = 0, binding = 3) uniform texture2D uniformTexArr[8]; + // + // void main() { + // int index = 0; + // float x = texture(sampler2D(uniformTexArr[nonuniformEXT(index)], uniformSampler), inTexcoord.xy).x; + // float y = texture(sampler2D(uniformTex, uniformSampler), inTexcoord.xy * uniforms.var0.xy).x; + // outColor = vec4(x, y, 0.0, 0.0); + // } + // + // clang-format on + + const std::string defs_before = + R"(OpCapability Shader +OpCapability ShaderNonUniformEXT +OpCapability SampledImageArrayNonUniformIndexingEXT +OpExtension "SPV_EXT_descriptor_indexing" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %inTexcoord %outColor +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 450 +OpSourceExtension "GL_EXT_nonuniform_qualifier" +OpName %main "main" +OpName %index "index" +OpName %x "x" +OpName %uniformTexArr "uniformTexArr" +OpName %uniformSampler "uniformSampler" +OpName %inTexcoord "inTexcoord" +OpName %y "y" +OpName %uniformTex "uniformTex" +OpName %Uniforms "Uniforms" +OpMemberName %Uniforms 0 "var0" +OpName %uniforms "uniforms" +OpName %outColor "outColor" +OpDecorate %uniformTexArr DescriptorSet 0 +OpDecorate %uniformTexArr Binding 3 +OpDecorate %19 NonUniformEXT +OpDecorate %22 NonUniformEXT +OpDecorate %uniformSampler DescriptorSet 0 +OpDecorate %uniformSampler Binding 1 +OpDecorate %inTexcoord Location 0 +OpDecorate %uniformTex DescriptorSet 0 +OpDecorate %uniformTex Binding 2 +OpMemberDecorate %Uniforms 0 Offset 0 +OpDecorate %Uniforms Block +OpDecorate %uniforms DescriptorSet 0 +OpDecorate %uniforms Binding 0 +OpDecorate %outColor Location 0 +%void = OpTypeVoid +%3 = OpTypeFunction %void +%int = OpTypeInt 32 1 +%_ptr_Function_int = OpTypePointer Function %int +%int_0 = OpConstant %int 0 +%float = OpTypeFloat 32 +%_ptr_Function_float = OpTypePointer Function %float +%13 = OpTypeImage %float 2D 0 0 0 1 Unknown +%uint = OpTypeInt 32 0 +%uint_8 = OpConstant %uint 8 +%_arr_13_uint_8 = OpTypeArray %13 %uint_8 +%_ptr_UniformConstant__arr_13_uint_8 = OpTypePointer UniformConstant %_arr_13_uint_8 +%uniformTexArr = OpVariable %_ptr_UniformConstant__arr_13_uint_8 UniformConstant +%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13 +%23 = OpTypeSampler +%_ptr_UniformConstant_23 = OpTypePointer UniformConstant %23 +%uniformSampler = OpVariable %_ptr_UniformConstant_23 UniformConstant +%27 = OpTypeSampledImage %13 +%v2float = OpTypeVector %float 2 +%_ptr_Input_v2float = OpTypePointer Input %v2float +%inTexcoord = OpVariable %_ptr_Input_v2float Input +%v4float = OpTypeVector %float 4 +%uint_0 = OpConstant %uint 0 +%uniformTex = OpVariable %_ptr_UniformConstant_13 UniformConstant +%Uniforms = OpTypeStruct %v2float +%_ptr_Uniform_Uniforms = OpTypePointer Uniform %Uniforms +%uniforms = OpVariable %_ptr_Uniform_Uniforms Uniform +%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float +%_ptr_Output_v4float = OpTypePointer Output %v4float +%outColor = OpVariable %_ptr_Output_v4float Output +%float_0 = OpConstant %float 0 +)"; + + const std::string defs_after = + R"(OpCapability Shader +OpCapability ShaderNonUniform +OpCapability SampledImageArrayNonUniformIndexing +OpExtension "SPV_EXT_descriptor_indexing" +OpExtension "SPV_KHR_storage_buffer_storage_class" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %inTexcoord %outColor %gl_FragCoord +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 450 +OpSourceExtension "GL_EXT_nonuniform_qualifier" +OpName %main "main" +OpName %index "index" +OpName %x "x" +OpName %uniformTexArr "uniformTexArr" +OpName %uniformSampler "uniformSampler" +OpName %inTexcoord "inTexcoord" +OpName %y "y" +OpName %uniformTex "uniformTex" +OpName %Uniforms "Uniforms" +OpMemberName %Uniforms 0 "var0" +OpName %uniforms "uniforms" +OpName %outColor "outColor" +OpDecorate %uniformTexArr DescriptorSet 0 +OpDecorate %uniformTexArr Binding 3 +OpDecorate %19 NonUniform +OpDecorate %22 NonUniform +OpDecorate %uniformSampler DescriptorSet 0 +OpDecorate %uniformSampler Binding 1 +OpDecorate %inTexcoord Location 0 +OpDecorate %uniformTex DescriptorSet 0 +OpDecorate %uniformTex Binding 2 +OpMemberDecorate %Uniforms 0 Offset 0 +OpDecorate %Uniforms Block +OpDecorate %uniforms DescriptorSet 0 +OpDecorate %uniforms Binding 0 +OpDecorate %outColor Location 0 +OpDecorate %63 NonUniform +OpDecorate %_runtimearr_uint ArrayStride 4 +OpDecorate %_struct_75 Block +OpMemberDecorate %_struct_75 0 Offset 0 +OpMemberDecorate %_struct_75 1 Offset 4 +OpDecorate %77 DescriptorSet 7 +OpDecorate %77 Binding 0 +OpDecorate %gl_FragCoord BuiltIn FragCoord +OpDecorate %_struct_132 Block +OpMemberDecorate %_struct_132 0 Offset 0 +OpDecorate %134 DescriptorSet 7 +OpDecorate %134 Binding 1 +OpDecorate %151 NonUniform +%void = OpTypeVoid +%3 = OpTypeFunction %void +%int = OpTypeInt 32 1 +%_ptr_Function_int = OpTypePointer Function %int +%int_0 = OpConstant %int 0 +%float = OpTypeFloat 32 +%_ptr_Function_float = OpTypePointer Function %float +%13 = OpTypeImage %float 2D 0 0 0 1 Unknown +%uint = OpTypeInt 32 0 +%uint_8 = OpConstant %uint 8 +%_arr_13_uint_8 = OpTypeArray %13 %uint_8 +%_ptr_UniformConstant__arr_13_uint_8 = OpTypePointer UniformConstant %_arr_13_uint_8 +%uniformTexArr = OpVariable %_ptr_UniformConstant__arr_13_uint_8 UniformConstant +%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13 +%23 = OpTypeSampler +%_ptr_UniformConstant_23 = OpTypePointer UniformConstant %23 +%uniformSampler = OpVariable %_ptr_UniformConstant_23 UniformConstant +%27 = OpTypeSampledImage %13 +%v2float = OpTypeVector %float 2 +%_ptr_Input_v2float = OpTypePointer Input %v2float +%inTexcoord = OpVariable %_ptr_Input_v2float Input +%v4float = OpTypeVector %float 4 +%uint_0 = OpConstant %uint 0 +%uniformTex = OpVariable %_ptr_UniformConstant_13 UniformConstant +%Uniforms = OpTypeStruct %v2float +%_ptr_Uniform_Uniforms = OpTypePointer Uniform %Uniforms +%uniforms = OpVariable %_ptr_Uniform_Uniforms Uniform +%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float +%_ptr_Output_v4float = OpTypePointer Output %v4float +%outColor = OpVariable %_ptr_Output_v4float Output +%float_0 = OpConstant %float 0 +%bool = OpTypeBool +%68 = OpTypeFunction %void %uint %uint %uint %uint +%_runtimearr_uint = OpTypeRuntimeArray %uint +%_struct_75 = OpTypeStruct %uint %_runtimearr_uint +%_ptr_StorageBuffer__struct_75 = OpTypePointer StorageBuffer %_struct_75 +%77 = OpVariable %_ptr_StorageBuffer__struct_75 StorageBuffer +%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint +%uint_10 = OpConstant %uint 10 +%uint_4 = OpConstant %uint 4 +%uint_1 = OpConstant %uint 1 +%uint_23 = OpConstant %uint 23 +%uint_2 = OpConstant %uint 2 +%uint_3 = OpConstant %uint 3 +%_ptr_Input_v4float = OpTypePointer Input %v4float +%gl_FragCoord = OpVariable %_ptr_Input_v4float Input +%v4uint = OpTypeVector %uint 4 +%uint_5 = OpConstant %uint 5 +%uint_7 = OpConstant %uint 7 +%uint_9 = OpConstant %uint 9 +%uint_79 = OpConstant %uint 79 +%122 = OpConstantNull %v4float +%126 = OpTypeFunction %uint %uint %uint %uint %uint +%_struct_132 = OpTypeStruct %_runtimearr_uint +%_ptr_StorageBuffer__struct_132 = OpTypePointer StorageBuffer %_struct_132 +%134 = OpVariable %_ptr_StorageBuffer__struct_132 StorageBuffer +%uint_87 = OpConstant %uint 87 +%165 = OpConstantNull %v2float +%uint_89 = OpConstant %uint 89 +)"; + + const std::string func_before = + R"(%main = OpFunction %void None %3 +%5 = OpLabel +%index = OpVariable %_ptr_Function_int Function +%x = OpVariable %_ptr_Function_float Function +%y = OpVariable %_ptr_Function_float Function +OpStore %index %int_0 +%19 = OpLoad %int %index +%21 = OpAccessChain %_ptr_UniformConstant_13 %uniformTexArr %19 +%22 = OpLoad %13 %21 +%26 = OpLoad %23 %uniformSampler +%28 = OpSampledImage %27 %22 %26 +%32 = OpLoad %v2float %inTexcoord +%34 = OpImageSampleImplicitLod %v4float %28 %32 +%36 = OpCompositeExtract %float %34 0 +OpStore %x %36 +%39 = OpLoad %13 %uniformTex +%40 = OpLoad %23 %uniformSampler +%41 = OpSampledImage %27 %39 %40 +%42 = OpLoad %v2float %inTexcoord +%47 = OpAccessChain %_ptr_Uniform_v2float %uniforms %int_0 +%48 = OpLoad %v2float %47 +%49 = OpFMul %v2float %42 %48 +%50 = OpImageSampleImplicitLod %v4float %41 %49 +%51 = OpCompositeExtract %float %50 0 +OpStore %y %51 +%54 = OpLoad %float %x +%55 = OpLoad %float %y +%57 = OpCompositeConstruct %v4float %54 %55 %float_0 %float_0 +OpStore %outColor %57 +OpReturn +OpFunctionEnd +)"; + + const std::string func_after = + R"(%main = OpFunction %void None %3 +%5 = OpLabel +%index = OpVariable %_ptr_Function_int Function +%x = OpVariable %_ptr_Function_float Function +%y = OpVariable %_ptr_Function_float Function +OpStore %index %int_0 +%19 = OpLoad %int %index +%21 = OpAccessChain %_ptr_UniformConstant_13 %uniformTexArr %19 +%22 = OpLoad %13 %21 +%26 = OpLoad %23 %uniformSampler +%28 = OpSampledImage %27 %22 %26 +%32 = OpLoad %v2float %inTexcoord +%59 = OpULessThan %bool %19 %uint_8 +OpSelectionMerge %60 None +OpBranchConditional %59 %61 %62 +%61 = OpLabel +%63 = OpLoad %13 %21 +%64 = OpSampledImage %27 %63 %26 +%124 = OpBitcast %uint %19 +%146 = OpFunctionCall %uint %125 %uint_0 %uint_0 %uint_3 %124 +%147 = OpINotEqual %bool %146 %uint_0 +OpSelectionMerge %148 None +OpBranchConditional %147 %149 %150 +%149 = OpLabel +%151 = OpLoad %13 %21 +%152 = OpSampledImage %27 %151 %26 +%153 = OpImageSampleImplicitLod %v4float %152 %32 +OpBranch %148 +%150 = OpLabel +%154 = OpBitcast %uint %19 +%155 = OpFunctionCall %void %67 %uint_79 %uint_1 %154 %uint_0 +OpBranch %148 +%148 = OpLabel +%156 = OpPhi %v4float %153 %149 %122 %150 +OpBranch %60 +%62 = OpLabel +%66 = OpBitcast %uint %19 +%121 = OpFunctionCall %void %67 %uint_79 %uint_0 %66 %uint_8 +OpBranch %60 +%60 = OpLabel +%123 = OpPhi %v4float %156 %148 %122 %62 +%36 = OpCompositeExtract %float %123 0 +OpStore %x %36 +%39 = OpLoad %13 %uniformTex +%40 = OpLoad %23 %uniformSampler +%41 = OpSampledImage %27 %39 %40 +%42 = OpLoad %v2float %inTexcoord +%47 = OpAccessChain %_ptr_Uniform_v2float %uniforms %int_0 +%157 = OpFunctionCall %uint %125 %uint_0 %uint_0 %uint_0 %uint_0 +%158 = OpINotEqual %bool %157 %uint_0 +OpSelectionMerge %159 None +OpBranchConditional %158 %160 %161 +%160 = OpLabel +%162 = OpLoad %v2float %47 +OpBranch %159 +%161 = OpLabel +%164 = OpFunctionCall %void %67 %uint_87 %uint_1 %uint_0 %uint_0 +OpBranch %159 +%159 = OpLabel +%166 = OpPhi %v2float %162 %160 %165 %161 +%49 = OpFMul %v2float %42 %166 +%167 = OpSampledImage %27 %39 %40 +%168 = OpFunctionCall %uint %125 %uint_0 %uint_0 %uint_2 %uint_0 +%169 = OpINotEqual %bool %168 %uint_0 +OpSelectionMerge %170 None +OpBranchConditional %169 %171 %172 +%171 = OpLabel +%173 = OpLoad %13 %uniformTex +%174 = OpSampledImage %27 %173 %40 +%175 = OpImageSampleImplicitLod %v4float %174 %49 +OpBranch %170 +%172 = OpLabel +%177 = OpFunctionCall %void %67 %uint_89 %uint_1 %uint_0 %uint_0 +OpBranch %170 +%170 = OpLabel +%178 = OpPhi %v4float %175 %171 %122 %172 +%51 = OpCompositeExtract %float %178 0 +OpStore %y %51 +%54 = OpLoad %float %x +%55 = OpLoad %float %y +%57 = OpCompositeConstruct %v4float %54 %55 %float_0 %float_0 +OpStore %outColor %57 +OpReturn +OpFunctionEnd +)"; + + const std::string new_funcs = + R"(%67 = OpFunction %void None %68 +%69 = OpFunctionParameter %uint +%70 = OpFunctionParameter %uint +%71 = OpFunctionParameter %uint +%72 = OpFunctionParameter %uint +%73 = OpLabel +%79 = OpAccessChain %_ptr_StorageBuffer_uint %77 %uint_0 +%82 = OpAtomicIAdd %uint %79 %uint_4 %uint_0 %uint_10 +%83 = OpIAdd %uint %82 %uint_10 +%84 = OpArrayLength %uint %77 1 +%85 = OpULessThanEqual %bool %83 %84 +OpSelectionMerge %86 None +OpBranchConditional %85 %87 %86 +%87 = OpLabel +%88 = OpIAdd %uint %82 %uint_0 +%90 = OpAccessChain %_ptr_StorageBuffer_uint %77 %uint_1 %88 +OpStore %90 %uint_10 +%92 = OpIAdd %uint %82 %uint_1 +%93 = OpAccessChain %_ptr_StorageBuffer_uint %77 %uint_1 %92 +OpStore %93 %uint_23 +%95 = OpIAdd %uint %82 %uint_2 +%96 = OpAccessChain %_ptr_StorageBuffer_uint %77 %uint_1 %95 +OpStore %96 %69 +%98 = OpIAdd %uint %82 %uint_3 +%99 = OpAccessChain %_ptr_StorageBuffer_uint %77 %uint_1 %98 +OpStore %99 %uint_4 +%102 = OpLoad %v4float %gl_FragCoord +%104 = OpBitcast %v4uint %102 +%105 = OpCompositeExtract %uint %104 0 +%106 = OpIAdd %uint %82 %uint_4 +%107 = OpAccessChain %_ptr_StorageBuffer_uint %77 %uint_1 %106 +OpStore %107 %105 +%108 = OpCompositeExtract %uint %104 1 +%110 = OpIAdd %uint %82 %uint_5 +%111 = OpAccessChain %_ptr_StorageBuffer_uint %77 %uint_1 %110 +OpStore %111 %108 +%113 = OpIAdd %uint %82 %uint_7 +%114 = OpAccessChain %_ptr_StorageBuffer_uint %77 %uint_1 %113 +OpStore %114 %70 +%115 = OpIAdd %uint %82 %uint_8 +%116 = OpAccessChain %_ptr_StorageBuffer_uint %77 %uint_1 %115 +OpStore %116 %71 +%118 = OpIAdd %uint %82 %uint_9 +%119 = OpAccessChain %_ptr_StorageBuffer_uint %77 %uint_1 %118 +OpStore %119 %72 +OpBranch %86 +%86 = OpLabel +OpReturn +OpFunctionEnd +%125 = OpFunction %uint None %126 +%127 = OpFunctionParameter %uint +%128 = OpFunctionParameter %uint +%129 = OpFunctionParameter %uint +%130 = OpFunctionParameter %uint +%131 = OpLabel +%135 = OpAccessChain %_ptr_StorageBuffer_uint %134 %uint_0 %127 +%136 = OpLoad %uint %135 +%137 = OpIAdd %uint %136 %128 +%138 = OpAccessChain %_ptr_StorageBuffer_uint %134 %uint_0 %137 +%139 = OpLoad %uint %138 +%140 = OpIAdd %uint %139 %129 +%141 = OpAccessChain %_ptr_StorageBuffer_uint %134 %uint_0 %140 +%142 = OpLoad %uint %141 +%143 = OpIAdd %uint %142 %130 +%144 = OpAccessChain %_ptr_StorageBuffer_uint %134 %uint_0 %143 +%145 = OpLoad %uint %144 +OpReturnValue %145 +OpFunctionEnd +)"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck( + defs_before + func_before, defs_after + func_after + new_funcs, true, + true, 7u, 23u, true, true); +} + +// TODO(greg-lunarg): Add tests to verify handling of these cases: +// +// Compute shader +// Geometry shader +// Tesselation control shader +// Tesselation eval shader +// OpImage +// SampledImage variable + +} // namespace +} // namespace opt +} // namespace spvtools diff --git a/third_party/spirv-tools/test/opt/inst_buff_addr_check_test.cpp b/third_party/spirv-tools/test/opt/inst_buff_addr_check_test.cpp new file mode 100644 index 0000000000..41ead67a5a --- /dev/null +++ b/third_party/spirv-tools/test/opt/inst_buff_addr_check_test.cpp @@ -0,0 +1,620 @@ +// Copyright (c) 2019 Valve Corporation +// Copyright (c) 2019 LunarG Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Bindless Check Instrumentation Tests. +// Tests ending with V2 use version 2 record format. + +#include +#include + +#include "test/opt/assembly_builder.h" +#include "test/opt/pass_fixture.h" +#include "test/opt/pass_utils.h" + +namespace spvtools { +namespace opt { +namespace { + +using InstBuffAddrTest = PassTest<::testing::Test>; + +TEST_F(InstBuffAddrTest, InstPhysicalStorageBufferStore) { + // #version 450 + // #extension GL_EXT_buffer_reference : enable + // + // layout(buffer_reference, buffer_reference_align = 16) buffer bufStruct; + // + // layout(set = 0, binding = 0) uniform ufoo { + // bufStruct data; + // uint offset; + // } u_info; + // + // layout(buffer_reference, std140) buffer bufStruct { + // layout(offset = 0) int a[2]; + // layout(offset = 32) int b; + // }; + // + // void main() { + // u_info.data.b = 0xca7; + // } + + const std::string defs_before = + R"(OpCapability Shader +OpCapability PhysicalStorageBufferAddresses +OpExtension "SPV_EXT_physical_storage_buffer" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel PhysicalStorageBuffer64 GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpSource GLSL 450 +OpSourceExtension "GL_EXT_buffer_reference" +OpName %main "main" +OpName %ufoo "ufoo" +OpMemberName %ufoo 0 "data" +OpMemberName %ufoo 1 "offset" +OpName %bufStruct "bufStruct" +OpMemberName %bufStruct 0 "a" +OpMemberName %bufStruct 1 "b" +OpName %u_info "u_info" +OpMemberDecorate %ufoo 0 Offset 0 +OpMemberDecorate %ufoo 1 Offset 8 +OpDecorate %ufoo Block +OpDecorate %_arr_int_uint_2 ArrayStride 16 +OpMemberDecorate %bufStruct 0 Offset 0 +OpMemberDecorate %bufStruct 1 Offset 32 +OpDecorate %bufStruct Block +OpDecorate %u_info DescriptorSet 0 +OpDecorate %u_info Binding 0 +%void = OpTypeVoid +%3 = OpTypeFunction %void +OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_bufStruct PhysicalStorageBuffer +%uint = OpTypeInt 32 0 +%ufoo = OpTypeStruct %_ptr_PhysicalStorageBuffer_bufStruct %uint +%int = OpTypeInt 32 1 +%uint_2 = OpConstant %uint 2 +%_arr_int_uint_2 = OpTypeArray %int %uint_2 +%bufStruct = OpTypeStruct %_arr_int_uint_2 %int +%_ptr_PhysicalStorageBuffer_bufStruct = OpTypePointer PhysicalStorageBuffer %bufStruct +%_ptr_Uniform_ufoo = OpTypePointer Uniform %ufoo +%u_info = OpVariable %_ptr_Uniform_ufoo Uniform +%int_0 = OpConstant %int 0 +%_ptr_Uniform__ptr_PhysicalStorageBuffer_bufStruct = OpTypePointer Uniform %_ptr_PhysicalStorageBuffer_bufStruct +%int_1 = OpConstant %int 1 +%int_3239 = OpConstant %int 3239 +%_ptr_PhysicalStorageBuffer_int = OpTypePointer PhysicalStorageBuffer %int +)"; + + const std::string defs_after = + R"(OpCapability Shader +OpCapability PhysicalStorageBufferAddresses +OpCapability Int64 +OpExtension "SPV_EXT_physical_storage_buffer" +OpExtension "SPV_KHR_storage_buffer_storage_class" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel PhysicalStorageBuffer64 GLSL450 +OpEntryPoint GLCompute %main "main" %gl_GlobalInvocationID +OpExecutionMode %main LocalSize 1 1 1 +OpSource GLSL 450 +OpSourceExtension "GL_EXT_buffer_reference" +OpName %main "main" +OpName %ufoo "ufoo" +OpMemberName %ufoo 0 "data" +OpMemberName %ufoo 1 "offset" +OpName %bufStruct "bufStruct" +OpMemberName %bufStruct 0 "a" +OpMemberName %bufStruct 1 "b" +OpName %u_info "u_info" +OpMemberDecorate %ufoo 0 Offset 0 +OpMemberDecorate %ufoo 1 Offset 8 +OpDecorate %ufoo Block +OpDecorate %_arr_int_uint_2 ArrayStride 16 +OpMemberDecorate %bufStruct 0 Offset 0 +OpMemberDecorate %bufStruct 1 Offset 32 +OpDecorate %bufStruct Block +OpDecorate %u_info DescriptorSet 0 +OpDecorate %u_info Binding 0 +OpDecorate %_runtimearr_ulong ArrayStride 8 +OpDecorate %_struct_39 Block +OpMemberDecorate %_struct_39 0 Offset 0 +OpDecorate %41 DescriptorSet 7 +OpDecorate %41 Binding 2 +OpDecorate %_runtimearr_uint ArrayStride 4 +OpDecorate %_struct_77 Block +OpMemberDecorate %_struct_77 0 Offset 0 +OpMemberDecorate %_struct_77 1 Offset 4 +OpDecorate %79 DescriptorSet 7 +OpDecorate %79 Binding 0 +OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId +%void = OpTypeVoid +%8 = OpTypeFunction %void +OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_bufStruct PhysicalStorageBuffer +%uint = OpTypeInt 32 0 +%ufoo = OpTypeStruct %_ptr_PhysicalStorageBuffer_bufStruct %uint +%int = OpTypeInt 32 1 +%uint_2 = OpConstant %uint 2 +%_arr_int_uint_2 = OpTypeArray %int %uint_2 +%bufStruct = OpTypeStruct %_arr_int_uint_2 %int +%_ptr_PhysicalStorageBuffer_bufStruct = OpTypePointer PhysicalStorageBuffer %bufStruct +%_ptr_Uniform_ufoo = OpTypePointer Uniform %ufoo +%u_info = OpVariable %_ptr_Uniform_ufoo Uniform +%int_0 = OpConstant %int 0 +%_ptr_Uniform__ptr_PhysicalStorageBuffer_bufStruct = OpTypePointer Uniform %_ptr_PhysicalStorageBuffer_bufStruct +%int_1 = OpConstant %int 1 +%int_3239 = OpConstant %int 3239 +%_ptr_PhysicalStorageBuffer_int = OpTypePointer PhysicalStorageBuffer %int +%ulong = OpTypeInt 64 0 +%uint_4 = OpConstant %uint 4 +%bool = OpTypeBool +%28 = OpTypeFunction %bool %ulong %uint +%uint_1 = OpConstant %uint 1 +%_runtimearr_ulong = OpTypeRuntimeArray %ulong +%_struct_39 = OpTypeStruct %_runtimearr_ulong +%_ptr_StorageBuffer__struct_39 = OpTypePointer StorageBuffer %_struct_39 +%41 = OpVariable %_ptr_StorageBuffer__struct_39 StorageBuffer +%_ptr_StorageBuffer_ulong = OpTypePointer StorageBuffer %ulong +%uint_0 = OpConstant %uint 0 +%uint_32 = OpConstant %uint 32 +%70 = OpTypeFunction %void %uint %uint %uint %uint +%_runtimearr_uint = OpTypeRuntimeArray %uint +%_struct_77 = OpTypeStruct %uint %_runtimearr_uint +%_ptr_StorageBuffer__struct_77 = OpTypePointer StorageBuffer %_struct_77 +%79 = OpVariable %_ptr_StorageBuffer__struct_77 StorageBuffer +%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint +%uint_10 = OpConstant %uint 10 +%uint_23 = OpConstant %uint 23 +%uint_5 = OpConstant %uint 5 +%uint_3 = OpConstant %uint 3 +%v3uint = OpTypeVector %uint 3 +%_ptr_Input_v3uint = OpTypePointer Input %v3uint +%gl_GlobalInvocationID = OpVariable %_ptr_Input_v3uint Input +%uint_6 = OpConstant %uint 6 +%uint_7 = OpConstant %uint 7 +%uint_8 = OpConstant %uint 8 +%uint_9 = OpConstant %uint 9 +%uint_48 = OpConstant %uint 48 +)"; + + const std::string func_before = + R"(%main = OpFunction %void None %3 +%5 = OpLabel +%17 = OpAccessChain %_ptr_Uniform__ptr_PhysicalStorageBuffer_bufStruct %u_info %int_0 +%18 = OpLoad %_ptr_PhysicalStorageBuffer_bufStruct %17 +%22 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %18 %int_1 +OpStore %22 %int_3239 Aligned 16 +OpReturn +OpFunctionEnd +)"; + + const std::string func_after = + R"(%main = OpFunction %void None %8 +%19 = OpLabel +%20 = OpAccessChain %_ptr_Uniform__ptr_PhysicalStorageBuffer_bufStruct %u_info %int_0 +%21 = OpLoad %_ptr_PhysicalStorageBuffer_bufStruct %20 +%22 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %21 %int_1 +%24 = OpConvertPtrToU %ulong %22 +%61 = OpFunctionCall %bool %26 %24 %uint_4 +OpSelectionMerge %62 None +OpBranchConditional %61 %63 %64 +%63 = OpLabel +OpStore %22 %int_3239 Aligned 16 +OpBranch %62 +%64 = OpLabel +%65 = OpUConvert %uint %24 +%67 = OpShiftRightLogical %ulong %24 %uint_32 +%68 = OpUConvert %uint %67 +%124 = OpFunctionCall %void %69 %uint_48 %uint_2 %65 %68 +OpBranch %62 +%62 = OpLabel +OpReturn +OpFunctionEnd +)"; + + const std::string new_funcs = + R"(%26 = OpFunction %bool None %28 +%29 = OpFunctionParameter %ulong +%30 = OpFunctionParameter %uint +%31 = OpLabel +OpBranch %32 +%32 = OpLabel +%34 = OpPhi %uint %uint_1 %31 %35 %33 +OpLoopMerge %37 %33 None +OpBranch %33 +%33 = OpLabel +%35 = OpIAdd %uint %34 %uint_1 +%44 = OpAccessChain %_ptr_StorageBuffer_ulong %41 %uint_0 %35 +%45 = OpLoad %ulong %44 +%46 = OpUGreaterThan %bool %45 %29 +OpBranchConditional %46 %37 %32 +%37 = OpLabel +%47 = OpISub %uint %35 %uint_1 +%48 = OpAccessChain %_ptr_StorageBuffer_ulong %41 %uint_0 %47 +%49 = OpLoad %ulong %48 +%50 = OpISub %ulong %29 %49 +%51 = OpUConvert %ulong %30 +%52 = OpIAdd %ulong %50 %51 +%53 = OpAccessChain %_ptr_StorageBuffer_ulong %41 %uint_0 %uint_0 +%54 = OpLoad %ulong %53 +%55 = OpUConvert %uint %54 +%56 = OpISub %uint %47 %uint_1 +%57 = OpIAdd %uint %56 %55 +%58 = OpAccessChain %_ptr_StorageBuffer_ulong %41 %uint_0 %57 +%59 = OpLoad %ulong %58 +%60 = OpULessThanEqual %bool %52 %59 +OpReturnValue %60 +OpFunctionEnd +%69 = OpFunction %void None %70 +%71 = OpFunctionParameter %uint +%72 = OpFunctionParameter %uint +%73 = OpFunctionParameter %uint +%74 = OpFunctionParameter %uint +%75 = OpLabel +%81 = OpAccessChain %_ptr_StorageBuffer_uint %79 %uint_0 +%83 = OpAtomicIAdd %uint %81 %uint_4 %uint_0 %uint_10 +%84 = OpIAdd %uint %83 %uint_10 +%85 = OpArrayLength %uint %79 1 +%86 = OpULessThanEqual %bool %84 %85 +OpSelectionMerge %87 None +OpBranchConditional %86 %88 %87 +%88 = OpLabel +%89 = OpIAdd %uint %83 %uint_0 +%90 = OpAccessChain %_ptr_StorageBuffer_uint %79 %uint_1 %89 +OpStore %90 %uint_10 +%92 = OpIAdd %uint %83 %uint_1 +%93 = OpAccessChain %_ptr_StorageBuffer_uint %79 %uint_1 %92 +OpStore %93 %uint_23 +%94 = OpIAdd %uint %83 %uint_2 +%95 = OpAccessChain %_ptr_StorageBuffer_uint %79 %uint_1 %94 +OpStore %95 %71 +%98 = OpIAdd %uint %83 %uint_3 +%99 = OpAccessChain %_ptr_StorageBuffer_uint %79 %uint_1 %98 +OpStore %99 %uint_5 +%103 = OpLoad %v3uint %gl_GlobalInvocationID +%104 = OpCompositeExtract %uint %103 0 +%105 = OpCompositeExtract %uint %103 1 +%106 = OpCompositeExtract %uint %103 2 +%107 = OpIAdd %uint %83 %uint_4 +%108 = OpAccessChain %_ptr_StorageBuffer_uint %79 %uint_1 %107 +OpStore %108 %104 +%109 = OpIAdd %uint %83 %uint_5 +%110 = OpAccessChain %_ptr_StorageBuffer_uint %79 %uint_1 %109 +OpStore %110 %105 +%112 = OpIAdd %uint %83 %uint_6 +%113 = OpAccessChain %_ptr_StorageBuffer_uint %79 %uint_1 %112 +OpStore %113 %106 +%115 = OpIAdd %uint %83 %uint_7 +%116 = OpAccessChain %_ptr_StorageBuffer_uint %79 %uint_1 %115 +OpStore %116 %72 +%118 = OpIAdd %uint %83 %uint_8 +%119 = OpAccessChain %_ptr_StorageBuffer_uint %79 %uint_1 %118 +OpStore %119 %73 +%121 = OpIAdd %uint %83 %uint_9 +%122 = OpAccessChain %_ptr_StorageBuffer_uint %79 %uint_1 %121 +OpStore %122 %74 +OpBranch %87 +%87 = OpLabel +OpReturn +OpFunctionEnd +)"; + + // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck( + defs_before + func_before, defs_after + func_after + new_funcs, true, + true, 7u, 23u); +} + +TEST_F(InstBuffAddrTest, InstPhysicalStorageBufferLoadAndStore) { + // #version 450 + // #extension GL_EXT_buffer_reference : enable + + // // forward reference + // layout(buffer_reference) buffer blockType; + + // layout(buffer_reference, std430, buffer_reference_align = 16) buffer + // blockType { + // int x; + // blockType next; + // }; + + // layout(std430) buffer rootBlock { + // blockType root; + // } r; + + // void main() + // { + // blockType b = r.root; + // b = b.next; + // b.x = 531; + // } + + const std::string defs_before = + R"(OpCapability Shader +OpCapability PhysicalStorageBufferAddresses +OpExtension "SPV_EXT_physical_storage_buffer" +OpExtension "SPV_KHR_storage_buffer_storage_class" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel PhysicalStorageBuffer64 GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpSource GLSL 450 +OpSourceExtension "GL_EXT_buffer_reference" +OpName %main "main" +OpName %blockType "blockType" +OpMemberName %blockType 0 "x" +OpMemberName %blockType 1 "next" +OpName %rootBlock "rootBlock" +OpMemberName %rootBlock 0 "root" +OpName %r "r" +OpMemberDecorate %blockType 0 Offset 0 +OpMemberDecorate %blockType 1 Offset 8 +OpDecorate %blockType Block +OpMemberDecorate %rootBlock 0 Offset 0 +OpDecorate %rootBlock Block +OpDecorate %r DescriptorSet 0 +OpDecorate %r Binding 0 +%void = OpTypeVoid +%3 = OpTypeFunction %void +OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_blockType PhysicalStorageBuffer +%int = OpTypeInt 32 1 +%blockType = OpTypeStruct %int %_ptr_PhysicalStorageBuffer_blockType +%_ptr_PhysicalStorageBuffer_blockType = OpTypePointer PhysicalStorageBuffer %blockType +%rootBlock = OpTypeStruct %_ptr_PhysicalStorageBuffer_blockType +%_ptr_StorageBuffer_rootBlock = OpTypePointer StorageBuffer %rootBlock +%r = OpVariable %_ptr_StorageBuffer_rootBlock StorageBuffer +%int_0 = OpConstant %int 0 +%_ptr_StorageBuffer__ptr_PhysicalStorageBuffer_blockType = OpTypePointer StorageBuffer %_ptr_PhysicalStorageBuffer_blockType +%int_1 = OpConstant %int 1 +%_ptr_PhysicalStorageBuffer__ptr_PhysicalStorageBuffer_blockType = OpTypePointer PhysicalStorageBuffer %_ptr_PhysicalStorageBuffer_blockType +%int_531 = OpConstant %int 531 +%_ptr_PhysicalStorageBuffer_int = OpTypePointer PhysicalStorageBuffer %int +)"; + + const std::string defs_after = + R"(OpCapability Shader +OpCapability PhysicalStorageBufferAddresses +OpCapability Int64 +OpExtension "SPV_EXT_physical_storage_buffer" +OpExtension "SPV_KHR_storage_buffer_storage_class" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel PhysicalStorageBuffer64 GLSL450 +OpEntryPoint GLCompute %main "main" %gl_GlobalInvocationID +OpExecutionMode %main LocalSize 1 1 1 +OpSource GLSL 450 +OpSourceExtension "GL_EXT_buffer_reference" +OpName %main "main" +OpName %blockType "blockType" +OpMemberName %blockType 0 "x" +OpMemberName %blockType 1 "next" +OpName %rootBlock "rootBlock" +OpMemberName %rootBlock 0 "root" +OpName %r "r" +OpMemberDecorate %blockType 0 Offset 0 +OpMemberDecorate %blockType 1 Offset 8 +OpDecorate %blockType Block +OpMemberDecorate %rootBlock 0 Offset 0 +OpDecorate %rootBlock Block +OpDecorate %r DescriptorSet 0 +OpDecorate %r Binding 0 +OpDecorate %_runtimearr_ulong ArrayStride 8 +OpDecorate %_struct_45 Block +OpMemberDecorate %_struct_45 0 Offset 0 +OpDecorate %47 DescriptorSet 7 +OpDecorate %47 Binding 2 +OpDecorate %_runtimearr_uint ArrayStride 4 +OpDecorate %_struct_84 Block +OpMemberDecorate %_struct_84 0 Offset 0 +OpMemberDecorate %_struct_84 1 Offset 4 +OpDecorate %86 DescriptorSet 7 +OpDecorate %86 Binding 0 +OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId +%void = OpTypeVoid +%3 = OpTypeFunction %void +OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_blockType PhysicalStorageBuffer +%int = OpTypeInt 32 1 +%blockType = OpTypeStruct %int %_ptr_PhysicalStorageBuffer_blockType +%_ptr_PhysicalStorageBuffer_blockType = OpTypePointer PhysicalStorageBuffer %blockType +%rootBlock = OpTypeStruct %_ptr_PhysicalStorageBuffer_blockType +%_ptr_StorageBuffer_rootBlock = OpTypePointer StorageBuffer %rootBlock +%r = OpVariable %_ptr_StorageBuffer_rootBlock StorageBuffer +%int_0 = OpConstant %int 0 +%_ptr_StorageBuffer__ptr_PhysicalStorageBuffer_blockType = OpTypePointer StorageBuffer %_ptr_PhysicalStorageBuffer_blockType +%int_1 = OpConstant %int 1 +%_ptr_PhysicalStorageBuffer__ptr_PhysicalStorageBuffer_blockType = OpTypePointer PhysicalStorageBuffer %_ptr_PhysicalStorageBuffer_blockType +%int_531 = OpConstant %int 531 +%_ptr_PhysicalStorageBuffer_int = OpTypePointer PhysicalStorageBuffer %int +%uint = OpTypeInt 32 0 +%uint_2 = OpConstant %uint 2 +%ulong = OpTypeInt 64 0 +%uint_8 = OpConstant %uint 8 +%bool = OpTypeBool +%34 = OpTypeFunction %bool %ulong %uint +%uint_1 = OpConstant %uint 1 +%_runtimearr_ulong = OpTypeRuntimeArray %ulong +%_struct_45 = OpTypeStruct %_runtimearr_ulong +%_ptr_StorageBuffer__struct_45 = OpTypePointer StorageBuffer %_struct_45 +%47 = OpVariable %_ptr_StorageBuffer__struct_45 StorageBuffer +%_ptr_StorageBuffer_ulong = OpTypePointer StorageBuffer %ulong +%uint_0 = OpConstant %uint 0 +%uint_32 = OpConstant %uint 32 +%77 = OpTypeFunction %void %uint %uint %uint %uint +%_runtimearr_uint = OpTypeRuntimeArray %uint +%_struct_84 = OpTypeStruct %uint %_runtimearr_uint +%_ptr_StorageBuffer__struct_84 = OpTypePointer StorageBuffer %_struct_84 +%86 = OpVariable %_ptr_StorageBuffer__struct_84 StorageBuffer +%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint +%uint_10 = OpConstant %uint 10 +%uint_4 = OpConstant %uint 4 +%uint_23 = OpConstant %uint 23 +%uint_5 = OpConstant %uint 5 +%uint_3 = OpConstant %uint 3 +%v3uint = OpTypeVector %uint 3 +%_ptr_Input_v3uint = OpTypePointer Input %v3uint +%gl_GlobalInvocationID = OpVariable %_ptr_Input_v3uint Input +%uint_6 = OpConstant %uint 6 +%uint_7 = OpConstant %uint 7 +%uint_9 = OpConstant %uint 9 +%uint_44 = OpConstant %uint 44 +%132 = OpConstantNull %ulong +%uint_46 = OpConstant %uint 46 +)"; + + const std::string func_before = + R"(%main = OpFunction %void None %3 +%5 = OpLabel +%16 = OpAccessChain %_ptr_StorageBuffer__ptr_PhysicalStorageBuffer_blockType %r %int_0 +%17 = OpLoad %_ptr_PhysicalStorageBuffer_blockType %16 +%21 = OpAccessChain %_ptr_PhysicalStorageBuffer__ptr_PhysicalStorageBuffer_blockType %17 %int_1 +%22 = OpLoad %_ptr_PhysicalStorageBuffer_blockType %21 Aligned 8 +%26 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %22 %int_0 +OpStore %26 %int_531 Aligned 16 +OpReturn +OpFunctionEnd +)"; + + const std::string func_after = + R"(%main = OpFunction %void None %3 +%5 = OpLabel +%16 = OpAccessChain %_ptr_StorageBuffer__ptr_PhysicalStorageBuffer_blockType %r %int_0 +%17 = OpLoad %_ptr_PhysicalStorageBuffer_blockType %16 +%21 = OpAccessChain %_ptr_PhysicalStorageBuffer__ptr_PhysicalStorageBuffer_blockType %17 %int_1 +%30 = OpConvertPtrToU %ulong %21 +%67 = OpFunctionCall %bool %32 %30 %uint_8 +OpSelectionMerge %68 None +OpBranchConditional %67 %69 %70 +%69 = OpLabel +%71 = OpLoad %_ptr_PhysicalStorageBuffer_blockType %21 Aligned 8 +OpBranch %68 +%70 = OpLabel +%72 = OpUConvert %uint %30 +%74 = OpShiftRightLogical %ulong %30 %uint_32 +%75 = OpUConvert %uint %74 +%131 = OpFunctionCall %void %76 %uint_44 %uint_2 %72 %75 +%133 = OpConvertUToPtr %_ptr_PhysicalStorageBuffer_blockType %132 +OpBranch %68 +%68 = OpLabel +%134 = OpPhi %_ptr_PhysicalStorageBuffer_blockType %71 %69 %133 %70 +%26 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %134 %int_0 +%135 = OpConvertPtrToU %ulong %26 +%136 = OpFunctionCall %bool %32 %135 %uint_4 +OpSelectionMerge %137 None +OpBranchConditional %136 %138 %139 +%138 = OpLabel +OpStore %26 %int_531 Aligned 16 +OpBranch %137 +%139 = OpLabel +%140 = OpUConvert %uint %135 +%141 = OpShiftRightLogical %ulong %135 %uint_32 +%142 = OpUConvert %uint %141 +%144 = OpFunctionCall %void %76 %uint_46 %uint_2 %140 %142 +OpBranch %137 +%137 = OpLabel +OpReturn +OpFunctionEnd +)"; + + const std::string new_funcs = + R"(%32 = OpFunction %bool None %34 +%35 = OpFunctionParameter %ulong +%36 = OpFunctionParameter %uint +%37 = OpLabel +OpBranch %38 +%38 = OpLabel +%40 = OpPhi %uint %uint_1 %37 %41 %39 +OpLoopMerge %43 %39 None +OpBranch %39 +%39 = OpLabel +%41 = OpIAdd %uint %40 %uint_1 +%50 = OpAccessChain %_ptr_StorageBuffer_ulong %47 %uint_0 %41 +%51 = OpLoad %ulong %50 +%52 = OpUGreaterThan %bool %51 %35 +OpBranchConditional %52 %43 %38 +%43 = OpLabel +%53 = OpISub %uint %41 %uint_1 +%54 = OpAccessChain %_ptr_StorageBuffer_ulong %47 %uint_0 %53 +%55 = OpLoad %ulong %54 +%56 = OpISub %ulong %35 %55 +%57 = OpUConvert %ulong %36 +%58 = OpIAdd %ulong %56 %57 +%59 = OpAccessChain %_ptr_StorageBuffer_ulong %47 %uint_0 %uint_0 +%60 = OpLoad %ulong %59 +%61 = OpUConvert %uint %60 +%62 = OpISub %uint %53 %uint_1 +%63 = OpIAdd %uint %62 %61 +%64 = OpAccessChain %_ptr_StorageBuffer_ulong %47 %uint_0 %63 +%65 = OpLoad %ulong %64 +%66 = OpULessThanEqual %bool %58 %65 +OpReturnValue %66 +OpFunctionEnd +%76 = OpFunction %void None %77 +%78 = OpFunctionParameter %uint +%79 = OpFunctionParameter %uint +%80 = OpFunctionParameter %uint +%81 = OpFunctionParameter %uint +%82 = OpLabel +%88 = OpAccessChain %_ptr_StorageBuffer_uint %86 %uint_0 +%91 = OpAtomicIAdd %uint %88 %uint_4 %uint_0 %uint_10 +%92 = OpIAdd %uint %91 %uint_10 +%93 = OpArrayLength %uint %86 1 +%94 = OpULessThanEqual %bool %92 %93 +OpSelectionMerge %95 None +OpBranchConditional %94 %96 %95 +%96 = OpLabel +%97 = OpIAdd %uint %91 %uint_0 +%98 = OpAccessChain %_ptr_StorageBuffer_uint %86 %uint_1 %97 +OpStore %98 %uint_10 +%100 = OpIAdd %uint %91 %uint_1 +%101 = OpAccessChain %_ptr_StorageBuffer_uint %86 %uint_1 %100 +OpStore %101 %uint_23 +%102 = OpIAdd %uint %91 %uint_2 +%103 = OpAccessChain %_ptr_StorageBuffer_uint %86 %uint_1 %102 +OpStore %103 %78 +%106 = OpIAdd %uint %91 %uint_3 +%107 = OpAccessChain %_ptr_StorageBuffer_uint %86 %uint_1 %106 +OpStore %107 %uint_5 +%111 = OpLoad %v3uint %gl_GlobalInvocationID +%112 = OpCompositeExtract %uint %111 0 +%113 = OpCompositeExtract %uint %111 1 +%114 = OpCompositeExtract %uint %111 2 +%115 = OpIAdd %uint %91 %uint_4 +%116 = OpAccessChain %_ptr_StorageBuffer_uint %86 %uint_1 %115 +OpStore %116 %112 +%117 = OpIAdd %uint %91 %uint_5 +%118 = OpAccessChain %_ptr_StorageBuffer_uint %86 %uint_1 %117 +OpStore %118 %113 +%120 = OpIAdd %uint %91 %uint_6 +%121 = OpAccessChain %_ptr_StorageBuffer_uint %86 %uint_1 %120 +OpStore %121 %114 +%123 = OpIAdd %uint %91 %uint_7 +%124 = OpAccessChain %_ptr_StorageBuffer_uint %86 %uint_1 %123 +OpStore %124 %79 +%125 = OpIAdd %uint %91 %uint_8 +%126 = OpAccessChain %_ptr_StorageBuffer_uint %86 %uint_1 %125 +OpStore %126 %80 +%128 = OpIAdd %uint %91 %uint_9 +%129 = OpAccessChain %_ptr_StorageBuffer_uint %86 %uint_1 %128 +OpStore %129 %81 +OpBranch %95 +%95 = OpLabel +OpReturn +OpFunctionEnd +)"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck( + defs_before + func_before, defs_after + func_after + new_funcs, true, + true, 7u, 23u); +} + +} // namespace +} // namespace opt +} // namespace spvtools diff --git a/third_party/spirv-tools/test/opt/instruction_test.cpp b/third_party/spirv-tools/test/opt/instruction_test.cpp index 2ace6b8acb..a6972011f9 100644 --- a/third_party/spirv-tools/test/opt/instruction_test.cpp +++ b/third_party/spirv-tools/test/opt/instruction_test.cpp @@ -622,6 +622,35 @@ TEST_F(GetBaseTest, SampleImage) { EXPECT_TRUE(load->GetBaseAddress() == base); } +TEST_F(GetBaseTest, PtrAccessChain) { + const std::string text = R"( + OpCapability VariablePointers + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "PSMain" %2 + OpExecutionMode %1 OriginUpperLeft + %void = OpTypeVoid + %4 = OpTypeFunction %void + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 + %int = OpTypeInt 32 8388353 + %int_0 = OpConstant %int 0 +%_ptr_Function_v4float = OpTypePointer Function %v4float + %2 = OpVariable %_ptr_Function_v4float Input + %1 = OpFunction %void None %4 + %10 = OpLabel + %11 = OpPtrAccessChain %_ptr_Function_v4float %2 %int_0 + %12 = OpLoad %v4float %11 + OpReturn + OpFunctionEnd +)"; + + std::unique_ptr context = + BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text); + Instruction* load = context->get_def_use_mgr()->GetDef(12); + Instruction* base = context->get_def_use_mgr()->GetDef(2); + EXPECT_TRUE(load->GetBaseAddress() == base); +} + TEST_F(GetBaseTest, ImageRead) { const std::string text = R"( OpCapability Shader diff --git a/third_party/spirv-tools/test/opt/ir_builder.cpp b/third_party/spirv-tools/test/opt/ir_builder.cpp index 7eeb86dd33..f800ca437e 100644 --- a/third_party/spirv-tools/test/opt/ir_builder.cpp +++ b/third_party/spirv-tools/test/opt/ir_builder.cpp @@ -17,6 +17,7 @@ #include #include +#include "effcee/effcee.h" #include "gmock/gmock.h" #include "gtest/gtest.h" #include "source/opt/basic_block.h" @@ -26,16 +27,10 @@ #include "source/opt/type_manager.h" #include "spirv-tools/libspirv.hpp" -#ifdef SPIRV_EFFCEE -#include "effcee/effcee.h" -#endif - namespace spvtools { namespace opt { namespace { -#ifdef SPIRV_EFFCEE - using Analysis = IRContext::Analysis; using IRBuilderTest = ::testing::Test; @@ -182,7 +177,7 @@ TEST_F(IRBuilderTest, TestCondBranchAddition) { %5 = OpTypeVoid %6 = OpTypeFunction %5 %7 = OpTypeBool - %8 = OpTypePointer Function %7 + %8 = OpTypePointer Private %7 %9 = OpConstantTrue %7 %10 = OpTypeFloat 32 %11 = OpTypeVector %10 4 @@ -203,6 +198,7 @@ TEST_F(IRBuilderTest, TestCondBranchAddition) { BasicBlock& bb_merge = *fn.begin(); + // TODO(1841): Handle id overflow. fn.begin().InsertBefore(std::unique_ptr( new BasicBlock(std::unique_ptr(new Instruction( context.get(), SpvOpLabel, 0, context->TakeNextId(), {}))))); @@ -212,6 +208,7 @@ TEST_F(IRBuilderTest, TestCondBranchAddition) { builder.AddBranch(bb_merge.id()); } + // TODO(1841): Handle id overflow. fn.begin().InsertBefore(std::unique_ptr( new BasicBlock(std::unique_ptr(new Instruction( context.get(), SpvOpLabel, 0, context->TakeNextId(), {}))))); @@ -322,20 +319,20 @@ OpFunctionEnd InstructionBuilder builder(context.get(), &*context->module()->begin()->begin()->begin()); - EXPECT_NE(nullptr, builder.Add32BitUnsignedIntegerConstant(13)); - EXPECT_NE(nullptr, builder.Add32BitSignedIntegerConstant(-1)); + EXPECT_NE(nullptr, builder.GetUintConstant(13)); + EXPECT_NE(nullptr, builder.GetSintConstant(-1)); // Try adding the same constants again to make sure they aren't added. - EXPECT_NE(nullptr, builder.Add32BitUnsignedIntegerConstant(13)); - EXPECT_NE(nullptr, builder.Add32BitSignedIntegerConstant(-1)); + EXPECT_NE(nullptr, builder.GetUintConstant(13)); + EXPECT_NE(nullptr, builder.GetSintConstant(-1)); // Try adding different constants to make sure the type is reused. - EXPECT_NE(nullptr, builder.Add32BitUnsignedIntegerConstant(1)); - EXPECT_NE(nullptr, builder.Add32BitSignedIntegerConstant(34)); + EXPECT_NE(nullptr, builder.GetUintConstant(1)); + EXPECT_NE(nullptr, builder.GetSintConstant(34)); // Try adding 0 as both signed and unsigned. - EXPECT_NE(nullptr, builder.Add32BitUnsignedIntegerConstant(0)); - EXPECT_NE(nullptr, builder.Add32BitSignedIntegerConstant(0)); + EXPECT_NE(nullptr, builder.GetUintConstant(0)); + EXPECT_NE(nullptr, builder.GetSintConstant(0)); Match(text, context.get()); } @@ -367,25 +364,25 @@ OpFunctionEnd InstructionBuilder builder(context.get(), &*context->module()->begin()->begin()->begin()); - Instruction* const_1 = builder.Add32BitUnsignedIntegerConstant(13); - Instruction* const_2 = builder.Add32BitSignedIntegerConstant(-1); + Instruction* const_1 = builder.GetUintConstant(13); + Instruction* const_2 = builder.GetSintConstant(-1); EXPECT_NE(nullptr, const_1); EXPECT_NE(nullptr, const_2); // Try adding the same constants again to make sure they aren't added. - EXPECT_EQ(const_1, builder.Add32BitUnsignedIntegerConstant(13)); - EXPECT_EQ(const_2, builder.Add32BitSignedIntegerConstant(-1)); + EXPECT_EQ(const_1, builder.GetUintConstant(13)); + EXPECT_EQ(const_2, builder.GetSintConstant(-1)); - Instruction* const_3 = builder.Add32BitUnsignedIntegerConstant(1); - Instruction* const_4 = builder.Add32BitSignedIntegerConstant(34); + Instruction* const_3 = builder.GetUintConstant(1); + Instruction* const_4 = builder.GetSintConstant(34); // Try adding different constants to make sure the type is reused. EXPECT_NE(nullptr, const_3); EXPECT_NE(nullptr, const_4); - Instruction* const_5 = builder.Add32BitUnsignedIntegerConstant(0); - Instruction* const_6 = builder.Add32BitSignedIntegerConstant(0); + Instruction* const_5 = builder.GetUintConstant(0); + Instruction* const_6 = builder.GetSintConstant(0); // Try adding 0 as both signed and unsigned. EXPECT_NE(nullptr, const_5); @@ -409,7 +406,33 @@ OpFunctionEnd Match(text, context.get()); } -#endif // SPIRV_EFFCEE +TEST_F(IRBuilderTest, AccelerationStructureNV) { + const std::string text = R"( +; CHECK: OpTypeAccelerationStructureNV +OpCapability Shader +OpCapability RayTracingNV +OpExtension "SPV_NV_ray_tracing" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %8 "main" +OpExecutionMode %8 OriginUpperLeft +%1 = OpTypeVoid +%2 = OpTypeBool +%3 = OpTypeAccelerationStructureNV +%7 = OpTypeFunction %1 +%8 = OpFunction %1 None %7 +%9 = OpLabel +OpReturn +OpFunctionEnd +)"; + + std::unique_ptr context = + BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text); + EXPECT_NE(nullptr, context); + + InstructionBuilder builder(context.get(), + &*context->module()->begin()->begin()->begin()); + Match(text, context.get()); +} } // namespace } // namespace opt diff --git a/third_party/spirv-tools/test/opt/ir_context_test.cpp b/third_party/spirv-tools/test/opt/ir_context_test.cpp index c64e5b04ff..d5710fc469 100644 --- a/third_party/spirv-tools/test/opt/ir_context_test.cpp +++ b/third_party/spirv-tools/test/opt/ir_context_test.cpp @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include "source/opt/ir_context.h" + #include #include #include @@ -19,7 +21,6 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" -#include "source/opt/ir_context.h" #include "source/opt/pass.h" #include "test/opt/pass_fixture.h" #include "test/opt/pass_utils.h" @@ -30,6 +31,7 @@ namespace { using Analysis = IRContext::Analysis; using ::testing::Each; +using ::testing::UnorderedElementsAre; class DummyPassPreservesNothing : public Pass { public: @@ -217,6 +219,64 @@ TEST_F(IRContextTest, KillMemberName) { } } +TEST_F(IRContextTest, KillGroupDecoration) { + const std::string text = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpSource GLSL 430 + OpDecorate %3 Restrict + %3 = OpDecorationGroup + OpGroupDecorate %3 %4 %5 + %6 = OpTypeFloat 32 + %7 = OpTypePointer Function %6 + %8 = OpTypeStruct %6 + %9 = OpTypeVoid + %10 = OpTypeFunction %9 + %2 = OpFunction %9 None %10 + %11 = OpLabel + %4 = OpVariable %7 Function + %5 = OpVariable %7 Function + OpReturn + OpFunctionEnd +)"; + + std::unique_ptr context = + BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text); + + // Build the decoration manager. + context->get_decoration_mgr(); + + // Delete the second variable. + context->KillDef(5); + + // The three decorations instructions should still be there. The first two + // should be the same, but the third should have %5 removed. + + // Check the OpDecorate instruction + auto inst = context->annotation_begin(); + EXPECT_EQ(inst->opcode(), SpvOpDecorate); + EXPECT_EQ(inst->GetSingleWordInOperand(0), 3); + + // Check the OpDecorationGroup Instruction + ++inst; + EXPECT_EQ(inst->opcode(), SpvOpDecorationGroup); + EXPECT_EQ(inst->result_id(), 3); + + // Check that %5 is no longer part of the group. + ++inst; + EXPECT_EQ(inst->opcode(), SpvOpGroupDecorate); + EXPECT_EQ(inst->NumInOperands(), 2); + EXPECT_EQ(inst->GetSingleWordInOperand(0), 3); + EXPECT_EQ(inst->GetSingleWordInOperand(1), 4); + + // Check that we are at the end. + ++inst; + EXPECT_EQ(inst, context->annotation_end()); +} + TEST_F(IRContextTest, TakeNextUniqueIdIncrementing) { const uint32_t NUM_TESTS = 1000; IRContext localContext(SPV_ENV_UNIVERSAL_1_2, nullptr); @@ -224,6 +284,471 @@ TEST_F(IRContextTest, TakeNextUniqueIdIncrementing) { EXPECT_EQ(i, localContext.TakeNextUniqueId()); } +TEST_F(IRContextTest, KillGroupDecorationWitNoDecorations) { + const std::string text = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpSource GLSL 430 + %3 = OpDecorationGroup + OpGroupDecorate %3 %4 %5 + %6 = OpTypeFloat 32 + %7 = OpTypePointer Function %6 + %8 = OpTypeStruct %6 + %9 = OpTypeVoid + %10 = OpTypeFunction %9 + %2 = OpFunction %9 None %10 + %11 = OpLabel + %4 = OpVariable %7 Function + %5 = OpVariable %7 Function + OpReturn + OpFunctionEnd +)"; + + std::unique_ptr context = + BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text); + + // Build the decoration manager. + context->get_decoration_mgr(); + + // Delete the second variable. + context->KillDef(5); + + // The two decoration instructions should still be there. The first one + // should be the same, but the second should have %5 removed. + + // Check the OpDecorationGroup Instruction + auto inst = context->annotation_begin(); + EXPECT_EQ(inst->opcode(), SpvOpDecorationGroup); + EXPECT_EQ(inst->result_id(), 3); + + // Check that %5 is no longer part of the group. + ++inst; + EXPECT_EQ(inst->opcode(), SpvOpGroupDecorate); + EXPECT_EQ(inst->NumInOperands(), 2); + EXPECT_EQ(inst->GetSingleWordInOperand(0), 3); + EXPECT_EQ(inst->GetSingleWordInOperand(1), 4); + + // Check that we are at the end. + ++inst; + EXPECT_EQ(inst, context->annotation_end()); +} + +TEST_F(IRContextTest, KillDecorationGroup) { + const std::string text = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpSource GLSL 430 + %3 = OpDecorationGroup + OpGroupDecorate %3 %4 %5 + %6 = OpTypeFloat 32 + %7 = OpTypePointer Function %6 + %8 = OpTypeStruct %6 + %9 = OpTypeVoid + %10 = OpTypeFunction %9 + %2 = OpFunction %9 None %10 + %11 = OpLabel + %4 = OpVariable %7 Function + %5 = OpVariable %7 Function + OpReturn + OpFunctionEnd +)"; + + std::unique_ptr context = + BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text); + + // Build the decoration manager. + context->get_decoration_mgr(); + + // Delete the second variable. + context->KillDef(3); + + // Check the OpDecorationGroup Instruction is still there. + EXPECT_TRUE(context->annotations().empty()); +} + +TEST_F(IRContextTest, BasicVisitFromEntryPoint) { + // Make sure we visit the entry point, and the function it calls. + // Do not visit Dead or Exported. + const std::string text = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %10 "main" + OpName %10 "main" + OpName %Dead "Dead" + OpName %11 "Constant" + OpName %ExportedFunc "ExportedFunc" + OpDecorate %ExportedFunc LinkageAttributes "ExportedFunc" Export + %void = OpTypeVoid + %6 = OpTypeFunction %void + %10 = OpFunction %void None %6 + %14 = OpLabel + %15 = OpFunctionCall %void %11 + %16 = OpFunctionCall %void %11 + OpReturn + OpFunctionEnd + %11 = OpFunction %void None %6 + %18 = OpLabel + OpReturn + OpFunctionEnd + %Dead = OpFunction %void None %6 + %19 = OpLabel + OpReturn + OpFunctionEnd +%ExportedFunc = OpFunction %void None %7 + %20 = OpLabel + %21 = OpFunctionCall %void %11 + OpReturn + OpFunctionEnd +)"; + // clang-format on + + std::unique_ptr localContext = + BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + EXPECT_NE(nullptr, localContext) << "Assembling failed for shader:\n" + << text << std::endl; + std::vector processed; + Pass::ProcessFunction mark_visited = [&processed](Function* fp) { + processed.push_back(fp->result_id()); + return false; + }; + localContext->ProcessEntryPointCallTree(mark_visited); + EXPECT_THAT(processed, UnorderedElementsAre(10, 11)); +} + +TEST_F(IRContextTest, BasicVisitReachable) { + // Make sure we visit the entry point, exported function, and the function + // they call. Do not visit Dead. + const std::string text = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %10 "main" + OpName %10 "main" + OpName %Dead "Dead" + OpName %11 "Constant" + OpName %12 "ExportedFunc" + OpName %13 "Constant2" + OpDecorate %12 LinkageAttributes "ExportedFunc" Export + %void = OpTypeVoid + %6 = OpTypeFunction %void + %10 = OpFunction %void None %6 + %14 = OpLabel + %15 = OpFunctionCall %void %11 + %16 = OpFunctionCall %void %11 + OpReturn + OpFunctionEnd + %11 = OpFunction %void None %6 + %18 = OpLabel + OpReturn + OpFunctionEnd + %Dead = OpFunction %void None %6 + %19 = OpLabel + OpReturn + OpFunctionEnd + %12 = OpFunction %void None %6 + %20 = OpLabel + %21 = OpFunctionCall %void %13 + OpReturn + OpFunctionEnd + %13 = OpFunction %void None %6 + %22 = OpLabel + OpReturn + OpFunctionEnd +)"; + // clang-format on + + std::unique_ptr localContext = + BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + EXPECT_NE(nullptr, localContext) << "Assembling failed for shader:\n" + << text << std::endl; + + std::vector processed; + Pass::ProcessFunction mark_visited = [&processed](Function* fp) { + processed.push_back(fp->result_id()); + return false; + }; + localContext->ProcessReachableCallTree(mark_visited); + EXPECT_THAT(processed, UnorderedElementsAre(10, 11, 12, 13)); +} + +TEST_F(IRContextTest, BasicVisitOnlyOnce) { + // Make sure we visit %12 only once, even if it is called from two different + // functions. + const std::string text = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %10 "main" + OpName %10 "main" + OpName %Dead "Dead" + OpName %11 "Constant" + OpName %12 "ExportedFunc" + OpDecorate %12 LinkageAttributes "ExportedFunc" Export + %void = OpTypeVoid + %6 = OpTypeFunction %void + %10 = OpFunction %void None %6 + %14 = OpLabel + %15 = OpFunctionCall %void %11 + %16 = OpFunctionCall %void %12 + OpReturn + OpFunctionEnd + %11 = OpFunction %void None %6 + %18 = OpLabel + %19 = OpFunctionCall %void %12 + OpReturn + OpFunctionEnd + %Dead = OpFunction %void None %6 + %20 = OpLabel + OpReturn + OpFunctionEnd + %12 = OpFunction %void None %6 + %21 = OpLabel + OpReturn + OpFunctionEnd +)"; + // clang-format on + + std::unique_ptr localContext = + BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + EXPECT_NE(nullptr, localContext) << "Assembling failed for shader:\n" + << text << std::endl; + + std::vector processed; + Pass::ProcessFunction mark_visited = [&processed](Function* fp) { + processed.push_back(fp->result_id()); + return false; + }; + localContext->ProcessReachableCallTree(mark_visited); + EXPECT_THAT(processed, UnorderedElementsAre(10, 11, 12)); +} + +TEST_F(IRContextTest, BasicDontVisitExportedVariable) { + // Make sure we only visit functions and not exported variables. + const std::string text = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %10 "main" + OpExecutionMode %10 OriginUpperLeft + OpSource GLSL 150 + OpName %10 "main" + OpName %12 "export_var" + OpDecorate %12 LinkageAttributes "export_var" Export + %void = OpTypeVoid + %6 = OpTypeFunction %void + %float = OpTypeFloat 32 + %float_1 = OpConstant %float 1 + %12 = OpVariable %float Output + %10 = OpFunction %void None %6 + %14 = OpLabel + OpStore %12 %float_1 + OpReturn + OpFunctionEnd +)"; + // clang-format on + + std::unique_ptr localContext = + BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + EXPECT_NE(nullptr, localContext) << "Assembling failed for shader:\n" + << text << std::endl; + + std::vector processed; + Pass::ProcessFunction mark_visited = [&processed](Function* fp) { + processed.push_back(fp->result_id()); + return false; + }; + localContext->ProcessReachableCallTree(mark_visited); + EXPECT_THAT(processed, UnorderedElementsAre(10)); +} + +TEST_F(IRContextTest, IdBoundTestAtLimit) { + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%1 = OpTypeVoid +%2 = OpTypeFunction %1 +%3 = OpFunction %1 None %2 +%4 = OpLabel +OpReturn +OpFunctionEnd)"; + + std::unique_ptr context = + BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + uint32_t current_bound = context->module()->id_bound(); + context->set_max_id_bound(current_bound); + uint32_t next_id_bound = context->TakeNextId(); + EXPECT_EQ(next_id_bound, 0); + EXPECT_EQ(current_bound, context->module()->id_bound()); + next_id_bound = context->TakeNextId(); + EXPECT_EQ(next_id_bound, 0); +} + +TEST_F(IRContextTest, IdBoundTestBelowLimit) { + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%1 = OpTypeVoid +%2 = OpTypeFunction %1 +%3 = OpFunction %1 None %2 +%4 = OpLabel +OpReturn +OpFunctionEnd)"; + + std::unique_ptr context = + BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + uint32_t current_bound = context->module()->id_bound(); + context->set_max_id_bound(current_bound + 100); + uint32_t next_id_bound = context->TakeNextId(); + EXPECT_EQ(next_id_bound, current_bound); + EXPECT_EQ(current_bound + 1, context->module()->id_bound()); + next_id_bound = context->TakeNextId(); + EXPECT_EQ(next_id_bound, current_bound + 1); +} + +TEST_F(IRContextTest, IdBoundTestNearLimit) { + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%1 = OpTypeVoid +%2 = OpTypeFunction %1 +%3 = OpFunction %1 None %2 +%4 = OpLabel +OpReturn +OpFunctionEnd)"; + + std::unique_ptr context = + BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + uint32_t current_bound = context->module()->id_bound(); + context->set_max_id_bound(current_bound + 1); + uint32_t next_id_bound = context->TakeNextId(); + EXPECT_EQ(next_id_bound, current_bound); + EXPECT_EQ(current_bound + 1, context->module()->id_bound()); + next_id_bound = context->TakeNextId(); + EXPECT_EQ(next_id_bound, 0); +} + +TEST_F(IRContextTest, IdBoundTestUIntMax) { + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%1 = OpTypeVoid +%2 = OpTypeFunction %1 +%3 = OpFunction %1 None %2 +%4294967294 = OpLabel ; ID is UINT_MAX-1 +OpReturn +OpFunctionEnd)"; + + std::unique_ptr context = + BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + uint32_t current_bound = context->module()->id_bound(); + + // Expecting |BuildModule| to preserve the numeric ids. + EXPECT_EQ(current_bound, std::numeric_limits::max()); + + context->set_max_id_bound(current_bound); + uint32_t next_id_bound = context->TakeNextId(); + EXPECT_EQ(next_id_bound, 0); + EXPECT_EQ(current_bound, context->module()->id_bound()); +} + +TEST_F(IRContextTest, CfgAndDomAnalysis) { + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%1 = OpTypeVoid +%2 = OpTypeFunction %1 +%3 = OpFunction %1 None %2 +%4 = OpLabel +OpReturn +OpFunctionEnd)"; + + std::unique_ptr ctx = + BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + + // Building the dominator analysis should build the CFG. + ASSERT_TRUE(ctx->module()->begin() != ctx->module()->end()); + ctx->GetDominatorAnalysis(&*ctx->module()->begin()); + + EXPECT_TRUE(ctx->AreAnalysesValid(IRContext::kAnalysisCFG)); + EXPECT_TRUE(ctx->AreAnalysesValid(IRContext::kAnalysisDominatorAnalysis)); + + // Invalidating the CFG analysis should invalidate the dominator analysis. + ctx->InvalidateAnalyses(IRContext::kAnalysisCFG); + EXPECT_FALSE(ctx->AreAnalysesValid(IRContext::kAnalysisCFG)); + EXPECT_FALSE(ctx->AreAnalysesValid(IRContext::kAnalysisDominatorAnalysis)); +} + +TEST_F(IRContextTest, AsanErrorTest) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %8 "x" + OpName %10 "y" + OpDecorate %8 RelaxedPrecision + OpDecorate %10 RelaxedPrecision + OpDecorate %11 RelaxedPrecision + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 1 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %10 = OpVariable %7 Function + OpStore %8 %9 + %11 = OpLoad %6 %8 + OpBranch %20 + %20 = OpLabel + %21 = OpPhi %6 %11 %5 + OpStore %10 %21 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = BuildModule( + env, consumer, shader, SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + + opt::Function* fun = + context->cfg()->block(5)->GetParent(); // Computes the CFG analysis + opt::DominatorAnalysis* dom = nullptr; + dom = context->GetDominatorAnalysis(fun); // Computes the dominator analysis, + // which depends on the CFG + // analysis + context->InvalidateAnalysesExceptFor( + opt::IRContext::Analysis::kAnalysisDominatorAnalysis); // Invalidates the + // CFG analysis + dom = context->GetDominatorAnalysis( + fun); // Recompute the CFG analysis because the Dominator tree uses it. + auto bb = dom->ImmediateDominator(5); + std::cout + << bb->id(); // Make sure asan does not complain about use after free. +} + } // namespace } // namespace opt } // namespace spvtools diff --git a/third_party/spirv-tools/test/opt/ir_loader_test.cpp b/third_party/spirv-tools/test/opt/ir_loader_test.cpp index ac5c52075c..c60e8537ad 100644 --- a/third_party/spirv-tools/test/opt/ir_loader_test.cpp +++ b/third_party/spirv-tools/test/opt/ir_loader_test.cpp @@ -129,6 +129,621 @@ TEST(IrBuilder, KeepLineDebugInfo) { // clang-format on } +TEST(IrBuilder, ConsumeDebugInfoInst) { + // /* HLSL */ + // + // struct VS_OUTPUT { + // float4 pos : SV_POSITION; + // float4 color : COLOR; + // }; + // + // VS_OUTPUT main(float4 pos : POSITION, + // float4 color : COLOR) { + // VS_OUTPUT vout; + // vout.pos = pos; + // vout.color = color; + // return vout; + // } + DoRoundTripCheck(R"(OpCapability Shader +%1 = OpExtInstImport "OpenCL.DebugInfo.100" +OpMemoryModel Logical GLSL450 +OpEntryPoint Vertex %main "main" %pos %color %gl_Position %out_var_COLOR +%7 = OpString "simple_vs.hlsl" +%8 = OpString "#line 1 \"simple_vs.hlsl\" +struct VS_OUTPUT { + float4 pos : SV_POSITION; + float4 color : COLOR; +}; + +VS_OUTPUT main(float4 pos : POSITION, + float4 color : COLOR) { + VS_OUTPUT vout; + vout.pos = pos; + vout.color = color; + return vout; +} +" +OpSource HLSL 600 %7 "#line 1 \"simple_vs.hlsl\" +struct VS_OUTPUT { + float4 pos : SV_POSITION; + float4 color : COLOR; +}; + +VS_OUTPUT main(float4 pos : POSITION, + float4 color : COLOR) { + VS_OUTPUT vout; + vout.pos = pos; + vout.color = color; + return vout; +} +" +%9 = OpString "struct VS_OUTPUT" +%10 = OpString "float" +%11 = OpString "pos : SV_POSITION" +%12 = OpString "color : COLOR" +%13 = OpString "VS_OUTPUT" +%14 = OpString "main" +%15 = OpString "VS_OUTPUT_main_v4f_v4f" +%16 = OpString "pos : POSITION" +%17 = OpString "color : COLOR" +%18 = OpString "vout" +OpName %out_var_COLOR "out.var.COLOR" +OpName %main "main" +OpName %VS_OUTPUT "VS_OUTPUT" +OpMemberName %VS_OUTPUT 0 "pos" +OpMemberName %VS_OUTPUT 1 "color" +OpName %pos "pos" +OpName %color "color" +OpName %vout "vout" +OpDecorate %gl_Position BuiltIn Position +OpDecorate %pos Location 0 +OpDecorate %color Location 1 +OpDecorate %out_var_COLOR Location 0 +%int = OpTypeInt 32 1 +%int_0 = OpConstant %int 0 +%int_1 = OpConstant %int 1 +%int_32 = OpConstant %int 32 +%int_128 = OpConstant %int 128 +%float = OpTypeFloat 32 +%v4float = OpTypeVector %float 4 +%_ptr_Input_v4float = OpTypePointer Input %v4float +%_ptr_Output_v4float = OpTypePointer Output %v4float +%void = OpTypeVoid +%31 = OpTypeFunction %void +%_ptr_Function_v4float = OpTypePointer Function %v4float +%VS_OUTPUT = OpTypeStruct %v4float %v4float +%_ptr_Function_VS_OUTPUT = OpTypePointer Function %VS_OUTPUT +OpLine %7 6 23 +%pos = OpVariable %_ptr_Input_v4float Input +OpLine %7 7 23 +%color = OpVariable %_ptr_Input_v4float Input +OpLine %7 2 16 +%gl_Position = OpVariable %_ptr_Output_v4float Output +OpLine %7 3 18 +%out_var_COLOR = OpVariable %_ptr_Output_v4float Output +%34 = OpExtInst %void %1 DebugSource %7 %8 +%35 = OpExtInst %void %1 DebugCompilationUnit 2 4 %34 HLSL +%36 = OpExtInst %void %1 DebugTypeComposite %9 Structure %34 1 1 %35 %13 %int_128 FlagIsProtected|FlagIsPrivate %37 %38 +%39 = OpExtInst %void %1 DebugTypeBasic %10 %int_32 Float +%40 = OpExtInst %void %1 DebugTypeVector %39 4 +%37 = OpExtInst %void %1 DebugTypeMember %11 %40 %34 2 3 %36 %int_0 %int_128 FlagIsProtected|FlagIsPrivate +%38 = OpExtInst %void %1 DebugTypeMember %12 %40 %34 3 3 %36 %int_128 %int_128 FlagIsProtected|FlagIsPrivate +%41 = OpExtInst %void %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %36 %40 %40 +%42 = OpExtInst %void %1 DebugExpression +%43 = OpExtInst %void %1 DebugFunction %14 %41 %34 6 1 %35 %15 FlagIsProtected|FlagIsPrivate 7 %main +%44 = OpExtInst %void %1 DebugLocalVariable %16 %40 %34 6 16 %43 FlagIsLocal 0 +%45 = OpExtInst %void %1 DebugLocalVariable %17 %40 %34 7 16 %43 FlagIsLocal 1 +%46 = OpExtInst %void %1 DebugLocalVariable %18 %36 %34 8 3 %43 FlagIsLocal +%47 = OpExtInst %void %1 DebugDeclare %44 %pos %42 +%48 = OpExtInst %void %1 DebugDeclare %45 %color %42 +OpLine %7 6 1 +%main = OpFunction %void None %31 +%49 = OpLabel +%50 = OpExtInst %void %1 DebugScope %43 +OpLine %7 8 13 +%vout = OpVariable %_ptr_Function_VS_OUTPUT Function +%51 = OpExtInst %void %1 DebugDeclare %46 %vout %42 +OpLine %7 9 14 +%52 = OpLoad %v4float %pos +OpLine %7 9 3 +%53 = OpAccessChain %_ptr_Function_v4float %vout %int_0 +%54 = OpExtInst %void %1 DebugValue %46 %53 %42 %int_0 +OpStore %53 %52 +OpLine %7 10 16 +%55 = OpLoad %v4float %color +OpLine %7 10 3 +%56 = OpAccessChain %_ptr_Function_v4float %vout %int_1 +%57 = OpExtInst %void %1 DebugValue %46 %56 %42 %int_1 +OpStore %56 %55 +OpLine %7 11 10 +%58 = OpLoad %VS_OUTPUT %vout +OpLine %7 11 3 +%59 = OpCompositeExtract %v4float %58 0 +OpStore %gl_Position %59 +%60 = OpCompositeExtract %v4float %58 1 +OpStore %out_var_COLOR %60 +OpReturn +OpFunctionEnd +)"); +} + +TEST(IrBuilder, ConsumeDebugInfoLexicalScopeInst) { + // /* HLSL */ + // + // float4 func2(float arg2) { // func2_block + // return float4(arg2, 0, 0, 0); + // } + // + // float4 func1(float arg1) { // func1_block + // if (arg1 > 1) { // if_true_block + // return float4(0, 0, 0, 0); + // } + // return func2(arg1); // if_merge_block + // } + // + // float4 main(float pos : POSITION) : SV_POSITION { // main + // return func1(pos); + // } + DoRoundTripCheck(R"(OpCapability Shader +%1 = OpExtInstImport "OpenCL.DebugInfo.100" +OpMemoryModel Logical GLSL450 +OpEntryPoint Vertex %main "main" %pos %gl_Position +%5 = OpString "block/block.hlsl" +%6 = OpString "#line 1 \"block/block.hlsl\" +float4 func2(float arg2) { + return float4(arg2, 0, 0, 0); +} + +float4 func1(float arg1) { + if (arg1 > 1) { + return float4(0, 0, 0, 0); + } + return func2(arg1); +} + +float4 main(float pos : POSITION) : SV_POSITION { + return func1(pos); +} +" +OpSource HLSL 600 %5 "#line 1 \"block/block.hlsl\" +float4 func2(float arg2) { + return float4(arg2, 0, 0, 0); +} + +float4 func1(float arg1) { + if (arg1 > 1) { + return float4(0, 0, 0, 0); + } + return func2(arg1); +} + +float4 main(float pos : POSITION) : SV_POSITION { + return func1(pos); +} +" +%7 = OpString "float" +%8 = OpString "main" +%9 = OpString "v4f_main_f" +%10 = OpString "v4f_func1_f" +%11 = OpString "v4f_func2_f" +%12 = OpString "pos : POSITION" +%13 = OpString "func1" +%14 = OpString "func2" +OpName %main "main" +OpName %pos "pos" +OpName %bb_entry "bb.entry" +OpName %param_var_arg1 "param.var.arg1" +OpName %func1 "func1" +OpName %arg1 "arg1" +OpName %bb_entry_0 "bb.entry" +OpName %param_var_arg2 "param.var.arg2" +OpName %if_true "if.true" +OpName %if_merge "if.merge" +OpName %func2 "func2" +OpName %arg2 "arg2" +OpName %bb_entry_1 "bb.entry" +OpDecorate %gl_Position BuiltIn Position +OpDecorate %pos Location 0 +%float = OpTypeFloat 32 +%int = OpTypeInt 32 1 +%float_1 = OpConstant %float 1 +%float_0 = OpConstant %float 0 +%int_32 = OpConstant %int 32 +%v4float = OpTypeVector %float 4 +%32 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0 +%_ptr_Input_float = OpTypePointer Input %float +%_ptr_Output_v4float = OpTypePointer Output %v4float +%void = OpTypeVoid +%36 = OpTypeFunction %void +%_ptr_Function_float = OpTypePointer Function %float +%38 = OpTypeFunction %v4float %_ptr_Function_float +%bool = OpTypeBool +OpLine %5 12 25 +%pos = OpVariable %_ptr_Input_float Input +OpLine %5 12 37 +%gl_Position = OpVariable %_ptr_Output_v4float Output +%40 = OpExtInst %void %1 DebugSource %5 %6 +%41 = OpExtInst %void %1 DebugCompilationUnit 2 4 %40 HLSL +%42 = OpExtInst %void %1 DebugTypeBasic %7 %int_32 Float +%43 = OpExtInst %void %1 DebugTypeVector %42 4 +%44 = OpExtInst %void %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %43 %42 +%45 = OpExtInst %void %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %43 %42 +%46 = OpExtInst %void %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %43 %42 +%47 = OpExtInst %void %1 DebugFunction %8 %44 %40 12 1 %41 %9 FlagIsProtected|FlagIsPrivate 13 %main +%48 = OpExtInst %void %1 DebugFunction %13 %45 %40 5 1 %41 %10 FlagIsProtected|FlagIsPrivate 13 %func1 +%49 = OpExtInst %void %1 DebugFunction %14 %46 %40 1 1 %41 %11 FlagIsProtected|FlagIsPrivate 13 %func2 +%50 = OpExtInst %void %1 DebugLexicalBlock %40 6 17 %48 +%51 = OpExtInst %void %1 DebugLexicalBlock %40 9 3 %48 +OpLine %5 12 1 +%main = OpFunction %void None %36 +%bb_entry = OpLabel +%52 = OpExtInst %void %1 DebugScope %47 +OpLine %5 13 16 +%param_var_arg1 = OpVariable %_ptr_Function_float Function +%53 = OpLoad %float %pos +OpStore %param_var_arg1 %53 +OpLine %5 13 10 +%54 = OpFunctionCall %v4float %func1 %param_var_arg1 +OpLine %5 13 3 +OpStore %gl_Position %54 +OpReturn +OpFunctionEnd +OpLine %5 5 1 +%func1 = OpFunction %v4float None %38 +OpLine %5 5 20 +%arg1 = OpFunctionParameter %_ptr_Function_float +%bb_entry_0 = OpLabel +%55 = OpExtInst %void %1 DebugScope %48 +OpLine %5 9 16 +%param_var_arg2 = OpVariable %_ptr_Function_float Function +OpLine %5 6 7 +%56 = OpLoad %float %arg1 +OpLine %5 6 12 +%57 = OpFOrdGreaterThan %bool %56 %float_1 +OpLine %5 6 17 +OpSelectionMerge %if_merge None +OpBranchConditional %57 %if_true %if_merge +%if_true = OpLabel +%58 = OpExtInst %void %1 DebugScope %50 +OpLine %5 7 5 +OpReturnValue %32 +%if_merge = OpLabel +%59 = OpExtInst %void %1 DebugScope %51 +OpLine %5 9 16 +%60 = OpLoad %float %arg1 +OpStore %param_var_arg2 %60 +OpLine %5 9 10 +%61 = OpFunctionCall %v4float %func2 %param_var_arg2 +OpLine %5 9 3 +OpReturnValue %61 +OpFunctionEnd +OpLine %5 1 1 +%func2 = OpFunction %v4float None %38 +OpLine %5 1 20 +%arg2 = OpFunctionParameter %_ptr_Function_float +%bb_entry_1 = OpLabel +%62 = OpExtInst %void %1 DebugScope %49 +OpLine %5 2 17 +%63 = OpLoad %float %arg2 +%64 = OpCompositeConstruct %v4float %63 %float_0 %float_0 %float_0 +OpLine %5 2 3 +OpReturnValue %64 +OpFunctionEnd +)"); +} + +TEST(IrBuilder, ConsumeDebugInlinedAt) { + // /* HLSL */ + // + // float4 func2(float arg2) { // func2_block + // return float4(arg2, 0, 0, 0); + // } + // + // float4 func1(float arg1) { // func1_block + // if (arg1 > 1) { // if_true_block + // return float4(0, 0, 0, 0); + // } + // return func2(arg1); // if_merge_block + // } + // + // float4 main(float pos : POSITION) : SV_POSITION { // main + // return func1(pos); + // } + // + // TODO(https://gitlab.khronos.org/spirv/SPIR-V/issues/533): In the following + // SPIRV code, we use DebugInfoNone to reference opted-out function from + // DebugFunction similar to opted-out global variable for DebugGlobalVariable, + // but this is not a part of the spec yet. We are still in discussion and we + // must correct it if our decision is different. + DoRoundTripCheck(R"(OpCapability Shader +%1 = OpExtInstImport "OpenCL.DebugInfo.100" +OpMemoryModel Logical GLSL450 +OpEntryPoint Vertex %main "main" %pos %gl_Position +%5 = OpString "block/block.hlsl" +%6 = OpString "#line 1 \"block/block.hlsl\" +float4 func2(float arg2) { + return float4(arg2, 0, 0, 0); +} + +float4 func1(float arg1) { + if (arg1 > 1) { + return float4(0, 0, 0, 0); + } + return func2(arg1); +} + +float4 main(float pos : POSITION) : SV_POSITION { + return func1(pos); +} +" +OpSource HLSL 600 %5 "#line 1 \"block/block.hlsl\" +float4 func2(float arg2) { + return float4(arg2, 0, 0, 0); +} + +float4 func1(float arg1) { + if (arg1 > 1) { + return float4(0, 0, 0, 0); + } + return func2(arg1); +} + +float4 main(float pos : POSITION) : SV_POSITION { + return func1(pos); +} +" +%7 = OpString "float" +%8 = OpString "main" +%9 = OpString "v4f_main_f" +%10 = OpString "v4f_func1_f" +%11 = OpString "v4f_func2_f" +%12 = OpString "pos : POSITION" +%13 = OpString "func1" +%14 = OpString "func2" +OpName %main "main" +OpName %pos "pos" +OpName %bb_entry "bb.entry" +OpName %if_true "if.true" +OpName %if_merge "if.merge" +OpDecorate %gl_Position BuiltIn Position +OpDecorate %pos Location 0 +%float = OpTypeFloat 32 +%int = OpTypeInt 32 1 +%float_1 = OpConstant %float 1 +%float_0 = OpConstant %float 0 +%int_32 = OpConstant %int 32 +%v4float = OpTypeVector %float 4 +%24 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0 +%_ptr_Input_float = OpTypePointer Input %float +%_ptr_Output_v4float = OpTypePointer Output %v4float +%void = OpTypeVoid +%28 = OpTypeFunction %void +%_ptr_Function_float = OpTypePointer Function %float +%30 = OpTypeFunction %v4float %_ptr_Function_float +%bool = OpTypeBool +OpLine %5 12 25 +%pos = OpVariable %_ptr_Input_float Input +OpLine %5 12 37 +%gl_Position = OpVariable %_ptr_Output_v4float Output +%32 = OpExtInst %void %1 DebugInfoNone +%33 = OpExtInst %void %1 DebugSource %5 %6 +%34 = OpExtInst %void %1 DebugCompilationUnit 2 4 %33 HLSL +%35 = OpExtInst %void %1 DebugTypeBasic %7 %int_32 Float +%36 = OpExtInst %void %1 DebugTypeVector %35 4 +%37 = OpExtInst %void %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %36 %35 +%38 = OpExtInst %void %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %36 %35 +%39 = OpExtInst %void %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %36 %35 +%40 = OpExtInst %void %1 DebugFunction %8 %37 %33 12 1 %34 %9 FlagIsProtected|FlagIsPrivate 13 %main +%41 = OpExtInst %void %1 DebugFunction %13 %38 %33 5 1 %34 %10 FlagIsProtected|FlagIsPrivate 13 %32 +%42 = OpExtInst %void %1 DebugFunction %14 %39 %33 1 1 %34 %11 FlagIsProtected|FlagIsPrivate 13 %32 +%43 = OpExtInst %void %1 DebugLexicalBlock %33 12 49 %40 +%44 = OpExtInst %void %1 DebugLexicalBlock %33 5 26 %41 +%45 = OpExtInst %void %1 DebugLexicalBlock %33 1 26 %42 +%46 = OpExtInst %void %1 DebugLexicalBlock %33 6 17 %44 +%47 = OpExtInst %void %1 DebugLexicalBlock %33 9 3 %44 +%48 = OpExtInst %void %1 DebugInlinedAt 9 %47 +%49 = OpExtInst %void %1 DebugInlinedAt 13 %43 +%50 = OpExtInst %void %1 DebugInlinedAt 13 %43 %48 +OpLine %5 12 1 +%main = OpFunction %void None %28 +%bb_entry = OpLabel +%51 = OpExtInst %void %1 DebugScope %44 %49 +OpLine %5 6 7 +%52 = OpLoad %float %pos +OpLine %5 6 12 +%53 = OpFOrdGreaterThan %bool %52 %float_1 +OpLine %5 6 17 +OpSelectionMerge %if_merge None +OpBranchConditional %53 %if_true %if_merge +%if_true = OpLabel +%54 = OpExtInst %void %1 DebugScope %46 %49 +OpLine %5 7 5 +OpStore %gl_Position %24 +OpReturn +%if_merge = OpLabel +%55 = OpExtInst %void %1 DebugScope %45 %50 +OpLine %5 2 17 +%56 = OpLoad %float %pos +OpLine %5 2 10 +%57 = OpCompositeConstruct %v4float %56 %float_0 %float_0 %float_0 +%58 = OpExtInst %void %1 DebugScope %43 +OpLine %5 13 3 +OpStore %gl_Position %57 +OpReturn +OpFunctionEnd +)"); +} + +TEST(IrBuilder, DebugInfoInstInFunctionOutOfBlock) { + // /* HLSL */ + // + // float4 func2(float arg2) { // func2_block + // return float4(arg2, 0, 0, 0); + // } + // + // float4 func1(float arg1) { // func1_block + // if (arg1 > 1) { // if_true_block + // return float4(0, 0, 0, 0); + // } + // return func2(arg1); // if_merge_block + // } + // + // float4 main(float pos : POSITION) : SV_POSITION { // main + // return func1(pos); + // } + const std::string text = R"(OpCapability Shader +%1 = OpExtInstImport "OpenCL.DebugInfo.100" +OpMemoryModel Logical GLSL450 +OpEntryPoint Vertex %main "main" %pos %gl_Position +%5 = OpString "block/block.hlsl" +%6 = OpString "#line 1 \"block/block.hlsl\" +float4 func2(float arg2) { + return float4(arg2, 0, 0, 0); +} + +float4 func1(float arg1) { + if (arg1 > 1) { + return float4(0, 0, 0, 0); + } + return func2(arg1); +} + +float4 main(float pos : POSITION) : SV_POSITION { + return func1(pos); +} +" +OpSource HLSL 600 %5 "#line 1 \"block/block.hlsl\" +float4 func2(float arg2) { + return float4(arg2, 0, 0, 0); +} + +float4 func1(float arg1) { + if (arg1 > 1) { + return float4(0, 0, 0, 0); + } + return func2(arg1); +} + +float4 main(float pos : POSITION) : SV_POSITION { + return func1(pos); +} +" +%7 = OpString "float" +%8 = OpString "main" +%9 = OpString "v4f_main_f" +%10 = OpString "v4f_func1_f" +%11 = OpString "v4f_func2_f" +%12 = OpString "pos : POSITION" +%13 = OpString "func1" +%14 = OpString "func2" +OpName %main "main" +OpName %pos "pos" +OpName %bb_entry "bb.entry" +OpName %param_var_arg1 "param.var.arg1" +OpName %func1 "func1" +OpName %arg1 "arg1" +OpName %bb_entry_0 "bb.entry" +OpName %param_var_arg2 "param.var.arg2" +OpName %if_true "if.true" +OpName %if_merge "if.merge" +OpName %func2 "func2" +OpName %arg2 "arg2" +OpName %bb_entry_1 "bb.entry" +OpDecorate %gl_Position BuiltIn Position +OpDecorate %pos Location 0 +%float = OpTypeFloat 32 +%int = OpTypeInt 32 1 +%float_1 = OpConstant %float 1 +%float_0 = OpConstant %float 0 +%int_32 = OpConstant %int 32 +%v4float = OpTypeVector %float 4 +%32 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0 +%_ptr_Input_float = OpTypePointer Input %float +%_ptr_Output_v4float = OpTypePointer Output %v4float +%void = OpTypeVoid +%36 = OpTypeFunction %void +%_ptr_Function_float = OpTypePointer Function %float +%38 = OpTypeFunction %v4float %_ptr_Function_float +%bool = OpTypeBool +OpLine %5 12 25 +%pos = OpVariable %_ptr_Input_float Input +OpLine %5 12 37 +%gl_Position = OpVariable %_ptr_Output_v4float Output +%40 = OpExtInst %void %1 DebugSource %5 %6 +%41 = OpExtInst %void %1 DebugCompilationUnit 2 4 %40 HLSL +%42 = OpExtInst %void %1 DebugTypeBasic %7 %int_32 Float +%43 = OpExtInst %void %1 DebugTypeVector %42 4 +%44 = OpExtInst %void %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %43 %42 +%45 = OpExtInst %void %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %43 %42 +%46 = OpExtInst %void %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %43 %42 +%47 = OpExtInst %void %1 DebugFunction %8 %44 %40 12 1 %41 %9 FlagIsProtected|FlagIsPrivate 13 %main +%48 = OpExtInst %void %1 DebugFunction %13 %45 %40 5 1 %41 %10 FlagIsProtected|FlagIsPrivate 13 %func1 +%49 = OpExtInst %void %1 DebugFunction %14 %46 %40 1 1 %41 %11 FlagIsProtected|FlagIsPrivate 13 %func2 +%50 = OpExtInst %void %1 DebugLexicalBlock %40 6 17 %48 +%51 = OpExtInst %void %1 DebugLexicalBlock %40 9 3 %48 +OpLine %5 12 1 +%main = OpFunction %void None %36 +%52 = OpExtInst %void %1 DebugScope %47 +%bb_entry = OpLabel +OpLine %5 13 16 +%param_var_arg1 = OpVariable %_ptr_Function_float Function +%53 = OpLoad %float %pos +OpStore %param_var_arg1 %53 +OpLine %5 13 10 +%54 = OpFunctionCall %v4float %func1 %param_var_arg1 +OpLine %5 13 3 +OpStore %gl_Position %54 +OpReturn +OpFunctionEnd +OpLine %5 5 1 +%func1 = OpFunction %v4float None %38 +OpLine %5 5 20 +%arg1 = OpFunctionParameter %_ptr_Function_float +%bb_entry_0 = OpLabel +%55 = OpExtInst %void %1 DebugScope %48 +OpLine %5 9 16 +%param_var_arg2 = OpVariable %_ptr_Function_float Function +OpLine %5 6 7 +%56 = OpLoad %float %arg1 +OpLine %5 6 12 +%57 = OpFOrdGreaterThan %bool %56 %float_1 +OpLine %5 6 17 +OpSelectionMerge %if_merge None +OpBranchConditional %57 %if_true %if_merge +%if_true = OpLabel +%58 = OpExtInst %void %1 DebugScope %50 +OpLine %5 7 5 +OpReturnValue %32 +%if_merge = OpLabel +%59 = OpExtInst %void %1 DebugScope %51 +OpLine %5 9 16 +%60 = OpLoad %float %arg1 +OpStore %param_var_arg2 %60 +OpLine %5 9 10 +%61 = OpFunctionCall %v4float %func2 %param_var_arg2 +OpLine %5 9 3 +OpReturnValue %61 +OpFunctionEnd +OpLine %5 1 1 +%func2 = OpFunction %v4float None %38 +OpLine %5 1 20 +%arg2 = OpFunctionParameter %_ptr_Function_float +%bb_entry_1 = OpLabel +%62 = OpExtInst %void %1 DebugScope %49 +OpLine %5 2 17 +%63 = OpLoad %float %arg2 +%64 = OpCompositeConstruct %v4float %63 %float_0 %float_0 %float_0 +OpLine %5 2 3 +OpReturnValue %64 +OpFunctionEnd +)"; + + SpirvTools t(SPV_ENV_UNIVERSAL_1_1); + std::unique_ptr context = + BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text); + ASSERT_EQ(nullptr, context); +} + TEST(IrBuilder, LocalGlobalVariables) { // #version 310 es // diff --git a/third_party/spirv-tools/test/opt/legalize_vector_shuffle_test.cpp b/third_party/spirv-tools/test/opt/legalize_vector_shuffle_test.cpp new file mode 100644 index 0000000000..07d96eb379 --- /dev/null +++ b/third_party/spirv-tools/test/opt/legalize_vector_shuffle_test.cpp @@ -0,0 +1,81 @@ +// Copyright (c) 2019 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 + +#include "test/opt/pass_fixture.h" +#include "test/opt/pass_utils.h" + +namespace spvtools { +namespace opt { +namespace { + +using LegalizeVectorShuffleTest = PassTest<::testing::Test>; + +void operator+=(std::vector& lhs, const char* rhs) { + lhs.push_back(rhs); +} + +void operator+=(std::vector& lhs, + const std::vector rhs) { + for (auto elem : rhs) lhs.push_back(elem); +} + +std::vector header = { + "OpCapability Shader", + "OpCapability VulkanMemoryModel", + "OpExtension \"SPV_KHR_vulkan_memory_model\"", + "OpMemoryModel Logical Vulkan", + "OpEntryPoint Vertex %1 \"shader\"", + "%uint = OpTypeInt 32 0", + "%v3uint = OpTypeVector %uint 3"}; + +std::string GetTestString(const char* shuffle) { + std::vector result = header; + result += {"%_ptr_Function_v3uint = OpTypePointer Function %v3uint", + "%void = OpTypeVoid", + "%6 = OpTypeFunction %void", + "%1 = OpFunction %void None %6", + "%7 = OpLabel", + "%8 = OpVariable %_ptr_Function_v3uint Function", + "%9 = OpLoad %v3uint %8", + "%10 = OpLoad %v3uint %8"}; + result += shuffle; + result += {"OpReturn", "OpFunctionEnd"}; + return JoinAllInsts(result); +} + +TEST_F(LegalizeVectorShuffleTest, Changed) { + std::string input = + GetTestString("%11 = OpVectorShuffle %v3uint %9 %10 2 1 0xFFFFFFFF"); + std::string expected = + GetTestString("%11 = OpVectorShuffle %v3uint %9 %10 2 1 0"); + + SinglePassRunAndCheck(input, expected, + /* skip_nop = */ false); +} + +TEST_F(LegalizeVectorShuffleTest, FunctionUnchanged) { + std::string input = + GetTestString("%11 = OpVectorShuffle %v3uint %9 %10 2 1 0"); + std::string expected = + GetTestString("%11 = OpVectorShuffle %v3uint %9 %10 2 1 0"); + + SinglePassRunAndCheck(input, expected, + /* skip_nop = */ false); +} + +} // namespace +} // namespace opt +} // namespace spvtools diff --git a/third_party/spirv-tools/test/opt/local_access_chain_convert_test.cpp b/third_party/spirv-tools/test/opt/local_access_chain_convert_test.cpp index cb3572161b..39899e3ee9 100644 --- a/third_party/spirv-tools/test/opt/local_access_chain_convert_test.cpp +++ b/third_party/spirv-tools/test/opt/local_access_chain_convert_test.cpp @@ -24,8 +24,6 @@ namespace { using LocalAccessChainConvertTest = PassTest<::testing::Test>; -#ifdef SPIRV_EFFCEE - TEST_F(LocalAccessChainConvertTest, StructOfVecsOfFloatConverted) { // #version 140 // @@ -625,7 +623,6 @@ OpFunctionEnd SinglePassRunAndMatch(predefs_before + before, true); } -#endif // SPIRV_EFFCEE TEST_F(LocalAccessChainConvertTest, DynamicallyIndexedVarNotConverted) { // #version 140 @@ -703,6 +700,233 @@ OpFunctionEnd true); } +TEST_F(LocalAccessChainConvertTest, VariablePointersStorageBuffer) { + // A case with a storage buffer variable pointer. We should still convert + // the access chain on the function scope symbol. + const std::string test = + R"( +; CHECK: OpFunction +; CHECK: [[var:%\w+]] = OpVariable {{%\w+}} Function +; CHECK: [[ld:%\w+]] = OpLoad {{%\w+}} [[var]] +; CHECK: OpCompositeExtract {{%\w+}} [[ld]] 0 0 + OpCapability Shader + OpCapability VariablePointersStorageBuffer + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %2 "main" + OpExecutionMode %2 LocalSize 1 1 1 + OpSource GLSL 450 + OpMemberDecorate %_struct_3 0 Offset 0 + OpDecorate %_struct_3 Block + OpDecorate %4 DescriptorSet 0 + OpDecorate %4 Binding 0 + OpDecorate %_ptr_StorageBuffer_int ArrayStride 4 + OpDecorate %_arr_int_int_128 ArrayStride 4 + %void = OpTypeVoid + %8 = OpTypeFunction %void + %int = OpTypeInt 32 1 + %int_128 = OpConstant %int 128 +%_arr_int_int_128 = OpTypeArray %int %int_128 + %_struct_3 = OpTypeStruct %_arr_int_int_128 +%_ptr_StorageBuffer__struct_3 = OpTypePointer StorageBuffer %_struct_3 +%_ptr_Function__struct_3 = OpTypePointer Function %_struct_3 + %4 = OpVariable %_ptr_StorageBuffer__struct_3 StorageBuffer + %bool = OpTypeBool + %true = OpConstantTrue %bool + %int_0 = OpConstant %int 0 + %int_1 = OpConstant %int 1 +%_ptr_StorageBuffer_int = OpTypePointer StorageBuffer %int +%_ptr_Function_int = OpTypePointer Function %int + %2 = OpFunction %void None %8 + %18 = OpLabel + %19 = OpVariable %_ptr_Function__struct_3 Function + %20 = OpAccessChain %_ptr_StorageBuffer_int %4 %int_0 %int_0 + OpBranch %21 + %21 = OpLabel + %22 = OpPhi %_ptr_StorageBuffer_int %20 %18 %23 %24 + OpLoopMerge %25 %24 None + OpBranchConditional %true %26 %25 + %26 = OpLabel + OpStore %22 %int_0 + OpBranch %24 + %24 = OpLabel + %23 = OpPtrAccessChain %_ptr_StorageBuffer_int %22 %int_1 + OpBranch %21 + %25 = OpLabel + %27 = OpAccessChain %_ptr_Function_int %19 %int_0 %int_0 + %28 = OpLoad %int %27 + OpReturn + OpFunctionEnd +)"; + + SinglePassRunAndMatch(test, true); +} + +TEST_F(LocalAccessChainConvertTest, VariablePointers) { + // A case with variable pointer capability. We should not convert + // the access chain on the function scope symbol because the variable pointer + // could the analysis to miss references to function scope symbols. + const std::string test = + R"(OpCapability Shader +OpCapability VariablePointers +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %2 "main" +OpExecutionMode %2 LocalSize 1 1 1 +OpSource GLSL 450 +OpMemberDecorate %_struct_3 0 Offset 0 +OpDecorate %_struct_3 Block +OpDecorate %4 DescriptorSet 0 +OpDecorate %4 Binding 0 +OpDecorate %_ptr_StorageBuffer_int ArrayStride 4 +OpDecorate %_arr_int_int_128 ArrayStride 4 +%void = OpTypeVoid +%8 = OpTypeFunction %void +%int = OpTypeInt 32 1 +%int_128 = OpConstant %int 128 +%_arr_int_int_128 = OpTypeArray %int %int_128 +%_struct_3 = OpTypeStruct %_arr_int_int_128 +%_ptr_StorageBuffer__struct_3 = OpTypePointer StorageBuffer %_struct_3 +%_ptr_Function__struct_3 = OpTypePointer Function %_struct_3 +%4 = OpVariable %_ptr_StorageBuffer__struct_3 StorageBuffer +%bool = OpTypeBool +%true = OpConstantTrue %bool +%int_0 = OpConstant %int 0 +%int_1 = OpConstant %int 1 +%_ptr_StorageBuffer_int = OpTypePointer StorageBuffer %int +%_ptr_Function_int = OpTypePointer Function %int +%2 = OpFunction %void None %8 +%18 = OpLabel +%19 = OpVariable %_ptr_Function__struct_3 Function +%20 = OpAccessChain %_ptr_StorageBuffer_int %4 %int_0 %int_0 +OpBranch %21 +%21 = OpLabel +%22 = OpPhi %_ptr_StorageBuffer_int %20 %18 %23 %24 +OpLoopMerge %25 %24 None +OpBranchConditional %true %26 %25 +%26 = OpLabel +OpStore %22 %int_0 +OpBranch %24 +%24 = OpLabel +%23 = OpPtrAccessChain %_ptr_StorageBuffer_int %22 %int_1 +OpBranch %21 +%25 = OpLabel +%27 = OpAccessChain %_ptr_Function_int %19 %int_0 %int_0 +%28 = OpLoad %int %27 +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndCheck(test, test, false, true); +} + +TEST_F(LocalAccessChainConvertTest, IdOverflowReplacingLoad) { + const std::string text = + R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "PSMain" + OpExecutionMode %4 OriginUpperLeft + OpDecorate %10 Location 47360 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 + %_struct_8 = OpTypeStruct %v4float +%_ptr_Function__struct_8 = OpTypePointer Function %_struct_8 + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 +%_ptr_Function_v4float = OpTypePointer Function %v4float + %4 = OpFunction %void None %3 + %5 = OpLabel + %10 = OpVariable %_ptr_Function__struct_8 Function + %4194301 = OpAccessChain %_ptr_Function_v4float %10 %int_0 + %4194302 = OpLoad %v4float %4194301 + OpReturn + OpFunctionEnd +)"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + + std::vector messages = { + {SPV_MSG_ERROR, "", 0, 0, "ID overflow. Try running compact-ids."}}; + SetMessageConsumer(GetTestMessageConsumer(messages)); + auto result = SinglePassRunToBinary(text, true); + EXPECT_EQ(Pass::Status::Failure, std::get<1>(result)); +} + +TEST_F(LocalAccessChainConvertTest, IdOverflowReplacingStore1) { + const std::string text = + R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "PSMain" + OpExecutionMode %4 OriginUpperLeft + OpDecorate %10 Location 47360 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 + %_struct_7 = OpTypeStruct %v4float +%_ptr_Function__struct_7 = OpTypePointer Function %_struct_7 + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 +%_ptr_Function_v4float = OpTypePointer Function %v4float + %13 = OpConstantNull %v4float + %4 = OpFunction %void None %3 + %5 = OpLabel + %10 = OpVariable %_ptr_Function__struct_7 Function + %4194302 = OpAccessChain %_ptr_Function_v4float %10 %int_0 + OpStore %4194302 %13 + OpReturn + OpFunctionEnd +)"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + + std::vector messages = { + {SPV_MSG_ERROR, "", 0, 0, "ID overflow. Try running compact-ids."}}; + SetMessageConsumer(GetTestMessageConsumer(messages)); + auto result = SinglePassRunToBinary(text, true); + EXPECT_EQ(Pass::Status::Failure, std::get<1>(result)); +} + +TEST_F(LocalAccessChainConvertTest, IdOverflowReplacingStore2) { + const std::string text = + R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "PSMain" + OpExecutionMode %4 OriginUpperLeft + OpDecorate %10 Location 47360 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 + %_struct_7 = OpTypeStruct %v4float +%_ptr_Function__struct_7 = OpTypePointer Function %_struct_7 + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 +%_ptr_Function_v4float = OpTypePointer Function %v4float + %13 = OpConstantNull %v4float + %4 = OpFunction %void None %3 + %5 = OpLabel + %10 = OpVariable %_ptr_Function__struct_7 Function + %4194301 = OpAccessChain %_ptr_Function_v4float %10 %int_0 + OpStore %4194301 %13 + OpReturn + OpFunctionEnd +)"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + + std::vector messages = { + {SPV_MSG_ERROR, "", 0, 0, "ID overflow. Try running compact-ids."}}; + SetMessageConsumer(GetTestMessageConsumer(messages)); + auto result = SinglePassRunToBinary(text, true); + EXPECT_EQ(Pass::Status::Failure, std::get<1>(result)); +} + // TODO(greg-lunarg): Add tests to verify handling of these cases: // // Assorted vector and matrix types diff --git a/third_party/spirv-tools/test/opt/local_redundancy_elimination_test.cpp b/third_party/spirv-tools/test/opt/local_redundancy_elimination_test.cpp index bdaafb85f0..bc4635e29b 100644 --- a/third_party/spirv-tools/test/opt/local_redundancy_elimination_test.cpp +++ b/third_party/spirv-tools/test/opt/local_redundancy_elimination_test.cpp @@ -29,7 +29,6 @@ using ::testing::HasSubstr; using ::testing::MatchesRegex; using LocalRedundancyEliminationTest = PassTest<::testing::Test>; -#ifdef SPIRV_EFFCEE // Remove an instruction when it was already computed. TEST_F(LocalRedundancyEliminationTest, RemoveRedundantAdd) { const std::string text = R"( @@ -154,7 +153,6 @@ TEST_F(LocalRedundancyEliminationTest, KeepInstructionsInDifferentBlocks) { )"; SinglePassRunAndMatch(text, false); } -#endif } // namespace } // namespace opt diff --git a/third_party/spirv-tools/test/opt/local_single_block_elim.cpp b/third_party/spirv-tools/test/opt/local_single_block_elim.cpp index da7540e6bf..402352d738 100644 --- a/third_party/spirv-tools/test/opt/local_single_block_elim.cpp +++ b/third_party/spirv-tools/test/opt/local_single_block_elim.cpp @@ -865,7 +865,9 @@ OpReturn OpFunctionEnd )"; + // Relax logical pointers to allow pointer allocations. SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + ValidatorOptions()->relax_logical_pointer = true; SinglePassRunAndCheck(before, after, true, true); } @@ -1060,6 +1062,62 @@ OpFunctionEnd SinglePassRunAndCheck( predefs + before, predefs + after, true, true); } + +TEST_F(LocalSingleBlockLoadStoreElimTest, VariablePointerTest) { + // Check that the load of the first variable is still used and that the load + // of the third variable is propagated. The first load has to remain because + // of the store to the variable pointer. + const std::string text = R"( +; CHECK: [[v1:%\w+]] = OpVariable +; CHECK: [[v2:%\w+]] = OpVariable +; CHECK: [[v3:%\w+]] = OpVariable +; CHECK: [[phi:%\w+]] = OpPhi +; CHECK: [[ld1:%\w+]] = OpLoad %int [[v1]] +; CHECK: OpIAdd %int [[ld1]] %int_0 + OpCapability Shader + OpCapability VariablePointers + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %2 "main" + OpExecutionMode %2 LocalSize 1 1 1 + OpSource GLSL 450 + OpMemberDecorate %_struct_3 0 Offset 0 + OpMemberDecorate %_struct_3 1 Offset 4 + %void = OpTypeVoid + %5 = OpTypeFunction %void + %int = OpTypeInt 32 1 + %bool = OpTypeBool + %_struct_3 = OpTypeStruct %int %int +%_ptr_Function__struct_3 = OpTypePointer Function %_struct_3 +%_ptr_Function_int = OpTypePointer Function %int + %true = OpConstantTrue %bool + %int_0 = OpConstant %int 0 + %int_1 = OpConstant %int 1 + %13 = OpConstantNull %_struct_3 + %2 = OpFunction %void None %5 + %14 = OpLabel + %15 = OpVariable %_ptr_Function_int Function + %16 = OpVariable %_ptr_Function_int Function + %17 = OpVariable %_ptr_Function_int Function + OpSelectionMerge %18 None + OpBranchConditional %true %19 %20 + %19 = OpLabel + OpBranch %18 + %20 = OpLabel + OpBranch %18 + %18 = OpLabel + %21 = OpPhi %_ptr_Function_int %15 %19 %16 %20 + OpStore %15 %int_1 + OpStore %21 %int_0 + %22 = OpLoad %int %15 + OpStore %17 %int_0 + %23 = OpLoad %int %17 + %24 = OpIAdd %int %22 %23 + OpReturn + OpFunctionEnd + )"; + SinglePassRunAndMatch(text, false); +} // TODO(greg-lunarg): Add tests to verify handling of these cases: // // Other target variable types diff --git a/third_party/spirv-tools/test/opt/local_single_store_elim_test.cpp b/third_party/spirv-tools/test/opt/local_single_store_elim_test.cpp index 23e82ba86d..5a1650b7f9 100644 --- a/third_party/spirv-tools/test/opt/local_single_store_elim_test.cpp +++ b/third_party/spirv-tools/test/opt/local_single_store_elim_test.cpp @@ -767,7 +767,9 @@ OpReturn OpFunctionEnd )"; + // Relax logical pointers to allow pointer allocations. SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + ValidatorOptions()->relax_logical_pointer = true; SinglePassRunAndCheck(before, after, true, true); } @@ -845,6 +847,61 @@ OpFunctionEnd SinglePassRunAndCheck(predefs + before, predefs + after, true, true); } + +TEST_F(LocalSingleStoreElimTest, VariablePointerTest) { + // Check that the load of the first variable is still used and that the load + // of the third variable is propagated. The first load has to remain because + // of the store to the variable pointer. + const std::string text = R"( +; CHECK: [[v1:%\w+]] = OpVariable +; CHECK: [[v2:%\w+]] = OpVariable +; CHECK: [[v3:%\w+]] = OpVariable +; CHECK: [[ld1:%\w+]] = OpLoad %int [[v1]] +; CHECK: OpIAdd %int [[ld1]] %int_0 + OpCapability Shader + OpCapability VariablePointers + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %2 "main" + OpExecutionMode %2 LocalSize 1 1 1 + OpSource GLSL 450 + OpMemberDecorate %_struct_3 0 Offset 0 + OpMemberDecorate %_struct_3 1 Offset 4 + %void = OpTypeVoid + %5 = OpTypeFunction %void + %int = OpTypeInt 32 1 + %bool = OpTypeBool + %_struct_3 = OpTypeStruct %int %int +%_ptr_Function__struct_3 = OpTypePointer Function %_struct_3 +%_ptr_Function_int = OpTypePointer Function %int + %true = OpConstantTrue %bool + %int_0 = OpConstant %int 0 + %int_1 = OpConstant %int 1 + %13 = OpConstantNull %_struct_3 + %2 = OpFunction %void None %5 + %14 = OpLabel + %15 = OpVariable %_ptr_Function_int Function + %16 = OpVariable %_ptr_Function_int Function + %17 = OpVariable %_ptr_Function_int Function + OpStore %15 %int_1 + OpStore %17 %int_0 + OpSelectionMerge %18 None + OpBranchConditional %true %19 %20 + %19 = OpLabel + OpBranch %18 + %20 = OpLabel + OpBranch %18 + %18 = OpLabel + %21 = OpPhi %_ptr_Function_int %15 %19 %16 %20 + OpStore %21 %int_0 + %22 = OpLoad %int %15 + %23 = OpLoad %int %17 + %24 = OpIAdd %int %22 %23 + OpReturn + OpFunctionEnd + )"; + SinglePassRunAndMatch(text, false); +} // TODO(greg-lunarg): Add tests to verify handling of these cases: // // Other types diff --git a/third_party/spirv-tools/test/opt/local_ssa_elim_test.cpp b/third_party/spirv-tools/test/opt/local_ssa_elim_test.cpp index 33419395b5..7afbb4cf41 100644 --- a/third_party/spirv-tools/test/opt/local_ssa_elim_test.cpp +++ b/third_party/spirv-tools/test/opt/local_ssa_elim_test.cpp @@ -138,8 +138,8 @@ OpReturn OpFunctionEnd )"; - SinglePassRunAndCheck(predefs + before, - predefs + after, true, true); + SinglePassRunAndCheck(predefs + before, predefs + after, true, + true); } TEST_F(LocalSSAElimTest, NestedForLoop) { @@ -193,7 +193,24 @@ OpDecorate %fo Location 0 )"; const std::string before = - R"(%main = OpFunction %void None %9 + R"( +; CHECK: = OpFunction +; CHECK-NEXT: [[entry:%\w+]] = OpLabel +; CHECK: [[outer_header:%\w+]] = OpLabel +; CHECK-NEXT: [[outer_f:%\w+]] = OpPhi %float %float_0 [[entry]] [[inner_f:%\w+]] [[outer_be:%\w+]] +; CHECK-NEXT: [[i:%\w+]] = OpPhi %int %int_0 [[entry]] [[i_next:%\w+]] [[outer_be]] +; CHECK-NEXT: OpSLessThan {{%\w+}} [[i]] +; CHECK: [[inner_pre_header:%\w+]] = OpLabel +; CHECK: [[inner_header:%\w+]] = OpLabel +; CHECK-NEXT: [[inner_f]] = OpPhi %float [[outer_f]] [[inner_pre_header]] [[f_next:%\w+]] [[inner_be:%\w+]] +; CHECK-NEXT: [[j:%\w+]] = OpPhi %int %int_0 [[inner_pre_header]] [[j_next:%\w+]] [[inner_be]] +; CHECK: [[inner_be]] = OpLabel +; CHECK: [[f_next]] = OpFAdd %float [[inner_f]] +; CHECK: [[j_next]] = OpIAdd %int [[j]] %int_1 +; CHECK: [[outer_be]] = OpLabel +; CHECK: [[i_next]] = OpIAdd +; CHECK: OpStore %fo [[outer_f]] +%main = OpFunction %void None %9 %24 = OpLabel %f = OpVariable %_ptr_Function_float Function %i = OpVariable %_ptr_Function_int Function @@ -212,8 +229,8 @@ OpBranch %31 %31 = OpLabel %32 = OpLoad %int %j %33 = OpSLessThan %bool %32 %int_4 -OpLoopMerge %29 %34 None -OpBranchConditional %33 %34 %29 +OpLoopMerge %50 %34 None +OpBranchConditional %33 %34 %50 %34 = OpLabel %35 = OpLoad %float %f %36 = OpLoad %int %i @@ -226,6 +243,8 @@ OpStore %f %40 %42 = OpIAdd %int %41 %int_1 OpStore %j %42 OpBranch %31 +%50 = OpLabel +OpBranch %29 %29 = OpLabel %43 = OpLoad %int %i %44 = OpIAdd %int %43 %int_1 @@ -238,50 +257,7 @@ OpReturn OpFunctionEnd )"; - const std::string after = - R"(%main = OpFunction %void None %9 -%24 = OpLabel -%f = OpVariable %_ptr_Function_float Function -%i = OpVariable %_ptr_Function_int Function -%j = OpVariable %_ptr_Function_int Function -OpStore %f %float_0 -OpStore %i %int_0 -OpBranch %25 -%25 = OpLabel -%47 = OpPhi %float %float_0 %24 %50 %29 -%46 = OpPhi %int %int_0 %24 %44 %29 -%27 = OpSLessThan %bool %46 %int_4 -OpLoopMerge %28 %29 None -OpBranchConditional %27 %30 %28 -%30 = OpLabel -OpStore %j %int_0 -OpBranch %31 -%31 = OpLabel -%50 = OpPhi %float %47 %30 %40 %34 -%48 = OpPhi %int %int_0 %30 %42 %34 -%33 = OpSLessThan %bool %48 %int_4 -OpLoopMerge %29 %34 None -OpBranchConditional %33 %34 %29 -%34 = OpLabel -%38 = OpAccessChain %_ptr_Input_float %BC %46 %48 -%39 = OpLoad %float %38 -%40 = OpFAdd %float %50 %39 -OpStore %f %40 -%42 = OpIAdd %int %48 %int_1 -OpStore %j %42 -OpBranch %31 -%29 = OpLabel -%44 = OpIAdd %int %46 %int_1 -OpStore %i %44 -OpBranch %25 -%28 = OpLabel -OpStore %fo %47 -OpReturn -OpFunctionEnd -)"; - - SinglePassRunAndCheck(predefs + before, - predefs + after, true, true); + SinglePassRunAndMatch(predefs + before, true); } TEST_F(LocalSSAElimTest, ForLoopWithContinue) { @@ -426,9 +402,9 @@ OpReturn OpFunctionEnd )"; - SinglePassRunAndCheck( - predefs + names + predefs2 + before, predefs + names + predefs2 + after, - true, true); + SinglePassRunAndCheck(predefs + names + predefs2 + before, + predefs + names + predefs2 + after, + true, true); } TEST_F(LocalSSAElimTest, ForLoopWithBreak) { @@ -567,8 +543,8 @@ OpReturn OpFunctionEnd )"; - SinglePassRunAndCheck(predefs + before, - predefs + after, true, true); + SinglePassRunAndCheck(predefs + before, predefs + after, true, + true); } TEST_F(LocalSSAElimTest, SwapProblem) { @@ -704,8 +680,8 @@ OpReturn OpFunctionEnd )"; - SinglePassRunAndCheck(predefs + before, - predefs + after, true, true); + SinglePassRunAndCheck(predefs + before, predefs + after, true, + true); } TEST_F(LocalSSAElimTest, LostCopyProblem) { @@ -848,8 +824,8 @@ OpReturn OpFunctionEnd )"; - SinglePassRunAndCheck(predefs + before, - predefs + after, true, true); + SinglePassRunAndCheck(predefs + before, predefs + after, true, + true); } TEST_F(LocalSSAElimTest, IfThenElse) { @@ -948,8 +924,8 @@ OpReturn OpFunctionEnd )"; - SinglePassRunAndCheck(predefs + before, - predefs + after, true, true); + SinglePassRunAndCheck(predefs + before, predefs + after, true, + true); } TEST_F(LocalSSAElimTest, IfThen) { @@ -1037,8 +1013,8 @@ OpReturn OpFunctionEnd )"; - SinglePassRunAndCheck(predefs + before, - predefs + after, true, true); + SinglePassRunAndCheck(predefs + before, predefs + after, true, + true); } TEST_F(LocalSSAElimTest, Switch) { @@ -1168,8 +1144,8 @@ OpReturn OpFunctionEnd )"; - SinglePassRunAndCheck(predefs + before, - predefs + after, true, true); + SinglePassRunAndCheck(predefs + before, predefs + after, true, + true); } TEST_F(LocalSSAElimTest, SwitchWithFallThrough) { @@ -1300,8 +1276,8 @@ OpReturn OpFunctionEnd )"; - SinglePassRunAndCheck(predefs + before, - predefs + after, true, true); + SinglePassRunAndCheck(predefs + before, predefs + after, true, + true); } TEST_F(LocalSSAElimTest, DontPatchPhiInLoopHeaderThatIsNotAVar) { @@ -1331,7 +1307,7 @@ OpReturn OpFunctionEnd )"; - SinglePassRunAndCheck(before, before, true, true); + SinglePassRunAndCheck(before, before, true, true); } TEST_F(LocalSSAElimTest, OptInitializedVariableLikeStore) { @@ -1428,8 +1404,8 @@ OpReturn OpFunctionEnd )"; - SinglePassRunAndCheck( - predefs + func_before, predefs + func_after, true, true); + SinglePassRunAndCheck(predefs + func_before, + predefs + func_after, true, true); } TEST_F(LocalSSAElimTest, PointerVariable) { @@ -1528,8 +1504,10 @@ OpReturn OpFunctionEnd )"; + // Relax logical pointers to allow pointer allocations. SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndCheck(before, after, true, true); + ValidatorOptions()->relax_logical_pointer = true; + SinglePassRunAndCheck(before, after, true, true); } TEST_F(LocalSSAElimTest, VerifyInstToBlockMap) { @@ -1618,14 +1596,12 @@ OpFunctionEnd // Force the instruction to block mapping to get built. context->get_instr_block(27u); - auto pass = MakeUnique(); + auto pass = MakeUnique(); pass->SetMessageConsumer(nullptr); const auto status = pass->Run(context.get()); EXPECT_TRUE(status == Pass::Status::SuccessWithChange); } -// TODO(dneto): Add Effcee as required dependency, and make this unconditional. -#ifdef SPIRV_EFFCEE TEST_F(LocalSSAElimTest, CompositeExtractProblem) { const std::string spv_asm = R"( OpCapability Tessellation @@ -1664,6 +1640,7 @@ TEST_F(LocalSSAElimTest, CompositeExtractProblem) { %_ptr_Function__struct_11 = OpTypePointer Function %_struct_11 %2 = OpFunction %void None %4 %33 = OpLabel + %66 = OpVariable %_ptr_Function__arr__struct_11_uint_3 Function %34 = OpLoad %_arr_v4float_uint_3 %16 %35 = OpLoad %_arr_v4float_uint_3 %17 %36 = OpLoad %_arr_v4float_uint_3 %18 @@ -1696,7 +1673,6 @@ TEST_F(LocalSSAElimTest, CompositeExtractProblem) { %63 = OpCompositeExtract %v2float %40 2 %64 = OpCompositeConstruct %_struct_11 %57 %58 %59 %60 %61 %62 %63 %65 = OpCompositeConstruct %_arr__struct_11_uint_3 %48 %56 %64 - %66 = OpVariable %_ptr_Function__arr__struct_11_uint_3 Function %67 = OpLoad %uint %20 ; CHECK OpStore {{%\d+}} [[store_source:%\d+]] @@ -1758,7 +1734,269 @@ TEST_F(LocalSSAElimTest, DecoratedVariable) { SinglePassRunAndMatch(spv_asm, true); } -#endif + +// Test that the RelaxedPrecision decoration on the variable to added to the +// result of the OpPhi instruction. +TEST_F(LocalSSAElimTest, MultipleEdges) { + const std::string spv_asm = R"( + ; CHECK: OpSelectionMerge + ; CHECK: [[header_bb:%\w+]] = OpLabel + ; CHECK-NOT: OpLabel + ; CHECK: OpSwitch {{%\w+}} {{%\w+}} 76 [[bb1:%\w+]] 17 [[bb2:%\w+]] + ; CHECK-SAME: 4 [[bb2]] + ; CHECK: [[bb2]] = OpLabel + ; CHECK-NEXT: OpPhi [[type:%\w+]] [[val:%\w+]] [[header_bb]] %int_0 [[bb1]] + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %int = OpTypeInt 32 1 + %_ptr_Function_int = OpTypePointer Function %int + %int_0 = OpConstant %int 0 + %bool = OpTypeBool + %true = OpConstantTrue %bool + %false = OpConstantFalse %bool + %int_1 = OpConstant %int 1 + %4 = OpFunction %void None %3 + %5 = OpLabel + %8 = OpVariable %_ptr_Function_int Function + OpBranch %10 + %10 = OpLabel + OpLoopMerge %12 %13 None + OpBranch %14 + %14 = OpLabel + OpBranchConditional %true %11 %12 + %11 = OpLabel + OpSelectionMerge %19 None + OpBranchConditional %false %18 %19 + %18 = OpLabel + OpSelectionMerge %22 None + OpSwitch %int_0 %22 76 %20 17 %21 4 %21 + %20 = OpLabel + %23 = OpLoad %int %8 + OpStore %8 %int_0 + OpBranch %21 + %21 = OpLabel + OpBranch %22 + %22 = OpLabel + OpBranch %19 + %19 = OpLabel + OpBranch %13 + %13 = OpLabel + OpBranch %10 + %12 = OpLabel + OpReturn + OpFunctionEnd + )"; + + SinglePassRunAndMatch(spv_asm, true); +} + +TEST_F(LocalSSAElimTest, VariablePointerTest1) { + // Check that the load of the first variable is still used and that the load + // of the third variable is propagated. The first load has to remain because + // of the store to the variable pointer. + const std::string text = R"( +; CHECK: [[v1:%\w+]] = OpVariable +; CHECK: [[v2:%\w+]] = OpVariable +; CHECK: [[v3:%\w+]] = OpVariable +; CHECK: [[ld1:%\w+]] = OpLoad %int [[v1]] +; CHECK: OpIAdd %int [[ld1]] %int_0 + OpCapability Shader + OpCapability VariablePointers + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %2 "main" + OpExecutionMode %2 LocalSize 1 1 1 + OpSource GLSL 450 + OpMemberDecorate %_struct_3 0 Offset 0 + OpMemberDecorate %_struct_3 1 Offset 4 + %void = OpTypeVoid + %5 = OpTypeFunction %void + %int = OpTypeInt 32 1 + %bool = OpTypeBool + %_struct_3 = OpTypeStruct %int %int +%_ptr_Function__struct_3 = OpTypePointer Function %_struct_3 +%_ptr_Function_int = OpTypePointer Function %int + %true = OpConstantTrue %bool + %int_0 = OpConstant %int 0 + %int_1 = OpConstant %int 1 + %13 = OpConstantNull %_struct_3 + %2 = OpFunction %void None %5 + %14 = OpLabel + %15 = OpVariable %_ptr_Function_int Function + %16 = OpVariable %_ptr_Function_int Function + %17 = OpVariable %_ptr_Function_int Function + OpStore %15 %int_1 + OpStore %17 %int_0 + OpSelectionMerge %18 None + OpBranchConditional %true %19 %20 + %19 = OpLabel + OpBranch %18 + %20 = OpLabel + OpBranch %18 + %18 = OpLabel + %21 = OpPhi %_ptr_Function_int %15 %19 %16 %20 + OpStore %21 %int_0 + %22 = OpLoad %int %15 + %23 = OpLoad %int %17 + %24 = OpIAdd %int %22 %23 + OpReturn + OpFunctionEnd + )"; + SinglePassRunAndMatch(text, false); +} + +TEST_F(LocalSSAElimTest, VariablePointerTest2) { + // Check that the load of the first variable is still used and that the load + // of the third variable is propagated. The first load has to remain because + // of the store to the variable pointer. + const std::string text = R"( +; CHECK: [[v1:%\w+]] = OpVariable +; CHECK: [[v2:%\w+]] = OpVariable +; CHECK: [[v3:%\w+]] = OpVariable +; CHECK: [[ld1:%\w+]] = OpLoad %int [[v1]] +; CHECK: OpIAdd %int [[ld1]] %int_0 + OpCapability Shader + OpCapability VariablePointers + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %2 "main" + OpExecutionMode %2 LocalSize 1 1 1 + OpSource GLSL 450 + OpMemberDecorate %_struct_3 0 Offset 0 + OpMemberDecorate %_struct_3 1 Offset 4 + %void = OpTypeVoid + %5 = OpTypeFunction %void + %int = OpTypeInt 32 1 + %bool = OpTypeBool + %_struct_3 = OpTypeStruct %int %int +%_ptr_Function__struct_3 = OpTypePointer Function %_struct_3 +%_ptr_Function_int = OpTypePointer Function %int + %true = OpConstantTrue %bool + %int_0 = OpConstant %int 0 + %int_1 = OpConstant %int 1 + %13 = OpConstantNull %_struct_3 + %2 = OpFunction %void None %5 + %14 = OpLabel + %15 = OpVariable %_ptr_Function_int Function + %16 = OpVariable %_ptr_Function_int Function + %17 = OpVariable %_ptr_Function_int Function + OpStore %15 %int_1 + OpStore %17 %int_0 + OpSelectionMerge %18 None + OpBranchConditional %true %19 %20 + %19 = OpLabel + OpBranch %18 + %20 = OpLabel + OpBranch %18 + %18 = OpLabel + %21 = OpPhi %_ptr_Function_int %15 %19 %16 %20 + OpStore %21 %int_0 + %22 = OpLoad %int %15 + %23 = OpLoad %int %17 + %24 = OpIAdd %int %22 %23 + OpReturn + OpFunctionEnd + )"; + SinglePassRunAndMatch(text, false); +} + +TEST_F(LocalSSAElimTest, ChainedTrivialPhis) { + // Check that the copy object get the undef value implicitly assigned in the + // entry block. + const std::string text = R"( +; CHECK: [[undef:%\w+]] = OpUndef %v4float +; CHECK: OpCopyObject %v4float [[undef]] + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %2 "main" + OpExecutionMode %2 LocalSize 1 18 6 + OpSource ESSL 310 + %void = OpTypeVoid + %4 = OpTypeFunction %void + %bool = OpTypeBool + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 +%_ptr_Function_v4float = OpTypePointer Function %v4float + %2 = OpFunction %void None %4 + %9 = OpLabel + %10 = OpVariable %_ptr_Function_v4float Function + OpBranch %11 + %11 = OpLabel + OpLoopMerge %12 %13 None + OpBranch %14 + %14 = OpLabel + %15 = OpUndef %bool + OpBranchConditional %15 %16 %12 + %16 = OpLabel + %17 = OpUndef %bool + OpSelectionMerge %18 None + OpBranchConditional %17 %19 %18 + %19 = OpLabel + %20 = OpUndef %bool + OpLoopMerge %21 %22 None + OpBranchConditional %20 %23 %21 + %23 = OpLabel + %24 = OpLoad %v4float %10 + %25 = OpCopyObject %v4float %24 + %26 = OpUndef %bool + OpBranch %22 + %22 = OpLabel + OpBranch %19 + %21 = OpLabel + OpBranch %12 + %18 = OpLabel + OpBranch %13 + %13 = OpLabel + OpBranch %11 + %12 = OpLabel + %27 = OpLoad %v4float %10 + OpReturn + OpFunctionEnd + )"; + SinglePassRunAndMatch(text, false); +} + +TEST_F(LocalSSAElimTest, Overflowtest1) { + // Check that the copy object get the undef value implicitly assigned in the + // entry block. + const std::string text = R"( +OpCapability Geometry +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %4 "P2Mai" %12 %17 +OpExecutionMode %4 OriginUpperLeft +%2 = OpTypeVoid +%3 = OpTypeFunction %2 +%6 = OpTypeFloat 32 +%7 = OpTypeVector %6 4 +%11 = OpTypePointer Input %7 +%16 = OpTypePointer Output %7 +%23 = OpTypePointer Function %7 +%12 = OpVariable %11 Input +%17 = OpVariable %16 Output +%4 = OpFunction %2 None %3 +%2177 = OpLabel +%4194302 = OpVariable %23 Function +%4194301 = OpLoad %7 %4194302 +OpStore %17 %4194301 +OpReturn +OpFunctionEnd + )"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + + std::vector messages = { + {SPV_MSG_ERROR, "", 0, 0, "ID overflow. Try running compact-ids."}}; + SetMessageConsumer(GetTestMessageConsumer(messages)); + auto result = SinglePassRunToBinary(text, true); + EXPECT_EQ(Pass::Status::Failure, std::get<1>(result)); +} // TODO(greg-lunarg): Add tests to verify handling of these cases: // diff --git a/third_party/spirv-tools/test/opt/loop_optimizations/CMakeLists.txt b/third_party/spirv-tools/test/opt/loop_optimizations/CMakeLists.txt index 8c7971b7fd..e3620787db 100644 --- a/third_party/spirv-tools/test/opt/loop_optimizations/CMakeLists.txt +++ b/third_party/spirv-tools/test/opt/loop_optimizations/CMakeLists.txt @@ -37,4 +37,5 @@ add_spvtools_unittest(TARGET opt_loops unroll_simple.cpp unswitch.cpp LIBS SPIRV-Tools-opt + PCH_FILE pch_test_opt_loop ) diff --git a/third_party/spirv-tools/test/opt/loop_optimizations/fusion_legal.cpp b/third_party/spirv-tools/test/opt/loop_optimizations/fusion_legal.cpp index 509516f80d..56b0b76f4c 100644 --- a/third_party/spirv-tools/test/opt/loop_optimizations/fusion_legal.cpp +++ b/third_party/spirv-tools/test/opt/loop_optimizations/fusion_legal.cpp @@ -18,15 +18,12 @@ #include #include +#include "effcee/effcee.h" #include "gmock/gmock.h" #include "source/opt/loop_descriptor.h" #include "source/opt/loop_fusion.h" #include "test/opt/pass_fixture.h" -#ifdef SPIRV_EFFCEE -#include "effcee/effcee.h" -#endif - namespace spvtools { namespace opt { namespace { @@ -52,7 +49,6 @@ void Match(const std::string& checks, IRContext* context) { std::vector bin; context->module()->ToBinary(&bin, true); EXPECT_TRUE(Validate(bin)); -#ifdef SPIRV_EFFCEE std::string assembly; SpirvTools tools(SPV_ENV_UNIVERSAL_1_2); EXPECT_TRUE( @@ -63,9 +59,6 @@ void Match(const std::string& checks, IRContext* context) { EXPECT_EQ(effcee::Result::Status::Ok, match_result.status()) << match_result.message() << "\nChecking result:\n" << assembly; -#else // ! SPIRV_EFFCEE - (void)checks; -#endif } /* @@ -3184,7 +3177,7 @@ TEST_F(FusionLegalTest, OuterloopWithBreakContinueInInner) { %21 = OpLabel %29 = OpSMod %6 %96 %28 %30 = OpIEqual %17 %29 %9 - OpSelectionMerge %32 None + OpSelectionMerge %sel_merge None OpBranchConditional %30 %31 %48 %31 = OpLabel %44 = OpAccessChain %7 %41 %91 %96 @@ -3194,8 +3187,10 @@ TEST_F(FusionLegalTest, OuterloopWithBreakContinueInInner) { OpStore %47 %46 OpBranch %32 %48 = OpLabel - OpBranch %23 + OpBranch %sel_merge %32 = OpLabel + OpBranch %sel_merge + %sel_merge = OpLabel OpBranch %23 %23 = OpLabel %52 = OpIAdd %6 %96 %51 @@ -3231,7 +3226,7 @@ TEST_F(FusionLegalTest, OuterloopWithBreakContinueInInner) { %72 = OpSMod %6 %93 %28 %73 = OpIEqual %17 %72 %9 OpSelectionMerge %75 None - OpBranchConditional %73 %74 %85 + OpBranchConditional %73 %74 %66 %74 = OpLabel %81 = OpAccessChain %7 %38 %92 %93 %82 = OpLoad %6 %81 @@ -3239,8 +3234,6 @@ TEST_F(FusionLegalTest, OuterloopWithBreakContinueInInner) { %84 = OpAccessChain %7 %76 %92 %93 OpStore %84 %83 OpBranch %75 - %85 = OpLabel - OpBranch %66 %75 = OpLabel OpBranch %67 %67 = OpLabel diff --git a/third_party/spirv-tools/test/opt/loop_optimizations/fusion_pass.cpp b/third_party/spirv-tools/test/opt/loop_optimizations/fusion_pass.cpp index 857ada9393..9493923750 100644 --- a/third_party/spirv-tools/test/opt/loop_optimizations/fusion_pass.cpp +++ b/third_party/spirv-tools/test/opt/loop_optimizations/fusion_pass.cpp @@ -14,21 +14,16 @@ #include +#include "effcee/effcee.h" #include "gmock/gmock.h" #include "test/opt/pass_fixture.h" -#ifdef SPIRV_EFFCEE -#include "effcee/effcee.h" -#endif - namespace spvtools { namespace opt { namespace { using FusionPassTest = PassTest<::testing::Test>; -#ifdef SPIRV_EFFCEE - /* Generated from the following GLSL + --eliminate-local-multi-store @@ -717,8 +712,6 @@ TEST_F(FusionPassTest, TooManyRegisters) { SinglePassRunAndMatch(text, true, 5); } -#endif - } // namespace } // namespace opt } // namespace spvtools diff --git a/third_party/spirv-tools/test/opt/loop_optimizations/hoist_single_nested_loops.cpp b/third_party/spirv-tools/test/opt/loop_optimizations/hoist_single_nested_loops.cpp index 7fa1fb0a0d..056f3f0259 100644 --- a/third_party/spirv-tools/test/opt/loop_optimizations/hoist_single_nested_loops.cpp +++ b/third_party/spirv-tools/test/opt/loop_optimizations/hoist_single_nested_loops.cpp @@ -158,6 +158,52 @@ OpFunctionEnd SinglePassRunAndCheck(before_hoist, after_hoist, true); } +TEST_F(PassClassTest, PreHeaderIsAlsoHeader) { + // Move OpSLessThan out of the inner loop. The preheader for the inner loop + // is the header of the outer loop. The loop merge should not be separated + // from the branch in that block. + const std::string text = R"( + ; CHECK: OpFunction + ; CHECK-NEXT: OpLabel + ; CHECK-NEXT: OpBranch [[header:%\w+]] + ; CHECK: [[header]] = OpLabel + ; CHECK-NEXT: OpSLessThan %bool %int_1 %int_1 + ; CHECK-NEXT: OpLoopMerge + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpSource ESSL 310 + %void = OpTypeVoid + %4 = OpTypeFunction %void + %int = OpTypeInt 32 1 + %int_1 = OpConstant %int 1 + %bool = OpTypeBool + %2 = OpFunction %void None %4 + %18 = OpLabel + OpBranch %21 + %21 = OpLabel + OpLoopMerge %22 %23 None + OpBranch %24 + %24 = OpLabel + %25 = OpSLessThan %bool %int_1 %int_1 + OpLoopMerge %26 %27 None + OpBranchConditional %25 %27 %26 + %27 = OpLabel + OpBranch %24 + %26 = OpLabel + OpBranch %22 + %23 = OpLabel + OpBranch %21 + %22 = OpLabel + OpReturn + OpFunctionEnd + )"; + + SinglePassRunAndMatch(text, true); +} + } // namespace } // namespace opt } // namespace spvtools diff --git a/third_party/spirv-tools/test/opt/loop_optimizations/hoist_without_preheader.cpp b/third_party/spirv-tools/test/opt/loop_optimizations/hoist_without_preheader.cpp index 9e8d02fac5..2e34b0142f 100644 --- a/third_party/spirv-tools/test/opt/loop_optimizations/hoist_without_preheader.cpp +++ b/third_party/spirv-tools/test/opt/loop_optimizations/hoist_without_preheader.cpp @@ -45,7 +45,6 @@ void main(){ } } */ -#ifdef SPIRV_EFFCEE TEST_F(PassClassTest, HoistWithoutPreheader) { const std::string text = R"(OpCapability Shader %1 = OpExtInstImport "GLSL.std.450" @@ -117,8 +116,82 @@ OpFunctionEnd SinglePassRunAndMatch(text, false); } -#endif +TEST_F(PassClassTest, HoistWithoutPreheaderAtIdBound) { + const std::string text = R"(OpCapability Shader +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 440 +OpName %main "main" +%void = OpTypeVoid +%4 = OpTypeFunction %void +%int = OpTypeInt 32 1 +%_ptr_Function_int = OpTypePointer Function %int +%int_1 = OpConstant %int 1 +%int_2 = OpConstant %int 2 +%int_0 = OpConstant %int 0 +%int_10 = OpConstant %int 10 +%bool = OpTypeBool +%int_5 = OpConstant %int 5 +%main = OpFunction %void None %4 +%13 = OpLabel +OpBranch %14 +%14 = OpLabel +%15 = OpPhi %int %int_0 %13 %16 %17 +OpLoopMerge %25 %17 None +OpBranch %19 +%19 = OpLabel +%20 = OpSLessThan %bool %15 %int_10 +OpBranchConditional %20 %21 %25 +%21 = OpLabel +%22 = OpIEqual %bool %15 %int_5 +OpSelectionMerge %23 None +OpBranchConditional %22 %24 %23 +%24 = OpLabel +OpBranch %25 +%23 = OpLabel +OpBranch %17 +%17 = OpLabel +%16 = OpIAdd %int %15 %int_1 +OpBranch %14 +%25 = OpLabel +%26 = OpPhi %int %int_0 %24 %int_0 %19 %27 %28 +%29 = OpPhi %int %int_0 %24 %int_0 %19 %30 %28 +OpLoopMerge %31 %28 None +OpBranch %32 +%32 = OpLabel +%33 = OpSLessThan %bool %29 %int_10 +OpBranchConditional %33 %34 %31 +%34 = OpLabel +%27 = OpIAdd %int %int_1 %int_2 +OpBranch %28 +%28 = OpLabel +%30 = OpIAdd %int %29 %int_1 +OpBranch %25 +%31 = OpLabel +OpReturn +OpFunctionEnd +)"; + + std::unique_ptr context = + BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + uint32_t current_bound = context->module()->id_bound(); + context->set_max_id_bound(current_bound); + + auto pass = MakeUnique(); + auto result = pass->Run(context.get()); + EXPECT_EQ(result, Pass::Status::Failure); + + std::vector binary; + context->module()->ToBinary(&binary, false); + std::string optimized_asm; + SpirvTools tools_(SPV_ENV_UNIVERSAL_1_1); + tools_.Disassemble(binary, &optimized_asm); + std::cout << optimized_asm << std::endl; +} } // namespace } // namespace opt } // namespace spvtools diff --git a/third_party/spirv-tools/test/opt/loop_optimizations/lcssa.cpp b/third_party/spirv-tools/test/opt/loop_optimizations/lcssa.cpp index 220772652b..ace6ce1968 100644 --- a/third_party/spirv-tools/test/opt/loop_optimizations/lcssa.cpp +++ b/third_party/spirv-tools/test/opt/loop_optimizations/lcssa.cpp @@ -16,6 +16,7 @@ #include #include +#include "effcee/effcee.h" #include "gmock/gmock.h" #include "source/opt/build_module.h" #include "source/opt/loop_descriptor.h" @@ -24,16 +25,10 @@ #include "test/opt//assembly_builder.h" #include "test/opt/function_utils.h" -#ifdef SPIRV_EFFCEE -#include "effcee/effcee.h" -#endif - namespace spvtools { namespace opt { namespace { -#ifdef SPIRV_EFFCEE - bool Validate(const std::vector& bin) { spv_target_env target_env = SPV_ENV_UNIVERSAL_1_2; spv_context spvContext = spvContextCreate(target_env); @@ -607,8 +602,6 @@ TEST_F(LCSSATest, LCSSAUseInNonEligiblePhi) { Match(text, context.get()); } -#endif // SPIRV_EFFCEE - } // namespace } // namespace opt } // namespace spvtools diff --git a/third_party/spirv-tools/test/opt/loop_optimizations/pch_test_opt_loop.cpp b/third_party/spirv-tools/test/opt/loop_optimizations/pch_test_opt_loop.cpp new file mode 100644 index 0000000000..f4ac7b2988 --- /dev/null +++ b/third_party/spirv-tools/test/opt/loop_optimizations/pch_test_opt_loop.cpp @@ -0,0 +1,15 @@ +// Copyright (c) 2018 The Khronos Group Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "pch_test_opt_loop.h" diff --git a/third_party/spirv-tools/test/opt/loop_optimizations/pch_test_opt_loop.h b/third_party/spirv-tools/test/opt/loop_optimizations/pch_test_opt_loop.h new file mode 100644 index 0000000000..4e8106fbfc --- /dev/null +++ b/third_party/spirv-tools/test/opt/loop_optimizations/pch_test_opt_loop.h @@ -0,0 +1,25 @@ +// Copyright (c) 2018 The Khronos Group Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "gmock/gmock.h" +#include "source/opt/iterator.h" +#include "source/opt/loop_dependence.h" +#include "source/opt/loop_descriptor.h" +#include "source/opt/pass.h" +#include "source/opt/scalar_analysis.h" +#include "source/opt/tree_iterator.h" +#include "test/opt/assembly_builder.h" +#include "test/opt/function_utils.h" +#include "test/opt/pass_fixture.h" +#include "test/opt/pass_utils.h" diff --git a/third_party/spirv-tools/test/opt/loop_optimizations/peeling.cpp b/third_party/spirv-tools/test/opt/loop_optimizations/peeling.cpp index e5db20b408..10d8add382 100644 --- a/third_party/spirv-tools/test/opt/loop_optimizations/peeling.cpp +++ b/third_party/spirv-tools/test/opt/loop_optimizations/peeling.cpp @@ -16,16 +16,13 @@ #include #include +#include "effcee/effcee.h" #include "gmock/gmock.h" #include "source/opt/ir_builder.h" #include "source/opt/loop_descriptor.h" #include "source/opt/loop_peeling.h" #include "test/opt/pass_fixture.h" -#ifdef SPIRV_EFFCEE -#include "effcee/effcee.h" -#endif - namespace spvtools { namespace opt { namespace { @@ -51,7 +48,6 @@ void Match(const std::string& checks, IRContext* context) { std::vector bin; context->module()->ToBinary(&bin, true); EXPECT_TRUE(Validate(bin)); -#ifdef SPIRV_EFFCEE std::string assembly; SpirvTools tools(SPV_ENV_UNIVERSAL_1_2); EXPECT_TRUE( @@ -62,9 +58,6 @@ void Match(const std::string& checks, IRContext* context) { EXPECT_EQ(effcee::Result::Status::Ok, match_result.status()) << match_result.message() << "\nChecking result:\n" << assembly; -#else // ! SPIRV_EFFCEE - (void)checks; -#endif } /* @@ -139,7 +132,7 @@ TEST_F(PeelingTest, CannotPeel) { } else { InstructionBuilder builder(context.get(), &*f.begin()); // Exit condition. - loop_count = builder.Add32BitSignedIntegerConstant(10); + loop_count = builder.GetSintConstant(10); } LoopPeeling peel(&*ld.begin(), loop_count); @@ -501,7 +494,7 @@ TEST_F(PeelingTest, SimplePeeling) { InstructionBuilder builder(context.get(), &*f.begin()); // Exit condition. - Instruction* ten_cst = builder.Add32BitSignedIntegerConstant(10); + Instruction* ten_cst = builder.GetSintConstant(10); LoopPeeling peel(&*ld.begin(), ten_cst); EXPECT_TRUE(peel.CanPeelLoop()); @@ -555,7 +548,7 @@ CHECK-NEXT: OpLoopMerge InstructionBuilder builder(context.get(), &*f.begin()); // Exit condition. - Instruction* ten_cst = builder.Add32BitSignedIntegerConstant(10); + Instruction* ten_cst = builder.GetSintConstant(10); LoopPeeling peel(&*ld.begin(), ten_cst); EXPECT_TRUE(peel.CanPeelLoop()); @@ -611,7 +604,7 @@ CHECK-NEXT: OpLoopMerge InstructionBuilder builder(context.get(), &*f.begin()); // Exit condition. - Instruction* ten_cst = builder.Add32BitSignedIntegerConstant(10); + Instruction* ten_cst = builder.GetSintConstant(10); LoopPeeling peel(&*ld.begin(), ten_cst, context->get_def_use_mgr()->GetDef(22)); @@ -664,7 +657,7 @@ CHECK-NEXT: OpLoopMerge InstructionBuilder builder(context.get(), &*f.begin()); // Exit condition. - Instruction* ten_cst = builder.Add32BitSignedIntegerConstant(10); + Instruction* ten_cst = builder.GetSintConstant(10); LoopPeeling peel(&*ld.begin(), ten_cst, context->get_def_use_mgr()->GetDef(22)); @@ -925,7 +918,7 @@ TEST_F(PeelingTest, DoWhilePeeling) { EXPECT_EQ(ld.NumLoops(), 1u); InstructionBuilder builder(context.get(), &*f.begin()); // Exit condition. - Instruction* ten_cst = builder.Add32BitUnsignedIntegerConstant(10); + Instruction* ten_cst = builder.GetUintConstant(10); LoopPeeling peel(&*ld.begin(), ten_cst); EXPECT_TRUE(peel.CanPeelLoop()); @@ -975,7 +968,7 @@ CHECK-NEXT: OpLoopMerge InstructionBuilder builder(context.get(), &*f.begin()); // Exit condition. - Instruction* ten_cst = builder.Add32BitUnsignedIntegerConstant(10); + Instruction* ten_cst = builder.GetUintConstant(10); LoopPeeling peel(&*ld.begin(), ten_cst); EXPECT_TRUE(peel.CanPeelLoop()); diff --git a/third_party/spirv-tools/test/opt/loop_optimizations/unroll_simple.cpp b/third_party/spirv-tools/test/opt/loop_optimizations/unroll_simple.cpp index 3b01fdc317..f551e7ca91 100644 --- a/third_party/spirv-tools/test/opt/loop_optimizations/unroll_simple.cpp +++ b/third_party/spirv-tools/test/opt/loop_optimizations/unroll_simple.cpp @@ -2952,6 +2952,52 @@ OpFunctionEnd EXPECT_NE(loop_2.GetLatchBlock(), loop_2.GetContinueBlock()); } +// Test that a loop with a self-referencing OpPhi instruction is handled +// correctly. +TEST_F(PassClassTest, OpPhiSelfReference) { + const std::string text = R"( + ; Find the two adds from the unrolled loop + ; CHECK: OpIAdd + ; CHECK: OpIAdd + ; CHECK: OpIAdd %uint %uint_0 %uint_1 + ; CHECK-NEXT: OpReturn + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %2 "main" + OpExecutionMode %2 LocalSize 8 8 1 + OpSource HLSL 600 + %uint = OpTypeInt 32 0 + %void = OpTypeVoid + %5 = OpTypeFunction %void +%uint_0 = OpConstant %uint 0 +%uint_1 = OpConstant %uint 1 + %bool = OpTypeBool + %true = OpConstantTrue %bool + %2 = OpFunction %void None %5 + %10 = OpLabel + OpBranch %19 + %19 = OpLabel + %20 = OpPhi %uint %uint_0 %10 %20 %21 + %22 = OpPhi %uint %uint_0 %10 %23 %21 + %24 = OpULessThanEqual %bool %22 %uint_1 + OpLoopMerge %25 %21 Unroll + OpBranchConditional %24 %21 %25 + %21 = OpLabel + %23 = OpIAdd %uint %22 %uint_1 + OpBranch %19 + %25 = OpLabel + %14 = OpIAdd %uint %20 %uint_1 + OpReturn + OpFunctionEnd + )"; + + const bool kFullyUnroll = true; + const uint32_t kUnrollFactor = 0; + SinglePassRunAndMatch(text, true, kFullyUnroll, + kUnrollFactor); +} + } // namespace } // namespace opt } // namespace spvtools diff --git a/third_party/spirv-tools/test/opt/loop_optimizations/unswitch.cpp b/third_party/spirv-tools/test/opt/loop_optimizations/unswitch.cpp index 96a7fc010b..dc7073fd56 100644 --- a/third_party/spirv-tools/test/opt/loop_optimizations/unswitch.cpp +++ b/third_party/spirv-tools/test/opt/loop_optimizations/unswitch.cpp @@ -14,21 +14,16 @@ #include +#include "effcee/effcee.h" #include "gmock/gmock.h" #include "test/opt/pass_fixture.h" -#ifdef SPIRV_EFFCEE -#include "effcee/effcee.h" -#endif - namespace spvtools { namespace opt { namespace { using UnswitchTest = PassTest<::testing::Test>; -#ifdef SPIRV_EFFCEE - /* Generated from the following GLSL + --eliminate-local-multi-store @@ -62,13 +57,18 @@ TEST_F(UnswitchTest, SimpleUnswitch) { ; CHECK-NEXT: [[phi_j:%\w+]] = OpPhi %int %int_0 [[loop_f]] [[iv_j:%\w+]] [[continue]] ; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] [[continue]] None ; CHECK: [[loop_exit:%\w+]] = OpSLessThan {{%\w+}} [[phi_i]] {{%\w+}} -; CHECK-NEXT: OpBranchConditional [[loop_exit]] {{%\w+}} [[merge]] -; Check that we have i+=1 and j+=2. -; CHECK: [[phi_j:%\w+]] = OpIAdd %int [[phi_j]] %int_1 -; CHECK: [[iv_i]] = OpIAdd %int [[phi_i]] %int_1 -; CHECK: [[iv_j]] = OpIAdd %int [[phi_j]] %int_1 -; CHECK: [[merge]] = OpLabel -; CHECK-NEXT: OpBranch [[if_merge]] +; CHECK-NEXT: OpBranchConditional [[loop_exit]] [[loop_body:%\w+]] [[merge]] +; [[loop_body]] = OpLabel +; CHECK: OpSelectionMerge [[sel_merge:%\w+]] None +; CHECK: OpBranchConditional %false [[bb1:%\w+]] [[bb2:%\w+]] +; CHECK: [[bb2]] = OpLabel +; CHECK-NEXT: [[inc_j:%\w+]] = OpIAdd %int [[phi_j]] %int_1 +; CHECK-NEXT: OpBranch [[sel_merge]] +; CHECK: [[bb1]] = OpLabel +; CHECK-NEXT: [[inc_i:%\w+]] = OpIAdd %int [[phi_i]] %int_1 +; CHECK-NEXT: OpBranch [[sel_merge]] +; CHECK: [[sel_merge]] = OpLabel +; CHECK: OpBranch [[if_merge]] ; Loop specialized for true. ; CHECK: [[loop_t]] = OpLabel @@ -78,13 +78,18 @@ TEST_F(UnswitchTest, SimpleUnswitch) { ; CHECK-NEXT: [[phi_j:%\w+]] = OpPhi %int %int_0 [[loop_t]] [[iv_j:%\w+]] [[continue]] ; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] [[continue]] None ; CHECK: [[loop_exit:%\w+]] = OpSLessThan {{%\w+}} [[phi_i]] {{%\w+}} -; CHECK-NEXT: OpBranchConditional [[loop_exit]] {{%\w+}} [[merge]] -; Check that we have i+=2 and j+=1. -; CHECK: [[phi_i:%\w+]] = OpIAdd %int [[phi_i]] %int_1 -; CHECK: [[iv_i]] = OpIAdd %int [[phi_i]] %int_1 -; CHECK: [[iv_j]] = OpIAdd %int [[phi_j]] %int_1 -; CHECK: [[merge]] = OpLabel -; CHECK-NEXT: OpBranch [[if_merge]] +; CHECK-NEXT: OpBranchConditional [[loop_exit]] [[loop_body:%\w+]] [[merge]] +; [[loop_body]] = OpLabel +; CHECK: OpSelectionMerge [[sel_merge:%\w+]] None +; CHECK: OpBranchConditional %true [[bb1:%\w+]] [[bb2:%\w+]] +; CHECK: [[bb1]] = OpLabel +; CHECK-NEXT: [[inc_i:%\w+]] = OpIAdd %int [[phi_i]] %int_1 +; CHECK-NEXT: OpBranch [[sel_merge]] +; CHECK: [[bb2]] = OpLabel +; CHECK-NEXT: [[inc_j:%\w+]] = OpIAdd %int [[phi_j]] %int_1 +; CHECK-NEXT: OpBranch [[sel_merge]] +; CHECK: [[sel_merge]] = OpLabel +; CHECK: OpBranch [[if_merge]] ; CHECK: [[if_merge]] = OpLabel ; CHECK-NEXT: OpReturn @@ -292,10 +297,10 @@ TEST_F(UnswitchTest, UnswitchContinue) { ; CHECK-NEXT: [[phi_i:%\w+]] = OpPhi %int %int_0 [[loop_f]] [[iv_i:%\w+]] [[continue:%\w+]] ; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] [[continue]] None ; CHECK: [[loop_exit:%\w+]] = OpSLessThan {{%\w+}} [[phi_i]] {{%\w+}} -; CHECK-NEXT: OpBranchConditional [[loop_exit]] {{%\w+}} [[merge]] -; Check that we have i+=2. -; CHECK: [[phi_i:%\w+]] = OpIAdd %int [[phi_i]] %int_1 -; CHECK: [[iv_i]] = OpIAdd %int [[phi_i]] %int_1 +; CHECK-NEXT: OpBranchConditional [[loop_exit]] [[loop_body:%\w+]] [[merge]] +; CHECK: [[loop_body:%\w+]] = OpLabel +; CHECK-NEXT: OpSelectionMerge +; CHECK-NEXT: OpBranchConditional %false ; CHECK: [[merge]] = OpLabel ; CHECK-NEXT: OpBranch [[if_merge]] @@ -306,9 +311,10 @@ TEST_F(UnswitchTest, UnswitchContinue) { ; CHECK-NEXT: [[phi_i:%\w+]] = OpPhi %int %int_0 [[loop_t]] [[iv_i:%\w+]] [[continue:%\w+]] ; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] [[continue]] None ; CHECK: [[loop_exit:%\w+]] = OpSLessThan {{%\w+}} [[phi_i]] {{%\w+}} -; CHECK-NEXT: OpBranchConditional [[loop_exit]] {{%\w+}} [[merge]] -; Check that we have i+=1. -; CHECK: [[iv_i]] = OpIAdd %int [[phi_i]] %int_1 +; CHECK-NEXT: OpBranchConditional [[loop_exit]] [[loop_body:%\w+]] [[merge]] +; CHECK: [[loop_body:%\w+]] = OpLabel +; CHECK-NEXT: OpSelectionMerge +; CHECK-NEXT: OpBranchConditional %true ; CHECK: [[merge]] = OpLabel ; CHECK-NEXT: OpBranch [[if_merge]] @@ -519,18 +525,40 @@ TEST_F(UnswitchTest, UnswitchSwitch) { ; CHECK-NEXT: [[phi_i:%\w+]] = OpPhi %int %int_0 [[loop_2]] [[iv_i:%\w+]] [[continue:%\w+]] ; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] [[continue]] None ; CHECK: [[loop_exit:%\w+]] = OpSLessThan {{%\w+}} [[phi_i]] {{%\w+}} -; CHECK-NEXT: OpBranchConditional [[loop_exit]] {{%\w+}} [[merge]] -; Check that we have i+=1. -; CHECK: [[iv_i]] = OpIAdd %int [[phi_i]] %int_1 -; CHECK: OpBranch [[loop]] +; CHECK-NEXT: OpBranchConditional [[loop_exit]] [[loop_body:%\w+]] [[merge]] +; CHECK: [[loop_body]] = OpLabel +; CHECK-NEXT: OpSelectionMerge +; CHECK-NEXT: OpSwitch %int_2 +; CHECK: [[merge]] = OpLabel +; CHECK-NEXT: OpBranch [[if_merge]] ; Loop specialized for 1. ; CHECK: [[loop_1]] = OpLabel -; CHECK: OpKill +; CHECK-NEXT: OpBranch [[loop:%\w+]] +; CHECK: [[loop]] = OpLabel +; CHECK-NEXT: [[phi_i:%\w+]] = OpPhi %int %int_0 [[loop_1]] [[iv_i:%\w+]] [[continue:%\w+]] +; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] [[continue]] None +; CHECK: [[loop_exit:%\w+]] = OpSLessThan {{%\w+}} [[phi_i]] {{%\w+}} +; CHECK-NEXT: OpBranchConditional [[loop_exit]] [[loop_body:%\w+]] [[merge]] +; CHECK: [[loop_body]] = OpLabel +; CHECK-NEXT: OpSelectionMerge +; CHECK-NEXT: OpSwitch %int_1 +; CHECK: [[merge]] = OpLabel +; CHECK-NEXT: OpBranch [[if_merge]] ; Loop specialized for 0. ; CHECK: [[loop_0]] = OpLabel -; CHECK: OpReturn +; CHECK-NEXT: OpBranch [[loop:%\w+]] +; CHECK: [[loop]] = OpLabel +; CHECK-NEXT: [[phi_i:%\w+]] = OpPhi %int %int_0 [[loop_0]] [[iv_i:%\w+]] [[continue:%\w+]] +; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] [[continue]] None +; CHECK: [[loop_exit:%\w+]] = OpSLessThan {{%\w+}} [[phi_i]] {{%\w+}} +; CHECK-NEXT: OpBranchConditional [[loop_exit]] [[loop_body:%\w+]] [[merge]] +; CHECK: [[loop_body]] = OpLabel +; CHECK-NEXT: OpSelectionMerge +; CHECK-NEXT: OpSwitch %int_0 +; CHECK: [[merge]] = OpLabel +; CHECK-NEXT: OpBranch [[if_merge]] ; Loop specialized for the default case. ; CHECK: [[default]] = OpLabel @@ -539,10 +567,12 @@ TEST_F(UnswitchTest, UnswitchSwitch) { ; CHECK-NEXT: [[phi_i:%\w+]] = OpPhi %int %int_0 [[default]] [[iv_i:%\w+]] [[continue:%\w+]] ; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] [[continue]] None ; CHECK: [[loop_exit:%\w+]] = OpSLessThan {{%\w+}} [[phi_i]] {{%\w+}} -; CHECK-NEXT: OpBranchConditional [[loop_exit]] {{%\w+}} [[merge]] -; Check that we have i+=1. -; CHECK: [[phi_i:%\w+]] = OpIAdd %int [[phi_i]] %int_1 -; CHECK: OpBranch [[loop]] +; CHECK-NEXT: OpBranchConditional [[loop_exit]] [[loop_body:%\w+]] [[merge]] +; CHECK: [[loop_body]] = OpLabel +; CHECK-NEXT: OpSelectionMerge +; CHECK-NEXT: OpSwitch %uint_3 +; CHECK: [[merge]] = OpLabel +; CHECK-NEXT: OpBranch [[if_merge]] ; CHECK: [[if_merge]] = OpLabel ; CHECK-NEXT: OpReturn @@ -628,90 +658,51 @@ void main() { } } } - for (; k < 10; k++) { - if (cond) { - k++; - } - } } */ TEST_F(UnswitchTest, UnSwitchNested) { + // Test that an branch can be unswitched out of two nested loops. const std::string text = R"( ; CHECK: [[cst_cond:%\w+]] = OpFOrdEqual ; CHECK-NEXT: OpSelectionMerge [[if_merge:%\w+]] None ; CHECK-NEXT: OpBranchConditional [[cst_cond]] [[loop_t:%\w+]] [[loop_f:%\w+]] -; Loop specialized for false, one loop is killed, j won't change anymore. +; Loop specialized for false ; CHECK: [[loop_f]] = OpLabel ; CHECK-NEXT: OpBranch [[loop:%\w+]] ; CHECK: [[loop]] = OpLabel -; CHECK-NEXT: [[phi_i:%\w+]] = OpPhi %int %int_0 [[loop_f]] [[iv_i:%\w+]] [[continue:%\w+]] -; CHECK-NEXT: [[phi_j:%\w+]] = OpPhi %int %int_0 [[loop_f]] [[iv_j:%\w+]] [[continue]] +; CHECK-NEXT: {{%\w+}} = OpPhi %int %int_0 [[loop_f]] {{%\w+}} [[continue:%\w+]] +; CHECK-NEXT: {{%\w+}} = OpPhi %int %int_0 [[loop_f]] {{%\w+}} [[continue]] ; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] [[continue]] None -; CHECK: [[iv_i]] = OpIAdd %int [[phi_i]] %int_1 -; CHECK-NEXT: OpBranch [[loop]] -; CHECK: OpReturn +; CHECK-NOT: [[merge]] = OpLabel +; CHECK: OpLoopMerge +; CHECK-NEXT: OpBranch [[bb1:%\w+]] +; CHECK: [[bb1]] = OpLabel +; CHECK-NEXT: OpSLessThan +; CHECK-NEXT: OpBranchConditional {{%\w+}} [[bb2:%\w+]] +; CHECK: [[bb2]] = OpLabel +; CHECK-NEXT: OpSelectionMerge +; CHECK-NEXT: OpBranchConditional %false +; CHECK: [[merge]] = OpLabel -; Loop specialized for true. +; Loop specialized for true. Same as first loop except the branch condition is true. ; CHECK: [[loop_t]] = OpLabel ; CHECK-NEXT: OpBranch [[loop:%\w+]] ; CHECK: [[loop]] = OpLabel -; CHECK-NEXT: [[phi_i:%\w+]] = OpPhi %int %int_0 [[loop_t]] [[iv_i:%\w+]] [[continue:%\w+]] -; CHECK-NEXT: [[phi_j:%\w+]] = OpPhi %int %int_0 [[loop_t]] [[iv_j:%\w+]] [[continue]] +; CHECK-NEXT: {{%\w+}} = OpPhi %int %int_0 [[loop_t]] {{%\w+}} [[continue:%\w+]] +; CHECK-NEXT: {{%\w+}} = OpPhi %int %int_0 [[loop_t]] {{%\w+}} [[continue]] ; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] [[continue]] None -; CHECK: [[loop_exit:%\w+]] = OpSLessThan {{%\w+}} [[phi_i]] {{%\w+}} -; CHECK-NEXT: OpBranchConditional [[loop_exit]] [[pre_loop_inner:%\w+]] [[merge]] - -; CHECK: [[pre_loop_inner]] = OpLabel -; CHECK-NEXT: OpBranch [[loop_inner:%\w+]] -; CHECK-NEXT: [[loop_inner]] = OpLabel -; CHECK-NEXT: [[phi2_i:%\w+]] = OpPhi %int [[phi_i]] [[pre_loop_inner]] [[iv2_i:%\w+]] [[continue2:%\w+]] -; CHECK-NEXT: [[phi2_j:%\w+]] = OpPhi %int [[phi_j]] [[pre_loop_inner]] [[iv2_j:%\w+]] [[continue2]] -; CHECK-NEXT: OpLoopMerge [[merge2:%\w+]] [[continue2]] None - -; CHECK: OpBranch [[continue2]] -; CHECK: [[merge2]] = OpLabel -; CHECK: OpBranch [[continue]] +; CHECK-NOT: [[merge]] = OpLabel +; CHECK: OpLoopMerge +; CHECK-NEXT: OpBranch [[bb1:%\w+]] +; CHECK: [[bb1]] = OpLabel +; CHECK-NEXT: OpSLessThan +; CHECK-NEXT: OpBranchConditional {{%\w+}} [[bb2:%\w+]] +; CHECK: [[bb2]] = OpLabel +; CHECK-NEXT: OpSelectionMerge +; CHECK-NEXT: OpBranchConditional %true ; CHECK: [[merge]] = OpLabel -; Unswitched double nested loop is done. Test the single remaining one. - -; CHECK: [[if_merge]] = OpLabel -; CHECK-NEXT: OpSelectionMerge [[if_merge:%\w+]] None -; CHECK-NEXT: OpBranchConditional [[cst_cond]] [[loop_t:%\w+]] [[loop_f:%\w+]] - -; Loop specialized for false. -; CHECK: [[loop_f]] = OpLabel -; CHECK-NEXT: OpBranch [[loop:%\w+]] -; CHECK: [[loop]] = OpLabel -; CHECK-NEXT: [[phi_k:%\w+]] = OpPhi %int %int_0 [[loop_f]] [[iv_k:%\w+]] [[continue:%\w+]] -; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] [[continue]] None -; CHECK: [[loop_exit:%\w+]] = OpSLessThan {{%\w+}} [[phi_k]] {{%\w+}} -; CHECK-NEXT: OpBranchConditional [[loop_exit]] {{%\w+}} [[merge]] -; Check that we have k+=1 -; CHECK: [[iv_k]] = OpIAdd %int [[phi_k]] %int_1 -; CHECK: OpBranch [[loop]] -; CHECK: [[merge]] = OpLabel -; CHECK-NEXT: OpBranch [[if_merge]] - -; Loop specialized for true. -; CHECK: [[loop_t]] = OpLabel -; CHECK-NEXT: OpBranch [[loop:%\w+]] -; CHECK: [[loop]] = OpLabel -; CHECK-NEXT: [[phi_k:%\w+]] = OpPhi %int %int_0 [[loop_t]] [[iv_k:%\w+]] [[continue:%\w+]] -; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] [[continue]] None -; CHECK: [[loop_exit:%\w+]] = OpSLessThan {{%\w+}} [[phi_k]] {{%\w+}} -; CHECK-NEXT: OpBranchConditional [[loop_exit]] {{%\w+}} [[merge]] -; Check that we have k+=2. -; CHECK: [[tmp_k:%\w+]] = OpIAdd %int [[phi_k]] %int_1 -; CHECK: [[iv_k]] = OpIAdd %int [[tmp_k]] %int_1 -; CHECK: OpBranch [[loop]] -; CHECK: [[merge]] = OpLabel -; CHECK-NEXT: OpBranch [[if_merge]] - -; CHECK: [[if_merge]] = OpLabel -; CHECK-NEXT: OpReturn - OpCapability Shader %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 @@ -782,34 +773,12 @@ TEST_F(UnswitchTest, UnSwitchNested) { %52 = OpIAdd %int %69 %int_1 OpBranch %26 %28 = OpLabel - OpBranch %53 - %53 = OpLabel - %71 = OpPhi %int %int_0 %28 %66 %56 - OpLoopMerge %55 %56 None - OpBranch %57 - %57 = OpLabel - %59 = OpSLessThan %bool %71 %int_10 - OpBranchConditional %59 %54 %55 - %54 = OpLabel - OpSelectionMerge %62 None - OpBranchConditional %25 %61 %62 - %61 = OpLabel - %64 = OpIAdd %int %71 %int_1 - OpBranch %62 - %62 = OpLabel - %72 = OpPhi %int %71 %54 %64 %61 - OpBranch %56 - %56 = OpLabel - %66 = OpIAdd %int %72 %int_1 - OpBranch %53 - %55 = OpLabel OpReturn OpFunctionEnd )"; SinglePassRunAndMatch(text, true); } -#endif // SPIRV_EFFCEE /* Generated from the following GLSL + --eliminate-local-multi-store @@ -912,6 +881,87 @@ TEST_F(UnswitchTest, UnswitchNotUniform) { EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)); } +TEST_F(UnswitchTest, DontUnswitchLatch) { + // Check that the unswitch is not triggered for the latch branch. + const std::string text = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %bool = OpTypeBool +%false = OpConstantFalse %bool + %4 = OpFunction %void None %3 + %5 = OpLabel + OpBranch %6 + %6 = OpLabel + OpLoopMerge %8 %9 None + OpBranch %7 + %7 = OpLabel + OpBranch %9 + %9 = OpLabel + OpBranchConditional %false %6 %8 + %8 = OpLabel + OpReturn + OpFunctionEnd + )"; + + auto result = + SinglePassRunAndDisassemble(text, true, false); + EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)); +} + +TEST_F(UnswitchTest, DontUnswitchConstantCondition) { + const std::string text = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" + OpExecutionMode %main OriginLowerLeft + OpSource GLSL 450 + OpName %main "main" + %void = OpTypeVoid + %4 = OpTypeFunction %void + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 + %bool = OpTypeBool + %true = OpConstantTrue %bool + %int_1 = OpConstant %int 1 + %main = OpFunction %void None %4 + %10 = OpLabel + OpBranch %11 + %11 = OpLabel + %12 = OpPhi %int %int_0 %10 %13 %14 + OpLoopMerge %15 %14 None + OpBranch %16 + %16 = OpLabel + %17 = OpSLessThan %bool %12 %int_1 + OpBranchConditional %17 %18 %15 + %18 = OpLabel + OpSelectionMerge %19 None + OpBranchConditional %true %20 %19 + %20 = OpLabel + %21 = OpIAdd %int %12 %int_1 + OpBranch %19 + %19 = OpLabel + %22 = OpPhi %int %21 %20 %12 %18 + OpBranch %14 + %14 = OpLabel + %13 = OpIAdd %int %22 %int_1 + OpBranch %11 + %15 = OpLabel + OpReturn + OpFunctionEnd + )"; + + auto result = + SinglePassRunAndDisassemble(text, true, false); + EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)); +} + } // namespace } // namespace opt } // namespace spvtools diff --git a/third_party/spirv-tools/test/opt/module_test.cpp b/third_party/spirv-tools/test/opt/module_test.cpp index c4f450ea95..406da0939f 100644 --- a/third_party/spirv-tools/test/opt/module_test.cpp +++ b/third_party/spirv-tools/test/opt/module_test.cpp @@ -21,6 +21,7 @@ #include "gtest/gtest.h" #include "source/opt/build_module.h" #include "source/opt/module.h" +#include "source/opt/pass.h" #include "spirv-tools/libspirv.hpp" #include "test/opt/module_utils.h" @@ -139,6 +140,161 @@ OpFunctionEnd)"; EXPECT_EQ(text, str.str()); } +TEST(ModuleTest, IdBoundTestAtLimit) { + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%1 = OpTypeVoid +%2 = OpTypeFunction %1 +%3 = OpFunction %1 None %2 +%4 = OpLabel +OpReturn +OpFunctionEnd)"; + + std::unique_ptr context = BuildModule(text); + uint32_t current_bound = context->module()->id_bound(); + context->set_max_id_bound(current_bound); + uint32_t next_id_bound = context->module()->TakeNextIdBound(); + EXPECT_EQ(next_id_bound, 0); + EXPECT_EQ(current_bound, context->module()->id_bound()); + next_id_bound = context->module()->TakeNextIdBound(); + EXPECT_EQ(next_id_bound, 0); +} + +TEST(ModuleTest, IdBoundTestBelowLimit) { + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%1 = OpTypeVoid +%2 = OpTypeFunction %1 +%3 = OpFunction %1 None %2 +%4 = OpLabel +OpReturn +OpFunctionEnd)"; + + std::unique_ptr context = BuildModule(text); + uint32_t current_bound = context->module()->id_bound(); + context->set_max_id_bound(current_bound + 100); + uint32_t next_id_bound = context->module()->TakeNextIdBound(); + EXPECT_EQ(next_id_bound, current_bound); + EXPECT_EQ(current_bound + 1, context->module()->id_bound()); + next_id_bound = context->module()->TakeNextIdBound(); + EXPECT_EQ(next_id_bound, current_bound + 1); +} + +TEST(ModuleTest, IdBoundTestNearLimit) { + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%1 = OpTypeVoid +%2 = OpTypeFunction %1 +%3 = OpFunction %1 None %2 +%4 = OpLabel +OpReturn +OpFunctionEnd)"; + + std::unique_ptr context = BuildModule(text); + uint32_t current_bound = context->module()->id_bound(); + context->set_max_id_bound(current_bound + 1); + uint32_t next_id_bound = context->module()->TakeNextIdBound(); + EXPECT_EQ(next_id_bound, current_bound); + EXPECT_EQ(current_bound + 1, context->module()->id_bound()); + next_id_bound = context->module()->TakeNextIdBound(); + EXPECT_EQ(next_id_bound, 0); +} + +TEST(ModuleTest, IdBoundTestUIntMax) { + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%1 = OpTypeVoid +%2 = OpTypeFunction %1 +%3 = OpFunction %1 None %2 +%4294967294 = OpLabel ; ID is UINT_MAX-1 +OpReturn +OpFunctionEnd)"; + + std::unique_ptr context = BuildModule(text); + uint32_t current_bound = context->module()->id_bound(); + + // Expecting |BuildModule| to preserve the numeric ids. + EXPECT_EQ(current_bound, std::numeric_limits::max()); + + context->set_max_id_bound(current_bound); + uint32_t next_id_bound = context->module()->TakeNextIdBound(); + EXPECT_EQ(next_id_bound, 0); + EXPECT_EQ(current_bound, context->module()->id_bound()); +} + +// Tests that "text" does not change when it is assembled, converted into a +// module, converted back to a binary, and then disassembled. +void AssembleAndDisassemble(const std::string& text) { + std::unique_ptr context = BuildModule(text); + std::vector binary; + + context->module()->ToBinary(&binary, false); + + SpirvTools tools(SPV_ENV_UNIVERSAL_1_1); + std::string s; + tools.Disassemble(binary, &s); + EXPECT_EQ(s, text); +} + +TEST(ModuleTest, TrailingOpLine) { + const std::string text = R"(OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%5 = OpString "file.ext" +%void = OpTypeVoid +%2 = OpTypeFunction %void +%3 = OpFunction %void None %2 +%4 = OpLabel +OpReturn +OpFunctionEnd +OpLine %5 1 0 +)"; + + AssembleAndDisassemble(text); +} + +TEST(ModuleTest, TrailingOpNoLine) { + const std::string text = R"(OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%2 = OpTypeFunction %void +%3 = OpFunction %void None %2 +%4 = OpLabel +OpReturn +OpFunctionEnd +OpNoLine +)"; + + AssembleAndDisassemble(text); +} + +TEST(ModuleTest, MulitpleTrailingOpLine) { + const std::string text = R"(OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%5 = OpString "file.ext" +%void = OpTypeVoid +%2 = OpTypeFunction %void +%3 = OpFunction %void None %2 +%4 = OpLabel +OpReturn +OpFunctionEnd +OpLine %5 1 0 +OpNoLine +OpLine %5 1 1 +)"; + + AssembleAndDisassemble(text); +} } // namespace } // namespace opt } // namespace spvtools diff --git a/third_party/spirv-tools/test/opt/optimizer_test.cpp b/third_party/spirv-tools/test/opt/optimizer_test.cpp index 90abc00d0d..945aa78265 100644 --- a/third_party/spirv-tools/test/opt/optimizer_test.cpp +++ b/third_party/spirv-tools/test/opt/optimizer_test.cpp @@ -163,7 +163,6 @@ TEST(Optimizer, CanRegisterPassesFromFlags) { "--eliminate-dead-branches", "--eliminate-dead-functions", "--eliminate-local-multi-store", - "--eliminate-common-uniform", "--eliminate-dead-const", "--eliminate-dead-inserts", "--eliminate-dead-variables", @@ -222,6 +221,547 @@ TEST(Optimizer, CanRegisterPassesFromFlags) { EXPECT_EQ(msg_level, SPV_MSG_ERROR); } +TEST(Optimizer, VulkanToWebGPUSetsCorrectPasses) { + Optimizer opt(SPV_ENV_VULKAN_1_1); + opt.RegisterVulkanToWebGPUPasses(); + std::vector pass_names = opt.GetPassNames(); + + std::vector registered_passes; + for (auto name = pass_names.begin(); name != pass_names.end(); ++name) + registered_passes.push_back(*name); + + std::vector expected_passes = {"eliminate-dead-branches", + "eliminate-dead-code-aggressive", + "eliminate-dead-const", + "flatten-decorations", + "strip-atomic-counter-memory", + "generate-webgpu-initializers", + "legalize-vector-shuffle", + "split-invalid-unreachable", + "compact-ids"}; + std::sort(registered_passes.begin(), registered_passes.end()); + std::sort(expected_passes.begin(), expected_passes.end()); + + ASSERT_EQ(registered_passes.size(), expected_passes.size()); + for (size_t i = 0; i < registered_passes.size(); i++) + EXPECT_EQ(registered_passes[i], expected_passes[i]); +} + +struct VulkanToWebGPUPassCase { + // Input SPIR-V + std::string input; + // Expected result SPIR-V + std::string expected; + // Specific pass under test, used for logging messages. + std::string pass; +}; + +using VulkanToWebGPUPassTest = + PassTest<::testing::TestWithParam>; + +TEST_P(VulkanToWebGPUPassTest, Ran) { + std::vector binary; + { + SpirvTools tools(SPV_ENV_VULKAN_1_1); + tools.Assemble(GetParam().input, &binary); + } + + Optimizer opt(SPV_ENV_VULKAN_1_1); + opt.RegisterVulkanToWebGPUPasses(); + + std::vector optimized; + class ValidatorOptions validator_options; + ASSERT_TRUE(opt.Run(binary.data(), binary.size(), &optimized, + validator_options, true)) + << GetParam().input << "\n"; + std::string disassembly; + { + SpirvTools tools(SPV_ENV_WEBGPU_0); + tools.Disassemble(optimized.data(), optimized.size(), &disassembly); + } + + EXPECT_EQ(GetParam().expected, disassembly) + << "Was expecting pass '" << GetParam().pass << "' to have been run.\n"; +} + +INSTANTIATE_TEST_SUITE_P( + Optimizer, VulkanToWebGPUPassTest, + ::testing::ValuesIn(std::vector{ + // FlattenDecorations + {// input + "OpCapability Shader\n" + "OpCapability VulkanMemoryModel\n" + "OpExtension \"SPV_KHR_vulkan_memory_model\"\n" + "OpMemoryModel Logical Vulkan\n" + "OpEntryPoint Fragment %main \"main\" %hue %saturation %value\n" + "OpExecutionMode %main OriginUpperLeft\n" + "OpDecorate %group Flat\n" + "OpDecorate %group NoPerspective\n" + "%group = OpDecorationGroup\n" + "%void = OpTypeVoid\n" + "%void_fn = OpTypeFunction %void\n" + "%float = OpTypeFloat 32\n" + "%_ptr_Input_float = OpTypePointer Input %float\n" + "%hue = OpVariable %_ptr_Input_float Input\n" + "%saturation = OpVariable %_ptr_Input_float Input\n" + "%value = OpVariable %_ptr_Input_float Input\n" + "%main = OpFunction %void None %void_fn\n" + "%entry = OpLabel\n" + "OpReturn\n" + "OpFunctionEnd\n", + // expected + "OpCapability Shader\n" + "OpCapability VulkanMemoryModel\n" + "OpExtension \"SPV_KHR_vulkan_memory_model\"\n" + "OpMemoryModel Logical Vulkan\n" + "OpEntryPoint Fragment %1 \"main\" %2 %3 %4\n" + "OpExecutionMode %1 OriginUpperLeft\n" + "%void = OpTypeVoid\n" + "%6 = OpTypeFunction %void\n" + "%float = OpTypeFloat 32\n" + "%_ptr_Input_float = OpTypePointer Input %float\n" + "%2 = OpVariable %_ptr_Input_float Input\n" + "%3 = OpVariable %_ptr_Input_float Input\n" + "%4 = OpVariable %_ptr_Input_float Input\n" + "%1 = OpFunction %void None %6\n" + "%9 = OpLabel\n" + "OpReturn\n" + "OpFunctionEnd\n", + // pass + "flatten-decorations"}, + // Eliminate Dead Constants + {// input + "OpCapability Shader\n" + "OpCapability VulkanMemoryModel\n" + "OpExtension \"SPV_KHR_vulkan_memory_model\"\n" + "OpMemoryModel Logical Vulkan\n" + "OpEntryPoint Vertex %func \"shader\"\n" + "%u32 = OpTypeInt 32 0\n" + "%u32_ptr = OpTypePointer Workgroup %u32\n" + "%u32_var = OpVariable %u32_ptr Workgroup\n" + "%u32_1 = OpConstant %u32 1\n" + "%cross_device = OpConstant %u32 0\n" + "%relaxed = OpConstant %u32 0\n" + "%acquire_release_atomic_counter_workgroup = OpConstant %u32 1288\n" + "%void = OpTypeVoid\n" + "%void_f = OpTypeFunction %void\n" + "%func = OpFunction %void None %void_f\n" + "%label = OpLabel\n" + "OpReturn\n" + "OpFunctionEnd\n", + // expected + "OpCapability Shader\n" + "OpCapability VulkanMemoryModel\n" + "OpExtension \"SPV_KHR_vulkan_memory_model\"\n" + "OpMemoryModel Logical Vulkan\n" + "OpEntryPoint Vertex %1 \"shader\"\n" + "%uint = OpTypeInt 32 0\n" + "%_ptr_Workgroup_uint = OpTypePointer Workgroup %uint\n" + "%4 = OpVariable %_ptr_Workgroup_uint Workgroup\n" + "%void = OpTypeVoid\n" + "%6 = OpTypeFunction %void\n" + "%1 = OpFunction %void None %6\n" + "%7 = OpLabel\n" + "OpReturn\n" + "OpFunctionEnd\n", + "eliminate-dead-const"}, + // Strip Atomic Counter Memory + {// input + "OpCapability Shader\n" + "OpCapability VulkanMemoryModel\n" + "OpExtension \"SPV_KHR_vulkan_memory_model\"\n" + "OpMemoryModel Logical Vulkan\n" + "OpEntryPoint Vertex %func \"shader\"\n" + "%u32 = OpTypeInt 32 0\n" + "%u32_ptr = OpTypePointer Workgroup %u32\n" + "%u32_var = OpVariable %u32_ptr Workgroup\n" + "%u32_0 = OpConstant %u32 0\n" + "%u32_1 = OpConstant %u32 1\n" + "%cross_device = OpConstant %u32 0\n" + "%acquire_release_atomic_counter_workgroup = OpConstant %u32 1288\n" + "%void = OpTypeVoid\n" + "%void_f = OpTypeFunction %void\n" + "%func = OpFunction %void None %void_f\n" + "%label = OpLabel\n" + " OpAtomicStore %u32_var %cross_device " + "%acquire_release_atomic_counter_workgroup %u32_1\n" + "%val1 = OpAtomicIIncrement %u32 %u32_var %cross_device " + "%acquire_release_atomic_counter_workgroup\n" + "%val2 = OpAtomicCompareExchange %u32 %u32_var %cross_device " + "%acquire_release_atomic_counter_workgroup " + "%acquire_release_atomic_counter_workgroup %u32_0 %u32_0\n" + "OpReturn\n" + "OpFunctionEnd\n", + // expected + "OpCapability Shader\n" + "OpCapability VulkanMemoryModel\n" + "OpExtension \"SPV_KHR_vulkan_memory_model\"\n" + "OpMemoryModel Logical Vulkan\n" + "OpEntryPoint Vertex %1 \"shader\"\n" + "%uint = OpTypeInt 32 0\n" + "%_ptr_Workgroup_uint = OpTypePointer Workgroup %uint\n" + "%4 = OpVariable %_ptr_Workgroup_uint Workgroup\n" + "%uint_0 = OpConstant %uint 0\n" + "%uint_1 = OpConstant %uint 1\n" + "%uint_0_0 = OpConstant %uint 0\n" + "%void = OpTypeVoid\n" + "%9 = OpTypeFunction %void\n" + "%uint_264 = OpConstant %uint 264\n" + "%1 = OpFunction %void None %9\n" + "%11 = OpLabel\n" + "OpAtomicStore %4 %uint_0_0 %uint_264 %uint_1\n" + "%12 = OpAtomicIIncrement %uint %4 %uint_0_0 %uint_264\n" + "%13 = OpAtomicCompareExchange %uint %4 %uint_0_0 %uint_264 %uint_264 " + "%uint_0 %uint_0\n" + "OpReturn\n" + "OpFunctionEnd\n", + // pass + "strip-atomic-counter-memory"}, + // Generate WebGPU Initializers + {// input + "OpCapability Shader\n" + "OpCapability VulkanMemoryModel\n" + "OpExtension \"SPV_KHR_vulkan_memory_model\"\n" + "OpMemoryModel Logical Vulkan\n" + "OpEntryPoint Vertex %func \"shader\"\n" + "%u32 = OpTypeInt 32 0\n" + "%u32_ptr = OpTypePointer Private %u32\n" + "%u32_var = OpVariable %u32_ptr Private\n" + "%u32_0 = OpConstant %u32 0\n" + "%void = OpTypeVoid\n" + "%void_f = OpTypeFunction %void\n" + "%func = OpFunction %void None %void_f\n" + "%label = OpLabel\n" + "OpStore %u32_var %u32_0\n" + "OpReturn\n" + "OpFunctionEnd\n", + // expected + "OpCapability Shader\n" + "OpCapability VulkanMemoryModel\n" + "OpExtension \"SPV_KHR_vulkan_memory_model\"\n" + "OpMemoryModel Logical Vulkan\n" + "OpEntryPoint Vertex %1 \"shader\"\n" + "%uint = OpTypeInt 32 0\n" + "%_ptr_Private_uint = OpTypePointer Private %uint\n" + "%4 = OpConstantNull %uint\n" + "%5 = OpVariable %_ptr_Private_uint Private %4\n" + "%uint_0 = OpConstant %uint 0\n" + "%void = OpTypeVoid\n" + "%8 = OpTypeFunction %void\n" + "%1 = OpFunction %void None %8\n" + "%9 = OpLabel\n" + "OpStore %5 %uint_0\n" + "OpReturn\n" + "OpFunctionEnd\n", + // pass + "generate-webgpu-initializers"}, + // Legalize Vector Shuffle + {// input + "OpCapability Shader\n" + "OpCapability VulkanMemoryModel\n" + "OpExtension \"SPV_KHR_vulkan_memory_model\"\n" + "OpMemoryModel Logical Vulkan\n" + "OpEntryPoint Vertex %1 \"shader\"\n" + "%uint = OpTypeInt 32 0\n" + "%v3uint = OpTypeVector %uint 3\n" + "%_ptr_Function_v3uint = OpTypePointer Function %v3uint\n" + "%void = OpTypeVoid\n" + "%6 = OpTypeFunction %void\n" + "%1 = OpFunction %void None %6\n" + "%7 = OpLabel\n" + "%8 = OpVariable %_ptr_Function_v3uint Function\n" + "%9 = OpLoad %v3uint %8\n" + "%10 = OpLoad %v3uint %8\n" + "%11 = OpVectorShuffle %v3uint %9 %10 2 1 0xFFFFFFFF\n" + "OpReturn\n" + "OpFunctionEnd\n", + // expected + "OpCapability Shader\n" + "OpCapability VulkanMemoryModel\n" + "OpExtension \"SPV_KHR_vulkan_memory_model\"\n" + "OpMemoryModel Logical Vulkan\n" + "OpEntryPoint Vertex %1 \"shader\"\n" + "%uint = OpTypeInt 32 0\n" + "%v3uint = OpTypeVector %uint 3\n" + "%_ptr_Function_v3uint = OpTypePointer Function %v3uint\n" + "%void = OpTypeVoid\n" + "%6 = OpTypeFunction %void\n" + "%7 = OpConstantNull %v3uint\n" + "%1 = OpFunction %void None %6\n" + "%8 = OpLabel\n" + "%9 = OpVariable %_ptr_Function_v3uint Function %7\n" + "%10 = OpLoad %v3uint %9\n" + "%11 = OpLoad %v3uint %9\n" + "%12 = OpVectorShuffle %v3uint %10 %11 2 1 0\n" + "OpReturn\n" + "OpFunctionEnd\n", + // pass + "legalize-vector-shuffle"}, + // Split Invalid Unreachable + {// input + "OpCapability Shader\n" + "OpCapability VulkanMemoryModel\n" + "OpExtension \"SPV_KHR_vulkan_memory_model\"\n" + "OpMemoryModel Logical Vulkan\n" + "OpEntryPoint Vertex %1 \"shader\"\n" + "%uint = OpTypeInt 32 0\n" + "%uint_1 = OpConstant %uint 1\n" + "%uint_2 = OpConstant %uint 2\n" + "%void = OpTypeVoid\n" + "%bool = OpTypeBool\n" + "%7 = OpTypeFunction %void\n" + "%1 = OpFunction %void None %7\n" + "%8 = OpLabel\n" + "OpBranch %9\n" + "%9 = OpLabel\n" + "OpLoopMerge %10 %11 None\n" + "OpBranch %12\n" + "%12 = OpLabel\n" + "%13 = OpSLessThan %bool %uint_1 %uint_2\n" + "OpSelectionMerge %11 None\n" + "OpBranchConditional %13 %14 %15\n" + "%14 = OpLabel\n" + "OpReturn\n" + "%15 = OpLabel\n" + "OpReturn\n" + "%10 = OpLabel\n" + "OpUnreachable\n" + "%11 = OpLabel\n" + "OpBranch %9\n" + "OpFunctionEnd\n", + // expected + "OpCapability Shader\n" + "OpCapability VulkanMemoryModel\n" + "OpExtension \"SPV_KHR_vulkan_memory_model\"\n" + "OpMemoryModel Logical Vulkan\n" + "OpEntryPoint Vertex %1 \"shader\"\n" + "%uint = OpTypeInt 32 0\n" + "%uint_1 = OpConstant %uint 1\n" + "%uint_2 = OpConstant %uint 2\n" + "%void = OpTypeVoid\n" + "%bool = OpTypeBool\n" + "%7 = OpTypeFunction %void\n" + "%1 = OpFunction %void None %7\n" + "%8 = OpLabel\n" + "OpBranch %9\n" + "%9 = OpLabel\n" + "OpLoopMerge %10 %11 None\n" + "OpBranch %12\n" + "%12 = OpLabel\n" + "%13 = OpSLessThan %bool %uint_1 %uint_2\n" + "OpSelectionMerge %14 None\n" + "OpBranchConditional %13 %15 %16\n" + "%15 = OpLabel\n" + "OpReturn\n" + "%16 = OpLabel\n" + "OpReturn\n" + "%10 = OpLabel\n" + "OpUnreachable\n" + "%14 = OpLabel\n" + "OpUnreachable\n" + "%11 = OpLabel\n" + "OpBranch %9\n" + "OpFunctionEnd\n", + // pass + "split-invalid-unreachable"}, + // Compact IDs + {// input + "OpCapability Shader\n" + "OpCapability VulkanMemoryModel\n" + "OpExtension \"SPV_KHR_vulkan_memory_model\"\n" + "OpMemoryModel Logical Vulkan\n" + "OpEntryPoint Vertex %1000 \"shader\"\n" + "%10 = OpTypeVoid\n" + "%100 = OpTypeFunction %10\n" + "%1000 = OpFunction %10 None %100\n" + "%10000 = OpLabel\n" + "OpReturn\n" + "OpFunctionEnd\n", + // expected + "OpCapability Shader\n" + "OpCapability VulkanMemoryModel\n" + "OpExtension \"SPV_KHR_vulkan_memory_model\"\n" + "OpMemoryModel Logical Vulkan\n" + "OpEntryPoint Vertex %1 \"shader\"\n" + "%void = OpTypeVoid\n" + "%3 = OpTypeFunction %void\n" + "%1 = OpFunction %void None %3\n" + "%4 = OpLabel\n" + "OpReturn\n" + "OpFunctionEnd\n", + // pass + "compact-ids"}})); + +TEST(Optimizer, WebGPUToVulkanSetsCorrectPasses) { + Optimizer opt(SPV_ENV_WEBGPU_0); + opt.RegisterWebGPUToVulkanPasses(); + std::vector pass_names = opt.GetPassNames(); + + std::vector registered_passes; + for (auto name = pass_names.begin(); name != pass_names.end(); ++name) + registered_passes.push_back(*name); + + std::vector expected_passes = {"decompose-initialized-variables", + "compact-ids"}; + std::sort(registered_passes.begin(), registered_passes.end()); + std::sort(expected_passes.begin(), expected_passes.end()); + + ASSERT_EQ(registered_passes.size(), expected_passes.size()); + for (size_t i = 0; i < registered_passes.size(); i++) + EXPECT_EQ(registered_passes[i], expected_passes[i]); +} + +struct WebGPUToVulkanPassCase { + // Input SPIR-V + std::string input; + // Expected result SPIR-V + std::string expected; + // Specific pass under test, used for logging messages. + std::string pass; +}; + +using WebGPUToVulkanPassTest = + PassTest<::testing::TestWithParam>; + +TEST_P(WebGPUToVulkanPassTest, Ran) { + std::vector binary; + { + SpirvTools tools(SPV_ENV_WEBGPU_0); + tools.Assemble(GetParam().input, &binary); + } + + Optimizer opt(SPV_ENV_WEBGPU_0); + opt.RegisterWebGPUToVulkanPasses(); + + std::vector optimized; + class ValidatorOptions validator_options; + ASSERT_TRUE(opt.Run(binary.data(), binary.size(), &optimized, + validator_options, true)); + std::string disassembly; + { + SpirvTools tools(SPV_ENV_VULKAN_1_1); + tools.Disassemble(optimized.data(), optimized.size(), &disassembly); + } + + EXPECT_EQ(GetParam().expected, disassembly) + << "Was expecting pass '" << GetParam().pass << "' to have been run.\n"; +} + +INSTANTIATE_TEST_SUITE_P( + Optimizer, WebGPUToVulkanPassTest, + ::testing::ValuesIn(std::vector{ + // Decompose Initialized Variables + {// input + "OpCapability Shader\n" + "OpCapability VulkanMemoryModel\n" + "OpExtension \"SPV_KHR_vulkan_memory_model\"\n" + "OpMemoryModel Logical Vulkan\n" + "OpEntryPoint Vertex %1 \"shader\"\n" + "%uint = OpTypeInt 32 0\n" + "%_ptr_Function_uint = OpTypePointer Function %uint\n" + "%4 = OpConstantNull %uint\n" + "%void = OpTypeVoid\n" + "%6 = OpTypeFunction %void\n" + "%1 = OpFunction %void None %6\n" + "%7 = OpLabel\n" + "%8 = OpVariable %_ptr_Function_uint Function %4\n" + "OpReturn\n" + "OpFunctionEnd\n", + // expected + "OpCapability Shader\n" + "OpCapability VulkanMemoryModel\n" + "OpExtension \"SPV_KHR_vulkan_memory_model\"\n" + "OpMemoryModel Logical Vulkan\n" + "OpEntryPoint Vertex %1 \"shader\"\n" + "%uint = OpTypeInt 32 0\n" + "%_ptr_Function_uint = OpTypePointer Function %uint\n" + "%4 = OpConstantNull %uint\n" + "%void = OpTypeVoid\n" + "%6 = OpTypeFunction %void\n" + "%1 = OpFunction %void None %6\n" + "%7 = OpLabel\n" + "%8 = OpVariable %_ptr_Function_uint Function\n" + "OpStore %8 %4\n" + "OpReturn\n" + "OpFunctionEnd\n", + // pass + "decompose-initialized-variables"}, + // Compact IDs + {// input + "OpCapability Shader\n" + "OpCapability VulkanMemoryModel\n" + "OpExtension \"SPV_KHR_vulkan_memory_model\"\n" + "OpMemoryModel Logical Vulkan\n" + "OpEntryPoint Vertex %1000 \"shader\"\n" + "%10 = OpTypeVoid\n" + "%100 = OpTypeFunction %10\n" + "%1000 = OpFunction %10 None %100\n" + "%10000 = OpLabel\n" + "OpReturn\n" + "OpFunctionEnd\n", + // expected + "OpCapability Shader\n" + "OpCapability VulkanMemoryModel\n" + "OpExtension \"SPV_KHR_vulkan_memory_model\"\n" + "OpMemoryModel Logical Vulkan\n" + "OpEntryPoint Vertex %1 \"shader\"\n" + "%void = OpTypeVoid\n" + "%3 = OpTypeFunction %void\n" + "%1 = OpFunction %void None %3\n" + "%4 = OpLabel\n" + "OpReturn\n" + "OpFunctionEnd\n", + // pass + "compact-ids"}})); + +TEST(Optimizer, RemoveNop) { + // Test that OpNops are removed even if no optimizations are run. + const std::string before = R"(OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%2 = OpTypeFunction %void +%3 = OpFunction %void None %2 +%4 = OpLabel +OpNop +OpReturn +OpFunctionEnd +)"; + + const std::string after = R"(OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%2 = OpTypeFunction %void +%3 = OpFunction %void None %2 +%4 = OpLabel +OpReturn +OpFunctionEnd +)"; + + std::vector binary; + { + SpirvTools tools(SPV_ENV_VULKAN_1_1); + tools.Assemble(before, &binary); + } + + Optimizer opt(SPV_ENV_VULKAN_1_1); + + std::vector optimized; + class ValidatorOptions validator_options; + ASSERT_TRUE(opt.Run(binary.data(), binary.size(), &optimized, + validator_options, true)) + << before << "\n"; + std::string disassembly; + { + SpirvTools tools(SPV_ENV_WEBGPU_0); + tools.Disassemble(optimized.data(), optimized.size(), &disassembly); + } + + EXPECT_EQ(after, disassembly) + << "Was expecting the OpNop to have been removed."; +} + } // namespace } // namespace opt } // namespace spvtools diff --git a/third_party/spirv-tools/test/opt/pass_fixture.h b/third_party/spirv-tools/test/opt/pass_fixture.h index 9d9eb3661c..64c089d886 100644 --- a/third_party/spirv-tools/test/opt/pass_fixture.h +++ b/third_party/spirv-tools/test/opt/pass_fixture.h @@ -22,17 +22,16 @@ #include #include +#include "effcee/effcee.h" #include "gtest/gtest.h" #include "source/opt/build_module.h" #include "source/opt/pass_manager.h" #include "source/opt/passes.h" +#include "source/spirv_optimizer_options.h" +#include "source/spirv_validator_options.h" #include "source/util/make_unique.h" #include "spirv-tools/libspirv.hpp" -#ifdef SPIRV_EFFCEE -#include "effcee/effcee.h" -#endif - namespace spvtools { namespace opt { @@ -47,30 +46,37 @@ template class PassTest : public TestT { public: PassTest() - : consumer_(nullptr), + : consumer_( + [](spv_message_level_t, const char*, const spv_position_t&, + const char* message) { std::cerr << message << std::endl; }), context_(nullptr), - tools_(SPV_ENV_UNIVERSAL_1_1), manager_(new PassManager()), assemble_options_(SpirvTools::kDefaultAssembleOption), - disassemble_options_(SpirvTools::kDefaultDisassembleOption) {} + disassemble_options_(SpirvTools::kDefaultDisassembleOption), + env_(SPV_ENV_UNIVERSAL_1_3) {} // Runs the given |pass| on the binary assembled from the |original|. // Returns a tuple of the optimized binary and the boolean value returned // from pass Process() function. std::tuple, Pass::Status> OptimizeToBinary( Pass* pass, const std::string& original, bool skip_nop) { - context_ = std::move(BuildModule(SPV_ENV_UNIVERSAL_1_1, consumer_, original, - assemble_options_)); + context_ = BuildModule(env_, consumer_, original, assemble_options_); EXPECT_NE(nullptr, context()) << "Assembling failed for shader:\n" << original << std::endl; if (!context()) { return std::make_tuple(std::vector(), Pass::Status::Failure); } + context()->set_preserve_bindings(OptimizerOptions()->preserve_bindings_); + context()->set_preserve_spec_constants( + OptimizerOptions()->preserve_spec_constants_); + const auto status = pass->Run(context()); std::vector binary; - context()->module()->ToBinary(&binary, skip_nop); + if (status != Pass::Status::Failure) { + context()->module()->ToBinary(&binary, skip_nop); + } return std::make_tuple(binary, status); } @@ -97,19 +103,20 @@ class PassTest : public TestT { std::tie(optimized_bin, status) = SinglePassRunToBinary( assembly, skip_nop, std::forward(args)...); if (do_validation) { - spv_target_env target_env = SPV_ENV_UNIVERSAL_1_1; - spv_context spvContext = spvContextCreate(target_env); + spv_context spvContext = spvContextCreate(env_); spv_diagnostic diagnostic = nullptr; spv_const_binary_t binary = {optimized_bin.data(), optimized_bin.size()}; - spv_result_t error = spvValidate(spvContext, &binary, &diagnostic); + spv_result_t error = spvValidateWithOptions( + spvContext, ValidatorOptions(), &binary, &diagnostic); EXPECT_EQ(error, 0); if (error != 0) spvDiagnosticPrint(diagnostic); spvDiagnosticDestroy(diagnostic); spvContextDestroy(spvContext); } std::string optimized_asm; + SpirvTools tools(env_); EXPECT_TRUE( - tools_.Disassemble(optimized_bin, &optimized_asm, disassemble_options_)) + tools.Disassemble(optimized_bin, &optimized_asm, disassemble_options_)) << "Disassembling failed for shader:\n" << assembly << std::endl; return std::make_tuple(optimized_asm, status); @@ -133,19 +140,20 @@ class PassTest : public TestT { EXPECT_EQ(original == expected, status == Pass::Status::SuccessWithoutChange); if (do_validation) { - spv_target_env target_env = SPV_ENV_UNIVERSAL_1_1; - spv_context spvContext = spvContextCreate(target_env); + spv_context spvContext = spvContextCreate(env_); spv_diagnostic diagnostic = nullptr; spv_const_binary_t binary = {optimized_bin.data(), optimized_bin.size()}; - spv_result_t error = spvValidate(spvContext, &binary, &diagnostic); + spv_result_t error = spvValidateWithOptions( + spvContext, ValidatorOptions(), &binary, &diagnostic); EXPECT_EQ(error, 0); if (error != 0) spvDiagnosticPrint(diagnostic); spvDiagnosticDestroy(diagnostic); spvContextDestroy(spvContext); } std::string optimized_asm; + SpirvTools tools(env_); EXPECT_TRUE( - tools_.Disassemble(optimized_bin, &optimized_asm, disassemble_options_)) + tools.Disassemble(optimized_bin, &optimized_asm, disassemble_options_)) << "Disassembling failed for shader:\n" << original << std::endl; EXPECT_EQ(expected, optimized_asm); @@ -163,7 +171,6 @@ class PassTest : public TestT { std::forward(args)...); } -#ifdef SPIRV_EFFCEE // Runs a single pass of class |PassT| on the binary assembled from the // |original| assembly, then runs an Effcee matcher over the disassembled // result, using checks parsed from |original|. Always skips OpNop. @@ -181,7 +188,31 @@ class PassTest : public TestT { << match_result.message() << "\nChecking result:\n" << disassembly; } -#endif + + // Runs a single pass of class |PassT| on the binary assembled from the + // |original| assembly. Check for failure and expect an Effcee matcher + // to pass when run on the diagnostic messages. This does *not* involve + // pass manager. Callers are suggested to use SCOPED_TRACE() for better + // messages. + template + void SinglePassRunAndFail(const std::string& original, Args&&... args) { + context_ = BuildModule(env_, consumer_, original, assemble_options_); + EXPECT_NE(nullptr, context()) << "Assembling failed for shader:\n" + << original << std::endl; + std::ostringstream errs; + auto error_consumer = [&errs](spv_message_level_t, const char*, + const spv_position_t&, const char* message) { + errs << message << std::endl; + }; + auto pass = MakeUnique(std::forward(args)...); + pass->SetMessageConsumer(error_consumer); + const auto status = pass->Run(context()); + EXPECT_EQ(Pass::Status::Failure, status); + auto match_result = effcee::Match(errs.str(), original); + EXPECT_EQ(effcee::Result::Status::Ok, match_result.status()) + << match_result.message() << "\nChecking messages:\n" + << errs.str(); + } // Adds a pass to be run. template @@ -202,18 +233,25 @@ class PassTest : public TestT { void RunAndCheck(const std::string& original, const std::string& expected) { assert(manager_->NumPasses()); - context_ = std::move(BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, original, - assemble_options_)); + context_ = BuildModule(env_, nullptr, original, assemble_options_); ASSERT_NE(nullptr, context()); - manager_->Run(context()); + context()->set_preserve_bindings(OptimizerOptions()->preserve_bindings_); + context()->set_preserve_spec_constants( + OptimizerOptions()->preserve_spec_constants_); - std::vector binary; - context()->module()->ToBinary(&binary, /* skip_nop = */ false); + auto status = manager_->Run(context()); + EXPECT_NE(status, Pass::Status::Failure); - std::string optimized; - EXPECT_TRUE(tools_.Disassemble(binary, &optimized, disassemble_options_)); - EXPECT_EQ(expected, optimized); + if (status != Pass::Status::Failure) { + std::vector binary; + context()->module()->ToBinary(&binary, /* skip_nop = */ false); + + std::string optimized; + SpirvTools tools(env_); + EXPECT_TRUE(tools.Disassemble(binary, &optimized, disassemble_options_)); + EXPECT_EQ(expected, optimized); + } } void SetAssembleOptions(uint32_t assemble_options) { @@ -231,13 +269,21 @@ class PassTest : public TestT { consumer_ = msg_consumer; } + spv_optimizer_options OptimizerOptions() { return &optimizer_options_; } + + spv_validator_options ValidatorOptions() { return &validator_options_; } + + void SetTargetEnv(spv_target_env env) { env_ = env; } + private: - MessageConsumer consumer_; // Message consumer. - std::unique_ptr context_; // IR context - SpirvTools tools_; // An instance for calling SPIRV-Tools functionalities. + MessageConsumer consumer_; // Message consumer. + std::unique_ptr context_; // IR context std::unique_ptr manager_; // The pass manager. uint32_t assemble_options_; uint32_t disassemble_options_; + spv_optimizer_options_t optimizer_options_; + spv_validator_options_t validator_options_; + spv_target_env env_; }; } // namespace opt diff --git a/third_party/spirv-tools/test/opt/pass_manager_test.cpp b/third_party/spirv-tools/test/opt/pass_manager_test.cpp index c7273e9c18..22d5e22ec3 100644 --- a/third_party/spirv-tools/test/opt/pass_manager_test.cpp +++ b/third_party/spirv-tools/test/opt/pass_manager_test.cpp @@ -107,8 +107,7 @@ class DuplicateInstPass : public Pass { public: const char* name() const override { return "DuplicateInst"; } Status Process() override { - auto inst = - MakeUnique(*(--context()->debug1_end())->Clone(context())); + auto inst = MakeUnique(*(--context()->debug1_end())); context()->AddDebug1Inst(std::move(inst)); return Status::SuccessWithChange; } @@ -121,21 +120,21 @@ TEST_F(PassManagerTest, Run) { AddPass(); AddPass(); - RunAndCheck(text.c_str(), (text + "OpNop\nOpNop\n").c_str()); + RunAndCheck(text, text + "OpNop\nOpNop\n"); RenewPassManger(); AddPass(); AddPass(); - RunAndCheck(text.c_str(), (text + "OpNop\nOpNop\n").c_str()); + RunAndCheck(text, text + "OpNop\nOpNop\n"); RenewPassManger(); AddPass(); AddPass(); - RunAndCheck(text.c_str(), (text + "OpSource ESSL 310\nOpNop\n").c_str()); + RunAndCheck(text, text + "OpSource ESSL 310\nOpNop\n"); RenewPassManger(); AddPass(3); - RunAndCheck(text.c_str(), (text + "OpNop\nOpNop\nOpNop\n").c_str()); + RunAndCheck(text, text + "OpNop\nOpNop\nOpNop\n"); } // A pass that appends an OpTypeVoid instruction that uses a given id. diff --git a/third_party/spirv-tools/test/opt/pass_merge_return_test.cpp b/third_party/spirv-tools/test/opt/pass_merge_return_test.cpp index 4dd4b6b285..d16b65c1c3 100644 --- a/third_party/spirv-tools/test/opt/pass_merge_return_test.cpp +++ b/third_party/spirv-tools/test/opt/pass_merge_return_test.cpp @@ -104,6 +104,7 @@ TEST_F(MergeReturnPassTest, TwoReturnsWithValues) { R"(OpCapability Linkage OpCapability Kernel OpMemoryModel Logical OpenCL +OpDecorate %7 LinkageAttributes "simple_kernel" Export %1 = OpTypeInt 32 0 %2 = OpTypeBool %3 = OpConstantFalse %2 @@ -124,6 +125,7 @@ OpFunctionEnd R"(OpCapability Linkage OpCapability Kernel OpMemoryModel Logical OpenCL +OpDecorate %7 LinkageAttributes "simple_kernel" Export %1 = OpTypeInt 32 0 %2 = OpTypeBool %3 = OpConstantFalse %2 @@ -207,6 +209,7 @@ TEST_F(MergeReturnPassTest, UnreachableReturnsWithValues) { R"(OpCapability Linkage OpCapability Kernel OpMemoryModel Logical OpenCL +OpDecorate %7 LinkageAttributes "simple_kernel" Export %1 = OpTypeInt 32 0 %2 = OpTypeBool %3 = OpConstantFalse %2 @@ -230,6 +233,7 @@ OpFunctionEnd R"(OpCapability Linkage OpCapability Kernel OpMemoryModel Logical OpenCL +OpDecorate %7 LinkageAttributes "simple_kernel" Export %1 = OpTypeInt 32 0 %2 = OpTypeBool %3 = OpConstantFalse %2 @@ -257,7 +261,6 @@ OpFunctionEnd SinglePassRunAndCheck(before, after, false, true); } -#ifdef SPIRV_EFFCEE TEST_F(MergeReturnPassTest, StructuredControlFlowWithUnreachableMerge) { const std::string before = R"( @@ -265,15 +268,19 @@ TEST_F(MergeReturnPassTest, StructuredControlFlowWithUnreachableMerge) { ; CHECK: [[true:%\w+]] = OpConstantTrue ; CHECK: OpFunction ; CHECK: [[var:%\w+]] = OpVariable [[:%\w+]] Function [[false]] +; CHECK: OpSelectionMerge [[return_block:%\w+]] ; CHECK: OpSelectionMerge [[merge_lab:%\w+]] ; CHECK: OpBranchConditional [[cond:%\w+]] [[if_lab:%\w+]] [[then_lab:%\w+]] ; CHECK: [[if_lab]] = OpLabel ; CHECK-NEXT: OpStore [[var]] [[true]] -; CHECK-NEXT: OpBranch +; CHECK-NEXT: OpBranch [[return_block]] ; CHECK: [[then_lab]] = OpLabel ; CHECK-NEXT: OpStore [[var]] [[true]] -; CHECK-NEXT: OpBranch [[merge_lab]] -; CHECK: OpReturn +; CHECK-NEXT: OpBranch [[return_block]] +; CHECK: [[merge_lab]] = OpLabel +; CHECK-NEXT: OpBranch [[return_block]] +; CHECK: [[return_block]] = OpLabel +; CHECK-NEXT: OpReturn OpCapability Addresses OpCapability Shader OpCapability Linkage @@ -307,6 +314,7 @@ TEST_F(MergeReturnPassTest, StructuredControlFlowAddPhi) { ; CHECK: [[true:%\w+]] = OpConstantTrue ; CHECK: OpFunction ; CHECK: [[var:%\w+]] = OpVariable [[:%\w+]] Function [[false]] +; CHECK: OpSelectionMerge [[dummy_loop_merge:%\w+]] ; CHECK: OpSelectionMerge [[merge_lab:%\w+]] ; CHECK: OpBranchConditional [[cond:%\w+]] [[if_lab:%\w+]] [[then_lab:%\w+]] ; CHECK: [[if_lab]] = OpLabel @@ -314,11 +322,10 @@ TEST_F(MergeReturnPassTest, StructuredControlFlowAddPhi) { ; CHECK-NEXT: OpBranch ; CHECK: [[then_lab]] = OpLabel ; CHECK-NEXT: OpStore [[var]] [[true]] -; CHECK-NEXT: OpBranch [[merge_lab]] +; CHECK-NEXT: OpBranch [[dummy_loop_merge]] ; CHECK: [[merge_lab]] = OpLabel -; CHECK-NEXT: [[phi:%\w+]] = OpPhi [[type]] [[add]] [[if_lab]] [[undef:%\w+]] [[then_lab]] -; CHECK: OpIAdd [[type]] [[phi]] [[phi]] -; CHECK: OpReturn +; CHECK: [[dummy_loop_merge]] = OpLabel +; CHECK-NEXT: OpReturn OpCapability Addresses OpCapability Shader OpCapability Linkage @@ -357,6 +364,7 @@ TEST_F(MergeReturnPassTest, StructuredControlDecoration) { ; CHECK: [[true:%\w+]] = OpConstantTrue ; CHECK: OpFunction ; CHECK: [[var:%\w+]] = OpVariable [[:%\w+]] Function [[false]] +; CHECK: OpSelectionMerge [[return_block:%\w+]] ; CHECK: OpSelectionMerge [[merge_lab:%\w+]] ; CHECK: OpBranchConditional [[cond:%\w+]] [[if_lab:%\w+]] [[then_lab:%\w+]] ; CHECK: [[if_lab]] = OpLabel @@ -364,9 +372,12 @@ TEST_F(MergeReturnPassTest, StructuredControlDecoration) { ; CHECK-NEXT: OpBranch ; CHECK: [[then_lab]] = OpLabel ; CHECK-NEXT: OpStore [[var]] [[true]] -; CHECK-NEXT: OpBranch [[merge_lab]] +; CHECK-NEXT: OpBranch [[return_block]] ; CHECK: [[merge_lab]] = OpLabel -; CHECK: OpReturn +; CHECK-NEXT: OpStore [[var]] [[true]] +; CHECK-NEXT: OpBranch [[return_block]] +; CHECK: [[return_block]] = OpLabel +; CHECK-NEXT: OpReturn OpCapability Addresses OpCapability Shader OpCapability Linkage @@ -396,69 +407,18 @@ OpFunctionEnd SinglePassRunAndMatch(before, false); } -TEST_F(MergeReturnPassTest, StructuredControlDecoration2) { - const std::string before = - R"( -; CHECK: OpDecorate [[dec_id:%\w+]] RelaxedPrecision -; CHECK: [[false:%\w+]] = OpConstantFalse -; CHECK: [[true:%\w+]] = OpConstantTrue -; CHECK: OpFunction -; CHECK: [[var:%\w+]] = OpVariable [[:%\w+]] Function [[false]] -; CHECK: OpSelectionMerge [[merge_lab:%\w+]] -; CHECK: OpBranchConditional [[cond:%\w+]] [[if_lab:%\w+]] [[then_lab:%\w+]] -; CHECK: [[if_lab]] = OpLabel -; CHECK-NEXT: [[dec_id]] = OpIAdd [[type:%\w+]] -; CHECK-NEXT: OpBranch -; CHECK: [[then_lab]] = OpLabel -; CHECK-NEXT: OpStore [[var]] [[true]] -; CHECK-NEXT: OpBranch [[merge_lab]] -; CHECK: [[merge_lab]] = OpLabel -; CHECK-NEXT: [[phi:%\w+]] = OpPhi [[type]] [[dec_id]] [[if_lab]] [[undef:%\w+]] [[then_lab]] -; CHECK: OpIAdd [[type]] [[phi]] [[phi]] -; CHECK: OpReturn -OpCapability Addresses -OpCapability Shader -OpCapability Linkage -OpMemoryModel Logical GLSL450 -OpEntryPoint GLCompute %6 "simple_shader" -OpDecorate %11 RelaxedPrecision -%2 = OpTypeVoid -%3 = OpTypeBool -%int = OpTypeInt 32 0 -%int_0 = OpConstant %int 0 -%4 = OpConstantFalse %3 -%1 = OpTypeFunction %2 -%6 = OpFunction %2 None %1 -%7 = OpLabel -OpSelectionMerge %10 None -OpBranchConditional %4 %8 %9 -%8 = OpLabel -%11 = OpIAdd %int %int_0 %int_0 -OpBranch %10 -%9 = OpLabel -OpReturn -%10 = OpLabel -%12 = OpIAdd %int %11 %11 -OpReturn -OpFunctionEnd -)"; - - SinglePassRunAndMatch(before, false); -} - TEST_F(MergeReturnPassTest, SplitBlockUsedInPhi) { const std::string before = R"( ; CHECK: OpFunction -; CHECK-NEXT: OpLabel -; CHECK: OpSelectionMerge [[merge1:%\w+]] None -; CHECK: [[merge1]] = OpLabel -; CHECK: OpBranchConditional %{{\w+}} %{{\w+}} [[old_merge:%\w+]] -; CHECK: [[old_merge]] = OpLabel -; CHECK-NEXT: OpSelectionMerge [[merge2:%\w+]] -; CHECK-NEXT: OpBranchConditional %false [[side_node:%\w+]] [[merge2]] -; CHECK: [[merge2]] = OpLabel -; CHECK-NEXT: OpPhi %bool %false [[old_merge]] %true [[side_node]] +; CHECK: OpSelectionMerge [[dummy_loop_merge:%\w+]] +; CHECK: OpLoopMerge [[loop_merge:%\w+]] +; CHECK: [[loop_merge]] = OpLabel +; CHECK: OpBranchConditional {{%\w+}} [[dummy_loop_merge]] [[old_code_path:%\w+]] +; CHECK: [[old_code_path:%\w+]] = OpLabel +; CHECK: OpBranchConditional {{%\w+}} [[side_node:%\w+]] [[phi_block:%\w+]] +; CHECK: [[phi_block]] = OpLabel +; CHECK-NEXT: OpPhi %bool %false [[side_node]] %true [[old_code_path]] OpCapability Addresses OpCapability Shader OpCapability Linkage @@ -471,17 +431,19 @@ TEST_F(MergeReturnPassTest, SplitBlockUsedInPhi) { %6 = OpTypeFunction %void %1 = OpFunction %void None %6 %7 = OpLabel - OpSelectionMerge %8 None - OpBranchConditional %false %9 %8 + OpLoopMerge %merge %cont None + OpBranchConditional %false %9 %merge %9 = OpLabel OpReturn - %8 = OpLabel - OpSelectionMerge %10 None - OpBranchConditional %false %11 %10 - %11 = OpLabel - OpBranch %10 - %10 = OpLabel - %12 = OpPhi %bool %false %8 %true %11 + %cont = OpLabel + OpBranch %7 + %merge = OpLabel + OpSelectionMerge %merge2 None + OpBranchConditional %false %if %merge2 + %if = OpLabel + OpBranch %merge2 + %merge2 = OpLabel + %12 = OpPhi %bool %false %if %true %merge OpReturn OpFunctionEnd )"; @@ -557,39 +519,61 @@ TEST_F(MergeReturnPassTest, UpdateOrderWhenPredicating) { SinglePassRunAndMatch(before, false); } */ -#endif TEST_F(MergeReturnPassTest, StructuredControlFlowBothMergeAndHeader) { - const std::string before = - R"(OpCapability Addresses + const std::string test = + R"( +; CHECK: OpFunction +; CHECK: [[ret_flag:%\w+]] = OpVariable %_ptr_Function_bool Function %false +; CHECK: OpSelectionMerge [[dummy_loop_merge:%\w+]] +; CHECK: OpLoopMerge [[loop1_merge:%\w+]] {{%\w+}} +; CHECK-NEXT: OpBranchConditional {{%\w+}} [[if_lab:%\w+]] {{%\w+}} +; CHECK: [[if_lab]] = OpLabel +; CHECK: OpStore [[ret_flag]] %true +; CHECK-NEXT: OpBranch [[loop1_merge]] +; CHECK: [[loop1_merge]] = OpLabel +; CHECK-NEXT: [[ld:%\w+]] = OpLoad %bool [[ret_flag]] +; CHECK-NOT: OpLabel +; CHECK: OpBranchConditional [[ld]] [[dummy_loop_merge]] [[empty_block:%\w+]] +; CHECK: [[empty_block]] = OpLabel +; CHECK-NEXT: OpBranch [[loop2:%\w+]] +; CHECK: [[loop2]] = OpLabel +; CHECK-NOT: OpLabel +; CHECK: OpLoopMerge + OpCapability Addresses OpCapability Shader OpCapability Linkage OpMemoryModel Logical GLSL450 OpEntryPoint GLCompute %1 "simple_shader" - %2 = OpTypeVoid - %3 = OpTypeBool - %4 = OpTypeInt 32 0 - %5 = OpConstant %4 0 - %6 = OpConstantFalse %3 - %7 = OpTypeFunction %2 - %1 = OpFunction %2 None %7 + %void = OpTypeVoid + %bool = OpTypeBool + %uint = OpTypeInt 32 0 + %uint_0 = OpConstant %uint 0 + %false = OpConstantFalse %bool + %7 = OpTypeFunction %void + %1 = OpFunction %void None %7 %8 = OpLabel - OpSelectionMerge %9 None - OpBranchConditional %6 %10 %11 - %10 = OpLabel - OpReturn - %11 = OpLabel OpBranch %9 %9 = OpLabel - OpLoopMerge %12 %13 None - OpBranch %13 - %13 = OpLabel - %14 = OpIAdd %4 %5 %5 - OpBranchConditional %6 %9 %12 + OpLoopMerge %10 %11 None + OpBranchConditional %false %12 %13 %12 = OpLabel - %15 = OpIAdd %4 %14 %14 + OpReturn + %13 = OpLabel + OpBranch %10 + %11 = OpLabel + OpBranch %9 + %10 = OpLabel + OpLoopMerge %14 %15 None + OpBranch %15 + %15 = OpLabel + %16 = OpIAdd %uint %uint_0 %uint_0 + OpBranchConditional %false %10 %14 + %14 = OpLabel + %17 = OpIAdd %uint %16 %16 OpReturn OpFunctionEnd + )"; const std::string after = @@ -639,7 +623,7 @@ OpReturn OpFunctionEnd )"; - SinglePassRunAndCheck(before, after, false, true); + SinglePassRunAndMatch(test, false); } // TODO(#1861): Reenable these test when the breaks from selection constructs @@ -927,8 +911,27 @@ OpFunctionEnd */ TEST_F(MergeReturnPassTest, NestedLoopMerge) { - const std::string before = - R"( OpCapability SampledBuffer + const std::string test = + R"( +; CHECK: OpFunction +; CHECK: OpSelectionMerge [[dummy_loop_merge:%\w+]] +; CHECK: OpLoopMerge [[outer_loop_merge:%\w+]] +; CHECK: OpLoopMerge [[inner_loop_merge:%\w+]] +; CHECK: OpSelectionMerge +; CHECK-NEXT: OpBranchConditional %true [[early_exit_block:%\w+]] +; CHECK: [[early_exit_block]] = OpLabel +; CHECK-NOT: OpLabel +; CHECK: OpBranch [[inner_loop_merge]] +; CHECK: [[inner_loop_merge]] = OpLabel +; CHECK-NOT: OpLabel +; CHECK: OpBranchConditional {{%\w+}} [[outer_loop_merge]] +; CHECK: [[outer_loop_merge]] = OpLabel +; CHECK-NOT: OpLabel +; CHECK: OpBranchConditional {{%\w+}} [[dummy_loop_merge]] +; CHECK: [[dummy_loop_merge]] = OpLabel +; CHECK-NOT: OpLabel +; CHECK: OpReturn + OpCapability SampledBuffer OpCapability StorageImageExtendedFormats OpCapability Shader %1 = OpExtInstImport "GLSL.std.450" @@ -936,7 +939,6 @@ TEST_F(MergeReturnPassTest, NestedLoopMerge) { OpEntryPoint GLCompute %2 "CS" OpExecutionMode %2 LocalSize 8 8 1 OpSource HLSL 600 - OpName %function "function" %uint = OpTypeInt 32 0 %void = OpTypeVoid %6 = OpTypeFunction %void @@ -946,29 +948,18 @@ TEST_F(MergeReturnPassTest, NestedLoopMerge) { %bool = OpTypeBool %true = OpConstantTrue %bool %_ptr_Function_uint = OpTypePointer Function %uint - %_struct_13 = OpTypeStruct %v3uint %v3uint %v3uint %uint %uint %uint %uint %uint %uint %2 = OpFunction %void None %6 %14 = OpLabel - %15 = OpFunctionCall %void %function - OpReturn - OpFunctionEnd - %function = OpFunction %void None %6 - %16 = OpLabel - %17 = OpVariable %_ptr_Function_uint Function - %18 = OpVariable %_ptr_Function_uint Function - OpStore %17 %uint_0 OpBranch %19 %19 = OpLabel - %20 = OpLoad %uint %17 + %20 = OpPhi %uint %uint_0 %2 %34 %23 %21 = OpULessThan %bool %20 %uint_1 OpLoopMerge %22 %23 DontUnroll OpBranchConditional %21 %24 %22 %24 = OpLabel - OpStore %18 %uint_1 OpBranch %25 %25 = OpLabel - %26 = OpLoad %uint %18 - %27 = OpINotEqual %bool %26 %uint_0 + %27 = OpINotEqual %bool %uint_1 %uint_0 OpLoopMerge %28 %29 DontUnroll OpBranchConditional %27 %30 %28 %30 = OpLabel @@ -977,110 +968,32 @@ TEST_F(MergeReturnPassTest, NestedLoopMerge) { %32 = OpLabel OpReturn %31 = OpLabel - OpStore %18 %uint_1 OpBranch %29 %29 = OpLabel OpBranch %25 %28 = OpLabel OpBranch %23 %23 = OpLabel - %33 = OpLoad %uint %17 - %34 = OpIAdd %uint %33 %uint_1 - OpStore %17 %34 + %34 = OpIAdd %uint %20 %uint_1 OpBranch %19 %22 = OpLabel OpReturn OpFunctionEnd )"; - const std::string after = - R"(OpCapability SampledBuffer -OpCapability StorageImageExtendedFormats -OpCapability Shader -%1 = OpExtInstImport "GLSL.std.450" -OpMemoryModel Logical GLSL450 -OpEntryPoint GLCompute %2 "CS" -OpExecutionMode %2 LocalSize 8 8 1 -OpSource HLSL 600 -OpName %function "function" -%uint = OpTypeInt 32 0 -%void = OpTypeVoid -%6 = OpTypeFunction %void -%uint_0 = OpConstant %uint 0 -%uint_1 = OpConstant %uint 1 -%v3uint = OpTypeVector %uint 3 -%bool = OpTypeBool -%true = OpConstantTrue %bool -%_ptr_Function_uint = OpTypePointer Function %uint -%_struct_13 = OpTypeStruct %v3uint %v3uint %v3uint %uint %uint %uint %uint %uint %uint -%false = OpConstantFalse %bool -%_ptr_Function_bool = OpTypePointer Function %bool -%2 = OpFunction %void None %6 -%14 = OpLabel -%15 = OpFunctionCall %void %function -OpReturn -OpFunctionEnd -%function = OpFunction %void None %6 -%16 = OpLabel -%38 = OpVariable %_ptr_Function_bool Function %false -%17 = OpVariable %_ptr_Function_uint Function -%18 = OpVariable %_ptr_Function_uint Function -OpStore %17 %uint_0 -OpBranch %19 -%19 = OpLabel -%20 = OpLoad %uint %17 -%21 = OpULessThan %bool %20 %uint_1 -OpLoopMerge %22 %23 DontUnroll -OpBranchConditional %21 %24 %22 -%24 = OpLabel -OpStore %18 %uint_1 -OpBranch %25 -%25 = OpLabel -%26 = OpLoad %uint %18 -%27 = OpINotEqual %bool %26 %uint_0 -OpLoopMerge %28 %29 DontUnroll -OpBranchConditional %27 %30 %28 -%30 = OpLabel -OpSelectionMerge %31 None -OpBranchConditional %true %32 %31 -%32 = OpLabel -OpStore %38 %true -OpBranch %28 -%31 = OpLabel -OpStore %18 %uint_1 -OpBranch %29 -%29 = OpLabel -OpBranch %25 -%28 = OpLabel -%40 = OpLoad %bool %38 -OpBranchConditional %40 %22 %39 -%39 = OpLabel -OpBranch %23 -%23 = OpLabel -%33 = OpLoad %uint %17 -%34 = OpIAdd %uint %33 %uint_1 -OpStore %17 %34 -OpBranch %19 -%22 = OpLabel -%43 = OpLoad %bool %38 -OpSelectionMerge %42 None -OpBranchConditional %43 %42 %41 -%41 = OpLabel -OpStore %38 %true -OpBranch %42 -%42 = OpLabel -OpBranch %35 -%35 = OpLabel -OpReturn -OpFunctionEnd -)"; - - SinglePassRunAndCheck(before, after, false, true); + SinglePassRunAndMatch(test, false); } TEST_F(MergeReturnPassTest, ReturnValueDecoration) { - const std::string before = - R"(OpCapability Linkage + const std::string test = + R"( +; CHECK: OpDecorate [[func:%\w+]] RelaxedPrecision +; CHECK: OpDecorate [[ret_val:%\w+]] RelaxedPrecision +; CHECK: [[func]] = OpFunction +; CHECK-NEXT: OpLabel +; CHECK-NOT: OpLabel +; CHECK: [[ret_val]] = OpVariable +OpCapability Linkage OpCapability Shader OpMemoryModel Logical GLSL450 OpEntryPoint GLCompute %11 "simple_shader" @@ -1095,6 +1008,7 @@ OpDecorate %7 RelaxedPrecision %13 = OpTypeFunction %12 %11 = OpFunction %12 None %13 %l1 = OpLabel +%fc = OpFunctionCall %1 %7 OpReturn OpFunctionEnd %7 = OpFunction %1 None %6 @@ -1107,51 +1021,953 @@ OpReturnValue %5 OpFunctionEnd )"; - const std::string after = - R"(OpCapability Linkage + SinglePassRunAndMatch(test, false); +} + +TEST_F(MergeReturnPassTest, + StructuredControlFlowWithNonTrivialUnreachableMerge) { + const std::string before = + R"( +OpCapability Addresses OpCapability Shader +OpCapability Linkage OpMemoryModel Logical GLSL450 -OpEntryPoint GLCompute %11 "simple_shader" -OpDecorate %7 RelaxedPrecision -OpDecorate %17 RelaxedPrecision -OpDecorate %18 RelaxedPrecision -%12 = OpTypeVoid -%1 = OpTypeInt 32 0 -%2 = OpTypeBool -%3 = OpConstantFalse %2 -%4 = OpConstant %1 0 -%5 = OpConstant %1 1 -%6 = OpTypeFunction %1 -%13 = OpTypeFunction %12 -%16 = OpTypePointer Function %1 -%19 = OpTypePointer Function %2 -%21 = OpConstantTrue %2 -%11 = OpFunction %12 None %13 -%14 = OpLabel +OpEntryPoint GLCompute %6 "simple_shader" +%2 = OpTypeVoid +%3 = OpTypeBool +%4 = OpConstantFalse %3 +%1 = OpTypeFunction %2 +%6 = OpFunction %2 None %1 +%7 = OpLabel +OpSelectionMerge %10 None +OpBranchConditional %4 %8 %9 +%8 = OpLabel +OpReturn +%9 = OpLabel +OpReturn +%10 = OpLabel +%11 = OpUndef %3 +OpUnreachable +OpFunctionEnd +)"; + + std::vector messages = { + {SPV_MSG_ERROR, nullptr, 0, 0, + "Module contains unreachable blocks during merge return. Run dead " + "branch elimination before merge return."}}; + SetMessageConsumer(GetTestMessageConsumer(messages)); + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + auto result = SinglePassRunToBinary(before, false); + EXPECT_EQ(Pass::Status::Failure, std::get<1>(result)); + EXPECT_TRUE(messages.empty()); +} + +TEST_F(MergeReturnPassTest, + StructuredControlFlowWithNonTrivialUnreachableContinue) { + const std::string before = + R"( +OpCapability Addresses +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %6 "simple_shader" +%2 = OpTypeVoid +%3 = OpTypeBool +%4 = OpConstantFalse %3 +%1 = OpTypeFunction %2 +%6 = OpFunction %2 None %1 +%7 = OpLabel +OpBranch %header +%header = OpLabel +OpLoopMerge %merge %continue None +OpBranchConditional %4 %8 %merge +%8 = OpLabel +OpReturn +%continue = OpLabel +%11 = OpUndef %3 +OpBranch %header +%merge = OpLabel OpReturn OpFunctionEnd -%7 = OpFunction %1 None %6 +)"; + + std::vector messages = { + {SPV_MSG_ERROR, nullptr, 0, 0, + "Module contains unreachable blocks during merge return. Run dead " + "branch elimination before merge return."}}; + SetMessageConsumer(GetTestMessageConsumer(messages)); + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + auto result = SinglePassRunToBinary(before, false); + EXPECT_EQ(Pass::Status::Failure, std::get<1>(result)); + EXPECT_TRUE(messages.empty()); +} + +TEST_F(MergeReturnPassTest, StructuredControlFlowWithUnreachableBlock) { + const std::string before = + R"( +OpCapability Addresses +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %6 "simple_shader" +%2 = OpTypeVoid +%3 = OpTypeBool +%4 = OpConstantFalse %3 +%1 = OpTypeFunction %2 +%6 = OpFunction %2 None %1 +%7 = OpLabel +OpBranch %header +%header = OpLabel +OpLoopMerge %merge %continue None +OpBranchConditional %4 %8 %merge %8 = OpLabel -%20 = OpVariable %19 Function %3 -%17 = OpVariable %16 Function -OpBranchConditional %3 %9 %10 +OpReturn +%continue = OpLabel +OpBranch %header +%merge = OpLabel +OpReturn +%unreachable = OpLabel +OpUnreachable +OpFunctionEnd +)"; + + std::vector messages = { + {SPV_MSG_ERROR, nullptr, 0, 0, + "Module contains unreachable blocks during merge return. Run dead " + "branch elimination before merge return."}}; + SetMessageConsumer(GetTestMessageConsumer(messages)); + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + auto result = SinglePassRunToBinary(before, false); + EXPECT_EQ(Pass::Status::Failure, std::get<1>(result)); + EXPECT_TRUE(messages.empty()); +} + +TEST_F(MergeReturnPassTest, StructuredControlFlowDontChangeEntryPhi) { + const std::string before = + R"( +; CHECK: OpFunction %void +; CHECK: OpLabel +; CHECK: [[pre_header:%\w+]] = OpLabel +; CHECK: [[header:%\w+]] = OpLabel +; CHECK-NEXT: OpPhi %bool {{%\w+}} [[pre_header]] [[iv:%\w+]] [[continue:%\w+]] +; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] [[continue]] +; CHECK: [[continue]] = OpLabel +; CHECK-NEXT: [[iv]] = Op +; CHECK: [[merge]] = OpLabel + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %1 "main" + %void = OpTypeVoid + %bool = OpTypeBool + %4 = OpTypeFunction %void + %1 = OpFunction %void None %4 + %5 = OpLabel + %6 = OpUndef %bool + OpBranch %7 + %7 = OpLabel + %8 = OpPhi %bool %6 %5 %9 %10 + OpLoopMerge %11 %10 None + OpBranch %12 + %12 = OpLabel + %13 = OpUndef %bool + OpSelectionMerge %10 DontFlatten + OpBranchConditional %13 %10 %14 + %14 = OpLabel + OpReturn + %10 = OpLabel + %9 = OpUndef %bool + OpBranchConditional %13 %7 %11 + %11 = OpLabel + OpReturn + OpFunctionEnd + +)"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndMatch(before, false); +} + +TEST_F(MergeReturnPassTest, StructuredControlFlowPartialReplacePhi) { + const std::string before = + R"( +; CHECK: OpFunction %void +; CHECK: OpLabel +; CHECK: [[pre_header:%\w+]] = OpLabel +; CHECK: [[header:%\w+]] = OpLabel +; CHECK-NEXT: OpPhi +; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] +; CHECK: OpLabel +; CHECK: [[old_ret_block:%\w+]] = OpLabel +; CHECK: [[bb:%\w+]] = OpLabel +; CHECK-NEXT: [[val:%\w+]] = OpUndef %bool +; CHECK: [[merge]] = OpLabel +; CHECK-NEXT: [[phi1:%\w+]] = OpPhi %bool {{%\w+}} [[old_ret_block]] [[val]] [[bb]] +; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} [[bb2:%\w+]] +; CHECK: [[bb2]] = OpLabel +; CHECK: OpBranch [[header2:%\w+]] +; CHECK: [[header2]] = OpLabel +; CHECK-NEXT: [[phi2:%\w+]] = OpPhi %bool [[phi1]] [[continue2:%\w+]] [[phi1]] [[bb2]] +; CHECK-NEXT: OpLoopMerge {{%\w+}} [[continue2]] +; CHECK: [[continue2]] = OpLabel +; CHECK-NEXT: OpBranch [[header2]] + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %1 "main" + %void = OpTypeVoid + %bool = OpTypeBool + %4 = OpTypeFunction %void + %1 = OpFunction %void None %4 + %5 = OpLabel + %6 = OpUndef %bool + OpBranch %7 + %7 = OpLabel + %8 = OpPhi %bool %6 %5 %9 %10 + OpLoopMerge %11 %10 None + OpBranch %12 + %12 = OpLabel + %13 = OpUndef %bool + OpSelectionMerge %10 DontFlatten + OpBranchConditional %13 %10 %14 + %14 = OpLabel + OpReturn + %10 = OpLabel + %9 = OpUndef %bool + OpBranchConditional %13 %7 %11 + %11 = OpLabel + %phi = OpPhi %bool %9 %10 %9 %cont + OpLoopMerge %ret %cont None + OpBranch %bb + %bb = OpLabel + OpBranchConditional %13 %ret %cont + %cont = OpLabel + OpBranch %11 + %ret = OpLabel + OpReturn + OpFunctionEnd +)"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndMatch(before, false); +} + +TEST_F(MergeReturnPassTest, GeneratePhiInOuterLoop) { + const std::string before = + R"( + ; CHECK: OpSelectionMerge + ; CHECK-NEXT: OpSwitch {{%\w+}} [[def_bb1:%\w+]] + ; CHECK-NEXT: [[def_bb1]] = OpLabel + ; CHECK: OpLoopMerge [[merge:%\w+]] [[continue:%\w+]] + ; CHECK: [[continue]] = OpLabel + ; CHECK-NEXT: [[undef:%\w+]] = OpUndef + ; CHECK: [[merge]] = OpLabel + ; CHECK-NEXT: [[phi:%\w+]] = OpPhi %bool {{%\w+}} {{%\w+}} [[undef]] [[continue]] + ; CHECK: OpCopyObject %bool [[phi]] + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %bool = OpTypeBool + %8 = OpTypeFunction %bool + %false = OpConstantFalse %bool + %4 = OpFunction %void None %3 + %5 = OpLabel + %63 = OpFunctionCall %bool %9 + OpReturn + OpFunctionEnd + %9 = OpFunction %bool None %8 + %10 = OpLabel + OpBranch %31 + %31 = OpLabel + OpLoopMerge %33 %34 None + OpBranch %32 + %32 = OpLabel + OpSelectionMerge %34 None + OpBranchConditional %false %46 %34 + %46 = OpLabel + OpLoopMerge %51 %52 None + OpBranch %53 + %53 = OpLabel + OpBranchConditional %false %50 %51 + %50 = OpLabel + OpReturnValue %false + %52 = OpLabel + OpBranch %46 + %51 = OpLabel + OpBranch %34 + %34 = OpLabel + %64 = OpUndef %bool + OpBranchConditional %false %31 %33 + %33 = OpLabel + OpBranch %28 + %28 = OpLabel + %60 = OpCopyObject %bool %64 + OpBranch %17 + %17 = OpLabel + OpReturnValue %false + OpFunctionEnd +)"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndMatch(before, false); +} + +TEST_F(MergeReturnPassTest, SerialLoopsUpdateBlockMapping) { + // #2455: This test case triggers phi insertions that use previously inserted + // phis. Without the fix, it fails to validate. + const std::string spirv = R"( +; CHECK: OpSelectionMerge +; CHECK-NEXT: OpSwitch {{%\w+}} [[def_bb1:%\w+]] +; CHECK-NEXT: [[def_bb1]] = OpLabel +; CHECK: OpLoopMerge +; CHECK: OpLoopMerge +; CHECK: OpLoopMerge [[merge:%\w+]] +; CHECK: [[def:%\w+]] = OpFOrdLessThan +; CHECK: [[merge]] = OpLabel +; CHECK-NEXT: [[phi:%\w+]] = OpPhi {{%\w+}} {{%\w+}} {{%\w+}} [[def]] +; CHECK: OpLoopMerge [[merge:%\w+]] [[cont:%\w+]] +; CHECK: [[cont]] = OpLabel +; CHECK-NEXT: OpBranchConditional [[phi]] +; CHECK-NOT: [[def]] + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" %53 + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpDecorate %20 RelaxedPrecision + OpDecorate %27 RelaxedPrecision + OpDecorate %53 BuiltIn FragCoord + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypeVector %6 3 + %8 = OpTypeFunction %7 + %11 = OpTypeBool + %12 = OpConstantFalse %11 + %15 = OpConstant %6 1 + %16 = OpConstantComposite %7 %15 %15 %15 + %18 = OpTypeInt 32 1 + %19 = OpTypePointer Function %18 + %21 = OpConstant %18 1 + %28 = OpConstant %18 0 + %31 = OpTypePointer Function %11 + %33 = OpConstantTrue %11 + %51 = OpTypeVector %6 4 + %52 = OpTypePointer Input %51 + %53 = OpVariable %52 Input + %54 = OpTypeInt 32 0 + %55 = OpConstant %54 0 + %56 = OpTypePointer Input %6 + %59 = OpConstant %6 0 + %76 = OpUndef %18 + %77 = OpUndef %11 + %78 = OpUndef %6 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %75 = OpFunctionCall %7 %9 + OpReturn + OpFunctionEnd + %9 = OpFunction %7 None %8 + %10 = OpLabel + %20 = OpVariable %19 Function + OpBranch %14 + %14 = OpLabel + OpBranch %22 + %22 = OpLabel + %27 = OpLoad %18 %20 + OpLoopMerge %24 %25 None + OpBranch %24 + %25 = OpLabel + OpBranch %22 + %24 = OpLabel + OpBranch %34 + %34 = OpLabel + OpLoopMerge %36 %40 None + OpBranch %35 + %35 = OpLabel + OpBranchConditional %77 %39 %40 + %39 = OpLabel + OpReturnValue %16 + %40 = OpLabel + OpBranchConditional %12 %34 %36 + %36 = OpLabel + OpBranch %43 + %43 = OpLabel + OpLoopMerge %45 %49 None + OpBranch %44 + %44 = OpLabel + OpBranchConditional %77 %48 %49 + %48 = OpLabel + OpReturnValue %16 + %49 = OpLabel + %60 = OpFOrdLessThan %11 %15 %59 + OpBranchConditional %12 %43 %45 + %45 = OpLabel + OpBranch %62 + %62 = OpLabel + OpLoopMerge %64 %68 None + OpBranch %63 + %63 = OpLabel + OpBranchConditional %77 %67 %68 + %67 = OpLabel + OpReturnValue %16 + %68 = OpLabel + OpBranchConditional %60 %62 %64 + %64 = OpLabel + OpReturnValue %16 + OpFunctionEnd +)"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndMatch(spirv, true); +} + +TEST_F(MergeReturnPassTest, InnerLoopMergeIsOuterLoopContinue) { + const std::string before = + R"( + ; CHECK: OpSelectionMerge + ; CHECK-NEXT: OpSwitch {{%\w+}} [[def_bb1:%\w+]] + ; CHECK-NEXT: [[def_bb1]] = OpLabel + ; CHECK-NEXT: OpBranch [[outer_loop_header:%\w+]] + ; CHECK: [[outer_loop_header]] = OpLabel + ; CHECK-NEXT: OpLoopMerge [[outer_loop_merge:%\w+]] [[outer_loop_continue:%\w+]] None + ; CHECK: [[outer_loop_continue]] = OpLabel + ; CHECK-NEXT: OpBranch [[outer_loop_header]] + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpSource ESSL 310 + %void = OpTypeVoid + %4 = OpTypeFunction %void + %bool = OpTypeBool + %6 = OpTypeFunction %bool + %true = OpConstantTrue %bool + %2 = OpFunction %void None %4 + %8 = OpLabel + %9 = OpFunctionCall %bool %10 + OpReturn + OpFunctionEnd + %10 = OpFunction %bool None %6 + %11 = OpLabel + OpBranch %12 + %12 = OpLabel + OpLoopMerge %13 %14 None + OpBranchConditional %true %15 %13 + %15 = OpLabel + OpLoopMerge %14 %16 None + OpBranchConditional %true %17 %14 + %17 = OpLabel + OpReturnValue %true + %16 = OpLabel + OpBranch %15 + %14 = OpLabel + OpBranch %12 + %13 = OpLabel + OpReturnValue %true + OpFunctionEnd +)"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndMatch(before, false); +} + +TEST_F(MergeReturnPassTest, BreakFromLoopUseNoLongerDominated) { + const std::string spirv = R"( +; CHECK: [[undef:%\w+]] = OpUndef +; CHECK: OpSelectionMerge +; CHECK-NEXT: OpSwitch {{%\w+}} [[def_bb1:%\w+]] +; CHECK-NEXT: [[def_bb1]] = OpLabel +; CHECK: OpLoopMerge [[merge:%\w+]] [[cont:%\w+]] +; CHECK-NEXT: OpBranch [[body:%\w+]] +; CHECK: [[body]] = OpLabel +; CHECK-NEXT: OpSelectionMerge [[non_ret:%\w+]] +; CHECK-NEXT: OpBranchConditional {{%\w+}} [[ret:%\w+]] [[non_ret]] +; CHECK: [[ret]] = OpLabel +; CHECK-NEXT: OpStore +; CHECK-NEXT: OpBranch [[merge]] +; CHECK: [[non_ret]] = OpLabel +; CHECK-NEXT: [[def:%\w+]] = OpLogicalNot +; CHECK-NEXT: OpBranchConditional {{%\w+}} [[break:%\w+]] [[cont]] +; CHECK: [[break]] = OpLabel +; CHECK-NEXT: OpBranch [[merge]] +; CHECK: [[cont]] = OpLabel +; CHECK-NEXT: OpBranchConditional {{%\w+}} {{%\w+}} [[merge]] +; CHECK: [[merge]] = OpLabel +; CHECK-NEXT: [[phi:%\w+]] = OpPhi {{%\w+}} [[undef]] [[ret]] [[def]] [[break]] [[def]] [[cont]] +; CHECK: OpLogicalNot {{%\w+}} [[phi]] +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %func "func" +OpExecutionMode %func LocalSize 1 1 1 +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%bool = OpTypeBool +%true = OpConstantTrue %bool +%func = OpFunction %void None %void_fn +%1 = OpLabel +OpBranch %2 +%2 = OpLabel +OpLoopMerge %8 %7 None +OpBranch %3 +%3 = OpLabel +OpSelectionMerge %5 None +OpBranchConditional %true %4 %5 +%4 = OpLabel +OpReturn +%5 = OpLabel +%def = OpLogicalNot %bool %true +OpBranchConditional %true %6 %7 +%6 = OpLabel +OpBranch %8 +%7 = OpLabel +OpBranchConditional %true %2 %8 +%8 = OpLabel +OpBranch %9 %9 = OpLabel -OpStore %20 %21 -OpStore %17 %4 -OpBranch %15 -%10 = OpLabel -OpStore %20 %21 -OpStore %17 %5 -OpBranch %15 -%15 = OpLabel -%18 = OpLoad %1 %17 -OpReturnValue %18 +%use = OpLogicalNot %bool %def +OpReturn OpFunctionEnd )"; SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER); - SinglePassRunAndCheck(before, after, false, true); + SinglePassRunAndMatch(spirv, true); +} + +TEST_F(MergeReturnPassTest, TwoBreaksFromLoopUsesNoLongerDominated) { + const std::string spirv = R"( +; CHECK: [[undef:%\w+]] = OpUndef +; CHECK: OpSelectionMerge +; CHECK-NEXT: OpSwitch {{%\w+}} [[def_bb1:%\w+]] +; CHECK-NEXT: [[def_bb1]] = OpLabel +; CHECK: OpLoopMerge [[merge:%\w+]] [[cont:%\w+]] +; CHECK-NEXT: OpBranch [[body:%\w+]] +; CHECK: [[body]] = OpLabel +; CHECK-NEXT: OpSelectionMerge [[body2:%\w+]] +; CHECK-NEXT: OpBranchConditional {{%\w+}} [[ret1:%\w+]] [[body2]] +; CHECK: [[ret1]] = OpLabel +; CHECK-NEXT: OpStore +; CHECK-NEXT: OpBranch [[merge]] +; CHECK: [[body2]] = OpLabel +; CHECK-NEXT: [[def1:%\w+]] = OpLogicalNot +; CHECK-NEXT: OpSelectionMerge [[body3:%\w+]] +; CHECK-NEXT: OpBranchConditional {{%\w+}} [[ret2:%\w+]] [[body3:%\w+]] +; CHECK: [[ret2]] = OpLabel +; CHECK-NEXT: OpStore +; CHECK-NEXT: OpBranch [[merge]] +; CHECK: [[body3]] = OpLabel +; CHECK-NEXT: [[def2:%\w+]] = OpLogicalAnd +; CHECK-NEXT: OpBranchConditional {{%\w+}} [[break:%\w+]] [[cont]] +; CHECK: [[break]] = OpLabel +; CHECK-NEXT: OpBranch [[merge]] +; CHECK: [[cont]] = OpLabel +; CHECK-NEXT: OpBranchConditional {{%\w+}} {{%\w+}} [[merge]] +; CHECK: [[merge]] = OpLabel +; CHECK-NEXT: [[phi1:%\w+]] = OpPhi {{%\w+}} [[undef]] [[ret1]] [[undef]] [[ret2]] [[def1]] [[break]] [[def1]] [[cont]] +; CHECK-NEXT: [[phi2:%\w+]] = OpPhi {{%\w+}} [[undef]] [[ret1]] [[undef]] [[ret2]] [[def2]] [[break]] [[def2]] [[cont]] +; CHECK: OpLogicalNot {{%\w+}} [[phi1]] +; CHECK: OpLogicalAnd {{%\w+}} [[phi2]] +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %func "func" +OpExecutionMode %func LocalSize 1 1 1 +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%bool = OpTypeBool +%true = OpConstantTrue %bool +%func = OpFunction %void None %void_fn +%1 = OpLabel +OpBranch %2 +%2 = OpLabel +OpLoopMerge %10 %9 None +OpBranch %3 +%3 = OpLabel +OpSelectionMerge %5 None +OpBranchConditional %true %4 %5 +%4 = OpLabel +OpReturn +%5 = OpLabel +%def1 = OpLogicalNot %bool %true +OpSelectionMerge %7 None +OpBranchConditional %true %6 %7 +%6 = OpLabel +OpReturn +%7 = OpLabel +%def2 = OpLogicalAnd %bool %true %true +OpBranchConditional %true %8 %9 +%8 = OpLabel +OpBranch %10 +%9 = OpLabel +OpBranchConditional %true %2 %10 +%10 = OpLabel +OpBranch %11 +%11 = OpLabel +%use1 = OpLogicalNot %bool %def1 +%use2 = OpLogicalAnd %bool %def2 %true +OpReturn +OpFunctionEnd +)"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndMatch(spirv, true); +} + +TEST_F(MergeReturnPassTest, PredicateBreakBlock) { + const std::string spirv = R"( +; IDs are being preserved so we can rely on basic block labels. +; CHECK: [[undef:%\w+]] = OpUndef +; CHECK: [[undef:%\w+]] = OpUndef +; CHECK: %13 = OpLabel +; CHECK-NEXT: [[def:%\w+]] = OpLogicalNot +; CHECK: %8 = OpLabel +; CHECK-NEXT: [[phi:%\w+]] = OpPhi {{%\w+}} [[undef]] {{%\w+}} [[undef]] {{%\w+}} [[def]] %13 [[undef]] {{%\w+}} +; CHECK: OpLogicalAnd {{%\w+}} [[phi]] +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %1 "func" +OpExecutionMode %1 LocalSize 1 1 1 +%void = OpTypeVoid +%3 = OpTypeFunction %void +%bool = OpTypeBool +%true = OpUndef %bool +%1 = OpFunction %void None %3 +%6 = OpLabel +OpBranch %7 +%7 = OpLabel +OpLoopMerge %8 %9 None +OpBranch %10 +%10 = OpLabel +OpSelectionMerge %11 None +OpBranchConditional %true %12 %13 +%12 = OpLabel +OpLoopMerge %14 %15 None +OpBranch %16 +%16 = OpLabel +OpReturn +%15 = OpLabel +OpBranch %12 +%14 = OpLabel +OpUnreachable +%13 = OpLabel +%17 = OpLogicalNot %bool %true +OpBranch %8 +%11 = OpLabel +OpUnreachable +%9 = OpLabel +OpBranch %7 +%8 = OpLabel +OpBranch %18 +%18 = OpLabel +%19 = OpLogicalAnd %bool %17 %true +OpReturn +OpFunctionEnd +)"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndMatch(spirv, true); +} + +TEST_F(MergeReturnPassTest, SingleReturnInLoop) { + const std::string predefs = + R"(OpCapability Shader +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpSource ESSL 310 +%void = OpTypeVoid +%7 = OpTypeFunction %void +%float = OpTypeFloat 32 +%9 = OpTypeFunction %float +%float_1 = OpConstant %float 1 +)"; + + const std::string caller = + R"( +; CHECK: OpFunction +; CHECK: OpFunctionEnd +%main = OpFunction %void None %7 +%22 = OpLabel +%30 = OpFunctionCall %float %f_ +OpReturn +OpFunctionEnd +)"; + + const std::string callee = + R"( +; CHECK: OpFunction +; CHECK: OpLoopMerge [[merge:%\w+]] +; CHECK: [[merge]] = OpLabel +; CHECK: OpReturnValue +; CHECK-NEXT: OpFunctionEnd +%f_ = OpFunction %float None %9 +%33 = OpLabel +OpBranch %34 +%34 = OpLabel +OpLoopMerge %35 %36 None +OpBranch %37 +%37 = OpLabel +OpReturnValue %float_1 +%36 = OpLabel +OpBranch %34 +%35 = OpLabel +OpUnreachable +OpFunctionEnd +)"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndMatch(predefs + caller + callee, true); +} + +TEST_F(MergeReturnPassTest, MergeToMergeBranch) { + const std::string text = + R"( +; CHECK: [[new_undef:%\w+]] = OpUndef %uint +; CHECK: OpSelectionMerge +; CHECK-NEXT: OpSwitch {{%\w+}} [[def_bb1:%\w+]] +; CHECK-NEXT: [[def_bb1]] = OpLabel +; CHECK: OpLoopMerge [[merge1:%\w+]] +; CHECK: OpLoopMerge [[merge2:%\w+]] +; CHECK: [[merge1]] = OpLabel +; CHECK-NEXT: OpPhi %uint [[new_undef]] [[merge2]] + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %2 "main" + OpExecutionMode %2 LocalSize 100 1 1 + OpSource ESSL 310 + %void = OpTypeVoid + %4 = OpTypeFunction %void + %uint = OpTypeInt 32 0 + %uint_1 = OpConstant %uint 1 + %bool = OpTypeBool + %false = OpConstantFalse %bool + %uint_0 = OpConstant %uint 0 + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 + %int_1 = OpConstant %int 1 + %13 = OpUndef %bool + %2 = OpFunction %void None %4 + %14 = OpLabel + OpBranch %15 + %15 = OpLabel + OpLoopMerge %16 %17 None + OpBranch %18 + %18 = OpLabel + OpLoopMerge %19 %20 None + OpBranchConditional %13 %21 %19 + %21 = OpLabel + OpReturn + %20 = OpLabel + OpBranch %18 + %19 = OpLabel + %22 = OpUndef %uint + OpBranch %23 + %23 = OpLabel + OpBranch %16 + %17 = OpLabel + OpBranch %15 + %16 = OpLabel + %24 = OpCopyObject %uint %22 + OpReturn + OpFunctionEnd +)"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndMatch(text, true); +} + +TEST_F(MergeReturnPassTest, PhiInSecondMerge) { + // Add and use a phi in the second merge block from the return. + const std::string text = + R"( +; CHECK: OpSelectionMerge +; CHECK-NEXT: OpSwitch {{%\w+}} [[def_bb1:%\w+]] +; CHECK-NEXT: [[def_bb1]] = OpLabel +; CHECK: OpLoopMerge [[merge_bb:%\w+]] [[continue_bb:%\w+]] +; CHECK: [[continue_bb]] = OpLabel +; CHECK-NEXT: [[val:%\w+]] = OpUndef %float +; CHECK: [[merge_bb]] = OpLabel +; CHECK-NEXT: [[phi:%\w+]] = OpPhi %float {{%\w+}} {{%\w+}} [[val]] [[continue_bb]] +; CHECK-NOT: OpLabel +; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} [[old_merge:%\w+]] +; CHECK: [[old_merge]] = OpLabel +; CHECK-NEXT: OpConvertFToS %int [[phi]] + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpSource ESSL 310 + %void = OpTypeVoid + %4 = OpTypeFunction %void + %int = OpTypeInt 32 1 + %float = OpTypeFloat 32 + %bool = OpTypeBool + %8 = OpUndef %bool + %2 = OpFunction %void None %4 + %9 = OpLabel + OpBranch %10 + %10 = OpLabel + OpLoopMerge %11 %12 None + OpBranch %13 + %13 = OpLabel + OpLoopMerge %18 %14 None + OpBranchConditional %8 %15 %18 + %15 = OpLabel + OpReturn + %14 = OpLabel + OpBranch %13 + %18 = OpLabel + OpBranch %12 + %12 = OpLabel + %16 = OpUndef %float + OpBranchConditional %8 %10 %11 + %11 = OpLabel + %17 = OpConvertFToS %int %16 + OpReturn + OpFunctionEnd +)"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndMatch(text, true); +} + +TEST_F(MergeReturnPassTest, ReturnsInSwitch) { + // Cannot branch directly to dummy switch merge block from original switch. + // Must branch to merge block of original switch and then do predicated + // branch to merge block of dummy switch. + const std::string text = + R"( +; CHECK: OpSelectionMerge [[dummy_merge_bb:%\w+]] +; CHECK-NEXT: OpSwitch {{%\w+}} [[def_bb1:%\w+]] +; CHECK-NEXT: [[def_bb1]] = OpLabel +; CHECK: OpSelectionMerge +; CHECK-NEXT: OpSwitch {{%\w+}} [[inner_merge_bb:%\w+]] 0 {{%\w+}} 1 {{%\w+}} +; CHECK: OpBranch [[inner_merge_bb]] +; CHECK: OpBranch [[inner_merge_bb]] +; CHECK-NEXT: [[inner_merge_bb]] = OpLabel +; CHECK: OpBranchConditional {{%\w+}} [[dummy_merge_bb]] {{%\w+}} + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %PSMain "PSMain" %_entryPointOutput_color + OpExecutionMode %PSMain OriginUpperLeft + OpSource HLSL 500 + OpMemberDecorate %cb 0 Offset 0 + OpMemberDecorate %cb 1 Offset 16 + OpMemberDecorate %cb 2 Offset 32 + OpMemberDecorate %cb 3 Offset 48 + OpDecorate %cb Block + OpDecorate %_ DescriptorSet 0 + OpDecorate %_ Binding 0 + OpDecorate %_entryPointOutput_color Location 0 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 + %8 = OpTypeFunction %v4float + %int = OpTypeInt 32 1 + %cb = OpTypeStruct %v4float %v4float %v4float %int +%_ptr_Uniform_cb = OpTypePointer Uniform %cb + %_ = OpVariable %_ptr_Uniform_cb Uniform + %int_3 = OpConstant %int 3 +%_ptr_Uniform_int = OpTypePointer Uniform %int + %int_0 = OpConstant %int 0 +%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float + %int_1 = OpConstant %int 1 + %int_2 = OpConstant %int 2 + %float_0 = OpConstant %float 0 + %float_1 = OpConstant %float 1 + %45 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_1 +%_ptr_Function_v4float = OpTypePointer Function %v4float +%_ptr_Output_v4float = OpTypePointer Output %v4float +%_entryPointOutput_color = OpVariable %_ptr_Output_v4float Output + %PSMain = OpFunction %void None %3 + %5 = OpLabel + %50 = OpFunctionCall %v4float %BlendValue_ + OpStore %_entryPointOutput_color %50 + OpReturn + OpFunctionEnd +%BlendValue_ = OpFunction %v4float None %8 + %10 = OpLabel + %21 = OpAccessChain %_ptr_Uniform_int %_ %int_3 + %22 = OpLoad %int %21 + OpSelectionMerge %25 None + OpSwitch %22 %25 0 %23 1 %24 + %23 = OpLabel + %28 = OpAccessChain %_ptr_Uniform_v4float %_ %int_0 + %29 = OpLoad %v4float %28 + OpReturnValue %29 + %24 = OpLabel + %31 = OpAccessChain %_ptr_Uniform_v4float %_ %int_0 + %32 = OpLoad %v4float %31 + %34 = OpAccessChain %_ptr_Uniform_v4float %_ %int_1 + %35 = OpLoad %v4float %34 + %37 = OpAccessChain %_ptr_Uniform_v4float %_ %int_2 + %38 = OpLoad %v4float %37 + %39 = OpFMul %v4float %35 %38 + %40 = OpFAdd %v4float %32 %39 + OpReturnValue %40 + %25 = OpLabel + OpReturnValue %45 + OpFunctionEnd +)"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndMatch(text, true); +} + +TEST_F(MergeReturnPassTest, UnreachableMergeAndContinue) { + // Make sure that the pass can handle a single block that is both a merge and + // a continue. + const std::string text = + R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpSource ESSL 310 + %void = OpTypeVoid + %4 = OpTypeFunction %void + %bool = OpTypeBool + %true = OpConstantTrue %bool + %2 = OpFunction %void None %4 + %7 = OpLabel + OpBranch %8 + %8 = OpLabel + OpLoopMerge %9 %10 None + OpBranch %11 + %11 = OpLabel + OpSelectionMerge %10 None + OpBranchConditional %true %12 %13 + %12 = OpLabel + OpReturn + %13 = OpLabel + OpReturn + %10 = OpLabel + OpBranch %8 + %9 = OpLabel + OpUnreachable + OpFunctionEnd +)"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + auto result = SinglePassRunAndDisassemble(text, true, true); + + // Not looking for any particular output. Other tests do that. + // Just want to make sure the check for unreachable blocks does not emit an + // error. + EXPECT_EQ(Pass::Status::SuccessWithChange, std::get<1>(result)); } } // namespace diff --git a/third_party/spirv-tools/test/opt/pass_test.cpp b/third_party/spirv-tools/test/opt/pass_test.cpp deleted file mode 100644 index bce05b6790..0000000000 --- a/third_party/spirv-tools/test/opt/pass_test.cpp +++ /dev/null @@ -1,242 +0,0 @@ -// Copyright (c) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include -#include - -#include "gmock/gmock.h" -#include "source/opt/pass.h" -#include "test/opt/assembly_builder.h" -#include "test/opt/pass_fixture.h" -#include "test/opt/pass_utils.h" - -namespace spvtools { -namespace opt { -namespace { - -class DummyPass : public Pass { - public: - const char* name() const override { return "dummy-pass"; } - Status Process() override { return Status::SuccessWithoutChange; } -}; - -using ::testing::UnorderedElementsAre; -using PassClassTest = PassTest<::testing::Test>; - -TEST_F(PassClassTest, BasicVisitFromEntryPoint) { - // Make sure we visit the entry point, and the function it calls. - // Do not visit Dead or Exported. - const std::string text = R"( - OpCapability Shader - OpMemoryModel Logical GLSL450 - OpEntryPoint Fragment %10 "main" - OpName %10 "main" - OpName %Dead "Dead" - OpName %11 "Constant" - OpName %ExportedFunc "ExportedFunc" - OpDecorate %ExportedFunc LinkageAttributes "ExportedFunc" Export - %void = OpTypeVoid - %6 = OpTypeFunction %void - %10 = OpFunction %void None %6 - %14 = OpLabel - %15 = OpFunctionCall %void %11 - %16 = OpFunctionCall %void %11 - OpReturn - OpFunctionEnd - %11 = OpFunction %void None %6 - %18 = OpLabel - OpReturn - OpFunctionEnd - %Dead = OpFunction %void None %6 - %19 = OpLabel - OpReturn - OpFunctionEnd -%ExportedFunc = OpFunction %void None %7 - %20 = OpLabel - %21 = OpFunctionCall %void %11 - OpReturn - OpFunctionEnd -)"; - // clang-format on - - std::unique_ptr localContext = - BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text, - SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - EXPECT_NE(nullptr, localContext) << "Assembling failed for shader:\n" - << text << std::endl; - DummyPass testPass; - std::vector processed; - Pass::ProcessFunction mark_visited = [&processed](Function* fp) { - processed.push_back(fp->result_id()); - return false; - }; - testPass.ProcessEntryPointCallTree(mark_visited, localContext->module()); - EXPECT_THAT(processed, UnorderedElementsAre(10, 11)); -} - -TEST_F(PassClassTest, BasicVisitReachable) { - // Make sure we visit the entry point, exported function, and the function - // they call. Do not visit Dead. - const std::string text = R"( - OpCapability Shader - OpMemoryModel Logical GLSL450 - OpEntryPoint Fragment %10 "main" - OpName %10 "main" - OpName %Dead "Dead" - OpName %11 "Constant" - OpName %12 "ExportedFunc" - OpName %13 "Constant2" - OpDecorate %12 LinkageAttributes "ExportedFunc" Export - %void = OpTypeVoid - %6 = OpTypeFunction %void - %10 = OpFunction %void None %6 - %14 = OpLabel - %15 = OpFunctionCall %void %11 - %16 = OpFunctionCall %void %11 - OpReturn - OpFunctionEnd - %11 = OpFunction %void None %6 - %18 = OpLabel - OpReturn - OpFunctionEnd - %Dead = OpFunction %void None %6 - %19 = OpLabel - OpReturn - OpFunctionEnd - %12 = OpFunction %void None %9 - %20 = OpLabel - %21 = OpFunctionCall %void %13 - OpReturn - OpFunctionEnd - %13 = OpFunction %void None %6 - %22 = OpLabel - OpReturn - OpFunctionEnd -)"; - // clang-format on - - std::unique_ptr localContext = - BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text, - SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - EXPECT_NE(nullptr, localContext) << "Assembling failed for shader:\n" - << text << std::endl; - - DummyPass testPass; - std::vector processed; - Pass::ProcessFunction mark_visited = [&processed](Function* fp) { - processed.push_back(fp->result_id()); - return false; - }; - testPass.ProcessReachableCallTree(mark_visited, localContext.get()); - EXPECT_THAT(processed, UnorderedElementsAre(10, 11, 12, 13)); -} - -TEST_F(PassClassTest, BasicVisitOnlyOnce) { - // Make sure we visit %11 only once, even if it is called from two different - // functions. - const std::string text = R"( - OpCapability Shader - OpMemoryModel Logical GLSL450 - OpEntryPoint Fragment %10 "main" %gl_FragColor - OpName %10 "main" - OpName %Dead "Dead" - OpName %11 "Constant" - OpName %12 "ExportedFunc" - OpDecorate %12 LinkageAttributes "ExportedFunc" Export - %void = OpTypeVoid - %6 = OpTypeFunction %void - %10 = OpFunction %void None %6 - %14 = OpLabel - %15 = OpFunctionCall %void %11 - %16 = OpFunctionCall %void %12 - OpReturn - OpFunctionEnd - %11 = OpFunction %void None %6 - %18 = OpLabel - %19 = OpFunctionCall %void %12 - OpReturn - OpFunctionEnd - %Dead = OpFunction %void None %6 - %20 = OpLabel - OpReturn - OpFunctionEnd - %12 = OpFunction %void None %9 - %21 = OpLabel - OpReturn - OpFunctionEnd -)"; - // clang-format on - - std::unique_ptr localContext = - BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text, - SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - EXPECT_NE(nullptr, localContext) << "Assembling failed for shader:\n" - << text << std::endl; - - DummyPass testPass; - std::vector processed; - Pass::ProcessFunction mark_visited = [&processed](Function* fp) { - processed.push_back(fp->result_id()); - return false; - }; - testPass.ProcessReachableCallTree(mark_visited, localContext.get()); - EXPECT_THAT(processed, UnorderedElementsAre(10, 11, 12)); -} - -TEST_F(PassClassTest, BasicDontVisitExportedVariable) { - // Make sure we only visit functions and not exported variables. - const std::string text = R"( - OpCapability Shader - OpMemoryModel Logical GLSL450 - OpEntryPoint Fragment %10 "main" %gl_FragColor - OpExecutionMode %10 OriginUpperLeft - OpSource GLSL 150 - OpName %10 "main" - OpName %Dead "Dead" - OpName %11 "Constant" - OpName %12 "export_var" - OpDecorate %12 LinkageAttributes "export_var" Export - %void = OpTypeVoid - %6 = OpTypeFunction %void - %float = OpTypeFloat 32 - %float_1 = OpConstant %float 1 - %12 = OpVariable %float Output - %10 = OpFunction %void None %6 - %14 = OpLabel - OpStore %12 %float_1 - OpReturn - OpFunctionEnd -)"; - // clang-format on - - std::unique_ptr localContext = - BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text, - SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - EXPECT_NE(nullptr, localContext) << "Assembling failed for shader:\n" - << text << std::endl; - - DummyPass testPass; - std::vector processed; - Pass::ProcessFunction mark_visited = [&processed](Function* fp) { - processed.push_back(fp->result_id()); - return false; - }; - testPass.ProcessReachableCallTree(mark_visited, localContext.get()); - EXPECT_THAT(processed, UnorderedElementsAre(10)); -} - -} // namespace -} // namespace opt -} // namespace spvtools diff --git a/third_party/spirv-tools/test/opt/pass_utils.cpp b/third_party/spirv-tools/test/opt/pass_utils.cpp index ceb9996102..4709d0fd1e 100644 --- a/third_party/spirv-tools/test/opt/pass_utils.cpp +++ b/third_party/spirv-tools/test/opt/pass_utils.cpp @@ -35,6 +35,26 @@ const char* kDebugOpcodes[] = { } // anonymous namespace +MessageConsumer GetTestMessageConsumer( + std::vector& expected_messages) { + return [&expected_messages](spv_message_level_t level, const char* source, + const spv_position_t& position, + const char* message) { + EXPECT_TRUE(!expected_messages.empty()); + if (expected_messages.empty()) { + return; + } + + EXPECT_EQ(expected_messages[0].level, level); + EXPECT_EQ(expected_messages[0].line_number, position.line); + EXPECT_EQ(expected_messages[0].column_number, position.column); + EXPECT_STREQ(expected_messages[0].source_file, source); + EXPECT_STREQ(expected_messages[0].message, message); + + expected_messages.erase(expected_messages.begin()); + }; +} + bool FindAndReplace(std::string* process_str, const std::string find_str, const std::string replace_str) { if (process_str->empty() || find_str.empty()) { diff --git a/third_party/spirv-tools/test/opt/pass_utils.h b/third_party/spirv-tools/test/opt/pass_utils.h index 37406842a9..8968f8a64b 100644 --- a/third_party/spirv-tools/test/opt/pass_utils.h +++ b/third_party/spirv-tools/test/opt/pass_utils.h @@ -21,9 +21,25 @@ #include #include +#include "gtest/gtest.h" +#include "include/spirv-tools/libspirv.h" +#include "include/spirv-tools/libspirv.hpp" + namespace spvtools { namespace opt { +struct Message { + spv_message_level_t level; + const char* source_file; + uint32_t line_number; + uint32_t column_number; + const char* message; +}; + +// Return a message consumer that can be used to check that the message produced +// are the messages in |expexted_messages|, and in the same order. +MessageConsumer GetTestMessageConsumer(std::vector& expected_messages); + // In-place substring replacement. Finds the |find_str| in the |process_str| // and replaces the found substring with |replace_str|. Returns true if at // least one replacement is done successfully, returns false otherwise. The diff --git a/third_party/spirv-tools/test/opt/pch_test_opt.cpp b/third_party/spirv-tools/test/opt/pch_test_opt.cpp new file mode 100644 index 0000000000..f158129137 --- /dev/null +++ b/third_party/spirv-tools/test/opt/pch_test_opt.cpp @@ -0,0 +1,15 @@ +// Copyright (c) 2018 The Khronos Group Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "pch_test_opt.h" diff --git a/third_party/spirv-tools/test/opt/pch_test_opt.h b/third_party/spirv-tools/test/opt/pch_test_opt.h new file mode 100644 index 0000000000..4e8106fbfc --- /dev/null +++ b/third_party/spirv-tools/test/opt/pch_test_opt.h @@ -0,0 +1,25 @@ +// Copyright (c) 2018 The Khronos Group Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "gmock/gmock.h" +#include "source/opt/iterator.h" +#include "source/opt/loop_dependence.h" +#include "source/opt/loop_descriptor.h" +#include "source/opt/pass.h" +#include "source/opt/scalar_analysis.h" +#include "source/opt/tree_iterator.h" +#include "test/opt/assembly_builder.h" +#include "test/opt/function_utils.h" +#include "test/opt/pass_fixture.h" +#include "test/opt/pass_utils.h" diff --git a/third_party/spirv-tools/test/opt/private_to_local_test.cpp b/third_party/spirv-tools/test/opt/private_to_local_test.cpp index d7eb37e511..12306529ad 100644 --- a/third_party/spirv-tools/test/opt/private_to_local_test.cpp +++ b/third_party/spirv-tools/test/opt/private_to_local_test.cpp @@ -29,7 +29,6 @@ using ::testing::HasSubstr; using ::testing::MatchesRegex; using PrivateToLocalTest = PassTest<::testing::Test>; -#ifdef SPIRV_EFFCEE TEST_F(PrivateToLocalTest, ChangeToLocal) { // Change the private variable to a local, and change the types accordingly. const std::string text = R"( @@ -309,7 +308,149 @@ TEST_F(PrivateToLocalTest, CreatePointerToAmbiguousStruct2) { SinglePassRunAndMatch(text, false); } -#endif +TEST_F(PrivateToLocalTest, SPV14RemoveFromInterface) { + const std::string text = R"( +; CHECK-NOT: OpEntryPoint GLCompute %foo "foo" %in %priv +; CHECK: OpEntryPoint GLCompute %foo "foo" %in +; CHECK: %priv = OpVariable {{%\w+}} Function +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %foo "foo" %in %priv +OpExecutionMode %foo LocalSize 1 1 1 +OpName %foo "foo" +OpName %in "in" +OpName %priv "priv" +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%ptr_ssbo_int = OpTypePointer StorageBuffer %int +%ptr_private_int = OpTypePointer Private %int +%in = OpVariable %ptr_ssbo_int StorageBuffer +%priv = OpVariable %ptr_private_int Private +%void_fn = OpTypeFunction %void +%foo = OpFunction %void None %void_fn +%entry = OpLabel +%ld = OpLoad %int %in +OpStore %priv %ld +OpReturn +OpFunctionEnd +)"; + + SetTargetEnv(SPV_ENV_UNIVERSAL_1_4); + SinglePassRunAndMatch(text, true); +} + +TEST_F(PrivateToLocalTest, SPV14RemoveFromInterfaceMultipleEntryPoints) { + const std::string text = R"( +; CHECK-NOT: OpEntryPoint GLCompute %foo "foo" %in %priv +; CHECK-NOT: OpEntryPoint GLCompute %foo "bar" %in %priv +; CHECK: OpEntryPoint GLCompute %foo "foo" %in +; CHECK: OpEntryPoint GLCompute %foo "bar" %in +; CHECK: %priv = OpVariable {{%\w+}} Function +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %foo "foo" %in %priv +OpEntryPoint GLCompute %foo "bar" %in %priv +OpExecutionMode %foo LocalSize 1 1 1 +OpName %foo "foo" +OpName %in "in" +OpName %priv "priv" +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%ptr_ssbo_int = OpTypePointer StorageBuffer %int +%ptr_private_int = OpTypePointer Private %int +%in = OpVariable %ptr_ssbo_int StorageBuffer +%priv = OpVariable %ptr_private_int Private +%void_fn = OpTypeFunction %void +%foo = OpFunction %void None %void_fn +%entry = OpLabel +%ld = OpLoad %int %in +OpStore %priv %ld +OpReturn +OpFunctionEnd +)"; + + SetTargetEnv(SPV_ENV_UNIVERSAL_1_4); + SinglePassRunAndMatch(text, true); +} + +TEST_F(PrivateToLocalTest, SPV14RemoveFromInterfaceMultipleVariables) { + const std::string text = R"( +; CHECK-NOT: OpEntryPoint GLCompute %foo "foo" %in %priv1 %priv2 +; CHECK: OpEntryPoint GLCompute %foo "foo" %in +; CHECK: %priv1 = OpVariable {{%\w+}} Function +; CHECK: %priv2 = OpVariable {{%\w+}} Function +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %foo "foo" %in %priv1 %priv2 +OpExecutionMode %foo LocalSize 1 1 1 +OpName %foo "foo" +OpName %in "in" +OpName %priv1 "priv1" +OpName %priv2 "priv2" +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%ptr_ssbo_int = OpTypePointer StorageBuffer %int +%ptr_private_int = OpTypePointer Private %int +%in = OpVariable %ptr_ssbo_int StorageBuffer +%priv1 = OpVariable %ptr_private_int Private +%priv2 = OpVariable %ptr_private_int Private +%void_fn = OpTypeFunction %void +%foo = OpFunction %void None %void_fn +%entry = OpLabel +%1 = OpFunctionCall %void %bar1 +%2 = OpFunctionCall %void %bar2 +OpReturn +OpFunctionEnd +%bar1 = OpFunction %void None %void_fn +%3 = OpLabel +%ld1 = OpLoad %int %in +OpStore %priv1 %ld1 +OpReturn +OpFunctionEnd +%bar2 = OpFunction %void None %void_fn +%4 = OpLabel +%ld2 = OpLoad %int %in +OpStore %priv2 %ld2 +OpReturn +OpFunctionEnd +)"; + + SetTargetEnv(SPV_ENV_UNIVERSAL_1_4); + SinglePassRunAndMatch(text, true); +} + +TEST_F(PrivateToLocalTest, IdBoundOverflow1) { + const std::string text = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginLowerLeft + OpSource HLSL 84 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypeVector %6 4 + %8 = OpTypeStruct %7 + %4194302 = OpTypeStruct %8 %8 + %9 = OpTypeStruct %8 %8 + %11 = OpTypePointer Private %7 + %18 = OpTypeStruct %6 %9 + %12 = OpVariable %11 Private + %4 = OpFunction %2 None %3 + %5 = OpLabel + %13 = OpLoad %7 %12 + OpReturn + OpFunctionEnd + )"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + + std::vector messages = { + {SPV_MSG_ERROR, "", 0, 0, "ID overflow. Try running compact-ids."}}; + SetMessageConsumer(GetTestMessageConsumer(messages)); + auto result = SinglePassRunToBinary(text, true); + EXPECT_EQ(Pass::Status::Failure, std::get<1>(result)); +} } // namespace } // namespace opt diff --git a/third_party/spirv-tools/test/opt/process_lines_test.cpp b/third_party/spirv-tools/test/opt/process_lines_test.cpp new file mode 100644 index 0000000000..33ad4be891 --- /dev/null +++ b/third_party/spirv-tools/test/opt/process_lines_test.cpp @@ -0,0 +1,695 @@ +// Copyright (c) 2017 Valve Corporation +// Copyright (c) 2017 LunarG Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include + +#include "test/opt/pass_fixture.h" +#include "test/opt/pass_utils.h" + +namespace spvtools { +namespace opt { +namespace { + +using ProcessLinesTest = PassTest<::testing::Test>; + +TEST_F(ProcessLinesTest, SimplePropagation) { + // Texture2D g_tColor[128]; + // + // layout(push_constant) cbuffer PerViewConstantBuffer_t + // { + // uint g_nDataIdx; + // uint g_nDataIdx2; + // bool g_B; + // }; + // + // SamplerState g_sAniso; + // + // struct PS_INPUT + // { + // float2 vTextureCoords : TEXCOORD2; + // }; + // + // struct PS_OUTPUT + // { + // float4 vColor : SV_Target0; + // }; + // + // PS_OUTPUT MainPs(PS_INPUT i) + // { + // PS_OUTPUT ps_output; + // + // uint u; + // if (g_B) + // u = g_nDataIdx; + // else + // u = g_nDataIdx2; + // ps_output.vColor = g_tColor[u].Sample(g_sAniso, i.vTextureCoords.xy); + // return ps_output; + // } + + const std::string predefs = + R"(OpCapability Shader +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor +OpExecutionMode %MainPs OriginUpperLeft +%5 = OpString "foo.frag" +OpSource HLSL 500 +OpName %MainPs "MainPs" +OpName %PS_INPUT "PS_INPUT" +OpMemberName %PS_INPUT 0 "vTextureCoords" +OpName %PS_OUTPUT "PS_OUTPUT" +OpMemberName %PS_OUTPUT 0 "vColor" +OpName %_MainPs_struct_PS_INPUT_vf21_ "@MainPs(struct-PS_INPUT-vf21;" +OpName %i "i" +OpName %PerViewConstantBuffer_t "PerViewConstantBuffer_t" +OpMemberName %PerViewConstantBuffer_t 0 "g_nDataIdx" +OpMemberName %PerViewConstantBuffer_t 1 "g_nDataIdx2" +OpMemberName %PerViewConstantBuffer_t 2 "g_B" +OpName %_ "" +OpName %u "u" +OpName %ps_output "ps_output" +OpName %g_tColor "g_tColor" +OpName %g_sAniso "g_sAniso" +OpName %i_0 "i" +OpName %i_vTextureCoords "i.vTextureCoords" +OpName %_entryPointOutput_vColor "@entryPointOutput.vColor" +OpName %param "param" +OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0 +OpMemberDecorate %PerViewConstantBuffer_t 1 Offset 4 +OpMemberDecorate %PerViewConstantBuffer_t 2 Offset 8 +OpDecorate %PerViewConstantBuffer_t Block +OpDecorate %g_tColor DescriptorSet 0 +OpDecorate %g_sAniso DescriptorSet 0 +OpDecorate %i_vTextureCoords Location 0 +OpDecorate %_entryPointOutput_vColor Location 0 +)"; + + const std::string before = + R"(%void = OpTypeVoid +%19 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v2float = OpTypeVector %float 2 +%PS_INPUT = OpTypeStruct %v2float +%_ptr_Function_PS_INPUT = OpTypePointer Function %PS_INPUT +%v4float = OpTypeVector %float 4 +%PS_OUTPUT = OpTypeStruct %v4float +%24 = OpTypeFunction %PS_OUTPUT %_ptr_Function_PS_INPUT +%uint = OpTypeInt 32 0 +%PerViewConstantBuffer_t = OpTypeStruct %uint %uint %uint +%_ptr_PushConstant_PerViewConstantBuffer_t = OpTypePointer PushConstant %PerViewConstantBuffer_t +%_ = OpVariable %_ptr_PushConstant_PerViewConstantBuffer_t PushConstant +%int = OpTypeInt 32 1 +%int_2 = OpConstant %int 2 +%_ptr_PushConstant_uint = OpTypePointer PushConstant %uint +%bool = OpTypeBool +%uint_0 = OpConstant %uint 0 +%_ptr_Function_uint = OpTypePointer Function %uint +%int_0 = OpConstant %int 0 +%int_1 = OpConstant %int 1 +%_ptr_Function_PS_OUTPUT = OpTypePointer Function %PS_OUTPUT +%36 = OpTypeImage %float 2D 0 0 0 1 Unknown +%uint_128 = OpConstant %uint 128 +%_arr_36_uint_128 = OpTypeArray %36 %uint_128 +%_ptr_UniformConstant__arr_36_uint_128 = OpTypePointer UniformConstant %_arr_36_uint_128 +%g_tColor = OpVariable %_ptr_UniformConstant__arr_36_uint_128 UniformConstant +%_ptr_UniformConstant_36 = OpTypePointer UniformConstant %36 +%41 = OpTypeSampler +%_ptr_UniformConstant_41 = OpTypePointer UniformConstant %41 +%g_sAniso = OpVariable %_ptr_UniformConstant_41 UniformConstant +%43 = OpTypeSampledImage %36 +%_ptr_Function_v2float = OpTypePointer Function %v2float +%_ptr_Function_v4float = OpTypePointer Function %v4float +%_ptr_Input_v2float = OpTypePointer Input %v2float +%i_vTextureCoords = OpVariable %_ptr_Input_v2float Input +%_ptr_Output_v4float = OpTypePointer Output %v4float +%_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output +%MainPs = OpFunction %void None %19 +%48 = OpLabel +%i_0 = OpVariable %_ptr_Function_PS_INPUT Function +%param = OpVariable %_ptr_Function_PS_INPUT Function +OpLine %5 23 0 +%49 = OpLoad %v2float %i_vTextureCoords +%50 = OpAccessChain %_ptr_Function_v2float %i_0 %int_0 +OpStore %50 %49 +%51 = OpLoad %PS_INPUT %i_0 +OpStore %param %51 +%52 = OpFunctionCall %PS_OUTPUT %_MainPs_struct_PS_INPUT_vf21_ %param +%53 = OpCompositeExtract %v4float %52 0 +OpStore %_entryPointOutput_vColor %53 +OpReturn +OpFunctionEnd +%_MainPs_struct_PS_INPUT_vf21_ = OpFunction %PS_OUTPUT None %24 +%i = OpFunctionParameter %_ptr_Function_PS_INPUT +%54 = OpLabel +%u = OpVariable %_ptr_Function_uint Function +%ps_output = OpVariable %_ptr_Function_PS_OUTPUT Function +OpLine %5 27 0 +%55 = OpAccessChain %_ptr_PushConstant_uint %_ %int_2 +%56 = OpLoad %uint %55 +%57 = OpINotEqual %bool %56 %uint_0 +OpSelectionMerge %58 None +OpBranchConditional %57 %59 %60 +%59 = OpLabel +OpLine %5 28 0 +%61 = OpAccessChain %_ptr_PushConstant_uint %_ %int_0 +%62 = OpLoad %uint %61 +OpStore %u %62 +OpBranch %58 +%60 = OpLabel +OpLine %5 30 0 +%63 = OpAccessChain %_ptr_PushConstant_uint %_ %int_1 +%64 = OpLoad %uint %63 +OpStore %u %64 +OpBranch %58 +%58 = OpLabel +OpLine %5 31 0 +%65 = OpLoad %uint %u +%66 = OpAccessChain %_ptr_UniformConstant_36 %g_tColor %65 +%67 = OpLoad %36 %66 +%68 = OpLoad %41 %g_sAniso +%69 = OpSampledImage %43 %67 %68 +%70 = OpAccessChain %_ptr_Function_v2float %i %int_0 +%71 = OpLoad %v2float %70 +%72 = OpImageSampleImplicitLod %v4float %69 %71 +%73 = OpAccessChain %_ptr_Function_v4float %ps_output %int_0 +OpStore %73 %72 +OpLine %5 32 0 +%74 = OpLoad %PS_OUTPUT %ps_output +OpReturnValue %74 +OpFunctionEnd +)"; + + const std::string after = + R"(OpNoLine +%void = OpTypeVoid +OpNoLine +%19 = OpTypeFunction %void +OpNoLine +%float = OpTypeFloat 32 +OpNoLine +%v2float = OpTypeVector %float 2 +OpNoLine +%PS_INPUT = OpTypeStruct %v2float +OpNoLine +%_ptr_Function_PS_INPUT = OpTypePointer Function %PS_INPUT +OpNoLine +%v4float = OpTypeVector %float 4 +OpNoLine +%PS_OUTPUT = OpTypeStruct %v4float +OpNoLine +%24 = OpTypeFunction %PS_OUTPUT %_ptr_Function_PS_INPUT +OpNoLine +%uint = OpTypeInt 32 0 +OpNoLine +%PerViewConstantBuffer_t = OpTypeStruct %uint %uint %uint +OpNoLine +%_ptr_PushConstant_PerViewConstantBuffer_t = OpTypePointer PushConstant %PerViewConstantBuffer_t +OpNoLine +%_ = OpVariable %_ptr_PushConstant_PerViewConstantBuffer_t PushConstant +OpNoLine +%int = OpTypeInt 32 1 +OpNoLine +%int_2 = OpConstant %int 2 +OpNoLine +%_ptr_PushConstant_uint = OpTypePointer PushConstant %uint +OpNoLine +%bool = OpTypeBool +OpNoLine +%uint_0 = OpConstant %uint 0 +OpNoLine +%_ptr_Function_uint = OpTypePointer Function %uint +OpNoLine +%int_0 = OpConstant %int 0 +OpNoLine +%int_1 = OpConstant %int 1 +OpNoLine +%_ptr_Function_PS_OUTPUT = OpTypePointer Function %PS_OUTPUT +OpNoLine +%36 = OpTypeImage %float 2D 0 0 0 1 Unknown +OpNoLine +%uint_128 = OpConstant %uint 128 +OpNoLine +%_arr_36_uint_128 = OpTypeArray %36 %uint_128 +OpNoLine +%_ptr_UniformConstant__arr_36_uint_128 = OpTypePointer UniformConstant %_arr_36_uint_128 +OpNoLine +%g_tColor = OpVariable %_ptr_UniformConstant__arr_36_uint_128 UniformConstant +OpNoLine +%_ptr_UniformConstant_36 = OpTypePointer UniformConstant %36 +OpNoLine +%41 = OpTypeSampler +OpNoLine +%_ptr_UniformConstant_41 = OpTypePointer UniformConstant %41 +OpNoLine +%g_sAniso = OpVariable %_ptr_UniformConstant_41 UniformConstant +OpNoLine +%43 = OpTypeSampledImage %36 +OpNoLine +%_ptr_Function_v2float = OpTypePointer Function %v2float +OpNoLine +%_ptr_Function_v4float = OpTypePointer Function %v4float +OpNoLine +%_ptr_Input_v2float = OpTypePointer Input %v2float +OpNoLine +%i_vTextureCoords = OpVariable %_ptr_Input_v2float Input +OpNoLine +%_ptr_Output_v4float = OpTypePointer Output %v4float +OpNoLine +%_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output +OpNoLine +%MainPs = OpFunction %void None %19 +OpNoLine +%48 = OpLabel +OpNoLine +%i_0 = OpVariable %_ptr_Function_PS_INPUT Function +OpNoLine +%param = OpVariable %_ptr_Function_PS_INPUT Function +OpLine %5 23 0 +%49 = OpLoad %v2float %i_vTextureCoords +OpLine %5 23 0 +%50 = OpAccessChain %_ptr_Function_v2float %i_0 %int_0 +OpLine %5 23 0 +OpStore %50 %49 +OpLine %5 23 0 +%51 = OpLoad %PS_INPUT %i_0 +OpLine %5 23 0 +OpStore %param %51 +OpLine %5 23 0 +%52 = OpFunctionCall %PS_OUTPUT %_MainPs_struct_PS_INPUT_vf21_ %param +OpLine %5 23 0 +%53 = OpCompositeExtract %v4float %52 0 +OpLine %5 23 0 +OpStore %_entryPointOutput_vColor %53 +OpLine %5 23 0 +OpReturn +OpNoLine +OpFunctionEnd +OpNoLine +%_MainPs_struct_PS_INPUT_vf21_ = OpFunction %PS_OUTPUT None %24 +OpNoLine +%i = OpFunctionParameter %_ptr_Function_PS_INPUT +OpNoLine +%54 = OpLabel +OpNoLine +%u = OpVariable %_ptr_Function_uint Function +OpNoLine +%ps_output = OpVariable %_ptr_Function_PS_OUTPUT Function +OpLine %5 27 0 +%55 = OpAccessChain %_ptr_PushConstant_uint %_ %int_2 +OpLine %5 27 0 +%56 = OpLoad %uint %55 +OpLine %5 27 0 +%57 = OpINotEqual %bool %56 %uint_0 +OpLine %5 27 0 +OpSelectionMerge %58 None +OpBranchConditional %57 %59 %60 +OpNoLine +%59 = OpLabel +OpLine %5 28 0 +%61 = OpAccessChain %_ptr_PushConstant_uint %_ %int_0 +OpLine %5 28 0 +%62 = OpLoad %uint %61 +OpLine %5 28 0 +OpStore %u %62 +OpLine %5 28 0 +OpBranch %58 +OpNoLine +%60 = OpLabel +OpLine %5 30 0 +%63 = OpAccessChain %_ptr_PushConstant_uint %_ %int_1 +OpLine %5 30 0 +%64 = OpLoad %uint %63 +OpLine %5 30 0 +OpStore %u %64 +OpLine %5 30 0 +OpBranch %58 +OpNoLine +%58 = OpLabel +OpLine %5 31 0 +%65 = OpLoad %uint %u +OpLine %5 31 0 +%66 = OpAccessChain %_ptr_UniformConstant_36 %g_tColor %65 +OpLine %5 31 0 +%67 = OpLoad %36 %66 +OpLine %5 31 0 +%68 = OpLoad %41 %g_sAniso +OpLine %5 31 0 +%69 = OpSampledImage %43 %67 %68 +OpLine %5 31 0 +%70 = OpAccessChain %_ptr_Function_v2float %i %int_0 +OpLine %5 31 0 +%71 = OpLoad %v2float %70 +OpLine %5 31 0 +%72 = OpImageSampleImplicitLod %v4float %69 %71 +OpLine %5 31 0 +%73 = OpAccessChain %_ptr_Function_v4float %ps_output %int_0 +OpLine %5 31 0 +OpStore %73 %72 +OpLine %5 32 0 +%74 = OpLoad %PS_OUTPUT %ps_output +OpLine %5 32 0 +OpReturnValue %74 +OpNoLine +OpFunctionEnd +)"; + + SinglePassRunAndCheck(predefs + before, predefs + after, + false, true, kLinesPropagateLines); +} + +TEST_F(ProcessLinesTest, SimpleElimination) { + // Previous test with before and after reversed + + const std::string predefs = + R"(OpCapability Shader +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor +OpExecutionMode %MainPs OriginUpperLeft +%5 = OpString "foo.frag" +OpSource HLSL 500 +OpName %MainPs "MainPs" +OpName %PS_INPUT "PS_INPUT" +OpMemberName %PS_INPUT 0 "vTextureCoords" +OpName %PS_OUTPUT "PS_OUTPUT" +OpMemberName %PS_OUTPUT 0 "vColor" +OpName %_MainPs_struct_PS_INPUT_vf21_ "@MainPs(struct-PS_INPUT-vf21;" +OpName %i "i" +OpName %PerViewConstantBuffer_t "PerViewConstantBuffer_t" +OpMemberName %PerViewConstantBuffer_t 0 "g_nDataIdx" +OpMemberName %PerViewConstantBuffer_t 1 "g_nDataIdx2" +OpMemberName %PerViewConstantBuffer_t 2 "g_B" +OpName %_ "" +OpName %u "u" +OpName %ps_output "ps_output" +OpName %g_tColor "g_tColor" +OpName %g_sAniso "g_sAniso" +OpName %i_0 "i" +OpName %i_vTextureCoords "i.vTextureCoords" +OpName %_entryPointOutput_vColor "@entryPointOutput.vColor" +OpName %param "param" +OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0 +OpMemberDecorate %PerViewConstantBuffer_t 1 Offset 4 +OpMemberDecorate %PerViewConstantBuffer_t 2 Offset 8 +OpDecorate %PerViewConstantBuffer_t Block +OpDecorate %g_tColor DescriptorSet 0 +OpDecorate %g_sAniso DescriptorSet 0 +OpDecorate %i_vTextureCoords Location 0 +OpDecorate %_entryPointOutput_vColor Location 0 +)"; + + const std::string before = + R"(OpNoLine +%void = OpTypeVoid +OpNoLine +%19 = OpTypeFunction %void +OpNoLine +%float = OpTypeFloat 32 +OpNoLine +%v2float = OpTypeVector %float 2 +OpNoLine +%PS_INPUT = OpTypeStruct %v2float +OpNoLine +%_ptr_Function_PS_INPUT = OpTypePointer Function %PS_INPUT +OpNoLine +%v4float = OpTypeVector %float 4 +OpNoLine +%PS_OUTPUT = OpTypeStruct %v4float +OpNoLine +%24 = OpTypeFunction %PS_OUTPUT %_ptr_Function_PS_INPUT +OpNoLine +%uint = OpTypeInt 32 0 +OpNoLine +%PerViewConstantBuffer_t = OpTypeStruct %uint %uint %uint +OpNoLine +%_ptr_PushConstant_PerViewConstantBuffer_t = OpTypePointer PushConstant %PerViewConstantBuffer_t +OpNoLine +%_ = OpVariable %_ptr_PushConstant_PerViewConstantBuffer_t PushConstant +OpNoLine +%int = OpTypeInt 32 1 +OpNoLine +%int_2 = OpConstant %int 2 +OpNoLine +%_ptr_PushConstant_uint = OpTypePointer PushConstant %uint +OpNoLine +%bool = OpTypeBool +OpNoLine +%uint_0 = OpConstant %uint 0 +OpNoLine +%_ptr_Function_uint = OpTypePointer Function %uint +OpNoLine +%int_0 = OpConstant %int 0 +OpNoLine +%int_1 = OpConstant %int 1 +OpNoLine +%_ptr_Function_PS_OUTPUT = OpTypePointer Function %PS_OUTPUT +OpNoLine +%36 = OpTypeImage %float 2D 0 0 0 1 Unknown +OpNoLine +%uint_128 = OpConstant %uint 128 +OpNoLine +%_arr_36_uint_128 = OpTypeArray %36 %uint_128 +OpNoLine +%_ptr_UniformConstant__arr_36_uint_128 = OpTypePointer UniformConstant %_arr_36_uint_128 +OpNoLine +%g_tColor = OpVariable %_ptr_UniformConstant__arr_36_uint_128 UniformConstant +OpNoLine +%_ptr_UniformConstant_36 = OpTypePointer UniformConstant %36 +OpNoLine +%41 = OpTypeSampler +OpNoLine +%_ptr_UniformConstant_41 = OpTypePointer UniformConstant %41 +OpNoLine +%g_sAniso = OpVariable %_ptr_UniformConstant_41 UniformConstant +OpNoLine +%43 = OpTypeSampledImage %36 +OpNoLine +%_ptr_Function_v2float = OpTypePointer Function %v2float +OpNoLine +%_ptr_Function_v4float = OpTypePointer Function %v4float +OpNoLine +%_ptr_Input_v2float = OpTypePointer Input %v2float +OpNoLine +%i_vTextureCoords = OpVariable %_ptr_Input_v2float Input +OpNoLine +%_ptr_Output_v4float = OpTypePointer Output %v4float +OpNoLine +%_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output +OpNoLine +%MainPs = OpFunction %void None %19 +OpNoLine +%48 = OpLabel +OpNoLine +%i_0 = OpVariable %_ptr_Function_PS_INPUT Function +OpNoLine +%param = OpVariable %_ptr_Function_PS_INPUT Function +OpLine %5 23 0 +%49 = OpLoad %v2float %i_vTextureCoords +OpLine %5 23 0 +%50 = OpAccessChain %_ptr_Function_v2float %i_0 %int_0 +OpLine %5 23 0 +OpStore %50 %49 +OpLine %5 23 0 +%51 = OpLoad %PS_INPUT %i_0 +OpLine %5 23 0 +OpStore %param %51 +OpLine %5 23 0 +%52 = OpFunctionCall %PS_OUTPUT %_MainPs_struct_PS_INPUT_vf21_ %param +OpLine %5 23 0 +%53 = OpCompositeExtract %v4float %52 0 +OpLine %5 23 0 +OpStore %_entryPointOutput_vColor %53 +OpLine %5 23 0 +OpReturn +OpNoLine +OpFunctionEnd +OpNoLine +%_MainPs_struct_PS_INPUT_vf21_ = OpFunction %PS_OUTPUT None %24 +OpNoLine +%i = OpFunctionParameter %_ptr_Function_PS_INPUT +OpNoLine +%54 = OpLabel +OpNoLine +%u = OpVariable %_ptr_Function_uint Function +OpNoLine +%ps_output = OpVariable %_ptr_Function_PS_OUTPUT Function +OpLine %5 27 0 +%55 = OpAccessChain %_ptr_PushConstant_uint %_ %int_2 +OpLine %5 27 0 +%56 = OpLoad %uint %55 +OpLine %5 27 0 +%57 = OpINotEqual %bool %56 %uint_0 +OpLine %5 27 0 +OpSelectionMerge %58 None +OpBranchConditional %57 %59 %60 +OpNoLine +%59 = OpLabel +OpLine %5 28 0 +%61 = OpAccessChain %_ptr_PushConstant_uint %_ %int_0 +OpLine %5 28 0 +%62 = OpLoad %uint %61 +OpLine %5 28 0 +OpStore %u %62 +OpLine %5 28 0 +OpBranch %58 +OpNoLine +%60 = OpLabel +OpLine %5 30 0 +%63 = OpAccessChain %_ptr_PushConstant_uint %_ %int_1 +OpLine %5 30 0 +%64 = OpLoad %uint %63 +OpLine %5 30 0 +OpStore %u %64 +OpLine %5 30 0 +OpBranch %58 +OpNoLine +%58 = OpLabel +OpLine %5 31 0 +%65 = OpLoad %uint %u +OpLine %5 31 0 +%66 = OpAccessChain %_ptr_UniformConstant_36 %g_tColor %65 +OpLine %5 31 0 +%67 = OpLoad %36 %66 +OpLine %5 31 0 +%68 = OpLoad %41 %g_sAniso +OpLine %5 31 0 +%69 = OpSampledImage %43 %67 %68 +OpLine %5 31 0 +%70 = OpAccessChain %_ptr_Function_v2float %i %int_0 +OpLine %5 31 0 +%71 = OpLoad %v2float %70 +OpLine %5 31 0 +%72 = OpImageSampleImplicitLod %v4float %69 %71 +OpLine %5 31 0 +%73 = OpAccessChain %_ptr_Function_v4float %ps_output %int_0 +OpLine %5 31 0 +OpStore %73 %72 +OpLine %5 32 0 +%74 = OpLoad %PS_OUTPUT %ps_output +OpLine %5 32 0 +OpReturnValue %74 +OpNoLine +OpFunctionEnd +)"; + + const std::string after = + R"(%void = OpTypeVoid +%19 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v2float = OpTypeVector %float 2 +%PS_INPUT = OpTypeStruct %v2float +%_ptr_Function_PS_INPUT = OpTypePointer Function %PS_INPUT +%v4float = OpTypeVector %float 4 +%PS_OUTPUT = OpTypeStruct %v4float +%24 = OpTypeFunction %PS_OUTPUT %_ptr_Function_PS_INPUT +%uint = OpTypeInt 32 0 +%PerViewConstantBuffer_t = OpTypeStruct %uint %uint %uint +%_ptr_PushConstant_PerViewConstantBuffer_t = OpTypePointer PushConstant %PerViewConstantBuffer_t +%_ = OpVariable %_ptr_PushConstant_PerViewConstantBuffer_t PushConstant +%int = OpTypeInt 32 1 +%int_2 = OpConstant %int 2 +%_ptr_PushConstant_uint = OpTypePointer PushConstant %uint +%bool = OpTypeBool +%uint_0 = OpConstant %uint 0 +%_ptr_Function_uint = OpTypePointer Function %uint +%int_0 = OpConstant %int 0 +%int_1 = OpConstant %int 1 +%_ptr_Function_PS_OUTPUT = OpTypePointer Function %PS_OUTPUT +%36 = OpTypeImage %float 2D 0 0 0 1 Unknown +%uint_128 = OpConstant %uint 128 +%_arr_36_uint_128 = OpTypeArray %36 %uint_128 +%_ptr_UniformConstant__arr_36_uint_128 = OpTypePointer UniformConstant %_arr_36_uint_128 +%g_tColor = OpVariable %_ptr_UniformConstant__arr_36_uint_128 UniformConstant +%_ptr_UniformConstant_36 = OpTypePointer UniformConstant %36 +%41 = OpTypeSampler +%_ptr_UniformConstant_41 = OpTypePointer UniformConstant %41 +%g_sAniso = OpVariable %_ptr_UniformConstant_41 UniformConstant +%43 = OpTypeSampledImage %36 +%_ptr_Function_v2float = OpTypePointer Function %v2float +%_ptr_Function_v4float = OpTypePointer Function %v4float +%_ptr_Input_v2float = OpTypePointer Input %v2float +%i_vTextureCoords = OpVariable %_ptr_Input_v2float Input +%_ptr_Output_v4float = OpTypePointer Output %v4float +%_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output +%MainPs = OpFunction %void None %19 +%48 = OpLabel +%i_0 = OpVariable %_ptr_Function_PS_INPUT Function +%param = OpVariable %_ptr_Function_PS_INPUT Function +OpLine %5 23 0 +%49 = OpLoad %v2float %i_vTextureCoords +%50 = OpAccessChain %_ptr_Function_v2float %i_0 %int_0 +OpStore %50 %49 +%51 = OpLoad %PS_INPUT %i_0 +OpStore %param %51 +%52 = OpFunctionCall %PS_OUTPUT %_MainPs_struct_PS_INPUT_vf21_ %param +%53 = OpCompositeExtract %v4float %52 0 +OpStore %_entryPointOutput_vColor %53 +OpReturn +OpFunctionEnd +%_MainPs_struct_PS_INPUT_vf21_ = OpFunction %PS_OUTPUT None %24 +%i = OpFunctionParameter %_ptr_Function_PS_INPUT +%54 = OpLabel +%u = OpVariable %_ptr_Function_uint Function +%ps_output = OpVariable %_ptr_Function_PS_OUTPUT Function +OpLine %5 27 0 +%55 = OpAccessChain %_ptr_PushConstant_uint %_ %int_2 +%56 = OpLoad %uint %55 +%57 = OpINotEqual %bool %56 %uint_0 +OpSelectionMerge %58 None +OpBranchConditional %57 %59 %60 +%59 = OpLabel +OpLine %5 28 0 +%61 = OpAccessChain %_ptr_PushConstant_uint %_ %int_0 +%62 = OpLoad %uint %61 +OpStore %u %62 +OpBranch %58 +%60 = OpLabel +OpLine %5 30 0 +%63 = OpAccessChain %_ptr_PushConstant_uint %_ %int_1 +%64 = OpLoad %uint %63 +OpStore %u %64 +OpBranch %58 +%58 = OpLabel +OpLine %5 31 0 +%65 = OpLoad %uint %u +%66 = OpAccessChain %_ptr_UniformConstant_36 %g_tColor %65 +%67 = OpLoad %36 %66 +%68 = OpLoad %41 %g_sAniso +%69 = OpSampledImage %43 %67 %68 +%70 = OpAccessChain %_ptr_Function_v2float %i %int_0 +%71 = OpLoad %v2float %70 +%72 = OpImageSampleImplicitLod %v4float %69 %71 +%73 = OpAccessChain %_ptr_Function_v4float %ps_output %int_0 +OpStore %73 %72 +OpLine %5 32 0 +%74 = OpLoad %PS_OUTPUT %ps_output +OpReturnValue %74 +OpFunctionEnd +)"; + + SinglePassRunAndCheck( + predefs + before, predefs + after, false, true, kLinesEliminateDeadLines); +} + +// TODO(greg-lunarg): Add tests to verify handling of these cases: +// +// TODO(greg-lunarg): Think about other tests :) + +} // namespace +} // namespace opt +} // namespace spvtools diff --git a/third_party/spirv-tools/test/opt/reduce_load_size_test.cpp b/third_party/spirv-tools/test/opt/reduce_load_size_test.cpp index 1d367e101b..50dc5017ca 100644 --- a/third_party/spirv-tools/test/opt/reduce_load_size_test.cpp +++ b/third_party/spirv-tools/test/opt/reduce_load_size_test.cpp @@ -23,7 +23,6 @@ namespace { using ReduceLoadSizeTest = PassTest<::testing::Test>; -#ifdef SPIRV_EFFCEE TEST_F(ReduceLoadSizeTest, cbuffer_load_extract) { // Originally from the following HLSL: // struct S { @@ -107,7 +106,6 @@ TEST_F(ReduceLoadSizeTest, cbuffer_load_extract) { SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES); SinglePassRunAndMatch(test, false); } -#endif TEST_F(ReduceLoadSizeTest, cbuffer_load_extract_vector) { // Originally from the following HLSL: diff --git a/third_party/spirv-tools/test/opt/redundancy_elimination_test.cpp b/third_party/spirv-tools/test/opt/redundancy_elimination_test.cpp index a6e8c4f28a..7d2abe846c 100644 --- a/third_party/spirv-tools/test/opt/redundancy_elimination_test.cpp +++ b/third_party/spirv-tools/test/opt/redundancy_elimination_test.cpp @@ -29,7 +29,6 @@ using ::testing::HasSubstr; using ::testing::MatchesRegex; using RedundancyEliminationTest = PassTest<::testing::Test>; -#ifdef SPIRV_EFFCEE // Test that it can get a simple case of local redundancy elimination. // The rest of the test check for extra functionality. TEST_F(RedundancyEliminationTest, RemoveRedundantLocalAdd) { @@ -273,8 +272,6 @@ TEST_F(RedundancyEliminationTest, KeepRedundantAddWithoutPhi) { EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)); } -#endif - } // namespace } // namespace opt } // namespace spvtools diff --git a/third_party/spirv-tools/test/opt/register_liveness.cpp b/third_party/spirv-tools/test/opt/register_liveness.cpp index cb973d2e6b..7cb210f1e5 100644 --- a/third_party/spirv-tools/test/opt/register_liveness.cpp +++ b/third_party/spirv-tools/test/opt/register_liveness.cpp @@ -1277,6 +1277,46 @@ TEST_F(PassClassTest, FissionSimulation) { } } +// Test that register liveness does not fail when there is an unreachable block. +// We are not testing if the liveness is computed correctly because the specific +// results do not matter for unreachable blocks. +TEST_F(PassClassTest, RegisterLivenessWithUnreachableBlock) { + const std::string text = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginLowerLeft + OpSource GLSL 330 + OpSourceExtension "GL_ARB_shading_language_420pack" + %void = OpTypeVoid + %4 = OpTypeFunction %void + %2 = OpFunction %void None %4 + %5 = OpLabel + OpBranch %6 + %6 = OpLabel + OpLoopMerge %7 %8 None + OpBranch %9 + %9 = OpLabel + OpBranch %7 + %8 = OpLabel + OpBranch %6 + %7 = OpLabel + OpReturn + OpFunctionEnd + )"; + + std::unique_ptr context = + BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + Module* module = context->module(); + EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n" + << text << std::endl; + Function* f = &*module->begin(); + LivenessAnalysis* liveness_analysis = context->GetLivenessAnalysis(); + liveness_analysis->Get(f); +} + } // namespace } // namespace opt } // namespace spvtools diff --git a/third_party/spirv-tools/test/opt/relax_float_ops_test.cpp b/third_party/spirv-tools/test/opt/relax_float_ops_test.cpp new file mode 100644 index 0000000000..14cde0b94d --- /dev/null +++ b/third_party/spirv-tools/test/opt/relax_float_ops_test.cpp @@ -0,0 +1,142 @@ +// Copyright (c) 2019 Valve Corporation +// Copyright (c) 2019 LunarG Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Relax float ops tests + +#include +#include + +#include "test/opt/assembly_builder.h" +#include "test/opt/pass_fixture.h" +#include "test/opt/pass_utils.h" + +namespace spvtools { +namespace opt { +namespace { + +using RelaxFloatOpsTest = PassTest<::testing::Test>; + +TEST_F(RelaxFloatOpsTest, RelaxFloatOpsBasic) { + // All float result instructions in functions should be relaxed + // clang-format off + // + // SamplerState g_sSamp : register(s0); + // uniform Texture1D g_tTex1df4 : register(t0); + // + // struct PS_INPUT + // { + // float Tex0 : TEXCOORD0; + // float Tex1 : TEXCOORD1; + // }; + // + // struct PS_OUTPUT + // { + // float4 Color : SV_Target0; + // }; + // + // PS_OUTPUT main(PS_INPUT i) + // { + // PS_OUTPUT psout; + // float4 txval10 = g_tTex1df4.Sample(g_sSamp, i.Tex0); + // float4 txval11 = g_tTex1df4.Sample(g_sSamp, i.Tex1); + // float4 t = txval10 + txval11; + // float4 t2 = t / 2.0; + // psout.Color = t2; + // return psout; + // } + // clang-format on + + const std::string defs0 = + R"(OpCapability Shader +OpCapability Sampled1D +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %i_Tex0 %i_Tex1 %_entryPointOutput_Color +OpExecutionMode %main OriginUpperLeft +OpSource HLSL 500 +OpName %main "main" +OpName %g_tTex1df4 "g_tTex1df4" +OpName %g_sSamp "g_sSamp" +OpName %i_Tex0 "i.Tex0" +OpName %i_Tex1 "i.Tex1" +OpName %_entryPointOutput_Color "@entryPointOutput.Color" +OpDecorate %g_tTex1df4 DescriptorSet 0 +OpDecorate %g_tTex1df4 Binding 0 +OpDecorate %g_sSamp DescriptorSet 0 +OpDecorate %g_sSamp Binding 0 +OpDecorate %i_Tex0 Location 0 +OpDecorate %i_Tex1 Location 1 +OpDecorate %_entryPointOutput_Color Location 0 +)"; + + const std::string defs1 = + R"(%void = OpTypeVoid +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v4float = OpTypeVector %float 4 +%17 = OpTypeImage %float 1D 0 0 0 1 Unknown +%_ptr_UniformConstant_17 = OpTypePointer UniformConstant %17 +%g_tTex1df4 = OpVariable %_ptr_UniformConstant_17 UniformConstant +%21 = OpTypeSampler +%_ptr_UniformConstant_21 = OpTypePointer UniformConstant %21 +%g_sSamp = OpVariable %_ptr_UniformConstant_21 UniformConstant +%25 = OpTypeSampledImage %17 +%_ptr_Input_float = OpTypePointer Input %float +%i_Tex0 = OpVariable %_ptr_Input_float Input +%i_Tex1 = OpVariable %_ptr_Input_float Input +%_ptr_Output_v4float = OpTypePointer Output %v4float +%_entryPointOutput_Color = OpVariable %_ptr_Output_v4float Output +%float_0_5 = OpConstant %float 0.5 +%116 = OpConstantComposite %v4float %float_0_5 %float_0_5 %float_0_5 %float_0_5 +)"; + + const std::string relax_decos = + R"(OpDecorate %60 RelaxedPrecision +OpDecorate %63 RelaxedPrecision +OpDecorate %82 RelaxedPrecision +OpDecorate %88 RelaxedPrecision +OpDecorate %91 RelaxedPrecision +OpDecorate %94 RelaxedPrecision +)"; + + const std::string func_orig = + R"(%main = OpFunction %void None %3 +%5 = OpLabel +%60 = OpLoad %float %i_Tex0 +%63 = OpLoad %float %i_Tex1 +%77 = OpLoad %17 %g_tTex1df4 +%78 = OpLoad %21 %g_sSamp +%79 = OpSampledImage %25 %77 %78 +%82 = OpImageSampleImplicitLod %v4float %79 %60 +%83 = OpLoad %17 %g_tTex1df4 +%84 = OpLoad %21 %g_sSamp +%85 = OpSampledImage %25 %83 %84 +%88 = OpImageSampleImplicitLod %v4float %85 %63 +%91 = OpFAdd %v4float %82 %88 +%94 = OpFMul %v4float %91 %116 +OpStore %_entryPointOutput_Color %94 +OpReturn +OpFunctionEnd +)"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck( + defs0 + defs1 + func_orig, defs0 + relax_decos + defs1 + func_orig, true, + true); +} + +} // namespace +} // namespace opt +} // namespace spvtools diff --git a/third_party/spirv-tools/test/opt/replace_invalid_opc_test.cpp b/third_party/spirv-tools/test/opt/replace_invalid_opc_test.cpp index adfe2ee1e9..1be904b4e4 100644 --- a/third_party/spirv-tools/test/opt/replace_invalid_opc_test.cpp +++ b/third_party/spirv-tools/test/opt/replace_invalid_opc_test.cpp @@ -17,6 +17,7 @@ #include #include "gmock/gmock.h" +#include "pass_utils.h" #include "test/opt/assembly_builder.h" #include "test/opt/pass_fixture.h" @@ -26,7 +27,6 @@ namespace { using ReplaceInvalidOpcodeTest = PassTest<::testing::Test>; -#ifdef SPIRV_EFFCEE TEST_F(ReplaceInvalidOpcodeTest, ReplaceInstruction) { const std::string text = R"( ; CHECK: [[special_const:%\w+]] = OpConstant %float -6.2598534e+18 @@ -435,34 +435,6 @@ TEST_F(ReplaceInvalidOpcodeTest, BarrierReplace) { SinglePassRunAndMatch(text, false); } -struct Message { - spv_message_level_t level; - const char* source_file; - uint32_t line_number; - uint32_t column_number; - const char* message; -}; - -MessageConsumer GetTestMessageConsumer( - std::vector& expected_messages) { - return [&expected_messages](spv_message_level_t level, const char* source, - const spv_position_t& position, - const char* message) { - EXPECT_TRUE(!expected_messages.empty()); - if (expected_messages.empty()) { - return; - } - - EXPECT_EQ(expected_messages[0].level, level); - EXPECT_EQ(expected_messages[0].line_number, position.line); - EXPECT_EQ(expected_messages[0].column_number, position.column); - EXPECT_STREQ(expected_messages[0].source_file, source); - EXPECT_STREQ(expected_messages[0].message, message); - - expected_messages.erase(expected_messages.begin()); - }; -} - TEST_F(ReplaceInvalidOpcodeTest, MessageTest) { const std::string text = R"( OpCapability Shader @@ -589,8 +561,6 @@ TEST_F(ReplaceInvalidOpcodeTest, MultipleMessageTest) { EXPECT_EQ(Pass::Status::SuccessWithChange, std::get<1>(result)); } -#endif - } // namespace } // namespace opt } // namespace spvtools diff --git a/third_party/spirv-tools/test/opt/scalar_replacement_test.cpp b/third_party/spirv-tools/test/opt/scalar_replacement_test.cpp index 652978bb06..3cf46ca13d 100644 --- a/third_party/spirv-tools/test/opt/scalar_replacement_test.cpp +++ b/third_party/spirv-tools/test/opt/scalar_replacement_test.cpp @@ -25,8 +25,6 @@ namespace { using ScalarReplacementTest = PassTest<::testing::Test>; -// TODO(dneto): Add Effcee as required dependency, and make this unconditional. -#ifdef SPIRV_EFFCEE TEST_F(ScalarReplacementTest, SimpleStruct) { const std::string text = R"( ; @@ -1151,7 +1149,6 @@ TEST_F(ScalarReplacementTest, NoPartialAccesses2) { ; CHECK: OpVariable [[float_ptr]] Function ; CHECK: OpVariable [[float_ptr]] Function ; CHECK: OpVariable [[float_ptr]] Function -; CHECK: OpVariable [[float_ptr]] Function ; CHECK-NOT: OpVariable ; OpCapability Shader @@ -1404,6 +1401,42 @@ OpFunctionEnd SinglePassRunAndMatch(text, true); } +TEST_F(ScalarReplacementTest, SpecConstantArray) { + const std::string text = R"( +; CHECK: [[int:%\w+]] = OpTypeInt +; CHECK: [[spec_const:%\w+]] = OpSpecConstant [[int]] 4 +; CHECK: [[spec_op:%\w+]] = OpSpecConstantOp [[int]] IAdd [[spec_const]] [[spec_const]] +; CHECK: [[array1:%\w+]] = OpTypeArray [[int]] [[spec_const]] +; CHECK: [[array2:%\w+]] = OpTypeArray [[int]] [[spec_op]] +; CHECK: [[ptr_array1:%\w+]] = OpTypePointer Function [[array1]] +; CHECK: [[ptr_array2:%\w+]] = OpTypePointer Function [[array2]] +; CHECK: OpLabel +; CHECK-NEXT: OpVariable [[ptr_array1]] Function +; CHECK-NEXT: OpVariable [[ptr_array2]] Function +; CHECK-NOT: OpVariable +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%int = OpTypeInt 32 0 +%spec_const = OpSpecConstant %int 4 +%spec_op = OpSpecConstantOp %int IAdd %spec_const %spec_const +%array_1 = OpTypeArray %int %spec_const +%array_2 = OpTypeArray %int %spec_op +%ptr_array_1_Function = OpTypePointer Function %array_1 +%ptr_array_2_Function = OpTypePointer Function %array_2 +%func = OpFunction %void None %void_fn +%1 = OpLabel +%var_1 = OpVariable %ptr_array_1_Function Function +%var_2 = OpVariable %ptr_array_2_Function Function +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + TEST_F(ScalarReplacementTest, CreateAmbiguousNullConstant2) { const std::string text = R"( ; @@ -1448,7 +1481,6 @@ OpFunctionEnd SinglePassRunAndMatch(text, true); } -#endif // SPIRV_EFFCEE // Test that a struct of size 4 is not replaced when there is a limit of 2. TEST_F(ScalarReplacementTest, TestLimit) { @@ -1522,6 +1554,351 @@ OpFunctionEnd EXPECT_EQ(Pass::Status::SuccessWithChange, std::get<1>(result)); } +TEST_F(ScalarReplacementTest, AmbigousPointer) { + const std::string text = R"( +; CHECK: [[s1:%\w+]] = OpTypeStruct %uint +; CHECK: [[s2:%\w+]] = OpTypeStruct %uint +; CHECK: [[s3:%\w+]] = OpTypeStruct [[s2]] +; CHECK: [[s3_const:%\w+]] = OpConstantComposite [[s3]] +; CHECK: [[s2_ptr:%\w+]] = OpTypePointer Function [[s2]] +; CHECK: OpCompositeExtract [[s2]] [[s3_const]] + + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpSource ESSL 310 + %void = OpTypeVoid + %5 = OpTypeFunction %void + %uint = OpTypeInt 32 0 + %_struct_7 = OpTypeStruct %uint + %_struct_8 = OpTypeStruct %uint + %_struct_9 = OpTypeStruct %_struct_8 + %uint_1 = OpConstant %uint 1 + %11 = OpConstantComposite %_struct_8 %uint_1 + %12 = OpConstantComposite %_struct_9 %11 +%_ptr_Function__struct_9 = OpTypePointer Function %_struct_9 +%_ptr_Function__struct_7 = OpTypePointer Function %_struct_7 + %2 = OpFunction %void None %5 + %15 = OpLabel + %var = OpVariable %_ptr_Function__struct_9 Function + OpStore %var %12 + %ld = OpLoad %_struct_9 %var + %ex = OpCompositeExtract %_struct_8 %ld 0 + OpReturn + OpFunctionEnd + )"; + + SinglePassRunAndMatch(text, true); +} + +// Test that scalar replacement does not crash when there is an OpAccessChain +// with no index. If we choose to handle this case in the future, then the +// result can change. +TEST_F(ScalarReplacementTest, TestAccessChainWithNoIndexes) { + const std::string text = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "main" + OpExecutionMode %1 OriginLowerLeft + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %_struct_5 = OpTypeStruct %float +%_ptr_Function__struct_5 = OpTypePointer Function %_struct_5 + %1 = OpFunction %void None %3 + %7 = OpLabel + %8 = OpVariable %_ptr_Function__struct_5 Function + %9 = OpAccessChain %_ptr_Function__struct_5 %8 + OpReturn + OpFunctionEnd + )"; + + auto result = + SinglePassRunAndDisassemble(text, true, false); + EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)); +} + +// Test that id overflow is handled gracefully. +TEST_F(ScalarReplacementTest, IdBoundOverflow1) { + const std::string text = R"( +OpCapability ImageQuery +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %4 "main" +OpExecutionMode %4 OriginUpperLeft +OpDecorate %4194302 DescriptorSet 1073495039 +%2 = OpTypeVoid +%3 = OpTypeFunction %2 +%6 = OpTypeFloat 32 +%7 = OpTypeStruct %6 %6 +%557056 = OpTypeStruct %7 +%9 = OpTypePointer Function %7 +%18 = OpTypeFunction %7 %9 +%4 = OpFunction %2 Pure|Const %3 +%1836763 = OpLabel +%4194302 = OpVariable %9 Function +%10 = OpVariable %9 Function +OpKill +%4194301 = OpLabel +%524296 = OpLoad %7 %4194302 +OpKill +OpFunctionEnd + )"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + + std::vector messages = { + {SPV_MSG_ERROR, "", 0, 0, "ID overflow. Try running compact-ids."}, + {SPV_MSG_ERROR, "", 0, 0, "ID overflow. Try running compact-ids."}}; + SetMessageConsumer(GetTestMessageConsumer(messages)); + auto result = SinglePassRunToBinary(text, true, false); + EXPECT_EQ(Pass::Status::Failure, std::get<1>(result)); +} + +// Test that id overflow is handled gracefully. +TEST_F(ScalarReplacementTest, IdBoundOverflow2) { + const std::string text = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %4 "main" %17 +OpExecutionMode %4 OriginUpperLeft +%2 = OpTypeVoid +%3 = OpTypeFunction %2 +%6 = OpTypeFloat 32 +%7 = OpTypeVector %6 4 +%8 = OpTypeStruct %7 +%9 = OpTypePointer Function %8 +%16 = OpTypePointer Output %7 +%21 = OpTypeInt 32 1 +%22 = OpConstant %21 0 +%23 = OpTypePointer Function %7 +%17 = OpVariable %16 Output +%4 = OpFunction %2 None %3 +%5 = OpLabel +%4194300 = OpVariable %23 Function +%10 = OpVariable %9 Function +%4194301 = OpAccessChain %23 %10 %22 +%4194302 = OpLoad %7 %4194301 +OpStore %4194300 %4194302 +%15 = OpLoad %7 %4194300 +OpStore %17 %15 +OpReturn +OpFunctionEnd + )"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + + std::vector messages = { + {SPV_MSG_ERROR, "", 0, 0, "ID overflow. Try running compact-ids."}}; + SetMessageConsumer(GetTestMessageConsumer(messages)); + auto result = SinglePassRunToBinary(text, true, false); + EXPECT_EQ(Pass::Status::Failure, std::get<1>(result)); +} + +// Test that id overflow is handled gracefully. +TEST_F(ScalarReplacementTest, IdBoundOverflow3) { + const std::string text = R"( +OpCapability InterpolationFunction +OpExtension "z" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %4 "main" +OpExecutionMode %4 OriginUpperLeft +%2 = OpTypeVoid +%3 = OpTypeFunction %2 +%6 = OpTypeFloat 32 +%7 = OpTypeStruct %6 %6 +%9 = OpTypePointer Function %7 +%18 = OpTypeFunction %7 %9 +%21 = OpTypeInt 32 0 +%22 = OpConstant %21 4293000676 +%4194302 = OpConstantNull %6 +%4 = OpFunction %2 Inline|Pure %3 +%786464 = OpLabel +%4194298 = OpVariable %9 Function +%10 = OpVariable %9 Function +%4194299 = OpUDiv %21 %22 %22 +%4194300 = OpLoad %7 %10 +%50959 = OpLoad %7 %4194298 +OpKill +OpFunctionEnd +%1 = OpFunction %7 None %18 +%19 = OpFunctionParameter %9 +%147667 = OpLabel +%2044391 = OpUDiv %21 %22 %22 +%25 = OpLoad %7 %19 +OpReturnValue %25 +OpFunctionEnd +%4194295 = OpFunction %2 None %3 +%4194296 = OpLabel +OpKill +OpFunctionEnd + )"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + + std::vector messages = { + {SPV_MSG_ERROR, "", 0, 0, "ID overflow. Try running compact-ids."}, + {SPV_MSG_ERROR, "", 0, 0, "ID overflow. Try running compact-ids."}, + {SPV_MSG_ERROR, "", 0, 0, "ID overflow. Try running compact-ids."}, + {SPV_MSG_ERROR, "", 0, 0, "ID overflow. Try running compact-ids."}, + {SPV_MSG_ERROR, "", 0, 0, "ID overflow. Try running compact-ids."}, + {SPV_MSG_ERROR, "", 0, 0, "ID overflow. Try running compact-ids."}, + {SPV_MSG_ERROR, "", 0, 0, "ID overflow. Try running compact-ids."}, + {SPV_MSG_ERROR, "", 0, 0, "ID overflow. Try running compact-ids."}, + {SPV_MSG_ERROR, "", 0, 0, "ID overflow. Try running compact-ids."}}; + SetMessageConsumer(GetTestMessageConsumer(messages)); + auto result = SinglePassRunToBinary(text, true, false); + EXPECT_EQ(Pass::Status::Failure, std::get<1>(result)); +} + +// Test that replacements for OpAccessChain do not go out of bounds. +// https://github.com/KhronosGroup/SPIRV-Tools/issues/2609. +TEST_F(ScalarReplacementTest, OutOfBoundOpAccessChain) { + const std::string text = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %_GLF_color + OpExecutionMode %main OriginUpperLeft + OpSource ESSL 310 + OpName %main "main" + OpName %a "a" + OpName %_GLF_color "_GLF_color" + OpDecorate %_GLF_color Location 0 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %int = OpTypeInt 32 1 +%_ptr_Function_int = OpTypePointer Function %int + %int_1 = OpConstant %int 1 + %float = OpTypeFloat 32 + %uint = OpTypeInt 32 0 + %uint_1 = OpConstant %uint 1 +%_arr_float_uint_1 = OpTypeArray %float %uint_1 +%_ptr_Function__arr_float_uint_1 = OpTypePointer Function %_arr_float_uint_1 +%_ptr_Function_float = OpTypePointer Function %float +%_ptr_Output_float = OpTypePointer Output %float + %_GLF_color = OpVariable %_ptr_Output_float Output + %main = OpFunction %void None %3 + %5 = OpLabel + %a = OpVariable %_ptr_Function__arr_float_uint_1 Function + %21 = OpAccessChain %_ptr_Function_float %a %int_1 + %22 = OpLoad %float %21 + OpStore %_GLF_color %22 + OpReturn + OpFunctionEnd + )"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + + auto result = + SinglePassRunAndDisassemble(text, true, false); + EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)); +} + +TEST_F(ScalarReplacementTest, CharIndex) { + const std::string text = R"( +; CHECK: [[int:%\w+]] = OpTypeInt 32 0 +; CHECK: [[ptr:%\w+]] = OpTypePointer Function [[int]] +; CHECK: OpVariable [[ptr]] Function +OpCapability Shader +OpCapability Int8 +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_1024 = OpConstant %int 1024 +%char = OpTypeInt 8 0 +%char_1 = OpConstant %char 1 +%array = OpTypeArray %int %int_1024 +%ptr_func_array = OpTypePointer Function %array +%ptr_func_int = OpTypePointer Function %int +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%var = OpVariable %ptr_func_array Function +%gep = OpAccessChain %ptr_func_int %var %char_1 +OpStore %gep %int_1024 +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true, 0); +} + +TEST_F(ScalarReplacementTest, OutOfBoundsOpAccessChainNegative) { + const std::string text = R"( +OpCapability Shader +OpCapability Int8 +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_1024 = OpConstant %int 1024 +%char = OpTypeInt 8 1 +%char_n1 = OpConstant %char -1 +%array = OpTypeArray %int %int_1024 +%ptr_func_array = OpTypePointer Function %array +%ptr_func_int = OpTypePointer Function %int +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%var = OpVariable %ptr_func_array Function +%gep = OpAccessChain %ptr_func_int %var %char_n1 +OpStore %gep %int_1024 +OpReturn +OpFunctionEnd +)"; + + auto result = + SinglePassRunAndDisassemble(text, true, true, 0); + EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)); +} + +TEST_F(ScalarReplacementTest, RelaxedPrecisionMemberDecoration) { + const std::string text = R"( +; CHECK: OpDecorate {{%\w+}} RelaxedPrecision +; CHECK: OpDecorate [[new_var:%\w+]] RelaxedPrecision +; CHECK: [[new_var]] = OpVariable %_ptr_Function_v3float Function +; CHECK: OpLoad %v3float [[new_var]] + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %1 "Draw2DTexCol_VS" %2 %3 + OpSource HLSL 600 + OpDecorate %2 Location 0 + OpDecorate %3 Location 1 + OpDecorate %3 RelaxedPrecision + OpMemberDecorate %_struct_4 1 RelaxedPrecision + %float = OpTypeFloat 32 + %int = OpTypeInt 32 1 + %int_1 = OpConstant %int 1 + %v3float = OpTypeVector %float 3 +%_ptr_Input_v3float = OpTypePointer Input %v3float + %void = OpTypeVoid + %11 = OpTypeFunction %void + %_struct_4 = OpTypeStruct %v3float %v3float +%_ptr_Function__struct_4 = OpTypePointer Function %_struct_4 +%_ptr_Function_v3float = OpTypePointer Function %v3float + %2 = OpVariable %_ptr_Input_v3float Input + %3 = OpVariable %_ptr_Input_v3float Input + %1 = OpFunction %void None %11 + %14 = OpLabel + %15 = OpVariable %_ptr_Function__struct_4 Function + %16 = OpLoad %v3float %2 + %17 = OpLoad %v3float %3 + %18 = OpCompositeConstruct %_struct_4 %16 %17 + OpStore %15 %18 + %19 = OpAccessChain %_ptr_Function_v3float %15 %int_1 + %20 = OpLoad %v3float %19 + OpReturn + OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + } // namespace } // namespace opt } // namespace spvtools diff --git a/third_party/spirv-tools/test/opt/set_spec_const_default_value_test.cpp b/third_party/spirv-tools/test/opt/set_spec_const_default_value_test.cpp index 161674fe02..5e63862e9a 100644 --- a/third_party/spirv-tools/test/opt/set_spec_const_default_value_test.cpp +++ b/third_party/spirv-tools/test/opt/set_spec_const_default_value_test.cpp @@ -50,7 +50,7 @@ TEST_P(DefaultValuesStringParsingTest, TestCase) { } } -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( ValidString, DefaultValuesStringParsingTest, ::testing::ValuesIn(std::vector{ // 0. empty map @@ -93,7 +93,7 @@ INSTANTIATE_TEST_CASE_P( {"100:1.5e-13", true, SpecIdToValueStrMap{{100, "1.5e-13"}}}, })); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( InvalidString, DefaultValuesStringParsingTest, ::testing::ValuesIn(std::vector{ // 0. missing default value @@ -148,7 +148,7 @@ TEST_P(SetSpecConstantDefaultValueInStringFormParamTest, TestCase) { tc.code, tc.expected, /* skip_nop = */ false, tc.default_values); } -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( ValidCases, SetSpecConstantDefaultValueInStringFormParamTest, ::testing::ValuesIn(std::vector< SetSpecConstantDefaultValueInStringFormTestCase>{ @@ -445,7 +445,7 @@ INSTANTIATE_TEST_CASE_P( }, })); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( InvalidCases, SetSpecConstantDefaultValueInStringFormParamTest, ::testing::ValuesIn(std::vector< SetSpecConstantDefaultValueInStringFormTestCase>{ @@ -610,7 +610,7 @@ TEST_P(SetSpecConstantDefaultValueInBitPatternFormParamTest, TestCase) { tc.code, tc.expected, /* skip_nop = */ false, tc.default_values); } -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( ValidCases, SetSpecConstantDefaultValueInBitPatternFormParamTest, ::testing::ValuesIn(std::vector< SetSpecConstantDefaultValueInBitPatternFormTestCase>{ @@ -937,7 +937,7 @@ INSTANTIATE_TEST_CASE_P( }, })); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( InvalidCases, SetSpecConstantDefaultValueInBitPatternFormParamTest, ::testing::ValuesIn(std::vector< SetSpecConstantDefaultValueInBitPatternFormTestCase>{ diff --git a/third_party/spirv-tools/test/opt/simplification_test.cpp b/third_party/spirv-tools/test/opt/simplification_test.cpp index b5ad26790a..7a9696eab4 100644 --- a/third_party/spirv-tools/test/opt/simplification_test.cpp +++ b/third_party/spirv-tools/test/opt/simplification_test.cpp @@ -25,7 +25,6 @@ namespace { using SimplificationTest = PassTest<::testing::Test>; -#ifdef SPIRV_EFFCEE TEST_F(SimplificationTest, StraightLineTest) { // Testing that folding rules are combined in simple straight line code. const std::string text = R"(OpCapability Shader @@ -72,6 +71,41 @@ TEST_F(SimplificationTest, StraightLineTest) { SinglePassRunAndMatch(text, false); } +TEST_F(SimplificationTest, NewInstructionTest) { + // Testing that new instructions are simplified. Specifically, + // that the new add instruction generated by FactorAddMul is + // further simplified by MergeGenericAddSub. + const std::string text = R"(OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" + OpExecutionMode %main OriginUpperLeft + OpSource GLSL 430 + OpName %main "main" + %void = OpTypeVoid + %4 = OpTypeFunction %void + %int = OpTypeInt 32 1 + %_ptr_int = OpTypePointer Function %int +; CHECK: [[mul:%[a-zA-Z_\d]+]] = OpIMul %int %13 %11 + %main = OpFunction %void None %4 + %7 = OpLabel + %8 = OpVariable %_ptr_int Function + %9 = OpVariable %_ptr_int Function + %10 = OpVariable %_ptr_int Function + %11 = OpLoad %int %8 + %12 = OpLoad %int %9 + %13 = OpLoad %int %10 + %14 = OpISub %int %11 %12 + %15 = OpIMul %int %13 %11 + %16 = OpIMul %int %13 %12 + %17 = OpIAdd %int %14 %15 + OpReturn + OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, false); +} + TEST_F(SimplificationTest, AcrossBasicBlocks) { // Testing that folding rules are combined across basic blocks. const std::string text = R"(OpCapability Shader @@ -203,7 +237,128 @@ TEST_F(SimplificationTest, ThroughLoops) { SinglePassRunAndMatch(text, false); } -#endif +TEST_F(SimplificationTest, CopyObjectWithDecorations1) { + // Don't simplify OpCopyObject if the result id has a decoration that the + // operand does not. + const std::string text = R"(OpCapability Shader +OpCapability ShaderNonUniform +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %2 "main" +OpExecutionMode %2 OriginUpperLeft +OpSource GLSL 430 +OpSourceExtension "GL_GOOGLE_cpp_style_line_directive" +OpSourceExtension "GL_GOOGLE_include_directive" +OpDecorate %3 NonUniform +%void = OpTypeVoid +%5 = OpTypeFunction %void +%int = OpTypeInt 32 1 +%2 = OpFunction %void None %5 +%7 = OpLabel +%8 = OpUndef %int +%3 = OpCopyObject %int %8 +%9 = OpIAdd %int %3 %3 +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndCheck(text, text, false); +} + +TEST_F(SimplificationTest, CopyObjectWithDecorations2) { + // Simplify OpCopyObject if the result id is a subset of the decorations of + // the operand. + const std::string before = R"(OpCapability Shader +OpCapability ShaderNonUniform +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %2 "main" +OpExecutionMode %2 OriginUpperLeft +OpSource GLSL 430 +OpSourceExtension "GL_GOOGLE_cpp_style_line_directive" +OpSourceExtension "GL_GOOGLE_include_directive" +OpDecorate %3 NonUniform +%void = OpTypeVoid +%5 = OpTypeFunction %void +%int = OpTypeInt 32 1 +%2 = OpFunction %void None %5 +%7 = OpLabel +%3 = OpUndef %int +%8 = OpCopyObject %int %3 +%9 = OpIAdd %int %8 %8 +OpReturn +OpFunctionEnd +)"; + + const std::string after = R"(OpCapability Shader +OpCapability ShaderNonUniform +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %2 "main" +OpExecutionMode %2 OriginUpperLeft +OpSource GLSL 430 +OpSourceExtension "GL_GOOGLE_cpp_style_line_directive" +OpSourceExtension "GL_GOOGLE_include_directive" +OpDecorate %3 NonUniform +%void = OpTypeVoid +%5 = OpTypeFunction %void +%int = OpTypeInt 32 1 +%2 = OpFunction %void None %5 +%7 = OpLabel +%3 = OpUndef %int +%9 = OpIAdd %int %3 %3 +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndCheck(before, after, false); +} + +TEST_F(SimplificationTest, DontMoveDecorations) { + const std::string spirv = R"( +; CHECK-NOT: RelaxedPrecision +; CHECK: [[sub:%\w+]] = OpFSub +; CHECK: OpStore {{.*}} [[sub]] +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %add RelaxedPrecision +OpDecorate %block Block +OpMemberDecorate %block 0 Offset 0 +OpMemberDecorate %block 1 Offset 4 +OpDecorate %in DescriptorSet 0 +OpDecorate %in Binding 0 +OpDecorate %out DescriptorSet 0 +OpDecorate %out Binding 1 +%void = OpTypeVoid +%float = OpTypeFloat 32 +%void_fn = OpTypeFunction %void +%block = OpTypeStruct %float %float +%ptr_ssbo_block = OpTypePointer StorageBuffer %block +%in = OpVariable %ptr_ssbo_block StorageBuffer +%out = OpVariable %ptr_ssbo_block StorageBuffer +%ptr_ssbo_float = OpTypePointer StorageBuffer %float +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%int_1 = OpConstant %int 1 +%float_0 = OpConstant %float 0 +%main = OpFunction %void None %void_fn +%entry = OpLabel +%in_gep_0 = OpAccessChain %ptr_ssbo_float %in %int_0 +%in_gep_1 = OpAccessChain %ptr_ssbo_float %in %int_1 +%load_0 = OpLoad %float %in_gep_0 +%load_1 = OpLoad %float %in_gep_1 +%sub = OpFSub %float %load_0 %load_1 +%add = OpFAdd %float %float_0 %sub +%out_gep_0 = OpAccessChain %ptr_ssbo_float %out %int_0 +OpStore %out_gep_0 %add +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(spirv, true); +} } // namespace } // namespace opt diff --git a/third_party/spirv-tools/test/opt/split_invalid_unreachable_test.cpp b/third_party/spirv-tools/test/opt/split_invalid_unreachable_test.cpp new file mode 100644 index 0000000000..520af0154b --- /dev/null +++ b/third_party/spirv-tools/test/opt/split_invalid_unreachable_test.cpp @@ -0,0 +1,155 @@ +// Copyright (c) 2019 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 + +#include "test/opt/pass_fixture.h" +#include "test/opt/pass_utils.h" + +namespace spvtools { +namespace opt { +namespace { + +using SplitInvalidUnreachableTest = PassTest<::testing::Test>; + +std::string spirv_header = R"(OpCapability Shader +OpCapability VulkanMemoryModel +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical Vulkan +OpEntryPoint Vertex %1 "shader" +%uint = OpTypeInt 32 0 +%uint_1 = OpConstant %uint 1 +%uint_2 = OpConstant %uint 2 +%void = OpTypeVoid +%bool = OpTypeBool +%7 = OpTypeFunction %void +)"; + +std::string function_head = R"(%1 = OpFunction %void None %7 +%8 = OpLabel +OpBranch %9 +)"; + +std::string function_tail = "OpFunctionEnd\n"; + +std::string GetLoopMergeBlock(std::string block_id, std::string merge_id, + std::string continue_id, std::string body_id) { + std::string result; + result += block_id + " = OpLabel\n"; + result += "OpLoopMerge " + merge_id + " " + continue_id + " None\n"; + result += "OpBranch " + body_id + "\n"; + return result; +} + +std::string GetSelectionMergeBlock(std::string block_id, + std::string condition_id, + std::string merge_id, std::string true_id, + std::string false_id) { + std::string result; + result += block_id + " = OpLabel\n"; + result += condition_id + " = OpSLessThan %bool %uint_1 %uint_2\n"; + result += "OpSelectionMerge " + merge_id + " None\n"; + result += "OpBranchConditional " + condition_id + " " + true_id + " " + + false_id + "\n"; + + return result; +} + +std::string GetReturnBlock(std::string block_id) { + std::string result; + result += block_id + " = OpLabel\n"; + result += "OpReturn\n"; + return result; +} + +std::string GetUnreachableBlock(std::string block_id) { + std::string result; + result += block_id + " = OpLabel\n"; + result += "OpUnreachable\n"; + return result; +} + +std::string GetBranchBlock(std::string block_id, std::string target_id) { + std::string result; + result += block_id + " = OpLabel\n"; + result += "OpBranch " + target_id + "\n"; + return result; +} + +TEST_F(SplitInvalidUnreachableTest, NoInvalidBlocks) { + std::string input = spirv_header + function_head; + input += GetLoopMergeBlock("%9", "%10", "%11", "%12"); + input += GetSelectionMergeBlock("%12", "%13", "%14", "%15", "%16"); + input += GetReturnBlock("%15"); + input += GetReturnBlock("%16"); + input += GetUnreachableBlock("%10"); + input += GetBranchBlock("%11", "%9"); + input += GetUnreachableBlock("%14"); + input += function_tail; + + SinglePassRunAndCheck(input, input, + /* skip_nop = */ false); +} + +TEST_F(SplitInvalidUnreachableTest, SelectionInLoop) { + std::string input = spirv_header + function_head; + input += GetLoopMergeBlock("%9", "%10", "%11", "%12"); + input += GetSelectionMergeBlock("%12", "%13", "%11", "%15", "%16"); + input += GetReturnBlock("%15"); + input += GetReturnBlock("%16"); + input += GetUnreachableBlock("%10"); + input += GetBranchBlock("%11", "%9"); + input += function_tail; + + std::string expected = spirv_header + function_head; + expected += GetLoopMergeBlock("%9", "%10", "%11", "%12"); + expected += GetSelectionMergeBlock("%12", "%13", "%16", "%14", "%15"); + expected += GetReturnBlock("%14"); + expected += GetReturnBlock("%15"); + expected += GetUnreachableBlock("%10"); + expected += GetUnreachableBlock("%16"); + expected += GetBranchBlock("%11", "%9"); + expected += function_tail; + + SinglePassRunAndCheck(input, expected, + /* skip_nop = */ false); +} + +TEST_F(SplitInvalidUnreachableTest, LoopInSelection) { + std::string input = spirv_header + function_head; + input += GetSelectionMergeBlock("%9", "%10", "%11", "%12", "%13"); + input += GetLoopMergeBlock("%12", "%14", "%11", "%15"); + input += GetReturnBlock("%13"); + input += GetUnreachableBlock("%14"); + input += GetBranchBlock("%11", "%12"); + input += GetReturnBlock("%15"); + input += function_tail; + + std::string expected = spirv_header + function_head; + expected += GetSelectionMergeBlock("%9", "%10", "%16", "%12", "%13"); + expected += GetLoopMergeBlock("%12", "%14", "%11", "%15"); + expected += GetReturnBlock("%13"); + expected += GetUnreachableBlock("%14"); + expected += GetUnreachableBlock("%16"); + expected += GetBranchBlock("%11", "%12"); + expected += GetReturnBlock("%15"); + expected += function_tail; + + SinglePassRunAndCheck(input, expected, + /* skip_nop = */ false); +} + +} // namespace +} // namespace opt +} // namespace spvtools diff --git a/third_party/spirv-tools/test/opt/strength_reduction_test.cpp b/third_party/spirv-tools/test/opt/strength_reduction_test.cpp index 654c90df95..31d0503605 100644 --- a/third_party/spirv-tools/test/opt/strength_reduction_test.cpp +++ b/third_party/spirv-tools/test/opt/strength_reduction_test.cpp @@ -65,7 +65,6 @@ TEST_F(StrengthReductionBasicTest, BasicReplaceMulBy8) { } // TODO(dneto): Add Effcee as required dependency, and make this unconditional. -#ifdef SPIRV_EFFCEE // Test to make sure we replace 16*5 // Also demonstrate use of Effcee matching. TEST_F(StrengthReductionBasicTest, BasicReplaceMulBy16) { @@ -102,7 +101,6 @@ TEST_F(StrengthReductionBasicTest, BasicReplaceMulBy16) { SinglePassRunAndMatch(text, false); } -#endif // Test to make sure we replace a multiple of 32 and 4. TEST_F(StrengthReductionBasicTest, BasicTwoPowersOf2) { diff --git a/third_party/spirv-tools/test/opt/strip_atomic_counter_memory_test.cpp b/third_party/spirv-tools/test/opt/strip_atomic_counter_memory_test.cpp new file mode 100644 index 0000000000..90daa59c1d --- /dev/null +++ b/third_party/spirv-tools/test/opt/strip_atomic_counter_memory_test.cpp @@ -0,0 +1,406 @@ +// Copyright (c) 2019 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 + +#include "test/opt/pass_fixture.h" +#include "test/opt/pass_utils.h" + +namespace spvtools { +namespace opt { +namespace { + +typedef std::tuple StripAtomicCounterMemoryParam; + +using MemorySemanticsModified = + PassTest<::testing::TestWithParam>; +using NonMemorySemanticsUnmodifiedTest = PassTest<::testing::Test>; + +void operator+=(std::vector& lhs, const char* rhs) { + lhs.push_back(rhs); +} + +std::string GetConstDecl(std::string val) { + std::string decl; + decl += "%uint_" + val + " = OpConstant %uint " + val; + return decl; +} + +std::string GetUnchangedString(std::string(generate_inst)(std::string), + std::string val) { + std::string decl = GetConstDecl(val); + std::string inst = generate_inst(val); + + std::vector result = { + // clang-format off + "OpCapability Shader", + "OpCapability VulkanMemoryModel", + "OpExtension \"SPV_KHR_vulkan_memory_model\"", + "OpMemoryModel Logical Vulkan", + "OpEntryPoint Vertex %1 \"shader\"", + "%uint = OpTypeInt 32 0", +"%_ptr_Workgroup_uint = OpTypePointer Workgroup %uint", + "%4 = OpVariable %_ptr_Workgroup_uint Workgroup", + "%uint_0 = OpConstant %uint 0", + "%uint_1 = OpConstant %uint 1", + "%void = OpTypeVoid", + "%8 = OpTypeFunction %void", + decl.c_str(), + "%1 = OpFunction %void None %8", + "%10 = OpLabel", + inst.c_str(), + "OpReturn", + "OpFunctionEnd" + // clang-format on + }; + return JoinAllInsts(result); +} + +std::string GetChangedString(std::string(generate_inst)(std::string), + std::string orig, std::string changed) { + std::string orig_decl = GetConstDecl(orig); + std::string changed_decl = GetConstDecl(changed); + std::string inst = generate_inst(changed); + + std::vector result = { + // clang-format off + "OpCapability Shader", + "OpCapability VulkanMemoryModel", + "OpExtension \"SPV_KHR_vulkan_memory_model\"", + "OpMemoryModel Logical Vulkan", + "OpEntryPoint Vertex %1 \"shader\"", + "%uint = OpTypeInt 32 0", +"%_ptr_Workgroup_uint = OpTypePointer Workgroup %uint", + "%4 = OpVariable %_ptr_Workgroup_uint Workgroup", + "%uint_0 = OpConstant %uint 0", + "%uint_1 = OpConstant %uint 1", + "%void = OpTypeVoid", + "%8 = OpTypeFunction %void", + orig_decl.c_str() }; + // clang-format on + if (changed != "0") result += changed_decl.c_str(); + result += "%1 = OpFunction %void None %8"; + result += "%10 = OpLabel"; + result += inst.c_str(); + result += "OpReturn"; + result += "OpFunctionEnd"; + return JoinAllInsts(result); +} + +std::tuple GetInputAndExpected( + std::string(generate_inst)(std::string), + StripAtomicCounterMemoryParam param) { + std::string orig = std::get<0>(param); + std::string changed = std::get<1>(param); + std::string input = GetUnchangedString(generate_inst, orig); + std::string expected = orig == changed + ? GetUnchangedString(generate_inst, changed) + : GetChangedString(generate_inst, orig, changed); + return std::make_tuple(input, expected); +} + +std::string GetOpControlBarrierInst(std::string val) { + return "OpControlBarrier %uint_1 %uint_1 %uint_" + val; +} + +TEST_P(MemorySemanticsModified, OpControlBarrier) { + std::string input, expected; + std::tie(input, expected) = + GetInputAndExpected(GetOpControlBarrierInst, GetParam()); + SinglePassRunAndCheck(input, expected, + /* skip_nop = */ false); +} + +std::string GetOpMemoryBarrierInst(std::string val) { + return "OpMemoryBarrier %uint_1 %uint_" + val; +} + +TEST_P(MemorySemanticsModified, OpMemoryBarrier) { + std::string input, expected; + std::tie(input, expected) = + GetInputAndExpected(GetOpMemoryBarrierInst, GetParam()); + SinglePassRunAndCheck(input, expected, + /* skip_nop = */ false); +} + +std::string GetOpAtomicLoadInst(std::string val) { + return "%11 = OpAtomicLoad %uint %4 %uint_1 %uint_" + val; +} + +TEST_P(MemorySemanticsModified, OpAtomicLoad) { + std::string input, expected; + std::tie(input, expected) = + GetInputAndExpected(GetOpAtomicLoadInst, GetParam()); + SinglePassRunAndCheck(input, expected, + /* skip_nop = */ false); +} + +std::string GetOpAtomicStoreInst(std::string val) { + return "OpAtomicStore %4 %uint_1 %uint_" + val + " %uint_1"; +} + +TEST_P(MemorySemanticsModified, OpAtomicStore) { + std::string input, expected; + std::tie(input, expected) = + GetInputAndExpected(GetOpAtomicStoreInst, GetParam()); + SinglePassRunAndCheck(input, expected, + /* skip_nop = */ false); +} + +std::string GetOpAtomicExchangeInst(std::string val) { + return "%11 = OpAtomicExchange %uint %4 %uint_1 %uint_" + val + " %uint_0"; +} + +TEST_P(MemorySemanticsModified, OpAtomicExchange) { + std::string input, expected; + std::tie(input, expected) = + GetInputAndExpected(GetOpAtomicExchangeInst, GetParam()); + SinglePassRunAndCheck(input, expected, + /* skip_nop = */ false); +} + +std::string GetOpAtomicCompareExchangeInst(std::string val) { + return "%11 = OpAtomicCompareExchange %uint %4 %uint_1 %uint_" + val + + " %uint_" + val + " %uint_0 %uint_0"; +} + +TEST_P(MemorySemanticsModified, OpAtomicCompareExchange) { + std::string input, expected; + std::tie(input, expected) = + GetInputAndExpected(GetOpAtomicCompareExchangeInst, GetParam()); + SinglePassRunAndCheck(input, expected, + /* skip_nop = */ false); +} + +std::string GetOpAtomicCompareExchangeWeakInst(std::string val) { + return "%11 = OpAtomicCompareExchangeWeak %uint %4 %uint_1 %uint_" + val + + " %uint_" + val + " %uint_0 %uint_0"; +} + +TEST_P(MemorySemanticsModified, OpAtomicCompareExchangeWeak) { + std::string input, expected; + std::tie(input, expected) = + GetInputAndExpected(GetOpAtomicCompareExchangeWeakInst, GetParam()); + SinglePassRunAndCheck(input, expected, + /* skip_nop = */ false); +} + +std::string GetOpAtomicIIncrementInst(std::string val) { + return "%11 = OpAtomicIIncrement %uint %4 %uint_1 %uint_" + val; +} + +TEST_P(MemorySemanticsModified, OpAtomicIIncrement) { + std::string input, expected; + std::tie(input, expected) = + GetInputAndExpected(GetOpAtomicIIncrementInst, GetParam()); + SinglePassRunAndCheck(input, expected, + /* skip_nop = */ false); +} + +std::string GetOpAtomicIDecrementInst(std::string val) { + return "%11 = OpAtomicIDecrement %uint %4 %uint_1 %uint_" + val; +} + +TEST_P(MemorySemanticsModified, OpAtomicIDecrement) { + std::string input, expected; + std::tie(input, expected) = + GetInputAndExpected(GetOpAtomicIDecrementInst, GetParam()); + SinglePassRunAndCheck(input, expected, + /* skip_nop = */ false); +} + +std::string GetOpAtomicIAddInst(std::string val) { + return "%11 = OpAtomicIAdd %uint %4 %uint_1 %uint_" + val + " %uint_1"; +} + +TEST_P(MemorySemanticsModified, OpAtomicIAdd) { + std::string input, expected; + std::tie(input, expected) = + GetInputAndExpected(GetOpAtomicIAddInst, GetParam()); + SinglePassRunAndCheck(input, expected, + /* skip_nop = */ false); +} + +std::string GetOpAtomicISubInst(std::string val) { + return "%11 = OpAtomicISub %uint %4 %uint_1 %uint_" + val + " %uint_1"; +} + +TEST_P(MemorySemanticsModified, OpAtomicISub) { + std::string input, expected; + std::tie(input, expected) = + GetInputAndExpected(GetOpAtomicISubInst, GetParam()); + SinglePassRunAndCheck(input, expected, + /* skip_nop = */ false); +} + +std::string GetOpAtomicSMinInst(std::string val) { + return "%11 = OpAtomicSMin %uint %4 %uint_1 %uint_" + val + " %uint_1"; +} + +TEST_P(MemorySemanticsModified, OpAtomicSMin) { + std::string input, expected; + std::tie(input, expected) = + GetInputAndExpected(GetOpAtomicSMinInst, GetParam()); + SinglePassRunAndCheck(input, expected, + /* skip_nop = */ false); +} + +std::string GetOpAtomicUMinInst(std::string val) { + return "%11 = OpAtomicUMin %uint %4 %uint_1 %uint_" + val + " %uint_1"; +} + +TEST_P(MemorySemanticsModified, OpAtomicUMin) { + std::string input, expected; + std::tie(input, expected) = + GetInputAndExpected(GetOpAtomicUMinInst, GetParam()); + SinglePassRunAndCheck(input, expected, + /* skip_nop = */ false); +} + +std::string GetOpAtomicSMaxInst(std::string val) { + return "%11 = OpAtomicSMax %uint %4 %uint_1 %uint_" + val + " %uint_1"; +} + +TEST_P(MemorySemanticsModified, OpAtomicSMax) { + std::string input, expected; + std::tie(input, expected) = + GetInputAndExpected(GetOpAtomicSMaxInst, GetParam()); + SinglePassRunAndCheck(input, expected, + /* skip_nop = */ false); +} + +std::string GetOpAtomicUMaxInst(std::string val) { + return "%11 = OpAtomicUMax %uint %4 %uint_1 %uint_" + val + " %uint_1"; +} + +TEST_P(MemorySemanticsModified, OpAtomicUMax) { + std::string input, expected; + std::tie(input, expected) = + GetInputAndExpected(GetOpAtomicUMaxInst, GetParam()); + SinglePassRunAndCheck(input, expected, + /* skip_nop = */ false); +} + +std::string GetOpAtomicAndInst(std::string val) { + return "%11 = OpAtomicAnd %uint %4 %uint_1 %uint_" + val + " %uint_1"; +} + +TEST_P(MemorySemanticsModified, OpAtomicAnd) { + std::string input, expected; + std::tie(input, expected) = + GetInputAndExpected(GetOpAtomicAndInst, GetParam()); + SinglePassRunAndCheck(input, expected, + /* skip_nop = */ false); +} + +std::string GetOpAtomicOrInst(std::string val) { + return "%11 = OpAtomicOr %uint %4 %uint_1 %uint_" + val + " %uint_1"; +} + +TEST_P(MemorySemanticsModified, OpAtomicOr) { + std::string input, expected; + std::tie(input, expected) = + GetInputAndExpected(GetOpAtomicOrInst, GetParam()); + SinglePassRunAndCheck(input, expected, + /* skip_nop = */ false); +} + +std::string GetOpAtomicXorInst(std::string val) { + return "%11 = OpAtomicXor %uint %4 %uint_1 %uint_" + val + " %uint_1"; +} + +TEST_P(MemorySemanticsModified, OpAtomicXor) { + std::string input, expected; + std::tie(input, expected) = + GetInputAndExpected(GetOpAtomicXorInst, GetParam()); + SinglePassRunAndCheck(input, expected, + /* skip_nop = */ false); +} + +std::string GetOpAtomicFlagTestAndSetInst(std::string val) { + return "%11 = OpAtomicFlagTestAndSet %uint %4 %uint_1 %uint_" + val; +} + +TEST_P(MemorySemanticsModified, OpAtomicFlagTestAndSet) { + std::string input, expected; + std::tie(input, expected) = + GetInputAndExpected(GetOpAtomicFlagTestAndSetInst, GetParam()); + SinglePassRunAndCheck(input, expected, + /* skip_nop = */ false); +} + +std::string GetOpAtomicFlagClearInst(std::string val) { + return "OpAtomicFlagClear %4 %uint_1 %uint_" + val; +} + +TEST_P(MemorySemanticsModified, OpAtomicFlagClear) { + std::string input, expected; + std::tie(input, expected) = + GetInputAndExpected(GetOpAtomicFlagClearInst, GetParam()); + SinglePassRunAndCheck(input, expected, + /* skip_nop = */ false); +} + +std::string GetOpMemoryNamedBarrierInst(std::string val) { + return "OpMemoryNamedBarrier %4 %uint_1 %uint_" + val; +} + +TEST_P(MemorySemanticsModified, OpMemoryNamedBarrier) { + std::string input, expected; + std::tie(input, expected) = + GetInputAndExpected(GetOpMemoryNamedBarrierInst, GetParam()); + SinglePassRunAndCheck(input, expected, + /* skip_nop = */ false); +} + +// clang-format off +INSTANTIATE_TEST_SUITE_P( + StripAtomicCounterMemoryTest, MemorySemanticsModified, + ::testing::ValuesIn(std::vector({ + std::make_tuple("1024", "0"), + std::make_tuple("5", "5"), + std::make_tuple("1288", "264"), + std::make_tuple("264", "264") + }))); +// clang-format on + +std::string GetNoMemorySemanticsPresentInst(std::string val) { + return "%11 = OpVariable %_ptr_Workgroup_uint Workgroup %uint_" + val; +} + +TEST_F(NonMemorySemanticsUnmodifiedTest, NoMemorySemanticsPresent) { + std::string input, expected; + StripAtomicCounterMemoryParam param = std::make_tuple("1288", "1288"); + std::tie(input, expected) = + GetInputAndExpected(GetNoMemorySemanticsPresentInst, param); + SinglePassRunAndCheck(input, expected, + /* skip_nop = */ false); +} + +std::string GetMemorySemanticsPresentInst(std::string val) { + return "%11 = OpAtomicIAdd %uint %4 %uint_1 %uint_" + val + " %uint_1288"; +} + +TEST_F(NonMemorySemanticsUnmodifiedTest, MemorySemanticsPresent) { + std::string input, expected; + StripAtomicCounterMemoryParam param = std::make_tuple("1288", "264"); + std::tie(input, expected) = + GetInputAndExpected(GetMemorySemanticsPresentInst, param); + SinglePassRunAndCheck(input, expected, + /* skip_nop = */ false); +} + +} // namespace +} // namespace opt +} // namespace spvtools diff --git a/third_party/spirv-tools/test/opt/strip_debug_info_test.cpp b/third_party/spirv-tools/test/opt/strip_debug_info_test.cpp index f40ed382a6..088bba986e 100644 --- a/third_party/spirv-tools/test/opt/strip_debug_info_test.cpp +++ b/third_party/spirv-tools/test/opt/strip_debug_info_test.cpp @@ -51,6 +51,8 @@ TEST_F(StripLineDebugInfoTest, LineNoLine) { "OpLine %3 4 4", "OpNoLine", "OpFunctionEnd", + "OpNoLine", + "OpLine %3 4 5" // clang-format on }; SinglePassRunAndCheck(JoinAllInsts(text), @@ -74,6 +76,129 @@ TEST_F(StripLineDebugInfoTest, LineNoLine) { /* skip_nop = */ false); } +using StripDebugStringTest = PassTest<::testing::Test>; + +TEST_F(StripDebugStringTest, OpDecorateRemoved) { + std::vector input{ + // clang-format off + "OpCapability Shader", + "%1 = OpExtInstImport \"GLSL.std.450\"", + "OpMemoryModel Logical GLSL450", + "OpEntryPoint Vertex %2 \"main\"", + "%3 = OpString \"minimal.vert\"", + "OpDecorate %3 Location 1337", + "%void = OpTypeVoid", + "%5 = OpTypeFunction %void", + "%2 = OpFunction %void None %5", + "%6 = OpLabel", + "OpReturn", + "OpFunctionEnd", + // clang-format on + }; + std::vector output{ + // clang-format off + "OpCapability Shader", + "%1 = OpExtInstImport \"GLSL.std.450\"", + "OpMemoryModel Logical GLSL450", + "OpEntryPoint Vertex %2 \"main\"", + "%void = OpTypeVoid", + "%5 = OpTypeFunction %void", + "%2 = OpFunction %void None %5", + "%6 = OpLabel", + "OpReturn", + "OpFunctionEnd", + // clang-format on + }; + SinglePassRunAndCheck(JoinAllInsts(input), + JoinAllInsts(output), + /* skip_nop = */ false, + /* do_validation */ true); +} + +TEST_F(StripDebugStringTest, OpNameRemoved) { + std::vector input{ + // clang-format off + "OpCapability Shader", + "%1 = OpExtInstImport \"GLSL.std.450\"", + "OpMemoryModel Logical GLSL450", + "OpEntryPoint Vertex %2 \"main\"", + "%3 = OpString \"minimal.vert\"", + "OpName %3 \"bob\"", + "%void = OpTypeVoid", + "%5 = OpTypeFunction %void", + "%2 = OpFunction %void None %5", + "%6 = OpLabel", + "OpReturn", + "OpFunctionEnd", + // clang-format on + }; + std::vector output{ + // clang-format off + "OpCapability Shader", + "%1 = OpExtInstImport \"GLSL.std.450\"", + "OpMemoryModel Logical GLSL450", + "OpEntryPoint Vertex %2 \"main\"", + "%void = OpTypeVoid", + "%5 = OpTypeFunction %void", + "%2 = OpFunction %void None %5", + "%6 = OpLabel", + "OpReturn", + "OpFunctionEnd", + // clang-format on + }; + SinglePassRunAndCheck(JoinAllInsts(input), + JoinAllInsts(output), + /* skip_nop = */ false, + /* do_validation */ true); +} + +TEST_F(StripDebugStringTest, OpStringRemovedWithNonSemantic) { + std::vector input{ + // clang-format off + "OpCapability Shader", + "OpExtension \"SPV_KHR_non_semantic_info\"", + "%1 = OpExtInstImport \"NonSemantic.Testing.Set\"", + "OpMemoryModel Logical GLSL450", + "OpEntryPoint Vertex %2 \"main\"", + // this string is not referenced, should be removed fully + "%3 = OpString \"minimal.vert\"", + "OpName %3 \"bob\"", + // this string is referenced and cannot be removed, + // but the name should be + "%4 = OpString \"secondary.inc\"", + "OpName %4 \"sue\"", + "%void = OpTypeVoid", + "%6 = OpTypeFunction %void", + "%2 = OpFunction %void None %6", + "%7 = OpLabel", + "%8 = OpExtInst %void %1 5 %4", + "OpReturn", + "OpFunctionEnd", + // clang-format on + }; + std::vector output{ + // clang-format off + "OpCapability Shader", + "OpExtension \"SPV_KHR_non_semantic_info\"", + "%1 = OpExtInstImport \"NonSemantic.Testing.Set\"", + "OpMemoryModel Logical GLSL450", + "OpEntryPoint Vertex %2 \"main\"", + "%4 = OpString \"secondary.inc\"", + "%void = OpTypeVoid", + "%6 = OpTypeFunction %void", + "%2 = OpFunction %void None %6", + "%7 = OpLabel", + "%8 = OpExtInst %void %1 5 %4", + "OpReturn", + "OpFunctionEnd", + // clang-format on + }; + SinglePassRunAndCheck(JoinAllInsts(input), + JoinAllInsts(output), + /* skip_nop = */ false, + /* do_validation */ true); +} + using StripDebugInfoTest = PassTest<::testing::TestWithParam>; TEST_P(StripDebugInfoTest, Kind) { @@ -89,7 +214,7 @@ TEST_P(StripDebugInfoTest, Kind) { // Test each possible non-line debug instruction. // clang-format off -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SingleKindDebugInst, StripDebugInfoTest, ::testing::ValuesIn(std::vector({ "OpSourceContinued \"I'm a happy shader! Yay! ;)\"", diff --git a/third_party/spirv-tools/test/opt/strip_reflect_info_test.cpp b/third_party/spirv-tools/test/opt/strip_reflect_info_test.cpp index 088cac7aa5..5db34b720c 100644 --- a/third_party/spirv-tools/test/opt/strip_reflect_info_test.cpp +++ b/third_party/spirv-tools/test/opt/strip_reflect_info_test.cpp @@ -13,6 +13,9 @@ // limitations under the License. #include +#include "gmock/gmock.h" + +#include "spirv-tools/optimizer.hpp" #include "test/opt/pass_fixture.h" #include "test/opt/pass_utils.h" @@ -23,6 +26,50 @@ namespace { using StripLineReflectInfoTest = PassTest<::testing::Test>; +// This test acts as an end-to-end code example on how to strip +// reflection info from a SPIR-V module. Use this code pattern +// when you have compiled HLSL code with Glslang or DXC using +// option -fhlsl_functionality1 to insert reflection information, +// but then want to filter out the extra instructions before sending +// it to a driver that does not implement VK_GOOGLE_hlsl_functionality1. +TEST_F(StripLineReflectInfoTest, StripReflectEnd2EndExample) { + // This is a non-sensical example, but exercises the instructions. + std::string before = R"(OpCapability Shader +OpCapability Linkage +OpExtension "SPV_GOOGLE_decorate_string" +OpExtension "SPV_GOOGLE_hlsl_functionality1" +OpMemoryModel Logical Simple +OpDecorateStringGOOGLE %float HlslSemanticGOOGLE "foobar" +OpDecorateStringGOOGLE %void HlslSemanticGOOGLE "my goodness" +%void = OpTypeVoid +%float = OpTypeFloat 32 +)"; + SpirvTools tools(SPV_ENV_UNIVERSAL_1_1); + std::vector binary_in; + tools.Assemble(before, &binary_in); + + // Instantiate the optimizer, and run the strip-reflection-info + // pass over the |binary_in| module, and place the modified module + // into |binary_out|. + spvtools::Optimizer optimizer(SPV_ENV_UNIVERSAL_1_1); + optimizer.RegisterPass(spvtools::CreateStripReflectInfoPass()); + std::vector binary_out; + optimizer.Run(binary_in.data(), binary_in.size(), &binary_out); + + // Check results + std::string disassembly; + tools.Disassemble(binary_out.data(), binary_out.size(), &disassembly); + std::string after = R"(OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical Simple +%void = OpTypeVoid +%float = OpTypeFloat 32 +)"; + EXPECT_THAT(disassembly, testing::Eq(after)); +} + +// This test is functionally the same as the end-to-end test above, +// but uses the test SinglePassRunAndCheck test fixture instead. TEST_F(StripLineReflectInfoTest, StripHlslSemantic) { // This is a non-sensical example, but exercises the instructions. std::string before = R"(OpCapability Shader @@ -64,6 +111,27 @@ OpMemoryModel Logical Simple SinglePassRunAndCheck(before, after, false); } +TEST_F(StripLineReflectInfoTest, StripHlslSemanticOnMember) { + // This is a non-sensical example, but exercises the instructions. + std::string before = R"(OpCapability Shader +OpCapability Linkage +OpExtension "SPV_GOOGLE_decorate_string" +OpExtension "SPV_GOOGLE_hlsl_functionality1" +OpMemoryModel Logical Simple +OpMemberDecorateStringGOOGLE %struct 0 HlslSemanticGOOGLE "foobar" +%float = OpTypeFloat 32 +%_struct_3 = OpTypeStruct %float +)"; + std::string after = R"(OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical Simple +%float = OpTypeFloat 32 +%_struct_3 = OpTypeStruct %float +)"; + + SinglePassRunAndCheck(before, after, false); +} + } // namespace } // namespace opt } // namespace spvtools diff --git a/third_party/spirv-tools/test/opt/struct_cfg_analysis_test.cpp b/third_party/spirv-tools/test/opt/struct_cfg_analysis_test.cpp new file mode 100644 index 0000000000..0451a8b46c --- /dev/null +++ b/third_party/spirv-tools/test/opt/struct_cfg_analysis_test.cpp @@ -0,0 +1,1374 @@ +// Copyright (c) 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/opt/struct_cfg_analysis.h" + +#include + +#include "gmock/gmock.h" +#include "test/opt/assembly_builder.h" +#include "test/opt/pass_fixture.h" +#include "test/opt/pass_utils.h" + +namespace spvtools { +namespace opt { +namespace { + +using StructCFGAnalysisTest = PassTest<::testing::Test>; +using ::testing::UnorderedElementsAre; + +TEST_F(StructCFGAnalysisTest, BBInSelection) { + const std::string text = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +%void = OpTypeVoid +%bool = OpTypeBool +%bool_undef = OpUndef %bool +%uint = OpTypeInt 32 0 +%uint_undef = OpUndef %uint +%void_func = OpTypeFunction %void +%main = OpFunction %void None %void_func +%1 = OpLabel +OpSelectionMerge %3 None +OpBranchConditional %undef_bool %2 %3 +%2 = OpLabel +OpBranch %3 +%3 = OpLabel +OpReturn +OpFunctionEnd +)"; + + std::unique_ptr context = + BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + + StructuredCFGAnalysis analysis(context.get()); + + // The header is not in the construct. + EXPECT_EQ(analysis.ContainingConstruct(1), 0); + EXPECT_EQ(analysis.ContainingLoop(1), 0); + EXPECT_EQ(analysis.MergeBlock(1), 0); + EXPECT_EQ(analysis.LoopMergeBlock(1), 0); + EXPECT_EQ(analysis.ContainingSwitch(1), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(1), 0); + EXPECT_FALSE(analysis.IsContinueBlock(1)); + EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(1)); + EXPECT_FALSE(analysis.IsInContinueConstruct(1)); + EXPECT_FALSE(analysis.IsMergeBlock(1)); + + // BB2 is in the construct. + EXPECT_EQ(analysis.ContainingConstruct(2), 1); + EXPECT_EQ(analysis.ContainingLoop(2), 0); + EXPECT_EQ(analysis.MergeBlock(2), 3); + EXPECT_EQ(analysis.LoopMergeBlock(2), 0); + EXPECT_EQ(analysis.ContainingSwitch(2), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(2), 0); + EXPECT_FALSE(analysis.IsContinueBlock(2)); + EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(2)); + EXPECT_FALSE(analysis.IsInContinueConstruct(2)); + EXPECT_FALSE(analysis.IsMergeBlock(2)); + + // The merge node is not in the construct. + EXPECT_EQ(analysis.ContainingConstruct(3), 0); + EXPECT_EQ(analysis.ContainingLoop(3), 0); + EXPECT_EQ(analysis.MergeBlock(3), 0); + EXPECT_EQ(analysis.LoopMergeBlock(3), 0); + EXPECT_EQ(analysis.ContainingSwitch(3), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(3), 0); + EXPECT_FALSE(analysis.IsContinueBlock(3)); + EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(3)); + EXPECT_FALSE(analysis.IsInContinueConstruct(3)); + EXPECT_TRUE(analysis.IsMergeBlock(3)); +} + +TEST_F(StructCFGAnalysisTest, BBInLoop) { + const std::string text = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +%void = OpTypeVoid +%bool = OpTypeBool +%bool_undef = OpUndef %bool +%uint = OpTypeInt 32 0 +%uint_undef = OpUndef %uint +%void_func = OpTypeFunction %void +%main = OpFunction %void None %void_func +%entry_lab = OpLabel +OpBranch %1 +%1 = OpLabel +OpLoopMerge %3 %4 None +OpBranchConditional %undef_bool %2 %3 +%2 = OpLabel +OpBranch %3 +%4 = OpLabel +OpBranch %1 +%3 = OpLabel +OpReturn +OpFunctionEnd +)"; + + std::unique_ptr context = + BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + + StructuredCFGAnalysis analysis(context.get()); + + // The header is not in the construct. + EXPECT_EQ(analysis.ContainingConstruct(1), 0); + EXPECT_EQ(analysis.ContainingLoop(1), 0); + EXPECT_EQ(analysis.MergeBlock(1), 0); + EXPECT_EQ(analysis.LoopMergeBlock(1), 0); + EXPECT_EQ(analysis.ContainingSwitch(1), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(1), 0); + EXPECT_FALSE(analysis.IsContinueBlock(1)); + EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(1)); + EXPECT_FALSE(analysis.IsInContinueConstruct(1)); + EXPECT_FALSE(analysis.IsMergeBlock(1)); + + // BB2 is in the construct. + EXPECT_EQ(analysis.ContainingConstruct(2), 1); + EXPECT_EQ(analysis.ContainingLoop(2), 1); + EXPECT_EQ(analysis.MergeBlock(2), 3); + EXPECT_EQ(analysis.LoopMergeBlock(2), 3); + EXPECT_EQ(analysis.ContainingSwitch(2), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(2), 0); + EXPECT_FALSE(analysis.IsContinueBlock(2)); + EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(2)); + EXPECT_FALSE(analysis.IsInContinueConstruct(2)); + EXPECT_FALSE(analysis.IsMergeBlock(2)); + + // The merge node is not in the construct. + EXPECT_EQ(analysis.ContainingConstruct(3), 0); + EXPECT_EQ(analysis.ContainingLoop(3), 0); + EXPECT_EQ(analysis.MergeBlock(3), 0); + EXPECT_EQ(analysis.LoopMergeBlock(3), 0); + EXPECT_EQ(analysis.ContainingSwitch(3), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(3), 0); + EXPECT_FALSE(analysis.IsContinueBlock(3)); + EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(3)); + EXPECT_FALSE(analysis.IsInContinueConstruct(3)); + EXPECT_TRUE(analysis.IsMergeBlock(3)); + + // The continue block is in the construct. + EXPECT_EQ(analysis.ContainingConstruct(4), 1); + EXPECT_EQ(analysis.ContainingLoop(4), 1); + EXPECT_EQ(analysis.MergeBlock(4), 3); + EXPECT_EQ(analysis.LoopMergeBlock(4), 3); + EXPECT_EQ(analysis.ContainingSwitch(4), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(4), 0); + EXPECT_TRUE(analysis.IsContinueBlock(4)); + EXPECT_TRUE(analysis.IsInContainingLoopsContinueConstruct(4)); + EXPECT_TRUE(analysis.IsInContinueConstruct(4)); + EXPECT_FALSE(analysis.IsMergeBlock(4)); +} + +TEST_F(StructCFGAnalysisTest, SelectionInLoop) { + const std::string text = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +%void = OpTypeVoid +%bool = OpTypeBool +%bool_undef = OpUndef %bool +%uint = OpTypeInt 32 0 +%uint_undef = OpUndef %uint +%void_func = OpTypeFunction %void +%main = OpFunction %void None %void_func +%entry_lab = OpLabel +OpBranch %1 +%1 = OpLabel +OpLoopMerge %3 %4 None +OpBranchConditional %undef_bool %2 %3 +%2 = OpLabel +OpSelectionMerge %6 None +OpBranchConditional %undef_bool %5 %6 +%5 = OpLabel +OpBranch %6 +%6 = OpLabel +OpBranch %3 +%4 = OpLabel +OpBranch %1 +%3 = OpLabel +OpReturn +OpFunctionEnd +)"; + + std::unique_ptr context = + BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + + StructuredCFGAnalysis analysis(context.get()); + + // The loop header is not in either construct. + EXPECT_EQ(analysis.ContainingConstruct(1), 0); + EXPECT_EQ(analysis.ContainingLoop(1), 0); + EXPECT_EQ(analysis.MergeBlock(1), 0); + EXPECT_EQ(analysis.LoopMergeBlock(1), 0); + EXPECT_EQ(analysis.ContainingSwitch(1), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(1), 0); + EXPECT_FALSE(analysis.IsContinueBlock(1)); + EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(1)); + EXPECT_FALSE(analysis.IsInContinueConstruct(1)); + EXPECT_FALSE(analysis.IsMergeBlock(1)); + + // Selection header is in the loop only. + EXPECT_EQ(analysis.ContainingConstruct(2), 1); + EXPECT_EQ(analysis.ContainingLoop(2), 1); + EXPECT_EQ(analysis.MergeBlock(2), 3); + EXPECT_EQ(analysis.LoopMergeBlock(2), 3); + EXPECT_EQ(analysis.ContainingSwitch(2), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(2), 0); + EXPECT_FALSE(analysis.IsContinueBlock(2)); + EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(2)); + EXPECT_FALSE(analysis.IsInContinueConstruct(2)); + EXPECT_FALSE(analysis.IsMergeBlock(2)); + + // The loop merge node is not in either construct. + EXPECT_EQ(analysis.ContainingConstruct(3), 0); + EXPECT_EQ(analysis.ContainingLoop(3), 0); + EXPECT_EQ(analysis.MergeBlock(3), 0); + EXPECT_EQ(analysis.LoopMergeBlock(3), 0); + EXPECT_EQ(analysis.ContainingSwitch(3), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(3), 0); + EXPECT_FALSE(analysis.IsContinueBlock(3)); + EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(3)); + EXPECT_FALSE(analysis.IsInContinueConstruct(3)); + EXPECT_TRUE(analysis.IsMergeBlock(3)); + + // The continue block is in the loop only. + EXPECT_EQ(analysis.ContainingConstruct(4), 1); + EXPECT_EQ(analysis.ContainingLoop(4), 1); + EXPECT_EQ(analysis.MergeBlock(4), 3); + EXPECT_EQ(analysis.LoopMergeBlock(4), 3); + EXPECT_EQ(analysis.ContainingSwitch(4), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(4), 0); + EXPECT_TRUE(analysis.IsContinueBlock(4)); + EXPECT_TRUE(analysis.IsInContainingLoopsContinueConstruct(4)); + EXPECT_TRUE(analysis.IsInContinueConstruct(4)); + EXPECT_FALSE(analysis.IsMergeBlock(4)); + + // BB5 is in the selection and the loop. + EXPECT_EQ(analysis.ContainingConstruct(5), 2); + EXPECT_EQ(analysis.ContainingLoop(5), 1); + EXPECT_EQ(analysis.MergeBlock(5), 6); + EXPECT_EQ(analysis.LoopMergeBlock(5), 3); + EXPECT_EQ(analysis.ContainingSwitch(5), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(5), 0); + EXPECT_FALSE(analysis.IsContinueBlock(5)); + EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(5)); + EXPECT_FALSE(analysis.IsInContinueConstruct(5)); + EXPECT_FALSE(analysis.IsMergeBlock(5)); + + // The selection merge is in the loop only. + EXPECT_EQ(analysis.ContainingConstruct(6), 1); + EXPECT_EQ(analysis.ContainingLoop(6), 1); + EXPECT_EQ(analysis.MergeBlock(6), 3); + EXPECT_EQ(analysis.LoopMergeBlock(6), 3); + EXPECT_EQ(analysis.ContainingSwitch(6), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(6), 0); + EXPECT_FALSE(analysis.IsContinueBlock(6)); + EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(6)); + EXPECT_FALSE(analysis.IsInContinueConstruct(6)); + EXPECT_TRUE(analysis.IsMergeBlock(6)); +} + +TEST_F(StructCFGAnalysisTest, LoopInSelection) { + const std::string text = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +%void = OpTypeVoid +%bool = OpTypeBool +%bool_undef = OpUndef %bool +%uint = OpTypeInt 32 0 +%uint_undef = OpUndef %uint +%void_func = OpTypeFunction %void +%main = OpFunction %void None %void_func +%entry_lab = OpLabel +OpBranch %1 +%1 = OpLabel +OpSelectionMerge %3 None +OpBranchConditional %undef_bool %2 %3 +%2 = OpLabel +OpLoopMerge %4 %5 None +OpBranchConditional %undef_bool %4 %6 +%5 = OpLabel +OpBranch %2 +%6 = OpLabel +OpBranch %4 +%4 = OpLabel +OpBranch %3 +%3 = OpLabel +OpReturn +OpFunctionEnd +)"; + + std::unique_ptr context = + BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + + StructuredCFGAnalysis analysis(context.get()); + + // The selection header is not in either construct. + EXPECT_EQ(analysis.ContainingConstruct(1), 0); + EXPECT_EQ(analysis.ContainingLoop(1), 0); + EXPECT_EQ(analysis.MergeBlock(1), 0); + EXPECT_EQ(analysis.LoopMergeBlock(1), 0); + EXPECT_EQ(analysis.ContainingSwitch(1), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(1), 0); + EXPECT_FALSE(analysis.IsContinueBlock(1)); + EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(1)); + EXPECT_FALSE(analysis.IsInContinueConstruct(1)); + EXPECT_FALSE(analysis.IsMergeBlock(1)); + + // Loop header is in the selection only. + EXPECT_EQ(analysis.ContainingConstruct(2), 1); + EXPECT_EQ(analysis.ContainingLoop(2), 0); + EXPECT_EQ(analysis.MergeBlock(2), 3); + EXPECT_EQ(analysis.LoopMergeBlock(2), 0); + EXPECT_EQ(analysis.ContainingSwitch(2), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(2), 0); + EXPECT_FALSE(analysis.IsContinueBlock(2)); + EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(2)); + EXPECT_FALSE(analysis.IsInContinueConstruct(2)); + EXPECT_FALSE(analysis.IsMergeBlock(2)); + + // The selection merge node is not in either construct. + EXPECT_EQ(analysis.ContainingConstruct(3), 0); + EXPECT_EQ(analysis.ContainingLoop(3), 0); + EXPECT_EQ(analysis.MergeBlock(3), 0); + EXPECT_EQ(analysis.LoopMergeBlock(3), 0); + EXPECT_EQ(analysis.ContainingSwitch(3), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(3), 0); + EXPECT_FALSE(analysis.IsContinueBlock(3)); + EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(3)); + EXPECT_FALSE(analysis.IsInContinueConstruct(3)); + EXPECT_TRUE(analysis.IsMergeBlock(3)); + + // The loop merge is in the selection only. + EXPECT_EQ(analysis.ContainingConstruct(4), 1); + EXPECT_EQ(analysis.ContainingLoop(4), 0); + EXPECT_EQ(analysis.MergeBlock(4), 3); + EXPECT_EQ(analysis.LoopMergeBlock(4), 0); + EXPECT_EQ(analysis.ContainingSwitch(4), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(4), 0); + EXPECT_FALSE(analysis.IsContinueBlock(4)); + EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(4)); + EXPECT_FALSE(analysis.IsInContinueConstruct(4)); + EXPECT_TRUE(analysis.IsMergeBlock(4)); + + // The loop continue target is in the loop. + EXPECT_EQ(analysis.ContainingConstruct(5), 2); + EXPECT_EQ(analysis.ContainingLoop(5), 2); + EXPECT_EQ(analysis.MergeBlock(5), 4); + EXPECT_EQ(analysis.LoopMergeBlock(5), 4); + EXPECT_EQ(analysis.ContainingSwitch(5), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(5), 0); + EXPECT_TRUE(analysis.IsContinueBlock(5)); + EXPECT_TRUE(analysis.IsInContainingLoopsContinueConstruct(5)); + EXPECT_TRUE(analysis.IsInContinueConstruct(5)); + EXPECT_FALSE(analysis.IsMergeBlock(5)); + + // BB6 is in the loop. + EXPECT_EQ(analysis.ContainingConstruct(6), 2); + EXPECT_EQ(analysis.ContainingLoop(6), 2); + EXPECT_EQ(analysis.MergeBlock(6), 4); + EXPECT_EQ(analysis.LoopMergeBlock(6), 4); + EXPECT_EQ(analysis.ContainingSwitch(6), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(6), 0); + EXPECT_FALSE(analysis.IsContinueBlock(6)); + EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(6)); + EXPECT_FALSE(analysis.IsInContinueConstruct(6)); + EXPECT_FALSE(analysis.IsMergeBlock(6)); +} + +TEST_F(StructCFGAnalysisTest, SelectionInSelection) { + const std::string text = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +%void = OpTypeVoid +%bool = OpTypeBool +%bool_undef = OpUndef %bool +%uint = OpTypeInt 32 0 +%uint_undef = OpUndef %uint +%void_func = OpTypeFunction %void +%main = OpFunction %void None %void_func +%entry_lab = OpLabel +OpBranch %1 +%1 = OpLabel +OpSelectionMerge %3 None +OpBranchConditional %undef_bool %2 %3 +%2 = OpLabel +OpSelectionMerge %4 None +OpBranchConditional %undef_bool %4 %5 +%5 = OpLabel +OpBranch %4 +%4 = OpLabel +OpBranch %3 +%3 = OpLabel +OpReturn +OpFunctionEnd +)"; + + std::unique_ptr context = + BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + + StructuredCFGAnalysis analysis(context.get()); + + // The outer selection header is not in either construct. + EXPECT_EQ(analysis.ContainingConstruct(1), 0); + EXPECT_EQ(analysis.ContainingLoop(1), 0); + EXPECT_EQ(analysis.MergeBlock(1), 0); + EXPECT_EQ(analysis.LoopMergeBlock(1), 0); + EXPECT_EQ(analysis.ContainingSwitch(1), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(1), 0); + EXPECT_FALSE(analysis.IsContinueBlock(1)); + EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(1)); + EXPECT_FALSE(analysis.IsInContinueConstruct(1)); + EXPECT_FALSE(analysis.IsMergeBlock(1)); + + // The inner header is in the outer selection. + EXPECT_EQ(analysis.ContainingConstruct(2), 1); + EXPECT_EQ(analysis.ContainingLoop(2), 0); + EXPECT_EQ(analysis.MergeBlock(2), 3); + EXPECT_EQ(analysis.LoopMergeBlock(2), 0); + EXPECT_EQ(analysis.ContainingSwitch(2), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(2), 0); + EXPECT_FALSE(analysis.IsContinueBlock(2)); + EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(2)); + EXPECT_FALSE(analysis.IsInContinueConstruct(2)); + EXPECT_FALSE(analysis.IsMergeBlock(2)); + + // The outer merge node is not in either construct. + EXPECT_EQ(analysis.ContainingConstruct(3), 0); + EXPECT_EQ(analysis.ContainingLoop(3), 0); + EXPECT_EQ(analysis.MergeBlock(3), 0); + EXPECT_EQ(analysis.LoopMergeBlock(3), 0); + EXPECT_EQ(analysis.ContainingSwitch(3), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(3), 0); + EXPECT_FALSE(analysis.IsContinueBlock(3)); + EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(3)); + EXPECT_FALSE(analysis.IsInContinueConstruct(3)); + EXPECT_TRUE(analysis.IsMergeBlock(3)); + + // The inner merge is in the outer selection. + EXPECT_EQ(analysis.ContainingConstruct(4), 1); + EXPECT_EQ(analysis.ContainingLoop(4), 0); + EXPECT_EQ(analysis.MergeBlock(4), 3); + EXPECT_EQ(analysis.LoopMergeBlock(4), 0); + EXPECT_EQ(analysis.ContainingSwitch(4), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(4), 0); + EXPECT_FALSE(analysis.IsContinueBlock(4)); + EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(4)); + EXPECT_FALSE(analysis.IsInContinueConstruct(4)); + EXPECT_TRUE(analysis.IsMergeBlock(4)); + + // BB5 is in the inner selection. + EXPECT_EQ(analysis.ContainingConstruct(5), 2); + EXPECT_EQ(analysis.ContainingLoop(5), 0); + EXPECT_EQ(analysis.MergeBlock(5), 4); + EXPECT_EQ(analysis.LoopMergeBlock(5), 0); + EXPECT_EQ(analysis.ContainingSwitch(5), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(5), 0); + EXPECT_FALSE(analysis.IsContinueBlock(5)); + EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(5)); + EXPECT_FALSE(analysis.IsInContinueConstruct(5)); + EXPECT_FALSE(analysis.IsMergeBlock(5)); +} + +TEST_F(StructCFGAnalysisTest, LoopInLoop) { + const std::string text = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +%void = OpTypeVoid +%bool = OpTypeBool +%bool_undef = OpUndef %bool +%uint = OpTypeInt 32 0 +%uint_undef = OpUndef %uint +%void_func = OpTypeFunction %void +%main = OpFunction %void None %void_func +%entry_lab = OpLabel +OpBranch %1 +%1 = OpLabel +OpLoopMerge %3 %7 None +OpBranchConditional %undef_bool %2 %3 +%2 = OpLabel +OpLoopMerge %4 %5 None +OpBranchConditional %undef_bool %4 %6 +%5 = OpLabel +OpBranch %2 +%6 = OpLabel +OpBranch %4 +%4 = OpLabel +OpBranch %3 +%7 = OpLabel +OpBranch %1 +%3 = OpLabel +OpReturn +OpFunctionEnd +)"; + + std::unique_ptr context = + BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + + StructuredCFGAnalysis analysis(context.get()); + + // The outer loop header is not in either construct. + EXPECT_EQ(analysis.ContainingConstruct(1), 0); + EXPECT_EQ(analysis.ContainingLoop(1), 0); + EXPECT_EQ(analysis.MergeBlock(1), 0); + EXPECT_EQ(analysis.LoopMergeBlock(1), 0); + EXPECT_EQ(analysis.ContainingSwitch(1), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(1), 0); + EXPECT_FALSE(analysis.IsContinueBlock(1)); + EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(1)); + EXPECT_FALSE(analysis.IsInContinueConstruct(1)); + EXPECT_FALSE(analysis.IsMergeBlock(1)); + + // The inner loop header is in the outer loop. + EXPECT_EQ(analysis.ContainingConstruct(2), 1); + EXPECT_EQ(analysis.ContainingLoop(2), 1); + EXPECT_EQ(analysis.MergeBlock(2), 3); + EXPECT_EQ(analysis.LoopMergeBlock(2), 3); + EXPECT_EQ(analysis.ContainingSwitch(2), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(2), 0); + EXPECT_FALSE(analysis.IsContinueBlock(2)); + EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(2)); + EXPECT_FALSE(analysis.IsInContinueConstruct(2)); + EXPECT_FALSE(analysis.IsMergeBlock(2)); + + // The outer merge node is not in either construct. + EXPECT_EQ(analysis.ContainingConstruct(3), 0); + EXPECT_EQ(analysis.ContainingLoop(3), 0); + EXPECT_EQ(analysis.MergeBlock(3), 0); + EXPECT_EQ(analysis.LoopMergeBlock(3), 0); + EXPECT_EQ(analysis.ContainingSwitch(3), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(3), 0); + EXPECT_FALSE(analysis.IsContinueBlock(3)); + EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(3)); + EXPECT_FALSE(analysis.IsInContinueConstruct(3)); + EXPECT_TRUE(analysis.IsMergeBlock(3)); + + // The inner merge is in the outer loop. + EXPECT_EQ(analysis.ContainingConstruct(4), 1); + EXPECT_EQ(analysis.ContainingLoop(4), 1); + EXPECT_EQ(analysis.MergeBlock(4), 3); + EXPECT_EQ(analysis.LoopMergeBlock(4), 3); + EXPECT_EQ(analysis.ContainingSwitch(4), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(4), 0); + EXPECT_FALSE(analysis.IsContinueBlock(4)); + EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(4)); + EXPECT_FALSE(analysis.IsInContinueConstruct(4)); + EXPECT_TRUE(analysis.IsMergeBlock(4)); + + // The inner continue target is in the inner loop. + EXPECT_EQ(analysis.ContainingConstruct(5), 2); + EXPECT_EQ(analysis.ContainingLoop(5), 2); + EXPECT_EQ(analysis.MergeBlock(5), 4); + EXPECT_EQ(analysis.LoopMergeBlock(5), 4); + EXPECT_EQ(analysis.ContainingSwitch(5), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(5), 0); + EXPECT_TRUE(analysis.IsContinueBlock(5)); + EXPECT_TRUE(analysis.IsInContainingLoopsContinueConstruct(5)); + EXPECT_TRUE(analysis.IsInContinueConstruct(5)); + EXPECT_FALSE(analysis.IsMergeBlock(5)); + + // BB6 is in the loop. + EXPECT_EQ(analysis.ContainingConstruct(6), 2); + EXPECT_EQ(analysis.ContainingLoop(6), 2); + EXPECT_EQ(analysis.MergeBlock(6), 4); + EXPECT_EQ(analysis.LoopMergeBlock(6), 4); + EXPECT_EQ(analysis.ContainingSwitch(6), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(6), 0); + EXPECT_FALSE(analysis.IsContinueBlock(6)); + EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(6)); + EXPECT_FALSE(analysis.IsInContinueConstruct(6)); + EXPECT_FALSE(analysis.IsMergeBlock(6)); + + // The outer continue target is in the outer loop. + EXPECT_EQ(analysis.ContainingConstruct(7), 1); + EXPECT_EQ(analysis.ContainingLoop(7), 1); + EXPECT_EQ(analysis.MergeBlock(7), 3); + EXPECT_EQ(analysis.LoopMergeBlock(7), 3); + EXPECT_EQ(analysis.ContainingSwitch(7), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(7), 0); + EXPECT_TRUE(analysis.IsContinueBlock(7)); + EXPECT_TRUE(analysis.IsInContainingLoopsContinueConstruct(7)); + EXPECT_TRUE(analysis.IsInContinueConstruct(7)); + EXPECT_FALSE(analysis.IsMergeBlock(7)); +} + +TEST_F(StructCFGAnalysisTest, KernelTest) { + const std::string text = R"( +OpCapability Kernel +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +%void = OpTypeVoid +%bool = OpTypeBool +%bool_undef = OpUndef %bool +%void_func = OpTypeFunction %void +%main = OpFunction %void None %void_func +%1 = OpLabel +OpBranchConditional %undef_bool %2 %3 +%2 = OpLabel +OpBranch %3 +%3 = OpLabel +OpReturn +OpFunctionEnd +)"; + + std::unique_ptr context = + BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + + StructuredCFGAnalysis analysis(context.get()); + + // No structured control flow, so none of the basic block are in any + // construct. + for (uint32_t i = 1; i <= 3; i++) { + EXPECT_EQ(analysis.ContainingConstruct(i), 0); + EXPECT_EQ(analysis.ContainingLoop(i), 0); + EXPECT_EQ(analysis.MergeBlock(i), 0); + EXPECT_EQ(analysis.LoopMergeBlock(i), 0); + EXPECT_EQ(analysis.ContainingSwitch(i), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(i), 0); + EXPECT_FALSE(analysis.IsContinueBlock(i)); + EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(i)); + EXPECT_FALSE(analysis.IsInContinueConstruct(i)); + EXPECT_FALSE(analysis.IsMergeBlock(i)); + } +} + +TEST_F(StructCFGAnalysisTest, EmptyFunctionTest) { + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpDecorate %func LinkageAttributes "x" Import +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%func = OpFunction %void None %void_fn +OpFunctionEnd +)"; + + std::unique_ptr context = + BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + + // #2451: This segfaulted on empty functions. + StructuredCFGAnalysis analysis(context.get()); +} + +TEST_F(StructCFGAnalysisTest, BBInSwitch) { + const std::string text = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +%void = OpTypeVoid +%bool = OpTypeBool +%bool_undef = OpUndef %bool +%uint = OpTypeInt 32 0 +%uint_undef = OpUndef %uint +%void_func = OpTypeFunction %void +%main = OpFunction %void None %void_func +%1 = OpLabel +OpSelectionMerge %3 None +OpSwitch %uint_undef %2 0 %3 +%2 = OpLabel +OpBranch %3 +%3 = OpLabel +OpReturn +OpFunctionEnd +)"; + + std::unique_ptr context = + BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + + StructuredCFGAnalysis analysis(context.get()); + + // The header is not in the construct. + EXPECT_EQ(analysis.ContainingConstruct(1), 0); + EXPECT_EQ(analysis.ContainingLoop(1), 0); + EXPECT_EQ(analysis.MergeBlock(1), 0); + EXPECT_EQ(analysis.LoopMergeBlock(1), 0); + EXPECT_EQ(analysis.ContainingSwitch(1), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(1), 0); + EXPECT_FALSE(analysis.IsContinueBlock(1)); + EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(1)); + EXPECT_FALSE(analysis.IsInContinueConstruct(1)); + EXPECT_FALSE(analysis.IsMergeBlock(1)); + + // BB2 is in the construct. + EXPECT_EQ(analysis.ContainingConstruct(2), 1); + EXPECT_EQ(analysis.ContainingLoop(2), 0); + EXPECT_EQ(analysis.MergeBlock(2), 3); + EXPECT_EQ(analysis.LoopMergeBlock(2), 0); + EXPECT_EQ(analysis.ContainingSwitch(2), 1); + EXPECT_EQ(analysis.SwitchMergeBlock(2), 3); + EXPECT_FALSE(analysis.IsContinueBlock(2)); + EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(2)); + EXPECT_FALSE(analysis.IsInContinueConstruct(2)); + EXPECT_FALSE(analysis.IsMergeBlock(2)); + + // The merge node is not in the construct. + EXPECT_EQ(analysis.ContainingConstruct(3), 0); + EXPECT_EQ(analysis.ContainingLoop(3), 0); + EXPECT_EQ(analysis.MergeBlock(3), 0); + EXPECT_EQ(analysis.LoopMergeBlock(3), 0); + EXPECT_EQ(analysis.ContainingSwitch(3), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(3), 0); + EXPECT_FALSE(analysis.IsContinueBlock(3)); + EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(3)); + EXPECT_FALSE(analysis.IsInContinueConstruct(3)); + EXPECT_TRUE(analysis.IsMergeBlock(3)); +} + +TEST_F(StructCFGAnalysisTest, LoopInSwitch) { + const std::string text = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +%void = OpTypeVoid +%bool = OpTypeBool +%bool_undef = OpUndef %bool +%uint = OpTypeInt 32 0 +%uint_undef = OpUndef %uint +%void_func = OpTypeFunction %void +%main = OpFunction %void None %void_func +%entry_lab = OpLabel +OpBranch %1 +%1 = OpLabel +OpSelectionMerge %3 None +OpSwitch %uint_undef %2 1 %3 +%2 = OpLabel +OpLoopMerge %4 %5 None +OpBranchConditional %undef_bool %4 %6 +%5 = OpLabel +OpBranch %2 +%6 = OpLabel +OpBranch %4 +%4 = OpLabel +OpBranch %3 +%3 = OpLabel +OpReturn +OpFunctionEnd +)"; + + std::unique_ptr context = + BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + + StructuredCFGAnalysis analysis(context.get()); + + // The selection header is not in either construct. + EXPECT_EQ(analysis.ContainingConstruct(1), 0); + EXPECT_EQ(analysis.ContainingLoop(1), 0); + EXPECT_EQ(analysis.MergeBlock(1), 0); + EXPECT_EQ(analysis.LoopMergeBlock(1), 0); + EXPECT_EQ(analysis.ContainingSwitch(1), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(1), 0); + EXPECT_FALSE(analysis.IsContinueBlock(1)); + EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(1)); + EXPECT_FALSE(analysis.IsInContinueConstruct(1)); + EXPECT_FALSE(analysis.IsMergeBlock(1)); + + // Loop header is in the selection only. + EXPECT_EQ(analysis.ContainingConstruct(2), 1); + EXPECT_EQ(analysis.ContainingLoop(2), 0); + EXPECT_EQ(analysis.MergeBlock(2), 3); + EXPECT_EQ(analysis.LoopMergeBlock(2), 0); + EXPECT_EQ(analysis.ContainingSwitch(2), 1); + EXPECT_EQ(analysis.SwitchMergeBlock(2), 3); + EXPECT_FALSE(analysis.IsContinueBlock(2)); + EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(2)); + EXPECT_FALSE(analysis.IsInContinueConstruct(2)); + EXPECT_FALSE(analysis.IsMergeBlock(2)); + + // The selection merge node is not in either construct. + EXPECT_EQ(analysis.ContainingConstruct(3), 0); + EXPECT_EQ(analysis.ContainingLoop(3), 0); + EXPECT_EQ(analysis.MergeBlock(3), 0); + EXPECT_EQ(analysis.LoopMergeBlock(3), 0); + EXPECT_EQ(analysis.ContainingSwitch(3), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(3), 0); + EXPECT_FALSE(analysis.IsContinueBlock(3)); + EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(3)); + EXPECT_FALSE(analysis.IsInContinueConstruct(3)); + EXPECT_TRUE(analysis.IsMergeBlock(3)); + + // The loop merge is in the selection only. + EXPECT_EQ(analysis.ContainingConstruct(4), 1); + EXPECT_EQ(analysis.ContainingLoop(4), 0); + EXPECT_EQ(analysis.MergeBlock(4), 3); + EXPECT_EQ(analysis.LoopMergeBlock(4), 0); + EXPECT_EQ(analysis.ContainingSwitch(4), 1); + EXPECT_EQ(analysis.SwitchMergeBlock(4), 3); + EXPECT_FALSE(analysis.IsContinueBlock(4)); + EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(4)); + EXPECT_FALSE(analysis.IsInContinueConstruct(4)); + EXPECT_TRUE(analysis.IsMergeBlock(4)); + + // The loop continue target is in the loop. + EXPECT_EQ(analysis.ContainingConstruct(5), 2); + EXPECT_EQ(analysis.ContainingLoop(5), 2); + EXPECT_EQ(analysis.MergeBlock(5), 4); + EXPECT_EQ(analysis.LoopMergeBlock(5), 4); + EXPECT_EQ(analysis.ContainingSwitch(5), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(5), 0); + EXPECT_TRUE(analysis.IsContinueBlock(5)); + EXPECT_TRUE(analysis.IsInContainingLoopsContinueConstruct(5)); + EXPECT_TRUE(analysis.IsInContinueConstruct(5)); + EXPECT_FALSE(analysis.IsMergeBlock(5)); + + // BB6 is in the loop. + EXPECT_EQ(analysis.ContainingConstruct(6), 2); + EXPECT_EQ(analysis.ContainingLoop(6), 2); + EXPECT_EQ(analysis.MergeBlock(6), 4); + EXPECT_EQ(analysis.LoopMergeBlock(6), 4); + EXPECT_EQ(analysis.ContainingSwitch(6), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(6), 0); + EXPECT_FALSE(analysis.IsContinueBlock(6)); + EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(6)); + EXPECT_FALSE(analysis.IsInContinueConstruct(6)); + EXPECT_FALSE(analysis.IsMergeBlock(6)); +} + +TEST_F(StructCFGAnalysisTest, SelectionInSwitch) { + const std::string text = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +%void = OpTypeVoid +%bool = OpTypeBool +%bool_undef = OpUndef %bool +%uint = OpTypeInt 32 0 +%uint_undef = OpUndef %uint +%void_func = OpTypeFunction %void +%main = OpFunction %void None %void_func +%entry_lab = OpLabel +OpBranch %1 +%1 = OpLabel +OpSelectionMerge %3 None +OpSwitch %uint_undef %2 10 %3 +%2 = OpLabel +OpSelectionMerge %4 None +OpBranchConditional %undef_bool %4 %5 +%5 = OpLabel +OpBranch %4 +%4 = OpLabel +OpBranch %3 +%3 = OpLabel +OpReturn +OpFunctionEnd +)"; + + std::unique_ptr context = + BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + + StructuredCFGAnalysis analysis(context.get()); + + // The outer selection header is not in either construct. + EXPECT_EQ(analysis.ContainingConstruct(1), 0); + EXPECT_EQ(analysis.ContainingLoop(1), 0); + EXPECT_EQ(analysis.MergeBlock(1), 0); + EXPECT_EQ(analysis.LoopMergeBlock(1), 0); + EXPECT_EQ(analysis.ContainingSwitch(1), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(1), 0); + EXPECT_FALSE(analysis.IsContinueBlock(1)); + EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(1)); + EXPECT_FALSE(analysis.IsInContinueConstruct(1)); + EXPECT_FALSE(analysis.IsMergeBlock(1)); + + // The inner header is in the outer selection. + EXPECT_EQ(analysis.ContainingConstruct(2), 1); + EXPECT_EQ(analysis.ContainingLoop(2), 0); + EXPECT_EQ(analysis.MergeBlock(2), 3); + EXPECT_EQ(analysis.LoopMergeBlock(2), 0); + EXPECT_EQ(analysis.ContainingSwitch(2), 1); + EXPECT_EQ(analysis.SwitchMergeBlock(2), 3); + EXPECT_FALSE(analysis.IsContinueBlock(2)); + EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(2)); + EXPECT_FALSE(analysis.IsInContinueConstruct(2)); + EXPECT_FALSE(analysis.IsMergeBlock(2)); + + // The outer merge node is not in either construct. + EXPECT_EQ(analysis.ContainingConstruct(3), 0); + EXPECT_EQ(analysis.ContainingLoop(3), 0); + EXPECT_EQ(analysis.MergeBlock(3), 0); + EXPECT_EQ(analysis.LoopMergeBlock(3), 0); + EXPECT_EQ(analysis.ContainingSwitch(3), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(3), 0); + EXPECT_FALSE(analysis.IsContinueBlock(3)); + EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(3)); + EXPECT_FALSE(analysis.IsInContinueConstruct(3)); + EXPECT_TRUE(analysis.IsMergeBlock(3)); + + // The inner merge is in the outer selection. + EXPECT_EQ(analysis.ContainingConstruct(4), 1); + EXPECT_EQ(analysis.ContainingLoop(4), 0); + EXPECT_EQ(analysis.MergeBlock(4), 3); + EXPECT_EQ(analysis.LoopMergeBlock(4), 0); + EXPECT_EQ(analysis.ContainingSwitch(4), 1); + EXPECT_EQ(analysis.SwitchMergeBlock(4), 3); + EXPECT_FALSE(analysis.IsContinueBlock(4)); + EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(4)); + EXPECT_FALSE(analysis.IsInContinueConstruct(4)); + EXPECT_TRUE(analysis.IsMergeBlock(4)); + + // BB5 is in the inner selection. + EXPECT_EQ(analysis.ContainingConstruct(5), 2); + EXPECT_EQ(analysis.ContainingLoop(5), 0); + EXPECT_EQ(analysis.MergeBlock(5), 4); + EXPECT_EQ(analysis.LoopMergeBlock(5), 0); + EXPECT_EQ(analysis.ContainingSwitch(5), 1); + EXPECT_EQ(analysis.SwitchMergeBlock(5), 3); + EXPECT_FALSE(analysis.IsContinueBlock(5)); + EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(5)); + EXPECT_FALSE(analysis.IsInContinueConstruct(5)); + EXPECT_FALSE(analysis.IsMergeBlock(5)); +} + +TEST_F(StructCFGAnalysisTest, SwitchInSelection) { + const std::string text = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +%void = OpTypeVoid +%bool = OpTypeBool +%bool_undef = OpUndef %bool +%uint = OpTypeInt 32 0 +%uint_undef = OpUndef %uint +%void_func = OpTypeFunction %void +%main = OpFunction %void None %void_func +%entry_lab = OpLabel +OpBranch %1 +%1 = OpLabel +OpSelectionMerge %3 None +OpBranchConditional %undef_bool %2 %3 +%2 = OpLabel +OpSelectionMerge %4 None +OpSwitch %uint_undef %4 7 %5 +%5 = OpLabel +OpBranch %4 +%4 = OpLabel +OpBranch %3 +%3 = OpLabel +OpReturn +OpFunctionEnd +)"; + + std::unique_ptr context = + BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + + StructuredCFGAnalysis analysis(context.get()); + + // The outer selection header is not in either construct. + EXPECT_EQ(analysis.ContainingConstruct(1), 0); + EXPECT_EQ(analysis.ContainingLoop(1), 0); + EXPECT_EQ(analysis.MergeBlock(1), 0); + EXPECT_EQ(analysis.LoopMergeBlock(1), 0); + EXPECT_EQ(analysis.ContainingSwitch(1), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(1), 0); + EXPECT_FALSE(analysis.IsContinueBlock(1)); + EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(1)); + EXPECT_FALSE(analysis.IsInContinueConstruct(1)); + EXPECT_FALSE(analysis.IsMergeBlock(1)); + + // The inner header is in the outer selection. + EXPECT_EQ(analysis.ContainingConstruct(2), 1); + EXPECT_EQ(analysis.ContainingLoop(2), 0); + EXPECT_EQ(analysis.MergeBlock(2), 3); + EXPECT_EQ(analysis.LoopMergeBlock(2), 0); + EXPECT_EQ(analysis.ContainingSwitch(2), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(2), 0); + EXPECT_FALSE(analysis.IsContinueBlock(2)); + EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(2)); + EXPECT_FALSE(analysis.IsInContinueConstruct(2)); + EXPECT_FALSE(analysis.IsMergeBlock(2)); + + // The outer merge node is not in either construct. + EXPECT_EQ(analysis.ContainingConstruct(3), 0); + EXPECT_EQ(analysis.ContainingLoop(3), 0); + EXPECT_EQ(analysis.MergeBlock(3), 0); + EXPECT_EQ(analysis.LoopMergeBlock(3), 0); + EXPECT_EQ(analysis.ContainingSwitch(3), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(3), 0); + EXPECT_FALSE(analysis.IsContinueBlock(3)); + EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(3)); + EXPECT_FALSE(analysis.IsInContinueConstruct(3)); + EXPECT_TRUE(analysis.IsMergeBlock(3)); + + // The inner merge is in the outer selection. + EXPECT_EQ(analysis.ContainingConstruct(4), 1); + EXPECT_EQ(analysis.ContainingLoop(4), 0); + EXPECT_EQ(analysis.MergeBlock(4), 3); + EXPECT_EQ(analysis.LoopMergeBlock(4), 0); + EXPECT_EQ(analysis.ContainingSwitch(4), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(4), 0); + EXPECT_FALSE(analysis.IsContinueBlock(4)); + EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(4)); + EXPECT_FALSE(analysis.IsInContinueConstruct(4)); + EXPECT_TRUE(analysis.IsMergeBlock(4)); + + // BB5 is in the inner selection. + EXPECT_EQ(analysis.ContainingConstruct(5), 2); + EXPECT_EQ(analysis.ContainingLoop(5), 0); + EXPECT_EQ(analysis.MergeBlock(5), 4); + EXPECT_EQ(analysis.LoopMergeBlock(5), 0); + EXPECT_EQ(analysis.ContainingSwitch(5), 2); + EXPECT_EQ(analysis.SwitchMergeBlock(5), 4); + EXPECT_FALSE(analysis.IsContinueBlock(5)); + EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(5)); + EXPECT_FALSE(analysis.IsInContinueConstruct(5)); + EXPECT_FALSE(analysis.IsMergeBlock(5)); +} + +TEST_F(StructCFGAnalysisTest, SelectionInContinue) { + const std::string text = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +%void = OpTypeVoid +%bool = OpTypeBool +%bool_undef = OpUndef %bool +%uint = OpTypeInt 32 0 +%uint_undef = OpUndef %uint +%void_func = OpTypeFunction %void +%main = OpFunction %void None %void_func +%entry_lab = OpLabel +OpBranch %1 +%1 = OpLabel +OpLoopMerge %3 %4 None +OpBranchConditional %undef_bool %2 %3 +%2 = OpLabel +OpBranch %3 +%4 = OpLabel +OpSelectionMerge %6 None +OpBranchConditional %undef_bool %5 %6 +%5 = OpLabel +OpBranch %6 +%6 = OpLabel +OpBranch %1 +%3 = OpLabel +OpReturn +OpFunctionEnd +)"; + + std::unique_ptr context = + BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + + StructuredCFGAnalysis analysis(context.get()); + + // The loop header is not in either construct. + EXPECT_EQ(analysis.ContainingConstruct(1), 0); + EXPECT_EQ(analysis.ContainingLoop(1), 0); + EXPECT_EQ(analysis.MergeBlock(1), 0); + EXPECT_EQ(analysis.LoopMergeBlock(1), 0); + EXPECT_EQ(analysis.ContainingSwitch(1), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(1), 0); + EXPECT_FALSE(analysis.IsContinueBlock(1)); + EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(1)); + EXPECT_FALSE(analysis.IsInContinueConstruct(1)); + EXPECT_FALSE(analysis.IsMergeBlock(1)); + + // Selection header is in the loop only. + EXPECT_EQ(analysis.ContainingConstruct(2), 1); + EXPECT_EQ(analysis.ContainingLoop(2), 1); + EXPECT_EQ(analysis.MergeBlock(2), 3); + EXPECT_EQ(analysis.LoopMergeBlock(2), 3); + EXPECT_EQ(analysis.ContainingSwitch(2), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(2), 0); + EXPECT_FALSE(analysis.IsContinueBlock(2)); + EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(2)); + EXPECT_FALSE(analysis.IsInContinueConstruct(2)); + EXPECT_FALSE(analysis.IsMergeBlock(2)); + + // The loop merge node is not in either construct. + EXPECT_EQ(analysis.ContainingConstruct(3), 0); + EXPECT_EQ(analysis.ContainingLoop(3), 0); + EXPECT_EQ(analysis.MergeBlock(3), 0); + EXPECT_EQ(analysis.LoopMergeBlock(3), 0); + EXPECT_EQ(analysis.ContainingSwitch(3), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(3), 0); + EXPECT_FALSE(analysis.IsContinueBlock(3)); + EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(3)); + EXPECT_FALSE(analysis.IsInContinueConstruct(3)); + EXPECT_TRUE(analysis.IsMergeBlock(3)); + + // The continue block is in the loop only. + EXPECT_EQ(analysis.ContainingConstruct(4), 1); + EXPECT_EQ(analysis.ContainingLoop(4), 1); + EXPECT_EQ(analysis.MergeBlock(4), 3); + EXPECT_EQ(analysis.LoopMergeBlock(4), 3); + EXPECT_EQ(analysis.ContainingSwitch(4), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(4), 0); + EXPECT_TRUE(analysis.IsContinueBlock(4)); + EXPECT_TRUE(analysis.IsInContainingLoopsContinueConstruct(4)); + EXPECT_TRUE(analysis.IsInContinueConstruct(4)); + EXPECT_FALSE(analysis.IsMergeBlock(4)); + + // BB5 is in the selection and the continue for the loop. + EXPECT_EQ(analysis.ContainingConstruct(5), 4); + EXPECT_EQ(analysis.ContainingLoop(5), 1); + EXPECT_EQ(analysis.MergeBlock(5), 6); + EXPECT_EQ(analysis.LoopMergeBlock(5), 3); + EXPECT_EQ(analysis.ContainingSwitch(5), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(5), 0); + EXPECT_FALSE(analysis.IsContinueBlock(5)); + EXPECT_TRUE(analysis.IsInContainingLoopsContinueConstruct(5)); + EXPECT_TRUE(analysis.IsInContinueConstruct(5)); + EXPECT_FALSE(analysis.IsMergeBlock(5)); + + // BB5 is in the continue for the loop. + EXPECT_EQ(analysis.ContainingConstruct(6), 1); + EXPECT_EQ(analysis.ContainingLoop(6), 1); + EXPECT_EQ(analysis.MergeBlock(6), 3); + EXPECT_EQ(analysis.LoopMergeBlock(6), 3); + EXPECT_EQ(analysis.ContainingSwitch(6), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(6), 0); + EXPECT_FALSE(analysis.IsContinueBlock(6)); + EXPECT_TRUE(analysis.IsInContainingLoopsContinueConstruct(6)); + EXPECT_TRUE(analysis.IsInContinueConstruct(6)); + EXPECT_TRUE(analysis.IsMergeBlock(6)); +} + +TEST_F(StructCFGAnalysisTest, LoopInContinue) { + const std::string text = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +%void = OpTypeVoid +%bool = OpTypeBool +%bool_undef = OpUndef %bool +%uint = OpTypeInt 32 0 +%uint_undef = OpUndef %uint +%void_func = OpTypeFunction %void +%main = OpFunction %void None %void_func +%entry_lab = OpLabel +OpBranch %1 +%1 = OpLabel +OpLoopMerge %3 %7 None +OpBranchConditional %undef_bool %2 %3 +%2 = OpLabel +OpBranchConditional %undef_bool %3 %7 +%7 = OpLabel +OpLoopMerge %4 %5 None +OpBranchConditional %undef_bool %4 %6 +%5 = OpLabel +OpBranch %7 +%6 = OpLabel +OpBranch %4 +%4 = OpLabel +OpBranch %1 +%3 = OpLabel +OpReturn +OpFunctionEnd +)"; + + std::unique_ptr context = + BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + + StructuredCFGAnalysis analysis(context.get()); + + // The outer loop header is not in either construct. + EXPECT_EQ(analysis.ContainingConstruct(1), 0); + EXPECT_EQ(analysis.ContainingLoop(1), 0); + EXPECT_EQ(analysis.MergeBlock(1), 0); + EXPECT_EQ(analysis.LoopMergeBlock(1), 0); + EXPECT_EQ(analysis.ContainingSwitch(1), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(1), 0); + EXPECT_FALSE(analysis.IsContinueBlock(1)); + EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(1)); + EXPECT_FALSE(analysis.IsInContinueConstruct(1)); + EXPECT_FALSE(analysis.IsMergeBlock(1)); + + // BB2 is a regular block in the inner loop. + EXPECT_EQ(analysis.ContainingConstruct(2), 1); + EXPECT_EQ(analysis.ContainingLoop(2), 1); + EXPECT_EQ(analysis.MergeBlock(2), 3); + EXPECT_EQ(analysis.LoopMergeBlock(2), 3); + EXPECT_EQ(analysis.ContainingSwitch(2), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(2), 0); + EXPECT_FALSE(analysis.IsContinueBlock(2)); + EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(2)); + EXPECT_FALSE(analysis.IsInContinueConstruct(2)); + EXPECT_FALSE(analysis.IsMergeBlock(2)); + + // The outer merge node is not in either construct. + EXPECT_EQ(analysis.ContainingConstruct(3), 0); + EXPECT_EQ(analysis.ContainingLoop(3), 0); + EXPECT_EQ(analysis.MergeBlock(3), 0); + EXPECT_EQ(analysis.LoopMergeBlock(3), 0); + EXPECT_EQ(analysis.ContainingSwitch(3), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(3), 0); + EXPECT_FALSE(analysis.IsContinueBlock(3)); + EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(3)); + EXPECT_FALSE(analysis.IsInContinueConstruct(3)); + EXPECT_TRUE(analysis.IsMergeBlock(3)); + + // The inner merge is in the continue of the outer loop. + EXPECT_EQ(analysis.ContainingConstruct(4), 1); + EXPECT_EQ(analysis.ContainingLoop(4), 1); + EXPECT_EQ(analysis.MergeBlock(4), 3); + EXPECT_EQ(analysis.LoopMergeBlock(4), 3); + EXPECT_EQ(analysis.ContainingSwitch(4), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(4), 0); + EXPECT_FALSE(analysis.IsContinueBlock(4)); + EXPECT_TRUE(analysis.IsInContainingLoopsContinueConstruct(4)); + EXPECT_TRUE(analysis.IsInContinueConstruct(4)); + EXPECT_TRUE(analysis.IsMergeBlock(4)); + + // The inner continue target is in the inner loop. + EXPECT_EQ(analysis.ContainingConstruct(5), 7); + EXPECT_EQ(analysis.ContainingLoop(5), 7); + EXPECT_EQ(analysis.MergeBlock(5), 4); + EXPECT_EQ(analysis.LoopMergeBlock(5), 4); + EXPECT_EQ(analysis.ContainingSwitch(5), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(5), 0); + EXPECT_TRUE(analysis.IsContinueBlock(5)); + EXPECT_TRUE(analysis.IsInContainingLoopsContinueConstruct(5)); + EXPECT_TRUE(analysis.IsInContinueConstruct(5)); + EXPECT_FALSE(analysis.IsMergeBlock(5)); + + // BB6 is a regular block in the inner loop. + EXPECT_EQ(analysis.ContainingConstruct(6), 7); + EXPECT_EQ(analysis.ContainingLoop(6), 7); + EXPECT_EQ(analysis.MergeBlock(6), 4); + EXPECT_EQ(analysis.LoopMergeBlock(6), 4); + EXPECT_EQ(analysis.ContainingSwitch(6), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(6), 0); + EXPECT_FALSE(analysis.IsContinueBlock(6)); + EXPECT_FALSE(analysis.IsInContainingLoopsContinueConstruct(6)); + EXPECT_TRUE(analysis.IsInContinueConstruct(6)); + EXPECT_FALSE(analysis.IsMergeBlock(6)); + + // The outer continue target is in the outer loop. + EXPECT_EQ(analysis.ContainingConstruct(7), 1); + EXPECT_EQ(analysis.ContainingLoop(7), 1); + EXPECT_EQ(analysis.MergeBlock(7), 3); + EXPECT_EQ(analysis.LoopMergeBlock(7), 3); + EXPECT_EQ(analysis.ContainingSwitch(7), 0); + EXPECT_EQ(analysis.SwitchMergeBlock(7), 0); + EXPECT_TRUE(analysis.IsContinueBlock(7)); + EXPECT_TRUE(analysis.IsInContainingLoopsContinueConstruct(7)); + EXPECT_TRUE(analysis.IsInContinueConstruct(7)); + EXPECT_FALSE(analysis.IsMergeBlock(7)); +} + +TEST_F(StructCFGAnalysisTest, FuncCallInContinueDirect) { + const std::string text = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "main" + %void = OpTypeVoid + %bool = OpTypeBool + %4 = OpUndef %bool + %uint = OpTypeInt 32 0 + %6 = OpUndef %uint + %7 = OpTypeFunction %void + %1 = OpFunction %void None %7 + %8 = OpLabel + OpBranch %9 + %9 = OpLabel + OpLoopMerge %10 %11 None + OpBranchConditional %12 %10 %11 + %11 = OpLabel + %13 = OpFunctionCall %void %14 + OpBranch %9 + %10 = OpLabel + %15 = OpFunctionCall %void %16 + OpReturn + OpFunctionEnd + %14 = OpFunction %void None %7 + %17 = OpLabel + OpReturn + OpFunctionEnd + %16 = OpFunction %void None %7 + %18 = OpLabel + OpReturn + OpFunctionEnd +)"; + + std::unique_ptr context = + BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + + StructuredCFGAnalysis analysis(context.get()); + + auto c = analysis.FindFuncsCalledFromContinue(); + EXPECT_THAT(c, UnorderedElementsAre(14u)); +} + +TEST_F(StructCFGAnalysisTest, FuncCallInContinueIndirect) { + const std::string text = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "main" + %void = OpTypeVoid + %bool = OpTypeBool + %4 = OpUndef %bool + %uint = OpTypeInt 32 0 + %6 = OpUndef %uint + %7 = OpTypeFunction %void + %1 = OpFunction %void None %7 + %8 = OpLabel + OpBranch %9 + %9 = OpLabel + OpLoopMerge %10 %11 None + OpBranchConditional %12 %10 %11 + %11 = OpLabel + %13 = OpFunctionCall %void %14 + OpBranch %9 + %10 = OpLabel + %15 = OpFunctionCall %void %16 + OpReturn + OpFunctionEnd + %14 = OpFunction %void None %7 + %17 = OpLabel + %19 = OpFunctionCall %void %16 + OpReturn + OpFunctionEnd + %16 = OpFunction %void None %7 + %18 = OpLabel + %20 = OpFunctionCall %void %21 + OpReturn + OpFunctionEnd + %21 = OpFunction %void None %7 + %22 = OpLabel + OpReturn + OpFunctionEnd +)"; + + std::unique_ptr context = + BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + + StructuredCFGAnalysis analysis(context.get()); + + auto c = analysis.FindFuncsCalledFromContinue(); + EXPECT_THAT(c, UnorderedElementsAre(14u, 16u, 21u)); +} +} // namespace +} // namespace opt +} // namespace spvtools diff --git a/third_party/spirv-tools/test/opt/type_manager_test.cpp b/third_party/spirv-tools/test/opt/type_manager_test.cpp index cf1fcb583e..743d0b616a 100644 --- a/third_party/spirv-tools/test/opt/type_manager_test.cpp +++ b/third_party/spirv-tools/test/opt/type_manager_test.cpp @@ -17,6 +17,7 @@ #include #include +#include "effcee/effcee.h" #include "gmock/gmock.h" #include "gtest/gtest.h" #include "source/opt/build_module.h" @@ -24,17 +25,11 @@ #include "source/opt/type_manager.h" #include "spirv-tools/libspirv.hpp" -#ifdef SPIRV_EFFCEE -#include "effcee/effcee.h" -#endif - namespace spvtools { namespace opt { namespace analysis { namespace { -#ifdef SPIRV_EFFCEE - bool Validate(const std::vector& bin) { spv_target_env target_env = SPV_ENV_UNIVERSAL_1_2; spv_context spvContext = spvContextCreate(target_env); @@ -66,8 +61,6 @@ void Match(const std::string& original, IRContext* context, << assembly; } -#endif - std::vector> GenerateAllTypes() { // Types in this test case are only equal to themselves, nothing else. std::vector> types; @@ -124,10 +117,10 @@ std::vector> GenerateAllTypes() { types.emplace_back(new SampledImage(image2)); // Array - types.emplace_back(new Array(f32, 100)); - types.emplace_back(new Array(f32, 42)); + types.emplace_back(new Array(f32, Array::LengthInfo{100, {0, 100u}})); + types.emplace_back(new Array(f32, Array::LengthInfo{42, {0, 42u}})); auto* a42f32 = types.back().get(); - types.emplace_back(new Array(u64, 24)); + types.emplace_back(new Array(u64, Array::LengthInfo{24, {0, 24u}})); // RuntimeArray types.emplace_back(new RuntimeArray(v3f32)); @@ -163,7 +156,8 @@ std::vector> GenerateAllTypes() { types.emplace_back(new ReserveId()); types.emplace_back(new Queue()); - // Pipe, Forward Pointer, PipeStorage, NamedBarrier + // Pipe, Forward Pointer, PipeStorage, NamedBarrier, AccelerationStructureNV, + // CooperativeMatrixNV types.emplace_back(new Pipe(SpvAccessQualifierReadWrite)); types.emplace_back(new Pipe(SpvAccessQualifierReadOnly)); types.emplace_back(new ForwardPointer(1, SpvStorageClassInput)); @@ -171,13 +165,16 @@ std::vector> GenerateAllTypes() { types.emplace_back(new ForwardPointer(2, SpvStorageClassUniform)); types.emplace_back(new PipeStorage()); types.emplace_back(new NamedBarrier()); + types.emplace_back(new AccelerationStructureNV()); + types.emplace_back(new CooperativeMatrixNV(f32, 24, 24, 24)); return types; } TEST(TypeManager, TypeStrings) { const std::string text = R"( - OpTypeForwardPointer !20 !2 ; id for %p is 20, Uniform is 2 + OpDecorate %spec_const_with_id SpecId 99 + OpTypeForwardPointer %p Uniform %void = OpTypeVoid %bool = OpTypeBool %u32 = OpTypeInt 32 0 @@ -206,47 +203,71 @@ TEST(TypeManager, TypeStrings) { %pipe = OpTypePipe ReadOnly %ps = OpTypePipeStorage %nb = OpTypeNamedBarrier + %rtacc = OpTypeAccelerationStructureNV + ; Set up other kinds of OpTypeArray + %s64 = OpTypeInt 64 1 + ; ID 32 + %spec_const_without_id = OpSpecConstant %s32 44 + %spec_const_with_id = OpSpecConstant %s32 42 ;; This is ID 1 + %long_constant = OpConstant %s64 5000000000 + %spec_const_op = OpSpecConstantOp %s32 IAdd %id4 %id4 + ; ID 35 + %arr_spec_const_without_id = OpTypeArray %s32 %spec_const_without_id + %arr_spec_const_with_id = OpTypeArray %s32 %spec_const_with_id + %arr_long_constant = OpTypeArray %s32 %long_constant + %arr_spec_const_op = OpTypeArray %s32 %spec_const_op + %cm = OpTypeCooperativeMatrixNV %f64 %id4 %id4 %id4 )"; std::vector> type_id_strs = { - {1, "void"}, - {2, "bool"}, - {3, "uint32"}, - // Id 4 is used by the constant. - {5, "sint32"}, - {6, "float64"}, - {7, ""}, - {8, "<, 3>"}, - {9, "image(sint32, 3, 0, 1, 1, 0, 3, 2)"}, - {10, "image(sint32, 3, 0, 1, 1, 0, 3, 0)"}, - {11, "sampler"}, - {12, "sampled_image(image(sint32, 3, 0, 1, 1, 0, 3, 2))"}, - {13, "sampled_image(image(sint32, 3, 0, 1, 1, 0, 3, 0))"}, - {14, "[uint32, id(4)]"}, - {15, "[float64]"}, - {16, "{uint32}"}, - {17, "{float64, sint32, }"}, - {18, "opaque('')"}, - {19, "opaque('opaque')"}, - {20, "{uint32}*"}, - {21, "(uint32, uint32) -> void"}, - {22, "event"}, - {23, "device_event"}, - {24, "reserve_id"}, - {25, "queue"}, - {26, "pipe(0)"}, - {27, "pipe_storage"}, - {28, "named_barrier"}, + {3, "void"}, + {4, "bool"}, + {5, "uint32"}, + // Id 6 is used by the constant. + {7, "sint32"}, + {8, "float64"}, + {9, ""}, + {10, "<, 3>"}, + {11, "image(sint32, 3, 0, 1, 1, 0, 3, 2)"}, + {12, "image(sint32, 3, 0, 1, 1, 0, 3, 0)"}, + {13, "sampler"}, + {14, "sampled_image(image(sint32, 3, 0, 1, 1, 0, 3, 2))"}, + {15, "sampled_image(image(sint32, 3, 0, 1, 1, 0, 3, 0))"}, + {16, "[uint32, id(6), words(0,4)]"}, + {17, "[float64]"}, + {18, "{uint32}"}, + {19, "{float64, sint32, }"}, + {20, "opaque('')"}, + {21, "opaque('opaque')"}, + {2, "{uint32} 2*"}, // Include storage class number + {22, "(uint32, uint32) -> void"}, + {23, "event"}, + {24, "device_event"}, + {25, "reserve_id"}, + {26, "queue"}, + {27, "pipe(0)"}, + {28, "pipe_storage"}, + {29, "named_barrier"}, + {30, "accelerationStructureNV"}, + {31, "sint64"}, + {35, "[sint32, id(32), words(0,44)]"}, + {36, "[sint32, id(1), words(1,99,42)]"}, + {37, "[sint32, id(33), words(0,705032704,1)]"}, + {38, "[sint32, id(34), words(2,34)]"}, + {39, ""}, }; std::unique_ptr context = BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text); + ASSERT_NE(nullptr, context.get()); // It assembled TypeManager manager(nullptr, context.get()); EXPECT_EQ(type_id_strs.size(), manager.NumTypes()); for (const auto& p : type_id_strs) { - EXPECT_EQ(p.second, manager.GetType(p.first)->str()); + ASSERT_NE(nullptr, manager.GetType(p.first)); + EXPECT_EQ(p.second, manager.GetType(p.first)->str()) + << " id is " << p.first; EXPECT_EQ(p.first, manager.GetId(manager.GetType(p.first))); } } @@ -939,7 +960,6 @@ OpMemoryModel Logical GLSL450 EXPECT_EQ(nullptr, context->get_type_mgr()->GetType(id)); } -#ifdef SPIRV_EFFCEE TEST(TypeManager, GetTypeInstructionInt) { const std::string text = R"( ; CHECK: OpTypeInt 32 0 @@ -1043,6 +1063,8 @@ TEST(TypeManager, GetTypeInstructionAllTypes) { ; CHECK: OpTypeForwardPointer [[uniform_ptr]] Uniform ; CHECK: OpTypePipeStorage ; CHECK: OpTypeNamedBarrier +; CHECK: OpTypeAccelerationStructureNV +; CHECK: OpTypeCooperativeMatrixNV [[f32]] [[uint24]] [[uint24]] [[uint24]] OpCapability Shader OpCapability Int64 OpCapability Linkage @@ -1145,7 +1167,6 @@ OpMemoryModel Logical GLSL450 context->get_type_mgr()->FindPointerToType(2, SpvStorageClassFunction); Match(text, context.get()); } -#endif // SPIRV_EFFCEE } // namespace } // namespace analysis diff --git a/third_party/spirv-tools/test/opt/types_test.cpp b/third_party/spirv-tools/test/opt/types_test.cpp index c11187e834..82e40405cf 100644 --- a/third_party/spirv-tools/test/opt/types_test.cpp +++ b/third_party/spirv-tools/test/opt/types_test.cpp @@ -12,12 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include "source/opt/types.h" + #include #include #include #include "gtest/gtest.h" -#include "source/opt/types.h" #include "source/util/make_unique.h" namespace spvtools { @@ -46,8 +47,8 @@ class SameTypeTest : public ::testing::Test { std::unique_ptr image_t_; }; -#define TestMultipleInstancesOfTheSameType(ty, ...) \ - TEST_F(SameTypeTest, MultiSame##ty) { \ +#define TestMultipleInstancesOfTheSameTypeQualified(ty, name, ...) \ + TEST_F(SameTypeTest, MultiSame##ty##name) { \ std::vector> types; \ for (int i = 0; i < 10; ++i) types.emplace_back(new ty(__VA_ARGS__)); \ for (size_t i = 0; i < types.size(); ++i) { \ @@ -61,36 +62,59 @@ class SameTypeTest : public ::testing::Test { } \ } \ } -TestMultipleInstancesOfTheSameType(Void); -TestMultipleInstancesOfTheSameType(Bool); -TestMultipleInstancesOfTheSameType(Integer, 32, true); -TestMultipleInstancesOfTheSameType(Float, 64); -TestMultipleInstancesOfTheSameType(Vector, u32_t_.get(), 3); -TestMultipleInstancesOfTheSameType(Matrix, v3u32_t_.get(), 4); +#define TestMultipleInstancesOfTheSameType(ty, ...) \ + TestMultipleInstancesOfTheSameTypeQualified(ty, Simple, __VA_ARGS__) + +// clang-format off +TestMultipleInstancesOfTheSameType(Void) +TestMultipleInstancesOfTheSameType(Bool) +TestMultipleInstancesOfTheSameType(Integer, 32, true) +TestMultipleInstancesOfTheSameType(Float, 64) +TestMultipleInstancesOfTheSameType(Vector, u32_t_.get(), 3) +TestMultipleInstancesOfTheSameType(Matrix, v3u32_t_.get(), 4) TestMultipleInstancesOfTheSameType(Image, f64_t_.get(), SpvDimCube, 0, 0, 1, 1, SpvImageFormatRgb10A2, - SpvAccessQualifierWriteOnly); -TestMultipleInstancesOfTheSameType(Sampler); -TestMultipleInstancesOfTheSameType(SampledImage, image_t_.get()); -TestMultipleInstancesOfTheSameType(Array, u32_t_.get(), 10); -TestMultipleInstancesOfTheSameType(RuntimeArray, u32_t_.get()); + SpvAccessQualifierWriteOnly) +TestMultipleInstancesOfTheSameType(Sampler) +TestMultipleInstancesOfTheSameType(SampledImage, image_t_.get()) +// There are three classes of arrays, based on the kinds of length information +// they have. +// 1. Array length is a constant or spec constant without spec ID, with literals +// for the constant value. +TestMultipleInstancesOfTheSameTypeQualified(Array, LenConstant, u32_t_.get(), + Array::LengthInfo{42, + { + 0, + 9999, + }}) +// 2. Array length is a spec constant with a given spec id. +TestMultipleInstancesOfTheSameTypeQualified(Array, LenSpecId, u32_t_.get(), + Array::LengthInfo{42, {1, 99}}) +// 3. Array length is an OpSpecConstantOp expression +TestMultipleInstancesOfTheSameTypeQualified(Array, LenDefiningId, u32_t_.get(), + Array::LengthInfo{42, {2, 42}}) + +TestMultipleInstancesOfTheSameType(RuntimeArray, u32_t_.get()) TestMultipleInstancesOfTheSameType(Struct, std::vector{ - u32_t_.get(), f64_t_.get()}); -TestMultipleInstancesOfTheSameType(Opaque, "testing rocks"); -TestMultipleInstancesOfTheSameType(Pointer, u32_t_.get(), SpvStorageClassInput); + u32_t_.get(), f64_t_.get()}) +TestMultipleInstancesOfTheSameType(Opaque, "testing rocks") +TestMultipleInstancesOfTheSameType(Pointer, u32_t_.get(), SpvStorageClassInput) TestMultipleInstancesOfTheSameType(Function, u32_t_.get(), - {f64_t_.get(), f64_t_.get()}); -TestMultipleInstancesOfTheSameType(Event); -TestMultipleInstancesOfTheSameType(DeviceEvent); -TestMultipleInstancesOfTheSameType(ReserveId); -TestMultipleInstancesOfTheSameType(Queue); -TestMultipleInstancesOfTheSameType(Pipe, SpvAccessQualifierReadWrite); -TestMultipleInstancesOfTheSameType(ForwardPointer, 10, SpvStorageClassUniform); -TestMultipleInstancesOfTheSameType(PipeStorage); -TestMultipleInstancesOfTheSameType(NamedBarrier); + {f64_t_.get(), f64_t_.get()}) +TestMultipleInstancesOfTheSameType(Event) +TestMultipleInstancesOfTheSameType(DeviceEvent) +TestMultipleInstancesOfTheSameType(ReserveId) +TestMultipleInstancesOfTheSameType(Queue) +TestMultipleInstancesOfTheSameType(Pipe, SpvAccessQualifierReadWrite) +TestMultipleInstancesOfTheSameType(ForwardPointer, 10, SpvStorageClassUniform) +TestMultipleInstancesOfTheSameType(PipeStorage) +TestMultipleInstancesOfTheSameType(NamedBarrier) +TestMultipleInstancesOfTheSameType(AccelerationStructureNV) #undef TestMultipleInstanceOfTheSameType +#undef TestMultipleInstanceOfTheSameTypeQual std::vector> GenerateAllTypes() { + // clang-format on // Types in this test case are only equal to themselves, nothing else. std::vector> types; @@ -150,10 +174,31 @@ std::vector> GenerateAllTypes() { types.emplace_back(new SampledImage(image2)); // Array - types.emplace_back(new Array(f32, 100)); - types.emplace_back(new Array(f32, 42)); + // Length is constant with integer bit representation of 42. + types.emplace_back(new Array(f32, Array::LengthInfo{99u, {0, 42u}})); auto* a42f32 = types.back().get(); - types.emplace_back(new Array(u64, 24)); + // Differs from previous in length value only. + types.emplace_back(new Array(f32, Array::LengthInfo{99u, {0, 44u}})); + // Length is 64-bit constant integer value 42. + types.emplace_back(new Array(u64, Array::LengthInfo{100u, {0, 42u, 0u}})); + // Differs from previous in length value only. + types.emplace_back(new Array(u64, Array::LengthInfo{100u, {0, 44u, 0u}})); + + // Length is spec constant with spec id 18 and default value 44. + types.emplace_back(new Array(f32, Array::LengthInfo{99u, + { + 1, + 18u, + 44u, + }})); + // Differs from previous in spec id only. + types.emplace_back(new Array(f32, Array::LengthInfo{99u, {1, 19u, 44u}})); + // Differs from previous in literal value only. + types.emplace_back(new Array(f32, Array::LengthInfo{99u, {1, 19u, 48u}})); + // Length is spec constant op with id 42. + types.emplace_back(new Array(f32, Array::LengthInfo{42u, {2, 42}})); + // Differs from previous in result id only. + types.emplace_back(new Array(f32, Array::LengthInfo{43u, {2, 43}})); // RuntimeArray types.emplace_back(new RuntimeArray(v3f32)); @@ -214,8 +259,8 @@ TEST(Types, AllTypes) { << types[j]->str() << "'"; } else { EXPECT_FALSE(types[i]->IsSame(types[j].get())) - << "expected '" << types[i]->str() << "' is different to '" - << types[j]->str() << "'"; + << "entry (" << i << "," << j << ") expected '" << types[i]->str() + << "' is different to '" << types[j]->str() << "'"; } } } diff --git a/third_party/spirv-tools/test/opt/unify_const_test.cpp b/third_party/spirv-tools/test/opt/unify_const_test.cpp index 37728cc232..6ed2173486 100644 --- a/third_party/spirv-tools/test/opt/unify_const_test.cpp +++ b/third_party/spirv-tools/test/opt/unify_const_test.cpp @@ -354,8 +354,14 @@ TEST_P(UnifyFrontEndConstantParamTest, TestCase) { Check(expected_builder, test_builder); } -INSTANTIATE_TEST_CASE_P(Case, UnifyFrontEndConstantParamTest, - ::testing::ValuesIn(std::vector({ +INSTANTIATE_TEST_SUITE_P( + Case, UnifyFrontEndConstantParamTest, + :: + testing:: + ValuesIn( + std:: + vector( + { // clang-format off // basic tests for scalar constants { diff --git a/third_party/spirv-tools/test/opt/upgrade_memory_model_test.cpp b/third_party/spirv-tools/test/opt/upgrade_memory_model_test.cpp new file mode 100644 index 0000000000..7f64ffd7cf --- /dev/null +++ b/third_party/spirv-tools/test/opt/upgrade_memory_model_test.cpp @@ -0,0 +1,2272 @@ +// Copyright (c) 2018 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 "assembly_builder.h" +#include "gmock/gmock.h" +#include "pass_fixture.h" +#include "pass_utils.h" + +namespace { + +using namespace spvtools; + +using UpgradeMemoryModelTest = opt::PassTest<::testing::Test>; + +TEST_F(UpgradeMemoryModelTest, InvalidMemoryModelOpenCL) { + const std::string text = R"( +; CHECK: OpMemoryModel Logical OpenCL +OpCapability Kernel +OpCapability Linkage +OpMemoryModel Logical OpenCL +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, InvalidMemoryModelVulkan) { + const std::string text = R"( +; CHECK: OpMemoryModel Logical Vulkan +OpCapability Shader +OpCapability Linkage +OpCapability VulkanMemoryModel +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical Vulkan +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, JustMemoryModel) { + const std::string text = R"( +; CHECK: OpCapability VulkanMemoryModel +; CHECK: OpExtension "SPV_KHR_vulkan_memory_model" +; CHECK: OpMemoryModel Logical Vulkan +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, RemoveDecorations) { + const std::string text = R"( +; CHECK-NOT: OpDecorate +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpDecorate %var Volatile +OpDecorate %var Coherent +%int = OpTypeInt 32 0 +%ptr_int_Uniform = OpTypePointer Uniform %int +%var = OpVariable %ptr_int_Uniform Uniform +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, WorkgroupVariable) { + const std::string text = R"( +; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 2 +; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisible|NonPrivatePointer [[scope]] +; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerAvailable|NonPrivatePointer [[scope]] +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%ptr_int_Workgroup = OpTypePointer Workgroup %int +%var = OpVariable %ptr_int_Workgroup Workgroup +%func_ty = OpTypeFunction %void +%func = OpFunction %void None %func_ty +%1 = OpLabel +%ld = OpLoad %int %var +OpStore %var %ld +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, WorkgroupFunctionParameter) { + const std::string text = R"( +; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 2 +; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisible|NonPrivatePointer [[scope]] +; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerAvailable|NonPrivatePointer [[scope]] +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%ptr_int_Workgroup = OpTypePointer Workgroup %int +%func_ty = OpTypeFunction %void %ptr_int_Workgroup +%func = OpFunction %void None %func_ty +%param = OpFunctionParameter %ptr_int_Workgroup +%1 = OpLabel +%ld = OpLoad %int %param +OpStore %param %ld +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, SimpleUniformVariable) { + const std::string text = R"( +; CHECK-NOT: OpDecorate +; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5 +; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerVisible|NonPrivatePointer [[scope]] +; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerAvailable|NonPrivatePointer [[scope]] +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpDecorate %var Coherent +OpDecorate %var Volatile +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%ptr_int_Uniform = OpTypePointer Uniform %int +%var = OpVariable %ptr_int_Uniform Uniform +%func_ty = OpTypeFunction %void +%func = OpFunction %void None %func_ty +%1 = OpLabel +%ld = OpLoad %int %var +OpStore %var %ld +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, SimpleUniformFunctionParameter) { + const std::string text = R"( +; CHECK-NOT: OpDecorate +; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5 +; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerVisible|NonPrivatePointer [[scope]] +; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerAvailable|NonPrivatePointer [[scope]] +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpDecorate %param Coherent +OpDecorate %param Volatile +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%ptr_int_Uniform = OpTypePointer Uniform %int +%func_ty = OpTypeFunction %void %ptr_int_Uniform +%func = OpFunction %void None %func_ty +%param = OpFunctionParameter %ptr_int_Uniform +%1 = OpLabel +%ld = OpLoad %int %param +OpStore %param %ld +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, SimpleUniformVariableOnlyVolatile) { + const std::string text = R"( +; CHECK-NOT: OpDecorate +; CHECK-NOT: OpConstant +; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile +; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpDecorate %var Volatile +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%ptr_int_Uniform = OpTypePointer Uniform %int +%var = OpVariable %ptr_int_Uniform Uniform +%func_ty = OpTypeFunction %void +%func = OpFunction %void None %func_ty +%1 = OpLabel +%ld = OpLoad %int %var +OpStore %var %ld +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, SimpleUniformVariableCopied) { + const std::string text = R"( +; CHECK-NOT: OpDecorate +; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5 +; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerVisible|NonPrivatePointer [[scope]] +; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerAvailable|NonPrivatePointer [[scope]] +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpDecorate %var Coherent +OpDecorate %var Volatile +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%ptr_int_Uniform = OpTypePointer Uniform %int +%var = OpVariable %ptr_int_Uniform Uniform +%func_ty = OpTypeFunction %void +%func = OpFunction %void None %func_ty +%1 = OpLabel +%copy = OpCopyObject %ptr_int_Uniform %var +%ld = OpLoad %int %copy +OpStore %copy %ld +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, SimpleUniformFunctionParameterCopied) { + const std::string text = R"( +; CHECK-NOT: OpDecorate +; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5 +; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerVisible|NonPrivatePointer [[scope]] +; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerAvailable|NonPrivatePointer [[scope]] +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpDecorate %param Coherent +OpDecorate %param Volatile +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%ptr_int_Uniform = OpTypePointer Uniform %int +%func_ty = OpTypeFunction %void %ptr_int_Uniform +%func = OpFunction %void None %func_ty +%param = OpFunctionParameter %ptr_int_Uniform +%1 = OpLabel +%copy = OpCopyObject %ptr_int_Uniform %param +%ld = OpLoad %int %copy +%copy2 = OpCopyObject %ptr_int_Uniform %param +OpStore %copy2 %ld +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, SimpleUniformVariableAccessChain) { + const std::string text = R"( +; CHECK-NOT: OpDecorate +; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5 +; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerVisible|NonPrivatePointer [[scope]] +; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerAvailable|NonPrivatePointer [[scope]] +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpDecorate %var Coherent +OpDecorate %var Volatile +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int0 = OpConstant %int 0 +%int3 = OpConstant %int 3 +%int_array_3 = OpTypeArray %int %int3 +%ptr_intarray_Uniform = OpTypePointer Uniform %int_array_3 +%ptr_int_Uniform = OpTypePointer Uniform %int +%var = OpVariable %ptr_intarray_Uniform Uniform +%func_ty = OpTypeFunction %void +%func = OpFunction %void None %func_ty +%1 = OpLabel +%gep = OpAccessChain %ptr_int_Uniform %var %int0 +%ld = OpLoad %int %gep +OpStore %gep %ld +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, SimpleUniformFunctionParameterAccessChain) { + const std::string text = R"( +; CHECK-NOT: OpDecorate +; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5 +; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerVisible|NonPrivatePointer [[scope]] +; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerAvailable|NonPrivatePointer [[scope]] +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpDecorate %param Coherent +OpDecorate %param Volatile +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int0 = OpConstant %int 0 +%int3 = OpConstant %int 3 +%int_array_3 = OpTypeArray %int %int3 +%ptr_intarray_Uniform = OpTypePointer Uniform %int_array_3 +%ptr_int_Uniform = OpTypePointer Uniform %int +%func_ty = OpTypeFunction %void %ptr_intarray_Uniform +%func = OpFunction %void None %func_ty +%param = OpFunctionParameter %ptr_intarray_Uniform +%1 = OpLabel +%ld_gep = OpAccessChain %ptr_int_Uniform %param %int0 +%ld = OpLoad %int %ld_gep +%st_gep = OpAccessChain %ptr_int_Uniform %param %int0 +OpStore %st_gep %ld +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, VariablePointerSelect) { + const std::string text = R"( +; CHECK-NOT: OpDecorate +; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5 +; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerVisible|NonPrivatePointer [[scope]] +; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerAvailable|NonPrivatePointer [[scope]] +OpCapability Shader +OpCapability Linkage +OpCapability VariablePointers +OpExtension "SPV_KHR_variable_pointers" +OpMemoryModel Logical GLSL450 +OpDecorate %var Coherent +OpDecorate %var Volatile +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%bool = OpTypeBool +%true = OpConstantTrue %bool +%ptr_int_StorageBuffer = OpTypePointer StorageBuffer %int +%null = OpConstantNull %ptr_int_StorageBuffer +%var = OpVariable %ptr_int_StorageBuffer StorageBuffer +%func_ty = OpTypeFunction %void +%func = OpFunction %void None %func_ty +%1 = OpLabel +%select = OpSelect %ptr_int_StorageBuffer %true %var %null +%ld = OpLoad %int %select +OpStore %var %ld +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, VariablePointerSelectConservative) { + const std::string text = R"( +; CHECK-NOT: OpDecorate +; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5 +; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerVisible|NonPrivatePointer [[scope]] +; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerAvailable|NonPrivatePointer [[scope]] +OpCapability Shader +OpCapability Linkage +OpCapability VariablePointers +OpExtension "SPV_KHR_variable_pointers" +OpMemoryModel Logical GLSL450 +OpDecorate %var1 Coherent +OpDecorate %var2 Volatile +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%bool = OpTypeBool +%true = OpConstantTrue %bool +%ptr_int_StorageBuffer = OpTypePointer StorageBuffer %int +%var1 = OpVariable %ptr_int_StorageBuffer StorageBuffer +%var2 = OpVariable %ptr_int_StorageBuffer StorageBuffer +%func_ty = OpTypeFunction %void +%func = OpFunction %void None %func_ty +%1 = OpLabel +%select = OpSelect %ptr_int_StorageBuffer %true %var1 %var2 +%ld = OpLoad %int %select +OpStore %select %ld +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, VariablePointerIncrement) { + const std::string text = R"( +; CHECK-NOT: OpDecorate {{%\w+}} Coherent +; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5 +; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisible|NonPrivatePointer [[scope]] +; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerAvailable|NonPrivatePointer [[scope]] +OpCapability Shader +OpCapability Linkage +OpCapability VariablePointers +OpExtension "SPV_KHR_variable_pointers" +OpMemoryModel Logical GLSL450 +OpDecorate %param Coherent +OpDecorate %param ArrayStride 4 +%void = OpTypeVoid +%bool = OpTypeBool +%int = OpTypeInt 32 0 +%int0 = OpConstant %int 0 +%int1 = OpConstant %int 1 +%int10 = OpConstant %int 10 +%ptr_int_StorageBuffer = OpTypePointer StorageBuffer %int +%func_ty = OpTypeFunction %void %ptr_int_StorageBuffer +%func = OpFunction %void None %func_ty +%param = OpFunctionParameter %ptr_int_StorageBuffer +%1 = OpLabel +OpBranch %2 +%2 = OpLabel +%phi = OpPhi %ptr_int_StorageBuffer %param %1 %ptr_next %2 +%iv = OpPhi %int %int0 %1 %inc %2 +%inc = OpIAdd %int %iv %int1 +%ptr_next = OpPtrAccessChain %ptr_int_StorageBuffer %phi %int1 +%cmp = OpIEqual %bool %iv %int10 +OpLoopMerge %3 %2 None +OpBranchConditional %cmp %3 %2 +%3 = OpLabel +%ld = OpLoad %int %phi +OpStore %phi %ld +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, CoherentStructElement) { + const std::string text = R"( +; CHECK-NOT: OpMemberDecorate +; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5 +; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisible|NonPrivatePointer [[scope]] +; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerAvailable|NonPrivatePointer [[scope]] +OpCapability Shader +OpCapability Linkage +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpMemoryModel Logical GLSL450 +OpMemberDecorate %struct 0 Coherent +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int0 = OpConstant %int 0 +%struct = OpTypeStruct %int +%ptr_struct_StorageBuffer = OpTypePointer StorageBuffer %struct +%ptr_int_StorageBuffer = OpTypePointer StorageBuffer %int +%func_ty = OpTypeFunction %void %ptr_struct_StorageBuffer +%func = OpFunction %void None %func_ty +%param = OpFunctionParameter %ptr_struct_StorageBuffer +%1 = OpLabel +%gep = OpAccessChain %ptr_int_StorageBuffer %param %int0 +%ld = OpLoad %int %gep +OpStore %gep %ld +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, CoherentElementFullStructAccess) { + const std::string text = R"( +; CHECK-NOT: OpMemberDecorate +; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5 +; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisible|NonPrivatePointer [[scope]] +; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerAvailable|NonPrivatePointer [[scope]] +OpCapability Shader +OpCapability Linkage +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpMemoryModel Logical GLSL450 +OpMemberDecorate %struct 0 Coherent +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%struct = OpTypeStruct %int +%ptr_struct_StorageBuffer = OpTypePointer StorageBuffer %struct +%func_ty = OpTypeFunction %void %ptr_struct_StorageBuffer +%func = OpFunction %void None %func_ty +%param = OpFunctionParameter %ptr_struct_StorageBuffer +%1 = OpLabel +%ld = OpLoad %struct %param +OpStore %param %ld +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, CoherentElementNotAccessed) { + const std::string text = R"( +; CHECK-NOT: OpMemberDecorate +; CHECK-NOT: MakePointerAvailable +; CHECK-NOT: NonPrivatePointer +; CHECK-NOT: MakePointerVisible +OpCapability Shader +OpCapability Linkage +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpMemoryModel Logical GLSL450 +OpMemberDecorate %struct 1 Coherent +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int0 = OpConstant %int 0 +%struct = OpTypeStruct %int %int +%ptr_struct_StorageBuffer = OpTypePointer StorageBuffer %struct +%ptr_int_StorageBuffer = OpTypePointer StorageBuffer %int +%func_ty = OpTypeFunction %void %ptr_struct_StorageBuffer +%func = OpFunction %void None %func_ty +%param = OpFunctionParameter %ptr_struct_StorageBuffer +%1 = OpLabel +%gep = OpAccessChain %ptr_int_StorageBuffer %param %int0 +%ld = OpLoad %int %gep +OpStore %gep %ld +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, MultiIndexAccessCoherent) { + const std::string text = R"( +; CHECK-NOT: OpMemberDecorate +; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5 +; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisible|NonPrivatePointer [[scope]] +; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerAvailable|NonPrivatePointer [[scope]] +OpCapability Shader +OpCapability Linkage +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpMemoryModel Logical GLSL450 +OpMemberDecorate %inner 1 Coherent +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int0 = OpConstant %int 0 +%int1 = OpConstant %int 1 +%inner = OpTypeStruct %int %int +%middle = OpTypeStruct %inner +%outer = OpTypeStruct %middle %middle +%ptr_outer_StorageBuffer = OpTypePointer StorageBuffer %outer +%ptr_int_StorageBuffer = OpTypePointer StorageBuffer %int +%func_ty = OpTypeFunction %void %ptr_outer_StorageBuffer +%func = OpFunction %void None %func_ty +%param = OpFunctionParameter %ptr_outer_StorageBuffer +%1 = OpLabel +%ld_gep = OpInBoundsAccessChain %ptr_int_StorageBuffer %param %int0 %int0 %int1 +%ld = OpLoad %int %ld_gep +%st_gep = OpInBoundsAccessChain %ptr_int_StorageBuffer %param %int1 %int0 %int1 +OpStore %st_gep %ld +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, MultiIndexAccessNonCoherent) { + const std::string text = R"( +; CHECK-NOT: OpMemberDecorate +; CHECK-NOT: MakePointerAvailable +; CHECK-NOT: NonPrivatePointer +; CHECK-NOT: MakePointerVisible +OpCapability Shader +OpCapability Linkage +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpMemoryModel Logical GLSL450 +OpMemberDecorate %inner 1 Coherent +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int0 = OpConstant %int 0 +%int1 = OpConstant %int 1 +%inner = OpTypeStruct %int %int +%middle = OpTypeStruct %inner +%outer = OpTypeStruct %middle %middle +%ptr_outer_StorageBuffer = OpTypePointer StorageBuffer %outer +%ptr_int_StorageBuffer = OpTypePointer StorageBuffer %int +%func_ty = OpTypeFunction %void %ptr_outer_StorageBuffer +%func = OpFunction %void None %func_ty +%param = OpFunctionParameter %ptr_outer_StorageBuffer +%1 = OpLabel +%ld_gep = OpInBoundsAccessChain %ptr_int_StorageBuffer %param %int0 %int0 %int0 +%ld = OpLoad %int %ld_gep +%st_gep = OpInBoundsAccessChain %ptr_int_StorageBuffer %param %int1 %int0 %int0 +OpStore %st_gep %ld +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, ConsecutiveAccessChainCoherent) { + const std::string text = R"( +; CHECK-NOT: OpMemberDecorate +; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5 +; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisible|NonPrivatePointer [[scope]] +; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerAvailable|NonPrivatePointer [[scope]] +OpCapability Shader +OpCapability Linkage +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpMemoryModel Logical GLSL450 +OpMemberDecorate %inner 1 Coherent +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int0 = OpConstant %int 0 +%int1 = OpConstant %int 1 +%inner = OpTypeStruct %int %int +%middle = OpTypeStruct %inner +%outer = OpTypeStruct %middle %middle +%ptr_outer_StorageBuffer = OpTypePointer StorageBuffer %outer +%ptr_middle_StorageBuffer = OpTypePointer StorageBuffer %middle +%ptr_inner_StorageBuffer = OpTypePointer StorageBuffer %inner +%ptr_int_StorageBuffer = OpTypePointer StorageBuffer %int +%func_ty = OpTypeFunction %void %ptr_outer_StorageBuffer +%func = OpFunction %void None %func_ty +%param = OpFunctionParameter %ptr_outer_StorageBuffer +%1 = OpLabel +%ld_gep1 = OpInBoundsAccessChain %ptr_middle_StorageBuffer %param %int0 +%ld_gep2 = OpInBoundsAccessChain %ptr_inner_StorageBuffer %ld_gep1 %int0 +%ld_gep3 = OpInBoundsAccessChain %ptr_int_StorageBuffer %ld_gep2 %int1 +%ld = OpLoad %int %ld_gep3 +%st_gep1 = OpInBoundsAccessChain %ptr_middle_StorageBuffer %param %int1 +%st_gep2 = OpInBoundsAccessChain %ptr_inner_StorageBuffer %st_gep1 %int0 +%st_gep3 = OpInBoundsAccessChain %ptr_int_StorageBuffer %st_gep2 %int1 +OpStore %st_gep3 %ld +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, ConsecutiveAccessChainNonCoherent) { + const std::string text = R"( +; CHECK-NOT: OpMemberDecorate +; CHECK-NOT: MakePointerAvailable +; CHECK-NOT: NonPrivatePointer +; CHECK-NOT: MakePointerVisible +OpCapability Shader +OpCapability Linkage +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpMemoryModel Logical GLSL450 +OpMemberDecorate %inner 1 Coherent +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int0 = OpConstant %int 0 +%int1 = OpConstant %int 1 +%inner = OpTypeStruct %int %int +%middle = OpTypeStruct %inner +%outer = OpTypeStruct %middle %middle +%ptr_outer_StorageBuffer = OpTypePointer StorageBuffer %outer +%ptr_middle_StorageBuffer = OpTypePointer StorageBuffer %middle +%ptr_inner_StorageBuffer = OpTypePointer StorageBuffer %inner +%ptr_int_StorageBuffer = OpTypePointer StorageBuffer %int +%func_ty = OpTypeFunction %void %ptr_outer_StorageBuffer +%func = OpFunction %void None %func_ty +%param = OpFunctionParameter %ptr_outer_StorageBuffer +%1 = OpLabel +%ld_gep1 = OpInBoundsAccessChain %ptr_middle_StorageBuffer %param %int0 +%ld_gep2 = OpInBoundsAccessChain %ptr_inner_StorageBuffer %ld_gep1 %int0 +%ld_gep3 = OpInBoundsAccessChain %ptr_int_StorageBuffer %ld_gep2 %int0 +%ld = OpLoad %int %ld_gep3 +%st_gep1 = OpInBoundsAccessChain %ptr_middle_StorageBuffer %param %int1 +%st_gep2 = OpInBoundsAccessChain %ptr_inner_StorageBuffer %st_gep1 %int0 +%st_gep3 = OpInBoundsAccessChain %ptr_int_StorageBuffer %st_gep2 %int0 +OpStore %st_gep3 %ld +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, CoherentStructElementAccess) { + const std::string text = R"( +; CHECK-NOT: OpMemberDecorate +; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5 +; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisible|NonPrivatePointer [[scope]] +; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerAvailable|NonPrivatePointer [[scope]] +OpCapability Shader +OpCapability Linkage +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpMemoryModel Logical GLSL450 +OpMemberDecorate %middle 0 Coherent +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int0 = OpConstant %int 0 +%int1 = OpConstant %int 1 +%inner = OpTypeStruct %int %int +%middle = OpTypeStruct %inner +%outer = OpTypeStruct %middle %middle +%ptr_outer_StorageBuffer = OpTypePointer StorageBuffer %outer +%ptr_middle_StorageBuffer = OpTypePointer StorageBuffer %middle +%ptr_inner_StorageBuffer = OpTypePointer StorageBuffer %inner +%ptr_int_StorageBuffer = OpTypePointer StorageBuffer %int +%func_ty = OpTypeFunction %void %ptr_outer_StorageBuffer +%func = OpFunction %void None %func_ty +%param = OpFunctionParameter %ptr_outer_StorageBuffer +%1 = OpLabel +%ld_gep1 = OpInBoundsAccessChain %ptr_middle_StorageBuffer %param %int0 +%ld_gep2 = OpInBoundsAccessChain %ptr_inner_StorageBuffer %ld_gep1 %int0 +%ld_gep3 = OpInBoundsAccessChain %ptr_int_StorageBuffer %ld_gep2 %int1 +%ld = OpLoad %int %ld_gep3 +%st_gep1 = OpInBoundsAccessChain %ptr_middle_StorageBuffer %param %int1 +%st_gep2 = OpInBoundsAccessChain %ptr_inner_StorageBuffer %st_gep1 %int0 +%st_gep3 = OpInBoundsAccessChain %ptr_int_StorageBuffer %st_gep2 %int1 +OpStore %st_gep3 %ld +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, NonCoherentLoadCoherentStore) { + const std::string text = R"( +; CHECK-NOT: OpMemberDecorate +; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5 +; CHECK-NOT: MakePointerVisible +; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerAvailable|NonPrivatePointer [[scope]] +OpCapability Shader +OpCapability Linkage +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpMemoryModel Logical GLSL450 +OpMemberDecorate %outer 1 Coherent +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int0 = OpConstant %int 0 +%int1 = OpConstant %int 1 +%inner = OpTypeStruct %int %int +%middle = OpTypeStruct %inner +%outer = OpTypeStruct %middle %middle +%ptr_outer_StorageBuffer = OpTypePointer StorageBuffer %outer +%ptr_middle_StorageBuffer = OpTypePointer StorageBuffer %middle +%ptr_inner_StorageBuffer = OpTypePointer StorageBuffer %inner +%ptr_int_StorageBuffer = OpTypePointer StorageBuffer %int +%func_ty = OpTypeFunction %void %ptr_outer_StorageBuffer +%func = OpFunction %void None %func_ty +%param = OpFunctionParameter %ptr_outer_StorageBuffer +%1 = OpLabel +%ld_gep1 = OpInBoundsAccessChain %ptr_middle_StorageBuffer %param %int0 +%ld_gep2 = OpInBoundsAccessChain %ptr_inner_StorageBuffer %ld_gep1 %int0 +%ld_gep3 = OpInBoundsAccessChain %ptr_int_StorageBuffer %ld_gep2 %int1 +%ld = OpLoad %int %ld_gep3 +%st_gep1 = OpInBoundsAccessChain %ptr_middle_StorageBuffer %param %int1 +%st_gep2 = OpInBoundsAccessChain %ptr_inner_StorageBuffer %st_gep1 %int0 +%st_gep3 = OpInBoundsAccessChain %ptr_int_StorageBuffer %st_gep2 %int1 +OpStore %st_gep3 %ld +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, CopyMemory) { + const std::string text = R"( +; CHECK-NOT: OpDecorate +; CHECK: [[queuefamily:%\w+]] = OpConstant {{%\w+}} 5 +; CHECK: OpCopyMemory {{%\w+}} {{%\w+}} Volatile|MakePointerVisible|NonPrivatePointer [[queuefamily]] +; CHECK-NOT: [[queuefamily]] +OpCapability Shader +OpCapability Linkage +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpMemoryModel Logical GLSL450 +OpDecorate %in_var Coherent +OpDecorate %out_var Volatile +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%ptr_int_StorageBuffer = OpTypePointer StorageBuffer %int +%in_var = OpVariable %ptr_int_StorageBuffer StorageBuffer +%out_var = OpVariable %ptr_int_StorageBuffer StorageBuffer +%func_ty = OpTypeFunction %void +%func = OpFunction %void None %func_ty +%1 = OpLabel +OpCopyMemory %out_var %in_var +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, CopyMemorySized) { + const std::string text = R"( +; CHECK-NOT: OpDecorate +; CHECK: [[queuefamily:%\w+]] = OpConstant {{%\w+}} 5 +; CHECK: OpCopyMemorySized {{%\w+}} {{%\w+}} {{%\w+}} Volatile|MakePointerAvailable|NonPrivatePointer [[queuefamily]] +; CHECK-NOT: [[queuefamily]] +OpCapability Shader +OpCapability Linkage +OpCapability Addresses +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpMemoryModel Logical GLSL450 +OpDecorate %out_param Coherent +OpDecorate %in_param Volatile +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int4 = OpConstant %int 4 +%ptr_int_StorageBuffer = OpTypePointer StorageBuffer %int +%func_ty = OpTypeFunction %void %ptr_int_StorageBuffer %ptr_int_StorageBuffer +%func = OpFunction %void None %func_ty +%in_param = OpFunctionParameter %ptr_int_StorageBuffer +%out_param = OpFunctionParameter %ptr_int_StorageBuffer +%1 = OpLabel +OpCopyMemorySized %out_param %in_param %int4 +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, CopyMemoryTwoScopes) { + const std::string text = R"( +; CHECK-NOT: OpDecorate +; CHECK-DAG: [[queuefamily:%\w+]] = OpConstant {{%\w+}} 5 +; CHECK-DAG: [[workgroup:%\w+]] = OpConstant {{%\w+}} 2 +; CHECK: OpCopyMemory {{%\w+}} {{%\w+}} MakePointerAvailable|MakePointerVisible|NonPrivatePointer [[workgroup]] [[queuefamily]] +OpCapability Shader +OpCapability Linkage +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpMemoryModel Logical GLSL450 +OpDecorate %in_var Coherent +OpDecorate %out_var Coherent +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%ptr_int_Workgroup = OpTypePointer Workgroup %int +%ptr_int_StorageBuffer = OpTypePointer StorageBuffer %int +%in_var = OpVariable %ptr_int_StorageBuffer StorageBuffer +%out_var = OpVariable %ptr_int_Workgroup Workgroup +%func_ty = OpTypeFunction %void +%func = OpFunction %void None %func_ty +%1 = OpLabel +OpCopyMemory %out_var %in_var +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, VolatileImageRead) { + const std::string text = R"( +; CHECK-NOT: OpDecorate +; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile +; CHECK: OpImageRead {{%\w+}} {{%\w+}} {{%\w+}} VolatileTexel +OpCapability Shader +OpCapability Linkage +OpCapability StorageImageReadWithoutFormat +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpMemoryModel Logical GLSL450 +OpDecorate %var Volatile +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%v2int = OpTypeVector %int 2 +%float = OpTypeFloat 32 +%int0 = OpConstant %int 0 +%v2int_0 = OpConstantComposite %v2int %int0 %int0 +%image = OpTypeImage %float 2D 0 0 0 2 Unknown +%ptr_image_StorageBuffer = OpTypePointer StorageBuffer %image +%var = OpVariable %ptr_image_StorageBuffer StorageBuffer +%func_ty = OpTypeFunction %void +%func = OpFunction %void None %func_ty +%1 = OpLabel +%ld = OpLoad %image %var +%rd = OpImageRead %float %ld %v2int_0 +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, CoherentImageRead) { + const std::string text = R"( +; CHECK-NOT: OpDecorate +; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5 +; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisible|NonPrivatePointer [[scope]] +; CHECK: OpImageRead {{%\w+}} {{%\w+}} {{%\w+}} MakeTexelVisible|NonPrivateTexel [[scope]] +OpCapability Shader +OpCapability Linkage +OpCapability StorageImageReadWithoutFormat +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpMemoryModel Logical GLSL450 +OpDecorate %var Coherent +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%v2int = OpTypeVector %int 2 +%float = OpTypeFloat 32 +%int0 = OpConstant %int 0 +%v2int_0 = OpConstantComposite %v2int %int0 %int0 +%image = OpTypeImage %float 2D 0 0 0 2 Unknown +%ptr_image_StorageBuffer = OpTypePointer StorageBuffer %image +%var = OpVariable %ptr_image_StorageBuffer StorageBuffer +%func_ty = OpTypeFunction %void +%func = OpFunction %void None %func_ty +%1 = OpLabel +%ld = OpLoad %image %var +%rd = OpImageRead %float %ld %v2int_0 +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, CoherentImageReadExtractedFromSampledImage) { + const std::string text = R"( +; CHECK-NOT: OpDecorate +; CHECK: [[image:%\w+]] = OpTypeImage +; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5 +; CHECK: OpLoad [[image]] {{%\w+}} MakePointerVisible|NonPrivatePointer [[scope]] +; CHECK-NOT: NonPrivatePointer +; CHECK: OpImageRead {{%\w+}} {{%\w+}} {{%\w+}} MakeTexelVisible|NonPrivateTexel [[scope]] +OpCapability Shader +OpCapability Linkage +OpCapability StorageImageReadWithoutFormat +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpMemoryModel Logical GLSL450 +OpDecorate %var Coherent +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%v2int = OpTypeVector %int 2 +%float = OpTypeFloat 32 +%int0 = OpConstant %int 0 +%v2int_0 = OpConstantComposite %v2int %int0 %int0 +%image = OpTypeImage %float 2D 0 0 0 0 Unknown +%sampled_image = OpTypeSampledImage %image +%sampler = OpTypeSampler +%ptr_image_StorageBuffer = OpTypePointer StorageBuffer %image +%ptr_sampler_StorageBuffer = OpTypePointer StorageBuffer %sampler +%var = OpVariable %ptr_image_StorageBuffer StorageBuffer +%sampler_var = OpVariable %ptr_sampler_StorageBuffer StorageBuffer +%func_ty = OpTypeFunction %void +%func = OpFunction %void None %func_ty +%1 = OpLabel +%ld = OpLoad %image %var +%ld_sampler = OpLoad %sampler %sampler_var +%sample = OpSampledImage %sampled_image %ld %ld_sampler +%extract = OpImage %image %sample +%rd = OpImageRead %float %extract %v2int_0 +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, VolatileImageWrite) { + const std::string text = R"( +; CHECK-NOT: OpDecorate +; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile +; CHECK: OpImageWrite {{%\w+}} {{%\w+}} {{%\w+}} VolatileTexel +OpCapability Shader +OpCapability Linkage +OpCapability StorageImageWriteWithoutFormat +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpMemoryModel Logical GLSL450 +OpDecorate %param Volatile +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%v2int = OpTypeVector %int 2 +%float = OpTypeFloat 32 +%float0 = OpConstant %float 0 +%v2int_null = OpConstantNull %v2int +%image = OpTypeImage %float 2D 0 0 0 0 Unknown +%ptr_image_StorageBuffer = OpTypePointer StorageBuffer %image +%func_ty = OpTypeFunction %void %ptr_image_StorageBuffer +%func = OpFunction %void None %func_ty +%param = OpFunctionParameter %ptr_image_StorageBuffer +%1 = OpLabel +%ld = OpLoad %image %param +OpImageWrite %ld %v2int_null %float0 +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, CoherentImageWrite) { + const std::string text = R"( +; CHECK-NOT: OpDecorate +; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5 +; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisible|NonPrivatePointer +; CHECK: OpImageWrite {{%\w+}} {{%\w+}} {{%\w+}} MakeTexelAvailable|NonPrivateTexel [[scope]] +OpCapability Shader +OpCapability Linkage +OpCapability StorageImageWriteWithoutFormat +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpMemoryModel Logical GLSL450 +OpDecorate %param Coherent +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%v2int = OpTypeVector %int 2 +%float = OpTypeFloat 32 +%float0 = OpConstant %float 0 +%v2int_null = OpConstantNull %v2int +%image = OpTypeImage %float 2D 0 0 0 0 Unknown +%ptr_image_StorageBuffer = OpTypePointer StorageBuffer %image +%func_ty = OpTypeFunction %void %ptr_image_StorageBuffer +%func = OpFunction %void None %func_ty +%param = OpFunctionParameter %ptr_image_StorageBuffer +%1 = OpLabel +%ld = OpLoad %image %param +OpImageWrite %ld %v2int_null %float0 +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, CoherentImageWriteExtractFromSampledImage) { + const std::string text = R"( +; CHECK-NOT: OpDecorate +; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5 +; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisible|NonPrivatePointer +; CHECK-NOT: NonPrivatePointer +; CHECK: OpImageWrite {{%\w+}} {{%\w+}} {{%\w+}} MakeTexelAvailable|NonPrivateTexel [[scope]] +OpCapability Shader +OpCapability Linkage +OpCapability StorageImageWriteWithoutFormat +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpMemoryModel Logical GLSL450 +OpDecorate %param Coherent +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%v2int = OpTypeVector %int 2 +%float = OpTypeFloat 32 +%float0 = OpConstant %float 0 +%v2int_null = OpConstantNull %v2int +%image = OpTypeImage %float 2D 0 0 0 0 Unknown +%sampled_image = OpTypeSampledImage %image +%sampler = OpTypeSampler +%ptr_image_StorageBuffer = OpTypePointer StorageBuffer %image +%ptr_sampler_StorageBuffer = OpTypePointer StorageBuffer %sampler +%func_ty = OpTypeFunction %void %ptr_image_StorageBuffer %ptr_sampler_StorageBuffer +%func = OpFunction %void None %func_ty +%param = OpFunctionParameter %ptr_image_StorageBuffer +%sampler_param = OpFunctionParameter %ptr_sampler_StorageBuffer +%1 = OpLabel +%ld = OpLoad %image %param +%ld_sampler = OpLoad %sampler %sampler_param +%sample = OpSampledImage %sampled_image %ld %ld_sampler +%extract = OpImage %image %sample +OpImageWrite %extract %v2int_null %float0 +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, VolatileImageSparseRead) { + const std::string text = R"( +; CHECK-NOT: OpDecorate +; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile +; CHECK: OpImageSparseRead {{%\w+}} {{%\w+}} {{%\w+}} VolatileTexel +OpCapability Shader +OpCapability Linkage +OpCapability StorageImageReadWithoutFormat +OpCapability SparseResidency +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpMemoryModel Logical GLSL450 +OpDecorate %var Volatile +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%v2int = OpTypeVector %int 2 +%float = OpTypeFloat 32 +%int0 = OpConstant %int 0 +%v2int_0 = OpConstantComposite %v2int %int0 %int0 +%image = OpTypeImage %float 2D 0 0 0 2 Unknown +%struct = OpTypeStruct %int %float +%ptr_image_StorageBuffer = OpTypePointer StorageBuffer %image +%var = OpVariable %ptr_image_StorageBuffer StorageBuffer +%func_ty = OpTypeFunction %void +%func = OpFunction %void None %func_ty +%1 = OpLabel +%ld = OpLoad %image %var +%rd = OpImageSparseRead %struct %ld %v2int_0 +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, CoherentImageSparseRead) { + const std::string text = R"( +; CHECK-NOT: OpDecorate +; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5 +; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisible|NonPrivatePointer [[scope]] +; CHECK: OpImageSparseRead {{%\w+}} {{%\w+}} {{%\w+}} MakeTexelVisible|NonPrivateTexel [[scope]] +OpCapability Shader +OpCapability Linkage +OpCapability StorageImageReadWithoutFormat +OpCapability SparseResidency +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpMemoryModel Logical GLSL450 +OpDecorate %var Coherent +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%v2int = OpTypeVector %int 2 +%float = OpTypeFloat 32 +%int0 = OpConstant %int 0 +%v2int_0 = OpConstantComposite %v2int %int0 %int0 +%image = OpTypeImage %float 2D 0 0 0 2 Unknown +%struct = OpTypeStruct %int %float +%ptr_image_StorageBuffer = OpTypePointer StorageBuffer %image +%var = OpVariable %ptr_image_StorageBuffer StorageBuffer +%func_ty = OpTypeFunction %void +%func = OpFunction %void None %func_ty +%1 = OpLabel +%ld = OpLoad %image %var +%rd = OpImageSparseRead %struct %ld %v2int_0 +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, + CoherentImageSparseReadExtractedFromSampledImage) { + const std::string text = R"( +; CHECK-NOT: OpDecorate +; CHECK: [[image:%\w+]] = OpTypeImage +; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5 +; CHECK: OpLoad [[image]] {{%\w+}} MakePointerVisible|NonPrivatePointer [[scope]] +; CHECK-NOT: NonPrivatePointer +; CHECK: OpImageSparseRead {{%\w+}} {{%\w+}} {{%\w+}} MakeTexelVisible|NonPrivateTexel [[scope]] +OpCapability Shader +OpCapability Linkage +OpCapability StorageImageReadWithoutFormat +OpCapability SparseResidency +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpMemoryModel Logical GLSL450 +OpDecorate %var Coherent +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%v2int = OpTypeVector %int 2 +%float = OpTypeFloat 32 +%int0 = OpConstant %int 0 +%v2int_0 = OpConstantComposite %v2int %int0 %int0 +%image = OpTypeImage %float 2D 0 0 0 0 Unknown +%struct = OpTypeStruct %int %float +%sampled_image = OpTypeSampledImage %image +%sampler = OpTypeSampler +%ptr_image_StorageBuffer = OpTypePointer StorageBuffer %image +%ptr_sampler_StorageBuffer = OpTypePointer StorageBuffer %sampler +%var = OpVariable %ptr_image_StorageBuffer StorageBuffer +%sampler_var = OpVariable %ptr_sampler_StorageBuffer StorageBuffer +%func_ty = OpTypeFunction %void +%func = OpFunction %void None %func_ty +%1 = OpLabel +%ld = OpLoad %image %var +%ld_sampler = OpLoad %sampler %sampler_var +%sample = OpSampledImage %sampled_image %ld %ld_sampler +%extract = OpImage %image %sample +%rd = OpImageSparseRead %struct %extract %v2int_0 +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, TessellationControlBarrierNoChange) { + const std::string text = R"( +; CHECK: [[none:%\w+]] = OpConstant {{%\w+}} 0 +; CHECK: [[workgroup:%\w+]] = OpConstant {{%\w+}} 2 +; CHECK: OpControlBarrier [[workgroup]] [[workgroup]] [[none]] +OpCapability Tessellation +OpMemoryModel Logical GLSL450 +OpEntryPoint TessellationControl %func "func" +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%none = OpConstant %int 0 +%workgroup = OpConstant %int 2 +%func_ty = OpTypeFunction %void +%func = OpFunction %void None %func_ty +%1 = OpLabel +OpControlBarrier %workgroup %workgroup %none +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, TessellationControlBarrierAddOutput) { + const std::string text = R"( +; CHECK: [[workgroup:%\w+]] = OpConstant {{%\w+}} 2 +; CHECK: [[output:%\w+]] = OpConstant {{%\w+}} 4096 +; CHECK: OpControlBarrier [[workgroup]] [[workgroup]] [[output]] +OpCapability Tessellation +OpMemoryModel Logical GLSL450 +OpEntryPoint TessellationControl %func "func" %var +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%none = OpConstant %int 0 +%workgroup = OpConstant %int 2 +%ptr_int_Output = OpTypePointer Output %int +%var = OpVariable %ptr_int_Output Output +%func_ty = OpTypeFunction %void +%func = OpFunction %void None %func_ty +%1 = OpLabel +%ld = OpLoad %int %var +OpControlBarrier %workgroup %workgroup %none +OpStore %var %ld +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, TessellationMemoryBarrierNoChange) { + const std::string text = R"( +; CHECK: [[none:%\w+]] = OpConstant {{%\w+}} 0 +; CHECK: [[workgroup:%\w+]] = OpConstant {{%\w+}} 2 +; CHECK: OpMemoryBarrier [[workgroup]] [[none]] +OpCapability Tessellation +OpMemoryModel Logical GLSL450 +OpEntryPoint TessellationControl %func "func" %var +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%none = OpConstant %int 0 +%workgroup = OpConstant %int 2 +%ptr_int_Output = OpTypePointer Output %int +%var = OpVariable %ptr_int_Output Output +%func_ty = OpTypeFunction %void +%func = OpFunction %void None %func_ty +%1 = OpLabel +%ld = OpLoad %int %var +OpMemoryBarrier %workgroup %none +OpStore %var %ld +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, TessellationControlBarrierAddOutputSubFunction) { + const std::string text = R"( +; CHECK: [[workgroup:%\w+]] = OpConstant {{%\w+}} 2 +; CHECK: [[output:%\w+]] = OpConstant {{%\w+}} 4096 +; CHECK: OpControlBarrier [[workgroup]] [[workgroup]] [[output]] +OpCapability Tessellation +OpMemoryModel Logical GLSL450 +OpEntryPoint TessellationControl %func "func" %var +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%none = OpConstant %int 0 +%workgroup = OpConstant %int 2 +%ptr_int_Output = OpTypePointer Output %int +%var = OpVariable %ptr_int_Output Output +%func_ty = OpTypeFunction %void +%func = OpFunction %void None %func_ty +%1 = OpLabel +%call = OpFunctionCall %void %sub_func +OpReturn +OpFunctionEnd +%sub_func = OpFunction %void None %func_ty +%2 = OpLabel +%ld = OpLoad %int %var +OpControlBarrier %workgroup %workgroup %none +OpStore %var %ld +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, + TessellationControlBarrierAddOutputDifferentFunctions) { + const std::string text = R"( +; CHECK: [[workgroup:%\w+]] = OpConstant {{%\w+}} 2 +; CHECK: [[output:%\w+]] = OpConstant {{%\w+}} 4096 +; CHECK: OpControlBarrier [[workgroup]] [[workgroup]] [[output]] +OpCapability Tessellation +OpMemoryModel Logical GLSL450 +OpEntryPoint TessellationControl %func "func" %var +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%none = OpConstant %int 0 +%workgroup = OpConstant %int 2 +%ptr_int_Output = OpTypePointer Output %int +%var = OpVariable %ptr_int_Output Output +%func_ty = OpTypeFunction %void +%ld_func_ty = OpTypeFunction %int +%st_func_ty = OpTypeFunction %void %int +%func = OpFunction %void None %func_ty +%1 = OpLabel +%call_ld = OpFunctionCall %int %ld_func +%call_barrier = OpFunctionCall %void %barrier_func +%call_st = OpFunctionCall %void %st_func %call_ld +OpReturn +OpFunctionEnd +%ld_func = OpFunction %int None %ld_func_ty +%2 = OpLabel +%ld = OpLoad %int %var +OpReturnValue %ld +OpFunctionEnd +%barrier_func = OpFunction %void None %func_ty +%3 = OpLabel +OpControlBarrier %workgroup %workgroup %none +OpReturn +OpFunctionEnd +%st_func = OpFunction %void None %st_func_ty +%param = OpFunctionParameter %int +%4 = OpLabel +OpStore %var %param +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, ChangeControlBarrierMemoryScope) { + std::string text = R"( +; CHECK: [[workgroup:%\w+]] = OpConstant {{%\w+}} 2 +; CHECK: [[queuefamily:%\w+]] = OpConstant {{%\w+}} 5 +; CHECK: OpControlBarrier [[workgroup]] [[queuefamily]] +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %func "func" +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%none = OpConstant %int 0 +%device = OpConstant %int 1 +%workgroup = OpConstant %int 2 +%func_ty = OpTypeFunction %void +%func = OpFunction %void None %func_ty +%1 = OpLabel +OpControlBarrier %workgroup %device %none +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, ChangeMemoryBarrierMemoryScope) { + std::string text = R"( +; CHECK: [[queuefamily:%\w+]] = OpConstant {{%\w+}} 5 +; CHECK: OpMemoryBarrier [[queuefamily]] +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %func "func" +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%none = OpConstant %int 0 +%device = OpConstant %int 1 +%func_ty = OpTypeFunction %void +%func = OpFunction %void None %func_ty +%1 = OpLabel +OpMemoryBarrier %device %none +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, ChangeAtomicMemoryScope) { + std::string text = R"( +; CHECK: [[int:%\w+]] = OpTypeInt +; CHECK: [[var:%\w+]] = OpVariable +; CHECK: [[qf:%\w+]] = OpConstant [[int]] 5 +; CHECK: OpAtomicLoad [[int]] [[var]] [[qf]] +; CHECK: OpAtomicStore [[var]] [[qf]] +; CHECK: OpAtomicExchange [[int]] [[var]] [[qf]] +; CHECK: OpAtomicCompareExchange [[int]] [[var]] [[qf]] +; CHECK: OpAtomicIIncrement [[int]] [[var]] [[qf]] +; CHECK: OpAtomicIDecrement [[int]] [[var]] [[qf]] +; CHECK: OpAtomicIAdd [[int]] [[var]] [[qf]] +; CHECK: OpAtomicISub [[int]] [[var]] [[qf]] +; CHECK: OpAtomicSMin [[int]] [[var]] [[qf]] +; CHECK: OpAtomicSMax [[int]] [[var]] [[qf]] +; CHECK: OpAtomicUMin [[int]] [[var]] [[qf]] +; CHECK: OpAtomicUMax [[int]] [[var]] [[qf]] +; CHECK: OpAtomicAnd [[int]] [[var]] [[qf]] +; CHECK: OpAtomicOr [[int]] [[var]] [[qf]] +; CHECK: OpAtomicXor [[int]] [[var]] [[qf]] +OpCapability Shader +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %func "func" +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%none = OpConstant %int 0 +%device = OpConstant %int 1 +%func_ty = OpTypeFunction %void +%ptr_int_StorageBuffer = OpTypePointer StorageBuffer %int +%var = OpVariable %ptr_int_StorageBuffer StorageBuffer +%func = OpFunction %void None %func_ty +%1 = OpLabel +%ld = OpAtomicLoad %int %var %device %none +OpAtomicStore %var %device %none %ld +%ex = OpAtomicExchange %int %var %device %none %ld +%cmp_ex = OpAtomicCompareExchange %int %var %device %none %none %ld %ld +%inc = OpAtomicIIncrement %int %var %device %none +%dec = OpAtomicIDecrement %int %var %device %none +%add = OpAtomicIAdd %int %var %device %none %ld +%sub = OpAtomicISub %int %var %device %none %ld +%smin = OpAtomicSMin %int %var %device %none %ld +%smax = OpAtomicSMax %int %var %device %none %ld +%umin = OpAtomicUMin %int %var %device %none %ld +%umax = OpAtomicUMax %int %var %device %none %ld +%and = OpAtomicAnd %int %var %device %none %ld +%or = OpAtomicOr %int %var %device %none %ld +%xor = OpAtomicXor %int %var %device %none %ld +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, UpgradeModfNoFlags) { + const std::string text = R"( +; CHECK: [[float:%\w+]] = OpTypeFloat 32 +; CHECK: [[float_0:%\w+]] = OpConstant [[float]] 0 +; CHECK: [[ptr:%\w+]] = OpTypePointer StorageBuffer [[float]] +; CHECK: [[var:%\w+]] = OpVariable [[ptr]] StorageBuffer +; CHECK: [[struct:%\w+]] = OpTypeStruct [[float]] [[float]] +; CHECK: [[modfstruct:%\w+]] = OpExtInst [[struct]] {{%\w+}} ModfStruct [[float_0]] +; CHECK: [[ex0:%\w+]] = OpCompositeExtract [[float]] [[modfstruct]] 0 +; CHECK: [[ex1:%\w+]] = OpCompositeExtract [[float]] [[modfstruct]] 1 +; CHECK: OpStore [[var]] [[ex1]] +; CHECK-NOT: NonPrivatePointer +; CHECK: OpFAdd [[float]] [[float_0]] [[ex0]] +OpCapability Shader +OpMemoryModel Logical GLSL450 +%import = OpExtInstImport "GLSL.std.450" +OpEntryPoint GLCompute %func "func" +%void = OpTypeVoid +%float = OpTypeFloat 32 +%float_0 = OpConstant %float 0 +%ptr_ssbo_float = OpTypePointer StorageBuffer %float +%ssbo_var = OpVariable %ptr_ssbo_float StorageBuffer +%func_ty = OpTypeFunction %void +%func = OpFunction %void None %func_ty +%1 = OpLabel +%2 = OpExtInst %float %import Modf %float_0 %ssbo_var +%3 = OpFAdd %float %float_0 %2 +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, UpgradeModfWorkgroupCoherent) { + const std::string text = R"( +; CHECK: [[float:%\w+]] = OpTypeFloat 32 +; CHECK: [[float_0:%\w+]] = OpConstant [[float]] 0 +; CHECK: [[ptr:%\w+]] = OpTypePointer Workgroup [[float]] +; CHECK: [[var:%\w+]] = OpVariable [[ptr]] Workgroup +; CHECK: [[struct:%\w+]] = OpTypeStruct [[float]] [[float]] +; CHECK: [[wg_scope:%\w+]] = OpConstant {{%\w+}} 2 +; CHECK: [[modfstruct:%\w+]] = OpExtInst [[struct]] {{%\w+}} ModfStruct [[float_0]] +; CHECK: [[ex0:%\w+]] = OpCompositeExtract [[float]] [[modfstruct]] 0 +; CHECK: [[ex1:%\w+]] = OpCompositeExtract [[float]] [[modfstruct]] 1 +; CHECK: OpStore [[var]] [[ex1]] MakePointerAvailable|NonPrivatePointer [[wg_scope]] +; CHECK: OpFAdd [[float]] [[float_0]] [[ex0]] +OpCapability Shader +OpMemoryModel Logical GLSL450 +%import = OpExtInstImport "GLSL.std.450" +OpEntryPoint GLCompute %func "func" +OpDecorate %wg_var Coherent +%void = OpTypeVoid +%float = OpTypeFloat 32 +%float_0 = OpConstant %float 0 +%ptr_wg_float = OpTypePointer Workgroup %float +%wg_var = OpVariable %ptr_wg_float Workgroup +%func_ty = OpTypeFunction %void +%func = OpFunction %void None %func_ty +%1 = OpLabel +%2 = OpExtInst %float %import Modf %float_0 %wg_var +%3 = OpFAdd %float %float_0 %2 +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, UpgradeModfSSBOCoherent) { + const std::string text = R"( +; CHECK: [[float:%\w+]] = OpTypeFloat 32 +; CHECK: [[float_0:%\w+]] = OpConstant [[float]] 0 +; CHECK: [[ptr:%\w+]] = OpTypePointer StorageBuffer [[float]] +; CHECK: [[var:%\w+]] = OpVariable [[ptr]] StorageBuffer +; CHECK: [[struct:%\w+]] = OpTypeStruct [[float]] [[float]] +; CHECK: [[qf_scope:%\w+]] = OpConstant {{%\w+}} 5 +; CHECK: [[modfstruct:%\w+]] = OpExtInst [[struct]] {{%\w+}} ModfStruct [[float_0]] +; CHECK: [[ex0:%\w+]] = OpCompositeExtract [[float]] [[modfstruct]] 0 +; CHECK: [[ex1:%\w+]] = OpCompositeExtract [[float]] [[modfstruct]] 1 +; CHECK: OpStore [[var]] [[ex1]] MakePointerAvailable|NonPrivatePointer [[qf_scope]] +; CHECK: OpFAdd [[float]] [[float_0]] [[ex0]] +OpCapability Shader +OpMemoryModel Logical GLSL450 +%import = OpExtInstImport "GLSL.std.450" +OpEntryPoint GLCompute %func "func" +OpDecorate %ssbo_var Coherent +%void = OpTypeVoid +%float = OpTypeFloat 32 +%float_0 = OpConstant %float 0 +%ptr_ssbo_float = OpTypePointer StorageBuffer %float +%ssbo_var = OpVariable %ptr_ssbo_float StorageBuffer +%func_ty = OpTypeFunction %void +%func = OpFunction %void None %func_ty +%1 = OpLabel +%2 = OpExtInst %float %import Modf %float_0 %ssbo_var +%3 = OpFAdd %float %float_0 %2 +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, UpgradeModfSSBOVolatile) { + const std::string text = R"( +; CHECK: [[float:%\w+]] = OpTypeFloat 32 +; CHECK: [[float_0:%\w+]] = OpConstant [[float]] 0 +; CHECK: [[ptr:%\w+]] = OpTypePointer StorageBuffer [[float]] +; CHECK: [[var:%\w+]] = OpVariable [[ptr]] StorageBuffer +; CHECK: [[struct:%\w+]] = OpTypeStruct [[float]] [[float]] +; CHECK: [[modfstruct:%\w+]] = OpExtInst [[struct]] {{%\w+}} ModfStruct [[float_0]] +; CHECK: [[ex0:%\w+]] = OpCompositeExtract [[float]] [[modfstruct]] 0 +; CHECK: [[ex1:%\w+]] = OpCompositeExtract [[float]] [[modfstruct]] 1 +; CHECK: OpStore [[var]] [[ex1]] Volatile +; CHECK: OpFAdd [[float]] [[float_0]] [[ex0]] +OpCapability Shader +OpMemoryModel Logical GLSL450 +%import = OpExtInstImport "GLSL.std.450" +OpEntryPoint GLCompute %func "func" +OpDecorate %wg_var Volatile +%void = OpTypeVoid +%float = OpTypeFloat 32 +%float_0 = OpConstant %float 0 +%ptr_ssbo_float = OpTypePointer StorageBuffer %float +%wg_var = OpVariable %ptr_ssbo_float StorageBuffer +%func_ty = OpTypeFunction %void +%func = OpFunction %void None %func_ty +%1 = OpLabel +%2 = OpExtInst %float %import Modf %float_0 %wg_var +%3 = OpFAdd %float %float_0 %2 +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, UpgradeFrexpNoFlags) { + const std::string text = R"( +; CHECK: [[float:%\w+]] = OpTypeFloat 32 +; CHECK: [[float_0:%\w+]] = OpConstant [[float]] 0 +; CHECK: [[int:%\w+]] = OpTypeInt 32 0 +; CHECK: [[ptr:%\w+]] = OpTypePointer StorageBuffer [[int]] +; CHECK: [[var:%\w+]] = OpVariable [[ptr]] StorageBuffer +; CHECK: [[struct:%\w+]] = OpTypeStruct [[float]] [[int]] +; CHECK: [[modfstruct:%\w+]] = OpExtInst [[struct]] {{%\w+}} FrexpStruct [[float_0]] +; CHECK: [[ex0:%\w+]] = OpCompositeExtract [[float]] [[modfstruct]] 0 +; CHECK: [[ex1:%\w+]] = OpCompositeExtract [[int]] [[modfstruct]] 1 +; CHECK: OpStore [[var]] [[ex1]] +; CHECK-NOT: NonPrivatePointer +; CHECK: OpFAdd [[float]] [[float_0]] [[ex0]] +OpCapability Shader +OpMemoryModel Logical GLSL450 +%import = OpExtInstImport "GLSL.std.450" +OpEntryPoint GLCompute %func "func" +%void = OpTypeVoid +%float = OpTypeFloat 32 +%float_0 = OpConstant %float 0 +%int = OpTypeInt 32 0 +%ptr_ssbo_int = OpTypePointer StorageBuffer %int +%ssbo_var = OpVariable %ptr_ssbo_int StorageBuffer +%func_ty = OpTypeFunction %void +%func = OpFunction %void None %func_ty +%1 = OpLabel +%2 = OpExtInst %float %import Frexp %float_0 %ssbo_var +%3 = OpFAdd %float %float_0 %2 +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, UpgradeFrexpWorkgroupCoherent) { + const std::string text = R"( +; CHECK: [[float:%\w+]] = OpTypeFloat 32 +; CHECK: [[float_0:%\w+]] = OpConstant [[float]] 0 +; CHECK: [[int:%\w+]] = OpTypeInt 32 0 +; CHECK: [[ptr:%\w+]] = OpTypePointer Workgroup [[int]] +; CHECK: [[var:%\w+]] = OpVariable [[ptr]] Workgroup +; CHECK: [[struct:%\w+]] = OpTypeStruct [[float]] [[int]] +; CHECK: [[wg_scope:%\w+]] = OpConstant {{%\w+}} 2 +; CHECK: [[modfstruct:%\w+]] = OpExtInst [[struct]] {{%\w+}} FrexpStruct [[float_0]] +; CHECK: [[ex0:%\w+]] = OpCompositeExtract [[float]] [[modfstruct]] 0 +; CHECK: [[ex1:%\w+]] = OpCompositeExtract [[int]] [[modfstruct]] 1 +; CHECK: OpStore [[var]] [[ex1]] MakePointerAvailable|NonPrivatePointer [[wg_scope]] +; CHECK: OpFAdd [[float]] [[float_0]] [[ex0]] +OpCapability Shader +OpMemoryModel Logical GLSL450 +%import = OpExtInstImport "GLSL.std.450" +OpEntryPoint GLCompute %func "func" +OpDecorate %wg_var Coherent +%void = OpTypeVoid +%float = OpTypeFloat 32 +%float_0 = OpConstant %float 0 +%int = OpTypeInt 32 0 +%ptr_wg_int = OpTypePointer Workgroup %int +%wg_var = OpVariable %ptr_wg_int Workgroup +%func_ty = OpTypeFunction %void +%func = OpFunction %void None %func_ty +%1 = OpLabel +%2 = OpExtInst %float %import Frexp %float_0 %wg_var +%3 = OpFAdd %float %float_0 %2 +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, UpgradeFrexpSSBOCoherent) { + const std::string text = R"( +; CHECK: [[float:%\w+]] = OpTypeFloat 32 +; CHECK: [[float_0:%\w+]] = OpConstant [[float]] 0 +; CHECK: [[int:%\w+]] = OpTypeInt 32 0 +; CHECK: [[ptr:%\w+]] = OpTypePointer StorageBuffer [[int]] +; CHECK: [[var:%\w+]] = OpVariable [[ptr]] StorageBuffer +; CHECK: [[struct:%\w+]] = OpTypeStruct [[float]] [[int]] +; CHECK: [[qf_scope:%\w+]] = OpConstant {{%\w+}} 5 +; CHECK: [[modfstruct:%\w+]] = OpExtInst [[struct]] {{%\w+}} FrexpStruct [[float_0]] +; CHECK: [[ex0:%\w+]] = OpCompositeExtract [[float]] [[modfstruct]] 0 +; CHECK: [[ex1:%\w+]] = OpCompositeExtract [[int]] [[modfstruct]] 1 +; CHECK: OpStore [[var]] [[ex1]] MakePointerAvailable|NonPrivatePointer [[qf_scope]] +; CHECK: OpFAdd [[float]] [[float_0]] [[ex0]] +OpCapability Shader +OpMemoryModel Logical GLSL450 +%import = OpExtInstImport "GLSL.std.450" +OpEntryPoint GLCompute %func "func" +OpDecorate %ssbo_var Coherent +%void = OpTypeVoid +%float = OpTypeFloat 32 +%float_0 = OpConstant %float 0 +%int = OpTypeInt 32 0 +%ptr_ssbo_int = OpTypePointer StorageBuffer %int +%ssbo_var = OpVariable %ptr_ssbo_int StorageBuffer +%func_ty = OpTypeFunction %void +%func = OpFunction %void None %func_ty +%1 = OpLabel +%2 = OpExtInst %float %import Frexp %float_0 %ssbo_var +%3 = OpFAdd %float %float_0 %2 +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, UpgradeFrexpSSBOVolatile) { + const std::string text = R"( +; CHECK: [[float:%\w+]] = OpTypeFloat 32 +; CHECK: [[float_0:%\w+]] = OpConstant [[float]] 0 +; CHECK: [[int:%\w+]] = OpTypeInt 32 0 +; CHECK: [[ptr:%\w+]] = OpTypePointer StorageBuffer [[int]] +; CHECK: [[var:%\w+]] = OpVariable [[ptr]] StorageBuffer +; CHECK: [[struct:%\w+]] = OpTypeStruct [[float]] [[int]] +; CHECK: [[modfstruct:%\w+]] = OpExtInst [[struct]] {{%\w+}} FrexpStruct [[float_0]] +; CHECK: [[ex0:%\w+]] = OpCompositeExtract [[float]] [[modfstruct]] 0 +; CHECK: [[ex1:%\w+]] = OpCompositeExtract [[int]] [[modfstruct]] 1 +; CHECK: OpStore [[var]] [[ex1]] Volatile +; CHECK: OpFAdd [[float]] [[float_0]] [[ex0]] +OpCapability Shader +OpMemoryModel Logical GLSL450 +%import = OpExtInstImport "GLSL.std.450" +OpEntryPoint GLCompute %func "func" +OpDecorate %wg_var Volatile +%void = OpTypeVoid +%float = OpTypeFloat 32 +%float_0 = OpConstant %float 0 +%int = OpTypeInt 32 0 +%ptr_ssbo_int = OpTypePointer StorageBuffer %int +%wg_var = OpVariable %ptr_ssbo_int StorageBuffer +%func_ty = OpTypeFunction %void +%func = OpFunction %void None %func_ty +%1 = OpLabel +%2 = OpExtInst %float %import Frexp %float_0 %wg_var +%3 = OpFAdd %float %float_0 %2 +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, SPV14NormalizeCopyMemoryAddOperands) { + const std::string text = R"( +; CHECK: OpCopyMemory {{%\w+}} {{%\w+}} None None +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %func "func" %src %dst +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%ptr_ssbo_int = OpTypePointer StorageBuffer %int +%src = OpVariable %ptr_ssbo_int StorageBuffer +%dst = OpVariable %ptr_ssbo_int StorageBuffer +%void_fn = OpTypeFunction %void +%func = OpFunction %void None %void_fn +%entry = OpLabel +OpCopyMemory %dst %src +OpReturn +OpFunctionEnd +)"; + + SetTargetEnv(SPV_ENV_UNIVERSAL_1_4); + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, SPV14NormalizeCopyMemoryDuplicateOperand) { + const std::string text = R"( +; CHECK: OpCopyMemory {{%\w+}} {{%\w+}} Nontemporal Nontemporal +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %func "func" %src %dst +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%ptr_ssbo_int = OpTypePointer StorageBuffer %int +%src = OpVariable %ptr_ssbo_int StorageBuffer +%dst = OpVariable %ptr_ssbo_int StorageBuffer +%void_fn = OpTypeFunction %void +%func = OpFunction %void None %void_fn +%entry = OpLabel +OpCopyMemory %dst %src Nontemporal +OpReturn +OpFunctionEnd +)"; + + SetTargetEnv(SPV_ENV_UNIVERSAL_1_4); + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, SPV14NormalizeCopyMemoryDuplicateOperands) { + const std::string text = R"( +; CHECK: OpCopyMemory {{%\w+}} {{%\w+}} Aligned 4 Aligned 4 +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %func "func" %src %dst +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%ptr_ssbo_int = OpTypePointer StorageBuffer %int +%src = OpVariable %ptr_ssbo_int StorageBuffer +%dst = OpVariable %ptr_ssbo_int StorageBuffer +%void_fn = OpTypeFunction %void +%func = OpFunction %void None %void_fn +%entry = OpLabel +OpCopyMemory %dst %src Aligned 4 +OpReturn +OpFunctionEnd +)"; + + SetTargetEnv(SPV_ENV_UNIVERSAL_1_4); + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, SPV14CopyMemoryDstCoherent) { + const std::string text = R"( +; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5 +; CHECK: OpCopyMemory {{%\w+}} {{%\w+}} MakePointerAvailable|NonPrivatePointer [[scope]] None +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %func "func" %src %dst +OpDecorate %dst Coherent +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%ptr_ssbo_int = OpTypePointer StorageBuffer %int +%src = OpVariable %ptr_ssbo_int StorageBuffer +%dst = OpVariable %ptr_ssbo_int StorageBuffer +%void_fn = OpTypeFunction %void +%func = OpFunction %void None %void_fn +%entry = OpLabel +OpCopyMemory %dst %src +OpReturn +OpFunctionEnd +)"; + + SetTargetEnv(SPV_ENV_UNIVERSAL_1_4); + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, SPV14CopyMemoryDstCoherentPreviousArgs) { + const std::string text = R"( +; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5 +; CHECK: OpCopyMemory {{%\w+}} {{%\w+}} Aligned|MakePointerAvailable|NonPrivatePointer 4 [[scope]] Aligned 4 +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %func "func" %src %dst +OpDecorate %dst Coherent +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%ptr_ssbo_int = OpTypePointer StorageBuffer %int +%src = OpVariable %ptr_ssbo_int StorageBuffer +%dst = OpVariable %ptr_ssbo_int StorageBuffer +%void_fn = OpTypeFunction %void +%func = OpFunction %void None %void_fn +%entry = OpLabel +OpCopyMemory %dst %src Aligned 4 +OpReturn +OpFunctionEnd +)"; + + SetTargetEnv(SPV_ENV_UNIVERSAL_1_4); + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, SPV14CopyMemorySrcCoherent) { + const std::string text = R"( +; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5 +; CHECK: OpCopyMemory {{%\w+}} {{%\w+}} None MakePointerVisible|NonPrivatePointer [[scope]] +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %func "func" %src %dst +OpDecorate %src Coherent +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%ptr_ssbo_int = OpTypePointer StorageBuffer %int +%src = OpVariable %ptr_ssbo_int StorageBuffer +%dst = OpVariable %ptr_ssbo_int StorageBuffer +%void_fn = OpTypeFunction %void +%func = OpFunction %void None %void_fn +%entry = OpLabel +OpCopyMemory %dst %src +OpReturn +OpFunctionEnd +)"; + + SetTargetEnv(SPV_ENV_UNIVERSAL_1_4); + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, SPV14CopyMemorySrcCoherentPreviousArgs) { + const std::string text = R"( +; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5 +; CHECK: OpCopyMemory {{%\w+}} {{%\w+}} Aligned 4 Aligned|MakePointerVisible|NonPrivatePointer 4 [[scope]] +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %func "func" %src %dst +OpDecorate %src Coherent +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%ptr_ssbo_int = OpTypePointer StorageBuffer %int +%src = OpVariable %ptr_ssbo_int StorageBuffer +%dst = OpVariable %ptr_ssbo_int StorageBuffer +%void_fn = OpTypeFunction %void +%func = OpFunction %void None %void_fn +%entry = OpLabel +OpCopyMemory %dst %src Aligned 4 +OpReturn +OpFunctionEnd +)"; + + SetTargetEnv(SPV_ENV_UNIVERSAL_1_4); + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, SPV14CopyMemoryBothCoherent) { + const std::string text = R"( +; CHECK-DAG: [[queue:%\w+]] = OpConstant {{%\w+}} 5 +; CHECK-DAG: [[wg:%\w+]] = OpConstant {{%\w+}} 2 +; CHECK: OpCopyMemory {{%\w+}} {{%\w+}} MakePointerAvailable|NonPrivatePointer [[wg]] MakePointerVisible|NonPrivatePointer [[queue]] +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %func "func" %src %dst +OpDecorate %src Coherent +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%ptr_ssbo_int = OpTypePointer StorageBuffer %int +%ptr_wg_int = OpTypePointer Workgroup %int +%src = OpVariable %ptr_ssbo_int StorageBuffer +%dst = OpVariable %ptr_wg_int Workgroup +%void_fn = OpTypeFunction %void +%func = OpFunction %void None %void_fn +%entry = OpLabel +OpCopyMemory %dst %src +OpReturn +OpFunctionEnd +)"; + + SetTargetEnv(SPV_ENV_UNIVERSAL_1_4); + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, SPV14CopyMemoryBothCoherentPreviousArgs) { + const std::string text = R"( +; CHECK-DAG: [[queue:%\w+]] = OpConstant {{%\w+}} 5 +; CHECK-DAG: [[wg:%\w+]] = OpConstant {{%\w+}} 2 +; CHECK: OpCopyMemory {{%\w+}} {{%\w+}} Aligned|MakePointerAvailable|NonPrivatePointer 4 [[queue]] Aligned|MakePointerVisible|NonPrivatePointer 4 [[wg]] +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %func "func" %src %dst +OpDecorate %dst Coherent +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%ptr_ssbo_int = OpTypePointer StorageBuffer %int +%ptr_wg_int = OpTypePointer Workgroup %int +%src = OpVariable %ptr_wg_int Workgroup +%dst = OpVariable %ptr_ssbo_int StorageBuffer +%void_fn = OpTypeFunction %void +%func = OpFunction %void None %void_fn +%entry = OpLabel +OpCopyMemory %dst %src Aligned 4 +OpReturn +OpFunctionEnd +)"; + + SetTargetEnv(SPV_ENV_UNIVERSAL_1_4); + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, SPV14CopyMemoryBothVolatile) { + const std::string text = R"( +; CHECK: OpCopyMemory {{%\w+}} {{%\w+}} Volatile Volatile +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %func "func" %src %dst +OpDecorate %src Volatile +OpDecorate %dst Volatile +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%ptr_ssbo_int = OpTypePointer StorageBuffer %int +%src = OpVariable %ptr_ssbo_int StorageBuffer +%dst = OpVariable %ptr_ssbo_int StorageBuffer +%void_fn = OpTypeFunction %void +%func = OpFunction %void None %void_fn +%entry = OpLabel +OpCopyMemory %dst %src +OpReturn +OpFunctionEnd +)"; + + SetTargetEnv(SPV_ENV_UNIVERSAL_1_4); + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, SPV14CopyMemoryBothVolatilePreviousArgs) { + const std::string text = R"( +; CHECK: OpCopyMemory {{%\w+}} {{%\w+}} Volatile|Aligned 4 Volatile|Aligned 4 +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %func "func" %src %dst +OpDecorate %src Volatile +OpDecorate %dst Volatile +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%ptr_ssbo_int = OpTypePointer StorageBuffer %int +%src = OpVariable %ptr_ssbo_int StorageBuffer +%dst = OpVariable %ptr_ssbo_int StorageBuffer +%void_fn = OpTypeFunction %void +%func = OpFunction %void None %void_fn +%entry = OpLabel +OpCopyMemory %dst %src Aligned 4 +OpReturn +OpFunctionEnd +)"; + + SetTargetEnv(SPV_ENV_UNIVERSAL_1_4); + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, SPV14CopyMemoryDstCoherentTwoOperands) { + const std::string text = R"( +; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5 +; CHECK: OpCopyMemory {{%\w+}} {{%\w+}} MakePointerAvailable|NonPrivatePointer [[scope]] None +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %func "func" %src %dst +OpDecorate %dst Coherent +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%ptr_ssbo_int = OpTypePointer StorageBuffer %int +%src = OpVariable %ptr_ssbo_int StorageBuffer +%dst = OpVariable %ptr_ssbo_int StorageBuffer +%void_fn = OpTypeFunction %void +%func = OpFunction %void None %void_fn +%entry = OpLabel +OpCopyMemory %dst %src None None +OpReturn +OpFunctionEnd +)"; + + SetTargetEnv(SPV_ENV_UNIVERSAL_1_4); + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, + SPV14CopyMemoryDstCoherentPreviousArgsTwoOperands) { + const std::string text = R"( +; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5 +; CHECK: OpCopyMemory {{%\w+}} {{%\w+}} Aligned|MakePointerAvailable|NonPrivatePointer 4 [[scope]] Aligned 8 +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %func "func" %src %dst +OpDecorate %dst Coherent +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%ptr_ssbo_int = OpTypePointer StorageBuffer %int +%src = OpVariable %ptr_ssbo_int StorageBuffer +%dst = OpVariable %ptr_ssbo_int StorageBuffer +%void_fn = OpTypeFunction %void +%func = OpFunction %void None %void_fn +%entry = OpLabel +OpCopyMemory %dst %src Aligned 4 Aligned 8 +OpReturn +OpFunctionEnd +)"; + + SetTargetEnv(SPV_ENV_UNIVERSAL_1_4); + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, VolatileAtomicLoad) { + const std::string text = R"( +; CHECK-NOT: OpDecorate {{.*}} Volatile +; CHECK: [[volatile:%[a-zA-Z0-9_]+]] = OpConstant [[int:%[a-zA-Z0-9_]+]] 32768 +; CHECK: OpAtomicLoad [[int]] {{.*}} {{.*}} [[volatile]] +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpDecorate %ssbo_var Volatile +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%device = OpConstant %int 1 +%relaxed = OpConstant %int 0 +%ptr_ssbo_int = OpTypePointer StorageBuffer %int +%ssbo_var = OpVariable %ptr_ssbo_int StorageBuffer +%void_fn = OpTypeFunction %void +%func = OpFunction %void None %void_fn +%entry = OpLabel +%ld = OpAtomicLoad %int %ssbo_var %device %relaxed +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, VolatileAtomicLoadPreviousFlags) { + const std::string text = R"( +; CHECK-NOT: OpDecorate {{.*}} Volatile +; CHECK: [[volatile:%[a-zA-Z0-9_]+]] = OpConstant [[int:%[a-zA-Z0-9_]+]] 32834 +; CHECK: OpAtomicLoad [[int]] {{.*}} {{.*}} [[volatile]] +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpDecorate %ssbo_var Volatile +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%device = OpConstant %int 1 +%acquire_ssbo = OpConstant %int 66 +%ptr_ssbo_int = OpTypePointer StorageBuffer %int +%ssbo_var = OpVariable %ptr_ssbo_int StorageBuffer +%void_fn = OpTypeFunction %void +%func = OpFunction %void None %void_fn +%entry = OpLabel +%ld = OpAtomicLoad %int %ssbo_var %device %acquire_ssbo +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, VolatileAtomicStore) { + const std::string text = R"( +; CHECK-NOT: OpDecorate {{.*}} Volatile +; CHECK: [[volatile:%[a-zA-Z0-9_]+]] = OpConstant {{.*}} 32768 +; CHECK: OpAtomicStore {{.*}} {{.*}} [[volatile]] +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpDecorate %ssbo_var Volatile +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%device = OpConstant %int 1 +%relaxed = OpConstant %int 0 +%ptr_ssbo_int = OpTypePointer StorageBuffer %int +%ssbo_var = OpVariable %ptr_ssbo_int StorageBuffer +%void_fn = OpTypeFunction %void +%func = OpFunction %void None %void_fn +%entry = OpLabel +OpAtomicStore %ssbo_var %device %relaxed %int_0 +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, VolatileAtomicStorePreviousFlags) { + const std::string text = R"( +; CHECK-NOT: OpDecorate {{.*}} Volatile +; CHECK: [[volatile:%[a-zA-Z0-9_]+]] = OpConstant {{.*}} 32836 +; CHECK: OpAtomicStore {{.*}} {{.*}} [[volatile]] +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpDecorate %ssbo_var Volatile +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%device = OpConstant %int 1 +%release_ssbo = OpConstant %int 68 +%ptr_ssbo_int = OpTypePointer StorageBuffer %int +%ssbo_var = OpVariable %ptr_ssbo_int StorageBuffer +%void_fn = OpTypeFunction %void +%func = OpFunction %void None %void_fn +%entry = OpLabel +OpAtomicStore %ssbo_var %device %release_ssbo %int_0 +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, VolatileAtomicCompareExchange) { + const std::string text = R"( +; CHECK-NOT: OpDecorate {{.*}} Volatile +; CHECK: [[volatile:%[a-zA-Z0-9_]+]] = OpConstant [[int:%[a-zA-Z0-9_]+]] 32768 +; CHECK: OpAtomicCompareExchange [[int]] {{.*}} {{.*}} [[volatile]] [[volatile]] +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpDecorate %ssbo_var Volatile +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%int_1 = OpConstant %int 1 +%device = OpConstant %int 1 +%relaxed = OpConstant %int 0 +%ptr_ssbo_int = OpTypePointer StorageBuffer %int +%ssbo_var = OpVariable %ptr_ssbo_int StorageBuffer +%void_fn = OpTypeFunction %void +%func = OpFunction %void None %void_fn +%entry = OpLabel +%ld = OpAtomicCompareExchange %int %ssbo_var %device %relaxed %relaxed %int_0 %int_1 +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, VolatileAtomicCompareExchangePreviousFlags) { + const std::string text = R"( +; CHECK-NOT: OpDecorate {{.*}} Volatile +; CHECK: [[volatile_acq_rel:%[a-zA-Z0-9_]+]] = OpConstant [[int:%[a-zA-Z0-9_]+]] 32840 +; CHECK: [[volatile_acq:%[a-zA-Z0-9_]+]] = OpConstant [[int:%[a-zA-Z0-9_]+]] 32834 +; CHECK: OpAtomicCompareExchange [[int]] {{.*}} {{.*}} [[volatile_acq_rel]] [[volatile_acq]] +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpDecorate %ssbo_var Volatile +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%int_1 = OpConstant %int 1 +%device = OpConstant %int 1 +%acq_ssbo = OpConstant %int 66 +%acq_rel_ssbo = OpConstant %int 72 +%ptr_ssbo_int = OpTypePointer StorageBuffer %int +%ssbo_var = OpVariable %ptr_ssbo_int StorageBuffer +%void_fn = OpTypeFunction %void +%func = OpFunction %void None %void_fn +%entry = OpLabel +%ld = OpAtomicCompareExchange %int %ssbo_var %device %acq_rel_ssbo %acq_ssbo %int_0 %int_1 +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, VolatileAtomicLoadMemberDecoration) { + const std::string text = R"( +; CHECK-NOT: OpMemberDecorate {{.*}} {{.*}} Volatile +; CHECK: [[relaxed:%[a-zA-Z0-9_]+]] = OpConstant {{.*}} 0 +; CHECK: [[volatile:%[a-zA-Z0-9_]+]] = OpConstant [[int:%[a-zA-Z0-9_]+]] 32768 +; CHECK: OpAtomicLoad [[int]] {{.*}} {{.*}} [[relaxed]] +; CHECK: OpAtomicLoad [[int]] {{.*}} {{.*}} [[volatile]] +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpMemberDecorate %struct 1 Volatile +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%device = OpConstant %int 1 +%relaxed = OpConstant %int 0 +%int_0 = OpConstant %int 0 +%int_1 = OpConstant %int 1 +%ptr_ssbo_int = OpTypePointer StorageBuffer %int +%struct = OpTypeStruct %int %int +%ptr_ssbo_struct = OpTypePointer StorageBuffer %struct +%ssbo_var = OpVariable %ptr_ssbo_struct StorageBuffer +%void_fn = OpTypeFunction %void +%func = OpFunction %void None %void_fn +%entry = OpLabel +%gep0 = OpAccessChain %ptr_ssbo_int %ssbo_var %int_0 +%ld0 = OpAtomicLoad %int %gep0 %device %relaxed +%gep1 = OpAccessChain %ptr_ssbo_int %ssbo_var %int_1 +%ld1 = OpAtomicLoad %int %gep1 %device %relaxed +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, CoherentStructMemberInArray) { + const std::string text = R"( +; CHECK-NOT: OpMemberDecorate +; CHECK: [[int:%[a-zA-Z0-9_]+]] = OpTypeInt 32 0 +; CHECK: [[device:%[a-zA-Z0-9_]+]] = OpConstant [[int]] 1 +; CHECK: OpLoad [[int]] {{.*}} MakePointerVisible|NonPrivatePointer +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpMemberDecorate %inner 1 Coherent +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%int_1 = OpConstant %int 1 +%int_4 = OpConstant %int 4 +%inner = OpTypeStruct %int %int +%array = OpTypeArray %inner %int_4 +%struct = OpTypeStruct %array +%ptr_ssbo_struct = OpTypePointer StorageBuffer %struct +%ptr_ssbo_int = OpTypePointer StorageBuffer %int +%ssbo_var = OpVariable %ptr_ssbo_struct StorageBuffer +%void_fn = OpTypeFunction %void +%func = OpFunction %void None %void_fn +%entry = OpLabel +%gep = OpAccessChain %ptr_ssbo_int %ssbo_var %int_0 %int_0 %int_1 +%ld = OpLoad %int %gep +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +} // namespace diff --git a/third_party/spirv-tools/test/opt/utils_test.cpp b/third_party/spirv-tools/test/opt/utils_test.cpp index 9bb82a367d..5ce146bbb2 100644 --- a/third_party/spirv-tools/test/opt/utils_test.cpp +++ b/third_party/spirv-tools/test/opt/utils_test.cpp @@ -72,7 +72,7 @@ TEST_P(FindAndReplaceTest, SubstringReplacement) { << " expected string: " << GetParam().expected_str; } -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SubstringReplacement, FindAndReplaceTest, ::testing::ValuesIn(std::vector({ // orig string, find substring, replace substring, expected string, diff --git a/third_party/spirv-tools/test/opt/value_table_test.cpp b/third_party/spirv-tools/test/opt/value_table_test.cpp index ef338ae7ec..a0942ccdc0 100644 --- a/third_party/spirv-tools/test/opt/value_table_test.cpp +++ b/third_party/spirv-tools/test/opt/value_table_test.cpp @@ -455,6 +455,34 @@ TEST_F(ValueTableTest, CopyObject) { EXPECT_EQ(vtable.GetValueNumber(inst1), vtable.GetValueNumber(inst2)); } +TEST_F(ValueTableTest, CopyObjectWitDecoration) { + const std::string text = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpSource GLSL 430 + OpDecorate %3 NonUniformEXT + %4 = OpTypeVoid + %5 = OpTypeFunction %4 + %6 = OpTypeFloat 32 + %7 = OpTypePointer Function %6 + %2 = OpFunction %4 None %5 + %8 = OpLabel + %9 = OpVariable %7 Function + %10 = OpLoad %6 %9 + %3 = OpCopyObject %6 %10 + OpReturn + OpFunctionEnd + )"; + auto context = BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text); + ValueNumberTable vtable(context.get()); + Instruction* inst1 = context->get_def_use_mgr()->GetDef(10); + Instruction* inst2 = context->get_def_use_mgr()->GetDef(3); + EXPECT_NE(vtable.GetValueNumber(inst1), vtable.GetValueNumber(inst2)); +} + // Test that a phi where the operands have the same value assigned that value // to the result of the phi. TEST_F(ValueTableTest, PhiTest1) { @@ -495,6 +523,45 @@ TEST_F(ValueTableTest, PhiTest1) { EXPECT_EQ(vtable.GetValueNumber(inst1), vtable.GetValueNumber(phi)); } +TEST_F(ValueTableTest, PhiTest1WithDecoration) { + const std::string text = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpSource GLSL 430 + OpDecorate %3 NonUniformEXT + %4 = OpTypeVoid + %5 = OpTypeFunction %5 + %6 = OpTypeFloat 32 + %7 = OpTypePointer Uniform %6 + %8 = OpTypeBool + %9 = OpConstantTrue %8 + %10 = OpVariable %7 Uniform + %2 = OpFunction %4 None %5 + %11 = OpLabel + OpBranchConditional %9 %12 %13 + %12 = OpLabel + %14 = OpLoad %6 %10 + OpBranch %15 + %13 = OpLabel + %16 = OpLoad %6 %10 + OpBranch %15 + %15 = OpLabel + %3 = OpPhi %6 %14 %12 %16 %13 + OpReturn + OpFunctionEnd + )"; + auto context = BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text); + ValueNumberTable vtable(context.get()); + Instruction* inst1 = context->get_def_use_mgr()->GetDef(14); + Instruction* inst2 = context->get_def_use_mgr()->GetDef(16); + Instruction* phi = context->get_def_use_mgr()->GetDef(3); + EXPECT_EQ(vtable.GetValueNumber(inst1), vtable.GetValueNumber(inst2)); + EXPECT_NE(vtable.GetValueNumber(inst1), vtable.GetValueNumber(phi)); +} + // When the values for the inputs to a phi do not match, then the phi should // have its own value number. TEST_F(ValueTableTest, PhiTest2) { @@ -586,6 +653,37 @@ TEST_F(ValueTableTest, PhiLoopTest) { EXPECT_NE(vtable.GetValueNumber(phi1), vtable.GetValueNumber(phi2)); } +// Test to make sure that OpPhi instructions with no in operands are handled +// correctly. +TEST_F(ValueTableTest, EmptyPhiTest) { + const std::string text = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpSource GLSL 430 + %void = OpTypeVoid + %4 = OpTypeFunction %void + %bool = OpTypeBool + %true = OpConstantTrue %bool + %2 = OpFunction %void None %4 + %7 = OpLabel + OpSelectionMerge %8 None + OpBranchConditional %true %9 %8 + %9 = OpLabel + OpKill + %8 = OpLabel + %10 = OpPhi %bool + OpReturn + OpFunctionEnd + )"; + auto context = BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text); + ValueNumberTable vtable(context.get()); + Instruction* inst = context->get_def_use_mgr()->GetDef(10); + vtable.GetValueNumber(inst); +} + } // namespace } // namespace opt } // namespace spvtools diff --git a/third_party/spirv-tools/test/opt/vector_dce_test.cpp b/third_party/spirv-tools/test/opt/vector_dce_test.cpp index d1af0de19c..594995c16d 100644 --- a/third_party/spirv-tools/test/opt/vector_dce_test.cpp +++ b/third_party/spirv-tools/test/opt/vector_dce_test.cpp @@ -490,6 +490,7 @@ OpDecorate %OutColor Location 0 %_ptr_Output_v4float = OpTypePointer Output %v4float %OutColor = OpVariable %_ptr_Output_v4float Output %27 = OpUndef %v4float +%55 = OpUndef %v4float )"; const std::string before = @@ -536,25 +537,31 @@ OpFunctionEnd R"(%main = OpFunction %void None %10 %28 = OpLabel %29 = OpLoad %v4float %In0 +%30 = OpLoad %float %In1 +%31 = OpLoad %float %In2 +%32 = OpFAdd %float %30 %31 +%33 = OpCompositeInsert %v4float %32 %29 1 %34 = OpAccessChain %_ptr_Uniform_uint %_ %int_0 %35 = OpLoad %uint %34 %36 = OpINotEqual %bool %35 %uint_0 OpSelectionMerge %37 None OpBranchConditional %36 %38 %37 %38 = OpLabel -%39 = OpCompositeInsert %v4float %float_1 %29 0 +%39 = OpCompositeInsert %v4float %float_1 %55 0 OpBranch %37 %37 = OpLabel %40 = OpPhi %v4float %29 %28 %39 %38 %41 = OpCompositeExtract %float %40 0 -%42 = OpCompositeInsert %v4float %41 %27 0 +%42 = OpCompositeInsert %v4float %41 %55 0 +%43 = OpCompositeExtract %float %40 1 +%44 = OpCompositeInsert %v4float %43 %42 1 %45 = OpAccessChain %_ptr_Uniform_uint %_ %int_1 %46 = OpLoad %uint %45 %47 = OpINotEqual %bool %46 %uint_0 OpSelectionMerge %48 None OpBranchConditional %47 %49 %48 %49 = OpLabel -%50 = OpCompositeInsert %v4float %float_0 %42 0 +%50 = OpCompositeInsert %v4float %float_0 %55 0 OpBranch %48 %48 = OpLabel %51 = OpPhi %v4float %42 %37 %50 %49 @@ -566,8 +573,8 @@ OpReturn OpFunctionEnd )"; - SinglePassRunAndCheck(before_predefs + before, - after_predefs + after, true, true); + SinglePassRunAndCheck(before_predefs + before, + after_predefs + after, true, true); } TEST_F(VectorDCETest, InsertObjectLive) { @@ -608,10 +615,9 @@ OpFunctionEnd )"; SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndCheck(before, before, true, true); + SinglePassRunAndCheck(before, before, true, true); } -#ifdef SPIRV_EFFCEE TEST_F(VectorDCETest, DeadInsertInCycle) { // Dead insert in chain with cycle. Demonstrates analysis can handle // cycles in chains going through scalars intermediate values. @@ -1078,13 +1084,12 @@ TEST_F(VectorDCETest, DeadInsertThroughOtherInst) { SinglePassRunAndMatch(assembly, true); } -#endif TEST_F(VectorDCETest, VectorIntoCompositeConstruct) { const std::string text = R"(OpCapability Linkage OpCapability Shader OpMemoryModel Logical GLSL450 -OpEntryPoint Vertex %1 "EntryPoint_Main" %2 %3 +OpEntryPoint Fragment %1 "EntryPoint_Main" %2 %3 OpExecutionMode %1 OriginUpperLeft OpDecorate %2 Location 0 OpDecorate %_struct_4 Block @@ -1150,7 +1155,7 @@ OpReturn OpFunctionEnd )"; - SinglePassRunAndCheck(text, text, true, true); + SinglePassRunAndCheck(text, text, true, true); } } // namespace diff --git a/third_party/spirv-tools/test/opt/workaround1209_test.cpp b/third_party/spirv-tools/test/opt/workaround1209_test.cpp index 853a01cb22..50d3c09151 100644 --- a/third_party/spirv-tools/test/opt/workaround1209_test.cpp +++ b/third_party/spirv-tools/test/opt/workaround1209_test.cpp @@ -30,7 +30,6 @@ namespace { using Workaround1209Test = PassTest<::testing::Test>; -#ifdef SPIRV_EFFCEE TEST_F(Workaround1209Test, RemoveOpUnreachableInLoop) { const std::string text = R"( OpCapability Shader @@ -418,7 +417,6 @@ TEST_F(Workaround1209Test, LeaveUnreachableNotInLoop) { SinglePassRunAndMatch(text, false); } -#endif } // namespace } // namespace opt diff --git a/third_party/spirv-tools/test/opt/wrap_opkill_test.cpp b/third_party/spirv-tools/test/opt/wrap_opkill_test.cpp new file mode 100644 index 0000000000..d50af28a18 --- /dev/null +++ b/third_party/spirv-tools/test/opt/wrap_opkill_test.cpp @@ -0,0 +1,518 @@ +// Copyright (c) 2019 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 "gmock/gmock.h" +#include "test/opt/assembly_builder.h" +#include "test/opt/pass_fixture.h" +#include "test/opt/pass_utils.h" + +namespace spvtools { +namespace opt { +namespace { + +using WrapOpKillTest = PassTest<::testing::Test>; + +TEST_F(WrapOpKillTest, SingleOpKill) { + const std::string text = R"( +; CHECK: OpEntryPoint Fragment [[main:%\w+]] +; CHECK: [[main]] = OpFunction +; CHECK: OpFunctionCall %void [[orig_kill:%\w+]] +; CHECK: [[orig_kill]] = OpFunction +; CHECK-NEXT: OpLabel +; CHECK-NEXT: OpFunctionCall %void [[new_kill:%\w+]] +; CHECK-NEXT: OpReturn +; CHECK: [[new_kill]] = OpFunction +; CHECK-NEXT: OpLabel +; CHECK-NEXT: OpKill +; CHECK-NEXT: OpFunctionEnd + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" + OpExecutionMode %main OriginUpperLeft + OpSource GLSL 330 + OpName %main "main" + %void = OpTypeVoid + %5 = OpTypeFunction %void + %bool = OpTypeBool + %true = OpConstantTrue %bool + %main = OpFunction %void None %5 + %8 = OpLabel + OpBranch %9 + %9 = OpLabel + OpLoopMerge %10 %11 None + OpBranch %12 + %12 = OpLabel + OpBranchConditional %true %13 %10 + %13 = OpLabel + OpBranch %11 + %11 = OpLabel + %14 = OpFunctionCall %void %kill_ + OpBranch %9 + %10 = OpLabel + OpReturn + OpFunctionEnd + %kill_ = OpFunction %void None %5 + %15 = OpLabel + OpKill + OpFunctionEnd + )"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(WrapOpKillTest, MultipleOpKillInSameFunc) { + const std::string text = R"( +; CHECK: OpEntryPoint Fragment [[main:%\w+]] +; CHECK: [[main]] = OpFunction +; CHECK: OpFunctionCall %void [[orig_kill:%\w+]] +; CHECK: [[orig_kill]] = OpFunction +; CHECK-NEXT: OpLabel +; CHECK-NEXT: OpSelectionMerge +; CHECK-NEXT: OpBranchConditional +; CHECK-NEXT: OpLabel +; CHECK-NEXT: OpFunctionCall %void [[new_kill:%\w+]] +; CHECK-NEXT: OpReturn +; CHECK-NEXT: OpLabel +; CHECK-NEXT: OpFunctionCall %void [[new_kill]] +; CHECK-NEXT: OpReturn +; CHECK: [[new_kill]] = OpFunction +; CHECK-NEXT: OpLabel +; CHECK-NEXT: OpKill +; CHECK-NEXT: OpFunctionEnd + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" + OpExecutionMode %main OriginUpperLeft + OpSource GLSL 330 + OpName %main "main" + %void = OpTypeVoid + %5 = OpTypeFunction %void + %bool = OpTypeBool + %true = OpConstantTrue %bool + %main = OpFunction %void None %5 + %8 = OpLabel + OpBranch %9 + %9 = OpLabel + OpLoopMerge %10 %11 None + OpBranch %12 + %12 = OpLabel + OpBranchConditional %true %13 %10 + %13 = OpLabel + OpBranch %11 + %11 = OpLabel + %14 = OpFunctionCall %void %kill_ + OpBranch %9 + %10 = OpLabel + OpReturn + OpFunctionEnd + %kill_ = OpFunction %void None %5 + %15 = OpLabel + OpSelectionMerge %16 None + OpBranchConditional %true %17 %18 + %17 = OpLabel + OpKill + %18 = OpLabel + OpKill + %16 = OpLabel + OpReturn + OpFunctionEnd + )"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(WrapOpKillTest, MultipleOpKillInDifferentFunc) { + const std::string text = R"( +; CHECK: OpEntryPoint Fragment [[main:%\w+]] +; CHECK: [[main]] = OpFunction +; CHECK: OpFunctionCall %void [[orig_kill1:%\w+]] +; CHECK-NEXT: OpFunctionCall %void [[orig_kill2:%\w+]] +; CHECK: [[orig_kill1]] = OpFunction +; CHECK-NEXT: OpLabel +; CHECK-NEXT: OpFunctionCall %void [[new_kill:%\w+]] +; CHECK-NEXT: OpReturn +; CHECK: [[orig_kill2]] = OpFunction +; CHECK-NEXT: OpLabel +; CHECK-NEXT: OpFunctionCall %void [[new_kill]] +; CHECK-NEXT: OpReturn +; CHECK: [[new_kill]] = OpFunction +; CHECK-NEXT: OpLabel +; CHECK-NEXT: OpKill +; CHECK-NEXT: OpFunctionEnd + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" + OpExecutionMode %main OriginUpperLeft + OpSource GLSL 330 + OpName %main "main" + %void = OpTypeVoid + %4 = OpTypeFunction %void + %bool = OpTypeBool + %true = OpConstantTrue %bool + %main = OpFunction %void None %4 + %7 = OpLabel + OpBranch %8 + %8 = OpLabel + OpLoopMerge %9 %10 None + OpBranch %11 + %11 = OpLabel + OpBranchConditional %true %12 %9 + %12 = OpLabel + OpBranch %10 + %10 = OpLabel + %13 = OpFunctionCall %void %14 + %15 = OpFunctionCall %void %16 + OpBranch %8 + %9 = OpLabel + OpReturn + OpFunctionEnd + %14 = OpFunction %void None %4 + %17 = OpLabel + OpKill + OpFunctionEnd + %16 = OpFunction %void None %4 + %18 = OpLabel + OpKill + OpFunctionEnd + )"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(WrapOpKillTest, FuncWithReturnValue) { + const std::string text = R"( +; CHECK: OpEntryPoint Fragment [[main:%\w+]] +; CHECK: [[main]] = OpFunction +; CHECK: OpFunctionCall %int [[orig_kill:%\w+]] +; CHECK: [[orig_kill]] = OpFunction +; CHECK-NEXT: OpLabel +; CHECK-NEXT: OpFunctionCall %void [[new_kill:%\w+]] +; CHECK-NEXT: [[undef:%\w+]] = OpUndef %int +; CHECK-NEXT: OpReturnValue [[undef]] +; CHECK: [[new_kill]] = OpFunction +; CHECK-NEXT: OpLabel +; CHECK-NEXT: OpKill +; CHECK-NEXT: OpFunctionEnd + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" + OpExecutionMode %main OriginUpperLeft + OpSource GLSL 330 + OpName %main "main" + %void = OpTypeVoid + %5 = OpTypeFunction %void + %int = OpTypeInt 32 1 + %func_type = OpTypeFunction %int + %bool = OpTypeBool + %true = OpConstantTrue %bool + %main = OpFunction %void None %5 + %8 = OpLabel + OpBranch %9 + %9 = OpLabel + OpLoopMerge %10 %11 None + OpBranch %12 + %12 = OpLabel + OpBranchConditional %true %13 %10 + %13 = OpLabel + OpBranch %11 + %11 = OpLabel + %14 = OpFunctionCall %int %kill_ + OpBranch %9 + %10 = OpLabel + OpReturn + OpFunctionEnd + %kill_ = OpFunction %int None %func_type + %15 = OpLabel + OpKill + OpFunctionEnd + )"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(WrapOpKillTest, IdBoundOverflow1) { + const std::string text = R"( +OpCapability GeometryStreams +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +%2 = OpTypeVoid +%3 = OpTypeFunction %2 +%bool = OpTypeBool +%true = OpConstantTrue %bool +%main = OpFunction %2 None %3 +%8 = OpLabel +OpBranch %9 +%9 = OpLabel +OpLoopMerge %10 %11 None +OpBranch %12 +%12 = OpLabel +OpBranchConditional %true %13 %10 +%13 = OpLabel +OpBranch %11 +%11 = OpLabel +%14 = OpFunctionCall %void %kill_ +OpBranch %9 +%10 = OpLabel +OpReturn +OpFunctionEnd +%kill_ = OpFunction %2 Pure|Const %3 +%4194302 = OpLabel +OpKill +OpFunctionEnd +)"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + + std::vector messages = { + {SPV_MSG_ERROR, "", 0, 0, "ID overflow. Try running compact-ids."}}; + SetMessageConsumer(GetTestMessageConsumer(messages)); + auto result = SinglePassRunToBinary(text, true); + EXPECT_EQ(Pass::Status::Failure, std::get<1>(result)); +} + +TEST_F(WrapOpKillTest, IdBoundOverflow2) { + const std::string text = R"( +OpCapability GeometryStreams +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +%2 = OpTypeVoid +%3 = OpTypeFunction %2 +%bool = OpTypeBool +%true = OpConstantTrue %bool +%main = OpFunction %2 None %3 +%8 = OpLabel +OpBranch %9 +%9 = OpLabel +OpLoopMerge %10 %11 None +OpBranch %12 +%12 = OpLabel +OpBranchConditional %true %13 %10 +%13 = OpLabel +OpBranch %11 +%11 = OpLabel +%14 = OpFunctionCall %void %kill_ +OpBranch %9 +%10 = OpLabel +OpReturn +OpFunctionEnd +%kill_ = OpFunction %2 Pure|Const %3 +%4194301 = OpLabel +OpKill +OpFunctionEnd +)"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + + std::vector messages = { + {SPV_MSG_ERROR, "", 0, 0, "ID overflow. Try running compact-ids."}}; + SetMessageConsumer(GetTestMessageConsumer(messages)); + auto result = SinglePassRunToBinary(text, true); + EXPECT_EQ(Pass::Status::Failure, std::get<1>(result)); +} + +TEST_F(WrapOpKillTest, IdBoundOverflow3) { + const std::string text = R"( +OpCapability GeometryStreams +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +%2 = OpTypeVoid +%3 = OpTypeFunction %2 +%bool = OpTypeBool +%true = OpConstantTrue %bool +%main = OpFunction %2 None %3 +%8 = OpLabel +OpBranch %9 +%9 = OpLabel +OpLoopMerge %10 %11 None +OpBranch %12 +%12 = OpLabel +OpBranchConditional %true %13 %10 +%13 = OpLabel +OpBranch %11 +%11 = OpLabel +%14 = OpFunctionCall %void %kill_ +OpBranch %9 +%10 = OpLabel +OpReturn +OpFunctionEnd +%kill_ = OpFunction %2 Pure|Const %3 +%4194300 = OpLabel +OpKill +OpFunctionEnd +)"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + + std::vector messages = { + {SPV_MSG_ERROR, "", 0, 0, "ID overflow. Try running compact-ids."}}; + SetMessageConsumer(GetTestMessageConsumer(messages)); + auto result = SinglePassRunToBinary(text, true); + EXPECT_EQ(Pass::Status::Failure, std::get<1>(result)); +} + +TEST_F(WrapOpKillTest, IdBoundOverflow4) { + const std::string text = R"( +OpCapability DerivativeControl +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpDecorate %2 Location 539091968 +%2 = OpTypeVoid +%3 = OpTypeFunction %2 +%bool = OpTypeBool +%true = OpConstantTrue %bool +%main = OpFunction %2 None %3 +%8 = OpLabel +OpBranch %9 +%9 = OpLabel +OpLoopMerge %10 %11 None +OpBranch %12 +%12 = OpLabel +OpBranchConditional %true %13 %10 +%13 = OpLabel +OpBranch %11 +%11 = OpLabel +%14 = OpFunctionCall %void %kill_ +OpBranch %9 +%10 = OpLabel +OpReturn +OpFunctionEnd +%kill_ = OpFunction %2 Inline|Pure|Const %3 +%4194302 = OpLabel +OpKill +OpFunctionEnd +)"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + + std::vector messages = { + {SPV_MSG_ERROR, "", 0, 0, "ID overflow. Try running compact-ids."}}; + SetMessageConsumer(GetTestMessageConsumer(messages)); + auto result = SinglePassRunToBinary(text, true); + EXPECT_EQ(Pass::Status::Failure, std::get<1>(result)); +} + +TEST_F(WrapOpKillTest, IdBoundOverflow5) { + const std::string text = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "main" + OpExecutionMode %1 OriginUpperLeft + OpDecorate %void Location 539091968 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %_struct_5 = OpTypeStruct %float %float + %_struct_6 = OpTypeStruct %_struct_5 +%_ptr_Function__struct_6 = OpTypePointer Function %_struct_6 +%_ptr_Output_float = OpTypePointer Output %float + %9 = OpTypeFunction %_struct_5 %_ptr_Function__struct_6 + %bool = OpTypeBool + %true = OpConstantTrue %bool + %1 = OpFunction %void None %3 + %12 = OpLabel + %13 = OpVariable %_ptr_Function__struct_6 Function + OpBranch %14 + %14 = OpLabel + OpLoopMerge %15 %16 None + OpBranch %17 + %17 = OpLabel + OpBranchConditional %true %18 %15 + %18 = OpLabel + OpBranch %16 + %16 = OpLabel + %19 = OpFunctionCall %void %20 + %21 = OpFunctionCall %_struct_5 %22 %13 + OpBranch %14 + %15 = OpLabel + OpReturn + OpFunctionEnd + %20 = OpFunction %void Inline|Pure|Const %3 + %23 = OpLabel + %24 = OpVariable %_ptr_Function__struct_6 Function + %25 = OpFunctionCall %_struct_5 %26 %24 + OpKill + OpFunctionEnd + %26 = OpFunction %_struct_5 None %9 + %27 = OpLabel + OpUnreachable + OpFunctionEnd + %22 = OpFunction %_struct_5 Inline %9 + %4194295 = OpLabel + OpKill + OpFunctionEnd +)"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + + std::vector messages = { + {SPV_MSG_ERROR, "", 0, 0, "ID overflow. Try running compact-ids."}}; + SetMessageConsumer(GetTestMessageConsumer(messages)); + auto result = SinglePassRunToBinary(text, true); + EXPECT_EQ(Pass::Status::Failure, std::get<1>(result)); +} + +TEST_F(WrapOpKillTest, SkipEntryPoint) { + const std::string text = R"( +OpCapability GeometryStreams +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %4 "main" +OpExecutionMode %4 OriginUpperLeft +%2 = OpTypeVoid +%3 = OpTypeFunction %2 +%4 = OpFunction %2 Pure|Const %3 +%5 = OpLabel +OpKill +OpFunctionEnd +)"; + + auto result = SinglePassRunToBinary(text, true); + EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)); +} + +TEST_F(WrapOpKillTest, SkipFunctionNotInContinue) { + const std::string text = R"( +OpCapability GeometryStreams +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +%2 = OpTypeVoid +%3 = OpTypeFunction %2 +%bool = OpTypeBool +%true = OpConstantTrue %bool +%main = OpFunction %2 None %3 +%6 = OpLabel +%7 = OpFunctionCall %void %4 +OpReturn +OpFunctionEnd +%4 = OpFunction %2 Pure|Const %3 +%5 = OpLabel +OpKill +OpFunctionEnd +)"; + + auto result = SinglePassRunToBinary(text, true); + EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)); +} + +} // namespace +} // namespace opt +} // namespace spvtools diff --git a/third_party/spirv-tools/test/pch_test.cpp b/third_party/spirv-tools/test/pch_test.cpp new file mode 100644 index 0000000000..3b06a0aa28 --- /dev/null +++ b/third_party/spirv-tools/test/pch_test.cpp @@ -0,0 +1,15 @@ +// Copyright (c) 2018 The Khronos Group Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "pch_test.h" diff --git a/third_party/spirv-tools/test/pch_test.h b/third_party/spirv-tools/test/pch_test.h new file mode 100644 index 0000000000..7dac06acf2 --- /dev/null +++ b/third_party/spirv-tools/test/pch_test.h @@ -0,0 +1,18 @@ +// Copyright (c) 2018 The Khronos Group Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "gmock/gmock.h" +#include "source/spirv_constant.h" +#include "test/test_fixture.h" +#include "test/unit_spirv.h" diff --git a/third_party/spirv-tools/test/reduce/CMakeLists.txt b/third_party/spirv-tools/test/reduce/CMakeLists.txt new file mode 100644 index 0000000000..b19bba4537 --- /dev/null +++ b/third_party/spirv-tools/test/reduce/CMakeLists.txt @@ -0,0 +1,34 @@ +# Copyright (c) 2018 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. + +add_spvtools_unittest(TARGET reduce + SRCS + merge_blocks_test.cpp + operand_to_constant_test.cpp + operand_to_undef_test.cpp + operand_to_dominating_id_test.cpp + reduce_test_util.cpp + reduce_test_util.h + reducer_test.cpp + remove_block_test.cpp + remove_function_test.cpp + remove_selection_test.cpp + remove_unreferenced_instruction_test.cpp + structured_loop_to_selection_test.cpp + validation_during_reduction_test.cpp + conditional_branch_to_simple_conditional_branch_test.cpp + simple_conditional_branch_to_branch_test.cpp + LIBS SPIRV-Tools-reduce + ) + diff --git a/third_party/spirv-tools/test/reduce/conditional_branch_to_simple_conditional_branch_test.cpp b/third_party/spirv-tools/test/reduce/conditional_branch_to_simple_conditional_branch_test.cpp new file mode 100644 index 0000000000..69ef1f48b0 --- /dev/null +++ b/third_party/spirv-tools/test/reduce/conditional_branch_to_simple_conditional_branch_test.cpp @@ -0,0 +1,501 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/reduce/conditional_branch_to_simple_conditional_branch_opportunity_finder.h" + +#include "source/opt/build_module.h" +#include "source/reduce/reduction_opportunity.h" +#include "source/reduce/reduction_pass.h" +#include "test/reduce/reduce_test_util.h" + +namespace spvtools { +namespace reduce { +namespace { + +const spv_target_env kEnv = SPV_ENV_UNIVERSAL_1_3; + +TEST(ConditionalBranchToSimpleConditionalBranchTest, Diamond) { + // A test with the following structure. + // + // selection header + // OpBranchConditional + // | | + // b b + // | | + // selection merge + // + // There should be two opportunities for redirecting the OpBranchConditional + // targets: redirecting the true to false, and vice-versa. E.g. false to true: + // + // selection header + // OpBranchConditional + // || + // b b + // | | + // selection merge + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpSource ESSL 310 + OpName %2 "main" + %3 = OpTypeVoid + %4 = OpTypeFunction %3 + %5 = OpTypeInt 32 1 + %6 = OpTypePointer Function %5 + %7 = OpTypeBool + %8 = OpConstantTrue %7 + %2 = OpFunction %3 None %4 + %9 = OpLabel + OpBranch %10 + %10 = OpLabel + OpSelectionMerge %11 None + OpBranchConditional %8 %12 %13 + %12 = OpLabel + OpBranch %11 + %13 = OpLabel + OpBranch %11 + %11 = OpLabel + OpReturn + OpFunctionEnd + + )"; + + auto context = BuildModule(kEnv, nullptr, shader, kReduceAssembleOption); + + CheckValid(kEnv, context.get()); + + auto ops = ConditionalBranchToSimpleConditionalBranchOpportunityFinder() + .GetAvailableOpportunities(context.get()); + + ASSERT_EQ(2, ops.size()); + + ASSERT_TRUE(ops[0]->PreconditionHolds()); + ASSERT_TRUE(ops[1]->PreconditionHolds()); + ops[0]->TryToApply(); + // The other opportunity should now be disabled. + ASSERT_FALSE(ops[1]->PreconditionHolds()); + + CheckValid(kEnv, context.get()); + + { + std::string after = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpSource ESSL 310 + OpName %2 "main" + %3 = OpTypeVoid + %4 = OpTypeFunction %3 + %5 = OpTypeInt 32 1 + %6 = OpTypePointer Function %5 + %7 = OpTypeBool + %8 = OpConstantTrue %7 + %2 = OpFunction %3 None %4 + %9 = OpLabel + OpBranch %10 + %10 = OpLabel + OpSelectionMerge %11 None + OpBranchConditional %8 %12 %12 + %12 = OpLabel + OpBranch %11 + %13 = OpLabel + OpBranch %11 + %11 = OpLabel + OpReturn + OpFunctionEnd + )"; + CheckEqual(kEnv, after, context.get()); + } + + ops = ConditionalBranchToSimpleConditionalBranchOpportunityFinder() + .GetAvailableOpportunities(context.get()); + ASSERT_EQ(0, ops.size()); + + // Start again, and apply the other op. + context = BuildModule(kEnv, nullptr, shader, kReduceAssembleOption); + + CheckValid(kEnv, context.get()); + + ops = ConditionalBranchToSimpleConditionalBranchOpportunityFinder() + .GetAvailableOpportunities(context.get()); + ASSERT_EQ(2, ops.size()); + + ASSERT_TRUE(ops[0]->PreconditionHolds()); + ASSERT_TRUE(ops[1]->PreconditionHolds()); + ops[1]->TryToApply(); + // The other opportunity should now be disabled. + ASSERT_FALSE(ops[0]->PreconditionHolds()); + + CheckValid(kEnv, context.get()); + + { + std::string after2 = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpSource ESSL 310 + OpName %2 "main" + %3 = OpTypeVoid + %4 = OpTypeFunction %3 + %5 = OpTypeInt 32 1 + %6 = OpTypePointer Function %5 + %7 = OpTypeBool + %8 = OpConstantTrue %7 + %2 = OpFunction %3 None %4 + %9 = OpLabel + OpBranch %10 + %10 = OpLabel + OpSelectionMerge %11 None + OpBranchConditional %8 %13 %13 + %12 = OpLabel + OpBranch %11 + %13 = OpLabel + OpBranch %11 + %11 = OpLabel + OpReturn + OpFunctionEnd + )"; + CheckEqual(kEnv, after2, context.get()); + } +} + +TEST(ConditionalBranchToSimpleConditionalBranchTest, AlreadySimplified) { + // A test with the following structure. + // + // selection header + // OpBranchConditional + // || + // b b + // | | + // selection merge + // + // There should be no opportunities for redirecting the OpBranchConditional + // as it is already simplified. + // + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpSource ESSL 310 + OpName %2 "main" + %3 = OpTypeVoid + %4 = OpTypeFunction %3 + %5 = OpTypeInt 32 1 + %6 = OpTypePointer Function %5 + %7 = OpTypeBool + %8 = OpConstantTrue %7 + %2 = OpFunction %3 None %4 + %9 = OpLabel + OpBranch %10 + %10 = OpLabel + OpSelectionMerge %11 None + OpBranchConditional %8 %12 %12 + %12 = OpLabel + OpBranch %11 + %11 = OpLabel + OpReturn + OpFunctionEnd + + )"; + + auto context = BuildModule(kEnv, nullptr, shader, kReduceAssembleOption); + + CheckValid(kEnv, context.get()); + + auto ops = ConditionalBranchToSimpleConditionalBranchOpportunityFinder() + .GetAvailableOpportunities(context.get()); + + ASSERT_EQ(0, ops.size()); +} + +TEST(ConditionalBranchToSimpleConditionalBranchTest, DontRemoveBackEdge) { + // A test with the following structure. The loop has a continue construct that + // ends with OpBranchConditional. The OpBranchConditional can be simplified, + // but only to point to the loop header, otherwise we have removed the + // back-edge. Thus, there should be one opportunity instead of two. + // + // loop header + // | + // loop continue target and back-edge block + // OpBranchConditional + // | | + // loop merge (to loop header^) + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpSource ESSL 310 + OpName %2 "main" + %3 = OpTypeVoid + %4 = OpTypeFunction %3 + %5 = OpTypeInt 32 1 + %6 = OpTypePointer Function %5 + %7 = OpTypeBool + %8 = OpConstantTrue %7 + %2 = OpFunction %3 None %4 + %9 = OpLabel + OpBranch %10 + %10 = OpLabel + OpLoopMerge %11 %12 None + OpBranch %12 + %12 = OpLabel + OpBranchConditional %8 %11 %10 + %11 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto context = + BuildModule(kEnv, nullptr, shader, kReduceAssembleOption); + + CheckValid(kEnv, context.get()); + + auto ops = ConditionalBranchToSimpleConditionalBranchOpportunityFinder() + .GetAvailableOpportunities(context.get()); + + ASSERT_EQ(1, ops.size()); + + ASSERT_TRUE(ops[0]->PreconditionHolds()); + ops[0]->TryToApply(); + CheckValid(kEnv, context.get()); + + std::string after = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpSource ESSL 310 + OpName %2 "main" + %3 = OpTypeVoid + %4 = OpTypeFunction %3 + %5 = OpTypeInt 32 1 + %6 = OpTypePointer Function %5 + %7 = OpTypeBool + %8 = OpConstantTrue %7 + %2 = OpFunction %3 None %4 + %9 = OpLabel + OpBranch %10 + %10 = OpLabel + OpLoopMerge %11 %12 None + OpBranch %12 + %12 = OpLabel + OpBranchConditional %8 %10 %10 + %11 = OpLabel + OpReturn + OpFunctionEnd + )"; + CheckEqual(kEnv, after, context.get()); + + ops = ConditionalBranchToSimpleConditionalBranchOpportunityFinder() + .GetAvailableOpportunities(context.get()); + ASSERT_EQ(0, ops.size()); +} + +TEST(ConditionalBranchToSimpleConditionalBranchTest, + DontRemoveBackEdgeCombinedHeaderContinue) { + // A test with the following structure. + // + // loop header and continue target and back-edge block + // OpBranchConditional + // | | + // loop merge (to loop header^) + // + // The OpBranchConditional-to-header edge must not be removed, so there should + // only be one opportunity. It should change both targets to be to the loop + // header. + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpSource ESSL 310 + OpName %2 "main" + %3 = OpTypeVoid + %4 = OpTypeFunction %3 + %5 = OpTypeInt 32 1 + %6 = OpTypePointer Function %5 + %7 = OpTypeBool + %8 = OpConstantTrue %7 + %2 = OpFunction %3 None %4 + %9 = OpLabel + OpBranch %10 + %10 = OpLabel + OpLoopMerge %11 %10 None + OpBranchConditional %8 %11 %10 + %11 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto context = + BuildModule(kEnv, nullptr, shader, kReduceAssembleOption); + + CheckValid(kEnv, context.get()); + + auto ops = ConditionalBranchToSimpleConditionalBranchOpportunityFinder() + .GetAvailableOpportunities(context.get()); + + ASSERT_EQ(1, ops.size()); + + ASSERT_TRUE(ops[0]->PreconditionHolds()); + ops[0]->TryToApply(); + CheckValid(kEnv, context.get()); + + std::string after = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpSource ESSL 310 + OpName %2 "main" + %3 = OpTypeVoid + %4 = OpTypeFunction %3 + %5 = OpTypeInt 32 1 + %6 = OpTypePointer Function %5 + %7 = OpTypeBool + %8 = OpConstantTrue %7 + %2 = OpFunction %3 None %4 + %9 = OpLabel + OpBranch %10 + %10 = OpLabel + OpLoopMerge %11 %10 None + OpBranchConditional %8 %10 %10 + %11 = OpLabel + OpReturn + OpFunctionEnd + )"; + CheckEqual(kEnv, after, context.get()); + + ops = ConditionalBranchToSimpleConditionalBranchOpportunityFinder() + .GetAvailableOpportunities(context.get()); + ASSERT_EQ(0, ops.size()); +} + +TEST(ConditionalBranchToSimpleConditionalBranchTest, BackEdgeUnreachable) { + // A test with the following structure. I.e. a loop with an unreachable + // continue construct that ends with OpBranchConditional. + // + // loop header + // | + // | loop continue target (unreachable) + // | | + // | back-edge block (unreachable) + // | OpBranchConditional + // | | | + // loop merge (to loop header^) + // + // The branch to the loop header must not be removed, even though the continue + // construct is unreachable. So there should only be one opportunity to make + // the true and false targets of the OpBranchConditional to point to the loop + // header. + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpSource ESSL 310 + OpName %2 "main" + %3 = OpTypeVoid + %4 = OpTypeFunction %3 + %5 = OpTypeInt 32 1 + %6 = OpTypePointer Function %5 + %7 = OpTypeBool + %8 = OpConstantTrue %7 + %2 = OpFunction %3 None %4 + %9 = OpLabel + OpBranch %10 + %10 = OpLabel + OpLoopMerge %11 %12 None + OpBranch %11 + %12 = OpLabel + OpBranch %13 + %13 = OpLabel + OpBranchConditional %8 %11 %10 + %11 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto context = + BuildModule(kEnv, nullptr, shader, kReduceAssembleOption); + + CheckValid(kEnv, context.get()); + + auto ops = ConditionalBranchToSimpleConditionalBranchOpportunityFinder() + .GetAvailableOpportunities(context.get()); + + ASSERT_EQ(1, ops.size()); + + ASSERT_TRUE(ops[0]->PreconditionHolds()); + ops[0]->TryToApply(); + CheckValid(kEnv, context.get()); + + std::string after = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpSource ESSL 310 + OpName %2 "main" + %3 = OpTypeVoid + %4 = OpTypeFunction %3 + %5 = OpTypeInt 32 1 + %6 = OpTypePointer Function %5 + %7 = OpTypeBool + %8 = OpConstantTrue %7 + %2 = OpFunction %3 None %4 + %9 = OpLabel + OpBranch %10 + %10 = OpLabel + OpLoopMerge %11 %12 None + OpBranch %11 + %12 = OpLabel + OpBranch %13 + %13 = OpLabel + OpBranchConditional %8 %10 %10 + %11 = OpLabel + OpReturn + OpFunctionEnd + )"; + CheckEqual(kEnv, after, context.get()); + + ops = ConditionalBranchToSimpleConditionalBranchOpportunityFinder() + .GetAvailableOpportunities(context.get()); + ASSERT_EQ(0, ops.size()); +} + +} // namespace +} // namespace reduce +} // namespace spvtools diff --git a/third_party/spirv-tools/test/reduce/merge_blocks_test.cpp b/third_party/spirv-tools/test/reduce/merge_blocks_test.cpp new file mode 100644 index 0000000000..dfb614ef55 --- /dev/null +++ b/third_party/spirv-tools/test/reduce/merge_blocks_test.cpp @@ -0,0 +1,652 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/reduce/merge_blocks_reduction_opportunity_finder.h" + +#include "source/opt/build_module.h" +#include "source/reduce/reduction_opportunity.h" +#include "test/reduce/reduce_test_util.h" + +namespace spvtools { +namespace reduce { +namespace { + +TEST(MergeBlocksReductionPassTest, BasicCheck) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %8 "x" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 1 + %10 = OpConstant %6 2 + %11 = OpConstant %6 3 + %12 = OpConstant %6 4 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + OpBranch %13 + %13 = OpLabel + OpStore %8 %9 + OpBranch %14 + %14 = OpLabel + OpStore %8 %10 + OpBranch %15 + %15 = OpLabel + OpStore %8 %11 + OpBranch %16 + %16 = OpLabel + OpStore %8 %12 + OpBranch %17 + %17 = OpLabel + OpReturn + OpFunctionEnd + )"; + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = + BuildModule(env, consumer, shader, kReduceAssembleOption); + const auto ops = + MergeBlocksReductionOpportunityFinder().GetAvailableOpportunities( + context.get()); + ASSERT_EQ(5, ops.size()); + + // Try order 3, 0, 2, 4, 1 + + ASSERT_TRUE(ops[3]->PreconditionHolds()); + ops[3]->TryToApply(); + + std::string after_op_3 = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %8 "x" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 1 + %10 = OpConstant %6 2 + %11 = OpConstant %6 3 + %12 = OpConstant %6 4 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + OpBranch %13 + %13 = OpLabel + OpStore %8 %9 + OpBranch %14 + %14 = OpLabel + OpStore %8 %10 + OpBranch %15 + %15 = OpLabel + OpStore %8 %11 + OpStore %8 %12 + OpBranch %17 + %17 = OpLabel + OpReturn + OpFunctionEnd + )"; + + CheckEqual(env, after_op_3, context.get()); + + ASSERT_TRUE(ops[0]->PreconditionHolds()); + ops[0]->TryToApply(); + + std::string after_op_0 = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %8 "x" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 1 + %10 = OpConstant %6 2 + %11 = OpConstant %6 3 + %12 = OpConstant %6 4 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + OpStore %8 %9 + OpBranch %14 + %14 = OpLabel + OpStore %8 %10 + OpBranch %15 + %15 = OpLabel + OpStore %8 %11 + OpStore %8 %12 + OpBranch %17 + %17 = OpLabel + OpReturn + OpFunctionEnd + )"; + + CheckEqual(env, after_op_0, context.get()); + + ASSERT_TRUE(ops[2]->PreconditionHolds()); + ops[2]->TryToApply(); + + std::string after_op_2 = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %8 "x" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 1 + %10 = OpConstant %6 2 + %11 = OpConstant %6 3 + %12 = OpConstant %6 4 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + OpStore %8 %9 + OpBranch %14 + %14 = OpLabel + OpStore %8 %10 + OpStore %8 %11 + OpStore %8 %12 + OpBranch %17 + %17 = OpLabel + OpReturn + OpFunctionEnd + )"; + + CheckEqual(env, after_op_2, context.get()); + + ASSERT_TRUE(ops[4]->PreconditionHolds()); + ops[4]->TryToApply(); + + std::string after_op_4 = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %8 "x" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 1 + %10 = OpConstant %6 2 + %11 = OpConstant %6 3 + %12 = OpConstant %6 4 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + OpStore %8 %9 + OpBranch %14 + %14 = OpLabel + OpStore %8 %10 + OpStore %8 %11 + OpStore %8 %12 + OpReturn + OpFunctionEnd + )"; + + CheckEqual(env, after_op_4, context.get()); + + ASSERT_TRUE(ops[1]->PreconditionHolds()); + ops[1]->TryToApply(); + + std::string after_op_1 = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %8 "x" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 1 + %10 = OpConstant %6 2 + %11 = OpConstant %6 3 + %12 = OpConstant %6 4 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + OpStore %8 %9 + OpStore %8 %10 + OpStore %8 %11 + OpStore %8 %12 + OpReturn + OpFunctionEnd + )"; + + CheckEqual(env, after_op_1, context.get()); +} + +TEST(MergeBlocksReductionPassTest, Loops) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %8 "x" + OpName %10 "i" + OpName %29 "i" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 1 + %11 = OpConstant %6 0 + %18 = OpConstant %6 10 + %19 = OpTypeBool + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %10 = OpVariable %7 Function + %29 = OpVariable %7 Function + OpStore %8 %9 + OpBranch %45 + %45 = OpLabel + OpStore %10 %11 + OpBranch %12 + %12 = OpLabel + OpLoopMerge %14 %15 None + OpBranch %16 + %16 = OpLabel + %17 = OpLoad %6 %10 + OpBranch %46 + %46 = OpLabel + %20 = OpSLessThan %19 %17 %18 + OpBranchConditional %20 %13 %14 + %13 = OpLabel + %21 = OpLoad %6 %10 + OpBranch %47 + %47 = OpLabel + %22 = OpLoad %6 %8 + %23 = OpIAdd %6 %22 %21 + OpStore %8 %23 + %24 = OpLoad %6 %10 + %25 = OpLoad %6 %8 + %26 = OpIAdd %6 %25 %24 + OpStore %8 %26 + OpBranch %48 + %48 = OpLabel + OpBranch %15 + %15 = OpLabel + %27 = OpLoad %6 %10 + %28 = OpIAdd %6 %27 %9 + OpStore %10 %28 + OpBranch %12 + %14 = OpLabel + OpStore %29 %11 + OpBranch %49 + %49 = OpLabel + OpBranch %30 + %30 = OpLabel + OpLoopMerge %32 %33 None + OpBranch %34 + %34 = OpLabel + %35 = OpLoad %6 %29 + %36 = OpSLessThan %19 %35 %18 + OpBranch %50 + %50 = OpLabel + OpBranchConditional %36 %31 %32 + %31 = OpLabel + %37 = OpLoad %6 %29 + %38 = OpLoad %6 %8 + %39 = OpIAdd %6 %38 %37 + OpStore %8 %39 + %40 = OpLoad %6 %29 + %41 = OpLoad %6 %8 + %42 = OpIAdd %6 %41 %40 + OpStore %8 %42 + OpBranch %33 + %33 = OpLabel + %43 = OpLoad %6 %29 + %44 = OpIAdd %6 %43 %9 + OpBranch %51 + %51 = OpLabel + OpStore %29 %44 + OpBranch %30 + %32 = OpLabel + OpReturn + OpFunctionEnd + )"; + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = + BuildModule(env, consumer, shader, kReduceAssembleOption); + const auto ops = + MergeBlocksReductionOpportunityFinder().GetAvailableOpportunities( + context.get()); + ASSERT_EQ(11, ops.size()); + + for (auto& ri : ops) { + ASSERT_TRUE(ri->PreconditionHolds()); + ri->TryToApply(); + } + + std::string after = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %8 "x" + OpName %10 "i" + OpName %29 "i" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 1 + %11 = OpConstant %6 0 + %18 = OpConstant %6 10 + %19 = OpTypeBool + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %10 = OpVariable %7 Function + %29 = OpVariable %7 Function + OpStore %8 %9 + OpStore %10 %11 + OpBranch %12 + %12 = OpLabel + %17 = OpLoad %6 %10 + %20 = OpSLessThan %19 %17 %18 + OpLoopMerge %14 %13 None + OpBranchConditional %20 %13 %14 + %13 = OpLabel + %21 = OpLoad %6 %10 + %22 = OpLoad %6 %8 + %23 = OpIAdd %6 %22 %21 + OpStore %8 %23 + %24 = OpLoad %6 %10 + %25 = OpLoad %6 %8 + %26 = OpIAdd %6 %25 %24 + OpStore %8 %26 + %27 = OpLoad %6 %10 + %28 = OpIAdd %6 %27 %9 + OpStore %10 %28 + OpBranch %12 + %14 = OpLabel + OpStore %29 %11 + OpBranch %30 + %30 = OpLabel + %35 = OpLoad %6 %29 + %36 = OpSLessThan %19 %35 %18 + OpLoopMerge %32 %31 None + OpBranchConditional %36 %31 %32 + %31 = OpLabel + %37 = OpLoad %6 %29 + %38 = OpLoad %6 %8 + %39 = OpIAdd %6 %38 %37 + OpStore %8 %39 + %40 = OpLoad %6 %29 + %41 = OpLoad %6 %8 + %42 = OpIAdd %6 %41 %40 + OpStore %8 %42 + %43 = OpLoad %6 %29 + %44 = OpIAdd %6 %43 %9 + OpStore %29 %44 + OpBranch %30 + %32 = OpLabel + OpReturn + OpFunctionEnd + )"; + + CheckEqual(env, after, context.get()); +} + +TEST(MergeBlocksReductionPassTest, MergeWithOpPhi) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %8 "x" + OpName %10 "y" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 1 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %10 = OpVariable %7 Function + OpStore %8 %9 + %11 = OpLoad %6 %8 + OpBranch %12 + %12 = OpLabel + %13 = OpPhi %6 %11 %5 + OpStore %10 %13 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = + BuildModule(env, consumer, shader, kReduceAssembleOption); + const auto ops = + MergeBlocksReductionOpportunityFinder().GetAvailableOpportunities( + context.get()); + ASSERT_EQ(1, ops.size()); + + ASSERT_TRUE(ops[0]->PreconditionHolds()); + ops[0]->TryToApply(); + + std::string after = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %8 "x" + OpName %10 "y" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 1 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %10 = OpVariable %7 Function + OpStore %8 %9 + %11 = OpLoad %6 %8 + OpStore %10 %11 + OpReturn + OpFunctionEnd + )"; + + CheckEqual(env, after, context.get()); +} + +void MergeBlocksReductionPassTest_LoopReturn_Helper(bool reverse) { + // A merge block opportunity stores a block that can be merged with its + // predecessor. + // Given blocks A -> B -> C: + // This test demonstrates how merging B->C can invalidate + // the opportunity of merging A->B, and vice-versa. E.g. + // B->C are merged: B is now terminated with OpReturn. + // A->B can now no longer be merged because A is a loop header, which + // cannot be terminated with OpReturn. + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpSource ESSL 310 + OpName %2 "main" + %3 = OpTypeVoid + %4 = OpTypeFunction %3 + %5 = OpTypeInt 32 1 + %6 = OpTypePointer Function %5 + %7 = OpTypeBool + %8 = OpConstantFalse %7 + %2 = OpFunction %3 None %4 + %9 = OpLabel + OpBranch %10 + %10 = OpLabel ; A (loop header) + OpLoopMerge %13 %12 None + OpBranch %11 + %12 = OpLabel ; (unreachable continue block) + OpBranch %10 + %11 = OpLabel ; B + OpBranch %15 + %15 = OpLabel ; C + OpReturn + %13 = OpLabel ; (unreachable merge block) + OpReturn + OpFunctionEnd + )"; + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = + BuildModule(env, consumer, shader, kReduceAssembleOption); + ASSERT_NE(context.get(), nullptr); + auto opportunities = + MergeBlocksReductionOpportunityFinder().GetAvailableOpportunities( + context.get()); + + // A->B and B->C + ASSERT_EQ(opportunities.size(), 2); + + // Test applying opportunities in both orders. + if (reverse) { + std::reverse(opportunities.begin(), opportunities.end()); + } + + size_t num_applied = 0; + for (auto& ri : opportunities) { + if (ri->PreconditionHolds()) { + ri->TryToApply(); + ++num_applied; + } + } + + // Only 1 opportunity can be applied, as both disable each other. + ASSERT_EQ(num_applied, 1); + + std::string after = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpSource ESSL 310 + OpName %2 "main" + %3 = OpTypeVoid + %4 = OpTypeFunction %3 + %5 = OpTypeInt 32 1 + %6 = OpTypePointer Function %5 + %7 = OpTypeBool + %8 = OpConstantFalse %7 + %2 = OpFunction %3 None %4 + %9 = OpLabel + OpBranch %10 + %10 = OpLabel ; A-B (loop header) + OpLoopMerge %13 %12 None + OpBranch %15 + %12 = OpLabel ; (unreachable continue block) + OpBranch %10 + %15 = OpLabel ; C + OpReturn + %13 = OpLabel ; (unreachable merge block) + OpReturn + OpFunctionEnd + )"; + + // The only difference is the labels. + std::string after_reversed = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpSource ESSL 310 + OpName %2 "main" + %3 = OpTypeVoid + %4 = OpTypeFunction %3 + %5 = OpTypeInt 32 1 + %6 = OpTypePointer Function %5 + %7 = OpTypeBool + %8 = OpConstantFalse %7 + %2 = OpFunction %3 None %4 + %9 = OpLabel + OpBranch %10 + %10 = OpLabel ; A (loop header) + OpLoopMerge %13 %12 None + OpBranch %11 + %12 = OpLabel ; (unreachable continue block) + OpBranch %10 + %11 = OpLabel ; B-C + OpReturn + %13 = OpLabel ; (unreachable merge block) + OpReturn + OpFunctionEnd + )"; + + CheckEqual(env, reverse ? after_reversed : after, context.get()); +} + +TEST(MergeBlocksReductionPassTest, LoopReturn) { + MergeBlocksReductionPassTest_LoopReturn_Helper(false); +} + +TEST(MergeBlocksReductionPassTest, LoopReturnReverse) { + MergeBlocksReductionPassTest_LoopReturn_Helper(true); +} + +} // namespace +} // namespace reduce +} // namespace spvtools diff --git a/third_party/spirv-tools/test/reduce/operand_to_constant_test.cpp b/third_party/spirv-tools/test/reduce/operand_to_constant_test.cpp new file mode 100644 index 0000000000..b2f67ee11b --- /dev/null +++ b/third_party/spirv-tools/test/reduce/operand_to_constant_test.cpp @@ -0,0 +1,160 @@ +// Copyright (c) 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/reduce/operand_to_const_reduction_opportunity_finder.h" + +#include "source/opt/build_module.h" +#include "source/reduce/reduction_opportunity.h" +#include "test/reduce/reduce_test_util.h" + +namespace spvtools { +namespace reduce { +namespace { + +TEST(OperandToConstantReductionPassTest, BasicCheck) { + std::string prologue = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" %37 + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %9 "buf1" + OpMemberName %9 0 "f" + OpName %11 "" + OpName %24 "buf2" + OpMemberName %24 0 "i" + OpName %26 "" + OpName %37 "_GLF_color" + OpMemberDecorate %9 0 Offset 0 + OpDecorate %9 Block + OpDecorate %11 DescriptorSet 0 + OpDecorate %11 Binding 1 + OpMemberDecorate %24 0 Offset 0 + OpDecorate %24 Block + OpDecorate %26 DescriptorSet 0 + OpDecorate %26 Binding 2 + OpDecorate %37 Location 0 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %9 = OpTypeStruct %6 + %10 = OpTypePointer Uniform %9 + %11 = OpVariable %10 Uniform + %12 = OpTypeInt 32 1 + %13 = OpConstant %12 0 + %14 = OpTypePointer Uniform %6 + %20 = OpConstant %6 2 + %24 = OpTypeStruct %12 + %25 = OpTypePointer Uniform %24 + %26 = OpVariable %25 Uniform + %27 = OpTypePointer Uniform %12 + %33 = OpConstant %12 3 + %35 = OpTypeVector %6 4 + %36 = OpTypePointer Output %35 + %37 = OpVariable %36 Output + %4 = OpFunction %2 None %3 + %5 = OpLabel + %15 = OpAccessChain %14 %11 %13 + %16 = OpLoad %6 %15 + %19 = OpFAdd %6 %16 %16 + %21 = OpFAdd %6 %19 %20 + %28 = OpAccessChain %27 %26 %13 + %29 = OpLoad %12 %28 + )"; + + std::string epilogue = R"( + %45 = OpConvertSToF %6 %34 + %46 = OpCompositeConstruct %35 %16 %21 %43 %45 + OpStore %37 %46 + OpReturn + OpFunctionEnd + )"; + + std::string original = prologue + R"( + %32 = OpIAdd %12 %29 %29 + %34 = OpIAdd %12 %32 %33 + %43 = OpConvertSToF %6 %29 + )" + epilogue; + + std::string expected = prologue + R"( + %32 = OpIAdd %12 %13 %13 ; %29 -> %13 x 2 + %34 = OpIAdd %12 %13 %33 ; %32 -> %13 + %43 = OpConvertSToF %6 %13 ; %29 -> %13 + )" + epilogue; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = + BuildModule(env, consumer, original, kReduceAssembleOption); + const auto ops = + OperandToConstReductionOpportunityFinder().GetAvailableOpportunities( + context.get()); + ASSERT_EQ(17, ops.size()); + ASSERT_TRUE(ops[0]->PreconditionHolds()); + ops[0]->TryToApply(); + ASSERT_TRUE(ops[1]->PreconditionHolds()); + ops[1]->TryToApply(); + ASSERT_TRUE(ops[2]->PreconditionHolds()); + ops[2]->TryToApply(); + ASSERT_TRUE(ops[3]->PreconditionHolds()); + ops[3]->TryToApply(); + + CheckEqual(env, expected, context.get()); +} + +TEST(OperandToConstantReductionPassTest, WithCalledFunction) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" %10 %12 + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypeVector %6 4 + %8 = OpTypeFunction %7 + %9 = OpTypePointer Output %7 + %10 = OpVariable %9 Output + %11 = OpTypePointer Input %7 + %12 = OpVariable %11 Input + %13 = OpConstant %6 0 + %14 = OpConstantComposite %7 %13 %13 %13 %13 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %15 = OpFunctionCall %7 %16 + OpReturn + OpFunctionEnd + %16 = OpFunction %7 None %8 + %17 = OpLabel + OpReturnValue %14 + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = + BuildModule(env, consumer, shader, kReduceAssembleOption); + const auto ops = + OperandToConstReductionOpportunityFinder().GetAvailableOpportunities( + context.get()); + ASSERT_EQ(0, ops.size()); +} + +} // namespace +} // namespace reduce +} // namespace spvtools diff --git a/third_party/spirv-tools/test/reduce/operand_to_dominating_id_test.cpp b/third_party/spirv-tools/test/reduce/operand_to_dominating_id_test.cpp new file mode 100644 index 0000000000..cd5b2c6891 --- /dev/null +++ b/third_party/spirv-tools/test/reduce/operand_to_dominating_id_test.cpp @@ -0,0 +1,198 @@ +// Copyright (c) 2018 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/reduce/operand_to_dominating_id_reduction_opportunity_finder.h" + +#include "source/opt/build_module.h" +#include "source/reduce/reduction_opportunity.h" +#include "test/reduce/reduce_test_util.h" + +namespace spvtools { +namespace reduce { +namespace { + +TEST(OperandToDominatingIdReductionPassTest, BasicCheck) { + std::string original = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %10 = OpVariable %7 Function + %14 = OpVariable %7 Function + OpStore %8 %9 + %11 = OpLoad %6 %8 + %12 = OpLoad %6 %8 + %13 = OpIAdd %6 %11 %12 + OpStore %10 %13 + %15 = OpLoad %6 %10 + OpStore %14 %15 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = + BuildModule(env, consumer, original, kReduceAssembleOption); + const auto ops = OperandToDominatingIdReductionOpportunityFinder() + .GetAvailableOpportunities(context.get()); + ASSERT_EQ(10, ops.size()); + ASSERT_TRUE(ops[0]->PreconditionHolds()); + ops[0]->TryToApply(); + + std::string after_op_0 = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %10 = OpVariable %7 Function + %14 = OpVariable %7 Function + OpStore %8 %9 + %11 = OpLoad %6 %8 + %12 = OpLoad %6 %8 + %13 = OpIAdd %6 %11 %12 + OpStore %8 %13 ; %10 -> %8 + %15 = OpLoad %6 %10 + OpStore %14 %15 + OpReturn + OpFunctionEnd + )"; + + CheckEqual(env, after_op_0, context.get()); + + ASSERT_TRUE(ops[1]->PreconditionHolds()); + ops[1]->TryToApply(); + + std::string after_op_1 = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %10 = OpVariable %7 Function + %14 = OpVariable %7 Function + OpStore %8 %9 + %11 = OpLoad %6 %8 + %12 = OpLoad %6 %8 + %13 = OpIAdd %6 %11 %12 + OpStore %8 %13 ; %10 -> %8 + %15 = OpLoad %6 %8 ; %10 -> %8 + OpStore %14 %15 + OpReturn + OpFunctionEnd + )"; + + CheckEqual(env, after_op_1, context.get()); + + ASSERT_TRUE(ops[2]->PreconditionHolds()); + ops[2]->TryToApply(); + + std::string after_op_2 = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %10 = OpVariable %7 Function + %14 = OpVariable %7 Function + OpStore %8 %9 + %11 = OpLoad %6 %8 + %12 = OpLoad %6 %8 + %13 = OpIAdd %6 %11 %12 + OpStore %8 %13 ; %10 -> %8 + %15 = OpLoad %6 %8 ; %10 -> %8 + OpStore %8 %15 ; %14 -> %8 + OpReturn + OpFunctionEnd + )"; + + CheckEqual(env, after_op_2, context.get()); + + // The precondition has been disabled by an earlier opportunity's application. + ASSERT_FALSE(ops[3]->PreconditionHolds()); + + ASSERT_TRUE(ops[4]->PreconditionHolds()); + ops[4]->TryToApply(); + + std::string after_op_4 = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %10 = OpVariable %7 Function + %14 = OpVariable %7 Function + OpStore %8 %9 + %11 = OpLoad %6 %8 + %12 = OpLoad %6 %8 + %13 = OpIAdd %6 %11 %11 ; %12 -> %11 + OpStore %8 %13 ; %10 -> %8 + %15 = OpLoad %6 %8 ; %10 -> %8 + OpStore %8 %15 ; %14 -> %8 + OpReturn + OpFunctionEnd + )"; + CheckEqual(env, after_op_4, context.get()); +} + +} // namespace +} // namespace reduce +} // namespace spvtools diff --git a/third_party/spirv-tools/test/reduce/operand_to_undef_test.cpp b/third_party/spirv-tools/test/reduce/operand_to_undef_test.cpp new file mode 100644 index 0000000000..fa64bd53d7 --- /dev/null +++ b/third_party/spirv-tools/test/reduce/operand_to_undef_test.cpp @@ -0,0 +1,230 @@ +// Copyright (c) 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/reduce/operand_to_undef_reduction_opportunity_finder.h" + +#include "source/opt/build_module.h" +#include "source/reduce/reduction_opportunity.h" +#include "test/reduce/reduce_test_util.h" + +namespace spvtools { +namespace reduce { +namespace { + +TEST(OperandToUndefReductionPassTest, BasicCheck) { + // The following shader has 10 opportunities for replacing with undef. + + // #version 310 es + // + // precision highp float; + // + // layout(location=0) out vec4 _GLF_color; + // + // layout(set = 0, binding = 0) uniform buf0 { + // vec2 uniform1; + // }; + // + // void main() + // { + // _GLF_color = + // vec4( // opportunity + // uniform1.x / 2.0, // opportunity x2 (2.0 is const) + // uniform1.y / uniform1.x, // opportunity x3 + // uniform1.x + uniform1.x, // opportunity x3 + // uniform1.y); // opportunity + // } + + std::string original = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" %9 + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %9 "_GLF_color" + OpName %11 "buf0" + OpMemberName %11 0 "uniform1" + OpName %13 "" + OpDecorate %9 Location 0 + OpMemberDecorate %11 0 Offset 0 + OpDecorate %11 Block + OpDecorate %13 DescriptorSet 0 + OpDecorate %13 Binding 0 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypeVector %6 4 + %8 = OpTypePointer Output %7 + %9 = OpVariable %8 Output + %10 = OpTypeVector %6 2 + %11 = OpTypeStruct %10 + %12 = OpTypePointer Uniform %11 + %13 = OpVariable %12 Uniform + %14 = OpTypeInt 32 1 + %15 = OpConstant %14 0 + %16 = OpTypeInt 32 0 + %17 = OpConstant %16 0 + %18 = OpTypePointer Uniform %6 + %21 = OpConstant %6 2 + %23 = OpConstant %16 1 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %19 = OpAccessChain %18 %13 %15 %17 + %20 = OpLoad %6 %19 + %22 = OpFDiv %6 %20 %21 ; opportunity %20 (%21 is const) + %24 = OpAccessChain %18 %13 %15 %23 + %25 = OpLoad %6 %24 + %26 = OpAccessChain %18 %13 %15 %17 + %27 = OpLoad %6 %26 + %28 = OpFDiv %6 %25 %27 ; opportunity %25 %27 + %29 = OpAccessChain %18 %13 %15 %17 + %30 = OpLoad %6 %29 + %31 = OpAccessChain %18 %13 %15 %17 + %32 = OpLoad %6 %31 + %33 = OpFAdd %6 %30 %32 ; opportunity %30 %32 + %34 = OpAccessChain %18 %13 %15 %23 + %35 = OpLoad %6 %34 + %36 = OpCompositeConstruct %7 %22 %28 %33 %35 ; opportunity %22 %28 %33 %35 + OpStore %9 %36 ; opportunity %36 + OpReturn + OpFunctionEnd + )"; + + // This is the same as original, except where noted. + std::string expected = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" %9 + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %9 "_GLF_color" + OpName %11 "buf0" + OpMemberName %11 0 "uniform1" + OpName %13 "" + OpDecorate %9 Location 0 + OpMemberDecorate %11 0 Offset 0 + OpDecorate %11 Block + OpDecorate %13 DescriptorSet 0 + OpDecorate %13 Binding 0 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypeVector %6 4 + %8 = OpTypePointer Output %7 + %9 = OpVariable %8 Output + %10 = OpTypeVector %6 2 + %11 = OpTypeStruct %10 + %12 = OpTypePointer Uniform %11 + %13 = OpVariable %12 Uniform + %14 = OpTypeInt 32 1 + %15 = OpConstant %14 0 + %16 = OpTypeInt 32 0 + %17 = OpConstant %16 0 + %18 = OpTypePointer Uniform %6 + %21 = OpConstant %6 2 + %23 = OpConstant %16 1 + %37 = OpUndef %6 ; Added undef float as %37 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %19 = OpAccessChain %18 %13 %15 %17 + %20 = OpLoad %6 %19 + %22 = OpFDiv %6 %37 %21 ; Replaced with %37 + %24 = OpAccessChain %18 %13 %15 %23 + %25 = OpLoad %6 %24 + %26 = OpAccessChain %18 %13 %15 %17 + %27 = OpLoad %6 %26 + %28 = OpFDiv %6 %37 %37 ; Replaced with %37 twice + %29 = OpAccessChain %18 %13 %15 %17 + %30 = OpLoad %6 %29 + %31 = OpAccessChain %18 %13 %15 %17 + %32 = OpLoad %6 %31 + %33 = OpFAdd %6 %30 %32 + %34 = OpAccessChain %18 %13 %15 %23 + %35 = OpLoad %6 %34 + %36 = OpCompositeConstruct %7 %22 %28 %33 %35 + OpStore %9 %36 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = + BuildModule(env, consumer, original, kReduceAssembleOption); + const auto ops = + OperandToUndefReductionOpportunityFinder().GetAvailableOpportunities( + context.get()); + + ASSERT_EQ(10, ops.size()); + + // Apply first three opportunities. + ASSERT_TRUE(ops[0]->PreconditionHolds()); + ops[0]->TryToApply(); + ASSERT_TRUE(ops[1]->PreconditionHolds()); + ops[1]->TryToApply(); + ASSERT_TRUE(ops[2]->PreconditionHolds()); + ops[2]->TryToApply(); + + CheckEqual(env, expected, context.get()); +} + +TEST(OperandToUndefReductionPassTest, WithCalledFunction) { + // The following shader has no opportunities. + // Most importantly, the noted function operand is not changed. + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" %10 %12 + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypeVector %6 4 + %8 = OpTypeFunction %7 + %9 = OpTypePointer Output %7 + %10 = OpVariable %9 Output + %11 = OpTypePointer Input %7 + %12 = OpVariable %11 Input + %13 = OpConstant %6 0 + %14 = OpConstantComposite %7 %13 %13 %13 %13 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %15 = OpFunctionCall %7 %16 ; do not replace %16 with undef + OpReturn + OpFunctionEnd + %16 = OpFunction %7 None %8 + %17 = OpLabel + OpReturnValue %14 + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = + BuildModule(env, consumer, shader, kReduceAssembleOption); + const auto ops = + OperandToUndefReductionOpportunityFinder().GetAvailableOpportunities( + context.get()); + ASSERT_EQ(0, ops.size()); +} + +} // namespace +} // namespace reduce +} // namespace spvtools diff --git a/third_party/spirv-tools/test/reduce/reduce_test_util.cpp b/third_party/spirv-tools/test/reduce/reduce_test_util.cpp new file mode 100644 index 0000000000..0c2341112c --- /dev/null +++ b/third_party/spirv-tools/test/reduce/reduce_test_util.cpp @@ -0,0 +1,112 @@ +// Copyright (c) 2018 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 "test/reduce/reduce_test_util.h" + +#include + +#include "tools/io.h" + +namespace spvtools { +namespace reduce { + +void CheckEqual(const spv_target_env env, + const std::vector& expected_binary, + const std::vector& actual_binary) { + if (expected_binary != actual_binary) { + SpirvTools t(env); + std::string expected_disassembled; + std::string actual_disassembled; + ASSERT_TRUE(t.Disassemble(expected_binary, &expected_disassembled, + kReduceDisassembleOption)); + ASSERT_TRUE(t.Disassemble(actual_binary, &actual_disassembled, + kReduceDisassembleOption)); + ASSERT_EQ(expected_disassembled, actual_disassembled); + } +} + +void CheckEqual(const spv_target_env env, const std::string& expected_text, + const std::vector& actual_binary) { + std::vector expected_binary; + SpirvTools t(env); + ASSERT_TRUE( + t.Assemble(expected_text, &expected_binary, kReduceAssembleOption)); + CheckEqual(env, expected_binary, actual_binary); +} + +void CheckEqual(const spv_target_env env, const std::string& expected_text, + const opt::IRContext* actual_ir) { + std::vector actual_binary; + actual_ir->module()->ToBinary(&actual_binary, false); + CheckEqual(env, expected_text, actual_binary); +} + +void CheckValid(spv_target_env env, const opt::IRContext* ir) { + std::vector binary; + ir->module()->ToBinary(&binary, false); + SpirvTools t(env); + ASSERT_TRUE(t.Validate(binary)); +} + +std::string ToString(spv_target_env env, const opt::IRContext* ir) { + std::vector binary; + ir->module()->ToBinary(&binary, false); + SpirvTools t(env); + std::string result; + t.Disassemble(binary, &result, kReduceDisassembleOption); + return result; +} + +void NopDiagnostic(spv_message_level_t /*level*/, const char* /*source*/, + const spv_position_t& /*position*/, + const char* /*message*/) {} + +void CLIMessageConsumer(spv_message_level_t level, const char*, + const spv_position_t& position, const char* message) { + switch (level) { + case SPV_MSG_FATAL: + case SPV_MSG_INTERNAL_ERROR: + case SPV_MSG_ERROR: + std::cerr << "error: line " << position.index << ": " << message + << std::endl; + break; + case SPV_MSG_WARNING: + std::cout << "warning: line " << position.index << ": " << message + << std::endl; + break; + case SPV_MSG_INFO: + std::cout << "info: line " << position.index << ": " << message + << std::endl; + break; + default: + break; + } +} + +void DumpShader(opt::IRContext* context, const char* filename) { + std::vector binary; + context->module()->ToBinary(&binary, false); + DumpShader(binary, filename); +} + +void DumpShader(const std::vector& binary, const char* filename) { + auto write_file_succeeded = + WriteFile(filename, "wb", &binary[0], binary.size()); + if (!write_file_succeeded) { + std::cerr << "Failed to dump shader" << std::endl; + } +} + +} // namespace reduce +} // namespace spvtools diff --git a/third_party/spirv-tools/test/reduce/reduce_test_util.h b/third_party/spirv-tools/test/reduce/reduce_test_util.h new file mode 100644 index 0000000000..b9ad12f4c8 --- /dev/null +++ b/third_party/spirv-tools/test/reduce/reduce_test_util.h @@ -0,0 +1,75 @@ +// Copyright (c) 2018 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 TEST_REDUCE_REDUCE_TEST_UTIL_H_ +#define TEST_REDUCE_REDUCE_TEST_UTIL_H_ + +#include "gtest/gtest.h" +#include "source/opt/ir_context.h" +#include "source/reduce/reduction_opportunity.h" +#include "spirv-tools/libspirv.h" + +namespace spvtools { +namespace reduce { + +// Checks whether the given binaries are bit-wise equal. +void CheckEqual(spv_target_env env, + const std::vector& expected_binary, + const std::vector& actual_binary); + +// Assembles the given text and check whether the resulting binary is bit-wise +// equal to the given binary. +void CheckEqual(spv_target_env env, const std::string& expected_text, + const std::vector& actual_binary); + +// Assembles the given text and turns the given IR into binary, then checks +// whether the resulting binaries are bit-wise equal. +void CheckEqual(spv_target_env env, const std::string& expected_text, + const opt::IRContext* actual_ir); + +// Assembles the given IR context and checks whether the resulting binary is +// valid. +void CheckValid(spv_target_env env, const opt::IRContext* ir); + +// Assembles the given IR context, then returns its disassembly as a string. +// Useful for debugging. +std::string ToString(spv_target_env env, const opt::IRContext* ir); + +// Assembly options for writing reduction tests. It simplifies matters if +// numeric ids do not change. +const uint32_t kReduceAssembleOption = + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS; +// Disassembly options for writing reduction tests. +const uint32_t kReduceDisassembleOption = + SPV_BINARY_TO_TEXT_OPTION_NO_HEADER | SPV_BINARY_TO_TEXT_OPTION_INDENT; + +// Don't print reducer info during testing. +void NopDiagnostic(spv_message_level_t /*level*/, const char* /*source*/, + const spv_position_t& /*position*/, const char* /*message*/); + +// Prints reducer messages (for debugging). +void CLIMessageConsumer(spv_message_level_t level, const char*, + const spv_position_t& position, const char* message); + +// Dumps the SPIRV-V module in |context| to file |filename|. Useful for +// interactive debugging. +void DumpShader(opt::IRContext* context, const char* filename); + +// Dumps |binary| to file |filename|. Useful for interactive debugging. +void DumpShader(const std::vector& binary, const char* filename); + +} // namespace reduce +} // namespace spvtools + +#endif // TEST_REDUCE_REDUCE_TEST_UTIL_H_ diff --git a/third_party/spirv-tools/test/reduce/reducer_test.cpp b/third_party/spirv-tools/test/reduce/reducer_test.cpp new file mode 100644 index 0000000000..59f2803691 --- /dev/null +++ b/third_party/spirv-tools/test/reduce/reducer_test.cpp @@ -0,0 +1,441 @@ +// Copyright (c) 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/reduce/reducer.h" + +#include "source/opt/build_module.h" +#include "source/reduce/operand_to_const_reduction_opportunity_finder.h" +#include "source/reduce/remove_unreferenced_instruction_reduction_opportunity_finder.h" +#include "test/reduce/reduce_test_util.h" + +namespace spvtools { +namespace reduce { +namespace { + +using opt::BasicBlock; +using opt::IRContext; + +const spv_target_env kEnv = SPV_ENV_UNIVERSAL_1_3; +const MessageConsumer kMessageConsumer = CLIMessageConsumer; + +// This changes its mind each time IsInteresting is invoked as to whether the +// binary is interesting, until some limit is reached after which the binary is +// always deemed interesting. This is useful to test that reduction passes +// interleave in interesting ways for a while, and then always succeed after +// some point; the latter is important to end up with a predictable final +// reduced binary for tests. +class PingPongInteresting { + public: + explicit PingPongInteresting(uint32_t always_interesting_after) + : is_interesting_(true), + always_interesting_after_(always_interesting_after), + count_(0) {} + + bool IsInteresting(const std::vector&) { + bool result; + if (count_ > always_interesting_after_) { + result = true; + } else { + result = is_interesting_; + is_interesting_ = !is_interesting_; + } + count_++; + return result; + } + + private: + bool is_interesting_; + const uint32_t always_interesting_after_; + uint32_t count_; +}; + +TEST(ReducerTest, ExprToConstantAndRemoveUnreferenced) { + // Check that ExprToConstant and RemoveUnreferenced work together; once some + // ID uses have been changed to constants, those IDs can be removed. + std::string original = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" %60 + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %16 "buf2" + OpMemberName %16 0 "i" + OpName %18 "" + OpName %25 "buf1" + OpMemberName %25 0 "f" + OpName %27 "" + OpName %60 "_GLF_color" + OpMemberDecorate %16 0 Offset 0 + OpDecorate %16 Block + OpDecorate %18 DescriptorSet 0 + OpDecorate %18 Binding 2 + OpMemberDecorate %25 0 Offset 0 + OpDecorate %25 Block + OpDecorate %27 DescriptorSet 0 + OpDecorate %27 Binding 1 + OpDecorate %60 Location 0 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %9 = OpConstant %6 0 + %16 = OpTypeStruct %6 + %17 = OpTypePointer Uniform %16 + %18 = OpVariable %17 Uniform + %19 = OpTypePointer Uniform %6 + %22 = OpTypeBool + %100 = OpConstantTrue %22 + %24 = OpTypeFloat 32 + %25 = OpTypeStruct %24 + %26 = OpTypePointer Uniform %25 + %27 = OpVariable %26 Uniform + %28 = OpTypePointer Uniform %24 + %31 = OpConstant %24 2 + %56 = OpConstant %6 1 + %58 = OpTypeVector %24 4 + %59 = OpTypePointer Output %58 + %60 = OpVariable %59 Output + %72 = OpUndef %24 + %74 = OpUndef %6 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpBranch %10 + %10 = OpLabel + %73 = OpPhi %6 %74 %5 %77 %34 + %71 = OpPhi %24 %72 %5 %76 %34 + %70 = OpPhi %6 %9 %5 %57 %34 + %20 = OpAccessChain %19 %18 %9 + %21 = OpLoad %6 %20 + %23 = OpSLessThan %22 %70 %21 + OpLoopMerge %12 %34 None + OpBranchConditional %23 %11 %12 + %11 = OpLabel + %29 = OpAccessChain %28 %27 %9 + %30 = OpLoad %24 %29 + %32 = OpFOrdGreaterThan %22 %30 %31 + OpSelectionMerge %90 None + OpBranchConditional %32 %33 %46 + %33 = OpLabel + %40 = OpFAdd %24 %71 %30 + %45 = OpISub %6 %73 %21 + OpBranch %90 + %46 = OpLabel + %50 = OpFMul %24 %71 %30 + %54 = OpSDiv %6 %73 %21 + OpBranch %90 + %90 = OpLabel + %77 = OpPhi %6 %45 %33 %54 %46 + %76 = OpPhi %24 %40 %33 %50 %46 + OpBranch %34 + %34 = OpLabel + %57 = OpIAdd %6 %70 %56 + OpBranch %10 + %12 = OpLabel + %61 = OpAccessChain %28 %27 %9 + %62 = OpLoad %24 %61 + %66 = OpConvertSToF %24 %21 + %68 = OpConvertSToF %24 %73 + %69 = OpCompositeConstruct %58 %62 %71 %66 %68 + OpStore %60 %69 + OpReturn + OpFunctionEnd + )"; + + std::string expected = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" %60 + OpExecutionMode %4 OriginUpperLeft + OpMemberDecorate %16 0 Offset 0 + OpDecorate %16 Block + OpDecorate %18 DescriptorSet 0 + OpDecorate %18 Binding 2 + OpMemberDecorate %25 0 Offset 0 + OpDecorate %25 Block + OpDecorate %27 DescriptorSet 0 + OpDecorate %27 Binding 1 + OpDecorate %60 Location 0 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %9 = OpConstant %6 0 + %16 = OpTypeStruct %6 + %17 = OpTypePointer Uniform %16 + %18 = OpVariable %17 Uniform + %22 = OpTypeBool + %100 = OpConstantTrue %22 + %24 = OpTypeFloat 32 + %25 = OpTypeStruct %24 + %26 = OpTypePointer Uniform %25 + %27 = OpVariable %26 Uniform + %31 = OpConstant %24 2 + %56 = OpConstant %6 1 + %58 = OpTypeVector %24 4 + %59 = OpTypePointer Output %58 + %60 = OpVariable %59 Output + %72 = OpUndef %24 + %74 = OpUndef %6 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpBranch %10 + %10 = OpLabel + OpLoopMerge %12 %34 None + OpBranchConditional %100 %11 %12 + %11 = OpLabel + OpSelectionMerge %90 None + OpBranchConditional %100 %33 %46 + %33 = OpLabel + OpBranch %90 + %46 = OpLabel + OpBranch %90 + %90 = OpLabel + OpBranch %34 + %34 = OpLabel + OpBranch %10 + %12 = OpLabel + OpReturn + OpFunctionEnd + )"; + + Reducer reducer(kEnv); + PingPongInteresting ping_pong_interesting(10); + reducer.SetMessageConsumer(NopDiagnostic); + reducer.SetInterestingnessFunction( + [&](const std::vector& binary, uint32_t) -> bool { + return ping_pong_interesting.IsInteresting(binary); + }); + reducer.AddReductionPass( + MakeUnique( + false)); + reducer.AddReductionPass( + MakeUnique()); + + std::vector binary_in; + SpirvTools t(kEnv); + + ASSERT_TRUE(t.Assemble(original, &binary_in, kReduceAssembleOption)); + std::vector binary_out; + spvtools::ReducerOptions reducer_options; + reducer_options.set_step_limit(500); + reducer_options.set_fail_on_validation_error(true); + spvtools::ValidatorOptions validator_options; + + Reducer::ReductionResultStatus status = reducer.Run( + std::move(binary_in), &binary_out, reducer_options, validator_options); + + ASSERT_EQ(status, Reducer::ReductionResultStatus::kComplete); + + CheckEqual(kEnv, expected, binary_out); +} + +bool InterestingWhileOpcodeExists(const std::vector& binary, + uint32_t opcode, uint32_t count, bool dump) { + if (dump) { + std::stringstream ss; + ss << "temp_" << count << ".spv"; + DumpShader(binary, ss.str().c_str()); + } + + std::unique_ptr context = + BuildModule(kEnv, kMessageConsumer, binary.data(), binary.size()); + assert(context); + bool interesting = false; + for (auto& function : *context->module()) { + context->cfg()->ForEachBlockInPostOrder( + &*function.begin(), [opcode, &interesting](BasicBlock* block) -> void { + for (auto& inst : *block) { + if (inst.opcode() == opcode) { + interesting = true; + break; + } + } + }); + if (interesting) { + break; + } + } + return interesting; +} + +bool InterestingWhileIMulReachable(const std::vector& binary, + uint32_t count) { + return InterestingWhileOpcodeExists(binary, SpvOpIMul, count, false); +} + +bool InterestingWhileSDivReachable(const std::vector& binary, + uint32_t count) { + return InterestingWhileOpcodeExists(binary, SpvOpSDiv, count, false); +} + +// The shader below was derived from the following GLSL, and optimized. +// #version 310 es +// precision highp float; +// layout(location = 0) out vec4 _GLF_color; +// int foo() { +// int x = 1; +// int y; +// x = y / x; // SDiv +// return x; +// } +// void main() { +// int c; +// while (bool(c)) { +// do { +// if (bool(c)) { +// if (bool(c)) { +// ++c; +// } else { +// _GLF_color.x = float(c*c); // IMul +// } +// return; +// } +// } while(bool(foo())); +// return; +// } +// } +const std::string kShaderWithLoopsDivAndMul = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" %49 + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %49 "_GLF_color" + OpDecorate %49 Location 0 + OpDecorate %52 RelaxedPrecision + OpDecorate %77 RelaxedPrecision + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %12 = OpConstant %6 1 + %27 = OpTypeBool + %28 = OpTypeInt 32 0 + %29 = OpConstant %28 0 + %46 = OpTypeFloat 32 + %47 = OpTypeVector %46 4 + %48 = OpTypePointer Output %47 + %49 = OpVariable %48 Output + %54 = OpTypePointer Output %46 + %64 = OpConstantFalse %27 + %67 = OpConstantTrue %27 + %81 = OpUndef %6 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpBranch %61 + %61 = OpLabel + OpLoopMerge %60 %63 None + OpBranch %20 + %20 = OpLabel + %30 = OpINotEqual %27 %81 %29 + OpLoopMerge %22 %23 None + OpBranchConditional %30 %21 %22 + %21 = OpLabel + OpBranch %31 + %31 = OpLabel + OpLoopMerge %33 %38 None + OpBranch %32 + %32 = OpLabel + OpBranchConditional %30 %37 %38 + %37 = OpLabel + OpSelectionMerge %42 None + OpBranchConditional %30 %41 %45 + %41 = OpLabel + OpBranch %42 + %45 = OpLabel + %52 = OpIMul %6 %81 %81 + %53 = OpConvertSToF %46 %52 + %55 = OpAccessChain %54 %49 %29 + OpStore %55 %53 + OpBranch %42 + %42 = OpLabel + OpBranch %33 + %38 = OpLabel + %77 = OpSDiv %6 %81 %12 + %58 = OpINotEqual %27 %77 %29 + OpBranchConditional %58 %31 %33 + %33 = OpLabel + %86 = OpPhi %27 %67 %42 %64 %38 + OpSelectionMerge %68 None + OpBranchConditional %86 %22 %68 + %68 = OpLabel + OpBranch %22 + %23 = OpLabel + OpBranch %20 + %22 = OpLabel + %90 = OpPhi %27 %64 %20 %86 %33 %67 %68 + OpSelectionMerge %70 None + OpBranchConditional %90 %60 %70 + %70 = OpLabel + OpBranch %60 + %63 = OpLabel + OpBranch %61 + %60 = OpLabel + OpReturn + OpFunctionEnd + )"; + +TEST(ReducerTest, ShaderReduceWhileMulReachable) { + Reducer reducer(kEnv); + + reducer.SetInterestingnessFunction(InterestingWhileIMulReachable); + reducer.AddDefaultReductionPasses(); + reducer.SetMessageConsumer(kMessageConsumer); + + std::vector binary_in; + SpirvTools t(kEnv); + + ASSERT_TRUE( + t.Assemble(kShaderWithLoopsDivAndMul, &binary_in, kReduceAssembleOption)); + std::vector binary_out; + spvtools::ReducerOptions reducer_options; + reducer_options.set_step_limit(500); + reducer_options.set_fail_on_validation_error(true); + spvtools::ValidatorOptions validator_options; + + Reducer::ReductionResultStatus status = reducer.Run( + std::move(binary_in), &binary_out, reducer_options, validator_options); + + ASSERT_EQ(status, Reducer::ReductionResultStatus::kComplete); +} + +TEST(ReducerTest, ShaderReduceWhileDivReachable) { + Reducer reducer(kEnv); + + reducer.SetInterestingnessFunction(InterestingWhileSDivReachable); + reducer.AddDefaultReductionPasses(); + reducer.SetMessageConsumer(kMessageConsumer); + + std::vector binary_in; + SpirvTools t(kEnv); + + ASSERT_TRUE( + t.Assemble(kShaderWithLoopsDivAndMul, &binary_in, kReduceAssembleOption)); + std::vector binary_out; + spvtools::ReducerOptions reducer_options; + reducer_options.set_step_limit(500); + reducer_options.set_fail_on_validation_error(true); + spvtools::ValidatorOptions validator_options; + + Reducer::ReductionResultStatus status = reducer.Run( + std::move(binary_in), &binary_out, reducer_options, validator_options); + + ASSERT_EQ(status, Reducer::ReductionResultStatus::kComplete); +} + +} // namespace +} // namespace reduce +} // namespace spvtools diff --git a/third_party/spirv-tools/test/reduce/remove_block_test.cpp b/third_party/spirv-tools/test/reduce/remove_block_test.cpp new file mode 100644 index 0000000000..f31cc9da36 --- /dev/null +++ b/third_party/spirv-tools/test/reduce/remove_block_test.cpp @@ -0,0 +1,358 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/reduce/remove_block_reduction_opportunity_finder.h" + +#include "source/opt/build_module.h" +#include "source/reduce/reduction_opportunity.h" +#include "test/reduce/reduce_test_util.h" + +namespace spvtools { +namespace reduce { +namespace { + +TEST(RemoveBlockReductionPassTest, BasicCheck) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %8 "x" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 1 + %10 = OpConstant %6 2 + %11 = OpConstant %6 3 + %12 = OpConstant %6 4 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + OpBranch %14 + %13 = OpLabel ; unreachable + OpStore %8 %9 + OpBranch %14 + %14 = OpLabel + OpStore %8 %10 + OpBranch %16 + %15 = OpLabel ; unreachable + OpStore %8 %11 + OpBranch %16 + %16 = OpLabel + OpStore %8 %12 + OpBranch %17 + %17 = OpLabel + OpReturn + OpFunctionEnd + )"; + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = + BuildModule(env, consumer, shader, kReduceAssembleOption); + const auto ops = + RemoveBlockReductionOpportunityFinder().GetAvailableOpportunities( + context.get()); + ASSERT_EQ(2, ops.size()); + + ASSERT_TRUE(ops[0]->PreconditionHolds()); + ops[0]->TryToApply(); + + std::string after_op_0 = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %8 "x" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 1 + %10 = OpConstant %6 2 + %11 = OpConstant %6 3 + %12 = OpConstant %6 4 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + OpBranch %14 + %14 = OpLabel + OpStore %8 %10 + OpBranch %16 + %15 = OpLabel + OpStore %8 %11 + OpBranch %16 + %16 = OpLabel + OpStore %8 %12 + OpBranch %17 + %17 = OpLabel + OpReturn + OpFunctionEnd + )"; + + CheckEqual(env, after_op_0, context.get()); + + ASSERT_TRUE(ops[1]->PreconditionHolds()); + ops[1]->TryToApply(); + + std::string after_op_1 = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %8 "x" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 1 + %10 = OpConstant %6 2 + %11 = OpConstant %6 3 + %12 = OpConstant %6 4 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + OpBranch %14 + %14 = OpLabel + OpStore %8 %10 + OpBranch %16 + %16 = OpLabel + OpStore %8 %12 + OpBranch %17 + %17 = OpLabel + OpReturn + OpFunctionEnd + )"; + + CheckEqual(env, after_op_1, context.get()); +} + +TEST(RemoveBlockReductionPassTest, UnreachableContinueAndMerge) { + // Loop with unreachable merge and continue target. There should be no + // opportunities. + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpBranch %13 + %13 = OpLabel + OpLoopMerge %16 %15 None + OpBranch %14 + %14 = OpLabel + OpReturn + %15 = OpLabel + OpBranch %13 + %16 = OpLabel + OpReturn + OpFunctionEnd + )"; + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = + BuildModule(env, consumer, shader, kReduceAssembleOption); + const auto ops = + RemoveBlockReductionOpportunityFinder().GetAvailableOpportunities( + context.get()); + ASSERT_EQ(0, ops.size()); +} + +TEST(RemoveBlockReductionPassTest, OneBlock) { + // Function with just one block. There should be no opportunities. + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = + BuildModule(env, consumer, shader, kReduceAssembleOption); + const auto ops = + RemoveBlockReductionOpportunityFinder().GetAvailableOpportunities( + context.get()); + ASSERT_EQ(0, ops.size()); +} + +TEST(RemoveBlockReductionPassTest, UnreachableBlocksWithOutsideIdUses) { + // A function with two unreachable blocks A -> B. A defines ID %9 and B uses + // %9. There are no references to A, but removing A would be invalid because + // of B's use of %9, so there should be no opportunities. + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpSource ESSL 310 + OpName %2 "main" + %3 = OpTypeVoid + %4 = OpTypeInt 32 1 + %5 = OpTypeFunction %3 + %6 = OpConstant %4 1 + %2 = OpFunction %3 None %5 + %7 = OpLabel + OpReturn + %8 = OpLabel ; A + %9 = OpUndef %4 + OpBranch %10 + %10 = OpLabel ; B + %11 = OpIAdd %4 %6 %9 ; uses %9 from A, so A cannot be removed + OpReturn + OpFunctionEnd + )"; + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = + BuildModule(env, consumer, shader, kReduceAssembleOption); + const auto ops = + RemoveBlockReductionOpportunityFinder().GetAvailableOpportunities( + context.get()); + ASSERT_EQ(0, ops.size()); +} + +TEST(RemoveBlockReductionPassTest, UnreachableBlocksWithInsideIdUses) { + // Similar to the above test. + + // A function with two unreachable blocks A -> B. Both blocks create and use + // IDs, but the uses are contained within each block, so A should be removed. + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpSource ESSL 310 + OpName %2 "main" + %3 = OpTypeVoid + %4 = OpTypeInt 32 1 + %5 = OpTypeFunction %3 + %6 = OpConstant %4 1 + %2 = OpFunction %3 None %5 + %7 = OpLabel + OpReturn + %8 = OpLabel ; A + %9 = OpUndef %4 ; define %9 + %10 = OpIAdd %4 %6 %9 ; use %9 + OpBranch %11 + %11 = OpLabel ; B + %12 = OpUndef %4 ; define %12 + %13 = OpIAdd %4 %6 %12 ; use %12 + OpReturn + OpFunctionEnd + )"; + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = + BuildModule(env, consumer, shader, kReduceAssembleOption); + auto ops = RemoveBlockReductionOpportunityFinder().GetAvailableOpportunities( + context.get()); + ASSERT_EQ(1, ops.size()); + + ASSERT_TRUE(ops[0]->PreconditionHolds()); + + ops[0]->TryToApply(); + + // Same as above, but block A is removed. + std::string after_op_0 = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpSource ESSL 310 + OpName %2 "main" + %3 = OpTypeVoid + %4 = OpTypeInt 32 1 + %5 = OpTypeFunction %3 + %6 = OpConstant %4 1 + %2 = OpFunction %3 None %5 + %7 = OpLabel + OpReturn + %11 = OpLabel + %12 = OpUndef %4 + %13 = OpIAdd %4 %6 %12 + OpReturn + OpFunctionEnd + )"; + + CheckEqual(env, after_op_0, context.get()); + + // Find opportunities again. There are no reference to B. B should now be + // removed. + + ops = RemoveBlockReductionOpportunityFinder().GetAvailableOpportunities( + context.get()); + + ASSERT_EQ(1, ops.size()); + + ASSERT_TRUE(ops[0]->PreconditionHolds()); + + ops[0]->TryToApply(); + + // Same as above, but block B is removed. + std::string after_op_0_again = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpSource ESSL 310 + OpName %2 "main" + %3 = OpTypeVoid + %4 = OpTypeInt 32 1 + %5 = OpTypeFunction %3 + %6 = OpConstant %4 1 + %2 = OpFunction %3 None %5 + %7 = OpLabel + OpReturn + OpFunctionEnd + )"; + + CheckEqual(env, after_op_0_again, context.get()); +} + +} // namespace +} // namespace reduce +} // namespace spvtools diff --git a/third_party/spirv-tools/test/reduce/remove_function_test.cpp b/third_party/spirv-tools/test/reduce/remove_function_test.cpp new file mode 100644 index 0000000000..576b603168 --- /dev/null +++ b/third_party/spirv-tools/test/reduce/remove_function_test.cpp @@ -0,0 +1,295 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/reduce/remove_function_reduction_opportunity_finder.h" + +#include "source/opt/build_module.h" +#include "source/reduce/reduction_opportunity.h" +#include "test/reduce/reduce_test_util.h" + +namespace spvtools { +namespace reduce { +namespace { + +// Helper to count the number of functions in the module. +// Remove if there turns out to be a more direct way to do this. +uint32_t count_functions(opt::IRContext* context) { + uint32_t result = 0; + for (auto& function : *context->module()) { + (void)(function); + ++result; + } + return result; +} + +TEST(RemoveFunctionTest, BasicCheck) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + %6 = OpFunction %2 None %3 + %7 = OpLabel + OpReturn + OpFunctionEnd + %8 = OpFunction %2 None %3 + %9 = OpLabel + %10 = OpFunctionCall %2 %6 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = + BuildModule(env, consumer, shader, kReduceAssembleOption); + + ASSERT_EQ(3, count_functions(context.get())); + + auto ops = + RemoveFunctionReductionOpportunityFinder().GetAvailableOpportunities( + context.get()); + ASSERT_EQ(1, ops.size()); + + ASSERT_TRUE(ops[0]->PreconditionHolds()); + ops[0]->TryToApply(); + + ASSERT_EQ(2, count_functions(context.get())); + + std::string after_first = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + %6 = OpFunction %2 None %3 + %7 = OpLabel + OpReturn + OpFunctionEnd + )"; + + CheckEqual(env, after_first, context.get()); + + ops = RemoveFunctionReductionOpportunityFinder().GetAvailableOpportunities( + context.get()); + + ASSERT_EQ(1, ops.size()); + + ASSERT_TRUE(ops[0]->PreconditionHolds()); + ops[0]->TryToApply(); + + ASSERT_EQ(1, count_functions(context.get())); + + std::string after_second = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + + CheckEqual(env, after_second, context.get()); +} + +TEST(RemoveFunctionTest, NothingToRemove) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %11 = OpFunctionCall %2 %8 + OpReturn + OpFunctionEnd + %6 = OpFunction %2 None %3 + %7 = OpLabel + OpReturn + OpFunctionEnd + %8 = OpFunction %2 None %3 + %9 = OpLabel + %10 = OpFunctionCall %2 %6 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = + BuildModule(env, consumer, shader, kReduceAssembleOption); + auto ops = + RemoveFunctionReductionOpportunityFinder().GetAvailableOpportunities( + context.get()); + ASSERT_EQ(0, ops.size()); +} + +TEST(RemoveFunctionTest, TwoRemovableFunctions) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + %6 = OpFunction %2 None %3 + %7 = OpLabel + OpReturn + OpFunctionEnd + %8 = OpFunction %2 None %3 + %9 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = + BuildModule(env, consumer, shader, kReduceAssembleOption); + + ASSERT_EQ(3, count_functions(context.get())); + + auto ops = + RemoveFunctionReductionOpportunityFinder().GetAvailableOpportunities( + context.get()); + ASSERT_EQ(2, ops.size()); + + ASSERT_TRUE(ops[0]->PreconditionHolds()); + ops[0]->TryToApply(); + ASSERT_EQ(2, count_functions(context.get())); + ASSERT_TRUE(ops[1]->PreconditionHolds()); + ops[1]->TryToApply(); + ASSERT_EQ(1, count_functions(context.get())); + + std::string after = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + + CheckEqual(env, after, context.get()); +} + +TEST(RemoveFunctionTest, NoRemovalsDueToOpName) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %6 "foo(" + OpName %8 "bar(" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + %6 = OpFunction %2 None %3 + %7 = OpLabel + OpReturn + OpFunctionEnd + %8 = OpFunction %2 None %3 + %9 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = + BuildModule(env, consumer, shader, kReduceAssembleOption); + auto ops = + RemoveFunctionReductionOpportunityFinder().GetAvailableOpportunities( + context.get()); + ASSERT_EQ(0, ops.size()); +} + +TEST(RemoveFunctionTest, NoRemovalDueToLinkageDecoration) { + // The non-entry point function is not removable because it is referenced by a + // linkage decoration. Thus no function can be removed. + std::string shader = R"( + OpCapability Shader + OpCapability Linkage + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "main" + OpName %1 "main" + OpDecorate %2 LinkageAttributes "ExportedFunc" Export + %4 = OpTypeVoid + %5 = OpTypeFunction %4 + %1 = OpFunction %4 None %5 + %6 = OpLabel + OpReturn + OpFunctionEnd + %2 = OpFunction %4 None %5 + %7 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto consumer = nullptr; + const auto context = + BuildModule(env, consumer, shader, kReduceAssembleOption); + auto ops = + RemoveFunctionReductionOpportunityFinder().GetAvailableOpportunities( + context.get()); + ASSERT_EQ(0, ops.size()); +} + +} // namespace +} // namespace reduce +} // namespace spvtools diff --git a/third_party/spirv-tools/test/reduce/remove_selection_test.cpp b/third_party/spirv-tools/test/reduce/remove_selection_test.cpp new file mode 100644 index 0000000000..f8acd5d456 --- /dev/null +++ b/third_party/spirv-tools/test/reduce/remove_selection_test.cpp @@ -0,0 +1,557 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/reduce/remove_selection_reduction_opportunity_finder.h" + +#include "source/opt/build_module.h" +#include "source/reduce/reduction_opportunity.h" +#include "test/reduce/reduce_test_util.h" + +namespace spvtools { +namespace reduce { +namespace { + +TEST(RemoveSelectionTest, OpportunityBecauseSameTargetBlock) { + // A test with the following structure. The OpSelectionMerge instruction + // should be removed. + // + // header + // || + // block + // | + // merge + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpSource ESSL 310 + OpName %2 "main" + %3 = OpTypeVoid + %4 = OpTypeFunction %3 + %5 = OpTypeInt 32 1 + %6 = OpTypePointer Function %5 + %7 = OpTypeBool + %8 = OpConstantTrue %7 + %2 = OpFunction %3 None %4 + %9 = OpLabel + OpSelectionMerge %10 None + OpBranchConditional %8 %11 %11 + %11 = OpLabel + OpBranch %10 + %10 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); + + auto ops = + RemoveSelectionReductionOpportunityFinder().GetAvailableOpportunities( + context.get()); + + ASSERT_EQ(1, ops.size()); + + ASSERT_TRUE(ops[0]->PreconditionHolds()); + ops[0]->TryToApply(); + CheckValid(env, context.get()); + + std::string after = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpSource ESSL 310 + OpName %2 "main" + %3 = OpTypeVoid + %4 = OpTypeFunction %3 + %5 = OpTypeInt 32 1 + %6 = OpTypePointer Function %5 + %7 = OpTypeBool + %8 = OpConstantTrue %7 + %2 = OpFunction %3 None %4 + %9 = OpLabel + OpBranchConditional %8 %11 %11 + %11 = OpLabel + OpBranch %10 + %10 = OpLabel + OpReturn + OpFunctionEnd + )"; + CheckEqual(env, after, context.get()); + + ops = RemoveSelectionReductionOpportunityFinder().GetAvailableOpportunities( + context.get()); + ASSERT_EQ(0, ops.size()); +} + +TEST(RemoveSelectionTest, OpportunityBecauseSameTargetBlockMerge) { + // A test with the following structure. The OpSelectionMerge instruction + // should be removed. + // + // header + // || + // merge + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpSource ESSL 310 + OpName %2 "main" + %3 = OpTypeVoid + %4 = OpTypeFunction %3 + %5 = OpTypeInt 32 1 + %6 = OpTypePointer Function %5 + %7 = OpTypeBool + %8 = OpConstantTrue %7 + %2 = OpFunction %3 None %4 + %9 = OpLabel + OpSelectionMerge %10 None + OpBranchConditional %8 %10 %10 + %10 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); + + auto ops = + RemoveSelectionReductionOpportunityFinder().GetAvailableOpportunities( + context.get()); + + ASSERT_EQ(1, ops.size()); + + ASSERT_TRUE(ops[0]->PreconditionHolds()); + ops[0]->TryToApply(); + CheckValid(env, context.get()); + + std::string after = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpSource ESSL 310 + OpName %2 "main" + %3 = OpTypeVoid + %4 = OpTypeFunction %3 + %5 = OpTypeInt 32 1 + %6 = OpTypePointer Function %5 + %7 = OpTypeBool + %8 = OpConstantTrue %7 + %2 = OpFunction %3 None %4 + %9 = OpLabel + OpBranchConditional %8 %10 %10 + %10 = OpLabel + OpReturn + OpFunctionEnd + )"; + CheckEqual(env, after, context.get()); + + ops = RemoveSelectionReductionOpportunityFinder().GetAvailableOpportunities( + context.get()); + ASSERT_EQ(0, ops.size()); +} + +TEST(RemoveSelectionTest, NoOpportunityBecauseDifferentTargetBlocksOneMerge) { + // A test with the following structure. The OpSelectionMerge instruction + // should NOT be removed. + // + // header + // | | + // | block + // | | + // merge + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpSource ESSL 310 + OpName %2 "main" + %3 = OpTypeVoid + %4 = OpTypeFunction %3 + %5 = OpTypeInt 32 1 + %6 = OpTypePointer Function %5 + %7 = OpTypeBool + %8 = OpConstantTrue %7 + %2 = OpFunction %3 None %4 + %9 = OpLabel + OpSelectionMerge %10 None + OpBranchConditional %8 %10 %11 + %11 = OpLabel + OpBranch %10 + %10 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); + + auto ops = + RemoveSelectionReductionOpportunityFinder().GetAvailableOpportunities( + context.get()); + ASSERT_EQ(0, ops.size()); +} + +TEST(RemoveSelectionTest, NoOpportunityBecauseDifferentTargetBlocks) { + // A test with the following structure. The OpSelectionMerge instruction + // should NOT be removed. + // + // header + // | | + // b b + // | | + // merge + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpSource ESSL 310 + OpName %2 "main" + %3 = OpTypeVoid + %4 = OpTypeFunction %3 + %5 = OpTypeInt 32 1 + %6 = OpTypePointer Function %5 + %7 = OpTypeBool + %8 = OpConstantTrue %7 + %2 = OpFunction %3 None %4 + %9 = OpLabel + OpSelectionMerge %10 None + OpBranchConditional %8 %11 %12 + %11 = OpLabel + OpBranch %10 + %12 = OpLabel + OpBranch %10 + %10 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); + + auto ops = + RemoveSelectionReductionOpportunityFinder().GetAvailableOpportunities( + context.get()); + ASSERT_EQ(0, ops.size()); +} + +TEST(RemoveSelectionTest, NoOpportunityBecauseMergeUsed) { + // A test with the following structure. The OpSelectionMerge instruction + // should NOT be removed. + // + // header + // || + // block + // | | + // | block + // | | + // merge + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpSource ESSL 310 + OpName %2 "main" + %3 = OpTypeVoid + %4 = OpTypeFunction %3 + %5 = OpTypeInt 32 1 + %6 = OpTypePointer Function %5 + %7 = OpTypeBool + %8 = OpConstantTrue %7 + %2 = OpFunction %3 None %4 + %9 = OpLabel + OpSelectionMerge %10 None + OpBranchConditional %8 %11 %12 + %11 = OpLabel + OpBranchConditional %8 %10 %12 + %12 = OpLabel + OpBranch %10 + %10 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); + + auto ops = + RemoveSelectionReductionOpportunityFinder().GetAvailableOpportunities( + context.get()); + ASSERT_EQ(0, ops.size()); +} + +TEST(RemoveSelectionTest, OpportunityBecauseLoopMergeUsed) { + // A test with the following structure. The OpSelectionMerge instruction + // should be removed. + // + // loop header + // | + // | + // s.header + // || + // block + // | | + // | | + // | | ^ (to loop header) + // s.merge | | + // | / loop continue target (unreachable) + // loop merge + // + // + // which becomes: + // + // loop header + // | + // | + // block + // || + // block + // | | + // | | + // | | ^ (to loop header) + // block | | + // | / loop continue target (unreachable) + // loop merge + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpSource ESSL 310 + OpName %2 "main" + %3 = OpTypeVoid + %4 = OpTypeFunction %3 + %5 = OpTypeInt 32 1 + %6 = OpTypePointer Function %5 + %7 = OpTypeBool + %8 = OpConstantTrue %7 + %2 = OpFunction %3 None %4 + %9 = OpLabel + OpBranch %10 + %10 = OpLabel + OpLoopMerge %11 %12 None + OpBranch %13 + %13 = OpLabel + OpSelectionMerge %14 None + OpBranchConditional %8 %15 %15 + %15 = OpLabel + OpBranchConditional %8 %14 %11 + %14 = OpLabel + OpBranch %11 + %12 = OpLabel + OpBranch %10 + %11 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); + + CheckValid(env, context.get()); + + auto ops = + RemoveSelectionReductionOpportunityFinder().GetAvailableOpportunities( + context.get()); + + ASSERT_EQ(1, ops.size()); + + ASSERT_TRUE(ops[0]->PreconditionHolds()); + ops[0]->TryToApply(); + CheckValid(env, context.get()); + + std::string after = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpSource ESSL 310 + OpName %2 "main" + %3 = OpTypeVoid + %4 = OpTypeFunction %3 + %5 = OpTypeInt 32 1 + %6 = OpTypePointer Function %5 + %7 = OpTypeBool + %8 = OpConstantTrue %7 + %2 = OpFunction %3 None %4 + %9 = OpLabel + OpBranch %10 + %10 = OpLabel + OpLoopMerge %11 %12 None + OpBranch %13 + %13 = OpLabel + OpBranchConditional %8 %15 %15 + %15 = OpLabel + OpBranchConditional %8 %14 %11 + %14 = OpLabel + OpBranch %11 + %12 = OpLabel + OpBranch %10 + %11 = OpLabel + OpReturn + OpFunctionEnd + )"; + CheckEqual(env, after, context.get()); + + ops = RemoveSelectionReductionOpportunityFinder().GetAvailableOpportunities( + context.get()); + ASSERT_EQ(0, ops.size()); +} + +TEST(RemoveSelectionTest, OpportunityBecauseLoopContinueUsed) { + // A test with the following structure. The OpSelectionMerge instruction + // should be removed. + // + // loop header + // | + // | + // s.header + // || + // block + // | | + // | | + // | | ^ (to loop header) + // s.merge | | + // | loop continue target + // loop merge + // + // + // which becomes: + // + // loop header + // | + // | + // block + // || + // block + // | | + // | | + // | | ^ (to loop header) + // block | | + // | loop continue target + // loop merge + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpSource ESSL 310 + OpName %2 "main" + %3 = OpTypeVoid + %4 = OpTypeFunction %3 + %5 = OpTypeInt 32 1 + %6 = OpTypePointer Function %5 + %7 = OpTypeBool + %8 = OpConstantTrue %7 + %2 = OpFunction %3 None %4 + %9 = OpLabel + OpBranch %10 + %10 = OpLabel + OpLoopMerge %11 %12 None + OpBranch %13 + %13 = OpLabel + OpSelectionMerge %14 None + OpBranchConditional %8 %15 %15 + %15 = OpLabel + OpBranchConditional %8 %14 %12 + %14 = OpLabel + OpBranch %11 + %12 = OpLabel + OpBranch %10 + %11 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); + + CheckValid(env, context.get()); + + auto ops = + RemoveSelectionReductionOpportunityFinder().GetAvailableOpportunities( + context.get()); + + ASSERT_EQ(1, ops.size()); + + ASSERT_TRUE(ops[0]->PreconditionHolds()); + ops[0]->TryToApply(); + CheckValid(env, context.get()); + + std::string after = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpSource ESSL 310 + OpName %2 "main" + %3 = OpTypeVoid + %4 = OpTypeFunction %3 + %5 = OpTypeInt 32 1 + %6 = OpTypePointer Function %5 + %7 = OpTypeBool + %8 = OpConstantTrue %7 + %2 = OpFunction %3 None %4 + %9 = OpLabel + OpBranch %10 + %10 = OpLabel + OpLoopMerge %11 %12 None + OpBranch %13 + %13 = OpLabel + OpBranchConditional %8 %15 %15 + %15 = OpLabel + OpBranchConditional %8 %14 %12 + %14 = OpLabel + OpBranch %11 + %12 = OpLabel + OpBranch %10 + %11 = OpLabel + OpReturn + OpFunctionEnd + )"; + CheckEqual(env, after, context.get()); + + ops = RemoveSelectionReductionOpportunityFinder().GetAvailableOpportunities( + context.get()); + ASSERT_EQ(0, ops.size()); +} + +} // namespace +} // namespace reduce +} // namespace spvtools diff --git a/third_party/spirv-tools/test/reduce/remove_unreferenced_instruction_test.cpp b/third_party/spirv-tools/test/reduce/remove_unreferenced_instruction_test.cpp new file mode 100644 index 0000000000..3caf88cfe0 --- /dev/null +++ b/third_party/spirv-tools/test/reduce/remove_unreferenced_instruction_test.cpp @@ -0,0 +1,380 @@ +// Copyright (c) 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/reduce/remove_unreferenced_instruction_reduction_opportunity_finder.h" + +#include "source/opt/build_module.h" +#include "source/reduce/reduction_opportunity.h" +#include "source/util/make_unique.h" +#include "test/reduce/reduce_test_util.h" + +namespace spvtools { +namespace reduce { +namespace { + +const spv_target_env kEnv = SPV_ENV_UNIVERSAL_1_3; + +TEST(RemoveUnreferencedInstructionReductionPassTest, RemoveStores) { + // A module with some unused instructions, including some unused OpStore + // instructions. + + RemoveUnreferencedInstructionReductionOpportunityFinder finder(true); + + const std::string original = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 ; 0 + OpName %4 "main" ; 1 + OpName %8 "a" ; 2 + OpName %10 "b" ; 3 + OpName %12 "c" ; 4 + OpName %14 "d" ; 5 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 10 + %11 = OpConstant %6 20 + %13 = OpConstant %6 30 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %10 = OpVariable %7 Function + %12 = OpVariable %7 Function + %14 = OpVariable %7 Function + OpStore %8 %9 ; 6 + OpStore %10 %11 ; 7 + OpStore %12 %13 ; 8 + %15 = OpLoad %6 %8 + OpStore %14 %15 ; 9 + OpReturn + OpFunctionEnd + + )"; + + const MessageConsumer consumer = nullptr; + const auto context = + BuildModule(kEnv, consumer, original, kReduceAssembleOption); + + CheckValid(kEnv, context.get()); + + auto ops = finder.GetAvailableOpportunities(context.get()); + + ASSERT_EQ(10, ops.size()); + + for (auto& op : ops) { + ASSERT_TRUE(op->PreconditionHolds()); + op->TryToApply(); + CheckValid(kEnv, context.get()); + } + + const std::string step_2 = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 10 ; 0 + %11 = OpConstant %6 20 ; 1 + %13 = OpConstant %6 30 ; 2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %10 = OpVariable %7 Function ; 3 + %12 = OpVariable %7 Function ; 4 + %14 = OpVariable %7 Function ; 5 + %15 = OpLoad %6 %8 ; 6 + OpReturn + OpFunctionEnd + )"; + + CheckEqual(kEnv, step_2, context.get()); + + ops = finder.GetAvailableOpportunities(context.get()); + + ASSERT_EQ(7, ops.size()); + + for (auto& op : ops) { + ASSERT_TRUE(op->PreconditionHolds()); + op->TryToApply(); + CheckValid(kEnv, context.get()); + } + + const std::string step_3 = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function ; 0 + OpReturn + OpFunctionEnd + )"; + + CheckEqual(kEnv, step_3, context.get()); + + ops = finder.GetAvailableOpportunities(context.get()); + + ASSERT_EQ(1, ops.size()); + + for (auto& op : ops) { + ASSERT_TRUE(op->PreconditionHolds()); + op->TryToApply(); + CheckValid(kEnv, context.get()); + } + + const std::string step_4 = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 ; 0 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + + CheckEqual(kEnv, step_4, context.get()); + + ops = finder.GetAvailableOpportunities(context.get()); + + ASSERT_EQ(1, ops.size()); + + for (auto& op : ops) { + ASSERT_TRUE(op->PreconditionHolds()); + op->TryToApply(); + CheckValid(kEnv, context.get()); + } + + const std::string step_5 = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 ; 0 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + + CheckEqual(kEnv, step_5, context.get()); + + ops = finder.GetAvailableOpportunities(context.get()); + + ASSERT_EQ(1, ops.size()); + + for (auto& op : ops) { + ASSERT_TRUE(op->PreconditionHolds()); + op->TryToApply(); + CheckValid(kEnv, context.get()); + } + + const std::string step_6 = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + + CheckEqual(kEnv, step_6, context.get()); + + ops = finder.GetAvailableOpportunities(context.get()); + + ASSERT_EQ(0, ops.size()); +} + +TEST(RemoveUnreferencedInstructionReductionPassTest, Referenced) { + // A module with some unused global variables, constants, and types. Some will + // not be removed initially because of the OpDecorate instructions. + + RemoveUnreferencedInstructionReductionOpportunityFinder finder(true); + + const std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 ; 1 + OpName %4 "main" ; 2 + OpName %12 "a" ; 3 + OpDecorate %12 RelaxedPrecision ; 4 + OpDecorate %13 RelaxedPrecision ; 5 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeBool + %7 = OpConstantTrue %6 ; 6 + %10 = OpTypeInt 32 1 + %11 = OpTypePointer Private %10 + %12 = OpVariable %11 Private + %13 = OpConstant %10 1 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + + auto context = BuildModule(kEnv, nullptr, shader, kReduceAssembleOption); + + CheckValid(kEnv, context.get()); + + auto ops = finder.GetAvailableOpportunities(context.get()); + + ASSERT_EQ(6, ops.size()); + + for (auto& op : ops) { + ASSERT_TRUE(op->PreconditionHolds()); + op->TryToApply(); + CheckValid(kEnv, context.get()); + } + + std::string after = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeBool ; 1 + %10 = OpTypeInt 32 1 + %11 = OpTypePointer Private %10 + %12 = OpVariable %11 Private ; 2 + %13 = OpConstant %10 1 ; 3 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + + CheckEqual(kEnv, after, context.get()); + + ops = finder.GetAvailableOpportunities(context.get()); + + ASSERT_EQ(3, ops.size()); + + for (auto& op : ops) { + ASSERT_TRUE(op->PreconditionHolds()); + op->TryToApply(); + CheckValid(kEnv, context.get()); + } + + std::string after_2 = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %10 = OpTypeInt 32 1 + %11 = OpTypePointer Private %10 ; 1 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + + CheckEqual(kEnv, after_2, context.get()); + + ops = finder.GetAvailableOpportunities(context.get()); + + ASSERT_EQ(1, ops.size()); + + for (auto& op : ops) { + ASSERT_TRUE(op->PreconditionHolds()); + op->TryToApply(); + CheckValid(kEnv, context.get()); + } + + std::string after_3 = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %10 = OpTypeInt 32 1 ; 1 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + + CheckEqual(kEnv, after_3, context.get()); + + ops = finder.GetAvailableOpportunities(context.get()); + + ASSERT_EQ(1, ops.size()); + + for (auto& op : ops) { + ASSERT_TRUE(op->PreconditionHolds()); + op->TryToApply(); + CheckValid(kEnv, context.get()); + } + + std::string after_4 = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + + CheckEqual(kEnv, after_4, context.get()); + + ops = finder.GetAvailableOpportunities(context.get()); + + ASSERT_EQ(0, ops.size()); +} + +} // namespace +} // namespace reduce +} // namespace spvtools diff --git a/third_party/spirv-tools/test/reduce/simple_conditional_branch_to_branch_test.cpp b/third_party/spirv-tools/test/reduce/simple_conditional_branch_to_branch_test.cpp new file mode 100644 index 0000000000..d55e691038 --- /dev/null +++ b/third_party/spirv-tools/test/reduce/simple_conditional_branch_to_branch_test.cpp @@ -0,0 +1,486 @@ +// Copyright (c) 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/reduce/simple_conditional_branch_to_branch_opportunity_finder.h" + +#include "source/opt/build_module.h" +#include "source/reduce/reduction_opportunity.h" +#include "source/reduce/reduction_pass.h" +#include "test/reduce/reduce_test_util.h" + +namespace spvtools { +namespace reduce { +namespace { + +const spv_target_env kEnv = SPV_ENV_UNIVERSAL_1_3; + +TEST(SimpleConditionalBranchToBranchTest, Diamond) { + // A test with the following structure. + // + // selection header + // OpBranchConditional + // || + // b b + // | | + // selection merge + // + // The conditional branch cannot be simplified because selection headers + // cannot end with OpBranch. + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpSource ESSL 310 + OpName %2 "main" + %3 = OpTypeVoid + %4 = OpTypeFunction %3 + %5 = OpTypeInt 32 1 + %6 = OpTypePointer Function %5 + %7 = OpTypeBool + %8 = OpConstantTrue %7 + %2 = OpFunction %3 None %4 + %9 = OpLabel + OpBranch %10 + %10 = OpLabel + OpSelectionMerge %11 None + OpBranchConditional %8 %12 %12 + %12 = OpLabel + OpBranch %11 + %13 = OpLabel + OpBranch %11 + %11 = OpLabel + OpReturn + OpFunctionEnd + + )"; + + auto context = BuildModule(kEnv, nullptr, shader, kReduceAssembleOption); + + CheckValid(kEnv, context.get()); + + auto ops = SimpleConditionalBranchToBranchOpportunityFinder() + .GetAvailableOpportunities(context.get()); + + ASSERT_EQ(0, ops.size()); +} + +TEST(SimpleConditionalBranchToBranchTest, DiamondNoSelection) { + // A test with the following structure. + // + // OpBranchConditional + // || + // b b + // | / + // b + // + // The conditional branch can be simplified. + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpSource ESSL 310 + OpName %2 "main" + %3 = OpTypeVoid + %4 = OpTypeFunction %3 + %5 = OpTypeInt 32 1 + %6 = OpTypePointer Function %5 + %7 = OpTypeBool + %8 = OpConstantTrue %7 + %2 = OpFunction %3 None %4 + %9 = OpLabel + OpBranch %10 + %10 = OpLabel + OpBranchConditional %8 %12 %12 + %12 = OpLabel + OpBranch %11 + %13 = OpLabel + OpBranch %11 + %11 = OpLabel + OpReturn + OpFunctionEnd + )"; + + auto context = BuildModule(kEnv, nullptr, shader, kReduceAssembleOption); + + CheckValid(kEnv, context.get()); + + auto ops = SimpleConditionalBranchToBranchOpportunityFinder() + .GetAvailableOpportunities(context.get()); + + ASSERT_EQ(1, ops.size()); + + ASSERT_TRUE(ops[0]->PreconditionHolds()); + ops[0]->TryToApply(); + CheckValid(kEnv, context.get()); + + std::string after = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpSource ESSL 310 + OpName %2 "main" + %3 = OpTypeVoid + %4 = OpTypeFunction %3 + %5 = OpTypeInt 32 1 + %6 = OpTypePointer Function %5 + %7 = OpTypeBool + %8 = OpConstantTrue %7 + %2 = OpFunction %3 None %4 + %9 = OpLabel + OpBranch %10 + %10 = OpLabel + OpBranch %12 + %12 = OpLabel + OpBranch %11 + %13 = OpLabel + OpBranch %11 + %11 = OpLabel + OpReturn + OpFunctionEnd + )"; + + CheckEqual(kEnv, after, context.get()); + + ops = SimpleConditionalBranchToBranchOpportunityFinder() + .GetAvailableOpportunities(context.get()); + ASSERT_EQ(0, ops.size()); +} + +TEST(SimpleConditionalBranchToBranchTest, ConditionalBranchesButNotSimple) { + // A test with the following structure. + // + // selection header + // OpBranchConditional + // | | + // b OpBranchConditional + // | | | + // | b | + // | | | + // selection merge + // + // None of the conditional branches can be simplified; the first is not simple + // AND part of a selection header; the second is just not simple (where + // "simple" means it only has one target). + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpSource ESSL 310 + OpName %2 "main" + %3 = OpTypeVoid + %4 = OpTypeFunction %3 + %5 = OpTypeInt 32 1 + %6 = OpTypePointer Function %5 + %7 = OpTypeBool + %8 = OpConstantTrue %7 + %2 = OpFunction %3 None %4 + %9 = OpLabel + OpBranch %10 + %10 = OpLabel + OpSelectionMerge %11 None + OpBranchConditional %8 %12 %13 + %12 = OpLabel + OpBranch %11 + %13 = OpLabel + OpBranchConditional %8 %14 %11 + %14 = OpLabel + OpBranch %11 + %11 = OpLabel + OpReturn + OpFunctionEnd + )"; + + auto context = BuildModule(kEnv, nullptr, shader, kReduceAssembleOption); + + CheckValid(kEnv, context.get()); + + auto ops = SimpleConditionalBranchToBranchOpportunityFinder() + .GetAvailableOpportunities(context.get()); + + ASSERT_EQ(0, ops.size()); +} + +TEST(SimpleConditionalBranchToBranchTest, SimplifyBackEdge) { + // A test with the following structure. The loop has a continue construct that + // ends with OpBranchConditional. The OpBranchConditional can be simplified. + // + // loop header + // | + // loop continue target and back-edge block + // OpBranchConditional + // || + // loop merge (to loop header^) + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpSource ESSL 310 + OpName %2 "main" + %3 = OpTypeVoid + %4 = OpTypeFunction %3 + %5 = OpTypeInt 32 1 + %6 = OpTypePointer Function %5 + %7 = OpTypeBool + %8 = OpConstantTrue %7 + %2 = OpFunction %3 None %4 + %9 = OpLabel + OpBranch %10 + %10 = OpLabel + OpLoopMerge %11 %12 None + OpBranch %12 + %12 = OpLabel + OpBranchConditional %8 %10 %10 + %11 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto context = + BuildModule(kEnv, nullptr, shader, kReduceAssembleOption); + + CheckValid(kEnv, context.get()); + + auto ops = SimpleConditionalBranchToBranchOpportunityFinder() + .GetAvailableOpportunities(context.get()); + + ASSERT_EQ(1, ops.size()); + + ASSERT_TRUE(ops[0]->PreconditionHolds()); + ops[0]->TryToApply(); + CheckValid(kEnv, context.get()); + + std::string after = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpSource ESSL 310 + OpName %2 "main" + %3 = OpTypeVoid + %4 = OpTypeFunction %3 + %5 = OpTypeInt 32 1 + %6 = OpTypePointer Function %5 + %7 = OpTypeBool + %8 = OpConstantTrue %7 + %2 = OpFunction %3 None %4 + %9 = OpLabel + OpBranch %10 + %10 = OpLabel + OpLoopMerge %11 %12 None + OpBranch %12 + %12 = OpLabel + OpBranch %10 + %11 = OpLabel + OpReturn + OpFunctionEnd + )"; + CheckEqual(kEnv, after, context.get()); + + ops = SimpleConditionalBranchToBranchOpportunityFinder() + .GetAvailableOpportunities(context.get()); + ASSERT_EQ(0, ops.size()); +} + +TEST(SimpleConditionalBranchToBranchTest, + DontRemoveBackEdgeCombinedHeaderContinue) { + // A test with the following structure. + // + // loop header and continue target and back-edge block + // OpBranchConditional + // || + // loop merge (to loop header^) + // + // The conditional branch can be simplified. + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpSource ESSL 310 + OpName %2 "main" + %3 = OpTypeVoid + %4 = OpTypeFunction %3 + %5 = OpTypeInt 32 1 + %6 = OpTypePointer Function %5 + %7 = OpTypeBool + %8 = OpConstantTrue %7 + %2 = OpFunction %3 None %4 + %9 = OpLabel + OpBranch %10 + %10 = OpLabel + OpLoopMerge %11 %10 None + OpBranchConditional %8 %10 %10 + %11 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto context = + BuildModule(kEnv, nullptr, shader, kReduceAssembleOption); + + CheckValid(kEnv, context.get()); + + auto ops = SimpleConditionalBranchToBranchOpportunityFinder() + .GetAvailableOpportunities(context.get()); + + ASSERT_EQ(1, ops.size()); + + ASSERT_TRUE(ops[0]->PreconditionHolds()); + ops[0]->TryToApply(); + CheckValid(kEnv, context.get()); + + std::string after = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpSource ESSL 310 + OpName %2 "main" + %3 = OpTypeVoid + %4 = OpTypeFunction %3 + %5 = OpTypeInt 32 1 + %6 = OpTypePointer Function %5 + %7 = OpTypeBool + %8 = OpConstantTrue %7 + %2 = OpFunction %3 None %4 + %9 = OpLabel + OpBranch %10 + %10 = OpLabel + OpLoopMerge %11 %10 None + OpBranch %10 + %11 = OpLabel + OpReturn + OpFunctionEnd + )"; + CheckEqual(kEnv, after, context.get()); + + ops = SimpleConditionalBranchToBranchOpportunityFinder() + .GetAvailableOpportunities(context.get()); + ASSERT_EQ(0, ops.size()); +} + +TEST(SimpleConditionalBranchToBranchTest, BackEdgeUnreachable) { + // A test with the following structure. I.e. a loop with an unreachable + // continue construct that ends with OpBranchConditional. + // + // loop header + // | + // | loop continue target (unreachable) + // | | + // | back-edge block (unreachable) + // | OpBranchConditional + // | || + // loop merge (to loop header^) + // + // The conditional branch can be simplified. + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpSource ESSL 310 + OpName %2 "main" + %3 = OpTypeVoid + %4 = OpTypeFunction %3 + %5 = OpTypeInt 32 1 + %6 = OpTypePointer Function %5 + %7 = OpTypeBool + %8 = OpConstantTrue %7 + %2 = OpFunction %3 None %4 + %9 = OpLabel + OpBranch %10 + %10 = OpLabel + OpLoopMerge %11 %12 None + OpBranch %11 + %12 = OpLabel + OpBranch %13 + %13 = OpLabel + OpBranchConditional %8 %10 %10 + %11 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto context = + BuildModule(kEnv, nullptr, shader, kReduceAssembleOption); + + CheckValid(kEnv, context.get()); + + auto ops = SimpleConditionalBranchToBranchOpportunityFinder() + .GetAvailableOpportunities(context.get()); + + ASSERT_EQ(1, ops.size()); + + ASSERT_TRUE(ops[0]->PreconditionHolds()); + ops[0]->TryToApply(); + CheckValid(kEnv, context.get()); + + std::string after = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpSource ESSL 310 + OpName %2 "main" + %3 = OpTypeVoid + %4 = OpTypeFunction %3 + %5 = OpTypeInt 32 1 + %6 = OpTypePointer Function %5 + %7 = OpTypeBool + %8 = OpConstantTrue %7 + %2 = OpFunction %3 None %4 + %9 = OpLabel + OpBranch %10 + %10 = OpLabel + OpLoopMerge %11 %12 None + OpBranch %11 + %12 = OpLabel + OpBranch %13 + %13 = OpLabel + OpBranch %10 + %11 = OpLabel + OpReturn + OpFunctionEnd + )"; + CheckEqual(kEnv, after, context.get()); + + ops = SimpleConditionalBranchToBranchOpportunityFinder() + .GetAvailableOpportunities(context.get()); + ASSERT_EQ(0, ops.size()); +} + +} // namespace +} // namespace reduce +} // namespace spvtools diff --git a/third_party/spirv-tools/test/reduce/structured_loop_to_selection_test.cpp b/third_party/spirv-tools/test/reduce/structured_loop_to_selection_test.cpp new file mode 100644 index 0000000000..95b5f4f150 --- /dev/null +++ b/third_party/spirv-tools/test/reduce/structured_loop_to_selection_test.cpp @@ -0,0 +1,3628 @@ +// Copyright (c) 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/reduce/structured_loop_to_selection_reduction_opportunity_finder.h" + +#include "source/opt/build_module.h" +#include "source/reduce/reduction_opportunity.h" +#include "test/reduce/reduce_test_util.h" + +namespace spvtools { +namespace reduce { +namespace { + +TEST(StructuredLoopToSelectionReductionPassTest, LoopyShader1) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 0 + %16 = OpConstant %6 100 + %17 = OpTypeBool + %20 = OpConstant %6 1 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + OpStore %8 %9 + OpBranch %10 + %10 = OpLabel + OpLoopMerge %12 %13 None + OpBranch %14 + %14 = OpLabel + %15 = OpLoad %6 %8 + %18 = OpSLessThan %17 %15 %16 + OpBranchConditional %18 %11 %12 + %11 = OpLabel + OpBranch %13 + %13 = OpLabel + %19 = OpLoad %6 %8 + %21 = OpIAdd %6 %19 %20 + OpStore %8 %21 + OpBranch %10 + %12 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); + const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() + .GetAvailableOpportunities(context.get()); + ASSERT_EQ(1, ops.size()); + + ASSERT_TRUE(ops[0]->PreconditionHolds()); + ops[0]->TryToApply(); + CheckValid(env, context.get()); + + std::string after_op_0 = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 0 + %16 = OpConstant %6 100 + %17 = OpTypeBool + %20 = OpConstant %6 1 + %22 = OpConstantTrue %17 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + OpStore %8 %9 + OpBranch %10 + %10 = OpLabel + OpSelectionMerge %12 None + OpBranchConditional %22 %14 %12 + %14 = OpLabel + %15 = OpLoad %6 %8 + %18 = OpSLessThan %17 %15 %16 + OpBranchConditional %18 %11 %12 + %11 = OpLabel + OpBranch %12 + %13 = OpLabel + %19 = OpLoad %6 %8 + %21 = OpIAdd %6 %19 %20 + OpStore %8 %21 + OpBranch %10 + %12 = OpLabel + OpReturn + OpFunctionEnd + )"; + CheckEqual(env, after_op_0, context.get()); +} + +TEST(StructuredLoopToSelectionReductionPassTest, LoopyShader2) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 0 + %16 = OpConstant %6 100 + %17 = OpTypeBool + %28 = OpConstant %6 1 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %19 = OpVariable %7 Function + %32 = OpVariable %7 Function + %40 = OpVariable %7 Function + OpStore %8 %9 + OpBranch %10 + %10 = OpLabel + OpLoopMerge %12 %13 None + OpBranch %14 + %14 = OpLabel + %15 = OpLoad %6 %8 + %18 = OpSLessThan %17 %15 %16 + OpBranchConditional %18 %11 %12 + %11 = OpLabel + OpStore %19 %9 + OpBranch %20 + %20 = OpLabel + OpLoopMerge %22 %23 None + OpBranch %24 + %24 = OpLabel + %25 = OpLoad %6 %19 + %26 = OpSLessThan %17 %25 %16 + OpBranchConditional %26 %21 %22 + %21 = OpLabel + OpBranch %23 + %23 = OpLabel + %27 = OpLoad %6 %19 + %29 = OpIAdd %6 %27 %28 + OpStore %19 %29 + OpBranch %20 + %22 = OpLabel + OpBranch %13 + %13 = OpLabel + %30 = OpLoad %6 %8 + %31 = OpIAdd %6 %30 %28 + OpStore %8 %31 + OpBranch %10 + %12 = OpLabel + OpStore %32 %9 + OpBranch %33 + %33 = OpLabel + OpLoopMerge %35 %36 None + OpBranch %37 + %37 = OpLabel + %38 = OpLoad %6 %32 + %39 = OpSLessThan %17 %38 %16 + OpBranchConditional %39 %34 %35 + %34 = OpLabel + OpStore %40 %9 + OpBranch %41 + %41 = OpLabel + OpLoopMerge %43 %44 None + OpBranch %45 + %45 = OpLabel + %46 = OpLoad %6 %40 + %47 = OpSLessThan %17 %46 %16 + OpBranchConditional %47 %42 %43 + %42 = OpLabel + OpBranch %44 + %44 = OpLabel + %48 = OpLoad %6 %40 + %49 = OpIAdd %6 %48 %28 + OpStore %40 %49 + OpBranch %41 + %43 = OpLabel + OpBranch %36 + %36 = OpLabel + %50 = OpLoad %6 %32 + %51 = OpIAdd %6 %50 %28 + OpStore %32 %51 + OpBranch %33 + %35 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); + const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() + .GetAvailableOpportunities(context.get()); + ASSERT_EQ(4, ops.size()); + + ASSERT_TRUE(ops[0]->PreconditionHolds()); + ops[0]->TryToApply(); + CheckValid(env, context.get()); + std::string after_op_0 = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 0 + %16 = OpConstant %6 100 + %17 = OpTypeBool + %28 = OpConstant %6 1 + %52 = OpConstantTrue %17 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %19 = OpVariable %7 Function + %32 = OpVariable %7 Function + %40 = OpVariable %7 Function + OpStore %8 %9 + OpBranch %10 + %10 = OpLabel + OpSelectionMerge %12 None + OpBranchConditional %52 %14 %12 + %14 = OpLabel + %15 = OpLoad %6 %8 + %18 = OpSLessThan %17 %15 %16 + OpBranchConditional %18 %11 %12 + %11 = OpLabel + OpStore %19 %9 + OpBranch %20 + %20 = OpLabel + OpLoopMerge %22 %23 None + OpBranch %24 + %24 = OpLabel + %25 = OpLoad %6 %19 + %26 = OpSLessThan %17 %25 %16 + OpBranchConditional %26 %21 %22 + %21 = OpLabel + OpBranch %23 + %23 = OpLabel + %27 = OpLoad %6 %19 + %29 = OpIAdd %6 %27 %28 + OpStore %19 %29 + OpBranch %20 + %22 = OpLabel + OpBranch %12 + %13 = OpLabel + %30 = OpLoad %6 %8 + %31 = OpIAdd %6 %30 %28 + OpStore %8 %31 + OpBranch %10 + %12 = OpLabel + OpStore %32 %9 + OpBranch %33 + %33 = OpLabel + OpLoopMerge %35 %36 None + OpBranch %37 + %37 = OpLabel + %38 = OpLoad %6 %32 + %39 = OpSLessThan %17 %38 %16 + OpBranchConditional %39 %34 %35 + %34 = OpLabel + OpStore %40 %9 + OpBranch %41 + %41 = OpLabel + OpLoopMerge %43 %44 None + OpBranch %45 + %45 = OpLabel + %46 = OpLoad %6 %40 + %47 = OpSLessThan %17 %46 %16 + OpBranchConditional %47 %42 %43 + %42 = OpLabel + OpBranch %44 + %44 = OpLabel + %48 = OpLoad %6 %40 + %49 = OpIAdd %6 %48 %28 + OpStore %40 %49 + OpBranch %41 + %43 = OpLabel + OpBranch %36 + %36 = OpLabel + %50 = OpLoad %6 %32 + %51 = OpIAdd %6 %50 %28 + OpStore %32 %51 + OpBranch %33 + %35 = OpLabel + OpReturn + OpFunctionEnd + )"; + CheckEqual(env, after_op_0, context.get()); + + ASSERT_TRUE(ops[1]->PreconditionHolds()); + ops[1]->TryToApply(); + CheckValid(env, context.get()); + std::string after_op_1 = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 0 + %16 = OpConstant %6 100 + %17 = OpTypeBool + %28 = OpConstant %6 1 + %52 = OpConstantTrue %17 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %19 = OpVariable %7 Function + %32 = OpVariable %7 Function + %40 = OpVariable %7 Function + OpStore %8 %9 + OpBranch %10 + %10 = OpLabel + OpSelectionMerge %12 None + OpBranchConditional %52 %14 %12 + %14 = OpLabel + %15 = OpLoad %6 %8 + %18 = OpSLessThan %17 %15 %16 + OpBranchConditional %18 %11 %12 + %11 = OpLabel + OpStore %19 %9 + OpBranch %20 + %20 = OpLabel + OpSelectionMerge %22 None + OpBranchConditional %52 %24 %22 + %24 = OpLabel + %25 = OpLoad %6 %19 + %26 = OpSLessThan %17 %25 %16 + OpBranchConditional %26 %21 %22 + %21 = OpLabel + OpBranch %22 + %23 = OpLabel + %27 = OpLoad %6 %19 + %29 = OpIAdd %6 %27 %28 + OpStore %19 %29 + OpBranch %20 + %22 = OpLabel + OpBranch %12 + %13 = OpLabel + %30 = OpLoad %6 %8 + %31 = OpIAdd %6 %30 %28 + OpStore %8 %31 + OpBranch %10 + %12 = OpLabel + OpStore %32 %9 + OpBranch %33 + %33 = OpLabel + OpLoopMerge %35 %36 None + OpBranch %37 + %37 = OpLabel + %38 = OpLoad %6 %32 + %39 = OpSLessThan %17 %38 %16 + OpBranchConditional %39 %34 %35 + %34 = OpLabel + OpStore %40 %9 + OpBranch %41 + %41 = OpLabel + OpLoopMerge %43 %44 None + OpBranch %45 + %45 = OpLabel + %46 = OpLoad %6 %40 + %47 = OpSLessThan %17 %46 %16 + OpBranchConditional %47 %42 %43 + %42 = OpLabel + OpBranch %44 + %44 = OpLabel + %48 = OpLoad %6 %40 + %49 = OpIAdd %6 %48 %28 + OpStore %40 %49 + OpBranch %41 + %43 = OpLabel + OpBranch %36 + %36 = OpLabel + %50 = OpLoad %6 %32 + %51 = OpIAdd %6 %50 %28 + OpStore %32 %51 + OpBranch %33 + %35 = OpLabel + OpReturn + OpFunctionEnd + )"; + CheckEqual(env, after_op_1, context.get()); + + ASSERT_TRUE(ops[2]->PreconditionHolds()); + ops[2]->TryToApply(); + CheckValid(env, context.get()); + std::string after_op_2 = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 0 + %16 = OpConstant %6 100 + %17 = OpTypeBool + %28 = OpConstant %6 1 + %52 = OpConstantTrue %17 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %19 = OpVariable %7 Function + %32 = OpVariable %7 Function + %40 = OpVariable %7 Function + OpStore %8 %9 + OpBranch %10 + %10 = OpLabel + OpSelectionMerge %12 None + OpBranchConditional %52 %14 %12 + %14 = OpLabel + %15 = OpLoad %6 %8 + %18 = OpSLessThan %17 %15 %16 + OpBranchConditional %18 %11 %12 + %11 = OpLabel + OpStore %19 %9 + OpBranch %20 + %20 = OpLabel + OpSelectionMerge %22 None + OpBranchConditional %52 %24 %22 + %24 = OpLabel + %25 = OpLoad %6 %19 + %26 = OpSLessThan %17 %25 %16 + OpBranchConditional %26 %21 %22 + %21 = OpLabel + OpBranch %22 + %23 = OpLabel + %27 = OpLoad %6 %19 + %29 = OpIAdd %6 %27 %28 + OpStore %19 %29 + OpBranch %20 + %22 = OpLabel + OpBranch %12 + %13 = OpLabel + %30 = OpLoad %6 %8 + %31 = OpIAdd %6 %30 %28 + OpStore %8 %31 + OpBranch %10 + %12 = OpLabel + OpStore %32 %9 + OpBranch %33 + %33 = OpLabel + OpSelectionMerge %35 None + OpBranchConditional %52 %37 %35 + %37 = OpLabel + %38 = OpLoad %6 %32 + %39 = OpSLessThan %17 %38 %16 + OpBranchConditional %39 %34 %35 + %34 = OpLabel + OpStore %40 %9 + OpBranch %41 + %41 = OpLabel + OpLoopMerge %43 %44 None + OpBranch %45 + %45 = OpLabel + %46 = OpLoad %6 %40 + %47 = OpSLessThan %17 %46 %16 + OpBranchConditional %47 %42 %43 + %42 = OpLabel + OpBranch %44 + %44 = OpLabel + %48 = OpLoad %6 %40 + %49 = OpIAdd %6 %48 %28 + OpStore %40 %49 + OpBranch %41 + %43 = OpLabel + OpBranch %35 + %36 = OpLabel + %50 = OpLoad %6 %32 + %51 = OpIAdd %6 %50 %28 + OpStore %32 %51 + OpBranch %33 + %35 = OpLabel + OpReturn + OpFunctionEnd + )"; + CheckEqual(env, after_op_2, context.get()); + + ASSERT_TRUE(ops[3]->PreconditionHolds()); + ops[3]->TryToApply(); + CheckValid(env, context.get()); + std::string after_op_3 = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 0 + %16 = OpConstant %6 100 + %17 = OpTypeBool + %28 = OpConstant %6 1 + %52 = OpConstantTrue %17 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %19 = OpVariable %7 Function + %32 = OpVariable %7 Function + %40 = OpVariable %7 Function + OpStore %8 %9 + OpBranch %10 + %10 = OpLabel + OpSelectionMerge %12 None + OpBranchConditional %52 %14 %12 + %14 = OpLabel + %15 = OpLoad %6 %8 + %18 = OpSLessThan %17 %15 %16 + OpBranchConditional %18 %11 %12 + %11 = OpLabel + OpStore %19 %9 + OpBranch %20 + %20 = OpLabel + OpSelectionMerge %22 None + OpBranchConditional %52 %24 %22 + %24 = OpLabel + %25 = OpLoad %6 %19 + %26 = OpSLessThan %17 %25 %16 + OpBranchConditional %26 %21 %22 + %21 = OpLabel + OpBranch %22 + %23 = OpLabel + %27 = OpLoad %6 %19 + %29 = OpIAdd %6 %27 %28 + OpStore %19 %29 + OpBranch %20 + %22 = OpLabel + OpBranch %12 + %13 = OpLabel + %30 = OpLoad %6 %8 + %31 = OpIAdd %6 %30 %28 + OpStore %8 %31 + OpBranch %10 + %12 = OpLabel + OpStore %32 %9 + OpBranch %33 + %33 = OpLabel + OpSelectionMerge %35 None + OpBranchConditional %52 %37 %35 + %37 = OpLabel + %38 = OpLoad %6 %32 + %39 = OpSLessThan %17 %38 %16 + OpBranchConditional %39 %34 %35 + %34 = OpLabel + OpStore %40 %9 + OpBranch %41 + %41 = OpLabel + OpSelectionMerge %43 None + OpBranchConditional %52 %45 %43 + %45 = OpLabel + %46 = OpLoad %6 %40 + %47 = OpSLessThan %17 %46 %16 + OpBranchConditional %47 %42 %43 + %42 = OpLabel + OpBranch %43 + %44 = OpLabel + %48 = OpLoad %6 %40 + %49 = OpIAdd %6 %48 %28 + OpStore %40 %49 + OpBranch %41 + %43 = OpLabel + OpBranch %35 + %36 = OpLabel + %50 = OpLoad %6 %32 + %51 = OpIAdd %6 %50 %28 + OpStore %32 %51 + OpBranch %33 + %35 = OpLabel + OpReturn + OpFunctionEnd + )"; + CheckEqual(env, after_op_3, context.get()); +} + +TEST(StructuredLoopToSelectionReductionPassTest, LoopyShader3) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %9 = OpConstant %6 10 + %16 = OpConstant %6 0 + %17 = OpTypeBool + %20 = OpConstant %6 1 + %23 = OpConstant %6 3 + %40 = OpConstant %6 5 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + OpStore %8 %9 + OpBranch %10 + %10 = OpLabel + OpLoopMerge %12 %13 None + OpBranch %14 + %14 = OpLabel + %15 = OpLoad %6 %8 + %18 = OpSGreaterThan %17 %15 %16 + OpBranchConditional %18 %11 %12 + %11 = OpLabel + %19 = OpLoad %6 %8 + %21 = OpISub %6 %19 %20 + OpStore %8 %21 + %22 = OpLoad %6 %8 + %24 = OpSLessThan %17 %22 %23 + OpSelectionMerge %26 None + OpBranchConditional %24 %25 %26 + %25 = OpLabel + OpBranch %13 + %26 = OpLabel + OpBranch %28 + %28 = OpLabel + OpLoopMerge %30 %31 None + OpBranch %29 + %29 = OpLabel + %32 = OpLoad %6 %8 + %33 = OpISub %6 %32 %20 + OpStore %8 %33 + %34 = OpLoad %6 %8 + %35 = OpIEqual %17 %34 %20 + OpSelectionMerge %37 None + OpBranchConditional %35 %36 %37 + %36 = OpLabel + OpReturn ; This return spoils everything: it means the merge does not post-dominate the header. + %37 = OpLabel + OpBranch %31 + %31 = OpLabel + %39 = OpLoad %6 %8 + %41 = OpSGreaterThan %17 %39 %40 + OpBranchConditional %41 %28 %30 + %30 = OpLabel + OpBranch %13 + %13 = OpLabel + OpBranch %10 + %12 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); + const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() + .GetAvailableOpportunities(context.get()); + ASSERT_EQ(0, ops.size()); +} + +TEST(StructuredLoopToSelectionReductionPassTest, LoopyShader4) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %8 = OpTypeFunction %6 %7 + %13 = OpConstant %6 0 + %22 = OpTypeBool + %25 = OpConstant %6 1 + %39 = OpConstant %6 100 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %45 = OpVariable %7 Function + %46 = OpVariable %7 Function + %47 = OpVariable %7 Function + %32 = OpVariable %7 Function + %42 = OpVariable %7 Function + OpStore %32 %13 + OpBranch %33 + %33 = OpLabel + OpLoopMerge %35 %36 None + OpBranch %37 + %37 = OpLabel + %38 = OpLoad %6 %32 + %40 = OpSLessThan %22 %38 %39 + OpBranchConditional %40 %34 %35 + %34 = OpLabel + OpBranch %36 + %36 = OpLabel + %41 = OpLoad %6 %32 + OpStore %42 %25 + OpStore %45 %13 + OpStore %46 %13 + OpBranch %48 + %48 = OpLabel + OpLoopMerge %49 %50 None + OpBranch %51 + %51 = OpLabel + %52 = OpLoad %6 %46 + %53 = OpLoad %6 %42 + %54 = OpSLessThan %22 %52 %53 + OpBranchConditional %54 %55 %49 + %55 = OpLabel + %56 = OpLoad %6 %45 + %57 = OpIAdd %6 %56 %25 + OpStore %45 %57 + OpBranch %50 + %50 = OpLabel + %58 = OpLoad %6 %46 + %59 = OpIAdd %6 %58 %25 + OpStore %46 %59 + OpBranch %48 + %49 = OpLabel + %60 = OpLoad %6 %45 + OpStore %47 %60 + %43 = OpLoad %6 %47 + %44 = OpIAdd %6 %41 %43 + OpStore %32 %44 + OpBranch %33 + %35 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); + const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() + .GetAvailableOpportunities(context.get()); + + // Initially there are two opportunities. + ASSERT_EQ(2, ops.size()); + + ASSERT_TRUE(ops[0]->PreconditionHolds()); + ops[0]->TryToApply(); + CheckValid(env, context.get()); + std::string after_op_0 = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %8 = OpTypeFunction %6 %7 + %13 = OpConstant %6 0 + %22 = OpTypeBool + %25 = OpConstant %6 1 + %39 = OpConstant %6 100 + %61 = OpConstantTrue %22 + %62 = OpUndef %6 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %45 = OpVariable %7 Function + %46 = OpVariable %7 Function + %47 = OpVariable %7 Function + %32 = OpVariable %7 Function + %42 = OpVariable %7 Function + OpStore %32 %13 + OpBranch %33 + %33 = OpLabel + OpSelectionMerge %35 None + OpBranchConditional %61 %37 %35 + %37 = OpLabel + %38 = OpLoad %6 %32 + %40 = OpSLessThan %22 %38 %39 + OpBranchConditional %40 %34 %35 + %34 = OpLabel + OpBranch %35 + %36 = OpLabel + %41 = OpLoad %6 %32 + OpStore %42 %25 + OpStore %45 %13 + OpStore %46 %13 + OpBranch %48 + %48 = OpLabel + OpLoopMerge %49 %50 None + OpBranch %51 + %51 = OpLabel + %52 = OpLoad %6 %46 + %53 = OpLoad %6 %42 + %54 = OpSLessThan %22 %52 %53 + OpBranchConditional %54 %55 %49 + %55 = OpLabel + %56 = OpLoad %6 %45 + %57 = OpIAdd %6 %56 %25 + OpStore %45 %57 + OpBranch %50 + %50 = OpLabel + %58 = OpLoad %6 %46 + %59 = OpIAdd %6 %58 %25 + OpStore %46 %59 + OpBranch %48 + %49 = OpLabel + %60 = OpLoad %6 %45 + OpStore %47 %60 + %43 = OpLoad %6 %47 + %44 = OpIAdd %6 %62 %43 + OpStore %32 %44 + OpBranch %33 + %35 = OpLabel + OpReturn + OpFunctionEnd + )"; + CheckEqual(env, after_op_0, context.get()); + + // Applying the first opportunity has killed the second opportunity, because + // there was a loop embedded in the continue target of the loop we have just + // eliminated; the continue-embedded loop is now unreachable. + ASSERT_FALSE(ops[1]->PreconditionHolds()); +} + +TEST(StructuredLoopToSelectionReductionPassTest, ConditionalBreak1) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %10 = OpTypeBool + %11 = OpConstantFalse %10 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpBranch %6 + %6 = OpLabel + OpLoopMerge %8 %9 None + OpBranch %7 + %7 = OpLabel + OpSelectionMerge %13 None + OpBranchConditional %11 %12 %13 + %12 = OpLabel + OpBranch %8 + %13 = OpLabel + OpBranch %9 + %9 = OpLabel + OpBranchConditional %11 %6 %8 + %8 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); + const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() + .GetAvailableOpportunities(context.get()); + ASSERT_EQ(1, ops.size()); + + ASSERT_TRUE(ops[0]->PreconditionHolds()); + ops[0]->TryToApply(); + CheckValid(env, context.get()); + std::string after_op_0 = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %10 = OpTypeBool + %11 = OpConstantFalse %10 + %14 = OpConstantTrue %10 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpBranch %6 + %6 = OpLabel + OpSelectionMerge %8 None + OpBranchConditional %14 %7 %8 + %7 = OpLabel + OpSelectionMerge %13 None + OpBranchConditional %11 %12 %13 + %12 = OpLabel + OpBranch %13 + %13 = OpLabel + OpBranch %8 + %9 = OpLabel + OpBranchConditional %11 %6 %8 + %8 = OpLabel + OpReturn + OpFunctionEnd + )"; + CheckEqual(env, after_op_0, context.get()); +} + +TEST(StructuredLoopToSelectionReductionPassTest, ConditionalBreak2) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %10 = OpTypeBool + %11 = OpConstantFalse %10 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpBranch %6 + %6 = OpLabel + OpLoopMerge %8 %9 None + OpBranch %7 + %7 = OpLabel + OpSelectionMerge %13 None + OpBranchConditional %11 %8 %13 + %13 = OpLabel + OpBranch %9 + %9 = OpLabel + OpBranchConditional %11 %6 %8 + %8 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); + const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() + .GetAvailableOpportunities(context.get()); + ASSERT_EQ(1, ops.size()); + + ASSERT_TRUE(ops[0]->PreconditionHolds()); + ops[0]->TryToApply(); + CheckValid(env, context.get()); + std::string after_op_0 = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %10 = OpTypeBool + %11 = OpConstantFalse %10 + %14 = OpConstantTrue %10 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpBranch %6 + %6 = OpLabel + OpSelectionMerge %8 None + OpBranchConditional %14 %7 %8 + %7 = OpLabel + OpSelectionMerge %13 None + OpBranchConditional %11 %13 %13 + %13 = OpLabel + OpBranch %8 + %9 = OpLabel + OpBranchConditional %11 %6 %8 + %8 = OpLabel + OpReturn + OpFunctionEnd + )"; + CheckEqual(env, after_op_0, context.get()); +} + +TEST(StructuredLoopToSelectionReductionPassTest, UnconditionalBreak) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpBranch %6 + %6 = OpLabel + OpLoopMerge %8 %9 None + OpBranch %7 + %7 = OpLabel + OpBranch %8 + %9 = OpLabel + OpBranch %6 + %8 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); + const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() + .GetAvailableOpportunities(context.get()); + ASSERT_EQ(1, ops.size()); + + ASSERT_TRUE(ops[0]->PreconditionHolds()); + ops[0]->TryToApply(); + CheckValid(env, context.get()); + std::string after_op_0 = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %10 = OpTypeBool + %11 = OpConstantTrue %10 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpBranch %6 + %6 = OpLabel + OpSelectionMerge %8 None + OpBranchConditional %11 %7 %8 + %7 = OpLabel + OpBranch %8 + %9 = OpLabel + OpBranch %6 + %8 = OpLabel + OpReturn + OpFunctionEnd + )"; + CheckEqual(env, after_op_0, context.get()); +} + +TEST(StructuredLoopToSelectionReductionPassTest, Complex) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" %3 + OpExecutionMode %2 OriginUpperLeft + OpSource ESSL 310 + OpMemberDecorate %4 0 Offset 0 + OpMemberDecorate %4 1 Offset 4 + OpMemberDecorate %4 2 Offset 8 + OpMemberDecorate %4 3 Offset 12 + OpDecorate %4 Block + OpDecorate %5 DescriptorSet 0 + OpDecorate %5 Binding 0 + OpDecorate %3 Location 0 + %6 = OpTypeVoid + %7 = OpTypeFunction %6 + %8 = OpTypeBool + %9 = OpTypePointer Function %8 + %10 = OpTypeInt 32 1 + %4 = OpTypeStruct %10 %10 %10 %10 + %11 = OpTypePointer Uniform %4 + %5 = OpVariable %11 Uniform + %12 = OpConstant %10 0 + %13 = OpTypePointer Uniform %10 + %14 = OpTypeInt 32 0 + %15 = OpConstant %14 0 + %16 = OpConstant %10 1 + %17 = OpConstant %10 2 + %18 = OpConstant %10 3 + %19 = OpTypePointer Function %10 + %20 = OpConstantFalse %8 + %21 = OpTypeFloat 32 + %22 = OpTypeVector %21 4 + %23 = OpTypePointer Output %22 + %3 = OpVariable %23 Output + %2 = OpFunction %6 None %7 + %24 = OpLabel + %25 = OpVariable %9 Function + %26 = OpVariable %9 Function + %27 = OpVariable %9 Function + %28 = OpVariable %9 Function + %29 = OpVariable %9 Function + %30 = OpVariable %19 Function + %31 = OpAccessChain %13 %5 %12 + %32 = OpLoad %10 %31 + %33 = OpINotEqual %8 %32 %15 + OpStore %25 %33 + %34 = OpAccessChain %13 %5 %16 + %35 = OpLoad %10 %34 + %36 = OpINotEqual %8 %35 %15 + OpStore %26 %36 + %37 = OpAccessChain %13 %5 %17 + %38 = OpLoad %10 %37 + %39 = OpINotEqual %8 %38 %15 + OpStore %27 %39 + %40 = OpAccessChain %13 %5 %18 + %41 = OpLoad %10 %40 + %42 = OpINotEqual %8 %41 %15 + OpStore %28 %42 + %43 = OpLoad %8 %25 + OpStore %29 %43 + OpStore %30 %12 + OpBranch %44 + %44 = OpLabel + OpLoopMerge %45 %46 None + OpBranch %47 + %47 = OpLabel + %48 = OpLoad %8 %29 + OpBranchConditional %48 %49 %45 + %49 = OpLabel + %50 = OpLoad %8 %25 + OpSelectionMerge %51 None + OpBranchConditional %50 %52 %51 + %52 = OpLabel + %53 = OpLoad %8 %26 + OpStore %29 %53 + %54 = OpLoad %10 %30 + %55 = OpIAdd %10 %54 %16 + OpStore %30 %55 + OpBranch %51 + %51 = OpLabel + %56 = OpLoad %8 %26 + OpSelectionMerge %57 None + OpBranchConditional %56 %58 %57 + %58 = OpLabel + %59 = OpLoad %10 %30 + %60 = OpIAdd %10 %59 %16 + OpStore %30 %60 + %61 = OpLoad %8 %29 + %62 = OpLoad %8 %25 + %63 = OpLogicalOr %8 %61 %62 + OpStore %29 %63 + %64 = OpLoad %8 %27 + OpSelectionMerge %65 None + OpBranchConditional %64 %66 %65 + %66 = OpLabel + %67 = OpLoad %10 %30 + %68 = OpIAdd %10 %67 %17 + OpStore %30 %68 + %69 = OpLoad %8 %29 + %70 = OpLogicalNot %8 %69 + OpStore %29 %70 + OpBranch %46 + %65 = OpLabel + %71 = OpLoad %8 %29 + %72 = OpLogicalOr %8 %71 %20 + OpStore %29 %72 + OpBranch %46 + %57 = OpLabel + OpBranch %73 + %73 = OpLabel + OpLoopMerge %74 %75 None + OpBranch %76 + %76 = OpLabel + %77 = OpLoad %8 %28 + OpSelectionMerge %78 None + OpBranchConditional %77 %79 %80 + %79 = OpLabel + %81 = OpLoad %10 %30 + OpSelectionMerge %82 None + OpSwitch %81 %83 1 %84 2 %85 + %83 = OpLabel + OpBranch %82 + %84 = OpLabel + %86 = OpLoad %8 %29 + %87 = OpSelect %10 %86 %16 %17 + %88 = OpLoad %10 %30 + %89 = OpIAdd %10 %88 %87 + OpStore %30 %89 + OpBranch %82 + %85 = OpLabel + OpBranch %75 + %82 = OpLabel + %90 = OpLoad %8 %27 + OpSelectionMerge %91 None + OpBranchConditional %90 %92 %91 + %92 = OpLabel + OpBranch %75 + %91 = OpLabel + OpBranch %78 + %80 = OpLabel + OpBranch %74 + %78 = OpLabel + OpBranch %75 + %75 = OpLabel + %93 = OpLoad %8 %29 + OpBranchConditional %93 %73 %74 + %74 = OpLabel + OpBranch %46 + %46 = OpLabel + OpBranch %44 + %45 = OpLabel + %94 = OpLoad %10 %30 + %95 = OpConvertSToF %21 %94 + %96 = OpCompositeConstruct %22 %95 %95 %95 %95 + OpStore %3 %96 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); + const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() + .GetAvailableOpportunities(context.get()); + + ASSERT_EQ(2, ops.size()); + ASSERT_TRUE(ops[0]->PreconditionHolds()); + ops[0]->TryToApply(); + CheckValid(env, context.get()); + std::string after_op_0 = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" %3 + OpExecutionMode %2 OriginUpperLeft + OpSource ESSL 310 + OpMemberDecorate %4 0 Offset 0 + OpMemberDecorate %4 1 Offset 4 + OpMemberDecorate %4 2 Offset 8 + OpMemberDecorate %4 3 Offset 12 + OpDecorate %4 Block + OpDecorate %5 DescriptorSet 0 + OpDecorate %5 Binding 0 + OpDecorate %3 Location 0 + %6 = OpTypeVoid + %7 = OpTypeFunction %6 + %8 = OpTypeBool + %9 = OpTypePointer Function %8 + %10 = OpTypeInt 32 1 + %4 = OpTypeStruct %10 %10 %10 %10 + %11 = OpTypePointer Uniform %4 + %5 = OpVariable %11 Uniform + %12 = OpConstant %10 0 + %13 = OpTypePointer Uniform %10 + %14 = OpTypeInt 32 0 + %15 = OpConstant %14 0 + %16 = OpConstant %10 1 + %17 = OpConstant %10 2 + %18 = OpConstant %10 3 + %19 = OpTypePointer Function %10 + %20 = OpConstantFalse %8 + %21 = OpTypeFloat 32 + %22 = OpTypeVector %21 4 + %23 = OpTypePointer Output %22 + %3 = OpVariable %23 Output + %97 = OpConstantTrue %8 + %2 = OpFunction %6 None %7 + %24 = OpLabel + %25 = OpVariable %9 Function + %26 = OpVariable %9 Function + %27 = OpVariable %9 Function + %28 = OpVariable %9 Function + %29 = OpVariable %9 Function + %30 = OpVariable %19 Function + %31 = OpAccessChain %13 %5 %12 + %32 = OpLoad %10 %31 + %33 = OpINotEqual %8 %32 %15 + OpStore %25 %33 + %34 = OpAccessChain %13 %5 %16 + %35 = OpLoad %10 %34 + %36 = OpINotEqual %8 %35 %15 + OpStore %26 %36 + %37 = OpAccessChain %13 %5 %17 + %38 = OpLoad %10 %37 + %39 = OpINotEqual %8 %38 %15 + OpStore %27 %39 + %40 = OpAccessChain %13 %5 %18 + %41 = OpLoad %10 %40 + %42 = OpINotEqual %8 %41 %15 + OpStore %28 %42 + %43 = OpLoad %8 %25 + OpStore %29 %43 + OpStore %30 %12 + OpBranch %44 + %44 = OpLabel + OpSelectionMerge %45 None ; Was OpLoopMerge %45 %46 None + OpBranchConditional %97 %47 %45 ; Was OpBranch %47 + %47 = OpLabel + %48 = OpLoad %8 %29 + OpBranchConditional %48 %49 %45 + %49 = OpLabel + %50 = OpLoad %8 %25 + OpSelectionMerge %51 None + OpBranchConditional %50 %52 %51 + %52 = OpLabel + %53 = OpLoad %8 %26 + OpStore %29 %53 + %54 = OpLoad %10 %30 + %55 = OpIAdd %10 %54 %16 + OpStore %30 %55 + OpBranch %51 + %51 = OpLabel + %56 = OpLoad %8 %26 + OpSelectionMerge %57 None + OpBranchConditional %56 %58 %57 + %58 = OpLabel + %59 = OpLoad %10 %30 + %60 = OpIAdd %10 %59 %16 + OpStore %30 %60 + %61 = OpLoad %8 %29 + %62 = OpLoad %8 %25 + %63 = OpLogicalOr %8 %61 %62 + OpStore %29 %63 + %64 = OpLoad %8 %27 + OpSelectionMerge %65 None + OpBranchConditional %64 %66 %65 + %66 = OpLabel + %67 = OpLoad %10 %30 + %68 = OpIAdd %10 %67 %17 + OpStore %30 %68 + %69 = OpLoad %8 %29 + %70 = OpLogicalNot %8 %69 + OpStore %29 %70 + OpBranch %65 ; Was OpBranch %46 + %65 = OpLabel + %71 = OpLoad %8 %29 + %72 = OpLogicalOr %8 %71 %20 + OpStore %29 %72 + OpBranch %57 ; Was OpBranch %46 + %57 = OpLabel + OpBranch %73 + %73 = OpLabel + OpLoopMerge %74 %75 None + OpBranch %76 + %76 = OpLabel + %77 = OpLoad %8 %28 + OpSelectionMerge %78 None + OpBranchConditional %77 %79 %80 + %79 = OpLabel + %81 = OpLoad %10 %30 + OpSelectionMerge %82 None + OpSwitch %81 %83 1 %84 2 %85 + %83 = OpLabel + OpBranch %82 + %84 = OpLabel + %86 = OpLoad %8 %29 + %87 = OpSelect %10 %86 %16 %17 + %88 = OpLoad %10 %30 + %89 = OpIAdd %10 %88 %87 + OpStore %30 %89 + OpBranch %82 + %85 = OpLabel + OpBranch %75 + %82 = OpLabel + %90 = OpLoad %8 %27 + OpSelectionMerge %91 None + OpBranchConditional %90 %92 %91 + %92 = OpLabel + OpBranch %75 + %91 = OpLabel + OpBranch %78 + %80 = OpLabel + OpBranch %74 + %78 = OpLabel + OpBranch %75 + %75 = OpLabel + %93 = OpLoad %8 %29 + OpBranchConditional %93 %73 %74 + %74 = OpLabel + OpBranch %45 ; Was OpBranch %46 + %46 = OpLabel + OpBranch %44 + %45 = OpLabel + %94 = OpLoad %10 %30 + %95 = OpConvertSToF %21 %94 + %96 = OpCompositeConstruct %22 %95 %95 %95 %95 + OpStore %3 %96 + OpReturn + OpFunctionEnd + )"; + CheckEqual(env, after_op_0, context.get()); + ASSERT_TRUE(ops[1]->PreconditionHolds()); + ops[1]->TryToApply(); + CheckValid(env, context.get()); + + std::string after_op_1 = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" %3 + OpExecutionMode %2 OriginUpperLeft + OpSource ESSL 310 + OpMemberDecorate %4 0 Offset 0 + OpMemberDecorate %4 1 Offset 4 + OpMemberDecorate %4 2 Offset 8 + OpMemberDecorate %4 3 Offset 12 + OpDecorate %4 Block + OpDecorate %5 DescriptorSet 0 + OpDecorate %5 Binding 0 + OpDecorate %3 Location 0 + %6 = OpTypeVoid + %7 = OpTypeFunction %6 + %8 = OpTypeBool + %9 = OpTypePointer Function %8 + %10 = OpTypeInt 32 1 + %4 = OpTypeStruct %10 %10 %10 %10 + %11 = OpTypePointer Uniform %4 + %5 = OpVariable %11 Uniform + %12 = OpConstant %10 0 + %13 = OpTypePointer Uniform %10 + %14 = OpTypeInt 32 0 + %15 = OpConstant %14 0 + %16 = OpConstant %10 1 + %17 = OpConstant %10 2 + %18 = OpConstant %10 3 + %19 = OpTypePointer Function %10 + %20 = OpConstantFalse %8 + %21 = OpTypeFloat 32 + %22 = OpTypeVector %21 4 + %23 = OpTypePointer Output %22 + %3 = OpVariable %23 Output + %97 = OpConstantTrue %8 + %2 = OpFunction %6 None %7 + %24 = OpLabel + %25 = OpVariable %9 Function + %26 = OpVariable %9 Function + %27 = OpVariable %9 Function + %28 = OpVariable %9 Function + %29 = OpVariable %9 Function + %30 = OpVariable %19 Function + %31 = OpAccessChain %13 %5 %12 + %32 = OpLoad %10 %31 + %33 = OpINotEqual %8 %32 %15 + OpStore %25 %33 + %34 = OpAccessChain %13 %5 %16 + %35 = OpLoad %10 %34 + %36 = OpINotEqual %8 %35 %15 + OpStore %26 %36 + %37 = OpAccessChain %13 %5 %17 + %38 = OpLoad %10 %37 + %39 = OpINotEqual %8 %38 %15 + OpStore %27 %39 + %40 = OpAccessChain %13 %5 %18 + %41 = OpLoad %10 %40 + %42 = OpINotEqual %8 %41 %15 + OpStore %28 %42 + %43 = OpLoad %8 %25 + OpStore %29 %43 + OpStore %30 %12 + OpBranch %44 + %44 = OpLabel + OpSelectionMerge %45 None ; Was OpLoopMerge %45 %46 None + OpBranchConditional %97 %47 %45 ; Was OpBranch %47 + %47 = OpLabel + %48 = OpLoad %8 %29 + OpBranchConditional %48 %49 %45 + %49 = OpLabel + %50 = OpLoad %8 %25 + OpSelectionMerge %51 None + OpBranchConditional %50 %52 %51 + %52 = OpLabel + %53 = OpLoad %8 %26 + OpStore %29 %53 + %54 = OpLoad %10 %30 + %55 = OpIAdd %10 %54 %16 + OpStore %30 %55 + OpBranch %51 + %51 = OpLabel + %56 = OpLoad %8 %26 + OpSelectionMerge %57 None + OpBranchConditional %56 %58 %57 + %58 = OpLabel + %59 = OpLoad %10 %30 + %60 = OpIAdd %10 %59 %16 + OpStore %30 %60 + %61 = OpLoad %8 %29 + %62 = OpLoad %8 %25 + %63 = OpLogicalOr %8 %61 %62 + OpStore %29 %63 + %64 = OpLoad %8 %27 + OpSelectionMerge %65 None + OpBranchConditional %64 %66 %65 + %66 = OpLabel + %67 = OpLoad %10 %30 + %68 = OpIAdd %10 %67 %17 + OpStore %30 %68 + %69 = OpLoad %8 %29 + %70 = OpLogicalNot %8 %69 + OpStore %29 %70 + OpBranch %65 ; Was OpBranch %46 + %65 = OpLabel + %71 = OpLoad %8 %29 + %72 = OpLogicalOr %8 %71 %20 + OpStore %29 %72 + OpBranch %57 ; Was OpBranch %46 + %57 = OpLabel + OpBranch %73 + %73 = OpLabel + OpSelectionMerge %74 None ; Was OpLoopMerge %74 %75 None + OpBranchConditional %97 %76 %74 ; Was OpBranch %76 + %76 = OpLabel + %77 = OpLoad %8 %28 + OpSelectionMerge %78 None + OpBranchConditional %77 %79 %80 + %79 = OpLabel + %81 = OpLoad %10 %30 + OpSelectionMerge %82 None + OpSwitch %81 %83 1 %84 2 %85 + %83 = OpLabel + OpBranch %82 + %84 = OpLabel + %86 = OpLoad %8 %29 + %87 = OpSelect %10 %86 %16 %17 + %88 = OpLoad %10 %30 + %89 = OpIAdd %10 %88 %87 + OpStore %30 %89 + OpBranch %82 + %85 = OpLabel + OpBranch %82 + %82 = OpLabel + %90 = OpLoad %8 %27 + OpSelectionMerge %91 None + OpBranchConditional %90 %92 %91 + %92 = OpLabel + OpBranch %91 + %91 = OpLabel + OpBranch %78 + %80 = OpLabel + OpBranch %78 ; Was OpBranch %74 + %78 = OpLabel + OpBranch %74 + %75 = OpLabel + %93 = OpLoad %8 %29 + OpBranchConditional %93 %73 %74 + %74 = OpLabel + OpBranch %45 ; Was OpBranch %46 + %46 = OpLabel + OpBranch %44 + %45 = OpLabel + %94 = OpLoad %10 %30 + %95 = OpConvertSToF %21 %94 + %96 = OpCompositeConstruct %22 %95 %95 %95 %95 + OpStore %3 %96 + OpReturn + OpFunctionEnd + )"; + CheckEqual(env, after_op_1, context.get()); +} + +TEST(StructuredLoopToSelectionReductionPassTest, ComplexOptimized) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" %3 + OpExecutionMode %2 OriginUpperLeft + OpSource ESSL 310 + OpMemberDecorate %4 0 Offset 0 + OpMemberDecorate %4 1 Offset 4 + OpMemberDecorate %4 2 Offset 8 + OpMemberDecorate %4 3 Offset 12 + OpDecorate %4 Block + OpDecorate %5 DescriptorSet 0 + OpDecorate %5 Binding 0 + OpDecorate %3 Location 0 + %6 = OpTypeVoid + %7 = OpTypeFunction %6 + %8 = OpTypeBool + %10 = OpTypeInt 32 1 + %4 = OpTypeStruct %10 %10 %10 %10 + %11 = OpTypePointer Uniform %4 + %5 = OpVariable %11 Uniform + %12 = OpConstant %10 0 + %13 = OpTypePointer Uniform %10 + %14 = OpTypeInt 32 0 + %15 = OpConstant %14 0 + %16 = OpConstant %10 1 + %17 = OpConstant %10 2 + %18 = OpConstant %10 3 + %20 = OpConstantFalse %8 + %21 = OpTypeFloat 32 + %22 = OpTypeVector %21 4 + %23 = OpTypePointer Output %22 + %3 = OpVariable %23 Output + %2 = OpFunction %6 None %7 + %24 = OpLabel + %31 = OpAccessChain %13 %5 %12 + %32 = OpLoad %10 %31 + %33 = OpINotEqual %8 %32 %15 + %34 = OpAccessChain %13 %5 %16 + %35 = OpLoad %10 %34 + %36 = OpINotEqual %8 %35 %15 + %37 = OpAccessChain %13 %5 %17 + %38 = OpLoad %10 %37 + %39 = OpINotEqual %8 %38 %15 + %40 = OpAccessChain %13 %5 %18 + %41 = OpLoad %10 %40 + %42 = OpINotEqual %8 %41 %15 + OpBranch %44 + %44 = OpLabel + %98 = OpPhi %10 %12 %24 %107 %46 + %97 = OpPhi %8 %33 %24 %105 %46 + OpLoopMerge %45 %46 None + OpBranchConditional %97 %49 %45 + %49 = OpLabel + OpSelectionMerge %51 None + OpBranchConditional %33 %52 %51 + %52 = OpLabel + %55 = OpIAdd %10 %98 %16 + OpBranch %51 + %51 = OpLabel + %100 = OpPhi %10 %98 %49 %55 %52 + %113 = OpSelect %8 %33 %36 %97 + OpSelectionMerge %57 None + OpBranchConditional %36 %58 %57 + %58 = OpLabel + %60 = OpIAdd %10 %100 %16 + %63 = OpLogicalOr %8 %113 %33 + OpSelectionMerge %65 None + OpBranchConditional %39 %66 %65 + %66 = OpLabel + %68 = OpIAdd %10 %100 %18 + %70 = OpLogicalNot %8 %63 + OpBranch %46 + %65 = OpLabel + %72 = OpLogicalOr %8 %63 %20 + OpBranch %46 + %57 = OpLabel + OpBranch %73 + %73 = OpLabel + %99 = OpPhi %10 %100 %57 %109 %75 + OpLoopMerge %74 %75 None + OpBranch %76 + %76 = OpLabel + OpSelectionMerge %78 None + OpBranchConditional %42 %79 %80 + %79 = OpLabel + OpSelectionMerge %82 None + OpSwitch %99 %83 1 %84 2 %85 + %83 = OpLabel + OpBranch %82 + %84 = OpLabel + %87 = OpSelect %10 %113 %16 %17 + %89 = OpIAdd %10 %99 %87 + OpBranch %82 + %85 = OpLabel + OpBranch %75 + %82 = OpLabel + %110 = OpPhi %10 %99 %83 %89 %84 + OpSelectionMerge %91 None + OpBranchConditional %39 %92 %91 + %92 = OpLabel + OpBranch %75 + %91 = OpLabel + OpBranch %78 + %80 = OpLabel + OpBranch %74 + %78 = OpLabel + OpBranch %75 + %75 = OpLabel + %109 = OpPhi %10 %99 %85 %110 %92 %110 %78 + OpBranchConditional %113 %73 %74 + %74 = OpLabel + %108 = OpPhi %10 %99 %80 %109 %75 + OpBranch %46 + %46 = OpLabel + %107 = OpPhi %10 %68 %66 %60 %65 %108 %74 + %105 = OpPhi %8 %70 %66 %72 %65 %113 %74 + OpBranch %44 + %45 = OpLabel + %95 = OpConvertSToF %21 %98 + %96 = OpCompositeConstruct %22 %95 %95 %95 %95 + OpStore %3 %96 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); + const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() + .GetAvailableOpportunities(context.get()); + + ASSERT_EQ(2, ops.size()); + ASSERT_TRUE(ops[0]->PreconditionHolds()); + ops[0]->TryToApply(); + CheckValid(env, context.get()); + std::string after_op_0 = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" %3 + OpExecutionMode %2 OriginUpperLeft + OpSource ESSL 310 + OpMemberDecorate %4 0 Offset 0 + OpMemberDecorate %4 1 Offset 4 + OpMemberDecorate %4 2 Offset 8 + OpMemberDecorate %4 3 Offset 12 + OpDecorate %4 Block + OpDecorate %5 DescriptorSet 0 + OpDecorate %5 Binding 0 + OpDecorate %3 Location 0 + %6 = OpTypeVoid + %7 = OpTypeFunction %6 + %8 = OpTypeBool + %10 = OpTypeInt 32 1 + %4 = OpTypeStruct %10 %10 %10 %10 + %11 = OpTypePointer Uniform %4 + %5 = OpVariable %11 Uniform + %12 = OpConstant %10 0 + %13 = OpTypePointer Uniform %10 + %14 = OpTypeInt 32 0 + %15 = OpConstant %14 0 + %16 = OpConstant %10 1 + %17 = OpConstant %10 2 + %18 = OpConstant %10 3 + %20 = OpConstantFalse %8 + %21 = OpTypeFloat 32 + %22 = OpTypeVector %21 4 + %23 = OpTypePointer Output %22 + %3 = OpVariable %23 Output + %114 = OpUndef %10 + %115 = OpUndef %8 + %2 = OpFunction %6 None %7 + %24 = OpLabel + %31 = OpAccessChain %13 %5 %12 + %32 = OpLoad %10 %31 + %33 = OpINotEqual %8 %32 %15 + %34 = OpAccessChain %13 %5 %16 + %35 = OpLoad %10 %34 + %36 = OpINotEqual %8 %35 %15 + %37 = OpAccessChain %13 %5 %17 + %38 = OpLoad %10 %37 + %39 = OpINotEqual %8 %38 %15 + %40 = OpAccessChain %13 %5 %18 + %41 = OpLoad %10 %40 + %42 = OpINotEqual %8 %41 %15 + OpBranch %44 + %44 = OpLabel + %98 = OpPhi %10 %12 %24 %114 %46 + %97 = OpPhi %8 %33 %24 %115 %46 + OpSelectionMerge %45 None ; Was OpLoopMerge %45 %46 None + OpBranchConditional %97 %49 %45 + %49 = OpLabel + OpSelectionMerge %51 None + OpBranchConditional %33 %52 %51 + %52 = OpLabel + %55 = OpIAdd %10 %98 %16 + OpBranch %51 + %51 = OpLabel + %100 = OpPhi %10 %98 %49 %55 %52 + %113 = OpSelect %8 %33 %36 %97 + OpSelectionMerge %57 None + OpBranchConditional %36 %58 %57 + %58 = OpLabel + %60 = OpIAdd %10 %100 %16 + %63 = OpLogicalOr %8 %113 %33 + OpSelectionMerge %65 None + OpBranchConditional %39 %66 %65 + %66 = OpLabel + %68 = OpIAdd %10 %100 %18 + %70 = OpLogicalNot %8 %63 + OpBranch %65 ; Was OpBranch %46 + %65 = OpLabel + %72 = OpLogicalOr %8 %63 %20 + OpBranch %57 ; Was OpBranch %46 + %57 = OpLabel + OpBranch %73 + %73 = OpLabel + %99 = OpPhi %10 %100 %57 %109 %75 + OpLoopMerge %74 %75 None + OpBranch %76 + %76 = OpLabel + OpSelectionMerge %78 None + OpBranchConditional %42 %79 %80 + %79 = OpLabel + OpSelectionMerge %82 None + OpSwitch %99 %83 1 %84 2 %85 + %83 = OpLabel + OpBranch %82 + %84 = OpLabel + %87 = OpSelect %10 %113 %16 %17 + %89 = OpIAdd %10 %99 %87 + OpBranch %82 + %85 = OpLabel + OpBranch %75 + %82 = OpLabel + %110 = OpPhi %10 %99 %83 %89 %84 + OpSelectionMerge %91 None + OpBranchConditional %39 %92 %91 + %92 = OpLabel + OpBranch %75 + %91 = OpLabel + OpBranch %78 + %80 = OpLabel + OpBranch %74 + %78 = OpLabel + OpBranch %75 + %75 = OpLabel + %109 = OpPhi %10 %99 %85 %110 %92 %110 %78 + OpBranchConditional %113 %73 %74 + %74 = OpLabel + %108 = OpPhi %10 %99 %80 %109 %75 + OpBranch %45 ; Was OpBranch %46 + %46 = OpLabel + %107 = OpPhi %10 ; Was OpPhi %10 %68 %66 %60 %65 %108 %74 + %105 = OpPhi %8 ; Was OpPhi %8 %70 %66 %72 %65 %113 %74 + OpBranch %44 + %45 = OpLabel + %95 = OpConvertSToF %21 %98 + %96 = OpCompositeConstruct %22 %95 %95 %95 %95 + OpStore %3 %96 + OpReturn + OpFunctionEnd + )"; + CheckEqual(env, after_op_0, context.get()); + + ASSERT_TRUE(ops[1]->PreconditionHolds()); + ops[1]->TryToApply(); + CheckValid(env, context.get()); + std::string after_op_1 = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" %3 + OpExecutionMode %2 OriginUpperLeft + OpSource ESSL 310 + OpMemberDecorate %4 0 Offset 0 + OpMemberDecorate %4 1 Offset 4 + OpMemberDecorate %4 2 Offset 8 + OpMemberDecorate %4 3 Offset 12 + OpDecorate %4 Block + OpDecorate %5 DescriptorSet 0 + OpDecorate %5 Binding 0 + OpDecorate %3 Location 0 + %6 = OpTypeVoid + %7 = OpTypeFunction %6 + %8 = OpTypeBool + %10 = OpTypeInt 32 1 + %4 = OpTypeStruct %10 %10 %10 %10 + %11 = OpTypePointer Uniform %4 + %5 = OpVariable %11 Uniform + %12 = OpConstant %10 0 + %13 = OpTypePointer Uniform %10 + %14 = OpTypeInt 32 0 + %15 = OpConstant %14 0 + %16 = OpConstant %10 1 + %17 = OpConstant %10 2 + %18 = OpConstant %10 3 + %20 = OpConstantFalse %8 + %21 = OpTypeFloat 32 + %22 = OpTypeVector %21 4 + %23 = OpTypePointer Output %22 + %3 = OpVariable %23 Output + %114 = OpUndef %10 + %115 = OpUndef %8 + %116 = OpConstantTrue %8 + %2 = OpFunction %6 None %7 + %24 = OpLabel + %31 = OpAccessChain %13 %5 %12 + %32 = OpLoad %10 %31 + %33 = OpINotEqual %8 %32 %15 + %34 = OpAccessChain %13 %5 %16 + %35 = OpLoad %10 %34 + %36 = OpINotEqual %8 %35 %15 + %37 = OpAccessChain %13 %5 %17 + %38 = OpLoad %10 %37 + %39 = OpINotEqual %8 %38 %15 + %40 = OpAccessChain %13 %5 %18 + %41 = OpLoad %10 %40 + %42 = OpINotEqual %8 %41 %15 + OpBranch %44 + %44 = OpLabel + %98 = OpPhi %10 %12 %24 %114 %46 + %97 = OpPhi %8 %33 %24 %115 %46 + OpSelectionMerge %45 None ; Was OpLoopMerge %45 %46 None + OpBranchConditional %97 %49 %45 + %49 = OpLabel + OpSelectionMerge %51 None + OpBranchConditional %33 %52 %51 + %52 = OpLabel + %55 = OpIAdd %10 %98 %16 + OpBranch %51 + %51 = OpLabel + %100 = OpPhi %10 %98 %49 %55 %52 + %113 = OpSelect %8 %33 %36 %97 + OpSelectionMerge %57 None + OpBranchConditional %36 %58 %57 + %58 = OpLabel + %60 = OpIAdd %10 %100 %16 + %63 = OpLogicalOr %8 %113 %33 + OpSelectionMerge %65 None + OpBranchConditional %39 %66 %65 + %66 = OpLabel + %68 = OpIAdd %10 %100 %18 + %70 = OpLogicalNot %8 %63 + OpBranch %65 ; Was OpBranch %46 + %65 = OpLabel + %72 = OpLogicalOr %8 %63 %20 + OpBranch %57 ; Was OpBranch %46 + %57 = OpLabel + OpBranch %73 + %73 = OpLabel + %99 = OpPhi %10 %100 %57 %114 %75 + OpSelectionMerge %74 None ; Was OpLoopMerge %74 %75 None + OpBranchConditional %116 %76 %74 + %76 = OpLabel + OpSelectionMerge %78 None + OpBranchConditional %42 %79 %80 + %79 = OpLabel + OpSelectionMerge %82 None + OpSwitch %99 %83 1 %84 2 %85 + %83 = OpLabel + OpBranch %82 + %84 = OpLabel + %87 = OpSelect %10 %113 %16 %17 + %89 = OpIAdd %10 %99 %87 + OpBranch %82 + %85 = OpLabel + OpBranch %82 ; Was OpBranch %75 + %82 = OpLabel + %110 = OpPhi %10 %99 %83 %89 %84 %114 %85 ; Was OpPhi %10 %99 %83 %89 %84 + OpSelectionMerge %91 None + OpBranchConditional %39 %92 %91 + %92 = OpLabel + OpBranch %91 ; OpBranch %75 + %91 = OpLabel + OpBranch %78 + %80 = OpLabel + OpBranch %78 ; Was OpBranch %74 + %78 = OpLabel + OpBranch %74 ; Was OpBranch %75 + %75 = OpLabel + %109 = OpPhi %10 ; Was OpPhi %10 %99 %85 %110 %92 %110 %78 + OpBranchConditional %115 %73 %74 + %74 = OpLabel + %108 = OpPhi %10 %114 %75 %114 %78 %114 %73 ; Was OpPhi %10 %99 %80 %109 %75 + OpBranch %45 ; Was OpBranch %46 + %46 = OpLabel + %107 = OpPhi %10 ; Was OpPhi %10 %68 %66 %60 %65 %108 %74 + %105 = OpPhi %8 ; Was OpPhi %8 %70 %66 %72 %65 %113 %74 + OpBranch %44 + %45 = OpLabel + %95 = OpConvertSToF %21 %98 + %96 = OpCompositeConstruct %22 %95 %95 %95 %95 + OpStore %3 %96 + OpReturn + OpFunctionEnd + )"; + CheckEqual(env, after_op_1, context.get()); +} + +TEST(StructuredLoopToSelectionReductionPassTest, DominanceIssue) { + // Exposes a scenario where redirecting edges results in uses of ids being + // non-dominated. We replace such uses with OpUndef to account for this. + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %5 = OpTypeInt 32 1 + %7 = OpTypePointer Function %5 + %6 = OpTypeBool + %8 = OpConstantTrue %6 + %9 = OpConstant %5 10 + %10 = OpConstant %5 20 + %11 = OpConstant %5 30 + %4 = OpFunction %2 None %3 + %12 = OpLabel + OpBranch %13 + %13 = OpLabel + OpLoopMerge %14 %15 None + OpBranch %16 + %16 = OpLabel + OpSelectionMerge %17 None + OpBranchConditional %8 %18 %19 + %18 = OpLabel + OpBranch %14 + %19 = OpLabel + %20 = OpIAdd %5 %9 %10 + OpBranch %17 + %17 = OpLabel + %21 = OpIAdd %5 %20 %11 + OpBranchConditional %8 %14 %15 + %15 = OpLabel + OpBranch %13 + %14 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); + const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() + .GetAvailableOpportunities(context.get()); + ASSERT_EQ(1, ops.size()); + + ASSERT_TRUE(ops[0]->PreconditionHolds()); + ops[0]->TryToApply(); + CheckValid(env, context.get()); + + std::string expected = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %5 = OpTypeInt 32 1 + %7 = OpTypePointer Function %5 + %6 = OpTypeBool + %8 = OpConstantTrue %6 + %9 = OpConstant %5 10 + %10 = OpConstant %5 20 + %11 = OpConstant %5 30 + %22 = OpUndef %5 + %4 = OpFunction %2 None %3 + %12 = OpLabel + OpBranch %13 + %13 = OpLabel + OpSelectionMerge %14 None + OpBranchConditional %8 %16 %14 + %16 = OpLabel + OpSelectionMerge %17 None + OpBranchConditional %8 %18 %19 + %18 = OpLabel + OpBranch %17 + %19 = OpLabel + %20 = OpIAdd %5 %9 %10 + OpBranch %17 + %17 = OpLabel + %21 = OpIAdd %5 %22 %11 + OpBranchConditional %8 %14 %14 + %15 = OpLabel + OpBranch %13 + %14 = OpLabel + OpReturn + OpFunctionEnd + )"; + CheckEqual(env, expected, context.get()); +} + +TEST(StructuredLoopToSelectionReductionPassTest, AccessChainIssue) { + // Exposes a scenario where redirecting edges results in a use of an id + // generated by an access chain being non-dominated. + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" %56 + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpMemberDecorate %28 0 Offset 0 + OpDecorate %28 Block + OpDecorate %30 DescriptorSet 0 + OpDecorate %30 Binding 0 + OpDecorate %56 Location 0 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypeVector %6 2 + %8 = OpTypePointer Function %7 + %60 = OpTypePointer Private %7 + %10 = OpConstant %6 0 + %11 = OpConstantComposite %7 %10 %10 + %12 = OpTypePointer Function %6 + %59 = OpTypePointer Private %6 + %14 = OpTypeInt 32 1 + %15 = OpTypePointer Function %14 + %17 = OpConstant %14 0 + %24 = OpConstant %14 100 + %25 = OpTypeBool + %28 = OpTypeStruct %6 + %29 = OpTypePointer Uniform %28 + %30 = OpVariable %29 Uniform + %31 = OpTypePointer Uniform %6 + %39 = OpTypeInt 32 0 + %40 = OpConstant %39 1 + %45 = OpConstant %39 0 + %52 = OpConstant %14 1 + %54 = OpTypeVector %6 4 + %55 = OpTypePointer Output %54 + %56 = OpVariable %55 Output + %9 = OpVariable %60 Private + %4 = OpFunction %2 None %3 + %5 = OpLabel + %13 = OpVariable %12 Function + %16 = OpVariable %15 Function + %38 = OpVariable %12 Function + OpStore %9 %11 + OpStore %13 %10 + OpStore %16 %17 + OpBranch %18 + %18 = OpLabel + OpLoopMerge %20 %21 None + OpBranch %22 + %22 = OpLabel + %23 = OpLoad %14 %16 + %26 = OpSLessThan %25 %23 %24 + OpBranchConditional %26 %19 %20 + %19 = OpLabel + %27 = OpLoad %14 %16 + %32 = OpAccessChain %31 %30 %17 + %33 = OpLoad %6 %32 + %34 = OpConvertFToS %14 %33 + %35 = OpSLessThan %25 %27 %34 + OpSelectionMerge %37 None + OpBranchConditional %35 %36 %44 + %36 = OpLabel + %41 = OpAccessChain %59 %9 %40 + %42 = OpLoad %6 %41 + OpStore %38 %42 + OpBranch %20 + %44 = OpLabel + %46 = OpAccessChain %59 %9 %45 + OpBranch %37 + %37 = OpLabel + %47 = OpLoad %6 %46 + OpStore %38 %47 + %48 = OpLoad %6 %38 + %49 = OpLoad %6 %13 + %50 = OpFAdd %6 %49 %48 + OpStore %13 %50 + OpBranch %21 + %21 = OpLabel + %51 = OpLoad %14 %16 + %53 = OpIAdd %14 %51 %52 + OpStore %16 %53 + OpBranch %18 + %20 = OpLabel + %57 = OpLoad %6 %13 + %58 = OpCompositeConstruct %54 %57 %57 %57 %57 + OpStore %56 %58 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); + const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() + .GetAvailableOpportunities(context.get()); + ASSERT_EQ(1, ops.size()); + + ASSERT_TRUE(ops[0]->PreconditionHolds()); + ops[0]->TryToApply(); + CheckValid(env, context.get()); + + std::string expected = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" %56 + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpMemberDecorate %28 0 Offset 0 + OpDecorate %28 Block + OpDecorate %30 DescriptorSet 0 + OpDecorate %30 Binding 0 + OpDecorate %56 Location 0 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypeVector %6 2 + %8 = OpTypePointer Function %7 + %60 = OpTypePointer Private %7 + %10 = OpConstant %6 0 + %11 = OpConstantComposite %7 %10 %10 + %12 = OpTypePointer Function %6 + %59 = OpTypePointer Private %6 + %14 = OpTypeInt 32 1 + %15 = OpTypePointer Function %14 + %17 = OpConstant %14 0 + %24 = OpConstant %14 100 + %25 = OpTypeBool + %28 = OpTypeStruct %6 + %29 = OpTypePointer Uniform %28 + %30 = OpVariable %29 Uniform + %31 = OpTypePointer Uniform %6 + %39 = OpTypeInt 32 0 + %40 = OpConstant %39 1 + %45 = OpConstant %39 0 + %52 = OpConstant %14 1 + %54 = OpTypeVector %6 4 + %55 = OpTypePointer Output %54 + %56 = OpVariable %55 Output + %9 = OpVariable %60 Private + %61 = OpConstantTrue %25 + %62 = OpVariable %59 Private + %4 = OpFunction %2 None %3 + %5 = OpLabel + %13 = OpVariable %12 Function + %16 = OpVariable %15 Function + %38 = OpVariable %12 Function + OpStore %9 %11 + OpStore %13 %10 + OpStore %16 %17 + OpBranch %18 + %18 = OpLabel + OpSelectionMerge %20 None + OpBranchConditional %61 %22 %20 + %22 = OpLabel + %23 = OpLoad %14 %16 + %26 = OpSLessThan %25 %23 %24 + OpBranchConditional %26 %19 %20 + %19 = OpLabel + %27 = OpLoad %14 %16 + %32 = OpAccessChain %31 %30 %17 + %33 = OpLoad %6 %32 + %34 = OpConvertFToS %14 %33 + %35 = OpSLessThan %25 %27 %34 + OpSelectionMerge %37 None + OpBranchConditional %35 %36 %44 + %36 = OpLabel + %41 = OpAccessChain %59 %9 %40 + %42 = OpLoad %6 %41 + OpStore %38 %42 + OpBranch %37 + %44 = OpLabel + %46 = OpAccessChain %59 %9 %45 + OpBranch %37 + %37 = OpLabel + %47 = OpLoad %6 %62 + OpStore %38 %47 + %48 = OpLoad %6 %38 + %49 = OpLoad %6 %13 + %50 = OpFAdd %6 %49 %48 + OpStore %13 %50 + OpBranch %20 + %21 = OpLabel + %51 = OpLoad %14 %16 + %53 = OpIAdd %14 %51 %52 + OpStore %16 %53 + OpBranch %18 + %20 = OpLabel + %57 = OpLoad %6 %13 + %58 = OpCompositeConstruct %54 %57 %57 %57 %57 + OpStore %56 %58 + OpReturn + OpFunctionEnd + )"; + CheckEqual(env, expected, context.get()); +} + +TEST(StructuredLoopToSelectionReductionPassTest, DominanceAndPhiIssue) { + // Exposes an interesting scenario where a use in a phi stops being dominated + // by the block with which it is associated in the phi. + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %17 = OpTypeBool + %18 = OpConstantTrue %17 + %19 = OpConstantFalse %17 + %20 = OpTypeInt 32 1 + %21 = OpConstant %20 5 + %22 = OpConstant %20 6 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpBranch %6 + %6 = OpLabel + OpLoopMerge %16 %15 None + OpBranch %7 + %7 = OpLabel + OpSelectionMerge %13 None + OpBranchConditional %18 %8 %9 + %8 = OpLabel + OpSelectionMerge %12 None + OpBranchConditional %18 %10 %11 + %9 = OpLabel + OpBranch %16 + %10 = OpLabel + OpBranch %16 + %11 = OpLabel + %23 = OpIAdd %20 %21 %22 + OpBranch %12 + %12 = OpLabel + OpBranch %13 + %13 = OpLabel + OpBranch %14 + %14 = OpLabel + %24 = OpPhi %20 %23 %13 + OpBranchConditional %19 %15 %16 + %15 = OpLabel + OpBranch %6 + %16 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); + const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() + .GetAvailableOpportunities(context.get()); + ASSERT_EQ(1, ops.size()); + + ASSERT_TRUE(ops[0]->PreconditionHolds()); + ops[0]->TryToApply(); + + CheckValid(env, context.get()); + + std::string expected = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %17 = OpTypeBool + %18 = OpConstantTrue %17 + %19 = OpConstantFalse %17 + %20 = OpTypeInt 32 1 + %21 = OpConstant %20 5 + %22 = OpConstant %20 6 + %25 = OpUndef %20 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpBranch %6 + %6 = OpLabel + OpSelectionMerge %16 None + OpBranchConditional %18 %7 %16 + %7 = OpLabel + OpSelectionMerge %13 None + OpBranchConditional %18 %8 %9 + %8 = OpLabel + OpSelectionMerge %12 None + OpBranchConditional %18 %10 %11 + %9 = OpLabel + OpBranch %13 + %10 = OpLabel + OpBranch %12 + %11 = OpLabel + %23 = OpIAdd %20 %21 %22 + OpBranch %12 + %12 = OpLabel + OpBranch %13 + %13 = OpLabel + OpBranch %14 + %14 = OpLabel + %24 = OpPhi %20 %25 %13 + OpBranchConditional %19 %16 %16 + %15 = OpLabel + OpBranch %6 + %16 = OpLabel + OpReturn + OpFunctionEnd + )"; + CheckEqual(env, expected, context.get()); +} + +TEST(StructuredLoopToSelectionReductionPassTest, OpLineBeforeOpPhi) { + // Test to ensure the pass knows OpLine and OpPhi instructions can be + // interleaved. + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpSource ESSL 310 + %3 = OpString "somefile" + %4 = OpTypeVoid + %5 = OpTypeFunction %4 + %6 = OpTypeInt 32 1 + %7 = OpConstant %6 10 + %8 = OpConstant %6 20 + %9 = OpConstant %6 30 + %10 = OpTypeBool + %11 = OpConstantTrue %10 + %2 = OpFunction %4 None %5 + %12 = OpLabel + OpBranch %13 + %13 = OpLabel + OpLoopMerge %14 %15 None + OpBranch %16 + %16 = OpLabel + OpSelectionMerge %17 None + OpBranchConditional %11 %18 %19 + %18 = OpLabel + %20 = OpIAdd %6 %7 %8 + %21 = OpIAdd %6 %7 %9 + OpBranch %17 + %19 = OpLabel + OpBranch %14 + %17 = OpLabel + %22 = OpPhi %6 %20 %18 + OpLine %3 0 0 + %23 = OpPhi %6 %21 %18 + OpBranch %15 + %15 = OpLabel + OpBranch %13 + %14 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); + const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() + .GetAvailableOpportunities(context.get()); + ASSERT_EQ(1, ops.size()); + + ASSERT_TRUE(ops[0]->PreconditionHolds()); + ops[0]->TryToApply(); + + CheckValid(env, context.get()); + + std::string expected = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpSource ESSL 310 + %3 = OpString "somefile" + %4 = OpTypeVoid + %5 = OpTypeFunction %4 + %6 = OpTypeInt 32 1 + %7 = OpConstant %6 10 + %8 = OpConstant %6 20 + %9 = OpConstant %6 30 + %10 = OpTypeBool + %11 = OpConstantTrue %10 + %24 = OpUndef %6 + %2 = OpFunction %4 None %5 + %12 = OpLabel + OpBranch %13 + %13 = OpLabel + OpSelectionMerge %14 None + OpBranchConditional %11 %16 %14 + %16 = OpLabel + OpSelectionMerge %17 None + OpBranchConditional %11 %18 %19 + %18 = OpLabel + %20 = OpIAdd %6 %7 %8 + %21 = OpIAdd %6 %7 %9 + OpBranch %17 + %19 = OpLabel + OpBranch %17 + %17 = OpLabel + %22 = OpPhi %6 %20 %18 %24 %19 + OpLine %3 0 0 + %23 = OpPhi %6 %21 %18 %24 %19 + OpBranch %14 + %15 = OpLabel + OpBranch %13 + %14 = OpLabel + OpReturn + OpFunctionEnd + )"; + CheckEqual(env, expected, context.get()); +} + +TEST(StructuredLoopToSelectionReductionPassTest, + SelectionMergeIsContinueTarget) { + // Example where a loop's continue target is also the target of a selection. + // In this scenario we cautiously do not apply the transformation. + std::string shader = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %1 "main" + %2 = OpTypeVoid + %3 = OpTypeBool + %4 = OpTypeFunction %2 + %1 = OpFunction %2 None %4 + %5 = OpLabel + %6 = OpUndef %3 + OpBranch %7 + %7 = OpLabel + %8 = OpPhi %3 %6 %5 %9 %10 + OpLoopMerge %11 %10 None + OpBranch %12 + %12 = OpLabel + %13 = OpUndef %3 + OpSelectionMerge %10 None + OpBranchConditional %13 %14 %10 + %14 = OpLabel + OpBranch %10 + %10 = OpLabel + %9 = OpUndef %3 + OpBranchConditional %9 %7 %11 + %11 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); + const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() + .GetAvailableOpportunities(context.get()); + + // There should be no opportunities. + ASSERT_EQ(0, ops.size()); +} + +TEST(StructuredLoopToSelectionReductionPassTest, + SwitchSelectionMergeIsContinueTarget) { + // Another example where a loop's continue target is also the target of a + // selection; this time a selection associated with an OpSwitch. We + // cautiously do not apply the transformation. + std::string shader = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %1 "main" + %2 = OpTypeVoid + %3 = OpTypeBool + %5 = OpTypeInt 32 1 + %4 = OpTypeFunction %2 + %6 = OpConstant %5 2 + %7 = OpConstantTrue %3 + %1 = OpFunction %2 None %4 + %8 = OpLabel + OpBranch %9 + %9 = OpLabel + OpLoopMerge %14 %15 None + OpBranchConditional %7 %10 %14 + %10 = OpLabel + OpSelectionMerge %15 None + OpSwitch %6 %12 1 %11 2 %11 3 %15 + %11 = OpLabel + OpBranch %12 + %12 = OpLabel + OpBranch %15 + %15 = OpLabel + OpBranch %9 + %14 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); + const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() + .GetAvailableOpportunities(context.get()); + + // There should be no opportunities. + ASSERT_EQ(0, ops.size()); +} + +TEST(StructuredLoopToSelectionReductionPassTest, ContinueTargetIsSwitchTarget) { + std::string shader = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %1 "main" + %2 = OpTypeVoid + %3 = OpTypeBool + %5 = OpTypeInt 32 1 + %4 = OpTypeFunction %2 + %6 = OpConstant %5 2 + %7 = OpConstantTrue %3 + %1 = OpFunction %2 None %4 + %8 = OpLabel + OpBranch %9 + %9 = OpLabel + OpLoopMerge %14 %12 None + OpBranchConditional %7 %10 %14 + %10 = OpLabel + OpSelectionMerge %15 None + OpSwitch %6 %12 1 %11 2 %11 3 %15 + %11 = OpLabel + OpBranch %12 + %12 = OpLabel + OpBranch %9 + %15 = OpLabel + OpBranch %14 + %14 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); + const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() + .GetAvailableOpportunities(context.get()); + + ASSERT_EQ(1, ops.size()); + ASSERT_TRUE(ops[0]->PreconditionHolds()); + ops[0]->TryToApply(); + + CheckValid(env, context.get()); + + std::string expected = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %1 "main" + %2 = OpTypeVoid + %3 = OpTypeBool + %5 = OpTypeInt 32 1 + %4 = OpTypeFunction %2 + %6 = OpConstant %5 2 + %7 = OpConstantTrue %3 + %1 = OpFunction %2 None %4 + %8 = OpLabel + OpBranch %9 + %9 = OpLabel + OpSelectionMerge %14 None + OpBranchConditional %7 %10 %14 + %10 = OpLabel + OpSelectionMerge %15 None + OpSwitch %6 %15 1 %11 2 %11 3 %15 + %11 = OpLabel + OpBranch %15 + %12 = OpLabel + OpBranch %9 + %15 = OpLabel + OpBranch %14 + %14 = OpLabel + OpReturn + OpFunctionEnd + )"; + CheckEqual(env, expected, context.get()); +} + +TEST(StructuredLoopToSelectionReductionPassTest, + MultipleSwitchTargetsAreContinueTarget) { + std::string shader = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %1 "main" + %2 = OpTypeVoid + %3 = OpTypeBool + %5 = OpTypeInt 32 1 + %4 = OpTypeFunction %2 + %6 = OpConstant %5 2 + %7 = OpConstantTrue %3 + %1 = OpFunction %2 None %4 + %8 = OpLabel + OpBranch %9 + %9 = OpLabel + OpLoopMerge %14 %12 None + OpBranchConditional %7 %10 %14 + %10 = OpLabel + OpSelectionMerge %15 None + OpSwitch %6 %11 1 %12 2 %12 3 %15 + %11 = OpLabel + OpBranch %12 + %12 = OpLabel + OpBranch %9 + %15 = OpLabel + OpBranch %14 + %14 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); + const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() + .GetAvailableOpportunities(context.get()); + + ASSERT_EQ(1, ops.size()); + ASSERT_TRUE(ops[0]->PreconditionHolds()); + ops[0]->TryToApply(); + + CheckValid(env, context.get()); + + std::string expected = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %1 "main" + %2 = OpTypeVoid + %3 = OpTypeBool + %5 = OpTypeInt 32 1 + %4 = OpTypeFunction %2 + %6 = OpConstant %5 2 + %7 = OpConstantTrue %3 + %1 = OpFunction %2 None %4 + %8 = OpLabel + OpBranch %9 + %9 = OpLabel + OpSelectionMerge %14 None + OpBranchConditional %7 %10 %14 + %10 = OpLabel + OpSelectionMerge %15 None + OpSwitch %6 %11 1 %15 2 %15 3 %15 + %11 = OpLabel + OpBranch %15 + %12 = OpLabel + OpBranch %9 + %15 = OpLabel + OpBranch %14 + %14 = OpLabel + OpReturn + OpFunctionEnd + )"; + CheckEqual(env, expected, context.get()); +} + +TEST(StructuredLoopToSelectionReductionPassTest, LoopBranchesStraightToMerge) { + std::string shader = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %1 "main" + %2 = OpTypeVoid + %4 = OpTypeFunction %2 + %1 = OpFunction %2 None %4 + %8 = OpLabel + OpBranch %9 + %9 = OpLabel + OpLoopMerge %14 %12 None + OpBranch %14 + %12 = OpLabel + OpBranch %9 + %14 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); + const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() + .GetAvailableOpportunities(context.get()); + + ASSERT_EQ(1, ops.size()); + ASSERT_TRUE(ops[0]->PreconditionHolds()); + ops[0]->TryToApply(); + + CheckValid(env, context.get()); + + std::string expected = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %1 "main" + %2 = OpTypeVoid + %4 = OpTypeFunction %2 + %15 = OpTypeBool + %16 = OpConstantTrue %15 + %1 = OpFunction %2 None %4 + %8 = OpLabel + OpBranch %9 + %9 = OpLabel + OpSelectionMerge %14 None + OpBranchConditional %16 %14 %14 + %12 = OpLabel + OpBranch %9 + %14 = OpLabel + OpReturn + OpFunctionEnd + )"; + CheckEqual(env, expected, context.get()); +} + +TEST(StructuredLoopToSelectionReductionPassTest, + LoopConditionallyJumpsToMergeOrContinue) { + std::string shader = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %1 "main" + %2 = OpTypeVoid + %3 = OpTypeBool + %4 = OpTypeFunction %2 + %7 = OpConstantTrue %3 + %1 = OpFunction %2 None %4 + %8 = OpLabel + OpBranch %9 + %9 = OpLabel + OpLoopMerge %14 %12 None + OpBranchConditional %7 %14 %12 + %12 = OpLabel + OpBranch %9 + %14 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); + const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() + .GetAvailableOpportunities(context.get()); + + ASSERT_EQ(1, ops.size()); + ASSERT_TRUE(ops[0]->PreconditionHolds()); + ops[0]->TryToApply(); + + CheckValid(env, context.get()); + + std::string expected = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %1 "main" + %2 = OpTypeVoid + %3 = OpTypeBool + %4 = OpTypeFunction %2 + %7 = OpConstantTrue %3 + %1 = OpFunction %2 None %4 + %8 = OpLabel + OpBranch %9 + %9 = OpLabel + OpSelectionMerge %14 None + OpBranchConditional %7 %14 %14 + %12 = OpLabel + OpBranch %9 + %14 = OpLabel + OpReturn + OpFunctionEnd + )"; + CheckEqual(env, expected, context.get()); +} + +TEST(StructuredLoopToSelectionReductionPassTest, MultipleAccessChains) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypeStruct %6 + %8 = OpTypeStruct %7 + %9 = OpTypePointer Function %8 + %11 = OpConstant %6 3 + %12 = OpConstantComposite %7 %11 + %13 = OpConstantComposite %8 %12 + %14 = OpTypePointer Function %7 + %16 = OpConstant %6 0 + %19 = OpTypePointer Function %6 + %15 = OpTypeBool + %18 = OpConstantTrue %15 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %10 = OpVariable %9 Function + %20 = OpVariable %19 Function + OpStore %10 %13 + OpBranch %23 + %23 = OpLabel + OpLoopMerge %25 %26 None + OpBranch %27 + %27 = OpLabel + OpSelectionMerge %28 None + OpBranchConditional %18 %29 %25 + %29 = OpLabel + %17 = OpAccessChain %14 %10 %16 + OpBranch %28 + %28 = OpLabel + %21 = OpAccessChain %19 %17 %16 + %22 = OpLoad %6 %21 + %24 = OpAccessChain %19 %10 %16 %16 + OpStore %24 %22 + OpBranch %25 + %26 = OpLabel + OpBranch %23 + %25 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); + const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() + .GetAvailableOpportunities(context.get()); + + ASSERT_EQ(1, ops.size()); + ASSERT_TRUE(ops[0]->PreconditionHolds()); + ops[0]->TryToApply(); + + CheckValid(env, context.get()); + + std::string expected = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypeStruct %6 + %8 = OpTypeStruct %7 + %9 = OpTypePointer Function %8 + %11 = OpConstant %6 3 + %12 = OpConstantComposite %7 %11 + %13 = OpConstantComposite %8 %12 + %14 = OpTypePointer Function %7 + %16 = OpConstant %6 0 + %19 = OpTypePointer Function %6 + %15 = OpTypeBool + %18 = OpConstantTrue %15 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %10 = OpVariable %9 Function + %20 = OpVariable %19 Function + %30 = OpVariable %14 Function + OpStore %10 %13 + OpBranch %23 + %23 = OpLabel + OpSelectionMerge %25 None + OpBranchConditional %18 %27 %25 + %27 = OpLabel + OpSelectionMerge %28 None + OpBranchConditional %18 %29 %28 + %29 = OpLabel + %17 = OpAccessChain %14 %10 %16 + OpBranch %28 + %28 = OpLabel + %21 = OpAccessChain %19 %30 %16 + %22 = OpLoad %6 %21 + %24 = OpAccessChain %19 %10 %16 %16 + OpStore %24 %22 + OpBranch %25 + %26 = OpLabel + OpBranch %23 + %25 = OpLabel + OpReturn + OpFunctionEnd + )"; + CheckEqual(env, expected, context.get()); +} + +TEST(StructuredLoopToSelectionReductionPassTest, + UnreachableInnerLoopContinueBranchingToOuterLoopMerge) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpSource ESSL 310 + %3 = OpTypeVoid + %4 = OpTypeFunction %3 + %5 = OpTypeBool + %6 = OpConstantTrue %5 + %2 = OpFunction %3 None %4 + %7 = OpLabel + OpBranch %8 + %8 = OpLabel + OpLoopMerge %9 %10 None + OpBranch %11 + %11 = OpLabel + OpLoopMerge %12 %13 None + OpBranch %12 + %13 = OpLabel + OpBranchConditional %6 %9 %11 + %12 = OpLabel + OpBranch %10 + %10 = OpLabel + OpBranchConditional %6 %9 %8 + %9 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); + const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() + .GetAvailableOpportunities(context.get()); + + ASSERT_EQ(2, ops.size()); + ASSERT_TRUE(ops[0]->PreconditionHolds()); + ops[0]->TryToApply(); + + CheckValid(env, context.get()); + + std::string after_op_0 = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpSource ESSL 310 + %3 = OpTypeVoid + %4 = OpTypeFunction %3 + %5 = OpTypeBool + %6 = OpConstantTrue %5 + %2 = OpFunction %3 None %4 + %7 = OpLabel + OpBranch %8 + %8 = OpLabel + OpSelectionMerge %9 None + OpBranchConditional %6 %11 %9 + %11 = OpLabel + OpLoopMerge %12 %13 None + OpBranch %12 + %13 = OpLabel + OpBranchConditional %6 %9 %11 + %12 = OpLabel + OpBranch %9 + %10 = OpLabel + OpBranchConditional %6 %9 %8 + %9 = OpLabel + OpReturn + OpFunctionEnd + )"; + CheckEqual(env, after_op_0, context.get()); + + ASSERT_TRUE(ops[1]->PreconditionHolds()); + ops[1]->TryToApply(); + + CheckValid(env, context.get()); + + std::string after_op_1 = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpSource ESSL 310 + %3 = OpTypeVoid + %4 = OpTypeFunction %3 + %5 = OpTypeBool + %6 = OpConstantTrue %5 + %2 = OpFunction %3 None %4 + %7 = OpLabel + OpBranch %8 + %8 = OpLabel + OpSelectionMerge %9 None + OpBranchConditional %6 %11 %9 + %11 = OpLabel + OpSelectionMerge %12 None + OpBranchConditional %6 %12 %12 + %13 = OpLabel + OpBranchConditional %6 %9 %11 + %12 = OpLabel + OpBranch %9 + %10 = OpLabel + OpBranchConditional %6 %9 %8 + %9 = OpLabel + OpReturn + OpFunctionEnd + )"; + CheckEqual(env, after_op_1, context.get()); +} + +TEST(StructuredLoopToSelectionReductionPassTest, + UnreachableInnerLoopContinueBranchingToOuterLoopMerge2) { + // In this test, the branch to the outer loop merge from the inner loop's + // continue is part of a structured selection. + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpSource ESSL 310 + %3 = OpTypeVoid + %4 = OpTypeFunction %3 + %5 = OpTypeBool + %6 = OpConstantTrue %5 + %2 = OpFunction %3 None %4 + %7 = OpLabel + OpBranch %8 + %8 = OpLabel + OpLoopMerge %9 %10 None + OpBranch %11 + %11 = OpLabel + OpLoopMerge %12 %13 None + OpBranch %12 + %13 = OpLabel + OpSelectionMerge %14 None + OpBranchConditional %6 %9 %14 + %14 = OpLabel + OpBranch %11 + %12 = OpLabel + OpBranch %10 + %10 = OpLabel + OpBranchConditional %6 %9 %8 + %9 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); + const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() + .GetAvailableOpportunities(context.get()); + + ASSERT_EQ(2, ops.size()); + ASSERT_TRUE(ops[0]->PreconditionHolds()); + ops[0]->TryToApply(); + + CheckValid(env, context.get()); + + std::string after_op_0 = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpSource ESSL 310 + %3 = OpTypeVoid + %4 = OpTypeFunction %3 + %5 = OpTypeBool + %6 = OpConstantTrue %5 + %2 = OpFunction %3 None %4 + %7 = OpLabel + OpBranch %8 + %8 = OpLabel + OpSelectionMerge %9 None + OpBranchConditional %6 %11 %9 + %11 = OpLabel + OpLoopMerge %12 %13 None + OpBranch %12 + %13 = OpLabel + OpSelectionMerge %14 None + OpBranchConditional %6 %9 %14 + %14 = OpLabel + OpBranch %11 + %12 = OpLabel + OpBranch %9 + %10 = OpLabel + OpBranchConditional %6 %9 %8 + %9 = OpLabel + OpReturn + OpFunctionEnd + )"; + CheckEqual(env, after_op_0, context.get()); + + ASSERT_TRUE(ops[1]->PreconditionHolds()); + ops[1]->TryToApply(); + + CheckValid(env, context.get()); + + std::string after_op_1 = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpSource ESSL 310 + %3 = OpTypeVoid + %4 = OpTypeFunction %3 + %5 = OpTypeBool + %6 = OpConstantTrue %5 + %2 = OpFunction %3 None %4 + %7 = OpLabel + OpBranch %8 + %8 = OpLabel + OpSelectionMerge %9 None + OpBranchConditional %6 %11 %9 + %11 = OpLabel + OpSelectionMerge %12 None + OpBranchConditional %6 %12 %12 + %13 = OpLabel + OpSelectionMerge %14 None + OpBranchConditional %6 %9 %14 + %14 = OpLabel + OpBranch %11 + %12 = OpLabel + OpBranch %9 + %10 = OpLabel + OpBranchConditional %6 %9 %8 + %9 = OpLabel + OpReturn + OpFunctionEnd + )"; + CheckEqual(env, after_op_1, context.get()); +} + +TEST(StructuredLoopToSelectionReductionPassTest, + InnerLoopHeaderBranchesToOuterLoopMerge) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpSource ESSL 310 + %3 = OpTypeVoid + %4 = OpTypeFunction %3 + %5 = OpTypeBool + %6 = OpConstantTrue %5 + %2 = OpFunction %3 None %4 + %7 = OpLabel + OpBranch %8 + %8 = OpLabel + OpLoopMerge %9 %10 None + OpBranch %11 + %11 = OpLabel + OpLoopMerge %12 %13 None + OpBranchConditional %6 %9 %13 + %13 = OpLabel + OpBranchConditional %6 %11 %12 + %12 = OpLabel + OpBranch %10 + %10 = OpLabel + OpBranchConditional %6 %9 %8 + %9 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); + auto ops = StructuredLoopToSelectionReductionOpportunityFinder() + .GetAvailableOpportunities(context.get()); + + // We cannot transform the inner loop due to its header jumping straight to + // the outer loop merge (the inner loop's merge does not post-dominate its + // header). + ASSERT_EQ(1, ops.size()); + ASSERT_TRUE(ops[0]->PreconditionHolds()); + ops[0]->TryToApply(); + + CheckValid(env, context.get()); + + std::string after_op_0 = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpSource ESSL 310 + %3 = OpTypeVoid + %4 = OpTypeFunction %3 + %5 = OpTypeBool + %6 = OpConstantTrue %5 + %2 = OpFunction %3 None %4 + %7 = OpLabel + OpBranch %8 + %8 = OpLabel + OpSelectionMerge %9 None + OpBranchConditional %6 %11 %9 + %11 = OpLabel + OpLoopMerge %12 %13 None + OpBranchConditional %6 %12 %13 + %13 = OpLabel + OpBranchConditional %6 %11 %12 + %12 = OpLabel + OpBranch %9 + %10 = OpLabel + OpBranchConditional %6 %9 %8 + %9 = OpLabel + OpReturn + OpFunctionEnd + )"; + CheckEqual(env, after_op_0, context.get()); + + // Now look again for more opportunities. + ops = StructuredLoopToSelectionReductionOpportunityFinder() + .GetAvailableOpportunities(context.get()); + + // What was the inner loop should now be transformable, as the jump to the + // outer loop's merge has been redirected. + ASSERT_EQ(1, ops.size()); + ASSERT_TRUE(ops[0]->PreconditionHolds()); + ops[0]->TryToApply(); + + CheckValid(env, context.get()); + + std::string after_another_op_0 = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpSource ESSL 310 + %3 = OpTypeVoid + %4 = OpTypeFunction %3 + %5 = OpTypeBool + %6 = OpConstantTrue %5 + %2 = OpFunction %3 None %4 + %7 = OpLabel + OpBranch %8 + %8 = OpLabel + OpSelectionMerge %9 None + OpBranchConditional %6 %11 %9 + %11 = OpLabel + OpSelectionMerge %12 None + OpBranchConditional %6 %12 %12 + %13 = OpLabel + OpBranchConditional %6 %11 %12 + %12 = OpLabel + OpBranch %9 + %10 = OpLabel + OpBranchConditional %6 %9 %8 + %9 = OpLabel + OpReturn + OpFunctionEnd + )"; + CheckEqual(env, after_another_op_0, context.get()); +} + +TEST(StructuredLoopToSelectionReductionPassTest, LongAccessChains) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpSource ESSL 310 + %3 = OpTypeVoid + %4 = OpTypeFunction %3 + %5 = OpTypeInt 32 1 + %6 = OpTypeInt 32 0 + %7 = OpConstant %6 5 + %8 = OpTypeArray %5 %7 + %9 = OpTypeStruct %8 + %10 = OpTypeStruct %9 %9 + %11 = OpConstant %6 2 + %12 = OpTypeArray %10 %11 + %13 = OpTypeStruct %12 + %14 = OpTypePointer Function %13 + %15 = OpConstant %5 0 + %16 = OpConstant %5 1 + %17 = OpConstant %5 2 + %18 = OpConstant %5 3 + %19 = OpConstant %5 4 + %20 = OpConstantComposite %8 %15 %16 %17 %18 %19 + %21 = OpConstantComposite %9 %20 + %22 = OpConstant %5 5 + %23 = OpConstant %5 6 + %24 = OpConstant %5 7 + %25 = OpConstant %5 8 + %26 = OpConstant %5 9 + %27 = OpConstantComposite %8 %22 %23 %24 %25 %26 + %28 = OpConstantComposite %9 %27 + %29 = OpConstantComposite %10 %21 %28 + %30 = OpConstant %5 10 + %31 = OpConstant %5 11 + %32 = OpConstant %5 12 + %33 = OpConstant %5 13 + %34 = OpConstant %5 14 + %35 = OpConstantComposite %8 %30 %31 %32 %33 %34 + %36 = OpConstantComposite %9 %35 + %37 = OpConstant %5 15 + %38 = OpConstant %5 16 + %39 = OpConstant %5 17 + %40 = OpConstant %5 18 + %41 = OpConstant %5 19 + %42 = OpConstantComposite %8 %37 %38 %39 %40 %41 + %43 = OpConstantComposite %9 %42 + %44 = OpConstantComposite %10 %36 %43 + %45 = OpConstantComposite %12 %29 %44 + %46 = OpConstantComposite %13 %45 + %47 = OpTypePointer Function %12 + %48 = OpTypePointer Function %10 + %49 = OpTypePointer Function %9 + %50 = OpTypePointer Function %8 + %51 = OpTypePointer Function %5 + %52 = OpTypeBool + %53 = OpConstantTrue %52 + %2 = OpFunction %3 None %4 + %54 = OpLabel + %55 = OpVariable %14 Function + OpStore %55 %46 + OpBranch %56 + %56 = OpLabel + OpLoopMerge %57 %58 None + OpBranchConditional %53 %57 %59 + %59 = OpLabel + OpSelectionMerge %60 None + OpBranchConditional %53 %61 %57 + %61 = OpLabel + %62 = OpAccessChain %47 %55 %15 + OpBranch %63 + %63 = OpLabel + OpSelectionMerge %64 None + OpBranchConditional %53 %65 %57 + %65 = OpLabel + %66 = OpAccessChain %48 %62 %16 + OpBranch %67 + %67 = OpLabel + OpSelectionMerge %68 None + OpBranchConditional %53 %69 %57 + %69 = OpLabel + %70 = OpAccessChain %49 %66 %16 + OpBranch %71 + %71 = OpLabel + OpSelectionMerge %72 None + OpBranchConditional %53 %73 %57 + %73 = OpLabel + %74 = OpAccessChain %50 %70 %15 + OpBranch %75 + %75 = OpLabel + OpSelectionMerge %76 None + OpBranchConditional %53 %77 %57 + %77 = OpLabel + %78 = OpAccessChain %51 %74 %17 + OpBranch %79 + %79 = OpLabel + OpSelectionMerge %80 None + OpBranchConditional %53 %81 %57 + %81 = OpLabel + %82 = OpLoad %5 %78 + OpBranch %80 + %80 = OpLabel + OpBranch %76 + %76 = OpLabel + OpBranch %72 + %72 = OpLabel + OpBranch %68 + %68 = OpLabel + OpBranch %64 + %64 = OpLabel + OpBranch %60 + %60 = OpLabel + OpBranch %58 + %58 = OpLabel + OpBranch %56 + %57 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); + auto ops = StructuredLoopToSelectionReductionOpportunityFinder() + .GetAvailableOpportunities(context.get()); + + ASSERT_EQ(1, ops.size()); + ASSERT_TRUE(ops[0]->PreconditionHolds()); + ops[0]->TryToApply(); + + CheckValid(env, context.get()); + + // TODO(2183): When we have a more general solution for handling access + // chains, write an expected result for this test. + // std::string expected = R"( + // Expected text for transformed shader + //)"; + // CheckEqual(env, expected, context.get()); +} + +TEST(StructuredLoopToSelectionReductionPassTest, LoopyShaderWithOpDecorate) { + // A shader containing a function that contains a loop and some definitions + // that are "used" in OpDecorate instructions (outside the function). These + // "uses" were causing segfaults because we try to calculate their dominance + // information, which doesn't make sense. + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" %9 + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %9 "_GLF_color" + OpName %14 "buf0" + OpMemberName %14 0 "a" + OpName %16 "" + OpDecorate %9 RelaxedPrecision + OpDecorate %9 Location 0 + OpMemberDecorate %14 0 RelaxedPrecision + OpMemberDecorate %14 0 Offset 0 + OpDecorate %14 Block + OpDecorate %16 DescriptorSet 0 + OpDecorate %16 Binding 0 + OpDecorate %21 RelaxedPrecision + OpDecorate %35 RelaxedPrecision + OpDecorate %36 RelaxedPrecision + OpDecorate %39 RelaxedPrecision + OpDecorate %40 RelaxedPrecision + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypeVector %6 4 + %8 = OpTypePointer Output %7 + %9 = OpVariable %8 Output + %10 = OpConstant %6 1 + %11 = OpConstantComposite %7 %10 %10 %10 %10 + %14 = OpTypeStruct %6 + %15 = OpTypePointer Uniform %14 + %16 = OpVariable %15 Uniform + %17 = OpTypeInt 32 1 + %18 = OpConstant %17 0 + %19 = OpTypePointer Uniform %6 + %28 = OpConstant %6 2 + %29 = OpTypeBool + %31 = OpTypeInt 32 0 + %32 = OpConstant %31 0 + %33 = OpTypePointer Output %6 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpStore %9 %11 + %20 = OpAccessChain %19 %16 %18 + %21 = OpLoad %6 %20 + OpBranch %22 + %22 = OpLabel + %40 = OpPhi %6 %21 %5 %39 %23 + %30 = OpFOrdLessThan %29 %40 %28 + OpLoopMerge %24 %23 None + OpBranchConditional %30 %23 %24 + %23 = OpLabel + %34 = OpAccessChain %33 %9 %32 + %35 = OpLoad %6 %34 + %36 = OpFAdd %6 %35 %10 + OpStore %34 %36 + %39 = OpFAdd %6 %40 %10 + OpBranch %22 + %24 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); + const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() + .GetAvailableOpportunities(context.get()); + ASSERT_EQ(1, ops.size()); + + ASSERT_TRUE(ops[0]->PreconditionHolds()); + ops[0]->TryToApply(); + CheckValid(env, context.get()); + + std::string after_op_0 = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" %9 + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %9 "_GLF_color" + OpName %14 "buf0" + OpMemberName %14 0 "a" + OpName %16 "" + OpDecorate %9 RelaxedPrecision + OpDecorate %9 Location 0 + OpMemberDecorate %14 0 RelaxedPrecision + OpMemberDecorate %14 0 Offset 0 + OpDecorate %14 Block + OpDecorate %16 DescriptorSet 0 + OpDecorate %16 Binding 0 + OpDecorate %21 RelaxedPrecision + OpDecorate %35 RelaxedPrecision + OpDecorate %36 RelaxedPrecision + OpDecorate %39 RelaxedPrecision + OpDecorate %40 RelaxedPrecision + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypeVector %6 4 + %8 = OpTypePointer Output %7 + %9 = OpVariable %8 Output + %10 = OpConstant %6 1 + %11 = OpConstantComposite %7 %10 %10 %10 %10 + %14 = OpTypeStruct %6 + %15 = OpTypePointer Uniform %14 + %16 = OpVariable %15 Uniform + %17 = OpTypeInt 32 1 + %18 = OpConstant %17 0 + %19 = OpTypePointer Uniform %6 + %28 = OpConstant %6 2 + %29 = OpTypeBool + %31 = OpTypeInt 32 0 + %32 = OpConstant %31 0 + %33 = OpTypePointer Output %6 + %41 = OpUndef %6 ; Added + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpStore %9 %11 + %20 = OpAccessChain %19 %16 %18 + %21 = OpLoad %6 %20 + OpBranch %22 + %22 = OpLabel + %40 = OpPhi %6 %21 %5 %41 %23 ; Changed + %30 = OpFOrdLessThan %29 %40 %28 + OpSelectionMerge %24 None ; Changed + OpBranchConditional %30 %24 %24 + %23 = OpLabel + %34 = OpAccessChain %33 %9 %32 + %35 = OpLoad %6 %34 + %36 = OpFAdd %6 %35 %10 + OpStore %34 %36 + %39 = OpFAdd %6 %41 %10 ; Changed + OpBranch %22 + %24 = OpLabel + OpReturn + OpFunctionEnd + )"; + CheckEqual(env, after_op_0, context.get()); +} + +TEST(StructuredLoopToSelectionReductionPassTest, + LoopWithCombinedHeaderAndContinue) { + // A shader containing a loop where the header is also the continue target. + // For now, we don't simplify such loops. + + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeBool + %30 = OpConstantFalse %6 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpBranch %10 + %10 = OpLabel ; loop header and continue target + OpLoopMerge %12 %10 None + OpBranchConditional %30 %10 %12 + %12 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_3; + const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption); + const auto ops = StructuredLoopToSelectionReductionOpportunityFinder() + .GetAvailableOpportunities(context.get()); + ASSERT_EQ(0, ops.size()); +} + +} // namespace +} // namespace reduce +} // namespace spvtools diff --git a/third_party/spirv-tools/test/reduce/validation_during_reduction_test.cpp b/third_party/spirv-tools/test/reduce/validation_during_reduction_test.cpp new file mode 100644 index 0000000000..2981c2ed8f --- /dev/null +++ b/third_party/spirv-tools/test/reduce/validation_during_reduction_test.cpp @@ -0,0 +1,589 @@ +// Copyright (c) 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/reduce/reducer.h" +#include "source/reduce/reduction_opportunity.h" +#include "source/reduce/remove_instruction_reduction_opportunity.h" +#include "test/reduce/reduce_test_util.h" + +namespace spvtools { +namespace reduce { +namespace { + +using opt::Function; +using opt::Instruction; +using opt::IRContext; + +// A dumb reduction opportunity finder that finds opportunities to remove global +// values regardless of whether they are referenced. This is very likely to make +// the resulting module invalid. We use this to test the reducer's behavior in +// the scenario where a bad reduction pass leads to an invalid module. +class BlindlyRemoveGlobalValuesReductionOpportunityFinder + : public ReductionOpportunityFinder { + public: + BlindlyRemoveGlobalValuesReductionOpportunityFinder() = default; + + ~BlindlyRemoveGlobalValuesReductionOpportunityFinder() override = default; + + // The name of this pass. + std::string GetName() const final { return "BlindlyRemoveGlobalValuesPass"; } + + // Finds opportunities to remove all global values. Assuming they are all + // referenced (directly or indirectly) from elsewhere in the module, each such + // opportunity will make the module invalid. + std::vector> GetAvailableOpportunities( + IRContext* context) const final { + std::vector> result; + for (auto& inst : context->module()->types_values()) { + if (inst.HasResultId()) { + result.push_back( + MakeUnique(&inst)); + } + } + return result; + } +}; + +// A dumb reduction opportunity that exists at the start of every function whose +// first instruction is an OpVariable instruction. When applied, the OpVariable +// instruction is duplicated (with a fresh result id). This allows each +// reduction step to increase the number of variables to check if the validator +// limits are enforced. +class OpVariableDuplicatorReductionOpportunity : public ReductionOpportunity { + public: + OpVariableDuplicatorReductionOpportunity(Function* function) + : function_(function) {} + + bool PreconditionHolds() override { + Instruction* first_instruction = &*function_->begin()[0].begin(); + return first_instruction->opcode() == SpvOpVariable; + } + + protected: + void Apply() override { + // Duplicate the first OpVariable instruction. + + Instruction* first_instruction = &*function_->begin()[0].begin(); + assert(first_instruction->opcode() == SpvOpVariable && + "Expected first instruction to be OpVariable"); + IRContext* context = first_instruction->context(); + Instruction* cloned_instruction = first_instruction->Clone(context); + cloned_instruction->SetResultId(context->TakeNextId()); + cloned_instruction->InsertBefore(first_instruction); + } + + private: + Function* function_; +}; + +// A reduction opportunity finder that finds +// OpVariableDuplicatorReductionOpportunity. +class OpVariableDuplicatorReductionOpportunityFinder + : public ReductionOpportunityFinder { + public: + OpVariableDuplicatorReductionOpportunityFinder() = default; + + ~OpVariableDuplicatorReductionOpportunityFinder() override = default; + + std::string GetName() const final { + return "LocalVariableAdderReductionOpportunityFinder"; + } + + std::vector> GetAvailableOpportunities( + IRContext* context) const final { + std::vector> result; + for (auto& function : *context->module()) { + Instruction* first_instruction = &*function.begin()[0].begin(); + if (first_instruction->opcode() == SpvOpVariable) { + result.push_back( + MakeUnique(&function)); + } + } + return result; + } +}; + +TEST(ValidationDuringReductionTest, CheckInvalidPassMakesNoProgress) { + // A module whose global values are all referenced, so that any application of + // MakeModuleInvalidPass will make the module invalid. Check that the reducer + // makes no progress, as every step will be invalid and treated as + // uninteresting. + std::string original = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" %60 + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %16 "buf2" + OpMemberName %16 0 "i" + OpName %18 "" + OpName %25 "buf1" + OpMemberName %25 0 "f" + OpName %27 "" + OpName %60 "_GLF_color" + OpMemberDecorate %16 0 Offset 0 + OpDecorate %16 Block + OpDecorate %18 DescriptorSet 0 + OpDecorate %18 Binding 2 + OpMemberDecorate %25 0 Offset 0 + OpDecorate %25 Block + OpDecorate %27 DescriptorSet 0 + OpDecorate %27 Binding 1 + OpDecorate %60 Location 0 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %9 = OpConstant %6 0 + %16 = OpTypeStruct %6 + %17 = OpTypePointer Uniform %16 + %18 = OpVariable %17 Uniform + %19 = OpTypePointer Uniform %6 + %22 = OpTypeBool + %24 = OpTypeFloat 32 + %25 = OpTypeStruct %24 + %26 = OpTypePointer Uniform %25 + %27 = OpVariable %26 Uniform + %28 = OpTypePointer Uniform %24 + %31 = OpConstant %24 2 + %56 = OpConstant %6 1 + %58 = OpTypeVector %24 4 + %59 = OpTypePointer Output %58 + %60 = OpVariable %59 Output + %72 = OpUndef %24 + %74 = OpUndef %6 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpBranch %10 + %10 = OpLabel + %73 = OpPhi %6 %74 %5 %77 %34 + %71 = OpPhi %24 %72 %5 %76 %34 + %70 = OpPhi %6 %9 %5 %57 %34 + %20 = OpAccessChain %19 %18 %9 + %21 = OpLoad %6 %20 + %23 = OpSLessThan %22 %70 %21 + OpLoopMerge %12 %34 None + OpBranchConditional %23 %11 %12 + %11 = OpLabel + %29 = OpAccessChain %28 %27 %9 + %30 = OpLoad %24 %29 + %32 = OpFOrdGreaterThan %22 %30 %31 + OpSelectionMerge %90 None + OpBranchConditional %32 %33 %46 + %33 = OpLabel + %40 = OpFAdd %24 %71 %30 + %45 = OpISub %6 %73 %21 + OpBranch %90 + %46 = OpLabel + %50 = OpFMul %24 %71 %30 + %54 = OpSDiv %6 %73 %21 + OpBranch %90 + %90 = OpLabel + %77 = OpPhi %6 %45 %33 %54 %46 + %76 = OpPhi %24 %40 %33 %50 %46 + OpBranch %34 + %34 = OpLabel + %57 = OpIAdd %6 %70 %56 + OpBranch %10 + %12 = OpLabel + %61 = OpAccessChain %28 %27 %9 + %62 = OpLoad %24 %61 + %66 = OpConvertSToF %24 %21 + %68 = OpConvertSToF %24 %73 + %69 = OpCompositeConstruct %58 %62 %71 %66 %68 + OpStore %60 %69 + OpReturn + OpFunctionEnd + )"; + + spv_target_env env = SPV_ENV_UNIVERSAL_1_3; + Reducer reducer(env); + reducer.SetMessageConsumer(NopDiagnostic); + + // Say that every module is interesting. + reducer.SetInterestingnessFunction( + [](const std::vector&, uint32_t) -> bool { return true; }); + + reducer.AddReductionPass( + MakeUnique()); + + std::vector binary_in; + SpirvTools t(env); + + ASSERT_TRUE(t.Assemble(original, &binary_in, kReduceAssembleOption)); + std::vector binary_out; + spvtools::ReducerOptions reducer_options; + reducer_options.set_step_limit(500); + // Don't fail on a validation error; just treat it as uninteresting. + reducer_options.set_fail_on_validation_error(false); + spvtools::ValidatorOptions validator_options; + + Reducer::ReductionResultStatus status = reducer.Run( + std::move(binary_in), &binary_out, reducer_options, validator_options); + + ASSERT_EQ(status, Reducer::ReductionResultStatus::kComplete); + + // The reducer should have no impact. + CheckEqual(env, original, binary_out); +} + +TEST(ValidationDuringReductionTest, CheckNotAlwaysInvalidCanMakeProgress) { + // A module with just one unreferenced global value. All but one application + // of MakeModuleInvalidPass will make the module invalid. + std::string original = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" %60 + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %16 "buf2" + OpMemberName %16 0 "i" + OpName %18 "" + OpName %25 "buf1" + OpMemberName %25 0 "f" + OpName %27 "" + OpName %60 "_GLF_color" + OpMemberDecorate %16 0 Offset 0 + OpDecorate %16 Block + OpDecorate %18 DescriptorSet 0 + OpDecorate %18 Binding 2 + OpMemberDecorate %25 0 Offset 0 + OpDecorate %25 Block + OpDecorate %27 DescriptorSet 0 + OpDecorate %27 Binding 1 + OpDecorate %60 Location 0 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %9 = OpConstant %6 0 + %16 = OpTypeStruct %6 + %17 = OpTypePointer Uniform %16 + %18 = OpVariable %17 Uniform + %19 = OpTypePointer Uniform %6 + %22 = OpTypeBool + %24 = OpTypeFloat 32 + %25 = OpTypeStruct %24 + %26 = OpTypePointer Uniform %25 + %27 = OpVariable %26 Uniform + %28 = OpTypePointer Uniform %24 + %31 = OpConstant %24 2 + %56 = OpConstant %6 1 + %1000 = OpConstant %6 1000 ; It should be possible to remove this instruction without making the module invalid. + %58 = OpTypeVector %24 4 + %59 = OpTypePointer Output %58 + %60 = OpVariable %59 Output + %72 = OpUndef %24 + %74 = OpUndef %6 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpBranch %10 + %10 = OpLabel + %73 = OpPhi %6 %74 %5 %77 %34 + %71 = OpPhi %24 %72 %5 %76 %34 + %70 = OpPhi %6 %9 %5 %57 %34 + %20 = OpAccessChain %19 %18 %9 + %21 = OpLoad %6 %20 + %23 = OpSLessThan %22 %70 %21 + OpLoopMerge %12 %34 None + OpBranchConditional %23 %11 %12 + %11 = OpLabel + %29 = OpAccessChain %28 %27 %9 + %30 = OpLoad %24 %29 + %32 = OpFOrdGreaterThan %22 %30 %31 + OpSelectionMerge %90 None + OpBranchConditional %32 %33 %46 + %33 = OpLabel + %40 = OpFAdd %24 %71 %30 + %45 = OpISub %6 %73 %21 + OpBranch %90 + %46 = OpLabel + %50 = OpFMul %24 %71 %30 + %54 = OpSDiv %6 %73 %21 + OpBranch %90 + %90 = OpLabel + %77 = OpPhi %6 %45 %33 %54 %46 + %76 = OpPhi %24 %40 %33 %50 %46 + OpBranch %34 + %34 = OpLabel + %57 = OpIAdd %6 %70 %56 + OpBranch %10 + %12 = OpLabel + %61 = OpAccessChain %28 %27 %9 + %62 = OpLoad %24 %61 + %66 = OpConvertSToF %24 %21 + %68 = OpConvertSToF %24 %73 + %69 = OpCompositeConstruct %58 %62 %71 %66 %68 + OpStore %60 %69 + OpReturn + OpFunctionEnd + )"; + + // This is the same as the original, except that the constant declaration of + // 1000 is gone. + std::string expected = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" %60 + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %16 "buf2" + OpMemberName %16 0 "i" + OpName %18 "" + OpName %25 "buf1" + OpMemberName %25 0 "f" + OpName %27 "" + OpName %60 "_GLF_color" + OpMemberDecorate %16 0 Offset 0 + OpDecorate %16 Block + OpDecorate %18 DescriptorSet 0 + OpDecorate %18 Binding 2 + OpMemberDecorate %25 0 Offset 0 + OpDecorate %25 Block + OpDecorate %27 DescriptorSet 0 + OpDecorate %27 Binding 1 + OpDecorate %60 Location 0 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %9 = OpConstant %6 0 + %16 = OpTypeStruct %6 + %17 = OpTypePointer Uniform %16 + %18 = OpVariable %17 Uniform + %19 = OpTypePointer Uniform %6 + %22 = OpTypeBool + %24 = OpTypeFloat 32 + %25 = OpTypeStruct %24 + %26 = OpTypePointer Uniform %25 + %27 = OpVariable %26 Uniform + %28 = OpTypePointer Uniform %24 + %31 = OpConstant %24 2 + %56 = OpConstant %6 1 + %58 = OpTypeVector %24 4 + %59 = OpTypePointer Output %58 + %60 = OpVariable %59 Output + %72 = OpUndef %24 + %74 = OpUndef %6 + %4 = OpFunction %2 None %3 + %5 = OpLabel + OpBranch %10 + %10 = OpLabel + %73 = OpPhi %6 %74 %5 %77 %34 + %71 = OpPhi %24 %72 %5 %76 %34 + %70 = OpPhi %6 %9 %5 %57 %34 + %20 = OpAccessChain %19 %18 %9 + %21 = OpLoad %6 %20 + %23 = OpSLessThan %22 %70 %21 + OpLoopMerge %12 %34 None + OpBranchConditional %23 %11 %12 + %11 = OpLabel + %29 = OpAccessChain %28 %27 %9 + %30 = OpLoad %24 %29 + %32 = OpFOrdGreaterThan %22 %30 %31 + OpSelectionMerge %90 None + OpBranchConditional %32 %33 %46 + %33 = OpLabel + %40 = OpFAdd %24 %71 %30 + %45 = OpISub %6 %73 %21 + OpBranch %90 + %46 = OpLabel + %50 = OpFMul %24 %71 %30 + %54 = OpSDiv %6 %73 %21 + OpBranch %90 + %90 = OpLabel + %77 = OpPhi %6 %45 %33 %54 %46 + %76 = OpPhi %24 %40 %33 %50 %46 + OpBranch %34 + %34 = OpLabel + %57 = OpIAdd %6 %70 %56 + OpBranch %10 + %12 = OpLabel + %61 = OpAccessChain %28 %27 %9 + %62 = OpLoad %24 %61 + %66 = OpConvertSToF %24 %21 + %68 = OpConvertSToF %24 %73 + %69 = OpCompositeConstruct %58 %62 %71 %66 %68 + OpStore %60 %69 + OpReturn + OpFunctionEnd + )"; + + spv_target_env env = SPV_ENV_UNIVERSAL_1_3; + Reducer reducer(env); + reducer.SetMessageConsumer(NopDiagnostic); + + // Say that every module is interesting. + reducer.SetInterestingnessFunction( + [](const std::vector&, uint32_t) -> bool { return true; }); + + reducer.AddReductionPass( + MakeUnique()); + + std::vector binary_in; + SpirvTools t(env); + + ASSERT_TRUE(t.Assemble(original, &binary_in, kReduceAssembleOption)); + std::vector binary_out; + spvtools::ReducerOptions reducer_options; + reducer_options.set_step_limit(500); + // Don't fail on a validation error; just treat it as uninteresting. + reducer_options.set_fail_on_validation_error(false); + spvtools::ValidatorOptions validator_options; + + Reducer::ReductionResultStatus status = reducer.Run( + std::move(binary_in), &binary_out, reducer_options, validator_options); + + ASSERT_EQ(status, Reducer::ReductionResultStatus::kComplete); + + CheckEqual(env, expected, binary_out); +} + +// Sets up a Reducer for use in the CheckValidationOptions test; avoids +// repetition. +void SetupReducerForCheckValidationOptions(Reducer* reducer) { + reducer->SetMessageConsumer(NopDiagnostic); + + // Say that every module is interesting. + reducer->SetInterestingnessFunction( + [](const std::vector&, uint32_t) -> bool { return true; }); + + // Each "reduction" step will duplicate the first OpVariable instruction in + // the function. + reducer->AddReductionPass( + MakeUnique()); +} + +TEST(ValidationDuringReductionTest, CheckValidationOptions) { + // A module that only validates when the "skip-block-layout" validator option + // is used. Also, the entry point's first instruction creates a local + // variable; this instruction will be duplicated on each reduction step. + std::string original = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %2 "Main" %3 + OpSource HLSL 600 + OpDecorate %3 BuiltIn Position + OpDecorate %4 DescriptorSet 0 + OpDecorate %4 Binding 99 + OpDecorate %5 ArrayStride 16 + OpMemberDecorate %6 0 Offset 0 + OpMemberDecorate %6 1 Offset 32 + OpMemberDecorate %6 1 MatrixStride 16 + OpMemberDecorate %6 1 ColMajor + OpMemberDecorate %6 2 Offset 96 + OpMemberDecorate %6 3 Offset 100 + OpMemberDecorate %6 4 Offset 112 + OpMemberDecorate %6 4 MatrixStride 16 + OpMemberDecorate %6 4 ColMajor + OpMemberDecorate %6 5 Offset 176 + OpDecorate %6 Block + %7 = OpTypeFloat 32 + %8 = OpTypeVector %7 4 + %9 = OpTypeMatrix %8 4 + %10 = OpTypeVector %7 2 + %11 = OpTypeInt 32 1 + %12 = OpTypeInt 32 0 + %13 = OpConstant %12 2 + %14 = OpConstant %11 1 + %15 = OpConstant %11 5 + %5 = OpTypeArray %8 %13 + %6 = OpTypeStruct %5 %9 %12 %10 %9 %7 + %16 = OpTypePointer Uniform %6 + %17 = OpTypePointer Output %8 + %18 = OpTypeVoid + %19 = OpTypeFunction %18 + %20 = OpTypePointer Uniform %7 + %4 = OpVariable %16 Uniform + %3 = OpVariable %17 Output + %21 = OpTypePointer Function %11 + %2 = OpFunction %18 None %19 + %22 = OpLabel + %23 = OpVariable %21 Function + %24 = OpAccessChain %20 %4 %15 + %25 = OpLoad %7 %24 + %26 = OpCompositeConstruct %8 %25 %25 %25 %25 + OpStore %3 %26 + OpReturn + OpFunctionEnd + )"; + + spv_target_env env = SPV_ENV_UNIVERSAL_1_3; + std::vector binary_in; + SpirvTools t(env); + + ASSERT_TRUE(t.Assemble(original, &binary_in, kReduceAssembleOption)); + std::vector binary_out; + spvtools::ReducerOptions reducer_options; + spvtools::ValidatorOptions validator_options; + + reducer_options.set_step_limit(3); + reducer_options.set_fail_on_validation_error(true); + + // Reduction should fail because the initial state is invalid without the + // "skip-block-layout" validator option. Note that the interestingness test + // always returns true. + { + Reducer reducer(env); + SetupReducerForCheckValidationOptions(&reducer); + + Reducer::ReductionResultStatus status = + reducer.Run(std::vector(binary_in), &binary_out, + reducer_options, validator_options); + + ASSERT_EQ(status, Reducer::ReductionResultStatus::kInitialStateInvalid); + } + + // Try again with validator option. + validator_options.SetSkipBlockLayout(true); + + // Reduction should hit step limit; module is seen as valid, interestingness + // test always succeeds, and the finder yields infinite opportunities. + { + Reducer reducer(env); + SetupReducerForCheckValidationOptions(&reducer); + + Reducer::ReductionResultStatus status = + reducer.Run(std::vector(binary_in), &binary_out, + reducer_options, validator_options); + + ASSERT_EQ(status, Reducer::ReductionResultStatus::kReachedStepLimit); + } + + // Now set a limit on the number of local variables. + validator_options.SetUniversalLimit(spv_validator_limit_max_local_variables, + 2); + + // Reduction should now fail due to reaching an invalid state; after one step, + // a local variable is added and the module becomes "invalid" given the + // validator limits. + { + Reducer reducer(env); + SetupReducerForCheckValidationOptions(&reducer); + + Reducer::ReductionResultStatus status = + reducer.Run(std::vector(binary_in), &binary_out, + reducer_options, validator_options); + + ASSERT_EQ(status, Reducer::ReductionResultStatus::kStateInvalid); + } +} + +} // namespace +} // namespace reduce +} // namespace spvtools diff --git a/third_party/spirv-tools/test/scripts/test_compact_ids.py b/third_party/spirv-tools/test/scripts/test_compact_ids.py index b9b5b1bc04..6ca6e67b2c 100644 --- a/third_party/spirv-tools/test/scripts/test_compact_ids.py +++ b/third_party/spirv-tools/test/scripts/test_compact_ids.py @@ -14,8 +14,6 @@ # limitations under the License. """Tests correctness of opt pass tools/opt --compact-ids.""" -from __future__ import print_function - import os.path import sys import tempfile diff --git a/third_party/spirv-tools/test/stats/CMakeLists.txt b/third_party/spirv-tools/test/stats/CMakeLists.txt deleted file mode 100644 index 3e4a0742f8..0000000000 --- a/third_party/spirv-tools/test/stats/CMakeLists.txt +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright (c) 2017 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -set(VAL_TEST_COMMON_SRCS - ${CMAKE_CURRENT_SOURCE_DIR}/../test_fixture.h - ${CMAKE_CURRENT_SOURCE_DIR}/../unit_spirv.h -) - -add_spvtools_unittest(TARGET stats_aggregate - SRCS stats_aggregate_test.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/../../tools/stats/spirv_stats.cpp - ${VAL_TEST_COMMON_SRCS} - LIBS ${SPIRV_TOOLS} -) - -add_spvtools_unittest(TARGET stats_analyzer - SRCS stats_analyzer_test.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/../../tools/stats/stats_analyzer.cpp - ${VAL_TEST_COMMON_SRCS} - LIBS ${SPIRV_TOOLS} -) diff --git a/third_party/spirv-tools/test/stats/stats_aggregate_test.cpp b/third_party/spirv-tools/test/stats/stats_aggregate_test.cpp deleted file mode 100644 index 505fe2d6d2..0000000000 --- a/third_party/spirv-tools/test/stats/stats_aggregate_test.cpp +++ /dev/null @@ -1,438 +0,0 @@ -// Copyright (c) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Tests for unique type declaration rules validator. - -#include -#include - -#include "test/test_fixture.h" -#include "test/unit_spirv.h" -#include "tools/stats/spirv_stats.h" - -namespace spvtools { -namespace stats { -namespace { - -using spvtest::ScopedContext; - -void DiagnosticsMessageHandler(spv_message_level_t level, const char*, - const spv_position_t& position, - const char* message) { - switch (level) { - case SPV_MSG_FATAL: - case SPV_MSG_INTERNAL_ERROR: - case SPV_MSG_ERROR: - std::cerr << "error: " << position.index << ": " << message << std::endl; - break; - case SPV_MSG_WARNING: - std::cout << "warning: " << position.index << ": " << message - << std::endl; - break; - case SPV_MSG_INFO: - std::cout << "info: " << position.index << ": " << message << std::endl; - break; - default: - break; - } -} - -// Calls AggregateStats for binary compiled from |code|. -void CompileAndAggregateStats(const std::string& code, SpirvStats* stats, - spv_target_env env = SPV_ENV_UNIVERSAL_1_1) { - ScopedContext ctx(env); - SetContextMessageConsumer(ctx.context, DiagnosticsMessageHandler); - spv_binary binary; - ASSERT_EQ(SPV_SUCCESS, spvTextToBinary(ctx.context, code.c_str(), code.size(), - &binary, nullptr)); - - ASSERT_EQ(SPV_SUCCESS, AggregateStats(*ctx.context, binary->code, - binary->wordCount, nullptr, stats)); - spvBinaryDestroy(binary); -} - -TEST(AggregateStats, CapabilityHistogram) { - const std::string code1 = R"( -OpCapability Addresses -OpCapability Kernel -OpCapability GenericPointer -OpCapability Linkage -OpMemoryModel Physical32 OpenCL -)"; - - const std::string code2 = R"( -OpCapability Shader -OpCapability Linkage -OpMemoryModel Logical GLSL450 -)"; - - SpirvStats stats; - - CompileAndAggregateStats(code1, &stats); - EXPECT_EQ(4u, stats.capability_hist.size()); - EXPECT_EQ(0u, stats.capability_hist.count(SpvCapabilityShader)); - EXPECT_EQ(1u, stats.capability_hist.at(SpvCapabilityAddresses)); - EXPECT_EQ(1u, stats.capability_hist.at(SpvCapabilityKernel)); - EXPECT_EQ(1u, stats.capability_hist.at(SpvCapabilityGenericPointer)); - EXPECT_EQ(1u, stats.capability_hist.at(SpvCapabilityLinkage)); - - CompileAndAggregateStats(code2, &stats); - EXPECT_EQ(5u, stats.capability_hist.size()); - EXPECT_EQ(1u, stats.capability_hist.at(SpvCapabilityShader)); - EXPECT_EQ(1u, stats.capability_hist.at(SpvCapabilityAddresses)); - EXPECT_EQ(1u, stats.capability_hist.at(SpvCapabilityKernel)); - EXPECT_EQ(1u, stats.capability_hist.at(SpvCapabilityGenericPointer)); - EXPECT_EQ(2u, stats.capability_hist.at(SpvCapabilityLinkage)); - - CompileAndAggregateStats(code1, &stats); - EXPECT_EQ(5u, stats.capability_hist.size()); - EXPECT_EQ(1u, stats.capability_hist.at(SpvCapabilityShader)); - EXPECT_EQ(2u, stats.capability_hist.at(SpvCapabilityAddresses)); - EXPECT_EQ(2u, stats.capability_hist.at(SpvCapabilityKernel)); - EXPECT_EQ(2u, stats.capability_hist.at(SpvCapabilityGenericPointer)); - EXPECT_EQ(3u, stats.capability_hist.at(SpvCapabilityLinkage)); - - CompileAndAggregateStats(code2, &stats); - EXPECT_EQ(5u, stats.capability_hist.size()); - EXPECT_EQ(2u, stats.capability_hist.at(SpvCapabilityShader)); - EXPECT_EQ(2u, stats.capability_hist.at(SpvCapabilityAddresses)); - EXPECT_EQ(2u, stats.capability_hist.at(SpvCapabilityKernel)); - EXPECT_EQ(2u, stats.capability_hist.at(SpvCapabilityGenericPointer)); - EXPECT_EQ(4u, stats.capability_hist.at(SpvCapabilityLinkage)); -} - -TEST(AggregateStats, ExtensionHistogram) { - const std::string code1 = R"( -OpCapability Addresses -OpCapability Kernel -OpCapability GenericPointer -OpCapability Linkage -OpExtension "SPV_KHR_16bit_storage" -OpMemoryModel Physical32 OpenCL -)"; - - const std::string code2 = R"( -OpCapability Shader -OpCapability Linkage -OpExtension "SPV_NV_viewport_array2" -OpExtension "greatest_extension_ever" -OpMemoryModel Logical GLSL450 -)"; - - SpirvStats stats; - - CompileAndAggregateStats(code1, &stats); - EXPECT_EQ(1u, stats.extension_hist.size()); - EXPECT_EQ(0u, stats.extension_hist.count("SPV_NV_viewport_array2")); - EXPECT_EQ(1u, stats.extension_hist.at("SPV_KHR_16bit_storage")); - - CompileAndAggregateStats(code2, &stats); - EXPECT_EQ(3u, stats.extension_hist.size()); - EXPECT_EQ(1u, stats.extension_hist.at("SPV_NV_viewport_array2")); - EXPECT_EQ(1u, stats.extension_hist.at("SPV_KHR_16bit_storage")); - EXPECT_EQ(1u, stats.extension_hist.at("greatest_extension_ever")); - - CompileAndAggregateStats(code1, &stats); - EXPECT_EQ(3u, stats.extension_hist.size()); - EXPECT_EQ(1u, stats.extension_hist.at("SPV_NV_viewport_array2")); - EXPECT_EQ(2u, stats.extension_hist.at("SPV_KHR_16bit_storage")); - EXPECT_EQ(1u, stats.extension_hist.at("greatest_extension_ever")); - - CompileAndAggregateStats(code2, &stats); - EXPECT_EQ(3u, stats.extension_hist.size()); - EXPECT_EQ(2u, stats.extension_hist.at("SPV_NV_viewport_array2")); - EXPECT_EQ(2u, stats.extension_hist.at("SPV_KHR_16bit_storage")); - EXPECT_EQ(2u, stats.extension_hist.at("greatest_extension_ever")); -} - -TEST(AggregateStats, VersionHistogram) { - const std::string code1 = R"( -OpCapability Shader -OpCapability Linkage -OpMemoryModel Logical GLSL450 -)"; - - SpirvStats stats; - - CompileAndAggregateStats(code1, &stats); - EXPECT_EQ(1u, stats.version_hist.size()); - EXPECT_EQ(1u, stats.version_hist.at(0x00010100)); - - CompileAndAggregateStats(code1, &stats, SPV_ENV_UNIVERSAL_1_0); - EXPECT_EQ(2u, stats.version_hist.size()); - EXPECT_EQ(1u, stats.version_hist.at(0x00010100)); - EXPECT_EQ(1u, stats.version_hist.at(0x00010000)); - - CompileAndAggregateStats(code1, &stats); - EXPECT_EQ(2u, stats.version_hist.size()); - EXPECT_EQ(2u, stats.version_hist.at(0x00010100)); - EXPECT_EQ(1u, stats.version_hist.at(0x00010000)); - - CompileAndAggregateStats(code1, &stats, SPV_ENV_UNIVERSAL_1_0); - EXPECT_EQ(2u, stats.version_hist.size()); - EXPECT_EQ(2u, stats.version_hist.at(0x00010100)); - EXPECT_EQ(2u, stats.version_hist.at(0x00010000)); -} - -TEST(AggregateStats, GeneratorHistogram) { - const std::string code1 = R"( -OpCapability Shader -OpCapability Linkage -OpMemoryModel Logical GLSL450 -)"; - - const uint32_t kGeneratorKhronosAssembler = SPV_GENERATOR_KHRONOS_ASSEMBLER - << 16; - - SpirvStats stats; - - CompileAndAggregateStats(code1, &stats); - EXPECT_EQ(1u, stats.generator_hist.size()); - EXPECT_EQ(1u, stats.generator_hist.at(kGeneratorKhronosAssembler)); - - CompileAndAggregateStats(code1, &stats); - EXPECT_EQ(1u, stats.generator_hist.size()); - EXPECT_EQ(2u, stats.generator_hist.at(kGeneratorKhronosAssembler)); -} - -TEST(AggregateStats, OpcodeHistogram) { - const std::string code1 = R"( -OpCapability Addresses -OpCapability Kernel -OpCapability Int64 -OpCapability Linkage -OpMemoryModel Physical32 OpenCL -%u64 = OpTypeInt 64 0 -%u32 = OpTypeInt 32 0 -%f32 = OpTypeFloat 32 -)"; - - const std::string code2 = R"( -OpCapability Shader -OpCapability Linkage -OpExtension "SPV_NV_viewport_array2" -OpMemoryModel Logical GLSL450 -)"; - - SpirvStats stats; - - CompileAndAggregateStats(code1, &stats); - EXPECT_EQ(4u, stats.opcode_hist.size()); - EXPECT_EQ(4u, stats.opcode_hist.at(SpvOpCapability)); - EXPECT_EQ(1u, stats.opcode_hist.at(SpvOpMemoryModel)); - EXPECT_EQ(2u, stats.opcode_hist.at(SpvOpTypeInt)); - EXPECT_EQ(1u, stats.opcode_hist.at(SpvOpTypeFloat)); - - CompileAndAggregateStats(code2, &stats); - EXPECT_EQ(5u, stats.opcode_hist.size()); - EXPECT_EQ(6u, stats.opcode_hist.at(SpvOpCapability)); - EXPECT_EQ(2u, stats.opcode_hist.at(SpvOpMemoryModel)); - EXPECT_EQ(2u, stats.opcode_hist.at(SpvOpTypeInt)); - EXPECT_EQ(1u, stats.opcode_hist.at(SpvOpTypeFloat)); - EXPECT_EQ(1u, stats.opcode_hist.at(SpvOpExtension)); - - CompileAndAggregateStats(code1, &stats); - EXPECT_EQ(5u, stats.opcode_hist.size()); - EXPECT_EQ(10u, stats.opcode_hist.at(SpvOpCapability)); - EXPECT_EQ(3u, stats.opcode_hist.at(SpvOpMemoryModel)); - EXPECT_EQ(4u, stats.opcode_hist.at(SpvOpTypeInt)); - EXPECT_EQ(2u, stats.opcode_hist.at(SpvOpTypeFloat)); - EXPECT_EQ(1u, stats.opcode_hist.at(SpvOpExtension)); - - CompileAndAggregateStats(code2, &stats); - EXPECT_EQ(5u, stats.opcode_hist.size()); - EXPECT_EQ(12u, stats.opcode_hist.at(SpvOpCapability)); - EXPECT_EQ(4u, stats.opcode_hist.at(SpvOpMemoryModel)); - EXPECT_EQ(4u, stats.opcode_hist.at(SpvOpTypeInt)); - EXPECT_EQ(2u, stats.opcode_hist.at(SpvOpTypeFloat)); - EXPECT_EQ(2u, stats.opcode_hist.at(SpvOpExtension)); -} - -TEST(AggregateStats, OpcodeMarkovHistogram) { - const std::string code1 = R"( -OpCapability Shader -OpCapability Linkage -OpExtension "SPV_NV_viewport_array2" -OpMemoryModel Logical GLSL450 -)"; - - const std::string code2 = R"( -OpCapability Addresses -OpCapability Kernel -OpCapability Int64 -OpCapability Linkage -OpMemoryModel Physical32 OpenCL -%u64 = OpTypeInt 64 0 -%u32 = OpTypeInt 32 0 -%f32 = OpTypeFloat 32 -)"; - - SpirvStats stats; - stats.opcode_markov_hist.resize(2); - - CompileAndAggregateStats(code1, &stats); - ASSERT_EQ(2u, stats.opcode_markov_hist.size()); - EXPECT_EQ(2u, stats.opcode_markov_hist[0].size()); - EXPECT_EQ(2u, stats.opcode_markov_hist[0].at(SpvOpCapability).size()); - EXPECT_EQ(1u, stats.opcode_markov_hist[0].at(SpvOpExtension).size()); - EXPECT_EQ( - 1u, stats.opcode_markov_hist[0].at(SpvOpCapability).at(SpvOpCapability)); - EXPECT_EQ(1u, - stats.opcode_markov_hist[0].at(SpvOpCapability).at(SpvOpExtension)); - EXPECT_EQ( - 1u, stats.opcode_markov_hist[0].at(SpvOpExtension).at(SpvOpMemoryModel)); - - EXPECT_EQ(1u, stats.opcode_markov_hist[1].size()); - EXPECT_EQ(2u, stats.opcode_markov_hist[1].at(SpvOpCapability).size()); - EXPECT_EQ(1u, - stats.opcode_markov_hist[1].at(SpvOpCapability).at(SpvOpExtension)); - EXPECT_EQ( - 1u, stats.opcode_markov_hist[1].at(SpvOpCapability).at(SpvOpMemoryModel)); - - CompileAndAggregateStats(code2, &stats); - ASSERT_EQ(2u, stats.opcode_markov_hist.size()); - EXPECT_EQ(4u, stats.opcode_markov_hist[0].size()); - EXPECT_EQ(3u, stats.opcode_markov_hist[0].at(SpvOpCapability).size()); - EXPECT_EQ(1u, stats.opcode_markov_hist[0].at(SpvOpExtension).size()); - EXPECT_EQ(1u, stats.opcode_markov_hist[0].at(SpvOpMemoryModel).size()); - EXPECT_EQ(2u, stats.opcode_markov_hist[0].at(SpvOpTypeInt).size()); - EXPECT_EQ( - 4u, stats.opcode_markov_hist[0].at(SpvOpCapability).at(SpvOpCapability)); - EXPECT_EQ(1u, - stats.opcode_markov_hist[0].at(SpvOpCapability).at(SpvOpExtension)); - EXPECT_EQ( - 1u, stats.opcode_markov_hist[0].at(SpvOpCapability).at(SpvOpMemoryModel)); - EXPECT_EQ( - 1u, stats.opcode_markov_hist[0].at(SpvOpExtension).at(SpvOpMemoryModel)); - EXPECT_EQ(1u, - stats.opcode_markov_hist[0].at(SpvOpMemoryModel).at(SpvOpTypeInt)); - EXPECT_EQ(1u, stats.opcode_markov_hist[0].at(SpvOpTypeInt).at(SpvOpTypeInt)); - EXPECT_EQ(1u, - stats.opcode_markov_hist[0].at(SpvOpTypeInt).at(SpvOpTypeFloat)); - - EXPECT_EQ(3u, stats.opcode_markov_hist[1].size()); - EXPECT_EQ(4u, stats.opcode_markov_hist[1].at(SpvOpCapability).size()); - EXPECT_EQ(1u, stats.opcode_markov_hist[1].at(SpvOpMemoryModel).size()); - EXPECT_EQ(1u, stats.opcode_markov_hist[1].at(SpvOpTypeInt).size()); - EXPECT_EQ( - 2u, stats.opcode_markov_hist[1].at(SpvOpCapability).at(SpvOpCapability)); - EXPECT_EQ(1u, - stats.opcode_markov_hist[1].at(SpvOpCapability).at(SpvOpExtension)); - EXPECT_EQ( - 2u, stats.opcode_markov_hist[1].at(SpvOpCapability).at(SpvOpMemoryModel)); - EXPECT_EQ(1u, - stats.opcode_markov_hist[1].at(SpvOpCapability).at(SpvOpTypeInt)); - EXPECT_EQ(1u, - stats.opcode_markov_hist[1].at(SpvOpMemoryModel).at(SpvOpTypeInt)); - EXPECT_EQ(1u, - stats.opcode_markov_hist[1].at(SpvOpTypeInt).at(SpvOpTypeFloat)); -} - -TEST(AggregateStats, ConstantLiteralsHistogram) { - const std::string code1 = R"( -OpCapability Addresses -OpCapability Kernel -OpCapability GenericPointer -OpCapability Linkage -OpCapability Float64 -OpCapability Int16 -OpCapability Int64 -OpMemoryModel Physical32 OpenCL -%u16 = OpTypeInt 16 0 -%u32 = OpTypeInt 32 0 -%u64 = OpTypeInt 64 0 -%f32 = OpTypeFloat 32 -%f64 = OpTypeFloat 64 -%1 = OpConstant %f32 0.1 -%2 = OpConstant %f32 -2 -%3 = OpConstant %f64 -2 -%4 = OpConstant %u16 16 -%5 = OpConstant %u16 2 -%6 = OpConstant %u32 32 -%7 = OpConstant %u64 64 -)"; - - const std::string code2 = R"( -OpCapability Shader -OpCapability Linkage -OpCapability Int16 -OpCapability Int64 -OpMemoryModel Logical GLSL450 -%f32 = OpTypeFloat 32 -%u16 = OpTypeInt 16 0 -%s16 = OpTypeInt 16 1 -%u32 = OpTypeInt 32 0 -%s32 = OpTypeInt 32 1 -%u64 = OpTypeInt 64 0 -%s64 = OpTypeInt 64 1 -%1 = OpConstant %f32 0.1 -%2 = OpConstant %f32 -2 -%3 = OpConstant %u16 1 -%4 = OpConstant %u16 16 -%5 = OpConstant %u16 2 -%6 = OpConstant %s16 -16 -%7 = OpConstant %u32 32 -%8 = OpConstant %s32 2 -%9 = OpConstant %s32 -32 -%10 = OpConstant %u64 64 -%11 = OpConstant %s64 -64 -)"; - - SpirvStats stats; - - CompileAndAggregateStats(code1, &stats); - EXPECT_EQ(2u, stats.f32_constant_hist.size()); - EXPECT_EQ(1u, stats.f64_constant_hist.size()); - EXPECT_EQ(1u, stats.f32_constant_hist.at(0.1f)); - EXPECT_EQ(1u, stats.f32_constant_hist.at(-2.f)); - EXPECT_EQ(1u, stats.f64_constant_hist.at(-2)); - - EXPECT_EQ(2u, stats.u16_constant_hist.size()); - EXPECT_EQ(0u, stats.s16_constant_hist.size()); - EXPECT_EQ(1u, stats.u32_constant_hist.size()); - EXPECT_EQ(0u, stats.s32_constant_hist.size()); - EXPECT_EQ(1u, stats.u64_constant_hist.size()); - EXPECT_EQ(0u, stats.s64_constant_hist.size()); - EXPECT_EQ(1u, stats.u16_constant_hist.at(16)); - EXPECT_EQ(1u, stats.u16_constant_hist.at(2)); - EXPECT_EQ(1u, stats.u32_constant_hist.at(32)); - EXPECT_EQ(1u, stats.u64_constant_hist.at(64)); - - CompileAndAggregateStats(code2, &stats); - EXPECT_EQ(2u, stats.f32_constant_hist.size()); - EXPECT_EQ(1u, stats.f64_constant_hist.size()); - EXPECT_EQ(2u, stats.f32_constant_hist.at(0.1f)); - EXPECT_EQ(2u, stats.f32_constant_hist.at(-2.f)); - EXPECT_EQ(1u, stats.f64_constant_hist.at(-2)); - - EXPECT_EQ(3u, stats.u16_constant_hist.size()); - EXPECT_EQ(1u, stats.s16_constant_hist.size()); - EXPECT_EQ(1u, stats.u32_constant_hist.size()); - EXPECT_EQ(2u, stats.s32_constant_hist.size()); - EXPECT_EQ(1u, stats.u64_constant_hist.size()); - EXPECT_EQ(1u, stats.s64_constant_hist.size()); - EXPECT_EQ(2u, stats.u16_constant_hist.at(16)); - EXPECT_EQ(2u, stats.u16_constant_hist.at(2)); - EXPECT_EQ(1u, stats.u16_constant_hist.at(1)); - EXPECT_EQ(1u, stats.s16_constant_hist.at(-16)); - EXPECT_EQ(2u, stats.u32_constant_hist.at(32)); - EXPECT_EQ(1u, stats.s32_constant_hist.at(2)); - EXPECT_EQ(1u, stats.s32_constant_hist.at(-32)); - EXPECT_EQ(2u, stats.u64_constant_hist.at(64)); - EXPECT_EQ(1u, stats.s64_constant_hist.at(-64)); -} - -} // namespace -} // namespace stats -} // namespace spvtools diff --git a/third_party/spirv-tools/test/stats/stats_analyzer_test.cpp b/third_party/spirv-tools/test/stats/stats_analyzer_test.cpp deleted file mode 100644 index 3764c5bdd2..0000000000 --- a/third_party/spirv-tools/test/stats/stats_analyzer_test.cpp +++ /dev/null @@ -1,174 +0,0 @@ -// Copyright (c) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Tests for unique type declaration rules validator. - -#include -#include - -#include "source/latest_version_spirv_header.h" -#include "test/test_fixture.h" -#include "tools/stats/stats_analyzer.h" - -namespace spvtools { -namespace stats { -namespace { - -// Fills |stats| with some synthetic header stats, as if aggregated from 100 -// modules (100 used for simpler percentage evaluation). -void FillDefaultStats(SpirvStats* stats) { - *stats = SpirvStats(); - stats->version_hist[0x00010000] = 40; - stats->version_hist[0x00010100] = 60; - stats->generator_hist[0x00000000] = 64; - stats->generator_hist[0x00010000] = 1; - stats->generator_hist[0x00020000] = 2; - stats->generator_hist[0x00030000] = 3; - stats->generator_hist[0x00040000] = 4; - stats->generator_hist[0x00050000] = 5; - stats->generator_hist[0x00060000] = 6; - stats->generator_hist[0x00070000] = 7; - stats->generator_hist[0x00080000] = 8; - - int num_version_entries = 0; - for (const auto& pair : stats->version_hist) { - num_version_entries += pair.second; - } - - int num_generator_entries = 0; - for (const auto& pair : stats->generator_hist) { - num_generator_entries += pair.second; - } - - EXPECT_EQ(num_version_entries, num_generator_entries); -} - -TEST(StatsAnalyzer, Version) { - SpirvStats stats; - FillDefaultStats(&stats); - - StatsAnalyzer analyzer(stats); - - std::stringstream ss; - analyzer.WriteVersion(ss); - const std::string output = ss.str(); - const std::string expected_output = "Version 1.1 60%\nVersion 1.0 40%\n"; - - EXPECT_EQ(expected_output, output); -} - -TEST(StatsAnalyzer, Generator) { - SpirvStats stats; - FillDefaultStats(&stats); - - StatsAnalyzer analyzer(stats); - - std::stringstream ss; - analyzer.WriteGenerator(ss); - const std::string output = ss.str(); - const std::string expected_output = - "Khronos 64%\nKhronos Glslang Reference Front End 8%\n" - "Khronos SPIR-V Tools Assembler 7%\nKhronos LLVM/SPIR-V Translator 6%" - "\nARM 5%\nNVIDIA 4%\nCodeplay 3%\nValve 2%\nLunarG 1%\n"; - - EXPECT_EQ(expected_output, output); -} - -TEST(StatsAnalyzer, Capability) { - SpirvStats stats; - FillDefaultStats(&stats); - - stats.capability_hist[SpvCapabilityShader] = 25; - stats.capability_hist[SpvCapabilityKernel] = 75; - - StatsAnalyzer analyzer(stats); - - std::stringstream ss; - analyzer.WriteCapability(ss); - const std::string output = ss.str(); - const std::string expected_output = "Kernel 75%\nShader 25%\n"; - - EXPECT_EQ(expected_output, output); -} - -TEST(StatsAnalyzer, Extension) { - SpirvStats stats; - FillDefaultStats(&stats); - - stats.extension_hist["greatest_extension_ever"] = 1; - stats.extension_hist["worst_extension_ever"] = 10; - - StatsAnalyzer analyzer(stats); - - std::stringstream ss; - analyzer.WriteExtension(ss); - const std::string output = ss.str(); - const std::string expected_output = - "worst_extension_ever 10%\ngreatest_extension_ever 1%\n"; - - EXPECT_EQ(expected_output, output); -} - -TEST(StatsAnalyzer, Opcode) { - SpirvStats stats; - FillDefaultStats(&stats); - - stats.opcode_hist[SpvOpCapability] = 20; - stats.opcode_hist[SpvOpConstant] = 80; - stats.opcode_hist[SpvOpDecorate] = 100; - - StatsAnalyzer analyzer(stats); - - std::stringstream ss; - analyzer.WriteOpcode(ss); - const std::string output = ss.str(); - const std::string expected_output = - "Total unique opcodes used: 3\nDecorate 50%\n" - "Constant 40%\nCapability 10%\n"; - - EXPECT_EQ(expected_output, output); -} - -TEST(StatsAnalyzer, OpcodeMarkov) { - SpirvStats stats; - FillDefaultStats(&stats); - - stats.opcode_hist[SpvOpFMul] = 400; - stats.opcode_hist[SpvOpFAdd] = 200; - stats.opcode_hist[SpvOpFSub] = 400; - - stats.opcode_markov_hist.resize(1); - auto& hist = stats.opcode_markov_hist[0]; - hist[SpvOpFMul][SpvOpFAdd] = 100; - hist[SpvOpFMul][SpvOpFSub] = 300; - hist[SpvOpFAdd][SpvOpFMul] = 100; - hist[SpvOpFAdd][SpvOpFAdd] = 100; - - StatsAnalyzer analyzer(stats); - - std::stringstream ss; - analyzer.WriteOpcodeMarkov(ss); - const std::string output = ss.str(); - const std::string expected_output = - "FMul -> FSub 75% (base rate 40%, pair occurrences 300)\n" - "FMul -> FAdd 25% (base rate 20%, pair occurrences 100)\n" - "FAdd -> FAdd 50% (base rate 20%, pair occurrences 100)\n" - "FAdd -> FMul 50% (base rate 40%, pair occurrences 100)\n"; - - EXPECT_EQ(expected_output, output); -} - -} // namespace -} // namespace stats -} // namespace spvtools diff --git a/third_party/spirv-tools/test/target_env_test.cpp b/third_party/spirv-tools/test/target_env_test.cpp index f9624646dc..9c86e2da6c 100644 --- a/third_party/spirv-tools/test/target_env_test.cpp +++ b/third_party/spirv-tools/test/target_env_test.cpp @@ -45,8 +45,8 @@ TEST_P(TargetEnvTest, ValidSpirvVersion) { ASSERT_THAT(spirv_version, AnyOf(0x10000, 0x10100, 0x10200, 0x10300)); } -INSTANTIATE_TEST_CASE_P(AllTargetEnvs, TargetEnvTest, - ValuesIn(spvtest::AllTargetEnvironments())); +INSTANTIATE_TEST_SUITE_P(AllTargetEnvs, TargetEnvTest, + ValuesIn(spvtest::AllTargetEnvironments())); TEST(GetContextTest, InvalidTargetEnvProducesNull) { // Use a value beyond the last valid enum value. @@ -63,14 +63,16 @@ struct ParseCase { using TargetParseTest = ::testing::TestWithParam; -TEST_P(TargetParseTest, InvalidTargetEnvProducesNull) { +TEST_P(TargetParseTest, Samples) { spv_target_env env; bool parsed = spvParseTargetEnv(GetParam().input, &env); EXPECT_THAT(parsed, Eq(GetParam().success)); - EXPECT_THAT(env, Eq(GetParam().env)); + if (parsed) { + EXPECT_THAT(env, Eq(GetParam().env)); + } } -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( TargetParsing, TargetParseTest, ValuesIn(std::vector{ {"spv1.0", true, SPV_ENV_UNIVERSAL_1_0}, @@ -79,6 +81,7 @@ INSTANTIATE_TEST_CASE_P( {"spv1.3", true, SPV_ENV_UNIVERSAL_1_3}, {"vulkan1.0", true, SPV_ENV_VULKAN_1_0}, {"vulkan1.1", true, SPV_ENV_VULKAN_1_1}, + {"vulkan1.2", true, SPV_ENV_VULKAN_1_2}, {"opencl2.1", true, SPV_ENV_OPENCL_2_1}, {"opencl2.2", true, SPV_ENV_OPENCL_2_2}, {"opengl4.0", true, SPV_ENV_OPENGL_4_0}, @@ -95,12 +98,68 @@ INSTANTIATE_TEST_CASE_P( {"webgpu0", true, SPV_ENV_WEBGPU_0}, {"opencl2.3", false, SPV_ENV_UNIVERSAL_1_0}, {"opencl3.0", false, SPV_ENV_UNIVERSAL_1_0}, - {"vulkan1.2", false, SPV_ENV_UNIVERSAL_1_0}, + {"vulkan1.9", false, SPV_ENV_UNIVERSAL_1_0}, {"vulkan2.0", false, SPV_ENV_UNIVERSAL_1_0}, {nullptr, false, SPV_ENV_UNIVERSAL_1_0}, {"", false, SPV_ENV_UNIVERSAL_1_0}, {"abc", false, SPV_ENV_UNIVERSAL_1_0}, })); +// A test case for parsing an environment string. +struct ParseVulkanCase { + uint32_t vulkan; + uint32_t spirv; + bool success; // Expect to successfully parse? + spv_target_env env; // The parsed environment, if successful. +}; + +using TargetParseVulkanTest = ::testing::TestWithParam; + +TEST_P(TargetParseVulkanTest, Samples) { + spv_target_env env; + bool parsed = spvParseVulkanEnv(GetParam().vulkan, GetParam().spirv, &env); + EXPECT_THAT(parsed, Eq(GetParam().success)); + if (parsed) { + EXPECT_THAT(env, Eq(GetParam().env)); + } +} + +#define VK(MAJ, MIN) ((MAJ << 22) | (MIN << 12)) +#define SPV(MAJ, MIN) ((MAJ << 16) | (MIN << 8)) +INSTANTIATE_TEST_SUITE_P( + TargetVulkanParsing, TargetParseVulkanTest, + ValuesIn(std::vector{ + // Vulkan 1.0 cases + {VK(1, 0), SPV(1, 0), true, SPV_ENV_VULKAN_1_0}, + {VK(1, 0), SPV(1, 1), true, SPV_ENV_VULKAN_1_1}, + {VK(1, 0), SPV(1, 2), true, SPV_ENV_VULKAN_1_1}, + {VK(1, 0), SPV(1, 3), true, SPV_ENV_VULKAN_1_1}, + {VK(1, 0), SPV(1, 4), true, SPV_ENV_VULKAN_1_1_SPIRV_1_4}, + {VK(1, 0), SPV(1, 5), true, SPV_ENV_VULKAN_1_2}, + {VK(1, 0), SPV(1, 6), false, SPV_ENV_UNIVERSAL_1_0}, + // Vulkan 1.1 cases + {VK(1, 1), SPV(1, 0), true, SPV_ENV_VULKAN_1_1}, + {VK(1, 1), SPV(1, 1), true, SPV_ENV_VULKAN_1_1}, + {VK(1, 1), SPV(1, 2), true, SPV_ENV_VULKAN_1_1}, + {VK(1, 1), SPV(1, 3), true, SPV_ENV_VULKAN_1_1}, + {VK(1, 1), SPV(1, 4), true, SPV_ENV_VULKAN_1_1_SPIRV_1_4}, + {VK(1, 1), SPV(1, 5), true, SPV_ENV_VULKAN_1_2}, + {VK(1, 1), SPV(1, 6), false, SPV_ENV_UNIVERSAL_1_0}, + // Vulkan 1.2 cases + {VK(1, 2), SPV(1, 0), true, SPV_ENV_VULKAN_1_2}, + {VK(1, 2), SPV(1, 1), true, SPV_ENV_VULKAN_1_2}, + {VK(1, 2), SPV(1, 2), true, SPV_ENV_VULKAN_1_2}, + {VK(1, 2), SPV(1, 3), true, SPV_ENV_VULKAN_1_2}, + {VK(1, 2), SPV(1, 4), true, SPV_ENV_VULKAN_1_2}, + {VK(1, 2), SPV(1, 5), true, SPV_ENV_VULKAN_1_2}, + {VK(1, 2), SPV(1, 6), false, SPV_ENV_UNIVERSAL_1_0}, + // Vulkan 1.3 cases + {VK(1, 3), SPV(1, 0), false, SPV_ENV_UNIVERSAL_1_0}, + // Vulkan 2.0 cases + {VK(2, 0), SPV(1, 0), false, SPV_ENV_UNIVERSAL_1_0}, + // Vulkan 99.0 cases + {VK(99, 0), SPV(1, 0), false, SPV_ENV_UNIVERSAL_1_0}, + })); + } // namespace } // namespace spvtools diff --git a/third_party/spirv-tools/test/test_fixture.h b/third_party/spirv-tools/test/test_fixture.h index e85015c947..436993e213 100644 --- a/third_party/spirv-tools/test/test_fixture.h +++ b/third_party/spirv-tools/test/test_fixture.h @@ -61,6 +61,8 @@ class TextToBinaryTestBase : public T { // compilation success. Returns the compiled code. SpirvVector CompileSuccessfully(const std::string& txt, spv_target_env env = SPV_ENV_UNIVERSAL_1_0) { + DestroyBinary(); + DestroyDiagnostic(); spv_result_t status = spvTextToBinary(ScopedContext(env).context, txt.c_str(), txt.size(), &binary, &diagnostic); @@ -79,6 +81,8 @@ class TextToBinaryTestBase : public T { // Returns the error message(s). std::string CompileFailure(const std::string& txt, spv_target_env env = SPV_ENV_UNIVERSAL_1_0) { + DestroyBinary(); + DestroyDiagnostic(); EXPECT_NE(SPV_SUCCESS, spvTextToBinary(ScopedContext(env).context, txt.c_str(), txt.size(), &binary, &diagnostic)) @@ -94,6 +98,7 @@ class TextToBinaryTestBase : public T { uint32_t disassemble_options = SPV_BINARY_TO_TEXT_OPTION_NONE, spv_target_env env = SPV_ENV_UNIVERSAL_1_0) { DestroyBinary(); + DestroyDiagnostic(); ScopedContext context(env); disassemble_options |= SPV_BINARY_TO_TEXT_OPTION_NO_HEADER; spv_result_t error = spvTextToBinary(context.context, txt.c_str(), @@ -126,6 +131,8 @@ class TextToBinaryTestBase : public T { // Returns the error message. std::string EncodeSuccessfullyDecodeFailed( const std::string& txt, const SpirvVector& words_to_append) { + DestroyBinary(); + DestroyDiagnostic(); SpirvVector code = spvtest::Concatenate({CompileSuccessfully(txt), words_to_append}); @@ -169,6 +176,12 @@ class TextToBinaryTestBase : public T { binary = nullptr; } + // Destroys the diagnostic, if it exists. + void DestroyDiagnostic() { + spvDiagnosticDestroy(diagnostic); + diagnostic = nullptr; + } + spv_diagnostic diagnostic; std::string textString; diff --git a/third_party/spirv-tools/test/text_literal_test.cpp b/third_party/spirv-tools/test/text_literal_test.cpp index 7028089317..28e3500de0 100644 --- a/third_party/spirv-tools/test/text_literal_test.cpp +++ b/third_party/spirv-tools/test/text_literal_test.cpp @@ -106,7 +106,7 @@ TEST_P(GoodStringTest, GoodStrings) { EXPECT_EQ(std::get<1>(GetParam()), l.str); } -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( TextLiteral, GoodStringTest, ::testing::ValuesIn(std::vector>{ {R"("-")", "-"}, @@ -121,7 +121,7 @@ INSTANTIATE_TEST_CASE_P( {"\"\xE4\xBA\xB2\"", "\xE4\xBA\xB2"}, {"\"\\\xE4\xBA\xB2\"", "\xE4\xBA\xB2"}, {"\"this \\\" and this \\\\ and \\\xE4\xBA\xB2\"", - "this \" and this \\ and \xE4\xBA\xB2"}}), ); + "this \" and this \\ and \xE4\xBA\xB2"}})); TEST(TextLiteral, StringTooLong) { spv_literal_t l; @@ -230,7 +230,7 @@ TextLiteralCase Make_Bad_Unsigned(uint32_t bitwidth, const char* text) { } // clang-format off -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( DecimalIntegers, IntegerTest, ::testing::ValuesIn(std::vector{ // Check max value and overflow value for 1-bit numbers. @@ -277,7 +277,7 @@ INSTANTIATE_TEST_CASE_P( Make_Ok__Unsigned(64, "18446744073709551615", {0xffffffff, 0xffffffff}), Make_Ok__Signed(64, "-9223372036854775808", {0x00000000, 0x80000000}), - }),); + })); // clang-format on using IntegerLeadingMinusTest = @@ -290,7 +290,7 @@ TEST_P(IntegerLeadingMinusTest, CantHaveLeadingMinusOnUnsigned) { } // clang-format off -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( DecimalAndHexIntegers, IntegerLeadingMinusTest, ::testing::ValuesIn(std::vector{ // Unsigned numbers never allow a leading minus sign. @@ -303,10 +303,10 @@ INSTANTIATE_TEST_CASE_P( Make_Bad_Unsigned(64, "-0"), Make_Bad_Unsigned(64, "-0x0"), Make_Bad_Unsigned(64, "-0x1"), - }),); + })); // clang-format off -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( HexIntegers, IntegerTest, ::testing::ValuesIn(std::vector{ // Check 0x and 0X prefices. @@ -370,7 +370,7 @@ INSTANTIATE_TEST_CASE_P( Make_Ok__Signed(64, "0x8000000000000000", {0x00000000, 0x80000000}), Make_Ok__Unsigned(64, "0x7fffffffffffffff", {0xffffffff, 0x7fffffff}), Make_Ok__Unsigned(64, "0x8000000000000000", {0x00000000, 0x80000000}), - }),); + })); // clang-format on TEST(OverflowIntegerParse, Decimal) { diff --git a/third_party/spirv-tools/test/text_to_binary.annotation_test.cpp b/third_party/spirv-tools/test/text_to_binary.annotation_test.cpp index 7aec905555..61bdf64c8b 100644 --- a/third_party/spirv-tools/test/text_to_binary.annotation_test.cpp +++ b/third_party/spirv-tools/test/text_to_binary.annotation_test.cpp @@ -21,6 +21,7 @@ #include #include "gmock/gmock.h" +#include "source/util/string_utils.h" #include "test/test_fixture.h" #include "test/unit_spirv.h" @@ -29,7 +30,7 @@ namespace { using spvtest::EnumCase; using spvtest::MakeInstruction; -using spvtest::MakeVector; +using utils::MakeVector; using spvtest::TextToBinaryTest; using ::testing::Combine; using ::testing::Eq; @@ -60,8 +61,31 @@ TEST_P(OpDecorateSimpleTest, AnySimpleDecoration) { Eq(input.str())); } +// Like above, but parameters to the decoration are IDs. +using OpDecorateSimpleIdTest = + spvtest::TextToBinaryTestBase<::testing::TestWithParam< + std::tuple>>>; + +TEST_P(OpDecorateSimpleIdTest, AnySimpleDecoration) { + // This string should assemble, but should not validate. + std::stringstream input; + input << "OpDecorateId %1 " << std::get<1>(GetParam()).name(); + for (auto operand : std::get<1>(GetParam()).operands()) + input << " %" << operand; + input << std::endl; + EXPECT_THAT(CompiledInstructions(input.str(), std::get<0>(GetParam())), + Eq(MakeInstruction(SpvOpDecorateId, + {1, uint32_t(std::get<1>(GetParam()).value())}, + std::get<1>(GetParam()).operands()))); + // Also check disassembly. + EXPECT_THAT( + EncodeAndDecodeSuccessfully(input.str(), SPV_BINARY_TO_TEXT_OPTION_NONE, + std::get<0>(GetParam())), + Eq(input.str())); +} + #define CASE(NAME) SpvDecoration##NAME, #NAME -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( TextToBinaryDecorateSimple, OpDecorateSimpleTest, Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1), ValuesIn(std::vector>{ @@ -106,12 +130,27 @@ INSTANTIATE_TEST_CASE_P( {CASE(NoContraction), {}}, {CASE(InputAttachmentIndex), {102}}, {CASE(Alignment), {16}}, - })), ); + }))); -INSTANTIATE_TEST_CASE_P(TextToBinaryDecorateSimpleV11, OpDecorateSimpleTest, - Combine(Values(SPV_ENV_UNIVERSAL_1_1), - Values(EnumCase{ - CASE(MaxByteOffset), {128}})), ); +INSTANTIATE_TEST_SUITE_P(TextToBinaryDecorateSimpleV11, OpDecorateSimpleTest, + Combine(Values(SPV_ENV_UNIVERSAL_1_1), + Values(EnumCase{ + CASE(MaxByteOffset), {128}}))); + +INSTANTIATE_TEST_SUITE_P(TextToBinaryDecorateSimpleV14, OpDecorateSimpleTest, + Combine(Values(SPV_ENV_UNIVERSAL_1_4), + ValuesIn(std::vector>{ + {CASE(Uniform), {}}, + }))); + +INSTANTIATE_TEST_SUITE_P(TextToBinaryDecorateSimpleIdV14, + OpDecorateSimpleIdTest, + Combine(Values(SPV_ENV_UNIVERSAL_1_4), + ValuesIn(std::vector>{ + // In 1.4, UniformId decoration takes a + // scope Id. + {CASE(UniformId), {1}}, + }))); #undef CASE TEST_F(OpDecorateSimpleTest, WrongDecoration) { @@ -164,7 +203,7 @@ TEST_P(OpDecorateEnumTest, AnyEnumDecoration) { // clang-format off #define CASE(NAME) \ { SpvBuiltIn##NAME, #NAME, SpvDecorationBuiltIn, "BuiltIn" } -INSTANTIATE_TEST_CASE_P(TextToBinaryDecorateBuiltIn, OpDecorateEnumTest, +INSTANTIATE_TEST_SUITE_P(TextToBinaryDecorateBuiltIn, OpDecorateEnumTest, ::testing::ValuesIn(std::vector{ CASE(Position), CASE(PointSize), @@ -209,7 +248,7 @@ INSTANTIATE_TEST_CASE_P(TextToBinaryDecorateBuiltIn, OpDecorateEnumTest, CASE(SubgroupLocalInvocationId), CASE(VertexIndex), CASE(InstanceIndex), - }),); + })); #undef CASE // clang-format on @@ -222,7 +261,7 @@ TEST_F(OpDecorateEnumTest, WrongBuiltIn) { // clang-format off #define CASE(NAME) \ { SpvFunctionParameterAttribute##NAME, #NAME, SpvDecorationFuncParamAttr, "FuncParamAttr" } -INSTANTIATE_TEST_CASE_P(TextToBinaryDecorateFuncParamAttr, OpDecorateEnumTest, +INSTANTIATE_TEST_SUITE_P(TextToBinaryDecorateFuncParamAttr, OpDecorateEnumTest, ::testing::ValuesIn(std::vector{ CASE(Zext), CASE(Sext), @@ -232,7 +271,7 @@ INSTANTIATE_TEST_CASE_P(TextToBinaryDecorateFuncParamAttr, OpDecorateEnumTest, CASE(NoCapture), CASE(NoWrite), CASE(NoReadWrite), - }),); + })); #undef CASE // clang-format on @@ -245,13 +284,13 @@ TEST_F(OpDecorateEnumTest, WrongFuncParamAttr) { // clang-format off #define CASE(NAME) \ { SpvFPRoundingMode##NAME, #NAME, SpvDecorationFPRoundingMode, "FPRoundingMode" } -INSTANTIATE_TEST_CASE_P(TextToBinaryDecorateFPRoundingMode, OpDecorateEnumTest, +INSTANTIATE_TEST_SUITE_P(TextToBinaryDecorateFPRoundingMode, OpDecorateEnumTest, ::testing::ValuesIn(std::vector{ CASE(RTE), CASE(RTZ), CASE(RTP), CASE(RTN), - }),); + })); #undef CASE // clang-format on @@ -268,7 +307,7 @@ TEST_F(OpDecorateEnumTest, WrongFPRoundingMode) { // clang-format off #define CASE(ENUM,NAME) \ { SpvFPFastMathMode##ENUM, #NAME, SpvDecorationFPFastMathMode, "FPFastMathMode" } -INSTANTIATE_TEST_CASE_P(TextToBinaryDecorateFPFastMathMode, OpDecorateEnumTest, +INSTANTIATE_TEST_SUITE_P(TextToBinaryDecorateFPFastMathMode, OpDecorateEnumTest, ::testing::ValuesIn(std::vector{ CASE(MaskNone, None), CASE(NotNaNMask, NotNaN), @@ -276,7 +315,7 @@ INSTANTIATE_TEST_CASE_P(TextToBinaryDecorateFPFastMathMode, OpDecorateEnumTest, CASE(NSZMask, NSZ), CASE(AllowRecipMask, AllowRecip), CASE(FastMask, Fast), - }),); + })); #undef CASE // clang-format on @@ -329,13 +368,13 @@ TEST_P(OpDecorateLinkageTest, AnyLinkageDecoration) { // clang-format off #define CASE(ENUM) SpvLinkageType##ENUM, #ENUM -INSTANTIATE_TEST_CASE_P(TextToBinaryDecorateLinkage, OpDecorateLinkageTest, +INSTANTIATE_TEST_SUITE_P(TextToBinaryDecorateLinkage, OpDecorateLinkageTest, ::testing::ValuesIn(std::vector{ { CASE(Import), "a" }, { CASE(Export), "foo" }, { CASE(Import), "some kind of long name with spaces etc." }, // TODO(dneto): utf-8, escaping, quoting cases. - }),); + })); #undef CASE // clang-format on @@ -423,7 +462,7 @@ TEST_P(OpMemberDecorateSimpleTest, AnySimpleDecoration) { } #define CASE(NAME) SpvDecoration##NAME, #NAME -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( TextToBinaryDecorateSimple, OpMemberDecorateSimpleTest, Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1), ValuesIn(std::vector>{ @@ -468,12 +507,12 @@ INSTANTIATE_TEST_CASE_P( {CASE(NoContraction), {}}, {CASE(InputAttachmentIndex), {102}}, {CASE(Alignment), {16}}, - })), ); + }))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( TextToBinaryDecorateSimpleV11, OpMemberDecorateSimpleTest, Combine(Values(SPV_ENV_UNIVERSAL_1_1), - Values(EnumCase{CASE(MaxByteOffset), {128}})), ); + Values(EnumCase{CASE(MaxByteOffset), {128}}))); #undef CASE TEST_F(OpMemberDecorateSimpleTest, WrongDecoration) { diff --git a/third_party/spirv-tools/test/text_to_binary.composite_test.cpp b/third_party/spirv-tools/test/text_to_binary.composite_test.cpp new file mode 100644 index 0000000000..6ae1cd35d6 --- /dev/null +++ b/third_party/spirv-tools/test/text_to_binary.composite_test.cpp @@ -0,0 +1,49 @@ +// Copyright (c) 2018 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. + +// Assembler tests for instructions in the "Group Instrucions" section of the +// SPIR-V spec. + +#include +#include + +#include "gmock/gmock.h" +#include "test/test_fixture.h" +#include "test/unit_spirv.h" + +using ::testing::Eq; +using ::testing::HasSubstr; + +namespace spvtools { +namespace { + +using spvtest::Concatenate; + +using CompositeRoundTripTest = RoundTripTest; + +TEST_F(CompositeRoundTripTest, Good) { + std::string spirv = "%2 = OpCopyLogical %1 %3\n"; + std::string disassembly = EncodeAndDecodeSuccessfully( + spirv, SPV_BINARY_TO_TEXT_OPTION_NONE, SPV_ENV_UNIVERSAL_1_4); + EXPECT_THAT(disassembly, Eq(spirv)); +} + +TEST_F(CompositeRoundTripTest, V13Bad) { + std::string spirv = "%2 = OpCopyLogical %1 %3\n"; + std::string err = CompileFailure(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_THAT(err, HasSubstr("Invalid Opcode name 'OpCopyLogical'")); +} + +} // namespace +} // namespace spvtools diff --git a/third_party/spirv-tools/test/text_to_binary.constant_test.cpp b/third_party/spirv-tools/test/text_to_binary.constant_test.cpp index 1a24b528f2..679bee40c9 100644 --- a/third_party/spirv-tools/test/text_to_binary.constant_test.cpp +++ b/third_party/spirv-tools/test/text_to_binary.constant_test.cpp @@ -47,7 +47,7 @@ TEST_P(SamplerAddressingModeTest, AnySamplerAddressingMode) { // clang-format off #define CASE(NAME) { SpvSamplerAddressingMode##NAME, #NAME } -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( TextToBinarySamplerAddressingMode, SamplerAddressingModeTest, ::testing::ValuesIn(std::vector>{ CASE(None), @@ -55,7 +55,7 @@ INSTANTIATE_TEST_CASE_P( CASE(Clamp), CASE(Repeat), CASE(RepeatMirrored), - }),); + })); #undef CASE // clang-format on @@ -79,12 +79,12 @@ TEST_P(SamplerFilterModeTest, AnySamplerFilterMode) { // clang-format off #define CASE(NAME) { SpvSamplerFilterMode##NAME, #NAME} -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( TextToBinarySamplerFilterMode, SamplerFilterModeTest, ::testing::ValuesIn(std::vector>{ CASE(Nearest), CASE(Linear), - }),); + })); #undef CASE // clang-format on @@ -114,7 +114,7 @@ TEST_P(OpConstantValidTest, ValidTypes) { } // clang-format off -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( TextToBinaryOpConstantValid, OpConstantValidTest, ::testing::ValuesIn(std::vector{ // Check 16 bits @@ -232,7 +232,7 @@ INSTANTIATE_TEST_CASE_P( {"OpTypeInt 64 1", "0x7fffffff", Concatenate({MakeInstruction(SpvOpTypeInt, {1, 64, 1}), MakeInstruction(SpvOpConstant, {1, 2, 0x7fffffffu, 0})})}, - }),); + })); // clang-format on // A test case for checking OpConstant with invalid literals with a leading @@ -255,7 +255,7 @@ TEST_P(OpConstantInvalidLeadingMinusTest, InvalidCase) { } // clang-format off -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( TextToBinaryOpConstantInvalidLeadingMinus, OpConstantInvalidLeadingMinusTest, ::testing::ValuesIn(std::vector{ {"OpTypeInt 16 0", "-0"}, @@ -267,7 +267,7 @@ INSTANTIATE_TEST_CASE_P( {"OpTypeInt 64 0", "-0"}, {"OpTypeInt 64 0", "-0x0"}, {"OpTypeInt 64 0", "-1"}, - }),); + })); // clang-format on // A test case for invalid floating point literals. @@ -293,7 +293,7 @@ TEST_P(OpConstantInvalidFloatConstant, Samples) { } // clang-format off -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( TextToBinaryInvalidFloatConstant, OpConstantInvalidFloatConstant, ::testing::ValuesIn(std::vector{ {16, "abc"}, @@ -323,12 +323,11 @@ INSTANTIATE_TEST_CASE_P( {64, "++1"}, {32, "1e400"}, // Overflow is an error for 64-bit floats. {32, "-1e400"}, - }),); + })); // clang-format on using OpConstantInvalidTypeTest = spvtest::TextToBinaryTestBase<::testing::TestWithParam>; - TEST_P(OpConstantInvalidTypeTest, InvalidTypes) { const std::string input = "%1 = " + GetParam() + "\n" @@ -339,7 +338,7 @@ TEST_P(OpConstantInvalidTypeTest, InvalidTypes) { } // clang-format off -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( TextToBinaryOpConstantInvalidValidType, OpConstantInvalidTypeTest, ::testing::ValuesIn(std::vector{ {"OpTypeVoid", @@ -360,11 +359,14 @@ INSTANTIATE_TEST_CASE_P( "OpTypeReserveId", "OpTypeQueue", "OpTypePipe ReadOnly", - "OpTypeForwardPointer %a UniformConstant", - // At least one thing that isn't a type at all + + // Skip OpTypeForwardPointer doesn't even produce a result ID. + // The assembler errors out if we try to check it in this scenario. + + // Try at least one thing that isn't a type at all "OpNot %a %b" }, - }),); + })); // clang-format on using OpSpecConstantValidTest = @@ -381,7 +383,7 @@ TEST_P(OpSpecConstantValidTest, ValidTypes) { } // clang-format off -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( TextToBinaryOpSpecConstantValid, OpSpecConstantValidTest, ::testing::ValuesIn(std::vector{ // Check 16 bits @@ -433,7 +435,7 @@ INSTANTIATE_TEST_CASE_P( {"OpTypeInt 64 1", "-42", Concatenate({MakeInstruction(SpvOpTypeInt, {1, 64, 1}), MakeInstruction(SpvOpSpecConstant, {1, 2, uint32_t(-42), uint32_t(-1)})})}, - }),); + })); // clang-format on using OpSpecConstantInvalidTypeTest = @@ -449,7 +451,7 @@ TEST_P(OpSpecConstantInvalidTypeTest, InvalidTypes) { } // clang-format off -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( TextToBinaryOpSpecConstantInvalidValidType, OpSpecConstantInvalidTypeTest, ::testing::ValuesIn(std::vector{ {"OpTypeVoid", @@ -470,18 +472,20 @@ INSTANTIATE_TEST_CASE_P( "OpTypeReserveId", "OpTypeQueue", "OpTypePipe ReadOnly", - "OpTypeForwardPointer %a UniformConstant", - // At least one thing that isn't a type at all + + // Skip testing OpTypeForwardPointer because it doesn't even produce a result ID. + + // Try at least one thing that isn't a type at all "OpNot %a %b" }, - }),); + })); // clang-format on const int64_t kMaxUnsigned48Bit = (int64_t(1) << 48) - 1; const int64_t kMaxSigned48Bit = (int64_t(1) << 47) - 1; const int64_t kMinSigned48Bit = -kMaxSigned48Bit - 1; -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( OpConstantRoundTrip, RoundTripTest, ::testing::ValuesIn(std::vector{ // 16 bit @@ -522,9 +526,9 @@ INSTANTIATE_TEST_CASE_P( "%1 = OpTypeFloat 64\n%2 = OpConstant %1 0\n", "%1 = OpTypeFloat 64\n%2 = OpConstant %1 1.79767e+308\n", "%1 = OpTypeFloat 64\n%2 = OpConstant %1 -1.79767e+308\n", - }), ); + })); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( OpConstantHalfRoundTrip, RoundTripTest, ::testing::ValuesIn(std::vector{ "%1 = OpTypeFloat 16\n%2 = OpConstant %1 -0x0p+0\n", @@ -557,11 +561,11 @@ INSTANTIATE_TEST_CASE_P( "%1 = OpTypeFloat 16\n%2 = OpConstant %1 -0x1.ffp+16\n", // -nan "%1 = OpTypeFloat 16\n%2 = OpConstant %1 -0x1.ffcp+16\n", // -nan "%1 = OpTypeFloat 16\n%2 = OpConstant %1 -0x1.004p+16\n", // -nan - }), ); + })); // clang-format off // (Clang-format really wants to break up these strings across lines. -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( OpConstantRoundTripNonFinite, RoundTripTest, ::testing::ValuesIn(std::vector{ "%1 = OpTypeFloat 32\n%2 = OpConstant %1 -0x1p+128\n", // -inf @@ -588,10 +592,10 @@ INSTANTIATE_TEST_CASE_P( "%1 = OpTypeFloat 64\n%2 = OpConstant %1 0x1.0000000000001p+1024\n", // -nan "%1 = OpTypeFloat 64\n%2 = OpConstant %1 0x1.00003p+1024\n", // -nan "%1 = OpTypeFloat 64\n%2 = OpConstant %1 0x1.fffffffffffffp+1024\n", // -nan - }),); + })); // clang-format on -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( OpSpecConstantRoundTrip, RoundTripTest, ::testing::ValuesIn(std::vector{ // 16 bit @@ -632,7 +636,7 @@ INSTANTIATE_TEST_CASE_P( "%1 = OpTypeFloat 64\n%2 = OpSpecConstant %1 0\n", "%1 = OpTypeFloat 64\n%2 = OpSpecConstant %1 1.79767e+308\n", "%1 = OpTypeFloat 64\n%2 = OpSpecConstant %1 -1.79767e+308\n", - }), ); + })); // Test OpSpecConstantOp @@ -662,7 +666,7 @@ TEST_P(OpSpecConstantOpTestWithIds, Assembly) { #define CASE4(NAME) { SpvOp##NAME, #NAME, {3, 4, 5, 6} } #define CASE5(NAME) { SpvOp##NAME, #NAME, {3, 4, 5, 6, 7} } #define CASE6(NAME) { SpvOp##NAME, #NAME, {3, 4, 5, 6, 7, 8} } -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( TextToBinaryOpSpecConstantOp, OpSpecConstantOpTestWithIds, ::testing::ValuesIn(std::vector>{ // Conversion @@ -738,7 +742,7 @@ INSTANTIATE_TEST_CASE_P( CASE2(InBoundsPtrAccessChain), CASE3(InBoundsPtrAccessChain), CASE6(InBoundsPtrAccessChain), - }),); + })); #undef CASE1 #undef CASE2 #undef CASE3 @@ -768,7 +772,7 @@ TEST_P(OpSpecConstantOpTestWithTwoIdsThenLiteralNumbers, Assembly) { } #define CASE(NAME) SpvOp##NAME, #NAME -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( TextToBinaryOpSpecConstantOp, OpSpecConstantOpTestWithTwoIdsThenLiteralNumbers, ::testing::ValuesIn(std::vector>{ @@ -783,7 +787,7 @@ INSTANTIATE_TEST_CASE_P( // composite, and then literal indices. {CASE(CompositeInsert), {0}}, {CASE(CompositeInsert), {4, 3, 99, 1}}, - }), ); + })); using OpSpecConstantOpTestWithOneIdThenLiteralNumbers = spvtest::TextToBinaryTestBase<::testing::TestWithParam>>; @@ -806,7 +810,7 @@ TEST_P(OpSpecConstantOpTestWithOneIdThenLiteralNumbers, Assembly) { } #define CASE(NAME) SpvOp##NAME, #NAME -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( TextToBinaryOpSpecConstantOp, OpSpecConstantOpTestWithOneIdThenLiteralNumbers, ::testing::ValuesIn(std::vector>{ @@ -814,7 +818,7 @@ INSTANTIATE_TEST_CASE_P( // indices. Let's only test a few. {CASE(CompositeExtract), {0}}, {CASE(CompositeExtract), {0, 99, 42, 16, 17, 12, 19}}, - }), ); + })); // TODO(dneto): OpConstantTrue // TODO(dneto): OpConstantFalse diff --git a/third_party/spirv-tools/test/text_to_binary.control_flow_test.cpp b/third_party/spirv-tools/test/text_to_binary.control_flow_test.cpp index 07f1108840..ae51f55d99 100644 --- a/third_party/spirv-tools/test/text_to_binary.control_flow_test.cpp +++ b/third_party/spirv-tools/test/text_to_binary.control_flow_test.cpp @@ -51,12 +51,12 @@ TEST_P(OpSelectionMergeTest, AnySingleSelectionControlMask) { // clang-format off #define CASE(VALUE,NAME) { SpvSelectionControl##VALUE, NAME} -INSTANTIATE_TEST_CASE_P(TextToBinarySelectionMerge, OpSelectionMergeTest, +INSTANTIATE_TEST_SUITE_P(TextToBinarySelectionMerge, OpSelectionMergeTest, ValuesIn(std::vector>{ CASE(MaskNone, "None"), CASE(FlattenMask, "Flatten"), CASE(DontFlattenMask, "DontFlatten"), - }),); + })); #undef CASE // clang-format on @@ -95,7 +95,7 @@ TEST_P(OpLoopMergeTest, AnySingleLoopControlMask) { { \ SpvLoopControl##VALUE, NAME, { PARM } \ } -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( TextToBinaryLoopMerge, OpLoopMergeTest, Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1), ValuesIn(std::vector>{ @@ -104,9 +104,9 @@ INSTANTIATE_TEST_CASE_P( CASE(UnrollMask, "Unroll"), CASE(DontUnrollMask, "DontUnroll"), // clang-format on - })), ); + }))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( TextToBinaryLoopMergeV11, OpLoopMergeTest, Combine(Values(SPV_ENV_UNIVERSAL_1_1), ValuesIn(std::vector>{ @@ -116,7 +116,7 @@ INSTANTIATE_TEST_CASE_P( {SpvLoopControlUnrollMask|SpvLoopControlDependencyLengthMask, "DependencyLength|Unroll", {33}}, // clang-format on - })), ); + }))); #undef CASE #undef CASE1 @@ -251,7 +251,7 @@ SwitchTestCase MakeSwitchTestCase(uint32_t integer_width, Concatenate({{2, 3}, encoded_case_value, {4}}))})}}; } -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( TextToBinaryOpSwitchValid1Word, OpSwitchValidTest, ValuesIn(std::vector({ MakeSwitchTestCase(32, 0, "42", {42}, "100", {100}), @@ -270,10 +270,10 @@ INSTANTIATE_TEST_CASE_P( MakeSwitchTestCase(16, 1, "0x8000", {0xffff8000}, "0x8100", {0xffff8100}), MakeSwitchTestCase(16, 0, "0x8000", {0x00008000}, "0x8100", {0x8100}), - })), ); + }))); // NB: The words LOW ORDER bits show up first. -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( TextToBinaryOpSwitchValid2Words, OpSwitchValidTest, ValuesIn(std::vector({ MakeSwitchTestCase(33, 0, "101", {101, 0}, "500", {500, 0}), @@ -291,9 +291,9 @@ INSTANTIATE_TEST_CASE_P( MakeSwitchTestCase(63, 0, "0x500000000", {0, 5}, "12", {12, 0}), MakeSwitchTestCase(64, 0, "0x600000000", {0, 6}, "12", {12, 0}), MakeSwitchTestCase(64, 1, "0x700000123", {0x123, 7}, "12", {12, 0}), - })), ); + }))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( OpSwitchRoundTripUnsignedIntegers, RoundTripTest, ValuesIn(std::vector({ // Unsigned 16-bit. @@ -307,9 +307,9 @@ INSTANTIATE_TEST_CASE_P( // Unsigned 64-bit, three non-default cases. "%1 = OpTypeInt 64 0\n%2 = OpConstant %1 9223372036854775807\n" "OpSwitch %2 %3 100 %4 102 %5 9000000000000000000 %6\n", - })), ); + }))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( OpSwitchRoundTripSignedIntegers, RoundTripTest, ValuesIn(std::vector{ // Signed 16-bit, with two non-default cases @@ -332,7 +332,7 @@ INSTANTIATE_TEST_CASE_P( "OpSwitch %2 %3 100 %4 7000000000 %5 -1000000000000000000 %6\n", "%1 = OpTypeInt 64 1\n%2 = OpConstant %1 -9223372036854775808\n" "OpSwitch %2 %3 100 %4 7000000000 %5 -1000000000000000000 %6\n", - }), ); + })); using OpSwitchInvalidTypeTestCase = spvtest::TextToBinaryTestBase>; @@ -342,14 +342,14 @@ TEST_P(OpSwitchInvalidTypeTestCase, InvalidTypes) { "%1 = " + GetParam() + "\n" "%3 = OpCopyObject %1 %2\n" // We only care the type of the expression - "%4 = OpSwitch %3 %default 32 %c\n"; + " OpSwitch %3 %default 32 %c\n"; EXPECT_THAT(CompileFailure(input), Eq("The selector operand for OpSwitch must be the result of an " "instruction that generates an integer scalar")); } // clang-format off -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( TextToBinaryOpSwitchInvalidTests, OpSwitchInvalidTypeTestCase, ValuesIn(std::vector{ {"OpTypeVoid", @@ -371,11 +371,14 @@ INSTANTIATE_TEST_CASE_P( "OpTypeReserveId", "OpTypeQueue", "OpTypePipe ReadOnly", - "OpTypeForwardPointer %a UniformConstant", - // At least one thing that isn't a type at all + + // Skip OpTypeForwardPointer becasuse it doesn't even produce a result + // ID. + + // At least one thing that isn't a type at all "OpNot %a %b" }, - }),); + })); // clang-format on // TODO(dneto): OpPhi diff --git a/third_party/spirv-tools/test/text_to_binary.debug_test.cpp b/third_party/spirv-tools/test/text_to_binary.debug_test.cpp index b85650e5ec..39ba5c524b 100644 --- a/third_party/spirv-tools/test/text_to_binary.debug_test.cpp +++ b/third_party/spirv-tools/test/text_to_binary.debug_test.cpp @@ -19,6 +19,7 @@ #include #include "gmock/gmock.h" +#include "source/util/string_utils.h" #include "test/test_fixture.h" #include "test/unit_spirv.h" @@ -26,7 +27,7 @@ namespace spvtools { namespace { using spvtest::MakeInstruction; -using spvtest::MakeVector; +using utils::MakeVector; using spvtest::TextToBinaryTest; using ::testing::Eq; @@ -73,8 +74,8 @@ TEST_P(OpSourceTest, AnyLanguage) { GetParam().version}))); } -INSTANTIATE_TEST_CASE_P(TextToBinaryTestDebug, OpSourceTest, - ::testing::ValuesIn(kLanguageCases), ); +INSTANTIATE_TEST_SUITE_P(TextToBinaryTestDebug, OpSourceTest, + ::testing::ValuesIn(kLanguageCases)); TEST_F(OpSourceTest, WrongLanguage) { EXPECT_THAT(CompileFailure("OpSource xxyyzz 12345"), @@ -113,9 +114,9 @@ TEST_P(OpSourceContinuedTest, AnyExtension) { } // TODO(dneto): utf-8, quoting, escaping -INSTANTIATE_TEST_CASE_P(TextToBinaryTestDebug, OpSourceContinuedTest, - ::testing::ValuesIn(std::vector{ - "", "foo bar this and that"}), ); +INSTANTIATE_TEST_SUITE_P(TextToBinaryTestDebug, OpSourceContinuedTest, + ::testing::ValuesIn(std::vector{ + "", "foo bar this and that"})); // Test OpSourceExtension @@ -132,9 +133,9 @@ TEST_P(OpSourceExtensionTest, AnyExtension) { } // TODO(dneto): utf-8, quoting, escaping -INSTANTIATE_TEST_CASE_P(TextToBinaryTestDebug, OpSourceExtensionTest, - ::testing::ValuesIn(std::vector{ - "", "foo bar this and that"}), ); +INSTANTIATE_TEST_SUITE_P(TextToBinaryTestDebug, OpSourceExtensionTest, + ::testing::ValuesIn(std::vector{ + "", "foo bar this and that"})); TEST_F(TextToBinaryTest, OpLine) { EXPECT_THAT(CompiledInstructions("OpLine %srcfile 42 99"), @@ -158,9 +159,9 @@ TEST_P(OpStringTest, AnyString) { } // TODO(dneto): utf-8, quoting, escaping -INSTANTIATE_TEST_CASE_P(TextToBinaryTestDebug, OpStringTest, - ::testing::ValuesIn(std::vector{ - "", "foo bar this and that"}), ); +INSTANTIATE_TEST_SUITE_P(TextToBinaryTestDebug, OpStringTest, + ::testing::ValuesIn(std::vector{ + "", "foo bar this and that"})); using OpNameTest = spvtest::TextToBinaryTestBase<::testing::TestWithParam>; @@ -174,8 +175,8 @@ TEST_P(OpNameTest, AnyString) { // UTF-8, quoting, escaping, etc. are covered in the StringLiterals tests in // BinaryToText.Literal.cpp. -INSTANTIATE_TEST_CASE_P(TextToBinaryTestDebug, OpNameTest, - ::testing::Values("", "foo bar this and that"), ); +INSTANTIATE_TEST_SUITE_P(TextToBinaryTestDebug, OpNameTest, + ::testing::Values("", "foo bar this and that")); using OpMemberNameTest = spvtest::TextToBinaryTestBase<::testing::TestWithParam>; @@ -190,9 +191,9 @@ TEST_P(OpMemberNameTest, AnyString) { } // TODO(dneto): utf-8, quoting, escaping -INSTANTIATE_TEST_CASE_P(TextToBinaryTestDebug, OpMemberNameTest, - ::testing::ValuesIn(std::vector{ - "", "foo bar this and that"}), ); +INSTANTIATE_TEST_SUITE_P(TextToBinaryTestDebug, OpMemberNameTest, + ::testing::ValuesIn(std::vector{ + "", "foo bar this and that"})); // TODO(dneto): Parse failures? @@ -207,8 +208,8 @@ TEST_P(OpModuleProcessedTest, AnyString) { Eq(MakeInstruction(SpvOpModuleProcessed, MakeVector(GetParam())))); } -INSTANTIATE_TEST_CASE_P(TextToBinaryTestDebug, OpModuleProcessedTest, - ::testing::Values("", "foo bar this and that"), ); +INSTANTIATE_TEST_SUITE_P(TextToBinaryTestDebug, OpModuleProcessedTest, + ::testing::Values("", "foo bar this and that")); } // namespace } // namespace spvtools diff --git a/third_party/spirv-tools/test/text_to_binary.device_side_enqueue_test.cpp b/third_party/spirv-tools/test/text_to_binary.device_side_enqueue_test.cpp index 25c100b8ef..03d7e7419f 100644 --- a/third_party/spirv-tools/test/text_to_binary.device_side_enqueue_test.cpp +++ b/third_party/spirv-tools/test/text_to_binary.device_side_enqueue_test.cpp @@ -49,7 +49,7 @@ TEST_P(OpEnqueueKernelGood, Sample) { GetParam().local_size_operands))); } -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( TextToBinaryTest, OpEnqueueKernelGood, ::testing::ValuesIn(std::vector{ // Provide IDs for pointer-to-local arguments for the @@ -71,7 +71,7 @@ INSTANTIATE_TEST_CASE_P( {13, 14, 15, 16, 17, 18, 19, 20, 21}}, {"%l0 %l1 %l2 %l3 %l4 %l5 %l6 %l7 %l8 %l9", {13, 14, 15, 16, 17, 18, 19, 20, 21, 22}}, - }), ); + })); // Test some bad parses of OpEnqueueKernel. For other cases, we're relying // on the uniformity of the parsing algorithm. The following two tests, ensure diff --git a/third_party/spirv-tools/test/text_to_binary.extension_test.cpp b/third_party/spirv-tools/test/text_to_binary.extension_test.cpp index 0d8d324b89..023763b769 100644 --- a/third_party/spirv-tools/test/text_to_binary.extension_test.cpp +++ b/third_party/spirv-tools/test/text_to_binary.extension_test.cpp @@ -22,6 +22,7 @@ #include "gmock/gmock.h" #include "source/latest_version_glsl_std_450_header.h" #include "source/latest_version_opencl_std_header.h" +#include "source/util/string_utils.h" #include "test/test_fixture.h" #include "test/unit_spirv.h" @@ -30,7 +31,7 @@ namespace { using spvtest::Concatenate; using spvtest::MakeInstruction; -using spvtest::MakeVector; +using utils::MakeVector; using spvtest::TextToBinaryTest; using ::testing::Combine; using ::testing::Eq; @@ -135,7 +136,7 @@ TEST_P(ExtensionRoundTripTest, Samples) { // SPV_KHR_shader_ballot -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SPV_KHR_shader_ballot, ExtensionRoundTripTest, // We'll get coverage over operand tables by trying the universal // environments, and at least one specific environment. @@ -164,9 +165,9 @@ INSTANTIATE_TEST_CASE_P( {"OpDecorate %1 BuiltIn SubgroupLtMask\n", MakeInstruction(SpvOpDecorate, {1, SpvDecorationBuiltIn, SpvBuiltInSubgroupLtMaskKHR})}, - })), ); + }))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SPV_KHR_shader_ballot_vulkan_1_1, ExtensionRoundTripTest, // In SPIR-V 1.3 and Vulkan 1.1 we can drop the KHR suffix on the // builtin enums. @@ -194,11 +195,11 @@ INSTANTIATE_TEST_CASE_P( {"OpDecorate %1 BuiltIn SubgroupLtMask\n", MakeInstruction(SpvOpDecorate, {1, SpvDecorationBuiltIn, SpvBuiltInSubgroupLtMask})}, - })), ); + }))); // The old builtin names (with KHR suffix) still work in the assmebler, and // map to the enums without the KHR. -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SPV_KHR_shader_ballot_vulkan_1_1_alias_check, ExtensionAssemblyTest, // In SPIR-V 1.3 and Vulkan 1.1 we can drop the KHR suffix on the // builtin enums. @@ -219,11 +220,11 @@ INSTANTIATE_TEST_CASE_P( {"OpDecorate %1 BuiltIn SubgroupLtMaskKHR\n", MakeInstruction(SpvOpDecorate, {1, SpvDecorationBuiltIn, SpvBuiltInSubgroupLtMask})}, - })), ); + }))); // SPV_KHR_shader_draw_parameters -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SPV_KHR_shader_draw_parameters, ExtensionRoundTripTest, // We'll get coverage over operand tables by trying the universal // environments, and at least one specific environment. @@ -241,11 +242,11 @@ INSTANTIATE_TEST_CASE_P( {"OpDecorate %1 BuiltIn DrawIndex\n", MakeInstruction(SpvOpDecorate, {1, SpvDecorationBuiltIn, SpvBuiltInDrawIndex})}, - })), ); + }))); // SPV_KHR_subgroup_vote -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SPV_KHR_subgroup_vote, ExtensionRoundTripTest, // We'll get coverage over operand tables by trying the universal // environments, and at least one specific environment. @@ -260,11 +261,11 @@ INSTANTIATE_TEST_CASE_P( MakeInstruction(SpvOpSubgroupAllKHR, {1, 2, 3})}, {"%2 = OpSubgroupAllEqualKHR %1 %3\n", MakeInstruction(SpvOpSubgroupAllEqualKHR, {1, 2, 3})}, - })), ); + }))); // SPV_KHR_16bit_storage -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SPV_KHR_16bit_storage, ExtensionRoundTripTest, // We'll get coverage over operand tables by trying the universal // environments, and at least one specific environment. @@ -276,11 +277,11 @@ INSTANTIATE_TEST_CASE_P( {"OpCapability StorageBuffer16BitAccess\n", MakeInstruction(SpvOpCapability, {SpvCapabilityStorageBuffer16BitAccess})}, - {"OpCapability StorageUniform16\n", + {"OpCapability UniformAndStorageBuffer16BitAccess\n", MakeInstruction( SpvOpCapability, {SpvCapabilityUniformAndStorageBuffer16BitAccess})}, - {"OpCapability StorageUniform16\n", + {"OpCapability UniformAndStorageBuffer16BitAccess\n", MakeInstruction(SpvOpCapability, {SpvCapabilityStorageUniform16})}, {"OpCapability StoragePushConstant16\n", @@ -289,9 +290,9 @@ INSTANTIATE_TEST_CASE_P( {"OpCapability StorageInputOutput16\n", MakeInstruction(SpvOpCapability, {SpvCapabilityStorageInputOutput16})}, - })), ); + }))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SPV_KHR_16bit_storage_alias_check, ExtensionAssemblyTest, Combine(ValuesIn(CommonVulkanEnvs()), ValuesIn(std::vector{ @@ -303,11 +304,11 @@ INSTANTIATE_TEST_CASE_P( {"OpCapability UniformAndStorageBuffer16BitAccess\n", MakeInstruction(SpvOpCapability, {SpvCapabilityStorageUniform16})}, - })), ); + }))); // SPV_KHR_device_group -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SPV_KHR_device_group, ExtensionRoundTripTest, // We'll get coverage over operand tables by trying the universal // environments, and at least one specific environment. @@ -318,11 +319,11 @@ INSTANTIATE_TEST_CASE_P( {"OpDecorate %1 BuiltIn DeviceIndex\n", MakeInstruction(SpvOpDecorate, {1, SpvDecorationBuiltIn, SpvBuiltInDeviceIndex})}, - })), ); + }))); // SPV_KHR_8bit_storage -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SPV_KHR_8bit_storage, ExtensionRoundTripTest, // We'll get coverage over operand tables by trying the universal // environments, and at least one specific environment. @@ -338,11 +339,11 @@ INSTANTIATE_TEST_CASE_P( {"OpCapability StoragePushConstant8\n", MakeInstruction(SpvOpCapability, {SpvCapabilityStoragePushConstant8})}, - })), ); + }))); // SPV_KHR_multiview -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SPV_KHR_multiview, ExtensionRoundTripTest, // We'll get coverage over operand tables by trying the universal // environments, and at least one specific environment. @@ -354,13 +355,13 @@ INSTANTIATE_TEST_CASE_P( {"OpDecorate %1 BuiltIn ViewIndex\n", MakeInstruction(SpvOpDecorate, {1, SpvDecorationBuiltIn, SpvBuiltInViewIndex})}, - })), ); + }))); // SPV_AMD_shader_explicit_vertex_parameter #define PREAMBLE \ "%1 = OpExtInstImport \"SPV_AMD_shader_explicit_vertex_parameter\"\n" -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SPV_AMD_shader_explicit_vertex_parameter, ExtensionRoundTripTest, // We'll get coverage over operand tables by trying the universal // environments, and at least one specific environment. @@ -374,13 +375,13 @@ INSTANTIATE_TEST_CASE_P( SpvOpExtInstImport, {1}, MakeVector("SPV_AMD_shader_explicit_vertex_parameter")), MakeInstruction(SpvOpExtInst, {2, 3, 1, 1, 4, 5})})}, - })), ); + }))); #undef PREAMBLE // SPV_AMD_shader_trinary_minmax #define PREAMBLE "%1 = OpExtInstImport \"SPV_AMD_shader_trinary_minmax\"\n" -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SPV_AMD_shader_trinary_minmax, ExtensionRoundTripTest, // We'll get coverage over operand tables by trying the universal // environments, and at least one specific environment. @@ -433,13 +434,13 @@ INSTANTIATE_TEST_CASE_P( {MakeInstruction(SpvOpExtInstImport, {1}, MakeVector("SPV_AMD_shader_trinary_minmax")), MakeInstruction(SpvOpExtInst, {2, 3, 1, 9, 4, 5, 6})})}, - })), ); + }))); #undef PREAMBLE // SPV_AMD_gcn_shader #define PREAMBLE "%1 = OpExtInstImport \"SPV_AMD_gcn_shader\"\n" -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SPV_AMD_gcn_shader, ExtensionRoundTripTest, // We'll get coverage over operand tables by trying the universal // environments, and at least one specific environment. @@ -458,13 +459,13 @@ INSTANTIATE_TEST_CASE_P( Concatenate({MakeInstruction(SpvOpExtInstImport, {1}, MakeVector("SPV_AMD_gcn_shader")), MakeInstruction(SpvOpExtInst, {2, 3, 1, 3})})}, - })), ); + }))); #undef PREAMBLE // SPV_AMD_shader_ballot #define PREAMBLE "%1 = OpExtInstImport \"SPV_AMD_shader_ballot\"\n" -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SPV_AMD_shader_ballot, ExtensionRoundTripTest, // We'll get coverage over operand tables by trying the universal // environments, and at least one specific environment. @@ -490,12 +491,12 @@ INSTANTIATE_TEST_CASE_P( Concatenate({MakeInstruction(SpvOpExtInstImport, {1}, MakeVector("SPV_AMD_shader_ballot")), MakeInstruction(SpvOpExtInst, {2, 3, 1, 4, 4})})}, - })), ); + }))); #undef PREAMBLE // SPV_KHR_variable_pointers -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SPV_KHR_variable_pointers, ExtensionRoundTripTest, // We'll get coverage over operand tables by trying the universal // environments, and at least one specific environment. @@ -508,12 +509,186 @@ INSTANTIATE_TEST_CASE_P( {"OpCapability VariablePointersStorageBuffer\n", MakeInstruction(SpvOpCapability, {SpvCapabilityVariablePointersStorageBuffer})}, - })), ); + }))); + +// SPV_KHR_vulkan_memory_model + +INSTANTIATE_TEST_SUITE_P( + SPV_KHR_vulkan_memory_model, ExtensionRoundTripTest, + // We'll get coverage over operand tables by trying the universal + // environments, and at least one specific environment. + // + // Note: SPV_KHR_vulkan_memory_model adds scope enum value QueueFamilyKHR. + // Scope enums are used in ID definitions elsewhere, that don't know they + // are using particular enums. So the assembler doesn't support assembling + // those enums names into the corresponding values. So there is no asm/dis + // tests for those enums. + Combine( + Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1, + SPV_ENV_UNIVERSAL_1_3, SPV_ENV_VULKAN_1_0, SPV_ENV_VULKAN_1_1), + ValuesIn(std::vector{ + {"OpCapability VulkanMemoryModel\n", + MakeInstruction(SpvOpCapability, + {SpvCapabilityVulkanMemoryModelKHR})}, + {"OpCapability VulkanMemoryModelDeviceScope\n", + MakeInstruction(SpvOpCapability, + {SpvCapabilityVulkanMemoryModelDeviceScopeKHR})}, + {"OpMemoryModel Logical Vulkan\n", + MakeInstruction(SpvOpMemoryModel, {SpvAddressingModelLogical, + SpvMemoryModelVulkanKHR})}, + {"OpStore %1 %2 MakePointerAvailable %3\n", + MakeInstruction(SpvOpStore, + {1, 2, SpvMemoryAccessMakePointerAvailableKHRMask, + 3})}, + {"OpStore %1 %2 Volatile|MakePointerAvailable %3\n", + MakeInstruction(SpvOpStore, + {1, 2, + int(SpvMemoryAccessMakePointerAvailableKHRMask) | + int(SpvMemoryAccessVolatileMask), + 3})}, + {"OpStore %1 %2 Aligned|MakePointerAvailable 4 %3\n", + MakeInstruction(SpvOpStore, + {1, 2, + int(SpvMemoryAccessMakePointerAvailableKHRMask) | + int(SpvMemoryAccessAlignedMask), + 4, 3})}, + {"OpStore %1 %2 MakePointerAvailable|NonPrivatePointer %3\n", + MakeInstruction(SpvOpStore, + {1, 2, + int(SpvMemoryAccessMakePointerAvailableKHRMask) | + int(SpvMemoryAccessNonPrivatePointerKHRMask), + 3})}, + {"%2 = OpLoad %1 %3 MakePointerVisible %4\n", + MakeInstruction(SpvOpLoad, + {1, 2, 3, SpvMemoryAccessMakePointerVisibleKHRMask, + 4})}, + {"%2 = OpLoad %1 %3 Volatile|MakePointerVisible %4\n", + MakeInstruction(SpvOpLoad, + {1, 2, 3, + int(SpvMemoryAccessMakePointerVisibleKHRMask) | + int(SpvMemoryAccessVolatileMask), + 4})}, + {"%2 = OpLoad %1 %3 Aligned|MakePointerVisible 8 %4\n", + MakeInstruction(SpvOpLoad, + {1, 2, 3, + int(SpvMemoryAccessMakePointerVisibleKHRMask) | + int(SpvMemoryAccessAlignedMask), + 8, 4})}, + {"%2 = OpLoad %1 %3 MakePointerVisible|NonPrivatePointer " + "%4\n", + MakeInstruction(SpvOpLoad, + {1, 2, 3, + int(SpvMemoryAccessMakePointerVisibleKHRMask) | + int(SpvMemoryAccessNonPrivatePointerKHRMask), + 4})}, + {"OpCopyMemory %1 %2 " + "MakePointerAvailable|" + "MakePointerVisible|" + "NonPrivatePointer " + "%3 %4\n", + MakeInstruction(SpvOpCopyMemory, + {1, 2, + (int(SpvMemoryAccessMakePointerVisibleKHRMask) | + int(SpvMemoryAccessMakePointerAvailableKHRMask) | + int(SpvMemoryAccessNonPrivatePointerKHRMask)), + 3, 4})}, + {"OpCopyMemorySized %1 %2 %3 " + "MakePointerAvailable|" + "MakePointerVisible|" + "NonPrivatePointer " + "%4 %5\n", + MakeInstruction(SpvOpCopyMemorySized, + {1, 2, 3, + (int(SpvMemoryAccessMakePointerVisibleKHRMask) | + int(SpvMemoryAccessMakePointerAvailableKHRMask) | + int(SpvMemoryAccessNonPrivatePointerKHRMask)), + 4, 5})}, + // Image operands + {"OpImageWrite %1 %2 %3 MakeTexelAvailable " + "%4\n", + MakeInstruction( + SpvOpImageWrite, + {1, 2, 3, int(SpvImageOperandsMakeTexelAvailableKHRMask), 4})}, + {"OpImageWrite %1 %2 %3 MakeTexelAvailable|NonPrivateTexel " + "%4\n", + MakeInstruction(SpvOpImageWrite, + {1, 2, 3, + int(SpvImageOperandsMakeTexelAvailableKHRMask) | + int(SpvImageOperandsNonPrivateTexelKHRMask), + 4})}, + {"OpImageWrite %1 %2 %3 " + "MakeTexelAvailable|NonPrivateTexel|VolatileTexel " + "%4\n", + MakeInstruction(SpvOpImageWrite, + {1, 2, 3, + int(SpvImageOperandsMakeTexelAvailableKHRMask) | + int(SpvImageOperandsNonPrivateTexelKHRMask) | + int(SpvImageOperandsVolatileTexelKHRMask), + 4})}, + {"%2 = OpImageRead %1 %3 %4 MakeTexelVisible " + "%5\n", + MakeInstruction(SpvOpImageRead, + {1, 2, 3, 4, + int(SpvImageOperandsMakeTexelVisibleKHRMask), + 5})}, + {"%2 = OpImageRead %1 %3 %4 " + "MakeTexelVisible|NonPrivateTexel " + "%5\n", + MakeInstruction(SpvOpImageRead, + {1, 2, 3, 4, + int(SpvImageOperandsMakeTexelVisibleKHRMask) | + int(SpvImageOperandsNonPrivateTexelKHRMask), + 5})}, + {"%2 = OpImageRead %1 %3 %4 " + "MakeTexelVisible|NonPrivateTexel|VolatileTexel " + "%5\n", + MakeInstruction(SpvOpImageRead, + {1, 2, 3, 4, + int(SpvImageOperandsMakeTexelVisibleKHRMask) | + int(SpvImageOperandsNonPrivateTexelKHRMask) | + int(SpvImageOperandsVolatileTexelKHRMask), + 5})}, + + // Memory semantics ID values are numbers put into a SPIR-V + // constant integer referenced by Id. There is no token for + // them, and so no assembler or disassembler support required. + // Similar for Scope ID. + }))); // SPV_GOOGLE_decorate_string -INSTANTIATE_TEST_CASE_P( +// Now that OpDecorateString is the preferred spelling for +// OpDecorateStringGOOGLE use that name in round trip tests, and the GOOGLE +// name in an assembly-only test. + +INSTANTIATE_TEST_SUITE_P( SPV_GOOGLE_decorate_string, ExtensionRoundTripTest, + Combine( + // We'll get coverage over operand tables by trying the universal + // environments, and at least one specific environment. + Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1, + SPV_ENV_UNIVERSAL_1_2, SPV_ENV_VULKAN_1_0), + ValuesIn(std::vector{ + {"OpDecorateString %1 UserSemantic \"ABC\"\n", + MakeInstruction(SpvOpDecorateStringGOOGLE, + {1, SpvDecorationHlslSemanticGOOGLE}, + MakeVector("ABC"))}, + {"OpDecorateString %1 UserSemantic \"ABC\"\n", + MakeInstruction(SpvOpDecorateString, + {1, SpvDecorationUserSemantic}, + MakeVector("ABC"))}, + {"OpMemberDecorateString %1 3 UserSemantic \"DEF\"\n", + MakeInstruction(SpvOpMemberDecorateStringGOOGLE, + {1, 3, SpvDecorationUserSemantic}, + MakeVector("DEF"))}, + {"OpMemberDecorateString %1 3 UserSemantic \"DEF\"\n", + MakeInstruction(SpvOpMemberDecorateString, + {1, 3, SpvDecorationUserSemantic}, + MakeVector("DEF"))}, + }))); + +INSTANTIATE_TEST_SUITE_P( + SPV_GOOGLE_decorate_string, ExtensionAssemblyTest, Combine( // We'll get coverage over operand tables by trying the universal // environments, and at least one specific environment. @@ -528,12 +703,33 @@ INSTANTIATE_TEST_CASE_P( MakeInstruction(SpvOpMemberDecorateStringGOOGLE, {1, 3, SpvDecorationHlslSemanticGOOGLE}, MakeVector("DEF"))}, - })), ); + }))); // SPV_GOOGLE_hlsl_functionality1 -INSTANTIATE_TEST_CASE_P( +// Now that CounterBuffer is the preferred spelling for HlslCounterBufferGOOGLE, +// use that name in round trip tests, and the GOOGLE name in an assembly-only +// test. +INSTANTIATE_TEST_SUITE_P( SPV_GOOGLE_hlsl_functionality1, ExtensionRoundTripTest, + Combine( + // We'll get coverage over operand tables by trying the universal + // environments, and at least one specific environment. + Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1, + SPV_ENV_UNIVERSAL_1_2, SPV_ENV_VULKAN_1_0), + // HlslSemanticGOOGLE is tested in SPV_GOOGLE_decorate_string, since + // they are coupled together. + ValuesIn(std::vector{ + {"OpDecorateId %1 CounterBuffer %2\n", + MakeInstruction(SpvOpDecorateId, + {1, SpvDecorationHlslCounterBufferGOOGLE, 2})}, + {"OpDecorateId %1 CounterBuffer %2\n", + MakeInstruction(SpvOpDecorateId, + {1, SpvDecorationCounterBuffer, 2})}, + }))); + +INSTANTIATE_TEST_SUITE_P( + SPV_GOOGLE_hlsl_functionality1, ExtensionAssemblyTest, Combine( // We'll get coverage over operand tables by trying the universal // environments, and at least one specific environment. @@ -545,11 +741,11 @@ INSTANTIATE_TEST_CASE_P( {"OpDecorateId %1 HlslCounterBufferGOOGLE %2\n", MakeInstruction(SpvOpDecorateId, {1, SpvDecorationHlslCounterBufferGOOGLE, 2})}, - })), ); + }))); // SPV_NV_viewport_array2 -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SPV_NV_viewport_array2, ExtensionRoundTripTest, Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1, SPV_ENV_UNIVERSAL_1_2, SPV_ENV_UNIVERSAL_1_3, @@ -573,11 +769,11 @@ INSTANTIATE_TEST_CASE_P( {"OpDecorate %1 BuiltIn ViewportMaskNV\n", MakeInstruction(SpvOpDecorate, {1, SpvDecorationBuiltIn, SpvBuiltInViewportMaskNV})}, - })), ); + }))); // SPV_NV_shader_subgroup_partitioned -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SPV_NV_shader_subgroup_partitioned, ExtensionRoundTripTest, Combine( Values(SPV_ENV_UNIVERSAL_1_3, SPV_ENV_VULKAN_1_1), @@ -615,11 +811,11 @@ INSTANTIATE_TEST_CASE_P( SpvGroupOperationPartitionedExclusiveScanNV, 4})}, {"%2 = OpGroupIAdd %1 %3 PartitionedExclusiveScanNV %4\n", MakeInstruction(SpvOpGroupIAdd, {1, 2, 3, 8, 4})}, - })), ); + }))); // SPV_EXT_descriptor_indexing -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SPV_EXT_descriptor_indexing, ExtensionRoundTripTest, Combine( Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1, @@ -630,84 +826,84 @@ INSTANTIATE_TEST_CASE_P( MakeInstruction(SpvOpExtension, MakeVector("SPV_EXT_descriptor_indexing"))}, // Check capabilities, by name - {"OpCapability ShaderNonUniformEXT\n", + {"OpCapability ShaderNonUniform\n", MakeInstruction(SpvOpCapability, {SpvCapabilityShaderNonUniformEXT})}, - {"OpCapability RuntimeDescriptorArrayEXT\n", + {"OpCapability RuntimeDescriptorArray\n", MakeInstruction(SpvOpCapability, {SpvCapabilityRuntimeDescriptorArrayEXT})}, - {"OpCapability InputAttachmentArrayDynamicIndexingEXT\n", + {"OpCapability InputAttachmentArrayDynamicIndexing\n", MakeInstruction( SpvOpCapability, {SpvCapabilityInputAttachmentArrayDynamicIndexingEXT})}, - {"OpCapability UniformTexelBufferArrayDynamicIndexingEXT\n", + {"OpCapability UniformTexelBufferArrayDynamicIndexing\n", MakeInstruction( SpvOpCapability, {SpvCapabilityUniformTexelBufferArrayDynamicIndexingEXT})}, - {"OpCapability StorageTexelBufferArrayDynamicIndexingEXT\n", + {"OpCapability StorageTexelBufferArrayDynamicIndexing\n", MakeInstruction( SpvOpCapability, {SpvCapabilityStorageTexelBufferArrayDynamicIndexingEXT})}, - {"OpCapability UniformBufferArrayNonUniformIndexingEXT\n", + {"OpCapability UniformBufferArrayNonUniformIndexing\n", MakeInstruction( SpvOpCapability, {SpvCapabilityUniformBufferArrayNonUniformIndexingEXT})}, - {"OpCapability SampledImageArrayNonUniformIndexingEXT\n", + {"OpCapability SampledImageArrayNonUniformIndexing\n", MakeInstruction( SpvOpCapability, {SpvCapabilitySampledImageArrayNonUniformIndexingEXT})}, - {"OpCapability StorageBufferArrayNonUniformIndexingEXT\n", + {"OpCapability StorageBufferArrayNonUniformIndexing\n", MakeInstruction( SpvOpCapability, {SpvCapabilityStorageBufferArrayNonUniformIndexingEXT})}, - {"OpCapability StorageImageArrayNonUniformIndexingEXT\n", + {"OpCapability StorageImageArrayNonUniformIndexing\n", MakeInstruction( SpvOpCapability, {SpvCapabilityStorageImageArrayNonUniformIndexingEXT})}, - {"OpCapability InputAttachmentArrayNonUniformIndexingEXT\n", + {"OpCapability InputAttachmentArrayNonUniformIndexing\n", MakeInstruction( SpvOpCapability, {SpvCapabilityInputAttachmentArrayNonUniformIndexingEXT})}, - {"OpCapability UniformTexelBufferArrayNonUniformIndexingEXT\n", + {"OpCapability UniformTexelBufferArrayNonUniformIndexing\n", MakeInstruction( SpvOpCapability, {SpvCapabilityUniformTexelBufferArrayNonUniformIndexingEXT})}, - {"OpCapability StorageTexelBufferArrayNonUniformIndexingEXT\n", + {"OpCapability StorageTexelBufferArrayNonUniformIndexing\n", MakeInstruction( SpvOpCapability, {SpvCapabilityStorageTexelBufferArrayNonUniformIndexingEXT})}, // Check capabilities, by number - {"OpCapability ShaderNonUniformEXT\n", + {"OpCapability ShaderNonUniform\n", MakeInstruction(SpvOpCapability, {5301})}, - {"OpCapability RuntimeDescriptorArrayEXT\n", + {"OpCapability RuntimeDescriptorArray\n", MakeInstruction(SpvOpCapability, {5302})}, - {"OpCapability InputAttachmentArrayDynamicIndexingEXT\n", + {"OpCapability InputAttachmentArrayDynamicIndexing\n", MakeInstruction(SpvOpCapability, {5303})}, - {"OpCapability UniformTexelBufferArrayDynamicIndexingEXT\n", + {"OpCapability UniformTexelBufferArrayDynamicIndexing\n", MakeInstruction(SpvOpCapability, {5304})}, - {"OpCapability StorageTexelBufferArrayDynamicIndexingEXT\n", + {"OpCapability StorageTexelBufferArrayDynamicIndexing\n", MakeInstruction(SpvOpCapability, {5305})}, - {"OpCapability UniformBufferArrayNonUniformIndexingEXT\n", + {"OpCapability UniformBufferArrayNonUniformIndexing\n", MakeInstruction(SpvOpCapability, {5306})}, - {"OpCapability SampledImageArrayNonUniformIndexingEXT\n", + {"OpCapability SampledImageArrayNonUniformIndexing\n", MakeInstruction(SpvOpCapability, {5307})}, - {"OpCapability StorageBufferArrayNonUniformIndexingEXT\n", + {"OpCapability StorageBufferArrayNonUniformIndexing\n", MakeInstruction(SpvOpCapability, {5308})}, - {"OpCapability StorageImageArrayNonUniformIndexingEXT\n", + {"OpCapability StorageImageArrayNonUniformIndexing\n", MakeInstruction(SpvOpCapability, {5309})}, - {"OpCapability InputAttachmentArrayNonUniformIndexingEXT\n", + {"OpCapability InputAttachmentArrayNonUniformIndexing\n", MakeInstruction(SpvOpCapability, {5310})}, - {"OpCapability UniformTexelBufferArrayNonUniformIndexingEXT\n", + {"OpCapability UniformTexelBufferArrayNonUniformIndexing\n", MakeInstruction(SpvOpCapability, {5311})}, - {"OpCapability StorageTexelBufferArrayNonUniformIndexingEXT\n", + {"OpCapability StorageTexelBufferArrayNonUniformIndexing\n", MakeInstruction(SpvOpCapability, {5312})}, // Check the decoration token - {"OpDecorate %1 NonUniformEXT\n", + {"OpDecorate %1 NonUniform\n", MakeInstruction(SpvOpDecorate, {1, SpvDecorationNonUniformEXT})}, - {"OpDecorate %1 NonUniformEXT\n", + {"OpDecorate %1 NonUniform\n", MakeInstruction(SpvOpDecorate, {1, 5300})}, - })), ); + }))); } // namespace } // namespace spvtools diff --git a/third_party/spirv-tools/test/text_to_binary.function_test.cpp b/third_party/spirv-tools/test/text_to_binary.function_test.cpp index 748461fb19..55a8e6ce6c 100644 --- a/third_party/spirv-tools/test/text_to_binary.function_test.cpp +++ b/third_party/spirv-tools/test/text_to_binary.function_test.cpp @@ -45,14 +45,14 @@ TEST_P(OpFunctionControlTest, AnySingleFunctionControlMask) { // clang-format off #define CASE(VALUE,NAME) { SpvFunctionControl##VALUE, NAME } -INSTANTIATE_TEST_CASE_P(TextToBinaryFunctionTest, OpFunctionControlTest, +INSTANTIATE_TEST_SUITE_P(TextToBinaryFunctionTest, OpFunctionControlTest, ::testing::ValuesIn(std::vector>{ CASE(MaskNone, "None"), CASE(InlineMask, "Inline"), CASE(DontInlineMask, "DontInline"), CASE(PureMask, "Pure"), CASE(ConstMask, "Const"), - }),); + })); #undef CASE // clang-format on diff --git a/third_party/spirv-tools/test/text_to_binary.group_test.cpp b/third_party/spirv-tools/test/text_to_binary.group_test.cpp index 2f4b76d2f2..becc3aa6f0 100644 --- a/third_party/spirv-tools/test/text_to_binary.group_test.cpp +++ b/third_party/spirv-tools/test/text_to_binary.group_test.cpp @@ -44,12 +44,12 @@ TEST_P(GroupOperationTest, AnyGroupOperation) { // clang-format off #define CASE(NAME) { SpvGroupOperation##NAME, #NAME} -INSTANTIATE_TEST_CASE_P(TextToBinaryGroupOperation, GroupOperationTest, +INSTANTIATE_TEST_SUITE_P(TextToBinaryGroupOperation, GroupOperationTest, ::testing::ValuesIn(std::vector>{ CASE(Reduce), CASE(InclusiveScan), CASE(ExclusiveScan), - }),); + })); #undef CASE // clang-format on diff --git a/third_party/spirv-tools/test/text_to_binary.image_test.cpp b/third_party/spirv-tools/test/text_to_binary.image_test.cpp index c1adedf448..d445369c2b 100644 --- a/third_party/spirv-tools/test/text_to_binary.image_test.cpp +++ b/third_party/spirv-tools/test/text_to_binary.image_test.cpp @@ -50,7 +50,7 @@ TEST_P(ImageOperandsTest, Sample) { } #define MASK(NAME) SpvImageOperands##NAME##Mask -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( TextToBinaryImageOperandsAny, ImageOperandsTest, ::testing::ValuesIn(std::vector{ // TODO(dneto): Rev32 adds many more values, and rearranges their @@ -66,10 +66,10 @@ INSTANTIATE_TEST_CASE_P( {" ConstOffsets %5", {MASK(ConstOffsets), 5}}, {" Sample %5", {MASK(Sample), 5}}, {" MinLod %5", {MASK(MinLod), 5}}, - }), ); + })); #undef MASK #define MASK(NAME) static_cast(SpvImageOperands##NAME##Mask) -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( TextToBinaryImageOperandsCombination, ImageOperandsTest, ::testing::ValuesIn(std::vector{ // TODO(dneto): Rev32 adds many more values, and rearranges their @@ -95,7 +95,7 @@ INSTANTIATE_TEST_CASE_P( " %5 %6 %7 %8 %9 %10 %11 %12", {MASK(Bias) | MASK(Lod) | MASK(Grad) | MASK(ConstOffset) | MASK(Offset) | MASK(ConstOffsets) | MASK(Sample), - 5, 6, 7, 8, 9, 10, 11, 12}}}), ); + 5, 6, 7, 8, 9, 10, 11, 12}}})); #undef MASK TEST_F(ImageOperandsTest, WrongOperand) { @@ -173,24 +173,24 @@ TEST_P(ImageSparseReadImageOperandsTest, Sample) { } #define MASK(NAME) SpvImageOperands##NAME##Mask -INSTANTIATE_TEST_CASE_P(ImageSparseReadImageOperandsAny, - ImageSparseReadImageOperandsTest, - ::testing::ValuesIn(std::vector{ - // Image operands are optional. - {"", {}}, - // Test each kind, alone. - {" Bias %5", {MASK(Bias), 5}}, - {" Lod %5", {MASK(Lod), 5}}, - {" Grad %5 %6", {MASK(Grad), 5, 6}}, - {" ConstOffset %5", {MASK(ConstOffset), 5}}, - {" Offset %5", {MASK(Offset), 5}}, - {" ConstOffsets %5", {MASK(ConstOffsets), 5}}, - {" Sample %5", {MASK(Sample), 5}}, - {" MinLod %5", {MASK(MinLod), 5}}, - }), ); +INSTANTIATE_TEST_SUITE_P(ImageSparseReadImageOperandsAny, + ImageSparseReadImageOperandsTest, + ::testing::ValuesIn(std::vector{ + // Image operands are optional. + {"", {}}, + // Test each kind, alone. + {" Bias %5", {MASK(Bias), 5}}, + {" Lod %5", {MASK(Lod), 5}}, + {" Grad %5 %6", {MASK(Grad), 5, 6}}, + {" ConstOffset %5", {MASK(ConstOffset), 5}}, + {" Offset %5", {MASK(Offset), 5}}, + {" ConstOffsets %5", {MASK(ConstOffsets), 5}}, + {" Sample %5", {MASK(Sample), 5}}, + {" MinLod %5", {MASK(MinLod), 5}}, + })); #undef MASK #define MASK(NAME) static_cast(SpvImageOperands##NAME##Mask) -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( ImageSparseReadImageOperandsCombination, ImageSparseReadImageOperandsTest, ::testing::ValuesIn(std::vector{ // values. @@ -212,7 +212,7 @@ INSTANTIATE_TEST_CASE_P( 5, 6, 7, 8, 9, 10, 11, 12}}, // Don't try the masks reversed, since this is a round trip test, // and the disassembler will sort them. - }), ); + })); #undef MASK TEST_F(OpImageSparseReadTest, InvalidTypeOperand) { diff --git a/third_party/spirv-tools/test/text_to_binary.memory_test.cpp b/third_party/spirv-tools/test/text_to_binary.memory_test.cpp index ead08e6fda..7b09ed5877 100644 --- a/third_party/spirv-tools/test/text_to_binary.memory_test.cpp +++ b/third_party/spirv-tools/test/text_to_binary.memory_test.cpp @@ -30,6 +30,7 @@ using spvtest::EnumCase; using spvtest::MakeInstruction; using spvtest::TextToBinaryTest; using ::testing::Eq; +using ::testing::HasSubstr; // Test assembly of Memory Access masks @@ -45,14 +46,14 @@ TEST_P(MemoryAccessTest, AnySingleMemoryAccessMask) { GetParam().operands()))); } -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( TextToBinaryMemoryAccessTest, MemoryAccessTest, ::testing::ValuesIn(std::vector>{ {SpvMemoryAccessMaskNone, "None", {}}, {SpvMemoryAccessVolatileMask, "Volatile", {}}, {SpvMemoryAccessAlignedMask, "Aligned", {16}}, {SpvMemoryAccessNontemporalMask, "Nontemporal", {}}, - }), ); + })); TEST_F(TextToBinaryTest, CombinedMemoryAccessMask) { const std::string input = "OpStore %ptr %value Volatile|Aligned 16"; @@ -76,7 +77,7 @@ TEST_P(StorageClassTest, AnyStorageClass) { // clang-format off #define CASE(NAME) { SpvStorageClass##NAME, #NAME, {} } -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( TextToBinaryStorageClassTest, StorageClassTest, ::testing::ValuesIn(std::vector>{ CASE(UniformConstant), @@ -91,16 +92,330 @@ INSTANTIATE_TEST_CASE_P( CASE(PushConstant), CASE(AtomicCounter), CASE(Image), - }),); + })); #undef CASE // clang-format on +using MemoryRoundTripTest = RoundTripTest; + +// OpPtrEqual appeared in SPIR-V 1.4 + +TEST_F(MemoryRoundTripTest, OpPtrEqualGood) { + std::string spirv = "%2 = OpPtrEqual %1 %3 %4\n"; + EXPECT_THAT(CompiledInstructions(spirv, SPV_ENV_UNIVERSAL_1_4), + Eq(MakeInstruction(SpvOpPtrEqual, {1, 2, 3, 4}))); + std::string disassembly = EncodeAndDecodeSuccessfully( + spirv, SPV_BINARY_TO_TEXT_OPTION_NONE, SPV_ENV_UNIVERSAL_1_4); + EXPECT_THAT(disassembly, Eq(spirv)); +} + +TEST_F(MemoryRoundTripTest, OpPtrEqualV13Bad) { + std::string spirv = "%2 = OpPtrEqual %1 %3 %4\n"; + std::string err = CompileFailure(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_THAT(err, HasSubstr("Invalid Opcode name 'OpPtrEqual'")); +} + +// OpPtrNotEqual appeared in SPIR-V 1.4 + +TEST_F(MemoryRoundTripTest, OpPtrNotEqualGood) { + std::string spirv = "%2 = OpPtrNotEqual %1 %3 %4\n"; + EXPECT_THAT(CompiledInstructions(spirv, SPV_ENV_UNIVERSAL_1_4), + Eq(MakeInstruction(SpvOpPtrNotEqual, {1, 2, 3, 4}))); + std::string disassembly = EncodeAndDecodeSuccessfully( + spirv, SPV_BINARY_TO_TEXT_OPTION_NONE, SPV_ENV_UNIVERSAL_1_4); + EXPECT_THAT(disassembly, Eq(spirv)); +} + +TEST_F(MemoryRoundTripTest, OpPtrNotEqualV13Bad) { + std::string spirv = "%2 = OpPtrNotEqual %1 %3 %4\n"; + std::string err = CompileFailure(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_THAT(err, HasSubstr("Invalid Opcode name 'OpPtrNotEqual'")); +} + +// OpPtrDiff appeared in SPIR-V 1.4 + +TEST_F(MemoryRoundTripTest, OpPtrDiffGood) { + std::string spirv = "%2 = OpPtrDiff %1 %3 %4\n"; + EXPECT_THAT(CompiledInstructions(spirv, SPV_ENV_UNIVERSAL_1_4), + Eq(MakeInstruction(SpvOpPtrDiff, {1, 2, 3, 4}))); + std::string disassembly = EncodeAndDecodeSuccessfully( + spirv, SPV_BINARY_TO_TEXT_OPTION_NONE, SPV_ENV_UNIVERSAL_1_4); + EXPECT_THAT(disassembly, Eq(spirv)); +} + +TEST_F(MemoryRoundTripTest, OpPtrDiffV13Good) { + // OpPtrDiff is enabled by a capability as well, so we can assemble + // it even in older SPIR-V environments. We do that so we can + // write tests. + std::string spirv = "%2 = OpPtrDiff %1 %3 %4\n"; + std::string disassembly = EncodeAndDecodeSuccessfully( + spirv, SPV_BINARY_TO_TEXT_OPTION_NONE, SPV_ENV_UNIVERSAL_1_4); +} + +// OpCopyMemory + +TEST_F(MemoryRoundTripTest, OpCopyMemoryNoMemAccessGood) { + std::string spirv = "OpCopyMemory %1 %2\n"; + EXPECT_THAT(CompiledInstructions(spirv), + Eq(MakeInstruction(SpvOpCopyMemory, {1, 2}))); + std::string disassembly = + EncodeAndDecodeSuccessfully(spirv, SPV_BINARY_TO_TEXT_OPTION_NONE); + EXPECT_THAT(disassembly, Eq(spirv)); +} + +TEST_F(MemoryRoundTripTest, OpCopyMemoryTooFewArgsBad) { + std::string spirv = "OpCopyMemory %1\n"; + std::string err = CompileFailure(spirv); + EXPECT_THAT(err, HasSubstr("Expected operand, found end of stream")); +} + +TEST_F(MemoryRoundTripTest, OpCopyMemoryTooManyArgsBad) { + std::string spirv = "OpCopyMemory %1 %2 %3\n"; + std::string err = CompileFailure(spirv); + EXPECT_THAT(err, HasSubstr("Invalid memory access operand '%3'")); +} + +TEST_F(MemoryRoundTripTest, OpCopyMemoryAccessNoneGood) { + std::string spirv = "OpCopyMemory %1 %2 None\n"; + EXPECT_THAT(CompiledInstructions(spirv), + Eq(MakeInstruction(SpvOpCopyMemory, {1, 2, 0}))); + std::string disassembly = + EncodeAndDecodeSuccessfully(spirv, SPV_BINARY_TO_TEXT_OPTION_NONE); + EXPECT_THAT(disassembly, Eq(spirv)); +} + +TEST_F(MemoryRoundTripTest, OpCopyMemoryAccessVolatileGood) { + std::string spirv = "OpCopyMemory %1 %2 Volatile\n"; + EXPECT_THAT(CompiledInstructions(spirv), + Eq(MakeInstruction(SpvOpCopyMemory, {1, 2, 1}))); + std::string disassembly = + EncodeAndDecodeSuccessfully(spirv, SPV_BINARY_TO_TEXT_OPTION_NONE); + EXPECT_THAT(disassembly, Eq(spirv)); +} + +TEST_F(MemoryRoundTripTest, OpCopyMemoryAccessAligned8Good) { + std::string spirv = "OpCopyMemory %1 %2 Aligned 8\n"; + EXPECT_THAT(CompiledInstructions(spirv), + Eq(MakeInstruction(SpvOpCopyMemory, {1, 2, 2, 8}))); + std::string disassembly = + EncodeAndDecodeSuccessfully(spirv, SPV_BINARY_TO_TEXT_OPTION_NONE); + EXPECT_THAT(disassembly, Eq(spirv)); +} + +TEST_F(MemoryRoundTripTest, OpCopyMemoryAccessNontemporalGood) { + std::string spirv = "OpCopyMemory %1 %2 Nontemporal\n"; + EXPECT_THAT(CompiledInstructions(spirv), + Eq(MakeInstruction(SpvOpCopyMemory, {1, 2, 4}))); + std::string disassembly = + EncodeAndDecodeSuccessfully(spirv, SPV_BINARY_TO_TEXT_OPTION_NONE); + EXPECT_THAT(disassembly, Eq(spirv)); +} + +TEST_F(MemoryRoundTripTest, OpCopyMemoryAccessAvGood) { + std::string spirv = "OpCopyMemory %1 %2 MakePointerAvailable %3\n"; + EXPECT_THAT(CompiledInstructions(spirv), + Eq(MakeInstruction(SpvOpCopyMemory, {1, 2, 8, 3}))); + std::string disassembly = + EncodeAndDecodeSuccessfully(spirv, SPV_BINARY_TO_TEXT_OPTION_NONE); + EXPECT_THAT(disassembly, Eq(spirv)); +} + +TEST_F(MemoryRoundTripTest, OpCopyMemoryAccessVisGood) { + std::string spirv = "OpCopyMemory %1 %2 MakePointerVisible %3\n"; + EXPECT_THAT(CompiledInstructions(spirv), + Eq(MakeInstruction(SpvOpCopyMemory, {1, 2, 16, 3}))); + std::string disassembly = + EncodeAndDecodeSuccessfully(spirv, SPV_BINARY_TO_TEXT_OPTION_NONE); + EXPECT_THAT(disassembly, Eq(spirv)); +} + +TEST_F(MemoryRoundTripTest, OpCopyMemoryAccessNonPrivateGood) { + std::string spirv = "OpCopyMemory %1 %2 NonPrivatePointer\n"; + EXPECT_THAT(CompiledInstructions(spirv), + Eq(MakeInstruction(SpvOpCopyMemory, {1, 2, 32}))); + std::string disassembly = + EncodeAndDecodeSuccessfully(spirv, SPV_BINARY_TO_TEXT_OPTION_NONE); + EXPECT_THAT(disassembly, Eq(spirv)); +} + +TEST_F(MemoryRoundTripTest, OpCopyMemoryAccessMixedGood) { + std::string spirv = + "OpCopyMemory %1 %2 " + "Volatile|Aligned|Nontemporal|MakePointerAvailable|" + "MakePointerVisible|NonPrivatePointer 16 %3 %4\n"; + EXPECT_THAT(CompiledInstructions(spirv), + Eq(MakeInstruction(SpvOpCopyMemory, {1, 2, 63, 16, 3, 4}))); + std::string disassembly = + EncodeAndDecodeSuccessfully(spirv, SPV_BINARY_TO_TEXT_OPTION_NONE); + EXPECT_THAT(disassembly, Eq(spirv)); +} + +TEST_F(MemoryRoundTripTest, OpCopyMemoryTwoAccessV13Good) { + std::string spirv = "OpCopyMemory %1 %2 Volatile Volatile\n"; + // Note: This will assemble but should not validate for SPIR-V 1.3 + EXPECT_THAT(CompiledInstructions(spirv, SPV_ENV_UNIVERSAL_1_3), + Eq(MakeInstruction(SpvOpCopyMemory, {1, 2, 1, 1}))); + std::string disassembly = + EncodeAndDecodeSuccessfully(spirv, SPV_BINARY_TO_TEXT_OPTION_NONE); + EXPECT_THAT(disassembly, Eq(spirv)); +} + +TEST_F(MemoryRoundTripTest, OpCopyMemoryTwoAccessV14Good) { + std::string spirv = "OpCopyMemory %1 %2 Volatile Volatile\n"; + EXPECT_THAT(CompiledInstructions(spirv, SPV_ENV_UNIVERSAL_1_4), + Eq(MakeInstruction(SpvOpCopyMemory, {1, 2, 1, 1}))); + std::string disassembly = + EncodeAndDecodeSuccessfully(spirv, SPV_BINARY_TO_TEXT_OPTION_NONE); + EXPECT_THAT(disassembly, Eq(spirv)); +} + +TEST_F(MemoryRoundTripTest, OpCopyMemoryTwoAccessMixedV14Good) { + std::string spirv = + "OpCopyMemory %1 %2 Volatile|Nontemporal|" + "MakePointerVisible %3 " + "Aligned|MakePointerAvailable|NonPrivatePointer 16 %4\n"; + EXPECT_THAT(CompiledInstructions(spirv), + Eq(MakeInstruction(SpvOpCopyMemory, {1, 2, 21, 3, 42, 16, 4}))); + std::string disassembly = + EncodeAndDecodeSuccessfully(spirv, SPV_BINARY_TO_TEXT_OPTION_NONE); + EXPECT_THAT(disassembly, Eq(spirv)); +} + +// OpCopyMemorySized + +TEST_F(MemoryRoundTripTest, OpCopyMemorySizedNoMemAccessGood) { + std::string spirv = "OpCopyMemorySized %1 %2 %3\n"; + EXPECT_THAT(CompiledInstructions(spirv), + Eq(MakeInstruction(SpvOpCopyMemorySized, {1, 2, 3}))); + std::string disassembly = + EncodeAndDecodeSuccessfully(spirv, SPV_BINARY_TO_TEXT_OPTION_NONE); + EXPECT_THAT(disassembly, Eq(spirv)); +} + +TEST_F(MemoryRoundTripTest, OpCopyMemorySizedTooFewArgsBad) { + std::string spirv = "OpCopyMemorySized %1 %2\n"; + std::string err = CompileFailure(spirv); + EXPECT_THAT(err, HasSubstr("Expected operand, found end of stream")); +} + +TEST_F(MemoryRoundTripTest, OpCopyMemorySizedTooManyArgsBad) { + std::string spirv = "OpCopyMemorySized %1 %2 %3 %4\n"; + std::string err = CompileFailure(spirv); + EXPECT_THAT(err, HasSubstr("Invalid memory access operand '%4'")); +} + +TEST_F(MemoryRoundTripTest, OpCopyMemorySizedAccessNoneGood) { + std::string spirv = "OpCopyMemorySized %1 %2 %3 None\n"; + EXPECT_THAT(CompiledInstructions(spirv), + Eq(MakeInstruction(SpvOpCopyMemorySized, {1, 2, 3, 0}))); + std::string disassembly = + EncodeAndDecodeSuccessfully(spirv, SPV_BINARY_TO_TEXT_OPTION_NONE); + EXPECT_THAT(disassembly, Eq(spirv)); +} + +TEST_F(MemoryRoundTripTest, OpCopyMemorySizedAccessVolatileGood) { + std::string spirv = "OpCopyMemorySized %1 %2 %3 Volatile\n"; + EXPECT_THAT(CompiledInstructions(spirv), + Eq(MakeInstruction(SpvOpCopyMemorySized, {1, 2, 3, 1}))); + std::string disassembly = + EncodeAndDecodeSuccessfully(spirv, SPV_BINARY_TO_TEXT_OPTION_NONE); + EXPECT_THAT(disassembly, Eq(spirv)); +} + +TEST_F(MemoryRoundTripTest, OpCopyMemorySizedAccessAligned8Good) { + std::string spirv = "OpCopyMemorySized %1 %2 %3 Aligned 8\n"; + EXPECT_THAT(CompiledInstructions(spirv), + Eq(MakeInstruction(SpvOpCopyMemorySized, {1, 2, 3, 2, 8}))); + std::string disassembly = + EncodeAndDecodeSuccessfully(spirv, SPV_BINARY_TO_TEXT_OPTION_NONE); + EXPECT_THAT(disassembly, Eq(spirv)); +} + +TEST_F(MemoryRoundTripTest, OpCopyMemorySizedAccessNontemporalGood) { + std::string spirv = "OpCopyMemorySized %1 %2 %3 Nontemporal\n"; + EXPECT_THAT(CompiledInstructions(spirv), + Eq(MakeInstruction(SpvOpCopyMemorySized, {1, 2, 3, 4}))); + std::string disassembly = + EncodeAndDecodeSuccessfully(spirv, SPV_BINARY_TO_TEXT_OPTION_NONE); + EXPECT_THAT(disassembly, Eq(spirv)); +} + +TEST_F(MemoryRoundTripTest, OpCopyMemorySizedAccessAvGood) { + std::string spirv = "OpCopyMemorySized %1 %2 %3 MakePointerAvailable %4\n"; + EXPECT_THAT(CompiledInstructions(spirv), + Eq(MakeInstruction(SpvOpCopyMemorySized, {1, 2, 3, 8, 4}))); + std::string disassembly = + EncodeAndDecodeSuccessfully(spirv, SPV_BINARY_TO_TEXT_OPTION_NONE); + EXPECT_THAT(disassembly, Eq(spirv)); +} + +TEST_F(MemoryRoundTripTest, OpCopyMemorySizedAccessVisGood) { + std::string spirv = "OpCopyMemorySized %1 %2 %3 MakePointerVisible %4\n"; + EXPECT_THAT(CompiledInstructions(spirv), + Eq(MakeInstruction(SpvOpCopyMemorySized, {1, 2, 3, 16, 4}))); + std::string disassembly = + EncodeAndDecodeSuccessfully(spirv, SPV_BINARY_TO_TEXT_OPTION_NONE); + EXPECT_THAT(disassembly, Eq(spirv)); +} + +TEST_F(MemoryRoundTripTest, OpCopyMemorySizedAccessNonPrivateGood) { + std::string spirv = "OpCopyMemorySized %1 %2 %3 NonPrivatePointer\n"; + EXPECT_THAT(CompiledInstructions(spirv), + Eq(MakeInstruction(SpvOpCopyMemorySized, {1, 2, 3, 32}))); + std::string disassembly = + EncodeAndDecodeSuccessfully(spirv, SPV_BINARY_TO_TEXT_OPTION_NONE); + EXPECT_THAT(disassembly, Eq(spirv)); +} + +TEST_F(MemoryRoundTripTest, OpCopyMemorySizedAccessMixedGood) { + std::string spirv = + "OpCopyMemorySized %1 %2 %3 " + "Volatile|Aligned|Nontemporal|MakePointerAvailable|" + "MakePointerVisible|NonPrivatePointer 16 %4 %5\n"; + EXPECT_THAT( + CompiledInstructions(spirv), + Eq(MakeInstruction(SpvOpCopyMemorySized, {1, 2, 3, 63, 16, 4, 5}))); + std::string disassembly = + EncodeAndDecodeSuccessfully(spirv, SPV_BINARY_TO_TEXT_OPTION_NONE); + EXPECT_THAT(disassembly, Eq(spirv)); +} + +TEST_F(MemoryRoundTripTest, OpCopyMemorySizedTwoAccessV13Good) { + std::string spirv = "OpCopyMemorySized %1 %2 %3 Volatile Volatile\n"; + // Note: This will assemble but should not validate for SPIR-V 1.3 + EXPECT_THAT(CompiledInstructions(spirv, SPV_ENV_UNIVERSAL_1_3), + Eq(MakeInstruction(SpvOpCopyMemorySized, {1, 2, 3, 1, 1}))); + std::string disassembly = + EncodeAndDecodeSuccessfully(spirv, SPV_BINARY_TO_TEXT_OPTION_NONE); + EXPECT_THAT(disassembly, Eq(spirv)); +} + +TEST_F(MemoryRoundTripTest, OpCopyMemorySizedTwoAccessV14Good) { + std::string spirv = "OpCopyMemorySized %1 %2 %3 Volatile Volatile\n"; + EXPECT_THAT(CompiledInstructions(spirv, SPV_ENV_UNIVERSAL_1_4), + Eq(MakeInstruction(SpvOpCopyMemorySized, {1, 2, 3, 1, 1}))); + std::string disassembly = + EncodeAndDecodeSuccessfully(spirv, SPV_BINARY_TO_TEXT_OPTION_NONE); + EXPECT_THAT(disassembly, Eq(spirv)); +} + +TEST_F(MemoryRoundTripTest, OpCopyMemorySizedTwoAccessMixedV14Good) { + std::string spirv = + "OpCopyMemorySized %1 %2 %3 Volatile|Nontemporal|" + "MakePointerVisible %4 " + "Aligned|MakePointerAvailable|NonPrivatePointer 16 %5\n"; + EXPECT_THAT( + CompiledInstructions(spirv), + Eq(MakeInstruction(SpvOpCopyMemorySized, {1, 2, 3, 21, 4, 42, 16, 5}))); + std::string disassembly = + EncodeAndDecodeSuccessfully(spirv, SPV_BINARY_TO_TEXT_OPTION_NONE); + EXPECT_THAT(disassembly, Eq(spirv)); +} + // TODO(dneto): OpVariable with initializers // TODO(dneto): OpImageTexelPointer // TODO(dneto): OpLoad // TODO(dneto): OpStore -// TODO(dneto): OpCopyMemory -// TODO(dneto): OpCopyMemorySized // TODO(dneto): OpAccessChain // TODO(dneto): OpInBoundsAccessChain // TODO(dneto): OpPtrAccessChain diff --git a/third_party/spirv-tools/test/text_to_binary.mode_setting_test.cpp b/third_party/spirv-tools/test/text_to_binary.mode_setting_test.cpp index ed4fa2fb41..8ddf42196b 100644 --- a/third_party/spirv-tools/test/text_to_binary.mode_setting_test.cpp +++ b/third_party/spirv-tools/test/text_to_binary.mode_setting_test.cpp @@ -20,6 +20,7 @@ #include #include "gmock/gmock.h" +#include "source/util/string_utils.h" #include "test/test_fixture.h" #include "test/unit_spirv.h" @@ -28,7 +29,7 @@ namespace { using spvtest::EnumCase; using spvtest::MakeInstruction; -using spvtest::MakeVector; +using utils::MakeVector; using ::testing::Combine; using ::testing::Eq; using ::testing::TestWithParam; @@ -69,7 +70,7 @@ TEST_P(OpMemoryModelTest, AnyMemoryModelCase) { #MEMORY \ } // clang-format off -INSTANTIATE_TEST_CASE_P(TextToBinaryMemoryModel, OpMemoryModelTest, +INSTANTIATE_TEST_SUITE_P(TextToBinaryMemoryModel, OpMemoryModelTest, ValuesIn(std::vector{ // These cases exercise each addressing model, and // each memory model, but not necessarily in @@ -78,7 +79,7 @@ INSTANTIATE_TEST_CASE_P(TextToBinaryMemoryModel, OpMemoryModelTest, CASE(Logical,GLSL450), CASE(Physical32,OpenCL), CASE(Physical64,OpenCL), - }),); + })); #undef CASE // clang-format on @@ -116,7 +117,7 @@ TEST_P(OpEntryPointTest, AnyEntryPointCase) { // clang-format off #define CASE(NAME) SpvExecutionModel##NAME, #NAME -INSTANTIATE_TEST_CASE_P(TextToBinaryEntryPoint, OpEntryPointTest, +INSTANTIATE_TEST_SUITE_P(TextToBinaryEntryPoint, OpEntryPointTest, ValuesIn(std::vector{ { CASE(Vertex), "" }, { CASE(TessellationControl), "my tess" }, @@ -125,7 +126,7 @@ INSTANTIATE_TEST_CASE_P(TextToBinaryEntryPoint, OpEntryPointTest, { CASE(Fragment), "FAT32" }, { CASE(GLCompute), "cubic" }, { CASE(Kernel), "Sanders" }, - }),); + })); #undef CASE // clang-format on @@ -151,7 +152,7 @@ TEST_P(OpExecutionModeTest, AnyExecutionMode) { } #define CASE(NAME) SpvExecutionMode##NAME, #NAME -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( TextToBinaryExecutionMode, OpExecutionModeTest, Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1), ValuesIn(std::vector>{ @@ -188,16 +189,16 @@ INSTANTIATE_TEST_CASE_P( {CASE(OutputTriangleStrip), {}}, {CASE(VecTypeHint), {96}}, {CASE(ContractionOff), {}}, - })), ); + }))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( TextToBinaryExecutionModeV11, OpExecutionModeTest, Combine(Values(SPV_ENV_UNIVERSAL_1_1), ValuesIn(std::vector>{ {CASE(Initializer)}, {CASE(Finalizer)}, {CASE(SubgroupSize), {12}}, - {CASE(SubgroupsPerWorkgroup), {64}}})), ); + {CASE(SubgroupsPerWorkgroup), {64}}}))); #undef CASE TEST_F(OpExecutionModeTest, WrongMode) { @@ -224,7 +225,7 @@ TEST_P(OpCapabilityTest, AnyCapability) { // clang-format off #define CASE(NAME) { SpvCapability##NAME, #NAME } -INSTANTIATE_TEST_CASE_P(TextToBinaryCapability, OpCapabilityTest, +INSTANTIATE_TEST_SUITE_P(TextToBinaryCapability, OpCapabilityTest, ValuesIn(std::vector>{ CASE(Matrix), CASE(Shader), @@ -280,7 +281,7 @@ INSTANTIATE_TEST_CASE_P(TextToBinaryCapability, OpCapabilityTest, CASE(DerivativeControl), CASE(InterpolationFunction), CASE(TransformFeedback), - }),); + })); #undef CASE // clang-format on diff --git a/third_party/spirv-tools/test/text_to_binary.type_declaration_test.cpp b/third_party/spirv-tools/test/text_to_binary.type_declaration_test.cpp index c6f158f299..1589188fda 100644 --- a/third_party/spirv-tools/test/text_to_binary.type_declaration_test.cpp +++ b/third_party/spirv-tools/test/text_to_binary.type_declaration_test.cpp @@ -48,7 +48,7 @@ TEST_P(DimTest, AnyDim) { // clang-format off #define CASE(NAME) {SpvDim##NAME, #NAME} -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( TextToBinaryDim, DimTest, ::testing::ValuesIn(std::vector>{ CASE(1D), @@ -58,7 +58,7 @@ INSTANTIATE_TEST_CASE_P( CASE(Rect), CASE(Buffer), CASE(SubpassData), - }),); + })); #undef CASE // clang-format on @@ -84,7 +84,7 @@ TEST_P(ImageFormatTest, AnyImageFormatAndNoAccessQualifier) { // clang-format off #define CASE(NAME) {SpvImageFormat##NAME, #NAME} -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( TextToBinaryImageFormat, ImageFormatTest, ::testing::ValuesIn(std::vector>{ CASE(Unknown), @@ -127,7 +127,7 @@ INSTANTIATE_TEST_CASE_P( CASE(Rg8ui), CASE(R16ui), CASE(R8ui), - }),); + })); #undef CASE // clang-format on @@ -153,13 +153,13 @@ TEST_P(ImageAccessQualifierTest, AnyAccessQualifier) { // clang-format off #define CASE(NAME) {SpvAccessQualifier##NAME, #NAME} -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( AccessQualifier, ImageAccessQualifierTest, ::testing::ValuesIn(std::vector>{ CASE(ReadOnly), CASE(WriteOnly), CASE(ReadWrite), - }),); + })); // clang-format on #undef CASE @@ -178,13 +178,13 @@ TEST_P(OpTypePipeTest, AnyAccessQualifier) { // clang-format off #define CASE(NAME) {SpvAccessQualifier##NAME, #NAME} -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( TextToBinaryTypePipe, OpTypePipeTest, ::testing::ValuesIn(std::vector>{ CASE(ReadOnly), CASE(WriteOnly), CASE(ReadWrite), - }),); + })); #undef CASE // clang-format on diff --git a/third_party/spirv-tools/test/text_to_binary_test.cpp b/third_party/spirv-tools/test/text_to_binary_test.cpp index 4ba37ad4de..57f0a6ce0b 100644 --- a/third_party/spirv-tools/test/text_to_binary_test.cpp +++ b/third_party/spirv-tools/test/text_to_binary_test.cpp @@ -58,7 +58,7 @@ TEST_P(GoodMaskParseTest, GoodMaskExpressions) { spvContextDestroy(context); } -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( ParseMask, GoodMaskParseTest, ::testing::ValuesIn(std::vector{ {SPV_OPERAND_TYPE_FP_FAST_MATH_MODE, 0, "None"}, @@ -87,7 +87,7 @@ INSTANTIATE_TEST_CASE_P( {SPV_OPERAND_TYPE_FUNCTION_CONTROL, 4, "Pure"}, {SPV_OPERAND_TYPE_FUNCTION_CONTROL, 8, "Const"}, {SPV_OPERAND_TYPE_FUNCTION_CONTROL, 0xd, "Inline|Const|Pure"}, - }), ); + })); using BadFPFastMathMaskParseTest = ::testing::TestWithParam; @@ -102,12 +102,12 @@ TEST_P(BadFPFastMathMaskParseTest, BadMaskExpressions) { spvContextDestroy(context); } -INSTANTIATE_TEST_CASE_P(ParseMask, BadFPFastMathMaskParseTest, - ::testing::ValuesIn(std::vector{ - nullptr, "", "NotValidEnum", "|", "NotInf|", - "|NotInf", "NotInf||NotNaN", - "Unroll" // A good word, but for the wrong enum - }), ); +INSTANTIATE_TEST_SUITE_P(ParseMask, BadFPFastMathMaskParseTest, + ::testing::ValuesIn(std::vector{ + nullptr, "", "NotValidEnum", "|", "NotInf|", + "|NotInf", "NotInf||NotNaN", + "Unroll" // A good word, but for the wrong enum + })); TEST_F(TextToBinaryTest, InvalidText) { ASSERT_EQ(SPV_ERROR_INVALID_TEXT, @@ -197,7 +197,7 @@ TEST_P(TextToBinaryFloatValueTest, Samples) { {1, 2, GetParam().second})}))); } -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( FloatValues, TextToBinaryFloatValueTest, ::testing::ValuesIn(std::vector>{ {"0.0", 0x00000000}, // +0 @@ -213,7 +213,7 @@ INSTANTIATE_TEST_CASE_P( {"-2.5", 0xc0200000}, {"!0xff800000", 0xff800000}, // -inf {"!0xff800001", 0xff800001}, // NaN - }), ); + })); using TextToBinaryHalfValueTest = spvtest::TextToBinaryTestBase< ::testing::TestWithParam>>; @@ -227,7 +227,7 @@ TEST_P(TextToBinaryHalfValueTest, Samples) { {1, 2, GetParam().second})}))); } -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( HalfValues, TextToBinaryHalfValueTest, ::testing::ValuesIn(std::vector>{ {"0.0", 0x00000000}, @@ -245,7 +245,7 @@ INSTANTIATE_TEST_CASE_P( {"0x1.8p4", 0x00004e00}, {"0x1.801p4", 0x00004e00}, {"0x1.804p4", 0x00004e01}, - }), ); + })); TEST(CreateContext, InvalidEnvironment) { spv_target_env env; diff --git a/third_party/spirv-tools/test/timer_test.cpp b/third_party/spirv-tools/test/timer_test.cpp index e53af66538..84ab46dab7 100644 --- a/third_party/spirv-tools/test/timer_test.cpp +++ b/third_party/spirv-tools/test/timer_test.cpp @@ -97,7 +97,7 @@ class MockCumulativeTimer : public CumulativeTimer { long PageFault() const override { return count_stop_ * 3600L; } // Calling Stop() does nothing but just increases |count_stop_| by 1. - void Stop() override { ++count_stop_; }; + void Stop() override { ++count_stop_; } private: unsigned int count_stop_; diff --git a/third_party/spirv-tools/test/tools/CMakeLists.txt b/third_party/spirv-tools/test/tools/CMakeLists.txt index cee95cadbd..99f9780c55 100644 --- a/third_party/spirv-tools/test/tools/CMakeLists.txt +++ b/third_party/spirv-tools/test/tools/CMakeLists.txt @@ -12,7 +12,10 @@ # See the License for the specific language governing permissions and # limitations under the License. -spirv_add_nosetests(expect) -spirv_add_nosetests(spirv_test_framework) - +add_test(NAME spirv-tools_expect_unittests + COMMAND ${PYTHON_EXECUTABLE} -m unittest expect_unittest.py + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) +add_test(NAME spirv-tools_spirv_test_framework_unittests + COMMAND ${PYTHON_EXECUTABLE} -m unittest spirv_test_framework_unittest.py + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) add_subdirectory(opt) diff --git a/third_party/spirv-tools/test/tools/expect.py b/third_party/spirv-tools/test/tools/expect.py index c9596506ad..0b51adc9c2 100755 --- a/third_party/spirv-tools/test/tools/expect.py +++ b/third_party/spirv-tools/test/tools/expect.py @@ -18,15 +18,20 @@ as superclass and providing the expected_* variables required by the check_*() methods in the mixin classes. """ import difflib +import functools import os import re import subprocess +import traceback from spirv_test_framework import SpirvTest +from builtins import bytes +DEFAULT_SPIRV_VERSION = 0x010000 def convert_to_unix_line_endings(source): """Converts all line endings in source to be unix line endings.""" - return source.replace('\r\n', '\n').replace('\r', '\n') + result = source.replace('\r\n', '\n').replace('\r', '\n') + return result def substitute_file_extension(filename, extension): @@ -74,6 +79,15 @@ class ReturnCodeIsZero(SpirvTest): return True, '' +class ReturnCodeIsNonZero(SpirvTest): + """Mixin class for checking that the return code is not zero.""" + + def check_return_code_is_nonzero(self, status): + if not status.returncode: + return False, 'return code is 0' + return True, '' + + class NoOutputOnStdout(SpirvTest): """Mixin class for checking that there is no output on stdout.""" @@ -133,7 +147,7 @@ class CorrectBinaryLengthAndPreamble(SpirvTest): word = binary[index * 4:(index + 1) * 4] if little_endian: word = reversed(word) - return reduce(lambda w, b: (w << 8) | ord(b), word, 0) + return functools.reduce(lambda w, b: (w << 8) | b, word, 0) def check_endianness(binary): """Checks the endianness of the given SPIR-V binary. @@ -169,7 +183,7 @@ class CorrectBinaryLengthAndPreamble(SpirvTest): # profile if version != spv_version and version != 0: - return False, 'Incorrect SPV binary: wrong version number' + return False, 'Incorrect SPV binary: wrong version number: ' + hex(version) + ' expected ' + hex(spv_version) # Shaderc-over-Glslang (0x000d....) or # SPIRV-Tools (0x0007....) generator number if read_word(preamble, 2, little_endian) != 0x000d0007 and \ @@ -185,7 +199,9 @@ class CorrectBinaryLengthAndPreamble(SpirvTest): class CorrectObjectFilePreamble(CorrectBinaryLengthAndPreamble): """Provides methods for verifying preamble for a SPV object file.""" - def verify_object_file_preamble(self, filename, spv_version=0x10000): + def verify_object_file_preamble(self, + filename, + spv_version=DEFAULT_SPIRV_VERSION): """Checks that the given SPIR-V binary file has correct preamble.""" success, message = verify_file_non_empty(filename) @@ -254,6 +270,21 @@ class ValidObjectFile1_3(ReturnCodeIsZero, CorrectObjectFilePreamble): return True, '' +class ValidObjectFile1_5(ReturnCodeIsZero, CorrectObjectFilePreamble): + """Mixin class for checking that every input file generates a valid SPIR-V 1.5 + object file following the object file naming rule, and there is no output on + stdout/stderr.""" + + def check_object_file_preamble(self, status): + for input_filename in status.input_filenames: + object_filename = get_object_filename(input_filename) + success, message = self.verify_object_file_preamble( + os.path.join(status.directory, object_filename), 0x10500) + if not success: + return False, message + return True, '' + + class ValidObjectFileWithAssemblySubstr(SuccessfulReturn, CorrectObjectFilePreamble): """Mixin class for checking that every input file generates a valid object @@ -564,8 +595,8 @@ class StdoutMatch(SpirvTest): 'Expected:\n{ex}'.format( ac=status.stdout, ex=self.expected_stdout)) else: - if not self.expected_stdout.search( - convert_to_unix_line_endings(status.stdout)): + converted = convert_to_unix_line_endings(status.stdout) + if not self.expected_stdout.search(converted): return False, ('Incorrect stdout output:\n{ac}\n' 'Expected to match regex:\n{ex}'.format( ac=status.stdout, ex=self.expected_stdout.pattern)) diff --git a/third_party/spirv-tools/test/tools/expect_nosetest.py b/third_party/spirv-tools/test/tools/expect_nosetest.py deleted file mode 100755 index b591a2d076..0000000000 --- a/third_party/spirv-tools/test/tools/expect_nosetest.py +++ /dev/null @@ -1,80 +0,0 @@ -# Copyright (c) 2018 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. -"""Tests for the expect module.""" - -import expect -from spirv_test_framework import TestStatus -from nose.tools import assert_equal, assert_true, assert_false -import re - - -def nosetest_get_object_name(): - """Tests get_object_filename().""" - source_and_object_names = [('a.vert', 'a.vert.spv'), ('b.frag', 'b.frag.spv'), - ('c.tesc', 'c.tesc.spv'), ('d.tese', 'd.tese.spv'), - ('e.geom', 'e.geom.spv'), ('f.comp', 'f.comp.spv'), - ('file', 'file.spv'), ('file.', 'file.spv'), - ('file.uk', - 'file.spv'), ('file.vert.', - 'file.vert.spv'), ('file.vert.bla', - 'file.vert.spv')] - actual_object_names = [ - expect.get_object_filename(f[0]) for f in source_and_object_names - ] - expected_object_names = [f[1] for f in source_and_object_names] - - assert_equal(actual_object_names, expected_object_names) - - -class TestStdoutMatchADotC(expect.StdoutMatch): - expected_stdout = re.compile('a.c') - - -def nosetest_stdout_match_regex_has_match(): - test = TestStdoutMatchADotC() - status = TestStatus( - test_manager=None, - returncode=0, - stdout='0abc1', - stderr=None, - directory=None, - inputs=None, - input_filenames=None) - assert_true(test.check_stdout_match(status)[0]) - - -def nosetest_stdout_match_regex_no_match(): - test = TestStdoutMatchADotC() - status = TestStatus( - test_manager=None, - returncode=0, - stdout='ab', - stderr=None, - directory=None, - inputs=None, - input_filenames=None) - assert_false(test.check_stdout_match(status)[0]) - - -def nosetest_stdout_match_regex_empty_stdout(): - test = TestStdoutMatchADotC() - status = TestStatus( - test_manager=None, - returncode=0, - stdout='', - stderr=None, - directory=None, - inputs=None, - input_filenames=None) - assert_false(test.check_stdout_match(status)[0]) diff --git a/third_party/spirv-tools/test/tools/expect_unittest.py b/third_party/spirv-tools/test/tools/expect_unittest.py new file mode 100644 index 0000000000..a28de1b976 --- /dev/null +++ b/third_party/spirv-tools/test/tools/expect_unittest.py @@ -0,0 +1,82 @@ +# Copyright (c) 2019 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. +"""Tests for the expect module.""" + +import expect +from spirv_test_framework import TestStatus +import re +import unittest + + +class TestStdoutMatchADotC(expect.StdoutMatch): + expected_stdout = re.compile('a.c') + + +class TestExpect(unittest.TestCase): + def test_get_object_name(self): + """Tests get_object_filename().""" + source_and_object_names = [('a.vert', 'a.vert.spv'), + ('b.frag', 'b.frag.spv'), + ('c.tesc', 'c.tesc.spv'), + ('d.tese', 'd.tese.spv'), + ('e.geom', 'e.geom.spv'), + ('f.comp', 'f.comp.spv'), + ('file', 'file.spv'), ('file.', 'file.spv'), + ('file.uk', + 'file.spv'), ('file.vert.', + 'file.vert.spv'), + ('file.vert.bla', + 'file.vert.spv')] + actual_object_names = [ + expect.get_object_filename(f[0]) for f in source_and_object_names + ] + expected_object_names = [f[1] for f in source_and_object_names] + + self.assertEqual(actual_object_names, expected_object_names) + + def test_stdout_match_regex_has_match(self): + test = TestStdoutMatchADotC() + status = TestStatus( + test_manager=None, + returncode=0, + stdout=b'0abc1', + stderr=None, + directory=None, + inputs=None, + input_filenames=None) + self.assertTrue(test.check_stdout_match(status)[0]) + + def test_stdout_match_regex_no_match(self): + test = TestStdoutMatchADotC() + status = TestStatus( + test_manager=None, + returncode=0, + stdout=b'ab', + stderr=None, + directory=None, + inputs=None, + input_filenames=None) + self.assertFalse(test.check_stdout_match(status)[0]) + + def test_stdout_match_regex_empty_stdout(self): + test = TestStdoutMatchADotC() + status = TestStatus( + test_manager=None, + returncode=0, + stdout=b'', + stderr=None, + directory=None, + inputs=None, + input_filenames=None) + self.assertFalse(test.check_stdout_match(status)[0]) diff --git a/third_party/spirv-tools/test/tools/opt/CMakeLists.txt b/third_party/spirv-tools/test/tools/opt/CMakeLists.txt index a6dc5262d0..21aa247f1f 100644 --- a/third_party/spirv-tools/test/tools/opt/CMakeLists.txt +++ b/third_party/spirv-tools/test/tools/opt/CMakeLists.txt @@ -14,7 +14,7 @@ if(NOT ${SPIRV_SKIP_TESTS}) if(${PYTHONINTERP_FOUND}) - add_test(NAME spirv_opt_tests + add_test(NAME spirv_opt_cli_tools_tests COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/../spirv_test_framework.py $ $ $ diff --git a/third_party/spirv-tools/test/tools/opt/flags.py b/third_party/spirv-tools/test/tools/opt/flags.py index 628d87108c..2f6c0a7937 100644 --- a/third_party/spirv-tools/test/tools/opt/flags.py +++ b/third_party/spirv-tools/test/tools/opt/flags.py @@ -34,7 +34,7 @@ def empty_main_assembly(): @inside_spirv_testsuite('SpirvOptBase') -class TestAssemblyFileAsOnlyParameter(expect.ValidObjectFile1_3): +class TestAssemblyFileAsOnlyParameter(expect.ValidObjectFile1_5): """Tests that spirv-opt accepts a SPIR-V object file.""" shader = placeholder.FileSPIRVShader(empty_main_assembly(), '.spvasm') @@ -52,14 +52,14 @@ class TestHelpFlag(expect.ReturnCodeIsZero, expect.StdoutMatch): @inside_spirv_testsuite('SpirvOptFlags') -class TestValidPassFlags(expect.ValidObjectFile1_3, +class TestValidPassFlags(expect.ValidObjectFile1_5, expect.ExecutedListOfPasses): """Tests that spirv-opt accepts all valid optimization flags.""" flags = [ - '--ccp', '--cfg-cleanup', '--combine-access-chains', '--compact-ids', + '--wrap-opkill', '--ccp', '--cfg-cleanup', '--combine-access-chains', '--compact-ids', '--convert-local-access-chains', '--copy-propagate-arrays', - '--eliminate-common-uniform', '--eliminate-dead-branches', + '--eliminate-dead-branches', '--eliminate-dead-code-aggressive', '--eliminate-dead-const', '--eliminate-dead-functions', '--eliminate-dead-inserts', '--eliminate-dead-variables', '--eliminate-insert-extract', @@ -76,13 +76,13 @@ class TestValidPassFlags(expect.ValidObjectFile1_3, '--unify-const' ] expected_passes = [ + 'wrap-opkill', 'ccp', 'cfg-cleanup', 'combine-access-chains', 'compact-ids', 'convert-local-access-chains', 'copy-propagate-arrays', - 'eliminate-common-uniform', 'eliminate-dead-branches', 'eliminate-dead-code-aggressive', 'eliminate-dead-const', @@ -91,7 +91,7 @@ class TestValidPassFlags(expect.ValidObjectFile1_3, 'eliminate-dead-variables', # --eliminate-insert-extract runs the simplify-instructions pass. 'simplify-instructions', - 'eliminate-local-multi-store', + 'ssa-rewrite', 'eliminate-local-single-block', 'eliminate-local-single-store', 'flatten-decorations', @@ -129,12 +129,14 @@ class TestValidPassFlags(expect.ValidObjectFile1_3, @inside_spirv_testsuite('SpirvOptFlags') -class TestPerformanceOptimizationPasses(expect.ValidObjectFile1_3, +class TestPerformanceOptimizationPasses(expect.ValidObjectFile1_5, expect.ExecutedListOfPasses): """Tests that spirv-opt schedules all the passes triggered by -O.""" flags = ['-O'] expected_passes = [ + 'wrap-opkill', + 'eliminate-dead-branches', 'merge-return', 'inline-entry-points-exhaustive', 'eliminate-dead-code-aggressive', @@ -147,7 +149,7 @@ class TestPerformanceOptimizationPasses(expect.ValidObjectFile1_3, 'eliminate-local-single-block', 'eliminate-local-single-store', 'eliminate-dead-code-aggressive', - 'eliminate-local-multi-store', + 'ssa-rewrite', 'eliminate-dead-code-aggressive', 'ccp', 'eliminate-dead-code-aggressive', @@ -175,36 +177,45 @@ class TestPerformanceOptimizationPasses(expect.ValidObjectFile1_3, @inside_spirv_testsuite('SpirvOptFlags') -class TestSizeOptimizationPasses(expect.ValidObjectFile1_3, +class TestSizeOptimizationPasses(expect.ValidObjectFile1_5, expect.ExecutedListOfPasses): """Tests that spirv-opt schedules all the passes triggered by -Os.""" flags = ['-Os'] expected_passes = [ + 'wrap-opkill', + 'eliminate-dead-branches', 'merge-return', 'inline-entry-points-exhaustive', - 'eliminate-dead-code-aggressive', + 'eliminate-dead-functions', 'private-to-local', - 'scalar-replacement=100', - 'convert-local-access-chains', - 'eliminate-local-single-block', - 'eliminate-local-single-store', - 'eliminate-dead-code-aggressive', - 'simplify-instructions', - 'eliminate-dead-inserts', - 'eliminate-local-multi-store', - 'eliminate-dead-code-aggressive', + 'scalar-replacement=0', + 'ssa-rewrite', 'ccp', + 'loop-unroll', + 'eliminate-dead-branches', + 'simplify-instructions', + 'scalar-replacement=0', + 'eliminate-local-single-store', + 'if-conversion', + 'simplify-instructions', 'eliminate-dead-code-aggressive', 'eliminate-dead-branches', - 'if-conversion', - 'eliminate-dead-code-aggressive', 'merge-blocks', - 'simplify-instructions', - 'eliminate-dead-inserts', - 'redundancy-elimination', - 'cfg-cleanup', + 'convert-local-access-chains', + 'eliminate-local-single-block', 'eliminate-dead-code-aggressive', + 'copy-propagate-arrays', + 'vector-dce', + 'eliminate-dead-inserts', + 'eliminate-dead-members', + 'eliminate-local-single-store', + 'merge-blocks', + 'ssa-rewrite', + 'redundancy-elimination', + 'simplify-instructions', + 'eliminate-dead-code-aggressive', + 'cfg-cleanup', ] shader = placeholder.FileSPIRVShader(empty_main_assembly(), '.spvasm') output = placeholder.TempFileName('output.spv') @@ -213,18 +224,20 @@ class TestSizeOptimizationPasses(expect.ValidObjectFile1_3, @inside_spirv_testsuite('SpirvOptFlags') -class TestLegalizationPasses(expect.ValidObjectFile1_3, +class TestLegalizationPasses(expect.ValidObjectFile1_5, expect.ExecutedListOfPasses): """Tests that spirv-opt schedules all the passes triggered by --legalize-hlsl. """ flags = ['--legalize-hlsl'] expected_passes = [ + 'wrap-opkill', 'eliminate-dead-branches', 'merge-return', 'inline-entry-points-exhaustive', 'eliminate-dead-functions', 'private-to-local', + 'fix-storage-class', 'eliminate-local-single-block', 'eliminate-local-single-store', 'eliminate-dead-code-aggressive', @@ -232,9 +245,10 @@ class TestLegalizationPasses(expect.ValidObjectFile1_3, 'eliminate-local-single-block', 'eliminate-local-single-store', 'eliminate-dead-code-aggressive', - 'eliminate-local-multi-store', + 'ssa-rewrite', 'eliminate-dead-code-aggressive', 'ccp', + 'loop-unroll', 'eliminate-dead-branches', 'simplify-instructions', 'eliminate-dead-code-aggressive', @@ -255,7 +269,7 @@ class TestScalarReplacementArgsNegative(expect.ErrorMessageSubstr): """Tests invalid arguments to --scalar-replacement.""" spirv_args = ['--scalar-replacement=-10'] - expected_error_substr = 'must have no arguments or a positive integer argument' + expected_error_substr = 'must have no arguments or a non-negative integer argument' @inside_spirv_testsuite('SpirvOptFlags') @@ -263,7 +277,7 @@ class TestScalarReplacementArgsInvalidNumber(expect.ErrorMessageSubstr): """Tests invalid arguments to --scalar-replacement.""" spirv_args = ['--scalar-replacement=a10f'] - expected_error_substr = 'must have no arguments or a positive integer argument' + expected_error_substr = 'must have no arguments or a non-negative integer argument' @inside_spirv_testsuite('SpirvOptFlags') @@ -328,3 +342,45 @@ class TestLoopPeelingThresholdArgsInvalidNumber(expect.ErrorMessageSubstr): spirv_args = ['--loop-peeling-threshold=a10f'] expected_error_substr = 'must have a positive integer argument' + +@inside_spirv_testsuite('SpirvOptFlags') +class TestWebGPUToVulkanThenVulkanToWebGPUIsInvalid(expect.ReturnCodeIsNonZero, expect.ErrorMessageSubstr): + """Tests Vulkan->WebGPU flag cannot be used after WebGPU->Vulkan flag.""" + + spirv_args = ['--webgpu-to-vulkan', '--vulkan-to-webgpu'] + expected_error_substr = 'Cannot use both' + +@inside_spirv_testsuite('SpirvOptFlags') +class TestVulkanToWebGPUThenWebGPUToVulkanIsInvalid(expect.ReturnCodeIsNonZero, expect.ErrorMessageSubstr): + """Tests WebGPU->Vulkan flag cannot be used after Vulkan->WebGPU flag.""" + + spirv_args = ['--vulkan-to-webgpu', '--webgpu-to-vulkan'] + expected_error_substr = 'Cannot use both' + +@inside_spirv_testsuite('SpirvOptFlags') +class TestTargetEnvThenVulkanToWebGPUIsInvalid(expect.ReturnCodeIsNonZero, expect.ErrorMessageSubstr): + """Tests Vulkan->WebGPU flag cannot be used after target env flag.""" + + spirv_args = ['--target-env=opengl4.0', '--vulkan-to-webgpu'] + expected_error_substr = 'defines the target environment' + +@inside_spirv_testsuite('SpirvOptFlags') +class TestVulkanToWebGPUThenTargetEnvIsInvalid(expect.ReturnCodeIsNonZero, expect.ErrorMessageSubstr): + """Tests target env flag cannot be used after Vulkan->WebGPU flag.""" + + spirv_args = ['--vulkan-to-webgpu', '--target-env=opengl4.0'] + expected_error_substr = 'defines the target environment' + +@inside_spirv_testsuite('SpirvOptFlags') +class TestTargetEnvThenWebGPUToVulkanIsInvalid(expect.ReturnCodeIsNonZero, expect.ErrorMessageSubstr): + """Tests WebGPU->Vulkan flag cannot be used after target env flag.""" + + spirv_args = ['--target-env=opengl4.0', '--webgpu-to-vulkan'] + expected_error_substr = 'defines the target environment' + +@inside_spirv_testsuite('SpirvOptFlags') +class TestWebGPUToVulkanThenTargetEnvIsInvalid(expect.ReturnCodeIsNonZero, expect.ErrorMessageSubstr): + """Tests target env flag cannot be used after WebGPU->Vulkan flag.""" + + spirv_args = ['--webgpu-to-vulkan', '--target-env=opengl4.0'] + expected_error_substr = 'defines the target environment' diff --git a/third_party/spirv-tools/test/tools/opt/oconfig.py b/third_party/spirv-tools/test/tools/opt/oconfig.py index 3372379949..899d93e563 100644 --- a/third_party/spirv-tools/test/tools/opt/oconfig.py +++ b/third_party/spirv-tools/test/tools/opt/oconfig.py @@ -56,3 +56,18 @@ class TestOconfigComments(expect.SuccessfulReturn): --loop-unroll """, '.cfg') spirv_args = [shader, '-o', placeholder.TempFileName('output.spv'), config] + +@inside_spirv_testsuite('SpirvOptConfigFile') +class TestOconfigComments(expect.SuccessfulReturn): + """Tests empty config files are accepted. + + https://github.com/KhronosGroup/SPIRV-Tools/issues/1778 + """ + + shader = placeholder.FileSPIRVShader(empty_main_assembly(), '.spvasm') + config = placeholder.ConfigFlagsFile(""" +# This is a comment. +-O +--relax-struct-store +""", '.cfg') + spirv_args = [shader, '-o', placeholder.TempFileName('output.spv'), config] diff --git a/third_party/spirv-tools/test/tools/spirv_test_framework.py b/third_party/spirv-tools/test/tools/spirv_test_framework.py index 03ad08fa8c..42f83c64ae 100755 --- a/third_party/spirv-tools/test/tools/spirv_test_framework.py +++ b/third_party/spirv-tools/test/tools/spirv_test_framework.py @@ -44,8 +44,6 @@ If --leave-output was not specified, all temporary files and directories will be deleted. """ -from __future__ import print_function - import argparse import fnmatch import inspect @@ -72,7 +70,7 @@ def get_all_methods(instance): def get_all_superclasses(cls): - """Returns all superclasses of a given class. + """Returns all superclasses of a given class. Omits root 'object' superclass. Returns: A list of superclasses of the given class. The order guarantees that @@ -85,11 +83,12 @@ def get_all_superclasses(cls): classes = [] for superclass in cls.__bases__: for c in get_all_superclasses(superclass): - if c not in classes: + if c is not object and c not in classes: classes.append(c) for superclass in cls.__bases__: - if superclass not in classes: + if superclass is not object and superclass not in classes: classes.append(superclass) + return classes @@ -144,8 +143,28 @@ class TestStatus: inputs, input_filenames): self.test_manager = test_manager self.returncode = returncode - self.stdout = stdout - self.stderr = stderr + # Some of our MacOS bots still run Python 2, so need to be backwards + # compatible here. + if type(stdout) is not str: + if sys.version_info[0] is 2: + self.stdout = stdout.decode('utf-8') + elif sys.version_info[0] is 3: + self.stdout = str(stdout, encoding='utf-8') if stdout is not None else stdout + else: + raise Exception('Unable to determine if running Python 2 or 3 from {}'.format(sys.version_info)) + else: + self.stdout = stdout + + if type(stderr) is not str: + if sys.version_info[0] is 2: + self.stderr = stderr.decode('utf-8') + elif sys.version_info[0] is 3: + self.stderr = str(stderr, encoding='utf-8') if stderr is not None else stderr + else: + raise Exception('Unable to determine if running Python 2 or 3 from {}'.format(sys.version_info)) + else: + self.stderr = stderr + # temporary directory where the test runs self.directory = directory # List of inputs, as PlaceHolder objects. diff --git a/third_party/spirv-tools/test/tools/spirv_test_framework_nosetest.py b/third_party/spirv-tools/test/tools/spirv_test_framework_nosetest.py deleted file mode 100755 index c0fbed5811..0000000000 --- a/third_party/spirv-tools/test/tools/spirv_test_framework_nosetest.py +++ /dev/null @@ -1,155 +0,0 @@ -# Copyright (c) 2018 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. - -from spirv_test_framework import get_all_test_methods, get_all_superclasses -from nose.tools import assert_equal, with_setup - - -# Classes to be used in testing get_all_{superclasses|test_methods}() -class Root: - - def check_root(self): - pass - - -class A(Root): - - def check_a(self): - pass - - -class B(Root): - - def check_b(self): - pass - - -class C(Root): - - def check_c(self): - pass - - -class D(Root): - - def check_d(self): - pass - - -class E(Root): - - def check_e(self): - pass - - -class H(B, C, D): - - def check_h(self): - pass - - -class I(E): - - def check_i(self): - pass - - -class O(H, I): - - def check_o(self): - pass - - -class U(A, O): - - def check_u(self): - pass - - -class X(U, A): - - def check_x(self): - pass - - -class R1: - - def check_r1(self): - pass - - -class R2: - - def check_r2(self): - pass - - -class Multi(R1, R2): - - def check_multi(self): - pass - - -def nosetest_get_all_superclasses(): - """Tests get_all_superclasses().""" - - assert_equal(get_all_superclasses(A), [Root]) - assert_equal(get_all_superclasses(B), [Root]) - assert_equal(get_all_superclasses(C), [Root]) - assert_equal(get_all_superclasses(D), [Root]) - assert_equal(get_all_superclasses(E), [Root]) - - assert_equal(get_all_superclasses(H), [Root, B, C, D]) - assert_equal(get_all_superclasses(I), [Root, E]) - - assert_equal(get_all_superclasses(O), [Root, B, C, D, E, H, I]) - - assert_equal(get_all_superclasses(U), [Root, B, C, D, E, H, I, A, O]) - assert_equal(get_all_superclasses(X), [Root, B, C, D, E, H, I, A, O, U]) - - assert_equal(get_all_superclasses(Multi), [R1, R2]) - - -def nosetest_get_all_methods(): - """Tests get_all_test_methods().""" - assert_equal(get_all_test_methods(A), ['check_root', 'check_a']) - assert_equal(get_all_test_methods(B), ['check_root', 'check_b']) - assert_equal(get_all_test_methods(C), ['check_root', 'check_c']) - assert_equal(get_all_test_methods(D), ['check_root', 'check_d']) - assert_equal(get_all_test_methods(E), ['check_root', 'check_e']) - - assert_equal( - get_all_test_methods(H), - ['check_root', 'check_b', 'check_c', 'check_d', 'check_h']) - assert_equal(get_all_test_methods(I), ['check_root', 'check_e', 'check_i']) - - assert_equal( - get_all_test_methods(O), [ - 'check_root', 'check_b', 'check_c', 'check_d', 'check_e', 'check_h', - 'check_i', 'check_o' - ]) - - assert_equal( - get_all_test_methods(U), [ - 'check_root', 'check_b', 'check_c', 'check_d', 'check_e', 'check_h', - 'check_i', 'check_a', 'check_o', 'check_u' - ]) - assert_equal( - get_all_test_methods(X), [ - 'check_root', 'check_b', 'check_c', 'check_d', 'check_e', 'check_h', - 'check_i', 'check_a', 'check_o', 'check_u', 'check_x' - ]) - - assert_equal( - get_all_test_methods(Multi), ['check_r1', 'check_r2', 'check_multi']) diff --git a/third_party/spirv-tools/test/tools/spirv_test_framework_unittest.py b/third_party/spirv-tools/test/tools/spirv_test_framework_unittest.py new file mode 100644 index 0000000000..e64e86c018 --- /dev/null +++ b/third_party/spirv-tools/test/tools/spirv_test_framework_unittest.py @@ -0,0 +1,158 @@ +# Copyright (c) 2019 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. +"""Tests for the spirv test framework module.""" + +from spirv_test_framework import get_all_test_methods, get_all_superclasses +import unittest + +# Classes to be used in testing get_all_{superclasses|test_methods}() + + +class Root: + + def check_root(self): + pass + + +class A(Root): + + def check_a(self): + pass + + +class B(Root): + + def check_b(self): + pass + + +class C(Root): + + def check_c(self): + pass + + +class D(Root): + + def check_d(self): + pass + + +class E(Root): + + def check_e(self): + pass + + +class H(B, C, D): + + def check_h(self): + pass + + +class I(E): + + def check_i(self): + pass + + +class O(H, I): + + def check_o(self): + pass + + +class U(A, O): + + def check_u(self): + pass + + +class X(U, A): + + def check_x(self): + pass + + +class R1: + + def check_r1(self): + pass + + +class R2: + + def check_r2(self): + pass + + +class Multi(R1, R2): + + def check_multi(self): + pass + + +class TestSpirvTestFramework(unittest.TestCase): + def test_get_all_superclasses(self): + self.assertEqual(get_all_superclasses(A), [Root]) + self.assertEqual(get_all_superclasses(B), [Root]) + self.assertEqual(get_all_superclasses(C), [Root]) + self.assertEqual(get_all_superclasses(D), [Root]) + self.assertEqual(get_all_superclasses(E), [Root]) + + self.assertEqual(get_all_superclasses(H), [Root, B, C, D]) + self.assertEqual(get_all_superclasses(I), [Root, E]) + + self.assertEqual(get_all_superclasses(O), [Root, B, C, D, E, H, I]) + + self.assertEqual(get_all_superclasses( + U), [Root, B, C, D, E, H, I, A, O]) + self.assertEqual(get_all_superclasses( + X), [Root, B, C, D, E, H, I, A, O, U]) + + self.assertEqual(get_all_superclasses(Multi), [R1, R2]) + + def test_get_all_methods(self): + self.assertEqual(get_all_test_methods(A), ['check_root', 'check_a']) + self.assertEqual(get_all_test_methods(B), ['check_root', 'check_b']) + self.assertEqual(get_all_test_methods(C), ['check_root', 'check_c']) + self.assertEqual(get_all_test_methods(D), ['check_root', 'check_d']) + self.assertEqual(get_all_test_methods(E), ['check_root', 'check_e']) + + self.assertEqual( + get_all_test_methods(H), + ['check_root', 'check_b', 'check_c', 'check_d', 'check_h']) + self.assertEqual(get_all_test_methods( + I), ['check_root', 'check_e', 'check_i']) + + self.assertEqual( + get_all_test_methods(O), [ + 'check_root', 'check_b', 'check_c', 'check_d', 'check_e', 'check_h', + 'check_i', 'check_o' + ]) + + self.assertEqual( + get_all_test_methods(U), [ + 'check_root', 'check_b', 'check_c', 'check_d', 'check_e', 'check_h', + 'check_i', 'check_a', 'check_o', 'check_u' + ]) + + self.assertEqual( + get_all_test_methods(X), [ + 'check_root', 'check_b', 'check_c', 'check_d', 'check_e', 'check_h', + 'check_i', 'check_a', 'check_o', 'check_u', 'check_x' + ]) + + self.assertEqual( + get_all_test_methods(Multi), ['check_r1', 'check_r2', 'check_multi']) diff --git a/third_party/spirv-tools/test/unit_spirv.cpp b/third_party/spirv-tools/test/unit_spirv.cpp index 84ed87a510..085443948e 100644 --- a/third_party/spirv-tools/test/unit_spirv.cpp +++ b/third_party/spirv-tools/test/unit_spirv.cpp @@ -15,12 +15,13 @@ #include "test/unit_spirv.h" #include "gmock/gmock.h" +#include "source/util/string_utils.h" #include "test/test_fixture.h" namespace spvtools { namespace { -using spvtest::MakeVector; +using utils::MakeVector; using ::testing::Eq; using Words = std::vector; diff --git a/third_party/spirv-tools/test/unit_spirv.h b/third_party/spirv-tools/test/unit_spirv.h index 2244288844..32646620de 100644 --- a/third_party/spirv-tools/test/unit_spirv.h +++ b/third_party/spirv-tools/test/unit_spirv.h @@ -133,29 +133,6 @@ inline std::vector Concatenate( return result; } -// Encodes a string as a sequence of words, using the SPIR-V encoding. -inline std::vector MakeVector(std::string input) { - std::vector result; - uint32_t word = 0; - size_t num_bytes = input.size(); - // SPIR-V strings are null-terminated. The byte_index == num_bytes - // case is used to push the terminating null byte. - for (size_t byte_index = 0; byte_index <= num_bytes; byte_index++) { - const auto new_byte = - (byte_index < num_bytes ? uint8_t(input[byte_index]) : uint8_t(0)); - word |= (new_byte << (8 * (byte_index % sizeof(uint32_t)))); - if (3 == (byte_index % sizeof(uint32_t))) { - result.push_back(word); - word = 0; - } - } - // Emit a trailing partial word. - if ((num_bytes + 1) % sizeof(uint32_t)) { - result.push_back(word); - } - return result; -} - // A type for easily creating spv_text_t values, with an implicit conversion to // spv_text. struct AutoText { diff --git a/third_party/spirv-tools/test/util/CMakeLists.txt b/third_party/spirv-tools/test/util/CMakeLists.txt index 66d4e8a421..6679dba7c6 100644 --- a/third_party/spirv-tools/test/util/CMakeLists.txt +++ b/third_party/spirv-tools/test/util/CMakeLists.txt @@ -12,15 +12,10 @@ # See the License for the specific language governing permissions and # limitations under the License. -add_spvtools_unittest(TARGET util_intrusive_list +add_spvtools_unittest(TARGET utils SRCS ilist_test.cpp -) - -add_spvtools_unittest(TARGET bit_vector - SRCS bit_vector_test.cpp + bit_vector_test.cpp + bitutils_test.cpp + small_vector_test.cpp LIBS SPIRV-Tools-opt ) - -add_spvtools_unittest(TARGET small_vector - SRCS small_vector_test.cpp -) diff --git a/third_party/spirv-tools/test/util/bitutils_test.cpp b/third_party/spirv-tools/test/util/bitutils_test.cpp new file mode 100644 index 0000000000..3be7ed2691 --- /dev/null +++ b/third_party/spirv-tools/test/util/bitutils_test.cpp @@ -0,0 +1,193 @@ +// Copyright (c) 2019 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/util/bitutils.h" + +#include "gmock/gmock.h" + +namespace spvtools { +namespace utils { +namespace { + +using BitUtilsTest = ::testing::Test; + +TEST(BitUtilsTest, MutateBitsWholeWord) { + const uint32_t zero_u32 = 0; + const uint32_t max_u32 = ~0; + + EXPECT_EQ(MutateBits(zero_u32, 0, 0, false), zero_u32); + EXPECT_EQ(MutateBits(max_u32, 0, 0, false), max_u32); + EXPECT_EQ(MutateBits(zero_u32, 0, 32, false), zero_u32); + EXPECT_EQ(MutateBits(zero_u32, 0, 32, true), max_u32); + EXPECT_EQ(MutateBits(max_u32, 0, 32, true), max_u32); + EXPECT_EQ(MutateBits(max_u32, 0, 32, false), zero_u32); +} + +TEST(BitUtilsTest, MutateBitsLow) { + const uint32_t zero_u32 = 0; + const uint32_t one_u32 = 1; + const uint32_t max_u32 = ~0; + + EXPECT_EQ(MutateBits(zero_u32, 0, 1, false), zero_u32); + EXPECT_EQ(MutateBits(zero_u32, 0, 1, true), one_u32); + EXPECT_EQ(MutateBits(max_u32, 0, 1, true), max_u32); + EXPECT_EQ(MutateBits(one_u32, 0, 32, false), zero_u32); + EXPECT_EQ(MutateBits(one_u32, 0, 1, true), one_u32); + EXPECT_EQ(MutateBits(one_u32, 0, 1, false), zero_u32); + EXPECT_EQ(MutateBits(zero_u32, 0, 3, true), uint32_t(7)); + EXPECT_EQ(MutateBits(uint32_t(7), 0, 2, false), uint32_t(4)); +} + +TEST(BitUtilsTest, MutateBitsHigh) { + const uint8_t zero_u8 = 0; + const uint8_t one_u8 = 1; + const uint8_t max_u8 = 255; + + EXPECT_EQ(MutateBits(zero_u8, 7, 0, true), zero_u8); + EXPECT_EQ(MutateBits(zero_u8, 7, 1, true), uint8_t(128)); + EXPECT_EQ(MutateBits(one_u8, 7, 1, true), uint8_t(129)); + EXPECT_EQ(MutateBits(max_u8, 7, 1, true), max_u8); + EXPECT_EQ(MutateBits(max_u8, 7, 1, false), uint8_t(127)); + EXPECT_EQ(MutateBits(max_u8, 6, 2, true), max_u8); + EXPECT_EQ(MutateBits(max_u8, 6, 2, false), uint8_t(63)); +} + +TEST(BitUtilsTest, MutateBitsUint8Mid) { + const uint8_t zero_u8 = 0; + const uint8_t max_u8 = 255; + + EXPECT_EQ(MutateBits(zero_u8, 1, 2, true), uint8_t(6)); + EXPECT_EQ(MutateBits(max_u8, 1, 2, true), max_u8); + EXPECT_EQ(MutateBits(max_u8, 1, 2, false), uint8_t(0xF9)); + EXPECT_EQ(MutateBits(zero_u8, 2, 3, true), uint8_t(0x1C)); +} + +TEST(BitUtilsTest, MutateBitsUint64Mid) { + const uint64_t zero_u64 = 0; + const uint64_t max_u64 = ~zero_u64; + + EXPECT_EQ(MutateBits(zero_u64, 1, 2, true), uint64_t(6)); + EXPECT_EQ(MutateBits(max_u64, 1, 2, true), max_u64); + EXPECT_EQ(MutateBits(max_u64, 1, 2, false), uint64_t(0xFFFFFFFFFFFFFFF9)); + EXPECT_EQ(MutateBits(zero_u64, 2, 3, true), uint64_t(0x000000000000001C)); + EXPECT_EQ(MutateBits(zero_u64, 2, 35, true), uint64_t(0x0000001FFFFFFFFC)); + EXPECT_EQ(MutateBits(zero_u64, 36, 4, true), uint64_t(0x000000F000000000)); + EXPECT_EQ(MutateBits(max_u64, 36, 4, false), uint64_t(0xFFFFFF0FFFFFFFFF)); +} + +TEST(BitUtilsTest, SetHighBitsUint32) { + const uint32_t zero_u32 = 0; + const uint32_t one_u32 = 1; + const uint32_t max_u32 = ~zero_u32; + + EXPECT_EQ(SetHighBits(zero_u32, 0), zero_u32); + EXPECT_EQ(SetHighBits(zero_u32, 1), 0x80000000); + EXPECT_EQ(SetHighBits(one_u32, 1), 0x80000001); + EXPECT_EQ(SetHighBits(one_u32, 2), 0xC0000001); + EXPECT_EQ(SetHighBits(zero_u32, 31), 0xFFFFFFFE); + EXPECT_EQ(SetHighBits(zero_u32, 32), max_u32); + EXPECT_EQ(SetHighBits(max_u32, 32), max_u32); +} + +TEST(BitUtilsTest, ClearHighBitsUint32) { + const uint32_t zero_u32 = 0; + const uint32_t one_u32 = 1; + const uint32_t max_u32 = ~zero_u32; + + EXPECT_EQ(ClearHighBits(zero_u32, 0), zero_u32); + EXPECT_EQ(ClearHighBits(zero_u32, 1), zero_u32); + EXPECT_EQ(ClearHighBits(one_u32, 1), one_u32); + EXPECT_EQ(ClearHighBits(one_u32, 31), one_u32); + EXPECT_EQ(ClearHighBits(one_u32, 32), zero_u32); + EXPECT_EQ(ClearHighBits(max_u32, 0), max_u32); + EXPECT_EQ(ClearHighBits(max_u32, 1), 0x7FFFFFFF); + EXPECT_EQ(ClearHighBits(max_u32, 2), 0x3FFFFFFF); + EXPECT_EQ(ClearHighBits(max_u32, 31), one_u32); + EXPECT_EQ(ClearHighBits(max_u32, 32), zero_u32); +} + +TEST(BitUtilsTest, IsBitSetAtPositionZero) { + const uint32_t zero_u32 = 0; + for (size_t i = 0; i != 32; ++i) { + EXPECT_FALSE(IsBitAtPositionSet(zero_u32, i)); + } + + const uint8_t zero_u8 = 0; + for (size_t i = 0; i != 8; ++i) { + EXPECT_FALSE(IsBitAtPositionSet(zero_u8, i)); + } + + const uint64_t zero_u64 = 0; + for (size_t i = 0; i != 64; ++i) { + EXPECT_FALSE(IsBitAtPositionSet(zero_u64, i)); + } +} + +TEST(BitUtilsTest, IsBitSetAtPositionOne) { + const uint32_t one_u32 = 1; + for (size_t i = 0; i != 32; ++i) { + if (i == 0) { + EXPECT_TRUE(IsBitAtPositionSet(one_u32, i)); + } else { + EXPECT_FALSE(IsBitAtPositionSet(one_u32, i)); + } + } + + const uint32_t two_to_17_u32 = 1 << 17; + for (size_t i = 0; i != 32; ++i) { + if (i == 17) { + EXPECT_TRUE(IsBitAtPositionSet(two_to_17_u32, i)); + } else { + EXPECT_FALSE(IsBitAtPositionSet(two_to_17_u32, i)); + } + } + + const uint8_t two_to_4_u8 = 1 << 4; + for (size_t i = 0; i != 8; ++i) { + if (i == 4) { + EXPECT_TRUE(IsBitAtPositionSet(two_to_4_u8, i)); + } else { + EXPECT_FALSE(IsBitAtPositionSet(two_to_4_u8, i)); + } + } + + const uint64_t two_to_55_u64 = uint64_t(1) << 55; + for (size_t i = 0; i != 64; ++i) { + if (i == 55) { + EXPECT_TRUE(IsBitAtPositionSet(two_to_55_u64, i)); + } else { + EXPECT_FALSE(IsBitAtPositionSet(two_to_55_u64, i)); + } + } +} + +TEST(BitUtilsTest, IsBitSetAtPositionAll) { + const uint32_t max_u32 = ~0; + for (size_t i = 0; i != 32; ++i) { + EXPECT_TRUE(IsBitAtPositionSet(max_u32, i)); + } + + const uint32_t max_u8 = ~uint8_t(0); + for (size_t i = 0; i != 8; ++i) { + EXPECT_TRUE(IsBitAtPositionSet(max_u8, i)); + } + + const uint64_t max_u64 = ~uint64_t(0); + for (size_t i = 0; i != 64; ++i) { + EXPECT_TRUE(IsBitAtPositionSet(max_u64, i)); + } +} +} // namespace +} // namespace utils +} // namespace spvtools diff --git a/third_party/spirv-tools/test/val/CMakeLists.txt b/third_party/spirv-tools/test/val/CMakeLists.txt index b1e87da664..138e71144a 100644 --- a/third_party/spirv-tools/test/val/CMakeLists.txt +++ b/third_party/spirv-tools/test/val/CMakeLists.txt @@ -15,6 +15,8 @@ set(VAL_TEST_COMMON_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/../test_fixture.h ${CMAKE_CURRENT_SOURCE_DIR}/../unit_spirv.h + ${CMAKE_CURRENT_SOURCE_DIR}/val_code_generator.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/val_code_generator.h ${CMAKE_CURRENT_SOURCE_DIR}/val_fixtures.h ) @@ -26,42 +28,60 @@ add_spvtools_unittest(TARGET val_abcde val_barriers_test.cpp val_bitwise_test.cpp val_builtins_test.cpp - val_capability_test.cpp val_cfg_test.cpp val_composites_test.cpp + val_constants_test.cpp val_conversion_test.cpp val_data_test.cpp val_decoration_test.cpp val_derivatives_test.cpp + val_entry_point.cpp val_explicit_reserved_test.cpp val_extensions_test.cpp val_ext_inst_test.cpp ${VAL_TEST_COMMON_SRCS} LIBS ${SPIRV_TOOLS} + PCH_FILE pch_test_val +) + +add_spvtools_unittest(TARGET val_capability + SRCS + val_capability_test.cpp + LIBS ${SPIRV_TOOLS} + PCH_FILE pch_test_val ) add_spvtools_unittest(TARGET val_limits SRCS val_limits_test.cpp ${VAL_TEST_COMMON_SRCS} LIBS ${SPIRV_TOOLS} + PCH_FILE pch_test_val ) -add_spvtools_unittest(TARGET val_ijklmnop +add_spvtools_unittest(TARGET val_fghijklmnop SRCS + val_function_test.cpp val_id_test.cpp val_image_test.cpp val_interfaces_test.cpp val_layout_test.cpp val_literals_test.cpp val_logicals_test.cpp + val_memory_test.cpp + val_misc_test.cpp + val_modes_test.cpp + val_non_semantic_test.cpp val_non_uniform_test.cpp + val_opencl_test.cpp val_primitives_test.cpp ${VAL_TEST_COMMON_SRCS} LIBS ${SPIRV_TOOLS} + PCH_FILE pch_test_val ) add_spvtools_unittest(TARGET val_stuvw SRCS + val_small_type_uses_test.cpp val_ssa_test.cpp val_state_test.cpp val_storage_test.cpp @@ -71,4 +91,5 @@ add_spvtools_unittest(TARGET val_stuvw val_webgpu_test.cpp ${VAL_TEST_COMMON_SRCS} LIBS ${SPIRV_TOOLS} + PCH_FILE pch_test_val ) diff --git a/third_party/spirv-tools/test/val/pch_test_val.cpp b/third_party/spirv-tools/test/val/pch_test_val.cpp new file mode 100644 index 0000000000..fc92e375a0 --- /dev/null +++ b/third_party/spirv-tools/test/val/pch_test_val.cpp @@ -0,0 +1,15 @@ +// Copyright (c) 2018 The Khronos Group Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "pch_test_val.h" diff --git a/third_party/spirv-tools/test/val/pch_test_val.h b/third_party/spirv-tools/test/val/pch_test_val.h new file mode 100644 index 0000000000..7b5881c43e --- /dev/null +++ b/third_party/spirv-tools/test/val/pch_test_val.h @@ -0,0 +1,19 @@ +// Copyright (c) 2018 The Khronos Group Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include "gmock/gmock.h" +#include "test/unit_spirv.h" +#include "test/val/val_fixtures.h" diff --git a/third_party/spirv-tools/test/val/val_adjacency_test.cpp b/third_party/spirv-tools/test/val/val_adjacency_test.cpp index d62830514a..0b09de0c2c 100644 --- a/third_party/spirv-tools/test/val/val_adjacency_test.cpp +++ b/third_party/spirv-tools/test/val/val_adjacency_test.cpp @@ -34,6 +34,7 @@ TEST_F(ValidateAdjacency, OpPhiBeginsModuleFail) { OpCapability Shader OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft %void = OpTypeVoid %bool = OpTypeBool %true = OpConstantTrue %bool @@ -52,7 +53,8 @@ OpFunctionEnd CompileSuccessfully(module); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), HasSubstr("ID 1 has not been defined")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("ID 1[%bool] has not been defined")); } TEST_F(ValidateAdjacency, OpLoopMergeEndsModuleFail) { @@ -60,6 +62,7 @@ TEST_F(ValidateAdjacency, OpLoopMergeEndsModuleFail) { OpCapability Shader OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft %void = OpTypeVoid %func = OpTypeFunction %void %main = OpFunction %void None %func @@ -80,6 +83,7 @@ TEST_F(ValidateAdjacency, OpSelectionMergeEndsModuleFail) { OpCapability Shader OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft %void = OpTypeVoid %func = OpTypeFunction %void %main = OpFunction %void None %func @@ -103,6 +107,9 @@ std::string GenerateShaderCode( ss << capabilities_and_extensions << "\n"; ss << "OpMemoryModel Logical GLSL450\n"; ss << "OpEntryPoint " << execution_model << " %main \"main\"\n"; + if (execution_model == "Fragment") { + ss << "OpExecutionMode %main OriginUpperLeft\n"; + } ss << R"( %string = OpString "" @@ -112,7 +119,9 @@ std::string GenerateShaderCode( %true = OpConstantTrue %bool %false = OpConstantFalse %bool %zero = OpConstant %int 0 +%int_1 = OpConstant %int 1 %func = OpTypeFunction %void +%func_int = OpTypePointer Function %int %main = OpFunction %void None %func %main_entry = OpLabel )"; @@ -135,7 +144,7 @@ OpBranch %end_label %false_label = OpLabel OpBranch %end_label %end_label = OpLabel -%line = OpLine %string 0 0 +OpLine %string 0 0 %result = OpPhi %bool %true %true_label %false %false_label )"; @@ -169,7 +178,7 @@ OpBranch %end_label %false_label = OpLabel OpBranch %end_label %end_label = OpLabel -%line = OpLine %string 0 0 +OpLine %string 0 0 %result = OpPhi %bool %true %true_label %false %false_label )"; @@ -193,7 +202,416 @@ OpNop CompileSuccessfully(GenerateShaderCode(body)); EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpPhi must appear before all non-OpPhi instructions")); + HasSubstr("OpPhi must appear within a non-entry block before all " + "non-OpPhi instructions")); +} + +TEST_F(ValidateAdjacency, OpPhiPreceededByOpLineAndBadOpFail) { + const std::string body = R"( +OpSelectionMerge %end_label None +OpBranchConditional %true %true_label %false_label +%true_label = OpLabel +OpBranch %end_label +%false_label = OpLabel +OpBranch %end_label +%end_label = OpLabel +OpNop +OpLine %string 1 1 +%result = OpPhi %bool %true %true_label %false %false_label +)"; + + CompileSuccessfully(GenerateShaderCode(body)); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("OpPhi must appear within a non-entry block before all " + "non-OpPhi instructions")); +} + +TEST_F(ValidateAdjacency, OpPhiFollowedByOpLineGood) { + const std::string body = R"( +OpSelectionMerge %end_label None +OpBranchConditional %true %true_label %false_label +%true_label = OpLabel +OpBranch %end_label +%false_label = OpLabel +OpBranch %end_label +%end_label = OpLabel +%result = OpPhi %bool %true %true_label %false %false_label +OpLine %string 1 1 +OpNop +OpNop +OpLine %string 2 1 +OpNop +OpLine %string 3 1 +)"; + + CompileSuccessfully(GenerateShaderCode(body)); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateAdjacency, OpPhiMultipleOpLineAndOpPhiFail) { + const std::string body = R"( +OpSelectionMerge %end_label None +OpBranchConditional %true %true_label %false_label +%true_label = OpLabel +OpBranch %end_label +%false_label = OpLabel +OpBranch %end_label +%end_label = OpLabel +OpLine %string 1 1 +%value = OpPhi %int %zero %true_label %int_1 %false_label +OpNop +OpLine %string 2 1 +OpNop +OpLine %string 3 1 +%result = OpPhi %bool %true %true_label %false %false_label +)"; + + CompileSuccessfully(GenerateShaderCode(body)); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("OpPhi must appear within a non-entry block before all " + "non-OpPhi instructions")); +} + +TEST_F(ValidateAdjacency, OpPhiMultipleOpLineAndOpPhiGood) { + const std::string body = R"( +OpSelectionMerge %end_label None +OpBranchConditional %true %true_label %false_label +%true_label = OpLabel +OpBranch %end_label +%false_label = OpLabel +OpBranch %end_label +%end_label = OpLabel +OpLine %string 1 1 +%value = OpPhi %int %zero %true_label %int_1 %false_label +OpLine %string 2 1 +%result = OpPhi %bool %true %true_label %false %false_label +OpLine %string 3 1 +OpNop +OpNop +OpLine %string 4 1 +OpNop +)"; + + CompileSuccessfully(GenerateShaderCode(body)); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateAdjacency, OpPhiInEntryBlockBad) { + const std::string body = R"( +OpLine %string 1 1 +%value = OpPhi %int +OpLine %string 2 1 +OpNop +OpLine %string 3 1 +OpNop +)"; + + CompileSuccessfully(GenerateShaderCode(body)); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("OpPhi must appear within a non-entry block before all " + "non-OpPhi instructions")); +} + +TEST_F(ValidateAdjacency, NonSemanticBeforeOpPhiBad) { + const std::string body = R"( +OpSelectionMerge %end_label None +OpBranchConditional %true %true_label %false_label +%true_label = OpLabel +OpBranch %end_label +%false_label = OpLabel +OpBranch %end_label +%end_label = OpLabel +%dummy = OpExtInst %void %extinst 123 %int_1 +%result = OpPhi %bool %true %true_label %false %false_label +)"; + + const std::string extra = R"(OpCapability Shader +OpExtension "SPV_KHR_non_semantic_info" +%extinst = OpExtInstImport "NonSemantic.Testing.Set" +)"; + + CompileSuccessfully(GenerateShaderCode(body, extra)); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("OpPhi must appear within a non-entry block before all " + "non-OpPhi instructions")); +} + +TEST_F(ValidateAdjacency, NonSemanticBetweenOpPhiBad) { + const std::string body = R"( +OpSelectionMerge %end_label None +OpBranchConditional %true %true_label %false_label +%true_label = OpLabel +OpBranch %end_label +%false_label = OpLabel +OpBranch %end_label +%end_label = OpLabel +%result1 = OpPhi %bool %true %true_label %false %false_label +%dummy = OpExtInst %void %extinst 123 %int_1 +%result2 = OpPhi %bool %true %true_label %false %false_label +)"; + + const std::string extra = R"(OpCapability Shader +OpExtension "SPV_KHR_non_semantic_info" +%extinst = OpExtInstImport "NonSemantic.Testing.Set" +)"; + + CompileSuccessfully(GenerateShaderCode(body, extra)); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("OpPhi must appear within a non-entry block before all " + "non-OpPhi instructions")); +} + +TEST_F(ValidateAdjacency, NonSemanticAfterOpPhiGood) { + const std::string body = R"( +OpSelectionMerge %end_label None +OpBranchConditional %true %true_label %false_label +%true_label = OpLabel +OpBranch %end_label +%false_label = OpLabel +OpBranch %end_label +%end_label = OpLabel +OpLine %string 0 0 +%result = OpPhi %bool %true %true_label %false %false_label +%dummy = OpExtInst %void %extinst 123 %int_1 +)"; + + const std::string extra = R"(OpCapability Shader +OpExtension "SPV_KHR_non_semantic_info" +%extinst = OpExtInstImport "NonSemantic.Testing.Set" +)"; + + CompileSuccessfully(GenerateShaderCode(body, extra)); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateAdjacency, NonSemanticBeforeOpFunctionParameterBad) { + const std::string body = R"( +OpCapability Shader +OpExtension "SPV_KHR_non_semantic_info" +%extinst = OpExtInstImport "NonSemantic.Testing.Set" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft + +%string = OpString "" +%void = OpTypeVoid +%bool = OpTypeBool +%int = OpTypeInt 32 0 +%true = OpConstantTrue %bool +%false = OpConstantFalse %bool +%zero = OpConstant %int 0 +%int_1 = OpConstant %int 1 +%func = OpTypeFunction %void +%func_int = OpTypePointer Function %int +%paramfunc_type = OpTypeFunction %void %int %int + +%paramfunc = OpFunction %void None %paramfunc_type +%dummy = OpExtInst %void %extinst 123 %int_1 +%a = OpFunctionParameter %int +%b = OpFunctionParameter %int +%paramfunc_entry = OpLabel +OpReturn +OpFunctionEnd + +%main = OpFunction %void None %func +%main_entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(body); + EXPECT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Non-semantic OpExtInst within function definition " + "must appear in a block")); +} + +TEST_F(ValidateAdjacency, NonSemanticBetweenOpFunctionParameterBad) { + const std::string body = R"( +OpCapability Shader +OpExtension "SPV_KHR_non_semantic_info" +%extinst = OpExtInstImport "NonSemantic.Testing.Set" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft + +%string = OpString "" +%void = OpTypeVoid +%bool = OpTypeBool +%int = OpTypeInt 32 0 +%true = OpConstantTrue %bool +%false = OpConstantFalse %bool +%zero = OpConstant %int 0 +%int_1 = OpConstant %int 1 +%func = OpTypeFunction %void +%func_int = OpTypePointer Function %int +%paramfunc_type = OpTypeFunction %void %int %int + +%paramfunc = OpFunction %void None %paramfunc_type +%a = OpFunctionParameter %int +%dummy = OpExtInst %void %extinst 123 %int_1 +%b = OpFunctionParameter %int +%paramfunc_entry = OpLabel +OpReturn +OpFunctionEnd + +%main = OpFunction %void None %func +%main_entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(body); + EXPECT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Non-semantic OpExtInst within function definition " + "must appear in a block")); +} + +TEST_F(ValidateAdjacency, NonSemanticAfterOpFunctionParameterGood) { + const std::string body = R"( +OpCapability Shader +OpExtension "SPV_KHR_non_semantic_info" +%extinst = OpExtInstImport "NonSemantic.Testing.Set" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft + +%string = OpString "" +%void = OpTypeVoid +%bool = OpTypeBool +%int = OpTypeInt 32 0 +%true = OpConstantTrue %bool +%false = OpConstantFalse %bool +%zero = OpConstant %int 0 +%int_1 = OpConstant %int 1 +%func = OpTypeFunction %void +%func_int = OpTypePointer Function %int +%paramfunc_type = OpTypeFunction %void %int %int + +%paramfunc = OpFunction %void None %paramfunc_type +%a = OpFunctionParameter %int +%b = OpFunctionParameter %int +%paramfunc_entry = OpLabel +%dummy = OpExtInst %void %extinst 123 %int_1 +OpReturn +OpFunctionEnd + +%main = OpFunction %void None %func +%main_entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(body); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateAdjacency, NonSemanticBetweenFunctionsGood) { + const std::string body = R"( +OpCapability Shader +OpExtension "SPV_KHR_non_semantic_info" +%extinst = OpExtInstImport "NonSemantic.Testing.Set" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft + +%string = OpString "" +%void = OpTypeVoid +%bool = OpTypeBool +%int = OpTypeInt 32 0 +%true = OpConstantTrue %bool +%false = OpConstantFalse %bool +%zero = OpConstant %int 0 +%int_1 = OpConstant %int 1 +%func = OpTypeFunction %void +%func_int = OpTypePointer Function %int +%paramfunc_type = OpTypeFunction %void %int %int + +%paramfunc = OpFunction %void None %paramfunc_type +%a = OpFunctionParameter %int +%b = OpFunctionParameter %int +%paramfunc_entry = OpLabel +OpReturn +OpFunctionEnd + +%dummy = OpExtInst %void %extinst 123 %int_1 + +%main = OpFunction %void None %func +%main_entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(body); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateAdjacency, OpVariableInFunctionGood) { + const std::string body = R"( +OpLine %string 1 1 +%var = OpVariable %func_int Function +OpLine %string 2 1 +OpNop +OpLine %string 3 1 +OpNop +)"; + + CompileSuccessfully(GenerateShaderCode(body)); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateAdjacency, OpVariableInFunctionMultipleGood) { + const std::string body = R"( +OpLine %string 1 1 +%1 = OpVariable %func_int Function +OpLine %string 2 1 +%2 = OpVariable %func_int Function +%3 = OpVariable %func_int Function +OpNop +OpLine %string 3 1 +OpNop +)"; + + CompileSuccessfully(GenerateShaderCode(body)); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateAdjacency, OpVariableInFunctionBad) { + const std::string body = R"( +%1 = OpUndef %int +%2 = OpVariable %func_int Function +)"; + + CompileSuccessfully(GenerateShaderCode(body)); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("All OpVariable instructions in a function must be the " + "first instructions")); +} + +TEST_F(ValidateAdjacency, OpVariableInFunctionMultipleBad) { + const std::string body = R"( +OpNop +%1 = OpVariable %func_int Function +OpLine %string 1 1 +%2 = OpVariable %func_int Function +OpNop +OpNop +OpLine %string 2 1 +%3 = OpVariable %func_int Function +)"; + + CompileSuccessfully(GenerateShaderCode(body)); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("All OpVariable instructions in a function must be the " + "first instructions")); } TEST_F(ValidateAdjacency, OpLoopMergePreceedsOpBranchSuccess) { diff --git a/third_party/spirv-tools/test/val/val_arithmetics_test.cpp b/third_party/spirv-tools/test/val/val_arithmetics_test.cpp index 1c8d88be5a..b82fc97e12 100644 --- a/third_party/spirv-tools/test/val/val_arithmetics_test.cpp +++ b/third_party/spirv-tools/test/val/val_arithmetics_test.cpp @@ -39,6 +39,7 @@ OpCapability Matrix %ext_inst = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft %void = OpTypeVoid %func = OpTypeFunction %void %bool = OpTypeBool @@ -604,10 +605,9 @@ TEST_F(ValidateArithmetics, DotNotVectorTypeOperand1) { )"; CompileSuccessfully(GenerateCode(body).c_str()); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr("Expected float vector as operand: Dot operand index 2")); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), HasSubstr("Operand 6[%float] cannot be a " + "type")); } TEST_F(ValidateArithmetics, DotNotVectorTypeOperand2) { @@ -1165,6 +1165,150 @@ TEST_F(ValidateArithmetics, OuterProductRightOperandWrongDimension) { "vector size of the right operand: OuterProduct")); } +std::string GenerateCoopMatCode(const std::string& extra_types, + const std::string& main_body) { + const std::string prefix = + R"( +OpCapability Shader +OpCapability Float16 +OpCapability CooperativeMatrixNV +OpExtension "SPV_NV_cooperative_matrix" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +%void = OpTypeVoid +%func = OpTypeFunction %void +%bool = OpTypeBool +%f16 = OpTypeFloat 16 +%f32 = OpTypeFloat 32 +%u32 = OpTypeInt 32 0 +%s32 = OpTypeInt 32 1 + +%u32_8 = OpConstant %u32 8 +%u32_16 = OpConstant %u32 16 +%u32_4 = OpConstant %u32 4 +%subgroup = OpConstant %u32 3 + +%f16mat = OpTypeCooperativeMatrixNV %f16 %subgroup %u32_8 %u32_8 +%u32mat = OpTypeCooperativeMatrixNV %u32 %subgroup %u32_8 %u32_8 +%s32mat = OpTypeCooperativeMatrixNV %s32 %subgroup %u32_8 %u32_8 + +%f16_1 = OpConstant %f16 1 +%f32_1 = OpConstant %f32 1 +%u32_1 = OpConstant %u32 1 +%s32_1 = OpConstant %s32 1 + +%f16mat_1 = OpConstantComposite %f16mat %f16_1 +%u32mat_1 = OpConstantComposite %u32mat %u32_1 +%s32mat_1 = OpConstantComposite %s32mat %s32_1 + +%u32_c1 = OpSpecConstant %u32 1 +%u32_c2 = OpSpecConstant %u32 2 + +%f16matc = OpTypeCooperativeMatrixNV %f16 %subgroup %u32_c1 %u32_c2 +%f16matc_1 = OpConstantComposite %f16matc %f16_1 + +%mat16x4 = OpTypeCooperativeMatrixNV %f16 %subgroup %u32_16 %u32_4 +%mat4x16 = OpTypeCooperativeMatrixNV %f16 %subgroup %u32_4 %u32_16 +%mat16x16 = OpTypeCooperativeMatrixNV %f16 %subgroup %u32_16 %u32_16 +%f16mat_16x4_1 = OpConstantComposite %mat16x4 %f16_1 +%f16mat_4x16_1 = OpConstantComposite %mat4x16 %f16_1 +%f16mat_16x16_1 = OpConstantComposite %mat16x16 %f16_1)"; + + const std::string func_begin = + R"( +%main = OpFunction %void None %func +%main_entry = OpLabel)"; + + const std::string suffix = + R"( +OpReturn +OpFunctionEnd)"; + + return prefix + extra_types + func_begin + main_body + suffix; +} + +TEST_F(ValidateArithmetics, CoopMatSuccess) { + const std::string body = R"( +%val1 = OpFAdd %f16mat %f16mat_1 %f16mat_1 +%val2 = OpFSub %f16mat %f16mat_1 %f16mat_1 +%val3 = OpFDiv %f16mat %f16mat_1 %f16mat_1 +%val4 = OpFNegate %f16mat %f16mat_1 +%val5 = OpIAdd %u32mat %u32mat_1 %u32mat_1 +%val6 = OpISub %u32mat %u32mat_1 %u32mat_1 +%val7 = OpUDiv %u32mat %u32mat_1 %u32mat_1 +%val8 = OpIAdd %s32mat %s32mat_1 %s32mat_1 +%val9 = OpISub %s32mat %s32mat_1 %s32mat_1 +%val10 = OpSDiv %s32mat %s32mat_1 %s32mat_1 +%val11 = OpSNegate %s32mat %s32mat_1 +%val12 = OpMatrixTimesScalar %f16mat %f16mat_1 %f16_1 +%val13 = OpMatrixTimesScalar %u32mat %u32mat_1 %u32_1 +%val14 = OpMatrixTimesScalar %s32mat %s32mat_1 %s32_1 +%val15 = OpCooperativeMatrixMulAddNV %mat16x16 %f16mat_16x4_1 %f16mat_4x16_1 %f16mat_16x16_1 +%val16 = OpCooperativeMatrixMulAddNV %f16matc %f16matc_1 %f16matc_1 %f16matc_1 +)"; + + CompileSuccessfully(GenerateCoopMatCode("", body).c_str()); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateArithmetics, CoopMatFMulFail) { + const std::string body = R"( +%val1 = OpFMul %f16mat %f16mat_1 %f16mat_1 +)"; + + CompileSuccessfully(GenerateCoopMatCode("", body).c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "Expected floating scalar or vector type as Result Type: FMul")); +} + +TEST_F(ValidateArithmetics, CoopMatMatrixTimesScalarMismatchFail) { + const std::string body = R"( +%val1 = OpMatrixTimesScalar %f16mat %f16mat_1 %f32_1 +)"; + + CompileSuccessfully(GenerateCoopMatCode("", body).c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Expected scalar operand type to be equal to the component " + "type of the matrix operand: MatrixTimesScalar")); +} + +TEST_F(ValidateArithmetics, CoopMatScopeFail) { + const std::string types = R"( +%workgroup = OpConstant %u32 2 + +%mat16x16_wg = OpTypeCooperativeMatrixNV %f16 %workgroup %u32_16 %u32_16 +%f16matwg_16x16_1 = OpConstantComposite %mat16x16_wg %f16_1 +)"; + + const std::string body = R"( +%val1 = OpCooperativeMatrixMulAddNV %mat16x16 %f16mat_16x4_1 %f16mat_4x16_1 %f16matwg_16x16_1 +)"; + + CompileSuccessfully(GenerateCoopMatCode(types, body).c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "Cooperative matrix scopes must match: CooperativeMatrixMulAddNV")); +} + +TEST_F(ValidateArithmetics, CoopMatDimFail) { + const std::string body = R"( +%val1 = OpCooperativeMatrixMulAddNV %mat16x16 %f16mat_4x16_1 %f16mat_16x4_1 %f16mat_16x16_1 +)"; + + CompileSuccessfully(GenerateCoopMatCode("", body).c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Cooperative matrix 'M' mismatch: CooperativeMatrixMulAddNV")); +} + TEST_F(ValidateArithmetics, IAddCarrySuccess) { const std::string body = R"( %val1 = OpIAddCarry %struct_u32_u32 %u32_0 %u32_1 diff --git a/third_party/spirv-tools/test/val/val_atomics_test.cpp b/third_party/spirv-tools/test/val/val_atomics_test.cpp index 9aece39aa1..cd723b221f 100644 --- a/third_party/spirv-tools/test/val/val_atomics_test.cpp +++ b/third_party/spirv-tools/test/val/val_atomics_test.cpp @@ -28,32 +28,29 @@ using ::testing::Not; using ValidateAtomics = spvtest::ValidateBase; -std::string GenerateShaderCode( - const std::string& body, - const std::string& capabilities_and_extensions = "") { +std::string GenerateShaderCodeImpl( + const std::string& body, const std::string& capabilities_and_extensions, + const std::string& definitions, const std::string& memory_model) { std::ostringstream ss; ss << R"( OpCapability Shader -OpCapability Int64 )"; - ss << capabilities_and_extensions; + ss << "OpMemoryModel Logical " << memory_model << "\n"; ss << R"( -OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft %void = OpTypeVoid %func = OpTypeFunction %void %bool = OpTypeBool %f32 = OpTypeFloat 32 %u32 = OpTypeInt 32 0 -%u64 = OpTypeInt 64 0 %f32vec4 = OpTypeVector %f32 4 %f32_0 = OpConstant %f32 0 %f32_1 = OpConstant %f32 1 %u32_0 = OpConstant %u32 0 %u32_1 = OpConstant %u32 1 -%u64_1 = OpConstant %u64 1 %f32vec4_0000 = OpConstantComposite %f32vec4 %f32_0 %f32_0 %f32_0 %f32_0 %cross_device = OpConstant %u32 0 @@ -61,6 +58,7 @@ OpEntryPoint Fragment %main "main" %workgroup = OpConstant %u32 2 %subgroup = OpConstant %u32 3 %invocation = OpConstant %u32 4 +%queuefamily = OpConstant %u32 5 %relaxed = OpConstant %u32 0 %acquire = OpConstant %u32 2 @@ -76,20 +74,17 @@ OpEntryPoint Fragment %main "main" %u32_ptr = OpTypePointer Workgroup %u32 %u32_var = OpVariable %u32_ptr Workgroup -%u64_ptr = OpTypePointer Workgroup %u64 -%u64_var = OpVariable %u64_ptr Workgroup - %f32vec4_ptr = OpTypePointer Workgroup %f32vec4 %f32vec4_var = OpVariable %f32vec4_ptr Workgroup %f32_ptr_function = OpTypePointer Function %f32 - +)"; + ss << definitions; + ss << R"( %main = OpFunction %void None %func %main_entry = OpLabel )"; - ss << body; - ss << R"( OpReturn OpFunctionEnd)"; @@ -97,6 +92,44 @@ OpFunctionEnd)"; return ss.str(); } +std::string GenerateShaderCode( + const std::string& body, + const std::string& capabilities_and_extensions = "", + const std::string& memory_model = "GLSL450") { + const std::string defintions = R"( +%u64 = OpTypeInt 64 0 +%s64 = OpTypeInt 64 1 + +%u64_1 = OpConstant %u64 1 +%s64_1 = OpConstant %s64 1 + +%u64_ptr = OpTypePointer Workgroup %u64 +%s64_ptr = OpTypePointer Workgroup %s64 +%u64_var = OpVariable %u64_ptr Workgroup +%s64_var = OpVariable %s64_ptr Workgroup +)"; + return GenerateShaderCodeImpl( + body, "OpCapability Int64\n" + capabilities_and_extensions, defintions, + memory_model); +} + +std::string GenerateWebGPUShaderCode( + const std::string& body, + const std::string& capabilities_and_extensions = "") { + const std::string vulkan_memory_capability = R"( +OpCapability VulkanMemoryModelDeviceScopeKHR +OpCapability VulkanMemoryModelKHR +)"; + const std::string vulkan_memory_extension = R"( +OpExtension "SPV_KHR_vulkan_memory_model" +)"; + return GenerateShaderCodeImpl(body, + vulkan_memory_capability + + capabilities_and_extensions + + vulkan_memory_extension, + "", "VulkanKHR"); +} + std::string GenerateKernelCode( const std::string& body, const std::string& capabilities_and_extensions = "") { @@ -154,6 +187,11 @@ OpMemoryModel Physical32 OpenCL %f32vec4_var = OpVariable %f32vec4_ptr Workgroup %f32_ptr_function = OpTypePointer Function %f32 +%f32_ptr_uniformconstant = OpTypePointer UniformConstant %f32 +%f32_uc_var = OpVariable %f32_ptr_uniformconstant UniformConstant + +%f32_ptr_image = OpTypePointer Image %f32 +%f32_im_var = OpVariable %f32_ptr_image Image %main = OpFunction %void None %func %main_entry = OpLabel @@ -190,7 +228,7 @@ TEST_F(ValidateAtomics, AtomicLoadKernelSuccess) { ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); } -TEST_F(ValidateAtomics, AtomicLoadVulkanSuccess) { +TEST_F(ValidateAtomics, AtomicLoadInt32VulkanSuccess) { const std::string body = R"( %val1 = OpAtomicLoad %u32 %u32_var %device %relaxed %val2 = OpAtomicLoad %u32 %u32_var %workgroup %acquire @@ -200,6 +238,64 @@ TEST_F(ValidateAtomics, AtomicLoadVulkanSuccess) { ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0)); } +TEST_F(ValidateAtomics, AtomicLoadFloatVulkan) { + const std::string body = R"( +%val1 = OpAtomicLoad %f32 %f32_var %device %relaxed +%val2 = OpAtomicLoad %f32 %f32_var %workgroup %acquire +)"; + + CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("expected Result Type to be int scalar type")); +} + +TEST_F(ValidateAtomics, AtomicLoadInt64WithCapabilityVulkanSuccess) { + const std::string body = R"( + %val1 = OpAtomicLoad %u64 %u64_var %device %relaxed + %val2 = OpAtomicLoad %u64 %u64_var %workgroup %acquire + )"; + + CompileSuccessfully(GenerateShaderCode(body, "OpCapability Int64Atomics\n"), + SPV_ENV_VULKAN_1_0); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0)); +} + +TEST_F(ValidateAtomics, AtomicLoadInt64WithoutCapabilityVulkan) { + const std::string body = R"( + %val1 = OpAtomicLoad %u64 %u64_var %device %relaxed + %val2 = OpAtomicLoad %u64 %u64_var %workgroup %acquire + )"; + + CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("64-bit atomics require the Int64Atomics capability")); +} + +TEST_F(ValidateAtomics, AtomicStoreOpenCLFunctionPointerStorageTypeSuccess) { + const std::string body = R"( +%f32_var_function = OpVariable %f32_ptr_function Function +OpAtomicStore %f32_var_function %device %relaxed %f32_1 +)"; + + CompileSuccessfully(GenerateKernelCode(body), SPV_ENV_OPENCL_1_2); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_OPENCL_1_2)); +} + +TEST_F(ValidateAtomics, AtomicStoreVulkanFunctionPointerStorageType) { + const std::string body = R"( +%f32_var_function = OpVariable %f32_ptr_function Function +OpAtomicStore %f32_var_function %device %relaxed %f32_1 +)"; + + CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("AtomicStore: Function storage class forbidden when " + "the Shader capability is declared.")); +} + // TODO(atgoo@github.com): the corresponding check fails Vulkan CTS, // reenable once fixed. TEST_F(ValidateAtomics, DISABLED_AtomicLoadVulkanSubgroup) { @@ -272,9 +368,92 @@ TEST_F(ValidateAtomics, AtomicLoadVulkanInt64) { CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "AtomicLoad: 64-bit atomics require the Int64Atomics capability")); +} + +TEST_F(ValidateAtomics, AtomicLoadWebGPUSuccess) { + const std::string body = R"( +%val1 = OpAtomicLoad %u32 %u32_var %queuefamily %relaxed +)"; + + CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); +} + +TEST_F(ValidateAtomics, AtomicLoadWebGPUNonQueueFamilyFailure) { + const std::string body = R"( +%val3 = OpAtomicLoad %u32 %u32_var %invocation %relaxed +)"; + + CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); EXPECT_THAT(getDiagnosticString(), - HasSubstr("AtomicLoad: according to the Vulkan spec atomic " - "Result Type needs to be a 32-bit int scalar type")); + HasSubstr("Memory Scope is limited to QueueFamilyKHR for " + "OpAtomic* operations")); +} + +TEST_F(ValidateAtomics, AtomicLoadWebGPUNonRelaxedFailure) { + const std::string body = R"( +%val1 = OpAtomicLoad %u32 %u32_var %queuefamily %acquire +)"; + + CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("no bits may be set for Memory Semantics of OpAtomic* " + "instructions")); +} + +TEST_F(ValidateAtomics, VK_KHR_shader_atomic_int64Success) { + const std::string body = R"( +%val1 = OpAtomicUMin %u64 %u64_var %device %relaxed %u64_1 +%val2 = OpAtomicUMax %u64 %u64_var %device %relaxed %u64_1 +%val3 = OpAtomicSMin %u64 %u64_var %device %relaxed %u64_1 +%val4 = OpAtomicSMax %u64 %u64_var %device %relaxed %u64_1 +%val5 = OpAtomicAnd %u64 %u64_var %device %relaxed %u64_1 +%val6 = OpAtomicOr %u64 %u64_var %device %relaxed %u64_1 +%val7 = OpAtomicXor %u64 %u64_var %device %relaxed %u64_1 +%val8 = OpAtomicIAdd %u64 %u64_var %device %relaxed %u64_1 +%val9 = OpAtomicExchange %u64 %u64_var %device %relaxed %u64_1 +%val10 = OpAtomicCompareExchange %u64 %u64_var %device %relaxed %relaxed %u64_1 %u64_1 + +%val11 = OpAtomicUMin %s64 %s64_var %device %relaxed %s64_1 +%val12 = OpAtomicUMax %s64 %s64_var %device %relaxed %s64_1 +%val13 = OpAtomicSMin %s64 %s64_var %device %relaxed %s64_1 +%val14 = OpAtomicSMax %s64 %s64_var %device %relaxed %s64_1 +%val15 = OpAtomicAnd %s64 %s64_var %device %relaxed %s64_1 +%val16 = OpAtomicOr %s64 %s64_var %device %relaxed %s64_1 +%val17 = OpAtomicXor %s64 %s64_var %device %relaxed %s64_1 +%val18 = OpAtomicIAdd %s64 %s64_var %device %relaxed %s64_1 +%val19 = OpAtomicExchange %s64 %s64_var %device %relaxed %s64_1 +%val20 = OpAtomicCompareExchange %s64 %s64_var %device %relaxed %relaxed %s64_1 %s64_1 + +%val21 = OpAtomicLoad %u64 %u64_var %device %relaxed +%val22 = OpAtomicLoad %s64 %s64_var %device %relaxed + +OpAtomicStore %u64_var %device %relaxed %u64_1 +OpAtomicStore %s64_var %device %relaxed %s64_1 +)"; + + CompileSuccessfully(GenerateShaderCode(body, "OpCapability Int64Atomics\n"), + SPV_ENV_VULKAN_1_0); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0)); +} + +TEST_F(ValidateAtomics, VK_KHR_shader_atomic_int64MissingCapability) { + const std::string body = R"( +%val1 = OpAtomicUMin %u64 %u64_var %device %relaxed %u64_1 +)"; + + CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "AtomicUMin: 64-bit atomics require the Int64Atomics capability")); } TEST_F(ValidateAtomics, AtomicLoadWrongResultType) { @@ -295,10 +474,9 @@ TEST_F(ValidateAtomics, AtomicLoadWrongPointerType) { )"; CompileSuccessfully(GenerateKernelCode(body)); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr("AtomicLoad: expected Pointer to be of type OpTypePointer")); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Operand 27[%_ptr_Workgroup_float] cannot be a type")); } TEST_F(ValidateAtomics, AtomicLoadWrongPointerDataType) { @@ -322,7 +500,7 @@ TEST_F(ValidateAtomics, AtomicLoadWrongScopeType) { CompileSuccessfully(GenerateKernelCode(body)); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("AtomicLoad: expected Scope to be 32-bit int")); + HasSubstr("AtomicLoad: expected scope to be a 32-bit int")); } TEST_F(ValidateAtomics, AtomicLoadWrongMemorySemanticsType) { @@ -334,7 +512,7 @@ TEST_F(ValidateAtomics, AtomicLoadWrongMemorySemanticsType) { ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), - HasSubstr("AtomicLoad: expected Memory Semantics to be 32-bit int")); + HasSubstr("AtomicLoad: expected Memory Semantics to be a 32-bit int")); } TEST_F(ValidateAtomics, AtomicStoreKernelSuccess) { @@ -405,6 +583,38 @@ OpAtomicStore %u32_var %device %sequentially_consistent %u32_1 "Acquire, AcquireRelease and SequentiallyConsistent")); } +TEST_F(ValidateAtomics, AtomicStoreWebGPUSuccess) { + const std::string body = R"( +OpAtomicStore %u32_var %queuefamily %relaxed %u32_1 +)"; + + CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); +} +TEST_F(ValidateAtomics, AtomicStoreWebGPUNonQueueFamilyFailure) { + const std::string body = R"( +OpAtomicStore %u32_var %workgroup %relaxed %u32_1 +)"; + + CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Memory Scope is limited to QueueFamilyKHR for " + "OpAtomic* operations")); +} + +TEST_F(ValidateAtomics, AtomicStoreWebGPUNonRelaxedFailure) { + const std::string body = R"( +OpAtomicStore %u32_var %queuefamily %release %u32_1 +)"; + + CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("no bits may be set for Memory Semantics of OpAtomic* " + "instructions")); +} + TEST_F(ValidateAtomics, AtomicStoreWrongPointerType) { const std::string body = R"( OpAtomicStore %f32_1 %device %relaxed %f32_1 @@ -431,19 +641,29 @@ OpAtomicStore %f32vec4_var %device %relaxed %f32_1 "type")); } +TEST_F(ValidateAtomics, AtomicStoreWrongPointerStorageTypeForOpenCL) { + const std::string body = R"( +OpAtomicStore %f32_im_var %device %relaxed %f32_1 +)"; + + CompileSuccessfully(GenerateKernelCode(body)); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_OPENCL_1_2)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("AtomicStore: storage class must be Function, Workgroup, " + "CrossWorkGroup or Generic in the OpenCL environment.")); +} + TEST_F(ValidateAtomics, AtomicStoreWrongPointerStorageType) { const std::string body = R"( -%f32_var_function = OpVariable %f32_ptr_function Function -OpAtomicStore %f32_var_function %device %relaxed %f32_1 +OpAtomicStore %f32_uc_var %device %relaxed %f32_1 )"; CompileSuccessfully(GenerateKernelCode(body)); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr("AtomicStore: expected Pointer Storage Class to be Uniform, " - "Workgroup, CrossWorkgroup, Generic, AtomicCounter, Image or " - "StorageBuffer")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("AtomicStore: storage class forbidden by universal " + "validation rules.")); } TEST_F(ValidateAtomics, AtomicStoreWrongScopeType) { @@ -454,7 +674,8 @@ OpAtomicStore %f32_var %f32_1 %relaxed %f32_1 CompileSuccessfully(GenerateKernelCode(body)); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("AtomicStore: expected Scope to be 32-bit int")); + HasSubstr("AtomicStore: expected scope to be a 32-bit int\n " + "OpAtomicStore %28 %float_1 %uint_0_1 %float_1\n")); } TEST_F(ValidateAtomics, AtomicStoreWrongMemorySemanticsType) { @@ -466,7 +687,7 @@ OpAtomicStore %f32_var %device %f32_1 %f32_1 ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), - HasSubstr("AtomicStore: expected Memory Semantics to be 32-bit int")); + HasSubstr("AtomicStore: expected Memory Semantics to be a 32-bit int")); } TEST_F(ValidateAtomics, AtomicStoreWrongValueType) { @@ -485,7 +706,7 @@ OpAtomicStore %f32_var %device %relaxed %u32_1 TEST_F(ValidateAtomics, AtomicExchangeShaderSuccess) { const std::string body = R"( -%val1 = OpAtomicStore %u32_var %device %relaxed %u32_1 +OpAtomicStore %u32_var %device %relaxed %u32_1 %val2 = OpAtomicExchange %u32 %u32_var %device %relaxed %u32_0 )"; @@ -497,7 +718,7 @@ TEST_F(ValidateAtomics, AtomicExchangeKernelSuccess) { const std::string body = R"( OpAtomicStore %f32_var %device %relaxed %f32_1 %val2 = OpAtomicExchange %f32 %f32_var %device %relaxed %f32_0 -%val3 = OpAtomicStore %u32_var %device %relaxed %u32_1 +OpAtomicStore %u32_var %device %relaxed %u32_1 %val4 = OpAtomicExchange %u32 %u32_var %device %relaxed %u32_0 )"; @@ -520,7 +741,7 @@ OpAtomicStore %f32_var %device %relaxed %f32_1 TEST_F(ValidateAtomics, AtomicExchangeWrongResultType) { const std::string body = R"( -%val1 = OpStore %f32vec4_var %f32vec4_0000 +OpStore %f32vec4_var %f32vec4_0000 %val2 = OpAtomicExchange %f32vec4 %f32vec4_var %device %relaxed %f32vec4_0000 )"; @@ -537,16 +758,15 @@ TEST_F(ValidateAtomics, AtomicExchangeWrongPointerType) { )"; CompileSuccessfully(GenerateKernelCode(body)); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr( - "AtomicExchange: expected Pointer to be of type OpTypePointer")); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Operand 33[%_ptr_Workgroup_v4float] cannot be a " + "type")); } TEST_F(ValidateAtomics, AtomicExchangeWrongPointerDataType) { const std::string body = R"( -%val1 = OpStore %f32vec4_var %f32vec4_0000 +OpStore %f32vec4_var %f32vec4_0000 %val2 = OpAtomicExchange %f32 %f32vec4_var %device %relaxed %f32vec4_0000 )"; @@ -567,7 +787,7 @@ OpAtomicStore %f32_var %device %relaxed %f32_1 CompileSuccessfully(GenerateKernelCode(body)); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("AtomicExchange: expected Scope to be 32-bit int")); + HasSubstr("AtomicExchange: expected scope to be a 32-bit int")); } TEST_F(ValidateAtomics, AtomicExchangeWrongMemorySemanticsType) { @@ -580,7 +800,8 @@ OpAtomicStore %f32_var %device %relaxed %f32_1 ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), - HasSubstr("AtomicExchange: expected Memory Semantics to be 32-bit int")); + HasSubstr( + "AtomicExchange: expected Memory Semantics to be a 32-bit int")); } TEST_F(ValidateAtomics, AtomicExchangeWrongValueType) { @@ -598,7 +819,7 @@ OpAtomicStore %f32_var %device %relaxed %f32_1 TEST_F(ValidateAtomics, AtomicCompareExchangeShaderSuccess) { const std::string body = R"( -%val1 = OpAtomicStore %u32_var %device %relaxed %u32_1 +OpAtomicStore %u32_var %device %relaxed %u32_1 %val2 = OpAtomicCompareExchange %u32 %u32_var %device %relaxed %relaxed %u32_0 %u32_0 )"; @@ -610,7 +831,7 @@ TEST_F(ValidateAtomics, AtomicCompareExchangeKernelSuccess) { const std::string body = R"( OpAtomicStore %f32_var %device %relaxed %f32_1 %val2 = OpAtomicCompareExchange %f32 %f32_var %device %relaxed %relaxed %f32_0 %f32_1 -%val3 = OpAtomicStore %u32_var %device %relaxed %u32_1 +OpAtomicStore %u32_var %device %relaxed %u32_1 %val4 = OpAtomicCompareExchange %u32 %u32_var %device %relaxed %relaxed %u32_0 %u32_0 )"; @@ -633,7 +854,7 @@ OpAtomicStore %f32_var %device %relaxed %f32_1 TEST_F(ValidateAtomics, AtomicCompareExchangeWrongResultType) { const std::string body = R"( -%val1 = OpStore %f32vec4_var %f32vec4_0000 +OpStore %f32vec4_var %f32vec4_0000 %val2 = OpAtomicCompareExchange %f32vec4 %f32vec4_var %device %relaxed %relaxed %f32vec4_0000 %f32vec4_0000 )"; @@ -650,15 +871,15 @@ TEST_F(ValidateAtomics, AtomicCompareExchangeWrongPointerType) { )"; CompileSuccessfully(GenerateKernelCode(body)); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("AtomicCompareExchange: expected Pointer to be of type " - "OpTypePointer")); + HasSubstr("Operand 33[%_ptr_Workgroup_v4float] cannot be a " + "type")); } TEST_F(ValidateAtomics, AtomicCompareExchangeWrongPointerDataType) { const std::string body = R"( -%val1 = OpStore %f32vec4_var %f32vec4_0000 +OpStore %f32vec4_var %f32vec4_0000 %val2 = OpAtomicCompareExchange %f32 %f32vec4_var %device %relaxed %relaxed %f32_0 %f32_1 )"; @@ -678,9 +899,9 @@ OpAtomicStore %f32_var %device %relaxed %f32_1 CompileSuccessfully(GenerateKernelCode(body)); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr("AtomicCompareExchange: expected Scope to be 32-bit int")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("AtomicCompareExchange: expected scope to be a 32-bit " + "int")); } TEST_F(ValidateAtomics, AtomicCompareExchangeWrongMemorySemanticsType1) { @@ -691,10 +912,9 @@ OpAtomicStore %f32_var %device %relaxed %f32_1 CompileSuccessfully(GenerateKernelCode(body)); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr( - "AtomicCompareExchange: expected Memory Semantics to be 32-bit int")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("AtomicCompareExchange: expected Memory Semantics to " + "be a 32-bit int")); } TEST_F(ValidateAtomics, AtomicCompareExchangeWrongMemorySemanticsType2) { @@ -705,10 +925,9 @@ OpAtomicStore %f32_var %device %relaxed %f32_1 CompileSuccessfully(GenerateKernelCode(body)); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr( - "AtomicCompareExchange: expected Memory Semantics to be 32-bit int")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("AtomicCompareExchange: expected Memory Semantics to " + "be a 32-bit int")); } TEST_F(ValidateAtomics, AtomicCompareExchangeUnequalRelease) { @@ -752,7 +971,7 @@ OpAtomicStore %f32_var %device %relaxed %f32_1 TEST_F(ValidateAtomics, AtomicCompareExchangeWeakSuccess) { const std::string body = R"( -%val3 = OpAtomicStore %u32_var %device %relaxed %u32_1 +OpAtomicStore %u32_var %device %relaxed %u32_1 %val4 = OpAtomicCompareExchangeWeak %u32 %u32_var %device %relaxed %relaxed %u32_0 %u32_0 )"; @@ -860,9 +1079,9 @@ TEST_F(ValidateAtomics, AtomicFlagTestAndSetWrongScopeType) { CompileSuccessfully(GenerateKernelCode(body)); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("AtomicFlagTestAndSet: " - "expected Scope to be 32-bit int")); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("AtomicFlagTestAndSet: expected scope to be a 32-bit int")); } TEST_F(ValidateAtomics, AtomicFlagTestAndSetWrongMemorySemanticsType) { @@ -874,7 +1093,7 @@ TEST_F(ValidateAtomics, AtomicFlagTestAndSetWrongMemorySemanticsType) { ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("AtomicFlagTestAndSet: " - "expected Memory Semantics to be 32-bit int")); + "expected Memory Semantics to be a 32-bit int")); } TEST_F(ValidateAtomics, AtomicFlagClearAcquire) { @@ -935,7 +1154,8 @@ OpAtomicFlagClear %u32_var %u64_1 %relaxed CompileSuccessfully(GenerateKernelCode(body)); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("AtomicFlagClear: expected Scope to be 32-bit int")); + HasSubstr("AtomicFlagClear: expected scope to be a 32-bit " + "int\n OpAtomicFlagClear %30 %ulong_1 %uint_0_1\n")); } TEST_F(ValidateAtomics, AtomicFlagClearWrongMemorySemanticsType) { @@ -947,7 +1167,8 @@ OpAtomicFlagClear %u32_var %device %u64_1 ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), - HasSubstr("AtomicFlagClear: expected Memory Semantics to be 32-bit int")); + HasSubstr( + "AtomicFlagClear: expected Memory Semantics to be a 32-bit int")); } TEST_F(ValidateAtomics, AtomicIIncrementAcquireAndRelease) { @@ -958,11 +1179,10 @@ OpAtomicStore %u32_var %device %relaxed %u32_1 CompileSuccessfully(GenerateKernelCode(body)); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr("AtomicIIncrement: no more than one of the following Memory " - "Semantics bits can be set at the same time: Acquire, Release, " - "AcquireRelease or SequentiallyConsistent")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("AtomicIIncrement: Memory Semantics can have at most " + "one of the following bits set: Acquire, Release, " + "AcquireRelease or SequentiallyConsistent")); } TEST_F(ValidateAtomics, AtomicUniformMemorySemanticsShader) { @@ -988,17 +1208,17 @@ OpAtomicStore %u32_var %device %relaxed %u32_1 "requires capability Shader")); } +// Lack of the AtomicStorage capability is intentionally ignored, see +// https://github.com/KhronosGroup/glslang/issues/1618 for the reasoning why. TEST_F(ValidateAtomics, AtomicCounterMemorySemanticsNoCapability) { const std::string body = R"( -OpAtomicStore %u32_var %device %relaxed %u32_1 -%val1 = OpAtomicIIncrement %u32 %u32_var %device %acquire_release_atomic_counter_workgroup + OpAtomicStore %u32_var %device %relaxed %u32_1 +%val1 = OpAtomicIIncrement %u32 %u32_var %device +%acquire_release_atomic_counter_workgroup )"; CompileSuccessfully(GenerateKernelCode(body)); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("AtomicIIncrement: Memory Semantics UniformMemory " - "requires capability AtomicStorage")); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); } TEST_F(ValidateAtomics, AtomicCounterMemorySemanticsWithCapability) { @@ -1011,6 +1231,922 @@ OpAtomicStore %u32_var %device %relaxed %u32_1 ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); } +TEST_F(ValidateAtomics, VulkanMemoryModelBanSequentiallyConsistentAtomicLoad) { + const std::string body = R"( +%ld = OpAtomicLoad %u32 %u32_var %workgroup %sequentially_consistent +)"; + + const std::string extra = R"( +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +)"; + + CompileSuccessfully(GenerateShaderCode(body, extra, "VulkanKHR"), + SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("SequentiallyConsistent memory semantics cannot be " + "used with the VulkanKHR memory model.")); +} + +TEST_F(ValidateAtomics, VulkanMemoryModelBanSequentiallyConsistentAtomicStore) { + const std::string body = R"( +OpAtomicStore %u32_var %workgroup %sequentially_consistent %u32_0 +)"; + + const std::string extra = R"( +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +)"; + + CompileSuccessfully(GenerateShaderCode(body, extra, "VulkanKHR"), + SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("SequentiallyConsistent memory semantics cannot be " + "used with the VulkanKHR memory model.")); +} + +TEST_F(ValidateAtomics, + VulkanMemoryModelBanSequentiallyConsistentAtomicExchange) { + const std::string body = R"( +%ex = OpAtomicExchange %u32 %u32_var %workgroup %sequentially_consistent %u32_0 +)"; + + const std::string extra = R"( +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +)"; + + CompileSuccessfully(GenerateShaderCode(body, extra, "VulkanKHR"), + SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("SequentiallyConsistent memory semantics cannot be " + "used with the VulkanKHR memory model.")); +} + +TEST_F(ValidateAtomics, + VulkanMemoryModelBanSequentiallyConsistentAtomicCompareExchangeEqual) { + const std::string body = R"( +%ex = OpAtomicCompareExchange %u32 %u32_var %workgroup %sequentially_consistent %relaxed %u32_0 %u32_0 +)"; + + const std::string extra = R"( +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +)"; + + CompileSuccessfully(GenerateShaderCode(body, extra, "VulkanKHR"), + SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("SequentiallyConsistent memory semantics cannot be " + "used with the VulkanKHR memory model.")); +} + +TEST_F(ValidateAtomics, + VulkanMemoryModelBanSequentiallyConsistentAtomicCompareExchangeUnequal) { + const std::string body = R"( +%ex = OpAtomicCompareExchange %u32 %u32_var %workgroup %relaxed %sequentially_consistent %u32_0 %u32_0 +)"; + + const std::string extra = R"( +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +)"; + + CompileSuccessfully(GenerateShaderCode(body, extra, "VulkanKHR"), + SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("SequentiallyConsistent memory semantics cannot be " + "used with the VulkanKHR memory model.")); +} + +TEST_F(ValidateAtomics, + VulkanMemoryModelBanSequentiallyConsistentAtomicIIncrement) { + const std::string body = R"( +%inc = OpAtomicIIncrement %u32 %u32_var %workgroup %sequentially_consistent +)"; + + const std::string extra = R"( +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +)"; + + CompileSuccessfully(GenerateShaderCode(body, extra, "VulkanKHR"), + SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("SequentiallyConsistent memory semantics cannot be " + "used with the VulkanKHR memory model.")); +} + +TEST_F(ValidateAtomics, + VulkanMemoryModelBanSequentiallyConsistentAtomicIDecrement) { + const std::string body = R"( +%dec = OpAtomicIDecrement %u32 %u32_var %workgroup %sequentially_consistent +)"; + + const std::string extra = R"( +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +)"; + + CompileSuccessfully(GenerateShaderCode(body, extra, "VulkanKHR"), + SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("SequentiallyConsistent memory semantics cannot be " + "used with the VulkanKHR memory model.")); +} + +TEST_F(ValidateAtomics, VulkanMemoryModelBanSequentiallyConsistentAtomicIAdd) { + const std::string body = R"( +%add = OpAtomicIAdd %u32 %u32_var %workgroup %sequentially_consistent %u32_0 +)"; + + const std::string extra = R"( +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +)"; + + CompileSuccessfully(GenerateShaderCode(body, extra, "VulkanKHR"), + SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("SequentiallyConsistent memory semantics cannot be " + "used with the VulkanKHR memory model.")); +} + +TEST_F(ValidateAtomics, VulkanMemoryModelBanSequentiallyConsistentAtomicISub) { + const std::string body = R"( +%sub = OpAtomicISub %u32 %u32_var %workgroup %sequentially_consistent %u32_0 +)"; + + const std::string extra = R"( +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +)"; + + CompileSuccessfully(GenerateShaderCode(body, extra, "VulkanKHR"), + SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("SequentiallyConsistent memory semantics cannot be " + "used with the VulkanKHR memory model.")); +} + +TEST_F(ValidateAtomics, VulkanMemoryModelBanSequentiallyConsistentAtomicSMin) { + const std::string body = R"( +%min = OpAtomicSMin %u32 %u32_var %workgroup %sequentially_consistent %u32_0 +)"; + + const std::string extra = R"( +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +)"; + + CompileSuccessfully(GenerateShaderCode(body, extra, "VulkanKHR"), + SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("SequentiallyConsistent memory semantics cannot be " + "used with the VulkanKHR memory model.")); +} + +TEST_F(ValidateAtomics, VulkanMemoryModelBanSequentiallyConsistentAtomicUMin) { + const std::string body = R"( +%min = OpAtomicUMin %u32 %u32_var %workgroup %sequentially_consistent %u32_0 +)"; + + const std::string extra = R"( +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +)"; + + CompileSuccessfully(GenerateShaderCode(body, extra, "VulkanKHR"), + SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("SequentiallyConsistent memory semantics cannot be " + "used with the VulkanKHR memory model.")); +} + +TEST_F(ValidateAtomics, VulkanMemoryModelBanSequentiallyConsistentAtomicSMax) { + const std::string body = R"( +%max = OpAtomicSMax %u32 %u32_var %workgroup %sequentially_consistent %u32_0 +)"; + + const std::string extra = R"( +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +)"; + + CompileSuccessfully(GenerateShaderCode(body, extra, "VulkanKHR"), + SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("SequentiallyConsistent memory semantics cannot be " + "used with the VulkanKHR memory model.")); +} + +TEST_F(ValidateAtomics, VulkanMemoryModelBanSequentiallyConsistentAtomicUMax) { + const std::string body = R"( +%max = OpAtomicUMax %u32 %u32_var %workgroup %sequentially_consistent %u32_0 +)"; + + const std::string extra = R"( +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +)"; + + CompileSuccessfully(GenerateShaderCode(body, extra, "VulkanKHR"), + SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("SequentiallyConsistent memory semantics cannot be " + "used with the VulkanKHR memory model.")); +} + +TEST_F(ValidateAtomics, VulkanMemoryModelBanSequentiallyConsistentAtomicAnd) { + const std::string body = R"( +%and = OpAtomicAnd %u32 %u32_var %workgroup %sequentially_consistent %u32_0 +)"; + + const std::string extra = R"( +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +)"; + + CompileSuccessfully(GenerateShaderCode(body, extra, "VulkanKHR"), + SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("SequentiallyConsistent memory semantics cannot be " + "used with the VulkanKHR memory model.")); +} + +TEST_F(ValidateAtomics, VulkanMemoryModelBanSequentiallyConsistentAtomicOr) { + const std::string body = R"( +%or = OpAtomicOr %u32 %u32_var %workgroup %sequentially_consistent %u32_0 +)"; + + const std::string extra = R"( +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +)"; + + CompileSuccessfully(GenerateShaderCode(body, extra, "VulkanKHR"), + SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("SequentiallyConsistent memory semantics cannot be " + "used with the VulkanKHR memory model.")); +} + +TEST_F(ValidateAtomics, VulkanMemoryModelBanSequentiallyConsistentAtomicXor) { + const std::string body = R"( +%xor = OpAtomicXor %u32 %u32_var %workgroup %sequentially_consistent %u32_0 +)"; + + const std::string extra = R"( +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +)"; + + CompileSuccessfully(GenerateShaderCode(body, extra, "VulkanKHR"), + SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("SequentiallyConsistent memory semantics cannot be " + "used with the VulkanKHR memory model.")); +} + +TEST_F(ValidateAtomics, OutputMemoryKHRRequiresVulkanMemoryModelKHR) { + const std::string text = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %1 "func" +OpExecutionMode %1 OriginUpperLeft +%2 = OpTypeVoid +%3 = OpTypeInt 32 0 +%semantics = OpConstant %3 4100 +%5 = OpTypeFunction %2 +%workgroup = OpConstant %3 2 +%ptr = OpTypePointer Workgroup %3 +%var = OpVariable %ptr Workgroup +%1 = OpFunction %2 None %5 +%7 = OpLabel +OpAtomicStore %var %workgroup %semantics %workgroup +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("AtomicStore: Memory Semantics OutputMemoryKHR " + "requires capability VulkanMemoryModelKHR")); +} + +TEST_F(ValidateAtomics, MakeAvailableKHRRequiresVulkanMemoryModelKHR) { + const std::string text = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %1 "func" +OpExecutionMode %1 OriginUpperLeft +%2 = OpTypeVoid +%3 = OpTypeInt 32 0 +%semantics = OpConstant %3 8196 +%5 = OpTypeFunction %2 +%workgroup = OpConstant %3 2 +%ptr = OpTypePointer Workgroup %3 +%var = OpVariable %ptr Workgroup +%1 = OpFunction %2 None %5 +%7 = OpLabel +OpAtomicStore %var %workgroup %semantics %workgroup +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("AtomicStore: Memory Semantics MakeAvailableKHR " + "requires capability VulkanMemoryModelKHR")); +} + +TEST_F(ValidateAtomics, MakeVisibleKHRRequiresVulkanMemoryModelKHR) { + const std::string text = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %1 "func" +OpExecutionMode %1 OriginUpperLeft +%2 = OpTypeVoid +%3 = OpTypeInt 32 0 +%semantics = OpConstant %3 16386 +%5 = OpTypeFunction %2 +%workgroup = OpConstant %3 2 +%ptr = OpTypePointer Workgroup %3 +%var = OpVariable %ptr Workgroup +%1 = OpFunction %2 None %5 +%7 = OpLabel +%ld = OpAtomicLoad %3 %var %workgroup %semantics +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("AtomicLoad: Memory Semantics MakeVisibleKHR requires " + "capability VulkanMemoryModelKHR")); +} + +TEST_F(ValidateAtomics, MakeAvailableKHRRequiresReleaseSemantics) { + const std::string text = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +OpEntryPoint Fragment %1 "func" +OpExecutionMode %1 OriginUpperLeft +%2 = OpTypeVoid +%3 = OpTypeInt 32 0 +%semantics = OpConstant %3 8448 +%5 = OpTypeFunction %2 +%workgroup = OpConstant %3 2 +%ptr = OpTypePointer Workgroup %3 +%var = OpVariable %ptr Workgroup +%1 = OpFunction %2 None %5 +%7 = OpLabel +OpAtomicStore %var %workgroup %semantics %workgroup +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("AtomicStore: MakeAvailableKHR Memory Semantics also requires " + "either Release or AcquireRelease Memory Semantics")); +} + +TEST_F(ValidateAtomics, MakeVisibleKHRRequiresAcquireSemantics) { + const std::string text = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +OpEntryPoint Fragment %1 "func" +OpExecutionMode %1 OriginUpperLeft +%2 = OpTypeVoid +%3 = OpTypeInt 32 0 +%semantics = OpConstant %3 16640 +%5 = OpTypeFunction %2 +%workgroup = OpConstant %3 2 +%ptr = OpTypePointer Workgroup %3 +%var = OpVariable %ptr Workgroup +%1 = OpFunction %2 None %5 +%7 = OpLabel +%ld = OpAtomicLoad %3 %var %workgroup %semantics +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("AtomicLoad: MakeVisibleKHR Memory Semantics also requires " + "either Acquire or AcquireRelease Memory Semantics")); +} + +TEST_F(ValidateAtomics, MakeAvailableKHRRequiresStorageSemantics) { + const std::string text = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +OpEntryPoint Fragment %1 "func" +OpExecutionMode %1 OriginUpperLeft +%2 = OpTypeVoid +%3 = OpTypeInt 32 0 +%semantics = OpConstant %3 8196 +%5 = OpTypeFunction %2 +%workgroup = OpConstant %3 2 +%ptr = OpTypePointer Workgroup %3 +%var = OpVariable %ptr Workgroup +%1 = OpFunction %2 None %5 +%7 = OpLabel +OpAtomicStore %var %workgroup %semantics %workgroup +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "AtomicStore: expected Memory Semantics to include a storage class")); +} + +TEST_F(ValidateAtomics, MakeVisibleKHRRequiresStorageSemantics) { + const std::string text = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +OpEntryPoint Fragment %1 "func" +OpExecutionMode %1 OriginUpperLeft +%2 = OpTypeVoid +%3 = OpTypeInt 32 0 +%semantics = OpConstant %3 16386 +%5 = OpTypeFunction %2 +%workgroup = OpConstant %3 2 +%ptr = OpTypePointer Workgroup %3 +%var = OpVariable %ptr Workgroup +%1 = OpFunction %2 None %5 +%7 = OpLabel +%ld = OpAtomicLoad %3 %var %workgroup %semantics +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "AtomicLoad: expected Memory Semantics to include a storage class")); +} + +TEST_F(ValidateAtomics, VulkanMemoryModelAllowsQueueFamilyKHR) { + const std::string body = R"( +%val = OpAtomicAnd %u32 %u32_var %queuefamily %relaxed %u32_1 +)"; + + const std::string extra = R"( +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +)"; + + CompileSuccessfully(GenerateShaderCode(body, extra, "VulkanKHR"), + SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1)); +} + +TEST_F(ValidateAtomics, NonVulkanMemoryModelDisallowsQueueFamilyKHR) { + const std::string body = R"( +%val = OpAtomicAnd %u32 %u32_var %queuefamily %relaxed %u32_1 +)"; + + CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("AtomicAnd: Memory Scope QueueFamilyKHR requires " + "capability VulkanMemoryModelKHR\n %42 = OpAtomicAnd " + "%uint %29 %uint_5 %uint_0_1 %uint_1\n")); +} + +TEST_F(ValidateAtomics, SemanticsSpecConstantShader) { + const std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%spec_const = OpSpecConstant %int 0 +%workgroup = OpConstant %int 2 +%ptr_int_workgroup = OpTypePointer Workgroup %int +%var = OpVariable %ptr_int_workgroup Workgroup +%voidfn = OpTypeFunction %void +%func = OpFunction %void None %voidfn +%entry = OpLabel +%ld = OpAtomicLoad %int %var %workgroup %spec_const +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Memory Semantics ids must be OpConstant when Shader " + "capability is present")); +} + +TEST_F(ValidateAtomics, SemanticsSpecConstantKernel) { + const std::string spirv = R"( +OpCapability Kernel +OpCapability Linkage +OpMemoryModel Logical OpenCL +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%spec_const = OpSpecConstant %int 0 +%workgroup = OpConstant %int 2 +%ptr_int_workgroup = OpTypePointer Workgroup %int +%var = OpVariable %ptr_int_workgroup Workgroup +%voidfn = OpTypeFunction %void +%func = OpFunction %void None %voidfn +%entry = OpLabel +%ld = OpAtomicLoad %int %var %workgroup %spec_const +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateAtomics, ScopeSpecConstantShader) { + const std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%spec_const = OpSpecConstant %int 0 +%relaxed = OpConstant %int 0 +%ptr_int_workgroup = OpTypePointer Workgroup %int +%var = OpVariable %ptr_int_workgroup Workgroup +%voidfn = OpTypeFunction %void +%func = OpFunction %void None %voidfn +%entry = OpLabel +%ld = OpAtomicLoad %int %var %spec_const %relaxed +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "Scope ids must be OpConstant when Shader capability is present")); +} + +TEST_F(ValidateAtomics, ScopeSpecConstantKernel) { + const std::string spirv = R"( +OpCapability Kernel +OpCapability Linkage +OpMemoryModel Logical OpenCL +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%spec_const = OpSpecConstant %int 0 +%relaxed = OpConstant %int 0 +%ptr_int_workgroup = OpTypePointer Workgroup %int +%var = OpVariable %ptr_int_workgroup Workgroup +%voidfn = OpTypeFunction %void +%func = OpFunction %void None %voidfn +%entry = OpLabel +%ld = OpAtomicLoad %int %var %spec_const %relaxed +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateAtomics, VulkanMemoryModelDeviceScopeBad) { + const std::string body = R"( +%val = OpAtomicAnd %u32 %u32_var %device %relaxed %u32_1 +)"; + + const std::string extra = R"(OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +)"; + + CompileSuccessfully(GenerateShaderCode(body, extra, "VulkanKHR"), + SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Use of device scope with VulkanKHR memory model requires the " + "VulkanMemoryModelDeviceScopeKHR capability")); +} + +TEST_F(ValidateAtomics, VulkanMemoryModelDeviceScopeGood) { + const std::string body = R"( +%val = OpAtomicAnd %u32 %u32_var %device %relaxed %u32_1 +)"; + + const std::string extra = R"(OpCapability VulkanMemoryModelKHR +OpCapability VulkanMemoryModelDeviceScopeKHR +OpExtension "SPV_KHR_vulkan_memory_model" +)"; + + CompileSuccessfully(GenerateShaderCode(body, extra, "VulkanKHR"), + SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); +} + +TEST_F(ValidateAtomics, WebGPUCrossDeviceMemoryScopeBad) { + const std::string body = R"( +%val1 = OpAtomicLoad %u32 %u32_var %cross_device %relaxed +)"; + + CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("in WebGPU environment Memory Scope is limited to " + "QueueFamilyKHR for OpAtomic* operations")); +} + +TEST_F(ValidateAtomics, WebGPUDeviceMemoryScopeBad) { + const std::string body = R"( +%val1 = OpAtomicLoad %u32 %u32_var %device %relaxed +)"; + + CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("in WebGPU environment Memory Scope is limited to " + "QueueFamilyKHR for OpAtomic* operations")); +} + +TEST_F(ValidateAtomics, WebGPUWorkgroupMemoryScopeBad) { + const std::string body = R"( +%val1 = OpAtomicLoad %u32 %u32_var %workgroup %relaxed +)"; + + CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("in WebGPU environment Memory Scope is limited to " + "QueueFamilyKHR for OpAtomic* operations")); +} + +TEST_F(ValidateAtomics, WebGPUSubgroupMemoryScopeBad) { + const std::string body = R"( +%val1 = OpAtomicLoad %u32 %u32_var %subgroup %relaxed +)"; + + CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("in WebGPU environment Memory Scope is limited to " + "QueueFamilyKHR for OpAtomic* operations")); +} + +TEST_F(ValidateAtomics, WebGPUInvocationMemoryScopeBad) { + const std::string body = R"( +%val1 = OpAtomicLoad %u32 %u32_var %invocation %relaxed +)"; + + CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("in WebGPU environment Memory Scope is limited to " + "QueueFamilyKHR for OpAtomic* operations")); +} + +TEST_F(ValidateAtomics, WebGPUQueueFamilyMemoryScopeGood) { + const std::string body = R"( +%val1 = OpAtomicLoad %u32 %u32_var %queuefamily %relaxed +)"; + + CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); +} + +TEST_F(ValidateAtomics, CompareExchangeWeakV13ValV14Good) { + const std::string body = R"( +%val1 = OpAtomicCompareExchangeWeak %u32 %u32_var %device %relaxed %relaxed %u32_0 %u32_0 +)"; + + CompileSuccessfully(GenerateKernelCode(body), SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); +} + +TEST_F(ValidateAtomics, CompareExchangeWeakV14Bad) { + const std::string body = R"( +%val1 = OpAtomicCompareExchangeWeak %u32 %u32_var %device %relaxed %relaxed %u32_0 %u32_0 +)"; + + CompileSuccessfully(GenerateKernelCode(body), SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_ERROR_WRONG_VERSION, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "AtomicCompareExchangeWeak requires SPIR-V version 1.3 or earlier")); +} + +TEST_F(ValidateAtomics, CompareExchangeVolatileMatch) { + const std::string spirv = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpCapability Linkage +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%int_1 = OpConstant %int 1 +%workgroup = OpConstant %int 2 +%volatile = OpConstant %int 32768 +%ptr_wg_int = OpTypePointer Workgroup %int +%wg_var = OpVariable %ptr_wg_int Workgroup +%void_fn = OpTypeFunction %void +%func = OpFunction %void None %void_fn +%entry = OpLabel +%cmp_ex = OpAtomicCompareExchange %int %wg_var %workgroup %volatile %volatile %int_0 %int_1 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateAtomics, CompareExchangeVolatileMismatch) { + const std::string spirv = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpCapability Linkage +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%int_1 = OpConstant %int 1 +%workgroup = OpConstant %int 2 +%volatile = OpConstant %int 32768 +%non_volatile = OpConstant %int 0 +%ptr_wg_int = OpTypePointer Workgroup %int +%wg_var = OpVariable %ptr_wg_int Workgroup +%void_fn = OpTypeFunction %void +%func = OpFunction %void None %void_fn +%entry = OpLabel +%cmp_ex = OpAtomicCompareExchange %int %wg_var %workgroup %non_volatile %volatile %int_0 %int_1 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Volatile mask setting must match for Equal and " + "Unequal memory semantics")); +} + +TEST_F(ValidateAtomics, CompareExchangeVolatileMismatchCooperativeMatrix) { + const std::string spirv = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpCapability Linkage +OpCapability CooperativeMatrixNV +OpExtension "SPV_KHR_vulkan_memory_model" +OpExtension "SPV_NV_cooperative_matrix" +OpMemoryModel Logical VulkanKHR +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%int_1 = OpConstant %int 1 +%workgroup = OpConstant %int 2 +%volatile = OpSpecConstant %int 32768 +%non_volatile = OpSpecConstant %int 32768 +%ptr_wg_int = OpTypePointer Workgroup %int +%wg_var = OpVariable %ptr_wg_int Workgroup +%void_fn = OpTypeFunction %void +%func = OpFunction %void None %void_fn +%entry = OpLabel +%cmp_ex = OpAtomicCompareExchange %int %wg_var %workgroup %volatile %non_volatile %int_0 %int_1 +OpReturn +OpFunctionEnd +)"; + + // This is ok because we cannot evaluate the spec constant defaults. + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateAtomics, VolatileRequiresVulkanMemoryModel) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%int_1 = OpConstant %int 1 +%workgroup = OpConstant %int 2 +%volatile = OpConstant %int 32768 +%ptr_wg_int = OpTypePointer Workgroup %int +%wg_var = OpVariable %ptr_wg_int Workgroup +%void_fn = OpTypeFunction %void +%func = OpFunction %void None %void_fn +%entry = OpLabel +%ld = OpAtomicLoad %int %wg_var %workgroup %volatile +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Memory Semantics Volatile requires capability " + "VulkanMemoryModelKHR")); +} + +TEST_F(ValidateAtomics, CooperativeMatrixSemanticsMustBeConstant) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability CooperativeMatrixNV +OpExtension "SPV_NV_cooperative_matrix" +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%int_1 = OpConstant %int 1 +%workgroup = OpConstant %int 2 +%undef = OpUndef %int +%ptr_wg_int = OpTypePointer Workgroup %int +%wg_var = OpVariable %ptr_wg_int Workgroup +%void_fn = OpTypeFunction %void +%func = OpFunction %void None %void_fn +%entry = OpLabel +%ld = OpAtomicLoad %int %wg_var %workgroup %undef +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Memory Semantics must be a constant instruction when " + "CooperativeMatrixNV capability is present")); +} + } // namespace } // namespace val } // namespace spvtools diff --git a/third_party/spirv-tools/test/val/val_barriers_test.cpp b/third_party/spirv-tools/test/val/val_barriers_test.cpp index 38c168eda9..ae166d9547 100644 --- a/third_party/spirv-tools/test/val/val_barriers_test.cpp +++ b/third_party/spirv-tools/test/val/val_barriers_test.cpp @@ -28,19 +28,26 @@ using ::testing::Not; using ValidateBarriers = spvtest::ValidateBase; -std::string GenerateShaderCode( - const std::string& body, - const std::string& capabilities_and_extensions = "", - const std::string& execution_model = "GLCompute") { +std::string GenerateShaderCodeImpl( + const std::string& body, const std::string& capabilities_and_extensions, + const std::string& definitions, const std::string& execution_model, + const std::string& memory_model) { std::ostringstream ss; ss << R"( OpCapability Shader -OpCapability Int64 )"; ss << capabilities_and_extensions; - ss << "OpMemoryModel Logical GLSL450\n"; + ss << memory_model << std::endl; ss << "OpEntryPoint " << execution_model << " %main \"main\"\n"; + if (execution_model == "Fragment") { + ss << "OpExecutionMode %main OriginUpperLeft\n"; + } else if (execution_model == "Geometry") { + ss << "OpExecutionMode %main InputPoints\n"; + ss << "OpExecutionMode %main OutputPoints\n"; + } else if (execution_model == "GLCompute") { + ss << "OpExecutionMode %main LocalSize 1 1 1\n"; + } ss << R"( %void = OpTypeVoid @@ -48,21 +55,21 @@ OpCapability Int64 %bool = OpTypeBool %f32 = OpTypeFloat 32 %u32 = OpTypeInt 32 0 -%u64 = OpTypeInt 64 0 %f32_0 = OpConstant %f32 0 %f32_1 = OpConstant %f32 1 %u32_0 = OpConstant %u32 0 %u32_1 = OpConstant %u32 1 %u32_4 = OpConstant %u32 4 -%u64_0 = OpConstant %u64 0 -%u64_1 = OpConstant %u64 1 - +)"; + ss << definitions; + ss << R"( %cross_device = OpConstant %u32 0 %device = OpConstant %u32 1 %workgroup = OpConstant %u32 2 %subgroup = OpConstant %u32 3 %invocation = OpConstant %u32 4 +%queuefamily = OpConstant %u32 5 %none = OpConstant %u32 0 %acquire = OpConstant %u32 2 @@ -71,9 +78,16 @@ OpCapability Int64 %acquire_and_release = OpConstant %u32 6 %sequentially_consistent = OpConstant %u32 16 %acquire_release_uniform_workgroup = OpConstant %u32 328 +%acquire_uniform_workgroup = OpConstant %u32 322 +%release_uniform_workgroup = OpConstant %u32 324 %acquire_and_release_uniform = OpConstant %u32 70 %acquire_release_subgroup = OpConstant %u32 136 +%acquire_release_workgroup = OpConstant %u32 264 %uniform = OpConstant %u32 64 +%uniform_workgroup = OpConstant %u32 320 +%workgroup_memory = OpConstant %u32 256 +%image_memory = OpConstant %u32 2048 +%uniform_image_memory = OpConstant %u32 2112 %main = OpFunction %void None %func %main_entry = OpLabel @@ -88,6 +102,42 @@ OpFunctionEnd)"; return ss.str(); } +std::string GenerateShaderCode( + const std::string& body, + const std::string& capabilities_and_extensions = "", + const std::string& execution_model = "GLCompute") { + const std::string int64_capability = R"( +OpCapability Int64 +)"; + const std::string int64_declarations = R"( +%u64 = OpTypeInt 64 0 +%u64_0 = OpConstant %u64 0 +%u64_1 = OpConstant %u64 1 +)"; + const std::string memory_model = "OpMemoryModel Logical GLSL450"; + return GenerateShaderCodeImpl( + body, int64_capability + capabilities_and_extensions, int64_declarations, + execution_model, memory_model); +} + +std::string GenerateWebGPUShaderCode( + const std::string& body, + const std::string& capabilities_and_extensions = "", + const std::string& execution_model = "GLCompute") { + const std::string vulkan_memory_capability = R"( +OpCapability VulkanMemoryModelKHR +)"; + const std::string vulkan_memory_extension = R"( +OpExtension "SPV_KHR_vulkan_memory_model" +)"; + const std::string memory_model = "OpMemoryModel Logical VulkanKHR"; + return GenerateShaderCodeImpl(body, + vulkan_memory_capability + + capabilities_and_extensions + + vulkan_memory_extension, + "", execution_model, memory_model); +} + std::string GenerateKernelCode( const std::string& body, const std::string& capabilities_and_extensions = "") { @@ -132,9 +182,7 @@ OpMemoryModel Physical32 OpenCL %acquire_release = OpConstant %u32 8 %acquire_and_release = OpConstant %u32 6 %sequentially_consistent = OpConstant %u32 16 -%acquire_release_uniform_workgroup = OpConstant %u32 328 -%acquire_and_release_uniform = OpConstant %u32 70 -%uniform = OpConstant %u32 64 +%acquire_release_workgroup = OpConstant %u32 264 %named_barrier = OpTypeNamedBarrier @@ -172,7 +220,7 @@ OpControlBarrier %workgroup %workgroup %acquire OpControlBarrier %workgroup %device %release OpControlBarrier %cross_device %cross_device %acquire_release OpControlBarrier %cross_device %cross_device %sequentially_consistent -OpControlBarrier %cross_device %cross_device %acquire_release_uniform_workgroup +OpControlBarrier %cross_device %cross_device %acquire_release_workgroup )"; CompileSuccessfully(GenerateKernelCode(body), SPV_ENV_UNIVERSAL_1_1); @@ -204,6 +252,64 @@ OpControlBarrier %workgroup %workgroup %acquire_release_uniform_workgroup ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0)); } +TEST_F(ValidateBarriers, OpControlBarrierWebGPUAcquireReleaseSuccess) { + const std::string body = R"( +OpControlBarrier %workgroup %workgroup %acquire_release_workgroup +)"; + + CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); +} + +TEST_F(ValidateBarriers, OpControlBarrierWebGPURelaxedFailure) { + const std::string body = R"( +OpControlBarrier %workgroup %workgroup %workgroup +)"; + + CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("For WebGPU, AcquireRelease must be set for Memory " + "Semantics of OpControlBarrier")); +} + +TEST_F(ValidateBarriers, OpControlBarrierWebGPUMissingWorkgroupFailure) { + const std::string body = R"( +OpControlBarrier %workgroup %workgroup %acquire_release +)"; + + CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("For WebGPU, WorkgroupMemory must be set for Memory " + "Semantics")); +} + +TEST_F(ValidateBarriers, OpControlBarrierWebGPUUniformFailure) { + const std::string body = R"( +OpControlBarrier %workgroup %workgroup %acquire_release_uniform_workgroup +)"; + + CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("For WebGPU only WorkgroupMemory and AcquireRelease may be set " + "for Memory Semantics of OpControlBarrier.")); +} + +TEST_F(ValidateBarriers, OpControlBarrierWebGPUReleaseFailure) { + const std::string body = R"( +OpControlBarrier %workgroup %workgroup %release_uniform_workgroup +)"; + + CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("For WebGPU, AcquireRelease must be set for Memory " + "Semantics of OpControlBarrier")); +} + TEST_F(ValidateBarriers, OpControlBarrierExecutionModelFragmentSpirv12) { const std::string body = R"( OpControlBarrier %device %device %none @@ -235,9 +341,8 @@ OpControlBarrier %f32_1 %device %none CompileSuccessfully(GenerateShaderCode(body)); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr("ControlBarrier: expected Execution Scope to be a 32-bit int")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("ControlBarrier: expected scope to be a 32-bit int")); } TEST_F(ValidateBarriers, OpControlBarrierU64ExecutionScope) { @@ -247,9 +352,8 @@ OpControlBarrier %u64_1 %device %none CompileSuccessfully(GenerateShaderCode(body)); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr("ControlBarrier: expected Execution Scope to be a 32-bit int")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("ControlBarrier: expected scope to be a 32-bit int")); } TEST_F(ValidateBarriers, OpControlBarrierFloatMemoryScope) { @@ -259,9 +363,8 @@ OpControlBarrier %device %f32_1 %none CompileSuccessfully(GenerateShaderCode(body)); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr("ControlBarrier: expected Memory Scope to be a 32-bit int")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("ControlBarrier: expected scope to be a 32-bit int")); } TEST_F(ValidateBarriers, OpControlBarrierU64MemoryScope) { @@ -271,9 +374,8 @@ OpControlBarrier %device %u64_1 %none CompileSuccessfully(GenerateShaderCode(body)); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr("ControlBarrier: expected Memory Scope to be a 32-bit int")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("ControlBarrier: expected scope to be a 32-bit int")); } TEST_F(ValidateBarriers, OpControlBarrierFloatMemorySemantics) { @@ -314,6 +416,30 @@ OpControlBarrier %device %workgroup %none "is limited to Workgroup and Subgroup")); } +TEST_F(ValidateBarriers, OpControlBarrierWebGPUExecutionScopeDeviceBad) { + const std::string body = R"( +OpControlBarrier %device %workgroup %none +)"; + + CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("ControlBarrier: in WebGPU environment Execution Scope " + "is limited to Workgroup")); +} + +TEST_F(ValidateBarriers, OpControlBarrierWebGPUExecutionScopeSubgroupBad) { + const std::string body = R"( +OpControlBarrier %subgroup %workgroup %none +)"; + + CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("ControlBarrier: in WebGPU environment Execution Scope " + "is limited to Workgroup")); +} + TEST_F(ValidateBarriers, OpControlBarrierVulkanMemoryScopeSubgroup) { const std::string body = R"( OpControlBarrier %subgroup %subgroup %none @@ -348,6 +474,18 @@ OpControlBarrier %subgroup %cross_device %none "cannot be CrossDevice")); } +TEST_F(ValidateBarriers, OpControlBarrierWebGPUMemoryScopeNonWorkgroup) { + const std::string body = R"( +OpControlBarrier %workgroup %subgroup %acquire_release_workgroup +)"; + + CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("ControlBarrier: in WebGPU environment Memory Scope is " + "limited to Workgroup for OpControlBarrier")); +} + TEST_F(ValidateBarriers, OpControlBarrierAcquireAndRelease) { const std::string body = R"( OpControlBarrier %device %device %acquire_and_release_uniform @@ -550,8 +688,8 @@ OpMemoryBarrier %device %uniform TEST_F(ValidateBarriers, OpMemoryBarrierKernelSuccess) { const std::string body = R"( -OpMemoryBarrier %cross_device %acquire_release_uniform_workgroup -OpMemoryBarrier %device %uniform +OpMemoryBarrier %cross_device %acquire_release_workgroup +OpMemoryBarrier %device %none )"; CompileSuccessfully(GenerateKernelCode(body), SPV_ENV_UNIVERSAL_1_1); @@ -567,6 +705,87 @@ OpMemoryBarrier %workgroup %acquire_release_uniform_workgroup ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0)); } +TEST_F(ValidateBarriers, OpMemoryBarrierWebGPUImageMemorySuccess) { + const std::string body = R"( +OpMemoryBarrier %workgroup %image_memory +)"; + + CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); +} + +TEST_F(ValidateBarriers, OpMemoryBarrierWebGPUDeviceFailure) { + const std::string body = R"( +OpMemoryBarrier %subgroup %image_memory +)"; + + CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("in WebGPU environment Memory Scope is limited to " + "Workgroup for OpMemoryBarrier")); +} + +TEST_F(ValidateBarriers, OpMemoryBarrierWebGPUAcquireReleaseFailure) { + const std::string body = R"( +OpMemoryBarrier %workgroup %acquire_release_uniform_workgroup +)"; + + CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("ImageMemory must be set for Memory Semantics of " + "OpMemoryBarrier")); +} + +TEST_F(ValidateBarriers, OpMemoryBarrierWebGPURelaxedFailure) { + const std::string body = R"( +OpMemoryBarrier %workgroup %uniform_workgroup +)"; + + CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("ImageMemory must be set for Memory Semantics of " + "OpMemoryBarrier")); +} + +TEST_F(ValidateBarriers, OpMemoryBarrierWebGPUAcquireFailure) { + const std::string body = R"( +OpMemoryBarrier %workgroup %acquire_uniform_workgroup +)"; + + CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("ImageMemory must be set for Memory Semantics of " + "OpMemoryBarrier")); +} + +TEST_F(ValidateBarriers, OpMemoryBarrierWebGPUReleaseFailure) { + const std::string body = R"( +OpMemoryBarrier %workgroup %release_uniform_workgroup +)"; + + CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("ImageMemory must be set for Memory Semantics of " + "OpMemoryBarrier")); +} + +TEST_F(ValidateBarriers, OpMemoryBarrierWebGPUUniformFailure) { + const std::string body = R"( +OpMemoryBarrier %workgroup %uniform_image_memory +)"; + + CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("only ImageMemory may be set for Memory Semantics of " + "OpMemoryBarrier")); +} + TEST_F(ValidateBarriers, OpMemoryBarrierFloatMemoryScope) { const std::string body = R"( OpMemoryBarrier %f32_1 %acquire_release_uniform_workgroup @@ -574,9 +793,8 @@ OpMemoryBarrier %f32_1 %acquire_release_uniform_workgroup CompileSuccessfully(GenerateShaderCode(body)); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr("MemoryBarrier: expected Memory Scope to be a 32-bit int")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("MemoryBarrier: expected scope to be a 32-bit int")); } TEST_F(ValidateBarriers, OpMemoryBarrierU64MemoryScope) { @@ -586,9 +804,8 @@ OpMemoryBarrier %u64_1 %acquire_release_uniform_workgroup CompileSuccessfully(GenerateShaderCode(body)); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr("MemoryBarrier: expected Memory Scope to be a 32-bit int")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("MemoryBarrier: expected scope to be a 32-bit int")); } TEST_F(ValidateBarriers, OpMemoryBarrierFloatMemorySemantics) { @@ -739,7 +956,7 @@ TEST_F(ValidateBarriers, OpNamedBarrierInitializeU64SubgroupCount) { TEST_F(ValidateBarriers, OpMemoryNamedBarrierSuccess) { const std::string body = R"( %barrier = OpNamedBarrierInitialize %named_barrier %u32_4 -OpMemoryNamedBarrier %barrier %workgroup %acquire_release_uniform_workgroup +OpMemoryNamedBarrier %barrier %workgroup %acquire_release_workgroup )"; CompileSuccessfully(GenerateKernelCode(body), SPV_ENV_UNIVERSAL_1_1); @@ -748,7 +965,7 @@ OpMemoryNamedBarrier %barrier %workgroup %acquire_release_uniform_workgroup TEST_F(ValidateBarriers, OpMemoryNamedBarrierNotNamedBarrier) { const std::string body = R"( -OpMemoryNamedBarrier %u32_1 %workgroup %acquire_release_uniform_workgroup +OpMemoryNamedBarrier %u32_1 %workgroup %acquire_release_workgroup )"; CompileSuccessfully(GenerateKernelCode(body), SPV_ENV_UNIVERSAL_1_1); @@ -762,7 +979,7 @@ OpMemoryNamedBarrier %u32_1 %workgroup %acquire_release_uniform_workgroup TEST_F(ValidateBarriers, OpMemoryNamedBarrierFloatMemoryScope) { const std::string body = R"( %barrier = OpNamedBarrierInitialize %named_barrier %u32_4 -OpMemoryNamedBarrier %barrier %f32_1 %acquire_release_uniform_workgroup +OpMemoryNamedBarrier %barrier %f32_1 %acquire_release_workgroup )"; CompileSuccessfully(GenerateKernelCode(body), SPV_ENV_UNIVERSAL_1_1); @@ -770,8 +987,7 @@ OpMemoryNamedBarrier %barrier %f32_1 %acquire_release_uniform_workgroup ValidateInstructions(SPV_ENV_UNIVERSAL_1_1)); EXPECT_THAT( getDiagnosticString(), - HasSubstr( - "MemoryNamedBarrier: expected Memory Scope to be a 32-bit int")); + HasSubstr("MemoryNamedBarrier: expected scope to be a 32-bit int")); } TEST_F(ValidateBarriers, OpMemoryNamedBarrierFloatMemorySemantics) { @@ -792,7 +1008,7 @@ OpMemoryNamedBarrier %barrier %workgroup %f32_0 TEST_F(ValidateBarriers, OpMemoryNamedBarrierAcquireAndRelease) { const std::string body = R"( %barrier = OpNamedBarrierInitialize %named_barrier %u32_4 -OpMemoryNamedBarrier %barrier %workgroup %acquire_and_release_uniform +OpMemoryNamedBarrier %barrier %workgroup %acquire_and_release )"; CompileSuccessfully(GenerateKernelCode(body), SPV_ENV_UNIVERSAL_1_1); @@ -809,11 +1025,520 @@ TEST_F(ValidateBarriers, TypeAsMemoryScope) { OpMemoryBarrier %u32 %u32_0 )"; - CompileSuccessfully(GenerateKernelCode(body)); + CompileSuccessfully(GenerateKernelCode(body), SPV_ENV_UNIVERSAL_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_1)); + EXPECT_THAT(getDiagnosticString(), HasSubstr("Operand 5[%uint] cannot be a " + "type")); +} + +TEST_F(ValidateBarriers, + OpControlBarrierVulkanMemoryModelBanSequentiallyConsistent) { + const std::string text = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +OpEntryPoint Fragment %1 "func" +OpExecutionMode %1 OriginUpperLeft +%2 = OpTypeVoid +%3 = OpTypeInt 32 0 +%4 = OpConstant %3 16 +%5 = OpTypeFunction %2 +%6 = OpConstant %3 5 +%1 = OpFunction %2 None %5 +%7 = OpLabel +OpControlBarrier %6 %6 %4 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("SequentiallyConsistent memory semantics cannot be " + "used with the VulkanKHR memory model.")); +} + +TEST_F(ValidateBarriers, + OpMemoryBarrierVulkanMemoryModelBanSequentiallyConsistent) { + const std::string text = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +OpEntryPoint Fragment %1 "func" +OpExecutionMode %1 OriginUpperLeft +%2 = OpTypeVoid +%3 = OpTypeInt 32 0 +%4 = OpConstant %3 16 +%5 = OpTypeFunction %2 +%6 = OpConstant %3 5 +%1 = OpFunction %2 None %5 +%7 = OpLabel +OpMemoryBarrier %6 %4 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("SequentiallyConsistent memory semantics cannot be " + "used with the VulkanKHR memory model.")); +} + +TEST_F(ValidateBarriers, OutputMemoryKHRRequireVulkanMemoryModelKHR) { + const std::string text = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %1 "func" +OpExecutionMode %1 OriginUpperLeft +%2 = OpTypeVoid +%3 = OpTypeInt 32 0 +%semantics = OpConstant %3 4104 +%5 = OpTypeFunction %2 +%device = OpConstant %3 1 +%1 = OpFunction %2 None %5 +%7 = OpLabel +OpControlBarrier %device %device %semantics +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("ControlBarrier: Memory Semantics OutputMemoryKHR " + "requires capability VulkanMemoryModelKHR")); +} + +TEST_F(ValidateBarriers, MakeAvailableKHRRequireVulkanMemoryModelKHR) { + const std::string text = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %1 "func" +OpExecutionMode %1 OriginUpperLeft +%2 = OpTypeVoid +%3 = OpTypeInt 32 0 +%semantics = OpConstant %3 8264 +%5 = OpTypeFunction %2 +%device = OpConstant %3 1 +%1 = OpFunction %2 None %5 +%7 = OpLabel +OpControlBarrier %device %device %semantics +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("ControlBarrier: Memory Semantics MakeAvailableKHR " + "requires capability VulkanMemoryModelKHR")); +} + +TEST_F(ValidateBarriers, MakeVisibleKHRRequireVulkanMemoryModelKHR) { + const std::string text = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %1 "func" +OpExecutionMode %1 OriginUpperLeft +%2 = OpTypeVoid +%3 = OpTypeInt 32 0 +%semantics = OpConstant %3 16456 +%5 = OpTypeFunction %2 +%device = OpConstant %3 1 +%1 = OpFunction %2 None %5 +%7 = OpLabel +OpControlBarrier %device %device %semantics +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("ControlBarrier: Memory Semantics MakeVisibleKHR " + "requires capability VulkanMemoryModelKHR")); +} + +TEST_F(ValidateBarriers, MakeAvailableKHRRequiresReleaseSemantics) { + const std::string text = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%workgroup = OpConstant %int 2 +%semantics = OpConstant %int 8448 +%functy = OpTypeFunction %void +%func = OpFunction %void None %functy +%1 = OpLabel +OpControlBarrier %workgroup %workgroup %semantics +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); EXPECT_THAT( getDiagnosticString(), - HasSubstr("MemoryBarrier: expected Memory Scope to be a 32-bit int")); + HasSubstr("ControlBarrier: MakeAvailableKHR Memory Semantics also " + "requires either Release or AcquireRelease Memory Semantics")); +} + +TEST_F(ValidateBarriers, MakeVisibleKHRRequiresAcquireSemantics) { + const std::string text = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%workgroup = OpConstant %int 2 +%semantics = OpConstant %int 16640 +%functy = OpTypeFunction %void +%func = OpFunction %void None %functy +%1 = OpLabel +OpControlBarrier %workgroup %workgroup %semantics +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("ControlBarrier: MakeVisibleKHR Memory Semantics also requires " + "either Acquire or AcquireRelease Memory Semantics")); +} + +TEST_F(ValidateBarriers, MakeAvailableKHRRequiresStorageSemantics) { + const std::string text = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%workgroup = OpConstant %int 2 +%semantics = OpConstant %int 8196 +%functy = OpTypeFunction %void +%func = OpFunction %void None %functy +%1 = OpLabel +OpMemoryBarrier %workgroup %semantics +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("MemoryBarrier: expected Memory Semantics to include a " + "storage class")); +} + +TEST_F(ValidateBarriers, MakeVisibleKHRRequiresStorageSemantics) { + const std::string text = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%workgroup = OpConstant %int 2 +%semantics = OpConstant %int 16386 +%functy = OpTypeFunction %void +%func = OpFunction %void None %functy +%1 = OpLabel +OpMemoryBarrier %workgroup %semantics +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("MemoryBarrier: expected Memory Semantics to include a " + "storage class")); +} + +TEST_F(ValidateBarriers, SemanticsSpecConstantShader) { + const std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%ptr_int_workgroup = OpTypePointer Workgroup %int +%var = OpVariable %ptr_int_workgroup Workgroup +%voidfn = OpTypeFunction %void +%spec_const = OpSpecConstant %int 0 +%workgroup = OpConstant %int 2 +%func = OpFunction %void None %voidfn +%entry = OpLabel +OpMemoryBarrier %workgroup %spec_const +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Memory Semantics ids must be OpConstant when Shader " + "capability is present")); +} + +TEST_F(ValidateBarriers, SemanticsSpecConstantKernel) { + const std::string spirv = R"( +OpCapability Kernel +OpCapability Linkage +OpMemoryModel Logical OpenCL +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%ptr_int_workgroup = OpTypePointer Workgroup %int +%var = OpVariable %ptr_int_workgroup Workgroup +%voidfn = OpTypeFunction %void +%spec_const = OpSpecConstant %int 0 +%workgroup = OpConstant %int 2 +%func = OpFunction %void None %voidfn +%entry = OpLabel +OpMemoryBarrier %workgroup %spec_const +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateBarriers, ScopeSpecConstantShader) { + const std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%ptr_int_workgroup = OpTypePointer Workgroup %int +%var = OpVariable %ptr_int_workgroup Workgroup +%voidfn = OpTypeFunction %void +%spec_const = OpSpecConstant %int 0 +%relaxed = OpConstant %int 0 +%func = OpFunction %void None %voidfn +%entry = OpLabel +OpMemoryBarrier %spec_const %relaxed +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Scope ids must be OpConstant when Shader " + "capability is present")); +} + +TEST_F(ValidateBarriers, ScopeSpecConstantKernel) { + const std::string spirv = R"( +OpCapability Kernel +OpCapability Linkage +OpMemoryModel Logical OpenCL +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%ptr_int_workgroup = OpTypePointer Workgroup %int +%var = OpVariable %ptr_int_workgroup Workgroup +%voidfn = OpTypeFunction %void +%spec_const = OpSpecConstant %int 0 +%relaxed = OpConstant %int 0 +%func = OpFunction %void None %voidfn +%entry = OpLabel +OpMemoryBarrier %spec_const %relaxed +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateBarriers, VulkanMemoryModelDeviceScopeBad) { + const std::string text = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%device = OpConstant %int 1 +%semantics = OpConstant %int 0 +%functy = OpTypeFunction %void +%func = OpFunction %void None %functy +%1 = OpLabel +OpMemoryBarrier %device %semantics +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Use of device scope with VulkanKHR memory model requires the " + "VulkanMemoryModelDeviceScopeKHR capability")); +} + +TEST_F(ValidateBarriers, VulkanMemoryModelDeviceScopeGood) { + const std::string text = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpCapability VulkanMemoryModelDeviceScopeKHR +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%device = OpConstant %int 1 +%semantics = OpConstant %int 0 +%functy = OpTypeFunction %void +%func = OpFunction %void None %functy +%1 = OpLabel +OpMemoryBarrier %device %semantics +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); +} + +TEST_F(ValidateBarriers, VolatileMemoryBarrier) { + const std::string text = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpCapability VulkanMemoryModelDeviceScopeKHR +OpCapability Linkage +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%device = OpConstant %int 1 +%semantics = OpConstant %int 32768 +%functy = OpTypeFunction %void +%func = OpFunction %void None %functy +%1 = OpLabel +OpMemoryBarrier %device %semantics +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Memory Semantics Volatile can only be used with " + "atomic instructions")); +} + +TEST_F(ValidateBarriers, VolatileControlBarrier) { + const std::string text = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpCapability VulkanMemoryModelDeviceScopeKHR +OpCapability Linkage +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%device = OpConstant %int 1 +%semantics = OpConstant %int 32768 +%functy = OpTypeFunction %void +%func = OpFunction %void None %functy +%1 = OpLabel +OpControlBarrier %device %device %semantics +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Memory Semantics Volatile can only be used with " + "atomic instructions")); +} + +TEST_F(ValidateBarriers, CooperativeMatrixSpecConstantVolatile) { + const std::string text = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpCapability VulkanMemoryModelDeviceScopeKHR +OpCapability CooperativeMatrixNV +OpCapability Linkage +OpExtension "SPV_KHR_vulkan_memory_model" +OpExtension "SPV_NV_cooperative_matrix" +OpMemoryModel Logical VulkanKHR +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%device = OpConstant %int 1 +%semantics = OpSpecConstant %int 32768 +%functy = OpTypeFunction %void +%func = OpFunction %void None %functy +%1 = OpLabel +OpControlBarrier %device %device %semantics +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateBarriers, CooperativeMatrixNonConstantSemantics) { + const std::string text = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpCapability VulkanMemoryModelDeviceScopeKHR +OpCapability CooperativeMatrixNV +OpCapability Linkage +OpExtension "SPV_KHR_vulkan_memory_model" +OpExtension "SPV_NV_cooperative_matrix" +OpMemoryModel Logical VulkanKHR +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%device = OpConstant %int 1 +%semantics = OpUndef %int +%functy = OpTypeFunction %void +%func = OpFunction %void None %functy +%1 = OpLabel +OpControlBarrier %device %device %semantics +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Memory Semantics must be a constant instruction when " + "CooperativeMatrixNV capability is present")); } } // namespace diff --git a/third_party/spirv-tools/test/val/val_bitwise_test.cpp b/third_party/spirv-tools/test/val/val_bitwise_test.cpp index 18ccd4f8e1..1001def8f7 100644 --- a/third_party/spirv-tools/test/val/val_bitwise_test.cpp +++ b/third_party/spirv-tools/test/val/val_bitwise_test.cpp @@ -42,6 +42,7 @@ OpCapability Float64)"; R"( OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft %void = OpTypeVoid %func = OpTypeFunction %void %bool = OpTypeBool diff --git a/third_party/spirv-tools/test/val/val_builtins_test.cpp b/third_party/spirv-tools/test/val/val_builtins_test.cpp index 0c8909cec1..58593dcf9b 100644 --- a/third_party/spirv-tools/test/val/val_builtins_test.cpp +++ b/third_party/spirv-tools/test/val/val_builtins_test.cpp @@ -24,7 +24,9 @@ #include #include "gmock/gmock.h" +#include "source/spirv_target_env.h" #include "test/unit_spirv.h" +#include "test/val/val_code_generator.h" #include "test/val/val_fixtures.h" namespace spvtools { @@ -50,162 +52,102 @@ using ::testing::Values; using ::testing::ValuesIn; using ValidateBuiltIns = spvtest::ValidateBase; +using ValidateVulkanSubgroupBuiltIns = spvtest::ValidateBase< + std::tuple>; using ValidateVulkanCombineBuiltInExecutionModelDataTypeResult = spvtest::ValidateBase>; +using ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult = + spvtest::ValidateBase>; using ValidateVulkanCombineBuiltInArrayedVariable = spvtest::ValidateBase< std::tuple>; +using ValidateWebGPUCombineBuiltInArrayedVariable = spvtest::ValidateBase< + std::tuple>; +using ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult = + spvtest::ValidateBase< + std::tuple>; -struct EntryPoint { - std::string name; - std::string execution_model; - std::string execution_modes; - std::string body; - std::string interfaces; -}; - -class CodeGenerator { - public: - std::string Build() const; - - std::vector entry_points_; - std::string capabilities_; - std::string extensions_; - std::string memory_model_; - std::string before_types_; - std::string types_; - std::string after_types_; - std::string add_at_the_end_; -}; - -std::string CodeGenerator::Build() const { - std::ostringstream ss; - - ss << capabilities_; - ss << extensions_; - ss << memory_model_; - - for (const EntryPoint& entry_point : entry_points_) { - ss << "OpEntryPoint " << entry_point.execution_model << " %" - << entry_point.name << " \"" << entry_point.name << "\" " - << entry_point.interfaces << "\n"; - } - - for (const EntryPoint& entry_point : entry_points_) { - ss << entry_point.execution_modes << "\n"; - } - - ss << before_types_; - ss << types_; - ss << after_types_; - - for (const EntryPoint& entry_point : entry_points_) { - ss << "\n"; - ss << "%" << entry_point.name << " = OpFunction %void None %func\n"; - ss << "%" << entry_point.name << "_entry = OpLabel\n"; - ss << entry_point.body; - ss << "\nOpReturn\nOpFunctionEnd\n"; - } - - ss << add_at_the_end_; - - return ss.str(); +bool InitializerRequired(spv_target_env env, const char* const storage_class) { + return spvIsWebGPUEnv(env) && (strncmp(storage_class, "Output", 6) == 0 || + strncmp(storage_class, "Private", 7) == 0 || + strncmp(storage_class, "Function", 8) == 0); } -std::string GetDefaultShaderCapabilities() { - return R"( -OpCapability Shader -OpCapability Geometry -OpCapability Tessellation -OpCapability Float64 -OpCapability Int64 -OpCapability MultiViewport -OpCapability SampleRateShading +CodeGenerator GetInMainCodeGenerator(spv_target_env env, + const char* const built_in, + const char* const execution_model, + const char* const storage_class, + const char* const capabilities, + const char* const extensions, + const char* const data_type) { + CodeGenerator generator = + spvIsWebGPUEnv(env) ? CodeGenerator::GetWebGPUShaderCodeGenerator() + : CodeGenerator::GetDefaultShaderCodeGenerator(); + + if (capabilities) { + generator.capabilities_ += capabilities; + } + if (extensions) { + generator.extensions_ += extensions; + } + + generator.before_types_ = "OpMemberDecorate %built_in_type 0 BuiltIn "; + generator.before_types_ += built_in; + generator.before_types_ += "\n"; + + std::ostringstream after_types; + + after_types << "%built_in_type = OpTypeStruct " << data_type << "\n"; + if (InitializerRequired(env, storage_class)) { + after_types << "%built_in_null = OpConstantNull %built_in_type\n"; + } + after_types << "%built_in_ptr = OpTypePointer " << storage_class + << " %built_in_type\n"; + after_types << "%built_in_var = OpVariable %built_in_ptr " << storage_class; + if (InitializerRequired(env, storage_class)) { + after_types << " %built_in_null"; + } + after_types << "\n"; + after_types << "%data_ptr = OpTypePointer " << storage_class << " " + << data_type << "\n"; + generator.after_types_ = after_types.str(); + + EntryPoint entry_point; + entry_point.name = "main"; + entry_point.execution_model = execution_model; + if (strncmp(storage_class, "Input", 5) == 0 || + strncmp(storage_class, "Output", 6) == 0) { + entry_point.interfaces = "%built_in_var"; + } + + std::ostringstream execution_modes; + if (0 == std::strcmp(execution_model, "Fragment")) { + execution_modes << "OpExecutionMode %" << entry_point.name + << " OriginUpperLeft\n"; + if (0 == std::strcmp(built_in, "FragDepth")) { + execution_modes << "OpExecutionMode %" << entry_point.name + << " DepthReplacing\n"; + } + } + if (0 == std::strcmp(execution_model, "Geometry")) { + execution_modes << "OpExecutionMode %" << entry_point.name + << " InputPoints\n"; + execution_modes << "OpExecutionMode %" << entry_point.name + << " OutputPoints\n"; + } + if (0 == std::strcmp(execution_model, "GLCompute")) { + execution_modes << "OpExecutionMode %" << entry_point.name + << " LocalSize 1 1 1\n"; + } + entry_point.execution_modes = execution_modes.str(); + + entry_point.body = R"( +%ptr = OpAccessChain %data_ptr %built_in_var %u32_0 )"; -} + generator.entry_points_.push_back(std::move(entry_point)); -std::string GetDefaultShaderTypes() { - return R"( -%void = OpTypeVoid -%func = OpTypeFunction %void -%bool = OpTypeBool -%f32 = OpTypeFloat 32 -%f64 = OpTypeFloat 64 -%u32 = OpTypeInt 32 0 -%u64 = OpTypeInt 64 0 -%f32vec2 = OpTypeVector %f32 2 -%f32vec3 = OpTypeVector %f32 3 -%f32vec4 = OpTypeVector %f32 4 -%f64vec2 = OpTypeVector %f64 2 -%f64vec3 = OpTypeVector %f64 3 -%f64vec4 = OpTypeVector %f64 4 -%u32vec2 = OpTypeVector %u32 2 -%u32vec3 = OpTypeVector %u32 3 -%u64vec3 = OpTypeVector %u64 3 -%u32vec4 = OpTypeVector %u32 4 -%u64vec2 = OpTypeVector %u64 2 - -%f32_0 = OpConstant %f32 0 -%f32_1 = OpConstant %f32 1 -%f32_2 = OpConstant %f32 2 -%f32_3 = OpConstant %f32 3 -%f32_4 = OpConstant %f32 4 -%f32_h = OpConstant %f32 0.5 -%f32vec2_01 = OpConstantComposite %f32vec2 %f32_0 %f32_1 -%f32vec2_12 = OpConstantComposite %f32vec2 %f32_1 %f32_2 -%f32vec3_012 = OpConstantComposite %f32vec3 %f32_0 %f32_1 %f32_2 -%f32vec3_123 = OpConstantComposite %f32vec3 %f32_1 %f32_2 %f32_3 -%f32vec4_0123 = OpConstantComposite %f32vec4 %f32_0 %f32_1 %f32_2 %f32_3 -%f32vec4_1234 = OpConstantComposite %f32vec4 %f32_1 %f32_2 %f32_3 %f32_4 - -%f64_0 = OpConstant %f64 0 -%f64_1 = OpConstant %f64 1 -%f64_2 = OpConstant %f64 2 -%f64_3 = OpConstant %f64 3 -%f64vec2_01 = OpConstantComposite %f64vec2 %f64_0 %f64_1 -%f64vec3_012 = OpConstantComposite %f64vec3 %f64_0 %f64_1 %f64_2 -%f64vec4_0123 = OpConstantComposite %f64vec4 %f64_0 %f64_1 %f64_2 %f64_3 - -%u32_0 = OpConstant %u32 0 -%u32_1 = OpConstant %u32 1 -%u32_2 = OpConstant %u32 2 -%u32_3 = OpConstant %u32 3 -%u32_4 = OpConstant %u32 4 - -%u64_0 = OpConstant %u64 0 -%u64_1 = OpConstant %u64 1 -%u64_2 = OpConstant %u64 2 -%u64_3 = OpConstant %u64 3 - -%u32vec2_01 = OpConstantComposite %u32vec2 %u32_0 %u32_1 -%u32vec2_12 = OpConstantComposite %u32vec2 %u32_1 %u32_2 -%u32vec4_0123 = OpConstantComposite %u32vec4 %u32_0 %u32_1 %u32_2 %u32_3 -%u64vec2_01 = OpConstantComposite %u64vec2 %u64_0 %u64_1 - -%u32arr2 = OpTypeArray %u32 %u32_2 -%u32arr3 = OpTypeArray %u32 %u32_3 -%u32arr4 = OpTypeArray %u32 %u32_4 -%u64arr2 = OpTypeArray %u64 %u32_2 -%u64arr3 = OpTypeArray %u64 %u32_3 -%u64arr4 = OpTypeArray %u64 %u32_4 -%f32arr2 = OpTypeArray %f32 %u32_2 -%f32arr3 = OpTypeArray %f32 %u32_3 -%f32arr4 = OpTypeArray %f32 %u32_4 -%f64arr2 = OpTypeArray %f64 %u32_2 -%f64arr3 = OpTypeArray %f64 %u32_3 -%f64arr4 = OpTypeArray %f64 %u32_4 - -%f32vec3arr3 = OpTypeArray %f32vec3 %u32_3 -%f32vec4arr3 = OpTypeArray %f32vec4 %u32_3 -%f64vec4arr3 = OpTypeArray %f64vec4 %u32_3 -)"; -} - -CodeGenerator GetDefaultShaderCodeGenerator() { - CodeGenerator generator; - generator.capabilities_ = GetDefaultShaderCapabilities(); - generator.memory_model_ = "OpMemoryModel Logical GLSL450\n"; - generator.types_ = GetDefaultShaderTypes(); return generator; } @@ -216,17 +158,103 @@ TEST_P(ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, InMain) { const char* const data_type = std::get<3>(GetParam()); const TestResult& test_result = std::get<4>(GetParam()); - CodeGenerator generator = GetDefaultShaderCodeGenerator(); + CodeGenerator generator = + GetInMainCodeGenerator(SPV_ENV_VULKAN_1_0, built_in, execution_model, + storage_class, NULL, NULL, data_type); + + CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0); + ASSERT_EQ(test_result.validation_result, + ValidateInstructions(SPV_ENV_VULKAN_1_0)); + if (test_result.error_str) { + EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str)); + } + if (test_result.error_str2) { + EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str2)); + } +} + +TEST_P(ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, InMain) { + const char* const built_in = std::get<0>(GetParam()); + const char* const execution_model = std::get<1>(GetParam()); + const char* const storage_class = std::get<2>(GetParam()); + const char* const data_type = std::get<3>(GetParam()); + const TestResult& test_result = std::get<4>(GetParam()); + + CodeGenerator generator = + GetInMainCodeGenerator(SPV_ENV_WEBGPU_0, built_in, execution_model, + storage_class, NULL, NULL, data_type); + + CompileSuccessfully(generator.Build(), SPV_ENV_WEBGPU_0); + ASSERT_EQ(test_result.validation_result, + ValidateInstructions(SPV_ENV_WEBGPU_0)); + if (test_result.error_str) { + EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str)); + } + if (test_result.error_str2) { + EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str2)); + } +} + +TEST_P( + ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult, + InMain) { + const char* const built_in = std::get<0>(GetParam()); + const char* const execution_model = std::get<1>(GetParam()); + const char* const storage_class = std::get<2>(GetParam()); + const char* const data_type = std::get<3>(GetParam()); + const char* const capabilities = std::get<4>(GetParam()); + const char* const extensions = std::get<5>(GetParam()); + const TestResult& test_result = std::get<6>(GetParam()); + + CodeGenerator generator = GetInMainCodeGenerator( + SPV_ENV_VULKAN_1_0, built_in, execution_model, storage_class, + capabilities, extensions, data_type); + + CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0); + ASSERT_EQ(test_result.validation_result, + ValidateInstructions(SPV_ENV_VULKAN_1_0)); + if (test_result.error_str) { + EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str)); + } + if (test_result.error_str2) { + EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str2)); + } +} + +CodeGenerator GetInFunctionCodeGenerator(spv_target_env env, + const char* const built_in, + const char* const execution_model, + const char* const storage_class, + const char* const capabilities, + const char* const extensions, + const char* const data_type) { + CodeGenerator generator = + spvIsWebGPUEnv(env) ? CodeGenerator::GetWebGPUShaderCodeGenerator() + : CodeGenerator::GetDefaultShaderCodeGenerator(); + + if (capabilities) { + generator.capabilities_ += capabilities; + } + if (extensions) { + generator.extensions_ += extensions; + } + generator.before_types_ = "OpMemberDecorate %built_in_type 0 BuiltIn "; generator.before_types_ += built_in; generator.before_types_ += "\n"; std::ostringstream after_types; after_types << "%built_in_type = OpTypeStruct " << data_type << "\n"; + if (InitializerRequired(env, storage_class)) { + after_types << "%built_in_null = OpConstantNull %built_in_type\n"; + } after_types << "%built_in_ptr = OpTypePointer " << storage_class << " %built_in_type\n"; - after_types << "%built_in_var = OpVariable %built_in_ptr " << storage_class - << "\n"; + after_types << "%built_in_var = OpVariable %built_in_ptr " << storage_class; + if (InitializerRequired(env, storage_class)) { + after_types << " %built_in_null"; + } + after_types << "\n"; after_types << "%data_ptr = OpTypePointer " << storage_class << " " << data_type << "\n"; generator.after_types_ = after_types.str(); @@ -243,27 +271,44 @@ TEST_P(ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, InMain) { if (0 == std::strcmp(execution_model, "Fragment")) { execution_modes << "OpExecutionMode %" << entry_point.name << " OriginUpperLeft\n"; + if (0 == std::strcmp(built_in, "FragDepth")) { + execution_modes << "OpExecutionMode %" << entry_point.name + << " DepthReplacing\n"; + } } - if (0 == std::strcmp(built_in, "FragDepth")) { + if (0 == std::strcmp(execution_model, "Geometry")) { execution_modes << "OpExecutionMode %" << entry_point.name - << " DepthReplacing\n"; + << " InputPoints\n"; + execution_modes << "OpExecutionMode %" << entry_point.name + << " OutputPoints\n"; + } + if (0 == std::strcmp(execution_model, "GLCompute")) { + execution_modes << "OpExecutionMode %" << entry_point.name + << " LocalSize 1 1 1\n"; } entry_point.execution_modes = execution_modes.str(); entry_point.body = R"( -%ptr = OpAccessChain %data_ptr %built_in_var %u32_0 +%val2 = OpFunctionCall %void %foo )"; + + std::string function_body = R"( +%foo = OpFunction %void None %func +%foo_entry = OpLabel +%ptr = OpAccessChain %data_ptr %built_in_var %u32_0 +OpReturn +OpFunctionEnd +)"; + + if (spvIsWebGPUEnv(env)) { + generator.after_types_ += function_body; + } else { + generator.add_at_the_end_ = function_body; + } + generator.entry_points_.push_back(std::move(entry_point)); - CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0); - ASSERT_EQ(test_result.validation_result, - ValidateInstructions(SPV_ENV_VULKAN_1_0)); - if (test_result.error_str) { - EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str)); - } - if (test_result.error_str2) { - EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str2)); - } + return generator; } TEST_P(ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, InFunction) { @@ -273,52 +318,9 @@ TEST_P(ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, InFunction) { const char* const data_type = std::get<3>(GetParam()); const TestResult& test_result = std::get<4>(GetParam()); - CodeGenerator generator = GetDefaultShaderCodeGenerator(); - generator.before_types_ = "OpMemberDecorate %built_in_type 0 BuiltIn "; - generator.before_types_ += built_in; - generator.before_types_ += "\n"; - - std::ostringstream after_types; - after_types << "%built_in_type = OpTypeStruct " << data_type << "\n"; - after_types << "%built_in_ptr = OpTypePointer " << storage_class - << " %built_in_type\n"; - after_types << "%built_in_var = OpVariable %built_in_ptr " << storage_class - << "\n"; - after_types << "%data_ptr = OpTypePointer " << storage_class << " " - << data_type << "\n"; - generator.after_types_ = after_types.str(); - - EntryPoint entry_point; - entry_point.name = "main"; - entry_point.execution_model = execution_model; - if (strncmp(storage_class, "Input", 5) == 0 || - strncmp(storage_class, "Output", 6) == 0) { - entry_point.interfaces = "%built_in_var"; - } - - std::ostringstream execution_modes; - if (0 == std::strcmp(execution_model, "Fragment")) { - execution_modes << "OpExecutionMode %" << entry_point.name - << " OriginUpperLeft\n"; - } - if (0 == std::strcmp(built_in, "FragDepth")) { - execution_modes << "OpExecutionMode %" << entry_point.name - << " DepthReplacing\n"; - } - entry_point.execution_modes = execution_modes.str(); - - entry_point.body = R"( -%val2 = OpFunctionCall %void %foo -)"; - - generator.add_at_the_end_ = R"( -%foo = OpFunction %void None %func -%foo_entry = OpLabel -%ptr = OpAccessChain %data_ptr %built_in_var %u32_0 -OpReturn -OpFunctionEnd -)"; - generator.entry_points_.push_back(std::move(entry_point)); + CodeGenerator generator = + GetInFunctionCodeGenerator(SPV_ENV_VULKAN_1_0, built_in, execution_model, + storage_class, NULL, NULL, data_type); CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0); ASSERT_EQ(test_result.validation_result, @@ -331,6 +333,127 @@ OpFunctionEnd } } +TEST_P(ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, InFunction) { + const char* const built_in = std::get<0>(GetParam()); + const char* const execution_model = std::get<1>(GetParam()); + const char* const storage_class = std::get<2>(GetParam()); + const char* const data_type = std::get<3>(GetParam()); + const TestResult& test_result = std::get<4>(GetParam()); + + CodeGenerator generator = + GetInFunctionCodeGenerator(SPV_ENV_WEBGPU_0, built_in, execution_model, + storage_class, NULL, NULL, data_type); + + CompileSuccessfully(generator.Build(), SPV_ENV_WEBGPU_0); + ASSERT_EQ(test_result.validation_result, + ValidateInstructions(SPV_ENV_WEBGPU_0)); + if (test_result.error_str) { + EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str)); + } + if (test_result.error_str2) { + EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str2)); + } +} + +TEST_P( + ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult, + InFunction) { + const char* const built_in = std::get<0>(GetParam()); + const char* const execution_model = std::get<1>(GetParam()); + const char* const storage_class = std::get<2>(GetParam()); + const char* const data_type = std::get<3>(GetParam()); + const char* const capabilities = std::get<4>(GetParam()); + const char* const extensions = std::get<5>(GetParam()); + const TestResult& test_result = std::get<6>(GetParam()); + + CodeGenerator generator = GetInFunctionCodeGenerator( + SPV_ENV_VULKAN_1_0, built_in, execution_model, storage_class, + capabilities, extensions, data_type); + + CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0); + ASSERT_EQ(test_result.validation_result, + ValidateInstructions(SPV_ENV_VULKAN_1_0)); + if (test_result.error_str) { + EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str)); + } + if (test_result.error_str2) { + EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str2)); + } +} + +CodeGenerator GetVariableCodeGenerator(spv_target_env env, + const char* const built_in, + const char* const execution_model, + const char* const storage_class, + const char* const capabilities, + const char* const extensions, + const char* const data_type) { + CodeGenerator generator = + spvIsWebGPUEnv(env) ? CodeGenerator::GetWebGPUShaderCodeGenerator() + : CodeGenerator::GetDefaultShaderCodeGenerator(); + + if (capabilities) { + generator.capabilities_ += capabilities; + } + if (extensions) { + generator.extensions_ += extensions; + } + + generator.before_types_ = "OpDecorate %built_in_var BuiltIn "; + generator.before_types_ += built_in; + generator.before_types_ += "\n"; + + std::ostringstream after_types; + if (InitializerRequired(env, storage_class)) { + after_types << "%built_in_null = OpConstantNull " << data_type << "\n"; + } + after_types << "%built_in_ptr = OpTypePointer " << storage_class << " " + << data_type << "\n"; + after_types << "%built_in_var = OpVariable %built_in_ptr " << storage_class; + if (InitializerRequired(env, storage_class)) { + after_types << " %built_in_null"; + } + after_types << "\n"; + generator.after_types_ = after_types.str(); + + EntryPoint entry_point; + entry_point.name = "main"; + entry_point.execution_model = execution_model; + if (strncmp(storage_class, "Input", 5) == 0 || + strncmp(storage_class, "Output", 6) == 0) { + entry_point.interfaces = "%built_in_var"; + } + // Any kind of reference would do. + entry_point.body = R"( +%val = OpBitcast %u32 %built_in_var +)"; + + std::ostringstream execution_modes; + if (0 == std::strcmp(execution_model, "Fragment")) { + execution_modes << "OpExecutionMode %" << entry_point.name + << " OriginUpperLeft\n"; + if (0 == std::strcmp(built_in, "FragDepth")) { + execution_modes << "OpExecutionMode %" << entry_point.name + << " DepthReplacing\n"; + } + } + if (0 == std::strcmp(execution_model, "Geometry")) { + execution_modes << "OpExecutionMode %" << entry_point.name + << " InputPoints\n"; + execution_modes << "OpExecutionMode %" << entry_point.name + << " OutputPoints\n"; + } + if (0 == std::strcmp(execution_model, "GLCompute")) { + execution_modes << "OpExecutionMode %" << entry_point.name + << " LocalSize 1 1 1\n"; + } + entry_point.execution_modes = execution_modes.str(); + + generator.entry_points_.push_back(std::move(entry_point)); + + return generator; +} + TEST_P(ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Variable) { const char* const built_in = std::get<0>(GetParam()); const char* const execution_model = std::get<1>(GetParam()); @@ -338,42 +461,9 @@ TEST_P(ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Variable) { const char* const data_type = std::get<3>(GetParam()); const TestResult& test_result = std::get<4>(GetParam()); - CodeGenerator generator = GetDefaultShaderCodeGenerator(); - generator.before_types_ = "OpDecorate %built_in_var BuiltIn "; - generator.before_types_ += built_in; - generator.before_types_ += "\n"; - - std::ostringstream after_types; - after_types << "%built_in_ptr = OpTypePointer " << storage_class << " " - << data_type << "\n"; - after_types << "%built_in_var = OpVariable %built_in_ptr " << storage_class - << "\n"; - generator.after_types_ = after_types.str(); - - EntryPoint entry_point; - entry_point.name = "main"; - entry_point.execution_model = execution_model; - if (strncmp(storage_class, "Input", 5) == 0 || - strncmp(storage_class, "Output", 6) == 0) { - entry_point.interfaces = "%built_in_var"; - } - // Any kind of reference would do. - entry_point.body = R"( -%val = OpBitcast %u64 %built_in_var -)"; - - std::ostringstream execution_modes; - if (0 == std::strcmp(execution_model, "Fragment")) { - execution_modes << "OpExecutionMode %" << entry_point.name - << " OriginUpperLeft\n"; - } - if (0 == std::strcmp(built_in, "FragDepth")) { - execution_modes << "OpExecutionMode %" << entry_point.name - << " DepthReplacing\n"; - } - entry_point.execution_modes = execution_modes.str(); - - generator.entry_points_.push_back(std::move(entry_point)); + CodeGenerator generator = + GetVariableCodeGenerator(SPV_ENV_VULKAN_1_0, built_in, execution_model, + storage_class, NULL, NULL, data_type); CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0); ASSERT_EQ(test_result.validation_result, @@ -386,25 +476,73 @@ TEST_P(ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Variable) { } } -INSTANTIATE_TEST_CASE_P( +TEST_P(ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, Variable) { + const char* const built_in = std::get<0>(GetParam()); + const char* const execution_model = std::get<1>(GetParam()); + const char* const storage_class = std::get<2>(GetParam()); + const char* const data_type = std::get<3>(GetParam()); + const TestResult& test_result = std::get<4>(GetParam()); + + CodeGenerator generator = + GetVariableCodeGenerator(SPV_ENV_WEBGPU_0, built_in, execution_model, + storage_class, NULL, NULL, data_type); + + CompileSuccessfully(generator.Build(), SPV_ENV_WEBGPU_0); + ASSERT_EQ(test_result.validation_result, + ValidateInstructions(SPV_ENV_WEBGPU_0)); + if (test_result.error_str) { + EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str)); + } + if (test_result.error_str2) { + EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str2)); + } +} + +TEST_P( + ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult, + Variable) { + const char* const built_in = std::get<0>(GetParam()); + const char* const execution_model = std::get<1>(GetParam()); + const char* const storage_class = std::get<2>(GetParam()); + const char* const data_type = std::get<3>(GetParam()); + const char* const capabilities = std::get<4>(GetParam()); + const char* const extensions = std::get<5>(GetParam()); + const TestResult& test_result = std::get<6>(GetParam()); + + CodeGenerator generator = GetVariableCodeGenerator( + SPV_ENV_VULKAN_1_0, built_in, execution_model, storage_class, + capabilities, extensions, data_type); + + CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0); + ASSERT_EQ(test_result.validation_result, + ValidateInstructions(SPV_ENV_VULKAN_1_0)); + if (test_result.error_str) { + EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str)); + } + if (test_result.error_str2) { + EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str2)); + } +} + +INSTANTIATE_TEST_SUITE_P( ClipAndCullDistanceOutputSuccess, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("ClipDistance", "CullDistance"), Values("Vertex", "Geometry", "TessellationControl", "TessellationEvaluation"), Values("Output"), Values("%f32arr2", "%f32arr4"), - Values(TestResult())), ); + Values(TestResult()))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( ClipAndCullDistanceInputSuccess, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("ClipDistance", "CullDistance"), Values("Fragment", "Geometry", "TessellationControl", "TessellationEvaluation"), Values("Input"), Values("%f32arr2", "%f32arr4"), - Values(TestResult())), ); + Values(TestResult()))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( ClipAndCullDistanceFragmentOutput, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("ClipDistance", "CullDistance"), Values("Fragment"), @@ -414,9 +552,19 @@ INSTANTIATE_TEST_CASE_P( "Vulkan spec doesn't allow BuiltIn ClipDistance/CullDistance " "to be used for variables with Output storage class if " "execution model is Fragment.", - "which is called with execution model Fragment."))), ); + "which is called with execution model Fragment.")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( + VertexIdAndInstanceIdVertexInput, + ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, + Combine(Values("VertexId", "InstanceId"), Values("Vertex"), Values("Input"), + Values("%u32"), + Values(TestResult( + SPV_ERROR_INVALID_DATA, + "Vulkan spec doesn't allow BuiltIn VertexId/InstanceId to be " + "used.")))); + +INSTANTIATE_TEST_SUITE_P( ClipAndCullDistanceVertexInput, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("ClipDistance", "CullDistance"), Values("Vertex"), @@ -426,9 +574,9 @@ INSTANTIATE_TEST_CASE_P( "Vulkan spec doesn't allow BuiltIn ClipDistance/CullDistance " "to be used for variables with Input storage class if " "execution model is Vertex.", - "which is called with execution model Vertex."))), ); + "which is called with execution model Vertex.")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( ClipAndCullInvalidExecutionModel, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("ClipDistance", "CullDistance"), Values("GLCompute"), @@ -436,41 +584,46 @@ INSTANTIATE_TEST_CASE_P( Values(TestResult( SPV_ERROR_INVALID_DATA, "to be used only with Fragment, Vertex, TessellationControl, " - "TessellationEvaluation or Geometry execution models"))), ); + "TessellationEvaluation or Geometry execution models")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( ClipAndCullDistanceNotArray, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("ClipDistance", "CullDistance"), Values("Fragment"), Values("Input"), Values("%f32vec2", "%f32vec4", "%f32"), Values(TestResult(SPV_ERROR_INVALID_DATA, "needs to be a 32-bit float array", - "is not an array"))), ); + "is not an array")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( ClipAndCullDistanceNotFloatArray, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("ClipDistance", "CullDistance"), Values("Fragment"), Values("Input"), Values("%u32arr2", "%u64arr4"), Values(TestResult(SPV_ERROR_INVALID_DATA, "needs to be a 32-bit float array", - "components are not float scalar"))), ); + "components are not float scalar")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( ClipAndCullDistanceNotF32Array, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("ClipDistance", "CullDistance"), Values("Fragment"), Values("Input"), Values("%f64arr2", "%f64arr4"), Values(TestResult(SPV_ERROR_INVALID_DATA, "needs to be a 32-bit float array", - "has components with bit width 64"))), ); + "has components with bit width 64")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( FragCoordSuccess, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("FragCoord"), Values("Fragment"), Values("Input"), - Values("%f32vec4"), Values(TestResult())), ); + Values("%f32vec4"), Values(TestResult()))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( + FragCoordSuccess, ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, + Combine(Values("FragCoord"), Values("Fragment"), Values("Input"), + Values("%f32vec4"), Values(TestResult()))); + +INSTANTIATE_TEST_SUITE_P( FragCoordNotFragment, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine( @@ -479,50 +632,91 @@ INSTANTIATE_TEST_CASE_P( "TessellationEvaluation"), Values("Input"), Values("%f32vec4"), Values(TestResult(SPV_ERROR_INVALID_DATA, - "to be used only with Fragment execution model"))), ); + "to be used only with Fragment execution model")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( + FragCoordNotFragment, + ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, + Combine( + Values("FragCoord"), Values("Vertex", "GLCompute"), Values("Input"), + Values("%f32vec4"), + Values(TestResult(SPV_ERROR_INVALID_DATA, + "to be used only with Fragment execution model")))); + +INSTANTIATE_TEST_SUITE_P( FragCoordNotInput, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("FragCoord"), Values("Fragment"), Values("Output"), Values("%f32vec4"), Values(TestResult( SPV_ERROR_INVALID_DATA, "to be only used for variables with Input storage class", - "uses storage class Output"))), ); + "uses storage class Output")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( + FragCoordNotInput, ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, + Combine(Values("FragCoord"), Values("Fragment"), Values("Output"), + Values("%f32vec4"), + Values(TestResult( + SPV_ERROR_INVALID_DATA, + "to be only used for variables with Input storage class", + "uses storage class Output")))); + +INSTANTIATE_TEST_SUITE_P( FragCoordNotFloatVector, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("FragCoord"), Values("Fragment"), Values("Input"), Values("%f32arr4", "%u32vec4"), Values(TestResult(SPV_ERROR_INVALID_DATA, "needs to be a 4-component 32-bit float vector", - "is not a float vector"))), ); + "is not a float vector")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( + FragCoordNotFloatVector, + ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, + Combine(Values("FragCoord"), Values("Fragment"), Values("Input"), + Values("%f32arr4", "%u32vec4"), + Values(TestResult(SPV_ERROR_INVALID_DATA, + "needs to be a 4-component 32-bit float vector", + "is not a float vector")))); + +INSTANTIATE_TEST_SUITE_P( FragCoordNotFloatVec4, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("FragCoord"), Values("Fragment"), Values("Input"), Values("%f32vec3"), Values(TestResult(SPV_ERROR_INVALID_DATA, "needs to be a 4-component 32-bit float vector", - "has 3 components"))), ); + "has 3 components")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( + FragCoordNotFloatVec4, + ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, + Combine(Values("FragCoord"), Values("Fragment"), Values("Input"), + Values("%f32vec3"), + Values(TestResult(SPV_ERROR_INVALID_DATA, + "needs to be a 4-component 32-bit float vector", + "has 3 components")))); + +INSTANTIATE_TEST_SUITE_P( FragCoordNotF32Vec4, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("FragCoord"), Values("Fragment"), Values("Input"), Values("%f64vec4"), Values(TestResult(SPV_ERROR_INVALID_DATA, "needs to be a 4-component 32-bit float vector", - "has components with bit width 64"))), ); + "has components with bit width 64")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( FragDepthSuccess, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("FragDepth"), Values("Fragment"), Values("Output"), - Values("%f32"), Values(TestResult())), ); + Values("%f32"), Values(TestResult()))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( + FragDepthSuccess, ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, + Combine(Values("FragDepth"), Values("Fragment"), Values("Output"), + Values("%f32"), Values(TestResult()))); + +INSTANTIATE_TEST_SUITE_P( FragDepthNotFragment, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine( @@ -531,9 +725,18 @@ INSTANTIATE_TEST_CASE_P( "TessellationEvaluation"), Values("Output"), Values("%f32"), Values(TestResult(SPV_ERROR_INVALID_DATA, - "to be used only with Fragment execution model"))), ); + "to be used only with Fragment execution model")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( + FragDepthNotFragment, + ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, + Combine( + Values("FragDepth"), Values("Vertex", "GLCompute"), Values("Output"), + Values("%f32"), + Values(TestResult(SPV_ERROR_INVALID_DATA, + "to be used only with Fragment execution model")))); + +INSTANTIATE_TEST_SUITE_P( FragDepthNotOutput, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("FragDepth"), Values("Fragment"), Values("Input"), @@ -541,32 +744,57 @@ INSTANTIATE_TEST_CASE_P( Values(TestResult( SPV_ERROR_INVALID_DATA, "to be only used for variables with Output storage class", - "uses storage class Input"))), ); + "uses storage class Input")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( + FragDepthNotOutput, + ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, + Combine(Values("FragDepth"), Values("Fragment"), Values("Input"), + Values("%f32"), + Values(TestResult( + SPV_ERROR_INVALID_DATA, + "to be only used for variables with Output storage class", + "uses storage class Input")))); + +INSTANTIATE_TEST_SUITE_P( FragDepthNotFloatScalar, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("FragDepth"), Values("Fragment"), Values("Output"), Values("%f32vec4", "%u32"), Values(TestResult(SPV_ERROR_INVALID_DATA, "needs to be a 32-bit float scalar", - "is not a float scalar"))), ); + "is not a float scalar")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( + FragDepthNotFloatScalar, + ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, + Combine(Values("FragDepth"), Values("Fragment"), Values("Output"), + Values("%f32vec4", "%u32"), + Values(TestResult(SPV_ERROR_INVALID_DATA, + "needs to be a 32-bit float scalar", + "is not a float scalar")))); + +INSTANTIATE_TEST_SUITE_P( FragDepthNotF32, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("FragDepth"), Values("Fragment"), Values("Output"), Values("%f64"), Values(TestResult(SPV_ERROR_INVALID_DATA, "needs to be a 32-bit float scalar", - "has bit width 64"))), ); + "has bit width 64")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( FrontFacingAndHelperInvocationSuccess, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("FrontFacing", "HelperInvocation"), Values("Fragment"), - Values("Input"), Values("%bool"), Values(TestResult())), ); + Values("Input"), Values("%bool"), Values(TestResult()))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( + FrontFacingSuccess, + ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, + Combine(Values("FrontFacing"), Values("Fragment"), Values("Input"), + Values("%bool"), Values(TestResult()))); + +INSTANTIATE_TEST_SUITE_P( FrontFacingAndHelperInvocationNotFragment, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine( @@ -575,9 +803,18 @@ INSTANTIATE_TEST_CASE_P( "TessellationEvaluation"), Values("Input"), Values("%bool"), Values(TestResult(SPV_ERROR_INVALID_DATA, - "to be used only with Fragment execution model"))), ); + "to be used only with Fragment execution model")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( + FrontFacingNotFragment, + ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, + Combine( + Values("FrontFacing"), Values("Vertex", "GLCompute"), Values("Input"), + Values("%bool"), + Values(TestResult(SPV_ERROR_INVALID_DATA, + "to be used only with Fragment execution model")))); + +INSTANTIATE_TEST_SUITE_P( FrontFacingAndHelperInvocationNotInput, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("FrontFacing", "HelperInvocation"), Values("Fragment"), @@ -585,38 +822,73 @@ INSTANTIATE_TEST_CASE_P( Values(TestResult( SPV_ERROR_INVALID_DATA, "to be only used for variables with Input storage class", - "uses storage class Output"))), ); + "uses storage class Output")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( + FrontFacingNotInput, + ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, + Combine(Values("FrontFacing"), Values("Fragment"), Values("Output"), + Values("%bool"), + Values(TestResult( + SPV_ERROR_INVALID_DATA, + "to be only used for variables with Input storage class", + "uses storage class Output")))); + +INSTANTIATE_TEST_SUITE_P( FrontFacingAndHelperInvocationNotBool, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("FrontFacing", "HelperInvocation"), Values("Fragment"), Values("Input"), Values("%f32", "%u32"), Values(TestResult(SPV_ERROR_INVALID_DATA, "needs to be a bool scalar", - "is not a bool scalar"))), ); + "is not a bool scalar")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( + FrontFacingNotBool, + ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, + Combine(Values("FrontFacing"), Values("Fragment"), Values("Input"), + Values("%f32", "%u32"), + Values(TestResult(SPV_ERROR_INVALID_DATA, + "needs to be a bool scalar", + "is not a bool scalar")))); + +INSTANTIATE_TEST_SUITE_P( ComputeShaderInputInt32Vec3Success, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("GlobalInvocationId", "LocalInvocationId", "NumWorkgroups", "WorkgroupId"), Values("GLCompute"), Values("Input"), Values("%u32vec3"), - Values(TestResult())), ); + Values(TestResult()))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( + ComputeShaderInputInt32Vec3Success, + ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, + Combine(Values("GlobalInvocationId", "LocalInvocationId", "NumWorkgroups"), + Values("GLCompute"), Values("Input"), Values("%u32vec3"), + Values(TestResult()))); + +INSTANTIATE_TEST_SUITE_P( ComputeShaderInputInt32Vec3NotGLCompute, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, - Combine(Values("GlobalInvocationId", "LocalInvocationId", "NumWorkgroups", - "WorkgroupId"), - Values("Vertex", "Fragment", "Geometry", "TessellationControl", - "TessellationEvaluation"), - Values("Input"), Values("%u32vec3"), - Values(TestResult( - SPV_ERROR_INVALID_DATA, - "to be used only with GLCompute execution model"))), ); + Combine( + Values("GlobalInvocationId", "LocalInvocationId", "NumWorkgroups", + "WorkgroupId"), + Values("Vertex", "Fragment", "Geometry", "TessellationControl", + "TessellationEvaluation"), + Values("Input"), Values("%u32vec3"), + Values(TestResult(SPV_ERROR_INVALID_DATA, + "to be used only with GLCompute execution model")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( + ComputeShaderInputInt32Vec3NotGLCompute, + ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, + Combine( + Values("GlobalInvocationId", "LocalInvocationId", "NumWorkgroups"), + Values("Vertex", "Fragment"), Values("Input"), Values("%u32vec3"), + Values(TestResult(SPV_ERROR_INVALID_DATA, + "to be used only with GLCompute execution model")))); + +INSTANTIATE_TEST_SUITE_P( ComputeShaderInputInt32Vec3NotInput, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("GlobalInvocationId", "LocalInvocationId", "NumWorkgroups", @@ -625,9 +897,19 @@ INSTANTIATE_TEST_CASE_P( Values(TestResult( SPV_ERROR_INVALID_DATA, "to be only used for variables with Input storage class", - "uses storage class Output"))), ); + "uses storage class Output")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( + ComputeShaderInputInt32Vec3NotInput, + ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, + Combine(Values("GlobalInvocationId", "LocalInvocationId", "NumWorkgroups"), + Values("GLCompute"), Values("Output"), Values("%u32vec3"), + Values(TestResult( + SPV_ERROR_INVALID_DATA, + "to be only used for variables with Input storage class", + "uses storage class Output")))); + +INSTANTIATE_TEST_SUITE_P( ComputeShaderInputInt32Vec3NotIntVector, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("GlobalInvocationId", "LocalInvocationId", "NumWorkgroups", @@ -636,9 +918,19 @@ INSTANTIATE_TEST_CASE_P( Values("%u32arr3", "%f32vec3"), Values(TestResult(SPV_ERROR_INVALID_DATA, "needs to be a 3-component 32-bit int vector", - "is not an int vector"))), ); + "is not an int vector")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( + ComputeShaderInputInt32Vec3NotIntVector, + ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, + Combine(Values("GlobalInvocationId", "LocalInvocationId", "NumWorkgroups"), + Values("GLCompute"), Values("Input"), + Values("%u32arr3", "%f32vec3"), + Values(TestResult(SPV_ERROR_INVALID_DATA, + "needs to be a 3-component 32-bit int vector", + "is not an int vector")))); + +INSTANTIATE_TEST_SUITE_P( ComputeShaderInputInt32Vec3NotIntVec3, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("GlobalInvocationId", "LocalInvocationId", "NumWorkgroups", @@ -646,9 +938,18 @@ INSTANTIATE_TEST_CASE_P( Values("GLCompute"), Values("Input"), Values("%u32vec4"), Values(TestResult(SPV_ERROR_INVALID_DATA, "needs to be a 3-component 32-bit int vector", - "has 4 components"))), ); + "has 4 components")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( + ComputeShaderInputInt32Vec3NotIntVec3, + ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, + Combine(Values("GlobalInvocationId", "LocalInvocationId", "NumWorkgroups"), + Values("GLCompute"), Values("Input"), Values("%u32vec4"), + Values(TestResult(SPV_ERROR_INVALID_DATA, + "needs to be a 3-component 32-bit int vector", + "has 4 components")))); + +INSTANTIATE_TEST_SUITE_P( ComputeShaderInputInt32Vec3NotInt32Vec, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("GlobalInvocationId", "LocalInvocationId", "NumWorkgroups", @@ -656,15 +957,15 @@ INSTANTIATE_TEST_CASE_P( Values("GLCompute"), Values("Input"), Values("%u64vec3"), Values(TestResult(SPV_ERROR_INVALID_DATA, "needs to be a 3-component 32-bit int vector", - "has components with bit width 64"))), ); + "has components with bit width 64")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( InvocationIdSuccess, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("InvocationId"), Values("Geometry", "TessellationControl"), - Values("Input"), Values("%u32"), Values(TestResult())), ); + Values("Input"), Values("%u32"), Values(TestResult()))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( InvocationIdInvalidExecutionModel, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("InvocationId"), @@ -672,9 +973,9 @@ INSTANTIATE_TEST_CASE_P( Values("Input"), Values("%u32"), Values(TestResult(SPV_ERROR_INVALID_DATA, "to be used only with TessellationControl or " - "Geometry execution models"))), ); + "Geometry execution models")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( InvocationIdNotInput, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("InvocationId"), Values("Geometry", "TessellationControl"), @@ -682,44 +983,57 @@ INSTANTIATE_TEST_CASE_P( Values(TestResult( SPV_ERROR_INVALID_DATA, "to be only used for variables with Input storage class", - "uses storage class Output"))), ); + "uses storage class Output")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( InvocationIdNotIntScalar, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("InvocationId"), Values("Geometry", "TessellationControl"), Values("Input"), Values("%f32", "%u32vec3"), Values(TestResult(SPV_ERROR_INVALID_DATA, "needs to be a 32-bit int scalar", - "is not an int scalar"))), ); + "is not an int scalar")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( InvocationIdNotInt32, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("InvocationId"), Values("Geometry", "TessellationControl"), Values("Input"), Values("%u64"), Values(TestResult(SPV_ERROR_INVALID_DATA, "needs to be a 32-bit int scalar", - "has bit width 64"))), ); + "has bit width 64")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( InstanceIndexSuccess, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("InstanceIndex"), Values("Vertex"), Values("Input"), - Values("%u32"), Values(TestResult())), ); + Values("%u32"), Values(TestResult()))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( + InstanceIndexSuccess, + ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, + Combine(Values("InstanceIndex"), Values("Vertex"), Values("Input"), + Values("%u32"), Values(TestResult()))); + +INSTANTIATE_TEST_SUITE_P( InstanceIndexInvalidExecutionModel, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, - Combine( - Values("InstanceIndex"), - Values("Geometry", "Fragment", "GLCompute", "TessellationControl", - "TessellationEvaluation"), - Values("Input"), Values("%u32"), - Values(TestResult(SPV_ERROR_INVALID_DATA, - "to be used only with Vertex execution model"))), ); + Combine(Values("InstanceIndex"), + Values("Geometry", "Fragment", "GLCompute", "TessellationControl", + "TessellationEvaluation"), + Values("Input"), Values("%u32"), + Values(TestResult(SPV_ERROR_INVALID_DATA, + "to be used only with Vertex execution model")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( + InstanceIndexInvalidExecutionModel, + ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, + Combine(Values("InstanceIndex"), Values("Fragment", "GLCompute"), + Values("Input"), Values("%u32"), + Values(TestResult(SPV_ERROR_INVALID_DATA, + "to be used only with Vertex execution model")))); + +INSTANTIATE_TEST_SUITE_P( InstanceIndexNotInput, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("InstanceIndex"), Values("Vertex"), Values("Output"), @@ -727,39 +1041,58 @@ INSTANTIATE_TEST_CASE_P( Values(TestResult( SPV_ERROR_INVALID_DATA, "to be only used for variables with Input storage class", - "uses storage class Output"))), ); + "uses storage class Output")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( + InstanceIndexNotInput, + ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, + Combine(Values("InstanceIndex"), Values("Vertex"), Values("Output"), + Values("%u32"), + Values(TestResult( + SPV_ERROR_INVALID_DATA, + "to be only used for variables with Input storage class", + "uses storage class Output")))); + +INSTANTIATE_TEST_SUITE_P( InstanceIndexNotIntScalar, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("InstanceIndex"), Values("Vertex"), Values("Input"), Values("%f32", "%u32vec3"), Values(TestResult(SPV_ERROR_INVALID_DATA, "needs to be a 32-bit int scalar", - "is not an int scalar"))), ); + "is not an int scalar")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( + InstanceIndexNotIntScalar, + ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, + Combine(Values("InstanceIndex"), Values("Vertex"), Values("Input"), + Values("%f32", "%u32vec3"), + Values(TestResult(SPV_ERROR_INVALID_DATA, + "needs to be a 32-bit int scalar", + "is not an int scalar")))); + +INSTANTIATE_TEST_SUITE_P( InstanceIndexNotInt32, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("InstanceIndex"), Values("Vertex"), Values("Input"), Values("%u64"), Values(TestResult(SPV_ERROR_INVALID_DATA, "needs to be a 32-bit int scalar", - "has bit width 64"))), ); + "has bit width 64")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( LayerAndViewportIndexInputSuccess, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("Layer", "ViewportIndex"), Values("Fragment"), - Values("Input"), Values("%u32"), Values(TestResult())), ); + Values("Input"), Values("%u32"), Values(TestResult()))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( LayerAndViewportIndexOutputSuccess, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("Layer", "ViewportIndex"), Values("Geometry"), - Values("Output"), Values("%u32"), Values(TestResult())), ); + Values("Output"), Values("%u32"), Values(TestResult()))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( LayerAndViewportIndexInvalidExecutionModel, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("Layer", "ViewportIndex"), @@ -768,9 +1101,9 @@ INSTANTIATE_TEST_CASE_P( Values(TestResult( SPV_ERROR_INVALID_DATA, "to be used only with Vertex, TessellationEvaluation, " - "Geometry, or Fragment execution models"))), ); + "Geometry, or Fragment execution models")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( LayerAndViewportIndexExecutionModelEnabledByCapability, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("Layer", "ViewportIndex"), @@ -778,9 +1111,9 @@ INSTANTIATE_TEST_CASE_P( Values("%u32"), Values(TestResult( SPV_ERROR_INVALID_DATA, - "requires the ShaderViewportIndexLayerEXT capability"))), ); + "requires the ShaderViewportIndexLayerEXT capability")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( LayerAndViewportIndexFragmentNotInput, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine( @@ -788,9 +1121,9 @@ INSTANTIATE_TEST_CASE_P( Values("%u32"), Values(TestResult(SPV_ERROR_INVALID_DATA, "Output storage class if execution model is Fragment", - "which is called with execution model Fragment"))), ); + "which is called with execution model Fragment")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( LayerAndViewportIndexGeometryNotOutput, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine( @@ -800,34 +1133,34 @@ INSTANTIATE_TEST_CASE_P( Values(TestResult(SPV_ERROR_INVALID_DATA, "Input storage class if execution model is Vertex, " "TessellationEvaluation, or Geometry", - "which is called with execution model"))), ); + "which is called with execution model")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( LayerAndViewportIndexNotIntScalar, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("Layer", "ViewportIndex"), Values("Fragment"), Values("Input"), Values("%f32", "%u32vec3"), Values(TestResult(SPV_ERROR_INVALID_DATA, "needs to be a 32-bit int scalar", - "is not an int scalar"))), ); + "is not an int scalar")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( LayerAndViewportIndexNotInt32, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("Layer", "ViewportIndex"), Values("Fragment"), Values("Input"), Values("%u64"), Values(TestResult(SPV_ERROR_INVALID_DATA, "needs to be a 32-bit int scalar", - "has bit width 64"))), ); + "has bit width 64")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( PatchVerticesSuccess, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("PatchVertices"), Values("TessellationEvaluation", "TessellationControl"), - Values("Input"), Values("%u32"), Values(TestResult())), ); + Values("Input"), Values("%u32"), Values(TestResult()))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( PatchVerticesInvalidExecutionModel, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("PatchVertices"), @@ -835,9 +1168,9 @@ INSTANTIATE_TEST_CASE_P( Values("Input"), Values("%u32"), Values(TestResult(SPV_ERROR_INVALID_DATA, "to be used only with TessellationControl or " - "TessellationEvaluation execution models"))), ); + "TessellationEvaluation execution models")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( PatchVerticesNotInput, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("PatchVertices"), @@ -846,9 +1179,9 @@ INSTANTIATE_TEST_CASE_P( Values(TestResult( SPV_ERROR_INVALID_DATA, "to be only used for variables with Input storage class", - "uses storage class Output"))), ); + "uses storage class Output")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( PatchVerticesNotIntScalar, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("PatchVertices"), @@ -856,9 +1189,9 @@ INSTANTIATE_TEST_CASE_P( Values("Input"), Values("%f32", "%u32vec3"), Values(TestResult(SPV_ERROR_INVALID_DATA, "needs to be a 32-bit int scalar", - "is not an int scalar"))), ); + "is not an int scalar")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( PatchVerticesNotInt32, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("PatchVertices"), @@ -866,14 +1199,14 @@ INSTANTIATE_TEST_CASE_P( Values("Input"), Values("%u64"), Values(TestResult(SPV_ERROR_INVALID_DATA, "needs to be a 32-bit int scalar", - "has bit width 64"))), ); + "has bit width 64")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( PointCoordSuccess, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("PointCoord"), Values("Fragment"), Values("Input"), - Values("%f32vec2"), Values(TestResult())), ); + Values("%f32vec2"), Values(TestResult()))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( PointCoordNotFragment, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine( @@ -882,9 +1215,9 @@ INSTANTIATE_TEST_CASE_P( "TessellationEvaluation"), Values("Input"), Values("%f32vec2"), Values(TestResult(SPV_ERROR_INVALID_DATA, - "to be used only with Fragment execution model"))), ); + "to be used only with Fragment execution model")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( PointCoordNotInput, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("PointCoord"), Values("Fragment"), Values("Output"), @@ -892,51 +1225,51 @@ INSTANTIATE_TEST_CASE_P( Values(TestResult( SPV_ERROR_INVALID_DATA, "to be only used for variables with Input storage class", - "uses storage class Output"))), ); + "uses storage class Output")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( PointCoordNotFloatVector, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("PointCoord"), Values("Fragment"), Values("Input"), Values("%f32arr2", "%u32vec2"), Values(TestResult(SPV_ERROR_INVALID_DATA, "needs to be a 2-component 32-bit float vector", - "is not a float vector"))), ); + "is not a float vector")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( PointCoordNotFloatVec3, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("PointCoord"), Values("Fragment"), Values("Input"), Values("%f32vec3"), Values(TestResult(SPV_ERROR_INVALID_DATA, "needs to be a 2-component 32-bit float vector", - "has 3 components"))), ); + "has 3 components")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( PointCoordNotF32Vec4, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("PointCoord"), Values("Fragment"), Values("Input"), Values("%f64vec2"), Values(TestResult(SPV_ERROR_INVALID_DATA, "needs to be a 2-component 32-bit float vector", - "has components with bit width 64"))), ); + "has components with bit width 64")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( PointSizeOutputSuccess, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("PointSize"), Values("Vertex", "Geometry", "TessellationControl", "TessellationEvaluation"), - Values("Output"), Values("%f32"), Values(TestResult())), ); + Values("Output"), Values("%f32"), Values(TestResult()))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( PointSizeInputSuccess, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("PointSize"), Values("Geometry", "TessellationControl", "TessellationEvaluation"), - Values("Input"), Values("%f32"), Values(TestResult())), ); + Values("Input"), Values("%f32"), Values(TestResult()))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( PointSizeVertexInput, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("PointSize"), Values("Vertex"), Values("Input"), @@ -946,9 +1279,9 @@ INSTANTIATE_TEST_CASE_P( "Vulkan spec doesn't allow BuiltIn PointSize " "to be used for variables with Input storage class if " "execution model is Vertex.", - "which is called with execution model Vertex."))), ); + "which is called with execution model Vertex.")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( PointSizeInvalidExecutionModel, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("PointSize"), Values("GLCompute", "Fragment"), @@ -956,41 +1289,66 @@ INSTANTIATE_TEST_CASE_P( Values(TestResult( SPV_ERROR_INVALID_DATA, "to be used only with Vertex, TessellationControl, " - "TessellationEvaluation or Geometry execution models"))), ); + "TessellationEvaluation or Geometry execution models")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( PointSizeNotFloatScalar, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("PointSize"), Values("Vertex"), Values("Output"), Values("%f32vec4", "%u32"), Values(TestResult(SPV_ERROR_INVALID_DATA, "needs to be a 32-bit float scalar", - "is not a float scalar"))), ); + "is not a float scalar")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( PointSizeNotF32, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("PointSize"), Values("Vertex"), Values("Output"), Values("%f64"), Values(TestResult(SPV_ERROR_INVALID_DATA, "needs to be a 32-bit float scalar", - "has bit width 64"))), ); + "has bit width 64")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( PositionOutputSuccess, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("Position"), Values("Vertex", "Geometry", "TessellationControl", "TessellationEvaluation"), - Values("Output"), Values("%f32vec4"), Values(TestResult())), ); + Values("Output"), Values("%f32vec4"), Values(TestResult()))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( + PositionOutputSuccess, + ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, + Combine(Values("Position"), Values("Vertex"), Values("Output"), + Values("%f32vec4"), Values(TestResult()))); + +INSTANTIATE_TEST_SUITE_P( + PositionOutputFailure, + ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, + Combine(Values("Position"), Values("Fragment", "GLCompute"), + Values("Output"), Values("%f32vec4"), + Values(TestResult(SPV_ERROR_INVALID_DATA, + "WebGPU spec allows BuiltIn Position to be used " + "only with the Vertex execution model.")))); + +INSTANTIATE_TEST_SUITE_P( PositionInputSuccess, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("Position"), Values("Geometry", "TessellationControl", "TessellationEvaluation"), - Values("Input"), Values("%f32vec4"), Values(TestResult())), ); + Values("Input"), Values("%f32vec4"), Values(TestResult()))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( + PositionInputFailure, + ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, + Combine( + Values("Position"), Values("Vertex", "Fragment", "GLCompute"), + Values("Input"), Values("%f32vec4"), + Values(TestResult(SPV_ERROR_INVALID_DATA, + "WebGPU spec allows BuiltIn Position to be only used " + "for variables with Output storage class")))); + +INSTANTIATE_TEST_SUITE_P( PositionVertexInput, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("Position"), Values("Vertex"), Values("Input"), @@ -1000,9 +1358,9 @@ INSTANTIATE_TEST_CASE_P( "Vulkan spec doesn't allow BuiltIn Position " "to be used for variables with Input storage class if " "execution model is Vertex.", - "which is called with execution model Vertex."))), ); + "which is called with execution model Vertex.")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( PositionInvalidExecutionModel, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("Position"), Values("GLCompute", "Fragment"), @@ -1010,50 +1368,68 @@ INSTANTIATE_TEST_CASE_P( Values(TestResult( SPV_ERROR_INVALID_DATA, "to be used only with Vertex, TessellationControl, " - "TessellationEvaluation or Geometry execution models"))), ); + "TessellationEvaluation or Geometry execution models")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( PositionNotFloatVector, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("Position"), Values("Geometry"), Values("Input"), Values("%f32arr4", "%u32vec4"), Values(TestResult(SPV_ERROR_INVALID_DATA, "needs to be a 4-component 32-bit float vector", - "is not a float vector"))), ); + "is not a float vector")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( + PositionNotFloatVector, + ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, + Combine( + Values("Position"), Values("Vertex"), Values("Output"), + Values("%f32arr4", "%u32vec4"), + Values(TestResult(SPV_ERROR_INVALID_DATA, + "needs to be a 4-component 32-bit float vector")))); + +INSTANTIATE_TEST_SUITE_P( PositionNotFloatVec4, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("Position"), Values("Geometry"), Values("Input"), Values("%f32vec3"), Values(TestResult(SPV_ERROR_INVALID_DATA, "needs to be a 4-component 32-bit float vector", - "has 3 components"))), ); + "has 3 components")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( + PositionNotFloatVec4, + ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, + Combine( + Values("Position"), Values("Vertex"), Values("Output"), + Values("%f32vec3"), + Values(TestResult(SPV_ERROR_INVALID_DATA, + "needs to be a 4-component 32-bit float vector")))); + +INSTANTIATE_TEST_SUITE_P( PositionNotF32Vec4, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("Position"), Values("Geometry"), Values("Input"), Values("%f64vec4"), Values(TestResult(SPV_ERROR_INVALID_DATA, "needs to be a 4-component 32-bit float vector", - "has components with bit width 64"))), ); + "has components with bit width 64")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( PrimitiveIdInputSuccess, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("PrimitiveId"), Values("Fragment", "TessellationControl", "TessellationEvaluation", "Geometry"), - Values("Input"), Values("%u32"), Values(TestResult())), ); + Values("Input"), Values("%u32"), Values(TestResult()))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( PrimitiveIdOutputSuccess, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("PrimitiveId"), Values("Geometry"), Values("Output"), - Values("%u32"), Values(TestResult())), ); + Values("%u32"), Values(TestResult()))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( PrimitiveIdInvalidExecutionModel, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("PrimitiveId"), Values("Vertex", "GLCompute"), @@ -1061,9 +1437,9 @@ INSTANTIATE_TEST_CASE_P( Values(TestResult( SPV_ERROR_INVALID_DATA, "to be used only with Fragment, TessellationControl, " - "TessellationEvaluation or Geometry execution models"))), ); + "TessellationEvaluation or Geometry execution models")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( PrimitiveIdFragmentNotInput, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine( @@ -1071,9 +1447,9 @@ INSTANTIATE_TEST_CASE_P( Values("%u32"), Values(TestResult(SPV_ERROR_INVALID_DATA, "Output storage class if execution model is Fragment", - "which is called with execution model Fragment"))), ); + "which is called with execution model Fragment")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( PrimitiveIdGeometryNotInput, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("PrimitiveId"), @@ -1082,32 +1458,32 @@ INSTANTIATE_TEST_CASE_P( Values(TestResult( SPV_ERROR_INVALID_DATA, "Output storage class if execution model is Tessellation", - "which is called with execution model Tessellation"))), ); + "which is called with execution model Tessellation")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( PrimitiveIdNotIntScalar, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("PrimitiveId"), Values("Fragment"), Values("Input"), Values("%f32", "%u32vec3"), Values(TestResult(SPV_ERROR_INVALID_DATA, "needs to be a 32-bit int scalar", - "is not an int scalar"))), ); + "is not an int scalar")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( PrimitiveIdNotInt32, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("PrimitiveId"), Values("Fragment"), Values("Input"), Values("%u64"), Values(TestResult(SPV_ERROR_INVALID_DATA, "needs to be a 32-bit int scalar", - "has bit width 64"))), ); + "has bit width 64")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SampleIdSuccess, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("SampleId"), Values("Fragment"), Values("Input"), - Values("%u32"), Values(TestResult())), ); + Values("%u32"), Values(TestResult()))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SampleIdInvalidExecutionModel, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine( @@ -1116,40 +1492,40 @@ INSTANTIATE_TEST_CASE_P( "TessellationEvaluation"), Values("Input"), Values("%u32"), Values(TestResult(SPV_ERROR_INVALID_DATA, - "to be used only with Fragment execution model"))), ); + "to be used only with Fragment execution model")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SampleIdNotInput, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine( Values("SampleId"), Values("Fragment"), Values("Output"), Values("%u32"), Values(TestResult(SPV_ERROR_INVALID_DATA, "Vulkan spec allows BuiltIn SampleId to be only used " - "for variables with Input storage class"))), ); + "for variables with Input storage class")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SampleIdNotIntScalar, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("SampleId"), Values("Fragment"), Values("Input"), Values("%f32", "%u32vec3"), Values(TestResult(SPV_ERROR_INVALID_DATA, "needs to be a 32-bit int scalar", - "is not an int scalar"))), ); + "is not an int scalar")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SampleIdNotInt32, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("SampleId"), Values("Fragment"), Values("Input"), Values("%u64"), Values(TestResult(SPV_ERROR_INVALID_DATA, "needs to be a 32-bit int scalar", - "has bit width 64"))), ); + "has bit width 64")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SampleMaskSuccess, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("SampleMask"), Values("Fragment"), Values("Input", "Output"), - Values("%u32arr2", "%u32arr4"), Values(TestResult())), ); + Values("%u32arr2", "%u32arr4"), Values(TestResult()))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SampleMaskInvalidExecutionModel, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine( @@ -1158,52 +1534,52 @@ INSTANTIATE_TEST_CASE_P( "TessellationEvaluation"), Values("Input"), Values("%u32arr2"), Values(TestResult(SPV_ERROR_INVALID_DATA, - "to be used only with Fragment execution model"))), ); + "to be used only with Fragment execution model")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SampleMaskWrongStorageClass, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, - Combine(Values("SampleMask"), Values("Fragment"), Values("UniformConstant"), + Combine(Values("SampleMask"), Values("Fragment"), Values("Workgroup"), Values("%u32arr2"), Values(TestResult( SPV_ERROR_INVALID_DATA, "Vulkan spec allows BuiltIn SampleMask to be only used for " - "variables with Input or Output storage class"))), ); + "variables with Input or Output storage class")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SampleMaskNotArray, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("SampleMask"), Values("Fragment"), Values("Input"), Values("%f32", "%u32vec3"), Values(TestResult(SPV_ERROR_INVALID_DATA, "needs to be a 32-bit int array", - "is not an array"))), ); + "is not an array")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SampleMaskNotIntArray, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("SampleMask"), Values("Fragment"), Values("Input"), Values("%f32arr2"), Values(TestResult(SPV_ERROR_INVALID_DATA, "needs to be a 32-bit int array", - "components are not int scalar"))), ); + "components are not int scalar")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SampleMaskNotInt32Array, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("SampleMask"), Values("Fragment"), Values("Input"), Values("%u64arr2"), Values(TestResult(SPV_ERROR_INVALID_DATA, "needs to be a 32-bit int array", - "has components with bit width 64"))), ); + "has components with bit width 64")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SamplePositionSuccess, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("SamplePosition"), Values("Fragment"), Values("Input"), - Values("%f32vec2"), Values(TestResult())), ); + Values("%f32vec2"), Values(TestResult()))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SamplePositionNotFragment, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine( @@ -1212,9 +1588,9 @@ INSTANTIATE_TEST_CASE_P( "TessellationEvaluation"), Values("Input"), Values("%f32vec2"), Values(TestResult(SPV_ERROR_INVALID_DATA, - "to be used only with Fragment execution model"))), ); + "to be used only with Fragment execution model")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SamplePositionNotInput, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("SamplePosition"), Values("Fragment"), Values("Output"), @@ -1222,41 +1598,41 @@ INSTANTIATE_TEST_CASE_P( Values(TestResult( SPV_ERROR_INVALID_DATA, "to be only used for variables with Input storage class", - "uses storage class Output"))), ); + "uses storage class Output")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SamplePositionNotFloatVector, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("SamplePosition"), Values("Fragment"), Values("Input"), Values("%f32arr2", "%u32vec4"), Values(TestResult(SPV_ERROR_INVALID_DATA, "needs to be a 2-component 32-bit float vector", - "is not a float vector"))), ); + "is not a float vector")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SamplePositionNotFloatVec2, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("SamplePosition"), Values("Fragment"), Values("Input"), Values("%f32vec3"), Values(TestResult(SPV_ERROR_INVALID_DATA, "needs to be a 2-component 32-bit float vector", - "has 3 components"))), ); + "has 3 components")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( SamplePositionNotF32Vec2, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("SamplePosition"), Values("Fragment"), Values("Input"), Values("%f64vec2"), Values(TestResult(SPV_ERROR_INVALID_DATA, "needs to be a 2-component 32-bit float vector", - "has components with bit width 64"))), ); + "has components with bit width 64")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( TessCoordSuccess, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("TessCoord"), Values("TessellationEvaluation"), - Values("Input"), Values("%f32vec3"), Values(TestResult())), ); + Values("Input"), Values("%f32vec3"), Values(TestResult()))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( TessCoordNotFragment, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine( @@ -1266,57 +1642,57 @@ INSTANTIATE_TEST_CASE_P( Values("Input"), Values("%f32vec3"), Values(TestResult( SPV_ERROR_INVALID_DATA, - "to be used only with TessellationEvaluation execution model"))), ); + "to be used only with TessellationEvaluation execution model")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( TessCoordNotInput, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("TessCoord"), Values("Fragment"), Values("Output"), Values("%f32vec3"), Values(TestResult( SPV_ERROR_INVALID_DATA, "to be only used for variables with Input storage class", - "uses storage class Output"))), ); + "uses storage class Output")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( TessCoordNotFloatVector, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("TessCoord"), Values("Fragment"), Values("Input"), Values("%f32arr3", "%u32vec4"), Values(TestResult(SPV_ERROR_INVALID_DATA, "needs to be a 3-component 32-bit float vector", - "is not a float vector"))), ); + "is not a float vector")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( TessCoordNotFloatVec3, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("TessCoord"), Values("Fragment"), Values("Input"), Values("%f32vec2"), Values(TestResult(SPV_ERROR_INVALID_DATA, "needs to be a 3-component 32-bit float vector", - "has 2 components"))), ); + "has 2 components")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( TessCoordNotF32Vec3, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("TessCoord"), Values("Fragment"), Values("Input"), Values("%f64vec3"), Values(TestResult(SPV_ERROR_INVALID_DATA, "needs to be a 3-component 32-bit float vector", - "has components with bit width 64"))), ); + "has components with bit width 64")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( TessLevelOuterTeseInputSuccess, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("TessLevelOuter"), Values("TessellationEvaluation"), - Values("Input"), Values("%f32arr4"), Values(TestResult())), ); + Values("Input"), Values("%f32arr4"), Values(TestResult()))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( TessLevelOuterTescOutputSuccess, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("TessLevelOuter"), Values("TessellationControl"), - Values("Output"), Values("%f32arr4"), Values(TestResult())), ); + Values("Output"), Values("%f32arr4"), Values(TestResult()))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( TessLevelOuterInvalidExecutionModel, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("TessLevelOuter"), @@ -1324,9 +1700,9 @@ INSTANTIATE_TEST_CASE_P( Values("Input"), Values("%f32arr4"), Values(TestResult(SPV_ERROR_INVALID_DATA, "to be used only with TessellationControl or " - "TessellationEvaluation execution models."))), ); + "TessellationEvaluation execution models.")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( TessLevelOuterOutputTese, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("TessLevelOuter"), Values("TessellationEvaluation"), @@ -1335,9 +1711,9 @@ INSTANTIATE_TEST_CASE_P( SPV_ERROR_INVALID_DATA, "Vulkan spec doesn't allow TessLevelOuter/TessLevelInner to be " "used for variables with Output storage class if execution " - "model is TessellationEvaluation."))), ); + "model is TessellationEvaluation.")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( TessLevelOuterInputTesc, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("TessLevelOuter"), Values("TessellationControl"), @@ -1346,57 +1722,57 @@ INSTANTIATE_TEST_CASE_P( SPV_ERROR_INVALID_DATA, "Vulkan spec doesn't allow TessLevelOuter/TessLevelInner to be " "used for variables with Input storage class if execution " - "model is TessellationControl."))), ); + "model is TessellationControl.")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( TessLevelOuterNotArray, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("TessLevelOuter"), Values("TessellationEvaluation"), Values("Input"), Values("%f32vec4", "%f32"), Values(TestResult(SPV_ERROR_INVALID_DATA, "needs to be a 4-component 32-bit float array", - "is not an array"))), ); + "is not an array")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( TessLevelOuterNotFloatArray, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("TessLevelOuter"), Values("TessellationEvaluation"), Values("Input"), Values("%u32arr4"), Values(TestResult(SPV_ERROR_INVALID_DATA, "needs to be a 4-component 32-bit float array", - "components are not float scalar"))), ); + "components are not float scalar")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( TessLevelOuterNotFloatArr4, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("TessLevelOuter"), Values("TessellationEvaluation"), Values("Input"), Values("%f32arr3"), Values(TestResult(SPV_ERROR_INVALID_DATA, "needs to be a 4-component 32-bit float array", - "has 3 components"))), ); + "has 3 components")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( TessLevelOuterNotF32Arr4, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("TessLevelOuter"), Values("TessellationEvaluation"), Values("Input"), Values("%f64arr4"), Values(TestResult(SPV_ERROR_INVALID_DATA, "needs to be a 4-component 32-bit float array", - "has components with bit width 64"))), ); + "has components with bit width 64")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( TessLevelInnerTeseInputSuccess, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("TessLevelInner"), Values("TessellationEvaluation"), - Values("Input"), Values("%f32arr2"), Values(TestResult())), ); + Values("Input"), Values("%f32arr2"), Values(TestResult()))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( TessLevelInnerTescOutputSuccess, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("TessLevelInner"), Values("TessellationControl"), - Values("Output"), Values("%f32arr2"), Values(TestResult())), ); + Values("Output"), Values("%f32arr2"), Values(TestResult()))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( TessLevelInnerInvalidExecutionModel, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("TessLevelInner"), @@ -1404,9 +1780,9 @@ INSTANTIATE_TEST_CASE_P( Values("Input"), Values("%f32arr2"), Values(TestResult(SPV_ERROR_INVALID_DATA, "to be used only with TessellationControl or " - "TessellationEvaluation execution models."))), ); + "TessellationEvaluation execution models.")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( TessLevelInnerOutputTese, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("TessLevelInner"), Values("TessellationEvaluation"), @@ -1415,9 +1791,9 @@ INSTANTIATE_TEST_CASE_P( SPV_ERROR_INVALID_DATA, "Vulkan spec doesn't allow TessLevelOuter/TessLevelInner to be " "used for variables with Output storage class if execution " - "model is TessellationEvaluation."))), ); + "model is TessellationEvaluation.")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( TessLevelInnerInputTesc, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("TessLevelInner"), Values("TessellationControl"), @@ -1426,62 +1802,75 @@ INSTANTIATE_TEST_CASE_P( SPV_ERROR_INVALID_DATA, "Vulkan spec doesn't allow TessLevelOuter/TessLevelInner to be " "used for variables with Input storage class if execution " - "model is TessellationControl."))), ); + "model is TessellationControl.")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( TessLevelInnerNotArray, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("TessLevelInner"), Values("TessellationEvaluation"), Values("Input"), Values("%f32vec2", "%f32"), Values(TestResult(SPV_ERROR_INVALID_DATA, "needs to be a 2-component 32-bit float array", - "is not an array"))), ); + "is not an array")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( TessLevelInnerNotFloatArray, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("TessLevelInner"), Values("TessellationEvaluation"), Values("Input"), Values("%u32arr2"), Values(TestResult(SPV_ERROR_INVALID_DATA, "needs to be a 2-component 32-bit float array", - "components are not float scalar"))), ); + "components are not float scalar")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( TessLevelInnerNotFloatArr2, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("TessLevelInner"), Values("TessellationEvaluation"), Values("Input"), Values("%f32arr3"), Values(TestResult(SPV_ERROR_INVALID_DATA, "needs to be a 2-component 32-bit float array", - "has 3 components"))), ); + "has 3 components")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( TessLevelInnerNotF32Arr2, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("TessLevelInner"), Values("TessellationEvaluation"), Values("Input"), Values("%f64arr2"), Values(TestResult(SPV_ERROR_INVALID_DATA, "needs to be a 2-component 32-bit float array", - "has components with bit width 64"))), ); + "has components with bit width 64")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( VertexIndexSuccess, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("VertexIndex"), Values("Vertex"), Values("Input"), - Values("%u32"), Values(TestResult())), ); + Values("%u32"), Values(TestResult()))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( + VertexIndexSuccess, + ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, + Combine(Values("VertexIndex"), Values("Vertex"), Values("Input"), + Values("%u32"), Values(TestResult()))); + +INSTANTIATE_TEST_SUITE_P( VertexIndexInvalidExecutionModel, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, - Combine( - Values("VertexIndex"), - Values("Fragment", "GLCompute", "Geometry", "TessellationControl", - "TessellationEvaluation"), - Values("Input"), Values("%u32"), - Values(TestResult(SPV_ERROR_INVALID_DATA, - "to be used only with Vertex execution model"))), ); + Combine(Values("VertexIndex"), + Values("Fragment", "GLCompute", "Geometry", "TessellationControl", + "TessellationEvaluation"), + Values("Input"), Values("%u32"), + Values(TestResult(SPV_ERROR_INVALID_DATA, + "to be used only with Vertex execution model")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( + VertexIndexInvalidExecutionModel, + ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, + Combine(Values("VertexIndex"), Values("Fragment", "GLCompute"), + Values("Input"), Values("%u32"), + Values(TestResult(SPV_ERROR_INVALID_DATA, + "to be used only with Vertex execution model")))); + +INSTANTIATE_TEST_SUITE_P( VertexIndexNotInput, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine( @@ -1489,44 +1878,115 @@ INSTANTIATE_TEST_CASE_P( Values("%u32"), Values(TestResult(SPV_ERROR_INVALID_DATA, "Vulkan spec allows BuiltIn VertexIndex to be only " - "used for variables with Input storage class"))), ); + "used for variables with Input storage class")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( + VertexIndexNotInput, + ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, + Combine( + Values("VertexIndex"), Values("Vertex"), Values("Output"), + Values("%u32"), + Values(TestResult(SPV_ERROR_INVALID_DATA, + "WebGPU spec allows BuiltIn VertexIndex to be only " + "used for variables with Input storage class")))); + +INSTANTIATE_TEST_SUITE_P( VertexIndexNotIntScalar, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("VertexIndex"), Values("Vertex"), Values("Input"), Values("%f32", "%u32vec3"), Values(TestResult(SPV_ERROR_INVALID_DATA, "needs to be a 32-bit int scalar", - "is not an int scalar"))), ); + "is not an int scalar")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( + VertexIndexNotIntScalar, + ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, + Combine(Values("VertexIndex"), Values("Vertex"), Values("Input"), + Values("%f32", "%u32vec3"), + Values(TestResult(SPV_ERROR_INVALID_DATA, + "needs to be a 32-bit int scalar", + "is not an int scalar")))); + +INSTANTIATE_TEST_SUITE_P( VertexIndexNotInt32, ValidateVulkanCombineBuiltInExecutionModelDataTypeResult, Combine(Values("VertexIndex"), Values("Vertex"), Values("Input"), Values("%u64"), Values(TestResult(SPV_ERROR_INVALID_DATA, "needs to be a 32-bit int scalar", - "has bit width 64"))), ); + "has bit width 64")))); -TEST_P(ValidateVulkanCombineBuiltInArrayedVariable, Variable) { - const char* const built_in = std::get<0>(GetParam()); - const char* const execution_model = std::get<1>(GetParam()); - const char* const storage_class = std::get<2>(GetParam()); - const char* const data_type = std::get<3>(GetParam()); - const TestResult& test_result = std::get<4>(GetParam()); +INSTANTIATE_TEST_SUITE_P( + LocalInvocationIndexSuccess, + ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, + Combine(Values("LocalInvocationIndex"), Values("GLCompute"), + Values("Input"), Values("%u32"), Values(TestResult()))); + +INSTANTIATE_TEST_SUITE_P( + LocalInvocationIndexInvalidExecutionModel, + ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, + Combine( + Values("LocalInvocationIndex"), Values("Fragment", "Vertex"), + Values("Input"), Values("%u32"), + Values(TestResult(SPV_ERROR_INVALID_DATA, + "to be used only with GLCompute execution model")))); + +INSTANTIATE_TEST_SUITE_P( + LocalInvocationIndexNotInput, + ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, + Combine( + Values("LocalInvocationIndex"), Values("GLCompute"), Values("Output"), + Values("%u32"), + Values(TestResult(SPV_ERROR_INVALID_DATA, + "WebGPU spec allows BuiltIn LocalInvocationIndex to " + "be only used for variables with Input storage " + "class")))); + +INSTANTIATE_TEST_SUITE_P( + LocalInvocationIndexNotIntScalar, + ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, + Combine(Values("LocalInvocationIndex"), Values("GLCompute"), + Values("Input"), Values("%f32", "%u32vec3"), + Values(TestResult(SPV_ERROR_INVALID_DATA, + "needs to be a 32-bit int", "is not an int")))); + +INSTANTIATE_TEST_SUITE_P( + WhitelistRejection, + ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult, + Combine(Values("PointSize", "ClipDistance", "CullDistance", "VertexId", + "InstanceId", "PointCoord", "SampleMask", "HelperInvocation", + "WorkgroupId"), + Values("Vertex"), Values("Input"), Values("%u32"), + Values(TestResult(SPV_ERROR_INVALID_DATA, + "WebGPU does not allow BuiltIn")))); + +CodeGenerator GetArrayedVariableCodeGenerator(spv_target_env env, + const char* const built_in, + const char* const execution_model, + const char* const storage_class, + const char* const data_type) { + CodeGenerator generator = + spvIsWebGPUEnv(env) ? CodeGenerator::GetWebGPUShaderCodeGenerator() + : CodeGenerator::GetDefaultShaderCodeGenerator(); - CodeGenerator generator = GetDefaultShaderCodeGenerator(); generator.before_types_ = "OpDecorate %built_in_var BuiltIn "; generator.before_types_ += built_in; generator.before_types_ += "\n"; std::ostringstream after_types; after_types << "%built_in_array = OpTypeArray " << data_type << " %u32_3\n"; + if (InitializerRequired(env, storage_class)) { + after_types << "%built_in_array_null = OpConstantNull %built_in_array\n"; + } + after_types << "%built_in_ptr = OpTypePointer " << storage_class << " %built_in_array\n"; - after_types << "%built_in_var = OpVariable %built_in_ptr " << storage_class - << "\n"; + after_types << "%built_in_var = OpVariable %built_in_ptr " << storage_class; + if (InitializerRequired(env, storage_class)) { + after_types << " %built_in_array_null"; + } + after_types << "\n"; generator.after_types_ = after_types.str(); EntryPoint entry_point; @@ -1535,22 +1995,45 @@ TEST_P(ValidateVulkanCombineBuiltInArrayedVariable, Variable) { entry_point.interfaces = "%built_in_var"; // Any kind of reference would do. entry_point.body = R"( -%val = OpBitcast %u64 %built_in_var +%val = OpBitcast %u32 %built_in_var )"; std::ostringstream execution_modes; if (0 == std::strcmp(execution_model, "Fragment")) { execution_modes << "OpExecutionMode %" << entry_point.name << " OriginUpperLeft\n"; + if (0 == std::strcmp(built_in, "FragDepth")) { + execution_modes << "OpExecutionMode %" << entry_point.name + << " DepthReplacing\n"; + } } - if (0 == std::strcmp(built_in, "FragDepth")) { + if (0 == std::strcmp(execution_model, "Geometry")) { execution_modes << "OpExecutionMode %" << entry_point.name - << " DepthReplacing\n"; + << " InputPoints\n"; + execution_modes << "OpExecutionMode %" << entry_point.name + << " OutputPoints\n"; + } + if (0 == std::strcmp(execution_model, "GLCompute")) { + execution_modes << "OpExecutionMode %" << entry_point.name + << " LocalSize 1 1 1\n"; } entry_point.execution_modes = execution_modes.str(); generator.entry_points_.push_back(std::move(entry_point)); + return generator; +} + +TEST_P(ValidateVulkanCombineBuiltInArrayedVariable, Variable) { + const char* const built_in = std::get<0>(GetParam()); + const char* const execution_model = std::get<1>(GetParam()); + const char* const storage_class = std::get<2>(GetParam()); + const char* const data_type = std::get<3>(GetParam()); + const TestResult& test_result = std::get<4>(GetParam()); + + CodeGenerator generator = GetArrayedVariableCodeGenerator( + SPV_ENV_VULKAN_1_0, built_in, execution_model, storage_class, data_type); + CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0); ASSERT_EQ(test_result.validation_result, ValidateInstructions(SPV_ENV_VULKAN_1_0)); @@ -1562,78 +2045,185 @@ TEST_P(ValidateVulkanCombineBuiltInArrayedVariable, Variable) { } } -INSTANTIATE_TEST_CASE_P(PointSizeArrayedF32TessControl, - ValidateVulkanCombineBuiltInArrayedVariable, - Combine(Values("PointSize"), - Values("TessellationControl"), Values("Input"), - Values("%f32"), Values(TestResult())), ); +TEST_P(ValidateWebGPUCombineBuiltInArrayedVariable, Variable) { + const char* const built_in = std::get<0>(GetParam()); + const char* const execution_model = std::get<1>(GetParam()); + const char* const storage_class = std::get<2>(GetParam()); + const char* const data_type = std::get<3>(GetParam()); + const TestResult& test_result = std::get<4>(GetParam()); -INSTANTIATE_TEST_CASE_P( + CodeGenerator generator = GetArrayedVariableCodeGenerator( + SPV_ENV_WEBGPU_0, built_in, execution_model, storage_class, data_type); + + CompileSuccessfully(generator.Build(), SPV_ENV_WEBGPU_0); + ASSERT_EQ(test_result.validation_result, + ValidateInstructions(SPV_ENV_WEBGPU_0)); + if (test_result.error_str) { + EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str)); + } + if (test_result.error_str2) { + EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str2)); + } +} + +INSTANTIATE_TEST_SUITE_P(PointSizeArrayedF32TessControl, + ValidateVulkanCombineBuiltInArrayedVariable, + Combine(Values("PointSize"), + Values("TessellationControl"), Values("Input"), + Values("%f32"), Values(TestResult()))); + +INSTANTIATE_TEST_SUITE_P( PointSizeArrayedF64TessControl, ValidateVulkanCombineBuiltInArrayedVariable, Combine(Values("PointSize"), Values("TessellationControl"), Values("Input"), Values("%f64"), Values(TestResult(SPV_ERROR_INVALID_DATA, "needs to be a 32-bit float scalar", - "has bit width 64"))), ); + "has bit width 64")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( PointSizeArrayedF32Vertex, ValidateVulkanCombineBuiltInArrayedVariable, Combine(Values("PointSize"), Values("Vertex"), Values("Output"), Values("%f32"), Values(TestResult(SPV_ERROR_INVALID_DATA, "needs to be a 32-bit float scalar", - "is not a float scalar"))), ); + "is not a float scalar")))); -INSTANTIATE_TEST_CASE_P(PositionArrayedF32Vec4TessControl, - ValidateVulkanCombineBuiltInArrayedVariable, - Combine(Values("Position"), - Values("TessellationControl"), Values("Input"), - Values("%f32vec4"), Values(TestResult())), ); +INSTANTIATE_TEST_SUITE_P(PositionArrayedF32Vec4TessControl, + ValidateVulkanCombineBuiltInArrayedVariable, + Combine(Values("Position"), + Values("TessellationControl"), Values("Input"), + Values("%f32vec4"), Values(TestResult()))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( PositionArrayedF32Vec3TessControl, ValidateVulkanCombineBuiltInArrayedVariable, Combine(Values("Position"), Values("TessellationControl"), Values("Input"), Values("%f32vec3"), Values(TestResult(SPV_ERROR_INVALID_DATA, "needs to be a 4-component 32-bit float vector", - "has 3 components"))), ); + "has 3 components")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( PositionArrayedF32Vec4Vertex, ValidateVulkanCombineBuiltInArrayedVariable, Combine(Values("Position"), Values("Vertex"), Values("Output"), - Values("%f32"), + Values("%f32vec4"), Values(TestResult(SPV_ERROR_INVALID_DATA, "needs to be a 4-component 32-bit float vector", - "is not a float vector"))), ); + "is not a float vector")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( + PositionArrayedF32Vec4Vertex, ValidateWebGPUCombineBuiltInArrayedVariable, + Combine(Values("Position"), Values("Vertex"), Values("Output"), + Values("%f32vec4"), + Values(TestResult(SPV_ERROR_INVALID_DATA, + "needs to be a 4-component 32-bit float vector", + "is not a float vector")))); + +INSTANTIATE_TEST_SUITE_P( ClipAndCullDistanceOutputSuccess, ValidateVulkanCombineBuiltInArrayedVariable, Combine(Values("ClipDistance", "CullDistance"), Values("Geometry", "TessellationControl", "TessellationEvaluation"), Values("Output"), Values("%f32arr2", "%f32arr4"), - Values(TestResult())), ); + Values(TestResult()))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( ClipAndCullDistanceVertexInput, ValidateVulkanCombineBuiltInArrayedVariable, Combine(Values("ClipDistance", "CullDistance"), Values("Fragment"), Values("Input"), Values("%f32arr4"), Values(TestResult(SPV_ERROR_INVALID_DATA, "needs to be a 32-bit float array", - "components are not float scalar"))), ); + "components are not float scalar")))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( ClipAndCullDistanceNotArray, ValidateVulkanCombineBuiltInArrayedVariable, Combine(Values("ClipDistance", "CullDistance"), Values("Geometry", "TessellationControl", "TessellationEvaluation"), Values("Input"), Values("%f32vec2", "%f32vec4"), Values(TestResult(SPV_ERROR_INVALID_DATA, "needs to be a 32-bit float array", - "components are not float scalar"))), ); + "components are not float scalar")))); + +INSTANTIATE_TEST_SUITE_P( + SMBuiltinsInputSuccess, + ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult, + Combine(Values("SMCountNV", "SMIDNV", "WarpsPerSMNV", "WarpIDNV"), + Values("Vertex", "Fragment", "TessellationControl", + "TessellationEvaluation", "Geometry", "GLCompute"), + Values("Input"), Values("%u32"), + Values("OpCapability ShaderSMBuiltinsNV\n"), + Values("OpExtension \"SPV_NV_shader_sm_builtins\"\n"), + Values(TestResult()))); + +INSTANTIATE_TEST_SUITE_P( + SMBuiltinsInputMeshSuccess, + ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult, + Combine( + Values("SMCountNV", "SMIDNV", "WarpsPerSMNV", "WarpIDNV"), + Values("MeshNV", "TaskNV"), Values("Input"), Values("%u32"), + Values("OpCapability ShaderSMBuiltinsNV\nOpCapability MeshShadingNV\n"), + Values("OpExtension \"SPV_NV_shader_sm_builtins\"\nOpExtension " + "\"SPV_NV_mesh_shader\"\n"), + Values(TestResult()))); + +INSTANTIATE_TEST_SUITE_P( + SMBuiltinsInputRaySuccess, + ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult, + Combine( + Values("SMCountNV", "SMIDNV", "WarpsPerSMNV", "WarpIDNV"), + Values("RayGenerationNV", "IntersectionNV", "AnyHitNV", "ClosestHitNV", + "MissNV", "CallableNV"), + Values("Input"), Values("%u32"), + Values("OpCapability ShaderSMBuiltinsNV\nOpCapability RayTracingNV\n"), + Values("OpExtension \"SPV_NV_shader_sm_builtins\"\nOpExtension " + "\"SPV_NV_ray_tracing\"\n"), + Values(TestResult()))); + +INSTANTIATE_TEST_SUITE_P( + SMBuiltinsNotInput, + ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult, + Combine(Values("SMCountNV", "SMIDNV", "WarpsPerSMNV", "WarpIDNV"), + Values("Vertex", "Fragment", "TessellationControl", + "TessellationEvaluation", "Geometry", "GLCompute"), + Values("Output"), Values("%u32"), + Values("OpCapability ShaderSMBuiltinsNV\n"), + Values("OpExtension \"SPV_NV_shader_sm_builtins\"\n"), + Values(TestResult( + SPV_ERROR_INVALID_DATA, + "to be only used for variables with Input storage class", + "uses storage class Output")))); + +INSTANTIATE_TEST_SUITE_P( + SMBuiltinsNotIntScalar, + ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult, + Combine(Values("SMCountNV", "SMIDNV", "WarpsPerSMNV", "WarpIDNV"), + Values("Vertex", "Fragment", "TessellationControl", + "TessellationEvaluation", "Geometry", "GLCompute"), + Values("Input"), Values("%f32", "%u32vec3"), + Values("OpCapability ShaderSMBuiltinsNV\n"), + Values("OpExtension \"SPV_NV_shader_sm_builtins\"\n"), + Values(TestResult(SPV_ERROR_INVALID_DATA, + "needs to be a 32-bit int scalar", + "is not an int scalar")))); + +INSTANTIATE_TEST_SUITE_P( + SMBuiltinsNotInt32, + ValidateVulkanCombineBuiltInExecutionModelDataTypeCapabilityExtensionResult, + Combine(Values("SMCountNV", "SMIDNV", "WarpsPerSMNV", "WarpIDNV"), + Values("Vertex", "Fragment", "TessellationControl", + "TessellationEvaluation", "Geometry", "GLCompute"), + Values("Input"), Values("%u64"), + Values("OpCapability ShaderSMBuiltinsNV\n"), + Values("OpExtension \"SPV_NV_shader_sm_builtins\"\n"), + Values(TestResult(SPV_ERROR_INVALID_DATA, + "needs to be a 32-bit int scalar", + "has bit width 64")))); + +CodeGenerator GetWorkgroupSizeSuccessGenerator(spv_target_env env) { + CodeGenerator generator = + env == SPV_ENV_WEBGPU_0 ? CodeGenerator::GetWebGPUShaderCodeGenerator() + : CodeGenerator::GetDefaultShaderCodeGenerator(); -TEST_F(ValidateBuiltIns, WorkgroupSizeSuccess) { - CodeGenerator generator = GetDefaultShaderCodeGenerator(); generator.before_types_ = R"( OpDecorate %workgroup_size BuiltIn WorkgroupSize )"; @@ -1650,12 +2240,27 @@ OpDecorate %workgroup_size BuiltIn WorkgroupSize )"; generator.entry_points_.push_back(std::move(entry_point)); + return generator; +} + +TEST_F(ValidateBuiltIns, VulkanWorkgroupSizeSuccess) { + CodeGenerator generator = + GetWorkgroupSizeSuccessGenerator(SPV_ENV_VULKAN_1_0); CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0); ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0)); } -TEST_F(ValidateBuiltIns, WorkgroupSizeFragment) { - CodeGenerator generator = GetDefaultShaderCodeGenerator(); +TEST_F(ValidateBuiltIns, WebGPUWorkgroupSizeSuccess) { + CodeGenerator generator = GetWorkgroupSizeSuccessGenerator(SPV_ENV_WEBGPU_0); + CompileSuccessfully(generator.Build(), SPV_ENV_WEBGPU_0); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); +} + +CodeGenerator GetWorkgroupSizeFragmentGenerator(spv_target_env env) { + CodeGenerator generator = + env == SPV_ENV_WEBGPU_0 ? CodeGenerator::GetWebGPUShaderCodeGenerator() + : CodeGenerator::GetDefaultShaderCodeGenerator(); + generator.before_types_ = R"( OpDecorate %workgroup_size BuiltIn WorkgroupSize )"; @@ -1673,6 +2278,13 @@ OpDecorate %workgroup_size BuiltIn WorkgroupSize )"; generator.entry_points_.push_back(std::move(entry_point)); + return generator; +} + +TEST_F(ValidateBuiltIns, VulkanWorkgroupSizeFragment) { + CodeGenerator generator = + GetWorkgroupSizeFragmentGenerator(SPV_ENV_VULKAN_1_0); + CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); EXPECT_THAT(getDiagnosticString(), @@ -1684,8 +2296,22 @@ OpDecorate %workgroup_size BuiltIn WorkgroupSize "called with execution model Fragment")); } +TEST_F(ValidateBuiltIns, WebGPUWorkgroupSizeFragment) { + CodeGenerator generator = GetWorkgroupSizeFragmentGenerator(SPV_ENV_WEBGPU_0); + + CompileSuccessfully(generator.Build(), SPV_ENV_WEBGPU_0); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("WebGPU spec allows BuiltIn WorkgroupSize to be used " + "only with GLCompute execution model")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("is referencing ID <2> (OpConstantComposite) which is " + "decorated with BuiltIn WorkgroupSize in function <1> " + "called with execution model Fragment")); +} + TEST_F(ValidateBuiltIns, WorkgroupSizeNotConstant) { - CodeGenerator generator = GetDefaultShaderCodeGenerator(); + CodeGenerator generator = CodeGenerator::GetDefaultShaderCodeGenerator(); generator.before_types_ = R"( OpDecorate %copy BuiltIn WorkgroupSize )"; @@ -1704,13 +2330,16 @@ OpDecorate %copy BuiltIn WorkgroupSize CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("Vulkan spec requires BuiltIn WorkgroupSize to be a " - "constant. ID <2> (OpCopyObject) is not a constant")); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("BuiltIns can only target variables, structs or constants")); } -TEST_F(ValidateBuiltIns, WorkgroupSizeNotVector) { - CodeGenerator generator = GetDefaultShaderCodeGenerator(); +CodeGenerator GetWorkgroupSizeNotVectorGenerator(spv_target_env env) { + CodeGenerator generator = + env == SPV_ENV_WEBGPU_0 ? CodeGenerator::GetWebGPUShaderCodeGenerator() + : CodeGenerator::GetDefaultShaderCodeGenerator(); + generator.before_types_ = R"( OpDecorate %workgroup_size BuiltIn WorkgroupSize )"; @@ -1727,6 +2356,13 @@ OpDecorate %workgroup_size BuiltIn WorkgroupSize )"; generator.entry_points_.push_back(std::move(entry_point)); + return generator; +} + +TEST_F(ValidateBuiltIns, VulkanWorkgroupSizeNotVector) { + CodeGenerator generator = + GetWorkgroupSizeNotVectorGenerator(SPV_ENV_VULKAN_1_0); + CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); EXPECT_THAT(getDiagnosticString(), @@ -1735,8 +2371,23 @@ OpDecorate %workgroup_size BuiltIn WorkgroupSize "ID <2> (OpConstant) is not an int vector.")); } -TEST_F(ValidateBuiltIns, WorkgroupSizeNotIntVector) { - CodeGenerator generator = GetDefaultShaderCodeGenerator(); +TEST_F(ValidateBuiltIns, WebGPUWorkgroupSizeNotVector) { + CodeGenerator generator = + GetWorkgroupSizeNotVectorGenerator(SPV_ENV_WEBGPU_0); + + CompileSuccessfully(generator.Build(), SPV_ENV_WEBGPU_0); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("According to the WebGPU spec BuiltIn WorkgroupSize " + "variable needs to be a 3-component 32-bit int vector. " + "ID <2> (OpConstant) is not an int vector.")); +} + +CodeGenerator GetWorkgroupSizeNotIntVectorGenerator(spv_target_env env) { + CodeGenerator generator = + env == SPV_ENV_WEBGPU_0 ? CodeGenerator::GetWebGPUShaderCodeGenerator() + : CodeGenerator::GetDefaultShaderCodeGenerator(); + generator.before_types_ = R"( OpDecorate %workgroup_size BuiltIn WorkgroupSize )"; @@ -1753,6 +2404,13 @@ OpDecorate %workgroup_size BuiltIn WorkgroupSize )"; generator.entry_points_.push_back(std::move(entry_point)); + return generator; +} + +TEST_F(ValidateBuiltIns, VulkanWorkgroupSizeNotIntVector) { + CodeGenerator generator = + GetWorkgroupSizeNotIntVectorGenerator(SPV_ENV_VULKAN_1_0); + CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); EXPECT_THAT(getDiagnosticString(), @@ -1761,8 +2419,23 @@ OpDecorate %workgroup_size BuiltIn WorkgroupSize "ID <2> (OpConstantComposite) is not an int vector.")); } -TEST_F(ValidateBuiltIns, WorkgroupSizeNotVec3) { - CodeGenerator generator = GetDefaultShaderCodeGenerator(); +TEST_F(ValidateBuiltIns, WebGPUWorkgroupSizeNotIntVector) { + CodeGenerator generator = + GetWorkgroupSizeNotIntVectorGenerator(SPV_ENV_WEBGPU_0); + + CompileSuccessfully(generator.Build(), SPV_ENV_WEBGPU_0); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("According to the WebGPU spec BuiltIn WorkgroupSize " + "variable needs to be a 3-component 32-bit int vector. " + "ID <2> (OpConstantComposite) is not an int vector.")); +} + +CodeGenerator GetWorkgroupSizeNotVec3Generator(spv_target_env env) { + CodeGenerator generator = + env == SPV_ENV_WEBGPU_0 ? CodeGenerator::GetWebGPUShaderCodeGenerator() + : CodeGenerator::GetDefaultShaderCodeGenerator(); + generator.before_types_ = R"( OpDecorate %workgroup_size BuiltIn WorkgroupSize )"; @@ -1779,6 +2452,13 @@ OpDecorate %workgroup_size BuiltIn WorkgroupSize )"; generator.entry_points_.push_back(std::move(entry_point)); + return generator; +} + +TEST_F(ValidateBuiltIns, VulkanWorkgroupSizeNotVec3) { + CodeGenerator generator = + GetWorkgroupSizeNotVec3Generator(SPV_ENV_VULKAN_1_0); + CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); EXPECT_THAT(getDiagnosticString(), @@ -1787,8 +2467,19 @@ OpDecorate %workgroup_size BuiltIn WorkgroupSize "ID <2> (OpConstantComposite) has 2 components.")); } +TEST_F(ValidateBuiltIns, WebGPUWorkgroupSizeNotVec3) { + CodeGenerator generator = GetWorkgroupSizeNotVec3Generator(SPV_ENV_WEBGPU_0); + + CompileSuccessfully(generator.Build(), SPV_ENV_WEBGPU_0); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("According to the WebGPU spec BuiltIn WorkgroupSize " + "variable needs to be a 3-component 32-bit int vector. " + "ID <2> (OpConstantComposite) has 2 components.")); +} + TEST_F(ValidateBuiltIns, WorkgroupSizeNotInt32Vec) { - CodeGenerator generator = GetDefaultShaderCodeGenerator(); + CodeGenerator generator = CodeGenerator::GetDefaultShaderCodeGenerator(); generator.before_types_ = R"( OpDecorate %workgroup_size BuiltIn WorkgroupSize )"; @@ -1815,7 +2506,7 @@ OpDecorate %workgroup_size BuiltIn WorkgroupSize } TEST_F(ValidateBuiltIns, WorkgroupSizePrivateVar) { - CodeGenerator generator = GetDefaultShaderCodeGenerator(); + CodeGenerator generator = CodeGenerator::GetDefaultShaderCodeGenerator(); generator.before_types_ = R"( OpDecorate %workgroup_size BuiltIn WorkgroupSize )"; @@ -1838,7 +2529,7 @@ OpDecorate %workgroup_size BuiltIn WorkgroupSize } TEST_F(ValidateBuiltIns, GeometryPositionInOutSuccess) { - CodeGenerator generator = GetDefaultShaderCodeGenerator(); + CodeGenerator generator = CodeGenerator::GetDefaultShaderCodeGenerator(); generator.before_types_ = R"( OpMemberDecorate %input_type 0 BuiltIn Position @@ -1869,13 +2560,46 @@ OpMemberDecorate %output_type 0 BuiltIn Position OpStore %output_pos %pos )"; generator.entry_points_.push_back(std::move(entry_point)); + generator.entry_points_[0].execution_modes = + "OpExecutionMode %main InputPoints\nOpExecutionMode %main OutputPoints\n"; CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0); ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0)); } +TEST_F(ValidateBuiltIns, WorkgroupIdNotVec3) { + CodeGenerator generator = CodeGenerator::GetDefaultShaderCodeGenerator(); + generator.before_types_ = R"( +OpDecorate %workgroup_size BuiltIn WorkgroupSize +OpDecorate %workgroup_id BuiltIn WorkgroupId +)"; + + generator.after_types_ = R"( +%workgroup_size = OpConstantComposite %u32vec3 %u32_1 %u32_1 %u32_1 + %input_ptr = OpTypePointer Input %u32vec2 + %workgroup_id = OpVariable %input_ptr Input +)"; + + EntryPoint entry_point; + entry_point.name = "main"; + entry_point.execution_model = "GLCompute"; + entry_point.interfaces = "%workgroup_id"; + entry_point.body = R"( +%copy_size = OpCopyObject %u32vec3 %workgroup_size + %load_id = OpLoad %u32vec2 %workgroup_id +)"; + generator.entry_points_.push_back(std::move(entry_point)); + + CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("According to the Vulkan spec BuiltIn WorkgroupId " + "variable needs to be a 3-component 32-bit int vector. " + "ID <2> (OpVariable) has 2 components.")); +} + TEST_F(ValidateBuiltIns, TwoBuiltInsFirstFails) { - CodeGenerator generator = GetDefaultShaderCodeGenerator(); + CodeGenerator generator = CodeGenerator::GetDefaultShaderCodeGenerator(); generator.before_types_ = R"( OpMemberDecorate %input_type 0 BuiltIn FragCoord @@ -1904,6 +2628,8 @@ OpMemberDecorate %output_type 0 BuiltIn Position OpStore %output_pos %pos )"; generator.entry_points_.push_back(std::move(entry_point)); + generator.entry_points_[0].execution_modes = + "OpExecutionMode %main InputPoints\nOpExecutionMode %main OutputPoints\n"; CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); @@ -1913,7 +2639,7 @@ OpStore %output_pos %pos } TEST_F(ValidateBuiltIns, TwoBuiltInsSecondFails) { - CodeGenerator generator = GetDefaultShaderCodeGenerator(); + CodeGenerator generator = CodeGenerator::GetDefaultShaderCodeGenerator(); generator.before_types_ = R"( OpMemberDecorate %input_type 0 BuiltIn Position @@ -1942,6 +2668,8 @@ OpMemberDecorate %output_type 0 BuiltIn FragCoord OpStore %output_pos %pos )"; generator.entry_points_.push_back(std::move(entry_point)); + generator.entry_points_[0].execution_modes = + "OpExecutionMode %main InputPoints\nOpExecutionMode %main OutputPoints\n"; CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); @@ -1951,7 +2679,7 @@ OpStore %output_pos %pos } TEST_F(ValidateBuiltIns, VertexPositionVariableSuccess) { - CodeGenerator generator = GetDefaultShaderCodeGenerator(); + CodeGenerator generator = CodeGenerator::GetDefaultShaderCodeGenerator(); generator.before_types_ = R"( OpDecorate %position BuiltIn Position )"; @@ -1975,7 +2703,7 @@ OpStore %position %f32vec4_0123 } TEST_F(ValidateBuiltIns, FragmentPositionTwoEntryPoints) { - CodeGenerator generator = GetDefaultShaderCodeGenerator(); + CodeGenerator generator = CodeGenerator::GetDefaultShaderCodeGenerator(); generator.before_types_ = R"( OpMemberDecorate %output_type 0 BuiltIn Position )"; @@ -2024,16 +2752,20 @@ OpFunctionEnd HasSubstr("called with execution model Fragment")); } -TEST_F(ValidateBuiltIns, FragmentFragDepthNoDepthReplacing) { - CodeGenerator generator = GetDefaultShaderCodeGenerator(); +CodeGenerator GetNoDepthReplacingGenerator(spv_target_env env) { + CodeGenerator generator = + spvIsWebGPUEnv(env) ? CodeGenerator::GetWebGPUShaderCodeGenerator() + : CodeGenerator::GetDefaultShaderCodeGenerator(); + generator.before_types_ = R"( OpMemberDecorate %output_type 0 BuiltIn FragDepth )"; generator.after_types_ = R"( %output_type = OpTypeStruct %f32 +%output_null = OpConstantNull %output_type %output_ptr = OpTypePointer Output %output_type -%output = OpVariable %output_ptr Output +%output = OpVariable %output_ptr Output %output_null %output_f32_ptr = OpTypePointer Output %f32 )"; @@ -2047,7 +2779,7 @@ OpMemberDecorate %output_type 0 BuiltIn FragDepth )"; generator.entry_points_.push_back(std::move(entry_point)); - generator.add_at_the_end_ = R"( + const std::string function_body = R"( %foo = OpFunction %void None %func %foo_entry = OpLabel %frag_depth = OpAccessChain %output_f32_ptr %output %u32_0 @@ -2056,6 +2788,18 @@ OpReturn OpFunctionEnd )"; + if (spvIsWebGPUEnv(env)) { + generator.after_types_ += function_body; + } else { + generator.add_at_the_end_ = function_body; + } + + return generator; +} + +TEST_F(ValidateBuiltIns, VulkanFragmentFragDepthNoDepthReplacing) { + CodeGenerator generator = GetNoDepthReplacingGenerator(SPV_ENV_VULKAN_1_0); + CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); EXPECT_THAT(getDiagnosticString(), @@ -2063,16 +2807,31 @@ OpFunctionEnd "be declared when using BuiltIn FragDepth")); } -TEST_F(ValidateBuiltIns, FragmentFragDepthOneMainHasDepthReplacingOtherHasnt) { - CodeGenerator generator = GetDefaultShaderCodeGenerator(); +TEST_F(ValidateBuiltIns, WebGPUFragmentFragDepthNoDepthReplacing) { + CodeGenerator generator = GetNoDepthReplacingGenerator(SPV_ENV_WEBGPU_0); + + CompileSuccessfully(generator.Build(), SPV_ENV_WEBGPU_0); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("WebGPU spec requires DepthReplacing execution mode to " + "be declared when using BuiltIn FragDepth")); +} + +CodeGenerator GetOneMainHasDepthReplacingOtherHasntGenerator( + spv_target_env env) { + CodeGenerator generator = + spvIsWebGPUEnv(env) ? CodeGenerator::GetWebGPUShaderCodeGenerator() + : CodeGenerator::GetDefaultShaderCodeGenerator(); + generator.before_types_ = R"( OpMemberDecorate %output_type 0 BuiltIn FragDepth )"; generator.after_types_ = R"( %output_type = OpTypeStruct %f32 +%output_null = OpConstantNull %output_type %output_ptr = OpTypePointer Output %output_type -%output = OpVariable %output_ptr Output +%output = OpVariable %output_ptr Output %output_null %output_f32_ptr = OpTypePointer Output %f32 )"; @@ -2097,7 +2856,7 @@ OpMemberDecorate %output_type 0 BuiltIn FragDepth )"; generator.entry_points_.push_back(std::move(entry_point)); - generator.add_at_the_end_ = R"( + const std::string function_body = R"( %foo = OpFunction %void None %func %foo_entry = OpLabel %frag_depth = OpAccessChain %output_f32_ptr %output %u32_0 @@ -2106,6 +2865,20 @@ OpReturn OpFunctionEnd )"; + if (spvIsWebGPUEnv(env)) { + generator.after_types_ += function_body; + } else { + generator.add_at_the_end_ = function_body; + } + + return generator; +} + +TEST_F(ValidateBuiltIns, + VulkanFragmentFragDepthOneMainHasDepthReplacingOtherHasnt) { + CodeGenerator generator = + GetOneMainHasDepthReplacingOtherHasntGenerator(SPV_ENV_VULKAN_1_0); + CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); EXPECT_THAT(getDiagnosticString(), @@ -2113,6 +2886,494 @@ OpFunctionEnd "be declared when using BuiltIn FragDepth")); } +TEST_F(ValidateBuiltIns, + WebGPUFragmentFragDepthOneMainHasDepthReplacingOtherHasnt) { + CodeGenerator generator = + GetOneMainHasDepthReplacingOtherHasntGenerator(SPV_ENV_WEBGPU_0); + + CompileSuccessfully(generator.Build(), SPV_ENV_WEBGPU_0); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("WebGPU spec requires DepthReplacing execution mode to " + "be declared when using BuiltIn FragDepth")); +} + +TEST_F(ValidateBuiltIns, AllowInstanceIdWithIntersectionShader) { + CodeGenerator generator = CodeGenerator::GetDefaultShaderCodeGenerator(); + generator.capabilities_ += R"( +OpCapability RayTracingNV +)"; + + generator.extensions_ = R"( +OpExtension "SPV_NV_ray_tracing" +)"; + + generator.before_types_ = R"( +OpMemberDecorate %input_type 0 BuiltIn InstanceId +)"; + + generator.after_types_ = R"( +%input_type = OpTypeStruct %u32 +%input_ptr = OpTypePointer Input %input_type +%input = OpVariable %input_ptr Input +)"; + + EntryPoint entry_point; + entry_point.name = "main_d_r"; + entry_point.execution_model = "IntersectionNV"; + entry_point.interfaces = "%input"; + entry_point.body = R"( +%val2 = OpFunctionCall %void %foo +)"; + generator.entry_points_.push_back(std::move(entry_point)); + + generator.add_at_the_end_ = R"( +%foo = OpFunction %void None %func +%foo_entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0); + EXPECT_THAT(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0)); +} + +TEST_F(ValidateBuiltIns, DisallowInstanceIdWithRayGenShader) { + CodeGenerator generator = CodeGenerator::GetDefaultShaderCodeGenerator(); + generator.capabilities_ += R"( +OpCapability RayTracingNV +)"; + + generator.extensions_ = R"( +OpExtension "SPV_NV_ray_tracing" +)"; + + generator.before_types_ = R"( +OpMemberDecorate %input_type 0 BuiltIn InstanceId +)"; + + generator.after_types_ = R"( +%input_type = OpTypeStruct %u32 +%input_ptr = OpTypePointer Input %input_type +%input_ptr_u32 = OpTypePointer Input %u32 +%input = OpVariable %input_ptr Input +)"; + + EntryPoint entry_point; + entry_point.name = "main_d_r"; + entry_point.execution_model = "RayGenerationNV"; + entry_point.interfaces = "%input"; + entry_point.body = R"( +%input_member = OpAccessChain %input_ptr_u32 %input %u32_0 +)"; + generator.entry_points_.push_back(std::move(entry_point)); + + CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Vulkan spec allows BuiltIn InstanceId to be used " + "only with IntersectionNV, ClosestHitNV and " + "AnyHitNV execution models")); +} + +TEST_F(ValidateBuiltIns, ValidBuiltinsForMeshShader) { + CodeGenerator generator = CodeGenerator::GetDefaultShaderCodeGenerator(); + generator.capabilities_ += R"( +OpCapability MeshShadingNV +)"; + + generator.extensions_ = R"( +OpExtension "SPV_NV_mesh_shader" +)"; + + generator.before_types_ = R"( +OpDecorate %gl_PrimitiveID BuiltIn PrimitiveId +OpDecorate %gl_PrimitiveID PerPrimitiveNV +OpDecorate %gl_Layer BuiltIn Layer +OpDecorate %gl_Layer PerPrimitiveNV +OpDecorate %gl_ViewportIndex BuiltIn ViewportIndex +OpDecorate %gl_ViewportIndex PerPrimitiveNV +)"; + + generator.after_types_ = R"( +%u32_81 = OpConstant %u32 81 +%_arr_int_uint_81 = OpTypeArray %i32 %u32_81 +%_ptr_Output__arr_int_uint_81 = OpTypePointer Output %_arr_int_uint_81 +%gl_PrimitiveID = OpVariable %_ptr_Output__arr_int_uint_81 Output +%gl_Layer = OpVariable %_ptr_Output__arr_int_uint_81 Output +%gl_ViewportIndex = OpVariable %_ptr_Output__arr_int_uint_81 Output +)"; + + EntryPoint entry_point; + entry_point.name = "main_d_r"; + entry_point.execution_model = "MeshNV"; + entry_point.interfaces = "%gl_PrimitiveID %gl_Layer %gl_ViewportIndex"; + generator.entry_points_.push_back(std::move(entry_point)); + + CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_1); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1)); +} + +TEST_F(ValidateBuiltIns, InvalidBuiltinsForMeshShader) { + CodeGenerator generator = CodeGenerator::GetDefaultShaderCodeGenerator(); + generator.capabilities_ += R"( +OpCapability MeshShadingNV +)"; + + generator.extensions_ = R"( +OpExtension "SPV_NV_mesh_shader" +)"; + + generator.before_types_ = R"( +OpDecorate %gl_PrimitiveID BuiltIn PrimitiveId +OpDecorate %gl_PrimitiveID PerPrimitiveNV +OpDecorate %gl_Layer BuiltIn Layer +OpDecorate %gl_Layer PerPrimitiveNV +OpDecorate %gl_ViewportIndex BuiltIn ViewportIndex +OpDecorate %gl_ViewportIndex PerPrimitiveNV +)"; + + generator.after_types_ = R"( +%u32_81 = OpConstant %u32 81 +%_arr_float_uint_81 = OpTypeArray %f32 %u32_81 +%_ptr_Output__arr_float_uint_81 = OpTypePointer Output %_arr_float_uint_81 +%gl_PrimitiveID = OpVariable %_ptr_Output__arr_float_uint_81 Output +%gl_Layer = OpVariable %_ptr_Output__arr_float_uint_81 Output +%gl_ViewportIndex = OpVariable %_ptr_Output__arr_float_uint_81 Output +)"; + + EntryPoint entry_point; + entry_point.name = "main_d_r"; + entry_point.execution_model = "MeshNV"; + entry_point.interfaces = "%gl_PrimitiveID %gl_Layer %gl_ViewportIndex"; + generator.entry_points_.push_back(std::move(entry_point)); + + CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_1); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("needs to be a 32-bit int scalar")); + EXPECT_THAT(getDiagnosticString(), HasSubstr("is not an int scalar")); +} + +TEST_F(ValidateBuiltIns, GetUnderlyingTypeNoAssert) { + std::string spirv = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "PSMa" %12 %17 + OpExecutionMode %4 OriginUpperLeft + OpDecorate %gl_PointCoord BuiltIn PointCoord + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 + %gl_PointCoord = OpTypeStruct %v4float + %_ptr_Input_v4float = OpTypePointer Input %v4float + %_ptr_Output_v4float = OpTypePointer Output %v4float + %12 = OpVariable %_ptr_Input_v4float Input + %17 = OpVariable %_ptr_Output_v4float Output + %4 = OpFunction %void None %3 + %15 = OpLabel + OpReturn + OpFunctionEnd)"; + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("did not find an member index to get underlying data " + "type")); +} + +TEST_P(ValidateVulkanSubgroupBuiltIns, InMain) { + const char* const built_in = std::get<0>(GetParam()); + const char* const execution_model = std::get<1>(GetParam()); + const char* const storage_class = std::get<2>(GetParam()); + const char* const data_type = std::get<3>(GetParam()); + const TestResult& test_result = std::get<4>(GetParam()); + + CodeGenerator generator = CodeGenerator::GetDefaultShaderCodeGenerator(); + generator.capabilities_ += R"( +OpCapability GroupNonUniformBallot +)"; + + generator.before_types_ = "OpDecorate %built_in_var BuiltIn "; + generator.before_types_ += built_in; + generator.before_types_ += "\n"; + + std::ostringstream after_types; + after_types << "%built_in_ptr = OpTypePointer " << storage_class << " " + << data_type << "\n"; + after_types << "%built_in_var = OpVariable %built_in_ptr " << storage_class; + after_types << "\n"; + generator.after_types_ = after_types.str(); + + EntryPoint entry_point; + entry_point.name = "main"; + entry_point.execution_model = execution_model; + if (strncmp(storage_class, "Input", 5) == 0 || + strncmp(storage_class, "Output", 6) == 0) { + entry_point.interfaces = "%built_in_var"; + } + entry_point.body = + std::string("%ld = OpLoad ") + data_type + " %built_in_var\n"; + + std::ostringstream execution_modes; + if (0 == std::strcmp(execution_model, "Fragment")) { + execution_modes << "OpExecutionMode %" << entry_point.name + << " OriginUpperLeft\n"; + if (0 == std::strcmp(built_in, "FragDepth")) { + execution_modes << "OpExecutionMode %" << entry_point.name + << " DepthReplacing\n"; + } + } + if (0 == std::strcmp(execution_model, "Geometry")) { + execution_modes << "OpExecutionMode %" << entry_point.name + << " InputPoints\n"; + execution_modes << "OpExecutionMode %" << entry_point.name + << " OutputPoints\n"; + } + if (0 == std::strcmp(execution_model, "GLCompute")) { + execution_modes << "OpExecutionMode %" << entry_point.name + << " LocalSize 1 1 1\n"; + } + entry_point.execution_modes = execution_modes.str(); + + generator.entry_points_.push_back(std::move(entry_point)); + + CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_1); + ASSERT_EQ(test_result.validation_result, + ValidateInstructions(SPV_ENV_VULKAN_1_1)); + if (test_result.error_str) { + EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str)); + } + if (test_result.error_str2) { + EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str2)); + } +} + +INSTANTIATE_TEST_SUITE_P( + SubgroupMaskNotVec4, ValidateVulkanSubgroupBuiltIns, + Combine(Values("SubgroupEqMask", "SubgroupGeMask", "SubgroupGtMask", + "SubgroupLeMask", "SubgroupLtMask"), + Values("GLCompute"), Values("Input"), Values("%u32vec3"), + Values(TestResult(SPV_ERROR_INVALID_DATA, + "needs to be a 4-component 32-bit int vector")))); + +INSTANTIATE_TEST_SUITE_P( + SubgroupMaskNotU32, ValidateVulkanSubgroupBuiltIns, + Combine(Values("SubgroupEqMask", "SubgroupGeMask", "SubgroupGtMask", + "SubgroupLeMask", "SubgroupLtMask"), + Values("GLCompute"), Values("Input"), Values("%f32vec4"), + Values(TestResult(SPV_ERROR_INVALID_DATA, + "needs to be a 4-component 32-bit int vector")))); + +INSTANTIATE_TEST_SUITE_P( + SubgroupMaskNotInput, ValidateVulkanSubgroupBuiltIns, + Combine(Values("SubgroupEqMask", "SubgroupGeMask", "SubgroupGtMask", + "SubgroupLeMask", "SubgroupLtMask"), + Values("GLCompute"), Values("Output", "Workgroup", "Private"), + Values("%u32vec4"), + Values(TestResult( + SPV_ERROR_INVALID_DATA, + "to be only used for variables with Input storage class")))); + +INSTANTIATE_TEST_SUITE_P(SubgroupMaskOk, ValidateVulkanSubgroupBuiltIns, + Combine(Values("SubgroupEqMask", "SubgroupGeMask", + "SubgroupGtMask", "SubgroupLeMask", + "SubgroupLtMask"), + Values("GLCompute"), Values("Input"), + Values("%u32vec4"), + Values(TestResult(SPV_SUCCESS, "")))); + +TEST_F(ValidateBuiltIns, SubgroupMaskMemberDecorate) { + const std::string text = R"( +OpCapability Shader +OpCapability GroupNonUniformBallot +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %foo "foo" +OpExecutionMode %foo LocalSize 1 1 1 +OpMemberDecorate %struct 0 BuiltIn SubgroupEqMask +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%struct = OpTypeStruct %int +%void_fn = OpTypeFunction %void +%foo = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text, SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "BuiltIn SubgroupEqMask cannot be used as a member decoration")); +} + +INSTANTIATE_TEST_SUITE_P( + SubgroupInvocationIdAndSizeNotU32, ValidateVulkanSubgroupBuiltIns, + Combine(Values("SubgroupLocalInvocationId", "SubgroupSize"), + Values("GLCompute"), Values("Input"), Values("%f32"), + Values(TestResult(SPV_ERROR_INVALID_DATA, + "needs to be a 32-bit int")))); + +INSTANTIATE_TEST_SUITE_P( + SubgroupInvocationIdAndSizeNotInput, ValidateVulkanSubgroupBuiltIns, + Combine(Values("SubgroupLocalInvocationId", "SubgroupSize"), + Values("GLCompute"), Values("Output", "Workgroup", "Private"), + Values("%u32"), + Values(TestResult( + SPV_ERROR_INVALID_DATA, + "to be only used for variables with Input storage class")))); + +INSTANTIATE_TEST_SUITE_P( + SubgroupInvocationIdAndSizeOk, ValidateVulkanSubgroupBuiltIns, + Combine(Values("SubgroupLocalInvocationId", "SubgroupSize"), + Values("GLCompute"), Values("Input"), Values("%u32"), + Values(TestResult(SPV_SUCCESS, "")))); + +TEST_F(ValidateBuiltIns, SubgroupSizeMemberDecorate) { + const std::string text = R"( +OpCapability Shader +OpCapability GroupNonUniform +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %foo "foo" +OpExecutionMode %foo LocalSize 1 1 1 +OpMemberDecorate %struct 0 BuiltIn SubgroupSize +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%struct = OpTypeStruct %int +%void_fn = OpTypeFunction %void +%foo = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text, SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("BuiltIn SubgroupSize cannot be used as a member decoration")); +} + +INSTANTIATE_TEST_SUITE_P( + SubgroupNumAndIdNotU32, ValidateVulkanSubgroupBuiltIns, + Combine(Values("SubgroupId", "NumSubgroups"), Values("GLCompute"), + Values("Input"), Values("%f32"), + Values(TestResult(SPV_ERROR_INVALID_DATA, + "needs to be a 32-bit int")))); + +INSTANTIATE_TEST_SUITE_P( + SubgroupNumAndIdNotInput, ValidateVulkanSubgroupBuiltIns, + Combine(Values("SubgroupId", "NumSubgroups"), Values("GLCompute"), + Values("Output", "Workgroup", "Private"), Values("%u32"), + Values(TestResult( + SPV_ERROR_INVALID_DATA, + "to be only used for variables with Input storage class")))); + +INSTANTIATE_TEST_SUITE_P(SubgroupNumAndIdOk, ValidateVulkanSubgroupBuiltIns, + Combine(Values("SubgroupId", "NumSubgroups"), + Values("GLCompute"), Values("Input"), + Values("%u32"), + Values(TestResult(SPV_SUCCESS, "")))); + +TEST_F(ValidateBuiltIns, SubgroupIdMemberDecorate) { + const std::string text = R"( +OpCapability Shader +OpCapability GroupNonUniform +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %foo "foo" +OpExecutionMode %foo LocalSize 1 1 1 +OpMemberDecorate %struct 0 BuiltIn SubgroupId +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%struct = OpTypeStruct %int +%void_fn = OpTypeFunction %void +%foo = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text, SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("BuiltIn SubgroupId cannot be used as a member decoration")); +} + +TEST_F(ValidateBuiltIns, TargetIsType) { + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpDecorate %void BuiltIn Position +%void = OpTypeVoid +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("BuiltIns can only target variables, structs or constants")); +} + +TEST_F(ValidateBuiltIns, TargetIsVariable) { + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpDecorate %wg_var BuiltIn Position +%int = OpTypeInt 32 0 +%int_wg_ptr = OpTypePointer Workgroup %int +%wg_var = OpVariable %int_wg_ptr Workgroup +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateBuiltIns, TargetIsStruct) { + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpDecorate %struct BuiltIn Position +%struct = OpTypeStruct +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateBuiltIns, TargetIsConstant) { + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpDecorate %int0 BuiltIn Position +%int = OpTypeInt 32 0 +%int0 = OpConstant %int 0 +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateBuiltIns, TargetIsSpecConstant) { + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpDecorate %int0 BuiltIn Position +%int = OpTypeInt 32 0 +%int0 = OpSpecConstant %int 0 +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + } // namespace } // namespace val } // namespace spvtools diff --git a/third_party/spirv-tools/test/val/val_capability_test.cpp b/third_party/spirv-tools/test/val/val_capability_test.cpp index 2ee7133cd6..098fa2f97f 100644 --- a/third_party/spirv-tools/test/val/val_capability_test.cpp +++ b/third_party/spirv-tools/test/val/val_capability_test.cpp @@ -23,6 +23,7 @@ #include "gmock/gmock.h" #include "source/assembly_grammar.h" #include "source/spirv_target_env.h" +#include "spirv-tools/libspirv.h" #include "test/test_fixture.h" #include "test/unit_spirv.h" #include "test/val/val_fixtures.h" @@ -33,6 +34,7 @@ namespace { using spvtest::ScopedContext; using testing::Combine; +using testing::Eq; using testing::HasSubstr; using testing::Values; using testing::ValuesIn; @@ -112,6 +114,10 @@ using ValidateCapabilityVulkan10 = spvtest::ValidateBase; using ValidateCapabilityOpenGL40 = spvtest::ValidateBase; // Always assembles using Vulkan 1.1. using ValidateCapabilityVulkan11 = spvtest::ValidateBase; +// Always assembles using Vulkan 1.2. +using ValidateCapabilityVulkan12 = spvtest::ValidateBase; +// Always assembles using WebGPU. +using ValidateCapabilityWebGPU = spvtest::ValidateBase; TEST_F(ValidateCapability, Default) { const char str[] = R"( @@ -213,6 +219,114 @@ const std::vector& AllCapabilities() { return *r; } +const std::vector& AllSpirV15Capabilities() { + static const auto r = new std::vector{ + "", + "Matrix", + "Shader", + "Geometry", + "Tessellation", + "Addresses", + "Linkage", + "Kernel", + "Vector16", + "Float16Buffer", + "Float16", + "Float64", + "Int64", + "Int64Atomics", + "ImageBasic", + "ImageReadWrite", + "ImageMipmap", + "Pipes", + "Groups", + "DeviceEnqueue", + "LiteralSampler", + "AtomicStorage", + "Int16", + "TessellationPointSize", + "GeometryPointSize", + "ImageGatherExtended", + "StorageImageMultisample", + "UniformBufferArrayDynamicIndexing", + "SampledImageArrayDynamicIndexing", + "StorageBufferArrayDynamicIndexing", + "StorageImageArrayDynamicIndexing", + "ClipDistance", + "CullDistance", + "ImageCubeArray", + "SampleRateShading", + "ImageRect", + "SampledRect", + "GenericPointer", + "Int8", + "InputAttachment", + "SparseResidency", + "MinLod", + "Sampled1D", + "Image1D", + "SampledCubeArray", + "SampledBuffer", + "ImageBuffer", + "ImageMSArray", + "StorageImageExtendedFormats", + "ImageQuery", + "DerivativeControl", + "InterpolationFunction", + "TransformFeedback", + "GeometryStreams", + "StorageImageReadWithoutFormat", + "StorageImageWriteWithoutFormat", + "MultiViewport", + "SubgroupDispatch", + "NamedBarrier", + "PipeStorage", + "GroupNonUniform", + "GroupNonUniformVote", + "GroupNonUniformArithmetic", + "GroupNonUniformBallot", + "GroupNonUniformShuffle", + "GroupNonUniformShuffleRelative", + "GroupNonUniformClustered", + "GroupNonUniformQuad", + "DrawParameters", + "StorageBuffer16BitAccess", + "StorageUniformBufferBlock16", + "UniformAndStorageBuffer16BitAccess", + "StorageUniform16", + "StoragePushConstant16", + "StorageInputOutput16", + "DeviceGroup", + "MultiView", + "VariablePointersStorageBuffer", + "VariablePointers", + "DenormPreserve", + "DenormFlushToZero", + "SignedZeroInfNanPreserve", + "RoundingModeRTE", + "RoundingModeRTZ", + // Omitted due to extra validation requirements on memory model. + //"VulkanMemoryModel", + //"VulkanMemoryModelDeviceScope", + "StorageBuffer8BitAccess", + "UniformAndStorageBuffer8BitAccess", + "StoragePushConstant8", + "ShaderViewportIndex", + "ShaderLayer", + "PhysicalStorageBufferAddresses", + "RuntimeDescriptorArray", + "UniformTexelBufferArrayDynamicIndexing", + "StorageTexelBufferArrayDynamicIndexing", + "UniformBufferArrayNonUniformIndexing", + "SampledImageArrayNonUniformIndexing", + "StorageBufferArrayNonUniformIndexing", + "StorageImageArrayNonUniformIndexing", + "InputAttachmentArrayNonUniformIndexing", + "UniformTexelBufferArrayNonUniformIndexing", + "StorageTexelBufferArrayNonUniformIndexing"}; + return *r; +} + const std::vector& AllSpirV10Capabilities() { static const auto r = new std::vector{ "", @@ -289,8 +403,10 @@ const std::vector& AllVulkan10Capabilities() { "DerivativeControl", "Geometry", "Tessellation", + "Float16", "Float64", "Int64", + "Int64Atomics", "Int16", "TessellationPointSize", "GeometryPointSize", @@ -304,6 +420,7 @@ const std::vector& AllVulkan10Capabilities() { "CullDistance", "ImageCubeArray", "SampleRateShading", + "Int8", "SparseResidency", "MinLod", "SampledCubeArray", @@ -312,7 +429,9 @@ const std::vector& AllVulkan10Capabilities() { "InterpolationFunction", "StorageImageReadWithoutFormat", "StorageImageWriteWithoutFormat", - "MultiViewport"}; + "MultiViewport", + "TransformFeedback", + "GeometryStreams"}; return *r; } @@ -330,8 +449,10 @@ const std::vector& AllVulkan11Capabilities() { "DerivativeControl", "Geometry", "Tessellation", + "Float16", "Float64", "Int64", + "Int64Atomics", "Int16", "TessellationPointSize", "GeometryPointSize", @@ -345,6 +466,7 @@ const std::vector& AllVulkan11Capabilities() { "CullDistance", "ImageCubeArray", "SampleRateShading", + "Int8", "SparseResidency", "MinLod", "SampledCubeArray", @@ -372,10 +494,112 @@ const std::vector& AllVulkan11Capabilities() { "DeviceGroup", "MultiView", "VariablePointersStorageBuffer", - "VariablePointers"}; + "VariablePointers", + "TransformFeedback", + "GeometryStreams"}; return *r; } +const std::vector& AllVulkan12Capabilities() { + static const auto r = new std::vector{ + "", + "Matrix", + "Shader", + "InputAttachment", + "Sampled1D", + "Image1D", + "SampledBuffer", + "ImageBuffer", + "ImageQuery", + "DerivativeControl", + "Geometry", + "Tessellation", + "Float16", + "Float64", + "Int64", + "Int64Atomics", + "Int16", + "TessellationPointSize", + "GeometryPointSize", + "ImageGatherExtended", + "StorageImageMultisample", + "UniformBufferArrayDynamicIndexing", + "SampledImageArrayDynamicIndexing", + "StorageBufferArrayDynamicIndexing", + "StorageImageArrayDynamicIndexing", + "ClipDistance", + "CullDistance", + "ImageCubeArray", + "SampleRateShading", + "Int8", + "SparseResidency", + "MinLod", + "SampledCubeArray", + "ImageMSArray", + "StorageImageExtendedFormats", + "InterpolationFunction", + "StorageImageReadWithoutFormat", + "StorageImageWriteWithoutFormat", + "MultiViewport", + "GroupNonUniform", + "GroupNonUniformVote", + "GroupNonUniformArithmetic", + "GroupNonUniformBallot", + "GroupNonUniformShuffle", + "GroupNonUniformShuffleRelative", + "GroupNonUniformClustered", + "GroupNonUniformQuad", + "DrawParameters", + "StorageBuffer16BitAccess", + "StorageUniformBufferBlock16", + "UniformAndStorageBuffer16BitAccess", + "StorageUniform16", + "StoragePushConstant16", + "StorageInputOutput16", + "DeviceGroup", + "MultiView", + "VariablePointersStorageBuffer", + "VariablePointers", + "TransformFeedback", + "GeometryStreams", + "DenormPreserve", + "DenormFlushToZero", + "SignedZeroInfNanPreserve", + "RoundingModeRTE", + "RoundingModeRTZ", + "VulkanMemoryModel", + "VulkanMemoryModelDeviceScope", + "StorageBuffer8BitAccess", + "UniformAndStorageBuffer8BitAccess", + "StoragePushConstant8", + "ShaderViewportIndex", + "ShaderLayer", + "PhysicalStorageBufferAddresses", + "RuntimeDescriptorArray", + "UniformTexelBufferArrayDynamicIndexing", + "StorageTexelBufferArrayDynamicIndexing", + "UniformBufferArrayNonUniformIndexing", + "SampledImageArrayNonUniformIndexing", + "StorageBufferArrayNonUniformIndexing", + "StorageImageArrayNonUniformIndexing", + "InputAttachmentArrayNonUniformIndexing", + "UniformTexelBufferArrayNonUniformIndexing", + "StorageTexelBufferArrayNonUniformIndexing"}; + return *r; +} + +const std::vector& AllWebGPUCapabilities() { + static const auto r = new std::vector{ + "", + "Shader", + "Matrix", + "Sampled1D", + "Image1D", + "ImageQuery", + "DerivativeControl"}; + return *r; +} + const std::vector& MatrixDependencies() { static const auto r = new std::vector{ "Matrix", @@ -566,6 +790,12 @@ const char kGLSL450MemoryModel[] = \ " OpCapability Shader" " OpMemoryModel Logical GLSL450 "; +const char kVulkanMemoryModel[] = \ + " OpCapability Shader" + " OpCapability VulkanMemoryModelKHR" + " OpExtension \"SPV_KHR_vulkan_memory_model\"" + " OpMemoryModel Logical VulkanKHR "; + const char kVoidFVoid[] = \ " %void = OpTypeVoid" " %void_f = OpTypeFunction %void" @@ -581,7 +811,7 @@ const char kVoidFVoid2[] = \ " OpReturn" " OpFunctionEnd "; -INSTANTIATE_TEST_CASE_P(ExecutionModel, ValidateCapability, +INSTANTIATE_TEST_SUITE_P(ExecutionModel, ValidateCapability, Combine( ValuesIn(AllCapabilities()), Values( @@ -596,9 +826,12 @@ std::make_pair(std::string(kOpenCLMemoryModel) + std::string(kVoidFVoid), TessellationDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + " OpEntryPoint Geometry %func \"shader\"" + + " OpExecutionMode %func InputPoints" + + " OpExecutionMode %func OutputPoints" + std::string(kVoidFVoid), GeometryDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + " OpEntryPoint Fragment %func \"shader\"" + + " OpExecutionMode %func OriginUpperLeft" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + " OpEntryPoint GLCompute %func \"shader\"" + @@ -606,9 +839,9 @@ std::make_pair(std::string(kOpenCLMemoryModel) + std::make_pair(std::string(kGLSL450MemoryModel) + " OpEntryPoint Kernel %func \"shader\"" + std::string(kVoidFVoid), KernelDependencies()) -)),); +))); -INSTANTIATE_TEST_CASE_P(AddressingAndMemoryModel, ValidateCapability, +INSTANTIATE_TEST_SUITE_P(AddressingAndMemoryModel, ValidateCapability, Combine( ValuesIn(AllCapabilities()), Values( @@ -648,15 +881,17 @@ std::make_pair(" OpCapability Kernel" " OpMemoryModel Physical64 OpenCL" " OpEntryPoint Kernel %func \"compute\"" + std::string(kVoidFVoid), AddressesDependencies()) -)),); +))); -INSTANTIATE_TEST_CASE_P(ExecutionMode, ValidateCapability, +INSTANTIATE_TEST_SUITE_P(ExecutionMode, ValidateCapability, Combine( ValuesIn(AllCapabilities()), Values( std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Geometry %func \"shader\" " "OpExecutionMode %func Invocations 42" + + " OpExecutionMode %func InputPoints" + + " OpExecutionMode %func OutputPoints" + std::string(kVoidFVoid), GeometryDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint TessellationControl %func \"shader\" " @@ -679,20 +914,22 @@ std::make_pair(std::string(kOpenCLMemoryModel) + "OpExecutionMode %func VertexOrderCcw" + std::string(kVoidFVoid), TessellationDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + - "OpEntryPoint Vertex %func \"shader\" " + "OpEntryPoint Fragment %func \"shader\" " "OpExecutionMode %func PixelCenterInteger" + + " OpExecutionMode %func OriginUpperLeft" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + - "OpEntryPoint Vertex %func \"shader\" " + "OpEntryPoint Fragment %func \"shader\" " "OpExecutionMode %func OriginUpperLeft" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + - "OpEntryPoint Vertex %func \"shader\" " + "OpEntryPoint Fragment %func \"shader\" " "OpExecutionMode %func OriginLowerLeft" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + - "OpEntryPoint Vertex %func \"shader\" " + "OpEntryPoint Fragment %func \"shader\" " "OpExecutionMode %func EarlyFragmentTests" + + " OpExecutionMode %func OriginUpperLeft" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint TessellationControl %func \"shader\" " @@ -703,20 +940,24 @@ std::make_pair(std::string(kOpenCLMemoryModel) + "OpExecutionMode %func Xfb" + std::string(kVoidFVoid), std::vector{"TransformFeedback"}), std::make_pair(std::string(kOpenCLMemoryModel) + - "OpEntryPoint Vertex %func \"shader\" " + "OpEntryPoint Fragment %func \"shader\" " "OpExecutionMode %func DepthReplacing" + + " OpExecutionMode %func OriginUpperLeft" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + - "OpEntryPoint Vertex %func \"shader\" " + "OpEntryPoint Fragment %func \"shader\" " "OpExecutionMode %func DepthGreater" + + " OpExecutionMode %func OriginUpperLeft" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + - "OpEntryPoint Vertex %func \"shader\" " + "OpEntryPoint Fragment %func \"shader\" " "OpExecutionMode %func DepthLess" + + " OpExecutionMode %func OriginUpperLeft" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + - "OpEntryPoint Vertex %func \"shader\" " + "OpEntryPoint Fragment %func \"shader\" " "OpExecutionMode %func DepthUnchanged" + + " OpExecutionMode %func OriginUpperLeft" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"shader\" " @@ -729,18 +970,22 @@ std::make_pair(std::string(kGLSL450MemoryModel) + std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Geometry %func \"shader\" " "OpExecutionMode %func InputPoints" + + " OpExecutionMode %func OutputPoints" + std::string(kVoidFVoid), GeometryDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Geometry %func \"shader\" " "OpExecutionMode %func InputLines" + + " OpExecutionMode %func OutputLineStrip" + std::string(kVoidFVoid), GeometryDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Geometry %func \"shader\" " "OpExecutionMode %func InputLinesAdjacency" + + " OpExecutionMode %func OutputLineStrip" + std::string(kVoidFVoid), GeometryDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Geometry %func \"shader\" " "OpExecutionMode %func Triangles" + + " OpExecutionMode %func OutputTriangleStrip" + std::string(kVoidFVoid), GeometryDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint TessellationControl %func \"shader\" " @@ -749,6 +994,7 @@ std::make_pair(std::string(kOpenCLMemoryModel) + std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Geometry %func \"shader\" " "OpExecutionMode %func InputTrianglesAdjacency" + + " OpExecutionMode %func OutputTriangleStrip" + std::string(kVoidFVoid), GeometryDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint TessellationControl %func \"shader\" " @@ -761,6 +1007,8 @@ std::make_pair(std::string(kOpenCLMemoryModel) + std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Geometry %func \"shader\" " "OpExecutionMode %func OutputVertices 42" + + " OpExecutionMode %func OutputPoints" + + " OpExecutionMode %func InputPoints" + std::string(kVoidFVoid), GeometryDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint TessellationControl %func \"shader\" " @@ -769,14 +1017,17 @@ std::make_pair(std::string(kOpenCLMemoryModel) + std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Geometry %func \"shader\" " "OpExecutionMode %func OutputPoints" + + " OpExecutionMode %func InputPoints" + std::string(kVoidFVoid), GeometryDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Geometry %func \"shader\" " "OpExecutionMode %func OutputLineStrip" + + " OpExecutionMode %func InputLines" + std::string(kVoidFVoid), GeometryDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Geometry %func \"shader\" " "OpExecutionMode %func OutputTriangleStrip" + + " OpExecutionMode %func Triangles" + std::string(kVoidFVoid), GeometryDependencies()), std::make_pair(std::string(kGLSL450MemoryModel) + "OpEntryPoint Kernel %func \"shader\" " @@ -785,11 +1036,11 @@ std::make_pair(std::string(kGLSL450MemoryModel) + std::make_pair(std::string(kGLSL450MemoryModel) + "OpEntryPoint Kernel %func \"shader\" " "OpExecutionMode %func ContractionOff" + - std::string(kVoidFVoid), KernelDependencies()))),); + std::string(kVoidFVoid), KernelDependencies())))); // clang-format on -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( ExecutionModeV11, ValidateCapabilityV11, Combine(ValuesIn(AllCapabilities()), Values(std::make_pair(std::string(kOpenCLMemoryModel) + @@ -802,10 +1053,10 @@ INSTANTIATE_TEST_CASE_P( "OpEntryPoint Kernel %func \"shader\" " "OpExecutionMode %func SubgroupsPerWorkgroup 65535" + std::string(kVoidFVoid), - std::vector{"SubgroupDispatch"}))), ); + std::vector{"SubgroupDispatch"})))); // clang-format off -INSTANTIATE_TEST_CASE_P(StorageClass, ValidateCapability, +INSTANTIATE_TEST_SUITE_P(StorageClass, ValidateCapability, Combine( ValuesIn(AllCapabilities()), Values( @@ -869,9 +1120,9 @@ std::make_pair(std::string(kGLSL450MemoryModel) + " %ptrt = OpTypePointer Image %intt\n" " %var = OpVariable %ptrt Image\n" + std::string(kVoidFVoid), AllCapabilities()) -)),); +))); -INSTANTIATE_TEST_CASE_P(Dim, ValidateCapability, +INSTANTIATE_TEST_SUITE_P(Dim, ValidateCapability, Combine( ValuesIn(AllCapabilities()), Values( @@ -917,11 +1168,11 @@ std::make_pair(" OpCapability ImageBasic" + " %voidt = OpTypeVoid" " %imgt = OpTypeImage %voidt SubpassData 0 0 0 2 Unknown" + std::string(kVoidFVoid2), std::vector{"InputAttachment"}) -)),); +))); // NOTE: All Sampler Address Modes require kernel capabilities but the // OpConstantSampler requires LiteralSampler which depends on Kernel -INSTANTIATE_TEST_CASE_P(SamplerAddressingMode, ValidateCapability, +INSTANTIATE_TEST_SUITE_P(SamplerAddressingMode, ValidateCapability, Combine( ValuesIn(AllCapabilities()), Values( @@ -955,7 +1206,7 @@ std::make_pair(std::string(kGLSL450MemoryModel) + " %sampler = OpConstantSampler %samplert RepeatMirrored 1 Nearest" + std::string(kVoidFVoid), std::vector{"LiteralSampler"}) -)),); +))); // TODO(umar): Sampler Filter Mode // TODO(umar): Image Format @@ -968,7 +1219,7 @@ std::make_pair(std::string(kGLSL450MemoryModel) + // TODO(umar): Access Qualifier // TODO(umar): Function Parameter Attribute -INSTANTIATE_TEST_CASE_P(Decoration, ValidateCapability, +INSTANTIATE_TEST_SUITE_P(Decoration, ValidateCapability, Combine( ValuesIn(AllCapabilities()), Values( @@ -1078,9 +1329,14 @@ std::make_pair(std::string(kOpenCLMemoryModel) + "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), AllCapabilities()), std::make_pair(std::string(kOpenCLMemoryModel) + + // NonWritable must target something valid, such as a storage image. "OpEntryPoint Kernel %func \"compute\" \n" - "OpDecorate %intt NonWritable\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %var NonWritable " + "%float = OpTypeFloat 32 " + "%imstor = OpTypeImage %float 2D 0 0 0 2 Unknown " + "%ptr = OpTypePointer UniformConstant %imstor " + "%var = OpVariable %ptr UniformConstant " + + std::string(kVoidFVoid), AllCapabilities()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" @@ -1088,9 +1344,12 @@ std::make_pair(std::string(kOpenCLMemoryModel) + "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), AllCapabilities()), std::make_pair(std::string(kOpenCLMemoryModel) + + // Uniform must target a non-void value. "OpEntryPoint Kernel %func \"compute\" \n" - "OpDecorate %intt Uniform\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %int0 Uniform\n" + "%intt = OpTypeInt 32 0\n" + + "%int0 = OpConstantNull %intt" + + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kGLSL450MemoryModel) + "OpEntryPoint Vertex %func \"shader\" \n" @@ -1109,8 +1368,10 @@ std::make_pair(std::string(kOpenCLMemoryModel) + ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" - "OpDecorate %intt Component 0\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %var Component 0\n" + "%intt = OpTypeInt 32 0\n" + "%ptr = OpTypePointer Input %intt\n" + "%var = OpVariable %ptr Input\n" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" @@ -1172,10 +1433,10 @@ std::make_pair(std::string(kGLSL450MemoryModel) + "OpDecorate %intt Alignment 4\n" "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), KernelDependencies()) -)),); +))); // clang-format on -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( DecorationSpecId, ValidateCapability, Combine( ValuesIn(AllSpirV10Capabilities()), @@ -1185,9 +1446,9 @@ INSTANTIATE_TEST_CASE_P( "%intt = OpTypeInt 32 0\n" "%1 = OpSpecConstant %intt 0\n" + std::string(kVoidFVoid), - ShaderDependencies()))), ); + ShaderDependencies())))); -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( DecorationV11, ValidateCapabilityV11, Combine(ValuesIn(AllCapabilities()), Values(std::make_pair(std::string(kOpenCLMemoryModel) + @@ -1216,238 +1477,281 @@ INSTANTIATE_TEST_CASE_P( "%intt = OpTypeInt 32 0 " "%1 = OpSpecConstant %intt 0") + std::string(kVoidFVoid), - ShaderDependencies()))), ); + ShaderDependencies())))); // clang-format off -INSTANTIATE_TEST_CASE_P(BuiltIn, ValidateCapability, +INSTANTIATE_TEST_SUITE_P(BuiltIn, ValidateCapability, Combine( ValuesIn(AllCapabilities()), Values( std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + - "OpDecorate %intt BuiltIn Position\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %int0 BuiltIn Position\n" + "%intt = OpTypeInt 32 0\n" + "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), ShaderDependencies()), // Just mentioning PointSize, ClipDistance, or CullDistance as a BuiltIn does // not trigger the requirement for the associated capability. // See https://github.com/KhronosGroup/SPIRV-Tools/issues/365 std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + - "OpDecorate %intt BuiltIn PointSize\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %int0 BuiltIn PointSize\n" + "%intt = OpTypeInt 32 0\n" + "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), AllCapabilities()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + - "OpDecorate %intt BuiltIn ClipDistance\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %int0 BuiltIn ClipDistance\n" + "%intt = OpTypeInt 32 0\n" + "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), AllCapabilities()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + - "OpDecorate %intt BuiltIn CullDistance\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %int0 BuiltIn CullDistance\n" + "%intt = OpTypeInt 32 0\n" + "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), AllCapabilities()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + - "OpDecorate %intt BuiltIn VertexId\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %int0 BuiltIn VertexId\n" + "%intt = OpTypeInt 32 0\n" + "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + - "OpDecorate %intt BuiltIn InstanceId\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %int0 BuiltIn InstanceId\n" + "%intt = OpTypeInt 32 0\n" + "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + - "OpDecorate %intt BuiltIn PrimitiveId\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %int0 BuiltIn PrimitiveId\n" + "%intt = OpTypeInt 32 0\n" + "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), GeometryTessellationDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + - "OpDecorate %intt BuiltIn InvocationId\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %int0 BuiltIn InvocationId\n" + "%intt = OpTypeInt 32 0\n" + "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), GeometryTessellationDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + - "OpDecorate %intt BuiltIn Layer\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %int0 BuiltIn Layer\n" + "%intt = OpTypeInt 32 0\n" + "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), GeometryDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + - "OpDecorate %intt BuiltIn ViewportIndex\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %int0 BuiltIn ViewportIndex\n" + "%intt = OpTypeInt 32 0\n" + "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), std::vector{"MultiViewport"}), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + - "OpDecorate %intt BuiltIn TessLevelOuter\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %int0 BuiltIn TessLevelOuter\n" + "%intt = OpTypeInt 32 0\n" + "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), TessellationDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + - "OpDecorate %intt BuiltIn TessLevelInner\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %int0 BuiltIn TessLevelInner\n" + "%intt = OpTypeInt 32 0\n" + "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), TessellationDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + - "OpDecorate %intt BuiltIn TessCoord\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %int0 BuiltIn TessCoord\n" + "%intt = OpTypeInt 32 0\n" + "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), TessellationDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + - "OpDecorate %intt BuiltIn PatchVertices\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %int0 BuiltIn PatchVertices\n" + "%intt = OpTypeInt 32 0\n" + "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), TessellationDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + - "OpDecorate %intt BuiltIn FragCoord\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %int0 BuiltIn FragCoord\n" + "%intt = OpTypeInt 32 0\n" + "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + - "OpDecorate %intt BuiltIn PointCoord\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %int0 BuiltIn PointCoord\n" + "%intt = OpTypeInt 32 0\n" + "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + - "OpDecorate %intt BuiltIn FrontFacing\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %int0 BuiltIn FrontFacing\n" + "%intt = OpTypeInt 32 0\n" + "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + - "OpDecorate %intt BuiltIn SampleId\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %int0 BuiltIn SampleId\n" + "%intt = OpTypeInt 32 0\n" + "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), std::vector{"SampleRateShading"}), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + - "OpDecorate %intt BuiltIn SamplePosition\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %int0 BuiltIn SamplePosition\n" + "%intt = OpTypeInt 32 0\n" + "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), std::vector{"SampleRateShading"}), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + - "OpDecorate %intt BuiltIn SampleMask\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %int0 BuiltIn SampleMask\n" + "%intt = OpTypeInt 32 0\n" + "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + - "OpDecorate %intt BuiltIn FragDepth\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %int0 BuiltIn FragDepth\n" + "%intt = OpTypeInt 32 0\n" + "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + - "OpDecorate %intt BuiltIn HelperInvocation\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %int0 BuiltIn HelperInvocation\n" + "%intt = OpTypeInt 32 0\n" + "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + - "OpDecorate %intt BuiltIn VertexIndex\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %int0 BuiltIn VertexIndex\n" + "%intt = OpTypeInt 32 0\n" + "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + - "OpDecorate %intt BuiltIn InstanceIndex\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %int0 BuiltIn InstanceIndex\n" + "%intt = OpTypeInt 32 0\n" + "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + - "OpDecorate %intt BuiltIn NumWorkgroups\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %int0 BuiltIn NumWorkgroups\n" + "%intt = OpTypeInt 32 0\n" + "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), AllCapabilities()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + - "OpDecorate %intt BuiltIn WorkgroupSize\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %int0 BuiltIn WorkgroupSize\n" + "%intt = OpTypeInt 32 0\n" + "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), AllCapabilities()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + - "OpDecorate %intt BuiltIn WorkgroupId\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %int0 BuiltIn WorkgroupId\n" + "%intt = OpTypeInt 32 0\n" + "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), AllCapabilities()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + - "OpDecorate %intt BuiltIn LocalInvocationId\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %int0 BuiltIn LocalInvocationId\n" + "%intt = OpTypeInt 32 0\n" + "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), AllCapabilities()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + - "OpDecorate %intt BuiltIn GlobalInvocationId\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %int0 BuiltIn GlobalInvocationId\n" + "%intt = OpTypeInt 32 0\n" + "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), AllCapabilities()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + - "OpDecorate %intt BuiltIn LocalInvocationIndex\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %int0 BuiltIn LocalInvocationIndex\n" + "%intt = OpTypeInt 32 0\n" + "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), AllCapabilities()), std::make_pair(std::string(kGLSL450MemoryModel) + "OpEntryPoint Vertex %func \"shader\" \n" + - "OpDecorate %intt BuiltIn WorkDim\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %int0 BuiltIn WorkDim\n" + "%intt = OpTypeInt 32 0\n" + "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), KernelDependencies()), std::make_pair(std::string(kGLSL450MemoryModel) + "OpEntryPoint Vertex %func \"shader\" \n" + - "OpDecorate %intt BuiltIn GlobalSize\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %int0 BuiltIn GlobalSize\n" + "%intt = OpTypeInt 32 0\n" + "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), KernelDependencies()), std::make_pair(std::string(kGLSL450MemoryModel) + "OpEntryPoint Vertex %func \"shader\" \n" + - "OpDecorate %intt BuiltIn EnqueuedWorkgroupSize\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %int0 BuiltIn EnqueuedWorkgroupSize\n" + "%intt = OpTypeInt 32 0\n" + "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), KernelDependencies()), std::make_pair(std::string(kGLSL450MemoryModel) + "OpEntryPoint Vertex %func \"shader\" \n" + - "OpDecorate %intt BuiltIn GlobalOffset\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %int0 BuiltIn GlobalOffset\n" + "%intt = OpTypeInt 32 0\n" + "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), KernelDependencies()), std::make_pair(std::string(kGLSL450MemoryModel) + "OpEntryPoint Vertex %func \"shader\" \n" + - "OpDecorate %intt BuiltIn GlobalLinearId\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %int0 BuiltIn GlobalLinearId\n" + "%intt = OpTypeInt 32 0\n" + "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), KernelDependencies()), std::make_pair(std::string(kGLSL450MemoryModel) + "OpEntryPoint Vertex %func \"shader\" \n" + - "OpDecorate %intt BuiltIn SubgroupSize\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %int0 BuiltIn SubgroupSize\n" + "%intt = OpTypeInt 32 0\n" + "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), KernelAndGroupNonUniformDependencies()), std::make_pair(std::string(kGLSL450MemoryModel) + "OpEntryPoint Vertex %func \"shader\" \n" + - "OpDecorate %intt BuiltIn SubgroupMaxSize\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %int0 BuiltIn SubgroupMaxSize\n" + "%intt = OpTypeInt 32 0\n" + "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), KernelDependencies()), std::make_pair(std::string(kGLSL450MemoryModel) + "OpEntryPoint Vertex %func \"shader\" \n" + - "OpDecorate %intt BuiltIn NumSubgroups\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %int0 BuiltIn NumSubgroups\n" + "%intt = OpTypeInt 32 0\n" + "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), KernelAndGroupNonUniformDependencies()), std::make_pair(std::string(kGLSL450MemoryModel) + "OpEntryPoint Vertex %func \"shader\" \n" + - "OpDecorate %intt BuiltIn NumEnqueuedSubgroups\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %int0 BuiltIn NumEnqueuedSubgroups\n" + "%intt = OpTypeInt 32 0\n" + "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), KernelDependencies()), std::make_pair(std::string(kGLSL450MemoryModel) + "OpEntryPoint Vertex %func \"shader\" \n" + - "OpDecorate %intt BuiltIn SubgroupId\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %int0 BuiltIn SubgroupId\n" + "%intt = OpTypeInt 32 0\n" + "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), KernelAndGroupNonUniformDependencies()), std::make_pair(std::string(kGLSL450MemoryModel) + "OpEntryPoint Vertex %func \"shader\" \n" + - "OpDecorate %intt BuiltIn SubgroupLocalInvocationId\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %int0 BuiltIn SubgroupLocalInvocationId\n" + "%intt = OpTypeInt 32 0\n" + "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), KernelAndGroupNonUniformDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + - "OpDecorate %intt BuiltIn VertexIndex\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %int0 BuiltIn VertexIndex\n" + "%intt = OpTypeInt 32 0\n" + "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), ShaderDependencies()), std::make_pair(std::string(kOpenCLMemoryModel) + "OpEntryPoint Kernel %func \"compute\" \n" + - "OpDecorate %intt BuiltIn InstanceIndex\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %int0 BuiltIn InstanceIndex\n" + "%intt = OpTypeInt 32 0\n" + "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), ShaderDependencies()) -)),); +))); // Ensure that mere mention of PointSize, ClipDistance, or CullDistance as // BuiltIns does not trigger the requirement for the associated // capability. // See https://github.com/KhronosGroup/SPIRV-Tools/issues/365 -INSTANTIATE_TEST_CASE_P(BuiltIn, ValidateCapabilityVulkan10, +INSTANTIATE_TEST_SUITE_P(BuiltIn, ValidateCapabilityVulkan10, Combine( // All capabilities to try. ValuesIn(AllSpirV10Capabilities()), @@ -1478,46 +1782,80 @@ std::make_pair(std::string(kGLSL450MemoryModel) + "%f32arr4 = OpTypeArray %f32 %intt_4\n" "%block = OpTypeStruct %f32arr4\n" + std::string(kVoidFVoid), AllVulkan10Capabilities()) -)),); +))); -INSTANTIATE_TEST_CASE_P(BuiltIn, ValidateCapabilityOpenGL40, +INSTANTIATE_TEST_SUITE_P(BuiltIn, ValidateCapabilityOpenGL40, Combine( // OpenGL 4.0 is based on SPIR-V 1.0 ValuesIn(AllSpirV10Capabilities()), Values( std::make_pair(std::string(kGLSL450MemoryModel) + "OpEntryPoint Vertex %func \"shader\" \n" + - "OpDecorate %intt BuiltIn PointSize\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %int0 BuiltIn PointSize\n" + "%intt = OpTypeInt 32 0\n" + "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), AllSpirV10Capabilities()), std::make_pair(std::string(kGLSL450MemoryModel) + "OpEntryPoint Vertex %func \"shader\" \n" + - "OpDecorate %intt BuiltIn ClipDistance\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %int0 BuiltIn ClipDistance\n" + "%intt = OpTypeInt 32 0\n" + "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), AllSpirV10Capabilities()), std::make_pair(std::string(kGLSL450MemoryModel) + "OpEntryPoint Vertex %func \"shader\" \n" + - "OpDecorate %intt BuiltIn CullDistance\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %int0 BuiltIn CullDistance\n" + "%intt = OpTypeInt 32 0\n" + "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), AllSpirV10Capabilities()) -)),); +))); -INSTANTIATE_TEST_CASE_P(Capabilities, ValidateCapabilityVulkan11, +INSTANTIATE_TEST_SUITE_P(Capabilities, ValidateCapabilityWebGPU, + Combine( + // All capabilities to try. + ValuesIn(AllCapabilities()), + Values( +std::make_pair(std::string(kVulkanMemoryModel) + + "OpEntryPoint Vertex %func \"shader\" \n" + std::string(kVoidFVoid), + AllWebGPUCapabilities()) +))); + +INSTANTIATE_TEST_SUITE_P(Capabilities, ValidateCapabilityVulkan11, Combine( // All capabilities to try. ValuesIn(AllCapabilities()), Values( std::make_pair(std::string(kGLSL450MemoryModel) + "OpEntryPoint Vertex %func \"shader\" \n" + - "OpDecorate %intt BuiltIn PointSize\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %int0 BuiltIn PointSize\n" + "%intt = OpTypeInt 32 0\n" + "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), AllVulkan11Capabilities()), std::make_pair(std::string(kGLSL450MemoryModel) + "OpEntryPoint Vertex %func \"shader\" \n" + - "OpDecorate %intt BuiltIn CullDistance\n" - "%intt = OpTypeInt 32 0\n" + std::string(kVoidFVoid), + "OpDecorate %int0 BuiltIn CullDistance\n" + "%intt = OpTypeInt 32 0\n" + "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), AllVulkan11Capabilities()) -)),); +))); + +INSTANTIATE_TEST_SUITE_P(Capabilities, ValidateCapabilityVulkan12, + Combine( + // All capabilities to try. + ValuesIn(AllSpirV15Capabilities()), + Values( +std::make_pair(std::string(kGLSL450MemoryModel) + + "OpEntryPoint Vertex %func \"shader\" \n" + + "OpDecorate %int0 BuiltIn PointSize\n" + "%intt = OpTypeInt 32 0\n" + "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), + AllVulkan12Capabilities()), +std::make_pair(std::string(kGLSL450MemoryModel) + + "OpEntryPoint Vertex %func \"shader\" \n" + + "OpDecorate %int0 BuiltIn CullDistance\n" + "%intt = OpTypeInt 32 0\n" + "%int0 = OpConstant %intt 0\n" + std::string(kVoidFVoid), + AllVulkan12Capabilities()) +))); // TODO(umar): Selection Control // TODO(umar): Loop Control @@ -1529,7 +1867,7 @@ std::make_pair(std::string(kGLSL450MemoryModel) + // TODO(umar): Kernel Enqueue Flags // TODO(umar): Kernel Profiling Flags -INSTANTIATE_TEST_CASE_P(MatrixOp, ValidateCapability, +INSTANTIATE_TEST_SUITE_P(MatrixOp, ValidateCapability, Combine( ValuesIn(AllCapabilities()), Values( @@ -1538,7 +1876,7 @@ std::make_pair(std::string(kOpenCLMemoryModel) + "%f32 = OpTypeFloat 32\n" "%vec3 = OpTypeVector %f32 3\n" "%mat33 = OpTypeMatrix %vec3 3\n" + std::string(kVoidFVoid), - MatrixDependencies()))),); + MatrixDependencies())))); // clang-format on #if 0 @@ -1579,7 +1917,7 @@ OpFunctionEnd return ss.str(); } -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( TwoImageOperandsMask, ValidateCapability, Combine( ValuesIn(AllCapabilities()), @@ -1682,6 +2020,17 @@ TEST_P(ValidateCapabilityVulkan11, Capability) { } } +TEST_P(ValidateCapabilityVulkan12, Capability) { + const std::string capability = Capability(GetParam()); + if (Exists(capability, SPV_ENV_VULKAN_1_2)) { + const std::string test_code = MakeAssembly(GetParam()); + CompileSuccessfully(test_code, SPV_ENV_VULKAN_1_2); + ASSERT_EQ(ExpectedResult(GetParam()), + ValidateInstructions(SPV_ENV_VULKAN_1_2)) + << test_code; + } +} + TEST_P(ValidateCapabilityOpenGL40, Capability) { const std::string capability = Capability(GetParam()); if (Exists(capability, SPV_ENV_OPENGL_4_0)) { @@ -1693,6 +2042,17 @@ TEST_P(ValidateCapabilityOpenGL40, Capability) { } } +TEST_P(ValidateCapabilityWebGPU, Capability) { + const std::string capability = Capability(GetParam()); + if (Exists(capability, SPV_ENV_WEBGPU_0)) { + const std::string test_code = MakeAssembly(GetParam()); + CompileSuccessfully(test_code, SPV_ENV_WEBGPU_0); + ASSERT_EQ(ExpectedResult(GetParam()), + ValidateInstructions(SPV_ENV_WEBGPU_0)) + << test_code; + } +} + TEST_F(ValidateCapability, SemanticsIdIsAnIdNotALiteral) { // From https://github.com/KhronosGroup/SPIRV-Tools/issues/248 // The validator was interpreting the memory semantics ID number @@ -2185,8 +2545,8 @@ OpMemoryModel Logical Simple EXPECT_EQ(SPV_ERROR_MISSING_EXTENSION, ValidateInstructions(SPV_ENV_UNIVERSAL_1_0)); EXPECT_THAT(getDiagnosticString(), - HasSubstr("operand 5255 requires one of these extensions: " - "SPV_NV_viewport_array2")); + HasSubstr("operand ShaderViewportMaskNV(5255) requires one of " + "these extensions: SPV_NV_viewport_array2")); } TEST_F(ValidateCapability, @@ -2267,8 +2627,8 @@ OpFunctionEnd EXPECT_EQ(SPV_ERROR_MISSING_EXTENSION, ValidateInstructions(SPV_ENV_UNIVERSAL_1_0)); EXPECT_THAT(getDiagnosticString(), - HasSubstr("operand 5568 requires one of these extensions: " - "SPV_INTEL_subgroups")); + HasSubstr("operand SubgroupShuffleINTEL(5568) requires one of " + "these extensions: SPV_INTEL_subgroups")); } TEST_F(ValidateCapability, @@ -2296,6 +2656,236 @@ OpFunctionEnd << getDiagnosticString(); } +TEST_F(ValidateCapability, VulkanMemoryModelWithVulkanKHR) { + const std::string spirv = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpCapability Linkage +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)) + << getDiagnosticString(); +} + +TEST_F(ValidateCapability, VulkanMemoryModelWithGLSL450) { + const std::string spirv = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpCapability Linkage +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical GLSL450 +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("VulkanMemoryModelKHR capability must only be " + "specified if the VulkanKHR memory model is used")); +} + +// In the grammar, SubgroupEqMask and SubgroupMaskKHR have different enabling +// lists of extensions. +TEST_F(ValidateCapability, SubgroupEqMaskEnabledByExtension) { + const std::string spirv = R"( +OpCapability Shader +OpCapability SubgroupBallotKHR +OpExtension "SPV_KHR_shader_ballot" +OpMemoryModel Logical Simple +OpEntryPoint GLCompute %main "main" +OpDecorate %var BuiltIn SubgroupEqMask +%void = OpTypeVoid +%uint = OpTypeInt 32 0 +%ptr_uint = OpTypePointer Private %uint +%var = OpVariable %ptr_uint Private +%fn = OpTypeFunction %void +%main = OpFunction %void None %fn +%entry = OpLabel +%val = OpLoad %uint %var +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_0); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_0)) + << getDiagnosticString(); +} + +// Test that extensions incorporated into SPIR-V 1.5 no longer require +// the associated OpExtension instruction. Test one capability per extension. + +struct CapabilityExtensionVersionCase { + std::string capability; + std::string capability_new_name; + std::string extension; + spv_target_env last_version_requiring_extension; + spv_target_env first_version_in_core; +}; + +using ValidateCapabilityExtensionVersionTest = + spvtest::ValidateBase; + +// Returns a minimal shader module with the given capability instruction. +std::string MinimalShaderModuleWithCapability(std::string cap) { + std::string mem_model = + (cap.find("VulkanMemory") == 0) ? "VulkanKHR" : "GLSL450"; + std::string extra_cap = (cap.find("VulkanMemoryModelDeviceScope") == 0) + ? "\nOpCapability VulkanMemoryModelKHR\n" + : ""; + return std::string("OpCapability ") + cap + extra_cap + R"( +OpCapability Shader +OpMemoryModel Logical )" + mem_model + R"( +OpEntryPoint Vertex %main "main" +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; +} + +TEST_P(ValidateCapabilityExtensionVersionTest, FailsInOlderSpirvVersion) { + const auto spirv = MinimalShaderModuleWithCapability(GetParam().capability); + CompileSuccessfully(spirv, GetParam().last_version_requiring_extension); + EXPECT_EQ(SPV_ERROR_MISSING_EXTENSION, + ValidateInstructions(GetParam().last_version_requiring_extension)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr(std::string("1st operand of Capability: operand ") + + GetParam().capability_new_name)) + << spirv << "\n"; + EXPECT_THAT(getDiagnosticString(), + HasSubstr(std::string("requires one of these extensions: ") + + GetParam().extension)); +} + +TEST_P(ValidateCapabilityExtensionVersionTest, + SucceedsInNewerSpirvVersionWithOldName) { + const auto spirv = MinimalShaderModuleWithCapability(GetParam().capability); + CompileSuccessfully(spirv, GetParam().first_version_in_core); + EXPECT_EQ(SPV_SUCCESS, + ValidateInstructions(GetParam().first_version_in_core)); + EXPECT_THAT(getDiagnosticString(), Eq("")) << spirv << "\n"; +} + +TEST_P(ValidateCapabilityExtensionVersionTest, + SucceedsInNewerSpirvVersionWithNewName) { + const auto spirv = + MinimalShaderModuleWithCapability(GetParam().capability_new_name); + CompileSuccessfully(spirv, GetParam().first_version_in_core); + EXPECT_EQ(SPV_SUCCESS, + ValidateInstructions(GetParam().first_version_in_core)); + EXPECT_THAT(getDiagnosticString(), Eq("")) << spirv << "\n"; +} + +std::vector CapVersionCases1_5() { +#define IN15NOSUFFIX(C, E) \ + { C, C, E, SPV_ENV_UNIVERSAL_1_4, SPV_ENV_UNIVERSAL_1_5 } +#define IN15(C, C_WITHOUT_SUFFIX, E) \ + { C, C_WITHOUT_SUFFIX, E, SPV_ENV_UNIVERSAL_1_4, SPV_ENV_UNIVERSAL_1_5 } + return std::vector{ + // SPV_KHR_8bit_storage + IN15NOSUFFIX("StorageBuffer8BitAccess", "SPV_KHR_8bit_storage"), + IN15NOSUFFIX("UniformAndStorageBuffer8BitAccess", "SPV_KHR_8bit_storage"), + IN15NOSUFFIX("StoragePushConstant8", "SPV_KHR_8bit_storage"), + // SPV_EXT_descriptor_indexing + IN15("ShaderNonUniformEXT", "ShaderNonUniform", + "SPV_EXT_descriptor_indexing"), + IN15("RuntimeDescriptorArrayEXT", "RuntimeDescriptorArray", + "SPV_EXT_descriptor_indexing"), + IN15("InputAttachmentArrayDynamicIndexingEXT", + "InputAttachmentArrayDynamicIndexing", + "SPV_EXT_descriptor_indexing"), + IN15("UniformTexelBufferArrayDynamicIndexingEXT", + "UniformTexelBufferArrayDynamicIndexing", + "SPV_EXT_descriptor_indexing"), + IN15("StorageTexelBufferArrayDynamicIndexingEXT", + "StorageTexelBufferArrayDynamicIndexing", + "SPV_EXT_descriptor_indexing"), + IN15("UniformBufferArrayNonUniformIndexingEXT", + "UniformBufferArrayNonUniformIndexing", + "SPV_EXT_descriptor_indexing"), + IN15("SampledImageArrayNonUniformIndexingEXT", + "SampledImageArrayNonUniformIndexing", + "SPV_EXT_descriptor_indexing"), + IN15("StorageBufferArrayNonUniformIndexingEXT", + "StorageBufferArrayNonUniformIndexing", + "SPV_EXT_descriptor_indexing"), + IN15("StorageImageArrayNonUniformIndexingEXT", + "StorageImageArrayNonUniformIndexing", + "SPV_EXT_descriptor_indexing"), + IN15("InputAttachmentArrayNonUniformIndexingEXT", + "InputAttachmentArrayNonUniformIndexing", + "SPV_EXT_descriptor_indexing"), + IN15("UniformTexelBufferArrayNonUniformIndexingEXT", + "UniformTexelBufferArrayNonUniformIndexing", + "SPV_EXT_descriptor_indexing"), + IN15("StorageTexelBufferArrayNonUniformIndexingEXT", + "StorageTexelBufferArrayNonUniformIndexing", + "SPV_EXT_descriptor_indexing"), + // SPV_EXT_physical_storage_buffer + IN15("PhysicalStorageBufferAddressesEXT", + "PhysicalStorageBufferAddresses", "SPV_EXT_physical_storage_buffer"), + // SPV_KHR_vulkan_memory_model + IN15("VulkanMemoryModelKHR", "VulkanMemoryModel", + "SPV_KHR_vulkan_memory_model"), + IN15("VulkanMemoryModelDeviceScopeKHR", "VulkanMemoryModelDeviceScope", + "SPV_KHR_vulkan_memory_model"), + }; +#undef IN15 +} + +INSTANTIATE_TEST_SUITE_P(NewInSpirv1_5, ValidateCapabilityExtensionVersionTest, + ValuesIn(CapVersionCases1_5())); + +TEST_P(ValidateCapability, + CapShaderViewportIndexLayerFailsInOlderSpirvVersion) { + const auto spirv = + MinimalShaderModuleWithCapability("ShaderViewportIndexLayerEXT"); + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_ERROR_MISSING_EXTENSION, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "1st operand of Capability: operand ShaderViewportIndexLayerEXT")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("requires one of these extensions: " + "SPV_EXT_shader_viewport_index_layer")); +} + +TEST_P(ValidateCapability, CapShaderViewportIndexLayerFailsInNewSpirvVersion) { + const auto spirv = + MinimalShaderModuleWithCapability("ShaderViewportIndexLayerEXT"); + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_5); + EXPECT_EQ(SPV_ERROR_MISSING_EXTENSION, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_5)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "1st operand of Capability: operand ShaderViewportIndexLayerEXT")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("requires one of these extensions: " + "SPV_EXT_shader_viewport_index_layer")); +} + +TEST_F(ValidateCapability, CapShaderViewportIndexSucceedsInNewSpirvVersion) { + const auto spirv = MinimalShaderModuleWithCapability("ShaderViewportIndex"); + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_5); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_5)); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateCapability, CapShaderLayerSucceedsInNewSpirvVersion) { + const auto spirv = MinimalShaderModuleWithCapability("ShaderLayer"); + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_5); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_5)); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + } // namespace } // namespace val } // namespace spvtools diff --git a/third_party/spirv-tools/test/val/val_cfg_test.cpp b/third_party/spirv-tools/test/val/val_cfg_test.cpp index 045166925c..4cf4029671 100644 --- a/third_party/spirv-tools/test/val/val_cfg_test.cpp +++ b/third_party/spirv-tools/test/val/val_cfg_test.cpp @@ -23,8 +23,8 @@ #include #include "gmock/gmock.h" - #include "source/diagnostic.h" +#include "source/spirv_target_env.h" #include "source/val/validate.h" #include "test/test_fixture.h" #include "test/unit_spirv.h" @@ -103,6 +103,12 @@ class Block { } out << ss.str(); } break; + case SpvOpLoopMerge: { + assert(successors_.size() == 2); + out << "OpLoopMerge %" + successors_[0].label_ + " %" + + successors_[0].label_ + "None"; + } break; + case SpvOpReturn: assert(successors_.size() == 0); out << "OpReturn\n"; @@ -115,6 +121,10 @@ class Block { assert(successors_.size() == 1); out << "OpBranch %" + successors_.front().label_; break; + case SpvOpKill: + assert(successors_.size() == 0); + out << "OpKill\n"; + break; default: assert(1 == 0 && "Unhandled"); } @@ -144,13 +154,13 @@ Block& operator>>(Block& lhs, Block& successor) { return lhs; } -const char* header(SpvCapability cap) { - static const char* shader_header = +const std::string& GetDefaultHeader(SpvCapability cap) { + static const std::string shader_header = "OpCapability Shader\n" "OpCapability Linkage\n" "OpMemoryModel Logical GLSL450\n"; - static const char* kernel_header = + static const std::string kernel_header = "OpCapability Kernel\n" "OpCapability Linkage\n" "OpMemoryModel Logical OpenCL\n"; @@ -158,8 +168,17 @@ const char* header(SpvCapability cap) { return (cap == SpvCapabilityShader) ? shader_header : kernel_header; } -const char* types_consts() { - static const char* types = +const std::string& GetWebGPUHeader() { + static const std::string header = + "OpCapability Shader\n" + "OpCapability VulkanMemoryModelKHR\n" + "OpExtension \"SPV_KHR_vulkan_memory_model\"\n" + "OpMemoryModel Logical VulkanKHR\n"; + return header; +} + +const std::string& types_consts() { + static const std::string types = "%voidt = OpTypeVoid\n" "%boolt = OpTypeBool\n" "%intt = OpTypeInt 32 0\n" @@ -167,13 +186,12 @@ const char* types_consts() { "%two = OpConstant %intt 2\n" "%ptrt = OpTypePointer Function %intt\n" "%funct = OpTypeFunction %voidt\n"; - return types; } -INSTANTIATE_TEST_CASE_P(StructuredControlFlow, ValidateCFG, - ::testing::Values(SpvCapabilityShader, - SpvCapabilityKernel)); +INSTANTIATE_TEST_SUITE_P(StructuredControlFlow, ValidateCFG, + ::testing::Values(SpvCapabilityShader, + SpvCapabilityKernel)); TEST_P(ValidateCFG, LoopReachableFromEntryButNeverLeadingToReturn) { // In this case, the loop is reachable from a node without a predecessor, @@ -270,7 +288,7 @@ TEST_P(ValidateCFG, Simple) { loop.SetBody("OpLoopMerge %merge %cont None\n"); } - std::string str = header(GetParam()) + + std::string str = GetDefaultHeader(GetParam()) + nameOps("loop", "entry", "cont", "merge", std::make_pair("func", "Main")) + types_consts() + @@ -293,7 +311,7 @@ TEST_P(ValidateCFG, Variable) { entry.SetBody("%var = OpVariable %ptrt Function\n"); - std::string str = header(GetParam()) + + std::string str = GetDefaultHeader(GetParam()) + nameOps(std::make_pair("func", "Main")) + types_consts() + " %func = OpFunction %voidt None %funct\n"; str += entry >> cont; @@ -313,7 +331,7 @@ TEST_P(ValidateCFG, VariableNotInFirstBlockBad) { // This operation should only be performed in the entry block cont.SetBody("%var = OpVariable %ptrt Function\n"); - std::string str = header(GetParam()) + + std::string str = GetDefaultHeader(GetParam()) + nameOps(std::make_pair("func", "Main")) + types_consts() + " %func = OpFunction %voidt None %funct\n"; @@ -323,11 +341,10 @@ TEST_P(ValidateCFG, VariableNotInFirstBlockBad) { str += "OpFunctionEnd\n"; CompileSuccessfully(str); - ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr( - "Variables can only be defined in the first block of a function")); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("All OpVariable instructions in a function must be the " + "first instructions in the first block")); } TEST_P(ValidateCFG, BlockSelfLoopIsOk) { @@ -339,7 +356,7 @@ TEST_P(ValidateCFG, BlockSelfLoopIsOk) { entry.SetBody("%cond = OpSLessThan %boolt %one %two\n"); if (is_shader) loop.SetBody("OpLoopMerge %merge %loop None\n"); - std::string str = header(GetParam()) + + std::string str = GetDefaultHeader(GetParam()) + nameOps("loop", "merge", std::make_pair("func", "Main")) + types_consts() + "%func = OpFunction %voidt None %funct\n"; @@ -364,7 +381,7 @@ TEST_P(ValidateCFG, BlockAppearsBeforeDominatorBad) { entry.SetBody("%cond = OpSLessThan %boolt %one %two\n"); if (is_shader) branch.SetBody("OpSelectionMerge %merge None\n"); - std::string str = header(GetParam()) + + std::string str = GetDefaultHeader(GetParam()) + nameOps("cont", "branch", std::make_pair("func", "Main")) + types_consts() + "%func = OpFunction %voidt None %funct\n"; @@ -378,8 +395,8 @@ TEST_P(ValidateCFG, BlockAppearsBeforeDominatorBad) { CompileSuccessfully(str); ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - MatchesRegex("Block .\\[cont\\] appears in the binary " - "before its dominator .\\[branch\\]\n" + MatchesRegex("Block .\\[%cont\\] appears in the binary " + "before its dominator .\\[%branch\\]\n" " %branch = OpLabel\n")); } @@ -396,9 +413,10 @@ TEST_P(ValidateCFG, MergeBlockTargetedByMultipleHeaderBlocksBad) { // cannot share the same merge if (is_shader) selection.SetBody("OpSelectionMerge %merge None\n"); - std::string str = - header(GetParam()) + nameOps("merge", std::make_pair("func", "Main")) + - types_consts() + "%func = OpFunction %voidt None %funct\n"; + std::string str = GetDefaultHeader(GetParam()) + + nameOps("merge", std::make_pair("func", "Main")) + + types_consts() + + "%func = OpFunction %voidt None %funct\n"; str += entry >> loop; str += loop >> selection; @@ -410,7 +428,7 @@ TEST_P(ValidateCFG, MergeBlockTargetedByMultipleHeaderBlocksBad) { if (is_shader) { ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - MatchesRegex("Block .\\[merge\\] is already a merge block " + MatchesRegex("Block .\\[%merge\\] is already a merge block " "for another header\n" " %Main = OpFunction %void None %9\n")); } else { @@ -431,9 +449,10 @@ TEST_P(ValidateCFG, MergeBlockTargetedByMultipleHeaderBlocksSelectionBad) { // cannot share the same merge if (is_shader) loop.SetBody(" OpLoopMerge %merge %loop None\n"); - std::string str = - header(GetParam()) + nameOps("merge", std::make_pair("func", "Main")) + - types_consts() + "%func = OpFunction %voidt None %funct\n"; + std::string str = GetDefaultHeader(GetParam()) + + nameOps("merge", std::make_pair("func", "Main")) + + types_consts() + + "%func = OpFunction %voidt None %funct\n"; str += entry >> selection; str += selection >> std::vector({merge, loop}); @@ -445,7 +464,7 @@ TEST_P(ValidateCFG, MergeBlockTargetedByMultipleHeaderBlocksSelectionBad) { if (is_shader) { ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - MatchesRegex("Block .\\[merge\\] is already a merge block " + MatchesRegex("Block .\\[%merge\\] is already a merge block " "for another header\n" " %Main = OpFunction %void None %9\n")); } else { @@ -457,7 +476,7 @@ TEST_P(ValidateCFG, BranchTargetFirstBlockBadSinceEntryBlock) { Block entry("entry"); Block bad("bad"); Block end("end", SpvOpReturn); - std::string str = header(GetParam()) + + std::string str = GetDefaultHeader(GetParam()) + nameOps("entry", "bad", std::make_pair("func", "Main")) + types_consts() + "%func = OpFunction %voidt None %funct\n"; @@ -470,8 +489,8 @@ TEST_P(ValidateCFG, BranchTargetFirstBlockBadSinceEntryBlock) { CompileSuccessfully(str); ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - MatchesRegex("First block .\\[entry\\] of function .\\[Main\\] " - "is targeted by block .\\[bad\\]\n" + MatchesRegex("First block .\\[%entry\\] of function " + ".\\[%Main\\] is targeted by block .\\[%bad\\]\n" " %Main = OpFunction %void None %10\n")); } @@ -481,7 +500,7 @@ TEST_P(ValidateCFG, BranchTargetFirstBlockBadSinceValue) { Block bad("bad"); Block end("end", SpvOpReturn); Block badvalue("undef"); // This referenes the OpUndef. - std::string str = header(GetParam()) + + std::string str = GetDefaultHeader(GetParam()) + nameOps("entry", "bad", std::make_pair("func", "Main")) + types_consts() + "%func = OpFunction %voidt None %funct\n"; @@ -493,12 +512,10 @@ TEST_P(ValidateCFG, BranchTargetFirstBlockBadSinceValue) { str += "OpFunctionEnd\n"; CompileSuccessfully(str); - ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - MatchesRegex("Block\\(s\\) \\{..\\} are referenced but not " - "defined in function .\\[Main\\]\n" - " %Main = OpFunction %void None %10\n")) - << str; + HasSubstr("'Target Label' operands for OpBranch must " + "be the ID of an OpLabel instruction")); } TEST_P(ValidateCFG, BranchConditionalTrueTargetFirstBlockBad) { @@ -509,7 +526,7 @@ TEST_P(ValidateCFG, BranchConditionalTrueTargetFirstBlockBad) { entry.SetBody("%cond = OpSLessThan %boolt %one %two\n"); bad.SetBody(" OpLoopMerge %entry %exit None\n"); - std::string str = header(GetParam()) + + std::string str = GetDefaultHeader(GetParam()) + nameOps("entry", "bad", std::make_pair("func", "Main")) + types_consts() + "%func = OpFunction %voidt None %funct\n"; @@ -522,8 +539,8 @@ TEST_P(ValidateCFG, BranchConditionalTrueTargetFirstBlockBad) { CompileSuccessfully(str); ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - MatchesRegex("First block .\\[entry\\] of function .\\[Main\\] " - "is targeted by block .\\[bad\\]\n" + MatchesRegex("First block .\\[%entry\\] of function .\\[%Main\\] " + "is targeted by block .\\[%bad\\]\n" " %Main = OpFunction %void None %10\n")); } @@ -537,7 +554,7 @@ TEST_P(ValidateCFG, BranchConditionalFalseTargetFirstBlockBad) { entry.SetBody("%cond = OpSLessThan %boolt %one %two\n"); bad.SetBody("OpLoopMerge %merge %cont None\n"); - std::string str = header(GetParam()) + + std::string str = GetDefaultHeader(GetParam()) + nameOps("entry", "bad", std::make_pair("func", "Main")) + types_consts() + "%func = OpFunction %voidt None %funct\n"; @@ -551,8 +568,8 @@ TEST_P(ValidateCFG, BranchConditionalFalseTargetFirstBlockBad) { CompileSuccessfully(str); ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - MatchesRegex("First block .\\[entry\\] of function .\\[Main\\] " - "is targeted by block .\\[bad\\]\n" + MatchesRegex("First block .\\[%entry\\] of function .\\[%Main\\] " + "is targeted by block .\\[%bad\\]\n" " %Main = OpFunction %void None %10\n")); } @@ -569,7 +586,7 @@ TEST_P(ValidateCFG, SwitchTargetFirstBlockBad) { entry.SetBody("%cond = OpSLessThan %boolt %one %two\n"); bad.SetBody("OpSelectionMerge %merge None\n"); - std::string str = header(GetParam()) + + std::string str = GetDefaultHeader(GetParam()) + nameOps("entry", "bad", std::make_pair("func", "Main")) + types_consts() + "%func = OpFunction %voidt None %funct\n"; @@ -587,8 +604,8 @@ TEST_P(ValidateCFG, SwitchTargetFirstBlockBad) { CompileSuccessfully(str); ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - MatchesRegex("First block .\\[entry\\] of function .\\[Main\\] " - "is targeted by block .\\[bad\\]\n" + MatchesRegex("First block .\\[%entry\\] of function .\\[%Main\\] " + "is targeted by block .\\[%bad\\]\n" " %Main = OpFunction %void None %10\n")); } @@ -604,9 +621,10 @@ TEST_P(ValidateCFG, BranchToBlockInOtherFunctionBad) { Block middle2("middle2"); Block end2("end2", SpvOpReturn); - std::string str = - header(GetParam()) + nameOps("middle2", std::make_pair("func", "Main")) + - types_consts() + "%func = OpFunction %voidt None %funct\n"; + std::string str = GetDefaultHeader(GetParam()) + + nameOps("middle2", std::make_pair("func", "Main")) + + types_consts() + + "%func = OpFunction %voidt None %funct\n"; str += entry >> middle; str += middle >> std::vector({end, middle2}); @@ -623,8 +641,8 @@ TEST_P(ValidateCFG, BranchToBlockInOtherFunctionBad) { ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), - MatchesRegex("Block\\(s\\) \\{.\\[middle2\\]\\} are referenced but not " - "defined in function .\\[Main\\]\n" + MatchesRegex("Block\\(s\\) \\{.\\[%middle2\\]\\} are referenced but not " + "defined in function .\\[%Main\\]\n" " %Main = OpFunction %void None %9\n")); } @@ -639,7 +657,7 @@ TEST_P(ValidateCFG, HeaderDoesntDominatesMergeBad) { if (is_shader) head.AppendBody("OpSelectionMerge %merge None\n"); - std::string str = header(GetParam()) + + std::string str = GetDefaultHeader(GetParam()) + nameOps("head", "merge", std::make_pair("func", "Main")) + types_consts() + "%func = OpFunction %voidt None %funct\n"; @@ -656,8 +674,8 @@ TEST_P(ValidateCFG, HeaderDoesntDominatesMergeBad) { EXPECT_THAT( getDiagnosticString(), MatchesRegex("The selection construct with the selection header " - ".\\[head\\] does not dominate the merge block " - ".\\[merge\\]\n %merge = OpLabel\n")); + ".\\[%head\\] does not dominate the merge block " + ".\\[%merge\\]\n %merge = OpLabel\n")); } else { ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); } @@ -674,7 +692,7 @@ TEST_P(ValidateCFG, HeaderDoesntStrictlyDominateMergeBad) { if (is_shader) head.AppendBody("OpSelectionMerge %head None\n"); - std::string str = header(GetParam()) + + std::string str = GetDefaultHeader(GetParam()) + nameOps("head", "exit", std::make_pair("func", "Main")) + types_consts() + "%func = OpFunction %voidt None %funct\n"; @@ -689,15 +707,17 @@ TEST_P(ValidateCFG, HeaderDoesntStrictlyDominateMergeBad) { EXPECT_THAT( getDiagnosticString(), MatchesRegex("The selection construct with the selection header " - ".\\[head\\] does not strictly dominate the merge block " - ".\\[head\\]\n %head = OpLabel\n")); + ".\\[%head\\] does not strictly dominate the merge block " + ".\\[%head\\]\n %head = OpLabel\n")); } else { ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()) << str; } } -TEST_P(ValidateCFG, UnreachableMerge) { - bool is_shader = GetParam() == SpvCapabilityShader; +std::string GetUnreachableMergeNoMergeInst(SpvCapability cap, + spv_target_env env) { + std::string header = + spvIsWebGPUEnv(env) ? GetWebGPUHeader() : GetDefaultHeader(cap); Block entry("entry"); Block branch("branch", SpvOpBranchConditional); Block t("t", SpvOpReturn); @@ -705,13 +725,18 @@ TEST_P(ValidateCFG, UnreachableMerge) { Block merge("merge", SpvOpReturn); entry.SetBody("%cond = OpSLessThan %boolt %one %two\n"); - if (is_shader) branch.AppendBody("OpSelectionMerge %merge None\n"); - - std::string str = header(GetParam()) + - nameOps("branch", "merge", std::make_pair("func", "Main")) + - types_consts() + - "%func = OpFunction %voidt None %funct\n"; + if (!spvIsWebGPUEnv(env) && cap == SpvCapabilityShader) + branch.AppendBody("OpSelectionMerge %merge None\n"); + std::string str = header; + if (spvIsWebGPUEnv(env)) { + str += + "OpEntryPoint Fragment %func \"func\"\n" + "OpExecutionMode %func OriginUpperLeft\n"; + } + if (!spvIsWebGPUEnv(env)) + str += nameOps("branch", "merge", std::make_pair("func", "Main")); + str += types_consts() + "%func = OpFunction %voidt None %funct\n"; str += entry >> branch; str += branch >> std::vector({t, f}); str += t; @@ -719,12 +744,209 @@ TEST_P(ValidateCFG, UnreachableMerge) { str += merge; str += "OpFunctionEnd\n"; - CompileSuccessfully(str); + return str; +} + +TEST_P(ValidateCFG, UnreachableMergeNoMergeInst) { + CompileSuccessfully( + GetUnreachableMergeNoMergeInst(GetParam(), SPV_ENV_UNIVERSAL_1_0)); ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); } -TEST_P(ValidateCFG, UnreachableMergeDefinedByOpUnreachable) { - bool is_shader = GetParam() == SpvCapabilityShader; +TEST_F(ValidateCFG, WebGPUUnreachableMergeNoMergeInst) { + CompileSuccessfully( + GetUnreachableMergeNoMergeInst(SpvCapabilityShader, SPV_ENV_WEBGPU_0)); + ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("For WebGPU, all blocks must be reachable")); +} + +std::string GetUnreachableMergeTerminatedBy(SpvCapability cap, + spv_target_env env, SpvOp op) { + std::string header = + spvIsWebGPUEnv(env) ? GetWebGPUHeader() : GetDefaultHeader(cap); + + Block entry("entry"); + Block branch("branch", SpvOpBranchConditional); + Block t("t", SpvOpReturn); + Block f("f", SpvOpReturn); + Block merge("merge", op); + + entry.SetBody("%cond = OpSLessThan %boolt %one %two\n"); + std::string str = header; + if (spvIsWebGPUEnv(env)) { + str += + "OpEntryPoint Fragment %func \"func\"\n" + "OpExecutionMode %func OriginUpperLeft\n"; + } + if (cap == SpvCapabilityShader) + branch.AppendBody("OpSelectionMerge %merge None\n"); + if (!spvIsWebGPUEnv(env)) + str += nameOps("branch", "merge", std::make_pair("func", "Main")); + + str += types_consts(); + str += "%func = OpFunction %voidt None %funct\n"; + str += entry >> branch; + str += branch >> std::vector({t, f}); + str += t; + str += f; + str += merge; + str += "OpFunctionEnd\n"; + + return str; +} + +TEST_P(ValidateCFG, UnreachableMergeTerminatedByOpUnreachable) { + CompileSuccessfully(GetUnreachableMergeTerminatedBy( + GetParam(), SPV_ENV_UNIVERSAL_1_0, SpvOpUnreachable)); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateCFG, UnreachableMergeTerminatedByOpKill) { + CompileSuccessfully(GetUnreachableMergeTerminatedBy( + SpvCapabilityShader, SPV_ENV_UNIVERSAL_1_0, SpvOpKill)); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_P(ValidateCFG, UnreachableMergeTerminatedByOpReturn) { + CompileSuccessfully(GetUnreachableMergeTerminatedBy( + GetParam(), SPV_ENV_UNIVERSAL_1_0, SpvOpReturn)); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateCFG, WebGPUUnreachableMergeTerminatedByOpUnreachable) { + CompileSuccessfully(GetUnreachableMergeTerminatedBy( + SpvCapabilityShader, SPV_ENV_WEBGPU_0, SpvOpUnreachable)); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); +} + +TEST_F(ValidateCFG, WebGPUUnreachableMergeTerminatedByOpKill) { + CompileSuccessfully(GetUnreachableMergeTerminatedBy( + SpvCapabilityShader, SPV_ENV_WEBGPU_0, SpvOpKill)); + ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("must terminate with OpUnreachable")); +} + +TEST_P(ValidateCFG, WebGPUUnreachableMergeTerminatedByOpReturn) { + CompileSuccessfully(GetUnreachableMergeTerminatedBy( + SpvCapabilityShader, SPV_ENV_WEBGPU_0, SpvOpReturn)); + ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("must terminate with OpUnreachable")); +} + +std::string GetUnreachableContinueTerminatedBy(SpvCapability cap, + spv_target_env env, SpvOp op) { + std::string header = + spvIsWebGPUEnv(env) ? GetWebGPUHeader() : GetDefaultHeader(cap); + + Block entry("entry"); + Block branch("branch", SpvOpBranch); + Block merge("merge", SpvOpReturn); + Block target("target", op); + + if (op == SpvOpBranch) target >> branch; + + std::string str = header; + if (spvIsWebGPUEnv(env)) { + str += + "OpEntryPoint Fragment %func \"func\"\n" + "OpExecutionMode %func OriginUpperLeft\n"; + } + if (cap == SpvCapabilityShader) + branch.AppendBody("OpLoopMerge %merge %target None\n"); + if (!spvIsWebGPUEnv(env)) + str += nameOps("branch", "merge", "target", std::make_pair("func", "Main")); + + str += types_consts(); + str += "%func = OpFunction %voidt None %funct\n"; + str += entry >> branch; + str += branch >> std::vector({merge}); + str += merge; + str += target; + str += "OpFunctionEnd\n"; + + return str; +} + +TEST_P(ValidateCFG, UnreachableContinueTerminatedBySpvOpUnreachable) { + CompileSuccessfully(GetUnreachableContinueTerminatedBy( + GetParam(), SPV_ENV_UNIVERSAL_1_0, SpvOpUnreachable)); + if (GetParam() == SpvCapabilityShader) { + ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("targeted by 0 back-edge blocks")); + } else { + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); + } +} + +TEST_F(ValidateCFG, UnreachableContinueTerminatedBySpvOpKill) { + CompileSuccessfully(GetUnreachableContinueTerminatedBy( + SpvCapabilityShader, SPV_ENV_UNIVERSAL_1_0, SpvOpKill)); + ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("targeted by 0 back-edge blocks")); +} + +TEST_P(ValidateCFG, UnreachableContinueTerminatedBySpvOpReturn) { + CompileSuccessfully(GetUnreachableContinueTerminatedBy( + GetParam(), SPV_ENV_UNIVERSAL_1_0, SpvOpReturn)); + if (GetParam() == SpvCapabilityShader) { + ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("targeted by 0 back-edge blocks")); + } else { + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); + } +} + +TEST_P(ValidateCFG, UnreachableContinueTerminatedBySpvOpBranch) { + CompileSuccessfully(GetUnreachableContinueTerminatedBy( + GetParam(), SPV_ENV_UNIVERSAL_1_0, SpvOpBranch)); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateCFG, WebGPUUnreachableContinueTerminatedBySpvOpUnreachable) { + CompileSuccessfully(GetUnreachableContinueTerminatedBy( + SpvCapabilityShader, SPV_ENV_WEBGPU_0, SpvOpUnreachable)); + ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("For WebGPU, unreachable continue-target must " + "terminate with OpBranch.\n %12 = OpLabel\n")); +} + +TEST_F(ValidateCFG, WebGPUUnreachableContinueTerminatedBySpvOpKill) { + CompileSuccessfully(GetUnreachableContinueTerminatedBy( + SpvCapabilityShader, SPV_ENV_WEBGPU_0, SpvOpKill)); + ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("For WebGPU, unreachable continue-target must " + "terminate with OpBranch.\n %12 = OpLabel\n")); +} + +TEST_F(ValidateCFG, WebGPUUnreachableContinueTerminatedBySpvOpReturn) { + CompileSuccessfully(GetUnreachableContinueTerminatedBy( + SpvCapabilityShader, SPV_ENV_WEBGPU_0, SpvOpReturn)); + ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("For WebGPU, unreachable continue-target must " + "terminate with OpBranch.\n %12 = OpLabel\n")); +} + +TEST_F(ValidateCFG, WebGPUUnreachableContinueTerminatedBySpvOpBranch) { + CompileSuccessfully(GetUnreachableContinueTerminatedBy( + SpvCapabilityShader, SPV_ENV_WEBGPU_0, SpvOpBranch)); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); +} + +std::string GetUnreachableMergeUnreachableMergeInst(SpvCapability cap, + spv_target_env env) { + std::string header = + spvIsWebGPUEnv(env) ? GetWebGPUHeader() : GetDefaultHeader(cap); + + Block body("body", SpvOpReturn); Block entry("entry"); Block branch("branch", SpvOpBranchConditional); Block t("t", SpvOpReturn); @@ -732,13 +954,134 @@ TEST_P(ValidateCFG, UnreachableMergeDefinedByOpUnreachable) { Block merge("merge", SpvOpUnreachable); entry.SetBody("%cond = OpSLessThan %boolt %one %two\n"); - if (is_shader) branch.AppendBody("OpSelectionMerge %merge None\n"); + std::string str = header; + if (spvIsWebGPUEnv(env)) { + str += + "OpEntryPoint Fragment %func \"func\"\n" + "OpExecutionMode %func OriginUpperLeft\n"; + } + if (cap == SpvCapabilityShader) + branch.AppendBody("OpSelectionMerge %merge None\n"); + if (!spvIsWebGPUEnv(env)) + str += nameOps("branch", "merge", std::make_pair("func", "Main")); - std::string str = header(GetParam()) + - nameOps("branch", "merge", std::make_pair("func", "Main")) + - types_consts() + - "%func = OpFunction %voidt None %funct\n"; + str += types_consts(); + str += "%func = OpFunction %voidt None %funct\n"; + str += body; + str += merge; + str += entry >> branch; + str += branch >> std::vector({t, f}); + str += t; + str += f; + str += "OpFunctionEnd\n"; + return str; +} + +TEST_P(ValidateCFG, UnreachableMergeUnreachableMergeInst) { + CompileSuccessfully(GetUnreachableMergeUnreachableMergeInst( + GetParam(), SPV_ENV_UNIVERSAL_1_0)); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateCFG, WebGPUUnreachableMergeUnreachableMergeInst) { + CompileSuccessfully(GetUnreachableMergeUnreachableMergeInst( + SpvCapabilityShader, SPV_ENV_WEBGPU_0)); + ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("must be referenced by a reachable merge instruction")); +} + +std::string GetUnreachableContinueUnreachableLoopInst(SpvCapability cap, + spv_target_env env) { + std::string header = + spvIsWebGPUEnv(env) ? GetWebGPUHeader() : GetDefaultHeader(cap); + + Block body("body", SpvOpReturn); + Block entry("entry"); + Block branch("branch", SpvOpBranch); + Block merge("merge", SpvOpReturn); + Block target("target", SpvOpBranch); + + target >> branch; + + std::string str = header; + if (spvIsWebGPUEnv(env)) { + str += + "OpEntryPoint Fragment %func \"func\"\n" + "OpExecutionMode %func OriginUpperLeft\n"; + } + if (cap == SpvCapabilityShader) + branch.AppendBody("OpLoopMerge %merge %target None\n"); + if (!spvIsWebGPUEnv(env)) + str += nameOps("branch", "merge", "target", std::make_pair("func", "Main")); + + str += types_consts(); + str += "%func = OpFunction %voidt None %funct\n"; + str += body; + str += target; + str += merge; + str += entry >> branch; + str += branch >> std::vector({merge}); + str += "OpFunctionEnd\n"; + + return str; +} + +TEST_P(ValidateCFG, UnreachableContinueUnreachableLoopInst) { + CompileSuccessfully(GetUnreachableContinueUnreachableLoopInst( + GetParam(), SPV_ENV_UNIVERSAL_1_0)); + if (GetParam() == SpvCapabilityShader) { + // Shader causes additional structured CFG checks that cause a failure. + ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Back-edges (1[%branch] -> 3[%target]) can only be " + "formed between a block and a loop header.")); + + } else { + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); + } +} + +TEST_F(ValidateCFG, WebGPUUnreachableContinueUnreachableLoopInst) { + CompileSuccessfully(GetUnreachableContinueUnreachableLoopInst( + SpvCapabilityShader, SPV_ENV_WEBGPU_0)); + ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("must be referenced by a reachable loop instruction")); +} + +std::string GetUnreachableMergeWithComplexBody(SpvCapability cap, + spv_target_env env) { + std::string header = + spvIsWebGPUEnv(env) ? GetWebGPUHeader() : GetDefaultHeader(cap); + + Block entry("entry"); + Block branch("branch", SpvOpBranchConditional); + Block t("t", SpvOpReturn); + Block f("f", SpvOpReturn); + Block merge("merge", SpvOpUnreachable); + + entry.AppendBody(spvIsWebGPUEnv(env) + ? "%dummy = OpVariable %intptrt Function %two\n" + : "%dummy = OpVariable %intptrt Function\n"); + entry.AppendBody("%cond = OpSLessThan %boolt %one %two\n"); + merge.AppendBody("OpStore %dummy %one\n"); + + std::string str = header; + if (spvIsWebGPUEnv(env)) { + str += + "OpEntryPoint Fragment %func \"func\"\n" + "OpExecutionMode %func OriginUpperLeft\n"; + } + if (cap == SpvCapabilityShader) + branch.AppendBody("OpSelectionMerge %merge None\n"); + if (!spvIsWebGPUEnv(env)) + str += nameOps("branch", "merge", std::make_pair("func", "Main")); + + str += types_consts(); + str += "%intptrt = OpTypePointer Function %intt\n"; + str += "%func = OpFunction %voidt None %funct\n"; str += entry >> branch; str += branch >> std::vector({t, f}); str += t; @@ -746,31 +1089,406 @@ TEST_P(ValidateCFG, UnreachableMergeDefinedByOpUnreachable) { str += merge; str += "OpFunctionEnd\n"; - CompileSuccessfully(str); + return str; +} + +TEST_P(ValidateCFG, UnreachableMergeWithComplexBody) { + CompileSuccessfully( + GetUnreachableMergeWithComplexBody(GetParam(), SPV_ENV_UNIVERSAL_1_0)); ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); } -TEST_P(ValidateCFG, UnreachableBlock) { +TEST_F(ValidateCFG, WebGPUUnreachableMergeWithComplexBody) { + CompileSuccessfully(GetUnreachableMergeWithComplexBody(SpvCapabilityShader, + SPV_ENV_WEBGPU_0)); + ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("must only contain an OpLabel and OpUnreachable instruction")); +} + +std::string GetUnreachableContinueWithComplexBody(SpvCapability cap, + spv_target_env env) { + std::string header = + spvIsWebGPUEnv(env) ? GetWebGPUHeader() : GetDefaultHeader(cap); + + Block entry("entry"); + Block branch("branch", SpvOpBranch); + Block merge("merge", SpvOpReturn); + Block target("target", SpvOpBranch); + + target >> branch; + + entry.AppendBody(spvIsWebGPUEnv(env) + ? "%dummy = OpVariable %intptrt Function %two\n" + : "%dummy = OpVariable %intptrt Function\n"); + target.AppendBody("OpStore %dummy %one\n"); + + std::string str = header; + if (spvIsWebGPUEnv(env)) { + str += + "OpEntryPoint Fragment %func \"func\"\n" + "OpExecutionMode %func OriginUpperLeft\n"; + } + if (cap == SpvCapabilityShader) + branch.AppendBody("OpLoopMerge %merge %target None\n"); + if (!spvIsWebGPUEnv(env)) + str += nameOps("branch", "merge", "target", std::make_pair("func", "Main")); + + str += types_consts(); + str += "%intptrt = OpTypePointer Function %intt\n"; + str += "%func = OpFunction %voidt None %funct\n"; + str += entry >> branch; + str += branch >> std::vector({merge}); + str += merge; + str += target; + str += "OpFunctionEnd\n"; + + return str; +} + +TEST_P(ValidateCFG, UnreachableContinueWithComplexBody) { + CompileSuccessfully( + GetUnreachableContinueWithComplexBody(GetParam(), SPV_ENV_UNIVERSAL_1_0)); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateCFG, WebGPUUnreachableContinueWithComplexBody) { + CompileSuccessfully(GetUnreachableContinueWithComplexBody(SpvCapabilityShader, + SPV_ENV_WEBGPU_0)); + ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("must only contain an OpLabel and an OpBranch instruction")); +} + +std::string GetUnreachableMergeWithBranchUse(SpvCapability cap, + spv_target_env env) { + std::string header = + spvIsWebGPUEnv(env) ? GetWebGPUHeader() : GetDefaultHeader(cap); + + Block entry("entry"); + Block branch("branch", SpvOpBranchConditional); + Block t("t", SpvOpBranch); + Block f("f", SpvOpReturn); + Block merge("merge", SpvOpUnreachable); + + entry.AppendBody("%cond = OpSLessThan %boolt %one %two\n"); + + std::string str = header; + if (spvIsWebGPUEnv(env)) { + str += + "OpEntryPoint Fragment %func \"func\"\n" + "OpExecutionMode %func OriginUpperLeft\n"; + } + if (cap == SpvCapabilityShader) + branch.AppendBody("OpSelectionMerge %merge None\n"); + if (!spvIsWebGPUEnv(env)) + str += nameOps("branch", "merge", std::make_pair("func", "Main")); + + str += types_consts(); + str += "%func = OpFunction %voidt None %funct\n"; + str += entry >> branch; + str += branch >> std::vector({t, f}); + str += t >> merge; + str += f; + str += merge; + str += "OpFunctionEnd\n"; + + return str; +} + +TEST_P(ValidateCFG, UnreachableMergeWithBranchUse) { + CompileSuccessfully( + GetUnreachableMergeWithBranchUse(GetParam(), SPV_ENV_UNIVERSAL_1_0)); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateCFG, WebGPUUnreachableMergeWithBranchUse) { + CompileSuccessfully( + GetUnreachableMergeWithBranchUse(SpvCapabilityShader, SPV_ENV_WEBGPU_0)); + ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("cannot be the target of a branch.")); +} + +std::string GetUnreachableMergeWithMultipleUses(SpvCapability cap, + spv_target_env env) { + std::string header = + spvIsWebGPUEnv(env) ? GetWebGPUHeader() : GetDefaultHeader(cap); + + Block entry("entry"); + Block branch("branch", SpvOpBranchConditional); + Block t("t", SpvOpReturn); + Block f("f", SpvOpReturn); + Block merge("merge", SpvOpUnreachable); + Block duplicate("duplicate", SpvOpBranchConditional); + + entry.AppendBody("%cond = OpSLessThan %boolt %one %two\n"); + + std::string str = header; + if (spvIsWebGPUEnv(env)) { + str += + "OpEntryPoint Fragment %func \"func\"\n" + "OpExecutionMode %func OriginUpperLeft\n"; + } + if (cap == SpvCapabilityShader) { + branch.AppendBody("OpSelectionMerge %merge None\n"); + duplicate.AppendBody("OpSelectionMerge %merge None\n"); + } + if (!spvIsWebGPUEnv(env)) + str += nameOps("branch", "merge", std::make_pair("func", "Main")); + + str += types_consts(); + str += "%func = OpFunction %voidt None %funct\n"; + str += entry >> branch; + str += branch >> std::vector({t, f}); + str += duplicate >> std::vector({t, f}); + str += t; + str += f; + str += merge; + str += "OpFunctionEnd\n"; + + return str; +} + +TEST_P(ValidateCFG, UnreachableMergeWithMultipleUses) { + CompileSuccessfully( + GetUnreachableMergeWithMultipleUses(GetParam(), SPV_ENV_UNIVERSAL_1_0)); + if (GetParam() == SpvCapabilityShader) { + ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("is already a merge block for another header")); + } else { + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); + } +} + +TEST_F(ValidateCFG, WebGPUUnreachableMergeWithMultipleUses) { + CompileSuccessfully(GetUnreachableMergeWithMultipleUses(SpvCapabilityShader, + SPV_ENV_WEBGPU_0)); + ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("is already a merge block for another header")); +} + +std::string GetUnreachableContinueWithBranchUse(SpvCapability cap, + spv_target_env env) { + std::string header = + spvIsWebGPUEnv(env) ? GetWebGPUHeader() : GetDefaultHeader(cap); + + Block entry("entry"); + Block foo("foo", SpvOpBranch); + Block branch("branch", SpvOpBranch); + Block merge("merge", SpvOpReturn); + Block target("target", SpvOpBranch); + + foo >> target; + target >> branch; + + entry.AppendBody(spvIsWebGPUEnv(env) + ? "%dummy = OpVariable %intptrt Function %two\n" + : "%dummy = OpVariable %intptrt Function\n"); + + std::string str = header; + if (spvIsWebGPUEnv(env)) { + str += + "OpEntryPoint Fragment %func \"func\"\n" + "OpExecutionMode %func OriginUpperLeft\n"; + } + if (cap == SpvCapabilityShader) + branch.AppendBody("OpLoopMerge %merge %target None\n"); + if (!spvIsWebGPUEnv(env)) + str += nameOps("branch", "merge", "target", std::make_pair("func", "Main")); + + str += types_consts(); + str += "%intptrt = OpTypePointer Function %intt\n"; + str += "%func = OpFunction %voidt None %funct\n"; + str += entry >> branch; + str += branch >> std::vector({merge}); + str += merge; + str += target; + str += foo; + str += "OpFunctionEnd\n"; + + return str; +} + +TEST_P(ValidateCFG, UnreachableContinueWithBranchUse) { + CompileSuccessfully( + GetUnreachableContinueWithBranchUse(GetParam(), SPV_ENV_UNIVERSAL_1_0)); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateCFG, WebGPUUnreachableContinueWithBranchUse) { + CompileSuccessfully(GetUnreachableContinueWithBranchUse(SpvCapabilityShader, + SPV_ENV_WEBGPU_0)); + ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("cannot be the target of a branch.")); +} + +std::string GetReachableMergeAndContinue(SpvCapability cap, + spv_target_env env) { + std::string header = + spvIsWebGPUEnv(env) ? GetWebGPUHeader() : GetDefaultHeader(cap); + + Block entry("entry"); + Block branch("branch", SpvOpBranch); + Block merge("merge", SpvOpReturn); + Block target("target", SpvOpBranch); + Block body("body", SpvOpBranchConditional); + Block t("t", SpvOpBranch); + Block f("f", SpvOpBranch); + + target >> branch; + body.SetBody("%cond = OpSLessThan %boolt %one %two\n"); + t >> merge; + f >> target; + + std::string str = header; + if (spvIsWebGPUEnv(env)) { + str += + "OpEntryPoint Fragment %func \"func\"\n" + "OpExecutionMode %func OriginUpperLeft\n"; + } + if (cap == SpvCapabilityShader) { + branch.AppendBody("OpLoopMerge %merge %target None\n"); + body.AppendBody("OpSelectionMerge %f None\n"); + } + + if (!spvIsWebGPUEnv(env)) + str += nameOps("branch", "merge", "target", "body", "t", "f", + std::make_pair("func", "Main")); + + str += types_consts(); + str += "%func = OpFunction %voidt None %funct\n"; + str += entry >> branch; + str += branch >> std::vector({body}); + str += body >> std::vector({t, f}); + str += t; + str += f; + str += merge; + str += target; + str += "OpFunctionEnd\n"; + + return str; +} + +TEST_P(ValidateCFG, ReachableMergeAndContinue) { + CompileSuccessfully( + GetReachableMergeAndContinue(GetParam(), SPV_ENV_UNIVERSAL_1_0)); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateCFG, WebGPUReachableMergeAndContinue) { + CompileSuccessfully( + GetReachableMergeAndContinue(SpvCapabilityShader, SPV_ENV_WEBGPU_0)); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); +} + +std::string GetUnreachableMergeAndContinue(SpvCapability cap, + spv_target_env env) { + std::string header = + spvIsWebGPUEnv(env) ? GetWebGPUHeader() : GetDefaultHeader(cap); + + Block entry("entry"); + Block branch("branch", SpvOpBranch); + Block merge("merge", SpvOpReturn); + Block target("target", SpvOpBranch); + Block body("body", SpvOpBranchConditional); + Block t("t", SpvOpReturn); + Block f("f", SpvOpReturn); + + target >> branch; + body.SetBody("%cond = OpSLessThan %boolt %one %two\n"); + + std::string str = header; + if (spvIsWebGPUEnv(env)) { + str += + "OpEntryPoint Fragment %func \"func\"\n" + "OpExecutionMode %func OriginUpperLeft\n"; + } + if (cap == SpvCapabilityShader) { + branch.AppendBody("OpLoopMerge %merge %target None\n"); + body.AppendBody("OpSelectionMerge %target None\n"); + } + + if (!spvIsWebGPUEnv(env)) + str += nameOps("branch", "merge", "target", "body", "t", "f", + std::make_pair("func", "Main")); + + str += types_consts(); + str += "%func = OpFunction %voidt None %funct\n"; + str += entry >> branch; + str += branch >> std::vector({body}); + str += body >> std::vector({t, f}); + str += t; + str += f; + str += merge; + str += target; + str += "OpFunctionEnd\n"; + + return str; +} + +TEST_P(ValidateCFG, UnreachableMergeAndContinue) { + CompileSuccessfully( + GetUnreachableMergeAndContinue(GetParam(), SPV_ENV_UNIVERSAL_1_0)); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateCFG, WebGPUUnreachableMergeAndContinue) { + CompileSuccessfully( + GetUnreachableMergeAndContinue(SpvCapabilityShader, SPV_ENV_WEBGPU_0)); + ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("unreachable merge-blocks must terminate with OpUnreachable")); +} + +std::string GetUnreachableBlock(SpvCapability cap, spv_target_env env) { + std::string header = + spvIsWebGPUEnv(env) ? GetWebGPUHeader() : GetDefaultHeader(cap); + Block entry("entry"); Block unreachable("unreachable"); Block exit("exit", SpvOpReturn); - std::string str = - header(GetParam()) + - nameOps("unreachable", "exit", std::make_pair("func", "Main")) + - types_consts() + "%func = OpFunction %voidt None %funct\n"; - + std::string str = header; + if (spvIsWebGPUEnv(env)) { + str += + "OpEntryPoint Fragment %func \"func\"\n" + "OpExecutionMode %func OriginUpperLeft\n"; + } + if (!spvIsWebGPUEnv(env)) + str += nameOps("unreachable", "exit", std::make_pair("func", "Main")); + str += types_consts(); + str += "%func = OpFunction %voidt None %funct\n"; str += entry >> exit; str += unreachable >> exit; str += exit; str += "OpFunctionEnd\n"; - CompileSuccessfully(str); + return str; +} + +TEST_P(ValidateCFG, UnreachableBlock) { + CompileSuccessfully(GetUnreachableBlock(GetParam(), SPV_ENV_UNIVERSAL_1_0)); ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); } -TEST_P(ValidateCFG, UnreachableBranch) { - bool is_shader = GetParam() == SpvCapabilityShader; +TEST_F(ValidateCFG, WebGPUUnreachableBlock) { + CompileSuccessfully( + GetUnreachableBlock(SpvCapabilityShader, SPV_ENV_WEBGPU_0)); + ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT(getDiagnosticString(), HasSubstr("all blocks must be reachable")); +} + +std::string GetUnreachableBranch(SpvCapability cap, spv_target_env env) { + std::string header = + spvIsWebGPUEnv(env) ? GetWebGPUHeader() : GetDefaultHeader(cap); + Block entry("entry"); Block unreachable("unreachable", SpvOpBranchConditional); Block unreachablechildt("unreachablechildt"); @@ -779,11 +1497,19 @@ TEST_P(ValidateCFG, UnreachableBranch) { Block exit("exit", SpvOpReturn); unreachable.SetBody("%cond = OpSLessThan %boolt %one %two\n"); - if (is_shader) unreachable.AppendBody("OpSelectionMerge %merge None\n"); - std::string str = - header(GetParam()) + - nameOps("unreachable", "exit", std::make_pair("func", "Main")) + - types_consts() + "%func = OpFunction %voidt None %funct\n"; + if (cap == SpvCapabilityShader) + unreachable.AppendBody("OpSelectionMerge %merge None\n"); + + std::string str = header; + if (spvIsWebGPUEnv(env)) { + str += + "OpEntryPoint Fragment %func \"func\"\n" + "OpExecutionMode %func OriginUpperLeft\n"; + } + if (!spvIsWebGPUEnv(env)) + str += nameOps("unreachable", "exit", std::make_pair("func", "Main")); + str += types_consts(); + str += "%func = OpFunction %voidt None %funct\n"; str += entry >> exit; str += @@ -794,12 +1520,23 @@ TEST_P(ValidateCFG, UnreachableBranch) { str += exit; str += "OpFunctionEnd\n"; - CompileSuccessfully(str); + return str; +} + +TEST_P(ValidateCFG, UnreachableBranch) { + CompileSuccessfully(GetUnreachableBranch(GetParam(), SPV_ENV_UNIVERSAL_1_0)); ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); } +TEST_F(ValidateCFG, WebGPUUnreachableBranch) { + CompileSuccessfully( + GetUnreachableBranch(SpvCapabilityShader, SPV_ENV_WEBGPU_0)); + ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT(getDiagnosticString(), HasSubstr("all blocks must be reachable")); +} + TEST_P(ValidateCFG, EmptyFunction) { - std::string str = header(GetParam()) + std::string(types_consts()) + + std::string str = GetDefaultHeader(GetParam()) + std::string(types_consts()) + R"(%func = OpFunction %voidt None %funct %l = OpLabel OpReturn @@ -818,7 +1555,7 @@ TEST_P(ValidateCFG, SingleBlockLoop) { entry.SetBody("%cond = OpSLessThan %boolt %one %two\n"); if (is_shader) loop.AppendBody("OpLoopMerge %exit %loop None\n"); - std::string str = header(GetParam()) + std::string(types_consts()) + + std::string str = GetDefaultHeader(GetParam()) + std::string(types_consts()) + "%func = OpFunction %voidt None %funct\n"; str += entry >> loop; @@ -847,8 +1584,8 @@ TEST_P(ValidateCFG, NestedLoops) { loop2.SetBody("OpLoopMerge %loop2_merge %loop2 None\n"); } - std::string str = header(GetParam()) + nameOps("loop2", "loop2_merge") + - types_consts() + + std::string str = GetDefaultHeader(GetParam()) + + nameOps("loop2", "loop2_merge") + types_consts() + "%func = OpFunction %voidt None %funct\n"; str += entry >> loop1; @@ -887,7 +1624,7 @@ TEST_P(ValidateCFG, NestedSelection) { if_blocks[i].SetBody("OpSelectionMerge %if_merge" + ss.str() + " None\n"); merge_blocks.emplace_back("if_merge" + ss.str(), SpvOpBranch); } - std::string str = header(GetParam()) + std::string(types_consts()) + + std::string str = GetDefaultHeader(GetParam()) + std::string(types_consts()) + "%func = OpFunction %voidt None %funct\n"; str += entry >> if_blocks[0]; @@ -912,25 +1649,27 @@ TEST_P(ValidateCFG, BackEdgeBlockDoesntPostDominateContinueTargetBad) { Block entry("entry"); Block loop1("loop1", SpvOpBranchConditional); Block loop2("loop2", SpvOpBranchConditional); - Block loop2_merge("loop2_merge", SpvOpBranchConditional); + Block loop2_merge("loop2_merge"); + Block loop1_cont("loop1_cont", SpvOpBranchConditional); Block be_block("be_block"); Block exit("exit", SpvOpReturn); entry.SetBody("%cond = OpSLessThan %boolt %one %two\n"); if (is_shader) { - loop1.SetBody("OpLoopMerge %exit %loop2_merge None\n"); + loop1.SetBody("OpLoopMerge %exit %loop1_cont None\n"); loop2.SetBody("OpLoopMerge %loop2_merge %loop2 None\n"); } - std::string str = header(GetParam()) + - nameOps("loop1", "loop2", "be_block", "loop2_merge") + - types_consts() + - "%func = OpFunction %voidt None %funct\n"; + std::string str = + GetDefaultHeader(GetParam()) + + nameOps("loop1", "loop2", "be_block", "loop1_cont", "loop2_merge") + + types_consts() + "%func = OpFunction %voidt None %funct\n"; str += entry >> loop1; str += loop1 >> std::vector({loop2, exit}); str += loop2 >> std::vector({loop2, loop2_merge}); - str += loop2_merge >> std::vector({be_block, exit}); + str += loop2_merge >> loop1_cont; + str += loop1_cont >> std::vector({be_block, exit}); str += be_block >> loop1; str += exit; str += "OpFunctionEnd"; @@ -940,8 +1679,8 @@ TEST_P(ValidateCFG, BackEdgeBlockDoesntPostDominateContinueTargetBad) { ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), MatchesRegex("The continue construct with the continue target " - ".\\[loop2_merge\\] is not post dominated by the " - "back-edge block .\\[be_block\\]\n" + ".\\[%loop1_cont\\] is not post dominated by the " + "back-edge block .\\[%be_block\\]\n" " %be_block = OpLabel\n")); } else { ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); @@ -959,7 +1698,7 @@ TEST_P(ValidateCFG, BranchingToNonLoopHeaderBlockBad) { entry.SetBody("%cond = OpSLessThan %boolt %one %two\n"); if (is_shader) split.SetBody("OpSelectionMerge %exit None\n"); - std::string str = header(GetParam()) + nameOps("split", "f") + + std::string str = GetDefaultHeader(GetParam()) + nameOps("split", "f") + types_consts() + "%func = OpFunction %voidt None %funct\n"; @@ -975,7 +1714,7 @@ TEST_P(ValidateCFG, BranchingToNonLoopHeaderBlockBad) { ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), - MatchesRegex("Back-edges \\(.\\[f\\] -> .\\[split\\]\\) can only " + MatchesRegex("Back-edges \\(.\\[%f\\] -> .\\[%split\\]\\) can only " "be formed between a block and a loop header.\n" " %f = OpLabel\n")); } else { @@ -992,7 +1731,8 @@ TEST_P(ValidateCFG, BranchingToSameNonLoopHeaderBlockBad) { entry.SetBody("%cond = OpSLessThan %boolt %one %two\n"); if (is_shader) split.SetBody("OpSelectionMerge %exit None\n"); - std::string str = header(GetParam()) + nameOps("split") + types_consts() + + std::string str = GetDefaultHeader(GetParam()) + nameOps("split") + + types_consts() + "%func = OpFunction %voidt None %funct\n"; str += entry >> split; @@ -1003,11 +1743,11 @@ TEST_P(ValidateCFG, BranchingToSameNonLoopHeaderBlockBad) { CompileSuccessfully(str); if (is_shader) { ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), - MatchesRegex( - "Back-edges \\(.\\[split\\] -> .\\[split\\]\\) can only be " - "formed between a block and a loop header.\n" - " %split = OpLabel\n")); + EXPECT_THAT( + getDiagnosticString(), + MatchesRegex( + "Back-edges \\(.\\[%split\\] -> .\\[%split\\]\\) can only be " + "formed between a block and a loop header.\n %split = OpLabel\n")); } else { ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); } @@ -1024,8 +1764,8 @@ TEST_P(ValidateCFG, MultipleBackEdgeBlocksToLoopHeaderBad) { entry.SetBody("%cond = OpSLessThan %boolt %one %two\n"); if (is_shader) loop.SetBody("OpLoopMerge %merge %back0 None\n"); - std::string str = header(GetParam()) + nameOps("loop", "back0", "back1") + - types_consts() + + std::string str = GetDefaultHeader(GetParam()) + + nameOps("loop", "back0", "back1") + types_consts() + "%func = OpFunction %voidt None %funct\n"; str += entry >> loop; @@ -1038,11 +1778,11 @@ TEST_P(ValidateCFG, MultipleBackEdgeBlocksToLoopHeaderBad) { CompileSuccessfully(str); if (is_shader) { ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), - MatchesRegex( - "Loop header .\\[loop\\] is targeted by 2 back-edge blocks " - "but the standard requires exactly one\n" - " %loop = OpLabel\n")) + EXPECT_THAT( + getDiagnosticString(), + MatchesRegex( + "Loop header .\\[%loop\\] is targeted by 2 back-edge blocks but " + "the standard requires exactly one\n %loop = OpLabel\n")) << str; } else { ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); @@ -1061,8 +1801,8 @@ TEST_P(ValidateCFG, ContinueTargetMustBePostDominatedByBackEdge) { entry.SetBody("%cond = OpSLessThan %boolt %one %two\n"); if (is_shader) loop.SetBody("OpLoopMerge %merge %cheader None\n"); - std::string str = header(GetParam()) + nameOps("cheader", "be_block") + - types_consts() + + std::string str = GetDefaultHeader(GetParam()) + + nameOps("cheader", "be_block") + types_consts() + "%func = OpFunction %voidt None %funct\n"; str += entry >> loop; @@ -1078,8 +1818,8 @@ TEST_P(ValidateCFG, ContinueTargetMustBePostDominatedByBackEdge) { ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), MatchesRegex("The continue construct with the continue target " - ".\\[cheader\\] is not post dominated by the " - "back-edge block .\\[be_block\\]\n" + ".\\[%cheader\\] is not post dominated by the " + "back-edge block .\\[%be_block\\]\n" " %be_block = OpLabel\n")); } else { ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); @@ -1096,7 +1836,7 @@ TEST_P(ValidateCFG, BranchOutOfConstructToMergeBad) { entry.SetBody("%cond = OpSLessThan %boolt %one %two\n"); if (is_shader) loop.SetBody("OpLoopMerge %merge %loop None\n"); - std::string str = header(GetParam()) + nameOps("cont", "loop") + + std::string str = GetDefaultHeader(GetParam()) + nameOps("cont", "loop") + types_consts() + "%func = OpFunction %voidt None %funct\n"; @@ -1111,8 +1851,8 @@ TEST_P(ValidateCFG, BranchOutOfConstructToMergeBad) { ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), MatchesRegex("The continue construct with the continue target " - ".\\[loop\\] is not post dominated by the " - "back-edge block .\\[cont\\]\n" + ".\\[%loop\\] is not post dominated by the " + "back-edge block .\\[%cont\\]\n" " %cont = OpLabel\n")) << str; } else { @@ -1131,7 +1871,7 @@ TEST_P(ValidateCFG, BranchOutOfConstructBad) { entry.SetBody("%cond = OpSLessThan %boolt %one %two\n"); if (is_shader) loop.SetBody("OpLoopMerge %merge %loop None\n"); - std::string str = header(GetParam()) + nameOps("cont", "loop") + + std::string str = GetDefaultHeader(GetParam()) + nameOps("cont", "loop") + types_consts() + "%func = OpFunction %voidt None %funct\n"; @@ -1147,8 +1887,8 @@ TEST_P(ValidateCFG, BranchOutOfConstructBad) { ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), MatchesRegex("The continue construct with the continue target " - ".\\[loop\\] is not post dominated by the " - "back-edge block .\\[cont\\]\n" + ".\\[%loop\\] is not post dominated by the " + "back-edge block .\\[%cont\\]\n" " %cont = OpLabel\n")); } else { ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); @@ -1206,12 +1946,13 @@ TEST_F(ValidateCFG, LoopWithZeroBackEdgesBad) { OpCapability Shader OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %main "main" + OpExecutionMode %main OriginUpperLeft OpName %loop "loop" %voidt = OpTypeVoid %funct = OpTypeFunction %voidt %main = OpFunction %voidt None %funct %loop = OpLabel - OpLoopMerge %exit %exit None + OpLoopMerge %exit %loop None OpBranch %exit %exit = OpLabel OpReturn @@ -1221,7 +1962,7 @@ TEST_F(ValidateCFG, LoopWithZeroBackEdgesBad) { ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), - MatchesRegex("Loop header .\\[loop\\] is targeted by " + MatchesRegex("Loop header .\\[%loop\\] is targeted by " "0 back-edge blocks but the standard requires exactly " "one\n %loop = OpLabel\n")); } @@ -1231,6 +1972,7 @@ TEST_F(ValidateCFG, LoopWithBackEdgeFromUnreachableContinueConstructGood) { OpCapability Shader OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %main "main" + OpExecutionMode %main OriginUpperLeft OpName %loop "loop" %voidt = OpTypeVoid %funct = OpTypeFunction %voidt @@ -1280,7 +2022,7 @@ TEST_P(ValidateCFG, inner_head.SetBody("OpSelectionMerge %inner_merge None\n"); } - std::string str = header(GetParam()) + + std::string str = GetDefaultHeader(GetParam()) + nameOps("entry", "inner_merge", "exit") + types_consts() + "%func = OpFunction %voidt None %funct\n"; @@ -1296,13 +2038,10 @@ TEST_P(ValidateCFG, EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()) << getDiagnosticString(); } -TEST_P(ValidateCFG, ContinueTargetCanBeMergeBlockForNestedStructureGood) { - // This example is valid. It shows that the validator can't just add - // an edge from the loop head to the continue target. If that edge - // is added, then the "if_merge" block is both the continue target - // for the loop and also the merge block for the nested selection, but - // then it wouldn't be dominated by "if_head", the header block for the - // nested selection. +TEST_P(ValidateCFG, ContinueTargetCanBeMergeBlockForNestedStructure) { + // The continue construct cannot be the merge target of a nested selection + // because the loop construct must contain "if_merge" because it contains + // "if_head". bool is_shader = GetParam() == SpvCapabilityShader; Block entry("entry"); Block loop("loop"); @@ -1318,7 +2057,7 @@ TEST_P(ValidateCFG, ContinueTargetCanBeMergeBlockForNestedStructureGood) { } std::string str = - header(GetParam()) + + GetDefaultHeader(GetParam()) + nameOps("entry", "loop", "if_head", "if_true", "if_merge", "merge") + types_consts() + "%func = OpFunction %voidt None %funct\n"; @@ -1331,7 +2070,16 @@ TEST_P(ValidateCFG, ContinueTargetCanBeMergeBlockForNestedStructureGood) { str += "OpFunctionEnd"; CompileSuccessfully(str); - EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()) << getDiagnosticString(); + if (is_shader) { + EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Header block 3[%if_head] is contained in the loop construct " + "headed " + "by 2[%loop], but its merge block 5[%if_merge] is not")); + } else { + EXPECT_THAT(SPV_SUCCESS, ValidateInstructions()); + } } TEST_P(ValidateCFG, SingleLatchBlockMultipleBranchesToLoopHeader) { @@ -1348,9 +2096,10 @@ TEST_P(ValidateCFG, SingleLatchBlockMultipleBranchesToLoopHeader) { loop.SetBody("OpLoopMerge %merge %latch None\n"); } - std::string str = - header(GetParam()) + nameOps("entry", "loop", "latch", "merge") + - types_consts() + "%func = OpFunction %voidt None %funct\n"; + std::string str = GetDefaultHeader(GetParam()) + + nameOps("entry", "loop", "latch", "merge") + + types_consts() + + "%func = OpFunction %voidt None %funct\n"; str += entry >> loop; str += loop >> std::vector({latch, merge}); @@ -1381,9 +2130,10 @@ TEST_P(ValidateCFG, SingleLatchBlockHeaderContinueTargetIsItselfGood) { loop.SetBody("OpLoopMerge %merge %loop None\n"); } - std::string str = - header(GetParam()) + nameOps("entry", "loop", "latch", "merge") + - types_consts() + "%func = OpFunction %voidt None %funct\n"; + std::string str = GetDefaultHeader(GetParam()) + + nameOps("entry", "loop", "latch", "merge") + + types_consts() + + "%func = OpFunction %voidt None %funct\n"; str += entry >> loop; str += loop >> latch; @@ -1465,6 +2215,7 @@ TEST_F(ValidateCFG, StructuredCFGBranchIntoSelectionBody) { OpCapability Shader OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft %void = OpTypeVoid %bool = OpTypeBool %true = OpConstantTrue %bool @@ -1564,8 +2315,8 @@ OpFunctionEnd EXPECT_THAT( getDiagnosticString(), HasSubstr( - "Case construct that targets 10 has branches to multiple other case " - "construct targets 12 and 11\n %10 = OpLabel")); + "Case construct that targets 10[%10] has branches to multiple other " + "case construct targets 12[%12] and 11[%11]\n %10 = OpLabel")); } TEST_F(ValidateCFG, MultipleFallThroughToDefault) { @@ -1599,7 +2350,7 @@ OpFunctionEnd EXPECT_THAT( getDiagnosticString(), HasSubstr("Multiple case constructs have branches to the case construct " - "that targets 10\n %10 = OpLabel")); + "that targets 10[%10]\n %10 = OpLabel")); } TEST_F(ValidateCFG, MultipleFallThroughToNonDefault) { @@ -1633,7 +2384,7 @@ OpFunctionEnd EXPECT_THAT( getDiagnosticString(), HasSubstr("Multiple case constructs have branches to the case construct " - "that targets 12\n %12 = OpLabel")); + "that targets 12[%12]\n %12 = OpLabel")); } TEST_F(ValidateCFG, DuplicateTargetWithFallThrough) { @@ -1694,8 +2445,8 @@ OpFunctionEnd ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), - HasSubstr("Case construct that targets 12 has branches to the case " - "construct that targets 11, but does not immediately " + HasSubstr("Case construct that targets 12[%12] has branches to the case " + "construct that targets 11[%11], but does not immediately " "precede it in the OpSwitch's target list\n" " OpSwitch %uint_0 %10 0 %11 1 %12")); } @@ -1730,8 +2481,8 @@ OpFunctionEnd ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), - HasSubstr("Case construct that targets 12 has branches to the case " - "construct that targets 11, but does not immediately " + HasSubstr("Case construct that targets 12[%12] has branches to the case " + "construct that targets 11[%11], but does not immediately " "precede it in the OpSwitch's target list\n" " OpSwitch %uint_0 %10 0 %11 1 %12")); } @@ -1768,17 +2519,52 @@ OpFunctionEnd ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), - HasSubstr("Case construct that targets 12 has branches to the case " - "construct that targets 11, but does not immediately " + HasSubstr("Case construct that targets 12[%12] has branches to the case " + "construct that targets 11[%11], but does not immediately " "precede it in the OpSwitch's target list\n" " OpSwitch %uint_0 %10 0 %11 1 %12 2 %13")); } +TEST_F(ValidateCFG, GoodUnreachableSwitch) { + const std::string text = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %2 "main" +OpExecutionMode %2 OriginUpperLeft +%3 = OpTypeVoid +%4 = OpTypeFunction %3 +%5 = OpTypeBool +%6 = OpConstantTrue %5 +%7 = OpTypeInt 32 1 +%9 = OpConstant %7 0 +%2 = OpFunction %3 None %4 +%10 = OpLabel +OpSelectionMerge %11 None +OpBranchConditional %6 %12 %13 +%12 = OpLabel +OpReturn +%13 = OpLabel +OpReturn +%11 = OpLabel +OpSelectionMerge %14 None +OpSwitch %9 %14 0 %15 +%15 = OpLabel +OpBranch %14 +%14 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_THAT(SPV_SUCCESS, ValidateInstructions()); +} + TEST_F(ValidateCFG, InvalidCaseExit) { const std::string text = R"( OpCapability Shader OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %1 "func" +OpExecutionMode %1 OriginUpperLeft %2 = OpTypeVoid %3 = OpTypeInt 32 0 %4 = OpTypeFunction %2 @@ -1801,9 +2587,10 @@ OpFunctionEnd CompileSuccessfully(text); ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("Case construct that targets 8 has invalid branch to " - "block 10 (not another case construct, corresponding " - "merge, outer loop merge or outer loop continue")); + HasSubstr("Case construct that targets 8[%8] has invalid branch " + "to block 10[%10] (not another case construct, " + "corresponding merge, outer loop merge or outer loop " + "continue)")); } TEST_F(ValidateCFG, GoodCaseExitsToOuterConstructs) { @@ -1811,6 +2598,7 @@ TEST_F(ValidateCFG, GoodCaseExitsToOuterConstructs) { OpCapability Shader OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft %void = OpTypeVoid %bool = OpTypeBool %true = OpConstantTrue %bool @@ -1841,7 +2629,1672 @@ OpFunctionEnd ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); } -/// TODO(umar): Nested CFG constructs +TEST_F(ValidateCFG, SwitchCaseOrderingBad1) { + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpName %default "default" +OpName %other "other" +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%undef = OpUndef %int +%void_fn = OpTypeFunction %void +%func = OpFunction %void None %void_fn +%entry = OpLabel +OpSelectionMerge %merge None +OpSwitch %undef %default 0 %other 1 %default +%default = OpLabel +OpBranch %other +%other = OpLabel +OpBranch %merge +%merge = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Case construct that targets 1[%default] has branches to the " + "case construct that targets 2[%other], but does not " + "immediately precede it in the OpSwitch's target list")); +} + +TEST_F(ValidateCFG, SwitchCaseOrderingBad2) { + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpName %default "default" +OpName %other "other" +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%undef = OpUndef %int +%void_fn = OpTypeFunction %void +%func = OpFunction %void None %void_fn +%entry = OpLabel +OpSelectionMerge %merge None +OpSwitch %undef %default 0 %default 1 %other +%other = OpLabel +OpBranch %default +%default = OpLabel +OpBranch %merge +%merge = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Case construct that targets 2[%other] has branches to the " + "case construct that targets 1[%default], but does not " + "immediately precede it in the OpSwitch's target list")); +} + +TEST_F(ValidateCFG, SwitchMultipleDefaultWithFallThroughGood) { + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpName %first "first" +OpName %second "second" +OpName %third "third" +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%undef = OpUndef %int +%void_fn = OpTypeFunction %void +%func = OpFunction %void None %void_fn +%entry = OpLabel +OpSelectionMerge %merge None +OpSwitch %undef %second 0 %first 1 %second 2 %third +%first = OpLabel +OpBranch %second +%second = OpLabel +OpBranch %third +%third = OpLabel +OpBranch %merge +%merge = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateCFG, SwitchMultipleDefaultWithFallThroughBad) { + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpName %first "first" +OpName %second "second" +OpName %third "third" +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%undef = OpUndef %int +%void_fn = OpTypeFunction %void +%func = OpFunction %void None %void_fn +%entry = OpLabel +OpSelectionMerge %merge None +OpSwitch %undef %second 0 %second 1 %first 2 %third +%first = OpLabel +OpBranch %second +%second = OpLabel +OpBranch %third +%third = OpLabel +OpBranch %merge +%merge = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); +} + +TEST_F(ValidateCFG, GoodUnreachableSelection) { + const std::string text = R"( +OpCapability Shader +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +%void = OpTypeVoid +%8 = OpTypeFunction %void +%bool = OpTypeBool +%false = OpConstantFalse %bool +%main = OpFunction %void None %8 +%15 = OpLabel +OpBranch %16 +%16 = OpLabel +OpLoopMerge %17 %18 None +OpBranch %19 +%19 = OpLabel +OpBranchConditional %false %21 %17 +%21 = OpLabel +OpSelectionMerge %22 None +OpBranchConditional %false %23 %22 +%23 = OpLabel +OpBranch %24 +%24 = OpLabel +OpLoopMerge %25 %26 None +OpBranch %27 +%27 = OpLabel +OpReturn +%26 = OpLabel +OpBranchConditional %false %24 %25 +%25 = OpLabel +OpSelectionMerge %28 None +OpBranchConditional %false %18 %28 +%28 = OpLabel +OpBranch %22 +%22 = OpLabel +OpBranch %18 +%18 = OpLabel +OpBranch %16 +%17 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateCFG, ShaderWithPhiPtr) { + const std::string text = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "main" + OpExecutionMode %1 LocalSize 1 1 1 + OpSource HLSL 600 + %bool = OpTypeBool +%_ptr_Function_bool = OpTypePointer Function %bool + %void = OpTypeVoid + %5 = OpTypeFunction %void + %1 = OpFunction %void None %5 + %6 = OpLabel + %7 = OpVariable %_ptr_Function_bool Function + %8 = OpVariable %_ptr_Function_bool Function + %9 = OpUndef %bool + OpSelectionMerge %10 None + OpBranchConditional %9 %11 %10 + %11 = OpLabel + OpBranch %10 + %10 = OpLabel + %12 = OpPhi %_ptr_Function_bool %7 %6 %8 %11 + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Using pointers with OpPhi requires capability " + "VariablePointers or VariablePointersStorageBuffer")); +} + +TEST_F(ValidateCFG, VarPtrShaderWithPhiPtr) { + const std::string text = R"( + OpCapability Shader + OpCapability VariablePointers + OpExtension "SPV_KHR_variable_pointers" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "main" + OpExecutionMode %1 LocalSize 1 1 1 + OpSource HLSL 600 + %bool = OpTypeBool +%_ptr_Function_bool = OpTypePointer Function %bool + %void = OpTypeVoid + %5 = OpTypeFunction %void + %1 = OpFunction %void None %5 + %6 = OpLabel + %7 = OpVariable %_ptr_Function_bool Function + %8 = OpVariable %_ptr_Function_bool Function + %9 = OpUndef %bool + OpSelectionMerge %10 None + OpBranchConditional %9 %11 %10 + %11 = OpLabel + OpBranch %10 + %10 = OpLabel + %12 = OpPhi %_ptr_Function_bool %7 %6 %8 %11 + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateCFG, VarPtrStgBufShaderWithPhiStgBufPtr) { + const std::string text = R"( + OpCapability Shader + OpCapability VariablePointersStorageBuffer + OpExtension "SPV_KHR_variable_pointers" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "main" + OpExecutionMode %1 LocalSize 1 1 1 + OpSource HLSL 600 + %bool = OpTypeBool + %float = OpTypeFloat 32 +%_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float + %7 = OpVariable %_ptr_StorageBuffer_float StorageBuffer + %8 = OpVariable %_ptr_StorageBuffer_float StorageBuffer + %void = OpTypeVoid + %5 = OpTypeFunction %void + %1 = OpFunction %void None %5 + %6 = OpLabel + %9 = OpUndef %bool + OpSelectionMerge %10 None + OpBranchConditional %9 %11 %10 + %11 = OpLabel + OpBranch %10 + %10 = OpLabel + %12 = OpPhi %_ptr_StorageBuffer_float %7 %6 %8 %11 + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateCFG, KernelWithPhiPtr) { + const std::string text = R"( + OpCapability Kernel + OpCapability Addresses + OpMemoryModel Physical32 OpenCL + OpEntryPoint Kernel %1 "main" + OpExecutionMode %1 LocalSize 1 1 1 + OpSource HLSL 600 + %bool = OpTypeBool +%_ptr_Function_bool = OpTypePointer Function %bool + %void = OpTypeVoid + %5 = OpTypeFunction %void + %1 = OpFunction %void None %5 + %6 = OpLabel + %7 = OpVariable %_ptr_Function_bool Function + %8 = OpVariable %_ptr_Function_bool Function + %9 = OpUndef %bool + OpSelectionMerge %10 None + OpBranchConditional %9 %11 %10 + %11 = OpLabel + OpBranch %10 + %10 = OpLabel + %12 = OpPhi %_ptr_Function_bool %7 %6 %8 %11 + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateCFG, SwitchTargetMustBeLabel) { + const std::string text = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "foo" + %uint = OpTypeInt 32 0 + %uint_0 = OpConstant %uint 0 + %void = OpTypeVoid + %5 = OpTypeFunction %void + %1 = OpFunction %void None %5 + %6 = OpLabel + %7 = OpCopyObject %uint %uint_0 + OpSelectionMerge %8 None + OpSwitch %uint_0 %8 0 %7 + %8 = OpLabel + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("'Target Label' operands for OpSwitch must " + "be IDs of an OpLabel instruction")); +} + +TEST_F(ValidateCFG, BranchTargetMustBeLabel) { + const std::string text = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "foo" + %uint = OpTypeInt 32 0 + %uint_0 = OpConstant %uint 0 + %void = OpTypeVoid + %5 = OpTypeFunction %void + %1 = OpFunction %void None %5 + %2 = OpLabel + %7 = OpCopyObject %uint %uint_0 + OpBranch %7 + %8 = OpLabel + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("'Target Label' operands for OpBranch must " + "be the ID of an OpLabel instruction")); +} + +TEST_F(ValidateCFG, ReachableOpUnreachableOneBlock) { + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%func = OpFunction %void None %void_fn +%entry = OpLabel +OpUnreachable +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateCFG, ReachableOpUnreachableOpBranch) { + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%func = OpFunction %void None %void_fn +%entry = OpLabel +OpBranch %block +%block = OpLabel +OpUnreachable +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateCFG, ReachableOpUnreachableOpBranchConditional) { + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%bool = OpTypeBool +%undef = OpUndef %bool +%func = OpFunction %void None %void_fn +%entry = OpLabel +OpSelectionMerge %block None +OpBranchConditional %undef %block %unreachable +%block = OpLabel +OpReturn +%unreachable = OpLabel +OpUnreachable +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateCFG, ReachableOpUnreachableOpSwitch) { + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%int = OpTypeInt 32 0 +%undef = OpUndef %int +%func = OpFunction %void None %void_fn +%entry = OpLabel +OpSelectionMerge %block1 None +OpSwitch %undef %block1 0 %unreachable 1 %block2 +%block1 = OpLabel +OpReturn +%unreachable = OpLabel +OpUnreachable +%block2 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateCFG, ReachableOpUnreachableLoop) { + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%bool = OpTypeBool +%undef = OpUndef %bool +%func = OpFunction %void None %void_fn +%entry = OpLabel +OpBranch %loop +%loop = OpLabel +OpLoopMerge %unreachable %loop None +OpBranchConditional %undef %loop %unreachable +%unreachable = OpLabel +OpUnreachable +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateCFG, UnreachableLoopBadBackedge) { + const std::string text = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %2 "main" +OpExecutionMode %2 OriginUpperLeft +%4 = OpTypeVoid +%5 = OpTypeFunction %4 +%8 = OpTypeBool +%13 = OpConstantTrue %8 +%2 = OpFunction %4 None %5 +%14 = OpLabel +OpSelectionMerge %15 None +OpBranchConditional %13 %15 %15 +%16 = OpLabel +OpLoopMerge %17 %18 None +OpBranch %17 +%18 = OpLabel +OpBranch %17 +%17 = OpLabel +OpBranch %15 +%15 = OpLabel +OpReturn +OpFunctionEnd +)"; + + // The back-edge in this test is bad, but the validator fails to identify it + // because it is in an entirely unreachable section of code. Prior to #2488 + // this code failed an assert in Construct::blocks(). + CompileSuccessfully(text); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateCFG, OneContinueTwoBackedges) { + const std::string text = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %1 "main" +OpExecutionMode %1 LocalSize 1 1 1 +%void = OpTypeVoid +%bool = OpTypeBool +%true = OpConstantTrue %bool +%5 = OpTypeFunction %void +%1 = OpFunction %void None %5 +%6 = OpLabel +OpBranch %7 +%7 = OpLabel +OpLoopMerge %8 %9 None +OpBranch %10 +%10 = OpLabel +OpLoopMerge %11 %9 None +OpBranchConditional %true %11 %9 +%9 = OpLabel +OpBranchConditional %true %10 %7 +%11 = OpLabel +OpBranch %8 +%8 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("block 9 branches to the loop construct, but not " + "to the loop header 7")); +} + +TEST_F(ValidateCFG, LoopMergeMergeBlockNotLabel) { + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpName %undef "undef" +%void = OpTypeVoid +%bool = OpTypeBool +%undef = OpUndef %bool +%void_fn = OpTypeFunction %void +%func = OpFunction %void None %void_fn +%1 = OpLabel +OpLoopMerge %undef %2 None +OpBranchConditional %undef %2 %2 +%2 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Merge Block 1[%undef] must be an OpLabel")); +} + +TEST_F(ValidateCFG, LoopMergeContinueTargetNotLabel) { + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpName %undef "undef" +%void = OpTypeVoid +%bool = OpTypeBool +%undef = OpUndef %bool +%void_fn = OpTypeFunction %void +%func = OpFunction %void None %void_fn +%1 = OpLabel +OpLoopMerge %2 %undef None +OpBranchConditional %undef %2 %2 +%2 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Continue Target 1[%undef] must be an OpLabel")); +} + +TEST_F(ValidateCFG, LoopMergeMergeBlockContinueTargetSameLabel) { + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpName %undef "undef" +%void = OpTypeVoid +%bool = OpTypeBool +%undef = OpUndef %bool +%void_fn = OpTypeFunction %void +%func = OpFunction %void None %void_fn +%1 = OpLabel +OpLoopMerge %2 %2 None +OpBranchConditional %undef %2 %2 +%2 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Merge Block and Continue Target must be different ids")); +} + +TEST_F(ValidateCFG, LoopMergeUnrollAndDontUnroll) { + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpName %undef "undef" +%void = OpTypeVoid +%bool = OpTypeBool +%undef = OpUndef %bool +%void_fn = OpTypeFunction %void +%func = OpFunction %void None %void_fn +%5 = OpLabel +OpBranch %1 +%1 = OpLabel +OpLoopMerge %2 %3 Unroll|DontUnroll +OpBranchConditional %undef %2 %3 +%3 = OpLabel +OpBranch %1 +%2 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "Unroll and DontUnroll loop controls must not both be specified")); +} + +TEST_F(ValidateCFG, LoopMergePeelCountAndDontUnroll) { + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpName %undef "undef" +%void = OpTypeVoid +%bool = OpTypeBool +%undef = OpUndef %bool +%void_fn = OpTypeFunction %void +%func = OpFunction %void None %void_fn +%5 = OpLabel +OpBranch %1 +%1 = OpLabel +OpLoopMerge %2 %3 DontUnroll|PeelCount 1 +OpBranchConditional %undef %2 %3 +%3 = OpLabel +OpBranch %1 +%2 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "PeelCount and DontUnroll loop controls must not both be specified")); +} + +TEST_F(ValidateCFG, LoopMergePartialCountAndDontUnroll) { + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpName %undef "undef" +%void = OpTypeVoid +%bool = OpTypeBool +%undef = OpUndef %bool +%void_fn = OpTypeFunction %void +%func = OpFunction %void None %void_fn +%5 = OpLabel +OpBranch %1 +%1 = OpLabel +OpLoopMerge %2 %3 DontUnroll|PartialCount 1 +OpBranchConditional %undef %2 %3 +%3 = OpLabel +OpBranch %1 +%2 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("PartialCount and DontUnroll loop controls must not " + "both be specified")); +} + +TEST_F(ValidateCFG, LoopMergeIterationMultipleZero) { + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpName %undef "undef" +%void = OpTypeVoid +%bool = OpTypeBool +%undef = OpUndef %bool +%void_fn = OpTypeFunction %void +%func = OpFunction %void None %void_fn +%5 = OpLabel +OpBranch %1 +%1 = OpLabel +OpLoopMerge %2 %3 IterationMultiple 0 +OpBranchConditional %undef %2 %3 +%3 = OpLabel +OpBranch %1 +%2 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "IterationMultiple loop control operand must be greater than zero")); +} + +TEST_F(ValidateCFG, LoopMergeIterationMultipleZeroMoreOperands) { + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpName %undef "undef" +%void = OpTypeVoid +%bool = OpTypeBool +%undef = OpUndef %bool +%void_fn = OpTypeFunction %void +%func = OpFunction %void None %void_fn +%5 = OpLabel +OpBranch %1 +%1 = OpLabel +OpLoopMerge %2 %3 MaxIterations|IterationMultiple 4 0 +OpBranchConditional %undef %2 %3 +%3 = OpLabel +OpBranch %1 +%2 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "IterationMultiple loop control operand must be greater than zero")); +} + +TEST_F(ValidateCFG, LoopMergeTargetsHeader) { + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%bool = OpTypeBool +%undef = OpUndef %bool +%void_fn = OpTypeFunction %void +%fn = OpFunction %void None %void_fn +%entry = OpLabel +OpBranch %loop +%loop = OpLabel +OpLoopMerge %loop %continue None +OpBranch %body +%continue = OpLabel +OpBranch %loop +%body = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Merge Block may not be the block containing the OpLoopMerge")); +} + +TEST_F(ValidateCFG, InvalidSelectionExit) { + const std::string text = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %1 "main" +OpExecutionMode %1 OriginUpperLeft +%2 = OpTypeVoid +%3 = OpTypeBool +%4 = OpConstantTrue %3 +%5 = OpTypeFunction %2 +%1 = OpFunction %2 None %5 +%6 = OpLabel +OpSelectionMerge %7 None +OpBranchConditional %4 %7 %8 +%8 = OpLabel +OpSelectionMerge %9 None +OpBranchConditional %4 %10 %9 +%10 = OpLabel +OpBranch %7 +%9 = OpLabel +OpBranch %7 +%7 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("block 10[%10] exits the selection headed by " + "8[%8], but not via a structured exit")); +} + +TEST_F(ValidateCFG, InvalidLoopExit) { + const std::string text = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %1 "main" +OpExecutionMode %1 OriginUpperLeft +%2 = OpTypeVoid +%3 = OpTypeBool +%4 = OpConstantTrue %3 +%5 = OpTypeFunction %2 +%1 = OpFunction %2 None %5 +%6 = OpLabel +OpSelectionMerge %7 None +OpBranchConditional %4 %7 %8 +%8 = OpLabel +OpLoopMerge %9 %10 None +OpBranchConditional %4 %9 %11 +%11 = OpLabel +OpBranchConditional %4 %7 %10 +%10 = OpLabel +OpBranch %8 +%9 = OpLabel +OpBranch %7 +%7 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("block 11[%11] exits the loop headed by " + "8[%8], but not via a structured exit")); +} + +TEST_F(ValidateCFG, InvalidContinueExit) { + const std::string text = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %1 "main" +OpExecutionMode %1 OriginUpperLeft +%2 = OpTypeVoid +%3 = OpTypeBool +%4 = OpConstantTrue %3 +%5 = OpTypeFunction %2 +%1 = OpFunction %2 None %5 +%6 = OpLabel +OpSelectionMerge %7 None +OpBranchConditional %4 %7 %8 +%8 = OpLabel +OpLoopMerge %9 %10 None +OpBranchConditional %4 %9 %10 +%10 = OpLabel +OpBranch %11 +%11 = OpLabel +OpBranchConditional %4 %8 %7 +%9 = OpLabel +OpBranch %7 +%7 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("block 11[%11] exits the continue headed by " + "10[%10], but not via a structured exit")); +} + +TEST_F(ValidateCFG, InvalidSelectionExitBackedge) { + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%1 = OpTypeVoid +%2 = OpTypeBool +%3 = OpUndef %2 +%4 = OpTypeFunction %1 +%5 = OpFunction %1 None %4 +%6 = OpLabel +OpBranch %7 +%7 = OpLabel +OpLoopMerge %8 %9 None +OpBranchConditional %3 %8 %9 +%9 = OpLabel +OpSelectionMerge %10 None +OpBranchConditional %3 %11 %12 +%11 = OpLabel +OpBranch %13 +%12 = OpLabel +OpBranch %13 +%13 = OpLabel +OpBranch %7 +%10 = OpLabel +OpUnreachable +%8 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("block 13[%13] exits the selection headed by " + "9[%9], but not via a structured exit")); +} + +TEST_F(ValidateCFG, BreakFromSwitch) { + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%1 = OpTypeVoid +%2 = OpTypeBool +%3 = OpTypeInt 32 0 +%4 = OpUndef %2 +%5 = OpUndef %3 +%6 = OpTypeFunction %1 +%7 = OpFunction %1 None %6 +%8 = OpLabel +OpSelectionMerge %9 None +OpSwitch %5 %9 0 %10 +%10 = OpLabel +OpSelectionMerge %11 None +OpBranchConditional %4 %11 %12 +%12 = OpLabel +OpBranch %9 +%11 = OpLabel +OpBranch %9 +%9 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateCFG, InvalidBreakFromSwitch) { + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%1 = OpTypeVoid +%2 = OpTypeBool +%3 = OpTypeInt 32 0 +%4 = OpUndef %2 +%5 = OpUndef %3 +%6 = OpTypeFunction %1 +%7 = OpFunction %1 None %6 +%8 = OpLabel +OpSelectionMerge %9 None +OpSwitch %5 %9 0 %10 +%10 = OpLabel +OpSelectionMerge %11 None +OpSwitch %5 %11 0 %12 +%12 = OpLabel +OpBranch %9 +%11 = OpLabel +OpBranch %9 +%9 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("block 12[%12] exits the selection headed by " + "10[%10], but not via a structured exit")); +} + +TEST_F(ValidateCFG, BreakToOuterSwitch) { + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%1 = OpTypeVoid +%2 = OpTypeBool +%3 = OpTypeInt 32 0 +%4 = OpUndef %2 +%5 = OpUndef %3 +%6 = OpTypeFunction %1 +%7 = OpFunction %1 None %6 +%8 = OpLabel +OpSelectionMerge %9 None +OpSwitch %5 %9 0 %10 +%10 = OpLabel +OpSelectionMerge %11 None +OpSwitch %5 %11 0 %12 +%12 = OpLabel +OpSelectionMerge %13 None +OpBranchConditional %4 %13 %14 +%14 = OpLabel +OpBranch %9 +%13 = OpLabel +OpBranch %11 +%11 = OpLabel +OpBranch %9 +%9 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("block 14[%14] exits the selection headed by " + "10[%10], but not via a structured exit")); +} + +TEST_F(ValidateCFG, BreakToOuterLoop) { + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%1 = OpTypeVoid +%2 = OpTypeBool +%3 = OpUndef %2 +%4 = OpTypeFunction %1 +%5 = OpFunction %1 None %4 +%6 = OpLabel +OpBranch %7 +%7 = OpLabel +OpLoopMerge %8 %9 None +OpBranch %10 +%10 = OpLabel +OpLoopMerge %11 %12 None +OpBranch %13 +%13 = OpLabel +OpSelectionMerge %14 None +OpBranchConditional %3 %14 %15 +%15 = OpLabel +OpBranch %8 +%14 = OpLabel +OpBranch %12 +%12 = OpLabel +OpBranchConditional %3 %10 %11 +%11 = OpLabel +OpBranch %9 +%9 = OpLabel +OpBranchConditional %3 %7 %8 +%8 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("block 15[%15] exits the loop headed by " + "10[%10], but not via a structured exit")); +} + +TEST_F(ValidateCFG, ContinueFromNestedSelection) { + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%bool = OpTypeBool +%undef = OpUndef %bool +%4 = OpFunction %void None %void_fn +%5 = OpLabel +OpBranch %48 +%48 = OpLabel +OpLoopMerge %47 %50 None +OpBranch %10 +%10 = OpLabel +OpLoopMerge %12 %37 None +OpBranchConditional %undef %11 %12 +%11 = OpLabel +OpSelectionMerge %31 None +OpBranchConditional %undef %30 %31 +%30 = OpLabel +OpSelectionMerge %38 None +OpBranchConditional %undef %36 %38 +%36 = OpLabel +OpBranch %38 +%38 = OpLabel +OpBranch %37 +%37 = OpLabel +OpBranch %10 +%31 = OpLabel +OpBranch %12 +%12 = OpLabel +OpSelectionMerge %55 None +OpBranchConditional %undef %47 %55 +%55 = OpLabel +OpBranch %47 +%50 = OpLabel +OpBranch %48 +%47 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateCFG, MissingMergeConditionalBranchBad) { + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%bool = OpTypeBool +%undef = OpUndef %bool +%func = OpFunction %void None %void_fn +%entry = OpLabel +OpBranchConditional %undef %then %else +%then = OpLabel +OpReturn +%else = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), HasSubstr("Selection must be structured")); +} + +TEST_F(ValidateCFG, MissingMergeSwitchBad) { + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%int = OpTypeInt 32 0 +%undef = OpUndef %int +%func = OpFunction %void None %void_fn +%entry = OpLabel +OpSwitch %undef %then 0 %else +%then = OpLabel +OpReturn +%else = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), HasSubstr("Selection must be structured")); +} + +TEST_F(ValidateCFG, MissingMergeSwitchBad2) { + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%int = OpTypeInt 32 0 +%undef = OpUndef %int +%func = OpFunction %void None %void_fn +%entry = OpLabel +OpSwitch %undef %then 0 %then 1 %then 2 %else +%then = OpLabel +OpReturn +%else = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), HasSubstr("Selection must be structured")); +} + +TEST_F(ValidateCFG, MissingMergeOneBranchToMergeGood) { + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%bool = OpTypeBool +%undef = OpUndef %bool +%func = OpFunction %void None %void_fn +%entry = OpLabel +OpSelectionMerge %b3 None +OpBranchConditional %undef %b1 %b2 +%b1 = OpLabel +OpBranchConditional %undef %b2 %b3 +%b2 = OpLabel +OpBranch %b3 +%b3 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateCFG, MissingMergeSameTargetConditionalBranchGood) { + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%bool = OpTypeBool +%undef = OpUndef %bool +%func = OpFunction %void None %void_fn +%entry = OpLabel +OpBranchConditional %undef %then %then +%then = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateCFG, MissingMergeOneTargetSwitchGood) { + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%int = OpTypeInt 32 0 +%undef = OpUndef %int +%func = OpFunction %void None %void_fn +%entry = OpLabel +OpSwitch %undef %then 0 %then 1 %then +%then = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateCFG, MissingMergeOneUnseenTargetSwitchGood) { + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%int = OpTypeInt 32 0 +%undef_int = OpUndef %int +%bool = OpTypeBool +%undef_bool = OpUndef %bool +%func = OpFunction %void None %void_fn +%entry = OpLabel +OpSelectionMerge %merge None +OpBranchConditional %undef_bool %merge %b1 +%b1 = OpLabel +OpSwitch %undef_int %b2 0 %b2 1 %merge 2 %b2 +%b2 = OpLabel +OpBranch %merge +%merge = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateCFG, MissingMergeLoopBreakGood) { + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%bool = OpTypeBool +%undef = OpUndef %bool +%func = OpFunction %void None %void_fn +%entry = OpLabel +OpBranch %loop +%loop = OpLabel +OpLoopMerge %exit %continue None +OpBranch %body +%body = OpLabel +OpBranchConditional %undef %body2 %exit +%body2 = OpLabel +OpBranch %continue +%continue = OpLabel +OpBranch %loop +%exit = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateCFG, MissingMergeLoopContinueGood) { + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%bool = OpTypeBool +%undef = OpUndef %bool +%func = OpFunction %void None %void_fn +%entry = OpLabel +OpBranch %loop +%loop = OpLabel +OpLoopMerge %exit %continue None +OpBranch %body +%body = OpLabel +OpBranchConditional %undef %body2 %continue +%body2 = OpLabel +OpBranch %continue +%continue = OpLabel +OpBranch %loop +%exit = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateCFG, MissingMergeSwitchBreakGood) { + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%bool = OpTypeBool +%undef = OpUndef %bool +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%func = OpFunction %void None %void_fn +%entry = OpLabel +OpSelectionMerge %merge None +OpSwitch %int_0 %merge 1 %b1 +%b1 = OpLabel +OpBranchConditional %undef %merge %b2 +%b2 = OpLabel +OpBranch %merge +%merge = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateCFG, MissingMergeSwitchFallThroughGood) { + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%bool = OpTypeBool +%undef = OpUndef %bool +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%func = OpFunction %void None %void_fn +%entry = OpLabel +OpSelectionMerge %merge None +OpSwitch %int_0 %b1 1 %b2 +%b1 = OpLabel +OpBranchConditional %undef %b3 %b2 +%b2 = OpLabel +OpBranch %merge +%b3 = OpLabel +OpBranch %merge +%merge = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateCFG, MissingMergeInALoopBad) { + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%bool = OpTypeBool +%undef = OpUndef %bool +%func = OpFunction %void None %void_fn +%entry = OpLabel +OpBranch %loop +%loop = OpLabel +OpLoopMerge %exit %continue None +OpBranch %body +%body = OpLabel +OpBranchConditional %undef %b1 %b2 +%b1 = OpLabel +OpBranch %exit +%b2 = OpLabel +OpBranch %continue +%continue = OpLabel +OpBranch %loop +%exit = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), HasSubstr("Selection must be structured")); +} + +TEST_F(ValidateCFG, MissingMergeCrissCrossBad) { + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%bool = OpTypeBool +%undef = OpUndef %bool +%func = OpFunction %void None %void_fn +%entry = OpLabel +OpSelectionMerge %merge None +OpBranchConditional %undef %b1 %b2 +%b1 = OpLabel +OpBranchConditional %undef %b3 %b4 +%b2 = OpLabel +OpBranchConditional %undef %b3 %b4 +%b3 = OpLabel +OpBranch %merge +%b4 = OpLabel +OpBranch %merge +%merge = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), HasSubstr("Selection must be structured")); +} + +TEST_F(ValidateCFG, ContinueCannotBeSelectionMergeTarget) { + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpName %loop "loop" +OpName %continue "continue" +OpName %body "body" +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%bool = OpTypeBool +%undef = OpUndef %bool +%func = OpFunction %void None %void_fn +%entry = OpLabel +OpBranch %loop +%loop = OpLabel +OpLoopMerge %exit %continue None +OpBranch %body +%body = OpLabel +OpSelectionMerge %continue None +OpBranchConditional %undef %exit %continue +%continue = OpLabel +OpBranch %loop +%exit = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "Header block 3[%body] is contained in the loop construct headed by " + "1[%loop], but its merge block 2[%continue] is not")); +} + +TEST_F(ValidateCFG, ContinueCannotBeLoopMergeTarget) { + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpName %loop "loop" +OpName %continue "continue" +OpName %inner "inner" +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%bool = OpTypeBool +%undef = OpUndef %bool +%func = OpFunction %void None %void_fn +%entry = OpLabel +OpBranch %loop +%loop = OpLabel +OpLoopMerge %exit %continue None +OpBranchConditional %undef %exit %inner +%inner = OpLabel +OpLoopMerge %continue %inner None +OpBranchConditional %undef %inner %continue +%continue = OpLabel +OpBranch %loop +%exit = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "Header block 3[%inner] is contained in the loop construct headed by " + "1[%loop], but its merge block 2[%continue] is not")); +} + +TEST_F(ValidateCFG, ExitFromConstructWhoseHeaderIsAMerge) { + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%2 = OpTypeFunction %void +%int = OpTypeInt 32 1 +%4 = OpUndef %int +%bool = OpTypeBool +%6 = OpUndef %bool +%7 = OpFunction %void None %2 +%8 = OpLabel +OpSelectionMerge %9 None +OpSwitch %4 %10 0 %11 +%10 = OpLabel +OpBranch %9 +%11 = OpLabel +OpBranch %12 +%12 = OpLabel +OpLoopMerge %13 %14 None +OpBranch %15 +%15 = OpLabel +OpSelectionMerge %16 None +OpSwitch %4 %17 1 %18 2 %19 +%17 = OpLabel +OpBranch %16 +%18 = OpLabel +OpBranch %14 +%19 = OpLabel +OpBranch %16 +%16 = OpLabel +OpBranch %14 +%14 = OpLabel +OpBranchConditional %6 %12 %13 +%13 = OpLabel +OpSelectionMerge %20 None +OpBranchConditional %6 %21 %20 +%21 = OpLabel +OpBranch %9 +%20 = OpLabel +OpBranch %10 +%9 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateCFG, ExitFromConstructWhoseHeaderIsAMerge2) { + const std::string text = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + %void = OpTypeVoid + %4 = OpTypeFunction %void + %int = OpTypeInt 32 1 + %6 = OpUndef %int + %bool = OpTypeBool + %8 = OpUndef %bool + %2 = OpFunction %void None %4 + %9 = OpLabel + OpSelectionMerge %10 None + OpSwitch %6 %11 0 %12 + %11 = OpLabel + OpBranch %10 + %12 = OpLabel + OpBranch %13 + %13 = OpLabel + OpLoopMerge %14 %15 None + OpBranch %16 + %16 = OpLabel + OpSelectionMerge %17 None + OpSwitch %6 %18 1 %19 2 %20 + %18 = OpLabel + OpBranch %17 + %19 = OpLabel + OpBranch %15 + %20 = OpLabel + OpBranch %17 + %17 = OpLabel + OpBranch %15 + %15 = OpLabel + OpBranchConditional %8 %13 %14 + %14 = OpLabel + OpSelectionMerge %21 None + OpBranchConditional %8 %22 %21 + %22 = OpLabel + OpSelectionMerge %23 None + OpBranchConditional %8 %24 %23 + %24 = OpLabel + OpBranch %10 + %23 = OpLabel + OpBranch %21 + %21 = OpLabel + OpBranch %11 + %10 = OpLabel + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} } // namespace } // namespace val diff --git a/third_party/spirv-tools/test/val/val_code_generator.cpp b/third_party/spirv-tools/test/val/val_code_generator.cpp new file mode 100644 index 0000000000..62aae9c410 --- /dev/null +++ b/third_party/spirv-tools/test/val/val_code_generator.cpp @@ -0,0 +1,224 @@ +// Copyright (c) 2019 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 "test/val/val_code_generator.h" + +#include + +namespace spvtools { +namespace val { +namespace { + +std::string GetDefaultShaderCapabilities() { + return R"( +OpCapability Shader +OpCapability Geometry +OpCapability Tessellation +OpCapability Float64 +OpCapability Int64 +OpCapability MultiViewport +OpCapability SampleRateShading +)"; +} + +std::string GetWebGPUShaderCapabilities() { + return R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +)"; +} + +std::string GetDefaultShaderTypes() { + return R"( +%void = OpTypeVoid +%func = OpTypeFunction %void +%bool = OpTypeBool +%f32 = OpTypeFloat 32 +%f64 = OpTypeFloat 64 +%i32 = OpTypeInt 32 1 +%i64 = OpTypeInt 64 1 +%u32 = OpTypeInt 32 0 +%u64 = OpTypeInt 64 0 +%f32vec2 = OpTypeVector %f32 2 +%f32vec3 = OpTypeVector %f32 3 +%f32vec4 = OpTypeVector %f32 4 +%f64vec2 = OpTypeVector %f64 2 +%f64vec3 = OpTypeVector %f64 3 +%f64vec4 = OpTypeVector %f64 4 +%u32vec2 = OpTypeVector %u32 2 +%u32vec3 = OpTypeVector %u32 3 +%u64vec3 = OpTypeVector %u64 3 +%u32vec4 = OpTypeVector %u32 4 +%u64vec2 = OpTypeVector %u64 2 + +%f32_0 = OpConstant %f32 0 +%f32_1 = OpConstant %f32 1 +%f32_2 = OpConstant %f32 2 +%f32_3 = OpConstant %f32 3 +%f32_4 = OpConstant %f32 4 +%f32_h = OpConstant %f32 0.5 +%f32vec2_01 = OpConstantComposite %f32vec2 %f32_0 %f32_1 +%f32vec2_12 = OpConstantComposite %f32vec2 %f32_1 %f32_2 +%f32vec3_012 = OpConstantComposite %f32vec3 %f32_0 %f32_1 %f32_2 +%f32vec3_123 = OpConstantComposite %f32vec3 %f32_1 %f32_2 %f32_3 +%f32vec4_0123 = OpConstantComposite %f32vec4 %f32_0 %f32_1 %f32_2 %f32_3 +%f32vec4_1234 = OpConstantComposite %f32vec4 %f32_1 %f32_2 %f32_3 %f32_4 + +%f64_0 = OpConstant %f64 0 +%f64_1 = OpConstant %f64 1 +%f64_2 = OpConstant %f64 2 +%f64_3 = OpConstant %f64 3 +%f64vec2_01 = OpConstantComposite %f64vec2 %f64_0 %f64_1 +%f64vec3_012 = OpConstantComposite %f64vec3 %f64_0 %f64_1 %f64_2 +%f64vec4_0123 = OpConstantComposite %f64vec4 %f64_0 %f64_1 %f64_2 %f64_3 + +%u32_0 = OpConstant %u32 0 +%u32_1 = OpConstant %u32 1 +%u32_2 = OpConstant %u32 2 +%u32_3 = OpConstant %u32 3 +%u32_4 = OpConstant %u32 4 + +%u64_0 = OpConstant %u64 0 +%u64_1 = OpConstant %u64 1 +%u64_2 = OpConstant %u64 2 +%u64_3 = OpConstant %u64 3 + +%u32vec2_01 = OpConstantComposite %u32vec2 %u32_0 %u32_1 +%u32vec2_12 = OpConstantComposite %u32vec2 %u32_1 %u32_2 +%u32vec4_0123 = OpConstantComposite %u32vec4 %u32_0 %u32_1 %u32_2 %u32_3 +%u64vec2_01 = OpConstantComposite %u64vec2 %u64_0 %u64_1 + +%u32arr2 = OpTypeArray %u32 %u32_2 +%u32arr3 = OpTypeArray %u32 %u32_3 +%u32arr4 = OpTypeArray %u32 %u32_4 +%u64arr2 = OpTypeArray %u64 %u32_2 +%u64arr3 = OpTypeArray %u64 %u32_3 +%u64arr4 = OpTypeArray %u64 %u32_4 +%f32arr2 = OpTypeArray %f32 %u32_2 +%f32arr3 = OpTypeArray %f32 %u32_3 +%f32arr4 = OpTypeArray %f32 %u32_4 +%f64arr2 = OpTypeArray %f64 %u32_2 +%f64arr3 = OpTypeArray %f64 %u32_3 +%f64arr4 = OpTypeArray %f64 %u32_4 + +%f32vec3arr3 = OpTypeArray %f32vec3 %u32_3 +%f32vec4arr3 = OpTypeArray %f32vec4 %u32_3 +%f64vec4arr3 = OpTypeArray %f64vec4 %u32_3 +)"; +} + +std::string GetWebGPUShaderTypes() { + return R"( +%void = OpTypeVoid +%func = OpTypeFunction %void +%bool = OpTypeBool +%f32 = OpTypeFloat 32 +%u32 = OpTypeInt 32 0 +%f32vec2 = OpTypeVector %f32 2 +%f32vec3 = OpTypeVector %f32 3 +%f32vec4 = OpTypeVector %f32 4 +%u32vec2 = OpTypeVector %u32 2 +%u32vec3 = OpTypeVector %u32 3 +%u32vec4 = OpTypeVector %u32 4 + +%f32_0 = OpConstant %f32 0 +%f32_1 = OpConstant %f32 1 +%f32_2 = OpConstant %f32 2 +%f32_3 = OpConstant %f32 3 +%f32_4 = OpConstant %f32 4 +%f32_h = OpConstant %f32 0.5 +%f32vec2_01 = OpConstantComposite %f32vec2 %f32_0 %f32_1 +%f32vec2_12 = OpConstantComposite %f32vec2 %f32_1 %f32_2 +%f32vec3_012 = OpConstantComposite %f32vec3 %f32_0 %f32_1 %f32_2 +%f32vec3_123 = OpConstantComposite %f32vec3 %f32_1 %f32_2 %f32_3 +%f32vec4_0123 = OpConstantComposite %f32vec4 %f32_0 %f32_1 %f32_2 %f32_3 +%f32vec4_1234 = OpConstantComposite %f32vec4 %f32_1 %f32_2 %f32_3 %f32_4 + +%u32_0 = OpConstant %u32 0 +%u32_1 = OpConstant %u32 1 +%u32_2 = OpConstant %u32 2 +%u32_3 = OpConstant %u32 3 +%u32_4 = OpConstant %u32 4 + +%u32vec2_01 = OpConstantComposite %u32vec2 %u32_0 %u32_1 +%u32vec2_12 = OpConstantComposite %u32vec2 %u32_1 %u32_2 +%u32vec4_0123 = OpConstantComposite %u32vec4 %u32_0 %u32_1 %u32_2 %u32_3 + +%u32arr2 = OpTypeArray %u32 %u32_2 +%u32arr3 = OpTypeArray %u32 %u32_3 +%u32arr4 = OpTypeArray %u32 %u32_4 +%f32arr2 = OpTypeArray %f32 %u32_2 +%f32arr3 = OpTypeArray %f32 %u32_3 +%f32arr4 = OpTypeArray %f32 %u32_4 + +%f32vec3arr3 = OpTypeArray %f32vec3 %u32_3 +%f32vec4arr3 = OpTypeArray %f32vec4 %u32_3 +)"; +} + +} // namespace + +CodeGenerator CodeGenerator::GetDefaultShaderCodeGenerator() { + CodeGenerator generator; + generator.capabilities_ = GetDefaultShaderCapabilities(); + generator.memory_model_ = "OpMemoryModel Logical GLSL450\n"; + generator.types_ = GetDefaultShaderTypes(); + return generator; +} + +CodeGenerator CodeGenerator::GetWebGPUShaderCodeGenerator() { + CodeGenerator generator; + generator.capabilities_ = GetWebGPUShaderCapabilities(); + generator.memory_model_ = "OpMemoryModel Logical VulkanKHR\n"; + generator.extensions_ = "OpExtension \"SPV_KHR_vulkan_memory_model\"\n"; + generator.types_ = GetWebGPUShaderTypes(); + return generator; +} + +std::string CodeGenerator::Build() const { + std::ostringstream ss; + + ss << capabilities_; + ss << extensions_; + ss << memory_model_; + + for (const EntryPoint& entry_point : entry_points_) { + ss << "OpEntryPoint " << entry_point.execution_model << " %" + << entry_point.name << " \"" << entry_point.name << "\" " + << entry_point.interfaces << "\n"; + } + + for (const EntryPoint& entry_point : entry_points_) { + ss << entry_point.execution_modes << "\n"; + } + + ss << before_types_; + ss << types_; + ss << after_types_; + + for (const EntryPoint& entry_point : entry_points_) { + ss << "\n"; + ss << "%" << entry_point.name << " = OpFunction %void None %func\n"; + ss << "%" << entry_point.name << "_entry = OpLabel\n"; + ss << entry_point.body; + ss << "\nOpReturn\nOpFunctionEnd\n"; + } + + ss << add_at_the_end_; + + return ss.str(); +} + +} // namespace val +} // namespace spvtools diff --git a/third_party/spirv-tools/test/val/val_code_generator.h b/third_party/spirv-tools/test/val/val_code_generator.h new file mode 100644 index 0000000000..e580ddff70 --- /dev/null +++ b/third_party/spirv-tools/test/val/val_code_generator.h @@ -0,0 +1,49 @@ +// Copyright (c) 2019 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. + +// Utility class used to generate SPIR-V code strings for tests + +#include +#include + +namespace spvtools { +namespace val { + +struct EntryPoint { + std::string name; + std::string execution_model; + std::string execution_modes; + std::string body; + std::string interfaces; +}; + +class CodeGenerator { + public: + static CodeGenerator GetDefaultShaderCodeGenerator(); + static CodeGenerator GetWebGPUShaderCodeGenerator(); + + std::string Build() const; + + std::vector entry_points_; + std::string capabilities_; + std::string extensions_; + std::string memory_model_; + std::string before_types_; + std::string types_; + std::string after_types_; + std::string add_at_the_end_; +}; + +} // namespace val +} // namespace spvtools diff --git a/third_party/spirv-tools/test/val/val_composites_test.cpp b/third_party/spirv-tools/test/val/val_composites_test.cpp index 429007b00b..e970562110 100644 --- a/third_party/spirv-tools/test/val/val_composites_test.cpp +++ b/third_party/spirv-tools/test/val/val_composites_test.cpp @@ -17,6 +17,7 @@ #include "gmock/gmock.h" #include "test/unit_spirv.h" +#include "test/val/val_code_generator.h" #include "test/val/val_fixtures.h" namespace spvtools { @@ -25,6 +26,7 @@ namespace { using ::testing::HasSubstr; using ::testing::Not; +using ::testing::Values; using ValidateComposites = spvtest::ValidateBase; @@ -41,6 +43,9 @@ OpCapability Float64 ss << capabilities_and_extensions; ss << "OpMemoryModel Logical GLSL450\n"; ss << "OpEntryPoint " << execution_model << " %main \"main\"\n"; + if (execution_model == "Fragment") { + ss << "OpExecutionMode %main OriginUpperLeft\n"; + } ss << R"( %void = OpTypeVoid @@ -149,15 +154,14 @@ OpMemoryModel Logical GLSL450 ; } %f32arr = OpTypeRuntimeArray %float -%bool = OpTypeBool %v4float = OpTypeVector %float 4 %array5_mat4x3 = OpTypeArray %mat4x3 %int_5 %array5_vec4 = OpTypeArray %v4float %int_5 %_ptr_Uniform_float = OpTypePointer Uniform %float %_ptr_Function_vec4 = OpTypePointer Function %v4float %_ptr_Uniform_vec4 = OpTypePointer Uniform %v4float -%struct_s = OpTypeStruct %bool %array5_vec4 %int %array5_mat4x3 -%struct_blockName = OpTypeStruct %struct_s %bool %f32arr +%struct_s = OpTypeStruct %int %array5_vec4 %int %array5_mat4x3 +%struct_blockName = OpTypeStruct %struct_s %int %f32arr %_ptr_Uniform_blockName = OpTypePointer Uniform %struct_blockName %_ptr_Uniform_struct_s = OpTypePointer Uniform %struct_s %_ptr_Uniform_array5_mat4x3 = OpTypePointer Uniform %array5_mat4x3 @@ -318,11 +322,9 @@ TEST_F(ValidateComposites, CompositeConstructVectorWrongConsituent1) { )"; CompileSuccessfully(GenerateShaderCode(body).c_str()); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr("Expected Constituents to be scalars or vectors of the same " - "type as Result Type components")); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), HasSubstr("Operand 5[%float] cannot be a " + "type")); } TEST_F(ValidateComposites, CompositeConstructVectorWrongConsituent2) { @@ -537,9 +539,9 @@ TEST_F(ValidateComposites, CopyObjectResultTypeNotType) { )"; CompileSuccessfully(GenerateShaderCode(body).c_str()); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("Expected Result Type to be a type")); + HasSubstr("ID 19[%float_0] is not a type id")); } TEST_F(ValidateComposites, CopyObjectWrongOperandType) { @@ -646,7 +648,6 @@ TEST_F(ValidateComposites, CompositeExtractSuccess) { %val16 = OpCompositeExtract %f32 %struct 4 1000 1 %val17 = OpCompositeExtract %f32 %struct 5 0 %val18 = OpCompositeExtract %u32 %struct 5 1 -%val19 = OpCompositeExtract %big_struct %struct )"; CompileSuccessfully(GenerateShaderCode(body)); @@ -659,10 +660,9 @@ TEST_F(ValidateComposites, CompositeExtractNotObject) { )"; CompileSuccessfully(GenerateShaderCode(body)); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("Expected Composite to be an object " - "of composite type")); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), HasSubstr("Operand 11[%v4float] cannot " + "be a type")); } TEST_F(ValidateComposites, CompositeExtractNotComposite) { @@ -766,6 +766,18 @@ TEST_F(ValidateComposites, CompositeExtractTooManyIndices) { "indexes still remain to be traversed.")); } +TEST_F(ValidateComposites, CompositeExtractNoIndices) { + const std::string body = R"( +%struct = OpLoad %big_struct %var_big_struct +%val1 = OpCompositeExtract %big_struct %struct +)"; + + CompileSuccessfully(GenerateShaderCode(body)); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Expected at least one index to OpCompositeExtract")); +} + TEST_F(ValidateComposites, CompositeExtractWrongType1) { const std::string body = R"( %struct = OpLoad %big_struct %var_big_struct @@ -860,7 +872,6 @@ TEST_F(ValidateComposites, CompositeInsertSuccess) { %val16 = OpCompositeInsert %big_struct %f32_3 %struct 4 1000 1 %val17 = OpCompositeInsert %big_struct %f32_3 %struct 5 0 %val18 = OpCompositeInsert %big_struct %u32_3 %struct 5 1 -%val19 = OpCompositeInsert %big_struct %struct %struct )"; CompileSuccessfully(GenerateShaderCode(body)); @@ -1156,9 +1167,8 @@ TEST_F(ValidateComposites, CompositeInsertWrongResultTypeBad) { HasSubstr("The Result Type must be the same as Composite type")); } -// Valid: No Indexes were passed to OpCompositeExtract, and the Result Type is -// the same as the Base Composite type. -TEST_F(ValidateComposites, CompositeExtractNoIndexesGood) { +// Invalid: No Indexes were passed to OpCompositeExtract. +TEST_F(ValidateComposites, CompositeExtractNoIndices2) { std::ostringstream spirv; spirv << GetHeaderForTestsFromValId() << std::endl; spirv << "%matrix = OpLoad %mat4x3 %my_matrix" << std::endl; @@ -1166,29 +1176,32 @@ TEST_F(ValidateComposites, CompositeExtractNoIndexesGood) { spirv << R"(OpReturn OpFunctionEnd)"; CompileSuccessfully(spirv.str()); - EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "Expected at least one index to OpCompositeExtract, zero found")); } -// Invalid: No Indexes were passed to OpCompositeExtract, but the Result Type is -// different from the Base Composite type. -TEST_F(ValidateComposites, CompositeExtractNoIndexesBad) { +// Invalid: No Indexes were passed to OpCompositeExtract. +TEST_F(ValidateComposites, CompositeExtractNoIndicesWrongResultType) { std::ostringstream spirv; spirv << GetHeaderForTestsFromValId() << std::endl; spirv << "%matrix = OpLoad %mat4x3 %my_matrix" << std::endl; - spirv << "%float_entry = OpCompositeExtract %float %matrix" << std::endl; + spirv << "%float_entry = OpCompositeExtract %float %matrix" << std::endl; spirv << R"(OpReturn OpFunctionEnd)"; CompileSuccessfully(spirv.str()); EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("Result type (OpTypeFloat) does not match the type " - "that results from indexing into the composite " - "(OpTypeMatrix).")); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "Expected at least one index to OpCompositeExtract, zero found")); } -// Valid: No Indexes were passed to OpCompositeInsert, and the type of the +// Invalid: No Indices were passed to OpCompositeInsert, and the type of the // Object argument matches the Composite type. -TEST_F(ValidateComposites, CompositeInsertMissingIndexesGood) { +TEST_F(ValidateComposites, CompositeInsertMissingIndices) { std::ostringstream spirv; spirv << GetHeaderForTestsFromValId() << std::endl; spirv << "%matrix = OpLoad %mat4x3 %my_matrix" << std::endl; @@ -1198,12 +1211,16 @@ TEST_F(ValidateComposites, CompositeInsertMissingIndexesGood) { OpReturn OpFunctionEnd)"; CompileSuccessfully(spirv.str()); - EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "Expected at least one index to OpCompositeInsert, zero found")); } -// Invalid: No Indexes were passed to OpCompositeInsert, but the type of the +// Invalid: No Indices were passed to OpCompositeInsert, but the type of the // Object argument does not match the Composite type. -TEST_F(ValidateComposites, CompositeInsertMissingIndexesBad) { +TEST_F(ValidateComposites, CompositeInsertMissingIndices2) { std::ostringstream spirv; spirv << GetHeaderForTestsFromValId() << std::endl; spirv << "%matrix = OpLoad %mat4x3 %my_matrix" << std::endl; @@ -1213,10 +1230,10 @@ TEST_F(ValidateComposites, CompositeInsertMissingIndexesBad) { OpFunctionEnd)"; CompileSuccessfully(spirv.str()); EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("The Object type (OpTypeInt) does not match the type " - "that results from indexing into the Composite " - "(OpTypeMatrix).")); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "Expected at least one index to OpCompositeInsert, zero found")); } // Valid: Tests that we can index into Struct, Array, Matrix, and Vector! @@ -1365,7 +1382,7 @@ TEST_F(ValidateComposites, CompositeExtractStructIndexOutOfBoundBad) { EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("Index is out of bounds, can not find index 3 in the " - "structure '26'. This structure has 3 members. " + "structure '25'. This structure has 3 members. " "Largest valid index is 2.")); } @@ -1386,7 +1403,7 @@ TEST_F(ValidateComposites, CompositeInsertStructIndexOutOfBoundBad) { EXPECT_THAT( getDiagnosticString(), HasSubstr("Index is out of bounds, can not find index 3 in the structure " - " '26'. This structure has 3 members. Largest valid index " + " '25'. This structure has 3 members. Largest valid index " "is 2.")); } @@ -1468,6 +1485,515 @@ OpFunctionEnd EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); } +TEST_F(ValidateComposites, CoopMatConstantCompositeMismatchFail) { + const std::string body = + R"( +OpCapability Shader +OpCapability Float16 +OpCapability CooperativeMatrixNV +OpExtension "SPV_NV_cooperative_matrix" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +%void = OpTypeVoid +%func = OpTypeFunction %void +%bool = OpTypeBool +%f16 = OpTypeFloat 16 +%f32 = OpTypeFloat 32 +%u32 = OpTypeInt 32 0 + +%u32_8 = OpConstant %u32 8 +%subgroup = OpConstant %u32 3 + +%f16mat = OpTypeCooperativeMatrixNV %f16 %subgroup %u32_8 %u32_8 + +%f32_1 = OpConstant %f32 1 + +%f16mat_1 = OpConstantComposite %f16mat %f32_1 + +%main = OpFunction %void None %func +%main_entry = OpLabel + +OpReturn +OpFunctionEnd)"; + + CompileSuccessfully(body.c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("OpConstantComposite Constituent '11[%float_1]' type does " + "not match the Result Type '10[%10]'s component type.")); +} + +TEST_F(ValidateComposites, CoopMatCompositeConstructMismatchFail) { + const std::string body = + R"( +OpCapability Shader +OpCapability Float16 +OpCapability CooperativeMatrixNV +OpExtension "SPV_NV_cooperative_matrix" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +%void = OpTypeVoid +%func = OpTypeFunction %void +%bool = OpTypeBool +%f16 = OpTypeFloat 16 +%f32 = OpTypeFloat 32 +%u32 = OpTypeInt 32 0 + +%u32_8 = OpConstant %u32 8 +%subgroup = OpConstant %u32 3 + +%f16mat = OpTypeCooperativeMatrixNV %f16 %subgroup %u32_8 %u32_8 + +%f32_1 = OpConstant %f32 1 + +%main = OpFunction %void None %func +%main_entry = OpLabel + +%f16mat_1 = OpCompositeConstruct %f16mat %f32_1 + +OpReturn +OpFunctionEnd)"; + + CompileSuccessfully(body.c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Expected Constituent type to be equal to the component type")); +} + +TEST_F(ValidateComposites, ExtractDynamicLabelIndex) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%float = OpTypeFloat 32 +%v4float = OpTypeVector %float 4 +%void_fn = OpTypeFunction %void +%float_0 = OpConstant %float 0 +%v4float_0 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0 +%func = OpFunction %void None %void_fn +%1 = OpLabel +%ex = OpVectorExtractDynamic %float %v4float_0 %v4float_0 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Expected Index to be int scalar")); +} + +TEST_F(ValidateComposites, CopyLogicalSameType) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%struct = OpTypeStruct +%const_struct = OpConstantComposite %struct +%void_fn = OpTypeFunction %void +%func = OpFunction %void None %void_fn +%1 = OpLabel +%copy = OpCopyLogical %struct %const_struct +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Result Type must not equal the Operand type")); +} + +TEST_F(ValidateComposites, CopyLogicalSameStructDifferentId) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%struct1 = OpTypeStruct +%struct2 = OpTypeStruct +%const_struct = OpConstantComposite %struct1 +%void_fn = OpTypeFunction %void +%func = OpFunction %void None %void_fn +%1 = OpLabel +%copy = OpCopyLogical %struct2 %const_struct +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); +} + +TEST_F(ValidateComposites, CopyLogicalArrayDifferentLength) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_4 = OpConstant %int 4 +%int_5 = OpConstant %int 5 +%array1 = OpTypeArray %int %int_4 +%array2 = OpTypeArray %int %int_5 +%const_array = OpConstantComposite %array1 %int_4 %int_4 %int_4 %int_4 +%void_fn = OpTypeFunction %void +%func = OpFunction %void None %void_fn +%1 = OpLabel +%copy = OpCopyLogical %array2 %const_array +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Result Type does not logically match the Operand type")); +} + +TEST_F(ValidateComposites, CopyLogicalArrayDifferentElement) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%float = OpTypeFloat 32 +%int = OpTypeInt 32 0 +%int_4 = OpConstant %int 4 +%array1 = OpTypeArray %int %int_4 +%array2 = OpTypeArray %float %int_4 +%const_array = OpConstantComposite %array1 %int_4 %int_4 %int_4 %int_4 +%void_fn = OpTypeFunction %void +%func = OpFunction %void None %void_fn +%1 = OpLabel +%copy = OpCopyLogical %array2 %const_array +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Result Type does not logically match the Operand type")); +} + +TEST_F(ValidateComposites, CopyLogicalArrayLogicallyMatchedElement) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%float = OpTypeFloat 32 +%int = OpTypeInt 32 0 +%int_1 = OpConstant %int 1 +%inner1 = OpTypeArray %int %int_1 +%inner2 = OpTypeArray %int %int_1 +%array1 = OpTypeArray %inner1 %int_1 +%array2 = OpTypeArray %inner2 %int_1 +%const_inner = OpConstantComposite %inner1 %int_1 +%const_array = OpConstantComposite %array1 %const_inner +%void_fn = OpTypeFunction %void +%func = OpFunction %void None %void_fn +%1 = OpLabel +%copy = OpCopyLogical %array2 %const_array +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); +} + +TEST_F(ValidateComposites, CopyLogicalStructDifferentNumberElements) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%struct1 = OpTypeStruct +%struct2 = OpTypeStruct %int +%const_struct = OpConstantComposite %struct1 +%void_fn = OpTypeFunction %void +%func = OpFunction %void None %void_fn +%1 = OpLabel +%copy = OpCopyLogical %struct2 %const_struct +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Result Type does not logically match the Operand type")); +} + +TEST_F(ValidateComposites, CopyLogicalStructDifferentElement) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%uint = OpTypeInt 32 0 +%int = OpTypeInt 32 1 +%int_0 = OpConstant %int 0 +%uint_0 = OpConstant %uint 0 +%struct1 = OpTypeStruct %int %uint +%struct2 = OpTypeStruct %int %int +%const_struct = OpConstantComposite %struct1 %int_0 %uint_0 +%void_fn = OpTypeFunction %void +%func = OpFunction %void None %void_fn +%1 = OpLabel +%copy = OpCopyLogical %struct2 %const_struct +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Result Type does not logically match the Operand type")); +} + +TEST_F(ValidateComposites, CopyLogicalStructLogicallyMatch) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_1 = OpConstant %int 1 +%array1 = OpTypeArray %int %int_1 +%array2 = OpTypeArray %int %int_1 +%struct1 = OpTypeStruct %int %array1 +%struct2 = OpTypeStruct %int %array2 +%const_array = OpConstantComposite %array1 %int_1 +%const_struct = OpConstantComposite %struct1 %int_1 %const_array +%void_fn = OpTypeFunction %void +%func = OpFunction %void None %void_fn +%1 = OpLabel +%copy = OpCopyLogical %struct2 %const_struct +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); +} + +using ValidateSmallComposites = spvtest::ValidateBase; + +CodeGenerator GetSmallCompositesCodeGenerator() { + CodeGenerator generator; + generator.capabilities_ = R"( +OpCapability Shader +OpCapability Linkage +OpCapability UniformAndStorageBuffer16BitAccess +OpCapability UniformAndStorageBuffer8BitAccess +)"; + generator.extensions_ = R"( +OpExtension "SPV_KHR_16bit_storage" +OpExtension "SPV_KHR_8bit_storage" +)"; + generator.memory_model_ = "OpMemoryModel Logical GLSL450\n"; + generator.before_types_ = R"( +OpDecorate %char_block Block +OpMemberDecorate %char_block 0 Offset 0 +OpDecorate %short_block Block +OpMemberDecorate %short_block 0 Offset 0 +OpDecorate %half_block Block +OpMemberDecorate %half_block 0 Offset 0 +)"; + generator.types_ = R"( +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%int_1 = OpConstant %int 1 +%char = OpTypeInt 8 0 +%char2 = OpTypeVector %char 2 +%short = OpTypeInt 16 0 +%short2 = OpTypeVector %short 2 +%half = OpTypeFloat 16 +%half2 = OpTypeVector %half 2 +%char_block = OpTypeStruct %char2 +%short_block = OpTypeStruct %short2 +%half_block = OpTypeStruct %half2 +%ptr_ssbo_char_block = OpTypePointer StorageBuffer %char_block +%ptr_ssbo_char2 = OpTypePointer StorageBuffer %char2 +%ptr_ssbo_char = OpTypePointer StorageBuffer %char +%ptr_ssbo_short_block = OpTypePointer StorageBuffer %short_block +%ptr_ssbo_short2 = OpTypePointer StorageBuffer %short2 +%ptr_ssbo_short = OpTypePointer StorageBuffer %short +%ptr_ssbo_half_block = OpTypePointer StorageBuffer %half_block +%ptr_ssbo_half2 = OpTypePointer StorageBuffer %half2 +%ptr_ssbo_half = OpTypePointer StorageBuffer %half +%void_fn = OpTypeFunction %void +%char_var = OpVariable %ptr_ssbo_char_block StorageBuffer +%short_var = OpVariable %ptr_ssbo_short_block StorageBuffer +%half_var = OpVariable %ptr_ssbo_half_block StorageBuffer +)"; + generator.after_types_ = R"( +%func = OpFunction %void None %void_fn +%entry = OpLabel +%char2_gep = OpAccessChain %ptr_ssbo_char2 %char_var %int_0 +%ld_char2 = OpLoad %char2 %char2_gep +%char_gep = OpAccessChain %ptr_ssbo_char %char_var %int_0 %int_0 +%ld_char = OpLoad %char %char_gep +%short2_gep = OpAccessChain %ptr_ssbo_short2 %short_var %int_0 +%ld_short2 = OpLoad %short2 %short2_gep +%short_gep = OpAccessChain %ptr_ssbo_short %short_var %int_0 %int_0 +%ld_short = OpLoad %short %short_gep +%half2_gep = OpAccessChain %ptr_ssbo_half2 %half_var %int_0 +%ld_half2 = OpLoad %half2 %half2_gep +%half_gep = OpAccessChain %ptr_ssbo_half %half_var %int_0 %int_0 +%ld_half = OpLoad %half %half_gep +)"; + generator.add_at_the_end_ = R"( +OpReturn +OpFunctionEnd +)"; + return generator; +} + +TEST_P(ValidateSmallComposites, VectorExtractDynamic) { + std::string type = GetParam(); + CodeGenerator generator = GetSmallCompositesCodeGenerator(); + std::string inst = + "%inst = OpVectorExtractDynamic %" + type + " %ld_" + type + "2 %int_0\n"; + generator.after_types_ += inst; + CompileSuccessfully(generator.Build(), SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Cannot extract from a vector of 8- or 16-bit types")); +} + +TEST_P(ValidateSmallComposites, VectorInsertDynamic) { + std::string type = GetParam(); + CodeGenerator generator = GetSmallCompositesCodeGenerator(); + std::string inst = "%inst = OpVectorInsertDynamic %" + type + "2 %ld_" + + type + "2 %ld_" + type + " %int_0\n"; + generator.after_types_ += inst; + CompileSuccessfully(generator.Build(), SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Cannot insert into a vector of 8- or 16-bit types")); +} + +TEST_P(ValidateSmallComposites, VectorShuffle) { + std::string type = GetParam(); + CodeGenerator generator = GetSmallCompositesCodeGenerator(); + std::string inst = "%inst = OpVectorShuffle %" + type + "2 %ld_" + type + + "2 %ld_" + type + "2 0 0\n"; + generator.after_types_ += inst; + CompileSuccessfully(generator.Build(), SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Cannot shuffle a vector of 8- or 16-bit types")); +} + +TEST_P(ValidateSmallComposites, CompositeConstruct) { + std::string type = GetParam(); + CodeGenerator generator = GetSmallCompositesCodeGenerator(); + std::string inst = "%inst = OpCompositeConstruct %" + type + "2 %ld_" + type + + " %ld_" + type + "\n"; + generator.after_types_ += inst; + CompileSuccessfully(generator.Build(), SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Cannot create a composite containing 8- or 16-bit types")); +} + +TEST_P(ValidateSmallComposites, CompositeExtract) { + std::string type = GetParam(); + CodeGenerator generator = GetSmallCompositesCodeGenerator(); + std::string inst = + "%inst = OpCompositeExtract %" + type + " %ld_" + type + "2 0\n"; + generator.after_types_ += inst; + CompileSuccessfully(generator.Build(), SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Cannot extract from a composite of 8- or 16-bit types")); +} + +TEST_P(ValidateSmallComposites, CompositeInsert) { + std::string type = GetParam(); + CodeGenerator generator = GetSmallCompositesCodeGenerator(); + std::string inst = "%inst = OpCompositeInsert %" + type + "2 %ld_" + type + + " %ld_" + type + "2 0\n"; + generator.after_types_ += inst; + CompileSuccessfully(generator.Build(), SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Cannot insert into a composite of 8- or 16-bit types")); +} + +TEST_P(ValidateSmallComposites, CopyObject) { + std::string type = GetParam(); + CodeGenerator generator = GetSmallCompositesCodeGenerator(); + std::string inst = "%inst = OpCopyObject %" + type + "2 %ld_" + type + "2\n"; + generator.after_types_ += inst; + CompileSuccessfully(generator.Build(), SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); +} + +INSTANTIATE_TEST_SUITE_P(SmallCompositeInstructions, ValidateSmallComposites, + Values("char", "short", "half")); + +TEST_F(ValidateComposites, HalfMatrixCannotTranspose) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability UniformAndStorageBuffer16BitAccess +OpExtension "SPV_KHR_16bit_storage" +OpMemoryModel Logical GLSL450 +OpDecorate %block Block +OpMemberDecorate %block 0 Offset 0 +OpMemberDecorate %block 0 RowMajor +OpMemberDecorate %block 0 MatrixStride 8 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%float = OpTypeFloat 16 +%float2 = OpTypeVector %float 2 +%mat2x2 = OpTypeMatrix %float2 2 +%block = OpTypeStruct %mat2x2 +%ptr_ssbo_block = OpTypePointer StorageBuffer %block +%ptr_ssbo_mat2x2 = OpTypePointer StorageBuffer %mat2x2 +%var = OpVariable %ptr_ssbo_block StorageBuffer +%void_fn = OpTypeFunction %void +%func = OpFunction %void None %void_fn +%entry = OpLabel +%gep = OpAccessChain %ptr_ssbo_mat2x2 %var %int_0 +%ld = OpLoad %mat2x2 %gep +%inst = OpTranspose %mat2x2 %ld +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Cannot transpose matrices of 16-bit floats")); +} + } // namespace } // namespace val } // namespace spvtools diff --git a/third_party/spirv-tools/test/val/val_constants_test.cpp b/third_party/spirv-tools/test/val/val_constants_test.cpp new file mode 100644 index 0000000000..301539d98f --- /dev/null +++ b/third_party/spirv-tools/test/val/val_constants_test.cpp @@ -0,0 +1,483 @@ +// Copyright (c) 2019 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. + +// Test validation of constants. +// +// This file contains newer tests. Older tests may be in other files such as +// val_id_test.cpp. + +#include +#include + +#include "gmock/gmock.h" +#include "test/unit_spirv.h" +#include "test/val/val_code_generator.h" +#include "test/val/val_fixtures.h" + +namespace spvtools { +namespace val { +namespace { + +using ::testing::Combine; +using ::testing::Eq; +using ::testing::HasSubstr; +using ::testing::Values; +using ::testing::ValuesIn; + +using ValidateConstant = spvtest::ValidateBase; + +#define kBasicTypes \ + "%bool = OpTypeBool " \ + "%uint = OpTypeInt 32 0 " \ + "%uint2 = OpTypeVector %uint 2 " \ + "%float = OpTypeFloat 32 " \ + "%_ptr_uint = OpTypePointer Workgroup %uint " \ + "%uint_0 = OpConstantNull %uint " \ + "%uint2_0 = OpConstantNull %uint " \ + "%float_0 = OpConstantNull %float " \ + "%false = OpConstantFalse %bool " \ + "%true = OpConstantTrue %bool " \ + "%null = OpConstantNull %_ptr_uint " + +#define kShaderPreamble \ + "OpCapability Shader\n" \ + "OpCapability Linkage\n" \ + "OpMemoryModel Logical Simple\n" + +#define kKernelPreamble \ + "OpCapability Kernel\n" \ + "OpCapability Linkage\n" \ + "OpCapability Addresses\n" \ + "OpMemoryModel Physical32 OpenCL\n" + +struct ConstantOpCase { + spv_target_env env; + std::string assembly; + bool expect_success; + std::string expect_err; +}; + +using ValidateConstantOp = spvtest::ValidateBase; + +TEST_P(ValidateConstantOp, Samples) { + const auto env = GetParam().env; + CompileSuccessfully(GetParam().assembly, env); + const auto result = ValidateInstructions(env); + if (GetParam().expect_success) { + EXPECT_EQ(SPV_SUCCESS, result); + EXPECT_THAT(getDiagnosticString(), Eq("")); + } else { + EXPECT_EQ(SPV_ERROR_INVALID_ID, result); + EXPECT_THAT(getDiagnosticString(), HasSubstr(GetParam().expect_err)); + } +} + +#define GOOD_SHADER_10(STR) \ + { SPV_ENV_UNIVERSAL_1_0, kShaderPreamble kBasicTypes STR, true, "" } +#define GOOD_KERNEL_10(STR) \ + { SPV_ENV_UNIVERSAL_1_0, kKernelPreamble kBasicTypes STR, true, "" } +INSTANTIATE_TEST_SUITE_P( + UniversalInShader, ValidateConstantOp, + ValuesIn(std::vector{ + // TODO(dneto): Conversions must change width. + GOOD_SHADER_10("%v = OpSpecConstantOp %uint SConvert %uint_0"), + GOOD_SHADER_10("%v = OpSpecConstantOp %float FConvert %float_0"), + GOOD_SHADER_10("%v = OpSpecConstantOp %uint SNegate %uint_0"), + GOOD_SHADER_10("%v = OpSpecConstantOp %uint Not %uint_0"), + GOOD_SHADER_10("%v = OpSpecConstantOp %uint IAdd %uint_0 %uint_0"), + GOOD_SHADER_10("%v = OpSpecConstantOp %uint ISub %uint_0 %uint_0"), + GOOD_SHADER_10("%v = OpSpecConstantOp %uint IMul %uint_0 %uint_0"), + GOOD_SHADER_10("%v = OpSpecConstantOp %uint UDiv %uint_0 %uint_0"), + GOOD_SHADER_10("%v = OpSpecConstantOp %uint SDiv %uint_0 %uint_0"), + GOOD_SHADER_10("%v = OpSpecConstantOp %uint UMod %uint_0 %uint_0"), + GOOD_SHADER_10("%v = OpSpecConstantOp %uint SRem %uint_0 %uint_0"), + GOOD_SHADER_10("%v = OpSpecConstantOp %uint SMod %uint_0 %uint_0"), + GOOD_SHADER_10( + "%v = OpSpecConstantOp %uint ShiftRightLogical %uint_0 %uint_0"), + GOOD_SHADER_10( + "%v = OpSpecConstantOp %uint ShiftRightArithmetic %uint_0 %uint_0"), + GOOD_SHADER_10( + "%v = OpSpecConstantOp %uint ShiftLeftLogical %uint_0 %uint_0"), + GOOD_SHADER_10("%v = OpSpecConstantOp %uint BitwiseOr %uint_0 %uint_0"), + GOOD_SHADER_10( + "%v = OpSpecConstantOp %uint BitwiseXor %uint_0 %uint_0"), + GOOD_SHADER_10( + "%v = OpSpecConstantOp %uint2 VectorShuffle %uint2_0 %uint2_0 1 3"), + GOOD_SHADER_10( + "%v = OpSpecConstantOp %uint CompositeExtract %uint2_0 1"), + GOOD_SHADER_10( + "%v = OpSpecConstantOp %uint2 CompositeInsert %uint_0 %uint2_0 1"), + GOOD_SHADER_10("%v = OpSpecConstantOp %bool LogicalOr %true %false"), + GOOD_SHADER_10("%v = OpSpecConstantOp %bool LogicalNot %true"), + GOOD_SHADER_10("%v = OpSpecConstantOp %bool LogicalAnd %true %false"), + GOOD_SHADER_10("%v = OpSpecConstantOp %bool LogicalEqual %true %false"), + GOOD_SHADER_10( + "%v = OpSpecConstantOp %bool LogicalNotEqual %true %false"), + GOOD_SHADER_10( + "%v = OpSpecConstantOp %uint Select %true %uint_0 %uint_0"), + GOOD_SHADER_10("%v = OpSpecConstantOp %bool IEqual %uint_0 %uint_0"), + GOOD_SHADER_10("%v = OpSpecConstantOp %bool INotEqual %uint_0 %uint_0"), + GOOD_SHADER_10("%v = OpSpecConstantOp %bool ULessThan %uint_0 %uint_0"), + GOOD_SHADER_10("%v = OpSpecConstantOp %bool SLessThan %uint_0 %uint_0"), + GOOD_SHADER_10( + "%v = OpSpecConstantOp %bool ULessThanEqual %uint_0 %uint_0"), + GOOD_SHADER_10( + "%v = OpSpecConstantOp %bool SLessThanEqual %uint_0 %uint_0"), + GOOD_SHADER_10( + "%v = OpSpecConstantOp %bool UGreaterThan %uint_0 %uint_0"), + GOOD_SHADER_10( + "%v = OpSpecConstantOp %bool UGreaterThanEqual %uint_0 %uint_0"), + GOOD_SHADER_10( + "%v = OpSpecConstantOp %bool SGreaterThan %uint_0 %uint_0"), + GOOD_SHADER_10( + "%v = OpSpecConstantOp %bool SGreaterThanEqual %uint_0 %uint_0"), + })); + +INSTANTIATE_TEST_SUITE_P( + UniversalInKernel, ValidateConstantOp, + ValuesIn(std::vector{ + // TODO(dneto): Conversions must change width. + GOOD_KERNEL_10("%v = OpSpecConstantOp %uint SConvert %uint_0"), + GOOD_KERNEL_10("%v = OpSpecConstantOp %float FConvert %float_0"), + GOOD_KERNEL_10("%v = OpSpecConstantOp %uint SNegate %uint_0"), + GOOD_KERNEL_10("%v = OpSpecConstantOp %uint Not %uint_0"), + GOOD_KERNEL_10("%v = OpSpecConstantOp %uint IAdd %uint_0 %uint_0"), + GOOD_KERNEL_10("%v = OpSpecConstantOp %uint ISub %uint_0 %uint_0"), + GOOD_KERNEL_10("%v = OpSpecConstantOp %uint IMul %uint_0 %uint_0"), + GOOD_KERNEL_10("%v = OpSpecConstantOp %uint UDiv %uint_0 %uint_0"), + GOOD_KERNEL_10("%v = OpSpecConstantOp %uint SDiv %uint_0 %uint_0"), + GOOD_KERNEL_10("%v = OpSpecConstantOp %uint UMod %uint_0 %uint_0"), + GOOD_KERNEL_10("%v = OpSpecConstantOp %uint SRem %uint_0 %uint_0"), + GOOD_KERNEL_10("%v = OpSpecConstantOp %uint SMod %uint_0 %uint_0"), + GOOD_KERNEL_10( + "%v = OpSpecConstantOp %uint ShiftRightLogical %uint_0 %uint_0"), + GOOD_KERNEL_10( + "%v = OpSpecConstantOp %uint ShiftRightArithmetic %uint_0 %uint_0"), + GOOD_KERNEL_10( + "%v = OpSpecConstantOp %uint ShiftLeftLogical %uint_0 %uint_0"), + GOOD_KERNEL_10("%v = OpSpecConstantOp %uint BitwiseOr %uint_0 %uint_0"), + GOOD_KERNEL_10( + "%v = OpSpecConstantOp %uint BitwiseXor %uint_0 %uint_0"), + GOOD_KERNEL_10( + "%v = OpSpecConstantOp %uint2 VectorShuffle %uint2_0 %uint2_0 1 3"), + GOOD_KERNEL_10( + "%v = OpSpecConstantOp %uint CompositeExtract %uint2_0 1"), + GOOD_KERNEL_10( + "%v = OpSpecConstantOp %uint2 CompositeInsert %uint_0 %uint2_0 1"), + GOOD_KERNEL_10("%v = OpSpecConstantOp %bool LogicalOr %true %false"), + GOOD_KERNEL_10("%v = OpSpecConstantOp %bool LogicalNot %true"), + GOOD_KERNEL_10("%v = OpSpecConstantOp %bool LogicalAnd %true %false"), + GOOD_KERNEL_10("%v = OpSpecConstantOp %bool LogicalEqual %true %false"), + GOOD_KERNEL_10( + "%v = OpSpecConstantOp %bool LogicalNotEqual %true %false"), + GOOD_KERNEL_10( + "%v = OpSpecConstantOp %uint Select %true %uint_0 %uint_0"), + GOOD_KERNEL_10("%v = OpSpecConstantOp %bool IEqual %uint_0 %uint_0"), + GOOD_KERNEL_10("%v = OpSpecConstantOp %bool INotEqual %uint_0 %uint_0"), + GOOD_KERNEL_10("%v = OpSpecConstantOp %bool ULessThan %uint_0 %uint_0"), + GOOD_KERNEL_10("%v = OpSpecConstantOp %bool SLessThan %uint_0 %uint_0"), + GOOD_KERNEL_10( + "%v = OpSpecConstantOp %bool ULessThanEqual %uint_0 %uint_0"), + GOOD_KERNEL_10( + "%v = OpSpecConstantOp %bool SLessThanEqual %uint_0 %uint_0"), + GOOD_KERNEL_10( + "%v = OpSpecConstantOp %bool UGreaterThan %uint_0 %uint_0"), + GOOD_KERNEL_10( + "%v = OpSpecConstantOp %bool UGreaterThanEqual %uint_0 %uint_0"), + GOOD_KERNEL_10( + "%v = OpSpecConstantOp %bool SGreaterThan %uint_0 %uint_0"), + GOOD_KERNEL_10( + "%v = OpSpecConstantOp %bool SGreaterThanEqual %uint_0 %uint_0"), + })); + +INSTANTIATE_TEST_SUITE_P( + UConvert, ValidateConstantOp, + ValuesIn(std::vector{ + // TODO(dneto): Conversions must change width. + {SPV_ENV_UNIVERSAL_1_0, + kKernelPreamble kBasicTypes + "%v = OpSpecConstantOp %uint UConvert %uint_0", + true, ""}, + {SPV_ENV_UNIVERSAL_1_1, + kKernelPreamble kBasicTypes + "%v = OpSpecConstantOp %uint UConvert %uint_0", + true, ""}, + {SPV_ENV_UNIVERSAL_1_3, + kKernelPreamble kBasicTypes + "%v = OpSpecConstantOp %uint UConvert %uint_0", + true, ""}, + {SPV_ENV_UNIVERSAL_1_3, + kKernelPreamble kBasicTypes + "%v = OpSpecConstantOp %uint UConvert %uint_0", + true, ""}, + {SPV_ENV_UNIVERSAL_1_4, + kKernelPreamble kBasicTypes + "%v = OpSpecConstantOp %uint UConvert %uint_0", + true, ""}, + {SPV_ENV_UNIVERSAL_1_0, + kShaderPreamble kBasicTypes + "%v = OpSpecConstantOp %uint UConvert %uint_0", + false, + "Prior to SPIR-V 1.4, specialization constant operation " + "UConvert requires Kernel capability"}, + {SPV_ENV_UNIVERSAL_1_1, + kShaderPreamble kBasicTypes + "%v = OpSpecConstantOp %uint UConvert %uint_0", + false, + "Prior to SPIR-V 1.4, specialization constant operation " + "UConvert requires Kernel capability"}, + {SPV_ENV_UNIVERSAL_1_3, + kShaderPreamble kBasicTypes + "%v = OpSpecConstantOp %uint UConvert %uint_0", + false, + "Prior to SPIR-V 1.4, specialization constant operation " + "UConvert requires Kernel capability"}, + {SPV_ENV_UNIVERSAL_1_3, + kShaderPreamble kBasicTypes + "%v = OpSpecConstantOp %uint UConvert %uint_0", + false, + "Prior to SPIR-V 1.4, specialization constant operation " + "UConvert requires Kernel capability"}, + {SPV_ENV_UNIVERSAL_1_4, + kShaderPreamble kBasicTypes + "%v = OpSpecConstantOp %uint UConvert %uint_0", + true, ""}, + })); + +INSTANTIATE_TEST_SUITE_P( + KernelInKernel, ValidateConstantOp, + ValuesIn(std::vector{ + // TODO(dneto): Conversions must change width. + GOOD_KERNEL_10("%v = OpSpecConstantOp %uint ConvertFToS %float_0"), + GOOD_KERNEL_10("%v = OpSpecConstantOp %float ConvertSToF %uint_0"), + GOOD_KERNEL_10("%v = OpSpecConstantOp %uint ConvertFToU %float_0"), + GOOD_KERNEL_10("%v = OpSpecConstantOp %float ConvertUToF %uint_0"), + GOOD_KERNEL_10("%v = OpSpecConstantOp %uint UConvert %uint_0"), + GOOD_KERNEL_10( + "%v = OpSpecConstantOp %_ptr_uint GenericCastToPtr %null"), + GOOD_KERNEL_10( + "%v = OpSpecConstantOp %_ptr_uint PtrCastToGeneric %null"), + GOOD_KERNEL_10("%v = OpSpecConstantOp %uint Bitcast %uint_0"), + GOOD_KERNEL_10("%v = OpSpecConstantOp %float FNegate %float_0"), + GOOD_KERNEL_10("%v = OpSpecConstantOp %float FAdd %float_0 %float_0"), + GOOD_KERNEL_10("%v = OpSpecConstantOp %float FSub %float_0 %float_0"), + GOOD_KERNEL_10("%v = OpSpecConstantOp %float FMul %float_0 %float_0"), + GOOD_KERNEL_10("%v = OpSpecConstantOp %float FDiv %float_0 %float_0"), + GOOD_KERNEL_10("%v = OpSpecConstantOp %float FRem %float_0 %float_0"), + GOOD_KERNEL_10("%v = OpSpecConstantOp %float FMod %float_0 %float_0"), + GOOD_KERNEL_10( + "%v = OpSpecConstantOp %_ptr_uint AccessChain %null %uint_0"), + GOOD_KERNEL_10("%v = OpSpecConstantOp %_ptr_uint InBoundsAccessChain " + "%null %uint_0"), + GOOD_KERNEL_10( + "%v = OpSpecConstantOp %_ptr_uint PtrAccessChain %null %uint_0"), + GOOD_KERNEL_10("%v = OpSpecConstantOp %_ptr_uint " + "InBoundsPtrAccessChain %null %uint_0"), + })); + +#define BAD_SHADER_10(STR, NAME) \ + { \ + SPV_ENV_UNIVERSAL_1_0, kShaderPreamble kBasicTypes STR, false, \ + "Specialization constant operation " NAME \ + " requires Kernel capability" \ + } +INSTANTIATE_TEST_SUITE_P( + KernelInShader, ValidateConstantOp, + ValuesIn(std::vector{ + // TODO(dneto): Conversions must change width. + BAD_SHADER_10("%v = OpSpecConstantOp %uint ConvertFToS %float_0", + "ConvertFToS"), + BAD_SHADER_10("%v = OpSpecConstantOp %float ConvertSToF %uint_0", + "ConvertSToF"), + BAD_SHADER_10("%v = OpSpecConstantOp %uint ConvertFToU %float_0", + "ConvertFToU"), + BAD_SHADER_10("%v = OpSpecConstantOp %float ConvertUToF %uint_0", + "ConvertUToF"), + BAD_SHADER_10("%v = OpSpecConstantOp %_ptr_uint GenericCastToPtr %null", + "GenericCastToPtr"), + BAD_SHADER_10("%v = OpSpecConstantOp %_ptr_uint PtrCastToGeneric %null", + "PtrCastToGeneric"), + BAD_SHADER_10("%v = OpSpecConstantOp %uint Bitcast %uint_0", "Bitcast"), + BAD_SHADER_10("%v = OpSpecConstantOp %float FNegate %float_0", + "FNegate"), + BAD_SHADER_10("%v = OpSpecConstantOp %float FAdd %float_0 %float_0", + "FAdd"), + BAD_SHADER_10("%v = OpSpecConstantOp %float FSub %float_0 %float_0", + "FSub"), + BAD_SHADER_10("%v = OpSpecConstantOp %float FMul %float_0 %float_0", + "FMul"), + BAD_SHADER_10("%v = OpSpecConstantOp %float FDiv %float_0 %float_0", + "FDiv"), + BAD_SHADER_10("%v = OpSpecConstantOp %float FRem %float_0 %float_0", + "FRem"), + BAD_SHADER_10("%v = OpSpecConstantOp %float FMod %float_0 %float_0", + "FMod"), + BAD_SHADER_10( + "%v = OpSpecConstantOp %_ptr_uint AccessChain %null %uint_0", + "AccessChain"), + BAD_SHADER_10("%v = OpSpecConstantOp %_ptr_uint InBoundsAccessChain " + "%null %uint_0", + "InBoundsAccessChain"), + BAD_SHADER_10( + "%v = OpSpecConstantOp %_ptr_uint PtrAccessChain %null %uint_0", + "PtrAccessChain"), + BAD_SHADER_10("%v = OpSpecConstantOp %_ptr_uint " + "InBoundsPtrAccessChain %null %uint_0", + "InBoundsPtrAccessChain"), + })); + +INSTANTIATE_TEST_SUITE_P( + UConvertInAMD_gpu_shader_int16, ValidateConstantOp, + ValuesIn(std::vector{ + // SPV_AMD_gpu_shader_int16 should enable UConvert for OpSpecConstantOp + // https://github.com/KhronosGroup/glslang/issues/848 + {SPV_ENV_UNIVERSAL_1_0, + "OpCapability Shader " + "OpCapability Linkage ; So we don't need to define a function\n" + "OpExtension \"SPV_AMD_gpu_shader_int16\" " + "OpMemoryModel Logical Simple " kBasicTypes + "%v = OpSpecConstantOp %uint UConvert %uint_0", + true, ""}, + })); + +TEST_F(ValidateConstant, SpecConstantUConvert1p3Binary1p4EnvBad) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%int = OpTypeInt 32 0 +%int0 = OpConstant %int 0 +%const = OpSpecConstantOp %int UConvert %int0 +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "Prior to SPIR-V 1.4, specialization constant operation UConvert " + "requires Kernel capability or extension SPV_AMD_gpu_shader_int16")); +} + +using SmallStorageConstants = spvtest::ValidateBase; + +CodeGenerator GetSmallStorageCodeGenerator() { + CodeGenerator generator; + generator.capabilities_ = R"( +OpCapability Shader +OpCapability Linkage +OpCapability UniformAndStorageBuffer16BitAccess +OpCapability StoragePushConstant16 +OpCapability StorageInputOutput16 +OpCapability UniformAndStorageBuffer8BitAccess +OpCapability StoragePushConstant8 +)"; + generator.extensions_ = R"( +OpExtension "SPV_KHR_16bit_storage" +OpExtension "SPV_KHR_8bit_storage" +)"; + generator.memory_model_ = "OpMemoryModel Logical GLSL450\n"; + generator.types_ = R"( +%short = OpTypeInt 16 0 +%short2 = OpTypeVector %short 2 +%char = OpTypeInt 8 0 +%char2 = OpTypeVector %char 2 +%half = OpTypeFloat 16 +%half2 = OpTypeVector %half 2 +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%float = OpTypeFloat 32 +%float_0 = OpConstant %float 0 +)"; + return generator; +} + +TEST_P(SmallStorageConstants, SmallConstant) { + std::string constant = GetParam(); + CodeGenerator generator = GetSmallStorageCodeGenerator(); + generator.after_types_ += constant + "\n"; + CompileSuccessfully(generator.Build(), SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Cannot form constants of 8- or 16-bit types")); +} + +// Constant composites would be caught through scalar constants. +INSTANTIATE_TEST_SUITE_P( + SmallConstants, SmallStorageConstants, + Values("%c = OpConstant %char 0", "%c = OpConstantNull %char2", + "%c = OpConstant %short 0", "%c = OpConstantNull %short", + "%c = OpConstant %half 0", "%c = OpConstantNull %half", + "%c = OpSpecConstant %char 0", "%c = OpSpecConstant %short 0", + "%c = OpSpecConstant %half 0", + "%c = OpSpecConstantOp %char SConvert %int_0", + "%c = OpSpecConstantOp %short SConvert %int_0", + "%c = OpSpecConstantOp %half FConvert %float_0")); + +TEST_F(ValidateConstant, NullPointerTo16BitStorageOk) { + std::string spirv = R"( +OpCapability Shader +OpCapability VariablePointersStorageBuffer +OpCapability UniformAndStorageBuffer16BitAccess +OpCapability Linkage +OpExtension "SPV_KHR_16bit_storage" +OpMemoryModel Logical GLSL450 +%half = OpTypeFloat 16 +%ptr_ssbo_half = OpTypePointer StorageBuffer %half +%null_ptr = OpConstantNull %ptr_ssbo_half +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); +} + +TEST_F(ValidateConstant, NullMatrix) { + std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%float = OpTypeFloat 32 +%v2float = OpTypeVector %float 2 +%mat2x2 = OpTypeMatrix %v2float 2 +%null_vector = OpConstantNull %v2float +%null_matrix = OpConstantComposite %mat2x2 %null_vector %null_vector +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateConstant, NullPhysicalStorageBuffer) { + std::string spirv = R"( +OpCapability Shader +OpCapability PhysicalStorageBufferAddresses +OpCapability Linkage +OpExtension "SPV_KHR_physical_storage_buffer" +OpMemoryModel PhysicalStorageBuffer64 GLSL450 +OpName %ptr "ptr" +%int = OpTypeInt 32 0 +%ptr = OpTypePointer PhysicalStorageBuffer %int +%null = OpConstantNull %ptr +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("OpConstantNull Result Type '1[%ptr]' cannot have " + "a null value")); +} + +} // namespace +} // namespace val +} // namespace spvtools diff --git a/third_party/spirv-tools/test/val/val_conversion_test.cpp b/third_party/spirv-tools/test/val/val_conversion_test.cpp index e0b8a00180..47e67938d8 100644 --- a/third_party/spirv-tools/test/val/val_conversion_test.cpp +++ b/third_party/spirv-tools/test/val/val_conversion_test.cpp @@ -18,6 +18,7 @@ #include "gmock/gmock.h" #include "test/unit_spirv.h" +#include "test/val/val_code_generator.h" #include "test/val/val_fixtures.h" namespace spvtools { @@ -26,22 +27,29 @@ namespace { using ::testing::HasSubstr; using ::testing::Not; +using ::testing::Values; using ValidateConversion = spvtest::ValidateBase; std::string GenerateShaderCode( const std::string& body, - const std::string& capabilities_and_extensions = "") { + const std::string& capabilities_and_extensions = "", + const std::string& decorations = "", const std::string& types = "", + const std::string& variables = "") { const std::string capabilities = R"( OpCapability Shader OpCapability Int64 OpCapability Float64)"; - const std::string after_extension_before_body = + const std::string after_extension_before_decorations = R"( OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft)"; + + const std::string after_decorations_before_types = + R"( %void = OpTypeVoid %func = OpTypeFunction %void %bool = OpTypeBool @@ -139,8 +147,10 @@ OpEntryPoint Fragment %main "main" %true = OpConstantTrue %bool %false = OpConstantFalse %bool -%f32ptr_func = OpTypePointer Function %f32 +%f32ptr_func = OpTypePointer Function %f32)"; + const std::string after_variables_before_body = + R"( %main = OpFunction %void None %func %main_entry = OpLabel)"; @@ -150,7 +160,9 @@ OpReturn OpFunctionEnd)"; return capabilities + capabilities_and_extensions + - after_extension_before_body + body + after_body; + after_extension_before_decorations + decorations + + after_decorations_before_types + types + variables + + after_variables_before_body + body + after_body; } std::string GenerateKernelCode( @@ -236,6 +248,8 @@ OpMemoryModel Physical32 OpenCL %f64vec4_0123 = OpConstantComposite %f64vec4 %f64_0 %f64_1 %f64_2 %f64_3 %f64vec4_1234 = OpConstantComposite %f64vec4 %f64_1 %f64_2 %f64_3 %f64_4 +%u64vec2_01 = OpConstantComposite %u64vec2 %u64_0 %u64_1 + %true = OpConstantTrue %bool %false = OpConstantFalse %bool @@ -798,9 +812,9 @@ TEST_F(ValidateConversion, PtrCastToGenericWrongInputType) { )"; CompileSuccessfully(GenerateKernelCode(body).c_str()); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("Expected input to be a pointer: PtrCastToGeneric")); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), HasSubstr("Operand 4[%float] cannot be a " + "type")); } TEST_F(ValidateConversion, PtrCastToGenericWrongInputStorageClass) { @@ -1010,6 +1024,172 @@ TEST_F(ValidateConversion, GenericCastToPtrExplicitPointToDifferentType) { "GenericCastToPtrExplicit")); } +TEST_F(ValidateConversion, CoopMatConversionSuccess) { + const std::string body = + R"( +OpCapability Shader +OpCapability Float16 +OpCapability Int16 +OpCapability CooperativeMatrixNV +OpExtension "SPV_NV_cooperative_matrix" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +%void = OpTypeVoid +%func = OpTypeFunction %void +%bool = OpTypeBool +%f16 = OpTypeFloat 16 +%f32 = OpTypeFloat 32 +%u16 = OpTypeInt 16 0 +%u32 = OpTypeInt 32 0 +%s16 = OpTypeInt 16 1 +%s32 = OpTypeInt 32 1 + +%u32_8 = OpConstant %u32 8 +%subgroup = OpConstant %u32 3 + +%f16mat = OpTypeCooperativeMatrixNV %f16 %subgroup %u32_8 %u32_8 +%f32mat = OpTypeCooperativeMatrixNV %f32 %subgroup %u32_8 %u32_8 +%u16mat = OpTypeCooperativeMatrixNV %u16 %subgroup %u32_8 %u32_8 +%u32mat = OpTypeCooperativeMatrixNV %u32 %subgroup %u32_8 %u32_8 +%s16mat = OpTypeCooperativeMatrixNV %s16 %subgroup %u32_8 %u32_8 +%s32mat = OpTypeCooperativeMatrixNV %s32 %subgroup %u32_8 %u32_8 + +%f16_1 = OpConstant %f16 1 +%f32_1 = OpConstant %f32 1 +%u16_1 = OpConstant %u16 1 +%u32_1 = OpConstant %u32 1 +%s16_1 = OpConstant %s16 1 +%s32_1 = OpConstant %s32 1 + +%f16mat_1 = OpConstantComposite %f16mat %f16_1 +%f32mat_1 = OpConstantComposite %f32mat %f32_1 +%u16mat_1 = OpConstantComposite %u16mat %u16_1 +%u32mat_1 = OpConstantComposite %u32mat %u32_1 +%s16mat_1 = OpConstantComposite %s16mat %s16_1 +%s32mat_1 = OpConstantComposite %s32mat %s32_1 + +%main = OpFunction %void None %func +%main_entry = OpLabel + +%val11 = OpConvertFToU %u16mat %f16mat_1 +%val12 = OpConvertFToU %u32mat %f16mat_1 +%val13 = OpConvertFToS %s16mat %f16mat_1 +%val14 = OpConvertFToS %s32mat %f16mat_1 +%val15 = OpFConvert %f32mat %f16mat_1 + +%val21 = OpConvertFToU %u16mat %f32mat_1 +%val22 = OpConvertFToU %u32mat %f32mat_1 +%val23 = OpConvertFToS %s16mat %f32mat_1 +%val24 = OpConvertFToS %s32mat %f32mat_1 +%val25 = OpFConvert %f16mat %f32mat_1 + +%val31 = OpConvertUToF %f16mat %u16mat_1 +%val32 = OpConvertUToF %f32mat %u16mat_1 +%val33 = OpUConvert %u32mat %u16mat_1 +%val34 = OpSConvert %s32mat %u16mat_1 + +%val41 = OpConvertSToF %f16mat %s16mat_1 +%val42 = OpConvertSToF %f32mat %s16mat_1 +%val43 = OpUConvert %u32mat %s16mat_1 +%val44 = OpSConvert %s32mat %s16mat_1 + +OpReturn +OpFunctionEnd)"; + + CompileSuccessfully(body.c_str()); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateConversion, CoopMatConversionShapesMismatchFail) { + const std::string body = + R"( +OpCapability Shader +OpCapability Float16 +OpCapability Int16 +OpCapability CooperativeMatrixNV +OpExtension "SPV_NV_cooperative_matrix" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +%void = OpTypeVoid +%func = OpTypeFunction %void +%bool = OpTypeBool +%f16 = OpTypeFloat 16 +%f32 = OpTypeFloat 32 +%u16 = OpTypeInt 16 0 +%u32 = OpTypeInt 32 0 +%s16 = OpTypeInt 16 1 +%s32 = OpTypeInt 32 1 + +%u32_8 = OpConstant %u32 8 +%u32_4 = OpConstant %u32 4 +%subgroup = OpConstant %u32 3 + +%f16mat = OpTypeCooperativeMatrixNV %f16 %subgroup %u32_8 %u32_8 +%f32mat = OpTypeCooperativeMatrixNV %f32 %subgroup %u32_4 %u32_4 + +%f16_1 = OpConstant %f16 1 + +%f16mat_1 = OpConstantComposite %f16mat %f16_1 + +%main = OpFunction %void None %func +%main_entry = OpLabel + +%val15 = OpFConvert %f32mat %f16mat_1 + +OpReturn +OpFunctionEnd)"; + + CompileSuccessfully(body.c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "Expected rows of Matrix type and Result Type to be identical")); +} + +TEST_F(ValidateConversion, CoopMatConversionShapesMismatchPass) { + const std::string body = + R"( +OpCapability Shader +OpCapability Float16 +OpCapability Int16 +OpCapability CooperativeMatrixNV +OpExtension "SPV_NV_cooperative_matrix" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +%void = OpTypeVoid +%func = OpTypeFunction %void +%bool = OpTypeBool +%f16 = OpTypeFloat 16 +%f32 = OpTypeFloat 32 +%u16 = OpTypeInt 16 0 +%u32 = OpTypeInt 32 0 +%s16 = OpTypeInt 16 1 +%s32 = OpTypeInt 32 1 + +%u32_8 = OpConstant %u32 8 +%u32_4 = OpSpecConstant %u32 4 +%subgroup = OpConstant %u32 3 + +%f16mat = OpTypeCooperativeMatrixNV %f16 %subgroup %u32_8 %u32_8 +%f32mat = OpTypeCooperativeMatrixNV %f32 %subgroup %u32_4 %u32_4 + +%f16_1 = OpConstant %f16 1 + +%f16mat_1 = OpConstantComposite %f16mat %f16_1 + +%main = OpFunction %void None %func +%main_entry = OpLabel + +%val15 = OpFConvert %f32mat %f16mat_1 + +OpReturn +OpFunctionEnd)"; + + CompileSuccessfully(body.c_str()); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + TEST_F(ValidateConversion, BitcastSuccess) { const std::string body = R"( %ptr = OpVariable %f32ptr_func Function @@ -1028,15 +1208,58 @@ TEST_F(ValidateConversion, BitcastSuccess) { ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); } +TEST_F(ValidateConversion, BitcastSuccessSPV1p5) { + const std::string body = R"( +%ptr = OpVariable %f32ptr_func Function +%val1 = OpBitcast %u32 %ptr +%val2 = OpBitcast %u64 %ptr +%val3 = OpBitcast %f32ptr_func %u32_1 +%val4 = OpBitcast %f32ptr_wg %u64_1 +%val5 = OpBitcast %f32 %u32_1 +%val6 = OpBitcast %f32vec2 %u32vec2_12 +%val7 = OpBitcast %f32vec2 %u64_1 +%val8 = OpBitcast %f64 %u32vec2_12 +%val9 = OpBitcast %f32vec4 %f64vec2_12 +%val10 = OpBitcast %u32ptr_func %u32vec2_01 +%val11 = OpBitcast %u32vec2 %ptr +)"; + + CompileSuccessfully(GenerateKernelCode(body).c_str(), SPV_ENV_UNIVERSAL_1_5); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_5)); +} + +TEST_F(ValidateConversion, BitcastSuccessPhysicalStorageBufferKHR) { + const std::string body = R"( +%ptr = OpVariable %f32ptr_func Function +%val1 = OpBitcast %u32 %ptr +%val2 = OpBitcast %u64 %ptr +%val3 = OpBitcast %f32ptr_func %u32_1 +%val4 = OpBitcast %f32ptr_wg %u64_1 +%val5 = OpBitcast %f32 %u32_1 +%val6 = OpBitcast %f32vec2 %u32vec2_12 +%val7 = OpBitcast %f32vec2 %u64_1 +%val8 = OpBitcast %f64 %u32vec2_12 +%val9 = OpBitcast %f32vec4 %f64vec2_12 +%val10 = OpBitcast %u32ptr_func %u32vec2_01 +%val11 = OpBitcast %u32vec2 %ptr +)"; + + CompileSuccessfully( + GenerateKernelCode(body, + "\nOpExtension \"SPV_KHR_physical_storage_buffer\"") + .c_str()); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + TEST_F(ValidateConversion, BitcastInputHasNoType) { const std::string body = R"( %val = OpBitcast %u32 %f32 )"; CompileSuccessfully(GenerateKernelCode(body).c_str()); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("Expected input to have a type: Bitcast")); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), HasSubstr("Operand 4[%float] cannot be a " + "type")); } TEST_F(ValidateConversion, BitcastWrongResultType) { @@ -1071,10 +1294,66 @@ TEST_F(ValidateConversion, BitcastPtrWrongInputType) { CompileSuccessfully(GenerateKernelCode(body).c_str()); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr("Expected input to be a pointer or int scalar if Result Type " - "is pointer: Bitcast")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Expected input to be a pointer or int scalar if " + "Result Type is pointer: Bitcast")); +} + +TEST_F(ValidateConversion, BitcastPtrWrongInputTypeSPV1p5) { + const std::string body = R"( +%val = OpBitcast %u32ptr_func %f32_1 +)"; + + CompileSuccessfully(GenerateKernelCode(body).c_str(), SPV_ENV_UNIVERSAL_1_5); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_5)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Expected input to be a pointer, int scalar or 32-bit " + "int vector if Result Type is pointer: Bitcast")); +} + +TEST_F(ValidateConversion, BitcastPtrWrongInputTypePhysicalStorageBufferKHR) { + const std::string body = R"( +%val = OpBitcast %u32ptr_func %f32_1 +)"; + + CompileSuccessfully( + GenerateKernelCode(body, + "\nOpExtension \"SPV_KHR_physical_storage_buffer\"") + .c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Expected input to be a pointer, int scalar or 32-bit " + "int vector if Result Type is pointer: Bitcast")); +} + +TEST_F(ValidateConversion, BitcastPtrWrongInputTypeIntVectorSPV1p5) { + const std::string body = R"( +%val = OpBitcast %u32ptr_func %u64vec2_01 +)"; + + CompileSuccessfully(GenerateKernelCode(body).c_str(), SPV_ENV_UNIVERSAL_1_5); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_5)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Expected input to be a pointer, int scalar or 32-bit " + "int vector if Result Type is pointer: Bitcast")); +} + +TEST_F(ValidateConversion, + BitcastPtrWrongInputTypeIntVectorPhysicalStorageBufferKHR) { + const std::string body = R"( +%val = OpBitcast %u32ptr_func %u64vec2_01 +)"; + + CompileSuccessfully( + GenerateKernelCode(body, + "\nOpExtension \"SPV_KHR_physical_storage_buffer\"") + .c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Expected input to be a pointer, int scalar or 32-bit " + "int vector if Result Type is pointer: Bitcast")); } TEST_F(ValidateConversion, BitcastPtrWrongResultType) { @@ -1084,11 +1363,66 @@ TEST_F(ValidateConversion, BitcastPtrWrongResultType) { CompileSuccessfully(GenerateKernelCode(body).c_str()); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr( - "Pointer can only be converted to another pointer or int scalar: " - "Bitcast")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Pointer can only be converted to another pointer or " + "int scalar: Bitcast")); +} + +TEST_F(ValidateConversion, BitcastPtrWrongResultTypeSPV1p5) { + const std::string body = R"( +%val = OpBitcast %f32 %f32inp +)"; + + CompileSuccessfully(GenerateKernelCode(body).c_str(), SPV_ENV_UNIVERSAL_1_5); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_5)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Pointer can only be converted to another pointer, int " + "scalar or 32-bit int vector: Bitcast")); +} + +TEST_F(ValidateConversion, BitcastPtrWrongResultTypePhysicalStorageBufferKHR) { + const std::string body = R"( +%val = OpBitcast %f32 %f32inp +)"; + + CompileSuccessfully( + GenerateKernelCode(body, + "\nOpExtension \"SPV_KHR_physical_storage_buffer\"") + .c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Pointer can only be converted to another pointer, int " + "scalar or 32-bit int vector: Bitcast")); +} + +TEST_F(ValidateConversion, BitcastPtrWrongResultTypeIntVectorSPV1p5) { + const std::string body = R"( +%val = OpBitcast %u64vec2 %f32inp +)"; + + CompileSuccessfully(GenerateKernelCode(body).c_str(), SPV_ENV_UNIVERSAL_1_5); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_5)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Pointer can only be converted to another pointer, int " + "scalar or 32-bit int vector: Bitcast")); +} + +TEST_F(ValidateConversion, + BitcastPtrWrongResultTypeIntVectorPhysicalStorageBufferKHR) { + const std::string body = R"( +%val = OpBitcast %u64vec2 %f32inp +)"; + + CompileSuccessfully( + GenerateKernelCode(body, + "\nOpExtension \"SPV_KHR_physical_storage_buffer\"") + .c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Pointer can only be converted to another pointer, int " + "scalar or 32-bit int vector: Bitcast")); } TEST_F(ValidateConversion, BitcastDifferentTotalBitWidth) { @@ -1105,6 +1439,283 @@ TEST_F(ValidateConversion, BitcastDifferentTotalBitWidth) { "Bitcast")); } +TEST_F(ValidateConversion, ConvertUToPtrInputIsAType) { + const std::string spirv = R"( +OpCapability Addresses +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%int = OpTypeInt 32 0 +%ptr_int = OpTypePointer Function %int +%void = OpTypeVoid +%voidfn = OpTypeFunction %void +%func = OpFunction %void None %voidfn +%entry = OpLabel +%1 = OpConvertUToPtr %ptr_int %int +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), HasSubstr("Operand 1[%uint] cannot be a " + "type")); +} + +TEST_F(ValidateConversion, ConvertUToPtrPSBSuccess) { + const std::string body = R"( +OpCapability PhysicalStorageBufferAddressesEXT +OpCapability Int64 +OpCapability Shader +OpExtension "SPV_EXT_physical_storage_buffer" +OpMemoryModel PhysicalStorageBuffer64EXT GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +%uint64 = OpTypeInt 64 0 +%u64_1 = OpConstant %uint64 1 +%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64 +%void = OpTypeVoid +%voidfn = OpTypeFunction %void +%main = OpFunction %void None %voidfn +%entry = OpLabel +%val1 = OpConvertUToPtr %ptr %u64_1 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(body.c_str()); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateConversion, ConvertUToPtrPSBStorageClass) { + const std::string body = R"( +OpCapability PhysicalStorageBufferAddressesEXT +OpCapability Int64 +OpCapability Shader +OpExtension "SPV_EXT_physical_storage_buffer" +OpMemoryModel PhysicalStorageBuffer64EXT GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +%uint64 = OpTypeInt 64 0 +%u64_1 = OpConstant %uint64 1 +%ptr = OpTypePointer Function %uint64 +%void = OpTypeVoid +%voidfn = OpTypeFunction %void +%main = OpFunction %void None %voidfn +%entry = OpLabel +%val1 = OpConvertUToPtr %ptr %u64_1 +%val2 = OpConvertPtrToU %uint64 %val1 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(body.c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Pointer storage class must be " + "PhysicalStorageBufferEXT: ConvertUToPtr")); +} + +TEST_F(ValidateConversion, ConvertPtrToUPSBSuccess) { + const std::string body = R"( +OpCapability PhysicalStorageBufferAddressesEXT +OpCapability Int64 +OpCapability Shader +OpExtension "SPV_EXT_physical_storage_buffer" +OpMemoryModel PhysicalStorageBuffer64EXT GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpDecorate %val1 RestrictPointerEXT +%uint64 = OpTypeInt 64 0 +%u64_1 = OpConstant %uint64 1 +%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64 +%pptr_f = OpTypePointer Function %ptr +%void = OpTypeVoid +%voidfn = OpTypeFunction %void +%main = OpFunction %void None %voidfn +%entry = OpLabel +%val1 = OpVariable %pptr_f Function +%val2 = OpLoad %ptr %val1 +%val3 = OpConvertPtrToU %uint64 %val2 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(body.c_str()); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateConversion, ConvertPtrToUPSBStorageClass) { + const std::string body = R"( +OpCapability PhysicalStorageBufferAddressesEXT +OpCapability Int64 +OpCapability Shader +OpExtension "SPV_EXT_physical_storage_buffer" +OpMemoryModel PhysicalStorageBuffer64EXT GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +%uint64 = OpTypeInt 64 0 +%u64_1 = OpConstant %uint64 1 +%ptr = OpTypePointer Function %uint64 +%void = OpTypeVoid +%voidfn = OpTypeFunction %void +%main = OpFunction %void None %voidfn +%entry = OpLabel +%val1 = OpVariable %ptr Function +%val2 = OpConvertPtrToU %uint64 %val1 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(body.c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Pointer storage class must be " + "PhysicalStorageBufferEXT: ConvertPtrToU")); +} + +using ValidateSmallConversions = spvtest::ValidateBase; + +CodeGenerator GetSmallConversionsCodeGenerator() { + CodeGenerator generator; + generator.capabilities_ = R"( +OpCapability Shader +OpCapability Linkage +OpCapability UniformAndStorageBuffer16BitAccess +OpCapability UniformAndStorageBuffer8BitAccess +)"; + generator.extensions_ = R"( +OpExtension "SPV_KHR_16bit_storage" +OpExtension "SPV_KHR_8bit_storage" +)"; + generator.memory_model_ = "OpMemoryModel Logical GLSL450\n"; + generator.before_types_ = R"( +OpDecorate %char_block Block +OpMemberDecorate %char_block 0 Offset 0 +OpDecorate %short_block Block +OpMemberDecorate %short_block 0 Offset 0 +OpDecorate %half_block Block +OpMemberDecorate %half_block 0 Offset 0 +OpDecorate %int_block Block +OpMemberDecorate %int_block 0 Offset 0 +OpDecorate %float_block Block +OpMemberDecorate %float_block 0 Offset 0 +)"; + generator.types_ = R"( +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%int_1 = OpConstant %int 1 +%int2 = OpTypeVector %int 2 +%float = OpTypeFloat 32 +%float_0 = OpConstant %float 0 +%float2 = OpTypeVector %float 2 +%char = OpTypeInt 8 0 +%char2 = OpTypeVector %char 2 +%short = OpTypeInt 16 0 +%short2 = OpTypeVector %short 2 +%half = OpTypeFloat 16 +%half2 = OpTypeVector %half 2 +%char_block = OpTypeStruct %char2 +%short_block = OpTypeStruct %short2 +%half_block = OpTypeStruct %half2 +%int_block = OpTypeStruct %int2 +%float_block = OpTypeStruct %float2 +%ptr_ssbo_char_block = OpTypePointer StorageBuffer %char_block +%ptr_ssbo_char2 = OpTypePointer StorageBuffer %char2 +%ptr_ssbo_char = OpTypePointer StorageBuffer %char +%ptr_ssbo_short_block = OpTypePointer StorageBuffer %short_block +%ptr_ssbo_short2 = OpTypePointer StorageBuffer %short2 +%ptr_ssbo_short = OpTypePointer StorageBuffer %short +%ptr_ssbo_half_block = OpTypePointer StorageBuffer %half_block +%ptr_ssbo_half2 = OpTypePointer StorageBuffer %half2 +%ptr_ssbo_half = OpTypePointer StorageBuffer %half +%ptr_ssbo_int_block = OpTypePointer StorageBuffer %int_block +%ptr_ssbo_int2 = OpTypePointer StorageBuffer %int2 +%ptr_ssbo_int = OpTypePointer StorageBuffer %int +%ptr_ssbo_float_block = OpTypePointer StorageBuffer %float_block +%ptr_ssbo_float2 = OpTypePointer StorageBuffer %float2 +%ptr_ssbo_float = OpTypePointer StorageBuffer %float +%void_fn = OpTypeFunction %void +%char_var = OpVariable %ptr_ssbo_char_block StorageBuffer +%short_var = OpVariable %ptr_ssbo_short_block StorageBuffer +%half_var = OpVariable %ptr_ssbo_half_block StorageBuffer +%int_var = OpVariable %ptr_ssbo_int_block StorageBuffer +%float_var = OpVariable %ptr_ssbo_float_block StorageBuffer +)"; + generator.after_types_ = R"( +%func = OpFunction %void None %void_fn +%entry = OpLabel +%char2_gep = OpAccessChain %ptr_ssbo_char2 %char_var %int_0 +%ld_char2 = OpLoad %char2 %char2_gep +%char_gep = OpAccessChain %ptr_ssbo_char %char_var %int_0 %int_0 +%ld_char = OpLoad %char %char_gep +%short2_gep = OpAccessChain %ptr_ssbo_short2 %short_var %int_0 +%ld_short2 = OpLoad %short2 %short2_gep +%short_gep = OpAccessChain %ptr_ssbo_short %short_var %int_0 %int_0 +%ld_short = OpLoad %short %short_gep +%half2_gep = OpAccessChain %ptr_ssbo_half2 %half_var %int_0 +%ld_half2 = OpLoad %half2 %half2_gep +%half_gep = OpAccessChain %ptr_ssbo_half %half_var %int_0 %int_0 +%ld_half = OpLoad %half %half_gep +%int2_gep = OpAccessChain %ptr_ssbo_int2 %int_var %int_0 +%ld_int2 = OpLoad %int2 %int2_gep +%int_gep = OpAccessChain %ptr_ssbo_int %int_var %int_0 %int_0 +%ld_int = OpLoad %int %int_gep +%float2_gep = OpAccessChain %ptr_ssbo_float2 %float_var %int_0 +%ld_float2 = OpLoad %float2 %float2_gep +%float_gep = OpAccessChain %ptr_ssbo_float %float_var %int_0 %int_0 +%ld_float = OpLoad %float %float_gep +)"; + generator.add_at_the_end_ = R"( +OpReturn +OpFunctionEnd +)"; + return generator; +} + +TEST_P(ValidateSmallConversions, Instruction) { + CodeGenerator generator = GetSmallConversionsCodeGenerator(); + generator.after_types_ += GetParam() + "\n"; + CompileSuccessfully(generator.Build(), SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "8- or 16-bit types can only be used with width-only conversions")); +} + +INSTANTIATE_TEST_SUITE_P(SmallConversionInstructions, ValidateSmallConversions, + Values("%inst = OpConvertFToU %char %ld_float", + "%inst = OpConvertFToU %char2 %ld_float2", + "%inst = OpConvertFToU %short %ld_float", + "%inst = OpConvertFToU %short2 %ld_float2", + "%inst = OpConvertFToU %int %ld_half", + "%inst = OpConvertFToU %int2 %ld_half2", + "%inst = OpConvertFToS %char %ld_float", + "%inst = OpConvertFToS %char2 %ld_float2", + "%inst = OpConvertFToS %short %ld_float", + "%inst = OpConvertFToS %short2 %ld_float2", + "%inst = OpConvertFToS %int %ld_half", + "%inst = OpConvertFToS %int2 %ld_half2", + "%inst = OpConvertSToF %float %ld_char", + "%inst = OpConvertSToF %float2 %ld_char2", + "%inst = OpConvertSToF %float %ld_short", + "%inst = OpConvertSToF %float2 %ld_short2", + "%inst = OpConvertSToF %half %ld_int", + "%inst = OpConvertSToF %half2 %ld_int2", + "%inst = OpConvertUToF %float %ld_char", + "%inst = OpConvertUToF %float2 %ld_char2", + "%inst = OpConvertUToF %float %ld_short", + "%inst = OpConvertUToF %float2 %ld_short2", + "%inst = OpConvertUToF %half %ld_int", + "%inst = OpConvertUToF %half2 %ld_int2", + "%inst = OpBitcast %half %ld_short", + "%inst = OpBitcast %half2 %ld_short2", + "%inst = OpBitcast %short %ld_half", + "%inst = OpBitcast %short2 %ld_half2")); + } // namespace } // namespace val } // namespace spvtools diff --git a/third_party/spirv-tools/test/val/val_data_test.cpp b/third_party/spirv-tools/test/val/val_data_test.cpp index d022d8b8a3..30afd03cd9 100644 --- a/third_party/spirv-tools/test/val/val_data_test.cpp +++ b/third_party/spirv-tools/test/val/val_data_test.cpp @@ -36,6 +36,24 @@ std::string HeaderWith(std::string cap) { cap + " OpMemoryModel Logical GLSL450 "; } +std::string WebGPUHeaderWith(std::string cap) { + return R"( +OpCapability Shader +OpCapability )" + + cap + R"( +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +)"; +} + +std::string webgpu_header = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +)"; + std::string header = R"( OpCapability Shader OpCapability Linkage @@ -249,6 +267,18 @@ TEST_F(ValidateData, int8_with_storage_push_constant_8_good) { EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()) << getDiagnosticString(); } +TEST_F(ValidateData, webgpu_int8_bad) { + std::string str = WebGPUHeaderWith("Int8") + "%2 = OpTypeInt 8 0"; + CompileSuccessfully(str.c_str(), SPV_ENV_WEBGPU_0); + ASSERT_EQ(SPV_ERROR_INVALID_CAPABILITY, + ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Capability Int8 is not allowed by WebGPU specification (or " + "requires extension)\n" + " OpCapability Int8\n")); +} + TEST_F(ValidateData, int16_good) { std::string str = header_with_int16 + "%2 = OpTypeInt 16 1"; CompileSuccessfully(str.c_str()); @@ -290,6 +320,17 @@ TEST_F(ValidateData, storage_input_output_16_good) { ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); } +TEST_F(ValidateData, amd_gpu_shader_half_float_fetch_16_good) { + std::string str = R"( + OpCapability Shader + OpCapability Linkage + OpExtension "SPV_AMD_gpu_shader_half_float_fetch" + OpMemoryModel Logical GLSL450 + %2 = OpTypeFloat 16)"; + CompileSuccessfully(str.c_str()); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + TEST_F(ValidateData, int16_bad) { std::string str = header + "%2 = OpTypeInt 16 1"; CompileSuccessfully(str.c_str()); @@ -297,6 +338,34 @@ TEST_F(ValidateData, int16_bad) { EXPECT_THAT(getDiagnosticString(), HasSubstr(missing_int16_cap_error)); } +TEST_F(ValidateData, webgpu_int16_bad) { + std::string str = WebGPUHeaderWith("Int16") + "%2 = OpTypeInt 16 1"; + CompileSuccessfully(str.c_str(), SPV_ENV_WEBGPU_0); + ASSERT_EQ(SPV_ERROR_INVALID_CAPABILITY, + ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Capability Int16 is not allowed by WebGPU specification (or " + "requires extension)\n" + " OpCapability Int16\n")); +} + +TEST_F(ValidateData, webgpu_int32_good) { + std::string str = webgpu_header + R"( + OpEntryPoint Fragment %func "func" + OpExecutionMode %func OriginUpperLeft +%uint_t = OpTypeInt 32 0 + %void = OpTypeVoid +%func_t = OpTypeFunction %void + %func = OpFunction %void None %func_t + %1 = OpLabel + OpReturn + OpFunctionEnd +)"; + CompileSuccessfully(str.c_str(), SPV_ENV_WEBGPU_0); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); +} + TEST_F(ValidateData, int64_good) { std::string str = header_with_int64 + "%2 = OpTypeInt 64 1"; CompileSuccessfully(str.c_str()); @@ -310,6 +379,18 @@ TEST_F(ValidateData, int64_bad) { EXPECT_THAT(getDiagnosticString(), HasSubstr(missing_int64_cap_error)); } +TEST_F(ValidateData, webgpu_int64_bad) { + std::string str = WebGPUHeaderWith("Int64") + "%2 = OpTypeInt 64 1"; + CompileSuccessfully(str.c_str(), SPV_ENV_WEBGPU_0); + ASSERT_EQ(SPV_ERROR_INVALID_CAPABILITY, + ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Capability Int64 is not allowed by WebGPU specification (or " + "requires extension)\n" + " OpCapability Int64\n")); +} + // Number of bits in an integer may be only one of: {8,16,32,64} TEST_F(ValidateData, int_invalid_num_bits) { std::string str = header + "%2 = OpTypeInt 48 1"; @@ -337,6 +418,34 @@ TEST_F(ValidateData, float16_bad) { EXPECT_THAT(getDiagnosticString(), HasSubstr(missing_float16_cap_error)); } +TEST_F(ValidateData, webgpu_float16_bad) { + std::string str = WebGPUHeaderWith("Float16") + "%2 = OpTypeFloat 16"; + CompileSuccessfully(str.c_str(), SPV_ENV_WEBGPU_0); + ASSERT_EQ(SPV_ERROR_INVALID_CAPABILITY, + ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Capability Float16 is not allowed by WebGPU specification (or " + "requires extension)\n" + " OpCapability Float16\n")); +} + +TEST_F(ValidateData, webgpu_float32_good) { + std::string str = webgpu_header + R"( + OpEntryPoint Fragment %func "func" + OpExecutionMode %func OriginUpperLeft +%float_t = OpTypeFloat 32 + %void = OpTypeVoid + %func_t = OpTypeFunction %void + %func = OpFunction %void None %func_t + %1 = OpLabel + OpReturn + OpFunctionEnd +)"; + CompileSuccessfully(str.c_str(), SPV_ENV_WEBGPU_0); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); +} + TEST_F(ValidateData, float64_good) { std::string str = header_with_float64 + "%2 = OpTypeFloat 64"; CompileSuccessfully(str.c_str()); @@ -350,6 +459,18 @@ TEST_F(ValidateData, float64_bad) { EXPECT_THAT(getDiagnosticString(), HasSubstr(missing_float64_cap_error)); } +TEST_F(ValidateData, webgpu_float64_bad) { + std::string str = WebGPUHeaderWith("Float64") + "%2 = OpTypeFloat 64"; + CompileSuccessfully(str.c_str(), SPV_ENV_WEBGPU_0); + ASSERT_EQ(SPV_ERROR_INVALID_CAPABILITY, + ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Capability Float64 is not allowed by WebGPU specification (or " + "requires extension)\n" + " OpCapability Float64\n")); +} + // Number of bits in a float may be only one of: {16,32,64} TEST_F(ValidateData, float_invalid_num_bits) { std::string str = header + "%2 = OpTypeFloat 48"; @@ -375,7 +496,8 @@ TEST_F(ValidateData, ids_should_be_validated_before_data) { )"; CompileSuccessfully(str.c_str()); ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), HasSubstr("ID 3 has not been defined")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("ID 3[%3] has not been defined")); } TEST_F(ValidateData, matrix_bad_column_type) { @@ -507,15 +629,26 @@ TEST_F(ValidateData, specialize_boolean) { ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); } -TEST_F(ValidateData, specialize_boolean_to_int) { +TEST_F(ValidateData, specialize_boolean_true_to_int) { + std::string str = header + R"( +%2 = OpTypeInt 32 1 +%3 = OpSpecConstantTrue %2)"; + CompileSuccessfully(str.c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("OpSpecConstantTrue Result Type '1[%int]' is not " + "a boolean type")); +} + +TEST_F(ValidateData, specialize_boolean_false_to_int) { std::string str = header + R"( %2 = OpTypeInt 32 1 -%3 = OpSpecConstantTrue %2 %4 = OpSpecConstantFalse %2)"; CompileSuccessfully(str.c_str()); ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("Specialization constant must be a boolean")); + HasSubstr("OpSpecConstantFalse Result Type '1[%int]' is not " + "a boolean type")); } TEST_F(ValidateData, missing_forward_pointer_decl) { @@ -526,7 +659,7 @@ TEST_F(ValidateData, missing_forward_pointer_decl) { CompileSuccessfully(str.c_str()); ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("must first be declared using OpTypeForwardPointer")); + HasSubstr("Operand 3[%3] requires a previous definition")); } TEST_F(ValidateData, missing_forward_pointer_decl_self_reference) { @@ -536,8 +669,9 @@ TEST_F(ValidateData, missing_forward_pointer_decl_self_reference) { )"; CompileSuccessfully(str.c_str()); ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("must first be declared using OpTypeForwardPointer")); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Operand 2[%_struct_2] requires a previous definition")); } TEST_F(ValidateData, forward_pointer_missing_definition) { @@ -562,8 +696,8 @@ OpTypeForwardPointer %_ptr_Generic_struct_A Generic CompileSuccessfully(str.c_str()); ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("Found a forward reference to a non-pointer type in " - "OpTypeStruct instruction.")); + HasSubstr("Pointer type in OpTypeForwardPointer is not a pointer " + "type.\n OpTypeForwardPointer %float Generic\n")); } TEST_F(ValidateData, forward_ref_points_to_non_struct) { @@ -576,9 +710,7 @@ OpTypeForwardPointer %_ptr_Generic_struct_A Generic CompileSuccessfully(str.c_str()); ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("A forward reference operand in an OpTypeStruct must " - "be an OpTypePointer that points to an OpTypeStruct. " - "Found OpTypePointer that points to OpTypeInt.")); + HasSubstr("Forward pointers must point to a structure")); } TEST_F(ValidateData, struct_forward_pointer_good) { @@ -595,19 +727,31 @@ OpTypeForwardPointer %_ptr_Generic_struct_A Generic } TEST_F(ValidateData, ext_16bit_storage_caps_allow_free_fp_rounding_mode) { - for (const char* cap : {"StorageUniform16", "StorageUniformBufferBlock16", - "StoragePushConstant16", "StorageInputOutput16"}) { + for (const char* cap : {"StorageUniform16", "StorageUniformBufferBlock16"}) { for (const char* mode : {"RTE", "RTZ", "RTP", "RTN"}) { std::string str = std::string(R"( OpCapability Shader OpCapability Linkage OpCapability )") + cap + R"( + OpExtension "SPV_KHR_storage_buffer_storage_class" + OpExtension "SPV_KHR_variable_pointers" OpExtension "SPV_KHR_16bit_storage" OpMemoryModel Logical GLSL450 - OpDecorate %2 FPRoundingMode )" + mode + R"( - %1 = OpTypeFloat 32 - %2 = OpConstant %1 1.25 + OpDecorate %_ FPRoundingMode )" + mode + R"( + %half = OpTypeFloat 16 + %float = OpTypeFloat 32 + %float_1_25 = OpConstant %float 1.25 + %half_ptr = OpTypePointer StorageBuffer %half + %half_ptr_var = OpVariable %half_ptr StorageBuffer + %void = OpTypeVoid + %func = OpTypeFunction %void + %main = OpFunction %void None %func + %main_entry = OpLabel + %_ = OpFConvert %half %float_1_25 + OpStore %half_ptr_var %_ + OpReturn + OpFunctionEnd )"; CompileSuccessfully(str.c_str()); ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); @@ -620,23 +764,186 @@ TEST_F(ValidateData, vulkan_disallow_free_fp_rounding_mode) { for (const auto env : {SPV_ENV_VULKAN_1_0, SPV_ENV_VULKAN_1_1}) { std::string str = std::string(R"( OpCapability Shader + OpExtension "SPV_KHR_storage_buffer_storage_class" + OpExtension "SPV_KHR_variable_pointers" OpMemoryModel Logical GLSL450 - OpDecorate %2 FPRoundingMode )") + + OpDecorate %_ FPRoundingMode )") + mode + R"( - %1 = OpTypeFloat 32 - %2 = OpConstant %1 1.25 + %half = OpTypeFloat 16 + %float = OpTypeFloat 32 + %float_1_25 = OpConstant %float 1.25 + %half_ptr = OpTypePointer StorageBuffer %half + %half_ptr_var = OpVariable %half_ptr StorageBuffer + %void = OpTypeVoid + %func = OpTypeFunction %void + %main = OpFunction %void None %func + %main_entry = OpLabel + %_ = OpFConvert %half %float_1_25 + OpStore %half_ptr_var %_ + OpReturn + OpFunctionEnd )"; CompileSuccessfully(str.c_str()); ASSERT_EQ(SPV_ERROR_INVALID_CAPABILITY, ValidateInstructions(env)); EXPECT_THAT( getDiagnosticString(), - HasSubstr("Operand 2 of Decorate requires one of these capabilities: " - "StorageBuffer16BitAccess StorageUniform16 " - "StoragePushConstant16 StorageInputOutput16")); + HasSubstr( + "Operand 2 of Decorate requires one of these capabilities: " + "StorageBuffer16BitAccess UniformAndStorageBuffer16BitAccess " + "StoragePushConstant16 StorageInputOutput16")); } } } +TEST_F(ValidateData, void_array) { + std::string str = header + R"( + %void = OpTypeVoid + %int = OpTypeInt 32 0 + %int_5 = OpConstant %int 5 + %array = OpTypeArray %void %int_5 + )"; + + CompileSuccessfully(str.c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("OpTypeArray Element Type '1[%void]' is a void type.")); +} + +TEST_F(ValidateData, void_runtime_array) { + std::string str = header + R"( + %void = OpTypeVoid + %array = OpTypeRuntimeArray %void + )"; + + CompileSuccessfully(str.c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "OpTypeRuntimeArray Element Type '1[%void]' is a void type.")); +} + +TEST_F(ValidateData, vulkan_RTA_array_at_end_of_struct) { + std::string str = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %func "func" + OpExecutionMode %func OriginUpperLeft + OpDecorate %array_t ArrayStride 4 + OpMemberDecorate %struct_t 0 Offset 0 + OpMemberDecorate %struct_t 1 Offset 4 + OpDecorate %struct_t Block + %uint_t = OpTypeInt 32 0 + %array_t = OpTypeRuntimeArray %uint_t + %struct_t = OpTypeStruct %uint_t %array_t +%struct_ptr = OpTypePointer StorageBuffer %struct_t + %2 = OpVariable %struct_ptr StorageBuffer + %void = OpTypeVoid + %func_t = OpTypeFunction %void + %func = OpFunction %void None %func_t + %1 = OpLabel + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(str.c_str(), SPV_ENV_VULKAN_1_1); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1)); +} + +TEST_F(ValidateData, vulkan_RTA_not_at_end_of_struct) { + std::string str = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %func "func" + OpExecutionMode %func OriginUpperLeft + OpDecorate %array_t ArrayStride 4 + OpMemberDecorate %struct_t 0 Offset 0 + OpMemberDecorate %struct_t 1 Offset 4 + OpDecorate %struct_t Block + %uint_t = OpTypeInt 32 0 + %array_t = OpTypeRuntimeArray %uint_t + %struct_t = OpTypeStruct %array_t %uint_t +%struct_ptr = OpTypePointer StorageBuffer %struct_t + %2 = OpVariable %struct_ptr StorageBuffer + %void = OpTypeVoid + %func_t = OpTypeFunction %void + %func = OpFunction %void None %func_t + %1 = OpLabel + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(str.c_str(), SPV_ENV_VULKAN_1_1); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("In Vulkan, OpTypeRuntimeArray must only be used for " + "the last member of an OpTypeStruct\n %_struct_3 = " + "OpTypeStruct %_runtimearr_uint %uint\n")); +} + +TEST_F(ValidateData, webgpu_RTA_array_at_end_of_struct) { + std::string str = R"( + OpCapability Shader + OpCapability VulkanMemoryModelKHR + OpExtension "SPV_KHR_vulkan_memory_model" + OpMemoryModel Logical VulkanKHR + OpEntryPoint Fragment %func "func" + OpExecutionMode %func OriginUpperLeft + OpDecorate %array_t ArrayStride 4 + OpMemberDecorate %struct_t 0 Offset 0 + OpMemberDecorate %struct_t 1 Offset 4 + OpDecorate %struct_t Block + %uint_t = OpTypeInt 32 0 + %array_t = OpTypeRuntimeArray %uint_t + %struct_t = OpTypeStruct %uint_t %array_t +%struct_ptr = OpTypePointer StorageBuffer %struct_t + %2 = OpVariable %struct_ptr StorageBuffer + %void = OpTypeVoid + %func_t = OpTypeFunction %void + %func = OpFunction %void None %func_t + %1 = OpLabel + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(str.c_str(), SPV_ENV_WEBGPU_0); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); +} + +TEST_F(ValidateData, webgpu_RTA_not_at_end_of_struct) { + std::string str = R"( + OpCapability Shader + OpCapability VulkanMemoryModelKHR + OpExtension "SPV_KHR_vulkan_memory_model" + OpMemoryModel Logical VulkanKHR + OpEntryPoint Fragment %func "func" + OpExecutionMode %func OriginUpperLeft + OpDecorate %array_t ArrayStride 4 + OpMemberDecorate %struct_t 0 Offset 0 + OpMemberDecorate %struct_t 1 Offset 4 + OpDecorate %struct_t Block + %uint_t = OpTypeInt 32 0 + %array_t = OpTypeRuntimeArray %uint_t + %struct_t = OpTypeStruct %array_t %uint_t +%struct_ptr = OpTypePointer StorageBuffer %struct_t + %2 = OpVariable %struct_ptr StorageBuffer + %void = OpTypeVoid + %func_t = OpTypeFunction %void + %func = OpFunction %void None %func_t + %1 = OpLabel + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(str.c_str(), SPV_ENV_WEBGPU_0); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("In WebGPU, OpTypeRuntimeArray must only be used for " + "the last member of an OpTypeStruct\n %_struct_3 = " + "OpTypeStruct %_runtimearr_uint %uint\n")); +} + } // namespace } // namespace val } // namespace spvtools diff --git a/third_party/spirv-tools/test/val/val_decoration_test.cpp b/third_party/spirv-tools/test/val/val_decoration_test.cpp index 4638af8688..256e115f57 100644 --- a/third_party/spirv-tools/test/val/val_decoration_test.cpp +++ b/third_party/spirv-tools/test/val/val_decoration_test.cpp @@ -19,17 +19,31 @@ #include "gmock/gmock.h" #include "source/val/decoration.h" +#include "test/test_fixture.h" #include "test/unit_spirv.h" +#include "test/val/val_code_generator.h" #include "test/val/val_fixtures.h" namespace spvtools { namespace val { namespace { +using ::testing::Combine; using ::testing::Eq; using ::testing::HasSubstr; +using ::testing::Values; + +struct TestResult { + TestResult(spv_result_t in_validation_result = SPV_SUCCESS, + const std::string& in_error_str = "") + : validation_result(in_validation_result), error_str(in_error_str) {} + spv_result_t validation_result; + const std::string error_str; +}; using ValidateDecorations = spvtest::ValidateBase; +using ValidateWebGPUCombineDecorationResult = + spvtest::ValidateBase>; TEST_F(ValidateDecorations, ValidateOpDecorateRegistration) { std::string spirv = R"( @@ -37,7 +51,7 @@ TEST_F(ValidateDecorations, ValidateOpDecorateRegistration) { OpCapability Linkage OpMemoryModel Logical GLSL450 OpDecorate %1 ArrayStride 4 - OpDecorate %1 Uniform + OpDecorate %1 RelaxedPrecision %2 = OpTypeFloat 32 %1 = OpTypeRuntimeArray %2 ; Since %1 is used first in Decoration, it gets id 1. @@ -49,7 +63,7 @@ TEST_F(ValidateDecorations, ValidateOpDecorateRegistration) { EXPECT_THAT( vstate_->id_decorations(id), Eq(std::vector{Decoration(SpvDecorationArrayStride, {4}), - Decoration(SpvDecorationUniform)})); + Decoration(SpvDecorationRelaxedPrecision)})); } TEST_F(ValidateDecorations, ValidateOpMemberDecorateRegistration) { @@ -85,13 +99,37 @@ TEST_F(ValidateDecorations, ValidateOpMemberDecorateRegistration) { Decoration(SpvDecorationBufferBlock)})); } +TEST_F(ValidateDecorations, ValidateOpMemberDecorateOutOfBound) { + std::string spirv = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "Main" + OpExecutionMode %1 OriginUpperLeft + OpMemberDecorate %_struct_2 1 RelaxedPrecision + %void = OpTypeVoid + %4 = OpTypeFunction %void + %float = OpTypeFloat 32 + %_struct_2 = OpTypeStruct %float + %1 = OpFunction %void None %4 + %6 = OpLabel + OpReturn + OpFunctionEnd +)"; + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Index 1 provided in OpMemberDecorate for struct " + "2[%_struct_2] is out of bounds. The structure has 1 " + "members. Largest valid index is 0.")); +} + TEST_F(ValidateDecorations, ValidateGroupDecorateRegistration) { std::string spirv = R"( OpCapability Shader OpCapability Linkage OpMemoryModel Logical GLSL450 OpDecorate %1 DescriptorSet 0 - OpDecorate %1 NonWritable + OpDecorate %1 RelaxedPrecision OpDecorate %1 Restrict %1 = OpDecorationGroup OpGroupDecorate %1 %2 %3 @@ -112,9 +150,10 @@ TEST_F(ValidateDecorations, ValidateGroupDecorateRegistration) { EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState()); // Decoration group has 3 decorations. - auto expected_decorations = std::vector{ - Decoration(SpvDecorationDescriptorSet, {0}), - Decoration(SpvDecorationNonWritable), Decoration(SpvDecorationRestrict)}; + auto expected_decorations = + std::vector{Decoration(SpvDecorationDescriptorSet, {0}), + Decoration(SpvDecorationRelaxedPrecision), + Decoration(SpvDecorationRestrict)}; // Decoration group is applied to id 1, 2, 3, and 4. Note that id 1 (which is // the decoration group id) also has all the decorations. @@ -124,6 +163,44 @@ TEST_F(ValidateDecorations, ValidateGroupDecorateRegistration) { EXPECT_THAT(vstate_->id_decorations(4), Eq(expected_decorations)); } +TEST_F(ValidateDecorations, WebGPUOpDecorationGroupBad) { + std::string spirv = R"( + OpCapability Shader + OpCapability VulkanMemoryModelKHR + OpExtension "SPV_KHR_vulkan_memory_model" + OpMemoryModel Logical VulkanKHR + OpDecorate %1 DescriptorSet 0 + OpDecorate %1 NonWritable + OpDecorate %1 Restrict + %1 = OpDecorationGroup + OpGroupDecorate %1 %2 %3 + OpGroupDecorate %1 %4 + %float = OpTypeFloat 32 +%_runtimearr_float = OpTypeRuntimeArray %float + %_struct_9 = OpTypeStruct %_runtimearr_float +%_ptr_Uniform__struct_9 = OpTypePointer Uniform %_struct_9 + %2 = OpVariable %_ptr_Uniform__struct_9 Uniform + %_struct_10 = OpTypeStruct %_runtimearr_float +%_ptr_Uniform__struct_10 = OpTypePointer Uniform %_struct_10 + %3 = OpVariable %_ptr_Uniform__struct_10 Uniform + %_struct_11 = OpTypeStruct %_runtimearr_float +%_ptr_Uniform__struct_11 = OpTypePointer Uniform %_struct_11 + %4 = OpVariable %_ptr_Uniform__struct_11 Uniform + )"; + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("OpDecorationGroup is not allowed in the WebGPU " + "execution environment.\n %1 = OpDecorationGroup\n")); +} + +// For WebGPU, OpGroupDecorate does not have a test case, because it requires +// being preceded by OpDecorationGroup, which will cause a validation error. + +// For WebGPU, OpGroupMemberDecorate does not have a test case, because it +// requires being preceded by OpDecorationGroup, which will cause a validation +// error. + TEST_F(ValidateDecorations, ValidateGroupMemberDecorateRegistration) { std::string spirv = R"( OpCapability Shader @@ -238,10 +315,11 @@ TEST_F(ValidateDecorations, StructContainsBuiltInStructBad) { CompileSuccessfully(spirv); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("Structure 1 contains members with BuiltIn " - "decoration. Therefore this structure may not be " - "contained as a member of another structure type. " - "Structure 4 contains structure 1.")); + HasSubstr("Structure 1[%_struct_1] contains members with " + "BuiltIn decoration. Therefore this structure may not " + "be contained as a member of another structure type. " + "Structure 4[%_struct_4] contains structure " + "1[%_struct_1].")); } TEST_F(ValidateDecorations, StructContainsNonBuiltInStructGood) { @@ -263,6 +341,8 @@ TEST_F(ValidateDecorations, MultipleBuiltInObjectsConsumedByOpEntryPointBad) { OpCapability Geometry OpMemoryModel Logical GLSL450 OpEntryPoint Geometry %main "main" %in_1 %in_2 + OpExecutionMode %main InputPoints + OpExecutionMode %main OutputPoints OpMemberDecorate %struct_1 0 BuiltIn InvocationId OpMemberDecorate %struct_2 0 BuiltIn Position %int = OpTypeInt 32 1 @@ -295,6 +375,8 @@ TEST_F(ValidateDecorations, OpCapability Geometry OpMemoryModel Logical GLSL450 OpEntryPoint Geometry %main "main" %in_1 %out_1 + OpExecutionMode %main InputPoints + OpExecutionMode %main OutputPoints OpMemberDecorate %struct_1 0 BuiltIn InvocationId OpMemberDecorate %struct_2 0 BuiltIn Position %int = OpTypeInt 32 1 @@ -322,6 +404,8 @@ TEST_F(ValidateDecorations, NoBuiltInObjectsConsumedByOpEntryPointGood) { OpCapability Geometry OpMemoryModel Logical GLSL450 OpEntryPoint Geometry %main "main" %in_1 %out_1 + OpExecutionMode %main InputPoints + OpExecutionMode %main OutputPoints %int = OpTypeInt 32 1 %void = OpTypeVoid %func = OpTypeFunction %void @@ -591,12 +675,12 @@ TEST_F(ValidateDecorations, RuntimeArrayOfDescriptorSetsIsAllowed) { %10 = OpTypeImage %float 2D 0 0 0 1 Unknown %11 = OpTypeSampledImage %10 %_runtimearr_11 = OpTypeRuntimeArray %11 -%_ptr_UniformConstant__runtimearr_11 = OpTypePointer UniformConstant %_runtimearr_11 - %s2d = OpVariable %_ptr_UniformConstant__runtimearr_11 UniformConstant +%_ptr_Uniform__runtimearr_11 = OpTypePointer Uniform %_runtimearr_11 + %s2d = OpVariable %_ptr_Uniform__runtimearr_11 Uniform %int = OpTypeInt 32 1 %_ptr_Input_int = OpTypePointer Input %int %i = OpVariable %_ptr_Input_int Input -%_ptr_UniformConstant_11 = OpTypePointer UniformConstant %11 +%_ptr_Uniform_11 = OpTypePointer Uniform %11 %v2float = OpTypeVector %float 2 %float_0_300000012 = OpConstant %float 0.300000012 %24 = OpConstantComposite %v2float %float_0_300000012 %float_0_300000012 @@ -605,7 +689,7 @@ TEST_F(ValidateDecorations, RuntimeArrayOfDescriptorSetsIsAllowed) { %5 = OpLabel %v = OpVariable %_ptr_Function_v4float Function %18 = OpLoad %int %i - %20 = OpAccessChain %_ptr_UniformConstant_11 %s2d %18 + %20 = OpAccessChain %_ptr_Uniform_11 %s2d %18 %21 = OpLoad %11 %20 %26 = OpImageSampleExplicitLod %v4float %21 %24 Lod %float_0 OpStore %v %26 @@ -616,119 +700,6 @@ TEST_F(ValidateDecorations, RuntimeArrayOfDescriptorSetsIsAllowed) { EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState()); } -// #version 440 -// #extension GL_EXT_nonuniform_qualifier : enable -// layout(binding = 1) uniform sampler2D s2d[][2]; -// layout(location = 0) in nonuniformEXT int i; -// void main() -// { -// vec4 v = texture(s2d[i][i], vec2(0.3)); -// } -TEST_F(ValidateDecorations, RuntimeArrayOfArraysOfDescriptorSetsIsDisallowed) { - const spv_target_env env = SPV_ENV_VULKAN_1_0; - std::string spirv = R"( - OpCapability Shader - OpCapability ShaderNonUniformEXT - OpCapability RuntimeDescriptorArrayEXT - OpCapability SampledImageArrayNonUniformIndexingEXT - OpExtension "SPV_EXT_descriptor_indexing" - %1 = OpExtInstImport "GLSL.std.450" - OpMemoryModel Logical GLSL450 - OpEntryPoint Vertex %main "main" %i - OpSource GLSL 440 - OpSourceExtension "GL_EXT_nonuniform_qualifier" - OpName %main "main" - OpName %v "v" - OpName %s2d "s2d" - OpName %i "i" - OpDecorate %s2d DescriptorSet 0 - OpDecorate %s2d Binding 1 - OpDecorate %i Location 0 - OpDecorate %i NonUniformEXT - OpDecorate %21 NonUniformEXT - OpDecorate %22 NonUniformEXT - OpDecorate %25 NonUniformEXT - %void = OpTypeVoid - %3 = OpTypeFunction %void - %float = OpTypeFloat 32 - %v4float = OpTypeVector %float 4 -%_ptr_Function_v4float = OpTypePointer Function %v4float - %10 = OpTypeImage %float 2D 0 0 0 1 Unknown - %11 = OpTypeSampledImage %10 - %uint = OpTypeInt 32 0 - %uint_2 = OpConstant %uint 2 -%_arr_11_uint_2 = OpTypeArray %11 %uint_2 -%_runtimearr__arr_11_uint_2 = OpTypeRuntimeArray %_arr_11_uint_2 -%_ptr_UniformConstant__runtimearr__arr_11_uint_2 = OpTypePointer UniformConstant %_runtimearr__arr_11_uint_2 - %s2d = OpVariable %_ptr_UniformConstant__runtimearr__arr_11_uint_2 UniformConstant - %int = OpTypeInt 32 1 -%_ptr_Input_int = OpTypePointer Input %int - %i = OpVariable %_ptr_Input_int Input -%_ptr_UniformConstant_11 = OpTypePointer UniformConstant %11 - %v2float = OpTypeVector %float 2 -%float_0_300000012 = OpConstant %float 0.300000012 - %28 = OpConstantComposite %v2float %float_0_300000012 %float_0_300000012 - %float_0 = OpConstant %float 0 - %main = OpFunction %void None %3 - %5 = OpLabel - %v = OpVariable %_ptr_Function_v4float Function - %21 = OpLoad %int %i - %22 = OpLoad %int %i - %24 = OpAccessChain %_ptr_UniformConstant_11 %s2d %21 %22 - %25 = OpLoad %11 %24 - %30 = OpImageSampleExplicitLod %v4float %25 %28 Lod %float_0 - OpStore %v %30 - OpReturn - OpFunctionEnd -)"; - CompileSuccessfully(spirv, env); - - EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState(env)); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("Only a single level of array is allowed for " - "descriptor set variables")); -} - -// #version 440 -// layout (set=1, binding=1) uniform sampler2D variableName[2][2]; -// void main() { -// } -TEST_F(ValidateDecorations, ArrayOfArraysOfDescriptorSetsIsDisallowed) { - const spv_target_env env = SPV_ENV_VULKAN_1_0; - std::string spirv = R"( - OpCapability Shader - %1 = OpExtInstImport "GLSL.std.450" - OpMemoryModel Logical GLSL450 - OpEntryPoint Vertex %main "main" - OpSource GLSL 440 - OpName %main "main" - OpName %variableName "variableName" - OpDecorate %variableName DescriptorSet 1 - OpDecorate %variableName Binding 1 - %void = OpTypeVoid - %3 = OpTypeFunction %void - %float = OpTypeFloat 32 - %7 = OpTypeImage %float 2D 0 0 0 1 Unknown - %8 = OpTypeSampledImage %7 - %uint = OpTypeInt 32 0 - %uint_2 = OpConstant %uint 2 -%_arr_8_uint_2 = OpTypeArray %8 %uint_2 -%_arr__arr_8_uint_2_uint_2 = OpTypeArray %_arr_8_uint_2 %uint_2 -%_ptr_UniformConstant__arr__arr_8_uint_2_uint_2 = OpTypePointer UniformConstant %_arr__arr_8_uint_2_uint_2 -%variableName = OpVariable %_ptr_UniformConstant__arr__arr_8_uint_2_uint_2 UniformConstant - %main = OpFunction %void None %3 - %5 = OpLabel - OpReturn - OpFunctionEnd -)"; - CompileSuccessfully(spirv, env); - - EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState(env)); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("Only a single level of array is allowed for " - "descriptor set variables")); -} - TEST_F(ValidateDecorations, BlockMissingOffsetBad) { std::string spirv = R"( OpCapability Shader @@ -1540,6 +1511,158 @@ TEST_F(ValidateDecorations, BlockLayoutPermitsTightVec3ScalarPackingGood) { << getDiagnosticString(); } +TEST_F(ValidateDecorations, BlockCantAppearWithinABlockBad) { + // See https://github.com/KhronosGroup/SPIRV-Tools/issues/1587 + std::string spirv = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %main "main" + OpSource GLSL 450 + OpMemberDecorate %S 0 Offset 0 + OpMemberDecorate %S 1 Offset 16 + OpMemberDecorate %S2 0 Offset 0 + OpMemberDecorate %S2 1 Offset 12 + OpDecorate %S Block + OpDecorate %S2 Block + OpDecorate %B DescriptorSet 0 + OpDecorate %B Binding 0 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %S2 = OpTypeStruct %float %float + %S = OpTypeStruct %float %S2 +%_ptr_Uniform_S = OpTypePointer Uniform %S + %B = OpVariable %_ptr_Uniform_S Uniform + %main = OpFunction %void None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("rules: A Block or BufferBlock cannot be nested within " + "another Block or BufferBlock.")); +} + +TEST_F(ValidateDecorations, BufferblockCantAppearWithinABufferblockBad) { + // See https://github.com/KhronosGroup/SPIRV-Tools/issues/1587 + std::string spirv = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %main "main" + OpSource GLSL 450 + OpMemberDecorate %S 0 Offset 0 + OpMemberDecorate %S 1 Offset 16 + OpMemberDecorate %S2 0 Offset 0 + OpMemberDecorate %S2 1 Offset 16 + OpMemberDecorate %S3 0 Offset 0 + OpMemberDecorate %S3 1 Offset 12 + OpDecorate %S BufferBlock + OpDecorate %S3 BufferBlock + OpDecorate %B DescriptorSet 0 + OpDecorate %B Binding 0 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %S3 = OpTypeStruct %float %float + %S2 = OpTypeStruct %float %S3 + %S = OpTypeStruct %float %S2 +%_ptr_Uniform_S = OpTypePointer Uniform %S + %B = OpVariable %_ptr_Uniform_S Uniform + %main = OpFunction %void None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("rules: A Block or BufferBlock cannot be nested within " + "another Block or BufferBlock.")); +} + +TEST_F(ValidateDecorations, BufferblockCantAppearWithinABlockBad) { + // See https://github.com/KhronosGroup/SPIRV-Tools/issues/1587 + std::string spirv = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %main "main" + OpSource GLSL 450 + OpMemberDecorate %S 0 Offset 0 + OpMemberDecorate %S 1 Offset 16 + OpMemberDecorate %S2 0 Offset 0 + OpMemberDecorate %S2 1 Offset 16 + OpMemberDecorate %S3 0 Offset 0 + OpMemberDecorate %S3 1 Offset 12 + OpDecorate %S Block + OpDecorate %S3 BufferBlock + OpDecorate %B DescriptorSet 0 + OpDecorate %B Binding 0 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %S3 = OpTypeStruct %float %float + %S2 = OpTypeStruct %float %S3 + %S = OpTypeStruct %float %S2 +%_ptr_Uniform_S = OpTypePointer Uniform %S + %B = OpVariable %_ptr_Uniform_S Uniform + %main = OpFunction %void None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("rules: A Block or BufferBlock cannot be nested within " + "another Block or BufferBlock.")); +} + +TEST_F(ValidateDecorations, BlockCantAppearWithinABufferblockBad) { + // See https://github.com/KhronosGroup/SPIRV-Tools/issues/1587 + std::string spirv = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %main "main" + OpSource GLSL 450 + OpMemberDecorate %S 0 Offset 0 + OpMemberDecorate %S 1 Offset 16 + OpMemberDecorate %S2 0 Offset 0 + OpMemberDecorate %S2 1 Offset 16 + OpMemberDecorate %S3 0 Offset 0 + OpMemberDecorate %S3 1 Offset 16 + OpMemberDecorate %S4 0 Offset 0 + OpMemberDecorate %S4 1 Offset 12 + OpDecorate %S BufferBlock + OpDecorate %S4 Block + OpDecorate %B DescriptorSet 0 + OpDecorate %B Binding 0 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %S4 = OpTypeStruct %float %float + %S3 = OpTypeStruct %float %S4 + %S2 = OpTypeStruct %float %S3 + %S = OpTypeStruct %float %S2 +%_ptr_Uniform_S = OpTypePointer Uniform %S + %B = OpVariable %_ptr_Uniform_S Uniform + %main = OpFunction %void None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("rules: A Block or BufferBlock cannot be nested within " + "another Block or BufferBlock.")); +} + TEST_F(ValidateDecorations, BlockLayoutForbidsTightScalarVec3PackingBad) { // See https://github.com/KhronosGroup/SPIRV-Tools/issues/1666 std::string spirv = R"( @@ -1642,7 +1765,7 @@ TEST_F(ValidateDecorations, getDiagnosticString(), HasSubstr( "Structure id 2 decorated as Block for variable in Uniform storage " - "class must follow standard uniform buffer layout rules: member 1 at " + "class must follow relaxed uniform buffer layout rules: member 1 at " "offset 5 is not aligned to scalar element size 4")); } @@ -1679,6 +1802,263 @@ TEST_F(ValidateDecorations, EXPECT_THAT(getDiagnosticString(), Eq("")); } +TEST_F(ValidateDecorations, + BlockLayoutPermitsTightScalarVec3PackingWithScalarLayoutGood) { + // Same as previous test, but with scalar block layout. + std::string spirv = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %main "main" + OpSource GLSL 450 + OpMemberDecorate %S 0 Offset 0 + OpMemberDecorate %S 1 Offset 4 + OpDecorate %S Block + OpDecorate %B DescriptorSet 0 + OpDecorate %B Binding 0 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %v3float = OpTypeVector %float 3 + %S = OpTypeStruct %float %v3float +%_ptr_Uniform_S = OpTypePointer Uniform %S + %B = OpVariable %_ptr_Uniform_S Uniform + %main = OpFunction %void None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + + CompileSuccessfully(spirv); + spvValidatorOptionsSetScalarBlockLayout(getValidatorOptions(), true); + EXPECT_EQ(SPV_SUCCESS, + ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateDecorations, + BlockLayoutPermitsScalarAlignedArrayWithScalarLayoutGood) { + // The array at offset 4 is ok with scalar block layout. + std::string spirv = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %main "main" + OpSource GLSL 450 + OpMemberDecorate %S 0 Offset 0 + OpMemberDecorate %S 1 Offset 4 + OpDecorate %S Block + OpDecorate %B DescriptorSet 0 + OpDecorate %B Binding 0 + OpDecorate %arr_float ArrayStride 4 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %uint = OpTypeInt 32 0 + %uint_3 = OpConstant %uint 3 + %float = OpTypeFloat 32 + %arr_float = OpTypeArray %float %uint_3 + %S = OpTypeStruct %float %arr_float +%_ptr_Uniform_S = OpTypePointer Uniform %S + %B = OpVariable %_ptr_Uniform_S Uniform + %main = OpFunction %void None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + + CompileSuccessfully(spirv); + spvValidatorOptionsSetScalarBlockLayout(getValidatorOptions(), true); + EXPECT_EQ(SPV_SUCCESS, + ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateDecorations, + BlockLayoutPermitsScalarAlignedArrayOfVec3WithScalarLayoutGood) { + // The array at offset 4 is ok with scalar block layout, even though + // its elements are vec3. + // This is the same as the previous case, but the array elements are vec3 + // instead of float. + std::string spirv = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %main "main" + OpSource GLSL 450 + OpMemberDecorate %S 0 Offset 0 + OpMemberDecorate %S 1 Offset 4 + OpDecorate %S Block + OpDecorate %B DescriptorSet 0 + OpDecorate %B Binding 0 + OpDecorate %arr_vec3 ArrayStride 12 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %uint = OpTypeInt 32 0 + %uint_3 = OpConstant %uint 3 + %float = OpTypeFloat 32 + %vec3 = OpTypeVector %float 3 + %arr_vec3 = OpTypeArray %vec3 %uint_3 + %S = OpTypeStruct %float %arr_vec3 +%_ptr_Uniform_S = OpTypePointer Uniform %S + %B = OpVariable %_ptr_Uniform_S Uniform + %main = OpFunction %void None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + + CompileSuccessfully(spirv); + spvValidatorOptionsSetScalarBlockLayout(getValidatorOptions(), true); + EXPECT_EQ(SPV_SUCCESS, + ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateDecorations, + BlockLayoutPermitsScalarAlignedStructWithScalarLayoutGood) { + // Scalar block layout permits the struct at offset 4, even though + // it contains a vector with base alignment 8 and scalar alignment 4. + std::string spirv = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %main "main" + OpSource GLSL 450 + OpMemberDecorate %S 0 Offset 0 + OpMemberDecorate %S 1 Offset 4 + OpMemberDecorate %st 0 Offset 0 + OpMemberDecorate %st 1 Offset 8 + OpDecorate %S Block + OpDecorate %B DescriptorSet 0 + OpDecorate %B Binding 0 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %vec2 = OpTypeVector %float 2 + %st = OpTypeStruct %vec2 %float + %S = OpTypeStruct %float %st +%_ptr_Uniform_S = OpTypePointer Uniform %S + %B = OpVariable %_ptr_Uniform_S Uniform + %main = OpFunction %void None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + + CompileSuccessfully(spirv); + spvValidatorOptionsSetScalarBlockLayout(getValidatorOptions(), true); + EXPECT_EQ(SPV_SUCCESS, + ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F( + ValidateDecorations, + BlockLayoutPermitsFieldsInBaseAlignmentPaddingAtEndOfStructWithScalarLayoutGood) { + // Scalar block layout permits fields in what would normally be the padding at + // the end of a struct. + std::string spirv = R"( + OpCapability Shader + OpCapability Float64 + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %main "main" + OpSource GLSL 450 + OpMemberDecorate %st 0 Offset 0 + OpMemberDecorate %st 1 Offset 8 + OpMemberDecorate %S 0 Offset 0 + OpMemberDecorate %S 1 Offset 12 + OpDecorate %S Block + OpDecorate %B DescriptorSet 0 + OpDecorate %B Binding 0 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %double = OpTypeFloat 64 + %st = OpTypeStruct %double %float + %S = OpTypeStruct %st %float +%_ptr_Uniform_S = OpTypePointer Uniform %S + %B = OpVariable %_ptr_Uniform_S Uniform + %main = OpFunction %void None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + + CompileSuccessfully(spirv); + spvValidatorOptionsSetScalarBlockLayout(getValidatorOptions(), true); + EXPECT_EQ(SPV_SUCCESS, + ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F( + ValidateDecorations, + BlockLayoutPermitsStraddlingVectorWithScalarLayoutOverrideRelaxBlockLayoutGood) { + // Same as previous, but set relaxed block layout first. Scalar layout always + // wins. + std::string spirv = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %main "main" + OpSource GLSL 450 + OpMemberDecorate %S 0 Offset 0 + OpMemberDecorate %S 1 Offset 4 + OpDecorate %S Block + OpDecorate %B DescriptorSet 0 + OpDecorate %B Binding 0 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %vec4 = OpTypeVector %float 4 + %S = OpTypeStruct %float %vec4 +%_ptr_Uniform_S = OpTypePointer Uniform %S + %B = OpVariable %_ptr_Uniform_S Uniform + %main = OpFunction %void None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + + CompileSuccessfully(spirv); + spvValidatorOptionsSetRelaxBlockLayout(getValidatorOptions(), true); + spvValidatorOptionsSetScalarBlockLayout(getValidatorOptions(), true); + EXPECT_EQ(SPV_SUCCESS, + ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F( + ValidateDecorations, + BlockLayoutPermitsStraddlingVectorWithRelaxedLayoutOverridenByScalarBlockLayoutGood) { + // Same as previous, but set scalar block layout first. Scalar layout always + // wins. + std::string spirv = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %main "main" + OpSource GLSL 450 + OpMemberDecorate %S 0 Offset 0 + OpMemberDecorate %S 1 Offset 4 + OpDecorate %S Block + OpDecorate %B DescriptorSet 0 + OpDecorate %B Binding 0 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %vec4 = OpTypeVector %float 4 + %S = OpTypeStruct %float %vec4 +%_ptr_Uniform_S = OpTypePointer Uniform %S + %B = OpVariable %_ptr_Uniform_S Uniform + %main = OpFunction %void None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + + CompileSuccessfully(spirv); + spvValidatorOptionsSetScalarBlockLayout(getValidatorOptions(), true); + spvValidatorOptionsSetRelaxBlockLayout(getValidatorOptions(), true); + EXPECT_EQ(SPV_SUCCESS, + ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + TEST_F(ValidateDecorations, BufferBlock16bitStandardStorageBufferLayout) { std::string spirv = R"( OpCapability Shader @@ -1720,7 +2100,7 @@ TEST_F(ValidateDecorations, BufferBlock16bitStandardStorageBufferLayout) { EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState()); } -TEST_F(ValidateDecorations, BlockArrayBaseAlignmentGood) { +TEST_F(ValidateDecorations, BlockArrayExtendedAlignmentGood) { // For uniform buffer, Array base alignment is 16, and ArrayStride // must be a multiple of 16. std::string spirv = R"( @@ -1753,7 +2133,7 @@ TEST_F(ValidateDecorations, BlockArrayBaseAlignmentGood) { << getDiagnosticString(); } -TEST_F(ValidateDecorations, BlockArrayBadAlignmentBad) { +TEST_F(ValidateDecorations, BlockArrayBaseAlignmentBad) { // For uniform buffer, Array base alignment is 16. std::string spirv = R"( OpCapability Shader @@ -1790,7 +2170,7 @@ TEST_F(ValidateDecorations, BlockArrayBadAlignmentBad) { "member 1 at offset 8 is not aligned to 16")); } -TEST_F(ValidateDecorations, BlockArrayBadAlignmentWithRelaxedLayoutStillBad) { +TEST_F(ValidateDecorations, BlockArrayBaseAlignmentWithRelaxedLayoutStillBad) { // For uniform buffer, Array base alignment is 16, and ArrayStride // must be a multiple of 16. This case uses relaxed block layout. Relaxed // layout only relaxes rules for vector alignment, not array alignment. @@ -1800,6 +2180,8 @@ TEST_F(ValidateDecorations, BlockArrayBadAlignmentWithRelaxedLayoutStillBad) { OpEntryPoint Vertex %main "main" OpSource GLSL 450 OpDecorate %_arr_float_uint_2 ArrayStride 16 + OpDecorate %u DescriptorSet 0 + OpDecorate %u Binding 0 OpMemberDecorate %S 0 Offset 0 OpMemberDecorate %S 1 Offset 8 OpDecorate %S Block @@ -1826,12 +2208,12 @@ TEST_F(ValidateDecorations, BlockArrayBadAlignmentWithRelaxedLayoutStillBad) { EXPECT_THAT( getDiagnosticString(), HasSubstr( - "Structure id 3 decorated as Block for variable in Uniform " + "Structure id 4 decorated as Block for variable in Uniform " "storage class must follow standard uniform buffer layout rules: " "member 1 at offset 8 is not aligned to 16")); } -TEST_F(ValidateDecorations, BlockArrayBadAlignmentWithVulkan1_1StillBad) { +TEST_F(ValidateDecorations, BlockArrayBaseAlignmentWithVulkan1_1StillBad) { // Same as previous test, but with Vulkan 1.1, which includes // VK_KHR_relaxed_block_layout in core. std::string spirv = R"( @@ -1840,6 +2222,8 @@ TEST_F(ValidateDecorations, BlockArrayBadAlignmentWithVulkan1_1StillBad) { OpEntryPoint Vertex %main "main" OpSource GLSL 450 OpDecorate %_arr_float_uint_2 ArrayStride 16 + OpDecorate %u DescriptorSet 0 + OpDecorate %u Binding 0 OpMemberDecorate %S 0 Offset 0 OpMemberDecorate %S 1 Offset 8 OpDecorate %S Block @@ -1865,11 +2249,80 @@ TEST_F(ValidateDecorations, BlockArrayBadAlignmentWithVulkan1_1StillBad) { EXPECT_THAT( getDiagnosticString(), HasSubstr( - "Structure id 3 decorated as Block for variable in Uniform " - "storage class must follow standard uniform buffer layout rules: " + "Structure id 4 decorated as Block for variable in Uniform " + "storage class must follow relaxed uniform buffer layout rules: " "member 1 at offset 8 is not aligned to 16")); } +TEST_F(ValidateDecorations, + BlockArrayBaseAlignmentWithBlockStandardLayoutGood) { + // Same as previous test, but with VK_KHR_uniform_buffer_standard_layout + std::string spirv = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %main "main" + OpSource GLSL 450 + OpDecorate %_arr_float_uint_2 ArrayStride 16 + OpDecorate %u DescriptorSet 0 + OpDecorate %u Binding 0 + OpMemberDecorate %S 0 Offset 0 + OpMemberDecorate %S 1 Offset 8 + OpDecorate %S Block + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %v2float = OpTypeVector %float 2 + %uint = OpTypeInt 32 0 + %uint_2 = OpConstant %uint 2 +%_arr_float_uint_2 = OpTypeArray %float %uint_2 + %S = OpTypeStruct %v2float %_arr_float_uint_2 +%_ptr_Uniform_S = OpTypePointer Uniform %S + %u = OpVariable %_ptr_Uniform_S Uniform + %main = OpFunction %void None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + + CompileSuccessfully(spirv); + spvValidatorOptionsSetUniformBufferStandardLayout(getValidatorOptions(), + true); + EXPECT_EQ(SPV_SUCCESS, + ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateDecorations, VulkanBufferBlockOnStorageBufferBad) { + std::string spirv = R"( + OpCapability Shader + OpExtension "SPV_KHR_storage_buffer_storage_class" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "main" + OpExecutionMode %1 OriginUpperLeft + + OpDecorate %struct BufferBlock + + %void = OpTypeVoid + %voidfn = OpTypeFunction %void + %float = OpTypeFloat 32 + %struct = OpTypeStruct %float + %ptr = OpTypePointer StorageBuffer %struct + %var = OpVariable %ptr StorageBuffer + + %1 = OpFunction %void None %voidfn + %label = OpLabel + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_ID, + ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("In Vulkan, BufferBlock is disallowed on variables in " + "the StorageBuffer storage class")); +} + TEST_F(ValidateDecorations, PushConstantArrayBaseAlignmentGood) { // Tests https://github.com/KhronosGroup/SPIRV-Tools/issues/1664 // From GLSL vertex shader: @@ -2007,6 +2460,797 @@ TEST_F(ValidateDecorations, "rules: member 1 at offset 4 is not aligned to 16")); } +TEST_F(ValidateDecorations, PushConstantMissingBlockGood) { + std::string spirv = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "main" + OpExecutionMode %1 OriginUpperLeft + + OpMemberDecorate %struct 0 Offset 0 + + %void = OpTypeVoid + %voidfn = OpTypeFunction %void + %float = OpTypeFloat 32 + %struct = OpTypeStruct %float + %ptr = OpTypePointer PushConstant %struct + %pc = OpVariable %ptr PushConstant + + %1 = OpFunction %void None %voidfn + %label = OpLabel + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState()) + << getDiagnosticString(); +} + +TEST_F(ValidateDecorations, VulkanPushConstantMissingBlockBad) { + std::string spirv = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "main" + OpExecutionMode %1 OriginUpperLeft + + OpMemberDecorate %struct 0 Offset 0 + + %void = OpTypeVoid + %voidfn = OpTypeFunction %void + %float = OpTypeFloat 32 + %struct = OpTypeStruct %float + %ptr = OpTypePointer PushConstant %struct + %pc = OpVariable %ptr PushConstant + + %1 = OpFunction %void None %voidfn + %label = OpLabel + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_ID, + ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("PushConstant id '2' is missing Block decoration.\n" + "From Vulkan spec, section 14.5.1:\n" + "Such variables must be identified with a Block " + "decoration")); +} + +TEST_F(ValidateDecorations, MultiplePushConstantsSingleEntryPointGood) { + std::string spirv = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "main" + OpExecutionMode %1 OriginUpperLeft + + OpDecorate %struct Block + OpMemberDecorate %struct 0 Offset 0 + + %void = OpTypeVoid + %voidfn = OpTypeFunction %void + %float = OpTypeFloat 32 + %int = OpTypeInt 32 0 + %int_0 = OpConstant %int 0 + %struct = OpTypeStruct %float + %ptr = OpTypePointer PushConstant %struct + %ptr_float = OpTypePointer PushConstant %float + %pc1 = OpVariable %ptr PushConstant + %pc2 = OpVariable %ptr PushConstant + + %1 = OpFunction %void None %voidfn + %label = OpLabel + %2 = OpAccessChain %ptr_float %pc1 %int_0 + %3 = OpLoad %float %2 + %4 = OpAccessChain %ptr_float %pc2 %int_0 + %5 = OpLoad %float %4 + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState()) + << getDiagnosticString(); +} + +TEST_F(ValidateDecorations, + VulkanMultiplePushConstantsDifferentEntryPointGood) { + std::string spirv = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %1 "func1" + OpEntryPoint Fragment %2 "func2" + OpExecutionMode %2 OriginUpperLeft + + OpDecorate %struct Block + OpMemberDecorate %struct 0 Offset 0 + + %void = OpTypeVoid + %voidfn = OpTypeFunction %void + %float = OpTypeFloat 32 + %int = OpTypeInt 32 0 + %int_0 = OpConstant %int 0 + %struct = OpTypeStruct %float + %ptr = OpTypePointer PushConstant %struct + %ptr_float = OpTypePointer PushConstant %float + %pc1 = OpVariable %ptr PushConstant + %pc2 = OpVariable %ptr PushConstant + + %1 = OpFunction %void None %voidfn + %label1 = OpLabel + %3 = OpAccessChain %ptr_float %pc1 %int_0 + %4 = OpLoad %float %3 + OpReturn + OpFunctionEnd + + %2 = OpFunction %void None %voidfn + %label2 = OpLabel + %5 = OpAccessChain %ptr_float %pc2 %int_0 + %6 = OpLoad %float %5 + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1)) + << getDiagnosticString(); +} + +TEST_F(ValidateDecorations, + VulkanMultiplePushConstantsUnusedSingleEntryPointGood) { + std::string spirv = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "main" + OpExecutionMode %1 OriginUpperLeft + + OpDecorate %struct Block + OpMemberDecorate %struct 0 Offset 0 + + %void = OpTypeVoid + %voidfn = OpTypeFunction %void + %float = OpTypeFloat 32 + %int = OpTypeInt 32 0 + %int_0 = OpConstant %int 0 + %struct = OpTypeStruct %float + %ptr = OpTypePointer PushConstant %struct + %ptr_float = OpTypePointer PushConstant %float + %pc1 = OpVariable %ptr PushConstant + %pc2 = OpVariable %ptr PushConstant + + %1 = OpFunction %void None %voidfn + %label = OpLabel + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1)) + << getDiagnosticString(); +} + +TEST_F(ValidateDecorations, VulkanMultiplePushConstantsSingleEntryPointBad) { + std::string spirv = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "main" + OpExecutionMode %1 OriginUpperLeft + + OpDecorate %struct Block + OpMemberDecorate %struct 0 Offset 0 + + %void = OpTypeVoid + %voidfn = OpTypeFunction %void + %float = OpTypeFloat 32 + %int = OpTypeInt 32 0 + %int_0 = OpConstant %int 0 + %struct = OpTypeStruct %float + %ptr = OpTypePointer PushConstant %struct + %ptr_float = OpTypePointer PushConstant %float + %pc1 = OpVariable %ptr PushConstant + %pc2 = OpVariable %ptr PushConstant + + %1 = OpFunction %void None %voidfn + %label = OpLabel + %2 = OpAccessChain %ptr_float %pc1 %int_0 + %3 = OpLoad %float %2 + %4 = OpAccessChain %ptr_float %pc2 %int_0 + %5 = OpLoad %float %4 + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_ID, + ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "Entry point id '1' uses more than one PushConstant interface.\n" + "From Vulkan spec, section 14.5.1:\n" + "There must be no more than one push constant block " + "statically used per shader entry point.")); +} + +TEST_F(ValidateDecorations, + VulkanMultiplePushConstantsDifferentEntryPointSubFunctionGood) { + std::string spirv = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %1 "func1" + OpEntryPoint Fragment %2 "func2" + OpExecutionMode %2 OriginUpperLeft + + OpDecorate %struct Block + OpMemberDecorate %struct 0 Offset 0 + + %void = OpTypeVoid + %voidfn = OpTypeFunction %void + %float = OpTypeFloat 32 + %int = OpTypeInt 32 0 + %int_0 = OpConstant %int 0 + %struct = OpTypeStruct %float + %ptr = OpTypePointer PushConstant %struct + %ptr_float = OpTypePointer PushConstant %float + %pc1 = OpVariable %ptr PushConstant + %pc2 = OpVariable %ptr PushConstant + + %sub1 = OpFunction %void None %voidfn + %label_sub1 = OpLabel + %3 = OpAccessChain %ptr_float %pc1 %int_0 + %4 = OpLoad %float %3 + OpReturn + OpFunctionEnd + + %sub2 = OpFunction %void None %voidfn + %label_sub2 = OpLabel + %5 = OpAccessChain %ptr_float %pc2 %int_0 + %6 = OpLoad %float %5 + OpReturn + OpFunctionEnd + + %1 = OpFunction %void None %voidfn + %label1 = OpLabel + %call1 = OpFunctionCall %void %sub1 + OpReturn + OpFunctionEnd + + %2 = OpFunction %void None %voidfn + %label2 = OpLabel + %call2 = OpFunctionCall %void %sub2 + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1)) + << getDiagnosticString(); +} + +TEST_F(ValidateDecorations, + VulkanMultiplePushConstantsSingleEntryPointSubFunctionBad) { + std::string spirv = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "main" + OpExecutionMode %1 OriginUpperLeft + + OpDecorate %struct Block + OpMemberDecorate %struct 0 Offset 0 + + %void = OpTypeVoid + %voidfn = OpTypeFunction %void + %float = OpTypeFloat 32 + %int = OpTypeInt 32 0 + %int_0 = OpConstant %int 0 + %struct = OpTypeStruct %float + %ptr = OpTypePointer PushConstant %struct + %ptr_float = OpTypePointer PushConstant %float + %pc1 = OpVariable %ptr PushConstant + %pc2 = OpVariable %ptr PushConstant + + %sub1 = OpFunction %void None %voidfn + %label_sub1 = OpLabel + %3 = OpAccessChain %ptr_float %pc1 %int_0 + %4 = OpLoad %float %3 + OpReturn + OpFunctionEnd + + %sub2 = OpFunction %void None %voidfn + %label_sub2 = OpLabel + %5 = OpAccessChain %ptr_float %pc2 %int_0 + %6 = OpLoad %float %5 + OpReturn + OpFunctionEnd + + %1 = OpFunction %void None %voidfn + %label1 = OpLabel + %call1 = OpFunctionCall %void %sub1 + %call2 = OpFunctionCall %void %sub2 + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_ID, + ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "Entry point id '1' uses more than one PushConstant interface.\n" + "From Vulkan spec, section 14.5.1:\n" + "There must be no more than one push constant block " + "statically used per shader entry point.")); +} + +TEST_F(ValidateDecorations, VulkanUniformMissingDescriptorSetBad) { + std::string spirv = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "main" + OpExecutionMode %1 OriginUpperLeft + + OpDecorate %struct Block + OpMemberDecorate %struct 0 Offset 0 + OpDecorate %var Binding 0 + + %void = OpTypeVoid + %voidfn = OpTypeFunction %void + %float = OpTypeFloat 32 + %struct = OpTypeStruct %float + %ptr = OpTypePointer Uniform %struct +%ptr_float = OpTypePointer Uniform %float + %var = OpVariable %ptr Uniform + %int = OpTypeInt 32 0 + %int_0 = OpConstant %int 0 + + %1 = OpFunction %void None %voidfn + %label = OpLabel + %2 = OpAccessChain %ptr_float %var %int_0 + %3 = OpLoad %float %2 + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_ID, + ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Uniform id '3' is missing DescriptorSet decoration.\n" + "From Vulkan spec, section 14.5.2:\n" + "These variables must have DescriptorSet and Binding " + "decorations specified")); +} + +TEST_F(ValidateDecorations, VulkanUniformMissingBindingBad) { + std::string spirv = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "main" + OpExecutionMode %1 OriginUpperLeft + + OpDecorate %struct Block + OpMemberDecorate %struct 0 Offset 0 + OpDecorate %var DescriptorSet 0 + + %void = OpTypeVoid + %voidfn = OpTypeFunction %void + %float = OpTypeFloat 32 + %struct = OpTypeStruct %float + %ptr = OpTypePointer Uniform %struct +%ptr_float = OpTypePointer Uniform %float + %var = OpVariable %ptr Uniform + %int = OpTypeInt 32 0 + %int_0 = OpConstant %int 0 + + %1 = OpFunction %void None %voidfn + %label = OpLabel + %2 = OpAccessChain %ptr_float %var %int_0 + %3 = OpLoad %float %2 + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_ID, + ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Uniform id '3' is missing Binding decoration.\n" + "From Vulkan spec, section 14.5.2:\n" + "These variables must have DescriptorSet and Binding " + "decorations specified")); +} + +TEST_F(ValidateDecorations, VulkanUniformConstantMissingDescriptorSetBad) { + std::string spirv = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "main" + OpExecutionMode %1 OriginUpperLeft + + OpDecorate %var Binding 0 + + %void = OpTypeVoid + %voidfn = OpTypeFunction %void + %sampler = OpTypeSampler + %ptr = OpTypePointer UniformConstant %sampler + %var = OpVariable %ptr UniformConstant + + %1 = OpFunction %void None %voidfn + %label = OpLabel + %2 = OpLoad %sampler %var + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_ID, + ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("UniformConstant id '2' is missing DescriptorSet decoration.\n" + "From Vulkan spec, section 14.5.2:\n" + "These variables must have DescriptorSet and Binding " + "decorations specified")); +} + +TEST_F(ValidateDecorations, VulkanUniformConstantMissingBindingBad) { + std::string spirv = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "main" + OpExecutionMode %1 OriginUpperLeft + + OpDecorate %var DescriptorSet 0 + + %void = OpTypeVoid + %voidfn = OpTypeFunction %void + %sampler = OpTypeSampler + %ptr = OpTypePointer UniformConstant %sampler + %var = OpVariable %ptr UniformConstant + + %1 = OpFunction %void None %voidfn + %label = OpLabel + %2 = OpLoad %sampler %var + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_ID, + ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("UniformConstant id '2' is missing Binding decoration.\n" + "From Vulkan spec, section 14.5.2:\n" + "These variables must have DescriptorSet and Binding " + "decorations specified")); +} + +TEST_F(ValidateDecorations, VulkanStorageBufferMissingDescriptorSetBad) { + std::string spirv = R"( + OpCapability Shader + OpExtension "SPV_KHR_storage_buffer_storage_class" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "main" + OpExecutionMode %1 OriginUpperLeft + + OpDecorate %struct Block + OpDecorate %var Binding 0 + + %void = OpTypeVoid + %voidfn = OpTypeFunction %void + %float = OpTypeFloat 32 + %struct = OpTypeStruct %float + %ptr = OpTypePointer StorageBuffer %struct + %var = OpVariable %ptr StorageBuffer +%ptr_float = OpTypePointer StorageBuffer %float + %int = OpTypeInt 32 0 + %int_0 = OpConstant %int 0 + + %1 = OpFunction %void None %voidfn + %label = OpLabel + %2 = OpAccessChain %ptr_float %var %int_0 + %3 = OpLoad %float %2 + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_ID, + ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("StorageBuffer id '3' is missing DescriptorSet decoration.\n" + "From Vulkan spec, section 14.5.2:\n" + "These variables must have DescriptorSet and Binding " + "decorations specified")); +} + +TEST_F(ValidateDecorations, VulkanStorageBufferMissingBindingBad) { + std::string spirv = R"( + OpCapability Shader + OpExtension "SPV_KHR_storage_buffer_storage_class" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "main" + OpExecutionMode %1 OriginUpperLeft + + OpDecorate %struct Block + OpDecorate %var DescriptorSet 0 + + %void = OpTypeVoid + %voidfn = OpTypeFunction %void + %float = OpTypeFloat 32 + %struct = OpTypeStruct %float + %ptr = OpTypePointer StorageBuffer %struct + %var = OpVariable %ptr StorageBuffer +%ptr_float = OpTypePointer StorageBuffer %float + %int = OpTypeInt 32 0 + %int_0 = OpConstant %int 0 + + %1 = OpFunction %void None %voidfn + %label = OpLabel + %2 = OpAccessChain %ptr_float %var %int_0 + %3 = OpLoad %float %2 + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_ID, + ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("StorageBuffer id '3' is missing Binding decoration.\n" + "From Vulkan spec, section 14.5.2:\n" + "These variables must have DescriptorSet and Binding " + "decorations specified")); +} + +TEST_F(ValidateDecorations, + VulkanStorageBufferMissingDescriptorSetSubFunctionBad) { + std::string spirv = R"( + OpCapability Shader + OpExtension "SPV_KHR_storage_buffer_storage_class" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "main" + OpExecutionMode %1 OriginUpperLeft + + OpDecorate %struct Block + OpDecorate %var Binding 0 + + %void = OpTypeVoid + %voidfn = OpTypeFunction %void + %float = OpTypeFloat 32 + %struct = OpTypeStruct %float + %ptr = OpTypePointer StorageBuffer %struct + %var = OpVariable %ptr StorageBuffer +%ptr_float = OpTypePointer StorageBuffer %float + %int = OpTypeInt 32 0 + %int_0 = OpConstant %int 0 + + %1 = OpFunction %void None %voidfn + %label = OpLabel + %call = OpFunctionCall %void %2 + OpReturn + OpFunctionEnd + %2 = OpFunction %void None %voidfn + %label2 = OpLabel + %3 = OpAccessChain %ptr_float %var %int_0 + %4 = OpLoad %float %3 + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_ID, + ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("StorageBuffer id '3' is missing DescriptorSet decoration.\n" + "From Vulkan spec, section 14.5.2:\n" + "These variables must have DescriptorSet and Binding " + "decorations specified")); +} + +TEST_F(ValidateDecorations, + VulkanStorageBufferMissingDescriptorAndBindingUnusedGood) { + std::string spirv = R"( + OpCapability Shader + OpExtension "SPV_KHR_storage_buffer_storage_class" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "main" + OpExecutionMode %1 OriginUpperLeft + OpDecorate %struct Block + OpMemberDecorate %struct 0 Offset 0 + + %void = OpTypeVoid + %voidfn = OpTypeFunction %void + %float = OpTypeFloat 32 + %struct = OpTypeStruct %float + %ptr = OpTypePointer StorageBuffer %struct + %var = OpVariable %ptr StorageBuffer + + %1 = OpFunction %void None %voidfn + %label = OpLabel + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_SUCCESS, + ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1)); +} + +TEST_F(ValidateDecorations, UniformMissingDescriptorSetGood) { + std::string spirv = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "main" + OpExecutionMode %1 OriginUpperLeft + + OpDecorate %struct Block + OpMemberDecorate %struct 0 Offset 0 + OpDecorate %var Binding 0 + + %void = OpTypeVoid + %voidfn = OpTypeFunction %void + %float = OpTypeFloat 32 + %struct = OpTypeStruct %float + %ptr = OpTypePointer Uniform %struct + %var = OpVariable %ptr Uniform + + %1 = OpFunction %void None %voidfn + %label = OpLabel + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState()) + << getDiagnosticString(); +} + +TEST_F(ValidateDecorations, UniformMissingBindingGood) { + std::string spirv = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "main" + OpExecutionMode %1 OriginUpperLeft + + OpDecorate %struct Block + OpMemberDecorate %struct 0 Offset 0 + OpDecorate %var DescriptorSet 0 + + %void = OpTypeVoid + %voidfn = OpTypeFunction %void + %float = OpTypeFloat 32 + %struct = OpTypeStruct %float + %ptr = OpTypePointer Uniform %struct + %var = OpVariable %ptr Uniform + + %1 = OpFunction %void None %voidfn + %label = OpLabel + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState()) + << getDiagnosticString(); +} + +TEST_F(ValidateDecorations, UniformConstantMissingDescriptorSetGood) { + std::string spirv = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "main" + OpExecutionMode %1 OriginUpperLeft + + OpDecorate %var Binding 0 + + %void = OpTypeVoid + %voidfn = OpTypeFunction %void + %sampler = OpTypeSampler + %ptr = OpTypePointer UniformConstant %sampler + %var = OpVariable %ptr UniformConstant + + %1 = OpFunction %void None %voidfn + %label = OpLabel + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState()) + << getDiagnosticString(); +} + +TEST_F(ValidateDecorations, UniformConstantMissingBindingGood) { + std::string spirv = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "main" + OpExecutionMode %1 OriginUpperLeft + + OpDecorate %var DescriptorSet 0 + + %void = OpTypeVoid + %voidfn = OpTypeFunction %void + %sampler = OpTypeSampler + %ptr = OpTypePointer UniformConstant %sampler + %var = OpVariable %ptr UniformConstant + + %1 = OpFunction %void None %voidfn + %label = OpLabel + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState()) + << getDiagnosticString(); +} + +TEST_F(ValidateDecorations, StorageBufferMissingDescriptorSetGood) { + std::string spirv = R"( + OpCapability Shader + OpExtension "SPV_KHR_storage_buffer_storage_class" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "main" + OpExecutionMode %1 OriginUpperLeft + + OpDecorate %struct BufferBlock + OpDecorate %var Binding 0 + + %void = OpTypeVoid + %voidfn = OpTypeFunction %void + %float = OpTypeFloat 32 + %struct = OpTypeStruct %float + %ptr = OpTypePointer StorageBuffer %struct + %var = OpVariable %ptr StorageBuffer + + %1 = OpFunction %void None %voidfn + %label = OpLabel + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState()) + << getDiagnosticString(); +} + +TEST_F(ValidateDecorations, StorageBufferMissingBindingGood) { + std::string spirv = R"( + OpCapability Shader + OpExtension "SPV_KHR_storage_buffer_storage_class" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "main" + OpExecutionMode %1 OriginUpperLeft + + OpDecorate %struct BufferBlock + OpDecorate %var DescriptorSet 0 + + %void = OpTypeVoid + %voidfn = OpTypeFunction %void + %float = OpTypeFloat 32 + %struct = OpTypeStruct %float + %ptr = OpTypePointer StorageBuffer %struct + %var = OpVariable %ptr StorageBuffer + + %1 = OpFunction %void None %voidfn + %label = OpLabel + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState()) + << getDiagnosticString(); +} + TEST_F(ValidateDecorations, StorageBufferStorageClassArrayBaseAlignmentGood) { // Spot check buffer rules when using StorageBuffer storage class with Block // decoration. @@ -2277,7 +3521,7 @@ TEST_F(ValidateDecorations, getDiagnosticString(), HasSubstr("Structure id 6 decorated as Block for variable in Uniform " "storage class must follow standard uniform buffer layout " - "rules: member 2 at offset 24 is not aligned to 16")); + "rules: member 2 at offset 152 is not aligned to 16")); } TEST_F(ValidateDecorations, @@ -2410,7 +3654,8 @@ TEST_F(ValidateDecorations, BlockUniformBufferLayoutIncorrectArrayStrideBad) { getDiagnosticString(), HasSubstr( "Structure id 6 decorated as Block for variable in Uniform storage " - "class must follow standard uniform buffer layout rules: member 4 is " + "class must follow standard uniform buffer layout rules: member 4 " + "contains " "an array with stride 49 not satisfying alignment to 16")); } @@ -2522,7 +3767,7 @@ TEST_F(ValidateDecorations, "offset 4 overlaps previous member ending at offset 15")); } -TEST_F(ValidateDecorations, BlockLayoutOffsetOutOfOrderBadUniversal1_0) { +TEST_F(ValidateDecorations, BlockLayoutOffsetOutOfOrderGoodUniversal1_0) { std::string spirv = R"( OpCapability Shader %1 = OpExtInstImport "GLSL.std.450" @@ -2547,17 +3792,11 @@ TEST_F(ValidateDecorations, BlockLayoutOffsetOutOfOrderBadUniversal1_0) { )"; CompileSuccessfully(spirv); - EXPECT_EQ(SPV_ERROR_INVALID_ID, + EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(SPV_ENV_UNIVERSAL_1_0)); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr( - "Structure id 3 decorated as Block for variable in Uniform storage " - "class must follow standard uniform buffer layout rules: member 0 at " - "offset 4 has a higher offset than member 1 at offset 0")); } -TEST_F(ValidateDecorations, BlockLayoutOffsetOutOfOrderBadOpenGL4_5) { +TEST_F(ValidateDecorations, BlockLayoutOffsetOutOfOrderGoodOpenGL4_5) { std::string spirv = R"( OpCapability Shader %1 = OpExtInstImport "GLSL.std.450" @@ -2582,14 +3821,8 @@ TEST_F(ValidateDecorations, BlockLayoutOffsetOutOfOrderBadOpenGL4_5) { )"; CompileSuccessfully(spirv); - EXPECT_EQ(SPV_ERROR_INVALID_ID, + EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(SPV_ENV_OPENGL_4_5)); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr( - "Structure id 3 decorated as Block for variable in Uniform storage " - "class must follow standard uniform buffer layout rules: member 0 at " - "offset 4 has a higher offset than member 1 at offset 0")); } TEST_F(ValidateDecorations, BlockLayoutOffsetOutOfOrderGoodVulkan1_1) { @@ -3026,6 +4259,7 @@ TEST_F(ValidateDecorations, EntryPointVariableWrongStorageClass) { OpCapability Shader OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %1 "func" %var +OpExecutionMode %1 OriginUpperLeft %void = OpTypeVoid %int = OpTypeInt 32 0 %ptr_int_Workgroup = OpTypePointer Workgroup %int @@ -3044,6 +4278,2723 @@ OpFunctionEnd "Storage Class of Input(1) or Output(3). Found Storage " "Class 4 for Entry Point id 1.")); } + +TEST_F(ValidateDecorations, VulkanMemoryModelNonCoherent) { + const std::string spirv = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpCapability Linkage +OpExtension "SPV_KHR_vulkan_memory_model" +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpMemoryModel Logical VulkanKHR +OpDecorate %1 Coherent +%2 = OpTypeInt 32 0 +%3 = OpTypePointer StorageBuffer %2 +%1 = OpVariable %3 StorageBuffer +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Coherent decoration targeting 1[%1] is " + "banned when using the Vulkan memory model.")); +} + +TEST_F(ValidateDecorations, VulkanMemoryModelNoCoherentMember) { + const std::string spirv = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpCapability Linkage +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +OpMemberDecorate %1 0 Coherent +%2 = OpTypeInt 32 0 +%1 = OpTypeStruct %2 %2 +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Coherent decoration targeting 1[%_struct_1] (member index 0) " + "is banned when using the Vulkan memory model.")); +} + +TEST_F(ValidateDecorations, VulkanMemoryModelNoVolatile) { + const std::string spirv = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpCapability Linkage +OpExtension "SPV_KHR_vulkan_memory_model" +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpMemoryModel Logical VulkanKHR +OpDecorate %1 Volatile +%2 = OpTypeInt 32 0 +%3 = OpTypePointer StorageBuffer %2 +%1 = OpVariable %3 StorageBuffer +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Volatile decoration targeting 1[%1] is banned when " + "using the Vulkan memory model.")); +} + +TEST_F(ValidateDecorations, VulkanMemoryModelNoVolatileMember) { + const std::string spirv = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpCapability Linkage +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +OpMemberDecorate %1 1 Volatile +%2 = OpTypeInt 32 0 +%1 = OpTypeStruct %2 %2 +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Volatile decoration targeting 1[%_struct_1] (member " + "index 1) is banned when using the Vulkan memory " + "model.")); +} + +TEST_F(ValidateDecorations, FPRoundingModeGood) { + std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability StorageBuffer16BitAccess +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpExtension "SPV_KHR_variable_pointers" +OpExtension "SPV_KHR_16bit_storage" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpDecorate %_ FPRoundingMode RTE +%half = OpTypeFloat 16 +%float = OpTypeFloat 32 +%float_1_25 = OpConstant %float 1.25 +%half_ptr = OpTypePointer StorageBuffer %half +%half_ptr_var = OpVariable %half_ptr StorageBuffer +%void = OpTypeVoid +%func = OpTypeFunction %void +%main = OpFunction %void None %func +%main_entry = OpLabel +%_ = OpFConvert %half %float_1_25 +OpStore %half_ptr_var %_ +OpReturn +OpFunctionEnd + )"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState()); +} + +TEST_F(ValidateDecorations, FPRoundingModeVectorGood) { + std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability StorageBuffer16BitAccess +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpExtension "SPV_KHR_variable_pointers" +OpExtension "SPV_KHR_16bit_storage" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpDecorate %_ FPRoundingMode RTE +%half = OpTypeFloat 16 +%float = OpTypeFloat 32 +%v2half = OpTypeVector %half 2 +%v2float = OpTypeVector %float 2 +%float_1_25 = OpConstant %float 1.25 +%floats = OpConstantComposite %v2float %float_1_25 %float_1_25 +%halfs_ptr = OpTypePointer StorageBuffer %v2half +%halfs_ptr_var = OpVariable %halfs_ptr StorageBuffer +%void = OpTypeVoid +%func = OpTypeFunction %void +%main = OpFunction %void None %func +%main_entry = OpLabel +%_ = OpFConvert %v2half %floats +OpStore %halfs_ptr_var %_ +OpReturn +OpFunctionEnd + )"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState()); +} + +TEST_F(ValidateDecorations, FPRoundingModeNotOpFConvert) { + std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability StorageBuffer16BitAccess +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpExtension "SPV_KHR_variable_pointers" +OpExtension "SPV_KHR_16bit_storage" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpDecorate %_ FPRoundingMode RTE +%short = OpTypeInt 16 1 +%int = OpTypeInt 32 1 +%int_17 = OpConstant %int 17 +%short_ptr = OpTypePointer StorageBuffer %short +%short_ptr_var = OpVariable %short_ptr StorageBuffer +%void = OpTypeVoid +%func = OpTypeFunction %void +%main = OpFunction %void None %func +%main_entry = OpLabel +%_ = OpSConvert %short %int_17 +OpStore %short_ptr_var %_ +OpReturn +OpFunctionEnd + )"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("FPRoundingMode decoration can be applied only to a " + "width-only conversion instruction for floating-point " + "object.")); +} + +TEST_F(ValidateDecorations, FPRoundingModeNoOpStoreGood) { + std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability StorageBuffer16BitAccess +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpExtension "SPV_KHR_variable_pointers" +OpExtension "SPV_KHR_16bit_storage" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpDecorate %_ FPRoundingMode RTE +%half = OpTypeFloat 16 +%float = OpTypeFloat 32 +%float_1_25 = OpConstant %float 1.25 +%half_ptr = OpTypePointer StorageBuffer %half +%half_ptr_var = OpVariable %half_ptr StorageBuffer +%void = OpTypeVoid +%func = OpTypeFunction %void +%main = OpFunction %void None %func +%main_entry = OpLabel +%_ = OpFConvert %half %float_1_25 +OpReturn +OpFunctionEnd + )"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState()); +} + +TEST_F(ValidateDecorations, FPRoundingModeFConvert64to16Good) { + std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability StorageBuffer16BitAccess +OpCapability Float64 +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpExtension "SPV_KHR_variable_pointers" +OpExtension "SPV_KHR_16bit_storage" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpDecorate %_ FPRoundingMode RTE +%half = OpTypeFloat 16 +%double = OpTypeFloat 64 +%double_1_25 = OpConstant %double 1.25 +%half_ptr = OpTypePointer StorageBuffer %half +%half_ptr_var = OpVariable %half_ptr StorageBuffer +%void = OpTypeVoid +%func = OpTypeFunction %void +%main = OpFunction %void None %func +%main_entry = OpLabel +%_ = OpFConvert %half %double_1_25 +OpStore %half_ptr_var %_ +OpReturn +OpFunctionEnd + )"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState()); +} + +TEST_F(ValidateDecorations, FPRoundingModeNotStoreInFloat16) { + std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability StorageBuffer16BitAccess +OpCapability Float64 +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpExtension "SPV_KHR_variable_pointers" +OpExtension "SPV_KHR_16bit_storage" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpDecorate %_ FPRoundingMode RTE +%float = OpTypeFloat 32 +%double = OpTypeFloat 64 +%double_1_25 = OpConstant %double 1.25 +%float_ptr = OpTypePointer StorageBuffer %float +%float_ptr_var = OpVariable %float_ptr StorageBuffer +%void = OpTypeVoid +%func = OpTypeFunction %void +%main = OpFunction %void None %func +%main_entry = OpLabel +%_ = OpFConvert %float %double_1_25 +OpStore %float_ptr_var %_ +OpReturn +OpFunctionEnd + )"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("FPRoundingMode decoration can be applied only to the " + "Object operand of an OpStore storing through a " + "pointer to a 16-bit floating-point scalar or vector object.")); +} + +TEST_F(ValidateDecorations, FPRoundingModeMultipleOpStoreGood) { + std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability StorageBuffer16BitAccess +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpExtension "SPV_KHR_variable_pointers" +OpExtension "SPV_KHR_16bit_storage" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpDecorate %_ FPRoundingMode RTE +%half = OpTypeFloat 16 +%float = OpTypeFloat 32 +%float_1_25 = OpConstant %float 1.25 +%half_ptr = OpTypePointer StorageBuffer %half +%half_ptr_var_0 = OpVariable %half_ptr StorageBuffer +%half_ptr_var_1 = OpVariable %half_ptr StorageBuffer +%half_ptr_var_2 = OpVariable %half_ptr StorageBuffer +%void = OpTypeVoid +%func = OpTypeFunction %void +%main = OpFunction %void None %func +%main_entry = OpLabel +%_ = OpFConvert %half %float_1_25 +OpStore %half_ptr_var_0 %_ +OpStore %half_ptr_var_1 %_ +OpStore %half_ptr_var_2 %_ +OpReturn +OpFunctionEnd + )"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState()); +} + +TEST_F(ValidateDecorations, FPRoundingModeMultipleUsesBad) { + std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability StorageBuffer16BitAccess +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpExtension "SPV_KHR_variable_pointers" +OpExtension "SPV_KHR_16bit_storage" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpDecorate %_ FPRoundingMode RTE +%half = OpTypeFloat 16 +%float = OpTypeFloat 32 +%float_1_25 = OpConstant %float 1.25 +%half_ptr = OpTypePointer StorageBuffer %half +%half_ptr_var_0 = OpVariable %half_ptr StorageBuffer +%half_ptr_var_1 = OpVariable %half_ptr StorageBuffer +%void = OpTypeVoid +%func = OpTypeFunction %void +%main = OpFunction %void None %func +%main_entry = OpLabel +%_ = OpFConvert %half %float_1_25 +OpStore %half_ptr_var_0 %_ +%result = OpFAdd %half %_ %_ +OpStore %half_ptr_var_1 %_ +OpReturn +OpFunctionEnd + )"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("FPRoundingMode decoration can be applied only to the " + "Object operand of an OpStore.")); +} + +TEST_F(ValidateDecorations, GroupDecorateTargetsDecorationGroup) { + std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%1 = OpDecorationGroup +OpGroupDecorate %1 %1 +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("OpGroupDecorate may not target OpDecorationGroup " + "'1[%1]'")); +} + +TEST_F(ValidateDecorations, GroupDecorateTargetsDecorationGroup2) { + std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%1 = OpDecorationGroup +OpGroupDecorate %1 %2 %1 +%2 = OpTypeVoid +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("OpGroupDecorate may not target OpDecorationGroup " + "'1[%1]'")); +} + +TEST_F(ValidateDecorations, RecurseThroughRuntimeArray) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpDecorate %outer Block +OpMemberDecorate %inner 0 Offset 0 +OpMemberDecorate %inner 1 Offset 1 +OpDecorate %runtime ArrayStride 16 +OpMemberDecorate %outer 0 Offset 0 +%int = OpTypeInt 32 0 +%inner = OpTypeStruct %int %int +%runtime = OpTypeRuntimeArray %inner +%outer = OpTypeStruct %runtime +%outer_ptr = OpTypePointer Uniform %outer +%var = OpVariable %outer_ptr Uniform +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Structure id 2 decorated as Block for variable in Uniform " + "storage class must follow standard uniform buffer layout " + "rules: member 1 at offset 1 is not aligned to 4")); +} + +TEST_F(ValidateDecorations, EmptyStructAtNonZeroOffsetGood) { + const std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %struct Block +OpMemberDecorate %struct 0 Offset 0 +OpMemberDecorate %struct 1 Offset 16 +OpDecorate %var DescriptorSet 0 +OpDecorate %var Binding 0 +%void = OpTypeVoid +%float = OpTypeFloat 32 +%empty = OpTypeStruct +%struct = OpTypeStruct %float %empty +%ptr_struct_ubo = OpTypePointer Uniform %struct +%var = OpVariable %ptr_struct_ubo Uniform +%voidfn = OpTypeFunction %void +%main = OpFunction %void None %voidfn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +// Uniform and UniformId decorations + +TEST_F(ValidateDecorations, UniformDecorationGood) { + const std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical Simple +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %int0 Uniform +OpDecorate %var Uniform +OpDecorate %val Uniform +%void = OpTypeVoid +%int = OpTypeInt 32 1 +%int0 = OpConstantNull %int +%intptr = OpTypePointer Private %int +%var = OpVariable %intptr Private +%fn = OpTypeFunction %void +%main = OpFunction %void None %fn +%entry = OpLabel +%val = OpLoad %int %var +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +// Returns SPIR-V assembly for a shader that uses a given decoration +// instruction. +std::string ShaderWithUniformLikeDecoration(const std::string& inst) { + return std::string(R"( +OpCapability Shader +OpMemoryModel Logical Simple +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpName %subgroupscope "subgroupscope" +OpName %call "call" +OpName %myfunc "myfunc" +OpName %int0 "int0" +OpName %float0 "float0" +OpName %fn "fn" +)") + inst + + R"( +%void = OpTypeVoid +%float = OpTypeFloat 32 +%int = OpTypeInt 32 1 +%int0 = OpConstantNull %int +%int_99 = OpConstant %int 99 +%subgroupscope = OpConstant %int 3 +%float0 = OpConstantNull %float +%fn = OpTypeFunction %void +%myfunc = OpFunction %void None %fn +%myfuncentry = OpLabel +OpReturn +OpFunctionEnd +%main = OpFunction %void None %fn +%entry = OpLabel +%call = OpFunctionCall %void %myfunc +OpReturn +OpFunctionEnd +)"; +} + +TEST_F(ValidateDecorations, UniformIdDecorationWithScopeIdV13Bad) { + const std::string spirv = ShaderWithUniformLikeDecoration( + "OpDecorateId %int0 UniformId %subgroupscope"); + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_WRONG_VERSION, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("requires SPIR-V version 1.4 or later\n" + " OpDecorateId %int0 UniformId %subgroupscope")) + << spirv; +} + +TEST_F(ValidateDecorations, UniformIdDecorationWithScopeIdV13BadTargetV14) { + const std::string spirv = ShaderWithUniformLikeDecoration( + "OpDecorateId %int0 UniformId %subgroupscope"); + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_WRONG_VERSION, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("requires SPIR-V version 1.4 or later")); +} + +TEST_F(ValidateDecorations, UniformIdDecorationWithScopeIdV14Good) { + const std::string spirv = ShaderWithUniformLikeDecoration( + "OpDecorateId %int0 UniformId %subgroupscope"); + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateDecorations, UniformDecorationTargetsTypeBad) { + const std::string spirv = + ShaderWithUniformLikeDecoration("OpDecorate %fn Uniform"); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Uniform decoration applied to a non-object")); + EXPECT_THAT(getDiagnosticString(), HasSubstr("%fn = OpTypeFunction %void")); +} + +TEST_F(ValidateDecorations, UniformIdDecorationTargetsTypeBad) { + const std::string spirv = ShaderWithUniformLikeDecoration( + "OpDecorateId %fn UniformId %subgroupscope"); + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("UniformId decoration applied to a non-object")); + EXPECT_THAT(getDiagnosticString(), HasSubstr("%fn = OpTypeFunction %void")); +} + +TEST_F(ValidateDecorations, UniformDecorationTargetsVoidValueBad) { + const std::string spirv = + ShaderWithUniformLikeDecoration("OpDecorate %call Uniform"); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Uniform decoration applied to a value with void type\n" + " %call = OpFunctionCall %void %myfunc")); +} + +TEST_F(ValidateDecorations, UniformIdDecorationTargetsVoidValueBad) { + const std::string spirv = ShaderWithUniformLikeDecoration( + "OpDecorateId %call UniformId %subgroupscope"); + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)) + << spirv; + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("UniformId decoration applied to a value with void type\n" + " %call = OpFunctionCall %void %myfunc")); +} + +TEST_F(ValidateDecorations, + UniformDecorationWithScopeIdV14IdIsFloatValueIsBad) { + const std::string spirv = + ShaderWithUniformLikeDecoration("OpDecorateId %int0 UniformId %float0"); + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("ConstantNull: expected scope to be a 32-bit int")); +} + +TEST_F(ValidateDecorations, + UniformDecorationWithScopeIdV14IdIsInvalidIntValueBad) { + const std::string spirv = + ShaderWithUniformLikeDecoration("OpDecorateId %int0 UniformId %int_99"); + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Invalid scope value:\n %int_99 = OpConstant %int 99\n")); +} + +TEST_F(ValidateDecorations, UniformDecorationWithScopeIdV14VulkanEnv) { + const std::string spirv = + ShaderWithUniformLikeDecoration("OpDecorateId %int0 UniformId %int0"); + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1_SPIRV_1_4); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_VULKAN_1_1_SPIRV_1_4)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr(": in Vulkan environment Execution Scope is limited to " + "Workgroup and Subgroup")); +} + +TEST_F(ValidateDecorations, UniformDecorationWithWrongInstructionBad) { + const std::string spirv = + ShaderWithUniformLikeDecoration("OpDecorateId %int0 Uniform"); + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_2); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_2)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Decorations that don't take ID parameters may not be " + "used with OpDecorateId\n" + " OpDecorateId %int0 Uniform")); +} + +TEST_F(ValidateDecorations, UniformIdDecorationWithWrongInstructionBad) { + const std::string spirv = ShaderWithUniformLikeDecoration( + "OpDecorate %int0 UniformId %subgroupscope"); + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "Decorations taking ID parameters may not be used with OpDecorateId\n" + " OpDecorate %int0 UniformId %subgroupscope")); +} + +TEST_F(ValidateDecorations, MultipleOffsetDecorationsOnSameID) { + std::string spirv = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "main" + OpExecutionMode %1 OriginUpperLeft + + OpMemberDecorate %struct 0 Offset 0 + OpMemberDecorate %struct 0 Offset 0 + + %void = OpTypeVoid + %voidfn = OpTypeFunction %void + %float = OpTypeFloat 32 + %struct = OpTypeStruct %float + + %1 = OpFunction %void None %voidfn + %label = OpLabel + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("ID '2', member '0' decorated with Offset multiple " + "times is not allowed.")); +} + +TEST_F(ValidateDecorations, MultipleArrayStrideDecorationsOnSameID) { + std::string spirv = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "main" + OpExecutionMode %1 OriginUpperLeft + + OpDecorate %array ArrayStride 4 + OpDecorate %array ArrayStride 4 + + %void = OpTypeVoid + %voidfn = OpTypeFunction %void + %float = OpTypeFloat 32 + %uint = OpTypeInt 32 0 + %uint_4 = OpConstant %uint 4 + %array = OpTypeArray %float %uint_4 + + %1 = OpFunction %void None %voidfn + %label = OpLabel + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("ID '2' decorated with ArrayStride multiple " + "times is not allowed.")); +} + +TEST_F(ValidateDecorations, MultipleMatrixStrideDecorationsOnSameID) { + std::string spirv = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "main" + OpExecutionMode %1 OriginUpperLeft + + OpMemberDecorate %struct 0 Offset 0 + OpMemberDecorate %struct 0 ColMajor + OpMemberDecorate %struct 0 MatrixStride 16 + OpMemberDecorate %struct 0 MatrixStride 16 + + %void = OpTypeVoid + %voidfn = OpTypeFunction %void + %float = OpTypeFloat 32 + %fvec4 = OpTypeVector %float 4 + %fmat4 = OpTypeMatrix %fvec4 4 + %struct = OpTypeStruct %fmat4 + + %1 = OpFunction %void None %voidfn + %label = OpLabel + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("ID '2', member '0' decorated with MatrixStride " + "multiple times is not allowed.")); +} + +TEST_F(ValidateDecorations, MultipleRowMajorDecorationsOnSameID) { + std::string spirv = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "main" + OpExecutionMode %1 OriginUpperLeft + + OpMemberDecorate %struct 0 Offset 0 + OpMemberDecorate %struct 0 MatrixStride 16 + OpMemberDecorate %struct 0 RowMajor + OpMemberDecorate %struct 0 RowMajor + + %void = OpTypeVoid + %voidfn = OpTypeFunction %void + %float = OpTypeFloat 32 + %fvec4 = OpTypeVector %float 4 + %fmat4 = OpTypeMatrix %fvec4 4 + %struct = OpTypeStruct %fmat4 + + %1 = OpFunction %void None %voidfn + %label = OpLabel + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("ID '2', member '0' decorated with RowMajor multiple " + "times is not allowed.")); +} + +TEST_F(ValidateDecorations, MultipleColMajorDecorationsOnSameID) { + std::string spirv = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "main" + OpExecutionMode %1 OriginUpperLeft + + OpMemberDecorate %struct 0 Offset 0 + OpMemberDecorate %struct 0 MatrixStride 16 + OpMemberDecorate %struct 0 ColMajor + OpMemberDecorate %struct 0 ColMajor + + %void = OpTypeVoid + %voidfn = OpTypeFunction %void + %float = OpTypeFloat 32 + %fvec4 = OpTypeVector %float 4 + %fmat4 = OpTypeMatrix %fvec4 4 + %struct = OpTypeStruct %fmat4 + + %1 = OpFunction %void None %voidfn + %label = OpLabel + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("ID '2', member '0' decorated with ColMajor multiple " + "times is not allowed.")); +} + +TEST_F(ValidateDecorations, RowMajorAndColMajorDecorationsOnSameID) { + std::string spirv = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "main" + OpExecutionMode %1 OriginUpperLeft + + OpMemberDecorate %struct 0 Offset 0 + OpMemberDecorate %struct 0 MatrixStride 16 + OpMemberDecorate %struct 0 ColMajor + OpMemberDecorate %struct 0 RowMajor + + %void = OpTypeVoid + %voidfn = OpTypeFunction %void + %float = OpTypeFloat 32 + %fvec4 = OpTypeVector %float 4 + %fmat4 = OpTypeMatrix %fvec4 4 + %struct = OpTypeStruct %fmat4 + + %1 = OpFunction %void None %voidfn + %label = OpLabel + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("ID '2', member '0' decorated with both RowMajor and " + "ColMajor is not allowed.")); +} + +TEST_F(ValidateDecorations, BlockAndBufferBlockDecorationsOnSameID) { + std::string spirv = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "main" + OpExecutionMode %1 OriginUpperLeft + + OpDecorate %struct Block + OpDecorate %struct BufferBlock + OpMemberDecorate %struct 0 Offset 0 + OpMemberDecorate %struct 0 MatrixStride 16 + OpMemberDecorate %struct 0 RowMajor + + %void = OpTypeVoid + %voidfn = OpTypeFunction %void + %float = OpTypeFloat 32 + %fvec4 = OpTypeVector %float 4 + %fmat4 = OpTypeMatrix %fvec4 4 + %struct = OpTypeStruct %fmat4 + + %1 = OpFunction %void None %voidfn + %label = OpLabel + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "ID '2' decorated with both BufferBlock and Block is not allowed.")); +} + +std::string MakeIntegerShader( + const std::string& decoration, const std::string& inst, + const std::string& extension = + "OpExtension \"SPV_KHR_no_integer_wrap_decoration\"") { + return R"( +OpCapability Shader +OpCapability Linkage +)" + extension + + R"( +%glsl = OpExtInstImport "GLSL.std.450" +%opencl = OpExtInstImport "OpenCL.std" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpName %entry "entry" +)" + decoration + + R"( + %void = OpTypeVoid + %voidfn = OpTypeFunction %void + %int = OpTypeInt 32 1 + %zero = OpConstantNull %int + %float = OpTypeFloat 32 + %float0 = OpConstantNull %float + %main = OpFunction %void None %voidfn + %entry = OpLabel +)" + inst + + R"( +OpReturn +OpFunctionEnd)"; +} + +// NoSignedWrap + +TEST_F(ValidateDecorations, NoSignedWrapOnTypeBad) { + std::string spirv = MakeIntegerShader("OpDecorate %void NoSignedWrap", ""); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("NoSignedWrap decoration may not be applied to TypeVoid")); +} + +TEST_F(ValidateDecorations, NoSignedWrapOnLabelBad) { + std::string spirv = MakeIntegerShader("OpDecorate %entry NoSignedWrap", ""); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("NoSignedWrap decoration may not be applied to Label")); +} + +TEST_F(ValidateDecorations, NoSignedWrapRequiresExtensionBad) { + std::string spirv = MakeIntegerShader("OpDecorate %val NoSignedWrap", + "%val = OpIAdd %int %zero %zero", ""); + + CompileSuccessfully(spirv); + EXPECT_NE(SPV_SUCCESS, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("requires one of these extensions: " + "SPV_KHR_no_integer_wrap_decoration")); +} + +TEST_F(ValidateDecorations, NoSignedWrapRequiresExtensionV13Bad) { + std::string spirv = MakeIntegerShader("OpDecorate %val NoSignedWrap", + "%val = OpIAdd %int %zero %zero", ""); + + CompileSuccessfully(spirv); + EXPECT_NE(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("requires one of these extensions: " + "SPV_KHR_no_integer_wrap_decoration")); +} + +TEST_F(ValidateDecorations, NoSignedWrapOkInSPV14Good) { + std::string spirv = MakeIntegerShader("OpDecorate %val NoSignedWrap", + "%val = OpIAdd %int %zero %zero", ""); + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateDecorations, NoSignedWrapIAddGood) { + std::string spirv = MakeIntegerShader("OpDecorate %val NoSignedWrap", + "%val = OpIAdd %int %zero %zero"); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateDecorations, NoSignedWrapISubGood) { + std::string spirv = MakeIntegerShader("OpDecorate %val NoSignedWrap", + "%val = OpISub %int %zero %zero"); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateDecorations, NoSignedWrapIMulGood) { + std::string spirv = MakeIntegerShader("OpDecorate %val NoSignedWrap", + "%val = OpIMul %int %zero %zero"); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateDecorations, NoSignedWrapShiftLeftLogicalGood) { + std::string spirv = + MakeIntegerShader("OpDecorate %val NoSignedWrap", + "%val = OpShiftLeftLogical %int %zero %zero"); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateDecorations, NoSignedWrapSNegateGood) { + std::string spirv = MakeIntegerShader("OpDecorate %val NoSignedWrap", + "%val = OpSNegate %int %zero"); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateDecorations, NoSignedWrapSRemBad) { + std::string spirv = MakeIntegerShader("OpDecorate %val NoSignedWrap", + "%val = OpSRem %int %zero %zero"); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("NoSignedWrap decoration may not be applied to SRem")); +} + +TEST_F(ValidateDecorations, NoSignedWrapFAddBad) { + std::string spirv = MakeIntegerShader("OpDecorate %val NoSignedWrap", + "%val = OpFAdd %float %float0 %float0"); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("NoSignedWrap decoration may not be applied to FAdd")); +} + +TEST_F(ValidateDecorations, NoSignedWrapExtInstOpenCLGood) { + std::string spirv = + MakeIntegerShader("OpDecorate %val NoSignedWrap", + "%val = OpExtInst %int %opencl s_abs %zero"); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateDecorations, NoSignedWrapExtInstGLSLGood) { + std::string spirv = MakeIntegerShader( + "OpDecorate %val NoSignedWrap", "%val = OpExtInst %int %glsl SAbs %zero"); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +// TODO(dneto): For NoSignedWrap and NoUnsignedWrap, permit +// "OpExtInst for instruction numbers specified in the extended +// instruction-set specifications as accepting this decoration." + +// NoUnignedWrap + +TEST_F(ValidateDecorations, NoUnsignedWrapOnTypeBad) { + std::string spirv = MakeIntegerShader("OpDecorate %void NoUnsignedWrap", ""); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("NoUnsignedWrap decoration may not be applied to TypeVoid")); +} + +TEST_F(ValidateDecorations, NoUnsignedWrapOnLabelBad) { + std::string spirv = MakeIntegerShader("OpDecorate %entry NoUnsignedWrap", ""); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("NoUnsignedWrap decoration may not be applied to Label")); +} + +TEST_F(ValidateDecorations, NoUnsignedWrapRequiresExtensionBad) { + std::string spirv = MakeIntegerShader("OpDecorate %val NoUnsignedWrap", + "%val = OpIAdd %int %zero %zero", ""); + + CompileSuccessfully(spirv); + EXPECT_NE(SPV_SUCCESS, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("requires one of these extensions: " + "SPV_KHR_no_integer_wrap_decoration")); +} + +TEST_F(ValidateDecorations, NoUnsignedWrapRequiresExtensionV13Bad) { + std::string spirv = MakeIntegerShader("OpDecorate %val NoUnsignedWrap", + "%val = OpIAdd %int %zero %zero", ""); + + CompileSuccessfully(spirv); + EXPECT_NE(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("requires one of these extensions: " + "SPV_KHR_no_integer_wrap_decoration")); +} + +TEST_F(ValidateDecorations, NoUnsignedWrapOkInSPV14Good) { + std::string spirv = MakeIntegerShader("OpDecorate %val NoUnsignedWrap", + "%val = OpIAdd %int %zero %zero", ""); + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateDecorations, NoUnsignedWrapIAddGood) { + std::string spirv = MakeIntegerShader("OpDecorate %val NoUnsignedWrap", + "%val = OpIAdd %int %zero %zero"); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateDecorations, NoUnsignedWrapISubGood) { + std::string spirv = MakeIntegerShader("OpDecorate %val NoUnsignedWrap", + "%val = OpISub %int %zero %zero"); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateDecorations, NoUnsignedWrapIMulGood) { + std::string spirv = MakeIntegerShader("OpDecorate %val NoUnsignedWrap", + "%val = OpIMul %int %zero %zero"); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateDecorations, NoUnsignedWrapShiftLeftLogicalGood) { + std::string spirv = + MakeIntegerShader("OpDecorate %val NoUnsignedWrap", + "%val = OpShiftLeftLogical %int %zero %zero"); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateDecorations, NoUnsignedWrapSNegateGood) { + std::string spirv = MakeIntegerShader("OpDecorate %val NoUnsignedWrap", + "%val = OpSNegate %int %zero"); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateDecorations, NoUnsignedWrapSRemBad) { + std::string spirv = MakeIntegerShader("OpDecorate %val NoUnsignedWrap", + "%val = OpSRem %int %zero %zero"); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("NoUnsignedWrap decoration may not be applied to SRem")); +} + +TEST_F(ValidateDecorations, NoUnsignedWrapFAddBad) { + std::string spirv = MakeIntegerShader("OpDecorate %val NoUnsignedWrap", + "%val = OpFAdd %float %float0 %float0"); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("NoUnsignedWrap decoration may not be applied to FAdd")); +} + +TEST_F(ValidateDecorations, NoUnsignedWrapExtInstOpenCLGood) { + std::string spirv = + MakeIntegerShader("OpDecorate %val NoUnsignedWrap", + "%val = OpExtInst %int %opencl s_abs %zero"); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateDecorations, NoUnsignedWrapExtInstGLSLGood) { + std::string spirv = + MakeIntegerShader("OpDecorate %val NoUnsignedWrap", + "%val = OpExtInst %int %glsl SAbs %zero"); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateDecorations, AliasedandRestrictBad) { + const std::string body = R"( +OpCapability Shader +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpSource GLSL 430 +OpMemberDecorate %Output 0 Offset 0 +OpDecorate %Output BufferBlock +OpDecorate %dataOutput Restrict +OpDecorate %dataOutput Aliased +%void = OpTypeVoid +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 +%Output = OpTypeStruct %float +%_ptr_Uniform_Output = OpTypePointer Uniform %Output +%dataOutput = OpVariable %_ptr_Uniform_Output Uniform +%main = OpFunction %void None %3 +%5 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(body.c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("decorated with both Aliased and Restrict is not allowed")); +} + +// TODO(dneto): For NoUnsignedWrap and NoUnsignedWrap, permit +// "OpExtInst for instruction numbers specified in the extended +// instruction-set specifications as accepting this decoration." + +TEST_F(ValidateDecorations, PSBAliasedRestrictPointerSuccess) { + const std::string body = R"( +OpCapability PhysicalStorageBufferAddressesEXT +OpCapability Int64 +OpCapability Shader +OpExtension "SPV_EXT_physical_storage_buffer" +OpMemoryModel PhysicalStorageBuffer64EXT GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpDecorate %val1 RestrictPointerEXT +%uint64 = OpTypeInt 64 0 +%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64 +%pptr_f = OpTypePointer Function %ptr +%void = OpTypeVoid +%voidfn = OpTypeFunction %void +%main = OpFunction %void None %voidfn +%entry = OpLabel +%val1 = OpVariable %pptr_f Function +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(body.c_str()); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateDecorations, PSBAliasedRestrictPointerMissing) { + const std::string body = R"( +OpCapability PhysicalStorageBufferAddressesEXT +OpCapability Int64 +OpCapability Shader +OpExtension "SPV_EXT_physical_storage_buffer" +OpMemoryModel PhysicalStorageBuffer64EXT GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +%uint64 = OpTypeInt 64 0 +%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64 +%pptr_f = OpTypePointer Function %ptr +%void = OpTypeVoid +%voidfn = OpTypeFunction %void +%main = OpFunction %void None %voidfn +%entry = OpLabel +%val1 = OpVariable %pptr_f Function +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(body.c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("expected AliasedPointerEXT or RestrictPointerEXT for " + "PhysicalStorageBufferEXT pointer")); +} + +TEST_F(ValidateDecorations, PSBAliasedRestrictPointerBoth) { + const std::string body = R"( +OpCapability PhysicalStorageBufferAddressesEXT +OpCapability Int64 +OpCapability Shader +OpExtension "SPV_EXT_physical_storage_buffer" +OpMemoryModel PhysicalStorageBuffer64EXT GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpDecorate %val1 RestrictPointerEXT +OpDecorate %val1 AliasedPointerEXT +%uint64 = OpTypeInt 64 0 +%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64 +%pptr_f = OpTypePointer Function %ptr +%void = OpTypeVoid +%voidfn = OpTypeFunction %void +%main = OpFunction %void None %voidfn +%entry = OpLabel +%val1 = OpVariable %pptr_f Function +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(body.c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("can't specify both AliasedPointerEXT and RestrictPointerEXT " + "for PhysicalStorageBufferEXT pointer")); +} + +TEST_F(ValidateDecorations, PSBAliasedRestrictFunctionParamSuccess) { + const std::string body = R"( +OpCapability PhysicalStorageBufferAddressesEXT +OpCapability Int64 +OpCapability Shader +OpExtension "SPV_EXT_physical_storage_buffer" +OpMemoryModel PhysicalStorageBuffer64EXT GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpDecorate %fparam Restrict +%uint64 = OpTypeInt 64 0 +%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64 +%void = OpTypeVoid +%voidfn = OpTypeFunction %void +%fnptr = OpTypeFunction %void %ptr +%main = OpFunction %void None %voidfn +%entry = OpLabel +OpReturn +OpFunctionEnd +%fn = OpFunction %void None %fnptr +%fparam = OpFunctionParameter %ptr +%lab = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(body.c_str()); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateDecorations, PSBAliasedRestrictFunctionParamMissing) { + const std::string body = R"( +OpCapability PhysicalStorageBufferAddressesEXT +OpCapability Int64 +OpCapability Shader +OpExtension "SPV_EXT_physical_storage_buffer" +OpMemoryModel PhysicalStorageBuffer64EXT GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +%uint64 = OpTypeInt 64 0 +%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64 +%void = OpTypeVoid +%voidfn = OpTypeFunction %void +%fnptr = OpTypeFunction %void %ptr +%main = OpFunction %void None %voidfn +%entry = OpLabel +OpReturn +OpFunctionEnd +%fn = OpFunction %void None %fnptr +%fparam = OpFunctionParameter %ptr +%lab = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(body.c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("expected Aliased or Restrict for " + "PhysicalStorageBufferEXT pointer")); +} + +TEST_F(ValidateDecorations, PSBAliasedRestrictFunctionParamBoth) { + const std::string body = R"( +OpCapability PhysicalStorageBufferAddressesEXT +OpCapability Int64 +OpCapability Shader +OpExtension "SPV_EXT_physical_storage_buffer" +OpMemoryModel PhysicalStorageBuffer64EXT GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpDecorate %fparam Restrict +OpDecorate %fparam Aliased +%uint64 = OpTypeInt 64 0 +%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64 +%void = OpTypeVoid +%voidfn = OpTypeFunction %void +%fnptr = OpTypeFunction %void %ptr +%main = OpFunction %void None %voidfn +%entry = OpLabel +OpReturn +OpFunctionEnd +%fn = OpFunction %void None %fnptr +%fparam = OpFunctionParameter %ptr +%lab = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(body.c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("can't specify both Aliased and Restrict for " + "PhysicalStorageBufferEXT pointer")); +} + +TEST_F(ValidateDecorations, PSBFPRoundingModeSuccess) { + std::string spirv = R"( +OpCapability PhysicalStorageBufferAddressesEXT +OpCapability Shader +OpCapability Linkage +OpCapability StorageBuffer16BitAccess +OpExtension "SPV_EXT_physical_storage_buffer" +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpExtension "SPV_KHR_variable_pointers" +OpExtension "SPV_KHR_16bit_storage" +OpMemoryModel PhysicalStorageBuffer64EXT GLSL450 +OpEntryPoint GLCompute %main "main" +OpDecorate %_ FPRoundingMode RTE +OpDecorate %half_ptr_var AliasedPointerEXT +%half = OpTypeFloat 16 +%float = OpTypeFloat 32 +%float_1_25 = OpConstant %float 1.25 +%half_ptr = OpTypePointer PhysicalStorageBufferEXT %half +%half_pptr_f = OpTypePointer Function %half_ptr +%void = OpTypeVoid +%func = OpTypeFunction %void +%main = OpFunction %void None %func +%main_entry = OpLabel +%half_ptr_var = OpVariable %half_pptr_f Function +%val1 = OpLoad %half_ptr %half_ptr_var +%_ = OpFConvert %half %float_1_25 +OpStore %val1 %_ Aligned 2 +OpReturn +OpFunctionEnd + )"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState()); +} + +TEST_F(ValidateDecorations, InvalidStraddle) { + const std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpMemberDecorate %inner_struct 0 Offset 0 +OpMemberDecorate %inner_struct 1 Offset 4 +OpDecorate %outer_struct Block +OpMemberDecorate %outer_struct 0 Offset 0 +OpMemberDecorate %outer_struct 1 Offset 8 +OpDecorate %var DescriptorSet 0 +OpDecorate %var Binding 0 +%void = OpTypeVoid +%float = OpTypeFloat 32 +%float2 = OpTypeVector %float 2 +%inner_struct = OpTypeStruct %float %float2 +%outer_struct = OpTypeStruct %float2 %inner_struct +%ptr_ssbo_outer = OpTypePointer StorageBuffer %outer_struct +%var = OpVariable %ptr_ssbo_outer StorageBuffer +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Structure id 2 decorated as Block for variable in " + "StorageBuffer storage class must follow relaxed " + "storage buffer layout rules: member 1 is an " + "improperly straddling vector at offset 12")); +} + +TEST_F(ValidateDecorations, DescriptorArray) { + const std::string spirv = R"( +OpCapability Shader +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %struct Block +OpMemberDecorate %struct 0 Offset 0 +OpMemberDecorate %struct 1 Offset 1 +OpDecorate %var DescriptorSet 0 +OpDecorate %var Binding 0 +%void = OpTypeVoid +%float = OpTypeFloat 32 +%int = OpTypeInt 32 0 +%int_2 = OpConstant %int 2 +%float2 = OpTypeVector %float 2 +%struct = OpTypeStruct %float %float2 +%struct_array = OpTypeArray %struct %int_2 +%ptr_ssbo_array = OpTypePointer StorageBuffer %struct_array +%var = OpVariable %ptr_ssbo_array StorageBuffer +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Structure id 2 decorated as Block for variable in " + "StorageBuffer storage class must follow standard " + "storage buffer layout rules: member 1 at offset 1 is " + "not aligned to 8")); +} + +TEST_F(ValidateDecorations, DescriptorRuntimeArray) { + const std::string spirv = R"( +OpCapability Shader +OpCapability RuntimeDescriptorArrayEXT +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpExtension "SPV_EXT_descriptor_indexing" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %struct Block +OpMemberDecorate %struct 0 Offset 0 +OpMemberDecorate %struct 1 Offset 1 +OpDecorate %var DescriptorSet 0 +OpDecorate %var Binding 0 +%void = OpTypeVoid +%float = OpTypeFloat 32 +%int = OpTypeInt 32 0 +%float2 = OpTypeVector %float 2 +%struct = OpTypeStruct %float %float2 +%struct_array = OpTypeRuntimeArray %struct +%ptr_ssbo_array = OpTypePointer StorageBuffer %struct_array +%var = OpVariable %ptr_ssbo_array StorageBuffer +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Structure id 2 decorated as Block for variable in " + "StorageBuffer storage class must follow standard " + "storage buffer layout rules: member 1 at offset 1 is " + "not aligned to 8")); +} + +TEST_F(ValidateDecorations, MultiDimensionalArray) { + const std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %struct Block +OpMemberDecorate %struct 0 Offset 0 +OpDecorate %array_4 ArrayStride 4 +OpDecorate %array_3 ArrayStride 48 +OpDecorate %var DescriptorSet 0 +OpDecorate %var Binding 0 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_3 = OpConstant %int 3 +%int_4 = OpConstant %int 4 +%array_4 = OpTypeArray %int %int_4 +%array_3 = OpTypeArray %array_4 %int_3 +%struct = OpTypeStruct %array_3 +%ptr_struct = OpTypePointer Uniform %struct +%var = OpVariable %ptr_struct Uniform +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Structure id 2 decorated as Block for variable in " + "Uniform storage class must follow standard uniform " + "buffer layout rules: member 0 contains an array with " + "stride 4 not satisfying alignment to 16")); +} + +TEST_F(ValidateDecorations, ImproperStraddleInArray) { + const std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %struct Block +OpMemberDecorate %struct 0 Offset 0 +OpDecorate %array ArrayStride 24 +OpMemberDecorate %inner 0 Offset 0 +OpMemberDecorate %inner 1 Offset 4 +OpMemberDecorate %inner 2 Offset 12 +OpMemberDecorate %inner 3 Offset 16 +OpDecorate %var DescriptorSet 0 +OpDecorate %var Binding 0 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_2 = OpConstant %int 2 +%int2 = OpTypeVector %int 2 +%inner = OpTypeStruct %int %int2 %int %int +%array = OpTypeArray %inner %int_2 +%struct = OpTypeStruct %array +%ptr_struct = OpTypePointer StorageBuffer %struct +%var = OpVariable %ptr_struct StorageBuffer +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Structure id 4 decorated as Block for variable in " + "StorageBuffer storage class must follow relaxed " + "storage buffer layout rules: member 1 is an " + "improperly straddling vector at offset 28")); +} + +TEST_F(ValidateDecorations, LargeArray) { + const std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %struct Block +OpMemberDecorate %struct 0 Offset 0 +OpDecorate %array ArrayStride 24 +OpMemberDecorate %inner 0 Offset 0 +OpMemberDecorate %inner 1 Offset 8 +OpMemberDecorate %inner 2 Offset 16 +OpMemberDecorate %inner 3 Offset 20 +OpDecorate %var DescriptorSet 0 +OpDecorate %var Binding 0 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_2000000 = OpConstant %int 2000000 +%int2 = OpTypeVector %int 2 +%inner = OpTypeStruct %int %int2 %int %int +%array = OpTypeArray %inner %int_2000000 +%struct = OpTypeStruct %array +%ptr_struct = OpTypePointer StorageBuffer %struct +%var = OpVariable %ptr_struct StorageBuffer +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1)); +} + +// NonWritable + +// Returns a SPIR-V shader module with variables in various storage classes, +// parameterizable by which ID should be decorated as NonWritable. +std::string ShaderWithNonWritableTarget(const std::string& target, + bool member_decorate = false) { + const std::string decoration_inst = + std::string(member_decorate ? "OpMemberDecorate " : "OpDecorate ") + + target + (member_decorate ? " 0" : ""); + + return std::string(R"( + OpCapability Shader + OpCapability RuntimeDescriptorArrayEXT + OpExtension "SPV_EXT_descriptor_indexing" + OpExtension "SPV_KHR_storage_buffer_storage_class" + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %main "main" + OpName %label "label" + OpName %param_f "param_f" + OpName %param_p "param_p" + OpName %_ptr_imstor "_ptr_imstor" + OpName %_ptr_imsam "_ptr_imsam" + OpName %var_wg "var_wg" + OpName %var_imsam "var_imsam" + OpName %var_priv "var_priv" + OpName %var_func "var_func" + OpName %simple_struct "simple_struct" + + OpDecorate %struct_b Block + OpDecorate %struct_b_rtarr Block + OpMemberDecorate %struct_b 0 Offset 0 + OpMemberDecorate %struct_b_rtarr 0 Offset 0 + OpDecorate %rtarr ArrayStride 4 +)") + decoration_inst + + + R"( NonWritable + + %void = OpTypeVoid + %void_fn = OpTypeFunction %void + %float = OpTypeFloat 32 + %float_0 = OpConstant %float 0 + %int = OpTypeInt 32 0 + %int_2 = OpConstant %int 2 + %struct_b = OpTypeStruct %float + %rtarr = OpTypeRuntimeArray %float +%struct_b_rtarr = OpTypeStruct %rtarr +%simple_struct = OpTypeStruct %float + ; storage image + %imstor = OpTypeImage %float 2D 0 0 0 2 R32f + ; sampled image + %imsam = OpTypeImage %float 2D 0 0 0 1 R32f +%array_imstor = OpTypeArray %imstor %int_2 +%rta_imstor = OpTypeRuntimeArray %imstor + +%_ptr_Uniform_stb = OpTypePointer Uniform %struct_b +%_ptr_StorageBuffer_stb = OpTypePointer StorageBuffer %struct_b +%_ptr_StorageBuffer_stb_rtarr = OpTypePointer StorageBuffer %struct_b_rtarr +%_ptr_Workgroup = OpTypePointer Workgroup %float +%_ptr_Private = OpTypePointer Private %float +%_ptr_Function = OpTypePointer Function %float +%_ptr_imstor = OpTypePointer UniformConstant %imstor +%_ptr_imsam = OpTypePointer UniformConstant %imsam +%_ptr_array_imstor = OpTypePointer UniformConstant %array_imstor +%_ptr_rta_imstor = OpTypePointer UniformConstant %rta_imstor + +%extra_fn = OpTypeFunction %void %float %_ptr_Private %_ptr_imstor + +%var_ubo = OpVariable %_ptr_Uniform_stb Uniform +%var_ssbo_sb = OpVariable %_ptr_StorageBuffer_stb StorageBuffer +%var_ssbo_sb_rtarr = OpVariable %_ptr_StorageBuffer_stb_rtarr StorageBuffer +%var_wg = OpVariable %_ptr_Workgroup Workgroup +%var_priv = OpVariable %_ptr_Private Private +%var_imstor = OpVariable %_ptr_imstor UniformConstant +%var_imsam = OpVariable %_ptr_imsam UniformConstant +%var_array_imstor = OpVariable %_ptr_array_imstor UniformConstant +%var_rta_imstor = OpVariable %_ptr_rta_imstor UniformConstant + + %helper = OpFunction %void None %extra_fn + %param_f = OpFunctionParameter %float + %param_p = OpFunctionParameter %_ptr_Private + %param_pimstor = OpFunctionParameter %_ptr_imstor +%helper_label = OpLabel +%helper_func_var = OpVariable %_ptr_Function Function + OpReturn + OpFunctionEnd + + %main = OpFunction %void None %void_fn + %label = OpLabel +%var_func = OpVariable %_ptr_Function Function + OpReturn + OpFunctionEnd +)"; +} + +TEST_F(ValidateDecorations, NonWritableLabelTargetBad) { + std::string spirv = ShaderWithNonWritableTarget("%label"); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Target of NonWritable decoration must be a " + "memory object declaration (a variable or a function " + "parameter)\n %label = OpLabel")); +} + +TEST_F(ValidateDecorations, NonWritableTypeTargetBad) { + std::string spirv = ShaderWithNonWritableTarget("%void"); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Target of NonWritable decoration must be a " + "memory object declaration (a variable or a function " + "parameter)\n %void = OpTypeVoid")); +} + +TEST_F(ValidateDecorations, NonWritableValueTargetBad) { + std::string spirv = ShaderWithNonWritableTarget("%float_0"); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Target of NonWritable decoration must be a " + "memory object declaration (a variable or a function " + "parameter)\n %float_0 = OpConstant %float 0")); +} + +TEST_F(ValidateDecorations, NonWritableValueParamBad) { + std::string spirv = ShaderWithNonWritableTarget("%param_f"); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Target of NonWritable decoration is invalid: must " + "point to a storage image, uniform block, or storage " + "buffer\n %param_f = OpFunctionParameter %float")); +} + +TEST_F(ValidateDecorations, NonWritablePointerParamButWrongTypeBad) { + std::string spirv = ShaderWithNonWritableTarget("%param_p"); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "Target of NonWritable decoration is invalid: must " + "point to a storage image, uniform block, or storage " + "buffer\n %param_p = OpFunctionParameter %_ptr_Private_float")); +} + +TEST_F(ValidateDecorations, NonWritablePointerParamStorageImageGood) { + std::string spirv = ShaderWithNonWritableTarget("%param_pimstor"); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateDecorations, NonWritableVarStorageImageGood) { + std::string spirv = ShaderWithNonWritableTarget("%var_imstor"); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateDecorations, NonWritableVarSampledImageBad) { + std::string spirv = ShaderWithNonWritableTarget("%var_imsam"); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Target of NonWritable decoration is invalid: must " + "point to a storage image, uniform block, or storage " + "buffer\n %var_imsam")); +} + +TEST_F(ValidateDecorations, NonWritableVarUboGood) { + std::string spirv = ShaderWithNonWritableTarget("%var_ubo"); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateDecorations, NonWritableVarSsboInUniformGood) { + const std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Vertex %main "main" +OpDecorate %struct_bb BufferBlock +OpMemberDecorate %struct_bb 0 Offset 0 +OpDecorate %var_ssbo_u NonWritable +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%float = OpTypeFloat 32 +%struct_bb = OpTypeStruct %float +%_ptr_Uniform_stbb = OpTypePointer Uniform %struct_bb +%var_ssbo_u = OpVariable %_ptr_Uniform_stbb Uniform +%main = OpFunction %void None %void_fn +%label = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateDecorations, NonWritableVarSsboInStorageBufferGood) { + std::string spirv = ShaderWithNonWritableTarget("%var_ssbo_sb"); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateDecorations, NonWritableMemberOfSsboInStorageBufferGood) { + std::string spirv = ShaderWithNonWritableTarget("%struct_b_rtarr", true); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateDecorations, NonWritableMemberOfStructGood) { + std::string spirv = ShaderWithNonWritableTarget("%simple_struct", true); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateDecorations, NonWritableVarWorkgroupBad) { + std::string spirv = ShaderWithNonWritableTarget("%var_wg"); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Target of NonWritable decoration is invalid: must " + "point to a storage image, uniform block, or storage " + "buffer\n %var_wg")); +} + +TEST_F(ValidateDecorations, NonWritableVarWorkgroupV14Bad) { + std::string spirv = ShaderWithNonWritableTarget("%var_wg"); + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Target of NonWritable decoration is invalid: must " + "point to a storage image, uniform block, storage " + "buffer, or variable in Private or Function storage " + "class\n %var_wg")); +} + +TEST_F(ValidateDecorations, NonWritableVarPrivateBad) { + std::string spirv = ShaderWithNonWritableTarget("%var_priv"); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Target of NonWritable decoration is invalid: must " + "point to a storage image, uniform block, or storage " + "buffer\n %var_priv")); +} + +TEST_F(ValidateDecorations, NonWritableVarPrivateV13Bad) { + std::string spirv = ShaderWithNonWritableTarget("%var_priv"); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Target of NonWritable decoration is invalid: must " + "point to a storage image, uniform block, or storage " + "buffer\n %var_priv")); +} + +TEST_F(ValidateDecorations, NonWritableVarPrivateV14Good) { + std::string spirv = ShaderWithNonWritableTarget("%var_priv"); + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateDecorations, NonWritableVarPrivateV13TargetV14Bad) { + std::string spirv = ShaderWithNonWritableTarget("%var_priv"); + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Target of NonWritable decoration is invalid: must " + "point to a storage image, uniform block, or storage " + "buffer\n %var_priv")); +} + +TEST_F(ValidateDecorations, NonWritableVarFunctionBad) { + std::string spirv = ShaderWithNonWritableTarget("%var_func"); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Target of NonWritable decoration is invalid: must " + "point to a storage image, uniform block, or storage " + "buffer\n %var_func")); +} + +TEST_F(ValidateDecorations, NonWritableArrayGood) { + std::string spirv = ShaderWithNonWritableTarget("%var_array_imstor"); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateDecorations, NonWritableRuntimeArrayGood) { + std::string spirv = ShaderWithNonWritableTarget("%var_rta_imstor"); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_P(ValidateWebGPUCombineDecorationResult, Decorate) { + const char* const decoration = std::get<0>(GetParam()); + const TestResult& test_result = std::get<1>(GetParam()); + + CodeGenerator generator = CodeGenerator::GetWebGPUShaderCodeGenerator(); + generator.before_types_ = "OpDecorate %u32 "; + generator.before_types_ += decoration; + generator.before_types_ += "\n"; + + EntryPoint entry_point; + entry_point.name = "main"; + entry_point.execution_model = "Vertex"; + generator.entry_points_.push_back(std::move(entry_point)); + + CompileSuccessfully(generator.Build(), SPV_ENV_WEBGPU_0); + ASSERT_EQ(test_result.validation_result, + ValidateInstructions(SPV_ENV_WEBGPU_0)); + if (test_result.error_str != "") { + EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str)); + } +} + +TEST_P(ValidateWebGPUCombineDecorationResult, DecorateMember) { + const char* const decoration = std::get<0>(GetParam()); + const TestResult& test_result = std::get<1>(GetParam()); + + CodeGenerator generator = CodeGenerator::GetWebGPUShaderCodeGenerator(); + generator.before_types_ = "OpMemberDecorate %struct_type 0 "; + generator.before_types_ += decoration; + generator.before_types_ += "\n"; + + generator.after_types_ = "%struct_type = OpTypeStruct %u32\n"; + + EntryPoint entry_point; + entry_point.name = "main"; + entry_point.execution_model = "Vertex"; + generator.entry_points_.push_back(std::move(entry_point)); + + CompileSuccessfully(generator.Build(), SPV_ENV_WEBGPU_0); + ASSERT_EQ(test_result.validation_result, + ValidateInstructions(SPV_ENV_WEBGPU_0)); + if (!test_result.error_str.empty()) { + EXPECT_THAT(getDiagnosticString(), HasSubstr(test_result.error_str)); + } +} + +INSTANTIATE_TEST_SUITE_P( + DecorationCapabilityFailure, ValidateWebGPUCombineDecorationResult, + Combine(Values("CPacked", "Patch", "Sample", "Constant", + "SaturatedConversion", "NonUniformEXT"), + Values(TestResult(SPV_ERROR_INVALID_CAPABILITY, + "requires one of these capabilities")))); + +INSTANTIATE_TEST_SUITE_P( + DecorationWhitelistFailure, ValidateWebGPUCombineDecorationResult, + Combine(Values("RelaxedPrecision", "BufferBlock", "GLSLShared", + "GLSLPacked", "Invariant", "Volatile", "Coherent"), + Values(TestResult( + SPV_ERROR_INVALID_ID, + "is not valid for the WebGPU execution environment.")))); + +TEST_F(ValidateDecorations, NonWritableVarFunctionV13Bad) { + std::string spirv = ShaderWithNonWritableTarget("%var_func"); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Target of NonWritable decoration is invalid: must " + "point to a storage image, uniform block, or storage " + "buffer\n %var_func")); +} + +TEST_F(ValidateDecorations, NonWritableVarFunctionV14Good) { + std::string spirv = ShaderWithNonWritableTarget("%var_func"); + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateDecorations, NonWritableVarFunctionV13TargetV14Bad) { + std::string spirv = ShaderWithNonWritableTarget("%var_func"); + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Target of NonWritable decoration is invalid: must " + "point to a storage image, uniform block, or storage " + "buffer\n %var_func")); +} + +TEST_F(ValidateDecorations, BufferBlockV13ValV14Good) { + std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpDecorate %1 BufferBlock +%1 = OpTypeStruct +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); +} + +TEST_F(ValidateDecorations, BufferBlockV14Bad) { + std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +OpDecorate %1 BufferBlock +%1 = OpTypeStruct +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_ERROR_WRONG_VERSION, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("2nd operand of Decorate: operand BufferBlock(3) " + "requires SPIR-V version 1.3 or earlier")); +} + +// Component + +TEST_F(ValidateDecorations, ComponentDecorationBadTarget) { + std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Vertex %main "main" +OpDecorate %t Component 0 +%void = OpTypeVoid +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 +%t = OpTypeVector %float 2 +%main = OpFunction %void None %3 +%5 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Target of Component decoration must be " + "a memory object declaration")); +} + +TEST_F(ValidateDecorations, ComponentDecorationBadStorageClass) { + std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Vertex %main "main" +OpDecorate %v Component 0 +%void = OpTypeVoid +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 +%t = OpTypeVector %float 2 +%ptr_private = OpTypePointer Private %t +%v = OpVariable %ptr_private Private +%main = OpFunction %void None %3 +%5 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Target of Component decoration is invalid: must " + "point to a Storage Class of Input(1) or Output(3)")); +} + +TEST_F(ValidateDecorations, ComponentDecorationBadTypeVulkan) { + const spv_target_env env = SPV_ENV_VULKAN_1_0; + std::string spirv = R"( +OpCapability Shader +OpCapability Matrix +OpMemoryModel Logical GLSL450 +OpEntryPoint Vertex %main "main" +OpDecorate %v Component 0 +%void = OpTypeVoid +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 +%vtype = OpTypeVector %float 4 +%t = OpTypeMatrix %vtype 4 +%ptr_input = OpTypePointer Input %t +%v = OpVariable %ptr_input Input +%main = OpFunction %void None %3 +%5 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, env); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState(env)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Component decoration specified for type")); + EXPECT_THAT(getDiagnosticString(), HasSubstr("is not a scalar or vector")); +} + +std::string ShaderWithComponentDecoration(const std::string& type, + const std::string& decoration) { + return R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %entryPointOutput +OpExecutionMode %main OriginUpperLeft +OpDecorate %entryPointOutput Location 0 +OpDecorate %entryPointOutput )" + + decoration + R"( +%void = OpTypeVoid +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v3float = OpTypeVector %float 3 +%v4float = OpTypeVector %float 4 +%uint = OpTypeInt 32 0 +%uint_2 = OpConstant %uint 2 +%arr_v3float_uint_2 = OpTypeArray %v3float %uint_2 +%float_0 = OpConstant %float 0 +%_ptr_Output_type = OpTypePointer Output %)" + type + R"( +%entryPointOutput = OpVariable %_ptr_Output_type Output +%main = OpFunction %void None %3 +%5 = OpLabel +OpReturn +OpFunctionEnd +)"; +} + +TEST_F(ValidateDecorations, ComponentDecorationIntGood0Vulkan) { + const spv_target_env env = SPV_ENV_VULKAN_1_0; + std::string spirv = ShaderWithComponentDecoration("uint", "Component 0"); + + CompileSuccessfully(spirv, env); + EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(env)); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateDecorations, ComponentDecorationIntGood1Vulkan) { + const spv_target_env env = SPV_ENV_VULKAN_1_0; + std::string spirv = ShaderWithComponentDecoration("uint", "Component 1"); + + CompileSuccessfully(spirv, env); + EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(env)); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateDecorations, ComponentDecorationIntGood2Vulkan) { + const spv_target_env env = SPV_ENV_VULKAN_1_0; + std::string spirv = ShaderWithComponentDecoration("uint", "Component 2"); + + CompileSuccessfully(spirv, env); + EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(env)); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateDecorations, ComponentDecorationIntGood3Vulkan) { + const spv_target_env env = SPV_ENV_VULKAN_1_0; + std::string spirv = ShaderWithComponentDecoration("uint", "Component 3"); + + CompileSuccessfully(spirv, env); + EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(env)); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateDecorations, ComponentDecorationIntBad4Vulkan) { + const spv_target_env env = SPV_ENV_VULKAN_1_0; + std::string spirv = ShaderWithComponentDecoration("uint", "Component 4"); + + CompileSuccessfully(spirv, env); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState(env)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Sequence of components starting with 4 " + "and ending with 4 gets larger than 3")); +} + +TEST_F(ValidateDecorations, ComponentDecorationVector3GoodVulkan) { + const spv_target_env env = SPV_ENV_VULKAN_1_0; + std::string spirv = ShaderWithComponentDecoration("v3float", "Component 1"); + + CompileSuccessfully(spirv, env); + EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(env)); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateDecorations, ComponentDecorationVector4GoodVulkan) { + const spv_target_env env = SPV_ENV_VULKAN_1_0; + std::string spirv = ShaderWithComponentDecoration("v4float", "Component 0"); + + CompileSuccessfully(spirv, env); + EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(env)); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateDecorations, ComponentDecorationVector4Bad1Vulkan) { + const spv_target_env env = SPV_ENV_VULKAN_1_0; + std::string spirv = ShaderWithComponentDecoration("v4float", "Component 1"); + + CompileSuccessfully(spirv, env); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState(env)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Sequence of components starting with 1 " + "and ending with 4 gets larger than 3")); +} + +TEST_F(ValidateDecorations, ComponentDecorationVector4Bad3Vulkan) { + const spv_target_env env = SPV_ENV_VULKAN_1_0; + std::string spirv = ShaderWithComponentDecoration("v4float", "Component 3"); + + CompileSuccessfully(spirv, env); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState(env)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Sequence of components starting with 3 " + "and ending with 6 gets larger than 3")); +} + +TEST_F(ValidateDecorations, ComponentDecorationArrayGoodVulkan) { + const spv_target_env env = SPV_ENV_VULKAN_1_0; + std::string spirv = + ShaderWithComponentDecoration("arr_v3float_uint_2", "Component 1"); + + CompileSuccessfully(spirv, env); + EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(env)); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateDecorations, ComponentDecorationArrayBadVulkan) { + const spv_target_env env = SPV_ENV_VULKAN_1_0; + std::string spirv = + ShaderWithComponentDecoration("arr_v3float_uint_2", "Component 2"); + + CompileSuccessfully(spirv, env); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState(env)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Sequence of components starting with 2 " + "and ending with 4 gets larger than 3")); +} + +TEST_F(ValidateDecorations, ComponentDecorationBlockGood) { + std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %4 "main" %9 %12 +OpExecutionMode %4 OriginUpperLeft +OpDecorate %9 Location 0 +OpMemberDecorate %block 0 Location 2 +OpMemberDecorate %block 0 Component 1 +OpDecorate %block Block +%2 = OpTypeVoid +%3 = OpTypeFunction %2 +%float = OpTypeFloat 32 +%vec3 = OpTypeVector %float 3 +%8 = OpTypePointer Output %vec3 +%9 = OpVariable %8 Output +%block = OpTypeStruct %vec3 +%11 = OpTypePointer Input %block +%12 = OpVariable %11 Input +%int = OpTypeInt 32 1 +%14 = OpConstant %int 0 +%15 = OpTypePointer Input %vec3 +%4 = OpFunction %2 None %3 +%5 = OpLabel +%16 = OpAccessChain %15 %12 %14 +%17 = OpLoad %vec3 %16 +OpStore %9 %17 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState()); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateDecorations, ComponentDecorationBlockBadVulkan) { + const spv_target_env env = SPV_ENV_VULKAN_1_0; + std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %4 "main" %9 %12 +OpExecutionMode %4 OriginUpperLeft +OpDecorate %9 Location 0 +OpMemberDecorate %block 0 Location 2 +OpMemberDecorate %block 0 Component 2 +OpDecorate %block Block +%2 = OpTypeVoid +%3 = OpTypeFunction %2 +%float = OpTypeFloat 32 +%vec3 = OpTypeVector %float 3 +%8 = OpTypePointer Output %vec3 +%9 = OpVariable %8 Output +%block = OpTypeStruct %vec3 +%11 = OpTypePointer Input %block +%12 = OpVariable %11 Input +%int = OpTypeInt 32 1 +%14 = OpConstant %int 0 +%15 = OpTypePointer Input %vec3 +%4 = OpFunction %2 None %3 +%5 = OpLabel +%16 = OpAccessChain %15 %12 %14 +%17 = OpLoad %vec3 %16 +OpStore %9 %17 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, env); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState(env)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Sequence of components starting with 2 " + "and ending with 4 gets larger than 3")); +} + +TEST_F(ValidateDecorations, ComponentDecorationFunctionParameter) { + std::string spirv = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %main "main" + + OpDecorate %param_f Component 0 + + %void = OpTypeVoid + %void_fn = OpTypeFunction %void + %float = OpTypeFloat 32 + %float_0 = OpConstant %float 0 + %int = OpTypeInt 32 0 + %int_2 = OpConstant %int 2 + %struct_b = OpTypeStruct %float + +%extra_fn = OpTypeFunction %void %float + + %helper = OpFunction %void None %extra_fn + %param_f = OpFunctionParameter %float +%helper_label = OpLabel + OpReturn + OpFunctionEnd + + %main = OpFunction %void None %void_fn + %label = OpLabel + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState()); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateDecorations, VulkanStorageBufferBlock) { + const std::string spirv = R"( +OpCapability Shader +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %struct Block +OpMemberDecorate %struct 0 Offset 0 +%void = OpTypeVoid +%uint = OpTypeInt 32 0 +%struct = OpTypeStruct %uint +%ptr_ssbo = OpTypePointer StorageBuffer %struct +%var = OpVariable %ptr_ssbo StorageBuffer +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0)); +} + +TEST_F(ValidateDecorations, VulkanStorageBufferMissingBlock) { + const std::string spirv = R"( +OpCapability Shader +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +%void = OpTypeVoid +%uint = OpTypeInt 32 0 +%struct = OpTypeStruct %uint +%ptr_ssbo = OpTypePointer StorageBuffer %struct +%var = OpVariable %ptr_ssbo StorageBuffer +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("From Vulkan spec, section 14.5.2:\nSuch variables " + "must be identified with a Block decoration")); +} + +TEST_F(ValidateDecorations, VulkanStorageBufferArrayMissingBlock) { + const std::string spirv = R"( +OpCapability Shader +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +%void = OpTypeVoid +%uint = OpTypeInt 32 0 +%uint_4 = OpConstant %uint 4 +%struct = OpTypeStruct %uint +%array = OpTypeArray %struct %uint_4 +%ptr_ssbo = OpTypePointer StorageBuffer %array +%var = OpVariable %ptr_ssbo StorageBuffer +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("From Vulkan spec, section 14.5.2:\nSuch variables " + "must be identified with a Block decoration")); +} + +TEST_F(ValidateDecorations, VulkanStorageBufferRuntimeArrayMissingBlock) { + const std::string spirv = R"( +OpCapability Shader +OpCapability RuntimeDescriptorArrayEXT +OpExtension "SPV_EXT_descriptor_indexing" +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +%void = OpTypeVoid +%uint = OpTypeInt 32 0 +%struct = OpTypeStruct %uint +%array = OpTypeRuntimeArray %struct +%ptr_ssbo = OpTypePointer StorageBuffer %array +%var = OpVariable %ptr_ssbo StorageBuffer +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("From Vulkan spec, section 14.5.2:\nSuch variables " + "must be identified with a Block decoration")); +} + +TEST_F(ValidateDecorations, VulkanUniformBlock) { + const std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %struct Block +OpMemberDecorate %struct 0 Offset 0 +%void = OpTypeVoid +%uint = OpTypeInt 32 0 +%struct = OpTypeStruct %uint +%ptr_ubo = OpTypePointer Uniform %struct +%var = OpVariable %ptr_ubo Uniform +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0)); +} + +TEST_F(ValidateDecorations, VulkanUniformBufferBlock) { + const std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %struct BufferBlock +OpMemberDecorate %struct 0 Offset 0 +%void = OpTypeVoid +%uint = OpTypeInt 32 0 +%struct = OpTypeStruct %uint +%ptr_ubo = OpTypePointer Uniform %struct +%var = OpVariable %ptr_ubo Uniform +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0)); +} + +TEST_F(ValidateDecorations, VulkanUniformMissingBlock) { + const std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +%void = OpTypeVoid +%uint = OpTypeInt 32 0 +%struct = OpTypeStruct %uint +%ptr_ubo = OpTypePointer Uniform %struct +%var = OpVariable %ptr_ubo Uniform +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("From Vulkan spec, section 14.5.2:\nSuch variables must be " + "identified with a Block or BufferBlock decoration")); +} + +TEST_F(ValidateDecorations, VulkanUniformArrayMissingBlock) { + const std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +%void = OpTypeVoid +%uint = OpTypeInt 32 0 +%uint_4 = OpConstant %uint 4 +%struct = OpTypeStruct %uint +%array = OpTypeArray %struct %uint_4 +%ptr_ubo = OpTypePointer Uniform %array +%var = OpVariable %ptr_ubo Uniform +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("From Vulkan spec, section 14.5.2:\nSuch variables must be " + "identified with a Block or BufferBlock decoration")); +} + +TEST_F(ValidateDecorations, VulkanUniformRuntimeArrayMissingBlock) { + const std::string spirv = R"( +OpCapability Shader +OpCapability RuntimeDescriptorArrayEXT +OpExtension "SPV_EXT_descriptor_indexing" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +%void = OpTypeVoid +%uint = OpTypeInt 32 0 +%struct = OpTypeStruct %uint +%array = OpTypeRuntimeArray %struct +%ptr_ubo = OpTypePointer Uniform %array +%var = OpVariable %ptr_ubo Uniform +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("From Vulkan spec, section 14.5.2:\nSuch variables must be " + "identified with a Block or BufferBlock decoration")); +} + +TEST_F(ValidateDecorations, VulkanArrayStrideZero) { + const std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %var DescriptorSet 0 +OpDecorate %var Binding 0 +OpDecorate %struct Block +OpMemberDecorate %struct 0 Offset 0 +OpDecorate %array ArrayStride 0 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_4 = OpConstant %int 4 +%array = OpTypeArray %int %int_4 +%struct = OpTypeStruct %array +%ptr_ssbo_struct = OpTypePointer StorageBuffer %struct +%var = OpVariable %ptr_ssbo_struct StorageBuffer +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("contains an array with stride 0")); +} + +TEST_F(ValidateDecorations, VulkanArrayStrideTooSmall) { + const std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %var DescriptorSet 0 +OpDecorate %var Binding 0 +OpDecorate %struct Block +OpMemberDecorate %struct 0 Offset 0 +OpDecorate %inner ArrayStride 4 +OpDecorate %outer ArrayStride 4 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_4 = OpConstant %int 4 +%inner = OpTypeArray %int %int_4 +%outer = OpTypeArray %inner %int_4 +%struct = OpTypeStruct %outer +%ptr_ssbo_struct = OpTypePointer StorageBuffer %struct +%var = OpVariable %ptr_ssbo_struct StorageBuffer +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "contains an array with stride 4, but with an element size of 16")); +} + } // namespace } // namespace val } // namespace spvtools diff --git a/third_party/spirv-tools/test/val/val_derivatives_test.cpp b/third_party/spirv-tools/test/val/val_derivatives_test.cpp index 93a70e87cf..606abb93dd 100644 --- a/third_party/spirv-tools/test/val/val_derivatives_test.cpp +++ b/third_party/spirv-tools/test/val/val_derivatives_test.cpp @@ -44,6 +44,9 @@ OpCapability DerivativeControl << " %f32_var_input" << " %f32vec4_var_input" << "\n"; + if (execution_model == "Fragment") { + ss << "OpExecutionMode %main OriginUpperLeft\n"; + } ss << R"( %void = OpTypeVoid @@ -59,7 +62,17 @@ OpCapability DerivativeControl %f32vec4_ptr_input = OpTypePointer Input %f32vec4 %f32vec4_var_input = OpVariable %f32vec4_ptr_input Input +)"; + if (capabilities_and_extensions.find("OpCapability Float16") != + std::string::npos) { + ss << "%f16 = OpTypeFloat 16\n" + << "%f16vec4 = OpTypeVector %f16 4\n" + << "%f16_0 = OpConstantNull %f16\n" + << "%f16vec4_0 = OpConstantNull %f16vec4\n"; + } + + ss << R"( %main = OpFunction %void None %func %main_entry = OpLabel )"; @@ -116,11 +129,9 @@ TEST_F(ValidateDerivatives, OpDPdxWrongResultType) { )"; CompileSuccessfully(GenerateShaderCode(body).c_str()); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr("Expected Result Type to be float scalar or vector type: " - "DPdx")); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), HasSubstr("Operand 10[%v4float] cannot " + "be a type")); } TEST_F(ValidateDerivatives, OpDPdxWrongPType) { @@ -144,12 +155,41 @@ TEST_F(ValidateDerivatives, OpDPdxWrongExecutionModel) { CompileSuccessfully(GenerateShaderCode(body, "", "Vertex").c_str()); ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr( - "Derivative instructions require Fragment execution model: DPdx")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Derivative instructions require Fragment or GLCompute " + "execution model: DPdx")); } +using ValidateHalfDerivatives = spvtest::ValidateBase; + +TEST_P(ValidateHalfDerivatives, ScalarFailure) { + const std::string op = GetParam(); + const std::string body = "%val = " + op + " %f16 %f16_0\n"; + + CompileSuccessfully( + GenerateShaderCode(body, "OpCapability Float16\n").c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Result type component width must be 32 bits")); +} + +TEST_P(ValidateHalfDerivatives, VectorFailure) { + const std::string op = GetParam(); + const std::string body = "%val = " + op + " %f16vec4 %f16vec4_0\n"; + + CompileSuccessfully( + GenerateShaderCode(body, "OpCapability Float16\n").c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Result type component width must be 32 bits")); +} + +INSTANTIATE_TEST_SUITE_P(HalfDerivatives, ValidateHalfDerivatives, + ::testing::Values("OpDPdx", "OpDPdy", "OpFwidth", + "OpDPdxFine", "OpDPdyFine", + "OpFwidthFine", "OpDPdxCoarse", + "OpDPdyCoarse", "OpFwidthCoarse")); + } // namespace } // namespace val } // namespace spvtools diff --git a/third_party/spirv-tools/test/val/val_entry_point.cpp b/third_party/spirv-tools/test/val/val_entry_point.cpp new file mode 100644 index 0000000000..f28cf5d19c --- /dev/null +++ b/third_party/spirv-tools/test/val/val_entry_point.cpp @@ -0,0 +1,76 @@ +// Copyright (c) 2019 Samsung Inc +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include "gmock/gmock.h" +#include "test/unit_spirv.h" +#include "test/val/val_fixtures.h" + +namespace spvtools { +namespace { + +using ::testing::Eq; +using ::testing::HasSubstr; + +using ValidateEntryPoints = spvtest::ValidateBase; + +TEST_F(ValidateEntryPoints, DuplicateEntryPoints) { + const std::string body = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %3 "foo" +OpEntryPoint GLCompute %4 "foo" +%1 = OpTypeVoid +%2 = OpTypeFunction %1 +%3 = OpFunction %1 None %2 +%20 = OpLabel +OpReturn +OpFunctionEnd +%4 = OpFunction %1 None %2 +%21 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(body); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Entry points cannot share the same name")); +} + +TEST_F(ValidateEntryPoints, UniqueEntryPoints) { + const std::string body = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %3 "foo" +OpEntryPoint GLCompute %4 "foo2" +%1 = OpTypeVoid +%2 = OpTypeFunction %1 +%3 = OpFunction %1 None %2 +%20 = OpLabel +OpReturn +OpFunctionEnd +%4 = OpFunction %1 None %2 +%21 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(body); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +} // namespace +} // namespace spvtools diff --git a/third_party/spirv-tools/test/val/val_ext_inst_test.cpp b/third_party/spirv-tools/test/val/val_ext_inst_test.cpp index 40126fd9d6..01df796b10 100644 --- a/third_party/spirv-tools/test/val/val_ext_inst_test.cpp +++ b/third_party/spirv-tools/test/val/val_ext_inst_test.cpp @@ -33,6 +33,9 @@ using ::testing::HasSubstr; using ::testing::Not; using ValidateExtInst = spvtest::ValidateBase; +using ValidateOldDebugInfo = spvtest::ValidateBase; +using ValidateOpenCL100DebugInfo = spvtest::ValidateBase; +using ValidateLocalDebugInfoOutOfFunction = spvtest::ValidateBase; using ValidateGlslStd450SqrtLike = spvtest::ValidateBase; using ValidateGlslStd450FMinLike = spvtest::ValidateBase; using ValidateGlslStd450FClampLike = spvtest::ValidateBase; @@ -107,6 +110,9 @@ OpCapability Int64 << " %u32vec2_input" << " %u64_input" << "\n"; + if (execution_model == "Fragment") { + ss << "OpExecutionMode %main OriginUpperLeft\n"; + } ss << R"( %void = OpTypeVoid @@ -425,6 +431,10 @@ OpCapability Matrix %f16vec8_input = OpVariable %f16vec8_ptr_input Input %f16_ptr_input = OpTypePointer Input %f16 +%u32vec8_ptr_input = OpTypePointer Input %u32vec8 +%u32vec8_input = OpVariable %u32vec8_ptr_input Input +%u32_ptr_input = OpTypePointer Input %u32 + %f32_ptr_generic = OpTypePointer Generic %f32 %u32_ptr_generic = OpTypePointer Generic %u32 @@ -453,6 +463,462 @@ OpFunctionEnd)"; return ss.str(); } +std::string GenerateShaderCodeForDebugInfo( + const std::string& op_string_instructions, + const std::string& op_const_instructions, + const std::string& debug_instructions_before_main, const std::string& body, + const std::string& capabilities_and_extensions = "", + const std::string& execution_model = "Fragment") { + std::ostringstream ss; + ss << R"( +OpCapability Shader +OpCapability Float16 +OpCapability Float64 +OpCapability Int16 +OpCapability Int64 +)"; + + ss << capabilities_and_extensions; + ss << "%extinst = OpExtInstImport \"GLSL.std.450\"\n"; + ss << "OpMemoryModel Logical GLSL450\n"; + ss << "OpEntryPoint " << execution_model << " %main \"main\"" + << " %f32_output" + << " %f32vec2_output" + << " %u32_output" + << " %u32vec2_output" + << " %u64_output" + << " %f32_input" + << " %f32vec2_input" + << " %u32_input" + << " %u32vec2_input" + << " %u64_input" + << "\n"; + if (execution_model == "Fragment") { + ss << "OpExecutionMode %main OriginUpperLeft\n"; + } + + ss << op_string_instructions; + + ss << R"( +%void = OpTypeVoid +%func = OpTypeFunction %void +%bool = OpTypeBool +%f16 = OpTypeFloat 16 +%f32 = OpTypeFloat 32 +%f64 = OpTypeFloat 64 +%u32 = OpTypeInt 32 0 +%s32 = OpTypeInt 32 1 +%u64 = OpTypeInt 64 0 +%s64 = OpTypeInt 64 1 +%u16 = OpTypeInt 16 0 +%s16 = OpTypeInt 16 1 +%f32vec2 = OpTypeVector %f32 2 +%f32vec3 = OpTypeVector %f32 3 +%f32vec4 = OpTypeVector %f32 4 +%f64vec2 = OpTypeVector %f64 2 +%f64vec3 = OpTypeVector %f64 3 +%f64vec4 = OpTypeVector %f64 4 +%u32vec2 = OpTypeVector %u32 2 +%u32vec3 = OpTypeVector %u32 3 +%s32vec2 = OpTypeVector %s32 2 +%u32vec4 = OpTypeVector %u32 4 +%s32vec4 = OpTypeVector %s32 4 +%u64vec2 = OpTypeVector %u64 2 +%s64vec2 = OpTypeVector %s64 2 +%f64mat22 = OpTypeMatrix %f64vec2 2 +%f32mat22 = OpTypeMatrix %f32vec2 2 +%f32mat23 = OpTypeMatrix %f32vec2 3 +%f32mat32 = OpTypeMatrix %f32vec3 2 +%f32mat33 = OpTypeMatrix %f32vec3 3 + +%f32_0 = OpConstant %f32 0 +%f32_1 = OpConstant %f32 1 +%f32_2 = OpConstant %f32 2 +%f32_3 = OpConstant %f32 3 +%f32_4 = OpConstant %f32 4 +%f32_h = OpConstant %f32 0.5 +%f32vec2_01 = OpConstantComposite %f32vec2 %f32_0 %f32_1 +%f32vec2_12 = OpConstantComposite %f32vec2 %f32_1 %f32_2 +%f32vec3_012 = OpConstantComposite %f32vec3 %f32_0 %f32_1 %f32_2 +%f32vec3_123 = OpConstantComposite %f32vec3 %f32_1 %f32_2 %f32_3 +%f32vec4_0123 = OpConstantComposite %f32vec4 %f32_0 %f32_1 %f32_2 %f32_3 +%f32vec4_1234 = OpConstantComposite %f32vec4 %f32_1 %f32_2 %f32_3 %f32_4 + +%f64_0 = OpConstant %f64 0 +%f64_1 = OpConstant %f64 1 +%f64_2 = OpConstant %f64 2 +%f64_3 = OpConstant %f64 3 +%f64vec2_01 = OpConstantComposite %f64vec2 %f64_0 %f64_1 +%f64vec3_012 = OpConstantComposite %f64vec3 %f64_0 %f64_1 %f64_2 +%f64vec4_0123 = OpConstantComposite %f64vec4 %f64_0 %f64_1 %f64_2 %f64_3 + +%f16_0 = OpConstant %f16 0 +%f16_1 = OpConstant %f16 1 +%f16_h = OpConstant %f16 0.5 + +%u32_0 = OpConstant %u32 0 +%u32_1 = OpConstant %u32 1 +%u32_2 = OpConstant %u32 2 +%u32_3 = OpConstant %u32 3 + +%s32_0 = OpConstant %s32 0 +%s32_1 = OpConstant %s32 1 +%s32_2 = OpConstant %s32 2 +%s32_3 = OpConstant %s32 3 + +%u64_0 = OpConstant %u64 0 +%u64_1 = OpConstant %u64 1 +%u64_2 = OpConstant %u64 2 +%u64_3 = OpConstant %u64 3 + +%s64_0 = OpConstant %s64 0 +%s64_1 = OpConstant %s64 1 +%s64_2 = OpConstant %s64 2 +%s64_3 = OpConstant %s64 3 +)"; + + ss << op_const_instructions; + + ss << R"( +%s32vec2_01 = OpConstantComposite %s32vec2 %s32_0 %s32_1 +%u32vec2_01 = OpConstantComposite %u32vec2 %u32_0 %u32_1 + +%s32vec2_12 = OpConstantComposite %s32vec2 %s32_1 %s32_2 +%u32vec2_12 = OpConstantComposite %u32vec2 %u32_1 %u32_2 + +%s32vec4_0123 = OpConstantComposite %s32vec4 %s32_0 %s32_1 %s32_2 %s32_3 +%u32vec4_0123 = OpConstantComposite %u32vec4 %u32_0 %u32_1 %u32_2 %u32_3 + +%s64vec2_01 = OpConstantComposite %s64vec2 %s64_0 %s64_1 +%u64vec2_01 = OpConstantComposite %u64vec2 %u64_0 %u64_1 + +%f32mat22_1212 = OpConstantComposite %f32mat22 %f32vec2_12 %f32vec2_12 +%f32mat23_121212 = OpConstantComposite %f32mat23 %f32vec2_12 %f32vec2_12 %f32vec2_12 + +%f32_ptr_output = OpTypePointer Output %f32 +%f32vec2_ptr_output = OpTypePointer Output %f32vec2 + +%u32_ptr_output = OpTypePointer Output %u32 +%u32vec2_ptr_output = OpTypePointer Output %u32vec2 + +%u64_ptr_output = OpTypePointer Output %u64 + +%f32_output = OpVariable %f32_ptr_output Output +%f32vec2_output = OpVariable %f32vec2_ptr_output Output + +%u32_output = OpVariable %u32_ptr_output Output +%u32vec2_output = OpVariable %u32vec2_ptr_output Output + +%u64_output = OpVariable %u64_ptr_output Output + +%f32_ptr_input = OpTypePointer Input %f32 +%f32vec2_ptr_input = OpTypePointer Input %f32vec2 + +%u32_ptr_input = OpTypePointer Input %u32 +%u32vec2_ptr_input = OpTypePointer Input %u32vec2 + +%u64_ptr_input = OpTypePointer Input %u64 + +%f32_ptr_function = OpTypePointer Function %f32 + +%f32_input = OpVariable %f32_ptr_input Input +%f32vec2_input = OpVariable %f32vec2_ptr_input Input + +%u32_input = OpVariable %u32_ptr_input Input +%u32vec2_input = OpVariable %u32vec2_ptr_input Input + +%u64_input = OpVariable %u64_ptr_input Input + +%u32_ptr_function = OpTypePointer Function %u32 + +%struct_f16_u16 = OpTypeStruct %f16 %u16 +%struct_f32_f32 = OpTypeStruct %f32 %f32 +%struct_f32_f32_f32 = OpTypeStruct %f32 %f32 %f32 +%struct_f32_u32 = OpTypeStruct %f32 %u32 +%struct_f32_u32_f32 = OpTypeStruct %f32 %u32 %f32 +%struct_u32_f32 = OpTypeStruct %u32 %f32 +%struct_u32_u32 = OpTypeStruct %u32 %u32 +%struct_f32_f64 = OpTypeStruct %f32 %f64 +%struct_f32vec2_f32vec2 = OpTypeStruct %f32vec2 %f32vec2 +%struct_f32vec2_u32vec2 = OpTypeStruct %f32vec2 %u32vec2 +)"; + + ss << debug_instructions_before_main; + + ss << R"( +%main = OpFunction %void None %func +%main_entry = OpLabel +)"; + + ss << body; + + ss << R"( +OpReturn +OpFunctionEnd)"; + + return ss.str(); +} + +TEST_F(ValidateOldDebugInfo, UseDebugInstructionOutOfFunction) { + const std::string src = R"( +%code = OpString "main() {}" +)"; + + const std::string dbg_inst = R"( +%cu = OpExtInst %void %DbgExt DebugCompilationUnit %code 1 1 +)"; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "DebugInfo" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo(src, "", dbg_inst, "", + extension, "Vertex")); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateOpenCL100DebugInfo, UseDebugInstructionOutOfFunction) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "main() {}" +)"; + + const std::string dbg_inst = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +)"; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo(src, "", dbg_inst, "", + extension, "Vertex")); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateOpenCL100DebugInfo, DebugSourceInFunction) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "main() {}" +)"; + + const std::string dbg_inst = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +)"; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo(src, "", "", dbg_inst, + extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Debug info extension instructions other than DebugScope, " + "DebugNoScope, DebugDeclare, DebugValue must appear between " + "section 9 (types, constants, global variables) and section 10 " + "(function declarations)")); +} + +TEST_P(ValidateLocalDebugInfoOutOfFunction, OpenCLDebugInfo100DebugScope) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "void main() {}" +%void_name = OpString "void" +%main_name = OpString "main" +%main_linkage_name = OpString "v_main" +%int_name = OpString "int" +%foo_name = OpString "foo" +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +%void_info = OpExtInst %void %DbgExt DebugTypeBasic %void_name %u32_0 Unspecified +%int_info = OpExtInst %void %DbgExt DebugTypeBasic %int_name %u32_0 Signed +%main_type_info = OpExtInst %void %DbgExt DebugTypeFunction FlagIsPublic %void_info %void_info +%main_info = OpExtInst %void %DbgExt DebugFunction %main_name %main_type_info %dbg_src 1 1 %comp_unit %main_linkage_name FlagIsPublic 1 %main +%foo_info = OpExtInst %void %DbgExt DebugLocalVariable %foo_name %int_info %dbg_src 1 1 %main_info FlagIsLocal +%expr = OpExtInst %void %DbgExt DebugExpression +)"; + + const std::string body = R"( +%foo = OpVariable %u32_ptr_function Function +%foo_val = OpLoad %u32 %foo +)"; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, "", dbg_inst_header + GetParam(), body, extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("DebugScope, DebugNoScope, DebugDeclare, DebugValue " + "of debug info extension must appear in a function " + "body")); +} + +INSTANTIATE_TEST_SUITE_P( + AllLocalDebugInfo, ValidateLocalDebugInfoOutOfFunction, + ::testing::ValuesIn(std::vector{ + "%main_scope = OpExtInst %void %DbgExt DebugScope %main_info", + "%no_scope = OpExtInst %void %DbgExt DebugNoScope", + })); + +TEST_F(ValidateOpenCL100DebugInfo, DebugFunctionForwardReference) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "void main() {}" +%void_name = OpString "void" +%main_name = OpString "main" +%main_linkage_name = OpString "v_main" +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +%void_info = OpExtInst %void %DbgExt DebugTypeBasic %void_name %u32_0 Unspecified +%main_type_info = OpExtInst %void %DbgExt DebugTypeFunction FlagIsPublic %void_info %void_info +%main_info = OpExtInst %void %DbgExt DebugFunction %main_name %main_type_info %dbg_src 1 1 %comp_unit %main_linkage_name FlagIsPublic 1 %main +)"; + + const std::string body = R"( +%main_scope = OpExtInst %void %DbgExt DebugScope %main_info +)"; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, "", dbg_inst_header, body, extension, "Vertex")); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateOpenCL100DebugInfo, DebugScopeBeforeOpVariableInFunction) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "float4 main(float arg) { + float foo; + return float4(0, 0, 0, 0); +} +" +%float_name = OpString "float" +%main_name = OpString "main" +%main_linkage_name = OpString "v4f_main_f" +)"; + + const std::string size_const = R"( +%int_32 = OpConstant %u32 32 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float +%v4float_info = OpExtInst %void %DbgExt DebugTypeVector %float_info 4 +%main_type_info = OpExtInst %void %DbgExt DebugTypeFunction FlagIsPublic %v4float_info %float_info +%main_info = OpExtInst %void %DbgExt DebugFunction %main_name %main_type_info %dbg_src 12 1 %comp_unit %main_linkage_name FlagIsPublic 13 %main +)"; + + const std::string body = R"( +%main_scope = OpExtInst %void %DbgExt DebugScope %main_info +%foo = OpVariable %f32_ptr_function Function +)"; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, size_const, dbg_inst_header, body, extension, "Vertex")); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateOpenCL100DebugInfo, DebugTypeCompositeForwardReference) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "struct VS_OUTPUT { + float4 pos : SV_POSITION; + float4 color : COLOR; +}; +main() {} +" +%VS_OUTPUT_name = OpString "struct VS_OUTPUT" +%float_name = OpString "float" +%VS_OUTPUT_pos_name = OpString "pos : SV_POSITION" +%VS_OUTPUT_color_name = OpString "color : COLOR" +%VS_OUTPUT_linkage_name = OpString "VS_OUTPUT" +)"; + + const std::string size_const = R"( +%int_32 = OpConstant %u32 32 +%int_128 = OpConstant %u32 128 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +%VS_OUTPUT_info = OpExtInst %void %DbgExt DebugTypeComposite %VS_OUTPUT_name Structure %dbg_src 1 1 %comp_unit %VS_OUTPUT_linkage_name %int_128 FlagIsPublic %VS_OUTPUT_pos_info %VS_OUTPUT_color_info +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float +%v4float_info = OpExtInst %void %DbgExt DebugTypeVector %float_info 4 +%VS_OUTPUT_pos_info = OpExtInst %void %DbgExt DebugTypeMember %VS_OUTPUT_pos_name %v4float_info %dbg_src 2 3 %VS_OUTPUT_info %u32_0 %int_128 FlagIsPublic +%VS_OUTPUT_color_info = OpExtInst %void %DbgExt DebugTypeMember %VS_OUTPUT_color_name %v4float_info %dbg_src 3 3 %VS_OUTPUT_info %int_128 %int_128 FlagIsPublic +)"; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, size_const, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateOpenCL100DebugInfo, DebugTypeCompositeMissingReference) { + const std::string src = R"( +%src = OpString "simple.hlsl" +%code = OpString "struct VS_OUTPUT { + float4 pos : SV_POSITION; + float4 color : COLOR; +}; +main() {} +" +%VS_OUTPUT_name = OpString "struct VS_OUTPUT" +%float_name = OpString "float" +%VS_OUTPUT_pos_name = OpString "pos : SV_POSITION" +%VS_OUTPUT_color_name = OpString "color : COLOR" +%VS_OUTPUT_linkage_name = OpString "VS_OUTPUT" +)"; + + const std::string size_const = R"( +%int_32 = OpConstant %u32 32 +%int_128 = OpConstant %u32 128 +)"; + + const std::string dbg_inst_header = R"( +%dbg_src = OpExtInst %void %DbgExt DebugSource %src %code +%comp_unit = OpExtInst %void %DbgExt DebugCompilationUnit 2 4 %dbg_src HLSL +%VS_OUTPUT_info = OpExtInst %void %DbgExt DebugTypeComposite %VS_OUTPUT_name Structure %dbg_src 1 1 %comp_unit %VS_OUTPUT_linkage_name %int_128 FlagIsPublic %VS_OUTPUT_pos_info %VS_OUTPUT_color_info +%float_info = OpExtInst %void %DbgExt DebugTypeBasic %float_name %int_32 Float +%v4float_info = OpExtInst %void %DbgExt DebugTypeVector %float_info 4 +%VS_OUTPUT_pos_info = OpExtInst %void %DbgExt DebugTypeMember %VS_OUTPUT_pos_name %v4float_info %dbg_src 2 3 %VS_OUTPUT_info %u32_0 %int_128 FlagIsPublic +)"; + + const std::string extension = R"( +%DbgExt = OpExtInstImport "OpenCL.DebugInfo.100" +)"; + + CompileSuccessfully(GenerateShaderCodeForDebugInfo( + src, size_const, dbg_inst_header, "", extension, "Vertex")); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("forward referenced IDs have not been defined")); +} + TEST_P(ValidateGlslStd450SqrtLike, Success) { const std::string ext_inst_name = GetParam(); std::ostringstream ss; @@ -490,20 +956,20 @@ TEST_P(ValidateGlslStd450SqrtLike, IntOperand) { "Result Type")); } -INSTANTIATE_TEST_CASE_P(AllSqrtLike, ValidateGlslStd450SqrtLike, - ::testing::ValuesIn(std::vector{ - "Round", - "RoundEven", - "FAbs", - "Trunc", - "FSign", - "Floor", - "Ceil", - "Fract", - "Sqrt", - "InverseSqrt", - "Normalize", - }), ); +INSTANTIATE_TEST_SUITE_P(AllSqrtLike, ValidateGlslStd450SqrtLike, + ::testing::ValuesIn(std::vector{ + "Round", + "RoundEven", + "FAbs", + "Trunc", + "FSign", + "Floor", + "Ceil", + "Fract", + "Sqrt", + "InverseSqrt", + "Normalize", + })); TEST_P(ValidateGlslStd450FMinLike, Success) { const std::string ext_inst_name = GetParam(); @@ -557,15 +1023,15 @@ TEST_P(ValidateGlslStd450FMinLike, IntOperand2) { "Result Type")); } -INSTANTIATE_TEST_CASE_P(AllFMinLike, ValidateGlslStd450FMinLike, - ::testing::ValuesIn(std::vector{ - "FMin", - "FMax", - "Step", - "Reflect", - "NMin", - "NMax", - }), ); +INSTANTIATE_TEST_SUITE_P(AllFMinLike, ValidateGlslStd450FMinLike, + ::testing::ValuesIn(std::vector{ + "FMin", + "FMax", + "Step", + "Reflect", + "NMin", + "NMax", + })); TEST_P(ValidateGlslStd450FClampLike, Success) { const std::string ext_inst_name = GetParam(); @@ -632,15 +1098,15 @@ TEST_P(ValidateGlslStd450FClampLike, IntOperand3) { "Result Type")); } -INSTANTIATE_TEST_CASE_P(AllFClampLike, ValidateGlslStd450FClampLike, - ::testing::ValuesIn(std::vector{ - "FClamp", - "FMix", - "SmoothStep", - "Fma", - "FaceForward", - "NClamp", - }), ); +INSTANTIATE_TEST_SUITE_P(AllFClampLike, ValidateGlslStd450FClampLike, + ::testing::ValuesIn(std::vector{ + "FClamp", + "FMix", + "SmoothStep", + "Fma", + "FaceForward", + "NClamp", + })); TEST_P(ValidateGlslStd450SAbsLike, Success) { const std::string ext_inst_name = GetParam(); @@ -713,14 +1179,14 @@ TEST_P(ValidateGlslStd450SAbsLike, WrongBitWidthOperand) { "Result Type")); } -INSTANTIATE_TEST_CASE_P(AllSAbsLike, ValidateGlslStd450SAbsLike, - ::testing::ValuesIn(std::vector{ - "SAbs", - "SSign", - "FindILsb", - "FindUMsb", - "FindSMsb", - }), ); +INSTANTIATE_TEST_SUITE_P(AllSAbsLike, ValidateGlslStd450SAbsLike, + ::testing::ValuesIn(std::vector{ + "SAbs", + "SSign", + "FindILsb", + "FindUMsb", + "FindSMsb", + })); TEST_F(ValidateExtInst, FindUMsbNot32Bit) { const std::string body = R"( @@ -862,13 +1328,13 @@ TEST_P(ValidateGlslStd450UMinLike, WrongBitWidthOperand2) { "Result Type")); } -INSTANTIATE_TEST_CASE_P(AllUMinLike, ValidateGlslStd450UMinLike, - ::testing::ValuesIn(std::vector{ - "UMin", - "SMin", - "UMax", - "SMax", - }), ); +INSTANTIATE_TEST_SUITE_P(AllUMinLike, ValidateGlslStd450UMinLike, + ::testing::ValuesIn(std::vector{ + "UMin", + "SMin", + "UMax", + "SMax", + })); TEST_P(ValidateGlslStd450UClampLike, Success) { const std::string ext_inst_name = GetParam(); @@ -1025,11 +1491,11 @@ TEST_P(ValidateGlslStd450UClampLike, WrongBitWidthOperand3) { "Result Type")); } -INSTANTIATE_TEST_CASE_P(AllUClampLike, ValidateGlslStd450UClampLike, - ::testing::ValuesIn(std::vector{ - "UClamp", - "SClamp", - }), ); +INSTANTIATE_TEST_SUITE_P(AllUClampLike, ValidateGlslStd450UClampLike, + ::testing::ValuesIn(std::vector{ + "UClamp", + "SClamp", + })); TEST_P(ValidateGlslStd450SinLike, Success) { const std::string ext_inst_name = GetParam(); @@ -1080,27 +1546,27 @@ TEST_P(ValidateGlslStd450SinLike, IntOperand) { "Result Type")); } -INSTANTIATE_TEST_CASE_P(AllSinLike, ValidateGlslStd450SinLike, - ::testing::ValuesIn(std::vector{ - "Radians", - "Degrees", - "Sin", - "Cos", - "Tan", - "Asin", - "Acos", - "Atan", - "Sinh", - "Cosh", - "Tanh", - "Asinh", - "Acosh", - "Atanh", - "Exp", - "Exp2", - "Log", - "Log2", - }), ); +INSTANTIATE_TEST_SUITE_P(AllSinLike, ValidateGlslStd450SinLike, + ::testing::ValuesIn(std::vector{ + "Radians", + "Degrees", + "Sin", + "Cos", + "Tan", + "Asin", + "Acos", + "Atan", + "Sinh", + "Cosh", + "Tanh", + "Asinh", + "Acosh", + "Atanh", + "Exp", + "Exp2", + "Log", + "Log2", + })); TEST_P(ValidateGlslStd450PowLike, Success) { const std::string ext_inst_name = GetParam(); @@ -1165,11 +1631,11 @@ TEST_P(ValidateGlslStd450PowLike, IntOperand2) { "Result Type")); } -INSTANTIATE_TEST_CASE_P(AllPowLike, ValidateGlslStd450PowLike, - ::testing::ValuesIn(std::vector{ - "Atan2", - "Pow", - }), ); +INSTANTIATE_TEST_SUITE_P(AllPowLike, ValidateGlslStd450PowLike, + ::testing::ValuesIn(std::vector{ + "Atan2", + "Pow", + })); TEST_F(ValidateExtInst, GlslStd450DeterminantSuccess) { const std::string body = R"( @@ -1792,14 +2258,14 @@ TEST_P(ValidateGlslStd450Pack, VWrongSizeVector) { EXPECT_THAT(getDiagnosticString(), HasSubstr(expected.str())); } -INSTANTIATE_TEST_CASE_P(AllPack, ValidateGlslStd450Pack, - ::testing::ValuesIn(std::vector{ - "PackSnorm4x8", - "PackUnorm4x8", - "PackSnorm2x16", - "PackUnorm2x16", - "PackHalf2x16", - }), ); +INSTANTIATE_TEST_SUITE_P(AllPack, ValidateGlslStd450Pack, + ::testing::ValuesIn(std::vector{ + "PackSnorm4x8", + "PackUnorm4x8", + "PackSnorm2x16", + "PackUnorm2x16", + "PackHalf2x16", + })); TEST_F(ValidateExtInst, PackDouble2x32Success) { const std::string body = R"( @@ -2031,14 +2497,14 @@ TEST_P(ValidateGlslStd450Unpack, ResultPWrongBitWidth) { EXPECT_THAT(getDiagnosticString(), HasSubstr(expected.str())); } -INSTANTIATE_TEST_CASE_P(AllUnpack, ValidateGlslStd450Unpack, - ::testing::ValuesIn(std::vector{ - "UnpackSnorm4x8", - "UnpackUnorm4x8", - "UnpackSnorm2x16", - "UnpackUnorm2x16", - "UnpackHalf2x16", - }), ); +INSTANTIATE_TEST_SUITE_P(AllUnpack, ValidateGlslStd450Unpack, + ::testing::ValuesIn(std::vector{ + "UnpackSnorm4x8", + "UnpackUnorm4x8", + "UnpackSnorm2x16", + "UnpackUnorm2x16", + "UnpackHalf2x16", + })); TEST_F(ValidateExtInst, UnpackDouble2x32Success) { const std::string body = R"( @@ -2828,7 +3294,7 @@ TEST_P(ValidateOpenCLStdSqrtLike, IntOperand) { "Result Type")); } -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( AllSqrtLike, ValidateOpenCLStdSqrtLike, ::testing::ValuesIn(std::vector{ "acos", "acosh", "acospi", "asin", @@ -2848,7 +3314,7 @@ INSTANTIATE_TEST_CASE_P( "native_log", "native_log2", "native_log10", "native_recip", "native_rsqrt", "native_sin", "native_sqrt", "native_tan", "degrees", "radians", "sign", - }), ); + })); TEST_P(ValidateOpenCLStdFMinLike, Success) { const std::string ext_inst_name = GetParam(); @@ -2902,16 +3368,16 @@ TEST_P(ValidateOpenCLStdFMinLike, IntOperand2) { "Result Type")); } -INSTANTIATE_TEST_CASE_P(AllFMinLike, ValidateOpenCLStdFMinLike, - ::testing::ValuesIn(std::vector{ - "atan2", "atan2pi", "copysign", - "fdim", "fmax", "fmin", - "fmod", "maxmag", "minmag", - "hypot", "nextafter", "pow", - "powr", "remainder", "half_divide", - "half_powr", "native_divide", "native_powr", - "step", "fmax_common", "fmin_common", - }), ); +INSTANTIATE_TEST_SUITE_P(AllFMinLike, ValidateOpenCLStdFMinLike, + ::testing::ValuesIn(std::vector{ + "atan2", "atan2pi", "copysign", + "fdim", "fmax", "fmin", + "fmod", "maxmag", "minmag", + "hypot", "nextafter", "pow", + "powr", "remainder", "half_divide", + "half_powr", "native_divide", "native_powr", + "step", "fmax_common", "fmin_common", + })); TEST_P(ValidateOpenCLStdFClampLike, Success) { const std::string ext_inst_name = GetParam(); @@ -2978,14 +3444,14 @@ TEST_P(ValidateOpenCLStdFClampLike, IntOperand3) { "Result Type")); } -INSTANTIATE_TEST_CASE_P(AllFClampLike, ValidateOpenCLStdFClampLike, - ::testing::ValuesIn(std::vector{ - "fma", - "mad", - "fclamp", - "mix", - "smoothstep", - }), ); +INSTANTIATE_TEST_SUITE_P(AllFClampLike, ValidateOpenCLStdFClampLike, + ::testing::ValuesIn(std::vector{ + "fma", + "mad", + "fclamp", + "mix", + "smoothstep", + })); TEST_P(ValidateOpenCLStdSAbsLike, Success) { const std::string ext_inst_name = GetParam(); @@ -3045,14 +3511,14 @@ TEST_P(ValidateOpenCLStdSAbsLike, U64Operand) { ": expected types of all operands to be equal to Result Type")); } -INSTANTIATE_TEST_CASE_P(AllSAbsLike, ValidateOpenCLStdSAbsLike, - ::testing::ValuesIn(std::vector{ - "s_abs", - "clz", - "ctz", - "popcount", - "u_abs", - }), ); +INSTANTIATE_TEST_SUITE_P(AllSAbsLike, ValidateOpenCLStdSAbsLike, + ::testing::ValuesIn(std::vector{ + "s_abs", + "clz", + "ctz", + "popcount", + "u_abs", + })); TEST_P(ValidateOpenCLStdUMinLike, Success) { const std::string ext_inst_name = GetParam(); @@ -3144,26 +3610,26 @@ TEST_P(ValidateOpenCLStdUMinLike, U64Operand2) { ": expected types of all operands to be equal to Result Type")); } -INSTANTIATE_TEST_CASE_P(AllUMinLike, ValidateOpenCLStdUMinLike, - ::testing::ValuesIn(std::vector{ - "s_max", - "u_max", - "s_min", - "u_min", - "s_abs_diff", - "s_add_sat", - "u_add_sat", - "s_mul_hi", - "rotate", - "s_sub_sat", - "u_sub_sat", - "s_hadd", - "u_hadd", - "s_rhadd", - "u_rhadd", - "u_abs_diff", - "u_mul_hi", - }), ); +INSTANTIATE_TEST_SUITE_P(AllUMinLike, ValidateOpenCLStdUMinLike, + ::testing::ValuesIn(std::vector{ + "s_max", + "u_max", + "s_min", + "u_min", + "s_abs_diff", + "s_add_sat", + "u_add_sat", + "s_mul_hi", + "rotate", + "s_sub_sat", + "u_sub_sat", + "s_hadd", + "u_hadd", + "s_rhadd", + "u_rhadd", + "u_abs_diff", + "u_mul_hi", + })); TEST_P(ValidateOpenCLStdUClampLike, Success) { const std::string ext_inst_name = GetParam(); @@ -3281,15 +3747,15 @@ TEST_P(ValidateOpenCLStdUClampLike, U64Operand3) { ": expected types of all operands to be equal to Result Type")); } -INSTANTIATE_TEST_CASE_P(AllUClampLike, ValidateOpenCLStdUClampLike, - ::testing::ValuesIn(std::vector{ - "s_clamp", - "u_clamp", - "s_mad_hi", - "u_mad_sat", - "s_mad_sat", - "u_mad_hi", - }), ); +INSTANTIATE_TEST_SUITE_P(AllUClampLike, ValidateOpenCLStdUClampLike, + ::testing::ValuesIn(std::vector{ + "s_clamp", + "u_clamp", + "s_mad_hi", + "u_mad_sat", + "s_mad_sat", + "u_mad_hi", + })); // ------------------------------------------------------------- TEST_P(ValidateOpenCLStdUMul24Like, Success) { @@ -3332,7 +3798,7 @@ TEST_P(ValidateOpenCLStdUMul24Like, FloatResultType) { TEST_P(ValidateOpenCLStdUMul24Like, U64ResultType) { const std::string ext_inst_name = GetParam(); const std::string body = - "%val1 = OpExtInst %u64 %extinst " + ext_inst_name + " %u64_0 %u64\n"; + "%val1 = OpExtInst %u64 %extinst " + ext_inst_name + " %u64_0 %u64_0\n"; CompileSuccessfully(GenerateKernelCode(body)); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); @@ -3395,11 +3861,11 @@ TEST_P(ValidateOpenCLStdUMul24Like, U64Operand2) { ": expected types of all operands to be equal to Result Type")); } -INSTANTIATE_TEST_CASE_P(AllUMul24Like, ValidateOpenCLStdUMul24Like, - ::testing::ValuesIn(std::vector{ - "s_mul24", - "u_mul24", - }), ); +INSTANTIATE_TEST_SUITE_P(AllUMul24Like, ValidateOpenCLStdUMul24Like, + ::testing::ValuesIn(std::vector{ + "s_mul24", + "u_mul24", + })); TEST_P(ValidateOpenCLStdUMad24Like, Success) { const std::string ext_inst_name = GetParam(); @@ -3530,11 +3996,11 @@ TEST_P(ValidateOpenCLStdUMad24Like, U64Operand3) { ": expected types of all operands to be equal to Result Type")); } -INSTANTIATE_TEST_CASE_P(AllUMad24Like, ValidateOpenCLStdUMad24Like, - ::testing::ValuesIn(std::vector{ - "s_mad24", - "u_mad24", - }), ); +INSTANTIATE_TEST_SUITE_P(AllUMad24Like, ValidateOpenCLStdUMad24Like, + ::testing::ValuesIn(std::vector{ + "s_mad24", + "u_mad24", + })); TEST_F(ValidateExtInst, OpenCLStdCrossSuccess) { const std::string body = R"( @@ -3659,11 +4125,11 @@ TEST_P(ValidateOpenCLStdLengthLike, DifferentType) { "Result Type")); } -INSTANTIATE_TEST_CASE_P(AllLengthLike, ValidateOpenCLStdLengthLike, - ::testing::ValuesIn(std::vector{ - "length", - "fast_length", - }), ); +INSTANTIATE_TEST_SUITE_P(AllLengthLike, ValidateOpenCLStdLengthLike, + ::testing::ValuesIn(std::vector{ + "length", + "fast_length", + })); TEST_P(ValidateOpenCLStdDistanceLike, Success) { const std::string ext_inst_name = GetParam(); @@ -3748,11 +4214,11 @@ TEST_P(ValidateOpenCLStdDistanceLike, DifferentOperands) { "expected operands P0 and P1 to be of the same type")); } -INSTANTIATE_TEST_CASE_P(AllDistanceLike, ValidateOpenCLStdDistanceLike, - ::testing::ValuesIn(std::vector{ - "distance", - "fast_distance", - }), ); +INSTANTIATE_TEST_SUITE_P(AllDistanceLike, ValidateOpenCLStdDistanceLike, + ::testing::ValuesIn(std::vector{ + "distance", + "fast_distance", + })); TEST_P(ValidateOpenCLStdNormalizeLike, Success) { const std::string ext_inst_name = GetParam(); @@ -3808,11 +4274,11 @@ TEST_P(ValidateOpenCLStdNormalizeLike, DifferentType) { "expected operand P type to be equal to Result Type")); } -INSTANTIATE_TEST_CASE_P(AllNormalizeLike, ValidateOpenCLStdNormalizeLike, - ::testing::ValuesIn(std::vector{ - "normalize", - "fast_normalize", - }), ); +INSTANTIATE_TEST_SUITE_P(AllNormalizeLike, ValidateOpenCLStdNormalizeLike, + ::testing::ValuesIn(std::vector{ + "normalize", + "fast_normalize", + })); TEST_F(ValidateExtInst, OpenCLStdBitselectSuccess) { const std::string body = R"( @@ -4130,10 +4596,9 @@ TEST_P(ValidateOpenCLStdVStoreHalfLike, PNotPointer) { } CompileSuccessfully(GenerateKernelCode(ss.str())); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpenCL.std " + ext_inst_name + - ": expected operand P to be a pointer")); + HasSubstr("Operand 89[%_ptr_Workgroup_half] cannot be a type")); } TEST_P(ValidateOpenCLStdVStoreHalfLike, ConstPointer) { @@ -4206,15 +4671,15 @@ TEST_P(ValidateOpenCLStdVStoreHalfLike, PDataTypeFloat32) { ": expected operand P data type to be 16-bit float scalar")); } -INSTANTIATE_TEST_CASE_P(AllVStoreHalfLike, ValidateOpenCLStdVStoreHalfLike, - ::testing::ValuesIn(std::vector{ - "vstore_half", - "vstore_half_r", - "vstore_halfn", - "vstore_halfn_r", - "vstorea_halfn", - "vstorea_halfn_r", - }), ); +INSTANTIATE_TEST_SUITE_P(AllVStoreHalfLike, ValidateOpenCLStdVStoreHalfLike, + ::testing::ValuesIn(std::vector{ + "vstore_half", + "vstore_half_r", + "vstore_halfn", + "vstore_halfn_r", + "vstorea_halfn", + "vstorea_halfn_r", + })); TEST_P(ValidateOpenCLStdVLoadHalfLike, SuccessPhysical32) { const std::string ext_inst_name = GetParam(); @@ -4303,10 +4768,9 @@ TEST_P(ValidateOpenCLStdVLoadHalfLike, PNotPointer) { << " %u32_1 %f16_ptr_workgroup 2\n"; CompileSuccessfully(GenerateKernelCode(ss.str())); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpenCL.std " + ext_inst_name + - ": expected operand P to be a pointer")); + HasSubstr("Operand 89[%_ptr_Workgroup_half] cannot be a type")); } TEST_P(ValidateOpenCLStdVLoadHalfLike, OffsetWrongStorageType) { @@ -4374,11 +4838,11 @@ TEST_P(ValidateOpenCLStdVLoadHalfLike, WrongN) { "components of Result Type")); } -INSTANTIATE_TEST_CASE_P(AllVLoadHalfLike, ValidateOpenCLStdVLoadHalfLike, - ::testing::ValuesIn(std::vector{ - "vload_halfn", - "vloada_halfn", - }), ); +INSTANTIATE_TEST_SUITE_P(AllVLoadHalfLike, ValidateOpenCLStdVLoadHalfLike, + ::testing::ValuesIn(std::vector{ + "vload_halfn", + "vloada_halfn", + })); TEST_F(ValidateExtInst, VLoadNSuccessFloatPhysical32) { std::ostringstream ss; @@ -4476,22 +4940,23 @@ TEST_F(ValidateExtInst, VLoadNPNotPointer) { "%f32_ptr_uniform_constant 2\n"; CompileSuccessfully(GenerateKernelCode(ss.str())); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr("OpenCL.std vloadn: expected operand P to be a pointer")); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Operand 120[%_ptr_UniformConstant_float] cannot be a " + "type")); } TEST_F(ValidateExtInst, VLoadNWrongStorageClass) { std::ostringstream ss; - ss << "%ptr = OpAccessChain %u32_ptr_workgroup %u32vec8_workgroup %u32_1\n"; + ss << "%ptr = OpAccessChain %u32_ptr_input %u32vec8_input %u32_1\n"; ss << "%val1 = OpExtInst %u32vec2 %extinst vloadn %u32_1 %ptr 2\n"; CompileSuccessfully(GenerateKernelCode(ss.str())); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("OpenCL.std vloadn: expected operand P storage class " - "to be UniformConstant or Generic")); + "to be UniformConstant, Generic, CrossWorkgroup, " + "Workgroup or Function")); } TEST_F(ValidateExtInst, VLoadNWrongComponentType) { @@ -4589,10 +5054,10 @@ TEST_F(ValidateExtInst, VLoadHalfPNotPointer) { "%f16_ptr_uniform_constant\n"; CompileSuccessfully(GenerateKernelCode(ss.str())); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr("OpenCL.std vload_half: expected operand P to be a pointer")); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Operand 114[%_ptr_UniformConstant_half] cannot be a " + "type")); } TEST_F(ValidateExtInst, VLoadHalfWrongStorageClass) { @@ -4743,22 +5208,23 @@ TEST_F(ValidateExtInst, VStoreNPNotPointer) { "%f32_ptr_generic\n"; CompileSuccessfully(GenerateKernelCode(ss.str())); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr("OpenCL.std vstoren: expected operand P to be a pointer")); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Operand 127[%_ptr_Generic_float] cannot be a type")); } -TEST_F(ValidateExtInst, VStoreNPNotGeneric) { +TEST_F(ValidateExtInst, VStoreNWrongStorageClass) { std::ostringstream ss; - ss << "%ptr_w = OpAccessChain %f32_ptr_workgroup %f32vec8_workgroup %u32_1\n"; + ss << "%ptr_w = OpAccessChain %f32_ptr_uniform_constant " + "%f32vec8_uniform_constant %u32_1\n"; ss << "%val1 = OpExtInst %void %extinst vstoren %f32vec2_01 %u32_1 %ptr_w\n"; CompileSuccessfully(GenerateKernelCode(ss.str())); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpenCL.std vstoren: expected operand P storage class " - "to be Generic")); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("OpenCL.std vstoren: expected operand P storage class " + "to be Generic, CrossWorkgroup, Workgroup or Function")); } TEST_F(ValidateExtInst, VStorePWrongDataType) { @@ -5058,10 +5524,10 @@ TEST_F(ValidateExtInst, OpenCLStdPrintfFormatNotPointer) { )"; CompileSuccessfully(GenerateKernelCode(body)); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr("OpenCL.std printf: expected operand Format to be a pointer")); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Operand 137[%_ptr_UniformConstant_uchar] cannot be a " + "type")); } TEST_F(ValidateExtInst, OpenCLStdPrintfFormatNotUniformConstStorageClass) { @@ -5151,10 +5617,10 @@ TEST_F(ValidateExtInst, OpenCLStdPrefetchPtrNotPointer) { )"; CompileSuccessfully(GenerateKernelCode(body)); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr("OpenCL.std prefetch: expected operand Ptr to be a pointer")); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Operand 99[%_ptr_CrossWorkgroup_uint] cannot be a " + "type")); } TEST_F(ValidateExtInst, OpenCLStdPrefetchPtrNotCrossWorkgroup) { @@ -5299,19 +5765,19 @@ TEST_P(ValidateOpenCLStdFractLike, PointerWrongDataType) { ": expected data type of the pointer to be equal to Result Type")); } -INSTANTIATE_TEST_CASE_P(AllFractLike, ValidateOpenCLStdFractLike, - ::testing::ValuesIn(std::vector{ - "fract", - "modf", - "sincos", - }), ); +INSTANTIATE_TEST_SUITE_P(AllFractLike, ValidateOpenCLStdFractLike, + ::testing::ValuesIn(std::vector{ + "fract", + "modf", + "sincos", + })); TEST_F(ValidateExtInst, OpenCLStdRemquoSuccess) { const std::string body = R"( -%var_f32 = OpVariable %f32_ptr_function Function -%var_f32vec2 = OpVariable %f32vec2_ptr_function Function -%val1 = OpExtInst %f32 %extinst remquo %f32_3 %f32_2 %var_f32 -%val2 = OpExtInst %f32vec2 %extinst remquo %f32vec2_01 %f32vec2_12 %var_f32vec2 +%var_u32 = OpVariable %u32_ptr_function Function +%var_u32vec2 = OpVariable %u32vec2_ptr_function Function +%val1 = OpExtInst %f32 %extinst remquo %f32_3 %f32_2 %var_u32 +%val2 = OpExtInst %f32vec2 %extinst remquo %f32vec2_01 %f32vec2_12 %var_u32vec2 )"; CompileSuccessfully(GenerateKernelCode(body)); @@ -5320,8 +5786,8 @@ TEST_F(ValidateExtInst, OpenCLStdRemquoSuccess) { TEST_F(ValidateExtInst, OpenCLStdRemquoIntResultType) { const std::string body = R"( -%var_f32 = OpVariable %f32_ptr_function Function -%val1 = OpExtInst %u32 %extinst remquo %f32_3 %f32_2 %var_f32 +%var_u32 = OpVariable %u32_ptr_function Function +%val1 = OpExtInst %u32 %extinst remquo %f32_3 %f32_2 %var_u32 )"; CompileSuccessfully(GenerateKernelCode(body)); @@ -5334,8 +5800,8 @@ TEST_F(ValidateExtInst, OpenCLStdRemquoIntResultType) { TEST_F(ValidateExtInst, OpenCLStdRemquoXWrongType) { const std::string body = R"( -%var_f32 = OpVariable %f32_ptr_function Function -%val1 = OpExtInst %f32 %extinst remquo %u32_3 %f32_2 %var_f32 +%var_u32 = OpVariable %f32_ptr_function Function +%val1 = OpExtInst %f32 %extinst remquo %u32_3 %f32_2 %var_u32 )"; CompileSuccessfully(GenerateKernelCode(body)); @@ -5348,8 +5814,8 @@ TEST_F(ValidateExtInst, OpenCLStdRemquoXWrongType) { TEST_F(ValidateExtInst, OpenCLStdRemquoYWrongType) { const std::string body = R"( -%var_f32 = OpVariable %f32_ptr_function Function -%val1 = OpExtInst %f32 %extinst remquo %f32_3 %u32_2 %var_f32 +%var_u32 = OpVariable %f32_ptr_function Function +%val1 = OpExtInst %f32 %extinst remquo %f32_3 %u32_2 %var_u32 )"; CompileSuccessfully(GenerateKernelCode(body)); @@ -5388,17 +5854,44 @@ TEST_F(ValidateExtInst, OpenCLStdRemquoPointerWrongStorageClass) { TEST_F(ValidateExtInst, OpenCLStdRemquoPointerWrongDataType) { const std::string body = R"( -%var_u32 = OpVariable %u32_ptr_function Function -%val1 = OpExtInst %f32 %extinst remquo %f32_3 %f32_2 %var_u32 +%var_f32 = OpVariable %f32_ptr_function Function +%val1 = OpExtInst %f32 %extinst remquo %f32_3 %f32_2 %var_f32 +)"; + + CompileSuccessfully(GenerateKernelCode(body)); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("OpenCL.std remquo: " + "expected data type of the pointer to be a 32-bit int " + "scalar or vector type")); +} + +TEST_F(ValidateExtInst, OpenCLStdRemquoPointerWrongDataTypeWidth) { + const std::string body = R"( +%var_u64 = OpVariable %u64_ptr_function Function +%val1 = OpExtInst %f32 %extinst remquo %f32_3 %f32_2 %var_u64 +)"; + CompileSuccessfully(GenerateKernelCode(body)); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("OpenCL.std remquo: " + "expected data type of the pointer to be a 32-bit int " + "scalar or vector type")); +} + +TEST_F(ValidateExtInst, OpenCLStdRemquoPointerWrongNumberOfComponents) { + const std::string body = R"( +%var_u32vec2 = OpVariable %u32vec2_ptr_function Function +%val1 = OpExtInst %f32 %extinst remquo %f32_3 %f32_2 %var_u32vec2 )"; CompileSuccessfully(GenerateKernelCode(body)); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), - HasSubstr( - "OpenCL.std remquo: " - "expected data type of the pointer to be equal to Result Type")); + HasSubstr("OpenCL.std remquo: " + "expected data type of the pointer to have the same number " + "of components as Result Type")); } TEST_P(ValidateOpenCLStdFrexpLike, Success) { @@ -5518,11 +6011,11 @@ TEST_P(ValidateOpenCLStdFrexpLike, PointerDataTypeDiffSize) { "number of components as Result Type")); } -INSTANTIATE_TEST_CASE_P(AllFrexpLike, ValidateOpenCLStdFrexpLike, - ::testing::ValuesIn(std::vector{ - "frexp", - "lgamma_r", - }), ); +INSTANTIATE_TEST_SUITE_P(AllFrexpLike, ValidateOpenCLStdFrexpLike, + ::testing::ValuesIn(std::vector{ + "frexp", + "lgamma_r", + })); TEST_F(ValidateExtInst, OpenCLStdIlogbSuccess) { const std::string body = R"( @@ -5716,12 +6209,12 @@ TEST_P(ValidateOpenCLStdLdexpLike, ExponentWrongSize) { "components as Result Type")); } -INSTANTIATE_TEST_CASE_P(AllLdexpLike, ValidateOpenCLStdLdexpLike, - ::testing::ValuesIn(std::vector{ - "ldexp", - "pown", - "rootn", - }), ); +INSTANTIATE_TEST_SUITE_P(AllLdexpLike, ValidateOpenCLStdLdexpLike, + ::testing::ValuesIn(std::vector{ + "ldexp", + "pown", + "rootn", + })); TEST_P(ValidateOpenCLStdUpsampleLike, Success) { const std::string ext_inst_name = GetParam(); @@ -5808,11 +6301,11 @@ TEST_P(ValidateOpenCLStdUpsampleLike, HiLoWrongBitWidth) { "be half of the bit width of components of Result Type")); } -INSTANTIATE_TEST_CASE_P(AllUpsampleLike, ValidateOpenCLStdUpsampleLike, - ::testing::ValuesIn(std::vector{ - "u_upsample", - "s_upsample", - }), ); +INSTANTIATE_TEST_SUITE_P(AllUpsampleLike, ValidateOpenCLStdUpsampleLike, + ::testing::ValuesIn(std::vector{ + "u_upsample", + "s_upsample", + })); } // namespace } // namespace val diff --git a/third_party/spirv-tools/test/val/val_extensions_test.cpp b/third_party/spirv-tools/test/val/val_extensions_test.cpp index b185c3ca7e..682c321436 100644 --- a/third_party/spirv-tools/test/val/val_extensions_test.cpp +++ b/third_party/spirv-tools/test/val/val_extensions_test.cpp @@ -43,7 +43,7 @@ std::string GetErrorString(const std::string& extension) { return "Found unrecognized extension " + extension; } -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( ExpectSuccess, ValidateKnownExtensions, Values( // Match the order as published on the SPIR-V Registry. @@ -64,9 +64,9 @@ INSTANTIATE_TEST_CASE_P( "SPV_GOOGLE_decorate_string", "SPV_GOOGLE_hlsl_functionality1", "SPV_NV_shader_subgroup_partitioned", "SPV_EXT_descriptor_indexing")); -INSTANTIATE_TEST_CASE_P(FailSilently, ValidateUnknownExtensions, - Values("ERROR_unknown_extension", "SPV_KHR_", - "SPV_KHR_shader_ballot_ERROR")); +INSTANTIATE_TEST_SUITE_P(FailSilently, ValidateUnknownExtensions, + Values("ERROR_unknown_extension", "SPV_KHR_", + "SPV_KHR_shader_ballot_ERROR")); TEST_P(ValidateKnownExtensions, ExpectSuccess) { const std::string extension = GetParam(); @@ -88,6 +88,29 @@ TEST_P(ValidateUnknownExtensions, FailSilently) { EXPECT_THAT(getDiagnosticString(), HasSubstr(GetErrorString(extension))); } +TEST_F(ValidateUnknownExtensions, HitMaxNumOfWarnings) { + const std::string str = + std::string("OpCapability Shader\n") + "OpCapability Linkage\n" + + "OpExtension \"bad_ext\"\n" + "OpExtension \"bad_ext\"\n" + + "OpExtension \"bad_ext\"\n" + "OpExtension \"bad_ext\"\n" + + "OpExtension \"bad_ext\"\n" + "OpExtension \"bad_ext\"\n" + + "OpExtension \"bad_ext\"\n" + "OpExtension \"bad_ext\"\n" + + "OpExtension \"bad_ext\"\n" + "OpExtension \"bad_ext\"\n" + + "OpExtension \"bad_ext\"\n" + "OpExtension \"bad_ext\"\n" + + "OpExtension \"bad_ext\"\n" + "OpExtension \"bad_ext\"\n" + + "OpExtension \"bad_ext\"\n" + "OpExtension \"bad_ext\"\n" + + "OpExtension \"bad_ext\"\n" + "OpExtension \"bad_ext\"\n" + + "OpExtension \"bad_ext\"\n" + "OpExtension \"bad_ext\"\n" + + "OpExtension \"bad_ext\"\n" + "OpExtension \"bad_ext\"\n" + + "OpExtension \"bad_ext\"\n" + "OpExtension \"bad_ext\"\n" + + "OpExtension \"bad_ext\"\n" + "OpExtension \"bad_ext\"\n" + + "OpMemoryModel Logical GLSL450"; + CompileSuccessfully(str.c_str()); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Other warnings have been suppressed.")); +} + TEST_F(ValidateExtensionCapabilities, DeclCapabilitySuccess) { const std::string str = "OpCapability Shader\nOpCapability Linkage\nOpCapability DeviceGroup\n" @@ -204,8 +227,8 @@ TEST_P(ValidateAMDShaderBallotCapabilities, ExpectSuccess) { EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()) << getDiagnosticString(); } -INSTANTIATE_TEST_CASE_P(ExpectSuccess, ValidateAMDShaderBallotCapabilities, - ValuesIn(AMDShaderBallotGroupInstructions())); +INSTANTIATE_TEST_SUITE_P(ExpectSuccess, ValidateAMDShaderBallotCapabilities, + ValuesIn(AMDShaderBallotGroupInstructions())); TEST_P(ValidateAMDShaderBallotCapabilities, ExpectFailure) { // Fail because the module does not specify the SPV_AMD_shader_ballot @@ -228,8 +251,8 @@ TEST_P(ValidateAMDShaderBallotCapabilities, ExpectFailure) { " requires one of these capabilities: Groups"))); } -INSTANTIATE_TEST_CASE_P(ExpectFailure, ValidateAMDShaderBallotCapabilities, - ValuesIn(AMDShaderBallotGroupInstructions())); +INSTANTIATE_TEST_SUITE_P(ExpectFailure, ValidateAMDShaderBallotCapabilities, + ValuesIn(AMDShaderBallotGroupInstructions())); struct ExtIntoCoreCase { const char* ext; @@ -265,9 +288,12 @@ TEST_P(ValidateExtIntoCore, DoNotAskForExtensionInLaterVersion) { CompileSuccessfully(code.c_str(), GetParam().env); if (GetParam().success) { - ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(GetParam().env)); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(GetParam().env)) + << getDiagnosticString(); } else { - ASSERT_NE(SPV_SUCCESS, ValidateInstructions(GetParam().env)); + ASSERT_NE(SPV_SUCCESS, ValidateInstructions(GetParam().env)) + << " in " << spvTargetEnvDescription(GetParam().env) << ":\n" + << code; const std::string message = getDiagnosticString(); if (spvIsVulkanEnv(GetParam().env)) { EXPECT_THAT(message, HasSubstr(std::string(GetParam().cap) + @@ -282,7 +308,7 @@ TEST_P(ValidateExtIntoCore, DoNotAskForExtensionInLaterVersion) { } // clang-format off -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( KHR_extensions, ValidateExtIntoCore, ValuesIn(std::vector{ // SPV_KHR_shader_draw_parameters became core SPIR-V 1.3 diff --git a/third_party/spirv-tools/test/val/val_fixtures.h b/third_party/spirv-tools/test/val/val_fixtures.h index 73a0cc6246..5635c7813f 100644 --- a/third_party/spirv-tools/test/val/val_fixtures.h +++ b/third_party/spirv-tools/test/val/val_fixtures.h @@ -21,6 +21,7 @@ #include #include "source/val/validation_state.h" +#include "spirv-tools/libspirv.h" #include "test/test_fixture.h" #include "test/unit_spirv.h" @@ -37,6 +38,11 @@ class ValidateBase : public ::testing::Test, // Returns the a spv_const_binary struct spv_const_binary get_const_binary(); + // Assembles the given SPIR-V text, checks that it fails to assemble, + // and returns resulting diagnostic. No internal state is updated. + std::string CompileFailure(std::string code, + spv_target_env env = SPV_ENV_UNIVERSAL_1_0); + // Checks that 'code' is valid SPIR-V text representation and stores the // binary version for further method calls. void CompileSuccessfully(std::string code, @@ -56,6 +62,18 @@ class ValidateBase : public ::testing::Test, spv_result_t ValidateAndRetrieveValidationState( spv_target_env env = SPV_ENV_UNIVERSAL_1_0); + // Destroys the stored binary. + void DestroyBinary() { + spvBinaryDestroy(binary_); + binary_ = nullptr; + } + + // Destroys the stored diagnostic. + void DestroyDiagnostic() { + spvDiagnosticDestroy(diagnostic_); + diagnostic_ = nullptr; + } + std::string getDiagnosticString(); spv_position_t getErrorPosition(); spv_validator_options getValidatorOptions(); @@ -67,7 +85,7 @@ class ValidateBase : public ::testing::Test, }; template -ValidateBase::ValidateBase() : binary_(), diagnostic_() { +ValidateBase::ValidateBase() : binary_(nullptr), diagnostic_(nullptr) { // Initialize to default command line options. Different tests can then // specialize specific options as necessary. options_ = spvValidatorOptionsCreate(); @@ -83,21 +101,37 @@ void ValidateBase::TearDown() { if (diagnostic_) { spvDiagnosticPrint(diagnostic_); } - spvDiagnosticDestroy(diagnostic_); - spvBinaryDestroy(binary_); + DestroyBinary(); + DestroyDiagnostic(); spvValidatorOptionsDestroy(options_); } +template +std::string ValidateBase::CompileFailure(std::string code, + spv_target_env env) { + spv_diagnostic diagnostic = nullptr; + EXPECT_NE(SPV_SUCCESS, + spvTextToBinary(ScopedContext(env).context, code.c_str(), + code.size(), &binary_, &diagnostic)); + std::string result(diagnostic->error); + spvDiagnosticDestroy(diagnostic); + return result; +} + template void ValidateBase::CompileSuccessfully(std::string code, spv_target_env env) { + DestroyBinary(); spv_diagnostic diagnostic = nullptr; - ASSERT_EQ(SPV_SUCCESS, - spvTextToBinary(ScopedContext(env).context, code.c_str(), - code.size(), &binary_, &diagnostic)) + ScopedContext context(env); + auto status = spvTextToBinary(context.context, code.c_str(), code.size(), + &binary_, &diagnostic); + EXPECT_EQ(SPV_SUCCESS, status) << "ERROR: " << diagnostic->error << "\nSPIR-V could not be compiled into binary:\n" << code; + ASSERT_EQ(SPV_SUCCESS, status); + spvDiagnosticDestroy(diagnostic); } template @@ -110,6 +144,14 @@ void ValidateBase::OverwriteAssembledBinary(uint32_t index, uint32_t word) { template spv_result_t ValidateBase::ValidateInstructions(spv_target_env env) { + DestroyDiagnostic(); + if (binary_ == nullptr) { + fprintf(stderr, + "ERROR: Attempting to validate a null binary, did you forget to " + "call CompileSuccessfully?"); + fflush(stderr); + } + assert(binary_ != nullptr); return spvValidateWithOptions(ScopedContext(env).context, options_, get_const_binary(), &diagnostic_); } @@ -117,6 +159,7 @@ spv_result_t ValidateBase::ValidateInstructions(spv_target_env env) { template spv_result_t ValidateBase::ValidateAndRetrieveValidationState( spv_target_env env) { + DestroyDiagnostic(); return spvtools::val::ValidateBinaryAndKeepValidationState( ScopedContext(env).context, options_, get_const_binary()->code, get_const_binary()->wordCount, &diagnostic_, &vstate_); diff --git a/third_party/spirv-tools/test/val/val_function_test.cpp b/third_party/spirv-tools/test/val/val_function_test.cpp new file mode 100644 index 0000000000..af0199a60d --- /dev/null +++ b/third_party/spirv-tools/test/val/val_function_test.cpp @@ -0,0 +1,843 @@ +// Copyright (c) 2019 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 +#include +#include + +#include "gmock/gmock.h" +#include "test/test_fixture.h" +#include "test/unit_spirv.h" +#include "test/val/val_fixtures.h" + +namespace spvtools { +namespace val { +namespace { + +using ::testing::Combine; +using ::testing::HasSubstr; +using ::testing::Values; + +using ValidateFunctionCall = spvtest::ValidateBase; + +std::string GenerateShader(const std::string& storage_class, + const std::string& capabilities, + const std::string& extensions) { + std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability AtomicStorage +)" + capabilities + R"( +OpExtension "SPV_KHR_storage_buffer_storage_class" +)" + + extensions + R"( +OpMemoryModel Logical GLSL450 +OpName %var "var" +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%ptr = OpTypePointer )" + storage_class + R"( %int +%caller_ty = OpTypeFunction %void +%callee_ty = OpTypeFunction %void %ptr +)"; + + if (storage_class != "Function") { + spirv += "%var = OpVariable %ptr " + storage_class; + } + + spirv += R"( +%caller = OpFunction %void None %caller_ty +%1 = OpLabel +)"; + + if (storage_class == "Function") { + spirv += "%var = OpVariable %ptr Function"; + } + + spirv += R"( +%call = OpFunctionCall %void %callee %var +OpReturn +OpFunctionEnd +%callee = OpFunction %void None %callee_ty +%param = OpFunctionParameter %ptr +%2 = OpLabel +OpReturn +OpFunctionEnd +)"; + + return spirv; +} + +std::string GenerateShaderParameter(const std::string& storage_class, + const std::string& capabilities, + const std::string& extensions) { + std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability AtomicStorage +)" + capabilities + R"( +OpExtension "SPV_KHR_storage_buffer_storage_class" +)" + + extensions + R"( +OpMemoryModel Logical GLSL450 +OpName %p "p" +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%ptr = OpTypePointer )" + storage_class + R"( %int +%func_ty = OpTypeFunction %void %ptr +%caller = OpFunction %void None %func_ty +%p = OpFunctionParameter %ptr +%1 = OpLabel +%call = OpFunctionCall %void %callee %p +OpReturn +OpFunctionEnd +%callee = OpFunction %void None %func_ty +%param = OpFunctionParameter %ptr +%2 = OpLabel +OpReturn +OpFunctionEnd +)"; + + return spirv; +} + +std::string GenerateShaderAccessChain(const std::string& storage_class, + const std::string& capabilities, + const std::string& extensions) { + std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability AtomicStorage +)" + capabilities + R"( +OpExtension "SPV_KHR_storage_buffer_storage_class" +)" + + extensions + R"( +OpMemoryModel Logical GLSL450 +OpName %var "var" +OpName %gep "gep" +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int2 = OpTypeVector %int 2 +%int_0 = OpConstant %int 0 +%ptr = OpTypePointer )" + storage_class + R"( %int2 +%ptr2 = OpTypePointer )" + + storage_class + R"( %int +%caller_ty = OpTypeFunction %void +%callee_ty = OpTypeFunction %void %ptr2 +)"; + + if (storage_class != "Function") { + spirv += "%var = OpVariable %ptr " + storage_class; + } + + spirv += R"( +%caller = OpFunction %void None %caller_ty +%1 = OpLabel +)"; + + if (storage_class == "Function") { + spirv += "%var = OpVariable %ptr Function"; + } + + spirv += R"( +%gep = OpAccessChain %ptr2 %var %int_0 +%call = OpFunctionCall %void %callee %gep +OpReturn +OpFunctionEnd +%callee = OpFunction %void None %callee_ty +%param = OpFunctionParameter %ptr2 +%2 = OpLabel +OpReturn +OpFunctionEnd +)"; + + return spirv; +} + +TEST_P(ValidateFunctionCall, VariableNoVariablePointers) { + const std::string storage_class = GetParam(); + + std::string spirv = GenerateShader(storage_class, "", ""); + + const std::vector valid_storage_classes = { + "UniformConstant", "Function", "Private", "Workgroup", "AtomicCounter"}; + bool valid = + std::find(valid_storage_classes.begin(), valid_storage_classes.end(), + storage_class) != valid_storage_classes.end(); + + CompileSuccessfully(spirv); + if (valid) { + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); + } else { + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + if (storage_class == "StorageBuffer") { + EXPECT_THAT(getDiagnosticString(), + HasSubstr("StorageBuffer pointer operand 1[%var] requires a " + "variable pointers capability")); + } else { + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Invalid storage class for pointer operand 1[%var]")); + } + } +} + +TEST_P(ValidateFunctionCall, VariableVariablePointersStorageClass) { + const std::string storage_class = GetParam(); + + std::string spirv = GenerateShader( + storage_class, "OpCapability VariablePointersStorageBuffer", + "OpExtension \"SPV_KHR_variable_pointers\""); + + const std::vector valid_storage_classes = { + "UniformConstant", "Function", "Private", + "Workgroup", "StorageBuffer", "AtomicCounter"}; + bool valid = + std::find(valid_storage_classes.begin(), valid_storage_classes.end(), + storage_class) != valid_storage_classes.end(); + + CompileSuccessfully(spirv); + if (valid) { + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); + } else { + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Invalid storage class for pointer operand 1[%var]")); + } +} + +TEST_P(ValidateFunctionCall, VariableVariablePointers) { + const std::string storage_class = GetParam(); + + std::string spirv = + GenerateShader(storage_class, "OpCapability VariablePointers", + "OpExtension \"SPV_KHR_variable_pointers\""); + + const std::vector valid_storage_classes = { + "UniformConstant", "Function", "Private", + "Workgroup", "StorageBuffer", "AtomicCounter"}; + bool valid = + std::find(valid_storage_classes.begin(), valid_storage_classes.end(), + storage_class) != valid_storage_classes.end(); + + CompileSuccessfully(spirv); + if (valid) { + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); + } else { + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Invalid storage class for pointer operand 1[%var]")); + } +} + +TEST_P(ValidateFunctionCall, ParameterNoVariablePointers) { + const std::string storage_class = GetParam(); + + std::string spirv = GenerateShaderParameter(storage_class, "", ""); + + const std::vector valid_storage_classes = { + "UniformConstant", "Function", "Private", "Workgroup", "AtomicCounter"}; + bool valid = + std::find(valid_storage_classes.begin(), valid_storage_classes.end(), + storage_class) != valid_storage_classes.end(); + + CompileSuccessfully(spirv); + if (valid) { + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); + } else { + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + if (storage_class == "StorageBuffer") { + EXPECT_THAT(getDiagnosticString(), + HasSubstr("StorageBuffer pointer operand 1[%p] requires a " + "variable pointers capability")); + } else { + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Invalid storage class for pointer operand 1[%p]")); + } + } +} + +TEST_P(ValidateFunctionCall, ParameterVariablePointersStorageBuffer) { + const std::string storage_class = GetParam(); + + std::string spirv = GenerateShaderParameter( + storage_class, "OpCapability VariablePointersStorageBuffer", + "OpExtension \"SPV_KHR_variable_pointers\""); + + const std::vector valid_storage_classes = { + "UniformConstant", "Function", "Private", + "Workgroup", "StorageBuffer", "AtomicCounter"}; + bool valid = + std::find(valid_storage_classes.begin(), valid_storage_classes.end(), + storage_class) != valid_storage_classes.end(); + + CompileSuccessfully(spirv); + if (valid) { + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); + } else { + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Invalid storage class for pointer operand 1[%p]")); + } +} + +TEST_P(ValidateFunctionCall, ParameterVariablePointers) { + const std::string storage_class = GetParam(); + + std::string spirv = + GenerateShaderParameter(storage_class, "OpCapability VariablePointers", + "OpExtension \"SPV_KHR_variable_pointers\""); + + const std::vector valid_storage_classes = { + "UniformConstant", "Function", "Private", + "Workgroup", "StorageBuffer", "AtomicCounter"}; + bool valid = + std::find(valid_storage_classes.begin(), valid_storage_classes.end(), + storage_class) != valid_storage_classes.end(); + + CompileSuccessfully(spirv); + if (valid) { + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); + } else { + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Invalid storage class for pointer operand 1[%p]")); + } +} + +TEST_P(ValidateFunctionCall, NonMemoryObjectDeclarationNoVariablePointers) { + const std::string storage_class = GetParam(); + + std::string spirv = GenerateShaderAccessChain(storage_class, "", ""); + + const std::vector valid_storage_classes = { + "Function", "Private", "Workgroup", "AtomicCounter"}; + bool valid_sc = + std::find(valid_storage_classes.begin(), valid_storage_classes.end(), + storage_class) != valid_storage_classes.end(); + + CompileSuccessfully(spirv); + spv_result_t expected_result = + storage_class == "UniformConstant" ? SPV_SUCCESS : SPV_ERROR_INVALID_ID; + EXPECT_EQ(expected_result, ValidateInstructions()); + if (valid_sc) { + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "Pointer operand 2[%gep] must be a memory object declaration")); + } else { + if (storage_class == "StorageBuffer") { + EXPECT_THAT(getDiagnosticString(), + HasSubstr("StorageBuffer pointer operand 2[%gep] requires a " + "variable pointers capability")); + } else if (storage_class != "UniformConstant") { + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Invalid storage class for pointer operand 2[%gep]")); + } + } +} + +TEST_P(ValidateFunctionCall, + NonMemoryObjectDeclarationVariablePointersStorageBuffer) { + const std::string storage_class = GetParam(); + + std::string spirv = GenerateShaderAccessChain( + storage_class, "OpCapability VariablePointersStorageBuffer", + "OpExtension \"SPV_KHR_variable_pointers\""); + + const std::vector valid_storage_classes = { + "Function", "Private", "Workgroup", "StorageBuffer", "AtomicCounter"}; + bool valid_sc = + std::find(valid_storage_classes.begin(), valid_storage_classes.end(), + storage_class) != valid_storage_classes.end(); + bool validate = + storage_class == "StorageBuffer" || storage_class == "UniformConstant"; + + CompileSuccessfully(spirv); + if (validate) { + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); + } else { + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + if (valid_sc) { + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "Pointer operand 2[%gep] must be a memory object declaration")); + } else { + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Invalid storage class for pointer operand 2[%gep]")); + } + } +} + +TEST_P(ValidateFunctionCall, NonMemoryObjectDeclarationVariablePointers) { + const std::string storage_class = GetParam(); + + std::string spirv = + GenerateShaderAccessChain(storage_class, "OpCapability VariablePointers", + "OpExtension \"SPV_KHR_variable_pointers\""); + + const std::vector valid_storage_classes = { + "Function", "Private", "Workgroup", "StorageBuffer", "AtomicCounter"}; + bool valid_sc = + std::find(valid_storage_classes.begin(), valid_storage_classes.end(), + storage_class) != valid_storage_classes.end(); + bool validate = storage_class == "StorageBuffer" || + storage_class == "Workgroup" || + storage_class == "UniformConstant"; + + CompileSuccessfully(spirv); + if (validate) { + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); + } else { + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + if (valid_sc) { + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "Pointer operand 2[%gep] must be a memory object declaration")); + } else { + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Invalid storage class for pointer operand 2[%gep]")); + } + } +} + +TEST_F(ValidateFunctionCall, LogicallyMatchingPointers) { + std::string spirv = + R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "main" + OpExecutionMode %1 LocalSize 1 1 1 + OpSource HLSL 600 + OpDecorate %2 DescriptorSet 0 + OpDecorate %2 Binding 0 + OpMemberDecorate %_struct_3 0 Offset 0 + OpDecorate %_runtimearr__struct_3 ArrayStride 4 + OpMemberDecorate %_struct_5 0 Offset 0 + OpDecorate %_struct_5 BufferBlock + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 + %uint = OpTypeInt 32 0 + %uint_0 = OpConstant %uint 0 + %_struct_3 = OpTypeStruct %int +%_runtimearr__struct_3 = OpTypeRuntimeArray %_struct_3 + %_struct_5 = OpTypeStruct %_runtimearr__struct_3 +%_ptr_Uniform__struct_5 = OpTypePointer Uniform %_struct_5 + %void = OpTypeVoid + %14 = OpTypeFunction %void + %_struct_15 = OpTypeStruct %int +%_ptr_Function__struct_15 = OpTypePointer Function %_struct_15 +%_ptr_Uniform__struct_3 = OpTypePointer Uniform %_struct_3 + %18 = OpTypeFunction %void %_ptr_Function__struct_15 + %2 = OpVariable %_ptr_Uniform__struct_5 Uniform + %1 = OpFunction %void None %14 + %19 = OpLabel + %20 = OpAccessChain %_ptr_Uniform__struct_3 %2 %int_0 %uint_0 + %21 = OpFunctionCall %void %22 %20 + OpReturn + OpFunctionEnd + %22 = OpFunction %void None %18 + %23 = OpFunctionParameter %_ptr_Function__struct_15 + %24 = OpLabel + OpReturn + OpFunctionEnd +)"; + CompileSuccessfully(spirv); + spvValidatorOptionsSetBeforeHlslLegalization(getValidatorOptions(), true); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateFunctionCall, LogicallyMatchingPointersNestedStruct) { + std::string spirv = + R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "main" + OpExecutionMode %1 LocalSize 1 1 1 + OpSource HLSL 600 + OpDecorate %2 DescriptorSet 0 + OpDecorate %2 Binding 0 + OpMemberDecorate %_struct_3 0 Offset 0 + OpMemberDecorate %_struct_4 0 Offset 0 + OpDecorate %_runtimearr__struct_4 ArrayStride 4 + OpMemberDecorate %_struct_6 0 Offset 0 + OpDecorate %_struct_6 BufferBlock + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 + %uint = OpTypeInt 32 0 + %uint_0 = OpConstant %uint 0 + %_struct_3 = OpTypeStruct %int + %_struct_4 = OpTypeStruct %_struct_3 +%_runtimearr__struct_4 = OpTypeRuntimeArray %_struct_4 + %_struct_6 = OpTypeStruct %_runtimearr__struct_4 +%_ptr_Uniform__struct_6 = OpTypePointer Uniform %_struct_6 + %void = OpTypeVoid + %13 = OpTypeFunction %void + %_struct_14 = OpTypeStruct %int + %_struct_15 = OpTypeStruct %_struct_14 +%_ptr_Function__struct_15 = OpTypePointer Function %_struct_15 +%_ptr_Uniform__struct_4 = OpTypePointer Uniform %_struct_4 + %18 = OpTypeFunction %void %_ptr_Function__struct_15 + %2 = OpVariable %_ptr_Uniform__struct_6 Uniform + %1 = OpFunction %void None %13 + %19 = OpLabel + %20 = OpVariable %_ptr_Function__struct_15 Function + %21 = OpAccessChain %_ptr_Uniform__struct_4 %2 %int_0 %uint_0 + %22 = OpFunctionCall %void %23 %21 + OpReturn + OpFunctionEnd + %23 = OpFunction %void None %18 + %24 = OpFunctionParameter %_ptr_Function__struct_15 + %25 = OpLabel + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + spvValidatorOptionsSetBeforeHlslLegalization(getValidatorOptions(), true); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateFunctionCall, LogicallyMatchingPointersNestedArray) { + std::string spirv = + R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "main" + OpExecutionMode %1 LocalSize 1 1 1 + OpSource HLSL 600 + OpDecorate %2 DescriptorSet 0 + OpDecorate %2 Binding 0 + OpDecorate %_arr_int_uint_10 ArrayStride 4 + OpMemberDecorate %_struct_4 0 Offset 0 + OpDecorate %_runtimearr__struct_4 ArrayStride 40 + OpMemberDecorate %_struct_6 0 Offset 0 + OpDecorate %_struct_6 BufferBlock + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 + %uint = OpTypeInt 32 0 + %uint_0 = OpConstant %uint 0 + %uint_10 = OpConstant %uint 10 +%_arr_int_uint_10 = OpTypeArray %int %uint_10 + %_struct_4 = OpTypeStruct %_arr_int_uint_10 +%_runtimearr__struct_4 = OpTypeRuntimeArray %_struct_4 + %_struct_6 = OpTypeStruct %_runtimearr__struct_4 +%_ptr_Uniform__struct_6 = OpTypePointer Uniform %_struct_6 + %void = OpTypeVoid + %14 = OpTypeFunction %void +%_ptr_Uniform__struct_4 = OpTypePointer Uniform %_struct_4 +%_arr_int_uint_10_0 = OpTypeArray %int %uint_10 + %_struct_17 = OpTypeStruct %_arr_int_uint_10_0 +%_ptr_Function__struct_17 = OpTypePointer Function %_struct_17 + %19 = OpTypeFunction %void %_ptr_Function__struct_17 + %2 = OpVariable %_ptr_Uniform__struct_6 Uniform + %1 = OpFunction %void None %14 + %20 = OpLabel + %21 = OpAccessChain %_ptr_Uniform__struct_4 %2 %int_0 %uint_0 + %22 = OpFunctionCall %void %23 %21 + OpReturn + OpFunctionEnd + %23 = OpFunction %void None %19 + %24 = OpFunctionParameter %_ptr_Function__struct_17 + %25 = OpLabel + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + spvValidatorOptionsSetBeforeHlslLegalization(getValidatorOptions(), true); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateFunctionCall, LogicallyMismatchedPointersMissingMember) { + // Validation should fail because the formal parameter type has two members, + // while the actual parameter only has 1. + std::string spirv = + R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "main" + OpExecutionMode %1 LocalSize 1 1 1 + OpSource HLSL 600 + OpDecorate %2 DescriptorSet 0 + OpDecorate %2 Binding 0 + OpMemberDecorate %_struct_3 0 Offset 0 + OpDecorate %_runtimearr__struct_3 ArrayStride 4 + OpMemberDecorate %_struct_5 0 Offset 0 + OpDecorate %_struct_5 BufferBlock + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 + %uint = OpTypeInt 32 0 + %uint_0 = OpConstant %uint 0 + %_struct_3 = OpTypeStruct %int +%_runtimearr__struct_3 = OpTypeRuntimeArray %_struct_3 + %_struct_5 = OpTypeStruct %_runtimearr__struct_3 +%_ptr_Uniform__struct_5 = OpTypePointer Uniform %_struct_5 + %void = OpTypeVoid + %14 = OpTypeFunction %void + %_struct_15 = OpTypeStruct %int %int +%_ptr_Function__struct_15 = OpTypePointer Function %_struct_15 +%_ptr_Uniform__struct_3 = OpTypePointer Uniform %_struct_3 + %18 = OpTypeFunction %void %_ptr_Function__struct_15 + %2 = OpVariable %_ptr_Uniform__struct_5 Uniform + %1 = OpFunction %void None %14 + %19 = OpLabel + %20 = OpAccessChain %_ptr_Uniform__struct_3 %2 %int_0 %uint_0 + %21 = OpFunctionCall %void %22 %20 + OpReturn + OpFunctionEnd + %22 = OpFunction %void None %18 + %23 = OpFunctionParameter %_ptr_Function__struct_15 + %24 = OpLabel + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + spvValidatorOptionsSetBeforeHlslLegalization(getValidatorOptions(), true); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), HasSubstr("OpFunctionCall Argument ")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("type does not match Function ")); +} + +TEST_F(ValidateFunctionCall, LogicallyMismatchedPointersDifferentMemberType) { + // Validation should fail because the formal parameter has a member that is + // a different type than the actual parameter. + std::string spirv = + R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "main" + OpExecutionMode %1 LocalSize 1 1 1 + OpSource HLSL 600 + OpDecorate %2 DescriptorSet 0 + OpDecorate %2 Binding 0 + OpMemberDecorate %_struct_3 0 Offset 0 + OpDecorate %_runtimearr__struct_3 ArrayStride 4 + OpMemberDecorate %_struct_5 0 Offset 0 + OpDecorate %_struct_5 BufferBlock + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 + %uint = OpTypeInt 32 0 + %uint_0 = OpConstant %uint 0 + %_struct_3 = OpTypeStruct %uint +%_runtimearr__struct_3 = OpTypeRuntimeArray %_struct_3 + %_struct_5 = OpTypeStruct %_runtimearr__struct_3 +%_ptr_Uniform__struct_5 = OpTypePointer Uniform %_struct_5 + %void = OpTypeVoid + %14 = OpTypeFunction %void + %_struct_15 = OpTypeStruct %int +%_ptr_Function__struct_15 = OpTypePointer Function %_struct_15 +%_ptr_Uniform__struct_3 = OpTypePointer Uniform %_struct_3 + %18 = OpTypeFunction %void %_ptr_Function__struct_15 + %2 = OpVariable %_ptr_Uniform__struct_5 Uniform + %1 = OpFunction %void None %14 + %19 = OpLabel + %20 = OpAccessChain %_ptr_Uniform__struct_3 %2 %int_0 %uint_0 + %21 = OpFunctionCall %void %22 %20 + OpReturn + OpFunctionEnd + %22 = OpFunction %void None %18 + %23 = OpFunctionParameter %_ptr_Function__struct_15 + %24 = OpLabel + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + spvValidatorOptionsSetBeforeHlslLegalization(getValidatorOptions(), true); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), HasSubstr("OpFunctionCall Argument ")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("type does not match Function ")); +} + +TEST_F(ValidateFunctionCall, + LogicallyMismatchedPointersIncompatableDecorations) { + // Validation should fail because the formal parameter has an incompatible + // decoration. + std::string spirv = + R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "main" + OpExecutionMode %1 LocalSize 1 1 1 + OpSource HLSL 600 + OpDecorate %2 DescriptorSet 0 + OpDecorate %2 Binding 0 + OpMemberDecorate %_struct_3 0 Offset 0 + OpDecorate %_runtimearr__struct_3 ArrayStride 4 + OpMemberDecorate %_struct_5 0 Offset 0 + OpDecorate %_struct_5 Block + OpMemberDecorate %_struct_15 0 NonWritable + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 + %uint = OpTypeInt 32 0 + %uint_0 = OpConstant %uint 0 + %_struct_3 = OpTypeStruct %int +%_runtimearr__struct_3 = OpTypeRuntimeArray %_struct_3 + %_struct_5 = OpTypeStruct %_runtimearr__struct_3 +%_ptr_StorageBuffer__struct_5 = OpTypePointer StorageBuffer %_struct_5 + %void = OpTypeVoid + %14 = OpTypeFunction %void + %_struct_15 = OpTypeStruct %int +%_ptr_Function__struct_15 = OpTypePointer Function %_struct_15 +%_ptr_StorageBuffer__struct_3 = OpTypePointer StorageBuffer %_struct_3 + %18 = OpTypeFunction %void %_ptr_Function__struct_15 + %2 = OpVariable %_ptr_StorageBuffer__struct_5 StorageBuffer + %1 = OpFunction %void None %14 + %19 = OpLabel + %20 = OpAccessChain %_ptr_StorageBuffer__struct_3 %2 %int_0 %uint_0 + %21 = OpFunctionCall %void %22 %20 + OpReturn + OpFunctionEnd + %22 = OpFunction %void None %18 + %23 = OpFunctionParameter %_ptr_Function__struct_15 + %24 = OpLabel + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + spvValidatorOptionsSetBeforeHlslLegalization(getValidatorOptions(), true); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT(getDiagnosticString(), HasSubstr("OpFunctionCall Argument ")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("type does not match Function ")); +} + +TEST_F(ValidateFunctionCall, + LogicallyMismatchedPointersIncompatableDecorations2) { + // Validation should fail because the formal parameter has an incompatible + // decoration. + std::string spirv = + R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "main" + OpExecutionMode %1 LocalSize 1 1 1 + OpSource HLSL 600 + OpDecorate %2 DescriptorSet 0 + OpDecorate %2 Binding 0 + OpMemberDecorate %_struct_3 0 Offset 0 + OpDecorate %_runtimearr__struct_3 ArrayStride 4 + OpMemberDecorate %_struct_5 0 Offset 0 + OpDecorate %_struct_5 BufferBlock + OpDecorate %_ptr_Uniform__struct_3 ArrayStride 4 + OpDecorate %_ptr_Uniform__struct_3_0 ArrayStride 8 + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 + %uint = OpTypeInt 32 0 + %uint_0 = OpConstant %uint 0 + %_struct_3 = OpTypeStruct %int +%_runtimearr__struct_3 = OpTypeRuntimeArray %_struct_3 + %_struct_5 = OpTypeStruct %_runtimearr__struct_3 +%_ptr_Uniform__struct_5 = OpTypePointer Uniform %_struct_5 + %void = OpTypeVoid + %14 = OpTypeFunction %void +%_ptr_Uniform__struct_3 = OpTypePointer Uniform %_struct_3 +%_ptr_Uniform__struct_3_0 = OpTypePointer Uniform %_struct_3 + %18 = OpTypeFunction %void %_ptr_Uniform__struct_3_0 + %2 = OpVariable %_ptr_Uniform__struct_5 Uniform + %1 = OpFunction %void None %14 + %19 = OpLabel + %20 = OpAccessChain %_ptr_Uniform__struct_3 %2 %int_0 %uint_0 + %21 = OpFunctionCall %void %22 %20 + OpReturn + OpFunctionEnd + %22 = OpFunction %void None %18 + %23 = OpFunctionParameter %_ptr_Uniform__struct_3_0 + %24 = OpLabel + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + spvValidatorOptionsSetBeforeHlslLegalization(getValidatorOptions(), true); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), HasSubstr("OpFunctionCall Argument ")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("type does not match Function ")); +} + +TEST_F(ValidateFunctionCall, LogicallyMismatchedPointersArraySize) { + // Validation should fail because the formal parameter array has a different + // number of element than the actual parameter. + std::string spirv = + R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "main" + OpExecutionMode %1 LocalSize 1 1 1 + OpSource HLSL 600 + OpDecorate %2 DescriptorSet 0 + OpDecorate %2 Binding 0 + OpDecorate %_arr_int_uint_10 ArrayStride 4 + OpMemberDecorate %_struct_4 0 Offset 0 + OpDecorate %_runtimearr__struct_4 ArrayStride 40 + OpMemberDecorate %_struct_6 0 Offset 0 + OpDecorate %_struct_6 BufferBlock + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 + %uint = OpTypeInt 32 0 + %uint_0 = OpConstant %uint 0 + %uint_5 = OpConstant %uint 5 + %uint_10 = OpConstant %uint 10 +%_arr_int_uint_10 = OpTypeArray %int %uint_10 + %_struct_4 = OpTypeStruct %_arr_int_uint_10 +%_runtimearr__struct_4 = OpTypeRuntimeArray %_struct_4 + %_struct_6 = OpTypeStruct %_runtimearr__struct_4 +%_ptr_Uniform__struct_6 = OpTypePointer Uniform %_struct_6 + %void = OpTypeVoid + %14 = OpTypeFunction %void +%_ptr_Uniform__struct_4 = OpTypePointer Uniform %_struct_4 +%_arr_int_uint_5 = OpTypeArray %int %uint_5 + %_struct_17 = OpTypeStruct %_arr_int_uint_5 +%_ptr_Function__struct_17 = OpTypePointer Function %_struct_17 + %19 = OpTypeFunction %void %_ptr_Function__struct_17 + %2 = OpVariable %_ptr_Uniform__struct_6 Uniform + %1 = OpFunction %void None %14 + %20 = OpLabel + %21 = OpAccessChain %_ptr_Uniform__struct_4 %2 %int_0 %uint_0 + %22 = OpFunctionCall %void %23 %21 + OpReturn + OpFunctionEnd + %23 = OpFunction %void None %19 + %24 = OpFunctionParameter %_ptr_Function__struct_17 + %25 = OpLabel + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + spvValidatorOptionsSetBeforeHlslLegalization(getValidatorOptions(), true); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), HasSubstr("OpFunctionCall Argument ")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("type does not match Function ")); +} + +INSTANTIATE_TEST_SUITE_P(StorageClass, ValidateFunctionCall, + Values("UniformConstant", "Input", "Uniform", "Output", + "Workgroup", "Private", "Function", + "PushConstant", "Image", "StorageBuffer", + "AtomicCounter")); +} // namespace +} // namespace val +} // namespace spvtools diff --git a/third_party/spirv-tools/test/val/val_id_test.cpp b/third_party/spirv-tools/test/val/val_id_test.cpp index 2b02e096b6..019d91ad71 100644 --- a/third_party/spirv-tools/test/val/val_id_test.cpp +++ b/third_party/spirv-tools/test/val/val_id_test.cpp @@ -37,6 +37,19 @@ using ::testing::ValuesIn; using ValidateIdWithMessage = spvtest::ValidateBase; +std::string kOpCapabilitySetupWithoutVector16 = R"( + OpCapability Shader + OpCapability Linkage + OpCapability Addresses + OpCapability Int8 + OpCapability Int16 + OpCapability Int64 + OpCapability Float64 + OpCapability LiteralSampler + OpCapability Pipes + OpCapability DeviceEnqueue +)"; + std::string kOpCapabilitySetup = R"( OpCapability Shader OpCapability Linkage @@ -51,7 +64,18 @@ std::string kOpCapabilitySetup = R"( OpCapability Vector16 )"; -std::string kGLSL450MemoryModel = kOpCapabilitySetup + R"( +std::string kOpVariablePtrSetUp = R"( + OpCapability VariablePointers + OpExtension "SPV_KHR_variable_pointers" +)"; + +std::string kGLSL450MemoryModel = + kOpCapabilitySetup + kOpVariablePtrSetUp + R"( + OpMemoryModel Logical GLSL450 +)"; + +std::string kGLSL450MemoryModelWithoutVector16 = + kOpCapabilitySetupWithoutVector16 + kOpVariablePtrSetUp + R"( OpMemoryModel Logical GLSL450 )"; @@ -181,7 +205,7 @@ TEST_F(ValidateIdWithMessage, OpMemberNameTypeBad) { EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), - HasSubstr("OpMemberName Type '1[foo]' is not a struct type.")); + HasSubstr("OpMemberName Type '1[%uint]' is not a struct type.")); } TEST_F(ValidateIdWithMessage, OpMemberNameMemberBad) { std::string spirv = kGLSL450MemoryModel + R"( @@ -192,8 +216,8 @@ TEST_F(ValidateIdWithMessage, OpMemberNameMemberBad) { EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), - HasSubstr("OpMemberName Member '1[foo]' index is larger than " - "Type '1[foo]'s member count.")); + HasSubstr("OpMemberName Member '1[%_struct_1]' index is larger " + "than Type '1[%_struct_1]'s member count.")); } TEST_F(ValidateIdWithMessage, OpLineGood) { @@ -215,7 +239,7 @@ TEST_F(ValidateIdWithMessage, OpLineFileBad) { CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpLine Target '1' is not an OpString.")); + HasSubstr("OpLine Target '1[%uint]' is not an OpString.")); } TEST_F(ValidateIdWithMessage, OpDecorateGood) { @@ -237,7 +261,7 @@ OpDecorate %1 GLSLShared)"; TEST_F(ValidateIdWithMessage, OpMemberDecorateGood) { std::string spirv = kGLSL450MemoryModel + R"( - OpMemberDecorate %2 0 Uniform + OpMemberDecorate %2 0 RelaxedPrecision %1 = OpTypeInt 32 0 %2 = OpTypeStruct %1 %1)"; CompileSuccessfully(spirv.c_str()); @@ -245,32 +269,31 @@ TEST_F(ValidateIdWithMessage, OpMemberDecorateGood) { } TEST_F(ValidateIdWithMessage, OpMemberDecorateBad) { std::string spirv = kGLSL450MemoryModel + R"( - OpMemberDecorate %1 0 Uniform + OpMemberDecorate %1 0 RelaxedPrecision %1 = OpTypeInt 32 0)"; CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr( - "OpMemberDecorate Structure type '1' is not a struct type.")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("OpMemberDecorate Structure type '1[%uint]' is " + "not a struct type.")); } TEST_F(ValidateIdWithMessage, OpMemberDecorateMemberBad) { std::string spirv = kGLSL450MemoryModel + R"( - OpMemberDecorate %1 3 Uniform + OpMemberDecorate %1 3 RelaxedPrecision %int = OpTypeInt 32 0 %1 = OpTypeStruct %int %int)"; CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("Index 3 provided in OpMemberDecorate for struct " - "1 is out of bounds. The structure has 2 members. " - "Largest valid index is 1.")); + "1[%_struct_1] is out of bounds. The structure has 2 " + "members. Largest valid index is 1.")); } TEST_F(ValidateIdWithMessage, OpGroupDecorateGood) { std::string spirv = kGLSL450MemoryModel + R"( %1 = OpDecorationGroup - OpDecorate %1 Uniform + OpDecorate %1 RelaxedPrecision OpDecorate %1 GLSLShared OpGroupDecorate %1 %3 %4 %2 = OpTypeInt 32 0 @@ -282,7 +305,7 @@ TEST_F(ValidateIdWithMessage, OpGroupDecorateGood) { TEST_F(ValidateIdWithMessage, OpDecorationGroupBad) { std::string spirv = kGLSL450MemoryModel + R"( %1 = OpDecorationGroup - OpDecorate %1 Uniform + OpDecorate %1 RelaxedPrecision OpDecorate %1 GLSLShared OpMemberDecorate %1 0 Constant )"; @@ -291,7 +314,7 @@ TEST_F(ValidateIdWithMessage, OpDecorationGroupBad) { EXPECT_THAT(getDiagnosticString(), HasSubstr("Result id of OpDecorationGroup can only " "be targeted by OpName, OpGroupDecorate, " - "OpDecorate, and OpGroupMemberDecorate")); + "OpDecorate, OpDecorateId, and OpGroupMemberDecorate")); } TEST_F(ValidateIdWithMessage, OpGroupDecorateDecorationGroupBad) { std::string spirv = R"( @@ -305,13 +328,13 @@ TEST_F(ValidateIdWithMessage, OpGroupDecorateDecorationGroupBad) { CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpGroupDecorate Decoration group '1' is not a " - "decoration group.")); + HasSubstr("OpGroupDecorate Decoration group '1[%1]' is not " + "a decoration group.")); } TEST_F(ValidateIdWithMessage, OpGroupDecorateTargetBad) { std::string spirv = kGLSL450MemoryModel + R"( %1 = OpDecorationGroup - OpDecorate %1 Uniform + OpDecorate %1 RelaxedPrecision OpDecorate %1 GLSLShared OpGroupDecorate %1 %3 %2 = OpTypeInt 32 0)"; @@ -331,8 +354,8 @@ TEST_F(ValidateIdWithMessage, OpGroupMemberDecorateDecorationGroupBad) { CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpGroupMemberDecorate Decoration group '1' is " - "not a decoration group.")); + HasSubstr("OpGroupMemberDecorate Decoration group '1[%1]' " + "is not a decoration group.")); } TEST_F(ValidateIdWithMessage, OpGroupMemberDecorateIdNotStructBad) { std::string spirv = kGLSL450MemoryModel + R"( @@ -342,8 +365,8 @@ TEST_F(ValidateIdWithMessage, OpGroupMemberDecorateIdNotStructBad) { CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpGroupMemberDecorate Structure type '2' is not " - "a struct type.")); + HasSubstr("OpGroupMemberDecorate Structure type '2[%uint]' " + "is not a struct type.")); } TEST_F(ValidateIdWithMessage, OpGroupMemberDecorateIndexOutOfBoundBad) { std::string spirv = kGLSL450MemoryModel + R"( @@ -357,8 +380,8 @@ TEST_F(ValidateIdWithMessage, OpGroupMemberDecorateIndexOutOfBoundBad) { EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("Index 3 provided in OpGroupMemberDecorate for struct " - " 2 is out of bounds. The structure has 3 members. " - "Largest valid index is 2.")); + " 2[%_struct_2] is out of bounds. The structure " + "has 3 members. Largest valid index is 2.")); } // TODO: OpExtInst @@ -382,9 +405,9 @@ TEST_F(ValidateIdWithMessage, OpEntryPointFunctionBad) { %1 = OpTypeVoid)"; CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr("OpEntryPoint Entry Point '1' is not a function.")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("OpEntryPoint Entry Point '1[%void]' is not a " + "function.")); } TEST_F(ValidateIdWithMessage, OpEntryPointParameterCountBad) { std::string spirv = kGLSL450MemoryModel + R"( @@ -398,8 +421,8 @@ TEST_F(ValidateIdWithMessage, OpEntryPointParameterCountBad) { CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpEntryPoint Entry Point '1's function parameter " - "count is not zero")); + HasSubstr("OpEntryPoint Entry Point '1[%1]'s function " + "parameter count is not zero")); } TEST_F(ValidateIdWithMessage, OpEntryPointReturnTypeBad) { std::string spirv = kGLSL450MemoryModel + R"( @@ -414,8 +437,8 @@ TEST_F(ValidateIdWithMessage, OpEntryPointReturnTypeBad) { CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpEntryPoint Entry Point '1's function return " - "type is not void.")); + HasSubstr("OpEntryPoint Entry Point '1[%1]'s function " + "return type is not void.")); } TEST_F(ValidateIdWithMessage, OpEntryPointInterfaceIsNotVariableTypeBad) { @@ -424,6 +447,8 @@ TEST_F(ValidateIdWithMessage, OpEntryPointInterfaceIsNotVariableTypeBad) { OpCapability Geometry OpMemoryModel Logical GLSL450 OpEntryPoint Geometry %main "main" %ptr_builtin_1 + OpExecutionMode %main InputPoints + OpExecutionMode %main OutputPoints OpMemberDecorate %struct_1 0 BuiltIn InvocationId %int = OpTypeInt 32 1 %void = OpTypeVoid @@ -448,6 +473,8 @@ TEST_F(ValidateIdWithMessage, OpEntryPointInterfaceStorageClassBad) { OpCapability Geometry OpMemoryModel Logical GLSL450 OpEntryPoint Geometry %main "main" %in_1 + OpExecutionMode %main InputPoints + OpExecutionMode %main OutputPoints OpMemberDecorate %struct_1 0 BuiltIn InvocationId %int = OpTypeInt 32 1 %void = OpTypeVoid @@ -494,8 +521,8 @@ TEST_F(ValidateIdWithMessage, OpExecutionModeEntryPointMissing) { CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpExecutionMode Entry Point '1' is not the Entry " - "Point operand of an OpEntryPoint.")); + HasSubstr("OpExecutionMode Entry Point '1[%1]' is not the " + "Entry Point operand of an OpEntryPoint.")); } TEST_F(ValidateIdWithMessage, OpExecutionModeEntryPointBad) { @@ -513,8 +540,8 @@ TEST_F(ValidateIdWithMessage, OpExecutionModeEntryPointBad) { CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpExecutionMode Entry Point '2' is not the Entry " - "Point operand of an OpEntryPoint.")); + HasSubstr("OpExecutionMode Entry Point '2[%2]' is not the " + "Entry Point operand of an OpEntryPoint.")); } TEST_F(ValidateIdWithMessage, OpTypeVectorFloat) { @@ -558,7 +585,76 @@ TEST_F(ValidateIdWithMessage, OpTypeVectorComponentTypeBad) { EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), - HasSubstr("OpTypeVector Component Type '2' is not a scalar type.")); + HasSubstr("OpTypeVector Component Type " + "'2[%_ptr_UniformConstant_float]' is not a scalar type.")); +} + +TEST_F(ValidateIdWithMessage, OpTypeVectorColumnCountLessThanTwoBad) { + std::string spirv = kGLSL450MemoryModel + R"( +%1 = OpTypeFloat 32 +%2 = OpTypeVector %1 1)"; + CompileSuccessfully(spirv.c_str()); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Illegal number of components (1) for TypeVector\n %v1float = " + "OpTypeVector %float 1\n")); +} + +TEST_F(ValidateIdWithMessage, OpTypeVectorColumnCountGreaterThanFourBad) { + std::string spirv = kGLSL450MemoryModel + R"( +%1 = OpTypeFloat 32 +%2 = OpTypeVector %1 5)"; + CompileSuccessfully(spirv.c_str()); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Illegal number of components (5) for TypeVector\n %v5float = " + "OpTypeVector %float 5\n")); +} + +TEST_F(ValidateIdWithMessage, OpTypeVectorColumnCountEightWithoutVector16Bad) { + std::string spirv = kGLSL450MemoryModelWithoutVector16 + R"( +%1 = OpTypeFloat 32 +%2 = OpTypeVector %1 8)"; + + CompileSuccessfully(spirv.c_str()); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Having 8 components for TypeVector requires the Vector16 " + "capability\n %v8float = OpTypeVector %float 8\n")); +} + +TEST_F(ValidateIdWithMessage, + OpTypeVectorColumnCountSixteenWithoutVector16Bad) { + std::string spirv = kGLSL450MemoryModelWithoutVector16 + R"( +%1 = OpTypeFloat 32 +%2 = OpTypeVector %1 16)"; + + CompileSuccessfully(spirv.c_str()); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Having 16 components for TypeVector requires the Vector16 " + "capability\n %v16float = OpTypeVector %float 16\n")); +} + +TEST_F(ValidateIdWithMessage, OpTypeVectorColumnCountOfEightWithVector16Good) { + std::string spirv = kGLSL450MemoryModel + R"( +%1 = OpTypeFloat 32 +%2 = OpTypeVector %1 8)"; + CompileSuccessfully(spirv.c_str()); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateIdWithMessage, + OpTypeVectorColumnCountOfSixteenWithVector16Good) { + std::string spirv = kGLSL450MemoryModel + R"( +%1 = OpTypeFloat 32 +%2 = OpTypeVector %1 16)"; + CompileSuccessfully(spirv.c_str()); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); } TEST_F(ValidateIdWithMessage, OpTypeMatrixGood) { @@ -569,14 +665,56 @@ TEST_F(ValidateIdWithMessage, OpTypeMatrixGood) { CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); } -TEST_F(ValidateIdWithMessage, OpTypeMatrixColumnTypeBad) { + +TEST_F(ValidateIdWithMessage, OpTypeMatrixColumnTypeNonVectorBad) { std::string spirv = kGLSL450MemoryModel + R"( -%1 = OpTypeInt 32 0 +%1 = OpTypeFloat 32 %2 = OpTypeMatrix %1 3)"; CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("Columns in a matrix must be of type vector.")); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("olumns in a matrix must be of type vector.\n %mat3float = " + "OpTypeMatrix %float 3\n")); +} + +TEST_F(ValidateIdWithMessage, OpTypeMatrixVectorTypeNonFloatBad) { + std::string spirv = kGLSL450MemoryModel + R"( +%1 = OpTypeInt 16 0 +%2 = OpTypeVector %1 2 +%3 = OpTypeMatrix %2 2)"; + CompileSuccessfully(spirv.c_str()); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Matrix types can only be parameterized with floating-point " + "types.\n %mat2v2ushort = OpTypeMatrix %v2ushort 2\n")); +} + +TEST_F(ValidateIdWithMessage, OpTypeMatrixColumnCountLessThanTwoBad) { + std::string spirv = kGLSL450MemoryModel + R"( +%1 = OpTypeFloat 32 +%2 = OpTypeVector %1 2 +%3 = OpTypeMatrix %2 1)"; + CompileSuccessfully(spirv.c_str()); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Matrix types can only be parameterized as having only 2, 3, " + "or 4 columns.\n %mat1v2float = OpTypeMatrix %v2float 1\n")); +} + +TEST_F(ValidateIdWithMessage, OpTypeMatrixColumnCountGreaterThanFourBad) { + std::string spirv = kGLSL450MemoryModel + R"( +%1 = OpTypeFloat 32 +%2 = OpTypeVector %1 2 +%3 = OpTypeMatrix %2 8)"; + CompileSuccessfully(spirv.c_str()); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Matrix types can only be parameterized as having only 2, 3, " + "or 4 columns.\n %mat8v2float = OpTypeMatrix %v2float 8\n")); } TEST_F(ValidateIdWithMessage, OpTypeSamplerGood) { @@ -604,26 +742,47 @@ TEST_F(ValidateIdWithMessage, OpTypeArrayElementTypeBad) { CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpTypeArray Element Type '2' is not a type.")); + HasSubstr("OpTypeArray Element Type '2[%uint_1]' is not a " + "type.")); } // Signed or unsigned. enum Signed { kSigned, kUnsigned }; -// Creates an assembly snippet declaring OpTypeArray with the given length. -std::string MakeArrayLength(const std::string& len, Signed isSigned, - int width) { +// Creates an assembly module declaring OpTypeArray with the given length. +std::string MakeArrayLength(const std::string& len, Signed isSigned, int width, + int max_int_width = 64, + bool use_vulkan_memory_model = false) { std::ostringstream ss; ss << R"( OpCapability Shader - OpCapability Linkage - OpCapability Int16 - OpCapability Int64 )"; - ss << "OpMemoryModel Logical GLSL450\n"; + if (use_vulkan_memory_model) { + ss << " OpCapability VulkanMemoryModel\n"; + } + if (width == 16) { + ss << " OpCapability Int16\n"; + } + if (max_int_width > 32) { + ss << "\n OpCapability Int64\n"; + } + if (use_vulkan_memory_model) { + ss << " OpExtension \"SPV_KHR_vulkan_memory_model\"\n"; + ss << "OpMemoryModel Logical Vulkan\n"; + } else { + ss << "OpMemoryModel Logical GLSL450\n"; + } + ss << "OpEntryPoint GLCompute %main \"main\"\n"; + ss << "OpExecutionMode %main LocalSize 1 1 1\n"; ss << " %t = OpTypeInt " << width << (isSigned == kSigned ? " 1" : " 0"); ss << " %l = OpConstant %t " << len; ss << " %a = OpTypeArray %t %l"; + ss << " %void = OpTypeVoid \n" + " %voidfn = OpTypeFunction %void \n" + " %main = OpFunction %void None %voidfn \n" + " %entry = OpLabel\n" + " OpReturn\n" + " OpFunctionEnd\n"; return ss.str(); } @@ -633,7 +792,8 @@ class OpTypeArrayLengthTest : public spvtest::TextToBinaryTestBase<::testing::TestWithParam> { protected: OpTypeArrayLengthTest() - : position_(spv_position_t{0, 0, 0}), + : env_(SPV_ENV_UNIVERSAL_1_0), + position_(spv_position_t{0, 0, 0}), diagnostic_(spvDiagnosticCreate(&position_, "")) {} ~OpTypeArrayLengthTest() { spvDiagnosticDestroy(diagnostic_); } @@ -641,21 +801,27 @@ class OpTypeArrayLengthTest // Runs spvValidate() on v, printing any errors via spvDiagnosticPrint(). spv_result_t Val(const SpirvVector& v, const std::string& expected_err = "") { spv_const_binary_t cbinary{v.data(), v.size()}; + spvDiagnosticDestroy(diagnostic_); + diagnostic_ = nullptr; const auto status = - spvValidate(ScopedContext().context, &cbinary, &diagnostic_); + spvValidate(ScopedContext(env_).context, &cbinary, &diagnostic_); if (status != SPV_SUCCESS) { spvDiagnosticPrint(diagnostic_); - EXPECT_THAT(std::string(diagnostic_->error), HasSubstr(expected_err)); + EXPECT_THAT(std::string(diagnostic_->error), + testing::ContainsRegex(expected_err)); } return status; } + protected: + spv_target_env env_; + private: spv_position_t position_; // For creating diagnostic_. spv_diagnostic diagnostic_; }; -TEST_P(OpTypeArrayLengthTest, LengthPositive) { +TEST_P(OpTypeArrayLengthTest, LengthPositiveSmall) { const int width = GetParam(); EXPECT_EQ(SPV_SUCCESS, Val(CompileSuccessfully(MakeArrayLength("1", kSigned, width)))); @@ -672,42 +838,106 @@ TEST_P(OpTypeArrayLengthTest, LengthPositive) { const std::string fpad(width / 4 - 1, 'F'); EXPECT_EQ( SPV_SUCCESS, - Val(CompileSuccessfully(MakeArrayLength("0x7" + fpad, kSigned, width)))); - EXPECT_EQ(SPV_SUCCESS, Val(CompileSuccessfully( - MakeArrayLength("0xF" + fpad, kUnsigned, width)))); + Val(CompileSuccessfully(MakeArrayLength("0x7" + fpad, kSigned, width)))) + << MakeArrayLength("0x7" + fpad, kSigned, width); } TEST_P(OpTypeArrayLengthTest, LengthZero) { const int width = GetParam(); - EXPECT_EQ( - SPV_ERROR_INVALID_ID, - Val(CompileSuccessfully(MakeArrayLength("0", kSigned, width)), - "OpTypeArray Length '2' default value must be at least 1.")); - EXPECT_EQ( - SPV_ERROR_INVALID_ID, - Val(CompileSuccessfully(MakeArrayLength("0", kUnsigned, width)), - "OpTypeArray Length '2' default value must be at least 1.")); + EXPECT_EQ(SPV_ERROR_INVALID_ID, + Val(CompileSuccessfully(MakeArrayLength("0", kSigned, width)), + "OpTypeArray Length '3\\[%.*\\]' default value must be at " + "least 1.")); + EXPECT_EQ(SPV_ERROR_INVALID_ID, + Val(CompileSuccessfully(MakeArrayLength("0", kUnsigned, width)), + "OpTypeArray Length '3\\[%.*\\]' default value must be at " + "least 1.")); } TEST_P(OpTypeArrayLengthTest, LengthNegative) { const int width = GetParam(); - EXPECT_EQ( - SPV_ERROR_INVALID_ID, - Val(CompileSuccessfully(MakeArrayLength("-1", kSigned, width)), - "OpTypeArray Length '2' default value must be at least 1.")); - EXPECT_EQ( - SPV_ERROR_INVALID_ID, - Val(CompileSuccessfully(MakeArrayLength("-2", kSigned, width)), - "OpTypeArray Length '2' default value must be at least 1.")); - EXPECT_EQ( - SPV_ERROR_INVALID_ID, - Val(CompileSuccessfully(MakeArrayLength("-123", kSigned, width)), - "OpTypeArray Length '2' default value must be at least 1.")); + EXPECT_EQ(SPV_ERROR_INVALID_ID, + Val(CompileSuccessfully(MakeArrayLength("-1", kSigned, width)), + "OpTypeArray Length '3\\[%.*\\]' default value must be at " + "least 1.")); + EXPECT_EQ(SPV_ERROR_INVALID_ID, + Val(CompileSuccessfully(MakeArrayLength("-2", kSigned, width)), + "OpTypeArray Length '3\\[%.*\\]' default value must be at " + "least 1.")); + EXPECT_EQ(SPV_ERROR_INVALID_ID, + Val(CompileSuccessfully(MakeArrayLength("-123", kSigned, width)), + "OpTypeArray Length '3\\[%.*\\]' default value must be at " + "least 1.")); const std::string neg_max = "0x8" + std::string(width / 4 - 1, '0'); - EXPECT_EQ( - SPV_ERROR_INVALID_ID, - Val(CompileSuccessfully(MakeArrayLength(neg_max, kSigned, width)), - "OpTypeArray Length '2' default value must be at least 1.")); + EXPECT_EQ(SPV_ERROR_INVALID_ID, + Val(CompileSuccessfully(MakeArrayLength(neg_max, kSigned, width)), + "OpTypeArray Length '3\\[%.*\\]' default value must be at " + "least 1.")); +} + +// Returns the string form of an integer of the form 0x80....0 of the +// given bit width. +std::string big_num_ending_0(int bit_width) { + return "0x8" + std::string(bit_width / 4 - 1, '0'); +} + +// Returns the string form of an integer of the form 0x80..001 of the +// given bit width. +std::string big_num_ending_1(int bit_width) { + return "0x8" + std::string(bit_width / 4 - 2, '0') + "1"; +} + +TEST_P(OpTypeArrayLengthTest, LengthPositiveHugeEnding0InVulkan) { + env_ = SPV_ENV_VULKAN_1_0; + const int width = GetParam(); + for (int max_int_width : {32, 64}) { + if (width > max_int_width) { + // Not valid to even make the OpConstant in this case. + continue; + } + const auto module = CompileSuccessfully(MakeArrayLength( + big_num_ending_0(width), kUnsigned, width, max_int_width)); + EXPECT_EQ(SPV_SUCCESS, Val(module)); + } +} + +TEST_P(OpTypeArrayLengthTest, LengthPositiveHugeEnding1InVulkan) { + env_ = SPV_ENV_VULKAN_1_0; + const int width = GetParam(); + for (int max_int_width : {32, 64}) { + if (width > max_int_width) { + // Not valid to even make the OpConstant in this case. + continue; + } + const auto module = CompileSuccessfully(MakeArrayLength( + big_num_ending_1(width), kUnsigned, width, max_int_width)); + EXPECT_EQ(SPV_SUCCESS, Val(module)); + } +} + +TEST_P(OpTypeArrayLengthTest, LengthPositiveHugeEnding0InWebGPU) { + env_ = SPV_ENV_WEBGPU_0; + const int width = GetParam(); + // WebGPU only has 32 bit integers. + if (width != 32) return; + const int max_int_width = 32; + const auto module = CompileSuccessfully(MakeArrayLength( + big_num_ending_0(width), kUnsigned, width, max_int_width, true)); + EXPECT_EQ(SPV_SUCCESS, Val(module)); +} + +TEST_P(OpTypeArrayLengthTest, LengthPositiveHugeEnding1InWebGPU) { + env_ = SPV_ENV_WEBGPU_0; + const int width = GetParam(); + // WebGPU only has 32 bit integers. + if (width != 32) return; + const int max_int_width = 32; + const auto module = CompileSuccessfully(MakeArrayLength( + big_num_ending_1(width), kUnsigned, width, max_int_width, true)); + EXPECT_EQ(SPV_ERROR_INVALID_ID, + Val(module, + "OpTypeArray Length '3\\[%.*\\]' size exceeds max value " + "2147483648 permitted by WebGPU: got 2147483649")); } // The only valid widths for integers are 8, 16, 32, and 64. @@ -715,8 +945,8 @@ TEST_P(OpTypeArrayLengthTest, LengthNegative) { // capability prohibits usage of signed integers, we can skip 8-bit integers // here since the purpose of these tests is to check the validity of // OpTypeArray, not OpTypeInt. -INSTANTIATE_TEST_CASE_P(Widths, OpTypeArrayLengthTest, - ValuesIn(std::vector{16, 32, 64})); +INSTANTIATE_TEST_SUITE_P(Widths, OpTypeArrayLengthTest, + ValuesIn(std::vector{16, 32, 64})); TEST_F(ValidateIdWithMessage, OpTypeArrayLengthNull) { std::string spirv = kGLSL450MemoryModel + R"( @@ -728,7 +958,7 @@ TEST_F(ValidateIdWithMessage, OpTypeArrayLengthNull) { EXPECT_THAT( getDiagnosticString(), HasSubstr( - "OpTypeArray Length '2' default value must be at least 1.")); + "OpTypeArray Length '2[%2]' default value must be at least 1.")); } TEST_F(ValidateIdWithMessage, OpTypeArrayLengthSpecConst) { @@ -767,7 +997,8 @@ TEST_F(ValidateIdWithMessage, OpTypeRuntimeArrayBad) { EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), - HasSubstr("OpTypeRuntimeArray Element Type '2' is not a type.")); + HasSubstr("OpTypeRuntimeArray Element Type '2[%uint_0]' is not a " + "type.")); } // TODO: Object of this type can only be created with OpVariable using the // Unifrom Storage Class @@ -790,7 +1021,28 @@ TEST_F(ValidateIdWithMessage, OpTypeStructMemberTypeBad) { CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpTypeStruct Member Type '3' is not a type.")); + HasSubstr("OpTypeStruct Member Type '3[%double_0]' is not " + "a type.")); +} + +TEST_F(ValidateIdWithMessage, OpTypeStructOpaqueTypeBad) { + std::string spirv = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %main "main" + %1 = OpTypeSampler + %2 = OpTypeStruct %1 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %main = OpFunction %void None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd +)"; + CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_0); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("OpTypeStruct must not contain an opaque type")); } TEST_F(ValidateIdWithMessage, OpTypePointerGood) { @@ -808,7 +1060,8 @@ TEST_F(ValidateIdWithMessage, OpTypePointerBad) { CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpTypePointer Type '2' is not a type.")); + HasSubstr("OpTypePointer Type '2[%uint_0]' is not a " + "type.")); } TEST_F(ValidateIdWithMessage, OpTypeFunctionGood) { @@ -826,7 +1079,8 @@ TEST_F(ValidateIdWithMessage, OpTypeFunctionReturnTypeBad) { CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpTypeFunction Return Type '2' is not a type.")); + HasSubstr("OpTypeFunction Return Type '2[%uint_0]' is not " + "a type.")); } TEST_F(ValidateIdWithMessage, OpTypeFunctionParameterBad) { std::string spirv = kGLSL450MemoryModel + R"( @@ -838,7 +1092,20 @@ TEST_F(ValidateIdWithMessage, OpTypeFunctionParameterBad) { EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), - HasSubstr("OpTypeFunction Parameter Type '3' is not a type.")); + HasSubstr("OpTypeFunction Parameter Type '3[%uint_0]' is not a " + "type.")); +} + +TEST_F(ValidateIdWithMessage, OpTypeFunctionParameterTypeVoidBad) { + std::string spirv = kGLSL450MemoryModel + R"( +%1 = OpTypeVoid +%2 = OpTypeInt 32 0 +%4 = OpTypeFunction %1 %2 %1)"; + CompileSuccessfully(spirv.c_str()); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("OpTypeFunction Parameter Type '1[%void]' cannot " + "be OpTypeVoid.")); } TEST_F(ValidateIdWithMessage, OpTypePipeGood) { @@ -865,7 +1132,8 @@ TEST_F(ValidateIdWithMessage, OpConstantTrueBad) { EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), - HasSubstr("OpConstantTrue Result Type '1' is not a boolean type.")); + HasSubstr("OpConstantTrue Result Type '1[%void]' is not a boolean " + "type.")); } TEST_F(ValidateIdWithMessage, OpConstantFalseGood) { @@ -883,7 +1151,8 @@ TEST_F(ValidateIdWithMessage, OpConstantFalseBad) { EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), - HasSubstr("OpConstantFalse Result Type '1' is not a boolean type.")); + HasSubstr("OpConstantFalse Result Type '1[%void]' is not a boolean " + "type.")); } TEST_F(ValidateIdWithMessage, OpConstantGood) { @@ -933,8 +1202,8 @@ TEST_F(ValidateIdWithMessage, OpConstantCompositeVectorResultTypeBad) { EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), - HasSubstr( - "OpConstantComposite Result Type '1' is not a composite type.")); + HasSubstr("OpConstantComposite Result Type '1[%float]' is not a " + "composite type.")); } TEST_F(ValidateIdWithMessage, OpConstantCompositeVectorConstituentTypeBad) { std::string spirv = kGLSL450MemoryModel + R"( @@ -948,8 +1217,9 @@ TEST_F(ValidateIdWithMessage, OpConstantCompositeVectorConstituentTypeBad) { EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), - HasSubstr("OpConstantComposite Constituent '5's type does not match " - "Result Type '2's vector element type.")); + HasSubstr("OpConstantComposite Constituent '5[%uint_42]'s type " + "does not match Result Type '2[%v4float]'s vector " + "element type.")); } TEST_F(ValidateIdWithMessage, OpConstantCompositeVectorConstituentUndefTypeBad) { @@ -964,8 +1234,8 @@ TEST_F(ValidateIdWithMessage, EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), - HasSubstr("OpConstantComposite Constituent '5's type does not match " - "Result Type '2's vector element type.")); + HasSubstr("OpConstantComposite Constituent '5[%5]'s type does not " + "match Result Type '2[%v4float]'s vector element type.")); } TEST_F(ValidateIdWithMessage, OpConstantCompositeMatrixGood) { std::string spirv = kGLSL450MemoryModel + R"( @@ -1013,9 +1283,9 @@ TEST_F(ValidateIdWithMessage, OpConstantCompositeMatrixConstituentTypeBad) { CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpConstantComposite Constituent '10' vector " - "component count does not match Result Type '4's " - "vector component count.")); + HasSubstr("OpConstantComposite Constituent '10[%10]' vector " + "component count does not match Result Type " + "'4[%mat4v4float]'s vector component count.")); } TEST_F(ValidateIdWithMessage, OpConstantCompositeMatrixConstituentUndefTypeBad) { @@ -1034,9 +1304,9 @@ TEST_F(ValidateIdWithMessage, CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpConstantComposite Constituent '10' vector " - "component count does not match Result Type '4's " - "vector component count.")); + HasSubstr("OpConstantComposite Constituent '10[%10]' vector " + "component count does not match Result Type " + "'4[%mat4v4float]'s vector component count.")); } TEST_F(ValidateIdWithMessage, OpConstantCompositeArrayGood) { std::string spirv = kGLSL450MemoryModel + R"( @@ -1057,16 +1327,30 @@ TEST_F(ValidateIdWithMessage, OpConstantCompositeArrayWithUndefGood) { CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); } -TEST_F(ValidateIdWithMessage, OpConstantCompositeArrayConstConstituentBad) { + +TEST_F(ValidateIdWithMessage, OpConstantCompositeArrayConstConstituentTypeBad) { std::string spirv = kGLSL450MemoryModel + R"( %1 = OpTypeInt 32 0 %2 = OpConstant %1 4 %3 = OpTypeArray %1 %2 %4 = OpConstantComposite %3 %2 %2 %2 %1)"; // Uses a type as operand + CompileSuccessfully(spirv.c_str()); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), HasSubstr("Operand 1[%uint] cannot be a " + "type")); +} +TEST_F(ValidateIdWithMessage, OpConstantCompositeArrayConstConstituentBad) { + std::string spirv = kGLSL450MemoryModel + R"( +%1 = OpTypeInt 32 0 +%2 = OpConstant %1 4 +%3 = OpTypeArray %1 %2 +%4 = OpTypePointer Uniform %1 +%5 = OpVariable %4 Uniform +%6 = OpConstantComposite %3 %2 %2 %2 %5)"; CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpConstantComposite Constituent '1' is not a " + HasSubstr("OpConstantComposite Constituent '5[%5]' is not a " "constant or undef.")); } TEST_F(ValidateIdWithMessage, OpConstantCompositeArrayConstituentTypeBad) { @@ -1080,8 +1364,10 @@ TEST_F(ValidateIdWithMessage, OpConstantCompositeArrayConstituentTypeBad) { CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpConstantComposite Constituent '5's type does " - "not match Result Type '3's array element type.")); + HasSubstr("OpConstantComposite Constituent " + "'5[%float_3_1400001]'s type does not match Result " + "Type '3[%_arr_uint_uint_4]'s array element " + "type.")); } TEST_F(ValidateIdWithMessage, OpConstantCompositeArrayConstituentUndefTypeBad) { std::string spirv = kGLSL450MemoryModel + R"( @@ -1094,8 +1380,10 @@ TEST_F(ValidateIdWithMessage, OpConstantCompositeArrayConstituentUndefTypeBad) { CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpConstantComposite Constituent '5's type does " - "not match Result Type '3's array element type.")); + HasSubstr("OpConstantComposite Constituent " + "'5[%5]'s type does not match Result " + "Type '3[%_arr_uint_uint_4]'s array element " + "type.")); } TEST_F(ValidateIdWithMessage, OpConstantCompositeStructGood) { std::string spirv = kGLSL450MemoryModel + R"( @@ -1130,8 +1418,9 @@ TEST_F(ValidateIdWithMessage, OpConstantCompositeStructMemberTypeBad) { CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpConstantComposite Constituent '5' type does " - "not match the Result Type '3's member type.")); + HasSubstr("OpConstantComposite Constituent " + "'5[%ulong_4300000000]' type does not match the " + "Result Type '3[%_struct_3]'s member type.")); } TEST_F(ValidateIdWithMessage, OpConstantCompositeStructMemberUndefTypeBad) { @@ -1145,8 +1434,9 @@ TEST_F(ValidateIdWithMessage, OpConstantCompositeStructMemberUndefTypeBad) { CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpConstantComposite Constituent '5' type does " - "not match the Result Type '3's member type.")); + HasSubstr("OpConstantComposite Constituent '5[%5]' type " + "does not match the Result Type '3[%_struct_3]'s " + "member type.")); } TEST_F(ValidateIdWithMessage, OpConstantSamplerGood) { @@ -1166,7 +1456,8 @@ TEST_F(ValidateIdWithMessage, OpConstantSamplerResultTypeBad) { EXPECT_THAT( getDiagnosticString(), HasSubstr( - "OpConstantSampler Result Type '1' is not a sampler type.")); + "OpConstantSampler Result Type '1[%float]' is not a sampler " + "type.")); } TEST_F(ValidateIdWithMessage, OpConstantNullGood) { @@ -1213,8 +1504,8 @@ TEST_F(ValidateIdWithMessage, OpConstantNullBasicBad) { EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), - HasSubstr( - "OpConstantNull Result Type '1' cannot have a null value.")); + HasSubstr("OpConstantNull Result Type '1[%void]' cannot have a null " + "value.")); } TEST_F(ValidateIdWithMessage, OpConstantNullArrayBad) { @@ -1229,7 +1520,8 @@ TEST_F(ValidateIdWithMessage, OpConstantNullArrayBad) { EXPECT_THAT( getDiagnosticString(), HasSubstr( - "OpConstantNull Result Type '4' cannot have a null value.")); + "OpConstantNull Result Type '4[%_arr_2_uint_4]' cannot have a " + "null value.")); } TEST_F(ValidateIdWithMessage, OpConstantNullStructBad) { @@ -1239,10 +1531,9 @@ TEST_F(ValidateIdWithMessage, OpConstantNullStructBad) { %4 = OpConstantNull %3)"; CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr( - "OpConstantNull Result Type '2' cannot have a null value.")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("OpConstantNull Result Type '2[%_struct_2]' " + "cannot have a null value.")); } TEST_F(ValidateIdWithMessage, OpConstantNullRuntimeArrayBad) { @@ -1255,7 +1546,8 @@ TEST_F(ValidateIdWithMessage, OpConstantNullRuntimeArrayBad) { EXPECT_THAT( getDiagnosticString(), HasSubstr( - "OpConstantNull Result Type '2' cannot have a null value.")); + "OpConstantNull Result Type '2[%_runtimearr_bool]' cannot have " + "a null value.")); } TEST_F(ValidateIdWithMessage, OpSpecConstantTrueGood) { @@ -1272,7 +1564,8 @@ TEST_F(ValidateIdWithMessage, OpSpecConstantTrueBad) { CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("Specialization constant must be a boolean type.")); + HasSubstr("OpSpecConstantTrue Result Type '1[%void]' is not " + "a boolean type")); } TEST_F(ValidateIdWithMessage, OpSpecConstantFalseGood) { @@ -1288,8 +1581,10 @@ TEST_F(ValidateIdWithMessage, OpSpecConstantFalseBad) { %2 = OpSpecConstantFalse %1)"; CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("Specialization constant must be a boolean type.")); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("OpSpecConstantFalse Result Type '1[%void]' is not " + "a boolean type")); } TEST_F(ValidateIdWithMessage, OpSpecConstantGood) { @@ -1361,9 +1656,9 @@ TEST_F(ValidateIdWithMessage, OpSpecConstantCompositeVectorConstituentTypeBad) { CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpSpecConstantComposite Constituent '5's type " - "does not match Result Type '2's vector element " - "type.")); + HasSubstr("OpSpecConstantComposite Constituent " + "'5[%uint_42]'s type does not match Result Type " + "'2[%v4float]'s vector element type.")); } // Invalid: Constituent is not a constant @@ -1374,12 +1669,14 @@ TEST_F(ValidateIdWithMessage, %2 = OpTypeVector %1 4 %3 = OpTypeInt 32 0 %4 = OpSpecConstant %1 3.14 -%6 = OpSpecConstantComposite %2 %3 %4 %4 %4)"; +%5 = OpTypePointer Uniform %1 +%6 = OpVariable %5 Uniform +%7 = OpSpecConstantComposite %2 %6 %4 %4 %4)"; CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpSpecConstantComposite Constituent '3' is not a " - "constant or undef.")); + HasSubstr("OpSpecConstantComposite Constituent '6[%6]' is " + "not a constant or undef.")); } // Invalid: Vector contains a mix of Undef-int and Float. @@ -1395,9 +1692,9 @@ TEST_F(ValidateIdWithMessage, CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpSpecConstantComposite Constituent '5's type " - "does not match Result Type '2's vector element " - "type.")); + HasSubstr("OpSpecConstantComposite Constituent '5[%5]'s " + "type does not match Result Type '2[%v4float]'s " + "vector element type.")); } // Invalid: Vector expects 3 components, but 4 specified. @@ -1412,8 +1709,8 @@ TEST_F(ValidateIdWithMessage, OpSpecConstantCompositeVectorNumComponentsBad) { EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("OpSpecConstantComposite Constituent count does " - "not match Result Type '2's vector component " - "count.")); + "not match Result Type '2[%v3float]'s vector " + "component count.")); } // Valid: 4x4 matrix of floats @@ -1467,9 +1764,9 @@ TEST_F(ValidateIdWithMessage, OpSpecConstantCompositeMatrixConstituentTypeBad) { CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpSpecConstantComposite Constituent '10' vector " - "component count does not match Result Type '4's " - "vector component count.")); + HasSubstr("OpSpecConstantComposite Constituent '10[%10]' " + "vector component count does not match Result Type " + " '4[%mat4v4float]'s vector component count.")); } // Invalid: Matrix type expects 4 columns but only 3 specified. @@ -1489,7 +1786,8 @@ TEST_F(ValidateIdWithMessage, OpSpecConstantCompositeMatrixNumColsBad) { EXPECT_THAT( getDiagnosticString(), HasSubstr("OpSpecConstantComposite Constituent count does " - "not match Result Type '3's matrix column count.")); + "not match Result Type '3[%mat4v4float]'s matrix column " + "count.")); } // Invalid: Composite contains a non-const/undef component @@ -1501,12 +1799,14 @@ TEST_F(ValidateIdWithMessage, %3 = OpTypeVector %1 4 %4 = OpTypeMatrix %3 4 %5 = OpSpecConstantComposite %3 %2 %2 %2 %2 - %6 = OpSpecConstantComposite %4 %5 %5 %5 %1)"; + %6 = OpTypePointer Uniform %1 + %7 = OpVariable %6 Uniform + %8 = OpSpecConstantComposite %4 %5 %5 %5 %7)"; CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpSpecConstantComposite Constituent '1' is not a " - "constant composite or undef.")); + HasSubstr("OpSpecConstantComposite Constituent '7[%7]' is " + "not a constant or undef.")); } // Invalid: Composite contains a column that is *not* a vector (it's an array) @@ -1525,9 +1825,9 @@ TEST_F(ValidateIdWithMessage, OpSpecConstantCompositeMatrixColTypeBad) { CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpSpecConstantComposite Constituent '8' type " - "does not match Result Type '7's matrix column " - "type.")); + HasSubstr("OpSpecConstantComposite Constituent '8[%8]' type " + "does not match Result Type '7[%mat4v4float]'s " + "matrix column type.")); } // Invalid: Matrix with an Undef column of the wrong size. @@ -1548,9 +1848,9 @@ TEST_F(ValidateIdWithMessage, CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpSpecConstantComposite Constituent '10' vector " - "component count does not match Result Type '4's " - "vector component count.")); + HasSubstr("OpSpecConstantComposite Constituent '10[%10]' " + "vector component count does not match Result Type " + " '4[%mat4v4float]'s vector component count.")); } // Invalid: Matrix in which some columns are Int and some are Float. @@ -1569,9 +1869,9 @@ TEST_F(ValidateIdWithMessage, OpSpecConstantCompositeMatrixColumnTypeBad) { CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpSpecConstantComposite Constituent '8' " - "component type does not match Result Type '5's " - "matrix column component type.")); + HasSubstr("OpSpecConstantComposite Constituent '8[%8]' " + "component type does not match Result Type " + "'5[%mat2v2float]'s matrix column component type.")); } // Valid: Array of integers @@ -1599,7 +1899,8 @@ TEST_F(ValidateIdWithMessage, OpSpecConstantCompositeArrayNumComponentsBad) { EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("OpSpecConstantComposite Constituent count does not " - "match Result Type '3's array length.")); + "match Result Type '3[%_arr_uint_uint_4]'s array " + "length.")); } // Valid: Array of Integers and Undef-int @@ -1620,12 +1921,14 @@ TEST_F(ValidateIdWithMessage, OpSpecConstantCompositeArrayConstConstituentBad) { %1 = OpTypeInt 32 0 %2 = OpConstant %1 4 %3 = OpTypeArray %1 %2 -%4 = OpSpecConstantComposite %3 %2 %2 %2 %1)"; +%4 = OpTypePointer Uniform %1 +%5 = OpVariable %4 Uniform +%6 = OpSpecConstantComposite %3 %2 %2 %2 %5)"; CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpSpecConstantComposite Constituent '1' is not a " - "constant or undef.")); + HasSubstr("OpSpecConstantComposite Constituent '5[%5]' is " + "not a constant or undef.")); } // Invalid: Array has a mix of Int and Float components. @@ -1640,9 +1943,9 @@ TEST_F(ValidateIdWithMessage, OpSpecConstantCompositeArrayConstituentTypeBad) { CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpSpecConstantComposite Constituent '5's type " - "does not match Result Type '3's array element " - "type.")); + HasSubstr("OpSpecConstantComposite Constituent '5[%5]'s " + "type does not match Result Type " + "'3[%_arr_uint_uint_4]'s array element type.")); } // Invalid: Array has a mix of Int and Undef-float. @@ -1658,9 +1961,9 @@ TEST_F(ValidateIdWithMessage, CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpSpecConstantComposite Constituent '5's type " - "does not match Result Type '3's array element " - "type.")); + HasSubstr("OpSpecConstantComposite Constituent '5[%5]'s " + "type does not match Result Type " + "'3[%_arr_uint_2]'s array element type.")); } // Valid: Struct of {Int32,Int32,Int64}. @@ -1688,9 +1991,9 @@ TEST_F(ValidateIdWithMessage, CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpSpecConstantComposite Constituent '2' count " - "does not match Result Type '2's struct member " - "count.")); + HasSubstr("OpSpecConstantComposite Constituent " + "'2[%_struct_2]' count does not match Result Type " + " '2[%_struct_2]'s struct member count.")); } // Valid: Struct uses Undef-int64. @@ -1714,12 +2017,14 @@ TEST_F(ValidateIdWithMessage, OpSpecConstantCompositeStructNonConstBad) { %3 = OpTypeStruct %1 %1 %2 %4 = OpSpecConstant %1 42 %5 = OpUndef %2 -%6 = OpSpecConstantComposite %3 %4 %1 %5)"; +%6 = OpTypePointer Uniform %1 +%7 = OpVariable %6 Uniform +%8 = OpSpecConstantComposite %3 %4 %7 %5)"; CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpSpecConstantComposite Constituent '1' is not a " - "constant or undef.")); + HasSubstr("OpSpecConstantComposite Constituent '7[%7]' is " + "not a constant or undef.")); } // Invalid: Struct component type does not match expected specialization type. @@ -1735,9 +2040,9 @@ TEST_F(ValidateIdWithMessage, OpSpecConstantCompositeStructMemberTypeBad) { CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpSpecConstantComposite Constituent '5' type " - "does not match the Result Type '3's member " - "type.")); + HasSubstr("OpSpecConstantComposite Constituent '5[%5]' type " + "does not match the Result Type '3[%_struct_3]'s " + "member type.")); } // Invalid: Undef-int64 used when Int32 was expected. @@ -1752,9 +2057,9 @@ TEST_F(ValidateIdWithMessage, OpSpecConstantCompositeStructMemberUndefTypeBad) { CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpSpecConstantComposite Constituent '5' type " - "does not match the Result Type '3's member " - "type.")); + HasSubstr("OpSpecConstantComposite Constituent '5[%5]' type " + "does not match the Result Type '3[%_struct_3]'s " + "member type.")); } // TODO: OpSpecConstantOp @@ -1781,8 +2086,9 @@ TEST_F(ValidateIdWithMessage, OpVariableInitializerGlobalVariableGood) { %1 = OpTypeInt 32 0 %2 = OpTypePointer Uniform %1 %3 = OpVariable %2 Uniform -%4 = OpTypePointer Uniform %2 ; pointer to pointer -%5 = OpVariable %4 Uniform %3)"; +%4 = OpTypePointer Private %2 ; pointer to pointer +%5 = OpVariable %4 Private %3 +)"; CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); } @@ -1795,7 +2101,8 @@ TEST_F(ValidateIdWithMessage, OpVariableResultTypeBad) { EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), - HasSubstr("OpVariable Result Type '1' is not a pointer type.")); + HasSubstr("OpVariable Result Type '1[%uint]' is not a pointer " + "type.")); } TEST_F(ValidateIdWithMessage, OpVariableInitializerIsTypeBad) { std::string spirv = kGLSL450MemoryModel + R"( @@ -1804,9 +2111,8 @@ TEST_F(ValidateIdWithMessage, OpVariableInitializerIsTypeBad) { %3 = OpVariable %2 Input %2)"; CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpVariable Initializer '2' is not a constant or " - "module-scope variable")); + EXPECT_THAT(getDiagnosticString(), HasSubstr("Operand 2[%_ptr_Input_uint] " + "cannot be a type")); } TEST_F(ValidateIdWithMessage, OpVariableInitializerIsFunctionVarBad) { @@ -1826,8 +2132,8 @@ OpFunctionEnd CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpVariable Initializer '8' is not a constant or " - "module-scope variable")); + HasSubstr("OpVariable Initializer '8[%8]' is not a constant " + "or module-scope variable")); } TEST_F(ValidateIdWithMessage, OpVariableInitializerIsModuleVarGood) { @@ -1848,6 +2154,250 @@ OpFunctionEnd EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); } +TEST_F(ValidateIdWithMessage, OpVariableContainsBoolBad) { + std::string spirv = kGLSL450MemoryModel + R"( +%bool = OpTypeBool +%int = OpTypeInt 32 0 +%block = OpTypeStruct %bool %int +%_ptr_Uniform_block = OpTypePointer Uniform %block +%var = OpVariable %_ptr_Uniform_block Uniform +%void = OpTypeVoid +%fnty = OpTypeFunction %void +%main = OpFunction %void None %fnty +%entry = OpLabel +%load = OpLoad %block %var +OpReturn +OpFunctionEnd +)"; + CompileSuccessfully(spirv.c_str()); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("If OpTypeBool is stored in conjunction with OpVariable" + ", it can only be used with non-externally visible " + "shader Storage Classes: Workgroup, CrossWorkgroup, " + "Private, and Function")); +} + +TEST_F(ValidateIdWithMessage, OpVariableContainsBoolPointerGood) { + std::string spirv = kGLSL450MemoryModel + R"( +%bool = OpTypeBool +%boolptr = OpTypePointer Uniform %bool +%int = OpTypeInt 32 0 +%block = OpTypeStruct %boolptr %int +%_ptr_Uniform_block = OpTypePointer Uniform %block +%var = OpVariable %_ptr_Uniform_block Uniform +%void = OpTypeVoid +%fnty = OpTypeFunction %void +%main = OpFunction %void None %fnty +%entry = OpLabel +%load = OpLoad %block %var +OpReturn +OpFunctionEnd +)"; + CompileSuccessfully(spirv.c_str()); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateIdWithMessage, OpVariableContainsBuiltinBoolGood) { + std::string spirv = kGLSL450MemoryModel + R"( +OpMemberDecorate %input 0 BuiltIn FrontFacing +%bool = OpTypeBool +%input = OpTypeStruct %bool +%_ptr_input = OpTypePointer Input %input +%var = OpVariable %_ptr_input Input +%void = OpTypeVoid +%fnty = OpTypeFunction %void +%main = OpFunction %void None %fnty +%entry = OpLabel +%load = OpLoad %input %var +OpReturn +OpFunctionEnd +)"; + CompileSuccessfully(spirv.c_str()); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateIdWithMessage, OpVariableContainsRayPayloadBoolGood) { + std::string spirv = R"( +OpCapability RayTracingNV +OpCapability Shader +OpCapability Linkage +OpExtension "SPV_NV_ray_tracing" +OpMemoryModel Logical GLSL450 +%bool = OpTypeBool +%PerRayData = OpTypeStruct %bool +%_ptr_PerRayData = OpTypePointer RayPayloadNV %PerRayData +%var = OpVariable %_ptr_PerRayData RayPayloadNV +%void = OpTypeVoid +%fnty = OpTypeFunction %void +%main = OpFunction %void None %fnty +%entry = OpLabel +%load = OpLoad %PerRayData %var +OpReturn +OpFunctionEnd +)"; + CompileSuccessfully(spirv.c_str()); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateIdWithMessage, OpVariablePointerNoVariablePointersBad) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%_ptr_workgroup_int = OpTypePointer Workgroup %int +%_ptr_function_ptr = OpTypePointer Function %_ptr_workgroup_int +%voidfn = OpTypeFunction %void +%func = OpFunction %void None %voidfn +%entry = OpLabel +%var = OpVariable %_ptr_function_ptr Function +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "In Logical addressing, variables may not allocate a pointer type")); +} + +TEST_F(ValidateIdWithMessage, + OpVariablePointerNoVariablePointersRelaxedLogicalGood) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%_ptr_workgroup_int = OpTypePointer Workgroup %int +%_ptr_function_ptr = OpTypePointer Function %_ptr_workgroup_int +%voidfn = OpTypeFunction %void +%func = OpFunction %void None %voidfn +%entry = OpLabel +%var = OpVariable %_ptr_function_ptr Function +OpReturn +OpFunctionEnd +)"; + + auto options = getValidatorOptions(); + options->relax_logical_pointer = true; + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateIdWithMessage, OpFunctionWithNonMemoryObject) { + // DXC generates code that looks like when given something like: + // T t; + // t.s.fn_1(); + // This needs to be accepted before legalization takes place, so we + // will include it with the relaxed logical pointer. + + const std::string spirv = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %1 "main" + OpSource HLSL 600 + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 + %void = OpTypeVoid + %9 = OpTypeFunction %void + %_struct_5 = OpTypeStruct + %_struct_6 = OpTypeStruct %_struct_5 +%_ptr_Function__struct_6 = OpTypePointer Function %_struct_6 +%_ptr_Function__struct_5 = OpTypePointer Function %_struct_5 + %23 = OpTypeFunction %void %_ptr_Function__struct_5 + %1 = OpFunction %void None %9 + %10 = OpLabel + %11 = OpVariable %_ptr_Function__struct_6 Function + %20 = OpAccessChain %_ptr_Function__struct_5 %11 %int_0 + %21 = OpFunctionCall %void %12 %20 + OpReturn + OpFunctionEnd + %12 = OpFunction %void None %23 + %13 = OpFunctionParameter %_ptr_Function__struct_5 + %14 = OpLabel + OpReturn + OpFunctionEnd +)"; + + auto options = getValidatorOptions(); + options->relax_logical_pointer = true; + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateIdWithMessage, + OpVariablePointerVariablePointersStorageBufferGood) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability VariablePointersStorageBuffer +OpExtension "SPV_KHR_variable_pointers" +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%_ptr_workgroup_int = OpTypePointer Workgroup %int +%_ptr_function_ptr = OpTypePointer Function %_ptr_workgroup_int +%voidfn = OpTypeFunction %void +%func = OpFunction %void None %voidfn +%entry = OpLabel +%var = OpVariable %_ptr_function_ptr Function +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateIdWithMessage, OpVariablePointerVariablePointersGood) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability VariablePointers +OpExtension "SPV_KHR_variable_pointers" +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%_ptr_workgroup_int = OpTypePointer Workgroup %int +%_ptr_function_ptr = OpTypePointer Function %_ptr_workgroup_int +%voidfn = OpTypeFunction %void +%func = OpFunction %void None %voidfn +%entry = OpLabel +%var = OpVariable %_ptr_function_ptr Function +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateIdWithMessage, OpVariablePointerVariablePointersBad) { + const std::string spirv = R"( +OpCapability Shader +OpCapability VariablePointers +OpExtension "SPV_KHR_variable_pointers" +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%_ptr_workgroup_int = OpTypePointer Workgroup %int +%_ptr_uniform_ptr = OpTypePointer Uniform %_ptr_workgroup_int +%var = OpVariable %_ptr_uniform_ptr Uniform +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("In Logical addressing with variable pointers, " + "variables that allocate pointers must be in Function " + "or Private storage classes")); +} + TEST_F(ValidateIdWithMessage, OpLoadGood) { std::string spirv = kGLSL450MemoryModel + R"( %1 = OpTypeVoid @@ -1858,8 +2408,8 @@ TEST_F(ValidateIdWithMessage, OpLoadGood) { %6 = OpFunction %1 None %4 %7 = OpLabel %8 = OpLoad %2 %5 - %9 = OpReturn -%10 = OpFunctionEnd + OpReturn + OpFunctionEnd )"; CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); @@ -1876,6 +2426,7 @@ void createVariablePointerSpirvProgram(std::ostringstream* spirv, *spirv << "OpCapability VariablePointers "; *spirv << "OpExtension \"SPV_KHR_variable_pointers\" "; } + *spirv << "OpExtension \"SPV_KHR_storage_buffer_storage_class\" "; *spirv << R"( OpMemoryModel Logical GLSL450 OpEntryPoint GLCompute %main "main" @@ -1884,12 +2435,12 @@ void createVariablePointerSpirvProgram(std::ostringstream* spirv, %bool = OpTypeBool %i32 = OpTypeInt 32 1 %f32 = OpTypeFloat 32 - %f32ptr = OpTypePointer Uniform %f32 + %f32ptr = OpTypePointer StorageBuffer %f32 %i = OpConstant %i32 1 %zero = OpConstant %i32 0 %float_1 = OpConstant %f32 1.0 - %ptr1 = OpVariable %f32ptr Uniform - %ptr2 = OpVariable %f32ptr Uniform + %ptr1 = OpVariable %f32ptr StorageBuffer + %ptr2 = OpVariable %f32ptr StorageBuffer )"; if (add_helper_function) { *spirv << R"( @@ -1979,9 +2530,9 @@ TEST_F(ValidateIdWithMessage, OpLoadVarPtrOpPhiGood) { EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); } -// Without the VariablePointers Capability, OpLoad will not allow loading -// through a variable pointer. -TEST_F(ValidateIdWithMessage, OpLoadVarPtrOpPhiBad) { +// Without the VariablePointers Capability, OpPhi can have a pointer result +// type. +TEST_F(ValidateIdWithMessage, OpPhiBad) { std::string result_strategy = R"( %is_neg = OpSLessThan %bool %i %zero OpSelectionMerge %end_label None @@ -2000,8 +2551,10 @@ TEST_F(ValidateIdWithMessage, OpLoadVarPtrOpPhiBad) { false /* Add VariablePointers Capability?*/, false /* Use Helper Function? */); CompileSuccessfully(spirv.str()); - EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), HasSubstr("is not a logical pointer")); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Using pointers with OpPhi requires capability " + "VariablePointers or VariablePointersStorageBuffer")); } // With the VariablePointer Capability, OpLoad should allow loading through a @@ -2038,8 +2591,9 @@ TEST_F(ValidateIdWithMessage, OpLoadResultTypeBad) { CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpLoad Result Type '3' does not match Pointer " - " '5's type.")); + HasSubstr("OpLoad Result Type " + "'3[%_ptr_UniformConstant_uint]' does not match " + "Pointer '5[%5]'s type.")); } TEST_F(ValidateIdWithMessage, OpLoadPointerBad) { @@ -2058,7 +2612,8 @@ TEST_F(ValidateIdWithMessage, OpLoadPointerBad) { EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); // Prove that SSA checks trigger for a bad Id value. // The next test case show the not-a-logical-pointer case. - EXPECT_THAT(getDiagnosticString(), HasSubstr("ID 8 has not been defined")); + EXPECT_THAT(getDiagnosticString(), HasSubstr("ID 8[%8] has not been " + "defined")); } // Disabled as bitcasting type to object is now not valid. @@ -2094,7 +2649,7 @@ TEST_F(ValidateIdWithMessage, OpStoreGood) { %3 = OpTypePointer Uniform %2 %4 = OpTypeFunction %1 %5 = OpConstant %2 42 -%6 = OpVariable %3 UniformConstant +%6 = OpVariable %3 Uniform %7 = OpFunction %1 None %4 %8 = OpLabel OpStore %6 %5 @@ -2111,15 +2666,17 @@ TEST_F(ValidateIdWithMessage, OpStorePointerBad) { %4 = OpTypeFunction %1 %5 = OpConstant %2 42 %6 = OpVariable %3 UniformConstant -%7 = OpFunction %1 None %4 -%8 = OpLabel - OpStore %3 %5 +%7 = OpConstant %2 0 +%8 = OpFunction %1 None %4 +%9 = OpLabel + OpStore %7 %5 OpReturn OpFunctionEnd)"; CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpStore Pointer '3' is not a logical pointer.")); + HasSubstr("OpStore Pointer '7[%uint_0]' is not a logical " + "pointer.")); } // Disabled as bitcasting type to object is now not valid. @@ -2189,7 +2746,7 @@ TEST_F(ValidateIdWithMessage, OpStoreObjectGood) { %3 = OpTypePointer Uniform %2 %4 = OpTypeFunction %1 %5 = OpConstant %2 42 -%6 = OpVariable %3 UniformConstant +%6 = OpVariable %3 Uniform %7 = OpFunction %1 None %4 %8 = OpLabel %9 = OpUndef %1 @@ -2199,7 +2756,7 @@ TEST_F(ValidateIdWithMessage, OpStoreObjectGood) { CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpStore Object '9's type is void.")); + HasSubstr("OpStore Object '9[%9]'s type is void.")); } TEST_F(ValidateIdWithMessage, OpStoreTypeBad) { std::string spirv = kGLSL450MemoryModel + R"( @@ -2209,7 +2766,7 @@ TEST_F(ValidateIdWithMessage, OpStoreTypeBad) { %3 = OpTypePointer Uniform %2 %4 = OpTypeFunction %1 %5 = OpConstant %9 3.14 -%6 = OpVariable %3 UniformConstant +%6 = OpVariable %3 Uniform %7 = OpFunction %1 None %4 %8 = OpLabel OpStore %6 %5 @@ -2218,8 +2775,8 @@ TEST_F(ValidateIdWithMessage, OpStoreTypeBad) { CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpStore Pointer '7's type does not match Object " - " '6's type.")); + HasSubstr("OpStore Pointer '7[%7]'s type does not match " + "Object '6[%float_3_1400001]'s type.")); } // The next series of test check test a relaxation of the rules for stores to @@ -2251,8 +2808,8 @@ TEST_F(ValidateIdWithMessage, OpStoreTypeBadStruct) { CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpStore Pointer '8's type does not match Object " - " '11's type.")); + HasSubstr("OpStore Pointer '8[%8]'s type does not match " + "Object '11[%11]'s type.")); } // Same code as the last test. The difference is that we relax the rule. @@ -2382,8 +2939,8 @@ TEST_F(ValidateIdWithMessage, OpStoreTypeBadRelaxedStruct1) { EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), - HasSubstr("OpStore Pointer '13's layout does not match Object " - " '16's layout.")); + HasSubstr("OpStore Pointer '13[%13]'s layout does not match Object " + " '16[%16]'s layout.")); } // This test check that the even with the relaxed rules an error is identified @@ -2422,8 +2979,8 @@ TEST_F(ValidateIdWithMessage, OpStoreTypeBadRelaxedStruct2) { EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), - HasSubstr("OpStore Pointer '13's layout does not match Object " - " '16's layout.")); + HasSubstr("OpStore Pointer '13[%13]'s layout does not match Object " + " '16[%16]'s layout.")); } TEST_F(ValidateIdWithMessage, OpStoreTypeRelaxedLogicalPointerReturnPointer) { @@ -2474,7 +3031,7 @@ TEST_F(ValidateIdWithMessage, OpStoreVoid) { %2 = OpTypeInt 32 0 %3 = OpTypePointer Uniform %2 %4 = OpTypeFunction %1 -%6 = OpVariable %3 UniformConstant +%6 = OpVariable %3 Uniform %7 = OpFunction %1 None %4 %8 = OpLabel %9 = OpFunctionCall %1 %7 @@ -2484,7 +3041,7 @@ TEST_F(ValidateIdWithMessage, OpStoreVoid) { CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpStore Object '8's type is void.")); + HasSubstr("OpStore Object '8[%8]'s type is void.")); } TEST_F(ValidateIdWithMessage, OpStoreLabel) { @@ -2493,7 +3050,7 @@ TEST_F(ValidateIdWithMessage, OpStoreLabel) { %2 = OpTypeInt 32 0 %3 = OpTypePointer Uniform %2 %4 = OpTypeFunction %1 -%6 = OpVariable %3 UniformConstant +%6 = OpVariable %3 Uniform %7 = OpFunction %1 None %4 %8 = OpLabel OpStore %6 %8 @@ -2502,7 +3059,7 @@ TEST_F(ValidateIdWithMessage, OpStoreLabel) { CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpStore Object '7' is not an object.")); + HasSubstr("Operand 7[%7] requires a type")); } // TODO: enable when this bug is fixed: @@ -2599,7 +3156,7 @@ OpFunctionEnd CompileSuccessfully(spirv); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("Target operand '6' is not a pointer.")); + HasSubstr("Target operand '6[%6]' is not a pointer.")); } TEST_F(ValidateIdWithMessage, OpCopyMemoryNonPointerSource) { @@ -2620,7 +3177,7 @@ OpFunctionEnd CompileSuccessfully(spirv); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("Source operand '6' is not a pointer.")); + HasSubstr("Source operand '6[%6]' is not a pointer.")); } TEST_F(ValidateIdWithMessage, OpCopyMemoryBad) { @@ -2643,8 +3200,8 @@ TEST_F(ValidateIdWithMessage, OpCopyMemoryBad) { CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("Target '5's type does not match " - "Source '2's type.")); + HasSubstr("Target '5[%5]'s type does not match " + "Source '2[%uint]'s type.")); } TEST_F(ValidateIdWithMessage, OpCopyMemoryVoidTarget) { @@ -2666,7 +3223,8 @@ OpFunctionEnd CompileSuccessfully(spirv); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("Target operand '7' cannot be a void pointer.")); + HasSubstr("Target operand '7[%7]' cannot be a void " + "pointer.")); } TEST_F(ValidateIdWithMessage, OpCopyMemoryVoidSource) { @@ -2688,7 +3246,8 @@ OpFunctionEnd CompileSuccessfully(spirv); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("Source operand '7' cannot be a void pointer.")); + HasSubstr("Source operand '7[%7]' cannot be a void " + "pointer.")); } TEST_F(ValidateIdWithMessage, OpCopyMemorySizedGood) { @@ -2720,13 +3279,13 @@ TEST_F(ValidateIdWithMessage, OpCopyMemorySizedTargetBad) { %7 = OpTypeFunction %1 %8 = OpFunction %1 None %7 %9 = OpLabel - OpCopyMemorySized %9 %6 %5 None + OpCopyMemorySized %5 %5 %5 None OpReturn OpFunctionEnd)"; CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("Target operand '9' is not a pointer.")); + HasSubstr("Target operand '5[%uint_4]' is not a pointer.")); } TEST_F(ValidateIdWithMessage, OpCopyMemorySizedSourceBad) { std::string spirv = kGLSL450MemoryModel + R"( @@ -2739,13 +3298,13 @@ TEST_F(ValidateIdWithMessage, OpCopyMemorySizedSourceBad) { %7 = OpFunction %1 None %6 %8 = OpLabel %9 = OpVariable %4 Function - OpCopyMemorySized %9 %6 %5 None + OpCopyMemorySized %9 %5 %5 None OpReturn OpFunctionEnd)"; CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("Source operand '6' is not a pointer.")); + HasSubstr("Source operand '5[%uint_4]' is not a pointer.")); } TEST_F(ValidateIdWithMessage, OpCopyMemorySizedSizeBad) { std::string spirv = kGLSL450MemoryModel + R"( @@ -2766,7 +3325,7 @@ TEST_F(ValidateIdWithMessage, OpCopyMemorySizedSizeBad) { EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), - HasSubstr("Size operand '6' must be a scalar integer type.")); + HasSubstr("Size operand '6[%6]' must be a scalar integer type.")); } TEST_F(ValidateIdWithMessage, OpCopyMemorySizedSizeTypeBad) { std::string spirv = kGLSL450MemoryModel + R"( @@ -2789,7 +3348,8 @@ TEST_F(ValidateIdWithMessage, OpCopyMemorySizedSizeTypeBad) { EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), - HasSubstr("Size operand '9' must be a scalar integer type.")); + HasSubstr("Size operand '9[%float_1]' must be a scalar integer " + "type.")); } TEST_F(ValidateIdWithMessage, OpCopyMemorySizedSizeConstantNull) { @@ -2813,7 +3373,8 @@ OpFunctionEnd CompileSuccessfully(spirv); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("Size operand '3' cannot be a constant zero.")); + HasSubstr("Size operand '3[%3]' cannot be a constant " + "zero.")); } TEST_F(ValidateIdWithMessage, OpCopyMemorySizedSizeConstantZero) { @@ -2837,7 +3398,8 @@ OpFunctionEnd CompileSuccessfully(spirv); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("Size operand '3' cannot be a constant zero.")); + HasSubstr("Size operand '3[%uint_0]' cannot be a constant " + "zero.")); } TEST_F(ValidateIdWithMessage, OpCopyMemorySizedSizeConstantZero64) { @@ -2861,7 +3423,8 @@ OpFunctionEnd CompileSuccessfully(spirv); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("Size operand '3' cannot be a constant zero.")); + HasSubstr("Size operand '3[%ulong_0]' cannot be a constant " + "zero.")); } TEST_F(ValidateIdWithMessage, OpCopyMemorySizedSizeConstantNegative) { @@ -2886,7 +3449,8 @@ OpFunctionEnd EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), - HasSubstr("Size operand '3' cannot have the sign bit set to 1.")); + HasSubstr("Size operand '3[%int_n1]' cannot have the sign bit set " + "to 1.")); } TEST_F(ValidateIdWithMessage, OpCopyMemorySizedSizeConstantNegative64) { @@ -2911,7 +3475,8 @@ OpFunctionEnd EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), - HasSubstr("Size operand '3' cannot have the sign bit set to 1.")); + HasSubstr("Size operand '3[%long_n1]' cannot have the sign bit set " + "to 1.")); } TEST_F(ValidateIdWithMessage, OpCopyMemorySizedSizeUnsignedNegative) { @@ -2991,15 +3556,14 @@ const char kDeeplyNestedStructureSetup[] = R"( ; } %f32arr = OpTypeRuntimeArray %float -%bool = OpTypeBool %v4float = OpTypeVector %float 4 %array5_mat4x3 = OpTypeArray %mat4x3 %int_5 %array5_vec4 = OpTypeArray %v4float %int_5 %_ptr_Uniform_float = OpTypePointer Uniform %float %_ptr_Function_vec4 = OpTypePointer Function %v4float %_ptr_Uniform_vec4 = OpTypePointer Uniform %v4float -%struct_s = OpTypeStruct %bool %array5_vec4 %int %array5_mat4x3 -%struct_blockName = OpTypeStruct %struct_s %bool %f32arr +%struct_s = OpTypeStruct %int %array5_vec4 %int %array5_mat4x3 +%struct_blockName = OpTypeStruct %struct_s %int %f32arr %_ptr_Uniform_blockName = OpTypePointer Uniform %struct_blockName %_ptr_Uniform_struct_s = OpTypePointer Uniform %struct_s %_ptr_Uniform_array5_mat4x3 = OpTypePointer Uniform %array5_mat4x3 @@ -3007,6 +3571,7 @@ const char kDeeplyNestedStructureSetup[] = R"( %_ptr_Uniform_v3float = OpTypePointer Uniform %v3float %blockName_var = OpVariable %_ptr_Uniform_blockName Uniform %spec_int = OpSpecConstant %int 2 +%float_0 = OpConstant %float 0 %func = OpFunction %void None %void_f %my_label = OpLabel )"; @@ -3051,7 +3616,7 @@ OpFunctionEnd )"; const std::string expected_err = "The Result Type of " + instr + - " '36' must be " + " '36[%36]' must be " "OpTypePointer. Found OpTypeFloat."; CompileSuccessfully(spirv); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); @@ -3069,12 +3634,10 @@ TEST_P(AccessChainInstructionTest, AccessChainBaseTypeVoidBad) { OpReturn OpFunctionEnd )"; - const std::string expected_err = "The Base '1' in " + instr + - " instruction must " - "be a pointer."; CompileSuccessfully(spirv); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), HasSubstr(expected_err)); + EXPECT_THAT(getDiagnosticString(), HasSubstr("Operand 1[%void] cannot be a " + "type")); } // Invalid. The base type of an access chain instruction must be a pointer. @@ -3089,12 +3652,10 @@ TEST_P(AccessChainInstructionTest, AccessChainBaseTypeNonPtrVariableBad) { OpReturn OpFunctionEnd )"; - const std::string expected_err = "The Base '8' in " + instr + - " instruction must " - "be a pointer."; CompileSuccessfully(spirv); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), HasSubstr(expected_err)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Operand 8[%_ptr_Private_float] cannot be a type")); } // Invalid: The storage class of Base and Result do not match. @@ -3313,7 +3874,7 @@ TEST_P(AccessChainInstructionTest, AccessChainUndefinedIndexBad) { std::string spirv = kGLSL450MemoryModel + kDeeplyNestedStructureSetup + R"( %entry = )" + instr + R"( %_ptr_Private_float %my_matrix )" + elem + - R"(%float %int_1 + R"(%float_0 %int_1 OpReturn OpFunctionEnd )"; @@ -3397,8 +3958,8 @@ OpFunctionEnd )"; const std::string expected_err = "Index is out of bounds: " + instr + " can not find index 3 into the structure " - " '26'. This structure has 3 members. " - "Largest valid index is 2."; + " '25[%_struct_25]'. This structure " + "has 3 members. Largest valid index is 2."; CompileSuccessfully(spirv); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr(expected_err)); @@ -3510,7 +4071,7 @@ OpFunctionEnd } // Run tests for Access Chain Instructions. -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( CheckAccessChainInstructions, AccessChainInstructionTest, ::testing::Values("OpAccessChain", "OpInBoundsAccessChain", "OpPtrAccessChain", "OpInBoundsPtrAccessChain")); @@ -3544,8 +4105,9 @@ TEST_F(ValidateIdWithMessage, OpFunctionResultTypeBad) { CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpFunction Result Type '2' does not match the " - "Function Type's return type '1'.")); + HasSubstr("OpFunction Result Type '2[%uint]' does not " + "match the Function Type's return type " + "'1[%void]'.")); } TEST_F(ValidateIdWithMessage, OpReturnValueTypeBad) { std::string spirv = kGLSL450MemoryModel + R"( @@ -3560,8 +4122,8 @@ TEST_F(ValidateIdWithMessage, OpReturnValueTypeBad) { CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpReturnValue Value '3's type does not match " - "OpFunction's return type.")); + HasSubstr("OpReturnValue Value '3[%float_0]'s type does " + "not match OpFunction's return type.")); } TEST_F(ValidateIdWithMessage, OpFunctionFunctionTypeBad) { std::string spirv = kGLSL450MemoryModel + R"( @@ -3575,7 +4137,8 @@ OpFunctionEnd)"; EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), - HasSubstr("OpFunction Function Type '2' is not a function type.")); + HasSubstr("OpFunction Function Type '2[%uint]' is not a function " + "type.")); } TEST_F(ValidateIdWithMessage, OpFunctionUseBad) { @@ -3591,7 +4154,7 @@ OpFunctionEnd CompileSuccessfully(spirv); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("Invalid use of function result id 3.")); + HasSubstr("Invalid use of function result id 3[%3].")); } TEST_F(ValidateIdWithMessage, OpFunctionParameterGood) { @@ -3635,8 +4198,8 @@ TEST_F(ValidateIdWithMessage, OpFunctionParameterResultTypeBad) { EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), - HasSubstr("OpFunctionParameter Result Type '1' does not match the " - "OpTypeFunction parameter type of the same index.")); + HasSubstr("OpFunctionParameter Result Type '1[%void]' does not " + "match the OpTypeFunction parameter type of the same index.")); } TEST_F(ValidateIdWithMessage, OpFunctionCallGood) { @@ -3684,8 +4247,9 @@ TEST_F(ValidateIdWithMessage, OpFunctionCallResultTypeBad) { CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpFunctionCall Result Type '1's type does not " - "match Function '2's return type.")); + HasSubstr("OpFunctionCall Result Type '1[%void]'s type " + "does not match Function '2[%uint]'s return " + "type.")); } TEST_F(ValidateIdWithMessage, OpFunctionCallFunctionBad) { std::string spirv = kGLSL450MemoryModel + R"( @@ -3703,7 +4267,8 @@ TEST_F(ValidateIdWithMessage, OpFunctionCallFunctionBad) { CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpFunctionCall Function '5' is not a function.")); + HasSubstr("OpFunctionCall Function '5[%uint_42]' is not a " + "function.")); } TEST_F(ValidateIdWithMessage, OpFunctionCallArgumentTypeBad) { std::string spirv = kGLSL450MemoryModel + R"( @@ -3731,8 +4296,9 @@ TEST_F(ValidateIdWithMessage, OpFunctionCallArgumentTypeBad) { CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpFunctionCall Argument '7's type does not match " - "Function '2's parameter type.")); + HasSubstr("OpFunctionCall Argument '7[%float_3_1400001]'s " + "type does not match Function '2[%uint]'s " + "parameter type.")); } // Valid: OpSampledImage result is used in the same block by @@ -3763,8 +4329,8 @@ OpFunctionEnd)"; getDiagnosticString(), HasSubstr("All OpSampledImage instructions must be in the same block in " "which their Result are consumed. OpSampledImage Result " - "Type '23' has a consumer in a different basic block. The " - "consumer instruction is '25'.")); + "Type '23[%23]' has a consumer in a different basic " + "block. The consumer instruction is '25[%25]'.")); } // Invalid: OpSampledImage result is used by OpSelect @@ -3968,7 +4534,7 @@ TEST_F(ValidateIdWithMessage, OpVectorShuffleComponentCount) { EXPECT_THAT( getDiagnosticString(), HasSubstr("OpVectorShuffle component literals count does not match " - "Result Type '2's vector component count.")); + "Result Type '2[%v3uint]'s vector component count.")); } TEST_F(ValidateIdWithMessage, OpVectorShuffleVector1Type) { @@ -4111,6 +4677,39 @@ TEST_F(ValidateIdWithMessage, OpVectorShuffleLiterals) { "size of 5.")); } +TEST_F(ValidateIdWithMessage, WebGPUOpVectorShuffle0xFFFFFFFFLiteralBad) { + std::string spirv = R"( + OpCapability Shader + OpCapability VulkanMemoryModelKHR + OpExtension "SPV_KHR_vulkan_memory_model" + OpMemoryModel Logical VulkanKHR +%float = OpTypeFloat 32 +%vec2 = OpTypeVector %float 2 +%vec3 = OpTypeVector %float 3 +%vec4 = OpTypeVector %float 4 +%ptr_vec2 = OpTypePointer Function %vec2 +%ptr_vec3 = OpTypePointer Function %vec3 +%float_1 = OpConstant %float 1 +%float_2 = OpConstant %float 2 +%1 = OpConstantComposite %vec2 %float_2 %float_1 +%2 = OpConstantComposite %vec3 %float_1 %float_2 %float_2 +%3 = OpTypeFunction %vec4 +%4 = OpFunction %vec4 None %3 +%5 = OpLabel +%var = OpVariable %ptr_vec2 Function %1 +%var2 = OpVariable %ptr_vec3 Function %2 +%6 = OpLoad %vec2 %var +%7 = OpLoad %vec3 %var2 +%8 = OpVectorShuffle %vec4 %6 %7 4 3 1 0xffffffff + OpReturnValue %8 + OpFunctionEnd)"; + CompileSuccessfully(spirv.c_str(), SPV_ENV_WEBGPU_0); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Component literal at operand 3 cannot be 0xFFFFFFFF in" + " WebGPU execution environment.")); +} + // TODO: OpCompositeConstruct // TODO: OpCompositeExtract // TODO: OpCompositeInsert @@ -4212,8 +4811,8 @@ OpFunctionEnd CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpPhi's type 3 is not a type instruction.")); + EXPECT_THAT(getDiagnosticString(), HasSubstr("ID 3[%true] is not a type " + "id")); } TEST_F(ValidateIdWithMessage, OpPhiSamePredecessor) { @@ -4325,8 +4924,9 @@ OpFunctionEnd CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpPhi's result type 2 does not match incoming " - "value 6 type 5.")); + HasSubstr("OpPhi's result type 2[%bool] does not match " + "incoming value 6[%uint_0] type " + "5[%uint].")); } TEST_F(ValidateIdWithMessage, OpPhiPredecessorNotABlock) { @@ -4350,9 +4950,9 @@ OpFunctionEnd CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr("OpPhi's incoming basic block 3 is not an OpLabel.")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("OpPhi's incoming basic block 3[%true] is not an " + "OpLabel.")); } TEST_F(ValidateIdWithMessage, OpPhiNotAPredecessor) { @@ -4377,8 +4977,8 @@ OpFunctionEnd CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpPhi's incoming basic block 9 is not a " - "predecessor of 8.")); + HasSubstr("OpPhi's incoming basic block 9[%9] is not a " + "predecessor of 8[%8].")); } TEST_F(ValidateIdWithMessage, OpBranchConditionalGood) { @@ -4471,6 +5071,17 @@ TEST_F(ValidateIdWithMessage, OpBranchConditional_TooManyWeights) { HasSubstr("OpBranchConditional requires either 3 or 5 parameters")); } +TEST_F(ValidateIdWithMessage, OpBranchConditional_ConditionIsAType) { + std::string spirv = BranchConditionalSetup + R"( +OpBranchConditional %bool %target_t %target_f +)" + BranchConditionalTail; + + CompileSuccessfully(spirv.c_str()); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), HasSubstr("Operand 3[%bool] cannot be a " + "type")); +} + // TODO: OpSwitch TEST_F(ValidateIdWithMessage, OpReturnValueConstantGood) { @@ -4530,9 +5141,8 @@ TEST_F(ValidateIdWithMessage, OpReturnValueIsType) { OpFunctionEnd)"; CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr("OpReturnValue Value '1' does not represent a value.")); + EXPECT_THAT(getDiagnosticString(), HasSubstr("Operand 1[%void] cannot be a " + "type")); } TEST_F(ValidateIdWithMessage, OpReturnValueIsLabel) { @@ -4546,9 +5156,8 @@ TEST_F(ValidateIdWithMessage, OpReturnValueIsLabel) { OpFunctionEnd)"; CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr("OpReturnValue Value '5' does not represent a value.")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Operand 5[%5] requires a type")); } TEST_F(ValidateIdWithMessage, OpReturnValueIsVoid) { @@ -4565,7 +5174,8 @@ TEST_F(ValidateIdWithMessage, OpReturnValueIsVoid) { EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), - HasSubstr("OpReturnValue value's type '1' is missing or void.")); + HasSubstr("OpReturnValue value's type '1[%void]' is missing or " + "void.")); } TEST_F(ValidateIdWithMessage, OpReturnValueIsVariableInPhysical) { @@ -4574,7 +5184,7 @@ TEST_F(ValidateIdWithMessage, OpReturnValueIsVariableInPhysical) { OpMemoryModel Physical32 OpenCL %1 = OpTypeVoid %2 = OpTypeInt 32 0 -%3 = OpTypePointer Private %2 +%3 = OpTypePointer Function %2 %4 = OpTypeFunction %3 %5 = OpFunction %3 None %4 %6 = OpLabel @@ -4591,7 +5201,7 @@ TEST_F(ValidateIdWithMessage, OpReturnValueIsVariableInLogical) { OpMemoryModel Logical GLSL450 %1 = OpTypeVoid %2 = OpTypeInt 32 0 -%3 = OpTypePointer Private %2 +%3 = OpTypePointer Function %2 %4 = OpTypeFunction %3 %5 = OpFunction %3 None %4 %6 = OpLabel @@ -4601,8 +5211,9 @@ TEST_F(ValidateIdWithMessage, OpReturnValueIsVariableInLogical) { CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpReturnValue value's type '3' is a pointer, " - "which is invalid in the Logical addressing model.")); + HasSubstr("OpReturnValue value's type " + "'3[%_ptr_Function_uint]' is a pointer, which is " + "invalid in the Logical addressing model.")); } // With the VariablePointer Capability, the return value of a function is @@ -4656,8 +5267,7 @@ TEST_F(ValidateIdWithMessage, UndefinedTypeId) { CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("Forward reference operands in an OpTypeStruct must " - "first be declared using OpTypeForwardPointer.")); + HasSubstr("Operand 2[%2] requires a previous definition")); } TEST_F(ValidateIdWithMessage, UndefinedIdScope) { @@ -4674,7 +5284,8 @@ TEST_F(ValidateIdWithMessage, UndefinedIdScope) { )"; CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), HasSubstr("ID 7 has not been defined")); + EXPECT_THAT(getDiagnosticString(), HasSubstr("ID 7[%7] has not been " + "defined")); } TEST_F(ValidateIdWithMessage, UndefinedIdMemSem) { @@ -4691,7 +5302,8 @@ TEST_F(ValidateIdWithMessage, UndefinedIdMemSem) { )"; CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), HasSubstr("ID 7 has not been defined")); + EXPECT_THAT(getDiagnosticString(), HasSubstr("ID 7[%7] has not been " + "defined")); } TEST_F(ValidateIdWithMessage, @@ -4762,6 +5374,33 @@ TEST_F(ValidateIdWithMessage, OpPtrAccessChainGood) { EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); } +TEST_F(ValidateIdWithMessage, StgBufOpPtrAccessChainGood) { + std::string spirv = R"( + OpCapability Shader + OpCapability Linkage + OpCapability VariablePointersStorageBuffer + OpExtension "SPV_KHR_variable_pointers" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %3 "" +%int = OpTypeInt 32 0 +%int_2 = OpConstant %int 2 +%int_4 = OpConstant %int 4 +%struct = OpTypeStruct %int +%array = OpTypeArray %struct %int_4 +%ptr = OpTypePointer StorageBuffer %array +%var = OpVariable %ptr StorageBuffer +%1 = OpTypeVoid +%2 = OpTypeFunction %1 +%3 = OpFunction %1 None %2 +%4 = OpLabel +%5 = OpPtrAccessChain %ptr %var %int_2 + OpReturn + OpFunctionEnd +)"; + CompileSuccessfully(spirv.c_str()); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + TEST_F(ValidateIdWithMessage, OpLoadBitcastPointerGood) { std::string spirv = kOpenCLMemoryModel64 + R"( %2 = OpTypeVoid @@ -4799,7 +5438,8 @@ TEST_F(ValidateIdWithMessage, OpLoadBitcastNonPointerBad) { EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), - HasSubstr("OpLoad type for pointer '11' is not a pointer type.")); + HasSubstr("OpLoad type for pointer '11[%11]' is not a pointer " + "type.")); } TEST_F(ValidateIdWithMessage, OpStoreBitcastPointerGood) { std::string spirv = kOpenCLMemoryModel64 + R"( @@ -4839,7 +5479,8 @@ TEST_F(ValidateIdWithMessage, OpStoreBitcastNonPointerBad) { EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), - HasSubstr("OpStore type for pointer '11' is not a pointer type.")); + HasSubstr("OpStore type for pointer '11[%11]' is not a pointer " + "type.")); } // Result resulting from an instruction within a function may not be used @@ -4866,7 +5507,8 @@ OpFunctionEnd EXPECT_THAT( getDiagnosticString(), HasSubstr( - "ID 7 defined in block 6 does not dominate its use in block 9")); + "ID 7[%7] defined in block 6[%6] does not dominate its use in block " + "9[%9]")); } TEST_F(ValidateIdWithMessage, SpecIdTargetNotSpecializationConstant) { @@ -4876,7 +5518,7 @@ OpDecorate %1 SpecId 200 %2 = OpTypeFunction %void %int = OpTypeInt 32 0 %1 = OpConstant %int 3 -%main = OpFunction %1 None %2 +%main = OpFunction %void None %2 %4 = OpLabel OpReturnValue %1 OpFunctionEnd @@ -4884,8 +5526,9 @@ OpFunctionEnd CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpDecorate SpecId decoration target '1' is not a " - "scalar specialization constant.")); + HasSubstr("OpDecorate SpecId decoration target " + "'1[%uint_3]' is not a scalar specialization " + "constant.")); } TEST_F(ValidateIdWithMessage, SpecIdTargetOpSpecConstantOpBad) { @@ -4897,7 +5540,7 @@ OpDecorate %1 SpecId 200 %3 = OpConstant %int 1 %4 = OpConstant %int 2 %1 = OpSpecConstantOp %int IAdd %3 %4 -%main = OpFunction %1 None %2 +%main = OpFunction %void None %2 %6 = OpLabel OpReturnValue %3 OpFunctionEnd @@ -4905,8 +5548,8 @@ OpFunctionEnd CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpDecorate SpecId decoration target '1' is not a " - "scalar specialization constant.")); + HasSubstr("OpDecorate SpecId decoration target '1[%1]' is " + "not a scalar specialization constant.")); } TEST_F(ValidateIdWithMessage, SpecIdTargetOpSpecConstantCompositeBad) { @@ -4917,7 +5560,7 @@ OpDecorate %1 SpecId 200 %int = OpTypeInt 32 0 %3 = OpConstant %int 1 %1 = OpSpecConstantComposite %int -%main = OpFunction %1 None %2 +%main = OpFunction %void None %2 %4 = OpLabel OpReturnValue %3 OpFunctionEnd @@ -4925,8 +5568,8 @@ OpFunctionEnd CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpDecorate SpecId decoration target '1' is not a " - "scalar specialization constant.")); + HasSubstr("OpDecorate SpecId decoration target '1[%1]' is " + "not a scalar specialization constant.")); } TEST_F(ValidateIdWithMessage, SpecIdTargetGood) { @@ -4974,7 +5617,7 @@ TEST_F(ValidateIdWithMessage, CorrectErrorForShuffle) { HasSubstr( "Component index 4 is out of bounds for combined (Vector1 + Vector2) " "size of 4.")); - EXPECT_EQ(23, getErrorPosition().index); + EXPECT_EQ(25, getErrorPosition().index); } TEST_F(ValidateIdWithMessage, VoidStructMember) { @@ -4989,69 +5632,945 @@ TEST_F(ValidateIdWithMessage, VoidStructMember) { HasSubstr("Structures cannot contain a void type.")); } -// TODO: OpLifetimeStart -// TODO: OpLifetimeStop -// TODO: OpAtomicInit -// TODO: OpAtomicLoad -// TODO: OpAtomicStore -// TODO: OpAtomicExchange -// TODO: OpAtomicCompareExchange -// TODO: OpAtomicCompareExchangeWeak -// TODO: OpAtomicIIncrement -// TODO: OpAtomicIDecrement -// TODO: OpAtomicIAdd -// TODO: OpAtomicISub -// TODO: OpAtomicUMin -// TODO: OpAtomicUMax -// TODO: OpAtomicAnd -// TODO: OpAtomicOr -// TODO: OpAtomicXor -// TODO: OpAtomicIMin -// TODO: OpAtomicIMax -// TODO: OpEmitStreamVertex -// TODO: OpEndStreamPrimitive -// TODO: OpAsyncGroupCopy -// TODO: OpWaitGroupEvents -// TODO: OpGroupAll -// TODO: OpGroupAny -// TODO: OpGroupBroadcast -// TODO: OpGroupIAdd -// TODO: OpGroupFAdd -// TODO: OpGroupFMin -// TODO: OpGroupUMin -// TODO: OpGroupSMin -// TODO: OpGroupFMax -// TODO: OpGroupUMax -// TODO: OpGroupSMax -// TODO: OpEnqueueMarker -// TODO: OpEnqueueKernel -// TODO: OpGetKernelNDrangeSubGroupCount -// TODO: OpGetKernelNDrangeMaxSubGroupSize -// TODO: OpGetKernelWorkGroupSize -// TODO: OpGetKernelPreferredWorkGroupSizeMultiple -// TODO: OpRetainEvent -// TODO: OpReleaseEvent -// TODO: OpCreateUserEvent -// TODO: OpIsValidEvent -// TODO: OpSetUserEventStatus -// TODO: OpCaptureEventProfilingInfo -// TODO: OpGetDefaultQueue -// TODO: OpBuildNDRange -// TODO: OpReadPipe -// TODO: OpWritePipe -// TODO: OpReservedReadPipe -// TODO: OpReservedWritePipe -// TODO: OpReserveReadPipePackets -// TODO: OpReserveWritePipePackets -// TODO: OpCommitReadPipe -// TODO: OpCommitWritePipe -// TODO: OpIsValidReserveId -// TODO: OpGetNumPipePackets -// TODO: OpGetMaxPipePackets -// TODO: OpGroupReserveReadPipePackets -// TODO: OpGroupReserveWritePipePackets -// TODO: OpGroupCommitReadPipe -// TODO: OpGroupCommitWritePipe +TEST_F(ValidateIdWithMessage, TypeFunctionBadUse) { + std::string spirv = kGLSL450MemoryModel + R"( +%1 = OpTypeVoid +%2 = OpTypeFunction %1 +%3 = OpTypePointer Function %2 +%4 = OpFunction %1 None %2 +%5 = OpLabel + OpReturn + OpFunctionEnd)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Invalid use of function type result id 2[%2].")); +} + +TEST_F(ValidateIdWithMessage, BadTypeId) { + std::string spirv = kGLSL450MemoryModel + R"( + %1 = OpTypeVoid + %2 = OpTypeFunction %1 + %3 = OpTypeFloat 32 + %4 = OpConstant %3 0 + %5 = OpFunction %1 None %2 + %6 = OpLabel + %7 = OpUndef %4 + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), HasSubstr("ID 4[%float_0] is not a type " + "id")); +} + +TEST_F(ValidateIdWithMessage, VulkanMemoryModelLoadMakePointerVisibleGood) { + std::string spirv = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpCapability Linkage +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +%1 = OpTypeVoid +%2 = OpTypeInt 32 0 +%3 = OpTypePointer Workgroup %2 +%4 = OpVariable %3 Workgroup +%5 = OpTypeFunction %1 +%6 = OpConstant %2 2 +%7 = OpFunction %1 None %5 +%8 = OpLabel +%9 = OpLoad %2 %4 NonPrivatePointerKHR|MakePointerVisibleKHR %6 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); +} + +TEST_F(ValidateIdWithMessage, + VulkanMemoryModelLoadMakePointerVisibleMissingNonPrivatePointer) { + std::string spirv = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpCapability Linkage +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +%1 = OpTypeVoid +%2 = OpTypeInt 32 0 +%3 = OpTypePointer Workgroup %2 +%4 = OpVariable %3 Workgroup +%5 = OpTypeFunction %1 +%6 = OpConstant %2 2 +%7 = OpFunction %1 None %5 +%8 = OpLabel +%9 = OpLoad %2 %4 MakePointerVisibleKHR %6 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("NonPrivatePointerKHR must be specified if " + "MakePointerVisibleKHR is specified.")); +} + +TEST_F(ValidateIdWithMessage, + VulkanMemoryModelLoadNonPrivatePointerBadStorageClass) { + std::string spirv = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpCapability Linkage +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +%1 = OpTypeVoid +%2 = OpTypeInt 32 0 +%3 = OpTypePointer Private %2 +%4 = OpVariable %3 Private +%5 = OpTypeFunction %1 +%6 = OpConstant %2 2 +%7 = OpFunction %1 None %5 +%8 = OpLabel +%9 = OpLoad %2 %4 NonPrivatePointerKHR +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("NonPrivatePointerKHR requires a pointer in Uniform, " + "Workgroup, CrossWorkgroup, Generic, Image or " + "StorageBuffer storage classes.")); +} + +TEST_F(ValidateIdWithMessage, + VulkanMemoryModelLoadMakePointerAvailableCannotBeUsed) { + std::string spirv = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpCapability Linkage +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +%1 = OpTypeVoid +%2 = OpTypeInt 32 0 +%3 = OpTypePointer Workgroup %2 +%4 = OpVariable %3 Workgroup +%5 = OpTypeFunction %1 +%6 = OpConstant %2 2 +%7 = OpFunction %1 None %5 +%8 = OpLabel +%9 = OpLoad %2 %4 NonPrivatePointerKHR|MakePointerAvailableKHR %6 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("MakePointerAvailableKHR cannot be used with OpLoad")); +} + +TEST_F(ValidateIdWithMessage, VulkanMemoryModelStoreMakePointerAvailableGood) { + std::string spirv = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpCapability Linkage +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +%1 = OpTypeVoid +%2 = OpTypeInt 32 0 +%3 = OpTypePointer Uniform %2 +%4 = OpVariable %3 Uniform +%5 = OpTypeFunction %1 +%6 = OpConstant %2 5 +%7 = OpFunction %1 None %5 +%8 = OpLabel +OpStore %4 %6 NonPrivatePointerKHR|MakePointerAvailableKHR %6 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); +} + +TEST_F(ValidateIdWithMessage, + VulkanMemoryModelStoreMakePointerAvailableMissingNonPrivatePointer) { + std::string spirv = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpCapability Linkage +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +%1 = OpTypeVoid +%2 = OpTypeInt 32 0 +%3 = OpTypePointer Uniform %2 +%4 = OpVariable %3 Uniform +%5 = OpTypeFunction %1 +%6 = OpConstant %2 5 +%7 = OpFunction %1 None %5 +%8 = OpLabel +OpStore %4 %6 MakePointerAvailableKHR %6 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("NonPrivatePointerKHR must be specified if " + "MakePointerAvailableKHR is specified.")); +} + +TEST_F(ValidateIdWithMessage, + VulkanMemoryModelStoreNonPrivatePointerBadStorageClass) { + std::string spirv = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpCapability Linkage +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +%1 = OpTypeVoid +%2 = OpTypeInt 32 0 +%3 = OpTypePointer Output %2 +%4 = OpVariable %3 Output +%5 = OpTypeFunction %1 +%6 = OpConstant %2 5 +%7 = OpFunction %1 None %5 +%8 = OpLabel +OpStore %4 %6 NonPrivatePointerKHR +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("NonPrivatePointerKHR requires a pointer in Uniform, " + "Workgroup, CrossWorkgroup, Generic, Image or " + "StorageBuffer storage classes.")); +} + +TEST_F(ValidateIdWithMessage, + VulkanMemoryModelStoreMakePointerVisibleCannotBeUsed) { + std::string spirv = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpCapability Linkage +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +%1 = OpTypeVoid +%2 = OpTypeInt 32 0 +%3 = OpTypePointer Uniform %2 +%4 = OpVariable %3 Uniform +%5 = OpTypeFunction %1 +%6 = OpConstant %2 5 +%7 = OpFunction %1 None %5 +%8 = OpLabel +OpStore %4 %6 NonPrivatePointerKHR|MakePointerVisibleKHR %6 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("MakePointerVisibleKHR cannot be used with OpStore.")); +} + +TEST_F(ValidateIdWithMessage, VulkanMemoryModelCopyMemoryAvailable) { + std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +%1 = OpTypeVoid +%2 = OpTypeInt 32 0 +%3 = OpTypePointer Workgroup %2 +%4 = OpVariable %3 Workgroup +%5 = OpTypePointer Uniform %2 +%6 = OpVariable %5 Uniform +%7 = OpConstant %2 2 +%8 = OpConstant %2 5 +%9 = OpTypeFunction %1 +%10 = OpFunction %1 None %9 +%11 = OpLabel +OpCopyMemory %4 %6 NonPrivatePointerKHR|MakePointerAvailableKHR %7 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); +} + +TEST_F(ValidateIdWithMessage, VulkanMemoryModelCopyMemoryVisible) { + std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +%1 = OpTypeVoid +%2 = OpTypeInt 32 0 +%3 = OpTypePointer Workgroup %2 +%4 = OpVariable %3 Workgroup +%5 = OpTypePointer Uniform %2 +%6 = OpVariable %5 Uniform +%7 = OpConstant %2 2 +%8 = OpConstant %2 5 +%9 = OpTypeFunction %1 +%10 = OpFunction %1 None %9 +%11 = OpLabel +OpCopyMemory %4 %6 NonPrivatePointerKHR|MakePointerVisibleKHR %8 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); +} + +TEST_F(ValidateIdWithMessage, VulkanMemoryModelCopyMemoryAvailableAndVisible) { + std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +%1 = OpTypeVoid +%2 = OpTypeInt 32 0 +%3 = OpTypePointer Workgroup %2 +%4 = OpVariable %3 Workgroup +%5 = OpTypePointer Uniform %2 +%6 = OpVariable %5 Uniform +%7 = OpConstant %2 2 +%8 = OpConstant %2 5 +%9 = OpTypeFunction %1 +%10 = OpFunction %1 None %9 +%11 = OpLabel +OpCopyMemory %4 %6 NonPrivatePointerKHR|MakePointerAvailableKHR|MakePointerVisibleKHR %7 %8 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); +} + +TEST_F(ValidateIdWithMessage, + VulkanMemoryModelCopyMemoryAvailableMissingNonPrivatePointer) { + std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +%1 = OpTypeVoid +%2 = OpTypeInt 32 0 +%3 = OpTypePointer Workgroup %2 +%4 = OpVariable %3 Workgroup +%5 = OpTypePointer Uniform %2 +%6 = OpVariable %5 Uniform +%7 = OpConstant %2 2 +%8 = OpConstant %2 5 +%9 = OpTypeFunction %1 +%10 = OpFunction %1 None %9 +%11 = OpLabel +OpCopyMemory %4 %6 MakePointerAvailableKHR %7 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("NonPrivatePointerKHR must be specified if " + "MakePointerAvailableKHR is specified.")); +} + +TEST_F(ValidateIdWithMessage, + VulkanMemoryModelCopyMemoryVisibleMissingNonPrivatePointer) { + std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +%1 = OpTypeVoid +%2 = OpTypeInt 32 0 +%3 = OpTypePointer Workgroup %2 +%4 = OpVariable %3 Workgroup +%5 = OpTypePointer Uniform %2 +%6 = OpVariable %5 Uniform +%7 = OpConstant %2 2 +%8 = OpConstant %2 5 +%9 = OpTypeFunction %1 +%10 = OpFunction %1 None %9 +%11 = OpLabel +OpCopyMemory %4 %6 MakePointerVisibleKHR %8 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("NonPrivatePointerKHR must be specified if " + "MakePointerVisibleKHR is specified.")); +} + +TEST_F(ValidateIdWithMessage, + VulkanMemoryModelCopyMemoryAvailableBadStorageClass) { + std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +%1 = OpTypeVoid +%2 = OpTypeInt 32 0 +%3 = OpTypePointer Output %2 +%4 = OpVariable %3 Output +%5 = OpTypePointer Uniform %2 +%6 = OpVariable %5 Uniform +%7 = OpConstant %2 2 +%8 = OpConstant %2 5 +%9 = OpTypeFunction %1 +%10 = OpFunction %1 None %9 +%11 = OpLabel +OpCopyMemory %4 %6 NonPrivatePointerKHR +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("NonPrivatePointerKHR requires a pointer in Uniform, " + "Workgroup, CrossWorkgroup, Generic, Image or " + "StorageBuffer storage classes.")); +} + +TEST_F(ValidateIdWithMessage, + VulkanMemoryModelCopyMemoryVisibleBadStorageClass) { + std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +%1 = OpTypeVoid +%2 = OpTypeInt 32 0 +%3 = OpTypePointer Workgroup %2 +%4 = OpVariable %3 Workgroup +%5 = OpTypePointer Input %2 +%6 = OpVariable %5 Input +%7 = OpConstant %2 2 +%8 = OpConstant %2 5 +%9 = OpTypeFunction %1 +%10 = OpFunction %1 None %9 +%11 = OpLabel +OpCopyMemory %4 %6 NonPrivatePointerKHR +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("NonPrivatePointerKHR requires a pointer in Uniform, " + "Workgroup, CrossWorkgroup, Generic, Image or " + "StorageBuffer storage classes.")); +} + +TEST_F(ValidateIdWithMessage, VulkanMemoryModelCopyMemorySizedAvailable) { + std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability Addresses +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +%1 = OpTypeVoid +%2 = OpTypeInt 32 0 +%3 = OpTypePointer Workgroup %2 +%4 = OpVariable %3 Workgroup +%5 = OpTypePointer Uniform %2 +%6 = OpVariable %5 Uniform +%7 = OpConstant %2 2 +%8 = OpConstant %2 5 +%9 = OpTypeFunction %1 +%10 = OpFunction %1 None %9 +%11 = OpLabel +OpCopyMemorySized %4 %6 %7 NonPrivatePointerKHR|MakePointerAvailableKHR %7 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); +} + +TEST_F(ValidateIdWithMessage, VulkanMemoryModelCopyMemorySizedVisible) { + std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability Addresses +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +%1 = OpTypeVoid +%2 = OpTypeInt 32 0 +%3 = OpTypePointer Workgroup %2 +%4 = OpVariable %3 Workgroup +%5 = OpTypePointer Uniform %2 +%6 = OpVariable %5 Uniform +%7 = OpConstant %2 2 +%8 = OpConstant %2 5 +%9 = OpTypeFunction %1 +%10 = OpFunction %1 None %9 +%11 = OpLabel +OpCopyMemorySized %4 %6 %7 NonPrivatePointerKHR|MakePointerVisibleKHR %8 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); +} + +TEST_F(ValidateIdWithMessage, + VulkanMemoryModelCopyMemorySizedAvailableAndVisible) { + std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability Addresses +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +%1 = OpTypeVoid +%2 = OpTypeInt 32 0 +%3 = OpTypePointer Workgroup %2 +%4 = OpVariable %3 Workgroup +%5 = OpTypePointer Uniform %2 +%6 = OpVariable %5 Uniform +%7 = OpConstant %2 2 +%8 = OpConstant %2 5 +%9 = OpTypeFunction %1 +%10 = OpFunction %1 None %9 +%11 = OpLabel +OpCopyMemorySized %4 %6 %7 NonPrivatePointerKHR|MakePointerAvailableKHR|MakePointerVisibleKHR %7 %8 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); +} + +TEST_F(ValidateIdWithMessage, + VulkanMemoryModelCopyMemorySizedAvailableMissingNonPrivatePointer) { + std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability Addresses +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +%1 = OpTypeVoid +%2 = OpTypeInt 32 0 +%3 = OpTypePointer Workgroup %2 +%4 = OpVariable %3 Workgroup +%5 = OpTypePointer Uniform %2 +%6 = OpVariable %5 Uniform +%7 = OpConstant %2 2 +%8 = OpConstant %2 5 +%9 = OpTypeFunction %1 +%10 = OpFunction %1 None %9 +%11 = OpLabel +OpCopyMemorySized %4 %6 %7 MakePointerAvailableKHR %7 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("NonPrivatePointerKHR must be specified if " + "MakePointerAvailableKHR is specified.")); +} + +TEST_F(ValidateIdWithMessage, + VulkanMemoryModelCopyMemorySizedVisibleMissingNonPrivatePointer) { + std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability Addresses +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +%1 = OpTypeVoid +%2 = OpTypeInt 32 0 +%3 = OpTypePointer Workgroup %2 +%4 = OpVariable %3 Workgroup +%5 = OpTypePointer Uniform %2 +%6 = OpVariable %5 Uniform +%7 = OpConstant %2 2 +%8 = OpConstant %2 5 +%9 = OpTypeFunction %1 +%10 = OpFunction %1 None %9 +%11 = OpLabel +OpCopyMemorySized %4 %6 %7 MakePointerVisibleKHR %8 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("NonPrivatePointerKHR must be specified if " + "MakePointerVisibleKHR is specified.")); +} + +TEST_F(ValidateIdWithMessage, + VulkanMemoryModelCopyMemorySizedAvailableBadStorageClass) { + std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability Addresses +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +%1 = OpTypeVoid +%2 = OpTypeInt 32 0 +%3 = OpTypePointer Output %2 +%4 = OpVariable %3 Output +%5 = OpTypePointer Uniform %2 +%6 = OpVariable %5 Uniform +%7 = OpConstant %2 2 +%8 = OpConstant %2 5 +%9 = OpTypeFunction %1 +%10 = OpFunction %1 None %9 +%11 = OpLabel +OpCopyMemorySized %4 %6 %7 NonPrivatePointerKHR +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("NonPrivatePointerKHR requires a pointer in Uniform, " + "Workgroup, CrossWorkgroup, Generic, Image or " + "StorageBuffer storage classes.")); +} + +TEST_F(ValidateIdWithMessage, + VulkanMemoryModelCopyMemorySizedVisibleBadStorageClass) { + std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability Addresses +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +%1 = OpTypeVoid +%2 = OpTypeInt 32 0 +%3 = OpTypePointer Workgroup %2 +%4 = OpVariable %3 Workgroup +%5 = OpTypePointer Input %2 +%6 = OpVariable %5 Input +%7 = OpConstant %2 2 +%8 = OpConstant %2 5 +%9 = OpTypeFunction %1 +%10 = OpFunction %1 None %9 +%11 = OpLabel +OpCopyMemorySized %4 %6 %7 NonPrivatePointerKHR +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("NonPrivatePointerKHR requires a pointer in Uniform, " + "Workgroup, CrossWorkgroup, Generic, Image or " + "StorageBuffer storage classes.")); +} + +TEST_F(ValidateIdWithMessage, IdDefInUnreachableBlock1) { + const std::string spirv = kNoKernelGLSL450MemoryModel + R"( +%1 = OpTypeVoid +%2 = OpTypeFunction %1 +%3 = OpTypeFloat 32 +%4 = OpTypeFunction %3 +%5 = OpFunction %1 None %2 +%6 = OpLabel +OpReturn +%7 = OpLabel +%8 = OpFunctionCall %3 %9 +OpUnreachable +OpFunctionEnd +%9 = OpFunction %3 None %4 +%10 = OpLabel +OpReturnValue %8 +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("ID 8[%8] defined in block 7[%7] does not dominate its " + "use in block 10[%10]\n %10 = OpLabel")); +} + +TEST_F(ValidateIdWithMessage, IdDefInUnreachableBlock2) { + const std::string spirv = kNoKernelGLSL450MemoryModel + R"( +%1 = OpTypeVoid +%2 = OpTypeFunction %1 +%3 = OpTypeFloat 32 +%4 = OpTypeFunction %3 +%5 = OpFunction %1 None %2 +%6 = OpLabel +OpReturn +%7 = OpLabel +%8 = OpFunctionCall %3 %9 +OpUnreachable +OpFunctionEnd +%9 = OpFunction %3 None %4 +%10 = OpLabel +OpReturnValue %8 +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("ID 8[%8] defined in block 7[%7] does not dominate its " + "use in block 10[%10]\n %10 = OpLabel")); +} + +TEST_F(ValidateIdWithMessage, IdDefInUnreachableBlock3) { + const std::string spirv = kNoKernelGLSL450MemoryModel + R"( +%1 = OpTypeVoid +%2 = OpTypeFunction %1 +%3 = OpTypeFloat 32 +%4 = OpTypeFunction %3 +%5 = OpFunction %1 None %2 +%6 = OpLabel +OpReturn +%7 = OpLabel +%8 = OpFunctionCall %3 %9 +OpReturn +OpFunctionEnd +%9 = OpFunction %3 None %4 +%10 = OpLabel +OpReturnValue %8 +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("ID 8[%8] defined in block 7[%7] does not dominate its " + "use in block 10[%10]\n %10 = OpLabel")); +} + +TEST_F(ValidateIdWithMessage, IdDefInUnreachableBlock4) { + const std::string spirv = kNoKernelGLSL450MemoryModel + R"( +%1 = OpTypeVoid +%2 = OpTypeFunction %1 +%3 = OpTypeFloat 32 +%4 = OpTypeFunction %3 +%5 = OpFunction %1 None %2 +%6 = OpLabel +OpReturn +%7 = OpLabel +%8 = OpUndef %3 +%9 = OpCopyObject %3 %8 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); +} + +TEST_F(ValidateIdWithMessage, IdDefInUnreachableBlock5) { + const std::string spirv = kNoKernelGLSL450MemoryModel + R"( +%1 = OpTypeVoid +%2 = OpTypeFunction %1 +%3 = OpTypeFloat 32 +%4 = OpTypeFunction %3 +%5 = OpFunction %1 None %2 +%6 = OpLabel +OpReturn +%7 = OpLabel +%8 = OpUndef %3 +OpBranch %9 +%9 = OpLabel +%10 = OpCopyObject %3 %8 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); +} + +TEST_F(ValidateIdWithMessage, IdDefInUnreachableBlock6) { + const std::string spirv = kNoKernelGLSL450MemoryModel + R"( +%1 = OpTypeVoid +%2 = OpTypeFunction %1 +%3 = OpTypeFloat 32 +%4 = OpTypeFunction %3 +%5 = OpFunction %1 None %2 +%6 = OpLabel +OpBranch %7 +%8 = OpLabel +%9 = OpUndef %3 +OpBranch %7 +%7 = OpLabel +%10 = OpCopyObject %3 %9 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("ID 9[%9] defined in block 8[%8] does not dominate its " + "use in block 7[%7]\n %7 = OpLabel")); +} + +TEST_F(ValidateIdWithMessage, ReachableDefUnreachableUse) { + const std::string spirv = kNoKernelGLSL450MemoryModel + R"( +%1 = OpTypeVoid +%2 = OpTypeFunction %1 +%3 = OpTypeFloat 32 +%4 = OpTypeFunction %3 +%5 = OpFunction %1 None %2 +%6 = OpLabel +%7 = OpUndef %3 +OpReturn +%8 = OpLabel +%9 = OpCopyObject %3 %7 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); +} + +TEST_F(ValidateIdWithMessage, UnreachableDefUsedInPhi) { + const std::string spirv = kNoKernelGLSL450MemoryModel + R"( + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %bool = OpTypeBool + %6 = OpTypeFunction %float + %1 = OpFunction %void None %3 + %7 = OpLabel + %8 = OpUndef %bool + OpSelectionMerge %9 None + OpBranchConditional %8 %10 %9 + %10 = OpLabel + %11 = OpUndef %float + OpBranch %9 + %12 = OpLabel + %13 = OpUndef %float + OpUnreachable + %9 = OpLabel + %14 = OpPhi %float %11 %10 %13 %7 + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("In OpPhi instruction 14[%14], ID 13[%13] definition does not " + "dominate its parent 7[%7]\n %14 = OpPhi %float %11 %10 %13 " + "%7")); +} + +TEST_F(ValidateIdWithMessage, OpTypeForwardPointerNotAPointerType) { + std::string spirv = R"( + OpCapability GenericPointer + OpCapability VariablePointersStorageBuffer + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "main" + OpExecutionMode %1 OriginLowerLeft + OpTypeForwardPointer %2 CrossWorkgroup +%2 = OpTypeVoid +%3 = OpTypeFunction %2 +%1 = OpFunction %2 DontInline %3 +%4 = OpLabel + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Pointer type in OpTypeForwardPointer is not a pointer " + "type.\n OpTypeForwardPointer %void CrossWorkgroup")); +} + +TEST_F(ValidateIdWithMessage, OpTypeForwardPointerWrongStorageClass) { + std::string spirv = R"( + OpCapability GenericPointer + OpCapability VariablePointersStorageBuffer + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "main" + OpExecutionMode %1 OriginLowerLeft + OpTypeForwardPointer %2 CrossWorkgroup +%int = OpTypeInt 32 1 +%2 = OpTypePointer Function %int +%void = OpTypeVoid +%3 = OpTypeFunction %void +%1 = OpFunction %void None %3 +%4 = OpLabel + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Storage class in OpTypeForwardPointer does not match the " + "pointer definition.\n OpTypeForwardPointer " + "%_ptr_Function_int CrossWorkgroup")); +} + +TEST_F(ValidateIdWithMessage, MissingForwardPointer) { + const std::string spirv = R"( + OpCapability Linkage + OpCapability Shader + OpMemoryModel Logical Simple + %float = OpTypeFloat 32 + %_struct_9 = OpTypeStruct %float %_ptr_Uniform__struct_9 +%_ptr_Uniform__struct_9 = OpTypePointer Uniform %_struct_9 + %1278 = OpVariable %_ptr_Uniform__struct_9 Uniform +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "Operand 3[%_ptr_Uniform__struct_2] requires a previous definition")); +} } // namespace } // namespace val diff --git a/third_party/spirv-tools/test/val/val_image_test.cpp b/third_party/spirv-tools/test/val/val_image_test.cpp index 03f3eeb995..433c9faed8 100644 --- a/third_party/spirv-tools/test/val/val_image_test.cpp +++ b/third_party/spirv-tools/test/val/val_image_test.cpp @@ -25,6 +25,7 @@ namespace spvtools { namespace val { namespace { +using ::testing::Eq; using ::testing::HasSubstr; using ::testing::Not; @@ -34,7 +35,9 @@ std::string GenerateShaderCode( const std::string& body, const std::string& capabilities_and_extensions = "", const std::string& execution_model = "Fragment", - const spv_target_env env = SPV_ENV_UNIVERSAL_1_0) { + const std::string& execution_mode = "", + const spv_target_env env = SPV_ENV_UNIVERSAL_1_0, + const std::string& memory_model = "GLSL450") { std::ostringstream ss; ss << R"( OpCapability Shader @@ -46,15 +49,77 @@ OpCapability ImageQuery OpCapability Int64 OpCapability Float64 OpCapability SparseResidency +OpCapability ImageBuffer )"; if (env == SPV_ENV_UNIVERSAL_1_0) { ss << "OpCapability SampledRect\n"; } + // In 1.4, the entry point must list all module-scope variables used. Just + // list all of them. + std::string interface_vars = (env != SPV_ENV_UNIVERSAL_1_4) ? "" : + R"( +%uniform_image_f32_1d_0001 +%uniform_image_f32_1d_0002_rgba32f +%uniform_image_f32_2d_0001 +%uniform_image_f32_2d_0010 +%uniform_image_u32_2d_0001 +%uniform_image_u32_2d_0000 +%uniform_image_s32_3d_0001 +%uniform_image_f32_2d_0002 +%uniform_image_s32_2d_0002 +%uniform_image_f32_spd_0002 +%uniform_image_f32_3d_0111 +%uniform_image_f32_cube_0101 +%uniform_image_f32_cube_0102_rgba32f +%uniform_sampler +%private_image_u32_buffer_0002_r32ui +%private_image_u32_spd_0002 +%private_image_f32_buffer_0002_r32ui +)"; + ss << capabilities_and_extensions; - ss << "OpMemoryModel Logical GLSL450\n"; - ss << "OpEntryPoint " << execution_model << " %main \"main\"\n"; + ss << "OpMemoryModel Logical " << memory_model << "\n"; + ss << "OpEntryPoint " << execution_model + << " %main \"main\" " + interface_vars + "\n"; + if (execution_model == "Fragment") { + ss << "OpExecutionMode %main OriginUpperLeft\n"; + } + ss << execution_mode; + + if (env == SPV_ENV_VULKAN_1_0) { + ss << R"( +OpDecorate %uniform_image_f32_1d_0001 DescriptorSet 0 +OpDecorate %uniform_image_f32_1d_0001 Binding 0 +OpDecorate %uniform_image_f32_1d_0002_rgba32f DescriptorSet 0 +OpDecorate %uniform_image_f32_1d_0002_rgba32f Binding 1 +OpDecorate %uniform_image_f32_2d_0001 DescriptorSet 0 +OpDecorate %uniform_image_f32_2d_0001 Binding 2 +OpDecorate %uniform_image_f32_2d_0010 DescriptorSet 0 +OpDecorate %uniform_image_f32_2d_0010 Binding 3 +OpDecorate %uniform_image_u32_2d_0001 DescriptorSet 1 +OpDecorate %uniform_image_u32_2d_0001 Binding 0 +OpDecorate %uniform_image_u32_2d_0000 DescriptorSet 1 +OpDecorate %uniform_image_u32_2d_0000 Binding 1 +OpDecorate %uniform_image_s32_3d_0001 DescriptorSet 1 +OpDecorate %uniform_image_s32_3d_0001 Binding 2 +OpDecorate %uniform_image_f32_2d_0002 DescriptorSet 1 +OpDecorate %uniform_image_f32_2d_0002 Binding 3 +OpDecorate %uniform_image_s32_2d_0002 DescriptorSet 1 +OpDecorate %uniform_image_s32_2d_0002 Binding 4 +OpDecorate %uniform_image_f32_spd_0002 DescriptorSet 2 +OpDecorate %uniform_image_f32_spd_0002 Binding 0 +OpDecorate %uniform_image_f32_3d_0111 DescriptorSet 2 +OpDecorate %uniform_image_f32_3d_0111 Binding 1 +OpDecorate %uniform_image_f32_cube_0101 DescriptorSet 2 +OpDecorate %uniform_image_f32_cube_0101 Binding 2 +OpDecorate %uniform_image_f32_cube_0102_rgba32f DescriptorSet 2 +OpDecorate %uniform_image_f32_cube_0102_rgba32f Binding 3 +OpDecorate %uniform_sampler DescriptorSet 3 +OpDecorate %uniform_sampler Binding 0 +)"; + } ss << R"( %void = OpTypeVoid @@ -186,6 +251,11 @@ OpCapability SparseResidency %uniform_image_f32_2d_0002 = OpVariable %ptr_image_f32_2d_0002 UniformConstant %type_sampled_image_f32_2d_0002 = OpTypeSampledImage %type_image_f32_2d_0002 +%type_image_s32_2d_0002 = OpTypeImage %s32 2D 0 0 0 2 Unknown +%ptr_image_s32_2d_0002 = OpTypePointer UniformConstant %type_image_s32_2d_0002 +%uniform_image_s32_2d_0002 = OpVariable %ptr_image_s32_2d_0002 UniformConstant +%type_sampled_image_s32_2d_0002 = OpTypeSampledImage %type_image_s32_2d_0002 + %type_image_f32_spd_0002 = OpTypeImage %f32 SubpassData 0 0 0 2 Unknown %ptr_image_f32_spd_0002 = OpTypePointer UniformConstant %type_image_f32_spd_0002 %uniform_image_f32_spd_0002 = OpVariable %ptr_image_f32_spd_0002 UniformConstant @@ -209,6 +279,22 @@ OpCapability SparseResidency %type_sampler = OpTypeSampler %ptr_sampler = OpTypePointer UniformConstant %type_sampler %uniform_sampler = OpVariable %ptr_sampler UniformConstant + +%type_image_u32_buffer_0002_r32ui = OpTypeImage %u32 Buffer 0 0 0 2 R32ui +%ptr_Image_u32 = OpTypePointer Image %u32 +%ptr_image_u32_buffer_0002_r32ui = OpTypePointer Private %type_image_u32_buffer_0002_r32ui +%private_image_u32_buffer_0002_r32ui = OpVariable %ptr_image_u32_buffer_0002_r32ui Private + +%ptr_Image_u32arr4 = OpTypePointer Image %u32arr4 + +%type_image_u32_spd_0002 = OpTypeImage %u32 SubpassData 0 0 0 2 Unknown +%ptr_image_u32_spd_0002 = OpTypePointer Private %type_image_u32_spd_0002 +%private_image_u32_spd_0002 = OpVariable %ptr_image_u32_spd_0002 Private + +%type_image_f32_buffer_0002_r32ui = OpTypeImage %f32 Buffer 0 0 0 2 R32ui +%ptr_Image_f32 = OpTypePointer Image %f32 +%ptr_image_f32_buffer_0002_r32ui = OpTypePointer Private %type_image_f32_buffer_0002_r32ui +%private_image_f32_buffer_0002_r32ui = OpVariable %ptr_image_f32_buffer_0002_r32ui Private )"; if (env == SPV_ENV_UNIVERSAL_1_0) { @@ -357,7 +443,8 @@ OpMemoryModel Logical GLSL450 )"; if (include_entry_point) { - ss << "OpEntryPoint Fragment %main \"main\""; + ss << "OpEntryPoint Fragment %main \"main\"\n"; + ss << "OpExecutionMode %main OriginUpperLeft"; } ss << R"( %void = OpTypeVoid @@ -521,7 +608,7 @@ TEST_F(ValidateImage, SampledImageVulkanSuccess) { )"; const spv_target_env env = SPV_ENV_VULKAN_1_0; - CompileSuccessfully(GenerateShaderCode(body, "", "Fragment", env), env); + CompileSuccessfully(GenerateShaderCode(body, "", "Fragment", "", env), env); ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(env)); } @@ -573,7 +660,7 @@ TEST_F(ValidateImage, SampledImageVulkanUnknownSampled) { )"; const spv_target_env env = SPV_ENV_VULKAN_1_0; - CompileSuccessfully(GenerateShaderCode(body, "", "Fragment", env), env); + CompileSuccessfully(GenerateShaderCode(body, "", "Fragment", "", env), env); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(env)); EXPECT_THAT(getDiagnosticString(), HasSubstr("Expected Image 'Sampled' parameter to " @@ -593,6 +680,157 @@ TEST_F(ValidateImage, SampledImageNotSampler) { HasSubstr("Expected Sampler to be of type OpTypeSampler")); } +TEST_F(ValidateImage, ImageTexelPointerSuccess) { + const std::string body = R"( +%texel_ptr = OpImageTexelPointer %ptr_Image_u32 %private_image_u32_buffer_0002_r32ui %u32_0 %u32_0 +%sum = OpAtomicIAdd %u32 %texel_ptr %u32_1 %u32_0 %u32_1 +)"; + + CompileSuccessfully(GenerateShaderCode(body).c_str()); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateImage, ImageTexelPointerResultTypeNotPointer) { + const std::string body = R"( +%texel_ptr = OpImageTexelPointer %type_image_u32_buffer_0002_r32ui %private_image_u32_buffer_0002_r32ui %u32_0 %u32_0 +%sum = OpAtomicIAdd %u32 %texel_ptr %u32_1 %u32_0 %u32_1 +)"; + + CompileSuccessfully(GenerateShaderCode(body).c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Expected Result Type to be OpTypePointer")); +} + +TEST_F(ValidateImage, ImageTexelPointerResultTypeNotImageClass) { + const std::string body = R"( +%texel_ptr = OpImageTexelPointer %ptr_image_f32_cube_0101 %private_image_u32_buffer_0002_r32ui %u32_0 %u32_0 +%sum = OpAtomicIAdd %u32 %texel_ptr %u32_1 %u32_0 %u32_1 +)"; + + CompileSuccessfully(GenerateShaderCode(body).c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Expected Result Type to be OpTypePointer whose " + "Storage Class operand is Image")); +} + +TEST_F(ValidateImage, ImageTexelPointerResultTypeNotNumericNorVoid) { + const std::string body = R"( +%texel_ptr = OpImageTexelPointer %ptr_Image_u32arr4 %private_image_u32_buffer_0002_r32ui %u32_0 %u32_0 +%sum = OpAtomicIAdd %u32 %texel_ptr %u32_1 %u32_0 %u32_1 +)"; + + CompileSuccessfully(GenerateShaderCode(body).c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Expected Result Type to be OpTypePointer whose Type operand " + "must be a scalar numerical type or OpTypeVoid")); +} + +TEST_F(ValidateImage, ImageTexelPointerImageNotResultTypePointer) { + const std::string body = R"( +%texel_ptr = OpImageTexelPointer %ptr_Image_u32 %type_image_f32_buffer_0002_r32ui %u32_0 %u32_0 +%sum = OpAtomicIAdd %u32 %texel_ptr %u32_1 %u32_0 %u32_1 +)"; + + CompileSuccessfully(GenerateShaderCode(body).c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), HasSubstr("Operand 140[%140] cannot be a " + "type")); +} + +TEST_F(ValidateImage, ImageTexelPointerImageNotImage) { + const std::string body = R"( +%texel_ptr = OpImageTexelPointer %ptr_Image_u32 %uniform_sampler %u32_0 %u32_0 +%sum = OpAtomicIAdd %u32 %texel_ptr %u32_1 %u32_0 %u32_1 +)"; + + CompileSuccessfully(GenerateShaderCode(body).c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Expected Image to be OpTypePointer with Type OpTypeImage")); +} + +TEST_F(ValidateImage, ImageTexelPointerImageSampledNotResultType) { + const std::string body = R"( +%texel_ptr = OpImageTexelPointer %ptr_Image_u32 %uniform_image_f32_cube_0101 %u32_0 %u32_0 +%sum = OpAtomicIAdd %u32 %texel_ptr %u32_1 %u32_0 %u32_1 +)"; + + CompileSuccessfully(GenerateShaderCode(body).c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Expected Image 'Sampled Type' to be the same as the " + "Type pointed to by Result Type")); +} + +TEST_F(ValidateImage, ImageTexelPointerImageDimSubpassDataBad) { + const std::string body = R"( +%texel_ptr = OpImageTexelPointer %ptr_Image_u32 %private_image_u32_spd_0002 %u32_0 %u32_0 +%sum = OpAtomicIAdd %u32 %texel_ptr %u32_1 %u32_0 %u32_1 +)"; + + CompileSuccessfully(GenerateShaderCode(body).c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "Image Dim SubpassData cannot be used with OpImageTexelPointer")); +} + +TEST_F(ValidateImage, ImageTexelPointerImageCoordTypeBad) { + const std::string body = R"( +%texel_ptr = OpImageTexelPointer %ptr_Image_f32 %private_image_f32_buffer_0002_r32ui %f32_0 %f32_0 +%sum = OpAtomicIAdd %f32 %texel_ptr %f32_1 %f32_0 %f32_1 +)"; + + CompileSuccessfully(GenerateShaderCode(body).c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Expected Coordinate to be integer scalar or vector")); +} + +TEST_F(ValidateImage, ImageTexelPointerImageCoordSizeBad) { + const std::string body = R"( +%texel_ptr = OpImageTexelPointer %ptr_Image_u32 %uniform_image_u32_2d_0000 %u32vec3_012 %u32_0 +%sum = OpAtomicIAdd %u32 %texel_ptr %u32_1 %u32_0 %u32_1 +)"; + + CompileSuccessfully(GenerateShaderCode(body).c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Expected Coordinate to have 2 components, but given 3")); +} + +TEST_F(ValidateImage, ImageTexelPointerSampleNotIntScalar) { + const std::string body = R"( +%texel_ptr = OpImageTexelPointer %ptr_Image_u32 %private_image_u32_buffer_0002_r32ui %u32_0 %f32_0 +%sum = OpAtomicIAdd %u32 %texel_ptr %u32_1 %u32_0 %u32_1 +)"; + + CompileSuccessfully(GenerateShaderCode(body).c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Expected Sample to be integer scalar")); +} + +TEST_F(ValidateImage, ImageTexelPointerSampleNotZeroForImageWithMSZero) { + const std::string body = R"( +%texel_ptr = OpImageTexelPointer %ptr_Image_u32 %private_image_u32_buffer_0002_r32ui %u32_0 %u32_1 +%sum = OpAtomicIAdd %u32 %texel_ptr %u32_1 %u32_0 %u32_1 +)"; + + CompileSuccessfully(GenerateShaderCode(body).c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Expected Sample for Image with MS 0 to be a valid " + " for the value 0")); +} + TEST_F(ValidateImage, SampleImplicitLodSuccess) { const std::string body = R"( %img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001 @@ -604,10 +842,17 @@ TEST_F(ValidateImage, SampleImplicitLodSuccess) { %res5 = OpImageSampleImplicitLod %f32vec4 %simg %f32vec2_hh Offset %s32vec2_01 %res6 = OpImageSampleImplicitLod %f32vec4 %simg %f32vec2_hh MinLod %f32_0_5 %res7 = OpImageSampleImplicitLod %f32vec4 %simg %f32vec2_hh Bias|Offset|MinLod %f32_0_25 %s32vec2_01 %f32_0_5 +%res8 = OpImageSampleImplicitLod %f32vec4 %simg %f32vec2_hh NonPrivateTexelKHR )"; - CompileSuccessfully(GenerateShaderCode(body).c_str()); - ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); + const std::string extra = R"( +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +)"; + CompileSuccessfully(GenerateShaderCode(body, extra, "Fragment", "", + SPV_ENV_UNIVERSAL_1_3, "VulkanKHR") + .c_str()); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); } TEST_F(ValidateImage, SampleImplicitLodWrongResultType) { @@ -717,10 +962,17 @@ TEST_F(ValidateImage, SampleExplicitLodSuccessShader) { %res3 = OpImageSampleExplicitLod %f32vec4 %simg %f32vec2_hh ConstOffset %s32vec2_01 %res4 = OpImageSampleExplicitLod %f32vec4 %simg %f32vec3_hhh Offset %s32vec2_01 %res5 = OpImageSampleExplicitLod %f32vec4 %simg %f32vec2_hh Grad|Offset|MinLod %f32vec2_10 %f32vec2_01 %s32vec2_01 %f32_0_5 +%res6 = OpImageSampleExplicitLod %f32vec4 %simg %f32vec4_0000 Lod|NonPrivateTexelKHR %f32_1 )"; - CompileSuccessfully(GenerateShaderCode(body).c_str()); - ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); + const std::string extra = R"( +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +)"; + CompileSuccessfully(GenerateShaderCode(body, extra, "Fragment", "", + SPV_ENV_UNIVERSAL_1_3, "VulkanKHR") + .c_str()); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); } TEST_F(ValidateImage, SampleExplicitLodSuccessKernel) { @@ -1295,10 +1547,17 @@ TEST_F(ValidateImage, SampleProjExplicitLodSuccess2D) { %res4 = OpImageSampleProjExplicitLod %f32vec4 %simg %f32vec3_hhh ConstOffset %s32vec2_01 %res5 = OpImageSampleProjExplicitLod %f32vec4 %simg %f32vec3_hhh Offset %s32vec2_01 %res7 = OpImageSampleProjExplicitLod %f32vec4 %simg %f32vec3_hhh Grad|Offset %f32vec2_10 %f32vec2_01 %s32vec2_01 +%res8 = OpImageSampleProjExplicitLod %f32vec4 %simg %f32vec3_hhh Lod|NonPrivateTexelKHR %f32_1 )"; - CompileSuccessfully(GenerateShaderCode(body).c_str()); - ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); + const std::string extra = R"( +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +)"; + CompileSuccessfully(GenerateShaderCode(body, extra, "Fragment", "", + SPV_ENV_UNIVERSAL_1_3, "VulkanKHR") + .c_str()); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); } TEST_F(ValidateImage, SampleProjExplicitLodSuccessRect) { @@ -1422,10 +1681,17 @@ TEST_F(ValidateImage, SampleProjImplicitLodSuccess) { %res5 = OpImageSampleProjImplicitLod %f32vec4 %simg %f32vec3_hhh Offset %s32vec2_01 %res6 = OpImageSampleProjImplicitLod %f32vec4 %simg %f32vec3_hhh MinLod %f32_0_5 %res7 = OpImageSampleProjImplicitLod %f32vec4 %simg %f32vec3_hhh Bias|Offset|MinLod %f32_0_25 %s32vec2_01 %f32_0_5 +%res8 = OpImageSampleProjImplicitLod %f32vec4 %simg %f32vec3_hhh NonPrivateTexelKHR )"; - CompileSuccessfully(GenerateShaderCode(body).c_str()); - ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); + const std::string extra = R"( +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +)"; + CompileSuccessfully(GenerateShaderCode(body, extra, "Fragment", "", + SPV_ENV_UNIVERSAL_1_3, "VulkanKHR") + .c_str()); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); } TEST_F(ValidateImage, SampleProjImplicitLodWrongResultType) { @@ -1536,10 +1802,17 @@ TEST_F(ValidateImage, SampleDrefImplicitLodSuccess) { %res5 = OpImageSampleDrefImplicitLod %u32 %simg %f32vec2_hh %f32_1 Offset %s32vec2_01 %res6 = OpImageSampleDrefImplicitLod %u32 %simg %f32vec2_hh %f32_1 MinLod %f32_0_5 %res7 = OpImageSampleDrefImplicitLod %u32 %simg %f32vec2_hh %f32_1 Bias|Offset|MinLod %f32_0_25 %s32vec2_01 %f32_0_5 +%res8 = OpImageSampleDrefImplicitLod %u32 %simg %f32vec2_hh %f32_1 NonPrivateTexelKHR )"; - CompileSuccessfully(GenerateShaderCode(body).c_str()); - ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); + const std::string extra = R"( +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +)"; + CompileSuccessfully(GenerateShaderCode(body, extra, "Fragment", "", + SPV_ENV_UNIVERSAL_1_3, "VulkanKHR") + .c_str()); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); } TEST_F(ValidateImage, SampleDrefImplicitLodWrongResultType) { @@ -1652,10 +1925,17 @@ TEST_F(ValidateImage, SampleDrefExplicitLodSuccess) { %res4 = OpImageSampleDrefExplicitLod %s32 %simg %f32vec3_hhh %f32_1 ConstOffset %s32vec3_012 %res5 = OpImageSampleDrefExplicitLod %s32 %simg %f32vec4_0000 %f32_1 Offset %s32vec3_012 %res7 = OpImageSampleDrefExplicitLod %s32 %simg %f32vec3_hhh %f32_1 Grad|Offset %f32vec3_hhh %f32vec3_hhh %s32vec3_012 +%res8 = OpImageSampleDrefExplicitLod %s32 %simg %f32vec4_0000 %f32_1 Lod|NonPrivateTexelKHR %f32_1 )"; - CompileSuccessfully(GenerateShaderCode(body).c_str()); - ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); + const std::string extra = R"( +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +)"; + CompileSuccessfully(GenerateShaderCode(body, extra, "Fragment", "", + SPV_ENV_UNIVERSAL_1_3, "VulkanKHR") + .c_str()); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); } TEST_F(ValidateImage, SampleDrefExplicitLodWrongResultType) { @@ -1769,10 +2049,17 @@ TEST_F(ValidateImage, SampleProjDrefImplicitLodSuccess) { %res5 = OpImageSampleProjDrefImplicitLod %f32 %simg %f32vec3_hhh %f32_0_5 Offset %s32vec2_01 %res6 = OpImageSampleProjDrefImplicitLod %f32 %simg %f32vec3_hhh %f32_0_5 MinLod %f32_0_5 %res7 = OpImageSampleProjDrefImplicitLod %f32 %simg %f32vec3_hhh %f32_0_5 Bias|Offset|MinLod %f32_0_25 %s32vec2_01 %f32_0_5 +%res8 = OpImageSampleProjDrefImplicitLod %f32 %simg %f32vec3_hhh %f32_0_5 NonPrivateTexelKHR )"; - CompileSuccessfully(GenerateShaderCode(body).c_str()); - ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); + const std::string extra = R"( +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +)"; + CompileSuccessfully(GenerateShaderCode(body, extra, "Fragment", "", + SPV_ENV_UNIVERSAL_1_3, "VulkanKHR") + .c_str()); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); } TEST_F(ValidateImage, SampleProjDrefImplicitLodWrongResultType) { @@ -1885,10 +2172,17 @@ TEST_F(ValidateImage, SampleProjDrefExplicitLodSuccess) { %res3 = OpImageSampleProjDrefExplicitLod %f32 %simg %f32vec2_hh %f32_0_5 ConstOffset %s32_1 %res4 = OpImageSampleProjDrefExplicitLod %f32 %simg %f32vec2_hh %f32_0_5 Offset %s32_1 %res5 = OpImageSampleProjDrefExplicitLod %f32 %simg %f32vec2_hh %f32_0_5 Grad|Offset %f32_0_5 %f32_0_5 %s32_1 +%res6 = OpImageSampleProjDrefExplicitLod %f32 %simg %f32vec2_hh %f32_0_5 Lod|NonPrivateTexelKHR %f32_1 )"; - CompileSuccessfully(GenerateShaderCode(body).c_str()); - ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); + const std::string extra = R"( +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +)"; + CompileSuccessfully(GenerateShaderCode(body, extra, "Fragment", "", + SPV_ENV_UNIVERSAL_1_3, "VulkanKHR") + .c_str()); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); } TEST_F(ValidateImage, SampleProjDrefExplicitLodWrongResultType) { @@ -1979,12 +2273,19 @@ TEST_F(ValidateImage, SampleProjDrefExplicitLodCoordinateSizeTooSmall) { TEST_F(ValidateImage, FetchSuccess) { const std::string body = R"( -%img = OpLoad %type_image_f32_rect_0001 %uniform_image_f32_rect_0001 +%img = OpLoad %type_image_f32_1d_0001 %uniform_image_f32_1d_0001 %res1 = OpImageFetch %f32vec4 %img %u32vec2_01 +%res2 = OpImageFetch %f32vec4 %img %u32vec2_01 NonPrivateTexelKHR )"; - CompileSuccessfully(GenerateShaderCode(body).c_str()); - ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); + const std::string extra = R"( +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +)"; + CompileSuccessfully(GenerateShaderCode(body, extra, "Fragment", "", + SPV_ENV_UNIVERSAL_1_3, "VulkanKHR") + .c_str()); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); } TEST_F(ValidateImage, FetchWrongResultType) { @@ -2016,7 +2317,7 @@ TEST_F(ValidateImage, FetchNotImage) { %img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001 %sampler = OpLoad %type_sampler %uniform_sampler %simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler -%res1 = OpImageFetch %f32vec4 %simg %u32vec2_01 +%res1 = OpImageFetch %f32vec4 %sampler %u32vec2_01 )"; CompileSuccessfully(GenerateShaderCode(body).c_str()); @@ -2025,6 +2326,21 @@ TEST_F(ValidateImage, FetchNotImage) { HasSubstr("Expected Image to be of type OpTypeImage")); } +TEST_F(ValidateImage, FetchSampledImageDirectly) { + const std::string body = R"( +%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001 +%sampler = OpLoad %type_sampler %uniform_sampler +%simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler +%res1 = OpImageFetch %f32vec4 %simg %u32vec2_01 +)"; + + CompileSuccessfully(GenerateShaderCode(body).c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("OpSampledImage instruction must not appear as operand " + "for OpImageFetch")); +} + TEST_F(ValidateImage, FetchNotSampled) { const std::string body = R"( %img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000 @@ -2118,10 +2434,17 @@ TEST_F(ValidateImage, GatherSuccess) { %simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler %res1 = OpImageGather %f32vec4 %simg %f32vec4_0000 %u32_1 %res2 = OpImageGather %f32vec4 %simg %f32vec4_0000 %u32_1 ConstOffsets %const_offsets +%res3 = OpImageGather %f32vec4 %simg %f32vec4_0000 %u32_1 NonPrivateTexelKHR )"; - CompileSuccessfully(GenerateShaderCode(body).c_str()); - ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); + const std::string extra = R"( +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +)"; + CompileSuccessfully(GenerateShaderCode(body, extra, "Fragment", "", + SPV_ENV_UNIVERSAL_1_3, "VulkanKHR") + .c_str()); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); } TEST_F(ValidateImage, GatherWrongResultType) { @@ -2367,10 +2690,17 @@ TEST_F(ValidateImage, DrefGatherSuccess) { %simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler %res1 = OpImageDrefGather %f32vec4 %simg %f32vec4_0000 %f32_0_5 %res2 = OpImageDrefGather %f32vec4 %simg %f32vec4_0000 %f32_0_5 ConstOffsets %const_offsets +%res3 = OpImageDrefGather %f32vec4 %simg %f32vec4_0000 %f32_0_5 NonPrivateTexelKHR )"; - CompileSuccessfully(GenerateShaderCode(body).c_str()); - ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); + const std::string extra = R"( +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +)"; + CompileSuccessfully(GenerateShaderCode(body, extra, "Fragment", "", + SPV_ENV_UNIVERSAL_1_3, "VulkanKHR") + .c_str()); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); } TEST_F(ValidateImage, DrefGatherVoidSampledType) { @@ -2452,7 +2782,19 @@ TEST_F(ValidateImage, ReadNeedCapabilityStorageImageReadWithoutFormat) { )"; CompileSuccessfully(GenerateShaderCode(body).c_str()); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateImage, ReadNeedCapabilityStorageImageReadWithoutFormatVulkan) { + const std::string body = R"( +%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000 +%res1 = OpImageRead %u32vec4 %img %u32vec2_01 +)"; + + spv_target_env env = SPV_ENV_VULKAN_1_0; + CompileSuccessfully(GenerateShaderCode(body, "", "Fragment", "", env).c_str(), + env); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(env)); EXPECT_THAT(getDiagnosticString(), HasSubstr("Capability StorageImageReadWithoutFormat is required " "to read storage image")); @@ -2596,7 +2938,7 @@ TEST_F(ValidateImage, ReadCoordinateSizeTooSmall) { TEST_F(ValidateImage, WriteSuccess1) { const std::string body = R"( %img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000 -%res1 = OpImageWrite %img %u32vec2_01 %u32vec4_0123 +OpImageWrite %img %u32vec2_01 %u32vec4_0123 )"; const std::string extra = "\nOpCapability StorageImageWriteWithoutFormat\n"; @@ -2607,7 +2949,7 @@ TEST_F(ValidateImage, WriteSuccess1) { TEST_F(ValidateImage, WriteSuccess2) { const std::string body = R"( %img = OpLoad %type_image_f32_1d_0002_rgba32f %uniform_image_f32_1d_0002_rgba32f -%res1 = OpImageWrite %img %u32_1 %f32vec4_0000 +OpImageWrite %img %u32_1 %f32vec4_0000 )"; const std::string extra = "\nOpCapability Image1D\n"; @@ -2618,7 +2960,7 @@ TEST_F(ValidateImage, WriteSuccess2) { TEST_F(ValidateImage, WriteSuccess3) { const std::string body = R"( %img = OpLoad %type_image_f32_cube_0102_rgba32f %uniform_image_f32_cube_0102_rgba32f -%res1 = OpImageWrite %img %u32vec3_012 %f32vec4_0000 +OpImageWrite %img %u32vec3_012 %f32vec4_0000 )"; const std::string extra = "\nOpCapability ImageCubeArray\n"; @@ -2630,8 +2972,8 @@ TEST_F(ValidateImage, WriteSuccess4) { const std::string body = R"( %img = OpLoad %type_image_f32_2d_0010 %uniform_image_f32_2d_0010 ;TODO(atgoo@github.com) Is it legal to write to MS image without sample index? -%res1 = OpImageWrite %img %u32vec2_01 %f32vec4_0000 -%res2 = OpImageWrite %img %u32vec2_01 %f32vec4_0000 Sample %u32_1 +OpImageWrite %img %u32vec2_01 %f32vec4_0000 +OpImageWrite %img %u32vec2_01 %f32vec4_0000 Sample %u32_1 )"; const std::string extra = "\nOpCapability StorageImageWriteWithoutFormat\n"; @@ -2642,7 +2984,7 @@ TEST_F(ValidateImage, WriteSuccess4) { TEST_F(ValidateImage, WriteSubpassData) { const std::string body = R"( %img = OpLoad %type_image_f32_spd_0002 %uniform_image_f32_spd_0002 -%res1 = OpImageWrite %img %u32vec2_01 %f32vec4_0000 +OpImageWrite %img %u32vec2_01 %f32vec4_0000 )"; CompileSuccessfully(GenerateShaderCode(body).c_str()); @@ -2654,11 +2996,23 @@ TEST_F(ValidateImage, WriteSubpassData) { TEST_F(ValidateImage, WriteNeedCapabilityStorageImageWriteWithoutFormat) { const std::string body = R"( %img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000 -%res1 = OpImageWrite %img %u32vec2_01 %u32vec4_0123 +OpImageWrite %img %u32vec2_01 %u32vec4_0123 )"; CompileSuccessfully(GenerateShaderCode(body).c_str()); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateImage, WriteNeedCapabilityStorageImageWriteWithoutFormatVulkan) { + const std::string body = R"( +%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000 +OpImageWrite %img %u32vec2_01 %u32vec4_0123 +)"; + + spv_target_env env = SPV_ENV_VULKAN_1_0; + CompileSuccessfully(GenerateShaderCode(body, "", "Fragment", "", env).c_str(), + env); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(env)); EXPECT_THAT( getDiagnosticString(), HasSubstr( @@ -2669,7 +3023,7 @@ TEST_F(ValidateImage, WriteNeedCapabilityStorageImageWriteWithoutFormat) { TEST_F(ValidateImage, WriteNeedCapabilityImage1D) { const std::string body = R"( %img = OpLoad %type_image_f32_1d_0002_rgba32f %uniform_image_f32_1d_0002_rgba32f -%res1 = OpImageWrite %img %u32vec2_01 %f32vec4_0000 +OpImageWrite %img %u32vec2_01 %f32vec4_0000 )"; CompileSuccessfully(GenerateShaderCode(body).c_str()); @@ -2682,7 +3036,7 @@ TEST_F(ValidateImage, WriteNeedCapabilityImage1D) { TEST_F(ValidateImage, WriteNeedCapabilityImageCubeArray) { const std::string body = R"( %img = OpLoad %type_image_f32_cube_0102_rgba32f %uniform_image_f32_cube_0102_rgba32f -%res1 = OpImageWrite %img %u32vec3_012 %f32vec4_0000 +OpImageWrite %img %u32vec3_012 %f32vec4_0000 )"; CompileSuccessfully(GenerateShaderCode(body).c_str()); @@ -2696,7 +3050,7 @@ TEST_F(ValidateImage, WriteNeedCapabilityImageCubeArray) { TEST_F(ValidateImage, WriteNotImage) { const std::string body = R"( %sampler = OpLoad %type_sampler %uniform_sampler -%res1 = OpImageWrite %sampler %u32vec2_01 %f32vec4_0000 +OpImageWrite %sampler %u32vec2_01 %f32vec4_0000 )"; CompileSuccessfully(GenerateShaderCode(body).c_str()); @@ -2708,7 +3062,7 @@ TEST_F(ValidateImage, WriteNotImage) { TEST_F(ValidateImage, WriteImageSampled) { const std::string body = R"( %img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001 -%res1 = OpImageWrite %img %u32vec2_01 %f32vec4_0000 +OpImageWrite %img %u32vec2_01 %f32vec4_0000 )"; const std::string extra = "\nOpCapability StorageImageWriteWithoutFormat\n"; @@ -2721,7 +3075,7 @@ TEST_F(ValidateImage, WriteImageSampled) { TEST_F(ValidateImage, WriteWrongCoordinateType) { const std::string body = R"( %img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000 -%res1 = OpImageWrite %img %f32vec2_00 %u32vec4_0123 +OpImageWrite %img %f32vec2_00 %u32vec4_0123 )"; const std::string extra = "\nOpCapability StorageImageWriteWithoutFormat\n"; @@ -2734,7 +3088,7 @@ TEST_F(ValidateImage, WriteWrongCoordinateType) { TEST_F(ValidateImage, WriteCoordinateSizeTooSmall) { const std::string body = R"( %img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000 -%res1 = OpImageWrite %img %u32_1 %u32vec4_0123 +OpImageWrite %img %u32_1 %u32vec4_0123 )"; const std::string extra = "\nOpCapability StorageImageWriteWithoutFormat\n"; @@ -2748,7 +3102,7 @@ TEST_F(ValidateImage, WriteCoordinateSizeTooSmall) { TEST_F(ValidateImage, WriteTexelWrongType) { const std::string body = R"( %img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000 -%res1 = OpImageWrite %img %u32vec2_01 %img +OpImageWrite %img %u32vec2_01 %img )"; const std::string extra = "\nOpCapability StorageImageWriteWithoutFormat\n"; @@ -2761,7 +3115,7 @@ TEST_F(ValidateImage, WriteTexelWrongType) { TEST_F(ValidateImage, DISABLED_WriteTexelNotVector4) { const std::string body = R"( %img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000 -%res1 = OpImageWrite %img %u32vec2_01 %u32vec3_012 +OpImageWrite %img %u32vec2_01 %u32vec3_012 )"; const std::string extra = "\nOpCapability StorageImageWriteWithoutFormat\n"; @@ -2774,7 +3128,7 @@ TEST_F(ValidateImage, DISABLED_WriteTexelNotVector4) { TEST_F(ValidateImage, WriteTexelWrongComponentType) { const std::string body = R"( %img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000 -%res1 = OpImageWrite %img %u32vec2_01 %f32vec4_0000 +OpImageWrite %img %u32vec2_01 %f32vec4_0000 )"; const std::string extra = "\nOpCapability StorageImageWriteWithoutFormat\n"; @@ -2789,7 +3143,7 @@ TEST_F(ValidateImage, WriteTexelWrongComponentType) { TEST_F(ValidateImage, WriteSampleNotInteger) { const std::string body = R"( %img = OpLoad %type_image_f32_2d_0010 %uniform_image_f32_2d_0010 -%res1 = OpImageWrite %img %u32vec2_01 %f32vec4_0000 Sample %f32_1 +OpImageWrite %img %u32vec2_01 %f32vec4_0000 Sample %f32_1 )"; const std::string extra = "\nOpCapability StorageImageWriteWithoutFormat\n"; @@ -2802,7 +3156,7 @@ TEST_F(ValidateImage, WriteSampleNotInteger) { TEST_F(ValidateImage, SampleNotMultisampled) { const std::string body = R"( %img = OpLoad %type_image_f32_2d_0002 %uniform_image_f32_2d_0002 -%res2 = OpImageWrite %img %u32vec2_01 %f32vec4_0000 Sample %u32_1 +OpImageWrite %img %u32vec2_01 %f32vec4_0000 Sample %u32_1 )"; const std::string extra = "\nOpCapability StorageImageWriteWithoutFormat\n"; @@ -2910,7 +3264,7 @@ TEST_F(ValidateImage, QueryFormatNotImage) { %img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001 %sampler = OpLoad %type_sampler %uniform_sampler %simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler -%res1 = OpImageQueryFormat %u32 %simg +%res1 = OpImageQueryFormat %u32 %sampler )"; CompileSuccessfully(GenerateKernelCode(body).c_str()); @@ -2946,7 +3300,7 @@ TEST_F(ValidateImage, QueryOrderNotImage) { %img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001 %sampler = OpLoad %type_sampler %uniform_sampler %simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler -%res1 = OpImageQueryOrder %u32 %simg +%res1 = OpImageQueryOrder %u32 %sampler )"; CompileSuccessfully(GenerateKernelCode(body).c_str()); @@ -2995,7 +3349,7 @@ TEST_F(ValidateImage, QuerySizeLodNotImage) { %img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001 %sampler = OpLoad %type_sampler %uniform_sampler %simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler -%res1 = OpImageQuerySizeLod %u32vec2 %simg %u32_1 +%res1 = OpImageQuerySizeLod %u32vec2 %sampler %u32_1 )"; CompileSuccessfully(GenerateKernelCode(body).c_str()); @@ -3004,6 +3358,21 @@ TEST_F(ValidateImage, QuerySizeLodNotImage) { HasSubstr("Expected Image to be of type OpTypeImage")); } +TEST_F(ValidateImage, QuerySizeLodSampledImageDirectly) { + const std::string body = R"( +%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001 +%sampler = OpLoad %type_sampler %uniform_sampler +%simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler +%res1 = OpImageQuerySizeLod %u32vec2 %simg %u32_1 +)"; + + CompileSuccessfully(GenerateShaderCode(body).c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("OpSampledImage instruction must not appear as operand " + "for OpImageQuerySizeLod")); +} + TEST_F(ValidateImage, QuerySizeLodWrongImageDim) { const std::string body = R"( %img = OpLoad %type_image_f32_rect_0001 %uniform_image_f32_rect_0001 @@ -3041,7 +3410,7 @@ TEST_F(ValidateImage, QuerySizeLodWrongLodType) { TEST_F(ValidateImage, QuerySizeSuccess) { const std::string body = R"( -%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001 +%img = OpLoad %type_image_f32_2d_0010 %uniform_image_f32_2d_0010 %res1 = OpImageQuerySize %u32vec2 %img )"; @@ -3051,7 +3420,7 @@ TEST_F(ValidateImage, QuerySizeSuccess) { TEST_F(ValidateImage, QuerySizeWrongResultType) { const std::string body = R"( -%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001 +%img = OpLoad %type_image_f32_2d_0010 %uniform_image_f32_2d_0010 %res1 = OpImageQuerySize %f32vec2 %img )"; @@ -3064,10 +3433,10 @@ TEST_F(ValidateImage, QuerySizeWrongResultType) { TEST_F(ValidateImage, QuerySizeNotImage) { const std::string body = R"( -%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001 +%img = OpLoad %type_image_f32_2d_0010 %uniform_image_f32_2d_0010 %sampler = OpLoad %type_sampler %uniform_sampler %simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler -%res1 = OpImageQuerySize %u32vec2 %simg +%res1 = OpImageQuerySize %u32vec2 %sampler )"; CompileSuccessfully(GenerateKernelCode(body).c_str()); @@ -3076,7 +3445,58 @@ TEST_F(ValidateImage, QuerySizeNotImage) { HasSubstr("Expected Image to be of type OpTypeImage")); } -// TODO(atgoo@github.com) Add more tests for OpQuerySize. +TEST_F(ValidateImage, QuerySizeSampledImageDirectly) { + const std::string body = R"( +%img = OpLoad %type_image_f32_2d_0010 %uniform_image_f32_2d_0010 +%sampler = OpLoad %type_sampler %uniform_sampler +%simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler +%res1 = OpImageQuerySize %u32vec2 %simg +)"; + + CompileSuccessfully(GenerateShaderCode(body).c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("OpSampledImage instruction must not appear as operand " + "for OpImageQuerySize")); +} + +TEST_F(ValidateImage, QuerySizeDimSubpassDataBad) { + const std::string body = R"( +%img = OpLoad %type_image_f32_spd_0002 %uniform_image_f32_spd_0002 +%res1 = OpImageQuerySize %u32vec2 %img +)"; + + CompileSuccessfully(GenerateShaderCode(body).c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Image 'Dim' must be 1D, Buffer, 2D, Cube, 3D or Rect")); +} + +TEST_F(ValidateImage, QuerySizeWrongSampling) { + const std::string body = R"( +%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001 +%res1 = OpImageQuerySize %u32vec2 %img +)"; + + CompileSuccessfully(GenerateKernelCode(body).c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Image must have either 'MS'=1 or 'Sampled'=0 or 'Sampled'=2")); +} + +TEST_F(ValidateImage, QuerySizeWrongNumberOfComponents) { + const std::string body = R"( +%img = OpLoad %type_image_f32_3d_0111 %uniform_image_f32_3d_0111 +%res1 = OpImageQuerySize %u32vec2 %img +)"; + + CompileSuccessfully(GenerateShaderCode(body).c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Result Type has 2 components, but 4 expected")); +} TEST_F(ValidateImage, QueryLodSuccessKernel) { const std::string body = R"( @@ -3214,7 +3634,7 @@ TEST_F(ValidateImage, QueryLevelsNotImage) { %img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001 %sampler = OpLoad %type_sampler %uniform_sampler %simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler -%res1 = OpImageQueryLevels %u32 %simg +%res1 = OpImageQueryLevels %u32 %sampler )"; CompileSuccessfully(GenerateKernelCode(body).c_str()); @@ -3223,6 +3643,21 @@ TEST_F(ValidateImage, QueryLevelsNotImage) { HasSubstr("Expected Image to be of type OpTypeImage")); } +TEST_F(ValidateImage, QueryLevelsSampledImageDirectly) { + const std::string body = R"( +%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001 +%sampler = OpLoad %type_sampler %uniform_sampler +%simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler +%res1 = OpImageQueryLevels %u32 %simg +)"; + + CompileSuccessfully(GenerateShaderCode(body).c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("OpSampledImage instruction must not appear as operand " + "for OpImageQueryLevels")); +} + TEST_F(ValidateImage, QueryLevelsWrongDim) { const std::string body = R"( %img = OpLoad %type_image_f32_rect_0001 %uniform_image_f32_rect_0001 @@ -3277,8 +3712,10 @@ TEST_F(ValidateImage, QueryLodWrongExecutionModel) { CompileSuccessfully(GenerateShaderCode(body, "", "Vertex").c_str()); ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpImageQueryLod requires Fragment execution model")); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "OpImageQueryLod requires Fragment or GLCompute execution model")); } TEST_F(ValidateImage, QueryLodWrongExecutionModelWithFunc) { @@ -3296,8 +3733,55 @@ OpFunctionEnd CompileSuccessfully(GenerateShaderCode(body, "", "Vertex").c_str()); ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "OpImageQueryLod requires Fragment or GLCompute execution model")); +} + +TEST_F(ValidateImage, QueryLodComputeShaderDerivatives) { + const std::string body = R"( +%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001 +%sampler = OpLoad %type_sampler %uniform_sampler +%simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler +%res1 = OpImageQueryLod %f32vec2 %simg %f32vec2_hh +)"; + + const std::string extra = R"( +OpCapability ComputeDerivativeGroupLinearNV +OpExtension "SPV_NV_compute_shader_derivatives" +)"; + const std::string mode = R"( +OpExecutionMode %main LocalSize 8 8 1 +OpExecutionMode %main DerivativeGroupLinearNV +)"; + CompileSuccessfully( + GenerateShaderCode(body, extra, "GLCompute", mode).c_str()); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateImage, QueryLodComputeShaderDerivativesMissingMode) { + const std::string body = R"( +%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001 +%sampler = OpLoad %type_sampler %uniform_sampler +%simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler +%res1 = OpImageQueryLod %f32vec2 %simg %f32vec2_hh +)"; + + const std::string extra = R"( +OpCapability ComputeDerivativeGroupLinearNV +OpExtension "SPV_NV_compute_shader_derivatives" +)"; + const std::string mode = R"( +OpExecutionMode %main LocalSize 8 8 1 +)"; + CompileSuccessfully( + GenerateShaderCode(body, extra, "GLCompute", mode).c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpImageQueryLod requires Fragment execution model")); + HasSubstr("OpImageQueryLod requires DerivativeGroupQuadsNV or " + "DerivativeGroupLinearNV execution mode for GLCompute " + "execution model")); } TEST_F(ValidateImage, ImplicitLodWrongExecutionModel) { @@ -3310,9 +3794,55 @@ TEST_F(ValidateImage, ImplicitLodWrongExecutionModel) { CompileSuccessfully(GenerateShaderCode(body, "", "Vertex").c_str()); ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("ImplicitLod instructions require Fragment or " + "GLCompute execution model")); +} + +TEST_F(ValidateImage, ImplicitLodComputeShaderDerivatives) { + const std::string body = R"( +%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001 +%sampler = OpLoad %type_sampler %uniform_sampler +%simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler +%res1 = OpImageSampleImplicitLod %f32vec4 %simg %f32vec2_hh +)"; + + const std::string extra = R"( +OpCapability ComputeDerivativeGroupLinearNV +OpExtension "SPV_NV_compute_shader_derivatives" +)"; + const std::string mode = R"( +OpExecutionMode %main LocalSize 8 8 1 +OpExecutionMode %main DerivativeGroupLinearNV +)"; + CompileSuccessfully( + GenerateShaderCode(body, extra, "GLCompute", mode).c_str()); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateImage, ImplicitLodComputeShaderDerivativesMissingMode) { + const std::string body = R"( +%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001 +%sampler = OpLoad %type_sampler %uniform_sampler +%simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler +%res1 = OpImageSampleImplicitLod %f32vec4 %simg %f32vec2_hh +)"; + + const std::string extra = R"( +OpCapability ComputeDerivativeGroupLinearNV +OpExtension "SPV_NV_compute_shader_derivatives" +)"; + const std::string mode = R"( +OpExecutionMode %main LocalSize 8 8 1 +)"; + CompileSuccessfully( + GenerateShaderCode(body, extra, "GLCompute", mode).c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), - HasSubstr("ImplicitLod instructions require Fragment execution model")); + HasSubstr("ImplicitLod instructions require DerivativeGroupQuadsNV or " + "DerivativeGroupLinearNV execution mode for GLCompute " + "execution model")); } TEST_F(ValidateImage, ReadSubpassDataWrongExecutionModel) { @@ -3339,10 +3869,17 @@ TEST_F(ValidateImage, SparseSampleImplicitLodSuccess) { %res5 = OpImageSparseSampleImplicitLod %struct_u32_f32vec4 %simg %f32vec2_hh Offset %s32vec2_01 %res6 = OpImageSparseSampleImplicitLod %struct_u32_f32vec4 %simg %f32vec2_hh MinLod %f32_0_5 %res7 = OpImageSparseSampleImplicitLod %struct_u64_f32vec4 %simg %f32vec2_hh Bias|Offset|MinLod %f32_0_25 %s32vec2_01 %f32_0_5 +%res8 = OpImageSparseSampleImplicitLod %struct_u32_f32vec4 %simg %f32vec2_hh NonPrivateTexelKHR )"; - CompileSuccessfully(GenerateShaderCode(body).c_str()); - ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); + const std::string extra = R"( +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +)"; + CompileSuccessfully(GenerateShaderCode(body, extra, "Fragment", "", + SPV_ENV_UNIVERSAL_1_3, "VulkanKHR") + .c_str()); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); } TEST_F(ValidateImage, SparseSampleImplicitLodResultTypeNotStruct) { @@ -3460,10 +3997,17 @@ TEST_F(ValidateImage, SparseSampleDrefImplicitLodSuccess) { %res5 = OpImageSparseSampleDrefImplicitLod %struct_u32_u32 %simg %f32vec2_hh %f32_1 Offset %s32vec2_01 %res6 = OpImageSparseSampleDrefImplicitLod %struct_u32_u32 %simg %f32vec2_hh %f32_1 MinLod %f32_0_5 %res7 = OpImageSparseSampleDrefImplicitLod %struct_u32_u32 %simg %f32vec2_hh %f32_1 Bias|Offset|MinLod %f32_0_25 %s32vec2_01 %f32_0_5 +%res8 = OpImageSparseSampleDrefImplicitLod %struct_u32_u32 %simg %f32vec2_hh %f32_1 NonPrivateTexelKHR )"; - CompileSuccessfully(GenerateShaderCode(body).c_str()); - ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); + const std::string extra = R"( +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +)"; + CompileSuccessfully(GenerateShaderCode(body, extra, "Fragment", "", + SPV_ENV_UNIVERSAL_1_3, "VulkanKHR") + .c_str()); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); } TEST_F(ValidateImage, SparseSampleDrefImplicitLodResultTypeNotStruct) { @@ -3545,12 +4089,19 @@ TEST_F(ValidateImage, SparseSampleDrefImplicitLodDifferentSampledType) { TEST_F(ValidateImage, SparseFetchSuccess) { const std::string body = R"( -%img = OpLoad %type_image_f32_rect_0001 %uniform_image_f32_rect_0001 +%img = OpLoad %type_image_f32_1d_0001 %uniform_image_f32_1d_0001 %res1 = OpImageSparseFetch %struct_u32_f32vec4 %img %u32vec2_01 +%res2 = OpImageSparseFetch %struct_u32_f32vec4 %img %u32vec2_01 NonPrivateTexelKHR )"; - CompileSuccessfully(GenerateShaderCode(body).c_str()); - ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); + const std::string extra = R"( +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +)"; + CompileSuccessfully(GenerateShaderCode(body, extra, "Fragment", "", + SPV_ENV_UNIVERSAL_1_3, "VulkanKHR") + .c_str()); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); } TEST_F(ValidateImage, SparseFetchResultTypeNotStruct) { @@ -3757,10 +4308,17 @@ TEST_F(ValidateImage, SparseGatherSuccess) { %sampler = OpLoad %type_sampler %uniform_sampler %simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler %res1 = OpImageSparseGather %struct_u32_f32vec4 %simg %f32vec4_0000 %u32_1 +%res2 = OpImageSparseGather %struct_u32_f32vec4 %simg %f32vec4_0000 %u32_1 NonPrivateTexelKHR )"; - CompileSuccessfully(GenerateShaderCode(body).c_str()); - ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); + const std::string extra = R"( +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +)"; + CompileSuccessfully(GenerateShaderCode(body, extra, "Fragment", "", + SPV_ENV_UNIVERSAL_1_3, "VulkanKHR") + .c_str()); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); } TEST_F(ValidateImage, SparseGatherResultTypeNotStruct) { @@ -3887,6 +4445,405 @@ TEST_F(ValidateImage, SparseTexelsResidentResultTypeNotBool) { HasSubstr("Expected Result Type to be bool scalar type")); } +TEST_F(ValidateImage, MakeTexelVisibleKHRSuccessImageRead) { + const std::string body = R"( +%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000 +%res1 = OpImageRead %u32vec4 %img %u32vec2_01 MakeTexelVisibleKHR|NonPrivateTexelKHR %u32_2 +)"; + + const std::string extra = R"( +OpCapability StorageImageReadWithoutFormat +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +)"; + CompileSuccessfully(GenerateShaderCode(body, extra, "Fragment", "", + SPV_ENV_UNIVERSAL_1_3, "VulkanKHR") + .c_str()); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); +} + +TEST_F(ValidateImage, MakeTexelVisibleKHRSuccessImageSparseRead) { + const std::string body = R"( +%img = OpLoad %type_image_f32_2d_0002 %uniform_image_f32_2d_0002 +%res1 = OpImageSparseRead %struct_u32_f32vec4 %img %u32vec2_01 MakeTexelVisibleKHR|NonPrivateTexelKHR %u32_2 +)"; + + const std::string extra = R"( +OpCapability StorageImageReadWithoutFormat +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +)"; + CompileSuccessfully(GenerateShaderCode(body, extra, "Fragment", "", + SPV_ENV_UNIVERSAL_1_3, "VulkanKHR") + .c_str()); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); +} + +TEST_F(ValidateImage, MakeTexelVisibleKHRFailureOpcode) { + const std::string body = R"( +%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001 +%sampler = OpLoad %type_sampler %uniform_sampler +%simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler +%res1 = OpImageSampleImplicitLod %f32vec4 %simg %f32vec2_hh MakeTexelVisibleKHR|NonPrivateTexelKHR %u32_1 +)"; + + const std::string extra = R"( +OpCapability StorageImageReadWithoutFormat +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +)"; + CompileSuccessfully(GenerateShaderCode(body, extra, "Fragment", "", + SPV_ENV_UNIVERSAL_1_3, "VulkanKHR") + .c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Image Operand MakeTexelVisibleKHR can only be used with " + "OpImageRead or OpImageSparseRead: OpImageSampleImplicitLod")); +} + +TEST_F(ValidateImage, MakeTexelVisibleKHRFailureMissingNonPrivate) { + const std::string body = R"( +%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000 +%res1 = OpImageRead %u32vec4 %img %u32vec2_01 MakeTexelVisibleKHR %u32_1 +)"; + + const std::string extra = R"( +OpCapability StorageImageReadWithoutFormat +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +)"; + CompileSuccessfully(GenerateShaderCode(body, extra, "Fragment", "", + SPV_ENV_UNIVERSAL_1_3, "VulkanKHR") + .c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Image Operand MakeTexelVisibleKHR requires " + "NonPrivateTexelKHR is also specified: OpImageRead")); +} + +TEST_F(ValidateImage, MakeTexelAvailableKHRSuccessImageWrite) { + const std::string body = R"( +%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000 +OpImageWrite %img %u32vec2_01 %u32vec4_0123 MakeTexelAvailableKHR|NonPrivateTexelKHR %u32_2 +)"; + + const std::string extra = R"( +OpCapability StorageImageWriteWithoutFormat +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +)"; + CompileSuccessfully(GenerateShaderCode(body, extra, "Fragment", "", + SPV_ENV_UNIVERSAL_1_3, "VulkanKHR") + .c_str()); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); +} + +TEST_F(ValidateImage, MakeTexelAvailableKHRFailureOpcode) { + const std::string body = R"( +%img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001 +%sampler = OpLoad %type_sampler %uniform_sampler +%simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler +%res1 = OpImageSampleImplicitLod %f32vec4 %simg %f32vec2_hh MakeTexelAvailableKHR|NonPrivateTexelKHR %u32_1 +)"; + + const std::string extra = R"( +OpCapability StorageImageReadWithoutFormat +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +)"; + CompileSuccessfully(GenerateShaderCode(body, extra, "Fragment", "", + SPV_ENV_UNIVERSAL_1_3, "VulkanKHR") + .c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Image Operand MakeTexelAvailableKHR can only be used " + "with OpImageWrite: OpImageSampleImplicitLod")); +} + +TEST_F(ValidateImage, MakeTexelAvailableKHRFailureMissingNonPrivate) { + const std::string body = R"( +%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000 +OpImageWrite %img %u32vec2_01 %u32vec4_0123 MakeTexelAvailableKHR %u32_1 +)"; + + const std::string extra = R"( +OpCapability StorageImageWriteWithoutFormat +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +)"; + CompileSuccessfully(GenerateShaderCode(body, extra, "Fragment", "", + SPV_ENV_UNIVERSAL_1_3, "VulkanKHR") + .c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Image Operand MakeTexelAvailableKHR requires " + "NonPrivateTexelKHR is also specified: OpImageWrite")); +} + +TEST_F(ValidateImage, VulkanMemoryModelDeviceScopeImageWriteBad) { + const std::string body = R"( +%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000 +OpImageWrite %img %u32vec2_01 %u32vec4_0123 MakeTexelAvailableKHR|NonPrivateTexelKHR %u32_1 +)"; + + const std::string extra = R"( +OpCapability StorageImageWriteWithoutFormat +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +)"; + CompileSuccessfully(GenerateShaderCode(body, extra, "Fragment", "", + SPV_ENV_UNIVERSAL_1_3, "VulkanKHR") + .c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Use of device scope with VulkanKHR memory model requires the " + "VulkanMemoryModelDeviceScopeKHR capability")); +} + +TEST_F(ValidateImage, VulkanMemoryModelDeviceScopeImageWriteGood) { + const std::string body = R"( +%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000 +OpImageWrite %img %u32vec2_01 %u32vec4_0123 MakeTexelAvailableKHR|NonPrivateTexelKHR %u32_1 +)"; + + const std::string extra = R"( +OpCapability StorageImageWriteWithoutFormat +OpCapability VulkanMemoryModelKHR +OpCapability VulkanMemoryModelDeviceScopeKHR +OpExtension "SPV_KHR_vulkan_memory_model" +)"; + CompileSuccessfully(GenerateShaderCode(body, extra, "Fragment", "", + SPV_ENV_UNIVERSAL_1_3, "VulkanKHR") + .c_str()); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); +} + +TEST_F(ValidateImage, VulkanMemoryModelDeviceScopeImageReadBad) { + const std::string body = R"( +%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000 +%res1 = OpImageRead %u32vec4 %img %u32vec2_01 MakeTexelVisibleKHR|NonPrivateTexelKHR %u32_1 +)"; + + const std::string extra = R"( +OpCapability StorageImageReadWithoutFormat +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +)"; + CompileSuccessfully(GenerateShaderCode(body, extra, "Fragment", "", + SPV_ENV_UNIVERSAL_1_3, "VulkanKHR") + .c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Use of device scope with VulkanKHR memory model requires the " + "VulkanMemoryModelDeviceScopeKHR capability")); +} + +TEST_F(ValidateImage, VulkanMemoryModelDeviceScopeImageReadGood) { + const std::string body = R"( +%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000 +%res1 = OpImageRead %u32vec4 %img %u32vec2_01 MakeTexelVisibleKHR|NonPrivateTexelKHR %u32_1 +)"; + + const std::string extra = R"( +OpCapability StorageImageReadWithoutFormat +OpCapability VulkanMemoryModelKHR +OpCapability VulkanMemoryModelDeviceScopeKHR +OpExtension "SPV_KHR_vulkan_memory_model" +)"; + CompileSuccessfully(GenerateShaderCode(body, extra, "Fragment", "", + SPV_ENV_UNIVERSAL_1_3, "VulkanKHR") + .c_str()); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); +} + +// This example used to cause a seg fault on OpReturnValue, verifying it doesn't +// anymore. +TEST_F(ValidateImage, Issue2463NoSegFault) { + const std::string spirv = R"( + OpCapability Linkage + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + %void = OpTypeVoid + %6 = OpTypeFunction %void + %float = OpTypeFloat 32 + %8 = OpTypeImage %float 3D 0 0 0 1 Unknown +%_ptr_UniformConstant_8 = OpTypePointer UniformConstant %8 + %10 = OpTypeSampler +%_ptr_UniformConstant_10 = OpTypePointer UniformConstant %10 + %12 = OpTypeSampledImage %8 + %13 = OpTypeFunction %12 %_ptr_UniformConstant_8 %_ptr_UniformConstant_10 + %23 = OpFunction %12 None %13 + %24 = OpFunctionParameter %_ptr_UniformConstant_8 + %25 = OpFunctionParameter %_ptr_UniformConstant_10 + %26 = OpLabel + %27 = OpLoad %8 %24 + %28 = OpLoad %10 %25 + %29 = OpSampledImage %12 %27 %28 + OpReturnValue %29 + OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("OpSampledImage instruction must not appear as operand " + "for OpReturnValue")); +} + +TEST_F(ValidateImage, SignExtendV13Bad) { + const std::string body = R"( +%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000 +%res1 = OpImageRead %u32vec4 %img %u32vec2_01 SignExtend +)"; + + EXPECT_THAT(CompileFailure(GenerateShaderCode(body, "", "Fragment", "", + SPV_ENV_UNIVERSAL_1_3)), + HasSubstr("Invalid image operand 'SignExtend'")); +} + +TEST_F(ValidateImage, ZeroExtendV13Bad) { + const std::string body = R"( +%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000 +%res1 = OpImageRead %u32vec4 %img %u32vec2_01 ZeroExtend +)"; + + EXPECT_THAT(CompileFailure(GenerateShaderCode(body, "", "Fragment", "", + SPV_ENV_UNIVERSAL_1_3)), + HasSubstr("Invalid image operand 'ZeroExtend'")); +} + +TEST_F(ValidateImage, SignExtendScalarUIntTexelV14Good) { + // Unsigned int sampled type + const std::string body = R"( +%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000 +%res1 = OpImageRead %u32 %img %u32vec2_01 SignExtend +)"; + const std::string extra = "\nOpCapability StorageImageReadWithoutFormat\n"; + + CompileSuccessfully( + GenerateShaderCode(body, extra, "Fragment", "", SPV_ENV_UNIVERSAL_1_4), + SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateImage, SignExtendScalarSIntTexelV14Good) { + // Signed int sampled type + const std::string body = R"( +%img = OpLoad %type_image_s32_2d_0002 %uniform_image_s32_2d_0002 +%res1 = OpImageRead %s32 %img %u32vec2_01 SignExtend +)"; + const std::string extra = "\nOpCapability StorageImageReadWithoutFormat\n"; + + CompileSuccessfully( + GenerateShaderCode(body, extra, "Fragment", "", SPV_ENV_UNIVERSAL_1_4), + SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateImage, SignExtendScalarVectorUIntTexelV14Good) { + const std::string body = R"( +%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000 +%res1 = OpImageRead %u32vec4 %img %u32vec2_01 SignExtend +)"; + const std::string extra = "\nOpCapability StorageImageReadWithoutFormat\n"; + + CompileSuccessfully( + GenerateShaderCode(body, extra, "Fragment", "", SPV_ENV_UNIVERSAL_1_4), + SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateImage, SignExtendVectorSIntTexelV14Good) { + const std::string body = R"( +%img = OpLoad %type_image_s32_2d_0002 %uniform_image_s32_2d_0002 +%res1 = OpImageRead %s32vec4 %img %u32vec2_01 SignExtend +)"; + const std::string extra = "\nOpCapability StorageImageReadWithoutFormat\n"; + + CompileSuccessfully( + GenerateShaderCode(body, extra, "Fragment", "", SPV_ENV_UNIVERSAL_1_4), + SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +// No negative tests for SignExtend since we don't truly know the +// texel format. + +TEST_F(ValidateImage, ZeroExtendScalarUIntTexelV14Good) { + // Unsigned int sampled type + const std::string body = R"( +%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000 +%res1 = OpImageRead %u32 %img %u32vec2_01 ZeroExtend +)"; + const std::string extra = "\nOpCapability StorageImageReadWithoutFormat\n"; + + CompileSuccessfully( + GenerateShaderCode(body, extra, "Fragment", "", SPV_ENV_UNIVERSAL_1_4), + SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateImage, ZeroExtendScalarSIntTexelV14Good) { + // Zeroed int sampled type + const std::string body = R"( +%img = OpLoad %type_image_s32_2d_0002 %uniform_image_s32_2d_0002 +%res1 = OpImageRead %s32 %img %u32vec2_01 ZeroExtend +)"; + const std::string extra = "\nOpCapability StorageImageReadWithoutFormat\n"; + + CompileSuccessfully( + GenerateShaderCode(body, extra, "Fragment", "", SPV_ENV_UNIVERSAL_1_4), + SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateImage, ZeroExtendScalarVectorUIntTexelV14Good) { + const std::string body = R"( +%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000 +%res1 = OpImageRead %u32vec4 %img %u32vec2_01 ZeroExtend +)"; + const std::string extra = "\nOpCapability StorageImageReadWithoutFormat\n"; + + CompileSuccessfully( + GenerateShaderCode(body, extra, "Fragment", "", SPV_ENV_UNIVERSAL_1_4), + SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateImage, ZeroExtendVectorSIntTexelV14Good) { + const std::string body = R"( +%img = OpLoad %type_image_s32_2d_0002 %uniform_image_s32_2d_0002 +%res1 = OpImageRead %s32vec4 %img %u32vec2_01 ZeroExtend +)"; + const std::string extra = "\nOpCapability StorageImageReadWithoutFormat\n"; + + CompileSuccessfully( + GenerateShaderCode(body, extra, "Fragment", "", SPV_ENV_UNIVERSAL_1_4), + SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +// No negative tests for ZeroExtend since we don't truly know the +// texel format. + } // namespace } // namespace val } // namespace spvtools diff --git a/third_party/spirv-tools/test/val/val_interfaces_test.cpp b/third_party/spirv-tools/test/val/val_interfaces_test.cpp index b673a040f4..3410616ddf 100644 --- a/third_party/spirv-tools/test/val/val_interfaces_test.cpp +++ b/third_party/spirv-tools/test/val/val_interfaces_test.cpp @@ -31,6 +31,7 @@ TEST_F(ValidateInterfacesTest, EntryPointMissingInput) { OpCapability Shader OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %1 "func" +OpExecutionMode %1 OriginUpperLeft %2 = OpTypeVoid %3 = OpTypeInt 32 0 %4 = OpTypePointer Input %3 @@ -47,8 +48,9 @@ OpFunctionEnd ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), - HasSubstr("Input variable id <5> is used by entry point 'func' id <1>, " - "but is not listed as an interface")); + HasSubstr( + "Interface variable id <5> is used by entry point 'func' id <1>, " + "but is not listed as an interface")); } TEST_F(ValidateInterfacesTest, EntryPointMissingOutput) { @@ -56,6 +58,7 @@ TEST_F(ValidateInterfacesTest, EntryPointMissingOutput) { OpCapability Shader OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %1 "func" +OpExecutionMode %1 OriginUpperLeft %2 = OpTypeVoid %3 = OpTypeInt 32 0 %4 = OpTypePointer Output %3 @@ -72,8 +75,9 @@ OpFunctionEnd ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), - HasSubstr("Output variable id <5> is used by entry point 'func' id <1>, " - "but is not listed as an interface")); + HasSubstr( + "Interface variable id <5> is used by entry point 'func' id <1>, " + "but is not listed as an interface")); } TEST_F(ValidateInterfacesTest, InterfaceMissingUseInSubfunction) { @@ -81,6 +85,7 @@ TEST_F(ValidateInterfacesTest, InterfaceMissingUseInSubfunction) { OpCapability Shader OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %1 "func" +OpExecutionMode %1 OriginUpperLeft %2 = OpTypeVoid %3 = OpTypeInt 32 0 %4 = OpTypePointer Input %3 @@ -102,8 +107,9 @@ OpFunctionEnd ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), - HasSubstr("Input variable id <5> is used by entry point 'func' id <1>, " - "but is not listed as an interface")); + HasSubstr( + "Interface variable id <5> is used by entry point 'func' id <1>, " + "but is not listed as an interface")); } TEST_F(ValidateInterfacesTest, TwoEntryPointsOneFunction) { @@ -112,6 +118,7 @@ OpCapability Shader OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %1 "func" %2 OpEntryPoint Fragment %1 "func2" +OpExecutionMode %1 OriginUpperLeft %3 = OpTypeVoid %4 = OpTypeInt 32 0 %5 = OpTypePointer Input %4 @@ -128,8 +135,9 @@ OpFunctionEnd ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), - HasSubstr("Input variable id <2> is used by entry point 'func2' id <1>, " - "but is not listed as an interface")); + HasSubstr( + "Interface variable id <2> is used by entry point 'func2' id <1>, " + "but is not listed as an interface")); } TEST_F(ValidateInterfacesTest, MissingInterfaceThroughInitializer) { @@ -138,6 +146,7 @@ OpCapability Shader OpCapability VariablePointers OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %1 "func" +OpExecutionMode %1 OriginUpperLeft %2 = OpTypeVoid %3 = OpTypeInt 32 0 %4 = OpTypePointer Input %3 @@ -155,8 +164,239 @@ OpFunctionEnd ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); EXPECT_THAT( getDiagnosticString(), - HasSubstr("Input variable id <6> is used by entry point 'func' id <1>, " - "but is not listed as an interface")); + HasSubstr( + "Interface variable id <6> is used by entry point 'func' id <1>, " + "but is not listed as an interface")); +} + +TEST_F(ValidateInterfacesTest, NonUniqueInterfacesSPV1p3) { + const std::string text = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" %var %var +OpExecutionMode %main LocalSize 1 1 1 +%void = OpTypeVoid +%uint = OpTypeInt 32 0 +%uint3 = OpTypeVector %uint 3 +%struct = OpTypeStruct %uint3 +%ptr_struct = OpTypePointer Input %struct +%var = OpVariable %ptr_struct Input +%func_ty = OpTypeFunction %void +%main = OpFunction %void None %func_ty +%1 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); +} + +TEST_F(ValidateInterfacesTest, NonUniqueInterfacesSPV1p4) { + const std::string text = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" %var %var +OpExecutionMode %main LocalSize 1 1 1 +OpName %main "main" +OpName %var "var" +%void = OpTypeVoid +%uint = OpTypeInt 32 0 +%uint3 = OpTypeVector %uint 3 +%struct = OpTypeStruct %uint3 +%ptr_struct = OpTypePointer Input %struct +%var = OpVariable %ptr_struct Input +%func_ty = OpTypeFunction %void +%main = OpFunction %void None %func_ty +%1 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Non-unique OpEntryPoint interface 2[%var] is disallowed")); +} + +TEST_F(ValidateInterfacesTest, MissingGlobalVarSPV1p3) { + const std::string text = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +%void = OpTypeVoid +%uint = OpTypeInt 32 0 +%uint3 = OpTypeVector %uint 3 +%struct = OpTypeStruct %uint3 +%ptr_struct = OpTypePointer StorageBuffer %struct +%var = OpVariable %ptr_struct StorageBuffer +%func_ty = OpTypeFunction %void +%main = OpFunction %void None %func_ty +%1 = OpLabel +%ld = OpLoad %struct %var +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); +} + +TEST_F(ValidateInterfacesTest, MissingGlobalVarSPV1p4) { + const std::string text = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpName %var "var" +%void = OpTypeVoid +%uint = OpTypeInt 32 0 +%uint3 = OpTypeVector %uint 3 +%struct = OpTypeStruct %uint3 +%ptr_struct = OpTypePointer StorageBuffer %struct +%var = OpVariable %ptr_struct StorageBuffer +%func_ty = OpTypeFunction %void +%main = OpFunction %void None %func_ty +%1 = OpLabel +%ld = OpLoad %struct %var +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Interface variable id <2> is used by entry point " + "'main' id <1>, but is not listed as an interface")); +} + +TEST_F(ValidateInterfacesTest, FunctionInterfaceVarSPV1p3) { + const std::string text = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" %var +OpExecutionMode %main LocalSize 1 1 1 +OpName %var "var" +%void = OpTypeVoid +%uint = OpTypeInt 32 0 +%uint3 = OpTypeVector %uint 3 +%struct = OpTypeStruct %uint3 +%ptr_struct = OpTypePointer Function %struct +%func_ty = OpTypeFunction %void +%main = OpFunction %void None %func_ty +%1 = OpLabel +%var = OpVariable %ptr_struct Function +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("OpEntryPoint interfaces must be OpVariables with " + "Storage Class of Input(1) or Output(3). Found Storage " + "Class 7 for Entry Point id 1.")); +} + +TEST_F(ValidateInterfacesTest, FunctionInterfaceVarSPV1p4) { + const std::string text = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" %var +OpExecutionMode %main LocalSize 1 1 1 +OpName %var "var" +%void = OpTypeVoid +%uint = OpTypeInt 32 0 +%uint3 = OpTypeVector %uint 3 +%struct = OpTypeStruct %uint3 +%ptr_struct = OpTypePointer Function %struct +%func_ty = OpTypeFunction %void +%main = OpFunction %void None %func_ty +%1 = OpLabel +%var = OpVariable %ptr_struct Function +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("OpEntryPoint interfaces should only list global variables")); +} + +TEST_F(ValidateInterfacesTest, ModuleSPV1p3ValidateSPV1p4_NotAllUsedGlobals) { + const std::string text = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpName %var "var" +%void = OpTypeVoid +%uint = OpTypeInt 32 0 +%uint3 = OpTypeVector %uint 3 +%struct = OpTypeStruct %uint3 +%ptr_struct = OpTypePointer StorageBuffer %struct +%var = OpVariable %ptr_struct StorageBuffer +%func_ty = OpTypeFunction %void +%main = OpFunction %void None %func_ty +%1 = OpLabel +%ld = OpLoad %struct %var +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); +} + +TEST_F(ValidateInterfacesTest, ModuleSPV1p3ValidateSPV1p4_DuplicateInterface) { + const std::string text = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" %gid %gid +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %gid BuiltIn GlobalInvocationId +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int3 = OpTypeVector %int 3 +%ptr_input_int3 = OpTypePointer Input %int3 +%gid = OpVariable %ptr_input_int3 Input +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); +} + +TEST_F(ValidateInterfacesTest, SPV14MultipleEntryPointsSameFunction) { + const std::string text = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main1" %gid +OpEntryPoint GLCompute %main "main2" %gid +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %gid BuiltIn GlobalInvocationId +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int3 = OpTypeVector %int 3 +%ptr_input_int3 = OpTypePointer Input %int3 +%gid = OpVariable %ptr_input_int3 Input +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); } } // namespace diff --git a/third_party/spirv-tools/test/val/val_layout_test.cpp b/third_party/spirv-tools/test/val/val_layout_test.cpp index 145c5439b3..9d4491c37e 100644 --- a/third_party/spirv-tools/test/val/val_layout_test.cpp +++ b/third_party/spirv-tools/test/val/val_layout_test.cpp @@ -120,7 +120,7 @@ const std::vector& getInstructions() { static const int kRangeEnd = 1000; pred_type All = Range<0, kRangeEnd>(); -INSTANTIATE_TEST_CASE_P(InstructionsOrder, +INSTANTIATE_TEST_SUITE_P(InstructionsOrder, ValidateLayout, ::testing::Combine(::testing::Range((int)0, (int)getInstructions().size()), // Note: Because of ID dependencies between instructions, some instructions @@ -160,7 +160,7 @@ INSTANTIATE_TEST_CASE_P(InstructionsOrder, , std::make_tuple(std::string("%fLabel = OpLabel") , Equals<39> , All) , std::make_tuple(std::string("OpNop") , Equals<40> , Range<40,kRangeEnd>()) , std::make_tuple(std::string("OpReturn ; %func2 return") , Equals<41> , All) - )),); + ))); // clang-format on // Creates a new vector which removes the string if the substr is found in the @@ -181,7 +181,7 @@ std::vector GenerateCode(std::string substr, int order) { } // This test will check the logical layout of a binary by removing each -// instruction in the pair of the INSTANTIATE_TEST_CASE_P call and moving it in +// instruction in the pair of the INSTANTIATE_TEST_SUITE_P call and moving it in // the SPIRV source formed by combining the vector "instructions". TEST_P(ValidateLayout, Layout) { int order; @@ -481,6 +481,7 @@ TEST_F(ValidateEntryPoint, FunctionIsTargetOfEntryPointAndFunctionCallBad) { OpCapability Shader OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %foo "foo" + OpExecutionMode %foo OriginUpperLeft %voidt = OpTypeVoid %funct = OpTypeFunction %voidt %foo = OpFunction %voidt None %funct @@ -647,6 +648,57 @@ TEST_F(ValidateLayout, ModuleProcessedInvalidInBasicBlock) { HasSubstr("ModuleProcessed cannot appear in a function declaration")); } +TEST_F(ValidateLayout, WebGPUCallerBeforeCalleeBad) { + char str[] = R"( + OpCapability Shader + OpCapability VulkanMemoryModelKHR + OpExtension "SPV_KHR_vulkan_memory_model" + OpMemoryModel Logical VulkanKHR + OpEntryPoint GLCompute %main "main" +%void = OpTypeVoid +%voidfn = OpTypeFunction %void +%main = OpFunction %void None %voidfn +%1 = OpLabel +%2 = OpFunctionCall %void %callee + OpReturn + OpFunctionEnd +%callee = OpFunction %void None %voidfn +%3 = OpLabel + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(str, SPV_ENV_WEBGPU_0); + ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("For WebGPU, functions need to be defined before being " + "called.\n %5 = OpFunctionCall %void %6\n")); +} + +TEST_F(ValidateLayout, WebGPUCalleeBeforeCallerGood) { + char str[] = R"( + OpCapability Shader + OpCapability VulkanMemoryModelKHR + OpExtension "SPV_KHR_vulkan_memory_model" + OpMemoryModel Logical VulkanKHR + OpEntryPoint GLCompute %main "main" +%void = OpTypeVoid +%voidfn = OpTypeFunction %void +%callee = OpFunction %void None %voidfn +%3 = OpLabel + OpReturn + OpFunctionEnd +%main = OpFunction %void None %voidfn +%1 = OpLabel +%2 = OpFunctionCall %void %callee + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(str, SPV_ENV_WEBGPU_0); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); +} + // TODO(umar): Test optional instructions } // namespace diff --git a/third_party/spirv-tools/test/val/val_limits_test.cpp b/third_party/spirv-tools/test/val/val_limits_test.cpp index 55bf1e5f16..0ef61e21bf 100644 --- a/third_party/spirv-tools/test/val/val_limits_test.cpp +++ b/third_party/spirv-tools/test/val/val_limits_test.cpp @@ -79,6 +79,70 @@ TEST_F(ValidateLimits, IdEqualToBoundBad) { HasSubstr("Result '64' must be less than the ID bound '64'.")); } +TEST_F(ValidateLimits, IdBoundTooBigDeaultLimit) { + std::string str = header; + + CompileSuccessfully(str); + + // The largest ID used in this program is 64. Let's overwrite the ID bound in + // the header to be 64. This should result in an error because all IDs must + // satisfy: 0 < id < bound. + OverwriteAssembledBinary(3, 0x4FFFFF); + + ASSERT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Invalid SPIR-V. The id bound is larger than the max " + "id bound 4194303.")); +} + +TEST_F(ValidateLimits, IdBoundAtSetLimit) { + std::string str = header; + + CompileSuccessfully(str); + + // The largest ID used in this program is 64. Let's overwrite the ID bound in + // the header to be 64. This should result in an error because all IDs must + // satisfy: 0 < id < bound. + uint32_t id_bound = 0x4FFFFF; + + OverwriteAssembledBinary(3, id_bound); + getValidatorOptions()->universal_limits_.max_id_bound = id_bound; + + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateLimits, IdBoundJustAboveSetLimit) { + std::string str = header; + + CompileSuccessfully(str); + + // The largest ID used in this program is 64. Let's overwrite the ID bound in + // the header to be 64. This should result in an error because all IDs must + // satisfy: 0 < id < bound. + uint32_t id_bound = 5242878; + + OverwriteAssembledBinary(3, id_bound); + getValidatorOptions()->universal_limits_.max_id_bound = id_bound - 1; + + ASSERT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Invalid SPIR-V. The id bound is larger than the max " + "id bound 5242877.")); +} + +TEST_F(ValidateLimits, IdBoundAtInMaxLimit) { + std::string str = header; + + CompileSuccessfully(str); + + uint32_t id_bound = std::numeric_limits::max(); + + OverwriteAssembledBinary(3, id_bound); + getValidatorOptions()->universal_limits_.max_id_bound = id_bound; + + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + TEST_F(ValidateLimits, StructNumMembersGood) { std::ostringstream spirv; spirv << header << R"( @@ -148,7 +212,7 @@ TEST_F(ValidateLimits, SwitchNumBranchesGood) { %5 = OpFunction %1 None %2 %7 = OpLabel %8 = OpIAdd %3 %4 %4 -%9 = OpSwitch %4 %10)"; + OpSwitch %4 %10)"; // Now add the (literal, label) pairs for (int i = 0; i < 16383; ++i) { @@ -176,7 +240,7 @@ TEST_F(ValidateLimits, SwitchNumBranchesBad) { %5 = OpFunction %1 None %2 %7 = OpLabel %8 = OpIAdd %3 %4 %4 -%9 = OpSwitch %4 %10)"; + OpSwitch %4 %10)"; // Now add the (literal, label) pairs for (int i = 0; i < 16384; ++i) { @@ -207,7 +271,7 @@ TEST_F(ValidateLimits, CustomizedSwitchNumBranchesGood) { %5 = OpFunction %1 None %2 %7 = OpLabel %8 = OpIAdd %3 %4 %4 -%9 = OpSwitch %4 %10)"; + OpSwitch %4 %10)"; // Now add the (literal, label) pairs for (int i = 0; i < 10; ++i) { @@ -237,7 +301,7 @@ TEST_F(ValidateLimits, CustomizedSwitchNumBranchesBad) { %5 = OpFunction %1 None %2 %7 = OpLabel %8 = OpIAdd %3 %4 %4 -%9 = OpSwitch %4 %10)"; + OpSwitch %4 %10)"; // Now add the (literal, label) pairs for (int i = 0; i < 11; ++i) { @@ -289,7 +353,7 @@ TEST_F(ValidateLimits, OpTypeFunctionBad) { EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("OpTypeFunction may not take more than 255 arguments. " - "OpTypeFunction '2' has 256 arguments.")); + "OpTypeFunction '2[%2]' has 256 arguments.")); } // Valid: OpTypeFunction with 100 arguments (Custom limit: 100) @@ -325,7 +389,7 @@ TEST_F(ValidateLimits, CustomizedOpTypeFunctionBad) { EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("OpTypeFunction may not take more than 100 arguments. " - "OpTypeFunction '2' has 101 arguments.")); + "OpTypeFunction '2[%2]' has 101 arguments.")); } // Valid: module has 65,535 global variables. @@ -649,14 +713,6 @@ void GenerateSpirvProgramWithCfgNestingDepth(std::string& str, int depth) { } // clang-format on -// Valid: Control Flow Nesting depth is 1023. -TEST_F(ValidateLimits, ControlFlowDepthGood) { - std::string spirv; - GenerateSpirvProgramWithCfgNestingDepth(spirv, 1023); - CompileSuccessfully(spirv); - EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); -} - // Invalid: Control Flow Nesting depth is 1024. (limit is 1023). TEST_F(ValidateLimits, ControlFlowDepthBad) { std::string spirv; @@ -698,13 +754,17 @@ TEST_F(ValidateLimits, ControlFlowNoEntryToLoopGood) { OpName %loop "loop" OpName %exit "exit" %voidt = OpTypeVoid +%boolt = OpTypeBool +%undef = OpUndef %boolt %funct = OpTypeFunction %voidt %main = OpFunction %voidt None %funct %entry = OpLabel OpBranch %exit %loop = OpLabel - OpLoopMerge %loop %loop None - OpBranch %loop + OpLoopMerge %dead %loop None + OpBranchConditional %undef %loop %loop +%dead = OpLabel + OpUnreachable %exit = OpLabel OpReturn OpFunctionEnd diff --git a/third_party/spirv-tools/test/val/val_literals_test.cpp b/third_party/spirv-tools/test/val/val_literals_test.cpp index cbdbdd10e7..6eadf321cc 100644 --- a/third_party/spirv-tools/test/val/val_literals_test.cpp +++ b/third_party/spirv-tools/test/val/val_literals_test.cpp @@ -85,6 +85,16 @@ TEST_F(ValidateLiterals, LiteralsShaderGood) { ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); } +TEST_F(ValidateLiterals, InvalidInt) { + std::string str = GenerateShaderCode() + R"( +%11 = OpTypeInt 32 90 + )"; + CompileSuccessfully(str); + EXPECT_EQ(SPV_ERROR_INVALID_VALUE, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("OpTypeInt has invalid signedness:")); +} + TEST_P(ValidateLiteralsShader, LiteralsShaderBad) { std::string str = GenerateShaderCode() + GetParam(); std::string inst_id = "11"; @@ -99,7 +109,7 @@ TEST_P(ValidateLiteralsShader, LiteralsShaderBad) { "or sign extended when Signedness is 1")); } -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( LiteralsShaderCases, ValidateLiteralsShader, ::testing::Values("%11 = OpConstant %int16 !0xFFFF0000", // Sign bit is 0 "%11 = OpConstant %int16 !0x00008000", // Sign bit is 1 @@ -132,7 +142,7 @@ TEST_P(ValidateLiteralsKernel, LiteralsKernelBad) { "or sign extended when Signedness is 1")); } -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( LiteralsKernelCases, ValidateLiteralsKernel, ::testing::Values("%2 = OpConstant %uint8 !0xABCDEF00", "%2 = OpConstant %uint8 !0xABCDEFFF")); diff --git a/third_party/spirv-tools/test/val/val_logicals_test.cpp b/third_party/spirv-tools/test/val/val_logicals_test.cpp index 449cdd54fc..b57c743371 100644 --- a/third_party/spirv-tools/test/val/val_logicals_test.cpp +++ b/third_party/spirv-tools/test/val/val_logicals_test.cpp @@ -24,6 +24,7 @@ namespace spvtools { namespace val { namespace { +using ::testing::Eq; using ::testing::HasSubstr; using ::testing::Not; @@ -43,6 +44,7 @@ OpCapability Float64)"; %ext_inst = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft %void = OpTypeVoid %func = OpTypeFunction %void %bool = OpTypeBool @@ -143,6 +145,18 @@ OpEntryPoint Fragment %main "main" %boolvec3_tft = OpConstantComposite %boolvec3 %true %false %true %boolvec4_tftf = OpConstantComposite %boolvec4 %true %false %true %false +%arr_u32_2 = OpTypeArray %u32 %u32_2 +%st_u32_u32 = OpTypeStruct %u32 %u32 +%mat_f32_2_2 = OpTypeMatrix %f32vec2 2 + +%nul_arr_u32_2 = OpConstantNull %arr_u32_2 +%nul_st_u32_u32 = OpConstantNull %st_u32_u32 +%nul_mat_f32_2_2 = OpConstantNull %mat_f32_2_2 + +%arr_u32_2_1_2 = OpConstantComposite %arr_u32_2 %u32_1 %u32_2 +%st_u32_u32_1_2 = OpConstantComposite %st_u32_u32 %u32_1 %u32_2 +%mat_f32_2_2_01_12 = OpConstantComposite %mat_f32_2_2 %f32vec2_01 %f32vec2_12 + %f32vec4ptr = OpTypePointer Function %f32vec4 %main = OpFunction %void None %func @@ -584,6 +598,20 @@ TEST_F(ValidateLogicals, OpSelectWrongTypeId) { HasSubstr("Expected scalar or vector type as Result Type: Select")); } +TEST_F(ValidateLogicals, OpSelectWrongTypeIdV14) { + // In 1.4, the message changes to allow composites. + const std::string body = R"( +%val1 = OpSelect %void %true %u32_0 %u32_1 +)"; + + CompileSuccessfully(GenerateShaderCode(body).c_str(), SPV_ENV_UNIVERSAL_1_4); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Expected scalar or composite type as Result Type: Select")); +} + TEST_F(ValidateLogicals, OpSelectPointerNoCapability) { const std::string body = R"( %x = OpVariable %f32vec4ptr Function @@ -686,6 +714,111 @@ TEST_F(ValidateLogicals, OpSelectWrongRightObject) { HasSubstr("Expected both objects to be of Result Type: Select")); } +TEST_F(ValidateLogicals, OpSelectArrayV13Bad) { + const std::string body = R"( +%val1 = OpSelect %arr_u32_2 %true %nul_arr_u32_2 %arr_u32_2_1_2 +)"; + + CompileSuccessfully(GenerateShaderCode(body).c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Expected scalar or vector type as Result Type: Select")); +} + +TEST_F(ValidateLogicals, OpSelectArrayV13TargetV14Bad) { + const std::string body = R"( +%val1 = OpSelect %arr_u32_2 %true %nul_arr_u32_2 %arr_u32_2_1_2 +)"; + + CompileSuccessfully(GenerateShaderCode(body).c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Expected scalar or vector type as Result Type")); +} + +TEST_F(ValidateLogicals, OpSelectArrayV14Good) { + const std::string body = R"( +%val1 = OpSelect %arr_u32_2 %true %nul_arr_u32_2 %arr_u32_2_1_2 +)"; + + CompileSuccessfully(GenerateShaderCode(body).c_str(), SPV_ENV_UNIVERSAL_1_4); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateLogicals, OpSelectStructV13Bad) { + const std::string body = R"( +%val1 = OpSelect %st_u32_u32 %true %nul_st_u32_u32 %st_u32_u32_1_2 +)"; + + CompileSuccessfully(GenerateShaderCode(body).c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Expected scalar or vector type as Result Type: Select")); +} + +TEST_F(ValidateLogicals, OpSelectStructV13TargetV14Bad) { + const std::string body = R"( +%val1 = OpSelect %st_u32_u32 %true %nul_st_u32_u32 %st_u32_u32_1_2 +)"; + + CompileSuccessfully(GenerateShaderCode(body).c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Expected scalar or vector type as Result Type")); +} + +TEST_F(ValidateLogicals, OpSelectStructV14Good) { + const std::string body = R"( +%val1 = OpSelect %st_u32_u32 %true %nul_st_u32_u32 %st_u32_u32_1_2 +)"; + + CompileSuccessfully(GenerateShaderCode(body).c_str(), SPV_ENV_UNIVERSAL_1_4); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateLogicals, OpSelectMatrixV13Bad) { + const std::string body = R"( +%val1 = OpSelect %mat_f32_2_2 %true %nul_mat_f32_2_2 %mat_f32_2_2_01_12 +)"; + + CompileSuccessfully(GenerateShaderCode(body).c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Expected scalar or vector type as Result Type: Select")); +} + +TEST_F(ValidateLogicals, OpSelectMatrixV13TargetV14Bad) { + const std::string body = R"( +%val1 = OpSelect %mat_f32_2_2 %true %nul_mat_f32_2_2 %mat_f32_2_2_01_12 +)"; + + CompileSuccessfully(GenerateShaderCode(body).c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Expected scalar or vector type as Result Type")); +} + +TEST_F(ValidateLogicals, OpSelectMatrixV14Good) { + const std::string body = R"( +%val1 = OpSelect %mat_f32_2_2 %true %nul_mat_f32_2_2 %mat_f32_2_2_01_12 +)"; + + CompileSuccessfully(GenerateShaderCode(body).c_str(), SPV_ENV_UNIVERSAL_1_4); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + TEST_F(ValidateLogicals, OpIEqualSuccess) { const std::string body = R"( %val1 = OpIEqual %bool %u32_0 %s32_1 @@ -918,6 +1051,114 @@ TEST_F(ValidateLogicals, OpSGreaterThanDifferentBitWidth) { "width: SGreaterThan")); } +TEST_F(ValidateLogicals, PSBSelectSuccess) { + const std::string body = R"( +OpCapability PhysicalStorageBufferAddressesEXT +OpCapability Int64 +OpCapability Shader +OpExtension "SPV_EXT_physical_storage_buffer" +OpMemoryModel PhysicalStorageBuffer64EXT GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpDecorate %val1 AliasedPointerEXT +%uint64 = OpTypeInt 64 0 +%bool = OpTypeBool +%true = OpConstantTrue %bool +%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64 +%pptr_f = OpTypePointer Function %ptr +%void = OpTypeVoid +%voidfn = OpTypeFunction %void +%main = OpFunction %void None %voidfn +%entry = OpLabel +%val1 = OpVariable %pptr_f Function +%val2 = OpLoad %ptr %val1 +%val3 = OpSelect %ptr %true %val2 %val2 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(body.c_str()); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateLogicals, SelectVectorsScalarCondition) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%bool = OpTypeBool +%int = OpTypeInt 32 0 +%int4 = OpTypeVector %int 4 +%int4_0 = OpConstantNull %int4 +%true = OpConstantTrue %bool +%void_fn = OpTypeFunction %void +%func = OpFunction %void None %void_fn +%1 = OpLabel +%select = OpSelect %int4 %true %int4_0 %int4_0 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Expected vector sizes of Result Type and the " + "condition to be equal: Select")); +} + +TEST_F(ValidateLogicals, SelectVectorsScalarCondition1p4) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%bool = OpTypeBool +%int = OpTypeInt 32 0 +%int4 = OpTypeVector %int 4 +%int4_0 = OpConstantNull %int4 +%true = OpConstantTrue %bool +%void_fn = OpTypeFunction %void +%func = OpFunction %void None %void_fn +%1 = OpLabel +%select = OpSelect %int4 %true %int4_0 %int4_0 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); +} + +TEST_F(ValidateLogicals, SelectVectorsVectorConditionMismatchedDimensions1p4) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%bool = OpTypeBool +%bool3 = OpTypeVector %bool 3 +%int = OpTypeInt 32 0 +%int4 = OpTypeVector %int 4 +%int4_0 = OpConstantNull %int4 +%bool3_null = OpConstantNull %bool3 +%void_fn = OpTypeFunction %void +%func = OpFunction %void None %void_fn +%1 = OpLabel +%select = OpSelect %int4 %bool3_null %int4_0 %int4_0 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Expected vector sizes of Result Type and the " + "condition to be equal: Select")); +} + } // namespace } // namespace val } // namespace spvtools diff --git a/third_party/spirv-tools/test/val/val_memory_test.cpp b/third_party/spirv-tools/test/val/val_memory_test.cpp new file mode 100644 index 0000000000..22761cc1e1 --- /dev/null +++ b/third_party/spirv-tools/test/val/val_memory_test.cpp @@ -0,0 +1,4483 @@ +// Copyright (c) 2018 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Validation tests for memory/storage + +#include +#include + +#include "gmock/gmock.h" +#include "test/unit_spirv.h" +#include "test/val/val_code_generator.h" +#include "test/val/val_fixtures.h" + +namespace spvtools { +namespace val { +namespace { + +using ::testing::Combine; +using ::testing::Eq; +using ::testing::HasSubstr; +using ::testing::Values; + +using ValidateMemory = spvtest::ValidateBase; + +TEST_F(ValidateMemory, VulkanUniformConstantOnNonOpaqueResourceBad) { + std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +%float = OpTypeFloat 32 +%float_ptr = OpTypePointer UniformConstant %float +%2 = OpVariable %float_ptr UniformConstant +%void = OpTypeVoid +%functy = OpTypeFunction %void +%func = OpFunction %void None %functy +%1 = OpLabel +OpReturn +OpFunctionEnd +)"; + CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("From Vulkan spec, section 14.5.2:\n" + "Variables identified with the UniformConstant storage class " + "are used only as handles to refer to opaque resources. Such " + "variables must be typed as OpTypeImage, OpTypeSampler, " + "OpTypeSampledImage, OpTypeAccelerationStructureNV, or an " + "array of one of these types.")); +} + +TEST_F(ValidateMemory, VulkanUniformConstantOnOpaqueResourceGood) { + std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +OpDecorate %2 DescriptorSet 0 +OpDecorate %2 Binding 0 +%sampler = OpTypeSampler +%sampler_ptr = OpTypePointer UniformConstant %sampler +%2 = OpVariable %sampler_ptr UniformConstant +%void = OpTypeVoid +%functy = OpTypeFunction %void +%func = OpFunction %void None %functy +%1 = OpLabel +OpReturn +OpFunctionEnd +)"; + CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1)); +} + +TEST_F(ValidateMemory, VulkanUniformConstantOnNonOpaqueResourceArrayBad) { + std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +%float = OpTypeFloat 32 +%uint = OpTypeInt 32 0 +%array_size = OpConstant %uint 5 +%array = OpTypeArray %float %array_size +%array_ptr = OpTypePointer UniformConstant %array +%2 = OpVariable %array_ptr UniformConstant +%void = OpTypeVoid +%functy = OpTypeFunction %void +%func = OpFunction %void None %functy +%1 = OpLabel +OpReturn +OpFunctionEnd +)"; + CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("From Vulkan spec, section 14.5.2:\n" + "Variables identified with the UniformConstant storage class " + "are used only as handles to refer to opaque resources. Such " + "variables must be typed as OpTypeImage, OpTypeSampler, " + "OpTypeSampledImage, OpTypeAccelerationStructureNV, or an " + "array of one of these types.")); +} + +TEST_F(ValidateMemory, VulkanUniformConstantOnOpaqueResourceArrayGood) { + std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +OpDecorate %2 DescriptorSet 0 +OpDecorate %2 Binding 0 +%sampler = OpTypeSampler +%uint = OpTypeInt 32 0 +%array_size = OpConstant %uint 5 +%array = OpTypeArray %sampler %array_size +%array_ptr = OpTypePointer UniformConstant %array +%2 = OpVariable %array_ptr UniformConstant +%void = OpTypeVoid +%functy = OpTypeFunction %void +%func = OpFunction %void None %functy +%1 = OpLabel +OpReturn +OpFunctionEnd +)"; + CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1)); +} + +TEST_F(ValidateMemory, VulkanUniformConstantOnOpaqueResourceRuntimeArrayGood) { + std::string spirv = R"( +OpCapability RuntimeDescriptorArrayEXT +OpCapability Shader +OpExtension "SPV_EXT_descriptor_indexing" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +OpDecorate %2 DescriptorSet 0 +OpDecorate %2 Binding 0 +%sampler = OpTypeSampler +%uint = OpTypeInt 32 0 +%array = OpTypeRuntimeArray %sampler +%array_ptr = OpTypePointer UniformConstant %array +%2 = OpVariable %array_ptr UniformConstant +%void = OpTypeVoid +%functy = OpTypeFunction %void +%func = OpFunction %void None %functy +%1 = OpLabel +OpReturn +OpFunctionEnd +)"; + CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1)); +} + +TEST_F(ValidateMemory, VulkanUniformOnIntBad) { + char src[] = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %kernel "main" + OpExecutionMode %kernel LocalSize 1 1 1 + + OpDecorate %var DescriptorSet 0 + OpDecorate %var Binding 0 + + %voidty = OpTypeVoid +%kernelty = OpTypeFunction %voidty + %intty = OpTypeInt 32 0 + %varty = OpTypePointer Uniform %intty + %value = OpConstant %intty 42 + + %var = OpVariable %varty Uniform + + %kernel = OpFunction %voidty None %kernelty + %label = OpLabel + OpStore %var %value + OpReturn + OpFunctionEnd +)"; + CompileSuccessfully(src, SPV_ENV_VULKAN_1_1); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("From Vulkan spec, section 14.5.2:\n" + "Variables identified with the Uniform storage class are used " + "to access transparent buffer backed resources. Such variables " + "must be typed as OpTypeStruct, or an array of this type")); +} + +// #version 440 +// #extension GL_EXT_nonuniform_qualifier : enable +// layout(binding = 1) uniform sampler2D s2d[][2]; +// layout(location = 0) in nonuniformEXT int i; +// void main() +// { +// vec4 v = texture(s2d[i][i], vec2(0.3)); +// } +TEST_F(ValidateMemory, VulkanUniformOnRuntimeArrayOfArrayBad) { + char src[] = R"( + OpCapability Shader + OpCapability ShaderNonUniformEXT + OpCapability RuntimeDescriptorArrayEXT + OpCapability SampledImageArrayNonUniformIndexingEXT + OpExtension "SPV_EXT_descriptor_indexing" + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %main "main" %i + OpSource GLSL 440 + OpSourceExtension "GL_EXT_nonuniform_qualifier" + OpName %main "main" + OpName %v "v" + OpName %s2d "s2d" + OpName %i "i" + OpDecorate %s2d DescriptorSet 0 + OpDecorate %s2d Binding 1 + OpDecorate %i Location 0 + OpDecorate %i NonUniformEXT + OpDecorate %21 NonUniformEXT + OpDecorate %22 NonUniformEXT + OpDecorate %25 NonUniformEXT + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 +%_ptr_Function_v4float = OpTypePointer Function %v4float + %10 = OpTypeImage %float 2D 0 0 0 1 Unknown + %11 = OpTypeSampledImage %10 + %uint = OpTypeInt 32 0 + %uint_2 = OpConstant %uint 2 +%_arr_11_uint_2 = OpTypeArray %11 %uint_2 +%_runtimearr__arr_11_uint_2 = OpTypeRuntimeArray %_arr_11_uint_2 +%_ptr_Uniform__runtimearr__arr_11_uint_2 = OpTypePointer Uniform %_runtimearr__arr_11_uint_2 + %s2d = OpVariable %_ptr_Uniform__runtimearr__arr_11_uint_2 Uniform + %int = OpTypeInt 32 1 +%_ptr_Input_int = OpTypePointer Input %int + %i = OpVariable %_ptr_Input_int Input +%_ptr_Uniform_11 = OpTypePointer Uniform %11 + %v2float = OpTypeVector %float 2 +%float_0_300000012 = OpConstant %float 0.300000012 + %28 = OpConstantComposite %v2float %float_0_300000012 %float_0_300000012 + %float_0 = OpConstant %float 0 + %main = OpFunction %void None %3 + %5 = OpLabel + %v = OpVariable %_ptr_Function_v4float Function + %21 = OpLoad %int %i + %22 = OpLoad %int %i + %24 = OpAccessChain %_ptr_Uniform_11 %s2d %21 %22 + %25 = OpLoad %11 %24 + %30 = OpImageSampleExplicitLod %v4float %25 %28 Lod %float_0 + OpStore %v %30 + OpReturn + OpFunctionEnd +)"; + CompileSuccessfully(src, SPV_ENV_VULKAN_1_1); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("From Vulkan spec, section 14.5.2:\n" + "Variables identified with the Uniform storage class are used " + "to access transparent buffer backed resources. Such variables " + "must be typed as OpTypeStruct, or an array of this type")); +} + +// #version 440 +// layout (set=1, binding=1) uniform sampler2D variableName[2][2]; +// void main() { +// } +TEST_F(ValidateMemory, VulkanUniformOnArrayOfArrayBad) { + char src[] = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %main "main" + OpSource GLSL 440 + OpName %main "main" + OpName %variableName "variableName" + OpDecorate %variableName DescriptorSet 1 + OpDecorate %variableName Binding 1 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %7 = OpTypeImage %float 2D 0 0 0 1 Unknown + %8 = OpTypeSampledImage %7 + %uint = OpTypeInt 32 0 + %uint_2 = OpConstant %uint 2 +%_arr_8_uint_2 = OpTypeArray %8 %uint_2 +%_arr__arr_8_uint_2_uint_2 = OpTypeArray %_arr_8_uint_2 %uint_2 +%_ptr_Uniform__arr__arr_8_uint_2_uint_2 = OpTypePointer Uniform %_arr__arr_8_uint_2_uint_2 +%variableName = OpVariable %_ptr_Uniform__arr__arr_8_uint_2_uint_2 Uniform + %main = OpFunction %void None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd +)"; + CompileSuccessfully(src, SPV_ENV_VULKAN_1_1); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("From Vulkan spec, section 14.5.2:\n" + "Variables identified with the Uniform storage class are used " + "to access transparent buffer backed resources. Such variables " + "must be typed as OpTypeStruct, or an array of this type")); +} + +TEST_F(ValidateMemory, MismatchingStorageClassesBad) { + std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +%float = OpTypeFloat 32 +%float_ptr = OpTypePointer Uniform %float +%void = OpTypeVoid +%functy = OpTypeFunction %void +%func = OpFunction %void None %functy +%1 = OpLabel +%2 = OpVariable %float_ptr Function +OpReturn +OpFunctionEnd +)"; + CompileSuccessfully(spirv.c_str()); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "From SPIR-V spec, section 3.32.8 on OpVariable:\n" + "Its Storage Class operand must be the same as the Storage Class " + "operand of the result type.")); +} + +TEST_F(ValidateMemory, MatchingStorageClassesGood) { + std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +%float = OpTypeFloat 32 +%float_ptr = OpTypePointer Function %float +%void = OpTypeVoid +%functy = OpTypeFunction %void +%func = OpFunction %void None %functy +%1 = OpLabel +%2 = OpVariable %float_ptr Function +OpReturn +OpFunctionEnd +)"; + CompileSuccessfully(spirv.c_str()); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateMemory, WebGPUInitializerWithOutputStorageClassesGood) { + std::string spirv = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +%float = OpTypeFloat 32 +%float_ptr = OpTypePointer Output %float +%init_val = OpConstant %float 1.0 +%1 = OpVariable %float_ptr Output %init_val +%void = OpTypeVoid +%functy = OpTypeFunction %void +%func = OpFunction %void None %functy +%2 = OpLabel +OpReturn +OpFunctionEnd +)"; + CompileSuccessfully(spirv.c_str(), SPV_ENV_WEBGPU_0); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); +} + +TEST_F(ValidateMemory, WebGPUInitializerWithFunctionStorageClassesGood) { + std::string spirv = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +%float = OpTypeFloat 32 +%float_ptr = OpTypePointer Function %float +%init_val = OpConstant %float 1.0 +%void = OpTypeVoid +%functy = OpTypeFunction %void +%func = OpFunction %void None %functy +%1 = OpLabel +%2 = OpVariable %float_ptr Function %init_val +OpReturn +OpFunctionEnd +)"; + CompileSuccessfully(spirv.c_str(), SPV_ENV_WEBGPU_0); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); +} + +TEST_F(ValidateMemory, WebGPUInitializerWithPrivateStorageClassesGood) { + std::string spirv = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +%float = OpTypeFloat 32 +%float_ptr = OpTypePointer Private %float +%init_val = OpConstant %float 1.0 +%1 = OpVariable %float_ptr Private %init_val +%void = OpTypeVoid +%functy = OpTypeFunction %void +%func = OpFunction %void None %functy +%2 = OpLabel +OpReturn +OpFunctionEnd +)"; + CompileSuccessfully(spirv.c_str(), SPV_ENV_WEBGPU_0); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); +} + +TEST_F(ValidateMemory, WebGPUInitializerWithDisallowedStorageClassesBad) { + std::string spirv = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +%float = OpTypeFloat 32 +%float_ptr = OpTypePointer Uniform %float +%init_val = OpConstant %float 1.0 +%1 = OpVariable %float_ptr Uniform %init_val +%void = OpTypeVoid +%functy = OpTypeFunction %void +%func = OpFunction %void None %functy +%2 = OpLabel +OpReturn +OpFunctionEnd +)"; + CompileSuccessfully(spirv.c_str(), SPV_ENV_WEBGPU_0); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("OpVariable, '5[%5]', has a disallowed initializer & " + "storage class combination.\nFrom WebGPU spec:\nVariable " + "declarations that include initializers must have one of the " + "following storage classes: Output, Private, or Function\n %5 " + "= OpVariable %_ptr_Uniform_float Uniform %float_1\n")); +} + +TEST_F(ValidateMemory, WebGPUOutputStorageClassWithoutInitializerBad) { + std::string spirv = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +%float = OpTypeFloat 32 +%float_ptr = OpTypePointer Output %float +%1 = OpVariable %float_ptr Output +%void = OpTypeVoid +%functy = OpTypeFunction %void +%func = OpFunction %void None %functy +%2 = OpLabel +OpReturn +OpFunctionEnd +)"; + CompileSuccessfully(spirv.c_str(), SPV_ENV_WEBGPU_0); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("OpVariable, '4[%4]', must have an initializer.\n" + "From WebGPU execution environment spec:\n" + "All variables in the following storage classes must have an " + "initializer: Output, Private, or Function\n" + " %4 = OpVariable %_ptr_Output_float Output\n")); +} + +TEST_F(ValidateMemory, WebGPUFunctionStorageClassWithoutInitializerBad) { + std::string spirv = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +%float = OpTypeFloat 32 +%float_ptr = OpTypePointer Function %float +%void = OpTypeVoid +%functy = OpTypeFunction %void +%func = OpFunction %void None %functy +%1 = OpLabel +%2 = OpVariable %float_ptr Function +OpReturn +OpFunctionEnd +)"; + CompileSuccessfully(spirv.c_str(), SPV_ENV_WEBGPU_0); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("OpVariable, '7[%7]', must have an initializer.\n" + "From WebGPU execution environment spec:\n" + "All variables in the following storage classes must have an " + "initializer: Output, Private, or Function\n" + " %7 = OpVariable %_ptr_Function_float Function\n")); +} + +TEST_F(ValidateMemory, WebGPUPrivateStorageClassWithoutInitializerBad) { + std::string spirv = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +%float = OpTypeFloat 32 +%float_ptr = OpTypePointer Private %float +%1 = OpVariable %float_ptr Private +%void = OpTypeVoid +%functy = OpTypeFunction %void +%func = OpFunction %void None %functy +%2 = OpLabel +OpReturn +OpFunctionEnd +)"; + CompileSuccessfully(spirv.c_str(), SPV_ENV_WEBGPU_0); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("OpVariable, '4[%4]', must have an initializer.\n" + "From WebGPU execution environment spec:\n" + "All variables in the following storage classes must have an " + "initializer: Output, Private, or Function\n" + " %4 = OpVariable %_ptr_Private_float Private\n")); +} + +TEST_F(ValidateMemory, VulkanInitializerWithOutputStorageClassesGood) { + std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +%float = OpTypeFloat 32 +%float_ptr = OpTypePointer Output %float +%init_val = OpConstant %float 1.0 +%1 = OpVariable %float_ptr Output %init_val +%void = OpTypeVoid +%functy = OpTypeFunction %void +%func = OpFunction %void None %functy +%2 = OpLabel +OpReturn +OpFunctionEnd +)"; + CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1)); +} + +TEST_F(ValidateMemory, VulkanInitializerWithFunctionStorageClassesGood) { + std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +%float = OpTypeFloat 32 +%float_ptr = OpTypePointer Function %float +%init_val = OpConstant %float 1.0 +%void = OpTypeVoid +%functy = OpTypeFunction %void +%func = OpFunction %void None %functy +%1 = OpLabel +%2 = OpVariable %float_ptr Function %init_val +OpReturn +OpFunctionEnd +)"; + CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1)); +} + +TEST_F(ValidateMemory, VulkanInitializerWithPrivateStorageClassesGood) { + std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +%float = OpTypeFloat 32 +%float_ptr = OpTypePointer Private %float +%init_val = OpConstant %float 1.0 +%1 = OpVariable %float_ptr Private %init_val +%void = OpTypeVoid +%functy = OpTypeFunction %void +%func = OpFunction %void None %functy +%2 = OpLabel +OpReturn +OpFunctionEnd +)"; + CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1)); +} + +TEST_F(ValidateMemory, VulkanInitializerWithDisallowedStorageClassesBad) { + std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +%float = OpTypeFloat 32 +%float_ptr = OpTypePointer Input %float +%init_val = OpConstant %float 1.0 +%1 = OpVariable %float_ptr Input %init_val +%void = OpTypeVoid +%functy = OpTypeFunction %void +%func = OpFunction %void None %functy +%2 = OpLabel +OpReturn +OpFunctionEnd +)"; + CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("OpVariable, '5[%5]', has a disallowed initializer & " + "storage class combination.\nFrom Vulkan spec:\nVariable " + "declarations that include initializers must have one of the " + "following storage classes: Output, Private, or Function\n %5 " + "= OpVariable %_ptr_Input_float Input %float_1\n")); +} + +TEST_F(ValidateMemory, ArrayLenCorrectResultType) { + std::string spirv = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "main" + OpExecutionMode %1 OriginUpperLeft + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %uint = OpTypeInt 32 0 +%_runtimearr_float = OpTypeRuntimeArray %float + %_struct_7 = OpTypeStruct %_runtimearr_float +%_ptr_Function__struct_7 = OpTypePointer Function %_struct_7 + %1 = OpFunction %void None %3 + %9 = OpLabel + %10 = OpVariable %_ptr_Function__struct_7 Function + %11 = OpArrayLength %uint %10 0 + OpReturn + OpFunctionEnd + +)"; + + CompileSuccessfully(spirv.c_str()); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateMemory, ArrayLenIndexCorrectWith2Members) { + std::string spirv = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "main" + OpExecutionMode %1 OriginUpperLeft + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %uint = OpTypeInt 32 0 +%_runtimearr_float = OpTypeRuntimeArray %float + %_struct_7 = OpTypeStruct %float %_runtimearr_float +%_ptr_Function__struct_7 = OpTypePointer Function %_struct_7 + %1 = OpFunction %void None %3 + %9 = OpLabel + %10 = OpVariable %_ptr_Function__struct_7 Function + %11 = OpArrayLength %uint %10 1 + OpReturn + OpFunctionEnd + +)"; + + CompileSuccessfully(spirv.c_str()); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateMemory, ArrayLenResultNotIntType) { + std::string spirv = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "main" + OpExecutionMode %1 OriginUpperLeft + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 +%_runtimearr_float = OpTypeRuntimeArray %float + %_struct_6 = OpTypeStruct %_runtimearr_float +%_ptr_Function__struct_6 = OpTypePointer Function %_struct_6 + %1 = OpFunction %void None %3 + %8 = OpLabel + %9 = OpVariable %_ptr_Function__struct_6 Function + %10 = OpArrayLength %float %9 0 + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv.c_str()); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "The Result Type of OpArrayLength '10[%10]' must be OpTypeInt " + "with width 32 and signedness 0.\n %10 = OpArrayLength %float %9 " + "0\n")); +} + +TEST_F(ValidateMemory, ArrayLenResultNot32bits) { + std::string spirv = R"( + OpCapability Shader + OpCapability Int16 + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "main" + OpExecutionMode %1 OriginUpperLeft + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %ushort = OpTypeInt 16 0 +%_runtimearr_float = OpTypeRuntimeArray %float + %_struct_7 = OpTypeStruct %_runtimearr_float +%_ptr_Function__struct_7 = OpTypePointer Function %_struct_7 + %1 = OpFunction %void None %3 + %9 = OpLabel + %10 = OpVariable %_ptr_Function__struct_7 Function + %11 = OpArrayLength %ushort %10 0 + OpReturn + OpFunctionEnd + +)"; + + CompileSuccessfully(spirv.c_str()); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "The Result Type of OpArrayLength '11[%11]' must be OpTypeInt " + "with width 32 and signedness 0.\n %11 = OpArrayLength %ushort %10 " + "0\n")); +} + +TEST_F(ValidateMemory, ArrayLenResultSigned) { + std::string spirv = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "main" + OpExecutionMode %1 OriginUpperLeft + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %int = OpTypeInt 32 1 +%_runtimearr_float = OpTypeRuntimeArray %float + %_struct_7 = OpTypeStruct %_runtimearr_float +%_ptr_Function__struct_7 = OpTypePointer Function %_struct_7 + %1 = OpFunction %void None %3 + %9 = OpLabel + %10 = OpVariable %_ptr_Function__struct_7 Function + %11 = OpArrayLength %int %10 0 + OpReturn + OpFunctionEnd + +)"; + + CompileSuccessfully(spirv.c_str()); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "The Result Type of OpArrayLength '11[%11]' must be OpTypeInt " + "with width 32 and signedness 0.\n %11 = OpArrayLength %int %10 " + "0\n")); +} + +TEST_F(ValidateMemory, ArrayLenInputNotStruct) { + std::string spirv = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "main" + OpExecutionMode %1 OriginUpperLeft + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %uint = OpTypeInt 32 0 +%_runtimearr_float = OpTypeRuntimeArray %float + %_struct_7 = OpTypeStruct %_runtimearr_float +%_ptr_Function_float = OpTypePointer Function %float + %1 = OpFunction %void None %3 + %9 = OpLabel + %10 = OpVariable %_ptr_Function_float Function + %11 = OpArrayLength %uint %10 0 + OpReturn + OpFunctionEnd + +)"; + + CompileSuccessfully(spirv.c_str()); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("The Struture's type in OpArrayLength '11[%11]' " + "must be a pointer to an OpTypeStruct.")); +} + +TEST_F(ValidateMemory, ArrayLenInputLastMemberNoRTA) { + std::string spirv = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "main" + OpExecutionMode %1 OriginUpperLeft + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %uint = OpTypeInt 32 0 +%_runtimearr_float = OpTypeRuntimeArray %float + %_struct_7 = OpTypeStruct %float +%_ptr_Function__struct_7 = OpTypePointer Function %_struct_7 + %1 = OpFunction %void None %3 + %9 = OpLabel + %10 = OpVariable %_ptr_Function__struct_7 Function + %11 = OpArrayLength %uint %10 0 + OpReturn + OpFunctionEnd + +)"; + + CompileSuccessfully(spirv.c_str()); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("The Struture's last member in OpArrayLength '11[%11]' " + "must be an OpTypeRuntimeArray.\n %11 = OpArrayLength %uint " + "%10 0\n")); +} + +TEST_F(ValidateMemory, ArrayLenInputLastMemberNoRTA2) { + std::string spirv = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "main" + OpExecutionMode %1 OriginUpperLeft + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %uint = OpTypeInt 32 0 +%_runtimearr_float = OpTypeRuntimeArray %float + %_struct_7 = OpTypeStruct %_runtimearr_float %float +%_ptr_Function__struct_7 = OpTypePointer Function %_struct_7 + %1 = OpFunction %void None %3 + %9 = OpLabel + %10 = OpVariable %_ptr_Function__struct_7 Function + %11 = OpArrayLength %uint %10 1 + OpReturn + OpFunctionEnd + +)"; + + CompileSuccessfully(spirv.c_str()); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("The Struture's last member in OpArrayLength '11[%11]' " + "must be an OpTypeRuntimeArray.\n %11 = OpArrayLength %uint " + "%10 1\n")); +} + +TEST_F(ValidateMemory, ArrayLenIndexNotLastMember) { + std::string spirv = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "main" + OpExecutionMode %1 OriginUpperLeft + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %uint = OpTypeInt 32 0 +%_runtimearr_float = OpTypeRuntimeArray %float + %_struct_7 = OpTypeStruct %float %_runtimearr_float +%_ptr_Function__struct_7 = OpTypePointer Function %_struct_7 + %1 = OpFunction %void None %3 + %9 = OpLabel + %10 = OpVariable %_ptr_Function__struct_7 Function + %11 = OpArrayLength %uint %10 0 + OpReturn + OpFunctionEnd + +)"; + + CompileSuccessfully(spirv.c_str()); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "The array member in OpArrayLength '11[%11]' must be an the " + "last member of the struct.\n %11 = OpArrayLength %uint %10 0\n")); +} + +TEST_F(ValidateMemory, ArrayLenIndexNotPointerToStruct) { + std::string spirv = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "main" + OpExecutionMode %1 OriginUpperLeft + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %uint = OpTypeInt 32 0 +%_runtimearr_float = OpTypeRuntimeArray %float + %_struct_7 = OpTypeStruct %float %_runtimearr_float +%_ptr_Function__struct_7 = OpTypePointer Function %_struct_7 + %1 = OpFunction %void None %3 + %9 = OpLabel + %10 = OpVariable %_ptr_Function__struct_7 Function + %11 = OpLoad %_struct_7 %10 + %12 = OpArrayLength %uint %11 0 + OpReturn + OpFunctionEnd + +)"; + + CompileSuccessfully(spirv.c_str()); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "The Struture's type in OpArrayLength '12[%12]' must be a " + "pointer to an OpTypeStruct.\n %12 = OpArrayLength %uint %11 0\n")); +} + +TEST_F(ValidateMemory, ArrayLenPointerIsAType) { + std::string spirv = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "main" + OpExecutionMode %1 OriginUpperLeft + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %uint = OpTypeInt 32 0 + %1 = OpFunction %void None %3 + %9 = OpLabel + %12 = OpArrayLength %uint %float 0 + OpReturn + OpFunctionEnd + +)"; + + CompileSuccessfully(spirv.c_str()); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), HasSubstr("Operand 4[%float] cannot be a " + "type")); +} + +TEST_F(ValidateMemory, PushConstantNotStructGood) { + std::string spirv = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "main" + OpExecutionMode %1 OriginUpperLeft + + %void = OpTypeVoid + %voidfn = OpTypeFunction %void + %float = OpTypeFloat 32 + %ptr = OpTypePointer PushConstant %float + %pc = OpVariable %ptr PushConstant + + %1 = OpFunction %void None %voidfn + %label = OpLabel + OpReturn + OpFunctionEnd +)"; + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateMemory, VulkanPushConstantNotStructBad) { + std::string spirv = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "main" + OpExecutionMode %1 OriginUpperLeft + + %void = OpTypeVoid + %voidfn = OpTypeFunction %void + %float = OpTypeFloat 32 + %ptr = OpTypePointer PushConstant %float + %pc = OpVariable %ptr PushConstant + + %1 = OpFunction %void None %voidfn + %label = OpLabel + OpReturn + OpFunctionEnd +)"; + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("PushConstant OpVariable '6[%6]' has illegal " + "type.\nFrom Vulkan spec, section 14.5.1:\n" + "Such variables must be typed as OpTypeStruct, " + "or an array of this type")); +} + +TEST_F(ValidateMemory, VulkanPushConstant) { + std::string spirv = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "main" + OpExecutionMode %1 OriginUpperLeft + + OpDecorate %struct Block + OpMemberDecorate %struct 0 Offset 0 + + %void = OpTypeVoid + %voidfn = OpTypeFunction %void + %float = OpTypeFloat 32 + %struct = OpTypeStruct %float + %ptr = OpTypePointer PushConstant %struct + %pc = OpVariable %ptr PushConstant + + %1 = OpFunction %void None %voidfn + %label = OpLabel + OpReturn + OpFunctionEnd +)"; + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1)); +} + +TEST_F(ValidateMemory, VulkanMemoryModelDeviceScopeLoadBad1) { + const std::string spirv = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpCapability Linkage +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%device = OpConstant %int 1 +%int_ptr_ssbo = OpTypePointer StorageBuffer %int +%var = OpVariable %int_ptr_ssbo StorageBuffer +%voidfn = OpTypeFunction %void +%func = OpFunction %void None %voidfn +%entry = OpLabel +%load = OpLoad %int %var MakePointerVisibleKHR|NonPrivatePointerKHR %device +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Use of device scope with VulkanKHR memory model requires the " + "VulkanMemoryModelDeviceScopeKHR capability")); +} + +TEST_F(ValidateMemory, VulkanMemoryModelDeviceScopeLoadBad2) { + const std::string spirv = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpCapability Linkage +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%device = OpConstant %int 1 +%int_ptr_ssbo = OpTypePointer StorageBuffer %int +%var = OpVariable %int_ptr_ssbo StorageBuffer +%voidfn = OpTypeFunction %void +%func = OpFunction %void None %voidfn +%entry = OpLabel +%load = OpLoad %int %var Aligned|MakePointerVisibleKHR|NonPrivatePointerKHR 4 %device +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Use of device scope with VulkanKHR memory model requires the " + "VulkanMemoryModelDeviceScopeKHR capability")); +} + +TEST_F(ValidateMemory, VulkanMemoryModelDeviceScopeLoadGood1) { + const std::string spirv = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpCapability VulkanMemoryModelDeviceScopeKHR +OpCapability Linkage +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%device = OpConstant %int 1 +%int_ptr_ssbo = OpTypePointer StorageBuffer %int +%var = OpVariable %int_ptr_ssbo StorageBuffer +%voidfn = OpTypeFunction %void +%func = OpFunction %void None %voidfn +%entry = OpLabel +%load = OpLoad %int %var MakePointerVisibleKHR|NonPrivatePointerKHR %device +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); +} + +TEST_F(ValidateMemory, VulkanMemoryModelDeviceScopeLoadGood2) { + const std::string spirv = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpCapability VulkanMemoryModelDeviceScopeKHR +OpCapability Linkage +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%device = OpConstant %int 1 +%int_ptr_ssbo = OpTypePointer StorageBuffer %int +%var = OpVariable %int_ptr_ssbo StorageBuffer +%voidfn = OpTypeFunction %void +%func = OpFunction %void None %voidfn +%entry = OpLabel +%load = OpLoad %int %var Aligned|MakePointerVisibleKHR|NonPrivatePointerKHR 4 %device +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); +} + +TEST_F(ValidateMemory, VulkanMemoryModelDeviceScopeStoreBad1) { + const std::string spirv = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpCapability Linkage +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%device = OpConstant %int 1 +%int_ptr_ssbo = OpTypePointer StorageBuffer %int +%var = OpVariable %int_ptr_ssbo StorageBuffer +%voidfn = OpTypeFunction %void +%func = OpFunction %void None %voidfn +%entry = OpLabel +OpStore %var %device MakePointerAvailableKHR|NonPrivatePointerKHR %device +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Use of device scope with VulkanKHR memory model requires the " + "VulkanMemoryModelDeviceScopeKHR capability")); +} + +TEST_F(ValidateMemory, VulkanMemoryModelDeviceScopeStoreBad2) { + const std::string spirv = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpCapability Linkage +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%device = OpConstant %int 1 +%int_ptr_ssbo = OpTypePointer StorageBuffer %int +%var = OpVariable %int_ptr_ssbo StorageBuffer +%voidfn = OpTypeFunction %void +%func = OpFunction %void None %voidfn +%entry = OpLabel +OpStore %var %device Aligned|MakePointerAvailableKHR|NonPrivatePointerKHR 4 %device +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Use of device scope with VulkanKHR memory model requires the " + "VulkanMemoryModelDeviceScopeKHR capability")); +} + +TEST_F(ValidateMemory, VulkanMemoryModelDeviceScopeStoreGood1) { + const std::string spirv = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpCapability VulkanMemoryModelDeviceScopeKHR +OpCapability Linkage +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%device = OpConstant %int 1 +%int_ptr_ssbo = OpTypePointer StorageBuffer %int +%var = OpVariable %int_ptr_ssbo StorageBuffer +%voidfn = OpTypeFunction %void +%func = OpFunction %void None %voidfn +%entry = OpLabel +OpStore %var %device MakePointerAvailableKHR|NonPrivatePointerKHR %device +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); +} + +TEST_F(ValidateMemory, VulkanMemoryModelDeviceScopeStoreGood2) { + const std::string spirv = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpCapability VulkanMemoryModelDeviceScopeKHR +OpCapability Linkage +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%device = OpConstant %int 1 +%int_ptr_ssbo = OpTypePointer StorageBuffer %int +%var = OpVariable %int_ptr_ssbo StorageBuffer +%voidfn = OpTypeFunction %void +%func = OpFunction %void None %voidfn +%entry = OpLabel +OpStore %var %device Aligned|MakePointerAvailableKHR|NonPrivatePointerKHR 4 %device +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); +} + +TEST_F(ValidateMemory, VulkanMemoryModelDeviceScopeCopyMemoryBad1) { + const std::string spirv = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpCapability Linkage +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%device = OpConstant %int 1 +%int_ptr_ssbo = OpTypePointer StorageBuffer %int +%var1 = OpVariable %int_ptr_ssbo StorageBuffer +%var2 = OpVariable %int_ptr_ssbo StorageBuffer +%voidfn = OpTypeFunction %void +%func = OpFunction %void None %voidfn +%entry = OpLabel +OpCopyMemory %var1 %var2 MakePointerAvailableKHR|NonPrivatePointerKHR %device +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Use of device scope with VulkanKHR memory model requires the " + "VulkanMemoryModelDeviceScopeKHR capability")); +} + +TEST_F(ValidateMemory, VulkanMemoryModelDeviceScopeCopyMemoryBad2) { + const std::string spirv = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpCapability Linkage +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%device = OpConstant %int 1 +%workgroup = OpConstant %int 1 +%int_ptr_ssbo = OpTypePointer StorageBuffer %int +%var1 = OpVariable %int_ptr_ssbo StorageBuffer +%var2 = OpVariable %int_ptr_ssbo StorageBuffer +%voidfn = OpTypeFunction %void +%func = OpFunction %void None %voidfn +%entry = OpLabel +OpCopyMemory %var1 %var2 Aligned|MakePointerVisibleKHR|MakePointerAvailableKHR|NonPrivatePointerKHR 4 %device %workgroup +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Use of device scope with VulkanKHR memory model requires the " + "VulkanMemoryModelDeviceScopeKHR capability")); +} + +TEST_F(ValidateMemory, VulkanMemoryModelDeviceScopeCopyMemoryBad3) { + const std::string spirv = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpCapability Linkage +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%device = OpConstant %int 1 +%workgroup = OpConstant %int 1 +%int_ptr_ssbo = OpTypePointer StorageBuffer %int +%var1 = OpVariable %int_ptr_ssbo StorageBuffer +%var2 = OpVariable %int_ptr_ssbo StorageBuffer +%voidfn = OpTypeFunction %void +%func = OpFunction %void None %voidfn +%entry = OpLabel +OpCopyMemory %var1 %var2 Aligned|MakePointerVisibleKHR|MakePointerAvailableKHR|NonPrivatePointerKHR 4 %workgroup %device +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Use of device scope with VulkanKHR memory model requires the " + "VulkanMemoryModelDeviceScopeKHR capability")); +} + +TEST_F(ValidateMemory, VulkanMemoryModelDeviceScopeCopyMemoryGood2) { + const std::string spirv = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpCapability VulkanMemoryModelDeviceScopeKHR +OpCapability Linkage +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%device = OpConstant %int 1 +%workgroup = OpConstant %int 2 +%int_ptr_ssbo = OpTypePointer StorageBuffer %int +%var1 = OpVariable %int_ptr_ssbo StorageBuffer +%var2 = OpVariable %int_ptr_ssbo StorageBuffer +%voidfn = OpTypeFunction %void +%func = OpFunction %void None %voidfn +%entry = OpLabel +OpCopyMemory %var1 %var2 Aligned|MakePointerVisibleKHR|MakePointerAvailableKHR|NonPrivatePointerKHR 4 %device %workgroup +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); +} + +TEST_F(ValidateMemory, VulkanMemoryModelDeviceScopeCopyMemoryGood3) { + const std::string spirv = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpCapability VulkanMemoryModelDeviceScopeKHR +OpCapability Linkage +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%device = OpConstant %int 1 +%workgroup = OpConstant %int 2 +%int_ptr_ssbo = OpTypePointer StorageBuffer %int +%var1 = OpVariable %int_ptr_ssbo StorageBuffer +%var2 = OpVariable %int_ptr_ssbo StorageBuffer +%voidfn = OpTypeFunction %void +%func = OpFunction %void None %voidfn +%entry = OpLabel +OpCopyMemory %var1 %var2 Aligned|MakePointerVisibleKHR|MakePointerAvailableKHR|NonPrivatePointerKHR 4 %workgroup %device +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); +} + +TEST_F(ValidateMemory, VulkanMemoryModelCopyMemoryTwoAccessAvVisBadBinaryV13) { + const std::string spirv = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpCapability VulkanMemoryModelDeviceScopeKHR +OpCapability Linkage +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%device = OpConstant %int 1 +%int_ptr_ssbo = OpTypePointer StorageBuffer %int +%var1 = OpVariable %int_ptr_ssbo StorageBuffer +%var2 = OpVariable %int_ptr_ssbo StorageBuffer +%voidfn = OpTypeFunction %void +%func = OpFunction %void None %voidfn +%entry = OpLabel +OpCopyMemory %var1 %var2 + MakePointerAvailableKHR|NonPrivatePointerKHR %device + MakePointerVisibleKHR|NonPrivatePointerKHR %device +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "with two memory access operands requires SPIR-V 1.4 or later")); +} + +TEST_F(ValidateMemory, VulkanMemoryModelCopyMemoryTwoAccessAvVisGood) { + const std::string spirv = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpCapability VulkanMemoryModelDeviceScopeKHR +OpCapability Linkage +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%device = OpConstant %int 1 +%int_ptr_ssbo = OpTypePointer StorageBuffer %int +%var1 = OpVariable %int_ptr_ssbo StorageBuffer +%var2 = OpVariable %int_ptr_ssbo StorageBuffer +%voidfn = OpTypeFunction %void +%func = OpFunction %void None %voidfn +%entry = OpLabel +OpCopyMemory %var1 %var2 + MakePointerAvailableKHR|NonPrivatePointerKHR %device + MakePointerVisibleKHR|NonPrivatePointerKHR %device +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateMemory, VulkanMemoryModelCopyMemoryTwoAccessFirstWithAvBad) { + const std::string spirv = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpCapability VulkanMemoryModelDeviceScopeKHR +OpCapability Linkage +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%device = OpConstant %int 1 +%int_ptr_ssbo = OpTypePointer StorageBuffer %int +%var1 = OpVariable %int_ptr_ssbo StorageBuffer +%var2 = OpVariable %int_ptr_ssbo StorageBuffer +%voidfn = OpTypeFunction %void +%func = OpFunction %void None %voidfn +%entry = OpLabel +OpCopyMemory %var1 %var2 + MakePointerAvailableKHR|NonPrivatePointerKHR %device + MakePointerAvailableKHR|NonPrivatePointerKHR %device +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "Source memory access must not include MakePointerAvailableKHR\n" + " OpCopyMemory %5 %6 MakePointerAvailable|NonPrivatePointer" + " %uint_1 MakePointerAvailable|NonPrivatePointer %uint_1")); +} + +TEST_F(ValidateMemory, VulkanMemoryModelCopyMemoryTwoAccessSecondWithVisBad) { + const std::string spirv = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpCapability VulkanMemoryModelDeviceScopeKHR +OpCapability Linkage +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%device = OpConstant %int 1 +%int_ptr_ssbo = OpTypePointer StorageBuffer %int +%var1 = OpVariable %int_ptr_ssbo StorageBuffer +%var2 = OpVariable %int_ptr_ssbo StorageBuffer +%voidfn = OpTypeFunction %void +%func = OpFunction %void None %voidfn +%entry = OpLabel +OpCopyMemory %var1 %var2 + MakePointerVisibleKHR|NonPrivatePointerKHR %device + MakePointerVisibleKHR|NonPrivatePointerKHR %device +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Target memory access must not include MakePointerVisibleKHR\n" + " OpCopyMemory %5 %6 MakePointerVisible|NonPrivatePointer" + " %uint_1 MakePointerVisible|NonPrivatePointer %uint_1")); +} + +TEST_F(ValidateMemory, VulkanMemoryModelDeviceScopeCopyMemorySizedBad1) { + const std::string spirv = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpCapability Linkage +OpCapability Addresses +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%device = OpConstant %int 1 +%int_ptr_ssbo = OpTypePointer StorageBuffer %int +%var1 = OpVariable %int_ptr_ssbo StorageBuffer +%var2 = OpVariable %int_ptr_ssbo StorageBuffer +%voidfn = OpTypeFunction %void +%func = OpFunction %void None %voidfn +%entry = OpLabel +OpCopyMemorySized %var1 %var2 %device MakePointerAvailableKHR|NonPrivatePointerKHR %device +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Use of device scope with VulkanKHR memory model requires the " + "VulkanMemoryModelDeviceScopeKHR capability")); +} + +TEST_F(ValidateMemory, VulkanMemoryModelDeviceScopeCopyMemorySizedBad2) { + const std::string spirv = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpCapability Linkage +OpCapability Addresses +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%device = OpConstant %int 1 +%workgroup = OpConstant %int 1 +%int_ptr_ssbo = OpTypePointer StorageBuffer %int +%var1 = OpVariable %int_ptr_ssbo StorageBuffer +%var2 = OpVariable %int_ptr_ssbo StorageBuffer +%voidfn = OpTypeFunction %void +%func = OpFunction %void None %voidfn +%entry = OpLabel +OpCopyMemorySized %var1 %var2 %device Aligned|MakePointerVisibleKHR|MakePointerAvailableKHR|NonPrivatePointerKHR 4 %device %workgroup +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Use of device scope with VulkanKHR memory model requires the " + "VulkanMemoryModelDeviceScopeKHR capability")); +} + +TEST_F(ValidateMemory, VulkanMemoryModelDeviceScopeCopyMemorySizedBad3) { + const std::string spirv = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpCapability Linkage +OpCapability Addresses +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%device = OpConstant %int 1 +%workgroup = OpConstant %int 1 +%int_ptr_ssbo = OpTypePointer StorageBuffer %int +%var1 = OpVariable %int_ptr_ssbo StorageBuffer +%var2 = OpVariable %int_ptr_ssbo StorageBuffer +%voidfn = OpTypeFunction %void +%func = OpFunction %void None %voidfn +%entry = OpLabel +OpCopyMemorySized %var1 %var2 %device Aligned|MakePointerVisibleKHR|MakePointerAvailableKHR|NonPrivatePointerKHR 4 %workgroup %device +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Use of device scope with VulkanKHR memory model requires the " + "VulkanMemoryModelDeviceScopeKHR capability")); +} + +TEST_F(ValidateMemory, VulkanMemoryModelDeviceScopeCopyMemorySizedGood1) { + const std::string spirv = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpCapability VulkanMemoryModelDeviceScopeKHR +OpCapability Linkage +OpCapability Addresses +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%device = OpConstant %int 1 +%int_ptr_ssbo = OpTypePointer StorageBuffer %int +%var1 = OpVariable %int_ptr_ssbo StorageBuffer +%var2 = OpVariable %int_ptr_ssbo StorageBuffer +%voidfn = OpTypeFunction %void +%func = OpFunction %void None %voidfn +%entry = OpLabel +OpCopyMemorySized %var1 %var2 %device MakePointerAvailableKHR|NonPrivatePointerKHR %device +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); +} + +TEST_F(ValidateMemory, VulkanMemoryModelDeviceScopeCopyMemorySizedGood2) { + const std::string spirv = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpCapability VulkanMemoryModelDeviceScopeKHR +OpCapability Linkage +OpCapability Addresses +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%device = OpConstant %int 1 +%workgroup = OpConstant %int 2 +%int_ptr_ssbo = OpTypePointer StorageBuffer %int +%var1 = OpVariable %int_ptr_ssbo StorageBuffer +%var2 = OpVariable %int_ptr_ssbo StorageBuffer +%voidfn = OpTypeFunction %void +%func = OpFunction %void None %voidfn +%entry = OpLabel +OpCopyMemorySized %var1 %var2 %device Aligned|MakePointerVisibleKHR|MakePointerAvailableKHR|NonPrivatePointerKHR 4 %device %workgroup +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); +} + +TEST_F(ValidateMemory, VulkanMemoryModelDeviceScopeCopyMemorySizedGood3) { + const std::string spirv = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpCapability VulkanMemoryModelDeviceScopeKHR +OpCapability Linkage +OpCapability Addresses +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%device = OpConstant %int 1 +%workgroup = OpConstant %int 2 +%int_ptr_ssbo = OpTypePointer StorageBuffer %int +%var1 = OpVariable %int_ptr_ssbo StorageBuffer +%var2 = OpVariable %int_ptr_ssbo StorageBuffer +%voidfn = OpTypeFunction %void +%func = OpFunction %void None %voidfn +%entry = OpLabel +OpCopyMemorySized %var1 %var2 %device Aligned|MakePointerVisibleKHR|MakePointerAvailableKHR|NonPrivatePointerKHR 4 %workgroup %device +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); +} + +TEST_F(ValidateMemory, ArrayLengthStructIsLabel) { + const std::string spirv = R"( +OpCapability Tessellation +OpMemoryModel Logical GLSL450 +OpName %20 "incorrect" +%void = OpTypeVoid +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v4float = OpTypeVector %float 4 +%uint = OpTypeInt 32 0 +%4 = OpFunction %void None %3 +%20 = OpLabel +%24 = OpArrayLength %uint %20 0 +%25 = OpLoad %v4float %24 +OpReturnValue %25 +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Operand 1[%incorrect] requires a type")); +} + +TEST_F(ValidateMemory, PSBLoadAlignedSuccess) { + const std::string body = R"( +OpCapability PhysicalStorageBufferAddressesEXT +OpCapability Int64 +OpCapability Shader +OpExtension "SPV_EXT_physical_storage_buffer" +OpMemoryModel PhysicalStorageBuffer64EXT GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpDecorate %val1 AliasedPointerEXT +%uint64 = OpTypeInt 64 0 +%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64 +%pptr_f = OpTypePointer Function %ptr +%void = OpTypeVoid +%voidfn = OpTypeFunction %void +%main = OpFunction %void None %voidfn +%entry = OpLabel +%val1 = OpVariable %pptr_f Function +%val2 = OpLoad %ptr %val1 +%val3 = OpLoad %uint64 %val2 Aligned 8 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(body.c_str()); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateMemory, PSBLoadAlignedMissing) { + const std::string body = R"( +OpCapability PhysicalStorageBufferAddressesEXT +OpCapability Int64 +OpCapability Shader +OpExtension "SPV_EXT_physical_storage_buffer" +OpMemoryModel PhysicalStorageBuffer64EXT GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpDecorate %val1 AliasedPointerEXT +%uint64 = OpTypeInt 64 0 +%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64 +%pptr_f = OpTypePointer Function %ptr +%void = OpTypeVoid +%voidfn = OpTypeFunction %void +%main = OpFunction %void None %voidfn +%entry = OpLabel +%val1 = OpVariable %pptr_f Function +%val2 = OpLoad %ptr %val1 +%val3 = OpLoad %uint64 %val2 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(body.c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "Memory accesses with PhysicalStorageBufferEXT must use Aligned")); +} + +TEST_F(ValidateMemory, PSBStoreAlignedSuccess) { + const std::string body = R"( +OpCapability PhysicalStorageBufferAddressesEXT +OpCapability Int64 +OpCapability Shader +OpExtension "SPV_EXT_physical_storage_buffer" +OpMemoryModel PhysicalStorageBuffer64EXT GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpDecorate %val1 AliasedPointerEXT +%uint64 = OpTypeInt 64 0 +%u64_1 = OpConstant %uint64 1 +%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64 +%pptr_f = OpTypePointer Function %ptr +%void = OpTypeVoid +%voidfn = OpTypeFunction %void +%main = OpFunction %void None %voidfn +%entry = OpLabel +%val1 = OpVariable %pptr_f Function +%val2 = OpLoad %ptr %val1 +OpStore %val2 %u64_1 Aligned 8 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(body.c_str()); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateMemory, PSBStoreAlignedMissing) { + const std::string body = R"( +OpCapability PhysicalStorageBufferAddressesEXT +OpCapability Int64 +OpCapability Shader +OpExtension "SPV_EXT_physical_storage_buffer" +OpMemoryModel PhysicalStorageBuffer64EXT GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpDecorate %val1 AliasedPointerEXT +%uint64 = OpTypeInt 64 0 +%u64_1 = OpConstant %uint64 1 +%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64 +%pptr_f = OpTypePointer Function %ptr +%void = OpTypeVoid +%voidfn = OpTypeFunction %void +%main = OpFunction %void None %voidfn +%entry = OpLabel +%val1 = OpVariable %pptr_f Function +%val2 = OpLoad %ptr %val1 +OpStore %val2 %u64_1 None +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(body.c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "Memory accesses with PhysicalStorageBufferEXT must use Aligned")); +} + +TEST_F(ValidateMemory, PSBVariable) { + const std::string body = R"( +OpCapability PhysicalStorageBufferAddressesEXT +OpCapability Int64 +OpCapability Shader +OpExtension "SPV_EXT_physical_storage_buffer" +OpMemoryModel PhysicalStorageBuffer64EXT GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpDecorate %val1 AliasedPointerEXT +%uint64 = OpTypeInt 64 0 +%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64 +%val1 = OpVariable %ptr PhysicalStorageBufferEXT +%void = OpTypeVoid +%voidfn = OpTypeFunction %void +%main = OpFunction %void None %voidfn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(body); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("PhysicalStorageBufferEXT must not be used with OpVariable")); +} + +std::string GenCoopMatLoadStoreShader(const std::string& storeMemoryAccess, + const std::string& loadMemoryAccess) { + std::string s = R"( +OpCapability Shader +OpCapability GroupNonUniform +OpCapability VulkanMemoryModelKHR +OpCapability CooperativeMatrixNV +OpExtension "SPV_KHR_vulkan_memory_model" +OpExtension "SPV_NV_cooperative_matrix" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical VulkanKHR +OpEntryPoint GLCompute %4 "main" %11 %21 +OpExecutionMode %4 LocalSize 1 1 1 +OpDecorate %11 BuiltIn SubgroupId +OpDecorate %21 BuiltIn WorkgroupId +OpDecorate %74 ArrayStride 4 +OpMemberDecorate %75 0 Offset 0 +OpDecorate %75 Block +OpDecorate %77 DescriptorSet 0 +OpDecorate %77 Binding 0 +OpDecorate %92 ArrayStride 4 +OpMemberDecorate %93 0 Offset 0 +OpDecorate %93 Block +OpDecorate %95 DescriptorSet 0 +OpDecorate %95 Binding 1 +OpDecorate %102 ArrayStride 4 +OpMemberDecorate %103 0 Offset 0 +OpDecorate %103 Block +OpDecorate %105 DescriptorSet 0 +OpDecorate %105 Binding 2 +OpDecorate %117 ArrayStride 4 +OpMemberDecorate %118 0 Offset 0 +OpDecorate %118 Block +OpDecorate %120 DescriptorSet 0 +OpDecorate %120 Binding 3 +OpDecorate %123 SpecId 2 +OpDecorate %124 SpecId 3 +OpDecorate %125 SpecId 4 +OpDecorate %126 SpecId 5 +OpDecorate %127 SpecId 0 +OpDecorate %128 SpecId 1 +OpDecorate %129 BuiltIn WorkgroupSize +%2 = OpTypeVoid +%3 = OpTypeFunction %2 +%6 = OpTypeInt 32 0 +%7 = OpTypeVector %6 2 +%8 = OpTypePointer Function %7 +%10 = OpTypePointer Input %6 +%11 = OpVariable %10 Input +%13 = OpConstant %6 2 +%19 = OpTypeVector %6 3 +%20 = OpTypePointer Input %19 +%21 = OpVariable %20 Input +%27 = OpConstantComposite %7 %13 %13 +%31 = OpTypePointer Function %6 +%33 = OpConstant %6 1024 +%34 = OpConstant %6 1 +%38 = OpConstant %6 8 +%39 = OpConstant %6 0 +%68 = OpTypeFloat 32 +%69 = OpConstant %6 16 +%70 = OpConstant %6 3 +%71 = OpTypeCooperativeMatrixNV %68 %70 %69 %38 +%72 = OpTypePointer Function %71 +%74 = OpTypeRuntimeArray %68 +%75 = OpTypeStruct %74 +%76 = OpTypePointer StorageBuffer %75 +%77 = OpVariable %76 StorageBuffer +%78 = OpTypeInt 32 1 +%79 = OpConstant %78 0 +%81 = OpConstant %6 5 +%82 = OpTypePointer StorageBuffer %68 +%84 = OpConstant %6 64 +%85 = OpTypeBool +%86 = OpConstantFalse %85 +%88 = OpTypePointer Private %71 +%89 = OpVariable %88 Private +%92 = OpTypeRuntimeArray %68 +%93 = OpTypeStruct %92 +%94 = OpTypePointer StorageBuffer %93 +%95 = OpVariable %94 StorageBuffer +%99 = OpVariable %88 Private +%102 = OpTypeRuntimeArray %68 +%103 = OpTypeStruct %102 +%104 = OpTypePointer StorageBuffer %103 +%105 = OpVariable %104 StorageBuffer +%109 = OpVariable %88 Private +%111 = OpVariable %88 Private +%112 = OpSpecConstantOp %6 CooperativeMatrixLengthNV %71 +%113 = OpSpecConstantOp %78 IAdd %112 %79 +%117 = OpTypeRuntimeArray %68 +%118 = OpTypeStruct %117 +%119 = OpTypePointer StorageBuffer %118 +%120 = OpVariable %119 StorageBuffer +%123 = OpSpecConstant %78 1 +%124 = OpSpecConstant %78 1 +%125 = OpSpecConstant %78 1 +%126 = OpSpecConstant %78 1 +%127 = OpSpecConstant %6 1 +%128 = OpSpecConstant %6 1 +%129 = OpSpecConstantComposite %19 %127 %128 %34 +%4 = OpFunction %2 None %3 +%5 = OpLabel +%9 = OpVariable %8 Function +%18 = OpVariable %8 Function +%32 = OpVariable %31 Function +%44 = OpVariable %31 Function +%52 = OpVariable %31 Function +%60 = OpVariable %31 Function +%73 = OpVariable %72 Function +%91 = OpVariable %72 Function +%101 = OpVariable %72 Function +%12 = OpLoad %6 %11 +%14 = OpUMod %6 %12 %13 +%15 = OpLoad %6 %11 +%16 = OpUDiv %6 %15 %13 +%17 = OpCompositeConstruct %7 %14 %16 +OpStore %9 %17 +%22 = OpLoad %19 %21 +%23 = OpVectorShuffle %7 %22 %22 0 1 +%24 = OpCompositeExtract %6 %23 0 +%25 = OpCompositeExtract %6 %23 1 +%26 = OpCompositeConstruct %7 %24 %25 +%28 = OpIMul %7 %26 %27 +%29 = OpLoad %7 %9 +%30 = OpIAdd %7 %28 %29 +OpStore %18 %30 +%35 = OpAccessChain %31 %18 %34 +%36 = OpLoad %6 %35 +%37 = OpIMul %6 %33 %36 +%40 = OpAccessChain %31 %18 %39 +%41 = OpLoad %6 %40 +%42 = OpIMul %6 %38 %41 +%43 = OpIAdd %6 %37 %42 +OpStore %32 %43 +%45 = OpAccessChain %31 %18 %34 +%46 = OpLoad %6 %45 +%47 = OpIMul %6 %33 %46 +%48 = OpAccessChain %31 %18 %39 +%49 = OpLoad %6 %48 +%50 = OpIMul %6 %38 %49 +%51 = OpIAdd %6 %47 %50 +OpStore %44 %51 +%53 = OpAccessChain %31 %18 %34 +%54 = OpLoad %6 %53 +%55 = OpIMul %6 %33 %54 +%56 = OpAccessChain %31 %18 %39 +%57 = OpLoad %6 %56 +%58 = OpIMul %6 %38 %57 +%59 = OpIAdd %6 %55 %58 +OpStore %52 %59 +%61 = OpAccessChain %31 %18 %34 +%62 = OpLoad %6 %61 +%63 = OpIMul %6 %33 %62 +%64 = OpAccessChain %31 %18 %39 +%65 = OpLoad %6 %64 +%66 = OpIMul %6 %38 %65 +%67 = OpIAdd %6 %63 %66 +OpStore %60 %67 +%80 = OpLoad %6 %32 +%83 = OpAccessChain %82 %77 %79 %80 +%87 = OpCooperativeMatrixLoadNV %71 %83 %84 %86 )" + + loadMemoryAccess + R"( %81 +OpStore %73 %87 +%90 = OpLoad %71 %73 +OpStore %89 %90 +%96 = OpLoad %6 %44 +%97 = OpAccessChain %82 %95 %79 %96 +%98 = OpCooperativeMatrixLoadNV %71 %97 %84 %86 MakePointerVisibleKHR|NonPrivatePointerKHR %81 +OpStore %91 %98 +%100 = OpLoad %71 %91 +OpStore %99 %100 +%106 = OpLoad %6 %52 +%107 = OpAccessChain %82 %105 %79 %106 +%108 = OpCooperativeMatrixLoadNV %71 %107 %84 %86 MakePointerVisibleKHR|NonPrivatePointerKHR %81 +OpStore %101 %108 +%110 = OpLoad %71 %101 +OpStore %109 %110 +%114 = OpConvertSToF %68 %113 +%115 = OpCompositeConstruct %71 %114 +OpStore %111 %115 +%116 = OpLoad %71 %111 +%121 = OpLoad %6 %60 +%122 = OpAccessChain %82 %120 %79 %121 +OpCooperativeMatrixStoreNV %122 %116 %84 %86 )" + storeMemoryAccess + R"( %81 +OpReturn +OpFunctionEnd +)"; + + return s; +} + +TEST_F(ValidateMemory, CoopMatLoadStoreSuccess) { + std::string spirv = + GenCoopMatLoadStoreShader("MakePointerAvailableKHR|NonPrivatePointerKHR", + "MakePointerVisibleKHR|NonPrivatePointerKHR"); + + CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1)); +} + +TEST_F(ValidateMemory, CoopMatStoreMemoryAccessFail) { + std::string spirv = + GenCoopMatLoadStoreShader("MakePointerVisibleKHR|NonPrivatePointerKHR", + "MakePointerVisibleKHR|NonPrivatePointerKHR"); + + CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("MakePointerVisibleKHR cannot be used with OpStore")); +} + +TEST_F(ValidateMemory, CoopMatLoadMemoryAccessFail) { + std::string spirv = + GenCoopMatLoadStoreShader("MakePointerAvailableKHR|NonPrivatePointerKHR", + "MakePointerAvailableKHR|NonPrivatePointerKHR"); + + CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("MakePointerAvailableKHR cannot be used with OpLoad")); +} + +TEST_F(ValidateMemory, CoopMatInvalidStorageClassFail) { + const std::string body = + R"( +OpCapability Shader +OpCapability Float16 +OpCapability CooperativeMatrixNV +OpExtension "SPV_NV_cooperative_matrix" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +%void = OpTypeVoid +%func = OpTypeFunction %void +%f16 = OpTypeFloat 16 +%u32 = OpTypeInt 32 0 + +%u32_8 = OpConstant %u32 8 +%subgroup = OpConstant %u32 3 + +%f16mat = OpTypeCooperativeMatrixNV %f16 %subgroup %u32_8 %u32_8 + +%str = OpTypeStruct %f16mat +%str_ptr = OpTypePointer Workgroup %str +%sh = OpVariable %str_ptr Workgroup + +%main = OpFunction %void None %func +%main_entry = OpLabel + +OpReturn +OpFunctionEnd)"; + + CompileSuccessfully(body.c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "Cooperative matrix types (or types containing them) can only be " + "allocated in Function or Private storage classes or as function " + "parameters")); +} + +TEST_F(ValidateMemory, CoopMatMatrixLengthResultTypeBad) { + const std::string body = + R"( +OpCapability Shader +OpCapability Float16 +OpCapability CooperativeMatrixNV +OpExtension "SPV_NV_cooperative_matrix" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +%void = OpTypeVoid +%func = OpTypeFunction %void +%f16 = OpTypeFloat 16 +%u32 = OpTypeInt 32 0 +%i32 = OpTypeInt 32 1 + +%u32_8 = OpConstant %u32 8 +%subgroup = OpConstant %u32 3 + +%f16mat = OpTypeCooperativeMatrixNV %f16 %subgroup %u32_8 %u32_8 + +%main = OpFunction %void None %func +%main_entry = OpLabel + +%1 = OpCooperativeMatrixLengthNV %i32 %f16mat + +OpReturn +OpFunctionEnd)"; + + CompileSuccessfully(body.c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("The Result Type of OpCooperativeMatrixLengthNV " + "'11[%11]' must be OpTypeInt with width 32 and signedness 0")); +} + +TEST_F(ValidateMemory, CoopMatMatrixLengthOperandTypeBad) { + const std::string body = + R"( +OpCapability Shader +OpCapability Float16 +OpCapability CooperativeMatrixNV +OpExtension "SPV_NV_cooperative_matrix" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +%void = OpTypeVoid +%func = OpTypeFunction %void +%f16 = OpTypeFloat 16 +%u32 = OpTypeInt 32 0 +%i32 = OpTypeInt 32 1 + +%u32_8 = OpConstant %u32 8 +%subgroup = OpConstant %u32 3 + +%f16mat = OpTypeCooperativeMatrixNV %f16 %subgroup %u32_8 %u32_8 + +%main = OpFunction %void None %func +%main_entry = OpLabel + +%1 = OpCooperativeMatrixLengthNV %u32 %u32 + +OpReturn +OpFunctionEnd)"; + + CompileSuccessfully(body.c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("The type in OpCooperativeMatrixLengthNV '5[%uint]' " + "must be OpTypeCooperativeMatrixNV")); +} + +TEST_F(ValidateMemory, CoopMatMatrixLengthGood) { + const std::string body = + R"( +OpCapability Shader +OpCapability Float16 +OpCapability CooperativeMatrixNV +OpExtension "SPV_NV_cooperative_matrix" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +%void = OpTypeVoid +%func = OpTypeFunction %void +%f16 = OpTypeFloat 16 +%u32 = OpTypeInt 32 0 +%i32 = OpTypeInt 32 1 + +%u32_8 = OpConstant %u32 8 +%subgroup = OpConstant %u32 3 + +%f16mat = OpTypeCooperativeMatrixNV %f16 %subgroup %u32_8 %u32_8 + +%main = OpFunction %void None %func +%main_entry = OpLabel + +%1 = OpCooperativeMatrixLengthNV %u32 %f16mat + +OpReturn +OpFunctionEnd)"; + + CompileSuccessfully(body.c_str()); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateMemory, VulkanRTAOutsideOfStructBad) { + std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +%sampler_t = OpTypeSampler +%array_t = OpTypeRuntimeArray %sampler_t +%array_ptr = OpTypePointer UniformConstant %array_t +%2 = OpVariable %array_ptr UniformConstant +%void = OpTypeVoid +%func_t = OpTypeFunction %void +%func = OpFunction %void None %func_t +%1 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "OpVariable, '5[%5]', is attempting to create memory for an " + "illegal type, OpTypeRuntimeArray.\nFor Vulkan OpTypeRuntimeArray " + "can only appear as the final member of an OpTypeStruct, thus cannot " + "be instantiated via OpVariable\n %5 = OpVariable " + "%_ptr_UniformConstant__runtimearr_2 UniformConstant\n")); +} + +TEST_F(ValidateMemory, WebGPURTAOutsideOfStructBad) { + std::string spirv = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +%sampler_t = OpTypeSampler +%array_t = OpTypeRuntimeArray %sampler_t +%array_ptr = OpTypePointer UniformConstant %array_t +%2 = OpVariable %array_ptr UniformConstant +%void = OpTypeVoid +%func_t = OpTypeFunction %void +%func = OpFunction %void None %func_t +%1 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv.c_str(), SPV_ENV_WEBGPU_0); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "OpVariable, '5[%5]', is attempting to create memory for an " + "illegal type, OpTypeRuntimeArray.\nFor WebGPU OpTypeRuntimeArray " + "can only appear as the final member of an OpTypeStruct, thus cannot " + "be instantiated via OpVariable\n %5 = OpVariable " + "%_ptr_UniformConstant__runtimearr_2 UniformConstant\n")); +} + +TEST_F(ValidateMemory, VulkanRTAOutsideOfStructWithRuntimeDescriptorArrayGood) { + std::string spirv = R"( +OpCapability Shader +OpCapability RuntimeDescriptorArrayEXT +OpExtension "SPV_EXT_descriptor_indexing" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +OpDecorate %struct Block +OpMemberDecorate %struct 0 Offset 0 +%sampler_t = OpTypeSampler +%uint = OpTypeInt 32 0 +%array_t = OpTypeRuntimeArray %sampler_t +%struct = OpTypeStruct %uint +%sb_array_t = OpTypeRuntimeArray %struct +%array_sb_ptr = OpTypePointer StorageBuffer %sb_array_t +%2 = OpVariable %array_sb_ptr StorageBuffer +%array_uc_ptr = OpTypePointer UniformConstant %array_t +%3 = OpVariable %array_uc_ptr UniformConstant +%void = OpTypeVoid +%func_t = OpTypeFunction %void +%func = OpFunction %void None %func_t +%1 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1)); +} + +TEST_F( + ValidateMemory, + VulkanRTAOutsideOfStructWithRuntimeDescriptorArrayAndWrongStorageClassBad) { + std::string spirv = R"( +OpCapability Shader +OpCapability RuntimeDescriptorArrayEXT +OpExtension "SPV_EXT_descriptor_indexing" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +%uint_t = OpTypeInt 32 0 +%array_t = OpTypeRuntimeArray %uint_t +%array_ptr = OpTypePointer Workgroup %array_t +%2 = OpVariable %array_ptr Workgroup +%void = OpTypeVoid +%func_t = OpTypeFunction %void +%func = OpFunction %void None %func_t +%1 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("For Vulkan with RuntimeDescriptorArrayEXT, a variable " + "containing OpTypeRuntimeArray must have storage class of " + "StorageBuffer, Uniform, or UniformConstant.\n %5 = " + "OpVariable %_ptr_Workgroup__runtimearr_uint Workgroup\n")); +} + +TEST_F(ValidateMemory, VulkanRTAInsideStorageBufferStructGood) { + std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +OpDecorate %array_t ArrayStride 4 +OpMemberDecorate %struct_t 0 Offset 0 +OpDecorate %struct_t Block +%uint_t = OpTypeInt 32 0 +%array_t = OpTypeRuntimeArray %uint_t +%struct_t = OpTypeStruct %array_t +%struct_ptr = OpTypePointer StorageBuffer %struct_t +%2 = OpVariable %struct_ptr StorageBuffer +%void = OpTypeVoid +%func_t = OpTypeFunction %void +%func = OpFunction %void None %func_t +%1 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1)); +} + +TEST_F(ValidateMemory, WebGPURTAInsideStorageBufferStructGood) { + std::string spirv = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +OpDecorate %array_t ArrayStride 4 +OpMemberDecorate %struct_t 0 Offset 0 +OpDecorate %struct_t Block +%uint_t = OpTypeInt 32 0 +%array_t = OpTypeRuntimeArray %uint_t +%struct_t = OpTypeStruct %array_t +%struct_ptr = OpTypePointer StorageBuffer %struct_t +%2 = OpVariable %struct_ptr StorageBuffer +%void = OpTypeVoid +%func_t = OpTypeFunction %void +%func = OpFunction %void None %func_t +%1 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv.c_str(), SPV_ENV_WEBGPU_0); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); +} + +TEST_F(ValidateMemory, VulkanRTAInsideWrongStorageClassStructBad) { + std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +%uint_t = OpTypeInt 32 0 +%array_t = OpTypeRuntimeArray %uint_t +%struct_t = OpTypeStruct %array_t +%struct_ptr = OpTypePointer Workgroup %struct_t +%2 = OpVariable %struct_ptr Workgroup +%void = OpTypeVoid +%func_t = OpTypeFunction %void +%func = OpFunction %void None %func_t +%1 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "For Vulkan, OpTypeStruct variables containing OpTypeRuntimeArray " + "must have storage class of StorageBuffer or Uniform.\n %6 = " + "OpVariable %_ptr_Workgroup__struct_4 Workgroup\n")); +} + +TEST_F(ValidateMemory, WebGPURTAInsideWrongStorageClassStructBad) { + std::string spirv = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +%uint_t = OpTypeInt 32 0 +%array_t = OpTypeRuntimeArray %uint_t +%struct_t = OpTypeStruct %array_t +%struct_ptr = OpTypePointer Workgroup %struct_t +%2 = OpVariable %struct_ptr Workgroup +%void = OpTypeVoid +%func_t = OpTypeFunction %void +%func = OpFunction %void None %func_t +%1 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv.c_str(), SPV_ENV_WEBGPU_0); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("For WebGPU, OpTypeStruct variables containing " + "OpTypeRuntimeArray must have storage class of StorageBuffer\n " + " %6 = OpVariable %_ptr_Workgroup__struct_4 Workgroup\n")); +} + +TEST_F(ValidateMemory, VulkanRTAInsideStorageBufferStructWithoutBlockBad) { + std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +%uint_t = OpTypeInt 32 0 +%array_t = OpTypeRuntimeArray %uint_t +%struct_t = OpTypeStruct %array_t +%struct_ptr = OpTypePointer StorageBuffer %struct_t +%2 = OpVariable %struct_ptr StorageBuffer +%void = OpTypeVoid +%func_t = OpTypeFunction %void +%func = OpFunction %void None %func_t +%1 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("For Vulkan, an OpTypeStruct variable containing an " + "OpTypeRuntimeArray must be decorated with Block if it " + "has storage class StorageBuffer.\n %6 = OpVariable " + "%_ptr_StorageBuffer__struct_4 StorageBuffer\n")); +} + +TEST_F(ValidateMemory, WebGPURTAInsideStorageBufferStructWithoutBlockBad) { + std::string spirv = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +%uint_t = OpTypeInt 32 0 +%array_t = OpTypeRuntimeArray %uint_t +%struct_t = OpTypeStruct %array_t +%struct_ptr = OpTypePointer StorageBuffer %struct_t +%2 = OpVariable %struct_ptr StorageBuffer +%void = OpTypeVoid +%func_t = OpTypeFunction %void +%func = OpFunction %void None %func_t +%1 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv.c_str(), SPV_ENV_WEBGPU_0); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("For WebGPU, an OpTypeStruct variable containing an " + "OpTypeRuntimeArray must be decorated with Block if it " + "has storage class StorageBuffer.\n %6 = OpVariable " + "%_ptr_StorageBuffer__struct_4 StorageBuffer\n")); +} + +TEST_F(ValidateMemory, VulkanRTAInsideUniformStructGood) { + std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +OpDecorate %array_t ArrayStride 4 +OpMemberDecorate %struct_t 0 Offset 0 +OpDecorate %struct_t BufferBlock +%uint_t = OpTypeInt 32 0 +%array_t = OpTypeRuntimeArray %uint_t +%struct_t = OpTypeStruct %array_t +%struct_ptr = OpTypePointer Uniform %struct_t +%2 = OpVariable %struct_ptr Uniform +%void = OpTypeVoid +%func_t = OpTypeFunction %void +%func = OpFunction %void None %func_t +%1 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1)); +} + +TEST_F(ValidateMemory, WebGPURTAInsideUniformStructBad) { + std::string spirv = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +OpDecorate %array_t ArrayStride 4 +OpMemberDecorate %struct_t 0 Offset 0 +OpDecorate %struct_t Block +%uint_t = OpTypeInt 32 0 +%array_t = OpTypeRuntimeArray %uint_t +%struct_t = OpTypeStruct %array_t +%struct_ptr = OpTypePointer Uniform %struct_t +%2 = OpVariable %struct_ptr Uniform +%void = OpTypeVoid +%func_t = OpTypeFunction %void +%func = OpFunction %void None %func_t +%1 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv.c_str(), SPV_ENV_WEBGPU_0); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("For WebGPU, OpTypeStruct variables containing " + "OpTypeRuntimeArray must have storage class of StorageBuffer\n " + " %6 = OpVariable %_ptr_Uniform__struct_3 Uniform\n")); +} + +TEST_F(ValidateMemory, VulkanRTAInsideUniformStructWithoutBufferBlockBad) { + std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +%uint_t = OpTypeInt 32 0 +%array_t = OpTypeRuntimeArray %uint_t +%struct_t = OpTypeStruct %array_t +%struct_ptr = OpTypePointer Uniform %struct_t +%2 = OpVariable %struct_ptr Uniform +%void = OpTypeVoid +%func_t = OpTypeFunction %void +%func = OpFunction %void None %func_t +%1 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("For Vulkan, an OpTypeStruct variable containing an " + "OpTypeRuntimeArray must be decorated with BufferBlock " + "if it has storage class Uniform.\n %6 = OpVariable " + "%_ptr_Uniform__struct_4 Uniform\n")); +} + +TEST_F(ValidateMemory, VulkanRTAInsideRTABad) { + std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +%sampler_t = OpTypeSampler +%inner_array_t = OpTypeRuntimeArray %sampler_t +%array_t = OpTypeRuntimeArray %inner_array_t +%array_ptr = OpTypePointer UniformConstant %array_t +%2 = OpVariable %array_ptr UniformConstant +%void = OpTypeVoid +%func_t = OpTypeFunction %void +%func = OpFunction %void None %func_t +%1 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "OpTypeRuntimeArray Element Type '3[%_runtimearr_2]' is not " + "valid in Vulkan environments.\n %_runtimearr__runtimearr_2 = " + "OpTypeRuntimeArray %_runtimearr_2\n")); +} + +TEST_F(ValidateMemory, WebGPURTAInsideRTABad) { + std::string spirv = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +%sampler_t = OpTypeSampler +%inner_array_t = OpTypeRuntimeArray %sampler_t +%array_t = OpTypeRuntimeArray %inner_array_t +%array_ptr = OpTypePointer UniformConstant %array_t +%2 = OpVariable %array_ptr UniformConstant +%void = OpTypeVoid +%func_t = OpTypeFunction %void +%func = OpFunction %void None %func_t +%1 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv.c_str(), SPV_ENV_WEBGPU_0); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "OpTypeRuntimeArray Element Type '3[%_runtimearr_2]' is not " + "valid in WebGPU environments.\n %_runtimearr__runtimearr_2 = " + "OpTypeRuntimeArray %_runtimearr_2\n")); +} + +TEST_F(ValidateMemory, VulkanRTAInsideRTAWithRuntimeDescriptorArrayBad) { + std::string spirv = R"( +OpCapability RuntimeDescriptorArrayEXT +OpCapability Shader +OpExtension "SPV_EXT_descriptor_indexing" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +OpDecorate %array_t Block +%uint_t = OpTypeInt 32 0 +%inner_array_t = OpTypeRuntimeArray %uint_t +%array_t = OpTypeRuntimeArray %inner_array_t +%array_ptr = OpTypePointer StorageBuffer %array_t +%2 = OpVariable %array_ptr StorageBuffer +%void = OpTypeVoid +%func_t = OpTypeFunction %void +%func = OpFunction %void None %func_t +%1 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "OpTypeRuntimeArray Element Type '4[%_runtimearr_uint]' is not " + "valid in Vulkan environments.\n %_runtimearr__runtimearr_uint = " + "OpTypeRuntimeArray %_runtimearr_uint\n")); +} + +TEST_F(ValidateMemory, + VulkanUniformStructInsideRTAWithRuntimeDescriptorArrayGood) { + std::string spirv = R"( +OpCapability RuntimeDescriptorArrayEXT +OpCapability Shader +OpExtension "SPV_EXT_descriptor_indexing" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +OpDecorate %array_t ArrayStride 4 +OpMemberDecorate %struct_t 0 Offset 0 +OpDecorate %struct_t Block +%uint_t = OpTypeInt 32 0 +%struct_t = OpTypeStruct %uint_t +%array_t = OpTypeRuntimeArray %struct_t +%array_ptr = OpTypePointer Uniform %array_t +%2 = OpVariable %array_ptr Uniform +%void = OpTypeVoid +%func_t = OpTypeFunction %void +%func = OpFunction %void None %func_t +%1 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1)); +} + +TEST_F(ValidateMemory, VulkanRTAInsideRTAInsideStructBad) { + std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +OpDecorate %array_t ArrayStride 4 +OpMemberDecorate %struct_t 0 Offset 0 +OpDecorate %struct_t Block +%uint_t = OpTypeInt 32 0 +%inner_array_t = OpTypeRuntimeArray %uint_t +%array_t = OpTypeRuntimeArray %inner_array_t +%struct_t = OpTypeStruct %array_t +%struct_ptr = OpTypePointer StorageBuffer %struct_t +%2 = OpVariable %struct_ptr StorageBuffer +%void = OpTypeVoid +%func_t = OpTypeFunction %void +%func = OpFunction %void None %func_t +%1 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "OpTypeRuntimeArray Element Type '5[%_runtimearr_uint]' is not " + "valid in Vulkan environments.\n %_runtimearr__runtimearr_uint = " + "OpTypeRuntimeArray %_runtimearr_uint\n")); +} + +TEST_F(ValidateMemory, + VulkanRTAInsideRTAInsideStructWithRuntimeDescriptorArrayBad) { + std::string spirv = R"( +OpCapability RuntimeDescriptorArrayEXT +OpCapability Shader +OpExtension "SPV_EXT_descriptor_indexing" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +OpDecorate %array_t ArrayStride 4 +OpMemberDecorate %struct_t 0 Offset 0 +OpDecorate %struct_t Block +%uint_t = OpTypeInt 32 0 +%inner_array_t = OpTypeRuntimeArray %uint_t +%array_t = OpTypeRuntimeArray %inner_array_t +%struct_t = OpTypeStruct %array_t +%struct_ptr = OpTypePointer StorageBuffer %struct_t +%2 = OpVariable %struct_ptr StorageBuffer +%void = OpTypeVoid +%func_t = OpTypeFunction %void +%func = OpFunction %void None %func_t +%1 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "OpTypeRuntimeArray Element Type '5[%_runtimearr_uint]' is not " + "valid in Vulkan environments.\n %_runtimearr__runtimearr_uint = " + "OpTypeRuntimeArray %_runtimearr_uint\n")); +} + +TEST_F(ValidateMemory, VulkanRTAInsideArrayBad) { + std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +%uint_t = OpTypeInt 32 0 +%dim = OpConstant %uint_t 1 +%sampler_t = OpTypeSampler +%inner_array_t = OpTypeRuntimeArray %sampler_t +%array_t = OpTypeArray %inner_array_t %dim +%array_ptr = OpTypePointer UniformConstant %array_t +%2 = OpVariable %array_ptr UniformConstant +%void = OpTypeVoid +%func_t = OpTypeFunction %void +%func = OpFunction %void None %func_t +%1 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("OpTypeArray Element Type '5[%_runtimearr_4]' is not " + "valid in Vulkan environments.\n %_arr__runtimearr_4_uint_1 = " + "OpTypeArray %_runtimearr_4 %uint_1\n")); +} + +TEST_F(ValidateMemory, WebGPURTAInsideArrayBad) { + std::string spirv = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +%uint_t = OpTypeInt 32 0 +%dim = OpConstant %uint_t 1 +%sampler_t = OpTypeSampler +%inner_array_t = OpTypeRuntimeArray %sampler_t +%array_t = OpTypeArray %inner_array_t %dim +%array_ptr = OpTypePointer UniformConstant %array_t +%2 = OpVariable %array_ptr UniformConstant +%void = OpTypeVoid +%func_t = OpTypeFunction %void +%func = OpFunction %void None %func_t +%1 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv.c_str(), SPV_ENV_WEBGPU_0); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("OpTypeArray Element Type '5[%_runtimearr_4]' is not " + "valid in WebGPU environments.\n %_arr__runtimearr_4_uint_1 = " + "OpTypeArray %_runtimearr_4 %uint_1\n")); +} + +TEST_F(ValidateMemory, VulkanRTAInsideArrayWithRuntimeDescriptorArrayBad) { + std::string spirv = R"( +OpCapability RuntimeDescriptorArrayEXT +OpCapability Shader +OpExtension "SPV_EXT_descriptor_indexing" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +OpDecorate %array_t Block +%uint_t = OpTypeInt 32 0 +%dim = OpConstant %uint_t 1 +%sampler_t = OpTypeSampler +%inner_array_t = OpTypeRuntimeArray %uint_t +%array_t = OpTypeRuntimeArray %inner_array_t +%array_ptr = OpTypePointer StorageBuffer %array_t +%2 = OpVariable %array_ptr StorageBuffer +%void = OpTypeVoid +%func_t = OpTypeFunction %void +%func = OpFunction %void None %func_t +%1 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "OpTypeRuntimeArray Element Type '6[%_runtimearr_uint]' is not " + "valid in Vulkan environments.\n %_runtimearr__runtimearr_uint = " + "OpTypeRuntimeArray %_runtimearr_uint\n")); +} + +TEST_F(ValidateMemory, VulkanRTAInsideArrayInsideStructBad) { + std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +OpDecorate %array_t ArrayStride 4 +OpMemberDecorate %struct_t 0 Offset 0 +OpDecorate %struct_t Block +%uint_t = OpTypeInt 32 0 +%dim = OpConstant %uint_t 1 +%inner_array_t = OpTypeRuntimeArray %uint_t +%array_t = OpTypeArray %inner_array_t %dim +%struct_t = OpTypeStruct %array_t +%struct_ptr = OpTypePointer StorageBuffer %struct_t +%2 = OpVariable %struct_ptr StorageBuffer +%void = OpTypeVoid +%func_t = OpTypeFunction %void +%func = OpFunction %void None %func_t +%1 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "OpTypeArray Element Type '6[%_runtimearr_uint]' is not " + "valid in Vulkan environments.\n %_arr__runtimearr_uint_uint_1 " + "= OpTypeArray %_runtimearr_uint %uint_1\n")); +} + +TEST_F(ValidateMemory, + VulkanRTAInsideArrayInsideStructWithRuntimeDescriptorArrayBad) { + std::string spirv = R"( +OpCapability RuntimeDescriptorArrayEXT +OpCapability Shader +OpExtension "SPV_EXT_descriptor_indexing" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +OpDecorate %array_t ArrayStride 4 +OpMemberDecorate %struct_t 0 Offset 0 +OpDecorate %struct_t Block +%uint_t = OpTypeInt 32 0 +%dim = OpConstant %uint_t 1 +%inner_array_t = OpTypeRuntimeArray %uint_t +%array_t = OpTypeArray %inner_array_t %dim +%struct_t = OpTypeStruct %array_t +%struct_ptr = OpTypePointer StorageBuffer %struct_t +%2 = OpVariable %struct_ptr StorageBuffer +%void = OpTypeVoid +%func_t = OpTypeFunction %void +%func = OpFunction %void None %func_t +%1 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "OpTypeArray Element Type '6[%_runtimearr_uint]' is not " + "valid in Vulkan environments.\n %_arr__runtimearr_uint_uint_1 " + "= OpTypeArray %_runtimearr_uint %uint_1\n")); +} + +TEST_F(ValidateMemory, VulkanRTAStructInsideRTAWithRuntimeDescriptorArrayGood) { + std::string spirv = R"( +OpCapability RuntimeDescriptorArrayEXT +OpCapability Shader +OpExtension "SPV_EXT_descriptor_indexing" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +OpDecorate %inner_array_t ArrayStride 4 +OpDecorate %array_t ArrayStride 4 +OpMemberDecorate %struct_t 0 Offset 0 +OpDecorate %struct_t Block +%uint_t = OpTypeInt 32 0 +%inner_array_t = OpTypeRuntimeArray %uint_t +%struct_t = OpTypeStruct %inner_array_t +%array_t = OpTypeRuntimeArray %struct_t +%array_ptr = OpTypePointer StorageBuffer %array_t +%2 = OpVariable %array_ptr StorageBuffer +%void = OpTypeVoid +%func_t = OpTypeFunction %void +%func = OpFunction %void None %func_t +%1 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1)); +} + +TEST_F(ValidateMemory, VulkanRTAStructInsideArrayGood) { + std::string spirv = R"( +OpCapability RuntimeDescriptorArrayEXT +OpCapability Shader +OpExtension "SPV_EXT_descriptor_indexing" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +OpDecorate %inner_array_t ArrayStride 4 +OpDecorate %array_t ArrayStride 4 +OpMemberDecorate %struct_t 0 Offset 0 +OpDecorate %struct_t Block +%uint_t = OpTypeInt 32 0 +%inner_array_t = OpTypeRuntimeArray %uint_t +%struct_t = OpTypeStruct %inner_array_t +%array_size = OpConstant %uint_t 5 +%array_t = OpTypeArray %struct_t %array_size +%array_ptr = OpTypePointer StorageBuffer %array_t +%2 = OpVariable %array_ptr StorageBuffer +%void = OpTypeVoid +%func_t = OpTypeFunction %void +%func = OpFunction %void None %func_t +%1 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1)); +} + +TEST_F(ValidateMemory, CopyMemoryNoAccessGood) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_ptr_priv = OpTypePointer Private %int +%var1 = OpVariable %int_ptr_priv Private +%var2 = OpVariable %int_ptr_priv Private +%voidfn = OpTypeFunction %void +%func = OpFunction %void None %voidfn +%entry = OpLabel +OpCopyMemory %var1 %var2 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateMemory, CopyMemorySimpleMixedAccessGood) { + // Test one memory access operand using features that don't require the + // Vulkan memory model. + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_ptr_priv = OpTypePointer Private %int +%var1 = OpVariable %int_ptr_priv Private +%var2 = OpVariable %int_ptr_priv Private +%voidfn = OpTypeFunction %void +%func = OpFunction %void None %voidfn +%entry = OpLabel +OpCopyMemory %var1 %var2 Volatile|Aligned|Nontemporal 4 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateMemory, CopyMemorySimpleTwoMixedAccessV13Bad) { + // Two memory access operands is invalid up to SPIR-V 1.3 + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_ptr_priv = OpTypePointer Private %int +%var1 = OpVariable %int_ptr_priv Private +%var2 = OpVariable %int_ptr_priv Private +%voidfn = OpTypeFunction %void +%func = OpFunction %void None %voidfn +%entry = OpLabel +OpCopyMemory %var1 %var2 Volatile Volatile +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("CopyMemory with two memory access operands requires " + "SPIR-V 1.4 or later")); +} + +TEST_F(ValidateMemory, CopyMemorySimpleTwoMixedAccessV14Good) { + // Two memory access operands is valid in SPIR-V 1.4 + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_ptr_priv = OpTypePointer Private %int +%var1 = OpVariable %int_ptr_priv Private +%var2 = OpVariable %int_ptr_priv Private +%voidfn = OpTypeFunction %void +%func = OpFunction %void None %voidfn +%entry = OpLabel +OpCopyMemory %var1 %var2 Volatile Volatile +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateMemory, CopyMemorySizedNoAccessGood) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability Addresses +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_16 = OpConstant %int 16 +%int_ptr_priv = OpTypePointer Private %int +%var1 = OpVariable %int_ptr_priv Private +%var2 = OpVariable %int_ptr_priv Private +%voidfn = OpTypeFunction %void +%func = OpFunction %void None %voidfn +%entry = OpLabel +OpCopyMemorySized %var1 %var2 %int_16 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateMemory, CopyMemorySizedSimpleMixedAccessGood) { + // Test one memory access operand using features that don't require the + // Vulkan memory model. + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability Addresses +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_16 = OpConstant %int 16 +%int_ptr_priv = OpTypePointer Private %int +%var1 = OpVariable %int_ptr_priv Private +%var2 = OpVariable %int_ptr_priv Private +%voidfn = OpTypeFunction %void +%func = OpFunction %void None %voidfn +%entry = OpLabel +OpCopyMemorySized %var1 %var2 %int_16 Volatile|Aligned|Nontemporal 4 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateMemory, CopyMemorySizedSimpleTwoMixedAccessV13Bad) { + // Two memory access operands is invalid up to SPIR-V 1.3 + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability Addresses +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_16 = OpConstant %int 16 +%int_ptr_priv = OpTypePointer Private %int +%var1 = OpVariable %int_ptr_priv Private +%var2 = OpVariable %int_ptr_priv Private +%voidfn = OpTypeFunction %void +%func = OpFunction %void None %voidfn +%entry = OpLabel +OpCopyMemorySized %var1 %var2 %int_16 Volatile Volatile +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("CopyMemorySized with two memory access operands requires " + "SPIR-V 1.4 or later")); +} + +TEST_F(ValidateMemory, CopyMemorySizedSimpleTwoMixedAccessV14Good) { + // Two memory access operands is valid in SPIR-V 1.4 + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability Addresses +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_16 = OpConstant %int 16 +%int_ptr_priv = OpTypePointer Private %int +%var1 = OpVariable %int_ptr_priv Private +%var2 = OpVariable %int_ptr_priv Private +%voidfn = OpTypeFunction %void +%func = OpFunction %void None %voidfn +%entry = OpLabel +OpCopyMemorySized %var1 %var2 %int_16 Volatile Volatile +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +using ValidatePointerComparisons = spvtest::ValidateBase; + +TEST_P(ValidatePointerComparisons, Good) { + const std::string operation = GetParam(); + + std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability VariablePointersStorageBuffer +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%bool = OpTypeBool +%int = OpTypeInt 32 0 +%ptr_int = OpTypePointer StorageBuffer %int +%var = OpVariable %ptr_int StorageBuffer +%func_ty = OpTypeFunction %void +%func = OpFunction %void None %func_ty +%1 = OpLabel +%equal = )" + operation; + + if (operation == "OpPtrDiff") { + spirv += " %int "; + } else { + spirv += " %bool "; + } + + spirv += R"(%var %var +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); +} + +TEST_P(ValidatePointerComparisons, GoodWorkgroup) { + const std::string operation = GetParam(); + + std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability VariablePointers +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%bool = OpTypeBool +%int = OpTypeInt 32 0 +%ptr_int = OpTypePointer Workgroup %int +%var = OpVariable %ptr_int Workgroup +%func_ty = OpTypeFunction %void +%func = OpFunction %void None %func_ty +%1 = OpLabel +%equal = )" + operation; + + if (operation == "OpPtrDiff") { + spirv += " %int "; + } else { + spirv += " %bool "; + } + + spirv += R"(%var %var +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); +} + +TEST_P(ValidatePointerComparisons, BadResultType) { + const std::string operation = GetParam(); + + std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability VariablePointersStorageBuffer +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%bool = OpTypeBool +%int = OpTypeInt 32 0 +%ptr_int = OpTypePointer StorageBuffer %int +%var = OpVariable %ptr_int StorageBuffer +%func_ty = OpTypeFunction %void +%func = OpFunction %void None %func_ty +%1 = OpLabel +%equal = )" + operation; + + if (operation == "OpPtrDiff") { + spirv += " %bool "; + } else { + spirv += " %int "; + } + + spirv += R"(%var %var +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + if (operation == "OpPtrDiff") { + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Result Type must be an integer scalar")); + } else { + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Result Type must be OpTypeBool")); + } +} + +TEST_P(ValidatePointerComparisons, BadCapabilities) { + const std::string operation = GetParam(); + + std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%bool = OpTypeBool +%int = OpTypeInt 32 0 +%ptr_int = OpTypePointer StorageBuffer %int +%var = OpVariable %ptr_int StorageBuffer +%func_ty = OpTypeFunction %void +%func = OpFunction %void None %func_ty +%1 = OpLabel +%equal = )" + operation; + + if (operation == "OpPtrDiff") { + spirv += " %int "; + } else { + spirv += " %bool "; + } + + spirv += R"(%var %var +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + if (operation == "OpPtrDiff") { + // Gets caught by the grammar. + EXPECT_EQ(SPV_ERROR_INVALID_CAPABILITY, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + } else { + EXPECT_EQ(SPV_ERROR_INVALID_ID, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Instruction cannot be used without a variable " + "pointers capability")); + } +} + +TEST_P(ValidatePointerComparisons, BadOperandType) { + const std::string operation = GetParam(); + + std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability VariablePointersStorageBuffer +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%bool = OpTypeBool +%int = OpTypeInt 32 0 +%ptr_int = OpTypePointer StorageBuffer %int +%var = OpVariable %ptr_int StorageBuffer +%func_ty = OpTypeFunction %void +%func = OpFunction %void None %func_ty +%1 = OpLabel +%ld = OpLoad %int %var +%equal = )" + operation; + + if (operation == "OpPtrDiff") { + spirv += " %int "; + } else { + spirv += " %bool "; + } + + spirv += R"(%ld %ld +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Operand type must be a pointer")); +} + +TEST_P(ValidatePointerComparisons, BadStorageClassWorkgroup) { + const std::string operation = GetParam(); + + std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability VariablePointersStorageBuffer +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%bool = OpTypeBool +%int = OpTypeInt 32 0 +%ptr_int = OpTypePointer Workgroup %int +%var = OpVariable %ptr_int Workgroup +%func_ty = OpTypeFunction %void +%func = OpFunction %void None %func_ty +%1 = OpLabel +%equal = )" + operation; + + if (operation == "OpPtrDiff") { + spirv += " %int "; + } else { + spirv += " %bool "; + } + + spirv += R"(%var %var +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Workgroup storage class pointer requires " + "VariablePointers capability to be specified")); +} + +TEST_P(ValidatePointerComparisons, BadStorageClass) { + const std::string operation = GetParam(); + + std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability VariablePointersStorageBuffer +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%bool = OpTypeBool +%int = OpTypeInt 32 0 +%ptr_int = OpTypePointer Private %int +%var = OpVariable %ptr_int Private +%func_ty = OpTypeFunction %void +%func = OpFunction %void None %func_ty +%1 = OpLabel +%equal = )" + operation; + + if (operation == "OpPtrDiff") { + spirv += " %int "; + } else { + spirv += " %bool "; + } + + spirv += R"(%var %var +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Invalid pointer storage class")); +} + +TEST_P(ValidatePointerComparisons, BadDiffOperandTypes) { + const std::string operation = GetParam(); + + std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability VariablePointersStorageBuffer +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%bool = OpTypeBool +%int = OpTypeInt 32 0 +%ptr_int = OpTypePointer Private %int +%var = OpVariable %ptr_int Private +%func_ty = OpTypeFunction %void +%func = OpFunction %void None %func_ty +%1 = OpLabel +%ld = OpLoad %int %var +%equal = )" + operation; + + if (operation == "OpPtrDiff") { + spirv += " %int "; + } else { + spirv += " %bool "; + } + + spirv += R"(%var %ld +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("The types of Operand 1 and Operand 2 must match")); +} + +INSTANTIATE_TEST_SUITE_P(PointerComparisons, ValidatePointerComparisons, + Values("OpPtrEqual", "OpPtrNotEqual", "OpPtrDiff")); + +TEST_F(ValidateMemory, VariableInitializerWrongType) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability VariablePointersStorageBuffer +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%float = OpTypeFloat 32 +%ptr_wg_int = OpTypePointer Workgroup %int +%ptr_wg_float = OpTypePointer Workgroup %int +%wg_var = OpVariable %ptr_wg_int Workgroup +%ptr_private_wg_float = OpTypePointer Private %ptr_wg_float +%priv_var = OpVariable %ptr_private_wg_float Private %wg_var +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Initializer type must match the type pointed to by " + "the Result Type")); +} + +TEST_F(ValidateMemory, StoreToUniformBlock) { + const std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %struct Block +OpMemberDecorate %struct 0 Offset 0 +OpDecorate %var DescriptorSet 0 +OpDecorate %var Binding 0 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%int4 = OpTypeVector %int 4 +%struct = OpTypeStruct %int4 +%ptr_uniform_struct = OpTypePointer Uniform %struct +%ptr_uniform_int4 = OpTypePointer Uniform %int4 +%ptr_uniform_int = OpTypePointer Uniform %int +%var = OpVariable %ptr_uniform_struct Uniform +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%gep1 = OpAccessChain %ptr_uniform_int4 %var %int_0 +%gep2 = OpAccessChain %ptr_uniform_int %gep1 %int_0 +OpStore %gep2 %int_0 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateMemory, StoreToUniformBlockVulkan) { + const std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %struct Block +OpMemberDecorate %struct 0 Offset 0 +OpDecorate %var DescriptorSet 0 +OpDecorate %var Binding 0 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%int4 = OpTypeVector %int 4 +%struct = OpTypeStruct %int4 +%ptr_uniform_struct = OpTypePointer Uniform %struct +%ptr_uniform_int4 = OpTypePointer Uniform %int4 +%ptr_uniform_int = OpTypePointer Uniform %int +%var = OpVariable %ptr_uniform_struct Uniform +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%gep1 = OpAccessChain %ptr_uniform_int4 %var %int_0 +%gep2 = OpAccessChain %ptr_uniform_int %gep1 %int_0 +OpStore %gep2 %int_0 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("In the Vulkan environment, cannot store to Uniform Blocks")); +} + +// This test requires that the struct is not id 2. +TEST_F(ValidateMemory, StoreToUniformBlockVulkan2) { + const std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" %gid_var +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %3 Block +OpMemberDecorate %3 0 Offset 0 +OpDecorate %var DescriptorSet 0 +OpDecorate %var Binding 0 +OpDecorate %gid_var BuiltIn GlobalInvocationId +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%int3 = OpTypeVector %int 3 +%int4 = OpTypeVector %int 4 +%3 = OpTypeStruct %int4 +%ptr_uniform_struct = OpTypePointer Uniform %3 +%ptr_uniform_int4 = OpTypePointer Uniform %int4 +%ptr_uniform_int = OpTypePointer Uniform %int +%var = OpVariable %ptr_uniform_struct Uniform +%ptr_input_int3 = OpTypePointer Input %int3 +%gid_var = OpVariable %ptr_input_int3 Input +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%gep1 = OpAccessChain %ptr_uniform_int4 %var %int_0 +%gep2 = OpAccessChain %ptr_uniform_int %gep1 %int_0 +OpStore %gep2 %int_0 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("In the Vulkan environment, cannot store to Uniform Blocks")); +} + +TEST_F(ValidateMemory, StoreToUniformBufferBlockVulkan) { + const std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %struct BufferBlock +OpMemberDecorate %struct 0 Offset 0 +OpDecorate %var DescriptorSet 0 +OpDecorate %var Binding 0 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%int4 = OpTypeVector %int 4 +%struct = OpTypeStruct %int4 +%ptr_uniform_struct = OpTypePointer Uniform %struct +%ptr_uniform_int4 = OpTypePointer Uniform %int4 +%ptr_uniform_int = OpTypePointer Uniform %int +%var = OpVariable %ptr_uniform_struct Uniform +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%gep1 = OpAccessChain %ptr_uniform_int4 %var %int_0 +%gep2 = OpAccessChain %ptr_uniform_int %gep1 %int_0 +OpStore %gep2 %int_0 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1)); +} + +TEST_F(ValidateMemory, StoreToUniformBlockVulkanArray) { + const std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %struct Block +OpMemberDecorate %struct 0 Offset 0 +OpDecorate %var DescriptorSet 0 +OpDecorate %var Binding 0 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%int_1 = OpConstant %int 1 +%int4 = OpTypeVector %int 4 +%struct = OpTypeStruct %int4 +%array_struct = OpTypeArray %struct %int_1 +%ptr_uniform_array = OpTypePointer Uniform %array_struct +%ptr_uniform_struct = OpTypePointer Uniform %struct +%ptr_uniform_int4 = OpTypePointer Uniform %int4 +%ptr_uniform_int = OpTypePointer Uniform %int +%var = OpVariable %ptr_uniform_array Uniform +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%gep1 = OpAccessChain %ptr_uniform_int %var %int_0 %int_0 %int_0 +%gep2 = OpCopyObject %ptr_uniform_int %gep1 +OpStore %gep2 %int_0 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("In the Vulkan environment, cannot store to Uniform Blocks")); +} + +// This test requires that the struct is not id 2. +TEST_F(ValidateMemory, StoreToUniformBlockVulkanArray2) { + const std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" %gid_var +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %struct Block +OpMemberDecorate %struct 0 Offset 0 +OpDecorate %var DescriptorSet 0 +OpDecorate %var Binding 0 +OpDecorate %gid_var BuiltIn GlobalInvocationId +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%int_1 = OpConstant %int 1 +%int3 = OpTypeVector %int 3 +%int4 = OpTypeVector %int 4 +%struct = OpTypeStruct %int4 +%array_struct = OpTypeArray %struct %int_1 +%ptr_uniform_array = OpTypePointer Uniform %array_struct +%ptr_uniform_struct = OpTypePointer Uniform %struct +%ptr_uniform_int4 = OpTypePointer Uniform %int4 +%ptr_uniform_int = OpTypePointer Uniform %int +%var = OpVariable %ptr_uniform_array Uniform +%ptr_input_int3 = OpTypePointer Input %int3 +%gid_var = OpVariable %ptr_input_int3 Input +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%gep1 = OpAccessChain %ptr_uniform_int %var %int_0 %int_0 %int_0 +%gep2 = OpCopyObject %ptr_uniform_int %gep1 +OpStore %gep2 %int_0 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("In the Vulkan environment, cannot store to Uniform Blocks")); +} + +TEST_F(ValidateMemory, StoreToUniformBlockVulkanRuntimeArray) { + const std::string spirv = R"( +OpCapability Shader +OpCapability RuntimeDescriptorArrayEXT +OpExtension "SPV_EXT_descriptor_indexing" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %struct Block +OpMemberDecorate %struct 0 Offset 0 +OpDecorate %var DescriptorSet 0 +OpDecorate %var Binding 0 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%int4 = OpTypeVector %int 4 +%struct = OpTypeStruct %int4 +%array_struct = OpTypeRuntimeArray %struct +%ptr_uniform_array = OpTypePointer Uniform %array_struct +%ptr_uniform_struct = OpTypePointer Uniform %struct +%ptr_uniform_int4 = OpTypePointer Uniform %int4 +%ptr_uniform_int = OpTypePointer Uniform %int +%var = OpVariable %ptr_uniform_array Uniform +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%gep1 = OpAccessChain %ptr_uniform_int4 %var %int_0 %int_0 +%gep2 = OpInBoundsAccessChain %ptr_uniform_int %gep1 %int_0 +OpStore %gep2 %int_0 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("In the Vulkan environment, cannot store to Uniform Blocks")); +} + +using ValidateSizedVariable = + spvtest::ValidateBase>; + +CodeGenerator GetSizedVariableCodeGenerator(bool is_8bit) { + CodeGenerator generator; + generator.capabilities_ = "OpCapability Shader\nOpCapability Linkage\n"; + generator.extensions_ = + "OpExtension \"SPV_KHR_16bit_storage\"\nOpExtension " + "\"SPV_KHR_8bit_storage\"\n"; + generator.memory_model_ = "OpMemoryModel Logical GLSL450\n"; + if (is_8bit) { + generator.before_types_ = R"(OpDecorate %char_buffer_block BufferBlock +OpMemberDecorate %char_buffer_block 0 Offset 0 +)"; + generator.types_ = R"(%void = OpTypeVoid +%char = OpTypeInt 8 0 +%char4 = OpTypeVector %char 4 +%char_buffer_block = OpTypeStruct %char +)"; + } else { + generator.before_types_ = R"(OpDecorate %half_buffer_block BufferBlock +OpDecorate %short_buffer_block BufferBlock +OpMemberDecorate %half_buffer_block 0 Offset 0 +OpMemberDecorate %short_buffer_block 0 Offset 0 +)"; + generator.types_ = R"(%void = OpTypeVoid +%short = OpTypeInt 16 0 +%half = OpTypeFloat 16 +%short4 = OpTypeVector %short 4 +%half4 = OpTypeVector %half 4 +%mat4x4 = OpTypeMatrix %half4 4 +%short_buffer_block = OpTypeStruct %short +%half_buffer_block = OpTypeStruct %half +)"; + } + generator.after_types_ = R"(%void_fn = OpTypeFunction %void +%func = OpFunction %void None %void_fn +%entry = OpLabel +)"; + generator.add_at_the_end_ = "OpReturn\nOpFunctionEnd\n"; + return generator; +} + +TEST_P(ValidateSizedVariable, Capability) { + const std::string storage_class = std::get<0>(GetParam()); + const std::string capability = std::get<1>(GetParam()); + const std::string var_type = std::get<2>(GetParam()); + + bool type_8bit = false; + if (var_type == "%char" || var_type == "%char4" || + var_type == "%char_buffer_block") { + type_8bit = true; + } + + auto generator = GetSizedVariableCodeGenerator(type_8bit); + generator.types_ += "%ptr_type = OpTypePointer " + storage_class + " " + + var_type + "\n%var = OpVariable %ptr_type " + + storage_class + "\n"; + generator.capabilities_ += "OpCapability " + capability + "\n"; + + bool capability_ok = false; + bool storage_class_ok = false; + if (storage_class == "Input" || storage_class == "Output") { + if (!type_8bit) { + capability_ok = capability == "StorageInputOutput16"; + storage_class_ok = true; + } + } else if (storage_class == "StorageBuffer") { + if (type_8bit) { + capability_ok = capability == "StorageBuffer8BitAccess" || + capability == "UniformAndStorageBuffer8BitAccess"; + } else { + capability_ok = capability == "StorageBuffer16BitAccess" || + capability == "UniformAndStorageBuffer16BitAccess"; + } + storage_class_ok = true; + } else if (storage_class == "PushConstant") { + if (type_8bit) { + capability_ok = capability == "StoragePushConstant8"; + } else { + capability_ok = capability == "StoragePushConstant16"; + } + storage_class_ok = true; + } else if (storage_class == "Uniform") { + bool buffer_block = var_type.find("buffer_block") != std::string::npos; + if (type_8bit) { + capability_ok = capability == "UniformAndStorageBuffer8BitAccess" || + (capability == "StorageBuffer8BitAccess" && buffer_block); + } else { + capability_ok = + capability == "UniformAndStorageBuffer16BitAccess" || + (capability == "StorageBuffer16BitAccess" && buffer_block); + } + storage_class_ok = true; + } + + CompileSuccessfully(generator.Build(), SPV_ENV_UNIVERSAL_1_3); + spv_result_t result = ValidateInstructions(SPV_ENV_UNIVERSAL_1_3); + if (capability_ok) { + EXPECT_EQ(SPV_SUCCESS, result); + } else { + EXPECT_EQ(SPV_ERROR_INVALID_ID, result); + if (storage_class_ok) { + std::string message = std::string("Allocating a variable containing a ") + + (type_8bit ? "8" : "16") + "-bit element in " + + storage_class + + " storage class requires an additional capability"; + EXPECT_THAT(getDiagnosticString(), HasSubstr(message)); + } else { + std::string message = + std::string("Cannot allocate a variable containing a ") + + (type_8bit ? "8" : "16") + "-bit type in " + storage_class + + " storage class"; + EXPECT_THAT(getDiagnosticString(), HasSubstr(message)); + } + } +} + +INSTANTIATE_TEST_SUITE_P( + Storage8, ValidateSizedVariable, + Combine(Values("UniformConstant", "Input", "Output", "Workgroup", + "CrossWorkgroup", "Private", "StorageBuffer", "Uniform"), + Values("StorageBuffer8BitAccess", + "UniformAndStorageBuffer8BitAccess", "StoragePushConstant8"), + Values("%char", "%char4", "%char_buffer_block"))); + +INSTANTIATE_TEST_SUITE_P( + Storage16, ValidateSizedVariable, + Combine(Values("UniformConstant", "Input", "Output", "Workgroup", + "CrossWorkgroup", "Private", "StorageBuffer", "Uniform"), + Values("StorageBuffer16BitAccess", + "UniformAndStorageBuffer16BitAccess", + "StoragePushConstant16", "StorageInputOutput16"), + Values("%short", "%half", "%short4", "%half4", "%mat4x4", + "%short_buffer_block", "%half_buffer_block"))); + +using ValidateSizedLoadStore = + spvtest::ValidateBase>; + +CodeGenerator GetSizedLoadStoreCodeGenerator(const std::string& base_type, + uint32_t width) { + CodeGenerator generator; + generator.capabilities_ = "OpCapability Shader\nOpCapability Linkage\n"; + if (width == 8) { + generator.capabilities_ += + "OpCapability UniformAndStorageBuffer8BitAccess\n"; + generator.extensions_ = "OpExtension \"SPV_KHR_8bit_storage\"\n"; + } else { + generator.capabilities_ += + "OpCapability UniformAndStorageBuffer16BitAccess\n"; + generator.extensions_ = "OpExtension \"SPV_KHR_16bit_storage\"\n"; + } + generator.memory_model_ = "OpMemoryModel Logical GLSL450\n"; + generator.before_types_ = R"(OpDecorate %block Block +OpMemberDecorate %block 0 Offset 0 +OpMemberDecorate %struct 0 Offset 0 +)"; + generator.types_ = R"(%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%int_1 = OpConstant %int 1 +%int_2 = OpConstant %int 2 +%int_3 = OpConstant %int 3 +)"; + + if (width == 8) { + generator.types_ += R"(%scalar = OpTypeInt 8 0 +%vector = OpTypeVector %scalar 4 +%struct = OpTypeStruct %vector +)"; + } else if (base_type == "int") { + generator.types_ += R"(%scalar = OpTypeInt 16 0 +%vector = OpTypeVector %scalar 4 +%struct = OpTypeStruct %vector +)"; + } else { + generator.types_ += R"(%scalar = OpTypeFloat 16 +%vector = OpTypeVector %scalar 4 +%matrix = OpTypeMatrix %vector 4 +%struct = OpTypeStruct %matrix +%ptr_ssbo_matrix = OpTypePointer StorageBuffer %matrix +)"; + generator.before_types_ += R"(OpMemberDecorate %struct 0 RowMajor +OpMemberDecorate %struct 0 MatrixStride 16 +)"; + } + generator.types_ += R"(%block = OpTypeStruct %struct +%ptr_ssbo_block = OpTypePointer StorageBuffer %block +%ptr_ssbo_struct = OpTypePointer StorageBuffer %struct +%ptr_ssbo_vector = OpTypePointer StorageBuffer %vector +%ptr_ssbo_scalar = OpTypePointer StorageBuffer %scalar +%ld_var = OpVariable %ptr_ssbo_block StorageBuffer +%st_var = OpVariable %ptr_ssbo_block StorageBuffer +)"; + + generator.after_types_ = R"(%void_fn = OpTypeFunction %void +%func = OpFunction %void None %void_fn +%entry = OpLabel +)"; + generator.add_at_the_end_ = "OpReturn\nOpFunctionEnd\n"; + return generator; +} + +TEST_P(ValidateSizedLoadStore, Load) { + std::string base_type = std::get<0>(GetParam()); + uint32_t width = std::get<1>(GetParam()); + std::string mem_type = std::get<2>(GetParam()); + + CodeGenerator generator = GetSizedLoadStoreCodeGenerator(base_type, width); + generator.after_types_ += + "%ld_gep = OpAccessChain %ptr_ssbo_" + mem_type + " %ld_var %int_0"; + if (mem_type != "struct") { + generator.after_types_ += " %int_0"; + if (mem_type != "matrix" && base_type == "float") { + generator.after_types_ += " %int_0"; + } + if (mem_type == "scalar") { + generator.after_types_ += " %int_0"; + } + } + generator.after_types_ += "\n"; + generator.after_types_ += "%ld = OpLoad %" + mem_type + " %ld_gep\n"; + + CompileSuccessfully(generator.Build(), SPV_ENV_UNIVERSAL_1_3); + if (mem_type == "struct") { + EXPECT_EQ(SPV_ERROR_INVALID_ID, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "8- or 16-bit loads must be a scalar, vector or matrix type")); + } else { + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + } +} + +TEST_P(ValidateSizedLoadStore, Store) { + std::string base_type = std::get<0>(GetParam()); + uint32_t width = std::get<1>(GetParam()); + std::string mem_type = std::get<2>(GetParam()); + + CodeGenerator generator = GetSizedLoadStoreCodeGenerator(base_type, width); + generator.after_types_ += + "%ld_gep = OpAccessChain %ptr_ssbo_" + mem_type + " %ld_var %int_0"; + if (mem_type != "struct") { + generator.after_types_ += " %int_0"; + if (mem_type != "matrix" && base_type == "float") { + generator.after_types_ += " %int_0"; + } + if (mem_type == "scalar") { + generator.after_types_ += " %int_0"; + } + } + generator.after_types_ += "\n"; + generator.after_types_ += "%ld = OpLoad %" + mem_type + " %ld_gep\n"; + generator.after_types_ += + "%st_gep = OpAccessChain %ptr_ssbo_" + mem_type + " %st_var %int_0"; + if (mem_type != "struct") { + generator.after_types_ += " %int_0"; + if (mem_type != "matrix" && base_type == "float") { + generator.after_types_ += " %int_0"; + } + if (mem_type == "scalar") { + generator.after_types_ += " %int_0"; + } + } + generator.after_types_ += "\n"; + generator.after_types_ += "OpStore %st_gep %ld\n"; + + CompileSuccessfully(generator.Build(), SPV_ENV_UNIVERSAL_1_3); + if (mem_type == "struct") { + EXPECT_EQ(SPV_ERROR_INVALID_ID, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + // Can only catch the load. + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "8- or 16-bit loads must be a scalar, vector or matrix type")); + } else { + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + } +} + +INSTANTIATE_TEST_SUITE_P(LoadStoreInt8, ValidateSizedLoadStore, + Combine(Values("int"), Values(8u), + Values("scalar", "vector", "struct"))); +INSTANTIATE_TEST_SUITE_P(LoadStoreInt16, ValidateSizedLoadStore, + Combine(Values("int"), Values(16u), + Values("scalar", "vector", "struct"))); +INSTANTIATE_TEST_SUITE_P(LoadStoreFloat16, ValidateSizedLoadStore, + Combine(Values("float"), Values(16u), + Values("scalar", "vector", "matrix", + "struct"))); + +TEST_F(ValidateMemory, SmallStorageCopyMemoryChar) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability UniformAndStorageBuffer8BitAccess +OpExtension "SPV_KHR_8bit_storage" +OpMemoryModel Logical GLSL450 +OpDecorate %block Block +OpMemberDecorate %block 0 Offset 0 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%char = OpTypeInt 8 0 +%block = OpTypeStruct %char +%ptr_ssbo_block = OpTypePointer StorageBuffer %block +%in = OpVariable %ptr_ssbo_block StorageBuffer +%out = OpVariable %ptr_ssbo_block StorageBuffer +%void_fn = OpTypeFunction %void +%func = OpFunction %void None %void_fn +%entry = OpLabel +OpCopyMemory %out %in +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Cannot copy memory of objects containing 8- or 16-bit types")); +} + +TEST_F(ValidateMemory, SmallStorageCopyMemoryShort) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability UniformAndStorageBuffer16BitAccess +OpExtension "SPV_KHR_16bit_storage" +OpMemoryModel Logical GLSL450 +OpDecorate %block Block +OpMemberDecorate %block 0 Offset 0 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%short = OpTypeInt 16 0 +%block = OpTypeStruct %short +%ptr_ssbo_block = OpTypePointer StorageBuffer %block +%in = OpVariable %ptr_ssbo_block StorageBuffer +%out = OpVariable %ptr_ssbo_block StorageBuffer +%void_fn = OpTypeFunction %void +%func = OpFunction %void None %void_fn +%entry = OpLabel +OpCopyMemory %out %in +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Cannot copy memory of objects containing 8- or 16-bit types")); +} + +TEST_F(ValidateMemory, SmallStorageCopyMemoryHalf) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability UniformAndStorageBuffer16BitAccess +OpExtension "SPV_KHR_16bit_storage" +OpMemoryModel Logical GLSL450 +OpDecorate %block Block +OpMemberDecorate %block 0 Offset 0 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%half = OpTypeFloat 16 +%block = OpTypeStruct %half +%ptr_ssbo_block = OpTypePointer StorageBuffer %block +%in = OpVariable %ptr_ssbo_block StorageBuffer +%out = OpVariable %ptr_ssbo_block StorageBuffer +%void_fn = OpTypeFunction %void +%func = OpFunction %void None %void_fn +%entry = OpLabel +OpCopyMemory %out %in +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Cannot copy memory of objects containing 8- or 16-bit types")); +} + +TEST_F(ValidateMemory, SmallStorageVariableArrayBufferBlockShort) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability StorageBuffer16BitAccess +OpExtension "SPV_KHR_16bit_storage" +OpMemoryModel Logical GLSL450 +OpDecorate %block BufferBlock +OpMemberDecorate %block 0 Offset 0 +%void = OpTypeVoid +%short = OpTypeInt 16 0 +%int = OpTypeInt 32 0 +%int_4 = OpConstant %int 4 +%block = OpTypeStruct %short +%block_array = OpTypeArray %block %int_4 +%ptr_block_array = OpTypePointer Uniform %block_array +%var = OpVariable %ptr_block_array Uniform +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); +} + +TEST_F(ValidateMemory, SmallStorageVariableArrayBufferBlockChar) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability StorageBuffer8BitAccess +OpExtension "SPV_KHR_8bit_storage" +OpMemoryModel Logical GLSL450 +OpDecorate %block BufferBlock +OpMemberDecorate %block 0 Offset 0 +%void = OpTypeVoid +%char = OpTypeInt 8 0 +%int = OpTypeInt 32 0 +%int_4 = OpConstant %int 4 +%block = OpTypeStruct %char +%block_array = OpTypeArray %block %int_4 +%ptr_block_array = OpTypePointer Uniform %block_array +%var = OpVariable %ptr_block_array Uniform +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); +} + +TEST_F(ValidateMemory, SmallStorageVariableArrayBufferBlockHalf) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability StorageBuffer16BitAccess +OpExtension "SPV_KHR_16bit_storage" +OpMemoryModel Logical GLSL450 +OpDecorate %block BufferBlock +OpMemberDecorate %block 0 Offset 0 +%void = OpTypeVoid +%half = OpTypeFloat 16 +%int = OpTypeInt 32 0 +%int_4 = OpConstant %int 4 +%block = OpTypeStruct %half +%block_array = OpTypeArray %block %int_4 +%ptr_block_array = OpTypePointer Uniform %block_array +%var = OpVariable %ptr_block_array Uniform +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); +} + +TEST_F(ValidateMemory, VulkanStorageBufferNotAStruct) { + const std::string spirv = R"( +OpCapability Shader +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +%void = OpTypeVoid +%uint = OpTypeInt 32 0 +%ptr_ssbo = OpTypePointer StorageBuffer %uint +%var = OpVariable %ptr_ssbo StorageBuffer +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("From Vulkan spec, section 14.5.2:\nVariables identified with " + "the StorageBuffer storage class are used to access " + "transparent buffer backed resources. Such variables must be " + "typed as OpTypeStruct, or an array of this type")); +} + +TEST_F(ValidateMemory, VulkanStorageBufferRuntimeArrayNotAStruct) { + const std::string spirv = R"( +OpCapability Shader +OpCapability RuntimeDescriptorArrayEXT +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpExtension "SPV_EXT_descriptor_indexing" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +%void = OpTypeVoid +%uint = OpTypeInt 32 0 +%array = OpTypeRuntimeArray %uint +%ptr_ssbo = OpTypePointer StorageBuffer %array +%var = OpVariable %ptr_ssbo StorageBuffer +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("From Vulkan spec, section 14.5.2:\nVariables identified with " + "the StorageBuffer storage class are used to access " + "transparent buffer backed resources. Such variables must be " + "typed as OpTypeStruct, or an array of this type")); +} + +TEST_F(ValidateMemory, VulkanStorageBufferArrayNotAStruct) { + const std::string spirv = R"( +OpCapability Shader +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +%void = OpTypeVoid +%uint = OpTypeInt 32 0 +%uint_4 = OpConstant %uint 4 +%array = OpTypeArray %uint %uint_4 +%ptr_ssbo = OpTypePointer StorageBuffer %array +%var = OpVariable %ptr_ssbo StorageBuffer +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("From Vulkan spec, section 14.5.2:\nVariables identified with " + "the StorageBuffer storage class are used to access " + "transparent buffer backed resources. Such variables must be " + "typed as OpTypeStruct, or an array of this type")); +} + +TEST_F(ValidateMemory, PhysicalStorageBufferPtrEqual) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Int64 +OpCapability PhysicalStorageBufferAddresses +OpMemoryModel PhysicalStorageBuffer64 GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +%void = OpTypeVoid +%bool = OpTypeBool +%long = OpTypeInt 64 0 +%long_0 = OpConstant %long 0 +%ptr_pssbo_long = OpTypePointer PhysicalStorageBuffer %long +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%conv = OpConvertUToPtr %ptr_pssbo_long %long_0 +%eq = OpPtrEqual %bool %conv %conv +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_5); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_5)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "Cannot use a pointer in the PhysicalStorageBuffer storage class")); +} + +TEST_F(ValidateMemory, PhysicalStorageBufferPtrNotEqual) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Int64 +OpCapability PhysicalStorageBufferAddresses +OpMemoryModel PhysicalStorageBuffer64 GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +%void = OpTypeVoid +%bool = OpTypeBool +%long = OpTypeInt 64 0 +%long_0 = OpConstant %long 0 +%ptr_pssbo_long = OpTypePointer PhysicalStorageBuffer %long +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%conv = OpConvertUToPtr %ptr_pssbo_long %long_0 +%neq = OpPtrNotEqual %bool %conv %conv +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_5); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_5)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "Cannot use a pointer in the PhysicalStorageBuffer storage class")); +} + +TEST_F(ValidateMemory, PhysicalStorageBufferPtrDiff) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Int64 +OpCapability PhysicalStorageBufferAddresses +OpCapability VariablePointers +OpMemoryModel PhysicalStorageBuffer64 GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +%void = OpTypeVoid +%long = OpTypeInt 64 0 +%long_0 = OpConstant %long 0 +%ptr_pssbo_long = OpTypePointer PhysicalStorageBuffer %long +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%conv = OpConvertUToPtr %ptr_pssbo_long %long_0 +%diff = OpPtrDiff %long %conv %conv +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_5); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_5)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "Cannot use a pointer in the PhysicalStorageBuffer storage class")); +} + +} // namespace +} // namespace val +} // namespace spvtools diff --git a/third_party/spirv-tools/test/val/val_misc_test.cpp b/third_party/spirv-tools/test/val/val_misc_test.cpp new file mode 100644 index 0000000000..93954844e9 --- /dev/null +++ b/third_party/spirv-tools/test/val/val_misc_test.cpp @@ -0,0 +1,231 @@ +// Copyright (c) 2019 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. + +// Validation tests for misc instructions + +#include +#include + +#include "gmock/gmock.h" +#include "test/unit_spirv.h" +#include "test/val/val_fixtures.h" + +namespace spvtools { +namespace val { +namespace { + +using ::testing::Eq; +using ::testing::HasSubstr; + +using ValidateMisc = spvtest::ValidateBase; + +TEST_F(ValidateMisc, UndefRestrictedShort) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability StorageBuffer16BitAccess +OpExtension "SPV_KHR_16bit_storage" +OpMemoryModel Logical GLSL450 +%short = OpTypeInt 16 0 +%undef = OpUndef %short +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Cannot create undefined values with 8- or 16-bit types")); +} + +TEST_F(ValidateMisc, UndefRestrictedChar) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability StorageBuffer8BitAccess +OpExtension "SPV_KHR_8bit_storage" +OpMemoryModel Logical GLSL450 +%char = OpTypeInt 8 0 +%undef = OpUndef %char +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Cannot create undefined values with 8- or 16-bit types")); +} + +TEST_F(ValidateMisc, UndefRestrictedHalf) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability StorageBuffer16BitAccess +OpExtension "SPV_KHR_16bit_storage" +OpMemoryModel Logical GLSL450 +%half = OpTypeFloat 16 +%undef = OpUndef %half +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Cannot create undefined values with 8- or 16-bit types")); +} + +const std::string ShaderClockSpriv = R"( +OpCapability Shader +OpCapability Int64 +OpCapability ShaderClockKHR +OpExtension "SPV_KHR_shader_clock" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 450 +OpSourceExtension "GL_ARB_gpu_shader_int64" +OpSourceExtension "GL_ARB_shader_clock" +OpSourceExtension "GL_EXT_shader_realtime_clock" +OpName %main "main" +OpName %time1 "time1" +%void = OpTypeVoid +)"; + +TEST_F(ValidateMisc, ShaderClockInt64) { + const std::string spirv = ShaderClockSpriv + R"( +%3 = OpTypeFunction %void +%uint = OpTypeInt 32 0 +%_ptr_Function_uint = OpTypePointer Function %uint +%uint_3 = OpConstant %uint 3 +%uint_1 = OpConstant %uint 1 +%main = OpFunction %void None %3 +%5 = OpLabel +%time1 = OpVariable %_ptr_Function_uint Function +%11 = OpReadClockKHR %uint %uint_3 +OpStore %time1 %11 +OpReturn +OpFunctionEnd)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), HasSubstr("or 64bit unsigned integer")); +} + +TEST_F(ValidateMisc, ShaderClockVec2) { + const std::string spirv = ShaderClockSpriv + R"( +%3 = OpTypeFunction %void +%ulong = OpTypeInt 64 0 +%_ptr_Function_ulong = OpTypePointer Function %ulong +%uint = OpTypeInt 32 0 +%uint_3 = OpConstant %uint 3 +%v2uint = OpTypeVector %ulong 2 +%_ptr_Function_v2uint = OpTypePointer Function %v2uint +%main = OpFunction %void None %3 +%5 = OpLabel +%time1 = OpVariable %_ptr_Function_v2uint Function +%15 = OpReadClockKHR %v2uint %uint_3 +OpStore %time1 %15 +OpReturn +OpFunctionEnd)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), HasSubstr("vector of two components")); +} + +TEST_F(ValidateMisc, ShaderClockInvalidScopeValue) { + const std::string spirv = ShaderClockSpriv + R"( +%3 = OpTypeFunction %void +%ulong = OpTypeInt 64 0 +%uint = OpTypeInt 32 0 +%_ptr_Function_ulong = OpTypePointer Function %ulong +%uint_10 = OpConstant %uint 10 +%uint_1 = OpConstant %uint 1 +%main = OpFunction %void None %3 +%5 = OpLabel +%time1 = OpVariable %_ptr_Function_ulong Function +%11 = OpReadClockKHR %ulong %uint_10 +OpStore %time1 %11 +OpReturn +OpFunctionEnd)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), HasSubstr("Invalid scope value")); +} + +TEST_F(ValidateMisc, ShaderClockSubgroupScope) { + const std::string spirv = ShaderClockSpriv + R"( +%3 = OpTypeFunction %void +%ulong = OpTypeInt 64 0 +%uint = OpTypeInt 32 0 +%_ptr_Function_ulong = OpTypePointer Function %ulong +%subgroup = OpConstant %uint 3 +%uint_1 = OpConstant %uint 1 +%main = OpFunction %void None %3 +%5 = OpLabel +%time1 = OpVariable %_ptr_Function_ulong Function +%11 = OpReadClockKHR %ulong %subgroup +OpStore %time1 %11 +OpReturn +OpFunctionEnd)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateMisc, ShaderClockDeviceScope) { + const std::string spirv = ShaderClockSpriv + R"( +%3 = OpTypeFunction %void +%ulong = OpTypeInt 64 0 +%uint = OpTypeInt 32 0 +%_ptr_Function_ulong = OpTypePointer Function %ulong +%device = OpConstant %uint 1 +%uint_1 = OpConstant %uint 1 +%main = OpFunction %void None %3 +%5 = OpLabel +%time1 = OpVariable %_ptr_Function_ulong Function +%11 = OpReadClockKHR %ulong %device +OpStore %time1 %11 +OpReturn +OpFunctionEnd)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateMisc, ShaderClockWorkgroupScope) { + const std::string spirv = ShaderClockSpriv + R"( +%3 = OpTypeFunction %void +%ulong = OpTypeInt 64 0 +%uint = OpTypeInt 32 0 +%_ptr_Function_ulong = OpTypePointer Function %ulong +%workgroup = OpConstant %uint 2 +%uint_1 = OpConstant %uint 1 +%main = OpFunction %void None %3 +%5 = OpLabel +%time1 = OpVariable %_ptr_Function_ulong Function +%11 = OpReadClockKHR %ulong %workgroup +OpStore %time1 %11 +OpReturn +OpFunctionEnd)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Scope must be Subgroup or Device")); +} +} // namespace +} // namespace val +} // namespace spvtools diff --git a/third_party/spirv-tools/test/val/val_modes_test.cpp b/third_party/spirv-tools/test/val/val_modes_test.cpp new file mode 100644 index 0000000000..688f433997 --- /dev/null +++ b/third_party/spirv-tools/test/val/val_modes_test.cpp @@ -0,0 +1,1183 @@ +// Copyright (c) 2018 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 +#include +#include + +#include "gmock/gmock.h" +#include "source/spirv_target_env.h" +#include "test/test_fixture.h" +#include "test/unit_spirv.h" +#include "test/val/val_fixtures.h" + +namespace spvtools { +namespace val { +namespace { + +using ::testing::Combine; +using ::testing::HasSubstr; +using ::testing::Values; +using ::testing::ValuesIn; + +using ValidateMode = spvtest::ValidateBase; + +const std::string kVoidFunction = R"(%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + +TEST_F(ValidateMode, GLComputeNoMode) { + const std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +)" + kVoidFunction; + + CompileSuccessfully(spirv); + EXPECT_THAT(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateMode, GLComputeNoModeVulkan) { + const std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +)" + kVoidFunction; + + spv_target_env env = SPV_ENV_VULKAN_1_0; + CompileSuccessfully(spirv, env); + EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions(env)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("In the Vulkan environment, GLCompute execution model entry " + "points require either the LocalSize execution mode or an " + "object decorated with WorkgroupSize must be specified.")); +} + +TEST_F(ValidateMode, GLComputeNoModeVulkanWorkgroupSize) { + const std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpDecorate %int3_1 BuiltIn WorkgroupSize +%int = OpTypeInt 32 0 +%int3 = OpTypeVector %int 3 +%int_1 = OpConstant %int 1 +%int3_1 = OpConstantComposite %int3 %int_1 %int_1 %int_1 +)" + kVoidFunction; + + spv_target_env env = SPV_ENV_VULKAN_1_0; + CompileSuccessfully(spirv, env); + EXPECT_THAT(SPV_SUCCESS, ValidateInstructions(env)); +} + +TEST_F(ValidateMode, GLComputeVulkanLocalSize) { + const std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +)" + kVoidFunction; + + spv_target_env env = SPV_ENV_VULKAN_1_0; + CompileSuccessfully(spirv, env); + EXPECT_THAT(SPV_SUCCESS, ValidateInstructions(env)); +} + +TEST_F(ValidateMode, FragmentOriginLowerLeftVulkan) { + const std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginLowerLeft +)" + kVoidFunction; + + spv_target_env env = SPV_ENV_VULKAN_1_0; + CompileSuccessfully(spirv, env); + EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions(env)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("In the Vulkan environment, the OriginLowerLeft " + "execution mode must not be used.")); +} + +TEST_F(ValidateMode, FragmentPixelCenterIntegerVulkan) { + const std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpExecutionMode %main PixelCenterInteger +)" + kVoidFunction; + + spv_target_env env = SPV_ENV_VULKAN_1_0; + CompileSuccessfully(spirv, env); + EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions(env)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("In the Vulkan environment, the PixelCenterInteger " + "execution mode must not be used.")); +} + +TEST_F(ValidateMode, GeometryNoOutputMode) { + const std::string spirv = R"( +OpCapability Geometry +OpMemoryModel Logical GLSL450 +OpEntryPoint Geometry %main "main" +OpExecutionMode %main InputPoints +)" + kVoidFunction; + + CompileSuccessfully(spirv); + EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Geometry execution model entry points must specify " + "exactly one of OutputPoints, OutputLineStrip or " + "OutputTriangleStrip execution modes.")); +} + +TEST_F(ValidateMode, GeometryNoInputMode) { + const std::string spirv = R"( +OpCapability Geometry +OpMemoryModel Logical GLSL450 +OpEntryPoint Geometry %main "main" +OpExecutionMode %main OutputPoints +)" + kVoidFunction; + + CompileSuccessfully(spirv); + EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Geometry execution model entry points must specify exactly " + "one of InputPoints, InputLines, InputLinesAdjacency, " + "Triangles or InputTrianglesAdjacency execution modes.")); +} + +TEST_F(ValidateMode, FragmentNoOrigin) { + const std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +)" + kVoidFunction; + + CompileSuccessfully(spirv); + EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Fragment execution model entry points require either an " + "OriginUpperLeft or OriginLowerLeft execution mode.")); +} + +TEST_F(ValidateMode, FragmentBothOrigins) { + const std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpExecutionMode %main OriginLowerLeft +)" + kVoidFunction; + + CompileSuccessfully(spirv); + EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Fragment execution model entry points can only specify one of " + "OriginUpperLeft or OriginLowerLeft execution modes.")); +} + +TEST_F(ValidateMode, FragmentDepthGreaterAndLess) { + const std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpExecutionMode %main DepthGreater +OpExecutionMode %main DepthLess +)" + kVoidFunction; + + CompileSuccessfully(spirv); + EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Fragment execution model entry points can specify at " + "most one of DepthGreater, DepthLess or DepthUnchanged " + "execution modes.")); +} + +TEST_F(ValidateMode, FragmentDepthGreaterAndUnchanged) { + const std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpExecutionMode %main DepthGreater +OpExecutionMode %main DepthUnchanged +)" + kVoidFunction; + + CompileSuccessfully(spirv); + EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Fragment execution model entry points can specify at " + "most one of DepthGreater, DepthLess or DepthUnchanged " + "execution modes.")); +} + +TEST_F(ValidateMode, FragmentDepthLessAndUnchanged) { + const std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpExecutionMode %main DepthLess +OpExecutionMode %main DepthUnchanged +)" + kVoidFunction; + + CompileSuccessfully(spirv); + EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Fragment execution model entry points can specify at " + "most one of DepthGreater, DepthLess or DepthUnchanged " + "execution modes.")); +} + +TEST_F(ValidateMode, FragmentAllDepths) { + const std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpExecutionMode %main DepthGreater +OpExecutionMode %main DepthLess +OpExecutionMode %main DepthUnchanged +)" + kVoidFunction; + + CompileSuccessfully(spirv); + EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Fragment execution model entry points can specify at " + "most one of DepthGreater, DepthLess or DepthUnchanged " + "execution modes.")); +} + +TEST_F(ValidateMode, TessellationControlSpacingEqualAndFractionalOdd) { + const std::string spirv = R"( +OpCapability Tessellation +OpMemoryModel Logical GLSL450 +OpEntryPoint TessellationControl %main "main" +OpExecutionMode %main SpacingEqual +OpExecutionMode %main SpacingFractionalOdd +)" + kVoidFunction; + + CompileSuccessfully(spirv); + EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Tessellation execution model entry points can specify " + "at most one of SpacingEqual, SpacingFractionalOdd or " + "SpacingFractionalEven execution modes.")); +} + +TEST_F(ValidateMode, TessellationControlSpacingEqualAndSpacingFractionalEven) { + const std::string spirv = R"( +OpCapability Tessellation +OpMemoryModel Logical GLSL450 +OpEntryPoint TessellationControl %main "main" +OpExecutionMode %main SpacingEqual +OpExecutionMode %main SpacingFractionalEven +)" + kVoidFunction; + + CompileSuccessfully(spirv); + EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Tessellation execution model entry points can specify " + "at most one of SpacingEqual, SpacingFractionalOdd or " + "SpacingFractionalEven execution modes.")); +} + +TEST_F(ValidateMode, + TessellationControlSpacingFractionalOddAndSpacingFractionalEven) { + const std::string spirv = R"( +OpCapability Tessellation +OpMemoryModel Logical GLSL450 +OpEntryPoint TessellationControl %main "main" +OpExecutionMode %main SpacingFractionalOdd +OpExecutionMode %main SpacingFractionalEven +)" + kVoidFunction; + + CompileSuccessfully(spirv); + EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Tessellation execution model entry points can specify " + "at most one of SpacingEqual, SpacingFractionalOdd or " + "SpacingFractionalEven execution modes.")); +} + +TEST_F(ValidateMode, TessellationControlAllSpacing) { + const std::string spirv = R"( +OpCapability Tessellation +OpMemoryModel Logical GLSL450 +OpEntryPoint TessellationControl %main "main" +OpExecutionMode %main SpacingEqual +OpExecutionMode %main SpacingFractionalOdd +OpExecutionMode %main SpacingFractionalEven +)" + kVoidFunction; + + CompileSuccessfully(spirv); + EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Tessellation execution model entry points can specify " + "at most one of SpacingEqual, SpacingFractionalOdd or " + "SpacingFractionalEven execution modes.")); +} + +TEST_F(ValidateMode, + TessellationEvaluationSpacingEqualAndSpacingFractionalOdd) { + const std::string spirv = R"( +OpCapability Tessellation +OpMemoryModel Logical GLSL450 +OpEntryPoint TessellationEvaluation %main "main" +OpExecutionMode %main SpacingEqual +OpExecutionMode %main SpacingFractionalOdd +)" + kVoidFunction; + + CompileSuccessfully(spirv); + EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Tessellation execution model entry points can specify " + "at most one of SpacingEqual, SpacingFractionalOdd or " + "SpacingFractionalEven execution modes.")); +} + +TEST_F(ValidateMode, + TessellationEvaluationSpacingEqualAndSpacingFractionalEven) { + const std::string spirv = R"( +OpCapability Tessellation +OpMemoryModel Logical GLSL450 +OpEntryPoint TessellationEvaluation %main "main" +OpExecutionMode %main SpacingEqual +OpExecutionMode %main SpacingFractionalEven +)" + kVoidFunction; + + CompileSuccessfully(spirv); + EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Tessellation execution model entry points can specify " + "at most one of SpacingEqual, SpacingFractionalOdd or " + "SpacingFractionalEven execution modes.")); +} + +TEST_F(ValidateMode, + TessellationEvaluationSpacingFractionalOddAndSpacingFractionalEven) { + const std::string spirv = R"( +OpCapability Tessellation +OpMemoryModel Logical GLSL450 +OpEntryPoint TessellationEvaluation %main "main" +OpExecutionMode %main SpacingFractionalOdd +OpExecutionMode %main SpacingFractionalEven +)" + kVoidFunction; + + CompileSuccessfully(spirv); + EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Tessellation execution model entry points can specify " + "at most one of SpacingEqual, SpacingFractionalOdd or " + "SpacingFractionalEven execution modes.")); +} + +TEST_F(ValidateMode, TessellationEvaluationAllSpacing) { + const std::string spirv = R"( +OpCapability Tessellation +OpMemoryModel Logical GLSL450 +OpEntryPoint TessellationEvaluation %main "main" +OpExecutionMode %main SpacingEqual +OpExecutionMode %main SpacingFractionalOdd +OpExecutionMode %main SpacingFractionalEven +)" + kVoidFunction; + + CompileSuccessfully(spirv); + EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Tessellation execution model entry points can specify " + "at most one of SpacingEqual, SpacingFractionalOdd or " + "SpacingFractionalEven execution modes.")); +} + +TEST_F(ValidateMode, TessellationControlBothVertex) { + const std::string spirv = R"( +OpCapability Tessellation +OpMemoryModel Logical GLSL450 +OpEntryPoint TessellationControl %main "main" +OpExecutionMode %main VertexOrderCw +OpExecutionMode %main VertexOrderCcw +)" + kVoidFunction; + + CompileSuccessfully(spirv); + EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Tessellation execution model entry points can specify at most " + "one of VertexOrderCw or VertexOrderCcw execution modes.")); +} + +TEST_F(ValidateMode, TessellationEvaluationBothVertex) { + const std::string spirv = R"( +OpCapability Tessellation +OpMemoryModel Logical GLSL450 +OpEntryPoint TessellationEvaluation %main "main" +OpExecutionMode %main VertexOrderCw +OpExecutionMode %main VertexOrderCcw +)" + kVoidFunction; + + CompileSuccessfully(spirv); + EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Tessellation execution model entry points can specify at most " + "one of VertexOrderCw or VertexOrderCcw execution modes.")); +} + +using ValidateModeGeometry = spvtest::ValidateBase, + std::tuple>>; + +TEST_P(ValidateModeGeometry, ExecutionMode) { + std::vector input_modes; + std::vector output_modes; + input_modes.push_back(std::get<0>(std::get<0>(GetParam()))); + input_modes.push_back(std::get<1>(std::get<0>(GetParam()))); + input_modes.push_back(std::get<2>(std::get<0>(GetParam()))); + input_modes.push_back(std::get<3>(std::get<0>(GetParam()))); + input_modes.push_back(std::get<4>(std::get<0>(GetParam()))); + output_modes.push_back(std::get<0>(std::get<1>(GetParam()))); + output_modes.push_back(std::get<1>(std::get<1>(GetParam()))); + output_modes.push_back(std::get<2>(std::get<1>(GetParam()))); + + std::ostringstream sstr; + sstr << "OpCapability Geometry\n"; + sstr << "OpMemoryModel Logical GLSL450\n"; + sstr << "OpEntryPoint Geometry %main \"main\"\n"; + size_t num_input_modes = 0; + for (auto input : input_modes) { + if (!input.empty()) { + num_input_modes++; + sstr << "OpExecutionMode %main " << input << "\n"; + } + } + size_t num_output_modes = 0; + for (auto output : output_modes) { + if (!output.empty()) { + num_output_modes++; + sstr << "OpExecutionMode %main " << output << "\n"; + } + } + sstr << "%void = OpTypeVoid\n"; + sstr << "%void_fn = OpTypeFunction %void\n"; + sstr << "%int = OpTypeInt 32 0\n"; + sstr << "%int1 = OpConstant %int 1\n"; + sstr << "%main = OpFunction %void None %void_fn\n"; + sstr << "%entry = OpLabel\n"; + sstr << "OpReturn\n"; + sstr << "OpFunctionEnd\n"; + + CompileSuccessfully(sstr.str()); + if (num_input_modes == 1 && num_output_modes == 1) { + EXPECT_THAT(SPV_SUCCESS, ValidateInstructions()); + } else { + EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + if (num_input_modes != 1) { + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Geometry execution model entry points must " + "specify exactly one of InputPoints, InputLines, " + "InputLinesAdjacency, Triangles or " + "InputTrianglesAdjacency execution modes.")); + } else { + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Geometry execution model entry points must specify " + "exactly one of OutputPoints, OutputLineStrip or " + "OutputTriangleStrip execution modes.")); + } + } +} + +INSTANTIATE_TEST_SUITE_P( + GeometryRequiredModes, ValidateModeGeometry, + Combine(Combine(Values("InputPoints", ""), Values("InputLines", ""), + Values("InputLinesAdjacency", ""), Values("Triangles", ""), + Values("InputTrianglesAdjacency", "")), + Combine(Values("OutputPoints", ""), Values("OutputLineStrip", ""), + Values("OutputTriangleStrip", "")))); + +using ValidateModeExecution = + spvtest::ValidateBase>; + +TEST_P(ValidateModeExecution, ExecutionMode) { + const spv_result_t expectation = std::get<0>(GetParam()); + const std::string error = std::get<1>(GetParam()); + const std::string model = std::get<2>(GetParam()); + const std::string mode = std::get<3>(GetParam()); + const spv_target_env env = std::get<4>(GetParam()); + + std::ostringstream sstr; + sstr << "OpCapability Shader\n"; + if (!spvIsWebGPUEnv(env)) { + sstr << "OpCapability Geometry\n"; + sstr << "OpCapability Tessellation\n"; + sstr << "OpCapability TransformFeedback\n"; + } + if (!spvIsVulkanOrWebGPUEnv(env)) { + sstr << "OpCapability Kernel\n"; + if (env == SPV_ENV_UNIVERSAL_1_3) { + sstr << "OpCapability SubgroupDispatch\n"; + } + } + if (spvIsWebGPUEnv(env)) { + sstr << "OpCapability VulkanMemoryModelKHR\n"; + sstr << "OpExtension \"SPV_KHR_vulkan_memory_model\"\n"; + sstr << "OpMemoryModel Logical VulkanKHR\n"; + } else { + sstr << "OpMemoryModel Logical GLSL450\n"; + } + sstr << "OpEntryPoint " << model << " %main \"main\"\n"; + if (mode.find("LocalSizeId") == 0 || mode.find("LocalSizeHintId") == 0 || + mode.find("SubgroupsPerWorkgroupId") == 0) { + sstr << "OpExecutionModeId %main " << mode << "\n"; + } else { + sstr << "OpExecutionMode %main " << mode << "\n"; + } + if (model == "Geometry") { + if (!(mode.find("InputPoints") == 0 || mode.find("InputLines") == 0 || + mode.find("InputLinesAdjacency") == 0 || + mode.find("Triangles") == 0 || + mode.find("InputTrianglesAdjacency") == 0)) { + // Exactly one of the above modes is required for Geometry shaders. + sstr << "OpExecutionMode %main InputPoints\n"; + } + if (!(mode.find("OutputPoints") == 0 || mode.find("OutputLineStrip") == 0 || + mode.find("OutputTriangleStrip") == 0)) { + // Exactly one of the above modes is required for Geometry shaders. + sstr << "OpExecutionMode %main OutputPoints\n"; + } + } else if (model == "Fragment") { + if (!(mode.find("OriginUpperLeft") == 0 || + mode.find("OriginLowerLeft") == 0)) { + // Exactly one of the above modes is required for Fragment shaders. + sstr << "OpExecutionMode %main OriginUpperLeft\n"; + } + } + sstr << "%void = OpTypeVoid\n"; + sstr << "%void_fn = OpTypeFunction %void\n"; + sstr << "%int = OpTypeInt 32 0\n"; + sstr << "%int1 = OpConstant %int 1\n"; + sstr << "%main = OpFunction %void None %void_fn\n"; + sstr << "%entry = OpLabel\n"; + sstr << "OpReturn\n"; + sstr << "OpFunctionEnd\n"; + + CompileSuccessfully(sstr.str(), env); + EXPECT_THAT(expectation, ValidateInstructions(env)); + if (expectation != SPV_SUCCESS) { + EXPECT_THAT(getDiagnosticString(), HasSubstr(error)); + } +} + +INSTANTIATE_TEST_SUITE_P( + ValidateModeGeometryOnlyGoodSpv10, ValidateModeExecution, + Combine(Values(SPV_SUCCESS), Values(""), Values("Geometry"), + Values("Invocations 3", "InputPoints", "InputLines", + "InputLinesAdjacency", "InputTrianglesAdjacency", + "OutputPoints", "OutputLineStrip", "OutputTriangleStrip"), + Values(SPV_ENV_UNIVERSAL_1_0))); + +INSTANTIATE_TEST_SUITE_P( + ValidateModeGeometryOnlyBadSpv10, ValidateModeExecution, + Combine(Values(SPV_ERROR_INVALID_DATA), + Values("Execution mode can only be used with the Geometry " + "execution model."), + Values("Fragment", "TessellationEvaluation", "TessellationControl", + "GLCompute", "Vertex", "Kernel"), + Values("Invocations 3", "InputPoints", "InputLines", + "InputLinesAdjacency", "InputTrianglesAdjacency", + "OutputPoints", "OutputLineStrip", "OutputTriangleStrip"), + Values(SPV_ENV_UNIVERSAL_1_0))); + +INSTANTIATE_TEST_SUITE_P( + ValidateModeTessellationOnlyGoodSpv10, ValidateModeExecution, + Combine(Values(SPV_SUCCESS), Values(""), + Values("TessellationControl", "TessellationEvaluation"), + Values("SpacingEqual", "SpacingFractionalEven", + "SpacingFractionalOdd", "VertexOrderCw", "VertexOrderCcw", + "PointMode", "Quads", "Isolines"), + Values(SPV_ENV_UNIVERSAL_1_0))); + +INSTANTIATE_TEST_SUITE_P( + ValidateModeTessellationOnlyBadSpv10, ValidateModeExecution, + Combine(Values(SPV_ERROR_INVALID_DATA), + Values("Execution mode can only be used with a tessellation " + "execution model."), + Values("Fragment", "Geometry", "GLCompute", "Vertex", "Kernel"), + Values("SpacingEqual", "SpacingFractionalEven", + "SpacingFractionalOdd", "VertexOrderCw", "VertexOrderCcw", + "PointMode", "Quads", "Isolines"), + Values(SPV_ENV_UNIVERSAL_1_0))); + +INSTANTIATE_TEST_SUITE_P(ValidateModeGeometryAndTessellationGoodSpv10, + ValidateModeExecution, + Combine(Values(SPV_SUCCESS), Values(""), + Values("TessellationControl", + "TessellationEvaluation", "Geometry"), + Values("Triangles", "OutputVertices 3"), + Values(SPV_ENV_UNIVERSAL_1_0))); + +INSTANTIATE_TEST_SUITE_P( + ValidateModeGeometryAndTessellationBadSpv10, ValidateModeExecution, + Combine(Values(SPV_ERROR_INVALID_DATA), + Values("Execution mode can only be used with a Geometry or " + "tessellation execution model."), + Values("Fragment", "GLCompute", "Vertex", "Kernel"), + Values("Triangles", "OutputVertices 3"), + Values(SPV_ENV_UNIVERSAL_1_0))); + +INSTANTIATE_TEST_SUITE_P( + ValidateModeFragmentOnlyGoodSpv10, ValidateModeExecution, + Combine(Values(SPV_SUCCESS), Values(""), Values("Fragment"), + Values("PixelCenterInteger", "OriginUpperLeft", "OriginLowerLeft", + "EarlyFragmentTests", "DepthReplacing", "DepthLess", + "DepthUnchanged"), + Values(SPV_ENV_UNIVERSAL_1_0))); + +INSTANTIATE_TEST_SUITE_P( + ValidateModeFragmentOnlyBadSpv10, ValidateModeExecution, + Combine(Values(SPV_ERROR_INVALID_DATA), + Values("Execution mode can only be used with the Fragment " + "execution model."), + Values("Geometry", "TessellationControl", "TessellationEvaluation", + "GLCompute", "Vertex", "Kernel"), + Values("PixelCenterInteger", "OriginUpperLeft", "OriginLowerLeft", + "EarlyFragmentTests", "DepthReplacing", "DepthGreater", + "DepthLess", "DepthUnchanged"), + Values(SPV_ENV_UNIVERSAL_1_0))); + +INSTANTIATE_TEST_SUITE_P(ValidateModeKernelOnlyGoodSpv13, ValidateModeExecution, + Combine(Values(SPV_SUCCESS), Values(""), + Values("Kernel"), + Values("LocalSizeHint 1 1 1", "VecTypeHint 4", + "ContractionOff", + "LocalSizeHintId %int1"), + Values(SPV_ENV_UNIVERSAL_1_3))); + +INSTANTIATE_TEST_SUITE_P( + ValidateModeKernelOnlyBadSpv13, ValidateModeExecution, + Combine( + Values(SPV_ERROR_INVALID_DATA), + Values( + "Execution mode can only be used with the Kernel execution model."), + Values("Geometry", "TessellationControl", "TessellationEvaluation", + "GLCompute", "Vertex", "Fragment"), + Values("LocalSizeHint 1 1 1", "VecTypeHint 4", "ContractionOff", + "LocalSizeHintId %int1"), + Values(SPV_ENV_UNIVERSAL_1_3))); + +INSTANTIATE_TEST_SUITE_P( + ValidateModeGLComputeAndKernelGoodSpv13, ValidateModeExecution, + Combine(Values(SPV_SUCCESS), Values(""), Values("Kernel", "GLCompute"), + Values("LocalSize 1 1 1", "LocalSizeId %int1 %int1 %int1"), + Values(SPV_ENV_UNIVERSAL_1_3))); + +INSTANTIATE_TEST_SUITE_P( + ValidateModeGLComputeAndKernelBadSpv13, ValidateModeExecution, + Combine(Values(SPV_ERROR_INVALID_DATA), + Values("Execution mode can only be used with a Kernel or GLCompute " + "execution model."), + Values("Geometry", "TessellationControl", "TessellationEvaluation", + "Fragment", "Vertex"), + Values("LocalSize 1 1 1", "LocalSizeId %int1 %int1 %int1"), + Values(SPV_ENV_UNIVERSAL_1_3))); + +INSTANTIATE_TEST_SUITE_P( + ValidateModeAllGoodSpv13, ValidateModeExecution, + Combine(Values(SPV_SUCCESS), Values(""), + Values("Kernel", "GLCompute", "Geometry", "TessellationControl", + "TessellationEvaluation", "Fragment", "Vertex"), + Values("Xfb", "Initializer", "Finalizer", "SubgroupSize 1", + "SubgroupsPerWorkgroup 1", "SubgroupsPerWorkgroupId %int1"), + Values(SPV_ENV_UNIVERSAL_1_3))); + +INSTANTIATE_TEST_SUITE_P(ValidateModeGLComputeWebGPUWhitelistGood, + ValidateModeExecution, + Combine(Values(SPV_SUCCESS), Values(""), + Values("GLCompute"), Values("LocalSize 1 1 1"), + Values(SPV_ENV_WEBGPU_0))); + +INSTANTIATE_TEST_SUITE_P( + ValidateModeGLComputeWebGPUWhitelistBad, ValidateModeExecution, + Combine(Values(SPV_ERROR_INVALID_DATA), + Values("Execution mode must be one of OriginUpperLeft, " + "DepthReplacing, DepthGreater, DepthLess, DepthUnchanged, " + "LocalSize, or LocalSizeHint for WebGPU environment"), + Values("GLCompute"), Values("LocalSizeId %int1 %int1 %int1"), + Values(SPV_ENV_WEBGPU_0))); + +INSTANTIATE_TEST_SUITE_P( + ValidateModeFragmentWebGPUWhitelistGood, ValidateModeExecution, + Combine(Values(SPV_SUCCESS), Values(""), Values("Fragment"), + Values("OriginUpperLeft", "DepthReplacing", "DepthGreater", + "DepthLess", "DepthUnchanged"), + Values(SPV_ENV_WEBGPU_0))); + +INSTANTIATE_TEST_SUITE_P( + ValidateModeFragmentWebGPUWhitelistBad, ValidateModeExecution, + Combine(Values(SPV_ERROR_INVALID_DATA), + Values("Execution mode must be one of OriginUpperLeft, " + "DepthReplacing, DepthGreater, DepthLess, DepthUnchanged, " + "LocalSize, or LocalSizeHint for WebGPU environment"), + Values("Fragment"), + Values("PixelCenterInteger", "OriginLowerLeft", + "EarlyFragmentTests"), + Values(SPV_ENV_WEBGPU_0))); + +TEST_F(ValidateModeExecution, MeshNVLocalSize) { + const std::string spirv = R"( +OpCapability Shader +OpCapability MeshShadingNV +OpExtension "SPV_NV_mesh_shader" +OpMemoryModel Logical GLSL450 +OpEntryPoint MeshNV %main "main" +OpExecutionMode %main LocalSize 1 1 1 +)" + kVoidFunction; + + CompileSuccessfully(spirv); + EXPECT_THAT(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateModeExecution, TaskNVLocalSize) { + const std::string spirv = R"( +OpCapability Shader +OpCapability MeshShadingNV +OpExtension "SPV_NV_mesh_shader" +OpMemoryModel Logical GLSL450 +OpEntryPoint TaskNV %main "main" +OpExecutionMode %main LocalSize 1 1 1 +)" + kVoidFunction; + + CompileSuccessfully(spirv); + EXPECT_THAT(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateModeExecution, MeshNVOutputPoints) { + const std::string spirv = R"( +OpCapability Shader +OpCapability MeshShadingNV +OpExtension "SPV_NV_mesh_shader" +OpMemoryModel Logical GLSL450 +OpEntryPoint MeshNV %main "main" +OpExecutionMode %main OutputPoints +)" + kVoidFunction; + + CompileSuccessfully(spirv); + EXPECT_THAT(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateModeExecution, MeshNVOutputVertices) { + const std::string spirv = R"( +OpCapability Shader +OpCapability MeshShadingNV +OpExtension "SPV_NV_mesh_shader" +OpMemoryModel Logical GLSL450 +OpEntryPoint MeshNV %main "main" +OpExecutionMode %main OutputVertices 42 +)" + kVoidFunction; + + CompileSuccessfully(spirv); + EXPECT_THAT(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateModeExecution, MeshNVLocalSizeId) { + const std::string spirv = R"( +OpCapability Shader +OpCapability MeshShadingNV +OpExtension "SPV_NV_mesh_shader" +OpMemoryModel Logical GLSL450 +OpEntryPoint MeshNV %main "main" +OpExecutionModeId %main LocalSizeId %int_1 %int_1 %int_1 +%int = OpTypeInt 32 0 +%int_1 = OpConstant %int 1 +)" + kVoidFunction; + + spv_target_env env = SPV_ENV_UNIVERSAL_1_3; + CompileSuccessfully(spirv, env); + EXPECT_THAT(SPV_SUCCESS, ValidateInstructions(env)); +} + +TEST_F(ValidateModeExecution, TaskNVLocalSizeId) { + const std::string spirv = R"( +OpCapability Shader +OpCapability MeshShadingNV +OpExtension "SPV_NV_mesh_shader" +OpMemoryModel Logical GLSL450 +OpEntryPoint TaskNV %main "main" +OpExecutionModeId %main LocalSizeId %int_1 %int_1 %int_1 +%int = OpTypeInt 32 0 +%int_1 = OpConstant %int 1 +)" + kVoidFunction; + + spv_target_env env = SPV_ENV_UNIVERSAL_1_3; + CompileSuccessfully(spirv, env); + EXPECT_THAT(SPV_SUCCESS, ValidateInstructions(env)); +} + +TEST_F(ValidateModeExecution, ExecModeSubgroupsPerWorkgroupIdBad) { + const std::string spirv = R"( +OpCapability Shader +OpCapability SubgroupDispatch +OpMemoryModel Logical GLSL450 +OpEntryPoint Vertex %main "main" +OpExecutionMode %main SubgroupsPerWorkgroupId %int_1 +%int = OpTypeInt 32 0 +%int_1 = OpConstant %int 1 +)" + kVoidFunction; + + spv_target_env env = SPV_ENV_UNIVERSAL_1_3; + CompileSuccessfully(spirv, env); + EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions(env)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("OpExecutionMode is only valid when the Mode operand " + "is an execution mode that takes no Extra Operands")); +} + +TEST_F(ValidateModeExecution, ExecModeIdSubgroupsPerWorkgroupIdGood) { + const std::string spirv = R"( +OpCapability Shader +OpCapability SubgroupDispatch +OpMemoryModel Logical GLSL450 +OpEntryPoint Vertex %main "main" +OpExecutionModeId %main SubgroupsPerWorkgroupId %int_1 +%int = OpTypeInt 32 0 +%int_1 = OpConstant %int 1 +)" + kVoidFunction; + + spv_target_env env = SPV_ENV_UNIVERSAL_1_3; + CompileSuccessfully(spirv, env); + EXPECT_THAT(SPV_SUCCESS, ValidateInstructions(env)); +} + +TEST_F(ValidateModeExecution, ExecModeIdSubgroupsPerWorkgroupIdNonConstantBad) { + const std::string spirv = R"( +OpCapability Shader +OpCapability SubgroupDispatch +OpMemoryModel Logical GLSL450 +OpEntryPoint Vertex %main "main" +OpExecutionModeId %main SubgroupsPerWorkgroupId %int_1 +%int = OpTypeInt 32 0 +%int_ptr = OpTypePointer Private %int +%int_1 = OpVariable %int_ptr Private +)" + kVoidFunction; + + spv_target_env env = SPV_ENV_UNIVERSAL_1_3; + CompileSuccessfully(spirv, env); + EXPECT_THAT(SPV_ERROR_INVALID_ID, ValidateInstructions(env)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("For OpExecutionModeId all Extra Operand ids must be " + "constant instructions.")); +} + +TEST_F(ValidateModeExecution, ExecModeLocalSizeHintIdBad) { + const std::string spirv = R"( +OpCapability Kernel +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Kernel %main "main" +OpExecutionMode %main LocalSizeHintId %int_1 +%int = OpTypeInt 32 0 +%int_1 = OpConstant %int 1 +)" + kVoidFunction; + + spv_target_env env = SPV_ENV_UNIVERSAL_1_3; + CompileSuccessfully(spirv, env); + EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions(env)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("OpExecutionMode is only valid when the Mode operand " + "is an execution mode that takes no Extra Operands")); +} + +TEST_F(ValidateModeExecution, ExecModeIdLocalSizeHintIdGood) { + const std::string spirv = R"( +OpCapability Kernel +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Kernel %main "main" +OpExecutionModeId %main LocalSizeHintId %int_1 +%int = OpTypeInt 32 0 +%int_1 = OpConstant %int 1 +)" + kVoidFunction; + + spv_target_env env = SPV_ENV_UNIVERSAL_1_3; + CompileSuccessfully(spirv, env); + EXPECT_THAT(SPV_SUCCESS, ValidateInstructions(env)); +} + +TEST_F(ValidateModeExecution, ExecModeIdLocalSizeHintIdNonConstantBad) { + const std::string spirv = R"( +OpCapability Kernel +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Vertex %main "main" +OpExecutionModeId %main LocalSizeHintId %int_1 +%int = OpTypeInt 32 0 +%int_ptr = OpTypePointer Private %int +%int_1 = OpVariable %int_ptr Private +)" + kVoidFunction; + + spv_target_env env = SPV_ENV_UNIVERSAL_1_3; + CompileSuccessfully(spirv, env); + EXPECT_THAT(SPV_ERROR_INVALID_ID, ValidateInstructions(env)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("For OpExecutionModeId all Extra Operand ids must be " + "constant instructions.")); +} + +TEST_F(ValidateModeExecution, ExecModeLocalSizeIdBad) { + const std::string spirv = R"( +OpCapability Kernel +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Kernel %main "main" +OpExecutionMode %main LocalSizeId %int_1 %int_1 %int_1 +%int = OpTypeInt 32 0 +%int_1 = OpConstant %int 1 +)" + kVoidFunction; + + spv_target_env env = SPV_ENV_UNIVERSAL_1_3; + CompileSuccessfully(spirv, env); + EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions(env)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("OpExecutionMode is only valid when the Mode operand " + "is an execution mode that takes no Extra Operands")); +} + +TEST_F(ValidateModeExecution, ExecModeIdLocalSizeIdGood) { + const std::string spirv = R"( +OpCapability Kernel +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Kernel %main "main" +OpExecutionModeId %main LocalSizeId %int_1 %int_1 %int_1 +%int = OpTypeInt 32 0 +%int_1 = OpConstant %int 1 +)" + kVoidFunction; + + spv_target_env env = SPV_ENV_UNIVERSAL_1_3; + CompileSuccessfully(spirv, env); + EXPECT_THAT(SPV_SUCCESS, ValidateInstructions(env)); +} + +TEST_F(ValidateModeExecution, ExecModeIdLocalSizeIdNonConstantBad) { + const std::string spirv = R"( +OpCapability Kernel +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Vertex %main "main" +OpExecutionModeId %main LocalSizeId %int_1 %int_1 %int_1 +%int = OpTypeInt 32 0 +%int_ptr = OpTypePointer Private %int +%int_1 = OpVariable %int_ptr Private +)" + kVoidFunction; + + spv_target_env env = SPV_ENV_UNIVERSAL_1_3; + CompileSuccessfully(spirv, env); + EXPECT_THAT(SPV_ERROR_INVALID_ID, ValidateInstructions(env)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("For OpExecutionModeId all Extra Operand ids must be " + "constant instructions.")); +} + +TEST_F(ValidateMode, FragmentShaderInterlockVertexBad) { + const std::string spirv = R"( +OpCapability Shader +OpCapability FragmentShaderPixelInterlockEXT +OpExtension "SPV_EXT_fragment_shader_interlock" +OpMemoryModel Logical GLSL450 +OpEntryPoint Vertex %main "main" +OpExecutionMode %main PixelInterlockOrderedEXT +)" + kVoidFunction; + + CompileSuccessfully(spirv); + EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "Execution mode can only be used with the Fragment execution model")); +} + +TEST_F(ValidateMode, FragmentShaderInterlockTooManyModesBad) { + const std::string spirv = R"( +OpCapability Shader +OpCapability FragmentShaderPixelInterlockEXT +OpCapability FragmentShaderSampleInterlockEXT +OpExtension "SPV_EXT_fragment_shader_interlock" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpExecutionMode %main PixelInterlockOrderedEXT +OpExecutionMode %main SampleInterlockOrderedEXT +)" + kVoidFunction; + + CompileSuccessfully(spirv); + EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Fragment execution model entry points can specify at most " + "one fragment shader interlock execution mode")); +} + +TEST_F(ValidateMode, FragmentShaderInterlockNoModeBad) { + const std::string spirv = R"( +OpCapability Shader +OpCapability FragmentShaderPixelInterlockEXT +OpExtension "SPV_EXT_fragment_shader_interlock" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%func = OpFunction %void None %void_fn +%entryf = OpLabel +OpBeginInvocationInterlockEXT +OpEndInvocationInterlockEXT +OpReturn +OpFunctionEnd +%main = OpFunction %void None %void_fn +%entry = OpLabel +%1 = OpFunctionCall %void %func +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_THAT(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "OpBeginInvocationInterlockEXT/OpEndInvocationInterlockEXT require a " + "fragment shader interlock execution mode")); +} + +TEST_F(ValidateMode, FragmentShaderInterlockGood) { + const std::string spirv = R"( +OpCapability Shader +OpCapability FragmentShaderPixelInterlockEXT +OpExtension "SPV_EXT_fragment_shader_interlock" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpExecutionMode %main PixelInterlockOrderedEXT +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%func = OpFunction %void None %void_fn +%entryf = OpLabel +OpBeginInvocationInterlockEXT +OpEndInvocationInterlockEXT +OpReturn +OpFunctionEnd +%main = OpFunction %void None %void_fn +%entry = OpLabel +%1 = OpFunctionCall %void %func +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_THAT(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateMode, FragmentShaderDemoteVertexBad) { + const std::string spirv = R"( +OpCapability Shader +OpCapability DemoteToHelperInvocationEXT +OpExtension "SPV_EXT_demote_to_helper_invocation" +OpMemoryModel Logical GLSL450 +OpEntryPoint Vertex %main "main" +%bool = OpTypeBool +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpDemoteToHelperInvocationEXT +%1 = OpIsHelperInvocationEXT %bool +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_THAT(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "OpDemoteToHelperInvocationEXT requires Fragment execution model")); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("OpIsHelperInvocationEXT requires Fragment execution model")); +} + +TEST_F(ValidateMode, FragmentShaderDemoteGood) { + const std::string spirv = R"( +OpCapability Shader +OpCapability DemoteToHelperInvocationEXT +OpExtension "SPV_EXT_demote_to_helper_invocation" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +%bool = OpTypeBool +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpDemoteToHelperInvocationEXT +%1 = OpIsHelperInvocationEXT %bool +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_THAT(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateMode, FragmentShaderDemoteBadType) { + const std::string spirv = R"( +OpCapability Shader +OpCapability DemoteToHelperInvocationEXT +OpExtension "SPV_EXT_demote_to_helper_invocation" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +%u32 = OpTypeInt 32 0 +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpDemoteToHelperInvocationEXT +%1 = OpIsHelperInvocationEXT %u32 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_THAT(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Expected bool scalar type as Result Type")); +} + +} // namespace +} // namespace val +} // namespace spvtools diff --git a/third_party/spirv-tools/test/val/val_non_semantic_test.cpp b/third_party/spirv-tools/test/val/val_non_semantic_test.cpp new file mode 100644 index 0000000000..b80bb1ac94 --- /dev/null +++ b/third_party/spirv-tools/test/val/val_non_semantic_test.cpp @@ -0,0 +1,195 @@ +// Copyright (c) 2019 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. + +// Validation tests for non-semantic instructions + +#include +#include + +#include "gmock/gmock.h" +#include "test/unit_spirv.h" +#include "test/val/val_code_generator.h" +#include "test/val/val_fixtures.h" + +namespace spvtools { +namespace val { +namespace { + +struct TestResult { + TestResult(spv_result_t in_validation_result = SPV_SUCCESS, + const char* in_error_str = nullptr, + const char* in_error_str2 = nullptr) + : validation_result(in_validation_result), + error_str(in_error_str), + error_str2(in_error_str2) {} + spv_result_t validation_result; + const char* error_str; + const char* error_str2; +}; + +using ::testing::Combine; +using ::testing::HasSubstr; +using ::testing::Values; +using ::testing::ValuesIn; + +using ValidateNonSemanticGenerated = spvtest::ValidateBase< + std::tuple>; +using ValidateNonSemanticString = spvtest::ValidateBase; + +CodeGenerator GetNonSemanticCodeGenerator(const bool declare_ext, + const bool declare_extinst, + const char* const global_extinsts, + const char* const function_extinsts) { + CodeGenerator generator = CodeGenerator::GetDefaultShaderCodeGenerator(); + + if (declare_ext) { + generator.extensions_ += "OpExtension \"SPV_KHR_non_semantic_info\"\n"; + } + if (declare_extinst) { + generator.extensions_ += + "%extinst = OpExtInstImport \"NonSemantic.Testing.Set\"\n"; + } + + generator.after_types_ = global_extinsts; + + generator.before_types_ = "%decorate_group = OpDecorationGroup"; + + EntryPoint entry_point; + entry_point.name = "main"; + entry_point.execution_model = "Vertex"; + + entry_point.body = R"( +)"; + entry_point.body += function_extinsts; + generator.entry_points_.push_back(std::move(entry_point)); + + return generator; +} + +TEST_P(ValidateNonSemanticGenerated, InTest) { + const bool declare_ext = std::get<0>(GetParam()); + const bool declare_extinst = std::get<1>(GetParam()); + const char* const global_extinsts = std::get<2>(GetParam()); + const char* const function_extinsts = std::get<3>(GetParam()); + const TestResult& test_result = std::get<4>(GetParam()); + + CodeGenerator generator = GetNonSemanticCodeGenerator( + declare_ext, declare_extinst, global_extinsts, function_extinsts); + + CompileSuccessfully(generator.Build(), SPV_ENV_VULKAN_1_0); + ASSERT_EQ(test_result.validation_result, + ValidateInstructions(SPV_ENV_VULKAN_1_0)); + if (test_result.error_str) { + EXPECT_THAT(getDiagnosticString(), + testing::ContainsRegex(test_result.error_str)); + } + if (test_result.error_str2) { + EXPECT_THAT(getDiagnosticString(), + testing::ContainsRegex(test_result.error_str2)); + } +} + +INSTANTIATE_TEST_SUITE_P(OnlyOpExtension, ValidateNonSemanticGenerated, + Combine(Values(true), Values(false), Values(""), + Values(""), Values(TestResult()))); + +INSTANTIATE_TEST_SUITE_P( + MissingOpExtension, ValidateNonSemanticGenerated, + Combine(Values(false), Values(true), Values(""), Values(""), + Values(TestResult( + SPV_ERROR_INVALID_DATA, + "NonSemantic extended instruction sets cannot be declared " + "without SPV_KHR_non_semantic_info.")))); + +INSTANTIATE_TEST_SUITE_P(NoExtInst, ValidateNonSemanticGenerated, + Combine(Values(true), Values(true), Values(""), + Values(""), Values(TestResult()))); + +INSTANTIATE_TEST_SUITE_P( + SimpleGlobalExtInst, ValidateNonSemanticGenerated, + Combine(Values(true), Values(true), + Values("%result = OpExtInst %void %extinst 123 %i32"), Values(""), + Values(TestResult()))); + +INSTANTIATE_TEST_SUITE_P( + ComplexGlobalExtInst, ValidateNonSemanticGenerated, + Combine(Values(true), Values(true), + Values("%result = OpExtInst %void %extinst 123 %i32 %u32_2 " + "%f32vec4_1234 %u32_0"), + Values(""), Values(TestResult()))); + +INSTANTIATE_TEST_SUITE_P( + SimpleFunctionLevelExtInst, ValidateNonSemanticGenerated, + Combine(Values(true), Values(true), Values(""), + Values("%result = OpExtInst %void %extinst 123 %i32"), + Values(TestResult()))); + +INSTANTIATE_TEST_SUITE_P( + FunctionTypeReference, ValidateNonSemanticGenerated, + Combine(Values(true), Values(true), + Values("%result = OpExtInst %void %extinst 123 %func"), Values(""), + Values(TestResult()))); + +INSTANTIATE_TEST_SUITE_P( + EntryPointReference, ValidateNonSemanticGenerated, + Combine(Values(true), Values(true), Values(""), + Values("%result = OpExtInst %void %extinst 123 %main"), + Values(TestResult()))); + +INSTANTIATE_TEST_SUITE_P( + DecorationGroupReference, ValidateNonSemanticGenerated, + Combine(Values(true), Values(true), Values(""), + Values("%result = OpExtInst %void %extinst 123 %decorate_group"), + Values(TestResult()))); + +INSTANTIATE_TEST_SUITE_P( + UnknownIDReference, ValidateNonSemanticGenerated, + Combine(Values(true), Values(true), + Values("%result = OpExtInst %void %extinst 123 %undefined_id"), + Values(""), + Values(TestResult(SPV_ERROR_INVALID_ID, + "ID .* has not been defined")))); + +INSTANTIATE_TEST_SUITE_P( + NonSemanticUseInSemantic, ValidateNonSemanticGenerated, + Combine(Values(true), Values(true), + Values("%result = OpExtInst %f32 %extinst 123 %i32\n" + "%invalid = OpConstantComposite %f32vec2 %f32_0 %result"), + Values(""), + Values(TestResult(SPV_ERROR_INVALID_ID, + "in semantic instruction cannot be a " + "non-semantic instruction")))); + +TEST_F(ValidateNonSemanticString, InvalidSectionOpExtInst) { + const std::string spirv = R"( +OpCapability Shader +OpExtension "SPV_KHR_non_semantic_info" +%extinst = OpExtInstImport "NonSemantic.Testing.Set" +%test = OpExtInst %void %extinst 4 %void +OpMemoryModel Logical GLSL450 +OpEntryPoint Vertex %main "main" +)"; + + CompileSuccessfully(spirv); + EXPECT_THAT(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + + // there's no specific error for using an OpExtInst too early, it requires a + // type so by definition any use of a type in it will be an undefined ID + EXPECT_THAT(getDiagnosticString(), + HasSubstr("ID 2[%2] has not been defined")); +} + +} // namespace +} // namespace val +} // namespace spvtools diff --git a/third_party/spirv-tools/test/val/val_non_uniform_test.cpp b/third_party/spirv-tools/test/val/val_non_uniform_test.cpp index 6ff5c127b3..fbd11a9ef2 100644 --- a/third_party/spirv-tools/test/val/val_non_uniform_test.cpp +++ b/third_party/spirv-tools/test/val/val_non_uniform_test.cpp @@ -49,14 +49,19 @@ OpCapability GroupNonUniformQuad ss << capabilities_and_extensions; ss << "OpMemoryModel Logical GLSL450\n"; ss << "OpEntryPoint " << execution_model << " %main \"main\"\n"; + if (execution_model == "GLCompute") { + ss << "OpExecutionMode %main LocalSize 1 1 1\n"; + } ss << R"( %void = OpTypeVoid %func = OpTypeFunction %void %bool = OpTypeBool %u32 = OpTypeInt 32 0 +%int = OpTypeInt 32 1 %float = OpTypeFloat 32 %u32vec4 = OpTypeVector %u32 4 +%u32vec3 = OpTypeVector %u32 3 %true = OpConstantTrue %bool %false = OpConstantFalse %bool @@ -66,6 +71,7 @@ OpCapability GroupNonUniformQuad %float_0 = OpConstant %float 0 %u32vec4_null = OpConstantComposite %u32vec4 %u32_0 %u32_0 %u32_0 %u32_0 +%u32vec3_null = OpConstantComposite %u32vec3 %u32_0 %u32_0 %u32_0 %cross_device = OpConstant %u32 0 %device = OpConstant %u32 1 @@ -94,8 +100,8 @@ OpFunctionEnd)"; SpvScope scopes[] = {SpvScopeCrossDevice, SpvScopeDevice, SpvScopeWorkgroup, SpvScopeSubgroup, SpvScopeInvocation}; -using GroupNonUniformScope = spvtest::ValidateBase< - std::tuple>; +using GroupNonUniform = spvtest::ValidateBase< + std::tuple>; std::string ConvertScope(SpvScope scope) { switch (scope) { @@ -114,11 +120,12 @@ std::string ConvertScope(SpvScope scope) { } } -TEST_P(GroupNonUniformScope, Vulkan1p1) { +TEST_P(GroupNonUniform, Vulkan1p1) { std::string opcode = std::get<0>(GetParam()); std::string type = std::get<1>(GetParam()); SpvScope execution_scope = std::get<2>(GetParam()); std::string args = std::get<3>(GetParam()); + std::string error = std::get<4>(GetParam()); std::ostringstream sstr; sstr << "%result = " << opcode << " "; @@ -128,22 +135,28 @@ TEST_P(GroupNonUniformScope, Vulkan1p1) { CompileSuccessfully(GenerateShaderCode(sstr.str()), SPV_ENV_VULKAN_1_1); spv_result_t result = ValidateInstructions(SPV_ENV_VULKAN_1_1); - if (execution_scope == SpvScopeSubgroup) { - EXPECT_EQ(SPV_SUCCESS, result); + if (error == "") { + if (execution_scope == SpvScopeSubgroup) { + EXPECT_EQ(SPV_SUCCESS, result); + } else { + EXPECT_EQ(SPV_ERROR_INVALID_DATA, result); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "in Vulkan environment Execution scope is limited to Subgroup")); + } } else { EXPECT_EQ(SPV_ERROR_INVALID_DATA, result); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr( - "in Vulkan environment Execution scope is limited to Subgroup")); + EXPECT_THAT(getDiagnosticString(), HasSubstr(error)); } } -TEST_P(GroupNonUniformScope, Spirv1p3) { +TEST_P(GroupNonUniform, Spirv1p3) { std::string opcode = std::get<0>(GetParam()); std::string type = std::get<1>(GetParam()); SpvScope execution_scope = std::get<2>(GetParam()); std::string args = std::get<3>(GetParam()); + std::string error = std::get<4>(GetParam()); std::ostringstream sstr; sstr << "%result = " << opcode << " "; @@ -153,99 +166,127 @@ TEST_P(GroupNonUniformScope, Spirv1p3) { CompileSuccessfully(GenerateShaderCode(sstr.str()), SPV_ENV_UNIVERSAL_1_3); spv_result_t result = ValidateInstructions(SPV_ENV_UNIVERSAL_1_3); - if (execution_scope == SpvScopeSubgroup || - execution_scope == SpvScopeWorkgroup) { - EXPECT_EQ(SPV_SUCCESS, result); + if (error == "") { + if (execution_scope == SpvScopeSubgroup || + execution_scope == SpvScopeWorkgroup) { + EXPECT_EQ(SPV_SUCCESS, result); + } else { + EXPECT_EQ(SPV_ERROR_INVALID_DATA, result); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Execution scope is limited to Subgroup or Workgroup")); + } } else { EXPECT_EQ(SPV_ERROR_INVALID_DATA, result); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr("Execution scope is limited to Subgroup or Workgroup")); + EXPECT_THAT(getDiagnosticString(), HasSubstr(error)); } } -INSTANTIATE_TEST_CASE_P(GroupNonUniformElect, GroupNonUniformScope, - Combine(Values("OpGroupNonUniformElect"), - Values("%bool"), ValuesIn(scopes), Values(""))); +INSTANTIATE_TEST_SUITE_P(GroupNonUniformElect, GroupNonUniform, + Combine(Values("OpGroupNonUniformElect"), + Values("%bool"), ValuesIn(scopes), Values(""), + Values(""))); -INSTANTIATE_TEST_CASE_P(GroupNonUniformVote, GroupNonUniformScope, - Combine(Values("OpGroupNonUniformAll", - "OpGroupNonUniformAny", - "OpGroupNonUniformAllEqual"), - Values("%bool"), ValuesIn(scopes), - Values("%true"))); +INSTANTIATE_TEST_SUITE_P(GroupNonUniformVote, GroupNonUniform, + Combine(Values("OpGroupNonUniformAll", + "OpGroupNonUniformAny", + "OpGroupNonUniformAllEqual"), + Values("%bool"), ValuesIn(scopes), + Values("%true"), Values(""))); -INSTANTIATE_TEST_CASE_P(GroupNonUniformBroadcast, GroupNonUniformScope, - Combine(Values("OpGroupNonUniformBroadcast"), - Values("%bool"), ValuesIn(scopes), - Values("%true %u32_0"))); +INSTANTIATE_TEST_SUITE_P(GroupNonUniformBroadcast, GroupNonUniform, + Combine(Values("OpGroupNonUniformBroadcast"), + Values("%bool"), ValuesIn(scopes), + Values("%true %u32_0"), Values(""))); -INSTANTIATE_TEST_CASE_P(GroupNonUniformBroadcastFirst, GroupNonUniformScope, - Combine(Values("OpGroupNonUniformBroadcastFirst"), - Values("%bool"), ValuesIn(scopes), - Values("%true"))); +INSTANTIATE_TEST_SUITE_P(GroupNonUniformBroadcastFirst, GroupNonUniform, + Combine(Values("OpGroupNonUniformBroadcastFirst"), + Values("%bool"), ValuesIn(scopes), + Values("%true"), Values(""))); -INSTANTIATE_TEST_CASE_P(GroupNonUniformBallot, GroupNonUniformScope, - Combine(Values("OpGroupNonUniformBallot"), - Values("%u32vec4"), ValuesIn(scopes), - Values("%true"))); +INSTANTIATE_TEST_SUITE_P(GroupNonUniformBallot, GroupNonUniform, + Combine(Values("OpGroupNonUniformBallot"), + Values("%u32vec4"), ValuesIn(scopes), + Values("%true"), Values(""))); -INSTANTIATE_TEST_CASE_P(GroupNonUniformInverseBallot, GroupNonUniformScope, - Combine(Values("OpGroupNonUniformInverseBallot"), - Values("%bool"), ValuesIn(scopes), - Values("%u32vec4_null"))); +INSTANTIATE_TEST_SUITE_P(GroupNonUniformInverseBallot, GroupNonUniform, + Combine(Values("OpGroupNonUniformInverseBallot"), + Values("%bool"), ValuesIn(scopes), + Values("%u32vec4_null"), Values(""))); -INSTANTIATE_TEST_CASE_P(GroupNonUniformBallotBitExtract, GroupNonUniformScope, - Combine(Values("OpGroupNonUniformBallotBitExtract"), - Values("%bool"), ValuesIn(scopes), - Values("%u32vec4_null %u32_0"))); +INSTANTIATE_TEST_SUITE_P(GroupNonUniformBallotBitExtract, GroupNonUniform, + Combine(Values("OpGroupNonUniformBallotBitExtract"), + Values("%bool"), ValuesIn(scopes), + Values("%u32vec4_null %u32_0"), Values(""))); -INSTANTIATE_TEST_CASE_P(GroupNonUniformBallotBitCount, GroupNonUniformScope, - Combine(Values("OpGroupNonUniformBallotBitCount"), - Values("%u32"), ValuesIn(scopes), - Values("Reduce %u32vec4_null"))); +INSTANTIATE_TEST_SUITE_P(GroupNonUniformBallotBitCount, GroupNonUniform, + Combine(Values("OpGroupNonUniformBallotBitCount"), + Values("%u32"), ValuesIn(scopes), + Values("Reduce %u32vec4_null"), Values(""))); -INSTANTIATE_TEST_CASE_P(GroupNonUniformBallotFind, GroupNonUniformScope, - Combine(Values("OpGroupNonUniformBallotFindLSB", - "OpGroupNonUniformBallotFindMSB"), - Values("%u32"), ValuesIn(scopes), - Values("%u32vec4_null"))); +INSTANTIATE_TEST_SUITE_P(GroupNonUniformBallotFind, GroupNonUniform, + Combine(Values("OpGroupNonUniformBallotFindLSB", + "OpGroupNonUniformBallotFindMSB"), + Values("%u32"), ValuesIn(scopes), + Values("%u32vec4_null"), Values(""))); -INSTANTIATE_TEST_CASE_P(GroupNonUniformShuffle, GroupNonUniformScope, - Combine(Values("OpGroupNonUniformShuffle", - "OpGroupNonUniformShuffleXor", - "OpGroupNonUniformShuffleUp", - "OpGroupNonUniformShuffleDown"), - Values("%u32"), ValuesIn(scopes), - Values("%u32_0 %u32_0"))); +INSTANTIATE_TEST_SUITE_P(GroupNonUniformShuffle, GroupNonUniform, + Combine(Values("OpGroupNonUniformShuffle", + "OpGroupNonUniformShuffleXor", + "OpGroupNonUniformShuffleUp", + "OpGroupNonUniformShuffleDown"), + Values("%u32"), ValuesIn(scopes), + Values("%u32_0 %u32_0"), Values(""))); -INSTANTIATE_TEST_CASE_P( - GroupNonUniformIntegerArithmetic, GroupNonUniformScope, +INSTANTIATE_TEST_SUITE_P( + GroupNonUniformIntegerArithmetic, GroupNonUniform, Combine(Values("OpGroupNonUniformIAdd", "OpGroupNonUniformIMul", "OpGroupNonUniformSMin", "OpGroupNonUniformUMin", "OpGroupNonUniformSMax", "OpGroupNonUniformUMax", "OpGroupNonUniformBitwiseAnd", "OpGroupNonUniformBitwiseOr", "OpGroupNonUniformBitwiseXor"), - Values("%u32"), ValuesIn(scopes), Values("Reduce %u32_0"))); + Values("%u32"), ValuesIn(scopes), Values("Reduce %u32_0"), + Values(""))); -INSTANTIATE_TEST_CASE_P( - GroupNonUniformFloatArithmetic, GroupNonUniformScope, +INSTANTIATE_TEST_SUITE_P( + GroupNonUniformFloatArithmetic, GroupNonUniform, Combine(Values("OpGroupNonUniformFAdd", "OpGroupNonUniformFMul", "OpGroupNonUniformFMin", "OpGroupNonUniformFMax"), - Values("%float"), ValuesIn(scopes), Values("Reduce %float_0"))); + Values("%float"), ValuesIn(scopes), Values("Reduce %float_0"), + Values(""))); -INSTANTIATE_TEST_CASE_P(GroupNonUniformLogicalArithmetic, GroupNonUniformScope, - Combine(Values("OpGroupNonUniformLogicalAnd", - "OpGroupNonUniformLogicalOr", - "OpGroupNonUniformLogicalXor"), - Values("%bool"), ValuesIn(scopes), - Values("Reduce %true"))); +INSTANTIATE_TEST_SUITE_P(GroupNonUniformLogicalArithmetic, GroupNonUniform, + Combine(Values("OpGroupNonUniformLogicalAnd", + "OpGroupNonUniformLogicalOr", + "OpGroupNonUniformLogicalXor"), + Values("%bool"), ValuesIn(scopes), + Values("Reduce %true"), Values(""))); -INSTANTIATE_TEST_CASE_P(GroupNonUniformQuad, GroupNonUniformScope, - Combine(Values("OpGroupNonUniformQuadBroadcast", - "OpGroupNonUniformQuadSwap"), - Values("%u32"), ValuesIn(scopes), - Values("%u32_0 %u32_0"))); +INSTANTIATE_TEST_SUITE_P(GroupNonUniformQuad, GroupNonUniform, + Combine(Values("OpGroupNonUniformQuadBroadcast", + "OpGroupNonUniformQuadSwap"), + Values("%u32"), ValuesIn(scopes), + Values("%u32_0 %u32_0"), Values(""))); + +INSTANTIATE_TEST_SUITE_P(GroupNonUniformBallotBitCountScope, GroupNonUniform, + Combine(Values("OpGroupNonUniformBallotBitCount"), + Values("%u32"), ValuesIn(scopes), + Values("Reduce %u32vec4_null"), Values(""))); + +INSTANTIATE_TEST_SUITE_P( + GroupNonUniformBallotBitCountBadResultType, GroupNonUniform, + Combine( + Values("OpGroupNonUniformBallotBitCount"), Values("%float", "%int"), + Values(SpvScopeSubgroup), Values("Reduce %u32vec4_null"), + Values("Expected Result Type to be an unsigned integer type scalar."))); + +INSTANTIATE_TEST_SUITE_P(GroupNonUniformBallotBitCountBadValue, GroupNonUniform, + Combine(Values("OpGroupNonUniformBallotBitCount"), + Values("%u32"), Values(SpvScopeSubgroup), + Values("Reduce %u32vec3_null", "Reduce %u32_0", + "Reduce %float_0"), + Values("Expected Value to be a vector of four " + "components of integer type scalar"))); } // namespace } // namespace val diff --git a/third_party/spirv-tools/test/val/val_opencl_test.cpp b/third_party/spirv-tools/test/val/val_opencl_test.cpp new file mode 100644 index 0000000000..10641587fe --- /dev/null +++ b/third_party/spirv-tools/test/val/val_opencl_test.cpp @@ -0,0 +1,275 @@ +// Copyright (c) 2019 The Khronos Group Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Validation tests for OpenCL env specific checks + +#include + +#include "gmock/gmock.h" +#include "test/val/val_fixtures.h" + +namespace spvtools { +namespace val { +namespace { + +using testing::HasSubstr; + +using ValidateOpenCL = spvtest::ValidateBase; + +TEST_F(ValidateOpenCL, NonPhysicalAddressingModelBad) { + std::string spirv = R"( + OpCapability Kernel + OpMemoryModel Logical OpenCL +)"; + + CompileSuccessfully(spirv); + + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_OPENCL_1_2)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Addressing model must be Physical32 or Physical64 " + "in the OpenCL environment.\n OpMemoryModel Logical " + "OpenCL\n")); +} + +TEST_F(ValidateOpenCL, NonOpenCLMemoryModelBad) { + std::string spirv = R"( + OpCapability Kernel + OpCapability Addresses + OpCapability VulkanMemoryModelKHR + OpExtension "SPV_KHR_vulkan_memory_model" + OpMemoryModel Physical32 VulkanKHR +)"; + + CompileSuccessfully(spirv); + + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_OPENCL_1_2)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Memory model must be OpenCL in the OpenCL environment.")); +} + +TEST_F(ValidateOpenCL, NonVoidSampledTypeImageBad) { + std::string spirv = R"( + OpCapability Addresses + OpCapability Kernel + OpMemoryModel Physical32 OpenCL + %1 = OpTypeInt 32 0 + %2 = OpTypeImage %1 2D 0 0 0 0 Unknown ReadOnly +)"; + + CompileSuccessfully(spirv); + + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_OPENCL_1_2)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Sampled Type must be OpTypeVoid in the OpenCL environment." + "\n %2 = OpTypeImage %uint 2D 0 0 0 0 Unknown ReadOnly\n")); +} + +TEST_F(ValidateOpenCL, NonZeroMSImageBad) { + std::string spirv = R"( + OpCapability Addresses + OpCapability Kernel + OpMemoryModel Physical32 OpenCL + %1 = OpTypeVoid + %2 = OpTypeImage %1 2D 0 0 1 0 Unknown ReadOnly +)"; + + CompileSuccessfully(spirv); + + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_OPENCL_1_2)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("MS must be 0 in the OpenCL environement." + "\n %2 = OpTypeImage %void 2D 0 0 1 0 Unknown ReadOnly\n")); +} + +TEST_F(ValidateOpenCL, Non1D2DArrayedImageBad) { + std::string spirv = R"( + OpCapability Addresses + OpCapability Kernel + OpMemoryModel Physical32 OpenCL + %1 = OpTypeVoid + %2 = OpTypeImage %1 3D 0 1 0 0 Unknown ReadOnly +)"; + + CompileSuccessfully(spirv); + + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_OPENCL_1_2)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("In the OpenCL environment, Arrayed may only be set to 1 " + "when Dim is either 1D or 2D." + "\n %2 = OpTypeImage %void 3D 0 1 0 0 Unknown ReadOnly\n")); +} + +TEST_F(ValidateOpenCL, NonZeroSampledImageBad) { + std::string spirv = R"( + OpCapability Addresses + OpCapability Kernel + OpMemoryModel Physical32 OpenCL + %1 = OpTypeVoid + %2 = OpTypeImage %1 3D 0 0 0 1 Unknown ReadOnly +)"; + + CompileSuccessfully(spirv); + + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_OPENCL_1_2)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Sampled must be 0 in the OpenCL environment." + "\n %2 = OpTypeImage %void 3D 0 0 0 1 Unknown ReadOnly\n")); +} + +TEST_F(ValidateOpenCL, NoAccessQualifierImageBad) { + std::string spirv = R"( + OpCapability Addresses + OpCapability Kernel + OpMemoryModel Physical32 OpenCL + %1 = OpTypeVoid + %2 = OpTypeImage %1 3D 0 0 0 0 Unknown +)"; + + CompileSuccessfully(spirv); + + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_OPENCL_1_2)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("In the OpenCL environment, the optional " + "Access Qualifier must be present." + "\n %2 = OpTypeImage %void 3D 0 0 0 0 Unknown\n")); +} + +TEST_F(ValidateOpenCL, ImageWriteWithOptionalImageOperandsBad) { + std::string spirv = R"( + OpCapability Addresses + OpCapability Kernel + OpCapability ImageBasic + OpMemoryModel Physical64 OpenCL + OpEntryPoint Kernel %5 "test" + %uint = OpTypeInt 32 0 + %uint_7 = OpConstant %uint 7 + %uint_3 = OpConstant %uint 3 + %uint_1 = OpConstant %uint 1 + %uint_2 = OpConstant %uint 2 + %uint_4 = OpConstant %uint 4 + %void = OpTypeVoid + %3 = OpTypeImage %void 2D 0 0 0 0 Unknown WriteOnly + %4 = OpTypeFunction %void %3 + %v2uint = OpTypeVector %uint 2 + %v4uint = OpTypeVector %uint 4 + %12 = OpConstantComposite %v2uint %uint_7 %uint_3 + %17 = OpConstantComposite %v4uint %uint_1 %uint_2 %uint_3 %uint_4 + %5 = OpFunction %void None %4 + %img = OpFunctionParameter %3 + %entry = OpLabel + OpImageWrite %img %12 %17 ConstOffset %12 + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_OPENCL_1_2)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Optional Image Operands are not allowed in the " + "OpenCL environment." + "\n OpImageWrite %15 %13 %14 ConstOffset %13\n")); +} + +TEST_F(ValidateOpenCL, ImageReadWithConstOffsetBad) { + std::string spirv = R"( + OpCapability Addresses + OpCapability Kernel + OpCapability ImageBasic + OpMemoryModel Physical64 OpenCL + OpEntryPoint Kernel %5 "image_kernel" + OpName %img "img" + OpName %coord "coord" + OpName %call "call" + %uint = OpTypeInt 32 0 + %uint_7 = OpConstant %uint 7 + %uint_3 = OpConstant %uint 3 + %void = OpTypeVoid + %3 = OpTypeImage %void 2D 0 0 0 0 Unknown ReadOnly + %4 = OpTypeFunction %void %3 + %v4uint = OpTypeVector %uint 4 + %v2uint = OpTypeVector %uint 2 + %coord = OpConstantComposite %v2uint %uint_7 %uint_3 + %5 = OpFunction %void None %4 + %img = OpFunctionParameter %3 + %entry = OpLabel + %call = OpImageRead %v4uint %img %coord ConstOffset %coord + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_OPENCL_1_2)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "ConstOffset image operand not allowed in the OpenCL environment." + "\n %call = OpImageRead %v4uint %img %coord ConstOffset %coord\n")); +} + +TEST_F(ValidateOpenCL, ImageSampleExplicitLodWithConstOffsetBad) { + std::string spirv = R"( + OpCapability Addresses + OpCapability Kernel + OpCapability ImageBasic + OpCapability LiteralSampler + OpMemoryModel Physical64 OpenCL + OpEntryPoint Kernel %5 "image_kernel" + OpName %img "img" + OpName %coord "coord" + OpName %call "call" + %uint = OpTypeInt 32 0 + %uint_7 = OpConstant %uint 7 + %uint_3 = OpConstant %uint 3 + %void = OpTypeVoid + %3 = OpTypeImage %void 2D 0 0 0 0 Unknown ReadOnly + %4 = OpTypeFunction %void %3 + %8 = OpTypeSampler + %10 = OpTypeSampledImage %3 + %v4uint = OpTypeVector %uint 4 + %v2uint = OpTypeVector %uint 2 + %float = OpTypeFloat 32 + %9 = OpConstantSampler %8 None 0 Nearest + %coord = OpConstantComposite %v2uint %uint_7 %uint_3 + %float_0 = OpConstant %float 0 + %5 = OpFunction %void None %4 + %6 = OpFunctionParameter %3 + %entry = OpLabel + %img = OpSampledImage %10 %6 %9 + %call = OpImageSampleExplicitLod %v4uint %img %coord + Lod|ConstOffset %float_0 %coord + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_OPENCL_1_2)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "ConstOffset image operand not allowed in the OpenCL environment." + "\n %call = OpImageSampleExplicitLod %v4uint %img " + "%coord Lod|ConstOffset %float_0 %coord\n")); +} + +} // namespace +} // namespace val +} // namespace spvtools diff --git a/third_party/spirv-tools/test/val/val_primitives_test.cpp b/third_party/spirv-tools/test/val/val_primitives_test.cpp index f02ba80570..04d0a4f8a5 100644 --- a/third_party/spirv-tools/test/val/val_primitives_test.cpp +++ b/third_party/spirv-tools/test/val/val_primitives_test.cpp @@ -37,6 +37,10 @@ std::string GenerateShaderCode( ss << capabilities_and_extensions << "\n"; ss << "OpMemoryModel Logical GLSL450\n"; ss << "OpEntryPoint " << execution_model << " %main \"main\"\n"; + if (execution_model == "Geometry") { + ss << "OpExecutionMode %main InputPoints\n"; + ss << "OpExecutionMode %main OutputPoints\n"; + } ss << R"( %void = OpTypeVoid diff --git a/third_party/spirv-tools/test/val/val_small_type_uses_test.cpp b/third_party/spirv-tools/test/val/val_small_type_uses_test.cpp new file mode 100644 index 0000000000..b950af5b01 --- /dev/null +++ b/third_party/spirv-tools/test/val/val_small_type_uses_test.cpp @@ -0,0 +1,338 @@ +// Copyright (c) 2019 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. + +// Validation tests for 8- and 16-bit type uses. + +#include +#include + +#include "gmock/gmock.h" +#include "test/unit_spirv.h" +#include "test/val/val_code_generator.h" +#include "test/val/val_fixtures.h" + +namespace spvtools { +namespace val { +namespace { + +using ::testing::Eq; +using ::testing::HasSubstr; +using ::testing::Values; + +using ValidateSmallTypeUses = spvtest::ValidateBase; + +CodeGenerator GetSmallTypesGenerator() { + CodeGenerator generator; + generator.capabilities_ = R"( +OpCapability Shader +OpCapability StorageBuffer16BitAccess +OpCapability StorageBuffer8BitAccess +)"; + generator.extensions_ = R"( +OpExtension "SPV_KHR_16bit_storage" +OpExtension "SPV_KHR_8bit_storage" +OpExtension "SPV_KHR_storage_buffer_storage_class" +%ext = OpExtInstImport "GLSL.std.450" +)"; + generator.memory_model_ = "OpMemoryModel Logical GLSL450\n"; + std::string body = R"( +%short_gep = OpAccessChain %ptr_ssbo_short %var %int_0 %int_0 +%ld_short = OpLoad %short %short_gep +%short_to_int = OpSConvert %int %ld_short +%short_to_uint = OpUConvert %int %ld_short +%short_to_char = OpSConvert %char %ld_short +%short_to_uchar = OpSConvert %char %ld_short +%short2_gep = OpAccessChain %ptr_ssbo_short2 %var %int_0 +%ld_short2 = OpLoad %short2 %short2_gep +%short2_to_int2 = OpSConvert %int2 %ld_short2 +%short2_to_uint2 = OpUConvert %int2 %ld_short2 +%short2_to_char2 = OpSConvert %char2 %ld_short2 +%short2_to_uchar2 = OpSConvert %char2 %ld_short2 + +%char_gep = OpAccessChain %ptr_ssbo_char %var %int_2 %int_0 +%ld_char = OpLoad %char %char_gep +%char_to_int = OpSConvert %int %ld_char +%char_to_uint = OpUConvert %int %ld_char +%char_to_short = OpSConvert %short %ld_char +%char_to_ushort = OpSConvert %short %ld_char +%char2_gep = OpAccessChain %ptr_ssbo_char2 %var %int_2 +%ld_char2 = OpLoad %char2 %char2_gep +%char2_to_int2 = OpSConvert %int2 %ld_char2 +%char2_to_uint2 = OpUConvert %int2 %ld_char2 +%char2_to_short2 = OpSConvert %short2 %ld_char2 +%char2_to_ushort2 = OpSConvert %short2 %ld_char2 + +%half_gep = OpAccessChain %ptr_ssbo_half %var %int_1 %int_0 +%ld_half = OpLoad %half %half_gep +%half_to_float = OpFConvert %float %ld_half +%half2_gep = OpAccessChain %ptr_ssbo_half2 %var %int_1 +%ld_half2 = OpLoad %half2 %half2_gep +%half2_to_float2 = OpFConvert %float2 %ld_half2 + +%int_to_short = OpSConvert %short %int_0 +%int_to_ushort = OpUConvert %short %int_0 +%int_to_char = OpSConvert %char %int_0 +%int_to_uchar = OpUConvert %char %int_0 +%int2_to_short2 = OpSConvert %short2 %int2_0 +%int2_to_ushort2 = OpUConvert %short2 %int2_0 +%int2_to_char2 = OpSConvert %char2 %int2_0 +%int2_to_uchar2 = OpUConvert %char2 %int2_0 +%int_gep = OpAccessChain %ptr_ssbo_int %var %int_3 %int_0 +%int2_gep = OpAccessChain %ptr_ssbo_int2 %var %int_3 + +%float_to_half = OpFConvert %half %float_0 +%float2_to_half2 = OpFConvert %half2 %float2_0 +%float_gep = OpAccessChain %ptr_ssbo_float %var %int_4 %int_0 +%float2_gep = OpAccessChain %ptr_ssbo_float2 %var %int_4 +)"; + generator.entry_points_.push_back( + {"foo", "GLCompute", "OpExecutionMode %foo LocalSize 1 1 1", body, ""}); + generator.before_types_ = R"( +OpDecorate %block Block +OpMemberDecorate %block 0 Offset 0 +OpMemberDecorate %block 1 Offset 8 +OpMemberDecorate %block 2 Offset 16 +OpMemberDecorate %block 3 Offset 32 +OpMemberDecorate %block 4 Offset 64 +)"; + generator.types_ = R"( +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int2 = OpTypeVector %int 2 +%float = OpTypeFloat 32 +%float2 = OpTypeVector %float 2 +%bool = OpTypeBool +%bool2 = OpTypeVector %bool 2 +%char = OpTypeInt 8 0 +%char2 = OpTypeVector %char 2 +%ptr_ssbo_char = OpTypePointer StorageBuffer %char +%ptr_ssbo_char2 = OpTypePointer StorageBuffer %char2 +%short = OpTypeInt 16 0 +%short2 = OpTypeVector %short 2 +%ptr_ssbo_short = OpTypePointer StorageBuffer %short +%ptr_ssbo_short2 = OpTypePointer StorageBuffer %short2 +%half = OpTypeFloat 16 +%half2 = OpTypeVector %half 2 +%ptr_ssbo_half = OpTypePointer StorageBuffer %half +%ptr_ssbo_half2 = OpTypePointer StorageBuffer %half2 +%ptr_ssbo_int = OpTypePointer StorageBuffer %int +%ptr_ssbo_int2 = OpTypePointer StorageBuffer %int2 +%ptr_ssbo_float = OpTypePointer StorageBuffer %float +%ptr_ssbo_float2 = OpTypePointer StorageBuffer %float2 +%block = OpTypeStruct %short2 %half2 %char2 %int2 %float2 +%ptr_ssbo_block = OpTypePointer StorageBuffer %block +%func = OpTypeFunction %void +)"; + generator.after_types_ = R"( +%var = OpVariable %ptr_ssbo_block StorageBuffer +%int_0 = OpConstant %int 0 +%int_1 = OpConstant %int 1 +%int_2 = OpConstant %int 2 +%int_3 = OpConstant %int 3 +%int_4 = OpConstant %int 4 +%int2_0 = OpConstantComposite %int2 %int_0 %int_0 +%float_0 = OpConstant %float 0 +%float2_0 = OpConstantComposite %float2 %float_0 %float_0 + +%short_func_ty = OpTypeFunction %void %short +%char_func_ty = OpTypeFunction %void %char +%half_func_ty = OpTypeFunction %void %half +)"; + generator.add_at_the_end_ = R"( +%short_func = OpFunction %void None %short_func_ty +%short_param = OpFunctionParameter %short +%short_func_entry = OpLabel +OpReturn +OpFunctionEnd +%char_func = OpFunction %void None %char_func_ty +%char_param = OpFunctionParameter %char +%char_func_entry = OpLabel +OpReturn +OpFunctionEnd +%half_func = OpFunction %void None %half_func_ty +%half_param = OpFunctionParameter %half +%half_func_entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + return generator; +} + +TEST_F(ValidateSmallTypeUses, BadCharPhi) { + CodeGenerator generator = GetSmallTypesGenerator(); + generator.entry_points_[0].body += R"( +OpBranch %next_block +%next_block = OpLabel +%phi = OpPhi %char %ld_char %foo_entry +)"; + + CompileSuccessfully(generator.Build()); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Invalid use of 8- or 16-bit result")); +} + +TEST_F(ValidateSmallTypeUses, BadShortPhi) { + CodeGenerator generator = GetSmallTypesGenerator(); + generator.entry_points_[0].body += R"( +OpBranch %next_block +%next_block = OpLabel +%phi = OpPhi %short %ld_short %foo_entry +)"; + + CompileSuccessfully(generator.Build()); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Invalid use of 8- or 16-bit result")); +} + +TEST_F(ValidateSmallTypeUses, BadHalfPhi) { + CodeGenerator generator = GetSmallTypesGenerator(); + generator.entry_points_[0].body += R"( +OpBranch %next_block +%next_block = OpLabel +%phi = OpPhi %half %ld_half %foo_entry +)"; + + CompileSuccessfully(generator.Build()); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Invalid use of 8- or 16-bit result")); +} + +using ValidateGoodUses = spvtest::ValidateBase; + +TEST_P(ValidateGoodUses, Inst) { + const std::string inst = GetParam(); + CodeGenerator generator = GetSmallTypesGenerator(); + generator.entry_points_[0].body += inst + "\n"; + + CompileSuccessfully(generator.Build()); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +INSTANTIATE_TEST_SUITE_P( + SmallTypeUsesValid, ValidateGoodUses, + Values( + "%inst = OpIAdd %int %short_to_int %int_0", + "%inst = OpIAdd %int %short_to_uint %int_0", + "%inst = OpIAdd %int2 %short2_to_int2 %int2_0", + "%inst = OpIAdd %int2 %short2_to_uint2 %int2_0", + "%inst = OpIAdd %int %char_to_int %int_0", + "%inst = OpIAdd %int %char_to_uint %int_0", + "%inst = OpIAdd %int2 %char2_to_int2 %int2_0", + "%inst = OpIAdd %int2 %char2_to_uint2 %int2_0", + "%inst = OpUConvert %int %ld_short", + "%inst = OpSConvert %int %ld_short", + "%inst = OpUConvert %char %ld_short", + "%inst = OpSConvert %char %ld_short", + "%inst = OpUConvert %int %ld_char", "%inst = OpSConvert %int %ld_char", + "%inst = OpUConvert %short %ld_char", + "%inst = OpSConvert %short %ld_char", + "%inst = OpUConvert %int2 %ld_short2", + "%inst = OpSConvert %int2 %ld_short2", + "%inst = OpUConvert %char2 %ld_short2", + "%inst = OpSConvert %char2 %ld_short2", + "%inst = OpUConvert %int2 %ld_char2", + "%inst = OpSConvert %int2 %ld_char2", + "%inst = OpUConvert %short2 %ld_char2", + "%inst = OpSConvert %short2 %ld_char2", + "OpStore %short_gep %int_to_short", "OpStore %short_gep %int_to_ushort", + "OpStore %short_gep %char_to_short", + "OpStore %short_gep %char_to_ushort", + "OpStore %short2_gep %int2_to_short2", + "OpStore %short2_gep %int2_to_ushort2", + "OpStore %short2_gep %char2_to_short2", + "OpStore %short2_gep %char2_to_ushort2", + "OpStore %char_gep %int_to_char", "OpStore %char_gep %int_to_uchar", + "OpStore %char_gep %short_to_char", "OpStore %char_gep %short_to_uchar", + "OpStore %char2_gep %int2_to_char2", + "OpStore %char2_gep %int2_to_uchar2", + "OpStore %char2_gep %short2_to_char2", + "OpStore %char2_gep %short2_to_uchar2", + "OpStore %int_gep %short_to_int", "OpStore %int_gep %short_to_uint", + "OpStore %int_gep %char_to_int", "OpStore %int2_gep %char2_to_uint2", + "OpStore %int2_gep %short2_to_int2", + "OpStore %int2_gep %short2_to_uint2", + "OpStore %int2_gep %char2_to_int2", "OpStore %int2_gep %char2_to_uint2", + "%inst = OpFAdd %float %half_to_float %float_0", + "%inst = OpFAdd %float2 %half2_to_float2 %float2_0", + "%inst = OpFConvert %float %ld_half", + "%inst = OpFConvert %float2 %ld_half2", + "OpStore %half_gep %float_to_half", "OpStore %half_gep %ld_half", + "OpStore %half2_gep %float2_to_half2", "OpStore %half2_gep %ld_half2", + "OpStore %float_gep %half_to_float", + "OpStore %float2_gep %half2_to_float2")); + +using ValidateBadUses = spvtest::ValidateBase; + +TEST_P(ValidateBadUses, Inst) { + const std::string inst = GetParam(); + CodeGenerator generator = GetSmallTypesGenerator(); + generator.entry_points_[0].body += inst + "\n"; + + CompileSuccessfully(generator.Build()); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Invalid use of 8- or 16-bit result")); +} + +// A smattering of unacceptable use cases. Far too vast to cover exhaustively. +INSTANTIATE_TEST_SUITE_P( + SmallTypeUsesInvalid, ValidateBadUses, + Values("%inst = OpIAdd %short %ld_short %ld_short", + "%inst = OpIAdd %short %char_to_short %char_to_short", + "%inst = OpIAdd %short %char_to_ushort %char_to_ushort", + "%inst = OpIAdd %short %int_to_short %int_to_short", + "%inst = OpIAdd %short %int_to_ushort %int_to_ushort", + "%inst = OpIAdd %short2 %ld_short2 %ld_short2", + "%inst = OpIAdd %short2 %char2_to_short2 %char2_to_short2", + "%inst = OpIAdd %short2 %char2_to_ushort2 %char2_to_ushort2", + "%inst = OpIAdd %short2 %int2_to_short2 %int2_to_short2", + "%inst = OpIAdd %short2 %int2_to_ushort2 %int2_to_ushort2", + "%inst = OpIEqual %bool %ld_short %ld_short", + "%inst = OpIEqual %bool %char_to_short %char_to_short", + "%inst = OpIEqual %bool %char_to_ushort %char_to_ushort", + "%inst = OpIEqual %bool %int_to_short %int_to_short", + "%inst = OpIEqual %bool %int_to_ushort %int_to_ushort", + "%inst = OpIEqual %bool2 %ld_short2 %ld_short2", + "%inst = OpIEqual %bool2 %char2_to_short2 %char2_to_short2", + "%inst = OpIEqual %bool2 %char2_to_ushort2 %char2_to_ushort2", + "%inst = OpIEqual %bool2 %int2_to_short2 %int2_to_short2", + "%inst = OpIEqual %bool2 %int2_to_ushort2 %int2_to_ushort2", + "%inst = OpFAdd %half %ld_half %ld_half", + "%inst = OpFAdd %half %float_to_half %float_to_half", + "%inst = OpFAdd %half2 %ld_half2 %ld_half2", + "%inst = OpFAdd %half2 %float2_to_half2 %float2_to_half2", + "%inst = OpFOrdGreaterThan %bool %ld_half %ld_half", + "%inst = OpFOrdGreaterThan %bool %float_to_half %float_to_half", + "%inst = OpFOrdGreaterThan %bool2 %ld_half2 %ld_half2", + "%inst = OpFOrdGreaterThan %bool2 %float2_to_half2 %float2_to_half2", + "%inst = OpFunctionCall %void %short_func %ld_short", + "%inst = OpFunctionCall %void %short_func %char_to_short", + "%inst = OpFunctionCall %void %short_func %char_to_ushort", + "%inst = OpFunctionCall %void %short_func %int_to_short", + "%inst = OpFunctionCall %void %short_func %int_to_ushort", + "%inst = OpFunctionCall %void %char_func %ld_char", + "%inst = OpFunctionCall %void %char_func %short_to_char", + "%inst = OpFunctionCall %void %char_func %short_to_uchar", + "%inst = OpFunctionCall %void %char_func %int_to_char", + "%inst = OpFunctionCall %void %char_func %int_to_uchar", + "%inst = OpFunctionCall %void %half_func %ld_half", + "%inst = OpFunctionCall %void %half_func %float_to_half")); + +} // namespace +} // namespace val +} // namespace spvtools diff --git a/third_party/spirv-tools/test/val/val_ssa_test.cpp b/third_party/spirv-tools/test/val/val_ssa_test.cpp index 25944f5189..035c710a2d 100644 --- a/third_party/spirv-tools/test/val/val_ssa_test.cpp +++ b/third_party/spirv-tools/test/val/val_ssa_test.cpp @@ -118,7 +118,7 @@ TEST_F(ValidateSSA, DominateUsageWithinBlockBad) { CompileSuccessfully(str); ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - MatchesRegex("ID .\\[bad\\] has not been defined\n" + MatchesRegex("ID .\\[%bad\\] has not been defined\n" " %8 = OpIAdd %uint %uint_1 %bad\n")); } @@ -141,7 +141,7 @@ TEST_F(ValidateSSA, DominateUsageSameInstructionBad) { CompileSuccessfully(str); ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - MatchesRegex("ID .\\[sum\\] has not been defined\n" + MatchesRegex("ID .\\[%sum\\] has not been defined\n" " %sum = OpIAdd %uint %uint_1 %sum\n")); } @@ -202,7 +202,9 @@ TEST_F(ValidateSSA, ForwardMemberNameMissingTargetBad) { )"; CompileSuccessfully(str); ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), HasSubstr("size")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("The following forward referenced IDs have not been " + "defined:\n2[%2]")); } TEST_F(ValidateSSA, ForwardDecorateGood) { @@ -821,7 +823,7 @@ std::pair cases[] = { {"OpGetKernelWorkGroupSize", kNoNDrange}, {"OpGetKernelPreferredWorkGroupSizeMultiple", kNoNDrange}}; -INSTANTIATE_TEST_CASE_P(KernelArgs, ValidateSSA, ::testing::ValuesIn(cases), ); +INSTANTIATE_TEST_SUITE_P(KernelArgs, ValidateSSA, ::testing::ValuesIn(cases)); static const std::string return_instructions = R"( OpReturn @@ -1124,17 +1126,18 @@ TEST_F(ValidateSSA, IdDoesNotDominateItsUseBad) { ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), - MatchesRegex("ID .\\[eleven\\] defined in block .\\[true_block\\] does " - "not dominate its use in block .\\[false_block\\]\n" + MatchesRegex("ID .\\[%eleven\\] defined in block .\\[%true_block\\] " + "does not dominate its use in block .\\[%false_block\\]\n" " %false_block = OpLabel\n")); } TEST_F(ValidateSSA, PhiUseDoesntDominateDefinitionGood) { std::string str = kHeader + kBasicTypes + R"( +%funcintptrt = OpTypePointer Function %uintt %func = OpFunction %voidt None %vfunct %entry = OpLabel -%var_one = OpVariable %intptrt Function %one +%var_one = OpVariable %funcintptrt Function %one %one_val = OpLoad %uintt %var_one OpBranch %loop %loop = OpLabel @@ -1184,7 +1187,7 @@ TEST_F(ValidateSSA, CompileSuccessfully(str); ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - MatchesRegex("ID .\\[inew\\] has not been defined\n" + MatchesRegex("ID .\\[%inew\\] has not been defined\n" " %19 = OpIAdd %uint %inew %uint_1\n")); } @@ -1267,8 +1270,8 @@ TEST_F(ValidateSSA, PhiVariableDefNotDominatedByParentBlockBad) { ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), - MatchesRegex("In OpPhi instruction .\\[phi\\], ID .\\[true_copy\\] " - "definition does not dominate its parent .\\[if_false\\]\n" + MatchesRegex("In OpPhi instruction .\\[%phi\\], ID .\\[%true_copy\\] " + "definition does not dominate its parent .\\[%if_false\\]\n" " %phi = OpPhi %bool %true_copy %if_false %false_copy " "%if_true\n")); } @@ -1395,8 +1398,8 @@ TEST_F(ValidateSSA, UseFunctionParameterFromOtherFunctionBad) { ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), - MatchesRegex("ID .\\[first\\] used in function .\\[func2\\] is used " - "outside of it's defining function .\\[func\\]\n" + MatchesRegex("ID .\\[%first\\] used in function .\\[%func2\\] is used " + "outside of it's defining function .\\[%func\\]\n" " %func = OpFunction %void None %14\n")); } @@ -1412,7 +1415,8 @@ TEST_F(ValidateSSA, TypeForwardPointerForwardReference) { OpName %intptrt "intptrt" OpTypeForwardPointer %intptrt UniformConstant %uint = OpTypeInt 32 0 - %intptrt = OpTypePointer UniformConstant %uint + %struct = OpTypeStruct %uint + %intptrt = OpTypePointer UniformConstant %struct )"; CompileSuccessfully(str); diff --git a/third_party/spirv-tools/test/val/val_state_test.cpp b/third_party/spirv-tools/test/val/val_state_test.cpp index 699b224ad0..18a4ef99e9 100644 --- a/third_party/spirv-tools/test/val/val_state_test.cpp +++ b/third_party/spirv-tools/test/val/val_state_test.cpp @@ -41,7 +41,7 @@ class ValidationStateTest : public testing::Test { ValidationStateTest() : context_(spvContextCreate(SPV_ENV_UNIVERSAL_1_0)), options_(spvValidatorOptionsCreate()), - state_(context_, options_, kFakeBinary, 0) {} + state_(context_, options_, kFakeBinary, 0, 1) {} ~ValidationStateTest() { spvContextDestroy(context_); diff --git a/third_party/spirv-tools/test/val/val_storage_test.cpp b/third_party/spirv-tools/test/val/val_storage_test.cpp index 46b3ddcbb5..fe37a93c6d 100644 --- a/third_party/spirv-tools/test/val/val_storage_test.cpp +++ b/third_party/spirv-tools/test/val/val_storage_test.cpp @@ -26,7 +26,10 @@ namespace val { namespace { using ::testing::HasSubstr; +using ::testing::Values; using ValidateStorage = spvtest::ValidateBase; +using ValidateStorageClass = + spvtest::ValidateBase>; TEST_F(ValidateStorage, FunctionStorageInsideFunction) { char str[] = R"( @@ -73,29 +76,38 @@ TEST_F(ValidateStorage, FunctionStorageOutsideFunction) { TEST_F(ValidateStorage, OtherStorageOutsideFunction) { char str[] = R"( - OpCapability Shader - OpCapability Kernel - OpCapability AtomicStorage - OpCapability Linkage - OpMemoryModel Logical GLSL450 -%intt = OpTypeInt 32 0 -%voidt = OpTypeVoid -%vfunct = OpTypeFunction %voidt -%ptrt = OpTypePointer Function %intt -%unicon = OpVariable %ptrt UniformConstant -%input = OpVariable %ptrt Input -%unif = OpVariable %ptrt Uniform -%output = OpVariable %ptrt Output -%wgroup = OpVariable %ptrt Workgroup -%xwgrp = OpVariable %ptrt CrossWorkgroup -%priv = OpVariable %ptrt Private -%pushco = OpVariable %ptrt PushConstant -%atomct = OpVariable %ptrt AtomicCounter -%image = OpVariable %ptrt Image -%func = OpFunction %voidt None %vfunct -%funcl = OpLabel - OpReturn - OpFunctionEnd + OpCapability Shader + OpCapability Kernel + OpCapability AtomicStorage + OpCapability Linkage + OpMemoryModel Logical GLSL450 +%intt = OpTypeInt 32 0 +%voidt = OpTypeVoid +%vfunct = OpTypeFunction %voidt +%uniconptrt = OpTypePointer UniformConstant %intt +%unicon = OpVariable %uniconptrt UniformConstant +%inputptrt = OpTypePointer Input %intt +%input = OpVariable %inputptrt Input +%unifptrt = OpTypePointer Uniform %intt +%unif = OpVariable %unifptrt Uniform +%outputptrt = OpTypePointer Output %intt +%output = OpVariable %outputptrt Output +%wgroupptrt = OpTypePointer Workgroup %intt +%wgroup = OpVariable %wgroupptrt Workgroup +%xwgrpptrt = OpTypePointer CrossWorkgroup %intt +%xwgrp = OpVariable %xwgrpptrt CrossWorkgroup +%privptrt = OpTypePointer Private %intt +%priv = OpVariable %privptrt Private +%pushcoptrt = OpTypePointer PushConstant %intt +%pushco = OpVariable %pushcoptrt PushConstant +%atomcptrt = OpTypePointer AtomicCounter %intt +%atomct = OpVariable %atomcptrt AtomicCounter +%imageptrt = OpTypePointer Image %intt +%image = OpVariable %imageptrt Image +%func = OpFunction %voidt None %vfunct +%funcl = OpLabel + OpReturn + OpFunctionEnd )"; CompileSuccessfully(str); @@ -128,7 +140,7 @@ TEST_P(ValidateStorage, OtherStorageInsideFunction) { "Variables must have a function[7] storage class inside of a function")); } -INSTANTIATE_TEST_CASE_P(MatrixOp, ValidateStorage, +INSTANTIATE_TEST_SUITE_P(MatrixOp, ValidateStorage, ::testing::Values( "Input", "Uniform", @@ -138,13 +150,14 @@ INSTANTIATE_TEST_CASE_P(MatrixOp, ValidateStorage, "Private", "PushConstant", "AtomicCounter", - "Image"),); + "Image")); // clang-format on TEST_F(ValidateStorage, GenericVariableOutsideFunction) { const auto str = R"( OpCapability Kernel OpCapability Linkage + OpCapability GenericPointer OpMemoryModel Logical OpenCL %intt = OpTypeInt 32 0 %ptrt = OpTypePointer Function %intt @@ -160,6 +173,7 @@ TEST_F(ValidateStorage, GenericVariableInsideFunction) { const auto str = R"( OpCapability Shader OpCapability Linkage + OpCapability GenericPointer OpMemoryModel Logical GLSL450 %intt = OpTypeInt 32 1 %voidt = OpTypeVoid @@ -172,11 +186,134 @@ TEST_F(ValidateStorage, GenericVariableInsideFunction) { OpFunctionEnd )"; CompileSuccessfully(str); - ASSERT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions()); + EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("OpVariable storage class cannot be Generic")); } +TEST_F(ValidateStorage, RelaxedLogicalPointerFunctionParam) { + const auto str = R"( + OpCapability Shader + OpCapability Linkage + OpMemoryModel Logical GLSL450 +%intt = OpTypeInt 32 1 +%voidt = OpTypeVoid +%ptrt = OpTypePointer Function %intt +%vfunct = OpTypeFunction %voidt +%vifunct = OpTypeFunction %voidt %ptrt +%wgroupptrt = OpTypePointer Workgroup %intt +%wgroup = OpVariable %wgroupptrt Workgroup +%main = OpFunction %voidt None %vfunct +%mainl = OpLabel +%ret = OpFunctionCall %voidt %func %wgroup + OpReturn + OpFunctionEnd +%func = OpFunction %voidt None %vifunct +%arg = OpFunctionParameter %ptrt +%funcl = OpLabel + OpReturn + OpFunctionEnd +)"; + CompileSuccessfully(str); + getValidatorOptions()->before_hlsl_legalization = true; + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateStorage, RelaxedLogicalPointerFunctionParamBad) { + const auto str = R"( + OpCapability Shader + OpCapability Linkage + OpMemoryModel Logical GLSL450 +%floatt = OpTypeFloat 32 +%intt = OpTypeInt 32 1 +%voidt = OpTypeVoid +%ptrt = OpTypePointer Function %intt +%vfunct = OpTypeFunction %voidt +%vifunct = OpTypeFunction %voidt %ptrt +%wgroupptrt = OpTypePointer Workgroup %floatt +%wgroup = OpVariable %wgroupptrt Workgroup +%main = OpFunction %voidt None %vfunct +%mainl = OpLabel +%ret = OpFunctionCall %voidt %func %wgroup + OpReturn + OpFunctionEnd +%func = OpFunction %voidt None %vifunct +%arg = OpFunctionParameter %ptrt +%funcl = OpLabel + OpReturn + OpFunctionEnd +)"; + CompileSuccessfully(str); + getValidatorOptions()->relax_logical_pointer = true; + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("OpFunctionCall Argument '")); +} + +std::string GetVarDeclStr(const std::string& storage_class) { + if (storage_class != "Output" && storage_class != "Private" && + storage_class != "Function") { + return "%var = OpVariable %ptrt " + storage_class + "\n"; + } else { + return "%var = OpVariable %ptrt " + storage_class + " %null\n"; + } +} + +TEST_P(ValidateStorageClass, WebGPU) { + std::string storage_class = std::get<0>(GetParam()); + bool is_local = std::get<1>(GetParam()); + bool is_valid = std::get<2>(GetParam()); + std::string error = std::get<3>(GetParam()); + + std::string str = R"( + OpCapability Shader + OpCapability VulkanMemoryModelKHR + OpExtension "SPV_KHR_vulkan_memory_model" + OpMemoryModel Logical VulkanKHR + OpEntryPoint Fragment %func "func" + OpExecutionMode %func OriginUpperLeft +%intt = OpTypeInt 32 1 +%voidt = OpTypeVoid +%vfunct = OpTypeFunction %voidt +%null = OpConstantNull %intt +)"; + str += "%ptrt = OpTypePointer " + storage_class + " %intt\n"; + if (!is_local) str += GetVarDeclStr(storage_class); + str += R"( +%func = OpFunction %voidt None %vfunct +%funcl = OpLabel +)"; + if (is_local) str += GetVarDeclStr(storage_class); + str += R"( +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(str, SPV_ENV_WEBGPU_0); + if (is_valid) { + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); + } else { + ASSERT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT(getDiagnosticString(), HasSubstr(error)); + } +} + +INSTANTIATE_TEST_SUITE_P( + StorageClass, ValidateStorageClass, + Values(std::make_tuple("UniformConstant", false, true, ""), + std::make_tuple("Uniform", false, true, ""), + std::make_tuple("StorageBuffer", false, true, ""), + std::make_tuple("Input", false, true, ""), + std::make_tuple("Output", false, true, ""), + std::make_tuple("Image", false, true, ""), + std::make_tuple("Workgroup", false, true, ""), + std::make_tuple("Private", false, true, ""), + std::make_tuple("Function", true, true, ""), + std::make_tuple("CrossWorkgroup", false, false, + "Invalid storage class for target environment"), + std::make_tuple("PushConstant", false, false, + "Invalid storage class for target environment"))); + } // namespace } // namespace val } // namespace spvtools diff --git a/third_party/spirv-tools/test/val/val_type_unique_test.cpp b/third_party/spirv-tools/test/val/val_type_unique_test.cpp index 67ceaddb86..45a4d50480 100644 --- a/third_party/spirv-tools/test/val/val_type_unique_test.cpp +++ b/third_party/spirv-tools/test/val/val_type_unique_test.cpp @@ -210,9 +210,11 @@ OpMemoryModel Physical32 OpenCL OpTypeForwardPointer %ptr Generic OpTypeForwardPointer %ptr2 Generic %intt = OpTypeInt 32 0 +%int_struct = OpTypeStruct %intt %floatt = OpTypeFloat 32 -%ptr = OpTypePointer Generic %intt -%ptr2 = OpTypePointer Generic %floatt +%ptr = OpTypePointer Generic %int_struct +%float_struct = OpTypeStruct %floatt +%ptr2 = OpTypePointer Generic %float_struct )"; CompileSuccessfully(str.c_str()); ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); diff --git a/third_party/spirv-tools/test/val/val_validation_state_test.cpp b/third_party/spirv-tools/test/val/val_validation_state_test.cpp index 68504c5288..458157902e 100644 --- a/third_party/spirv-tools/test/val/val_validation_state_test.cpp +++ b/third_party/spirv-tools/test/val/val_validation_state_test.cpp @@ -29,11 +29,17 @@ using ::testing::HasSubstr; using ValidationStateTest = spvtest::ValidateBase; -const char header[] = +const char kHeader[] = " OpCapability Shader" " OpCapability Linkage" " OpMemoryModel Logical GLSL450 "; +const char kVulkanMemoryHeader[] = + " OpCapability Shader" + " OpCapability VulkanMemoryModelKHR" + " OpExtension \"SPV_KHR_vulkan_memory_model\"" + " OpMemoryModel Logical VulkanKHR "; + const char kVoidFVoid[] = " %void = OpTypeVoid" " %void_f = OpTypeFunction %void" @@ -42,9 +48,81 @@ const char kVoidFVoid[] = " OpReturn" " OpFunctionEnd "; +// k*RecursiveBody examples originally from test/opt/function_test.cpp +const char* kNonRecursiveBody = R"( +OpEntryPoint Fragment %1 "main" +OpExecutionMode %1 OriginUpperLeft +%void = OpTypeVoid +%4 = OpTypeFunction %void +%float = OpTypeFloat 32 +%_struct_6 = OpTypeStruct %float %float +%null = OpConstantNull %_struct_6 +%7 = OpTypeFunction %_struct_6 +%12 = OpFunction %_struct_6 None %7 +%13 = OpLabel +OpReturnValue %null +OpFunctionEnd +%9 = OpFunction %_struct_6 None %7 +%10 = OpLabel +%11 = OpFunctionCall %_struct_6 %12 +OpReturnValue %null +OpFunctionEnd +%1 = OpFunction %void Pure|Const %4 +%8 = OpLabel +%2 = OpFunctionCall %_struct_6 %9 +OpKill +OpFunctionEnd +)"; + +const char* kDirectlyRecursiveBody = R"( +OpEntryPoint Fragment %1 "main" +OpExecutionMode %1 OriginUpperLeft +%void = OpTypeVoid +%4 = OpTypeFunction %void +%float = OpTypeFloat 32 +%_struct_6 = OpTypeStruct %float %float +%7 = OpTypeFunction %_struct_6 +%9 = OpFunction %_struct_6 None %7 +%10 = OpLabel +%11 = OpFunctionCall %_struct_6 %9 +OpKill +OpFunctionEnd +%1 = OpFunction %void Pure|Const %4 +%8 = OpLabel +%2 = OpFunctionCall %_struct_6 %9 +OpReturn +OpFunctionEnd +)"; + +const char* kIndirectlyRecursiveBody = R"( +OpEntryPoint Fragment %1 "main" +OpExecutionMode %1 OriginUpperLeft +%void = OpTypeVoid +%4 = OpTypeFunction %void +%float = OpTypeFloat 32 +%_struct_6 = OpTypeStruct %float %float +%null = OpConstantNull %_struct_6 +%7 = OpTypeFunction %_struct_6 +%9 = OpFunction %_struct_6 None %7 +%10 = OpLabel +%11 = OpFunctionCall %_struct_6 %12 +OpReturnValue %null +OpFunctionEnd +%12 = OpFunction %_struct_6 None %7 +%13 = OpLabel +%14 = OpFunctionCall %_struct_6 %9 +OpReturnValue %null +OpFunctionEnd +%1 = OpFunction %void Pure|Const %4 +%8 = OpLabel +%2 = OpFunctionCall %_struct_6 %9 +OpKill +OpFunctionEnd +)"; + // Tests that the instruction count in ValidationState is correct. TEST_F(ValidationStateTest, CheckNumInstructions) { - std::string spirv = std::string(header) + "%int = OpTypeInt 32 0"; + std::string spirv = std::string(kHeader) + "%int = OpTypeInt 32 0"; CompileSuccessfully(spirv); EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState()); EXPECT_EQ(size_t(4), vstate_->ordered_instructions().size()); @@ -52,7 +130,7 @@ TEST_F(ValidationStateTest, CheckNumInstructions) { // Tests that the number of global variables in ValidationState is correct. TEST_F(ValidationStateTest, CheckNumGlobalVars) { - std::string spirv = std::string(header) + R"( + std::string spirv = std::string(kHeader) + R"( %int = OpTypeInt 32 0 %_ptr_int = OpTypePointer Input %int %var_1 = OpVariable %_ptr_int Input @@ -65,7 +143,7 @@ TEST_F(ValidationStateTest, CheckNumGlobalVars) { // Tests that the number of local variables in ValidationState is correct. TEST_F(ValidationStateTest, CheckNumLocalVars) { - std::string spirv = std::string(header) + R"( + std::string spirv = std::string(kHeader) + R"( %int = OpTypeInt 32 0 %_ptr_int = OpTypePointer Function %int %voidt = OpTypeVoid @@ -85,7 +163,7 @@ TEST_F(ValidationStateTest, CheckNumLocalVars) { // Tests that the "id bound" in ValidationState is correct. TEST_F(ValidationStateTest, CheckIdBound) { - std::string spirv = std::string(header) + R"( + std::string spirv = std::string(kHeader) + R"( %int = OpTypeInt 32 0 %voidt = OpTypeVoid )"; @@ -96,7 +174,7 @@ TEST_F(ValidationStateTest, CheckIdBound) { // Tests that the entry_points in ValidationState is correct. TEST_F(ValidationStateTest, CheckEntryPoints) { - std::string spirv = std::string(header) + + std::string spirv = std::string(kHeader) + " OpEntryPoint Vertex %func \"shader\"" + std::string(kVoidFVoid); CompileSuccessfully(spirv); @@ -154,6 +232,130 @@ TEST_F(ValidationStateTest, CheckAccessChainIndexesLimitOption) { EXPECT_EQ(100u, options_->universal_limits_.max_access_chain_indexes); } +TEST_F(ValidationStateTest, CheckNonRecursiveBodyGood) { + std::string spirv = std::string(kHeader) + kNonRecursiveBody; + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState()); +} + +TEST_F(ValidationStateTest, CheckVulkanNonRecursiveBodyGood) { + std::string spirv = std::string(kVulkanMemoryHeader) + kNonRecursiveBody; + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_SUCCESS, + ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1)); +} + +TEST_F(ValidationStateTest, CheckWebGPUNonRecursiveBodyGood) { + std::string spirv = std::string(kVulkanMemoryHeader) + kNonRecursiveBody; + CompileSuccessfully(spirv, SPV_ENV_WEBGPU_0); + EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState(SPV_ENV_WEBGPU_0)); +} + +TEST_F(ValidationStateTest, CheckDirectlyRecursiveBodyGood) { + std::string spirv = std::string(kHeader) + kDirectlyRecursiveBody; + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState()); +} + +TEST_F(ValidationStateTest, CheckVulkanDirectlyRecursiveBodyBad) { + std::string spirv = std::string(kVulkanMemoryHeader) + kDirectlyRecursiveBody; + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_BINARY, + ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Entry points may not have a call graph with cycles.\n " + " %1 = OpFunction %void Pure|Const %3\n")); +} + +TEST_F(ValidationStateTest, CheckWebGPUDirectlyRecursiveBodyBad) { + std::string spirv = std::string(kVulkanMemoryHeader) + kDirectlyRecursiveBody; + CompileSuccessfully(spirv, SPV_ENV_WEBGPU_0); + EXPECT_EQ(SPV_ERROR_INVALID_BINARY, + ValidateAndRetrieveValidationState(SPV_ENV_WEBGPU_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Entry points may not have a call graph with cycles.\n " + " %1 = OpFunction %void Pure|Const %3\n")); +} + +TEST_F(ValidationStateTest, CheckIndirectlyRecursiveBodyGood) { + std::string spirv = std::string(kHeader) + kIndirectlyRecursiveBody; + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState()); +} + +TEST_F(ValidationStateTest, CheckVulkanIndirectlyRecursiveBodyBad) { + std::string spirv = + std::string(kVulkanMemoryHeader) + kIndirectlyRecursiveBody; + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_BINARY, + ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Entry points may not have a call graph with cycles.\n " + " %1 = OpFunction %void Pure|Const %3\n")); +} + +// Indirectly recursive functions are caught by the function definition layout +// rules, because they cause a situation where there are 2 functions that have +// to be before each other, and layout is checked earlier. +TEST_F(ValidationStateTest, CheckWebGPUIndirectlyRecursiveBodyBad) { + std::string spirv = + std::string(kVulkanMemoryHeader) + kIndirectlyRecursiveBody; + CompileSuccessfully(spirv, SPV_ENV_WEBGPU_0); + EXPECT_EQ(SPV_ERROR_INVALID_LAYOUT, + ValidateAndRetrieveValidationState(SPV_ENV_WEBGPU_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("For WebGPU, functions need to be defined before being " + "called.\n %10 = OpFunctionCall %_struct_5 %11\n")); +} + +TEST_F(ValidationStateTest, + CheckWebGPUDuplicateEntryNamesDifferentFunctionsBad) { + std::string spirv = std::string(kVulkanMemoryHeader) + R"( +OpEntryPoint Fragment %func_1 "main" +OpEntryPoint Vertex %func_2 "main" +OpExecutionMode %func_1 OriginUpperLeft +%void = OpTypeVoid +%void_f = OpTypeFunction %void +%func_1 = OpFunction %void None %void_f +%label_1 = OpLabel + OpReturn + OpFunctionEnd +%func_2 = OpFunction %void None %void_f +%label_2 = OpLabel + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_WEBGPU_0); + EXPECT_EQ(SPV_ERROR_INVALID_BINARY, + ValidateAndRetrieveValidationState(SPV_ENV_WEBGPU_0)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Entry point name \"main\" is not unique, which is not allow " + "in WebGPU env.\n %1 = OpFunction %void None %4\n")); +} + +TEST_F(ValidationStateTest, CheckWebGPUDuplicateEntryNamesSameFunctionBad) { + std::string spirv = std::string(kVulkanMemoryHeader) + R"( +OpEntryPoint GLCompute %func_1 "main" +OpEntryPoint Vertex %func_1 "main" +%void = OpTypeVoid +%void_f = OpTypeFunction %void +%func_1 = OpFunction %void None %void_f +%label_1 = OpLabel + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_WEBGPU_0); + EXPECT_EQ(SPV_ERROR_INVALID_BINARY, + ValidateAndRetrieveValidationState(SPV_ENV_WEBGPU_0)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Entry point name \"main\" is not unique, which is not allow " + "in WebGPU env.\n %1 = OpFunction %void None %3\n")); +} + } // namespace } // namespace val } // namespace spvtools diff --git a/third_party/spirv-tools/test/val/val_version_test.cpp b/third_party/spirv-tools/test/val/val_version_test.cpp index fa252ac869..2b9542a126 100644 --- a/third_party/spirv-tools/test/val/val_version_test.cpp +++ b/third_party/spirv-tools/test/val/val_version_test.cpp @@ -31,6 +31,22 @@ const std::string vulkan_spirv = R"( OpCapability Shader OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +%void = OpTypeVoid +%functy = OpTypeFunction %void +%func = OpFunction %void None %functy +%1 = OpLabel +OpReturn +OpFunctionEnd +)"; + +const std::string webgpu_spirv = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft %void = OpTypeVoid %functy = OpTypeFunction %void %func = OpFunction %void None %functy @@ -40,9 +56,10 @@ OpFunctionEnd )"; const std::string opencl_spirv = R"( +OpCapability Addresses OpCapability Kernel OpCapability Linkage -OpMemoryModel Logical OpenCL +OpMemoryModel Physical32 OpenCL )"; std::string version(spv_target_env env) { @@ -70,6 +87,9 @@ std::string version(spv_target_env env) { case SPV_ENV_VULKAN_1_1: case SPV_ENV_WEBGPU_0: return "1.3"; + case SPV_ENV_UNIVERSAL_1_4: + case SPV_ENV_VULKAN_1_1_SPIRV_1_4: + return "1.4"; default: return "0"; } @@ -92,7 +112,7 @@ TEST_P(ValidateVersion, version) { } // clang-format off -INSTANTIATE_TEST_CASE_P(Universal, ValidateVersion, +INSTANTIATE_TEST_SUITE_P(Universal, ValidateVersion, ::testing::Values( // Binary version, Target environment std::make_tuple(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_0, vulkan_spirv, true), @@ -106,7 +126,7 @@ INSTANTIATE_TEST_CASE_P(Universal, ValidateVersion, std::make_tuple(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_OPENGL_4_2, vulkan_spirv, true), std::make_tuple(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_OPENGL_4_3, vulkan_spirv, true), std::make_tuple(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_OPENGL_4_5, vulkan_spirv, true), - std::make_tuple(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_WEBGPU_0, vulkan_spirv, true), + std::make_tuple(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_WEBGPU_0, webgpu_spirv, true), std::make_tuple(SPV_ENV_UNIVERSAL_1_1, SPV_ENV_UNIVERSAL_1_0, vulkan_spirv, false), std::make_tuple(SPV_ENV_UNIVERSAL_1_1, SPV_ENV_UNIVERSAL_1_1, vulkan_spirv, true), @@ -119,7 +139,7 @@ INSTANTIATE_TEST_CASE_P(Universal, ValidateVersion, std::make_tuple(SPV_ENV_UNIVERSAL_1_1, SPV_ENV_OPENGL_4_2, vulkan_spirv, false), std::make_tuple(SPV_ENV_UNIVERSAL_1_1, SPV_ENV_OPENGL_4_3, vulkan_spirv, false), std::make_tuple(SPV_ENV_UNIVERSAL_1_1, SPV_ENV_OPENGL_4_5, vulkan_spirv, false), - std::make_tuple(SPV_ENV_UNIVERSAL_1_1, SPV_ENV_WEBGPU_0, vulkan_spirv, true), + std::make_tuple(SPV_ENV_UNIVERSAL_1_1, SPV_ENV_WEBGPU_0, webgpu_spirv, true), std::make_tuple(SPV_ENV_UNIVERSAL_1_2, SPV_ENV_UNIVERSAL_1_0, vulkan_spirv, false), std::make_tuple(SPV_ENV_UNIVERSAL_1_2, SPV_ENV_UNIVERSAL_1_1, vulkan_spirv, false), @@ -132,7 +152,7 @@ INSTANTIATE_TEST_CASE_P(Universal, ValidateVersion, std::make_tuple(SPV_ENV_UNIVERSAL_1_2, SPV_ENV_OPENGL_4_2, vulkan_spirv, false), std::make_tuple(SPV_ENV_UNIVERSAL_1_2, SPV_ENV_OPENGL_4_3, vulkan_spirv, false), std::make_tuple(SPV_ENV_UNIVERSAL_1_2, SPV_ENV_OPENGL_4_5, vulkan_spirv, false), - std::make_tuple(SPV_ENV_UNIVERSAL_1_2, SPV_ENV_WEBGPU_0, vulkan_spirv, true), + std::make_tuple(SPV_ENV_UNIVERSAL_1_2, SPV_ENV_WEBGPU_0, webgpu_spirv, true), std::make_tuple(SPV_ENV_UNIVERSAL_1_3, SPV_ENV_UNIVERSAL_1_0, vulkan_spirv, false), std::make_tuple(SPV_ENV_UNIVERSAL_1_3, SPV_ENV_UNIVERSAL_1_1, vulkan_spirv, false), @@ -145,11 +165,11 @@ INSTANTIATE_TEST_CASE_P(Universal, ValidateVersion, std::make_tuple(SPV_ENV_UNIVERSAL_1_3, SPV_ENV_OPENGL_4_2, vulkan_spirv, false), std::make_tuple(SPV_ENV_UNIVERSAL_1_3, SPV_ENV_OPENGL_4_3, vulkan_spirv, false), std::make_tuple(SPV_ENV_UNIVERSAL_1_3, SPV_ENV_OPENGL_4_5, vulkan_spirv, false), - std::make_tuple(SPV_ENV_UNIVERSAL_1_3, SPV_ENV_WEBGPU_0, vulkan_spirv, true) + std::make_tuple(SPV_ENV_UNIVERSAL_1_3, SPV_ENV_WEBGPU_0, webgpu_spirv, true) ) ); -INSTANTIATE_TEST_CASE_P(Vulkan, ValidateVersion, +INSTANTIATE_TEST_SUITE_P(Vulkan, ValidateVersion, ::testing::Values( // Binary version, Target environment std::make_tuple(SPV_ENV_VULKAN_1_0, SPV_ENV_UNIVERSAL_1_0, vulkan_spirv, true), @@ -163,6 +183,7 @@ INSTANTIATE_TEST_CASE_P(Vulkan, ValidateVersion, std::make_tuple(SPV_ENV_VULKAN_1_0, SPV_ENV_OPENGL_4_2, vulkan_spirv, true), std::make_tuple(SPV_ENV_VULKAN_1_0, SPV_ENV_OPENGL_4_3, vulkan_spirv, true), std::make_tuple(SPV_ENV_VULKAN_1_0, SPV_ENV_OPENGL_4_5, vulkan_spirv, true), + std::make_tuple(SPV_ENV_VULKAN_1_0, SPV_ENV_VULKAN_1_1_SPIRV_1_4, vulkan_spirv, true), std::make_tuple(SPV_ENV_VULKAN_1_1, SPV_ENV_UNIVERSAL_1_0, vulkan_spirv, false), std::make_tuple(SPV_ENV_VULKAN_1_1, SPV_ENV_UNIVERSAL_1_1, vulkan_spirv, false), @@ -174,11 +195,12 @@ INSTANTIATE_TEST_CASE_P(Vulkan, ValidateVersion, std::make_tuple(SPV_ENV_VULKAN_1_1, SPV_ENV_OPENGL_4_1, vulkan_spirv, false), std::make_tuple(SPV_ENV_VULKAN_1_1, SPV_ENV_OPENGL_4_2, vulkan_spirv, false), std::make_tuple(SPV_ENV_VULKAN_1_1, SPV_ENV_OPENGL_4_3, vulkan_spirv, false), - std::make_tuple(SPV_ENV_VULKAN_1_1, SPV_ENV_OPENGL_4_5, vulkan_spirv, false) + std::make_tuple(SPV_ENV_VULKAN_1_1, SPV_ENV_OPENGL_4_5, vulkan_spirv, false), + std::make_tuple(SPV_ENV_VULKAN_1_1, SPV_ENV_VULKAN_1_1_SPIRV_1_4, vulkan_spirv, true) ) ); -INSTANTIATE_TEST_CASE_P(OpenCL, ValidateVersion, +INSTANTIATE_TEST_SUITE_P(OpenCL, ValidateVersion, ::testing::Values( // Binary version, Target environment std::make_tuple(SPV_ENV_OPENCL_2_0, SPV_ENV_UNIVERSAL_1_0, opencl_spirv, true), @@ -231,7 +253,7 @@ INSTANTIATE_TEST_CASE_P(OpenCL, ValidateVersion, ) ); -INSTANTIATE_TEST_CASE_P(OpenCLEmbedded, ValidateVersion, +INSTANTIATE_TEST_SUITE_P(OpenCLEmbedded, ValidateVersion, ::testing::Values( // Binary version, Target environment std::make_tuple(SPV_ENV_OPENCL_EMBEDDED_2_0, SPV_ENV_UNIVERSAL_1_0, opencl_spirv, true), diff --git a/third_party/spirv-tools/test/val/val_webgpu_test.cpp b/third_party/spirv-tools/test/val/val_webgpu_test.cpp index b65d08fe69..e81fc7ce3b 100644 --- a/third_party/spirv-tools/test/val/val_webgpu_test.cpp +++ b/third_party/spirv-tools/test/val/val_webgpu_test.cpp @@ -29,11 +29,19 @@ using ValidateWebGPU = spvtest::ValidateBase; TEST_F(ValidateWebGPU, OpUndefIsDisallowed) { std::string spirv = R"( - OpCapability Shader - OpCapability Linkage - OpMemoryModel Logical GLSL450 - %float = OpTypeFloat 32 - %1 = OpUndef %float + OpCapability Shader + OpCapability VulkanMemoryModelKHR + OpExtension "SPV_KHR_vulkan_memory_model" + OpMemoryModel Logical VulkanKHR + OpEntryPoint Vertex %func "shader" +%float = OpTypeFloat 32 +%1 = OpUndef %float +%void = OpTypeVoid +%void_f = OpTypeFunction %void +%func = OpFunction %void None %void_f +%label = OpLabel + OpReturn + OpFunctionEnd )"; CompileSuccessfully(spirv); @@ -46,6 +54,320 @@ TEST_F(ValidateWebGPU, OpUndefIsDisallowed) { EXPECT_THAT(getDiagnosticString(), HasSubstr("OpUndef is disallowed")); } +TEST_F(ValidateWebGPU, OpNameIsAllowed) { + std::string spirv = R"( + OpCapability Shader + OpCapability VulkanMemoryModelKHR + OpExtension "SPV_KHR_vulkan_memory_model" + OpMemoryModel Logical VulkanKHR + OpEntryPoint Vertex %func "shader" + OpName %1 "foo" + %1 = OpTypeFloat 32 + %void = OpTypeVoid + %void_f = OpTypeFunction %void + %func = OpFunction %void None %void_f + %label = OpLabel + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); +} + +TEST_F(ValidateWebGPU, OpMemberNameIsAllowed) { + std::string spirv = R"( + OpCapability Shader + OpCapability VulkanMemoryModelKHR + OpExtension "SPV_KHR_vulkan_memory_model" + OpMemoryModel Logical VulkanKHR + OpEntryPoint Vertex %func "shader" + OpMemberName %2 0 "foo" + %1 = OpTypeFloat 32 + %2 = OpTypeStruct %1 + %void = OpTypeVoid + %void_f = OpTypeFunction %void + %func = OpFunction %void None %void_f + %label = OpLabel + OpReturn + OpFunctionEnd + +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); +} + +TEST_F(ValidateWebGPU, OpSourceIsAllowed) { + std::string spirv = R"( + OpCapability Shader + OpCapability VulkanMemoryModelKHR + OpExtension "SPV_KHR_vulkan_memory_model" + OpMemoryModel Logical VulkanKHR + OpEntryPoint Vertex %func "shader" + OpSource GLSL 450 + %void = OpTypeVoid + %void_f = OpTypeFunction %void + %func = OpFunction %void None %void_f + %label = OpLabel + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); +} + +TEST_F(ValidateWebGPU, OpSourceContinuedIsAllowed) { + std::string spirv = R"( + OpCapability Shader + OpCapability VulkanMemoryModelKHR + OpExtension "SPV_KHR_vulkan_memory_model" + OpMemoryModel Logical VulkanKHR + OpEntryPoint Vertex %func "shader" + OpSource GLSL 450 + OpSourceContinued "I am a happy shader! Yay! ;" + %void = OpTypeVoid + %void_f = OpTypeFunction %void + %func = OpFunction %void None %void_f + %label = OpLabel + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); +} + +TEST_F(ValidateWebGPU, OpSourceExtensionIsAllowed) { + std::string spirv = R"( + OpCapability Shader + OpCapability VulkanMemoryModelKHR + OpExtension "SPV_KHR_vulkan_memory_model" + OpMemoryModel Logical VulkanKHR + OpEntryPoint Vertex %func "shader" + OpSourceExtension "bar" + %void = OpTypeVoid + %void_f = OpTypeFunction %void + %func = OpFunction %void None %void_f + %label = OpLabel + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); +} + +TEST_F(ValidateWebGPU, OpStringIsAllowed) { + std::string spirv = R"( + OpCapability Shader + OpCapability VulkanMemoryModelKHR + OpExtension "SPV_KHR_vulkan_memory_model" + OpMemoryModel Logical VulkanKHR + OpEntryPoint Vertex %func "shader" + %1 = OpString "foo" + %void = OpTypeVoid + %void_f = OpTypeFunction %void + %func = OpFunction %void None %void_f + %label = OpLabel + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); +} + +TEST_F(ValidateWebGPU, OpLineIsAllowed) { + std::string spirv = R"( + OpCapability Shader + OpCapability VulkanMemoryModelKHR + OpExtension "SPV_KHR_vulkan_memory_model" + OpMemoryModel Logical VulkanKHR + OpEntryPoint Vertex %func "shader" + %1 = OpString "minimal.vert" + OpLine %1 1 1 + %void = OpTypeVoid + %void_f = OpTypeFunction %void + %func = OpFunction %void None %void_f + %label = OpLabel + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); +} + +TEST_F(ValidateWebGPU, OpNoLineIsAllowed) { + std::string spirv = R"( + OpCapability Shader + OpCapability VulkanMemoryModelKHR + OpExtension "SPV_KHR_vulkan_memory_model" + OpMemoryModel Logical VulkanKHR + OpEntryPoint Vertex %func "shader" + OpNoLine + %void = OpTypeVoid + %void_f = OpTypeFunction %void + %func = OpFunction %void None %void_f + %label = OpLabel + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); +} + +TEST_F(ValidateWebGPU, LogicalAddressingVulkanKHRMemoryGood) { + std::string spirv = R"( + OpCapability Shader + OpCapability VulkanMemoryModelKHR + OpExtension "SPV_KHR_vulkan_memory_model" + OpMemoryModel Logical VulkanKHR + OpEntryPoint Vertex %func "shader" +%void = OpTypeVoid +%void_f = OpTypeFunction %void +%func = OpFunction %void None %void_f +%label = OpLabel + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); +} + +TEST_F(ValidateWebGPU, NonVulkanKHRMemoryModelBad) { + std::string spirv = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpNoLine +)"; + + CompileSuccessfully(spirv); + + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Memory model must be VulkanKHR for WebGPU " + "environment.\n OpMemoryModel Logical GLSL450\n")); +} + +TEST_F(ValidateWebGPU, WhitelistedExtendedInstructionsImportGood) { + std::string spirv = R"( + OpCapability Shader + OpCapability VulkanMemoryModelKHR + OpExtension "SPV_KHR_vulkan_memory_model" +%1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical VulkanKHR + OpEntryPoint Vertex %func "shader" +%void = OpTypeVoid +%void_f = OpTypeFunction %void +%func = OpFunction %void None %void_f +%label = OpLabel + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); +} + +TEST_F(ValidateWebGPU, NonWhitelistedExtendedInstructionsImportBad) { + std::string spirv = R"( + OpCapability Shader + OpCapability VulkanMemoryModelKHR + OpExtension "SPV_KHR_vulkan_memory_model" +%1 = OpExtInstImport "OpenCL.std" + OpMemoryModel Logical VulkanKHR +)"; + + CompileSuccessfully(spirv); + + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("For WebGPU, the only valid parameter to " + "OpExtInstImport is \"GLSL.std.450\".\n %1 = " + "OpExtInstImport \"OpenCL.std\"\n")); +} + +TEST_F(ValidateWebGPU, NonVulkanKHRMemoryModelExtensionBad) { + std::string spirv = R"( + OpCapability Shader + OpCapability VulkanMemoryModelKHR + OpExtension "SPV_KHR_8bit_storage" + OpExtension "SPV_KHR_vulkan_memory_model" + OpMemoryModel Logical VulkanKHR +)"; + + CompileSuccessfully(spirv); + + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("For WebGPU, the only valid parameter to OpExtension " + "is \"SPV_KHR_vulkan_memory_model\".\n OpExtension " + "\"SPV_KHR_8bit_storage\"\n")); +} + +spv_binary GenerateTrivialBinary(bool need_little_endian) { + // Smallest possible valid WebGPU SPIR-V binary in little endian. Contains all + // the required boilerplate and a trivial entry point function. + static const uint8_t binary_bytes[] = { + // clang-format off + 0x03, 0x02, 0x23, 0x07, 0x00, 0x03, 0x01, 0x00, 0x00, 0x00, 0x07, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0xE1, 0x14, 0x00, 0x00, + 0x0A, 0x00, 0x08, 0x00, 0x53, 0x50, 0x56, 0x5F, 0x4B, 0x48, 0x52, 0x5F, + 0x76, 0x75, 0x6C, 0x6B, 0x61, 0x6E, 0x5F, 0x6D, 0x65, 0x6D, 0x6F, 0x72, + 0x79, 0x5F, 0x6D, 0x6F, 0x64, 0x65, 0x6C, 0x00, 0x0E, 0x00, 0x03, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x05, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x73, 0x68, 0x61, 0x64, + 0x65, 0x72, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x21, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x36, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, + 0x04, 0x00, 0x00, 0x00, 0xFD, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00 + // clang-format on + }; + static const size_t word_count = sizeof(binary_bytes) / sizeof(uint32_t); + std::unique_ptr result(new spv_binary_t); + if (!result) return nullptr; + + result->wordCount = word_count; + result->code = new uint32_t[word_count]; + if (!result->code) return nullptr; + + if (need_little_endian) { + memcpy(result->code, binary_bytes, sizeof(binary_bytes)); + } else { + uint8_t* code_bytes = reinterpret_cast(result->code); + for (size_t word = 0; word < word_count; ++word) { + code_bytes[4 * word] = binary_bytes[4 * word + 3]; + code_bytes[4 * word + 1] = binary_bytes[4 * word + 2]; + code_bytes[4 * word + 2] = binary_bytes[4 * word + 1]; + code_bytes[4 * word + 3] = binary_bytes[4 * word]; + } + } + + return result.release(); +} + +TEST_F(ValidateWebGPU, LittleEndianGood) { + DestroyBinary(); + binary_ = GenerateTrivialBinary(true); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); +} + +TEST_F(ValidateWebGPU, BigEndianBad) { + DestroyBinary(); + binary_ = GenerateTrivialBinary(false); + EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("WebGPU requires SPIR-V to be little endian.")); +} + } // namespace } // namespace val } // namespace spvtools diff --git a/third_party/spirv-tools/tools/CMakeLists.txt b/third_party/spirv-tools/tools/CMakeLists.txt index 67143d879e..b3a4cc1a00 100644 --- a/third_party/spirv-tools/tools/CMakeLists.txt +++ b/third_party/spirv-tools/tools/CMakeLists.txt @@ -12,7 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -add_subdirectory(lesspipe) +if (NOT ${SPIRV_SKIP_EXECUTABLES}) + add_subdirectory(lesspipe) +endif() add_subdirectory(emacs) # Add a SPIR-V Tools command line tool. Signature: @@ -42,14 +44,10 @@ if (NOT ${SPIRV_SKIP_EXECUTABLES}) add_spvtools_tool(TARGET spirv-dis SRCS dis/dis.cpp LIBS ${SPIRV_TOOLS}) add_spvtools_tool(TARGET spirv-val SRCS val/val.cpp util/cli_consumer.cpp LIBS ${SPIRV_TOOLS}) add_spvtools_tool(TARGET spirv-opt SRCS opt/opt.cpp util/cli_consumer.cpp LIBS SPIRV-Tools-opt ${SPIRV_TOOLS}) + if (NOT DEFINED IOS_PLATFORM) # iOS does not allow std::system calls which spirv-reduce requires + add_spvtools_tool(TARGET spirv-reduce SRCS reduce/reduce.cpp util/cli_consumer.cpp LIBS SPIRV-Tools-reduce ${SPIRV_TOOLS}) + endif() add_spvtools_tool(TARGET spirv-link SRCS link/linker.cpp LIBS SPIRV-Tools-link ${SPIRV_TOOLS}) - add_spvtools_tool(TARGET spirv-stats - SRCS stats/stats.cpp - stats/stats_analyzer.cpp - stats/stats_analyzer.h - stats/spirv_stats.cpp - stats/spirv_stats.h - LIBS ${SPIRV_TOOLS}) add_spvtools_tool(TARGET spirv-cfg SRCS cfg/cfg.cpp cfg/bin_to_dot.h @@ -57,22 +55,16 @@ if (NOT ${SPIRV_SKIP_EXECUTABLES}) LIBS ${SPIRV_TOOLS}) target_include_directories(spirv-cfg PRIVATE ${spirv-tools_SOURCE_DIR} ${SPIRV_HEADER_INCLUDE_DIR}) - target_include_directories(spirv-stats PRIVATE ${spirv-tools_SOURCE_DIR} - ${SPIRV_HEADER_INCLUDE_DIR}) - - set(SPIRV_INSTALL_TARGETS spirv-as spirv-dis spirv-val spirv-opt spirv-stats + set(SPIRV_INSTALL_TARGETS spirv-as spirv-dis spirv-val spirv-opt spirv-cfg spirv-link) + if(NOT DEFINED IOS_PLATFORM) + set(SPIRV_INSTALL_TARGETS ${SPIRV_INSTALL_TARGETS} spirv-reduce) + endif() - if(SPIRV_BUILD_COMPRESSION) - add_spvtools_tool(TARGET spirv-markv - SRCS comp/markv.cpp - comp/markv_model_factory.cpp - comp/markv_model_shader.cpp - LIBS SPIRV-Tools-comp SPIRV-Tools-opt ${SPIRV_TOOLS}) - target_include_directories(spirv-markv PRIVATE ${spirv-tools_SOURCE_DIR} - ${SPIRV_HEADER_INCLUDE_DIR}) - set(SPIRV_INSTALL_TARGETS ${SPIRV_INSTALL_TARGETS} spirv-markv) - endif(SPIRV_BUILD_COMPRESSION) + if(SPIRV_BUILD_FUZZER) + add_spvtools_tool(TARGET spirv-fuzz SRCS fuzz/fuzz.cpp util/cli_consumer.cpp LIBS SPIRV-Tools-fuzz ${SPIRV_TOOLS}) + set(SPIRV_INSTALL_TARGETS ${SPIRV_INSTALL_TARGETS} spirv-fuzz) + endif(SPIRV_BUILD_FUZZER) if(ENABLE_SPIRV_TOOLS_INSTALL) install(TARGETS ${SPIRV_INSTALL_TARGETS} diff --git a/third_party/spirv-tools/tools/as/as.cpp b/third_party/spirv-tools/tools/as/as.cpp index 287ba51f8a..f6e9629441 100644 --- a/third_party/spirv-tools/tools/as/as.cpp +++ b/third_party/spirv-tools/tools/as/as.cpp @@ -21,6 +21,7 @@ #include "tools/io.h" void print_usage(char* argv0) { + std::string target_env_list = spvTargetEnvList(19, 80); printf( R"(%s - Create a SPIR-V binary module from SPIR-V assembly text @@ -41,14 +42,13 @@ Options: Numeric IDs in the binary will have the same values as in the source. Non-numeric IDs are allocated by filling in the gaps, starting with 1 and going up. - --target-env {vulkan1.0|vulkan1.1|spv1.0|spv1.1|spv1.2|spv1.3} - Use Vulkan 1.0, Vulkan 1.1, SPIR-V 1.0, SPIR-V 1.1, - SPIR-V 1.2, or SPIR-V 1.3 + --target-env {%s} + Use specified environment. )", - argv0, argv0); + argv0, argv0, target_env_list.c_str()); } -static const auto kDefaultEnvironment = SPV_ENV_UNIVERSAL_1_3; +static const auto kDefaultEnvironment = SPV_ENV_UNIVERSAL_1_5; int main(int argc, char** argv) { const char* inFile = nullptr; diff --git a/third_party/spirv-tools/tools/cfg/cfg.cpp b/third_party/spirv-tools/tools/cfg/cfg.cpp index 9e2c448ba2..ce7f1c2241 100644 --- a/third_party/spirv-tools/tools/cfg/cfg.cpp +++ b/third_party/spirv-tools/tools/cfg/cfg.cpp @@ -44,7 +44,7 @@ Options: argv0, argv0); } -static const auto kDefaultEnvironment = SPV_ENV_UNIVERSAL_1_2; +static const auto kDefaultEnvironment = SPV_ENV_UNIVERSAL_1_5; int main(int argc, char** argv) { const char* inFile = nullptr; diff --git a/third_party/spirv-tools/tools/comp/markv.cpp b/third_party/spirv-tools/tools/comp/markv.cpp deleted file mode 100644 index 9a0a51808d..0000000000 --- a/third_party/spirv-tools/tools/comp/markv.cpp +++ /dev/null @@ -1,385 +0,0 @@ -// Copyright (c) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "source/comp/markv.h" -#include "source/spirv_target_env.h" -#include "source/table.h" -#include "spirv-tools/optimizer.hpp" -#include "tools/comp/markv_model_factory.h" -#include "tools/io.h" - -namespace { - -const auto kSpvEnv = SPV_ENV_UNIVERSAL_1_2; - -enum Task { - kNoTask = 0, - kEncode, - kDecode, - kTest, -}; - -struct ScopedContext { - ScopedContext(spv_target_env env) : context(spvContextCreate(env)) {} - ~ScopedContext() { spvContextDestroy(context); } - spv_context context; -}; - -void print_usage(char* argv0) { - printf( - R"(%s - Encodes or decodes a SPIR-V binary to or from a MARK-V binary. - -USAGE: %s [e|d|t] [options] [] - -The input binary is read from . If no file is specified, -or if the filename is "-", then the binary is read from standard input. - -If no output is specified then the output is printed to stdout in a human -readable format. - -WIP: MARK-V codec is in early stages of development. At the moment it only -can encode and decode some SPIR-V files and only if exacly the same build of -software is used (is doesn't write or handle version numbers yet). - -Tasks: - e Encode SPIR-V to MARK-V. - d Decode MARK-V to SPIR-V. - t Test the codec by first encoding the given SPIR-V file to - MARK-V, then decoding it back to SPIR-V and comparing results. - -Options: - -h, --help Print this help. - --comments Write codec comments to stderr. - --version Display MARK-V codec version. - --validate Validate SPIR-V while encoding or decoding. - --model= - Compression model, possible values: - shader_lite - fast, poor compression ratio - shader_mid - balanced - shader_max - best compression ratio - Default: shader_lite - - -o Set the output filename. - Output goes to standard output if this option is - not specified, or if the filename is "-". - Not needed for 't' task (testing). -)", - argv0, argv0); -} - -void DiagnosticsMessageHandler(spv_message_level_t level, const char*, - const spv_position_t& position, - const char* message) { - switch (level) { - case SPV_MSG_FATAL: - case SPV_MSG_INTERNAL_ERROR: - case SPV_MSG_ERROR: - std::cerr << "error: " << position.index << ": " << message << std::endl; - break; - case SPV_MSG_WARNING: - std::cerr << "warning: " << position.index << ": " << message - << std::endl; - break; - case SPV_MSG_INFO: - std::cerr << "info: " << position.index << ": " << message << std::endl; - break; - default: - break; - } -} - -} // namespace - -int main(int argc, char** argv) { - const char* input_filename = nullptr; - const char* output_filename = nullptr; - - Task task = kNoTask; - - if (argc < 3) { - print_usage(argv[0]); - return 0; - } - - const char* task_char = argv[1]; - if (0 == strcmp("e", task_char)) { - task = kEncode; - } else if (0 == strcmp("d", task_char)) { - task = kDecode; - } else if (0 == strcmp("t", task_char)) { - task = kTest; - } - - if (task == kNoTask) { - print_usage(argv[0]); - return 1; - } - - bool want_comments = false; - bool validate_spirv_binary = false; - - spvtools::comp::MarkvModelType model_type = - spvtools::comp::kMarkvModelUnknown; - - for (int argi = 2; argi < argc; ++argi) { - if ('-' == argv[argi][0]) { - switch (argv[argi][1]) { - case 'h': - print_usage(argv[0]); - return 0; - case 'o': { - if (!output_filename && argi + 1 < argc && - (task == kEncode || task == kDecode)) { - output_filename = argv[++argi]; - } else { - print_usage(argv[0]); - return 1; - } - } break; - case '-': { - if (0 == strcmp(argv[argi], "--help")) { - print_usage(argv[0]); - return 0; - } else if (0 == strcmp(argv[argi], "--comments")) { - want_comments = true; - } else if (0 == strcmp(argv[argi], "--version")) { - fprintf(stderr, "error: Not implemented\n"); - return 1; - } else if (0 == strcmp(argv[argi], "--validate")) { - validate_spirv_binary = true; - } else if (0 == strcmp(argv[argi], "--model=shader_lite")) { - if (model_type != spvtools::comp::kMarkvModelUnknown) - fprintf(stderr, "error: More than one model specified\n"); - model_type = spvtools::comp::kMarkvModelShaderLite; - } else if (0 == strcmp(argv[argi], "--model=shader_mid")) { - if (model_type != spvtools::comp::kMarkvModelUnknown) - fprintf(stderr, "error: More than one model specified\n"); - model_type = spvtools::comp::kMarkvModelShaderMid; - } else if (0 == strcmp(argv[argi], "--model=shader_max")) { - if (model_type != spvtools::comp::kMarkvModelUnknown) - fprintf(stderr, "error: More than one model specified\n"); - model_type = spvtools::comp::kMarkvModelShaderMax; - } else { - print_usage(argv[0]); - return 1; - } - } break; - case '\0': { - // Setting a filename of "-" to indicate stdin. - if (!input_filename) { - input_filename = argv[argi]; - } else { - fprintf(stderr, "error: More than one input file specified\n"); - return 1; - } - } break; - default: - print_usage(argv[0]); - return 1; - } - } else { - if (!input_filename) { - input_filename = argv[argi]; - } else { - fprintf(stderr, "error: More than one input file specified\n"); - return 1; - } - } - } - - if (model_type == spvtools::comp::kMarkvModelUnknown) - model_type = spvtools::comp::kMarkvModelShaderLite; - - const auto no_comments = spvtools::comp::MarkvLogConsumer(); - const auto output_to_stderr = [](const std::string& str) { - std::cerr << str; - }; - - ScopedContext ctx(kSpvEnv); - - std::unique_ptr model = - spvtools::comp::CreateMarkvModel(model_type); - - std::vector spirv; - std::vector markv; - - spvtools::comp::MarkvCodecOptions options; - options.validate_spirv_binary = validate_spirv_binary; - - if (task == kEncode) { - if (!ReadFile(input_filename, "rb", &spirv)) return 1; - assert(!spirv.empty()); - - if (SPV_SUCCESS != spvtools::comp::SpirvToMarkv( - ctx.context, spirv, options, *model, - DiagnosticsMessageHandler, - want_comments ? output_to_stderr : no_comments, - spvtools::comp::MarkvDebugConsumer(), &markv)) { - std::cerr << "error: Failed to encode " << input_filename << " to MARK-V " - << std::endl; - return 1; - } - - if (!WriteFile(output_filename, "wb", markv.data(), markv.size())) - return 1; - } else if (task == kDecode) { - if (!ReadFile(input_filename, "rb", &markv)) return 1; - assert(!markv.empty()); - - if (SPV_SUCCESS != spvtools::comp::MarkvToSpirv( - ctx.context, markv, options, *model, - DiagnosticsMessageHandler, - want_comments ? output_to_stderr : no_comments, - spvtools::comp::MarkvDebugConsumer(), &spirv)) { - std::cerr << "error: Failed to decode " << input_filename << " to SPIR-V " - << std::endl; - return 1; - } - - if (!WriteFile(output_filename, "wb", spirv.data(), spirv.size())) - return 1; - } else if (task == kTest) { - if (!ReadFile(input_filename, "rb", &spirv)) return 1; - assert(!spirv.empty()); - - std::vector spirv_before; - spvtools::Optimizer optimizer(kSpvEnv); - optimizer.RegisterPass(spvtools::CreateCompactIdsPass()); - if (!optimizer.Run(spirv.data(), spirv.size(), &spirv_before)) { - std::cerr << "error: Optimizer failure on: " << input_filename - << std::endl; - } - - std::vector encoder_instruction_bits; - std::vector encoder_instruction_comments; - std::vector> encoder_instruction_words; - std::vector decoder_instruction_bits; - std::vector decoder_instruction_comments; - std::vector> decoder_instruction_words; - - const auto encoder_debug_consumer = [&](const std::vector& words, - const std::string& bits, - const std::string& comment) { - encoder_instruction_words.push_back(words); - encoder_instruction_bits.push_back(bits); - encoder_instruction_comments.push_back(comment); - return true; - }; - - if (SPV_SUCCESS != spvtools::comp::SpirvToMarkv( - ctx.context, spirv_before, options, *model, - DiagnosticsMessageHandler, - want_comments ? output_to_stderr : no_comments, - encoder_debug_consumer, &markv)) { - std::cerr << "error: Failed to encode " << input_filename << " to MARK-V " - << std::endl; - return 1; - } - - const auto write_bug_report = [&]() { - for (size_t inst_index = 0; inst_index < decoder_instruction_words.size(); - ++inst_index) { - std::cerr << "\nInstruction #" << inst_index << std::endl; - std::cerr << "\nEncoder words: "; - for (uint32_t word : encoder_instruction_words[inst_index]) - std::cerr << word << " "; - std::cerr << "\nDecoder words: "; - for (uint32_t word : decoder_instruction_words[inst_index]) - std::cerr << word << " "; - std::cerr << std::endl; - - std::cerr << "\nEncoder bits: " << encoder_instruction_bits[inst_index]; - std::cerr << "\nDecoder bits: " << decoder_instruction_bits[inst_index]; - std::cerr << std::endl; - - std::cerr << "\nEncoder comments:\n" - << encoder_instruction_comments[inst_index]; - std::cerr << "Decoder comments:\n" - << decoder_instruction_comments[inst_index]; - std::cerr << std::endl; - } - }; - - const auto decoder_debug_consumer = [&](const std::vector& words, - const std::string& bits, - const std::string& comment) { - const size_t inst_index = decoder_instruction_words.size(); - if (inst_index >= encoder_instruction_words.size()) { - write_bug_report(); - std::cerr << "error: Decoder has more instructions than encoder: " - << input_filename << std::endl; - return false; - } - - decoder_instruction_words.push_back(words); - decoder_instruction_bits.push_back(bits); - decoder_instruction_comments.push_back(comment); - - if (encoder_instruction_words[inst_index] != - decoder_instruction_words[inst_index]) { - write_bug_report(); - std::cerr << "error: Words of the last decoded instruction differ from " - "reference: " - << input_filename << std::endl; - return false; - } - - if (encoder_instruction_bits[inst_index] != - decoder_instruction_bits[inst_index]) { - write_bug_report(); - std::cerr << "error: Bits of the last decoded instruction differ from " - "reference: " - << input_filename << std::endl; - return false; - } - return true; - }; - - std::vector spirv_after; - const spv_result_t decoding_result = spvtools::comp::MarkvToSpirv( - ctx.context, markv, options, *model, DiagnosticsMessageHandler, - want_comments ? output_to_stderr : no_comments, decoder_debug_consumer, - &spirv_after); - - if (decoding_result == SPV_REQUESTED_TERMINATION) { - std::cerr << "error: Decoding interrupted by the debugger: " - << input_filename << std::endl; - return 1; - } - - if (decoding_result != SPV_SUCCESS) { - std::cerr << "error: Failed to decode encoded " << input_filename - << " back to SPIR-V " << std::endl; - return 1; - } - - assert(spirv_before.size() == spirv_after.size()); - assert(std::mismatch(std::next(spirv_before.begin(), 5), spirv_before.end(), - std::next(spirv_after.begin(), 5)) == - std::make_pair(spirv_before.end(), spirv_after.end())); - } - - return 0; -} diff --git a/third_party/spirv-tools/tools/comp/markv_model_factory.cpp b/third_party/spirv-tools/tools/comp/markv_model_factory.cpp deleted file mode 100644 index 863fcf5587..0000000000 --- a/third_party/spirv-tools/tools/comp/markv_model_factory.cpp +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (c) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "tools/comp/markv_model_factory.h" - -#include "source/util/make_unique.h" -#include "tools/comp/markv_model_shader.h" - -namespace spvtools { -namespace comp { - -std::unique_ptr CreateMarkvModel(MarkvModelType type) { - std::unique_ptr model; - switch (type) { - case kMarkvModelShaderLite: { - model = MakeUnique(); - break; - } - case kMarkvModelShaderMid: { - model = MakeUnique(); - break; - } - case kMarkvModelShaderMax: { - model = MakeUnique(); - break; - } - case kMarkvModelUnknown: { - assert(0 && "kMarkvModelUnknown supplied to CreateMarkvModel"); - return model; - } - } - - model->SetModelType(static_cast(type)); - - return model; -} - -} // namespace comp -} // namespace spvtools diff --git a/third_party/spirv-tools/tools/comp/markv_model_shader.cpp b/third_party/spirv-tools/tools/comp/markv_model_shader.cpp deleted file mode 100644 index 8e296cd8ce..0000000000 --- a/third_party/spirv-tools/tools/comp/markv_model_shader.cpp +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright (c) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "tools/comp/markv_model_shader.h" - -#include -#include -#include -#include -#include -#include - -#include "source/util/make_unique.h" - -namespace spvtools { -namespace comp { -namespace { - -// Signals that the value is not in the coding scheme and a fallback method -// needs to be used. -const uint64_t kMarkvNoneOfTheAbove = MarkvModel::GetMarkvNoneOfTheAbove(); - -inline uint32_t CombineOpcodeAndNumOperands(uint32_t opcode, - uint32_t num_operands) { - return opcode | (num_operands << 16); -} - -#include "tools/comp/markv_model_shader_default_autogen.inc" - -} // namespace - -MarkvModelShaderLite::MarkvModelShaderLite() { - const uint16_t kVersionNumber = 1; - SetModelVersion(kVersionNumber); - - opcode_and_num_operands_huffman_codec_ = - MakeUnique>(GetOpcodeAndNumOperandsHist()); - - id_fallback_strategy_ = IdFallbackStrategy::kShortDescriptor; -} - -MarkvModelShaderMid::MarkvModelShaderMid() { - const uint16_t kVersionNumber = 1; - SetModelVersion(kVersionNumber); - - opcode_and_num_operands_huffman_codec_ = - MakeUnique>(GetOpcodeAndNumOperandsHist()); - non_id_word_huffman_codecs_ = GetNonIdWordHuffmanCodecs(); - id_descriptor_huffman_codecs_ = GetIdDescriptorHuffmanCodecs(); - descriptors_with_coding_scheme_ = GetDescriptorsWithCodingScheme(); - literal_string_huffman_codecs_ = GetLiteralStringHuffmanCodecs(); - - id_fallback_strategy_ = IdFallbackStrategy::kShortDescriptor; -} - -MarkvModelShaderMax::MarkvModelShaderMax() { - const uint16_t kVersionNumber = 1; - SetModelVersion(kVersionNumber); - - opcode_and_num_operands_huffman_codec_ = - MakeUnique>(GetOpcodeAndNumOperandsHist()); - opcode_and_num_operands_markov_huffman_codecs_ = - GetOpcodeAndNumOperandsMarkovHuffmanCodecs(); - non_id_word_huffman_codecs_ = GetNonIdWordHuffmanCodecs(); - id_descriptor_huffman_codecs_ = GetIdDescriptorHuffmanCodecs(); - descriptors_with_coding_scheme_ = GetDescriptorsWithCodingScheme(); - literal_string_huffman_codecs_ = GetLiteralStringHuffmanCodecs(); - - id_fallback_strategy_ = IdFallbackStrategy::kRuleBased; -} - -} // namespace comp -} // namespace spvtools diff --git a/third_party/spirv-tools/tools/comp/markv_model_shader.h b/third_party/spirv-tools/tools/comp/markv_model_shader.h deleted file mode 100644 index 3a704571fd..0000000000 --- a/third_party/spirv-tools/tools/comp/markv_model_shader.h +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef TOOLS_COMP_MARKV_MODEL_SHADER_H_ -#define TOOLS_COMP_MARKV_MODEL_SHADER_H_ - -#include "source/comp/markv_model.h" - -namespace spvtools { -namespace comp { - -// MARK-V shader compression model, which only uses fast and lightweight -// algorithms, which do not require training and are not heavily dependent on -// SPIR-V grammar. Compression ratio is worse than by other models. -class MarkvModelShaderLite : public MarkvModel { - public: - MarkvModelShaderLite(); -}; - -// MARK-V shader compression model with balanced compression ratio and runtime -// performance. -class MarkvModelShaderMid : public MarkvModel { - public: - MarkvModelShaderMid(); -}; - -// MARK-V shader compression model designed for maximum compression. -class MarkvModelShaderMax : public MarkvModel { - public: - MarkvModelShaderMax(); -}; - -} // namespace comp -} // namespace spvtools - -#endif // TOOLS_COMP_MARKV_MODEL_SHADER_H_ diff --git a/third_party/spirv-tools/tools/comp/markv_model_shader_default_autogen.inc b/third_party/spirv-tools/tools/comp/markv_model_shader_default_autogen.inc deleted file mode 100644 index 0093cf1c0b..0000000000 --- a/third_party/spirv-tools/tools/comp/markv_model_shader_default_autogen.inc +++ /dev/null @@ -1,14519 +0,0 @@ - -std::map GetOpcodeAndNumOperandsHist() { - return std::map({ - { CombineOpcodeAndNumOperands(SpvOpExtInst, 7), 158282 }, - { CombineOpcodeAndNumOperands(SpvOpDot, 4), 151035 }, - { CombineOpcodeAndNumOperands(SpvOpVectorShuffle, 6), 183292 }, - { CombineOpcodeAndNumOperands(SpvOpImageSampleImplicitLod, 4), 126492 }, - { CombineOpcodeAndNumOperands(SpvOpExecutionMode, 2), 13311 }, - { CombineOpcodeAndNumOperands(SpvOpFNegate, 3), 29952 }, - { CombineOpcodeAndNumOperands(SpvOpExtInst, 5), 106847 }, - { CombineOpcodeAndNumOperands(SpvOpImageSampleExplicitLod, 7), 26350 }, - { CombineOpcodeAndNumOperands(SpvOpImageSampleExplicitLod, 6), 28186 }, - { CombineOpcodeAndNumOperands(SpvOpFDiv, 4), 41635 }, - { CombineOpcodeAndNumOperands(SpvOpFMul, 4), 412786 }, - { CombineOpcodeAndNumOperands(SpvOpFunction, 4), 62905 }, - { CombineOpcodeAndNumOperands(SpvOpVectorShuffle, 8), 118614 }, - { CombineOpcodeAndNumOperands(SpvOpDecorate, 2), 100735 }, - { CombineOpcodeAndNumOperands(SpvOpReturnValue, 1), 40852 }, - { CombineOpcodeAndNumOperands(SpvOpVectorTimesScalar, 4), 157091 }, - { CombineOpcodeAndNumOperands(SpvOpExtInst, 6), 122100 }, - { CombineOpcodeAndNumOperands(SpvOpAccessChain, 5), 82930 }, - { CombineOpcodeAndNumOperands(SpvOpFSub, 4), 161019 }, - { CombineOpcodeAndNumOperands(SpvOpConstant, 3), 466014 }, - { CombineOpcodeAndNumOperands(SpvOpCompositeExtract, 5), 107126 }, - { CombineOpcodeAndNumOperands(SpvOpTypeImage, 8), 34775 }, - { CombineOpcodeAndNumOperands(SpvOpImageSampleDrefExplicitLod, 7), 26146 }, - { CombineOpcodeAndNumOperands(SpvOpMemoryModel, 2), 18879 }, - { CombineOpcodeAndNumOperands(SpvOpDecorate, 3), 485251 }, - { CombineOpcodeAndNumOperands(SpvOpCompositeConstruct, 4), 78011 }, - { CombineOpcodeAndNumOperands(SpvOpTypeFloat, 2), 18879 }, - { CombineOpcodeAndNumOperands(SpvOpVectorTimesMatrix, 4), 15848 }, - { CombineOpcodeAndNumOperands(SpvOpTypeVector, 3), 69404 }, - { CombineOpcodeAndNumOperands(SpvOpTypeFunction, 3), 19998 }, - { CombineOpcodeAndNumOperands(SpvOpConstantComposite, 6), 40228 }, - { CombineOpcodeAndNumOperands(SpvOpCapability, 1), 22510 }, - { CombineOpcodeAndNumOperands(SpvOpTypeArray, 3), 37585 }, - { CombineOpcodeAndNumOperands(SpvOpTypeInt, 3), 30454 }, - { CombineOpcodeAndNumOperands(SpvOpFunctionCall, 4), 29021 }, - { CombineOpcodeAndNumOperands(SpvOpFAdd, 4), 342237 }, - { CombineOpcodeAndNumOperands(SpvOpTypeMatrix, 3), 24449 }, - { CombineOpcodeAndNumOperands(SpvOpLabel, 1), 129408 }, - { CombineOpcodeAndNumOperands(SpvOpTypePointer, 3), 246535 }, - { CombineOpcodeAndNumOperands(SpvOpAccessChain, 4), 503456 }, - { CombineOpcodeAndNumOperands(SpvOpTypeFunction, 2), 19779 }, - { CombineOpcodeAndNumOperands(SpvOpBranchConditional, 3), 24139 }, - { CombineOpcodeAndNumOperands(SpvOpVariable, 3), 697946 }, - { CombineOpcodeAndNumOperands(SpvOpConstantComposite, 5), 55769 }, - { CombineOpcodeAndNumOperands(SpvOpTypeVoid, 1), 18879 }, - { CombineOpcodeAndNumOperands(SpvOpCompositeConstruct, 6), 145508 }, - { CombineOpcodeAndNumOperands(SpvOpFunctionParameter, 2), 85583 }, - { CombineOpcodeAndNumOperands(SpvOpTypeSampledImage, 2), 34775 }, - { CombineOpcodeAndNumOperands(SpvOpConstantComposite, 4), 66362 }, - { CombineOpcodeAndNumOperands(SpvOpLoad, 3), 1272902 }, - { CombineOpcodeAndNumOperands(SpvOpReturn, 0), 22122 }, - { CombineOpcodeAndNumOperands(SpvOpCompositeExtract, 4), 861008 }, - { CombineOpcodeAndNumOperands(SpvOpFunctionEnd, 0), 62905 }, - { CombineOpcodeAndNumOperands(SpvOpExtInstImport, 2), 18879 }, - { CombineOpcodeAndNumOperands(SpvOpSelectionMerge, 2), 22009 }, - { CombineOpcodeAndNumOperands(SpvOpBranch, 1), 38275 }, - { CombineOpcodeAndNumOperands(SpvOpTypeBool, 1), 12208 }, - { CombineOpcodeAndNumOperands(SpvOpSampledImage, 4), 95518 }, - { CombineOpcodeAndNumOperands(SpvOpMemberDecorate, 3), 94887 }, - { CombineOpcodeAndNumOperands(SpvOpMemberDecorate, 4), 1942215 }, - { CombineOpcodeAndNumOperands(SpvOpCompositeConstruct, 5), 205266 }, - { CombineOpcodeAndNumOperands(SpvOpUndef, 2), 22157 }, - { CombineOpcodeAndNumOperands(SpvOpCompositeInsert, 5), 142749 }, - { CombineOpcodeAndNumOperands(SpvOpCompositeInsert, 6), 24420 }, - { CombineOpcodeAndNumOperands(SpvOpCompositeExtract, 6), 16896 }, - { CombineOpcodeAndNumOperands(SpvOpStore, 2), 604982 }, - { CombineOpcodeAndNumOperands(SpvOpIAdd, 4), 14471 }, - { CombineOpcodeAndNumOperands(SpvOpVectorShuffle, 7), 269658 }, - { kMarkvNoneOfTheAbove, 399895 }, - }); -} - -std::map>> -GetOpcodeAndNumOperandsMarkovHuffmanCodecs() { - std::map>> codecs; - { - std::unique_ptr> codec(new HuffmanCodec(35, { - {0, 0, 0}, - {65790, 0, 0}, - {131134, 0, 0}, - {196669, 0, 0}, - {262209, 0, 0}, - {262221, 0, 0}, - {262225, 0, 0}, - {262230, 0, 0}, - {262273, 0, 0}, - {262277, 0, 0}, - {262286, 0, 0}, - {327745, 0, 0}, - {327761, 0, 0}, - {327762, 0, 0}, - {393295, 0, 0}, - {393304, 0, 0}, - {458831, 0, 0}, - {458840, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 11, 8}, - {0, 12, 19}, - {0, 18, 20}, - {0, 5, 21}, - {0, 15, 7}, - {0, 10, 1}, - {0, 23, 22}, - {0, 14, 24}, - {0, 6, 4}, - {0, 2, 17}, - {0, 13, 25}, - {0, 9, 26}, - {0, 28, 27}, - {0, 3, 29}, - {0, 30, 16}, - {0, 32, 31}, - {0, 34, 33}, - })); - - codecs.emplace(SpvOpImageSampleExplicitLod, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(55, { - {0, 0, 0}, - {65785, 0, 0}, - {65790, 0, 0}, - {131134, 0, 0}, - {196669, 0, 0}, - {196735, 0, 0}, - {262201, 0, 0}, - {262209, 0, 0}, - {262224, 0, 0}, - {262225, 0, 0}, - {262231, 0, 0}, - {262273, 0, 0}, - {262275, 0, 0}, - {262277, 0, 0}, - {262280, 0, 0}, - {262286, 0, 0}, - {327692, 0, 0}, - {327745, 0, 0}, - {327760, 0, 0}, - {327762, 0, 0}, - {393228, 0, 0}, - {393295, 0, 0}, - {393296, 0, 0}, - {393303, 0, 0}, - {393304, 0, 0}, - {458764, 0, 0}, - {458831, 0, 0}, - {524367, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 14, 5}, - {0, 29, 17}, - {0, 1, 30}, - {0, 10, 20}, - {0, 32, 31}, - {0, 33, 2}, - {0, 34, 23}, - {0, 8, 35}, - {0, 6, 36}, - {0, 19, 22}, - {0, 28, 25}, - {0, 38, 37}, - {0, 13, 39}, - {0, 40, 24}, - {0, 27, 21}, - {0, 26, 41}, - {0, 42, 12}, - {0, 15, 43}, - {0, 44, 18}, - {0, 45, 3}, - {0, 11, 7}, - {0, 16, 46}, - {0, 47, 9}, - {0, 4, 48}, - {0, 50, 49}, - {0, 52, 51}, - {0, 54, 53}, - })); - - codecs.emplace(SpvOpFDiv, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(19, { - {0, 0, 0}, - {196669, 0, 0}, - {262209, 0, 0}, - {262224, 0, 0}, - {262225, 0, 0}, - {262231, 0, 0}, - {262286, 0, 0}, - {393295, 0, 0}, - {393304, 0, 0}, - {458840, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 8, 10}, - {0, 11, 3}, - {0, 2, 9}, - {0, 4, 1}, - {0, 5, 6}, - {0, 13, 12}, - {0, 15, 14}, - {0, 16, 7}, - {0, 18, 17}, - })); - - codecs.emplace(SpvOpSampledImage, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(67, { - {0, 0, 0}, - {65785, 0, 0}, - {65790, 0, 0}, - {131134, 0, 0}, - {131319, 0, 0}, - {196669, 0, 0}, - {196735, 0, 0}, - {262209, 0, 0}, - {262224, 0, 0}, - {262225, 0, 0}, - {262231, 0, 0}, - {262272, 0, 0}, - {262273, 0, 0}, - {262275, 0, 0}, - {262277, 0, 0}, - {262280, 0, 0}, - {262285, 0, 0}, - {262286, 0, 0}, - {262292, 0, 0}, - {327692, 0, 0}, - {327745, 0, 0}, - {327760, 0, 0}, - {327761, 0, 0}, - {327762, 0, 0}, - {393228, 0, 0}, - {393281, 0, 0}, - {393295, 0, 0}, - {393296, 0, 0}, - {393297, 0, 0}, - {393298, 0, 0}, - {393304, 0, 0}, - {458764, 0, 0}, - {458831, 0, 0}, - {524367, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 4, 10}, - {0, 30, 35}, - {0, 1, 36}, - {0, 11, 37}, - {0, 38, 6}, - {0, 16, 39}, - {0, 15, 40}, - {0, 25, 2}, - {0, 41, 20}, - {0, 26, 19}, - {0, 42, 29}, - {0, 28, 22}, - {0, 23, 34}, - {0, 44, 43}, - {0, 17, 45}, - {0, 24, 27}, - {0, 18, 33}, - {0, 47, 46}, - {0, 8, 48}, - {0, 50, 49}, - {0, 32, 51}, - {0, 31, 52}, - {0, 53, 21}, - {0, 54, 13}, - {0, 3, 55}, - {0, 7, 14}, - {0, 57, 56}, - {0, 58, 5}, - {0, 59, 9}, - {0, 61, 60}, - {0, 63, 62}, - {0, 64, 12}, - {0, 66, 65}, - })); - - codecs.emplace(SpvOpFMul, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(79, { - {0, 0, 0}, - {65785, 0, 0}, - {65790, 0, 0}, - {131134, 0, 0}, - {196669, 0, 0}, - {196735, 0, 0}, - {262201, 0, 0}, - {262209, 0, 0}, - {262224, 0, 0}, - {262225, 0, 0}, - {262230, 0, 0}, - {262231, 0, 0}, - {262272, 0, 0}, - {262273, 0, 0}, - {262275, 0, 0}, - {262277, 0, 0}, - {262280, 0, 0}, - {262286, 0, 0}, - {262288, 0, 0}, - {262292, 0, 0}, - {262328, 0, 0}, - {262334, 0, 0}, - {327692, 0, 0}, - {327737, 0, 0}, - {327745, 0, 0}, - {327760, 0, 0}, - {327761, 0, 0}, - {327762, 0, 0}, - {393228, 0, 0}, - {393281, 0, 0}, - {393295, 0, 0}, - {393296, 0, 0}, - {393297, 0, 0}, - {393303, 0, 0}, - {393304, 0, 0}, - {458764, 0, 0}, - {458831, 0, 0}, - {458840, 0, 0}, - {524345, 0, 0}, - {524367, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 38, 33}, - {0, 18, 41}, - {0, 42, 23}, - {0, 43, 6}, - {0, 34, 44}, - {0, 1, 45}, - {0, 31, 14}, - {0, 47, 46}, - {0, 48, 2}, - {0, 12, 21}, - {0, 49, 30}, - {0, 37, 50}, - {0, 51, 20}, - {0, 5, 24}, - {0, 40, 16}, - {0, 29, 13}, - {0, 26, 52}, - {0, 53, 17}, - {0, 36, 54}, - {0, 55, 28}, - {0, 57, 56}, - {0, 19, 25}, - {0, 39, 8}, - {0, 32, 58}, - {0, 59, 27}, - {0, 22, 10}, - {0, 35, 60}, - {0, 62, 61}, - {0, 63, 7}, - {0, 65, 64}, - {0, 4, 66}, - {0, 68, 67}, - {0, 11, 3}, - {0, 15, 69}, - {0, 9, 70}, - {0, 72, 71}, - {0, 74, 73}, - {0, 76, 75}, - {0, 78, 77}, - })); - - codecs.emplace(SpvOpFAdd, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(55, { - {0, 0, 0}, - {65556, 0, 0}, - {65562, 0, 0}, - {131073, 0, 0}, - {131094, 0, 0}, - {131105, 0, 0}, - {196629, 0, 0}, - {196631, 0, 0}, - {196632, 0, 0}, - {196636, 0, 0}, - {196640, 0, 0}, - {196641, 0, 0}, - {196651, 0, 0}, - {196667, 0, 0}, - {262177, 0, 0}, - {262188, 0, 0}, - {262198, 0, 0}, - {327713, 0, 0}, - {327724, 0, 0}, - {393249, 0, 0}, - {393260, 0, 0}, - {458785, 0, 0}, - {524313, 0, 0}, - {524321, 0, 0}, - {589857, 0, 0}, - {655393, 0, 0}, - {720929, 0, 0}, - {852001, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 26, 24}, - {0, 29, 27}, - {0, 4, 30}, - {0, 21, 9}, - {0, 31, 20}, - {0, 33, 32}, - {0, 34, 3}, - {0, 8, 35}, - {0, 36, 5}, - {0, 23, 16}, - {0, 38, 37}, - {0, 25, 2}, - {0, 39, 1}, - {0, 17, 40}, - {0, 41, 15}, - {0, 18, 42}, - {0, 43, 6}, - {0, 44, 14}, - {0, 28, 19}, - {0, 7, 45}, - {0, 46, 22}, - {0, 48, 47}, - {0, 49, 11}, - {0, 51, 50}, - {0, 12, 10}, - {0, 53, 52}, - {0, 13, 54}, - })); - - codecs.emplace(SpvOpTypePointer, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(57, { - {0, 0, 0}, - {65785, 0, 0}, - {65790, 0, 0}, - {131134, 0, 0}, - {196669, 0, 0}, - {196735, 0, 0}, - {262209, 0, 0}, - {262224, 0, 0}, - {262225, 0, 0}, - {262272, 0, 0}, - {262273, 0, 0}, - {262275, 0, 0}, - {262277, 0, 0}, - {262280, 0, 0}, - {262286, 0, 0}, - {262292, 0, 0}, - {262328, 0, 0}, - {327692, 0, 0}, - {327745, 0, 0}, - {327760, 0, 0}, - {327761, 0, 0}, - {327762, 0, 0}, - {393228, 0, 0}, - {393273, 0, 0}, - {393295, 0, 0}, - {393296, 0, 0}, - {458764, 0, 0}, - {458831, 0, 0}, - {524367, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 9, 23}, - {0, 1, 30}, - {0, 5, 31}, - {0, 32, 28}, - {0, 33, 25}, - {0, 34, 29}, - {0, 18, 24}, - {0, 27, 16}, - {0, 7, 13}, - {0, 14, 35}, - {0, 20, 10}, - {0, 36, 21}, - {0, 2, 37}, - {0, 38, 3}, - {0, 39, 22}, - {0, 40, 19}, - {0, 41, 11}, - {0, 6, 4}, - {0, 12, 42}, - {0, 43, 8}, - {0, 15, 26}, - {0, 45, 44}, - {0, 47, 46}, - {0, 48, 17}, - {0, 50, 49}, - {0, 52, 51}, - {0, 54, 53}, - {0, 56, 55}, - })); - - codecs.emplace(SpvOpFSub, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(13, { - {0, 0, 0}, - {65785, 0, 0}, - {131134, 0, 0}, - {196719, 0, 0}, - {262209, 0, 0}, - {262276, 0, 0}, - {327745, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 7, 4}, - {0, 2, 8}, - {0, 1, 9}, - {0, 5, 10}, - {0, 3, 6}, - {0, 12, 11}, - })); - - codecs.emplace(SpvOpIAdd, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(83, { - {0, 0, 0}, - {65785, 0, 0}, - {65790, 0, 0}, - {131134, 0, 0}, - {131319, 0, 0}, - {196669, 0, 0}, - {196732, 0, 0}, - {196735, 0, 0}, - {262209, 0, 0}, - {262221, 0, 0}, - {262224, 0, 0}, - {262225, 0, 0}, - {262230, 0, 0}, - {262231, 0, 0}, - {262273, 0, 0}, - {262275, 0, 0}, - {262277, 0, 0}, - {262280, 0, 0}, - {262286, 0, 0}, - {262288, 0, 0}, - {262292, 0, 0}, - {262328, 0, 0}, - {262334, 0, 0}, - {262340, 0, 0}, - {327692, 0, 0}, - {327737, 0, 0}, - {327745, 0, 0}, - {327760, 0, 0}, - {327761, 0, 0}, - {327762, 0, 0}, - {393228, 0, 0}, - {393273, 0, 0}, - {393295, 0, 0}, - {393296, 0, 0}, - {393297, 0, 0}, - {393298, 0, 0}, - {393304, 0, 0}, - {458764, 0, 0}, - {458831, 0, 0}, - {458840, 0, 0}, - {458842, 0, 0}, - {524367, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 25, 2}, - {0, 31, 43}, - {0, 4, 44}, - {0, 26, 45}, - {0, 39, 46}, - {0, 34, 36}, - {0, 19, 47}, - {0, 6, 48}, - {0, 35, 9}, - {0, 12, 29}, - {0, 21, 49}, - {0, 22, 13}, - {0, 17, 50}, - {0, 23, 51}, - {0, 52, 7}, - {0, 37, 1}, - {0, 53, 3}, - {0, 54, 24}, - {0, 56, 55}, - {0, 32, 57}, - {0, 59, 58}, - {0, 42, 10}, - {0, 60, 8}, - {0, 5, 41}, - {0, 61, 20}, - {0, 62, 38}, - {0, 64, 63}, - {0, 40, 65}, - {0, 66, 18}, - {0, 15, 28}, - {0, 14, 67}, - {0, 68, 30}, - {0, 70, 69}, - {0, 72, 71}, - {0, 73, 27}, - {0, 16, 74}, - {0, 75, 33}, - {0, 77, 76}, - {0, 79, 78}, - {0, 81, 80}, - {0, 82, 11}, - })); - - codecs.emplace(SpvOpCompositeExtract, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(29, { - {0, 0, 0}, - {65790, 0, 0}, - {131134, 0, 0}, - {196669, 0, 0}, - {262209, 0, 0}, - {262225, 0, 0}, - {262273, 0, 0}, - {262288, 0, 0}, - {262292, 0, 0}, - {327692, 0, 0}, - {327761, 0, 0}, - {327762, 0, 0}, - {393295, 0, 0}, - {458831, 0, 0}, - {524367, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 10, 6}, - {0, 16, 13}, - {0, 7, 17}, - {0, 15, 18}, - {0, 19, 12}, - {0, 20, 14}, - {0, 1, 4}, - {0, 22, 21}, - {0, 11, 8}, - {0, 2, 5}, - {0, 9, 23}, - {0, 3, 24}, - {0, 26, 25}, - {0, 28, 27}, - })); - - codecs.emplace(SpvOpVectorTimesMatrix, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {65784, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(SpvOpBranch, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {262198, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(SpvOpFunctionEnd, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {65784, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(SpvOpBranchConditional, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(53, { - {0, 0, 0}, - {65785, 0, 0}, - {65790, 0, 0}, - {131134, 0, 0}, - {131319, 0, 0}, - {196665, 0, 0}, - {196669, 0, 0}, - {196735, 0, 0}, - {262201, 0, 0}, - {262209, 0, 0}, - {262224, 0, 0}, - {262225, 0, 0}, - {262231, 0, 0}, - {262273, 0, 0}, - {262275, 0, 0}, - {262277, 0, 0}, - {262280, 0, 0}, - {262286, 0, 0}, - {262288, 0, 0}, - {262292, 0, 0}, - {327692, 0, 0}, - {327745, 0, 0}, - {327760, 0, 0}, - {393228, 0, 0}, - {393295, 0, 0}, - {458764, 0, 0}, - {458831, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 25, 16}, - {0, 21, 28}, - {0, 18, 23}, - {0, 4, 29}, - {0, 10, 5}, - {0, 1, 30}, - {0, 32, 31}, - {0, 22, 33}, - {0, 34, 8}, - {0, 35, 15}, - {0, 13, 36}, - {0, 26, 17}, - {0, 38, 37}, - {0, 39, 11}, - {0, 40, 14}, - {0, 12, 27}, - {0, 19, 41}, - {0, 24, 42}, - {0, 44, 43}, - {0, 45, 7}, - {0, 20, 46}, - {0, 9, 47}, - {0, 48, 2}, - {0, 50, 49}, - {0, 6, 3}, - {0, 52, 51}, - })); - - codecs.emplace(SpvOpFunctionCall, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(71, { - {0, 0, 0}, - {65556, 0, 0}, - {65562, 0, 0}, - {131073, 0, 0}, - {131094, 0, 0}, - {131099, 0, 0}, - {131134, 0, 0}, - {196629, 0, 0}, - {196631, 0, 0}, - {196632, 0, 0}, - {196636, 0, 0}, - {196640, 0, 0}, - {196651, 0, 0}, - {196665, 0, 0}, - {196667, 0, 0}, - {196669, 0, 0}, - {262188, 0, 0}, - {262198, 0, 0}, - {262201, 0, 0}, - {262209, 0, 0}, - {262225, 0, 0}, - {262275, 0, 0}, - {262280, 0, 0}, - {262292, 0, 0}, - {327692, 0, 0}, - {327724, 0, 0}, - {327737, 0, 0}, - {327745, 0, 0}, - {393228, 0, 0}, - {393260, 0, 0}, - {393273, 0, 0}, - {393295, 0, 0}, - {393296, 0, 0}, - {458831, 0, 0}, - {524313, 0, 0}, - {524367, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 22, 4}, - {0, 32, 23}, - {0, 37, 30}, - {0, 21, 38}, - {0, 39, 31}, - {0, 41, 40}, - {0, 13, 42}, - {0, 43, 26}, - {0, 10, 44}, - {0, 28, 45}, - {0, 35, 18}, - {0, 20, 46}, - {0, 33, 47}, - {0, 24, 48}, - {0, 6, 49}, - {0, 3, 50}, - {0, 16, 51}, - {0, 27, 52}, - {0, 53, 1}, - {0, 9, 17}, - {0, 29, 54}, - {0, 19, 2}, - {0, 8, 36}, - {0, 55, 34}, - {0, 25, 56}, - {0, 7, 57}, - {0, 5, 58}, - {0, 60, 59}, - {0, 61, 15}, - {0, 63, 62}, - {0, 65, 64}, - {0, 66, 11}, - {0, 12, 67}, - {0, 69, 68}, - {0, 14, 70}, - })); - - codecs.emplace(SpvOpVariable, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(5, { - {0, 0, 0}, - {131134, 0, 0}, - {196669, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 3}, - {0, 2, 4}, - })); - - codecs.emplace(SpvOpAccessChain, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(73, { - {0, 0, 0}, - {252, 0, 0}, - {253, 0, 0}, - {65785, 0, 0}, - {65790, 0, 0}, - {131073, 0, 0}, - {131134, 0, 0}, - {131319, 0, 0}, - {196665, 0, 0}, - {196667, 0, 0}, - {196669, 0, 0}, - {196735, 0, 0}, - {196854, 0, 0}, - {262201, 0, 0}, - {262209, 0, 0}, - {262221, 0, 0}, - {262225, 0, 0}, - {262272, 0, 0}, - {262273, 0, 0}, - {262275, 0, 0}, - {262276, 0, 0}, - {262277, 0, 0}, - {262280, 0, 0}, - {262286, 0, 0}, - {262292, 0, 0}, - {262321, 0, 0}, - {327692, 0, 0}, - {327745, 0, 0}, - {327761, 0, 0}, - {327762, 0, 0}, - {393228, 0, 0}, - {393295, 0, 0}, - {393296, 0, 0}, - {393298, 0, 0}, - {393461, 0, 0}, - {458831, 0, 0}, - {524367, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 28, 5}, - {0, 30, 8}, - {0, 13, 38}, - {0, 40, 39}, - {0, 41, 26}, - {0, 42, 19}, - {0, 43, 29}, - {0, 23, 44}, - {0, 36, 32}, - {0, 45, 22}, - {0, 2, 46}, - {0, 21, 20}, - {0, 48, 47}, - {0, 33, 49}, - {0, 4, 50}, - {0, 51, 24}, - {0, 18, 11}, - {0, 52, 12}, - {0, 25, 15}, - {0, 53, 17}, - {0, 37, 54}, - {0, 55, 35}, - {0, 7, 27}, - {0, 57, 56}, - {0, 58, 31}, - {0, 6, 59}, - {0, 1, 60}, - {0, 62, 61}, - {0, 63, 14}, - {0, 3, 16}, - {0, 34, 64}, - {0, 66, 65}, - {0, 68, 67}, - {0, 70, 69}, - {0, 10, 9}, - {0, 72, 71}, - })); - - codecs.emplace(SpvOpLabel, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(5, { - {0, 0, 0}, - {56, 0, 0}, - {65784, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 3, 2}, - {0, 1, 4}, - })); - - codecs.emplace(SpvOpReturn, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(5, { - {0, 0, 0}, - {65784, 0, 0}, - {131127, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 3}, - {0, 2, 4}, - })); - - codecs.emplace(SpvOpFunction, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(31, { - {0, 0, 0}, - {65556, 0, 0}, - {196629, 0, 0}, - {196631, 0, 0}, - {196632, 0, 0}, - {196636, 0, 0}, - {196640, 0, 0}, - {196641, 0, 0}, - {196651, 0, 0}, - {196667, 0, 0}, - {262177, 0, 0}, - {262188, 0, 0}, - {262198, 0, 0}, - {327713, 0, 0}, - {393260, 0, 0}, - {524313, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 12, 1}, - {0, 13, 5}, - {0, 18, 17}, - {0, 7, 19}, - {0, 9, 20}, - {0, 16, 21}, - {0, 15, 10}, - {0, 22, 4}, - {0, 24, 23}, - {0, 25, 14}, - {0, 8, 11}, - {0, 2, 26}, - {0, 28, 27}, - {0, 3, 6}, - {0, 30, 29}, - })); - - codecs.emplace(SpvOpTypeVector, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(5, { - {0, 0, 0}, - {65784, 0, 0}, - {131127, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 2, 3}, - {0, 4, 1}, - })); - - codecs.emplace(SpvOpFunctionParameter, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(5, { - {0, 0, 0}, - {56, 0, 0}, - {65784, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 3, 2}, - {0, 1, 4}, - })); - - codecs.emplace(SpvOpReturnValue, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {131105, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(SpvOpTypeVoid, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(89, { - {0, 0, 0}, - {253, 0, 0}, - {65785, 0, 0}, - {65790, 0, 0}, - {131134, 0, 0}, - {131319, 0, 0}, - {196665, 0, 0}, - {196669, 0, 0}, - {196735, 0, 0}, - {262201, 0, 0}, - {262209, 0, 0}, - {262224, 0, 0}, - {262225, 0, 0}, - {262272, 0, 0}, - {262273, 0, 0}, - {262275, 0, 0}, - {262277, 0, 0}, - {262280, 0, 0}, - {262286, 0, 0}, - {262288, 0, 0}, - {262292, 0, 0}, - {327692, 0, 0}, - {327737, 0, 0}, - {327745, 0, 0}, - {327760, 0, 0}, - {327761, 0, 0}, - {327762, 0, 0}, - {393228, 0, 0}, - {393273, 0, 0}, - {393281, 0, 0}, - {393295, 0, 0}, - {393296, 0, 0}, - {458764, 0, 0}, - {458809, 0, 0}, - {458831, 0, 0}, - {524345, 0, 0}, - {524367, 0, 0}, - {589881, 0, 0}, - {655417, 0, 0}, - {720953, 0, 0}, - {786489, 0, 0}, - {852025, 0, 0}, - {917561, 0, 0}, - {983097, 0, 0}, - {1114169, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 40, 32}, - {0, 46, 29}, - {0, 38, 27}, - {0, 20, 47}, - {0, 49, 48}, - {0, 50, 44}, - {0, 51, 43}, - {0, 14, 5}, - {0, 42, 52}, - {0, 13, 19}, - {0, 3, 26}, - {0, 54, 53}, - {0, 56, 55}, - {0, 57, 6}, - {0, 39, 37}, - {0, 15, 58}, - {0, 18, 31}, - {0, 59, 21}, - {0, 60, 17}, - {0, 61, 41}, - {0, 62, 24}, - {0, 34, 63}, - {0, 35, 64}, - {0, 65, 8}, - {0, 66, 36}, - {0, 67, 30}, - {0, 16, 11}, - {0, 69, 68}, - {0, 70, 28}, - {0, 22, 71}, - {0, 33, 72}, - {0, 45, 73}, - {0, 75, 74}, - {0, 77, 76}, - {0, 78, 12}, - {0, 1, 2}, - {0, 9, 79}, - {0, 25, 80}, - {0, 23, 81}, - {0, 4, 82}, - {0, 84, 83}, - {0, 86, 85}, - {0, 7, 10}, - {0, 88, 87}, - })); - - codecs.emplace(SpvOpStore, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(13, { - {0, 0, 0}, - {131075, 0, 0}, - {131088, 0, 0}, - {131143, 0, 0}, - {196624, 0, 0}, - {196679, 0, 0}, - {262216, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 3, 4}, - {0, 1, 8}, - {0, 7, 9}, - {0, 6, 10}, - {0, 5, 11}, - {0, 2, 12}, - })); - - codecs.emplace(SpvOpEntryPoint, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(97, { - {0, 0, 0}, - {65785, 0, 0}, - {65790, 0, 0}, - {131134, 0, 0}, - {131319, 0, 0}, - {196665, 0, 0}, - {196669, 0, 0}, - {196732, 0, 0}, - {196735, 0, 0}, - {262201, 0, 0}, - {262209, 0, 0}, - {262224, 0, 0}, - {262225, 0, 0}, - {262230, 0, 0}, - {262231, 0, 0}, - {262272, 0, 0}, - {262273, 0, 0}, - {262275, 0, 0}, - {262276, 0, 0}, - {262277, 0, 0}, - {262280, 0, 0}, - {262286, 0, 0}, - {262288, 0, 0}, - {262292, 0, 0}, - {262326, 0, 0}, - {262328, 0, 0}, - {262330, 0, 0}, - {327692, 0, 0}, - {327737, 0, 0}, - {327745, 0, 0}, - {327760, 0, 0}, - {327761, 0, 0}, - {327762, 0, 0}, - {393228, 0, 0}, - {393273, 0, 0}, - {393281, 0, 0}, - {393295, 0, 0}, - {393296, 0, 0}, - {393297, 0, 0}, - {393304, 0, 0}, - {458764, 0, 0}, - {458809, 0, 0}, - {458817, 0, 0}, - {458831, 0, 0}, - {458840, 0, 0}, - {524345, 0, 0}, - {524367, 0, 0}, - {589881, 0, 0}, - {720953, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 42, 47}, - {0, 48, 50}, - {0, 45, 51}, - {0, 34, 52}, - {0, 53, 41}, - {0, 1, 54}, - {0, 55, 5}, - {0, 15, 4}, - {0, 56, 35}, - {0, 26, 24}, - {0, 18, 28}, - {0, 57, 38}, - {0, 59, 58}, - {0, 60, 25}, - {0, 20, 9}, - {0, 7, 61}, - {0, 62, 22}, - {0, 11, 31}, - {0, 63, 8}, - {0, 64, 40}, - {0, 66, 65}, - {0, 27, 44}, - {0, 29, 67}, - {0, 68, 39}, - {0, 69, 2}, - {0, 37, 49}, - {0, 71, 70}, - {0, 30, 72}, - {0, 73, 17}, - {0, 33, 74}, - {0, 23, 14}, - {0, 32, 75}, - {0, 21, 76}, - {0, 77, 16}, - {0, 46, 78}, - {0, 13, 79}, - {0, 80, 12}, - {0, 19, 81}, - {0, 43, 36}, - {0, 83, 82}, - {0, 10, 84}, - {0, 85, 3}, - {0, 6, 86}, - {0, 88, 87}, - {0, 90, 89}, - {0, 92, 91}, - {0, 94, 93}, - {0, 96, 95}, - })); - - codecs.emplace(SpvOpLoad, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(47, { - {0, 0, 0}, - {262159, 0, 0}, - {327695, 0, 0}, - {393231, 0, 0}, - {458767, 0, 0}, - {524303, 0, 0}, - {589839, 0, 0}, - {655375, 0, 0}, - {720911, 0, 0}, - {786447, 0, 0}, - {851983, 0, 0}, - {917519, 0, 0}, - {983055, 0, 0}, - {1048591, 0, 0}, - {1114127, 0, 0}, - {1179663, 0, 0}, - {1245199, 0, 0}, - {1310735, 0, 0}, - {1376271, 0, 0}, - {1441807, 0, 0}, - {1507343, 0, 0}, - {1572879, 0, 0}, - {1638415, 0, 0}, - {1703951, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 23}, - {0, 22, 25}, - {0, 21, 26}, - {0, 6, 20}, - {0, 19, 27}, - {0, 29, 28}, - {0, 24, 18}, - {0, 30, 13}, - {0, 31, 14}, - {0, 32, 7}, - {0, 17, 15}, - {0, 33, 2}, - {0, 34, 8}, - {0, 16, 12}, - {0, 35, 3}, - {0, 36, 5}, - {0, 9, 37}, - {0, 39, 38}, - {0, 11, 40}, - {0, 4, 10}, - {0, 42, 41}, - {0, 44, 43}, - {0, 46, 45}, - })); - - codecs.emplace(SpvOpMemoryModel, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(7, { - {0, 0, 0}, - {196631, 0, 0}, - {196640, 0, 0}, - {196641, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 2, 3}, - {0, 4, 5}, - {0, 1, 6}, - })); - - codecs.emplace(SpvOpTypeFloat, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(69, { - {0, 0, 0}, - {65790, 0, 0}, - {131134, 0, 0}, - {196669, 0, 0}, - {196735, 0, 0}, - {262201, 0, 0}, - {262209, 0, 0}, - {262224, 0, 0}, - {262225, 0, 0}, - {262231, 0, 0}, - {262272, 0, 0}, - {262273, 0, 0}, - {262275, 0, 0}, - {262277, 0, 0}, - {262280, 0, 0}, - {262286, 0, 0}, - {262288, 0, 0}, - {262289, 0, 0}, - {262292, 0, 0}, - {327692, 0, 0}, - {327745, 0, 0}, - {327760, 0, 0}, - {327761, 0, 0}, - {327762, 0, 0}, - {327849, 0, 0}, - {393228, 0, 0}, - {393281, 0, 0}, - {393295, 0, 0}, - {393296, 0, 0}, - {393304, 0, 0}, - {458764, 0, 0}, - {458809, 0, 0}, - {458831, 0, 0}, - {524345, 0, 0}, - {524367, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 33, 10}, - {0, 31, 36}, - {0, 26, 37}, - {0, 5, 38}, - {0, 20, 39}, - {0, 22, 40}, - {0, 24, 25}, - {0, 15, 41}, - {0, 9, 17}, - {0, 1, 42}, - {0, 4, 43}, - {0, 35, 44}, - {0, 34, 45}, - {0, 19, 46}, - {0, 7, 29}, - {0, 16, 47}, - {0, 48, 32}, - {0, 49, 27}, - {0, 11, 14}, - {0, 18, 28}, - {0, 23, 50}, - {0, 51, 12}, - {0, 52, 21}, - {0, 6, 53}, - {0, 55, 54}, - {0, 57, 56}, - {0, 3, 58}, - {0, 13, 59}, - {0, 60, 8}, - {0, 30, 61}, - {0, 62, 2}, - {0, 64, 63}, - {0, 66, 65}, - {0, 68, 67}, - })); - - codecs.emplace(SpvOpCompositeConstruct, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(39, { - {0, 0, 0}, - {65556, 0, 0}, - {131094, 0, 0}, - {131105, 0, 0}, - {196629, 0, 0}, - {196631, 0, 0}, - {196632, 0, 0}, - {196640, 0, 0}, - {196641, 0, 0}, - {262177, 0, 0}, - {327713, 0, 0}, - {393249, 0, 0}, - {458785, 0, 0}, - {524313, 0, 0}, - {524321, 0, 0}, - {589857, 0, 0}, - {655393, 0, 0}, - {786465, 0, 0}, - {917537, 0, 0}, - {1048609, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 19, 18}, - {0, 21, 15}, - {0, 1, 22}, - {0, 16, 23}, - {0, 14, 24}, - {0, 20, 25}, - {0, 13, 17}, - {0, 3, 26}, - {0, 6, 11}, - {0, 27, 12}, - {0, 4, 28}, - {0, 29, 10}, - {0, 9, 30}, - {0, 7, 31}, - {0, 33, 32}, - {0, 34, 5}, - {0, 8, 35}, - {0, 2, 36}, - {0, 38, 37}, - })); - - codecs.emplace(SpvOpTypeFunction, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {131086, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(SpvOpExtInstImport, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(5, { - {0, 0, 0}, - {131099, 0, 0}, - {196640, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 2, 3}, - {0, 1, 4}, - })); - - codecs.emplace(SpvOpTypeImage, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(9, { - {0, 0, 0}, - {131143, 0, 0}, - {196679, 0, 0}, - {196680, 0, 0}, - {262216, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 5, 2}, - {0, 3, 6}, - {0, 7, 1}, - {0, 4, 8}, - })); - - codecs.emplace(SpvOpMemberDecorate, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(5, { - {0, 0, 0}, - {65553, 0, 0}, - {131083, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 3}, - {0, 2, 4}, - })); - - codecs.emplace(SpvOpCapability, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(17, { - {0, 0, 0}, - {196629, 0, 0}, - {196631, 0, 0}, - {196632, 0, 0}, - {196640, 0, 0}, - {196651, 0, 0}, - {196667, 0, 0}, - {327713, 0, 0}, - {458785, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 7, 8}, - {0, 1, 10}, - {0, 6, 11}, - {0, 9, 12}, - {0, 4, 13}, - {0, 3, 14}, - {0, 15, 2}, - {0, 5, 16}, - })); - - codecs.emplace(SpvOpTypeInt, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(29, { - {0, 0, 0}, - {65556, 0, 0}, - {131073, 0, 0}, - {196629, 0, 0}, - {196631, 0, 0}, - {196632, 0, 0}, - {196636, 0, 0}, - {196640, 0, 0}, - {196651, 0, 0}, - {196667, 0, 0}, - {262188, 0, 0}, - {262198, 0, 0}, - {327724, 0, 0}, - {393260, 0, 0}, - {524313, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 2, 6}, - {0, 16, 3}, - {0, 11, 17}, - {0, 5, 18}, - {0, 15, 19}, - {0, 13, 20}, - {0, 1, 4}, - {0, 12, 21}, - {0, 7, 22}, - {0, 14, 23}, - {0, 24, 10}, - {0, 25, 9}, - {0, 27, 26}, - {0, 8, 28}, - })); - - codecs.emplace(SpvOpConstantComposite, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(15, { - {0, 0, 0}, - {65556, 0, 0}, - {196631, 0, 0}, - {196640, 0, 0}, - {196651, 0, 0}, - {196667, 0, 0}, - {327724, 0, 0}, - {393260, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 6, 7}, - {0, 1, 9}, - {0, 10, 8}, - {0, 2, 11}, - {0, 5, 12}, - {0, 13, 4}, - {0, 3, 14}, - })); - - codecs.emplace(SpvOpTypeSampledImage, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(21, { - {0, 0, 0}, - {131073, 0, 0}, - {196629, 0, 0}, - {196631, 0, 0}, - {196632, 0, 0}, - {196636, 0, 0}, - {196640, 0, 0}, - {196641, 0, 0}, - {196651, 0, 0}, - {196667, 0, 0}, - {262198, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 3, 5}, - {0, 11, 12}, - {0, 8, 13}, - {0, 7, 14}, - {0, 4, 10}, - {0, 9, 2}, - {0, 16, 15}, - {0, 1, 17}, - {0, 19, 18}, - {0, 6, 20}, - })); - - codecs.emplace(SpvOpTypeStruct, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(49, { - {0, 0, 0}, - {65785, 0, 0}, - {65790, 0, 0}, - {131134, 0, 0}, - {196669, 0, 0}, - {196735, 0, 0}, - {262201, 0, 0}, - {262209, 0, 0}, - {262224, 0, 0}, - {262225, 0, 0}, - {262272, 0, 0}, - {262273, 0, 0}, - {262275, 0, 0}, - {262277, 0, 0}, - {262286, 0, 0}, - {262292, 0, 0}, - {327692, 0, 0}, - {327745, 0, 0}, - {327760, 0, 0}, - {327762, 0, 0}, - {393228, 0, 0}, - {393295, 0, 0}, - {393296, 0, 0}, - {458764, 0, 0}, - {458831, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 20, 12}, - {0, 26, 24}, - {0, 21, 27}, - {0, 28, 16}, - {0, 10, 8}, - {0, 30, 29}, - {0, 31, 17}, - {0, 32, 13}, - {0, 25, 6}, - {0, 1, 33}, - {0, 14, 11}, - {0, 3, 34}, - {0, 18, 35}, - {0, 37, 36}, - {0, 23, 5}, - {0, 38, 2}, - {0, 39, 7}, - {0, 4, 9}, - {0, 40, 19}, - {0, 42, 41}, - {0, 43, 22}, - {0, 45, 44}, - {0, 46, 15}, - {0, 48, 47}, - })); - - codecs.emplace(SpvOpFNegate, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(11, { - {0, 0, 0}, - {65555, 0, 0}, - {131143, 0, 0}, - {196679, 0, 0}, - {196680, 0, 0}, - {262216, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 4, 6}, - {0, 1, 2}, - {0, 8, 7}, - {0, 5, 9}, - {0, 3, 10}, - })); - - codecs.emplace(SpvOpDecorate, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(25, { - {0, 0, 0}, - {65562, 0, 0}, - {196629, 0, 0}, - {196631, 0, 0}, - {196632, 0, 0}, - {196636, 0, 0}, - {196640, 0, 0}, - {196641, 0, 0}, - {196651, 0, 0}, - {196667, 0, 0}, - {262177, 0, 0}, - {262198, 0, 0}, - {327713, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 12, 11}, - {0, 9, 14}, - {0, 10, 15}, - {0, 13, 16}, - {0, 4, 17}, - {0, 2, 1}, - {0, 18, 7}, - {0, 20, 19}, - {0, 21, 3}, - {0, 22, 6}, - {0, 5, 8}, - {0, 24, 23}, - })); - - codecs.emplace(SpvOpTypeMatrix, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(31, { - {0, 0, 0}, - {65556, 0, 0}, - {131073, 0, 0}, - {131094, 0, 0}, - {196629, 0, 0}, - {196631, 0, 0}, - {196632, 0, 0}, - {196636, 0, 0}, - {196640, 0, 0}, - {196651, 0, 0}, - {196667, 0, 0}, - {262188, 0, 0}, - {262198, 0, 0}, - {327724, 0, 0}, - {393260, 0, 0}, - {524313, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 12, 2}, - {0, 17, 3}, - {0, 5, 18}, - {0, 1, 19}, - {0, 16, 4}, - {0, 21, 20}, - {0, 6, 15}, - {0, 7, 22}, - {0, 24, 23}, - {0, 13, 14}, - {0, 25, 8}, - {0, 26, 11}, - {0, 27, 10}, - {0, 29, 28}, - {0, 30, 9}, - })); - - codecs.emplace(SpvOpConstant, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(33, { - {0, 0, 0}, - {131113, 0, 0}, - {196629, 0, 0}, - {196631, 0, 0}, - {196632, 0, 0}, - {196640, 0, 0}, - {196641, 0, 0}, - {196651, 0, 0}, - {196667, 0, 0}, - {262188, 0, 0}, - {262198, 0, 0}, - {327713, 0, 0}, - {327724, 0, 0}, - {393249, 0, 0}, - {393260, 0, 0}, - {524313, 0, 0}, - {524321, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 6, 4}, - {0, 13, 11}, - {0, 16, 15}, - {0, 18, 10}, - {0, 20, 19}, - {0, 21, 2}, - {0, 23, 22}, - {0, 8, 24}, - {0, 9, 25}, - {0, 17, 26}, - {0, 14, 27}, - {0, 12, 28}, - {0, 1, 3}, - {0, 5, 29}, - {0, 30, 7}, - {0, 32, 31}, - })); - - codecs.emplace(SpvOpTypeBool, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(11, { - {0, 0, 0}, - {196636, 0, 0}, - {196640, 0, 0}, - {196651, 0, 0}, - {196667, 0, 0}, - {524313, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 4, 5}, - {0, 3, 7}, - {0, 2, 8}, - {0, 6, 9}, - {0, 1, 10}, - })); - - codecs.emplace(SpvOpTypeArray, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(67, { - {0, 0, 0}, - {65785, 0, 0}, - {65790, 0, 0}, - {131134, 0, 0}, - {131319, 0, 0}, - {196669, 0, 0}, - {196735, 0, 0}, - {262201, 0, 0}, - {262209, 0, 0}, - {262224, 0, 0}, - {262225, 0, 0}, - {262231, 0, 0}, - {262272, 0, 0}, - {262273, 0, 0}, - {262275, 0, 0}, - {262277, 0, 0}, - {262280, 0, 0}, - {262286, 0, 0}, - {262292, 0, 0}, - {262334, 0, 0}, - {327692, 0, 0}, - {327737, 0, 0}, - {327745, 0, 0}, - {327760, 0, 0}, - {327761, 0, 0}, - {327762, 0, 0}, - {393228, 0, 0}, - {393273, 0, 0}, - {393281, 0, 0}, - {393295, 0, 0}, - {393296, 0, 0}, - {458764, 0, 0}, - {458831, 0, 0}, - {524367, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 7, 27}, - {0, 11, 28}, - {0, 35, 21}, - {0, 36, 1}, - {0, 4, 37}, - {0, 39, 38}, - {0, 40, 30}, - {0, 41, 12}, - {0, 19, 42}, - {0, 13, 43}, - {0, 16, 44}, - {0, 45, 22}, - {0, 34, 18}, - {0, 29, 24}, - {0, 46, 25}, - {0, 6, 2}, - {0, 9, 31}, - {0, 17, 47}, - {0, 49, 48}, - {0, 50, 33}, - {0, 51, 26}, - {0, 20, 52}, - {0, 32, 53}, - {0, 3, 54}, - {0, 15, 14}, - {0, 23, 55}, - {0, 8, 56}, - {0, 58, 57}, - {0, 10, 59}, - {0, 5, 60}, - {0, 62, 61}, - {0, 64, 63}, - {0, 66, 65}, - })); - - codecs.emplace(SpvOpExtInst, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(57, { - {0, 0, 0}, - {65790, 0, 0}, - {131134, 0, 0}, - {196665, 0, 0}, - {196669, 0, 0}, - {196718, 0, 0}, - {262201, 0, 0}, - {262209, 0, 0}, - {262224, 0, 0}, - {262225, 0, 0}, - {262231, 0, 0}, - {262273, 0, 0}, - {262275, 0, 0}, - {262277, 0, 0}, - {262280, 0, 0}, - {262286, 0, 0}, - {262292, 0, 0}, - {327692, 0, 0}, - {327745, 0, 0}, - {327760, 0, 0}, - {327762, 0, 0}, - {393228, 0, 0}, - {393273, 0, 0}, - {393295, 0, 0}, - {393296, 0, 0}, - {393303, 0, 0}, - {458764, 0, 0}, - {458831, 0, 0}, - {524367, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 18, 6}, - {0, 30, 22}, - {0, 31, 25}, - {0, 10, 32}, - {0, 21, 33}, - {0, 3, 34}, - {0, 35, 5}, - {0, 23, 36}, - {0, 14, 17}, - {0, 37, 26}, - {0, 1, 38}, - {0, 29, 39}, - {0, 13, 40}, - {0, 41, 19}, - {0, 28, 20}, - {0, 16, 42}, - {0, 27, 43}, - {0, 8, 24}, - {0, 7, 44}, - {0, 9, 45}, - {0, 15, 46}, - {0, 12, 47}, - {0, 48, 2}, - {0, 4, 49}, - {0, 51, 50}, - {0, 11, 52}, - {0, 54, 53}, - {0, 56, 55}, - })); - - codecs.emplace(SpvOpVectorTimesScalar, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(67, { - {0, 0, 0}, - {65785, 0, 0}, - {65790, 0, 0}, - {131134, 0, 0}, - {196669, 0, 0}, - {196735, 0, 0}, - {262201, 0, 0}, - {262209, 0, 0}, - {262224, 0, 0}, - {262225, 0, 0}, - {262230, 0, 0}, - {262231, 0, 0}, - {262272, 0, 0}, - {262273, 0, 0}, - {262275, 0, 0}, - {262277, 0, 0}, - {262280, 0, 0}, - {262286, 0, 0}, - {262292, 0, 0}, - {327692, 0, 0}, - {327737, 0, 0}, - {327745, 0, 0}, - {327760, 0, 0}, - {327761, 0, 0}, - {327762, 0, 0}, - {393228, 0, 0}, - {393273, 0, 0}, - {393295, 0, 0}, - {393296, 0, 0}, - {393303, 0, 0}, - {393304, 0, 0}, - {458764, 0, 0}, - {458831, 0, 0}, - {524367, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 26, 29}, - {0, 20, 35}, - {0, 12, 36}, - {0, 6, 37}, - {0, 38, 28}, - {0, 30, 5}, - {0, 8, 39}, - {0, 2, 40}, - {0, 41, 21}, - {0, 1, 10}, - {0, 43, 42}, - {0, 23, 16}, - {0, 44, 33}, - {0, 34, 31}, - {0, 14, 45}, - {0, 19, 46}, - {0, 25, 47}, - {0, 49, 48}, - {0, 27, 22}, - {0, 7, 50}, - {0, 17, 32}, - {0, 18, 51}, - {0, 24, 52}, - {0, 54, 53}, - {0, 55, 9}, - {0, 56, 11}, - {0, 57, 4}, - {0, 15, 58}, - {0, 59, 13}, - {0, 60, 3}, - {0, 62, 61}, - {0, 64, 63}, - {0, 66, 65}, - })); - - codecs.emplace(SpvOpVectorShuffle, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(33, { - {0, 0, 0}, - {65790, 0, 0}, - {131134, 0, 0}, - {196669, 0, 0}, - {262201, 0, 0}, - {262209, 0, 0}, - {262225, 0, 0}, - {262231, 0, 0}, - {262273, 0, 0}, - {262277, 0, 0}, - {262286, 0, 0}, - {262292, 0, 0}, - {327745, 0, 0}, - {393281, 0, 0}, - {393295, 0, 0}, - {393296, 0, 0}, - {458831, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 13, 12}, - {0, 1, 18}, - {0, 19, 11}, - {0, 9, 20}, - {0, 10, 21}, - {0, 22, 15}, - {0, 23, 8}, - {0, 4, 24}, - {0, 25, 7}, - {0, 17, 26}, - {0, 5, 27}, - {0, 14, 3}, - {0, 29, 28}, - {0, 30, 2}, - {0, 6, 31}, - {0, 32, 16}, - })); - - codecs.emplace(SpvOpImageSampleImplicitLod, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(55, { - {0, 0, 0}, - {65785, 0, 0}, - {65790, 0, 0}, - {131134, 0, 0}, - {196669, 0, 0}, - {196735, 0, 0}, - {196817, 0, 0}, - {262209, 0, 0}, - {262224, 0, 0}, - {262225, 0, 0}, - {262273, 0, 0}, - {262275, 0, 0}, - {262277, 0, 0}, - {262280, 0, 0}, - {262286, 0, 0}, - {262292, 0, 0}, - {327692, 0, 0}, - {327745, 0, 0}, - {327760, 0, 0}, - {327761, 0, 0}, - {327762, 0, 0}, - {393228, 0, 0}, - {393281, 0, 0}, - {393295, 0, 0}, - {393296, 0, 0}, - {393298, 0, 0}, - {458764, 0, 0}, - {458831, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 5, 2}, - {0, 22, 29}, - {0, 30, 1}, - {0, 6, 31}, - {0, 9, 32}, - {0, 28, 3}, - {0, 27, 33}, - {0, 20, 16}, - {0, 34, 8}, - {0, 10, 35}, - {0, 4, 36}, - {0, 24, 23}, - {0, 21, 13}, - {0, 7, 37}, - {0, 38, 14}, - {0, 25, 39}, - {0, 17, 11}, - {0, 12, 19}, - {0, 41, 40}, - {0, 42, 18}, - {0, 15, 43}, - {0, 45, 44}, - {0, 47, 46}, - {0, 26, 48}, - {0, 50, 49}, - {0, 52, 51}, - {0, 54, 53}, - })); - - codecs.emplace(SpvOpDot, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(11, { - {0, 0, 0}, - {131075, 0, 0}, - {131088, 0, 0}, - {196624, 0, 0}, - {196679, 0, 0}, - {262216, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 5, 3}, - {0, 2, 7}, - {0, 1, 8}, - {0, 6, 9}, - {0, 4, 10}, - })); - - codecs.emplace(SpvOpExecutionMode, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {196858, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(SpvOpSelectionMerge, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(23, { - {0, 0, 0}, - {131134, 0, 0}, - {196669, 0, 0}, - {262209, 0, 0}, - {262224, 0, 0}, - {262225, 0, 0}, - {262277, 0, 0}, - {327745, 0, 0}, - {327761, 0, 0}, - {327762, 0, 0}, - {393295, 0, 0}, - {393296, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 2, 12}, - {0, 7, 13}, - {0, 5, 1}, - {0, 4, 10}, - {0, 14, 6}, - {0, 16, 15}, - {0, 17, 11}, - {0, 3, 8}, - {0, 19, 18}, - {0, 9, 20}, - {0, 22, 21}, - })); - - codecs.emplace(SpvOpImageSampleDrefExplicitLod, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(7, { - {0, 0, 0}, - {65790, 0, 0}, - {131073, 0, 0}, - {262198, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 4, 1}, - {0, 3, 5}, - {0, 2, 6}, - })); - - codecs.emplace(SpvOpUndef, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(59, { - {0, 0, 0}, - {65785, 0, 0}, - {131134, 0, 0}, - {131319, 0, 0}, - {196669, 0, 0}, - {196735, 0, 0}, - {262209, 0, 0}, - {262221, 0, 0}, - {262224, 0, 0}, - {262225, 0, 0}, - {262230, 0, 0}, - {262273, 0, 0}, - {262275, 0, 0}, - {262277, 0, 0}, - {262280, 0, 0}, - {262286, 0, 0}, - {262288, 0, 0}, - {262292, 0, 0}, - {262334, 0, 0}, - {327692, 0, 0}, - {327760, 0, 0}, - {327761, 0, 0}, - {327762, 0, 0}, - {393228, 0, 0}, - {393295, 0, 0}, - {393296, 0, 0}, - {393298, 0, 0}, - {458764, 0, 0}, - {458831, 0, 0}, - {524367, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 17, 3}, - {0, 5, 31}, - {0, 11, 32}, - {0, 33, 12}, - {0, 34, 20}, - {0, 16, 27}, - {0, 35, 23}, - {0, 37, 36}, - {0, 14, 18}, - {0, 39, 38}, - {0, 7, 30}, - {0, 8, 25}, - {0, 40, 15}, - {0, 13, 2}, - {0, 1, 29}, - {0, 19, 41}, - {0, 43, 42}, - {0, 28, 44}, - {0, 46, 45}, - {0, 22, 21}, - {0, 47, 24}, - {0, 48, 26}, - {0, 10, 6}, - {0, 50, 49}, - {0, 52, 51}, - {0, 54, 53}, - {0, 4, 9}, - {0, 56, 55}, - {0, 58, 57}, - })); - - codecs.emplace(SpvOpCompositeInsert, std::move(codec)); - } - - return codecs; -} - -std::map>> -GetLiteralStringHuffmanCodecs() { - std::map>> codecs; - { - std::unique_ptr> codec(new HuffmanCodec(7, { - {"", 0, 0}, - {"MainPs", 0, 0}, - {"MainVs", 0, 0}, - {"kMarkvNoneOfTheAbove", 0, 0}, - {"main", 0, 0}, - {"", 2, 3}, - {"", 1, 5}, - {"", 4, 6}, - })); - - codecs.emplace(SpvOpEntryPoint, std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {"", 0, 0}, - {"GLSL.std.450", 0, 0}, - {"kMarkvNoneOfTheAbove", 0, 0}, - {"", 1, 2}, - })); - - codecs.emplace(SpvOpExtInstImport, std::move(codec)); - } - - return codecs; -} - -std::map, std::unique_ptr>> -GetNonIdWordHuffmanCodecs() { - std::map, std::unique_ptr>> codecs; - { - std::unique_ptr> codec(new HuffmanCodec(33, { - {0, 0, 0}, - {4, 0, 0}, - {8, 0, 0}, - {10, 0, 0}, - {26, 0, 0}, - {29, 0, 0}, - {31, 0, 0}, - {37, 0, 0}, - {40, 0, 0}, - {43, 0, 0}, - {46, 0, 0}, - {49, 0, 0}, - {66, 0, 0}, - {67, 0, 0}, - {68, 0, 0}, - {69, 0, 0}, - {71, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 12, 5}, - {0, 18, 13}, - {0, 3, 7}, - {0, 19, 11}, - {0, 20, 16}, - {0, 14, 17}, - {0, 21, 1}, - {0, 2, 6}, - {0, 23, 22}, - {0, 4, 24}, - {0, 26, 25}, - {0, 28, 27}, - {0, 10, 15}, - {0, 8, 9}, - {0, 30, 29}, - {0, 32, 31}, - })); - - codecs.emplace(std::pair(SpvOpExtInst, 3), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {0, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpMemoryModel, 0), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {1, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpMemoryModel, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(5, { - {0, 0, 0}, - {0, 0, 0}, - {4, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 3}, - {0, 2, 4}, - })); - - codecs.emplace(std::pair(SpvOpEntryPoint, 0), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(5, { - {0, 0, 0}, - {7, 0, 0}, - {8, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 3, 2}, - {0, 1, 4}, - })); - - codecs.emplace(std::pair(SpvOpExecutionMode, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(11, { - {0, 0, 0}, - {1, 0, 0}, - {2, 0, 0}, - {3, 0, 0}, - {4, 0, 0}, - {18, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 4, 2}, - {0, 6, 5}, - {0, 7, 1}, - {0, 3, 8}, - {0, 10, 9}, - })); - - codecs.emplace(std::pair(SpvOpExecutionMode, 2), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(5, { - {0, 0, 0}, - {1, 0, 0}, - {32, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 2, 3}, - {0, 1, 4}, - })); - - codecs.emplace(std::pair(SpvOpCapability, 0), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {32, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpTypeInt, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(5, { - {0, 0, 0}, - {0, 0, 0}, - {1, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 2, 3}, - {0, 1, 4}, - })); - - codecs.emplace(std::pair(SpvOpTypeInt, 2), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {32, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpTypeFloat, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(7, { - {0, 0, 0}, - {2, 0, 0}, - {3, 0, 0}, - {4, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 2, 4}, - {0, 1, 5}, - {0, 6, 3}, - })); - - codecs.emplace(std::pair(SpvOpTypeVector, 2), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(7, { - {0, 0, 0}, - {2, 0, 0}, - {3, 0, 0}, - {4, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 4}, - {0, 2, 5}, - {0, 3, 6}, - })); - - codecs.emplace(std::pair(SpvOpTypeMatrix, 2), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(7, { - {0, 0, 0}, - {1, 0, 0}, - {2, 0, 0}, - {3, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 3, 4}, - {0, 2, 5}, - {0, 1, 6}, - })); - - codecs.emplace(std::pair(SpvOpTypeImage, 2), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(5, { - {0, 0, 0}, - {0, 0, 0}, - {1, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 2, 3}, - {0, 1, 4}, - })); - - codecs.emplace(std::pair(SpvOpTypeImage, 3), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {0, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpTypeImage, 4), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {0, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpTypeImage, 5), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {1, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpTypeImage, 6), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {0, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpTypeImage, 7), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(13, { - {0, 0, 0}, - {0, 0, 0}, - {1, 0, 0}, - {2, 0, 0}, - {3, 0, 0}, - {6, 0, 0}, - {7, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 5, 7}, - {0, 6, 8}, - {0, 1, 4}, - {0, 2, 9}, - {0, 10, 3}, - {0, 12, 11}, - })); - - codecs.emplace(std::pair(SpvOpTypePointer, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(173, { - {0, 0, 0}, - {0, 0, 0}, - {1, 0, 0}, - {2, 0, 0}, - {3, 0, 0}, - {4, 0, 0}, - {5, 0, 0}, - {6, 0, 0}, - {7, 0, 0}, - {8, 0, 0}, - {9, 0, 0}, - {10, 0, 0}, - {11, 0, 0}, - {12, 0, 0}, - {13, 0, 0}, - {14, 0, 0}, - {15, 0, 0}, - {16, 0, 0}, - {17, 0, 0}, - {18, 0, 0}, - {19, 0, 0}, - {20, 0, 0}, - {21, 0, 0}, - {22, 0, 0}, - {23, 0, 0}, - {24, 0, 0}, - {26, 0, 0}, - {27, 0, 0}, - {28, 0, 0}, - {29, 0, 0}, - {30, 0, 0}, - {31, 0, 0}, - {32, 0, 0}, - {256, 0, 0}, - {507307272, 0, 0}, - {864026611, 0, 0}, - {981668463, 0, 0}, - {997553156, 0, 0}, - {1014330372, 0, 0}, - {1020708227, 0, 0}, - {1028443341, 0, 0}, - {1032953056, 0, 0}, - {1033463938, 0, 0}, - {1033463943, 0, 0}, - {1039998884, 0, 0}, - {1039998950, 0, 0}, - {1040187392, 0, 0}, - {1042401985, 0, 0}, - {1044220635, 0, 0}, - {1045622707, 0, 0}, - {1045622740, 0, 0}, - {1048576000, 0, 0}, - {1053609165, 0, 0}, - {1053790359, 0, 0}, - {1054448026, 0, 0}, - {1055437881, 0, 0}, - {1056300230, 0, 0}, - {1056964608, 0, 0}, - {1058056805, 0, 0}, - {1059286575, 0, 0}, - {1061158912, 0, 0}, - {1061997773, 0, 0}, - {1064514355, 0, 0}, - {1064854933, 0, 0}, - {1065353216, 0, 0}, - {1069547520, 0, 0}, - {1073741824, 0, 0}, - {1077936128, 0, 0}, - {1082130432, 0, 0}, - {1091567616, 0, 0}, - {1115422720, 0, 0}, - {1124073472, 0, 0}, - {1132396544, 0, 0}, - {1140850688, 0, 0}, - {1199562752, 0, 0}, - {3179067684, 0, 0}, - {3180973575, 0, 0}, - {3182651297, 0, 0}, - {3196448879, 0, 0}, - {3204448256, 0, 0}, - {3204993516, 0, 0}, - {3205248529, 0, 0}, - {3207137644, 0, 0}, - {3208642560, 0, 0}, - {3211081967, 0, 0}, - {3212836864, 0, 0}, - {3332128768, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 38, 37}, - {0, 42, 39}, - {0, 49, 44}, - {0, 45, 43}, - {0, 26, 50}, - {0, 46, 73}, - {0, 35, 28}, - {0, 32, 65}, - {0, 83, 40}, - {0, 60, 62}, - {0, 27, 54}, - {0, 79, 67}, - {0, 31, 74}, - {0, 51, 12}, - {0, 70, 30}, - {0, 15, 16}, - {0, 88, 25}, - {0, 90, 89}, - {0, 34, 71}, - {0, 72, 29}, - {0, 92, 91}, - {0, 14, 33}, - {0, 94, 93}, - {0, 22, 23}, - {0, 21, 95}, - {0, 19, 24}, - {0, 96, 13}, - {0, 47, 41}, - {0, 53, 48}, - {0, 58, 56}, - {0, 63, 59}, - {0, 76, 75}, - {0, 78, 77}, - {0, 81, 80}, - {0, 84, 82}, - {0, 52, 20}, - {0, 97, 69}, - {0, 99, 98}, - {0, 18, 10}, - {0, 68, 61}, - {0, 17, 100}, - {0, 102, 101}, - {0, 11, 36}, - {0, 104, 103}, - {0, 86, 105}, - {0, 107, 106}, - {0, 109, 108}, - {0, 110, 9}, - {0, 8, 111}, - {0, 113, 112}, - {0, 115, 114}, - {0, 117, 116}, - {0, 119, 118}, - {0, 121, 120}, - {0, 123, 122}, - {0, 125, 124}, - {0, 126, 7}, - {0, 127, 85}, - {0, 6, 128}, - {0, 129, 55}, - {0, 130, 5}, - {0, 132, 131}, - {0, 134, 133}, - {0, 136, 135}, - {0, 137, 66}, - {0, 139, 138}, - {0, 141, 140}, - {0, 143, 142}, - {0, 145, 144}, - {0, 146, 57}, - {0, 147, 64}, - {0, 148, 4}, - {0, 149, 2}, - {0, 151, 150}, - {0, 152, 3}, - {0, 154, 153}, - {0, 156, 155}, - {0, 158, 157}, - {0, 159, 1}, - {0, 160, 87}, - {0, 162, 161}, - {0, 164, 163}, - {0, 166, 165}, - {0, 168, 167}, - {0, 170, 169}, - {0, 172, 171}, - })); - - codecs.emplace(std::pair(SpvOpConstant, 2), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {0, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpFunction, 2), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(13, { - {0, 0, 0}, - {0, 0, 0}, - {1, 0, 0}, - {2, 0, 0}, - {3, 0, 0}, - {6, 0, 0}, - {7, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 3, 7}, - {0, 4, 8}, - {0, 9, 2}, - {0, 1, 5}, - {0, 10, 6}, - {0, 12, 11}, - })); - - codecs.emplace(std::pair(SpvOpVariable, 2), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(15, { - {0, 0, 0}, - {0, 0, 0}, - {2, 0, 0}, - {6, 0, 0}, - {11, 0, 0}, - {30, 0, 0}, - {33, 0, 0}, - {34, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 4, 8}, - {0, 9, 1}, - {0, 3, 10}, - {0, 6, 11}, - {0, 12, 2}, - {0, 7, 5}, - {0, 14, 13}, - })); - - codecs.emplace(std::pair(SpvOpDecorate, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(37, { - {0, 0, 0}, - {0, 0, 0}, - {1, 0, 0}, - {2, 0, 0}, - {3, 0, 0}, - {4, 0, 0}, - {5, 0, 0}, - {6, 0, 0}, - {7, 0, 0}, - {8, 0, 0}, - {9, 0, 0}, - {10, 0, 0}, - {12, 0, 0}, - {13, 0, 0}, - {14, 0, 0}, - {15, 0, 0}, - {16, 0, 0}, - {18, 0, 0}, - {64, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 17, 11}, - {0, 10, 13}, - {0, 12, 14}, - {0, 21, 20}, - {0, 9, 22}, - {0, 19, 15}, - {0, 8, 23}, - {0, 18, 24}, - {0, 25, 7}, - {0, 5, 6}, - {0, 26, 16}, - {0, 27, 4}, - {0, 28, 3}, - {0, 30, 29}, - {0, 31, 2}, - {0, 33, 32}, - {0, 35, 34}, - {0, 1, 36}, - })); - - codecs.emplace(std::pair(SpvOpDecorate, 2), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(79, { - {0, 0, 0}, - {0, 0, 0}, - {1, 0, 0}, - {2, 0, 0}, - {3, 0, 0}, - {4, 0, 0}, - {5, 0, 0}, - {6, 0, 0}, - {7, 0, 0}, - {8, 0, 0}, - {9, 0, 0}, - {10, 0, 0}, - {11, 0, 0}, - {12, 0, 0}, - {13, 0, 0}, - {14, 0, 0}, - {15, 0, 0}, - {16, 0, 0}, - {17, 0, 0}, - {18, 0, 0}, - {19, 0, 0}, - {20, 0, 0}, - {21, 0, 0}, - {22, 0, 0}, - {23, 0, 0}, - {24, 0, 0}, - {25, 0, 0}, - {26, 0, 0}, - {27, 0, 0}, - {28, 0, 0}, - {29, 0, 0}, - {30, 0, 0}, - {31, 0, 0}, - {32, 0, 0}, - {33, 0, 0}, - {34, 0, 0}, - {35, 0, 0}, - {36, 0, 0}, - {37, 0, 0}, - {38, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 39, 37}, - {0, 40, 36}, - {0, 34, 35}, - {0, 32, 33}, - {0, 30, 31}, - {0, 27, 29}, - {0, 26, 28}, - {0, 42, 41}, - {0, 23, 25}, - {0, 38, 22}, - {0, 44, 43}, - {0, 46, 45}, - {0, 21, 47}, - {0, 19, 20}, - {0, 17, 18}, - {0, 14, 15}, - {0, 12, 10}, - {0, 16, 13}, - {0, 9, 11}, - {0, 7, 8}, - {0, 6, 5}, - {0, 24, 48}, - {0, 50, 49}, - {0, 3, 4}, - {0, 51, 2}, - {0, 1, 52}, - {0, 54, 53}, - {0, 56, 55}, - {0, 58, 57}, - {0, 60, 59}, - {0, 62, 61}, - {0, 64, 63}, - {0, 66, 65}, - {0, 68, 67}, - {0, 70, 69}, - {0, 72, 71}, - {0, 74, 73}, - {0, 76, 75}, - {0, 78, 77}, - })); - - codecs.emplace(std::pair(SpvOpMemberDecorate, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(7, { - {0, 0, 0}, - {4, 0, 0}, - {7, 0, 0}, - {35, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 4}, - {0, 5, 2}, - {0, 3, 6}, - })); - - codecs.emplace(std::pair(SpvOpMemberDecorate, 2), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(149, { - {0, 0, 0}, - {0, 0, 0}, - {16, 0, 0}, - {28, 0, 0}, - {32, 0, 0}, - {36, 0, 0}, - {40, 0, 0}, - {44, 0, 0}, - {48, 0, 0}, - {60, 0, 0}, - {64, 0, 0}, - {76, 0, 0}, - {80, 0, 0}, - {84, 0, 0}, - {88, 0, 0}, - {92, 0, 0}, - {96, 0, 0}, - {100, 0, 0}, - {108, 0, 0}, - {112, 0, 0}, - {120, 0, 0}, - {124, 0, 0}, - {128, 0, 0}, - {132, 0, 0}, - {136, 0, 0}, - {140, 0, 0}, - {144, 0, 0}, - {148, 0, 0}, - {152, 0, 0}, - {156, 0, 0}, - {160, 0, 0}, - {172, 0, 0}, - {176, 0, 0}, - {192, 0, 0}, - {204, 0, 0}, - {208, 0, 0}, - {224, 0, 0}, - {236, 0, 0}, - {240, 0, 0}, - {248, 0, 0}, - {256, 0, 0}, - {272, 0, 0}, - {288, 0, 0}, - {292, 0, 0}, - {296, 0, 0}, - {300, 0, 0}, - {304, 0, 0}, - {316, 0, 0}, - {320, 0, 0}, - {332, 0, 0}, - {336, 0, 0}, - {348, 0, 0}, - {352, 0, 0}, - {364, 0, 0}, - {368, 0, 0}, - {372, 0, 0}, - {376, 0, 0}, - {384, 0, 0}, - {392, 0, 0}, - {400, 0, 0}, - {416, 0, 0}, - {424, 0, 0}, - {432, 0, 0}, - {448, 0, 0}, - {460, 0, 0}, - {464, 0, 0}, - {468, 0, 0}, - {472, 0, 0}, - {476, 0, 0}, - {480, 0, 0}, - {488, 0, 0}, - {492, 0, 0}, - {496, 0, 0}, - {512, 0, 0}, - {640, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 14, 17}, - {0, 37, 31}, - {0, 21, 39}, - {0, 24, 23}, - {0, 5, 13}, - {0, 38, 76}, - {0, 51, 77}, - {0, 55, 53}, - {0, 58, 56}, - {0, 64, 61}, - {0, 67, 66}, - {0, 70, 68}, - {0, 54, 71}, - {0, 62, 60}, - {0, 65, 63}, - {0, 73, 72}, - {0, 59, 57}, - {0, 52, 74}, - {0, 50, 69}, - {0, 49, 47}, - {0, 48, 46}, - {0, 45, 43}, - {0, 42, 44}, - {0, 78, 41}, - {0, 20, 18}, - {0, 80, 79}, - {0, 15, 27}, - {0, 7, 34}, - {0, 81, 6}, - {0, 28, 3}, - {0, 35, 82}, - {0, 9, 36}, - {0, 84, 83}, - {0, 86, 85}, - {0, 88, 87}, - {0, 90, 89}, - {0, 92, 91}, - {0, 94, 93}, - {0, 96, 95}, - {0, 98, 97}, - {0, 11, 29}, - {0, 99, 25}, - {0, 100, 40}, - {0, 102, 101}, - {0, 26, 32}, - {0, 19, 30}, - {0, 16, 12}, - {0, 4, 8}, - {0, 104, 103}, - {0, 106, 105}, - {0, 33, 107}, - {0, 109, 108}, - {0, 111, 110}, - {0, 22, 112}, - {0, 113, 10}, - {0, 115, 114}, - {0, 75, 116}, - {0, 118, 117}, - {0, 119, 1}, - {0, 121, 120}, - {0, 123, 122}, - {0, 125, 124}, - {0, 127, 126}, - {0, 129, 128}, - {0, 131, 130}, - {0, 132, 2}, - {0, 134, 133}, - {0, 136, 135}, - {0, 138, 137}, - {0, 140, 139}, - {0, 142, 141}, - {0, 144, 143}, - {0, 146, 145}, - {0, 148, 147}, - })); - - codecs.emplace(std::pair(SpvOpMemberDecorate, 3), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(11, { - {0, 0, 0}, - {0, 0, 0}, - {1, 0, 0}, - {2, 0, 0}, - {3, 0, 0}, - {4, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 2, 6}, - {0, 4, 7}, - {0, 8, 3}, - {0, 9, 5}, - {0, 1, 10}, - })); - - codecs.emplace(std::pair(SpvOpVectorShuffle, 4), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(13, { - {0, 0, 0}, - {0, 0, 0}, - {1, 0, 0}, - {2, 0, 0}, - {3, 0, 0}, - {4, 0, 0}, - {5, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 3, 7}, - {0, 8, 5}, - {0, 9, 1}, - {0, 4, 10}, - {0, 11, 6}, - {0, 2, 12}, - })); - - codecs.emplace(std::pair(SpvOpVectorShuffle, 5), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(15, { - {0, 0, 0}, - {0, 0, 0}, - {1, 0, 0}, - {2, 0, 0}, - {3, 0, 0}, - {4, 0, 0}, - {5, 0, 0}, - {6, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 6, 8}, - {0, 5, 2}, - {0, 10, 9}, - {0, 1, 4}, - {0, 12, 11}, - {0, 7, 13}, - {0, 3, 14}, - })); - - codecs.emplace(std::pair(SpvOpVectorShuffle, 6), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(15, { - {0, 0, 0}, - {0, 0, 0}, - {1, 0, 0}, - {2, 0, 0}, - {3, 0, 0}, - {4, 0, 0}, - {5, 0, 0}, - {6, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 8, 5}, - {0, 9, 7}, - {0, 10, 3}, - {0, 11, 2}, - {0, 6, 1}, - {0, 13, 12}, - {0, 4, 14}, - })); - - codecs.emplace(std::pair(SpvOpVectorShuffle, 7), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(61, { - {0, 0, 0}, - {0, 0, 0}, - {1, 0, 0}, - {2, 0, 0}, - {3, 0, 0}, - {4, 0, 0}, - {5, 0, 0}, - {6, 0, 0}, - {7, 0, 0}, - {8, 0, 0}, - {9, 0, 0}, - {10, 0, 0}, - {11, 0, 0}, - {12, 0, 0}, - {13, 0, 0}, - {14, 0, 0}, - {15, 0, 0}, - {16, 0, 0}, - {17, 0, 0}, - {18, 0, 0}, - {19, 0, 0}, - {20, 0, 0}, - {21, 0, 0}, - {22, 0, 0}, - {23, 0, 0}, - {24, 0, 0}, - {27, 0, 0}, - {28, 0, 0}, - {29, 0, 0}, - {30, 0, 0}, - {31, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 30, 16}, - {0, 26, 27}, - {0, 29, 28}, - {0, 18, 22}, - {0, 12, 19}, - {0, 15, 20}, - {0, 14, 23}, - {0, 32, 7}, - {0, 8, 21}, - {0, 11, 33}, - {0, 17, 34}, - {0, 25, 13}, - {0, 36, 35}, - {0, 9, 10}, - {0, 38, 37}, - {0, 39, 31}, - {0, 5, 40}, - {0, 42, 41}, - {0, 44, 43}, - {0, 6, 45}, - {0, 46, 24}, - {0, 48, 47}, - {0, 50, 49}, - {0, 52, 51}, - {0, 54, 53}, - {0, 55, 4}, - {0, 56, 3}, - {0, 57, 2}, - {0, 58, 1}, - {0, 60, 59}, - })); - - codecs.emplace(std::pair(SpvOpCompositeExtract, 3), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(63, { - {0, 0, 0}, - {0, 0, 0}, - {1, 0, 0}, - {2, 0, 0}, - {3, 0, 0}, - {4, 0, 0}, - {5, 0, 0}, - {6, 0, 0}, - {7, 0, 0}, - {8, 0, 0}, - {9, 0, 0}, - {10, 0, 0}, - {11, 0, 0}, - {12, 0, 0}, - {13, 0, 0}, - {29, 0, 0}, - {30, 0, 0}, - {31, 0, 0}, - {32, 0, 0}, - {33, 0, 0}, - {34, 0, 0}, - {35, 0, 0}, - {36, 0, 0}, - {37, 0, 0}, - {38, 0, 0}, - {39, 0, 0}, - {40, 0, 0}, - {41, 0, 0}, - {42, 0, 0}, - {43, 0, 0}, - {44, 0, 0}, - {45, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 13, 14}, - {0, 12, 9}, - {0, 11, 25}, - {0, 27, 26}, - {0, 29, 28}, - {0, 31, 30}, - {0, 23, 22}, - {0, 10, 24}, - {0, 8, 21}, - {0, 17, 7}, - {0, 19, 18}, - {0, 15, 20}, - {0, 6, 16}, - {0, 5, 33}, - {0, 35, 34}, - {0, 37, 36}, - {0, 39, 38}, - {0, 41, 40}, - {0, 43, 42}, - {0, 45, 44}, - {0, 47, 46}, - {0, 49, 48}, - {0, 51, 50}, - {0, 32, 52}, - {0, 54, 53}, - {0, 56, 55}, - {0, 58, 57}, - {0, 3, 2}, - {0, 59, 4}, - {0, 60, 1}, - {0, 62, 61}, - })); - - codecs.emplace(std::pair(SpvOpCompositeExtract, 4), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(9, { - {0, 0, 0}, - {0, 0, 0}, - {1, 0, 0}, - {2, 0, 0}, - {3, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 5}, - {0, 3, 2}, - {0, 6, 4}, - {0, 8, 7}, - })); - - codecs.emplace(std::pair(SpvOpCompositeExtract, 5), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(23, { - {0, 0, 0}, - {0, 0, 0}, - {1, 0, 0}, - {2, 0, 0}, - {3, 0, 0}, - {4, 0, 0}, - {5, 0, 0}, - {6, 0, 0}, - {7, 0, 0}, - {8, 0, 0}, - {9, 0, 0}, - {10, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 12, 11}, - {0, 10, 13}, - {0, 9, 14}, - {0, 7, 5}, - {0, 8, 6}, - {0, 4, 15}, - {0, 17, 16}, - {0, 18, 3}, - {0, 19, 2}, - {0, 20, 1}, - {0, 22, 21}, - })); - - codecs.emplace(std::pair(SpvOpCompositeInsert, 4), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(9, { - {0, 0, 0}, - {0, 0, 0}, - {1, 0, 0}, - {2, 0, 0}, - {3, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 3, 5}, - {0, 2, 6}, - {0, 7, 1}, - {0, 4, 8}, - })); - - codecs.emplace(std::pair(SpvOpCompositeInsert, 5), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {1, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpImageSampleImplicitLod, 4), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(5, { - {0, 0, 0}, - {2, 0, 0}, - {10, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 2, 3}, - {0, 1, 4}, - })); - - codecs.emplace(std::pair(SpvOpImageSampleExplicitLod, 4), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {2, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpImageSampleDrefExplicitLod, 5), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {0, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpSelectionMerge, 1), std::move(codec)); - } - - return codecs; -} - -std::map, std::unique_ptr>> -GetIdDescriptorHuffmanCodecs() { - std::map, std::unique_ptr>> codecs; - { - std::unique_ptr> codec(new HuffmanCodec(9, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 3, 5}, - {0, 4, 6}, - {0, 1, 7}, - {0, 2, 8}, - })); - - codecs.emplace(std::pair(SpvOpExtInst, 0), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(63, { - {0, 0, 0}, - {34183582, 0, 0}, - {223800276, 0, 0}, - {295018543, 0, 0}, - {439764402, 0, 0}, - {443558693, 0, 0}, - {583624926, 0, 0}, - {599185303, 0, 0}, - {779021139, 0, 0}, - {1015552308, 0, 0}, - {1027242654, 0, 0}, - {1077859090, 0, 0}, - {1104362365, 0, 0}, - {1132589448, 0, 0}, - {1236389532, 0, 0}, - {1739837626, 0, 0}, - {1955104493, 0, 0}, - {2161102232, 0, 0}, - {2197874825, 0, 0}, - {2217833278, 0, 0}, - {2244470522, 0, 0}, - {2532518896, 0, 0}, - {2789375411, 0, 0}, - {3061690214, 0, 0}, - {3287039847, 0, 0}, - {3357301402, 0, 0}, - {3365041621, 0, 0}, - {3510257966, 0, 0}, - {3534235309, 0, 0}, - {4018237905, 0, 0}, - {4145966869, 0, 0}, - {4272200782, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 10, 19}, - {0, 6, 1}, - {0, 26, 13}, - {0, 2, 11}, - {0, 15, 22}, - {0, 23, 18}, - {0, 4, 27}, - {0, 28, 12}, - {0, 3, 30}, - {0, 9, 7}, - {0, 20, 14}, - {0, 29, 16}, - {0, 21, 8}, - {0, 34, 33}, - {0, 36, 35}, - {0, 31, 25}, - {0, 37, 24}, - {0, 39, 38}, - {0, 41, 40}, - {0, 43, 42}, - {0, 45, 44}, - {0, 17, 5}, - {0, 47, 46}, - {0, 49, 48}, - {0, 51, 50}, - {0, 53, 52}, - {0, 55, 54}, - {0, 57, 56}, - {0, 59, 58}, - {0, 61, 60}, - {0, 32, 62}, - })); - - codecs.emplace(std::pair(SpvOpExtInst, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {4228502127, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpExtInst, 2), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(113, { - {0, 0, 0}, - {50998433, 0, 0}, - {139011596, 0, 0}, - {181902171, 0, 0}, - {296981500, 0, 0}, - {321630747, 0, 0}, - {416853049, 0, 0}, - {464259778, 0, 0}, - {615982737, 0, 0}, - {669982125, 0, 0}, - {759277550, 0, 0}, - {810488476, 0, 0}, - {870594305, 0, 0}, - {922996215, 0, 0}, - {969500141, 0, 0}, - {1015552308, 0, 0}, - {1139547465, 0, 0}, - {1203545131, 0, 0}, - {1220643281, 0, 0}, - {1220749418, 0, 0}, - {1367301635, 0, 0}, - {1395923345, 0, 0}, - {1554194368, 0, 0}, - {1742737136, 0, 0}, - {1755648697, 0, 0}, - {1962162282, 0, 0}, - {1964254745, 0, 0}, - {2055836767, 0, 0}, - {2096388952, 0, 0}, - {2124837447, 0, 0}, - {2161102232, 0, 0}, - {2321729979, 0, 0}, - {2346547796, 0, 0}, - {2399809085, 0, 0}, - {2432827426, 0, 0}, - {2455417440, 0, 0}, - {2572638469, 0, 0}, - {2614879967, 0, 0}, - {2855506940, 0, 0}, - {2919796598, 0, 0}, - {2970183398, 0, 0}, - {2976066508, 0, 0}, - {3044188332, 0, 0}, - {3061690214, 0, 0}, - {3091876332, 0, 0}, - {3104643263, 0, 0}, - {3107165180, 0, 0}, - {3187066832, 0, 0}, - {3413713311, 0, 0}, - {3487022798, 0, 0}, - {3602693817, 0, 0}, - {3678875745, 0, 0}, - {3701632935, 0, 0}, - {3829325073, 0, 0}, - {4040340620, 0, 0}, - {4174489262, 0, 0}, - {4272200782, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 33, 7}, - {0, 13, 34}, - {0, 21, 18}, - {0, 53, 22}, - {0, 39, 1}, - {0, 14, 9}, - {0, 43, 26}, - {0, 51, 35}, - {0, 19, 6}, - {0, 15, 25}, - {0, 55, 29}, - {0, 32, 3}, - {0, 27, 44}, - {0, 10, 46}, - {0, 45, 24}, - {0, 36, 40}, - {0, 47, 8}, - {0, 48, 54}, - {0, 58, 5}, - {0, 60, 59}, - {0, 30, 61}, - {0, 62, 56}, - {0, 64, 63}, - {0, 41, 50}, - {0, 66, 65}, - {0, 68, 67}, - {0, 70, 69}, - {0, 37, 31}, - {0, 4, 17}, - {0, 16, 20}, - {0, 72, 71}, - {0, 73, 52}, - {0, 49, 12}, - {0, 75, 74}, - {0, 76, 11}, - {0, 23, 42}, - {0, 78, 77}, - {0, 80, 79}, - {0, 82, 81}, - {0, 84, 83}, - {0, 85, 28}, - {0, 87, 86}, - {0, 89, 88}, - {0, 91, 90}, - {0, 93, 92}, - {0, 94, 2}, - {0, 96, 95}, - {0, 98, 97}, - {0, 100, 99}, - {0, 102, 101}, - {0, 38, 103}, - {0, 105, 104}, - {0, 107, 106}, - {0, 109, 108}, - {0, 111, 110}, - {0, 57, 112}, - })); - - codecs.emplace(std::pair(SpvOpExtInst, 4), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(127, { - {0, 0, 0}, - {72782198, 0, 0}, - {139011596, 0, 0}, - {296981500, 0, 0}, - {300939750, 0, 0}, - {401211099, 0, 0}, - {429277936, 0, 0}, - {505940164, 0, 0}, - {538168945, 0, 0}, - {603915804, 0, 0}, - {688216667, 0, 0}, - {706016261, 0, 0}, - {790502615, 0, 0}, - {810488476, 0, 0}, - {993150979, 0, 0}, - {1203545131, 0, 0}, - {1206726575, 0, 0}, - {1265796414, 0, 0}, - {1314843976, 0, 0}, - {1367301635, 0, 0}, - {1378082995, 0, 0}, - {1410311776, 0, 0}, - {1443829854, 0, 0}, - {1448448666, 0, 0}, - {1468919488, 0, 0}, - {1496351055, 0, 0}, - {1619778288, 0, 0}, - {1684282922, 0, 0}, - {1848784182, 0, 0}, - {1901166356, 0, 0}, - {2095546797, 0, 0}, - {2096388952, 0, 0}, - {2162986400, 0, 0}, - {2197874825, 0, 0}, - {2246405597, 0, 0}, - {2250225826, 0, 0}, - {2282454607, 0, 0}, - {2328748202, 0, 0}, - {2348201466, 0, 0}, - {2597020383, 0, 0}, - {2633682514, 0, 0}, - {2817335337, 0, 0}, - {2855506940, 0, 0}, - {2936040203, 0, 0}, - {2955375511, 0, 0}, - {3122368657, 0, 0}, - {3154597438, 0, 0}, - {3184381405, 0, 0}, - {3187066832, 0, 0}, - {3233393284, 0, 0}, - {3251128023, 0, 0}, - {3260309823, 0, 0}, - {3441531391, 0, 0}, - {3496407048, 0, 0}, - {3582002820, 0, 0}, - {3647586740, 0, 0}, - {3653838348, 0, 0}, - {3730093054, 0, 0}, - {3759072440, 0, 0}, - {3928764629, 0, 0}, - {3969279737, 0, 0}, - {3994511488, 0, 0}, - {4026740269, 0, 0}, - {4274214049, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 43, 23}, - {0, 5, 24}, - {0, 9, 8}, - {0, 36, 21}, - {0, 13, 46}, - {0, 7, 12}, - {0, 35, 20}, - {0, 61, 59}, - {0, 22, 29}, - {0, 38, 62}, - {0, 56, 45}, - {0, 6, 48}, - {0, 33, 30}, - {0, 14, 58}, - {0, 34, 28}, - {0, 51, 40}, - {0, 63, 55}, - {0, 25, 16}, - {0, 17, 11}, - {0, 53, 52}, - {0, 65, 27}, - {0, 39, 41}, - {0, 67, 66}, - {0, 69, 68}, - {0, 10, 4}, - {0, 37, 18}, - {0, 60, 47}, - {0, 1, 32}, - {0, 71, 70}, - {0, 73, 72}, - {0, 57, 26}, - {0, 74, 31}, - {0, 76, 75}, - {0, 77, 44}, - {0, 78, 15}, - {0, 79, 54}, - {0, 81, 80}, - {0, 82, 49}, - {0, 84, 83}, - {0, 86, 85}, - {0, 88, 87}, - {0, 89, 19}, - {0, 91, 90}, - {0, 93, 92}, - {0, 95, 94}, - {0, 2, 96}, - {0, 98, 97}, - {0, 100, 99}, - {0, 102, 101}, - {0, 104, 103}, - {0, 106, 105}, - {0, 3, 107}, - {0, 109, 108}, - {0, 111, 110}, - {0, 113, 112}, - {0, 114, 50}, - {0, 116, 115}, - {0, 118, 117}, - {0, 120, 119}, - {0, 122, 121}, - {0, 124, 123}, - {0, 64, 42}, - {0, 126, 125}, - })); - - codecs.emplace(std::pair(SpvOpExtInst, 5), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(93, { - {0, 0, 0}, - {99347751, 0, 0}, - {102542696, 0, 0}, - {107497541, 0, 0}, - {112452386, 0, 0}, - {139011596, 0, 0}, - {296981500, 0, 0}, - {429277936, 0, 0}, - {451957774, 0, 0}, - {508217552, 0, 0}, - {573901046, 0, 0}, - {774727851, 0, 0}, - {801484894, 0, 0}, - {920604853, 0, 0}, - {925559698, 0, 0}, - {1022915255, 0, 0}, - {1209418480, 0, 0}, - {1287937401, 0, 0}, - {1319785741, 0, 0}, - {1392080469, 0, 0}, - {1538342947, 0, 0}, - {1541020250, 0, 0}, - {1587209598, 0, 0}, - {1594733696, 0, 0}, - {1631434666, 0, 0}, - {1636389511, 0, 0}, - {1684282922, 0, 0}, - {1859128680, 0, 0}, - {1901166356, 0, 0}, - {2004567202, 0, 0}, - {2119793999, 0, 0}, - {2280400314, 0, 0}, - {2538917932, 0, 0}, - {2677264274, 0, 0}, - {2683080096, 0, 0}, - {2854085372, 0, 0}, - {2879917501, 0, 0}, - {3059119137, 0, 0}, - {3174324790, 0, 0}, - {3194725903, 0, 0}, - {3358097187, 0, 0}, - {3547456240, 0, 0}, - {3614752756, 0, 0}, - {3753486980, 0, 0}, - {3811268385, 0, 0}, - {3953733490, 0, 0}, - {3990925720, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 23, 22}, - {0, 36, 31}, - {0, 17, 40}, - {0, 27, 19}, - {0, 35, 33}, - {0, 30, 38}, - {0, 42, 39}, - {0, 46, 32}, - {0, 13, 12}, - {0, 44, 14}, - {0, 29, 11}, - {0, 10, 18}, - {0, 15, 37}, - {0, 1, 4}, - {0, 45, 2}, - {0, 21, 28}, - {0, 8, 5}, - {0, 49, 48}, - {0, 51, 50}, - {0, 53, 52}, - {0, 54, 16}, - {0, 55, 25}, - {0, 56, 3}, - {0, 58, 57}, - {0, 59, 26}, - {0, 20, 7}, - {0, 61, 60}, - {0, 62, 24}, - {0, 41, 63}, - {0, 65, 64}, - {0, 9, 34}, - {0, 67, 66}, - {0, 69, 68}, - {0, 71, 70}, - {0, 73, 72}, - {0, 75, 74}, - {0, 76, 43}, - {0, 78, 77}, - {0, 80, 79}, - {0, 82, 81}, - {0, 84, 83}, - {0, 86, 85}, - {0, 88, 87}, - {0, 90, 89}, - {0, 47, 91}, - {0, 92, 6}, - })); - - codecs.emplace(std::pair(SpvOpExtInst, 6), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(15, { - {0, 0, 0}, - {166253838, 0, 0}, - {679771963, 0, 0}, - {1247793383, 0, 0}, - {2261697609, 0, 0}, - {2263349224, 0, 0}, - {2320303498, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 4, 8}, - {0, 9, 1}, - {0, 3, 5}, - {0, 11, 10}, - {0, 2, 12}, - {0, 7, 6}, - {0, 14, 13}, - })); - - codecs.emplace(std::pair(SpvOpTypeVector, 0), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(9, { - {0, 0, 0}, - {789872778, 0, 0}, - {1415510495, 0, 0}, - {1951208733, 0, 0}, - {2430404313, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 2, 5}, - {0, 4, 6}, - {0, 7, 1}, - {0, 3, 8}, - })); - - codecs.emplace(std::pair(SpvOpTypeVector, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(15, { - {0, 0, 0}, - {1389644742, 0, 0}, - {3232633974, 0, 0}, - {3278176820, 0, 0}, - {3648138580, 0, 0}, - {3687777340, 0, 0}, - {3694383800, 0, 0}, - {3697687030, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 5, 4}, - {0, 9, 6}, - {0, 10, 8}, - {0, 2, 11}, - {0, 12, 3}, - {0, 1, 13}, - {0, 14, 7}, - })); - - codecs.emplace(std::pair(SpvOpTypeArray, 0), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(7, { - {0, 0, 0}, - {1951208733, 0, 0}, - {2160380860, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 4}, - {0, 2, 5}, - {0, 3, 6}, - })); - - codecs.emplace(std::pair(SpvOpTypeArray, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(13, { - {0, 0, 0}, - {144116905, 0, 0}, - {827246872, 0, 0}, - {1545298048, 0, 0}, - {2715370488, 0, 0}, - {2798552666, 0, 0}, - {3812456892, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 2, 3}, - {0, 8, 6}, - {0, 9, 7}, - {0, 1, 10}, - {0, 11, 4}, - {0, 5, 12}, - })); - - codecs.emplace(std::pair(SpvOpTypeArray, 2), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(67, { - {0, 0, 0}, - {40653745, 0, 0}, - {119981689, 0, 0}, - {153085016, 0, 0}, - {451382997, 0, 0}, - {545678922, 0, 0}, - {899570100, 0, 0}, - {929101967, 0, 0}, - {1070791291, 0, 0}, - {1100599986, 0, 0}, - {1103903216, 0, 0}, - {1154919607, 0, 0}, - {1199157863, 0, 0}, - {1258105452, 0, 0}, - {1369578001, 0, 0}, - {1372881231, 0, 0}, - {1674803691, 0, 0}, - {1677700667, 0, 0}, - {1989520052, 0, 0}, - {2593884753, 0, 0}, - {2664825925, 0, 0}, - {2924146124, 0, 0}, - {2926633629, 0, 0}, - {3249265647, 0, 0}, - {3345288309, 0, 0}, - {3410158390, 0, 0}, - {3489360962, 0, 0}, - {3495967422, 0, 0}, - {3504981554, 0, 0}, - {3705139860, 0, 0}, - {3822983876, 0, 0}, - {4141567741, 0, 0}, - {4234287173, 0, 0}, - {4240893633, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 15, 23}, - {0, 20, 17}, - {0, 32, 22}, - {0, 19, 12}, - {0, 13, 3}, - {0, 30, 27}, - {0, 4, 35}, - {0, 24, 36}, - {0, 31, 37}, - {0, 33, 38}, - {0, 39, 7}, - {0, 6, 40}, - {0, 41, 29}, - {0, 14, 42}, - {0, 43, 28}, - {0, 10, 44}, - {0, 45, 18}, - {0, 26, 46}, - {0, 5, 47}, - {0, 48, 2}, - {0, 49, 9}, - {0, 50, 16}, - {0, 34, 25}, - {0, 52, 51}, - {0, 54, 53}, - {0, 56, 55}, - {0, 58, 57}, - {0, 60, 59}, - {0, 8, 21}, - {0, 1, 11}, - {0, 62, 61}, - {0, 64, 63}, - {0, 66, 65}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 0), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(11, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {2160380860, 0, 0}, - {3278176820, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 4, 6}, - {0, 2, 7}, - {0, 3, 8}, - {0, 9, 1}, - {0, 5, 10}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(13, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {2160380860, 0, 0}, - {2320303498, 0, 0}, - {3232633974, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 5, 7}, - {0, 2, 8}, - {0, 4, 9}, - {0, 10, 3}, - {0, 1, 6}, - {0, 12, 11}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 2), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(11, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {2160380860, 0, 0}, - {2320303498, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 5, 6}, - {0, 1, 7}, - {0, 3, 4}, - {0, 8, 2}, - {0, 10, 9}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 3), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(11, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {2160380860, 0, 0}, - {2320303498, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 2, 6}, - {0, 3, 7}, - {0, 5, 4}, - {0, 8, 1}, - {0, 10, 9}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 4), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(9, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {2263349224, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 3, 5}, - {0, 1, 6}, - {0, 2, 7}, - {0, 8, 4}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 5), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(9, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 3, 5}, - {0, 1, 6}, - {0, 2, 7}, - {0, 8, 4}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 6), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(9, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 3, 5}, - {0, 4, 6}, - {0, 7, 1}, - {0, 2, 8}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 7), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(9, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 3, 5}, - {0, 1, 6}, - {0, 7, 4}, - {0, 2, 8}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 8), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(7, { - {0, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 2, 4}, - {0, 3, 5}, - {0, 1, 6}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 9), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(9, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 5, 3}, - {0, 1, 6}, - {0, 4, 7}, - {0, 8, 2}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 10), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(9, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 3, 5}, - {0, 1, 6}, - {0, 7, 4}, - {0, 8, 2}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 11), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(5, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 2, 3}, - {0, 4, 1}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 12), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(7, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 3, 4}, - {0, 1, 5}, - {0, 2, 6}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 13), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(9, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 4, 5}, - {0, 3, 6}, - {0, 7, 1}, - {0, 8, 2}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 14), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(7, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 4}, - {0, 5, 3}, - {0, 6, 2}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 15), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(7, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 3, 4}, - {0, 2, 5}, - {0, 1, 6}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 16), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(9, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 3, 5}, - {0, 4, 6}, - {0, 7, 1}, - {0, 8, 2}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 17), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(7, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 3, 4}, - {0, 1, 5}, - {0, 2, 6}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 18), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(7, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 4}, - {0, 3, 5}, - {0, 2, 6}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 19), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(7, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 3, 4}, - {0, 1, 5}, - {0, 2, 6}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 20), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(7, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 4}, - {0, 2, 5}, - {0, 3, 6}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 21), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(9, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 5, 1}, - {0, 2, 6}, - {0, 3, 7}, - {0, 8, 4}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 22), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(9, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 5}, - {0, 2, 6}, - {0, 4, 7}, - {0, 8, 3}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 23), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(11, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {2160380860, 0, 0}, - {2320303498, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 6, 4}, - {0, 1, 7}, - {0, 2, 8}, - {0, 3, 9}, - {0, 10, 5}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 24), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(9, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 5}, - {0, 2, 6}, - {0, 4, 7}, - {0, 8, 3}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 25), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(7, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 4}, - {0, 2, 5}, - {0, 3, 6}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 26), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(7, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 4}, - {0, 2, 5}, - {0, 3, 6}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 27), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(5, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 2, 3}, - {0, 1, 4}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 28), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(5, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 3}, - {0, 2, 4}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 29), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(5, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 3}, - {0, 2, 4}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 30), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(7, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 4, 3}, - {0, 1, 5}, - {0, 2, 6}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 31), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(7, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 3, 4}, - {0, 1, 5}, - {0, 2, 6}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 32), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(5, { - {0, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 2, 3}, - {0, 1, 4}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 33), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(5, { - {0, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 3}, - {0, 2, 4}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 34), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(5, { - {0, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 2, 3}, - {0, 1, 4}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 35), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(5, { - {0, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 2, 3}, - {0, 1, 4}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 36), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {679771963, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 37), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {1389644742, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 38), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {3697687030, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 39), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {2320303498, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 40), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {2320303498, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 41), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {679771963, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 42), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {679771963, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 43), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {679771963, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 44), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {679771963, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 45), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {679771963, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 46), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {679771963, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 47), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {679771963, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 48), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {679771963, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 49), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {679771963, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 50), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {679771963, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpTypeStruct, 51), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(101, { - {0, 0, 0}, - {85880059, 0, 0}, - {135486769, 0, 0}, - {304448521, 0, 0}, - {436416061, 0, 0}, - {440421571, 0, 0}, - {450406196, 0, 0}, - {503094540, 0, 0}, - {543621065, 0, 0}, - {626892406, 0, 0}, - {628544021, 0, 0}, - {827698488, 0, 0}, - {869050696, 0, 0}, - {907126242, 0, 0}, - {908777857, 0, 0}, - {910429472, 0, 0}, - {1113409935, 0, 0}, - {1294403159, 0, 0}, - {1296054774, 0, 0}, - {1297706389, 0, 0}, - {1322549027, 0, 0}, - {1784441183, 0, 0}, - {2080953106, 0, 0}, - {2194691858, 0, 0}, - {2448331885, 0, 0}, - {2466255445, 0, 0}, - {2468230023, 0, 0}, - {2547657777, 0, 0}, - {2549309392, 0, 0}, - {2550961007, 0, 0}, - {2894051250, 0, 0}, - {2929019254, 0, 0}, - {2934934694, 0, 0}, - {2936586309, 0, 0}, - {2938237924, 0, 0}, - {3077271274, 0, 0}, - {3092528578, 0, 0}, - {3094180193, 0, 0}, - {3094857332, 0, 0}, - {3095831808, 0, 0}, - {3183924418, 0, 0}, - {3207966516, 0, 0}, - {3282979782, 0, 0}, - {3433956341, 0, 0}, - {3561562003, 0, 0}, - {3563213618, 0, 0}, - {3564865233, 0, 0}, - {3585511591, 0, 0}, - {4028622909, 0, 0}, - {4039938779, 0, 0}, - {4050155669, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 16, 25}, - {0, 50, 1}, - {0, 42, 35}, - {0, 31, 41}, - {0, 4, 43}, - {0, 9, 10}, - {0, 3, 30}, - {0, 52, 47}, - {0, 12, 53}, - {0, 55, 54}, - {0, 36, 56}, - {0, 49, 57}, - {0, 6, 58}, - {0, 34, 33}, - {0, 59, 26}, - {0, 21, 32}, - {0, 60, 15}, - {0, 24, 61}, - {0, 62, 38}, - {0, 22, 2}, - {0, 37, 7}, - {0, 63, 46}, - {0, 14, 13}, - {0, 64, 5}, - {0, 65, 45}, - {0, 66, 19}, - {0, 18, 67}, - {0, 17, 20}, - {0, 68, 11}, - {0, 8, 69}, - {0, 70, 39}, - {0, 72, 71}, - {0, 74, 73}, - {0, 40, 75}, - {0, 76, 23}, - {0, 78, 77}, - {0, 29, 79}, - {0, 28, 80}, - {0, 27, 48}, - {0, 82, 81}, - {0, 51, 83}, - {0, 84, 44}, - {0, 86, 85}, - {0, 88, 87}, - {0, 90, 89}, - {0, 92, 91}, - {0, 94, 93}, - {0, 96, 95}, - {0, 98, 97}, - {0, 100, 99}, - })); - - codecs.emplace(std::pair(SpvOpTypePointer, 0), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(65, { - {0, 0, 0}, - {119981689, 0, 0}, - {162255877, 0, 0}, - {451382997, 0, 0}, - {545678922, 0, 0}, - {679771963, 0, 0}, - {789872778, 0, 0}, - {1100599986, 0, 0}, - {1103903216, 0, 0}, - {1154919607, 0, 0}, - {1343794461, 0, 0}, - {1415510495, 0, 0}, - {1674803691, 0, 0}, - {1951208733, 0, 0}, - {1989520052, 0, 0}, - {2160380860, 0, 0}, - {2263349224, 0, 0}, - {2320303498, 0, 0}, - {2924146124, 0, 0}, - {2984325996, 0, 0}, - {3334207724, 0, 0}, - {3345288309, 0, 0}, - {3410158390, 0, 0}, - {3489360962, 0, 0}, - {3495967422, 0, 0}, - {3504981554, 0, 0}, - {3800912395, 0, 0}, - {3802564010, 0, 0}, - {3866587616, 0, 0}, - {3868239231, 0, 0}, - {3869890846, 0, 0}, - {3998230222, 0, 0}, - {4240893633, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 4, 3}, - {0, 6, 24}, - {0, 11, 7}, - {0, 32, 21}, - {0, 27, 34}, - {0, 35, 25}, - {0, 36, 8}, - {0, 26, 31}, - {0, 14, 15}, - {0, 28, 37}, - {0, 1, 23}, - {0, 39, 38}, - {0, 12, 40}, - {0, 22, 41}, - {0, 10, 16}, - {0, 43, 42}, - {0, 29, 44}, - {0, 2, 45}, - {0, 46, 19}, - {0, 48, 47}, - {0, 18, 49}, - {0, 50, 30}, - {0, 9, 33}, - {0, 52, 51}, - {0, 54, 53}, - {0, 13, 55}, - {0, 17, 56}, - {0, 5, 57}, - {0, 59, 58}, - {0, 60, 20}, - {0, 62, 61}, - {0, 64, 63}, - })); - - codecs.emplace(std::pair(SpvOpTypePointer, 2), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(99, { - {0, 0, 0}, - {75986790, 0, 0}, - {95470391, 0, 0}, - {170378107, 0, 0}, - {172029722, 0, 0}, - {204234270, 0, 0}, - {205885885, 0, 0}, - {244668133, 0, 0}, - {265778447, 0, 0}, - {616435646, 0, 0}, - {618087261, 0, 0}, - {753954113, 0, 0}, - {1000070091, 0, 0}, - {1308462133, 0, 0}, - {1671139745, 0, 0}, - {1774874546, 0, 0}, - {1776526161, 0, 0}, - {1887808856, 0, 0}, - {1889460471, 0, 0}, - {1917966999, 0, 0}, - {2044728014, 0, 0}, - {2192810893, 0, 0}, - {2293247016, 0, 0}, - {2503194620, 0, 0}, - {2605012269, 0, 0}, - {2608484640, 0, 0}, - {2615111110, 0, 0}, - {2668769415, 0, 0}, - {2759951687, 0, 0}, - {2761603302, 0, 0}, - {2856623532, 0, 0}, - {2945369269, 0, 0}, - {2956189845, 0, 0}, - {3085119011, 0, 0}, - {3367313400, 0, 0}, - {3447882276, 0, 0}, - {3633746133, 0, 0}, - {3635397748, 0, 0}, - {3710645347, 0, 0}, - {3712296962, 0, 0}, - {3715846592, 0, 0}, - {3727494858, 0, 0}, - {3747079365, 0, 0}, - {3748965853, 0, 0}, - {3750617468, 0, 0}, - {4018820793, 0, 0}, - {4022124023, 0, 0}, - {4024173916, 0, 0}, - {4215670524, 0, 0}, - {4217322139, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 10, 9}, - {0, 31, 24}, - {0, 40, 13}, - {0, 45, 33}, - {0, 34, 46}, - {0, 43, 38}, - {0, 44, 15}, - {0, 11, 30}, - {0, 21, 6}, - {0, 47, 3}, - {0, 51, 16}, - {0, 14, 52}, - {0, 8, 53}, - {0, 35, 5}, - {0, 55, 54}, - {0, 56, 26}, - {0, 20, 57}, - {0, 39, 19}, - {0, 59, 58}, - {0, 61, 60}, - {0, 4, 62}, - {0, 2, 63}, - {0, 25, 7}, - {0, 64, 27}, - {0, 12, 22}, - {0, 65, 48}, - {0, 41, 42}, - {0, 17, 23}, - {0, 49, 66}, - {0, 68, 67}, - {0, 70, 69}, - {0, 72, 71}, - {0, 74, 73}, - {0, 18, 75}, - {0, 37, 32}, - {0, 76, 36}, - {0, 78, 77}, - {0, 79, 28}, - {0, 81, 80}, - {0, 82, 29}, - {0, 84, 83}, - {0, 86, 85}, - {0, 88, 87}, - {0, 90, 89}, - {0, 91, 50}, - {0, 93, 92}, - {0, 95, 94}, - {0, 1, 96}, - {0, 98, 97}, - })); - - codecs.emplace(std::pair(SpvOpTypeFunction, 0), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(27, { - {0, 0, 0}, - {545678922, 0, 0}, - {679771963, 0, 0}, - {899570100, 0, 0}, - {929101967, 0, 0}, - {1100599986, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {3056042030, 0, 0}, - {3334207724, 0, 0}, - {3357250579, 0, 0}, - {3705139860, 0, 0}, - {3800912395, 0, 0}, - {3802564010, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 5, 3}, - {0, 10, 13}, - {0, 4, 15}, - {0, 16, 11}, - {0, 17, 1}, - {0, 14, 12}, - {0, 19, 18}, - {0, 21, 20}, - {0, 7, 6}, - {0, 9, 22}, - {0, 24, 23}, - {0, 25, 2}, - {0, 26, 8}, - })); - - codecs.emplace(std::pair(SpvOpTypeFunction, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(57, { - {0, 0, 0}, - {283209196, 0, 0}, - {436416061, 0, 0}, - {679771963, 0, 0}, - {789872778, 0, 0}, - {815757910, 0, 0}, - {827698488, 0, 0}, - {1164221089, 0, 0}, - {1294403159, 0, 0}, - {1296054774, 0, 0}, - {1297706389, 0, 0}, - {1525861001, 0, 0}, - {1579585816, 0, 0}, - {1675764636, 0, 0}, - {1824016656, 0, 0}, - {1951208733, 0, 0}, - {1991787192, 0, 0}, - {2180701723, 0, 0}, - {2194691858, 0, 0}, - {2320303498, 0, 0}, - {2881886868, 0, 0}, - {2926633629, 0, 0}, - {3249265647, 0, 0}, - {3334207724, 0, 0}, - {3472123498, 0, 0}, - {3674863070, 0, 0}, - {4050155669, 0, 0}, - {4141567741, 0, 0}, - {4155122613, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 24, 7}, - {0, 17, 1}, - {0, 4, 15}, - {0, 11, 16}, - {0, 28, 30}, - {0, 25, 20}, - {0, 14, 31}, - {0, 32, 26}, - {0, 12, 5}, - {0, 2, 22}, - {0, 33, 13}, - {0, 35, 34}, - {0, 37, 36}, - {0, 39, 38}, - {0, 40, 21}, - {0, 29, 18}, - {0, 27, 41}, - {0, 43, 42}, - {0, 19, 44}, - {0, 45, 23}, - {0, 6, 3}, - {0, 47, 46}, - {0, 49, 48}, - {0, 51, 50}, - {0, 10, 8}, - {0, 53, 52}, - {0, 9, 54}, - {0, 56, 55}, - })); - - codecs.emplace(std::pair(SpvOpTypeFunction, 2), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(17, { - {0, 0, 0}, - {679771963, 0, 0}, - {827698488, 0, 0}, - {1294403159, 0, 0}, - {1296054774, 0, 0}, - {1297706389, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 8, 9}, - {0, 10, 6}, - {0, 1, 5}, - {0, 11, 3}, - {0, 12, 7}, - {0, 13, 2}, - {0, 15, 14}, - {0, 16, 4}, - })); - - codecs.emplace(std::pair(SpvOpTypeFunction, 3), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(17, { - {0, 0, 0}, - {679771963, 0, 0}, - {827698488, 0, 0}, - {1294403159, 0, 0}, - {1296054774, 0, 0}, - {1951208733, 0, 0}, - {2194691858, 0, 0}, - {2320303498, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 8, 5}, - {0, 10, 9}, - {0, 11, 6}, - {0, 7, 12}, - {0, 1, 3}, - {0, 2, 13}, - {0, 15, 14}, - {0, 4, 16}, - })); - - codecs.emplace(std::pair(SpvOpTypeFunction, 4), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(11, { - {0, 0, 0}, - {827698488, 0, 0}, - {1294403159, 0, 0}, - {1296054774, 0, 0}, - {1297706389, 0, 0}, - {1951208733, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 4, 6}, - {0, 5, 7}, - {0, 2, 8}, - {0, 1, 9}, - {0, 10, 3}, - })); - - codecs.emplace(std::pair(SpvOpTypeFunction, 5), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(11, { - {0, 0, 0}, - {827698488, 0, 0}, - {1294403159, 0, 0}, - {1296054774, 0, 0}, - {1951208733, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 2, 6}, - {0, 4, 7}, - {0, 8, 5}, - {0, 3, 9}, - {0, 1, 10}, - })); - - codecs.emplace(std::pair(SpvOpTypeFunction, 6), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(9, { - {0, 0, 0}, - {789872778, 0, 0}, - {827698488, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 5, 1}, - {0, 4, 6}, - {0, 3, 7}, - {0, 2, 8}, - })); - - codecs.emplace(std::pair(SpvOpTypeFunction, 7), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(7, { - {0, 0, 0}, - {543621065, 0, 0}, - {827698488, 0, 0}, - {1951208733, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 3, 4}, - {0, 1, 5}, - {0, 2, 6}, - })); - - codecs.emplace(std::pair(SpvOpTypeFunction, 8), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(7, { - {0, 0, 0}, - {827698488, 0, 0}, - {1951208733, 0, 0}, - {3095831808, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 2, 4}, - {0, 3, 5}, - {0, 1, 6}, - })); - - codecs.emplace(std::pair(SpvOpTypeFunction, 9), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(5, { - {0, 0, 0}, - {1296054774, 0, 0}, - {1951208733, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 3, 2}, - {0, 1, 4}, - })); - - codecs.emplace(std::pair(SpvOpTypeFunction, 10), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(5, { - {0, 0, 0}, - {1296054774, 0, 0}, - {2320303498, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 3, 2}, - {0, 1, 4}, - })); - - codecs.emplace(std::pair(SpvOpTypeFunction, 11), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(5, { - {0, 0, 0}, - {789872778, 0, 0}, - {1951208733, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 3, 2}, - {0, 4, 1}, - })); - - codecs.emplace(std::pair(SpvOpTypeFunction, 12), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(5, { - {0, 0, 0}, - {789872778, 0, 0}, - {1951208733, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 2, 1}, - {0, 4, 3}, - })); - - codecs.emplace(std::pair(SpvOpTypeFunction, 13), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {1951208733, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 2, 1}, - })); - - codecs.emplace(std::pair(SpvOpTypeFunction, 14), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {1951208733, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 2, 1}, - })); - - codecs.emplace(std::pair(SpvOpTypeFunction, 15), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(7, { - {0, 0, 0}, - {789872778, 0, 0}, - {1951208733, 0, 0}, - {2430404313, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 3, 4}, - {0, 1, 5}, - {0, 2, 6}, - })); - - codecs.emplace(std::pair(SpvOpConstant, 0), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(183, { - {0, 0, 0}, - {51041423, 0, 0}, - {52882140, 0, 0}, - {72782198, 0, 0}, - {142465290, 0, 0}, - {144116905, 0, 0}, - {158160339, 0, 0}, - {169135842, 0, 0}, - {210116709, 0, 0}, - {290391815, 0, 0}, - {296981500, 0, 0}, - {385229009, 0, 0}, - {438318340, 0, 0}, - {529742207, 0, 0}, - {628331516, 0, 0}, - {677668732, 0, 0}, - {778500192, 0, 0}, - {825595257, 0, 0}, - {910398460, 0, 0}, - {917019124, 0, 0}, - {959681532, 0, 0}, - {1031290113, 0, 0}, - {1039111164, 0, 0}, - {1064945649, 0, 0}, - {1087394637, 0, 0}, - {1092948665, 0, 0}, - {1156369516, 0, 0}, - {1158021131, 0, 0}, - {1172110445, 0, 0}, - {1304296041, 0, 0}, - {1400019344, 0, 0}, - {1450415100, 0, 0}, - {1452222566, 0, 0}, - {1543646433, 0, 0}, - {1543672828, 0, 0}, - {1612361408, 0, 0}, - {1622381564, 0, 0}, - {1691572958, 0, 0}, - {1755648697, 0, 0}, - {1782996825, 0, 0}, - {1784648440, 0, 0}, - {1930923350, 0, 0}, - {1939359710, 0, 0}, - {1971252067, 0, 0}, - {1979847999, 0, 0}, - {2078849875, 0, 0}, - {2113115132, 0, 0}, - {2135340676, 0, 0}, - {2170273742, 0, 0}, - {2268204687, 0, 0}, - {2285081596, 0, 0}, - {2318200267, 0, 0}, - {2321729979, 0, 0}, - {2326636627, 0, 0}, - {2444465148, 0, 0}, - {2466126792, 0, 0}, - {2490492987, 0, 0}, - {2524697596, 0, 0}, - {2557550659, 0, 0}, - {2678954464, 0, 0}, - {2705477184, 0, 0}, - {2715370488, 0, 0}, - {2732195517, 0, 0}, - {2775815164, 0, 0}, - {2796901051, 0, 0}, - {2798552666, 0, 0}, - {2855506940, 0, 0}, - {2860348412, 0, 0}, - {2922615804, 0, 0}, - {2937761472, 0, 0}, - {2944827576, 0, 0}, - {3092754101, 0, 0}, - {3107165180, 0, 0}, - {3168953855, 0, 0}, - {3184177968, 0, 0}, - {3202349435, 0, 0}, - {3266548732, 0, 0}, - {3332104493, 0, 0}, - {3362723943, 0, 0}, - {3571454885, 0, 0}, - {3712763835, 0, 0}, - {3743748793, 0, 0}, - {3810805277, 0, 0}, - {3912967080, 0, 0}, - {3929248764, 0, 0}, - {3958731802, 0, 0}, - {3997952447, 0, 0}, - {4016096296, 0, 0}, - {4106658327, 0, 0}, - {4172568578, 0, 0}, - {4198082194, 0, 0}, - {4248015868, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 35, 16}, - {0, 49, 42}, - {0, 86, 69}, - {0, 53, 30}, - {0, 45, 89}, - {0, 50, 68}, - {0, 73, 71}, - {0, 17, 46}, - {0, 14, 81}, - {0, 63, 44}, - {0, 12, 3}, - {0, 72, 31}, - {0, 55, 67}, - {0, 36, 19}, - {0, 22, 88}, - {0, 9, 70}, - {0, 93, 23}, - {0, 95, 94}, - {0, 47, 91}, - {0, 34, 32}, - {0, 97, 96}, - {0, 41, 61}, - {0, 99, 98}, - {0, 37, 1}, - {0, 77, 100}, - {0, 51, 60}, - {0, 101, 79}, - {0, 6, 2}, - {0, 11, 7}, - {0, 24, 21}, - {0, 43, 28}, - {0, 59, 56}, - {0, 75, 62}, - {0, 80, 78}, - {0, 87, 83}, - {0, 18, 15}, - {0, 102, 38}, - {0, 104, 103}, - {0, 85, 90}, - {0, 76, 25}, - {0, 29, 105}, - {0, 107, 106}, - {0, 58, 52}, - {0, 109, 108}, - {0, 57, 110}, - {0, 112, 111}, - {0, 114, 113}, - {0, 115, 33}, - {0, 74, 116}, - {0, 118, 117}, - {0, 120, 119}, - {0, 122, 121}, - {0, 124, 123}, - {0, 126, 125}, - {0, 128, 127}, - {0, 130, 129}, - {0, 131, 13}, - {0, 54, 27}, - {0, 133, 132}, - {0, 48, 40}, - {0, 5, 8}, - {0, 82, 134}, - {0, 26, 135}, - {0, 39, 4}, - {0, 136, 64}, - {0, 138, 137}, - {0, 140, 139}, - {0, 84, 141}, - {0, 143, 142}, - {0, 145, 144}, - {0, 147, 146}, - {0, 149, 148}, - {0, 20, 150}, - {0, 65, 151}, - {0, 66, 152}, - {0, 153, 10}, - {0, 155, 154}, - {0, 157, 156}, - {0, 159, 158}, - {0, 161, 160}, - {0, 163, 162}, - {0, 165, 164}, - {0, 167, 166}, - {0, 169, 168}, - {0, 170, 92}, - {0, 172, 171}, - {0, 174, 173}, - {0, 176, 175}, - {0, 178, 177}, - {0, 180, 179}, - {0, 182, 181}, - })); - - codecs.emplace(std::pair(SpvOpConstant, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(9, { - {0, 0, 0}, - {679771963, 0, 0}, - {1247793383, 0, 0}, - {2320303498, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 2, 5}, - {0, 4, 6}, - {0, 1, 3}, - {0, 8, 7}, - })); - - codecs.emplace(std::pair(SpvOpConstantComposite, 0), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(83, { - {0, 0, 0}, - {15502752, 0, 0}, - {46736908, 0, 0}, - {139011596, 0, 0}, - {149720480, 0, 0}, - {249378857, 0, 0}, - {251209228, 0, 0}, - {503145996, 0, 0}, - {836581417, 0, 0}, - {882718761, 0, 0}, - {1289566249, 0, 0}, - {1325348861, 0, 0}, - {1558001705, 0, 0}, - {1646147798, 0, 0}, - {1679946323, 0, 0}, - {1766401548, 0, 0}, - {1992893964, 0, 0}, - {2123388694, 0, 0}, - {2162986400, 0, 0}, - {2580096524, 0, 0}, - {2598189097, 0, 0}, - {2683080096, 0, 0}, - {2698156268, 0, 0}, - {2763960513, 0, 0}, - {3015046341, 0, 0}, - {3133016299, 0, 0}, - {3251128023, 0, 0}, - {3504158761, 0, 0}, - {3535289452, 0, 0}, - {3536941067, 0, 0}, - {3538592682, 0, 0}, - {3540244297, 0, 0}, - {3541895912, 0, 0}, - {3570219049, 0, 0}, - {3653838348, 0, 0}, - {3764205609, 0, 0}, - {3882634684, 0, 0}, - {3913885196, 0, 0}, - {3982047273, 0, 0}, - {4024252457, 0, 0}, - {4243119782, 0, 0}, - {4255182614, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 8, 4}, - {0, 39, 2}, - {0, 38, 10}, - {0, 29, 41}, - {0, 23, 28}, - {0, 9, 24}, - {0, 44, 43}, - {0, 45, 6}, - {0, 20, 12}, - {0, 18, 33}, - {0, 19, 16}, - {0, 7, 46}, - {0, 48, 47}, - {0, 5, 49}, - {0, 13, 11}, - {0, 17, 14}, - {0, 25, 22}, - {0, 40, 36}, - {0, 1, 50}, - {0, 31, 30}, - {0, 51, 32}, - {0, 42, 52}, - {0, 54, 53}, - {0, 55, 15}, - {0, 37, 56}, - {0, 57, 34}, - {0, 59, 58}, - {0, 61, 60}, - {0, 35, 21}, - {0, 62, 26}, - {0, 64, 63}, - {0, 65, 27}, - {0, 3, 66}, - {0, 68, 67}, - {0, 70, 69}, - {0, 72, 71}, - {0, 74, 73}, - {0, 76, 75}, - {0, 78, 77}, - {0, 80, 79}, - {0, 82, 81}, - })); - - codecs.emplace(std::pair(SpvOpConstantComposite, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(65, { - {0, 0, 0}, - {142465290, 0, 0}, - {158160339, 0, 0}, - {169135842, 0, 0}, - {210116709, 0, 0}, - {296981500, 0, 0}, - {615748604, 0, 0}, - {910398460, 0, 0}, - {959681532, 0, 0}, - {1039111164, 0, 0}, - {1087394637, 0, 0}, - {1156369516, 0, 0}, - {1450415100, 0, 0}, - {1543672828, 0, 0}, - {2100532220, 0, 0}, - {2170273742, 0, 0}, - {2285081596, 0, 0}, - {2326636627, 0, 0}, - {2444465148, 0, 0}, - {2732195517, 0, 0}, - {2763232252, 0, 0}, - {2796901051, 0, 0}, - {2855506940, 0, 0}, - {2922615804, 0, 0}, - {2937761472, 0, 0}, - {3202349435, 0, 0}, - {3362723943, 0, 0}, - {3712763835, 0, 0}, - {3810805277, 0, 0}, - {3929248764, 0, 0}, - {4016096296, 0, 0}, - {4172568578, 0, 0}, - {4248015868, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 12, 23}, - {0, 13, 6}, - {0, 20, 14}, - {0, 15, 24}, - {0, 17, 28}, - {0, 16, 31}, - {0, 7, 34}, - {0, 9, 32}, - {0, 36, 35}, - {0, 38, 37}, - {0, 40, 39}, - {0, 2, 8}, - {0, 10, 3}, - {0, 25, 19}, - {0, 27, 26}, - {0, 33, 30}, - {0, 11, 41}, - {0, 1, 21}, - {0, 18, 42}, - {0, 44, 43}, - {0, 46, 45}, - {0, 48, 47}, - {0, 29, 49}, - {0, 4, 50}, - {0, 52, 51}, - {0, 54, 53}, - {0, 56, 55}, - {0, 58, 57}, - {0, 59, 5}, - {0, 61, 60}, - {0, 62, 22}, - {0, 64, 63}, - })); - - codecs.emplace(std::pair(SpvOpConstantComposite, 2), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(57, { - {0, 0, 0}, - {52882140, 0, 0}, - {210116709, 0, 0}, - {296981500, 0, 0}, - {385229009, 0, 0}, - {615748604, 0, 0}, - {910398460, 0, 0}, - {959681532, 0, 0}, - {1031290113, 0, 0}, - {1039111164, 0, 0}, - {1172110445, 0, 0}, - {1450415100, 0, 0}, - {1543672828, 0, 0}, - {1622381564, 0, 0}, - {1782996825, 0, 0}, - {1971252067, 0, 0}, - {2100532220, 0, 0}, - {2268204687, 0, 0}, - {2326636627, 0, 0}, - {2444465148, 0, 0}, - {2490492987, 0, 0}, - {2678954464, 0, 0}, - {2763232252, 0, 0}, - {2855506940, 0, 0}, - {2922615804, 0, 0}, - {3912967080, 0, 0}, - {3929248764, 0, 0}, - {4172568578, 0, 0}, - {4248015868, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 11, 24}, - {0, 12, 5}, - {0, 22, 16}, - {0, 18, 17}, - {0, 30, 27}, - {0, 6, 13}, - {0, 9, 28}, - {0, 32, 31}, - {0, 34, 33}, - {0, 7, 35}, - {0, 4, 1}, - {0, 10, 8}, - {0, 20, 15}, - {0, 25, 21}, - {0, 36, 29}, - {0, 19, 37}, - {0, 39, 38}, - {0, 41, 40}, - {0, 43, 42}, - {0, 26, 44}, - {0, 45, 2}, - {0, 47, 46}, - {0, 49, 48}, - {0, 50, 14}, - {0, 51, 3}, - {0, 53, 52}, - {0, 54, 23}, - {0, 56, 55}, - })); - - codecs.emplace(std::pair(SpvOpConstantComposite, 3), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(39, { - {0, 0, 0}, - {210116709, 0, 0}, - {296981500, 0, 0}, - {615748604, 0, 0}, - {910398460, 0, 0}, - {959681532, 0, 0}, - {1039111164, 0, 0}, - {1092948665, 0, 0}, - {1450415100, 0, 0}, - {1543672828, 0, 0}, - {1612361408, 0, 0}, - {2100532220, 0, 0}, - {2326636627, 0, 0}, - {2444465148, 0, 0}, - {2524697596, 0, 0}, - {2763232252, 0, 0}, - {2855506940, 0, 0}, - {3929248764, 0, 0}, - {4172568578, 0, 0}, - {4248015868, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 8, 7}, - {0, 9, 3}, - {0, 15, 11}, - {0, 10, 21}, - {0, 18, 12}, - {0, 4, 20}, - {0, 22, 19}, - {0, 23, 6}, - {0, 14, 24}, - {0, 5, 25}, - {0, 27, 26}, - {0, 28, 17}, - {0, 30, 29}, - {0, 31, 13}, - {0, 1, 32}, - {0, 34, 33}, - {0, 16, 35}, - {0, 2, 36}, - {0, 38, 37}, - })); - - codecs.emplace(std::pair(SpvOpConstantComposite, 4), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(35, { - {0, 0, 0}, - {296981500, 0, 0}, - {615748604, 0, 0}, - {673708384, 0, 0}, - {959681532, 0, 0}, - {1039111164, 0, 0}, - {1450415100, 0, 0}, - {1543672828, 0, 0}, - {1939359710, 0, 0}, - {2100532220, 0, 0}, - {2113115132, 0, 0}, - {2326636627, 0, 0}, - {2444465148, 0, 0}, - {2763232252, 0, 0}, - {2855506940, 0, 0}, - {3929248764, 0, 0}, - {4172568578, 0, 0}, - {4248015868, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 18, 3}, - {0, 6, 19}, - {0, 12, 4}, - {0, 17, 2}, - {0, 9, 7}, - {0, 20, 13}, - {0, 11, 8}, - {0, 10, 16}, - {0, 21, 15}, - {0, 5, 22}, - {0, 24, 23}, - {0, 26, 25}, - {0, 28, 27}, - {0, 29, 1}, - {0, 31, 30}, - {0, 33, 32}, - {0, 34, 14}, - })); - - codecs.emplace(std::pair(SpvOpConstantComposite, 5), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(23, { - {0, 0, 0}, - {545678922, 0, 0}, - {679771963, 0, 0}, - {929101967, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {3056042030, 0, 0}, - {3334207724, 0, 0}, - {3357250579, 0, 0}, - {3705139860, 0, 0}, - {3800912395, 0, 0}, - {3802564010, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 8, 11}, - {0, 9, 3}, - {0, 1, 13}, - {0, 14, 10}, - {0, 12, 15}, - {0, 17, 16}, - {0, 18, 4}, - {0, 7, 5}, - {0, 20, 19}, - {0, 2, 21}, - {0, 22, 6}, - })); - - codecs.emplace(std::pair(SpvOpFunction, 0), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(89, { - {0, 0, 0}, - {35240468, 0, 0}, - {123060826, 0, 0}, - {184634770, 0, 0}, - {359054425, 0, 0}, - {459968607, 0, 0}, - {619875033, 0, 0}, - {904486530, 0, 0}, - {945128292, 0, 0}, - {950731750, 0, 0}, - {1058429216, 0, 0}, - {1182296898, 0, 0}, - {1238120570, 0, 0}, - {1429389803, 0, 0}, - {1652168174, 0, 0}, - {1717510093, 0, 0}, - {1766422419, 0, 0}, - {1775308984, 0, 0}, - {1776629361, 0, 0}, - {1824526196, 0, 0}, - {1957265068, 0, 0}, - {1998433745, 0, 0}, - {2055664760, 0, 0}, - {2303184249, 0, 0}, - {2451531615, 0, 0}, - {2507457870, 0, 0}, - {2550501832, 0, 0}, - {2590402790, 0, 0}, - {2649103430, 0, 0}, - {2780190687, 0, 0}, - {2831059514, 0, 0}, - {3167253437, 0, 0}, - {3269075805, 0, 0}, - {3323202731, 0, 0}, - {3361419439, 0, 0}, - {3464197236, 0, 0}, - {3472029049, 0, 0}, - {3518630848, 0, 0}, - {3604842236, 0, 0}, - {3653985133, 0, 0}, - {4091916710, 0, 0}, - {4121643374, 0, 0}, - {4185590212, 0, 0}, - {4233562270, 0, 0}, - {4235213885, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 6, 40}, - {0, 14, 31}, - {0, 7, 9}, - {0, 29, 27}, - {0, 18, 44}, - {0, 8, 5}, - {0, 10, 3}, - {0, 41, 37}, - {0, 42, 35}, - {0, 2, 1}, - {0, 47, 46}, - {0, 48, 4}, - {0, 11, 49}, - {0, 50, 36}, - {0, 19, 51}, - {0, 53, 52}, - {0, 55, 54}, - {0, 15, 12}, - {0, 26, 16}, - {0, 56, 21}, - {0, 25, 33}, - {0, 43, 24}, - {0, 57, 39}, - {0, 59, 58}, - {0, 61, 60}, - {0, 62, 34}, - {0, 64, 63}, - {0, 17, 30}, - {0, 66, 65}, - {0, 20, 67}, - {0, 13, 68}, - {0, 28, 69}, - {0, 70, 32}, - {0, 72, 71}, - {0, 73, 22}, - {0, 75, 74}, - {0, 77, 76}, - {0, 79, 78}, - {0, 80, 23}, - {0, 45, 81}, - {0, 83, 82}, - {0, 85, 84}, - {0, 38, 86}, - {0, 88, 87}, - })); - - codecs.emplace(std::pair(SpvOpFunction, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(87, { - {0, 0, 0}, - {75986790, 0, 0}, - {95470391, 0, 0}, - {170378107, 0, 0}, - {172029722, 0, 0}, - {204234270, 0, 0}, - {205885885, 0, 0}, - {244668133, 0, 0}, - {265778447, 0, 0}, - {753954113, 0, 0}, - {1000070091, 0, 0}, - {1671139745, 0, 0}, - {1774874546, 0, 0}, - {1776526161, 0, 0}, - {1887808856, 0, 0}, - {1889460471, 0, 0}, - {1917966999, 0, 0}, - {2044728014, 0, 0}, - {2192810893, 0, 0}, - {2293247016, 0, 0}, - {2503194620, 0, 0}, - {2608484640, 0, 0}, - {2615111110, 0, 0}, - {2668769415, 0, 0}, - {2759951687, 0, 0}, - {2761603302, 0, 0}, - {2856623532, 0, 0}, - {2956189845, 0, 0}, - {3085119011, 0, 0}, - {3367313400, 0, 0}, - {3447882276, 0, 0}, - {3633746133, 0, 0}, - {3635397748, 0, 0}, - {3710645347, 0, 0}, - {3712296962, 0, 0}, - {3727494858, 0, 0}, - {3747079365, 0, 0}, - {3748965853, 0, 0}, - {3750617468, 0, 0}, - {4018820793, 0, 0}, - {4022124023, 0, 0}, - {4024173916, 0, 0}, - {4215670524, 0, 0}, - {4217322139, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 39, 28}, - {0, 29, 40}, - {0, 37, 33}, - {0, 38, 12}, - {0, 9, 26}, - {0, 18, 6}, - {0, 41, 3}, - {0, 11, 13}, - {0, 5, 8}, - {0, 45, 30}, - {0, 22, 46}, - {0, 48, 47}, - {0, 16, 17}, - {0, 34, 49}, - {0, 51, 50}, - {0, 53, 52}, - {0, 7, 2}, - {0, 23, 21}, - {0, 54, 10}, - {0, 20, 36}, - {0, 55, 35}, - {0, 56, 4}, - {0, 43, 57}, - {0, 59, 58}, - {0, 60, 42}, - {0, 62, 61}, - {0, 63, 15}, - {0, 64, 31}, - {0, 14, 65}, - {0, 66, 24}, - {0, 67, 32}, - {0, 68, 19}, - {0, 70, 69}, - {0, 71, 27}, - {0, 73, 72}, - {0, 75, 74}, - {0, 77, 76}, - {0, 78, 25}, - {0, 44, 79}, - {0, 81, 80}, - {0, 83, 82}, - {0, 1, 84}, - {0, 86, 85}, - })); - - codecs.emplace(std::pair(SpvOpFunction, 3), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(41, { - {0, 0, 0}, - {436416061, 0, 0}, - {543621065, 0, 0}, - {679771963, 0, 0}, - {815757910, 0, 0}, - {827698488, 0, 0}, - {1294403159, 0, 0}, - {1296054774, 0, 0}, - {1297706389, 0, 0}, - {1579585816, 0, 0}, - {1675764636, 0, 0}, - {1824016656, 0, 0}, - {1951208733, 0, 0}, - {2194691858, 0, 0}, - {2320303498, 0, 0}, - {2926633629, 0, 0}, - {3095831808, 0, 0}, - {3249265647, 0, 0}, - {3334207724, 0, 0}, - {4050155669, 0, 0}, - {4141567741, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 2, 11}, - {0, 19, 16}, - {0, 9, 4}, - {0, 1, 17}, - {0, 22, 10}, - {0, 24, 23}, - {0, 15, 25}, - {0, 13, 26}, - {0, 27, 20}, - {0, 12, 28}, - {0, 30, 29}, - {0, 31, 18}, - {0, 3, 21}, - {0, 32, 14}, - {0, 34, 33}, - {0, 35, 8}, - {0, 5, 6}, - {0, 37, 36}, - {0, 39, 38}, - {0, 40, 7}, - })); - - codecs.emplace(std::pair(SpvOpFunctionParameter, 0), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(41, { - {0, 0, 0}, - {522971108, 0, 0}, - {615341051, 0, 0}, - {718301639, 0, 0}, - {985750227, 0, 0}, - {1395113939, 0, 0}, - {1510333659, 0, 0}, - {1642805350, 0, 0}, - {1846856260, 0, 0}, - {1957218950, 0, 0}, - {1977038330, 0, 0}, - {1978689945, 0, 0}, - {1980341560, 0, 0}, - {2262220987, 0, 0}, - {2674422363, 0, 0}, - {3197739982, 0, 0}, - {3465954368, 0, 0}, - {3941049054, 0, 0}, - {3945795573, 0, 0}, - {4080527786, 0, 0}, - {4154758669, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 3, 17}, - {0, 4, 15}, - {0, 8, 7}, - {0, 2, 20}, - {0, 22, 19}, - {0, 24, 23}, - {0, 14, 25}, - {0, 16, 26}, - {0, 27, 13}, - {0, 6, 28}, - {0, 30, 29}, - {0, 31, 10}, - {0, 11, 21}, - {0, 32, 12}, - {0, 34, 33}, - {0, 35, 5}, - {0, 9, 18}, - {0, 37, 36}, - {0, 39, 38}, - {0, 40, 1}, - })); - - codecs.emplace(std::pair(SpvOpFunctionParameter, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(27, { - {0, 0, 0}, - {545678922, 0, 0}, - {679771963, 0, 0}, - {899570100, 0, 0}, - {929101967, 0, 0}, - {1100599986, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {3056042030, 0, 0}, - {3334207724, 0, 0}, - {3357250579, 0, 0}, - {3705139860, 0, 0}, - {3800912395, 0, 0}, - {3802564010, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 5, 3}, - {0, 10, 13}, - {0, 4, 15}, - {0, 16, 11}, - {0, 17, 1}, - {0, 14, 12}, - {0, 19, 18}, - {0, 21, 20}, - {0, 22, 8}, - {0, 7, 6}, - {0, 23, 9}, - {0, 25, 24}, - {0, 26, 2}, - })); - - codecs.emplace(std::pair(SpvOpFunctionCall, 0), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(115, { - {0, 0, 0}, - {57149555, 0, 0}, - {86116519, 0, 0}, - {168339452, 0, 0}, - {181902171, 0, 0}, - {284226441, 0, 0}, - {314809953, 0, 0}, - {330249537, 0, 0}, - {527665290, 0, 0}, - {545363837, 0, 0}, - {707478563, 0, 0}, - {740921498, 0, 0}, - {807276090, 0, 0}, - {824323032, 0, 0}, - {835458563, 0, 0}, - {1162127370, 0, 0}, - {1245448751, 0, 0}, - {1277245109, 0, 0}, - {1375043498, 0, 0}, - {1380991098, 0, 0}, - {1603937321, 0, 0}, - {1708264968, 0, 0}, - {1717555224, 0, 0}, - {1765126703, 0, 0}, - {1838993983, 0, 0}, - {1949856502, 0, 0}, - {2108571893, 0, 0}, - {2110223508, 0, 0}, - {2293637521, 0, 0}, - {2377112119, 0, 0}, - {2378763734, 0, 0}, - {2512398201, 0, 0}, - {2516325050, 0, 0}, - {2645135839, 0, 0}, - {2708915136, 0, 0}, - {2894979602, 0, 0}, - {2903897222, 0, 0}, - {2976581453, 0, 0}, - {3054834317, 0, 0}, - {3075866530, 0, 0}, - {3085157904, 0, 0}, - {3242843022, 0, 0}, - {3266028549, 0, 0}, - {3296691317, 0, 0}, - {3299488628, 0, 0}, - {3322500634, 0, 0}, - {3345707173, 0, 0}, - {3536390697, 0, 0}, - {3584683259, 0, 0}, - {3647606635, 0, 0}, - {3760372982, 0, 0}, - {3823959661, 0, 0}, - {3839389658, 0, 0}, - {4124281183, 0, 0}, - {4130950286, 0, 0}, - {4169878842, 0, 0}, - {4174489262, 0, 0}, - {4237497041, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 17, 23}, - {0, 37, 8}, - {0, 45, 39}, - {0, 41, 14}, - {0, 48, 43}, - {0, 40, 31}, - {0, 19, 29}, - {0, 53, 26}, - {0, 10, 5}, - {0, 50, 24}, - {0, 27, 3}, - {0, 59, 32}, - {0, 51, 18}, - {0, 52, 55}, - {0, 60, 57}, - {0, 62, 61}, - {0, 36, 33}, - {0, 64, 63}, - {0, 65, 22}, - {0, 66, 46}, - {0, 6, 67}, - {0, 68, 13}, - {0, 21, 44}, - {0, 1, 69}, - {0, 30, 11}, - {0, 71, 70}, - {0, 12, 72}, - {0, 74, 73}, - {0, 76, 75}, - {0, 16, 2}, - {0, 49, 35}, - {0, 77, 9}, - {0, 42, 28}, - {0, 15, 78}, - {0, 80, 79}, - {0, 82, 81}, - {0, 47, 83}, - {0, 85, 84}, - {0, 87, 86}, - {0, 89, 88}, - {0, 20, 38}, - {0, 54, 90}, - {0, 34, 91}, - {0, 93, 92}, - {0, 25, 94}, - {0, 95, 7}, - {0, 97, 96}, - {0, 56, 98}, - {0, 100, 99}, - {0, 102, 101}, - {0, 104, 103}, - {0, 4, 105}, - {0, 107, 106}, - {0, 58, 108}, - {0, 110, 109}, - {0, 112, 111}, - {0, 114, 113}, - })); - - codecs.emplace(std::pair(SpvOpFunctionCall, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(81, { - {0, 0, 0}, - {35240468, 0, 0}, - {36096192, 0, 0}, - {123060826, 0, 0}, - {184634770, 0, 0}, - {459968607, 0, 0}, - {619875033, 0, 0}, - {950731750, 0, 0}, - {1058429216, 0, 0}, - {1182296898, 0, 0}, - {1238120570, 0, 0}, - {1271484400, 0, 0}, - {1429389803, 0, 0}, - {1717510093, 0, 0}, - {1766422419, 0, 0}, - {1775308984, 0, 0}, - {1817271123, 0, 0}, - {1917336504, 0, 0}, - {1957265068, 0, 0}, - {1998433745, 0, 0}, - {2055664760, 0, 0}, - {2303184249, 0, 0}, - {2308565678, 0, 0}, - {2451531615, 0, 0}, - {2496297824, 0, 0}, - {2507457870, 0, 0}, - {2550501832, 0, 0}, - {2590402790, 0, 0}, - {2649103430, 0, 0}, - {2831059514, 0, 0}, - {2836440943, 0, 0}, - {3269075805, 0, 0}, - {3361419439, 0, 0}, - {3457269042, 0, 0}, - {3464197236, 0, 0}, - {3472029049, 0, 0}, - {3518630848, 0, 0}, - {3587381650, 0, 0}, - {3653985133, 0, 0}, - {4185590212, 0, 0}, - {4233562270, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 40, 37}, - {0, 22, 30}, - {0, 2, 7}, - {0, 24, 11}, - {0, 16, 33}, - {0, 6, 34}, - {0, 42, 27}, - {0, 5, 43}, - {0, 4, 44}, - {0, 36, 8}, - {0, 39, 45}, - {0, 46, 1}, - {0, 3, 47}, - {0, 48, 23}, - {0, 49, 9}, - {0, 50, 35}, - {0, 52, 51}, - {0, 32, 53}, - {0, 13, 10}, - {0, 26, 14}, - {0, 19, 54}, - {0, 55, 25}, - {0, 56, 38}, - {0, 17, 57}, - {0, 59, 58}, - {0, 61, 60}, - {0, 62, 29}, - {0, 12, 15}, - {0, 18, 63}, - {0, 28, 64}, - {0, 65, 31}, - {0, 67, 66}, - {0, 20, 41}, - {0, 69, 68}, - {0, 71, 70}, - {0, 21, 72}, - {0, 74, 73}, - {0, 76, 75}, - {0, 78, 77}, - {0, 80, 79}, - })); - - codecs.emplace(std::pair(SpvOpFunctionCall, 2), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(61, { - {0, 0, 0}, - {37459569, 0, 0}, - {162167595, 0, 0}, - {535067202, 0, 0}, - {701281393, 0, 0}, - {837715723, 0, 0}, - {1320550031, 0, 0}, - {1630583316, 0, 0}, - {1913735398, 0, 0}, - {1918481917, 0, 0}, - {1955871800, 0, 0}, - {1977038330, 0, 0}, - {2053214130, 0, 0}, - {2443959748, 0, 0}, - {2564745684, 0, 0}, - {2622612602, 0, 0}, - {2677252364, 0, 0}, - {2736026107, 0, 0}, - {2790624748, 0, 0}, - {2882994691, 0, 0}, - {2888125966, 0, 0}, - {2970183398, 0, 0}, - {3253403867, 0, 0}, - {3427283542, 0, 0}, - {3570411982, 0, 0}, - {3619787319, 0, 0}, - {3662767579, 0, 0}, - {3884846406, 0, 0}, - {3910458990, 0, 0}, - {3927915220, 0, 0}, - {4224872590, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 5, 20}, - {0, 6, 25}, - {0, 23, 3}, - {0, 2, 4}, - {0, 14, 17}, - {0, 11, 8}, - {0, 27, 10}, - {0, 19, 28}, - {0, 12, 16}, - {0, 33, 32}, - {0, 35, 34}, - {0, 37, 36}, - {0, 39, 38}, - {0, 40, 15}, - {0, 41, 7}, - {0, 1, 21}, - {0, 24, 13}, - {0, 29, 42}, - {0, 44, 43}, - {0, 22, 45}, - {0, 47, 46}, - {0, 49, 48}, - {0, 50, 30}, - {0, 31, 51}, - {0, 53, 52}, - {0, 55, 54}, - {0, 56, 9}, - {0, 57, 26}, - {0, 59, 58}, - {0, 60, 18}, - })); - - codecs.emplace(std::pair(SpvOpFunctionCall, 3), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(39, { - {0, 0, 0}, - {744062262, 0, 0}, - {810488476, 0, 0}, - {1040775722, 0, 0}, - {1280126114, 0, 0}, - {1367301635, 0, 0}, - {1684282922, 0, 0}, - {1918481917, 0, 0}, - {1978689945, 0, 0}, - {1980341560, 0, 0}, - {2443959748, 0, 0}, - {2629265310, 0, 0}, - {2790624748, 0, 0}, - {2970183398, 0, 0}, - {3044188332, 0, 0}, - {3496407048, 0, 0}, - {3662767579, 0, 0}, - {3887377256, 0, 0}, - {3971481069, 0, 0}, - {4224872590, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 3, 2}, - {0, 18, 15}, - {0, 21, 6}, - {0, 13, 11}, - {0, 4, 22}, - {0, 14, 1}, - {0, 24, 23}, - {0, 25, 8}, - {0, 27, 26}, - {0, 20, 17}, - {0, 5, 28}, - {0, 29, 9}, - {0, 16, 10}, - {0, 31, 30}, - {0, 32, 7}, - {0, 19, 33}, - {0, 35, 34}, - {0, 37, 36}, - {0, 38, 12}, - })); - - codecs.emplace(std::pair(SpvOpFunctionCall, 4), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(27, { - {0, 0, 0}, - {37459569, 0, 0}, - {837715723, 0, 0}, - {1352628475, 0, 0}, - {1918481917, 0, 0}, - {1978689945, 0, 0}, - {1980341560, 0, 0}, - {2096388952, 0, 0}, - {2622612602, 0, 0}, - {2790624748, 0, 0}, - {2970183398, 0, 0}, - {3510682541, 0, 0}, - {3783543823, 0, 0}, - {4224872590, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 7, 11}, - {0, 2, 8}, - {0, 15, 12}, - {0, 1, 3}, - {0, 16, 6}, - {0, 18, 17}, - {0, 19, 14}, - {0, 20, 5}, - {0, 10, 21}, - {0, 22, 4}, - {0, 23, 13}, - {0, 25, 24}, - {0, 9, 26}, - })); - - codecs.emplace(std::pair(SpvOpFunctionCall, 5), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(13, { - {0, 0, 0}, - {1510333659, 0, 0}, - {1684282922, 0, 0}, - {1918481917, 0, 0}, - {2790624748, 0, 0}, - {3662767579, 0, 0}, - {4224872590, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 5, 1}, - {0, 8, 2}, - {0, 9, 7}, - {0, 3, 10}, - {0, 6, 11}, - {0, 4, 12}, - })); - - codecs.emplace(std::pair(SpvOpFunctionCall, 6), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(27, { - {0, 0, 0}, - {161668409, 0, 0}, - {188347929, 0, 0}, - {653708953, 0, 0}, - {976111724, 0, 0}, - {1510333659, 0, 0}, - {1918481917, 0, 0}, - {2790624748, 0, 0}, - {3033873113, 0, 0}, - {3499234137, 0, 0}, - {3525913657, 0, 0}, - {3552593177, 0, 0}, - {3570411982, 0, 0}, - {4224872590, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 8, 3}, - {0, 2, 9}, - {0, 10, 11}, - {0, 15, 1}, - {0, 17, 16}, - {0, 19, 18}, - {0, 5, 4}, - {0, 20, 6}, - {0, 12, 21}, - {0, 14, 22}, - {0, 24, 23}, - {0, 7, 25}, - {0, 13, 26}, - })); - - codecs.emplace(std::pair(SpvOpFunctionCall, 7), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(31, { - {0, 0, 0}, - {226836633, 0, 0}, - {296981500, 0, 0}, - {718877177, 0, 0}, - {745556697, 0, 0}, - {798915737, 0, 0}, - {1510333659, 0, 0}, - {1684282922, 0, 0}, - {2444465148, 0, 0}, - {2713718873, 0, 0}, - {3495546641, 0, 0}, - {3564402361, 0, 0}, - {4056442905, 0, 0}, - {4083122425, 0, 0}, - {4123141705, 0, 0}, - {4224872590, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 14, 4}, - {0, 5, 3}, - {0, 9, 8}, - {0, 13, 12}, - {0, 1, 11}, - {0, 18, 17}, - {0, 2, 19}, - {0, 21, 20}, - {0, 23, 22}, - {0, 25, 24}, - {0, 26, 7}, - {0, 27, 16}, - {0, 10, 6}, - {0, 29, 28}, - {0, 15, 30}, - })); - - codecs.emplace(std::pair(SpvOpFunctionCall, 8), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(35, { - {0, 0, 0}, - {161668409, 0, 0}, - {188347929, 0, 0}, - {215027449, 0, 0}, - {296981500, 0, 0}, - {653708953, 0, 0}, - {680388473, 0, 0}, - {1119069977, 0, 0}, - {1510333659, 0, 0}, - {1584774136, 0, 0}, - {2049792025, 0, 0}, - {2444465148, 0, 0}, - {2568512089, 0, 0}, - {3033873113, 0, 0}, - {3499234137, 0, 0}, - {3525913657, 0, 0}, - {3552593177, 0, 0}, - {4224872590, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 7, 6}, - {0, 10, 12}, - {0, 4, 3}, - {0, 16, 11}, - {0, 19, 14}, - {0, 5, 2}, - {0, 20, 13}, - {0, 21, 15}, - {0, 1, 22}, - {0, 24, 23}, - {0, 26, 25}, - {0, 28, 27}, - {0, 18, 29}, - {0, 8, 30}, - {0, 32, 31}, - {0, 9, 33}, - {0, 17, 34}, - })); - - codecs.emplace(std::pair(SpvOpFunctionCall, 9), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(25, { - {0, 0, 0}, - {825595257, 0, 0}, - {1064945649, 0, 0}, - {1290956281, 0, 0}, - {1510333659, 0, 0}, - {2096388952, 0, 0}, - {2248357849, 0, 0}, - {2713718873, 0, 0}, - {3187066832, 0, 0}, - {3205759417, 0, 0}, - {4064212479, 0, 0}, - {4163160985, 0, 0}, - {4224872590, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 8, 3}, - {0, 2, 9}, - {0, 7, 6}, - {0, 5, 14}, - {0, 16, 15}, - {0, 17, 11}, - {0, 19, 18}, - {0, 20, 1}, - {0, 4, 13}, - {0, 22, 21}, - {0, 10, 23}, - {0, 12, 24}, - })); - - codecs.emplace(std::pair(SpvOpFunctionCall, 10), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(27, { - {0, 0, 0}, - {123108003, 0, 0}, - {296981500, 0, 0}, - {595410904, 0, 0}, - {1466938734, 0, 0}, - {1503477720, 0, 0}, - {1816558243, 0, 0}, - {1990431740, 0, 0}, - {2724625059, 0, 0}, - {2790624748, 0, 0}, - {2812498065, 0, 0}, - {3160388974, 0, 0}, - {3745223676, 0, 0}, - {3982311384, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 5, 13}, - {0, 8, 1}, - {0, 12, 11}, - {0, 15, 3}, - {0, 6, 4}, - {0, 16, 7}, - {0, 17, 14}, - {0, 18, 2}, - {0, 19, 10}, - {0, 21, 20}, - {0, 23, 22}, - {0, 25, 24}, - {0, 9, 26}, - })); - - codecs.emplace(std::pair(SpvOpFunctionCall, 11), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(25, { - {0, 0, 0}, - {94145952, 0, 0}, - {1054641568, 0, 0}, - {1269075360, 0, 0}, - {1675922848, 0, 0}, - {2038205856, 0, 0}, - {2433519008, 0, 0}, - {2636942752, 0, 0}, - {2790624748, 0, 0}, - {2840366496, 0, 0}, - {2851900832, 0, 0}, - {2964622752, 0, 0}, - {3654061472, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 7, 1}, - {0, 12, 6}, - {0, 14, 10}, - {0, 13, 4}, - {0, 11, 15}, - {0, 3, 16}, - {0, 2, 17}, - {0, 18, 5}, - {0, 9, 19}, - {0, 21, 20}, - {0, 23, 22}, - {0, 8, 24}, - })); - - codecs.emplace(std::pair(SpvOpFunctionCall, 12), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(45, { - {0, 0, 0}, - {107544081, 0, 0}, - {125015036, 0, 0}, - {586244865, 0, 0}, - {1033081852, 0, 0}, - {1064945649, 0, 0}, - {1155765244, 0, 0}, - {1304296041, 0, 0}, - {1543646433, 0, 0}, - {1782996825, 0, 0}, - {1941148668, 0, 0}, - {2002490364, 0, 0}, - {2022347217, 0, 0}, - {2063832060, 0, 0}, - {2487708241, 0, 0}, - {2726532092, 0, 0}, - {2849215484, 0, 0}, - {2966409025, 0, 0}, - {3445109809, 0, 0}, - {3458449569, 0, 0}, - {3634598908, 0, 0}, - {3695940604, 0, 0}, - {3923810593, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 7, 2}, - {0, 14, 13}, - {0, 1, 23}, - {0, 6, 5}, - {0, 16, 15}, - {0, 24, 17}, - {0, 12, 25}, - {0, 22, 18}, - {0, 10, 26}, - {0, 28, 27}, - {0, 21, 29}, - {0, 31, 30}, - {0, 9, 8}, - {0, 11, 32}, - {0, 33, 19}, - {0, 3, 34}, - {0, 36, 35}, - {0, 38, 37}, - {0, 20, 39}, - {0, 41, 40}, - {0, 42, 4}, - {0, 44, 43}, - })); - - codecs.emplace(std::pair(SpvOpFunctionCall, 13), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(23, { - {0, 0, 0}, - {247698428, 0, 0}, - {309040124, 0, 0}, - {333554713, 0, 0}, - {572905105, 0, 0}, - {1033081852, 0, 0}, - {2002490364, 0, 0}, - {2009007457, 0, 0}, - {2487708241, 0, 0}, - {3634598908, 0, 0}, - {3695940604, 0, 0}, - {3923810593, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 6, 1}, - {0, 9, 7}, - {0, 5, 12}, - {0, 14, 13}, - {0, 15, 8}, - {0, 3, 16}, - {0, 17, 11}, - {0, 10, 4}, - {0, 2, 18}, - {0, 20, 19}, - {0, 22, 21}, - })); - - codecs.emplace(std::pair(SpvOpFunctionCall, 14), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(11, { - {0, 0, 0}, - {247698428, 0, 0}, - {1033081852, 0, 0}, - {2002490364, 0, 0}, - {2910557180, 0, 0}, - {3757282300, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 6, 4}, - {0, 7, 3}, - {0, 2, 8}, - {0, 1, 5}, - {0, 10, 9}, - })); - - codecs.emplace(std::pair(SpvOpFunctionCall, 15), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(9, { - {0, 0, 0}, - {1033081852, 0, 0}, - {1094423548, 0, 0}, - {2002490364, 0, 0}, - {3757282300, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 3, 5}, - {0, 6, 2}, - {0, 4, 7}, - {0, 8, 1}, - })); - - codecs.emplace(std::pair(SpvOpFunctionCall, 16), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(57, { - {0, 0, 0}, - {135486769, 0, 0}, - {450406196, 0, 0}, - {503094540, 0, 0}, - {543621065, 0, 0}, - {827698488, 0, 0}, - {1294403159, 0, 0}, - {1296054774, 0, 0}, - {1297706389, 0, 0}, - {1322549027, 0, 0}, - {1784441183, 0, 0}, - {2194691858, 0, 0}, - {2448331885, 0, 0}, - {2468230023, 0, 0}, - {2547657777, 0, 0}, - {2549309392, 0, 0}, - {2550961007, 0, 0}, - {2934934694, 0, 0}, - {2936586309, 0, 0}, - {2938237924, 0, 0}, - {3094180193, 0, 0}, - {3095831808, 0, 0}, - {3183924418, 0, 0}, - {3561562003, 0, 0}, - {3563213618, 0, 0}, - {3564865233, 0, 0}, - {4028622909, 0, 0}, - {4039938779, 0, 0}, - {4050155669, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 27, 28}, - {0, 10, 2}, - {0, 25, 24}, - {0, 1, 12}, - {0, 30, 3}, - {0, 20, 31}, - {0, 9, 32}, - {0, 34, 33}, - {0, 35, 22}, - {0, 26, 15}, - {0, 19, 36}, - {0, 18, 37}, - {0, 38, 16}, - {0, 39, 8}, - {0, 5, 40}, - {0, 6, 41}, - {0, 21, 42}, - {0, 11, 29}, - {0, 4, 43}, - {0, 13, 23}, - {0, 14, 17}, - {0, 7, 44}, - {0, 46, 45}, - {0, 48, 47}, - {0, 50, 49}, - {0, 52, 51}, - {0, 54, 53}, - {0, 56, 55}, - })); - - codecs.emplace(std::pair(SpvOpVariable, 0), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(57, { - {0, 0, 0}, - {37459569, 0, 0}, - {112745085, 0, 0}, - {137840602, 0, 0}, - {565334834, 0, 0}, - {625975427, 0, 0}, - {630964591, 0, 0}, - {680016782, 0, 0}, - {769422756, 0, 0}, - {1009983433, 0, 0}, - {1093210099, 0, 0}, - {1572088444, 0, 0}, - {1584774136, 0, 0}, - {1641565587, 0, 0}, - {1918481917, 0, 0}, - {2190437442, 0, 0}, - {2790624748, 0, 0}, - {3085467405, 0, 0}, - {3181646225, 0, 0}, - {3192069648, 0, 0}, - {3253403867, 0, 0}, - {3390051757, 0, 0}, - {3560665067, 0, 0}, - {3662767579, 0, 0}, - {4053789056, 0, 0}, - {4064212479, 0, 0}, - {4192247221, 0, 0}, - {4224872590, 0, 0}, - {4290024976, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 2, 20}, - {0, 28, 10}, - {0, 13, 8}, - {0, 15, 17}, - {0, 30, 21}, - {0, 19, 31}, - {0, 4, 32}, - {0, 34, 33}, - {0, 35, 5}, - {0, 7, 24}, - {0, 9, 36}, - {0, 3, 37}, - {0, 38, 6}, - {0, 39, 23}, - {0, 27, 40}, - {0, 14, 41}, - {0, 25, 42}, - {0, 1, 29}, - {0, 12, 43}, - {0, 11, 26}, - {0, 18, 22}, - {0, 16, 44}, - {0, 46, 45}, - {0, 48, 47}, - {0, 50, 49}, - {0, 52, 51}, - {0, 54, 53}, - {0, 56, 55}, - })); - - codecs.emplace(std::pair(SpvOpVariable, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(27, { - {0, 0, 0}, - {162255877, 0, 0}, - {679771963, 0, 0}, - {789872778, 0, 0}, - {1154919607, 0, 0}, - {1343794461, 0, 0}, - {1951208733, 0, 0}, - {2263349224, 0, 0}, - {2320303498, 0, 0}, - {2924146124, 0, 0}, - {2984325996, 0, 0}, - {3334207724, 0, 0}, - {3868239231, 0, 0}, - {3869890846, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 5, 3}, - {0, 9, 7}, - {0, 12, 4}, - {0, 16, 15}, - {0, 18, 17}, - {0, 14, 19}, - {0, 13, 10}, - {0, 20, 1}, - {0, 21, 8}, - {0, 2, 22}, - {0, 11, 23}, - {0, 6, 24}, - {0, 26, 25}, - })); - - codecs.emplace(std::pair(SpvOpLoad, 0), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(83, { - {0, 0, 0}, - {169674806, 0, 0}, - {269823086, 0, 0}, - {408465899, 0, 0}, - {451264926, 0, 0}, - {543558236, 0, 0}, - {810488476, 0, 0}, - {850497536, 0, 0}, - {870594305, 0, 0}, - {883854656, 0, 0}, - {1033363654, 0, 0}, - {1069781886, 0, 0}, - {1141965917, 0, 0}, - {1323407757, 0, 0}, - {1570165302, 0, 0}, - {1684282922, 0, 0}, - {1742737136, 0, 0}, - {1901166356, 0, 0}, - {1949759310, 0, 0}, - {2043873558, 0, 0}, - {2087004702, 0, 0}, - {2096388952, 0, 0}, - {2157103435, 0, 0}, - {2219733501, 0, 0}, - {2356768706, 0, 0}, - {2443959748, 0, 0}, - {2517964682, 0, 0}, - {2614879967, 0, 0}, - {2622612602, 0, 0}, - {2660843182, 0, 0}, - {2959147533, 0, 0}, - {2970183398, 0, 0}, - {3044188332, 0, 0}, - {3091876332, 0, 0}, - {3187066832, 0, 0}, - {3244209297, 0, 0}, - {3487022798, 0, 0}, - {3496407048, 0, 0}, - {3570411982, 0, 0}, - {3692647551, 0, 0}, - {3713290482, 0, 0}, - {3831290364, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 4, 1}, - {0, 35, 13}, - {0, 25, 11}, - {0, 7, 10}, - {0, 19, 36}, - {0, 43, 27}, - {0, 16, 29}, - {0, 22, 3}, - {0, 41, 30}, - {0, 44, 12}, - {0, 2, 24}, - {0, 40, 32}, - {0, 23, 45}, - {0, 46, 39}, - {0, 17, 33}, - {0, 48, 47}, - {0, 8, 49}, - {0, 51, 50}, - {0, 52, 20}, - {0, 53, 14}, - {0, 31, 54}, - {0, 15, 55}, - {0, 57, 56}, - {0, 59, 58}, - {0, 6, 26}, - {0, 61, 60}, - {0, 34, 62}, - {0, 64, 63}, - {0, 5, 37}, - {0, 9, 65}, - {0, 18, 28}, - {0, 66, 38}, - {0, 68, 67}, - {0, 69, 21}, - {0, 71, 70}, - {0, 73, 72}, - {0, 75, 74}, - {0, 77, 76}, - {0, 79, 78}, - {0, 80, 42}, - {0, 82, 81}, - })); - - codecs.emplace(std::pair(SpvOpLoad, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(83, { - {0, 0, 0}, - {28782128, 0, 0}, - {30433743, 0, 0}, - {37459569, 0, 0}, - {137840602, 0, 0}, - {522971108, 0, 0}, - {565334834, 0, 0}, - {625975427, 0, 0}, - {630964591, 0, 0}, - {680016782, 0, 0}, - {1009983433, 0, 0}, - {1079999262, 0, 0}, - {1395113939, 0, 0}, - {1572088444, 0, 0}, - {1584774136, 0, 0}, - {1649426421, 0, 0}, - {1918481917, 0, 0}, - {1957218950, 0, 0}, - {2311941439, 0, 0}, - {2313593054, 0, 0}, - {2790624748, 0, 0}, - {2838165089, 0, 0}, - {2839816704, 0, 0}, - {2841468319, 0, 0}, - {3085467405, 0, 0}, - {3181646225, 0, 0}, - {3192069648, 0, 0}, - {3253403867, 0, 0}, - {3364388739, 0, 0}, - {3366040354, 0, 0}, - {3367691969, 0, 0}, - {3369343584, 0, 0}, - {3560665067, 0, 0}, - {3662767579, 0, 0}, - {3945795573, 0, 0}, - {4053789056, 0, 0}, - {4064212479, 0, 0}, - {4224872590, 0, 0}, - {4239834800, 0, 0}, - {4241486415, 0, 0}, - {4243138030, 0, 0}, - {4244789645, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 27}, - {0, 15, 2}, - {0, 10, 26}, - {0, 7, 24}, - {0, 9, 31}, - {0, 43, 30}, - {0, 29, 12}, - {0, 11, 41}, - {0, 40, 39}, - {0, 44, 23}, - {0, 22, 6}, - {0, 34, 35}, - {0, 18, 45}, - {0, 46, 21}, - {0, 17, 19}, - {0, 48, 47}, - {0, 28, 49}, - {0, 51, 50}, - {0, 52, 38}, - {0, 53, 33}, - {0, 4, 54}, - {0, 13, 55}, - {0, 57, 56}, - {0, 59, 58}, - {0, 37, 8}, - {0, 61, 60}, - {0, 5, 62}, - {0, 64, 63}, - {0, 36, 32}, - {0, 3, 65}, - {0, 14, 16}, - {0, 66, 25}, - {0, 68, 67}, - {0, 69, 20}, - {0, 71, 70}, - {0, 73, 72}, - {0, 75, 74}, - {0, 77, 76}, - {0, 79, 78}, - {0, 80, 42}, - {0, 82, 81}, - })); - - codecs.emplace(std::pair(SpvOpLoad, 2), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(49, { - {0, 0, 0}, - {137840602, 0, 0}, - {522971108, 0, 0}, - {769422756, 0, 0}, - {1009983433, 0, 0}, - {1079999262, 0, 0}, - {1558345254, 0, 0}, - {1572088444, 0, 0}, - {1641565587, 0, 0}, - {1918481917, 0, 0}, - {2311941439, 0, 0}, - {2313593054, 0, 0}, - {2790624748, 0, 0}, - {2838165089, 0, 0}, - {2994529201, 0, 0}, - {2996180816, 0, 0}, - {2997832431, 0, 0}, - {3027538652, 0, 0}, - {3253403867, 0, 0}, - {3364388739, 0, 0}, - {3560665067, 0, 0}, - {3662767579, 0, 0}, - {3945795573, 0, 0}, - {4192247221, 0, 0}, - {4224872590, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 14, 17}, - {0, 16, 15}, - {0, 13, 11}, - {0, 10, 3}, - {0, 22, 18}, - {0, 6, 8}, - {0, 19, 2}, - {0, 27, 26}, - {0, 28, 5}, - {0, 30, 29}, - {0, 32, 31}, - {0, 34, 33}, - {0, 4, 35}, - {0, 37, 36}, - {0, 21, 1}, - {0, 39, 38}, - {0, 40, 24}, - {0, 7, 23}, - {0, 20, 9}, - {0, 42, 41}, - {0, 43, 25}, - {0, 44, 12}, - {0, 46, 45}, - {0, 48, 47}, - })); - - codecs.emplace(std::pair(SpvOpStore, 0), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(59, { - {0, 0, 0}, - {139011596, 0, 0}, - {177111659, 0, 0}, - {296981500, 0, 0}, - {408465899, 0, 0}, - {495107308, 0, 0}, - {810488476, 0, 0}, - {870594305, 0, 0}, - {1367301635, 0, 0}, - {1901166356, 0, 0}, - {2055836767, 0, 0}, - {2087004702, 0, 0}, - {2096388952, 0, 0}, - {2204920111, 0, 0}, - {2517964682, 0, 0}, - {2622612602, 0, 0}, - {2660843182, 0, 0}, - {2842919847, 0, 0}, - {2855506940, 0, 0}, - {2959147533, 0, 0}, - {3044188332, 0, 0}, - {3187066832, 0, 0}, - {3504158761, 0, 0}, - {3570411982, 0, 0}, - {3619787319, 0, 0}, - {3653838348, 0, 0}, - {3692647551, 0, 0}, - {3764205609, 0, 0}, - {3831290364, 0, 0}, - {3913885196, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 20, 29}, - {0, 25, 8}, - {0, 5, 1}, - {0, 24, 26}, - {0, 14, 9}, - {0, 27, 16}, - {0, 31, 7}, - {0, 33, 32}, - {0, 17, 34}, - {0, 35, 13}, - {0, 22, 6}, - {0, 3, 2}, - {0, 23, 36}, - {0, 28, 37}, - {0, 19, 4}, - {0, 38, 10}, - {0, 39, 15}, - {0, 40, 18}, - {0, 42, 41}, - {0, 43, 12}, - {0, 44, 21}, - {0, 45, 11}, - {0, 47, 46}, - {0, 49, 48}, - {0, 51, 50}, - {0, 53, 52}, - {0, 55, 54}, - {0, 57, 56}, - {0, 30, 58}, - })); - - codecs.emplace(std::pair(SpvOpStore, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(35, { - {0, 0, 0}, - {440421571, 0, 0}, - {827698488, 0, 0}, - {907126242, 0, 0}, - {908777857, 0, 0}, - {910429472, 0, 0}, - {1294403159, 0, 0}, - {1296054774, 0, 0}, - {1297706389, 0, 0}, - {2080953106, 0, 0}, - {2468230023, 0, 0}, - {2547657777, 0, 0}, - {2549309392, 0, 0}, - {2550961007, 0, 0}, - {3094857332, 0, 0}, - {3561562003, 0, 0}, - {3563213618, 0, 0}, - {3564865233, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 16, 12}, - {0, 17, 13}, - {0, 14, 19}, - {0, 18, 20}, - {0, 5, 21}, - {0, 11, 7}, - {0, 15, 22}, - {0, 9, 8}, - {0, 24, 23}, - {0, 25, 4}, - {0, 27, 26}, - {0, 28, 3}, - {0, 29, 10}, - {0, 6, 1}, - {0, 31, 30}, - {0, 32, 2}, - {0, 34, 33}, - })); - - codecs.emplace(std::pair(SpvOpAccessChain, 0), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(99, { - {0, 0, 0}, - {27130513, 0, 0}, - {28782128, 0, 0}, - {30433743, 0, 0}, - {32085358, 0, 0}, - {155458798, 0, 0}, - {157110413, 0, 0}, - {163402553, 0, 0}, - {165054168, 0, 0}, - {213642219, 0, 0}, - {215293834, 0, 0}, - {216945449, 0, 0}, - {221900294, 0, 0}, - {545986953, 0, 0}, - {979993429, 0, 0}, - {1079999262, 0, 0}, - {1302400505, 0, 0}, - {1313182965, 0, 0}, - {1314834580, 0, 0}, - {1315613425, 0, 0}, - {1317265040, 0, 0}, - {1558345254, 0, 0}, - {1649426421, 0, 0}, - {2311941439, 0, 0}, - {2313593054, 0, 0}, - {2602027658, 0, 0}, - {2838165089, 0, 0}, - {2839816704, 0, 0}, - {2841468319, 0, 0}, - {2863084840, 0, 0}, - {2994529201, 0, 0}, - {2996180816, 0, 0}, - {2997832431, 0, 0}, - {3027538652, 0, 0}, - {3187387500, 0, 0}, - {3189039115, 0, 0}, - {3364388739, 0, 0}, - {3366040354, 0, 0}, - {3367691969, 0, 0}, - {3369343584, 0, 0}, - {3716914380, 0, 0}, - {3928842969, 0, 0}, - {3930494584, 0, 0}, - {3932146199, 0, 0}, - {3945482286, 0, 0}, - {4105051793, 0, 0}, - {4239834800, 0, 0}, - {4241486415, 0, 0}, - {4243138030, 0, 0}, - {4244789645, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 29, 10}, - {0, 17, 18}, - {0, 13, 14}, - {0, 44, 25}, - {0, 8, 7}, - {0, 20, 11}, - {0, 33, 19}, - {0, 6, 45}, - {0, 42, 43}, - {0, 40, 5}, - {0, 9, 16}, - {0, 1, 4}, - {0, 35, 34}, - {0, 12, 21}, - {0, 52, 51}, - {0, 31, 30}, - {0, 41, 32}, - {0, 54, 53}, - {0, 55, 2}, - {0, 3, 56}, - {0, 58, 57}, - {0, 60, 59}, - {0, 61, 22}, - {0, 63, 62}, - {0, 65, 64}, - {0, 67, 66}, - {0, 39, 68}, - {0, 38, 69}, - {0, 47, 70}, - {0, 49, 71}, - {0, 28, 48}, - {0, 37, 15}, - {0, 73, 72}, - {0, 74, 27}, - {0, 23, 75}, - {0, 76, 26}, - {0, 24, 77}, - {0, 79, 78}, - {0, 81, 80}, - {0, 82, 46}, - {0, 36, 83}, - {0, 85, 84}, - {0, 87, 86}, - {0, 89, 88}, - {0, 91, 90}, - {0, 93, 92}, - {0, 95, 94}, - {0, 97, 96}, - {0, 50, 98}, - })); - - codecs.emplace(std::pair(SpvOpAccessChain, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(101, { - {0, 0, 0}, - {112745085, 0, 0}, - {116376005, 0, 0}, - {137840602, 0, 0}, - {400248103, 0, 0}, - {406044930, 0, 0}, - {468372467, 0, 0}, - {522971108, 0, 0}, - {615341051, 0, 0}, - {625975427, 0, 0}, - {630964591, 0, 0}, - {680016782, 0, 0}, - {763027711, 0, 0}, - {977312655, 0, 0}, - {1009983433, 0, 0}, - {1062250709, 0, 0}, - {1395113939, 0, 0}, - {1410849099, 0, 0}, - {1642805350, 0, 0}, - {1692932387, 0, 0}, - {1698730948, 0, 0}, - {1827244161, 0, 0}, - {1918481917, 0, 0}, - {2096472894, 0, 0}, - {2190437442, 0, 0}, - {2299842241, 0, 0}, - {2433358586, 0, 0}, - {2593325766, 0, 0}, - {2785441472, 0, 0}, - {2790624748, 0, 0}, - {2879917723, 0, 0}, - {2882994691, 0, 0}, - {2902069960, 0, 0}, - {3090408469, 0, 0}, - {3181646225, 0, 0}, - {3255947500, 0, 0}, - {3263901372, 0, 0}, - {3268751013, 0, 0}, - {3347863687, 0, 0}, - {3390051757, 0, 0}, - {3560665067, 0, 0}, - {3617689692, 0, 0}, - {3662767579, 0, 0}, - {3717523241, 0, 0}, - {3854557817, 0, 0}, - {3910458990, 0, 0}, - {3941049054, 0, 0}, - {3945795573, 0, 0}, - {4080527786, 0, 0}, - {4101009465, 0, 0}, - {4290024976, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 32, 44}, - {0, 41, 26}, - {0, 16, 10}, - {0, 27, 45}, - {0, 25, 38}, - {0, 12, 18}, - {0, 6, 35}, - {0, 46, 23}, - {0, 20, 37}, - {0, 52, 19}, - {0, 53, 21}, - {0, 54, 48}, - {0, 33, 55}, - {0, 3, 8}, - {0, 28, 56}, - {0, 13, 57}, - {0, 59, 58}, - {0, 1, 49}, - {0, 47, 60}, - {0, 61, 14}, - {0, 63, 62}, - {0, 64, 43}, - {0, 7, 4}, - {0, 65, 15}, - {0, 67, 66}, - {0, 68, 17}, - {0, 36, 2}, - {0, 30, 69}, - {0, 71, 70}, - {0, 34, 5}, - {0, 73, 72}, - {0, 75, 74}, - {0, 77, 76}, - {0, 24, 78}, - {0, 39, 31}, - {0, 80, 79}, - {0, 9, 11}, - {0, 42, 81}, - {0, 83, 82}, - {0, 29, 50}, - {0, 84, 51}, - {0, 86, 85}, - {0, 22, 40}, - {0, 88, 87}, - {0, 90, 89}, - {0, 92, 91}, - {0, 94, 93}, - {0, 96, 95}, - {0, 98, 97}, - {0, 100, 99}, - })); - - codecs.emplace(std::pair(SpvOpAccessChain, 2), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(69, { - {0, 0, 0}, - {51041423, 0, 0}, - {142465290, 0, 0}, - {144116905, 0, 0}, - {290391815, 0, 0}, - {438318340, 0, 0}, - {529742207, 0, 0}, - {677668732, 0, 0}, - {917019124, 0, 0}, - {1064945649, 0, 0}, - {1156369516, 0, 0}, - {1158021131, 0, 0}, - {1304296041, 0, 0}, - {1452222566, 0, 0}, - {1543646433, 0, 0}, - {1691572958, 0, 0}, - {1782996825, 0, 0}, - {1784648440, 0, 0}, - {1930923350, 0, 0}, - {2170273742, 0, 0}, - {2318200267, 0, 0}, - {2466126792, 0, 0}, - {2557550659, 0, 0}, - {2705477184, 0, 0}, - {2796901051, 0, 0}, - {2798552666, 0, 0}, - {2944827576, 0, 0}, - {3092754101, 0, 0}, - {3184177968, 0, 0}, - {3332104493, 0, 0}, - {3571454885, 0, 0}, - {3810805277, 0, 0}, - {3958731802, 0, 0}, - {4106658327, 0, 0}, - {4198082194, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 27, 33}, - {0, 21, 5}, - {0, 26, 13}, - {0, 20, 8}, - {0, 15, 7}, - {0, 37, 36}, - {0, 32, 29}, - {0, 38, 4}, - {0, 30, 1}, - {0, 9, 12}, - {0, 39, 18}, - {0, 22, 40}, - {0, 42, 41}, - {0, 44, 43}, - {0, 45, 35}, - {0, 46, 34}, - {0, 6, 14}, - {0, 28, 23}, - {0, 48, 47}, - {0, 49, 31}, - {0, 51, 50}, - {0, 19, 24}, - {0, 52, 10}, - {0, 2, 53}, - {0, 55, 54}, - {0, 25, 56}, - {0, 11, 57}, - {0, 59, 58}, - {0, 3, 17}, - {0, 61, 60}, - {0, 16, 62}, - {0, 64, 63}, - {0, 66, 65}, - {0, 68, 67}, - })); - - codecs.emplace(std::pair(SpvOpAccessChain, 3), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(85, { - {0, 0, 0}, - {142465290, 0, 0}, - {144116905, 0, 0}, - {198967948, 0, 0}, - {290391815, 0, 0}, - {529742207, 0, 0}, - {586244865, 0, 0}, - {677668732, 0, 0}, - {825595257, 0, 0}, - {917019124, 0, 0}, - {973521782, 0, 0}, - {1064945649, 0, 0}, - {1156369516, 0, 0}, - {1158021131, 0, 0}, - {1212872174, 0, 0}, - {1304296041, 0, 0}, - {1452222566, 0, 0}, - {1543646433, 0, 0}, - {1600149091, 0, 0}, - {1782996825, 0, 0}, - {1784648440, 0, 0}, - {1839499483, 0, 0}, - {1930923350, 0, 0}, - {2170273742, 0, 0}, - {2226776400, 0, 0}, - {2318200267, 0, 0}, - {2466126792, 0, 0}, - {2557550659, 0, 0}, - {2614053317, 0, 0}, - {2796901051, 0, 0}, - {2798552666, 0, 0}, - {2853403709, 0, 0}, - {2944827576, 0, 0}, - {3184177968, 0, 0}, - {3240680626, 0, 0}, - {3480031018, 0, 0}, - {3571454885, 0, 0}, - {3810805277, 0, 0}, - {3867307935, 0, 0}, - {3958731802, 0, 0}, - {4106658327, 0, 0}, - {4198082194, 0, 0}, - {4254584852, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 7, 11}, - {0, 15, 4}, - {0, 32, 25}, - {0, 44, 39}, - {0, 36, 22}, - {0, 45, 17}, - {0, 24, 46}, - {0, 10, 9}, - {0, 6, 27}, - {0, 28, 18}, - {0, 42, 34}, - {0, 31, 14}, - {0, 41, 38}, - {0, 26, 3}, - {0, 47, 33}, - {0, 21, 8}, - {0, 5, 35}, - {0, 40, 16}, - {0, 37, 23}, - {0, 49, 48}, - {0, 51, 50}, - {0, 53, 52}, - {0, 55, 54}, - {0, 57, 56}, - {0, 59, 58}, - {0, 61, 60}, - {0, 63, 62}, - {0, 65, 64}, - {0, 67, 66}, - {0, 68, 12}, - {0, 29, 69}, - {0, 70, 1}, - {0, 30, 2}, - {0, 43, 71}, - {0, 73, 72}, - {0, 74, 20}, - {0, 75, 19}, - {0, 77, 76}, - {0, 13, 78}, - {0, 80, 79}, - {0, 82, 81}, - {0, 84, 83}, - })); - - codecs.emplace(std::pair(SpvOpAccessChain, 4), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(9, { - {0, 0, 0}, - {144116905, 0, 0}, - {1158021131, 0, 0}, - {1784648440, 0, 0}, - {2798552666, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 5}, - {0, 4, 2}, - {0, 6, 3}, - {0, 8, 7}, - })); - - codecs.emplace(std::pair(SpvOpAccessChain, 5), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(5, { - {0, 0, 0}, - {142465290, 0, 0}, - {1782996825, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 2, 1}, - {0, 4, 3}, - })); - - codecs.emplace(std::pair(SpvOpAccessChain, 6), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(7, { - {0, 0, 0}, - {679771963, 0, 0}, - {2320303498, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 3, 4}, - {0, 2, 5}, - {0, 6, 1}, - })); - - codecs.emplace(std::pair(SpvOpVectorShuffle, 0), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(59, { - {0, 0, 0}, - {177111659, 0, 0}, - {413918748, 0, 0}, - {529383565, 0, 0}, - {646282397, 0, 0}, - {837715723, 0, 0}, - {1019457583, 0, 0}, - {1022544883, 0, 0}, - {1054461787, 0, 0}, - {1097775533, 0, 0}, - {1136775085, 0, 0}, - {1191015885, 0, 0}, - {1196280518, 0, 0}, - {1203545131, 0, 0}, - {1352628475, 0, 0}, - {1367301635, 0, 0}, - {1918742169, 0, 0}, - {1922045399, 0, 0}, - {2055836767, 0, 0}, - {2183547611, 0, 0}, - {2204920111, 0, 0}, - {2358141757, 0, 0}, - {2572638469, 0, 0}, - {2597020383, 0, 0}, - {2842919847, 0, 0}, - {3619787319, 0, 0}, - {3701632935, 0, 0}, - {3783543823, 0, 0}, - {4245257809, 0, 0}, - {4265894873, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 11, 23}, - {0, 12, 2}, - {0, 9, 7}, - {0, 21, 19}, - {0, 4, 29}, - {0, 10, 28}, - {0, 17, 16}, - {0, 27, 3}, - {0, 32, 31}, - {0, 33, 22}, - {0, 6, 34}, - {0, 35, 8}, - {0, 36, 24}, - {0, 38, 37}, - {0, 1, 14}, - {0, 39, 20}, - {0, 5, 40}, - {0, 42, 41}, - {0, 43, 26}, - {0, 45, 44}, - {0, 47, 46}, - {0, 48, 18}, - {0, 15, 49}, - {0, 50, 25}, - {0, 51, 13}, - {0, 53, 52}, - {0, 55, 54}, - {0, 57, 56}, - {0, 30, 58}, - })); - - codecs.emplace(std::pair(SpvOpVectorShuffle, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(59, { - {0, 0, 0}, - {236660303, 0, 0}, - {342159236, 0, 0}, - {371428004, 0, 0}, - {373079619, 0, 0}, - {488500848, 0, 0}, - {495107308, 0, 0}, - {864295921, 0, 0}, - {1071164424, 0, 0}, - {1136911283, 0, 0}, - {1178317551, 0, 0}, - {1510422521, 0, 0}, - {1570165302, 0, 0}, - {1822823090, 0, 0}, - {1858116930, 0, 0}, - {1977038330, 0, 0}, - {2096388952, 0, 0}, - {2157103435, 0, 0}, - {2231688008, 0, 0}, - {2604576561, 0, 0}, - {2622612602, 0, 0}, - {2771938750, 0, 0}, - {2777172031, 0, 0}, - {2996594997, 0, 0}, - {3187066832, 0, 0}, - {3496407048, 0, 0}, - {3570411982, 0, 0}, - {3609540589, 0, 0}, - {3713290482, 0, 0}, - {3797761273, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 18, 8}, - {0, 27, 9}, - {0, 21, 10}, - {0, 14, 24}, - {0, 12, 19}, - {0, 11, 15}, - {0, 23, 2}, - {0, 7, 13}, - {0, 31, 22}, - {0, 32, 4}, - {0, 33, 29}, - {0, 34, 1}, - {0, 35, 3}, - {0, 37, 36}, - {0, 38, 28}, - {0, 39, 5}, - {0, 41, 40}, - {0, 42, 17}, - {0, 16, 43}, - {0, 45, 44}, - {0, 46, 6}, - {0, 48, 47}, - {0, 50, 49}, - {0, 52, 51}, - {0, 25, 53}, - {0, 54, 20}, - {0, 55, 26}, - {0, 57, 56}, - {0, 30, 58}, - })); - - codecs.emplace(std::pair(SpvOpVectorShuffle, 2), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(47, { - {0, 0, 0}, - {236660303, 0, 0}, - {342159236, 0, 0}, - {488500848, 0, 0}, - {495107308, 0, 0}, - {864295921, 0, 0}, - {1178317551, 0, 0}, - {1510422521, 0, 0}, - {1570165302, 0, 0}, - {1858116930, 0, 0}, - {1977038330, 0, 0}, - {2096388952, 0, 0}, - {2157103435, 0, 0}, - {2231688008, 0, 0}, - {2604576561, 0, 0}, - {2622612602, 0, 0}, - {2771938750, 0, 0}, - {2777172031, 0, 0}, - {2996594997, 0, 0}, - {3496407048, 0, 0}, - {3570411982, 0, 0}, - {3609540589, 0, 0}, - {3713290482, 0, 0}, - {3797761273, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 21, 13}, - {0, 16, 6}, - {0, 14, 9}, - {0, 7, 10}, - {0, 18, 2}, - {0, 17, 5}, - {0, 25, 8}, - {0, 22, 12}, - {0, 26, 23}, - {0, 27, 1}, - {0, 28, 3}, - {0, 30, 29}, - {0, 32, 31}, - {0, 34, 33}, - {0, 35, 11}, - {0, 36, 4}, - {0, 38, 37}, - {0, 40, 39}, - {0, 41, 15}, - {0, 42, 19}, - {0, 20, 43}, - {0, 45, 44}, - {0, 24, 46}, - })); - - codecs.emplace(std::pair(SpvOpVectorShuffle, 3), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(15, { - {0, 0, 0}, - {679771963, 0, 0}, - {1146476634, 0, 0}, - {2160380860, 0, 0}, - {2320303498, 0, 0}, - {3334207724, 0, 0}, - {3800912395, 0, 0}, - {3802564010, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 2, 3}, - {0, 9, 6}, - {0, 8, 7}, - {0, 11, 10}, - {0, 4, 12}, - {0, 5, 13}, - {0, 14, 1}, - })); - - codecs.emplace(std::pair(SpvOpCompositeConstruct, 0), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(79, { - {0, 0, 0}, - {107497541, 0, 0}, - {289648234, 0, 0}, - {348584153, 0, 0}, - {369686787, 0, 0}, - {429277936, 0, 0}, - {449954059, 0, 0}, - {508217552, 0, 0}, - {742917749, 0, 0}, - {1032593647, 0, 0}, - {1158929937, 0, 0}, - {1209418480, 0, 0}, - {1319785741, 0, 0}, - {1321616112, 0, 0}, - {1417363940, 0, 0}, - {1541020250, 0, 0}, - {1564342316, 0, 0}, - {1578775276, 0, 0}, - {1631434666, 0, 0}, - {1636389511, 0, 0}, - {2012838864, 0, 0}, - {2262137600, 0, 0}, - {2281956980, 0, 0}, - {2359973133, 0, 0}, - {2464905186, 0, 0}, - {2613179511, 0, 0}, - {2621255555, 0, 0}, - {2817335337, 0, 0}, - {2881302403, 0, 0}, - {3063300848, 0, 0}, - {3151638847, 0, 0}, - {3233393284, 0, 0}, - {3323682385, 0, 0}, - {3337532056, 0, 0}, - {3456899824, 0, 0}, - {3547456240, 0, 0}, - {3675926744, 0, 0}, - {3753486980, 0, 0}, - {3931641900, 0, 0}, - {3970432934, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 25, 1}, - {0, 6, 4}, - {0, 8, 19}, - {0, 39, 24}, - {0, 3, 2}, - {0, 34, 14}, - {0, 10, 9}, - {0, 18, 38}, - {0, 32, 15}, - {0, 27, 16}, - {0, 28, 35}, - {0, 13, 26}, - {0, 20, 23}, - {0, 21, 11}, - {0, 36, 33}, - {0, 5, 22}, - {0, 42, 41}, - {0, 43, 29}, - {0, 45, 44}, - {0, 7, 46}, - {0, 48, 47}, - {0, 30, 31}, - {0, 50, 49}, - {0, 52, 51}, - {0, 54, 53}, - {0, 55, 17}, - {0, 57, 56}, - {0, 59, 58}, - {0, 61, 60}, - {0, 62, 12}, - {0, 64, 63}, - {0, 66, 65}, - {0, 67, 37}, - {0, 69, 68}, - {0, 71, 70}, - {0, 73, 72}, - {0, 75, 74}, - {0, 77, 76}, - {0, 40, 78}, - })); - - codecs.emplace(std::pair(SpvOpCompositeConstruct, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(87, { - {0, 0, 0}, - {153013225, 0, 0}, - {296836635, 0, 0}, - {296981500, 0, 0}, - {778500192, 0, 0}, - {810488476, 0, 0}, - {848380423, 0, 0}, - {900522183, 0, 0}, - {910398460, 0, 0}, - {959681532, 0, 0}, - {1141965917, 0, 0}, - {1287304304, 0, 0}, - {1323407757, 0, 0}, - {1417363940, 0, 0}, - {1471851763, 0, 0}, - {1526654696, 0, 0}, - {1654776395, 0, 0}, - {1684282922, 0, 0}, - {1739837626, 0, 0}, - {1791352211, 0, 0}, - {2195550588, 0, 0}, - {2319227476, 0, 0}, - {2491124112, 0, 0}, - {2789375411, 0, 0}, - {2807448986, 0, 0}, - {2817579280, 0, 0}, - {2835131395, 0, 0}, - {2847102741, 0, 0}, - {2855506940, 0, 0}, - {2860348412, 0, 0}, - {3079287749, 0, 0}, - {3091876332, 0, 0}, - {3168953855, 0, 0}, - {3374978006, 0, 0}, - {3399062057, 0, 0}, - {3510257966, 0, 0}, - {3554463148, 0, 0}, - {3579593979, 0, 0}, - {3757851979, 0, 0}, - {3759503594, 0, 0}, - {3761155209, 0, 0}, - {3762806824, 0, 0}, - {3902853271, 0, 0}, - {4140081844, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 38, 42}, - {0, 14, 23}, - {0, 26, 18}, - {0, 39, 35}, - {0, 6, 40}, - {0, 16, 13}, - {0, 33, 34}, - {0, 12, 4}, - {0, 27, 41}, - {0, 25, 21}, - {0, 24, 1}, - {0, 37, 19}, - {0, 32, 22}, - {0, 2, 8}, - {0, 20, 17}, - {0, 43, 36}, - {0, 29, 15}, - {0, 46, 45}, - {0, 48, 47}, - {0, 50, 49}, - {0, 52, 51}, - {0, 54, 53}, - {0, 7, 55}, - {0, 56, 30}, - {0, 57, 5}, - {0, 59, 58}, - {0, 60, 11}, - {0, 9, 61}, - {0, 63, 62}, - {0, 65, 64}, - {0, 66, 31}, - {0, 68, 67}, - {0, 10, 69}, - {0, 71, 70}, - {0, 28, 72}, - {0, 74, 73}, - {0, 76, 75}, - {0, 78, 77}, - {0, 79, 3}, - {0, 81, 80}, - {0, 83, 82}, - {0, 85, 84}, - {0, 44, 86}, - })); - - codecs.emplace(std::pair(SpvOpCompositeConstruct, 2), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(81, { - {0, 0, 0}, - {14244860, 0, 0}, - {150820676, 0, 0}, - {153013225, 0, 0}, - {269823086, 0, 0}, - {289648234, 0, 0}, - {296981500, 0, 0}, - {678695941, 0, 0}, - {810488476, 0, 0}, - {850592577, 0, 0}, - {870594305, 0, 0}, - {910398460, 0, 0}, - {959681532, 0, 0}, - {1206571206, 0, 0}, - {1287304304, 0, 0}, - {1323407757, 0, 0}, - {1471851763, 0, 0}, - {1526654696, 0, 0}, - {1684282922, 0, 0}, - {1734446471, 0, 0}, - {1758530522, 0, 0}, - {2117320444, 0, 0}, - {2118972059, 0, 0}, - {2120623674, 0, 0}, - {2122275289, 0, 0}, - {2219733501, 0, 0}, - {2262321736, 0, 0}, - {2807448986, 0, 0}, - {2817579280, 0, 0}, - {2835131395, 0, 0}, - {2855506940, 0, 0}, - {2860348412, 0, 0}, - {2951272396, 0, 0}, - {3079287749, 0, 0}, - {3168953855, 0, 0}, - {3502816184, 0, 0}, - {3510257966, 0, 0}, - {3554463148, 0, 0}, - {3997952447, 0, 0}, - {4140081844, 0, 0}, - {4182141402, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 21, 26}, - {0, 29, 16}, - {0, 22, 36}, - {0, 1, 23}, - {0, 20, 5}, - {0, 19, 35}, - {0, 10, 38}, - {0, 13, 24}, - {0, 28, 7}, - {0, 27, 3}, - {0, 40, 2}, - {0, 34, 9}, - {0, 32, 11}, - {0, 33, 18}, - {0, 39, 37}, - {0, 31, 17}, - {0, 43, 42}, - {0, 45, 44}, - {0, 47, 46}, - {0, 49, 48}, - {0, 51, 50}, - {0, 8, 52}, - {0, 15, 53}, - {0, 55, 54}, - {0, 56, 14}, - {0, 58, 57}, - {0, 60, 59}, - {0, 61, 25}, - {0, 63, 62}, - {0, 4, 64}, - {0, 66, 65}, - {0, 68, 67}, - {0, 70, 69}, - {0, 71, 12}, - {0, 6, 72}, - {0, 30, 73}, - {0, 75, 74}, - {0, 77, 76}, - {0, 79, 78}, - {0, 41, 80}, - })); - - codecs.emplace(std::pair(SpvOpCompositeConstruct, 3), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(111, { - {0, 0, 0}, - {34183582, 0, 0}, - {93914936, 0, 0}, - {94303122, 0, 0}, - {117998987, 0, 0}, - {153013225, 0, 0}, - {296981500, 0, 0}, - {451264926, 0, 0}, - {473485679, 0, 0}, - {476788909, 0, 0}, - {478440524, 0, 0}, - {480092139, 0, 0}, - {481743754, 0, 0}, - {810488476, 0, 0}, - {871966503, 0, 0}, - {910398460, 0, 0}, - {918189168, 0, 0}, - {933769938, 0, 0}, - {959681532, 0, 0}, - {1149665466, 0, 0}, - {1166917451, 0, 0}, - {1227221002, 0, 0}, - {1310740861, 0, 0}, - {1323407757, 0, 0}, - {1341516288, 0, 0}, - {1373166395, 0, 0}, - {1445161581, 0, 0}, - {1461645203, 0, 0}, - {1471851763, 0, 0}, - {1526654696, 0, 0}, - {1561718045, 0, 0}, - {1593584949, 0, 0}, - {1684282922, 0, 0}, - {1800404122, 0, 0}, - {1862284649, 0, 0}, - {2213411495, 0, 0}, - {2668680621, 0, 0}, - {2805256437, 0, 0}, - {2807448986, 0, 0}, - {2835131395, 0, 0}, - {2855506940, 0, 0}, - {2860348412, 0, 0}, - {3000904950, 0, 0}, - {3107413701, 0, 0}, - {3168953855, 0, 0}, - {3333131702, 0, 0}, - {3365041621, 0, 0}, - {3456899824, 0, 0}, - {3505028338, 0, 0}, - {3510257966, 0, 0}, - {3554463148, 0, 0}, - {3606320646, 0, 0}, - {3692647551, 0, 0}, - {3861006967, 0, 0}, - {4126287524, 0, 0}, - {4140081844, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 14, 33}, - {0, 35, 25}, - {0, 27, 17}, - {0, 8, 20}, - {0, 3, 54}, - {0, 1, 19}, - {0, 10, 46}, - {0, 11, 9}, - {0, 39, 28}, - {0, 53, 49}, - {0, 12, 2}, - {0, 34, 4}, - {0, 47, 36}, - {0, 23, 45}, - {0, 5, 37}, - {0, 24, 38}, - {0, 43, 26}, - {0, 48, 51}, - {0, 44, 32}, - {0, 15, 16}, - {0, 57, 22}, - {0, 55, 50}, - {0, 29, 58}, - {0, 60, 59}, - {0, 41, 61}, - {0, 63, 62}, - {0, 65, 64}, - {0, 67, 66}, - {0, 69, 68}, - {0, 13, 70}, - {0, 71, 7}, - {0, 42, 31}, - {0, 73, 72}, - {0, 75, 74}, - {0, 21, 30}, - {0, 77, 76}, - {0, 79, 78}, - {0, 81, 80}, - {0, 82, 18}, - {0, 84, 83}, - {0, 86, 85}, - {0, 88, 87}, - {0, 90, 89}, - {0, 52, 91}, - {0, 6, 92}, - {0, 94, 93}, - {0, 96, 95}, - {0, 98, 97}, - {0, 99, 40}, - {0, 101, 100}, - {0, 103, 102}, - {0, 105, 104}, - {0, 107, 106}, - {0, 109, 108}, - {0, 56, 110}, - })); - - codecs.emplace(std::pair(SpvOpCompositeConstruct, 4), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(155, { - {0, 0, 0}, - {18776483, 0, 0}, - {37009196, 0, 0}, - {277023757, 0, 0}, - {296981500, 0, 0}, - {348988933, 0, 0}, - {451264926, 0, 0}, - {564884461, 0, 0}, - {804899022, 0, 0}, - {810488476, 0, 0}, - {870594305, 0, 0}, - {876864198, 0, 0}, - {900522183, 0, 0}, - {928261291, 0, 0}, - {959681532, 0, 0}, - {1164724902, 0, 0}, - {1323407757, 0, 0}, - {1332774287, 0, 0}, - {1404739463, 0, 0}, - {1447712361, 0, 0}, - {1450415100, 0, 0}, - {1513770932, 0, 0}, - {1620634991, 0, 0}, - {1692600167, 0, 0}, - {1860649552, 0, 0}, - {1932614728, 0, 0}, - {2087004702, 0, 0}, - {2148510256, 0, 0}, - {2220475432, 0, 0}, - {2388524817, 0, 0}, - {2460489993, 0, 0}, - {2676385521, 0, 0}, - {2748350697, 0, 0}, - {2855506940, 0, 0}, - {2860348412, 0, 0}, - {2916400082, 0, 0}, - {2988365258, 0, 0}, - {3061856840, 0, 0}, - {3063508455, 0, 0}, - {3065160070, 0, 0}, - {3066811685, 0, 0}, - {3068463300, 0, 0}, - {3070114915, 0, 0}, - {3071766530, 0, 0}, - {3073418145, 0, 0}, - {3075069760, 0, 0}, - {3076721375, 0, 0}, - {3078372990, 0, 0}, - {3080024605, 0, 0}, - {3081676220, 0, 0}, - {3083327835, 0, 0}, - {3084979450, 0, 0}, - {3086631065, 0, 0}, - {3088282680, 0, 0}, - {3114708520, 0, 0}, - {3116360135, 0, 0}, - {3118011750, 0, 0}, - {3119663365, 0, 0}, - {3121314980, 0, 0}, - {3124618210, 0, 0}, - {3126269825, 0, 0}, - {3127921440, 0, 0}, - {3129573055, 0, 0}, - {3131224670, 0, 0}, - {3132876285, 0, 0}, - {3134527900, 0, 0}, - {3136179515, 0, 0}, - {3204260786, 0, 0}, - {3264086791, 0, 0}, - {3276225962, 0, 0}, - {3444275347, 0, 0}, - {3516240523, 0, 0}, - {3588205699, 0, 0}, - {3732136051, 0, 0}, - {3804101227, 0, 0}, - {3874089391, 0, 0}, - {4044115788, 0, 0}, - {4116080964, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 45, 43}, - {0, 3, 46}, - {0, 71, 36}, - {0, 44, 34}, - {0, 76, 54}, - {0, 73, 55}, - {0, 57, 67}, - {0, 51, 56}, - {0, 31, 27}, - {0, 38, 37}, - {0, 40, 39}, - {0, 42, 41}, - {0, 49, 47}, - {0, 35, 50}, - {0, 21, 70}, - {0, 19, 5}, - {0, 8, 58}, - {0, 17, 11}, - {0, 24, 18}, - {0, 30, 29}, - {0, 52, 9}, - {0, 77, 22}, - {0, 62, 48}, - {0, 25, 53}, - {0, 20, 59}, - {0, 26, 60}, - {0, 72, 6}, - {0, 79, 69}, - {0, 80, 7}, - {0, 81, 2}, - {0, 12, 13}, - {0, 82, 68}, - {0, 65, 61}, - {0, 74, 63}, - {0, 23, 83}, - {0, 64, 10}, - {0, 84, 32}, - {0, 66, 28}, - {0, 15, 85}, - {0, 86, 16}, - {0, 88, 87}, - {0, 90, 89}, - {0, 92, 91}, - {0, 1, 93}, - {0, 95, 94}, - {0, 97, 96}, - {0, 99, 98}, - {0, 100, 75}, - {0, 102, 101}, - {0, 104, 103}, - {0, 106, 105}, - {0, 107, 14}, - {0, 109, 108}, - {0, 111, 110}, - {0, 113, 112}, - {0, 115, 114}, - {0, 117, 116}, - {0, 119, 118}, - {0, 121, 120}, - {0, 123, 122}, - {0, 125, 124}, - {0, 127, 126}, - {0, 129, 128}, - {0, 131, 130}, - {0, 133, 132}, - {0, 135, 134}, - {0, 137, 136}, - {0, 139, 138}, - {0, 141, 140}, - {0, 143, 142}, - {0, 145, 144}, - {0, 147, 146}, - {0, 33, 148}, - {0, 4, 149}, - {0, 78, 150}, - {0, 152, 151}, - {0, 154, 153}, - })); - - codecs.emplace(std::pair(SpvOpCompositeConstruct, 5), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(11, { - {0, 0, 0}, - {679771963, 0, 0}, - {789872778, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 6, 2}, - {0, 4, 7}, - {0, 1, 8}, - {0, 9, 5}, - {0, 3, 10}, - })); - - codecs.emplace(std::pair(SpvOpCompositeExtract, 0), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(49, { - {0, 0, 0}, - {126463145, 0, 0}, - {171307615, 0, 0}, - {342159236, 0, 0}, - {354479447, 0, 0}, - {593829839, 0, 0}, - {743407979, 0, 0}, - {898191441, 0, 0}, - {900522183, 0, 0}, - {1265796414, 0, 0}, - {1287304304, 0, 0}, - {1356063462, 0, 0}, - {1368383673, 0, 0}, - {1526654696, 0, 0}, - {1766994680, 0, 0}, - {1793544760, 0, 0}, - {1811839150, 0, 0}, - {2234361374, 0, 0}, - {2279700640, 0, 0}, - {2383939514, 0, 0}, - {2780898906, 0, 0}, - {2996594997, 0, 0}, - {3413713311, 0, 0}, - {3554463148, 0, 0}, - {3635542517, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 11, 15}, - {0, 20, 14}, - {0, 7, 18}, - {0, 6, 1}, - {0, 12, 10}, - {0, 23, 19}, - {0, 13, 5}, - {0, 24, 17}, - {0, 21, 3}, - {0, 22, 16}, - {0, 26, 2}, - {0, 27, 8}, - {0, 4, 28}, - {0, 29, 9}, - {0, 31, 30}, - {0, 33, 32}, - {0, 35, 34}, - {0, 37, 36}, - {0, 39, 38}, - {0, 41, 40}, - {0, 43, 42}, - {0, 45, 44}, - {0, 47, 46}, - {0, 25, 48}, - })); - - codecs.emplace(std::pair(SpvOpCompositeExtract, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(153, { - {0, 0, 0}, - {13107491, 0, 0}, - {257136089, 0, 0}, - {293528591, 0, 0}, - {321459212, 0, 0}, - {425022309, 0, 0}, - {490769168, 0, 0}, - {495107308, 0, 0}, - {517919178, 0, 0}, - {617312262, 0, 0}, - {708736129, 0, 0}, - {753756604, 0, 0}, - {765238787, 0, 0}, - {796985462, 0, 0}, - {819503463, 0, 0}, - {850497536, 0, 0}, - {948086521, 0, 0}, - {1004589179, 0, 0}, - {1120149824, 0, 0}, - {1165671422, 0, 0}, - {1203545131, 0, 0}, - {1297165140, 0, 0}, - {1335363438, 0, 0}, - {1351676723, 0, 0}, - {1391866096, 0, 0}, - {1584369690, 0, 0}, - {1631216488, 0, 0}, - {1691646294, 0, 0}, - {1779143013, 0, 0}, - {1858116930, 0, 0}, - {1890300748, 0, 0}, - {1915438939, 0, 0}, - {1918742169, 0, 0}, - {1922045399, 0, 0}, - {1961990747, 0, 0}, - {2037710159, 0, 0}, - {2037814253, 0, 0}, - {2043873558, 0, 0}, - {2096388952, 0, 0}, - {2169307971, 0, 0}, - {2257843797, 0, 0}, - {2262220987, 0, 0}, - {2338272340, 0, 0}, - {2405770322, 0, 0}, - {2498042266, 0, 0}, - {2563789125, 0, 0}, - {2588618056, 0, 0}, - {2645120714, 0, 0}, - {2864863800, 0, 0}, - {2909957084, 0, 0}, - {2975894973, 0, 0}, - {3041450802, 0, 0}, - {3151638847, 0, 0}, - {3187066832, 0, 0}, - {3244716568, 0, 0}, - {3271748023, 0, 0}, - {3304438238, 0, 0}, - {3312467582, 0, 0}, - {3325419312, 0, 0}, - {3370185097, 0, 0}, - {3419674548, 0, 0}, - {3435931956, 0, 0}, - {3504158761, 0, 0}, - {3602522282, 0, 0}, - {3653059026, 0, 0}, - {3716353056, 0, 0}, - {3782099915, 0, 0}, - {3838648480, 0, 0}, - {3847846774, 0, 0}, - {3913593633, 0, 0}, - {3989799199, 0, 0}, - {3997038726, 0, 0}, - {4046301857, 0, 0}, - {4092654294, 0, 0}, - {4176581069, 0, 0}, - {4242327928, 0, 0}, - {4285652249, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 74, 38}, - {0, 12, 56}, - {0, 28, 24}, - {0, 60, 43}, - {0, 65, 72}, - {0, 18, 2}, - {0, 52, 3}, - {0, 19, 10}, - {0, 49, 36}, - {0, 67, 66}, - {0, 41, 17}, - {0, 53, 11}, - {0, 29, 68}, - {0, 26, 55}, - {0, 70, 76}, - {0, 73, 47}, - {0, 51, 22}, - {0, 39, 21}, - {0, 5, 9}, - {0, 40, 48}, - {0, 59, 44}, - {0, 6, 69}, - {0, 32, 31}, - {0, 4, 33}, - {0, 13, 54}, - {0, 14, 50}, - {0, 35, 75}, - {0, 58, 23}, - {0, 16, 34}, - {0, 27, 63}, - {0, 45, 61}, - {0, 20, 46}, - {0, 71, 1}, - {0, 79, 78}, - {0, 81, 80}, - {0, 83, 82}, - {0, 84, 8}, - {0, 86, 85}, - {0, 88, 87}, - {0, 90, 89}, - {0, 92, 91}, - {0, 94, 93}, - {0, 96, 95}, - {0, 98, 97}, - {0, 64, 99}, - {0, 101, 100}, - {0, 103, 102}, - {0, 105, 104}, - {0, 106, 62}, - {0, 108, 107}, - {0, 110, 109}, - {0, 7, 111}, - {0, 113, 112}, - {0, 115, 114}, - {0, 117, 116}, - {0, 119, 118}, - {0, 121, 120}, - {0, 123, 122}, - {0, 30, 124}, - {0, 126, 125}, - {0, 128, 127}, - {0, 130, 129}, - {0, 132, 131}, - {0, 134, 133}, - {0, 135, 25}, - {0, 57, 136}, - {0, 138, 137}, - {0, 42, 139}, - {0, 37, 140}, - {0, 142, 141}, - {0, 143, 15}, - {0, 145, 144}, - {0, 147, 146}, - {0, 149, 148}, - {0, 151, 150}, - {0, 152, 77}, - })); - - codecs.emplace(std::pair(SpvOpCompositeExtract, 2), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(47, { - {0, 0, 0}, - {545678922, 0, 0}, - {630592085, 0, 0}, - {679771963, 0, 0}, - {899570100, 0, 0}, - {906176560, 0, 0}, - {929101967, 0, 0}, - {1100599986, 0, 0}, - {1103903216, 0, 0}, - {1107206446, 0, 0}, - {1369578001, 0, 0}, - {1372881231, 0, 0}, - {2320303498, 0, 0}, - {2926633629, 0, 0}, - {3249265647, 0, 0}, - {3334207724, 0, 0}, - {3486057732, 0, 0}, - {3674863070, 0, 0}, - {3705139860, 0, 0}, - {3800912395, 0, 0}, - {3802564010, 0, 0}, - {3822983876, 0, 0}, - {4141567741, 0, 0}, - {4292991777, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 9, 17}, - {0, 20, 11}, - {0, 25, 5}, - {0, 2, 14}, - {0, 23, 13}, - {0, 16, 26}, - {0, 27, 24}, - {0, 28, 8}, - {0, 29, 18}, - {0, 22, 30}, - {0, 6, 31}, - {0, 21, 32}, - {0, 3, 33}, - {0, 35, 34}, - {0, 1, 12}, - {0, 10, 36}, - {0, 37, 19}, - {0, 4, 15}, - {0, 39, 38}, - {0, 7, 40}, - {0, 42, 41}, - {0, 44, 43}, - {0, 46, 45}, - })); - - codecs.emplace(std::pair(SpvOpCompositeInsert, 0), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(103, { - {0, 0, 0}, - {125792961, 0, 0}, - {132755933, 0, 0}, - {156014509, 0, 0}, - {436066778, 0, 0}, - {463084678, 0, 0}, - {531559080, 0, 0}, - {565233904, 0, 0}, - {578132535, 0, 0}, - {600906020, 0, 0}, - {602222721, 0, 0}, - {694743357, 0, 0}, - {760554870, 0, 0}, - {996663016, 0, 0}, - {1022309772, 0, 0}, - {1351676723, 0, 0}, - {1496901698, 0, 0}, - {1502470404, 0, 0}, - {1522901980, 0, 0}, - {1548254487, 0, 0}, - {1637661947, 0, 0}, - {1788504755, 0, 0}, - {2092468906, 0, 0}, - {2094647776, 0, 0}, - {2127660080, 0, 0}, - {2213946343, 0, 0}, - {2225172640, 0, 0}, - {2259467579, 0, 0}, - {2263866576, 0, 0}, - {2600961503, 0, 0}, - {2727022058, 0, 0}, - {2752967311, 0, 0}, - {2864705739, 0, 0}, - {3021406120, 0, 0}, - {3044723416, 0, 0}, - {3052439312, 0, 0}, - {3136865519, 0, 0}, - {3297860332, 0, 0}, - {3352361837, 0, 0}, - {3670298840, 0, 0}, - {3712946115, 0, 0}, - {3732709413, 0, 0}, - {3764662384, 0, 0}, - {3788324110, 0, 0}, - {3928555688, 0, 0}, - {4083347580, 0, 0}, - {4098876453, 0, 0}, - {4147239510, 0, 0}, - {4199470013, 0, 0}, - {4211577142, 0, 0}, - {4218799564, 0, 0}, - {4290374884, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 4, 2}, - {0, 9, 8}, - {0, 17, 10}, - {0, 20, 18}, - {0, 22, 21}, - {0, 26, 23}, - {0, 31, 29}, - {0, 35, 34}, - {0, 45, 36}, - {0, 5, 3}, - {0, 12, 6}, - {0, 15, 14}, - {0, 25, 19}, - {0, 28, 27}, - {0, 38, 33}, - {0, 43, 39}, - {0, 47, 46}, - {0, 50, 49}, - {0, 7, 51}, - {0, 1, 48}, - {0, 37, 24}, - {0, 44, 42}, - {0, 13, 11}, - {0, 41, 40}, - {0, 54, 53}, - {0, 56, 55}, - {0, 58, 57}, - {0, 60, 59}, - {0, 62, 61}, - {0, 64, 63}, - {0, 66, 65}, - {0, 68, 67}, - {0, 70, 69}, - {0, 72, 71}, - {0, 30, 16}, - {0, 73, 32}, - {0, 75, 74}, - {0, 77, 76}, - {0, 79, 78}, - {0, 81, 80}, - {0, 83, 82}, - {0, 85, 84}, - {0, 87, 86}, - {0, 89, 88}, - {0, 91, 90}, - {0, 93, 92}, - {0, 95, 94}, - {0, 97, 96}, - {0, 99, 98}, - {0, 101, 100}, - {0, 52, 102}, - })); - - codecs.emplace(std::pair(SpvOpCompositeInsert, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(93, { - {0, 0, 0}, - {17185761, 0, 0}, - {117250846, 0, 0}, - {296981500, 0, 0}, - {330388453, 0, 0}, - {346929928, 0, 0}, - {533021259, 0, 0}, - {564302770, 0, 0}, - {680157484, 0, 0}, - {721450866, 0, 0}, - {798549062, 0, 0}, - {853200279, 0, 0}, - {864295921, 0, 0}, - {900522183, 0, 0}, - {973908139, 0, 0}, - {983243705, 0, 0}, - {1033363654, 0, 0}, - {1037370721, 0, 0}, - {1464587427, 0, 0}, - {1670691893, 0, 0}, - {1686512349, 0, 0}, - {1849065716, 0, 0}, - {1917602962, 0, 0}, - {1965902997, 0, 0}, - {2121980967, 0, 0}, - {2311072371, 0, 0}, - {2339901602, 0, 0}, - {2517964682, 0, 0}, - {2542834724, 0, 0}, - {2558655180, 0, 0}, - {2736881867, 0, 0}, - {2855506940, 0, 0}, - {2888753905, 0, 0}, - {2950446516, 0, 0}, - {3044188332, 0, 0}, - {3079287749, 0, 0}, - {3153451899, 0, 0}, - {3214537066, 0, 0}, - {3234673086, 0, 0}, - {3349230696, 0, 0}, - {3504158761, 0, 0}, - {3570411982, 0, 0}, - {3652695478, 0, 0}, - {3764205609, 0, 0}, - {3940720663, 0, 0}, - {4180570743, 0, 0}, - {4221373527, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 24, 18}, - {0, 4, 2}, - {0, 15, 14}, - {0, 21, 20}, - {0, 29, 26}, - {0, 42, 36}, - {0, 7, 45}, - {0, 37, 9}, - {0, 8, 5}, - {0, 32, 11}, - {0, 39, 38}, - {0, 12, 10}, - {0, 28, 19}, - {0, 1, 46}, - {0, 17, 6}, - {0, 30, 23}, - {0, 44, 33}, - {0, 35, 13}, - {0, 16, 48}, - {0, 50, 49}, - {0, 52, 51}, - {0, 54, 53}, - {0, 55, 40}, - {0, 57, 56}, - {0, 59, 58}, - {0, 61, 60}, - {0, 25, 22}, - {0, 63, 62}, - {0, 3, 64}, - {0, 66, 65}, - {0, 68, 67}, - {0, 70, 69}, - {0, 34, 71}, - {0, 73, 72}, - {0, 75, 74}, - {0, 77, 76}, - {0, 27, 43}, - {0, 79, 78}, - {0, 81, 80}, - {0, 83, 82}, - {0, 84, 31}, - {0, 86, 85}, - {0, 41, 87}, - {0, 89, 88}, - {0, 91, 90}, - {0, 47, 92}, - })); - - codecs.emplace(std::pair(SpvOpCompositeInsert, 2), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(115, { - {0, 0, 0}, - {132755933, 0, 0}, - {156014509, 0, 0}, - {255227811, 0, 0}, - {371186900, 0, 0}, - {371428004, 0, 0}, - {374731234, 0, 0}, - {531559080, 0, 0}, - {565233904, 0, 0}, - {578132535, 0, 0}, - {591140762, 0, 0}, - {600906020, 0, 0}, - {602222721, 0, 0}, - {656610661, 0, 0}, - {760554870, 0, 0}, - {996663016, 0, 0}, - {1022309772, 0, 0}, - {1496901698, 0, 0}, - {1502470404, 0, 0}, - {1522901980, 0, 0}, - {1536350567, 0, 0}, - {1543280290, 0, 0}, - {1548254487, 0, 0}, - {1788504755, 0, 0}, - {2064733527, 0, 0}, - {2092468906, 0, 0}, - {2094647776, 0, 0}, - {2162986400, 0, 0}, - {2225172640, 0, 0}, - {2259467579, 0, 0}, - {2263866576, 0, 0}, - {2360004627, 0, 0}, - {2507709226, 0, 0}, - {2600961503, 0, 0}, - {2727022058, 0, 0}, - {2752967311, 0, 0}, - {2864705739, 0, 0}, - {3021406120, 0, 0}, - {3052439312, 0, 0}, - {3136865519, 0, 0}, - {3297860332, 0, 0}, - {3352361837, 0, 0}, - {3598957382, 0, 0}, - {3619787319, 0, 0}, - {3655201337, 0, 0}, - {3670298840, 0, 0}, - {3774892253, 0, 0}, - {3788324110, 0, 0}, - {3808408202, 0, 0}, - {3951925872, 0, 0}, - {3952316364, 0, 0}, - {4098876453, 0, 0}, - {4147239510, 0, 0}, - {4199470013, 0, 0}, - {4211577142, 0, 0}, - {4217306348, 0, 0}, - {4218799564, 0, 0}, - {4290374884, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 6, 43}, - {0, 4, 1}, - {0, 11, 9}, - {0, 13, 12}, - {0, 19, 18}, - {0, 25, 23}, - {0, 28, 26}, - {0, 35, 33}, - {0, 39, 38}, - {0, 2, 49}, - {0, 7, 3}, - {0, 16, 14}, - {0, 29, 22}, - {0, 37, 30}, - {0, 45, 41}, - {0, 51, 47}, - {0, 54, 52}, - {0, 57, 56}, - {0, 53, 8}, - {0, 32, 10}, - {0, 42, 40}, - {0, 24, 46}, - {0, 15, 50}, - {0, 55, 20}, - {0, 59, 44}, - {0, 61, 60}, - {0, 63, 62}, - {0, 65, 64}, - {0, 67, 66}, - {0, 69, 68}, - {0, 71, 70}, - {0, 73, 72}, - {0, 75, 74}, - {0, 77, 76}, - {0, 31, 17}, - {0, 36, 34}, - {0, 79, 78}, - {0, 81, 80}, - {0, 27, 82}, - {0, 5, 21}, - {0, 48, 83}, - {0, 85, 84}, - {0, 87, 86}, - {0, 89, 88}, - {0, 91, 90}, - {0, 93, 92}, - {0, 95, 94}, - {0, 97, 96}, - {0, 99, 98}, - {0, 101, 100}, - {0, 103, 102}, - {0, 105, 104}, - {0, 107, 106}, - {0, 109, 108}, - {0, 111, 110}, - {0, 113, 112}, - {0, 58, 114}, - })); - - codecs.emplace(std::pair(SpvOpCompositeInsert, 3), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(7, { - {0, 0, 0}, - {3866587616, 0, 0}, - {3868239231, 0, 0}, - {3869890846, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 4}, - {0, 2, 5}, - {0, 3, 6}, - })); - - codecs.emplace(std::pair(SpvOpSampledImage, 0), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(9, { - {0, 0, 0}, - {1164218401, 0, 0}, - {2036361232, 0, 0}, - {2637132451, 0, 0}, - {3237903670, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 4, 5}, - {0, 3, 6}, - {0, 1, 7}, - {0, 2, 8}, - })); - - codecs.emplace(std::pair(SpvOpSampledImage, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(7, { - {0, 0, 0}, - {543558236, 0, 0}, - {1069781886, 0, 0}, - {1596005536, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 3, 4}, - {0, 2, 5}, - {0, 1, 6}, - })); - - codecs.emplace(std::pair(SpvOpSampledImage, 2), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {1949759310, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpSampledImage, 3), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpImageSampleImplicitLod, 0), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(87, { - {0, 0, 0}, - {236660303, 0, 0}, - {347505241, 0, 0}, - {426360862, 0, 0}, - {439998433, 0, 0}, - {488500848, 0, 0}, - {495107308, 0, 0}, - {868652905, 0, 0}, - {1191735827, 0, 0}, - {1265998516, 0, 0}, - {1309728002, 0, 0}, - {1365842164, 0, 0}, - {1396344138, 0, 0}, - {1508074873, 0, 0}, - {1553476262, 0, 0}, - {1642818143, 0, 0}, - {1851510470, 0, 0}, - {1858116930, 0, 0}, - {1863199739, 0, 0}, - {1979978194, 0, 0}, - {1986584654, 0, 0}, - {2092100514, 0, 0}, - {2098706974, 0, 0}, - {2231688008, 0, 0}, - {2232491275, 0, 0}, - {2329992200, 0, 0}, - {2637935122, 0, 0}, - {2693892518, 0, 0}, - {2759250216, 0, 0}, - {2839765116, 0, 0}, - {2855895374, 0, 0}, - {2913136690, 0, 0}, - {3012980338, 0, 0}, - {3327770644, 0, 0}, - {3362344229, 0, 0}, - {3398925952, 0, 0}, - {3448018532, 0, 0}, - {3457985288, 0, 0}, - {3566035349, 0, 0}, - {3657635382, 0, 0}, - {3702405475, 0, 0}, - {3757479030, 0, 0}, - {3797204453, 0, 0}, - {4291477370, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 32, 28}, - {0, 9, 35}, - {0, 31, 11}, - {0, 10, 30}, - {0, 25, 21}, - {0, 40, 2}, - {0, 15, 19}, - {0, 24, 36}, - {0, 42, 4}, - {0, 18, 16}, - {0, 29, 26}, - {0, 43, 7}, - {0, 45, 8}, - {0, 37, 13}, - {0, 47, 46}, - {0, 48, 33}, - {0, 49, 14}, - {0, 3, 22}, - {0, 50, 12}, - {0, 41, 39}, - {0, 51, 34}, - {0, 52, 20}, - {0, 54, 53}, - {0, 56, 55}, - {0, 58, 57}, - {0, 60, 59}, - {0, 61, 23}, - {0, 63, 62}, - {0, 65, 64}, - {0, 27, 66}, - {0, 67, 38}, - {0, 68, 17}, - {0, 70, 69}, - {0, 72, 71}, - {0, 74, 73}, - {0, 76, 75}, - {0, 5, 77}, - {0, 78, 1}, - {0, 80, 79}, - {0, 82, 81}, - {0, 83, 6}, - {0, 85, 84}, - {0, 44, 86}, - })); - - codecs.emplace(std::pair(SpvOpImageSampleImplicitLod, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(15, { - {0, 0, 0}, - {883854656, 0, 0}, - {1962971231, 0, 0}, - {2036361232, 0, 0}, - {2356768706, 0, 0}, - {2637132451, 0, 0}, - {3237903670, 0, 0}, - {3829682756, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 8, 2}, - {0, 6, 9}, - {0, 10, 7}, - {0, 4, 5}, - {0, 12, 11}, - {0, 3, 13}, - {0, 14, 1}, - })); - - codecs.emplace(std::pair(SpvOpImageSampleImplicitLod, 2), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(87, { - {0, 0, 0}, - {150685616, 0, 0}, - {255302575, 0, 0}, - {414620710, 0, 0}, - {557400685, 0, 0}, - {575205902, 0, 0}, - {618761615, 0, 0}, - {646282397, 0, 0}, - {686024761, 0, 0}, - {740921498, 0, 0}, - {921246433, 0, 0}, - {1057578789, 0, 0}, - {1162127370, 0, 0}, - {1329499601, 0, 0}, - {1352628475, 0, 0}, - {1502028603, 0, 0}, - {1519723107, 0, 0}, - {1543798545, 0, 0}, - {1545450160, 0, 0}, - {1570165302, 0, 0}, - {1600392975, 0, 0}, - {1641415225, 0, 0}, - {2204920111, 0, 0}, - {2257971049, 0, 0}, - {2276405827, 0, 0}, - {2339018837, 0, 0}, - {2340670452, 0, 0}, - {2517964682, 0, 0}, - {2532518896, 0, 0}, - {2674090849, 0, 0}, - {2754074729, 0, 0}, - {2804281092, 0, 0}, - {2816338013, 0, 0}, - {2841008029, 0, 0}, - {3234673086, 0, 0}, - {3249261197, 0, 0}, - {3619787319, 0, 0}, - {3627739127, 0, 0}, - {3669223677, 0, 0}, - {3787567939, 0, 0}, - {3898287302, 0, 0}, - {4142016703, 0, 0}, - {4237092412, 0, 0}, - {4285779501, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 16, 15}, - {0, 2, 33}, - {0, 41, 35}, - {0, 32, 30}, - {0, 39, 38}, - {0, 5, 1}, - {0, 9, 43}, - {0, 40, 22}, - {0, 29, 12}, - {0, 4, 3}, - {0, 25, 37}, - {0, 34, 26}, - {0, 45, 19}, - {0, 31, 24}, - {0, 47, 46}, - {0, 48, 20}, - {0, 49, 6}, - {0, 8, 21}, - {0, 50, 11}, - {0, 13, 10}, - {0, 51, 42}, - {0, 52, 23}, - {0, 54, 53}, - {0, 56, 55}, - {0, 58, 57}, - {0, 60, 59}, - {0, 61, 28}, - {0, 63, 62}, - {0, 65, 64}, - {0, 17, 66}, - {0, 67, 18}, - {0, 68, 7}, - {0, 70, 69}, - {0, 72, 71}, - {0, 74, 73}, - {0, 76, 75}, - {0, 14, 77}, - {0, 78, 27}, - {0, 80, 79}, - {0, 82, 81}, - {0, 83, 36}, - {0, 85, 84}, - {0, 44, 86}, - })); - - codecs.emplace(std::pair(SpvOpImageSampleImplicitLod, 3), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(7, { - {0, 0, 0}, - {2855506940, 0, 0}, - {3266548732, 0, 0}, - {3732640764, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 2, 1}, - {0, 5, 4}, - {0, 3, 6}, - })); - - codecs.emplace(std::pair(SpvOpImageSampleImplicitLod, 5), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpImageSampleExplicitLod, 0), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(139, { - {0, 0, 0}, - {27177503, 0, 0}, - {30663912, 0, 0}, - {151672195, 0, 0}, - {162608772, 0, 0}, - {180913835, 0, 0}, - {371621315, 0, 0}, - {414444763, 0, 0}, - {421602934, 0, 0}, - {443347828, 0, 0}, - {458937500, 0, 0}, - {587888644, 0, 0}, - {601656217, 0, 0}, - {665789406, 0, 0}, - {712168842, 0, 0}, - {730943059, 0, 0}, - {750870327, 0, 0}, - {875212982, 0, 0}, - {899320334, 0, 0}, - {973908139, 0, 0}, - {989813600, 0, 0}, - {1057606514, 0, 0}, - {1171541710, 0, 0}, - {1243764146, 0, 0}, - {1310404265, 0, 0}, - {1366337101, 0, 0}, - {1443547269, 0, 0}, - {1472185378, 0, 0}, - {1473799048, 0, 0}, - {1543935193, 0, 0}, - {1572834111, 0, 0}, - {1623013158, 0, 0}, - {1686512349, 0, 0}, - {1705716306, 0, 0}, - {1747355813, 0, 0}, - {1755165354, 0, 0}, - {1781864804, 0, 0}, - {1916983087, 0, 0}, - {1941403425, 0, 0}, - {2023008475, 0, 0}, - {2043684541, 0, 0}, - {2274226560, 0, 0}, - {2285438321, 0, 0}, - {2315690100, 0, 0}, - {2344328209, 0, 0}, - {2414725163, 0, 0}, - {2493146691, 0, 0}, - {2495155989, 0, 0}, - {2558655180, 0, 0}, - {2577859137, 0, 0}, - {2857814560, 0, 0}, - {2895151306, 0, 0}, - {2986830770, 0, 0}, - {3006548167, 0, 0}, - {3127329373, 0, 0}, - {3157581152, 0, 0}, - {3216471040, 0, 0}, - {3296722158, 0, 0}, - {3367298820, 0, 0}, - {3376009661, 0, 0}, - {3450001968, 0, 0}, - {3526837441, 0, 0}, - {3609540589, 0, 0}, - {3743398113, 0, 0}, - {3858973601, 0, 0}, - {3953984401, 0, 0}, - {3999472204, 0, 0}, - {4088613871, 0, 0}, - {4184019303, 0, 0}, - {4258229445, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 31, 16}, - {0, 58, 47}, - {0, 21, 61}, - {0, 6, 14}, - {0, 65, 23}, - {0, 35, 5}, - {0, 2, 7}, - {0, 10, 25}, - {0, 40, 22}, - {0, 9, 50}, - {0, 20, 11}, - {0, 38, 36}, - {0, 13, 12}, - {0, 67, 28}, - {0, 71, 68}, - {0, 73, 72}, - {0, 3, 29}, - {0, 27, 8}, - {0, 44, 37}, - {0, 74, 63}, - {0, 76, 75}, - {0, 18, 1}, - {0, 78, 77}, - {0, 80, 79}, - {0, 82, 81}, - {0, 26, 15}, - {0, 83, 43}, - {0, 85, 84}, - {0, 19, 86}, - {0, 48, 32}, - {0, 33, 46}, - {0, 87, 49}, - {0, 89, 88}, - {0, 91, 90}, - {0, 41, 30}, - {0, 52, 42}, - {0, 64, 55}, - {0, 92, 53}, - {0, 94, 93}, - {0, 51, 39}, - {0, 45, 95}, - {0, 66, 54}, - {0, 97, 96}, - {0, 57, 98}, - {0, 99, 69}, - {0, 101, 100}, - {0, 56, 102}, - {0, 4, 59}, - {0, 34, 17}, - {0, 103, 24}, - {0, 105, 104}, - {0, 107, 106}, - {0, 109, 108}, - {0, 60, 110}, - {0, 111, 62}, - {0, 113, 112}, - {0, 115, 114}, - {0, 117, 116}, - {0, 119, 118}, - {0, 121, 120}, - {0, 123, 122}, - {0, 125, 124}, - {0, 127, 126}, - {0, 129, 128}, - {0, 70, 130}, - {0, 132, 131}, - {0, 134, 133}, - {0, 136, 135}, - {0, 138, 137}, - })); - - codecs.emplace(std::pair(SpvOpImageSampleExplicitLod, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(11, { - {0, 0, 0}, - {883854656, 0, 0}, - {1962971231, 0, 0}, - {2036361232, 0, 0}, - {2366506734, 0, 0}, - {3829682756, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 4, 2}, - {0, 6, 7}, - {0, 8, 5}, - {0, 3, 9}, - {0, 1, 10}, - })); - - codecs.emplace(std::pair(SpvOpImageSampleExplicitLod, 2), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(73, { - {0, 0, 0}, - {178571546, 0, 0}, - {223310468, 0, 0}, - {388034151, 0, 0}, - {449954059, 0, 0}, - {694743357, 0, 0}, - {797415788, 0, 0}, - {835638766, 0, 0}, - {1002144380, 0, 0}, - {1221183390, 0, 0}, - {1570165302, 0, 0}, - {1663234329, 0, 0}, - {1750829822, 0, 0}, - {1894133125, 0, 0}, - {1967643923, 0, 0}, - {1980341560, 0, 0}, - {2278706468, 0, 0}, - {2326990117, 0, 0}, - {2464905186, 0, 0}, - {2511346984, 0, 0}, - {2517964682, 0, 0}, - {2616085763, 0, 0}, - {2710583246, 0, 0}, - {2745872368, 0, 0}, - {2924263085, 0, 0}, - {3027500544, 0, 0}, - {3044723416, 0, 0}, - {3202324433, 0, 0}, - {3289213933, 0, 0}, - {3323682385, 0, 0}, - {3366848728, 0, 0}, - {3417583519, 0, 0}, - {3732916270, 0, 0}, - {3787909072, 0, 0}, - {3877813395, 0, 0}, - {4028028350, 0, 0}, - {4178218543, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 36, 31}, - {0, 15, 3}, - {0, 17, 1}, - {0, 24, 12}, - {0, 35, 34}, - {0, 28, 27}, - {0, 21, 38}, - {0, 6, 13}, - {0, 14, 7}, - {0, 39, 25}, - {0, 40, 30}, - {0, 42, 41}, - {0, 32, 43}, - {0, 23, 9}, - {0, 11, 44}, - {0, 45, 22}, - {0, 47, 46}, - {0, 2, 16}, - {0, 49, 48}, - {0, 4, 50}, - {0, 51, 18}, - {0, 53, 52}, - {0, 33, 54}, - {0, 26, 55}, - {0, 57, 56}, - {0, 5, 58}, - {0, 59, 8}, - {0, 19, 60}, - {0, 10, 61}, - {0, 29, 62}, - {0, 37, 63}, - {0, 65, 64}, - {0, 67, 66}, - {0, 20, 68}, - {0, 70, 69}, - {0, 72, 71}, - })); - - codecs.emplace(std::pair(SpvOpImageSampleExplicitLod, 3), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {2855506940, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpImageSampleExplicitLod, 5), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(13, { - {0, 0, 0}, - {3533637837, 0, 0}, - {3535289452, 0, 0}, - {3536941067, 0, 0}, - {3538592682, 0, 0}, - {3540244297, 0, 0}, - {3541895912, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 7}, - {0, 2, 8}, - {0, 9, 3}, - {0, 4, 10}, - {0, 5, 11}, - {0, 12, 6}, - })); - - codecs.emplace(std::pair(SpvOpImageSampleExplicitLod, 6), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(9, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 4, 5}, - {0, 2, 6}, - {0, 1, 3}, - {0, 8, 7}, - })); - - codecs.emplace(std::pair(SpvOpFAdd, 0), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(45, { - {0, 0, 0}, - {328661377, 0, 0}, - {464259778, 0, 0}, - {920941800, 0, 0}, - {969500141, 0, 0}, - {1449907751, 0, 0}, - {1451831482, 0, 0}, - {1543798545, 0, 0}, - {1545450160, 0, 0}, - {1626224034, 0, 0}, - {1669930486, 0, 0}, - {1770165905, 0, 0}, - {2278571792, 0, 0}, - {2432827426, 0, 0}, - {2656211099, 0, 0}, - {2736844435, 0, 0}, - {2870852215, 0, 0}, - {2919626325, 0, 0}, - {2923708820, 0, 0}, - {3325419312, 0, 0}, - {3678875745, 0, 0}, - {4182141402, 0, 0}, - {4241374559, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 2, 6}, - {0, 9, 13}, - {0, 5, 15}, - {0, 4, 11}, - {0, 20, 22}, - {0, 10, 1}, - {0, 18, 14}, - {0, 16, 3}, - {0, 12, 21}, - {0, 8, 7}, - {0, 24, 17}, - {0, 19, 25}, - {0, 27, 26}, - {0, 29, 28}, - {0, 31, 30}, - {0, 33, 32}, - {0, 35, 34}, - {0, 37, 36}, - {0, 39, 38}, - {0, 41, 40}, - {0, 43, 42}, - {0, 23, 44}, - })); - - codecs.emplace(std::pair(SpvOpFAdd, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(89, { - {0, 0, 0}, - {135920445, 0, 0}, - {176166202, 0, 0}, - {294390719, 0, 0}, - {296981500, 0, 0}, - {743407979, 0, 0}, - {810488476, 0, 0}, - {837715723, 0, 0}, - {885020215, 0, 0}, - {922996215, 0, 0}, - {959681532, 0, 0}, - {963902061, 0, 0}, - {1136775085, 0, 0}, - {1189681639, 0, 0}, - {1203545131, 0, 0}, - {1297294717, 0, 0}, - {1317058015, 0, 0}, - {1352397672, 0, 0}, - {1367301635, 0, 0}, - {1412908157, 0, 0}, - {1570165302, 0, 0}, - {1763758554, 0, 0}, - {1791427568, 0, 0}, - {1992893964, 0, 0}, - {2013867381, 0, 0}, - {2096388952, 0, 0}, - {2219733501, 0, 0}, - {2383939514, 0, 0}, - {2517964682, 0, 0}, - {2555315060, 0, 0}, - {2572638469, 0, 0}, - {2762094724, 0, 0}, - {2770161927, 0, 0}, - {2855506940, 0, 0}, - {3044188332, 0, 0}, - {3187066832, 0, 0}, - {3319278167, 0, 0}, - {3653838348, 0, 0}, - {3675926744, 0, 0}, - {3701632935, 0, 0}, - {3712946115, 0, 0}, - {3732709413, 0, 0}, - {3743748793, 0, 0}, - {3783543823, 0, 0}, - {3930727258, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 15, 12}, - {0, 38, 16}, - {0, 41, 40}, - {0, 1, 33}, - {0, 21, 34}, - {0, 9, 2}, - {0, 24, 7}, - {0, 39, 44}, - {0, 29, 22}, - {0, 17, 19}, - {0, 36, 32}, - {0, 26, 18}, - {0, 30, 3}, - {0, 11, 8}, - {0, 42, 35}, - {0, 46, 31}, - {0, 27, 5}, - {0, 48, 47}, - {0, 28, 49}, - {0, 51, 50}, - {0, 52, 23}, - {0, 54, 53}, - {0, 13, 14}, - {0, 6, 55}, - {0, 57, 56}, - {0, 59, 58}, - {0, 60, 43}, - {0, 62, 61}, - {0, 37, 63}, - {0, 65, 64}, - {0, 67, 66}, - {0, 69, 68}, - {0, 70, 4}, - {0, 10, 71}, - {0, 72, 20}, - {0, 74, 73}, - {0, 76, 75}, - {0, 78, 77}, - {0, 80, 79}, - {0, 81, 25}, - {0, 83, 82}, - {0, 85, 84}, - {0, 87, 86}, - {0, 45, 88}, - })); - - codecs.emplace(std::pair(SpvOpFAdd, 2), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(103, { - {0, 0, 0}, - {126463145, 0, 0}, - {220008971, 0, 0}, - {246375791, 0, 0}, - {503145996, 0, 0}, - {628331516, 0, 0}, - {643418617, 0, 0}, - {743407979, 0, 0}, - {837715723, 0, 0}, - {858902117, 0, 0}, - {870594305, 0, 0}, - {939671928, 0, 0}, - {959681532, 0, 0}, - {1051471757, 0, 0}, - {1092948665, 0, 0}, - {1097775533, 0, 0}, - {1136775085, 0, 0}, - {1140367371, 0, 0}, - {1332643570, 0, 0}, - {1367301635, 0, 0}, - {1558001705, 0, 0}, - {1684282922, 0, 0}, - {2096388952, 0, 0}, - {2183547611, 0, 0}, - {2219733501, 0, 0}, - {2358141757, 0, 0}, - {2359973133, 0, 0}, - {2383939514, 0, 0}, - {2444465148, 0, 0}, - {2517964682, 0, 0}, - {2567901801, 0, 0}, - {2598189097, 0, 0}, - {2655147757, 0, 0}, - {2683080096, 0, 0}, - {2705434194, 0, 0}, - {2738307068, 0, 0}, - {2780898906, 0, 0}, - {3030911670, 0, 0}, - {3032677281, 0, 0}, - {3063300848, 0, 0}, - {3277199633, 0, 0}, - {3289969989, 0, 0}, - {3401762422, 0, 0}, - {3436143898, 0, 0}, - {3560552546, 0, 0}, - {3656163446, 0, 0}, - {3675926744, 0, 0}, - {3701632935, 0, 0}, - {3743748793, 0, 0}, - {3752211294, 0, 0}, - {3794803132, 0, 0}, - {4241374559, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 21}, - {0, 17, 11}, - {0, 36, 35}, - {0, 46, 45}, - {0, 50, 49}, - {0, 9, 3}, - {0, 20, 47}, - {0, 37, 31}, - {0, 2, 34}, - {0, 40, 13}, - {0, 51, 32}, - {0, 41, 10}, - {0, 38, 19}, - {0, 18, 44}, - {0, 43, 16}, - {0, 48, 24}, - {0, 26, 5}, - {0, 53, 8}, - {0, 15, 7}, - {0, 25, 23}, - {0, 54, 27}, - {0, 56, 55}, - {0, 58, 57}, - {0, 60, 59}, - {0, 39, 42}, - {0, 62, 61}, - {0, 30, 63}, - {0, 4, 64}, - {0, 65, 28}, - {0, 66, 22}, - {0, 68, 67}, - {0, 69, 14}, - {0, 70, 33}, - {0, 71, 6}, - {0, 73, 72}, - {0, 75, 74}, - {0, 29, 76}, - {0, 78, 77}, - {0, 80, 79}, - {0, 82, 81}, - {0, 84, 83}, - {0, 86, 85}, - {0, 88, 87}, - {0, 90, 89}, - {0, 91, 12}, - {0, 93, 92}, - {0, 95, 94}, - {0, 97, 96}, - {0, 99, 98}, - {0, 101, 100}, - {0, 52, 102}, - })); - - codecs.emplace(std::pair(SpvOpFAdd, 3), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(9, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 3, 5}, - {0, 4, 6}, - {0, 1, 7}, - {0, 2, 8}, - })); - - codecs.emplace(std::pair(SpvOpFSub, 0), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(159, { - {0, 0, 0}, - {50385656, 0, 0}, - {117250846, 0, 0}, - {171494987, 0, 0}, - {195244192, 0, 0}, - {210754155, 0, 0}, - {265392489, 0, 0}, - {333855951, 0, 0}, - {416853049, 0, 0}, - {529068443, 0, 0}, - {533021259, 0, 0}, - {615982737, 0, 0}, - {660038281, 0, 0}, - {663341511, 0, 0}, - {669812542, 0, 0}, - {716890919, 0, 0}, - {1081536219, 0, 0}, - {1119744229, 0, 0}, - {1123617794, 0, 0}, - {1139547465, 0, 0}, - {1162789888, 0, 0}, - {1178317551, 0, 0}, - {1190147516, 0, 0}, - {1193734351, 0, 0}, - {1215030156, 0, 0}, - {1220749418, 0, 0}, - {1318479490, 0, 0}, - {1461398554, 0, 0}, - {1486207619, 0, 0}, - {1551372768, 0, 0}, - {1763758554, 0, 0}, - {1797960910, 0, 0}, - {1850331254, 0, 0}, - {1894417995, 0, 0}, - {1964254745, 0, 0}, - {1965902997, 0, 0}, - {1989327599, 0, 0}, - {2095027856, 0, 0}, - {2123683379, 0, 0}, - {2124837447, 0, 0}, - {2137526937, 0, 0}, - {2269114589, 0, 0}, - {2269130237, 0, 0}, - {2330636993, 0, 0}, - {2481746922, 0, 0}, - {2503770904, 0, 0}, - {2589449658, 0, 0}, - {2603020391, 0, 0}, - {2604576561, 0, 0}, - {2795773560, 0, 0}, - {2835131395, 0, 0}, - {2852854788, 0, 0}, - {2890638791, 0, 0}, - {2895413148, 0, 0}, - {2950446516, 0, 0}, - {2963744582, 0, 0}, - {3079287749, 0, 0}, - {3088785099, 0, 0}, - {3280064277, 0, 0}, - {3335250889, 0, 0}, - {3510242586, 0, 0}, - {3517169445, 0, 0}, - {3518703473, 0, 0}, - {3536471583, 0, 0}, - {3579593979, 0, 0}, - {3591222197, 0, 0}, - {3673811979, 0, 0}, - {3727034815, 0, 0}, - {3730093054, 0, 0}, - {3898287302, 0, 0}, - {3944781937, 0, 0}, - {3950980241, 0, 0}, - {4033586023, 0, 0}, - {4041974454, 0, 0}, - {4052965752, 0, 0}, - {4083161638, 0, 0}, - {4167600590, 0, 0}, - {4185661467, 0, 0}, - {4237092412, 0, 0}, - {4244540017, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 44, 18}, - {0, 69, 57}, - {0, 24, 16}, - {0, 79, 5}, - {0, 59, 4}, - {0, 76, 40}, - {0, 53, 45}, - {0, 14, 2}, - {0, 62, 61}, - {0, 33, 75}, - {0, 38, 37}, - {0, 42, 58}, - {0, 66, 47}, - {0, 63, 67}, - {0, 1, 7}, - {0, 10, 3}, - {0, 13, 12}, - {0, 23, 22}, - {0, 32, 28}, - {0, 36, 35}, - {0, 72, 49}, - {0, 74, 73}, - {0, 77, 55}, - {0, 27, 41}, - {0, 31, 15}, - {0, 6, 54}, - {0, 78, 17}, - {0, 81, 56}, - {0, 83, 82}, - {0, 85, 84}, - {0, 48, 30}, - {0, 71, 60}, - {0, 65, 51}, - {0, 87, 86}, - {0, 50, 34}, - {0, 89, 88}, - {0, 90, 9}, - {0, 25, 8}, - {0, 92, 91}, - {0, 93, 26}, - {0, 95, 94}, - {0, 52, 39}, - {0, 29, 20}, - {0, 97, 96}, - {0, 99, 98}, - {0, 101, 100}, - {0, 64, 102}, - {0, 104, 103}, - {0, 106, 105}, - {0, 21, 107}, - {0, 108, 68}, - {0, 109, 46}, - {0, 110, 11}, - {0, 112, 111}, - {0, 114, 113}, - {0, 116, 115}, - {0, 117, 70}, - {0, 43, 118}, - {0, 120, 119}, - {0, 122, 121}, - {0, 124, 123}, - {0, 126, 125}, - {0, 128, 127}, - {0, 129, 19}, - {0, 131, 130}, - {0, 133, 132}, - {0, 135, 134}, - {0, 137, 136}, - {0, 139, 138}, - {0, 141, 140}, - {0, 143, 142}, - {0, 145, 144}, - {0, 147, 146}, - {0, 149, 148}, - {0, 151, 150}, - {0, 153, 152}, - {0, 155, 154}, - {0, 157, 156}, - {0, 158, 80}, - })); - - codecs.emplace(std::pair(SpvOpFSub, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(103, { - {0, 0, 0}, - {50998433, 0, 0}, - {171494987, 0, 0}, - {249378857, 0, 0}, - {296981500, 0, 0}, - {508007510, 0, 0}, - {610429940, 0, 0}, - {660038281, 0, 0}, - {663341511, 0, 0}, - {836581417, 0, 0}, - {1027242654, 0, 0}, - {1167160774, 0, 0}, - {1191015885, 0, 0}, - {1200870684, 0, 0}, - {1203545131, 0, 0}, - {1265796414, 0, 0}, - {1319785741, 0, 0}, - {1669959736, 0, 0}, - {1684282922, 0, 0}, - {1752686878, 0, 0}, - {1850331254, 0, 0}, - {1901166356, 0, 0}, - {1906988301, 0, 0}, - {2055836767, 0, 0}, - {2095027856, 0, 0}, - {2096388952, 0, 0}, - {2144962711, 0, 0}, - {2217833278, 0, 0}, - {2500819054, 0, 0}, - {2525173102, 0, 0}, - {2575525651, 0, 0}, - {2660843182, 0, 0}, - {2855506940, 0, 0}, - {2918750759, 0, 0}, - {2919787747, 0, 0}, - {3091876332, 0, 0}, - {3187066832, 0, 0}, - {3244209297, 0, 0}, - {3423702268, 0, 0}, - {3508792859, 0, 0}, - {3548535223, 0, 0}, - {3619787319, 0, 0}, - {3653838348, 0, 0}, - {3692647551, 0, 0}, - {3713290482, 0, 0}, - {3753486980, 0, 0}, - {3783756895, 0, 0}, - {3797961332, 0, 0}, - {3836822275, 0, 0}, - {4043078107, 0, 0}, - {4052965752, 0, 0}, - {4091394002, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 31, 49}, - {0, 24, 19}, - {0, 46, 45}, - {0, 6, 48}, - {0, 12, 33}, - {0, 17, 21}, - {0, 43, 11}, - {0, 7, 2}, - {0, 9, 8}, - {0, 28, 13}, - {0, 44, 38}, - {0, 30, 50}, - {0, 26, 22}, - {0, 29, 51}, - {0, 34, 37}, - {0, 53, 40}, - {0, 23, 54}, - {0, 55, 25}, - {0, 27, 18}, - {0, 1, 10}, - {0, 57, 56}, - {0, 59, 58}, - {0, 5, 47}, - {0, 60, 20}, - {0, 62, 61}, - {0, 64, 63}, - {0, 66, 65}, - {0, 67, 39}, - {0, 69, 68}, - {0, 16, 70}, - {0, 3, 71}, - {0, 73, 72}, - {0, 41, 15}, - {0, 35, 74}, - {0, 76, 75}, - {0, 78, 77}, - {0, 36, 79}, - {0, 81, 80}, - {0, 83, 82}, - {0, 14, 84}, - {0, 86, 85}, - {0, 88, 87}, - {0, 32, 89}, - {0, 42, 90}, - {0, 92, 91}, - {0, 94, 93}, - {0, 96, 95}, - {0, 98, 97}, - {0, 52, 99}, - {0, 100, 4}, - {0, 102, 101}, - })); - - codecs.emplace(std::pair(SpvOpFSub, 2), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(157, { - {0, 0, 0}, - {49456560, 0, 0}, - {170690025, 0, 0}, - {243178923, 0, 0}, - {295017943, 0, 0}, - {296981500, 0, 0}, - {330249537, 0, 0}, - {435256475, 0, 0}, - {443558693, 0, 0}, - {456043370, 0, 0}, - {470277359, 0, 0}, - {592180731, 0, 0}, - {663258455, 0, 0}, - {706238670, 0, 0}, - {810488476, 0, 0}, - {870594305, 0, 0}, - {877895868, 0, 0}, - {900522183, 0, 0}, - {1077859090, 0, 0}, - {1082941229, 0, 0}, - {1104362365, 0, 0}, - {1132589448, 0, 0}, - {1173092699, 0, 0}, - {1203545131, 0, 0}, - {1265796414, 0, 0}, - {1278818058, 0, 0}, - {1285705317, 0, 0}, - {1319785741, 0, 0}, - {1382106590, 0, 0}, - {1461897718, 0, 0}, - {1474506522, 0, 0}, - {1530183840, 0, 0}, - {1558001705, 0, 0}, - {1558990974, 0, 0}, - {1616846013, 0, 0}, - {1633850097, 0, 0}, - {1684282922, 0, 0}, - {1725011064, 0, 0}, - {1767704813, 0, 0}, - {1923453688, 0, 0}, - {1941148668, 0, 0}, - {1955104493, 0, 0}, - {2022961611, 0, 0}, - {2162274327, 0, 0}, - {2212501241, 0, 0}, - {2219733501, 0, 0}, - {2234361374, 0, 0}, - {2272221101, 0, 0}, - {2305269460, 0, 0}, - {2488410748, 0, 0}, - {2566666743, 0, 0}, - {2598189097, 0, 0}, - {2775815164, 0, 0}, - {2793529873, 0, 0}, - {2844616706, 0, 0}, - {2970183398, 0, 0}, - {3103302036, 0, 0}, - {3110479131, 0, 0}, - {3115038057, 0, 0}, - {3116932970, 0, 0}, - {3152745753, 0, 0}, - {3187066832, 0, 0}, - {3244209297, 0, 0}, - {3383007207, 0, 0}, - {3392887901, 0, 0}, - {3508792859, 0, 0}, - {3737376990, 0, 0}, - {3753486980, 0, 0}, - {3765247327, 0, 0}, - {3817149113, 0, 0}, - {3839047923, 0, 0}, - {3886529747, 0, 0}, - {4044928561, 0, 0}, - {4061558677, 0, 0}, - {4069720347, 0, 0}, - {4069810315, 0, 0}, - {4128942283, 0, 0}, - {4164704452, 0, 0}, - {4273793488, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 74, 47}, - {0, 34, 33}, - {0, 36, 14}, - {0, 61, 48}, - {0, 13, 31}, - {0, 39, 25}, - {0, 37, 29}, - {0, 65, 54}, - {0, 4, 73}, - {0, 38, 10}, - {0, 15, 43}, - {0, 6, 35}, - {0, 9, 16}, - {0, 30, 19}, - {0, 49, 44}, - {0, 57, 53}, - {0, 60, 58}, - {0, 72, 66}, - {0, 59, 76}, - {0, 1, 68}, - {0, 70, 42}, - {0, 63, 3}, - {0, 28, 69}, - {0, 17, 55}, - {0, 45, 64}, - {0, 81, 80}, - {0, 7, 82}, - {0, 12, 11}, - {0, 21, 50}, - {0, 83, 18}, - {0, 22, 84}, - {0, 85, 26}, - {0, 20, 86}, - {0, 87, 40}, - {0, 56, 88}, - {0, 90, 89}, - {0, 92, 91}, - {0, 93, 2}, - {0, 95, 94}, - {0, 97, 96}, - {0, 98, 41}, - {0, 100, 99}, - {0, 101, 52}, - {0, 103, 102}, - {0, 77, 71}, - {0, 104, 78}, - {0, 105, 46}, - {0, 32, 8}, - {0, 106, 51}, - {0, 108, 107}, - {0, 23, 109}, - {0, 110, 27}, - {0, 112, 111}, - {0, 113, 75}, - {0, 115, 114}, - {0, 117, 116}, - {0, 119, 118}, - {0, 121, 120}, - {0, 123, 122}, - {0, 124, 62}, - {0, 126, 125}, - {0, 128, 127}, - {0, 67, 129}, - {0, 131, 130}, - {0, 5, 132}, - {0, 134, 133}, - {0, 136, 135}, - {0, 138, 137}, - {0, 139, 24}, - {0, 141, 140}, - {0, 143, 142}, - {0, 145, 144}, - {0, 147, 146}, - {0, 149, 148}, - {0, 151, 150}, - {0, 153, 152}, - {0, 79, 154}, - {0, 156, 155}, - })); - - codecs.emplace(std::pair(SpvOpFSub, 3), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(9, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 4, 5}, - {0, 3, 6}, - {0, 1, 7}, - {0, 8, 2}, - })); - - codecs.emplace(std::pair(SpvOpFMul, 0), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(41, { - {0, 0, 0}, - {342197850, 0, 0}, - {885020215, 0, 0}, - {963902061, 0, 0}, - {1041368449, 0, 0}, - {1352397672, 0, 0}, - {1791427568, 0, 0}, - {2013867381, 0, 0}, - {2513230733, 0, 0}, - {2555315060, 0, 0}, - {2562485583, 0, 0}, - {2567901801, 0, 0}, - {2655147757, 0, 0}, - {2680283743, 0, 0}, - {2752766693, 0, 0}, - {2806716850, 0, 0}, - {3030911670, 0, 0}, - {3401762422, 0, 0}, - {3697738938, 0, 0}, - {4164704452, 0, 0}, - {4273793488, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 14, 10}, - {0, 7, 16}, - {0, 1, 15}, - {0, 9, 6}, - {0, 4, 12}, - {0, 18, 5}, - {0, 13, 2}, - {0, 19, 3}, - {0, 17, 20}, - {0, 23, 22}, - {0, 24, 8}, - {0, 26, 25}, - {0, 27, 11}, - {0, 29, 28}, - {0, 31, 30}, - {0, 33, 32}, - {0, 35, 34}, - {0, 37, 36}, - {0, 39, 38}, - {0, 21, 40}, - })); - - codecs.emplace(std::pair(SpvOpFMul, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(129, { - {0, 0, 0}, - {126463145, 0, 0}, - {129135650, 0, 0}, - {200922300, 0, 0}, - {328661377, 0, 0}, - {354479447, 0, 0}, - {360730278, 0, 0}, - {451264926, 0, 0}, - {529068443, 0, 0}, - {593829839, 0, 0}, - {742917749, 0, 0}, - {761731755, 0, 0}, - {810488476, 0, 0}, - {870594305, 0, 0}, - {894529125, 0, 0}, - {959681532, 0, 0}, - {1054461787, 0, 0}, - {1077859090, 0, 0}, - {1086964761, 0, 0}, - {1158929937, 0, 0}, - {1168927492, 0, 0}, - {1196280518, 0, 0}, - {1203545131, 0, 0}, - {1367301635, 0, 0}, - {1508550646, 0, 0}, - {1618544981, 0, 0}, - {1661163736, 0, 0}, - {1684282922, 0, 0}, - {1766994680, 0, 0}, - {1830851200, 0, 0}, - {1901166356, 0, 0}, - {1955104493, 0, 0}, - {2055836767, 0, 0}, - {2096388952, 0, 0}, - {2100052708, 0, 0}, - {2161102232, 0, 0}, - {2197904616, 0, 0}, - {2262137600, 0, 0}, - {2278571792, 0, 0}, - {2281956980, 0, 0}, - {2438466459, 0, 0}, - {2443959748, 0, 0}, - {2517964682, 0, 0}, - {2557754096, 0, 0}, - {2622612602, 0, 0}, - {2660843182, 0, 0}, - {2736844435, 0, 0}, - {2780898906, 0, 0}, - {3044188332, 0, 0}, - {3059119137, 0, 0}, - {3194725903, 0, 0}, - {3270430997, 0, 0}, - {3337532056, 0, 0}, - {3407526215, 0, 0}, - {3496407048, 0, 0}, - {3504158761, 0, 0}, - {3534518722, 0, 0}, - {3570411982, 0, 0}, - {3701632935, 0, 0}, - {3929248764, 0, 0}, - {3944781937, 0, 0}, - {3970432934, 0, 0}, - {4008405264, 0, 0}, - {4245257809, 0, 0}, - {4253051659, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 6, 26}, - {0, 46, 24}, - {0, 64, 50}, - {0, 7, 17}, - {0, 40, 57}, - {0, 56, 49}, - {0, 34, 10}, - {0, 32, 61}, - {0, 36, 44}, - {0, 8, 43}, - {0, 4, 18}, - {0, 25, 23}, - {0, 9, 54}, - {0, 45, 41}, - {0, 13, 21}, - {0, 47, 31}, - {0, 39, 53}, - {0, 11, 3}, - {0, 29, 20}, - {0, 38, 58}, - {0, 37, 14}, - {0, 66, 52}, - {0, 67, 35}, - {0, 48, 68}, - {0, 1, 69}, - {0, 70, 28}, - {0, 27, 63}, - {0, 72, 71}, - {0, 74, 73}, - {0, 75, 60}, - {0, 77, 76}, - {0, 5, 51}, - {0, 15, 78}, - {0, 30, 79}, - {0, 55, 80}, - {0, 42, 81}, - {0, 83, 82}, - {0, 85, 84}, - {0, 86, 2}, - {0, 19, 16}, - {0, 87, 59}, - {0, 62, 88}, - {0, 90, 89}, - {0, 22, 91}, - {0, 93, 92}, - {0, 95, 94}, - {0, 97, 96}, - {0, 99, 98}, - {0, 101, 100}, - {0, 12, 102}, - {0, 104, 103}, - {0, 33, 105}, - {0, 107, 106}, - {0, 109, 108}, - {0, 111, 110}, - {0, 113, 112}, - {0, 115, 114}, - {0, 117, 116}, - {0, 119, 118}, - {0, 121, 120}, - {0, 123, 122}, - {0, 125, 124}, - {0, 127, 126}, - {0, 65, 128}, - })); - - codecs.emplace(std::pair(SpvOpFMul, 2), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(127, { - {0, 0, 0}, - {13319433, 0, 0}, - {15502752, 0, 0}, - {162608772, 0, 0}, - {171307615, 0, 0}, - {296981500, 0, 0}, - {354479447, 0, 0}, - {413918748, 0, 0}, - {443490822, 0, 0}, - {487719832, 0, 0}, - {593829839, 0, 0}, - {615982737, 0, 0}, - {703543228, 0, 0}, - {810488476, 0, 0}, - {870594305, 0, 0}, - {875212982, 0, 0}, - {959681532, 0, 0}, - {1019457583, 0, 0}, - {1203545131, 0, 0}, - {1278448636, 0, 0}, - {1325348861, 0, 0}, - {1368383673, 0, 0}, - {1400019344, 0, 0}, - {1646147798, 0, 0}, - {1679946323, 0, 0}, - {1684282922, 0, 0}, - {1747355813, 0, 0}, - {1755648697, 0, 0}, - {1793544760, 0, 0}, - {1811839150, 0, 0}, - {1901166356, 0, 0}, - {1947620272, 0, 0}, - {1992893964, 0, 0}, - {2042001863, 0, 0}, - {2096388952, 0, 0}, - {2123388694, 0, 0}, - {2128251367, 0, 0}, - {2130747644, 0, 0}, - {2135340676, 0, 0}, - {2161102232, 0, 0}, - {2443959748, 0, 0}, - {2513230733, 0, 0}, - {2557754096, 0, 0}, - {2580096524, 0, 0}, - {2589449658, 0, 0}, - {2614879967, 0, 0}, - {2698156268, 0, 0}, - {2970183398, 0, 0}, - {3002890475, 0, 0}, - {3133016299, 0, 0}, - {3142155593, 0, 0}, - {3187066832, 0, 0}, - {3266548732, 0, 0}, - {3287039847, 0, 0}, - {3357301402, 0, 0}, - {3413713311, 0, 0}, - {3434076295, 0, 0}, - {3496407048, 0, 0}, - {3504158761, 0, 0}, - {3882634684, 0, 0}, - {3929248764, 0, 0}, - {3987079331, 0, 0}, - {4076840151, 0, 0}, - {4243119782, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 31, 8}, - {0, 14, 56}, - {0, 7, 12}, - {0, 9, 30}, - {0, 42, 36}, - {0, 19, 11}, - {0, 22, 40}, - {0, 15, 3}, - {0, 57, 26}, - {0, 58, 61}, - {0, 55, 51}, - {0, 48, 34}, - {0, 20, 1}, - {0, 24, 23}, - {0, 46, 35}, - {0, 59, 49}, - {0, 21, 63}, - {0, 62, 44}, - {0, 6, 50}, - {0, 28, 18}, - {0, 66, 65}, - {0, 41, 32}, - {0, 39, 54}, - {0, 53, 67}, - {0, 68, 37}, - {0, 33, 69}, - {0, 43, 70}, - {0, 71, 38}, - {0, 72, 27}, - {0, 13, 47}, - {0, 45, 73}, - {0, 75, 74}, - {0, 76, 5}, - {0, 77, 17}, - {0, 79, 78}, - {0, 52, 80}, - {0, 2, 81}, - {0, 83, 82}, - {0, 85, 84}, - {0, 87, 86}, - {0, 4, 88}, - {0, 16, 29}, - {0, 90, 89}, - {0, 92, 91}, - {0, 94, 93}, - {0, 60, 95}, - {0, 97, 96}, - {0, 98, 10}, - {0, 25, 99}, - {0, 101, 100}, - {0, 103, 102}, - {0, 105, 104}, - {0, 107, 106}, - {0, 109, 108}, - {0, 111, 110}, - {0, 113, 112}, - {0, 115, 114}, - {0, 117, 116}, - {0, 119, 118}, - {0, 121, 120}, - {0, 123, 122}, - {0, 125, 124}, - {0, 64, 126}, - })); - - codecs.emplace(std::pair(SpvOpFMul, 3), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(9, { - {0, 0, 0}, - {679771963, 0, 0}, - {1951208733, 0, 0}, - {2320303498, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 4, 5}, - {0, 3, 6}, - {0, 7, 1}, - {0, 2, 8}, - })); - - codecs.emplace(std::pair(SpvOpFDiv, 0), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(153, { - {0, 0, 0}, - {10142671, 0, 0}, - {27865391, 0, 0}, - {29517006, 0, 0}, - {41739659, 0, 0}, - {97231530, 0, 0}, - {171334650, 0, 0}, - {200553094, 0, 0}, - {257136089, 0, 0}, - {294390719, 0, 0}, - {375530199, 0, 0}, - {380957745, 0, 0}, - {388034151, 0, 0}, - {455591063, 0, 0}, - {462664429, 0, 0}, - {491456522, 0, 0}, - {502863753, 0, 0}, - {626480004, 0, 0}, - {643418617, 0, 0}, - {651464351, 0, 0}, - {701281393, 0, 0}, - {744817486, 0, 0}, - {783918780, 0, 0}, - {862784766, 0, 0}, - {930804377, 0, 0}, - {952536201, 0, 0}, - {955476870, 0, 0}, - {1043738701, 0, 0}, - {1047011733, 0, 0}, - {1080545747, 0, 0}, - {1137442027, 0, 0}, - {1235468610, 0, 0}, - {1412908157, 0, 0}, - {1431749301, 0, 0}, - {1434223270, 0, 0}, - {1440646342, 0, 0}, - {1508570930, 0, 0}, - {1510422521, 0, 0}, - {1548121999, 0, 0}, - {1582841441, 0, 0}, - {1612225949, 0, 0}, - {1665981878, 0, 0}, - {1680746207, 0, 0}, - {1696076631, 0, 0}, - {1702168830, 0, 0}, - {1761469971, 0, 0}, - {1799299383, 0, 0}, - {1910240213, 0, 0}, - {1917451875, 0, 0}, - {1945006185, 0, 0}, - {1998444837, 0, 0}, - {2045285083, 0, 0}, - {2217966239, 0, 0}, - {2279273489, 0, 0}, - {2289803479, 0, 0}, - {2348676810, 0, 0}, - {2353194283, 0, 0}, - {2403632109, 0, 0}, - {2409539315, 0, 0}, - {2414984922, 0, 0}, - {2477389837, 0, 0}, - {2524531022, 0, 0}, - {2573160348, 0, 0}, - {2639720559, 0, 0}, - {2773229577, 0, 0}, - {2796513469, 0, 0}, - {2881225774, 0, 0}, - {2890570341, 0, 0}, - {2952850186, 0, 0}, - {3023287679, 0, 0}, - {3118548424, 0, 0}, - {3877813395, 0, 0}, - {3931288033, 0, 0}, - {3972309363, 0, 0}, - {4117704995, 0, 0}, - {4140081844, 0, 0}, - {4258414038, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 74, 53}, - {0, 58, 52}, - {0, 65, 60}, - {0, 41, 5}, - {0, 1, 67}, - {0, 24, 28}, - {0, 27, 26}, - {0, 55, 31}, - {0, 36, 61}, - {0, 13, 49}, - {0, 56, 48}, - {0, 16, 64}, - {0, 76, 42}, - {0, 45, 29}, - {0, 23, 6}, - {0, 72, 12}, - {0, 35, 19}, - {0, 20, 7}, - {0, 21, 46}, - {0, 71, 78}, - {0, 80, 79}, - {0, 47, 17}, - {0, 81, 70}, - {0, 34, 25}, - {0, 83, 82}, - {0, 85, 84}, - {0, 37, 86}, - {0, 87, 73}, - {0, 10, 4}, - {0, 40, 30}, - {0, 88, 57}, - {0, 54, 89}, - {0, 50, 90}, - {0, 11, 91}, - {0, 39, 15}, - {0, 59, 44}, - {0, 92, 66}, - {0, 69, 93}, - {0, 95, 94}, - {0, 14, 96}, - {0, 98, 97}, - {0, 62, 51}, - {0, 100, 99}, - {0, 102, 101}, - {0, 104, 103}, - {0, 32, 43}, - {0, 105, 38}, - {0, 107, 106}, - {0, 109, 108}, - {0, 22, 9}, - {0, 33, 110}, - {0, 2, 111}, - {0, 112, 3}, - {0, 114, 113}, - {0, 116, 115}, - {0, 68, 63}, - {0, 118, 117}, - {0, 120, 119}, - {0, 121, 8}, - {0, 123, 122}, - {0, 125, 124}, - {0, 127, 126}, - {0, 129, 128}, - {0, 131, 130}, - {0, 133, 132}, - {0, 75, 18}, - {0, 135, 134}, - {0, 137, 136}, - {0, 139, 138}, - {0, 141, 140}, - {0, 143, 142}, - {0, 145, 144}, - {0, 147, 146}, - {0, 149, 148}, - {0, 150, 77}, - {0, 152, 151}, - })); - - codecs.emplace(std::pair(SpvOpFDiv, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(131, { - {0, 0, 0}, - {5908395, 0, 0}, - {139011596, 0, 0}, - {296981500, 0, 0}, - {342615870, 0, 0}, - {370232173, 0, 0}, - {492958971, 0, 0}, - {528662843, 0, 0}, - {551924251, 0, 0}, - {604894932, 0, 0}, - {610429940, 0, 0}, - {780957373, 0, 0}, - {810488476, 0, 0}, - {872544165, 0, 0}, - {878733439, 0, 0}, - {918849409, 0, 0}, - {959681532, 0, 0}, - {1013756921, 0, 0}, - {1038982109, 0, 0}, - {1081611718, 0, 0}, - {1125913837, 0, 0}, - {1209418480, 0, 0}, - {1318081294, 0, 0}, - {1367301635, 0, 0}, - {1417425499, 0, 0}, - {1625742020, 0, 0}, - {1684282922, 0, 0}, - {1746004874, 0, 0}, - {1758287856, 0, 0}, - {1777640493, 0, 0}, - {2066323109, 0, 0}, - {2094550054, 0, 0}, - {2096388952, 0, 0}, - {2144962711, 0, 0}, - {2434845539, 0, 0}, - {2480811229, 0, 0}, - {2552825357, 0, 0}, - {2636946065, 0, 0}, - {2651956495, 0, 0}, - {2669086217, 0, 0}, - {2680819379, 0, 0}, - {2709694527, 0, 0}, - {2715304020, 0, 0}, - {2790648021, 0, 0}, - {2802261839, 0, 0}, - {2806296851, 0, 0}, - {2864543087, 0, 0}, - {2952260510, 0, 0}, - {2963184673, 0, 0}, - {3091876332, 0, 0}, - {3098991995, 0, 0}, - {3131890669, 0, 0}, - {3138977758, 0, 0}, - {3198541202, 0, 0}, - {3260579369, 0, 0}, - {3263841912, 0, 0}, - {3335250889, 0, 0}, - {3345856521, 0, 0}, - {3381478137, 0, 0}, - {3489269251, 0, 0}, - {3510242586, 0, 0}, - {3820814597, 0, 0}, - {3900859293, 0, 0}, - {4041974454, 0, 0}, - {4244540017, 0, 0}, - {4265894873, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 15, 52}, - {0, 20, 18}, - {0, 39, 29}, - {0, 9, 43}, - {0, 22, 13}, - {0, 46, 27}, - {0, 51, 48}, - {0, 19, 57}, - {0, 34, 24}, - {0, 64, 59}, - {0, 5, 7}, - {0, 38, 37}, - {0, 45, 47}, - {0, 2, 56}, - {0, 67, 8}, - {0, 17, 68}, - {0, 69, 61}, - {0, 70, 6}, - {0, 55, 54}, - {0, 72, 71}, - {0, 4, 73}, - {0, 74, 40}, - {0, 30, 11}, - {0, 42, 36}, - {0, 75, 58}, - {0, 31, 76}, - {0, 1, 77}, - {0, 44, 14}, - {0, 78, 50}, - {0, 79, 23}, - {0, 26, 80}, - {0, 81, 12}, - {0, 83, 82}, - {0, 84, 21}, - {0, 32, 85}, - {0, 87, 86}, - {0, 35, 10}, - {0, 88, 62}, - {0, 90, 89}, - {0, 41, 91}, - {0, 92, 53}, - {0, 93, 63}, - {0, 95, 94}, - {0, 33, 96}, - {0, 98, 97}, - {0, 99, 3}, - {0, 100, 28}, - {0, 101, 49}, - {0, 102, 60}, - {0, 104, 103}, - {0, 106, 105}, - {0, 108, 107}, - {0, 110, 109}, - {0, 65, 111}, - {0, 25, 112}, - {0, 114, 113}, - {0, 116, 115}, - {0, 117, 16}, - {0, 119, 118}, - {0, 121, 120}, - {0, 123, 122}, - {0, 125, 124}, - {0, 127, 126}, - {0, 128, 66}, - {0, 130, 129}, - })); - - codecs.emplace(std::pair(SpvOpFDiv, 2), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(95, { - {0, 0, 0}, - {116093251, 0, 0}, - {149720480, 0, 0}, - {183103444, 0, 0}, - {251209228, 0, 0}, - {296981500, 0, 0}, - {357505993, 0, 0}, - {394654115, 0, 0}, - {410274915, 0, 0}, - {452208841, 0, 0}, - {788046331, 0, 0}, - {797934924, 0, 0}, - {810488476, 0, 0}, - {1144188012, 0, 0}, - {1220127364, 0, 0}, - {1321616112, 0, 0}, - {1324351672, 0, 0}, - {1348149915, 0, 0}, - {1459457331, 0, 0}, - {1465623797, 0, 0}, - {1531216990, 0, 0}, - {1543672828, 0, 0}, - {1578775276, 0, 0}, - {1738815671, 0, 0}, - {1904128160, 0, 0}, - {2071351379, 0, 0}, - {2119793999, 0, 0}, - {2274779301, 0, 0}, - {2291766425, 0, 0}, - {2357410109, 0, 0}, - {2438466459, 0, 0}, - {2496463830, 0, 0}, - {2630220147, 0, 0}, - {2682510803, 0, 0}, - {3047649911, 0, 0}, - {3085703811, 0, 0}, - {3235459678, 0, 0}, - {3261703164, 0, 0}, - {3331487616, 0, 0}, - {3462674048, 0, 0}, - {3570219049, 0, 0}, - {3585315836, 0, 0}, - {3602108619, 0, 0}, - {3724004880, 0, 0}, - {3931641900, 0, 0}, - {3955205564, 0, 0}, - {4073492988, 0, 0}, - {4127308103, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 24, 37}, - {0, 13, 38}, - {0, 17, 39}, - {0, 35, 23}, - {0, 18, 36}, - {0, 46, 19}, - {0, 20, 33}, - {0, 47, 6}, - {0, 1, 45}, - {0, 3, 27}, - {0, 8, 49}, - {0, 50, 29}, - {0, 10, 51}, - {0, 43, 31}, - {0, 53, 52}, - {0, 54, 26}, - {0, 7, 55}, - {0, 56, 32}, - {0, 57, 41}, - {0, 59, 58}, - {0, 61, 60}, - {0, 63, 62}, - {0, 64, 25}, - {0, 2, 34}, - {0, 65, 14}, - {0, 67, 66}, - {0, 12, 21}, - {0, 9, 68}, - {0, 69, 16}, - {0, 71, 70}, - {0, 72, 44}, - {0, 11, 73}, - {0, 74, 30}, - {0, 4, 75}, - {0, 28, 15}, - {0, 76, 42}, - {0, 5, 77}, - {0, 78, 40}, - {0, 80, 79}, - {0, 82, 81}, - {0, 22, 83}, - {0, 85, 84}, - {0, 86, 48}, - {0, 88, 87}, - {0, 90, 89}, - {0, 92, 91}, - {0, 94, 93}, - })); - - codecs.emplace(std::pair(SpvOpFDiv, 3), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(7, { - {0, 0, 0}, - {679771963, 0, 0}, - {2320303498, 0, 0}, - {3334207724, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 3, 4}, - {0, 2, 5}, - {0, 1, 6}, - })); - - codecs.emplace(std::pair(SpvOpVectorTimesScalar, 0), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(121, { - {0, 0, 0}, - {14113753, 0, 0}, - {102358168, 0, 0}, - {179458548, 0, 0}, - {330388453, 0, 0}, - {386525753, 0, 0}, - {470277359, 0, 0}, - {497658126, 0, 0}, - {508007510, 0, 0}, - {815034111, 0, 0}, - {826214242, 0, 0}, - {849867303, 0, 0}, - {885645401, 0, 0}, - {939415664, 0, 0}, - {968885186, 0, 0}, - {1105835505, 0, 0}, - {1159301677, 0, 0}, - {1461897718, 0, 0}, - {1482251215, 0, 0}, - {1486206763, 0, 0}, - {1527762373, 0, 0}, - {1558990974, 0, 0}, - {1618754372, 0, 0}, - {1669959736, 0, 0}, - {1752686878, 0, 0}, - {2004567202, 0, 0}, - {2055637638, 0, 0}, - {2113506324, 0, 0}, - {2154320787, 0, 0}, - {2162274327, 0, 0}, - {2306141594, 0, 0}, - {2345566651, 0, 0}, - {2457690657, 0, 0}, - {2473053808, 0, 0}, - {2500422644, 0, 0}, - {2504802016, 0, 0}, - {2506771164, 0, 0}, - {2793529873, 0, 0}, - {2801333547, 0, 0}, - {2879050471, 0, 0}, - {3032677281, 0, 0}, - {3045470312, 0, 0}, - {3181546731, 0, 0}, - {3240977890, 0, 0}, - {3262572726, 0, 0}, - {3307100165, 0, 0}, - {3425841570, 0, 0}, - {3560552546, 0, 0}, - {3641833815, 0, 0}, - {3652695478, 0, 0}, - {3782362128, 0, 0}, - {3797961332, 0, 0}, - {3837583704, 0, 0}, - {3886529747, 0, 0}, - {3907920335, 0, 0}, - {4043078107, 0, 0}, - {4044928561, 0, 0}, - {4069720347, 0, 0}, - {4180570743, 0, 0}, - {4245743275, 0, 0}, - {4285201458, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 44, 28}, - {0, 13, 45}, - {0, 19, 15}, - {0, 32, 31}, - {0, 43, 42}, - {0, 16, 52}, - {0, 33, 22}, - {0, 57, 55}, - {0, 24, 21}, - {0, 2, 59}, - {0, 10, 3}, - {0, 18, 12}, - {0, 41, 39}, - {0, 60, 46}, - {0, 4, 25}, - {0, 58, 49}, - {0, 14, 1}, - {0, 27, 17}, - {0, 50, 36}, - {0, 23, 54}, - {0, 5, 30}, - {0, 11, 7}, - {0, 38, 29}, - {0, 37, 8}, - {0, 48, 56}, - {0, 20, 6}, - {0, 34, 26}, - {0, 63, 62}, - {0, 65, 64}, - {0, 67, 66}, - {0, 69, 68}, - {0, 71, 70}, - {0, 73, 72}, - {0, 75, 74}, - {0, 9, 76}, - {0, 78, 77}, - {0, 80, 79}, - {0, 82, 81}, - {0, 84, 83}, - {0, 40, 35}, - {0, 85, 47}, - {0, 86, 51}, - {0, 88, 87}, - {0, 90, 89}, - {0, 53, 91}, - {0, 93, 92}, - {0, 95, 94}, - {0, 97, 96}, - {0, 99, 98}, - {0, 101, 100}, - {0, 103, 102}, - {0, 105, 104}, - {0, 107, 106}, - {0, 109, 108}, - {0, 111, 110}, - {0, 113, 112}, - {0, 115, 114}, - {0, 117, 116}, - {0, 119, 118}, - {0, 61, 120}, - })); - - codecs.emplace(std::pair(SpvOpVectorTimesScalar, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(127, { - {0, 0, 0}, - {100979271, 0, 0}, - {269576093, 0, 0}, - {314809953, 0, 0}, - {354479447, 0, 0}, - {497658126, 0, 0}, - {882718761, 0, 0}, - {968885186, 0, 0}, - {973908139, 0, 0}, - {1019457583, 0, 0}, - {1191015885, 0, 0}, - {1266262705, 0, 0}, - {1310404265, 0, 0}, - {1325348861, 0, 0}, - {1367301635, 0, 0}, - {1368383673, 0, 0}, - {1570165302, 0, 0}, - {1618544981, 0, 0}, - {1646147798, 0, 0}, - {1674464100, 0, 0}, - {1679946323, 0, 0}, - {1686512349, 0, 0}, - {1766401548, 0, 0}, - {1774052499, 0, 0}, - {1788301425, 0, 0}, - {2023008475, 0, 0}, - {2055836767, 0, 0}, - {2096388952, 0, 0}, - {2123388694, 0, 0}, - {2129301998, 0, 0}, - {2212501241, 0, 0}, - {2274226560, 0, 0}, - {2362972044, 0, 0}, - {2378763734, 0, 0}, - {2506771164, 0, 0}, - {2558655180, 0, 0}, - {2622612602, 0, 0}, - {2660843182, 0, 0}, - {2698156268, 0, 0}, - {2801333547, 0, 0}, - {2850246066, 0, 0}, - {2895151306, 0, 0}, - {2970183398, 0, 0}, - {2986830770, 0, 0}, - {3001444829, 0, 0}, - {3133016299, 0, 0}, - {3152745753, 0, 0}, - {3187066832, 0, 0}, - {3261122899, 0, 0}, - {3496407048, 0, 0}, - {3513669836, 0, 0}, - {3536390697, 0, 0}, - {3570411982, 0, 0}, - {3653838348, 0, 0}, - {3713290482, 0, 0}, - {3858973601, 0, 0}, - {3873587660, 0, 0}, - {3877583949, 0, 0}, - {3882634684, 0, 0}, - {3907920335, 0, 0}, - {3997432565, 0, 0}, - {4169226615, 0, 0}, - {4219766939, 0, 0}, - {4243119782, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 25, 12}, - {0, 41, 29}, - {0, 56, 44}, - {0, 1, 3}, - {0, 48, 24}, - {0, 33, 60}, - {0, 8, 50}, - {0, 35, 21}, - {0, 11, 7}, - {0, 34, 23}, - {0, 59, 57}, - {0, 10, 62}, - {0, 40, 2}, - {0, 5, 49}, - {0, 39, 17}, - {0, 9, 61}, - {0, 30, 6}, - {0, 19, 46}, - {0, 53, 54}, - {0, 31, 52}, - {0, 55, 43}, - {0, 66, 65}, - {0, 16, 67}, - {0, 51, 68}, - {0, 70, 69}, - {0, 26, 36}, - {0, 72, 71}, - {0, 74, 73}, - {0, 76, 75}, - {0, 78, 77}, - {0, 80, 79}, - {0, 82, 81}, - {0, 37, 83}, - {0, 85, 84}, - {0, 13, 86}, - {0, 20, 18}, - {0, 38, 28}, - {0, 58, 45}, - {0, 87, 63}, - {0, 15, 88}, - {0, 32, 22}, - {0, 89, 4}, - {0, 90, 14}, - {0, 91, 42}, - {0, 93, 92}, - {0, 95, 94}, - {0, 97, 96}, - {0, 99, 98}, - {0, 101, 100}, - {0, 103, 102}, - {0, 105, 104}, - {0, 107, 106}, - {0, 109, 108}, - {0, 111, 110}, - {0, 113, 112}, - {0, 115, 114}, - {0, 27, 47}, - {0, 117, 116}, - {0, 119, 118}, - {0, 121, 120}, - {0, 123, 122}, - {0, 125, 124}, - {0, 126, 64}, - })); - - codecs.emplace(std::pair(SpvOpVectorTimesScalar, 2), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(137, { - {0, 0, 0}, - {11698369, 0, 0}, - {146392076, 0, 0}, - {151810803, 0, 0}, - {223800276, 0, 0}, - {227103506, 0, 0}, - {253329281, 0, 0}, - {346929928, 0, 0}, - {461040879, 0, 0}, - {629859130, 0, 0}, - {680157484, 0, 0}, - {783918780, 0, 0}, - {810488476, 0, 0}, - {824323032, 0, 0}, - {870594305, 0, 0}, - {959681532, 0, 0}, - {975807626, 0, 0}, - {1081642571, 0, 0}, - {1084574846, 0, 0}, - {1094817798, 0, 0}, - {1141965917, 0, 0}, - {1164137269, 0, 0}, - {1166917451, 0, 0}, - {1204787336, 0, 0}, - {1232501371, 0, 0}, - {1318479490, 0, 0}, - {1369818198, 0, 0}, - {1372785527, 0, 0}, - {1526654696, 0, 0}, - {1543672828, 0, 0}, - {1548121999, 0, 0}, - {1635292159, 0, 0}, - {1641070431, 0, 0}, - {1684282922, 0, 0}, - {1767704813, 0, 0}, - {1781765116, 0, 0}, - {1838763297, 0, 0}, - {1901166356, 0, 0}, - {1904846533, 0, 0}, - {2011183308, 0, 0}, - {2032069771, 0, 0}, - {2071351379, 0, 0}, - {2087004702, 0, 0}, - {2244928358, 0, 0}, - {2314864456, 0, 0}, - {2374216296, 0, 0}, - {2394332122, 0, 0}, - {2443610186, 0, 0}, - {2524697596, 0, 0}, - {2526961521, 0, 0}, - {2568098594, 0, 0}, - {2807907995, 0, 0}, - {3103302036, 0, 0}, - {3117071189, 0, 0}, - {3188115516, 0, 0}, - {3417584874, 0, 0}, - {3554463148, 0, 0}, - {3561482820, 0, 0}, - {3691770462, 0, 0}, - {3729929345, 0, 0}, - {3733675151, 0, 0}, - {3831290364, 0, 0}, - {3866493821, 0, 0}, - {3929248764, 0, 0}, - {4060703604, 0, 0}, - {4092487128, 0, 0}, - {4167600590, 0, 0}, - {4214779116, 0, 0}, - {4248015868, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 36, 13}, - {0, 49, 60}, - {0, 51, 9}, - {0, 3, 62}, - {0, 67, 41}, - {0, 4, 31}, - {0, 66, 5}, - {0, 55, 32}, - {0, 2, 1}, - {0, 30, 16}, - {0, 7, 38}, - {0, 19, 10}, - {0, 34, 20}, - {0, 45, 46}, - {0, 22, 11}, - {0, 25, 23}, - {0, 40, 39}, - {0, 21, 57}, - {0, 6, 35}, - {0, 61, 8}, - {0, 52, 26}, - {0, 70, 59}, - {0, 71, 14}, - {0, 68, 47}, - {0, 73, 72}, - {0, 29, 74}, - {0, 76, 75}, - {0, 77, 17}, - {0, 79, 78}, - {0, 81, 80}, - {0, 82, 18}, - {0, 83, 42}, - {0, 85, 84}, - {0, 87, 86}, - {0, 27, 37}, - {0, 53, 43}, - {0, 89, 88}, - {0, 64, 54}, - {0, 90, 65}, - {0, 92, 91}, - {0, 58, 93}, - {0, 56, 48}, - {0, 94, 28}, - {0, 96, 95}, - {0, 98, 97}, - {0, 44, 99}, - {0, 101, 100}, - {0, 15, 12}, - {0, 103, 102}, - {0, 104, 33}, - {0, 106, 105}, - {0, 108, 107}, - {0, 24, 109}, - {0, 111, 110}, - {0, 113, 112}, - {0, 114, 50}, - {0, 116, 115}, - {0, 118, 117}, - {0, 120, 119}, - {0, 122, 121}, - {0, 124, 123}, - {0, 126, 125}, - {0, 128, 127}, - {0, 129, 63}, - {0, 131, 130}, - {0, 133, 132}, - {0, 135, 134}, - {0, 136, 69}, - })); - - codecs.emplace(std::pair(SpvOpVectorTimesScalar, 3), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {1951208733, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpDot, 0), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(97, { - {0, 0, 0}, - {78001013, 0, 0}, - {170690025, 0, 0}, - {206688607, 0, 0}, - {443490822, 0, 0}, - {461476226, 0, 0}, - {537830163, 0, 0}, - {669982125, 0, 0}, - {790502615, 0, 0}, - {805072272, 0, 0}, - {1173092699, 0, 0}, - {1220643281, 0, 0}, - {1448448666, 0, 0}, - {1466804584, 0, 0}, - {1473411044, 0, 0}, - {1515695460, 0, 0}, - {1587730355, 0, 0}, - {1625742020, 0, 0}, - {2071351379, 0, 0}, - {2250055803, 0, 0}, - {2291766425, 0, 0}, - {2416108131, 0, 0}, - {2427834344, 0, 0}, - {2436009347, 0, 0}, - {2455417440, 0, 0}, - {2480811229, 0, 0}, - {2654325647, 0, 0}, - {2919796598, 0, 0}, - {3047649911, 0, 0}, - {3088511797, 0, 0}, - {3104643263, 0, 0}, - {3198541202, 0, 0}, - {3204986803, 0, 0}, - {3272233597, 0, 0}, - {3383007207, 0, 0}, - {3602108619, 0, 0}, - {3622349409, 0, 0}, - {3714664910, 0, 0}, - {3717942504, 0, 0}, - {3732000233, 0, 0}, - {3759072440, 0, 0}, - {3765247327, 0, 0}, - {3805423332, 0, 0}, - {3829325073, 0, 0}, - {3866493821, 0, 0}, - {4058280485, 0, 0}, - {4061558677, 0, 0}, - {4148979936, 0, 0}, - {4155586396, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 13, 38}, - {0, 39, 14}, - {0, 44, 9}, - {0, 48, 47}, - {0, 23, 15}, - {0, 33, 25}, - {0, 1, 42}, - {0, 5, 46}, - {0, 31, 3}, - {0, 36, 28}, - {0, 16, 12}, - {0, 32, 22}, - {0, 41, 21}, - {0, 6, 50}, - {0, 51, 29}, - {0, 45, 34}, - {0, 37, 8}, - {0, 19, 52}, - {0, 11, 4}, - {0, 43, 40}, - {0, 27, 53}, - {0, 54, 10}, - {0, 24, 55}, - {0, 57, 56}, - {0, 58, 26}, - {0, 2, 59}, - {0, 61, 60}, - {0, 63, 62}, - {0, 65, 64}, - {0, 20, 66}, - {0, 30, 35}, - {0, 67, 17}, - {0, 68, 7}, - {0, 70, 69}, - {0, 71, 18}, - {0, 73, 72}, - {0, 75, 74}, - {0, 77, 76}, - {0, 79, 78}, - {0, 81, 80}, - {0, 83, 82}, - {0, 85, 84}, - {0, 87, 86}, - {0, 89, 88}, - {0, 91, 90}, - {0, 93, 92}, - {0, 95, 94}, - {0, 49, 96}, - })); - - codecs.emplace(std::pair(SpvOpDot, 1), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(117, { - {0, 0, 0}, - {50385656, 0, 0}, - {181902171, 0, 0}, - {560078433, 0, 0}, - {615982737, 0, 0}, - {674428451, 0, 0}, - {837715723, 0, 0}, - {886972033, 0, 0}, - {900101778, 0, 0}, - {983299427, 0, 0}, - {1237148906, 0, 0}, - {1364157225, 0, 0}, - {1367301635, 0, 0}, - {1380160211, 0, 0}, - {1451831482, 0, 0}, - {1499923635, 0, 0}, - {1570165302, 0, 0}, - {1735295265, 0, 0}, - {1766401548, 0, 0}, - {1796311149, 0, 0}, - {1826456251, 0, 0}, - {1839669171, 0, 0}, - {2012838864, 0, 0}, - {2024071551, 0, 0}, - {2096388952, 0, 0}, - {2161102232, 0, 0}, - {2197874825, 0, 0}, - {2279700640, 0, 0}, - {2289183712, 0, 0}, - {2351620600, 0, 0}, - {2362972044, 0, 0}, - {2472176885, 0, 0}, - {2477434291, 0, 0}, - {2530899578, 0, 0}, - {2531826164, 0, 0}, - {2558133383, 0, 0}, - {2589449658, 0, 0}, - {2621255555, 0, 0}, - {2622612602, 0, 0}, - {2872580757, 0, 0}, - {2881302403, 0, 0}, - {2891091137, 0, 0}, - {2923708820, 0, 0}, - {2936040203, 0, 0}, - {2970183398, 0, 0}, - {3187066832, 0, 0}, - {3224952074, 0, 0}, - {3244383472, 0, 0}, - {3261122899, 0, 0}, - {3362830643, 0, 0}, - {3538158875, 0, 0}, - {3635542517, 0, 0}, - {3682213068, 0, 0}, - {3721902098, 0, 0}, - {3826846522, 0, 0}, - {3877583949, 0, 0}, - {3997432565, 0, 0}, - {4093615095, 0, 0}, - {4106828015, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 52, 28}, - {0, 33, 20}, - {0, 46, 57}, - {0, 47, 54}, - {0, 21, 17}, - {0, 31, 58}, - {0, 12, 53}, - {0, 29, 3}, - {0, 35, 34}, - {0, 48, 41}, - {0, 8, 5}, - {0, 7, 55}, - {0, 37, 32}, - {0, 60, 38}, - {0, 61, 16}, - {0, 14, 62}, - {0, 23, 63}, - {0, 13, 19}, - {0, 64, 9}, - {0, 65, 39}, - {0, 2, 66}, - {0, 67, 42}, - {0, 69, 68}, - {0, 25, 70}, - {0, 1, 49}, - {0, 6, 71}, - {0, 72, 15}, - {0, 73, 11}, - {0, 75, 74}, - {0, 77, 76}, - {0, 4, 78}, - {0, 56, 50}, - {0, 80, 79}, - {0, 10, 81}, - {0, 83, 82}, - {0, 85, 84}, - {0, 86, 27}, - {0, 43, 40}, - {0, 88, 87}, - {0, 44, 24}, - {0, 30, 89}, - {0, 51, 36}, - {0, 45, 90}, - {0, 18, 91}, - {0, 93, 92}, - {0, 22, 94}, - {0, 26, 95}, - {0, 97, 96}, - {0, 99, 98}, - {0, 101, 100}, - {0, 103, 102}, - {0, 105, 104}, - {0, 107, 106}, - {0, 109, 108}, - {0, 111, 110}, - {0, 113, 112}, - {0, 59, 114}, - {0, 116, 115}, - })); - - codecs.emplace(std::pair(SpvOpDot, 2), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(179, { - {0, 0, 0}, - {27177503, 0, 0}, - {50385656, 0, 0}, - {129748122, 0, 0}, - {139011596, 0, 0}, - {162608772, 0, 0}, - {181902171, 0, 0}, - {225200779, 0, 0}, - {342159236, 0, 0}, - {386293029, 0, 0}, - {429023543, 0, 0}, - {443558693, 0, 0}, - {504514034, 0, 0}, - {615982737, 0, 0}, - {669812542, 0, 0}, - {674428451, 0, 0}, - {837715723, 0, 0}, - {861753115, 0, 0}, - {875212982, 0, 0}, - {876867882, 0, 0}, - {899320334, 0, 0}, - {900101778, 0, 0}, - {938517572, 0, 0}, - {1347339159, 0, 0}, - {1356063462, 0, 0}, - {1373856501, 0, 0}, - {1376656865, 0, 0}, - {1451831482, 0, 0}, - {1522979646, 0, 0}, - {1548491889, 0, 0}, - {1570165302, 0, 0}, - {1735295265, 0, 0}, - {1747355813, 0, 0}, - {1766401548, 0, 0}, - {1871105284, 0, 0}, - {1918742169, 0, 0}, - {1922045399, 0, 0}, - {1978689945, 0, 0}, - {2024071551, 0, 0}, - {2059975069, 0, 0}, - {2076833303, 0, 0}, - {2096388952, 0, 0}, - {2181030375, 0, 0}, - {2197874825, 0, 0}, - {2362972044, 0, 0}, - {2414725163, 0, 0}, - {2517964682, 0, 0}, - {2564745684, 0, 0}, - {2577387676, 0, 0}, - {2589449658, 0, 0}, - {2604242419, 0, 0}, - {2683080096, 0, 0}, - {2696349144, 0, 0}, - {2763960513, 0, 0}, - {2817823941, 0, 0}, - {2852854788, 0, 0}, - {2891091137, 0, 0}, - {2919626325, 0, 0}, - {2923708820, 0, 0}, - {2936040203, 0, 0}, - {2963744582, 0, 0}, - {2970183398, 0, 0}, - {2984459037, 0, 0}, - {2996594997, 0, 0}, - {3015046341, 0, 0}, - {3055195668, 0, 0}, - {3127329373, 0, 0}, - {3187066832, 0, 0}, - {3193597927, 0, 0}, - {3200890815, 0, 0}, - {3224258475, 0, 0}, - {3224480461, 0, 0}, - {3261122899, 0, 0}, - {3609540589, 0, 0}, - {3619404941, 0, 0}, - {3619626927, 0, 0}, - {3727034815, 0, 0}, - {3742724777, 0, 0}, - {3742946763, 0, 0}, - {3836179806, 0, 0}, - {3913885196, 0, 0}, - {3927338499, 0, 0}, - {3927466635, 0, 0}, - {3997432565, 0, 0}, - {3999472204, 0, 0}, - {4010499223, 0, 0}, - {4032662899, 0, 0}, - {4110915453, 0, 0}, - {4145966869, 0, 0}, - {4228303141, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 23, 87}, - {0, 9, 28}, - {0, 42, 17}, - {0, 74, 70}, - {0, 86, 77}, - {0, 18, 5}, - {0, 31, 32}, - {0, 34, 3}, - {0, 38, 68}, - {0, 50, 29}, - {0, 72, 62}, - {0, 21, 15}, - {0, 14, 54}, - {0, 56, 22}, - {0, 48, 88}, - {0, 2, 76}, - {0, 6, 47}, - {0, 26, 79}, - {0, 65, 12}, - {0, 37, 81}, - {0, 91, 60}, - {0, 30, 92}, - {0, 25, 7}, - {0, 45, 40}, - {0, 66, 52}, - {0, 71, 69}, - {0, 78, 75}, - {0, 84, 82}, - {0, 94, 93}, - {0, 27, 95}, - {0, 97, 96}, - {0, 99, 98}, - {0, 100, 39}, - {0, 55, 101}, - {0, 58, 102}, - {0, 89, 103}, - {0, 35, 11}, - {0, 104, 36}, - {0, 53, 10}, - {0, 1, 64}, - {0, 73, 20}, - {0, 105, 13}, - {0, 107, 106}, - {0, 8, 16}, - {0, 24, 19}, - {0, 85, 63}, - {0, 109, 108}, - {0, 111, 110}, - {0, 4, 112}, - {0, 114, 113}, - {0, 116, 115}, - {0, 118, 117}, - {0, 83, 119}, - {0, 121, 120}, - {0, 123, 122}, - {0, 49, 44}, - {0, 124, 57}, - {0, 125, 59}, - {0, 126, 67}, - {0, 128, 127}, - {0, 130, 129}, - {0, 132, 131}, - {0, 134, 133}, - {0, 135, 51}, - {0, 137, 136}, - {0, 138, 61}, - {0, 43, 41}, - {0, 140, 139}, - {0, 142, 141}, - {0, 144, 143}, - {0, 146, 145}, - {0, 148, 147}, - {0, 149, 33}, - {0, 80, 150}, - {0, 152, 151}, - {0, 154, 153}, - {0, 156, 155}, - {0, 158, 157}, - {0, 160, 159}, - {0, 162, 161}, - {0, 164, 163}, - {0, 166, 165}, - {0, 168, 167}, - {0, 46, 169}, - {0, 171, 170}, - {0, 90, 172}, - {0, 174, 173}, - {0, 176, 175}, - {0, 178, 177}, - })); - - codecs.emplace(std::pair(SpvOpDot, 3), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {1036475267, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpLabel, 0), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(3, { - {0, 0, 0}, - {1036475267, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 1, 2}, - })); - - codecs.emplace(std::pair(SpvOpBranch, 0), std::move(codec)); - } - - { - std::unique_ptr> codec(new HuffmanCodec(119, { - {0, 0, 0}, - {57149555, 0, 0}, - {139011596, 0, 0}, - {255835594, 0, 0}, - {330249537, 0, 0}, - {388686774, 0, 0}, - {508217552, 0, 0}, - {550831114, 0, 0}, - {559246409, 0, 0}, - {599185303, 0, 0}, - {649208064, 0, 0}, - {679061455, 0, 0}, - {810488476, 0, 0}, - {951841533, 0, 0}, - {1008886329, 0, 0}, - {1022544883, 0, 0}, - {1215030156, 0, 0}, - {1305703280, 0, 0}, - {1367301635, 0, 0}, - {1453447304, 0, 0}, - {1487177499, 0, 0}, - {1603937321, 0, 0}, - {1617826947, 0, 0}, - {1643868273, 0, 0}, - {1672607981, 0, 0}, - {1681941034, 0, 0}, - {1755165354, 0, 0}, - {1781864804, 0, 0}, - {1795715718, 0, 0}, - {1977038330, 0, 0}, - {2096388952, 0, 0}, - {2204920111, 0, 0}, - {2244470522, 0, 0}, - {2330636993, 0, 0}, - {2400601988, 0, 0}, - {2424848261, 0, 0}, - {2603020391, 0, 0}, - {2622612602, 0, 0}, - {2645135839, 0, 0}, - {2660843182, 0, 0}, - {2708915136, 0, 0}, - {2724166585, 0, 0}, - {2728667725, 0, 0}, - {2890638791, 0, 0}, - {2901034693, 0, 0}, - {2941648648, 0, 0}, - {2970183398, 0, 0}, - {2998120306, 0, 0}, - {3123244280, 0, 0}, - {3187066832, 0, 0}, - {3209399506, 0, 0}, - {3230260738, 0, 0}, - {3344189994, 0, 0}, - {3345707173, 0, 0}, - {3367298820, 0, 0}, - {3397078357, 0, 0}, - {3569736966, 0, 0}, - {3816961131, 0, 0}, - {4091670162, 0, 0}, - {4237497041, 0, 0}, - {1111111111111111111, 0, 0}, - {0, 17, 44}, - {0, 25, 20}, - {0, 29, 34}, - {0, 18, 2}, - {0, 54, 49}, - {0, 28, 7}, - {0, 47, 52}, - {0, 23, 56}, - {0, 55, 26}, - {0, 24, 61}, - {0, 13, 62}, - {0, 63, 45}, - {0, 27, 15}, - {0, 64, 8}, - {0, 65, 59}, - {0, 35, 22}, - {0, 53, 38}, - {0, 58, 51}, - {0, 11, 66}, - {0, 10, 3}, - {0, 46, 67}, - {0, 69, 68}, - {0, 1, 50}, - {0, 42, 19}, - {0, 70, 6}, - {0, 31, 71}, - {0, 16, 72}, - {0, 74, 73}, - {0, 76, 75}, - {0, 78, 77}, - {0, 79, 4}, - {0, 5, 37}, - {0, 14, 36}, - {0, 80, 57}, - {0, 81, 48}, - {0, 83, 82}, - {0, 39, 84}, - {0, 86, 85}, - {0, 40, 87}, - {0, 89, 88}, - {0, 91, 90}, - {0, 93, 92}, - {0, 21, 9}, - {0, 41, 32}, - {0, 12, 43}, - {0, 95, 94}, - {0, 97, 96}, - {0, 99, 98}, - {0, 100, 33}, - {0, 60, 101}, - {0, 103, 102}, - {0, 105, 104}, - {0, 107, 106}, - {0, 109, 108}, - {0, 110, 30}, - {0, 112, 111}, - {0, 114, 113}, - {0, 116, 115}, - {0, 118, 117}, - })); - - codecs.emplace(std::pair(SpvOpReturnValue, 0), std::move(codec)); - } - - return codecs; -} - -std::unordered_set GetDescriptorsWithCodingScheme() { - std::unordered_set descriptors_with_coding_scheme = { - 3816961131, - 3569736966, - 3397078357, - 3344189994, - 3230260738, - 2941648648, - 2901034693, - 2728667725, - 2400601988, - 1795715718, - 1681941034, - 1487177499, - 1453447304, - 679061455, - 649208064, - 559246409, - 388686774, - 4228303141, - 4110915453, - 4010499223, - 3927466635, - 3927338499, - 3836179806, - 3742724777, - 3619404941, - 3224480461, - 3224258475, - 3200890815, - 3742946763, - 3193597927, - 2604242419, - 2577387676, - 2181030375, - 1376656865, - 1347339159, - 938517572, - 876867882, - 429023543, - 129748122, - 4106828015, - 4093615095, - 3826846522, - 3721902098, - 3244383472, - 2891091137, - 2872580757, - 2558133383, - 2477434291, - 1839669171, - 2059975069, - 1735295265, - 1364157225, - 1237148906, - 886972033, - 674428451, - 4148979936, - 3805423332, - 3732000233, - 3717942504, - 3714664910, - 3622349409, - 3272233597, - 3204986803, - 3088511797, - 1672607981, - 2416108131, - 2250055803, - 1796311149, - 1515695460, - 537830163, - 461476226, - 206688607, - 78001013, - 3866493821, - 3417584874, - 3188115516, - 2526961521, - 2443610186, - 2394332122, - 2374216296, - 2032069771, - 2011183308, - 1904846533, - 1641070431, - 1635292159, - 1372785527, - 1369818198, - 1204787336, - 1826456251, - 1164137269, - 1081642571, - 629859130, - 253329281, - 227103506, - 11698369, - 4219766939, - 4169226615, - 3997432565, - 3873587660, - 3513669836, - 3261122899, - 2129301998, - 1774052499, - 1266262705, - 4285201458, - 4245743275, - 3907920335, - 3837583704, - 3641833815, - 3307100165, - 1232501371, - 3262572726, - 3045470312, - 2879050471, - 2801333547, - 2506771164, - 2504802016, - 2500422644, - 2473053808, - 2457690657, - 2345566651, - 2306141594, - 2154320787, - 2055637638, - 1527762373, - 1486206763, - 1159301677, - 1105835505, - 968885186, - 885645401, - 849867303, - 815034111, - 497658126, - 386525753, - 179458548, - 102358168, - 4127308103, - 4073492988, - 1473411044, - 805072272, - 3724004880, - 3602108619, - 3585315836, - 3331487616, - 3261703164, - 3235459678, - 3085703811, - 3047649911, - 2357410109, - 2291766425, - 2071351379, - 1904128160, - 1738815671, - 1531216990, - 1465623797, - 1324351672, - 1220127364, - 1144188012, - 183103444, - 116093251, - 3900859293, - 3345856521, - 3691770462, - 3263841912, - 3198541202, - 3098991995, - 3682213068, - 2963184673, - 2864543087, - 2802261839, - 2790648021, - 900101778, - 2715304020, - 100979271, - 2709694527, - 2669086217, - 2531826164, - 2651956495, - 2552825357, - 2480811229, - 3138977758, - 2434845539, - 2066323109, - 1777640493, - 1758287856, - 1746004874, - 3945482286, - 3932146199, - 3129573055, - 3126269825, - 3716914380, - 985750227, - 1543672828, - 3189039115, - 1839499483, - 2696349144, - 1536350567, - 3971481069, - 3001444829, - 4028622909, - 215293834, - 213642219, - 153085016, - 1189681639, - 165054168, - 29517006, - 2614879967, - 27865391, - 1649426421, - 4239834800, - 1947620272, - 28782128, - 3207966516, - 3713290482, - 2042001863, - 2724166585, - 2356768706, - 1793544760, - 4092654294, - 2157103435, - 2087004702, - 2043873558, - 27177503, - 1033363654, - 4214779116, - 408465899, - 451264926, - 2377112119, - 1182296898, - 760554870, - 3566035349, - 2630220147, - 4192247221, - 1572088444, - 3538592682, - 769422756, - 1674803691, - 630964591, - 3458449569, - 565334834, - 137840602, - 3955205564, - 2009007457, - 1258105452, - 333554713, - 3923810593, - 126463145, - 3445109809, - 2966409025, - 2849215484, - 1910240213, - 3131890669, - 586244865, - 2320303498, - 3116932970, - 1317265040, - 2812498065, - 1466938734, - 4064212479, - 2613179511, - 2095546797, - 1671139745, - 2568512089, - 3695940604, - 1119069977, - 215027449, - 4123141705, - 3495546641, - 1978689945, - 3202324433, - 3783543823, - 2674422363, - 1352628475, - 1290956281, - 1894417995, - 740921498, - 4211577142, - 1033081852, - 3884846406, - 3253403867, - 2790624748, - 2538917932, - 2144962711, - 3323202731, - 4290024976, - 2564745684, - 2963744582, - 2443959748, - 354479447, - 750870327, - 1918481917, - 4032662899, - 3587381650, - 2414725163, - 1081611718, - 1625742020, - 2308565678, - 1871105284, - 2807907995, - 2121980967, - 1054641568, - 413918748, - 1917336504, - 1816558243, - 4130950286, - 1522979646, - 1669959736, - 1320550031, - 3104643263, - 3823959661, - 3525913657, - 3584683259, - 2918750759, - 3536390697, - 94303122, - 3296691317, - 801484894, - 2496463830, - 3266028549, - 3085157904, - 973908139, - 3787909072, - 3107413701, - 2378763734, - 920604853, - 2516325050, - 1838993983, - 1603937321, - 3183924418, - 1945006185, - 3982311384, - 2682510803, - 680388473, - 979993429, - 2405770322, - 461040879, - 2817579280, - 14113753, - 2894979602, - 168339452, - 951841533, - 4154758669, - 2637132451, - 3877583949, - 1949856502, - 922996215, - 3941049054, - 4182141402, - 2262220987, - 1957218950, - 2094550054, - 1846856260, - 3499234137, - 3086631065, - 3054834317, - 593829839, - 522971108, - 1162127370, - 4233562270, - 2780190687, - 1558345254, - 3716353056, - 3518630848, - 1158929937, - 2038205856, - 86116519, - 4185661467, - 975807626, - 3910458990, - 4124281183, - 3361419439, - 171334650, - 2590402790, - 2890570341, - 2303184249, - 385229009, - 1998433745, - 1717510093, - 4022124023, - 1429389803, - 945128292, - 904486530, - 3869890846, - 619875033, - 459968607, - 3743748793, - 359054425, - 1417363940, - 3653985133, - 255835594, - 1047011733, - 2763232252, - 1329499601, - 328661377, - 2162274327, - 2100532220, - 4255182614, - 4243119782, - 3982047273, - 4053789056, - 401211099, - 950731750, - 1319785741, - 32085358, - 3882634684, - 3117071189, - 3554463148, - 3570219049, - 3535289452, - 2314864456, - 3913885196, - 2763960513, - 1079999262, - 27130513, - 3033873113, - 2976581453, - 2598189097, - 595410904, - 1572834111, - 13319433, - 1084574846, - 2123388694, - 560078433, - 1679946323, - 3518703473, - 184634770, - 296981500, - 1646147798, - 455591063, - 1325348861, - 3224952074, - 1027242654, - 2281956980, - 4221373527, - 1289566249, - 4044928561, - 882718761, - 1510333659, - 836581417, - 1901166356, - 2276405827, - 4052965752, - 1155765244, - 503145996, - 251209228, - 495107308, - 3944781937, - 37459569, - 4248015868, - 4198082194, - 1302400505, - 4106658327, - 680016782, - 2319227476, - 2738307068, - 3929248764, - 2850246066, - 1824526196, - 3912967080, - 3044723416, - 3133016299, - 2517964682, - 3647586740, - 3653838348, - 929101967, - 3571454885, - 2806296851, - 977312655, - 646282397, - 3448018532, - 824323032, - 204234270, - 1579585816, - 3712763835, - 1212872174, - 3953984401, - 3168953855, - 2944827576, - 1582841441, - 2796901051, - 3323682385, - 1317058015, - 2557550659, - 1620634991, - 2986830770, - 2490492987, - 1817271123, - 40653745, - 1696076631, - 2466126792, - 4169878842, - 3251128023, - 2444465148, - 678695941, - 2481746922, - 2836440943, - 774727851, - 2246405597, - 4028028350, - 2524697596, - 1977038330, - 2817823941, - 2219733501, - 688216667, - 3634598908, - 3232633974, - 2724625059, - 3269075805, - 3732640764, - 2263349224, - 1680746207, - 2414984922, - 2507457870, - 50998433, - 3092528578, - 3712946115, - 1543935193, - 807276090, - 1221183390, - 172029722, - 2122275289, - 3990925720, - 2261697609, - 2736881867, - 295017943, - 3278176820, - 3748965853, - 3174324790, - 1103903216, - 3184177968, - 1113409935, - 2299842241, - 2162986400, - 1538342947, - 4056442905, - 1631434666, - 205885885, - 1594733696, - 1955104493, - 1022309772, - 3820814597, - 993150979, - 1209418480, - 1784441183, - 3958731802, - 2250225826, - 3065160070, - 2024071551, - 107497541, - 628544021, - 2732195517, - 4241486415, - 3969279737, - 870594305, - 2916400082, - 1193734351, - 3202349435, - 3831290364, - 3282979782, - 3928764629, - 1308462133, - 3216471040, - 2433519008, - 2022961611, - 3604842236, - 3374978006, - 2855895374, - 3496407048, - 1482251215, - 3994511488, - 2997832431, - 1132589448, - 1348149915, - 2092468906, - 2451531615, - 779021139, - 3730093054, - 3413713311, - 1022915255, - 2204920111, - 2660843182, - 1080545747, - 1642805350, - 1766422419, - 4141567741, - 1558990974, - 4185590212, - 2841468319, - 701281393, - 3325419312, - 451957774, - 357505993, - 1156369516, - 3187387500, - 2259467579, - 2678954464, - 3154597438, - 543558236, - 2359973133, - 1990431740, - 2705477184, - 1041368449, - 3122368657, - 3181646225, - 1094423548, - 2955375511, - 2888125966, - 153013225, - 2936040203, - 1758530522, - 573901046, - 3030911670, - 1675922848, - 4235213885, - 4091916710, - 2633682514, - 4254584852, - 2328748202, - 3357301402, - 3877813395, - 2004567202, - 2496297824, - 3334207724, - 1600149091, - 293528591, - 1782996825, - 3757282300, - 1107206446, - 1092948665, - 1797960910, - 1206726575, - 1496351055, - 3021406120, - 99347751, - 3797204453, - 1468919488, - 797415788, - 1314843976, - 2934934694, - 490769168, - 1474506522, - 3811268385, - 864295921, - 3081676220, - 151810803, - 2588618056, - 2998120306, - 416853049, - 3495967422, - 3233393284, - 508007510, - 759277550, - 1971252067, - 869050696, - 810488476, - 745556697, - 789872778, - 3362723943, - 1617826947, - 3260309823, - 2197904616, - 1199157863, - 1643868273, - 2430404313, - 321630747, - 2503194620, - 3194725903, - 2881225774, - 3997952447, - 1389644742, - 2713718873, - 3585511591, - 1684282922, - 3366848728, - 284226441, - 1541020250, - 4018237905, - 1369578001, - 2424848261, - 2654325647, - 1626224034, - 1081536219, - 309040124, - 123060826, - 3997038726, - 1670691893, - 1543280290, - 443347828, - 1776629361, - 3118548424, - 478440524, - 679771963, - 3729929345, - 4244789645, - 2366506734, - 2838165089, - 1619778288, - 1313182965, - 3240680626, - 1323407757, - 883854656, - 2194691858, - 15502752, - 3760372982, - 1366337101, - 3656163446, - 295018543, - 825595257, - 57149555, - 2563789125, - 2353194283, - 2636942752, - 4026740269, - 3570411982, - 123108003, - 3782362128, - 1280126114, - 1410849099, - 4228502127, - 3609540589, - 3365041621, - 269823086, - 348988933, - 1636389511, - 2936586309, - 2761603302, - 2318200267, - 449954059, - 2895413148, - 1755165354, - 4274214049, - 778500192, - 3345707173, - 3732136051, - 721450866, - 1600392975, - 2466255445, - 4050155669, - 3541895912, - 1139547465, - 394654115, - 1380991098, - 3516240523, - 2234361374, - 1094817798, - 744817486, - 3564402361, - 1452222566, - 1851510470, - 3619787319, - 4265894873, - 216945449, - 3061690214, - 2910557180, - 255227811, - 4167600590, - 1587209598, - 3157581152, - 3184381405, - 2572638469, - 615748604, - 2532518896, - 1774874546, - 599185303, - 1561718045, - 1742737136, - 1674464100, - 3136865519, - 706016261, - 2793529873, - 3504981554, - 4155122613, - 2080953106, - 1104362365, - 2879917501, - 850497536, - 1392080469, - 1287937401, - 718877177, - 1917966999, - 1822823090, - 3701632935, - 3591222197, - 2817335337, - 1941148668, - 3110479131, - 3289213933, - 583624926, - 468372467, - 1633850097, - 2110223508, - 898191441, - 112745085, - 4018820793, - 3085119011, - 2919626325, - 3094857332, - 2348201466, - 2192810893, - 4163160985, - 1269075360, - 3952316364, - 2881886868, - 439764402, - 1584774136, - 169674806, - 3759072440, - 102542696, - 2996180816, - 804899022, - 1015552308, - 963902061, - 3504158761, - 2002490364, - 2806716850, - 265778447, - 4083122425, - 181902171, - 1238120570, - 75986790, - 1265796414, - 899570100, - 2988365258, - 3655201337, - 3654061472, - 3061856840, - 1077859090, - 615341051, - 3678875745, - 3349230696, - 3647606635, - 2549309392, - 1508570930, - 1766401548, - 1448448666, - 1499923635, - 2882994691, - 3674863070, - 3056042030, - 4240893633, - 1395113939, - 2964622752, - 1951208733, - 3536941067, - 4176581069, - 1203545131, - 3092754101, - 246375791, - 2736026107, - 1069781886, - 3687777340, - 1564342316, - 535067202, - 1395923345, - 3240977890, - 1447712361, - 2602027658, - 718301639, - 3123244280, - 1032593647, - 2840366496, - 2680819379, - 3839389658, - 277023757, - 1172110445, - 1755648697, - 2472176885, - 223800276, - 625975427, - 976111724, - 4145966869, - 2789375411, - 618087261, - 249378857, - 4058280485, - 827698488, - 1558001705, - 3561482820, - 2562485583, - 4243138030, - 615982737, - 1220643281, - 150685616, - 3091876332, - 1040775722, - 669982125, - 4116080964, - 3582002820, - 910398460, - 1036475267, - 3800912395, - 146392076, - 1686512349, - 2326636627, - 2839816704, - 3502816184, - 226836633, - 3953733490, - 257136089, - 819503463, - 2863084840, - 1949759310, - 210754155, - 1367301635, - 3822983876, - 4273793488, - 3635397748, - 3930494584, - 3127921440, - 3167253437, - 3868239231, - 1859128680, - 3480031018, - 3810805277, - 2677252364, - 156014509, - 3627739127, - 2321729979, - 1146476634, - 4039938779, - 1964254745, - 2055836767, - 119981689, - 2629265310, - 2448331885, - 3737376990, - 144116905, - 2272221101, - 2197874825, - 1277245109, - 2503770904, - 360730278, - 3489360962, - 1166917451, - 707478563, - 4155586396, - 162255877, - 347505241, - 4215670524, - 3187066832, - 2399809085, - 2754074729, - 4060703604, - 628331516, - 1304296041, - 616435646, - 4080527786, - 1443829854, - 2512398201, - 708736129, - 13107491, - 3794803132, - 2049792025, - 2455417440, - 3367313400, - 3357250579, - 3694383800, - 2339901602, - 3242843022, - 2282454607, - 1243764146, - 835458563, - 1297706389, - 464259778, - 1766994680, - 1294403159, - 2568098594, - 3107165180, - 4040340620, - 3352361837, - 1031290113, - 2903897222, - 1677700667, - 3160388974, - 107544081, - 3044188332, - 2285081596, - 2835131395, - 2984459037, - 4174489262, - 1236389532, - 2938237924, - 321459212, - 3407526215, - 300939750, - 3441531391, - 2909957084, - 3192069648, - 1849065716, - 2524531022, - 505940164, - 4121643374, - 3774892253, - 3197739982, - 2161102232, - 2715370488, - 1992893964, - 1781864804, - 587888644, - 1039111164, - 4237497041, - 451382997, - 969500141, - 1415510495, - 3743398113, - 3027538652, - 2525173102, - 1708264968, - 3366040354, - 1100599986, - 188347929, - 2597020383, - 2705434194, - 2593884753, - 3472123498, - 2975894973, - 3152745753, - 1154919607, - 1930923350, - 3287039847, - 1372881231, - 2280400314, - 3369343584, - 2351620600, - 2645135839, - 2752766693, - 1471851763, - 1989520052, - 1141965917, - 1503477720, - 653708953, - 1765126703, - 2432827426, - 95470391, - 2567901801, - 2589449658, - 4218799564, - 3249265647, - 3673811979, - 210116709, - 1593584949, - 1791352211, - 3457985288, - 3345288309, - 531559080, - 2491124112, - 3410158390, - 4224872590, - 3705139860, - 162608772, - 4258229445, - 925559698, - 3928842969, - 4253051659, - 3633746133, - 3867307935, - 3560665067, - 798915737, - 2945369269, - 2677264274, - 2278571792, - 177111659, - 85880059, - 1297165140, - 1630583316, - 2232491275, - 1848784182, - 2487708241, - 626480004, - 3427283542, - 2108571893, - 304448521, - 3332104493, - 2244470522, - 436416061, - 221900294, - 1502470404, - 3552593177, - 440421571, - 450406196, - 503094540, - 3836822275, - 2708915136, - 3750617468, - 1119744229, - 3614752756, - 921246433, - 2285438321, - 626892406, - 2362972044, - 72782198, - 2929019254, - 2795773560, - 907126242, - 155458798, - 2798552666, - 1404739463, - 4285652249, - 1998444837, - 908777857, - 872544165, - 910429472, - 135486769, - 3457269042, - 426360862, - 1725011064, - 296836635, - 1322549027, - 2044728014, - 1530183840, - 529742207, - 4272200782, - 1341516288, - 2608484640, - 41739659, - 3260579369, - 2745872368, - 2894051250, - 862784766, - 3077271274, - 3094180193, - 3619626927, - 3745223676, - 2976066508, - 2854085372, - 2959147533, - 3266548732, - 1776526161, - 3712296962, - 1955871800, - 2580096524, - 2507709226, - 3564865233, - 948086521, - 1548254487, - 142465290, - 1472185378, - 1459457331, - 2274226560, - 3153451899, - 492958971, - 3563213618, - 1285705317, - 410274915, - 3710645347, - 1309728002, - 2119793999, - 1343794461, - 4024173916, - 2383939514, - 955476870, - 2698156268, - 35240468, - 2655147757, - 3764205609, - 3802564010, - 170690025, - 2311941439, - 3181546731, - 3866587616, - 3648138580, - 93914936, - 170378107, - 2120623674, - 1064945649, - 1618754372, - 244668133, - 247698428, - 3669223677, - 470277359, - 1781765116, - 1691572958, - 1373856501, - 2668769415, - 1087394637, - 1009983433, - 2180701723, - 4008405264, - 2831059514, - 2645120714, - 2649103430, - 2664825925, - 790502615, - 1739837626, - 2293247016, - 1784648440, - 1887808856, - 1788504755, - 112452386, - 1979978194, - 3462674048, - 2170273742, - 538168945, - 753954113, - 374731234, - 3715846592, - 1962971231, - 1860649552, - 1378082995, - 665789406, - 1717555224, - 139011596, - 1375043498, - 1618544981, - 1889460471, - 2262321736, - 1788301425, - 1652168174, - 2668680621, - 2636946065, - 2856623532, - 2759951687, - 959681532, - 3209399506, - 3055195668, - 1227221002, - 508217552, - 3289969989, - 243178923, - 2956189845, - 3075866530, - 2274779301, - 3940720663, - 3998230222, - 1178317551, - 4016096296, - 1545450160, - 2842919847, - 314809953, - 2952850186, - 3747079365, - 4147239510, - 169135842, - 1332643570, - 2994529201, - 973521782, - 1584369690, - 1043738701, - 2851900832, - 290391815, - 283209196, - 2468230023, - 1164221089, - 1991787192, - 3358097187, - 51041423, - 52882140, - 2339018837, - 2053214130, - 3757479030, - 158160339, - 853200279, - 1986584654, - 438318340, - 827246872, - 3299488628, - 2924263085, - 3472029049, - 2736844435, - 677668732, - 604894932, - 1158021131, - 1400019344, - 2268204687, - 1450415100, - 3854557817, - 1543646433, - 1278448636, - 342615870, - 1554194368, - 3080024605, - 3423702268, - 1675764636, - 1622381564, - 2078849875, - 2113115132, - 1380160211, - 3132876285, - 125015036, - 269576093, - 94145952, - 2777172031, - 2683080096, - 3812456892, - 488500848, - 3270430997, - 2895151306, - 116376005, - 400248103, - 406044930, - 1616846013, - 10142671, - 763027711, - 225200779, - 1062250709, - 2013867381, - 2113506324, - 1692932387, - 1827244161, - 3124618210, - 2096472894, - 2924146124, - 2128251367, - 2433358586, - 1939359710, - 2593325766, - 2879917723, - 694743357, - 2902069960, - 220008971, - 3090408469, - 917019124, - 1705716306, - 3263901372, - 3347863687, - 3447882276, - 1661163736, - 3617689692, - 3928555688, - 1057578789, - 435256475, - 4101009465, - 1941403425, - 198967948, - 3733675151, - 2043684541, - 3517169445, - 2226776400, - 2853403709, - 529383565, - 2807448986, - 4234287173, - 1019457583, - 1022544883, - 2493146691, - 1054461787, - 1008886329, - 1136775085, - 1191015885, - 1196280518, - 1979847999, - 50385656, - 1918742169, - 3999472204, - 3697687030, - 2220475432, - 2358141757, - 2360004627, - 4245257809, - 236660303, - 429277936, - 342159236, - 2622612602, - 371428004, - 373079619, - 643418617, - 2095027856, - 1071164424, - 1136911283, - 1548491889, - 2169307971, - 375530199, - 1510422521, - 3151638847, - 1698730948, - 2231688008, - 2604576561, - 2771938750, - 2996594997, - 289648234, - 348584153, - 2748350697, - 2926633629, - 2123683379, - 369686787, - 742917749, - 3538158875, - 2937761472, - 1545298048, - 1321616112, - 2855506940, - 900522183, - 1578775276, - 2217833278, - 2012838864, - 3753486980, - 2839765116, - 2464905186, - 2621255555, - 1305703280, - 861753115, - 3319278167, - 3063300848, - 149720480, - 1082941229, - 3337532056, - 2248357849, - 3675926744, - 1508550646, - 2289803479, - 3456899824, - 3931641900, - 3970432934, - 3419674548, - 1093210099, - 456043370, - 848380423, - 1287304304, - 1526654696, - 2055664760, - 1373166395, - 4291477370, - 2195550588, - 2847102741, - 3399062057, - 1641565587, - 2888753905, - 3579593979, - 3653059026, - 3757851979, - 2922615804, - 2919796598, - 1553476262, - 2566666743, - 3759503594, - 550831114, - 3761155209, - 3762806824, - 3902853271, - 4140081844, - 14244860, - 3847846774, - 150820676, - 1278818058, - 850592577, - 1206571206, - 1734446471, - 2117320444, - 1382106590, - 2436009347, - 2118972059, - 2951272396, - 36096192, - 117998987, - 473485679, - 2244928358, - 476788909, - 3489269251, - 610429940, - 480092139, - 481743754, - 871966503, - 918189168, - 601656217, - 933769938, - 939671928, - 1799299383, - 3312467582, - 1149665466, - 3006548167, - 1310740861, - 3602693817, - 1461645203, - 3367691969, - 1800404122, - 3486057732, - 1862284649, - 2076833303, - 2213411495, - 2805256437, - 3927915220, - 3000904950, - 2094647776, - 3333131702, - 1315613425, - 3752211294, - 603915804, - 3505028338, - 663258455, - 3322500634, - 1612225949, - 3606320646, - 157110413, - 1352397672, - 3861006967, - 452208841, - 18776483, - 1058429216, - 37009196, - 564884461, - 876864198, - 2952260510, - 2860348412, - 928261291, - 1164724902, - 2775815164, - 1332774287, - 780957373, - 939415664, - 1513770932, - 788046331, - 1692600167, - 4069810315, - 673708384, - 4024252457, - 1932614728, - 2148510256, - 3131224670, - 2388524817, - 2460489993, - 2676385521, - 826214242, - 3692647551, - 3063508455, - 3071766530, - 2063832060, - 1525861001, - 3073418145, - 837715723, - 3075069760, - 3076721375, - 3078372990, - 983243705, - 3083327835, - 171307615, - 1824016656, - 3084979450, - 1310404265, - 1775308984, - 3114708520, - 3116360135, - 3121314980, - 3134527900, - 1691646294, - 2804281092, - 97231530, - 3136179515, - 3204260786, - 3276225962, - 1220749418, - 3588205699, - 3874089391, - 4044115788, - 3268751013, - 743407979, - 166253838, - 1356063462, - 1368383673, - 2279700640, - 2130747644, - 3945795573, - 2780898906, - 3635542517, - 425022309, - 517919178, - 4061558677, - 2190437442, - 543621065, - 753756604, - 2500819054, - 1004589179, - 1165671422, - 30433743, - 3444275347, - 1335363438, - 1913735398, - 1265998516, - 3829325073, - 3662767579, - 463084678, - 1351676723, - 1391866096, - 3398925952, - 1631216488, - 815757910, - 1915438939, - 2427834344, - 1445161581, - 1890300748, - 2864863800, - 1961990747, - 575205902, - 2037710159, - 2037814253, - 617312262, - 3732916270, - 783918780, - 2257843797, - 2096388952, - 2338272340, - 1434223270, - 578132535, - 1980341560, - 1002144380, - 3244716568, - 4258414038, - 3271748023, - 3304438238, - 3717523241, - 3370185097, - 3435931956, - 1957265068, - 3602522282, - 2547657777, - 439998433, - 3838648480, - 3913593633, - 3989799199, - 906176560, - 1894133125, - 4046301857, - 4242327928, - 630592085, - 2693892518, - 4292991777, - 545678922, - 125792961, - 3015046341, - 132755933, - 2615111110, - 1570165302, - 1440646342, - 436066778, - 565233904, - 600906020, - 602222721, - 3951925872, - 1496901698, - 1522901980, - 2785441472, - 3041450802, - 1637661947, - 2127660080, - 3487022798, - 2269114589, - 1314834580, - 2315690100, - 3817149113, - 4091670162, - 1431749301, - 1858116930, - 2213946343, - 2225172640, - 2263866576, - 2727022058, - 2752967311, - 2864705739, - 3052439312, - 3510257966, - 2614053317, - 3297860332, - 3670298840, - 3732709413, - 3788324110, - 4098876453, - 4290374884, - 1623013158, - 3381478137, - 17185761, - 3931288033, - 2890638791, - 330388453, - 346929928, - 2022347217, - 4083347580, - 533021259, - 564302770, - 1917602962, - 680157484, - 3264086791, - 3727034815, - 798549062, - 3068463300, - 669812542, - 1965902997, - 2311072371, - 3079287749, - 2542834724, - 1587730355, - 2558655180, - 1838763297, - 4172568578, - 2160380860, - 2950446516, - 1830851200, - 3214537066, - 3234673086, - 3652695478, - 3103302036, - 3465954368, - 4180570743, - 3534518722, - 371186900, - 4091394002, - 1013756921, - 443558693, - 591140762, - 656610661, - 2064733527, - 3808408202, - 983299427, - 4217306348, - 1164218401, - 2036361232, - 3237903670, - 2970183398, - 2293637521, - 135920445, - 1596005536, - 868652905, - 1191735827, - 3987079331, - 1365842164, - 1508074873, - 1642818143, - 3436143898, - 4105051793, - 1863199739, - 3425841570, - 1070791291, - 2135340676, - 2639720559, - 3364388739, - 3797761273, - 2092100514, - 2098706974, - 2329992200, - 414444763, - 2759250216, - 2913136690, - 3012980338, - 3327770644, - 4128942283, - 3362344229, - 161668409, - 3401762422, - 2852854788, - 4237092412, - 1245448751, - 3702405475, - 918849409, - 3829682756, - 1612361408, - 255302575, - 414620710, - 386293029, - 618761615, - 686024761, - 744062262, - 1502028603, - 1543798545, - 1641415225, - 1548121999, - 2257971049, - 2124837447, - 878733439, - 2340670452, - 2674090849, - 3118011750, - 2816338013, - 178571546, - 2841008029, - 3249261197, - 370232173, - 4092487128, - 3787567939, - 3898287302, - 4142016703, - 4285779501, - 30663912, - 151672195, - 180913835, - 3534235309, - 34183582, - 4083161638, - 651464351, - 1410311776, - 371621315, - 421602934, - 458937500, - 2710583246, - 712168842, - 730943059, - 1519723107, - 875212982, - 1247793383, - 4217322139, - 989813600, - 1057606514, - 3764662384, - 1443547269, - 3066811685, - 3598957382, - 1791427568, - 1171541710, - 3930727258, - 1473799048, - 1296054774, - 1747355813, - 765238787, - 2023008475, - 1190147516, - 2344328209, - 2495155989, - 2577859137, - 2857814560, - 3127329373, - 3296722158, - 2773229577, - 3376009661, - 3450001968, - 920941800, - 3526837441, - 3858973601, - 1702168830, - 4088613871, - 1464587427, - 223310468, - 388034151, - 2346547796, - 1663234329, - 1750829822, - 1967643923, - 2881302403, - 2278706468, - 2326990117, - 2511346984, - 3088785099, - 2616085763, - 3027500544, - 3417583519, - 4178218543, - 1412908157, - 797934924, - 3533637837, - 1449907751, - 3362830643, - 1451831482, - 2637935122, - 3070114915, - 3023287679, - 551924251, - 1669930486, - 46736908, - 2870852215, - 1120149824, - 2923708820, - 3887377256, - 3464197236, - 4241374559, - 527665290, - 996663016, - 885020215, - 1763758554, - 3059119137, - 2555315060, - 2762094724, - 2530899578, - 2770161927, - 2262137600, - 3547456240, - 858902117, - 1140367371, - 1215030156, - 443490822, - 294390719, - 3032677281, - 1917451875, - 4184019303, - 3277199633, - 1271484400, - 1297294717, - 3560552546, - 171494987, - 195244192, - 3002890475, - 1811839150, - 265392489, - 1461398554, - 3205759417, - 333855951, - 529068443, - 660038281, - 557400685, - 663341511, - 930804377, - 1922045399, - 716890919, - 162167595, - 1654776395, - 1779143013, - 1123617794, - 2984325996, - 1162789888, - 1318479490, - 1235468610, - 3561562003, - 1486207619, - 1551372768, - 1850331254, - 3255947500, - 1037370721, - 1989327599, - 2137526937, - 835638766, - 2269130237, - 1962162282, - 3244209297, - 2330636993, - 3095831808, - 1396344138, - 2603020391, - 3434076295, - 3280064277, - 2656211099, - 3335250889, - 2550961007, - 3510242586, - 3536471583, - 3950980241, - 4033586023, - 117250846, - 3088282680, - 4041974454, - 4244540017, - 1167160774, - 899320334, - 1200870684, - 1752686878, - 1906988301, - 3804101227, - 2575525651, - 2919787747, - 3508792859, - 3548535223, - 3783756895, - 3797961332, - 4043078107, - 3115038057, - 2313593054, - 49456560, - 592180731, - 1051471757, - 1097775533, - 706238670, - 877895868, - 1173092699, - 1461897718, - 1767704813, - 1770165905, - 1923453688, - 2212501241, - 2305269460, - 2488410748, - 3782099915, - 2844616706, - 3383007207, - 3392887901, - 504514034, - 3765247327, - 1000070091, - 3727494858, - 3657635382, - 3839047923, - 3886529747, - 4069720347, - 4164704452, - 342197850, - 3540244297, - 2513230733, - 4117704995, - 3367298820, - 2680283743, - 3119663365, - 3697738938, - 545363837, - 163402553, - 5908395, - 129135650, - 2289183712, - 200922300, - 761731755, - 894529125, - 1086964761, - 1168927492, - 2100052708, - 2438466459, - 3390051757, - 2498042266, - 2557754096, - 2600961503, - 487719832, - 703543228, - 2726532092, - 4199470013, - 3142155593, - 2550501832, - 4076840151, - 200553094, - 380957745, - 572905105, - 462664429, - 1466804584, - 330249537, - 2605012269, - 491456522, - 4126287524, - 502863753, - 952536201, - 3510682541, - 1137442027, - 1665981878, - 1761469971, - 3085467405, - 2045285083, - 796985462, - 3433956341, - 2217966239, - 2183547611, - 2279273489, - 1916983087, - 2348676810, - 2403632109, - 2409539315, - 545986953, - 176166202, - 2477389837, - 2573160348, - 2796513469, - 3972309363, - 528662843, - 1038982109, - 1125913837, - 1318081294, - 1417425499, - }; - return descriptors_with_coding_scheme; -} diff --git a/third_party/spirv-tools/tools/dis/dis.cpp b/third_party/spirv-tools/tools/dis/dis.cpp index 6a2e269327..c0ce267d11 100644 --- a/third_party/spirv-tools/tools/dis/dis.cpp +++ b/third_party/spirv-tools/tools/dis/dis.cpp @@ -60,7 +60,7 @@ Options: argv0, argv0); } -static const auto kDefaultEnvironment = SPV_ENV_UNIVERSAL_1_3; +static const auto kDefaultEnvironment = SPV_ENV_UNIVERSAL_1_5; int main(int argc, char** argv) { const char* inFile = nullptr; diff --git a/third_party/spirv-tools/tools/fuzz/fuzz.cpp b/third_party/spirv-tools/tools/fuzz/fuzz.cpp new file mode 100644 index 0000000000..718d038a80 --- /dev/null +++ b/third_party/spirv-tools/tools/fuzz/fuzz.cpp @@ -0,0 +1,636 @@ +// Copyright (c) 2019 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 +#include +#include +#include +#include +#include +#include +#include + +#include "source/fuzz/force_render_red.h" +#include "source/fuzz/fuzzer.h" +#include "source/fuzz/fuzzer_util.h" +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "source/fuzz/replayer.h" +#include "source/fuzz/shrinker.h" +#include "source/opt/build_module.h" +#include "source/opt/ir_context.h" +#include "source/opt/log.h" +#include "source/spirv_fuzzer_options.h" +#include "source/util/string_utils.h" +#include "tools/io.h" +#include "tools/util/cli_consumer.h" + +namespace { + +// Check that the std::system function can actually be used. +bool CheckExecuteCommand() { + int res = std::system(nullptr); + return res != 0; +} + +// Execute a command using the shell. +// Returns true if and only if the command's exit status was 0. +bool ExecuteCommand(const std::string& command) { + errno = 0; + int status = std::system(command.c_str()); + assert(errno == 0 && "failed to execute command"); + // The result returned by 'system' is implementation-defined, but is + // usually the case that the returned value is 0 when the command's exit + // code was 0. We are assuming that here, and that's all we depend on. + return status == 0; +} + +// Status and actions to perform after parsing command-line arguments. +enum class FuzzActions { + FORCE_RENDER_RED, // Turn the shader into a form such that it is guaranteed + // to render a red image. + FUZZ, // Run the fuzzer to apply transformations in a randomized fashion. + REPLAY, // Replay an existing sequence of transformations. + SHRINK, // Shrink an existing sequence of transformations with respect to an + // interestingness function. + STOP // Do nothing. +}; + +struct FuzzStatus { + FuzzActions action; + int code; +}; + +void PrintUsage(const char* program) { + // NOTE: Please maintain flags in lexicographical order. + printf( + R"(%s - Fuzzes an equivalent SPIR-V binary based on a given binary. + +USAGE: %s [options] -o \ + --donors= +USAGE: %s [options] -o \ + --shrink= -- [args...] + +The SPIR-V binary is read from . If is also present, +facts about the SPIR-V binary are read from this file. + +The transformed SPIR-V binary is written to . Human-readable and +binary representations of the transformations that were applied are written to + and , respectively. + +When passing --shrink= an +must also be provided; this is the path to a script that returns 0 if and only +if a given SPIR-V binary is interesting. The SPIR-V binary will be passed to +the script as an argument after any other provided arguments [args...]. The +"--" characters are optional but denote that all arguments that follow are +positional arguments and thus will be forwarded to the interestingness script, +and not parsed by %s. + +NOTE: The fuzzer is a work in progress. + +Options (in lexicographical order): + + -h, --help + Print this help. + --donors= + File specifying a series of donor files, one per line. Must be + provided if the tool is invoked in fuzzing mode; incompatible + with replay and shrink modes. The file should be empty if no + donors are to be used. + --force-render-red + Transforms the input shader into a shader that writes red to the + output buffer, and then captures the original shader as the body + of a conditional with a dynamically false guard. Exploits input + facts to make the guard non-obviously false. This option is a + helper for massaging crash-inducing tests into a runnable + format; it does not perform any fuzzing. + --fuzzer-pass-validation + Run the validator after applying each fuzzer pass during + fuzzing. Aborts fuzzing early if an invalid binary is created. + Useful for debugging spirv-fuzz. + --replay + File from which to read a sequence of transformations to replay + (instead of fuzzing) + --seed= + Unsigned 32-bit integer seed to control random number + generation. + --shrink= + File from which to read a sequence of transformations to shrink + (instead of fuzzing) + --shrinker-step-limit= + Unsigned 32-bit integer specifying maximum number of steps the + shrinker will take before giving up. Ignored unless --shrink + is used. + --shrinker-temp-file-prefix= + Specifies a temporary file prefix that will be used to output + temporary shader files during shrinking. A number and .spv + extension will be added. The default is "temp_", which will + cause files like "temp_0001.spv" to be output to the current + directory. Ignored unless --shrink is used. + --replay-validation + Run the validator after applying each transformation during + replay (including the replay that occurs during shrinking). + Aborts if an invalid binary is created. Useful for debugging + spirv-fuzz. + --version + Display fuzzer version information. + +)", + program, program, program, program); +} + +// Message consumer for this tool. Used to emit diagnostics during +// initialization and setup. Note that |source| and |position| are irrelevant +// here because we are still not processing a SPIR-V input file. +void FuzzDiagnostic(spv_message_level_t level, const char* /*source*/, + const spv_position_t& /*position*/, const char* message) { + if (level == SPV_MSG_ERROR) { + fprintf(stderr, "error: "); + } + fprintf(stderr, "%s\n", message); +} + +FuzzStatus ParseFlags(int argc, const char** argv, std::string* in_binary_file, + std::string* out_binary_file, std::string* donors_file, + std::string* replay_transformations_file, + std::vector* interestingness_test, + std::string* shrink_transformations_file, + std::string* shrink_temp_file_prefix, + spvtools::FuzzerOptions* fuzzer_options) { + uint32_t positional_arg_index = 0; + bool only_positional_arguments_remain = false; + bool force_render_red = false; + + for (int argi = 1; argi < argc; ++argi) { + const char* cur_arg = argv[argi]; + if ('-' == cur_arg[0] && !only_positional_arguments_remain) { + if (0 == strcmp(cur_arg, "--version")) { + spvtools::Logf(FuzzDiagnostic, SPV_MSG_INFO, nullptr, {}, "%s\n", + spvSoftwareVersionDetailsString()); + return {FuzzActions::STOP, 0}; + } else if (0 == strcmp(cur_arg, "--help") || 0 == strcmp(cur_arg, "-h")) { + PrintUsage(argv[0]); + return {FuzzActions::STOP, 0}; + } else if (0 == strcmp(cur_arg, "-o")) { + if (out_binary_file->empty() && argi + 1 < argc) { + *out_binary_file = std::string(argv[++argi]); + } else { + PrintUsage(argv[0]); + return {FuzzActions::STOP, 1}; + } + } else if (0 == strncmp(cur_arg, "--donors=", sizeof("--donors=") - 1)) { + const auto split_flag = spvtools::utils::SplitFlagArgs(cur_arg); + *donors_file = std::string(split_flag.second); + } else if (0 == strncmp(cur_arg, "--force-render-red", + sizeof("--force-render-red") - 1)) { + force_render_red = true; + } else if (0 == strncmp(cur_arg, "--fuzzer-pass-validation", + sizeof("--fuzzer-pass-validation") - 1)) { + fuzzer_options->enable_fuzzer_pass_validation(); + } else if (0 == strncmp(cur_arg, "--replay=", sizeof("--replay=") - 1)) { + const auto split_flag = spvtools::utils::SplitFlagArgs(cur_arg); + *replay_transformations_file = std::string(split_flag.second); + } else if (0 == strncmp(cur_arg, "--replay-validation", + sizeof("--replay-validation") - 1)) { + fuzzer_options->enable_replay_validation(); + } else if (0 == strncmp(cur_arg, "--shrink=", sizeof("--shrink=") - 1)) { + const auto split_flag = spvtools::utils::SplitFlagArgs(cur_arg); + *shrink_transformations_file = std::string(split_flag.second); + } else if (0 == strncmp(cur_arg, "--seed=", sizeof("--seed=") - 1)) { + const auto split_flag = spvtools::utils::SplitFlagArgs(cur_arg); + char* end = nullptr; + errno = 0; + const auto seed = + static_cast(strtol(split_flag.second.c_str(), &end, 10)); + assert(end != split_flag.second.c_str() && errno == 0); + fuzzer_options->set_random_seed(seed); + } else if (0 == strncmp(cur_arg, "--shrinker-step-limit=", + sizeof("--shrinker-step-limit=") - 1)) { + const auto split_flag = spvtools::utils::SplitFlagArgs(cur_arg); + char* end = nullptr; + errno = 0; + const auto step_limit = + static_cast(strtol(split_flag.second.c_str(), &end, 10)); + assert(end != split_flag.second.c_str() && errno == 0); + fuzzer_options->set_shrinker_step_limit(step_limit); + } else if (0 == strncmp(cur_arg, "--shrinker-temp-file-prefix=", + sizeof("--shrinker-temp-file-prefix=") - 1)) { + const auto split_flag = spvtools::utils::SplitFlagArgs(cur_arg); + *shrink_temp_file_prefix = std::string(split_flag.second); + } else if (0 == strcmp(cur_arg, "--")) { + only_positional_arguments_remain = true; + } else { + std::stringstream ss; + ss << "Unrecognized argument: " << cur_arg << std::endl; + spvtools::Error(FuzzDiagnostic, nullptr, {}, ss.str().c_str()); + PrintUsage(argv[0]); + return {FuzzActions::STOP, 1}; + } + } else if (positional_arg_index == 0) { + // Binary input file name + assert(in_binary_file->empty()); + *in_binary_file = std::string(cur_arg); + positional_arg_index++; + } else { + interestingness_test->push_back(std::string(cur_arg)); + } + } + + if (in_binary_file->empty()) { + spvtools::Error(FuzzDiagnostic, nullptr, {}, "No input file specified"); + return {FuzzActions::STOP, 1}; + } + + if (out_binary_file->empty()) { + spvtools::Error(FuzzDiagnostic, nullptr, {}, "-o required"); + return {FuzzActions::STOP, 1}; + } + + auto const_fuzzer_options = + static_cast(*fuzzer_options); + if (force_render_red) { + if (!replay_transformations_file->empty() || + !shrink_transformations_file->empty() || + const_fuzzer_options->replay_validation_enabled) { + spvtools::Error(FuzzDiagnostic, nullptr, {}, + "The --force-render-red argument cannot be used with any " + "other arguments except -o."); + return {FuzzActions::STOP, 1}; + } + return {FuzzActions::FORCE_RENDER_RED, 0}; + } + + if (replay_transformations_file->empty() && + shrink_transformations_file->empty() && + static_cast(*fuzzer_options) + ->replay_validation_enabled) { + spvtools::Error(FuzzDiagnostic, nullptr, {}, + "The --replay-validation argument can only be used with " + "one of the --replay or --shrink arguments."); + return {FuzzActions::STOP, 1}; + } + + if (shrink_transformations_file->empty() && !interestingness_test->empty()) { + spvtools::Error(FuzzDiagnostic, nullptr, {}, + "Too many positional arguments specified; extra positional " + "arguments are used as the interestingness function, which " + "are only valid with the --shrink option."); + return {FuzzActions::STOP, 1}; + } + + if (!shrink_transformations_file->empty() && interestingness_test->empty()) { + spvtools::Error( + FuzzDiagnostic, nullptr, {}, + "The --shrink option requires an interestingness function."); + return {FuzzActions::STOP, 1}; + } + + if (!replay_transformations_file->empty() || + !shrink_transformations_file->empty()) { + // Donors should not be provided when replaying or shrinking: they only make + // sense during fuzzing. + if (!donors_file->empty()) { + spvtools::Error(FuzzDiagnostic, nullptr, {}, + "The --donors argument is not compatible with --replay " + "nor --shrink."); + return {FuzzActions::STOP, 1}; + } + } + + if (!replay_transformations_file->empty()) { + // A replay transformations file was given, thus the tool is being invoked + // in replay mode. + if (!shrink_transformations_file->empty()) { + spvtools::Error( + FuzzDiagnostic, nullptr, {}, + "The --replay and --shrink arguments are mutually exclusive."); + return {FuzzActions::STOP, 1}; + } + return {FuzzActions::REPLAY, 0}; + } + + if (!shrink_transformations_file->empty()) { + // The tool is being invoked in shrink mode. + assert(!interestingness_test->empty() && + "An error should have been raised if --shrink was provided without " + "an interestingness test."); + return {FuzzActions::SHRINK, 0}; + } + + // The tool is being invoked in fuzz mode. + if (donors_file->empty()) { + spvtools::Error(FuzzDiagnostic, nullptr, {}, + "Fuzzing requires that the --donors option is used."); + return {FuzzActions::STOP, 1}; + } + return {FuzzActions::FUZZ, 0}; +} + +bool ParseTransformations( + const std::string& transformations_file, + spvtools::fuzz::protobufs::TransformationSequence* transformations) { + std::ifstream transformations_stream; + transformations_stream.open(transformations_file, + std::ios::in | std::ios::binary); + auto parse_success = + transformations->ParseFromIstream(&transformations_stream); + transformations_stream.close(); + if (!parse_success) { + spvtools::Error(FuzzDiagnostic, nullptr, {}, + ("Error reading transformations from file '" + + transformations_file + "'") + .c_str()); + return false; + } + return true; +} + +bool Replay(const spv_target_env& target_env, + spv_const_fuzzer_options fuzzer_options, + const std::vector& binary_in, + const spvtools::fuzz::protobufs::FactSequence& initial_facts, + const std::string& replay_transformations_file, + std::vector* binary_out, + spvtools::fuzz::protobufs::TransformationSequence* + transformations_applied) { + spvtools::fuzz::protobufs::TransformationSequence transformation_sequence; + if (!ParseTransformations(replay_transformations_file, + &transformation_sequence)) { + return false; + } + spvtools::fuzz::Replayer replayer(target_env, + fuzzer_options->replay_validation_enabled); + replayer.SetMessageConsumer(spvtools::utils::CLIMessageConsumer); + auto replay_result_status = + replayer.Run(binary_in, initial_facts, transformation_sequence, + binary_out, transformations_applied); + return !(replay_result_status != + spvtools::fuzz::Replayer::ReplayerResultStatus::kComplete); +} + +bool Shrink(const spv_target_env& target_env, + spv_const_fuzzer_options fuzzer_options, + const std::vector& binary_in, + const spvtools::fuzz::protobufs::FactSequence& initial_facts, + const std::string& shrink_transformations_file, + const std::string& shrink_temp_file_prefix, + const std::vector& interestingness_command, + std::vector* binary_out, + spvtools::fuzz::protobufs::TransformationSequence* + transformations_applied) { + spvtools::fuzz::protobufs::TransformationSequence transformation_sequence; + if (!ParseTransformations(shrink_transformations_file, + &transformation_sequence)) { + return false; + } + spvtools::fuzz::Shrinker shrinker(target_env, + fuzzer_options->shrinker_step_limit, + fuzzer_options->replay_validation_enabled); + shrinker.SetMessageConsumer(spvtools::utils::CLIMessageConsumer); + + assert(!interestingness_command.empty() && + "An error should have been raised because the interestingness_command " + "is empty."); + std::stringstream joined; + joined << interestingness_command[0]; + for (size_t i = 1, size = interestingness_command.size(); i < size; ++i) { + joined << " " << interestingness_command[i]; + } + std::string interestingness_command_joined = joined.str(); + + spvtools::fuzz::Shrinker::InterestingnessFunction interestingness_function = + [interestingness_command_joined, shrink_temp_file_prefix]( + std::vector binary, uint32_t reductions_applied) -> bool { + std::stringstream ss; + ss << shrink_temp_file_prefix << std::setw(4) << std::setfill('0') + << reductions_applied << ".spv"; + const auto spv_file = ss.str(); + const std::string command = interestingness_command_joined + " " + spv_file; + auto write_file_succeeded = + WriteFile(spv_file.c_str(), "wb", &binary[0], binary.size()); + (void)(write_file_succeeded); + assert(write_file_succeeded); + return ExecuteCommand(command); + }; + + auto shrink_result_status = shrinker.Run( + binary_in, initial_facts, transformation_sequence, + interestingness_function, binary_out, transformations_applied); + return spvtools::fuzz::Shrinker::ShrinkerResultStatus::kComplete == + shrink_result_status || + spvtools::fuzz::Shrinker::ShrinkerResultStatus::kStepLimitReached == + shrink_result_status; +} + +bool Fuzz(const spv_target_env& target_env, + spv_const_fuzzer_options fuzzer_options, + const std::vector& binary_in, + const spvtools::fuzz::protobufs::FactSequence& initial_facts, + const std::string& donors, std::vector* binary_out, + spvtools::fuzz::protobufs::TransformationSequence* + transformations_applied) { + auto message_consumer = spvtools::utils::CLIMessageConsumer; + + std::vector donor_suppliers; + + std::ifstream donors_file(donors); + if (!donors_file) { + spvtools::Error(FuzzDiagnostic, nullptr, {}, "Error opening donors file"); + return false; + } + std::string donor_filename; + while (std::getline(donors_file, donor_filename)) { + donor_suppliers.emplace_back( + [donor_filename, message_consumer, + target_env]() -> std::unique_ptr { + std::vector donor_binary; + if (!ReadFile(donor_filename.c_str(), "rb", + &donor_binary)) { + return nullptr; + } + return spvtools::BuildModule(target_env, message_consumer, + donor_binary.data(), + donor_binary.size()); + }); + } + + spvtools::fuzz::Fuzzer fuzzer( + target_env, + fuzzer_options->has_random_seed + ? fuzzer_options->random_seed + : static_cast(std::random_device()()), + fuzzer_options->fuzzer_pass_validation_enabled); + fuzzer.SetMessageConsumer(message_consumer); + auto fuzz_result_status = + fuzzer.Run(binary_in, initial_facts, donor_suppliers, binary_out, + transformations_applied); + if (fuzz_result_status != + spvtools::fuzz::Fuzzer::FuzzerResultStatus::kComplete) { + spvtools::Error(FuzzDiagnostic, nullptr, {}, "Error running fuzzer"); + return false; + } + return true; +} + +} // namespace + +// Dumps |binary| to file |filename|. Useful for interactive debugging. +void DumpShader(const std::vector& binary, const char* filename) { + auto write_file_succeeded = + WriteFile(filename, "wb", &binary[0], binary.size()); + if (!write_file_succeeded) { + std::cerr << "Failed to dump shader" << std::endl; + } +} + +// Dumps the SPIRV-V module in |context| to file |filename|. Useful for +// interactive debugging. +void DumpShader(spvtools::opt::IRContext* context, const char* filename) { + std::vector binary; + context->module()->ToBinary(&binary, false); + DumpShader(binary, filename); +} + +const auto kDefaultEnvironment = SPV_ENV_UNIVERSAL_1_3; + +int main(int argc, const char** argv) { + std::string in_binary_file; + std::string out_binary_file; + std::string donors_file; + std::string replay_transformations_file; + std::vector interestingness_test; + std::string shrink_transformations_file; + std::string shrink_temp_file_prefix = "temp_"; + + spvtools::FuzzerOptions fuzzer_options; + + FuzzStatus status = ParseFlags( + argc, argv, &in_binary_file, &out_binary_file, &donors_file, + &replay_transformations_file, &interestingness_test, + &shrink_transformations_file, &shrink_temp_file_prefix, &fuzzer_options); + + if (status.action == FuzzActions::STOP) { + return status.code; + } + + std::vector binary_in; + if (!ReadFile(in_binary_file.c_str(), "rb", &binary_in)) { + return 1; + } + + spvtools::fuzz::protobufs::FactSequence initial_facts; + + // If not found, dot_pos will be std::string::npos, which can be used in + // substr to mean "the end of the string"; there is no need to check the + // result. + size_t dot_pos = in_binary_file.rfind('.'); + std::string in_facts_file = in_binary_file.substr(0, dot_pos) + ".facts"; + std::ifstream facts_input(in_facts_file); + if (facts_input) { + std::string facts_json_string((std::istreambuf_iterator(facts_input)), + std::istreambuf_iterator()); + facts_input.close(); + if (google::protobuf::util::Status::OK != + google::protobuf::util::JsonStringToMessage(facts_json_string, + &initial_facts)) { + spvtools::Error(FuzzDiagnostic, nullptr, {}, "Error reading facts data"); + return 1; + } + } + + std::vector binary_out; + spvtools::fuzz::protobufs::TransformationSequence transformations_applied; + + spv_target_env target_env = kDefaultEnvironment; + + switch (status.action) { + case FuzzActions::FORCE_RENDER_RED: + if (!spvtools::fuzz::ForceRenderRed(target_env, binary_in, initial_facts, + &binary_out)) { + return 1; + } + break; + case FuzzActions::FUZZ: + if (!Fuzz(target_env, fuzzer_options, binary_in, initial_facts, + donors_file, &binary_out, &transformations_applied)) { + return 1; + } + break; + case FuzzActions::REPLAY: + if (!Replay(target_env, fuzzer_options, binary_in, initial_facts, + replay_transformations_file, &binary_out, + &transformations_applied)) { + return 1; + } + break; + case FuzzActions::SHRINK: { + if (!CheckExecuteCommand()) { + std::cerr << "could not find shell interpreter for executing a command" + << std::endl; + return 1; + } + if (!Shrink(target_env, fuzzer_options, binary_in, initial_facts, + shrink_transformations_file, shrink_temp_file_prefix, + interestingness_test, &binary_out, + &transformations_applied)) { + return 1; + } + } break; + default: + assert(false && "Unknown fuzzer action."); + break; + } + + if (!WriteFile(out_binary_file.c_str(), "wb", binary_out.data(), + binary_out.size())) { + spvtools::Error(FuzzDiagnostic, nullptr, {}, "Error writing out binary"); + return 1; + } + + if (status.action != FuzzActions::FORCE_RENDER_RED) { + // If not found, dot_pos will be std::string::npos, which can be used in + // substr to mean "the end of the string"; there is no need to check the + // result. + dot_pos = out_binary_file.rfind('.'); + std::string output_file_prefix = out_binary_file.substr(0, dot_pos); + std::ofstream transformations_file; + transformations_file.open(output_file_prefix + ".transformations", + std::ios::out | std::ios::binary); + bool success = + transformations_applied.SerializeToOstream(&transformations_file); + transformations_file.close(); + if (!success) { + spvtools::Error(FuzzDiagnostic, nullptr, {}, + "Error writing out transformations binary"); + return 1; + } + + std::string json_string; + auto json_options = google::protobuf::util::JsonOptions(); + json_options.add_whitespace = true; + auto json_generation_status = google::protobuf::util::MessageToJsonString( + transformations_applied, &json_string, json_options); + if (json_generation_status != google::protobuf::util::Status::OK) { + spvtools::Error(FuzzDiagnostic, nullptr, {}, + "Error writing out transformations in JSON format"); + return 1; + } + + std::ofstream transformations_json_file(output_file_prefix + + ".transformations_json"); + transformations_json_file << json_string; + transformations_json_file.close(); + } + + return 0; +} diff --git a/third_party/spirv-tools/tools/io.h b/third_party/spirv-tools/tools/io.h index aaf8fcdd29..97a31636ba 100644 --- a/third_party/spirv-tools/tools/io.h +++ b/third_party/spirv-tools/tools/io.h @@ -37,6 +37,7 @@ bool ReadFile(const char* filename, const char* mode, std::vector* data) { if (ftell(fp) == -1L) { if (ferror(fp)) { fprintf(stderr, "error: error reading file '%s'\n", filename); + if (use_file) fclose(fp); return false; } } else { @@ -45,6 +46,7 @@ bool ReadFile(const char* filename, const char* mode, std::vector* data) { stderr, "error: file size should be a multiple of %zd; file '%s' corrupt\n", sizeof(T), filename); + if (use_file) fclose(fp); return false; } } @@ -69,6 +71,7 @@ bool WriteFile(const char* filename, const char* mode, const T* data, size_t written = fwrite(data, sizeof(T), count, fp); if (count != written) { fprintf(stderr, "error: could not write to file '%s'\n", filename); + if (!use_stdout) fclose(fp); return false; } if (!use_stdout) fclose(fp); diff --git a/third_party/spirv-tools/tools/lesspipe/spirv-lesspipe.sh b/third_party/spirv-tools/tools/lesspipe/spirv-lesspipe.sh index 81e335501b..57684a2017 100644 --- a/third_party/spirv-tools/tools/lesspipe/spirv-lesspipe.sh +++ b/third_party/spirv-tools/tools/lesspipe/spirv-lesspipe.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env sh # Copyright (c) 2016 The Khronos Group Inc. # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/third_party/spirv-tools/tools/link/linker.cpp b/third_party/spirv-tools/tools/link/linker.cpp index fb44a37ad6..82d430ebb7 100644 --- a/third_party/spirv-tools/tools/link/linker.cpp +++ b/third_party/spirv-tools/tools/link/linker.cpp @@ -23,6 +23,7 @@ #include "tools/io.h" void print_usage(char* argv0) { + std::string target_env_list = spvTargetEnvList(27, 95); printf( R"(%s - Link SPIR-V binary files together. @@ -39,10 +40,10 @@ Options: --allow-partial-linkage Allow partial linkage by accepting imported symbols to be unresolved. --verify-ids Verify that IDs in the resulting modules are truly unique. --version Display linker version information - --target-env {vulkan1.0|spv1.0|spv1.1|spv1.2|opencl2.1|opencl2.2} - Use Vulkan1.0/SPIR-V1.0/SPIR-V1.1/SPIR-V1.2/OpenCL-2.1/OpenCL2.2 validation rules. + --target-env {%s} + Use validation rules from the specified environment. )", - argv0, argv0); + argv0, argv0, target_env_list.c_str()); } int main(int argc, char** argv) { diff --git a/third_party/spirv-tools/tools/opt/opt.cpp b/third_party/spirv-tools/tools/opt/opt.cpp index fcd260e45b..0ff937ae56 100644 --- a/third_party/spirv-tools/tools/opt/opt.cpp +++ b/third_party/spirv-tools/tools/opt/opt.cpp @@ -23,9 +23,9 @@ #include #include "source/opt/log.h" -#include "source/opt/loop_peeling.h" -#include "source/opt/set_spec_constant_default_value_pass.h" -#include "source/spirv_validator_options.h" +#include "source/spirv_target_env.h" +#include "source/util/string_utils.h" +#include "spirv-tools/libspirv.hpp" #include "spirv-tools/optimizer.hpp" #include "tools/io.h" #include "tools/util/cli_consumer.h" @@ -59,7 +59,7 @@ std::string GetListOfPassesAsString(const spvtools::Optimizer& optimizer) { return ss.str(); } -const auto kDefaultEnvironment = SPV_ENV_UNIVERSAL_1_3; +const auto kDefaultEnvironment = SPV_ENV_UNIVERSAL_1_5; std::string GetLegalizationPasses() { spvtools::Optimizer optimizer(kDefaultEnvironment); @@ -79,7 +79,20 @@ std::string GetSizePasses() { return GetListOfPassesAsString(optimizer); } +std::string GetVulkanToWebGPUPasses() { + spvtools::Optimizer optimizer(SPV_ENV_VULKAN_1_1); + optimizer.RegisterVulkanToWebGPUPasses(); + return GetListOfPassesAsString(optimizer); +} + +std::string GetWebGPUToVulkanPasses() { + spvtools::Optimizer optimizer(SPV_ENV_WEBGPU_0); + optimizer.RegisterWebGPUToVulkanPasses(); + return GetListOfPassesAsString(optimizer); +} + void PrintUsage(const char* program) { + std::string target_env_list = spvTargetEnvList(16, 80); // NOTE: Please maintain flags in lexicographical order. printf( R"(%s - Optimize a SPIR-V binary file. @@ -93,91 +106,147 @@ standard output. NOTE: The optimizer is a work in progress. -Options (in lexicographical order): +Options (in lexicographical order):)", + program, program); + printf(R"( + --amd-ext-to-khr + Replaces the extensions VK_AMD_shader_ballot, VK_AMD_gcn_shader, + and VK_AMD_shader_trinary_minmax with equivalant code using core + instructions and capabilities.)"); + printf(R"( --ccp Apply the conditional constant propagation transform. This will propagate constant values throughout the program, and simplify expressions and conditional jumps with known predicate values. Performed on entry point call tree functions and - exported functions. + exported functions.)"); + printf(R"( --cfg-cleanup Cleanup the control flow graph. This will remove any unnecessary code from the CFG like unreachable code. Performed on entry - point call tree functions and exported functions. + point call tree functions and exported functions.)"); + printf(R"( --combine-access-chains Combines chained access chains to produce a single instruction - where possible. + where possible.)"); + printf(R"( --compact-ids Remap result ids to a compact range starting from %%1 and without - any gaps. + any gaps.)"); + printf(R"( --convert-local-access-chains Convert constant index access chain loads/stores into equivalent load/stores with inserts and extracts. Performed on function scope variables referenced only with load, store, and constant index access chains in entry point call tree - functions. + functions.)"); + printf(R"( + --convert-relaxed-to-half + Convert all RelaxedPrecision arithmetic operations to half + precision, inserting conversion operations where needed. + Run after function scope variable load and store elimination + for better results. Simplify-instructions, redundancy-elimination + and DCE should be run after this pass to eliminate excess + conversions. This conversion is useful when the target platform + does not support RelaxedPrecision or ignores it. This pass also + removes all RelaxedPrecision decorations.)"); + printf(R"( --copy-propagate-arrays Does propagation of memory references when an array is a copy of another. It will only propagate an array if the source is never - written to, and the only store to the target is the copy. - --eliminate-common-uniform - Perform load/load elimination for duplicate uniform values. - Converts any constant index access chain uniform loads into - its equivalent load and extract. Some loads will be moved - to facilitate sharing. Performed only on entry point - call tree functions. + written to, and the only store to the target is the copy.)"); + printf(R"( + --decompose-initialized-variables + Decomposes initialized variable declarations into a declaration + followed by a store of the initial value. This is done to work + around known issues with some Vulkan drivers for initialize + variables.)"); + printf(R"( + --descriptor-scalar-replacement + Replaces every array variable |desc| that has a DescriptorSet + and Binding decorations with a new variable for each element of + the array. Suppose |desc| was bound at binding |b|. Then the + variable corresponding to |desc[i]| will have binding |b+i|. + The descriptor set will be the same. All accesses to |desc| + must be in OpAccessChain instructions with a literal index for + the first index.)"); + printf(R"( --eliminate-dead-branches Convert conditional branches with constant condition to the indicated unconditional brranch. Delete all resulting dead - code. Performed only on entry point call tree functions. + code. Performed only on entry point call tree functions.)"); + printf(R"( --eliminate-dead-code-aggressive Delete instructions which do not contribute to a function's - output. Performed only on entry point call tree functions. + output. Performed only on entry point call tree functions.)"); + printf(R"( --eliminate-dead-const - Eliminate dead constants. + Eliminate dead constants.)"); + printf(R"( --eliminate-dead-functions Deletes functions that cannot be reached from entry points or - exported functions. + exported functions.)"); + printf(R"( --eliminate-dead-inserts Deletes unreferenced inserts into composites, most notably unused stores to vector components, that are not removed by - aggressive dead code elimination. + aggressive dead code elimination.)"); + printf(R"( --eliminate-dead-variables - Deletes module scope variables that are not referenced. + Deletes module scope variables that are not referenced.)"); + printf(R"( --eliminate-insert-extract DEPRECATED. This pass has been replaced by the simplification pass, and that pass will be run instead. - See --simplify-instructions. + See --simplify-instructions.)"); + printf(R"( --eliminate-local-multi-store Replace stores and loads of function scope variables that are stored multiple times. Performed on variables referenceed only with loads and stores. Performed only on entry point call tree - functions. + functions.)"); + printf(R"( --eliminate-local-single-block Perform single-block store/load and load/load elimination. Performed only on function scope variables in entry point - call tree functions. + call tree functions.)"); + printf(R"( --eliminate-local-single-store Replace stores and loads of function scope variables that are only stored once. Performed on variables referenceed only with loads and stores. Performed only on entry point call tree - functions. + functions.)"); + printf(R"( --flatten-decorations Replace decoration groups with repeated OpDecorate and - OpMemberDecorate instructions. + OpMemberDecorate instructions.)"); + printf(R"( --fold-spec-const-op-composite Fold the spec constants defined by OpSpecConstantOp or OpSpecConstantComposite instructions to front-end constants - when possible. + when possible.)"); + printf(R"( --freeze-spec-const Freeze the values of specialization constants to their default - values. + values.)"); + printf(R"( + --graphics-robust-access + Clamp indices used to access buffers and internal composite + values, providing guarantees that satisfy Vulkan's + robustBufferAccess rules.)"); + printf(R"( + --generate-webgpu-initializers + Adds initial values to OpVariable instructions that are missing + them, due to their storage type requiring them for WebGPU.)"); + printf(R"( --if-conversion - Convert if-then-else like assignments into OpSelect. + Convert if-then-else like assignments into OpSelect.)"); + printf(R"( --inline-entry-points-exhaustive Exhaustively inline all function calls in entry point call tree functions. Currently does not inline calls to functions with - early return in a loop. + early return in a loop.)"); + printf(R"( --legalize-hlsl Runs a series of optimizations that attempts to take SPIR-V generated by an HLSL front-end and generates legal Vulkan SPIR-V. @@ -185,39 +254,63 @@ Options (in lexicographical order): %s Note this does not guarantee legal code. This option passes the - option --relax-logical-pointer to the validator. + option --relax-logical-pointer to the validator.)", + GetLegalizationPasses().c_str()); + printf(R"( + --legalize-vector-shuffle + Converts any usages of 0xFFFFFFFF for the literals in + OpVectorShuffle to a literal 0. This is done since 0xFFFFFFFF is + forbidden in WebGPU.)"); + printf(R"( --local-redundancy-elimination Looks for instructions in the same basic block that compute the - same value, and deletes the redundant ones. + same value, and deletes the redundant ones.)"); + printf(R"( --loop-fission - Splits any top level loops in which the register pressure has exceeded - a given threshold. The threshold must follow the use of this flag and - must be a positive integer value. + Splits any top level loops in which the register pressure has + exceeded a given threshold. The threshold must follow the use of + this flag and must be a positive integer value.)"); + printf(R"( --loop-fusion Identifies adjacent loops with the same lower and upper bound. If this is legal, then merge the loops into a single loop. Includes heuristics to ensure it does not increase number of registers too much, while reducing the number of loads from memory. Takes an additional positive integer argument to set - the maximum number of registers. + the maximum number of registers.)"); + printf(R"( + --loop-invariant-code-motion + Identifies code in loops that has the same value for every + iteration of the loop, and move it to the loop pre-header.)"); + printf(R"( --loop-unroll - Fully unrolls loops marked with the Unroll flag + Fully unrolls loops marked with the Unroll flag)"); + printf(R"( --loop-unroll-partial Partially unrolls loops marked with the Unroll flag. Takes an additional non-0 integer argument to set the unroll factor, or - how many times a loop body should be duplicated + how many times a loop body should be duplicated)"); + printf(R"( --loop-peeling Execute few first (respectively last) iterations before - (respectively after) the loop if it can elide some branches. + (respectively after) the loop if it can elide some branches.)"); + printf(R"( --loop-peeling-threshold Takes a non-0 integer argument to set the loop peeling code size growth threshold. The threshold prevents the loop peeling from happening if the code size increase created by - the optimization is above the threshold. + the optimization is above the threshold.)"); + printf(R"( + --max-id-bound= + Sets the maximum value for the id bound for the moudle. The + default is the minimum value for this limit, 0x3FFFFF. See + section 2.17 of the Spir-V specification.)"); + printf(R"( --merge-blocks Join two blocks into a single block if the second has the first as its only predecessor. Performed only on entry point - call tree functions. + call tree functions.)"); + printf(R"( --merge-return Changes functions that have multiple return statements so they have a single return statement. @@ -231,17 +324,21 @@ Options (in lexicographical order): label and an OpBranch to the header, nothing else. These conditions are guaranteed to be met after running - dead-branch elimination. + dead-branch elimination.)"); + printf(R"( --loop-unswitch Hoists loop-invariant conditionals out of loops by duplicating the loop on each branch of the conditional and adjusting each - copy of the loop. + copy of the loop.)"); + printf(R"( -O Optimize for performance. Apply a sequence of transformations in an attempt to improve the performance of the generated code. For this version of the optimizer, this flag is equivalent to specifying the following optimization code names: - %s + %s)", + GetOptimizationPasses().c_str()); + printf(R"( -Os Optimize for size. Apply a sequence of transformations in an attempt to minimize the size of the generated code. For this @@ -250,7 +347,9 @@ Options (in lexicographical order): %s NOTE: The specific transformations done by -O and -Os change - from release to release. + from release to release.)", + GetSizePasses().c_str()); + printf(R"( -Oconfig= Apply the sequence of transformations indicated in . This file contains a sequence of strings separated by whitespace @@ -278,84 +377,175 @@ Options (in lexicographical order): that position in the command line. For example, the invocation 'spirv-opt --merge-blocks -O ...' applies the transformation --merge-blocks followed by all the transformations implied by - -O. + -O.)"); + printf(R"( + --preserve-bindings + Ensure that the optimizer preserves all bindings declared within + the module, even when those bindings are unused.)"); + printf(R"( + --preserve-spec-constants + Ensure that the optimizer preserves all specialization constants declared + within the module, even when those constants are unused.)"); + printf(R"( --print-all Print SPIR-V assembly to standard error output before each pass - and after the last pass. + and after the last pass.)"); + printf(R"( --private-to-local Change the scope of private variables that are used in a single - function to that function. + function to that function.)"); + printf(R"( --reduce-load-size Replaces loads of composite objects where not every component is - used by loads of just the elements that are used. + used by loads of just the elements that are used.)"); + printf(R"( --redundancy-elimination Looks for instructions in the same function that compute the - same value, and deletes the redundant ones. + same value, and deletes the redundant ones.)"); + printf(R"( + --relax-float-ops + Decorate all float operations with RelaxedPrecision if not already + so decorated. This does not decorate types or variables.)"); + printf(R"( --relax-struct-store Allow store from one struct type to a different type with compatible layout and members. This option is forwarded to the - validator. + validator.)"); + printf(R"( --remove-duplicates Removes duplicate types, decorations, capabilities and extension - instructions. + instructions.)"); + printf(R"( --replace-invalid-opcode Replaces instructions whose opcode is valid for shader modules, but not for the current shader stage. To have an effect, all - entry points must have the same execution model. + entry points must have the same execution model.)"); + printf(R"( --ssa-rewrite Replace loads and stores to function local variables with - operations on SSA IDs. + operations on SSA IDs.)"); + printf(R"( --scalar-replacement[=] Replace aggregate function scope variables that are only accessed via their elements with new function variables representing each element. is a limit on the size of the aggragates that will be replaced. 0 means there is no limit. The default value is - 100. + 100.)"); + printf(R"( --set-spec-const-default-value ": ..." Set the default values of the specialization constants with : pairs specified in a double-quoted string. : pairs must be separated by blank spaces, and in each pair, spec id and default value must be separated with colon ':' without any blank spaces in between. - e.g.: --set-spec-const-default-value "1:100 2:400" + e.g.: --set-spec-const-default-value "1:100 2:400")"); + printf(R"( --simplify-instructions Will simplify all instructions in the function as much as - possible. + possible.)"); + printf(R"( + --split-invalid-unreachable + Attempts to legalize for WebGPU cases where an unreachable + merge-block is also a continue-target by splitting it into two + seperate blocks. There exist legal, for Vulkan, instances of this + pattern that cannot be converted into legal WebGPU, so this + conversion may not succeed.)"); + printf(R"( --skip-validation Will not validate the SPIR-V before optimizing. If the SPIR-V is invalid, the optimizer may fail or generate incorrect code. - This options should be used rarely, and with caution. + This options should be used rarely, and with caution.)"); + printf(R"( --strength-reduction - Replaces instructions with equivalent and less expensive ones. + Replaces instructions with equivalent and less expensive ones.)"); + printf(R"( + --strip-atomic-counter-memory + Removes AtomicCountMemory bit from memory semantics values.)"); + printf(R"( --strip-debug - Remove all debug instructions. + Remove all debug instructions.)"); + printf(R"( --strip-reflect Remove all reflection information. For now, this covers - reflection information defined by SPV_GOOGLE_hlsl_functionality1. + reflection information defined by SPV_GOOGLE_hlsl_functionality1 + and SPV_KHR_non_semantic_info)"); + printf(R"( + --target-env= + Set the target environment. Without this flag the target + enviroment defaults to spv1.3. must be one of + {%s})", + target_env_list.c_str()); + printf(R"( --time-report Print the resource utilization of each pass (e.g., CPU time, RSS) to standard error output. Currently it supports only Unix systems. This option is the same as -ftime-report in GCC. It prints CPU/WALL/USR/SYS time (and RSS if possible), but note that USR/SYS time are returned by getrusage() and can have a small - error. + error.)"); + printf(R"( + --upgrade-memory-model + Upgrades the Logical GLSL450 memory model to Logical VulkanKHR. + Transforms memory, image, atomic and barrier operations to conform + to that model's requirements.)"); + printf(R"( --vector-dce This pass looks for components of vectors that are unused, and removes them from the vector. Note this would still leave around - lots of dead code that a pass of ADCE will be able to remove. + lots of dead code that a pass of ADCE will be able to remove.)"); + printf(R"( + --vulkan-to-webgpu + Turns on the prescribed passes for converting from Vulkan to + WebGPU and sets the target environment to webgpu0. Other passes + may be turned on via additional flags, but such combinations are + not tested. + Using --target-env with this flag is not allowed. + + This flag is the equivalent of passing in --target-env=webgpu0 + and specifying the following optimization code names: + %s + + NOTE: This flag is a WIP and its behaviour is subject to change.)", + GetVulkanToWebGPUPasses().c_str()); + printf(R"( + --webgpu-to-vulkan + Turns on the prescribed passes for converting from WebGPU to + Vulkan and sets the target environment to vulkan1.1. Other passes + may be turned on via additional flags, but such combinations are + not tested. + Using --target-env with this flag is not allowed. + + This flag is the equivalent of passing in --target-env=vulkan1.1 + and specifying the following optimization code names: + %s + + NOTE: This flag is a WIP and its behaviour is subject to change.)", + GetWebGPUToVulkanPasses().c_str()); + printf(R"( --workaround-1209 Rewrites instructions for which there are known driver bugs to avoid triggering those bugs. - Current workarounds: Avoid OpUnreachable in loops. + Current workarounds: Avoid OpUnreachable in loops.)"); + printf(R"( + --wrap-opkill + Replaces all OpKill instructions in functions that can be called + from a continue construct with a function call to a function + whose only instruction is an OpKill. This is done to enable + inlining on these functions. + )"); + printf(R"( --unify-const - Remove the duplicated constants. + Remove the duplicated constants.)"); + printf(R"( + --validate-after-all + Validate the module after each pass is performed.)"); + printf(R"( -h, --help - Print this help. + Print this help.)"); + printf(R"( --version Display optimizer version information. -)", - program, program, GetLegalizationPasses().c_str(), - GetOptimizationPasses().c_str(), GetSizePasses().c_str()); +)"); } // Reads command-line flags the file specified in |oconfig_flag|. This string @@ -406,18 +596,22 @@ bool ReadFlagsFromFile(const char* oconfig_flag, OptStatus ParseFlags(int argc, const char** argv, spvtools::Optimizer* optimizer, const char** in_file, - const char** out_file, spvtools::ValidatorOptions* options, - bool* skip_validator); + const char** out_file, + spvtools::ValidatorOptions* validator_options, + spvtools::OptimizerOptions* optimizer_options); // Parses and handles the -Oconfig flag. |prog_name| contains the name of // the spirv-opt binary (used to build a new argv vector for the recursive // invocation to ParseFlags). |opt_flag| contains the -Oconfig=FILENAME flag. -// |optimizer|, |in_file| and |out_file| are as in ParseFlags. +// |optimizer|, |in_file|, |out_file|, |validator_options|, and +// |optimizer_options| are as in ParseFlags. // // This returns the same OptStatus instance returned by ParseFlags. OptStatus ParseOconfigFlag(const char* prog_name, const char* opt_flag, spvtools::Optimizer* optimizer, const char** in_file, - const char** out_file) { + const char** out_file, + spvtools::ValidatorOptions* validator_options, + spvtools::OptimizerOptions* optimizer_options) { std::vector flags; flags.push_back(prog_name); @@ -440,9 +634,11 @@ OptStatus ParseOconfigFlag(const char* prog_name, const char* opt_flag, new_argv[i] = flags[i].c_str(); } - bool skip_validator = false; - return ParseFlags(static_cast(flags.size()), new_argv, optimizer, - in_file, out_file, nullptr, &skip_validator); + auto ret_val = + ParseFlags(static_cast(flags.size()), new_argv, optimizer, in_file, + out_file, validator_options, optimizer_options); + delete[] new_argv; + return ret_val; } // Canonicalize the flag in |argv[argi]| of the form '--pass arg' into @@ -485,9 +681,9 @@ std::string CanonicalizeFlag(const char** argv, int argc, int* argi) { return canonical_arg.str(); } -// the number of command-line flags. |argv| points to an array of strings -// holding the flags. |optimizer| is the Optimizer instance used to optimize the -// program. +// Parses command-line flags. |argc| contains the number of command-line flags. +// |argv| points to an array of strings holding the flags. |optimizer| is the +// Optimizer instance used to optimize the program. // // On return, this function stores the name of the input program in |in_file|. // The name of the output file in |out_file|. The return value indicates whether @@ -495,9 +691,13 @@ std::string CanonicalizeFlag(const char** argv, int argc, int* argi) { // success. OptStatus ParseFlags(int argc, const char** argv, spvtools::Optimizer* optimizer, const char** in_file, - const char** out_file, spvtools::ValidatorOptions* options, - bool* skip_validator) { + const char** out_file, + spvtools::ValidatorOptions* validator_options, + spvtools::OptimizerOptions* optimizer_options) { std::vector pass_flags; + bool target_env_set = false; + bool vulkan_to_webgpu_set = false; + bool webgpu_to_vulkan_set = false; for (int argi = 1; argi < argc; ++argi) { const char* cur_arg = argv[argi]; if ('-' == cur_arg[0]) { @@ -526,18 +726,102 @@ OptStatus ParseFlags(int argc, const char** argv, } } else if (0 == strncmp(cur_arg, "-Oconfig=", sizeof("-Oconfig=") - 1)) { OptStatus status = - ParseOconfigFlag(argv[0], cur_arg, optimizer, in_file, out_file); + ParseOconfigFlag(argv[0], cur_arg, optimizer, in_file, out_file, + validator_options, optimizer_options); if (status.action != OPT_CONTINUE) { return status; } } else if (0 == strcmp(cur_arg, "--skip-validation")) { - *skip_validator = true; + optimizer_options->set_run_validator(false); } else if (0 == strcmp(cur_arg, "--print-all")) { optimizer->SetPrintAll(&std::cerr); + } else if (0 == strcmp(cur_arg, "--preserve-bindings")) { + optimizer_options->set_preserve_bindings(true); + } else if (0 == strcmp(cur_arg, "--preserve-spec-constants")) { + optimizer_options->set_preserve_spec_constants(true); } else if (0 == strcmp(cur_arg, "--time-report")) { optimizer->SetTimeReport(&std::cerr); } else if (0 == strcmp(cur_arg, "--relax-struct-store")) { - options->SetRelaxStructStore(true); + validator_options->SetRelaxStructStore(true); + } else if (0 == strncmp(cur_arg, "--max-id-bound=", + sizeof("--max-id-bound=") - 1)) { + auto split_flag = spvtools::utils::SplitFlagArgs(cur_arg); + // Will not allow values in the range [2^31,2^32). + uint32_t max_id_bound = + static_cast(atoi(split_flag.second.c_str())); + + // That SPIR-V mandates the minimum value for max id bound but + // implementations may allow higher minimum bounds. + if (max_id_bound < kDefaultMaxIdBound) { + spvtools::Error(opt_diagnostic, nullptr, {}, + "The max id bound must be at least 0x3FFFFF"); + return {OPT_STOP, 1}; + } + optimizer_options->set_max_id_bound(max_id_bound); + validator_options->SetUniversalLimit(spv_validator_limit_max_id_bound, + max_id_bound); + } else if (0 == strncmp(cur_arg, + "--target-env=", sizeof("--target-env=") - 1)) { + target_env_set = true; + if (vulkan_to_webgpu_set) { + spvtools::Error(opt_diagnostic, nullptr, {}, + "--vulkan-to-webgpu defines the target environment, " + "so --target-env cannot be set at the same time"); + return {OPT_STOP, 1}; + } + if (webgpu_to_vulkan_set) { + spvtools::Error(opt_diagnostic, nullptr, {}, + "--webgpu-to-vulkan defines the target environment, " + "so --target-env cannot be set at the same time"); + return {OPT_STOP, 1}; + } + const auto split_flag = spvtools::utils::SplitFlagArgs(cur_arg); + const auto target_env_str = split_flag.second.c_str(); + spv_target_env target_env; + if (!spvParseTargetEnv(target_env_str, &target_env)) { + spvtools::Error(opt_diagnostic, nullptr, {}, + "Invalid value passed to --target-env"); + return {OPT_STOP, 1}; + } + optimizer->SetTargetEnv(target_env); + } else if (0 == strcmp(cur_arg, "--vulkan-to-webgpu")) { + vulkan_to_webgpu_set = true; + if (target_env_set) { + spvtools::Error(opt_diagnostic, nullptr, {}, + "--vulkan-to-webgpu defines the target environment, " + "so --target-env cannot be set at the same time"); + return {OPT_STOP, 1}; + } + if (webgpu_to_vulkan_set) { + spvtools::Error(opt_diagnostic, nullptr, {}, + "Cannot use both --webgpu-to-vulkan and " + "--vulkan-to-webgpu at the same time, invoke twice " + "if you are wanting to go to and from"); + return {OPT_STOP, 1}; + } + + optimizer->SetTargetEnv(SPV_ENV_VULKAN_1_1); + optimizer->RegisterVulkanToWebGPUPasses(); + } else if (0 == strcmp(cur_arg, "--webgpu-to-vulkan")) { + webgpu_to_vulkan_set = true; + if (target_env_set) { + spvtools::Error(opt_diagnostic, nullptr, {}, + "--webgpu-to-vulkan defines the target environment, " + "so --target-env cannot be set at the same time"); + return {OPT_STOP, 1}; + } + if (vulkan_to_webgpu_set) { + spvtools::Error(opt_diagnostic, nullptr, {}, + "Cannot use both --webgpu-to-vulkan and " + "--vulkan-to-webgpu at the same time, invoke twice " + "if you are wanting to go to and from"); + return {OPT_STOP, 1}; + } + + optimizer->SetTargetEnv(SPV_ENV_WEBGPU_0); + optimizer->RegisterWebGPUToVulkanPasses(); + } else if (0 == strcmp(cur_arg, "--validate-after-all")) { + optimizer->SetValidateAfterAll(true); } else { // Some passes used to accept the form '--pass arg', canonicalize them // to '--pass=arg'. @@ -546,7 +830,7 @@ OptStatus ParseFlags(int argc, const char** argv, // If we were requested to legalize SPIR-V generated from the HLSL // front-end, skip validation. if (0 == strcmp(cur_arg, "--legalize-hlsl")) { - options->SetRelaxLogicalPointer(true); + validator_options->SetBeforeHlslLegalization(true); } } } else { @@ -572,16 +856,17 @@ OptStatus ParseFlags(int argc, const char** argv, int main(int argc, const char** argv) { const char* in_file = nullptr; const char* out_file = nullptr; - bool skip_validator = false; spv_target_env target_env = kDefaultEnvironment; - spvtools::ValidatorOptions options; spvtools::Optimizer optimizer(target_env); optimizer.SetMessageConsumer(spvtools::utils::CLIMessageConsumer); + spvtools::ValidatorOptions validator_options; + spvtools::OptimizerOptions optimizer_options; OptStatus status = ParseFlags(argc, argv, &optimizer, &in_file, &out_file, - &options, &skip_validator); + &validator_options, &optimizer_options); + optimizer_options.set_validator_options(validator_options); if (status.action == OPT_STOP) { return status.code; @@ -599,8 +884,8 @@ int main(int argc, const char** argv) { // By using the same vector as input and output, we save time in the case // that there was no change. - bool ok = optimizer.Run(binary.data(), binary.size(), &binary, options, - skip_validator); + bool ok = + optimizer.Run(binary.data(), binary.size(), &binary, optimizer_options); if (!WriteFile(out_file, "wb", binary.data(), binary.size())) { return 1; diff --git a/third_party/spirv-tools/tools/reduce/reduce.cpp b/third_party/spirv-tools/tools/reduce/reduce.cpp new file mode 100644 index 0000000000..0bdeb82ae1 --- /dev/null +++ b/third_party/spirv-tools/tools/reduce/reduce.cpp @@ -0,0 +1,327 @@ +// Copyright (c) 2018 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 +#include +#include +#include + +#include "source/opt/build_module.h" +#include "source/opt/ir_context.h" +#include "source/opt/log.h" +#include "source/reduce/reducer.h" +#include "source/spirv_reducer_options.h" +#include "source/util/string_utils.h" +#include "tools/io.h" +#include "tools/util/cli_consumer.h" + +namespace { + +// Check that the std::system function can actually be used. +bool CheckExecuteCommand() { + int res = std::system(nullptr); + return res != 0; +} + +// Execute a command using the shell. +// Returns true if and only if the command's exit status was 0. +bool ExecuteCommand(const std::string& command) { + errno = 0; + int status = std::system(command.c_str()); + assert(errno == 0 && "failed to execute command"); + // The result returned by 'system' is implementation-defined, but is + // usually the case that the returned value is 0 when the command's exit + // code was 0. We are assuming that here, and that's all we depend on. + return status == 0; +} + +// Status and actions to perform after parsing command-line arguments. +enum ReduceActions { REDUCE_CONTINUE, REDUCE_STOP }; + +struct ReduceStatus { + ReduceActions action; + int code; +}; + +void PrintUsage(const char* program) { + // NOTE: Please maintain flags in lexicographical order. + printf( + R"(%s - Reduce a SPIR-V binary file with respect to a user-provided +interestingness test. + +USAGE: %s [options] -o -- [args...] + +The SPIR-V binary is read from . The reduced SPIR-V binary is +written to . + +Whether a binary is interesting is determined by , which +should be the path to a script. The "--" characters are optional but denote +that all arguments that follow are positional arguments and thus will be +forwarded to the interestingness test, and not parsed by %s. + + * The script must be executable. + + * The script should take the path to a SPIR-V binary file (.spv) as an + argument, and exit with code 0 if and only if the binary file is + interesting. The binary will be passed to the script as an argument after + any other provided arguments [args...]. + + * Example: an interestingness test for reducing a SPIR-V binary file that + causes tool "foo" to exit with error code 1 and print "Fatal error: bar" to + standard error should: + - invoke "foo" on the binary passed as the script argument; + - capture the return code and standard error from "bar"; + - exit with code 0 if and only if the return code of "foo" was 1 and the + standard error from "bar" contained "Fatal error: bar". + + * The reducer does not place a time limit on how long the interestingness test + takes to run, so it is advisable to use per-command timeouts inside the + script when invoking SPIR-V-processing tools (such as "foo" in the above + example). + +NOTE: The reducer is a work in progress. + +Options (in lexicographical order): + + --fail-on-validation-error + Stop reduction with an error if any reduction step produces a + SPIR-V module that fails to validate. + -h, --help + Print this help. + --step-limit= + 32-bit unsigned integer specifying maximum number of steps the + reducer will take before giving up. + --temp-file-prefix= + Specifies a temporary file prefix that will be used to output + temporary shader files during reduction. A number and .spv + extension will be added. The default is "temp_", which will + cause files like "temp_0001.spv" to be output to the current + directory. + --version + Display reducer version information. + +Supported validator options are as follows. See `spirv-val --help` for details. + --before-hlsl-legalization + --relax-block-layout + --relax-logical-pointer + --relax-struct-store + --scalar-block-layout + --skip-block-layout +)", + program, program, program); +} + +// Message consumer for this tool. Used to emit diagnostics during +// initialization and setup. Note that |source| and |position| are irrelevant +// here because we are still not processing a SPIR-V input file. +void ReduceDiagnostic(spv_message_level_t level, const char* /*source*/, + const spv_position_t& /*position*/, const char* message) { + if (level == SPV_MSG_ERROR) { + fprintf(stderr, "error: "); + } + fprintf(stderr, "%s\n", message); +} + +ReduceStatus ParseFlags(int argc, const char** argv, + std::string* in_binary_file, + std::string* out_binary_file, + std::vector* interestingness_test, + std::string* temp_file_prefix, + spvtools::ReducerOptions* reducer_options, + spvtools::ValidatorOptions* validator_options) { + uint32_t positional_arg_index = 0; + bool only_positional_arguments_remain = false; + + for (int argi = 1; argi < argc; ++argi) { + const char* cur_arg = argv[argi]; + if ('-' == cur_arg[0] && !only_positional_arguments_remain) { + if (0 == strcmp(cur_arg, "--version")) { + spvtools::Logf(ReduceDiagnostic, SPV_MSG_INFO, nullptr, {}, "%s\n", + spvSoftwareVersionDetailsString()); + return {REDUCE_STOP, 0}; + } else if (0 == strcmp(cur_arg, "--help") || 0 == strcmp(cur_arg, "-h")) { + PrintUsage(argv[0]); + return {REDUCE_STOP, 0}; + } else if (0 == strcmp(cur_arg, "-o")) { + if (out_binary_file->empty() && argi + 1 < argc) { + *out_binary_file = std::string(argv[++argi]); + } else { + PrintUsage(argv[0]); + return {REDUCE_STOP, 1}; + } + } else if (0 == strncmp(cur_arg, + "--step-limit=", sizeof("--step-limit=") - 1)) { + const auto split_flag = spvtools::utils::SplitFlagArgs(cur_arg); + char* end = nullptr; + errno = 0; + const auto step_limit = + static_cast(strtol(split_flag.second.c_str(), &end, 10)); + assert(end != split_flag.second.c_str() && errno == 0); + reducer_options->set_step_limit(step_limit); + } else if (0 == strcmp(cur_arg, "--fail-on-validation-error")) { + reducer_options->set_fail_on_validation_error(true); + } else if (0 == strcmp(cur_arg, "--before-hlsl-legalization")) { + validator_options->SetBeforeHlslLegalization(true); + } else if (0 == strcmp(cur_arg, "--relax-logical-pointer")) { + validator_options->SetRelaxLogicalPointer(true); + } else if (0 == strcmp(cur_arg, "--relax-block-layout")) { + validator_options->SetRelaxBlockLayout(true); + } else if (0 == strcmp(cur_arg, "--scalar-block-layout")) { + validator_options->SetScalarBlockLayout(true); + } else if (0 == strcmp(cur_arg, "--skip-block-layout")) { + validator_options->SetSkipBlockLayout(true); + } else if (0 == strcmp(cur_arg, "--relax-struct-store")) { + validator_options->SetRelaxStructStore(true); + } else if (0 == strncmp(cur_arg, "--temp-file-prefix=", + sizeof("--temp-file-prefix=") - 1)) { + const auto split_flag = spvtools::utils::SplitFlagArgs(cur_arg); + *temp_file_prefix = std::string(split_flag.second); + } else if (0 == strcmp(cur_arg, "--")) { + only_positional_arguments_remain = true; + } else { + std::stringstream ss; + ss << "Unrecognized argument: " << cur_arg << std::endl; + spvtools::Error(ReduceDiagnostic, nullptr, {}, ss.str().c_str()); + PrintUsage(argv[0]); + return {REDUCE_STOP, 1}; + } + } else if (positional_arg_index == 0) { + // Binary input file name + assert(in_binary_file->empty()); + *in_binary_file = std::string(cur_arg); + positional_arg_index++; + } else { + interestingness_test->push_back(std::string(cur_arg)); + } + } + + if (in_binary_file->empty()) { + spvtools::Error(ReduceDiagnostic, nullptr, {}, "No input file specified"); + return {REDUCE_STOP, 1}; + } + + if (out_binary_file->empty()) { + spvtools::Error(ReduceDiagnostic, nullptr, {}, "-o required"); + return {REDUCE_STOP, 1}; + } + + if (interestingness_test->empty()) { + spvtools::Error(ReduceDiagnostic, nullptr, {}, + "No interestingness test specified"); + return {REDUCE_STOP, 1}; + } + + return {REDUCE_CONTINUE, 0}; +} + +} // namespace + +// Dumps |binary| to file |filename|. Useful for interactive debugging. +void DumpShader(const std::vector& binary, const char* filename) { + auto write_file_succeeded = + WriteFile(filename, "wb", &binary[0], binary.size()); + if (!write_file_succeeded) { + std::cerr << "Failed to dump shader" << std::endl; + } +} + +// Dumps the SPIRV-V module in |context| to file |filename|. Useful for +// interactive debugging. +void DumpShader(spvtools::opt::IRContext* context, const char* filename) { + std::vector binary; + context->module()->ToBinary(&binary, false); + DumpShader(binary, filename); +} + +const auto kDefaultEnvironment = SPV_ENV_UNIVERSAL_1_5; + +int main(int argc, const char** argv) { + std::string in_binary_file; + std::string out_binary_file; + std::vector interestingness_test; + std::string temp_file_prefix = "temp_"; + + spv_target_env target_env = kDefaultEnvironment; + spvtools::ReducerOptions reducer_options; + spvtools::ValidatorOptions validator_options; + + ReduceStatus status = ParseFlags( + argc, argv, &in_binary_file, &out_binary_file, &interestingness_test, + &temp_file_prefix, &reducer_options, &validator_options); + + if (status.action == REDUCE_STOP) { + return status.code; + } + + if (!CheckExecuteCommand()) { + std::cerr << "could not find shell interpreter for executing a command" + << std::endl; + return 2; + } + + spvtools::reduce::Reducer reducer(target_env); + + std::stringstream joined; + joined << interestingness_test[0]; + for (size_t i = 1, size = interestingness_test.size(); i < size; ++i) { + joined << " " << interestingness_test[i]; + } + std::string interestingness_command_joined = joined.str(); + + reducer.SetInterestingnessFunction( + [interestingness_command_joined, temp_file_prefix]( + std::vector binary, uint32_t reductions_applied) -> bool { + std::stringstream ss; + ss << temp_file_prefix << std::setw(4) << std::setfill('0') + << reductions_applied << ".spv"; + const auto spv_file = ss.str(); + const std::string command = + interestingness_command_joined + " " + spv_file; + auto write_file_succeeded = + WriteFile(spv_file.c_str(), "wb", &binary[0], binary.size()); + (void)(write_file_succeeded); + assert(write_file_succeeded); + return ExecuteCommand(command); + }); + + reducer.AddDefaultReductionPasses(); + + reducer.SetMessageConsumer(spvtools::utils::CLIMessageConsumer); + + std::vector binary_in; + if (!ReadFile(in_binary_file.c_str(), "rb", &binary_in)) { + return 1; + } + + std::vector binary_out; + const auto reduction_status = reducer.Run(std::move(binary_in), &binary_out, + reducer_options, validator_options); + + // Always try to write the output file, even if the reduction failed. + if (!WriteFile(out_binary_file.c_str(), "wb", binary_out.data(), + binary_out.size())) { + return 1; + } + + // These are the only successful statuses. + switch (reduction_status) { + case spvtools::reduce::Reducer::ReductionResultStatus::kComplete: + case spvtools::reduce::Reducer::ReductionResultStatus::kReachedStepLimit: + return 0; + default: + break; + } + + return 1; +} diff --git a/third_party/spirv-tools/tools/stats/spirv_stats.cpp b/third_party/spirv-tools/tools/stats/spirv_stats.cpp deleted file mode 100644 index 7751c64024..0000000000 --- a/third_party/spirv-tools/tools/stats/spirv_stats.cpp +++ /dev/null @@ -1,165 +0,0 @@ -// Copyright (c) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "tools/stats/spirv_stats.h" - -#include - -#include -#include -#include - -#include "source/diagnostic.h" -#include "source/enum_string_mapping.h" -#include "source/extensions.h" -#include "source/id_descriptor.h" -#include "source/instruction.h" -#include "source/opcode.h" -#include "source/operand.h" -#include "source/val/instruction.h" -#include "source/val/validate.h" -#include "source/val/validation_state.h" -#include "spirv-tools/libspirv.h" - -namespace spvtools { -namespace stats { -namespace { - -// Helper class for stats aggregation. Receives as in/out parameter. -// Constructs ValidationState and updates it by running validator for each -// instruction. -class StatsAggregator { - public: - StatsAggregator(SpirvStats* in_out_stats, const val::ValidationState_t* state) - : stats_(in_out_stats), vstate_(state) {} - - // Processes the instructions to collect stats. - void aggregate() { - const auto& instructions = vstate_->ordered_instructions(); - - ++stats_->version_hist[vstate_->version()]; - ++stats_->generator_hist[vstate_->generator()]; - - for (size_t i = 0; i < instructions.size(); ++i) { - const auto& inst = instructions[i]; - - ProcessOpcode(&inst, i); - ProcessCapability(&inst); - ProcessExtension(&inst); - ProcessConstant(&inst); - } - } - - // Collects OpCapability statistics. - void ProcessCapability(const val::Instruction* inst) { - if (inst->opcode() != SpvOpCapability) return; - const uint32_t capability = inst->word(inst->operands()[0].offset); - ++stats_->capability_hist[capability]; - } - - // Collects OpExtension statistics. - void ProcessExtension(const val::Instruction* inst) { - if (inst->opcode() != SpvOpExtension) return; - const std::string extension = GetExtensionString(&inst->c_inst()); - ++stats_->extension_hist[extension]; - } - - // Collects OpCode statistics. - void ProcessOpcode(const val::Instruction* inst, size_t idx) { - const SpvOp opcode = inst->opcode(); - ++stats_->opcode_hist[opcode]; - - if (idx == 0) return; - - --idx; - - const auto& instructions = vstate_->ordered_instructions(); - - auto step_it = stats_->opcode_markov_hist.begin(); - for (; step_it != stats_->opcode_markov_hist.end(); --idx, ++step_it) { - auto& hist = (*step_it)[instructions[idx].opcode()]; - ++hist[opcode]; - - if (idx == 0) break; - } - } - - // Collects OpConstant statistics. - void ProcessConstant(const val::Instruction* inst) { - if (inst->opcode() != SpvOpConstant) return; - - const uint32_t type_id = inst->GetOperandAs(0); - const auto type_decl_it = vstate_->all_definitions().find(type_id); - assert(type_decl_it != vstate_->all_definitions().end()); - - const val::Instruction& type_decl_inst = *type_decl_it->second; - const SpvOp type_op = type_decl_inst.opcode(); - if (type_op == SpvOpTypeInt) { - const uint32_t bit_width = type_decl_inst.GetOperandAs(1); - const uint32_t is_signed = type_decl_inst.GetOperandAs(2); - assert(is_signed == 0 || is_signed == 1); - if (bit_width == 16) { - if (is_signed) - ++stats_->s16_constant_hist[inst->GetOperandAs(2)]; - else - ++stats_->u16_constant_hist[inst->GetOperandAs(2)]; - } else if (bit_width == 32) { - if (is_signed) - ++stats_->s32_constant_hist[inst->GetOperandAs(2)]; - else - ++stats_->u32_constant_hist[inst->GetOperandAs(2)]; - } else if (bit_width == 64) { - if (is_signed) - ++stats_->s64_constant_hist[inst->GetOperandAs(2)]; - else - ++stats_->u64_constant_hist[inst->GetOperandAs(2)]; - } else { - assert(false && "TypeInt bit width is not 16, 32 or 64"); - } - } else if (type_op == SpvOpTypeFloat) { - const uint32_t bit_width = type_decl_inst.GetOperandAs(1); - if (bit_width == 32) { - ++stats_->f32_constant_hist[inst->GetOperandAs(2)]; - } else if (bit_width == 64) { - ++stats_->f64_constant_hist[inst->GetOperandAs(2)]; - } else { - assert(bit_width == 16); - } - } - } - - private: - SpirvStats* stats_; - const val::ValidationState_t* vstate_; - IdDescriptorCollection id_descriptors_; -}; - -} // namespace - -spv_result_t AggregateStats(const spv_context_t& context, const uint32_t* words, - const size_t num_words, spv_diagnostic* pDiagnostic, - SpirvStats* stats) { - std::unique_ptr vstate; - spv_validator_options_t options; - spv_result_t result = ValidateBinaryAndKeepValidationState( - &context, &options, words, num_words, pDiagnostic, &vstate); - if (result != SPV_SUCCESS) return result; - - StatsAggregator stats_aggregator(stats, vstate.get()); - stats_aggregator.aggregate(); - return SPV_SUCCESS; -} - -} // namespace stats -} // namespace spvtools diff --git a/third_party/spirv-tools/tools/stats/spirv_stats.h b/third_party/spirv-tools/tools/stats/spirv_stats.h deleted file mode 100644 index 16e720fe31..0000000000 --- a/third_party/spirv-tools/tools/stats/spirv_stats.h +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright (c) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef TOOLS_STATS_SPIRV_STATS_H_ -#define TOOLS_STATS_SPIRV_STATS_H_ - -#include -#include -#include -#include -#include - -#include "spirv-tools/libspirv.hpp" - -namespace spvtools { -namespace stats { - -struct SpirvStats { - // Version histogram, version_word -> count. - std::unordered_map version_hist; - - // Generator histogram, generator_word -> count. - std::unordered_map generator_hist; - - // Capability histogram, SpvCapabilityXXX -> count. - std::unordered_map capability_hist; - - // Extension histogram, extension_string -> count. - std::unordered_map extension_hist; - - // Opcode histogram, SpvOpXXX -> count. - std::unordered_map opcode_hist; - - // OpConstant u16 histogram, value -> count. - std::unordered_map u16_constant_hist; - - // OpConstant u32 histogram, value -> count. - std::unordered_map u32_constant_hist; - - // OpConstant u64 histogram, value -> count. - std::unordered_map u64_constant_hist; - - // OpConstant s16 histogram, value -> count. - std::unordered_map s16_constant_hist; - - // OpConstant s32 histogram, value -> count. - std::unordered_map s32_constant_hist; - - // OpConstant s64 histogram, value -> count. - std::unordered_map s64_constant_hist; - - // OpConstant f32 histogram, value -> count. - std::unordered_map f32_constant_hist; - - // OpConstant f64 histogram, value -> count. - std::unordered_map f64_constant_hist; - - // Used to collect statistics on opcodes triggering other opcodes. - // Container scheme: gap between instructions -> cue opcode -> later opcode - // -> count. - // For example opcode_markov_hist[2][OpFMul][OpFAdd] corresponds to - // the number of times an OpMul appears, followed by 2 other instructions, - // followed by OpFAdd. - // opcode_markov_hist[0][OpFMul][OpFAdd] corresponds to how many times - // OpFMul appears, directly followed by OpFAdd. - // The size of the outer std::vector also serves as an input parameter, - // determining how many steps will be collected. - // I.e. do opcode_markov_hist.resize(1) to collect data for one step only. - std::vector< - std::unordered_map>> - opcode_markov_hist; -}; - -// Aggregates existing |stats| with new stats extracted from |binary|. -spv_result_t AggregateStats(const spv_context_t& context, const uint32_t* words, - const size_t num_words, spv_diagnostic* pDiagnostic, - SpirvStats* stats); - -} // namespace stats -} // namespace spvtools - -#endif // TOOLS_STATS_SPIRV_STATS_H_ diff --git a/third_party/spirv-tools/tools/stats/stats.cpp b/third_party/spirv-tools/tools/stats/stats.cpp deleted file mode 100644 index 256ec1e1b9..0000000000 --- a/third_party/spirv-tools/tools/stats/stats.cpp +++ /dev/null @@ -1,180 +0,0 @@ -// Copyright (c) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include -#include -#include -#include -#include - -#include "source/table.h" -#include "spirv-tools/libspirv.h" -#include "tools/io.h" -#include "tools/stats/spirv_stats.h" -#include "tools/stats/stats_analyzer.h" - -namespace { - -struct ScopedContext { - ScopedContext(spv_target_env env) : context(spvContextCreate(env)) {} - ~ScopedContext() { spvContextDestroy(context); } - spv_context context; -}; - -void PrintUsage(char* argv0) { - printf( - R"(%s - Collect statistics from one or more SPIR-V binary file(s). - -USAGE: %s [options] [] - -TIP: In order to collect statistics from all .spv files under current dir use -find . -name "*.spv" -print0 | xargs -0 -s 2000000 %s - -Options: - -h, --help - Print this help. - - -v, --verbose - Print additional info to stderr. -)", - argv0, argv0, argv0); -} - -void DiagnosticsMessageHandler(spv_message_level_t level, const char*, - const spv_position_t& position, - const char* message) { - switch (level) { - case SPV_MSG_FATAL: - case SPV_MSG_INTERNAL_ERROR: - case SPV_MSG_ERROR: - std::cerr << "error: " << position.index << ": " << message << std::endl; - break; - case SPV_MSG_WARNING: - std::cout << "warning: " << position.index << ": " << message - << std::endl; - break; - case SPV_MSG_INFO: - std::cout << "info: " << position.index << ": " << message << std::endl; - break; - default: - break; - } -} - -} // namespace - -int main(int argc, char** argv) { - bool continue_processing = true; - int return_code = 0; - - bool expect_output_path = false; - bool verbose = false; - - std::vector paths; - const char* output_path = nullptr; - - for (int argi = 1; continue_processing && argi < argc; ++argi) { - const char* cur_arg = argv[argi]; - if ('-' == cur_arg[0]) { - if (0 == strcmp(cur_arg, "--help") || 0 == strcmp(cur_arg, "-h")) { - PrintUsage(argv[0]); - continue_processing = false; - return_code = 0; - } else if (0 == strcmp(cur_arg, "--verbose") || - 0 == strcmp(cur_arg, "-v")) { - verbose = true; - } else if (0 == strcmp(cur_arg, "--output") || - 0 == strcmp(cur_arg, "-o")) { - expect_output_path = true; - } else { - PrintUsage(argv[0]); - continue_processing = false; - return_code = 1; - } - } else { - if (expect_output_path) { - output_path = cur_arg; - expect_output_path = false; - } else { - paths.push_back(cur_arg); - } - } - } - - // Exit if command line parsing was not successful. - if (!continue_processing) { - return return_code; - } - - std::cerr << "Processing " << paths.size() << " files..." << std::endl; - - ScopedContext ctx(SPV_ENV_UNIVERSAL_1_1); - spvtools::SetContextMessageConsumer(ctx.context, DiagnosticsMessageHandler); - - spvtools::stats::SpirvStats stats; - stats.opcode_markov_hist.resize(1); - - for (size_t index = 0; index < paths.size(); ++index) { - const size_t kMilestonePeriod = 1000; - if (verbose) { - if (index % kMilestonePeriod == kMilestonePeriod - 1) - std::cerr << "Processed " << index + 1 << " files..." << std::endl; - } - - const char* path = paths[index]; - std::vector contents; - if (!ReadFile(path, "rb", &contents)) return 1; - - if (SPV_SUCCESS != - spvtools::stats::AggregateStats(*ctx.context, contents.data(), - contents.size(), nullptr, &stats)) { - std::cerr << "error: Failed to aggregate stats for " << path << std::endl; - return 1; - } - } - - spvtools::stats::StatsAnalyzer analyzer(stats); - - std::ofstream fout; - if (output_path) { - fout.open(output_path); - if (!fout.is_open()) { - std::cerr << "error: Failed to open " << output_path << std::endl; - return 1; - } - } - - std::ostream& out = fout.is_open() ? fout : std::cout; - out << std::endl; - analyzer.WriteVersion(out); - analyzer.WriteGenerator(out); - - out << std::endl; - analyzer.WriteCapability(out); - - out << std::endl; - analyzer.WriteExtension(out); - - out << std::endl; - analyzer.WriteOpcode(out); - - out << std::endl; - analyzer.WriteOpcodeMarkov(out); - - out << std::endl; - analyzer.WriteConstantLiterals(out); - - return 0; -} diff --git a/third_party/spirv-tools/tools/stats/stats_analyzer.cpp b/third_party/spirv-tools/tools/stats/stats_analyzer.cpp deleted file mode 100644 index 6d4cabbf6d..0000000000 --- a/third_party/spirv-tools/tools/stats/stats_analyzer.cpp +++ /dev/null @@ -1,235 +0,0 @@ -// Copyright (c) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "tools/stats/stats_analyzer.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "source/comp/markv_model.h" -#include "source/enum_string_mapping.h" -#include "source/latest_version_spirv_header.h" -#include "source/opcode.h" -#include "source/operand.h" -#include "source/spirv_constant.h" - -namespace spvtools { -namespace stats { -namespace { - -// Signals that the value is not in the coding scheme and a fallback method -// needs to be used. -const uint64_t kMarkvNoneOfTheAbove = - comp::MarkvModel::GetMarkvNoneOfTheAbove(); - -std::string GetVersionString(uint32_t word) { - std::stringstream ss; - ss << "Version " << SPV_SPIRV_VERSION_MAJOR_PART(word) << "." - << SPV_SPIRV_VERSION_MINOR_PART(word); - return ss.str(); -} - -std::string GetGeneratorString(uint32_t word) { - return spvGeneratorStr(SPV_GENERATOR_TOOL_PART(word)); -} - -std::string GetOpcodeString(uint32_t word) { - return spvOpcodeString(static_cast(word)); -} - -std::string GetCapabilityString(uint32_t word) { - return CapabilityToString(static_cast(word)); -} - -template -std::string KeyIsLabel(T key) { - std::stringstream ss; - ss << key; - return ss.str(); -} - -template -std::unordered_map GetRecall( - const std::unordered_map& hist, uint64_t total) { - std::unordered_map freq; - for (const auto& pair : hist) { - const double frequency = - static_cast(pair.second) / static_cast(total); - freq.emplace(pair.first, frequency); - } - return freq; -} - -template -std::unordered_map GetPrevalence( - const std::unordered_map& hist) { - uint64_t total = 0; - for (const auto& pair : hist) { - total += pair.second; - } - - return GetRecall(hist, total); -} - -// Writes |freq| to |out| sorted by frequency in the following format: -// LABEL3 70% -// LABEL1 20% -// LABEL2 10% -// |label_from_key| is used to convert |Key| to label. -template -void WriteFreq(std::ostream& out, const std::unordered_map& freq, - std::string (*label_from_key)(Key)) { - std::vector> sorted_freq(freq.begin(), freq.end()); - std::sort(sorted_freq.begin(), sorted_freq.end(), - [](const std::pair& left, - const std::pair& right) { - return left.second > right.second; - }); - - for (const auto& pair : sorted_freq) { - if (pair.second < 0.001) break; - out << label_from_key(pair.first) << " " << pair.second * 100.0 << "%" - << std::endl; - } -} - -} // namespace - -StatsAnalyzer::StatsAnalyzer(const SpirvStats& stats) : stats_(stats) { - num_modules_ = 0; - for (const auto& pair : stats_.version_hist) { - num_modules_ += pair.second; - } - - version_freq_ = GetRecall(stats_.version_hist, num_modules_); - generator_freq_ = GetRecall(stats_.generator_hist, num_modules_); - capability_freq_ = GetRecall(stats_.capability_hist, num_modules_); - extension_freq_ = GetRecall(stats_.extension_hist, num_modules_); - opcode_freq_ = GetPrevalence(stats_.opcode_hist); -} - -void StatsAnalyzer::WriteVersion(std::ostream& out) { - WriteFreq(out, version_freq_, GetVersionString); -} - -void StatsAnalyzer::WriteGenerator(std::ostream& out) { - WriteFreq(out, generator_freq_, GetGeneratorString); -} - -void StatsAnalyzer::WriteCapability(std::ostream& out) { - WriteFreq(out, capability_freq_, GetCapabilityString); -} - -void StatsAnalyzer::WriteExtension(std::ostream& out) { - WriteFreq(out, extension_freq_, KeyIsLabel); -} - -void StatsAnalyzer::WriteOpcode(std::ostream& out) { - out << "Total unique opcodes used: " << opcode_freq_.size() << std::endl; - WriteFreq(out, opcode_freq_, GetOpcodeString); -} - -void StatsAnalyzer::WriteConstantLiterals(std::ostream& out) { - out << "Constant literals" << std::endl; - - out << "Float 32" << std::endl; - WriteFreq(out, GetPrevalence(stats_.f32_constant_hist), KeyIsLabel); - - out << std::endl << "Float 64" << std::endl; - WriteFreq(out, GetPrevalence(stats_.f64_constant_hist), KeyIsLabel); - - out << std::endl << "Unsigned int 16" << std::endl; - WriteFreq(out, GetPrevalence(stats_.u16_constant_hist), KeyIsLabel); - - out << std::endl << "Signed int 16" << std::endl; - WriteFreq(out, GetPrevalence(stats_.s16_constant_hist), KeyIsLabel); - - out << std::endl << "Unsigned int 32" << std::endl; - WriteFreq(out, GetPrevalence(stats_.u32_constant_hist), KeyIsLabel); - - out << std::endl << "Signed int 32" << std::endl; - WriteFreq(out, GetPrevalence(stats_.s32_constant_hist), KeyIsLabel); - - out << std::endl << "Unsigned int 64" << std::endl; - WriteFreq(out, GetPrevalence(stats_.u64_constant_hist), KeyIsLabel); - - out << std::endl << "Signed int 64" << std::endl; - WriteFreq(out, GetPrevalence(stats_.s64_constant_hist), KeyIsLabel); -} - -void StatsAnalyzer::WriteOpcodeMarkov(std::ostream& out) { - if (stats_.opcode_markov_hist.empty()) return; - - const std::unordered_map>& - cue_to_hist = stats_.opcode_markov_hist[0]; - - // Sort by prevalence of the opcodes in opcode_freq_ (descending). - std::vector>> - sorted_cue_to_hist(cue_to_hist.begin(), cue_to_hist.end()); - std::sort( - sorted_cue_to_hist.begin(), sorted_cue_to_hist.end(), - [this](const std::pair>& - left, - const std::pair>& - right) { - const double lf = opcode_freq_[left.first]; - const double rf = opcode_freq_[right.first]; - if (lf == rf) return right.first > left.first; - return lf > rf; - }); - - for (const auto& kv : sorted_cue_to_hist) { - const uint32_t cue = kv.first; - const double kFrequentEnoughToAnalyze = 0.0001; - if (opcode_freq_[cue] < kFrequentEnoughToAnalyze) continue; - - const std::unordered_map& hist = kv.second; - - uint32_t total = 0; - for (const auto& pair : hist) { - total += pair.second; - } - - std::vector> sorted_hist(hist.begin(), - hist.end()); - std::sort(sorted_hist.begin(), sorted_hist.end(), - [](const std::pair& left, - const std::pair& right) { - if (left.second == right.second) - return right.first > left.first; - return left.second > right.second; - }); - - for (const auto& pair : sorted_hist) { - const double prior = opcode_freq_[pair.first]; - const double posterior = - static_cast(pair.second) / static_cast(total); - out << GetOpcodeString(cue) << " -> " << GetOpcodeString(pair.first) - << " " << posterior * 100 << "% (base rate " << prior * 100 - << "%, pair occurrences " << pair.second << ")" << std::endl; - } - } -} - -} // namespace stats -} // namespace spvtools diff --git a/third_party/spirv-tools/tools/stats/stats_analyzer.h b/third_party/spirv-tools/tools/stats/stats_analyzer.h deleted file mode 100644 index f1c37bfaa0..0000000000 --- a/third_party/spirv-tools/tools/stats/stats_analyzer.h +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) 2017 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef TOOLS_STATS_STATS_ANALYZER_H_ -#define TOOLS_STATS_STATS_ANALYZER_H_ - -#include -#include - -#include "tools/stats/spirv_stats.h" - -namespace spvtools { -namespace stats { - -class StatsAnalyzer { - public: - explicit StatsAnalyzer(const SpirvStats& stats); - - // Writes respective histograms to |out|. - void WriteVersion(std::ostream& out); - void WriteGenerator(std::ostream& out); - void WriteCapability(std::ostream& out); - void WriteExtension(std::ostream& out); - void WriteOpcode(std::ostream& out); - void WriteConstantLiterals(std::ostream& out); - - // Writes first order Markov analysis to |out|. - // stats_.opcode_markov_hist needs to contain raw data for at least one - // level. - void WriteOpcodeMarkov(std::ostream& out); - - private: - const SpirvStats& stats_; - - uint32_t num_modules_; - - std::unordered_map version_freq_; - std::unordered_map generator_freq_; - std::unordered_map capability_freq_; - std::unordered_map extension_freq_; - std::unordered_map opcode_freq_; -}; - -} // namespace stats -} // namespace spvtools - -#endif // TOOLS_STATS_STATS_ANALYZER_H_ diff --git a/third_party/spirv-tools/tools/sva/.eslintrc.json b/third_party/spirv-tools/tools/sva/.eslintrc.json new file mode 100644 index 0000000000..2f07726782 --- /dev/null +++ b/third_party/spirv-tools/tools/sva/.eslintrc.json @@ -0,0 +1,25 @@ +{ + "env": { + "browser": true, + "es6": true, + "node": true, + "mocha": true + }, + "extends": "eslint:recommended", + "parserOptions": { + "ecmaVersion": 2018, + "sourceType": "module" + }, + "rules": { + "block-scoped-var": "error", + "consistent-return": "error", + "eqeqeq": ["error", "always"], + "indent": [ "error", 2 ], + "linebreak-style": [ "error", "unix" ], + "no-eval": "error", + "no-shadow": "error", + "no-shadow-restricted-names": "error", + "quotes": [ "error", "double" ], + "semi": [ "error", "always" ] + } +} diff --git a/third_party/spirv-tools/tools/sva/.gitignore b/third_party/spirv-tools/tools/sva/.gitignore new file mode 100644 index 0000000000..88e64c381d --- /dev/null +++ b/third_party/spirv-tools/tools/sva/.gitignore @@ -0,0 +1,6 @@ +.DS_Store +node_modules +third_party/spirv-headers +o.sva +build +yarn-error.log diff --git a/third_party/spirv-tools/tools/sva/README.md b/third_party/spirv-tools/tools/sva/README.md new file mode 100644 index 0000000000..d80b4d2c3a --- /dev/null +++ b/third_party/spirv-tools/tools/sva/README.md @@ -0,0 +1,41 @@ +# SVA + +SPIR-V Assember for WebGPU. The SPIR-V Assembler is a JavaScript library to +convert SPIR-V assembly (as produced by spirv-dis in SPIR-V Tools) into a +SPIR-V binary. The assembler assumes it is generating WebGPU SPIR-V and thus has +the following limitations. + + * Only 32 bit integers and floats supported + * Only GLSL accepted as an extended instruction set + * Doesn't support ! syntax for integers + * Doesn't support hex encoding for float + +```shell +yarn install +yarn test +``` + +You can also use `yarn watch` to watch all of the files and re-run tests as +needed. + +## Webserver +Using `yarn serve` will start a webserver on localhost:5000. If you load the +`tests/index.html` file this will load the SVA files into browser. + +## Command Line +There is a simple assembler binary with can be executed from the command line. + +```shell +yarn sva tests/simple.spv_asm +``` + +The above will generate a `o.sva` file in the current directory. + +## Update spirv.data.json + +If there is a new spirv-headers release update the externals folder checkout +and then: + +```shell +./tools/process_grammar.rb > src/spirv.data.json +``` diff --git a/third_party/spirv-tools/tools/sva/bin/sva.js b/third_party/spirv-tools/tools/sva/bin/sva.js new file mode 100755 index 0000000000..e2448d6ef4 --- /dev/null +++ b/third_party/spirv-tools/tools/sva/bin/sva.js @@ -0,0 +1,32 @@ +#!/usr/bin/env node +// +// Copyright 2019 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. + +"use strict"; + +const fs = require("fs"); + +import SVA from "../src/sva.js"; + +let input = fs.readFileSync(process.argv[2], "utf-8"); +let u = SVA.assemble(input); + +if (typeof u === "string") { + console.log(u); +} else { + fs.writeFileSync("o.sva", new Buffer(u.buffer), (err) => { + console.log(["ERROR", err]); + }); +} diff --git a/third_party/spirv-tools/tools/sva/mocha.opts b/third_party/spirv-tools/tools/sva/mocha.opts new file mode 100644 index 0000000000..4a52320178 --- /dev/null +++ b/third_party/spirv-tools/tools/sva/mocha.opts @@ -0,0 +1 @@ +--recursive diff --git a/third_party/spirv-tools/tools/sva/package.json b/third_party/spirv-tools/tools/sva/package.json new file mode 100644 index 0000000000..3072d4cc86 --- /dev/null +++ b/third_party/spirv-tools/tools/sva/package.json @@ -0,0 +1,25 @@ +{ + "name": "sva", + "version": "0.1.0", + "description": "SPIR-V Assembler", + "main": "index.js", + "author": "dan sinclair ", + "license": "Apache-2.0", + "private": true, + "scripts": { + "sva": "node -r esm bin/sva.js", + "lint": "eslint --fix --ext .js .", + "test": "mocha --require esm src/**/*_test.js", + "watch": "mocha --require esm --watch --watch-extension js \"src/**/*_test.js\"", + "serve": "serve", + "bundle": "rollup -c" + }, + "devDependencies": { + "chai": "^4.2.0", + "eslint": "^6.3.0", + "esm": "^3.2.25", + "mocha": "^6.2.0", + "rollup": "^1.21.4", + "serve": "^11.1.0" + } +} diff --git a/third_party/spirv-tools/tools/sva/rollup.config.js b/third_party/spirv-tools/tools/sva/rollup.config.js new file mode 100644 index 0000000000..2056e16e58 --- /dev/null +++ b/third_party/spirv-tools/tools/sva/rollup.config.js @@ -0,0 +1,7 @@ +export default { + input: 'src/sva.js', + output: { + file: 'build/sva.js', + format: 'esm', + } +} diff --git a/third_party/spirv-tools/tools/sva/src/assembler.js b/third_party/spirv-tools/tools/sva/src/assembler.js new file mode 100644 index 0000000000..7bc208ec14 --- /dev/null +++ b/third_party/spirv-tools/tools/sva/src/assembler.js @@ -0,0 +1,98 @@ +// Copyright 2019 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. + +export default class Assembler { + static get GENERATOR_ID() { return 0; } + + /** + * @param {AST} the AST to build the SPIR-V from + */ + constructor(ast) { + this.ast_ = ast; + } + + /** + * Assembles the AST into binary SPIR-V. + * @return {Uint32Array} The SPIR-V binary data. + */ + assemble() { + let total_size = 5; + for (const inst of this.ast_.instructions()) { + total_size += 1; + for (const op of inst.operands()) { + total_size += op.length(); + } + } + + let u = new Uint32Array(total_size); + u[0] = 0x07230203; // Magic + u[1] = 0x00010500; // Version 1.5 + u[2] = Assembler.GENERATOR_ID; // Generator magic number + u[3] = this.ast_.getIdBounds(); // ID bounds + u[4] = 0; // Reserved + + let idx = 5; + for (const inst of this.ast_.instructions()) { + let op_size = 1; + for (const op of inst.operands()) { + op_size += op.length(); + } + + u[idx++] = op_size << 16 | inst.opcode(); + for (const op of inst.operands()) { + idx = this.processOp(u, idx, op); + } + } + + return u; + } + + processOp(u, idx, op) { + if (op.type() === "string") { + let len = 0; + let v = 0; + for (const ch of op.value()) { + v = v | (ch.charCodeAt(0) << (len * 8)); + len += 1; + + if (len === 4) { + u[idx++] = v; + len = 0; + v = 0; + } + } + // Make sure either the terminating 0 byte is written or the last + // partial word is written. + u[idx++] = v; + + } else if (op.type() === "float") { + // TODO(dsinclair): Handle 64 bit floats ... + let b = new ArrayBuffer(4); + let f = new Float32Array(b); + f[0] = op.value(); + + let u2 = new Uint32Array(b); + + u[idx++] = u2[0]; + } else { + u[idx++] = op.value(); + } + + for (const param of op.params()) { + idx = this.processOp(u, idx, param); + } + + return idx; + } +} diff --git a/third_party/spirv-tools/tools/sva/src/assembler_test.js b/third_party/spirv-tools/tools/sva/src/assembler_test.js new file mode 100644 index 0000000000..a23d211da5 --- /dev/null +++ b/third_party/spirv-tools/tools/sva/src/assembler_test.js @@ -0,0 +1,165 @@ +// Copyright 2019 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. + +import { assert } from "chai"; +import Lexer from "./lexer"; +import Parser from "./parser"; +import grammar from "./spirv.data.js"; +import Assembler from "./assembler"; + +describe("assembler", () => { + it("generates SPIR-V magic number", () => { + let input = `; SPIR-V +; Version: 1.0 +; Generator: Khronos Glslang Reference Front End; 7 +; Bound: 6 +; Schema: 0 + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" + OpExecutionMode %main OriginUpperLeft + OpSource GLSL 440 + OpName %main "main" + %void = OpTypeVoid + %3 = OpTypeFunction %void + %main = OpFunction %void None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd`; + let l = new Lexer(input); + let p = new Parser(grammar, l); + + let ast = p.parse(); + assert.exists(ast, p.error); + + let a = new Assembler(ast); + let res = a.assemble(); + assert.equal(res[0], 0x07230203); + }); + + it("assembles enumerant params", () => { + let input = "OpExecutionMode %main LocalSize 2 3 4"; + + let l = new Lexer(input); + let p = new Parser(grammar, l); + + let ast = p.parse(); + assert.exists(ast, p.error); + + let a = new Assembler(ast); + let res = a.assemble(); + + assert.lengthOf(res, 11); + assert.equal(res[5], (6 /* word count */ << 16) | 16 /* opcode */); + assert.equal(res[6], 1 /* %main */); + assert.equal(res[7], 17 /* LocalSize */); + assert.equal(res[8], 2); + assert.equal(res[9], 3); + assert.equal(res[10], 4); + }); + + it("assembles float 32 values", () => { + let input = `%float = OpTypeFloat 32 + %float1 = OpConstant %float 0.400000006`; + let l = new Lexer(input); + let p = new Parser(grammar, l); + + let ast = p.parse(); + assert.exists(ast, p.error); + + let a = new Assembler(ast); + let res = a.assemble(); + + assert.lengthOf(res, 12); + assert.equal(res[8], (4 /* word count */ << 16) | 43 /* opcode */); + assert.equal(res[9], 1 /* %float */); + assert.equal(res[10], 2 /* %float */); + assert.equal(res[11], 0x3ecccccd /* 0.400000006 */); + }); + + describe("strings", () => { + it("assembles 'abcd'", () => { + let input = `OpName %mains "abcd"`; + let l = new Lexer(input); + let p = new Parser(grammar, l); + + let ast = p.parse(); + assert.exists(ast, p.error); + + let a = new Assembler(ast); + let res = a.assemble(); + + assert.lengthOf(res, 9); + assert.equal(res[5], (4 /* word count */ << 16) | 5 /* opcode */); + assert.equal(res[6], 1 /* %mains */); + assert.equal(res[7], 0x64636261 /* food */); + assert.equal(res[8], 0x00000000 /* null byte */); + }); + + it("assembles 'abcde'", () => { + let input = `OpName %mains "abcde"`; + let l = new Lexer(input); + let p = new Parser(grammar, l); + + let ast = p.parse(); + assert.exists(ast, p.error); + + let a = new Assembler(ast); + let res = a.assemble(); + + assert.lengthOf(res, 9); + assert.equal(res[5], (4 /* word count */ << 16) | 5 /* opcode */); + assert.equal(res[6], 1 /* %mains */); + assert.equal(res[7], 0x64636261 /* abcd */); + assert.equal(res[8], 0x00000065 /* e */); + }); + + it("assembles 'abcdef'", () => { + let input = `OpName %mains "abcdef"`; + let l = new Lexer(input); + let p = new Parser(grammar, l); + + let ast = p.parse(); + assert.exists(ast, p.error); + + let a = new Assembler(ast); + let res = a.assemble(); + + assert.lengthOf(res, 9); + assert.equal(res[5], (4 /* word count */ << 16) | 5 /* opcode */); + assert.equal(res[6], 1 /* %mains */); + assert.equal(res[7], 0x64636261 /* abcd */); + assert.equal(res[8], 0x00006665 /* ef */); + }); + + it("assembles 'abcdefg'", () => { + let input = `OpName %mains "abcdefg"`; + let l = new Lexer(input); + let p = new Parser(grammar, l); + + let ast = p.parse(); + assert.exists(ast, p.error); + + let a = new Assembler(ast); + let res = a.assemble(); + + assert.lengthOf(res, 9); + assert.equal(res[5], (4 /* word count */ << 16) | 5 /* opcode */); + assert.equal(res[6], 1 /* %mains */); + assert.equal(res[7], 0x64636261 /* abcd */); + assert.equal(res[8], 0x00676665 /* efg */); + }); + }); +}); diff --git a/third_party/spirv-tools/tools/sva/src/ast.js b/third_party/spirv-tools/tools/sva/src/ast.js new file mode 100644 index 0000000000..d396d2fb6d --- /dev/null +++ b/third_party/spirv-tools/tools/sva/src/ast.js @@ -0,0 +1,141 @@ +// Copyright 2019 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. + +class Module { + constructor() { + this.instructions_ = []; + this.next_id_ = 1; + + /** + * Maps {string, hash} where the string is the type name and the hash is: + * type- 'float' or 'int' + * width- number of bits needed to store number + * signed- the sign of the number + */ + this.types_ = {}; + + /** + * Maps {string, number} where the string is the type name and the number is + * the id value. + */ + this.assigned_ids_ = {}; + } + + instructions() { return this.instructions_; } + + instruction(val) { return this.instructions_[val]; } + + addInstruction(inst) { + this.instructions_.push(inst); + + // Record type information + if (inst.name() === "OpTypeInt" || inst.name() === "OpTypeFloat") { + let is_int = inst.name() === "OpTypeInt"; + + this.types_[inst.operand(0).name()] = { + type: is_int ? "int" : "float", + width: inst.operand(1).value(), + signed: is_int ? inst.operand(2).value() : 1 + }; + } + + // Record operand result id's + inst.operands().forEach((op) => { + if (op.rawValue() !== undefined && op.type() === "result_id") { + this.next_id_ = Math.max(this.next_id_, op.rawValue() + 1); + } + }); + } + + getType(name) { return this.types_[name]; } + + getId(name) { + if (this.assigned_ids_[name] !== undefined) { + return this.assigned_ids_[name]; + } + + let next = this.next_id_; + this.assigned_ids_[name] = next; + + this.next_id_ += 1; + return next; + } + + getIdBounds() { return this.next_id_; } +} + +class Instruction { + constructor(name, opcode, operands) { + this.name_ = name; + this.opcode_ = opcode; + this.operands_ = operands; + } + + name() { return this.name_; } + + opcode() { return this.opcode_; } + + operands() { return this.operands_; } + + operand(val) { return this.operands_[val]; } +} + +class Operand { + constructor(mod, name, type, value, params) { + this.module_ = mod; + this.name_ = name; + this.type_ = type; + this.value_ = value; + this.params_ = params; + } + + name() { return this.name_; } + + length() { + // Get the value just to force it to be filled. + this.value(); + + if (this.type_ === "string") { + return Math.ceil((this.value_.length + 1) / 4); + } + + let size = 1; + for (const param of this.params_) { + size += param.length(); + } + return size; + } + + type() { return this.type_; } + + rawValue() { return this.value_; } + + // This method should only be called on ResultId's after the full parse is + // complete. This is because the AST will only have the maximum seen numeric + // ResultId when the parse is done. + value() { + if (this.value_ === undefined) { + this.value_ = this.module_.getId(this.name_); + } + return this.value_; + } + + params() { return this.params_; } +} + +export { + Module, + Instruction, + Operand +}; diff --git a/third_party/spirv-tools/tools/sva/src/lexer.js b/third_party/spirv-tools/tools/sva/src/lexer.js new file mode 100644 index 0000000000..b39f93a029 --- /dev/null +++ b/third_party/spirv-tools/tools/sva/src/lexer.js @@ -0,0 +1,363 @@ +// Copyright 2019 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. + +import { Token, TokenType } from "./token.js"; + +export default class Lexer { + /** + * @param {String} input The input string to tokenize. + */ + constructor(input) { + this.input_ = input; + this.len_ = input.length; + this.cur_pos_ = 0; + this.cur_line_ = 1; + + this.num_regex_ = /^[0-9]+$/; + this.alpha_regex_ = /^[a-zA-Z_]+$/; + this.op_regex_ = /^Op[A-Z][^\s]*$/; + this.hex_regex_ = /^[0-9a-fA-F]$/; + } + + /** + * Parses the next token from the input stream. + * @return {Token} the next token. + */ + next() { + this.skipWhitespace(); + this.skipComments(); + + if (this.cur_pos_ >= this.len_) + return new Token(TokenType.kEOF, this.cur_line_); + + let n = this.tryHexInteger(); + if (n !== undefined) + return n; + + n = this.tryFloat(); + if (n !== undefined) + return n; + + n = this.tryInteger(); + if (n !== undefined) + return n; + + n = this.tryString(); + if (n !== undefined) + return n; + + n = this.tryOp(); + if (n !== undefined) + return n; + + n = this.tryPunctuation(); + if (n !== undefined) + return n; + + n = this.tryResultId(); + if (n !== undefined) + return n; + + n = this.tryIdent(); + if (n !== undefined) + return n; + + return new Token(TokenType.kError, this.cur_line_, "Failed to match token"); + } + + is(str) { + if (this.len_ <= this.cur_pos_ + (str.length - 1)) + return false; + + for (let i = 0; i < str.length; ++i) { + if (this.input_[this.cur_pos_ + i] !== str[i]) + return false; + } + + return true; + } + + isNum(ch) { + return ch.match(this.num_regex_); + } + + isAlpha(ch) { + return ch.match(this.alpha_regex_); + } + + isAlphaNum(ch) { + return this.isNum(ch) || this.isAlpha(ch); + } + + isHex(char) { + return char.match(this.hex_regex_); + } + + isCurWhitespace() { + return this.is(" ") || this.is("\t") || this.is("\r") || this.is("\n"); + } + + skipWhitespace() { + for(;;) { + let cur_pos = this.cur_pos_; + while (this.cur_pos_ < this.len_ && + this.isCurWhitespace()) { + if (this.is("\n")) + this.cur_line_ += 1; + + this.cur_pos_ += 1; + } + + this.skipComments(); + + // Cursor didn't move so no whitespace matched. + if (cur_pos === this.cur_pos_) + break; + } + } + + skipComments() { + if (!this.is(";")) + return; + + while (this.cur_pos_ < this.len_ && !this.is("\n")) + this.cur_pos_ += 1; + } + + /** + * Attempt to parse the next part of the input as a float. + * @return {Token|undefined} returns a Token if a float is matched, + * undefined otherwise. + */ + tryFloat() { + let start = this.cur_pos_; + let end = start; + + if (this.cur_pos_ >= this.len_) + return undefined; + if (this.input_[end] === "-") + end += 1; + + while (end < this.len_ && this.isNum(this.input_[end])) + end += 1; + + // Must have a "." in a float + if (end >= this.len_ || this.input_[end] !== ".") + return undefined; + + end += 1; + while (end < this.len_ && this.isNum(this.input_[end])) + end += 1; + + let substr = this.input_.substr(start, end - start); + if (substr === "." || substr === "-.") + return undefined; + + this.cur_pos_ = end; + + return new Token(TokenType.kFloatLiteral, this.cur_line_, parseFloat(substr)); + } + + /** + * Attempt to parse a hex encoded integer. + * @return {Token|undefined} returns a Token if a Hex number is matched, + * undefined otherwise. + */ + tryHexInteger() { + let start = this.cur_pos_; + let end = start; + + if (this.cur_pos_ >= this.len_) + return undefined; + if (end + 2 >= this.len_ || this.input_[end] !== "0" || + this.input_[end + 1] !== "x") { + return undefined; + } + + end += 2; + + while (end < this.len_ && this.isHex(this.input_[end])) + end += 1; + + this.cur_pos_ = end; + + let val = parseInt(this.input_.substr(start, end - start), 16); + return new Token(TokenType.kIntegerLiteral, this.cur_line_, val); + } + + /** + * Attempt to parse an encoded integer. + * @return {Token|undefined} returns a Token if a number is matched, + * undefined otherwise. + */ + tryInteger() { + let start = this.cur_pos_; + let end = start; + + if (this.cur_pos_ >= this.len_) + return undefined; + if (this.input_[end] === "-") + end += 1; + + if (end >= this.len_ || !this.isNum(this.input_[end])) + return undefined; + + while (end < this.len_ && this.isNum(this.input_[end])) + end += 1; + + this.cur_pos_ = end; + + let val = parseInt(this.input_.substr(start, end - start), 10); + return new Token(TokenType.kIntegerLiteral, this.cur_line_, val); + } + + /** + * Attempt to parse a result id. + * @return {Token|undefined} returns a Token if a result id is matched, + * undefined otherwise. + */ + tryResultId() { + let start = this.cur_pos_; + if (start >= this.len_) + return undefined; + if (!this.is("%")) + return undefined; + + start += 1; + this.cur_pos_ += 1; + while (this.cur_pos_ < this.len_ && + (this.isAlphaNum(this.input_[this.cur_pos_]) || this.is("_"))) { + this.cur_pos_ += 1; + } + + let ident = this.input_.substr(start, this.cur_pos_ - start); + let value = undefined; + if (ident.match(this.num_regex_)) + value = parseInt(ident, 10); + + return new Token(TokenType.kResultId, this.cur_line_, { + name: ident, + val: value + }); + } + + /** + * Attempt to parse an identifier. + * @return {Token|undefined} returns a Token if an identifier is matched, + * undefined otherwise. + */ + tryIdent() { + let start = this.cur_pos_; + if (start >= this.len_) + return undefined; + + while (this.cur_pos_ < this.len_ && + (this.isAlphaNum(this.input_[this.cur_pos_]) || this.is("_"))) { + this.cur_pos_ += 1; + } + + let ident = this.input_.substr(start, this.cur_pos_ - start); + return new Token(TokenType.kIdentifier, this.cur_line_, ident); + } + + /** + * Attempt to parse an Op command. + * @return {Token|undefined} returns a Token if an Op command is matched, + * undefined otherwise. + */ + tryOp() { + let start = this.cur_pos_; + if (this.cur_pos_ >= this.len_ || (this.cur_pos_ + 1 >= this.len_)) + return undefined; + + if (this.input_[this.cur_pos_] !== "O" || + this.input_[this.cur_pos_ + 1] !== "p") { + return undefined; + } + + while (this.cur_pos_ < this.len_ && + !this.isCurWhitespace()) { + this.cur_pos_ += 1; + } + + return new Token(TokenType.kOp, this.cur_line_, { + name: this.input_.substr(start, this.cur_pos_ - start) + }); + } + + /** + * Attempts to match punctuation strings against the input + * @return {Token|undefined} Returns the Token for the punctuation or + * undefined if no matches found. + */ + tryPunctuation() { + let type = undefined; + if (this.is("=")) + type = TokenType.kEqual; + else if (this.is("|")) + type = TokenType.kPipe; + + if (type === undefined) + return undefined; + + this.cur_pos_ += type.length; + return new Token(type, this.cur_line_, type); + } + + /** + * Attempts to match strings against the input + * @return {Token|undefined} Returns the Token for the string or undefined + * if no match found. + */ + tryString() { + let start = this.cur_pos_; + + // Must have at least 2 chars for a string. + if (this.cur_pos_ >= this.len_ || (this.cur_pos_ + 1 >= this.len_)) + return undefined; + if (!this.is("\"")) + return undefined; + + this.cur_pos_ += 1; + let str = ""; + while (this.cur_pos_ <= this.len_) { + if (this.is("\"")) + break; + + if (this.is("\\")) { + this.cur_pos_ += 1; + if (this.cur_pos_ >= this.len_) + return undefined; + + if (this.is("\\")) { + str += "\\"; + } else if (this.is("\"")) { + str += '"'; + } else { + str += this.input_[this.cur_pos_]; + } + } else { + str += this.input_[this.cur_pos_]; + } + this.cur_pos_ += 1; + } + + if (this.cur_pos_ >= this.len_) + return undefined; + + this.cur_pos_ += 1; + + return new Token(TokenType.kStringLiteral, this.cur_line_, str); + } +} diff --git a/third_party/spirv-tools/tools/sva/src/lexer_test.js b/third_party/spirv-tools/tools/sva/src/lexer_test.js new file mode 100644 index 0000000000..32b24c75aa --- /dev/null +++ b/third_party/spirv-tools/tools/sva/src/lexer_test.js @@ -0,0 +1,191 @@ +// Copyright 2019 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. + +import { assert } from "chai"; +import Lexer from "./lexer"; +import { TokenType } from "./token"; + +describe("lexer", () => { + describe("skipped content", () => { + it("skips whitespace", () => { + let input = " \t\r\n\t \tOpKill\t\n\t \r "; + let l = new Lexer(input); + + let t = l.next(); + assert.equal(t.type, TokenType.kOp); + assert.equal(t.line, 2); + assert.equal(t.data.name, "OpKill"); + + t = l.next(); + assert.equal(t.type, TokenType.kEOF); + assert.equal(t.line, 3); + }); + + it("skips ; comments", () => { + let input = `; start with comment +OpKill ; end of line comment +; another comment +%1`; + + let l = new Lexer(input); + let t = l.next(); + assert.equal(t.type, TokenType.kOp); + assert.equal(t.data.name, "OpKill"); + assert.equal(t.line, 2); + + t = l.next(); + assert.equal(t.type, TokenType.kResultId); + assert.equal(t.data.name, "1"); + assert.equal(t.data.val, 1); + assert.equal(t.line, 4); + }); + }); + + describe("numerics", () => { + it("parses floats", () => { + let input = ["0.0", "0.", ".0", "5.7", "5.", ".7", "-0.0", "-.0", + "-0.", "-5.7", "-5.", "-.7"]; + + let results = [0.0, 0.0, 0.0, 5.7, 5.0, 0.7, 0.0, 0.0, 0.0, -5.7, -5.0, + -0.7]; + input.forEach((val, idx) => { + let l = new Lexer(val); + let t = l.next(); + + assert.equal(t.type, TokenType.kFloatLiteral, + `expected ${val} to be a float got ${t.type}`); + assert.equal(t.data, results[idx], + `expected ${results[idx]} === ${t.data}`); + + t = l.next(); + assert.equal(t.type, TokenType.kEOF); + assert.equal(t.data, undefined); + }); + }); + + it("handles invalid floats", () => { + let input = [".", "-."]; + input.forEach((val) => { + let l = new Lexer(val); + let t = l.next(); + + assert.notEqual(t.type, TokenType.kFloatLiteral, + `expect ${val} to not match type float`); + }); + }); + + it("parses integers", () => { + let input = ["0", "-0", "123", "-123", "2147483647", "-2147483648", + "4294967295", "0x00", "0x24"]; + let results = [0, 0, 123, -123,2147483647, -2147483648, 4294967295, + 0x0, 0x24]; + + input.forEach((val, idx) => { + let l = new Lexer(val); + let t = l.next(); + + assert.equal(t.type, TokenType.kIntegerLiteral, + `expected ${val} to be an integer got ${t.type}`); + assert.equal(t.data, results[idx], + `expected ${results[idx]} === ${t.data}`); + + t = l.next(); + assert.equal(t.type, TokenType.kEOF); + assert.equal(t.data, undefined); + }); + }); + }); + + it("matches result_ids", () => { + let input = `%123 +%001 +%main +%_a_b_c`; + + let result = [ + {name: "123", val: 123}, + {name: "001", val: 1}, + {name: "main", val: undefined}, + {name: "_a_b_c", val: undefined} + ]; + + let l = new Lexer(input); + for (let i = 0; i < result.length; ++i) { + let t = l.next(); + assert.equal(t.type, TokenType.kResultId); + assert.equal(t.data.name, result[i].name); + assert.equal(t.data.val, result[i].val); + } + }); + + it("matches punctuation", () => { + let input = "="; + let results = [TokenType.kEqual]; + + let l = new Lexer(input); + for (let i = 0; i < results.length; ++i) { + let t = l.next(); + assert.equal(t.type, results[i]); + assert.equal(t.line, i + 1); + } + + let t = l.next(); + assert.equal(t.type, TokenType.kEOF); + }); + + describe("strings", () => { + it("matches strings", () => { + let input = "\"GLSL.std.450\""; + + let l = new Lexer(input); + let t = l.next(); + assert.equal(t.type, TokenType.kStringLiteral); + assert.equal(t.data, "GLSL.std.450"); + }); + + it("handles unfinished strings", () => { + let input = "\"GLSL.std.450"; + + let l = new Lexer(input); + let t = l.next(); + assert.equal(t.type, TokenType.kError); + }); + + it("handles escapes", () => { + let input = `"embedded\\"quote" +"embedded\\\\slash" +"embedded\\nchar"`; + let results = [`embedded\"quote`, `embedded\\slash`, `embeddednchar`]; + + let l = new Lexer(input); + for (let i = 0; i < results.length; ++i) { + let t = l.next(); + assert.equal(t.type, TokenType.kStringLiteral, results[i]); + assert.equal(t.data, results[i]); + } + }); + }); + + it("matches keywords", () => { + let input = "GLSL Function"; + let results = ["GLSL", "Function"]; + + let l = new Lexer(input); + for (let i = 0; i < results.length; ++i) { + let t = l.next(); + assert.equal(t.type, TokenType.kIdentifier, results[i]); + assert.equal(t.data, results[i]); + } + }); +}); diff --git a/third_party/spirv-tools/tools/sva/src/parser.js b/third_party/spirv-tools/tools/sva/src/parser.js new file mode 100644 index 0000000000..ccf872a110 --- /dev/null +++ b/third_party/spirv-tools/tools/sva/src/parser.js @@ -0,0 +1,283 @@ +// Copyright 2019 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. + +import { TokenType } from "./token.js"; +import * as AST from "./ast.js"; + +export default class Parser { + /** + * @param {Hash} The SPIR-V grammar + * @param {Lexer} The lexer + * @return {AST} Attempts to build an AST from the tokens returned by the + * given lexer + */ + constructor(grammar, lexer) { + this.grammar_ = grammar; + this.lexer_ = lexer; + + this.peek_ = []; + this.error_ = ""; + } + + get error() { return this.error_; } + + next() { + return this.peek_.shift() || this.lexer_.next(); + } + + peek(idx) { + while (this.peek_.length <= idx) { + this.peek_.push(this.lexer_.next()); + } + return this.peek_[idx]; + } + + /** + * Executes the parser. + * + * @return {AST|undefined} returns a parsed AST on success or undefined + * on error. The error message can be retrieved by + * calling error(). + */ + parse() { + let ast = new AST.Module(); + for(;;) { + let token = this.next(); + if (token === TokenType.kError) { + this.error_ = token.line() + ": " + token.data(); + return undefined; + } + if (token.type === TokenType.kEOF) + break; + + let result_id = undefined; + if (token.type === TokenType.kResultId) { + result_id = token; + + token = this.next(); + if (token.type !== TokenType.kEqual) { + this.error_ = token.line + ": expected = after result id"; + return undefined; + } + + token = this.next(); + } + + if (token.type !== TokenType.kOp) { + this.error_ = token.line + ": expected Op got " + token.type; + return undefined; + } + + let name = token.data.name; + let data = this.getInstructionData(name); + let operands = []; + let result_type = undefined; + + for (let operand of data.operands) { + if (operand.kind === "IdResult") { + if (result_id === undefined) { + this.error_ = token.line + ": expected result id"; + return undefined; + } + let o = new AST.Operand(ast, result_id.data.name, "result_id", + result_id.data.val, []); + if (o === undefined) { + return undefined; + } + operands.push(o); + } else { + if (operand.quantifier === "?") { + if (this.nextIsNewInstr()) { + break; + } + } else if (operand.quantifier === "*") { + while (!this.nextIsNewInstr()) { + let o = this.extractOperand(ast, result_type, operand); + if (o === undefined) { + return undefined; + } + operands.push(o); + } + break; + } + + let o = this.extractOperand(ast, result_type, operand); + if (o === undefined) { + return undefined; + } + + // Store the result type away so we can use it for context dependent + // numbers if needed. + if (operand.kind === "IdResultType") { + result_type = ast.getType(o.name()); + } + + operands.push(o); + } + } + + // Verify only GLSL extended instructions are used + if (name === "OpExtInstImport" && operands[1].value() !== "GLSL.std.450") { + this.error_ = token.line + ": Only GLSL.std.450 external instructions supported"; + return undefined; + } + + let inst = new AST.Instruction(name, data.opcode, operands); + + ast.addInstruction(inst); + } + return ast; + } + + getInstructionData(name) { + return this.grammar_["instructions"][name]; + } + + nextIsNewInstr() { + let n0 = this.peek(0); + if (n0.type === TokenType.kOp || n0.type === TokenType.kEOF) { + return true; + } + + let n1 = this.peek(1); + if (n1.type === TokenType.kEOF) { + return false; + } + if (n0.type === TokenType.kResultId && n1.type === TokenType.kEqual) + return true; + + return false; + } + + extractOperand(ast, result_type, data) { + let t = this.next(); + + let name = undefined; + let kind = undefined; + let value = undefined; + let params = []; + + // TODO(dsinclair): There are a bunch of missing types here. See + // https://github.com/KhronosGroup/SPIRV-Tools/blob/master/source/text.cpp#L210 + // + // LiteralSpecConstantOpInteger + // PairLiteralIntegerIdRef + // PairIdRefLiteralInteger + // PairIdRefIdRef + if (data.kind === "IdResult" || data.kind === "IdRef" + || data.kind === "IdResultType" || data.kind === "IdScope" + || data.kind === "IdMemorySemantics") { + if (t.type !== TokenType.kResultId) { + this.error_ = t.line + ": expected result id"; + return undefined; + } + + name = t.data.name; + kind = "result_id"; + value = t.data.val; + } else if (data.kind === "LiteralString") { + if (t.type !== TokenType.kStringLiteral) { + this.error_ = t.line + ": expected string not found"; + return undefined; + } + + name = t.data; + kind = "string"; + value = t.data; + } else if (data.kind === "LiteralInteger") { + if (t.type !== TokenType.kIntegerLiteral) { + this.error_ = t.line + ": expected integer not found"; + return undefined; + } + + name = "" + t.data; + kind = t.type; + value = t.data; + } else if (data.kind === "LiteralContextDependentNumber") { + if (result_type === undefined) { + this.error_ = t.line + + ": missing result type for context dependent number"; + return undefined; + } + if (t.type !== TokenType.kIntegerLiteral + && t.type !== TokenType.kFloatLiteral) { + this.error_ = t.line + ": expected number not found"; + return undefined; + } + + name = "" + t.data; + kind = result_type.type; + value = t.data; + + } else if (data.kind === "LiteralExtInstInteger") { + if (t.type !== TokenType.kIdentifier) { + this.error_ = t.line + ": expected instruction identifier"; + return undefined; + } + + if (this.grammar_.ext[t.data] === undefined) { + this.error_ = t.line + `: unable to find extended instruction (${t.data})`; + return undefined; + } + + name = t.data; + kind = "integer"; + value = this.grammar_.ext[t.data]; + + } else { + let d = this.grammar_.operand_kinds[data.kind]; + if (d === undefined) { + this.error_ = t.line + ": expected " + data.kind + " not found"; + return undefined; + } + + let val = d.values[t.data]["value"]; + let names = [t.data]; + if (d.type === "BitEnum") { + for(;;) { + let tmp = this.peek(0); + if (tmp.type !== TokenType.kPipe) { + break; + } + + this.next(); // skip pipe + tmp = this.next(); + + if (tmp.type !== TokenType.kIdentifier) { + this.error_ = tmp.line() + ": expected identifier"; + return undefined; + } + + val |= d.values[tmp.data]["value"]; + names.push(tmp.data); + } + } + + name = names.join("|"); + kind = d.type; + value = val; + + for (const op_name of names) { + if (d.values[op_name]['params'] === undefined) { + continue; + } + + for (const param of d.values[op_name]["params"]) { + params.push(this.extractOperand(ast, result_type, { kind: param })); + } + } + } + return new AST.Operand(ast, name, kind, value, params); + } +} diff --git a/third_party/spirv-tools/tools/sva/src/parser_test.js b/third_party/spirv-tools/tools/sva/src/parser_test.js new file mode 100644 index 0000000000..dffc0b33b6 --- /dev/null +++ b/third_party/spirv-tools/tools/sva/src/parser_test.js @@ -0,0 +1,489 @@ +// Copyright 2019 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. + +import { assert } from "chai"; +import Lexer from "./lexer"; +import Parser from "./parser"; +import grammar from "./spirv.data.js"; + +describe("parser", () => { + it("parses an opcode", () => { + let input = "OpKill"; + let l = new Lexer(input); + let p = new Parser(grammar, l); + + let ast = p.parse(); + assert.exists(ast); + assert.lengthOf(ast.instructions(), 1); + + let inst = ast.instruction(0); + assert.equal(inst.name(), "OpKill"); + assert.equal(inst.opcode(), 252); + assert.lengthOf(inst.operands, 0); + }); + + it("parses an opcode with an identifier", () => { + let input = "OpCapability Shader"; + let l = new Lexer(input); + let p = new Parser(grammar, l); + + let ast = p.parse(); + assert.exists(ast, p.error); + assert.lengthOf(ast.instructions(), 1); + + let inst = ast.instruction(0); + assert.equal(inst.name(), "OpCapability"); + assert.equal(inst.opcode(), 17); + assert.lengthOf(inst.operands(), 1); + + let op = inst.operand(0); + assert.equal(op.name(), "Shader"); + assert.equal(op.type(), "ValueEnum"); + assert.equal(op.value(), 1); + }); + + it("parses an opcode with a result", () => { + let input = "%void = OpTypeVoid"; + let l = new Lexer(input); + let p = new Parser(grammar, l); + + let ast = p.parse(); + assert.exists(ast); + assert.lengthOf(ast.instructions(), 1); + + let inst = ast.instruction(0); + assert.equal(inst.name(), "OpTypeVoid"); + assert.equal(inst.opcode(), 19); + assert.lengthOf(inst.operands(), 1); + + let op = inst.operand(0); + assert.equal(op.name(), "void"); + assert.equal(op.value(), 1); + }); + + it("sets module bounds based on numeric result", () => { + let input = "%3 = OpTypeVoid"; + + let l = new Lexer(input); + let p = new Parser(grammar, l); + + let ast = p.parse(); + assert.exists(ast); + assert.equal(ast.getId("next"), 4); + }); + + it("returns the same value for a named result_id", () => { + let input = "%3 = OpTypeFunction %int %int"; + + let l = new Lexer(input); + let p = new Parser(grammar, l); + + let ast = p.parse(); + assert.exists(ast); + assert.lengthOf(ast.instructions(), 1); + + let inst = ast.instruction(0); + let op1 = inst.operand(1); + assert.equal(op1.name(), "int"); + assert.equal(op1.value(), 4); + + let op2 = inst.operand(2); + assert.equal(op2.name(), "int"); + assert.equal(op2.value(), 4); + }); + + it("parses an opcode with a string", () => { + let input = "OpEntryPoint Fragment %main \"main\""; + + let l = new Lexer(input); + let p = new Parser(grammar, l); + + let ast = p.parse(); + assert.exists(ast); + assert.lengthOf(ast.instructions(), 1); + + let inst = ast.instruction(0); + let op = inst.operand(2); + assert.equal(op.name(), "main"); + assert.equal(op.value(), "main"); + }); + + describe("numerics", () => { + describe("integers", () => { + it("parses an opcode with an integer", () => { + let input = "OpSource GLSL 440"; + + let l = new Lexer(input); + let p = new Parser(grammar, l); + + let ast = p.parse(); + assert.exists(ast); + assert.lengthOf(ast.instructions(), 1); + + let inst = ast.instruction(0); + let op0 = inst.operand(0); + assert.equal(op0.name(), "GLSL"); + assert.equal(op0.type(), "ValueEnum"); + assert.equal(op0.value(), 2); + + let op1 = inst.operand(1); + assert.equal(op1.name(), "440"); + assert.equal(op1.value(), 440); + }); + + it("parses an opcode with a hex integer", () => { + let input = "OpSource GLSL 0x440"; + + let l = new Lexer(input); + let p = new Parser(grammar, l); + + let ast = p.parse(); + assert.exists(ast); + assert.lengthOf(ast.instructions(), 1); + + let inst = ast.instruction(0); + let op0 = inst.operand(0); + assert.equal(op0.name(), "GLSL"); + assert.equal(op0.type(), "ValueEnum"); + assert.equal(op0.value(), 2); + + let op1 = inst.operand(1); + assert.equal(op1.name(), "1088"); + assert.equal(op1.value(), 0x440); + }); + + it.skip("parses immediate integers", () => { + // TODO(dsinclair): Support or skip? + }); + }); + + describe("floats", () => { + it("parses floats", () => { + let input = `%float = OpTypeFloat 32 + %float1 = OpConstant %float 0.400000006`; + + let l = new Lexer(input); + let p = new Parser(grammar, l); + + let ast = p.parse(); + assert.exists(ast, p.error); + assert.lengthOf(ast.instructions(), 2); + + let inst = ast.instruction(1); + let op2 = inst.operand(2); + assert.equal(op2.value(), 0.400000006); + }); + + // TODO(dsinclair): Make hex encoded floats parse ... + it.skip("parses hex floats", () => { + let input = `%float = OpTypeFloat 32 + %nfloat = OpConstant %float -0.4p+2 + %pfloat = OpConstant %float 0.4p-2 + %inf = OpConstant %float32 0x1p+128 + %neginf = OpConstant %float32 -0x1p+128 + %aNaN = OpConstant %float32 0x1.8p+128 + %moreNaN = OpConstant %float32 -0x1.0002p+128`; + + let results = [-40.0, .004, 0x00000, 0x00000, 0x7fc00000, 0xff800100]; + let l = new Lexer(input); + let p = new Parser(grammar, l); + + let ast = p.parse(); + assert.exists(ast, p.error); + assert.lengthOf(ast.instructions(), 7); + + for (const idx in results) { + let inst = ast.instruction(idx); + let op2 = inst.operand(2); + assert.equal(op2.value(), results[idx]); + } + }); + + it("parses a float that looks like an int", () => { + let input = `%float = OpTypeFloat 32 + %float1 = OpConstant %float 1`; + + let l = new Lexer(input); + let p = new Parser(grammar, l); + + let ast = p.parse(); + assert.exists(ast, p.error); + assert.lengthOf(ast.instructions(), 2); + + let inst = ast.instruction(1); + let op2 = inst.operand(2); + assert.equal(op2.value(), 1); + assert.equal(op2.type(), "float"); + }); + }); + }); + + describe("enums", () => { + it("parses enum values", () => { + let input = `%1 = OpTypeFloat 32 + %30 = OpImageSampleExplicitLod %1 %20 %18 Grad|ConstOffset %22 %24 %29`; + + let vals = [{val: 1, name: "1"}, + {val: 30, name: "30"}, + {val: 20, name: "20"}, + {val: 18, name: "18"}, + {val: 12, name: "Grad|ConstOffset"}]; + + let l = new Lexer(input); + let p = new Parser(grammar, l); + + let ast = p.parse(); + assert.exists(ast, p.error); + assert.lengthOf(ast.instructions(), 2); + + let inst = ast.instruction(1); + for (let idx in vals) { + let op = inst.operand(idx); + assert.equal(op.name(), vals[idx].name); + assert.equal(op.value(), vals[idx].val); + } + + // BitEnum + let params = inst.operand(4).params(); + assert.lengthOf(params, 3); + assert.equal(params[0].name(), "22"); + assert.equal(params[0].value(), 22); + assert.equal(params[1].name(), "24"); + assert.equal(params[1].value(), 24); + assert.equal(params[2].name(), "29"); + assert.equal(params[2].value(), 29); + }); + + it("parses enumerants with parameters", () => { + let input ="OpExecutionMode %main LocalSize 2 3 4"; + + let l = new Lexer(input); + let p = new Parser(grammar, l); + + let ast = p.parse(); + assert.exists(ast, p.error); + assert.lengthOf(ast.instructions(), 1); + + let inst = ast.instruction(0); + assert.equal(inst.name(), "OpExecutionMode"); + assert.lengthOf(inst.operands(), 2); + assert.equal(inst.operand(0).name(), "main"); + assert.equal(inst.operand(1).name(), "LocalSize"); + + let params = inst.operand(1).params(); + assert.lengthOf(params, 3); + assert.equal(params[0].name(), "2"); + assert.equal(params[1].name(), "3"); + assert.equal(params[2].name(), "4"); + }); + }); + + it("parses result into second operand if needed", () => { + let input = `%int = OpTypeInt 32 1 + %int_3 = OpConstant %int 3`; + let l = new Lexer(input); + let p = new Parser(grammar, l); + + let ast = p.parse(); + assert.exists(ast); + assert.lengthOf(ast.instructions(), 2); + + let inst = ast.instruction(1); + assert.equal(inst.name(), "OpConstant"); + assert.equal(inst.opcode(), 43); + assert.lengthOf(inst.operands(), 3); + + let op0 = inst.operand(0); + assert.equal(op0.name(), "int"); + assert.equal(op0.value(), 1); + + let op1 = inst.operand(1); + assert.equal(op1.name(), "int_3"); + assert.equal(op1.value(), 2); + + let op2 = inst.operand(2); + assert.equal(op2.name(), "3"); + assert.equal(op2.value(), 3); + }); + + describe("quantifiers", () => { + describe("?", () => { + it("skips if missing", () => { + let input = `OpImageWrite %1 %2 %3 +OpKill`; + let l = new Lexer(input); + let p = new Parser(grammar, l); + + let ast = p.parse(); + assert.exists(ast); + assert.lengthOf(ast.instructions(), 2); + + let inst = ast.instruction(0); + assert.equal(inst.name(), "OpImageWrite"); + assert.lengthOf(inst.operands(), 3); + }); + + it("skips if missing at EOF", () => { + let input = "OpImageWrite %1 %2 %3"; + let l = new Lexer(input); + let p = new Parser(grammar, l); + + let ast = p.parse(); + assert.exists(ast); + assert.lengthOf(ast.instructions(), 1); + + let inst = ast.instruction(0); + assert.equal(inst.name(), "OpImageWrite"); + assert.lengthOf(inst.operands(), 3); + }); + + it("extracts if available", () => { + let input = `OpImageWrite %1 %2 %3 ConstOffset %2 +OpKill`; + let l = new Lexer(input); + let p = new Parser(grammar, l); + + let ast = p.parse(); + assert.exists(ast); + assert.lengthOf(ast.instructions(), 2); + + let inst = ast.instruction(0); + assert.equal(inst.name(), "OpImageWrite"); + assert.lengthOf(inst.operands(), 4); + assert.equal(inst.operand(3).name(), "ConstOffset"); + }); + }); + + describe("*", () => { + it("skips if missing", () => { + let input = `OpEntryPoint Fragment %main "main" +OpKill`; + + let l = new Lexer(input); + let p = new Parser(grammar, l); + + let ast = p.parse(); + assert.exists(ast); + assert.lengthOf(ast.instructions(), 2); + + let inst = ast.instruction(0); + assert.equal(inst.name(), "OpEntryPoint"); + assert.lengthOf(inst.operands(), 3); + assert.equal(inst.operand(2).name(), "main"); + }); + + it("extracts one if available", () => { + let input = `OpEntryPoint Fragment %main "main" %2 +OpKill`; + + let l = new Lexer(input); + let p = new Parser(grammar, l); + + let ast = p.parse(); + assert.exists(ast); + assert.lengthOf(ast.instructions(), 2); + + let inst = ast.instruction(0); + assert.equal(inst.name(), "OpEntryPoint"); + assert.lengthOf(inst.operands(), 4); + assert.equal(inst.operand(3).name(), "2"); + }); + + it("extracts multiple if available", () => { + let input = `OpEntryPoint Fragment %main "main" %2 %3 %4 %5 +OpKill`; + + let l = new Lexer(input); + let p = new Parser(grammar, l); + + let ast = p.parse(); + assert.exists(ast); + assert.lengthOf(ast.instructions(), 2); + + let inst = ast.instruction(0); + assert.equal(inst.name(), "OpEntryPoint"); + assert.lengthOf(inst.operands(), 7); + assert.equal(inst.operand(3).name(), "2"); + assert.equal(inst.operand(4).name(), "3"); + assert.equal(inst.operand(5).name(), "4"); + assert.equal(inst.operand(6).name(), "5"); + }); + }); + }); + + describe("extended instructions", () => { + it("errors on non-glsl extensions", () => { + let input = "%1 = OpExtInstImport \"OpenCL.std.100\""; + + let l = new Lexer(input); + let p = new Parser(grammar, l); + + assert.isUndefined(p.parse()); + }); + + it("handles extended instructions", () => { + let input = `%1 = OpExtInstImport "GLSL.std.450" + %44 = OpExtInst %7 %1 Sqrt %43`; + + let l = new Lexer(input); + let p = new Parser(grammar, l); + + let ast = p.parse(); + assert.exists(ast, p.error); + assert.lengthOf(ast.instructions(), 2); + + let inst = ast.instruction(1); + assert.lengthOf(inst.operands(), 5); + assert.equal(inst.operand(3).value(), 31); + assert.equal(inst.operand(3).name(), "Sqrt"); + assert.equal(inst.operand(4).value(), 43); + assert.equal(inst.operand(4).name(), "43"); + }); + }); + + it.skip("handles spec constant ops", () => { + // let input = "%sum = OpSpecConstantOp %i32 IAdd %a %b"; + }); + + it("handles OpCopyMemory", () => { + let input = "OpCopyMemory %1 %2 " + + "Volatile|Nontemporal|MakePointerVisible %3 " + + "Aligned|MakePointerAvailable|NonPrivatePointer 16 %4"; + + let l = new Lexer(input); + let p = new Parser(grammar, l); + + let ast = p.parse(); + assert.exists(ast, p.error); + assert.lengthOf(ast.instructions(), 1); + + let inst = ast.instruction(0); + assert.lengthOf(inst.operands(), 4); + assert.equal(inst.operand(0).value(), 1); + assert.equal(inst.operand(1).value(), 2); + + assert.equal(inst.operand(2).name(), + "Volatile|Nontemporal|MakePointerVisible"); + assert.equal(inst.operand(2).value(), 21); + assert.lengthOf(inst.operand(2).params(), 1); + assert.equal(inst.operand(2).params()[0].value(), 3); + + assert.equal(inst.operand(3).name(), + "Aligned|MakePointerAvailable|NonPrivatePointer"); + assert.equal(inst.operand(3).value(), 42); + assert.lengthOf(inst.operand(3).params(), 2); + assert.equal(inst.operand(3).params()[0].value(), 16); + assert.equal(inst.operand(3).params()[1].value(), 4); + }); +}); diff --git a/third_party/spirv-tools/tools/sva/src/spirv.data.js b/third_party/spirv-tools/tools/sva/src/spirv.data.js new file mode 100644 index 0000000000..ba969d86b3 --- /dev/null +++ b/third_party/spirv-tools/tools/sva/src/spirv.data.js @@ -0,0 +1,4567 @@ +/*Copyright (c) 2014-2016 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"), +to deal in the Materials without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Materials, and to permit persons to whom the +Materials are furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Materials. + +MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS +STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND +HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/ + +THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM,OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS +IN THE MATERIALS.*/ + +// THIS FILE IS GENERATED WITH tools/process_grammar.rb + +export default { + "magic": "0x07230203", + "version": [ + 1, + 5 + ], + "instructions": { + "OpNop": { + "opcode": 0, + "operands": [ + + ] + }, + "OpUndef": { + "opcode": 1, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + } + ] + }, + "OpSourceContinued": { + "opcode": 2, + "operands": [ + { + "kind": "LiteralString" + } + ] + }, + "OpSource": { + "opcode": 3, + "operands": [ + { + "kind": "SourceLanguage" + }, + { + "kind": "LiteralInteger" + }, + { + "kind": "IdRef", + "quantifier": "?" + }, + { + "kind": "LiteralString", + "quantifier": "?" + } + ] + }, + "OpSourceExtension": { + "opcode": 4, + "operands": [ + { + "kind": "LiteralString" + } + ] + }, + "OpName": { + "opcode": 5, + "operands": [ + { + "kind": "IdRef" + }, + { + "kind": "LiteralString" + } + ] + }, + "OpMemberName": { + "opcode": 6, + "operands": [ + { + "kind": "IdRef" + }, + { + "kind": "LiteralInteger" + }, + { + "kind": "LiteralString" + } + ] + }, + "OpString": { + "opcode": 7, + "operands": [ + { + "kind": "IdResult" + }, + { + "kind": "LiteralString" + } + ] + }, + "OpLine": { + "opcode": 8, + "operands": [ + { + "kind": "IdRef" + }, + { + "kind": "LiteralInteger" + }, + { + "kind": "LiteralInteger" + } + ] + }, + "OpExtension": { + "opcode": 10, + "operands": [ + { + "kind": "LiteralString" + } + ] + }, + "OpExtInstImport": { + "opcode": 11, + "operands": [ + { + "kind": "IdResult" + }, + { + "kind": "LiteralString" + } + ] + }, + "OpExtInst": { + "opcode": 12, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "LiteralExtInstInteger" + }, + { + "kind": "IdRef", + "quantifier": "*" + } + ] + }, + "OpMemoryModel": { + "opcode": 14, + "operands": [ + { + "kind": "AddressingModel" + }, + { + "kind": "MemoryModel" + } + ] + }, + "OpEntryPoint": { + "opcode": 15, + "operands": [ + { + "kind": "ExecutionModel" + }, + { + "kind": "IdRef" + }, + { + "kind": "LiteralString" + }, + { + "kind": "IdRef", + "quantifier": "*" + } + ] + }, + "OpExecutionMode": { + "opcode": 16, + "operands": [ + { + "kind": "IdRef" + }, + { + "kind": "ExecutionMode" + } + ] + }, + "OpCapability": { + "opcode": 17, + "operands": [ + { + "kind": "Capability" + } + ] + }, + "OpTypeVoid": { + "opcode": 19, + "operands": [ + { + "kind": "IdResult" + } + ] + }, + "OpTypeBool": { + "opcode": 20, + "operands": [ + { + "kind": "IdResult" + } + ] + }, + "OpTypeInt": { + "opcode": 21, + "operands": [ + { + "kind": "IdResult" + }, + { + "kind": "LiteralInteger" + }, + { + "kind": "LiteralInteger" + } + ] + }, + "OpTypeFloat": { + "opcode": 22, + "operands": [ + { + "kind": "IdResult" + }, + { + "kind": "LiteralInteger" + } + ] + }, + "OpTypeVector": { + "opcode": 23, + "operands": [ + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "LiteralInteger" + } + ] + }, + "OpTypeMatrix": { + "opcode": 24, + "operands": [ + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "LiteralInteger" + } + ] + }, + "OpTypeImage": { + "opcode": 25, + "operands": [ + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "Dim" + }, + { + "kind": "LiteralInteger" + }, + { + "kind": "LiteralInteger" + }, + { + "kind": "LiteralInteger" + }, + { + "kind": "LiteralInteger" + }, + { + "kind": "ImageFormat" + }, + { + "kind": "AccessQualifier", + "quantifier": "?" + } + ] + }, + "OpTypeSampler": { + "opcode": 26, + "operands": [ + { + "kind": "IdResult" + } + ] + }, + "OpTypeSampledImage": { + "opcode": 27, + "operands": [ + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + } + ] + }, + "OpTypeArray": { + "opcode": 28, + "operands": [ + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpTypeRuntimeArray": { + "opcode": 29, + "operands": [ + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + } + ] + }, + "OpTypeStruct": { + "opcode": 30, + "operands": [ + { + "kind": "IdResult" + }, + { + "kind": "IdRef", + "quantifier": "*" + } + ] + }, + "OpTypePointer": { + "opcode": 32, + "operands": [ + { + "kind": "IdResult" + }, + { + "kind": "StorageClass" + }, + { + "kind": "IdRef" + } + ] + }, + "OpTypeFunction": { + "opcode": 33, + "operands": [ + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef", + "quantifier": "*" + } + ] + }, + "OpConstantTrue": { + "opcode": 41, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + } + ] + }, + "OpConstantFalse": { + "opcode": 42, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + } + ] + }, + "OpConstant": { + "opcode": 43, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "LiteralContextDependentNumber" + } + ] + }, + "OpConstantComposite": { + "opcode": 44, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef", + "quantifier": "*" + } + ] + }, + "OpConstantNull": { + "opcode": 46, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + } + ] + }, + "OpSpecConstantTrue": { + "opcode": 48, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + } + ] + }, + "OpSpecConstantFalse": { + "opcode": 49, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + } + ] + }, + "OpSpecConstant": { + "opcode": 50, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "LiteralContextDependentNumber" + } + ] + }, + "OpSpecConstantComposite": { + "opcode": 51, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef", + "quantifier": "*" + } + ] + }, + "OpSpecConstantOp": { + "opcode": 52, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "LiteralSpecConstantOpInteger" + } + ] + }, + "OpFunction": { + "opcode": 54, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "FunctionControl" + }, + { + "kind": "IdRef" + } + ] + }, + "OpFunctionParameter": { + "opcode": 55, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + } + ] + }, + "OpFunctionEnd": { + "opcode": 56, + "operands": [ + + ] + }, + "OpFunctionCall": { + "opcode": 57, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef", + "quantifier": "*" + } + ] + }, + "OpVariable": { + "opcode": 59, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "StorageClass" + }, + { + "kind": "IdRef", + "quantifier": "?" + } + ] + }, + "OpImageTexelPointer": { + "opcode": 60, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpLoad": { + "opcode": 61, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "MemoryAccess", + "quantifier": "?" + } + ] + }, + "OpStore": { + "opcode": 62, + "operands": [ + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + }, + { + "kind": "MemoryAccess", + "quantifier": "?" + } + ] + }, + "OpCopyMemory": { + "opcode": 63, + "operands": [ + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + }, + { + "kind": "MemoryAccess", + "quantifier": "?" + }, + { + "kind": "MemoryAccess", + "quantifier": "?" + } + ] + }, + "OpAccessChain": { + "opcode": 65, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef", + "quantifier": "*" + } + ] + }, + "OpInBoundsAccessChain": { + "opcode": 66, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef", + "quantifier": "*" + } + ] + }, + "OpArrayLength": { + "opcode": 68, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "LiteralInteger" + } + ] + }, + "OpDecorate": { + "opcode": 71, + "operands": [ + { + "kind": "IdRef" + }, + { + "kind": "Decoration" + } + ] + }, + "OpMemberDecorate": { + "opcode": 72, + "operands": [ + { + "kind": "IdRef" + }, + { + "kind": "LiteralInteger" + }, + { + "kind": "Decoration" + } + ] + }, + "OpDecorationGroup": { + "opcode": 73, + "operands": [ + { + "kind": "IdResult" + } + ] + }, + "OpGroupDecorate": { + "opcode": 74, + "operands": [ + { + "kind": "IdRef" + }, + { + "kind": "IdRef", + "quantifier": "*" + } + ] + }, + "OpGroupMemberDecorate": { + "opcode": 75, + "operands": [ + { + "kind": "IdRef" + }, + { + "kind": "PairIdRefLiteralInteger", + "quantifier": "*" + } + ] + }, + "OpVectorExtractDynamic": { + "opcode": 77, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpVectorInsertDynamic": { + "opcode": 78, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpVectorShuffle": { + "opcode": 79, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + }, + { + "kind": "LiteralInteger", + "quantifier": "*" + } + ] + }, + "OpCompositeConstruct": { + "opcode": 80, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef", + "quantifier": "*" + } + ] + }, + "OpCompositeExtract": { + "opcode": 81, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "LiteralInteger", + "quantifier": "*" + } + ] + }, + "OpCompositeInsert": { + "opcode": 82, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + }, + { + "kind": "LiteralInteger", + "quantifier": "*" + } + ] + }, + "OpCopyObject": { + "opcode": 83, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + } + ] + }, + "OpTranspose": { + "opcode": 84, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + } + ] + }, + "OpSampledImage": { + "opcode": 86, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpImageSampleImplicitLod": { + "opcode": 87, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + }, + { + "kind": "ImageOperands", + "quantifier": "?" + } + ] + }, + "OpImageSampleExplicitLod": { + "opcode": 88, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + }, + { + "kind": "ImageOperands" + } + ] + }, + "OpImageSampleDrefImplicitLod": { + "opcode": 89, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + }, + { + "kind": "ImageOperands", + "quantifier": "?" + } + ] + }, + "OpImageSampleDrefExplicitLod": { + "opcode": 90, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + }, + { + "kind": "ImageOperands" + } + ] + }, + "OpImageSampleProjImplicitLod": { + "opcode": 91, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + }, + { + "kind": "ImageOperands", + "quantifier": "?" + } + ] + }, + "OpImageSampleProjExplicitLod": { + "opcode": 92, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + }, + { + "kind": "ImageOperands" + } + ] + }, + "OpImageSampleProjDrefImplicitLod": { + "opcode": 93, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + }, + { + "kind": "ImageOperands", + "quantifier": "?" + } + ] + }, + "OpImageSampleProjDrefExplicitLod": { + "opcode": 94, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + }, + { + "kind": "ImageOperands" + } + ] + }, + "OpImageFetch": { + "opcode": 95, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + }, + { + "kind": "ImageOperands", + "quantifier": "?" + } + ] + }, + "OpImageGather": { + "opcode": 96, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + }, + { + "kind": "ImageOperands", + "quantifier": "?" + } + ] + }, + "OpImageDrefGather": { + "opcode": 97, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + }, + { + "kind": "ImageOperands", + "quantifier": "?" + } + ] + }, + "OpImageRead": { + "opcode": 98, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + }, + { + "kind": "ImageOperands", + "quantifier": "?" + } + ] + }, + "OpImageWrite": { + "opcode": 99, + "operands": [ + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + }, + { + "kind": "ImageOperands", + "quantifier": "?" + } + ] + }, + "OpImage": { + "opcode": 100, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + } + ] + }, + "OpImageQuerySizeLod": { + "opcode": 103, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpImageQuerySize": { + "opcode": 104, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + } + ] + }, + "OpImageQueryLod": { + "opcode": 105, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpImageQueryLevels": { + "opcode": 106, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + } + ] + }, + "OpImageQuerySamples": { + "opcode": 107, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + } + ] + }, + "OpConvertFToU": { + "opcode": 109, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + } + ] + }, + "OpConvertFToS": { + "opcode": 110, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + } + ] + }, + "OpConvertSToF": { + "opcode": 111, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + } + ] + }, + "OpConvertUToF": { + "opcode": 112, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + } + ] + }, + "OpUConvert": { + "opcode": 113, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + } + ] + }, + "OpSConvert": { + "opcode": 114, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + } + ] + }, + "OpFConvert": { + "opcode": 115, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + } + ] + }, + "OpQuantizeToF16": { + "opcode": 116, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + } + ] + }, + "OpBitcast": { + "opcode": 124, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + } + ] + }, + "OpSNegate": { + "opcode": 126, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + } + ] + }, + "OpFNegate": { + "opcode": 127, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + } + ] + }, + "OpIAdd": { + "opcode": 128, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpFAdd": { + "opcode": 129, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpISub": { + "opcode": 130, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpFSub": { + "opcode": 131, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpIMul": { + "opcode": 132, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpFMul": { + "opcode": 133, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpUDiv": { + "opcode": 134, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpSDiv": { + "opcode": 135, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpFDiv": { + "opcode": 136, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpUMod": { + "opcode": 137, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpSRem": { + "opcode": 138, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpSMod": { + "opcode": 139, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpFRem": { + "opcode": 140, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpFMod": { + "opcode": 141, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpVectorTimesScalar": { + "opcode": 142, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpMatrixTimesScalar": { + "opcode": 143, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpVectorTimesMatrix": { + "opcode": 144, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpMatrixTimesVector": { + "opcode": 145, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpMatrixTimesMatrix": { + "opcode": 146, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpOuterProduct": { + "opcode": 147, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpDot": { + "opcode": 148, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpIAddCarry": { + "opcode": 149, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpISubBorrow": { + "opcode": 150, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpUMulExtended": { + "opcode": 151, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpSMulExtended": { + "opcode": 152, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpAny": { + "opcode": 154, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + } + ] + }, + "OpAll": { + "opcode": 155, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + } + ] + }, + "OpIsNan": { + "opcode": 156, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + } + ] + }, + "OpIsInf": { + "opcode": 157, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + } + ] + }, + "OpLogicalEqual": { + "opcode": 164, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpLogicalNotEqual": { + "opcode": 165, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpLogicalOr": { + "opcode": 166, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpLogicalAnd": { + "opcode": 167, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpLogicalNot": { + "opcode": 168, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + } + ] + }, + "OpSelect": { + "opcode": 169, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpIEqual": { + "opcode": 170, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpINotEqual": { + "opcode": 171, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpUGreaterThan": { + "opcode": 172, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpSGreaterThan": { + "opcode": 173, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpUGreaterThanEqual": { + "opcode": 174, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpSGreaterThanEqual": { + "opcode": 175, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpULessThan": { + "opcode": 176, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpSLessThan": { + "opcode": 177, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpULessThanEqual": { + "opcode": 178, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpSLessThanEqual": { + "opcode": 179, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpFOrdEqual": { + "opcode": 180, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpFUnordEqual": { + "opcode": 181, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpFOrdNotEqual": { + "opcode": 182, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpFUnordNotEqual": { + "opcode": 183, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpFOrdLessThan": { + "opcode": 184, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpFUnordLessThan": { + "opcode": 185, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpFOrdGreaterThan": { + "opcode": 186, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpFUnordGreaterThan": { + "opcode": 187, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpFOrdLessThanEqual": { + "opcode": 188, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpFUnordLessThanEqual": { + "opcode": 189, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpFOrdGreaterThanEqual": { + "opcode": 190, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpFUnordGreaterThanEqual": { + "opcode": 191, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpShiftRightLogical": { + "opcode": 194, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpShiftRightArithmetic": { + "opcode": 195, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpShiftLeftLogical": { + "opcode": 196, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpBitwiseOr": { + "opcode": 197, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpBitwiseXor": { + "opcode": 198, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpBitwiseAnd": { + "opcode": 199, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpNot": { + "opcode": 200, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + } + ] + }, + "OpBitFieldInsert": { + "opcode": 201, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpBitFieldSExtract": { + "opcode": 202, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpBitFieldUExtract": { + "opcode": 203, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpBitReverse": { + "opcode": 204, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + } + ] + }, + "OpBitCount": { + "opcode": 205, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + } + ] + }, + "OpDPdx": { + "opcode": 207, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + } + ] + }, + "OpDPdy": { + "opcode": 208, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + } + ] + }, + "OpFwidth": { + "opcode": 209, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + } + ] + }, + "OpDPdxFine": { + "opcode": 210, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + } + ] + }, + "OpDPdyFine": { + "opcode": 211, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + } + ] + }, + "OpFwidthFine": { + "opcode": 212, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + } + ] + }, + "OpDPdxCoarse": { + "opcode": 213, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + } + ] + }, + "OpDPdyCoarse": { + "opcode": 214, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + } + ] + }, + "OpFwidthCoarse": { + "opcode": 215, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + } + ] + }, + "OpControlBarrier": { + "opcode": 224, + "operands": [ + { + "kind": "IdScope" + }, + { + "kind": "IdScope" + }, + { + "kind": "IdMemorySemantics" + } + ] + }, + "OpMemoryBarrier": { + "opcode": 225, + "operands": [ + { + "kind": "IdScope" + }, + { + "kind": "IdMemorySemantics" + } + ] + }, + "OpAtomicLoad": { + "opcode": 227, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdScope" + }, + { + "kind": "IdMemorySemantics" + } + ] + }, + "OpAtomicStore": { + "opcode": 228, + "operands": [ + { + "kind": "IdRef" + }, + { + "kind": "IdScope" + }, + { + "kind": "IdMemorySemantics" + }, + { + "kind": "IdRef" + } + ] + }, + "OpAtomicExchange": { + "opcode": 229, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdScope" + }, + { + "kind": "IdMemorySemantics" + }, + { + "kind": "IdRef" + } + ] + }, + "OpAtomicCompareExchange": { + "opcode": 230, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdScope" + }, + { + "kind": "IdMemorySemantics" + }, + { + "kind": "IdMemorySemantics" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpAtomicIIncrement": { + "opcode": 232, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdScope" + }, + { + "kind": "IdMemorySemantics" + } + ] + }, + "OpAtomicIDecrement": { + "opcode": 233, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdScope" + }, + { + "kind": "IdMemorySemantics" + } + ] + }, + "OpAtomicIAdd": { + "opcode": 234, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdScope" + }, + { + "kind": "IdMemorySemantics" + }, + { + "kind": "IdRef" + } + ] + }, + "OpAtomicISub": { + "opcode": 235, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdScope" + }, + { + "kind": "IdMemorySemantics" + }, + { + "kind": "IdRef" + } + ] + }, + "OpAtomicSMin": { + "opcode": 236, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdScope" + }, + { + "kind": "IdMemorySemantics" + }, + { + "kind": "IdRef" + } + ] + }, + "OpAtomicUMin": { + "opcode": 237, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdScope" + }, + { + "kind": "IdMemorySemantics" + }, + { + "kind": "IdRef" + } + ] + }, + "OpAtomicSMax": { + "opcode": 238, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdScope" + }, + { + "kind": "IdMemorySemantics" + }, + { + "kind": "IdRef" + } + ] + }, + "OpAtomicUMax": { + "opcode": 239, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdScope" + }, + { + "kind": "IdMemorySemantics" + }, + { + "kind": "IdRef" + } + ] + }, + "OpAtomicAnd": { + "opcode": 240, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdScope" + }, + { + "kind": "IdMemorySemantics" + }, + { + "kind": "IdRef" + } + ] + }, + "OpAtomicOr": { + "opcode": 241, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdScope" + }, + { + "kind": "IdMemorySemantics" + }, + { + "kind": "IdRef" + } + ] + }, + "OpAtomicXor": { + "opcode": 242, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdScope" + }, + { + "kind": "IdMemorySemantics" + }, + { + "kind": "IdRef" + } + ] + }, + "OpPhi": { + "opcode": 245, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "PairIdRefIdRef", + "quantifier": "*" + } + ] + }, + "OpLoopMerge": { + "opcode": 246, + "operands": [ + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + }, + { + "kind": "LoopControl" + } + ] + }, + "OpSelectionMerge": { + "opcode": 247, + "operands": [ + { + "kind": "IdRef" + }, + { + "kind": "SelectionControl" + } + ] + }, + "OpLabel": { + "opcode": 248, + "operands": [ + { + "kind": "IdResult" + } + ] + }, + "OpBranch": { + "opcode": 249, + "operands": [ + { + "kind": "IdRef" + } + ] + }, + "OpBranchConditional": { + "opcode": 250, + "operands": [ + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + }, + { + "kind": "LiteralInteger", + "quantifier": "*" + } + ] + }, + "OpSwitch": { + "opcode": 251, + "operands": [ + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + }, + { + "kind": "PairLiteralIntegerIdRef", + "quantifier": "*" + } + ] + }, + "OpKill": { + "opcode": 252, + "operands": [ + + ] + }, + "OpReturn": { + "opcode": 253, + "operands": [ + + ] + }, + "OpReturnValue": { + "opcode": 254, + "operands": [ + { + "kind": "IdRef" + } + ] + }, + "OpUnreachable": { + "opcode": 255, + "operands": [ + + ] + }, + "OpNoLine": { + "opcode": 317, + "operands": [ + + ] + }, + "OpModuleProcessed": { + "opcode": 330, + "operands": [ + { + "kind": "LiteralString" + } + ] + }, + "OpExecutionModeId": { + "opcode": 331, + "operands": [ + { + "kind": "IdRef" + }, + { + "kind": "ExecutionMode" + } + ] + }, + "OpDecorateId": { + "opcode": 332, + "operands": [ + { + "kind": "IdRef" + }, + { + "kind": "Decoration" + } + ] + }, + "OpCopyLogical": { + "opcode": 400, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + } + ] + }, + "OpPtrEqual": { + "opcode": 401, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpPtrNotEqual": { + "opcode": 402, + "operands": [ + { + "kind": "IdResultType" + }, + { + "kind": "IdResult" + }, + { + "kind": "IdRef" + }, + { + "kind": "IdRef" + } + ] + }, + "OpDecorateString": { + "opcode": 5632, + "operands": [ + { + "kind": "IdRef" + }, + { + "kind": "Decoration" + } + ] + }, + "OpDecorateStringGOOGLE": { + "opcode": 5632, + "operands": [ + { + "kind": "IdRef" + }, + { + "kind": "Decoration" + } + ] + }, + "OpMemberDecorateString": { + "opcode": 5633, + "operands": [ + { + "kind": "IdRef" + }, + { + "kind": "LiteralInteger" + }, + { + "kind": "Decoration" + } + ] + }, + "OpMemberDecorateStringGOOGLE": { + "opcode": 5633, + "operands": [ + { + "kind": "IdRef" + }, + { + "kind": "LiteralInteger" + }, + { + "kind": "Decoration" + } + ] + } + }, + "operand_kinds": { + "ImageOperands": { + "type": "BitEnum", + "values": { + "None": { + "value": 0 + }, + "Bias": { + "value": 1, + "params": [ + "IdRef" + ] + }, + "Lod": { + "value": 2, + "params": [ + "IdRef" + ] + }, + "Grad": { + "value": 4, + "params": [ + "IdRef", + "IdRef" + ] + }, + "ConstOffset": { + "value": 8, + "params": [ + "IdRef" + ] + }, + "Sample": { + "value": 64, + "params": [ + "IdRef" + ] + }, + "MakeTexelAvailable": { + "value": 256, + "params": [ + "IdScope" + ] + }, + "MakeTexelAvailableKHR": { + "value": 256, + "params": [ + "IdScope" + ] + }, + "MakeTexelVisible": { + "value": 512, + "params": [ + "IdScope" + ] + }, + "MakeTexelVisibleKHR": { + "value": 512, + "params": [ + "IdScope" + ] + }, + "NonPrivateTexel": { + "value": 1024 + }, + "NonPrivateTexelKHR": { + "value": 1024 + }, + "VolatileTexel": { + "value": 2048 + }, + "VolatileTexelKHR": { + "value": 2048 + }, + "SignExtend": { + "value": 4096 + }, + "ZeroExtend": { + "value": 8192 + } + } + }, + "FPFastMathMode": { + "type": "BitEnum", + "values": { + "None": { + "value": 0 + } + } + }, + "SelectionControl": { + "type": "BitEnum", + "values": { + "None": { + "value": 0 + }, + "Flatten": { + "value": 1 + }, + "DontFlatten": { + "value": 2 + } + } + }, + "LoopControl": { + "type": "BitEnum", + "values": { + "None": { + "value": 0 + }, + "Unroll": { + "value": 1 + }, + "DontUnroll": { + "value": 2 + }, + "DependencyInfinite": { + "value": 4 + }, + "DependencyLength": { + "value": 8, + "params": [ + "LiteralInteger" + ] + }, + "MinIterations": { + "value": 16, + "params": [ + "LiteralInteger" + ] + }, + "MaxIterations": { + "value": 32, + "params": [ + "LiteralInteger" + ] + }, + "IterationMultiple": { + "value": 64, + "params": [ + "LiteralInteger" + ] + }, + "PeelCount": { + "value": 128, + "params": [ + "LiteralInteger" + ] + }, + "PartialCount": { + "value": 256, + "params": [ + "LiteralInteger" + ] + } + } + }, + "FunctionControl": { + "type": "BitEnum", + "values": { + "None": { + "value": 0 + }, + "Inline": { + "value": 1 + }, + "DontInline": { + "value": 2 + }, + "Pure": { + "value": 4 + }, + "Const": { + "value": 8 + } + } + }, + "MemorySemantics": { + "type": "BitEnum", + "values": { + "Relaxed": { + "value": 0 + }, + "None": { + "value": 0 + }, + "Acquire": { + "value": 2 + }, + "Release": { + "value": 4 + }, + "AcquireRelease": { + "value": 8 + }, + "SequentiallyConsistent": { + "value": 16 + }, + "UniformMemory": { + "value": 64 + }, + "SubgroupMemory": { + "value": 128 + }, + "WorkgroupMemory": { + "value": 256 + }, + "CrossWorkgroupMemory": { + "value": 512 + }, + "ImageMemory": { + "value": 2048 + }, + "OutputMemory": { + "value": 4096 + }, + "OutputMemoryKHR": { + "value": 4096 + }, + "MakeAvailable": { + "value": 8192 + }, + "MakeAvailableKHR": { + "value": 8192 + }, + "MakeVisible": { + "value": 16384 + }, + "MakeVisibleKHR": { + "value": 16384 + }, + "Volatile": { + "value": 32768 + } + } + }, + "MemoryAccess": { + "type": "BitEnum", + "values": { + "None": { + "value": 0 + }, + "Volatile": { + "value": 1 + }, + "Aligned": { + "value": 2, + "params": [ + "LiteralInteger" + ] + }, + "Nontemporal": { + "value": 4 + }, + "MakePointerAvailable": { + "value": 8, + "params": [ + "IdScope" + ] + }, + "MakePointerAvailableKHR": { + "value": 8, + "params": [ + "IdScope" + ] + }, + "MakePointerVisible": { + "value": 16, + "params": [ + "IdScope" + ] + }, + "MakePointerVisibleKHR": { + "value": 16, + "params": [ + "IdScope" + ] + }, + "NonPrivatePointer": { + "value": 32 + }, + "NonPrivatePointerKHR": { + "value": 32 + } + } + }, + "KernelProfilingInfo": { + "type": "BitEnum", + "values": { + "None": { + "value": 0 + } + } + }, + "SourceLanguage": { + "type": "ValueEnum", + "values": { + "Unknown": { + "value": 0 + }, + "ESSL": { + "value": 1 + }, + "GLSL": { + "value": 2 + }, + "OpenCL_C": { + "value": 3 + }, + "OpenCL_CPP": { + "value": 4 + }, + "HLSL": { + "value": 5 + } + } + }, + "ExecutionModel": { + "type": "ValueEnum", + "values": { + "Vertex": { + "value": 0 + }, + "Fragment": { + "value": 4 + }, + "GLCompute": { + "value": 5 + } + } + }, + "AddressingModel": { + "type": "ValueEnum", + "values": { + "Logical": { + "value": 0 + } + } + }, + "MemoryModel": { + "type": "ValueEnum", + "values": { + "Simple": { + "value": 0 + }, + "GLSL450": { + "value": 1 + }, + "Vulkan": { + "value": 3 + }, + "VulkanKHR": { + "value": 3 + } + } + }, + "ExecutionMode": { + "type": "ValueEnum", + "values": { + "PixelCenterInteger": { + "value": 6 + }, + "OriginUpperLeft": { + "value": 7 + }, + "OriginLowerLeft": { + "value": 8 + }, + "EarlyFragmentTests": { + "value": 9 + }, + "DepthReplacing": { + "value": 12 + }, + "DepthGreater": { + "value": 14 + }, + "DepthLess": { + "value": 15 + }, + "DepthUnchanged": { + "value": 16 + }, + "LocalSize": { + "value": 17, + "params": [ + "LiteralInteger", + "LiteralInteger", + "LiteralInteger" + ] + }, + "LocalSizeId": { + "value": 38, + "params": [ + "IdRef", + "IdRef", + "IdRef" + ] + } + } + }, + "StorageClass": { + "type": "ValueEnum", + "values": { + "UniformConstant": { + "value": 0 + }, + "Input": { + "value": 1 + }, + "Uniform": { + "value": 2 + }, + "Output": { + "value": 3 + }, + "Workgroup": { + "value": 4 + }, + "CrossWorkgroup": { + "value": 5 + }, + "Private": { + "value": 6 + }, + "Function": { + "value": 7 + }, + "PushConstant": { + "value": 9 + }, + "Image": { + "value": 11 + }, + "StorageBuffer": { + "value": 12 + } + } + }, + "Dim": { + "type": "ValueEnum", + "values": { + "1D": { + "value": 0 + }, + "2D": { + "value": 1 + }, + "3D": { + "value": 2 + }, + "Cube": { + "value": 3 + } + } + }, + "ImageFormat": { + "type": "ValueEnum", + "values": { + "Unknown": { + "value": 0 + }, + "Rgba32f": { + "value": 1 + }, + "Rgba16f": { + "value": 2 + }, + "R32f": { + "value": 3 + }, + "Rgba8": { + "value": 4 + }, + "Rgba8Snorm": { + "value": 5 + }, + "Rgba32i": { + "value": 21 + }, + "Rgba16i": { + "value": 22 + }, + "Rgba8i": { + "value": 23 + }, + "R32i": { + "value": 24 + }, + "Rgba32ui": { + "value": 30 + }, + "Rgba16ui": { + "value": 31 + }, + "Rgba8ui": { + "value": 32 + }, + "R32ui": { + "value": 33 + } + } + }, + "FPRoundingMode": { + "type": "ValueEnum", + "values": { + "RTE": { + "value": 0 + }, + "RTZ": { + "value": 1 + }, + "RTP": { + "value": 2 + }, + "RTN": { + "value": 3 + } + } + }, + "Decoration": { + "type": "ValueEnum", + "values": { + "RelaxedPrecision": { + "value": 0 + }, + "SpecId": { + "value": 1, + "params": [ + "LiteralInteger" + ] + }, + "Block": { + "value": 2 + }, + "BufferBlock": { + "value": 3 + }, + "RowMajor": { + "value": 4 + }, + "ColMajor": { + "value": 5 + }, + "ArrayStride": { + "value": 6, + "params": [ + "LiteralInteger" + ] + }, + "MatrixStride": { + "value": 7, + "params": [ + "LiteralInteger" + ] + }, + "GLSLShared": { + "value": 8 + }, + "GLSLPacked": { + "value": 9 + }, + "BuiltIn": { + "value": 11, + "params": [ + "BuiltIn" + ] + }, + "NoPerspective": { + "value": 13 + }, + "Flat": { + "value": 14 + }, + "Centroid": { + "value": 16 + }, + "Invariant": { + "value": 18 + }, + "Restrict": { + "value": 19 + }, + "Aliased": { + "value": 20 + }, + "Volatile": { + "value": 21 + }, + "Coherent": { + "value": 23 + }, + "NonWritable": { + "value": 24 + }, + "NonReadable": { + "value": 25 + }, + "Uniform": { + "value": 26 + }, + "UniformId": { + "value": 27, + "params": [ + "IdScope" + ] + }, + "Location": { + "value": 30, + "params": [ + "LiteralInteger" + ] + }, + "Component": { + "value": 31, + "params": [ + "LiteralInteger" + ] + }, + "Index": { + "value": 32, + "params": [ + "LiteralInteger" + ] + }, + "Binding": { + "value": 33, + "params": [ + "LiteralInteger" + ] + }, + "DescriptorSet": { + "value": 34, + "params": [ + "LiteralInteger" + ] + }, + "Offset": { + "value": 35, + "params": [ + "LiteralInteger" + ] + }, + "FPRoundingMode": { + "value": 39, + "params": [ + "FPRoundingMode" + ] + }, + "NoContraction": { + "value": 42 + }, + "NoSignedWrap": { + "value": 4469 + }, + "NoUnsignedWrap": { + "value": 4470 + }, + "ExplicitInterpAMD": { + "value": 4999 + }, + "CounterBuffer": { + "value": 5634, + "params": [ + "IdRef" + ] + }, + "HlslCounterBufferGOOGLE": { + "value": 5634, + "params": [ + "IdRef" + ] + }, + "UserSemantic": { + "value": 5635, + "params": [ + "LiteralString" + ] + }, + "HlslSemanticGOOGLE": { + "value": 5635, + "params": [ + "LiteralString" + ] + }, + "UserTypeGOOGLE": { + "value": 5636, + "params": [ + "LiteralString" + ] + } + } + }, + "BuiltIn": { + "type": "ValueEnum", + "values": { + "Position": { + "value": 0 + }, + "PointSize": { + "value": 1 + }, + "VertexId": { + "value": 5 + }, + "InstanceId": { + "value": 6 + }, + "FragCoord": { + "value": 15 + }, + "PointCoord": { + "value": 16 + }, + "FrontFacing": { + "value": 17 + }, + "SampleMask": { + "value": 20 + }, + "FragDepth": { + "value": 22 + }, + "HelperInvocation": { + "value": 23 + }, + "NumWorkgroups": { + "value": 24 + }, + "WorkgroupSize": { + "value": 25 + }, + "WorkgroupId": { + "value": 26 + }, + "LocalInvocationId": { + "value": 27 + }, + "GlobalInvocationId": { + "value": 28 + }, + "LocalInvocationIndex": { + "value": 29 + }, + "VertexIndex": { + "value": 42 + }, + "InstanceIndex": { + "value": 43 + }, + "BaryCoordNoPerspAMD": { + "value": 4992 + }, + "BaryCoordNoPerspCentroidAMD": { + "value": 4993 + }, + "BaryCoordNoPerspSampleAMD": { + "value": 4994 + }, + "BaryCoordSmoothAMD": { + "value": 4995 + }, + "BaryCoordSmoothCentroidAMD": { + "value": 4996 + }, + "BaryCoordSmoothSampleAMD": { + "value": 4997 + }, + "BaryCoordPullModelAMD": { + "value": 4998 + } + } + }, + "Scope": { + "type": "ValueEnum", + "values": { + "CrossDevice": { + "value": 0 + }, + "Device": { + "value": 1 + }, + "Workgroup": { + "value": 2 + }, + "Subgroup": { + "value": 3 + }, + "Invocation": { + "value": 4 + }, + "QueueFamily": { + "value": 5 + }, + "QueueFamilyKHR": { + "value": 5 + } + } + }, + "Capability": { + "type": "ValueEnum", + "values": { + "Matrix": { + "value": 0 + }, + "Shader": { + "value": 1 + }, + "Geometry": { + "value": 2 + }, + "Tessellation": { + "value": 3 + }, + "Addresses": { + "value": 4 + }, + "Linkage": { + "value": 5 + }, + "Kernel": { + "value": 6 + }, + "Float16": { + "value": 9 + }, + "Float64": { + "value": 10 + }, + "Int64": { + "value": 11 + }, + "Groups": { + "value": 18 + }, + "AtomicStorage": { + "value": 21 + }, + "Int16": { + "value": 22 + }, + "ImageGatherExtended": { + "value": 25 + }, + "StorageImageMultisample": { + "value": 27 + }, + "UniformBufferArrayDynamicIndexing": { + "value": 28 + }, + "SampledImageArrayDynamicIndexing": { + "value": 29 + }, + "StorageBufferArrayDynamicIndexing": { + "value": 30 + }, + "StorageImageArrayDynamicIndexing": { + "value": 31 + }, + "ClipDistance": { + "value": 32 + }, + "CullDistance": { + "value": 33 + }, + "SampleRateShading": { + "value": 35 + }, + "SampledRect": { + "value": 37 + }, + "Int8": { + "value": 39 + }, + "InputAttachment": { + "value": 40 + }, + "SparseResidency": { + "value": 41 + }, + "MinLod": { + "value": 42 + }, + "Sampled1D": { + "value": 43 + }, + "Image1D": { + "value": 44 + }, + "SampledCubeArray": { + "value": 45 + }, + "SampledBuffer": { + "value": 46 + }, + "ImageMSArray": { + "value": 48 + }, + "StorageImageExtendedFormats": { + "value": 49 + }, + "ImageQuery": { + "value": 50 + }, + "DerivativeControl": { + "value": 51 + }, + "InterpolationFunction": { + "value": 52 + }, + "TransformFeedback": { + "value": 53 + }, + "StorageImageReadWithoutFormat": { + "value": 55 + }, + "StorageImageWriteWithoutFormat": { + "value": 56 + }, + "GroupNonUniform": { + "value": 61 + }, + "ShaderLayer": { + "value": 69 + }, + "ShaderViewportIndex": { + "value": 70 + }, + "SubgroupBallotKHR": { + "value": 4423 + }, + "DrawParameters": { + "value": 4427 + }, + "SubgroupVoteKHR": { + "value": 4431 + }, + "StorageBuffer16BitAccess": { + "value": 4433 + }, + "StorageUniformBufferBlock16": { + "value": 4433 + }, + "StoragePushConstant16": { + "value": 4435 + }, + "StorageInputOutput16": { + "value": 4436 + }, + "DeviceGroup": { + "value": 4437 + }, + "MultiView": { + "value": 4439 + }, + "VariablePointersStorageBuffer": { + "value": 4441 + }, + "AtomicStorageOps": { + "value": 4445 + }, + "SampleMaskPostDepthCoverage": { + "value": 4447 + }, + "StorageBuffer8BitAccess": { + "value": 4448 + }, + "StoragePushConstant8": { + "value": 4450 + }, + "DenormPreserve": { + "value": 4464 + }, + "DenormFlushToZero": { + "value": 4465 + }, + "SignedZeroInfNanPreserve": { + "value": 4466 + }, + "RoundingModeRTE": { + "value": 4467 + }, + "RoundingModeRTZ": { + "value": 4468 + }, + "Float16ImageAMD": { + "value": 5008 + }, + "ImageGatherBiasLodAMD": { + "value": 5009 + }, + "FragmentMaskAMD": { + "value": 5010 + }, + "StencilExportEXT": { + "value": 5013 + }, + "ImageReadWriteLodAMD": { + "value": 5015 + }, + "ShaderClockKHR": { + "value": 5055 + }, + "FragmentFullyCoveredEXT": { + "value": 5265 + }, + "MeshShadingNV": { + "value": 5266 + }, + "ImageFootprintNV": { + "value": 5282 + }, + "FragmentBarycentricNV": { + "value": 5284 + }, + "ComputeDerivativeGroupQuadsNV": { + "value": 5288 + }, + "FragmentDensityEXT": { + "value": 5291 + }, + "ShadingRateNV": { + "value": 5291 + }, + "GroupNonUniformPartitionedNV": { + "value": 5297 + }, + "ShaderNonUniform": { + "value": 5301 + }, + "ShaderNonUniformEXT": { + "value": 5301 + }, + "RuntimeDescriptorArray": { + "value": 5302 + }, + "RuntimeDescriptorArrayEXT": { + "value": 5302 + }, + "RayTracingNV": { + "value": 5340 + }, + "VulkanMemoryModel": { + "value": 5345 + }, + "VulkanMemoryModelKHR": { + "value": 5345 + }, + "VulkanMemoryModelDeviceScope": { + "value": 5346 + }, + "VulkanMemoryModelDeviceScopeKHR": { + "value": 5346 + }, + "PhysicalStorageBufferAddresses": { + "value": 5347 + }, + "PhysicalStorageBufferAddressesEXT": { + "value": 5347 + }, + "ComputeDerivativeGroupLinearNV": { + "value": 5350 + }, + "CooperativeMatrixNV": { + "value": 5357 + }, + "FragmentShaderSampleInterlockEXT": { + "value": 5363 + }, + "FragmentShaderShadingRateInterlockEXT": { + "value": 5372 + }, + "ShaderSMBuiltinsNV": { + "value": 5373 + }, + "FragmentShaderPixelInterlockEXT": { + "value": 5378 + }, + "DemoteToHelperInvocationEXT": { + "value": 5379 + }, + "SubgroupShuffleINTEL": { + "value": 5568 + }, + "SubgroupBufferBlockIOINTEL": { + "value": 5569 + }, + "SubgroupImageBlockIOINTEL": { + "value": 5570 + }, + "SubgroupImageMediaBlockIOINTEL": { + "value": 5579 + }, + "IntegerFunctions2INTEL": { + "value": 5584 + }, + "SubgroupAvcMotionEstimationINTEL": { + "value": 5696 + }, + "SubgroupAvcMotionEstimationIntraINTEL": { + "value": 5697 + }, + "SubgroupAvcMotionEstimationChromaINTEL": { + "value": 5698 + } + } + } + }, + "ext": { + "Round": 1, + "RoundEven": 2, + "Trunc": 3, + "FAbs": 4, + "SAbs": 5, + "FSign": 6, + "SSign": 7, + "Floor": 8, + "Ceil": 9, + "Fract": 10, + "Radians": 11, + "Degrees": 12, + "Sin": 13, + "Cos": 14, + "Tan": 15, + "Asin": 16, + "Acos": 17, + "Atan": 18, + "Sinh": 19, + "Cosh": 20, + "Tanh": 21, + "Asinh": 22, + "Acosh": 23, + "Atanh": 24, + "Atan2": 25, + "Pow": 26, + "Exp": 27, + "Log": 28, + "Exp2": 29, + "Log2": 30, + "Sqrt": 31, + "InverseSqrt": 32, + "Determinant": 33, + "MatrixInverse": 34, + "Modf": 35, + "ModfStruct": 36, + "FMin": 37, + "UMin": 38, + "SMin": 39, + "FMax": 40, + "UMax": 41, + "SMax": 42, + "FClamp": 43, + "UClamp": 44, + "SClamp": 45, + "FMix": 46, + "IMix": 47, + "Step": 48, + "SmoothStep": 49, + "Fma": 50, + "Frexp": 51, + "FrexpStruct": 52, + "Ldexp": 53, + "PackSnorm4x8": 54, + "PackUnorm4x8": 55, + "PackSnorm2x16": 56, + "PackUnorm2x16": 57, + "PackHalf2x16": 58, + "PackDouble2x32": 59, + "UnpackSnorm2x16": 60, + "UnpackUnorm2x16": 61, + "UnpackHalf2x16": 62, + "UnpackSnorm4x8": 63, + "UnpackUnorm4x8": 64, + "UnpackDouble2x32": 65, + "Length": 66, + "Distance": 67, + "Cross": 68, + "Normalize": 69, + "FaceForward": 70, + "Reflect": 71, + "Refract": 72, + "FindILsb": 73, + "FindSMsb": 74, + "FindUMsb": 75, + "InterpolateAtCentroid": 76, + "InterpolateAtSample": 77, + "InterpolateAtOffset": 78, + "NMin": 79, + "NMax": 80, + "NClamp": 81 + } +} diff --git a/third_party/spirv-tools/tools/sva/src/sva.js b/third_party/spirv-tools/tools/sva/src/sva.js new file mode 100644 index 0000000000..c76ed296ea --- /dev/null +++ b/third_party/spirv-tools/tools/sva/src/sva.js @@ -0,0 +1,40 @@ +// Copyright 2019 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. + +import Parser from "./parser.js"; +import Lexer from "./lexer.js"; +import Assembler from "./assembler.js"; + +import grammar from "./spirv.data.js"; + +export default class SVA { + /** + * Attempts to convert |input| SPIR-V assembly into SPIR-V binary. + * + * @param {String} the input string containing the assembly + * @return {Uint32Array|string} returns a Uint32Array containing the binary + * SPIR-V or a string on error. + */ + static assemble(input) { + let l = new Lexer(input); + let p = new Parser(grammar, l); + + let ast = p.parse(); + if (ast === undefined) + return p.error; + + let a = new Assembler(ast); + return a.assemble(); + } +} diff --git a/third_party/spirv-tools/tools/sva/src/token.js b/third_party/spirv-tools/tools/sva/src/token.js new file mode 100644 index 0000000000..3813191dcb --- /dev/null +++ b/third_party/spirv-tools/tools/sva/src/token.js @@ -0,0 +1,55 @@ +// Copyright 2019 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. + +const TokenType = { + kEOF: "end of file", + kError: "error", + + kIdentifier: "identifier", + + kIntegerLiteral: "integer_literal", + kFloatLiteral: "float_literal", + kStringLiteral: "string_literal", + kResultId: "result_id", + + kOp: "Op", + kEqual: "=", + kPipe: "|", +}; + +class Token { + /** + * @param {TokenType} type The type of token + * @param {Integer} line The line number this token was on + * @param {Any} data Data attached to the token + * @param {Integer} bits If the type is a float or integer the bit width + */ + constructor(type, line, data) { + this.type_ = type; + this.line_ = line; + this.data_ = data; + this.bits_ = 0; + } + + get type() { return this.type_; } + get line() { return this.line_; } + + get data() { return this.data_; } + set data(val) { this.data_ = val; } + + get bits() { return this.bits_; } + set bits(val) { this.bits_ = val; } +} + +export {Token, TokenType}; diff --git a/third_party/spirv-tools/tools/sva/tests/empty_main.spv_asm b/third_party/spirv-tools/tools/sva/tests/empty_main.spv_asm new file mode 100644 index 0000000000..ad6e64b4fb --- /dev/null +++ b/third_party/spirv-tools/tools/sva/tests/empty_main.spv_asm @@ -0,0 +1,18 @@ +; SPIR-V +; Version: 1.0 +; Generator: Khronos Glslang Reference Front End; 7 +; Bound: 6 +; Schema: 0 + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" + OpExecutionMode %main OriginUpperLeft + OpSource GLSL 440 + OpName %main "main" + %void = OpTypeVoid + %3 = OpTypeFunction %void + %main = OpFunction %void None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd diff --git a/third_party/spirv-tools/tools/sva/tests/index.html b/third_party/spirv-tools/tools/sva/tests/index.html new file mode 100644 index 0000000000..dd028479b4 --- /dev/null +++ b/third_party/spirv-tools/tools/sva/tests/index.html @@ -0,0 +1,23 @@ + + + + + + +
+ + + + diff --git a/third_party/spirv-tools/tools/sva/tests/simple.spv_asm b/third_party/spirv-tools/tools/sva/tests/simple.spv_asm new file mode 100644 index 0000000000..b4b3f67572 --- /dev/null +++ b/third_party/spirv-tools/tools/sva/tests/simple.spv_asm @@ -0,0 +1,30 @@ +; SPIR-V +; Version: 1.0 +; Generator: Khronos Glslang Reference Front End; 7 +; Bound: 14 +; Schema: 0 + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %gl_FragColor + OpExecutionMode %main OriginUpperLeft + OpSource GLSL 330 + OpName %main "main" + OpName %gl_FragColor "gl_FragColor" + OpDecorate %gl_FragColor Location 0 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 +%_ptr_Output_v4float = OpTypePointer Output %v4float +%gl_FragColor = OpVariable %_ptr_Output_v4float Output +%float_0_400000006 = OpConstant %float 0.400000006 +%float_0_800000012 = OpConstant %float 0.800000012 + %float_1 = OpConstant %float 1 + %13 = OpConstantComposite %v4float %float_0_400000006 %float_0_400000006 %float_0_800000012 %float_1 + %main = OpFunction %void None %3 + %5 = OpLabel + OpStore %gl_FragColor %13 + OpReturn + OpFunctionEnd + diff --git a/third_party/spirv-tools/tools/sva/tools/process_grammar.rb b/third_party/spirv-tools/tools/sva/tools/process_grammar.rb new file mode 100755 index 0000000000..1bbff68621 --- /dev/null +++ b/third_party/spirv-tools/tools/sva/tools/process_grammar.rb @@ -0,0 +1,119 @@ +#!/usr/bin/env ruby + +# Copyright 2019 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. + +require 'json' + +GRAMMAR = "../../external/spirv-headers/include/spirv/unified1/spirv.core.grammar.json" +GLSL = "../../external/spirv-headers/include/spirv/unified1/extinst.glsl.std.450.grammar.json" + +CAPABILITIES = %w( + Matrix + Shader + Sampled1D + Image1D + DerivativeControl + ImageQuery + VulkanMemoryModel +) + +g = JSON.parse(File.open(GRAMMAR).read) +magic = g['magic_number'] +vers = [g['major_version'], g['minor_version']] +instructions = {} + +g['instructions'].each do |inst| + if (inst.has_key?('capabilities')) + skip = true + inst['capabilities'].each do |cap| + if CAPABILITIES.include?(cap) + skip = false + break + end + end + next if skip + end + + op = { + opcode: inst['opcode'], + operands: [] + } + + if !inst['operands'].nil? + inst['operands'].each do |operand| + operand.delete('name') + op[:operands] << operand + end + end + + instructions[inst['opname']] = op +end + +operand_kinds = {} +g['operand_kinds'].each do |op_kind| + next if op_kind['category'] !~ /Enum/ + + kind = { + type: op_kind['category'], + values: {} + } + + op_kind['enumerants'].each do |enum| + if (enum.has_key?('capabilities')) + skip = true + enum['capabilities'].each do |cap| + if CAPABILITIES.include?(cap) + skip = false + break + end + end + next if skip + end + + v = if op_kind['category'] == 'BitEnum' + enum['value'].to_i(16) + else + enum['value'].to_i + end + params = [] + if enum.has_key?('parameters') + enum['parameters'].each do |param| + params << param['kind'] + end + end + kind[:values][enum['enumerant']] = {value: v} + kind[:values][enum['enumerant']][:params] = params unless params.empty? + end + + next if kind[:values].empty? + operand_kinds[op_kind['kind']] = kind +end + +# We only support GLSL extensions at the moment. +ext = {} +glsl = JSON.parse(File.open(GLSL).read) +glsl['instructions'].each do |inst| + ext[inst['opname']] = inst['opcode'] +end + +puts "/*#{g['copyright'].join("\n")}*/" +puts "\n// THIS FILE IS GENERATED WITH tools/process_grammar.rb\n\n" +puts "export default " + JSON.pretty_generate({ + magic: magic, + version: vers, + instructions: instructions, + operand_kinds: operand_kinds, + ext: ext +}) diff --git a/third_party/spirv-tools/tools/sva/yarn.lock b/third_party/spirv-tools/tools/sva/yarn.lock new file mode 100644 index 0000000000..be19e7ca6b --- /dev/null +++ b/third_party/spirv-tools/tools/sva/yarn.lock @@ -0,0 +1,1778 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@babel/code-frame@^7.0.0": + version "7.5.5" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.5.5.tgz#bc0782f6d69f7b7d49531219699b988f669a8f9d" + integrity sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw== + dependencies: + "@babel/highlight" "^7.0.0" + +"@babel/highlight@^7.0.0": + version "7.5.0" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.5.0.tgz#56d11312bd9248fa619591d02472be6e8cb32540" + integrity sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ== + dependencies: + chalk "^2.0.0" + esutils "^2.0.2" + js-tokens "^4.0.0" + +"@types/estree@0.0.39": + version "0.0.39" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f" + integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw== + +"@types/node@^12.7.5": + version "12.7.5" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.7.5.tgz#e19436e7f8e9b4601005d73673b6dc4784ffcc2f" + integrity sha512-9fq4jZVhPNW8r+UYKnxF1e2HkDWOWKM5bC2/7c9wPV835I0aOrVbS/Hw/pWPk2uKrNXQqg9Z959Kz+IYDd5p3w== + +"@zeit/schemas@2.6.0": + version "2.6.0" + resolved "https://registry.yarnpkg.com/@zeit/schemas/-/schemas-2.6.0.tgz#004e8e553b4cd53d538bd38eac7bcbf58a867fe3" + integrity sha512-uUrgZ8AxS+Lio0fZKAipJjAh415JyrOZowliZAzmnJSsf7piVL5w+G0+gFJ0KSu3QRhvui/7zuvpLz03YjXAhg== + +accepts@~1.3.5: + version "1.3.7" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" + integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA== + dependencies: + mime-types "~2.1.24" + negotiator "0.6.2" + +acorn-jsx@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.0.2.tgz#84b68ea44b373c4f8686023a551f61a21b7c4a4f" + integrity sha512-tiNTrP1MP0QrChmD2DdupCr6HWSFeKVw5d/dHTu4Y7rkAkRhU/Dt7dphAfIUyxtHpl/eBVip5uTNSpQJHylpAw== + +acorn@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.0.0.tgz#26b8d1cd9a9b700350b71c0905546f64d1284e7a" + integrity sha512-PaF/MduxijYYt7unVGRuds1vBC9bFxbNf+VWqhOClfdgy7RlVkQqt610ig1/yxTgsDIfW1cWDel5EBbOy3jdtQ== + +ajv@6.5.3: + version "6.5.3" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.5.3.tgz#71a569d189ecf4f4f321224fecb166f071dd90f9" + integrity sha512-LqZ9wY+fx3UMiiPd741yB2pj3hhil+hQc8taf4o2QGRFpWgZ2V5C8HA165DY9sS3fJwsk7uT7ZlFEyC3Ig3lLg== + dependencies: + fast-deep-equal "^2.0.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ajv@^6.10.0, ajv@^6.10.2: + version "6.10.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.2.tgz#d3cea04d6b017b2894ad69040fec8b623eb4bd52" + integrity sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw== + dependencies: + fast-deep-equal "^2.0.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ansi-align@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-2.0.0.tgz#c36aeccba563b89ceb556f3690f0b1d9e3547f7f" + integrity sha1-w2rsy6VjuJzrVW82kPCx2eNUf38= + dependencies: + string-width "^2.0.0" + +ansi-colors@3.2.3: + version "3.2.3" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.3.tgz#57d35b8686e851e2cc04c403f1c00203976a1813" + integrity sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw== + +ansi-escapes@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" + integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ== + +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= + +ansi-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= + +ansi-regex@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" + integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== + +ansi-styles@^3.2.0, ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +arch@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/arch/-/arch-2.1.1.tgz#8f5c2731aa35a30929221bb0640eed65175ec84e" + integrity sha512-BLM56aPo9vLLFVa8+/+pJLnrZ7QGGTVHWsCwieAWT9o9K8UeGaQbzZbGoabWLOo2ksBCztoXdqBZBplqLDDCSg== + +arg@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/arg/-/arg-2.0.0.tgz#c06e7ff69ab05b3a4a03ebe0407fac4cba657545" + integrity sha512-XxNTUzKnz1ctK3ZIcI2XUPlD96wbHP2nGqkPKpvk/HNRlPveYrXIVSTk9m3LcqOgDPg3B1nMvdV/K8wZd7PG4w== + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + +assertion-error@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" + integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== + +astral-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" + integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== + +balanced-match@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= + +boxen@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/boxen/-/boxen-1.3.0.tgz#55c6c39a8ba58d9c61ad22cd877532deb665a20b" + integrity sha512-TNPjfTr432qx7yOjQyaXm3dSR0MH9vXp7eT1BFSl/C51g+EFnOR9hTg1IreahGBmDNCehscshe45f+C1TBZbLw== + dependencies: + ansi-align "^2.0.0" + camelcase "^4.0.0" + chalk "^2.0.1" + cli-boxes "^1.0.0" + string-width "^2.0.0" + term-size "^1.2.0" + widest-line "^2.0.0" + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +browser-stdout@1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" + integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== + +bytes@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" + integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg= + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +camelcase@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" + integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0= + +camelcase@^5.0.0: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +chai@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/chai/-/chai-4.2.0.tgz#760aa72cf20e3795e84b12877ce0e83737aa29e5" + integrity sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw== + dependencies: + assertion-error "^1.1.0" + check-error "^1.0.2" + deep-eql "^3.0.1" + get-func-name "^2.0.0" + pathval "^1.1.0" + type-detect "^4.0.5" + +chalk@2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e" + integrity sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chardet@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" + integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== + +check-error@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" + integrity sha1-V00xLt2Iu13YkS6Sht1sCu1KrII= + +cli-boxes@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-1.0.0.tgz#4fa917c3e59c94a004cd61f8ee509da651687143" + integrity sha1-T6kXw+WclKAEzWH47lCdplFocUM= + +cli-cursor@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" + integrity sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU= + dependencies: + restore-cursor "^2.0.0" + +cli-width@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" + integrity sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk= + +clipboardy@1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/clipboardy/-/clipboardy-1.2.3.tgz#0526361bf78724c1f20be248d428e365433c07ef" + integrity sha512-2WNImOvCRe6r63Gk9pShfkwXsVtKCroMAevIbiae021mS850UkWPbevxsBz3tnvjZIEGvlwaqCPsw+4ulzNgJA== + dependencies: + arch "^2.1.0" + execa "^0.8.0" + +cliui@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.1.0.tgz#348422dbe82d800b3022eef4f6ac10bf2e4d1b49" + integrity sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ== + dependencies: + string-width "^2.1.1" + strip-ansi "^4.0.0" + wrap-ansi "^2.0.0" + +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= + +compressible@~2.0.14: + version "2.0.17" + resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.17.tgz#6e8c108a16ad58384a977f3a482ca20bff2f38c1" + integrity sha512-BGHeLCK1GV7j1bSmQQAi26X+GgWcTjLr/0tzSvMCl3LH1w1IJ4PFSPoV5316b30cneTziC+B1a+3OjoSUcQYmw== + dependencies: + mime-db ">= 1.40.0 < 2" + +compression@1.7.3: + version "1.7.3" + resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.3.tgz#27e0e176aaf260f7f2c2813c3e440adb9f1993db" + integrity sha512-HSjyBG5N1Nnz7tF2+O7A9XUhyjru71/fwgNb7oIsEVHR0WShfs2tIS/EySLgiTe98aOK18YDlMXpzjCXY/n9mg== + dependencies: + accepts "~1.3.5" + bytes "3.0.0" + compressible "~2.0.14" + debug "2.6.9" + on-headers "~1.0.1" + safe-buffer "5.1.2" + vary "~1.1.2" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + +content-disposition@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" + integrity sha1-DPaLud318r55YcOoUXjLhdunjLQ= + +cross-spawn@^5.0.1: + version "5.1.0" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" + integrity sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk= + dependencies: + lru-cache "^4.0.1" + shebang-command "^1.2.0" + which "^1.2.9" + +cross-spawn@^6.0.0, cross-spawn@^6.0.5: + version "6.0.5" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" + integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== + dependencies: + nice-try "^1.0.4" + path-key "^2.0.1" + semver "^5.5.0" + shebang-command "^1.2.0" + which "^1.2.9" + +debug@2.6.9: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +debug@3.2.6: + version "3.2.6" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" + integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== + dependencies: + ms "^2.1.1" + +debug@^4.0.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" + integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== + dependencies: + ms "^2.1.1" + +decamelize@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= + +deep-eql@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-3.0.1.tgz#dfc9404400ad1c8fe023e7da1df1c147c4b444df" + integrity sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw== + dependencies: + type-detect "^4.0.0" + +deep-extend@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" + integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== + +deep-is@~0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" + integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= + +define-properties@^1.1.2, define-properties@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" + integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== + dependencies: + object-keys "^1.0.12" + +diff@3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" + integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== + +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + +emoji-regex@^7.0.1: + version "7.0.3" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" + integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== + +end-of-stream@^1.1.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43" + integrity sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q== + dependencies: + once "^1.4.0" + +es-abstract@^1.5.1: + version "1.14.2" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.14.2.tgz#7ce108fad83068c8783c3cdf62e504e084d8c497" + integrity sha512-DgoQmbpFNOofkjJtKwr87Ma5EW4Dc8fWhD0R+ndq7Oc456ivUfGOOP6oAZTTKl5/CcNMP+EN+e3/iUzgE0veZg== + dependencies: + es-to-primitive "^1.2.0" + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.0" + is-callable "^1.1.4" + is-regex "^1.0.4" + object-inspect "^1.6.0" + object-keys "^1.1.1" + string.prototype.trimleft "^2.0.0" + string.prototype.trimright "^2.0.0" + +es-to-primitive@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.0.tgz#edf72478033456e8dda8ef09e00ad9650707f377" + integrity sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg== + dependencies: + is-callable "^1.1.4" + is-date-object "^1.0.1" + is-symbol "^1.0.2" + +escape-string-regexp@1.0.5, escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= + +eslint-scope@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.0.0.tgz#e87c8887c73e8d1ec84f1ca591645c358bfc8fb9" + integrity sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw== + dependencies: + esrecurse "^4.1.0" + estraverse "^4.1.1" + +eslint-utils@^1.4.2: + version "1.4.2" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.2.tgz#166a5180ef6ab7eb462f162fd0e6f2463d7309ab" + integrity sha512-eAZS2sEUMlIeCjBeubdj45dmBHQwPHWyBcT1VSYB7o9x9WRRqKxyUoiXlRjyAwzN7YEzHJlYg0NmzDRWx6GP4Q== + dependencies: + eslint-visitor-keys "^1.0.0" + +eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz#e2a82cea84ff246ad6fb57f9bde5b46621459ec2" + integrity sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A== + +eslint@^6.3.0: + version "6.4.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-6.4.0.tgz#5aa9227c3fbe921982b2eda94ba0d7fae858611a" + integrity sha512-WTVEzK3lSFoXUovDHEbkJqCVPEPwbhCq4trDktNI6ygs7aO41d4cDT0JFAT5MivzZeVLWlg7vHL+bgrQv/t3vA== + dependencies: + "@babel/code-frame" "^7.0.0" + ajv "^6.10.0" + chalk "^2.1.0" + cross-spawn "^6.0.5" + debug "^4.0.1" + doctrine "^3.0.0" + eslint-scope "^5.0.0" + eslint-utils "^1.4.2" + eslint-visitor-keys "^1.1.0" + espree "^6.1.1" + esquery "^1.0.1" + esutils "^2.0.2" + file-entry-cache "^5.0.1" + functional-red-black-tree "^1.0.1" + glob-parent "^5.0.0" + globals "^11.7.0" + ignore "^4.0.6" + import-fresh "^3.0.0" + imurmurhash "^0.1.4" + inquirer "^6.4.1" + is-glob "^4.0.0" + js-yaml "^3.13.1" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.3.0" + lodash "^4.17.14" + minimatch "^3.0.4" + mkdirp "^0.5.1" + natural-compare "^1.4.0" + optionator "^0.8.2" + progress "^2.0.0" + regexpp "^2.0.1" + semver "^6.1.2" + strip-ansi "^5.2.0" + strip-json-comments "^3.0.1" + table "^5.2.3" + text-table "^0.2.0" + v8-compile-cache "^2.0.3" + +esm@^3.2.25: + version "3.2.25" + resolved "https://registry.yarnpkg.com/esm/-/esm-3.2.25.tgz#342c18c29d56157688ba5ce31f8431fbb795cc10" + integrity sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA== + +espree@^6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-6.1.1.tgz#7f80e5f7257fc47db450022d723e356daeb1e5de" + integrity sha512-EYbr8XZUhWbYCqQRW0duU5LxzL5bETN6AjKBGy1302qqzPaCH10QbRg3Wvco79Z8x9WbiE8HYB4e75xl6qUYvQ== + dependencies: + acorn "^7.0.0" + acorn-jsx "^5.0.2" + eslint-visitor-keys "^1.1.0" + +esprima@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +esquery@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.1.tgz#406c51658b1f5991a5f9b62b1dc25b00e3e5c708" + integrity sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA== + dependencies: + estraverse "^4.0.0" + +esrecurse@^4.1.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf" + integrity sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ== + dependencies: + estraverse "^4.1.0" + +estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1: + version "4.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +execa@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777" + integrity sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c= + dependencies: + cross-spawn "^5.0.1" + get-stream "^3.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + +execa@^0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-0.8.0.tgz#d8d76bbc1b55217ed190fd6dd49d3c774ecfc8da" + integrity sha1-2NdrvBtVIX7RkP1t1J08d07PyNo= + dependencies: + cross-spawn "^5.0.1" + get-stream "^3.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + +execa@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" + integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA== + dependencies: + cross-spawn "^6.0.0" + get-stream "^4.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + +external-editor@^3.0.3: + version "3.1.0" + resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" + integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== + dependencies: + chardet "^0.7.0" + iconv-lite "^0.4.24" + tmp "^0.0.33" + +fast-deep-equal@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" + integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk= + +fast-json-stable-stringify@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" + integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= + +fast-levenshtein@~2.0.4: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= + +fast-url-parser@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/fast-url-parser/-/fast-url-parser-1.1.3.tgz#f4af3ea9f34d8a271cf58ad2b3759f431f0b318d" + integrity sha1-9K8+qfNNiicc9YrSs3WfQx8LMY0= + dependencies: + punycode "^1.3.2" + +figures@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" + integrity sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI= + dependencies: + escape-string-regexp "^1.0.5" + +file-entry-cache@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c" + integrity sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g== + dependencies: + flat-cache "^2.0.1" + +find-up@3.0.0, find-up@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" + integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== + dependencies: + locate-path "^3.0.0" + +flat-cache@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0" + integrity sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA== + dependencies: + flatted "^2.0.0" + rimraf "2.6.3" + write "1.0.3" + +flat@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/flat/-/flat-4.1.0.tgz#090bec8b05e39cba309747f1d588f04dbaf98db2" + integrity sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw== + dependencies: + is-buffer "~2.0.3" + +flatted@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.1.tgz#69e57caa8f0eacbc281d2e2cb458d46fdb449e08" + integrity sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg== + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +functional-red-black-tree@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" + integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= + +get-caller-file@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" + integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w== + +get-caller-file@^2.0.1: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-func-name@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" + integrity sha1-6td0q+5y4gQJQzoGY2YCPdaIekE= + +get-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" + integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ= + +get-stream@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" + integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== + dependencies: + pump "^3.0.0" + +glob-parent@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.0.0.tgz#1dc99f0f39b006d3e92c2c284068382f0c20e954" + integrity sha512-Z2RwiujPRGluePM6j699ktJYxmPpJKCfpGA13jz2hmFZC7gKetzrWvg5KN3+OsIFmydGyZ1AVwERCq1w/ZZwRg== + dependencies: + is-glob "^4.0.1" + +glob@7.1.3: + version "7.1.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" + integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^7.1.3: + version "7.1.4" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255" + integrity sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +globals@^11.7.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +growl@1.10.5: + version "1.10.5" + resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" + integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA== + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= + +has-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44" + integrity sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q= + +has@^1.0.1, has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +he@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" + integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== + +iconv-lite@^0.4.24: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +ignore@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" + integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== + +import-fresh@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.1.0.tgz#6d33fa1dcef6df930fae003446f33415af905118" + integrity sha512-PpuksHKGt8rXfWEr9m9EHIpgyyaltBy8+eF6GJM0QCAxMgxCfucMF3mjecK2QsJr0amJW7gTqh5/wht0z2UhEQ== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +ini@~1.3.0: + version "1.3.5" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" + integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== + +inquirer@^6.4.1: + version "6.5.2" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.5.2.tgz#ad50942375d036d327ff528c08bd5fab089928ca" + integrity sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ== + dependencies: + ansi-escapes "^3.2.0" + chalk "^2.4.2" + cli-cursor "^2.1.0" + cli-width "^2.0.0" + external-editor "^3.0.3" + figures "^2.0.0" + lodash "^4.17.12" + mute-stream "0.0.7" + run-async "^2.2.0" + rxjs "^6.4.0" + string-width "^2.1.0" + strip-ansi "^5.1.0" + through "^2.3.6" + +invert-kv@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02" + integrity sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA== + +is-buffer@~2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.3.tgz#4ecf3fcf749cbd1e472689e109ac66261a25e725" + integrity sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw== + +is-callable@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75" + integrity sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA== + +is-date-object@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" + integrity sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY= + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= + +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= + +is-glob@^4.0.0, is-glob@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" + integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== + dependencies: + is-extglob "^2.1.1" + +is-promise@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" + integrity sha1-eaKp7OfwlugPNtKy87wWwf9L8/o= + +is-regex@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" + integrity sha1-VRdIm1RwkbCTDglWVM7SXul+lJE= + dependencies: + has "^1.0.1" + +is-stream@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= + +is-symbol@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.2.tgz#a055f6ae57192caee329e7a860118b497a950f38" + integrity sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw== + dependencies: + has-symbols "^1.0.0" + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= + +js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@3.13.1, js-yaml@^3.13.1: + version "3.13.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" + integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= + +lcid@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/lcid/-/lcid-2.0.0.tgz#6ef5d2df60e52f82eb228a4c373e8d1f397253cf" + integrity sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA== + dependencies: + invert-kv "^2.0.0" + +levn@^0.3.0, levn@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= + dependencies: + prelude-ls "~1.1.2" + type-check "~0.3.2" + +locate-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" + integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== + dependencies: + p-locate "^3.0.0" + path-exists "^3.0.0" + +lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.14: + version "4.17.15" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" + integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== + +log-symbols@2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a" + integrity sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg== + dependencies: + chalk "^2.0.1" + +lru-cache@^4.0.1: + version "4.1.5" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" + integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g== + dependencies: + pseudomap "^1.0.2" + yallist "^2.1.2" + +map-age-cleaner@^0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz#7d583a7306434c055fe474b0f45078e6e1b4b92a" + integrity sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w== + dependencies: + p-defer "^1.0.0" + +mem@^4.0.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/mem/-/mem-4.3.0.tgz#461af497bc4ae09608cdb2e60eefb69bff744178" + integrity sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w== + dependencies: + map-age-cleaner "^0.1.1" + mimic-fn "^2.0.0" + p-is-promise "^2.0.0" + +mime-db@1.40.0: + version "1.40.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.40.0.tgz#a65057e998db090f732a68f6c276d387d4126c32" + integrity sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA== + +"mime-db@>= 1.40.0 < 2": + version "1.41.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.41.0.tgz#9110408e1f6aa1b34aef51f2c9df3caddf46b6a0" + integrity sha512-B5gxBI+2K431XW8C2rcc/lhppbuji67nf9v39eH8pkWoZDxnAL0PxdpH32KYRScniF8qDHBDlI+ipgg5WrCUYw== + +mime-db@~1.33.0: + version "1.33.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.33.0.tgz#a3492050a5cb9b63450541e39d9788d2272783db" + integrity sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ== + +mime-types@2.1.18: + version "2.1.18" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.18.tgz#6f323f60a83d11146f831ff11fd66e2fe5503bb8" + integrity sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ== + dependencies: + mime-db "~1.33.0" + +mime-types@~2.1.24: + version "2.1.24" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.24.tgz#b6f8d0b3e951efb77dedeca194cff6d16f676f81" + integrity sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ== + dependencies: + mime-db "1.40.0" + +mimic-fn@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" + integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== + +mimic-fn@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +minimatch@3.0.4, minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== + dependencies: + brace-expansion "^1.1.7" + +minimist@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= + +minimist@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" + integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= + +mkdirp@0.5.1, mkdirp@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" + integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= + dependencies: + minimist "0.0.8" + +mocha@^6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-6.2.0.tgz#f896b642843445d1bb8bca60eabd9206b8916e56" + integrity sha512-qwfFgY+7EKAAUAdv7VYMZQknI7YJSGesxHyhn6qD52DV8UcSZs5XwCifcZGMVIE4a5fbmhvbotxC0DLQ0oKohQ== + dependencies: + ansi-colors "3.2.3" + browser-stdout "1.3.1" + debug "3.2.6" + diff "3.5.0" + escape-string-regexp "1.0.5" + find-up "3.0.0" + glob "7.1.3" + growl "1.10.5" + he "1.2.0" + js-yaml "3.13.1" + log-symbols "2.2.0" + minimatch "3.0.4" + mkdirp "0.5.1" + ms "2.1.1" + node-environment-flags "1.0.5" + object.assign "4.1.0" + strip-json-comments "2.0.1" + supports-color "6.0.0" + which "1.3.1" + wide-align "1.1.3" + yargs "13.2.2" + yargs-parser "13.0.0" + yargs-unparser "1.5.0" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= + +ms@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" + integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== + +ms@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +mute-stream@0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" + integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s= + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= + +negotiator@0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" + integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== + +nice-try@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" + integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== + +node-environment-flags@1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/node-environment-flags/-/node-environment-flags-1.0.5.tgz#fa930275f5bf5dae188d6192b24b4c8bbac3d76a" + integrity sha512-VNYPRfGfmZLx0Ye20jWzHUjyTW/c+6Wq+iLhDzUI4XmhrDd9l/FozXV3F2xOaXjvp0co0+v1YSR3CMP6g+VvLQ== + dependencies: + object.getownpropertydescriptors "^2.0.3" + semver "^5.7.0" + +npm-run-path@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" + integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= + dependencies: + path-key "^2.0.0" + +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= + +object-inspect@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.6.0.tgz#c70b6cbf72f274aab4c34c0c82f5167bf82cf15b" + integrity sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ== + +object-keys@^1.0.11, object-keys@^1.0.12, object-keys@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + +object.assign@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da" + integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w== + dependencies: + define-properties "^1.1.2" + function-bind "^1.1.1" + has-symbols "^1.0.0" + object-keys "^1.0.11" + +object.getownpropertydescriptors@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz#8758c846f5b407adab0f236e0986f14b051caa16" + integrity sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY= + dependencies: + define-properties "^1.1.2" + es-abstract "^1.5.1" + +on-headers@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" + integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== + +once@^1.3.0, once@^1.3.1, once@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + dependencies: + wrappy "1" + +onetime@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" + integrity sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ= + dependencies: + mimic-fn "^1.0.0" + +optionator@^0.8.2: + version "0.8.2" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" + integrity sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q= + dependencies: + deep-is "~0.1.3" + fast-levenshtein "~2.0.4" + levn "~0.3.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" + wordwrap "~1.0.0" + +os-locale@^3.0.0, os-locale@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.1.0.tgz#a802a6ee17f24c10483ab9935719cef4ed16bf1a" + integrity sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q== + dependencies: + execa "^1.0.0" + lcid "^2.0.0" + mem "^4.0.0" + +os-tmpdir@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= + +p-defer@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c" + integrity sha1-n26xgvbJqozXQwBKfU+WsZaw+ww= + +p-finally@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= + +p-is-promise@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-2.1.0.tgz#918cebaea248a62cf7ffab8e3bca8c5f882fc42e" + integrity sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg== + +p-limit@^2.0.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.1.tgz#aa07a788cc3151c939b5131f63570f0dd2009537" + integrity sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg== + dependencies: + p-try "^2.0.0" + +p-locate@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" + integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== + dependencies: + p-limit "^2.0.0" + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + +path-is-inside@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" + integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM= + +path-key@^2.0.0, path-key@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= + +path-to-regexp@2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-2.2.1.tgz#90b617025a16381a879bc82a38d4e8bdeb2bcf45" + integrity sha512-gu9bD6Ta5bwGrrU8muHzVOBFFREpp2iRkVfhBJahwJ6p6Xw20SjT0MxLnwkjOibQmGSYhiUnf2FLe7k+jcFmGQ== + +pathval@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.0.tgz#b942e6d4bde653005ef6b71361def8727d0645e0" + integrity sha1-uULm1L3mUwBe9rcTYd74cn0GReA= + +prelude-ls@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= + +progress@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" + integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== + +pseudomap@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" + integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= + +pump@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" + integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +punycode@^1.3.2: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= + +punycode@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== + +range-parser@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" + integrity sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4= + +rc@^1.0.1, rc@^1.1.6: + version "1.2.8" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" + integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== + dependencies: + deep-extend "^0.6.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~2.0.1" + +regexpp@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" + integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw== + +registry-auth-token@3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-3.3.2.tgz#851fd49038eecb586911115af845260eec983f20" + integrity sha512-JL39c60XlzCVgNrO+qq68FoNb56w/m7JYvGR2jT5iR1xBrUA3Mfx5Twk5rqTThPmQKMWydGmq8oFtDlxfrmxnQ== + dependencies: + rc "^1.1.6" + safe-buffer "^5.0.1" + +registry-url@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-3.1.0.tgz#3d4ef870f73dde1d77f0cf9a381432444e174942" + integrity sha1-PU74cPc93h138M+aOBQyRE4XSUI= + dependencies: + rc "^1.0.1" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= + +require-main-filename@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" + integrity sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE= + +require-main-filename@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" + integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +restore-cursor@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" + integrity sha1-n37ih/gv0ybU/RYpI9YhKe7g368= + dependencies: + onetime "^2.0.0" + signal-exit "^3.0.2" + +rimraf@2.6.3: + version "2.6.3" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" + integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== + dependencies: + glob "^7.1.3" + +rollup@^1.21.4: + version "1.21.4" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-1.21.4.tgz#00a41a30f90095db890301b226cbe2918e4cf54d" + integrity sha512-Pl512XVCmVzgcBz5h/3Li4oTaoDcmpuFZ+kdhS/wLreALz//WuDAMfomD3QEYl84NkDu6Z6wV9twlcREb4qQsw== + dependencies: + "@types/estree" "0.0.39" + "@types/node" "^12.7.5" + acorn "^7.0.0" + +run-async@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" + integrity sha1-A3GrSuC91yDUFm19/aZP96RFpsA= + dependencies: + is-promise "^2.1.0" + +rxjs@^6.4.0: + version "6.5.3" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.3.tgz#510e26317f4db91a7eb1de77d9dd9ba0a4899a3a" + integrity sha512-wuYsAYYFdWTAnAaPoKGNhfpWwKZbJW+HgAJ+mImp+Epl7BG8oNWBCTyRM8gba9k4lk8BgWdoYm21Mo/RYhhbgA== + dependencies: + tslib "^1.9.0" + +safe-buffer@5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +safe-buffer@^5.0.1: + version "5.2.0" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519" + integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg== + +"safer-buffer@>= 2.1.2 < 3": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +semver@^5.5.0, semver@^5.7.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" + integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== + +semver@^6.1.2: + version "6.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + +serve-handler@6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/serve-handler/-/serve-handler-6.1.0.tgz#f1606dc6ff8f9029a1ee042c11dfe7903a5cb92e" + integrity sha512-63N075Tn3PsFYcu0NVV7tb367UbiW3gnC+/50ohL4oqOhAG6bmbaWqiRcXQgbzqc0ALBjSAzg7VTfa0Qw4E3hA== + dependencies: + bytes "3.0.0" + content-disposition "0.5.2" + fast-url-parser "1.1.3" + mime-types "2.1.18" + minimatch "3.0.4" + path-is-inside "1.0.2" + path-to-regexp "2.2.1" + range-parser "1.2.0" + +serve@^11.1.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/serve/-/serve-11.1.0.tgz#1bfe2f4a08d0130cbf44711cdb7996cb742172e0" + integrity sha512-+4wpDtOSS+4ZLyDWMxThutA3iOTawX2+yDovOI8cjOUOmemyvNlHyFAsezBlSgbZKTYChI3tzA1Mh0z6XZ62qA== + dependencies: + "@zeit/schemas" "2.6.0" + ajv "6.5.3" + arg "2.0.0" + boxen "1.3.0" + chalk "2.4.1" + clipboardy "1.2.3" + compression "1.7.3" + serve-handler "6.1.0" + update-check "1.5.2" + +set-blocking@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= + +shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= + dependencies: + shebang-regex "^1.0.0" + +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= + +signal-exit@^3.0.0, signal-exit@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" + integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= + +slice-ansi@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" + integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ== + dependencies: + ansi-styles "^3.2.0" + astral-regex "^1.0.0" + is-fullwidth-code-point "^2.0.0" + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= + +string-width@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +"string-width@^1.0.2 || 2", string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^4.0.0" + +string-width@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" + integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== + dependencies: + emoji-regex "^7.0.1" + is-fullwidth-code-point "^2.0.0" + strip-ansi "^5.1.0" + +string.prototype.trimleft@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/string.prototype.trimleft/-/string.prototype.trimleft-2.1.0.tgz#6cc47f0d7eb8d62b0f3701611715a3954591d634" + integrity sha512-FJ6b7EgdKxxbDxc79cOlok6Afd++TTs5szo+zJTUyow3ycrRfJVE2pq3vcN53XexvKZu/DJMDfeI/qMiZTrjTw== + dependencies: + define-properties "^1.1.3" + function-bind "^1.1.1" + +string.prototype.trimright@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/string.prototype.trimright/-/string.prototype.trimright-2.1.0.tgz#669d164be9df9b6f7559fa8e89945b168a5a6c58" + integrity sha512-fXZTSV55dNBwv16uw+hh5jkghxSnc5oHq+5K/gXgizHwAvMetdAJlHqqoFC1FSDVPYWLkAKl2cxpUT41sV7nSg== + dependencies: + define-properties "^1.1.3" + function-bind "^1.1.1" + +strip-ansi@^3.0.0, strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= + dependencies: + ansi-regex "^2.0.0" + +strip-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= + dependencies: + ansi-regex "^3.0.0" + +strip-ansi@^5.1.0, strip-ansi@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" + integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== + dependencies: + ansi-regex "^4.1.0" + +strip-eof@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" + integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= + +strip-json-comments@2.0.1, strip-json-comments@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= + +strip-json-comments@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.0.1.tgz#85713975a91fb87bf1b305cca77395e40d2a64a7" + integrity sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw== + +supports-color@6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.0.0.tgz#76cfe742cf1f41bb9b1c29ad03068c05b4c0e40a" + integrity sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg== + dependencies: + has-flag "^3.0.0" + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +table@^5.2.3: + version "5.4.6" + resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" + integrity sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug== + dependencies: + ajv "^6.10.2" + lodash "^4.17.14" + slice-ansi "^2.1.0" + string-width "^3.0.0" + +term-size@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/term-size/-/term-size-1.2.0.tgz#458b83887f288fc56d6fffbfad262e26638efa69" + integrity sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk= + dependencies: + execa "^0.7.0" + +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= + +through@^2.3.6: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= + +tmp@^0.0.33: + version "0.0.33" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== + dependencies: + os-tmpdir "~1.0.2" + +tslib@^1.9.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a" + integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ== + +type-check@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= + dependencies: + prelude-ls "~1.1.2" + +type-detect@^4.0.0, type-detect@^4.0.5: + version "4.0.8" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" + integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== + +update-check@1.5.2: + version "1.5.2" + resolved "https://registry.yarnpkg.com/update-check/-/update-check-1.5.2.tgz#2fe09f725c543440b3d7dabe8971f2d5caaedc28" + integrity sha512-1TrmYLuLj/5ZovwUS7fFd1jMH3NnFDN1y1A8dboedIDt7zs/zJMo6TwwlhYKkSeEwzleeiSBV5/3c9ufAQWDaQ== + dependencies: + registry-auth-token "3.3.2" + registry-url "3.1.0" + +uri-js@^4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" + integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ== + dependencies: + punycode "^2.1.0" + +v8-compile-cache@^2.0.3: + version "2.1.0" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz#e14de37b31a6d194f5690d67efc4e7f6fc6ab30e" + integrity sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g== + +vary@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= + +which-module@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" + integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= + +which@1.3.1, which@^1.2.9: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + +wide-align@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" + integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== + dependencies: + string-width "^1.0.2 || 2" + +widest-line@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-2.0.1.tgz#7438764730ec7ef4381ce4df82fb98a53142a3fc" + integrity sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA== + dependencies: + string-width "^2.1.1" + +wordwrap@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= + +wrap-ansi@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" + integrity sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU= + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + +write@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3" + integrity sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig== + dependencies: + mkdirp "^0.5.1" + +"y18n@^3.2.1 || ^4.0.0", y18n@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" + integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w== + +yallist@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" + integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= + +yargs-parser@13.0.0: + version "13.0.0" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.0.0.tgz#3fc44f3e76a8bdb1cc3602e860108602e5ccde8b" + integrity sha512-w2LXjoL8oRdRQN+hOyppuXs+V/fVAYtpcrRxZuF7Kt/Oc+Jr2uAcVntaUTNT6w5ihoWfFDpNY8CPx1QskxZ/pw== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + +yargs-parser@^11.1.1: + version "11.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-11.1.1.tgz#879a0865973bca9f6bab5cbdf3b1c67ec7d3bcf4" + integrity sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + +yargs-parser@^13.0.0: + version "13.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.1.tgz#d26058532aa06d365fe091f6a1fc06b2f7e5eca0" + integrity sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + +yargs-unparser@1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-1.5.0.tgz#f2bb2a7e83cbc87bb95c8e572828a06c9add6e0d" + integrity sha512-HK25qidFTCVuj/D1VfNiEndpLIeJN78aqgR23nL3y4N0U/91cOAzqfHlF8n2BvoNDcZmJKin3ddNSvOxSr8flw== + dependencies: + flat "^4.1.0" + lodash "^4.17.11" + yargs "^12.0.5" + +yargs@13.2.2: + version "13.2.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.2.2.tgz#0c101f580ae95cea7f39d927e7770e3fdc97f993" + integrity sha512-WyEoxgyTD3w5XRpAQNYUB9ycVH/PQrToaTXdYXRdOXvEy1l19br+VJsc0vcO8PTGg5ro/l/GY7F/JMEBmI0BxA== + dependencies: + cliui "^4.0.0" + find-up "^3.0.0" + get-caller-file "^2.0.1" + os-locale "^3.1.0" + require-directory "^2.1.1" + require-main-filename "^2.0.0" + set-blocking "^2.0.0" + string-width "^3.0.0" + which-module "^2.0.0" + y18n "^4.0.0" + yargs-parser "^13.0.0" + +yargs@^12.0.5: + version "12.0.5" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.5.tgz#05f5997b609647b64f66b81e3b4b10a368e7ad13" + integrity sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw== + dependencies: + cliui "^4.0.0" + decamelize "^1.2.0" + find-up "^3.0.0" + get-caller-file "^1.0.1" + os-locale "^3.0.0" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^2.0.0" + which-module "^2.0.0" + y18n "^3.2.1 || ^4.0.0" + yargs-parser "^11.1.1" diff --git a/third_party/spirv-tools/tools/util/cli_consumer.h b/third_party/spirv-tools/tools/util/cli_consumer.h index ca3d91b95a..64a5e46b84 100644 --- a/third_party/spirv-tools/tools/util/cli_consumer.h +++ b/third_party/spirv-tools/tools/util/cli_consumer.h @@ -15,7 +15,7 @@ #ifndef SOURCE_UTIL_CLI_CONSUMMER_H_ #define SOURCE_UTIL_CLI_CONSUMMER_H_ -#include +#include "include/spirv-tools/libspirv.h" namespace spvtools { namespace utils { diff --git a/third_party/spirv-tools/tools/val/val.cpp b/third_party/spirv-tools/tools/val/val.cpp index 172dd121de..19b8c776a8 100644 --- a/third_party/spirv-tools/tools/val/val.cpp +++ b/third_party/spirv-tools/tools/val/val.cpp @@ -25,6 +25,7 @@ #include "tools/util/cli_consumer.h" void print_usage(char* argv0) { + std::string target_env_list = spvTargetEnvList(36, 105); printf( R"(%s - Validate a SPIR-V binary file. @@ -45,25 +46,35 @@ Options: --max-function-args --max-control-flow-nesting-depth --max-access-chain-indexes + --max-id-bound --relax-logical-pointer Allow allocating an object of a pointer type and returning a pointer value from a function in logical addressing mode - --relax-block-layout Enable VK_HR_relaxed_block_layout when checking standard - uniform/storage buffer layout - --skip-block-layout Skip checking standard uniform/storage buffer layout + --relax-block-layout Enable VK_KHR_relaxed_block_layout when checking standard + uniform, storage buffer, and push constant layouts. + This is the default when targeting Vulkan 1.1 or later. + --uniform-buffer-standard-layout Enable VK_KHR_uniform_buffer_standard_layout when checking standard + uniform buffer layouts. + --scalar-block-layout Enable VK_EXT_scalar_block_layout when checking standard + uniform, storage buffer, and push constant layouts. Scalar layout + rules are more permissive than relaxed block layout so in effect + this will override the --relax-block-layout option. + --skip-block-layout Skip checking standard uniform/storage buffer layout. + Overrides any --relax-block-layout or --scalar-block-layout option. --relax-struct-store Allow store from one struct type to a different type with compatible layout and members. + --before-hlsl-legalization Allows code patterns that are intended to be + fixed by spirv-opt's legalization passes. --version Display validator version information. - --target-env {vulkan1.0|vulkan1.1|opencl2.2|spv1.0|spv1.1|spv1.2|spv1.3|webgpu0} - Use Vulkan 1.0, Vulkan 1.1, OpenCL 2.2, SPIR-V 1.0, - SPIR-V 1.1, SPIR-V 1.2, SPIR-V 1.3 or WIP WebGPU validation rules. + --target-env {%s} + Use validation rules from the specified environment. )", - argv0, argv0); + argv0, argv0, target_env_list.c_str()); } int main(int argc, char** argv) { const char* inFile = nullptr; - spv_target_env target_env = SPV_ENV_UNIVERSAL_1_3; + spv_target_env target_env = SPV_ENV_UNIVERSAL_1_5; spvtools::ValidatorOptions options; bool continue_processing = true; int return_code = 0; @@ -95,15 +106,20 @@ int main(int argc, char** argv) { } } else if (0 == strcmp(cur_arg, "--version")) { printf("%s\n", spvSoftwareVersionDetailsString()); - printf("Targets:\n %s\n %s\n %s\n %s\n %s\n %s\n %s\n %s\n", - spvTargetEnvDescription(SPV_ENV_UNIVERSAL_1_0), - spvTargetEnvDescription(SPV_ENV_UNIVERSAL_1_1), - spvTargetEnvDescription(SPV_ENV_UNIVERSAL_1_2), - spvTargetEnvDescription(SPV_ENV_UNIVERSAL_1_3), - spvTargetEnvDescription(SPV_ENV_OPENCL_2_2), - spvTargetEnvDescription(SPV_ENV_VULKAN_1_0), - spvTargetEnvDescription(SPV_ENV_VULKAN_1_1), - spvTargetEnvDescription(SPV_ENV_WEBGPU_0)); + printf( + "Targets:\n %s\n %s\n %s\n %s\n %s\n %s\n %s\n %s\n %s\n " + "%s\n %s\n", + spvTargetEnvDescription(SPV_ENV_UNIVERSAL_1_0), + spvTargetEnvDescription(SPV_ENV_UNIVERSAL_1_1), + spvTargetEnvDescription(SPV_ENV_UNIVERSAL_1_2), + spvTargetEnvDescription(SPV_ENV_UNIVERSAL_1_3), + spvTargetEnvDescription(SPV_ENV_UNIVERSAL_1_4), + spvTargetEnvDescription(SPV_ENV_UNIVERSAL_1_5), + spvTargetEnvDescription(SPV_ENV_OPENCL_2_2), + spvTargetEnvDescription(SPV_ENV_VULKAN_1_0), + spvTargetEnvDescription(SPV_ENV_VULKAN_1_1), + spvTargetEnvDescription(SPV_ENV_VULKAN_1_1_SPIRV_1_4), + spvTargetEnvDescription(SPV_ENV_WEBGPU_0)); continue_processing = false; return_code = 0; } else if (0 == strcmp(cur_arg, "--help") || 0 == strcmp(cur_arg, "-h")) { @@ -123,10 +139,16 @@ int main(int argc, char** argv) { continue_processing = false; return_code = 1; } + } else if (0 == strcmp(cur_arg, "--before-hlsl-legalization")) { + options.SetBeforeHlslLegalization(true); } else if (0 == strcmp(cur_arg, "--relax-logical-pointer")) { options.SetRelaxLogicalPointer(true); } else if (0 == strcmp(cur_arg, "--relax-block-layout")) { options.SetRelaxBlockLayout(true); + } else if (0 == strcmp(cur_arg, "--uniform-buffer-standard-layout")) { + options.SetUniformBufferStandardLayout(true); + } else if (0 == strcmp(cur_arg, "--scalar-block-layout")) { + options.SetScalarBlockLayout(true); } else if (0 == strcmp(cur_arg, "--skip-block-layout")) { options.SetSkipBlockLayout(true); } else if (0 == strcmp(cur_arg, "--relax-struct-store")) { diff --git a/third_party/spirv-tools/utils/check_code_format.sh b/third_party/spirv-tools/utils/check_code_format.sh index a6a58796a7..7994740226 100755 --- a/third_party/spirv-tools/utils/check_code_format.sh +++ b/third_party/spirv-tools/utils/check_code_format.sh @@ -18,14 +18,16 @@ # # This script assumes to be invoked at the project root directory. -FILES_TO_CHECK=$(git diff --name-only master | grep -E ".*\.(cpp|cc|c\+\+|cxx|c|h|hpp)$") +BASE_BRANCH=${1:-master} + +FILES_TO_CHECK=$(git diff --name-only ${BASE_BRANCH} | grep -E ".*\.(cpp|cc|c\+\+|cxx|c|h|hpp)$") if [ -z "${FILES_TO_CHECK}" ]; then echo "No source code to check for formatting." exit 0 fi -FORMAT_DIFF=$(git diff -U0 master -- ${FILES_TO_CHECK} | python ./utils/clang-format-diff.py -p1 -style=file) +FORMAT_DIFF=$(git diff -U0 ${BASE_BRANCH} -- ${FILES_TO_CHECK} | python ./utils/clang-format-diff.py -p1 -style=file) if [ -z "${FORMAT_DIFF}" ]; then echo "All source code in PR properly formatted." diff --git a/third_party/spirv-tools/utils/check_copyright.py b/third_party/spirv-tools/utils/check_copyright.py index 85ea12891f..2d288a1226 100755 --- a/third_party/spirv-tools/utils/check_copyright.py +++ b/third_party/spirv-tools/utils/check_copyright.py @@ -16,7 +16,6 @@ current directory. Optionally insert them. When inserting, replaces an MIT or Khronos free use license with Apache 2. """ -from __future__ import print_function import argparse import fileinput @@ -31,10 +30,11 @@ AUTHORS = ['The Khronos Group Inc.', 'LunarG Inc.', 'Google Inc.', 'Google LLC', - 'Pierre Moreau'] -CURRENT_YEAR='2018' + 'Pierre Moreau', + 'Samsung Inc'] +CURRENT_YEAR='2020' -YEARS = '(2014-2016|2015-2016|2016|2016-2017|2017|2018)' +YEARS = '(2014-2016|2015-2016|2016|2016-2017|2017|2017-2019|2018|2019|2020)' COPYRIGHT_RE = re.compile( 'Copyright \(c\) {} ({})'.format(YEARS, '|'.join(AUTHORS))) diff --git a/third_party/spirv-tools/utils/check_symbol_exports.py b/third_party/spirv-tools/utils/check_symbol_exports.py index c9c0364df0..e14c2eb896 100755 --- a/third_party/spirv-tools/utils/check_symbol_exports.py +++ b/third_party/spirv-tools/utils/check_symbol_exports.py @@ -14,8 +14,6 @@ # limitations under the License. """Checks names of global exports from a library.""" -from __future__ import print_function - import os.path import re import subprocess @@ -56,6 +54,13 @@ def check_library(library): # _ZN : something in a namespace # _Z[0-9]+spv[A-Z_] : C++ symbol starting with spv[A-Z_] symbol_ok_pattern = re.compile(r'^(spv[A-Z]|_ZN|_Z[0-9]+spv[A-Z_])') + + # In addition, the following pattern whitelists global functions that are added + # by the protobuf compiler: + # - AddDescriptors_spvtoolsfuzz_2eproto() + # - InitDefaults_spvtoolsfuzz_2eproto() + symbol_whitelist_pattern = re.compile(r'_Z[0-9]+(InitDefaults|AddDescriptors)_spvtoolsfuzz_2eprotov') + seen = set() result = 0 for line in command_output(['objdump', '-t', library], '.').split('\n'): @@ -65,7 +70,7 @@ def check_library(library): if symbol not in seen: seen.add(symbol) #print("look at '{}'".format(symbol)) - if not symbol_ok_pattern.match(symbol): + if not (symbol_whitelist_pattern.match(symbol) or symbol_ok_pattern.match(symbol)): print('{}: error: Unescaped exported symbol: {}'.format(PROG, symbol)) result = 1 return result @@ -81,7 +86,7 @@ def main(): print('{}: error: {} does not exist'.format(PROG, args.library)) sys.exit(1) - if os.name is 'posix': + if os.name == 'posix': status = check_library(args.library) sys.exit(status) else: diff --git a/third_party/spirv-tools/utils/generate_grammar_tables.py b/third_party/spirv-tools/utils/generate_grammar_tables.py index aabdad505e..2a67733697 100755 --- a/third_party/spirv-tools/utils/generate_grammar_tables.py +++ b/third_party/spirv-tools/utils/generate_grammar_tables.py @@ -14,8 +14,6 @@ # limitations under the License. """Generates various info tables from SPIR-V JSON grammar.""" -from __future__ import print_function - import errno import json import os.path @@ -32,12 +30,13 @@ SPV_AMD_gcn_shader SPV_AMD_gpu_shader_half_float SPV_AMD_gpu_shader_int16 SPV_AMD_shader_trinary_minmax +SPV_KHR_non_semantic_info """ def make_path_to_file(f): - """Makes all ancestor directories to the given file, if they - don't yet exist. + """Makes all ancestor directories to the given file, if they don't yet + exist. Arguments: f: The file whose ancestor directories are to be created. @@ -53,8 +52,8 @@ def make_path_to_file(f): def convert_min_required_version(version): - """Converts the minimal required SPIR-V version encoded in the - grammar to the symbol in SPIRV-Tools""" + """Converts the minimal required SPIR-V version encoded in the grammar to + the symbol in SPIRV-Tools.""" if version is None: return 'SPV_SPIRV_VERSION_WORD(1, 0)' if version == 'None': @@ -62,6 +61,14 @@ def convert_min_required_version(version): return 'SPV_SPIRV_VERSION_WORD({})'.format(version.replace('.', ',')) +def convert_max_required_version(version): + """Converts the maximum required SPIR-V version encoded in the grammar to + the symbol in SPIRV-Tools.""" + if version is None: + return '0xffffffffu' + return 'SPV_SPIRV_VERSION_WORD({})'.format(version.replace('.', ',')) + + def compose_capability_list(caps): """Returns a string containing a braced list of capabilities as enums. @@ -71,7 +78,7 @@ def compose_capability_list(caps): Returns: a string containing the braced list of SpvCapability* enums named by caps. """ - return "{" + ", ".join(['SpvCapability{}'.format(c) for c in caps]) + "}" + return '{' + ', '.join(['SpvCapability{}'.format(c) for c in caps]) + '}' def get_capability_array_name(caps): @@ -108,8 +115,8 @@ def compose_extension_list(exts): Returns: a string containing the braced list of extensions named by exts. """ - return "{" + ", ".join( - ['spvtools::Extension::k{}'.format(e) for e in exts]) + "}" + return '{' + ', '.join( + ['spvtools::Extension::k{}'.format(e) for e in exts]) + '}' def get_extension_array_name(extensions): @@ -140,8 +147,8 @@ def generate_extension_arrays(extensions): def convert_operand_kind(operand_tuple): - """Returns the corresponding operand type used in spirv-tools for - the given operand kind and quantifier used in the JSON grammar. + """Returns the corresponding operand type used in spirv-tools for the given + operand kind and quantifier used in the JSON grammar. Arguments: - operand_tuple: a tuple of two elements: @@ -203,10 +210,10 @@ def convert_operand_kind(operand_tuple): class InstInitializer(object): - """Instances holds a SPIR-V instruction suitable for printing as - the initializer for spv_opcode_desc_t.""" + """Instances holds a SPIR-V instruction suitable for printing as the + initializer for spv_opcode_desc_t.""" - def __init__(self, opname, caps, exts, operands, version): + def __init__(self, opname, caps, exts, operands, version, lastVersion): """Initialization. Arguments: @@ -215,6 +222,7 @@ class InstInitializer(object): - exts: a sequence of names of extensions enabling this enumerant - operands: a sequence of (operand-kind, operand-quantifier) tuples - version: minimal SPIR-V version required for this opcode + - lastVersion: last version of SPIR-V that includes this opcode """ assert opname.startswith('Op') @@ -232,10 +240,11 @@ class InstInitializer(object): self.def_result_id = 'IdResult' in operands self.version = convert_min_required_version(version) + self.lastVersion = convert_max_required_version(lastVersion) def fix_syntax(self): - """Fix an instruction's syntax, adjusting for differences between - the officially released grammar and how SPIRV-Tools uses the grammar. + """Fix an instruction's syntax, adjusting for differences between the + officially released grammar and how SPIRV-Tools uses the grammar. Fixes: - ExtInst should not end with SPV_OPERAND_VARIABLE_ID. @@ -251,7 +260,7 @@ class InstInitializer(object): '{num_operands}', '{{{operands}}}', '{def_result_id}', '{ref_type_id}', '{num_exts}', '{exts}', - '{min_version}}}'] + '{min_version}', '{max_version}}}'] return ', '.join(template).format( opname=self.opname, num_caps=self.num_caps, @@ -262,7 +271,8 @@ class InstInitializer(object): ref_type_id=(1 if self.ref_type_id else 0), num_exts=self.num_exts, exts=self.exts, - min_version=self.version) + min_version=self.version, + max_version=self.lastVersion) class ExtInstInitializer(object): @@ -315,18 +325,19 @@ def generate_instruction(inst, is_ext_inst): operands = inst.get('operands', {}) operands = [(o['kind'], o.get('quantifier', '')) for o in operands] min_version = inst.get('version', None) + max_version = inst.get('lastVersion', None) assert opname is not None if is_ext_inst: return str(ExtInstInitializer(opname, opcode, caps, operands)) else: - return str(InstInitializer(opname, caps, exts, operands, min_version)) + return str(InstInitializer(opname, caps, exts, operands, min_version, max_version)) def generate_instruction_table(inst_table): - """Returns the info table containing all SPIR-V instructions, - sorted by opcode, and prefixed by capability arrays. + """Returns the info table containing all SPIR-V instructions, sorted by + opcode, and prefixed by capability arrays. Note: - the built-in sorted() function is guaranteed to be stable. @@ -349,14 +360,22 @@ def generate_instruction_table(inst_table): return '{}\n\n{}\n\n{}'.format(caps_arrays, exts_arrays, '\n'.join(insts)) -def generate_extended_instruction_table(inst_table, set_name): +def generate_extended_instruction_table(json_grammar, set_name, operand_kind_prefix=""): """Returns the info table containing all SPIR-V extended instructions, sorted by opcode, and prefixed by capability arrays. Arguments: - inst_table: a list containing all SPIR-V instructions. - set_name: the name of the extended instruction set. + - operand_kind_prefix: the prefix, if any, to add to the front + of operand kind names. """ + if operand_kind_prefix: + prefix_operand_kind_names(operand_kind_prefix, json_grammar) + + inst_table = json_grammar["instructions"] + set_name = set_name.replace(".", "_") + inst_table = sorted(inst_table, key=lambda k: k['opcode']) caps = [inst.get('capabilities', []) for inst in inst_table] caps_arrays = generate_capability_arrays(caps) @@ -370,7 +389,7 @@ def generate_extended_instruction_table(inst_table, set_name): class EnumerantInitializer(object): """Prints an enumerant as the initializer for spv_operand_desc_t.""" - def __init__(self, enumerant, value, caps, exts, parameters, version): + def __init__(self, enumerant, value, caps, exts, parameters, version, lastVersion): """Initialization. Arguments: @@ -380,6 +399,7 @@ class EnumerantInitializer(object): - exts: a sequence of names of extensions enabling this enumerant - parameters: a sequence of (operand-kind, operand-quantifier) tuples - version: minimal SPIR-V version required for this opcode + - lastVersion: last SPIR-V version this opode appears """ self.enumerant = enumerant self.value = value @@ -389,11 +409,13 @@ class EnumerantInitializer(object): self.exts = get_extension_array_name(exts) self.parameters = [convert_operand_kind(p) for p in parameters] self.version = convert_min_required_version(version) + self.lastVersion = convert_max_required_version(lastVersion) def __str__(self): template = ['{{"{enumerant}"', '{value}', '{num_caps}', '{caps}', '{num_exts}', '{exts}', - '{{{parameters}}}', '{min_version}}}'] + '{{{parameters}}}', '{min_version}', + '{max_version}}}'] return ', '.join(template).format( enumerant=self.enumerant, value=self.value, @@ -402,14 +424,16 @@ class EnumerantInitializer(object): num_exts=self.num_exts, exts=self.exts, parameters=', '.join(self.parameters), - min_version=self.version) + min_version=self.version, + max_version=self.lastVersion) -def generate_enum_operand_kind_entry(entry): +def generate_enum_operand_kind_entry(entry, extension_map): """Returns the C initializer for the given operand enum entry. Arguments: - entry: a dict containing information about an enum entry + - extension_map: a dict mapping enum value to list of extensions Returns: a string containing the C initializer for spv_operand_desc_t @@ -417,35 +441,61 @@ def generate_enum_operand_kind_entry(entry): enumerant = entry.get('enumerant') value = entry.get('value') caps = entry.get('capabilities', []) - exts = entry.get('extensions', []) + if value in extension_map: + exts = extension_map[value] + else: + exts = [] params = entry.get('parameters', []) params = [p.get('kind') for p in params] params = zip(params, [''] * len(params)) version = entry.get('version', None) + max_version = entry.get('lastVersion', None) assert enumerant is not None assert value is not None return str(EnumerantInitializer( - enumerant, value, caps, exts, params, version)) + enumerant, value, caps, exts, params, version, max_version)) -def generate_enum_operand_kind(enum): - """Returns the C definition for the given operand kind.""" +def generate_enum_operand_kind(enum, synthetic_exts_list): + """Returns the C definition for the given operand kind. + It's a static const named array of spv_operand_desc_t. + + Also appends to |synthetic_exts_list| a list of extension lists + used. + """ kind = enum.get('kind') assert kind is not None - # Sort all enumerants first according to their values and then - # their names so that the symbols with the same values are - # grouped together. + # Sort all enumerants according to their values, but otherwise + # preserve their order so the first name listed in the grammar + # as the preferred name for disassembly. if enum.get('category') == 'ValueEnum': - functor = lambda k: (k['value'], k['enumerant']) + def functor(k): return (k['value']) else: - functor = lambda k: (int(k['value'], 16), k['enumerant']) + def functor(k): return (int(k['value'], 16)) entries = sorted(enum.get('enumerants', []), key=functor) + # SubgroupEqMask and SubgroupEqMaskKHR are the same number with + # same semantics, but one has no extension list while the other + # does. Both should have the extension list. + # So create a mapping from enum value to the union of the extensions + # across all those grammar entries. Preserve order. + extension_map = {} + for e in entries: + value = e.get('value') + extension_map[value] = [] + for e in entries: + value = e.get('value') + exts = e.get('extensions', []) + for ext in exts: + if ext not in extension_map[value]: + extension_map[value].append(ext) + synthetic_exts_list.extend(extension_map.values()) + name = '{}_{}Entries'.format(PYGEN_VARIABLE_PREFIX, kind) - entries = [' {}'.format(generate_enum_operand_kind_entry(e)) + entries = [' {}'.format(generate_enum_operand_kind_entry(e, extension_map)) for e in entries] template = ['static const spv_operand_desc_t {name}[] = {{', @@ -470,9 +520,9 @@ def generate_operand_kind_table(enums): exts = [entry.get('extensions', []) for enum in enums for entry in enum.get('enumerants', [])] + enums = [generate_enum_operand_kind(e, exts) for e in enums] exts_arrays = generate_extension_arrays(exts) - enums = [generate_enum_operand_kind(e) for e in enums] # We have three operand kinds that requires their optional counterpart to # exist in the operand info table. three_optional_enums = ['ImageOperands', 'AccessQualifier', 'MemoryAccess'] @@ -504,7 +554,8 @@ def get_extension_list(instructions, operand_kinds): things_with_an_extensions_field = [item for item in instructions] - enumerants = sum([item.get('enumerants', []) for item in operand_kinds], []) + enumerants = sum([item.get('enumerants', []) + for item in operand_kinds], []) things_with_an_extensions_field.extend(enumerants) @@ -513,11 +564,12 @@ def get_extension_list(instructions, operand_kinds): if item.get('extensions')], []) for item in EXTENSIONS_FROM_SPIRV_REGISTRY_AND_NOT_FROM_GRAMMARS.split(): - # If it's already listed in a grammar, then don't put it in the - # special exceptions list. - assert item not in extensions, "Extension %s is already in a grammar file" % item + # If it's already listed in a grammar, then don't put it in the + # special exceptions list. + assert item not in extensions, 'Extension %s is already in a grammar file' % item - extensions.extend(EXTENSIONS_FROM_SPIRV_REGISTRY_AND_NOT_FROM_GRAMMARS.split()) + extensions.extend( + EXTENSIONS_FROM_SPIRV_REGISTRY_AND_NOT_FROM_GRAMMARS.split()) # Validator would ignore type declaration unique check. Should only be used # for legacy autogenerated test files containing multiple instances of the @@ -530,8 +582,7 @@ def get_extension_list(instructions, operand_kinds): def get_capabilities(operand_kinds): """Returns capabilities as a list of JSON objects, in order of - appearance. - """ + appearance.""" enumerants = sum([item.get('enumerants', []) for item in operand_kinds if item.get('kind') in ['Capability']], []) return enumerants @@ -580,6 +631,7 @@ def generate_string_to_extension_mapping(extensions): def generate_capability_to_string_mapping(operand_kinds): """Returns mapping function from capabilities to corresponding strings. + We take care to avoid emitting duplicate values. """ function = 'const char* CapabilityToString(SpvCapability capability) {\n' @@ -608,6 +660,56 @@ def generate_all_string_enum_mappings(extensions, operand_kinds): return '\n\n'.join(tables) +def precondition_operand_kinds(operand_kinds): + """For operand kinds that have the same number, make sure they all have the + same extension list.""" + + # Map operand kind and value to list of the union of extensions + # for same-valued enumerants. + exts = {} + for kind_entry in operand_kinds: + kind = kind_entry.get('kind') + for enum_entry in kind_entry.get('enumerants', []): + value = enum_entry.get('value') + key = kind + '.' + str(value) + if key in exts: + exts[key].extend(enum_entry.get('extensions', [])) + else: + exts[key] = enum_entry.get('extensions', []) + exts[key] = sorted(set(exts[key])) + + # Now make each entry the same list. + for kind_entry in operand_kinds: + kind = kind_entry.get('kind') + for enum_entry in kind_entry.get('enumerants', []): + value = enum_entry.get('value') + key = kind + '.' + str(value) + if len(exts[key]) > 0: + enum_entry['extensions'] = exts[key] + + return operand_kinds + + +def prefix_operand_kind_names(prefix, json_dict): + """Modifies json_dict, by prefixing all the operand kind names + with the given prefix. Also modifies their uses in the instructions + to match. + """ + + old_to_new = {} + for operand_kind in json_dict["operand_kinds"]: + old_name = operand_kind["kind"] + new_name = prefix + old_name + operand_kind["kind"] = new_name + old_to_new[old_name] = new_name + + for instruction in json_dict["instructions"]: + for operand in instruction.get("operands", []): + replacement = old_to_new.get(operand["kind"]) + if replacement is not None: + operand["kind"] = replacement + + def main(): import argparse parser = argparse.ArgumentParser(description='Generate SPIR-V info tables') @@ -620,6 +722,10 @@ def main(): type=str, required=False, default=None, help='input JSON grammar file for DebugInfo extended ' 'instruction set') + parser.add_argument('--extinst-cldebuginfo100-grammar', metavar='', + type=str, required=False, default=None, + help='input JSON grammar file for OpenCL.DebugInfo.100 ' + 'extended instruction set') parser.add_argument('--extinst-glsl-grammar', metavar='', type=str, required=False, default=None, help='input JSON grammar file for GLSL extended ' @@ -654,16 +760,27 @@ def main(): parser.add_argument('--vendor-insts-output', metavar='', type=str, required=False, default=None, help='output file for vendor extended instruction set') + parser.add_argument('--vendor-operand-kind-prefix', metavar='', + type=str, required=False, default=None, + help='prefix for operand kinds (to disambiguate operand type enums)') args = parser.parse_args() + # The GN build system needs this because it doesn't handle quoting + # empty string arguments well. + if args.vendor_operand_kind_prefix == "...nil...": + args.vendor_operand_kind_prefix = "" + if (args.core_insts_output is None) != \ (args.operand_kinds_output is None): print('error: --core-insts-output and --operand-kinds-output ' 'should be specified together.') exit(1) - if args.operand_kinds_output and not (args.spirv_core_grammar and args.extinst_debuginfo_grammar): + if args.operand_kinds_output and not (args.spirv_core_grammar and + args.extinst_debuginfo_grammar and + args.extinst_cldebuginfo100_grammar): print('error: --operand-kinds-output requires --spirv-core-grammar ' - 'and --exinst-debuginfo-grammar') + 'and --extinst-debuginfo-grammar ' + 'and --extinst-cldebuginfo100-grammar') exit(1) if (args.glsl_insts_output is None) != \ (args.extinst_glsl_grammar is None): @@ -694,55 +811,63 @@ def main(): core_grammar = json.loads(json_file.read()) with open(args.extinst_debuginfo_grammar) as debuginfo_json_file: debuginfo_grammar = json.loads(debuginfo_json_file.read()) - instructions = [] - instructions.extend(core_grammar['instructions']) - instructions.extend(debuginfo_grammar['instructions']) - operand_kinds = [] - operand_kinds.extend(core_grammar['operand_kinds']) - operand_kinds.extend(debuginfo_grammar['operand_kinds']) - extensions = get_extension_list(instructions, operand_kinds) + with open(args.extinst_cldebuginfo100_grammar) as cldebuginfo100_json_file: + cldebuginfo100_grammar = json.loads(cldebuginfo100_json_file.read()) + prefix_operand_kind_names("CLDEBUG100_", cldebuginfo100_grammar) + instructions = [] + instructions.extend(core_grammar['instructions']) + instructions.extend(debuginfo_grammar['instructions']) + instructions.extend(cldebuginfo100_grammar['instructions']) + operand_kinds = [] + operand_kinds.extend(core_grammar['operand_kinds']) + operand_kinds.extend(debuginfo_grammar['operand_kinds']) + operand_kinds.extend(cldebuginfo100_grammar['operand_kinds']) + extensions = get_extension_list(instructions, operand_kinds) + operand_kinds = precondition_operand_kinds(operand_kinds) if args.core_insts_output is not None: make_path_to_file(args.core_insts_output) make_path_to_file(args.operand_kinds_output) - print(generate_instruction_table(core_grammar['instructions']), - file=open(args.core_insts_output, 'w')) - print(generate_operand_kind_table(operand_kinds), - file=open(args.operand_kinds_output, 'w')) + with open(args.core_insts_output, 'w') as f: + f.write(generate_instruction_table( + core_grammar['instructions'])) + with open(args.operand_kinds_output, 'w') as f: + f.write(generate_operand_kind_table(operand_kinds)) if args.extension_enum_output is not None: make_path_to_file(args.extension_enum_output) - print(generate_extension_enum(extensions), - file=open(args.extension_enum_output, 'w')) + with open(args.extension_enum_output, 'w') as f: + f.write(generate_extension_enum(extensions)) if args.enum_string_mapping_output is not None: make_path_to_file(args.enum_string_mapping_output) - print(generate_all_string_enum_mappings(extensions, operand_kinds), - file=open(args.enum_string_mapping_output, 'w')) + with open(args.enum_string_mapping_output, 'w') as f: + f.write(generate_all_string_enum_mappings( + extensions, operand_kinds)) if args.extinst_glsl_grammar is not None: with open(args.extinst_glsl_grammar) as json_file: grammar = json.loads(json_file.read()) make_path_to_file(args.glsl_insts_output) - print(generate_extended_instruction_table( - grammar['instructions'], "glsl"), - file=open(args.glsl_insts_output, 'w')) + with open(args.glsl_insts_output, 'w') as f: + f.write(generate_extended_instruction_table( + grammar, 'glsl')) if args.extinst_opencl_grammar is not None: with open(args.extinst_opencl_grammar) as json_file: grammar = json.loads(json_file.read()) make_path_to_file(args.opencl_insts_output) - print(generate_extended_instruction_table( - grammar['instructions'], "opencl"), - file=open(args.opencl_insts_output, 'w')) + with open(args.opencl_insts_output, 'w') as f: + f.write(generate_extended_instruction_table( + grammar, 'opencl')) if args.extinst_vendor_grammar is not None: with open(args.extinst_vendor_grammar) as json_file: grammar = json.loads(json_file.read()) make_path_to_file(args.vendor_insts_output) name = args.extinst_vendor_grammar - start = name.find("extinst.") + len("extinst.") - name = name[start:-len(".grammar.json")].replace("-", "_") - print(generate_extended_instruction_table( - grammar['instructions'], name), - file=open(args.vendor_insts_output, 'w')) + start = name.find('extinst.') + len('extinst.') + name = name[start:-len('.grammar.json')].replace('-', '_') + with open(args.vendor_insts_output, 'w') as f: + f.write(generate_extended_instruction_table( + grammar, name, args.vendor_operand_kind_prefix)) if __name__ == '__main__': diff --git a/third_party/spirv-tools/utils/generate_language_headers.py b/third_party/spirv-tools/utils/generate_language_headers.py index 1886bf4f38..0296163365 100755 --- a/third_party/spirv-tools/utils/generate_language_headers.py +++ b/third_party/spirv-tools/utils/generate_language_headers.py @@ -14,8 +14,6 @@ # limitations under the License. """Generates language headers from a JSON grammar file""" -from __future__ import print_function - import errno import json import os.path @@ -181,7 +179,8 @@ def main(): version = grammar_json['version'], revision = grammar_json['revision']) make_path_to_file(args.extinst_output_base) - print(CGenerator().generate(grammar), file=open(args.extinst_output_base + '.h', 'w')) + with open(args.extinst_output_base + '.h', 'w') as f: + f.write(CGenerator().generate(grammar)) if __name__ == '__main__': diff --git a/third_party/spirv-tools/utils/generate_registry_tables.py b/third_party/spirv-tools/utils/generate_registry_tables.py index 8b1c357213..e662ba99bf 100755 --- a/third_party/spirv-tools/utils/generate_registry_tables.py +++ b/third_party/spirv-tools/utils/generate_registry_tables.py @@ -14,8 +14,6 @@ # limitations under the License. """Generates the vendor tool table from the SPIR-V XML registry.""" -from __future__ import print_function - import distutils.dir_util import os.path import xml.etree.ElementTree @@ -65,7 +63,8 @@ def main(): registry = xml.etree.ElementTree.fromstring(xml_in.read()) distutils.dir_util.mkpath(os.path.dirname(args.generator_output)) - print(generate_vendor_table(registry), file=open(args.generator_output, 'w')) + with open(args.generator_output, 'w') as f: + f.write(generate_vendor_table(registry)) if __name__ == '__main__': diff --git a/third_party/spirv-tools/utils/generate_vim_syntax.py b/third_party/spirv-tools/utils/generate_vim_syntax.py index 03c0b478bc..da7e99ba77 100755 --- a/third_party/spirv-tools/utils/generate_vim_syntax.py +++ b/third_party/spirv-tools/utils/generate_vim_syntax.py @@ -14,8 +14,6 @@ # limitations under the License. """Generates Vim syntax rules for SPIR-V assembly (.spvasm) files""" -from __future__ import print_function - import json PREAMBLE="""" Vim syntax file diff --git a/third_party/spirv-tools/utils/git-sync-deps b/third_party/spirv-tools/utils/git-sync-deps new file mode 100755 index 0000000000..0575641324 --- /dev/null +++ b/third_party/spirv-tools/utils/git-sync-deps @@ -0,0 +1,282 @@ +#!/usr/bin/env python +# Copyright 2014 Google Inc. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Parse a DEPS file and git checkout all of the dependencies. + +Args: + An optional list of deps_os values. + +Environment Variables: + GIT_EXECUTABLE: path to "git" binary; if unset, will look for one of + ['git', 'git.exe', 'git.bat'] in your default path. + + GIT_SYNC_DEPS_PATH: file to get the dependency list from; if unset, + will use the file ../DEPS relative to this script's directory. + + GIT_SYNC_DEPS_QUIET: if set to non-empty string, suppress messages. + +Git Config: + To disable syncing of a single repository: + cd path/to/repository + git config sync-deps.disable true + + To re-enable sync: + cd path/to/repository + git config --unset sync-deps.disable +""" + + +import os +import re +import subprocess +import sys +import threading +from builtins import bytes + + +def git_executable(): + """Find the git executable. + + Returns: + A string suitable for passing to subprocess functions, or None. + """ + envgit = os.environ.get('GIT_EXECUTABLE') + searchlist = ['git', 'git.exe', 'git.bat'] + if envgit: + searchlist.insert(0, envgit) + with open(os.devnull, 'w') as devnull: + for git in searchlist: + try: + subprocess.call([git, '--version'], stdout=devnull) + except (OSError,): + continue + return git + return None + + +DEFAULT_DEPS_PATH = os.path.normpath( + os.path.join(os.path.dirname(__file__), os.pardir, 'DEPS')) + + +def usage(deps_file_path = None): + sys.stderr.write( + 'Usage: run to grab dependencies, with optional platform support:\n') + sys.stderr.write(' %s %s' % (sys.executable, __file__)) + if deps_file_path: + parsed_deps = parse_file_to_dict(deps_file_path) + if 'deps_os' in parsed_deps: + for deps_os in parsed_deps['deps_os']: + sys.stderr.write(' [%s]' % deps_os) + sys.stderr.write('\n\n') + sys.stderr.write(__doc__) + + +def git_repository_sync_is_disabled(git, directory): + try: + disable = subprocess.check_output( + [git, 'config', 'sync-deps.disable'], cwd=directory) + return disable.lower().strip() in ['true', '1', 'yes', 'on'] + except subprocess.CalledProcessError: + return False + + +def is_git_toplevel(git, directory): + """Return true iff the directory is the top level of a Git repository. + + Args: + git (string) the git executable + + directory (string) the path into which the repository + is expected to be checked out. + """ + try: + toplevel = subprocess.check_output( + [git, 'rev-parse', '--show-toplevel'], cwd=directory).strip() + return os.path.realpath(bytes(directory, 'utf8')) == os.path.realpath(toplevel) + except subprocess.CalledProcessError: + return False + + +def status(directory, checkoutable): + def truncate(s, length): + return s if len(s) <= length else s[:(length - 3)] + '...' + dlen = 36 + directory = truncate(directory, dlen) + checkoutable = truncate(checkoutable, 40) + sys.stdout.write('%-*s @ %s\n' % (dlen, directory, checkoutable)) + + +def git_checkout_to_directory(git, repo, checkoutable, directory, verbose): + """Checkout (and clone if needed) a Git repository. + + Args: + git (string) the git executable + + repo (string) the location of the repository, suitable + for passing to `git clone`. + + checkoutable (string) a tag, branch, or commit, suitable for + passing to `git checkout` + + directory (string) the path into which the repository + should be checked out. + + verbose (boolean) + + Raises an exception if any calls to git fail. + """ + if not os.path.isdir(directory): + subprocess.check_call( + [git, 'clone', '--quiet', repo, directory]) + + if not is_git_toplevel(git, directory): + # if the directory exists, but isn't a git repo, you will modify + # the parent repostory, which isn't what you want. + sys.stdout.write('%s\n IS NOT TOP-LEVEL GIT DIRECTORY.\n' % directory) + return + + # Check to see if this repo is disabled. Quick return. + if git_repository_sync_is_disabled(git, directory): + sys.stdout.write('%s\n SYNC IS DISABLED.\n' % directory) + return + + with open(os.devnull, 'w') as devnull: + # If this fails, we will fetch before trying again. Don't spam user + # with error infomation. + if 0 == subprocess.call([git, 'checkout', '--quiet', checkoutable], + cwd=directory, stderr=devnull): + # if this succeeds, skip slow `git fetch`. + if verbose: + status(directory, checkoutable) # Success. + return + + # If the repo has changed, always force use of the correct repo. + # If origin already points to repo, this is a quick no-op. + subprocess.check_call( + [git, 'remote', 'set-url', 'origin', repo], cwd=directory) + + subprocess.check_call([git, 'fetch', '--quiet'], cwd=directory) + + subprocess.check_call([git, 'checkout', '--quiet', checkoutable], cwd=directory) + + if verbose: + status(directory, checkoutable) # Success. + + +def parse_file_to_dict(path): + dictionary = {} + contents = open(path).read() + # Need to convert Var() to vars[], so that the DEPS is actually Python. Var() + # comes from Autoroller using gclient which has a slightly different DEPS + # format. + contents = re.sub(r"Var\((.*?)\)", r"vars[\1]", contents) + exec(contents, dictionary) + return dictionary + + +def git_sync_deps(deps_file_path, command_line_os_requests, verbose): + """Grab dependencies, with optional platform support. + + Args: + deps_file_path (string) Path to the DEPS file. + + command_line_os_requests (list of strings) Can be empty list. + List of strings that should each be a key in the deps_os + dictionary in the DEPS file. + + Raises git Exceptions. + """ + git = git_executable() + assert git + + deps_file_directory = os.path.dirname(deps_file_path) + deps_file = parse_file_to_dict(deps_file_path) + dependencies = deps_file['deps'].copy() + os_specific_dependencies = deps_file.get('deps_os', dict()) + if 'all' in command_line_os_requests: + for value in list(os_specific_dependencies.values()): + dependencies.update(value) + else: + for os_name in command_line_os_requests: + # Add OS-specific dependencies + if os_name in os_specific_dependencies: + dependencies.update(os_specific_dependencies[os_name]) + for directory in dependencies: + for other_dir in dependencies: + if directory.startswith(other_dir + '/'): + raise Exception('%r is parent of %r' % (other_dir, directory)) + list_of_arg_lists = [] + for directory in sorted(dependencies): + if '@' in dependencies[directory]: + repo, checkoutable = dependencies[directory].split('@', 1) + else: + raise Exception("please specify commit or tag") + + relative_directory = os.path.join(deps_file_directory, directory) + + list_of_arg_lists.append( + (git, repo, checkoutable, relative_directory, verbose)) + + multithread(git_checkout_to_directory, list_of_arg_lists) + + for directory in deps_file.get('recursedeps', []): + recursive_path = os.path.join(deps_file_directory, directory, 'DEPS') + git_sync_deps(recursive_path, command_line_os_requests, verbose) + + +def multithread(function, list_of_arg_lists): + # for args in list_of_arg_lists: + # function(*args) + # return + threads = [] + for args in list_of_arg_lists: + thread = threading.Thread(None, function, None, args) + thread.start() + threads.append(thread) + for thread in threads: + thread.join() + + +def main(argv): + deps_file_path = os.environ.get('GIT_SYNC_DEPS_PATH', DEFAULT_DEPS_PATH) + verbose = not bool(os.environ.get('GIT_SYNC_DEPS_QUIET', False)) + + if '--help' in argv or '-h' in argv: + usage(deps_file_path) + return 1 + + git_sync_deps(deps_file_path, argv, verbose) + # subprocess.check_call( + # [sys.executable, + # os.path.join(os.path.dirname(deps_file_path), 'bin', 'fetch-gn')]) + return 0 + + +if __name__ == '__main__': + exit(main(sys.argv[1:])) diff --git a/third_party/spirv-tools/utils/roll_deps.sh b/third_party/spirv-tools/utils/roll_deps.sh new file mode 100755 index 0000000000..622afc9ed8 --- /dev/null +++ b/third_party/spirv-tools/utils/roll_deps.sh @@ -0,0 +1,31 @@ +#!/usr/bin/env bash +# Copyright (c) 2019 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Attempts to roll all entries in DEPS to origin/master and creates a +# commit. +# +# Depends on roll-dep from depot_path being in PATH. + +# This script assumes it's parent directory is the repo root. +repo_path=$(dirname "$0")/.. + +effcee_dir="external/effcee/" +googletest_dir="external/googletest/" +re2_dir="external/re2/" +spirv_headers_dir="external/spirv-headers/" + +cd "$repo_path" + +roll-dep "$@" "${effcee_dir}" "${googletest_dir}" "${re2_dir}" "${spirv_headers_dir}" diff --git a/third_party/spirv-tools/utils/update_build_version.py b/third_party/spirv-tools/utils/update_build_version.py index d71aeccd9d..321de74bdc 100755 --- a/third_party/spirv-tools/utils/update_build_version.py +++ b/third_party/spirv-tools/utils/update_build_version.py @@ -29,8 +29,6 @@ # "unknown hash". # The string contents are escaped as necessary. -from __future__ import print_function - import datetime import errno import os @@ -88,7 +86,7 @@ def deduce_software_version(directory): # Linux. pattern = re.compile(r'^(v\d+\.\d+(-dev)?) \d\d\d\d-\d\d-\d\d\s*$') changes_file = os.path.join(directory, 'CHANGES') - with open(changes_file, mode='rU') as f: + with open(changes_file, mode='r') as f: for line in f.readlines(): match = pattern.match(line) if match: @@ -118,10 +116,10 @@ def describe(directory): # e.g. because the source tree might not be in a git tree. # In this case, usually use a timestamp. However, to ensure # reproducible builds, allow the builder to override the wall - # clock time with enviornment variable SOURCE_DATE_EPOCH + # clock time with environment variable SOURCE_DATE_EPOCH # containing a (presumably) fixed timestamp. timestamp = int(os.environ.get('SOURCE_DATE_EPOCH', time.time())) - formatted = datetime.date.fromtimestamp(timestamp).isoformat() + formatted = datetime.datetime.utcfromtimestamp(timestamp).isoformat() return 'unknown hash, {}'.format(formatted) diff --git a/third_party/spirv-tools/utils/vscode/.gitignore b/third_party/spirv-tools/utils/vscode/.gitignore new file mode 100644 index 0000000000..e934adfd1b --- /dev/null +++ b/third_party/spirv-tools/utils/vscode/.gitignore @@ -0,0 +1 @@ +cache/ diff --git a/third_party/spirv-tools/utils/vscode/README.md b/third_party/spirv-tools/utils/vscode/README.md new file mode 100644 index 0000000000..bc022112bf --- /dev/null +++ b/third_party/spirv-tools/utils/vscode/README.md @@ -0,0 +1,17 @@ +# Visual Studio Code extension for SPIR-V disassembly files + +This directory holds a Visual Studio Code extension adding syntax highlighting for SPIR-V assembly files (`.spvasm`) + +## Dependencies + +In order to build and install the Visual Studio Code language server extension, you will need to install and have on your `PATH` the following dependencies: +* [`npm`](https://www.npmjs.com/) +* [`golang`](https://golang.org/) + +## Installing (macOS / Linux) + +Run `install.sh` + +## Installing (Windows) + +Run `install.bat` diff --git a/third_party/spirv-tools/utils/vscode/extension.js b/third_party/spirv-tools/utils/vscode/extension.js new file mode 100644 index 0000000000..f2201722db --- /dev/null +++ b/third_party/spirv-tools/utils/vscode/extension.js @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2019 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var path = require('path'); +var vscode = require('vscode'); +var langClient = require('vscode-languageclient'); + +var LanguageClient = langClient.LanguageClient; + +// this method is called when your extension is activated +// your extension is activated the very first time the command is executed +function activate(context) { + let serverModule = path.join(context.extensionPath, 'langsvr'); + let debugOptions = {}; + + // If the extension is launched in debug mode then the debug server options are used + // Otherwise the run options are used + let serverOptions = { + run: { command: serverModule, transport: langClient.stdio }, + debug: { command: serverModule, transport: langClient.stdio, options: debugOptions } + } + + // Options to control the language client + let clientOptions = { + documentSelector: ['spirv'], + synchronize: { + // Synchronize the setting section 'spirv' to the server + configurationSection: 'spirv', + // Notify the server about file changes to .spvasm files contained in the workspace + fileEvents: vscode.workspace.createFileSystemWatcher('**/*.spvasm') + } + } + + // Create the language client and start the client. + let disposable = new LanguageClient('spirv', serverOptions, clientOptions).start(); + + // Push the disposable to the context's subscriptions so that the + // client can be deactivated on extension deactivation + context.subscriptions.push(disposable); + + // Set the language configuration here instead of a language configuration + // file to work around https://github.com/microsoft/vscode/issues/42649. + vscode.languages.setLanguageConfiguration("spirv", { + comments: { "lineComment": ";" }, + wordPattern: /(-?\d*\.\d\w*)|([^\`\~\!\@\#\^\&\*\(\)\-\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s]+)/g, + }); +} +exports.activate = activate; + +// this method is called when your extension is deactivated +function deactivate() { +} +exports.deactivate = deactivate; \ No newline at end of file diff --git a/third_party/spirv-tools/utils/vscode/install.bat b/third_party/spirv-tools/utils/vscode/install.bat new file mode 100644 index 0000000000..21a52ecdd6 --- /dev/null +++ b/third_party/spirv-tools/utils/vscode/install.bat @@ -0,0 +1,30 @@ +@REM Copyright (c) 2019 Google Inc. +@REM +@REM Licensed under the Apache License, Version 2.0 (the "License"); +@REM you may not use this file except in compliance with the License. +@REM You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, software +@REM distributed under the License is distributed on an "AS IS" BASIS, +@REM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@REM See the License for the specific language governing permissions and +@REM limitations under the License. + +@set EXT_PATH=%userprofile%\.vscode\extensions\google.spirvls-0.0.1 +@set ROOT_PATH=%~dp0 + +go run %ROOT_PATH%\src\tools\gen-grammar.go --cache %ROOT_PATH%\cache --template %ROOT_PATH%\spirv.json.tmpl --out %ROOT_PATH%\spirv.json +go run %ROOT_PATH%\src\tools\gen-grammar.go --cache %ROOT_PATH%\cache --template %ROOT_PATH%\src\schema\schema.go.tmpl --out %ROOT_PATH%\src\schema\schema.go + +if not exist %EXT_PATH% mkdir -p %EXT_PATH% +copy %ROOT_PATH%\extension.js %EXT_PATH% +copy %ROOT_PATH%\package.json %EXT_PATH% +copy %ROOT_PATH%\spirv.json %EXT_PATH% + +go build -o %EXT_PATH%\langsvr %ROOT_PATH%\src\langsvr.go + +@pushd %EXT_PATH% +call npm install +@popd diff --git a/third_party/spirv-tools/utils/vscode/install.sh b/third_party/spirv-tools/utils/vscode/install.sh new file mode 100755 index 0000000000..01fc914068 --- /dev/null +++ b/third_party/spirv-tools/utils/vscode/install.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash +# Copyright (c) 2019 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -e # Fail on any error. + +EXT_PATH=~/.vscode/extensions/google.spirvls-0.0.1 +ROOT_PATH="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" + +go run ${ROOT_PATH}/src/tools/gen-grammar.go --cache ${ROOT_PATH}/cache --template ${ROOT_PATH}/spirv.json.tmpl --out ${ROOT_PATH}/spirv.json +go run ${ROOT_PATH}/src/tools/gen-grammar.go --cache ${ROOT_PATH}/cache --template ${ROOT_PATH}/src/schema/schema.go.tmpl --out ${ROOT_PATH}/src/schema/schema.go + +mkdir -p ${EXT_PATH} +cp ${ROOT_PATH}/extension.js ${EXT_PATH} +cp ${ROOT_PATH}/package.json ${EXT_PATH} +cp ${ROOT_PATH}/spirv.json ${EXT_PATH} + +go build -o ${EXT_PATH}/langsvr ${ROOT_PATH}/src/langsvr.go + +cd ${EXT_PATH} +npm install diff --git a/third_party/spirv-tools/utils/vscode/package.json b/third_party/spirv-tools/utils/vscode/package.json new file mode 100644 index 0000000000..76fb348ba8 --- /dev/null +++ b/third_party/spirv-tools/utils/vscode/package.json @@ -0,0 +1,39 @@ +{ + "name": "spirvls", + "description": "Language support for SPIR-V disassembly files", + "author": "Google", + "license": "Apache-2.0", + "version": "0.0.1", + "private": true, + "publisher": "Google", + "engines": { + "vscode": "^0.10.10" + }, + "categories": [ + "Programming Languages" + ], + "contributes": { + "languages": [ + { + "id": "spirv", + "extensions": [ + "spvasm" + ] + } + ], + "grammars": [ + { + "language": "spirv", + "scopeName": "source.spirv", + "path": "spirv.json" + } + ] + }, + "dependencies": { + "vscode-languageclient": "~4.3.0" + }, + "activationEvents": [ + "*" + ], + "main": "./extension.js" +} diff --git a/third_party/spirv-tools/utils/vscode/spirv.json b/third_party/spirv-tools/utils/vscode/spirv.json new file mode 100644 index 0000000000..30573d4550 --- /dev/null +++ b/third_party/spirv-tools/utils/vscode/spirv.json @@ -0,0 +1,212 @@ +{ + "scopeName": "source.spirv", + "name": "SPIR-V", + "comment": "Generated by gen-grammar.go --template=../../spirv.json.tmpl --out=../../spirv.json. Do not modify this file directly.", + "patterns": [ + { "include": "#BitEnum_ImageOperands" }, + { "include": "#BitEnum_FPFastMathMode" }, + { "include": "#BitEnum_SelectionControl" }, + { "include": "#BitEnum_LoopControl" }, + { "include": "#BitEnum_FunctionControl" }, + { "include": "#BitEnum_MemorySemantics" }, + { "include": "#BitEnum_MemoryAccess" }, + { "include": "#BitEnum_KernelProfilingInfo" }, + { "include": "#ValueEnum_SourceLanguage" }, + { "include": "#ValueEnum_ExecutionModel" }, + { "include": "#ValueEnum_AddressingModel" }, + { "include": "#ValueEnum_MemoryModel" }, + { "include": "#ValueEnum_ExecutionMode" }, + { "include": "#ValueEnum_StorageClass" }, + { "include": "#ValueEnum_Dim" }, + { "include": "#ValueEnum_SamplerAddressingMode" }, + { "include": "#ValueEnum_SamplerFilterMode" }, + { "include": "#ValueEnum_ImageFormat" }, + { "include": "#ValueEnum_ImageChannelOrder" }, + { "include": "#ValueEnum_ImageChannelDataType" }, + { "include": "#ValueEnum_FPRoundingMode" }, + { "include": "#ValueEnum_LinkageType" }, + { "include": "#ValueEnum_AccessQualifier" }, + { "include": "#ValueEnum_FunctionParameterAttribute" }, + { "include": "#ValueEnum_Decoration" }, + { "include": "#ValueEnum_BuiltIn" }, + { "include": "#ValueEnum_Scope" }, + { "include": "#ValueEnum_GroupOperation" }, + { "include": "#ValueEnum_KernelEnqueueFlags" }, + { "include": "#ValueEnum_Capability" }, + { "include": "#opcode" }, + { "include": "#identifier" }, + { "include": "#number" }, + { "include": "#string" }, + { "include": "#comment" }, + { "include": "#operator" } + ], + "repository": { + "BitEnum_ImageOperands": { + "match": "\\b(None|Bias|Lod|Grad|ConstOffset|Offset|ConstOffsets|Sample|MinLod|MakeTexelAvailable|MakeTexelAvailableKHR|MakeTexelVisible|MakeTexelVisibleKHR|NonPrivateTexel|NonPrivateTexelKHR|VolatileTexel|VolatileTexelKHR|SignExtend|ZeroExtend)\\b", + "name": "keyword.spirv" + }, + "BitEnum_FPFastMathMode": { + "match": "\\b(None|NotNaN|NotInf|NSZ|AllowRecip|Fast)\\b", + "name": "keyword.spirv" + }, + "BitEnum_SelectionControl": { + "match": "\\b(None|Flatten|DontFlatten)\\b", + "name": "keyword.spirv" + }, + "BitEnum_LoopControl": { + "match": "\\b(None|Unroll|DontUnroll|DependencyInfinite|DependencyLength|MinIterations|MaxIterations|IterationMultiple|PeelCount|PartialCount)\\b", + "name": "keyword.spirv" + }, + "BitEnum_FunctionControl": { + "match": "\\b(None|Inline|DontInline|Pure|Const)\\b", + "name": "keyword.spirv" + }, + "BitEnum_MemorySemantics": { + "match": "\\b(Relaxed|None|Acquire|Release|AcquireRelease|SequentiallyConsistent|UniformMemory|SubgroupMemory|WorkgroupMemory|CrossWorkgroupMemory|AtomicCounterMemory|ImageMemory|OutputMemory|OutputMemoryKHR|MakeAvailable|MakeAvailableKHR|MakeVisible|MakeVisibleKHR|Volatile)\\b", + "name": "keyword.spirv" + }, + "BitEnum_MemoryAccess": { + "match": "\\b(None|Volatile|Aligned|Nontemporal|MakePointerAvailable|MakePointerAvailableKHR|MakePointerVisible|MakePointerVisibleKHR|NonPrivatePointer|NonPrivatePointerKHR)\\b", + "name": "keyword.spirv" + }, + "BitEnum_KernelProfilingInfo": { + "match": "\\b(None|CmdExecTime)\\b", + "name": "keyword.spirv" + }, + "ValueEnum_SourceLanguage": { + "match": "\\b(Unknown|ESSL|GLSL|OpenCL_C|OpenCL_CPP|HLSL)\\b", + "name": "keyword.spirv" + }, + "ValueEnum_ExecutionModel": { + "match": "\\b(Vertex|TessellationControl|TessellationEvaluation|Geometry|Fragment|GLCompute|Kernel|TaskNV|MeshNV|RayGenerationNV|IntersectionNV|AnyHitNV|ClosestHitNV|MissNV|CallableNV)\\b", + "name": "keyword.spirv" + }, + "ValueEnum_AddressingModel": { + "match": "\\b(Logical|Physical32|Physical64|PhysicalStorageBuffer64|PhysicalStorageBuffer64EXT)\\b", + "name": "keyword.spirv" + }, + "ValueEnum_MemoryModel": { + "match": "\\b(Simple|GLSL450|OpenCL|Vulkan|VulkanKHR)\\b", + "name": "keyword.spirv" + }, + "ValueEnum_ExecutionMode": { + "match": "\\b(Invocations|SpacingEqual|SpacingFractionalEven|SpacingFractionalOdd|VertexOrderCw|VertexOrderCcw|PixelCenterInteger|OriginUpperLeft|OriginLowerLeft|EarlyFragmentTests|PointMode|Xfb|DepthReplacing|DepthGreater|DepthLess|DepthUnchanged|LocalSize|LocalSizeHint|InputPoints|InputLines|InputLinesAdjacency|Triangles|InputTrianglesAdjacency|Quads|Isolines|OutputVertices|OutputPoints|OutputLineStrip|OutputTriangleStrip|VecTypeHint|ContractionOff|Initializer|Finalizer|SubgroupSize|SubgroupsPerWorkgroup|SubgroupsPerWorkgroupId|LocalSizeId|LocalSizeHintId|PostDepthCoverage|DenormPreserve|DenormFlushToZero|SignedZeroInfNanPreserve|RoundingModeRTE|RoundingModeRTZ|StencilRefReplacingEXT|OutputLinesNV|OutputPrimitivesNV|DerivativeGroupQuadsNV|DerivativeGroupLinearNV|OutputTrianglesNV|PixelInterlockOrderedEXT|PixelInterlockUnorderedEXT|SampleInterlockOrderedEXT|SampleInterlockUnorderedEXT|ShadingRateInterlockOrderedEXT|ShadingRateInterlockUnorderedEXT)\\b", + "name": "keyword.spirv" + }, + "ValueEnum_StorageClass": { + "match": "\\b(UniformConstant|Input|Uniform|Output|Workgroup|CrossWorkgroup|Private|Function|Generic|PushConstant|AtomicCounter|Image|StorageBuffer|CallableDataNV|IncomingCallableDataNV|RayPayloadNV|HitAttributeNV|IncomingRayPayloadNV|ShaderRecordBufferNV|PhysicalStorageBuffer|PhysicalStorageBufferEXT)\\b", + "name": "keyword.spirv" + }, + "ValueEnum_Dim": { + "match": "\\b(1D|2D|3D|Cube|Rect|Buffer|SubpassData)\\b", + "name": "keyword.spirv" + }, + "ValueEnum_SamplerAddressingMode": { + "match": "\\b(None|ClampToEdge|Clamp|Repeat|RepeatMirrored)\\b", + "name": "keyword.spirv" + }, + "ValueEnum_SamplerFilterMode": { + "match": "\\b(Nearest|Linear)\\b", + "name": "keyword.spirv" + }, + "ValueEnum_ImageFormat": { + "match": "\\b(Unknown|Rgba32f|Rgba16f|R32f|Rgba8|Rgba8Snorm|Rg32f|Rg16f|R11fG11fB10f|R16f|Rgba16|Rgb10A2|Rg16|Rg8|R16|R8|Rgba16Snorm|Rg16Snorm|Rg8Snorm|R16Snorm|R8Snorm|Rgba32i|Rgba16i|Rgba8i|R32i|Rg32i|Rg16i|Rg8i|R16i|R8i|Rgba32ui|Rgba16ui|Rgba8ui|R32ui|Rgb10a2ui|Rg32ui|Rg16ui|Rg8ui|R16ui|R8ui)\\b", + "name": "keyword.spirv" + }, + "ValueEnum_ImageChannelOrder": { + "match": "\\b(R|A|RG|RA|RGB|RGBA|BGRA|ARGB|Intensity|Luminance|Rx|RGx|RGBx|Depth|DepthStencil|sRGB|sRGBx|sRGBA|sBGRA|ABGR)\\b", + "name": "keyword.spirv" + }, + "ValueEnum_ImageChannelDataType": { + "match": "\\b(SnormInt8|SnormInt16|UnormInt8|UnormInt16|UnormShort565|UnormShort555|UnormInt101010|SignedInt8|SignedInt16|SignedInt32|UnsignedInt8|UnsignedInt16|UnsignedInt32|HalfFloat|Float|UnormInt24|UnormInt101010_2)\\b", + "name": "keyword.spirv" + }, + "ValueEnum_FPRoundingMode": { + "match": "\\b(RTE|RTZ|RTP|RTN)\\b", + "name": "keyword.spirv" + }, + "ValueEnum_LinkageType": { + "match": "\\b(Export|Import)\\b", + "name": "keyword.spirv" + }, + "ValueEnum_AccessQualifier": { + "match": "\\b(ReadOnly|WriteOnly|ReadWrite)\\b", + "name": "keyword.spirv" + }, + "ValueEnum_FunctionParameterAttribute": { + "match": "\\b(Zext|Sext|ByVal|Sret|NoAlias|NoCapture|NoWrite|NoReadWrite)\\b", + "name": "keyword.spirv" + }, + "ValueEnum_Decoration": { + "match": "\\b(RelaxedPrecision|SpecId|Block|BufferBlock|RowMajor|ColMajor|ArrayStride|MatrixStride|GLSLShared|GLSLPacked|CPacked|BuiltIn|NoPerspective|Flat|Patch|Centroid|Sample|Invariant|Restrict|Aliased|Volatile|Constant|Coherent|NonWritable|NonReadable|Uniform|UniformId|SaturatedConversion|Stream|Location|Component|Index|Binding|DescriptorSet|Offset|XfbBuffer|XfbStride|FuncParamAttr|FPRoundingMode|FPFastMathMode|LinkageAttributes|NoContraction|InputAttachmentIndex|Alignment|MaxByteOffset|AlignmentId|MaxByteOffsetId|NoSignedWrap|NoUnsignedWrap|ExplicitInterpAMD|OverrideCoverageNV|PassthroughNV|ViewportRelativeNV|SecondaryViewportRelativeNV|PerPrimitiveNV|PerViewNV|PerTaskNV|PerVertexNV|NonUniform|NonUniformEXT|RestrictPointer|RestrictPointerEXT|AliasedPointer|AliasedPointerEXT|CounterBuffer|HlslCounterBufferGOOGLE|UserSemantic|HlslSemanticGOOGLE|UserTypeGOOGLE)\\b", + "name": "keyword.spirv" + }, + "ValueEnum_BuiltIn": { + "match": "\\b(Position|PointSize|ClipDistance|CullDistance|VertexId|InstanceId|PrimitiveId|InvocationId|Layer|ViewportIndex|TessLevelOuter|TessLevelInner|TessCoord|PatchVertices|FragCoord|PointCoord|FrontFacing|SampleId|SamplePosition|SampleMask|FragDepth|HelperInvocation|NumWorkgroups|WorkgroupSize|WorkgroupId|LocalInvocationId|GlobalInvocationId|LocalInvocationIndex|WorkDim|GlobalSize|EnqueuedWorkgroupSize|GlobalOffset|GlobalLinearId|SubgroupSize|SubgroupMaxSize|NumSubgroups|NumEnqueuedSubgroups|SubgroupId|SubgroupLocalInvocationId|VertexIndex|InstanceIndex|SubgroupEqMask|SubgroupGeMask|SubgroupGtMask|SubgroupLeMask|SubgroupLtMask|SubgroupEqMaskKHR|SubgroupGeMaskKHR|SubgroupGtMaskKHR|SubgroupLeMaskKHR|SubgroupLtMaskKHR|BaseVertex|BaseInstance|DrawIndex|DeviceIndex|ViewIndex|BaryCoordNoPerspAMD|BaryCoordNoPerspCentroidAMD|BaryCoordNoPerspSampleAMD|BaryCoordSmoothAMD|BaryCoordSmoothCentroidAMD|BaryCoordSmoothSampleAMD|BaryCoordPullModelAMD|FragStencilRefEXT|ViewportMaskNV|SecondaryPositionNV|SecondaryViewportMaskNV|PositionPerViewNV|ViewportMaskPerViewNV|FullyCoveredEXT|TaskCountNV|PrimitiveCountNV|PrimitiveIndicesNV|ClipDistancePerViewNV|CullDistancePerViewNV|LayerPerViewNV|MeshViewCountNV|MeshViewIndicesNV|BaryCoordNV|BaryCoordNoPerspNV|FragSizeEXT|FragmentSizeNV|FragInvocationCountEXT|InvocationsPerPixelNV|LaunchIdNV|LaunchSizeNV|WorldRayOriginNV|WorldRayDirectionNV|ObjectRayOriginNV|ObjectRayDirectionNV|RayTminNV|RayTmaxNV|InstanceCustomIndexNV|ObjectToWorldNV|WorldToObjectNV|HitTNV|HitKindNV|IncomingRayFlagsNV|WarpsPerSMNV|SMCountNV|WarpIDNV|SMIDNV)\\b", + "name": "keyword.spirv" + }, + "ValueEnum_Scope": { + "match": "\\b(CrossDevice|Device|Workgroup|Subgroup|Invocation|QueueFamily|QueueFamilyKHR)\\b", + "name": "keyword.spirv" + }, + "ValueEnum_GroupOperation": { + "match": "\\b(Reduce|InclusiveScan|ExclusiveScan|ClusteredReduce|PartitionedReduceNV|PartitionedInclusiveScanNV|PartitionedExclusiveScanNV)\\b", + "name": "keyword.spirv" + }, + "ValueEnum_KernelEnqueueFlags": { + "match": "\\b(NoWait|WaitKernel|WaitWorkGroup)\\b", + "name": "keyword.spirv" + }, + "ValueEnum_Capability": { + "match": "\\b(Matrix|Shader|Geometry|Tessellation|Addresses|Linkage|Kernel|Vector16|Float16Buffer|Float16|Float64|Int64|Int64Atomics|ImageBasic|ImageReadWrite|ImageMipmap|Pipes|Groups|DeviceEnqueue|LiteralSampler|AtomicStorage|Int16|TessellationPointSize|GeometryPointSize|ImageGatherExtended|StorageImageMultisample|UniformBufferArrayDynamicIndexing|SampledImageArrayDynamicIndexing|StorageBufferArrayDynamicIndexing|StorageImageArrayDynamicIndexing|ClipDistance|CullDistance|ImageCubeArray|SampleRateShading|ImageRect|SampledRect|GenericPointer|Int8|InputAttachment|SparseResidency|MinLod|Sampled1D|Image1D|SampledCubeArray|SampledBuffer|ImageBuffer|ImageMSArray|StorageImageExtendedFormats|ImageQuery|DerivativeControl|InterpolationFunction|TransformFeedback|GeometryStreams|StorageImageReadWithoutFormat|StorageImageWriteWithoutFormat|MultiViewport|SubgroupDispatch|NamedBarrier|PipeStorage|GroupNonUniform|GroupNonUniformVote|GroupNonUniformArithmetic|GroupNonUniformBallot|GroupNonUniformShuffle|GroupNonUniformShuffleRelative|GroupNonUniformClustered|GroupNonUniformQuad|ShaderLayer|ShaderViewportIndex|SubgroupBallotKHR|DrawParameters|SubgroupVoteKHR|StorageBuffer16BitAccess|StorageUniformBufferBlock16|UniformAndStorageBuffer16BitAccess|StorageUniform16|StoragePushConstant16|StorageInputOutput16|DeviceGroup|MultiView|VariablePointersStorageBuffer|VariablePointers|AtomicStorageOps|SampleMaskPostDepthCoverage|StorageBuffer8BitAccess|UniformAndStorageBuffer8BitAccess|StoragePushConstant8|DenormPreserve|DenormFlushToZero|SignedZeroInfNanPreserve|RoundingModeRTE|RoundingModeRTZ|Float16ImageAMD|ImageGatherBiasLodAMD|FragmentMaskAMD|StencilExportEXT|ImageReadWriteLodAMD|ShaderClockKHR|SampleMaskOverrideCoverageNV|GeometryShaderPassthroughNV|ShaderViewportIndexLayerEXT|ShaderViewportIndexLayerNV|ShaderViewportMaskNV|ShaderStereoViewNV|PerViewAttributesNV|FragmentFullyCoveredEXT|MeshShadingNV|ImageFootprintNV|FragmentBarycentricNV|ComputeDerivativeGroupQuadsNV|FragmentDensityEXT|ShadingRateNV|GroupNonUniformPartitionedNV|ShaderNonUniform|ShaderNonUniformEXT|RuntimeDescriptorArray|RuntimeDescriptorArrayEXT|InputAttachmentArrayDynamicIndexing|InputAttachmentArrayDynamicIndexingEXT|UniformTexelBufferArrayDynamicIndexing|UniformTexelBufferArrayDynamicIndexingEXT|StorageTexelBufferArrayDynamicIndexing|StorageTexelBufferArrayDynamicIndexingEXT|UniformBufferArrayNonUniformIndexing|UniformBufferArrayNonUniformIndexingEXT|SampledImageArrayNonUniformIndexing|SampledImageArrayNonUniformIndexingEXT|StorageBufferArrayNonUniformIndexing|StorageBufferArrayNonUniformIndexingEXT|StorageImageArrayNonUniformIndexing|StorageImageArrayNonUniformIndexingEXT|InputAttachmentArrayNonUniformIndexing|InputAttachmentArrayNonUniformIndexingEXT|UniformTexelBufferArrayNonUniformIndexing|UniformTexelBufferArrayNonUniformIndexingEXT|StorageTexelBufferArrayNonUniformIndexing|StorageTexelBufferArrayNonUniformIndexingEXT|RayTracingNV|VulkanMemoryModel|VulkanMemoryModelKHR|VulkanMemoryModelDeviceScope|VulkanMemoryModelDeviceScopeKHR|PhysicalStorageBufferAddresses|PhysicalStorageBufferAddressesEXT|ComputeDerivativeGroupLinearNV|CooperativeMatrixNV|FragmentShaderSampleInterlockEXT|FragmentShaderShadingRateInterlockEXT|ShaderSMBuiltinsNV|FragmentShaderPixelInterlockEXT|DemoteToHelperInvocationEXT|SubgroupShuffleINTEL|SubgroupBufferBlockIOINTEL|SubgroupImageBlockIOINTEL|SubgroupImageMediaBlockIOINTEL|IntegerFunctions2INTEL|SubgroupAvcMotionEstimationINTEL|SubgroupAvcMotionEstimationIntraINTEL|SubgroupAvcMotionEstimationChromaINTEL)\\b", + "name": "keyword.spirv" + }, + "opcode": { + "match": "(Op[a-zA-Z]+)", + "name": "entity.name.function.spirv" + }, + "identifier": { + "match": "%[a-zA-Z0-9_]+", + "name": "variable.spirv" + }, + "number": { + "match": "\\b[0-9]+.?[0-9]*\\b", + "name": "constant.numeric.spirv" + }, + "comment": { + "match": ";[^\n]*", + "name": "comment.line.spirv" + }, + "operator": { + "match": "=", + "name": "keyword.operator.spirv" + }, + "string": { + "begin": "\"", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.spirv" + } + }, + "end": "\"", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.spirv" + } + }, + "name": "string.quoted.double.spirv", + "patterns": [ { "include": "#string_escaped_char" } ] + }, + "string_escaped_char": { + "patterns": [ + { + "match": "\\\\([0-7]{3}|[abfnrtv\\\\'\"]|x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8})", + "name": "constant.character.escape.spirv" + }, { + "match": "\\\\[^0-7xuUabfnrtv\\'\"]", + "name": "invalid.illegal.unknown-escape.spirv" + } + ] + } + } +} diff --git a/third_party/spirv-tools/utils/vscode/spirv.json.tmpl b/third_party/spirv-tools/utils/vscode/spirv.json.tmpl new file mode 100644 index 0000000000..8582d03fd4 --- /dev/null +++ b/third_party/spirv-tools/utils/vscode/spirv.json.tmpl @@ -0,0 +1,67 @@ +{ + "scopeName": "source.spirv", + "name": "SPIR-V", + "comment": "Generated by {{GenerateArguments}}. Do not modify this file directly.", + "patterns": [ +{{range $o := .OperandKinds}}{{if len $o.Enumerants}} { "include": "#{{$o.Category}}_{{$o.Kind}}" }, +{{end}}{{end}} { "include": "#opcode" }, + { "include": "#identifier" }, + { "include": "#number" }, + { "include": "#string" }, + { "include": "#comment" }, + { "include": "#operator" } + ], + "repository": { {{range $o := .OperandKinds}}{{if len $o.Enumerants}} + "{{$o.Category}}_{{$o.Kind}}": { + "match": "\\b({{OperandKindsMatch $o}})\\b", + "name": "keyword.spirv" + },{{end}}{{end}} + "opcode": { + "match": "(Op[a-zA-Z]+)", + "name": "entity.name.function.spirv" + }, + "identifier": { + "match": "%[a-zA-Z0-9_]+", + "name": "variable.spirv" + }, + "number": { + "match": "\\b[0-9]+.?[0-9]*\\b", + "name": "constant.numeric.spirv" + }, + "comment": { + "match": ";[^\n]*", + "name": "comment.line.spirv" + }, + "operator": { + "match": "=", + "name": "keyword.operator.spirv" + }, + "string": { + "begin": "\"", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.spirv" + } + }, + "end": "\"", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.spirv" + } + }, + "name": "string.quoted.double.spirv", + "patterns": [ { "include": "#string_escaped_char" } ] + }, + "string_escaped_char": { + "patterns": [ + { + "match": "\\\\([0-7]{3}|[abfnrtv\\\\'\"]|x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8})", + "name": "constant.character.escape.spirv" + }, { + "match": "\\\\[^0-7xuUabfnrtv\\'\"]", + "name": "invalid.illegal.unknown-escape.spirv" + } + ] + } + } +} diff --git a/third_party/spirv-tools/utils/vscode/src/grammar/grammar.go b/third_party/spirv-tools/utils/vscode/src/grammar/grammar.go new file mode 100644 index 0000000000..857a193e3c --- /dev/null +++ b/third_party/spirv-tools/utils/vscode/src/grammar/grammar.go @@ -0,0 +1,81 @@ +// Copyright (C) 2019 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package grammar holds the JSON type definitions for the SPIR-V grammar schema. +// +// See https://www.khronos.org/registry/spir-v/specs/unified1/MachineReadableGrammar.html +// for more information. +package grammar + +// Root is the top-level structure of the JSON grammar. +type Root struct { + MagicNumber string `json:"magic_number"` + MajorVersion int `json:"major_version"` + MinorVersion int `json:"minor_version"` + Revision int `json:"revision"` + Instructions []Instruction `json:"instructions"` + OperandKinds []OperandKind `json:"operand_kinds"` +} + +// Instruction holds information about a specific SPIR-V instruction. +type Instruction struct { + Opname string `json:"opname"` + Class string `json:"class"` + Opcode int `json:"opcode"` + Operands []Operand `json:"operands"` +} + +// Operand contains information about a logical operand for an instruction. +type Operand struct { + Kind string `json:"kind"` + Name string `json:"name"` + Quantifier Quantifier `json:"quantifier"` +} + +// OperandKind contains information about a specific operand kind. +type OperandKind struct { + Category string `json:"category"` + Kind string `json:"kind"` + Enumerants []Enumerant `json:"enumerants"` + Bases []string `json:"bases"` +} + +// Enumerant contains information about an enumerant in an enum. +type Enumerant struct { + Enumerant string `json:"enumerant"` + Value interface{} `json:"value"` + Capabilities []string `json:"capabilities"` + Parameters []Parameter `json:"parameters"` + Version string `json:"version"` +} + +// Parameter contains information about a logical parameter for an enumerant. +type Parameter struct { + Kind string `json:"kind"` + Name string `json:"name"` +} + +// Quantifier indicates the number of times the quantified term may appear. +type Quantifier string + +const ( + // Once indicates the quantified term may appear exactly once. + Once Quantifier = "" + // ZeroOrOnce indicates the quantified term may appear zero or one + // time; an optional term. + ZeroOrOnce Quantifier = "?" + // ZeroOrMany indicates the quantified term may appear any number of + // times. + ZeroOrMany Quantifier = "*" +) diff --git a/third_party/spirv-tools/utils/vscode/src/langsvr.go b/third_party/spirv-tools/utils/vscode/src/langsvr.go new file mode 100644 index 0000000000..d1b80dcab5 --- /dev/null +++ b/third_party/spirv-tools/utils/vscode/src/langsvr.go @@ -0,0 +1,527 @@ +// Copyright (C) 2019 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// langsvr implements a Language Server for the SPIRV assembly language. +package main + +import ( + "context" + "fmt" + "io" + "io/ioutil" + "log" + "os" + "path" + "sort" + "strings" + "sync" + "unicode/utf8" + + "./parser" + "./schema" + + "./lsp/jsonrpc2" + lsp "./lsp/protocol" +) + +// rSpy is a reader 'spy' that wraps an io.Reader, and logs all data that passes +// through it. +type rSpy struct { + prefix string + r io.Reader +} + +func (s rSpy) Read(p []byte) (n int, err error) { + n, err = s.r.Read(p) + log.Printf("%v %v", s.prefix, string(p[:n])) + return n, err +} + +// wSpy is a reader 'spy' that wraps an io.Writer, and logs all data that passes +// through it. +type wSpy struct { + prefix string + w io.Writer +} + +func (s wSpy) Write(p []byte) (n int, err error) { + n, err = s.w.Write(p) + log.Printf("%v %v", s.prefix, string(p)) + return n, err +} + +// main entry point. +func main() { + // create a log file in the executable's directory. + if logfile, err := os.Create(path.Join(path.Dir(os.Args[0]), "log.txt")); err == nil { + defer logfile.Close() + log.SetOutput(logfile) + } else { + log.SetOutput(ioutil.Discard) + } + + log.Println("language server started") + + stream := jsonrpc2.NewHeaderStream(rSpy{"IDE", os.Stdin}, wSpy{"LS", os.Stdout}) + s := server{ + files: map[string]*file{}, + } + s.ctx, s.conn, s.client = lsp.NewServer(context.Background(), stream, &s) + if err := s.conn.Run(s.ctx); err != nil { + log.Panicln(err) + os.Exit(1) + } + + log.Println("language server stopped") +} + +type server struct { + ctx context.Context + conn *jsonrpc2.Conn + client lsp.Client + + files map[string]*file + filesMutex sync.Mutex +} + +// file represents a source file +type file struct { + fullRange parser.Range + res parser.Results +} + +// tokAt returns the parser token at the given position lp +func (f *file) tokAt(lp lsp.Position) *parser.Token { + toks := f.res.Tokens + p := parser.Position{Line: int(lp.Line) + 1, Column: int(lp.Character) + 1} + i := sort.Search(len(toks), func(i int) bool { return p.LessThan(toks[i].Range.End) }) + if i == len(toks) { + return nil + } + if toks[i].Range.Contains(p) { + return toks[i] + } + return nil +} + +func (s *server) DidChangeWorkspaceFolders(ctx context.Context, p *lsp.DidChangeWorkspaceFoldersParams) error { + log.Println("server.DidChangeWorkspaceFolders()") + return nil +} +func (s *server) Initialized(ctx context.Context, p *lsp.InitializedParams) error { + log.Println("server.Initialized()") + return nil +} +func (s *server) Exit(ctx context.Context) error { + log.Println("server.Exit()") + return nil +} +func (s *server) DidChangeConfiguration(ctx context.Context, p *lsp.DidChangeConfigurationParams) error { + log.Println("server.DidChangeConfiguration()") + return nil +} +func (s *server) DidOpen(ctx context.Context, p *lsp.DidOpenTextDocumentParams) error { + log.Println("server.DidOpen()") + return s.processFile(ctx, p.TextDocument.URI, p.TextDocument.Text) +} +func (s *server) DidChange(ctx context.Context, p *lsp.DidChangeTextDocumentParams) error { + log.Println("server.DidChange()") + return s.processFile(ctx, p.TextDocument.URI, p.ContentChanges[0].Text) +} +func (s *server) DidClose(ctx context.Context, p *lsp.DidCloseTextDocumentParams) error { + log.Println("server.DidClose()") + return nil +} +func (s *server) DidSave(ctx context.Context, p *lsp.DidSaveTextDocumentParams) error { + log.Println("server.DidSave()") + return nil +} +func (s *server) WillSave(ctx context.Context, p *lsp.WillSaveTextDocumentParams) error { + log.Println("server.WillSave()") + return nil +} +func (s *server) DidChangeWatchedFiles(ctx context.Context, p *lsp.DidChangeWatchedFilesParams) error { + log.Println("server.DidChangeWatchedFiles()") + return nil +} +func (s *server) Progress(ctx context.Context, p *lsp.ProgressParams) error { + log.Println("server.Progress()") + return nil +} +func (s *server) SetTraceNotification(ctx context.Context, p *lsp.SetTraceParams) error { + log.Println("server.SetTraceNotification()") + return nil +} +func (s *server) LogTraceNotification(ctx context.Context, p *lsp.LogTraceParams) error { + log.Println("server.LogTraceNotification()") + return nil +} +func (s *server) Implementation(ctx context.Context, p *lsp.ImplementationParams) ([]lsp.Location, error) { + log.Println("server.Implementation()") + return nil, nil +} +func (s *server) TypeDefinition(ctx context.Context, p *lsp.TypeDefinitionParams) ([]lsp.Location, error) { + log.Println("server.TypeDefinition()") + return nil, nil +} +func (s *server) DocumentColor(ctx context.Context, p *lsp.DocumentColorParams) ([]lsp.ColorInformation, error) { + log.Println("server.DocumentColor()") + return nil, nil +} +func (s *server) ColorPresentation(ctx context.Context, p *lsp.ColorPresentationParams) ([]lsp.ColorPresentation, error) { + log.Println("server.ColorPresentation()") + return nil, nil +} +func (s *server) FoldingRange(ctx context.Context, p *lsp.FoldingRangeParams) ([]lsp.FoldingRange, error) { + log.Println("server.FoldingRange()") + return nil, nil +} +func (s *server) Declaration(ctx context.Context, p *lsp.DeclarationParams) ([]lsp.DeclarationLink, error) { + log.Println("server.Declaration()") + return nil, nil +} +func (s *server) SelectionRange(ctx context.Context, p *lsp.SelectionRangeParams) ([]lsp.SelectionRange, error) { + log.Println("server.SelectionRange()") + return nil, nil +} +func (s *server) Initialize(ctx context.Context, p *lsp.ParamInitia) (*lsp.InitializeResult, error) { + log.Println("server.Initialize()") + res := lsp.InitializeResult{ + Capabilities: lsp.ServerCapabilities{ + TextDocumentSync: lsp.TextDocumentSyncOptions{ + OpenClose: true, + Change: lsp.Full, // TODO: Implement incremental + }, + HoverProvider: true, + DefinitionProvider: true, + ReferencesProvider: true, + RenameProvider: true, + DocumentFormattingProvider: true, + }, + } + return &res, nil +} +func (s *server) Shutdown(ctx context.Context) error { + log.Println("server.Shutdown()") + return nil +} +func (s *server) WillSaveWaitUntil(ctx context.Context, p *lsp.WillSaveTextDocumentParams) ([]lsp.TextEdit, error) { + log.Println("server.WillSaveWaitUntil()") + return nil, nil +} +func (s *server) Completion(ctx context.Context, p *lsp.CompletionParams) (*lsp.CompletionList, error) { + log.Println("server.Completion()") + return nil, nil +} +func (s *server) Resolve(ctx context.Context, p *lsp.CompletionItem) (*lsp.CompletionItem, error) { + log.Println("server.Resolve()") + return nil, nil +} +func (s *server) Hover(ctx context.Context, p *lsp.HoverParams) (*lsp.Hover, error) { + log.Println("server.Hover()") + f := s.getFile(p.TextDocument.URI) + if f == nil { + return nil, fmt.Errorf("Unknown file") + } + + if tok := f.tokAt(p.Position); tok != nil { + sb := strings.Builder{} + switch v := f.res.Mappings[tok].(type) { + default: + sb.WriteString(fmt.Sprintf("", v)) + case *parser.Instruction: + sb.WriteString(fmt.Sprintf("```\n%v\n```", v.Opcode.Opname)) + case *parser.Identifier: + sb.WriteString(fmt.Sprintf("```\n%v\n```", v.Definition.Range.Text(f.res.Lines))) + case *parser.Operand: + if v.Name != "" { + sb.WriteString(strings.Trim(v.Name, `'`)) + sb.WriteString("\n\n") + } + + switch v.Kind.Category { + case schema.OperandCategoryBitEnum: + case schema.OperandCategoryValueEnum: + sb.WriteString("```\n") + sb.WriteString(strings.Trim(v.Kind.Kind, `'`)) + sb.WriteString("\n```") + case schema.OperandCategoryID: + if s := tok.Text(f.res.Lines); s != "" { + if id, ok := f.res.Identifiers[s]; ok && id.Definition != nil { + sb.WriteString("```\n") + sb.WriteString(id.Definition.Range.Text(f.res.Lines)) + sb.WriteString("\n```") + } + } + case schema.OperandCategoryLiteral: + case schema.OperandCategoryComposite: + } + case nil: + } + + if sb.Len() > 0 { + res := lsp.Hover{ + Contents: lsp.MarkupContent{ + Kind: "markdown", + Value: sb.String(), + }, + } + return &res, nil + } + } + + return nil, nil +} +func (s *server) SignatureHelp(ctx context.Context, p *lsp.SignatureHelpParams) (*lsp.SignatureHelp, error) { + log.Println("server.SignatureHelp()") + return nil, nil +} +func (s *server) Definition(ctx context.Context, p *lsp.DefinitionParams) ([]lsp.Location, error) { + log.Println("server.Definition()") + if f := s.getFile(p.TextDocument.URI); f != nil { + if tok := f.tokAt(p.Position); tok != nil { + if s := tok.Text(f.res.Lines); s != "" { + if id, ok := f.res.Identifiers[s]; ok { + loc := lsp.Location{ + URI: p.TextDocument.URI, + Range: rangeToLSP(id.Definition.Range), + } + return []lsp.Location{loc}, nil + } + } + } + } + return nil, nil +} +func (s *server) References(ctx context.Context, p *lsp.ReferenceParams) ([]lsp.Location, error) { + log.Println("server.References()") + if f := s.getFile(p.TextDocument.URI); f != nil { + if tok := f.tokAt(p.Position); tok != nil { + if s := tok.Text(f.res.Lines); s != "" { + if id, ok := f.res.Identifiers[s]; ok { + locs := make([]lsp.Location, len(id.References)) + for i, r := range id.References { + locs[i] = lsp.Location{ + URI: p.TextDocument.URI, + Range: rangeToLSP(r.Range), + } + } + return locs, nil + } + } + } + } + return nil, nil +} +func (s *server) DocumentHighlight(ctx context.Context, p *lsp.DocumentHighlightParams) ([]lsp.DocumentHighlight, error) { + log.Println("server.DocumentHighlight()") + return nil, nil +} +func (s *server) DocumentSymbol(ctx context.Context, p *lsp.DocumentSymbolParams) ([]lsp.DocumentSymbol, error) { + log.Println("server.DocumentSymbol()") + return nil, nil +} +func (s *server) CodeAction(ctx context.Context, p *lsp.CodeActionParams) ([]lsp.CodeAction, error) { + log.Println("server.CodeAction()") + return nil, nil +} +func (s *server) Symbol(ctx context.Context, p *lsp.WorkspaceSymbolParams) ([]lsp.SymbolInformation, error) { + log.Println("server.Symbol()") + return nil, nil +} +func (s *server) CodeLens(ctx context.Context, p *lsp.CodeLensParams) ([]lsp.CodeLens, error) { + log.Println("server.CodeLens()") + return nil, nil +} +func (s *server) ResolveCodeLens(ctx context.Context, p *lsp.CodeLens) (*lsp.CodeLens, error) { + log.Println("server.ResolveCodeLens()") + return nil, nil +} +func (s *server) DocumentLink(ctx context.Context, p *lsp.DocumentLinkParams) ([]lsp.DocumentLink, error) { + log.Println("server.DocumentLink()") + return nil, nil +} +func (s *server) ResolveDocumentLink(ctx context.Context, p *lsp.DocumentLink) (*lsp.DocumentLink, error) { + log.Println("server.ResolveDocumentLink()") + return nil, nil +} +func (s *server) Formatting(ctx context.Context, p *lsp.DocumentFormattingParams) ([]lsp.TextEdit, error) { + log.Println("server.Formatting()") + if f := s.getFile(p.TextDocument.URI); f != nil { + // Start by measuring the distance from the start of each line to the + // first opcode on that line. + lineInstOffsets, maxInstOffset, instOffset, curOffset := []int{}, 0, 0, -1 + for _, t := range f.res.Tokens { + curOffset++ // whitespace between tokens + switch t.Type { + case parser.Ident: + if _, isInst := schema.Opcodes[t.Text(f.res.Lines)]; isInst && instOffset == 0 { + instOffset = curOffset + continue + } + case parser.Newline: + lineInstOffsets = append(lineInstOffsets, instOffset) + if instOffset > maxInstOffset { + maxInstOffset = instOffset + } + curOffset, instOffset = -1, 0 + default: + curOffset += utf8.RuneCountInString(t.Text(f.res.Lines)) + } + } + lineInstOffsets = append(lineInstOffsets, instOffset) + + // Now rewrite each of the lines, adding padding at the start of the + // line for alignment. + sb, newline := strings.Builder{}, true + for _, t := range f.res.Tokens { + if newline { + newline = false + indent := maxInstOffset - lineInstOffsets[0] + lineInstOffsets = lineInstOffsets[1:] + switch t.Type { + case parser.Newline, parser.Comment: + default: + for s := 0; s < indent; s++ { + sb.WriteRune(' ') + } + } + } else if t.Type != parser.Newline { + sb.WriteString(" ") + } + + sb.WriteString(t.Text(f.res.Lines)) + if t.Type == parser.Newline { + newline = true + } + } + + // Every good file ends with a new line. + sb.WriteString("\n") + + return []lsp.TextEdit{ + lsp.TextEdit{ + Range: rangeToLSP(f.fullRange), + NewText: sb.String(), + }, + }, nil + } + return nil, nil +} +func (s *server) RangeFormatting(ctx context.Context, p *lsp.DocumentRangeFormattingParams) ([]lsp.TextEdit, error) { + log.Println("server.RangeFormatting()") + return nil, nil +} +func (s *server) OnTypeFormatting(ctx context.Context, p *lsp.DocumentOnTypeFormattingParams) ([]lsp.TextEdit, error) { + log.Println("server.OnTypeFormatting()") + return nil, nil +} +func (s *server) Rename(ctx context.Context, p *lsp.RenameParams) (*lsp.WorkspaceEdit, error) { + log.Println("server.Rename()") + if f := s.getFile(p.TextDocument.URI); f != nil { + if tok := f.tokAt(p.Position); tok != nil { + if s := tok.Text(f.res.Lines); s != "" { + if id, ok := f.res.Identifiers[s]; ok { + changes := make([]lsp.TextEdit, len(id.References)) + for i, r := range id.References { + changes[i].Range = rangeToLSP(r.Range) + changes[i].NewText = p.NewName + } + m := map[string][]lsp.TextEdit{} + m[p.TextDocument.URI] = changes + return &lsp.WorkspaceEdit{Changes: &m}, nil + } + } + } + } + return nil, nil +} +func (s *server) PrepareRename(ctx context.Context, p *lsp.PrepareRenameParams) (*lsp.Range, error) { + log.Println("server.PrepareRename()") + return nil, nil +} +func (s *server) ExecuteCommand(ctx context.Context, p *lsp.ExecuteCommandParams) (interface{}, error) { + log.Println("server.ExecuteCommand()") + return nil, nil +} + +func (s *server) processFile(ctx context.Context, uri, source string) error { + log.Println("server.DidOpen()") + res, err := parser.Parse(source) + if err != nil { + return err + } + fullRange := parser.Range{ + Start: parser.Position{Line: 1, Column: 1}, + End: parser.Position{Line: len(res.Lines), Column: utf8.RuneCountInString(res.Lines[len(res.Lines)-1]) + 1}, + } + + s.filesMutex.Lock() + s.files[uri] = &file{ + fullRange: fullRange, + res: res, + } + s.filesMutex.Unlock() + + dp := lsp.PublishDiagnosticsParams{URI: uri, Diagnostics: make([]lsp.Diagnostic, len(res.Diagnostics))} + for i, d := range res.Diagnostics { + dp.Diagnostics[i] = diagnosticToLSP(d) + } + s.client.PublishDiagnostics(ctx, &dp) + return nil +} + +func (s *server) getFile(uri string) *file { + s.filesMutex.Lock() + defer s.filesMutex.Unlock() + return s.files[uri] +} + +func diagnosticToLSP(d parser.Diagnostic) lsp.Diagnostic { + return lsp.Diagnostic{ + Range: rangeToLSP(d.Range), + Severity: severityToLSP(d.Severity), + Message: d.Message, + } +} + +func severityToLSP(s parser.Severity) lsp.DiagnosticSeverity { + switch s { + case parser.SeverityError: + return lsp.SeverityError + case parser.SeverityWarning: + return lsp.SeverityWarning + case parser.SeverityInformation: + return lsp.SeverityInformation + case parser.SeverityHint: + return lsp.SeverityHint + default: + log.Panicf("Invalid severity '%d'", int(s)) + return lsp.SeverityError + } +} + +func rangeToLSP(r parser.Range) lsp.Range { + return lsp.Range{ + Start: positionToLSP(r.Start), + End: positionToLSP(r.End), + } +} + +func positionToLSP(r parser.Position) lsp.Position { + return lsp.Position{ + Line: float64(r.Line - 1), + Character: float64(r.Column - 1), + } +} diff --git a/third_party/spirv-tools/utils/vscode/src/lsp/LICENSE b/third_party/spirv-tools/utils/vscode/src/lsp/LICENSE new file mode 100644 index 0000000000..d645695673 --- /dev/null +++ b/third_party/spirv-tools/utils/vscode/src/lsp/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/third_party/spirv-tools/utils/vscode/src/lsp/README.md b/third_party/spirv-tools/utils/vscode/src/lsp/README.md new file mode 100644 index 0000000000..c78f183f34 --- /dev/null +++ b/third_party/spirv-tools/utils/vscode/src/lsp/README.md @@ -0,0 +1,5 @@ +This directory contains code forked from https://github.com/golang/tools/tree/master/internal/lsp. + +This code has been modified to remove unneeded features and dependencies. + +Submitted on behalf of a third-party: The Go Authors diff --git a/third_party/spirv-tools/utils/vscode/src/lsp/jsonrpc2/handler.go b/third_party/spirv-tools/utils/vscode/src/lsp/jsonrpc2/handler.go new file mode 100644 index 0000000000..20d484178f --- /dev/null +++ b/third_party/spirv-tools/utils/vscode/src/lsp/jsonrpc2/handler.go @@ -0,0 +1,134 @@ +// Copyright 2019 The Go Authors. +// +// 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. + +package jsonrpc2 + +import ( + "context" +) + +// Handler is the interface used to hook into the message handling of an rpc +// connection. +type Handler interface { + // Deliver is invoked to handle incoming requests. + // If the request returns false from IsNotify then the Handler must eventually + // call Reply on the Conn with the supplied request. + // Handlers are called synchronously, they should pass the work off to a go + // routine if they are going to take a long time. + // If Deliver returns true all subsequent handlers will be invoked with + // delivered set to true, and should not attempt to deliver the message. + Deliver(ctx context.Context, r *Request, delivered bool) bool + + // Cancel is invoked for cancelled outgoing requests. + // It is okay to use the connection to send notifications, but the context will + // be in the cancelled state, so you must do it with the background context + // instead. + // If Cancel returns true all subsequent handlers will be invoked with + // cancelled set to true, and should not attempt to cancel the message. + Cancel(ctx context.Context, conn *Conn, id ID, cancelled bool) bool + + // Log is invoked for all messages flowing through a Conn. + // direction indicates if the message being received or sent + // id is the message id, if not set it was a notification + // elapsed is the time between a call being seen and the response, and is + // negative for anything that is not a response. + // method is the method name specified in the message + // payload is the parameters for a call or notification, and the result for a + // response + + // Request is called near the start of processing any request. + Request(ctx context.Context, conn *Conn, direction Direction, r *WireRequest) context.Context + // Response is called near the start of processing any response. + Response(ctx context.Context, conn *Conn, direction Direction, r *WireResponse) context.Context + // Done is called when any request is fully processed. + // For calls, this means the response has also been processed, for notifies + // this is as soon as the message has been written to the stream. + // If err is set, it implies the request failed. + Done(ctx context.Context, err error) + // Read is called with a count each time some data is read from the stream. + // The read calls are delayed until after the data has been interpreted so + // that it can be attributed to a request/response. + Read(ctx context.Context, bytes int64) context.Context + // Wrote is called each time some data is written to the stream. + Wrote(ctx context.Context, bytes int64) context.Context + // Error is called with errors that cannot be delivered through the normal + // mechanisms, for instance a failure to process a notify cannot be delivered + // back to the other party. + Error(ctx context.Context, err error) +} + +// Direction is used to indicate to a logger whether the logged message was being +// sent or received. +type Direction bool + +const ( + // Send indicates the message is outgoing. + Send = Direction(true) + // Receive indicates the message is incoming. + Receive = Direction(false) +) + +func (d Direction) String() string { + switch d { + case Send: + return "send" + case Receive: + return "receive" + default: + panic("unreachable") + } +} + +type EmptyHandler struct{} + +func (EmptyHandler) Deliver(ctx context.Context, r *Request, delivered bool) bool { + return false +} + +func (EmptyHandler) Cancel(ctx context.Context, conn *Conn, id ID, cancelled bool) bool { + return false +} + +func (EmptyHandler) Request(ctx context.Context, conn *Conn, direction Direction, r *WireRequest) context.Context { + return ctx +} + +func (EmptyHandler) Response(ctx context.Context, conn *Conn, direction Direction, r *WireResponse) context.Context { + return ctx +} + +func (EmptyHandler) Done(ctx context.Context, err error) { +} + +func (EmptyHandler) Read(ctx context.Context, bytes int64) context.Context { + return ctx +} + +func (EmptyHandler) Wrote(ctx context.Context, bytes int64) context.Context { + return ctx +} + +func (EmptyHandler) Error(ctx context.Context, err error) {} + +type defaultHandler struct{ EmptyHandler } + +func (defaultHandler) Deliver(ctx context.Context, r *Request, delivered bool) bool { + if delivered { + return false + } + if !r.IsNotify() { + r.Reply(ctx, nil, NewErrorf(CodeMethodNotFound, "method %q not found", r.Method)) + } + return true +} diff --git a/third_party/spirv-tools/utils/vscode/src/lsp/jsonrpc2/jsonrpc2.go b/third_party/spirv-tools/utils/vscode/src/lsp/jsonrpc2/jsonrpc2.go new file mode 100644 index 0000000000..b8436d27b4 --- /dev/null +++ b/third_party/spirv-tools/utils/vscode/src/lsp/jsonrpc2/jsonrpc2.go @@ -0,0 +1,416 @@ +// Copyright 2018 The Go Authors. +// +// 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. + +// Package jsonrpc2 is a minimal implementation of the JSON RPC 2 spec. +// https://www.jsonrpc.org/specification +// It is intended to be compatible with other implementations at the wire level. +package jsonrpc2 + +import ( + "context" + "encoding/json" + "fmt" + "sync" + "sync/atomic" +) + +// Conn is a JSON RPC 2 client server connection. +// Conn is bidirectional; it does not have a designated server or client end. +type Conn struct { + seq int64 // must only be accessed using atomic operations + handlers []Handler + stream Stream + err error + pendingMu sync.Mutex // protects the pending map + pending map[ID]chan *WireResponse + handlingMu sync.Mutex // protects the handling map + handling map[ID]*Request +} + +type requestState int + +const ( + requestWaiting = requestState(iota) + requestSerial + requestParallel + requestReplied + requestDone +) + +// Request is sent to a server to represent a Call or Notify operaton. +type Request struct { + conn *Conn + cancel context.CancelFunc + state requestState + nextRequest chan struct{} + + // The Wire values of the request. + WireRequest +} + +// NewErrorf builds a Error struct for the supplied message and code. +// If args is not empty, message and args will be passed to Sprintf. +func NewErrorf(code int64, format string, args ...interface{}) *Error { + return &Error{ + Code: code, + Message: fmt.Sprintf(format, args...), + } +} + +// NewConn creates a new connection object around the supplied stream. +// You must call Run for the connection to be active. +func NewConn(s Stream) *Conn { + conn := &Conn{ + handlers: []Handler{defaultHandler{}}, + stream: s, + pending: make(map[ID]chan *WireResponse), + handling: make(map[ID]*Request), + } + return conn +} + +// AddHandler adds a new handler to the set the connection will invoke. +// Handlers are invoked in the reverse order of how they were added, this +// allows the most recent addition to be the first one to attempt to handle a +// message. +func (c *Conn) AddHandler(handler Handler) { + // prepend the new handlers so we use them first + c.handlers = append([]Handler{handler}, c.handlers...) +} + +// Cancel cancels a pending Call on the server side. +// The call is identified by its id. +// JSON RPC 2 does not specify a cancel message, so cancellation support is not +// directly wired in. This method allows a higher level protocol to choose how +// to propagate the cancel. +func (c *Conn) Cancel(id ID) { + c.handlingMu.Lock() + handling, found := c.handling[id] + c.handlingMu.Unlock() + if found { + handling.cancel() + } +} + +// Notify is called to send a notification request over the connection. +// It will return as soon as the notification has been sent, as no response is +// possible. +func (c *Conn) Notify(ctx context.Context, method string, params interface{}) (err error) { + jsonParams, err := marshalToRaw(params) + if err != nil { + return fmt.Errorf("marshalling notify parameters: %v", err) + } + request := &WireRequest{ + Method: method, + Params: jsonParams, + } + data, err := json.Marshal(request) + if err != nil { + return fmt.Errorf("marshalling notify request: %v", err) + } + for _, h := range c.handlers { + ctx = h.Request(ctx, c, Send, request) + } + defer func() { + for _, h := range c.handlers { + h.Done(ctx, err) + } + }() + n, err := c.stream.Write(ctx, data) + for _, h := range c.handlers { + ctx = h.Wrote(ctx, n) + } + return err +} + +// Call sends a request over the connection and then waits for a response. +// If the response is not an error, it will be decoded into result. +// result must be of a type you an pass to json.Unmarshal. +func (c *Conn) Call(ctx context.Context, method string, params, result interface{}) (err error) { + // generate a new request identifier + id := ID{Number: atomic.AddInt64(&c.seq, 1)} + jsonParams, err := marshalToRaw(params) + if err != nil { + return fmt.Errorf("marshalling call parameters: %v", err) + } + request := &WireRequest{ + ID: &id, + Method: method, + Params: jsonParams, + } + // marshal the request now it is complete + data, err := json.Marshal(request) + if err != nil { + return fmt.Errorf("marshalling call request: %v", err) + } + for _, h := range c.handlers { + ctx = h.Request(ctx, c, Send, request) + } + // we have to add ourselves to the pending map before we send, otherwise we + // are racing the response + rchan := make(chan *WireResponse) + c.pendingMu.Lock() + c.pending[id] = rchan + c.pendingMu.Unlock() + defer func() { + // clean up the pending response handler on the way out + c.pendingMu.Lock() + delete(c.pending, id) + c.pendingMu.Unlock() + for _, h := range c.handlers { + h.Done(ctx, err) + } + }() + // now we are ready to send + n, err := c.stream.Write(ctx, data) + for _, h := range c.handlers { + ctx = h.Wrote(ctx, n) + } + if err != nil { + // sending failed, we will never get a response, so don't leave it pending + return err + } + // now wait for the response + select { + case response := <-rchan: + for _, h := range c.handlers { + ctx = h.Response(ctx, c, Receive, response) + } + // is it an error response? + if response.Error != nil { + return response.Error + } + if result == nil || response.Result == nil { + return nil + } + if err := json.Unmarshal(*response.Result, result); err != nil { + return fmt.Errorf("unmarshalling result: %v", err) + } + return nil + case <-ctx.Done(): + // allow the handler to propagate the cancel + cancelled := false + for _, h := range c.handlers { + if h.Cancel(ctx, c, id, cancelled) { + cancelled = true + } + } + return ctx.Err() + } +} + +// Conn returns the connection that created this request. +func (r *Request) Conn() *Conn { return r.conn } + +// IsNotify returns true if this request is a notification. +func (r *Request) IsNotify() bool { + return r.ID == nil +} + +// Parallel indicates that the system is now allowed to process other requests +// in parallel with this one. +// It is safe to call any number of times, but must only be called from the +// request handling go routine. +// It is implied by both reply and by the handler returning. +func (r *Request) Parallel() { + if r.state >= requestParallel { + return + } + r.state = requestParallel + close(r.nextRequest) +} + +// Reply sends a reply to the given request. +// It is an error to call this if request was not a call. +// You must call this exactly once for any given request. +// It should only be called from the handler go routine. +// If err is set then result will be ignored. +// If the request has not yet dropped into parallel mode +// it will be before this function returns. +func (r *Request) Reply(ctx context.Context, result interface{}, err error) error { + if r.state >= requestReplied { + return fmt.Errorf("reply invoked more than once") + } + if r.IsNotify() { + return fmt.Errorf("reply not invoked with a valid call") + } + // reply ends the handling phase of a call, so if we are not yet + // parallel we should be now. The go routine is allowed to continue + // to do work after replying, which is why it is important to unlock + // the rpc system at this point. + r.Parallel() + r.state = requestReplied + + var raw *json.RawMessage + if err == nil { + raw, err = marshalToRaw(result) + } + response := &WireResponse{ + Result: raw, + ID: r.ID, + } + if err != nil { + if callErr, ok := err.(*Error); ok { + response.Error = callErr + } else { + response.Error = NewErrorf(0, "%s", err) + } + } + data, err := json.Marshal(response) + if err != nil { + return err + } + for _, h := range r.conn.handlers { + ctx = h.Response(ctx, r.conn, Send, response) + } + n, err := r.conn.stream.Write(ctx, data) + for _, h := range r.conn.handlers { + ctx = h.Wrote(ctx, n) + } + + if err != nil { + // TODO(iancottrell): if a stream write fails, we really need to shut down + // the whole stream + return err + } + return nil +} + +func (c *Conn) setHandling(r *Request, active bool) { + if r.ID == nil { + return + } + r.conn.handlingMu.Lock() + defer r.conn.handlingMu.Unlock() + if active { + r.conn.handling[*r.ID] = r + } else { + delete(r.conn.handling, *r.ID) + } +} + +// combined has all the fields of both Request and Response. +// We can decode this and then work out which it is. +type combined struct { + VersionTag VersionTag `json:"jsonrpc"` + ID *ID `json:"id,omitempty"` + Method string `json:"method"` + Params *json.RawMessage `json:"params,omitempty"` + Result *json.RawMessage `json:"result,omitempty"` + Error *Error `json:"error,omitempty"` +} + +// Run blocks until the connection is terminated, and returns any error that +// caused the termination. +// It must be called exactly once for each Conn. +// It returns only when the reader is closed or there is an error in the stream. +func (c *Conn) Run(runCtx context.Context) error { + // we need to make the next request "lock" in an unlocked state to allow + // the first incoming request to proceed. All later requests are unlocked + // by the preceding request going to parallel mode. + nextRequest := make(chan struct{}) + close(nextRequest) + for { + // get the data for a message + data, n, err := c.stream.Read(runCtx) + if err != nil { + // the stream failed, we cannot continue + return err + } + // read a combined message + msg := &combined{} + if err := json.Unmarshal(data, msg); err != nil { + // a badly formed message arrived, log it and continue + // we trust the stream to have isolated the error to just this message + for _, h := range c.handlers { + h.Error(runCtx, fmt.Errorf("unmarshal failed: %v", err)) + } + continue + } + // work out which kind of message we have + switch { + case msg.Method != "": + // if method is set it must be a request + reqCtx, cancelReq := context.WithCancel(runCtx) + thisRequest := nextRequest + nextRequest = make(chan struct{}) + req := &Request{ + conn: c, + cancel: cancelReq, + nextRequest: nextRequest, + WireRequest: WireRequest{ + VersionTag: msg.VersionTag, + Method: msg.Method, + Params: msg.Params, + ID: msg.ID, + }, + } + for _, h := range c.handlers { + reqCtx = h.Request(reqCtx, c, Receive, &req.WireRequest) + reqCtx = h.Read(reqCtx, n) + } + c.setHandling(req, true) + go func() { + <-thisRequest + req.state = requestSerial + defer func() { + c.setHandling(req, false) + if !req.IsNotify() && req.state < requestReplied { + req.Reply(reqCtx, nil, NewErrorf(CodeInternalError, "method %q did not reply", req.Method)) + } + req.Parallel() + for _, h := range c.handlers { + h.Done(reqCtx, err) + } + cancelReq() + }() + delivered := false + for _, h := range c.handlers { + if h.Deliver(reqCtx, req, delivered) { + delivered = true + } + } + }() + case msg.ID != nil: + // we have a response, get the pending entry from the map + c.pendingMu.Lock() + rchan := c.pending[*msg.ID] + if rchan != nil { + delete(c.pending, *msg.ID) + } + c.pendingMu.Unlock() + // and send the reply to the channel + response := &WireResponse{ + Result: msg.Result, + Error: msg.Error, + ID: msg.ID, + } + rchan <- response + close(rchan) + default: + for _, h := range c.handlers { + h.Error(runCtx, fmt.Errorf("message not a call, notify or response, ignoring")) + } + } + } +} + +func marshalToRaw(obj interface{}) (*json.RawMessage, error) { + data, err := json.Marshal(obj) + if err != nil { + return nil, err + } + raw := json.RawMessage(data) + return &raw, nil +} diff --git a/third_party/spirv-tools/utils/vscode/src/lsp/jsonrpc2/stream.go b/third_party/spirv-tools/utils/vscode/src/lsp/jsonrpc2/stream.go new file mode 100644 index 0000000000..2c6ad6dfdc --- /dev/null +++ b/third_party/spirv-tools/utils/vscode/src/lsp/jsonrpc2/stream.go @@ -0,0 +1,160 @@ +// Copyright 2018 The Go Authors. +// +// 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. + +package jsonrpc2 + +import ( + "bufio" + "context" + "encoding/json" + "fmt" + "io" + "strconv" + "strings" + "sync" +) + +// Stream abstracts the transport mechanics from the JSON RPC protocol. +// A Conn reads and writes messages using the stream it was provided on +// construction, and assumes that each call to Read or Write fully transfers +// a single message, or returns an error. +type Stream interface { + // Read gets the next message from the stream. + // It is never called concurrently. + Read(context.Context) ([]byte, int64, error) + // Write sends a message to the stream. + // It must be safe for concurrent use. + Write(context.Context, []byte) (int64, error) +} + +// NewStream returns a Stream built on top of an io.Reader and io.Writer +// The messages are sent with no wrapping, and rely on json decode consistency +// to determine message boundaries. +func NewStream(in io.Reader, out io.Writer) Stream { + return &plainStream{ + in: json.NewDecoder(in), + out: out, + } +} + +type plainStream struct { + in *json.Decoder + outMu sync.Mutex + out io.Writer +} + +func (s *plainStream) Read(ctx context.Context) ([]byte, int64, error) { + select { + case <-ctx.Done(): + return nil, 0, ctx.Err() + default: + } + var raw json.RawMessage + if err := s.in.Decode(&raw); err != nil { + return nil, 0, err + } + return raw, int64(len(raw)), nil +} + +func (s *plainStream) Write(ctx context.Context, data []byte) (int64, error) { + select { + case <-ctx.Done(): + return 0, ctx.Err() + default: + } + s.outMu.Lock() + n, err := s.out.Write(data) + s.outMu.Unlock() + return int64(n), err +} + +// NewHeaderStream returns a Stream built on top of an io.Reader and io.Writer +// The messages are sent with HTTP content length and MIME type headers. +// This is the format used by LSP and others. +func NewHeaderStream(in io.Reader, out io.Writer) Stream { + return &headerStream{ + in: bufio.NewReader(in), + out: out, + } +} + +type headerStream struct { + in *bufio.Reader + outMu sync.Mutex + out io.Writer +} + +func (s *headerStream) Read(ctx context.Context) ([]byte, int64, error) { + select { + case <-ctx.Done(): + return nil, 0, ctx.Err() + default: + } + var total, length int64 + // read the header, stop on the first empty line + for { + line, err := s.in.ReadString('\n') + total += int64(len(line)) + if err != nil { + return nil, total, fmt.Errorf("failed reading header line %q", err) + } + line = strings.TrimSpace(line) + // check we have a header line + if line == "" { + break + } + colon := strings.IndexRune(line, ':') + if colon < 0 { + return nil, total, fmt.Errorf("invalid header line %q", line) + } + name, value := line[:colon], strings.TrimSpace(line[colon+1:]) + switch name { + case "Content-Length": + if length, err = strconv.ParseInt(value, 10, 32); err != nil { + return nil, total, fmt.Errorf("failed parsing Content-Length: %v", value) + } + if length <= 0 { + return nil, total, fmt.Errorf("invalid Content-Length: %v", length) + } + default: + // ignoring unknown headers + } + } + if length == 0 { + return nil, total, fmt.Errorf("missing Content-Length header") + } + data := make([]byte, length) + if _, err := io.ReadFull(s.in, data); err != nil { + return nil, total, err + } + total += length + return data, total, nil +} + +func (s *headerStream) Write(ctx context.Context, data []byte) (int64, error) { + select { + case <-ctx.Done(): + return 0, ctx.Err() + default: + } + s.outMu.Lock() + defer s.outMu.Unlock() + n, err := fmt.Fprintf(s.out, "Content-Length: %v\r\n\r\n", len(data)) + total := int64(n) + if err == nil { + n, err = s.out.Write(data) + total += int64(n) + } + return total, err +} diff --git a/third_party/spirv-tools/utils/vscode/src/lsp/jsonrpc2/wire.go b/third_party/spirv-tools/utils/vscode/src/lsp/jsonrpc2/wire.go new file mode 100644 index 0000000000..3e31c340d5 --- /dev/null +++ b/third_party/spirv-tools/utils/vscode/src/lsp/jsonrpc2/wire.go @@ -0,0 +1,148 @@ +// Copyright 2018 The Go Authors. +// +// 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. + +package jsonrpc2 + +import ( + "encoding/json" + "fmt" + "strconv" +) + +// this file contains the go forms of the wire specification +// see http://www.jsonrpc.org/specification for details + +const ( + // CodeUnknownError should be used for all non coded errors. + CodeUnknownError = -32001 + // CodeParseError is used when invalid JSON was received by the server. + CodeParseError = -32700 + //CodeInvalidRequest is used when the JSON sent is not a valid Request object. + CodeInvalidRequest = -32600 + // CodeMethodNotFound should be returned by the handler when the method does + // not exist / is not available. + CodeMethodNotFound = -32601 + // CodeInvalidParams should be returned by the handler when method + // parameter(s) were invalid. + CodeInvalidParams = -32602 + // CodeInternalError is not currently returned but defined for completeness. + CodeInternalError = -32603 + + //CodeServerOverloaded is returned when a message was refused due to a + //server being temporarily unable to accept any new messages. + CodeServerOverloaded = -32000 +) + +// WireRequest is sent to a server to represent a Call or Notify operaton. +type WireRequest struct { + // VersionTag is always encoded as the string "2.0" + VersionTag VersionTag `json:"jsonrpc"` + // Method is a string containing the method name to invoke. + Method string `json:"method"` + // Params is either a struct or an array with the parameters of the method. + Params *json.RawMessage `json:"params,omitempty"` + // The id of this request, used to tie the Response back to the request. + // Will be either a string or a number. If not set, the Request is a notify, + // and no response is possible. + ID *ID `json:"id,omitempty"` +} + +// WireResponse is a reply to a Request. +// It will always have the ID field set to tie it back to a request, and will +// have either the Result or Error fields set depending on whether it is a +// success or failure response. +type WireResponse struct { + // VersionTag is always encoded as the string "2.0" + VersionTag VersionTag `json:"jsonrpc"` + // Result is the response value, and is required on success. + Result *json.RawMessage `json:"result,omitempty"` + // Error is a structured error response if the call fails. + Error *Error `json:"error,omitempty"` + // ID must be set and is the identifier of the Request this is a response to. + ID *ID `json:"id,omitempty"` +} + +// Error represents a structured error in a Response. +type Error struct { + // Code is an error code indicating the type of failure. + Code int64 `json:"code"` + // Message is a short description of the error. + Message string `json:"message"` + // Data is optional structured data containing additional information about the error. + Data *json.RawMessage `json:"data"` +} + +// VersionTag is a special 0 sized struct that encodes as the jsonrpc version +// tag. +// It will fail during decode if it is not the correct version tag in the +// stream. +type VersionTag struct{} + +// ID is a Request identifier. +// Only one of either the Name or Number members will be set, using the +// number form if the Name is the empty string. +type ID struct { + Name string + Number int64 +} + +func (err *Error) Error() string { + if err == nil { + return "" + } + return err.Message +} + +func (VersionTag) MarshalJSON() ([]byte, error) { + return json.Marshal("2.0") +} + +func (VersionTag) UnmarshalJSON(data []byte) error { + version := "" + if err := json.Unmarshal(data, &version); err != nil { + return err + } + if version != "2.0" { + return fmt.Errorf("Invalid RPC version %v", version) + } + return nil +} + +// String returns a string representation of the ID. +// The representation is non ambiguous, string forms are quoted, number forms +// are preceded by a # +func (id *ID) String() string { + if id == nil { + return "" + } + if id.Name != "" { + return strconv.Quote(id.Name) + } + return "#" + strconv.FormatInt(id.Number, 10) +} + +func (id *ID) MarshalJSON() ([]byte, error) { + if id.Name != "" { + return json.Marshal(id.Name) + } + return json.Marshal(id.Number) +} + +func (id *ID) UnmarshalJSON(data []byte) error { + *id = ID{} + if err := json.Unmarshal(data, &id.Number); err == nil { + return nil + } + return json.Unmarshal(data, &id.Name) +} diff --git a/third_party/spirv-tools/utils/vscode/src/lsp/protocol/context.go b/third_party/spirv-tools/utils/vscode/src/lsp/protocol/context.go new file mode 100644 index 0000000000..7833d40e1b --- /dev/null +++ b/third_party/spirv-tools/utils/vscode/src/lsp/protocol/context.go @@ -0,0 +1,29 @@ +// Copyright 2018 The Go Authors. +// +// 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. + +package protocol + +import ( + "context" +) + +type contextKey int + +const ( + clientKey = contextKey(iota) +) + +func WithClient(ctx context.Context, client Client) context.Context { + return context.WithValue(ctx, clientKey, client) +} diff --git a/third_party/spirv-tools/utils/vscode/src/lsp/protocol/doc.go b/third_party/spirv-tools/utils/vscode/src/lsp/protocol/doc.go new file mode 100644 index 0000000000..3c9198d3b6 --- /dev/null +++ b/third_party/spirv-tools/utils/vscode/src/lsp/protocol/doc.go @@ -0,0 +1,26 @@ +// Copyright 2018 The Go Authors. +// +// 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. + +// Package protocol contains the structs that map directly to the wire format +// of the "Language Server Protocol". +// +// It is a literal transcription, with unmodified comments, and only the changes +// required to make it go code. +// Names are uppercased to export them. +// All fields have JSON tags added to correct the names. +// Fields marked with a ? are also marked as "omitempty" +// Fields that are "|| null" are made pointers +// Fields that are string or number are left as string +// Fields that are type "number" are made float64 +package protocol diff --git a/third_party/spirv-tools/utils/vscode/src/lsp/protocol/enums.go b/third_party/spirv-tools/utils/vscode/src/lsp/protocol/enums.go new file mode 100644 index 0000000000..db76ca39cc --- /dev/null +++ b/third_party/spirv-tools/utils/vscode/src/lsp/protocol/enums.go @@ -0,0 +1,256 @@ +// Copyright 2018 The Go Authors. +// +// 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. + +package protocol + +import ( + "fmt" +) + +var ( + namesTextDocumentSyncKind [int(Incremental) + 1]string + namesInitializeError [int(UnknownProtocolVersion) + 1]string + namesMessageType [int(Log) + 1]string + namesFileChangeType [int(Deleted) + 1]string + namesWatchKind [int(WatchDelete) + 1]string + namesCompletionTriggerKind [int(TriggerForIncompleteCompletions) + 1]string + namesDiagnosticSeverity [int(SeverityHint) + 1]string + namesDiagnosticTag [int(Unnecessary) + 1]string + namesCompletionItemKind [int(TypeParameterCompletion) + 1]string + namesInsertTextFormat [int(SnippetTextFormat) + 1]string + namesDocumentHighlightKind [int(Write) + 1]string + namesSymbolKind [int(TypeParameter) + 1]string + namesTextDocumentSaveReason [int(FocusOut) + 1]string +) + +func init() { + namesTextDocumentSyncKind[int(None)] = "None" + namesTextDocumentSyncKind[int(Full)] = "Full" + namesTextDocumentSyncKind[int(Incremental)] = "Incremental" + + namesInitializeError[int(UnknownProtocolVersion)] = "UnknownProtocolVersion" + + namesMessageType[int(Error)] = "Error" + namesMessageType[int(Warning)] = "Warning" + namesMessageType[int(Info)] = "Info" + namesMessageType[int(Log)] = "Log" + + namesFileChangeType[int(Created)] = "Created" + namesFileChangeType[int(Changed)] = "Changed" + namesFileChangeType[int(Deleted)] = "Deleted" + + namesWatchKind[int(WatchCreate)] = "WatchCreate" + namesWatchKind[int(WatchChange)] = "WatchChange" + namesWatchKind[int(WatchDelete)] = "WatchDelete" + + namesCompletionTriggerKind[int(Invoked)] = "Invoked" + namesCompletionTriggerKind[int(TriggerCharacter)] = "TriggerCharacter" + namesCompletionTriggerKind[int(TriggerForIncompleteCompletions)] = "TriggerForIncompleteCompletions" + + namesDiagnosticSeverity[int(SeverityError)] = "Error" + namesDiagnosticSeverity[int(SeverityWarning)] = "Warning" + namesDiagnosticSeverity[int(SeverityInformation)] = "Information" + namesDiagnosticSeverity[int(SeverityHint)] = "Hint" + + namesDiagnosticTag[int(Unnecessary)] = "Unnecessary" + + namesCompletionItemKind[int(TextCompletion)] = "text" + namesCompletionItemKind[int(MethodCompletion)] = "method" + namesCompletionItemKind[int(FunctionCompletion)] = "func" + namesCompletionItemKind[int(ConstructorCompletion)] = "constructor" + namesCompletionItemKind[int(FieldCompletion)] = "field" + namesCompletionItemKind[int(VariableCompletion)] = "var" + namesCompletionItemKind[int(ClassCompletion)] = "type" + namesCompletionItemKind[int(InterfaceCompletion)] = "interface" + namesCompletionItemKind[int(ModuleCompletion)] = "package" + namesCompletionItemKind[int(PropertyCompletion)] = "property" + namesCompletionItemKind[int(UnitCompletion)] = "unit" + namesCompletionItemKind[int(ValueCompletion)] = "value" + namesCompletionItemKind[int(EnumCompletion)] = "enum" + namesCompletionItemKind[int(KeywordCompletion)] = "keyword" + namesCompletionItemKind[int(SnippetCompletion)] = "snippet" + namesCompletionItemKind[int(ColorCompletion)] = "color" + namesCompletionItemKind[int(FileCompletion)] = "file" + namesCompletionItemKind[int(ReferenceCompletion)] = "reference" + namesCompletionItemKind[int(FolderCompletion)] = "folder" + namesCompletionItemKind[int(EnumMemberCompletion)] = "enumMember" + namesCompletionItemKind[int(ConstantCompletion)] = "const" + namesCompletionItemKind[int(StructCompletion)] = "struct" + namesCompletionItemKind[int(EventCompletion)] = "event" + namesCompletionItemKind[int(OperatorCompletion)] = "operator" + namesCompletionItemKind[int(TypeParameterCompletion)] = "typeParam" + + namesInsertTextFormat[int(PlainTextTextFormat)] = "PlainText" + namesInsertTextFormat[int(SnippetTextFormat)] = "Snippet" + + namesDocumentHighlightKind[int(Text)] = "Text" + namesDocumentHighlightKind[int(Read)] = "Read" + namesDocumentHighlightKind[int(Write)] = "Write" + + namesSymbolKind[int(File)] = "File" + namesSymbolKind[int(Module)] = "Module" + namesSymbolKind[int(Namespace)] = "Namespace" + namesSymbolKind[int(Package)] = "Package" + namesSymbolKind[int(Class)] = "Class" + namesSymbolKind[int(Method)] = "Method" + namesSymbolKind[int(Property)] = "Property" + namesSymbolKind[int(Field)] = "Field" + namesSymbolKind[int(Constructor)] = "Constructor" + namesSymbolKind[int(Enum)] = "Enum" + namesSymbolKind[int(Interface)] = "Interface" + namesSymbolKind[int(Function)] = "Function" + namesSymbolKind[int(Variable)] = "Variable" + namesSymbolKind[int(Constant)] = "Constant" + namesSymbolKind[int(String)] = "String" + namesSymbolKind[int(Number)] = "Number" + namesSymbolKind[int(Boolean)] = "Boolean" + namesSymbolKind[int(Array)] = "Array" + namesSymbolKind[int(Object)] = "Object" + namesSymbolKind[int(Key)] = "Key" + namesSymbolKind[int(Null)] = "Null" + namesSymbolKind[int(EnumMember)] = "EnumMember" + namesSymbolKind[int(Struct)] = "Struct" + namesSymbolKind[int(Event)] = "Event" + namesSymbolKind[int(Operator)] = "Operator" + namesSymbolKind[int(TypeParameter)] = "TypeParameter" + + namesTextDocumentSaveReason[int(Manual)] = "Manual" + namesTextDocumentSaveReason[int(AfterDelay)] = "AfterDelay" + namesTextDocumentSaveReason[int(FocusOut)] = "FocusOut" +} + +func formatEnum(f fmt.State, c rune, i int, names []string, unknown string) { + s := "" + if i >= 0 && i < len(names) { + s = names[i] + } + if s != "" { + fmt.Fprint(f, s) + } else { + fmt.Fprintf(f, "%s(%d)", unknown, i) + } +} + +func parseEnum(s string, names []string) int { + for i, name := range names { + if s == name { + return i + } + } + return 0 +} + +func (e TextDocumentSyncKind) Format(f fmt.State, c rune) { + formatEnum(f, c, int(e), namesTextDocumentSyncKind[:], "TextDocumentSyncKind") +} + +func ParseTextDocumentSyncKind(s string) TextDocumentSyncKind { + return TextDocumentSyncKind(parseEnum(s, namesTextDocumentSyncKind[:])) +} + +func (e InitializeError) Format(f fmt.State, c rune) { + formatEnum(f, c, int(e), namesInitializeError[:], "InitializeError") +} + +func ParseInitializeError(s string) InitializeError { + return InitializeError(parseEnum(s, namesInitializeError[:])) +} + +func (e MessageType) Format(f fmt.State, c rune) { + formatEnum(f, c, int(e), namesMessageType[:], "MessageType") +} + +func ParseMessageType(s string) MessageType { + return MessageType(parseEnum(s, namesMessageType[:])) +} + +func (e FileChangeType) Format(f fmt.State, c rune) { + formatEnum(f, c, int(e), namesFileChangeType[:], "FileChangeType") +} + +func ParseFileChangeType(s string) FileChangeType { + return FileChangeType(parseEnum(s, namesFileChangeType[:])) +} + +func (e WatchKind) Format(f fmt.State, c rune) { + formatEnum(f, c, int(e), namesWatchKind[:], "WatchKind") +} + +func ParseWatchKind(s string) WatchKind { + return WatchKind(parseEnum(s, namesWatchKind[:])) +} + +func (e CompletionTriggerKind) Format(f fmt.State, c rune) { + formatEnum(f, c, int(e), namesCompletionTriggerKind[:], "CompletionTriggerKind") +} + +func ParseCompletionTriggerKind(s string) CompletionTriggerKind { + return CompletionTriggerKind(parseEnum(s, namesCompletionTriggerKind[:])) +} + +func (e DiagnosticSeverity) Format(f fmt.State, c rune) { + formatEnum(f, c, int(e), namesDiagnosticSeverity[:], "DiagnosticSeverity") +} + +func ParseDiagnosticSeverity(s string) DiagnosticSeverity { + return DiagnosticSeverity(parseEnum(s, namesDiagnosticSeverity[:])) +} + +func (e DiagnosticTag) Format(f fmt.State, c rune) { + formatEnum(f, c, int(e), namesDiagnosticTag[:], "DiagnosticTag") +} + +func ParseDiagnosticTag(s string) DiagnosticTag { + return DiagnosticTag(parseEnum(s, namesDiagnosticTag[:])) +} + +func (e CompletionItemKind) Format(f fmt.State, c rune) { + formatEnum(f, c, int(e), namesCompletionItemKind[:], "CompletionItemKind") +} + +func ParseCompletionItemKind(s string) CompletionItemKind { + return CompletionItemKind(parseEnum(s, namesCompletionItemKind[:])) +} + +func (e InsertTextFormat) Format(f fmt.State, c rune) { + formatEnum(f, c, int(e), namesInsertTextFormat[:], "InsertTextFormat") +} + +func ParseInsertTextFormat(s string) InsertTextFormat { + return InsertTextFormat(parseEnum(s, namesInsertTextFormat[:])) +} + +func (e DocumentHighlightKind) Format(f fmt.State, c rune) { + formatEnum(f, c, int(e), namesDocumentHighlightKind[:], "DocumentHighlightKind") +} + +func ParseDocumentHighlightKind(s string) DocumentHighlightKind { + return DocumentHighlightKind(parseEnum(s, namesDocumentHighlightKind[:])) +} + +func (e SymbolKind) Format(f fmt.State, c rune) { + formatEnum(f, c, int(e), namesSymbolKind[:], "SymbolKind") +} + +func ParseSymbolKind(s string) SymbolKind { + return SymbolKind(parseEnum(s, namesSymbolKind[:])) +} + +func (e TextDocumentSaveReason) Format(f fmt.State, c rune) { + formatEnum(f, c, int(e), namesTextDocumentSaveReason[:], "TextDocumentSaveReason") +} + +func ParseTextDocumentSaveReason(s string) TextDocumentSaveReason { + return TextDocumentSaveReason(parseEnum(s, namesTextDocumentSaveReason[:])) +} diff --git a/third_party/spirv-tools/utils/vscode/src/lsp/protocol/log.go b/third_party/spirv-tools/utils/vscode/src/lsp/protocol/log.go new file mode 100644 index 0000000000..f245881e18 --- /dev/null +++ b/third_party/spirv-tools/utils/vscode/src/lsp/protocol/log.go @@ -0,0 +1,258 @@ +// Copyright 2018 The Go Authors. +// +// 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. + +package protocol + +import ( + "context" + "encoding/json" + "fmt" + "io" + "strings" + "sync" + "time" + + "../jsonrpc2" +) + +type loggingStream struct { + stream jsonrpc2.Stream + log io.Writer +} + +// LoggingStream returns a stream that does LSP protocol logging too +func LoggingStream(str jsonrpc2.Stream, w io.Writer) jsonrpc2.Stream { + return &loggingStream{str, w} +} + +func (s *loggingStream) Read(ctx context.Context) ([]byte, int64, error) { + data, count, err := s.stream.Read(ctx) + if err == nil { + logIn(s.log, data) + } + return data, count, err +} + +func (s *loggingStream) Write(ctx context.Context, data []byte) (int64, error) { + logOut(s.log, data) + count, err := s.stream.Write(ctx, data) + return count, err +} + +// Combined has all the fields of both Request and Response. +// We can decode this and then work out which it is. +type Combined struct { + VersionTag jsonrpc2.VersionTag `json:"jsonrpc"` + ID *jsonrpc2.ID `json:"id,omitempty"` + Method string `json:"method"` + Params *json.RawMessage `json:"params,omitempty"` + Result *json.RawMessage `json:"result,omitempty"` + Error *jsonrpc2.Error `json:"error,omitempty"` +} + +type req struct { + method string + start time.Time +} + +type mapped struct { + mu sync.Mutex + clientCalls map[string]req + serverCalls map[string]req +} + +var maps = &mapped{ + sync.Mutex{}, + make(map[string]req), + make(map[string]req), +} + +// these 4 methods are each used exactly once, but it seemed +// better to have the encapsulation rather than ad hoc mutex +// code in 4 places +func (m *mapped) client(id string, del bool) req { + m.mu.Lock() + defer m.mu.Unlock() + v := m.clientCalls[id] + if del { + delete(m.clientCalls, id) + } + return v +} + +func (m *mapped) server(id string, del bool) req { + m.mu.Lock() + defer m.mu.Unlock() + v := m.serverCalls[id] + if del { + delete(m.serverCalls, id) + } + return v +} + +func (m *mapped) setClient(id string, r req) { + m.mu.Lock() + defer m.mu.Unlock() + m.clientCalls[id] = r +} + +func (m *mapped) setServer(id string, r req) { + m.mu.Lock() + defer m.mu.Unlock() + m.serverCalls[id] = r +} + +const eor = "\r\n\r\n\r\n" + +func strID(x *jsonrpc2.ID) string { + if x == nil { + // should never happen, but we need a number + return "999999999" + } + if x.Name != "" { + return x.Name + } + return fmt.Sprintf("%d", x.Number) +} + +func logCommon(outfd io.Writer, data []byte) (*Combined, time.Time, string) { + if outfd == nil { + return nil, time.Time{}, "" + } + var v Combined + err := json.Unmarshal(data, &v) + if err != nil { + fmt.Fprintf(outfd, "Unmarshal %v\n", err) + panic(err) // do better + } + tm := time.Now() + tmfmt := tm.Format("15:04:05.000 PM") + return &v, tm, tmfmt +} + +// logOut and logIn could be combined. "received"<->"Sending", serverCalls<->clientCalls +// but it wouldn't be a lot shorter or clearer and "shutdown" is a special case + +// Writing a message to the client, log it +func logOut(outfd io.Writer, data []byte) { + v, tm, tmfmt := logCommon(outfd, data) + if v == nil { + return + } + if v.Error != nil { + id := strID(v.ID) + fmt.Fprintf(outfd, "[Error - %s] Received #%s %s%s", tmfmt, id, v.Error, eor) + return + } + buf := strings.Builder{} + id := strID(v.ID) + fmt.Fprintf(&buf, "[Trace - %s] ", tmfmt) // common beginning + if v.ID != nil && v.Method != "" && v.Params != nil { + fmt.Fprintf(&buf, "Received request '%s - (%s)'.\n", v.Method, id) + fmt.Fprintf(&buf, "Params: %s%s", *v.Params, eor) + maps.setServer(id, req{method: v.Method, start: tm}) + } else if v.ID != nil && v.Method == "" && v.Params == nil { + cc := maps.client(id, true) + elapsed := tm.Sub(cc.start) + fmt.Fprintf(&buf, "Received response '%s - (%s)' in %dms.\n", + cc.method, id, elapsed/time.Millisecond) + if v.Result == nil { + fmt.Fprintf(&buf, "Result: {}%s", eor) + } else { + fmt.Fprintf(&buf, "Result: %s%s", string(*v.Result), eor) + } + } else if v.ID == nil && v.Method != "" && v.Params != nil { + p := "null" + if v.Params != nil { + p = string(*v.Params) + } + fmt.Fprintf(&buf, "Received notification '%s'.\n", v.Method) + fmt.Fprintf(&buf, "Params: %s%s", p, eor) + } else { // for completeness, as it should never happen + buf = strings.Builder{} // undo common Trace + fmt.Fprintf(&buf, "[Error - %s] on write ID?%v method:%q Params:%v Result:%v Error:%v%s", + tmfmt, v.ID != nil, v.Method, v.Params != nil, + v.Result != nil, v.Error != nil, eor) + p := "null" + if v.Params != nil { + p = string(*v.Params) + } + r := "null" + if v.Result != nil { + r = string(*v.Result) + } + fmt.Fprintf(&buf, "%s\n%s\n%s%s", p, r, v.Error, eor) + } + outfd.Write([]byte(buf.String())) +} + +// Got a message from the client, log it +func logIn(outfd io.Writer, data []byte) { + v, tm, tmfmt := logCommon(outfd, data) + if v == nil { + return + } + // ID Method Params => Sending request + // ID !Method Result(might be null, but !Params) => Sending response (could we get an Error?) + // !ID Method Params => Sending notification + if v.Error != nil { // does this ever happen? + id := strID(v.ID) + fmt.Fprintf(outfd, "[Error - %s] Sent #%s %s%s", tmfmt, id, v.Error, eor) + return + } + buf := strings.Builder{} + id := strID(v.ID) + fmt.Fprintf(&buf, "[Trace - %s] ", tmfmt) // common beginning + if v.ID != nil && v.Method != "" && (v.Params != nil || v.Method == "shutdown") { + fmt.Fprintf(&buf, "Sending request '%s - (%s)'.\n", v.Method, id) + x := "{}" + if v.Params != nil { + x = string(*v.Params) + } + fmt.Fprintf(&buf, "Params: %s%s", x, eor) + maps.setClient(id, req{method: v.Method, start: tm}) + } else if v.ID != nil && v.Method == "" && v.Params == nil { + sc := maps.server(id, true) + elapsed := tm.Sub(sc.start) + fmt.Fprintf(&buf, "Sending response '%s - (%s)' took %dms.\n", + sc.method, id, elapsed/time.Millisecond) + if v.Result == nil { + fmt.Fprintf(&buf, "Result: {}%s", eor) + } else { + fmt.Fprintf(&buf, "Result: %s%s", string(*v.Result), eor) + } + } else if v.ID == nil && v.Method != "" { + p := "null" + if v.Params != nil { + p = string(*v.Params) + } + fmt.Fprintf(&buf, "Sending notification '%s'.\n", v.Method) + fmt.Fprintf(&buf, "Params: %s%s", p, eor) + } else { // for completeness, as it should never happen + buf = strings.Builder{} // undo common Trace + fmt.Fprintf(&buf, "[Error - %s] on read ID?%v method:%q Params:%v Result:%v Error:%v%s", + tmfmt, v.ID != nil, v.Method, v.Params != nil, + v.Result != nil, v.Error != nil, eor) + p := "null" + if v.Params != nil { + p = string(*v.Params) + } + r := "null" + if v.Result != nil { + r = string(*v.Result) + } + fmt.Fprintf(&buf, "%s\n%s\n%s%s", p, r, v.Error, eor) + } + outfd.Write([]byte(buf.String())) +} diff --git a/third_party/spirv-tools/utils/vscode/src/lsp/protocol/protocol.go b/third_party/spirv-tools/utils/vscode/src/lsp/protocol/protocol.go new file mode 100644 index 0000000000..e396c8325e --- /dev/null +++ b/third_party/spirv-tools/utils/vscode/src/lsp/protocol/protocol.go @@ -0,0 +1,86 @@ +// Copyright 2018 The Go Authors. +// +// 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. + +package protocol + +import ( + "context" + "encoding/json" + "log" + + "../jsonrpc2" +) + +const ( + // RequestCancelledError should be used when a request is cancelled early. + RequestCancelledError = -32800 +) + +type DocumentUri = string + +type canceller struct{ jsonrpc2.EmptyHandler } + +type clientHandler struct { + canceller + client Client +} + +type serverHandler struct { + canceller + server Server +} + +func (canceller) Request(ctx context.Context, conn *jsonrpc2.Conn, direction jsonrpc2.Direction, r *jsonrpc2.WireRequest) context.Context { + if direction == jsonrpc2.Receive && r.Method == "$/cancelRequest" { + var params CancelParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + log.Printf("%v", err) + } else { + conn.Cancel(params.ID) + } + } + return ctx +} + +func (canceller) Cancel(ctx context.Context, conn *jsonrpc2.Conn, id jsonrpc2.ID, cancelled bool) bool { + if cancelled { + return false + } + conn.Notify(ctx, "$/cancelRequest", &CancelParams{ID: id}) + return true +} + +func NewClient(ctx context.Context, stream jsonrpc2.Stream, client Client) (context.Context, *jsonrpc2.Conn, Server) { + ctx = WithClient(ctx, client) + conn := jsonrpc2.NewConn(stream) + conn.AddHandler(&clientHandler{client: client}) + return ctx, conn, &serverDispatcher{Conn: conn} +} + +func NewServer(ctx context.Context, stream jsonrpc2.Stream, server Server) (context.Context, *jsonrpc2.Conn, Client) { + conn := jsonrpc2.NewConn(stream) + client := &clientDispatcher{Conn: conn} + ctx = WithClient(ctx, client) + conn.AddHandler(&serverHandler{server: server}) + return ctx, conn, client +} + +func sendParseError(ctx context.Context, req *jsonrpc2.Request, err error) { + if _, ok := err.(*jsonrpc2.Error); !ok { + err = jsonrpc2.NewErrorf(jsonrpc2.CodeParseError, "%v", err) + } + if err := req.Reply(ctx, nil, err); err != nil { + log.Printf("%v", err) + } +} diff --git a/third_party/spirv-tools/utils/vscode/src/lsp/protocol/span.go b/third_party/spirv-tools/utils/vscode/src/lsp/protocol/span.go new file mode 100644 index 0000000000..33cc2a651b --- /dev/null +++ b/third_party/spirv-tools/utils/vscode/src/lsp/protocol/span.go @@ -0,0 +1,137 @@ +// Copyright 2018 The Go Authors. +// +// 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. + +// this file contains protocol<->span converters + +package protocol + +import ( + "fmt" + + "../span" + errors "golang.org/x/xerrors" +) + +type ColumnMapper struct { + URI span.URI + Converter *span.TokenConverter + Content []byte +} + +func NewURI(uri span.URI) string { + return string(uri) +} + +func (m *ColumnMapper) Location(s span.Span) (Location, error) { + rng, err := m.Range(s) + if err != nil { + return Location{}, err + } + return Location{URI: NewURI(s.URI()), Range: rng}, nil +} + +func (m *ColumnMapper) Range(s span.Span) (Range, error) { + if span.CompareURI(m.URI, s.URI()) != 0 { + return Range{}, errors.Errorf("column mapper is for file %q instead of %q", m.URI, s.URI()) + } + s, err := s.WithAll(m.Converter) + if err != nil { + return Range{}, err + } + start, err := m.Position(s.Start()) + if err != nil { + return Range{}, err + } + end, err := m.Position(s.End()) + if err != nil { + return Range{}, err + } + return Range{Start: start, End: end}, nil +} + +func (m *ColumnMapper) Position(p span.Point) (Position, error) { + chr, err := span.ToUTF16Column(p, m.Content) + if err != nil { + return Position{}, err + } + return Position{ + Line: float64(p.Line() - 1), + Character: float64(chr - 1), + }, nil +} + +func (m *ColumnMapper) Span(l Location) (span.Span, error) { + return m.RangeSpan(l.Range) +} + +func (m *ColumnMapper) RangeSpan(r Range) (span.Span, error) { + start, err := m.Point(r.Start) + if err != nil { + return span.Span{}, err + } + end, err := m.Point(r.End) + if err != nil { + return span.Span{}, err + } + return span.New(m.URI, start, end).WithAll(m.Converter) +} + +func (m *ColumnMapper) PointSpan(p Position) (span.Span, error) { + start, err := m.Point(p) + if err != nil { + return span.Span{}, err + } + return span.New(m.URI, start, start).WithAll(m.Converter) +} + +func (m *ColumnMapper) Point(p Position) (span.Point, error) { + line := int(p.Line) + 1 + offset, err := m.Converter.ToOffset(line, 1) + if err != nil { + return span.Point{}, err + } + lineStart := span.NewPoint(line, 1, offset) + return span.FromUTF16Column(lineStart, int(p.Character)+1, m.Content) +} + +func IsPoint(r Range) bool { + return r.Start.Line == r.End.Line && r.Start.Character == r.End.Character +} + +func CompareRange(a, b Range) int { + if r := ComparePosition(a.Start, b.Start); r != 0 { + return r + } + return ComparePosition(a.End, b.End) +} + +func ComparePosition(a, b Position) int { + if a.Line < b.Line { + return -1 + } + if a.Line > b.Line { + return 1 + } + if a.Character < b.Character { + return -1 + } + if a.Character > b.Character { + return 1 + } + return 0 +} + +func (r Range) Format(f fmt.State, _ rune) { + fmt.Fprintf(f, "%v:%v-%v:%v", r.Start.Line, r.Start.Character, r.End.Line, r.End.Character) +} diff --git a/third_party/spirv-tools/utils/vscode/src/lsp/protocol/tsclient.go b/third_party/spirv-tools/utils/vscode/src/lsp/protocol/tsclient.go new file mode 100644 index 0000000000..2f9beef46a --- /dev/null +++ b/third_party/spirv-tools/utils/vscode/src/lsp/protocol/tsclient.go @@ -0,0 +1,221 @@ +// Copyright 2019 The Go Authors. +// +// 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. + +package protocol + +import ( + "context" + "encoding/json" + "log" + + "../jsonrpc2" +) + +type Client interface { + ShowMessage(context.Context, *ShowMessageParams) error + LogMessage(context.Context, *LogMessageParams) error + Event(context.Context, *interface{}) error + PublishDiagnostics(context.Context, *PublishDiagnosticsParams) error + WorkspaceFolders(context.Context) ([]WorkspaceFolder, error) + Configuration(context.Context, *ParamConfig) ([]interface{}, error) + RegisterCapability(context.Context, *RegistrationParams) error + UnregisterCapability(context.Context, *UnregistrationParams) error + ShowMessageRequest(context.Context, *ShowMessageRequestParams) (*MessageActionItem, error) + ApplyEdit(context.Context, *ApplyWorkspaceEditParams) (*ApplyWorkspaceEditResponse, error) +} + +func (h clientHandler) Deliver(ctx context.Context, r *jsonrpc2.Request, delivered bool) bool { + if delivered { + return false + } + if ctx.Err() != nil { + r.Reply(ctx, nil, jsonrpc2.NewErrorf(RequestCancelledError, "")) + return true + } + switch r.Method { + case "window/showMessage": // notif + var params ShowMessageParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + sendParseError(ctx, r, err) + return true + } + if err := h.client.ShowMessage(ctx, ¶ms); err != nil { + log.Printf("%v", err) + } + return true + case "window/logMessage": // notif + var params LogMessageParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + sendParseError(ctx, r, err) + return true + } + if err := h.client.LogMessage(ctx, ¶ms); err != nil { + log.Printf("%v", err) + } + return true + case "telemetry/event": // notif + var params interface{} + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + sendParseError(ctx, r, err) + return true + } + if err := h.client.Event(ctx, ¶ms); err != nil { + log.Printf("%v", err) + } + return true + case "textDocument/publishDiagnostics": // notif + var params PublishDiagnosticsParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + sendParseError(ctx, r, err) + return true + } + if err := h.client.PublishDiagnostics(ctx, ¶ms); err != nil { + log.Printf("%v", err) + } + return true + case "workspace/workspaceFolders": // req + if r.Params != nil { + r.Reply(ctx, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeInvalidParams, "Expected no params")) + return true + } + resp, err := h.client.WorkspaceFolders(ctx) + if err := r.Reply(ctx, resp, err); err != nil { + log.Printf("%v", err) + } + return true + case "workspace/configuration": // req + var params ParamConfig + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + sendParseError(ctx, r, err) + return true + } + resp, err := h.client.Configuration(ctx, ¶ms) + if err := r.Reply(ctx, resp, err); err != nil { + log.Printf("%v", err) + } + return true + case "client/registerCapability": // req + var params RegistrationParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + sendParseError(ctx, r, err) + return true + } + err := h.client.RegisterCapability(ctx, ¶ms) + if err := r.Reply(ctx, nil, err); err != nil { + log.Printf("%v", err) + } + return true + case "client/unregisterCapability": // req + var params UnregistrationParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + sendParseError(ctx, r, err) + return true + } + err := h.client.UnregisterCapability(ctx, ¶ms) + if err := r.Reply(ctx, nil, err); err != nil { + log.Printf("%v", err) + } + return true + case "window/showMessageRequest": // req + var params ShowMessageRequestParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + sendParseError(ctx, r, err) + return true + } + resp, err := h.client.ShowMessageRequest(ctx, ¶ms) + if err := r.Reply(ctx, resp, err); err != nil { + log.Printf("%v", err) + } + return true + case "workspace/applyEdit": // req + var params ApplyWorkspaceEditParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + sendParseError(ctx, r, err) + return true + } + resp, err := h.client.ApplyEdit(ctx, ¶ms) + if err := r.Reply(ctx, resp, err); err != nil { + log.Printf("%v", err) + } + return true + + default: + return false + } +} + +type clientDispatcher struct { + *jsonrpc2.Conn +} + +func (s *clientDispatcher) ShowMessage(ctx context.Context, params *ShowMessageParams) error { + return s.Conn.Notify(ctx, "window/showMessage", params) +} + +func (s *clientDispatcher) LogMessage(ctx context.Context, params *LogMessageParams) error { + return s.Conn.Notify(ctx, "window/logMessage", params) +} + +func (s *clientDispatcher) Event(ctx context.Context, params *interface{}) error { + return s.Conn.Notify(ctx, "telemetry/event", params) +} + +func (s *clientDispatcher) PublishDiagnostics(ctx context.Context, params *PublishDiagnosticsParams) error { + return s.Conn.Notify(ctx, "textDocument/publishDiagnostics", params) +} +func (s *clientDispatcher) WorkspaceFolders(ctx context.Context) ([]WorkspaceFolder, error) { + var result []WorkspaceFolder + if err := s.Conn.Call(ctx, "workspace/workspaceFolders", nil, &result); err != nil { + return nil, err + } + return result, nil +} + +func (s *clientDispatcher) Configuration(ctx context.Context, params *ParamConfig) ([]interface{}, error) { + var result []interface{} + if err := s.Conn.Call(ctx, "workspace/configuration", params, &result); err != nil { + return nil, err + } + return result, nil +} + +func (s *clientDispatcher) RegisterCapability(ctx context.Context, params *RegistrationParams) error { + return s.Conn.Call(ctx, "client/registerCapability", params, nil) // Call, not Notify +} + +func (s *clientDispatcher) UnregisterCapability(ctx context.Context, params *UnregistrationParams) error { + return s.Conn.Call(ctx, "client/unregisterCapability", params, nil) // Call, not Notify +} + +func (s *clientDispatcher) ShowMessageRequest(ctx context.Context, params *ShowMessageRequestParams) (*MessageActionItem, error) { + var result MessageActionItem + if err := s.Conn.Call(ctx, "window/showMessageRequest", params, &result); err != nil { + return nil, err + } + return &result, nil +} + +func (s *clientDispatcher) ApplyEdit(ctx context.Context, params *ApplyWorkspaceEditParams) (*ApplyWorkspaceEditResponse, error) { + var result ApplyWorkspaceEditResponse + if err := s.Conn.Call(ctx, "workspace/applyEdit", params, &result); err != nil { + return nil, err + } + return &result, nil +} + +// Types constructed to avoid structs as formal argument types +type ParamConfig struct { + ConfigurationParams + PartialResultParams +} diff --git a/third_party/spirv-tools/utils/vscode/src/lsp/protocol/tsprotocol.go b/third_party/spirv-tools/utils/vscode/src/lsp/protocol/tsprotocol.go new file mode 100644 index 0000000000..50543fc819 --- /dev/null +++ b/third_party/spirv-tools/utils/vscode/src/lsp/protocol/tsprotocol.go @@ -0,0 +1,4630 @@ +// Copyright 2019 The Go Authors. +// +// 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. + +// Package protocol contains data types and code for LSP jsonrpcs +// generated automatically from vscode-languageserver-node +// commit: 36ac51f057215e6e2e0408384e07ecf564a938da +// last fetched Tue Sep 24 2019 17:44:28 GMT-0400 (Eastern Daylight Time) +package protocol + +// Code generated (see typescript/README.md) DO NOT EDIT. + +/*ImplementationClientCapabilities defined: + * Since 3.6.0 + */ +type ImplementationClientCapabilities struct { + + /*DynamicRegistration defined: + * Whether implementation supports dynamic registration. If this is set to `true` + * the client supports the new `ImplementationRegistrationOptions` return value + * for the corresponding server capability as well. + */ + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` + + /*LinkSupport defined: + * The client supports additional metadata in the form of definition links. + * + * Since 3.14.0 + */ + LinkSupport bool `json:"linkSupport,omitempty"` +} + +// ImplementationOptions is +type ImplementationOptions struct { + WorkDoneProgressOptions +} + +// ImplementationRegistrationOptions is +type ImplementationRegistrationOptions struct { + TextDocumentRegistrationOptions + ImplementationOptions + StaticRegistrationOptions +} + +// ImplementationParams is +type ImplementationParams struct { + TextDocumentPositionParams + WorkDoneProgressParams + PartialResultParams +} + +/*TypeDefinitionClientCapabilities defined: + * Since 3.6.0 + */ +type TypeDefinitionClientCapabilities struct { + + /*DynamicRegistration defined: + * Whether implementation supports dynamic registration. If this is set to `true` + * the client supports the new `TypeDefinitionRegistrationOptions` return value + * for the corresponding server capability as well. + */ + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` + + /*LinkSupport defined: + * The client supports additional metadata in the form of definition links. + * + * Since 3.14.0 + */ + LinkSupport bool `json:"linkSupport,omitempty"` +} + +// TypeDefinitionOptions is +type TypeDefinitionOptions struct { + WorkDoneProgressOptions +} + +// TypeDefinitionRegistrationOptions is +type TypeDefinitionRegistrationOptions struct { + TextDocumentRegistrationOptions + TypeDefinitionOptions + StaticRegistrationOptions +} + +// TypeDefinitionParams is +type TypeDefinitionParams struct { + TextDocumentPositionParams + WorkDoneProgressParams + PartialResultParams +} + +// WorkspaceFoldersInitializeParams is +type WorkspaceFoldersInitializeParams struct { + + /*WorkspaceFolders defined: + * The actual configured workspace folders. + */ + WorkspaceFolders []WorkspaceFolder `json:"workspaceFolders"` +} + +// WorkspaceFoldersClientCapabilities is +type WorkspaceFoldersClientCapabilities struct { + + /*Workspace defined: + * The workspace client capabilities + */ + Workspace *struct { + + /*WorkspaceFolders defined: + * The client has support for workspace folders + */ + WorkspaceFolders bool `json:"workspaceFolders,omitempty"` + } `json:"workspace,omitempty"` +} + +// WorkspaceFoldersServerCapabilities is +type WorkspaceFoldersServerCapabilities struct { + + /*Workspace defined: + * The workspace server capabilities + */ + Workspace *struct { + + // WorkspaceFolders is + WorkspaceFolders *struct { + + /*Supported defined: + * The Server has support for workspace folders + */ + Supported bool `json:"supported,omitempty"` + + /*ChangeNotifications defined: + * Whether the server wants to receive workspace folder + * change notifications. + * + * If a strings is provided the string is treated as a ID + * under which the notification is registed on the client + * side. The ID can be used to unregister for these events + * using the `client/unregisterCapability` request. + */ + ChangeNotifications string `json:"changeNotifications,omitempty"` // string | boolean + } `json:"workspaceFolders,omitempty"` + } `json:"workspace,omitempty"` +} + +// WorkspaceFolder is +type WorkspaceFolder struct { + + /*URI defined: + * The associated URI for this workspace folder. + */ + URI string `json:"uri"` + + /*Name defined: + * The name of the workspace folder. Used to refer to this + * workspace folder in thge user interface. + */ + Name string `json:"name"` +} + +/*DidChangeWorkspaceFoldersParams defined: + * The parameters of a `workspace/didChangeWorkspaceFolders` notification. + */ +type DidChangeWorkspaceFoldersParams struct { + + /*Event defined: + * The actual workspace folder change event. + */ + Event WorkspaceFoldersChangeEvent `json:"event"` +} + +/*WorkspaceFoldersChangeEvent defined: + * The workspace folder change event. + */ +type WorkspaceFoldersChangeEvent struct { + + /*Added defined: + * The array of added workspace folders + */ + Added []WorkspaceFolder `json:"added"` + + /*Removed defined: + * The array of the removed workspace folders + */ + Removed []WorkspaceFolder `json:"removed"` +} + +// ConfigurationClientCapabilities is +type ConfigurationClientCapabilities struct { + + /*Workspace defined: + * The workspace client capabilities + */ + Workspace *struct { + + /*Configuration defined: + * The client supports `workspace/configuration` requests. + */ + Configuration bool `json:"configuration,omitempty"` + } `json:"workspace,omitempty"` +} + +// ConfigurationItem is +type ConfigurationItem struct { + + /*ScopeURI defined: + * The scope to get the configuration section for. + */ + ScopeURI string `json:"scopeUri,omitempty"` + + /*Section defined: + * The configuration section asked for. + */ + Section string `json:"section,omitempty"` +} + +/*ConfigurationParams defined: + * The parameters of a configuration request. + */ +type ConfigurationParams struct { + + // Items is + Items []ConfigurationItem `json:"items"` +} + +// DocumentColorClientCapabilities is +type DocumentColorClientCapabilities struct { + + /*DynamicRegistration defined: + * Whether implementation supports dynamic registration. If this is set to `true` + * the client supports the new `DocumentColorRegistrationOptions` return value + * for the corresponding server capability as well. + */ + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` +} + +// DocumentColorOptions is +type DocumentColorOptions struct { + + /*ResolveProvider defined: + * Code lens has a resolve provider as well. + */ + ResolveProvider bool `json:"resolveProvider,omitempty"` + WorkDoneProgressOptions +} + +// DocumentColorRegistrationOptions is +type DocumentColorRegistrationOptions struct { + TextDocumentRegistrationOptions + StaticRegistrationOptions + DocumentColorOptions +} + +/*DocumentColorParams defined: + * Parameters for a [DocumentColorRequest](#DocumentColorRequest). + */ +type DocumentColorParams struct { + + /*TextDocument defined: + * The text document. + */ + TextDocument TextDocumentIdentifier `json:"textDocument"` + WorkDoneProgressParams + PartialResultParams +} + +/*ColorPresentationParams defined: + * Parameters for a [ColorPresentationRequest](#ColorPresentationRequest). + */ +type ColorPresentationParams struct { + + /*TextDocument defined: + * The text document. + */ + TextDocument TextDocumentIdentifier `json:"textDocument"` + + /*Color defined: + * The color to request presentations for. + */ + Color Color `json:"color"` + + /*Range defined: + * The range where the color would be inserted. Serves as a context. + */ + Range Range `json:"range"` + WorkDoneProgressParams + PartialResultParams +} + +// FoldingRangeClientCapabilities is +type FoldingRangeClientCapabilities struct { + + /*DynamicRegistration defined: + * Whether implementation supports dynamic registration for folding range providers. If this is set to `true` + * the client supports the new `FoldingRangeRegistrationOptions` return value for the corresponding server + * capability as well. + */ + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` + + /*RangeLimit defined: + * The maximum number of folding ranges that the client prefers to receive per document. The value serves as a + * hint, servers are free to follow the limit. + */ + RangeLimit float64 `json:"rangeLimit,omitempty"` + + /*LineFoldingOnly defined: + * If set, the client signals that it only supports folding complete lines. If set, client will + * ignore specified `startCharacter` and `endCharacter` properties in a FoldingRange. + */ + LineFoldingOnly bool `json:"lineFoldingOnly,omitempty"` +} + +// FoldingRangeOptions is +type FoldingRangeOptions struct { + WorkDoneProgressOptions +} + +// FoldingRangeRegistrationOptions is +type FoldingRangeRegistrationOptions struct { + TextDocumentRegistrationOptions + FoldingRangeOptions + StaticRegistrationOptions +} + +/*FoldingRange defined: + * Represents a folding range. + */ +type FoldingRange struct { + + /*StartLine defined: + * The zero-based line number from where the folded range starts. + */ + StartLine float64 `json:"startLine"` + + /*StartCharacter defined: + * The zero-based character offset from where the folded range starts. If not defined, defaults to the length of the start line. + */ + StartCharacter float64 `json:"startCharacter,omitempty"` + + /*EndLine defined: + * The zero-based line number where the folded range ends. + */ + EndLine float64 `json:"endLine"` + + /*EndCharacter defined: + * The zero-based character offset before the folded range ends. If not defined, defaults to the length of the end line. + */ + EndCharacter float64 `json:"endCharacter,omitempty"` + + /*Kind defined: + * Describes the kind of the folding range such as `comment' or 'region'. The kind + * is used to categorize folding ranges and used by commands like 'Fold all comments'. See + * [FoldingRangeKind](#FoldingRangeKind) for an enumeration of standardized kinds. + */ + Kind string `json:"kind,omitempty"` +} + +/*FoldingRangeParams defined: + * Parameters for a [FoldingRangeRequest](#FoldingRangeRequest). + */ +type FoldingRangeParams struct { + + /*TextDocument defined: + * The text document. + */ + TextDocument TextDocumentIdentifier `json:"textDocument"` + WorkDoneProgressParams + PartialResultParams +} + +/*DeclarationClientCapabilities defined: + * Since 3.14.0 + */ +type DeclarationClientCapabilities struct { + + /*DynamicRegistration defined: + * Whether declaration supports dynamic registration. If this is set to `true` + * the client supports the new `DeclarationRegistrationOptions` return value + * for the corresponding server capability as well. + */ + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` + + /*LinkSupport defined: + * The client supports additional metadata in the form of declaration links. + */ + LinkSupport bool `json:"linkSupport,omitempty"` +} + +// DeclarationOptions is +type DeclarationOptions struct { + WorkDoneProgressOptions +} + +// DeclarationRegistrationOptions is +type DeclarationRegistrationOptions struct { + DeclarationOptions + TextDocumentRegistrationOptions + StaticRegistrationOptions +} + +// DeclarationParams is +type DeclarationParams struct { + TextDocumentPositionParams + WorkDoneProgressParams + PartialResultParams +} + +// SelectionRangeClientCapabilities is +type SelectionRangeClientCapabilities struct { + + /*DynamicRegistration defined: + * Whether implementation supports dynamic registration for selection range providers. If this is set to `true` + * the client supports the new `SelectionRangeRegistrationOptions` return value for the corresponding server + * capability as well. + */ + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` +} + +// SelectionRangeOptions is +type SelectionRangeOptions struct { + WorkDoneProgressOptions +} + +// SelectionRangeRegistrationOptions is +type SelectionRangeRegistrationOptions struct { + SelectionRangeOptions + TextDocumentRegistrationOptions + StaticRegistrationOptions +} + +/*SelectionRangeParams defined: + * A parameter literal used in selection range requests. + */ +type SelectionRangeParams struct { + + /*TextDocument defined: + * The text document. + */ + TextDocument TextDocumentIdentifier `json:"textDocument"` + + /*Positions defined: + * The positions inside the text document. + */ + Positions []Position `json:"positions"` + WorkDoneProgressParams + PartialResultParams +} + +/*Registration defined: + * General parameters to to register for an notification or to register a provider. + */ +type Registration struct { + + /*ID defined: + * The id used to register the request. The id can be used to deregister + * the request again. + */ + ID string `json:"id"` + + /*Method defined: + * The method to register for. + */ + Method string `json:"method"` + + /*RegisterOptions defined: + * Options necessary for the registration. + */ + RegisterOptions interface{} `json:"registerOptions,omitempty"` +} + +// RegistrationParams is +type RegistrationParams struct { + + // Registrations is + Registrations []Registration `json:"registrations"` +} + +/*Unregistration defined: + * General parameters to unregister a request or notification. + */ +type Unregistration struct { + + /*ID defined: + * The id used to unregister the request or notification. Usually an id + * provided during the register request. + */ + ID string `json:"id"` + + /*Method defined: + * The method to unregister for. + */ + Method string `json:"method"` +} + +// UnregistrationParams is +type UnregistrationParams struct { + + // Unregisterations is + Unregisterations []Unregistration `json:"unregisterations"` +} + +// WorkDoneProgressParams is +type WorkDoneProgressParams struct { + + /*WorkDoneToken defined: + * An optional token that a server can use to report work done progress. + */ + WorkDoneToken *ProgressToken `json:"workDoneToken,omitempty"` +} + +// PartialResultParams is +type PartialResultParams struct { + + /*PartialResultToken defined: + * An optional token that a server can use to report partial results (e.g. streaming) to + * the client. + */ + PartialResultToken *ProgressToken `json:"partialResultToken,omitempty"` +} + +/*TextDocumentPositionParams defined: + * A parameter literal used in requests to pass a text document and a position inside that + * document. + */ +type TextDocumentPositionParams struct { + + /*TextDocument defined: + * The text document. + */ + TextDocument TextDocumentIdentifier `json:"textDocument"` + + /*Position defined: + * The position inside the text document. + */ + Position Position `json:"position"` +} + +/*WorkspaceClientCapabilities defined: + * Workspace specific client capabilities. + */ +type WorkspaceClientCapabilities struct { + + /*ApplyEdit defined: + * The client supports applying batch edits + * to the workspace by supporting the request + * 'workspace/applyEdit' + */ + ApplyEdit bool `json:"applyEdit,omitempty"` + + /*WorkspaceEdit defined: + * Capabilities specific to `WorkspaceEdit`s + */ + WorkspaceEdit *WorkspaceEditClientCapabilities `json:"workspaceEdit,omitempty"` + + /*DidChangeConfiguration defined: + * Capabilities specific to the `workspace/didChangeConfiguration` notification. + */ + DidChangeConfiguration *DidChangeConfigurationClientCapabilities `json:"didChangeConfiguration,omitempty"` + + /*DidChangeWatchedFiles defined: + * Capabilities specific to the `workspace/didChangeWatchedFiles` notification. + */ + DidChangeWatchedFiles *DidChangeWatchedFilesClientCapabilities `json:"didChangeWatchedFiles,omitempty"` + + /*Symbol defined: + * Capabilities specific to the `workspace/symbol` request. + */ + Symbol *WorkspaceSymbolClientCapabilities `json:"symbol,omitempty"` + + /*ExecuteCommand defined: + * Capabilities specific to the `workspace/executeCommand` request. + */ + ExecuteCommand *ExecuteCommandClientCapabilities `json:"executeCommand,omitempty"` +} + +/*TextDocumentClientCapabilities defined: + * Text document specific client capabilities. + */ +type TextDocumentClientCapabilities struct { + + /*Synchronization defined: + * Defines which synchronization capabilities the client supports. + */ + Synchronization *TextDocumentSyncClientCapabilities `json:"synchronization,omitempty"` + + /*Completion defined: + * Capabilities specific to the `textDocument/completion` + */ + Completion *CompletionClientCapabilities `json:"completion,omitempty"` + + /*Hover defined: + * Capabilities specific to the `textDocument/hover` + */ + Hover *HoverClientCapabilities `json:"hover,omitempty"` + + /*SignatureHelp defined: + * Capabilities specific to the `textDocument/signatureHelp` + */ + SignatureHelp *SignatureHelpClientCapabilities `json:"signatureHelp,omitempty"` + + /*Declaration defined: + * Capabilities specific to the `textDocument/declaration` + * + * @since 3.14.0 + */ + Declaration *DeclarationClientCapabilities `json:"declaration,omitempty"` + + /*Definition defined: + * Capabilities specific to the `textDocument/definition` + */ + Definition *DefinitionClientCapabilities `json:"definition,omitempty"` + + /*TypeDefinition defined: + * Capabilities specific to the `textDocument/typeDefinition` + * + * @since 3.6.0 + */ + TypeDefinition *TypeDefinitionClientCapabilities `json:"typeDefinition,omitempty"` + + /*Implementation defined: + * Capabilities specific to the `textDocument/implementation` + * + * @since 3.6.0 + */ + Implementation *ImplementationClientCapabilities `json:"implementation,omitempty"` + + /*References defined: + * Capabilities specific to the `textDocument/references` + */ + References *ReferenceClientCapabilities `json:"references,omitempty"` + + /*DocumentHighlight defined: + * Capabilities specific to the `textDocument/documentHighlight` + */ + DocumentHighlight *DocumentHighlightClientCapabilities `json:"documentHighlight,omitempty"` + + /*DocumentSymbol defined: + * Capabilities specific to the `textDocument/documentSymbol` + */ + DocumentSymbol *DocumentSymbolClientCapabilities `json:"documentSymbol,omitempty"` + + /*CodeAction defined: + * Capabilities specific to the `textDocument/codeAction` + */ + CodeAction *CodeActionClientCapabilities `json:"codeAction,omitempty"` + + /*CodeLens defined: + * Capabilities specific to the `textDocument/codeLens` + */ + CodeLens *CodeLensClientCapabilities `json:"codeLens,omitempty"` + + /*DocumentLink defined: + * Capabilities specific to the `textDocument/documentLink` + */ + DocumentLink *DocumentLinkClientCapabilities `json:"documentLink,omitempty"` + + /*ColorProvider defined: + * Capabilities specific to the `textDocument/documentColor` + */ + ColorProvider *DocumentColorClientCapabilities `json:"colorProvider,omitempty"` + + /*Formatting defined: + * Capabilities specific to the `textDocument/formatting` + */ + Formatting *DocumentFormattingClientCapabilities `json:"formatting,omitempty"` + + /*RangeFormatting defined: + * Capabilities specific to the `textDocument/rangeFormatting` + */ + RangeFormatting *DocumentRangeFormattingClientCapabilities `json:"rangeFormatting,omitempty"` + + /*OnTypeFormatting defined: + * Capabilities specific to the `textDocument/onTypeFormatting` + */ + OnTypeFormatting *DocumentOnTypeFormattingClientCapabilities `json:"onTypeFormatting,omitempty"` + + /*Rename defined: + * Capabilities specific to the `textDocument/rename` + */ + Rename *RenameClientCapabilities `json:"rename,omitempty"` + + /*FoldingRange defined: + * Capabilities specific to `textDocument/foldingRange` requests. + * + * @since 3.10.0 + */ + FoldingRange *FoldingRangeClientCapabilities `json:"foldingRange,omitempty"` + + /*SelectionRange defined: + * Capabilities specific to `textDocument/selectionRange` requests + * + * @since 3.15.0 + */ + SelectionRange *SelectionRangeClientCapabilities `json:"selectionRange,omitempty"` + + /*PublishDiagnostics defined: + * Capabilities specific to `textDocument/publishDiagnostics`. + */ + PublishDiagnostics *PublishDiagnosticsClientCapabilities `json:"publishDiagnostics,omitempty"` +} + +/*InnerClientCapabilities defined: + * Defines the capabilities provided by the client. + */ +type InnerClientCapabilities struct { + + /*Workspace defined: + * Workspace specific client capabilities. + */ + Workspace *WorkspaceClientCapabilities `json:"workspace,omitempty"` + + /*TextDocument defined: + * Text document specific client capabilities. + */ + TextDocument *TextDocumentClientCapabilities `json:"textDocument,omitempty"` + + /*Window defined: + * Window specific client capabilities. + */ + Window interface{} `json:"window,omitempty"` + + /*Experimental defined: + * Experimental client capabilities. + */ + Experimental interface{} `json:"experimental,omitempty"` +} + +// ClientCapabilities is +type ClientCapabilities struct { + + /*Workspace defined: + * Workspace specific client capabilities. + */ + Workspace struct { + + /*ApplyEdit defined: + * The client supports applying batch edits + * to the workspace by supporting the request + * 'workspace/applyEdit' + */ + ApplyEdit bool `json:"applyEdit,omitempty"` + + /*WorkspaceEdit defined: + * Capabilities specific to `WorkspaceEdit`s + */ + WorkspaceEdit WorkspaceEditClientCapabilities `json:"workspaceEdit,omitempty"` + + /*DidChangeConfiguration defined: + * Capabilities specific to the `workspace/didChangeConfiguration` notification. + */ + DidChangeConfiguration DidChangeConfigurationClientCapabilities `json:"didChangeConfiguration,omitempty"` + + /*DidChangeWatchedFiles defined: + * Capabilities specific to the `workspace/didChangeWatchedFiles` notification. + */ + DidChangeWatchedFiles DidChangeWatchedFilesClientCapabilities `json:"didChangeWatchedFiles,omitempty"` + + /*Symbol defined: + * Capabilities specific to the `workspace/symbol` request. + */ + Symbol WorkspaceSymbolClientCapabilities `json:"symbol,omitempty"` + + /*ExecuteCommand defined: + * Capabilities specific to the `workspace/executeCommand` request. + */ + ExecuteCommand ExecuteCommandClientCapabilities `json:"executeCommand,omitempty"` + + /*WorkspaceFolders defined: + * The client has support for workspace folders + */ + WorkspaceFolders bool `json:"workspaceFolders,omitempty"` + + /*Configuration defined: + * The client supports `workspace/configuration` requests. + */ + Configuration bool `json:"configuration,omitempty"` + } `json:"workspace,omitempty"` + + /*TextDocument defined: + * Text document specific client capabilities. + */ + TextDocument TextDocumentClientCapabilities `json:"textDocument,omitempty"` + + /*Window defined: + * Window specific client capabilities. + */ + Window interface{} `json:"window,omitempty"` + + /*Experimental defined: + * Experimental client capabilities. + */ + Experimental interface{} `json:"experimental,omitempty"` + + /*DynamicRegistration defined: + * Whether implementation supports dynamic registration for selection range providers. If this is set to `true` + * the client supports the new `SelectionRangeRegistrationOptions` return value for the corresponding server + * capability as well. + */ + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` +} + +/*StaticRegistrationOptions defined: + * Static registration options to be returned in the initialize + * request. + */ +type StaticRegistrationOptions struct { + + /*ID defined: + * The id used to register the request. The id can be used to deregister + * the request again. See also Registration#id. + */ + ID string `json:"id,omitempty"` +} + +/*TextDocumentRegistrationOptions defined: + * General text document registration options. + */ +type TextDocumentRegistrationOptions struct { + + /*DocumentSelector defined: + * A document selector to identify the scope of the registration. If set to null + * the document selector provided on the client side will be used. + */ + DocumentSelector DocumentSelector `json:"documentSelector"` +} + +/*SaveOptions defined: + * Save options. + */ +type SaveOptions struct { + + /*IncludeText defined: + * The client is supposed to include the content on save. + */ + IncludeText bool `json:"includeText,omitempty"` +} + +// WorkDoneProgressOptions is +type WorkDoneProgressOptions struct { + + // WorkDoneProgress is + WorkDoneProgress bool `json:"workDoneProgress,omitempty"` +} + +/*InnerServerCapabilities defined: + * Defines the capabilities provided by a language + * server. + */ +type InnerServerCapabilities struct { + + /*TextDocumentSync defined: + * Defines how text documents are synced. Is either a detailed structure defining each notification or + * for backwards compatibility the TextDocumentSyncKind number. + */ + TextDocumentSync interface{} `json:"textDocumentSync,omitempty"` // TextDocumentSyncOptions | TextDocumentSyncKind + + /*CompletionProvider defined: + * The server provides completion support. + */ + CompletionProvider *CompletionOptions `json:"completionProvider,omitempty"` + + /*HoverProvider defined: + * The server provides hover support. + */ + HoverProvider bool `json:"hoverProvider,omitempty"` // boolean | HoverOptions + + /*SignatureHelpProvider defined: + * The server provides signature help support. + */ + SignatureHelpProvider *SignatureHelpOptions `json:"signatureHelpProvider,omitempty"` + + /*DeclarationProvider defined: + * The server provides Goto Declaration support. + */ + DeclarationProvider bool `json:"declarationProvider,omitempty"` // boolean | DeclarationOptions | DeclarationRegistrationOptions + + /*DefinitionProvider defined: + * The server provides goto definition support. + */ + DefinitionProvider bool `json:"definitionProvider,omitempty"` // boolean | DefinitionOptions + + /*TypeDefinitionProvider defined: + * The server provides Goto Type Definition support. + */ + TypeDefinitionProvider bool `json:"typeDefinitionProvider,omitempty"` // boolean | TypeDefinitionOptions | TypeDefinitionRegistrationOptions + + /*ImplementationProvider defined: + * The server provides Goto Implementation support. + */ + ImplementationProvider bool `json:"implementationProvider,omitempty"` // boolean | ImplementationOptions | ImplementationRegistrationOptions + + /*ReferencesProvider defined: + * The server provides find references support. + */ + ReferencesProvider bool `json:"referencesProvider,omitempty"` // boolean | ReferenceOptions + + /*DocumentHighlightProvider defined: + * The server provides document highlight support. + */ + DocumentHighlightProvider bool `json:"documentHighlightProvider,omitempty"` // boolean | DocumentHighlightOptions + + /*DocumentSymbolProvider defined: + * The server provides document symbol support. + */ + DocumentSymbolProvider bool `json:"documentSymbolProvider,omitempty"` // boolean | DocumentSymbolOptions + + /*CodeActionProvider defined: + * The server provides code actions. CodeActionOptions may only be + * specified if the client states that it supports + * `codeActionLiteralSupport` in its initial `initialize` request. + */ + CodeActionProvider interface{} `json:"codeActionProvider,omitempty"` // boolean | CodeActionOptions + + /*CodeLensProvider defined: + * The server provides code lens. + */ + CodeLensProvider *CodeLensOptions `json:"codeLensProvider,omitempty"` + + /*DocumentLinkProvider defined: + * The server provides document link support. + */ + DocumentLinkProvider *DocumentLinkOptions `json:"documentLinkProvider,omitempty"` + + /*ColorProvider defined: + * The server provides color provider support. + */ + ColorProvider bool `json:"colorProvider,omitempty"` // boolean | DocumentColorOptions | DocumentColorRegistrationOptions + + /*WorkspaceSymbolProvider defined: + * The server provides workspace symbol support. + */ + WorkspaceSymbolProvider bool `json:"workspaceSymbolProvider,omitempty"` // boolean | WorkspaceSymbolOptions + + /*DocumentFormattingProvider defined: + * The server provides document formatting. + */ + DocumentFormattingProvider bool `json:"documentFormattingProvider,omitempty"` // boolean | DocumentFormattingOptions + + /*DocumentRangeFormattingProvider defined: + * The server provides document range formatting. + */ + DocumentRangeFormattingProvider bool `json:"documentRangeFormattingProvider,omitempty"` // boolean | DocumentRangeFormattingOptions + + /*DocumentOnTypeFormattingProvider defined: + * The server provides document formatting on typing. + */ + DocumentOnTypeFormattingProvider *DocumentOnTypeFormattingOptions `json:"documentOnTypeFormattingProvider,omitempty"` + + /*RenameProvider defined: + * The server provides rename support. RenameOptions may only be + * specified if the client states that it supports + * `prepareSupport` in its initial `initialize` request. + */ + RenameProvider interface{} `json:"renameProvider,omitempty"` // boolean | RenameOptions + + /*FoldingRangeProvider defined: + * The server provides folding provider support. + */ + FoldingRangeProvider bool `json:"foldingRangeProvider,omitempty"` // boolean | FoldingRangeOptions | FoldingRangeRegistrationOptions + + /*SelectionRangeProvider defined: + * The server provides selection range support. + */ + SelectionRangeProvider bool `json:"selectionRangeProvider,omitempty"` // boolean | SelectionRangeOptions | SelectionRangeRegistrationOptions + + /*ExecuteCommandProvider defined: + * The server provides execute command support. + */ + ExecuteCommandProvider *ExecuteCommandOptions `json:"executeCommandProvider,omitempty"` + + /*Experimental defined: + * Experimental server capabilities. + */ + Experimental interface{} `json:"experimental,omitempty"` +} + +// ServerCapabilities is +type ServerCapabilities struct { + + /*TextDocumentSync defined: + * Defines how text documents are synced. Is either a detailed structure defining each notification or + * for backwards compatibility the TextDocumentSyncKind number. + */ + TextDocumentSync interface{} `json:"textDocumentSync,omitempty"` // TextDocumentSyncOptions | TextDocumentSyncKind + + /*CompletionProvider defined: + * The server provides completion support. + */ + CompletionProvider *CompletionOptions `json:"completionProvider,omitempty"` + + /*HoverProvider defined: + * The server provides hover support. + */ + HoverProvider bool `json:"hoverProvider,omitempty"` // boolean | HoverOptions + + /*SignatureHelpProvider defined: + * The server provides signature help support. + */ + SignatureHelpProvider *SignatureHelpOptions `json:"signatureHelpProvider,omitempty"` + + /*DeclarationProvider defined: + * The server provides Goto Declaration support. + */ + DeclarationProvider bool `json:"declarationProvider,omitempty"` // boolean | DeclarationOptions | DeclarationRegistrationOptions + + /*DefinitionProvider defined: + * The server provides goto definition support. + */ + DefinitionProvider bool `json:"definitionProvider,omitempty"` // boolean | DefinitionOptions + + /*TypeDefinitionProvider defined: + * The server provides Goto Type Definition support. + */ + TypeDefinitionProvider bool `json:"typeDefinitionProvider,omitempty"` // boolean | TypeDefinitionOptions | TypeDefinitionRegistrationOptions + + /*ImplementationProvider defined: + * The server provides Goto Implementation support. + */ + ImplementationProvider bool `json:"implementationProvider,omitempty"` // boolean | ImplementationOptions | ImplementationRegistrationOptions + + /*ReferencesProvider defined: + * The server provides find references support. + */ + ReferencesProvider bool `json:"referencesProvider,omitempty"` // boolean | ReferenceOptions + + /*DocumentHighlightProvider defined: + * The server provides document highlight support. + */ + DocumentHighlightProvider bool `json:"documentHighlightProvider,omitempty"` // boolean | DocumentHighlightOptions + + /*DocumentSymbolProvider defined: + * The server provides document symbol support. + */ + DocumentSymbolProvider bool `json:"documentSymbolProvider,omitempty"` // boolean | DocumentSymbolOptions + + /*CodeActionProvider defined: + * The server provides code actions. CodeActionOptions may only be + * specified if the client states that it supports + * `codeActionLiteralSupport` in its initial `initialize` request. + */ + CodeActionProvider interface{} `json:"codeActionProvider,omitempty"` // boolean | CodeActionOptions + + /*CodeLensProvider defined: + * The server provides code lens. + */ + CodeLensProvider *CodeLensOptions `json:"codeLensProvider,omitempty"` + + /*DocumentLinkProvider defined: + * The server provides document link support. + */ + DocumentLinkProvider *DocumentLinkOptions `json:"documentLinkProvider,omitempty"` + + /*ColorProvider defined: + * The server provides color provider support. + */ + ColorProvider bool `json:"colorProvider,omitempty"` // boolean | DocumentColorOptions | DocumentColorRegistrationOptions + + /*WorkspaceSymbolProvider defined: + * The server provides workspace symbol support. + */ + WorkspaceSymbolProvider bool `json:"workspaceSymbolProvider,omitempty"` // boolean | WorkspaceSymbolOptions + + /*DocumentFormattingProvider defined: + * The server provides document formatting. + */ + DocumentFormattingProvider bool `json:"documentFormattingProvider,omitempty"` // boolean | DocumentFormattingOptions + + /*DocumentRangeFormattingProvider defined: + * The server provides document range formatting. + */ + DocumentRangeFormattingProvider bool `json:"documentRangeFormattingProvider,omitempty"` // boolean | DocumentRangeFormattingOptions + + /*DocumentOnTypeFormattingProvider defined: + * The server provides document formatting on typing. + */ + DocumentOnTypeFormattingProvider *DocumentOnTypeFormattingOptions `json:"documentOnTypeFormattingProvider,omitempty"` + + /*RenameProvider defined: + * The server provides rename support. RenameOptions may only be + * specified if the client states that it supports + * `prepareSupport` in its initial `initialize` request. + */ + RenameProvider interface{} `json:"renameProvider,omitempty"` // boolean | RenameOptions + + /*FoldingRangeProvider defined: + * The server provides folding provider support. + */ + FoldingRangeProvider bool `json:"foldingRangeProvider,omitempty"` // boolean | FoldingRangeOptions | FoldingRangeRegistrationOptions + + /*SelectionRangeProvider defined: + * The server provides selection range support. + */ + SelectionRangeProvider bool `json:"selectionRangeProvider,omitempty"` // boolean | SelectionRangeOptions | SelectionRangeRegistrationOptions + + /*ExecuteCommandProvider defined: + * The server provides execute command support. + */ + ExecuteCommandProvider *ExecuteCommandOptions `json:"executeCommandProvider,omitempty"` + + /*Experimental defined: + * Experimental server capabilities. + */ + Experimental interface{} `json:"experimental,omitempty"` + + /*Workspace defined: + * The workspace server capabilities + */ + Workspace *struct { + + // WorkspaceFolders is + WorkspaceFolders *struct { + + /*Supported defined: + * The Server has support for workspace folders + */ + Supported bool `json:"supported,omitempty"` + + /*ChangeNotifications defined: + * Whether the server wants to receive workspace folder + * change notifications. + * + * If a strings is provided the string is treated as a ID + * under which the notification is registed on the client + * side. The ID can be used to unregister for these events + * using the `client/unregisterCapability` request. + */ + ChangeNotifications string `json:"changeNotifications,omitempty"` // string | boolean + } `json:"workspaceFolders,omitempty"` + } `json:"workspace,omitempty"` +} + +/*InnerInitializeParams defined: + * The initialize parameters + */ +type InnerInitializeParams struct { + + /*ProcessID defined: + * The process Id of the parent process that started + * the server. + */ + ProcessID float64 `json:"processId"` + + /*ClientInfo defined: + * Information about the client + * + * @since 3.15.0 + */ + ClientInfo *struct { + + /*Name defined: + * The name of the client as defined by the client. + */ + Name string `json:"name"` + + /*Version defined: + * The client's version as defined by the client. + */ + Version string `json:"version,omitempty"` + } `json:"clientInfo,omitempty"` + + /*RootPath defined: + * The rootPath of the workspace. Is null + * if no folder is open. + * + * @deprecated in favour of rootUri. + */ + RootPath string `json:"rootPath,omitempty"` + + /*RootURI defined: + * The rootUri of the workspace. Is null if no + * folder is open. If both `rootPath` and `rootUri` are set + * `rootUri` wins. + * + * @deprecated in favour of workspaceFolders. + */ + RootURI DocumentURI `json:"rootUri"` + + /*Capabilities defined: + * The capabilities provided by the client (editor or tool) + */ + Capabilities ClientCapabilities `json:"capabilities"` + + /*InitializationOptions defined: + * User provided initialization options. + */ + InitializationOptions interface{} `json:"initializationOptions,omitempty"` + + /*Trace defined: + * The initial trace setting. If omitted trace is disabled ('off'). + */ + Trace string `json:"trace,omitempty"` // 'off' | 'messages' | 'verbose' + WorkDoneProgressParams +} + +// InitializeParams is +type InitializeParams struct { + + /*ProcessID defined: + * The process Id of the parent process that started + * the server. + */ + ProcessID float64 `json:"processId"` + + /*ClientInfo defined: + * Information about the client + * + * @since 3.15.0 + */ + ClientInfo *struct { + + /*Name defined: + * The name of the client as defined by the client. + */ + Name string `json:"name"` + + /*Version defined: + * The client's version as defined by the client. + */ + Version string `json:"version,omitempty"` + } `json:"clientInfo,omitempty"` + + /*RootPath defined: + * The rootPath of the workspace. Is null + * if no folder is open. + * + * @deprecated in favour of rootUri. + */ + RootPath string `json:"rootPath,omitempty"` + + /*RootURI defined: + * The rootUri of the workspace. Is null if no + * folder is open. If both `rootPath` and `rootUri` are set + * `rootUri` wins. + * + * @deprecated in favour of workspaceFolders. + */ + RootURI DocumentURI `json:"rootUri"` + + /*Capabilities defined: + * The capabilities provided by the client (editor or tool) + */ + Capabilities ClientCapabilities `json:"capabilities"` + + /*InitializationOptions defined: + * User provided initialization options. + */ + InitializationOptions interface{} `json:"initializationOptions,omitempty"` + + /*Trace defined: + * The initial trace setting. If omitted trace is disabled ('off'). + */ + Trace string `json:"trace,omitempty"` // 'off' | 'messages' | 'verbose' + + /*WorkspaceFolders defined: + * The actual configured workspace folders. + */ + WorkspaceFolders []WorkspaceFolder `json:"workspaceFolders"` +} + +/*InitializeResult defined: + * The result returned from an initialize request. + */ +type InitializeResult struct { + + /*Capabilities defined: + * The capabilities the language server provides. + */ + Capabilities ServerCapabilities `json:"capabilities"` + + /*ServerInfo defined: + * Information about the server. + * + * @since 3.15.0 + */ + ServerInfo *struct { + + /*Name defined: + * The name of the server as defined by the server. + */ + Name string `json:"name"` + + /*Version defined: + * The servers's version as defined by the server. + */ + Version string `json:"version,omitempty"` + } `json:"serverInfo,omitempty"` + + /*Custom defined: + * Custom initialization results. + */ + Custom map[string]interface{} `json:"custom"` // [custom: string]: any; +} + +// InitializedParams is +type InitializedParams struct { +} + +// DidChangeConfigurationClientCapabilities is +type DidChangeConfigurationClientCapabilities struct { + + /*DynamicRegistration defined: + * Did change configuration notification supports dynamic registration. + */ + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` +} + +// DidChangeConfigurationRegistrationOptions is +type DidChangeConfigurationRegistrationOptions struct { + + // Section is + Section string `json:"section,omitempty"` // string | string[] +} + +/*DidChangeConfigurationParams defined: + * The parameters of a change configuration notification. + */ +type DidChangeConfigurationParams struct { + + /*Settings defined: + * The actual changed settings + */ + Settings interface{} `json:"settings"` +} + +/*ShowMessageParams defined: + * The parameters of a notification message. + */ +type ShowMessageParams struct { + + /*Type defined: + * The message type. See {@link MessageType} + */ + Type MessageType `json:"type"` + + /*Message defined: + * The actual message + */ + Message string `json:"message"` +} + +// MessageActionItem is +type MessageActionItem struct { + + /*Title defined: + * A short title like 'Retry', 'Open Log' etc. + */ + Title string `json:"title"` +} + +// ShowMessageRequestParams is +type ShowMessageRequestParams struct { + + /*Type defined: + * The message type. See {@link MessageType} + */ + Type MessageType `json:"type"` + + /*Message defined: + * The actual message + */ + Message string `json:"message"` + + /*Actions defined: + * The message action items to present. + */ + Actions []MessageActionItem `json:"actions,omitempty"` +} + +/*LogMessageParams defined: + * The log message parameters. + */ +type LogMessageParams struct { + + /*Type defined: + * The message type. See {@link MessageType} + */ + Type MessageType `json:"type"` + + /*Message defined: + * The actual message + */ + Message string `json:"message"` +} + +// TextDocumentSyncClientCapabilities is +type TextDocumentSyncClientCapabilities struct { + + /*DynamicRegistration defined: + * Whether text document synchronization supports dynamic registration. + */ + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` + + /*WillSave defined: + * The client supports sending will save notifications. + */ + WillSave bool `json:"willSave,omitempty"` + + /*WillSaveWaitUntil defined: + * The client supports sending a will save request and + * waits for a response providing text edits which will + * be applied to the document before it is saved. + */ + WillSaveWaitUntil bool `json:"willSaveWaitUntil,omitempty"` + + /*DidSave defined: + * The client supports did save notifications. + */ + DidSave bool `json:"didSave,omitempty"` +} + +// TextDocumentSyncOptions is +type TextDocumentSyncOptions struct { + + /*OpenClose defined: + * Open and close notifications are sent to the server. If omitted open close notification should not + * be sent. + */ + OpenClose bool `json:"openClose,omitempty"` + + /*Change defined: + * Change notifications are sent to the server. See TextDocumentSyncKind.None, TextDocumentSyncKind.Full + * and TextDocumentSyncKind.Incremental. If omitted it defaults to TextDocumentSyncKind.None. + */ + Change TextDocumentSyncKind `json:"change,omitempty"` + + /*WillSave defined: + * If present will save notifications are sent to the server. If omitted the notification should not be + * sent. + */ + WillSave bool `json:"willSave,omitempty"` + + /*WillSaveWaitUntil defined: + * If present will save wait until requests are sent to the server. If omitted the request should not be + * sent. + */ + WillSaveWaitUntil bool `json:"willSaveWaitUntil,omitempty"` + + /*Save defined: + * If present save notifications are sent to the server. If omitted the notification should not be + * sent. + */ + Save *SaveOptions `json:"save,omitempty"` +} + +/*DidOpenTextDocumentParams defined: + * The parameters send in a open text document notification + */ +type DidOpenTextDocumentParams struct { + + /*TextDocument defined: + * The document that was opened. + */ + TextDocument TextDocumentItem `json:"textDocument"` +} + +/*DidChangeTextDocumentParams defined: + * The change text document notification's parameters. + */ +type DidChangeTextDocumentParams struct { + + /*TextDocument defined: + * The document that did change. The version number points + * to the version after all provided content changes have + * been applied. + */ + TextDocument VersionedTextDocumentIdentifier `json:"textDocument"` + + /*ContentChanges defined: + * The actual content changes. The content changes describe single state changes + * to the document. So if there are two content changes c1 and c2 for a document + * in state S then c1 move the document to S' and c2 to S''. + */ + ContentChanges []TextDocumentContentChangeEvent `json:"contentChanges"` +} + +/*TextDocumentChangeRegistrationOptions defined: + * Describe options to be used when registered for text document change events. + */ +type TextDocumentChangeRegistrationOptions struct { + + /*SyncKind defined: + * How documents are synced to the server. + */ + SyncKind TextDocumentSyncKind `json:"syncKind"` + TextDocumentRegistrationOptions +} + +/*DidCloseTextDocumentParams defined: + * The parameters send in a close text document notification + */ +type DidCloseTextDocumentParams struct { + + /*TextDocument defined: + * The document that was closed. + */ + TextDocument TextDocumentIdentifier `json:"textDocument"` +} + +/*DidSaveTextDocumentParams defined: + * The parameters send in a save text document notification + */ +type DidSaveTextDocumentParams struct { + + /*TextDocument defined: + * The document that was closed. + */ + TextDocument VersionedTextDocumentIdentifier `json:"textDocument"` + + /*Text defined: + * Optional the content when saved. Depends on the includeText value + * when the save notification was requested. + */ + Text string `json:"text,omitempty"` +} + +/*TextDocumentSaveRegistrationOptions defined: + * Save registration options. + */ +type TextDocumentSaveRegistrationOptions struct { + TextDocumentRegistrationOptions + SaveOptions +} + +/*WillSaveTextDocumentParams defined: + * The parameters send in a will save text document notification. + */ +type WillSaveTextDocumentParams struct { + + /*TextDocument defined: + * The document that will be saved. + */ + TextDocument TextDocumentIdentifier `json:"textDocument"` + + /*Reason defined: + * The 'TextDocumentSaveReason'. + */ + Reason TextDocumentSaveReason `json:"reason"` +} + +// DidChangeWatchedFilesClientCapabilities is +type DidChangeWatchedFilesClientCapabilities struct { + + /*DynamicRegistration defined: + * Did change watched files notification supports dynamic registration. Please note + * that the current protocol doesn't support static configuration for file changes + * from the server side. + */ + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` +} + +/*DidChangeWatchedFilesParams defined: + * The watched files change notification's parameters. + */ +type DidChangeWatchedFilesParams struct { + + /*Changes defined: + * The actual file events. + */ + Changes []FileEvent `json:"changes"` +} + +/*FileEvent defined: + * An event describing a file change. + */ +type FileEvent struct { + + /*URI defined: + * The file's uri. + */ + URI DocumentURI `json:"uri"` + + /*Type defined: + * The change type. + */ + Type FileChangeType `json:"type"` +} + +/*DidChangeWatchedFilesRegistrationOptions defined: + * Describe options to be used when registered for text document change events. + */ +type DidChangeWatchedFilesRegistrationOptions struct { + + /*Watchers defined: + * The watchers to register. + */ + Watchers []FileSystemWatcher `json:"watchers"` +} + +// FileSystemWatcher is +type FileSystemWatcher struct { + + /*GlobPattern defined: + * The glob pattern to watch. Glob patterns can have the following syntax: + * - `*` to match one or more characters in a path segment + * - `?` to match on one character in a path segment + * - `**` to match any number of path segments, including none + * - `{}` to group conditions (e.g. `**​/*.{ts,js}` matches all TypeScript and JavaScript files) + * - `[]` to declare a range of characters to match in a path segment (e.g., `example.[0-9]` to match on `example.0`, `example.1`, …) + * - `[!...]` to negate a range of characters to match in a path segment (e.g., `example.[!0-9]` to match on `example.a`, `example.b`, but not `example.0`) + */ + GlobPattern string `json:"globPattern"` + + /*Kind defined: + * The kind of events of interest. If omitted it defaults + * to WatchKind.Create | WatchKind.Change | WatchKind.Delete + * which is 7. + */ + Kind float64 `json:"kind,omitempty"` +} + +/*PublishDiagnosticsClientCapabilities defined: + * The publish diagnostic client capabilities. + */ +type PublishDiagnosticsClientCapabilities struct { + + /*RelatedInformation defined: + * Whether the clients accepts diagnostics with related information. + */ + RelatedInformation bool `json:"relatedInformation,omitempty"` + + /*TagSupport defined: + * Client supports the tag property to provide meta data about a diagnostic. + * Clients supporting tags have to handle unknown tags gracefully. + * + * @since 3.15.0 + */ + TagSupport *struct { + + /*ValueSet defined: + * The tags supported by the client. + */ + ValueSet []DiagnosticTag `json:"valueSet"` + } `json:"tagSupport,omitempty"` +} + +/*PublishDiagnosticsParams defined: + * The publish diagnostic notification's parameters. + */ +type PublishDiagnosticsParams struct { + + /*URI defined: + * The URI for which diagnostic information is reported. + */ + URI DocumentURI `json:"uri"` + + /*Version defined: + * Optional the version number of the document the diagnostics are published for. + * + * @since 3.15.0 + */ + Version float64 `json:"version,omitempty"` + + /*Diagnostics defined: + * An array of diagnostic information items. + */ + Diagnostics []Diagnostic `json:"diagnostics"` +} + +/*CompletionClientCapabilities defined: + * Completion client capabilities + */ +type CompletionClientCapabilities struct { + + /*DynamicRegistration defined: + * Whether completion supports dynamic registration. + */ + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` + + /*CompletionItem defined: + * The client supports the following `CompletionItem` specific + * capabilities. + */ + CompletionItem *struct { + + /*SnippetSupport defined: + * Client supports snippets as insert text. + * + * A snippet can define tab stops and placeholders with `$1`, `$2` + * and `${3:foo}`. `$0` defines the final tab stop, it defaults to + * the end of the snippet. Placeholders with equal identifiers are linked, + * that is typing in one will update others too. + */ + SnippetSupport bool `json:"snippetSupport,omitempty"` + + /*CommitCharactersSupport defined: + * Client supports commit characters on a completion item. + */ + CommitCharactersSupport bool `json:"commitCharactersSupport,omitempty"` + + /*DocumentationFormat defined: + * Client supports the follow content formats for the documentation + * property. The order describes the preferred format of the client. + */ + DocumentationFormat []MarkupKind `json:"documentationFormat,omitempty"` + + /*DeprecatedSupport defined: + * Client supports the deprecated property on a completion item. + */ + DeprecatedSupport bool `json:"deprecatedSupport,omitempty"` + + /*PreselectSupport defined: + * Client supports the preselect property on a completion item. + */ + PreselectSupport bool `json:"preselectSupport,omitempty"` + + /*TagSupport defined: + * Client supports the tag property on a completion item. Clients supporting + * tags have to handle unknown tags gracefully. Clients especially need to + * preserve unknown tags when sending a completion item back to the server in + * a resolve call. + * + * @since 3.15.0 + */ + TagSupport *struct { + + /*ValueSet defined: + * The tags supported by the client. + */ + ValueSet []CompletionItemTag `json:"valueSet"` + } `json:"tagSupport,omitempty"` + } `json:"completionItem,omitempty"` + + // CompletionItemKind is + CompletionItemKind *struct { + + /*ValueSet defined: + * The completion item kind values the client supports. When this + * property exists the client also guarantees that it will + * handle values outside its set gracefully and falls back + * to a default value when unknown. + * + * If this property is not present the client only supports + * the completion items kinds from `Text` to `Reference` as defined in + * the initial version of the protocol. + */ + ValueSet []CompletionItemKind `json:"valueSet,omitempty"` + } `json:"completionItemKind,omitempty"` + + /*ContextSupport defined: + * The client supports to send additional context information for a + * `textDocument/completion` requestion. + */ + ContextSupport bool `json:"contextSupport,omitempty"` +} + +/*CompletionContext defined: + * Contains additional information about the context in which a completion request is triggered. + */ +type CompletionContext struct { + + /*TriggerKind defined: + * How the completion was triggered. + */ + TriggerKind CompletionTriggerKind `json:"triggerKind"` + + /*TriggerCharacter defined: + * The trigger character (a single character) that has trigger code complete. + * Is undefined if `triggerKind !== CompletionTriggerKind.TriggerCharacter` + */ + TriggerCharacter string `json:"triggerCharacter,omitempty"` +} + +/*CompletionParams defined: + * Completion parameters + */ +type CompletionParams struct { + + /*Context defined: + * The completion context. This is only available it the client specifies + * to send this using the client capability `textDocument.completion.contextSupport === true` + */ + Context *CompletionContext `json:"context,omitempty"` + TextDocumentPositionParams + WorkDoneProgressParams + PartialResultParams +} + +/*CompletionOptions defined: + * Completion options. + */ +type CompletionOptions struct { + + /*TriggerCharacters defined: + * Most tools trigger completion request automatically without explicitly requesting + * it using a keyboard shortcut (e.g. Ctrl+Space). Typically they do so when the user + * starts to type an identifier. For example if the user types `c` in a JavaScript file + * code complete will automatically pop up present `console` besides others as a + * completion item. Characters that make up identifiers don't need to be listed here. + * + * If code complete should automatically be trigger on characters not being valid inside + * an identifier (for example `.` in JavaScript) list them in `triggerCharacters`. + */ + TriggerCharacters []string `json:"triggerCharacters,omitempty"` + + /*AllCommitCharacters defined: + * The list of all possible characters that commit a completion. This field can be used + * if clients don't support individual commmit characters per completion item. See + * `ClientCapabilities.textDocument.completion.completionItem.commitCharactersSupport` + * + * @since 3.2.0 + */ + AllCommitCharacters []string `json:"allCommitCharacters,omitempty"` + + /*ResolveProvider defined: + * The server provides support to resolve additional + * information for a completion item. + */ + ResolveProvider bool `json:"resolveProvider,omitempty"` + WorkDoneProgressOptions +} + +/*CompletionRegistrationOptions defined: + * Registration options for a [CompletionRequest](#CompletionRequest). + */ +type CompletionRegistrationOptions struct { + TextDocumentRegistrationOptions + CompletionOptions +} + +// HoverClientCapabilities is +type HoverClientCapabilities struct { + + /*DynamicRegistration defined: + * Whether hover supports dynamic registration. + */ + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` + + /*ContentFormat defined: + * Client supports the follow content formats for the content + * property. The order describes the preferred format of the client. + */ + ContentFormat []MarkupKind `json:"contentFormat,omitempty"` +} + +/*HoverOptions defined: + * Hover options. + */ +type HoverOptions struct { + WorkDoneProgressOptions +} + +/*HoverParams defined: + * Parameters for a [HoverRequest](#HoverRequest). + */ +type HoverParams struct { + TextDocumentPositionParams + WorkDoneProgressParams +} + +/*HoverRegistrationOptions defined: + * Registration options for a [HoverRequest](#HoverRequest). + */ +type HoverRegistrationOptions struct { + TextDocumentRegistrationOptions + HoverOptions +} + +/*SignatureHelpClientCapabilities defined: + * Client Capabilities for a [SignatureHelpRequest](#SignatureHelpRequest). + */ +type SignatureHelpClientCapabilities struct { + + /*DynamicRegistration defined: + * Whether signature help supports dynamic registration. + */ + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` + + /*SignatureInformation defined: + * The client supports the following `SignatureInformation` + * specific properties. + */ + SignatureInformation *struct { + + /*DocumentationFormat defined: + * Client supports the follow content formats for the documentation + * property. The order describes the preferred format of the client. + */ + DocumentationFormat []MarkupKind `json:"documentationFormat,omitempty"` + + /*ParameterInformation defined: + * Client capabilities specific to parameter information. + */ + ParameterInformation *struct { + + /*LabelOffsetSupport defined: + * The client supports processing label offsets instead of a + * simple label string. + * + * @since 3.14.0 + */ + LabelOffsetSupport bool `json:"labelOffsetSupport,omitempty"` + } `json:"parameterInformation,omitempty"` + } `json:"signatureInformation,omitempty"` + + /*ContextSupport defined: + * The client supports to send additional context information for a + * `textDocument/signatureHelp` request. A client that opts into + * contextSupport will also support the `retriggerCharacters` on + * `SignatureHelpOptions`. + * + * @since 3.15.0 + */ + ContextSupport bool `json:"contextSupport,omitempty"` +} + +/*SignatureHelpOptions defined: + * Server Capabilities for a [SignatureHelpRequest](#SignatureHelpRequest). + */ +type SignatureHelpOptions struct { + + /*TriggerCharacters defined: + * List of characters that trigger signature help. + */ + TriggerCharacters []string `json:"triggerCharacters,omitempty"` + + /*RetriggerCharacters defined: + * List of characters that re-trigger signature help. + * + * These trigger characters are only active when signature help is already showing. All trigger characters + * are also counted as re-trigger characters. + * + * @since 3.15.0 + */ + RetriggerCharacters []string `json:"retriggerCharacters,omitempty"` + WorkDoneProgressOptions +} + +/*SignatureHelpContext defined: + * Additional information about the context in which a signature help request was triggered. + * + * @since 3.15.0 + */ +type SignatureHelpContext struct { + + /*TriggerKind defined: + * Action that caused signature help to be triggered. + */ + TriggerKind SignatureHelpTriggerKind `json:"triggerKind"` + + /*TriggerCharacter defined: + * Character that caused signature help to be triggered. + * + * This is undefined when `triggerKind !== SignatureHelpTriggerKind.TriggerCharacter` + */ + TriggerCharacter string `json:"triggerCharacter,omitempty"` + + /*IsRetrigger defined: + * `true` if signature help was already showing when it was triggered. + * + * Retriggers occur when the signature help is already active and can be caused by actions such as + * typing a trigger character, a cursor move, or document content changes. + */ + IsRetrigger bool `json:"isRetrigger"` + + /*ActiveSignatureHelp defined: + * The currently active `SignatureHelp`. + * + * The `activeSignatureHelp` has its `SignatureHelp.activeSignature` field updated based on + * the user navigating through available signatures. + */ + ActiveSignatureHelp *SignatureHelp `json:"activeSignatureHelp,omitempty"` +} + +/*SignatureHelpParams defined: + * Parameters for a [SignatureHelpRequest](#SignatureHelpRequest). + */ +type SignatureHelpParams struct { + + /*Context defined: + * The signature help context. This is only available if the client specifies + * to send this using the client capability `textDocument.signatureHelp.contextSupport === true` + * + * @since 3.15.0 + */ + Context *SignatureHelpContext `json:"context,omitempty"` + TextDocumentPositionParams + WorkDoneProgressParams +} + +/*SignatureHelpRegistrationOptions defined: + * Registration options for a [SignatureHelpRequest](#SignatureHelpRequest). + */ +type SignatureHelpRegistrationOptions struct { + TextDocumentRegistrationOptions + SignatureHelpOptions +} + +/*DefinitionClientCapabilities defined: + * Client Capabilities for a [DefinitionRequest](#DefinitionRequest). + */ +type DefinitionClientCapabilities struct { + + /*DynamicRegistration defined: + * Whether definition supports dynamic registration. + */ + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` + + /*LinkSupport defined: + * The client supports additional metadata in the form of definition links. + * + * @since 3.14.0 + */ + LinkSupport bool `json:"linkSupport,omitempty"` +} + +/*DefinitionOptions defined: + * Server Capabilities for a [DefinitionRequest](#DefinitionRequest). + */ +type DefinitionOptions struct { + WorkDoneProgressOptions +} + +/*DefinitionParams defined: + * Parameters for a [DefinitionRequest](#DefinitionRequest). + */ +type DefinitionParams struct { + TextDocumentPositionParams + WorkDoneProgressParams + PartialResultParams +} + +/*DefinitionRegistrationOptions defined: + * Registration options for a [DefinitionRequest](#DefinitionRequest). + */ +type DefinitionRegistrationOptions struct { + TextDocumentRegistrationOptions + DefinitionOptions +} + +/*ReferenceClientCapabilities defined: + * Client Capabilities for a [ReferencesRequest](#ReferencesRequest). + */ +type ReferenceClientCapabilities struct { + + /*DynamicRegistration defined: + * Whether references supports dynamic registration. + */ + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` +} + +/*ReferenceParams defined: + * Parameters for a [ReferencesRequest](#ReferencesRequest). + */ +type ReferenceParams struct { + + // Context is + Context ReferenceContext `json:"context"` + TextDocumentPositionParams + WorkDoneProgressParams + PartialResultParams +} + +/*ReferenceOptions defined: + * Reference options. + */ +type ReferenceOptions struct { + WorkDoneProgressOptions +} + +/*ReferenceRegistrationOptions defined: + * Registration options for a [ReferencesRequest](#ReferencesRequest). + */ +type ReferenceRegistrationOptions struct { + TextDocumentRegistrationOptions + ReferenceOptions +} + +/*DocumentHighlightClientCapabilities defined: + * Client Capabilities for a [DocumentHighlightRequest](#DocumentHighlightRequest). + */ +type DocumentHighlightClientCapabilities struct { + + /*DynamicRegistration defined: + * Whether document highlight supports dynamic registration. + */ + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` +} + +/*DocumentHighlightParams defined: + * Parameters for a [DocumentHighlightRequest](#DocumentHighlightRequest). + */ +type DocumentHighlightParams struct { + TextDocumentPositionParams + WorkDoneProgressParams + PartialResultParams +} + +/*DocumentHighlightOptions defined: + * Provider options for a [DocumentHighlightRequest](#DocumentHighlightRequest). + */ +type DocumentHighlightOptions struct { + WorkDoneProgressOptions +} + +/*DocumentHighlightRegistrationOptions defined: + * Registration options for a [DocumentHighlightRequest](#DocumentHighlightRequest). + */ +type DocumentHighlightRegistrationOptions struct { + TextDocumentRegistrationOptions + DocumentHighlightOptions +} + +/*DocumentSymbolClientCapabilities defined: + * Client Capabilities for a [DocumentSymbolRequest](#DocumentSymbolRequest). + */ +type DocumentSymbolClientCapabilities struct { + + /*DynamicRegistration defined: + * Whether document symbol supports dynamic registration. + */ + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` + + /*SymbolKind defined: + * Specific capabilities for the `SymbolKind`. + */ + SymbolKind *struct { + + /*ValueSet defined: + * The symbol kind values the client supports. When this + * property exists the client also guarantees that it will + * handle values outside its set gracefully and falls back + * to a default value when unknown. + * + * If this property is not present the client only supports + * the symbol kinds from `File` to `Array` as defined in + * the initial version of the protocol. + */ + ValueSet []SymbolKind `json:"valueSet,omitempty"` + } `json:"symbolKind,omitempty"` + + /*HierarchicalDocumentSymbolSupport defined: + * The client support hierarchical document symbols. + */ + HierarchicalDocumentSymbolSupport bool `json:"hierarchicalDocumentSymbolSupport,omitempty"` +} + +/*DocumentSymbolParams defined: + * Parameters for a [DocumentSymbolRequest](#DocumentSymbolRequest). + */ +type DocumentSymbolParams struct { + + /*TextDocument defined: + * The text document. + */ + TextDocument TextDocumentIdentifier `json:"textDocument"` + WorkDoneProgressParams + PartialResultParams +} + +/*DocumentSymbolOptions defined: + * Provider options for a [DocumentSymbolRequest](#DocumentSymbolRequest). + */ +type DocumentSymbolOptions struct { + WorkDoneProgressOptions +} + +/*DocumentSymbolRegistrationOptions defined: + * Registration options for a [DocumentSymbolRequest](#DocumentSymbolRequest). + */ +type DocumentSymbolRegistrationOptions struct { + TextDocumentRegistrationOptions + DocumentSymbolOptions +} + +/*CodeActionClientCapabilities defined: + * The Client Capabilities of a [CodeActionRequest](#CodeActionRequest). + */ +type CodeActionClientCapabilities struct { + + /*DynamicRegistration defined: + * Whether code action supports dynamic registration. + */ + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` + + /*CodeActionLiteralSupport defined: + * The client support code action literals as a valid + * response of the `textDocument/codeAction` request. + * + * @since 3.8.0 + */ + CodeActionLiteralSupport *struct { + + /*CodeActionKind defined: + * The code action kind is support with the following value + * set. + */ + CodeActionKind struct { + + /*ValueSet defined: + * The code action kind values the client supports. When this + * property exists the client also guarantees that it will + * handle values outside its set gracefully and falls back + * to a default value when unknown. + */ + ValueSet []CodeActionKind `json:"valueSet"` + } `json:"codeActionKind"` + } `json:"codeActionLiteralSupport,omitempty"` + + /*IsPreferredSupport defined: + * Whether code action supports the `isPreferred` property. + * @since 3.15.0 + */ + IsPreferredSupport bool `json:"isPreferredSupport,omitempty"` +} + +/*CodeActionParams defined: + * The parameters of a [CodeActionRequest](#CodeActionRequest). + */ +type CodeActionParams struct { + + /*TextDocument defined: + * The document in which the command was invoked. + */ + TextDocument TextDocumentIdentifier `json:"textDocument"` + + /*Range defined: + * The range for which the command was invoked. + */ + Range Range `json:"range"` + + /*Context defined: + * Context carrying additional information. + */ + Context CodeActionContext `json:"context"` + WorkDoneProgressParams + PartialResultParams +} + +/*CodeActionOptions defined: + * Provider options for a [CodeActionRequest](#CodeActionRequest). + */ +type CodeActionOptions struct { + + /*CodeActionKinds defined: + * CodeActionKinds that this server may return. + * + * The list of kinds may be generic, such as `CodeActionKind.Refactor`, or the server + * may list out every specific kind they provide. + */ + CodeActionKinds []CodeActionKind `json:"codeActionKinds,omitempty"` + WorkDoneProgressOptions +} + +/*CodeActionRegistrationOptions defined: + * Registration options for a [CodeActionRequest](#CodeActionRequest). + */ +type CodeActionRegistrationOptions struct { + TextDocumentRegistrationOptions + CodeActionOptions +} + +/*WorkspaceSymbolClientCapabilities defined: + * Client capabilities for a [WorkspaceSymbolRequest](#WorkspaceSymbolRequest). + */ +type WorkspaceSymbolClientCapabilities struct { + + /*DynamicRegistration defined: + * Symbol request supports dynamic registration. + */ + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` + + /*SymbolKind defined: + * Specific capabilities for the `SymbolKind` in the `workspace/symbol` request. + */ + SymbolKind *struct { + + /*ValueSet defined: + * The symbol kind values the client supports. When this + * property exists the client also guarantees that it will + * handle values outside its set gracefully and falls back + * to a default value when unknown. + * + * If this property is not present the client only supports + * the symbol kinds from `File` to `Array` as defined in + * the initial version of the protocol. + */ + ValueSet []SymbolKind `json:"valueSet,omitempty"` + } `json:"symbolKind,omitempty"` +} + +/*WorkspaceSymbolParams defined: + * The parameters of a [WorkspaceSymbolRequest](#WorkspaceSymbolRequest). + */ +type WorkspaceSymbolParams struct { + + /*Query defined: + * A query string to filter symbols by. Clients may send an empty + * string here to request all symbols. + */ + Query string `json:"query"` + WorkDoneProgressParams + PartialResultParams +} + +/*WorkspaceSymbolOptions defined: + * Server capabilities for a [WorkspaceSymbolRequest](#WorkspaceSymbolRequest). + */ +type WorkspaceSymbolOptions struct { + WorkDoneProgressOptions +} + +/*WorkspaceSymbolRegistrationOptions defined: + * Registration options for a [WorkspaceSymbolRequest](#WorkspaceSymbolRequest). + */ +type WorkspaceSymbolRegistrationOptions struct { + WorkspaceSymbolOptions +} + +/*CodeLensClientCapabilities defined: + * The client capabilities of a [CodeLensRequest](#CodeLensRequest). + */ +type CodeLensClientCapabilities struct { + + /*DynamicRegistration defined: + * Whether code lens supports dynamic registration. + */ + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` +} + +/*CodeLensParams defined: + * The parameters of a [CodeLensRequest](#CodeLensRequest). + */ +type CodeLensParams struct { + + /*TextDocument defined: + * The document to request code lens for. + */ + TextDocument TextDocumentIdentifier `json:"textDocument"` + WorkDoneProgressParams + PartialResultParams +} + +/*CodeLensOptions defined: + * Code Lens provider options of a [CodeLensRequest](#CodeLensRequest). + */ +type CodeLensOptions struct { + + /*ResolveProvider defined: + * Code lens has a resolve provider as well. + */ + ResolveProvider bool `json:"resolveProvider,omitempty"` + WorkDoneProgressOptions +} + +/*CodeLensRegistrationOptions defined: + * Registration options for a [CodeLensRequest](#CodeLensRequest). + */ +type CodeLensRegistrationOptions struct { + TextDocumentRegistrationOptions + CodeLensOptions +} + +/*DocumentLinkClientCapabilities defined: + * The client capabilities of a [DocumentLinkRequest](#DocumentLinkRequest). + */ +type DocumentLinkClientCapabilities struct { + + /*DynamicRegistration defined: + * Whether document link supports dynamic registration. + */ + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` + + /*TooltipSupport defined: + * Whether the client support the `tooltip` property on `DocumentLink`. + * + * @since 3.15.0 + */ + TooltipSupport bool `json:"tooltipSupport,omitempty"` +} + +/*DocumentLinkParams defined: + * The parameters of a [DocumentLinkRequest](#DocumentLinkRequest). + */ +type DocumentLinkParams struct { + + /*TextDocument defined: + * The document to provide document links for. + */ + TextDocument TextDocumentIdentifier `json:"textDocument"` + WorkDoneProgressParams + PartialResultParams +} + +/*DocumentLinkOptions defined: + * Provider options for a [DocumentLinkRequest](#DocumentLinkRequest). + */ +type DocumentLinkOptions struct { + + /*ResolveProvider defined: + * Document links have a resolve provider as well. + */ + ResolveProvider bool `json:"resolveProvider,omitempty"` + WorkDoneProgressOptions +} + +/*DocumentLinkRegistrationOptions defined: + * Registration options for a [DocumentLinkRequest](#DocumentLinkRequest). + */ +type DocumentLinkRegistrationOptions struct { + TextDocumentRegistrationOptions + DocumentLinkOptions +} + +/*DocumentFormattingClientCapabilities defined: + * Client capabilities of a [DocumentFormattingRequest](#DocumentFormattingRequest). + */ +type DocumentFormattingClientCapabilities struct { + + /*DynamicRegistration defined: + * Whether formatting supports dynamic registration. + */ + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` +} + +/*DocumentFormattingParams defined: + * The parameters of a [DocumentFormattingRequest](#DocumentFormattingRequest). + */ +type DocumentFormattingParams struct { + + /*TextDocument defined: + * The document to format. + */ + TextDocument TextDocumentIdentifier `json:"textDocument"` + + /*Options defined: + * The format options + */ + Options FormattingOptions `json:"options"` + WorkDoneProgressParams +} + +/*DocumentFormattingOptions defined: + * Provider options for a [DocumentFormattingRequest](#DocumentFormattingRequest). + */ +type DocumentFormattingOptions struct { + WorkDoneProgressOptions +} + +/*DocumentFormattingRegistrationOptions defined: + * Registration options for a [DocumentFormattingRequest](#DocumentFormattingRequest). + */ +type DocumentFormattingRegistrationOptions struct { + TextDocumentRegistrationOptions + DocumentFormattingOptions +} + +/*DocumentRangeFormattingClientCapabilities defined: + * Client capabilities of a [DocumentRangeFormattingRequest](#DocumentRangeFormattingRequest). + */ +type DocumentRangeFormattingClientCapabilities struct { + + /*DynamicRegistration defined: + * Whether range formatting supports dynamic registration. + */ + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` +} + +/*DocumentRangeFormattingParams defined: + * The parameters of a [DocumentRangeFormattingRequest](#DocumentRangeFormattingRequest). + */ +type DocumentRangeFormattingParams struct { + + /*TextDocument defined: + * The document to format. + */ + TextDocument TextDocumentIdentifier `json:"textDocument"` + + /*Range defined: + * The range to format + */ + Range Range `json:"range"` + + /*Options defined: + * The format options + */ + Options FormattingOptions `json:"options"` + WorkDoneProgressParams +} + +/*DocumentRangeFormattingOptions defined: + * Provider options for a [DocumentRangeFormattingRequest](#DocumentRangeFormattingRequest). + */ +type DocumentRangeFormattingOptions struct { + WorkDoneProgressOptions +} + +/*DocumentRangeFormattingRegistrationOptions defined: + * Registration options for a [DocumentRangeFormattingRequest](#DocumentRangeFormattingRequest). + */ +type DocumentRangeFormattingRegistrationOptions struct { + TextDocumentRegistrationOptions + DocumentRangeFormattingOptions +} + +/*DocumentOnTypeFormattingClientCapabilities defined: + * Client capabilities of a [DocumentOnTypeFormattingRequest](#DocumentOnTypeFormattingRequest). + */ +type DocumentOnTypeFormattingClientCapabilities struct { + + /*DynamicRegistration defined: + * Whether on type formatting supports dynamic registration. + */ + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` +} + +/*DocumentOnTypeFormattingParams defined: + * The parameters of a [DocumentOnTypeFormattingRequest](#DocumentOnTypeFormattingRequest). + */ +type DocumentOnTypeFormattingParams struct { + + /*TextDocument defined: + * The document to format. + */ + TextDocument TextDocumentIdentifier `json:"textDocument"` + + /*Position defined: + * The position at which this request was send. + */ + Position Position `json:"position"` + + /*Ch defined: + * The character that has been typed. + */ + Ch string `json:"ch"` + + /*Options defined: + * The format options. + */ + Options FormattingOptions `json:"options"` +} + +/*DocumentOnTypeFormattingOptions defined: + * Provider options for a [DocumentOnTypeFormattingRequest](#DocumentOnTypeFormattingRequest). + */ +type DocumentOnTypeFormattingOptions struct { + + /*FirstTriggerCharacter defined: + * A character on which formatting should be triggered, like `}`. + */ + FirstTriggerCharacter string `json:"firstTriggerCharacter"` + + /*MoreTriggerCharacter defined: + * More trigger characters. + */ + MoreTriggerCharacter []string `json:"moreTriggerCharacter,omitempty"` +} + +/*DocumentOnTypeFormattingRegistrationOptions defined: + * Registration options for a [DocumentOnTypeFormattingRequest](#DocumentOnTypeFormattingRequest). + */ +type DocumentOnTypeFormattingRegistrationOptions struct { + TextDocumentRegistrationOptions + DocumentOnTypeFormattingOptions +} + +// RenameClientCapabilities is +type RenameClientCapabilities struct { + + /*DynamicRegistration defined: + * Whether rename supports dynamic registration. + */ + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` + + /*PrepareSupport defined: + * Client supports testing for validity of rename operations + * before execution. + * + * @since version 3.12.0 + */ + PrepareSupport bool `json:"prepareSupport,omitempty"` +} + +/*RenameParams defined: + * The parameters of a [RenameRequest](#RenameRequest). + */ +type RenameParams struct { + + /*TextDocument defined: + * The document to rename. + */ + TextDocument TextDocumentIdentifier `json:"textDocument"` + + /*Position defined: + * The position at which this request was sent. + */ + Position Position `json:"position"` + + /*NewName defined: + * The new name of the symbol. If the given name is not valid the + * request must return a [ResponseError](#ResponseError) with an + * appropriate message set. + */ + NewName string `json:"newName"` + WorkDoneProgressParams +} + +/*RenameOptions defined: + * Provider options for a [RenameRequest](#RenameRequest). + */ +type RenameOptions struct { + + /*PrepareProvider defined: + * Renames should be checked and tested before being executed. + * + * @since version 3.12.0 + */ + PrepareProvider bool `json:"prepareProvider,omitempty"` + WorkDoneProgressOptions +} + +/*RenameRegistrationOptions defined: + * Registration options for a [RenameRequest](#RenameRequest). + */ +type RenameRegistrationOptions struct { + TextDocumentRegistrationOptions + RenameOptions +} + +// PrepareRenameParams is +type PrepareRenameParams struct { + TextDocumentPositionParams + WorkDoneProgressParams +} + +/*ExecuteCommandClientCapabilities defined: + * The client capabilities of a [ExecuteCommandRequest](#ExecuteCommandRequest). + */ +type ExecuteCommandClientCapabilities struct { + + /*DynamicRegistration defined: + * Execute command supports dynamic registration. + */ + DynamicRegistration bool `json:"dynamicRegistration,omitempty"` +} + +/*ExecuteCommandParams defined: + * The parameters of a [ExecuteCommandRequest](#ExecuteCommandRequest). + */ +type ExecuteCommandParams struct { + + /*Command defined: + * The identifier of the actual command handler. + */ + Command string `json:"command"` + + /*Arguments defined: + * Arguments that the command should be invoked with. + */ + Arguments []interface{} `json:"arguments,omitempty"` + WorkDoneProgressParams +} + +/*ExecuteCommandOptions defined: + * The server capabilities of a [ExecuteCommandRequest](#ExecuteCommandRequest). + */ +type ExecuteCommandOptions struct { + + /*Commands defined: + * The commands to be executed on the server + */ + Commands []string `json:"commands"` + WorkDoneProgressOptions +} + +/*ExecuteCommandRegistrationOptions defined: + * Registration options for a [ExecuteCommandRequest](#ExecuteCommandRequest). + */ +type ExecuteCommandRegistrationOptions struct { + ExecuteCommandOptions +} + +// WorkspaceEditClientCapabilities is +type WorkspaceEditClientCapabilities struct { + + /*DocumentChanges defined: + * The client supports versioned document changes in `WorkspaceEdit`s + */ + DocumentChanges bool `json:"documentChanges,omitempty"` + + /*ResourceOperations defined: + * The resource operations the client supports. Clients should at least + * support 'create', 'rename' and 'delete' files and folders. + * + * @since 3.13.0 + */ + ResourceOperations []ResourceOperationKind `json:"resourceOperations,omitempty"` + + /*FailureHandling defined: + * The failure handling strategy of a client if applying the workspace edit + * fails. + * + * @since 3.13.0 + */ + FailureHandling FailureHandlingKind `json:"failureHandling,omitempty"` +} + +/*ApplyWorkspaceEditParams defined: + * The parameters passed via a apply workspace edit request. + */ +type ApplyWorkspaceEditParams struct { + + /*Label defined: + * An optional label of the workspace edit. This label is + * presented in the user interface for example on an undo + * stack to undo the workspace edit. + */ + Label string `json:"label,omitempty"` + + /*Edit defined: + * The edits to apply. + */ + Edit WorkspaceEdit `json:"edit"` +} + +/*ApplyWorkspaceEditResponse defined: + * A response returned from the apply workspace edit request. + */ +type ApplyWorkspaceEditResponse struct { + + /*Applied defined: + * Indicates whether the edit was applied or not. + */ + Applied bool `json:"applied"` + + /*FailureReason defined: + * An optional textual description for why the edit was not applied. + * This may be used by the server for diagnostic logging or to provide + * a suitable error for a request that triggered the edit. + */ + FailureReason string `json:"failureReason,omitempty"` + + /*FailedChange defined: + * Depending on the client's failure handling strategy `failedChange` might + * contain the index of the change that failed. This property is only available + * if the client signals a `failureHandlingStrategy` in its client capabilities. + */ + FailedChange float64 `json:"failedChange,omitempty"` +} + +/*Position defined: + * Position in a text document expressed as zero-based line and character offset. + * The offsets are based on a UTF-16 string representation. So a string of the form + * `a𐐀b` the character offset of the character `a` is 0, the character offset of `𐐀` + * is 1 and the character offset of b is 3 since `𐐀` is represented using two code + * units in UTF-16. + * + * Positions are line end character agnostic. So you can not specify a position that + * denotes `\r|\n` or `\n|` where `|` represents the character offset. + */ +type Position struct { + + /*Line defined: + * Line position in a document (zero-based). + * If a line number is greater than the number of lines in a document, it defaults back to the number of lines in the document. + * If a line number is negative, it defaults to 0. + */ + Line float64 `json:"line"` + + /*Character defined: + * Character offset on a line in a document (zero-based). Assuming that the line is + * represented as a string, the `character` value represents the gap between the + * `character` and `character + 1`. + * + * If the character value is greater than the line length it defaults back to the + * line length. + * If a line number is negative, it defaults to 0. + */ + Character float64 `json:"character"` +} + +/*Range defined: + * A range in a text document expressed as (zero-based) start and end positions. + * + * If you want to specify a range that contains a line including the line ending + * character(s) then use an end position denoting the start of the next line. + * For example: + * ```ts + * { + * start: { line: 5, character: 23 } + * end : { line 6, character : 0 } + * } + * ``` + */ +type Range struct { + + /*Start defined: + * The range's start position + */ + Start Position `json:"start"` + + /*End defined: + * The range's end position. + */ + End Position `json:"end"` +} + +/*Location defined: + * Represents a location inside a resource, such as a line + * inside a text file. + */ +type Location struct { + + // URI is + URI DocumentURI `json:"uri"` + + // Range is + Range Range `json:"range"` +} + +/*LocationLink defined: + * Represents the connection of two locations. Provides additional metadata over normal [locations](#Location), + * including an origin range. + */ +type LocationLink struct { + + /*OriginSelectionRange defined: + * Span of the origin of this link. + * + * Used as the underlined span for mouse definition hover. Defaults to the word range at + * the definition position. + */ + OriginSelectionRange *Range `json:"originSelectionRange,omitempty"` + + /*TargetURI defined: + * The target resource identifier of this link. + */ + TargetURI DocumentURI `json:"targetUri"` + + /*TargetRange defined: + * The full target range of this link. If the target for example is a symbol then target range is the + * range enclosing this symbol not including leading/trailing whitespace but everything else + * like comments. This information is typically used to highlight the range in the editor. + */ + TargetRange Range `json:"targetRange"` + + /*TargetSelectionRange defined: + * The range that should be selected and revealed when this link is being followed, e.g the name of a function. + * Must be contained by the the `targetRange`. See also `DocumentSymbol#range` + */ + TargetSelectionRange Range `json:"targetSelectionRange"` +} + +/*Color defined: + * Represents a color in RGBA space. + */ +type Color struct { + + /*Red defined: + * The red component of this color in the range [0-1]. + */ + Red float64 `json:"red"` + + /*Green defined: + * The green component of this color in the range [0-1]. + */ + Green float64 `json:"green"` + + /*Blue defined: + * The blue component of this color in the range [0-1]. + */ + Blue float64 `json:"blue"` + + /*Alpha defined: + * The alpha component of this color in the range [0-1]. + */ + Alpha float64 `json:"alpha"` +} + +/*ColorInformation defined: + * Represents a color range from a document. + */ +type ColorInformation struct { + + /*Range defined: + * The range in the document where this color appers. + */ + Range Range `json:"range"` + + /*Color defined: + * The actual color value for this color range. + */ + Color Color `json:"color"` +} + +// ColorPresentation is +type ColorPresentation struct { + + /*Label defined: + * The label of this color presentation. It will be shown on the color + * picker header. By default this is also the text that is inserted when selecting + * this color presentation. + */ + Label string `json:"label"` + + /*TextEdit defined: + * An [edit](#TextEdit) which is applied to a document when selecting + * this presentation for the color. When `falsy` the [label](#ColorPresentation.label) + * is used. + */ + TextEdit *TextEdit `json:"textEdit,omitempty"` + + /*AdditionalTextEdits defined: + * An optional array of additional [text edits](#TextEdit) that are applied when + * selecting this color presentation. Edits must not overlap with the main [edit](#ColorPresentation.textEdit) nor with themselves. + */ + AdditionalTextEdits []TextEdit `json:"additionalTextEdits,omitempty"` +} + +/*DiagnosticRelatedInformation defined: + * Represents a related message and source code location for a diagnostic. This should be + * used to point to code locations that cause or related to a diagnostics, e.g when duplicating + * a symbol in a scope. + */ +type DiagnosticRelatedInformation struct { + + /*Location defined: + * The location of this related diagnostic information. + */ + Location Location `json:"location"` + + /*Message defined: + * The message of this related diagnostic information. + */ + Message string `json:"message"` +} + +/*Diagnostic defined: + * Represents a diagnostic, such as a compiler error or warning. Diagnostic objects + * are only valid in the scope of a resource. + */ +type Diagnostic struct { + + /*Range defined: + * The range at which the message applies + */ + Range Range `json:"range"` + + /*Severity defined: + * The diagnostic's severity. Can be omitted. If omitted it is up to the + * client to interpret diagnostics as error, warning, info or hint. + */ + Severity DiagnosticSeverity `json:"severity,omitempty"` + + /*Code defined: + * The diagnostic's code, which usually appear in the user interface. + */ + Code interface{} `json:"code,omitempty"` // number | string + + /*Source defined: + * A human-readable string describing the source of this + * diagnostic, e.g. 'typescript' or 'super lint'. It usually + * appears in the user interface. + */ + Source string `json:"source,omitempty"` + + /*Message defined: + * The diagnostic's message. It usually appears in the user interface + */ + Message string `json:"message"` + + /*Tags defined: + * Additional metadata about the diagnostic. + */ + Tags []DiagnosticTag `json:"tags,omitempty"` + + /*RelatedInformation defined: + * An array of related diagnostic information, e.g. when symbol-names within + * a scope collide all definitions can be marked via this property. + */ + RelatedInformation []DiagnosticRelatedInformation `json:"relatedInformation,omitempty"` +} + +/*Command defined: + * Represents a reference to a command. Provides a title which + * will be used to represent a command in the UI and, optionally, + * an array of arguments which will be passed to the command handler + * function when invoked. + */ +type Command struct { + + /*Title defined: + * Title of the command, like `save`. + */ + Title string `json:"title"` + + /*Command defined: + * The identifier of the actual command handler. + */ + Command string `json:"command"` + + /*Arguments defined: + * Arguments that the command handler should be + * invoked with. + */ + Arguments []interface{} `json:"arguments,omitempty"` +} + +/*TextEdit defined: + * A text edit applicable to a text document. + */ +type TextEdit struct { + + /*Range defined: + * The range of the text document to be manipulated. To insert + * text into a document create a range where start === end. + */ + Range Range `json:"range"` + + /*NewText defined: + * The string to be inserted. For delete operations use an + * empty string. + */ + NewText string `json:"newText"` +} + +/*TextDocumentEdit defined: + * Describes textual changes on a text document. + */ +type TextDocumentEdit struct { + + /*TextDocument defined: + * The text document to change. + */ + TextDocument VersionedTextDocumentIdentifier `json:"textDocument"` + + /*Edits defined: + * The edits to be applied. + */ + Edits []TextEdit `json:"edits"` +} + +// ResourceOperation is +type ResourceOperation struct { + + // Kind is + Kind string `json:"kind"` +} + +/*CreateFileOptions defined: + * Options to create a file. + */ +type CreateFileOptions struct { + + /*Overwrite defined: + * Overwrite existing file. Overwrite wins over `ignoreIfExists` + */ + Overwrite bool `json:"overwrite,omitempty"` + + /*IgnoreIfExists defined: + * Ignore if exists. + */ + IgnoreIfExists bool `json:"ignoreIfExists,omitempty"` +} + +/*CreateFile defined: + * Create file operation. + */ +type CreateFile struct { + + /*Kind defined: + * A create + */ + Kind string `json:"kind"` // 'create' + + /*URI defined: + * The resource to create. + */ + URI DocumentURI `json:"uri"` + + /*Options defined: + * Additional options + */ + Options *CreateFileOptions `json:"options,omitempty"` +} + +/*RenameFileOptions defined: + * Rename file options + */ +type RenameFileOptions struct { + + /*Overwrite defined: + * Overwrite target if existing. Overwrite wins over `ignoreIfExists` + */ + Overwrite bool `json:"overwrite,omitempty"` + + /*IgnoreIfExists defined: + * Ignores if target exists. + */ + IgnoreIfExists bool `json:"ignoreIfExists,omitempty"` +} + +/*RenameFile defined: + * Rename file operation + */ +type RenameFile struct { + + /*Kind defined: + * A rename + */ + Kind string `json:"kind"` // 'rename' + + /*OldURI defined: + * The old (existing) location. + */ + OldURI DocumentURI `json:"oldUri"` + + /*NewURI defined: + * The new location. + */ + NewURI DocumentURI `json:"newUri"` + + /*Options defined: + * Rename options. + */ + Options *RenameFileOptions `json:"options,omitempty"` +} + +/*DeleteFileOptions defined: + * Delete file options + */ +type DeleteFileOptions struct { + + /*Recursive defined: + * Delete the content recursively if a folder is denoted. + */ + Recursive bool `json:"recursive,omitempty"` + + /*IgnoreIfNotExists defined: + * Ignore the operation if the file doesn't exist. + */ + IgnoreIfNotExists bool `json:"ignoreIfNotExists,omitempty"` +} + +/*DeleteFile defined: + * Delete file operation + */ +type DeleteFile struct { + + /*Kind defined: + * A delete + */ + Kind string `json:"kind"` // 'delete' + + /*URI defined: + * The file to delete. + */ + URI DocumentURI `json:"uri"` + + /*Options defined: + * Delete options. + */ + Options *DeleteFileOptions `json:"options,omitempty"` +} + +/*WorkspaceEdit defined: + * A workspace edit represents changes to many resources managed in the workspace. The edit + * should either provide `changes` or `documentChanges`. If documentChanges are present + * they are preferred over `changes` if the client can handle versioned document edits. + */ +type WorkspaceEdit struct { + + /*Changes defined: + * Holds changes to existing resources. + */ + Changes *map[string][]TextEdit `json:"changes,omitempty"` // [uri: string]: TextEdit[]; + + /*DocumentChanges defined: + * Depending on the client capability `workspace.workspaceEdit.resourceOperations` document changes + * are either an array of `TextDocumentEdit`s to express changes to n different text documents + * where each text document edit addresses a specific version of a text document. Or it can contain + * above `TextDocumentEdit`s mixed with create, rename and delete file / folder operations. + * + * Whether a client supports versioned document edits is expressed via + * `workspace.workspaceEdit.documentChanges` client capability. + * + * If a client neither supports `documentChanges` nor `workspace.workspaceEdit.resourceOperations` then + * only plain `TextEdit`s using the `changes` property are supported. + */ + DocumentChanges []TextDocumentEdit `json:"documentChanges,omitempty"` // (TextDocumentEdit | CreateFile | RenameFile | DeleteFile) +} + +/*TextEditChange defined: + * A change to capture text edits for existing resources. + */ +type TextEditChange struct { +} + +/*TextDocumentIdentifier defined: + * A literal to identify a text document in the client. + */ +type TextDocumentIdentifier struct { + + /*URI defined: + * The text document's uri. + */ + URI DocumentURI `json:"uri"` +} + +/*VersionedTextDocumentIdentifier defined: + * An identifier to denote a specific version of a text document. + */ +type VersionedTextDocumentIdentifier struct { + + /*Version defined: + * The version number of this document. If a versioned text document identifier + * is sent from the server to the client and the file is not open in the editor + * (the server has not received an open notification before) the server can send + * `null` to indicate that the version is unknown and the content on disk is the + * truth (as speced with document content ownership). + */ + Version float64 `json:"version"` + TextDocumentIdentifier +} + +/*TextDocumentItem defined: + * An item to transfer a text document from the client to the + * server. + */ +type TextDocumentItem struct { + + /*URI defined: + * The text document's uri. + */ + URI DocumentURI `json:"uri"` + + /*LanguageID defined: + * The text document's language identifier + */ + LanguageID string `json:"languageId"` + + /*Version defined: + * The version number of this document (it will increase after each + * change, including undo/redo). + */ + Version float64 `json:"version"` + + /*Text defined: + * The content of the opened text document. + */ + Text string `json:"text"` +} + +/*MarkupContent defined: + * A `MarkupContent` literal represents a string value which content is interpreted base on its + * kind flag. Currently the protocol supports `plaintext` and `markdown` as markup kinds. + * + * If the kind is `markdown` then the value can contain fenced code blocks like in GitHub issues. + * See https://help.github.com/articles/creating-and-highlighting-code-blocks/#syntax-highlighting + * + * Here is an example how such a string can be constructed using JavaScript / TypeScript: + * ```ts + * let markdown: MarkdownContent = { + * kind: MarkupKind.Markdown, + * value: [ + * '# Header', + * 'Some text', + * '```typescript', + * 'someCode();', + * '```' + * ].join('\n') + * }; + * ``` + * + * *Please Note* that clients might sanitize the return markdown. A client could decide to + * remove HTML from the markdown to avoid script execution. + */ +type MarkupContent struct { + + /*Kind defined: + * The type of the Markup + */ + Kind MarkupKind `json:"kind"` + + /*Value defined: + * The content itself + */ + Value string `json:"value"` +} + +/*CompletionItem defined: + * A completion item represents a text snippet that is + * proposed to complete text that is being typed. + */ +type CompletionItem struct { + + /*Label defined: + * The label of this completion item. By default + * also the text that is inserted when selecting + * this completion. + */ + Label string `json:"label"` + + /*Kind defined: + * The kind of this completion item. Based of the kind + * an icon is chosen by the editor. + */ + Kind CompletionItemKind `json:"kind,omitempty"` + + /*Tags defined: + * Tags for this completion item. + * + * @since 3.15.0 + */ + Tags []CompletionItemTag `json:"tags,omitempty"` + + /*Detail defined: + * A human-readable string with additional information + * about this item, like type or symbol information. + */ + Detail string `json:"detail,omitempty"` + + /*Documentation defined: + * A human-readable string that represents a doc-comment. + */ + Documentation string `json:"documentation,omitempty"` // string | MarkupContent + + /*Deprecated defined: + * Indicates if this item is deprecated. + * @deprecated Use `tags` instead. + */ + Deprecated bool `json:"deprecated,omitempty"` + + /*Preselect defined: + * Select this item when showing. + * + * *Note* that only one completion item can be selected and that the + * tool / client decides which item that is. The rule is that the *first* + * item of those that match best is selected. + */ + Preselect bool `json:"preselect,omitempty"` + + /*SortText defined: + * A string that should be used when comparing this item + * with other items. When `falsy` the [label](#CompletionItem.label) + * is used. + */ + SortText string `json:"sortText,omitempty"` + + /*FilterText defined: + * A string that should be used when filtering a set of + * completion items. When `falsy` the [label](#CompletionItem.label) + * is used. + */ + FilterText string `json:"filterText,omitempty"` + + /*InsertText defined: + * A string that should be inserted into a document when selecting + * this completion. When `falsy` the [label](#CompletionItem.label) + * is used. + * + * The `insertText` is subject to interpretation by the client side. + * Some tools might not take the string literally. For example + * VS Code when code complete is requested in this example `con` + * and a completion item with an `insertText` of `console` is provided it + * will only insert `sole`. Therefore it is recommended to use `textEdit` instead + * since it avoids additional client side interpretation. + */ + InsertText string `json:"insertText,omitempty"` + + /*InsertTextFormat defined: + * The format of the insert text. The format applies to both the `insertText` property + * and the `newText` property of a provided `textEdit`. + */ + InsertTextFormat InsertTextFormat `json:"insertTextFormat,omitempty"` + + /*TextEdit defined: + * An [edit](#TextEdit) which is applied to a document when selecting + * this completion. When an edit is provided the value of + * [insertText](#CompletionItem.insertText) is ignored. + * + * *Note:* The text edit's range must be a [single line] and it must contain the position + * at which completion has been requested. + */ + TextEdit *TextEdit `json:"textEdit,omitempty"` + + /*AdditionalTextEdits defined: + * An optional array of additional [text edits](#TextEdit) that are applied when + * selecting this completion. Edits must not overlap (including the same insert position) + * with the main [edit](#CompletionItem.textEdit) nor with themselves. + * + * Additional text edits should be used to change text unrelated to the current cursor position + * (for example adding an import statement at the top of the file if the completion item will + * insert an unqualified type). + */ + AdditionalTextEdits []TextEdit `json:"additionalTextEdits,omitempty"` + + /*CommitCharacters defined: + * An optional set of characters that when pressed while this completion is active will accept it first and + * then type that character. *Note* that all commit characters should have `length=1` and that superfluous + * characters will be ignored. + */ + CommitCharacters []string `json:"commitCharacters,omitempty"` + + /*Command defined: + * An optional [command](#Command) that is executed *after* inserting this completion. *Note* that + * additional modifications to the current document should be described with the + * [additionalTextEdits](#CompletionItem.additionalTextEdits)-property. + */ + Command *Command `json:"command,omitempty"` + + /*Data defined: + * An data entry field that is preserved on a completion item between + * a [CompletionRequest](#CompletionRequest) and a [CompletionResolveRequest] + * (#CompletionResolveRequest) + */ + Data interface{} `json:"data,omitempty"` +} + +/*CompletionList defined: + * Represents a collection of [completion items](#CompletionItem) to be presented + * in the editor. + */ +type CompletionList struct { + + /*IsIncomplete defined: + * This list it not complete. Further typing results in recomputing this list. + */ + IsIncomplete bool `json:"isIncomplete"` + + /*Items defined: + * The completion items. + */ + Items []CompletionItem `json:"items"` +} + +/*Hover defined: + * The result of a hover request. + */ +type Hover struct { + + /*Contents defined: + * The hover's content + */ + Contents MarkupContent `json:"contents"` // MarkupContent | MarkedString | MarkedString[] + + /*Range defined: + * An optional range + */ + Range *Range `json:"range,omitempty"` +} + +/*ParameterInformation defined: + * Represents a parameter of a callable-signature. A parameter can + * have a label and a doc-comment. + */ +type ParameterInformation struct { + + /*Label defined: + * The label of this parameter information. + * + * Either a string or an inclusive start and exclusive end offsets within its containing + * signature label. (see SignatureInformation.label). The offsets are based on a UTF-16 + * string representation as `Position` and `Range` does. + * + * *Note*: a label of type string should be a substring of its containing signature label. + * Its intended use case is to highlight the parameter label part in the `SignatureInformation.label`. + */ + Label string `json:"label"` // string | [number, number] + + /*Documentation defined: + * The human-readable doc-comment of this signature. Will be shown + * in the UI but can be omitted. + */ + Documentation string `json:"documentation,omitempty"` // string | MarkupContent +} + +/*SignatureInformation defined: + * Represents the signature of something callable. A signature + * can have a label, like a function-name, a doc-comment, and + * a set of parameters. + */ +type SignatureInformation struct { + + /*Label defined: + * The label of this signature. Will be shown in + * the UI. + */ + Label string `json:"label"` + + /*Documentation defined: + * The human-readable doc-comment of this signature. Will be shown + * in the UI but can be omitted. + */ + Documentation string `json:"documentation,omitempty"` // string | MarkupContent + + /*Parameters defined: + * The parameters of this signature. + */ + Parameters []ParameterInformation `json:"parameters,omitempty"` +} + +/*SignatureHelp defined: + * Signature help represents the signature of something + * callable. There can be multiple signature but only one + * active and only one active parameter. + */ +type SignatureHelp struct { + + /*Signatures defined: + * One or more signatures. + */ + Signatures []SignatureInformation `json:"signatures"` + + /*ActiveSignature defined: + * The active signature. Set to `null` if no + * signatures exist. + */ + ActiveSignature float64 `json:"activeSignature"` + + /*ActiveParameter defined: + * The active parameter of the active signature. Set to `null` + * if the active signature has no parameters. + */ + ActiveParameter float64 `json:"activeParameter"` +} + +/*ReferenceContext defined: + * Value-object that contains additional information when + * requesting references. + */ +type ReferenceContext struct { + + /*IncludeDeclaration defined: + * Include the declaration of the current symbol. + */ + IncludeDeclaration bool `json:"includeDeclaration"` +} + +/*DocumentHighlight defined: + * A document highlight is a range inside a text document which deserves + * special attention. Usually a document highlight is visualized by changing + * the background color of its range. + */ +type DocumentHighlight struct { + + /*Range defined: + * The range this highlight applies to. + */ + Range Range `json:"range"` + + /*Kind defined: + * The highlight kind, default is [text](#DocumentHighlightKind.Text). + */ + Kind *DocumentHighlightKind `json:"kind,omitempty"` +} + +/*SymbolInformation defined: + * Represents information about programming constructs like variables, classes, + * interfaces etc. + */ +type SymbolInformation struct { + + /*Name defined: + * The name of this symbol. + */ + Name string `json:"name"` + + /*Kind defined: + * The kind of this symbol. + */ + Kind SymbolKind `json:"kind"` + + /*Deprecated defined: + * Indicates if this symbol is deprecated. + */ + Deprecated bool `json:"deprecated,omitempty"` + + /*Location defined: + * The location of this symbol. The location's range is used by a tool + * to reveal the location in the editor. If the symbol is selected in the + * tool the range's start information is used to position the cursor. So + * the range usually spans more than the actual symbol's name and does + * normally include thinks like visibility modifiers. + * + * The range doesn't have to denote a node range in the sense of a abstract + * syntax tree. It can therefore not be used to re-construct a hierarchy of + * the symbols. + */ + Location Location `json:"location"` + + /*ContainerName defined: + * The name of the symbol containing this symbol. This information is for + * user interface purposes (e.g. to render a qualifier in the user interface + * if necessary). It can't be used to re-infer a hierarchy for the document + * symbols. + */ + ContainerName string `json:"containerName,omitempty"` +} + +/*DocumentSymbol defined: + * Represents programming constructs like variables, classes, interfaces etc. + * that appear in a document. Document symbols can be hierarchical and they + * have two ranges: one that encloses its definition and one that points to + * its most interesting range, e.g. the range of an identifier. + */ +type DocumentSymbol struct { + + /*Name defined: + * The name of this symbol. Will be displayed in the user interface and therefore must not be + * an empty string or a string only consisting of white spaces. + */ + Name string `json:"name"` + + /*Detail defined: + * More detail for this symbol, e.g the signature of a function. + */ + Detail string `json:"detail,omitempty"` + + /*Kind defined: + * The kind of this symbol. + */ + Kind SymbolKind `json:"kind"` + + /*Deprecated defined: + * Indicates if this symbol is deprecated. + */ + Deprecated bool `json:"deprecated,omitempty"` + + /*Range defined: + * The range enclosing this symbol not including leading/trailing whitespace but everything else + * like comments. This information is typically used to determine if the the clients cursor is + * inside the symbol to reveal in the symbol in the UI. + */ + Range Range `json:"range"` + + /*SelectionRange defined: + * The range that should be selected and revealed when this symbol is being picked, e.g the name of a function. + * Must be contained by the the `range`. + */ + SelectionRange Range `json:"selectionRange"` + + /*Children defined: + * Children of this symbol, e.g. properties of a class. + */ + Children []DocumentSymbol `json:"children,omitempty"` +} + +/*CodeActionContext defined: + * Contains additional diagnostic information about the context in which + * a [code action](#CodeActionProvider.provideCodeActions) is run. + */ +type CodeActionContext struct { + + /*Diagnostics defined: + * An array of diagnostics known on the client side overlapping the range provided to the + * `textDocument/codeAction` request. They are provied so that the server knows which + * errors are currently presented to the user for the given range. There is no guarantee + * that these accurately reflect the error state of the resource. The primary parameter + * to compute code actions is the provided range. + */ + Diagnostics []Diagnostic `json:"diagnostics"` + + /*Only defined: + * Requested kind of actions to return. + * + * Actions not of this kind are filtered out by the client before being shown. So servers + * can omit computing them. + */ + Only []CodeActionKind `json:"only,omitempty"` +} + +/*CodeAction defined: + * A code action represents a change that can be performed in code, e.g. to fix a problem or + * to refactor code. + * + * A CodeAction must set either `edit` and/or a `command`. If both are supplied, the `edit` is applied first, then the `command` is executed. + */ +type CodeAction struct { + + /*Title defined: + * A short, human-readable, title for this code action. + */ + Title string `json:"title"` + + /*Kind defined: + * The kind of the code action. + * + * Used to filter code actions. + */ + Kind CodeActionKind `json:"kind,omitempty"` + + /*Diagnostics defined: + * The diagnostics that this code action resolves. + */ + Diagnostics []Diagnostic `json:"diagnostics,omitempty"` + + /*IsPreferred defined: + * Marks this as a preferred action. Preferred actions are used by the `auto fix` command and can be targeted + * by keybindings. + * + * A quick fix should be marked preferred if it properly addresses the underlying error. + * A refactoring should be marked preferred if it is the most reasonable choice of actions to take. + * + * @since 3.15.0 + */ + IsPreferred bool `json:"isPreferred,omitempty"` + + /*Edit defined: + * The workspace edit this code action performs. + */ + Edit *WorkspaceEdit `json:"edit,omitempty"` + + /*Command defined: + * A command this code action executes. If a code action + * provides a edit and a command, first the edit is + * executed and then the command. + */ + Command *Command `json:"command,omitempty"` +} + +/*CodeLens defined: + * A code lens represents a [command](#Command) that should be shown along with + * source text, like the number of references, a way to run tests, etc. + * + * A code lens is _unresolved_ when no command is associated to it. For performance + * reasons the creation of a code lens and resolving should be done to two stages. + */ +type CodeLens struct { + + /*Range defined: + * The range in which this code lens is valid. Should only span a single line. + */ + Range Range `json:"range"` + + /*Command defined: + * The command this code lens represents. + */ + Command *Command `json:"command,omitempty"` + + /*Data defined: + * An data entry field that is preserved on a code lens item between + * a [CodeLensRequest](#CodeLensRequest) and a [CodeLensResolveRequest] + * (#CodeLensResolveRequest) + */ + Data interface{} `json:"data,omitempty"` +} + +/*FormattingOptions defined: + * Value-object describing what options formatting should use. + */ +type FormattingOptions struct { + + /*TabSize defined: + * Size of a tab in spaces. + */ + TabSize float64 `json:"tabSize"` + + /*InsertSpaces defined: + * Prefer spaces over tabs. + */ + InsertSpaces bool `json:"insertSpaces"` + + /*TrimTrailingWhitespace defined: + * Trim trailing whitespaces on a line. + * + * @since 3.15.0 + */ + TrimTrailingWhitespace bool `json:"trimTrailingWhitespace,omitempty"` + + /*InsertFinalNewline defined: + * Insert a newline character at the end of the file if one does not exist. + * + * @since 3.15.0 + */ + InsertFinalNewline bool `json:"insertFinalNewline,omitempty"` + + /*TrimFinalNewlines defined: + * Trim all newlines after the final newline at the end of the file. + * + * @since 3.15.0 + */ + TrimFinalNewlines bool `json:"trimFinalNewlines,omitempty"` + + /*Key defined: + * Signature for further properties. + */ + Key map[string]bool `json:"key"` // [key: string]: boolean | number | string | undefined; +} + +/*DocumentLink defined: + * A document link is a range in a text document that links to an internal or external resource, like another + * text document or a web site. + */ +type DocumentLink struct { + + /*Range defined: + * The range this link applies to. + */ + Range Range `json:"range"` + + /*Target defined: + * The uri this link points to. + */ + Target string `json:"target,omitempty"` + + /*Tooltip defined: + * The tooltip text when you hover over this link. + * + * If a tooltip is provided, is will be displayed in a string that includes instructions on how to + * trigger the link, such as `{0} (ctrl + click)`. The specific instructions vary depending on OS, + * user settings, and localization. + * + * @since 3.15.0 + */ + Tooltip string `json:"tooltip,omitempty"` + + /*Data defined: + * A data entry field that is preserved on a document link between a + * DocumentLinkRequest and a DocumentLinkResolveRequest. + */ + Data interface{} `json:"data,omitempty"` +} + +/*SelectionRange defined: + * A selection range represents a part of a selection hierarchy. A selection range + * may have a parent selection range that contains it. + */ +type SelectionRange struct { + + /*Range defined: + * The [range](#Range) of this selection range. + */ + Range Range `json:"range"` + + /*Parent defined: + * The parent selection range containing this range. Therefore `parent.range` must contain `this.range`. + */ + Parent *SelectionRange `json:"parent,omitempty"` +} + +/*TextDocument defined: + * A simple text document. Not to be implemented. + */ +type TextDocument struct { + + /*URI defined: + * The associated URI for this document. Most documents have the __file__-scheme, indicating that they + * represent files on disk. However, some documents may have other schemes indicating that they are not + * available on disk. + * + * @readonly + */ + URI DocumentURI `json:"uri"` + + /*LanguageID defined: + * The identifier of the language associated with this document. + * + * @readonly + */ + LanguageID string `json:"languageId"` + + /*Version defined: + * The version number of this document (it will increase after each + * change, including undo/redo). + * + * @readonly + */ + Version float64 `json:"version"` + + /*LineCount defined: + * The number of lines in this document. + * + * @readonly + */ + LineCount float64 `json:"lineCount"` +} + +/*TextDocumentChangeEvent defined: + * Event to signal changes to a simple text document. + */ +type TextDocumentChangeEvent struct { + + /*Document defined: + * The document that has changed. + */ + Document TextDocument `json:"document"` +} + +// TextDocumentWillSaveEvent is +type TextDocumentWillSaveEvent struct { + + /*Document defined: + * The document that will be saved + */ + Document TextDocument `json:"document"` + + /*Reason defined: + * The reason why save was triggered. + */ + Reason TextDocumentSaveReason `json:"reason"` +} + +/*TextDocumentContentChangeEvent defined: + * An event describing a change to a text document. If range and rangeLength are omitted + * the new text is considered to be the full content of the document. + */ +type TextDocumentContentChangeEvent struct { + + /*Range defined: + * The range of the document that changed. + */ + Range *Range `json:"range,omitempty"` + + /*RangeLength defined: + * The length of the range that got replaced. + */ + RangeLength float64 `json:"rangeLength,omitempty"` + + /*Text defined: + * The new text of the document. + */ + Text string `json:"text"` +} + +// ProgressParams is +type ProgressParams struct { + + /*Token defined: + * The progress token provided by the client or server. + */ + Token ProgressToken `json:"token"` + + /*Value defined: + * The progress data. + */ + Value interface{} `json:"value"` +} + +// SetTraceParams is +type SetTraceParams struct { + + // Value is + Value TraceValues `json:"value"` +} + +// LogTraceParams is +type LogTraceParams struct { + + // Message is + Message string `json:"message"` + + // Verbose is + Verbose string `json:"verbose,omitempty"` +} + +// Tracer is +type Tracer struct { +} + +// FoldingRangeKind defines constants +type FoldingRangeKind string + +// ResourceOperationKind defines constants +type ResourceOperationKind string + +// FailureHandlingKind defines constants +type FailureHandlingKind string + +// InitializeError defines constants +type InitializeError float64 + +// MessageType defines constants +type MessageType float64 + +// TextDocumentSyncKind defines constants +type TextDocumentSyncKind float64 + +// FileChangeType defines constants +type FileChangeType float64 + +// WatchKind defines constants +type WatchKind float64 + +// CompletionTriggerKind defines constants +type CompletionTriggerKind float64 + +// SignatureHelpTriggerKind defines constants +type SignatureHelpTriggerKind float64 + +// DiagnosticSeverity defines constants +type DiagnosticSeverity float64 + +// DiagnosticTag defines constants +type DiagnosticTag float64 + +// MarkupKind defines constants +type MarkupKind string + +// CompletionItemKind defines constants +type CompletionItemKind float64 + +// InsertTextFormat defines constants +type InsertTextFormat float64 + +// CompletionItemTag defines constants +type CompletionItemTag float64 + +// DocumentHighlightKind defines constants +type DocumentHighlightKind float64 + +// SymbolKind defines constants +type SymbolKind float64 + +// CodeActionKind defines constants +type CodeActionKind string + +// TextDocumentSaveReason defines constants +type TextDocumentSaveReason float64 + +// ErrorCodes defines constants +type ErrorCodes float64 + +// Touch defines constants +type Touch float64 + +// Trace defines constants +type Trace string + +// TraceFormat defines constants +type TraceFormat string + +// ConnectionErrors defines constants +type ConnectionErrors float64 + +// ConnectionState defines constants +type ConnectionState float64 + +const ( + + /*Comment defined: + * Folding range for a comment + */ + Comment FoldingRangeKind = "comment" + + /*Imports defined: + * Folding range for a imports or includes + */ + Imports FoldingRangeKind = "imports" + + /*Region defined: + * Folding range for a region (e.g. `#region`) + */ + Region FoldingRangeKind = "region" + + /*Create defined: + * Supports creating new files and folders. + */ + Create ResourceOperationKind = "create" + + /*Rename defined: + * Supports renaming existing files and folders. + */ + Rename ResourceOperationKind = "rename" + + /*Delete defined: + * Supports deleting existing files and folders. + */ + Delete ResourceOperationKind = "delete" + + /*Abort defined: + * Applying the workspace change is simply aborted if one of the changes provided + * fails. All operations executed before the failing operation stay executed. + */ + Abort FailureHandlingKind = "abort" + + /*Transactional defined: + * All operations are executed transactional. That means they either all + * succeed or no changes at all are applied to the workspace. + */ + Transactional FailureHandlingKind = "transactional" + + /*TextOnlyTransactional defined: + * If the workspace edit contains only textual file changes they are executed transactional. + * If resource changes (create, rename or delete file) are part of the change the failure + * handling startegy is abort. + */ + TextOnlyTransactional FailureHandlingKind = "textOnlyTransactional" + + /*Undo defined: + * The client tries to undo the operations already executed. But there is no + * guaruntee that this is succeeding. + */ + Undo FailureHandlingKind = "undo" + + /*UnknownProtocolVersion defined: + * If the protocol version provided by the client can't be handled by the server. + * @deprecated This initialize error got replaced by client capabilities. There is + * no version handshake in version 3.0x + */ + UnknownProtocolVersion InitializeError = 1 + + /*Error defined: + * An error message. + */ + Error MessageType = 1 + + /*Warning defined: + * A warning message. + */ + Warning MessageType = 2 + + /*Info defined: + * An information message. + */ + Info MessageType = 3 + + /*Log defined: + * A log message. + */ + Log MessageType = 4 + + /*None defined: + * Documents should not be synced at all. + */ + None TextDocumentSyncKind = 0 + + /*Full defined: + * Documents are synced by always sending the full content + * of the document. + */ + Full TextDocumentSyncKind = 1 + + /*Incremental defined: + * Documents are synced by sending the full content on open. + * After that only incremental updates to the document are + * send. + */ + Incremental TextDocumentSyncKind = 2 + + /*Created defined: + * The file got created. + */ + Created FileChangeType = 1 + + /*Changed defined: + * The file got changed. + */ + Changed FileChangeType = 2 + + /*Deleted defined: + * The file got deleted. + */ + Deleted FileChangeType = 3 + + /*WatchCreate defined: + * Interested in create events. + */ + WatchCreate WatchKind = 1 + + /*WatchChange defined: + * Interested in change events + */ + WatchChange WatchKind = 2 + + /*WatchDelete defined: + * Interested in delete events + */ + WatchDelete WatchKind = 4 + + /*Invoked defined: + * Completion was triggered by typing an identifier (24x7 code + * complete), manual invocation (e.g Ctrl+Space) or via API. + */ + Invoked CompletionTriggerKind = 1 + + /*TriggerCharacter defined: + * Completion was triggered by a trigger character specified by + * the `triggerCharacters` properties of the `CompletionRegistrationOptions`. + */ + TriggerCharacter CompletionTriggerKind = 2 + + /*TriggerForIncompleteCompletions defined: + * Completion was re-triggered as current completion list is incomplete + */ + TriggerForIncompleteCompletions CompletionTriggerKind = 3 + + /*ContentChange defined: + * Signature help was triggered by the cursor moving or by the document content changing. + */ + ContentChange SignatureHelpTriggerKind = 3 + + /*SeverityError defined: + * Reports an error. + */ + SeverityError DiagnosticSeverity = 1 + + /*SeverityWarning defined: + * Reports a warning. + */ + SeverityWarning DiagnosticSeverity = 2 + + /*SeverityInformation defined: + * Reports an information. + */ + SeverityInformation DiagnosticSeverity = 3 + + /*SeverityHint defined: + * Reports a hint. + */ + SeverityHint DiagnosticSeverity = 4 + + /*Unnecessary defined: + * Unused or unnecessary code. + * + * Clients are allowed to render diagnostics with this tag faded out instead of having + * an error squiggle. + */ + Unnecessary DiagnosticTag = 1 + + /*Deprecated defined: + * Deprecated or obsolete code. + * + * Clients are allowed to rendered diagnostics with this tag strike through. + */ + Deprecated DiagnosticTag = 2 + + /*PlainText defined: + * Plain text is supported as a content format + */ + PlainText MarkupKind = "plaintext" + + /*Markdown defined: + * Markdown is supported as a content format + */ + Markdown MarkupKind = "markdown" + + // TextCompletion is + TextCompletion CompletionItemKind = 1 + + // MethodCompletion is + MethodCompletion CompletionItemKind = 2 + + // FunctionCompletion is + FunctionCompletion CompletionItemKind = 3 + + // ConstructorCompletion is + ConstructorCompletion CompletionItemKind = 4 + + // FieldCompletion is + FieldCompletion CompletionItemKind = 5 + + // VariableCompletion is + VariableCompletion CompletionItemKind = 6 + + // ClassCompletion is + ClassCompletion CompletionItemKind = 7 + + // InterfaceCompletion is + InterfaceCompletion CompletionItemKind = 8 + + // ModuleCompletion is + ModuleCompletion CompletionItemKind = 9 + + // PropertyCompletion is + PropertyCompletion CompletionItemKind = 10 + + // UnitCompletion is + UnitCompletion CompletionItemKind = 11 + + // ValueCompletion is + ValueCompletion CompletionItemKind = 12 + + // EnumCompletion is + EnumCompletion CompletionItemKind = 13 + + // KeywordCompletion is + KeywordCompletion CompletionItemKind = 14 + + // SnippetCompletion is + SnippetCompletion CompletionItemKind = 15 + + // ColorCompletion is + ColorCompletion CompletionItemKind = 16 + + // FileCompletion is + FileCompletion CompletionItemKind = 17 + + // ReferenceCompletion is + ReferenceCompletion CompletionItemKind = 18 + + // FolderCompletion is + FolderCompletion CompletionItemKind = 19 + + // EnumMemberCompletion is + EnumMemberCompletion CompletionItemKind = 20 + + // ConstantCompletion is + ConstantCompletion CompletionItemKind = 21 + + // StructCompletion is + StructCompletion CompletionItemKind = 22 + + // EventCompletion is + EventCompletion CompletionItemKind = 23 + + // OperatorCompletion is + OperatorCompletion CompletionItemKind = 24 + + // TypeParameterCompletion is + TypeParameterCompletion CompletionItemKind = 25 + + /*PlainTextTextFormat defined: + * The primary text to be inserted is treated as a plain string. + */ + PlainTextTextFormat InsertTextFormat = 1 + + /*SnippetTextFormat defined: + * The primary text to be inserted is treated as a snippet. + * + * A snippet can define tab stops and placeholders with `$1`, `$2` + * and `${3:foo}`. `$0` defines the final tab stop, it defaults to + * the end of the snippet. Placeholders with equal identifiers are linked, + * that is typing in one will update others too. + * + * See also: https://github.com/Microsoft/vscode/blob/master/src/vs/editor/contrib/snippet/common/snippet.md + */ + SnippetTextFormat InsertTextFormat = 2 + + /*Text defined: + * A textual occurrence. + */ + Text DocumentHighlightKind = 1 + + /*Read defined: + * Read-access of a symbol, like reading a variable. + */ + Read DocumentHighlightKind = 2 + + /*Write defined: + * Write-access of a symbol, like writing to a variable. + */ + Write DocumentHighlightKind = 3 + + // File is + File SymbolKind = 1 + + // Module is + Module SymbolKind = 2 + + // Namespace is + Namespace SymbolKind = 3 + + // Package is + Package SymbolKind = 4 + + // Class is + Class SymbolKind = 5 + + // Method is + Method SymbolKind = 6 + + // Property is + Property SymbolKind = 7 + + // Field is + Field SymbolKind = 8 + + // Constructor is + Constructor SymbolKind = 9 + + // Enum is + Enum SymbolKind = 10 + + // Interface is + Interface SymbolKind = 11 + + // Function is + Function SymbolKind = 12 + + // Variable is + Variable SymbolKind = 13 + + // Constant is + Constant SymbolKind = 14 + + // String is + String SymbolKind = 15 + + // Number is + Number SymbolKind = 16 + + // Boolean is + Boolean SymbolKind = 17 + + // Array is + Array SymbolKind = 18 + + // Object is + Object SymbolKind = 19 + + // Key is + Key SymbolKind = 20 + + // Null is + Null SymbolKind = 21 + + // EnumMember is + EnumMember SymbolKind = 22 + + // Struct is + Struct SymbolKind = 23 + + // Event is + Event SymbolKind = 24 + + // Operator is + Operator SymbolKind = 25 + + // TypeParameter is + TypeParameter SymbolKind = 26 + + /*Empty defined: + * Empty kind. + */ + Empty CodeActionKind = "" + + /*QuickFix defined: + * Base kind for quickfix actions: 'quickfix' + */ + QuickFix CodeActionKind = "quickfix" + + /*Refactor defined: + * Base kind for refactoring actions: 'refactor' + */ + Refactor CodeActionKind = "refactor" + + /*RefactorExtract defined: + * Base kind for refactoring extraction actions: 'refactor.extract' + * + * Example extract actions: + * + * - Extract method + * - Extract function + * - Extract variable + * - Extract interface from class + * - ... + */ + RefactorExtract CodeActionKind = "refactor.extract" + + /*RefactorInline defined: + * Base kind for refactoring inline actions: 'refactor.inline' + * + * Example inline actions: + * + * - Inline function + * - Inline variable + * - Inline constant + * - ... + */ + RefactorInline CodeActionKind = "refactor.inline" + + /*RefactorRewrite defined: + * Base kind for refactoring rewrite actions: 'refactor.rewrite' + * + * Example rewrite actions: + * + * - Convert JavaScript function to class + * - Add or remove parameter + * - Encapsulate field + * - Make method static + * - Move method to base class + * - ... + */ + RefactorRewrite CodeActionKind = "refactor.rewrite" + + /*Source defined: + * Base kind for source actions: `source` + * + * Source code actions apply to the entire file. + */ + Source CodeActionKind = "source" + + /*SourceOrganizeImports defined: + * Base kind for an organize imports source action: `source.organizeImports` + */ + SourceOrganizeImports CodeActionKind = "source.organizeImports" + + /*Manual defined: + * Manually triggered, e.g. by the user pressing save, by starting debugging, + * or by an API call. + */ + Manual TextDocumentSaveReason = 1 + + /*AfterDelay defined: + * Automatic after a delay. + */ + AfterDelay TextDocumentSaveReason = 2 + + /*FocusOut defined: + * When the editor lost focus. + */ + FocusOut TextDocumentSaveReason = 3 + + // MessageWriteError is + MessageWriteError ErrorCodes = 1 + + // MessageReadError is + MessageReadError ErrorCodes = 2 + + // First is + First Touch = 1 + + // Last is + Last Touch = 2 + + // JSON is + JSON TraceFormat = "json" + + /*Closed defined: + * The connection is closed. + */ + Closed ConnectionErrors = 1 + + /*Disposed defined: + * The connection got disposed. + */ + Disposed ConnectionErrors = 2 + + /*AlreadyListening defined: + * The connection is already in listening mode. + */ + AlreadyListening ConnectionErrors = 3 + + // New is + New ConnectionState = 1 + + // Listening is + Listening ConnectionState = 2 +) + +// DocumentFilter is a type +/** + * A document filter denotes a document by different properties like + * the [language](#TextDocument.languageId), the [scheme](#Uri.scheme) of + * its resource, or a glob-pattern that is applied to the [path](#TextDocument.fileName). + * + * Glob patterns can have the following syntax: + * - `*` to match one or more characters in a path segment + * - `?` to match on one character in a path segment + * - `**` to match any number of path segments, including none + * - `{}` to group conditions (e.g. `**​/*.{ts,js}` matches all TypeScript and JavaScript files) + * - `[]` to declare a range of characters to match in a path segment (e.g., `example.[0-9]` to match on `example.0`, `example.1`, …) + * - `[!...]` to negate a range of characters to match in a path segment (e.g., `example.[!0-9]` to match on `example.a`, `example.b`, but not `example.0`) + * + * @sample A language filter that applies to typescript files on disk: `{ language: 'typescript', scheme: 'file' }` + * @sample A language filter that applies to all package.json paths: `{ language: 'json', pattern: '**package.json' }` + */ +type DocumentFilter = struct { + + /*Language defined: A language id, like `typescript`. */ + Language string `json:"language,omitempty"` + + /*Scheme defined: A Uri [scheme](#Uri.scheme), like `file` or `untitled`. */ + Scheme string `json:"scheme,omitempty"` + + /*Pattern defined: A glob pattern, like `*.{ts,js}`. */ + Pattern string `json:"pattern,omitempty"` +} + +// DocumentSelector is a type +/** + * A document selector is the combination of one or many document filters. + * + * @sample `let sel:DocumentSelector = [{ language: 'typescript' }, { language: 'json', pattern: '**∕tsconfig.json' }]`; + */ +type DocumentSelector = []DocumentFilter + +// DocumentURI is a type +/** + * A tagging type for string properties that are actually URIs. + */ +type DocumentURI = string + +// MarkedString is a type +/** + * MarkedString can be used to render human readable text. It is either a markdown string + * or a code-block that provides a language and a code snippet. The language identifier + * is semantically equal to the optional language identifier in fenced code blocks in GitHub + * issues. See https://help.github.com/articles/creating-and-highlighting-code-blocks/#syntax-highlighting + * + * The pair of a language and a value is an equivalent to markdown: + * ```${language} + * ${value} + * ``` + * + * Note that markdown strings will be sanitized - that means html will be escaped. + * @deprecated use MarkupContent instead. + */ +type MarkedString = string + +// DefinitionLink is a type +/** + * Information about where a symbol is defined. + * + * Provides additional metadata over normal [location](#Location) definitions, including the range of + * the defining symbol + */ +type DefinitionLink = LocationLink + +// DeclarationLink is a type +/** + * Information about where a symbol is declared. + * + * Provides additional metadata over normal [location](#Location) declarations, including the range of + * the declaring symbol. + * + * Servers should prefer returning `DeclarationLink` over `Declaration` if supported + * by the client. + */ +type DeclarationLink = LocationLink + +// LSPMessageType is a type +/** + * A LSP Log Entry. + */ +type LSPMessageType = string + +// ProgressToken is a type +type ProgressToken = interface{} // number | string +// TraceValues is a type +type TraceValues = string diff --git a/third_party/spirv-tools/utils/vscode/src/lsp/protocol/tsserver.go b/third_party/spirv-tools/utils/vscode/src/lsp/protocol/tsserver.go new file mode 100644 index 0000000000..d76050121f --- /dev/null +++ b/third_party/spirv-tools/utils/vscode/src/lsp/protocol/tsserver.go @@ -0,0 +1,842 @@ +// Copyright 2019 The Go Authors. +// +// 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. + +package protocol + +import ( + "context" + "encoding/json" + "log" + + "../jsonrpc2" +) + +type Server interface { + DidChangeWorkspaceFolders(context.Context, *DidChangeWorkspaceFoldersParams) error + Initialized(context.Context, *InitializedParams) error + Exit(context.Context) error + DidChangeConfiguration(context.Context, *DidChangeConfigurationParams) error + DidOpen(context.Context, *DidOpenTextDocumentParams) error + DidChange(context.Context, *DidChangeTextDocumentParams) error + DidClose(context.Context, *DidCloseTextDocumentParams) error + DidSave(context.Context, *DidSaveTextDocumentParams) error + WillSave(context.Context, *WillSaveTextDocumentParams) error + DidChangeWatchedFiles(context.Context, *DidChangeWatchedFilesParams) error + Progress(context.Context, *ProgressParams) error + SetTraceNotification(context.Context, *SetTraceParams) error + LogTraceNotification(context.Context, *LogTraceParams) error + Implementation(context.Context, *ImplementationParams) ([]Location, error) + TypeDefinition(context.Context, *TypeDefinitionParams) ([]Location, error) + DocumentColor(context.Context, *DocumentColorParams) ([]ColorInformation, error) + ColorPresentation(context.Context, *ColorPresentationParams) ([]ColorPresentation, error) + FoldingRange(context.Context, *FoldingRangeParams) ([]FoldingRange, error) + Declaration(context.Context, *DeclarationParams) ([]DeclarationLink, error) + SelectionRange(context.Context, *SelectionRangeParams) ([]SelectionRange, error) + Initialize(context.Context, *ParamInitia) (*InitializeResult, error) + Shutdown(context.Context) error + WillSaveWaitUntil(context.Context, *WillSaveTextDocumentParams) ([]TextEdit, error) + Completion(context.Context, *CompletionParams) (*CompletionList, error) + Resolve(context.Context, *CompletionItem) (*CompletionItem, error) + Hover(context.Context, *HoverParams) (*Hover, error) + SignatureHelp(context.Context, *SignatureHelpParams) (*SignatureHelp, error) + Definition(context.Context, *DefinitionParams) ([]Location, error) + References(context.Context, *ReferenceParams) ([]Location, error) + DocumentHighlight(context.Context, *DocumentHighlightParams) ([]DocumentHighlight, error) + DocumentSymbol(context.Context, *DocumentSymbolParams) ([]DocumentSymbol, error) + CodeAction(context.Context, *CodeActionParams) ([]CodeAction, error) + Symbol(context.Context, *WorkspaceSymbolParams) ([]SymbolInformation, error) + CodeLens(context.Context, *CodeLensParams) ([]CodeLens, error) + ResolveCodeLens(context.Context, *CodeLens) (*CodeLens, error) + DocumentLink(context.Context, *DocumentLinkParams) ([]DocumentLink, error) + ResolveDocumentLink(context.Context, *DocumentLink) (*DocumentLink, error) + Formatting(context.Context, *DocumentFormattingParams) ([]TextEdit, error) + RangeFormatting(context.Context, *DocumentRangeFormattingParams) ([]TextEdit, error) + OnTypeFormatting(context.Context, *DocumentOnTypeFormattingParams) ([]TextEdit, error) + Rename(context.Context, *RenameParams) (*WorkspaceEdit, error) + PrepareRename(context.Context, *PrepareRenameParams) (*Range, error) + ExecuteCommand(context.Context, *ExecuteCommandParams) (interface{}, error) +} + +func (h serverHandler) Deliver(ctx context.Context, r *jsonrpc2.Request, delivered bool) bool { + if delivered { + return false + } + if ctx.Err() != nil { + r.Reply(ctx, nil, jsonrpc2.NewErrorf(RequestCancelledError, "")) + return true + } + switch r.Method { + case "workspace/didChangeWorkspaceFolders": // notif + var params DidChangeWorkspaceFoldersParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + sendParseError(ctx, r, err) + return true + } + if err := h.server.DidChangeWorkspaceFolders(ctx, ¶ms); err != nil { + log.Printf("%v", err) + } + return true + case "initialized": // notif + var params InitializedParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + sendParseError(ctx, r, err) + return true + } + if err := h.server.Initialized(ctx, ¶ms); err != nil { + log.Printf("%v", err) + } + return true + case "exit": // notif + if err := h.server.Exit(ctx); err != nil { + log.Printf("%v", err) + } + return true + case "workspace/didChangeConfiguration": // notif + var params DidChangeConfigurationParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + sendParseError(ctx, r, err) + return true + } + if err := h.server.DidChangeConfiguration(ctx, ¶ms); err != nil { + log.Printf("%v", err) + } + return true + case "textDocument/didOpen": // notif + var params DidOpenTextDocumentParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + sendParseError(ctx, r, err) + return true + } + if err := h.server.DidOpen(ctx, ¶ms); err != nil { + log.Printf("%v", err) + } + return true + case "textDocument/didChange": // notif + var params DidChangeTextDocumentParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + sendParseError(ctx, r, err) + return true + } + if err := h.server.DidChange(ctx, ¶ms); err != nil { + log.Printf("%v", err) + } + return true + case "textDocument/didClose": // notif + var params DidCloseTextDocumentParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + sendParseError(ctx, r, err) + return true + } + if err := h.server.DidClose(ctx, ¶ms); err != nil { + log.Printf("%v", err) + } + return true + case "textDocument/didSave": // notif + var params DidSaveTextDocumentParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + sendParseError(ctx, r, err) + return true + } + if err := h.server.DidSave(ctx, ¶ms); err != nil { + log.Printf("%v", err) + } + return true + case "textDocument/willSave": // notif + var params WillSaveTextDocumentParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + sendParseError(ctx, r, err) + return true + } + if err := h.server.WillSave(ctx, ¶ms); err != nil { + log.Printf("%v", err) + } + return true + case "workspace/didChangeWatchedFiles": // notif + var params DidChangeWatchedFilesParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + sendParseError(ctx, r, err) + return true + } + if err := h.server.DidChangeWatchedFiles(ctx, ¶ms); err != nil { + log.Printf("%v", err) + } + return true + case "$/progress": // notif + var params ProgressParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + sendParseError(ctx, r, err) + return true + } + if err := h.server.Progress(ctx, ¶ms); err != nil { + log.Printf("%v", err) + } + return true + case "$/setTraceNotification": // notif + var params SetTraceParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + sendParseError(ctx, r, err) + return true + } + if err := h.server.SetTraceNotification(ctx, ¶ms); err != nil { + log.Printf("%v", err) + } + return true + case "$/logTraceNotification": // notif + var params LogTraceParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + sendParseError(ctx, r, err) + return true + } + if err := h.server.LogTraceNotification(ctx, ¶ms); err != nil { + log.Printf("%v", err) + } + return true + case "textDocument/implementation": // req + var params ImplementationParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + sendParseError(ctx, r, err) + return true + } + resp, err := h.server.Implementation(ctx, ¶ms) + if err := r.Reply(ctx, resp, err); err != nil { + log.Printf("%v", err) + } + return true + case "textDocument/typeDefinition": // req + var params TypeDefinitionParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + sendParseError(ctx, r, err) + return true + } + resp, err := h.server.TypeDefinition(ctx, ¶ms) + if err := r.Reply(ctx, resp, err); err != nil { + log.Printf("%v", err) + } + return true + case "textDocument/documentColor": // req + var params DocumentColorParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + sendParseError(ctx, r, err) + return true + } + resp, err := h.server.DocumentColor(ctx, ¶ms) + if err := r.Reply(ctx, resp, err); err != nil { + log.Printf("%v", err) + } + return true + case "textDocument/colorPresentation": // req + var params ColorPresentationParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + sendParseError(ctx, r, err) + return true + } + resp, err := h.server.ColorPresentation(ctx, ¶ms) + if err := r.Reply(ctx, resp, err); err != nil { + log.Printf("%v", err) + } + return true + case "textDocument/foldingRange": // req + var params FoldingRangeParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + sendParseError(ctx, r, err) + return true + } + resp, err := h.server.FoldingRange(ctx, ¶ms) + if err := r.Reply(ctx, resp, err); err != nil { + log.Printf("%v", err) + } + return true + case "textDocument/declaration": // req + var params DeclarationParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + sendParseError(ctx, r, err) + return true + } + resp, err := h.server.Declaration(ctx, ¶ms) + if err := r.Reply(ctx, resp, err); err != nil { + log.Printf("%v", err) + } + return true + case "textDocument/selectionRange": // req + var params SelectionRangeParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + sendParseError(ctx, r, err) + return true + } + resp, err := h.server.SelectionRange(ctx, ¶ms) + if err := r.Reply(ctx, resp, err); err != nil { + log.Printf("%v", err) + } + return true + case "initialize": // req + var params ParamInitia + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + sendParseError(ctx, r, err) + return true + } + resp, err := h.server.Initialize(ctx, ¶ms) + if err := r.Reply(ctx, resp, err); err != nil { + log.Printf("%v", err) + } + return true + case "shutdown": // req + if r.Params != nil { + r.Reply(ctx, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeInvalidParams, "Expected no params")) + return true + } + err := h.server.Shutdown(ctx) + if err := r.Reply(ctx, nil, err); err != nil { + log.Printf("%v", err) + } + return true + case "textDocument/willSaveWaitUntil": // req + var params WillSaveTextDocumentParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + sendParseError(ctx, r, err) + return true + } + resp, err := h.server.WillSaveWaitUntil(ctx, ¶ms) + if err := r.Reply(ctx, resp, err); err != nil { + log.Printf("%v", err) + } + return true + case "textDocument/completion": // req + var params CompletionParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + sendParseError(ctx, r, err) + return true + } + resp, err := h.server.Completion(ctx, ¶ms) + if err := r.Reply(ctx, resp, err); err != nil { + log.Printf("%v", err) + } + return true + case "completionItem/resolve": // req + var params CompletionItem + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + sendParseError(ctx, r, err) + return true + } + resp, err := h.server.Resolve(ctx, ¶ms) + if err := r.Reply(ctx, resp, err); err != nil { + log.Printf("%v", err) + } + return true + case "textDocument/hover": // req + var params HoverParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + sendParseError(ctx, r, err) + return true + } + resp, err := h.server.Hover(ctx, ¶ms) + if err := r.Reply(ctx, resp, err); err != nil { + log.Printf("%v", err) + } + return true + case "textDocument/signatureHelp": // req + var params SignatureHelpParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + sendParseError(ctx, r, err) + return true + } + resp, err := h.server.SignatureHelp(ctx, ¶ms) + if err := r.Reply(ctx, resp, err); err != nil { + log.Printf("%v", err) + } + return true + case "textDocument/definition": // req + var params DefinitionParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + sendParseError(ctx, r, err) + return true + } + resp, err := h.server.Definition(ctx, ¶ms) + if err := r.Reply(ctx, resp, err); err != nil { + log.Printf("%v", err) + } + return true + case "textDocument/references": // req + var params ReferenceParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + sendParseError(ctx, r, err) + return true + } + resp, err := h.server.References(ctx, ¶ms) + if err := r.Reply(ctx, resp, err); err != nil { + log.Printf("%v", err) + } + return true + case "textDocument/documentHighlight": // req + var params DocumentHighlightParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + sendParseError(ctx, r, err) + return true + } + resp, err := h.server.DocumentHighlight(ctx, ¶ms) + if err := r.Reply(ctx, resp, err); err != nil { + log.Printf("%v", err) + } + return true + case "textDocument/documentSymbol": // req + var params DocumentSymbolParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + sendParseError(ctx, r, err) + return true + } + resp, err := h.server.DocumentSymbol(ctx, ¶ms) + if err := r.Reply(ctx, resp, err); err != nil { + log.Printf("%v", err) + } + return true + case "textDocument/codeAction": // req + var params CodeActionParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + sendParseError(ctx, r, err) + return true + } + resp, err := h.server.CodeAction(ctx, ¶ms) + if err := r.Reply(ctx, resp, err); err != nil { + log.Printf("%v", err) + } + return true + case "workspace/symbol": // req + var params WorkspaceSymbolParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + sendParseError(ctx, r, err) + return true + } + resp, err := h.server.Symbol(ctx, ¶ms) + if err := r.Reply(ctx, resp, err); err != nil { + log.Printf("%v", err) + } + return true + case "textDocument/codeLens": // req + var params CodeLensParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + sendParseError(ctx, r, err) + return true + } + resp, err := h.server.CodeLens(ctx, ¶ms) + if err := r.Reply(ctx, resp, err); err != nil { + log.Printf("%v", err) + } + return true + case "codeLens/resolve": // req + var params CodeLens + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + sendParseError(ctx, r, err) + return true + } + resp, err := h.server.ResolveCodeLens(ctx, ¶ms) + if err := r.Reply(ctx, resp, err); err != nil { + log.Printf("%v", err) + } + return true + case "textDocument/documentLink": // req + var params DocumentLinkParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + sendParseError(ctx, r, err) + return true + } + resp, err := h.server.DocumentLink(ctx, ¶ms) + if err := r.Reply(ctx, resp, err); err != nil { + log.Printf("%v", err) + } + return true + case "documentLink/resolve": // req + var params DocumentLink + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + sendParseError(ctx, r, err) + return true + } + resp, err := h.server.ResolveDocumentLink(ctx, ¶ms) + if err := r.Reply(ctx, resp, err); err != nil { + log.Printf("%v", err) + } + return true + case "textDocument/formatting": // req + var params DocumentFormattingParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + sendParseError(ctx, r, err) + return true + } + resp, err := h.server.Formatting(ctx, ¶ms) + if err := r.Reply(ctx, resp, err); err != nil { + log.Printf("%v", err) + } + return true + case "textDocument/rangeFormatting": // req + var params DocumentRangeFormattingParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + sendParseError(ctx, r, err) + return true + } + resp, err := h.server.RangeFormatting(ctx, ¶ms) + if err := r.Reply(ctx, resp, err); err != nil { + log.Printf("%v", err) + } + return true + case "textDocument/onTypeFormatting": // req + var params DocumentOnTypeFormattingParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + sendParseError(ctx, r, err) + return true + } + resp, err := h.server.OnTypeFormatting(ctx, ¶ms) + if err := r.Reply(ctx, resp, err); err != nil { + log.Printf("%v", err) + } + return true + case "textDocument/rename": // req + var params RenameParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + sendParseError(ctx, r, err) + return true + } + resp, err := h.server.Rename(ctx, ¶ms) + if err := r.Reply(ctx, resp, err); err != nil { + log.Printf("%v", err) + } + return true + case "textDocument/prepareRename": // req + var params PrepareRenameParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + sendParseError(ctx, r, err) + return true + } + resp, err := h.server.PrepareRename(ctx, ¶ms) + if err := r.Reply(ctx, resp, err); err != nil { + log.Printf("%v", err) + } + return true + case "workspace/executeCommand": // req + var params ExecuteCommandParams + if err := json.Unmarshal(*r.Params, ¶ms); err != nil { + sendParseError(ctx, r, err) + return true + } + resp, err := h.server.ExecuteCommand(ctx, ¶ms) + if err := r.Reply(ctx, resp, err); err != nil { + log.Printf("%v", err) + } + return true + + default: + return false + } +} + +type serverDispatcher struct { + *jsonrpc2.Conn +} + +func (s *serverDispatcher) DidChangeWorkspaceFolders(ctx context.Context, params *DidChangeWorkspaceFoldersParams) error { + return s.Conn.Notify(ctx, "workspace/didChangeWorkspaceFolders", params) +} + +func (s *serverDispatcher) Initialized(ctx context.Context, params *InitializedParams) error { + return s.Conn.Notify(ctx, "initialized", params) +} + +func (s *serverDispatcher) Exit(ctx context.Context) error { + return s.Conn.Notify(ctx, "exit", nil) +} + +func (s *serverDispatcher) DidChangeConfiguration(ctx context.Context, params *DidChangeConfigurationParams) error { + return s.Conn.Notify(ctx, "workspace/didChangeConfiguration", params) +} + +func (s *serverDispatcher) DidOpen(ctx context.Context, params *DidOpenTextDocumentParams) error { + return s.Conn.Notify(ctx, "textDocument/didOpen", params) +} + +func (s *serverDispatcher) DidChange(ctx context.Context, params *DidChangeTextDocumentParams) error { + return s.Conn.Notify(ctx, "textDocument/didChange", params) +} + +func (s *serverDispatcher) DidClose(ctx context.Context, params *DidCloseTextDocumentParams) error { + return s.Conn.Notify(ctx, "textDocument/didClose", params) +} + +func (s *serverDispatcher) DidSave(ctx context.Context, params *DidSaveTextDocumentParams) error { + return s.Conn.Notify(ctx, "textDocument/didSave", params) +} + +func (s *serverDispatcher) WillSave(ctx context.Context, params *WillSaveTextDocumentParams) error { + return s.Conn.Notify(ctx, "textDocument/willSave", params) +} + +func (s *serverDispatcher) DidChangeWatchedFiles(ctx context.Context, params *DidChangeWatchedFilesParams) error { + return s.Conn.Notify(ctx, "workspace/didChangeWatchedFiles", params) +} + +func (s *serverDispatcher) Progress(ctx context.Context, params *ProgressParams) error { + return s.Conn.Notify(ctx, "$/progress", params) +} + +func (s *serverDispatcher) SetTraceNotification(ctx context.Context, params *SetTraceParams) error { + return s.Conn.Notify(ctx, "$/setTraceNotification", params) +} + +func (s *serverDispatcher) LogTraceNotification(ctx context.Context, params *LogTraceParams) error { + return s.Conn.Notify(ctx, "$/logTraceNotification", params) +} +func (s *serverDispatcher) Implementation(ctx context.Context, params *ImplementationParams) ([]Location, error) { + var result []Location + if err := s.Conn.Call(ctx, "textDocument/implementation", params, &result); err != nil { + return nil, err + } + return result, nil +} + +func (s *serverDispatcher) TypeDefinition(ctx context.Context, params *TypeDefinitionParams) ([]Location, error) { + var result []Location + if err := s.Conn.Call(ctx, "textDocument/typeDefinition", params, &result); err != nil { + return nil, err + } + return result, nil +} + +func (s *serverDispatcher) DocumentColor(ctx context.Context, params *DocumentColorParams) ([]ColorInformation, error) { + var result []ColorInformation + if err := s.Conn.Call(ctx, "textDocument/documentColor", params, &result); err != nil { + return nil, err + } + return result, nil +} + +func (s *serverDispatcher) ColorPresentation(ctx context.Context, params *ColorPresentationParams) ([]ColorPresentation, error) { + var result []ColorPresentation + if err := s.Conn.Call(ctx, "textDocument/colorPresentation", params, &result); err != nil { + return nil, err + } + return result, nil +} + +func (s *serverDispatcher) FoldingRange(ctx context.Context, params *FoldingRangeParams) ([]FoldingRange, error) { + var result []FoldingRange + if err := s.Conn.Call(ctx, "textDocument/foldingRange", params, &result); err != nil { + return nil, err + } + return result, nil +} + +func (s *serverDispatcher) Declaration(ctx context.Context, params *DeclarationParams) ([]DeclarationLink, error) { + var result []DeclarationLink + if err := s.Conn.Call(ctx, "textDocument/declaration", params, &result); err != nil { + return nil, err + } + return result, nil +} + +func (s *serverDispatcher) SelectionRange(ctx context.Context, params *SelectionRangeParams) ([]SelectionRange, error) { + var result []SelectionRange + if err := s.Conn.Call(ctx, "textDocument/selectionRange", params, &result); err != nil { + return nil, err + } + return result, nil +} + +func (s *serverDispatcher) Initialize(ctx context.Context, params *ParamInitia) (*InitializeResult, error) { + var result InitializeResult + if err := s.Conn.Call(ctx, "initialize", params, &result); err != nil { + return nil, err + } + return &result, nil +} + +func (s *serverDispatcher) Shutdown(ctx context.Context) error { + return s.Conn.Call(ctx, "shutdown", nil, nil) +} + +func (s *serverDispatcher) WillSaveWaitUntil(ctx context.Context, params *WillSaveTextDocumentParams) ([]TextEdit, error) { + var result []TextEdit + if err := s.Conn.Call(ctx, "textDocument/willSaveWaitUntil", params, &result); err != nil { + return nil, err + } + return result, nil +} + +func (s *serverDispatcher) Completion(ctx context.Context, params *CompletionParams) (*CompletionList, error) { + var result CompletionList + if err := s.Conn.Call(ctx, "textDocument/completion", params, &result); err != nil { + return nil, err + } + return &result, nil +} + +func (s *serverDispatcher) Resolve(ctx context.Context, params *CompletionItem) (*CompletionItem, error) { + var result CompletionItem + if err := s.Conn.Call(ctx, "completionItem/resolve", params, &result); err != nil { + return nil, err + } + return &result, nil +} + +func (s *serverDispatcher) Hover(ctx context.Context, params *HoverParams) (*Hover, error) { + var result Hover + if err := s.Conn.Call(ctx, "textDocument/hover", params, &result); err != nil { + return nil, err + } + return &result, nil +} + +func (s *serverDispatcher) SignatureHelp(ctx context.Context, params *SignatureHelpParams) (*SignatureHelp, error) { + var result SignatureHelp + if err := s.Conn.Call(ctx, "textDocument/signatureHelp", params, &result); err != nil { + return nil, err + } + return &result, nil +} + +func (s *serverDispatcher) Definition(ctx context.Context, params *DefinitionParams) ([]Location, error) { + var result []Location + if err := s.Conn.Call(ctx, "textDocument/definition", params, &result); err != nil { + return nil, err + } + return result, nil +} + +func (s *serverDispatcher) References(ctx context.Context, params *ReferenceParams) ([]Location, error) { + var result []Location + if err := s.Conn.Call(ctx, "textDocument/references", params, &result); err != nil { + return nil, err + } + return result, nil +} + +func (s *serverDispatcher) DocumentHighlight(ctx context.Context, params *DocumentHighlightParams) ([]DocumentHighlight, error) { + var result []DocumentHighlight + if err := s.Conn.Call(ctx, "textDocument/documentHighlight", params, &result); err != nil { + return nil, err + } + return result, nil +} + +func (s *serverDispatcher) DocumentSymbol(ctx context.Context, params *DocumentSymbolParams) ([]DocumentSymbol, error) { + var result []DocumentSymbol + if err := s.Conn.Call(ctx, "textDocument/documentSymbol", params, &result); err != nil { + return nil, err + } + return result, nil +} + +func (s *serverDispatcher) CodeAction(ctx context.Context, params *CodeActionParams) ([]CodeAction, error) { + var result []CodeAction + if err := s.Conn.Call(ctx, "textDocument/codeAction", params, &result); err != nil { + return nil, err + } + return result, nil +} + +func (s *serverDispatcher) Symbol(ctx context.Context, params *WorkspaceSymbolParams) ([]SymbolInformation, error) { + var result []SymbolInformation + if err := s.Conn.Call(ctx, "workspace/symbol", params, &result); err != nil { + return nil, err + } + return result, nil +} + +func (s *serverDispatcher) CodeLens(ctx context.Context, params *CodeLensParams) ([]CodeLens, error) { + var result []CodeLens + if err := s.Conn.Call(ctx, "textDocument/codeLens", params, &result); err != nil { + return nil, err + } + return result, nil +} + +func (s *serverDispatcher) ResolveCodeLens(ctx context.Context, params *CodeLens) (*CodeLens, error) { + var result CodeLens + if err := s.Conn.Call(ctx, "codeLens/resolve", params, &result); err != nil { + return nil, err + } + return &result, nil +} + +func (s *serverDispatcher) DocumentLink(ctx context.Context, params *DocumentLinkParams) ([]DocumentLink, error) { + var result []DocumentLink + if err := s.Conn.Call(ctx, "textDocument/documentLink", params, &result); err != nil { + return nil, err + } + return result, nil +} + +func (s *serverDispatcher) ResolveDocumentLink(ctx context.Context, params *DocumentLink) (*DocumentLink, error) { + var result DocumentLink + if err := s.Conn.Call(ctx, "documentLink/resolve", params, &result); err != nil { + return nil, err + } + return &result, nil +} + +func (s *serverDispatcher) Formatting(ctx context.Context, params *DocumentFormattingParams) ([]TextEdit, error) { + var result []TextEdit + if err := s.Conn.Call(ctx, "textDocument/formatting", params, &result); err != nil { + return nil, err + } + return result, nil +} + +func (s *serverDispatcher) RangeFormatting(ctx context.Context, params *DocumentRangeFormattingParams) ([]TextEdit, error) { + var result []TextEdit + if err := s.Conn.Call(ctx, "textDocument/rangeFormatting", params, &result); err != nil { + return nil, err + } + return result, nil +} + +func (s *serverDispatcher) OnTypeFormatting(ctx context.Context, params *DocumentOnTypeFormattingParams) ([]TextEdit, error) { + var result []TextEdit + if err := s.Conn.Call(ctx, "textDocument/onTypeFormatting", params, &result); err != nil { + return nil, err + } + return result, nil +} + +func (s *serverDispatcher) Rename(ctx context.Context, params *RenameParams) (*WorkspaceEdit, error) { + var result WorkspaceEdit + if err := s.Conn.Call(ctx, "textDocument/rename", params, &result); err != nil { + return nil, err + } + return &result, nil +} + +func (s *serverDispatcher) PrepareRename(ctx context.Context, params *PrepareRenameParams) (*Range, error) { + var result Range + if err := s.Conn.Call(ctx, "textDocument/prepareRename", params, &result); err != nil { + return nil, err + } + return &result, nil +} + +func (s *serverDispatcher) ExecuteCommand(ctx context.Context, params *ExecuteCommandParams) (interface{}, error) { + var result interface{} + if err := s.Conn.Call(ctx, "workspace/executeCommand", params, &result); err != nil { + return nil, err + } + return result, nil +} + +type CancelParams struct { + /** + * The request id to cancel. + */ + ID jsonrpc2.ID `json:"id"` +} + +// Types constructed to avoid structs as formal argument types +type ParamInitia struct { + InitializeParams + WorkDoneProgressParams +} diff --git a/third_party/spirv-tools/utils/vscode/src/lsp/span/parse.go b/third_party/spirv-tools/utils/vscode/src/lsp/span/parse.go new file mode 100644 index 0000000000..ec393c2a75 --- /dev/null +++ b/third_party/spirv-tools/utils/vscode/src/lsp/span/parse.go @@ -0,0 +1,110 @@ +// Copyright 2019 The Go Authors. +// +// 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. + +package span + +import ( + "strconv" + "strings" + "unicode/utf8" +) + +// Parse returns the location represented by the input. +// All inputs are valid locations, as they can always be a pure filename. +// The returned span will be normalized, and thus if printed may produce a +// different string. +func Parse(input string) Span { + // :0:0#0-0:0#0 + valid := input + var hold, offset int + hadCol := false + suf := rstripSuffix(input) + if suf.sep == "#" { + offset = suf.num + suf = rstripSuffix(suf.remains) + } + if suf.sep == ":" { + valid = suf.remains + hold = suf.num + hadCol = true + suf = rstripSuffix(suf.remains) + } + switch { + case suf.sep == ":": + return New(NewURI(suf.remains), NewPoint(suf.num, hold, offset), Point{}) + case suf.sep == "-": + // we have a span, fall out of the case to continue + default: + // separator not valid, rewind to either the : or the start + return New(NewURI(valid), NewPoint(hold, 0, offset), Point{}) + } + // only the span form can get here + // at this point we still don't know what the numbers we have mean + // if have not yet seen a : then we might have either a line or a column depending + // on whether start has a column or not + // we build an end point and will fix it later if needed + end := NewPoint(suf.num, hold, offset) + hold, offset = 0, 0 + suf = rstripSuffix(suf.remains) + if suf.sep == "#" { + offset = suf.num + suf = rstripSuffix(suf.remains) + } + if suf.sep != ":" { + // turns out we don't have a span after all, rewind + return New(NewURI(valid), end, Point{}) + } + valid = suf.remains + hold = suf.num + suf = rstripSuffix(suf.remains) + if suf.sep != ":" { + // line#offset only + return New(NewURI(valid), NewPoint(hold, 0, offset), end) + } + // we have a column, so if end only had one number, it is also the column + if !hadCol { + end = NewPoint(suf.num, end.v.Line, end.v.Offset) + } + return New(NewURI(suf.remains), NewPoint(suf.num, hold, offset), end) +} + +type suffix struct { + remains string + sep string + num int +} + +func rstripSuffix(input string) suffix { + if len(input) == 0 { + return suffix{"", "", -1} + } + remains := input + num := -1 + // first see if we have a number at the end + last := strings.LastIndexFunc(remains, func(r rune) bool { return r < '0' || r > '9' }) + if last >= 0 && last < len(remains)-1 { + number, err := strconv.ParseInt(remains[last+1:], 10, 64) + if err == nil { + num = int(number) + remains = remains[:last+1] + } + } + // now see if we have a trailing separator + r, w := utf8.DecodeLastRuneInString(remains) + if r != ':' && r != '#' && r == '#' { + return suffix{input, "", -1} + } + remains = remains[:len(remains)-w] + return suffix{remains, string(r), num} +} diff --git a/third_party/spirv-tools/utils/vscode/src/lsp/span/span.go b/third_party/spirv-tools/utils/vscode/src/lsp/span/span.go new file mode 100644 index 0000000000..aefd4f3fad --- /dev/null +++ b/third_party/spirv-tools/utils/vscode/src/lsp/span/span.go @@ -0,0 +1,295 @@ +// Copyright 2019 The Go Authors. +// +// 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. + +// Package span contains support for representing with positions and ranges in +// text files. +package span + +import ( + "encoding/json" + "fmt" + "path" +) + +// Span represents a source code range in standardized form. +type Span struct { + v span +} + +// Point represents a single point within a file. +// In general this should only be used as part of a Span, as on its own it +// does not carry enough information. +type Point struct { + v point +} + +type span struct { + URI URI `json:"uri"` + Start point `json:"start"` + End point `json:"end"` +} + +type point struct { + Line int `json:"line"` + Column int `json:"column"` + Offset int `json:"offset"` +} + +// Invalid is a span that reports false from IsValid +var Invalid = Span{v: span{Start: invalidPoint.v, End: invalidPoint.v}} + +var invalidPoint = Point{v: point{Line: 0, Column: 0, Offset: -1}} + +// Converter is the interface to an object that can convert between line:column +// and offset forms for a single file. +type Converter interface { + //ToPosition converts from an offset to a line:column pair. + ToPosition(offset int) (int, int, error) + //ToOffset converts from a line:column pair to an offset. + ToOffset(line, col int) (int, error) +} + +func New(uri URI, start Point, end Point) Span { + s := Span{v: span{URI: uri, Start: start.v, End: end.v}} + s.v.clean() + return s +} + +func NewPoint(line, col, offset int) Point { + p := Point{v: point{Line: line, Column: col, Offset: offset}} + p.v.clean() + return p +} + +func Compare(a, b Span) int { + if r := CompareURI(a.URI(), b.URI()); r != 0 { + return r + } + if r := comparePoint(a.v.Start, b.v.Start); r != 0 { + return r + } + return comparePoint(a.v.End, b.v.End) +} + +func ComparePoint(a, b Point) int { + return comparePoint(a.v, b.v) +} + +func comparePoint(a, b point) int { + if !a.hasPosition() { + if a.Offset < b.Offset { + return -1 + } + if a.Offset > b.Offset { + return 1 + } + return 0 + } + if a.Line < b.Line { + return -1 + } + if a.Line > b.Line { + return 1 + } + if a.Column < b.Column { + return -1 + } + if a.Column > b.Column { + return 1 + } + return 0 +} + +func (s Span) HasPosition() bool { return s.v.Start.hasPosition() } +func (s Span) HasOffset() bool { return s.v.Start.hasOffset() } +func (s Span) IsValid() bool { return s.v.Start.isValid() } +func (s Span) IsPoint() bool { return s.v.Start == s.v.End } +func (s Span) URI() URI { return s.v.URI } +func (s Span) Start() Point { return Point{s.v.Start} } +func (s Span) End() Point { return Point{s.v.End} } +func (s *Span) MarshalJSON() ([]byte, error) { return json.Marshal(&s.v) } +func (s *Span) UnmarshalJSON(b []byte) error { return json.Unmarshal(b, &s.v) } + +func (p Point) HasPosition() bool { return p.v.hasPosition() } +func (p Point) HasOffset() bool { return p.v.hasOffset() } +func (p Point) IsValid() bool { return p.v.isValid() } +func (p *Point) MarshalJSON() ([]byte, error) { return json.Marshal(&p.v) } +func (p *Point) UnmarshalJSON(b []byte) error { return json.Unmarshal(b, &p.v) } +func (p Point) Line() int { + if !p.v.hasPosition() { + panic(fmt.Errorf("position not set in %v", p.v)) + } + return p.v.Line +} +func (p Point) Column() int { + if !p.v.hasPosition() { + panic(fmt.Errorf("position not set in %v", p.v)) + } + return p.v.Column +} +func (p Point) Offset() int { + if !p.v.hasOffset() { + panic(fmt.Errorf("offset not set in %v", p.v)) + } + return p.v.Offset +} + +func (p point) hasPosition() bool { return p.Line > 0 } +func (p point) hasOffset() bool { return p.Offset >= 0 } +func (p point) isValid() bool { return p.hasPosition() || p.hasOffset() } +func (p point) isZero() bool { + return (p.Line == 1 && p.Column == 1) || (!p.hasPosition() && p.Offset == 0) +} + +func (s *span) clean() { + //this presumes the points are already clean + if !s.End.isValid() || (s.End == point{}) { + s.End = s.Start + } +} + +func (p *point) clean() { + if p.Line < 0 { + p.Line = 0 + } + if p.Column <= 0 { + if p.Line > 0 { + p.Column = 1 + } else { + p.Column = 0 + } + } + if p.Offset == 0 && (p.Line > 1 || p.Column > 1) { + p.Offset = -1 + } +} + +// Format implements fmt.Formatter to print the Location in a standard form. +// The format produced is one that can be read back in using Parse. +func (s Span) Format(f fmt.State, c rune) { + fullForm := f.Flag('+') + preferOffset := f.Flag('#') + // we should always have a uri, simplify if it is file format + //TODO: make sure the end of the uri is unambiguous + uri := string(s.v.URI) + if c == 'f' { + uri = path.Base(uri) + } else if !fullForm { + uri = s.v.URI.Filename() + } + fmt.Fprint(f, uri) + if !s.IsValid() || (!fullForm && s.v.Start.isZero() && s.v.End.isZero()) { + return + } + // see which bits of start to write + printOffset := s.HasOffset() && (fullForm || preferOffset || !s.HasPosition()) + printLine := s.HasPosition() && (fullForm || !printOffset) + printColumn := printLine && (fullForm || (s.v.Start.Column > 1 || s.v.End.Column > 1)) + fmt.Fprint(f, ":") + if printLine { + fmt.Fprintf(f, "%d", s.v.Start.Line) + } + if printColumn { + fmt.Fprintf(f, ":%d", s.v.Start.Column) + } + if printOffset { + fmt.Fprintf(f, "#%d", s.v.Start.Offset) + } + // start is written, do we need end? + if s.IsPoint() { + return + } + // we don't print the line if it did not change + printLine = fullForm || (printLine && s.v.End.Line > s.v.Start.Line) + fmt.Fprint(f, "-") + if printLine { + fmt.Fprintf(f, "%d", s.v.End.Line) + } + if printColumn { + if printLine { + fmt.Fprint(f, ":") + } + fmt.Fprintf(f, "%d", s.v.End.Column) + } + if printOffset { + fmt.Fprintf(f, "#%d", s.v.End.Offset) + } +} + +func (s Span) WithPosition(c Converter) (Span, error) { + if err := s.update(c, true, false); err != nil { + return Span{}, err + } + return s, nil +} + +func (s Span) WithOffset(c Converter) (Span, error) { + if err := s.update(c, false, true); err != nil { + return Span{}, err + } + return s, nil +} + +func (s Span) WithAll(c Converter) (Span, error) { + if err := s.update(c, true, true); err != nil { + return Span{}, err + } + return s, nil +} + +func (s *Span) update(c Converter, withPos, withOffset bool) error { + if !s.IsValid() { + return fmt.Errorf("cannot add information to an invalid span") + } + if withPos && !s.HasPosition() { + if err := s.v.Start.updatePosition(c); err != nil { + return err + } + if s.v.End.Offset == s.v.Start.Offset { + s.v.End = s.v.Start + } else if err := s.v.End.updatePosition(c); err != nil { + return err + } + } + if withOffset && (!s.HasOffset() || (s.v.End.hasPosition() && !s.v.End.hasOffset())) { + if err := s.v.Start.updateOffset(c); err != nil { + return err + } + if s.v.End.Line == s.v.Start.Line && s.v.End.Column == s.v.Start.Column { + s.v.End.Offset = s.v.Start.Offset + } else if err := s.v.End.updateOffset(c); err != nil { + return err + } + } + return nil +} + +func (p *point) updatePosition(c Converter) error { + line, col, err := c.ToPosition(p.Offset) + if err != nil { + return err + } + p.Line = line + p.Column = col + return nil +} + +func (p *point) updateOffset(c Converter) error { + offset, err := c.ToOffset(p.Line, p.Column) + if err != nil { + return err + } + p.Offset = offset + return nil +} diff --git a/third_party/spirv-tools/utils/vscode/src/lsp/span/token.go b/third_party/spirv-tools/utils/vscode/src/lsp/span/token.go new file mode 100644 index 0000000000..f5a38708f7 --- /dev/null +++ b/third_party/spirv-tools/utils/vscode/src/lsp/span/token.go @@ -0,0 +1,161 @@ +// Copyright 2019 The Go Authors. +// +// 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. + +package span + +import ( + "fmt" + "go/token" +) + +// Range represents a source code range in token.Pos form. +// It also carries the FileSet that produced the positions, so that it is +// self contained. +type Range struct { + FileSet *token.FileSet + Start token.Pos + End token.Pos +} + +// TokenConverter is a Converter backed by a token file set and file. +// It uses the file set methods to work out the conversions, which +// makes it fast and does not require the file contents. +type TokenConverter struct { + fset *token.FileSet + file *token.File +} + +// NewRange creates a new Range from a FileSet and two positions. +// To represent a point pass a 0 as the end pos. +func NewRange(fset *token.FileSet, start, end token.Pos) Range { + return Range{ + FileSet: fset, + Start: start, + End: end, + } +} + +// NewTokenConverter returns an implementation of Converter backed by a +// token.File. +func NewTokenConverter(fset *token.FileSet, f *token.File) *TokenConverter { + return &TokenConverter{fset: fset, file: f} +} + +// NewContentConverter returns an implementation of Converter for the +// given file content. +func NewContentConverter(filename string, content []byte) *TokenConverter { + fset := token.NewFileSet() + f := fset.AddFile(filename, -1, len(content)) + f.SetLinesForContent(content) + return &TokenConverter{fset: fset, file: f} +} + +// IsPoint returns true if the range represents a single point. +func (r Range) IsPoint() bool { + return r.Start == r.End +} + +// Span converts a Range to a Span that represents the Range. +// It will fill in all the members of the Span, calculating the line and column +// information. +func (r Range) Span() (Span, error) { + f := r.FileSet.File(r.Start) + if f == nil { + return Span{}, fmt.Errorf("file not found in FileSet") + } + s := Span{v: span{URI: FileURI(f.Name())}} + var err error + s.v.Start.Offset, err = offset(f, r.Start) + if err != nil { + return Span{}, err + } + if r.End.IsValid() { + s.v.End.Offset, err = offset(f, r.End) + if err != nil { + return Span{}, err + } + } + s.v.Start.clean() + s.v.End.clean() + s.v.clean() + converter := NewTokenConverter(r.FileSet, f) + return s.WithPosition(converter) +} + +// offset is a copy of the Offset function in go/token, but with the adjustment +// that it does not panic on invalid positions. +func offset(f *token.File, pos token.Pos) (int, error) { + if int(pos) < f.Base() || int(pos) > f.Base()+f.Size() { + return 0, fmt.Errorf("invalid pos") + } + return int(pos) - f.Base(), nil +} + +// Range converts a Span to a Range that represents the Span for the supplied +// File. +func (s Span) Range(converter *TokenConverter) (Range, error) { + s, err := s.WithOffset(converter) + if err != nil { + return Range{}, err + } + // go/token will panic if the offset is larger than the file's size, + // so check here to avoid panicking. + if s.Start().Offset() > converter.file.Size() { + return Range{}, fmt.Errorf("start offset %v is past the end of the file %v", s.Start(), converter.file.Size()) + } + if s.End().Offset() > converter.file.Size() { + return Range{}, fmt.Errorf("end offset %v is past the end of the file %v", s.End(), converter.file.Size()) + } + return Range{ + FileSet: converter.fset, + Start: converter.file.Pos(s.Start().Offset()), + End: converter.file.Pos(s.End().Offset()), + }, nil +} + +func (l *TokenConverter) ToPosition(offset int) (int, int, error) { + if offset > l.file.Size() { + return 0, 0, fmt.Errorf("offset %v is past the end of the file %v", offset, l.file.Size()) + } + pos := l.file.Pos(offset) + p := l.fset.Position(pos) + if offset == l.file.Size() { + return p.Line + 1, 1, nil + } + return p.Line, p.Column, nil +} + +func (l *TokenConverter) ToOffset(line, col int) (int, error) { + if line < 0 { + return -1, fmt.Errorf("line is not valid") + } + lineMax := l.file.LineCount() + 1 + if line > lineMax { + return -1, fmt.Errorf("line is beyond end of file %v", lineMax) + } else if line == lineMax { + if col > 1 { + return -1, fmt.Errorf("column is beyond end of file") + } + // at the end of the file, allowing for a trailing eol + return l.file.Size(), nil + } + pos := lineStart(l.file, line) + if !pos.IsValid() { + return -1, fmt.Errorf("line is not in file") + } + // we assume that column is in bytes here, and that the first byte of a + // line is at column 1 + pos += token.Pos(col - 1) + return offset(l.file, pos) +} diff --git a/third_party/spirv-tools/utils/vscode/src/lsp/span/token111.go b/third_party/spirv-tools/utils/vscode/src/lsp/span/token111.go new file mode 100644 index 0000000000..768419a701 --- /dev/null +++ b/third_party/spirv-tools/utils/vscode/src/lsp/span/token111.go @@ -0,0 +1,49 @@ +// Copyright 2019 The Go Authors. +// +// 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. + +// +build !go1.12 + +package span + +import ( + "go/token" +) + +// lineStart is the pre-Go 1.12 version of (*token.File).LineStart. For Go +// versions <= 1.11, we borrow logic from the analysisutil package. +// TODO(rstambler): Delete this file when we no longer support Go 1.11. +func lineStart(f *token.File, line int) token.Pos { + // Use binary search to find the start offset of this line. + + min := 0 // inclusive + max := f.Size() // exclusive + for { + offset := (min + max) / 2 + pos := f.Pos(offset) + posn := f.Position(pos) + if posn.Line == line { + return pos - (token.Pos(posn.Column) - 1) + } + + if min+1 >= max { + return token.NoPos + } + + if posn.Line < line { + min = offset + } else { + max = offset + } + } +} diff --git a/third_party/spirv-tools/utils/vscode/src/lsp/span/token112.go b/third_party/spirv-tools/utils/vscode/src/lsp/span/token112.go new file mode 100644 index 0000000000..abff500d2b --- /dev/null +++ b/third_party/spirv-tools/utils/vscode/src/lsp/span/token112.go @@ -0,0 +1,26 @@ +// Copyright 2019 The Go Authors. +// +// 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. + +// +build go1.12 + +package span + +import ( + "go/token" +) + +// TODO(rstambler): Delete this file when we no longer support Go 1.11. +func lineStart(f *token.File, line int) token.Pos { + return f.LineStart(line) +} diff --git a/third_party/spirv-tools/utils/vscode/src/lsp/span/uri.go b/third_party/spirv-tools/utils/vscode/src/lsp/span/uri.go new file mode 100644 index 0000000000..525518bef2 --- /dev/null +++ b/third_party/spirv-tools/utils/vscode/src/lsp/span/uri.go @@ -0,0 +1,162 @@ +// Copyright 2019 The Go Authors. +// +// 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. + +package span + +import ( + "fmt" + "net/url" + "os" + "path" + "path/filepath" + "runtime" + "strings" + "unicode" +) + +const fileScheme = "file" + +// URI represents the full URI for a file. +type URI string + +// Filename returns the file path for the given URI. +// It is an error to call this on a URI that is not a valid filename. +func (uri URI) Filename() string { + filename, err := filename(uri) + if err != nil { + panic(err) + } + return filepath.FromSlash(filename) +} + +func filename(uri URI) (string, error) { + if uri == "" { + return "", nil + } + u, err := url.ParseRequestURI(string(uri)) + if err != nil { + return "", err + } + if u.Scheme != fileScheme { + return "", fmt.Errorf("only file URIs are supported, got %q from %q", u.Scheme, uri) + } + if isWindowsDriveURI(u.Path) { + u.Path = u.Path[1:] + } + return u.Path, nil +} + +// NewURI returns a span URI for the string. +// It will attempt to detect if the string is a file path or uri. +func NewURI(s string) URI { + if u, err := url.PathUnescape(s); err == nil { + s = u + } + if strings.HasPrefix(s, fileScheme+"://") { + return URI(s) + } + return FileURI(s) +} + +func CompareURI(a, b URI) int { + if equalURI(a, b) { + return 0 + } + if a < b { + return -1 + } + return 1 +} + +func equalURI(a, b URI) bool { + if a == b { + return true + } + // If we have the same URI basename, we may still have the same file URIs. + if !strings.EqualFold(path.Base(string(a)), path.Base(string(b))) { + return false + } + fa, err := filename(a) + if err != nil { + return false + } + fb, err := filename(b) + if err != nil { + return false + } + // Stat the files to check if they are equal. + infoa, err := os.Stat(filepath.FromSlash(fa)) + if err != nil { + return false + } + infob, err := os.Stat(filepath.FromSlash(fb)) + if err != nil { + return false + } + return os.SameFile(infoa, infob) +} + +// FileURI returns a span URI for the supplied file path. +// It will always have the file scheme. +func FileURI(path string) URI { + if path == "" { + return "" + } + // Handle standard library paths that contain the literal "$GOROOT". + // TODO(rstambler): The go/packages API should allow one to determine a user's $GOROOT. + const prefix = "$GOROOT" + if len(path) >= len(prefix) && strings.EqualFold(prefix, path[:len(prefix)]) { + suffix := path[len(prefix):] + path = runtime.GOROOT() + suffix + } + if !isWindowsDrivePath(path) { + if abs, err := filepath.Abs(path); err == nil { + path = abs + } + } + // Check the file path again, in case it became absolute. + if isWindowsDrivePath(path) { + path = "/" + path + } + path = filepath.ToSlash(path) + u := url.URL{ + Scheme: fileScheme, + Path: path, + } + uri := u.String() + if unescaped, err := url.PathUnescape(uri); err == nil { + uri = unescaped + } + return URI(uri) +} + +// isWindowsDrivePath returns true if the file path is of the form used by +// Windows. We check if the path begins with a drive letter, followed by a ":". +func isWindowsDrivePath(path string) bool { + if len(path) < 4 { + return false + } + return unicode.IsLetter(rune(path[0])) && path[1] == ':' +} + +// isWindowsDriveURI returns true if the file URI is of the format used by +// Windows URIs. The url.Parse package does not specially handle Windows paths +// (see https://golang.org/issue/6027). We check if the URI path has +// a drive prefix (e.g. "/C:"). If so, we trim the leading "/". +func isWindowsDriveURI(uri string) bool { + if len(uri) < 4 { + return false + } + return uri[0] == '/' && unicode.IsLetter(rune(uri[1])) && uri[2] == ':' +} diff --git a/third_party/spirv-tools/utils/vscode/src/lsp/span/utf16.go b/third_party/spirv-tools/utils/vscode/src/lsp/span/utf16.go new file mode 100644 index 0000000000..6821851d18 --- /dev/null +++ b/third_party/spirv-tools/utils/vscode/src/lsp/span/utf16.go @@ -0,0 +1,104 @@ +// Copyright 2019 The Go Authors. +// +// 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. + +package span + +import ( + "fmt" + "unicode/utf16" + "unicode/utf8" +) + +// ToUTF16Column calculates the utf16 column expressed by the point given the +// supplied file contents. +// This is used to convert from the native (always in bytes) column +// representation and the utf16 counts used by some editors. +func ToUTF16Column(p Point, content []byte) (int, error) { + if content == nil { + return -1, fmt.Errorf("ToUTF16Column: missing content") + } + if !p.HasPosition() { + return -1, fmt.Errorf("ToUTF16Column: point is missing position") + } + if !p.HasOffset() { + return -1, fmt.Errorf("ToUTF16Column: point is missing offset") + } + offset := p.Offset() // 0-based + colZero := p.Column() - 1 // 0-based + if colZero == 0 { + // 0-based column 0, so it must be chr 1 + return 1, nil + } else if colZero < 0 { + return -1, fmt.Errorf("ToUTF16Column: column is invalid (%v)", colZero) + } + // work out the offset at the start of the line using the column + lineOffset := offset - colZero + if lineOffset < 0 || offset > len(content) { + return -1, fmt.Errorf("ToUTF16Column: offsets %v-%v outside file contents (%v)", lineOffset, offset, len(content)) + } + // Use the offset to pick out the line start. + // This cannot panic: offset > len(content) and lineOffset < offset. + start := content[lineOffset:] + + // Now, truncate down to the supplied column. + start = start[:colZero] + + // and count the number of utf16 characters + // in theory we could do this by hand more efficiently... + return len(utf16.Encode([]rune(string(start)))) + 1, nil +} + +// FromUTF16Column advances the point by the utf16 character offset given the +// supplied line contents. +// This is used to convert from the utf16 counts used by some editors to the +// native (always in bytes) column representation. +func FromUTF16Column(p Point, chr int, content []byte) (Point, error) { + if !p.HasOffset() { + return Point{}, fmt.Errorf("FromUTF16Column: point is missing offset") + } + // if chr is 1 then no adjustment needed + if chr <= 1 { + return p, nil + } + if p.Offset() >= len(content) { + return p, fmt.Errorf("FromUTF16Column: offset (%v) greater than length of content (%v)", p.Offset(), len(content)) + } + remains := content[p.Offset():] + // scan forward the specified number of characters + for count := 1; count < chr; count++ { + if len(remains) <= 0 { + return Point{}, fmt.Errorf("FromUTF16Column: chr goes beyond the content") + } + r, w := utf8.DecodeRune(remains) + if r == '\n' { + // Per the LSP spec: + // + // > If the character value is greater than the line length it + // > defaults back to the line length. + break + } + remains = remains[w:] + if r >= 0x10000 { + // a two point rune + count++ + // if we finished in a two point rune, do not advance past the first + if count >= chr { + break + } + } + p.v.Column += w + p.v.Offset += w + } + return p, nil +} diff --git a/third_party/spirv-tools/utils/vscode/src/parser/parser.go b/third_party/spirv-tools/utils/vscode/src/parser/parser.go new file mode 100644 index 0000000000..64ba462d53 --- /dev/null +++ b/third_party/spirv-tools/utils/vscode/src/parser/parser.go @@ -0,0 +1,763 @@ +// Copyright (C) 2019 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package parser implements a SPIR-V assembly parser. +package parser + +import ( + "fmt" + "io" + "log" + "strings" + "unicode" + "unicode/utf8" + + "../schema" +) + +// Type is an enumerator of token types. +type Type int + +// Type enumerators +const ( + Ident Type = iota // Foo + PIdent // %32, %foo + Integer + Float + String + Operator + Comment + Newline +) + +func (t Type) String() string { + switch t { + case Ident: + return "Ident" + case PIdent: + return "PIdent" + case Integer: + return "Integer" + case Float: + return "Float" + case String: + return "String" + case Operator: + return "Operator" + case Comment: + return "Comment" + default: + return "" + } +} + +// Token represents a single lexed token. +type Token struct { + Type Type + Range Range +} + +func (t Token) String() string { return fmt.Sprintf("{%v %v}", t.Type, t.Range) } + +// Text returns the tokens text from the source. +func (t Token) Text(lines []string) string { return t.Range.Text(lines) } + +// Range represents an interval in a text file. +type Range struct { + Start Position + End Position +} + +func (r Range) String() string { return fmt.Sprintf("[%v %v]", r.Start, r.End) } + +// Text returns the text for the given Range in the provided lines. +func (r Range) Text(lines []string) string { + sl, sc := r.Start.Line-1, r.Start.Column-1 + if sl < 0 || sc < 0 || sl > len(lines) || sc > len(lines[sl]) { + return fmt.Sprintf("", r.Start) + } + el, ec := r.End.Line-1, r.End.Column-1 + if el < 0 || ec < 0 || el > len(lines) || ec > len(lines[sl]) { + return fmt.Sprintf("", r.End) + } + + sb := strings.Builder{} + if sl != el { + sb.WriteString(lines[sl][sc:]) + for l := sl + 1; l < el; l++ { + sb.WriteString(lines[l]) + } + sb.WriteString(lines[el][:ec]) + } else { + sb.WriteString(lines[sl][sc:ec]) + } + return sb.String() +} + +// Contains returns true if p is in r. +func (r Range) Contains(p Position) bool { + return !(p.LessThan(r.Start) || p.GreaterThan(r.End)) +} + +func (r *Range) grow(o Range) { + if !r.Start.IsValid() || o.Start.LessThan(r.Start) { + r.Start = o.Start + } + if !r.End.IsValid() || o.End.GreaterThan(r.End) { + r.End = o.End + } +} + +// Position holds a line and column position in a text file. +type Position struct { + Line, Column int +} + +func (p Position) String() string { return fmt.Sprintf("%v:%v", p.Line, p.Column) } + +// IsValid returns true if the position has a line and column greater than 1. +func (p Position) IsValid() bool { return p.Line > 0 && p.Column > 0 } + +// LessThan returns true iff o is before p. +func (p Position) LessThan(o Position) bool { + switch { + case !p.IsValid() || !o.IsValid(): + return false + case p.Line < o.Line: + return true + case p.Line > o.Line: + return false + case p.Column < o.Column: + return true + default: + return false + } +} + +// GreaterThan returns true iff o is greater than p. +func (p Position) GreaterThan(o Position) bool { + switch { + case !p.IsValid() || !o.IsValid(): + return false + case p.Line > o.Line: + return true + case p.Line < o.Line: + return false + case p.Column > o.Column: + return true + default: + return false + } +} + +type lexer struct { + source string + lexerState + diags []Diagnostic + e error +} + +type lexerState struct { + offset int // byte offset in source + toks []*Token // all the lexed tokens + pos Position // current position +} + +// err appends an fmt.Printf style error into l.diags for the given token. +func (l *lexer) err(tok *Token, msg string, args ...interface{}) { + rng := Range{} + if tok != nil { + rng = tok.Range + } + l.diags = append(l.diags, Diagnostic{ + Range: rng, + Severity: SeverityError, + Message: fmt.Sprintf(msg, args...), + }) +} + +// next returns the next rune, or io.EOF if the last rune has already been +// consumed. +func (l *lexer) next() rune { + if l.offset >= len(l.source) { + l.e = io.EOF + return 0 + } + r, n := utf8.DecodeRuneInString(l.source[l.offset:]) + l.offset += n + if n == 0 { + l.e = io.EOF + return 0 + } + if r == '\n' { + l.pos.Line++ + l.pos.Column = 1 + } else { + l.pos.Column++ + } + return r +} + +// save returns the current lexerState. +func (l *lexer) save() lexerState { + return l.lexerState +} + +// restore restores the current lexer state with s. +func (l *lexer) restore(s lexerState) { + l.lexerState = s +} + +// pident processes the PIdent token at the current position. +// The lexer *must* know the next token is a PIdent before calling. +func (l *lexer) pident() { + tok := &Token{Type: PIdent, Range: Range{Start: l.pos, End: l.pos}} + if r := l.next(); r != '%' { + log.Fatalf("lexer expected '%%', got '%v'", r) + return + } + for l.e == nil { + s := l.save() + r := l.next() + if !isAlphaNumeric(r) && r != '_' { + l.restore(s) + break + } + } + tok.Range.End = l.pos + l.toks = append(l.toks, tok) +} + +// numberOrIdent processes the Ident, Float or Integer token at the current +// position. +func (l *lexer) numberOrIdent() { + const Unknown Type = -1 + tok := &Token{Type: Unknown, Range: Range{Start: l.pos, End: l.pos}} +loop: + for l.e == nil { + s := l.save() + r := l.next() + switch { + case r == '-', r == '+', isNumeric(r): + continue + case isAlpha(r), r == '_': + switch tok.Type { + case Unknown: + tok.Type = Ident + case Float, Integer: + l.err(tok, "invalid number") + return + } + case r == '.': + switch tok.Type { + case Unknown: + tok.Type = Float + default: + l.restore(s) + break loop + } + default: + if tok.Type == Unknown { + tok.Type = Integer + } + l.restore(s) + break loop + } + } + tok.Range.End = l.pos + l.toks = append(l.toks, tok) +} + +// string processes the String token at the current position. +// The lexer *must* know the next token is a String before calling. +func (l *lexer) string() { + tok := &Token{Type: String, Range: Range{Start: l.pos, End: l.pos}} + if r := l.next(); r != '"' { + log.Fatalf("lexer expected '\"', got '%v'", r) + return + } + escape := false + for l.e == nil { + switch l.next() { + case '"': + if !escape { + tok.Range.End = l.pos + l.toks = append(l.toks, tok) + return + } + case '\\': + escape = !escape + default: + escape = false + } + } +} + +// operator processes the Operator token at the current position. +// The lexer *must* know the next token is a Operator before calling. +func (l *lexer) operator() { + tok := &Token{Type: Operator, Range: Range{Start: l.pos, End: l.pos}} + for l.e == nil { + switch l.next() { + case '=': + tok.Range.End = l.pos + l.toks = append(l.toks, tok) + return + } + } +} + +// lineComment processes the Comment token at the current position. +// The lexer *must* know the next token is a Comment before calling. +func (l *lexer) lineComment() { + tok := &Token{Type: Comment, Range: Range{Start: l.pos, End: l.pos}} + if r := l.next(); r != ';' { + log.Fatalf("lexer expected ';', got '%v'", r) + return + } + for l.e == nil { + s := l.save() + switch l.next() { + case '\n': + l.restore(s) + tok.Range.End = l.pos + l.toks = append(l.toks, tok) + return + } + } +} + +// newline processes the Newline token at the current position. +// The lexer *must* know the next token is a Newline before calling. +func (l *lexer) newline() { + tok := &Token{Type: Newline, Range: Range{Start: l.pos, End: l.pos}} + if r := l.next(); r != '\n' { + log.Fatalf("lexer expected '\n', got '%v'", r) + return + } + tok.Range.End = l.pos + l.toks = append(l.toks, tok) +} + +// lex returns all the tokens and diagnostics after lexing source. +func lex(source string) ([]*Token, []Diagnostic, error) { + l := lexer{source: source, lexerState: lexerState{pos: Position{1, 1}}} + + lastPos := Position{} + for l.e == nil { + // Sanity check the parser is making progress + if l.pos == lastPos { + log.Panicf("Parsing stuck at %v", l.pos) + } + lastPos = l.pos + + s := l.save() + r := l.next() + switch { + case r == '%': + l.restore(s) + l.pident() + case r == '+' || r == '-' || r == '_' || isAlphaNumeric(r): + l.restore(s) + l.numberOrIdent() + case r == '"': + l.restore(s) + l.string() + case r == '=': + l.restore(s) + l.operator() + case r == ';': + l.restore(s) + l.lineComment() + case r == '\n': + l.restore(s) + l.newline() + } + } + if l.e != nil && l.e != io.EOF { + return nil, nil, l.e + } + return l.toks, l.diags, nil +} + +func isNumeric(r rune) bool { return unicode.IsDigit(r) } +func isAlpha(r rune) bool { return unicode.IsLetter(r) } +func isAlphaNumeric(r rune) bool { return isAlpha(r) || isNumeric(r) } + +type parser struct { + lines []string // all source lines + toks []*Token // all tokens + diags []Diagnostic // parser emitted diagnostics + idents map[string]*Identifier // identifiers by name + mappings map[*Token]interface{} // tokens to semantic map + insts []*Instruction // all instructions +} + +func (p *parser) parse() error { + for i := 0; i < len(p.toks); { + if p.newline(i) || p.comment(i) { + i++ + continue + } + if n := p.instruction(i); n > 0 { + i += n + } else { + p.unexpected(i) + i++ + } + } + return nil +} + +// instruction parses the instruction starting at the i'th token. +func (p *parser) instruction(i int) (n int) { + inst := &Instruction{} + + switch { + case p.opcode(i) != nil: + inst.Opcode = p.opcode(i) + inst.Tokens = []*Token{p.tok(i)} + p.mappings[p.tok(i)] = inst + n++ + case p.opcode(i+2) != nil: // try '%id' '=' + inst.Result, inst.Opcode = p.pident(i), p.opcode(i+2) + if inst.Result == nil || p.operator(i+1) != "=" { + return 0 + } + n += 3 + inst.Tokens = []*Token{p.tok(i), p.tok(i + 1), p.tok(i + 2)} + p.mappings[p.tok(i+2)] = inst + default: + return + } + + expectsResult := len(inst.Opcode.Operands) > 0 && IsResult(inst.Opcode.Operands[0].Kind) + operands := inst.Opcode.Operands + switch { + case inst.Result != nil && !expectsResult: + p.err(inst.Result, "'%s' does not have a result", inst.Opcode.Opname) + return + case inst.Result == nil && expectsResult: + p.err(p.tok(i), "'%s' expects a result", inst.Opcode.Opname) + return + case inst.Result != nil && expectsResult: + // Check the result is of the correct type + o := inst.Opcode.Operands[0] + p.operand(o.Name, o.Kind, i, false) + operands = operands[1:] + p.addIdentDef(inst.Result.Text(p.lines), inst, p.tok(i)) + } + + for _, o := range operands { + if p.newline(i + n) { + break + } + + switch o.Quantifier { + case schema.Once: + if op, c := p.operand(o.Name, o.Kind, i+n, false); op != nil { + inst.Tokens = append(inst.Tokens, op.Tokens...) + n += c + } + case schema.ZeroOrOnce: + if op, c := p.operand(o.Name, o.Kind, i+n, true); op != nil { + inst.Tokens = append(inst.Tokens, op.Tokens...) + n += c + } + case schema.ZeroOrMany: + for !p.newline(i + n) { + if op, c := p.operand(o.Name, o.Kind, i+n, true); op != nil { + inst.Tokens = append(inst.Tokens, op.Tokens...) + n += c + } else { + break + } + } + } + } + + for _, t := range inst.Tokens { + inst.Range.grow(t.Range) + } + + p.insts = append(p.insts, inst) + return +} + +// operand parses the operand with the name n, kind k, starting at the i'th +// token. +func (p *parser) operand(n string, k *schema.OperandKind, i int, optional bool) (*Operand, int) { + tok := p.tok(i) + if tok == nil { + return nil, 0 + } + + op := &Operand{ + Name: n, + Kind: k, + Tokens: []*Token{tok}, + } + p.mappings[tok] = op + + switch k.Category { + case schema.OperandCategoryBitEnum, schema.OperandCategoryValueEnum: + s := tok.Text(p.lines) + for _, e := range k.Enumerants { + if e.Enumerant == s { + n := 1 + for _, param := range e.Parameters { + p, c := p.operand(param.Name, param.Kind, i+n, false) + if p != nil { + op.Tokens = append(op.Tokens, p.Tokens...) + op.Parameters = append(op.Parameters, p) + } + n += c + } + return op, n + } + } + if !optional { + p.err(p.tok(i), "invalid operand value '%s'", s) + } + return nil, 0 + + case schema.OperandCategoryID: + id := p.pident(i) + if id != nil { + p.addIdentRef(p.tok(i)) + return op, 1 + } + if !optional { + p.err(p.tok(i), "operand requires id, got '%s'", tok.Text(p.lines)) + } + return nil, 0 + + case schema.OperandCategoryLiteral: + switch tok.Type { + case String, Integer, Float: + return op, 1 + } + if !optional { + p.err(p.tok(i), "operand requires literal, got '%s'", tok.Text(p.lines)) + } + return nil, 0 + + case schema.OperandCategoryComposite: + n := 1 + for _, b := range k.Bases { + o, c := p.operand(b.Kind, b, i+n, optional) + if o != nil { + op.Tokens = append(op.Tokens, o.Tokens...) + } + n += c + } + return op, n + + default: + p.err(p.tok(i), "OperandKind '%s' has unexpected category '%s'", k.Kind, k.Category) + return nil, 0 + } +} + +// tok returns the i'th token, or nil if i is out of bounds. +func (p *parser) tok(i int) *Token { + if i < 0 || i >= len(p.toks) { + return nil + } + return p.toks[i] +} + +// opcode returns the schema.Opcode for the i'th token, or nil if the i'th token +// does not represent an opcode. +func (p *parser) opcode(i int) *schema.Opcode { + if tok := p.ident(i); tok != nil { + name := tok.Text(p.lines) + if inst, found := schema.Opcodes[name]; found { + return inst + } + } + return nil +} + +// operator returns the operator for the i'th token, or and empty string if the +// i'th token is not an operator. +func (p *parser) operator(i int) string { + if tok := p.tok(i); tok != nil && tok.Type == Operator { + return tok.Text(p.lines) + } + return "" +} + +// ident returns the i'th token if it is an Ident, otherwise nil. +func (p *parser) ident(i int) *Token { + if tok := p.tok(i); tok != nil && tok.Type == Ident { + return tok + } + return nil +} + +// pident returns the i'th token if it is an PIdent, otherwise nil. +func (p *parser) pident(i int) *Token { + if tok := p.tok(i); tok != nil && tok.Type == PIdent { + return tok + } + return nil +} + +// comment returns true if the i'th token is a Comment, otherwise false. +func (p *parser) comment(i int) bool { + if tok := p.tok(i); tok != nil && tok.Type == Comment { + return true + } + return false +} + +// newline returns true if the i'th token is a Newline, otherwise false. +func (p *parser) newline(i int) bool { + if tok := p.tok(i); tok != nil && tok.Type == Newline { + return true + } + return false +} + +// unexpected emits an 'unexpected token error' for the i'th token. +func (p *parser) unexpected(i int) { + p.err(p.toks[i], "syntax error: unexpected '%s'", p.toks[i].Text(p.lines)) +} + +// addIdentDef records the token definition for the instruction inst with the +// given id. +func (p *parser) addIdentDef(id string, inst *Instruction, def *Token) { + i, existing := p.idents[id] + if !existing { + i = &Identifier{} + p.idents[id] = i + } + if i.Definition == nil { + i.Definition = inst + } else { + p.err(def, "id '%v' redeclared", id) + } +} + +// addIdentRef adds a identifier reference for the token ref. +func (p *parser) addIdentRef(ref *Token) { + id := ref.Text(p.lines) + i, existing := p.idents[id] + if !existing { + i = &Identifier{} + p.idents[id] = i + } + i.References = append(i.References, ref) +} + +// err appends an fmt.Printf style error into l.diags for the given token. +func (p *parser) err(tok *Token, msg string, args ...interface{}) { + rng := Range{} + if tok != nil { + rng = tok.Range + } + p.diags = append(p.diags, Diagnostic{ + Range: rng, + Severity: SeverityError, + Message: fmt.Sprintf(msg, args...), + }) +} + +// Parse parses the SPIR-V assembly string source, returning the parse results. +func Parse(source string) (Results, error) { + toks, diags, err := lex(source) + if err != nil { + return Results{}, err + } + lines := strings.SplitAfter(source, "\n") + p := parser{ + lines: lines, + toks: toks, + idents: map[string]*Identifier{}, + mappings: map[*Token]interface{}{}, + } + if err := p.parse(); err != nil { + return Results{}, err + } + diags = append(diags, p.diags...) + return Results{ + Lines: lines, + Tokens: toks, + Diagnostics: p.diags, + Identifiers: p.idents, + Mappings: p.mappings, + }, nil +} + +// IsResult returns true if k is used to store the result of an instruction. +func IsResult(k *schema.OperandKind) bool { + switch k { + case schema.OperandKindIdResult, schema.OperandKindIdResultType: + return true + default: + return false + } +} + +// Results holds the output of Parse(). +type Results struct { + Lines []string + Tokens []*Token + Diagnostics []Diagnostic + Identifiers map[string]*Identifier // identifiers by name + Mappings map[*Token]interface{} // tokens to semantic map +} + +// Instruction describes a single instruction instance +type Instruction struct { + Tokens []*Token // all the tokens that make up the instruction + Result *Token // the token that represents the result of the instruction, or nil + Operands []*Operand // the operands of the instruction + Range Range // the textual range of the instruction + Opcode *schema.Opcode // the opcode for the instruction +} + +// Operand describes a single operand instance +type Operand struct { + Name string // name of the operand + Kind *schema.OperandKind // kind of the operand + Tokens []*Token // all the tokens that make up the operand + Parameters []*Operand // all the parameters for the operand +} + +// Identifier describes a single, unique SPIR-V identifier (i.e. %32) +type Identifier struct { + Definition *Instruction // where the identifier was defined + References []*Token // all the places the identifier was referenced +} + +// Severity is an enumerator of diagnositc seeverities +type Severity int + +// Severity levels +const ( + SeverityError Severity = iota + SeverityWarning + SeverityInformation + SeverityHint +) + +// Diagnostic holds a single diagnostic message that was generated while +// parsing. +type Diagnostic struct { + Range Range + Severity Severity + Message string +} diff --git a/third_party/spirv-tools/utils/vscode/src/schema/schema.go b/third_party/spirv-tools/utils/vscode/src/schema/schema.go new file mode 100755 index 0000000000..c7e1ca4948 --- /dev/null +++ b/third_party/spirv-tools/utils/vscode/src/schema/schema.go @@ -0,0 +1,18118 @@ +// Copyright (C) 2019 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Generated by gen-grammar.go --template=../schema/schema.go.tmpl --out=../schema/schema.go +// Do not modify this file directly. + +package schema + +// Opcode holds information about a specific SPIR-V opcode. +type Opcode struct { + Opname string + Class string + Opcode int + Operands []Operand +} + +// Operand contains information about a logical operand for an instruction. +type Operand struct { + Kind *OperandKind + Name string + Quantifier Quantifier +} + +// OperandKind contains information about a specific operand kind. +type OperandKind struct { + Category OperandCategory + Kind string + Enumerants []Enumerant + Bases []*OperandKind +} + +// Enumerant contains information about an enumerant in an enum. +type Enumerant struct { + Enumerant string + Value interface{} + Capabilities []string + Parameters []Parameter + Version string +} + +// Parameter contains information about a logical parameter for an enumerant. +type Parameter struct { + Kind *OperandKind + Name string +} + +// Quantifier indicates the number of times the quantified term may appear. +type Quantifier string + +const ( + // Once indicates the quantified term may appear exactly once. + Once Quantifier = "" + + // ZeroOrOnce indicates the quantified term may appear zero or one + // time; an optional term. + ZeroOrOnce Quantifier = "?" + + // ZeroOrMany indicates the quantified term may appear any number of + // times. + ZeroOrMany Quantifier = "*" +) + +// OperandCategory is an enumerator that groups operand kinds. +type OperandCategory string + +const ( + // OperandCategoryBitEnum describes an operand kind where its value is a + // mask, which is formed by combining the bits specified as enumerants in an + // enum. + OperandCategoryBitEnum = "BitEnum" + + // OperandCategoryValueEnum describes an operand kind where its value is an + // enumerant from an enum. + OperandCategoryValueEnum = "ValueEnum" + + // OperandCategoryID describes and operand kind where its value is an + // definition or reference. + OperandCategoryID = "Id" + + // OperandCategoryLiteral describes and operand kind where its value is an + // literal number or string. + OperandCategoryLiteral = "Literal" + + // OperandCategoryComposite describes and operand kind where its value is + // composed from operand values from the above categories. + OperandCategoryComposite = "Composite" +) + +var ( + // Opcodes is a map of opcode name to Opcode description. + Opcodes = map[string]*Opcode { + "OpNop": OpNop, + "OpUndef": OpUndef, + "OpSourceContinued": OpSourceContinued, + "OpSource": OpSource, + "OpSourceExtension": OpSourceExtension, + "OpName": OpName, + "OpMemberName": OpMemberName, + "OpString": OpString, + "OpLine": OpLine, + "OpExtension": OpExtension, + "OpExtInstImport": OpExtInstImport, + "OpExtInst": OpExtInst, + "OpMemoryModel": OpMemoryModel, + "OpEntryPoint": OpEntryPoint, + "OpExecutionMode": OpExecutionMode, + "OpCapability": OpCapability, + "OpTypeVoid": OpTypeVoid, + "OpTypeBool": OpTypeBool, + "OpTypeInt": OpTypeInt, + "OpTypeFloat": OpTypeFloat, + "OpTypeVector": OpTypeVector, + "OpTypeMatrix": OpTypeMatrix, + "OpTypeImage": OpTypeImage, + "OpTypeSampler": OpTypeSampler, + "OpTypeSampledImage": OpTypeSampledImage, + "OpTypeArray": OpTypeArray, + "OpTypeRuntimeArray": OpTypeRuntimeArray, + "OpTypeStruct": OpTypeStruct, + "OpTypeOpaque": OpTypeOpaque, + "OpTypePointer": OpTypePointer, + "OpTypeFunction": OpTypeFunction, + "OpTypeEvent": OpTypeEvent, + "OpTypeDeviceEvent": OpTypeDeviceEvent, + "OpTypeReserveId": OpTypeReserveId, + "OpTypeQueue": OpTypeQueue, + "OpTypePipe": OpTypePipe, + "OpTypeForwardPointer": OpTypeForwardPointer, + "OpConstantTrue": OpConstantTrue, + "OpConstantFalse": OpConstantFalse, + "OpConstant": OpConstant, + "OpConstantComposite": OpConstantComposite, + "OpConstantSampler": OpConstantSampler, + "OpConstantNull": OpConstantNull, + "OpSpecConstantTrue": OpSpecConstantTrue, + "OpSpecConstantFalse": OpSpecConstantFalse, + "OpSpecConstant": OpSpecConstant, + "OpSpecConstantComposite": OpSpecConstantComposite, + "OpSpecConstantOp": OpSpecConstantOp, + "OpFunction": OpFunction, + "OpFunctionParameter": OpFunctionParameter, + "OpFunctionEnd": OpFunctionEnd, + "OpFunctionCall": OpFunctionCall, + "OpVariable": OpVariable, + "OpImageTexelPointer": OpImageTexelPointer, + "OpLoad": OpLoad, + "OpStore": OpStore, + "OpCopyMemory": OpCopyMemory, + "OpCopyMemorySized": OpCopyMemorySized, + "OpAccessChain": OpAccessChain, + "OpInBoundsAccessChain": OpInBoundsAccessChain, + "OpPtrAccessChain": OpPtrAccessChain, + "OpArrayLength": OpArrayLength, + "OpGenericPtrMemSemantics": OpGenericPtrMemSemantics, + "OpInBoundsPtrAccessChain": OpInBoundsPtrAccessChain, + "OpDecorate": OpDecorate, + "OpMemberDecorate": OpMemberDecorate, + "OpDecorationGroup": OpDecorationGroup, + "OpGroupDecorate": OpGroupDecorate, + "OpGroupMemberDecorate": OpGroupMemberDecorate, + "OpVectorExtractDynamic": OpVectorExtractDynamic, + "OpVectorInsertDynamic": OpVectorInsertDynamic, + "OpVectorShuffle": OpVectorShuffle, + "OpCompositeConstruct": OpCompositeConstruct, + "OpCompositeExtract": OpCompositeExtract, + "OpCompositeInsert": OpCompositeInsert, + "OpCopyObject": OpCopyObject, + "OpTranspose": OpTranspose, + "OpSampledImage": OpSampledImage, + "OpImageSampleImplicitLod": OpImageSampleImplicitLod, + "OpImageSampleExplicitLod": OpImageSampleExplicitLod, + "OpImageSampleDrefImplicitLod": OpImageSampleDrefImplicitLod, + "OpImageSampleDrefExplicitLod": OpImageSampleDrefExplicitLod, + "OpImageSampleProjImplicitLod": OpImageSampleProjImplicitLod, + "OpImageSampleProjExplicitLod": OpImageSampleProjExplicitLod, + "OpImageSampleProjDrefImplicitLod": OpImageSampleProjDrefImplicitLod, + "OpImageSampleProjDrefExplicitLod": OpImageSampleProjDrefExplicitLod, + "OpImageFetch": OpImageFetch, + "OpImageGather": OpImageGather, + "OpImageDrefGather": OpImageDrefGather, + "OpImageRead": OpImageRead, + "OpImageWrite": OpImageWrite, + "OpImage": OpImage, + "OpImageQueryFormat": OpImageQueryFormat, + "OpImageQueryOrder": OpImageQueryOrder, + "OpImageQuerySizeLod": OpImageQuerySizeLod, + "OpImageQuerySize": OpImageQuerySize, + "OpImageQueryLod": OpImageQueryLod, + "OpImageQueryLevels": OpImageQueryLevels, + "OpImageQuerySamples": OpImageQuerySamples, + "OpConvertFToU": OpConvertFToU, + "OpConvertFToS": OpConvertFToS, + "OpConvertSToF": OpConvertSToF, + "OpConvertUToF": OpConvertUToF, + "OpUConvert": OpUConvert, + "OpSConvert": OpSConvert, + "OpFConvert": OpFConvert, + "OpQuantizeToF16": OpQuantizeToF16, + "OpConvertPtrToU": OpConvertPtrToU, + "OpSatConvertSToU": OpSatConvertSToU, + "OpSatConvertUToS": OpSatConvertUToS, + "OpConvertUToPtr": OpConvertUToPtr, + "OpPtrCastToGeneric": OpPtrCastToGeneric, + "OpGenericCastToPtr": OpGenericCastToPtr, + "OpGenericCastToPtrExplicit": OpGenericCastToPtrExplicit, + "OpBitcast": OpBitcast, + "OpSNegate": OpSNegate, + "OpFNegate": OpFNegate, + "OpIAdd": OpIAdd, + "OpFAdd": OpFAdd, + "OpISub": OpISub, + "OpFSub": OpFSub, + "OpIMul": OpIMul, + "OpFMul": OpFMul, + "OpUDiv": OpUDiv, + "OpSDiv": OpSDiv, + "OpFDiv": OpFDiv, + "OpUMod": OpUMod, + "OpSRem": OpSRem, + "OpSMod": OpSMod, + "OpFRem": OpFRem, + "OpFMod": OpFMod, + "OpVectorTimesScalar": OpVectorTimesScalar, + "OpMatrixTimesScalar": OpMatrixTimesScalar, + "OpVectorTimesMatrix": OpVectorTimesMatrix, + "OpMatrixTimesVector": OpMatrixTimesVector, + "OpMatrixTimesMatrix": OpMatrixTimesMatrix, + "OpOuterProduct": OpOuterProduct, + "OpDot": OpDot, + "OpIAddCarry": OpIAddCarry, + "OpISubBorrow": OpISubBorrow, + "OpUMulExtended": OpUMulExtended, + "OpSMulExtended": OpSMulExtended, + "OpAny": OpAny, + "OpAll": OpAll, + "OpIsNan": OpIsNan, + "OpIsInf": OpIsInf, + "OpIsFinite": OpIsFinite, + "OpIsNormal": OpIsNormal, + "OpSignBitSet": OpSignBitSet, + "OpLessOrGreater": OpLessOrGreater, + "OpOrdered": OpOrdered, + "OpUnordered": OpUnordered, + "OpLogicalEqual": OpLogicalEqual, + "OpLogicalNotEqual": OpLogicalNotEqual, + "OpLogicalOr": OpLogicalOr, + "OpLogicalAnd": OpLogicalAnd, + "OpLogicalNot": OpLogicalNot, + "OpSelect": OpSelect, + "OpIEqual": OpIEqual, + "OpINotEqual": OpINotEqual, + "OpUGreaterThan": OpUGreaterThan, + "OpSGreaterThan": OpSGreaterThan, + "OpUGreaterThanEqual": OpUGreaterThanEqual, + "OpSGreaterThanEqual": OpSGreaterThanEqual, + "OpULessThan": OpULessThan, + "OpSLessThan": OpSLessThan, + "OpULessThanEqual": OpULessThanEqual, + "OpSLessThanEqual": OpSLessThanEqual, + "OpFOrdEqual": OpFOrdEqual, + "OpFUnordEqual": OpFUnordEqual, + "OpFOrdNotEqual": OpFOrdNotEqual, + "OpFUnordNotEqual": OpFUnordNotEqual, + "OpFOrdLessThan": OpFOrdLessThan, + "OpFUnordLessThan": OpFUnordLessThan, + "OpFOrdGreaterThan": OpFOrdGreaterThan, + "OpFUnordGreaterThan": OpFUnordGreaterThan, + "OpFOrdLessThanEqual": OpFOrdLessThanEqual, + "OpFUnordLessThanEqual": OpFUnordLessThanEqual, + "OpFOrdGreaterThanEqual": OpFOrdGreaterThanEqual, + "OpFUnordGreaterThanEqual": OpFUnordGreaterThanEqual, + "OpShiftRightLogical": OpShiftRightLogical, + "OpShiftRightArithmetic": OpShiftRightArithmetic, + "OpShiftLeftLogical": OpShiftLeftLogical, + "OpBitwiseOr": OpBitwiseOr, + "OpBitwiseXor": OpBitwiseXor, + "OpBitwiseAnd": OpBitwiseAnd, + "OpNot": OpNot, + "OpBitFieldInsert": OpBitFieldInsert, + "OpBitFieldSExtract": OpBitFieldSExtract, + "OpBitFieldUExtract": OpBitFieldUExtract, + "OpBitReverse": OpBitReverse, + "OpBitCount": OpBitCount, + "OpDPdx": OpDPdx, + "OpDPdy": OpDPdy, + "OpFwidth": OpFwidth, + "OpDPdxFine": OpDPdxFine, + "OpDPdyFine": OpDPdyFine, + "OpFwidthFine": OpFwidthFine, + "OpDPdxCoarse": OpDPdxCoarse, + "OpDPdyCoarse": OpDPdyCoarse, + "OpFwidthCoarse": OpFwidthCoarse, + "OpEmitVertex": OpEmitVertex, + "OpEndPrimitive": OpEndPrimitive, + "OpEmitStreamVertex": OpEmitStreamVertex, + "OpEndStreamPrimitive": OpEndStreamPrimitive, + "OpControlBarrier": OpControlBarrier, + "OpMemoryBarrier": OpMemoryBarrier, + "OpAtomicLoad": OpAtomicLoad, + "OpAtomicStore": OpAtomicStore, + "OpAtomicExchange": OpAtomicExchange, + "OpAtomicCompareExchange": OpAtomicCompareExchange, + "OpAtomicCompareExchangeWeak": OpAtomicCompareExchangeWeak, + "OpAtomicIIncrement": OpAtomicIIncrement, + "OpAtomicIDecrement": OpAtomicIDecrement, + "OpAtomicIAdd": OpAtomicIAdd, + "OpAtomicISub": OpAtomicISub, + "OpAtomicSMin": OpAtomicSMin, + "OpAtomicUMin": OpAtomicUMin, + "OpAtomicSMax": OpAtomicSMax, + "OpAtomicUMax": OpAtomicUMax, + "OpAtomicAnd": OpAtomicAnd, + "OpAtomicOr": OpAtomicOr, + "OpAtomicXor": OpAtomicXor, + "OpPhi": OpPhi, + "OpLoopMerge": OpLoopMerge, + "OpSelectionMerge": OpSelectionMerge, + "OpLabel": OpLabel, + "OpBranch": OpBranch, + "OpBranchConditional": OpBranchConditional, + "OpSwitch": OpSwitch, + "OpKill": OpKill, + "OpReturn": OpReturn, + "OpReturnValue": OpReturnValue, + "OpUnreachable": OpUnreachable, + "OpLifetimeStart": OpLifetimeStart, + "OpLifetimeStop": OpLifetimeStop, + "OpGroupAsyncCopy": OpGroupAsyncCopy, + "OpGroupWaitEvents": OpGroupWaitEvents, + "OpGroupAll": OpGroupAll, + "OpGroupAny": OpGroupAny, + "OpGroupBroadcast": OpGroupBroadcast, + "OpGroupIAdd": OpGroupIAdd, + "OpGroupFAdd": OpGroupFAdd, + "OpGroupFMin": OpGroupFMin, + "OpGroupUMin": OpGroupUMin, + "OpGroupSMin": OpGroupSMin, + "OpGroupFMax": OpGroupFMax, + "OpGroupUMax": OpGroupUMax, + "OpGroupSMax": OpGroupSMax, + "OpReadPipe": OpReadPipe, + "OpWritePipe": OpWritePipe, + "OpReservedReadPipe": OpReservedReadPipe, + "OpReservedWritePipe": OpReservedWritePipe, + "OpReserveReadPipePackets": OpReserveReadPipePackets, + "OpReserveWritePipePackets": OpReserveWritePipePackets, + "OpCommitReadPipe": OpCommitReadPipe, + "OpCommitWritePipe": OpCommitWritePipe, + "OpIsValidReserveId": OpIsValidReserveId, + "OpGetNumPipePackets": OpGetNumPipePackets, + "OpGetMaxPipePackets": OpGetMaxPipePackets, + "OpGroupReserveReadPipePackets": OpGroupReserveReadPipePackets, + "OpGroupReserveWritePipePackets": OpGroupReserveWritePipePackets, + "OpGroupCommitReadPipe": OpGroupCommitReadPipe, + "OpGroupCommitWritePipe": OpGroupCommitWritePipe, + "OpEnqueueMarker": OpEnqueueMarker, + "OpEnqueueKernel": OpEnqueueKernel, + "OpGetKernelNDrangeSubGroupCount": OpGetKernelNDrangeSubGroupCount, + "OpGetKernelNDrangeMaxSubGroupSize": OpGetKernelNDrangeMaxSubGroupSize, + "OpGetKernelWorkGroupSize": OpGetKernelWorkGroupSize, + "OpGetKernelPreferredWorkGroupSizeMultiple": OpGetKernelPreferredWorkGroupSizeMultiple, + "OpRetainEvent": OpRetainEvent, + "OpReleaseEvent": OpReleaseEvent, + "OpCreateUserEvent": OpCreateUserEvent, + "OpIsValidEvent": OpIsValidEvent, + "OpSetUserEventStatus": OpSetUserEventStatus, + "OpCaptureEventProfilingInfo": OpCaptureEventProfilingInfo, + "OpGetDefaultQueue": OpGetDefaultQueue, + "OpBuildNDRange": OpBuildNDRange, + "OpImageSparseSampleImplicitLod": OpImageSparseSampleImplicitLod, + "OpImageSparseSampleExplicitLod": OpImageSparseSampleExplicitLod, + "OpImageSparseSampleDrefImplicitLod": OpImageSparseSampleDrefImplicitLod, + "OpImageSparseSampleDrefExplicitLod": OpImageSparseSampleDrefExplicitLod, + "OpImageSparseSampleProjImplicitLod": OpImageSparseSampleProjImplicitLod, + "OpImageSparseSampleProjExplicitLod": OpImageSparseSampleProjExplicitLod, + "OpImageSparseSampleProjDrefImplicitLod": OpImageSparseSampleProjDrefImplicitLod, + "OpImageSparseSampleProjDrefExplicitLod": OpImageSparseSampleProjDrefExplicitLod, + "OpImageSparseFetch": OpImageSparseFetch, + "OpImageSparseGather": OpImageSparseGather, + "OpImageSparseDrefGather": OpImageSparseDrefGather, + "OpImageSparseTexelsResident": OpImageSparseTexelsResident, + "OpNoLine": OpNoLine, + "OpAtomicFlagTestAndSet": OpAtomicFlagTestAndSet, + "OpAtomicFlagClear": OpAtomicFlagClear, + "OpImageSparseRead": OpImageSparseRead, + "OpSizeOf": OpSizeOf, + "OpTypePipeStorage": OpTypePipeStorage, + "OpConstantPipeStorage": OpConstantPipeStorage, + "OpCreatePipeFromPipeStorage": OpCreatePipeFromPipeStorage, + "OpGetKernelLocalSizeForSubgroupCount": OpGetKernelLocalSizeForSubgroupCount, + "OpGetKernelMaxNumSubgroups": OpGetKernelMaxNumSubgroups, + "OpTypeNamedBarrier": OpTypeNamedBarrier, + "OpNamedBarrierInitialize": OpNamedBarrierInitialize, + "OpMemoryNamedBarrier": OpMemoryNamedBarrier, + "OpModuleProcessed": OpModuleProcessed, + "OpExecutionModeId": OpExecutionModeId, + "OpDecorateId": OpDecorateId, + "OpGroupNonUniformElect": OpGroupNonUniformElect, + "OpGroupNonUniformAll": OpGroupNonUniformAll, + "OpGroupNonUniformAny": OpGroupNonUniformAny, + "OpGroupNonUniformAllEqual": OpGroupNonUniformAllEqual, + "OpGroupNonUniformBroadcast": OpGroupNonUniformBroadcast, + "OpGroupNonUniformBroadcastFirst": OpGroupNonUniformBroadcastFirst, + "OpGroupNonUniformBallot": OpGroupNonUniformBallot, + "OpGroupNonUniformInverseBallot": OpGroupNonUniformInverseBallot, + "OpGroupNonUniformBallotBitExtract": OpGroupNonUniformBallotBitExtract, + "OpGroupNonUniformBallotBitCount": OpGroupNonUniformBallotBitCount, + "OpGroupNonUniformBallotFindLSB": OpGroupNonUniformBallotFindLSB, + "OpGroupNonUniformBallotFindMSB": OpGroupNonUniformBallotFindMSB, + "OpGroupNonUniformShuffle": OpGroupNonUniformShuffle, + "OpGroupNonUniformShuffleXor": OpGroupNonUniformShuffleXor, + "OpGroupNonUniformShuffleUp": OpGroupNonUniformShuffleUp, + "OpGroupNonUniformShuffleDown": OpGroupNonUniformShuffleDown, + "OpGroupNonUniformIAdd": OpGroupNonUniformIAdd, + "OpGroupNonUniformFAdd": OpGroupNonUniformFAdd, + "OpGroupNonUniformIMul": OpGroupNonUniformIMul, + "OpGroupNonUniformFMul": OpGroupNonUniformFMul, + "OpGroupNonUniformSMin": OpGroupNonUniformSMin, + "OpGroupNonUniformUMin": OpGroupNonUniformUMin, + "OpGroupNonUniformFMin": OpGroupNonUniformFMin, + "OpGroupNonUniformSMax": OpGroupNonUniformSMax, + "OpGroupNonUniformUMax": OpGroupNonUniformUMax, + "OpGroupNonUniformFMax": OpGroupNonUniformFMax, + "OpGroupNonUniformBitwiseAnd": OpGroupNonUniformBitwiseAnd, + "OpGroupNonUniformBitwiseOr": OpGroupNonUniformBitwiseOr, + "OpGroupNonUniformBitwiseXor": OpGroupNonUniformBitwiseXor, + "OpGroupNonUniformLogicalAnd": OpGroupNonUniformLogicalAnd, + "OpGroupNonUniformLogicalOr": OpGroupNonUniformLogicalOr, + "OpGroupNonUniformLogicalXor": OpGroupNonUniformLogicalXor, + "OpGroupNonUniformQuadBroadcast": OpGroupNonUniformQuadBroadcast, + "OpGroupNonUniformQuadSwap": OpGroupNonUniformQuadSwap, + "OpCopyLogical": OpCopyLogical, + "OpPtrEqual": OpPtrEqual, + "OpPtrNotEqual": OpPtrNotEqual, + "OpPtrDiff": OpPtrDiff, + "OpSubgroupBallotKHR": OpSubgroupBallotKHR, + "OpSubgroupFirstInvocationKHR": OpSubgroupFirstInvocationKHR, + "OpSubgroupAllKHR": OpSubgroupAllKHR, + "OpSubgroupAnyKHR": OpSubgroupAnyKHR, + "OpSubgroupAllEqualKHR": OpSubgroupAllEqualKHR, + "OpSubgroupReadInvocationKHR": OpSubgroupReadInvocationKHR, + "OpGroupIAddNonUniformAMD": OpGroupIAddNonUniformAMD, + "OpGroupFAddNonUniformAMD": OpGroupFAddNonUniformAMD, + "OpGroupFMinNonUniformAMD": OpGroupFMinNonUniformAMD, + "OpGroupUMinNonUniformAMD": OpGroupUMinNonUniformAMD, + "OpGroupSMinNonUniformAMD": OpGroupSMinNonUniformAMD, + "OpGroupFMaxNonUniformAMD": OpGroupFMaxNonUniformAMD, + "OpGroupUMaxNonUniformAMD": OpGroupUMaxNonUniformAMD, + "OpGroupSMaxNonUniformAMD": OpGroupSMaxNonUniformAMD, + "OpFragmentMaskFetchAMD": OpFragmentMaskFetchAMD, + "OpFragmentFetchAMD": OpFragmentFetchAMD, + "OpReadClockKHR": OpReadClockKHR, + "OpImageSampleFootprintNV": OpImageSampleFootprintNV, + "OpGroupNonUniformPartitionNV": OpGroupNonUniformPartitionNV, + "OpWritePackedPrimitiveIndices4x8NV": OpWritePackedPrimitiveIndices4x8NV, + "OpReportIntersectionNV": OpReportIntersectionNV, + "OpIgnoreIntersectionNV": OpIgnoreIntersectionNV, + "OpTerminateRayNV": OpTerminateRayNV, + "OpTraceNV": OpTraceNV, + "OpTypeAccelerationStructureNV": OpTypeAccelerationStructureNV, + "OpExecuteCallableNV": OpExecuteCallableNV, + "OpTypeCooperativeMatrixNV": OpTypeCooperativeMatrixNV, + "OpCooperativeMatrixLoadNV": OpCooperativeMatrixLoadNV, + "OpCooperativeMatrixStoreNV": OpCooperativeMatrixStoreNV, + "OpCooperativeMatrixMulAddNV": OpCooperativeMatrixMulAddNV, + "OpCooperativeMatrixLengthNV": OpCooperativeMatrixLengthNV, + "OpBeginInvocationInterlockEXT": OpBeginInvocationInterlockEXT, + "OpEndInvocationInterlockEXT": OpEndInvocationInterlockEXT, + "OpDemoteToHelperInvocationEXT": OpDemoteToHelperInvocationEXT, + "OpIsHelperInvocationEXT": OpIsHelperInvocationEXT, + "OpSubgroupShuffleINTEL": OpSubgroupShuffleINTEL, + "OpSubgroupShuffleDownINTEL": OpSubgroupShuffleDownINTEL, + "OpSubgroupShuffleUpINTEL": OpSubgroupShuffleUpINTEL, + "OpSubgroupShuffleXorINTEL": OpSubgroupShuffleXorINTEL, + "OpSubgroupBlockReadINTEL": OpSubgroupBlockReadINTEL, + "OpSubgroupBlockWriteINTEL": OpSubgroupBlockWriteINTEL, + "OpSubgroupImageBlockReadINTEL": OpSubgroupImageBlockReadINTEL, + "OpSubgroupImageBlockWriteINTEL": OpSubgroupImageBlockWriteINTEL, + "OpSubgroupImageMediaBlockReadINTEL": OpSubgroupImageMediaBlockReadINTEL, + "OpSubgroupImageMediaBlockWriteINTEL": OpSubgroupImageMediaBlockWriteINTEL, + "OpUCountLeadingZerosINTEL": OpUCountLeadingZerosINTEL, + "OpUCountTrailingZerosINTEL": OpUCountTrailingZerosINTEL, + "OpAbsISubINTEL": OpAbsISubINTEL, + "OpAbsUSubINTEL": OpAbsUSubINTEL, + "OpIAddSatINTEL": OpIAddSatINTEL, + "OpUAddSatINTEL": OpUAddSatINTEL, + "OpIAverageINTEL": OpIAverageINTEL, + "OpUAverageINTEL": OpUAverageINTEL, + "OpIAverageRoundedINTEL": OpIAverageRoundedINTEL, + "OpUAverageRoundedINTEL": OpUAverageRoundedINTEL, + "OpISubSatINTEL": OpISubSatINTEL, + "OpUSubSatINTEL": OpUSubSatINTEL, + "OpIMul32x16INTEL": OpIMul32x16INTEL, + "OpUMul32x16INTEL": OpUMul32x16INTEL, + "OpDecorateString": OpDecorateString, + "OpDecorateStringGOOGLE": OpDecorateStringGOOGLE, + "OpMemberDecorateString": OpMemberDecorateString, + "OpMemberDecorateStringGOOGLE": OpMemberDecorateStringGOOGLE, + "OpVmeImageINTEL": OpVmeImageINTEL, + "OpTypeVmeImageINTEL": OpTypeVmeImageINTEL, + "OpTypeAvcImePayloadINTEL": OpTypeAvcImePayloadINTEL, + "OpTypeAvcRefPayloadINTEL": OpTypeAvcRefPayloadINTEL, + "OpTypeAvcSicPayloadINTEL": OpTypeAvcSicPayloadINTEL, + "OpTypeAvcMcePayloadINTEL": OpTypeAvcMcePayloadINTEL, + "OpTypeAvcMceResultINTEL": OpTypeAvcMceResultINTEL, + "OpTypeAvcImeResultINTEL": OpTypeAvcImeResultINTEL, + "OpTypeAvcImeResultSingleReferenceStreamoutINTEL": OpTypeAvcImeResultSingleReferenceStreamoutINTEL, + "OpTypeAvcImeResultDualReferenceStreamoutINTEL": OpTypeAvcImeResultDualReferenceStreamoutINTEL, + "OpTypeAvcImeSingleReferenceStreaminINTEL": OpTypeAvcImeSingleReferenceStreaminINTEL, + "OpTypeAvcImeDualReferenceStreaminINTEL": OpTypeAvcImeDualReferenceStreaminINTEL, + "OpTypeAvcRefResultINTEL": OpTypeAvcRefResultINTEL, + "OpTypeAvcSicResultINTEL": OpTypeAvcSicResultINTEL, + "OpSubgroupAvcMceGetDefaultInterBaseMultiReferencePenaltyINTEL": OpSubgroupAvcMceGetDefaultInterBaseMultiReferencePenaltyINTEL, + "OpSubgroupAvcMceSetInterBaseMultiReferencePenaltyINTEL": OpSubgroupAvcMceSetInterBaseMultiReferencePenaltyINTEL, + "OpSubgroupAvcMceGetDefaultInterShapePenaltyINTEL": OpSubgroupAvcMceGetDefaultInterShapePenaltyINTEL, + "OpSubgroupAvcMceSetInterShapePenaltyINTEL": OpSubgroupAvcMceSetInterShapePenaltyINTEL, + "OpSubgroupAvcMceGetDefaultInterDirectionPenaltyINTEL": OpSubgroupAvcMceGetDefaultInterDirectionPenaltyINTEL, + "OpSubgroupAvcMceSetInterDirectionPenaltyINTEL": OpSubgroupAvcMceSetInterDirectionPenaltyINTEL, + "OpSubgroupAvcMceGetDefaultIntraLumaShapePenaltyINTEL": OpSubgroupAvcMceGetDefaultIntraLumaShapePenaltyINTEL, + "OpSubgroupAvcMceGetDefaultInterMotionVectorCostTableINTEL": OpSubgroupAvcMceGetDefaultInterMotionVectorCostTableINTEL, + "OpSubgroupAvcMceGetDefaultHighPenaltyCostTableINTEL": OpSubgroupAvcMceGetDefaultHighPenaltyCostTableINTEL, + "OpSubgroupAvcMceGetDefaultMediumPenaltyCostTableINTEL": OpSubgroupAvcMceGetDefaultMediumPenaltyCostTableINTEL, + "OpSubgroupAvcMceGetDefaultLowPenaltyCostTableINTEL": OpSubgroupAvcMceGetDefaultLowPenaltyCostTableINTEL, + "OpSubgroupAvcMceSetMotionVectorCostFunctionINTEL": OpSubgroupAvcMceSetMotionVectorCostFunctionINTEL, + "OpSubgroupAvcMceGetDefaultIntraLumaModePenaltyINTEL": OpSubgroupAvcMceGetDefaultIntraLumaModePenaltyINTEL, + "OpSubgroupAvcMceGetDefaultNonDcLumaIntraPenaltyINTEL": OpSubgroupAvcMceGetDefaultNonDcLumaIntraPenaltyINTEL, + "OpSubgroupAvcMceGetDefaultIntraChromaModeBasePenaltyINTEL": OpSubgroupAvcMceGetDefaultIntraChromaModeBasePenaltyINTEL, + "OpSubgroupAvcMceSetAcOnlyHaarINTEL": OpSubgroupAvcMceSetAcOnlyHaarINTEL, + "OpSubgroupAvcMceSetSourceInterlacedFieldPolarityINTEL": OpSubgroupAvcMceSetSourceInterlacedFieldPolarityINTEL, + "OpSubgroupAvcMceSetSingleReferenceInterlacedFieldPolarityINTEL": OpSubgroupAvcMceSetSingleReferenceInterlacedFieldPolarityINTEL, + "OpSubgroupAvcMceSetDualReferenceInterlacedFieldPolaritiesINTEL": OpSubgroupAvcMceSetDualReferenceInterlacedFieldPolaritiesINTEL, + "OpSubgroupAvcMceConvertToImePayloadINTEL": OpSubgroupAvcMceConvertToImePayloadINTEL, + "OpSubgroupAvcMceConvertToImeResultINTEL": OpSubgroupAvcMceConvertToImeResultINTEL, + "OpSubgroupAvcMceConvertToRefPayloadINTEL": OpSubgroupAvcMceConvertToRefPayloadINTEL, + "OpSubgroupAvcMceConvertToRefResultINTEL": OpSubgroupAvcMceConvertToRefResultINTEL, + "OpSubgroupAvcMceConvertToSicPayloadINTEL": OpSubgroupAvcMceConvertToSicPayloadINTEL, + "OpSubgroupAvcMceConvertToSicResultINTEL": OpSubgroupAvcMceConvertToSicResultINTEL, + "OpSubgroupAvcMceGetMotionVectorsINTEL": OpSubgroupAvcMceGetMotionVectorsINTEL, + "OpSubgroupAvcMceGetInterDistortionsINTEL": OpSubgroupAvcMceGetInterDistortionsINTEL, + "OpSubgroupAvcMceGetBestInterDistortionsINTEL": OpSubgroupAvcMceGetBestInterDistortionsINTEL, + "OpSubgroupAvcMceGetInterMajorShapeINTEL": OpSubgroupAvcMceGetInterMajorShapeINTEL, + "OpSubgroupAvcMceGetInterMinorShapeINTEL": OpSubgroupAvcMceGetInterMinorShapeINTEL, + "OpSubgroupAvcMceGetInterDirectionsINTEL": OpSubgroupAvcMceGetInterDirectionsINTEL, + "OpSubgroupAvcMceGetInterMotionVectorCountINTEL": OpSubgroupAvcMceGetInterMotionVectorCountINTEL, + "OpSubgroupAvcMceGetInterReferenceIdsINTEL": OpSubgroupAvcMceGetInterReferenceIdsINTEL, + "OpSubgroupAvcMceGetInterReferenceInterlacedFieldPolaritiesINTEL": OpSubgroupAvcMceGetInterReferenceInterlacedFieldPolaritiesINTEL, + "OpSubgroupAvcImeInitializeINTEL": OpSubgroupAvcImeInitializeINTEL, + "OpSubgroupAvcImeSetSingleReferenceINTEL": OpSubgroupAvcImeSetSingleReferenceINTEL, + "OpSubgroupAvcImeSetDualReferenceINTEL": OpSubgroupAvcImeSetDualReferenceINTEL, + "OpSubgroupAvcImeRefWindowSizeINTEL": OpSubgroupAvcImeRefWindowSizeINTEL, + "OpSubgroupAvcImeAdjustRefOffsetINTEL": OpSubgroupAvcImeAdjustRefOffsetINTEL, + "OpSubgroupAvcImeConvertToMcePayloadINTEL": OpSubgroupAvcImeConvertToMcePayloadINTEL, + "OpSubgroupAvcImeSetMaxMotionVectorCountINTEL": OpSubgroupAvcImeSetMaxMotionVectorCountINTEL, + "OpSubgroupAvcImeSetUnidirectionalMixDisableINTEL": OpSubgroupAvcImeSetUnidirectionalMixDisableINTEL, + "OpSubgroupAvcImeSetEarlySearchTerminationThresholdINTEL": OpSubgroupAvcImeSetEarlySearchTerminationThresholdINTEL, + "OpSubgroupAvcImeSetWeightedSadINTEL": OpSubgroupAvcImeSetWeightedSadINTEL, + "OpSubgroupAvcImeEvaluateWithSingleReferenceINTEL": OpSubgroupAvcImeEvaluateWithSingleReferenceINTEL, + "OpSubgroupAvcImeEvaluateWithDualReferenceINTEL": OpSubgroupAvcImeEvaluateWithDualReferenceINTEL, + "OpSubgroupAvcImeEvaluateWithSingleReferenceStreaminINTEL": OpSubgroupAvcImeEvaluateWithSingleReferenceStreaminINTEL, + "OpSubgroupAvcImeEvaluateWithDualReferenceStreaminINTEL": OpSubgroupAvcImeEvaluateWithDualReferenceStreaminINTEL, + "OpSubgroupAvcImeEvaluateWithSingleReferenceStreamoutINTEL": OpSubgroupAvcImeEvaluateWithSingleReferenceStreamoutINTEL, + "OpSubgroupAvcImeEvaluateWithDualReferenceStreamoutINTEL": OpSubgroupAvcImeEvaluateWithDualReferenceStreamoutINTEL, + "OpSubgroupAvcImeEvaluateWithSingleReferenceStreaminoutINTEL": OpSubgroupAvcImeEvaluateWithSingleReferenceStreaminoutINTEL, + "OpSubgroupAvcImeEvaluateWithDualReferenceStreaminoutINTEL": OpSubgroupAvcImeEvaluateWithDualReferenceStreaminoutINTEL, + "OpSubgroupAvcImeConvertToMceResultINTEL": OpSubgroupAvcImeConvertToMceResultINTEL, + "OpSubgroupAvcImeGetSingleReferenceStreaminINTEL": OpSubgroupAvcImeGetSingleReferenceStreaminINTEL, + "OpSubgroupAvcImeGetDualReferenceStreaminINTEL": OpSubgroupAvcImeGetDualReferenceStreaminINTEL, + "OpSubgroupAvcImeStripSingleReferenceStreamoutINTEL": OpSubgroupAvcImeStripSingleReferenceStreamoutINTEL, + "OpSubgroupAvcImeStripDualReferenceStreamoutINTEL": OpSubgroupAvcImeStripDualReferenceStreamoutINTEL, + "OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeMotionVectorsINTEL": OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeMotionVectorsINTEL, + "OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeDistortionsINTEL": OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeDistortionsINTEL, + "OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeReferenceIdsINTEL": OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeReferenceIdsINTEL, + "OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeMotionVectorsINTEL": OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeMotionVectorsINTEL, + "OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeDistortionsINTEL": OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeDistortionsINTEL, + "OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeReferenceIdsINTEL": OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeReferenceIdsINTEL, + "OpSubgroupAvcImeGetBorderReachedINTEL": OpSubgroupAvcImeGetBorderReachedINTEL, + "OpSubgroupAvcImeGetTruncatedSearchIndicationINTEL": OpSubgroupAvcImeGetTruncatedSearchIndicationINTEL, + "OpSubgroupAvcImeGetUnidirectionalEarlySearchTerminationINTEL": OpSubgroupAvcImeGetUnidirectionalEarlySearchTerminationINTEL, + "OpSubgroupAvcImeGetWeightingPatternMinimumMotionVectorINTEL": OpSubgroupAvcImeGetWeightingPatternMinimumMotionVectorINTEL, + "OpSubgroupAvcImeGetWeightingPatternMinimumDistortionINTEL": OpSubgroupAvcImeGetWeightingPatternMinimumDistortionINTEL, + "OpSubgroupAvcFmeInitializeINTEL": OpSubgroupAvcFmeInitializeINTEL, + "OpSubgroupAvcBmeInitializeINTEL": OpSubgroupAvcBmeInitializeINTEL, + "OpSubgroupAvcRefConvertToMcePayloadINTEL": OpSubgroupAvcRefConvertToMcePayloadINTEL, + "OpSubgroupAvcRefSetBidirectionalMixDisableINTEL": OpSubgroupAvcRefSetBidirectionalMixDisableINTEL, + "OpSubgroupAvcRefSetBilinearFilterEnableINTEL": OpSubgroupAvcRefSetBilinearFilterEnableINTEL, + "OpSubgroupAvcRefEvaluateWithSingleReferenceINTEL": OpSubgroupAvcRefEvaluateWithSingleReferenceINTEL, + "OpSubgroupAvcRefEvaluateWithDualReferenceINTEL": OpSubgroupAvcRefEvaluateWithDualReferenceINTEL, + "OpSubgroupAvcRefEvaluateWithMultiReferenceINTEL": OpSubgroupAvcRefEvaluateWithMultiReferenceINTEL, + "OpSubgroupAvcRefEvaluateWithMultiReferenceInterlacedINTEL": OpSubgroupAvcRefEvaluateWithMultiReferenceInterlacedINTEL, + "OpSubgroupAvcRefConvertToMceResultINTEL": OpSubgroupAvcRefConvertToMceResultINTEL, + "OpSubgroupAvcSicInitializeINTEL": OpSubgroupAvcSicInitializeINTEL, + "OpSubgroupAvcSicConfigureSkcINTEL": OpSubgroupAvcSicConfigureSkcINTEL, + "OpSubgroupAvcSicConfigureIpeLumaINTEL": OpSubgroupAvcSicConfigureIpeLumaINTEL, + "OpSubgroupAvcSicConfigureIpeLumaChromaINTEL": OpSubgroupAvcSicConfigureIpeLumaChromaINTEL, + "OpSubgroupAvcSicGetMotionVectorMaskINTEL": OpSubgroupAvcSicGetMotionVectorMaskINTEL, + "OpSubgroupAvcSicConvertToMcePayloadINTEL": OpSubgroupAvcSicConvertToMcePayloadINTEL, + "OpSubgroupAvcSicSetIntraLumaShapePenaltyINTEL": OpSubgroupAvcSicSetIntraLumaShapePenaltyINTEL, + "OpSubgroupAvcSicSetIntraLumaModeCostFunctionINTEL": OpSubgroupAvcSicSetIntraLumaModeCostFunctionINTEL, + "OpSubgroupAvcSicSetIntraChromaModeCostFunctionINTEL": OpSubgroupAvcSicSetIntraChromaModeCostFunctionINTEL, + "OpSubgroupAvcSicSetBilinearFilterEnableINTEL": OpSubgroupAvcSicSetBilinearFilterEnableINTEL, + "OpSubgroupAvcSicSetSkcForwardTransformEnableINTEL": OpSubgroupAvcSicSetSkcForwardTransformEnableINTEL, + "OpSubgroupAvcSicSetBlockBasedRawSkipSadINTEL": OpSubgroupAvcSicSetBlockBasedRawSkipSadINTEL, + "OpSubgroupAvcSicEvaluateIpeINTEL": OpSubgroupAvcSicEvaluateIpeINTEL, + "OpSubgroupAvcSicEvaluateWithSingleReferenceINTEL": OpSubgroupAvcSicEvaluateWithSingleReferenceINTEL, + "OpSubgroupAvcSicEvaluateWithDualReferenceINTEL": OpSubgroupAvcSicEvaluateWithDualReferenceINTEL, + "OpSubgroupAvcSicEvaluateWithMultiReferenceINTEL": OpSubgroupAvcSicEvaluateWithMultiReferenceINTEL, + "OpSubgroupAvcSicEvaluateWithMultiReferenceInterlacedINTEL": OpSubgroupAvcSicEvaluateWithMultiReferenceInterlacedINTEL, + "OpSubgroupAvcSicConvertToMceResultINTEL": OpSubgroupAvcSicConvertToMceResultINTEL, + "OpSubgroupAvcSicGetIpeLumaShapeINTEL": OpSubgroupAvcSicGetIpeLumaShapeINTEL, + "OpSubgroupAvcSicGetBestIpeLumaDistortionINTEL": OpSubgroupAvcSicGetBestIpeLumaDistortionINTEL, + "OpSubgroupAvcSicGetBestIpeChromaDistortionINTEL": OpSubgroupAvcSicGetBestIpeChromaDistortionINTEL, + "OpSubgroupAvcSicGetPackedIpeLumaModesINTEL": OpSubgroupAvcSicGetPackedIpeLumaModesINTEL, + "OpSubgroupAvcSicGetIpeChromaModeINTEL": OpSubgroupAvcSicGetIpeChromaModeINTEL, + "OpSubgroupAvcSicGetPackedSkcLumaCountThresholdINTEL": OpSubgroupAvcSicGetPackedSkcLumaCountThresholdINTEL, + "OpSubgroupAvcSicGetPackedSkcLumaSumThresholdINTEL": OpSubgroupAvcSicGetPackedSkcLumaSumThresholdINTEL, + "OpSubgroupAvcSicGetInterRawSadsINTEL": OpSubgroupAvcSicGetInterRawSadsINTEL, + } + + OpNop = &Opcode { + Opname: "OpNop", + Operands: []Operand { + }, + } + OpUndef = &Opcode { + Opname: "OpUndef", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + }, + } + OpSourceContinued = &Opcode { + Opname: "OpSourceContinued", + Operands: []Operand { + Operand { + Kind: OperandKindLiteralString, + Name: "'Continued Source'", + Quantifier: "", + }, + }, + } + OpSource = &Opcode { + Opname: "OpSource", + Operands: []Operand { + Operand { + Kind: OperandKindSourceLanguage, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindLiteralInteger, + Name: "'Version'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'File'", + Quantifier: "?", + }, + Operand { + Kind: OperandKindLiteralString, + Name: "'Source'", + Quantifier: "?", + }, + }, + } + OpSourceExtension = &Opcode { + Opname: "OpSourceExtension", + Operands: []Operand { + Operand { + Kind: OperandKindLiteralString, + Name: "'Extension'", + Quantifier: "", + }, + }, + } + OpName = &Opcode { + Opname: "OpName", + Operands: []Operand { + Operand { + Kind: OperandKindIdRef, + Name: "'Target'", + Quantifier: "", + }, + Operand { + Kind: OperandKindLiteralString, + Name: "'Name'", + Quantifier: "", + }, + }, + } + OpMemberName = &Opcode { + Opname: "OpMemberName", + Operands: []Operand { + Operand { + Kind: OperandKindIdRef, + Name: "'Type'", + Quantifier: "", + }, + Operand { + Kind: OperandKindLiteralInteger, + Name: "'Member'", + Quantifier: "", + }, + Operand { + Kind: OperandKindLiteralString, + Name: "'Name'", + Quantifier: "", + }, + }, + } + OpString = &Opcode { + Opname: "OpString", + Operands: []Operand { + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindLiteralString, + Name: "'String'", + Quantifier: "", + }, + }, + } + OpLine = &Opcode { + Opname: "OpLine", + Operands: []Operand { + Operand { + Kind: OperandKindIdRef, + Name: "'File'", + Quantifier: "", + }, + Operand { + Kind: OperandKindLiteralInteger, + Name: "'Line'", + Quantifier: "", + }, + Operand { + Kind: OperandKindLiteralInteger, + Name: "'Column'", + Quantifier: "", + }, + }, + } + OpExtension = &Opcode { + Opname: "OpExtension", + Operands: []Operand { + Operand { + Kind: OperandKindLiteralString, + Name: "'Name'", + Quantifier: "", + }, + }, + } + OpExtInstImport = &Opcode { + Opname: "OpExtInstImport", + Operands: []Operand { + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindLiteralString, + Name: "'Name'", + Quantifier: "", + }, + }, + } + OpExtInst = &Opcode { + Opname: "OpExtInst", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Set'", + Quantifier: "", + }, + Operand { + Kind: OperandKindLiteralExtInstInteger, + Name: "'Instruction'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 1', + 'Operand 2', + ...", + Quantifier: "*", + }, + }, + } + OpMemoryModel = &Opcode { + Opname: "OpMemoryModel", + Operands: []Operand { + Operand { + Kind: OperandKindAddressingModel, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindMemoryModel, + Name: "", + Quantifier: "", + }, + }, + } + OpEntryPoint = &Opcode { + Opname: "OpEntryPoint", + Operands: []Operand { + Operand { + Kind: OperandKindExecutionModel, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Entry Point'", + Quantifier: "", + }, + Operand { + Kind: OperandKindLiteralString, + Name: "'Name'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Interface'", + Quantifier: "*", + }, + }, + } + OpExecutionMode = &Opcode { + Opname: "OpExecutionMode", + Operands: []Operand { + Operand { + Kind: OperandKindIdRef, + Name: "'Entry Point'", + Quantifier: "", + }, + Operand { + Kind: OperandKindExecutionMode, + Name: "'Mode'", + Quantifier: "", + }, + }, + } + OpCapability = &Opcode { + Opname: "OpCapability", + Operands: []Operand { + Operand { + Kind: OperandKindCapability, + Name: "'Capability'", + Quantifier: "", + }, + }, + } + OpTypeVoid = &Opcode { + Opname: "OpTypeVoid", + Operands: []Operand { + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + }, + } + OpTypeBool = &Opcode { + Opname: "OpTypeBool", + Operands: []Operand { + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + }, + } + OpTypeInt = &Opcode { + Opname: "OpTypeInt", + Operands: []Operand { + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindLiteralInteger, + Name: "'Width'", + Quantifier: "", + }, + Operand { + Kind: OperandKindLiteralInteger, + Name: "'Signedness'", + Quantifier: "", + }, + }, + } + OpTypeFloat = &Opcode { + Opname: "OpTypeFloat", + Operands: []Operand { + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindLiteralInteger, + Name: "'Width'", + Quantifier: "", + }, + }, + } + OpTypeVector = &Opcode { + Opname: "OpTypeVector", + Operands: []Operand { + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Component Type'", + Quantifier: "", + }, + Operand { + Kind: OperandKindLiteralInteger, + Name: "'Component Count'", + Quantifier: "", + }, + }, + } + OpTypeMatrix = &Opcode { + Opname: "OpTypeMatrix", + Operands: []Operand { + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Column Type'", + Quantifier: "", + }, + Operand { + Kind: OperandKindLiteralInteger, + Name: "'Column Count'", + Quantifier: "", + }, + }, + } + OpTypeImage = &Opcode { + Opname: "OpTypeImage", + Operands: []Operand { + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Sampled Type'", + Quantifier: "", + }, + Operand { + Kind: OperandKindDim, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindLiteralInteger, + Name: "'Depth'", + Quantifier: "", + }, + Operand { + Kind: OperandKindLiteralInteger, + Name: "'Arrayed'", + Quantifier: "", + }, + Operand { + Kind: OperandKindLiteralInteger, + Name: "'MS'", + Quantifier: "", + }, + Operand { + Kind: OperandKindLiteralInteger, + Name: "'Sampled'", + Quantifier: "", + }, + Operand { + Kind: OperandKindImageFormat, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindAccessQualifier, + Name: "", + Quantifier: "?", + }, + }, + } + OpTypeSampler = &Opcode { + Opname: "OpTypeSampler", + Operands: []Operand { + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + }, + } + OpTypeSampledImage = &Opcode { + Opname: "OpTypeSampledImage", + Operands: []Operand { + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Image Type'", + Quantifier: "", + }, + }, + } + OpTypeArray = &Opcode { + Opname: "OpTypeArray", + Operands: []Operand { + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Element Type'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Length'", + Quantifier: "", + }, + }, + } + OpTypeRuntimeArray = &Opcode { + Opname: "OpTypeRuntimeArray", + Operands: []Operand { + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Element Type'", + Quantifier: "", + }, + }, + } + OpTypeStruct = &Opcode { + Opname: "OpTypeStruct", + Operands: []Operand { + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Member 0 type', + 'member 1 type', + ...", + Quantifier: "*", + }, + }, + } + OpTypeOpaque = &Opcode { + Opname: "OpTypeOpaque", + Operands: []Operand { + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindLiteralString, + Name: "The name of the opaque type.", + Quantifier: "", + }, + }, + } + OpTypePointer = &Opcode { + Opname: "OpTypePointer", + Operands: []Operand { + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindStorageClass, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Type'", + Quantifier: "", + }, + }, + } + OpTypeFunction = &Opcode { + Opname: "OpTypeFunction", + Operands: []Operand { + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Return Type'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Parameter 0 Type', + 'Parameter 1 Type', + ...", + Quantifier: "*", + }, + }, + } + OpTypeEvent = &Opcode { + Opname: "OpTypeEvent", + Operands: []Operand { + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + }, + } + OpTypeDeviceEvent = &Opcode { + Opname: "OpTypeDeviceEvent", + Operands: []Operand { + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + }, + } + OpTypeReserveId = &Opcode { + Opname: "OpTypeReserveId", + Operands: []Operand { + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + }, + } + OpTypeQueue = &Opcode { + Opname: "OpTypeQueue", + Operands: []Operand { + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + }, + } + OpTypePipe = &Opcode { + Opname: "OpTypePipe", + Operands: []Operand { + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindAccessQualifier, + Name: "'Qualifier'", + Quantifier: "", + }, + }, + } + OpTypeForwardPointer = &Opcode { + Opname: "OpTypeForwardPointer", + Operands: []Operand { + Operand { + Kind: OperandKindIdRef, + Name: "'Pointer Type'", + Quantifier: "", + }, + Operand { + Kind: OperandKindStorageClass, + Name: "", + Quantifier: "", + }, + }, + } + OpConstantTrue = &Opcode { + Opname: "OpConstantTrue", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + }, + } + OpConstantFalse = &Opcode { + Opname: "OpConstantFalse", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + }, + } + OpConstant = &Opcode { + Opname: "OpConstant", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindLiteralContextDependentNumber, + Name: "'Value'", + Quantifier: "", + }, + }, + } + OpConstantComposite = &Opcode { + Opname: "OpConstantComposite", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Constituents'", + Quantifier: "*", + }, + }, + } + OpConstantSampler = &Opcode { + Opname: "OpConstantSampler", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindSamplerAddressingMode, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindLiteralInteger, + Name: "'Param'", + Quantifier: "", + }, + Operand { + Kind: OperandKindSamplerFilterMode, + Name: "", + Quantifier: "", + }, + }, + } + OpConstantNull = &Opcode { + Opname: "OpConstantNull", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + }, + } + OpSpecConstantTrue = &Opcode { + Opname: "OpSpecConstantTrue", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + }, + } + OpSpecConstantFalse = &Opcode { + Opname: "OpSpecConstantFalse", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + }, + } + OpSpecConstant = &Opcode { + Opname: "OpSpecConstant", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindLiteralContextDependentNumber, + Name: "'Value'", + Quantifier: "", + }, + }, + } + OpSpecConstantComposite = &Opcode { + Opname: "OpSpecConstantComposite", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Constituents'", + Quantifier: "*", + }, + }, + } + OpSpecConstantOp = &Opcode { + Opname: "OpSpecConstantOp", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindLiteralSpecConstantOpInteger, + Name: "'Opcode'", + Quantifier: "", + }, + }, + } + OpFunction = &Opcode { + Opname: "OpFunction", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindFunctionControl, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Function Type'", + Quantifier: "", + }, + }, + } + OpFunctionParameter = &Opcode { + Opname: "OpFunctionParameter", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + }, + } + OpFunctionEnd = &Opcode { + Opname: "OpFunctionEnd", + Operands: []Operand { + }, + } + OpFunctionCall = &Opcode { + Opname: "OpFunctionCall", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Function'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Argument 0', + 'Argument 1', + ...", + Quantifier: "*", + }, + }, + } + OpVariable = &Opcode { + Opname: "OpVariable", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindStorageClass, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Initializer'", + Quantifier: "?", + }, + }, + } + OpImageTexelPointer = &Opcode { + Opname: "OpImageTexelPointer", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Coordinate'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Sample'", + Quantifier: "", + }, + }, + } + OpLoad = &Opcode { + Opname: "OpLoad", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Pointer'", + Quantifier: "", + }, + Operand { + Kind: OperandKindMemoryAccess, + Name: "", + Quantifier: "?", + }, + }, + } + OpStore = &Opcode { + Opname: "OpStore", + Operands: []Operand { + Operand { + Kind: OperandKindIdRef, + Name: "'Pointer'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Object'", + Quantifier: "", + }, + Operand { + Kind: OperandKindMemoryAccess, + Name: "", + Quantifier: "?", + }, + }, + } + OpCopyMemory = &Opcode { + Opname: "OpCopyMemory", + Operands: []Operand { + Operand { + Kind: OperandKindIdRef, + Name: "'Target'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Source'", + Quantifier: "", + }, + Operand { + Kind: OperandKindMemoryAccess, + Name: "", + Quantifier: "?", + }, + Operand { + Kind: OperandKindMemoryAccess, + Name: "", + Quantifier: "?", + }, + }, + } + OpCopyMemorySized = &Opcode { + Opname: "OpCopyMemorySized", + Operands: []Operand { + Operand { + Kind: OperandKindIdRef, + Name: "'Target'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Source'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Size'", + Quantifier: "", + }, + Operand { + Kind: OperandKindMemoryAccess, + Name: "", + Quantifier: "?", + }, + Operand { + Kind: OperandKindMemoryAccess, + Name: "", + Quantifier: "?", + }, + }, + } + OpAccessChain = &Opcode { + Opname: "OpAccessChain", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Base'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Indexes'", + Quantifier: "*", + }, + }, + } + OpInBoundsAccessChain = &Opcode { + Opname: "OpInBoundsAccessChain", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Base'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Indexes'", + Quantifier: "*", + }, + }, + } + OpPtrAccessChain = &Opcode { + Opname: "OpPtrAccessChain", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Base'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Element'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Indexes'", + Quantifier: "*", + }, + }, + } + OpArrayLength = &Opcode { + Opname: "OpArrayLength", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Structure'", + Quantifier: "", + }, + Operand { + Kind: OperandKindLiteralInteger, + Name: "'Array member'", + Quantifier: "", + }, + }, + } + OpGenericPtrMemSemantics = &Opcode { + Opname: "OpGenericPtrMemSemantics", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Pointer'", + Quantifier: "", + }, + }, + } + OpInBoundsPtrAccessChain = &Opcode { + Opname: "OpInBoundsPtrAccessChain", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Base'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Element'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Indexes'", + Quantifier: "*", + }, + }, + } + OpDecorate = &Opcode { + Opname: "OpDecorate", + Operands: []Operand { + Operand { + Kind: OperandKindIdRef, + Name: "'Target'", + Quantifier: "", + }, + Operand { + Kind: OperandKindDecoration, + Name: "", + Quantifier: "", + }, + }, + } + OpMemberDecorate = &Opcode { + Opname: "OpMemberDecorate", + Operands: []Operand { + Operand { + Kind: OperandKindIdRef, + Name: "'Structure Type'", + Quantifier: "", + }, + Operand { + Kind: OperandKindLiteralInteger, + Name: "'Member'", + Quantifier: "", + }, + Operand { + Kind: OperandKindDecoration, + Name: "", + Quantifier: "", + }, + }, + } + OpDecorationGroup = &Opcode { + Opname: "OpDecorationGroup", + Operands: []Operand { + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + }, + } + OpGroupDecorate = &Opcode { + Opname: "OpGroupDecorate", + Operands: []Operand { + Operand { + Kind: OperandKindIdRef, + Name: "'Decoration Group'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Targets'", + Quantifier: "*", + }, + }, + } + OpGroupMemberDecorate = &Opcode { + Opname: "OpGroupMemberDecorate", + Operands: []Operand { + Operand { + Kind: OperandKindIdRef, + Name: "'Decoration Group'", + Quantifier: "", + }, + Operand { + Kind: OperandKindPairIdRefLiteralInteger, + Name: "'Targets'", + Quantifier: "*", + }, + }, + } + OpVectorExtractDynamic = &Opcode { + Opname: "OpVectorExtractDynamic", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Vector'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Index'", + Quantifier: "", + }, + }, + } + OpVectorInsertDynamic = &Opcode { + Opname: "OpVectorInsertDynamic", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Vector'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Component'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Index'", + Quantifier: "", + }, + }, + } + OpVectorShuffle = &Opcode { + Opname: "OpVectorShuffle", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Vector 1'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Vector 2'", + Quantifier: "", + }, + Operand { + Kind: OperandKindLiteralInteger, + Name: "'Components'", + Quantifier: "*", + }, + }, + } + OpCompositeConstruct = &Opcode { + Opname: "OpCompositeConstruct", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Constituents'", + Quantifier: "*", + }, + }, + } + OpCompositeExtract = &Opcode { + Opname: "OpCompositeExtract", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Composite'", + Quantifier: "", + }, + Operand { + Kind: OperandKindLiteralInteger, + Name: "'Indexes'", + Quantifier: "*", + }, + }, + } + OpCompositeInsert = &Opcode { + Opname: "OpCompositeInsert", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Object'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Composite'", + Quantifier: "", + }, + Operand { + Kind: OperandKindLiteralInteger, + Name: "'Indexes'", + Quantifier: "*", + }, + }, + } + OpCopyObject = &Opcode { + Opname: "OpCopyObject", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand'", + Quantifier: "", + }, + }, + } + OpTranspose = &Opcode { + Opname: "OpTranspose", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Matrix'", + Quantifier: "", + }, + }, + } + OpSampledImage = &Opcode { + Opname: "OpSampledImage", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Sampler'", + Quantifier: "", + }, + }, + } + OpImageSampleImplicitLod = &Opcode { + Opname: "OpImageSampleImplicitLod", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Sampled Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Coordinate'", + Quantifier: "", + }, + Operand { + Kind: OperandKindImageOperands, + Name: "", + Quantifier: "?", + }, + }, + } + OpImageSampleExplicitLod = &Opcode { + Opname: "OpImageSampleExplicitLod", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Sampled Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Coordinate'", + Quantifier: "", + }, + Operand { + Kind: OperandKindImageOperands, + Name: "", + Quantifier: "", + }, + }, + } + OpImageSampleDrefImplicitLod = &Opcode { + Opname: "OpImageSampleDrefImplicitLod", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Sampled Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Coordinate'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'D~ref~'", + Quantifier: "", + }, + Operand { + Kind: OperandKindImageOperands, + Name: "", + Quantifier: "?", + }, + }, + } + OpImageSampleDrefExplicitLod = &Opcode { + Opname: "OpImageSampleDrefExplicitLod", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Sampled Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Coordinate'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'D~ref~'", + Quantifier: "", + }, + Operand { + Kind: OperandKindImageOperands, + Name: "", + Quantifier: "", + }, + }, + } + OpImageSampleProjImplicitLod = &Opcode { + Opname: "OpImageSampleProjImplicitLod", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Sampled Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Coordinate'", + Quantifier: "", + }, + Operand { + Kind: OperandKindImageOperands, + Name: "", + Quantifier: "?", + }, + }, + } + OpImageSampleProjExplicitLod = &Opcode { + Opname: "OpImageSampleProjExplicitLod", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Sampled Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Coordinate'", + Quantifier: "", + }, + Operand { + Kind: OperandKindImageOperands, + Name: "", + Quantifier: "", + }, + }, + } + OpImageSampleProjDrefImplicitLod = &Opcode { + Opname: "OpImageSampleProjDrefImplicitLod", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Sampled Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Coordinate'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'D~ref~'", + Quantifier: "", + }, + Operand { + Kind: OperandKindImageOperands, + Name: "", + Quantifier: "?", + }, + }, + } + OpImageSampleProjDrefExplicitLod = &Opcode { + Opname: "OpImageSampleProjDrefExplicitLod", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Sampled Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Coordinate'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'D~ref~'", + Quantifier: "", + }, + Operand { + Kind: OperandKindImageOperands, + Name: "", + Quantifier: "", + }, + }, + } + OpImageFetch = &Opcode { + Opname: "OpImageFetch", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Coordinate'", + Quantifier: "", + }, + Operand { + Kind: OperandKindImageOperands, + Name: "", + Quantifier: "?", + }, + }, + } + OpImageGather = &Opcode { + Opname: "OpImageGather", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Sampled Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Coordinate'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Component'", + Quantifier: "", + }, + Operand { + Kind: OperandKindImageOperands, + Name: "", + Quantifier: "?", + }, + }, + } + OpImageDrefGather = &Opcode { + Opname: "OpImageDrefGather", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Sampled Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Coordinate'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'D~ref~'", + Quantifier: "", + }, + Operand { + Kind: OperandKindImageOperands, + Name: "", + Quantifier: "?", + }, + }, + } + OpImageRead = &Opcode { + Opname: "OpImageRead", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Coordinate'", + Quantifier: "", + }, + Operand { + Kind: OperandKindImageOperands, + Name: "", + Quantifier: "?", + }, + }, + } + OpImageWrite = &Opcode { + Opname: "OpImageWrite", + Operands: []Operand { + Operand { + Kind: OperandKindIdRef, + Name: "'Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Coordinate'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Texel'", + Quantifier: "", + }, + Operand { + Kind: OperandKindImageOperands, + Name: "", + Quantifier: "?", + }, + }, + } + OpImage = &Opcode { + Opname: "OpImage", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Sampled Image'", + Quantifier: "", + }, + }, + } + OpImageQueryFormat = &Opcode { + Opname: "OpImageQueryFormat", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Image'", + Quantifier: "", + }, + }, + } + OpImageQueryOrder = &Opcode { + Opname: "OpImageQueryOrder", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Image'", + Quantifier: "", + }, + }, + } + OpImageQuerySizeLod = &Opcode { + Opname: "OpImageQuerySizeLod", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Level of Detail'", + Quantifier: "", + }, + }, + } + OpImageQuerySize = &Opcode { + Opname: "OpImageQuerySize", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Image'", + Quantifier: "", + }, + }, + } + OpImageQueryLod = &Opcode { + Opname: "OpImageQueryLod", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Sampled Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Coordinate'", + Quantifier: "", + }, + }, + } + OpImageQueryLevels = &Opcode { + Opname: "OpImageQueryLevels", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Image'", + Quantifier: "", + }, + }, + } + OpImageQuerySamples = &Opcode { + Opname: "OpImageQuerySamples", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Image'", + Quantifier: "", + }, + }, + } + OpConvertFToU = &Opcode { + Opname: "OpConvertFToU", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Float Value'", + Quantifier: "", + }, + }, + } + OpConvertFToS = &Opcode { + Opname: "OpConvertFToS", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Float Value'", + Quantifier: "", + }, + }, + } + OpConvertSToF = &Opcode { + Opname: "OpConvertSToF", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Signed Value'", + Quantifier: "", + }, + }, + } + OpConvertUToF = &Opcode { + Opname: "OpConvertUToF", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Unsigned Value'", + Quantifier: "", + }, + }, + } + OpUConvert = &Opcode { + Opname: "OpUConvert", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Unsigned Value'", + Quantifier: "", + }, + }, + } + OpSConvert = &Opcode { + Opname: "OpSConvert", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Signed Value'", + Quantifier: "", + }, + }, + } + OpFConvert = &Opcode { + Opname: "OpFConvert", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Float Value'", + Quantifier: "", + }, + }, + } + OpQuantizeToF16 = &Opcode { + Opname: "OpQuantizeToF16", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Value'", + Quantifier: "", + }, + }, + } + OpConvertPtrToU = &Opcode { + Opname: "OpConvertPtrToU", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Pointer'", + Quantifier: "", + }, + }, + } + OpSatConvertSToU = &Opcode { + Opname: "OpSatConvertSToU", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Signed Value'", + Quantifier: "", + }, + }, + } + OpSatConvertUToS = &Opcode { + Opname: "OpSatConvertUToS", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Unsigned Value'", + Quantifier: "", + }, + }, + } + OpConvertUToPtr = &Opcode { + Opname: "OpConvertUToPtr", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Integer Value'", + Quantifier: "", + }, + }, + } + OpPtrCastToGeneric = &Opcode { + Opname: "OpPtrCastToGeneric", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Pointer'", + Quantifier: "", + }, + }, + } + OpGenericCastToPtr = &Opcode { + Opname: "OpGenericCastToPtr", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Pointer'", + Quantifier: "", + }, + }, + } + OpGenericCastToPtrExplicit = &Opcode { + Opname: "OpGenericCastToPtrExplicit", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Pointer'", + Quantifier: "", + }, + Operand { + Kind: OperandKindStorageClass, + Name: "'Storage'", + Quantifier: "", + }, + }, + } + OpBitcast = &Opcode { + Opname: "OpBitcast", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand'", + Quantifier: "", + }, + }, + } + OpSNegate = &Opcode { + Opname: "OpSNegate", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand'", + Quantifier: "", + }, + }, + } + OpFNegate = &Opcode { + Opname: "OpFNegate", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand'", + Quantifier: "", + }, + }, + } + OpIAdd = &Opcode { + Opname: "OpIAdd", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 1'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 2'", + Quantifier: "", + }, + }, + } + OpFAdd = &Opcode { + Opname: "OpFAdd", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 1'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 2'", + Quantifier: "", + }, + }, + } + OpISub = &Opcode { + Opname: "OpISub", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 1'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 2'", + Quantifier: "", + }, + }, + } + OpFSub = &Opcode { + Opname: "OpFSub", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 1'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 2'", + Quantifier: "", + }, + }, + } + OpIMul = &Opcode { + Opname: "OpIMul", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 1'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 2'", + Quantifier: "", + }, + }, + } + OpFMul = &Opcode { + Opname: "OpFMul", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 1'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 2'", + Quantifier: "", + }, + }, + } + OpUDiv = &Opcode { + Opname: "OpUDiv", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 1'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 2'", + Quantifier: "", + }, + }, + } + OpSDiv = &Opcode { + Opname: "OpSDiv", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 1'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 2'", + Quantifier: "", + }, + }, + } + OpFDiv = &Opcode { + Opname: "OpFDiv", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 1'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 2'", + Quantifier: "", + }, + }, + } + OpUMod = &Opcode { + Opname: "OpUMod", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 1'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 2'", + Quantifier: "", + }, + }, + } + OpSRem = &Opcode { + Opname: "OpSRem", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 1'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 2'", + Quantifier: "", + }, + }, + } + OpSMod = &Opcode { + Opname: "OpSMod", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 1'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 2'", + Quantifier: "", + }, + }, + } + OpFRem = &Opcode { + Opname: "OpFRem", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 1'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 2'", + Quantifier: "", + }, + }, + } + OpFMod = &Opcode { + Opname: "OpFMod", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 1'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 2'", + Quantifier: "", + }, + }, + } + OpVectorTimesScalar = &Opcode { + Opname: "OpVectorTimesScalar", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Vector'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Scalar'", + Quantifier: "", + }, + }, + } + OpMatrixTimesScalar = &Opcode { + Opname: "OpMatrixTimesScalar", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Matrix'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Scalar'", + Quantifier: "", + }, + }, + } + OpVectorTimesMatrix = &Opcode { + Opname: "OpVectorTimesMatrix", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Vector'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Matrix'", + Quantifier: "", + }, + }, + } + OpMatrixTimesVector = &Opcode { + Opname: "OpMatrixTimesVector", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Matrix'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Vector'", + Quantifier: "", + }, + }, + } + OpMatrixTimesMatrix = &Opcode { + Opname: "OpMatrixTimesMatrix", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'LeftMatrix'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'RightMatrix'", + Quantifier: "", + }, + }, + } + OpOuterProduct = &Opcode { + Opname: "OpOuterProduct", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Vector 1'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Vector 2'", + Quantifier: "", + }, + }, + } + OpDot = &Opcode { + Opname: "OpDot", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Vector 1'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Vector 2'", + Quantifier: "", + }, + }, + } + OpIAddCarry = &Opcode { + Opname: "OpIAddCarry", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 1'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 2'", + Quantifier: "", + }, + }, + } + OpISubBorrow = &Opcode { + Opname: "OpISubBorrow", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 1'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 2'", + Quantifier: "", + }, + }, + } + OpUMulExtended = &Opcode { + Opname: "OpUMulExtended", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 1'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 2'", + Quantifier: "", + }, + }, + } + OpSMulExtended = &Opcode { + Opname: "OpSMulExtended", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 1'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 2'", + Quantifier: "", + }, + }, + } + OpAny = &Opcode { + Opname: "OpAny", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Vector'", + Quantifier: "", + }, + }, + } + OpAll = &Opcode { + Opname: "OpAll", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Vector'", + Quantifier: "", + }, + }, + } + OpIsNan = &Opcode { + Opname: "OpIsNan", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'x'", + Quantifier: "", + }, + }, + } + OpIsInf = &Opcode { + Opname: "OpIsInf", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'x'", + Quantifier: "", + }, + }, + } + OpIsFinite = &Opcode { + Opname: "OpIsFinite", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'x'", + Quantifier: "", + }, + }, + } + OpIsNormal = &Opcode { + Opname: "OpIsNormal", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'x'", + Quantifier: "", + }, + }, + } + OpSignBitSet = &Opcode { + Opname: "OpSignBitSet", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'x'", + Quantifier: "", + }, + }, + } + OpLessOrGreater = &Opcode { + Opname: "OpLessOrGreater", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'x'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'y'", + Quantifier: "", + }, + }, + } + OpOrdered = &Opcode { + Opname: "OpOrdered", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'x'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'y'", + Quantifier: "", + }, + }, + } + OpUnordered = &Opcode { + Opname: "OpUnordered", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'x'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'y'", + Quantifier: "", + }, + }, + } + OpLogicalEqual = &Opcode { + Opname: "OpLogicalEqual", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 1'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 2'", + Quantifier: "", + }, + }, + } + OpLogicalNotEqual = &Opcode { + Opname: "OpLogicalNotEqual", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 1'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 2'", + Quantifier: "", + }, + }, + } + OpLogicalOr = &Opcode { + Opname: "OpLogicalOr", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 1'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 2'", + Quantifier: "", + }, + }, + } + OpLogicalAnd = &Opcode { + Opname: "OpLogicalAnd", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 1'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 2'", + Quantifier: "", + }, + }, + } + OpLogicalNot = &Opcode { + Opname: "OpLogicalNot", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand'", + Quantifier: "", + }, + }, + } + OpSelect = &Opcode { + Opname: "OpSelect", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Condition'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Object 1'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Object 2'", + Quantifier: "", + }, + }, + } + OpIEqual = &Opcode { + Opname: "OpIEqual", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 1'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 2'", + Quantifier: "", + }, + }, + } + OpINotEqual = &Opcode { + Opname: "OpINotEqual", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 1'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 2'", + Quantifier: "", + }, + }, + } + OpUGreaterThan = &Opcode { + Opname: "OpUGreaterThan", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 1'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 2'", + Quantifier: "", + }, + }, + } + OpSGreaterThan = &Opcode { + Opname: "OpSGreaterThan", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 1'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 2'", + Quantifier: "", + }, + }, + } + OpUGreaterThanEqual = &Opcode { + Opname: "OpUGreaterThanEqual", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 1'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 2'", + Quantifier: "", + }, + }, + } + OpSGreaterThanEqual = &Opcode { + Opname: "OpSGreaterThanEqual", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 1'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 2'", + Quantifier: "", + }, + }, + } + OpULessThan = &Opcode { + Opname: "OpULessThan", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 1'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 2'", + Quantifier: "", + }, + }, + } + OpSLessThan = &Opcode { + Opname: "OpSLessThan", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 1'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 2'", + Quantifier: "", + }, + }, + } + OpULessThanEqual = &Opcode { + Opname: "OpULessThanEqual", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 1'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 2'", + Quantifier: "", + }, + }, + } + OpSLessThanEqual = &Opcode { + Opname: "OpSLessThanEqual", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 1'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 2'", + Quantifier: "", + }, + }, + } + OpFOrdEqual = &Opcode { + Opname: "OpFOrdEqual", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 1'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 2'", + Quantifier: "", + }, + }, + } + OpFUnordEqual = &Opcode { + Opname: "OpFUnordEqual", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 1'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 2'", + Quantifier: "", + }, + }, + } + OpFOrdNotEqual = &Opcode { + Opname: "OpFOrdNotEqual", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 1'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 2'", + Quantifier: "", + }, + }, + } + OpFUnordNotEqual = &Opcode { + Opname: "OpFUnordNotEqual", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 1'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 2'", + Quantifier: "", + }, + }, + } + OpFOrdLessThan = &Opcode { + Opname: "OpFOrdLessThan", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 1'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 2'", + Quantifier: "", + }, + }, + } + OpFUnordLessThan = &Opcode { + Opname: "OpFUnordLessThan", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 1'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 2'", + Quantifier: "", + }, + }, + } + OpFOrdGreaterThan = &Opcode { + Opname: "OpFOrdGreaterThan", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 1'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 2'", + Quantifier: "", + }, + }, + } + OpFUnordGreaterThan = &Opcode { + Opname: "OpFUnordGreaterThan", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 1'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 2'", + Quantifier: "", + }, + }, + } + OpFOrdLessThanEqual = &Opcode { + Opname: "OpFOrdLessThanEqual", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 1'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 2'", + Quantifier: "", + }, + }, + } + OpFUnordLessThanEqual = &Opcode { + Opname: "OpFUnordLessThanEqual", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 1'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 2'", + Quantifier: "", + }, + }, + } + OpFOrdGreaterThanEqual = &Opcode { + Opname: "OpFOrdGreaterThanEqual", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 1'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 2'", + Quantifier: "", + }, + }, + } + OpFUnordGreaterThanEqual = &Opcode { + Opname: "OpFUnordGreaterThanEqual", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 1'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 2'", + Quantifier: "", + }, + }, + } + OpShiftRightLogical = &Opcode { + Opname: "OpShiftRightLogical", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Base'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Shift'", + Quantifier: "", + }, + }, + } + OpShiftRightArithmetic = &Opcode { + Opname: "OpShiftRightArithmetic", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Base'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Shift'", + Quantifier: "", + }, + }, + } + OpShiftLeftLogical = &Opcode { + Opname: "OpShiftLeftLogical", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Base'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Shift'", + Quantifier: "", + }, + }, + } + OpBitwiseOr = &Opcode { + Opname: "OpBitwiseOr", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 1'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 2'", + Quantifier: "", + }, + }, + } + OpBitwiseXor = &Opcode { + Opname: "OpBitwiseXor", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 1'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 2'", + Quantifier: "", + }, + }, + } + OpBitwiseAnd = &Opcode { + Opname: "OpBitwiseAnd", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 1'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 2'", + Quantifier: "", + }, + }, + } + OpNot = &Opcode { + Opname: "OpNot", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand'", + Quantifier: "", + }, + }, + } + OpBitFieldInsert = &Opcode { + Opname: "OpBitFieldInsert", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Base'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Insert'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Offset'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Count'", + Quantifier: "", + }, + }, + } + OpBitFieldSExtract = &Opcode { + Opname: "OpBitFieldSExtract", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Base'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Offset'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Count'", + Quantifier: "", + }, + }, + } + OpBitFieldUExtract = &Opcode { + Opname: "OpBitFieldUExtract", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Base'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Offset'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Count'", + Quantifier: "", + }, + }, + } + OpBitReverse = &Opcode { + Opname: "OpBitReverse", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Base'", + Quantifier: "", + }, + }, + } + OpBitCount = &Opcode { + Opname: "OpBitCount", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Base'", + Quantifier: "", + }, + }, + } + OpDPdx = &Opcode { + Opname: "OpDPdx", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'P'", + Quantifier: "", + }, + }, + } + OpDPdy = &Opcode { + Opname: "OpDPdy", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'P'", + Quantifier: "", + }, + }, + } + OpFwidth = &Opcode { + Opname: "OpFwidth", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'P'", + Quantifier: "", + }, + }, + } + OpDPdxFine = &Opcode { + Opname: "OpDPdxFine", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'P'", + Quantifier: "", + }, + }, + } + OpDPdyFine = &Opcode { + Opname: "OpDPdyFine", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'P'", + Quantifier: "", + }, + }, + } + OpFwidthFine = &Opcode { + Opname: "OpFwidthFine", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'P'", + Quantifier: "", + }, + }, + } + OpDPdxCoarse = &Opcode { + Opname: "OpDPdxCoarse", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'P'", + Quantifier: "", + }, + }, + } + OpDPdyCoarse = &Opcode { + Opname: "OpDPdyCoarse", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'P'", + Quantifier: "", + }, + }, + } + OpFwidthCoarse = &Opcode { + Opname: "OpFwidthCoarse", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'P'", + Quantifier: "", + }, + }, + } + OpEmitVertex = &Opcode { + Opname: "OpEmitVertex", + Operands: []Operand { + }, + } + OpEndPrimitive = &Opcode { + Opname: "OpEndPrimitive", + Operands: []Operand { + }, + } + OpEmitStreamVertex = &Opcode { + Opname: "OpEmitStreamVertex", + Operands: []Operand { + Operand { + Kind: OperandKindIdRef, + Name: "'Stream'", + Quantifier: "", + }, + }, + } + OpEndStreamPrimitive = &Opcode { + Opname: "OpEndStreamPrimitive", + Operands: []Operand { + Operand { + Kind: OperandKindIdRef, + Name: "'Stream'", + Quantifier: "", + }, + }, + } + OpControlBarrier = &Opcode { + Opname: "OpControlBarrier", + Operands: []Operand { + Operand { + Kind: OperandKindIdScope, + Name: "'Execution'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Memory'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdMemorySemantics, + Name: "'Semantics'", + Quantifier: "", + }, + }, + } + OpMemoryBarrier = &Opcode { + Opname: "OpMemoryBarrier", + Operands: []Operand { + Operand { + Kind: OperandKindIdScope, + Name: "'Memory'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdMemorySemantics, + Name: "'Semantics'", + Quantifier: "", + }, + }, + } + OpAtomicLoad = &Opcode { + Opname: "OpAtomicLoad", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Pointer'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Memory'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdMemorySemantics, + Name: "'Semantics'", + Quantifier: "", + }, + }, + } + OpAtomicStore = &Opcode { + Opname: "OpAtomicStore", + Operands: []Operand { + Operand { + Kind: OperandKindIdRef, + Name: "'Pointer'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Memory'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdMemorySemantics, + Name: "'Semantics'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Value'", + Quantifier: "", + }, + }, + } + OpAtomicExchange = &Opcode { + Opname: "OpAtomicExchange", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Pointer'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Memory'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdMemorySemantics, + Name: "'Semantics'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Value'", + Quantifier: "", + }, + }, + } + OpAtomicCompareExchange = &Opcode { + Opname: "OpAtomicCompareExchange", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Pointer'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Memory'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdMemorySemantics, + Name: "'Equal'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdMemorySemantics, + Name: "'Unequal'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Value'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Comparator'", + Quantifier: "", + }, + }, + } + OpAtomicCompareExchangeWeak = &Opcode { + Opname: "OpAtomicCompareExchangeWeak", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Pointer'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Memory'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdMemorySemantics, + Name: "'Equal'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdMemorySemantics, + Name: "'Unequal'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Value'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Comparator'", + Quantifier: "", + }, + }, + } + OpAtomicIIncrement = &Opcode { + Opname: "OpAtomicIIncrement", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Pointer'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Memory'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdMemorySemantics, + Name: "'Semantics'", + Quantifier: "", + }, + }, + } + OpAtomicIDecrement = &Opcode { + Opname: "OpAtomicIDecrement", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Pointer'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Memory'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdMemorySemantics, + Name: "'Semantics'", + Quantifier: "", + }, + }, + } + OpAtomicIAdd = &Opcode { + Opname: "OpAtomicIAdd", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Pointer'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Memory'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdMemorySemantics, + Name: "'Semantics'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Value'", + Quantifier: "", + }, + }, + } + OpAtomicISub = &Opcode { + Opname: "OpAtomicISub", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Pointer'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Memory'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdMemorySemantics, + Name: "'Semantics'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Value'", + Quantifier: "", + }, + }, + } + OpAtomicSMin = &Opcode { + Opname: "OpAtomicSMin", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Pointer'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Memory'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdMemorySemantics, + Name: "'Semantics'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Value'", + Quantifier: "", + }, + }, + } + OpAtomicUMin = &Opcode { + Opname: "OpAtomicUMin", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Pointer'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Memory'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdMemorySemantics, + Name: "'Semantics'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Value'", + Quantifier: "", + }, + }, + } + OpAtomicSMax = &Opcode { + Opname: "OpAtomicSMax", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Pointer'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Memory'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdMemorySemantics, + Name: "'Semantics'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Value'", + Quantifier: "", + }, + }, + } + OpAtomicUMax = &Opcode { + Opname: "OpAtomicUMax", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Pointer'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Memory'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdMemorySemantics, + Name: "'Semantics'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Value'", + Quantifier: "", + }, + }, + } + OpAtomicAnd = &Opcode { + Opname: "OpAtomicAnd", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Pointer'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Memory'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdMemorySemantics, + Name: "'Semantics'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Value'", + Quantifier: "", + }, + }, + } + OpAtomicOr = &Opcode { + Opname: "OpAtomicOr", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Pointer'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Memory'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdMemorySemantics, + Name: "'Semantics'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Value'", + Quantifier: "", + }, + }, + } + OpAtomicXor = &Opcode { + Opname: "OpAtomicXor", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Pointer'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Memory'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdMemorySemantics, + Name: "'Semantics'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Value'", + Quantifier: "", + }, + }, + } + OpPhi = &Opcode { + Opname: "OpPhi", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindPairIdRefIdRef, + Name: "'Variable, Parent, ...'", + Quantifier: "*", + }, + }, + } + OpLoopMerge = &Opcode { + Opname: "OpLoopMerge", + Operands: []Operand { + Operand { + Kind: OperandKindIdRef, + Name: "'Merge Block'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Continue Target'", + Quantifier: "", + }, + Operand { + Kind: OperandKindLoopControl, + Name: "", + Quantifier: "", + }, + }, + } + OpSelectionMerge = &Opcode { + Opname: "OpSelectionMerge", + Operands: []Operand { + Operand { + Kind: OperandKindIdRef, + Name: "'Merge Block'", + Quantifier: "", + }, + Operand { + Kind: OperandKindSelectionControl, + Name: "", + Quantifier: "", + }, + }, + } + OpLabel = &Opcode { + Opname: "OpLabel", + Operands: []Operand { + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + }, + } + OpBranch = &Opcode { + Opname: "OpBranch", + Operands: []Operand { + Operand { + Kind: OperandKindIdRef, + Name: "'Target Label'", + Quantifier: "", + }, + }, + } + OpBranchConditional = &Opcode { + Opname: "OpBranchConditional", + Operands: []Operand { + Operand { + Kind: OperandKindIdRef, + Name: "'Condition'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'True Label'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'False Label'", + Quantifier: "", + }, + Operand { + Kind: OperandKindLiteralInteger, + Name: "'Branch weights'", + Quantifier: "*", + }, + }, + } + OpSwitch = &Opcode { + Opname: "OpSwitch", + Operands: []Operand { + Operand { + Kind: OperandKindIdRef, + Name: "'Selector'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Default'", + Quantifier: "", + }, + Operand { + Kind: OperandKindPairLiteralIntegerIdRef, + Name: "'Target'", + Quantifier: "*", + }, + }, + } + OpKill = &Opcode { + Opname: "OpKill", + Operands: []Operand { + }, + } + OpReturn = &Opcode { + Opname: "OpReturn", + Operands: []Operand { + }, + } + OpReturnValue = &Opcode { + Opname: "OpReturnValue", + Operands: []Operand { + Operand { + Kind: OperandKindIdRef, + Name: "'Value'", + Quantifier: "", + }, + }, + } + OpUnreachable = &Opcode { + Opname: "OpUnreachable", + Operands: []Operand { + }, + } + OpLifetimeStart = &Opcode { + Opname: "OpLifetimeStart", + Operands: []Operand { + Operand { + Kind: OperandKindIdRef, + Name: "'Pointer'", + Quantifier: "", + }, + Operand { + Kind: OperandKindLiteralInteger, + Name: "'Size'", + Quantifier: "", + }, + }, + } + OpLifetimeStop = &Opcode { + Opname: "OpLifetimeStop", + Operands: []Operand { + Operand { + Kind: OperandKindIdRef, + Name: "'Pointer'", + Quantifier: "", + }, + Operand { + Kind: OperandKindLiteralInteger, + Name: "'Size'", + Quantifier: "", + }, + }, + } + OpGroupAsyncCopy = &Opcode { + Opname: "OpGroupAsyncCopy", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Execution'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Destination'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Source'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Num Elements'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Stride'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Event'", + Quantifier: "", + }, + }, + } + OpGroupWaitEvents = &Opcode { + Opname: "OpGroupWaitEvents", + Operands: []Operand { + Operand { + Kind: OperandKindIdScope, + Name: "'Execution'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Num Events'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Events List'", + Quantifier: "", + }, + }, + } + OpGroupAll = &Opcode { + Opname: "OpGroupAll", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Execution'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Predicate'", + Quantifier: "", + }, + }, + } + OpGroupAny = &Opcode { + Opname: "OpGroupAny", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Execution'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Predicate'", + Quantifier: "", + }, + }, + } + OpGroupBroadcast = &Opcode { + Opname: "OpGroupBroadcast", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Execution'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Value'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'LocalId'", + Quantifier: "", + }, + }, + } + OpGroupIAdd = &Opcode { + Opname: "OpGroupIAdd", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Execution'", + Quantifier: "", + }, + Operand { + Kind: OperandKindGroupOperation, + Name: "'Operation'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'X'", + Quantifier: "", + }, + }, + } + OpGroupFAdd = &Opcode { + Opname: "OpGroupFAdd", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Execution'", + Quantifier: "", + }, + Operand { + Kind: OperandKindGroupOperation, + Name: "'Operation'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'X'", + Quantifier: "", + }, + }, + } + OpGroupFMin = &Opcode { + Opname: "OpGroupFMin", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Execution'", + Quantifier: "", + }, + Operand { + Kind: OperandKindGroupOperation, + Name: "'Operation'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'X'", + Quantifier: "", + }, + }, + } + OpGroupUMin = &Opcode { + Opname: "OpGroupUMin", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Execution'", + Quantifier: "", + }, + Operand { + Kind: OperandKindGroupOperation, + Name: "'Operation'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'X'", + Quantifier: "", + }, + }, + } + OpGroupSMin = &Opcode { + Opname: "OpGroupSMin", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Execution'", + Quantifier: "", + }, + Operand { + Kind: OperandKindGroupOperation, + Name: "'Operation'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'X'", + Quantifier: "", + }, + }, + } + OpGroupFMax = &Opcode { + Opname: "OpGroupFMax", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Execution'", + Quantifier: "", + }, + Operand { + Kind: OperandKindGroupOperation, + Name: "'Operation'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'X'", + Quantifier: "", + }, + }, + } + OpGroupUMax = &Opcode { + Opname: "OpGroupUMax", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Execution'", + Quantifier: "", + }, + Operand { + Kind: OperandKindGroupOperation, + Name: "'Operation'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'X'", + Quantifier: "", + }, + }, + } + OpGroupSMax = &Opcode { + Opname: "OpGroupSMax", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Execution'", + Quantifier: "", + }, + Operand { + Kind: OperandKindGroupOperation, + Name: "'Operation'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'X'", + Quantifier: "", + }, + }, + } + OpReadPipe = &Opcode { + Opname: "OpReadPipe", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Pipe'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Pointer'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Packet Size'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Packet Alignment'", + Quantifier: "", + }, + }, + } + OpWritePipe = &Opcode { + Opname: "OpWritePipe", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Pipe'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Pointer'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Packet Size'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Packet Alignment'", + Quantifier: "", + }, + }, + } + OpReservedReadPipe = &Opcode { + Opname: "OpReservedReadPipe", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Pipe'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Reserve Id'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Index'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Pointer'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Packet Size'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Packet Alignment'", + Quantifier: "", + }, + }, + } + OpReservedWritePipe = &Opcode { + Opname: "OpReservedWritePipe", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Pipe'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Reserve Id'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Index'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Pointer'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Packet Size'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Packet Alignment'", + Quantifier: "", + }, + }, + } + OpReserveReadPipePackets = &Opcode { + Opname: "OpReserveReadPipePackets", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Pipe'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Num Packets'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Packet Size'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Packet Alignment'", + Quantifier: "", + }, + }, + } + OpReserveWritePipePackets = &Opcode { + Opname: "OpReserveWritePipePackets", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Pipe'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Num Packets'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Packet Size'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Packet Alignment'", + Quantifier: "", + }, + }, + } + OpCommitReadPipe = &Opcode { + Opname: "OpCommitReadPipe", + Operands: []Operand { + Operand { + Kind: OperandKindIdRef, + Name: "'Pipe'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Reserve Id'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Packet Size'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Packet Alignment'", + Quantifier: "", + }, + }, + } + OpCommitWritePipe = &Opcode { + Opname: "OpCommitWritePipe", + Operands: []Operand { + Operand { + Kind: OperandKindIdRef, + Name: "'Pipe'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Reserve Id'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Packet Size'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Packet Alignment'", + Quantifier: "", + }, + }, + } + OpIsValidReserveId = &Opcode { + Opname: "OpIsValidReserveId", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Reserve Id'", + Quantifier: "", + }, + }, + } + OpGetNumPipePackets = &Opcode { + Opname: "OpGetNumPipePackets", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Pipe'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Packet Size'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Packet Alignment'", + Quantifier: "", + }, + }, + } + OpGetMaxPipePackets = &Opcode { + Opname: "OpGetMaxPipePackets", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Pipe'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Packet Size'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Packet Alignment'", + Quantifier: "", + }, + }, + } + OpGroupReserveReadPipePackets = &Opcode { + Opname: "OpGroupReserveReadPipePackets", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Execution'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Pipe'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Num Packets'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Packet Size'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Packet Alignment'", + Quantifier: "", + }, + }, + } + OpGroupReserveWritePipePackets = &Opcode { + Opname: "OpGroupReserveWritePipePackets", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Execution'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Pipe'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Num Packets'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Packet Size'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Packet Alignment'", + Quantifier: "", + }, + }, + } + OpGroupCommitReadPipe = &Opcode { + Opname: "OpGroupCommitReadPipe", + Operands: []Operand { + Operand { + Kind: OperandKindIdScope, + Name: "'Execution'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Pipe'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Reserve Id'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Packet Size'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Packet Alignment'", + Quantifier: "", + }, + }, + } + OpGroupCommitWritePipe = &Opcode { + Opname: "OpGroupCommitWritePipe", + Operands: []Operand { + Operand { + Kind: OperandKindIdScope, + Name: "'Execution'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Pipe'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Reserve Id'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Packet Size'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Packet Alignment'", + Quantifier: "", + }, + }, + } + OpEnqueueMarker = &Opcode { + Opname: "OpEnqueueMarker", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Queue'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Num Events'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Wait Events'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Ret Event'", + Quantifier: "", + }, + }, + } + OpEnqueueKernel = &Opcode { + Opname: "OpEnqueueKernel", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Queue'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Flags'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'ND Range'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Num Events'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Wait Events'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Ret Event'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Invoke'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Param'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Param Size'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Param Align'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Local Size'", + Quantifier: "*", + }, + }, + } + OpGetKernelNDrangeSubGroupCount = &Opcode { + Opname: "OpGetKernelNDrangeSubGroupCount", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'ND Range'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Invoke'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Param'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Param Size'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Param Align'", + Quantifier: "", + }, + }, + } + OpGetKernelNDrangeMaxSubGroupSize = &Opcode { + Opname: "OpGetKernelNDrangeMaxSubGroupSize", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'ND Range'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Invoke'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Param'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Param Size'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Param Align'", + Quantifier: "", + }, + }, + } + OpGetKernelWorkGroupSize = &Opcode { + Opname: "OpGetKernelWorkGroupSize", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Invoke'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Param'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Param Size'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Param Align'", + Quantifier: "", + }, + }, + } + OpGetKernelPreferredWorkGroupSizeMultiple = &Opcode { + Opname: "OpGetKernelPreferredWorkGroupSizeMultiple", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Invoke'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Param'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Param Size'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Param Align'", + Quantifier: "", + }, + }, + } + OpRetainEvent = &Opcode { + Opname: "OpRetainEvent", + Operands: []Operand { + Operand { + Kind: OperandKindIdRef, + Name: "'Event'", + Quantifier: "", + }, + }, + } + OpReleaseEvent = &Opcode { + Opname: "OpReleaseEvent", + Operands: []Operand { + Operand { + Kind: OperandKindIdRef, + Name: "'Event'", + Quantifier: "", + }, + }, + } + OpCreateUserEvent = &Opcode { + Opname: "OpCreateUserEvent", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + }, + } + OpIsValidEvent = &Opcode { + Opname: "OpIsValidEvent", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Event'", + Quantifier: "", + }, + }, + } + OpSetUserEventStatus = &Opcode { + Opname: "OpSetUserEventStatus", + Operands: []Operand { + Operand { + Kind: OperandKindIdRef, + Name: "'Event'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Status'", + Quantifier: "", + }, + }, + } + OpCaptureEventProfilingInfo = &Opcode { + Opname: "OpCaptureEventProfilingInfo", + Operands: []Operand { + Operand { + Kind: OperandKindIdRef, + Name: "'Event'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Profiling Info'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Value'", + Quantifier: "", + }, + }, + } + OpGetDefaultQueue = &Opcode { + Opname: "OpGetDefaultQueue", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + }, + } + OpBuildNDRange = &Opcode { + Opname: "OpBuildNDRange", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'GlobalWorkSize'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'LocalWorkSize'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'GlobalWorkOffset'", + Quantifier: "", + }, + }, + } + OpImageSparseSampleImplicitLod = &Opcode { + Opname: "OpImageSparseSampleImplicitLod", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Sampled Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Coordinate'", + Quantifier: "", + }, + Operand { + Kind: OperandKindImageOperands, + Name: "", + Quantifier: "?", + }, + }, + } + OpImageSparseSampleExplicitLod = &Opcode { + Opname: "OpImageSparseSampleExplicitLod", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Sampled Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Coordinate'", + Quantifier: "", + }, + Operand { + Kind: OperandKindImageOperands, + Name: "", + Quantifier: "", + }, + }, + } + OpImageSparseSampleDrefImplicitLod = &Opcode { + Opname: "OpImageSparseSampleDrefImplicitLod", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Sampled Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Coordinate'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'D~ref~'", + Quantifier: "", + }, + Operand { + Kind: OperandKindImageOperands, + Name: "", + Quantifier: "?", + }, + }, + } + OpImageSparseSampleDrefExplicitLod = &Opcode { + Opname: "OpImageSparseSampleDrefExplicitLod", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Sampled Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Coordinate'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'D~ref~'", + Quantifier: "", + }, + Operand { + Kind: OperandKindImageOperands, + Name: "", + Quantifier: "", + }, + }, + } + OpImageSparseSampleProjImplicitLod = &Opcode { + Opname: "OpImageSparseSampleProjImplicitLod", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Sampled Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Coordinate'", + Quantifier: "", + }, + Operand { + Kind: OperandKindImageOperands, + Name: "", + Quantifier: "?", + }, + }, + } + OpImageSparseSampleProjExplicitLod = &Opcode { + Opname: "OpImageSparseSampleProjExplicitLod", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Sampled Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Coordinate'", + Quantifier: "", + }, + Operand { + Kind: OperandKindImageOperands, + Name: "", + Quantifier: "", + }, + }, + } + OpImageSparseSampleProjDrefImplicitLod = &Opcode { + Opname: "OpImageSparseSampleProjDrefImplicitLod", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Sampled Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Coordinate'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'D~ref~'", + Quantifier: "", + }, + Operand { + Kind: OperandKindImageOperands, + Name: "", + Quantifier: "?", + }, + }, + } + OpImageSparseSampleProjDrefExplicitLod = &Opcode { + Opname: "OpImageSparseSampleProjDrefExplicitLod", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Sampled Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Coordinate'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'D~ref~'", + Quantifier: "", + }, + Operand { + Kind: OperandKindImageOperands, + Name: "", + Quantifier: "", + }, + }, + } + OpImageSparseFetch = &Opcode { + Opname: "OpImageSparseFetch", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Coordinate'", + Quantifier: "", + }, + Operand { + Kind: OperandKindImageOperands, + Name: "", + Quantifier: "?", + }, + }, + } + OpImageSparseGather = &Opcode { + Opname: "OpImageSparseGather", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Sampled Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Coordinate'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Component'", + Quantifier: "", + }, + Operand { + Kind: OperandKindImageOperands, + Name: "", + Quantifier: "?", + }, + }, + } + OpImageSparseDrefGather = &Opcode { + Opname: "OpImageSparseDrefGather", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Sampled Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Coordinate'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'D~ref~'", + Quantifier: "", + }, + Operand { + Kind: OperandKindImageOperands, + Name: "", + Quantifier: "?", + }, + }, + } + OpImageSparseTexelsResident = &Opcode { + Opname: "OpImageSparseTexelsResident", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Resident Code'", + Quantifier: "", + }, + }, + } + OpNoLine = &Opcode { + Opname: "OpNoLine", + Operands: []Operand { + }, + } + OpAtomicFlagTestAndSet = &Opcode { + Opname: "OpAtomicFlagTestAndSet", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Pointer'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Memory'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdMemorySemantics, + Name: "'Semantics'", + Quantifier: "", + }, + }, + } + OpAtomicFlagClear = &Opcode { + Opname: "OpAtomicFlagClear", + Operands: []Operand { + Operand { + Kind: OperandKindIdRef, + Name: "'Pointer'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Memory'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdMemorySemantics, + Name: "'Semantics'", + Quantifier: "", + }, + }, + } + OpImageSparseRead = &Opcode { + Opname: "OpImageSparseRead", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Coordinate'", + Quantifier: "", + }, + Operand { + Kind: OperandKindImageOperands, + Name: "", + Quantifier: "?", + }, + }, + } + OpSizeOf = &Opcode { + Opname: "OpSizeOf", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Pointer'", + Quantifier: "", + }, + }, + } + OpTypePipeStorage = &Opcode { + Opname: "OpTypePipeStorage", + Operands: []Operand { + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + }, + } + OpConstantPipeStorage = &Opcode { + Opname: "OpConstantPipeStorage", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindLiteralInteger, + Name: "'Packet Size'", + Quantifier: "", + }, + Operand { + Kind: OperandKindLiteralInteger, + Name: "'Packet Alignment'", + Quantifier: "", + }, + Operand { + Kind: OperandKindLiteralInteger, + Name: "'Capacity'", + Quantifier: "", + }, + }, + } + OpCreatePipeFromPipeStorage = &Opcode { + Opname: "OpCreatePipeFromPipeStorage", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Pipe Storage'", + Quantifier: "", + }, + }, + } + OpGetKernelLocalSizeForSubgroupCount = &Opcode { + Opname: "OpGetKernelLocalSizeForSubgroupCount", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Subgroup Count'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Invoke'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Param'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Param Size'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Param Align'", + Quantifier: "", + }, + }, + } + OpGetKernelMaxNumSubgroups = &Opcode { + Opname: "OpGetKernelMaxNumSubgroups", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Invoke'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Param'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Param Size'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Param Align'", + Quantifier: "", + }, + }, + } + OpTypeNamedBarrier = &Opcode { + Opname: "OpTypeNamedBarrier", + Operands: []Operand { + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + }, + } + OpNamedBarrierInitialize = &Opcode { + Opname: "OpNamedBarrierInitialize", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Subgroup Count'", + Quantifier: "", + }, + }, + } + OpMemoryNamedBarrier = &Opcode { + Opname: "OpMemoryNamedBarrier", + Operands: []Operand { + Operand { + Kind: OperandKindIdRef, + Name: "'Named Barrier'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Memory'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdMemorySemantics, + Name: "'Semantics'", + Quantifier: "", + }, + }, + } + OpModuleProcessed = &Opcode { + Opname: "OpModuleProcessed", + Operands: []Operand { + Operand { + Kind: OperandKindLiteralString, + Name: "'Process'", + Quantifier: "", + }, + }, + } + OpExecutionModeId = &Opcode { + Opname: "OpExecutionModeId", + Operands: []Operand { + Operand { + Kind: OperandKindIdRef, + Name: "'Entry Point'", + Quantifier: "", + }, + Operand { + Kind: OperandKindExecutionMode, + Name: "'Mode'", + Quantifier: "", + }, + }, + } + OpDecorateId = &Opcode { + Opname: "OpDecorateId", + Operands: []Operand { + Operand { + Kind: OperandKindIdRef, + Name: "'Target'", + Quantifier: "", + }, + Operand { + Kind: OperandKindDecoration, + Name: "", + Quantifier: "", + }, + }, + } + OpGroupNonUniformElect = &Opcode { + Opname: "OpGroupNonUniformElect", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Execution'", + Quantifier: "", + }, + }, + } + OpGroupNonUniformAll = &Opcode { + Opname: "OpGroupNonUniformAll", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Execution'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Predicate'", + Quantifier: "", + }, + }, + } + OpGroupNonUniformAny = &Opcode { + Opname: "OpGroupNonUniformAny", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Execution'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Predicate'", + Quantifier: "", + }, + }, + } + OpGroupNonUniformAllEqual = &Opcode { + Opname: "OpGroupNonUniformAllEqual", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Execution'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Value'", + Quantifier: "", + }, + }, + } + OpGroupNonUniformBroadcast = &Opcode { + Opname: "OpGroupNonUniformBroadcast", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Execution'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Value'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Id'", + Quantifier: "", + }, + }, + } + OpGroupNonUniformBroadcastFirst = &Opcode { + Opname: "OpGroupNonUniformBroadcastFirst", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Execution'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Value'", + Quantifier: "", + }, + }, + } + OpGroupNonUniformBallot = &Opcode { + Opname: "OpGroupNonUniformBallot", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Execution'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Predicate'", + Quantifier: "", + }, + }, + } + OpGroupNonUniformInverseBallot = &Opcode { + Opname: "OpGroupNonUniformInverseBallot", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Execution'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Value'", + Quantifier: "", + }, + }, + } + OpGroupNonUniformBallotBitExtract = &Opcode { + Opname: "OpGroupNonUniformBallotBitExtract", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Execution'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Value'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Index'", + Quantifier: "", + }, + }, + } + OpGroupNonUniformBallotBitCount = &Opcode { + Opname: "OpGroupNonUniformBallotBitCount", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Execution'", + Quantifier: "", + }, + Operand { + Kind: OperandKindGroupOperation, + Name: "'Operation'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Value'", + Quantifier: "", + }, + }, + } + OpGroupNonUniformBallotFindLSB = &Opcode { + Opname: "OpGroupNonUniformBallotFindLSB", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Execution'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Value'", + Quantifier: "", + }, + }, + } + OpGroupNonUniformBallotFindMSB = &Opcode { + Opname: "OpGroupNonUniformBallotFindMSB", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Execution'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Value'", + Quantifier: "", + }, + }, + } + OpGroupNonUniformShuffle = &Opcode { + Opname: "OpGroupNonUniformShuffle", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Execution'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Value'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Id'", + Quantifier: "", + }, + }, + } + OpGroupNonUniformShuffleXor = &Opcode { + Opname: "OpGroupNonUniformShuffleXor", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Execution'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Value'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Mask'", + Quantifier: "", + }, + }, + } + OpGroupNonUniformShuffleUp = &Opcode { + Opname: "OpGroupNonUniformShuffleUp", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Execution'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Value'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Delta'", + Quantifier: "", + }, + }, + } + OpGroupNonUniformShuffleDown = &Opcode { + Opname: "OpGroupNonUniformShuffleDown", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Execution'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Value'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Delta'", + Quantifier: "", + }, + }, + } + OpGroupNonUniformIAdd = &Opcode { + Opname: "OpGroupNonUniformIAdd", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Execution'", + Quantifier: "", + }, + Operand { + Kind: OperandKindGroupOperation, + Name: "'Operation'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Value'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'ClusterSize'", + Quantifier: "?", + }, + }, + } + OpGroupNonUniformFAdd = &Opcode { + Opname: "OpGroupNonUniformFAdd", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Execution'", + Quantifier: "", + }, + Operand { + Kind: OperandKindGroupOperation, + Name: "'Operation'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Value'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'ClusterSize'", + Quantifier: "?", + }, + }, + } + OpGroupNonUniformIMul = &Opcode { + Opname: "OpGroupNonUniformIMul", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Execution'", + Quantifier: "", + }, + Operand { + Kind: OperandKindGroupOperation, + Name: "'Operation'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Value'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'ClusterSize'", + Quantifier: "?", + }, + }, + } + OpGroupNonUniformFMul = &Opcode { + Opname: "OpGroupNonUniformFMul", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Execution'", + Quantifier: "", + }, + Operand { + Kind: OperandKindGroupOperation, + Name: "'Operation'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Value'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'ClusterSize'", + Quantifier: "?", + }, + }, + } + OpGroupNonUniformSMin = &Opcode { + Opname: "OpGroupNonUniformSMin", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Execution'", + Quantifier: "", + }, + Operand { + Kind: OperandKindGroupOperation, + Name: "'Operation'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Value'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'ClusterSize'", + Quantifier: "?", + }, + }, + } + OpGroupNonUniformUMin = &Opcode { + Opname: "OpGroupNonUniformUMin", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Execution'", + Quantifier: "", + }, + Operand { + Kind: OperandKindGroupOperation, + Name: "'Operation'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Value'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'ClusterSize'", + Quantifier: "?", + }, + }, + } + OpGroupNonUniformFMin = &Opcode { + Opname: "OpGroupNonUniformFMin", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Execution'", + Quantifier: "", + }, + Operand { + Kind: OperandKindGroupOperation, + Name: "'Operation'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Value'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'ClusterSize'", + Quantifier: "?", + }, + }, + } + OpGroupNonUniformSMax = &Opcode { + Opname: "OpGroupNonUniformSMax", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Execution'", + Quantifier: "", + }, + Operand { + Kind: OperandKindGroupOperation, + Name: "'Operation'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Value'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'ClusterSize'", + Quantifier: "?", + }, + }, + } + OpGroupNonUniformUMax = &Opcode { + Opname: "OpGroupNonUniformUMax", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Execution'", + Quantifier: "", + }, + Operand { + Kind: OperandKindGroupOperation, + Name: "'Operation'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Value'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'ClusterSize'", + Quantifier: "?", + }, + }, + } + OpGroupNonUniformFMax = &Opcode { + Opname: "OpGroupNonUniformFMax", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Execution'", + Quantifier: "", + }, + Operand { + Kind: OperandKindGroupOperation, + Name: "'Operation'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Value'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'ClusterSize'", + Quantifier: "?", + }, + }, + } + OpGroupNonUniformBitwiseAnd = &Opcode { + Opname: "OpGroupNonUniformBitwiseAnd", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Execution'", + Quantifier: "", + }, + Operand { + Kind: OperandKindGroupOperation, + Name: "'Operation'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Value'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'ClusterSize'", + Quantifier: "?", + }, + }, + } + OpGroupNonUniformBitwiseOr = &Opcode { + Opname: "OpGroupNonUniformBitwiseOr", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Execution'", + Quantifier: "", + }, + Operand { + Kind: OperandKindGroupOperation, + Name: "'Operation'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Value'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'ClusterSize'", + Quantifier: "?", + }, + }, + } + OpGroupNonUniformBitwiseXor = &Opcode { + Opname: "OpGroupNonUniformBitwiseXor", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Execution'", + Quantifier: "", + }, + Operand { + Kind: OperandKindGroupOperation, + Name: "'Operation'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Value'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'ClusterSize'", + Quantifier: "?", + }, + }, + } + OpGroupNonUniformLogicalAnd = &Opcode { + Opname: "OpGroupNonUniformLogicalAnd", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Execution'", + Quantifier: "", + }, + Operand { + Kind: OperandKindGroupOperation, + Name: "'Operation'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Value'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'ClusterSize'", + Quantifier: "?", + }, + }, + } + OpGroupNonUniformLogicalOr = &Opcode { + Opname: "OpGroupNonUniformLogicalOr", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Execution'", + Quantifier: "", + }, + Operand { + Kind: OperandKindGroupOperation, + Name: "'Operation'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Value'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'ClusterSize'", + Quantifier: "?", + }, + }, + } + OpGroupNonUniformLogicalXor = &Opcode { + Opname: "OpGroupNonUniformLogicalXor", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Execution'", + Quantifier: "", + }, + Operand { + Kind: OperandKindGroupOperation, + Name: "'Operation'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Value'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'ClusterSize'", + Quantifier: "?", + }, + }, + } + OpGroupNonUniformQuadBroadcast = &Opcode { + Opname: "OpGroupNonUniformQuadBroadcast", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Execution'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Value'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Index'", + Quantifier: "", + }, + }, + } + OpGroupNonUniformQuadSwap = &Opcode { + Opname: "OpGroupNonUniformQuadSwap", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Execution'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Value'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Direction'", + Quantifier: "", + }, + }, + } + OpCopyLogical = &Opcode { + Opname: "OpCopyLogical", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand'", + Quantifier: "", + }, + }, + } + OpPtrEqual = &Opcode { + Opname: "OpPtrEqual", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 1'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 2'", + Quantifier: "", + }, + }, + } + OpPtrNotEqual = &Opcode { + Opname: "OpPtrNotEqual", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 1'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 2'", + Quantifier: "", + }, + }, + } + OpPtrDiff = &Opcode { + Opname: "OpPtrDiff", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 1'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 2'", + Quantifier: "", + }, + }, + } + OpSubgroupBallotKHR = &Opcode { + Opname: "OpSubgroupBallotKHR", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Predicate'", + Quantifier: "", + }, + }, + } + OpSubgroupFirstInvocationKHR = &Opcode { + Opname: "OpSubgroupFirstInvocationKHR", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Value'", + Quantifier: "", + }, + }, + } + OpSubgroupAllKHR = &Opcode { + Opname: "OpSubgroupAllKHR", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Predicate'", + Quantifier: "", + }, + }, + } + OpSubgroupAnyKHR = &Opcode { + Opname: "OpSubgroupAnyKHR", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Predicate'", + Quantifier: "", + }, + }, + } + OpSubgroupAllEqualKHR = &Opcode { + Opname: "OpSubgroupAllEqualKHR", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Predicate'", + Quantifier: "", + }, + }, + } + OpSubgroupReadInvocationKHR = &Opcode { + Opname: "OpSubgroupReadInvocationKHR", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Value'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Index'", + Quantifier: "", + }, + }, + } + OpGroupIAddNonUniformAMD = &Opcode { + Opname: "OpGroupIAddNonUniformAMD", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Execution'", + Quantifier: "", + }, + Operand { + Kind: OperandKindGroupOperation, + Name: "'Operation'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'X'", + Quantifier: "", + }, + }, + } + OpGroupFAddNonUniformAMD = &Opcode { + Opname: "OpGroupFAddNonUniformAMD", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Execution'", + Quantifier: "", + }, + Operand { + Kind: OperandKindGroupOperation, + Name: "'Operation'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'X'", + Quantifier: "", + }, + }, + } + OpGroupFMinNonUniformAMD = &Opcode { + Opname: "OpGroupFMinNonUniformAMD", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Execution'", + Quantifier: "", + }, + Operand { + Kind: OperandKindGroupOperation, + Name: "'Operation'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'X'", + Quantifier: "", + }, + }, + } + OpGroupUMinNonUniformAMD = &Opcode { + Opname: "OpGroupUMinNonUniformAMD", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Execution'", + Quantifier: "", + }, + Operand { + Kind: OperandKindGroupOperation, + Name: "'Operation'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'X'", + Quantifier: "", + }, + }, + } + OpGroupSMinNonUniformAMD = &Opcode { + Opname: "OpGroupSMinNonUniformAMD", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Execution'", + Quantifier: "", + }, + Operand { + Kind: OperandKindGroupOperation, + Name: "'Operation'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'X'", + Quantifier: "", + }, + }, + } + OpGroupFMaxNonUniformAMD = &Opcode { + Opname: "OpGroupFMaxNonUniformAMD", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Execution'", + Quantifier: "", + }, + Operand { + Kind: OperandKindGroupOperation, + Name: "'Operation'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'X'", + Quantifier: "", + }, + }, + } + OpGroupUMaxNonUniformAMD = &Opcode { + Opname: "OpGroupUMaxNonUniformAMD", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Execution'", + Quantifier: "", + }, + Operand { + Kind: OperandKindGroupOperation, + Name: "'Operation'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'X'", + Quantifier: "", + }, + }, + } + OpGroupSMaxNonUniformAMD = &Opcode { + Opname: "OpGroupSMaxNonUniformAMD", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Execution'", + Quantifier: "", + }, + Operand { + Kind: OperandKindGroupOperation, + Name: "'Operation'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'X'", + Quantifier: "", + }, + }, + } + OpFragmentMaskFetchAMD = &Opcode { + Opname: "OpFragmentMaskFetchAMD", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Coordinate'", + Quantifier: "", + }, + }, + } + OpFragmentFetchAMD = &Opcode { + Opname: "OpFragmentFetchAMD", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Coordinate'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Fragment Index'", + Quantifier: "", + }, + }, + } + OpReadClockKHR = &Opcode { + Opname: "OpReadClockKHR", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Execution'", + Quantifier: "", + }, + }, + } + OpImageSampleFootprintNV = &Opcode { + Opname: "OpImageSampleFootprintNV", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Sampled Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Coordinate'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Granularity'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Coarse'", + Quantifier: "", + }, + Operand { + Kind: OperandKindImageOperands, + Name: "", + Quantifier: "?", + }, + }, + } + OpGroupNonUniformPartitionNV = &Opcode { + Opname: "OpGroupNonUniformPartitionNV", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Value'", + Quantifier: "", + }, + }, + } + OpWritePackedPrimitiveIndices4x8NV = &Opcode { + Opname: "OpWritePackedPrimitiveIndices4x8NV", + Operands: []Operand { + Operand { + Kind: OperandKindIdRef, + Name: "'Index Offset'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Packed Indices'", + Quantifier: "", + }, + }, + } + OpReportIntersectionNV = &Opcode { + Opname: "OpReportIntersectionNV", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Hit'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'HitKind'", + Quantifier: "", + }, + }, + } + OpIgnoreIntersectionNV = &Opcode { + Opname: "OpIgnoreIntersectionNV", + Operands: []Operand { + }, + } + OpTerminateRayNV = &Opcode { + Opname: "OpTerminateRayNV", + Operands: []Operand { + }, + } + OpTraceNV = &Opcode { + Opname: "OpTraceNV", + Operands: []Operand { + Operand { + Kind: OperandKindIdRef, + Name: "'Accel'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Ray Flags'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Cull Mask'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'SBT Offset'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'SBT Stride'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Miss Index'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Ray Origin'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Ray Tmin'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Ray Direction'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Ray Tmax'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'PayloadId'", + Quantifier: "", + }, + }, + } + OpTypeAccelerationStructureNV = &Opcode { + Opname: "OpTypeAccelerationStructureNV", + Operands: []Operand { + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + }, + } + OpExecuteCallableNV = &Opcode { + Opname: "OpExecuteCallableNV", + Operands: []Operand { + Operand { + Kind: OperandKindIdRef, + Name: "'SBT Index'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Callable DataId'", + Quantifier: "", + }, + }, + } + OpTypeCooperativeMatrixNV = &Opcode { + Opname: "OpTypeCooperativeMatrixNV", + Operands: []Operand { + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Component Type'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdScope, + Name: "'Execution'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Rows'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Columns'", + Quantifier: "", + }, + }, + } + OpCooperativeMatrixLoadNV = &Opcode { + Opname: "OpCooperativeMatrixLoadNV", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Pointer'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Stride'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Column Major'", + Quantifier: "", + }, + Operand { + Kind: OperandKindMemoryAccess, + Name: "", + Quantifier: "?", + }, + }, + } + OpCooperativeMatrixStoreNV = &Opcode { + Opname: "OpCooperativeMatrixStoreNV", + Operands: []Operand { + Operand { + Kind: OperandKindIdRef, + Name: "'Pointer'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Object'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Stride'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Column Major'", + Quantifier: "", + }, + Operand { + Kind: OperandKindMemoryAccess, + Name: "", + Quantifier: "?", + }, + }, + } + OpCooperativeMatrixMulAddNV = &Opcode { + Opname: "OpCooperativeMatrixMulAddNV", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'A'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'B'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'C'", + Quantifier: "", + }, + }, + } + OpCooperativeMatrixLengthNV = &Opcode { + Opname: "OpCooperativeMatrixLengthNV", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Type'", + Quantifier: "", + }, + }, + } + OpBeginInvocationInterlockEXT = &Opcode { + Opname: "OpBeginInvocationInterlockEXT", + Operands: []Operand { + }, + } + OpEndInvocationInterlockEXT = &Opcode { + Opname: "OpEndInvocationInterlockEXT", + Operands: []Operand { + }, + } + OpDemoteToHelperInvocationEXT = &Opcode { + Opname: "OpDemoteToHelperInvocationEXT", + Operands: []Operand { + }, + } + OpIsHelperInvocationEXT = &Opcode { + Opname: "OpIsHelperInvocationEXT", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + }, + } + OpSubgroupShuffleINTEL = &Opcode { + Opname: "OpSubgroupShuffleINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Data'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'InvocationId'", + Quantifier: "", + }, + }, + } + OpSubgroupShuffleDownINTEL = &Opcode { + Opname: "OpSubgroupShuffleDownINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Current'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Next'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Delta'", + Quantifier: "", + }, + }, + } + OpSubgroupShuffleUpINTEL = &Opcode { + Opname: "OpSubgroupShuffleUpINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Previous'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Current'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Delta'", + Quantifier: "", + }, + }, + } + OpSubgroupShuffleXorINTEL = &Opcode { + Opname: "OpSubgroupShuffleXorINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Data'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Value'", + Quantifier: "", + }, + }, + } + OpSubgroupBlockReadINTEL = &Opcode { + Opname: "OpSubgroupBlockReadINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Ptr'", + Quantifier: "", + }, + }, + } + OpSubgroupBlockWriteINTEL = &Opcode { + Opname: "OpSubgroupBlockWriteINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdRef, + Name: "'Ptr'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Data'", + Quantifier: "", + }, + }, + } + OpSubgroupImageBlockReadINTEL = &Opcode { + Opname: "OpSubgroupImageBlockReadINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Coordinate'", + Quantifier: "", + }, + }, + } + OpSubgroupImageBlockWriteINTEL = &Opcode { + Opname: "OpSubgroupImageBlockWriteINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdRef, + Name: "'Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Coordinate'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Data'", + Quantifier: "", + }, + }, + } + OpSubgroupImageMediaBlockReadINTEL = &Opcode { + Opname: "OpSubgroupImageMediaBlockReadINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Coordinate'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Width'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Height'", + Quantifier: "", + }, + }, + } + OpSubgroupImageMediaBlockWriteINTEL = &Opcode { + Opname: "OpSubgroupImageMediaBlockWriteINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdRef, + Name: "'Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Coordinate'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Width'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Height'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Data'", + Quantifier: "", + }, + }, + } + OpUCountLeadingZerosINTEL = &Opcode { + Opname: "OpUCountLeadingZerosINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand'", + Quantifier: "", + }, + }, + } + OpUCountTrailingZerosINTEL = &Opcode { + Opname: "OpUCountTrailingZerosINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand'", + Quantifier: "", + }, + }, + } + OpAbsISubINTEL = &Opcode { + Opname: "OpAbsISubINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 1'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 2'", + Quantifier: "", + }, + }, + } + OpAbsUSubINTEL = &Opcode { + Opname: "OpAbsUSubINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 1'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 2'", + Quantifier: "", + }, + }, + } + OpIAddSatINTEL = &Opcode { + Opname: "OpIAddSatINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 1'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 2'", + Quantifier: "", + }, + }, + } + OpUAddSatINTEL = &Opcode { + Opname: "OpUAddSatINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 1'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 2'", + Quantifier: "", + }, + }, + } + OpIAverageINTEL = &Opcode { + Opname: "OpIAverageINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 1'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 2'", + Quantifier: "", + }, + }, + } + OpUAverageINTEL = &Opcode { + Opname: "OpUAverageINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 1'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 2'", + Quantifier: "", + }, + }, + } + OpIAverageRoundedINTEL = &Opcode { + Opname: "OpIAverageRoundedINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 1'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 2'", + Quantifier: "", + }, + }, + } + OpUAverageRoundedINTEL = &Opcode { + Opname: "OpUAverageRoundedINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 1'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 2'", + Quantifier: "", + }, + }, + } + OpISubSatINTEL = &Opcode { + Opname: "OpISubSatINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 1'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 2'", + Quantifier: "", + }, + }, + } + OpUSubSatINTEL = &Opcode { + Opname: "OpUSubSatINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 1'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 2'", + Quantifier: "", + }, + }, + } + OpIMul32x16INTEL = &Opcode { + Opname: "OpIMul32x16INTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 1'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 2'", + Quantifier: "", + }, + }, + } + OpUMul32x16INTEL = &Opcode { + Opname: "OpUMul32x16INTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 1'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Operand 2'", + Quantifier: "", + }, + }, + } + OpDecorateString = &Opcode { + Opname: "OpDecorateString", + Operands: []Operand { + Operand { + Kind: OperandKindIdRef, + Name: "'Target'", + Quantifier: "", + }, + Operand { + Kind: OperandKindDecoration, + Name: "", + Quantifier: "", + }, + }, + } + OpDecorateStringGOOGLE = &Opcode { + Opname: "OpDecorateStringGOOGLE", + Operands: []Operand { + Operand { + Kind: OperandKindIdRef, + Name: "'Target'", + Quantifier: "", + }, + Operand { + Kind: OperandKindDecoration, + Name: "", + Quantifier: "", + }, + }, + } + OpMemberDecorateString = &Opcode { + Opname: "OpMemberDecorateString", + Operands: []Operand { + Operand { + Kind: OperandKindIdRef, + Name: "'Struct Type'", + Quantifier: "", + }, + Operand { + Kind: OperandKindLiteralInteger, + Name: "'Member'", + Quantifier: "", + }, + Operand { + Kind: OperandKindDecoration, + Name: "", + Quantifier: "", + }, + }, + } + OpMemberDecorateStringGOOGLE = &Opcode { + Opname: "OpMemberDecorateStringGOOGLE", + Operands: []Operand { + Operand { + Kind: OperandKindIdRef, + Name: "'Struct Type'", + Quantifier: "", + }, + Operand { + Kind: OperandKindLiteralInteger, + Name: "'Member'", + Quantifier: "", + }, + Operand { + Kind: OperandKindDecoration, + Name: "", + Quantifier: "", + }, + }, + } + OpVmeImageINTEL = &Opcode { + Opname: "OpVmeImageINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Image Type'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Sampler'", + Quantifier: "", + }, + }, + } + OpTypeVmeImageINTEL = &Opcode { + Opname: "OpTypeVmeImageINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Image Type'", + Quantifier: "", + }, + }, + } + OpTypeAvcImePayloadINTEL = &Opcode { + Opname: "OpTypeAvcImePayloadINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + }, + } + OpTypeAvcRefPayloadINTEL = &Opcode { + Opname: "OpTypeAvcRefPayloadINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + }, + } + OpTypeAvcSicPayloadINTEL = &Opcode { + Opname: "OpTypeAvcSicPayloadINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + }, + } + OpTypeAvcMcePayloadINTEL = &Opcode { + Opname: "OpTypeAvcMcePayloadINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + }, + } + OpTypeAvcMceResultINTEL = &Opcode { + Opname: "OpTypeAvcMceResultINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + }, + } + OpTypeAvcImeResultINTEL = &Opcode { + Opname: "OpTypeAvcImeResultINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + }, + } + OpTypeAvcImeResultSingleReferenceStreamoutINTEL = &Opcode { + Opname: "OpTypeAvcImeResultSingleReferenceStreamoutINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + }, + } + OpTypeAvcImeResultDualReferenceStreamoutINTEL = &Opcode { + Opname: "OpTypeAvcImeResultDualReferenceStreamoutINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + }, + } + OpTypeAvcImeSingleReferenceStreaminINTEL = &Opcode { + Opname: "OpTypeAvcImeSingleReferenceStreaminINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + }, + } + OpTypeAvcImeDualReferenceStreaminINTEL = &Opcode { + Opname: "OpTypeAvcImeDualReferenceStreaminINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + }, + } + OpTypeAvcRefResultINTEL = &Opcode { + Opname: "OpTypeAvcRefResultINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + }, + } + OpTypeAvcSicResultINTEL = &Opcode { + Opname: "OpTypeAvcSicResultINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + }, + } + OpSubgroupAvcMceGetDefaultInterBaseMultiReferencePenaltyINTEL = &Opcode { + Opname: "OpSubgroupAvcMceGetDefaultInterBaseMultiReferencePenaltyINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Slice Type'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Qp'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcMceSetInterBaseMultiReferencePenaltyINTEL = &Opcode { + Opname: "OpSubgroupAvcMceSetInterBaseMultiReferencePenaltyINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Reference Base Penalty'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcMceGetDefaultInterShapePenaltyINTEL = &Opcode { + Opname: "OpSubgroupAvcMceGetDefaultInterShapePenaltyINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Slice Type'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Qp'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcMceSetInterShapePenaltyINTEL = &Opcode { + Opname: "OpSubgroupAvcMceSetInterShapePenaltyINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Packed Shape Penalty'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcMceGetDefaultInterDirectionPenaltyINTEL = &Opcode { + Opname: "OpSubgroupAvcMceGetDefaultInterDirectionPenaltyINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Slice Type'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Qp'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcMceSetInterDirectionPenaltyINTEL = &Opcode { + Opname: "OpSubgroupAvcMceSetInterDirectionPenaltyINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Direction Cost'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcMceGetDefaultIntraLumaShapePenaltyINTEL = &Opcode { + Opname: "OpSubgroupAvcMceGetDefaultIntraLumaShapePenaltyINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Slice Type'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Qp'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcMceGetDefaultInterMotionVectorCostTableINTEL = &Opcode { + Opname: "OpSubgroupAvcMceGetDefaultInterMotionVectorCostTableINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Slice Type'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Qp'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcMceGetDefaultHighPenaltyCostTableINTEL = &Opcode { + Opname: "OpSubgroupAvcMceGetDefaultHighPenaltyCostTableINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + }, + } + OpSubgroupAvcMceGetDefaultMediumPenaltyCostTableINTEL = &Opcode { + Opname: "OpSubgroupAvcMceGetDefaultMediumPenaltyCostTableINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + }, + } + OpSubgroupAvcMceGetDefaultLowPenaltyCostTableINTEL = &Opcode { + Opname: "OpSubgroupAvcMceGetDefaultLowPenaltyCostTableINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + }, + } + OpSubgroupAvcMceSetMotionVectorCostFunctionINTEL = &Opcode { + Opname: "OpSubgroupAvcMceSetMotionVectorCostFunctionINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Packed Cost Center Delta'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Packed Cost Table'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Cost Precision'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcMceGetDefaultIntraLumaModePenaltyINTEL = &Opcode { + Opname: "OpSubgroupAvcMceGetDefaultIntraLumaModePenaltyINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Slice Type'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Qp'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcMceGetDefaultNonDcLumaIntraPenaltyINTEL = &Opcode { + Opname: "OpSubgroupAvcMceGetDefaultNonDcLumaIntraPenaltyINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + }, + } + OpSubgroupAvcMceGetDefaultIntraChromaModeBasePenaltyINTEL = &Opcode { + Opname: "OpSubgroupAvcMceGetDefaultIntraChromaModeBasePenaltyINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + }, + } + OpSubgroupAvcMceSetAcOnlyHaarINTEL = &Opcode { + Opname: "OpSubgroupAvcMceSetAcOnlyHaarINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcMceSetSourceInterlacedFieldPolarityINTEL = &Opcode { + Opname: "OpSubgroupAvcMceSetSourceInterlacedFieldPolarityINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Source Field Polarity'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcMceSetSingleReferenceInterlacedFieldPolarityINTEL = &Opcode { + Opname: "OpSubgroupAvcMceSetSingleReferenceInterlacedFieldPolarityINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Reference Field Polarity'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcMceSetDualReferenceInterlacedFieldPolaritiesINTEL = &Opcode { + Opname: "OpSubgroupAvcMceSetDualReferenceInterlacedFieldPolaritiesINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Forward Reference Field Polarity'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Backward Reference Field Polarity'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcMceConvertToImePayloadINTEL = &Opcode { + Opname: "OpSubgroupAvcMceConvertToImePayloadINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcMceConvertToImeResultINTEL = &Opcode { + Opname: "OpSubgroupAvcMceConvertToImeResultINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcMceConvertToRefPayloadINTEL = &Opcode { + Opname: "OpSubgroupAvcMceConvertToRefPayloadINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcMceConvertToRefResultINTEL = &Opcode { + Opname: "OpSubgroupAvcMceConvertToRefResultINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcMceConvertToSicPayloadINTEL = &Opcode { + Opname: "OpSubgroupAvcMceConvertToSicPayloadINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcMceConvertToSicResultINTEL = &Opcode { + Opname: "OpSubgroupAvcMceConvertToSicResultINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcMceGetMotionVectorsINTEL = &Opcode { + Opname: "OpSubgroupAvcMceGetMotionVectorsINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcMceGetInterDistortionsINTEL = &Opcode { + Opname: "OpSubgroupAvcMceGetInterDistortionsINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcMceGetBestInterDistortionsINTEL = &Opcode { + Opname: "OpSubgroupAvcMceGetBestInterDistortionsINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcMceGetInterMajorShapeINTEL = &Opcode { + Opname: "OpSubgroupAvcMceGetInterMajorShapeINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcMceGetInterMinorShapeINTEL = &Opcode { + Opname: "OpSubgroupAvcMceGetInterMinorShapeINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcMceGetInterDirectionsINTEL = &Opcode { + Opname: "OpSubgroupAvcMceGetInterDirectionsINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcMceGetInterMotionVectorCountINTEL = &Opcode { + Opname: "OpSubgroupAvcMceGetInterMotionVectorCountINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcMceGetInterReferenceIdsINTEL = &Opcode { + Opname: "OpSubgroupAvcMceGetInterReferenceIdsINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcMceGetInterReferenceInterlacedFieldPolaritiesINTEL = &Opcode { + Opname: "OpSubgroupAvcMceGetInterReferenceInterlacedFieldPolaritiesINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Packed Reference Ids'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Packed Reference Parameter Field Polarities'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcImeInitializeINTEL = &Opcode { + Opname: "OpSubgroupAvcImeInitializeINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Src Coord'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Partition Mask'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'SAD Adjustment'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcImeSetSingleReferenceINTEL = &Opcode { + Opname: "OpSubgroupAvcImeSetSingleReferenceINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Ref Offset'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Search Window Config'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcImeSetDualReferenceINTEL = &Opcode { + Opname: "OpSubgroupAvcImeSetDualReferenceINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Fwd Ref Offset'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Bwd Ref Offset'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'id> Search Window Config'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcImeRefWindowSizeINTEL = &Opcode { + Opname: "OpSubgroupAvcImeRefWindowSizeINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Search Window Config'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Dual Ref'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcImeAdjustRefOffsetINTEL = &Opcode { + Opname: "OpSubgroupAvcImeAdjustRefOffsetINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Ref Offset'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Src Coord'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Ref Window Size'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Image Size'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcImeConvertToMcePayloadINTEL = &Opcode { + Opname: "OpSubgroupAvcImeConvertToMcePayloadINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcImeSetMaxMotionVectorCountINTEL = &Opcode { + Opname: "OpSubgroupAvcImeSetMaxMotionVectorCountINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Max Motion Vector Count'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcImeSetUnidirectionalMixDisableINTEL = &Opcode { + Opname: "OpSubgroupAvcImeSetUnidirectionalMixDisableINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcImeSetEarlySearchTerminationThresholdINTEL = &Opcode { + Opname: "OpSubgroupAvcImeSetEarlySearchTerminationThresholdINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Threshold'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcImeSetWeightedSadINTEL = &Opcode { + Opname: "OpSubgroupAvcImeSetWeightedSadINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Packed Sad Weights'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcImeEvaluateWithSingleReferenceINTEL = &Opcode { + Opname: "OpSubgroupAvcImeEvaluateWithSingleReferenceINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Src Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Ref Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcImeEvaluateWithDualReferenceINTEL = &Opcode { + Opname: "OpSubgroupAvcImeEvaluateWithDualReferenceINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Src Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Fwd Ref Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Bwd Ref Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcImeEvaluateWithSingleReferenceStreaminINTEL = &Opcode { + Opname: "OpSubgroupAvcImeEvaluateWithSingleReferenceStreaminINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Src Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Ref Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Streamin Components'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcImeEvaluateWithDualReferenceStreaminINTEL = &Opcode { + Opname: "OpSubgroupAvcImeEvaluateWithDualReferenceStreaminINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Src Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Fwd Ref Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Bwd Ref Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Streamin Components'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcImeEvaluateWithSingleReferenceStreamoutINTEL = &Opcode { + Opname: "OpSubgroupAvcImeEvaluateWithSingleReferenceStreamoutINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Src Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Ref Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcImeEvaluateWithDualReferenceStreamoutINTEL = &Opcode { + Opname: "OpSubgroupAvcImeEvaluateWithDualReferenceStreamoutINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Src Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Fwd Ref Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Bwd Ref Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcImeEvaluateWithSingleReferenceStreaminoutINTEL = &Opcode { + Opname: "OpSubgroupAvcImeEvaluateWithSingleReferenceStreaminoutINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Src Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Ref Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Streamin Components'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcImeEvaluateWithDualReferenceStreaminoutINTEL = &Opcode { + Opname: "OpSubgroupAvcImeEvaluateWithDualReferenceStreaminoutINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Src Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Fwd Ref Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Bwd Ref Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Streamin Components'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcImeConvertToMceResultINTEL = &Opcode { + Opname: "OpSubgroupAvcImeConvertToMceResultINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcImeGetSingleReferenceStreaminINTEL = &Opcode { + Opname: "OpSubgroupAvcImeGetSingleReferenceStreaminINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcImeGetDualReferenceStreaminINTEL = &Opcode { + Opname: "OpSubgroupAvcImeGetDualReferenceStreaminINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcImeStripSingleReferenceStreamoutINTEL = &Opcode { + Opname: "OpSubgroupAvcImeStripSingleReferenceStreamoutINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcImeStripDualReferenceStreamoutINTEL = &Opcode { + Opname: "OpSubgroupAvcImeStripDualReferenceStreamoutINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeMotionVectorsINTEL = &Opcode { + Opname: "OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeMotionVectorsINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Major Shape'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeDistortionsINTEL = &Opcode { + Opname: "OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeDistortionsINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Major Shape'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeReferenceIdsINTEL = &Opcode { + Opname: "OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeReferenceIdsINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Major Shape'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeMotionVectorsINTEL = &Opcode { + Opname: "OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeMotionVectorsINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Major Shape'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Direction'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeDistortionsINTEL = &Opcode { + Opname: "OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeDistortionsINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Major Shape'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Direction'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeReferenceIdsINTEL = &Opcode { + Opname: "OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeReferenceIdsINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Major Shape'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Direction'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcImeGetBorderReachedINTEL = &Opcode { + Opname: "OpSubgroupAvcImeGetBorderReachedINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Image Select'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcImeGetTruncatedSearchIndicationINTEL = &Opcode { + Opname: "OpSubgroupAvcImeGetTruncatedSearchIndicationINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcImeGetUnidirectionalEarlySearchTerminationINTEL = &Opcode { + Opname: "OpSubgroupAvcImeGetUnidirectionalEarlySearchTerminationINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcImeGetWeightingPatternMinimumMotionVectorINTEL = &Opcode { + Opname: "OpSubgroupAvcImeGetWeightingPatternMinimumMotionVectorINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcImeGetWeightingPatternMinimumDistortionINTEL = &Opcode { + Opname: "OpSubgroupAvcImeGetWeightingPatternMinimumDistortionINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcFmeInitializeINTEL = &Opcode { + Opname: "OpSubgroupAvcFmeInitializeINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Src Coord'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Motion Vectors'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Major Shapes'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Minor Shapes'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Direction'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Pixel Resolution'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Sad Adjustment'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcBmeInitializeINTEL = &Opcode { + Opname: "OpSubgroupAvcBmeInitializeINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Src Coord'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Motion Vectors'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Major Shapes'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Minor Shapes'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Direction'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Pixel Resolution'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Bidirectional Weight'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Sad Adjustment'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcRefConvertToMcePayloadINTEL = &Opcode { + Opname: "OpSubgroupAvcRefConvertToMcePayloadINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcRefSetBidirectionalMixDisableINTEL = &Opcode { + Opname: "OpSubgroupAvcRefSetBidirectionalMixDisableINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcRefSetBilinearFilterEnableINTEL = &Opcode { + Opname: "OpSubgroupAvcRefSetBilinearFilterEnableINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcRefEvaluateWithSingleReferenceINTEL = &Opcode { + Opname: "OpSubgroupAvcRefEvaluateWithSingleReferenceINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Src Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Ref Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcRefEvaluateWithDualReferenceINTEL = &Opcode { + Opname: "OpSubgroupAvcRefEvaluateWithDualReferenceINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Src Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Fwd Ref Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Bwd Ref Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcRefEvaluateWithMultiReferenceINTEL = &Opcode { + Opname: "OpSubgroupAvcRefEvaluateWithMultiReferenceINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Src Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Packed Reference Ids'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcRefEvaluateWithMultiReferenceInterlacedINTEL = &Opcode { + Opname: "OpSubgroupAvcRefEvaluateWithMultiReferenceInterlacedINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Src Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Packed Reference Ids'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Packed Reference Field Polarities'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcRefConvertToMceResultINTEL = &Opcode { + Opname: "OpSubgroupAvcRefConvertToMceResultINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcSicInitializeINTEL = &Opcode { + Opname: "OpSubgroupAvcSicInitializeINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Src Coord'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcSicConfigureSkcINTEL = &Opcode { + Opname: "OpSubgroupAvcSicConfigureSkcINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Skip Block Partition Type'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Skip Motion Vector Mask'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Motion Vectors'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Bidirectional Weight'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Sad Adjustment'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcSicConfigureIpeLumaINTEL = &Opcode { + Opname: "OpSubgroupAvcSicConfigureIpeLumaINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Luma Intra Partition Mask'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Intra Neighbour Availabilty'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Left Edge Luma Pixels'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Upper Left Corner Luma Pixel'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Upper Edge Luma Pixels'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Upper Right Edge Luma Pixels'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Sad Adjustment'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcSicConfigureIpeLumaChromaINTEL = &Opcode { + Opname: "OpSubgroupAvcSicConfigureIpeLumaChromaINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Luma Intra Partition Mask'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Intra Neighbour Availabilty'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Left Edge Luma Pixels'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Upper Left Corner Luma Pixel'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Upper Edge Luma Pixels'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Upper Right Edge Luma Pixels'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Left Edge Chroma Pixels'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Upper Left Corner Chroma Pixel'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Upper Edge Chroma Pixels'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Sad Adjustment'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcSicGetMotionVectorMaskINTEL = &Opcode { + Opname: "OpSubgroupAvcSicGetMotionVectorMaskINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Skip Block Partition Type'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Direction'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcSicConvertToMcePayloadINTEL = &Opcode { + Opname: "OpSubgroupAvcSicConvertToMcePayloadINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcSicSetIntraLumaShapePenaltyINTEL = &Opcode { + Opname: "OpSubgroupAvcSicSetIntraLumaShapePenaltyINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Packed Shape Penalty'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcSicSetIntraLumaModeCostFunctionINTEL = &Opcode { + Opname: "OpSubgroupAvcSicSetIntraLumaModeCostFunctionINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Luma Mode Penalty'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Luma Packed Neighbor Modes'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Luma Packed Non Dc Penalty'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcSicSetIntraChromaModeCostFunctionINTEL = &Opcode { + Opname: "OpSubgroupAvcSicSetIntraChromaModeCostFunctionINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Chroma Mode Base Penalty'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcSicSetBilinearFilterEnableINTEL = &Opcode { + Opname: "OpSubgroupAvcSicSetBilinearFilterEnableINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcSicSetSkcForwardTransformEnableINTEL = &Opcode { + Opname: "OpSubgroupAvcSicSetSkcForwardTransformEnableINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Packed Sad Coefficients'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcSicSetBlockBasedRawSkipSadINTEL = &Opcode { + Opname: "OpSubgroupAvcSicSetBlockBasedRawSkipSadINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Block Based Skip Type'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcSicEvaluateIpeINTEL = &Opcode { + Opname: "OpSubgroupAvcSicEvaluateIpeINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Src Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcSicEvaluateWithSingleReferenceINTEL = &Opcode { + Opname: "OpSubgroupAvcSicEvaluateWithSingleReferenceINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Src Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Ref Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcSicEvaluateWithDualReferenceINTEL = &Opcode { + Opname: "OpSubgroupAvcSicEvaluateWithDualReferenceINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Src Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Fwd Ref Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Bwd Ref Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcSicEvaluateWithMultiReferenceINTEL = &Opcode { + Opname: "OpSubgroupAvcSicEvaluateWithMultiReferenceINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Src Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Packed Reference Ids'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcSicEvaluateWithMultiReferenceInterlacedINTEL = &Opcode { + Opname: "OpSubgroupAvcSicEvaluateWithMultiReferenceInterlacedINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Src Image'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Packed Reference Ids'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Packed Reference Field Polarities'", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcSicConvertToMceResultINTEL = &Opcode { + Opname: "OpSubgroupAvcSicConvertToMceResultINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcSicGetIpeLumaShapeINTEL = &Opcode { + Opname: "OpSubgroupAvcSicGetIpeLumaShapeINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcSicGetBestIpeLumaDistortionINTEL = &Opcode { + Opname: "OpSubgroupAvcSicGetBestIpeLumaDistortionINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcSicGetBestIpeChromaDistortionINTEL = &Opcode { + Opname: "OpSubgroupAvcSicGetBestIpeChromaDistortionINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcSicGetPackedIpeLumaModesINTEL = &Opcode { + Opname: "OpSubgroupAvcSicGetPackedIpeLumaModesINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcSicGetIpeChromaModeINTEL = &Opcode { + Opname: "OpSubgroupAvcSicGetIpeChromaModeINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcSicGetPackedSkcLumaCountThresholdINTEL = &Opcode { + Opname: "OpSubgroupAvcSicGetPackedSkcLumaCountThresholdINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcSicGetPackedSkcLumaSumThresholdINTEL = &Opcode { + Opname: "OpSubgroupAvcSicGetPackedSkcLumaSumThresholdINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + OpSubgroupAvcSicGetInterRawSadsINTEL = &Opcode { + Opname: "OpSubgroupAvcSicGetInterRawSadsINTEL", + Operands: []Operand { + Operand { + Kind: OperandKindIdResultType, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdResult, + Name: "", + Quantifier: "", + }, + Operand { + Kind: OperandKindIdRef, + Name: "'Payload'", + Quantifier: "", + }, + }, + } + + + OperandKindImageOperands = &OperandKind { + Kind: "ImageOperands", + Category: "BitEnum", + Enumerants: []Enumerant { + Enumerant{ + Enumerant: "None", + Value: 0x0000, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Bias", + Value: 0x0001, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{{OperandKindIdRef, ""},}, + Version: "", + }, + Enumerant{ + Enumerant: "Lod", + Value: 0x0002, + Capabilities: []string{}, + Parameters: []Parameter{{OperandKindIdRef, ""},}, + Version: "", + }, + Enumerant{ + Enumerant: "Grad", + Value: 0x0004, + Capabilities: []string{}, + Parameters: []Parameter{{OperandKindIdRef, ""},{OperandKindIdRef, ""},}, + Version: "", + }, + Enumerant{ + Enumerant: "ConstOffset", + Value: 0x0008, + Capabilities: []string{}, + Parameters: []Parameter{{OperandKindIdRef, ""},}, + Version: "", + }, + Enumerant{ + Enumerant: "Offset", + Value: 0x0010, + Capabilities: []string{"ImageGatherExtended",}, + Parameters: []Parameter{{OperandKindIdRef, ""},}, + Version: "", + }, + Enumerant{ + Enumerant: "ConstOffsets", + Value: 0x0020, + Capabilities: []string{"ImageGatherExtended",}, + Parameters: []Parameter{{OperandKindIdRef, ""},}, + Version: "", + }, + Enumerant{ + Enumerant: "Sample", + Value: 0x0040, + Capabilities: []string{}, + Parameters: []Parameter{{OperandKindIdRef, ""},}, + Version: "", + }, + Enumerant{ + Enumerant: "MinLod", + Value: 0x0080, + Capabilities: []string{"MinLod",}, + Parameters: []Parameter{{OperandKindIdRef, ""},}, + Version: "", + }, + Enumerant{ + Enumerant: "MakeTexelAvailable", + Value: 0x0100, + Capabilities: []string{"VulkanMemoryModel",}, + Parameters: []Parameter{{OperandKindIdScope, ""},}, + Version: "1.5", + }, + Enumerant{ + Enumerant: "MakeTexelAvailableKHR", + Value: 0x0100, + Capabilities: []string{"VulkanMemoryModel",}, + Parameters: []Parameter{{OperandKindIdScope, ""},}, + Version: "1.5", + }, + Enumerant{ + Enumerant: "MakeTexelVisible", + Value: 0x0200, + Capabilities: []string{"VulkanMemoryModel",}, + Parameters: []Parameter{{OperandKindIdScope, ""},}, + Version: "1.5", + }, + Enumerant{ + Enumerant: "MakeTexelVisibleKHR", + Value: 0x0200, + Capabilities: []string{"VulkanMemoryModel",}, + Parameters: []Parameter{{OperandKindIdScope, ""},}, + Version: "1.5", + }, + Enumerant{ + Enumerant: "NonPrivateTexel", + Value: 0x0400, + Capabilities: []string{"VulkanMemoryModel",}, + Parameters: []Parameter{}, + Version: "1.5", + }, + Enumerant{ + Enumerant: "NonPrivateTexelKHR", + Value: 0x0400, + Capabilities: []string{"VulkanMemoryModel",}, + Parameters: []Parameter{}, + Version: "1.5", + }, + Enumerant{ + Enumerant: "VolatileTexel", + Value: 0x0800, + Capabilities: []string{"VulkanMemoryModel",}, + Parameters: []Parameter{}, + Version: "1.5", + }, + Enumerant{ + Enumerant: "VolatileTexelKHR", + Value: 0x0800, + Capabilities: []string{"VulkanMemoryModel",}, + Parameters: []Parameter{}, + Version: "1.5", + }, + Enumerant{ + Enumerant: "SignExtend", + Value: 0x1000, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "1.4", + }, + Enumerant{ + Enumerant: "ZeroExtend", + Value: 0x2000, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "1.4", + }, + }, + Bases: []*OperandKind {}, + } + OperandKindFPFastMathMode = &OperandKind { + Kind: "FPFastMathMode", + Category: "BitEnum", + Enumerants: []Enumerant { + Enumerant{ + Enumerant: "None", + Value: 0x0000, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "NotNaN", + Value: 0x0001, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "NotInf", + Value: 0x0002, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "NSZ", + Value: 0x0004, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "AllowRecip", + Value: 0x0008, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Fast", + Value: 0x0010, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + }, + Bases: []*OperandKind {}, + } + OperandKindSelectionControl = &OperandKind { + Kind: "SelectionControl", + Category: "BitEnum", + Enumerants: []Enumerant { + Enumerant{ + Enumerant: "None", + Value: 0x0000, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Flatten", + Value: 0x0001, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "DontFlatten", + Value: 0x0002, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + }, + Bases: []*OperandKind {}, + } + OperandKindLoopControl = &OperandKind { + Kind: "LoopControl", + Category: "BitEnum", + Enumerants: []Enumerant { + Enumerant{ + Enumerant: "None", + Value: 0x0000, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Unroll", + Value: 0x0001, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "DontUnroll", + Value: 0x0002, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "DependencyInfinite", + Value: 0x0004, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "1.1", + }, + Enumerant{ + Enumerant: "DependencyLength", + Value: 0x0008, + Capabilities: []string{}, + Parameters: []Parameter{{OperandKindLiteralInteger, ""},}, + Version: "1.1", + }, + Enumerant{ + Enumerant: "MinIterations", + Value: 0x0010, + Capabilities: []string{}, + Parameters: []Parameter{{OperandKindLiteralInteger, ""},}, + Version: "1.4", + }, + Enumerant{ + Enumerant: "MaxIterations", + Value: 0x0020, + Capabilities: []string{}, + Parameters: []Parameter{{OperandKindLiteralInteger, ""},}, + Version: "1.4", + }, + Enumerant{ + Enumerant: "IterationMultiple", + Value: 0x0040, + Capabilities: []string{}, + Parameters: []Parameter{{OperandKindLiteralInteger, ""},}, + Version: "1.4", + }, + Enumerant{ + Enumerant: "PeelCount", + Value: 0x0080, + Capabilities: []string{}, + Parameters: []Parameter{{OperandKindLiteralInteger, ""},}, + Version: "1.4", + }, + Enumerant{ + Enumerant: "PartialCount", + Value: 0x0100, + Capabilities: []string{}, + Parameters: []Parameter{{OperandKindLiteralInteger, ""},}, + Version: "1.4", + }, + }, + Bases: []*OperandKind {}, + } + OperandKindFunctionControl = &OperandKind { + Kind: "FunctionControl", + Category: "BitEnum", + Enumerants: []Enumerant { + Enumerant{ + Enumerant: "None", + Value: 0x0000, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Inline", + Value: 0x0001, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "DontInline", + Value: 0x0002, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Pure", + Value: 0x0004, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Const", + Value: 0x0008, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + }, + Bases: []*OperandKind {}, + } + OperandKindMemorySemantics = &OperandKind { + Kind: "MemorySemantics", + Category: "BitEnum", + Enumerants: []Enumerant { + Enumerant{ + Enumerant: "Relaxed", + Value: 0x0000, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "None", + Value: 0x0000, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Acquire", + Value: 0x0002, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Release", + Value: 0x0004, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "AcquireRelease", + Value: 0x0008, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "SequentiallyConsistent", + Value: 0x0010, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "UniformMemory", + Value: 0x0040, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "SubgroupMemory", + Value: 0x0080, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "WorkgroupMemory", + Value: 0x0100, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "CrossWorkgroupMemory", + Value: 0x0200, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "AtomicCounterMemory", + Value: 0x0400, + Capabilities: []string{"AtomicStorage",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "ImageMemory", + Value: 0x0800, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "OutputMemory", + Value: 0x1000, + Capabilities: []string{"VulkanMemoryModel",}, + Parameters: []Parameter{}, + Version: "1.5", + }, + Enumerant{ + Enumerant: "OutputMemoryKHR", + Value: 0x1000, + Capabilities: []string{"VulkanMemoryModel",}, + Parameters: []Parameter{}, + Version: "1.5", + }, + Enumerant{ + Enumerant: "MakeAvailable", + Value: 0x2000, + Capabilities: []string{"VulkanMemoryModel",}, + Parameters: []Parameter{}, + Version: "1.5", + }, + Enumerant{ + Enumerant: "MakeAvailableKHR", + Value: 0x2000, + Capabilities: []string{"VulkanMemoryModel",}, + Parameters: []Parameter{}, + Version: "1.5", + }, + Enumerant{ + Enumerant: "MakeVisible", + Value: 0x4000, + Capabilities: []string{"VulkanMemoryModel",}, + Parameters: []Parameter{}, + Version: "1.5", + }, + Enumerant{ + Enumerant: "MakeVisibleKHR", + Value: 0x4000, + Capabilities: []string{"VulkanMemoryModel",}, + Parameters: []Parameter{}, + Version: "1.5", + }, + Enumerant{ + Enumerant: "Volatile", + Value: 0x8000, + Capabilities: []string{"VulkanMemoryModel",}, + Parameters: []Parameter{}, + Version: "1.5", + }, + }, + Bases: []*OperandKind {}, + } + OperandKindMemoryAccess = &OperandKind { + Kind: "MemoryAccess", + Category: "BitEnum", + Enumerants: []Enumerant { + Enumerant{ + Enumerant: "None", + Value: 0x0000, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Volatile", + Value: 0x0001, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Aligned", + Value: 0x0002, + Capabilities: []string{}, + Parameters: []Parameter{{OperandKindLiteralInteger, ""},}, + Version: "", + }, + Enumerant{ + Enumerant: "Nontemporal", + Value: 0x0004, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "MakePointerAvailable", + Value: 0x0008, + Capabilities: []string{"VulkanMemoryModel",}, + Parameters: []Parameter{{OperandKindIdScope, ""},}, + Version: "1.5", + }, + Enumerant{ + Enumerant: "MakePointerAvailableKHR", + Value: 0x0008, + Capabilities: []string{"VulkanMemoryModel",}, + Parameters: []Parameter{{OperandKindIdScope, ""},}, + Version: "1.5", + }, + Enumerant{ + Enumerant: "MakePointerVisible", + Value: 0x0010, + Capabilities: []string{"VulkanMemoryModel",}, + Parameters: []Parameter{{OperandKindIdScope, ""},}, + Version: "1.5", + }, + Enumerant{ + Enumerant: "MakePointerVisibleKHR", + Value: 0x0010, + Capabilities: []string{"VulkanMemoryModel",}, + Parameters: []Parameter{{OperandKindIdScope, ""},}, + Version: "1.5", + }, + Enumerant{ + Enumerant: "NonPrivatePointer", + Value: 0x0020, + Capabilities: []string{"VulkanMemoryModel",}, + Parameters: []Parameter{}, + Version: "1.5", + }, + Enumerant{ + Enumerant: "NonPrivatePointerKHR", + Value: 0x0020, + Capabilities: []string{"VulkanMemoryModel",}, + Parameters: []Parameter{}, + Version: "1.5", + }, + }, + Bases: []*OperandKind {}, + } + OperandKindKernelProfilingInfo = &OperandKind { + Kind: "KernelProfilingInfo", + Category: "BitEnum", + Enumerants: []Enumerant { + Enumerant{ + Enumerant: "None", + Value: 0x0000, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "CmdExecTime", + Value: 0x0001, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + }, + Bases: []*OperandKind {}, + } + OperandKindSourceLanguage = &OperandKind { + Kind: "SourceLanguage", + Category: "ValueEnum", + Enumerants: []Enumerant { + Enumerant{ + Enumerant: "Unknown", + Value: 0, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "ESSL", + Value: 1, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "GLSL", + Value: 2, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "OpenCL_C", + Value: 3, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "OpenCL_CPP", + Value: 4, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "HLSL", + Value: 5, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + }, + Bases: []*OperandKind {}, + } + OperandKindExecutionModel = &OperandKind { + Kind: "ExecutionModel", + Category: "ValueEnum", + Enumerants: []Enumerant { + Enumerant{ + Enumerant: "Vertex", + Value: 0, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "TessellationControl", + Value: 1, + Capabilities: []string{"Tessellation",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "TessellationEvaluation", + Value: 2, + Capabilities: []string{"Tessellation",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Geometry", + Value: 3, + Capabilities: []string{"Geometry",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Fragment", + Value: 4, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "GLCompute", + Value: 5, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Kernel", + Value: 6, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "TaskNV", + Value: 5267, + Capabilities: []string{"MeshShadingNV",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "MeshNV", + Value: 5268, + Capabilities: []string{"MeshShadingNV",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "RayGenerationNV", + Value: 5313, + Capabilities: []string{"RayTracingNV",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "IntersectionNV", + Value: 5314, + Capabilities: []string{"RayTracingNV",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "AnyHitNV", + Value: 5315, + Capabilities: []string{"RayTracingNV",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "ClosestHitNV", + Value: 5316, + Capabilities: []string{"RayTracingNV",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "MissNV", + Value: 5317, + Capabilities: []string{"RayTracingNV",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "CallableNV", + Value: 5318, + Capabilities: []string{"RayTracingNV",}, + Parameters: []Parameter{}, + Version: "None", + }, + }, + Bases: []*OperandKind {}, + } + OperandKindAddressingModel = &OperandKind { + Kind: "AddressingModel", + Category: "ValueEnum", + Enumerants: []Enumerant { + Enumerant{ + Enumerant: "Logical", + Value: 0, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Physical32", + Value: 1, + Capabilities: []string{"Addresses",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Physical64", + Value: 2, + Capabilities: []string{"Addresses",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "PhysicalStorageBuffer64", + Value: 5348, + Capabilities: []string{"PhysicalStorageBufferAddresses",}, + Parameters: []Parameter{}, + Version: "1.5", + }, + Enumerant{ + Enumerant: "PhysicalStorageBuffer64EXT", + Value: 5348, + Capabilities: []string{"PhysicalStorageBufferAddresses",}, + Parameters: []Parameter{}, + Version: "1.5", + }, + }, + Bases: []*OperandKind {}, + } + OperandKindMemoryModel = &OperandKind { + Kind: "MemoryModel", + Category: "ValueEnum", + Enumerants: []Enumerant { + Enumerant{ + Enumerant: "Simple", + Value: 0, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "GLSL450", + Value: 1, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "OpenCL", + Value: 2, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Vulkan", + Value: 3, + Capabilities: []string{"VulkanMemoryModel",}, + Parameters: []Parameter{}, + Version: "1.5", + }, + Enumerant{ + Enumerant: "VulkanKHR", + Value: 3, + Capabilities: []string{"VulkanMemoryModel",}, + Parameters: []Parameter{}, + Version: "1.5", + }, + }, + Bases: []*OperandKind {}, + } + OperandKindExecutionMode = &OperandKind { + Kind: "ExecutionMode", + Category: "ValueEnum", + Enumerants: []Enumerant { + Enumerant{ + Enumerant: "Invocations", + Value: 0, + Capabilities: []string{"Geometry",}, + Parameters: []Parameter{{OperandKindLiteralInteger, "'Number of <>'"},}, + Version: "", + }, + Enumerant{ + Enumerant: "SpacingEqual", + Value: 1, + Capabilities: []string{"Tessellation",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "SpacingFractionalEven", + Value: 2, + Capabilities: []string{"Tessellation",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "SpacingFractionalOdd", + Value: 3, + Capabilities: []string{"Tessellation",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "VertexOrderCw", + Value: 4, + Capabilities: []string{"Tessellation",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "VertexOrderCcw", + Value: 5, + Capabilities: []string{"Tessellation",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "PixelCenterInteger", + Value: 6, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "OriginUpperLeft", + Value: 7, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "OriginLowerLeft", + Value: 8, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "EarlyFragmentTests", + Value: 9, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "PointMode", + Value: 10, + Capabilities: []string{"Tessellation",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Xfb", + Value: 11, + Capabilities: []string{"TransformFeedback",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "DepthReplacing", + Value: 12, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "DepthGreater", + Value: 14, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "DepthLess", + Value: 15, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "DepthUnchanged", + Value: 16, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "LocalSize", + Value: 17, + Capabilities: []string{}, + Parameters: []Parameter{{OperandKindLiteralInteger, "'x size'"},{OperandKindLiteralInteger, "'y size'"},{OperandKindLiteralInteger, "'z size'"},}, + Version: "", + }, + Enumerant{ + Enumerant: "LocalSizeHint", + Value: 18, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{{OperandKindLiteralInteger, "'x size'"},{OperandKindLiteralInteger, "'y size'"},{OperandKindLiteralInteger, "'z size'"},}, + Version: "", + }, + Enumerant{ + Enumerant: "InputPoints", + Value: 19, + Capabilities: []string{"Geometry",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "InputLines", + Value: 20, + Capabilities: []string{"Geometry",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "InputLinesAdjacency", + Value: 21, + Capabilities: []string{"Geometry",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Triangles", + Value: 22, + Capabilities: []string{"Geometry","Tessellation",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "InputTrianglesAdjacency", + Value: 23, + Capabilities: []string{"Geometry",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Quads", + Value: 24, + Capabilities: []string{"Tessellation",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Isolines", + Value: 25, + Capabilities: []string{"Tessellation",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "OutputVertices", + Value: 26, + Capabilities: []string{"Geometry","Tessellation","MeshShadingNV",}, + Parameters: []Parameter{{OperandKindLiteralInteger, "'Vertex count'"},}, + Version: "", + }, + Enumerant{ + Enumerant: "OutputPoints", + Value: 27, + Capabilities: []string{"Geometry","MeshShadingNV",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "OutputLineStrip", + Value: 28, + Capabilities: []string{"Geometry",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "OutputTriangleStrip", + Value: 29, + Capabilities: []string{"Geometry",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "VecTypeHint", + Value: 30, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{{OperandKindLiteralInteger, "'Vector type'"},}, + Version: "", + }, + Enumerant{ + Enumerant: "ContractionOff", + Value: 31, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Initializer", + Value: 33, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "1.1", + }, + Enumerant{ + Enumerant: "Finalizer", + Value: 34, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "1.1", + }, + Enumerant{ + Enumerant: "SubgroupSize", + Value: 35, + Capabilities: []string{"SubgroupDispatch",}, + Parameters: []Parameter{{OperandKindLiteralInteger, "'Subgroup Size'"},}, + Version: "1.1", + }, + Enumerant{ + Enumerant: "SubgroupsPerWorkgroup", + Value: 36, + Capabilities: []string{"SubgroupDispatch",}, + Parameters: []Parameter{{OperandKindLiteralInteger, "'Subgroups Per Workgroup'"},}, + Version: "1.1", + }, + Enumerant{ + Enumerant: "SubgroupsPerWorkgroupId", + Value: 37, + Capabilities: []string{"SubgroupDispatch",}, + Parameters: []Parameter{{OperandKindIdRef, "'Subgroups Per Workgroup'"},}, + Version: "1.2", + }, + Enumerant{ + Enumerant: "LocalSizeId", + Value: 38, + Capabilities: []string{}, + Parameters: []Parameter{{OperandKindIdRef, "'x size'"},{OperandKindIdRef, "'y size'"},{OperandKindIdRef, "'z size'"},}, + Version: "1.2", + }, + Enumerant{ + Enumerant: "LocalSizeHintId", + Value: 39, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{{OperandKindIdRef, "'Local Size Hint'"},}, + Version: "1.2", + }, + Enumerant{ + Enumerant: "PostDepthCoverage", + Value: 4446, + Capabilities: []string{"SampleMaskPostDepthCoverage",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "DenormPreserve", + Value: 4459, + Capabilities: []string{"DenormPreserve",}, + Parameters: []Parameter{{OperandKindLiteralInteger, "'Target Width'"},}, + Version: "1.4", + }, + Enumerant{ + Enumerant: "DenormFlushToZero", + Value: 4460, + Capabilities: []string{"DenormFlushToZero",}, + Parameters: []Parameter{{OperandKindLiteralInteger, "'Target Width'"},}, + Version: "1.4", + }, + Enumerant{ + Enumerant: "SignedZeroInfNanPreserve", + Value: 4461, + Capabilities: []string{"SignedZeroInfNanPreserve",}, + Parameters: []Parameter{{OperandKindLiteralInteger, "'Target Width'"},}, + Version: "1.4", + }, + Enumerant{ + Enumerant: "RoundingModeRTE", + Value: 4462, + Capabilities: []string{"RoundingModeRTE",}, + Parameters: []Parameter{{OperandKindLiteralInteger, "'Target Width'"},}, + Version: "1.4", + }, + Enumerant{ + Enumerant: "RoundingModeRTZ", + Value: 4463, + Capabilities: []string{"RoundingModeRTZ",}, + Parameters: []Parameter{{OperandKindLiteralInteger, "'Target Width'"},}, + Version: "1.4", + }, + Enumerant{ + Enumerant: "StencilRefReplacingEXT", + Value: 5027, + Capabilities: []string{"StencilExportEXT",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "OutputLinesNV", + Value: 5269, + Capabilities: []string{"MeshShadingNV",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "OutputPrimitivesNV", + Value: 5270, + Capabilities: []string{"MeshShadingNV",}, + Parameters: []Parameter{{OperandKindLiteralInteger, "'Primitive count'"},}, + Version: "None", + }, + Enumerant{ + Enumerant: "DerivativeGroupQuadsNV", + Value: 5289, + Capabilities: []string{"ComputeDerivativeGroupQuadsNV",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "DerivativeGroupLinearNV", + Value: 5290, + Capabilities: []string{"ComputeDerivativeGroupLinearNV",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "OutputTrianglesNV", + Value: 5298, + Capabilities: []string{"MeshShadingNV",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "PixelInterlockOrderedEXT", + Value: 5366, + Capabilities: []string{"FragmentShaderPixelInterlockEXT",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "PixelInterlockUnorderedEXT", + Value: 5367, + Capabilities: []string{"FragmentShaderPixelInterlockEXT",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "SampleInterlockOrderedEXT", + Value: 5368, + Capabilities: []string{"FragmentShaderSampleInterlockEXT",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "SampleInterlockUnorderedEXT", + Value: 5369, + Capabilities: []string{"FragmentShaderSampleInterlockEXT",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "ShadingRateInterlockOrderedEXT", + Value: 5370, + Capabilities: []string{"FragmentShaderShadingRateInterlockEXT",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "ShadingRateInterlockUnorderedEXT", + Value: 5371, + Capabilities: []string{"FragmentShaderShadingRateInterlockEXT",}, + Parameters: []Parameter{}, + Version: "None", + }, + }, + Bases: []*OperandKind {}, + } + OperandKindStorageClass = &OperandKind { + Kind: "StorageClass", + Category: "ValueEnum", + Enumerants: []Enumerant { + Enumerant{ + Enumerant: "UniformConstant", + Value: 0, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Input", + Value: 1, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Uniform", + Value: 2, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Output", + Value: 3, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Workgroup", + Value: 4, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "CrossWorkgroup", + Value: 5, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Private", + Value: 6, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Function", + Value: 7, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Generic", + Value: 8, + Capabilities: []string{"GenericPointer",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "PushConstant", + Value: 9, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "AtomicCounter", + Value: 10, + Capabilities: []string{"AtomicStorage",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Image", + Value: 11, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "StorageBuffer", + Value: 12, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "1.3", + }, + Enumerant{ + Enumerant: "CallableDataNV", + Value: 5328, + Capabilities: []string{"RayTracingNV",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "IncomingCallableDataNV", + Value: 5329, + Capabilities: []string{"RayTracingNV",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "RayPayloadNV", + Value: 5338, + Capabilities: []string{"RayTracingNV",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "HitAttributeNV", + Value: 5339, + Capabilities: []string{"RayTracingNV",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "IncomingRayPayloadNV", + Value: 5342, + Capabilities: []string{"RayTracingNV",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "ShaderRecordBufferNV", + Value: 5343, + Capabilities: []string{"RayTracingNV",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "PhysicalStorageBuffer", + Value: 5349, + Capabilities: []string{"PhysicalStorageBufferAddresses",}, + Parameters: []Parameter{}, + Version: "1.5", + }, + Enumerant{ + Enumerant: "PhysicalStorageBufferEXT", + Value: 5349, + Capabilities: []string{"PhysicalStorageBufferAddresses",}, + Parameters: []Parameter{}, + Version: "1.5", + }, + }, + Bases: []*OperandKind {}, + } + OperandKindDim = &OperandKind { + Kind: "Dim", + Category: "ValueEnum", + Enumerants: []Enumerant { + Enumerant{ + Enumerant: "1D", + Value: 0, + Capabilities: []string{"Sampled1D","Image1D",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "2D", + Value: 1, + Capabilities: []string{"Shader","Kernel","ImageMSArray",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "3D", + Value: 2, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Cube", + Value: 3, + Capabilities: []string{"Shader","ImageCubeArray",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Rect", + Value: 4, + Capabilities: []string{"SampledRect","ImageRect",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Buffer", + Value: 5, + Capabilities: []string{"SampledBuffer","ImageBuffer",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "SubpassData", + Value: 6, + Capabilities: []string{"InputAttachment",}, + Parameters: []Parameter{}, + Version: "", + }, + }, + Bases: []*OperandKind {}, + } + OperandKindSamplerAddressingMode = &OperandKind { + Kind: "SamplerAddressingMode", + Category: "ValueEnum", + Enumerants: []Enumerant { + Enumerant{ + Enumerant: "None", + Value: 0, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "ClampToEdge", + Value: 1, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Clamp", + Value: 2, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Repeat", + Value: 3, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "RepeatMirrored", + Value: 4, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + }, + Bases: []*OperandKind {}, + } + OperandKindSamplerFilterMode = &OperandKind { + Kind: "SamplerFilterMode", + Category: "ValueEnum", + Enumerants: []Enumerant { + Enumerant{ + Enumerant: "Nearest", + Value: 0, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Linear", + Value: 1, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + }, + Bases: []*OperandKind {}, + } + OperandKindImageFormat = &OperandKind { + Kind: "ImageFormat", + Category: "ValueEnum", + Enumerants: []Enumerant { + Enumerant{ + Enumerant: "Unknown", + Value: 0, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Rgba32f", + Value: 1, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Rgba16f", + Value: 2, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "R32f", + Value: 3, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Rgba8", + Value: 4, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Rgba8Snorm", + Value: 5, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Rg32f", + Value: 6, + Capabilities: []string{"StorageImageExtendedFormats",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Rg16f", + Value: 7, + Capabilities: []string{"StorageImageExtendedFormats",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "R11fG11fB10f", + Value: 8, + Capabilities: []string{"StorageImageExtendedFormats",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "R16f", + Value: 9, + Capabilities: []string{"StorageImageExtendedFormats",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Rgba16", + Value: 10, + Capabilities: []string{"StorageImageExtendedFormats",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Rgb10A2", + Value: 11, + Capabilities: []string{"StorageImageExtendedFormats",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Rg16", + Value: 12, + Capabilities: []string{"StorageImageExtendedFormats",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Rg8", + Value: 13, + Capabilities: []string{"StorageImageExtendedFormats",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "R16", + Value: 14, + Capabilities: []string{"StorageImageExtendedFormats",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "R8", + Value: 15, + Capabilities: []string{"StorageImageExtendedFormats",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Rgba16Snorm", + Value: 16, + Capabilities: []string{"StorageImageExtendedFormats",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Rg16Snorm", + Value: 17, + Capabilities: []string{"StorageImageExtendedFormats",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Rg8Snorm", + Value: 18, + Capabilities: []string{"StorageImageExtendedFormats",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "R16Snorm", + Value: 19, + Capabilities: []string{"StorageImageExtendedFormats",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "R8Snorm", + Value: 20, + Capabilities: []string{"StorageImageExtendedFormats",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Rgba32i", + Value: 21, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Rgba16i", + Value: 22, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Rgba8i", + Value: 23, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "R32i", + Value: 24, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Rg32i", + Value: 25, + Capabilities: []string{"StorageImageExtendedFormats",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Rg16i", + Value: 26, + Capabilities: []string{"StorageImageExtendedFormats",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Rg8i", + Value: 27, + Capabilities: []string{"StorageImageExtendedFormats",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "R16i", + Value: 28, + Capabilities: []string{"StorageImageExtendedFormats",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "R8i", + Value: 29, + Capabilities: []string{"StorageImageExtendedFormats",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Rgba32ui", + Value: 30, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Rgba16ui", + Value: 31, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Rgba8ui", + Value: 32, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "R32ui", + Value: 33, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Rgb10a2ui", + Value: 34, + Capabilities: []string{"StorageImageExtendedFormats",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Rg32ui", + Value: 35, + Capabilities: []string{"StorageImageExtendedFormats",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Rg16ui", + Value: 36, + Capabilities: []string{"StorageImageExtendedFormats",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Rg8ui", + Value: 37, + Capabilities: []string{"StorageImageExtendedFormats",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "R16ui", + Value: 38, + Capabilities: []string{"StorageImageExtendedFormats",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "R8ui", + Value: 39, + Capabilities: []string{"StorageImageExtendedFormats",}, + Parameters: []Parameter{}, + Version: "", + }, + }, + Bases: []*OperandKind {}, + } + OperandKindImageChannelOrder = &OperandKind { + Kind: "ImageChannelOrder", + Category: "ValueEnum", + Enumerants: []Enumerant { + Enumerant{ + Enumerant: "R", + Value: 0, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "A", + Value: 1, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "RG", + Value: 2, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "RA", + Value: 3, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "RGB", + Value: 4, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "RGBA", + Value: 5, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "BGRA", + Value: 6, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "ARGB", + Value: 7, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Intensity", + Value: 8, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Luminance", + Value: 9, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Rx", + Value: 10, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "RGx", + Value: 11, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "RGBx", + Value: 12, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Depth", + Value: 13, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "DepthStencil", + Value: 14, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "sRGB", + Value: 15, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "sRGBx", + Value: 16, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "sRGBA", + Value: 17, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "sBGRA", + Value: 18, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "ABGR", + Value: 19, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + }, + Bases: []*OperandKind {}, + } + OperandKindImageChannelDataType = &OperandKind { + Kind: "ImageChannelDataType", + Category: "ValueEnum", + Enumerants: []Enumerant { + Enumerant{ + Enumerant: "SnormInt8", + Value: 0, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "SnormInt16", + Value: 1, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "UnormInt8", + Value: 2, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "UnormInt16", + Value: 3, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "UnormShort565", + Value: 4, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "UnormShort555", + Value: 5, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "UnormInt101010", + Value: 6, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "SignedInt8", + Value: 7, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "SignedInt16", + Value: 8, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "SignedInt32", + Value: 9, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "UnsignedInt8", + Value: 10, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "UnsignedInt16", + Value: 11, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "UnsignedInt32", + Value: 12, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "HalfFloat", + Value: 13, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Float", + Value: 14, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "UnormInt24", + Value: 15, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "UnormInt101010_2", + Value: 16, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + }, + Bases: []*OperandKind {}, + } + OperandKindFPRoundingMode = &OperandKind { + Kind: "FPRoundingMode", + Category: "ValueEnum", + Enumerants: []Enumerant { + Enumerant{ + Enumerant: "RTE", + Value: 0, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "RTZ", + Value: 1, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "RTP", + Value: 2, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "RTN", + Value: 3, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + }, + Bases: []*OperandKind {}, + } + OperandKindLinkageType = &OperandKind { + Kind: "LinkageType", + Category: "ValueEnum", + Enumerants: []Enumerant { + Enumerant{ + Enumerant: "Export", + Value: 0, + Capabilities: []string{"Linkage",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Import", + Value: 1, + Capabilities: []string{"Linkage",}, + Parameters: []Parameter{}, + Version: "", + }, + }, + Bases: []*OperandKind {}, + } + OperandKindAccessQualifier = &OperandKind { + Kind: "AccessQualifier", + Category: "ValueEnum", + Enumerants: []Enumerant { + Enumerant{ + Enumerant: "ReadOnly", + Value: 0, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "WriteOnly", + Value: 1, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "ReadWrite", + Value: 2, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + }, + Bases: []*OperandKind {}, + } + OperandKindFunctionParameterAttribute = &OperandKind { + Kind: "FunctionParameterAttribute", + Category: "ValueEnum", + Enumerants: []Enumerant { + Enumerant{ + Enumerant: "Zext", + Value: 0, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Sext", + Value: 1, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "ByVal", + Value: 2, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Sret", + Value: 3, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "NoAlias", + Value: 4, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "NoCapture", + Value: 5, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "NoWrite", + Value: 6, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "NoReadWrite", + Value: 7, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + }, + Bases: []*OperandKind {}, + } + OperandKindDecoration = &OperandKind { + Kind: "Decoration", + Category: "ValueEnum", + Enumerants: []Enumerant { + Enumerant{ + Enumerant: "RelaxedPrecision", + Value: 0, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "SpecId", + Value: 1, + Capabilities: []string{"Shader","Kernel",}, + Parameters: []Parameter{{OperandKindLiteralInteger, "'Specialization Constant ID'"},}, + Version: "", + }, + Enumerant{ + Enumerant: "Block", + Value: 2, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "BufferBlock", + Value: 3, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "RowMajor", + Value: 4, + Capabilities: []string{"Matrix",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "ColMajor", + Value: 5, + Capabilities: []string{"Matrix",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "ArrayStride", + Value: 6, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{{OperandKindLiteralInteger, "'Array Stride'"},}, + Version: "", + }, + Enumerant{ + Enumerant: "MatrixStride", + Value: 7, + Capabilities: []string{"Matrix",}, + Parameters: []Parameter{{OperandKindLiteralInteger, "'Matrix Stride'"},}, + Version: "", + }, + Enumerant{ + Enumerant: "GLSLShared", + Value: 8, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "GLSLPacked", + Value: 9, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "CPacked", + Value: 10, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "BuiltIn", + Value: 11, + Capabilities: []string{}, + Parameters: []Parameter{{OperandKindBuiltIn, ""},}, + Version: "", + }, + Enumerant{ + Enumerant: "NoPerspective", + Value: 13, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Flat", + Value: 14, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Patch", + Value: 15, + Capabilities: []string{"Tessellation",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Centroid", + Value: 16, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Sample", + Value: 17, + Capabilities: []string{"SampleRateShading",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Invariant", + Value: 18, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Restrict", + Value: 19, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Aliased", + Value: 20, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Volatile", + Value: 21, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Constant", + Value: 22, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Coherent", + Value: 23, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "NonWritable", + Value: 24, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "NonReadable", + Value: 25, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Uniform", + Value: 26, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "UniformId", + Value: 27, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{{OperandKindIdScope, "'Execution'"},}, + Version: "1.4", + }, + Enumerant{ + Enumerant: "SaturatedConversion", + Value: 28, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Stream", + Value: 29, + Capabilities: []string{"GeometryStreams",}, + Parameters: []Parameter{{OperandKindLiteralInteger, "'Stream Number'"},}, + Version: "", + }, + Enumerant{ + Enumerant: "Location", + Value: 30, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{{OperandKindLiteralInteger, "'Location'"},}, + Version: "", + }, + Enumerant{ + Enumerant: "Component", + Value: 31, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{{OperandKindLiteralInteger, "'Component'"},}, + Version: "", + }, + Enumerant{ + Enumerant: "Index", + Value: 32, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{{OperandKindLiteralInteger, "'Index'"},}, + Version: "", + }, + Enumerant{ + Enumerant: "Binding", + Value: 33, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{{OperandKindLiteralInteger, "'Binding Point'"},}, + Version: "", + }, + Enumerant{ + Enumerant: "DescriptorSet", + Value: 34, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{{OperandKindLiteralInteger, "'Descriptor Set'"},}, + Version: "", + }, + Enumerant{ + Enumerant: "Offset", + Value: 35, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{{OperandKindLiteralInteger, "'Byte Offset'"},}, + Version: "", + }, + Enumerant{ + Enumerant: "XfbBuffer", + Value: 36, + Capabilities: []string{"TransformFeedback",}, + Parameters: []Parameter{{OperandKindLiteralInteger, "'XFB Buffer Number'"},}, + Version: "", + }, + Enumerant{ + Enumerant: "XfbStride", + Value: 37, + Capabilities: []string{"TransformFeedback",}, + Parameters: []Parameter{{OperandKindLiteralInteger, "'XFB Stride'"},}, + Version: "", + }, + Enumerant{ + Enumerant: "FuncParamAttr", + Value: 38, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{{OperandKindFunctionParameterAttribute, "'Function Parameter Attribute'"},}, + Version: "", + }, + Enumerant{ + Enumerant: "FPRoundingMode", + Value: 39, + Capabilities: []string{}, + Parameters: []Parameter{{OperandKindFPRoundingMode, "'Floating-Point Rounding Mode'"},}, + Version: "", + }, + Enumerant{ + Enumerant: "FPFastMathMode", + Value: 40, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{{OperandKindFPFastMathMode, "'Fast-Math Mode'"},}, + Version: "", + }, + Enumerant{ + Enumerant: "LinkageAttributes", + Value: 41, + Capabilities: []string{"Linkage",}, + Parameters: []Parameter{{OperandKindLiteralString, "'Name'"},{OperandKindLinkageType, "'Linkage Type'"},}, + Version: "", + }, + Enumerant{ + Enumerant: "NoContraction", + Value: 42, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "InputAttachmentIndex", + Value: 43, + Capabilities: []string{"InputAttachment",}, + Parameters: []Parameter{{OperandKindLiteralInteger, "'Attachment Index'"},}, + Version: "", + }, + Enumerant{ + Enumerant: "Alignment", + Value: 44, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{{OperandKindLiteralInteger, "'Alignment'"},}, + Version: "", + }, + Enumerant{ + Enumerant: "MaxByteOffset", + Value: 45, + Capabilities: []string{"Addresses",}, + Parameters: []Parameter{{OperandKindLiteralInteger, "'Max Byte Offset'"},}, + Version: "1.1", + }, + Enumerant{ + Enumerant: "AlignmentId", + Value: 46, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{{OperandKindIdRef, "'Alignment'"},}, + Version: "1.2", + }, + Enumerant{ + Enumerant: "MaxByteOffsetId", + Value: 47, + Capabilities: []string{"Addresses",}, + Parameters: []Parameter{{OperandKindIdRef, "'Max Byte Offset'"},}, + Version: "1.2", + }, + Enumerant{ + Enumerant: "NoSignedWrap", + Value: 4469, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "1.4", + }, + Enumerant{ + Enumerant: "NoUnsignedWrap", + Value: 4470, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "1.4", + }, + Enumerant{ + Enumerant: "ExplicitInterpAMD", + Value: 4999, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "OverrideCoverageNV", + Value: 5248, + Capabilities: []string{"SampleMaskOverrideCoverageNV",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "PassthroughNV", + Value: 5250, + Capabilities: []string{"GeometryShaderPassthroughNV",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "ViewportRelativeNV", + Value: 5252, + Capabilities: []string{"ShaderViewportMaskNV",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "SecondaryViewportRelativeNV", + Value: 5256, + Capabilities: []string{"ShaderStereoViewNV",}, + Parameters: []Parameter{{OperandKindLiteralInteger, "'Offset'"},}, + Version: "None", + }, + Enumerant{ + Enumerant: "PerPrimitiveNV", + Value: 5271, + Capabilities: []string{"MeshShadingNV",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "PerViewNV", + Value: 5272, + Capabilities: []string{"MeshShadingNV",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "PerTaskNV", + Value: 5273, + Capabilities: []string{"MeshShadingNV",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "PerVertexNV", + Value: 5285, + Capabilities: []string{"FragmentBarycentricNV",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "NonUniform", + Value: 5300, + Capabilities: []string{"ShaderNonUniform",}, + Parameters: []Parameter{}, + Version: "1.5", + }, + Enumerant{ + Enumerant: "NonUniformEXT", + Value: 5300, + Capabilities: []string{"ShaderNonUniform",}, + Parameters: []Parameter{}, + Version: "1.5", + }, + Enumerant{ + Enumerant: "RestrictPointer", + Value: 5355, + Capabilities: []string{"PhysicalStorageBufferAddresses",}, + Parameters: []Parameter{}, + Version: "1.5", + }, + Enumerant{ + Enumerant: "RestrictPointerEXT", + Value: 5355, + Capabilities: []string{"PhysicalStorageBufferAddresses",}, + Parameters: []Parameter{}, + Version: "1.5", + }, + Enumerant{ + Enumerant: "AliasedPointer", + Value: 5356, + Capabilities: []string{"PhysicalStorageBufferAddresses",}, + Parameters: []Parameter{}, + Version: "1.5", + }, + Enumerant{ + Enumerant: "AliasedPointerEXT", + Value: 5356, + Capabilities: []string{"PhysicalStorageBufferAddresses",}, + Parameters: []Parameter{}, + Version: "1.5", + }, + Enumerant{ + Enumerant: "CounterBuffer", + Value: 5634, + Capabilities: []string{}, + Parameters: []Parameter{{OperandKindIdRef, "'Counter Buffer'"},}, + Version: "1.4", + }, + Enumerant{ + Enumerant: "HlslCounterBufferGOOGLE", + Value: 5634, + Capabilities: []string{}, + Parameters: []Parameter{{OperandKindIdRef, "'Counter Buffer'"},}, + Version: "None", + }, + Enumerant{ + Enumerant: "UserSemantic", + Value: 5635, + Capabilities: []string{}, + Parameters: []Parameter{{OperandKindLiteralString, "'Semantic'"},}, + Version: "1.4", + }, + Enumerant{ + Enumerant: "HlslSemanticGOOGLE", + Value: 5635, + Capabilities: []string{}, + Parameters: []Parameter{{OperandKindLiteralString, "'Semantic'"},}, + Version: "None", + }, + Enumerant{ + Enumerant: "UserTypeGOOGLE", + Value: 5636, + Capabilities: []string{}, + Parameters: []Parameter{{OperandKindLiteralString, "'User Type'"},}, + Version: "None", + }, + }, + Bases: []*OperandKind {}, + } + OperandKindBuiltIn = &OperandKind { + Kind: "BuiltIn", + Category: "ValueEnum", + Enumerants: []Enumerant { + Enumerant{ + Enumerant: "Position", + Value: 0, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "PointSize", + Value: 1, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "ClipDistance", + Value: 3, + Capabilities: []string{"ClipDistance",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "CullDistance", + Value: 4, + Capabilities: []string{"CullDistance",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "VertexId", + Value: 5, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "InstanceId", + Value: 6, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "PrimitiveId", + Value: 7, + Capabilities: []string{"Geometry","Tessellation","RayTracingNV",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "InvocationId", + Value: 8, + Capabilities: []string{"Geometry","Tessellation",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Layer", + Value: 9, + Capabilities: []string{"Geometry","ShaderLayer","ShaderViewportIndexLayerEXT",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "ViewportIndex", + Value: 10, + Capabilities: []string{"MultiViewport","ShaderViewportIndex","ShaderViewportIndexLayerEXT",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "TessLevelOuter", + Value: 11, + Capabilities: []string{"Tessellation",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "TessLevelInner", + Value: 12, + Capabilities: []string{"Tessellation",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "TessCoord", + Value: 13, + Capabilities: []string{"Tessellation",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "PatchVertices", + Value: 14, + Capabilities: []string{"Tessellation",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "FragCoord", + Value: 15, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "PointCoord", + Value: 16, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "FrontFacing", + Value: 17, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "SampleId", + Value: 18, + Capabilities: []string{"SampleRateShading",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "SamplePosition", + Value: 19, + Capabilities: []string{"SampleRateShading",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "SampleMask", + Value: 20, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "FragDepth", + Value: 22, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "HelperInvocation", + Value: 23, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "NumWorkgroups", + Value: 24, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "WorkgroupSize", + Value: 25, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "WorkgroupId", + Value: 26, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "LocalInvocationId", + Value: 27, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "GlobalInvocationId", + Value: 28, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "LocalInvocationIndex", + Value: 29, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "WorkDim", + Value: 30, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "GlobalSize", + Value: 31, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "EnqueuedWorkgroupSize", + Value: 32, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "GlobalOffset", + Value: 33, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "GlobalLinearId", + Value: 34, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "SubgroupSize", + Value: 36, + Capabilities: []string{"Kernel","GroupNonUniform","SubgroupBallotKHR",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "SubgroupMaxSize", + Value: 37, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "NumSubgroups", + Value: 38, + Capabilities: []string{"Kernel","GroupNonUniform",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "NumEnqueuedSubgroups", + Value: 39, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "SubgroupId", + Value: 40, + Capabilities: []string{"Kernel","GroupNonUniform",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "SubgroupLocalInvocationId", + Value: 41, + Capabilities: []string{"Kernel","GroupNonUniform","SubgroupBallotKHR",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "VertexIndex", + Value: 42, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "InstanceIndex", + Value: 43, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "SubgroupEqMask", + Value: 4416, + Capabilities: []string{"SubgroupBallotKHR","GroupNonUniformBallot",}, + Parameters: []Parameter{}, + Version: "1.3", + }, + Enumerant{ + Enumerant: "SubgroupGeMask", + Value: 4417, + Capabilities: []string{"SubgroupBallotKHR","GroupNonUniformBallot",}, + Parameters: []Parameter{}, + Version: "1.3", + }, + Enumerant{ + Enumerant: "SubgroupGtMask", + Value: 4418, + Capabilities: []string{"SubgroupBallotKHR","GroupNonUniformBallot",}, + Parameters: []Parameter{}, + Version: "1.3", + }, + Enumerant{ + Enumerant: "SubgroupLeMask", + Value: 4419, + Capabilities: []string{"SubgroupBallotKHR","GroupNonUniformBallot",}, + Parameters: []Parameter{}, + Version: "1.3", + }, + Enumerant{ + Enumerant: "SubgroupLtMask", + Value: 4420, + Capabilities: []string{"SubgroupBallotKHR","GroupNonUniformBallot",}, + Parameters: []Parameter{}, + Version: "1.3", + }, + Enumerant{ + Enumerant: "SubgroupEqMaskKHR", + Value: 4416, + Capabilities: []string{"SubgroupBallotKHR","GroupNonUniformBallot",}, + Parameters: []Parameter{}, + Version: "1.3", + }, + Enumerant{ + Enumerant: "SubgroupGeMaskKHR", + Value: 4417, + Capabilities: []string{"SubgroupBallotKHR","GroupNonUniformBallot",}, + Parameters: []Parameter{}, + Version: "1.3", + }, + Enumerant{ + Enumerant: "SubgroupGtMaskKHR", + Value: 4418, + Capabilities: []string{"SubgroupBallotKHR","GroupNonUniformBallot",}, + Parameters: []Parameter{}, + Version: "1.3", + }, + Enumerant{ + Enumerant: "SubgroupLeMaskKHR", + Value: 4419, + Capabilities: []string{"SubgroupBallotKHR","GroupNonUniformBallot",}, + Parameters: []Parameter{}, + Version: "1.3", + }, + Enumerant{ + Enumerant: "SubgroupLtMaskKHR", + Value: 4420, + Capabilities: []string{"SubgroupBallotKHR","GroupNonUniformBallot",}, + Parameters: []Parameter{}, + Version: "1.3", + }, + Enumerant{ + Enumerant: "BaseVertex", + Value: 4424, + Capabilities: []string{"DrawParameters",}, + Parameters: []Parameter{}, + Version: "1.3", + }, + Enumerant{ + Enumerant: "BaseInstance", + Value: 4425, + Capabilities: []string{"DrawParameters",}, + Parameters: []Parameter{}, + Version: "1.3", + }, + Enumerant{ + Enumerant: "DrawIndex", + Value: 4426, + Capabilities: []string{"DrawParameters","MeshShadingNV",}, + Parameters: []Parameter{}, + Version: "1.3", + }, + Enumerant{ + Enumerant: "DeviceIndex", + Value: 4438, + Capabilities: []string{"DeviceGroup",}, + Parameters: []Parameter{}, + Version: "1.3", + }, + Enumerant{ + Enumerant: "ViewIndex", + Value: 4440, + Capabilities: []string{"MultiView",}, + Parameters: []Parameter{}, + Version: "1.3", + }, + Enumerant{ + Enumerant: "BaryCoordNoPerspAMD", + Value: 4992, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "BaryCoordNoPerspCentroidAMD", + Value: 4993, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "BaryCoordNoPerspSampleAMD", + Value: 4994, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "BaryCoordSmoothAMD", + Value: 4995, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "BaryCoordSmoothCentroidAMD", + Value: 4996, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "BaryCoordSmoothSampleAMD", + Value: 4997, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "BaryCoordPullModelAMD", + Value: 4998, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "FragStencilRefEXT", + Value: 5014, + Capabilities: []string{"StencilExportEXT",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "ViewportMaskNV", + Value: 5253, + Capabilities: []string{"ShaderViewportMaskNV","MeshShadingNV",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "SecondaryPositionNV", + Value: 5257, + Capabilities: []string{"ShaderStereoViewNV",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "SecondaryViewportMaskNV", + Value: 5258, + Capabilities: []string{"ShaderStereoViewNV",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "PositionPerViewNV", + Value: 5261, + Capabilities: []string{"PerViewAttributesNV","MeshShadingNV",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "ViewportMaskPerViewNV", + Value: 5262, + Capabilities: []string{"PerViewAttributesNV","MeshShadingNV",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "FullyCoveredEXT", + Value: 5264, + Capabilities: []string{"FragmentFullyCoveredEXT",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "TaskCountNV", + Value: 5274, + Capabilities: []string{"MeshShadingNV",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "PrimitiveCountNV", + Value: 5275, + Capabilities: []string{"MeshShadingNV",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "PrimitiveIndicesNV", + Value: 5276, + Capabilities: []string{"MeshShadingNV",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "ClipDistancePerViewNV", + Value: 5277, + Capabilities: []string{"MeshShadingNV",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "CullDistancePerViewNV", + Value: 5278, + Capabilities: []string{"MeshShadingNV",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "LayerPerViewNV", + Value: 5279, + Capabilities: []string{"MeshShadingNV",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "MeshViewCountNV", + Value: 5280, + Capabilities: []string{"MeshShadingNV",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "MeshViewIndicesNV", + Value: 5281, + Capabilities: []string{"MeshShadingNV",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "BaryCoordNV", + Value: 5286, + Capabilities: []string{"FragmentBarycentricNV",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "BaryCoordNoPerspNV", + Value: 5287, + Capabilities: []string{"FragmentBarycentricNV",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "FragSizeEXT", + Value: 5292, + Capabilities: []string{"FragmentDensityEXT","ShadingRateNV",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "FragmentSizeNV", + Value: 5292, + Capabilities: []string{"ShadingRateNV","FragmentDensityEXT",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "FragInvocationCountEXT", + Value: 5293, + Capabilities: []string{"FragmentDensityEXT","ShadingRateNV",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "InvocationsPerPixelNV", + Value: 5293, + Capabilities: []string{"ShadingRateNV","FragmentDensityEXT",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "LaunchIdNV", + Value: 5319, + Capabilities: []string{"RayTracingNV",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "LaunchSizeNV", + Value: 5320, + Capabilities: []string{"RayTracingNV",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "WorldRayOriginNV", + Value: 5321, + Capabilities: []string{"RayTracingNV",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "WorldRayDirectionNV", + Value: 5322, + Capabilities: []string{"RayTracingNV",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "ObjectRayOriginNV", + Value: 5323, + Capabilities: []string{"RayTracingNV",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "ObjectRayDirectionNV", + Value: 5324, + Capabilities: []string{"RayTracingNV",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "RayTminNV", + Value: 5325, + Capabilities: []string{"RayTracingNV",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "RayTmaxNV", + Value: 5326, + Capabilities: []string{"RayTracingNV",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "InstanceCustomIndexNV", + Value: 5327, + Capabilities: []string{"RayTracingNV",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "ObjectToWorldNV", + Value: 5330, + Capabilities: []string{"RayTracingNV",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "WorldToObjectNV", + Value: 5331, + Capabilities: []string{"RayTracingNV",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "HitTNV", + Value: 5332, + Capabilities: []string{"RayTracingNV",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "HitKindNV", + Value: 5333, + Capabilities: []string{"RayTracingNV",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "IncomingRayFlagsNV", + Value: 5351, + Capabilities: []string{"RayTracingNV",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "WarpsPerSMNV", + Value: 5374, + Capabilities: []string{"ShaderSMBuiltinsNV",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "SMCountNV", + Value: 5375, + Capabilities: []string{"ShaderSMBuiltinsNV",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "WarpIDNV", + Value: 5376, + Capabilities: []string{"ShaderSMBuiltinsNV",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "SMIDNV", + Value: 5377, + Capabilities: []string{"ShaderSMBuiltinsNV",}, + Parameters: []Parameter{}, + Version: "None", + }, + }, + Bases: []*OperandKind {}, + } + OperandKindScope = &OperandKind { + Kind: "Scope", + Category: "ValueEnum", + Enumerants: []Enumerant { + Enumerant{ + Enumerant: "CrossDevice", + Value: 0, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Device", + Value: 1, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Workgroup", + Value: 2, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Subgroup", + Value: 3, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Invocation", + Value: 4, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "QueueFamily", + Value: 5, + Capabilities: []string{"VulkanMemoryModel",}, + Parameters: []Parameter{}, + Version: "1.5", + }, + Enumerant{ + Enumerant: "QueueFamilyKHR", + Value: 5, + Capabilities: []string{"VulkanMemoryModel",}, + Parameters: []Parameter{}, + Version: "1.5", + }, + }, + Bases: []*OperandKind {}, + } + OperandKindGroupOperation = &OperandKind { + Kind: "GroupOperation", + Category: "ValueEnum", + Enumerants: []Enumerant { + Enumerant{ + Enumerant: "Reduce", + Value: 0, + Capabilities: []string{"Kernel","GroupNonUniformArithmetic","GroupNonUniformBallot",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "InclusiveScan", + Value: 1, + Capabilities: []string{"Kernel","GroupNonUniformArithmetic","GroupNonUniformBallot",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "ExclusiveScan", + Value: 2, + Capabilities: []string{"Kernel","GroupNonUniformArithmetic","GroupNonUniformBallot",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "ClusteredReduce", + Value: 3, + Capabilities: []string{"GroupNonUniformClustered",}, + Parameters: []Parameter{}, + Version: "1.3", + }, + Enumerant{ + Enumerant: "PartitionedReduceNV", + Value: 6, + Capabilities: []string{"GroupNonUniformPartitionedNV",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "PartitionedInclusiveScanNV", + Value: 7, + Capabilities: []string{"GroupNonUniformPartitionedNV",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "PartitionedExclusiveScanNV", + Value: 8, + Capabilities: []string{"GroupNonUniformPartitionedNV",}, + Parameters: []Parameter{}, + Version: "None", + }, + }, + Bases: []*OperandKind {}, + } + OperandKindKernelEnqueueFlags = &OperandKind { + Kind: "KernelEnqueueFlags", + Category: "ValueEnum", + Enumerants: []Enumerant { + Enumerant{ + Enumerant: "NoWait", + Value: 0, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "WaitKernel", + Value: 1, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "WaitWorkGroup", + Value: 2, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + }, + Bases: []*OperandKind {}, + } + OperandKindCapability = &OperandKind { + Kind: "Capability", + Category: "ValueEnum", + Enumerants: []Enumerant { + Enumerant{ + Enumerant: "Matrix", + Value: 0, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Shader", + Value: 1, + Capabilities: []string{"Matrix",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Geometry", + Value: 2, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Tessellation", + Value: 3, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Addresses", + Value: 4, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Linkage", + Value: 5, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Kernel", + Value: 6, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Vector16", + Value: 7, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Float16Buffer", + Value: 8, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Float16", + Value: 9, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Float64", + Value: 10, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Int64", + Value: 11, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Int64Atomics", + Value: 12, + Capabilities: []string{"Int64",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "ImageBasic", + Value: 13, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "ImageReadWrite", + Value: 14, + Capabilities: []string{"ImageBasic",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "ImageMipmap", + Value: 15, + Capabilities: []string{"ImageBasic",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Pipes", + Value: 17, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Groups", + Value: 18, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "DeviceEnqueue", + Value: 19, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "LiteralSampler", + Value: 20, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "AtomicStorage", + Value: 21, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Int16", + Value: 22, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "TessellationPointSize", + Value: 23, + Capabilities: []string{"Tessellation",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "GeometryPointSize", + Value: 24, + Capabilities: []string{"Geometry",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "ImageGatherExtended", + Value: 25, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "StorageImageMultisample", + Value: 27, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "UniformBufferArrayDynamicIndexing", + Value: 28, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "SampledImageArrayDynamicIndexing", + Value: 29, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "StorageBufferArrayDynamicIndexing", + Value: 30, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "StorageImageArrayDynamicIndexing", + Value: 31, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "ClipDistance", + Value: 32, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "CullDistance", + Value: 33, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "ImageCubeArray", + Value: 34, + Capabilities: []string{"SampledCubeArray",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "SampleRateShading", + Value: 35, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "ImageRect", + Value: 36, + Capabilities: []string{"SampledRect",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "SampledRect", + Value: 37, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "GenericPointer", + Value: 38, + Capabilities: []string{"Addresses",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Int8", + Value: 39, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "InputAttachment", + Value: 40, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "SparseResidency", + Value: 41, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "MinLod", + Value: 42, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Sampled1D", + Value: 43, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "Image1D", + Value: 44, + Capabilities: []string{"Sampled1D",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "SampledCubeArray", + Value: 45, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "SampledBuffer", + Value: 46, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "ImageBuffer", + Value: 47, + Capabilities: []string{"SampledBuffer",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "ImageMSArray", + Value: 48, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "StorageImageExtendedFormats", + Value: 49, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "ImageQuery", + Value: 50, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "DerivativeControl", + Value: 51, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "InterpolationFunction", + Value: 52, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "TransformFeedback", + Value: 53, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "GeometryStreams", + Value: 54, + Capabilities: []string{"Geometry",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "StorageImageReadWithoutFormat", + Value: 55, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "StorageImageWriteWithoutFormat", + Value: 56, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "MultiViewport", + Value: 57, + Capabilities: []string{"Geometry",}, + Parameters: []Parameter{}, + Version: "", + }, + Enumerant{ + Enumerant: "SubgroupDispatch", + Value: 58, + Capabilities: []string{"DeviceEnqueue",}, + Parameters: []Parameter{}, + Version: "1.1", + }, + Enumerant{ + Enumerant: "NamedBarrier", + Value: 59, + Capabilities: []string{"Kernel",}, + Parameters: []Parameter{}, + Version: "1.1", + }, + Enumerant{ + Enumerant: "PipeStorage", + Value: 60, + Capabilities: []string{"Pipes",}, + Parameters: []Parameter{}, + Version: "1.1", + }, + Enumerant{ + Enumerant: "GroupNonUniform", + Value: 61, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "1.3", + }, + Enumerant{ + Enumerant: "GroupNonUniformVote", + Value: 62, + Capabilities: []string{"GroupNonUniform",}, + Parameters: []Parameter{}, + Version: "1.3", + }, + Enumerant{ + Enumerant: "GroupNonUniformArithmetic", + Value: 63, + Capabilities: []string{"GroupNonUniform",}, + Parameters: []Parameter{}, + Version: "1.3", + }, + Enumerant{ + Enumerant: "GroupNonUniformBallot", + Value: 64, + Capabilities: []string{"GroupNonUniform",}, + Parameters: []Parameter{}, + Version: "1.3", + }, + Enumerant{ + Enumerant: "GroupNonUniformShuffle", + Value: 65, + Capabilities: []string{"GroupNonUniform",}, + Parameters: []Parameter{}, + Version: "1.3", + }, + Enumerant{ + Enumerant: "GroupNonUniformShuffleRelative", + Value: 66, + Capabilities: []string{"GroupNonUniform",}, + Parameters: []Parameter{}, + Version: "1.3", + }, + Enumerant{ + Enumerant: "GroupNonUniformClustered", + Value: 67, + Capabilities: []string{"GroupNonUniform",}, + Parameters: []Parameter{}, + Version: "1.3", + }, + Enumerant{ + Enumerant: "GroupNonUniformQuad", + Value: 68, + Capabilities: []string{"GroupNonUniform",}, + Parameters: []Parameter{}, + Version: "1.3", + }, + Enumerant{ + Enumerant: "ShaderLayer", + Value: 69, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "1.5", + }, + Enumerant{ + Enumerant: "ShaderViewportIndex", + Value: 70, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "1.5", + }, + Enumerant{ + Enumerant: "SubgroupBallotKHR", + Value: 4423, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "DrawParameters", + Value: 4427, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "1.3", + }, + Enumerant{ + Enumerant: "SubgroupVoteKHR", + Value: 4431, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "StorageBuffer16BitAccess", + Value: 4433, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "1.3", + }, + Enumerant{ + Enumerant: "StorageUniformBufferBlock16", + Value: 4433, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "1.3", + }, + Enumerant{ + Enumerant: "UniformAndStorageBuffer16BitAccess", + Value: 4434, + Capabilities: []string{"StorageBuffer16BitAccess","StorageUniformBufferBlock16",}, + Parameters: []Parameter{}, + Version: "1.3", + }, + Enumerant{ + Enumerant: "StorageUniform16", + Value: 4434, + Capabilities: []string{"StorageBuffer16BitAccess","StorageUniformBufferBlock16",}, + Parameters: []Parameter{}, + Version: "1.3", + }, + Enumerant{ + Enumerant: "StoragePushConstant16", + Value: 4435, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "1.3", + }, + Enumerant{ + Enumerant: "StorageInputOutput16", + Value: 4436, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "1.3", + }, + Enumerant{ + Enumerant: "DeviceGroup", + Value: 4437, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "1.3", + }, + Enumerant{ + Enumerant: "MultiView", + Value: 4439, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "1.3", + }, + Enumerant{ + Enumerant: "VariablePointersStorageBuffer", + Value: 4441, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "1.3", + }, + Enumerant{ + Enumerant: "VariablePointers", + Value: 4442, + Capabilities: []string{"VariablePointersStorageBuffer",}, + Parameters: []Parameter{}, + Version: "1.3", + }, + Enumerant{ + Enumerant: "AtomicStorageOps", + Value: 4445, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "SampleMaskPostDepthCoverage", + Value: 4447, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "StorageBuffer8BitAccess", + Value: 4448, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "1.5", + }, + Enumerant{ + Enumerant: "UniformAndStorageBuffer8BitAccess", + Value: 4449, + Capabilities: []string{"StorageBuffer8BitAccess",}, + Parameters: []Parameter{}, + Version: "1.5", + }, + Enumerant{ + Enumerant: "StoragePushConstant8", + Value: 4450, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "1.5", + }, + Enumerant{ + Enumerant: "DenormPreserve", + Value: 4464, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "1.4", + }, + Enumerant{ + Enumerant: "DenormFlushToZero", + Value: 4465, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "1.4", + }, + Enumerant{ + Enumerant: "SignedZeroInfNanPreserve", + Value: 4466, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "1.4", + }, + Enumerant{ + Enumerant: "RoundingModeRTE", + Value: 4467, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "1.4", + }, + Enumerant{ + Enumerant: "RoundingModeRTZ", + Value: 4468, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "1.4", + }, + Enumerant{ + Enumerant: "Float16ImageAMD", + Value: 5008, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "ImageGatherBiasLodAMD", + Value: 5009, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "FragmentMaskAMD", + Value: 5010, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "StencilExportEXT", + Value: 5013, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "ImageReadWriteLodAMD", + Value: 5015, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "ShaderClockKHR", + Value: 5055, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "SampleMaskOverrideCoverageNV", + Value: 5249, + Capabilities: []string{"SampleRateShading",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "GeometryShaderPassthroughNV", + Value: 5251, + Capabilities: []string{"Geometry",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "ShaderViewportIndexLayerEXT", + Value: 5254, + Capabilities: []string{"MultiViewport",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "ShaderViewportIndexLayerNV", + Value: 5254, + Capabilities: []string{"MultiViewport",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "ShaderViewportMaskNV", + Value: 5255, + Capabilities: []string{"ShaderViewportIndexLayerNV",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "ShaderStereoViewNV", + Value: 5259, + Capabilities: []string{"ShaderViewportMaskNV",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "PerViewAttributesNV", + Value: 5260, + Capabilities: []string{"MultiView",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "FragmentFullyCoveredEXT", + Value: 5265, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "MeshShadingNV", + Value: 5266, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "ImageFootprintNV", + Value: 5282, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "FragmentBarycentricNV", + Value: 5284, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "ComputeDerivativeGroupQuadsNV", + Value: 5288, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "FragmentDensityEXT", + Value: 5291, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "ShadingRateNV", + Value: 5291, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "GroupNonUniformPartitionedNV", + Value: 5297, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "ShaderNonUniform", + Value: 5301, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "1.5", + }, + Enumerant{ + Enumerant: "ShaderNonUniformEXT", + Value: 5301, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "1.5", + }, + Enumerant{ + Enumerant: "RuntimeDescriptorArray", + Value: 5302, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "1.5", + }, + Enumerant{ + Enumerant: "RuntimeDescriptorArrayEXT", + Value: 5302, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "1.5", + }, + Enumerant{ + Enumerant: "InputAttachmentArrayDynamicIndexing", + Value: 5303, + Capabilities: []string{"InputAttachment",}, + Parameters: []Parameter{}, + Version: "1.5", + }, + Enumerant{ + Enumerant: "InputAttachmentArrayDynamicIndexingEXT", + Value: 5303, + Capabilities: []string{"InputAttachment",}, + Parameters: []Parameter{}, + Version: "1.5", + }, + Enumerant{ + Enumerant: "UniformTexelBufferArrayDynamicIndexing", + Value: 5304, + Capabilities: []string{"SampledBuffer",}, + Parameters: []Parameter{}, + Version: "1.5", + }, + Enumerant{ + Enumerant: "UniformTexelBufferArrayDynamicIndexingEXT", + Value: 5304, + Capabilities: []string{"SampledBuffer",}, + Parameters: []Parameter{}, + Version: "1.5", + }, + Enumerant{ + Enumerant: "StorageTexelBufferArrayDynamicIndexing", + Value: 5305, + Capabilities: []string{"ImageBuffer",}, + Parameters: []Parameter{}, + Version: "1.5", + }, + Enumerant{ + Enumerant: "StorageTexelBufferArrayDynamicIndexingEXT", + Value: 5305, + Capabilities: []string{"ImageBuffer",}, + Parameters: []Parameter{}, + Version: "1.5", + }, + Enumerant{ + Enumerant: "UniformBufferArrayNonUniformIndexing", + Value: 5306, + Capabilities: []string{"ShaderNonUniform",}, + Parameters: []Parameter{}, + Version: "1.5", + }, + Enumerant{ + Enumerant: "UniformBufferArrayNonUniformIndexingEXT", + Value: 5306, + Capabilities: []string{"ShaderNonUniform",}, + Parameters: []Parameter{}, + Version: "1.5", + }, + Enumerant{ + Enumerant: "SampledImageArrayNonUniformIndexing", + Value: 5307, + Capabilities: []string{"ShaderNonUniform",}, + Parameters: []Parameter{}, + Version: "1.5", + }, + Enumerant{ + Enumerant: "SampledImageArrayNonUniformIndexingEXT", + Value: 5307, + Capabilities: []string{"ShaderNonUniform",}, + Parameters: []Parameter{}, + Version: "1.5", + }, + Enumerant{ + Enumerant: "StorageBufferArrayNonUniformIndexing", + Value: 5308, + Capabilities: []string{"ShaderNonUniform",}, + Parameters: []Parameter{}, + Version: "1.5", + }, + Enumerant{ + Enumerant: "StorageBufferArrayNonUniformIndexingEXT", + Value: 5308, + Capabilities: []string{"ShaderNonUniform",}, + Parameters: []Parameter{}, + Version: "1.5", + }, + Enumerant{ + Enumerant: "StorageImageArrayNonUniformIndexing", + Value: 5309, + Capabilities: []string{"ShaderNonUniform",}, + Parameters: []Parameter{}, + Version: "1.5", + }, + Enumerant{ + Enumerant: "StorageImageArrayNonUniformIndexingEXT", + Value: 5309, + Capabilities: []string{"ShaderNonUniform",}, + Parameters: []Parameter{}, + Version: "1.5", + }, + Enumerant{ + Enumerant: "InputAttachmentArrayNonUniformIndexing", + Value: 5310, + Capabilities: []string{"InputAttachment","ShaderNonUniform",}, + Parameters: []Parameter{}, + Version: "1.5", + }, + Enumerant{ + Enumerant: "InputAttachmentArrayNonUniformIndexingEXT", + Value: 5310, + Capabilities: []string{"InputAttachment","ShaderNonUniform",}, + Parameters: []Parameter{}, + Version: "1.5", + }, + Enumerant{ + Enumerant: "UniformTexelBufferArrayNonUniformIndexing", + Value: 5311, + Capabilities: []string{"SampledBuffer","ShaderNonUniform",}, + Parameters: []Parameter{}, + Version: "1.5", + }, + Enumerant{ + Enumerant: "UniformTexelBufferArrayNonUniformIndexingEXT", + Value: 5311, + Capabilities: []string{"SampledBuffer","ShaderNonUniform",}, + Parameters: []Parameter{}, + Version: "1.5", + }, + Enumerant{ + Enumerant: "StorageTexelBufferArrayNonUniformIndexing", + Value: 5312, + Capabilities: []string{"ImageBuffer","ShaderNonUniform",}, + Parameters: []Parameter{}, + Version: "1.5", + }, + Enumerant{ + Enumerant: "StorageTexelBufferArrayNonUniformIndexingEXT", + Value: 5312, + Capabilities: []string{"ImageBuffer","ShaderNonUniform",}, + Parameters: []Parameter{}, + Version: "1.5", + }, + Enumerant{ + Enumerant: "RayTracingNV", + Value: 5340, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "VulkanMemoryModel", + Value: 5345, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "1.5", + }, + Enumerant{ + Enumerant: "VulkanMemoryModelKHR", + Value: 5345, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "1.5", + }, + Enumerant{ + Enumerant: "VulkanMemoryModelDeviceScope", + Value: 5346, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "1.5", + }, + Enumerant{ + Enumerant: "VulkanMemoryModelDeviceScopeKHR", + Value: 5346, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "1.5", + }, + Enumerant{ + Enumerant: "PhysicalStorageBufferAddresses", + Value: 5347, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "1.5", + }, + Enumerant{ + Enumerant: "PhysicalStorageBufferAddressesEXT", + Value: 5347, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "1.5", + }, + Enumerant{ + Enumerant: "ComputeDerivativeGroupLinearNV", + Value: 5350, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "CooperativeMatrixNV", + Value: 5357, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "FragmentShaderSampleInterlockEXT", + Value: 5363, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "FragmentShaderShadingRateInterlockEXT", + Value: 5372, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "ShaderSMBuiltinsNV", + Value: 5373, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "FragmentShaderPixelInterlockEXT", + Value: 5378, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "DemoteToHelperInvocationEXT", + Value: 5379, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "SubgroupShuffleINTEL", + Value: 5568, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "SubgroupBufferBlockIOINTEL", + Value: 5569, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "SubgroupImageBlockIOINTEL", + Value: 5570, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "SubgroupImageMediaBlockIOINTEL", + Value: 5579, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "IntegerFunctions2INTEL", + Value: 5584, + Capabilities: []string{"Shader",}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "SubgroupAvcMotionEstimationINTEL", + Value: 5696, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "SubgroupAvcMotionEstimationIntraINTEL", + Value: 5697, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "None", + }, + Enumerant{ + Enumerant: "SubgroupAvcMotionEstimationChromaINTEL", + Value: 5698, + Capabilities: []string{}, + Parameters: []Parameter{}, + Version: "None", + }, + }, + Bases: []*OperandKind {}, + } + OperandKindIdResultType = &OperandKind { + Kind: "IdResultType", + Category: "Id", + Enumerants: []Enumerant { + }, + Bases: []*OperandKind {}, + } + OperandKindIdResult = &OperandKind { + Kind: "IdResult", + Category: "Id", + Enumerants: []Enumerant { + }, + Bases: []*OperandKind {}, + } + OperandKindIdMemorySemantics = &OperandKind { + Kind: "IdMemorySemantics", + Category: "Id", + Enumerants: []Enumerant { + }, + Bases: []*OperandKind {}, + } + OperandKindIdScope = &OperandKind { + Kind: "IdScope", + Category: "Id", + Enumerants: []Enumerant { + }, + Bases: []*OperandKind {}, + } + OperandKindIdRef = &OperandKind { + Kind: "IdRef", + Category: "Id", + Enumerants: []Enumerant { + }, + Bases: []*OperandKind {}, + } + OperandKindLiteralInteger = &OperandKind { + Kind: "LiteralInteger", + Category: "Literal", + Enumerants: []Enumerant { + }, + Bases: []*OperandKind {}, + } + OperandKindLiteralString = &OperandKind { + Kind: "LiteralString", + Category: "Literal", + Enumerants: []Enumerant { + }, + Bases: []*OperandKind {}, + } + OperandKindLiteralContextDependentNumber = &OperandKind { + Kind: "LiteralContextDependentNumber", + Category: "Literal", + Enumerants: []Enumerant { + }, + Bases: []*OperandKind {}, + } + OperandKindLiteralExtInstInteger = &OperandKind { + Kind: "LiteralExtInstInteger", + Category: "Literal", + Enumerants: []Enumerant { + }, + Bases: []*OperandKind {}, + } + OperandKindLiteralSpecConstantOpInteger = &OperandKind { + Kind: "LiteralSpecConstantOpInteger", + Category: "Literal", + Enumerants: []Enumerant { + }, + Bases: []*OperandKind {}, + } + OperandKindPairLiteralIntegerIdRef = &OperandKind { + Kind: "PairLiteralIntegerIdRef", + Category: "Composite", + Enumerants: []Enumerant { + }, + Bases: []*OperandKind {OperandKindLiteralInteger,OperandKindIdRef,}, + } + OperandKindPairIdRefLiteralInteger = &OperandKind { + Kind: "PairIdRefLiteralInteger", + Category: "Composite", + Enumerants: []Enumerant { + }, + Bases: []*OperandKind {OperandKindIdRef,OperandKindLiteralInteger,}, + } + OperandKindPairIdRefIdRef = &OperandKind { + Kind: "PairIdRefIdRef", + Category: "Composite", + Enumerants: []Enumerant { + }, + Bases: []*OperandKind {OperandKindIdRef,OperandKindIdRef,}, + } + +) diff --git a/third_party/spirv-tools/utils/vscode/src/schema/schema.go.tmpl b/third_party/spirv-tools/utils/vscode/src/schema/schema.go.tmpl new file mode 100644 index 0000000000..b584058763 --- /dev/null +++ b/third_party/spirv-tools/utils/vscode/src/schema/schema.go.tmpl @@ -0,0 +1,133 @@ +// Copyright (C) 2019 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Generated by {{GenerateArguments}} +// Do not modify this file directly. + +package schema + +// Opcode holds information about a specific SPIR-V opcode. +type Opcode struct { + Opname string + Class string + Opcode int + Operands []Operand +} + +// Operand contains information about a logical operand for an instruction. +type Operand struct { + Kind *OperandKind + Name string + Quantifier Quantifier +} + +// OperandKind contains information about a specific operand kind. +type OperandKind struct { + Category OperandCategory + Kind string + Enumerants []Enumerant + Bases []*OperandKind +} + +// Enumerant contains information about an enumerant in an enum. +type Enumerant struct { + Enumerant string + Value interface{} + Capabilities []string + Parameters []Parameter + Version string +} + +// Parameter contains information about a logical parameter for an enumerant. +type Parameter struct { + Kind *OperandKind + Name string +} + +// Quantifier indicates the number of times the quantified term may appear. +type Quantifier string + +const ( + // Once indicates the quantified term may appear exactly once. + Once Quantifier = "" + + // ZeroOrOnce indicates the quantified term may appear zero or one + // time; an optional term. + ZeroOrOnce Quantifier = "?" + + // ZeroOrMany indicates the quantified term may appear any number of + // times. + ZeroOrMany Quantifier = "*" +) + +// OperandCategory is an enumerator that groups operand kinds. +type OperandCategory string + +const ( + // OperandCategoryBitEnum describes an operand kind where its value is a + // mask, which is formed by combining the bits specified as enumerants in an + // enum. + OperandCategoryBitEnum = "BitEnum" + + // OperandCategoryValueEnum describes an operand kind where its value is an + // enumerant from an enum. + OperandCategoryValueEnum = "ValueEnum" + + // OperandCategoryID describes and operand kind where its value is an + // definition or reference. + OperandCategoryID = "Id" + + // OperandCategoryLiteral describes and operand kind where its value is an + // literal number or string. + OperandCategoryLiteral = "Literal" + + // OperandCategoryComposite describes and operand kind where its value is + // composed from operand values from the above categories. + OperandCategoryComposite = "Composite" +) + +var ( + // Opcodes is a map of opcode name to Opcode description. + Opcodes = map[string]*Opcode {•{{range $i := .Instructions}} + "{{$i.Opname}}": {{$i.Opname}},{{end}} + } + +{{range $i := .Instructions}} {{$i.Opname}} = &Opcode { + Opname: "{{$i.Opname}}", + Operands: []Operand {•{{range $i := $i.Operands}} + Operand { + Kind: OperandKind{{$i.Kind}}, + Name: "{{Replace $i.Name "\n" " "}}", + Quantifier: "{{$i.Quantifier}}", + }, {{end}} + }, + } +{{end}} + +{{range $o := .OperandKinds}} OperandKind{{$o.Kind}} = &OperandKind { + Kind: "{{$o.Kind}}", + Category: "{{$o.Category}}", + Enumerants: []Enumerant {•{{range $e := $o.Enumerants}} + Enumerant{ + Enumerant: "{{$e.Enumerant}}", + Value: {{$e.Value}}, + Capabilities: []string{•{{range $c := $e.Capabilities}}"{{$c}}",{{end}}•}, + Parameters: []Parameter{•{{range $p := $e.Parameters}}{•OperandKind{{$p.Kind}}, "{{$p.Name}}"•},{{end}}•}, + Version: "{{$e.Version}}", + },{{end}} + }, + Bases: []*OperandKind {•{{range $b := $o.Bases}}OperandKind{{$b}},{{end}}•}, + } +{{end}} +) diff --git a/third_party/spirv-tools/utils/vscode/src/tools/gen-grammar.go b/third_party/spirv-tools/utils/vscode/src/tools/gen-grammar.go new file mode 100644 index 0000000000..42cbbe9aca --- /dev/null +++ b/third_party/spirv-tools/utils/vscode/src/tools/gen-grammar.go @@ -0,0 +1,171 @@ +// Copyright (C) 2019 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// gen-grammar generates the spirv.json grammar file from the official SPIR-V +// grammar JSON file. +package main + +import ( + "bytes" + "encoding/json" + "flag" + "fmt" + "io/ioutil" + "net/http" + "os" + "path/filepath" + "runtime" + "strings" + "text/template" + + "github.com/pkg/errors" + + "../grammar" +) + +const ( + spirvGrammarURL = "https://raw.githubusercontent.com/KhronosGroup/SPIRV-Headers/master/include/spirv/unified1/spirv.core.grammar.json" + spirvGrammarName = "spirv.core.grammar.json" +) + +var ( + templatePath = flag.String("template", "", "Path to input template file (required)") + outputPath = flag.String("out", "", "Path to output generated file (required)") + cachePath = flag.String("cache", "", "Cache directory for downloaded files (optional)") + + thisDir = func() string { + _, file, _, _ := runtime.Caller(1) + return filepath.Dir(file) + }() +) + +func main() { + flag.Parse() + if *templatePath == "" || *outputPath == "" { + flag.Usage() + os.Exit(1) + } + if err := run(); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} + +func run() error { + tf, err := ioutil.ReadFile(*templatePath) + if err != nil { + return errors.Wrap(err, "Could not open template file") + } + t, err := template.New("tmpl"). + Funcs(template.FuncMap{ + "GenerateArguments": func() string { + relPath := func(path string) string { + rel, err := filepath.Rel(thisDir, path) + if err != nil { + return path + } + return rel + } + escape := func(str string) string { + return strings.ReplaceAll(str, `\`, `/`) + } + args := []string{ + "--template=" + escape(relPath(*templatePath)), + "--out=" + escape(relPath(*outputPath)), + } + return "gen-grammar.go " + strings.Join(args, " ") + }, + "OperandKindsMatch": func(k grammar.OperandKind) string { + sb := strings.Builder{} + for i, e := range k.Enumerants { + if i > 0 { + sb.WriteString("|") + } + sb.WriteString(e.Enumerant) + } + return sb.String() + }, + "Replace": strings.ReplaceAll, + }).Parse(string(tf)) + if err != nil { + return errors.Wrap(err, "Failed to parse template") + } + + file, err := getOrDownload(spirvGrammarName, spirvGrammarURL) + if err != nil { + return errors.Wrap(err, "Failed to load grammar file") + } + + g := grammar.Root{} + if err := json.NewDecoder(bytes.NewReader(file)).Decode(&g); err != nil { + return errors.Wrap(err, "Failed to parse grammar file") + } + + buf := bytes.Buffer{} + if err := t.Execute(&buf, g); err != nil { + return errors.Wrap(err, "Failed to execute template") + } + + out := buf.String() + out = strings.ReplaceAll(out, "•", "") + + if err := ioutil.WriteFile(*outputPath, []byte(out), 0777); err != nil { + return errors.Wrap(err, "Failed to write output file") + } + + return nil +} + +// getOrDownload loads the specific file from the cache, or downloads the file +// from the given url. +func getOrDownload(name, url string) ([]byte, error) { + if *cachePath != "" { + if err := os.MkdirAll(*cachePath, 0777); err == nil { + path := filepath.Join(*cachePath, name) + if isFile(path) { + return ioutil.ReadFile(path) + } + } + } + resp, err := http.Get(url) + if err != nil { + return nil, err + } + data, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + if *cachePath != "" { + ioutil.WriteFile(filepath.Join(*cachePath, name), data, 0777) + } + return data, nil +} + +// isFile returns true if path is a file. +func isFile(path string) bool { + s, err := os.Stat(path) + if err != nil { + return false + } + return !s.IsDir() +} + +// isDir returns true if path is a directory. +func isDir(path string) bool { + s, err := os.Stat(path) + if err != nil { + return false + } + return s.IsDir() +}